commit 5b1ff23e0f7ead9dde6fa9561b1f801bb786ee23 Author: Jeff Farrand Date: Sun Jan 12 09:48:16 2014 -0600 Initial Commit diff --git a/COPYING.txt b/COPYING.txt new file mode 100755 index 0000000..b3f64f0 --- /dev/null +++ b/COPYING.txt @@ -0,0 +1,345 @@ + 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. \ No newline at end of file diff --git a/DOOM CLASSIC IOS v.2.1 README.txt b/DOOM CLASSIC IOS v.2.1 README.txt new file mode 100755 index 0000000..9589793 --- /dev/null +++ b/DOOM CLASSIC IOS v.2.1 README.txt @@ -0,0 +1,24 @@ +DOOM Classic iOS v2.1 GPL source release +=============================================== + +This file contains the following sections: + +GENERAL NOTES +LICENSE + +GENERAL NOTES +============= + +DOOM Classic iOS v2.1 is a free release, and can be downloaded from +http://http://www.idsoftware.com/idstuff/doom/doomclassic_ios_v21_src.zip + +This source release does not contain any game data, the game data remains subject to the original EULA and applicable law. + + +LICENSE +======= + +See COPYING.txt for the GNU GENERAL PUBLIC LICENSE. If COPYING.txt does not accompany, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + + diff --git a/DoomClassic/base.parm b/DoomClassic/base.parm new file mode 100755 index 0000000..806dda4 --- /dev/null +++ b/DoomClassic/base.parm @@ -0,0 +1,2 @@ +iphone/livetile_1.tga PVR2 +iphone/arialImageLAL.tga LA diff --git a/DoomClassic/base/prboom.wad b/DoomClassic/base/prboom.wad new file mode 100755 index 0000000..8516986 Binary files /dev/null and b/DoomClassic/base/prboom.wad differ diff --git a/DoomClassic/code/iphone/ControlsMenuView.xib b/DoomClassic/code/iphone/ControlsMenuView.xib new file mode 100755 index 0000000..f4f6c59 --- /dev/null +++ b/DoomClassic/code/iphone/ControlsMenuView.xib @@ -0,0 +1,255 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DoomClassic/code/iphone/ControlsMenuViewController.h b/DoomClassic/code/iphone/ControlsMenuViewController.h new file mode 100755 index 0000000..ca9fa5f --- /dev/null +++ b/DoomClassic/code/iphone/ControlsMenuViewController.h @@ -0,0 +1,58 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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. + + */ +#import + +/* + ================================================================================================ + ControlsMenuViewController + + ================================================================================================ + */ +@interface Doom_ControlsMenuViewController : UIViewController { + + IBOutlet UISlider * movestickSize; + IBOutlet UISlider * turnstickSize; + IBOutlet UISlider * tiltMoveSpeed; + IBOutlet UISlider * tiltTurnSpeed; + + + IBOutlet UIButton * singleThumbButton; + IBOutlet UIButton * dualThumbButton; + IBOutlet UIButton * dirWheelButton; + +} + + +- (void) SetupSlider:(UISlider*)slider minimumTrack:(UIImage*)minImage + maximumTrack:(UIImage*)maxImage + thumb:(UIImage*)thumbImage; + +- (IBAction) BackToMain; +- (IBAction) HudLayoutPressed; +- (IBAction) SingleThumbpadPressed; +- (IBAction) DualThumbpadPressed; +- (IBAction) DirWheelPressed; + +- (IBAction) MoveStickValChanged; +- (IBAction) TurnStickValChanged; +- (IBAction) TiltMoveValChanged; +- (IBAction) TiltTurnValChanged; + +@end diff --git a/DoomClassic/code/iphone/ControlsMenuViewController.mm b/DoomClassic/code/iphone/ControlsMenuViewController.mm new file mode 100755 index 0000000..d1cb7ad --- /dev/null +++ b/DoomClassic/code/iphone/ControlsMenuViewController.mm @@ -0,0 +1,332 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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. + + */ + +#import "ControlsMenuViewController.h" +#include "doomiphone.h" +#include "iphone_delegate.h" + +/* + ================================================================================================ + CreditsMenuViewController + + ================================================================================================ + */ +@implementation Doom_ControlsMenuViewController + +/* + ======================== + Doom_ControlsMenuViewController::Initialize + ======================== + */ +- (void) Initialize { + + + // Minimum track image setup. + UIImage* minimumTrackImage = [UIImage imageNamed:@"SliderBar.png"]; + NSInteger minimumTrackImageCap = (NSInteger)(minimumTrackImage.size.width * 0.5f); + + UIImage* minimumTrackImageCapped = [minimumTrackImage stretchableImageWithLeftCapWidth:minimumTrackImageCap topCapHeight: 0]; + + + // Maximum track image setup. + UIImage* maximumTrackImage = [UIImage imageNamed:@"SliderBackground.png"]; + NSInteger maximumTrackImageCap = (NSInteger)(maximumTrackImage.size.width * 0.5f); + + UIImage* maximumTrackImageCapped = [maximumTrackImage stretchableImageWithLeftCapWidth:maximumTrackImageCap topCapHeight: 0]; + + // Thumb image. + UIImage* thumbImage = [UIImage imageNamed:@"SliderSkull.png"]; + + // Set up slider instances. + [self SetupSlider:movestickSize minimumTrack:minimumTrackImageCapped + maximumTrack:maximumTrackImageCapped + thumb:thumbImage]; + + + [self SetupSlider:turnstickSize minimumTrack:minimumTrackImageCapped + maximumTrack:maximumTrackImageCapped + thumb:thumbImage]; + + + + [self SetupSlider:tiltMoveSpeed minimumTrack:minimumTrackImageCapped + maximumTrack:maximumTrackImageCapped + thumb:thumbImage]; + + + + + [self SetupSlider:tiltTurnSpeed minimumTrack:minimumTrackImageCapped + maximumTrack:maximumTrackImageCapped + thumb:thumbImage]; + + movestickSize.value = stickMove->value / 255; + turnstickSize.value = stickTurn->value / 255; + tiltMoveSpeed.value = tiltMove->value; + tiltTurnSpeed.value = tiltTurn->value; + + if( controlScheme->value == 0 ) { + singleThumbButton.enabled = NO; + dualThumbButton.enabled = YES; + dirWheelButton.enabled = YES; + } else if( controlScheme->value == 1 ) { + singleThumbButton.enabled = YES; + dualThumbButton.enabled = NO; + dirWheelButton.enabled = YES; + } else if( controlScheme->value == 2 ) { + singleThumbButton.enabled = YES; + dualThumbButton.enabled = YES; + dirWheelButton.enabled = NO; + } + +} + +/* + ======================== + Doom_ControlsMenuViewController::initWithNibName + ======================== + */ +- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil +{ + self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; + if (self) { + // Custom initialization + } + return self; +} + +/* + ======================== + Doom_ControlsMenuViewController::didReceiveMemoryWarning + ======================== + */ +- (void)didReceiveMemoryWarning +{ + // Releases the view if it doesn't have a superview. + [super didReceiveMemoryWarning]; + + // Release any cached data, images, etc that aren't in use. +} + +#pragma mark - View lifecycle + +/* + ======================== + Doom_ControlsMenuViewController::viewDidLoad + ======================== + */ +- (void)viewDidLoad +{ + [super viewDidLoad]; + [ self Initialize ]; +} + +/* + ======================== + Doom_ControlsMenuViewController::viewDidUnload + ======================== + */ +- (void)viewDidUnload +{ + [super viewDidUnload]; + // Release any retained subviews of the main view. + // e.g. self.myOutlet = nil; +} + +/* + ======================== + Doom_ControlsMenuViewController::SetupSlider + ======================== + */ +- (void) SetupSlider:(UISlider*)slider minimumTrack:(UIImage*)minImage + maximumTrack:(UIImage*)maxImage + thumb:(UIImage*)thumbImage { + + //[slider setMinimumTrackImage:minImage forState:UIControlStateNormal]; + //slider setMaximumTrackImage:maxImage forState:UIControlStateNormal]; + + [slider setThumbImage:thumbImage forState:UIControlStateNormal]; + [slider setThumbImage:thumbImage forState:UIControlStateHighlighted]; +} + +/* + ======================== + Doom_ControlsMenuViewController::BackToMain + ======================== + */ +- (IBAction) BackToMain { + + [self.navigationController popViewControllerAnimated:NO]; + Sound_StartLocalSound( "iphone/controller_down_01_SILENCE.wav" ); +} + +/* + ======================== + Doom_ControlsMenuViewController::HudLayoutPressed + ======================== + */ +- (IBAction) HudLayoutPressed { + + menuState = IPM_HUDEDIT; + HudEditFrame(); + [gAppDelegate ShowGLView ]; +} + +/* + ======================== + Doom_ControlsMenuViewController::SingleThumbpadPressed + ======================== + */ +- (IBAction) SingleThumbpadPressed { + + Cvar_SetValue( controlScheme->name, 0 ); + HudSetForScheme( 0 ); + + if( controlScheme->value == 0 ) { + singleThumbButton.enabled = NO; + dualThumbButton.enabled = YES; + dirWheelButton.enabled = YES; + } else if( controlScheme->value == 1 ) { + singleThumbButton.enabled = YES; + dualThumbButton.enabled = NO; + dirWheelButton.enabled = YES; + } else if( controlScheme->value == 2 ) { + singleThumbButton.enabled = YES; + dualThumbButton.enabled = YES; + dirWheelButton.enabled = NO; + } + +} + +/* + ======================== + Doom_ControlsMenuViewController::DualThumbpadPressed + ======================== + */ +- (IBAction) DualThumbpadPressed { + + Cvar_SetValue( controlScheme->name, 1 ); + HudSetForScheme( 1 ); + + if( controlScheme->value == 0 ) { + singleThumbButton.enabled = NO; + dualThumbButton.enabled = YES; + dirWheelButton.enabled = YES; + } else if( controlScheme->value == 1 ) { + singleThumbButton.enabled = YES; + dualThumbButton.enabled = NO; + dirWheelButton.enabled = YES; + } else if( controlScheme->value == 2 ) { + singleThumbButton.enabled = YES; + dualThumbButton.enabled = YES; + dirWheelButton.enabled = NO; + } +} + +/* + ======================== + Doom_ControlsMenuViewController::DirWheelPressed + ======================== + */ +- (IBAction) DirWheelPressed { + + Cvar_SetValue( controlScheme->name, 2 ); + HudSetForScheme( 2 ); + + if( controlScheme->value == 0 ) { + singleThumbButton.enabled = NO; + dualThumbButton.enabled = YES; + dirWheelButton.enabled = YES; + } else if( controlScheme->value == 1 ) { + singleThumbButton.enabled = YES; + dualThumbButton.enabled = NO; + dirWheelButton.enabled = YES; + } else if( controlScheme->value == 2 ) { + singleThumbButton.enabled = YES; + dualThumbButton.enabled = YES; + dirWheelButton.enabled = NO; + } +} + +/* + ======================== + Doom_ControlsMenuViewController::MoveStickValChanged + ======================== + */ +- (IBAction) MoveStickValChanged { + + Cvar_SetValue( stickMove->name, movestickSize.value * 256.0f ); + +} + +/* + ======================== + Doom_ControlsMenuViewController::TurnStickValChanged + ======================== + */ +- (IBAction) TurnStickValChanged { + + Cvar_SetValue( stickTurn->name, turnstickSize.value * 256.0f ); +} + +/* + ======================== + Doom_ControlsMenuViewController::TiltMoveValChanged + ======================== + */ +- (IBAction) TiltMoveValChanged { + Cvar_SetValue( tiltMove->name, tiltMoveSpeed.value ); + + if ( tiltMove->value == 100 ) { + Cvar_SetValue( tiltMove->name, 0 ); + tiltMoveSpeed.value = tiltMove->value; + } + if ( tiltMove->value ) { + Cvar_SetValue( tiltTurn->name, 0 ); + tiltTurnSpeed.value = tiltTurn->value; + } + + + +} + +/* + ======================== + Doom_ControlsMenuViewController::TiltTurnValChanged + ======================== + */ +- (IBAction) TiltTurnValChanged { + Cvar_SetValue( tiltTurn->name, tiltTurnSpeed.value ); + + if ( tiltTurn->value == 1500 ) { + Cvar_SetValue( tiltTurn->name, 0 ); + tiltTurnSpeed.value = tiltTurn->value; + } + if ( tiltTurn->value ) { + Cvar_SetValue( tiltMove->name, 0 ); + tiltMoveSpeed.value = tiltMove->value; + } + + + +} + + +@end diff --git a/DoomClassic/code/iphone/ControlsMenuViewi5.xib b/DoomClassic/code/iphone/ControlsMenuViewi5.xib new file mode 100755 index 0000000..ce721ae --- /dev/null +++ b/DoomClassic/code/iphone/ControlsMenuViewi5.xib @@ -0,0 +1,256 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DoomClassic/code/iphone/ControlsMenuView~ipad.xib b/DoomClassic/code/iphone/ControlsMenuView~ipad.xib new file mode 100755 index 0000000..d94755d --- /dev/null +++ b/DoomClassic/code/iphone/ControlsMenuView~ipad.xib @@ -0,0 +1,255 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DoomClassic/code/iphone/CreditsMenuView.xib b/DoomClassic/code/iphone/CreditsMenuView.xib new file mode 100755 index 0000000..26f1b93 --- /dev/null +++ b/DoomClassic/code/iphone/CreditsMenuView.xib @@ -0,0 +1,360 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DoomClassic/code/iphone/CreditsMenuViewController.h b/DoomClassic/code/iphone/CreditsMenuViewController.h new file mode 100755 index 0000000..1c25310 --- /dev/null +++ b/DoomClassic/code/iphone/CreditsMenuViewController.h @@ -0,0 +1,38 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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. + + */ + +#import + +/* + ================================================================================================ + CreditsMenuViewController + + ================================================================================================ + */ +@interface Doom_CreditsMenuViewController : UIViewController { + + IBOutlet UIScrollView * scrollView; + IBOutlet UILabel * lastItem; + +} + +- (IBAction) BackToMain; + +@end diff --git a/DoomClassic/code/iphone/CreditsMenuViewController.mm b/DoomClassic/code/iphone/CreditsMenuViewController.mm new file mode 100755 index 0000000..a8140a4 --- /dev/null +++ b/DoomClassic/code/iphone/CreditsMenuViewController.mm @@ -0,0 +1,97 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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. + + */ + +#import "CreditsMenuViewController.h" +#include "doomiphone.h" +#include "iphone_delegate.h" + +@implementation Doom_CreditsMenuViewController + +/* + ======================== + Doom_CreditsMenuViewController::initWithNibName + ======================== + */ +- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil +{ + self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; + if (self) { + + } + return self; +} + +/* + ======================== + Doom_CreditsMenuViewController::didReceiveMemoryWarning + ======================== + */ +- (void)didReceiveMemoryWarning +{ + // Releases the view if it doesn't have a superview. + [super didReceiveMemoryWarning]; + + // Release any cached data, images, etc that aren't in use. +} + +#pragma mark - View lifecycle + +/* + ======================== + Doom_CreditsMenuViewController::viewDidLoad + ======================== + */ +- (void)viewDidLoad +{ + [super viewDidLoad]; + + if( scrollView != nil ) { + + [scrollView setContentSize:CGSizeMake( + scrollView.bounds.size.width, + CGRectGetMaxY(lastItem.frame) + )]; + } +} + +/* + ======================== + Doom_CreditsMenuViewController::viewDidUnload + ======================== + */ +- (void)viewDidUnload +{ + [super viewDidUnload]; + // Release any retained subviews of the main view. + // e.g. self.myOutlet = nil; +} + +/* + ======================== + Doom_CreditsMenuViewController::BackToMain + ======================== + */ +- (IBAction) BackToMain { + + [self.navigationController popViewControllerAnimated:NO]; + Sound_StartLocalSound( "iphone/controller_down_01_SILENCE.wav" ); +} + +@end diff --git a/DoomClassic/code/iphone/CreditsMenuViewi5.xib b/DoomClassic/code/iphone/CreditsMenuViewi5.xib new file mode 100755 index 0000000..15e2c01 --- /dev/null +++ b/DoomClassic/code/iphone/CreditsMenuViewi5.xib @@ -0,0 +1,362 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DoomClassic/code/iphone/CreditsMenuView~ipad.xib b/DoomClassic/code/iphone/CreditsMenuView~ipad.xib new file mode 100755 index 0000000..a9c6311 --- /dev/null +++ b/DoomClassic/code/iphone/CreditsMenuView~ipad.xib @@ -0,0 +1,369 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DoomClassic/code/iphone/Doom.xcodeproj/_backup_project.bak b/DoomClassic/code/iphone/Doom.xcodeproj/_backup_project.bak new file mode 100755 index 0000000..41f01b0 --- /dev/null +++ b/DoomClassic/code/iphone/Doom.xcodeproj/_backup_project.bak @@ -0,0 +1,1023 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 45; + objects = { + +/* Begin PBXBuildFile section */ + 1D60589B0D05DD56006BFB54 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; }; + 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; }; + 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */; }; + 28AD733F0D9D9553002E5188 /* MainWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 28AD733E0D9D9553002E5188 /* MainWindow.xib */; }; + 28FD15000DC6FC520079059D /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 28FD14FF0DC6FC520079059D /* OpenGLES.framework */; }; + 4333CCE80F5CC23E00AE2B6F /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4333CCE70F5CC23E00AE2B6F /* AudioToolbox.framework */; }; + 434669960F8D058400EA7D6D /* doom_icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 434669950F8D058400EA7D6D /* doom_icon.png */; }; + 434669A60F8D08C000EA7D6D /* doomAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 434669A50F8D08C000EA7D6D /* doomAppDelegate.m */; }; + 4364BF3F0F5CB25900F29317 /* dist.plist in Resources */ = {isa = PBXBuildFile; fileRef = 4364BF3E0F5CB25900F29317 /* dist.plist */; }; + 43A945150F82D75900FFD32E /* iphone_sys.c in Sources */ = {isa = PBXBuildFile; fileRef = 43A945140F82D75900FFD32E /* iphone_sys.c */; }; + 43AE7E9F0F67387500B2F562 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43AE7E9E0F67387500B2F562 /* CoreGraphics.framework */; }; + 43CF02FF0F56974E00E4A23D /* Default.png in Resources */ = {isa = PBXBuildFile; fileRef = 43CF02FE0F56974E00E4A23D /* Default.png */; }; + 43CF030A0F56D5C200E4A23D /* iphone_loop.c in Sources */ = {isa = PBXBuildFile; fileRef = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; }; + 43DD8392100295F70006E1DD /* iphone_async.c in Sources */ = {isa = PBXBuildFile; fileRef = 43DD8391100295F70006E1DD /* iphone_async.c */; }; + 43E8D2E10F4FC61E003F09B2 /* iphone_main.c in Sources */ = {isa = PBXBuildFile; fileRef = 43E8D2DF0F4FC61E003F09B2 /* iphone_main.c */; }; + 43E8D4E00F51B48B003F09B2 /* OpenAL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43E8D4DF0F51B48B003F09B2 /* OpenAL.framework */; }; + 720EBBAE0F82E0BB003F989A /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 720EBBAD0F82E0BB003F989A /* QuartzCore.framework */; }; + 7229CE4A0F6C89F8004123C5 /* EAGLView.m in Sources */ = {isa = PBXBuildFile; fileRef = 7229CE460F6C89F8004123C5 /* EAGLView.m */; }; + 7229CE550F6C8CDE004123C5 /* gles_glue.c in Sources */ = {isa = PBXBuildFile; fileRef = 7229CE540F6C8CDE004123C5 /* gles_glue.c */; }; + 7239452C0F9C0E7500EADD62 /* iphone_mapSelect.c in Sources */ = {isa = PBXBuildFile; fileRef = 7239452B0F9C0E7500EADD62 /* iphone_mapSelect.c */; }; + 72484E5E0FB0E99900124E1C /* iphone_render.c in Sources */ = {isa = PBXBuildFile; fileRef = 72484E5D0FB0E99900124E1C /* iphone_render.c */; }; + 724C531F0FBDBCEE000E4348 /* BackgroundMusic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 724C531E0FBDBCEE000E4348 /* BackgroundMusic.cpp */; }; + 72A55EEF1003A94300F788A5 /* iphone_start.c in Sources */ = {isa = PBXBuildFile; fileRef = 72A55EEE1003A94300F788A5 /* iphone_start.c */; }; + 72A560E21004FAEE00F788A5 /* iphone_net.c in Sources */ = {isa = PBXBuildFile; fileRef = 72A560E11004FAEE00F788A5 /* iphone_net.c */; }; + 72A7E8F70F5F2063005B83C0 /* iphone_menus.c in Sources */ = {isa = PBXBuildFile; fileRef = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; }; + 72B5FF390F7E5C3D00C8A372 /* hud.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B5FF380F7E5C3D00C8A372 /* hud.c */; }; + 72D50DBC0F8ED98000BB49E6 /* ipak.c in Sources */ = {isa = PBXBuildFile; fileRef = 72D50DBB0F8ED98000BB49E6 /* ipak.c */; }; + 72E731EB0F97E68100E702CD /* iphone_sound.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E731EA0F97E68100E702CD /* iphone_sound.c */; }; + 72E847650F93C61900AB3C99 /* am_map.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E847640F93C61900AB3C99 /* am_map.c */; }; + 72E847740F93FFDB00AB3C99 /* d_client.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E8476F0F93FFDB00AB3C99 /* d_client.c */; }; + 72E847750F93FFDB00AB3C99 /* d_deh.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E847700F93FFDB00AB3C99 /* d_deh.c */; }; + 72E847B20F9400D700AB3C99 /* d_items.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E8477A0F9400D700AB3C99 /* d_items.c */; }; + 72E847B30F9400D700AB3C99 /* d_main.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E8477C0F9400D700AB3C99 /* d_main.c */; }; + 72E847B50F9400D700AB3C99 /* doomdef.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E847840F9400D700AB3C99 /* doomdef.c */; }; + 72E847B60F9400D700AB3C99 /* doomstat.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E847860F9400D700AB3C99 /* doomstat.c */; }; + 72E847B70F9400D700AB3C99 /* dstrings.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E847890F9400D700AB3C99 /* dstrings.c */; }; + 72E847B80F9400D700AB3C99 /* f_finale.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E8478B0F9400D700AB3C99 /* f_finale.c */; }; + 72E847B90F9400D700AB3C99 /* f_wipe.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E8478D0F9400D700AB3C99 /* f_wipe.c */; }; + 72E847BA0F9400D700AB3C99 /* g_game.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E8478F0F9400D700AB3C99 /* g_game.c */; }; + 72E847BB0F9400D700AB3C99 /* gl_main.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E847920F9400D700AB3C99 /* gl_main.c */; }; + 72E847BC0F9400D700AB3C99 /* gl_texture.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E847940F9400D700AB3C99 /* gl_texture.c */; }; + 72E847BD0F9400D700AB3C99 /* hu_lib.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E847950F9400D700AB3C99 /* hu_lib.c */; }; + 72E847BE0F9400D700AB3C99 /* hu_stuff.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E847970F9400D700AB3C99 /* hu_stuff.c */; }; + 72E847BF0F9400D700AB3C99 /* info.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E8479F0F9400D700AB3C99 /* info.c */; }; + 72E847C00F9400D700AB3C99 /* lprintf.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E847A10F9400D700AB3C99 /* lprintf.c */; }; + 72E847C10F9400D700AB3C99 /* m_argv.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E847A30F9400D700AB3C99 /* m_argv.c */; }; + 72E847C20F9400D700AB3C99 /* m_bbox.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E847A50F9400D700AB3C99 /* m_bbox.c */; }; + 72E847C30F9400D700AB3C99 /* m_cheat.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E847A70F9400D700AB3C99 /* m_cheat.c */; }; + 72E847C40F9400D700AB3C99 /* m_menu.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E847AA0F9400D700AB3C99 /* m_menu.c */; }; + 72E847C50F9400D700AB3C99 /* m_misc.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E847AC0F9400D700AB3C99 /* m_misc.c */; }; + 72E847C60F9400D700AB3C99 /* m_random.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E847AE0F9400D700AB3C99 /* m_random.c */; }; + 72E848050F941A5900AB3C99 /* md5.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E847E00F941A5900AB3C99 /* md5.c */; }; + 72E848070F941A5900AB3C99 /* p_ceilng.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E847E40F941A5900AB3C99 /* p_ceilng.c */; }; + 72E848080F941A5900AB3C99 /* p_checksum.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E847E50F941A5900AB3C99 /* p_checksum.c */; }; + 72E848090F941A5900AB3C99 /* p_doors.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E847E70F941A5900AB3C99 /* p_doors.c */; }; + 72E8480A0F941A5900AB3C99 /* p_enemy.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E847E80F941A5900AB3C99 /* p_enemy.c */; }; + 72E8480B0F941A5900AB3C99 /* p_floor.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E847EA0F941A5900AB3C99 /* p_floor.c */; }; + 72E8480C0F941A5900AB3C99 /* p_genlin.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E847EB0F941A5900AB3C99 /* p_genlin.c */; }; + 72E8480D0F941A5900AB3C99 /* p_inter.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E847EC0F941A5900AB3C99 /* p_inter.c */; }; + 72E8480E0F941A5900AB3C99 /* p_lights.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E847EE0F941A5900AB3C99 /* p_lights.c */; }; + 72E8480F0F941A5900AB3C99 /* p_map.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E847EF0F941A5900AB3C99 /* p_map.c */; }; + 72E848100F941A5900AB3C99 /* p_maputl.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E847F10F941A5900AB3C99 /* p_maputl.c */; }; + 72E848110F941A5900AB3C99 /* p_mobj.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E847F30F941A5900AB3C99 /* p_mobj.c */; }; + 72E848120F941A5900AB3C99 /* p_plats.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E847F50F941A5900AB3C99 /* p_plats.c */; }; + 72E848130F941A5900AB3C99 /* p_pspr.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E847F60F941A5900AB3C99 /* p_pspr.c */; }; + 72E848140F941A5900AB3C99 /* p_saveg.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E847F80F941A5900AB3C99 /* p_saveg.c */; }; + 72E848150F941A5900AB3C99 /* p_setup.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E847FA0F941A5900AB3C99 /* p_setup.c */; }; + 72E848160F941A5900AB3C99 /* p_sight.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E847FC0F941A5900AB3C99 /* p_sight.c */; }; + 72E848170F941A5900AB3C99 /* p_spec.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E847FD0F941A5900AB3C99 /* p_spec.c */; }; + 72E848180F941A5900AB3C99 /* p_switch.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E847FF0F941A5900AB3C99 /* p_switch.c */; }; + 72E848190F941A5900AB3C99 /* p_telept.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E848000F941A5900AB3C99 /* p_telept.c */; }; + 72E8481A0F941A5900AB3C99 /* p_tick.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E848010F941A5900AB3C99 /* p_tick.c */; }; + 72E8481B0F941A5900AB3C99 /* p_user.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E848030F941A5900AB3C99 /* p_user.c */; }; + 72E848260F941A8300AB3C99 /* r_bsp.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E8481D0F941A8300AB3C99 /* r_bsp.c */; }; + 72E848270F941A8300AB3C99 /* r_data.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E8481F0F941A8300AB3C99 /* r_data.c */; }; + 72E848280F941A8300AB3C99 /* r_demo.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E848220F941A8300AB3C99 /* r_demo.c */; }; + 72E848290F941A8300AB3C99 /* r_draw.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E848240F941A8300AB3C99 /* r_draw.c */; }; + 72E8483D0F941AAC00AB3C99 /* r_filter.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E8482A0F941AAC00AB3C99 /* r_filter.c */; }; + 72E8483E0F941AAC00AB3C99 /* r_fps.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E8482C0F941AAC00AB3C99 /* r_fps.c */; }; + 72E8483F0F941AAC00AB3C99 /* r_main.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E8482E0F941AAC00AB3C99 /* r_main.c */; }; + 72E848400F941AAC00AB3C99 /* r_patch.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E848300F941AAC00AB3C99 /* r_patch.c */; }; + 72E848410F941AAC00AB3C99 /* r_plane.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E848320F941AAC00AB3C99 /* r_plane.c */; }; + 72E848420F941AAC00AB3C99 /* r_segs.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E848340F941AAC00AB3C99 /* r_segs.c */; }; + 72E848430F941AAC00AB3C99 /* r_sky.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E848360F941AAC00AB3C99 /* r_sky.c */; }; + 72E848440F941AAC00AB3C99 /* r_things.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E848390F941AAC00AB3C99 /* r_things.c */; }; + 72E848450F941AAC00AB3C99 /* s_sound.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E8483B0F941AAC00AB3C99 /* s_sound.c */; }; + 72E8485C0F941ADC00AB3C99 /* sounds.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E848460F941ADC00AB3C99 /* sounds.c */; }; + 72E8485D0F941ADC00AB3C99 /* st_lib.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E848480F941ADC00AB3C99 /* st_lib.c */; }; + 72E8485E0F941ADC00AB3C99 /* st_stuff.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E8484A0F941ADC00AB3C99 /* st_stuff.c */; }; + 72E8485F0F941ADC00AB3C99 /* tables.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E8484C0F941ADC00AB3C99 /* tables.c */; }; + 72E848600F941ADC00AB3C99 /* v_video.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E8484E0F941ADC00AB3C99 /* v_video.c */; }; + 72E848610F941ADC00AB3C99 /* version.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E848500F941ADC00AB3C99 /* version.c */; }; + 72E848630F941ADC00AB3C99 /* w_mmap.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E848530F941ADC00AB3C99 /* w_mmap.c */; }; + 72E848640F941ADC00AB3C99 /* w_wad.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E848540F941ADC00AB3C99 /* w_wad.c */; }; + 72E848650F941ADC00AB3C99 /* wi_stuff.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E848560F941ADC00AB3C99 /* wi_stuff.c */; }; + 72E848660F941ADC00AB3C99 /* z_bmalloc.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E848580F941ADC00AB3C99 /* z_bmalloc.c */; }; + 72E848670F941ADC00AB3C99 /* z_zone.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E8485A0F941ADC00AB3C99 /* z_zone.c */; }; + 72E849600F942B9300AB3C99 /* cvar.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E8495C0F942B9300AB3C99 /* cvar.c */; }; + 72E849610F942B9300AB3C99 /* misc.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E8495E0F942B9300AB3C99 /* misc.c */; }; + 72E849F60F94ED1100AB3C99 /* prboomInterface.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E849F50F94ED1100AB3C99 /* prboomInterface.c */; }; + 72E84A290F9503F100AB3C99 /* cmd.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E84A280F9503F100AB3C99 /* cmd.c */; }; + 72F1F9B40F96C18800AD49AC /* dict.c in Sources */ = {isa = PBXBuildFile; fileRef = 72F1F99D0F96C18800AD49AC /* dict.c */; }; + 72F1F9B50F96C18800AD49AC /* geom.c in Sources */ = {isa = PBXBuildFile; fileRef = 72F1F99F0F96C18800AD49AC /* geom.c */; }; + 72F1F9B60F96C18800AD49AC /* memalloc.c in Sources */ = {isa = PBXBuildFile; fileRef = 72F1F9A10F96C18800AD49AC /* memalloc.c */; }; + 72F1F9B70F96C18800AD49AC /* mesh.c in Sources */ = {isa = PBXBuildFile; fileRef = 72F1F9A30F96C18800AD49AC /* mesh.c */; }; + 72F1F9B80F96C18800AD49AC /* normal.c in Sources */ = {isa = PBXBuildFile; fileRef = 72F1F9A50F96C18800AD49AC /* normal.c */; }; + 72F1F9BA0F96C18800AD49AC /* priorityq.c in Sources */ = {isa = PBXBuildFile; fileRef = 72F1F9AA0F96C18800AD49AC /* priorityq.c */; }; + 72F1F9BB0F96C18800AD49AC /* render.c in Sources */ = {isa = PBXBuildFile; fileRef = 72F1F9AC0F96C18800AD49AC /* render.c */; }; + 72F1F9BC0F96C18800AD49AC /* sweep.c in Sources */ = {isa = PBXBuildFile; fileRef = 72F1F9AE0F96C18800AD49AC /* sweep.c */; }; + 72F1F9BD0F96C18800AD49AC /* tess.c in Sources */ = {isa = PBXBuildFile; fileRef = 72F1F9B00F96C18800AD49AC /* tess.c */; }; + 72F1F9BE0F96C18800AD49AC /* tessmono.c in Sources */ = {isa = PBXBuildFile; fileRef = 72F1F9B20F96C18800AD49AC /* tessmono.c */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 1D30AB110D05D00D00671497 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 1D6058910D05DD3D006BFB54 /* doom.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = doom.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; + 28AD733E0D9D9553002E5188 /* MainWindow.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MainWindow.xib; sourceTree = ""; }; + 28FD14FF0DC6FC520079059D /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = System/Library/Frameworks/OpenGLES.framework; sourceTree = SDKROOT; }; + 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 4333CCE70F5CC23E00AE2B6F /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = /System/Library/Frameworks/AudioToolbox.framework; sourceTree = ""; }; + 434669950F8D058400EA7D6D /* doom_icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = doom_icon.png; sourceTree = ""; }; + 434669A30F8D08C000EA7D6D /* doom_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = doom_Prefix.pch; sourceTree = ""; }; + 434669A40F8D08C000EA7D6D /* doomAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = doomAppDelegate.h; sourceTree = ""; }; + 434669A50F8D08C000EA7D6D /* doomAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = doomAppDelegate.m; sourceTree = ""; }; + 4364BF3E0F5CB25900F29317 /* dist.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = dist.plist; sourceTree = ""; }; + 43A945140F82D75900FFD32E /* iphone_sys.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = iphone_sys.c; sourceTree = ""; }; + 43AE7E9E0F67387500B2F562 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; + 43CF02FE0F56974E00E4A23D /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Default.png; sourceTree = ""; }; + 43CF03090F56D5C200E4A23D /* iphone_loop.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = iphone_loop.c; sourceTree = ""; }; + 43DD8391100295F70006E1DD /* iphone_async.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = iphone_async.c; sourceTree = ""; }; + 43E8D2DF0F4FC61E003F09B2 /* iphone_main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = iphone_main.c; sourceTree = ""; }; + 43E8D4DF0F51B48B003F09B2 /* OpenAL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenAL.framework; path = /System/Library/Frameworks/OpenAL.framework; sourceTree = ""; }; + 720EBBAD0F82E0BB003F989A /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = /System/Library/Frameworks/QuartzCore.framework; sourceTree = ""; }; + 7229CC8E0F6B3363004123C5 /* doomiphone.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = doomiphone.h; path = ../doomiphone.h; sourceTree = SOURCE_ROOT; }; + 7229CE450F6C89F8004123C5 /* EAGLView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EAGLView.h; sourceTree = ""; }; + 7229CE460F6C89F8004123C5 /* EAGLView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EAGLView.m; sourceTree = ""; }; + 7229CE540F6C8CDE004123C5 /* gles_glue.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gles_glue.c; sourceTree = ""; }; + 7239452B0F9C0E7500EADD62 /* iphone_mapSelect.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = iphone_mapSelect.c; sourceTree = ""; }; + 72484E5D0FB0E99900124E1C /* iphone_render.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = iphone_render.c; sourceTree = ""; }; + 724C531E0FBDBCEE000E4348 /* BackgroundMusic.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BackgroundMusic.cpp; sourceTree = ""; }; + 727886A20FBDBA740020D469 /* gles_glue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gles_glue.h; sourceTree = ""; }; + 72A55EEE1003A94300F788A5 /* iphone_start.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = iphone_start.c; sourceTree = ""; }; + 72A560E11004FAEE00F788A5 /* iphone_net.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = iphone_net.c; sourceTree = ""; }; + 72A7E8F30F5F2001005B83C0 /* iphone_doom.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = iphone_doom.h; sourceTree = ""; }; + 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = iphone_menus.c; sourceTree = ""; }; + 72B5FF380F7E5C3D00C8A372 /* hud.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hud.c; sourceTree = ""; }; + 72D50DBA0F8ED98000BB49E6 /* ipak.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ipak.h; sourceTree = ""; }; + 72D50DBB0F8ED98000BB49E6 /* ipak.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ipak.c; sourceTree = ""; }; + 72E731EA0F97E68100E702CD /* iphone_sound.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = iphone_sound.c; sourceTree = ""; }; + 72E847640F93C61900AB3C99 /* am_map.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = am_map.c; path = ../prboom/am_map.c; sourceTree = SOURCE_ROOT; }; + 72E847680F93FF2F00AB3C99 /* config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = config.h; path = ../prboom/config.h; sourceTree = SOURCE_ROOT; }; + 72E8476E0F93FFDB00AB3C99 /* am_map.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = am_map.h; path = ../prboom/am_map.h; sourceTree = SOURCE_ROOT; }; + 72E8476F0F93FFDB00AB3C99 /* d_client.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = d_client.c; path = ../prboom/d_client.c; sourceTree = SOURCE_ROOT; }; + 72E847700F93FFDB00AB3C99 /* d_deh.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = d_deh.c; path = ../prboom/d_deh.c; sourceTree = SOURCE_ROOT; }; + 72E847710F93FFDB00AB3C99 /* d_deh.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = d_deh.h; path = ../prboom/d_deh.h; sourceTree = SOURCE_ROOT; }; + 72E847720F93FFDB00AB3C99 /* d_englsh.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = d_englsh.h; path = ../prboom/d_englsh.h; sourceTree = SOURCE_ROOT; }; + 72E847730F93FFDB00AB3C99 /* d_event.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = d_event.h; path = ../prboom/d_event.h; sourceTree = SOURCE_ROOT; }; + 72E8477A0F9400D700AB3C99 /* d_items.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = d_items.c; path = ../prboom/d_items.c; sourceTree = SOURCE_ROOT; }; + 72E8477B0F9400D700AB3C99 /* d_items.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = d_items.h; path = ../prboom/d_items.h; sourceTree = SOURCE_ROOT; }; + 72E8477C0F9400D700AB3C99 /* d_main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = d_main.c; path = ../prboom/d_main.c; sourceTree = SOURCE_ROOT; }; + 72E8477D0F9400D700AB3C99 /* d_main.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = d_main.h; path = ../prboom/d_main.h; sourceTree = SOURCE_ROOT; }; + 72E8477E0F9400D700AB3C99 /* d_net.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = d_net.h; path = ../prboom/d_net.h; sourceTree = SOURCE_ROOT; }; + 72E8477F0F9400D700AB3C99 /* d_player.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = d_player.h; path = ../prboom/d_player.h; sourceTree = SOURCE_ROOT; }; + 72E847810F9400D700AB3C99 /* d_think.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = d_think.h; path = ../prboom/d_think.h; sourceTree = SOURCE_ROOT; }; + 72E847820F9400D700AB3C99 /* d_ticcmd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = d_ticcmd.h; path = ../prboom/d_ticcmd.h; sourceTree = SOURCE_ROOT; }; + 72E847830F9400D700AB3C99 /* doomdata.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = doomdata.h; path = ../prboom/doomdata.h; sourceTree = SOURCE_ROOT; }; + 72E847840F9400D700AB3C99 /* doomdef.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = doomdef.c; path = ../prboom/doomdef.c; sourceTree = SOURCE_ROOT; }; + 72E847850F9400D700AB3C99 /* doomdef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = doomdef.h; path = ../prboom/doomdef.h; sourceTree = SOURCE_ROOT; }; + 72E847860F9400D700AB3C99 /* doomstat.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = doomstat.c; path = ../prboom/doomstat.c; sourceTree = SOURCE_ROOT; }; + 72E847870F9400D700AB3C99 /* doomstat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = doomstat.h; path = ../prboom/doomstat.h; sourceTree = SOURCE_ROOT; }; + 72E847880F9400D700AB3C99 /* doomtype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = doomtype.h; path = ../prboom/doomtype.h; sourceTree = SOURCE_ROOT; }; + 72E847890F9400D700AB3C99 /* dstrings.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dstrings.c; path = ../prboom/dstrings.c; sourceTree = SOURCE_ROOT; }; + 72E8478A0F9400D700AB3C99 /* dstrings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dstrings.h; path = ../prboom/dstrings.h; sourceTree = SOURCE_ROOT; }; + 72E8478B0F9400D700AB3C99 /* f_finale.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = f_finale.c; path = ../prboom/f_finale.c; sourceTree = SOURCE_ROOT; }; + 72E8478C0F9400D700AB3C99 /* f_finale.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = f_finale.h; path = ../prboom/f_finale.h; sourceTree = SOURCE_ROOT; }; + 72E8478D0F9400D700AB3C99 /* f_wipe.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = f_wipe.c; path = ../prboom/f_wipe.c; sourceTree = SOURCE_ROOT; }; + 72E8478E0F9400D700AB3C99 /* f_wipe.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = f_wipe.h; path = ../prboom/f_wipe.h; sourceTree = SOURCE_ROOT; }; + 72E8478F0F9400D700AB3C99 /* g_game.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = g_game.c; path = ../prboom/g_game.c; sourceTree = SOURCE_ROOT; }; + 72E847900F9400D700AB3C99 /* g_game.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = g_game.h; path = ../prboom/g_game.h; sourceTree = SOURCE_ROOT; }; + 72E847910F9400D700AB3C99 /* gl_intern.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = gl_intern.h; path = ../prboom/gl_intern.h; sourceTree = SOURCE_ROOT; }; + 72E847920F9400D700AB3C99 /* gl_main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = gl_main.c; path = ../prboom/gl_main.c; sourceTree = SOURCE_ROOT; }; + 72E847930F9400D700AB3C99 /* gl_struct.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = gl_struct.h; path = ../prboom/gl_struct.h; sourceTree = SOURCE_ROOT; }; + 72E847940F9400D700AB3C99 /* gl_texture.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = gl_texture.c; path = ../prboom/gl_texture.c; sourceTree = SOURCE_ROOT; }; + 72E847950F9400D700AB3C99 /* hu_lib.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = hu_lib.c; path = ../prboom/hu_lib.c; sourceTree = SOURCE_ROOT; }; + 72E847960F9400D700AB3C99 /* hu_lib.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = hu_lib.h; path = ../prboom/hu_lib.h; sourceTree = SOURCE_ROOT; }; + 72E847970F9400D700AB3C99 /* hu_stuff.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = hu_stuff.c; path = ../prboom/hu_stuff.c; sourceTree = SOURCE_ROOT; }; + 72E847980F9400D700AB3C99 /* hu_stuff.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = hu_stuff.h; path = ../prboom/hu_stuff.h; sourceTree = SOURCE_ROOT; }; + 72E847990F9400D700AB3C99 /* i_joy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = i_joy.h; path = ../prboom/i_joy.h; sourceTree = SOURCE_ROOT; }; + 72E8479A0F9400D700AB3C99 /* i_main.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = i_main.h; path = ../prboom/i_main.h; sourceTree = SOURCE_ROOT; }; + 72E8479B0F9400D700AB3C99 /* i_network.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = i_network.h; path = ../prboom/i_network.h; sourceTree = SOURCE_ROOT; }; + 72E8479C0F9400D700AB3C99 /* i_sound.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = i_sound.h; path = ../prboom/i_sound.h; sourceTree = SOURCE_ROOT; }; + 72E8479D0F9400D700AB3C99 /* i_system.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = i_system.h; path = ../prboom/i_system.h; sourceTree = SOURCE_ROOT; }; + 72E8479E0F9400D700AB3C99 /* i_video.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = i_video.h; path = ../prboom/i_video.h; sourceTree = SOURCE_ROOT; }; + 72E8479F0F9400D700AB3C99 /* info.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = info.c; path = ../prboom/info.c; sourceTree = SOURCE_ROOT; }; + 72E847A00F9400D700AB3C99 /* info.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = info.h; path = ../prboom/info.h; sourceTree = SOURCE_ROOT; }; + 72E847A10F9400D700AB3C99 /* lprintf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = lprintf.c; path = ../prboom/lprintf.c; sourceTree = SOURCE_ROOT; }; + 72E847A20F9400D700AB3C99 /* lprintf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = lprintf.h; path = ../prboom/lprintf.h; sourceTree = SOURCE_ROOT; }; + 72E847A30F9400D700AB3C99 /* m_argv.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = m_argv.c; path = ../prboom/m_argv.c; sourceTree = SOURCE_ROOT; }; + 72E847A40F9400D700AB3C99 /* m_argv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = m_argv.h; path = ../prboom/m_argv.h; sourceTree = SOURCE_ROOT; }; + 72E847A50F9400D700AB3C99 /* m_bbox.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = m_bbox.c; path = ../prboom/m_bbox.c; sourceTree = SOURCE_ROOT; }; + 72E847A60F9400D700AB3C99 /* m_bbox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = m_bbox.h; path = ../prboom/m_bbox.h; sourceTree = SOURCE_ROOT; }; + 72E847A70F9400D700AB3C99 /* m_cheat.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = m_cheat.c; path = ../prboom/m_cheat.c; sourceTree = SOURCE_ROOT; }; + 72E847A80F9400D700AB3C99 /* m_cheat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = m_cheat.h; path = ../prboom/m_cheat.h; sourceTree = SOURCE_ROOT; }; + 72E847A90F9400D700AB3C99 /* m_fixed.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = m_fixed.h; path = ../prboom/m_fixed.h; sourceTree = SOURCE_ROOT; }; + 72E847AA0F9400D700AB3C99 /* m_menu.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = m_menu.c; path = ../prboom/m_menu.c; sourceTree = SOURCE_ROOT; }; + 72E847AB0F9400D700AB3C99 /* m_menu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = m_menu.h; path = ../prboom/m_menu.h; sourceTree = SOURCE_ROOT; }; + 72E847AC0F9400D700AB3C99 /* m_misc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = m_misc.c; path = ../prboom/m_misc.c; sourceTree = SOURCE_ROOT; }; + 72E847AD0F9400D700AB3C99 /* m_misc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = m_misc.h; path = ../prboom/m_misc.h; sourceTree = SOURCE_ROOT; }; + 72E847AE0F9400D700AB3C99 /* m_random.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = m_random.c; path = ../prboom/m_random.c; sourceTree = SOURCE_ROOT; }; + 72E847AF0F9400D700AB3C99 /* m_random.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = m_random.h; path = ../prboom/m_random.h; sourceTree = SOURCE_ROOT; }; + 72E847B00F9400D700AB3C99 /* m_swap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = m_swap.h; path = ../prboom/m_swap.h; sourceTree = SOURCE_ROOT; }; + 72E847CA0F94096C00AB3C99 /* SDL_opengl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SDL_opengl.h; path = ../prboom/SDL_opengl.h; sourceTree = SOURCE_ROOT; }; + 72E847E00F941A5900AB3C99 /* md5.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = md5.c; path = ../prboom/md5.c; sourceTree = SOURCE_ROOT; }; + 72E847E10F941A5900AB3C99 /* md5.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = md5.h; path = ../prboom/md5.h; sourceTree = SOURCE_ROOT; }; + 72E847E40F941A5900AB3C99 /* p_ceilng.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = p_ceilng.c; path = ../prboom/p_ceilng.c; sourceTree = SOURCE_ROOT; }; + 72E847E50F941A5900AB3C99 /* p_checksum.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = p_checksum.c; path = ../prboom/p_checksum.c; sourceTree = SOURCE_ROOT; }; + 72E847E60F941A5900AB3C99 /* p_checksum.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = p_checksum.h; path = ../prboom/p_checksum.h; sourceTree = SOURCE_ROOT; }; + 72E847E70F941A5900AB3C99 /* p_doors.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = p_doors.c; path = ../prboom/p_doors.c; sourceTree = SOURCE_ROOT; }; + 72E847E80F941A5900AB3C99 /* p_enemy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = p_enemy.c; path = ../prboom/p_enemy.c; sourceTree = SOURCE_ROOT; }; + 72E847E90F941A5900AB3C99 /* p_enemy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = p_enemy.h; path = ../prboom/p_enemy.h; sourceTree = SOURCE_ROOT; }; + 72E847EA0F941A5900AB3C99 /* p_floor.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = p_floor.c; path = ../prboom/p_floor.c; sourceTree = SOURCE_ROOT; }; + 72E847EB0F941A5900AB3C99 /* p_genlin.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = p_genlin.c; path = ../prboom/p_genlin.c; sourceTree = SOURCE_ROOT; }; + 72E847EC0F941A5900AB3C99 /* p_inter.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = p_inter.c; path = ../prboom/p_inter.c; sourceTree = SOURCE_ROOT; }; + 72E847ED0F941A5900AB3C99 /* p_inter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = p_inter.h; path = ../prboom/p_inter.h; sourceTree = SOURCE_ROOT; }; + 72E847EE0F941A5900AB3C99 /* p_lights.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = p_lights.c; path = ../prboom/p_lights.c; sourceTree = SOURCE_ROOT; }; + 72E847EF0F941A5900AB3C99 /* p_map.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = p_map.c; path = ../prboom/p_map.c; sourceTree = SOURCE_ROOT; }; + 72E847F00F941A5900AB3C99 /* p_map.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = p_map.h; path = ../prboom/p_map.h; sourceTree = SOURCE_ROOT; }; + 72E847F10F941A5900AB3C99 /* p_maputl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = p_maputl.c; path = ../prboom/p_maputl.c; sourceTree = SOURCE_ROOT; }; + 72E847F20F941A5900AB3C99 /* p_maputl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = p_maputl.h; path = ../prboom/p_maputl.h; sourceTree = SOURCE_ROOT; }; + 72E847F30F941A5900AB3C99 /* p_mobj.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = p_mobj.c; path = ../prboom/p_mobj.c; sourceTree = SOURCE_ROOT; }; + 72E847F40F941A5900AB3C99 /* p_mobj.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = p_mobj.h; path = ../prboom/p_mobj.h; sourceTree = SOURCE_ROOT; }; + 72E847F50F941A5900AB3C99 /* p_plats.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = p_plats.c; path = ../prboom/p_plats.c; sourceTree = SOURCE_ROOT; }; + 72E847F60F941A5900AB3C99 /* p_pspr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = p_pspr.c; path = ../prboom/p_pspr.c; sourceTree = SOURCE_ROOT; }; + 72E847F70F941A5900AB3C99 /* p_pspr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = p_pspr.h; path = ../prboom/p_pspr.h; sourceTree = SOURCE_ROOT; }; + 72E847F80F941A5900AB3C99 /* p_saveg.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = p_saveg.c; path = ../prboom/p_saveg.c; sourceTree = SOURCE_ROOT; }; + 72E847F90F941A5900AB3C99 /* p_saveg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = p_saveg.h; path = ../prboom/p_saveg.h; sourceTree = SOURCE_ROOT; }; + 72E847FA0F941A5900AB3C99 /* p_setup.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = p_setup.c; path = ../prboom/p_setup.c; sourceTree = SOURCE_ROOT; }; + 72E847FB0F941A5900AB3C99 /* p_setup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = p_setup.h; path = ../prboom/p_setup.h; sourceTree = SOURCE_ROOT; }; + 72E847FC0F941A5900AB3C99 /* p_sight.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = p_sight.c; path = ../prboom/p_sight.c; sourceTree = SOURCE_ROOT; }; + 72E847FD0F941A5900AB3C99 /* p_spec.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = p_spec.c; path = ../prboom/p_spec.c; sourceTree = SOURCE_ROOT; }; + 72E847FE0F941A5900AB3C99 /* p_spec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = p_spec.h; path = ../prboom/p_spec.h; sourceTree = SOURCE_ROOT; }; + 72E847FF0F941A5900AB3C99 /* p_switch.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = p_switch.c; path = ../prboom/p_switch.c; sourceTree = SOURCE_ROOT; }; + 72E848000F941A5900AB3C99 /* p_telept.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = p_telept.c; path = ../prboom/p_telept.c; sourceTree = SOURCE_ROOT; }; + 72E848010F941A5900AB3C99 /* p_tick.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = p_tick.c; path = ../prboom/p_tick.c; sourceTree = SOURCE_ROOT; }; + 72E848020F941A5900AB3C99 /* p_tick.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = p_tick.h; path = ../prboom/p_tick.h; sourceTree = SOURCE_ROOT; }; + 72E848030F941A5900AB3C99 /* p_user.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = p_user.c; path = ../prboom/p_user.c; sourceTree = SOURCE_ROOT; }; + 72E848040F941A5900AB3C99 /* p_user.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = p_user.h; path = ../prboom/p_user.h; sourceTree = SOURCE_ROOT; }; + 72E8481C0F941A8300AB3C99 /* protocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = protocol.h; path = ../prboom/protocol.h; sourceTree = SOURCE_ROOT; }; + 72E8481D0F941A8300AB3C99 /* r_bsp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = r_bsp.c; path = ../prboom/r_bsp.c; sourceTree = SOURCE_ROOT; }; + 72E8481E0F941A8300AB3C99 /* r_bsp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = r_bsp.h; path = ../prboom/r_bsp.h; sourceTree = SOURCE_ROOT; }; + 72E8481F0F941A8300AB3C99 /* r_data.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = r_data.c; path = ../prboom/r_data.c; sourceTree = SOURCE_ROOT; }; + 72E848200F941A8300AB3C99 /* r_data.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = r_data.h; path = ../prboom/r_data.h; sourceTree = SOURCE_ROOT; }; + 72E848210F941A8300AB3C99 /* r_defs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = r_defs.h; path = ../prboom/r_defs.h; sourceTree = SOURCE_ROOT; }; + 72E848220F941A8300AB3C99 /* r_demo.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = r_demo.c; path = ../prboom/r_demo.c; sourceTree = SOURCE_ROOT; }; + 72E848230F941A8300AB3C99 /* r_demo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = r_demo.h; path = ../prboom/r_demo.h; sourceTree = SOURCE_ROOT; }; + 72E848240F941A8300AB3C99 /* r_draw.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = r_draw.c; path = ../prboom/r_draw.c; sourceTree = SOURCE_ROOT; }; + 72E848250F941A8300AB3C99 /* r_draw.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = r_draw.h; path = ../prboom/r_draw.h; sourceTree = SOURCE_ROOT; }; + 72E8482A0F941AAC00AB3C99 /* r_filter.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = r_filter.c; path = ../prboom/r_filter.c; sourceTree = SOURCE_ROOT; }; + 72E8482B0F941AAC00AB3C99 /* r_filter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = r_filter.h; path = ../prboom/r_filter.h; sourceTree = SOURCE_ROOT; }; + 72E8482C0F941AAC00AB3C99 /* r_fps.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = r_fps.c; path = ../prboom/r_fps.c; sourceTree = SOURCE_ROOT; }; + 72E8482D0F941AAC00AB3C99 /* r_fps.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = r_fps.h; path = ../prboom/r_fps.h; sourceTree = SOURCE_ROOT; }; + 72E8482E0F941AAC00AB3C99 /* r_main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = r_main.c; path = ../prboom/r_main.c; sourceTree = SOURCE_ROOT; }; + 72E8482F0F941AAC00AB3C99 /* r_main.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = r_main.h; path = ../prboom/r_main.h; sourceTree = SOURCE_ROOT; }; + 72E848300F941AAC00AB3C99 /* r_patch.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = r_patch.c; path = ../prboom/r_patch.c; sourceTree = SOURCE_ROOT; }; + 72E848310F941AAC00AB3C99 /* r_patch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = r_patch.h; path = ../prboom/r_patch.h; sourceTree = SOURCE_ROOT; }; + 72E848320F941AAC00AB3C99 /* r_plane.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = r_plane.c; path = ../prboom/r_plane.c; sourceTree = SOURCE_ROOT; }; + 72E848330F941AAC00AB3C99 /* r_plane.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = r_plane.h; path = ../prboom/r_plane.h; sourceTree = SOURCE_ROOT; }; + 72E848340F941AAC00AB3C99 /* r_segs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = r_segs.c; path = ../prboom/r_segs.c; sourceTree = SOURCE_ROOT; }; + 72E848350F941AAC00AB3C99 /* r_segs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = r_segs.h; path = ../prboom/r_segs.h; sourceTree = SOURCE_ROOT; }; + 72E848360F941AAC00AB3C99 /* r_sky.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = r_sky.c; path = ../prboom/r_sky.c; sourceTree = SOURCE_ROOT; }; + 72E848370F941AAC00AB3C99 /* r_sky.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = r_sky.h; path = ../prboom/r_sky.h; sourceTree = SOURCE_ROOT; }; + 72E848380F941AAC00AB3C99 /* r_state.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = r_state.h; path = ../prboom/r_state.h; sourceTree = SOURCE_ROOT; }; + 72E848390F941AAC00AB3C99 /* r_things.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = r_things.c; path = ../prboom/r_things.c; sourceTree = SOURCE_ROOT; }; + 72E8483A0F941AAC00AB3C99 /* r_things.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = r_things.h; path = ../prboom/r_things.h; sourceTree = SOURCE_ROOT; }; + 72E8483B0F941AAC00AB3C99 /* s_sound.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = s_sound.c; path = ../prboom/s_sound.c; sourceTree = SOURCE_ROOT; }; + 72E8483C0F941AAC00AB3C99 /* s_sound.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = s_sound.h; path = ../prboom/s_sound.h; sourceTree = SOURCE_ROOT; }; + 72E848460F941ADC00AB3C99 /* sounds.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = sounds.c; path = ../prboom/sounds.c; sourceTree = SOURCE_ROOT; }; + 72E848470F941ADC00AB3C99 /* sounds.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sounds.h; path = ../prboom/sounds.h; sourceTree = SOURCE_ROOT; }; + 72E848480F941ADC00AB3C99 /* st_lib.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = st_lib.c; path = ../prboom/st_lib.c; sourceTree = SOURCE_ROOT; }; + 72E848490F941ADC00AB3C99 /* st_lib.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = st_lib.h; path = ../prboom/st_lib.h; sourceTree = SOURCE_ROOT; }; + 72E8484A0F941ADC00AB3C99 /* st_stuff.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = st_stuff.c; path = ../prboom/st_stuff.c; sourceTree = SOURCE_ROOT; }; + 72E8484B0F941ADC00AB3C99 /* st_stuff.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = st_stuff.h; path = ../prboom/st_stuff.h; sourceTree = SOURCE_ROOT; }; + 72E8484C0F941ADC00AB3C99 /* tables.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = tables.c; path = ../prboom/tables.c; sourceTree = SOURCE_ROOT; }; + 72E8484D0F941ADC00AB3C99 /* tables.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = tables.h; path = ../prboom/tables.h; sourceTree = SOURCE_ROOT; }; + 72E8484E0F941ADC00AB3C99 /* v_video.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = v_video.c; path = ../prboom/v_video.c; sourceTree = SOURCE_ROOT; }; + 72E8484F0F941ADC00AB3C99 /* v_video.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = v_video.h; path = ../prboom/v_video.h; sourceTree = SOURCE_ROOT; }; + 72E848500F941ADC00AB3C99 /* version.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = version.c; path = ../prboom/version.c; sourceTree = SOURCE_ROOT; }; + 72E848510F941ADC00AB3C99 /* version.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = version.h; path = ../prboom/version.h; sourceTree = SOURCE_ROOT; }; + 72E848530F941ADC00AB3C99 /* w_mmap.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = w_mmap.c; path = ../prboom/w_mmap.c; sourceTree = SOURCE_ROOT; }; + 72E848540F941ADC00AB3C99 /* w_wad.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = w_wad.c; path = ../prboom/w_wad.c; sourceTree = SOURCE_ROOT; }; + 72E848550F941ADC00AB3C99 /* w_wad.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = w_wad.h; path = ../prboom/w_wad.h; sourceTree = SOURCE_ROOT; }; + 72E848560F941ADC00AB3C99 /* wi_stuff.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wi_stuff.c; path = ../prboom/wi_stuff.c; sourceTree = SOURCE_ROOT; }; + 72E848570F941ADC00AB3C99 /* wi_stuff.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = wi_stuff.h; path = ../prboom/wi_stuff.h; sourceTree = SOURCE_ROOT; }; + 72E848580F941ADC00AB3C99 /* z_bmalloc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = z_bmalloc.c; path = ../prboom/z_bmalloc.c; sourceTree = SOURCE_ROOT; }; + 72E848590F941ADC00AB3C99 /* z_bmalloc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = z_bmalloc.h; path = ../prboom/z_bmalloc.h; sourceTree = SOURCE_ROOT; }; + 72E8485A0F941ADC00AB3C99 /* z_zone.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = z_zone.c; path = ../prboom/z_zone.c; sourceTree = SOURCE_ROOT; }; + 72E8485B0F941ADC00AB3C99 /* z_zone.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = z_zone.h; path = ../prboom/z_zone.h; sourceTree = SOURCE_ROOT; }; + 72E8495C0F942B9300AB3C99 /* cvar.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cvar.c; sourceTree = ""; }; + 72E8495D0F942B9300AB3C99 /* cvar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cvar.h; sourceTree = ""; }; + 72E8495E0F942B9300AB3C99 /* misc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = misc.c; sourceTree = ""; }; + 72E8495F0F942B9300AB3C99 /* misc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = misc.h; sourceTree = ""; }; + 72E849F50F94ED1100AB3C99 /* prboomInterface.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = prboomInterface.c; sourceTree = ""; }; + 72E84A280F9503F100AB3C99 /* cmd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cmd.c; sourceTree = ""; }; + 72F1F99C0F96C18800AD49AC /* dict-list.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "dict-list.h"; path = "../libtess/dict-list.h"; sourceTree = SOURCE_ROOT; }; + 72F1F99D0F96C18800AD49AC /* dict.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dict.c; path = ../libtess/dict.c; sourceTree = SOURCE_ROOT; }; + 72F1F99E0F96C18800AD49AC /* dict.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dict.h; path = ../libtess/dict.h; sourceTree = SOURCE_ROOT; }; + 72F1F99F0F96C18800AD49AC /* geom.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = geom.c; path = ../libtess/geom.c; sourceTree = SOURCE_ROOT; }; + 72F1F9A00F96C18800AD49AC /* geom.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = geom.h; path = ../libtess/geom.h; sourceTree = SOURCE_ROOT; }; + 72F1F9A10F96C18800AD49AC /* memalloc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = memalloc.c; path = ../libtess/memalloc.c; sourceTree = SOURCE_ROOT; }; + 72F1F9A20F96C18800AD49AC /* memalloc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = memalloc.h; path = ../libtess/memalloc.h; sourceTree = SOURCE_ROOT; }; + 72F1F9A30F96C18800AD49AC /* mesh.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mesh.c; path = ../libtess/mesh.c; sourceTree = SOURCE_ROOT; }; + 72F1F9A40F96C18800AD49AC /* mesh.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mesh.h; path = ../libtess/mesh.h; sourceTree = SOURCE_ROOT; }; + 72F1F9A50F96C18800AD49AC /* normal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = normal.c; path = ../libtess/normal.c; sourceTree = SOURCE_ROOT; }; + 72F1F9A60F96C18800AD49AC /* normal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = normal.h; path = ../libtess/normal.h; sourceTree = SOURCE_ROOT; }; + 72F1F9A80F96C18800AD49AC /* priorityq-heap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "priorityq-heap.h"; path = "../libtess/priorityq-heap.h"; sourceTree = SOURCE_ROOT; }; + 72F1F9A90F96C18800AD49AC /* priorityq-sort.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "priorityq-sort.h"; path = "../libtess/priorityq-sort.h"; sourceTree = SOURCE_ROOT; }; + 72F1F9AA0F96C18800AD49AC /* priorityq.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = priorityq.c; path = ../libtess/priorityq.c; sourceTree = SOURCE_ROOT; }; + 72F1F9AB0F96C18800AD49AC /* priorityq.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = priorityq.h; path = ../libtess/priorityq.h; sourceTree = SOURCE_ROOT; }; + 72F1F9AC0F96C18800AD49AC /* render.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = render.c; path = ../libtess/render.c; sourceTree = SOURCE_ROOT; }; + 72F1F9AD0F96C18800AD49AC /* render.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = render.h; path = ../libtess/render.h; sourceTree = SOURCE_ROOT; }; + 72F1F9AE0F96C18800AD49AC /* sweep.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = sweep.c; path = ../libtess/sweep.c; sourceTree = SOURCE_ROOT; }; + 72F1F9AF0F96C18800AD49AC /* sweep.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sweep.h; path = ../libtess/sweep.h; sourceTree = SOURCE_ROOT; }; + 72F1F9B00F96C18800AD49AC /* tess.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = tess.c; path = ../libtess/tess.c; sourceTree = SOURCE_ROOT; }; + 72F1F9B10F96C18800AD49AC /* tess.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = tess.h; path = ../libtess/tess.h; sourceTree = SOURCE_ROOT; }; + 72F1F9B20F96C18800AD49AC /* tessmono.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = tessmono.c; path = ../libtess/tessmono.c; sourceTree = SOURCE_ROOT; }; + 72F1F9B30F96C18800AD49AC /* tessmono.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = tessmono.h; path = ../libtess/tessmono.h; sourceTree = SOURCE_ROOT; }; + 8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 1D60588F0D05DD3D006BFB54 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */, + 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */, + 28FD15000DC6FC520079059D /* OpenGLES.framework in Frameworks */, + 43E8D4E00F51B48B003F09B2 /* OpenAL.framework in Frameworks */, + 4333CCE80F5CC23E00AE2B6F /* AudioToolbox.framework in Frameworks */, + 43AE7E9F0F67387500B2F562 /* CoreGraphics.framework in Frameworks */, + 720EBBAE0F82E0BB003F989A /* QuartzCore.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 19C28FACFE9D520D11CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + 1D6058910D05DD3D006BFB54 /* doom.app */, + 4364BF3E0F5CB25900F29317 /* dist.plist */, + ); + name = Products; + sourceTree = ""; + }; + 29B97314FDCFA39411CA2CEA /* CustomTemplate */ = { + isa = PBXGroup; + children = ( + 29B97315FDCFA39411CA2CEA /* Other Sources */, + 29B97317FDCFA39411CA2CEA /* Resources */, + 29B97323FDCFA39411CA2CEA /* Frameworks */, + 19C28FACFE9D520D11CA2CBB /* Products */, + 43AE7E9E0F67387500B2F562 /* CoreGraphics.framework */, + ); + name = CustomTemplate; + sourceTree = ""; + }; + 29B97315FDCFA39411CA2CEA /* Other Sources */ = { + isa = PBXGroup; + children = ( + 72F1F94B0F96B55B00AD49AC /* libtess */, + 72E847620F93C5F900AB3C99 /* prboom */, + 72E8495C0F942B9300AB3C99 /* cvar.c */, + 72E8495D0F942B9300AB3C99 /* cvar.h */, + 72E84A280F9503F100AB3C99 /* cmd.c */, + 72E8495E0F942B9300AB3C99 /* misc.c */, + 72E8495F0F942B9300AB3C99 /* misc.h */, + 434669A30F8D08C000EA7D6D /* doom_Prefix.pch */, + 434669A40F8D08C000EA7D6D /* doomAppDelegate.h */, + 434669A50F8D08C000EA7D6D /* doomAppDelegate.m */, + 29B97316FDCFA39411CA2CEA /* main.m */, + 724C531E0FBDBCEE000E4348 /* BackgroundMusic.cpp */, + 7229CE540F6C8CDE004123C5 /* gles_glue.c */, + 727886A20FBDBA740020D469 /* gles_glue.h */, + 7229CE450F6C89F8004123C5 /* EAGLView.h */, + 7229CE460F6C89F8004123C5 /* EAGLView.m */, + 72B5FF380F7E5C3D00C8A372 /* hud.c */, + 7229CC8E0F6B3363004123C5 /* doomiphone.h */, + 72D50DBA0F8ED98000BB49E6 /* ipak.h */, + 72D50DBB0F8ED98000BB49E6 /* ipak.c */, + 72E849F50F94ED1100AB3C99 /* prboomInterface.c */, + 43A945140F82D75900FFD32E /* iphone_sys.c */, + 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */, + 72A560E11004FAEE00F788A5 /* iphone_net.c */, + 72E731EA0F97E68100E702CD /* iphone_sound.c */, + 7239452B0F9C0E7500EADD62 /* iphone_mapSelect.c */, + 72484E5D0FB0E99900124E1C /* iphone_render.c */, + 43CF03090F56D5C200E4A23D /* iphone_loop.c */, + 72A7E8F30F5F2001005B83C0 /* iphone_doom.h */, + 43E8D2DF0F4FC61E003F09B2 /* iphone_main.c */, + 43DD8391100295F70006E1DD /* iphone_async.c */, + 72A55EEE1003A94300F788A5 /* iphone_start.c */, + ); + name = "Other Sources"; + sourceTree = ""; + }; + 29B97317FDCFA39411CA2CEA /* Resources */ = { + isa = PBXGroup; + children = ( + 434669950F8D058400EA7D6D /* doom_icon.png */, + 43CF02FE0F56974E00E4A23D /* Default.png */, + 28AD733E0D9D9553002E5188 /* MainWindow.xib */, + 8D1107310486CEB800E47090 /* Info.plist */, + ); + name = Resources; + sourceTree = ""; + }; + 29B97323FDCFA39411CA2CEA /* Frameworks */ = { + isa = PBXGroup; + children = ( + 720EBBAD0F82E0BB003F989A /* QuartzCore.framework */, + 4333CCE70F5CC23E00AE2B6F /* AudioToolbox.framework */, + 43E8D4DF0F51B48B003F09B2 /* OpenAL.framework */, + 28FD14FF0DC6FC520079059D /* OpenGLES.framework */, + 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */, + 1D30AB110D05D00D00671497 /* Foundation.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 72E847620F93C5F900AB3C99 /* prboom */ = { + isa = PBXGroup; + children = ( + 72E848460F941ADC00AB3C99 /* sounds.c */, + 72E848470F941ADC00AB3C99 /* sounds.h */, + 72E848480F941ADC00AB3C99 /* st_lib.c */, + 72E848490F941ADC00AB3C99 /* st_lib.h */, + 72E8484A0F941ADC00AB3C99 /* st_stuff.c */, + 72E8484B0F941ADC00AB3C99 /* st_stuff.h */, + 72E8484C0F941ADC00AB3C99 /* tables.c */, + 72E8484D0F941ADC00AB3C99 /* tables.h */, + 72E8484E0F941ADC00AB3C99 /* v_video.c */, + 72E8484F0F941ADC00AB3C99 /* v_video.h */, + 72E848500F941ADC00AB3C99 /* version.c */, + 72E848510F941ADC00AB3C99 /* version.h */, + 72E848530F941ADC00AB3C99 /* w_mmap.c */, + 72E848540F941ADC00AB3C99 /* w_wad.c */, + 72E848550F941ADC00AB3C99 /* w_wad.h */, + 72E848560F941ADC00AB3C99 /* wi_stuff.c */, + 72E848570F941ADC00AB3C99 /* wi_stuff.h */, + 72E848580F941ADC00AB3C99 /* z_bmalloc.c */, + 72E848590F941ADC00AB3C99 /* z_bmalloc.h */, + 72E8485A0F941ADC00AB3C99 /* z_zone.c */, + 72E8485B0F941ADC00AB3C99 /* z_zone.h */, + 72E8482A0F941AAC00AB3C99 /* r_filter.c */, + 72E8482B0F941AAC00AB3C99 /* r_filter.h */, + 72E8482C0F941AAC00AB3C99 /* r_fps.c */, + 72E8482D0F941AAC00AB3C99 /* r_fps.h */, + 72E8482E0F941AAC00AB3C99 /* r_main.c */, + 72E8482F0F941AAC00AB3C99 /* r_main.h */, + 72E848300F941AAC00AB3C99 /* r_patch.c */, + 72E848310F941AAC00AB3C99 /* r_patch.h */, + 72E848320F941AAC00AB3C99 /* r_plane.c */, + 72E848330F941AAC00AB3C99 /* r_plane.h */, + 72E848340F941AAC00AB3C99 /* r_segs.c */, + 72E848350F941AAC00AB3C99 /* r_segs.h */, + 72E848360F941AAC00AB3C99 /* r_sky.c */, + 72E848370F941AAC00AB3C99 /* r_sky.h */, + 72E848380F941AAC00AB3C99 /* r_state.h */, + 72E848390F941AAC00AB3C99 /* r_things.c */, + 72E8483A0F941AAC00AB3C99 /* r_things.h */, + 72E8483B0F941AAC00AB3C99 /* s_sound.c */, + 72E8483C0F941AAC00AB3C99 /* s_sound.h */, + 72E8481C0F941A8300AB3C99 /* protocol.h */, + 72E8481D0F941A8300AB3C99 /* r_bsp.c */, + 72E8481E0F941A8300AB3C99 /* r_bsp.h */, + 72E8481F0F941A8300AB3C99 /* r_data.c */, + 72E848200F941A8300AB3C99 /* r_data.h */, + 72E848210F941A8300AB3C99 /* r_defs.h */, + 72E848220F941A8300AB3C99 /* r_demo.c */, + 72E848230F941A8300AB3C99 /* r_demo.h */, + 72E848240F941A8300AB3C99 /* r_draw.c */, + 72E848250F941A8300AB3C99 /* r_draw.h */, + 72E847E00F941A5900AB3C99 /* md5.c */, + 72E847E10F941A5900AB3C99 /* md5.h */, + 72E847E40F941A5900AB3C99 /* p_ceilng.c */, + 72E847E50F941A5900AB3C99 /* p_checksum.c */, + 72E847E60F941A5900AB3C99 /* p_checksum.h */, + 72E847E70F941A5900AB3C99 /* p_doors.c */, + 72E847E80F941A5900AB3C99 /* p_enemy.c */, + 72E847E90F941A5900AB3C99 /* p_enemy.h */, + 72E847EA0F941A5900AB3C99 /* p_floor.c */, + 72E847EB0F941A5900AB3C99 /* p_genlin.c */, + 72E847EC0F941A5900AB3C99 /* p_inter.c */, + 72E847ED0F941A5900AB3C99 /* p_inter.h */, + 72E847EE0F941A5900AB3C99 /* p_lights.c */, + 72E847EF0F941A5900AB3C99 /* p_map.c */, + 72E847F00F941A5900AB3C99 /* p_map.h */, + 72E847F10F941A5900AB3C99 /* p_maputl.c */, + 72E847F20F941A5900AB3C99 /* p_maputl.h */, + 72E847F30F941A5900AB3C99 /* p_mobj.c */, + 72E847F40F941A5900AB3C99 /* p_mobj.h */, + 72E847F50F941A5900AB3C99 /* p_plats.c */, + 72E847F60F941A5900AB3C99 /* p_pspr.c */, + 72E847F70F941A5900AB3C99 /* p_pspr.h */, + 72E847F80F941A5900AB3C99 /* p_saveg.c */, + 72E847F90F941A5900AB3C99 /* p_saveg.h */, + 72E847FA0F941A5900AB3C99 /* p_setup.c */, + 72E847FB0F941A5900AB3C99 /* p_setup.h */, + 72E847FC0F941A5900AB3C99 /* p_sight.c */, + 72E847FD0F941A5900AB3C99 /* p_spec.c */, + 72E847FE0F941A5900AB3C99 /* p_spec.h */, + 72E847FF0F941A5900AB3C99 /* p_switch.c */, + 72E848000F941A5900AB3C99 /* p_telept.c */, + 72E848010F941A5900AB3C99 /* p_tick.c */, + 72E848020F941A5900AB3C99 /* p_tick.h */, + 72E848030F941A5900AB3C99 /* p_user.c */, + 72E848040F941A5900AB3C99 /* p_user.h */, + 72E847CA0F94096C00AB3C99 /* SDL_opengl.h */, + 72E8477A0F9400D700AB3C99 /* d_items.c */, + 72E8477B0F9400D700AB3C99 /* d_items.h */, + 72E8477C0F9400D700AB3C99 /* d_main.c */, + 72E8477D0F9400D700AB3C99 /* d_main.h */, + 72E8477E0F9400D700AB3C99 /* d_net.h */, + 72E8477F0F9400D700AB3C99 /* d_player.h */, + 72E847810F9400D700AB3C99 /* d_think.h */, + 72E847820F9400D700AB3C99 /* d_ticcmd.h */, + 72E847830F9400D700AB3C99 /* doomdata.h */, + 72E847840F9400D700AB3C99 /* doomdef.c */, + 72E847850F9400D700AB3C99 /* doomdef.h */, + 72E847860F9400D700AB3C99 /* doomstat.c */, + 72E847870F9400D700AB3C99 /* doomstat.h */, + 72E847880F9400D700AB3C99 /* doomtype.h */, + 72E847890F9400D700AB3C99 /* dstrings.c */, + 72E8478A0F9400D700AB3C99 /* dstrings.h */, + 72E8478B0F9400D700AB3C99 /* f_finale.c */, + 72E8478C0F9400D700AB3C99 /* f_finale.h */, + 72E8478D0F9400D700AB3C99 /* f_wipe.c */, + 72E8478E0F9400D700AB3C99 /* f_wipe.h */, + 72E8478F0F9400D700AB3C99 /* g_game.c */, + 72E847900F9400D700AB3C99 /* g_game.h */, + 72E847950F9400D700AB3C99 /* hu_lib.c */, + 72E847960F9400D700AB3C99 /* hu_lib.h */, + 72E847970F9400D700AB3C99 /* hu_stuff.c */, + 72E847980F9400D700AB3C99 /* hu_stuff.h */, + 72E847990F9400D700AB3C99 /* i_joy.h */, + 72E8479A0F9400D700AB3C99 /* i_main.h */, + 72E8479B0F9400D700AB3C99 /* i_network.h */, + 72E8479C0F9400D700AB3C99 /* i_sound.h */, + 72E8479D0F9400D700AB3C99 /* i_system.h */, + 72E8479E0F9400D700AB3C99 /* i_video.h */, + 72E8479F0F9400D700AB3C99 /* info.c */, + 72E847A00F9400D700AB3C99 /* info.h */, + 72E847A10F9400D700AB3C99 /* lprintf.c */, + 72E847A20F9400D700AB3C99 /* lprintf.h */, + 72E847A30F9400D700AB3C99 /* m_argv.c */, + 72E847A40F9400D700AB3C99 /* m_argv.h */, + 72E847A50F9400D700AB3C99 /* m_bbox.c */, + 72E847A60F9400D700AB3C99 /* m_bbox.h */, + 72E847A70F9400D700AB3C99 /* m_cheat.c */, + 72E847A80F9400D700AB3C99 /* m_cheat.h */, + 72E847AA0F9400D700AB3C99 /* m_menu.c */, + 72E847A90F9400D700AB3C99 /* m_fixed.h */, + 72E847AB0F9400D700AB3C99 /* m_menu.h */, + 72E847AC0F9400D700AB3C99 /* m_misc.c */, + 72E847AD0F9400D700AB3C99 /* m_misc.h */, + 72E847AE0F9400D700AB3C99 /* m_random.c */, + 72E847AF0F9400D700AB3C99 /* m_random.h */, + 72E847B00F9400D700AB3C99 /* m_swap.h */, + 72E8476E0F93FFDB00AB3C99 /* am_map.h */, + 72E8476F0F93FFDB00AB3C99 /* d_client.c */, + 72E847700F93FFDB00AB3C99 /* d_deh.c */, + 72E847710F93FFDB00AB3C99 /* d_deh.h */, + 72E847720F93FFDB00AB3C99 /* d_englsh.h */, + 72E847730F93FFDB00AB3C99 /* d_event.h */, + 72E847640F93C61900AB3C99 /* am_map.c */, + 72E847680F93FF2F00AB3C99 /* config.h */, + 72E847910F9400D700AB3C99 /* gl_intern.h */, + 72E847930F9400D700AB3C99 /* gl_struct.h */, + 72E847940F9400D700AB3C99 /* gl_texture.c */, + 72E847920F9400D700AB3C99 /* gl_main.c */, + ); + name = prboom; + sourceTree = ""; + }; + 72F1F94B0F96B55B00AD49AC /* libtess */ = { + isa = PBXGroup; + children = ( + 72F1F99C0F96C18800AD49AC /* dict-list.h */, + 72F1F99D0F96C18800AD49AC /* dict.c */, + 72F1F99E0F96C18800AD49AC /* dict.h */, + 72F1F99F0F96C18800AD49AC /* geom.c */, + 72F1F9A00F96C18800AD49AC /* geom.h */, + 72F1F9A10F96C18800AD49AC /* memalloc.c */, + 72F1F9A20F96C18800AD49AC /* memalloc.h */, + 72F1F9A30F96C18800AD49AC /* mesh.c */, + 72F1F9A40F96C18800AD49AC /* mesh.h */, + 72F1F9A50F96C18800AD49AC /* normal.c */, + 72F1F9A60F96C18800AD49AC /* normal.h */, + 72F1F9A80F96C18800AD49AC /* priorityq-heap.h */, + 72F1F9A90F96C18800AD49AC /* priorityq-sort.h */, + 72F1F9AA0F96C18800AD49AC /* priorityq.c */, + 72F1F9AB0F96C18800AD49AC /* priorityq.h */, + 72F1F9AC0F96C18800AD49AC /* render.c */, + 72F1F9AD0F96C18800AD49AC /* render.h */, + 72F1F9AE0F96C18800AD49AC /* sweep.c */, + 72F1F9AF0F96C18800AD49AC /* sweep.h */, + 72F1F9B00F96C18800AD49AC /* tess.c */, + 72F1F9B10F96C18800AD49AC /* tess.h */, + 72F1F9B20F96C18800AD49AC /* tessmono.c */, + 72F1F9B30F96C18800AD49AC /* tessmono.h */, + ); + name = libtess; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 1D6058900D05DD3D006BFB54 /* doom */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "doom" */; + buildPhases = ( + 1D60588D0D05DD3D006BFB54 /* Resources */, + 1D60588E0D05DD3D006BFB54 /* Sources */, + 1D60588F0D05DD3D006BFB54 /* Frameworks */, + 435F41A90F532CA300887552 /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = doom; + productName = wolf3d; + productReference = 1D6058910D05DD3D006BFB54 /* doom.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 "doom" */; + compatibilityVersion = "Xcode 3.1"; + hasScannedForEncodings = 1; + mainGroup = 29B97314FDCFA39411CA2CEA /* CustomTemplate */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 1D6058900D05DD3D006BFB54 /* doom */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 1D60588D0D05DD3D006BFB54 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 28AD733F0D9D9553002E5188 /* MainWindow.xib in Resources */, + 43CF02FF0F56974E00E4A23D /* Default.png in Resources */, + 4364BF3F0F5CB25900F29317 /* dist.plist in Resources */, + 434669960F8D058400EA7D6D /* doom_icon.png in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 435F41A90F532CA300887552 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = "/bin/sh -x"; + shellScript = "PBXCP=${DEVELOPER_DIR}/Library/PrivateFrameworks/DevToolsCore.framework/Resources/pbxcp\n${PBXCP} -exclude .svn \"${PROJECT_DIR}/../../base\" \"${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/\"\n"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 1D60588E0D05DD3D006BFB54 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1D60589B0D05DD56006BFB54 /* main.m in Sources */, + 43E8D2E10F4FC61E003F09B2 /* iphone_main.c in Sources */, + 43CF030A0F56D5C200E4A23D /* iphone_loop.c in Sources */, + 72A7E8F70F5F2063005B83C0 /* iphone_menus.c in Sources */, + 7229CE4A0F6C89F8004123C5 /* EAGLView.m in Sources */, + 7229CE550F6C8CDE004123C5 /* gles_glue.c in Sources */, + 72B5FF390F7E5C3D00C8A372 /* hud.c in Sources */, + 43A945150F82D75900FFD32E /* iphone_sys.c in Sources */, + 434669A60F8D08C000EA7D6D /* doomAppDelegate.m in Sources */, + 72D50DBC0F8ED98000BB49E6 /* ipak.c in Sources */, + 72E847650F93C61900AB3C99 /* am_map.c in Sources */, + 72E847740F93FFDB00AB3C99 /* d_client.c in Sources */, + 72E847750F93FFDB00AB3C99 /* d_deh.c in Sources */, + 72E847B20F9400D700AB3C99 /* d_items.c in Sources */, + 72E847B30F9400D700AB3C99 /* d_main.c in Sources */, + 72E847B50F9400D700AB3C99 /* doomdef.c in Sources */, + 72E847B60F9400D700AB3C99 /* doomstat.c in Sources */, + 72E847B70F9400D700AB3C99 /* dstrings.c in Sources */, + 72E847B80F9400D700AB3C99 /* f_finale.c in Sources */, + 72E847B90F9400D700AB3C99 /* f_wipe.c in Sources */, + 72E847BA0F9400D700AB3C99 /* g_game.c in Sources */, + 72E847BB0F9400D700AB3C99 /* gl_main.c in Sources */, + 72E847BC0F9400D700AB3C99 /* gl_texture.c in Sources */, + 72E847BD0F9400D700AB3C99 /* hu_lib.c in Sources */, + 72E847BE0F9400D700AB3C99 /* hu_stuff.c in Sources */, + 72E847BF0F9400D700AB3C99 /* info.c in Sources */, + 72E847C00F9400D700AB3C99 /* lprintf.c in Sources */, + 72E847C10F9400D700AB3C99 /* m_argv.c in Sources */, + 72E847C20F9400D700AB3C99 /* m_bbox.c in Sources */, + 72E847C30F9400D700AB3C99 /* m_cheat.c in Sources */, + 72E847C40F9400D700AB3C99 /* m_menu.c in Sources */, + 72E847C50F9400D700AB3C99 /* m_misc.c in Sources */, + 72E847C60F9400D700AB3C99 /* m_random.c in Sources */, + 72E848050F941A5900AB3C99 /* md5.c in Sources */, + 72E848070F941A5900AB3C99 /* p_ceilng.c in Sources */, + 72E848080F941A5900AB3C99 /* p_checksum.c in Sources */, + 72E848090F941A5900AB3C99 /* p_doors.c in Sources */, + 72E8480A0F941A5900AB3C99 /* p_enemy.c in Sources */, + 72E8480B0F941A5900AB3C99 /* p_floor.c in Sources */, + 72E8480C0F941A5900AB3C99 /* p_genlin.c in Sources */, + 72E8480D0F941A5900AB3C99 /* p_inter.c in Sources */, + 72E8480E0F941A5900AB3C99 /* p_lights.c in Sources */, + 72E8480F0F941A5900AB3C99 /* p_map.c in Sources */, + 72E848100F941A5900AB3C99 /* p_maputl.c in Sources */, + 72E848110F941A5900AB3C99 /* p_mobj.c in Sources */, + 72E848120F941A5900AB3C99 /* p_plats.c in Sources */, + 72E848130F941A5900AB3C99 /* p_pspr.c in Sources */, + 72E848140F941A5900AB3C99 /* p_saveg.c in Sources */, + 72E848150F941A5900AB3C99 /* p_setup.c in Sources */, + 72E848160F941A5900AB3C99 /* p_sight.c in Sources */, + 72E848170F941A5900AB3C99 /* p_spec.c in Sources */, + 72E848180F941A5900AB3C99 /* p_switch.c in Sources */, + 72E848190F941A5900AB3C99 /* p_telept.c in Sources */, + 72E8481A0F941A5900AB3C99 /* p_tick.c in Sources */, + 72E8481B0F941A5900AB3C99 /* p_user.c in Sources */, + 72E848260F941A8300AB3C99 /* r_bsp.c in Sources */, + 72E848270F941A8300AB3C99 /* r_data.c in Sources */, + 72E848280F941A8300AB3C99 /* r_demo.c in Sources */, + 72E848290F941A8300AB3C99 /* r_draw.c in Sources */, + 72E8483D0F941AAC00AB3C99 /* r_filter.c in Sources */, + 72E8483E0F941AAC00AB3C99 /* r_fps.c in Sources */, + 72E8483F0F941AAC00AB3C99 /* r_main.c in Sources */, + 72E848400F941AAC00AB3C99 /* r_patch.c in Sources */, + 72E848410F941AAC00AB3C99 /* r_plane.c in Sources */, + 72E848420F941AAC00AB3C99 /* r_segs.c in Sources */, + 72E848430F941AAC00AB3C99 /* r_sky.c in Sources */, + 72E848440F941AAC00AB3C99 /* r_things.c in Sources */, + 72E848450F941AAC00AB3C99 /* s_sound.c in Sources */, + 72E8485C0F941ADC00AB3C99 /* sounds.c in Sources */, + 72E8485D0F941ADC00AB3C99 /* st_lib.c in Sources */, + 72E8485E0F941ADC00AB3C99 /* st_stuff.c in Sources */, + 72E8485F0F941ADC00AB3C99 /* tables.c in Sources */, + 72E848600F941ADC00AB3C99 /* v_video.c in Sources */, + 72E848610F941ADC00AB3C99 /* version.c in Sources */, + 72E848630F941ADC00AB3C99 /* w_mmap.c in Sources */, + 72E848640F941ADC00AB3C99 /* w_wad.c in Sources */, + 72E848650F941ADC00AB3C99 /* wi_stuff.c in Sources */, + 72E848660F941ADC00AB3C99 /* z_bmalloc.c in Sources */, + 72E848670F941ADC00AB3C99 /* z_zone.c in Sources */, + 72E849600F942B9300AB3C99 /* cvar.c in Sources */, + 72E849610F942B9300AB3C99 /* misc.c in Sources */, + 72E849F60F94ED1100AB3C99 /* prboomInterface.c in Sources */, + 72E84A290F9503F100AB3C99 /* cmd.c in Sources */, + 72F1F9B40F96C18800AD49AC /* dict.c in Sources */, + 72F1F9B50F96C18800AD49AC /* geom.c in Sources */, + 72F1F9B60F96C18800AD49AC /* memalloc.c in Sources */, + 72F1F9B70F96C18800AD49AC /* mesh.c in Sources */, + 72F1F9B80F96C18800AD49AC /* normal.c in Sources */, + 72F1F9BA0F96C18800AD49AC /* priorityq.c in Sources */, + 72F1F9BB0F96C18800AD49AC /* render.c in Sources */, + 72F1F9BC0F96C18800AD49AC /* sweep.c in Sources */, + 72F1F9BD0F96C18800AD49AC /* tess.c in Sources */, + 72F1F9BE0F96C18800AD49AC /* tessmono.c in Sources */, + 72E731EB0F97E68100E702CD /* iphone_sound.c in Sources */, + 7239452C0F9C0E7500EADD62 /* iphone_mapSelect.c in Sources */, + 72484E5E0FB0E99900124E1C /* iphone_render.c in Sources */, + 724C531F0FBDBCEE000E4348 /* BackgroundMusic.cpp in Sources */, + 43DD8392100295F70006E1DD /* iphone_async.c in Sources */, + 72A55EEF1003A94300F788A5 /* iphone_start.c in Sources */, + 72A560E21004FAEE00F788A5 /* iphone_net.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 1D6058940D05DD3E006BFB54 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer: John Carmack"; + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = doom_Prefix.pch; + GCC_PREPROCESSOR_DEFINITIONS = ( + _DEBUG, + HAVE_CONFIG_H, + IPHONE, + ); + HEADER_SEARCH_PATHS = ""; + INFOPLIST_FILE = Info.plist; + PRODUCT_NAME = doom; + PROFILE_PREFIX = com.idsoftware; + "PROVISIONING_PROFILE[sdk=iphoneos*]" = "DC390A27-85C5-4A7F-A464-432AC944FB52"; + }; + name = Debug; + }; + 1D6058950D05DD3E006BFB54 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer: John Carmack"; + COPY_PHASE_STRIP = YES; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = doom_Prefix.pch; + GCC_PREPROCESSOR_DEFINITIONS = ( + HAVE_CONFIG_H, + IPHONE, + ); + HEADER_SEARCH_PATHS = ""; + INFOPLIST_FILE = Info.plist; + PRODUCT_NAME = doom; + PROFILE_PREFIX = com.idsoftware; + "PROVISIONING_PROFILE[sdk=iphoneos*]" = "DC390A27-85C5-4A7F-A464-432AC944FB52"; + }; + name = Release; + }; + 4364BF480F5CB27300F29317 /* AdHocDist */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + CODE_SIGN_ENTITLEMENTS = dist.plist; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution: Cass Everitt"; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_THUMB_SUPPORT = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + PREBINDING = NO; + "PROVISIONING_PROFILE[sdk=iphoneos*]" = "E2E91433-8CD1-46DB-9DC5-B7E4C84FD1C2"; + SDKROOT = iphoneos2.0; + }; + name = AdHocDist; + }; + 4364BF490F5CB27300F29317 /* AdHocDist */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution: id Software"; + COPY_PHASE_STRIP = YES; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = doom_Prefix.pch; + GCC_PREPROCESSOR_DEFINITIONS = ( + HAVE_CONFIG_H, + IPHONE, + ); + HEADER_SEARCH_PATHS = ""; + INFOPLIST_FILE = Info.plist; + PRODUCT_NAME = doom; + PROFILE_PREFIX = com.idsoftware; + "PROVISIONING_PROFILE[sdk=iphoneos*]" = "0599767D-56AE-4548-A7CD-558CF4F0A4D7"; + }; + name = AdHocDist; + }; + 43AE7CA40F61EC4E00B2F562 /* ReleaseLite */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer: John Carmack"; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_THUMB_SUPPORT = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + PREBINDING = NO; + "PROVISIONING_PROFILE[sdk=iphoneos*]" = "FBAC6BB4-2067-4E29-909B-F56A0CBAE973"; + SDKROOT = iphoneos2.0; + }; + name = ReleaseLite; + }; + 43AE7CA50F61EC4E00B2F562 /* ReleaseLite */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer: John Carmack"; + COPY_PHASE_STRIP = YES; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = doom_Prefix.pch; + GCC_PREPROCESSOR_DEFINITIONS = ( + EPISODE1, + IPHONE, + ); + HEADER_SEARCH_PATHS = ""; + INFOPLIST_FILE = Info.plist; + PRODUCT_NAME = doomLite; + PROFILE_PREFIX = com.idsoftware; + "PROVISIONING_PROFILE[sdk=iphoneos*]" = "EB156887-88D8-459D-BA95-C039B07F9874"; + }; + name = ReleaseLite; + }; + 43AE7CAE0F61FC9200B2F562 /* DebugLite */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer: John Carmack"; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + ONLY_ACTIVE_ARCH = YES; + PREBINDING = NO; + "PROVISIONING_PROFILE[sdk=iphoneos*]" = "FBAC6BB4-2067-4E29-909B-F56A0CBAE973"; + SDKROOT = iphoneos2.0; + }; + name = DebugLite; + }; + 43AE7CAF0F61FC9200B2F562 /* DebugLite */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer: John Carmack"; + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = doom_Prefix.pch; + GCC_PREPROCESSOR_DEFINITIONS = ( + EPISODE1, + IPHONE, + ); + HEADER_SEARCH_PATHS = ""; + INFOPLIST_FILE = Info.plist; + PRODUCT_NAME = doomLite; + PROFILE_PREFIX = com.idsoftware; + "PROVISIONING_PROFILE[sdk=iphoneos*]" = "EB156887-88D8-459D-BA95-C039B07F9874"; + }; + name = DebugLite; + }; + C01FCF4F08A954540054247B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_PREPROCESSOR_DEFINITIONS = "HAVE_CONFIG_H=1"; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + ONLY_ACTIVE_ARCH = YES; + PREBINDING = NO; + PROVISIONING_PROFILE = ""; + "PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; + SDKROOT = iphoneos2.0; + }; + name = Debug; + }; + C01FCF5008A954540054247B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + CODE_SIGN_IDENTITY = "iPhone Developer: John Carmack"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer: John Carmack"; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_PREPROCESSOR_DEFINITIONS = HAVE_CONFIG_H; + GCC_THUMB_SUPPORT = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + PREBINDING = NO; + PROVISIONING_PROFILE = "5A48C2AC-452B-49C9-BF02-32B58D6C471D"; + "PROVISIONING_PROFILE[sdk=iphoneos*]" = "5A48C2AC-452B-49C9-BF02-32B58D6C471D"; + SDKROOT = iphoneos2.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "doom" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1D6058940D05DD3E006BFB54 /* Debug */, + 43AE7CAF0F61FC9200B2F562 /* DebugLite */, + 1D6058950D05DD3E006BFB54 /* Release */, + 43AE7CA50F61EC4E00B2F562 /* ReleaseLite */, + 4364BF490F5CB27300F29317 /* AdHocDist */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + C01FCF4E08A954540054247B /* Build configuration list for PBXProject "doom" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C01FCF4F08A954540054247B /* Debug */, + 43AE7CAE0F61FC9200B2F562 /* DebugLite */, + C01FCF5008A954540054247B /* Release */, + 43AE7CA40F61EC4E00B2F562 /* ReleaseLite */, + 4364BF480F5CB27300F29317 /* AdHocDist */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; +} diff --git a/DoomClassic/code/iphone/Doom.xcodeproj/greghodges.mode1v3 b/DoomClassic/code/iphone/Doom.xcodeproj/greghodges.mode1v3 new file mode 100755 index 0000000..de6af4e --- /dev/null +++ b/DoomClassic/code/iphone/Doom.xcodeproj/greghodges.mode1v3 @@ -0,0 +1,1404 @@ + + + + + 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 + XCProjectFormatConflictsModule + Name + Project Format Conflicts List + + + 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 + + + BundleLoadPath + + MaxInstances + n + Module + XCSnapshotModule + Name + Snapshots Tool + + + BundlePath + /Developer/Library/PrivateFrameworks/DevToolsInterface.framework/Resources + Description + DefaultDescriptionKey + DockingSystemVisible + + Extension + mode1v3 + FavBarConfig + + PBXProjectModuleGUID + ED9BABAC108380C600166CDA + XCBarModuleItemNames + + XCBarModuleItems + + + FirstTimeWindowDisplayed + + Identifier + com.apple.perspectives.project.mode1v3 + MajorVersion + 33 + MinorVersion + 0 + Name + Default + Notifications + + OpenEditors + + PerspectiveWidths + + -1 + -1 + + Perspectives + + + ChosenToolbarItems + + active-combo-popup + action + NSToolbarFlexibleSpaceItem + debugger-enable-breakpoints + build-and-go + com.apple.ide.PBXToolbarStopButton + get-info + NSToolbarFlexibleSpaceItem + com.apple.pbx.toolbar.searchfield + + ControllerClassBaseName + + IconName + WindowOfProjectWithEditor + Identifier + perspective.project + IsVertical + + Layout + + + ContentConfiguration + + PBXBottomSmartGroupGIDs + + 1C37FBAC04509CD000000102 + 1C37FAAC04509CD000000102 + 1C37FABC05509CD000000102 + 1C37FABC05539CD112110102 + E2644B35053B69B200211256 + 1C37FABC04509CD000100104 + 1CC0EA4004350EF90044410B + 1CC0EA4004350EF90041110B + + PBXProjectModuleGUID + 1CE0B1FE06471DED0097A5F4 + PBXProjectModuleLabel + Files + PBXProjectStructureProvided + yes + PBXSmartGroupTreeModuleColumnData + + PBXSmartGroupTreeModuleColumnWidthsKey + + 186 + + PBXSmartGroupTreeModuleColumnsKey_v4 + + MainColumn + + + PBXSmartGroupTreeModuleOutlineStateKey_v7 + + PBXSmartGroupTreeModuleOutlineStateExpansionKey + + 29B97314FDCFA39411CA2CEA + 29B97315FDCFA39411CA2CEA + 29B97317FDCFA39411CA2CEA + 29B97323FDCFA39411CA2CEA + 43E8D4DF0F51B48B003F09B2 + 19C28FACFE9D520D11CA2CBB + 1C37FBAC04509CD000000102 + 1C37FABC05509CD000000102 + + PBXSmartGroupTreeModuleOutlineStateSelectionKey + + + 54 + 53 + + + PBXSmartGroupTreeModuleOutlineStateVisibleRectKey + {{0, 81}, {186, 973}} + + PBXTopSmartGroupGIDs + + XCIncludePerspectivesSwitch + + XCSharingToken + com.apple.Xcode.GFSharingToken + + GeometryConfiguration + + Frame + {{0, 0}, {203, 991}} + GroupTreeTableConfiguration + + MainColumn + 186 + + RubberWindowFrame + 0 145 877 1032 0 0 1920 1178 + + Module + PBXSmartGroupTreeModule + Proportion + 203pt + + + Dock + + + BecomeActive + + ContentConfiguration + + PBXProjectModuleGUID + 1CE0B20306471E060097A5F4 + PBXProjectModuleLabel + BackgroundMusic.cpp + PBXSplitModuleInNavigatorKey + + Split0 + + PBXProjectModuleGUID + 1CE0B20406471E060097A5F4 + PBXProjectModuleLabel + BackgroundMusic.cpp + _historyCapacity + 0 + bookmark + EDD2765D11C2B634004A9B9B + history + + ED9BABDF1083850C00166CDA + ED2D127F10838A65003A9380 + ED9AB3E610967730000B5852 + ED9AB3E710967730000B5852 + EDAFC7F5109A575F002C3487 + EDAFC819109A5B94002C3487 + EDFDF9B410A2054E0071CB9B + ED60B15110B61ADE003A8B9F + ED60B15210B61ADE003A8B9F + ED80ABFC10E930AC006AAD9D + EDA4D0A6110A1FCD0014EF0F + EDD2763611C2B43F004A9B9B + EDD2763711C2B43F004A9B9B + + + SplitCount + 1 + + StatusBarVisibility + + + GeometryConfiguration + + Frame + {{0, 0}, {669, 899}} + RubberWindowFrame + 0 145 877 1032 0 0 1920 1178 + + Module + PBXNavigatorGroup + Proportion + 899pt + + + ContentConfiguration + + PBXProjectModuleGUID + 1CE0B20506471E060097A5F4 + PBXProjectModuleLabel + Detail + + GeometryConfiguration + + Frame + {{0, 904}, {669, 87}} + RubberWindowFrame + 0 145 877 1032 0 0 1920 1178 + + Module + XCDetailModule + Proportion + 87pt + + + Proportion + 669pt + + + Name + Project + ServiceClasses + + XCModuleDock + PBXSmartGroupTreeModule + XCModuleDock + PBXNavigatorGroup + XCDetailModule + + TableOfContents + + EDD2763911C2B43F004A9B9B + 1CE0B1FE06471DED0097A5F4 + EDD2763A11C2B43F004A9B9B + 1CE0B20306471E060097A5F4 + 1CE0B20506471E060097A5F4 + + ToolbarConfigUserDefaultsMinorVersion + 2 + ToolbarConfiguration + xcode.toolbar.config.defaultV3 + + + 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.shortV3 + + + PerspectivesBarVisible + + ShelfIsVisible + + SourceDescription + file at '/Developer/Library/PrivateFrameworks/DevToolsInterface.framework/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 + + EDD2765E11C2B634004A9B9B + EDD2765F11C2B634004A9B9B + 1CD10A99069EF8BA00B06720 + ED9BABAD108380C600166CDA + 1C78EAAD065D492600B07095 + /Volumes/Work/idMobileDepot/DoomClassicDepot/code/iphone/Doom.xcodeproj + + WindowString + 0 145 877 1032 0 0 1920 1178 + WindowToolsV3 + + + FirstTimeWindowDisplayed + + Identifier + windowTool.build + IsVertical + + Layout + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + 1CD0528F0623707200166675 + PBXProjectModuleLabel + BackgroundMusic.cpp + StatusBarVisibility + + + GeometryConfiguration + + Frame + {{0, 0}, {1073, 761}} + RubberWindowFrame + 124 183 1073 925 0 0 1920 1178 + + Module + PBXNavigatorGroup + Proportion + 761pt + + + BecomeActive + + ContentConfiguration + + PBXProjectModuleGUID + XCMainBuildResultsModuleGUID + PBXProjectModuleLabel + Build Results + XCBuildResultsTrigger_Collapse + 1021 + XCBuildResultsTrigger_Open + 1011 + + GeometryConfiguration + + Frame + {{0, 766}, {1073, 118}} + RubberWindowFrame + 124 183 1073 925 0 0 1920 1178 + + Module + PBXBuildResultsModule + Proportion + 118pt + + + Proportion + 884pt + + + Name + Build Results + ServiceClasses + + PBXBuildResultsModule + + StatusbarIsVisible + + TableOfContents + + ED9BABAD108380C600166CDA + EDD2761111C2B1AF004A9B9B + 1CD0528F0623707200166675 + XCMainBuildResultsModuleGUID + + ToolbarConfiguration + xcode.toolbar.config.buildV3 + WindowString + 124 183 1073 925 0 0 1920 1178 + WindowToolGUID + ED9BABAD108380C600166CDA + WindowToolIsVisible + + + + FirstTimeWindowDisplayed + + Identifier + windowTool.debugger + IsVertical + + Layout + + + Dock + + + ContentConfiguration + + Debugger + + HorizontalSplitView + + _collapsingFrameDimension + 0.0 + _indexOfCollapsedView + 0 + _percentageOfCollapsedView + 0.0 + isCollapsed + yes + sizes + + {{0, 0}, {347, 190}} + {{0, 190}, {347, 191}} + + + VerticalSplitView + + _collapsingFrameDimension + 0.0 + _indexOfCollapsedView + 0 + _percentageOfCollapsedView + 0.0 + isCollapsed + yes + sizes + + {{0, 0}, {347, 381}} + {{347, 0}, {347, 381}} + + + + LauncherConfigVersion + 8 + PBXProjectModuleGUID + 1C162984064C10D400B95A72 + PBXProjectModuleLabel + Debug - GLUTExamples (Underwater) + + GeometryConfiguration + + DebugConsoleVisible + None + DebugConsoleWindowFrame + {{200, 200}, {500, 300}} + DebugSTDIOWindowFrame + {{200, 200}, {500, 300}} + Frame + {{0, 0}, {694, 381}} + PBXDebugSessionStackFrameViewKey + + DebugVariablesTableConfiguration + + Name + 120 + Value + 85 + Summary + 117 + + Frame + {{0, 190}, {347, 191}} + RubberWindowFrame + 128 689 694 422 0 0 1920 1178 + + RubberWindowFrame + 128 689 694 422 0 0 1920 1178 + + Module + PBXDebugSessionModule + Proportion + 381pt + + + Proportion + 381pt + + + Name + Debugger + ServiceClasses + + PBXDebugSessionModule + + StatusbarIsVisible + + TableOfContents + + 1CD10A99069EF8BA00B06720 + EDD2763B11C2B43F004A9B9B + 1C162984064C10D400B95A72 + EDD2763C11C2B43F004A9B9B + EDD2763D11C2B43F004A9B9B + EDD2763E11C2B43F004A9B9B + EDD2763F11C2B43F004A9B9B + EDD2764011C2B43F004A9B9B + + ToolbarConfiguration + xcode.toolbar.config.debugV3 + WindowString + 128 689 694 422 0 0 1920 1178 + WindowToolGUID + 1CD10A99069EF8BA00B06720 + WindowToolIsVisible + + + + FirstTimeWindowDisplayed + + Identifier + windowTool.find + IsVertical + + Layout + + + Dock + + + Dock + + + BecomeActive + + ContentConfiguration + + PBXProjectModuleGUID + 1CDD528C0622207200134675 + PBXProjectModuleLabel + iphone_sound.c + StatusBarVisibility + + + GeometryConfiguration + + Frame + {{0, 0}, {934, 674}} + RubberWindowFrame + 64 158 934 948 0 0 1920 1178 + + Module + PBXNavigatorGroup + Proportion + 934pt + + + Proportion + 674pt + + + ContentConfiguration + + PBXProjectModuleGUID + 1CD0528E0623707200166675 + PBXProjectModuleLabel + Project Find + + GeometryConfiguration + + Frame + {{0, 679}, {934, 228}} + RubberWindowFrame + 64 158 934 948 0 0 1920 1178 + + Module + PBXProjectFindModule + Proportion + 228pt + + + Proportion + 907pt + + + Name + Project Find + ServiceClasses + + PBXProjectFindModule + + StatusbarIsVisible + + TableOfContents + + 1C530D57069F1CE1000CFCEE + EDFA718A1194DF840098FFFC + EDFA718B1194DF840098FFFC + 1CDD528C0622207200134675 + 1CD0528E0623707200166675 + + WindowString + 64 158 934 948 0 0 1920 1178 + WindowToolGUID + 1C530D57069F1CE1000CFCEE + WindowToolIsVisible + + + + Identifier + MENUSEPARATOR + + + FirstTimeWindowDisplayed + + Identifier + windowTool.debuggerConsole + IsVertical + + Layout + + + Dock + + + BecomeActive + + ContentConfiguration + + PBXProjectModuleGUID + 1C78EAAC065D492600B07095 + PBXProjectModuleLabel + Debugger Console + + GeometryConfiguration + + Frame + {{0, 0}, {646, 511}} + RubberWindowFrame + 493 610 646 552 0 0 1920 1178 + + Module + PBXDebugCLIModule + Proportion + 511pt + + + Proportion + 511pt + + + Name + Debugger Console + ServiceClasses + + PBXDebugCLIModule + + StatusbarIsVisible + + TableOfContents + + 1C78EAAD065D492600B07095 + EDD2764111C2B43F004A9B9B + 1C78EAAC065D492600B07095 + + ToolbarConfiguration + xcode.toolbar.config.consoleV3 + WindowString + 493 610 646 552 0 0 1920 1178 + WindowToolGUID + 1C78EAAD065D492600B07095 + WindowToolIsVisible + + + + Identifier + windowTool.snapshots + Layout + + + Dock + + + Module + XCSnapshotModule + Proportion + 100% + + + Proportion + 100% + + + Name + Snapshots + ServiceClasses + + XCSnapshotModule + + StatusbarIsVisible + Yes + ToolbarConfiguration + xcode.toolbar.config.snapshots + WindowString + 315 824 300 550 0 0 1440 878 + WindowToolIsVisible + Yes + + + 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.0950012207031 + + 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 + 3 + MinorVersion + 0 + Name + Breakpoints + ServiceClasses + + PBXSmartGroupTreeModule + XCDetailModule + + StatusbarIsVisible + 1 + TableOfContents + + 1CDDB66807F98D9800BB5817 + 1CDDB66907F98D9800BB5817 + 1CE0B1FE06471DED0097A5F4 + 1CA1AED706398EBD00589147 + + ToolbarConfiguration + xcode.toolbar.config.breakpointsV3 + 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.debugAnimatorV3 + 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.projectFormatConflicts + Layout + + + Dock + + + Module + XCProjectFormatConflictsModule + Proportion + 100% + + + Proportion + 100% + + + Name + Project Format Conflicts + ServiceClasses + + XCProjectFormatConflictsModule + + StatusbarIsVisible + 0 + WindowContentMinSize + 450 300 + WindowString + 50 850 472 307 0 0 1440 877 + + + 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 + + + Identifier + windowTool.refactoring + IncludeInToolsMenu + 0 + Layout + + + Dock + + + BecomeActive + 1 + GeometryConfiguration + + Frame + {0, 0}, {500, 335} + RubberWindowFrame + {0, 0}, {500, 335} + + Module + XCRefactoringModule + Proportion + 100% + + + Proportion + 100% + + + Name + Refactoring + ServiceClasses + + XCRefactoringModule + + WindowString + 200 200 500 356 0 0 1920 1200 + + + + diff --git a/DoomClassic/code/iphone/Doom.xcodeproj/greghodges.pbxuser b/DoomClassic/code/iphone/Doom.xcodeproj/greghodges.pbxuser new file mode 100755 index 0000000..71ec3d6 --- /dev/null +++ b/DoomClassic/code/iphone/Doom.xcodeproj/greghodges.pbxuser @@ -0,0 +1,825 @@ +// !$*UTF8*$! +{ + 1D6058900D05DD3D006BFB54 /* Doom */ = { + activeExec = 0; + executables = ( + ED9BAB90108380AC00166CDA /* Doom */, + ); + }; + 29B97313FDCFA39411CA2CEA /* Project object */ = { + activeBuildConfigurationName = Debug; + activeExecutable = ED9BAB90108380AC00166CDA /* Doom */; + activeSDKPreference = iphoneos3.0; + activeTarget = 1D6058900D05DD3D006BFB54 /* Doom */; + addToTargets = ( + 1D6058900D05DD3D006BFB54 /* Doom */, + ); + codeSenseManager = ED9BABB0108380C600166CDA /* Code sense */; + executables = ( + ED9BAB90108380AC00166CDA /* Doom */, + ); + perUserDictionary = { + PBXConfiguration.PBXFileTableDataSource3.PBXBookmarksDataSource = { + PBXFileTableDataSourceColumnSortingDirectionKey = "-1"; + PBXFileTableDataSourceColumnSortingKey = PBXBookmarksDataSource_NameID; + PBXFileTableDataSourceColumnWidthsKey = ( + 200, + 200, + 293.58349609375, + ); + PBXFileTableDataSourceColumnsKey = ( + PBXBookmarksDataSource_LocationID, + PBXBookmarksDataSource_NameID, + PBXBookmarksDataSource_CommentsID, + ); + }; + PBXConfiguration.PBXFileTableDataSource3.PBXFileTableDataSource = { + PBXFileTableDataSourceColumnSortingDirectionKey = "-1"; + PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID; + PBXFileTableDataSourceColumnWidthsKey = ( + 20, + 430, + 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.PBXFileTableDataSource3.PBXFindDataSource = { + PBXFileTableDataSourceColumnSortingDirectionKey = "-1"; + PBXFileTableDataSourceColumnSortingKey = PBXFindDataSource_LocationID; + PBXFileTableDataSourceColumnWidthsKey = ( + 200, + 498, + ); + PBXFileTableDataSourceColumnsKey = ( + PBXFindDataSource_MessageID, + PBXFindDataSource_LocationID, + ); + }; + PBXConfiguration.PBXTargetDataSource.PBXTargetDataSource = { + PBXFileTableDataSourceColumnSortingDirectionKey = "-1"; + PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID; + PBXFileTableDataSourceColumnWidthsKey = ( + 20, + 390, + 60, + 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 = 297971964; + PBXWorkspaceStateSaveDate = 297971964; + }; + perUserProjectItems = { + ED28ACA810AB233200DFC9C8 = ED28ACA810AB233200DFC9C8 /* PBXTextBookmark */; + ED28ACAB10AB233200DFC9C8 = ED28ACAB10AB233200DFC9C8 /* PBXTextBookmark */; + ED28ACAC10AB233200DFC9C8 = ED28ACAC10AB233200DFC9C8 /* PBXTextBookmark */; + ED28ACAD10AB233200DFC9C8 = ED28ACAD10AB233200DFC9C8 /* PBXTextBookmark */; + ED2D127F10838A65003A9380 = ED2D127F10838A65003A9380 /* PBXBookmark */; + ED2D128210838A65003A9380 = ED2D128210838A65003A9380 /* PBXBookmark */; + ED60B15110B61ADE003A8B9F = ED60B15110B61ADE003A8B9F /* PBXTextBookmark */; + ED60B15210B61ADE003A8B9F = ED60B15210B61ADE003A8B9F /* PBXTextBookmark */; + ED80ABFC10E930AC006AAD9D = ED80ABFC10E930AC006AAD9D /* PBXTextBookmark */; + ED80ABFF10E930AC006AAD9D = ED80ABFF10E930AC006AAD9D /* PBXTextBookmark */; + ED80AC0010E930AC006AAD9D = ED80AC0010E930AC006AAD9D /* PBXTextBookmark */; + ED9AB3E410967730000B5852 = ED9AB3E410967730000B5852 /* PlistBookmark */; + ED9AB3E610967730000B5852 = ED9AB3E610967730000B5852 /* PBXTextBookmark */; + ED9AB3E710967730000B5852 = ED9AB3E710967730000B5852 /* PBXTextBookmark */; + ED9AB3E910967730000B5852 = ED9AB3E910967730000B5852 /* PBXTextBookmark */; + ED9AB3EC10967730000B5852 = ED9AB3EC10967730000B5852 /* PBXTextBookmark */; + ED9AB3ED10967730000B5852 = ED9AB3ED10967730000B5852 /* PBXTextBookmark */; + ED9AB3EF10967730000B5852 = ED9AB3EF10967730000B5852 /* PBXTextBookmark */; + ED9AB3F210967730000B5852 = ED9AB3F210967730000B5852 /* PBXTextBookmark */; + ED9AB3F310967730000B5852 = ED9AB3F310967730000B5852 /* PBXTextBookmark */; + ED9BABDF1083850C00166CDA = ED9BABDF1083850C00166CDA /* PlistBookmark */; + ED9BABE11083850C00166CDA = ED9BABE11083850C00166CDA /* PlistBookmark */; + ED9BABE21083850C00166CDA = ED9BABE21083850C00166CDA /* PlistBookmark */; + EDA4D0A6110A1FCD0014EF0F = EDA4D0A6110A1FCD0014EF0F /* PBXTextBookmark */; + EDA4D0A7110A1FCD0014EF0F = EDA4D0A7110A1FCD0014EF0F /* PBXTextBookmark */; + EDA4D0A8110A1FCD0014EF0F = EDA4D0A8110A1FCD0014EF0F /* PBXTextBookmark */; + EDADAE4110ED10F70056382E = EDADAE4110ED10F70056382E /* PBXTextBookmark */; + EDADAE4210ED10F70056382E = EDADAE4210ED10F70056382E /* PBXTextBookmark */; + EDAFC7F5109A575F002C3487 = EDAFC7F5109A575F002C3487 /* PBXTextBookmark */; + EDAFC7F7109A575F002C3487 = EDAFC7F7109A575F002C3487 /* PBXTextBookmark */; + EDAFC7F8109A575F002C3487 = EDAFC7F8109A575F002C3487 /* PBXTextBookmark */; + EDAFC7F9109A575F002C3487 = EDAFC7F9109A575F002C3487 /* PBXTextBookmark */; + EDAFC818109A5B94002C3487 = EDAFC818109A5B94002C3487 /* PBXTextBookmark */; + EDAFC819109A5B94002C3487 = EDAFC819109A5B94002C3487 /* PBXTextBookmark */; + EDAFC81B109A5B94002C3487 = EDAFC81B109A5B94002C3487 /* PBXTextBookmark */; + EDD2763611C2B43F004A9B9B /* PlistBookmark */ = EDD2763611C2B43F004A9B9B /* PlistBookmark */; + EDD2763711C2B43F004A9B9B /* XCBuildMessageTextBookmark */ = EDD2763711C2B43F004A9B9B /* XCBuildMessageTextBookmark */; + EDD2763811C2B43F004A9B9B /* PBXTextBookmark */ = EDD2763811C2B43F004A9B9B /* PBXTextBookmark */; + EDD2764A11C2B47C004A9B9B /* PBXTextBookmark */ = EDD2764A11C2B47C004A9B9B /* PBXTextBookmark */; + EDD2764D11C2B499004A9B9B /* PBXTextBookmark */ = EDD2764D11C2B499004A9B9B /* PBXTextBookmark */; + EDD2765011C2B4C2004A9B9B /* XCBuildMessageTextBookmark */ = EDD2765011C2B4C2004A9B9B /* XCBuildMessageTextBookmark */; + EDD2765111C2B4C2004A9B9B /* PBXTextBookmark */ = EDD2765111C2B4C2004A9B9B /* PBXTextBookmark */; + EDD2765411C2B4E4004A9B9B /* PBXTextBookmark */ = EDD2765411C2B4E4004A9B9B /* PBXTextBookmark */; + EDD2765D11C2B634004A9B9B /* PBXTextBookmark */ = EDD2765D11C2B634004A9B9B /* PBXTextBookmark */; + EDFDF9B310A2054E0071CB9B = EDFDF9B310A2054E0071CB9B /* PBXTextBookmark */; + EDFDF9B410A2054E0071CB9B = EDFDF9B410A2054E0071CB9B /* PBXTextBookmark */; + EDFDF9B610A2054E0071CB9B = EDFDF9B610A2054E0071CB9B /* PBXTextBookmark */; + EDFDF9C110A205F50071CB9B = EDFDF9C110A205F50071CB9B /* PBXTextBookmark */; + }; + sourceControlManager = ED9BABAF108380C600166CDA /* Source Control */; + userBuildSettings = { + }; + }; + 434669950F8D058400EA7D6D /* Doom_icon.png */ = { + uiCtxt = { + sepNavWindowFrame = "{{15, 250}, {800, 773}}"; + }; + }; + 434669A40F8D08C000EA7D6D /* doomAppDelegate.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {662, 621}}"; + sepNavSelRange = "{898, 0}"; + sepNavVisRange = "{0, 1144}"; + }; + }; + 434669A50F8D08C000EA7D6D /* doomAppDelegate.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {662, 3290}}"; + sepNavSelRange = "{6607, 0}"; + sepNavVisRange = "{1068, 1018}"; + }; + }; + 43CF03090F56D5C200E4A23D /* iphone_loop.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {732, 24640}}"; + sepNavSelRange = "{6159, 14}"; + sepNavVisRange = "{5677, 1070}"; + }; + }; + 43E8D2DF0F4FC61E003F09B2 /* iphone_main.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {720, 7154}}"; + sepNavSelRange = "{8344, 0}"; + sepNavVisRange = "{8241, 409}"; + }; + }; + 7229CC8E0F6B3363004123C5 /* doomiphone.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {662, 1512}}"; + sepNavSelRange = "{2492, 0}"; + sepNavVisRange = "{1199, 1295}"; + }; + }; + 7229CE460F6C89F8004123C5 /* EAGLView.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {662, 5236}}"; + sepNavSelRange = "{9878, 0}"; + sepNavVisRange = "{9018, 1103}"; + }; + }; + 724C531E0FBDBCEE000E4348 /* BackgroundMusic.cpp */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {810, 7490}}"; + sepNavSelRange = "{11337, 0}"; + sepNavVisRange = "{10271, 2574}"; + }; + }; + 72A55EEE1003A94300F788A5 /* iphone_start.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {924, 3332}}"; + sepNavSelRange = "{2085, 10}"; + sepNavVisRange = "{1556, 1013}"; + }; + }; + 72A560E11004FAEE00F788A5 /* iphone_net.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {924, 8568}}"; + sepNavSelRange = "{13921, 0}"; + sepNavVisRange = "{13317, 1419}"; + }; + }; + 72A7E8F30F5F2001005B83C0 /* iphone_doom.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {742, 7686}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 933}"; + }; + }; + 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {924, 13034}}"; + sepNavSelRange = "{16785, 7}"; + sepNavVisRange = "{16110, 1348}"; + }; + }; + 72D50DBA0F8ED98000BB49E6 /* ipak.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {662, 2478}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{287, 1502}"; + }; + }; + 72D50DBB0F8ED98000BB49E6 /* ipak.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {864, 5586}}"; + sepNavSelRange = "{578, 8}"; + sepNavVisRange = "{1113, 1914}"; + }; + }; + 72E731EA0F97E68100E702CD /* iphone_sound.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {864, 4172}}"; + sepNavSelRange = "{4675, 0}"; + sepNavVisRange = "{3563, 1771}"; + }; + }; + 72E8478F0F9400D700AB3C99 /* g_game.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {742, 42056}}"; + sepNavSelRange = "{37902, 0}"; + sepNavVisRange = "{38963, 593}"; + }; + }; + 72E847CA0F94096C00AB3C99 /* SDL_opengl.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {870, 3024}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 1327}"; + }; + }; + 72E847FD0F941A5900AB3C99 /* p_spec.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {742, 46256}}"; + sepNavSelRange = "{65721, 11}"; + sepNavVisRange = "{65587, 835}"; + }; + }; + 72E847FF0F941A5900AB3C99 /* p_switch.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {742, 16408}}"; + sepNavSelRange = "{14154, 10}"; + sepNavVisRange = "{13963, 628}"; + }; + }; + 72E8495E0F942B9300AB3C99 /* misc.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {742, 1218}}"; + sepNavSelRange = "{1221, 0}"; + sepNavVisRange = "{1132, 433}"; + }; + }; + ED28ACA810AB233200DFC9C8 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E731EA0F97E68100E702CD /* iphone_sound.c */; + name = "iphone_sound.c: 148"; + rLen = 0; + rLoc = 4675; + rType = 0; + vrLen = 1771; + vrLoc = 3563; + }; + ED28ACAB10AB233200DFC9C8 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E731EA0F97E68100E702CD /* iphone_sound.c */; + name = "iphone_sound.c: 148"; + rLen = 0; + rLoc = 4675; + rType = 0; + vrLen = 1771; + vrLoc = 3563; + }; + ED28ACAC10AB233200DFC9C8 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 434669A50F8D08C000EA7D6D /* doomAppDelegate.m */; + name = "doomAppDelegate.m: 206"; + rLen = 0; + rLoc = 6278; + rType = 0; + vrLen = 1081; + vrLoc = 5802; + }; + ED28ACAD10AB233200DFC9C8 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 434669A40F8D08C000EA7D6D /* doomAppDelegate.h */; + name = "doomAppDelegate.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1144; + vrLoc = 0; + }; + ED2D127F10838A65003A9380 /* PBXBookmark */ = { + isa = PBXBookmark; + fRef = 434669950F8D058400EA7D6D /* Doom_icon.png */; + }; + ED2D128210838A65003A9380 /* PBXBookmark */ = { + isa = PBXBookmark; + fRef = 434669950F8D058400EA7D6D /* Doom_icon.png */; + }; + ED60B15110B61ADE003A8B9F /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 434669A40F8D08C000EA7D6D /* doomAppDelegate.h */; + name = "doomAppDelegate.h: 27"; + rLen = 0; + rLoc = 898; + rType = 0; + vrLen = 1144; + vrLoc = 0; + }; + ED60B15210B61ADE003A8B9F /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 434669A50F8D08C000EA7D6D /* doomAppDelegate.m */; + name = "doomAppDelegate.m: 215"; + rLen = 0; + rLoc = 6607; + rType = 0; + vrLen = 1018; + vrLoc = 1068; + }; + ED80ABFC10E930AC006AAD9D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7229CE460F6C89F8004123C5 /* EAGLView.m */; + name = "EAGLView.m: 345"; + rLen = 0; + rLoc = 9878; + rType = 0; + vrLen = 1103; + vrLoc = 9018; + }; + ED80ABFF10E930AC006AAD9D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7229CE460F6C89F8004123C5 /* EAGLView.m */; + name = "EAGLView.m: 345"; + rLen = 0; + rLoc = 9878; + rType = 0; + vrLen = 1103; + vrLoc = 9018; + }; + ED80AC0010E930AC006AAD9D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72A560E11004FAEE00F788A5 /* iphone_net.c */; + name = "iphone_net.c: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1501; + vrLoc = 16093; + }; + ED9AB3CF10966E85000B5852 /* iphone_email.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {662, 621}}"; + sepNavSelRange = "{319, 0}"; + sepNavVisRange = "{0, 319}"; + }; + }; + ED9AB3D010966E85000B5852 /* iphone_email.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {750, 3024}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 1042}"; + }; + }; + ED9AB3E410967730000B5852 /* PlistBookmark */ = { + isa = PlistBookmark; + fRef = 8D1107310486CEB800E47090 /* Info.plist */; + fallbackIsa = PBXBookmark; + isK = 0; + kPath = ( + UIPrerenderedIcon, + ); + name = /Users/greghodges/doom/code/iphone/Info.plist; + rLen = 0; + rLoc = 2147483647; + }; + ED9AB3E610967730000B5852 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = ED9AB3CF10966E85000B5852 /* iphone_email.h */; + name = "iphone_email.h: 15"; + rLen = 0; + rLoc = 319; + rType = 0; + vrLen = 319; + vrLoc = 0; + }; + ED9AB3E710967730000B5852 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = ED9AB3D010966E85000B5852 /* iphone_email.m */; + name = "iphone_email.m: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1042; + vrLoc = 0; + }; + ED9AB3E910967730000B5852 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7229CC8E0F6B3363004123C5 /* doomiphone.h */; + name = "doomiphone.h: 106"; + rLen = 0; + rLoc = 2492; + rType = 0; + vrLen = 1295; + vrLoc = 1199; + }; + ED9AB3EC10967730000B5852 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = ED9AB3CF10966E85000B5852 /* iphone_email.h */; + name = "iphone_email.h: 15"; + rLen = 0; + rLoc = 319; + rType = 0; + vrLen = 319; + vrLoc = 0; + }; + ED9AB3ED10967730000B5852 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72A55EEE1003A94300F788A5 /* iphone_start.c */; + name = "iphone_start.c: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 757; + vrLoc = 0; + }; + ED9AB3EF10967730000B5852 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = ED9AB3D010966E85000B5852 /* iphone_email.m */; + name = "iphone_email.m: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1042; + vrLoc = 0; + }; + ED9AB3F210967730000B5852 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43E8D2DF0F4FC61E003F09B2 /* iphone_main.c */; + name = "iphone_main.c: 334"; + rLen = 0; + rLoc = 8790; + rType = 0; + vrLen = 1755; + vrLoc = 7979; + }; + ED9AB3F310967730000B5852 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7229CC8E0F6B3363004123C5 /* doomiphone.h */; + name = "doomiphone.h: 106"; + rLen = 0; + rLoc = 2492; + rType = 0; + vrLen = 1295; + vrLoc = 1199; + }; + ED9BAB90108380AC00166CDA /* Doom */ = { + isa = PBXExecutable; + activeArgIndices = ( + ); + argumentStrings = ( + ); + autoAttachOnCrash = 1; + breakpointsEnabled = 0; + configStateDict = { + }; + customDataFormattersEnabled = 1; + dataTipCustomDataFormattersEnabled = 1; + dataTipShowTypeColumn = 1; + dataTipSortType = 0; + debuggerPlugin = GDBDebugging; + disassemblyDisplayState = 0; + dylibVariantSuffix = ""; + enableDebugStr = 1; + environmentEntries = ( + ); + executableSystemSymbolLevel = 0; + executableUserSymbolLevel = 0; + libgmallocEnabled = 0; + name = Doom; + savedGlobals = { + }; + showTypeColumn = 0; + sourceDirectories = ( + ); + }; + ED9BABAF108380C600166CDA /* Source Control */ = { + isa = PBXSourceControlManager; + fallbackIsa = XCSourceControlManager; + isSCMEnabled = 0; + scmConfiguration = { + repositoryNamesForRoots = { + "" = ""; + }; + }; + }; + ED9BABB0108380C600166CDA /* Code sense */ = { + isa = PBXCodeSenseManager; + indexTemplatePath = ""; + }; + ED9BABDF1083850C00166CDA /* PlistBookmark */ = { + isa = PlistBookmark; + fRef = 4364BF3E0F5CB25900F29317 /* dist.plist */; + fallbackIsa = PBXBookmark; + isK = 0; + kPath = ( + ); + name = /Users/greghodges/doom/code/iphone/dist.plist; + rLen = 0; + rLoc = 2147483647; + }; + ED9BABE11083850C00166CDA /* PlistBookmark */ = { + isa = PlistBookmark; + fRef = 8D1107310486CEB800E47090 /* Info.plist */; + fallbackIsa = PBXBookmark; + isK = 0; + kPath = ( + CFBundleIconFile, + ); + name = /Users/greghodges/doom/code/iphone/Info.plist; + rLen = 0; + rLoc = 2147483647; + }; + ED9BABE21083850C00166CDA /* PlistBookmark */ = { + isa = PlistBookmark; + fRef = 4364BF3E0F5CB25900F29317 /* dist.plist */; + fallbackIsa = PBXBookmark; + isK = 0; + kPath = ( + ); + name = /Users/greghodges/doom/code/iphone/dist.plist; + rLen = 0; + rLoc = 2147483647; + }; + EDA4D0A6110A1FCD0014EF0F /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + name = "iphone_menus.c: 595"; + rLen = 7; + rLoc = 16785; + rType = 0; + vrLen = 1348; + vrLoc = 16110; + }; + EDA4D0A7110A1FCD0014EF0F /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + name = "iphone_menus.c: 595"; + rLen = 7; + rLoc = 16785; + rType = 0; + vrLen = 1348; + vrLoc = 16110; + }; + EDA4D0A8110A1FCD0014EF0F /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72A560E11004FAEE00F788A5 /* iphone_net.c */; + name = "iphone_net.c: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1499; + vrLoc = 13317; + }; + EDADAE4110ED10F70056382E /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72A55EEE1003A94300F788A5 /* iphone_start.c */; + name = "iphone_start.c: 94"; + rLen = 10; + rLoc = 2085; + rType = 0; + vrLen = 1013; + vrLoc = 1556; + }; + EDADAE4210ED10F70056382E /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72A560E11004FAEE00F788A5 /* iphone_net.c */; + name = "iphone_net.c: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1499; + vrLoc = 13317; + }; + EDAFC7F5109A575F002C3487 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + name = "iphone_loop.c: 212"; + rLen = 14; + rLoc = 6159; + rType = 0; + vrLen = 1070; + vrLoc = 5677; + }; + EDAFC7F7109A575F002C3487 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8495E0F942B9300AB3C99 /* misc.c */; + name = "misc.c: 40"; + rLen = 0; + rLoc = 768; + rType = 0; + vrLen = 807; + vrLoc = 0; + }; + EDAFC7F8109A575F002C3487 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + name = "iphone_menus.c: 201"; + rLen = 13; + rLoc = 5284; + rType = 0; + vrLen = 1236; + vrLoc = 4701; + }; + EDAFC7F9109A575F002C3487 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + name = "iphone_loop.c: 212"; + rLen = 14; + rLoc = 6159; + rType = 0; + vrLen = 1070; + vrLoc = 5677; + }; + EDAFC818109A5B94002C3487 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72D50DBB0F8ED98000BB49E6 /* ipak.c */; + name = "ipak.c: 28"; + rLen = 7; + rLoc = 467; + rType = 0; + vrLen = 1190; + vrLoc = 359; + }; + EDAFC819109A5B94002C3487 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43E8D2DF0F4FC61E003F09B2 /* iphone_main.c */; + name = "iphone_main.c: 325"; + rLen = 7; + rLoc = 8411; + rType = 0; + vrLen = 1755; + vrLoc = 7979; + }; + EDAFC81B109A5B94002C3487 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72D50DBB0F8ED98000BB49E6 /* ipak.c */; + name = "ipak.c: 28"; + rLen = 7; + rLoc = 467; + rType = 0; + vrLen = 1190; + vrLoc = 359; + }; + EDD2763611C2B43F004A9B9B /* PlistBookmark */ = { + isa = PlistBookmark; + fRef = 8D1107310486CEB800E47090 /* Info.plist */; + fallbackIsa = PBXBookmark; + isK = 0; + kPath = ( + ); + name = /Volumes/Work/idMobileDepot/DoomClassicDepot/code/iphone/Info.plist; + rLen = 0; + rLoc = 9223372036854775807; + }; + EDD2763711C2B43F004A9B9B /* XCBuildMessageTextBookmark */ = { + isa = PBXTextBookmark; + comments = "Jump to label 'end'"; + fRef = 724C531E0FBDBCEE000E4348 /* BackgroundMusic.cpp */; + fallbackIsa = XCBuildMessageTextBookmark; + rLen = 1; + rLoc = 355; + rType = 1; + }; + EDD2763811C2B43F004A9B9B /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 724C531E0FBDBCEE000E4348 /* BackgroundMusic.cpp */; + name = "BackgroundMusic.cpp: 356"; + rLen = 0; + rLoc = 11880; + rType = 0; + vrLen = 2847; + vrLoc = 10470; + }; + EDD2764A11C2B47C004A9B9B /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 724C531E0FBDBCEE000E4348 /* BackgroundMusic.cpp */; + name = "BackgroundMusic.cpp: 344"; + rLen = 0; + rLoc = 11438; + rType = 0; + vrLen = 2847; + vrLoc = 10470; + }; + EDD2764D11C2B499004A9B9B /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 724C531E0FBDBCEE000E4348 /* BackgroundMusic.cpp */; + name = "BackgroundMusic.cpp: 344"; + rLen = 0; + rLoc = 11438; + rType = 0; + vrLen = 2899; + vrLoc = 10470; + }; + EDD2765011C2B4C2004A9B9B /* XCBuildMessageTextBookmark */ = { + isa = PBXTextBookmark; + comments = "Jump to label 'end'"; + fRef = 724C531E0FBDBCEE000E4348 /* BackgroundMusic.cpp */; + fallbackIsa = XCBuildMessageTextBookmark; + rLen = 1; + rLoc = 355; + rType = 1; + }; + EDD2765111C2B4C2004A9B9B /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 724C531E0FBDBCEE000E4348 /* BackgroundMusic.cpp */; + name = "BackgroundMusic.cpp: 364"; + rLen = 0; + rLoc = 12089; + rType = 0; + vrLen = 1932; + vrLoc = 4187; + }; + EDD2765411C2B4E4004A9B9B /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 724C531E0FBDBCEE000E4348 /* BackgroundMusic.cpp */; + name = "BackgroundMusic.cpp: 364"; + rLen = 0; + rLoc = 12089; + rType = 0; + vrLen = 1932; + vrLoc = 4187; + }; + EDD2765D11C2B634004A9B9B /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 724C531E0FBDBCEE000E4348 /* BackgroundMusic.cpp */; + name = "BackgroundMusic.cpp: 343"; + rLen = 0; + rLoc = 11337; + rType = 0; + vrLen = 2574; + vrLoc = 10271; + }; + EDFDF9B310A2054E0071CB9B /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72D50DBA0F8ED98000BB49E6 /* ipak.h */; + name = "ipak.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1502; + vrLoc = 287; + }; + EDFDF9B410A2054E0071CB9B /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8495E0F942B9300AB3C99 /* misc.c */; + name = "misc.c: 60"; + rLen = 0; + rLoc = 1496; + rType = 0; + vrLen = 964; + vrLoc = 869; + }; + EDFDF9B610A2054E0071CB9B /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72D50DBA0F8ED98000BB49E6 /* ipak.h */; + name = "ipak.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1502; + vrLoc = 287; + }; + EDFDF9C110A205F50071CB9B /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = EDFDF9C210A205F50071CB9B /* alc.h */; + name = "alc.h: 186"; + rLen = 0; + rLoc = 3852; + rType = 0; + vrLen = 1365; + vrLoc = 3211; + }; + EDFDF9C210A205F50071CB9B /* alc.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = alc.h; + path = /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator2.0.sdk/System/Library/Frameworks/OpenAL.framework/Headers/alc.h; + sourceTree = ""; + }; +} diff --git a/DoomClassic/code/iphone/Doom.xcodeproj/jeff.farrand.mode1v3 b/DoomClassic/code/iphone/Doom.xcodeproj/jeff.farrand.mode1v3 new file mode 100755 index 0000000..72b6697 --- /dev/null +++ b/DoomClassic/code/iphone/Doom.xcodeproj/jeff.farrand.mode1v3 @@ -0,0 +1,1396 @@ + + + + + ActivePerspectiveName + Morph + 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 + XCProjectFormatConflictsModule + Name + Project Format Conflicts List + + + 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 + + + BundleLoadPath + + MaxInstances + n + Module + XCSnapshotModule + Name + Snapshots Tool + + + BundlePath + /Developer/Library/PrivateFrameworks/DevToolsInterface.framework/Resources + Description + DefaultDescriptionKey + DockingSystemVisible + + Extension + mode1v3 + FavBarConfig + + PBXProjectModuleGUID + C861F25913BD2C7A00DB34A8 + XCBarModuleItemNames + + XCBarModuleItems + + + FirstTimeWindowDisplayed + + Identifier + com.apple.perspectives.project.mode1v3 + MajorVersion + 33 + MinorVersion + 0 + Name + Default + Notifications + + OpenEditors + + PerspectiveWidths + + 788 + 295 + + Perspectives + + + ChosenToolbarItems + + XCToolbarPerspectiveControl + NSToolbarSeparatorItem + active-combo-popup + action + NSToolbarFlexibleSpaceItem + debugger-enable-breakpoints + build-and-go + com.apple.ide.PBXToolbarStopButton + get-info + NSToolbarFlexibleSpaceItem + com.apple.pbx.toolbar.searchfield + + ControllerClassBaseName + + IconName + WindowOfProjectWithEditor + Identifier + perspective.project + IsVertical + + Layout + + + ContentConfiguration + + PBXBottomSmartGroupGIDs + + 1C37FBAC04509CD000000102 + 1C37FAAC04509CD000000102 + 1C37FABC05509CD000000102 + 1C37FABC05539CD112110102 + E2644B35053B69B200211256 + 1C37FABC04509CD000100104 + 1CC0EA4004350EF90044410B + 1CC0EA4004350EF90041110B + + PBXProjectModuleGUID + 1CE0B1FE06471DED0097A5F4 + PBXProjectModuleLabel + Files + PBXProjectStructureProvided + yes + PBXSmartGroupTreeModuleColumnData + + PBXSmartGroupTreeModuleColumnWidthsKey + + 186 + + PBXSmartGroupTreeModuleColumnsKey_v4 + + MainColumn + + + PBXSmartGroupTreeModuleOutlineStateKey_v7 + + PBXSmartGroupTreeModuleOutlineStateExpansionKey + + 29B97314FDCFA39411CA2CEA + 29B97315FDCFA39411CA2CEA + C86F965213D615BB0069B7B6 + 29B97317FDCFA39411CA2CEA + C84F820613D73D28006D01AB + 1C37FBAC04509CD000000102 + 1C37FABC05509CD000000102 + + PBXSmartGroupTreeModuleOutlineStateSelectionKey + + + 57 + 8 + 0 + + + PBXSmartGroupTreeModuleOutlineStateVisibleRectKey + {{0, 700}, {186, 789}} + + PBXTopSmartGroupGIDs + + XCIncludePerspectivesSwitch + + XCSharingToken + com.apple.Xcode.GFSharingToken + + GeometryConfiguration + + Frame + {{0, 0}, {203, 807}} + GroupTreeTableConfiguration + + MainColumn + 186 + + + Module + PBXSmartGroupTreeModule + Proportion + 203pt + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + 1CE0B20306471E060097A5F4 + PBXProjectModuleLabel + + PBXSplitModuleInNavigatorKey + + Split0 + + PBXProjectModuleGUID + 1CE0B20406471E060097A5F4 + PBXProjectModuleLabel + + + SplitCount + 1 + + StatusBarVisibility + + + GeometryConfiguration + + Frame + {{0, 0}, {580, 562}} + + Module + PBXNavigatorGroup + Proportion + 562pt + + + ContentConfiguration + + PBXProjectModuleGUID + 1CE0B20506471E060097A5F4 + PBXProjectModuleLabel + Detail + + GeometryConfiguration + + Frame + {{0, 567}, {580, 240}} + + Module + XCDetailModule + Proportion + 240pt + + + Proportion + 580pt + + + Name + Project + ServiceClasses + + XCModuleDock + PBXSmartGroupTreeModule + XCModuleDock + PBXNavigatorGroup + XCDetailModule + + TableOfContents + + C8139A4E13F9DCAD0094C2C0 + 1CE0B1FE06471DED0097A5F4 + C8139A4F13F9DCAD0094C2C0 + 1CE0B20306471E060097A5F4 + 1CE0B20506471E060097A5F4 + + ToolbarConfigUserDefaultsMinorVersion + 2 + ToolbarConfiguration + xcode.toolbar.config.defaultV3 + + + ChosenToolbarItems + + XCToolbarPerspectiveControl + NSToolbarSeparatorItem + active-combo-popup + com.apple.ide.PBXToolbarStopButton + build-and-go + go + NSToolbarFlexibleSpaceItem + + ControllerClassBaseName + + IconName + WindowOfProject + Identifier + perspective.morph + IsVertical + + Layout + + + BecomeActive + + ContentConfiguration + + PBXBottomSmartGroupGIDs + + 1C37FBAC04509CD000000102 + 1C37FAAC04509CD000000102 + 1C37FABC05509CD000000102 + 1C37FABC05539CD112110102 + E2644B35053B69B200211256 + 1C37FABC04509CD000100104 + 1CC0EA4004350EF90044410B + 1CC0EA4004350EF90041110B + + PBXProjectModuleGUID + 11E0B1FE06471DED0097A5F4 + PBXProjectModuleLabel + Files + PBXProjectStructureProvided + yes + PBXSmartGroupTreeModuleColumnData + + PBXSmartGroupTreeModuleColumnWidthsKey + + 278 + + PBXSmartGroupTreeModuleColumnsKey_v4 + + MainColumn + + + PBXSmartGroupTreeModuleOutlineStateKey_v7 + + PBXSmartGroupTreeModuleOutlineStateExpansionKey + + 29B97314FDCFA39411CA2CEA + 29B97317FDCFA39411CA2CEA + 1C37FBAC04509CD000000102 + 1C37FABC05509CD000000102 + + PBXSmartGroupTreeModuleOutlineStateSelectionKey + + + 7 + 0 + + + PBXSmartGroupTreeModuleOutlineStateVisibleRectKey + {{0, 0}, {278, 768}} + + PBXTopSmartGroupGIDs + + XCIncludePerspectivesSwitch + + XCSharingToken + com.apple.Xcode.GFSharingToken + + GeometryConfiguration + + Frame + {{0, 0}, {295, 786}} + GroupTreeTableConfiguration + + MainColumn + 278 + + RubberWindowFrame + 86 717 295 827 0 0 2560 1578 + + Module + PBXSmartGroupTreeModule + Proportion + 295pt + + + Name + Morph + PreferredWidth + 300 + ServiceClasses + + XCModuleDock + PBXSmartGroupTreeModule + + TableOfContents + + C8139A5013F9DCAD0094C2C0 + 11E0B1FE06471DED0097A5F4 + + ToolbarConfigUserDefaultsMinorVersion + 2 + ToolbarConfiguration + xcode.toolbar.config.default.shortV3 + + + PerspectivesBarVisible + + ShelfIsVisible + + SourceDescription + file at '/Developer/Library/PrivateFrameworks/DevToolsInterface.framework/Resources/XCPerspectivesSpecificationMode1.xcperspec' + StatusbarIsVisible + + TimeStamp + 0.0 + ToolbarConfigUserDefaultsMinorVersion + 2 + ToolbarDisplayMode + 2 + ToolbarIsVisible + + ToolbarSizeMode + 2 + 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 + + 1C530D57069F1CE1000CFCEE + C8139A7513F9DFEC0094C2C0 + C8139A7613F9DFEC0094C2C0 + 1C78EAAD065D492600B07095 + 1CD10A99069EF8BA00B06720 + C861F25A13BD2C7A00DB34A8 + /Volumes/Work/idMobileDepot/Archive/DoomClassicDepot/code/iphone/Doom.xcodeproj + + WindowString + 86 717 295 827 0 0 2560 1578 + WindowToolsV3 + + + FirstTimeWindowDisplayed + + Identifier + windowTool.build + IsVertical + + Layout + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + 1CD0528F0623707200166675 + PBXProjectModuleLabel + + StatusBarVisibility + + + GeometryConfiguration + + Frame + {{0, 0}, {1194, 0}} + RubberWindowFrame + 385 804 1194 740 0 0 2560 1578 + + Module + PBXNavigatorGroup + Proportion + 0pt + + + BecomeActive + + ContentConfiguration + + PBXProjectModuleGUID + XCMainBuildResultsModuleGUID + PBXProjectModuleLabel + Build Results + XCBuildResultsTrigger_Collapse + 1021 + XCBuildResultsTrigger_Open + 1011 + + GeometryConfiguration + + Frame + {{0, 5}, {1194, 694}} + RubberWindowFrame + 385 804 1194 740 0 0 2560 1578 + + Module + PBXBuildResultsModule + Proportion + 694pt + + + Proportion + 699pt + + + Name + Build Results + ServiceClasses + + PBXBuildResultsModule + + StatusbarIsVisible + + TableOfContents + + C861F25A13BD2C7A00DB34A8 + C8139A5113F9DCAD0094C2C0 + 1CD0528F0623707200166675 + XCMainBuildResultsModuleGUID + + ToolbarConfiguration + xcode.toolbar.config.buildV3 + WindowContentMinSize + 486 300 + WindowString + 385 804 1194 740 0 0 2560 1578 + WindowToolGUID + C861F25A13BD2C7A00DB34A8 + WindowToolIsVisible + + + + FirstTimeWindowDisplayed + + Identifier + windowTool.debugger + IsVertical + + Layout + + + Dock + + + ContentConfiguration + + Debugger + + HorizontalSplitView + + _collapsingFrameDimension + 0.0 + _indexOfCollapsedView + 0 + _percentageOfCollapsedView + 0.0 + isCollapsed + yes + sizes + + {{0, 0}, {857, 448}} + {{0, 448}, {857, 449}} + + + VerticalSplitView + + _collapsingFrameDimension + 0.0 + _indexOfCollapsedView + 0 + _percentageOfCollapsedView + 0.0 + isCollapsed + yes + sizes + + {{0, 0}, {857, 897}} + {{857, 0}, {856, 897}} + + + + LauncherConfigVersion + 8 + PBXProjectModuleGUID + 1C162984064C10D400B95A72 + PBXProjectModuleLabel + Debug - GLUTExamples (Underwater) + + GeometryConfiguration + + DebugConsoleVisible + None + DebugConsoleWindowFrame + {{200, 200}, {500, 300}} + DebugSTDIOWindowFrame + {{200, 200}, {500, 300}} + Frame + {{0, 0}, {1713, 897}} + PBXDebugSessionStackFrameViewKey + + DebugVariablesTableConfiguration + + Name + 217 + Value + 85 + Summary + 530 + + Frame + {{0, 448}, {857, 449}} + RubberWindowFrame + 403 451 1713 938 0 0 2560 1578 + + RubberWindowFrame + 403 451 1713 938 0 0 2560 1578 + + Module + PBXDebugSessionModule + Proportion + 897pt + + + Proportion + 897pt + + + Name + Debugger + ServiceClasses + + PBXDebugSessionModule + + StatusbarIsVisible + + TableOfContents + + 1CD10A99069EF8BA00B06720 + C8139A6E13F9DFEC0094C2C0 + 1C162984064C10D400B95A72 + C8139A6F13F9DFEC0094C2C0 + C8139A7013F9DFEC0094C2C0 + C8139A7113F9DFEC0094C2C0 + C8139A7213F9DFEC0094C2C0 + C8139A7313F9DFEC0094C2C0 + + ToolbarConfiguration + xcode.toolbar.config.debugV3 + WindowString + 403 451 1713 938 0 0 2560 1578 + WindowToolGUID + 1CD10A99069EF8BA00B06720 + WindowToolIsVisible + + + + FirstTimeWindowDisplayed + + Identifier + windowTool.find + IsVertical + + Layout + + + Dock + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + 1CDD528C0622207200134675 + PBXProjectModuleLabel + <No Editor> + StatusBarVisibility + + + GeometryConfiguration + + Frame + {{0, 0}, {1231, 451}} + RubberWindowFrame + 137 320 1231 879 0 0 2560 1578 + + Module + PBXNavigatorGroup + Proportion + 1231pt + + + Proportion + 451pt + + + ContentConfiguration + + PBXProjectModuleGUID + 1CD0528E0623707200166675 + PBXProjectModuleLabel + Project Find + + GeometryConfiguration + + Frame + {{0, 456}, {1231, 382}} + RubberWindowFrame + 137 320 1231 879 0 0 2560 1578 + + Module + PBXProjectFindModule + Proportion + 382pt + + + Proportion + 838pt + + + Name + Project Find + ServiceClasses + + PBXProjectFindModule + + StatusbarIsVisible + + TableOfContents + + 1C530D57069F1CE1000CFCEE + C8139AF713FB133A0094C2C0 + C8139AF813FB133A0094C2C0 + 1CDD528C0622207200134675 + 1CD0528E0623707200166675 + + WindowString + 137 320 1231 879 0 0 2560 1578 + WindowToolGUID + 1C530D57069F1CE1000CFCEE + WindowToolIsVisible + + + + Identifier + MENUSEPARATOR + + + FirstTimeWindowDisplayed + + Identifier + windowTool.debuggerConsole + IsVertical + + Layout + + + Dock + + + BecomeActive + + ContentConfiguration + + PBXProjectModuleGUID + 1C78EAAC065D492600B07095 + PBXProjectModuleLabel + Debugger Console + + GeometryConfiguration + + Frame + {{0, 0}, {693, 503}} + RubberWindowFrame + 1048 670 693 544 0 0 2560 1578 + + Module + PBXDebugCLIModule + Proportion + 503pt + + + Proportion + 503pt + + + Name + Debugger Console + ServiceClasses + + PBXDebugCLIModule + + StatusbarIsVisible + + TableOfContents + + 1C78EAAD065D492600B07095 + C8139A7413F9DFEC0094C2C0 + 1C78EAAC065D492600B07095 + + ToolbarConfiguration + xcode.toolbar.config.consoleV3 + WindowString + 1048 670 693 544 0 0 2560 1578 + WindowToolGUID + 1C78EAAD065D492600B07095 + WindowToolIsVisible + + + + Identifier + windowTool.snapshots + Layout + + + Dock + + + Module + XCSnapshotModule + Proportion + 100% + + + Proportion + 100% + + + Name + Snapshots + ServiceClasses + + XCSnapshotModule + + StatusbarIsVisible + Yes + ToolbarConfiguration + xcode.toolbar.config.snapshots + WindowString + 315 824 300 550 0 0 1440 878 + WindowToolIsVisible + Yes + + + 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.0950012207031 + + 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 + 3 + MinorVersion + 0 + Name + Breakpoints + ServiceClasses + + PBXSmartGroupTreeModule + XCDetailModule + + StatusbarIsVisible + 1 + TableOfContents + + 1CDDB66807F98D9800BB5817 + 1CDDB66907F98D9800BB5817 + 1CE0B1FE06471DED0097A5F4 + 1CA1AED706398EBD00589147 + + ToolbarConfiguration + xcode.toolbar.config.breakpointsV3 + 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.debugAnimatorV3 + 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.projectFormatConflicts + Layout + + + Dock + + + Module + XCProjectFormatConflictsModule + Proportion + 100% + + + Proportion + 100% + + + Name + Project Format Conflicts + ServiceClasses + + XCProjectFormatConflictsModule + + StatusbarIsVisible + 0 + WindowContentMinSize + 450 300 + WindowString + 50 850 472 307 0 0 1440 877 + + + 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 + + + Identifier + windowTool.refactoring + IncludeInToolsMenu + 0 + Layout + + + Dock + + + BecomeActive + 1 + GeometryConfiguration + + Frame + {0, 0}, {500, 335} + RubberWindowFrame + {0, 0}, {500, 335} + + Module + XCRefactoringModule + Proportion + 100% + + + Proportion + 100% + + + Name + Refactoring + ServiceClasses + + XCRefactoringModule + + WindowString + 200 200 500 356 0 0 1920 1200 + + + + diff --git a/DoomClassic/code/iphone/Doom.xcodeproj/jeff.farrand.pbxuser b/DoomClassic/code/iphone/Doom.xcodeproj/jeff.farrand.pbxuser new file mode 100755 index 0000000..46bc192 --- /dev/null +++ b/DoomClassic/code/iphone/Doom.xcodeproj/jeff.farrand.pbxuser @@ -0,0 +1,859 @@ +// !$*UTF8*$! +{ + 1D6058900D05DD3D006BFB54 /* Doom */ = { + activeExec = 0; + executables = ( + C861F24F13BD2C7700DB34A8 /* Doom */, + ); + }; + 29B97313FDCFA39411CA2CEA /* Project object */ = { + activeBuildConfigurationName = Distribution; + activeExecutable = C861F24F13BD2C7700DB34A8 /* Doom */; + activeSDKPreference = iphoneos4.3; + activeTarget = 1D6058900D05DD3D006BFB54 /* Doom */; + addToTargets = ( + 1D6058900D05DD3D006BFB54 /* Doom */, + ); + breakpoints = ( + C885311113D8CF7A00A5FBF7 /* gl_main.c:1961 */, + C885311313D8CF8000A5FBF7 /* gl_main.c:1958 */, + ); + codeSenseManager = C861F25D13BD2C7A00DB34A8 /* Code sense */; + executables = ( + C861F24F13BD2C7700DB34A8 /* Doom */, + ); + perUserDictionary = { + PBXConfiguration.PBXFileTableDataSource3.PBXFileTableDataSource = { + PBXFileTableDataSourceColumnSortingDirectionKey = "-1"; + PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID; + PBXFileTableDataSourceColumnWidthsKey = ( + 20, + 341, + 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, + 301, + 60, + 20, + 48.16259765625, + 43, + 43, + ); + PBXFileTableDataSourceColumnsKey = ( + PBXFileDataSource_FiletypeID, + PBXFileDataSource_Filename_ColumnID, + PBXTargetDataSource_PrimaryAttribute, + PBXFileDataSource_Built_ColumnID, + PBXFileDataSource_ObjectSize_ColumnID, + PBXFileDataSource_Errors_ColumnID, + PBXFileDataSource_Warnings_ColumnID, + ); + }; + PBXPerProjectTemplateStateSaveDate = 335141858; + PBXWorkspaceStateSaveDate = 335141858; + }; + sourceControlManager = C861F25C13BD2C7A00DB34A8 /* Source Control */; + userBuildSettings = { + }; + }; + 29B97316FDCFA39411CA2CEA /* main.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1436, 837}}"; + sepNavSelRange = "{807, 0}"; + sepNavVisRange = "{0, 1417}"; + sepNavWindowFrame = "{{258, 17}, {1495, 988}}"; + }; + }; + 434669A40F8D08C000EA7D6D /* doomAppDelegate.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {975, 946}}"; + sepNavSelRange = "{1749, 38}"; + sepNavVisRange = "{0, 2185}"; + sepNavWindowFrame = "{{305, 0}, {1034, 1074}}"; + }; + }; + 434669A50F8D08C000EA7D6D /* doomAppDelegate.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {975, 5590}}"; + sepNavSelRange = "{10774, 0}"; + sepNavVisRange = "{9736, 1348}"; + sepNavWindowFrame = "{{582, 18}, {1034, 1074}}"; + }; + }; + 43A945140F82D75900FFD32E /* iphone_sys.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1436, 860}}"; + sepNavSelRange = "{1155, 0}"; + sepNavVisRange = "{0, 1456}"; + sepNavWindowFrame = "{{338, 149}, {1495, 988}}"; + }; + }; + 43CF02FE0F56974E00E4A23D /* Default.png */ = { + uiCtxt = { + sepNavWindowFrame = "{{141, 122}, {1494, 988}}"; + }; + }; + 43CF03090F56D5C200E4A23D /* iphone_loop.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1170, 23244}}"; + sepNavSelRange = "{35580, 16}"; + sepNavVisRange = "{34567, 1066}"; + sepNavWindowFrame = "{{422, 82}, {1495, 988}}"; + }; + }; + 43DD8391100295F70006E1DD /* iphone_async.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1170, 12766}}"; + sepNavSelRange = "{15359, 0}"; + sepNavVisRange = "{14906, 953}"; + sepNavWindowFrame = "{{385, 87}, {1020, 1074}}"; + }; + }; + 43E8D2DF0F4FC61E003F09B2 /* iphone_main.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1436, 6370}}"; + sepNavSelRange = "{13195, 24}"; + sepNavVisRange = "{12907, 1397}"; + sepNavWindowFrame = "{{378, 95}, {1495, 988}}"; + }; + }; + 7229CC8E0F6B3363004123C5 /* doomiphone.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1436, 1729}}"; + sepNavSelRange = "{2545, 0}"; + sepNavVisRange = "{1637, 1684}"; + sepNavWindowFrame = "{{250, 102}, {1495, 988}}"; + }; + }; + 7229CE450F6C89F8004123C5 /* EAGLView.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1436, 837}}"; + sepNavSelRange = "{1326, 0}"; + sepNavVisRange = "{0, 1452}"; + sepNavWindowFrame = "{{339, 120}, {1495, 988}}"; + }; + }; + 7229CE460F6C89F8004123C5 /* EAGLView.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {795, 5239}}"; + sepNavSelRange = "{10535, 0}"; + sepNavVisRange = "{9431, 1714}"; + sepNavWindowFrame = "{{339, 120}, {1495, 988}}"; + }; + }; + 7229CE540F6C8CDE004123C5 /* gles_glue.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {961, 2613}}"; + sepNavSelRange = "{4886, 0}"; + sepNavVisRange = "{2348, 1738}"; + sepNavWindowFrame = "{{117, 57}, {1020, 1074}}"; + }; + }; + 7239452B0F9C0E7500EADD62 /* iphone_mapSelect.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1170, 6032}}"; + sepNavSelRange = "{9756, 0}"; + sepNavVisRange = "{9339, 1082}"; + sepNavWindowFrame = "{{432, 79}, {1020, 1074}}"; + }; + }; + 72484E5D0FB0E99900124E1C /* iphone_render.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1170, 23283}}"; + sepNavSelRange = "{39537, 12}"; + sepNavVisRange = "{38797, 993}"; + sepNavWindowFrame = "{{442, 119}, {1495, 988}}"; + }; + }; + 724C531E0FBDBCEE000E4348 /* BackgroundMusic.cpp */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1027, 7306}}"; + sepNavSelRange = "{17453, 0}"; + sepNavVisRange = "{16201, 1360}"; + sepNavWindowFrame = "{{814, 31}, {1013, 1096}}"; + }; + }; + 727886A20FBDBA740020D469 /* gles_glue.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1436, 837}}"; + sepNavSelRange = "{813, 0}"; + sepNavVisRange = "{0, 1318}"; + sepNavWindowFrame = "{{143, 122}, {1495, 988}}"; + }; + }; + 72A55EEE1003A94300F788A5 /* iphone_start.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1170, 2951}}"; + sepNavSelRange = "{1098, 16}"; + sepNavVisRange = "{871, 652}"; + sepNavWindowFrame = "{{330, 73}, {1013, 1096}}"; + }; + }; + 72A560E11004FAEE00F788A5 /* iphone_net.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {943, 7917}}"; + sepNavSelRange = "{11148, 0}"; + sepNavVisRange = "{10878, 2023}"; + }; + }; + 72A7E8F30F5F2001005B83C0 /* iphone_doom.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1436, 7267}}"; + sepNavSelRange = "{3966, 0}"; + sepNavVisRange = "{3109, 1821}"; + sepNavWindowFrame = "{{338, 79}, {1495, 988}}"; + }; + }; + 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1170, 11713}}"; + sepNavSelRange = "{12956, 11}"; + sepNavVisRange = "{12441, 1092}"; + sepNavWindowFrame = "{{361, 84}, {1495, 988}}"; + }; + }; + 72B5FF380F7E5C3D00C8A372 /* hud.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1435, 2899}}"; + sepNavSelRange = "{2031, 0}"; + sepNavVisRange = "{1549, 2560}"; + sepNavWindowFrame = "{{478, 283}, {1494, 988}}"; + }; + }; + 72D50DBA0F8ED98000BB49E6 /* ipak.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1436, 2379}}"; + sepNavSelRange = "{1539, 0}"; + sepNavVisRange = "{2918, 1995}"; + sepNavWindowFrame = "{{166, 101}, {1495, 988}}"; + }; + }; + 72D50DBB0F8ED98000BB49E6 /* ipak.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1170, 4901}}"; + sepNavSelRange = "{3115, 0}"; + sepNavVisRange = "{2968, 1187}"; + }; + }; + 72E731EA0F97E68100E702CD /* iphone_sound.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1170, 3731}}"; + sepNavSelRange = "{4780, 0}"; + sepNavVisRange = "{4469, 975}"; + sepNavWindowFrame = "{{74, 99}, {1034, 1074}}"; + }; + }; + 72E847640F93C61900AB3C99 /* am_map.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1170, 20709}}"; + sepNavSelRange = "{40979, 11}"; + sepNavVisRange = "{40171, 1067}"; + }; + }; + 72E847680F93FF2F00AB3C99 /* config.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1170, 1391}}"; + sepNavSelRange = "{5, 25}"; + sepNavVisRange = "{0, 779}"; + }; + }; + 72E847700F93FFDB00AB3C99 /* d_deh.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1170, 40040}}"; + sepNavSelRange = "{90350, 3}"; + sepNavVisRange = "{89773, 1257}"; + }; + }; + 72E8477C0F9400D700AB3C99 /* d_main.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1170, 22971}}"; + sepNavSelRange = "{8166, 19}"; + sepNavVisRange = "{5621, 886}"; + }; + }; + 72E847820F9400D700AB3C99 /* d_ticcmd.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {975, 946}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 2087}"; + sepNavWindowFrame = "{{120, 57}, {1034, 1074}}"; + }; + }; + 72E847840F9400D700AB3C99 /* doomdef.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1170, 637}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{923, 791}"; + }; + }; + 72E847850F9400D700AB3C99 /* doomdef.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1170, 4511}}"; + sepNavSelRange = "{3355, 0}"; + sepNavVisRange = "{3067, 869}"; + }; + }; + 72E847870F9400D700AB3C99 /* doomstat.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {795, 4407}}"; + sepNavSelRange = "{8186, 103}"; + sepNavVisRange = "{1261, 2035}"; + }; + }; + 72E847880F9400D700AB3C99 /* doomtype.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {954, 1677}}"; + sepNavSelRange = "{1683, 36}"; + sepNavVisRange = "{1780, 2766}"; + sepNavWindowFrame = "{{117, 35}, {1013, 1096}}"; + }; + }; + 72E8478D0F9400D700AB3C99 /* f_wipe.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1170, 2613}}"; + sepNavSelRange = "{1943, 15}"; + sepNavVisRange = "{1511, 568}"; + }; + }; + 72E8478F0F9400D700AB3C99 /* g_game.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1133, 38753}}"; + sepNavSelRange = "{45949, 0}"; + sepNavVisRange = "{45385, 979}"; + sepNavWindowFrame = "{{432, 40}, {1020, 1074}}"; + }; + }; + 72E847900F9400D700AB3C99 /* g_game.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1133, 2301}}"; + sepNavSelRange = "{2038, 0}"; + sepNavVisRange = "{1507, 1552}"; + }; + }; + 72E847920F9400D700AB3C99 /* gl_main.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {957, 38675}}"; + sepNavSelRange = "{68792, 0}"; + sepNavVisRange = "{67681, 1381}"; + }; + }; + 72E847940F9400D700AB3C99 /* gl_texture.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1170, 14833}}"; + sepNavSelRange = "{4039, 9}"; + sepNavVisRange = "{2189, 719}"; + }; + }; + 72E847950F9400D700AB3C99 /* hu_lib.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1170, 9594}}"; + sepNavSelRange = "{6401, 9}"; + sepNavVisRange = "{6054, 847}"; + }; + }; + 72E847AA0F9400D700AB3C99 /* m_menu.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1170, 73606}}"; + sepNavSelRange = "{75941, 9}"; + sepNavVisRange = "{75515, 846}"; + }; + }; + 72E847AC0F9400D700AB3C99 /* m_misc.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {803, 14274}}"; + sepNavSelRange = "{2940, 48}"; + sepNavVisRange = "{2182, 1395}"; + sepNavWindowFrame = "{{120, 143}, {1495, 988}}"; + }; + }; + 72E847CA0F94096C00AB3C99 /* SDL_opengl.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1170, 2834}}"; + sepNavSelRange = "{1988, 9}"; + sepNavVisRange = "{1587, 1159}"; + }; + }; + 72E847E80F941A5900AB3C99 /* p_enemy.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1170, 33345}}"; + sepNavSelRange = "{57961, 8}"; + sepNavVisRange = "{57509, 924}"; + }; + }; + 72E847EF0F941A5900AB3C99 /* p_map.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {579, 30563}}"; + sepNavSelRange = "{62364, 0}"; + sepNavVisRange = "{60545, 1308}"; + sepNavWindowFrame = "{{161, 15}, {1020, 1074}}"; + }; + }; + 72E847F10F941A5900AB3C99 /* p_maputl.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {579, 8307}}"; + sepNavSelRange = "{12207, 5}"; + sepNavVisRange = "{11014, 1594}"; + }; + }; + 72E847F30F941A5900AB3C99 /* p_mobj.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {614, 19903}}"; + sepNavSelRange = "{36423, 0}"; + sepNavVisRange = "{24142, 1382}"; + }; + }; + 72E847F80F941A5900AB3C99 /* p_saveg.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {795, 13546}}"; + sepNavSelRange = "{7502, 0}"; + sepNavVisRange = "{6470, 1758}"; + }; + }; + 72E847FA0F941A5900AB3C99 /* p_setup.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {795, 22386}}"; + sepNavSelRange = "{52386, 0}"; + sepNavVisRange = "{51170, 1404}"; + }; + }; + 72E848010F941A5900AB3C99 /* p_tick.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {975, 3796}}"; + sepNavSelRange = "{1529, 0}"; + sepNavVisRange = "{6515, 1880}"; + sepNavWindowFrame = "{{441, 79}, {1034, 1074}}"; + }; + }; + 72E8481F0F941A8300AB3C99 /* r_data.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {663, 9490}}"; + sepNavSelRange = "{18820, 0}"; + sepNavVisRange = "{18175, 1283}"; + }; + }; + 72E848210F941A8300AB3C99 /* r_defs.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1170, 5772}}"; + sepNavSelRange = "{13256, 15}"; + sepNavVisRange = "{12677, 758}"; + }; + }; + 72E848240F941A8300AB3C99 /* r_draw.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1436, 14534}}"; + sepNavSelRange = "{2082, 0}"; + sepNavVisRange = "{0, 2309}"; + sepNavWindowFrame = "{{97, 164}, {1495, 988}}"; + }; + }; + 72E8482C0F941AAC00AB3C99 /* r_fps.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1076, 5408}}"; + sepNavSelRange = "{6475, 0}"; + sepNavVisRange = "{5696, 1799}"; + }; + }; + 72E8482E0F941AAC00AB3C99 /* r_main.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {615, 8489}}"; + sepNavSelRange = "{10582, 0}"; + sepNavVisRange = "{10221, 944}"; + }; + }; + 72E8482F0F941AAC00AB3C99 /* r_main.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1436, 1677}}"; + sepNavSelRange = "{1669, 9}"; + sepNavVisRange = "{726, 1672}"; + sepNavWindowFrame = "{{74, 185}, {1495, 988}}"; + }; + }; + 72E848390F941AAC00AB3C99 /* r_things.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1170, 13858}}"; + sepNavSelRange = "{23894, 10}"; + sepNavVisRange = "{23446, 766}"; + }; + }; + 72E8483B0F941AAC00AB3C99 /* s_sound.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1170, 9620}}"; + sepNavSelRange = "{14012, 15}"; + sepNavVisRange = "{13585, 796}"; + }; + }; + 72E8484B0F941ADC00AB3C99 /* st_stuff.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {615, 1469}}"; + sepNavSelRange = "{1775, 54}"; + sepNavVisRange = "{1111, 1199}"; + }; + }; + 72E848540F941ADC00AB3C99 /* w_wad.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {705, 5629}}"; + sepNavSelRange = "{8919, 0}"; + sepNavVisRange = "{9326, 1979}"; + }; + }; + 72E8495C0F942B9300AB3C99 /* cvar.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {795, 4784}}"; + sepNavSelRange = "{5299, 0}"; + sepNavVisRange = "{4783, 1173}"; + sepNavWindowFrame = "{{235, 38}, {1495, 988}}"; + }; + }; + 72E8495E0F942B9300AB3C99 /* misc.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {795, 1183}}"; + sepNavSelRange = "{959, 0}"; + sepNavVisRange = "{654, 1355}"; + }; + }; + 72E8495F0F942B9300AB3C99 /* misc.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1436, 975}}"; + sepNavSelRange = "{905, 0}"; + sepNavVisRange = "{128, 2344}"; + sepNavWindowFrame = "{{97, 164}, {1495, 988}}"; + }; + }; + 72E849F50F94ED1100AB3C99 /* prboomInterface.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {607, 4602}}"; + sepNavSelRange = "{1876, 0}"; + sepNavVisRange = "{1393, 1085}"; + sepNavWindowFrame = "{{120, 143}, {1495, 988}}"; + }; + }; + 8D1107310486CEB800E47090 /* Info.plist */ = { + uiCtxt = { + sepNavWindowFrame = "{{430, 53}, {1020, 1074}}"; + }; + }; + C8139A7813F9E0440094C2C0 /* UICustomSlider.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1211, 925}}"; + sepNavSelRange = "{381, 0}"; + sepNavVisRange = "{0, 489}"; + sepNavWindowFrame = "{{188, 450}, {1270, 1076}}"; + }; + }; + C8139AB213FADA800094C2C0 /* SliderSkull@2x.png */ = { + uiCtxt = { + sepNavWindowFrame = "{{120, 455}, {1270, 1076}}"; + }; + }; + C8139AB413FADA9D0094C2C0 /* SliderSkull~ipad.png */ = { + uiCtxt = { + sepNavWindowFrame = "{{143, 434}, {1270, 1076}}"; + }; + }; + C81E0C7013DF471000B1049A /* UIFontButton.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {975, 946}}"; + sepNavSelRange = "{337, 0}"; + sepNavVisRange = "{0, 617}"; + sepNavWindowFrame = "{{598, 99}, {1034, 1074}}"; + }; + }; + C81E0C7113DF471000B1049A /* UIFontButton.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {975, 1547}}"; + sepNavSelRange = "{487, 0}"; + sepNavVisRange = "{34, 1751}"; + sepNavWindowFrame = "{{859, 141}, {1034, 1074}}"; + }; + }; + C81E0C8D13DF4A1B00B1049A /* UIFontLabel.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {975, 923}}"; + sepNavSelRange = "{207, 0}"; + sepNavVisRange = "{0, 216}"; + }; + }; + C81E0C8E13DF4A1B00B1049A /* UIFontLabel.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {975, 923}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 341}"; + sepNavWindowFrame = "{{720, 70}, {1034, 1074}}"; + }; + }; + C81E104113E1CCA000B1049A /* Button.png */ = { + uiCtxt = { + sepNavWindowFrame = "{{1105, 424}, {1289, 1086}}"; + }; + }; + C84F829013D76E96006D01AB /* MapMenuView.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {961, 4381}}"; + sepNavSelRange = "{3960, 0}"; + sepNavVisRange = "{3339, 1855}"; + sepNavWindowFrame = "{{362, 0}, {1020, 1074}}"; + }; + }; + C84F829113D76E96006D01AB /* MapMenuView.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {961, 1352}}"; + sepNavSelRange = "{234, 0}"; + sepNavVisRange = "{0, 1787}"; + sepNavWindowFrame = "{{801, 14}, {1020, 1074}}"; + }; + }; + C84F83F413D7A99C006D01AB /* GenericMenuView.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {961, 946}}"; + sepNavSelRange = "{560, 16}"; + sepNavVisRange = "{0, 851}"; + sepNavWindowFrame = "{{437, 37}, {1020, 1074}}"; + }; + }; + C84F83F513D7A99C006D01AB /* GenericMenuView.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {961, 1404}}"; + sepNavSelRange = "{1234, 0}"; + sepNavVisRange = "{727, 1690}"; + sepNavWindowFrame = "{{445, 418}, {1020, 1074}}"; + }; + }; + C84F855713D8B55C006D01AB /* SettingsMenuView.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {961, 946}}"; + sepNavSelRange = "{501, 0}"; + sepNavVisRange = "{0, 983}"; + sepNavWindowFrame = "{{737, 146}, {1020, 1074}}"; + }; + }; + C84F855813D8B55C006D01AB /* SettingsMenuView.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {961, 1508}}"; + sepNavSelRange = "{968, 0}"; + sepNavVisRange = "{867, 1642}"; + sepNavWindowFrame = "{{731, 79}, {1020, 1074}}"; + }; + }; + C861F24F13BD2C7700DB34A8 /* Doom */ = { + isa = PBXExecutable; + activeArgIndices = ( + ); + argumentStrings = ( + ); + autoAttachOnCrash = 1; + breakpointsEnabled = 1; + configStateDict = { + }; + customDataFormattersEnabled = 1; + dataTipCustomDataFormattersEnabled = 1; + dataTipShowTypeColumn = 1; + dataTipSortType = 0; + debuggerPlugin = GDBDebugging; + disassemblyDisplayState = 0; + dylibVariantSuffix = ""; + enableDebugStr = 1; + environmentEntries = ( + ); + executableSystemSymbolLevel = 0; + executableUserSymbolLevel = 0; + libgmallocEnabled = 0; + name = Doom; + savedGlobals = { + }; + showTypeColumn = 0; + sourceDirectories = ( + ); + variableFormatDictionary = { + }; + }; + C861F25C13BD2C7A00DB34A8 /* Source Control */ = { + isa = PBXSourceControlManager; + fallbackIsa = XCSourceControlManager; + isSCMEnabled = 0; + scmConfiguration = { + repositoryNamesForRoots = { + ../.. = Rage; + }; + }; + }; + C861F25D13BD2C7A00DB34A8 /* Code sense */ = { + isa = PBXCodeSenseManager; + indexTemplatePath = ""; + }; + C86F965513D615F70069B7B6 /* MainMenuView.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {954, 945}}"; + sepNavSelRange = "{634, 182}"; + sepNavVisRange = "{0, 1366}"; + sepNavWindowFrame = "{{660, 48}, {1013, 1096}}"; + }; + }; + C86F966613D617740069B7B6 /* MenuViewController.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {954, 945}}"; + sepNavSelRange = "{242, 0}"; + sepNavVisRange = "{0, 253}"; + sepNavWindowFrame = "{{74, 77}, {1013, 1096}}"; + }; + }; + C86F966713D617740069B7B6 /* MenuViewController.mm */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {957, 968}}"; + sepNavSelRange = "{309, 0}"; + sepNavVisRange = "{0, 442}"; + sepNavWindowFrame = "{{542, 55}, {1013, 1096}}"; + }; + }; + C86F975C13D6377B0069B7B6 /* IBGlue.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1127, 585}}"; + sepNavSelRange = "{226, 0}"; + sepNavVisRange = "{0, 0}"; + sepNavWindowFrame = "{{517, 25}, {1020, 1074}}"; + }; + }; + C86F975D13D6377B0069B7B6 /* IBGlue.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {961, 946}}"; + sepNavSelRange = "{310, 0}"; + sepNavVisRange = "{0, 311}"; + sepNavWindowFrame = "{{545, 24}, {1020, 1074}}"; + }; + }; + C879308513F5D8AA003D834F /* DifficultyBackground.png */ = { + uiCtxt = { + sepNavWindowFrame = "{{143, 424}, {1289, 1086}}"; + }; + }; + C879308C13F5D8AA003D834F /* MissonBackground.png */ = { + uiCtxt = { + sepNavWindowFrame = "{{960, 209}, {1289, 1086}}"; + }; + }; + C879308E13F5D8AA003D834F /* UpArrow.png */ = { + uiCtxt = { + sepNavWindowFrame = "{{120, 445}, {1289, 1086}}"; + }; + }; + C87931E013F610B9003D834F /* Divide.png */ = { + uiCtxt = { + sepNavWindowFrame = "{{189, 382}, {1289, 1086}}"; + }; + }; + C87931E813F610B9003D834F /* SettingsButton.png */ = { + uiCtxt = { + sepNavWindowFrame = "{{212, 361}, {1289, 1086}}"; + }; + }; + C87931EB13F610B9003D834F /* SliderSkull.png */ = { + uiCtxt = { + sepNavWindowFrame = "{{568, 448}, {1270, 1076}}"; + }; + }; + C87931FF13F6143C003D834F /* UICustomSwitch.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1230, 958}}"; + sepNavSelRange = "{226, 0}"; + sepNavVisRange = "{0, 278}"; + }; + }; + C879320013F6143C003D834F /* UICustomSwitch.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1230, 935}}"; + sepNavSelRange = "{495, 0}"; + sepNavVisRange = "{0, 719}"; + sepNavWindowFrame = "{{405, 455}, {1289, 1086}}"; + }; + }; + C88530C813D8CBEA00A5FBF7 /* MainMenuView.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {795, 3263}}"; + sepNavSelRange = "{506, 0}"; + sepNavVisRange = "{153, 1477}"; + sepNavWindowFrame = "{{500, 378}, {1013, 1096}}"; + }; + }; + C885311113D8CF7A00A5FBF7 /* gl_main.c:1961 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E847920F9400D700AB3C99 /* gl_main.c */; + functionName = "gld_StartDrawScene()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1961; + modificationTime = 335298652.845627; + originalNumberOfMultipleMatches = 1; + state = 1; + }; + C885311313D8CF8000A5FBF7 /* gl_main.c:1958 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E847920F9400D700AB3C99 /* gl_main.c */; + functionName = "gld_StartDrawScene()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1958; + modificationTime = 335298652.845659; + originalNumberOfMultipleMatches = 1; + state = 1; + }; + C885314213D8D79400A5FBF7 /* ControlsMenuView.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {975, 2899}}"; + sepNavSelRange = "{1432, 0}"; + sepNavVisRange = "{912, 2131}"; + sepNavWindowFrame = "{{205, 358}, {1034, 1074}}"; + }; + }; + C885314313D8D79400A5FBF7 /* ControlsMenuView.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {975, 946}}"; + sepNavSelRange = "{466, 14}"; + sepNavVisRange = "{0, 781}"; + }; + }; + ED9AB3CF10966E85000B5852 /* iphone_email.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1170, 468}}"; + sepNavSelRange = "{7, 14}"; + sepNavVisRange = "{0, 955}"; + sepNavWindowFrame = "{{93, 78}, {1020, 1074}}"; + }; + }; + ED9AB3D010966E85000B5852 /* iphone_email.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1170, 3094}}"; + sepNavSelRange = "{888, 14}"; + sepNavVisRange = "{303, 924}"; + sepNavWindowFrame = "{{93, 78}, {1020, 1074}}"; + }; + }; +} diff --git a/DoomClassic/code/iphone/Doom.xcodeproj/johnc.pbxuser b/DoomClassic/code/iphone/Doom.xcodeproj/johnc.pbxuser new file mode 100755 index 0000000..f058fde --- /dev/null +++ b/DoomClassic/code/iphone/Doom.xcodeproj/johnc.pbxuser @@ -0,0 +1,13013 @@ +// !$*UTF8*$! +{ + 1D6058900D05DD3D006BFB54 /* Doom */ = { + activeExec = 0; + executables = ( + 72AD09A80FA224D0000999A0 /* Doom */, + ); + }; + 29B97313FDCFA39411CA2CEA /* Project object */ = { + activeBuildConfigurationName = Debug; + activeExecutable = 72AD09A80FA224D0000999A0 /* Doom */; + activeSDKPreference = iphoneos2.2.1; + activeTarget = 1D6058900D05DD3D006BFB54 /* Doom */; + addToTargets = ( + 1D6058900D05DD3D006BFB54 /* Doom */, + ); + breakpoints = ( + 72BD33100FB486E0002E4055 /* opengl_error_break */, + 724C56670FBE6194000E4348 /* BackgroundMusic.cpp:503 */, + 724C567A0FBE6314000E4348 /* g_game.c:632 */, + 724C56B30FBE6AE0000E4348 /* BackgroundMusic.cpp:285 */, + 724C56C00FBE6B54000E4348 /* BackgroundMusic.cpp:251 */, + 724C56D80FBE6C7D000E4348 /* BackgroundMusic.cpp:503 */, + 724C57210FC18C12000E4348 /* BackgroundMusic.cpp:344 */, + 724C57290FC18C90000E4348 /* BackgroundMusic.cpp:355 */, + 724C57390FC18DAC000E4348 /* BackgroundMusic.cpp:312 */, + 724C573B0FC18E01000E4348 /* BackgroundMusic.cpp:249 */, + 724C574A0FC18F72000E4348 /* BackgroundMusic.cpp:250 */, + 724C57520FC193AD000E4348 /* BackgroundMusic.cpp:376 */, + 724C57F60FC1B36B000E4348 /* iphone_main.c:237 */, + 724C58020FC1B3D6000E4348 /* iphone_loop.c:66 */, + 724C58110FC1B5B4000E4348 /* iphone_loop.c:66 */, + 724C58470FC1C649000E4348 /* iphone_loop.c:66 */, + 724C58710FC1CD56000E4348 /* r_things.c:260 */, + 724C587C0FC1CDC1000E4348 /* r_things.c:174 */, + 724C58AB0FC1D0E6000E4348 /* BackgroundMusic.cpp:252 */, + 724C58CB0FC1D2E1000E4348 /* BackgroundMusic.cpp:502 */, + 724C58D70FC1D555000E4348 /* iphone_loop.c:66 */, + 724C58D90FC1D563000E4348 /* iphone_loop.c:66 */, + 724C58F10FC1D925000E4348 /* EAGLView.m:212 */, + 724C59250FC1E488000E4348 /* BackgroundMusic.cpp:487 */, + 724C59330FC1E4DF000E4348 /* BackgroundMusic.cpp:496 */, + 724C59350FC1E4E1000E4348 /* BackgroundMusic.cpp:497 */, + 724C595E0FC20D2A000E4348 /* BackgroundMusic.cpp:483 */, + 724C59710FC20DC9000E4348 /* EAGLView.m:206 */, + 724C59730FC20DD2000E4348 /* EAGLView.m:204 */, + 724C59820FC20EA4000E4348 /* EAGLView.m:149 */, + 724C59870FC20F72000E4348 /* iphone_loop.c:66 */, + 724C59A40FC211A2000E4348 /* EAGLView.m:128 */, + 724C59BD0FC2132D000E4348 /* EAGLView.m:127 */, + 724C59F60FC2145D000E4348 /* EAGLView.m:171 */, + 724C59F90FC214B5000E4348 /* EAGLView.m:169 */, + 724C5A0B0FC2169B000E4348 /* EAGLView.m:175 */, + 724C5A1D0FC21A02000E4348 /* EAGLView.m:122 */, + 724C5A340FC21A79000E4348 /* iphone_loop.c:66 */, + 724C5A9B0FC21CFA000E4348 /* iphone_loop.c:66 */, + 724C5A9F0FC21D09000E4348 /* iphone_loop.c:66 */, + 724C5AE30FC229F4000E4348 /* iphone_render.c:350 */, + 724C5AFC0FC2536D000E4348 /* iphone_render.c:1466 */, + 724C5B100FC2548C000E4348 /* iphone_render.c:1466 */, + 724C5B1D0FC254C9000E4348 /* iphone_render.c:216 */, + 724C5B200FC254E2000E4348 /* iphone_render.c:216 */, + 724C5B220FC255B5000E4348 /* iphone_render.c:216 */, + 724C5B280FC25893000E4348 /* iphone_render.c:1447 */, + 724C5B2D0FC259C3000E4348 /* iphone_render.c:216 */, + 724C5B6C0FC2D000000E4348 /* iphone_render.c:886 */, + 724C5B750FC2D12F000E4348 /* iphone_render.c:1733 */, + 724C5B770FC2D141000E4348 /* iphone_render.c:1729 */, + 724C5B7C0FC2D161000E4348 /* iphone_render.c:1735 */, + 724C5B890FC2D261000E4348 /* iphone_render.c:1451 */, + 724C5B990FC2D7DF000E4348 /* iphone_loop.c:1641 */, + 724C5B9E0FC2D818000E4348 /* iphone_loop.c:1559 */, + 724C5BEF0FC47F0E000E4348 /* g_game.c:850 */, + 724C5C4B0FC48C2D000E4348 /* st_stuff.c:857 */, + 724C5C8F0FC48DE7000E4348 /* p_user.c:300 */, + 724C5C9E0FC48E9D000E4348 /* p_mobj.c:1059 */, + 724C5CA00FC48EB7000E4348 /* g_game.c:773 */, + 724C5CC80FC4909E000E4348 /* p_spec.c:2328 */, + 724C5D960FC7AB77000E4348 /* iphone_main.c:237 */, + 724C5E150FC7B910000E4348 /* iphone_loop.c:66 */, + 724C5E170FC7B91B000E4348 /* iphone_loop.c:66 */, + 724C5E210FC7B9D6000E4348 /* iphone_loop.c:66 */, + 724C5E2C0FC7BA6F000E4348 /* iphone_loop.c:66 */, + 724C5E2E0FC7BA76000E4348 /* iphone_loop.c:66 */, + 724C5E340FC7BE09000E4348 /* iphone_loop.c:66 */, + 724C5E670FC7C28C000E4348 /* iphone_loop.c:1509 */, + 724C5E8B0FC9A14A000E4348 /* iphone_loop.c:66 */, + 724C5E9F0FC9A2BB000E4348 /* gl_texture.c:1010 */, + 724C5EAE0FC9A3A8000E4348 /* gl_texture.c:1061 */, + 724C5ED70FC9A4A5000E4348 /* gl_texture.c:183 */, + 724C5F040FC9BE0E000E4348 /* iphone_loop.c:66 */, + 724C5F150FC9BEE1000E4348 /* iphone_loop.c:66 */, + 724C5F1A0FC9BEF7000E4348 /* iphone_loop.c:66 */, + 724C5F2B0FC9BFD7000E4348 /* iphone_loop.c:66 */, + 724C5F560FC9C9B4000E4348 /* iphone_menus.c:27 */, + 724C5F580FC9C9C6000E4348 /* iphone_menus.c:27 */, + 724C5F910FC9E520000E4348 /* iphone_loop.c:66 */, + 724C5FD70FC9E846000E4348 /* iphone_loop.c:1673 */, + 724C5FE00FC9E96A000E4348 /* g_game.c:1172 */, + 724C5FE60FC9EB5B000E4348 /* m_random.c:143 */, + 724C600E0FC9EC9B000E4348 /* m_random.c:130 */, + 724C60540FCA1E3B000E4348 /* iphone_mapSelect.c:421 */, + 724C60860FCA1F05000E4348 /* iphone_mapSelect.c:421 */, + 724C60890FCA1F07000E4348 /* iphone_mapSelect.c:421 */, + 724C608B0FCA1F24000E4348 /* iphone_mapSelect.c:361 */, + 724C608D0FCA1FA8000E4348 /* iphone_loop.c:66 */, + 724C60A10FCA20D0000E4348 /* iphone_loop.c:1508 */, + 724C60CC0FCB061C000E4348 /* iphone_menus.c:27 */, + 724C60CF0FCB062D000E4348 /* iphone_menus.c:27 */, + 724C61200FCB0CFC000E4348 /* iphone_menus.c:27 */, + 724C61370FCB0E32000E4348 /* iphone_menus.c:27 */, + 724C61390FCB0E3E000E4348 /* iphone_menus.c:27 */, + 724C61690FCB1395000E4348 /* iphone_menus.c:27 */, + 724C61A60FCB17CD000E4348 /* iphone_menus.c:27 */, + 724C61A80FCB17DE000E4348 /* iphone_menus.c:27 */, + 724C61BF0FCB1A6D000E4348 /* iphone_menus.c:27 */, + 724C61EC0FCB1FB2000E4348 /* iphone_menus.c:27 */, + 724C62170FCB25F5000E4348 /* iphone_menus.c:27 */, + 724C621D0FCB26F3000E4348 /* iphone_menus.c:27 */, + 724C625A0FCB3C8D000E4348 /* asm iphoneFrame 0x00007c98:64 */, + 724C625D0FCB3C8E000E4348 /* asm iphoneFrame 0x00007c98:64 */, + 724C62800FCB3EBF000E4348 /* iphone_loop.c:1439 */, + 724C62A90FCB41BE000E4348 /* iphone_loop.c:1475 */, + 724C62D50FCB654C000E4348 /* iphone_menus.c:27 */, + 724C62F50FCB6C65000E4348 /* iphone_main.c:237 */, + 724C63380FCB6D31000E4348 /* iphone_main.c:237 */, + 724C633A0FCB6D36000E4348 /* iphone_main.c:237 */, + 724C63A20FCC3A8B000E4348 /* iphone_main.c:237 */, + 724C63A50FCC3A91000E4348 /* iphone_main.c:237 */, + 724C63AF0FCC3CE2000E4348 /* iphone_main.c:237 */, + 724C63C50FCC3ED5000E4348 /* iphone_main.c:237 */, + 724C63E70FCC4104000E4348 /* iphone_menus.c:27 */, + 724C63F20FCC414A000E4348 /* iphone_menus.c:27 */, + 724C64060FCC4257000E4348 /* iphone_menus.c:27 */, + 724C64790FCD7A1F000E4348 /* iphone_render.c:1425 */, + 724C64D50FCD7D98000E4348 /* gl_main.c:1306 */, + 724C64E00FCD7E61000E4348 /* gl_main.c:1336 */, + 724C64E20FCD7E63000E4348 /* gl_main.c:1342 */, + 724C64EB0FCD7FCB000E4348 /* gl_main.c:1411 */, + 724C64ED0FCD8008000E4348 /* gl_main.c:1494 */, + 724C64F20FCD8180000E4348 /* gl_main.c:1856 */, + 724C652B0FCD8702000E4348 /* iphone_render.c:1047 */, + 724C658C0FCD9455000E4348 /* iphone_render.c:124 */, + 724C65930FCD9482000E4348 /* gl_main.c:1863 */, + 724C65D60FCD9922000E4348 /* iphone_render.c:142 */, + 724C65FE0FCD9BB0000E4348 /* iphone_loop.c:1439 */, + 724C66240FCDA0BE000E4348 /* iphone_sound.c:221 */, + 724C662B0FCDA169000E4348 /* p_mobj.c:1518 */, + 724C664F0FCDA2B3000E4348 /* iphone_sound.c:226 */, + 724C66520FCDA2C3000E4348 /* s_sound.c:295 */, + 724C66560FCDA3DA000E4348 /* s_sound.c:627 */, + 724C66710FCDAB26000E4348 /* iphone_render.c:1281 */, + 724C66980FCDB407000E4348 /* iphone_menus.c:27 */, + 724C669A0FCDB413000E4348 /* iphone_loop.c:346 */, + 724C66D20FCDB610000E4348 /* doomAppDelegate.m:184 */, + 724C66D40FCDB612000E4348 /* doomAppDelegate.m:191 */, + 724C66D80FCDB702000E4348 /* iphone_main.c:237 */, + 724C66DB0FCDB77F000E4348 /* doomAppDelegate.m:195 */, + 724C678D0FCDC379000E4348 /* ipak.c:76 */, + 724C678F0FCDC37A000E4348 /* ipak.c:78 */, + 724C67910FCDC37C000E4348 /* ipak.c:82 */, + 724C67930FCDC37F000E4348 /* ipak.c:84 */, + 724C679C0FCDCAE4000E4348 /* opengl_error_break */, + 724C67C00FCDD6EF000E4348 /* iphone_render.c:220 */, + 724C68030FCDE782000E4348 /* iphone_menus.c:27 */, + 72B9E7730FCDFB4F00939821 /* iphone_loop.c:1125 */, + 72B9E79F0FCDFCC500939821 /* iphone_loop.c:673 */, + 72B9E7C60FCDFEB700939821 /* iphone_loop.c:1285 */, + 72B9E7C80FCDFEC600939821 /* p_pspr.c:651 */, + 72B9E7EC0FCE14B600939821 /* p_pspr.c:628 */, + 72B9E7F10FCE18E500939821 /* p_pspr.c:617 */, + 72B9E8170FCE1D5000939821 /* iphone_loop.c:1571 */, + 7285881F0FE3E44C007D4FCD /* iphone_mapSelect.c:361 */, + 728588440FE53F70007D4FCD /* iphone_mapSelect.c:361 */, + 7285886D0FE7BF39007D4FCD /* iphone_loop.c:1285 */, + 728588970FEFE103007D4FCD /* iphone_loop.c:1286 */, + 72973A2E0FF1784300F813E6 /* iphone_loop.c:1401 */, + 72973A560FF2AF0C00F813E6 /* iphone_loop.c:1443 */, + 72973ACF0FF51FC300F813E6 /* iphone_loop.c:1125 */, + 72973ADA0FF51FD700F813E6 /* iphone_loop.c:1286 */, + 72973B410FF52D1A00F813E6 /* iphone_menus.c:27 */, + 72973B730FF52F2500F813E6 /* iphone_main.c:237 */, + 72973BC00FF5471D00F813E6 /* iphone_main.c:237 */, + 72973C0E0FF54A9700F813E6 /* iphone_sound.c:27 */, + 721D073B0FF55DF0008465F7 /* iphone_loop.c:1286 */, + 721D07460FF560EC008465F7 /* iphone_loop.c:1286 */, + 721D07C90FF56BB7008465F7 /* iphone_loop.c:1286 */, + 721D07D30FF56BFC008465F7 /* iphone_main.c:237 */, + 721D07D50FF56C00008465F7 /* iphone_main.c:237 */, + 72151FA50FF57354001CDDB7 /* iphone_loop.c:1286 */, + 72151FA70FF57356001CDDB7 /* iphone_loop.c:1286 */, + 72151FA90FF5735A001CDDB7 /* iphone_loop.c:1286 */, + 72151FD50FF57D22001CDDB7 /* iphone_menus.c:27 */, + 721520130FF588E9001CDDB7 /* iphone_menus.c:27 */, + 721520370FF5895A001CDDB7 /* g_game.c:1248 */, + 721520390FF5895D001CDDB7 /* g_game.c:1260 */, + 7215204D0FF58C16001CDDB7 /* iphone_loop.c:1286 */, + 721520810FF58D43001CDDB7 /* iphone_loop.c:1285 */, + 721520BC0FF5936A001CDDB7 /* iphone_loop.c:1464 */, + 721520BE0FF59476001CDDB7 /* iphone_loop.c:1286 */, + 721521040FF5992A001CDDB7 /* iphone_menus.c:27 */, + 721521120FF59AA5001CDDB7 /* iphone_loop.c:1286 */, + 72C6EB1E0FFBD0920085A32E /* iphone_loop.c:1286 */, + 72C6A5F30FFBFCF20005E863 /* iphone_menus.c:181 */, + 72C6A6000FFBFDC70005E863 /* iphone_menus.c:181 */, + 72C6A6020FFBFDFB0005E863 /* iphone_menus.c:181 */, + 72C6A6110FFC001E0005E863 /* iphone_menus.c:181 */, + 72C6A6130FFC00250005E863 /* iphone_menus.c:181 */, + 72C6A6180FFC00D70005E863 /* iphone_menus.c:181 */, + 72C6A61B0FFC038C0005E863 /* iphone_menus.c:181 */, + 72C6A63A0FFC0C930005E863 /* iphone_menus.c:181 */, + 72C6A64C0FFC0F0D0005E863 /* iphone_menus.c:181 */, + 72C6A64E0FFC0F120005E863 /* iphone_menus.c:181 */, + 72C6A65C0FFC16B20005E863 /* iphone_loop.c:1286 */, + 725EFEC20FFC197500A7D6A7 /* iphone_loop.c:1286 */, + 725EFEDA0FFC1FDA00A7D6A7 /* iphone_loop.c:1286 */, + 725EFF0F0FFC272B00A7D6A7 /* iphone_loop.c:1286 */, + 725EFF320FFC30C300A7D6A7 /* iphone_loop.c:1286 */, + 725EFF4C0FFC34AC00A7D6A7 /* iphone_loop.c:1125 */, + 725EFF4E0FFC34BB00A7D6A7 /* iphone_loop.c:1647 */, + 725EFF510FFC34C100A7D6A7 /* iphone_loop.c:1650 */, + 725EFF540FFC34ED00A7D6A7 /* iphone_loop.c:1125 */, + 725EFF6C0FFC3EDE00A7D6A7 /* iphone_loop.c:1716 */, + 725EFF790FFC3F8400A7D6A7 /* iphone_loop.c:1299 */, + 725EFFD40FFD0F6500A7D6A7 /* iphone_menus.c:425 */, + 725EFFF80FFD173300A7D6A7 /* iphone_menus.c:883 */, + 725E00150FFD261F00A7D6A7 /* iphone_loop.c:1557 */, + 725E00330FFD299400A7D6A7 /* iphone_menus.c:490 */, + 725E00350FFD29A400A7D6A7 /* iphone_menus.c:415 */, + 725E003A0FFD29C400A7D6A7 /* iphone_menus.c:449 */, + 725E00500FFD29DE00A7D6A7 /* iphone_menus.c:478 */, + 725E00520FFD29E700A7D6A7 /* iphone_menus.c:418 */, + 725E00850FFD2F3600A7D6A7 /* iphone_loop.c:1410 */, + 725E00A20FFD312B00A7D6A7 /* iphone_loop.c:1413 */, + 725E00C40FFD31D800A7D6A7 /* doomAppDelegate.m:133 */, + 725E00C90FFD335500A7D6A7 /* doomAppDelegate.m:134 */, + 725E01E90FFD522100A7D6A7 /* doomAppDelegate.m:145 */, + 725E02190FFD55DC00A7D6A7 /* doomAppDelegate.m:146 */, + 725E02890FFD66D100A7D6A7 /* iphone_menus.c:919 */, + 725E028E0FFD66EC00A7D6A7 /* iphone_menus.c:883 */, + 725E02900FFD672A00A7D6A7 /* iphone_menus.c:883 */, + 725E03601002577600A7D6A7 /* iphone_menus.c:883 */, + 725E03731002582400A7D6A7 /* iphone_menus.c:363 */, + 725E03781002586500A7D6A7 /* iphone_menus.c:883 */, + 725E03811002592E00A7D6A7 /* iphone_menus.c:363 */, + 725E041A10027B6500A7D6A7 /* gl_main.c:2910 */, + 725E042210027E9800A7D6A7 /* gl_main.c:1705 */, + 72A55D361002AC4A00F788A5 /* iphone_async.c:110 */, + 72A55DB81002B04600F788A5 /* iphone_menus.c:883 */, + 72A55DDC1002C17900F788A5 /* iphone_menus.c:883 */, + 72A55DDE1002C18000F788A5 /* iphone_menus.c:883 */, + 72A55E031002C44500F788A5 /* iphone_menus.c:363 */, + 72A55E1A1002C7C800F788A5 /* iphone_menus.c:363 */, + 72A55E2E1002C8BA00F788A5 /* iphone_menus.c:883 */, + 72A55E3E1002CFEC00F788A5 /* iphone_menus.c:883 */, + 72A55E4C1002D02A00F788A5 /* iphone_main.c:314 */, + 72A55E851003A05700F788A5 /* iphone_loop.c:1486 */, + 72A55EBB1003A31100F788A5 /* iphone_async.c:808 */, + 72A55ED41003A56700F788A5 /* iphone_main.c:468 */, + 72A55EF31003B06400F788A5 /* iphone_menus.c:726 */, + 72A55EF51003B07200F788A5 /* iphone_start.c:108 */, + 72A55F631003BAAA00F788A5 /* iphone_async.c:121 */, + 72A55F991003C0D400F788A5 /* iphone_start.c:208 */, + 72A55FA51003C16300F788A5 /* iphone_loop.c:1342 */, + 72A55FB21003C3C100F788A5 /* iphone_start.c:195 */, + 72A560BC1004031F00F788A5 /* iphone_async.c:116 */, + 72A560C5100403E900F788A5 /* iphone_async.c:715 */, + 72A560ED1005212200F788A5 /* iphone_net.c:38 */, + 72A56111100521C700F788A5 /* iphone_net.c:365 */, + 72A5613810052AD900F788A5 /* iphone_main.c:314 */, + 7280FC2110052E3A000F05FD /* iphone_net.c:38 */, + 7280FC2310052E8C000F05FD /* iphone_menus.c:247 */, + 7280FC5210052F94000F05FD /* iphone_net.c:363 */, + 7280FC5B10053042000F05FD /* iphone_net.c:38 */, + 7280FC841005358B000F05FD /* iphone_net.c:38 */, + 7280FCCD10053D90000F05FD /* iphone_main.c:314 */, + 7280FD0E10053E70000F05FD /* iphone_menus.c:407 */, + 7280FD3010054021000F05FD /* iphone_menus.c:466 */, + 7280FD4B10054074000F05FD /* iphone_menus.c:243 */, + 7280FD661005414A000F05FD /* iphone_async.c:106 */, + 7280FD811005486D000F05FD /* iphone_main.c:299 */, + 7280FD9310054B9F000F05FD /* iphone_main.c:314 */, + 7280FDFD100560E2000F05FD /* iphone_async.c:810 */, + 7280FE00100560FE000F05FD /* iphone_menus.c:363 */, + 7280FE0210056104000F05FD /* iphone_menus.c:385 */, + 7280FE041005610F000F05FD /* iphone_async.c:850 */, + 7280FE0610056115000F05FD /* iphone_async.c:950 */, + 7280FEC110057E63000F05FD /* iphone_async.c:756 */, + 7280FF051005903F000F05FD /* iphone_async.c:96 */, + 7280FF13100591F0000F05FD /* iphone_async.c:91 */, + 7280FF1B1005924B000F05FD /* iphone_async.c:86 */, + 7280FF1F10059290000F05FD /* iphone_async.c:88 */, + 720CBDFF10065F6500801220 /* s_sound.c:290 */, + 720CBE21100661BC00801220 /* s_sound.c:732 */, + 720CBE95100680E500801220 /* iphone_loop.c:1363 */, + 72540ED61006849B00925CFB /* iphone_net.c:38 */, + 72540EE81006863400925CFB /* iphone_net.c:38 */, + 72540F2010068B4800925CFB /* iphone_net.c:38 */, + 72540F741006994500925CFB /* iphone_async.c:946 */, + 72540F8310069BEB00925CFB /* iphone_net.c:38 */, + 72540FA210069F2D00925CFB /* iphone_net.c:38 */, + 72541053100795CB00925CFB /* iphone_mapSelect.c:262 */, + 7254109D10079DDE00925CFB /* iphone_loop.c:614 */, + 725410AA10079E2E00925CFB /* iphone_loop.c:616 */, + 725410C11007AC0C00925CFB /* hud.c:194 */, + 725410EE1007AFE100925CFB /* iphone_loop.c:309 */, + 725410F81007AFF800925CFB /* iphone_loop.c:313 */, + 725411031007B02300925CFB /* iphone_sound.c:29 */, + 7254113F1007B14E00925CFB /* iphone_sound.c:43 */, + 725411431007B19000925CFB /* iphone_mapSelect.c:386 */, + 725411471007B1A200925CFB /* iphone_loop.c:128 */, + 725411491007B1A600925CFB /* iphone_mapSelect.c:388 */, + 725411881007B40200925CFB /* iphone_loop.c:254 */, + 7254118A1007B40900925CFB /* iphone_loop.c:252 */, + 725411AD1007B8F300925CFB /* iphone_loop.c:1079 */, + 725411BE1007B93800925CFB /* iphone_loop.c:1050 */, + 725412071007C19A00925CFB /* iphone_loop.c:1056 */, + 725412181007C3EC00925CFB /* s_sound.c:730 */, + 725412251007C6F100925CFB /* s_sound.c:303 */, + 725413041007DC0B00925CFB /* iphone_async.c:206 */, + 725413061007DC0D00925CFB /* iphone_async.c:244 */, + 7240B2B61017AB7A00522838 /* iphone_net.c:431 */, + 7240B2EC1017B17200522838 /* iphone_net.c:410 */, + 7240B2EE1017B17400522838 /* iphone_net.c:406 */, + 7240B30C1017B30000522838 /* iphone_net.c:403 */, + 7240B39A1017C84300522838 /* iphone_net.c:582 */, + 7240B3AB1017C8D500522838 /* iphone_async.c:815 */, + 7240B3AD1017C8EA00522838 /* iphone_async.c:807 */, + 7240B3F91017DF4300522838 /* iphone_async.c:945 */, + 7240B4351017F48400522838 /* iphone_net.c:570 */, + 7240B49610180AAA00522838 /* iphone_net.c:38 */, + 7288D1111018CBE900678FAC /* iphone_async.c:615 */, + 7288D11F1018F64000678FAC /* iphone_loop.c:1657 */, + 7288D1901019115700678FAC /* iphone_async.c:435 */, + 7288D1951019131400678FAC /* iphone_async.c:388 */, + 7288D1A61019133200678FAC /* iphone_loop.c:157 */, + 7288D1EA101A165800678FAC /* s_sound.c:335 */, + 7288D1EF101A16CD00678FAC /* s_sound.c:426 */, + 7288D22B101A16FD00678FAC /* iphone_loop.c:1471 */, + 7288D22E101A172100678FAC /* iphone_loop.c:1473 */, + 72DB56C1101A53BB00A58CED /* s_sound.c:330 */, + 72DB56C3101A53BD00A58CED /* s_sound.c:334 */, + 72DB56D1101A56B200A58CED /* s_sound.c:225 */, + 72DB56D3101A56B500A58CED /* s_sound.c:244 */, + 72DB56D5101A56BF00A58CED /* s_sound.c:264 */, + 72DB56D9101A56DD00A58CED /* s_sound.c:262 */, + 72DB56DC101A571A00A58CED /* s_sound.c:264 */, + 72DB56EF101A57E700A58CED /* s_sound.c:264 */, + 72DB56F1101A57E900A58CED /* s_sound.c:264 */, + 72DB5743101A6A4500A58CED /* iphone_async.c:653 */, + 72DB579B101A78EF00A58CED /* iphone_loop.c:894 */, + 72DB57CE101A80BB00A58CED /* iphone_mapSelect.c:342 */, + 72DB57D0101A80E200A58CED /* iphone_mapSelect.c:341 */, + 72679959101E92F600CEA3A2 /* iphone_async.c:136 */, + 7267998F101E9AFD00CEA3A2 /* iphone_async.c:112 */, + 72BA12571028B0D100DDB148 /* iphone_render.c:1247 */, + 72BA125A1028B0E100DDB148 /* iphone_render.c:912 */, + 72BA125C1028B0E300DDB148 /* iphone_render.c:927 */, + 72BA126E1028BE8800DDB148 /* iphone_async.c:554 */, + 72BA127E1028BF8A00DDB148 /* iphone_async.c:561 */, + 72BA128E1028C19F00DDB148 /* iphone_async.c:561 */, + 72BA129B1028C25200DDB148 /* EAGLView.m:194 */, + 72BA12A61028C2C400DDB148 /* EAGLView.m:100 */, + 72BA13141028C88A00DDB148 /* iphone_loop.c:248 */, + 72BA13341028CA0100DDB148 /* iphone_sound.c:168 */, + 72BA135A1028D36000DDB148 /* iphone_loop.c:301 */, + 72BA13661028D38200DDB148 /* iphone_loop.c:1667 */, + 72BA139D1028D4E900DDB148 /* iphone_loop.c:1664 */, + 72BA13A51028D52000DDB148 /* iphone_loop.c:270 */, + 72AC934C107E927700D77CA8 /* iphone_loop.c:1668 */, + 72AC9350107E92FC00D77CA8 /* iphone_loop.c:357 */, + 72AC9353107E934200D77CA8 /* iphone_loop.c:270 */, + 72AC9368107E967100D77CA8 /* iphone_loop.c:284 */, + 72AC937B107E985A00D77CA8 /* iphone_loop.c:288 */, + 72AC937D107E986100D77CA8 /* iphone_loop.c:281 */, + 72AC937F107E986900D77CA8 /* iphone_loop.c:317 */, + 72AC9385107E997800D77CA8 /* iphone_loop.c:299 */, + 72AC938B107E99E300D77CA8 /* iphone_loop.c:318 */, + 725D1D31107EB60E00B86564 /* iphone_sound.c:229 */, + 725D1D33107EB61800B86564 /* iphone_sound.c:46 */, + 725D1D48107EBA1600B86564 /* iphone_net.c:455 */, + 72F222F7107F968D000F9D8D /* iphone_async.c:801 */, + 72F22330107F9ACD000F9D8D /* iphone_net.c:545 */, + 72F2238E107FBD27000F9D8D /* hud.c:73 */, + 72F22391107FBD4A000F9D8D /* iphone_loop.c:311 */, + 728818E3108576640049CC03 /* BackgroundMusic.cpp:493 */, + 728818E5108576800049CC03 /* BackgroundMusic.cpp:515 */, + 728818E7108576840049CC03 /* BackgroundMusic.cpp:509 */, + 728818EB108577430049CC03 /* s_sound.c:528 */, + 728818F6108577980049CC03 /* BackgroundMusic.cpp:482 */, + 72881909108578560049CC03 /* BackgroundMusic.cpp:500 */, + ); + codeSenseManager = 72AD09B00FA224DC000999A0 /* Code sense */; + executables = ( + 72AD09A80FA224D0000999A0 /* Doom */, + ); + expressions = ( + "*(memblock_t *)0x82ca00", + ); + perUserDictionary = { + "PBXConfiguration.PBXBreakpointsDataSource.v1:1CA23EDF0692099D00951B8B" = { + PBXFileTableDataSourceColumnSortingDirectionKey = "-1"; + PBXFileTableDataSourceColumnSortingKey = PBXBreakpointsDataSource_BreakpointID; + PBXFileTableDataSourceColumnWidthsKey = ( + 20, + 20, + 297, + 20, + 197, + 197, + 126, + 20, + ); + PBXFileTableDataSourceColumnsKey = ( + PBXBreakpointsDataSource_ActionID, + PBXBreakpointsDataSource_TypeID, + PBXBreakpointsDataSource_BreakpointID, + PBXBreakpointsDataSource_UseID, + PBXBreakpointsDataSource_LocationID, + PBXBreakpointsDataSource_ConditionID, + PBXBreakpointsDataSource_IgnoreCountID, + PBXBreakpointsDataSource_ContinueID, + ); + }; + PBXConfiguration.PBXFileTableDataSource3.PBXExecutablesDataSource = { + PBXFileTableDataSourceColumnSortingDirectionKey = "-1"; + PBXFileTableDataSourceColumnSortingKey = PBXExecutablesDataSource_NameID; + PBXFileTableDataSourceColumnWidthsKey = ( + 22, + 300, + 594.58349609375, + ); + PBXFileTableDataSourceColumnsKey = ( + PBXExecutablesDataSource_ActiveFlagID, + PBXExecutablesDataSource_NameID, + PBXExecutablesDataSource_CommentsID, + ); + }; + PBXConfiguration.PBXFileTableDataSource3.PBXFileTableDataSource = { + PBXFileTableDataSourceColumnSortingDirectionKey = "-1"; + PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID; + PBXFileTableDataSourceColumnWidthsKey = ( + 20, + 131, + 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, + 667, + 60, + 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 = 277181662; + PBXWorkspaceStateSaveDate = 277181662; + }; + perUserProjectItems = { + 7201D45F0FA6828B00D81683 = 7201D45F0FA6828B00D81683 /* PBXTextBookmark */; + 7201D4600FA6828B00D81683 = 7201D4600FA6828B00D81683 /* PBXTextBookmark */; + 7201D4610FA6828B00D81683 = 7201D4610FA6828B00D81683 /* PBXTextBookmark */; + 7201D4640FA6828B00D81683 = 7201D4640FA6828B00D81683 /* PBXTextBookmark */; + 7201D47A0FA684B400D81683 = 7201D47A0FA684B400D81683 /* PBXTextBookmark */; + 7201D47C0FA684B400D81683 = 7201D47C0FA684B400D81683 /* PBXTextBookmark */; + 7201D47E0FA684B400D81683 = 7201D47E0FA684B400D81683 /* PBXTextBookmark */; + 7201D4900FA685CB00D81683 = 7201D4900FA685CB00D81683 /* PBXTextBookmark */; + 7201D4980FA6862500D81683 = 7201D4980FA6862500D81683 /* PBXTextBookmark */; + 7201D49D0FA6862500D81683 = 7201D49D0FA6862500D81683 /* PBXTextBookmark */; + 7201D4D00FA694B500D81683 = 7201D4D00FA694B500D81683 /* PBXTextBookmark */; + 7201D5B00FA79C1800D81683 = 7201D5B00FA79C1800D81683 /* PBXTextBookmark */; + 7201D73B0FA7FD3300D81683 = 7201D73B0FA7FD3300D81683 /* PBXTextBookmark */; + 7201D7620FA7FED300D81683 = 7201D7620FA7FED300D81683 /* PBXTextBookmark */; + 7201D7650FA7FED300D81683 = 7201D7650FA7FED300D81683 /* PBXTextBookmark */; + 7201D7660FA7FED300D81683 = 7201D7660FA7FED300D81683 /* PBXTextBookmark */; + 7201D76D0FA7FED300D81683 = 7201D76D0FA7FED300D81683 /* PBXTextBookmark */; + 7201D7B70FA8B04600D81683 = 7201D7B70FA8B04600D81683 /* PBXTextBookmark */; + 7201D7BE0FA8B04600D81683 = 7201D7BE0FA8B04600D81683 /* PBXTextBookmark */; + 7201D7BF0FA8B04600D81683 = 7201D7BF0FA8B04600D81683 /* PBXTextBookmark */; + 7201D7C10FA8B04600D81683 = 7201D7C10FA8B04600D81683 /* PBXTextBookmark */; + 7201D8040FA8C52200D81683 = 7201D8040FA8C52200D81683 /* PBXTextBookmark */; + 7201D8270FA8CBFA00D81683 = 7201D8270FA8CBFA00D81683 /* PBXTextBookmark */; + 7201D8950FA8E2AD00D81683 = 7201D8950FA8E2AD00D81683 /* PBXTextBookmark */; + 7201D8DB0FA8ED7D00D81683 = 7201D8DB0FA8ED7D00D81683 /* PBXTextBookmark */; + 7201D9CC0FA91DCE00D81683 = 7201D9CC0FA91DCE00D81683 /* PBXTextBookmark */; + 7201D9CD0FA91DCE00D81683 = 7201D9CD0FA91DCE00D81683 /* PBXTextBookmark */; + 7201D9CF0FA91DCE00D81683 = 7201D9CF0FA91DCE00D81683 /* PBXTextBookmark */; + 7201DA4F0FA929DB00D81683 = 7201DA4F0FA929DB00D81683 /* PBXTextBookmark */; + 7201DA500FA929DB00D81683 = 7201DA500FA929DB00D81683 /* PBXTextBookmark */; + 720CBE281006623E00801220 = 720CBE281006623E00801220 /* PBXTextBookmark */; + 720CBE371006623E00801220 = 720CBE371006623E00801220 /* PBXTextBookmark */; + 721520CC0FF59671001CDDB7 = 721520CC0FF59671001CDDB7 /* PBXTextBookmark */; + 721520F70FF597C4001CDDB7 = 721520F70FF597C4001CDDB7 /* PBXTextBookmark */; + 722DFAE80FB8A419002A6405 = 722DFAE80FB8A419002A6405 /* PBXTextBookmark */; + 7240B2831017A35C00522838 = 7240B2831017A35C00522838 /* PBXTextBookmark */; + 7240B28A1017A35C00522838 = 7240B28A1017A35C00522838 /* PBXTextBookmark */; + 7240B29E1017A9B600522838 = 7240B29E1017A9B600522838 /* PBXTextBookmark */; + 7240B2EF1017B18E00522838 = 7240B2EF1017B18E00522838 /* PBXTextBookmark */; + 7240B2F61017B18E00522838 = 7240B2F61017B18E00522838 /* PBXTextBookmark */; + 7240B32A1017B71400522838 = 7240B32A1017B71400522838 /* PBXTextBookmark */; + 7240B3381017B71400522838 = 7240B3381017B71400522838 /* PBXTextBookmark */; + 7240B3571017BD1B00522838 = 7240B3571017BD1B00522838 /* PBXTextBookmark */; + 7240B36A1017BF1800522838 = 7240B36A1017BF1800522838 /* PBXTextBookmark */; + 7240B36E1017BF1800522838 = 7240B36E1017BF1800522838 /* PBXTextBookmark */; + 7240B4121017F25A00522838 = 7240B4121017F25A00522838 /* PBXTextBookmark */; + 7240B4141017F25A00522838 = 7240B4141017F25A00522838 /* PBXTextBookmark */; + 7240B4161017F25A00522838 = 7240B4161017F25A00522838 /* PBXTextBookmark */; + 7240B4181017F25A00522838 = 7240B4181017F25A00522838 /* PBXTextBookmark */; + 7240B41A1017F25A00522838 = 7240B41A1017F25A00522838 /* PBXTextBookmark */; + 7240B41C1017F25A00522838 = 7240B41C1017F25A00522838 /* PBXTextBookmark */; + 7240B4201017F25A00522838 = 7240B4201017F25A00522838 /* PBXTextBookmark */; + 7240B4221017F25A00522838 = 7240B4221017F25A00522838 /* PBXTextBookmark */; + 7240B4241017F25A00522838 = 7240B4241017F25A00522838 /* PBXTextBookmark */; + 7240B4261017F25A00522838 = 7240B4261017F25A00522838 /* PBXTextBookmark */; + 7240B4281017F25A00522838 = 7240B4281017F25A00522838 /* PBXTextBookmark */; + 7240B42A1017F25A00522838 = 7240B42A1017F25A00522838 /* PBXTextBookmark */; + 7240B4371017F49300522838 = 7240B4371017F49300522838 /* PBXTextBookmark */; + 72484DB00FB0E95C00124E1C = 72484DB00FB0E95C00124E1C /* PBXTextBookmark */; + 72484DB70FB0E95C00124E1C = 72484DB70FB0E95C00124E1C /* PBXTextBookmark */; + 72484DB90FB0E95C00124E1C = 72484DB90FB0E95C00124E1C /* PBXTextBookmark */; + 72484DBB0FB0E95C00124E1C = 72484DBB0FB0E95C00124E1C /* PBXTextBookmark */; + 72484DBC0FB0E95C00124E1C = 72484DBC0FB0E95C00124E1C /* PBXTextBookmark */; + 72484DBD0FB0E95C00124E1C = 72484DBD0FB0E95C00124E1C /* PBXTextBookmark */; + 72484DC20FB0E95C00124E1C = 72484DC20FB0E95C00124E1C /* PBXTextBookmark */; + 72484DC30FB0E95C00124E1C = 72484DC30FB0E95C00124E1C /* PBXTextBookmark */; + 72484DC60FB0E95C00124E1C = 72484DC60FB0E95C00124E1C /* PBXTextBookmark */; + 72484DC70FB0E95C00124E1C = 72484DC70FB0E95C00124E1C /* PBXTextBookmark */; + 72484DC80FB0E95C00124E1C = 72484DC80FB0E95C00124E1C /* PBXTextBookmark */; + 72484DCB0FB0E95C00124E1C = 72484DCB0FB0E95C00124E1C /* PBXTextBookmark */; + 72484DCC0FB0E95C00124E1C = 72484DCC0FB0E95C00124E1C /* PBXTextBookmark */; + 72484DCD0FB0E95C00124E1C = 72484DCD0FB0E95C00124E1C /* PBXTextBookmark */; + 72484DCF0FB0E95C00124E1C = 72484DCF0FB0E95C00124E1C /* PBXTextBookmark */; + 72484DD10FB0E95C00124E1C = 72484DD10FB0E95C00124E1C /* PBXTextBookmark */; + 72484DD20FB0E95C00124E1C = 72484DD20FB0E95C00124E1C /* PBXTextBookmark */; + 72484DD40FB0E95C00124E1C = 72484DD40FB0E95C00124E1C /* PBXTextBookmark */; + 72484DD50FB0E95C00124E1C = 72484DD50FB0E95C00124E1C /* PBXTextBookmark */; + 72484DDA0FB0E95C00124E1C = 72484DDA0FB0E95C00124E1C /* PBXTextBookmark */; + 72484DDB0FB0E95C00124E1C = 72484DDB0FB0E95C00124E1C /* PBXTextBookmark */; + 72484DDC0FB0E95C00124E1C = 72484DDC0FB0E95C00124E1C /* PBXTextBookmark */; + 72484DDD0FB0E95C00124E1C = 72484DDD0FB0E95C00124E1C /* PBXTextBookmark */; + 72484DDE0FB0E95C00124E1C = 72484DDE0FB0E95C00124E1C /* PBXTextBookmark */; + 72484DDF0FB0E95C00124E1C = 72484DDF0FB0E95C00124E1C /* PBXTextBookmark */; + 72484DE20FB0E95C00124E1C = 72484DE20FB0E95C00124E1C /* PBXTextBookmark */; + 72484DE30FB0E95C00124E1C = 72484DE30FB0E95C00124E1C /* PBXTextBookmark */; + 72484DE40FB0E95C00124E1C = 72484DE40FB0E95C00124E1C /* PBXTextBookmark */; + 72484DE50FB0E95C00124E1C = 72484DE50FB0E95C00124E1C /* PBXTextBookmark */; + 72484DE60FB0E95C00124E1C = 72484DE60FB0E95C00124E1C /* PBXTextBookmark */; + 72484DEB0FB0E95C00124E1C = 72484DEB0FB0E95C00124E1C /* PBXTextBookmark */; + 72484DED0FB0E95C00124E1C = 72484DED0FB0E95C00124E1C /* PBXTextBookmark */; + 72484DEE0FB0E95C00124E1C = 72484DEE0FB0E95C00124E1C /* PBXTextBookmark */; + 72484DEF0FB0E95C00124E1C = 72484DEF0FB0E95C00124E1C /* PBXTextBookmark */; + 72484DF00FB0E95C00124E1C = 72484DF00FB0E95C00124E1C /* PBXTextBookmark */; + 72484DF20FB0E95C00124E1C = 72484DF20FB0E95C00124E1C /* PBXTextBookmark */; + 72484DF30FB0E95C00124E1C = 72484DF30FB0E95C00124E1C /* PBXTextBookmark */; + 72484E080FB0E95C00124E1C = 72484E080FB0E95C00124E1C /* PBXTextBookmark */; + 72484E0C0FB0E95C00124E1C = 72484E0C0FB0E95C00124E1C /* PBXTextBookmark */; + 72484E0D0FB0E95C00124E1C = 72484E0D0FB0E95C00124E1C /* PBXTextBookmark */; + 72484E0E0FB0E95C00124E1C = 72484E0E0FB0E95C00124E1C /* PBXTextBookmark */; + 72484E0F0FB0E95C00124E1C = 72484E0F0FB0E95C00124E1C /* PBXTextBookmark */; + 72484E100FB0E95C00124E1C = 72484E100FB0E95C00124E1C /* PBXTextBookmark */; + 72484E130FB0E95C00124E1C = 72484E130FB0E95C00124E1C /* PBXTextBookmark */; + 72484E140FB0E95C00124E1C = 72484E140FB0E95C00124E1C /* PBXTextBookmark */; + 72484E150FB0E95C00124E1C = 72484E150FB0E95C00124E1C /* PBXTextBookmark */; + 72484E160FB0E95C00124E1C = 72484E160FB0E95C00124E1C /* PBXTextBookmark */; + 72484E170FB0E95C00124E1C = 72484E170FB0E95C00124E1C /* PBXTextBookmark */; + 72484E180FB0E95C00124E1C = 72484E180FB0E95C00124E1C /* PBXTextBookmark */; + 72484E190FB0E95C00124E1C = 72484E190FB0E95C00124E1C /* PBXTextBookmark */; + 72484E1C0FB0E95C00124E1C = 72484E1C0FB0E95C00124E1C /* PBXTextBookmark */; + 72484E1D0FB0E95C00124E1C = 72484E1D0FB0E95C00124E1C /* PBXTextBookmark */; + 72484E210FB0E95C00124E1C = 72484E210FB0E95C00124E1C /* PBXTextBookmark */; + 72484E220FB0E95C00124E1C = 72484E220FB0E95C00124E1C /* PBXTextBookmark */; + 72484E230FB0E95C00124E1C = 72484E230FB0E95C00124E1C /* PBXTextBookmark */; + 72484E240FB0E95C00124E1C = 72484E240FB0E95C00124E1C /* PBXTextBookmark */; + 72484E250FB0E95C00124E1C = 72484E250FB0E95C00124E1C /* PBXTextBookmark */; + 72484E260FB0E95C00124E1C = 72484E260FB0E95C00124E1C /* PBXTextBookmark */; + 72484E270FB0E95C00124E1C = 72484E270FB0E95C00124E1C /* PBXTextBookmark */; + 72484E280FB0E95C00124E1C = 72484E280FB0E95C00124E1C /* PBXTextBookmark */; + 72484E2B0FB0E95C00124E1C = 72484E2B0FB0E95C00124E1C /* PBXTextBookmark */; + 72484E2C0FB0E95C00124E1C = 72484E2C0FB0E95C00124E1C /* PBXTextBookmark */; + 72484E2D0FB0E95C00124E1C = 72484E2D0FB0E95C00124E1C /* PBXTextBookmark */; + 72484E2F0FB0E95C00124E1C = 72484E2F0FB0E95C00124E1C /* PBXTextBookmark */; + 72484E300FB0E95C00124E1C = 72484E300FB0E95C00124E1C /* PBXTextBookmark */; + 72484E310FB0E95C00124E1C = 72484E310FB0E95C00124E1C /* PBXTextBookmark */; + 72484E330FB0E95C00124E1C = 72484E330FB0E95C00124E1C /* PBXTextBookmark */; + 72484E340FB0E95C00124E1C = 72484E340FB0E95C00124E1C /* PBXTextBookmark */; + 72484E350FB0E95C00124E1C = 72484E350FB0E95C00124E1C /* PBXTextBookmark */; + 72484E370FB0E95C00124E1C = 72484E370FB0E95C00124E1C /* PBXTextBookmark */; + 72484E390FB0E95C00124E1C = 72484E390FB0E95C00124E1C /* PBXTextBookmark */; + 72484E3B0FB0E95C00124E1C = 72484E3B0FB0E95C00124E1C /* PBXTextBookmark */; + 72484E3C0FB0E95C00124E1C = 72484E3C0FB0E95C00124E1C /* PBXTextBookmark */; + 72484E3D0FB0E95C00124E1C = 72484E3D0FB0E95C00124E1C /* PBXTextBookmark */; + 72484E3E0FB0E95C00124E1C = 72484E3E0FB0E95C00124E1C /* PBXTextBookmark */; + 72484E3F0FB0E95C00124E1C = 72484E3F0FB0E95C00124E1C /* PBXTextBookmark */; + 72484E400FB0E95C00124E1C = 72484E400FB0E95C00124E1C /* PBXTextBookmark */; + 72484E410FB0E95C00124E1C = 72484E410FB0E95C00124E1C /* PBXTextBookmark */; + 72484E420FB0E95C00124E1C = 72484E420FB0E95C00124E1C /* PBXTextBookmark */; + 72484E430FB0E95C00124E1C = 72484E430FB0E95C00124E1C /* PBXTextBookmark */; + 72484E440FB0E95C00124E1C = 72484E440FB0E95C00124E1C /* PBXTextBookmark */; + 72484E450FB0E95C00124E1C = 72484E450FB0E95C00124E1C /* PBXTextBookmark */; + 72484E8D0FB1F22E00124E1C = 72484E8D0FB1F22E00124E1C /* PBXTextBookmark */; + 72484E900FB1F22E00124E1C = 72484E900FB1F22E00124E1C /* PBXTextBookmark */; + 72484E940FB1F22E00124E1C = 72484E940FB1F22E00124E1C /* PBXTextBookmark */; + 72484E980FB1F22E00124E1C = 72484E980FB1F22E00124E1C /* PBXTextBookmark */; + 72484E990FB1F22E00124E1C = 72484E990FB1F22E00124E1C /* PBXTextBookmark */; + 72484EA60FB1F22E00124E1C = 72484EA60FB1F22E00124E1C /* PBXTextBookmark */; + 72484EAA0FB1F22E00124E1C = 72484EAA0FB1F22E00124E1C /* PBXTextBookmark */; + 72484F5D0FB1F8DA00124E1C = 72484F5D0FB1F8DA00124E1C /* PBXTextBookmark */; + 724C53220FBDBD31000E4348 = 724C53220FBDBD31000E4348 /* PBXTextBookmark */; + 724C532A0FBDBD31000E4348 = 724C532A0FBDBD31000E4348 /* PBXTextBookmark */; + 724C532F0FBDBD31000E4348 = 724C532F0FBDBD31000E4348 /* PBXTextBookmark */; + 724C536A0FBDC094000E4348 = 724C536A0FBDC094000E4348 /* PBXTextBookmark */; + 724C536C0FBDC094000E4348 = 724C536C0FBDC094000E4348 /* PBXTextBookmark */; + 724C53AB0FBDC6B6000E4348 = 724C53AB0FBDC6B6000E4348 /* PBXTextBookmark */; + 724C53AD0FBDC6B6000E4348 = 724C53AD0FBDC6B6000E4348 /* PBXTextBookmark */; + 724C53AF0FBDC6B6000E4348 = 724C53AF0FBDC6B6000E4348 /* PBXTextBookmark */; + 724C53B20FBDC6B6000E4348 = 724C53B20FBDC6B6000E4348 /* PBXTextBookmark */; + 724C53B40FBDC6B6000E4348 = 724C53B40FBDC6B6000E4348 /* PBXTextBookmark */; + 724C53CD0FBDC6B6000E4348 = 724C53CD0FBDC6B6000E4348 /* PBXTextBookmark */; + 724C53D20FBDC6B6000E4348 = 724C53D20FBDC6B6000E4348 /* PBXTextBookmark */; + 724C53E50FBDC6B6000E4348 = 724C53E50FBDC6B6000E4348 /* PBXTextBookmark */; + 724C53E70FBDC6B6000E4348 = 724C53E70FBDC6B6000E4348 /* PBXTextBookmark */; + 724C53EC0FBDC6B6000E4348 = 724C53EC0FBDC6B6000E4348 /* PBXTextBookmark */; + 724C54190FBDC908000E4348 = 724C54190FBDC908000E4348 /* PBXTextBookmark */; + 724C54B70FBDEB53000E4348 = 724C54B70FBDEB53000E4348 /* PBXTextBookmark */; + 724C55470FBDF916000E4348 = 724C55470FBDF916000E4348 /* PBXTextBookmark */; + 724C55FB0FBE0A75000E4348 = 724C55FB0FBE0A75000E4348 /* PBXTextBookmark */; + 724C565B0FBE1019000E4348 = 724C565B0FBE1019000E4348 /* PBXTextBookmark */; + 724C565E0FBE1019000E4348 = 724C565E0FBE1019000E4348 /* PBXTextBookmark */; + 724C576D0FC1B041000E4348 = 724C576D0FC1B041000E4348 /* PBXTextBookmark */; + 724C576F0FC1B041000E4348 = 724C576F0FC1B041000E4348 /* PBXTextBookmark */; + 724C58300FC1C408000E4348 = 724C58300FC1C408000E4348 /* PBXTextBookmark */; + 724C58B10FC1D13D000E4348 = 724C58B10FC1D13D000E4348 /* PBXTextBookmark */; + 724C5BE90FC47EFB000E4348 = 724C5BE90FC47EFB000E4348 /* PBXTextBookmark */; + 724C5BFE0FC48768000E4348 = 724C5BFE0FC48768000E4348 /* PBXTextBookmark */; + 724C5C030FC48768000E4348 = 724C5C030FC48768000E4348 /* PBXTextBookmark */; + 724C5C110FC48768000E4348 = 724C5C110FC48768000E4348 /* PBXTextBookmark */; + 724C5CA20FC48EBF000E4348 = 724C5CA20FC48EBF000E4348 /* PBXTextBookmark */; + 724C5CCE0FC490AE000E4348 = 724C5CCE0FC490AE000E4348 /* PBXTextBookmark */; + 724C5D240FC5D5AA000E4348 = 724C5D240FC5D5AA000E4348 /* PBXTextBookmark */; + 724C5D250FC5D5AA000E4348 = 724C5D250FC5D5AA000E4348 /* PBXTextBookmark */; + 724C5D260FC5D5AA000E4348 = 724C5D260FC5D5AA000E4348 /* PBXTextBookmark */; + 724C5D270FC5D5AA000E4348 = 724C5D270FC5D5AA000E4348 /* PBXTextBookmark */; + 724C5D380FC5D5AA000E4348 = 724C5D380FC5D5AA000E4348 /* PBXTextBookmark */; + 724C5D760FC7AAC4000E4348 = 724C5D760FC7AAC4000E4348 /* PBXTextBookmark */; + 724C5D870FC7AAC4000E4348 = 724C5D870FC7AAC4000E4348 /* PBXTextBookmark */; + 724C5DE80FC7B5AF000E4348 = 724C5DE80FC7B5AF000E4348 /* PBXTextBookmark */; + 724C5DEF0FC7B5AF000E4348 = 724C5DEF0FC7B5AF000E4348 /* PBXTextBookmark */; + 724C5DF40FC7B5AF000E4348 = 724C5DF40FC7B5AF000E4348 /* PBXTextBookmark */; + 724C5F060FC9BE48000E4348 = 724C5F060FC9BE48000E4348 /* PBXTextBookmark */; + 724C5F0A0FC9BE48000E4348 = 724C5F0A0FC9BE48000E4348 /* PBXTextBookmark */; + 724C5FE80FC9EBAE000E4348 = 724C5FE80FC9EBAE000E4348 /* PBXTextBookmark */; + 724C5FF10FC9EBAE000E4348 = 724C5FF10FC9EBAE000E4348 /* PBXTextBookmark */; + 724C600F0FC9ECA0000E4348 = 724C600F0FC9ECA0000E4348 /* PBXTextBookmark */; + 724C60140FC9ECA0000E4348 = 724C60140FC9ECA0000E4348 /* PBXTextBookmark */; + 724C604B0FC9F13B000E4348 = 724C604B0FC9F13B000E4348 /* PBXTextBookmark */; + 724C605B0FCA1E6E000E4348 = 724C605B0FCA1E6E000E4348 /* PBXTextBookmark */; + 724C60690FCA1E6E000E4348 = 724C60690FCA1E6E000E4348 /* PBXTextBookmark */; + 724C606A0FCA1E6E000E4348 = 724C606A0FCA1E6E000E4348 /* PBXTextBookmark */; + 724C62AC0FCB49BE000E4348 = 724C62AC0FCB49BE000E4348 /* PBXTextBookmark */; + 724C62B50FCB49BE000E4348 = 724C62B50FCB49BE000E4348 /* PBXTextBookmark */; + 724C643A0FCC46E2000E4348 = 724C643A0FCC46E2000E4348 /* PBXTextBookmark */; + 724C64F50FCD818B000E4348 = 724C64F50FCD818B000E4348 /* PBXTextBookmark */; + 724C64F90FCD818B000E4348 = 724C64F90FCD818B000E4348 /* PBXTextBookmark */; + 724C65030FCD8287000E4348 = 724C65030FCD8287000E4348 /* PBXTextBookmark */; + 724C65070FCD8287000E4348 = 724C65070FCD8287000E4348 /* PBXTextBookmark */; + 724C651A0FCD8435000E4348 = 724C651A0FCD8435000E4348 /* PBXTextBookmark */; + 724C65F10FCD9B5F000E4348 = 724C65F10FCD9B5F000E4348 /* PBXTextBookmark */; + 724C65F20FCD9B5F000E4348 = 724C65F20FCD9B5F000E4348 /* PBXTextBookmark */; + 724C66070FCD9EA8000E4348 = 724C66070FCD9EA8000E4348 /* PBXTextBookmark */; + 72540F5B1006938400925CFB = 72540F5B1006938400925CFB /* PBXTextBookmark */; + 725410561007961500925CFB = 725410561007961500925CFB /* PBXTextBookmark */; + 725410571007961500925CFB = 725410571007961500925CFB /* PBXTextBookmark */; + 725410581007961500925CFB = 725410581007961500925CFB /* PBXTextBookmark */; + 7254122F1007C71F00925CFB = 7254122F1007C71F00925CFB /* PBXTextBookmark */; + 725412E11007D63200925CFB = 725412E11007D63200925CFB /* PBXTextBookmark */; + 725D1D20107EAE6800B86564 = 725D1D20107EAE6800B86564 /* PlistBookmark */; + 725D1D22107EAE6800B86564 = 725D1D22107EAE6800B86564 /* PBXTextBookmark */; + 725D1D23107EAE6800B86564 = 725D1D23107EAE6800B86564 /* PBXTextBookmark */; + 725E01ED0FFD528100A7D6A7 = 725E01ED0FFD528100A7D6A7 /* PBXTextBookmark */; + 725E01EF0FFD528100A7D6A7 = 725E01EF0FFD528100A7D6A7 /* PBXTextBookmark */; + 725E01F30FFD528100A7D6A7 = 725E01F30FFD528100A7D6A7 /* PBXTextBookmark */; + 725E01F60FFD528100A7D6A7 = 725E01F60FFD528100A7D6A7 /* PBXTextBookmark */; + 725E02070FFD554600A7D6A7 = 725E02070FFD554600A7D6A7 /* PBXTextBookmark */; + 725E02090FFD554600A7D6A7 = 725E02090FFD554600A7D6A7 /* PBXTextBookmark */; + 725E020D0FFD554600A7D6A7 = 725E020D0FFD554600A7D6A7 /* PBXTextBookmark */; + 725E020F0FFD554600A7D6A7 = 725E020F0FFD554600A7D6A7 /* PBXTextBookmark */; + 725E02C4100242F200A7D6A7 = 725E02C4100242F200A7D6A7 /* PBXTextBookmark */; + 725E02C9100242F200A7D6A7 = 725E02C9100242F200A7D6A7 /* PBXTextBookmark */; + 725E033410024FC300A7D6A7 = 725E033410024FC300A7D6A7 /* PBXTextBookmark */; + 725E03FA100279FF00A7D6A7 = 725E03FA100279FF00A7D6A7 /* PBXTextBookmark */; + 725E03FD100279FF00A7D6A7 = 725E03FD100279FF00A7D6A7 /* PBXTextBookmark */; + 725E042410027EA700A7D6A7 = 725E042410027EA700A7D6A7 /* PBXTextBookmark */; + 725E042510027EA700A7D6A7 = 725E042510027EA700A7D6A7 /* PBXTextBookmark */; + 725E042610027EA700A7D6A7 = 725E042610027EA700A7D6A7 /* PBXTextBookmark */; + 725E04611002857800A7D6A7 = 725E04611002857800A7D6A7 /* PBXTextBookmark */; + 725E04A310028FCE00A7D6A7 = 725E04A310028FCE00A7D6A7 /* PBXTextBookmark */; + 725E04A410028FCE00A7D6A7 = 725E04A410028FCE00A7D6A7 /* PBXTextBookmark */; + 725EFFB40FFD05AB00A7D6A7 = 725EFFB40FFD05AB00A7D6A7 /* PBXTextBookmark */; + 726799F8102879A100CEA3A2 = 726799F8102879A100CEA3A2 /* PBXTextBookmark */; + 7278865F0FBDAF4B0020D469 = 7278865F0FBDAF4B0020D469 /* PBXTextBookmark */; + 727886650FBDAF4B0020D469 = 727886650FBDAF4B0020D469 /* PBXTextBookmark */; + 7280FC8A100536FA000F05FD = 7280FC8A100536FA000F05FD /* PBXTextBookmark */; + 7280FC8E100536FA000F05FD = 7280FC8E100536FA000F05FD /* PBXTextBookmark */; + 7280FD9E10054C2D000F05FD = 7280FD9E10054C2D000F05FD /* PBXTextBookmark */; + 7280FDD310054DAB000F05FD = 7280FDD310054DAB000F05FD /* PBXTextBookmark */; + 728818D5108575100049CC03 /* PBXTextBookmark */ = 728818D5108575100049CC03 /* PBXTextBookmark */; + 728818D6108575100049CC03 /* PBXTextBookmark */ = 728818D6108575100049CC03 /* PBXTextBookmark */; + 728818D7108575100049CC03 /* PBXTextBookmark */ = 728818D7108575100049CC03 /* PBXTextBookmark */; + 728818D8108575100049CC03 /* PBXTextBookmark */ = 728818D8108575100049CC03 /* PBXTextBookmark */; + 728818EC1085775C0049CC03 /* PBXTextBookmark */ = 728818EC1085775C0049CC03 /* PBXTextBookmark */; + 728818ED1085775C0049CC03 /* PBXTextBookmark */ = 728818ED1085775C0049CC03 /* PBXTextBookmark */; + 728818EE1085775C0049CC03 /* PBXTextBookmark */ = 728818EE1085775C0049CC03 /* PBXTextBookmark */; + 728818EF1085775C0049CC03 /* PBXTextBookmark */ = 728818EF1085775C0049CC03 /* PBXTextBookmark */; + 728818F01085775C0049CC03 /* PBXTextBookmark */ = 728818F01085775C0049CC03 /* PBXTextBookmark */; + 728818F11085775C0049CC03 /* PBXTextBookmark */ = 728818F11085775C0049CC03 /* PBXTextBookmark */; + 728818F2108577850049CC03 /* PBXTextBookmark */ = 728818F2108577850049CC03 /* PBXTextBookmark */; + 728818F4108577850049CC03 /* PBXTextBookmark */ = 728818F4108577850049CC03 /* PBXTextBookmark */; + 728818F7108577A30049CC03 /* PBXTextBookmark */ = 728818F7108577A30049CC03 /* PBXTextBookmark */; + 728818F8108577A30049CC03 /* PBXTextBookmark */ = 728818F8108577A30049CC03 /* PBXTextBookmark */; + 728818F9108577A30049CC03 /* PBXTextBookmark */ = 728818F9108577A30049CC03 /* PBXTextBookmark */; + 728818FA108577A30049CC03 /* PBXTextBookmark */ = 728818FA108577A30049CC03 /* PBXTextBookmark */; + 728818FB108577BE0049CC03 /* PBXTextBookmark */ = 728818FB108577BE0049CC03 /* PBXTextBookmark */; + 728818FC108577BE0049CC03 /* PBXTextBookmark */ = 728818FC108577BE0049CC03 /* PBXTextBookmark */; + 728818FF108578270049CC03 /* PBXTextBookmark */ = 728818FF108578270049CC03 /* PBXTextBookmark */; + 72881900108578270049CC03 /* PBXTextBookmark */ = 72881900108578270049CC03 /* PBXTextBookmark */; + 72881901108578270049CC03 /* PBXTextBookmark */ = 72881901108578270049CC03 /* PBXTextBookmark */; + 72881902108578270049CC03 /* PBXTextBookmark */ = 72881902108578270049CC03 /* PBXTextBookmark */; + 728819031085784E0049CC03 /* PBXTextBookmark */ = 728819031085784E0049CC03 /* PBXTextBookmark */; + 728819041085784E0049CC03 /* PBXTextBookmark */ = 728819041085784E0049CC03 /* PBXTextBookmark */; + 728819061085784E0049CC03 /* PBXTextBookmark */ = 728819061085784E0049CC03 /* PBXTextBookmark */; + 728819071085784E0049CC03 /* PBXTextBookmark */ = 728819071085784E0049CC03 /* PBXTextBookmark */; + 72973B310FF5259E00F813E6 = 72973B310FF5259E00F813E6 /* PBXTextBookmark */; + 72973B7A0FF52F5800F813E6 = 72973B7A0FF52F5800F813E6 /* PBXTextBookmark */; + 72A55D451002ACBB00F788A5 = 72A55D451002ACBB00F788A5 /* PBXTextBookmark */; + 72A55DCE1002B27400F788A5 = 72A55DCE1002B27400F788A5 /* PBXTextBookmark */; + 72A55E7110039E9700F788A5 = 72A55E7110039E9700F788A5 /* PBXTextBookmark */; + 72A55F381003B1E200F788A5 = 72A55F381003B1E200F788A5 /* PBXTextBookmark */; + 72A55F391003B1E200F788A5 = 72A55F391003B1E200F788A5 /* PBXTextBookmark */; + 72A55F3A1003B1E200F788A5 = 72A55F3A1003B1E200F788A5 /* PBXTextBookmark */; + 72A55FD41003D14900F788A5 = 72A55FD41003D14900F788A5 /* PBXTextBookmark */; + 72A5604D1003E44400F788A5 = 72A5604D1003E44400F788A5 /* PBXTextBookmark */; + 72A560551003E44400F788A5 = 72A560551003E44400F788A5 /* PBXTextBookmark */; + 72A6EEFA0FABCA670000A7A0 = 72A6EEFA0FABCA670000A7A0 /* PBXTextBookmark */; + 72A6EEFC0FABCA670000A7A0 = 72A6EEFC0FABCA670000A7A0 /* PBXTextBookmark */; + 72A6EF3D0FABCE0D0000A7A0 = 72A6EF3D0FABCE0D0000A7A0 /* PBXTextBookmark */; + 72A6EFEA0FABE6ED0000A7A0 = 72A6EFEA0FABE6ED0000A7A0 /* PBXTextBookmark */; + 72A6EFEB0FABE6ED0000A7A0 = 72A6EFEB0FABE6ED0000A7A0 /* PBXTextBookmark */; + 72A6EFF20FABE6ED0000A7A0 = 72A6EFF20FABE6ED0000A7A0 /* PBXTextBookmark */; + 72A6EFF30FABE6ED0000A7A0 = 72A6EFF30FABE6ED0000A7A0 /* PBXTextBookmark */; + 72A6EFF40FABE6ED0000A7A0 = 72A6EFF40FABE6ED0000A7A0 /* PBXTextBookmark */; + 72A6F0010FABE81E0000A7A0 = 72A6F0010FABE81E0000A7A0 /* PBXTextBookmark */; + 72A6F0040FABE81E0000A7A0 = 72A6F0040FABE81E0000A7A0 /* PBXTextBookmark */; + 72A6F0480FAF3E350000A7A0 = 72A6F0480FAF3E350000A7A0 /* PBXTextBookmark */; + 72A6F0F00FAF7C5F0000A7A0 = 72A6F0F00FAF7C5F0000A7A0 /* PBXTextBookmark */; + 72A6F11A0FAF7E860000A7A0 = 72A6F11A0FAF7E860000A7A0 /* PBXTextBookmark */; + 72AC93D7107EA14200D77CA8 = 72AC93D7107EA14200D77CA8 /* PBXTextBookmark */; + 72AD09B60FA22C8A000999A0 = 72AD09B60FA22C8A000999A0 /* PBXTextBookmark */; + 72AD09B70FA22C8A000999A0 = 72AD09B70FA22C8A000999A0 /* PBXTextBookmark */; + 72AD09B80FA22C8A000999A0 = 72AD09B80FA22C8A000999A0 /* PBXTextBookmark */; + 72AD09BB0FA22C8A000999A0 = 72AD09BB0FA22C8A000999A0 /* PBXTextBookmark */; + 72AD09CC0FA22D58000999A0 = 72AD09CC0FA22D58000999A0 /* PBXTextBookmark */; + 72AD09DA0FA23046000999A0 = 72AD09DA0FA23046000999A0 /* PBXTextBookmark */; + 72AD09DB0FA23046000999A0 = 72AD09DB0FA23046000999A0 /* PBXTextBookmark */; + 72AD0A0B0FA23674000999A0 = 72AD0A0B0FA23674000999A0 /* PBXTextBookmark */; + 72AD0A6C0FA4961E000999A0 = 72AD0A6C0FA4961E000999A0 /* PBXTextBookmark */; + 72AD0A810FA4961E000999A0 = 72AD0A810FA4961E000999A0 /* PBXTextBookmark */; + 72AD0BEC0FA62D9E000999A0 = 72AD0BEC0FA62D9E000999A0 /* PBXTextBookmark */; + 72AD0BF50FA62D9E000999A0 = 72AD0BF50FA62D9E000999A0 /* PBXTextBookmark */; + 72AD0BF60FA62D9E000999A0 = 72AD0BF60FA62D9E000999A0 /* PBXTextBookmark */; + 72AD0BF80FA62D9E000999A0 = 72AD0BF80FA62D9E000999A0 /* PBXTextBookmark */; + 72AD0C020FA62D9E000999A0 = 72AD0C020FA62D9E000999A0 /* PBXTextBookmark */; + 72AD0C060FA62D9E000999A0 = 72AD0C060FA62D9E000999A0 /* PBXTextBookmark */; + 72AD0C2C0FA63091000999A0 = 72AD0C2C0FA63091000999A0 /* PBXTextBookmark */; + 72AD0CAA0FA64E09000999A0 = 72AD0CAA0FA64E09000999A0 /* PBXTextBookmark */; + 72B0E92F0FBC872600D1D1FA = 72B0E92F0FBC872600D1D1FA /* PBXTextBookmark */; + 72B0E9300FBC872600D1D1FA = 72B0E9300FBC872600D1D1FA /* PBXTextBookmark */; + 72B0E93F0FBC872600D1D1FA = 72B0E93F0FBC872600D1D1FA /* PBXTextBookmark */; + 72B0E9A30FBC8F3600D1D1FA = 72B0E9A30FBC8F3600D1D1FA /* PBXTextBookmark */; + 72B0E9A40FBC8F3600D1D1FA = 72B0E9A40FBC8F3600D1D1FA /* PBXTextBookmark */; + 72B0E9A80FBC8F3600D1D1FA = 72B0E9A80FBC8F3600D1D1FA /* PBXTextBookmark */; + 72B0E9D40FBCDCDC00D1D1FA = 72B0E9D40FBCDCDC00D1D1FA /* PBXTextBookmark */; + 72B0EA0A0FBCE5F600D1D1FA = 72B0EA0A0FBCE5F600D1D1FA /* PBXTextBookmark */; + 72B2B1D70FB9BA7D00AAFC45 = 72B2B1D70FB9BA7D00AAFC45 /* PBXTextBookmark */; + 72B2B2C60FB9DC5900AAFC45 = 72B2B2C60FB9DC5900AAFC45 /* PBXTextBookmark */; + 72B2B2CA0FB9DC5900AAFC45 = 72B2B2CA0FB9DC5900AAFC45 /* PBXTextBookmark */; + 72B2B2CB0FB9DC5900AAFC45 = 72B2B2CB0FB9DC5900AAFC45 /* PBXTextBookmark */; + 72B4A6C40FAB633200DC59D9 = 72B4A6C40FAB633200DC59D9 /* PBXTextBookmark */; + 72B4A6CE0FAB633200DC59D9 = 72B4A6CE0FAB633200DC59D9 /* PBXTextBookmark */; + 72B4A7610FAB7B6100DC59D9 = 72B4A7610FAB7B6100DC59D9 /* PBXTextBookmark */; + 72B9E7450FCDF4A000939821 = 72B9E7450FCDF4A000939821 /* PBXTextBookmark */; + 72B9E7770FCDFB5200939821 = 72B9E7770FCDFB5200939821 /* PBXTextBookmark */; + 72B9E7F50FCE199C00939821 = 72B9E7F50FCE199C00939821 /* PBXTextBookmark */; + 72B9E7FA0FCE199C00939821 = 72B9E7FA0FCE199C00939821 /* PBXTextBookmark */; + 72BA12631028B32000DDB148 = 72BA12631028B32000DDB148 /* PBXTextBookmark */; + 72BA12711028BED300DDB148 = 72BA12711028BED300DDB148 /* PBXTextBookmark */; + 72BA131A1028C8D200DDB148 = 72BA131A1028C8D200DDB148 /* PBXTextBookmark */; + 72BCB43E0FB8C17C000EC406 = 72BCB43E0FB8C17C000EC406 /* PBXTextBookmark */; + 72BCB4430FB8C17C000EC406 = 72BCB4430FB8C17C000EC406 /* PBXTextBookmark */; + 72BCB4710FB8DCB6000EC406 = 72BCB4710FB8DCB6000EC406 /* PBXTextBookmark */; + 72BCB4860FB8DCB6000EC406 = 72BCB4860FB8DCB6000EC406 /* PBXTextBookmark */; + 72BCB4E20FB8DEDE000EC406 = 72BCB4E20FB8DEDE000EC406 /* PBXTextBookmark */; + 72BCB54A0FB8E380000EC406 = 72BCB54A0FB8E380000EC406 /* PBXTextBookmark */; + 72BCB56A0FB8E4B7000EC406 = 72BCB56A0FB8E4B7000EC406 /* PBXTextBookmark */; + 72BCB5830FB8E5B1000EC406 = 72BCB5830FB8E5B1000EC406 /* PBXTextBookmark */; + 72BCB5840FB8E5B1000EC406 = 72BCB5840FB8E5B1000EC406 /* PBXTextBookmark */; + 72BCB5860FB8E5B1000EC406 = 72BCB5860FB8E5B1000EC406 /* PBXTextBookmark */; + 72BCB5A00FB8E713000EC406 = 72BCB5A00FB8E713000EC406 /* PBXTextBookmark */; + 72BCB66B0FB8EADA000EC406 = 72BCB66B0FB8EADA000EC406 /* PBXTextBookmark */; + 72BCB6D00FB8FB83000EC406 = 72BCB6D00FB8FB83000EC406 /* PBXTextBookmark */; + 72BCB7530FB90A87000EC406 = 72BCB7530FB90A87000EC406 /* PBXTextBookmark */; + 72BD33500FB49A10002E4055 = 72BD33500FB49A10002E4055 /* PBXTextBookmark */; + 72BD33540FB49A10002E4055 = 72BD33540FB49A10002E4055 /* PBXTextBookmark */; + 72BD34BB0FB505C4002E4055 = 72BD34BB0FB505C4002E4055 /* PBXTextBookmark */; + 72BD34C10FB505C4002E4055 = 72BD34C10FB505C4002E4055 /* PBXTextBookmark */; + 72DB5702101A58CB00A58CED = 72DB5702101A58CB00A58CED /* PBXTextBookmark */; + 72DB5727101A617200A58CED = 72DB5727101A617200A58CED /* PBXTextBookmark */; + 72DB578C101A742600A58CED = 72DB578C101A742600A58CED /* PBXTextBookmark */; + 72DB579D101A78F300A58CED = 72DB579D101A78F300A58CED /* PBXTextBookmark */; + 72E7896F0FB762C1001FACDD = 72E7896F0FB762C1001FACDD /* PBXTextBookmark */; + 72F222C4107F9025000F9D8D = 72F222C4107F9025000F9D8D /* PlistBookmark */; + 72F222C6107F9025000F9D8D = 72F222C6107F9025000F9D8D /* PlistBookmark */; + 72F222FE107F96AB000F9D8D = 72F222FE107F96AB000F9D8D /* PBXTextBookmark */; + 72F222FF107F96AB000F9D8D = 72F222FF107F96AB000F9D8D /* PBXTextBookmark */; + 72F2230B107F97D5000F9D8D = 72F2230B107F97D5000F9D8D /* PBXTextBookmark */; + 72F2231A107F9A44000F9D8D = 72F2231A107F9A44000F9D8D /* PBXTextBookmark */; + 72F2231E107F9A44000F9D8D = 72F2231E107F9A44000F9D8D /* PBXTextBookmark */; + 72F2231F107F9A44000F9D8D = 72F2231F107F9A44000F9D8D /* PBXTextBookmark */; + 72F22320107F9A44000F9D8D = 72F22320107F9A44000F9D8D /* PBXTextBookmark */; + 72F22321107F9A44000F9D8D = 72F22321107F9A44000F9D8D /* PBXTextBookmark */; + 72F22322107F9A44000F9D8D = 72F22322107F9A44000F9D8D /* PBXTextBookmark */; + 72F22323107F9A44000F9D8D = 72F22323107F9A44000F9D8D /* PBXTextBookmark */; + 72F22324107F9A44000F9D8D = 72F22324107F9A44000F9D8D /* PBXTextBookmark */; + 72F22325107F9A44000F9D8D = 72F22325107F9A44000F9D8D /* PBXTextBookmark */; + 72F22334107F9AD2000F9D8D = 72F22334107F9AD2000F9D8D /* PBXTextBookmark */; + 72F2233C107F9C82000F9D8D = 72F2233C107F9C82000F9D8D /* PBXTextBookmark */; + 72F2233D107F9C82000F9D8D = 72F2233D107F9C82000F9D8D /* PBXTextBookmark */; + 72F2233F107F9C82000F9D8D = 72F2233F107F9C82000F9D8D /* PBXTextBookmark */; + 72F22340107F9C82000F9D8D = 72F22340107F9C82000F9D8D /* PBXTextBookmark */; + 72F22341107F9C82000F9D8D = 72F22341107F9C82000F9D8D /* PBXTextBookmark */; + 72F22342107F9C82000F9D8D = 72F22342107F9C82000F9D8D /* PBXTextBookmark */; + 72F22343107F9C82000F9D8D = 72F22343107F9C82000F9D8D /* PBXTextBookmark */; + 72F22344107F9C82000F9D8D = 72F22344107F9C82000F9D8D /* PBXTextBookmark */; + 72F22345107F9C82000F9D8D = 72F22345107F9C82000F9D8D /* PBXTextBookmark */; + 72F22346107F9C82000F9D8D = 72F22346107F9C82000F9D8D /* PBXTextBookmark */; + 72F22347107F9C82000F9D8D = 72F22347107F9C82000F9D8D /* PBXTextBookmark */; + 72F22356107F9D12000F9D8D = 72F22356107F9D12000F9D8D /* PBXTextBookmark */; + 72F22357107F9D12000F9D8D = 72F22357107F9D12000F9D8D /* PBXTextBookmark */; + 72F22359107F9D12000F9D8D = 72F22359107F9D12000F9D8D /* PBXTextBookmark */; + 72F2235A107F9D12000F9D8D = 72F2235A107F9D12000F9D8D /* PBXTextBookmark */; + 72F2235B107F9D12000F9D8D = 72F2235B107F9D12000F9D8D /* PBXTextBookmark */; + 72F22380107FB264000F9D8D = 72F22380107FB264000F9D8D /* PBXTextBookmark */; + 72F22384107FB264000F9D8D = 72F22384107FB264000F9D8D /* PBXTextBookmark */; + 72F22385107FB264000F9D8D = 72F22385107FB264000F9D8D /* PBXTextBookmark */; + 72F22386107FB264000F9D8D = 72F22386107FB264000F9D8D /* PBXTextBookmark */; + 72F22393107FBD55000F9D8D = 72F22393107FBD55000F9D8D /* PBXTextBookmark */; + 72F22394107FBD55000F9D8D = 72F22394107FBD55000F9D8D /* PBXTextBookmark */; + 72F22397107FBD55000F9D8D = 72F22397107FBD55000F9D8D /* PBXTextBookmark */; + 72F22398107FBD55000F9D8D = 72F22398107FBD55000F9D8D /* PBXTextBookmark */; + 72F22399107FBD55000F9D8D = 72F22399107FBD55000F9D8D /* PBXTextBookmark */; + 72F2239A107FBD55000F9D8D = 72F2239A107FBD55000F9D8D /* PBXTextBookmark */; + 72F2239B107FBD55000F9D8D = 72F2239B107FBD55000F9D8D /* PBXTextBookmark */; + 72F2239C107FBD55000F9D8D = 72F2239C107FBD55000F9D8D /* PBXTextBookmark */; + 72F2239D107FBD55000F9D8D = 72F2239D107FBD55000F9D8D /* PBXTextBookmark */; + 72F2239E107FBD55000F9D8D = 72F2239E107FBD55000F9D8D /* PBXTextBookmark */; + 72F2239F107FBD55000F9D8D = 72F2239F107FBD55000F9D8D /* PBXTextBookmark */; + 72F223A0107FBD55000F9D8D = 72F223A0107FBD55000F9D8D /* PBXTextBookmark */; + 72F223AC107FBDA6000F9D8D = 72F223AC107FBDA6000F9D8D /* PBXTextBookmark */; + 72F223AD107FBDA6000F9D8D = 72F223AD107FBDA6000F9D8D /* PBXTextBookmark */; + 72F223AF107FBDA6000F9D8D = 72F223AF107FBDA6000F9D8D /* PBXTextBookmark */; + 72F223B0107FBDA6000F9D8D = 72F223B0107FBDA6000F9D8D /* PBXTextBookmark */; + 72F223B1107FBDA6000F9D8D = 72F223B1107FBDA6000F9D8D /* PBXTextBookmark */; + 72F223B2107FBDA6000F9D8D = 72F223B2107FBDA6000F9D8D /* PBXTextBookmark */; + 72F223B8107FBDD0000F9D8D = 72F223B8107FBDD0000F9D8D /* PBXTextBookmark */; + 72F223BC107FC076000F9D8D = 72F223BC107FC076000F9D8D /* PBXTextBookmark */; + 72F223BD107FC076000F9D8D = 72F223BD107FC076000F9D8D /* PBXTextBookmark */; + 72F223BE107FC076000F9D8D = 72F223BE107FC076000F9D8D /* PBXTextBookmark */; + 72F223BF107FC076000F9D8D = 72F223BF107FC076000F9D8D /* PlistBookmark */; + 72F223C0107FC076000F9D8D = 72F223C0107FC076000F9D8D /* PBXTextBookmark */; + 72F223C1107FC076000F9D8D = 72F223C1107FC076000F9D8D /* PBXTextBookmark */; + }; + sourceControlManager = 72AD09AF0FA224DC000999A0 /* Source Control */; + userBookmarkGroup = 725EFEA30FFC17BA00A7D6A7 /* PBXBookmarkGroup */; + userBuildSettings = { + }; + }; + 29B97316FDCFA39411CA2CEA /* main.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {850, 950}}"; + sepNavSelRange = "{941, 0}"; + sepNavVisRange = "{531, 865}"; + }; + }; + 434669A30F8D08C000EA7D6D /* doom_Prefix.pch */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {850, 477}}"; + sepNavSelRange = "{70, 0}"; + sepNavVisRange = "{0, 169}"; + }; + }; + 434669A40F8D08C000EA7D6D /* doomAppDelegate.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {850, 760}}"; + sepNavSelRange = "{836, 0}"; + sepNavVisRange = "{483, 660}"; + }; + }; + 434669A50F8D08C000EA7D6D /* doomAppDelegate.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {823, 4351}}"; + sepNavSelRange = "{3905, 0}"; + sepNavVisRange = "{3028, 1730}"; + sepNavWindowFrame = "{{470, 51}, {882, 977}}"; + }; + }; + 43A945140F82D75900FFD32E /* iphone_sys.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {885, 1178}}"; + sepNavSelRange = "{936, 0}"; + sepNavVisRange = "{936, 518}"; + }; + }; + 43CF03090F56D5C200E4A23D /* iphone_loop.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {940, 33174}}"; + sepNavSelRange = "{11680, 3}"; + sepNavVisRange = "{11286, 821}"; + sepNavWindowFrame = "{{90, -141}, {882, 977}}"; + }; + }; + 43DD8391100295F70006E1DD /* iphone_async.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {866, 18658}}"; + sepNavSelRange = "{16313, 0}"; + sepNavVisRange = "{15866, 1136}"; + }; + }; + 43E8D2DF0F4FC61E003F09B2 /* iphone_main.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {848, 10165}}"; + sepNavSelRange = "{3966, 0}"; + sepNavVisRange = "{3014, 993}"; + sepNavWindowFrame = "{{101, 26}, {907, 950}}"; + }; + }; + 7201D45F0FA6828B00D81683 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847640F93C61900AB3C99 /* am_map.c */; + name = "am_map.c: 843"; + rLen = 28; + rLoc = 21845; + rType = 0; + vrLen = 753; + vrLoc = 24308; + }; + 7201D4600FA6828B00D81683 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8484E0F941ADC00AB3C99 /* v_video.c */; + name = "v_video.c: 766"; + rLen = 12; + rLoc = 24593; + rType = 0; + vrLen = 1311; + vrLoc = 24144; + }; + 7201D4610FA6828B00D81683 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847920F9400D700AB3C99 /* gl_main.c */; + name = "gl_main.c: 651"; + rLen = 14; + rLoc = 27525; + rType = 0; + vrLen = 621; + vrLoc = 26645; + }; + 7201D4640FA6828B00D81683 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848550F941ADC00AB3C99 /* w_wad.h */; + name = "w_wad.h: 126"; + rLen = 120; + rLoc = 3562; + rType = 0; + vrLen = 1148; + vrLoc = 3271; + }; + 7201D47A0FA684B400D81683 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847CA0F94096C00AB3C99 /* SDL_opengl.h */; + name = "SDL_opengl.h: 26"; + rLen = 0; + rLoc = 681; + rType = 0; + vrLen = 892; + vrLoc = 72; + }; + 7201D47C0FA684B400D81683 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E849F50F94ED1100AB3C99 /* prboomInterface.c */; + name = "prboomInterface.c: 322"; + rLen = 0; + rLoc = 6518; + rType = 0; + vrLen = 442; + vrLoc = 7196; + }; + 7201D47E0FA684B400D81683 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847CA0F94096C00AB3C99 /* SDL_opengl.h */; + name = "SDL_opengl.h: 26"; + rLen = 0; + rLoc = 681; + rType = 0; + vrLen = 892; + vrLoc = 72; + }; + 7201D4900FA685CB00D81683 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847930F9400D700AB3C99 /* gl_struct.h */; + name = "gl_struct.h: 39"; + rLen = 13; + rLoc = 1440; + rType = 0; + vrLen = 908; + vrLoc = 1038; + }; + 7201D4980FA6862500D81683 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7201D4990FA6862500D81683 /* r_drawcolumn.inl */; + name = "r_drawcolumn.inl: 253"; + rLen = 60; + rLoc = 9288; + rType = 0; + vrLen = 961; + vrLoc = 8776; + }; + 7201D4990FA6862500D81683 /* r_drawcolumn.inl */ = { + isa = PBXFileReference; + lastKnownFileType = text; + name = r_drawcolumn.inl; + path = /Users/johnc/dev/iphone/doom/code/iphone/../prboom/r_drawcolumn.inl; + sourceTree = ""; + }; + 7201D49D0FA6862500D81683 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7201D49E0FA6862500D81683 /* r_drawcolumn.inl */; + name = "r_drawcolumn.inl: 253"; + rLen = 60; + rLoc = 9288; + rType = 0; + vrLen = 961; + vrLoc = 8776; + }; + 7201D49E0FA6862500D81683 /* r_drawcolumn.inl */ = { + isa = PBXFileReference; + lastKnownFileType = text; + name = r_drawcolumn.inl; + path = /Users/johnc/dev/iphone/doom/code/iphone/../prboom/r_drawcolumn.inl; + sourceTree = ""; + }; + 7201D4D00FA694B500D81683 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A945140F82D75900FFD32E /* iphone_sys.c */; + name = "iphone_sys.c: 71"; + rLen = 0; + rLoc = 936; + rType = 0; + vrLen = 0; + vrLoc = 1455; + }; + 7201D5B00FA79C1800D81683 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E731EA0F97E68100E702CD /* iphone_sound.c */; + name = "iphone_sound.c: 443"; + rLen = 0; + rLoc = 717; + rType = 0; + vrLen = 0; + vrLoc = 6971; + }; + 7201D73B0FA7FD3300D81683 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847AA0F9400D700AB3C99 /* m_menu.c */; + name = "m_menu.c: 995"; + rLen = 10; + rLoc = 22273; + rType = 0; + vrLen = 732; + vrLoc = 21789; + }; + 7201D7620FA7FED300D81683 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8477C0F9400D700AB3C99 /* d_main.c */; + name = "d_main.c: 212"; + rLen = 0; + rLoc = 6082; + rType = 0; + vrLen = 959; + vrLoc = 5621; + }; + 7201D7650FA7FED300D81683 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847970F9400D700AB3C99 /* hu_stuff.c */; + name = "hu_stuff.c: 1285"; + rLen = 0; + rLoc = 38156; + rType = 0; + vrLen = 721; + vrLoc = 37682; + }; + 7201D7660FA7FED300D81683 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847950F9400D700AB3C99 /* hu_lib.c */; + name = "hu_lib.c: 378"; + rLen = 0; + rLoc = 8874; + rType = 0; + vrLen = 587; + vrLoc = 8624; + }; + 7201D76D0FA7FED300D81683 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8482E0F941AAC00AB3C99 /* r_main.c */; + name = "r_main.c: 371"; + rLen = 49; + rLoc = 10582; + rType = 0; + vrLen = 659; + vrLoc = 10506; + }; + 7201D7B70FA8B04600D81683 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8479C0F9400D700AB3C99 /* i_sound.h */; + name = "i_sound.h: 64"; + rLen = 12; + rLoc = 1909; + rType = 0; + vrLen = 675; + vrLoc = 1528; + }; + 7201D7BE0FA8B04600D81683 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8483B0F941AAC00AB3C99 /* s_sound.c */; + name = "s_sound.c: 308"; + rLen = 12; + rLoc = 9959; + rType = 0; + vrLen = 732; + vrLoc = 8092; + }; + 7201D7BF0FA8B04600D81683 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8479C0F9400D700AB3C99 /* i_sound.h */; + name = "i_sound.h: 64"; + rLen = 12; + rLoc = 1909; + rType = 0; + vrLen = 675; + vrLoc = 1528; + }; + 7201D7C10FA8B04600D81683 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847AC0F9400D700AB3C99 /* m_misc.c */; + name = "m_misc.c: 298"; + rLen = 13; + rLoc = 11661; + rType = 0; + vrLen = 1599; + vrLoc = 11025; + }; + 7201D8040FA8C52200D81683 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847A90F9400D700AB3C99 /* m_fixed.h */; + name = "m_fixed.h: 1"; + rLen = 6081; + rLoc = 0; + rType = 0; + vrLen = 633; + vrLoc = 5448; + }; + 7201D8270FA8CBFA00D81683 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8481D0F941A8300AB3C99 /* r_bsp.c */; + name = "r_bsp.c: 493"; + rLen = 0; + rLoc = 15440; + rType = 0; + vrLen = 684; + vrLoc = 15147; + }; + 7201D8950FA8E2AD00D81683 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848340F941AAC00AB3C99 /* r_segs.c */; + name = "r_segs.c: 497"; + rLen = 0; + rLoc = 16588; + rType = 0; + vrLen = 745; + vrLoc = 15738; + }; + 7201D8DB0FA8ED7D00D81683 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848300F941AAC00AB3C99 /* r_patch.c */; + name = "r_patch.c: 719"; + rLen = 0; + rLoc = 24495; + rType = 0; + vrLen = 739; + vrLoc = 2949; + }; + 7201D9CC0FA91DCE00D81683 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8478F0F9400D700AB3C99 /* g_game.c */; + name = "g_game.c: 2618"; + rLen = 10; + rLoc = 76460; + rType = 0; + vrLen = 588; + vrLoc = 76128; + }; + 7201D9CD0FA91DCE00D81683 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847730F93FFDB00AB3C99 /* d_event.h */; + name = "d_event.h: 76"; + rLen = 10; + rLoc = 1961; + rType = 0; + vrLen = 356; + vrLoc = 1796; + }; + 7201D9CF0FA91DCE00D81683 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847720F93FFDB00AB3C99 /* d_englsh.h */; + name = "d_englsh.h: 54"; + rLen = 7; + rLoc = 2296; + rType = 0; + vrLen = 1164; + vrLoc = 1770; + }; + 7201DA4F0FA929DB00D81683 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847A70F9400D700AB3C99 /* m_cheat.c */; + name = "m_cheat.c: 509"; + rLen = 7; + rLoc = 15728; + rType = 0; + vrLen = 993; + vrLoc = 15235; + }; + 7201DA500FA929DB00D81683 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8481F0F941A8300AB3C99 /* r_data.c */; + name = "r_data.c: 454"; + rLen = 7; + rLoc = 14367; + rType = 0; + vrLen = 761; + vrLoc = 14131; + }; + 720CBDFF10065F6500801220 /* s_sound.c:290 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E8483B0F941AAC00AB3C99 /* s_sound.c */; + functionName = "S_StartSoundAtVolume()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 290; + location = doom; + modificationTime = 277182472.328285; + state = 2; + }; + 720CBE21100661BC00801220 /* s_sound.c:732 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E8483B0F941AAC00AB3C99 /* s_sound.c */; + functionName = "S_getChannel()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 732; + location = doom; + modificationTime = 277182472.328555; + state = 2; + }; + 720CBE281006623E00801220 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 720CBE291006623E00801220 /* ctype.h */; + name = "ctype.h: 317"; + rLen = 0; + rLoc = 9560; + rType = 0; + vrLen = 346; + vrLoc = 9336; + }; + 720CBE291006623E00801220 /* ctype.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = ctype.h; + path = /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.0.sdk/usr/include/ctype.h; + sourceTree = ""; + }; + 720CBE371006623E00801220 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 720CBE381006623E00801220 /* ctype.h */; + name = "ctype.h: 317"; + rLen = 0; + rLoc = 9560; + rType = 0; + vrLen = 346; + vrLoc = 9336; + }; + 720CBE381006623E00801220 /* ctype.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = ctype.h; + path = /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.0.sdk/usr/include/ctype.h; + sourceTree = ""; + }; + 720CBE95100680E500801220 /* iphone_loop.c:1363 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneFrame()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1363; + location = doom; + modificationTime = 277182472.328818; + state = 2; + }; + 72151FA50FF57354001CDDB7 /* iphone_loop.c:1286 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneAsyncTic()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1286; + location = doom; + modificationTime = 277182472.309181; + state = 2; + }; + 72151FA70FF57356001CDDB7 /* iphone_loop.c:1286 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneAsyncTic()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1286; + location = doom; + modificationTime = 277182472.309329; + state = 2; + }; + 72151FA90FF5735A001CDDB7 /* iphone_loop.c:1286 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneAsyncTic()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1286; + location = doom; + modificationTime = 277182472.309476; + state = 2; + }; + 72151FD50FF57D22001CDDB7 /* iphone_menus.c:27 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "StartNetGame()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 27; + location = doom; + modificationTime = 277182472.309628; + state = 2; + }; + 721520130FF588E9001CDDB7 /* iphone_menus.c:27 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "iphoneIntermission()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 27; + location = doom; + modificationTime = 277182472.309783; + state = 2; + }; + 721520370FF5895A001CDDB7 /* g_game.c:1248 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E8478F0F9400D700AB3C99 /* g_game.c */; + functionName = "G_ExitLevel()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1248; + location = doom; + modificationTime = 277182472.309939; + state = 2; + }; + 721520390FF5895D001CDDB7 /* g_game.c:1260 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E8478F0F9400D700AB3C99 /* g_game.c */; + functionName = "G_SecretExitLevel()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1260; + location = doom; + modificationTime = 277182472.310091; + state = 2; + }; + 7215204D0FF58C16001CDDB7 /* iphone_loop.c:1286 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneAsyncTic()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1286; + location = doom; + modificationTime = 277182472.310246; + state = 2; + }; + 721520810FF58D43001CDDB7 /* iphone_loop.c:1285 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "DropPlayer()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1285; + location = doom; + modificationTime = 277182472.310399; + state = 2; + }; + 721520BC0FF5936A001CDDB7 /* iphone_loop.c:1464 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneFrame()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1464; + location = doom; + modificationTime = 277182472.31055; + state = 2; + }; + 721520BE0FF59476001CDDB7 /* iphone_loop.c:1286 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneAsyncTic()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1286; + location = doom; + modificationTime = 277182472.310702; + state = 2; + }; + 721520CC0FF59671001CDDB7 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847E50F941A5900AB3C99 /* p_checksum.c */; + name = "p_checksum.c: 16"; + rLen = 0; + rLoc = 314; + rType = 0; + vrLen = 574; + vrLoc = 0; + }; + 721520F70FF597C4001CDDB7 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847FD0F941A5900AB3C99 /* p_spec.c */; + name = "p_spec.c: 2322"; + rLen = 0; + rLoc = 65715; + rType = 0; + vrLen = 713; + vrLoc = 65353; + }; + 721521040FF5992A001CDDB7 /* iphone_menus.c:27 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "StartNetGame()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 27; + location = doom; + modificationTime = 277182472.310854; + state = 2; + }; + 721521120FF59AA5001CDDB7 /* iphone_loop.c:1286 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneAsyncTic()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1286; + location = doom; + modificationTime = 277182472.31101; + state = 2; + }; + 721D073B0FF55DF0008465F7 /* iphone_loop.c:1286 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneAsyncTic()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1286; + location = doom; + modificationTime = 277182472.30832; + state = 2; + }; + 721D07460FF560EC008465F7 /* iphone_loop.c:1286 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneAsyncTic()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1286; + location = doom; + modificationTime = 277182472.30847; + state = 2; + }; + 721D07C90FF56BB7008465F7 /* iphone_loop.c:1286 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneAsyncTic()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1286; + location = doom; + modificationTime = 277182472.308621; + state = 2; + }; + 721D07D30FF56BFC008465F7 /* iphone_main.c:237 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43E8D2DF0F4FC61E003F09B2 /* iphone_main.c */; + functionName = "iphoneStartup()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 237; + location = doom; + modificationTime = 277182472.308768; + state = 2; + }; + 721D07D50FF56C00008465F7 /* iphone_main.c:237 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43E8D2DF0F4FC61E003F09B2 /* iphone_main.c */; + functionName = "iphoneStartup()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 237; + location = doom; + modificationTime = 277182472.308974; + state = 2; + }; + 7229CC8E0F6B3363004123C5 /* doomiphone.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {779, 2033}}"; + sepNavSelRange = "{2066, 0}"; + sepNavVisRange = "{1479, 931}"; + sepNavWindowFrame = "{{402, 185}, {838, 824}}"; + }; + }; + 7229CE450F6C89F8004123C5 /* EAGLView.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {850, 950}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 1184}"; + }; + }; + 7229CE460F6C89F8004123C5 /* EAGLView.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {956, 6308}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 364}"; + sepNavWindowFrame = "{{114, 68}, {907, 950}}"; + }; + }; + 7229CE540F6C8CDE004123C5 /* gles_glue.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {866, 3724}}"; + sepNavSelRange = "{4744, 3}"; + sepNavVisRange = "{4394, 716}"; + }; + }; + 722DFAE80FB8A419002A6405 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847910F9400D700AB3C99 /* gl_intern.h */; + name = "gl_intern.h: 91"; + rLen = 0; + rLoc = 2312; + rType = 0; + vrLen = 493; + vrLoc = 2041; + }; + 7239452B0F9C0E7500EADD62 /* iphone_mapSelect.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {866, 8721}}"; + sepNavSelRange = "{7396, 0}"; + sepNavVisRange = "{7073, 890}"; + sepNavWindowFrame = "{{93, -122}, {907, 950}}"; + }; + }; + 7240B2831017A35C00522838 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7240B2841017A35C00522838 /* main.c */; + name = "main.c: 362"; + rLen = 4; + rLoc = 8843; + rType = 0; + vrLen = 751; + vrLoc = 8433; + }; + 7240B2841017A35C00522838 /* main.c */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + name = main.c; + path = /Users/johnc/dev/utils/tgaconv/main.c; + sourceTree = ""; + }; + 7240B28A1017A35C00522838 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7240B28B1017A35C00522838 /* main.c */; + name = "main.c: 362"; + rLen = 4; + rLoc = 8843; + rType = 0; + vrLen = 751; + vrLoc = 8433; + }; + 7240B28B1017A35C00522838 /* main.c */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + name = main.c; + path = /Users/johnc/dev/utils/tgaconv/main.c; + sourceTree = ""; + }; + 7240B29E1017A9B600522838 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8479B0F9400D700AB3C99 /* i_network.h */; + name = "i_network.h: 35"; + rLen = 0; + rLoc = 1440; + rType = 0; + vrLen = 775; + vrLoc = 1277; + }; + 7240B2B61017AB7A00522838 /* iphone_net.c:431 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A560E11004FAEE00F788A5 /* iphone_net.c */; + functionName = "ReportNetworkInterfaces()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 431; + location = doom; + modificationTime = 277182472.334545; + state = 2; + }; + 7240B2EC1017B17200522838 /* iphone_net.c:410 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A560E11004FAEE00F788A5 /* iphone_net.c */; + functionName = "ReportNetworkInterfaces()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 410; + location = doom; + modificationTime = 277182472.334766; + state = 2; + }; + 7240B2EE1017B17400522838 /* iphone_net.c:406 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A560E11004FAEE00F788A5 /* iphone_net.c */; + functionName = "ReportNetworkInterfaces()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 406; + location = doom; + modificationTime = 277182472.334993; + state = 2; + }; + 7240B2EF1017B18E00522838 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 724C5D880FC7AAC4000E4348 /* socket.h */; + name = "socket.h: 255"; + rLen = 7; + rLoc = 10033; + rType = 0; + vrLen = 1536; + vrLoc = 8955; + }; + 7240B2F61017B18E00522838 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7240B2F71017B18E00522838 /* if_var.h */; + name = "if_var.h: 63"; + rLen = 1; + rLoc = 3294; + rType = 0; + vrLen = 872; + vrLoc = 3078; + }; + 7240B2F71017B18E00522838 /* if_var.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = if_var.h; + path = /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.0.sdk/usr/include/net/if_var.h; + sourceTree = ""; + }; + 7240B30C1017B30000522838 /* iphone_net.c:403 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A560E11004FAEE00F788A5 /* iphone_net.c */; + functionName = "ReportNetworkInterfaces()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 403; + location = doom; + modificationTime = 277182472.335205; + state = 2; + }; + 7240B3111017B30800522838 /* if_var.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = if_var.h; + path = /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.0.sdk/usr/include/net/if_var.h; + sourceTree = ""; + }; + 7240B32A1017B71400522838 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7240B32B1017B71400522838 /* ifaddrs.h */; + name = "ifaddrs.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1369; + vrLoc = 0; + }; + 7240B32B1017B71400522838 /* ifaddrs.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = ifaddrs.h; + path = /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.2.1.sdk/usr/include/ifaddrs.h; + sourceTree = ""; + }; + 7240B3381017B71400522838 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7240B3391017B71400522838 /* ifaddrs.h */; + name = "ifaddrs.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1369; + vrLoc = 0; + }; + 7240B3391017B71400522838 /* ifaddrs.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = ifaddrs.h; + path = /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.2.1.sdk/usr/include/ifaddrs.h; + sourceTree = ""; + }; + 7240B33B1017B71400522838 /* ifaddrs.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = ifaddrs.h; + path = /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.0.sdk/usr/include/ifaddrs.h; + sourceTree = ""; + }; + 7240B3571017BD1B00522838 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7240B33B1017B71400522838 /* ifaddrs.h */; + name = "ifaddrs.h: 5"; + rLen = 0; + rLoc = 149; + rType = 0; + vrLen = 489; + vrLoc = 1278; + }; + 7240B36A1017BF1800522838 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7240B33B1017B71400522838 /* ifaddrs.h */; + name = "ifaddrs.h: 5"; + rLen = 0; + rLoc = 149; + rType = 0; + vrLen = 644; + vrLoc = 1278; + }; + 7240B36E1017BF1800522838 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72A560E11004FAEE00F788A5 /* iphone_net.c */; + name = "iphone_net.c: 363"; + rLen = 0; + rLoc = 11833; + rType = 0; + vrLen = 847; + vrLoc = 10720; + }; + 7240B39A1017C84300522838 /* iphone_net.c:582 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A560E11004FAEE00F788A5 /* iphone_net.c */; + functionName = "UDPSocket()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 582; + location = doom; + modificationTime = 277182472.335457; + state = 2; + }; + 7240B3AB1017C8D500522838 /* iphone_async.c:815 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43DD8391100295F70006E1DD /* iphone_async.c */; + functionName = "iphoneAsyncTic()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 815; + location = doom; + modificationTime = 277182472.335681; + state = 2; + }; + 7240B3AD1017C8EA00522838 /* iphone_async.c:807 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43DD8391100295F70006E1DD /* iphone_async.c */; + functionName = "iphoneAsyncTic()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 807; + location = doom; + modificationTime = 277182472.335899; + state = 2; + }; + 7240B3F91017DF4300522838 /* iphone_async.c:945 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43DD8391100295F70006E1DD /* iphone_async.c */; + functionName = "iphoneAsyncTic()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 945; + modificationTime = 277182472.336118; + state = 2; + }; + 7240B4121017F25A00522838 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7240B4131017F25A00522838 /* device_types.h */; + name = "device_types.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 742; + vrLoc = 3457; + }; + 7240B4131017F25A00522838 /* device_types.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = device_types.h; + path = /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.0.sdk/usr/include/device/device_types.h; + sourceTree = ""; + }; + 7240B4141017F25A00522838 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7240B4151017F25A00522838 /* in.h */; + name = "in.h: 496"; + rLen = 17; + rLoc = 20531; + rType = 0; + vrLen = 1141; + vrLoc = 20198; + }; + 7240B4151017F25A00522838 /* in.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = in.h; + path = /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.0.sdk/usr/include/netinet/in.h; + sourceTree = ""; + }; + 7240B4161017F25A00522838 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7240B4171017F25A00522838 /* ethernet.h */; + name = "ethernet.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 960; + vrLoc = 2721; + }; + 7240B4171017F25A00522838 /* ethernet.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = ethernet.h; + path = /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.0.sdk/usr/include/net/ethernet.h; + sourceTree = ""; + }; + 7240B4181017F25A00522838 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7240B4191017F25A00522838 /* if_dl.h */; + name = "if_dl.h: 6"; + rLen = 0; + rLoc = 168; + rType = 0; + vrLen = 860; + vrLoc = 4234; + }; + 7240B4191017F25A00522838 /* if_dl.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = if_dl.h; + path = /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.0.sdk/usr/include/net/if_dl.h; + sourceTree = ""; + }; + 7240B41A1017F25A00522838 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7240B41B1017F25A00522838 /* if_var.h */; + name = "if_var.h: 11"; + rLen = 0; + rLoc = 538; + rType = 0; + vrLen = 802; + vrLoc = 8602; + }; + 7240B41B1017F25A00522838 /* if_var.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = if_var.h; + path = /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.0.sdk/usr/include/net/if_var.h; + sourceTree = ""; + }; + 7240B41C1017F25A00522838 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7240B41D1017F25A00522838 /* if.h */; + name = "if.h: 104"; + rLen = 0; + rLoc = 4182; + rType = 0; + vrLen = 1266; + vrLoc = 4080; + }; + 7240B41D1017F25A00522838 /* if.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = if.h; + path = /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.0.sdk/usr/include/net/if.h; + sourceTree = ""; + }; + 7240B4201017F25A00522838 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7240B4211017F25A00522838 /* device_types.h */; + name = "device_types.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 742; + vrLoc = 3457; + }; + 7240B4211017F25A00522838 /* device_types.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = device_types.h; + path = /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.0.sdk/usr/include/device/device_types.h; + sourceTree = ""; + }; + 7240B4221017F25A00522838 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7240B4231017F25A00522838 /* in.h */; + name = "in.h: 496"; + rLen = 17; + rLoc = 20531; + rType = 0; + vrLen = 1141; + vrLoc = 20198; + }; + 7240B4231017F25A00522838 /* in.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = in.h; + path = /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.0.sdk/usr/include/netinet/in.h; + sourceTree = ""; + }; + 7240B4241017F25A00522838 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7240B4251017F25A00522838 /* ethernet.h */; + name = "ethernet.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 960; + vrLoc = 2721; + }; + 7240B4251017F25A00522838 /* ethernet.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = ethernet.h; + path = /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.0.sdk/usr/include/net/ethernet.h; + sourceTree = ""; + }; + 7240B4261017F25A00522838 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7240B4271017F25A00522838 /* if_dl.h */; + name = "if_dl.h: 6"; + rLen = 0; + rLoc = 168; + rType = 0; + vrLen = 860; + vrLoc = 4234; + }; + 7240B4271017F25A00522838 /* if_dl.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = if_dl.h; + path = /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.0.sdk/usr/include/net/if_dl.h; + sourceTree = ""; + }; + 7240B4281017F25A00522838 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7240B4291017F25A00522838 /* if_var.h */; + name = "if_var.h: 11"; + rLen = 0; + rLoc = 538; + rType = 0; + vrLen = 802; + vrLoc = 8602; + }; + 7240B4291017F25A00522838 /* if_var.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = if_var.h; + path = /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.0.sdk/usr/include/net/if_var.h; + sourceTree = ""; + }; + 7240B42A1017F25A00522838 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7240B42B1017F25A00522838 /* if.h */; + name = "if.h: 104"; + rLen = 0; + rLoc = 4182; + rType = 0; + vrLen = 1266; + vrLoc = 4080; + }; + 7240B42B1017F25A00522838 /* if.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = if.h; + path = /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.0.sdk/usr/include/net/if.h; + sourceTree = ""; + }; + 7240B4351017F48400522838 /* iphone_net.c:570 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A560E11004FAEE00F788A5 /* iphone_net.c */; + functionName = "UDPSocket()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 570; + location = doom; + modificationTime = 277182472.336342; + state = 2; + }; + 7240B4371017F49300522838 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7240B3111017B30800522838 /* if_var.h */; + name = "if_var.h: 149"; + rLen = 0; + rLoc = 5801; + rType = 0; + vrLen = 1525; + vrLoc = 6193; + }; + 7240B49610180AAA00522838 /* iphone_net.c:38 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A560E11004FAEE00F788A5 /* iphone_net.c */; + functionName = "NetworkServerTransport()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 38; + location = doom; + modificationTime = 277182472.33655; + state = 2; + }; + 72484DB00FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A945140F82D75900FFD32E /* iphone_sys.c */; + name = "iphone_sys.c: 71"; + rLen = 0; + rLoc = 936; + rType = 0; + vrLen = 0; + vrLoc = 1455; + }; + 72484DB70FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7229CE450F6C89F8004123C5 /* EAGLView.h */; + name = "EAGLView.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1184; + vrLoc = 0; + }; + 72484DB90FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 29B97316FDCFA39411CA2CEA /* main.m */; + name = "main.m: 31"; + rLen = 0; + rLoc = 941; + rType = 0; + vrLen = 865; + vrLoc = 531; + }; + 72484DBB0FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 434669A40F8D08C000EA7D6D /* doomAppDelegate.h */; + name = "doomAppDelegate.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1043; + vrLoc = 0; + }; + 72484DBC0FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 434669A30F8D08C000EA7D6D /* doom_Prefix.pch */; + name = "doom_Prefix.pch: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 173; + vrLoc = 0; + }; + 72484DBD0FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8495F0F942B9300AB3C99 /* misc.h */; + name = "misc.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 910; + vrLoc = 0; + }; + 72484DC20FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848460F941ADC00AB3C99 /* sounds.c */; + name = "sounds.c: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1438; + vrLoc = 0; + }; + 72484DC30FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848470F941ADC00AB3C99 /* sounds.h */; + name = "sounds.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1471; + vrLoc = 0; + }; + 72484DC60FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8484B0F941ADC00AB3C99 /* st_stuff.h */; + name = "st_stuff.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1431; + vrLoc = 0; + }; + 72484DC70FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8484C0F941ADC00AB3C99 /* tables.c */; + name = "tables.c: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1379; + vrLoc = 0; + }; + 72484DC80FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8484D0F941ADC00AB3C99 /* tables.h */; + name = "tables.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1379; + vrLoc = 0; + }; + 72484DCB0FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848500F941ADC00AB3C99 /* version.c */; + name = "version.c: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1379; + vrLoc = 0; + }; + 72484DCC0FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848510F941ADC00AB3C99 /* version.h */; + name = "version.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1392; + vrLoc = 0; + }; + 72484DCD0FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848530F941ADC00AB3C99 /* w_mmap.c */; + name = "w_mmap.c: 272"; + rLen = 0; + rLoc = 6859; + rType = 0; + vrLen = 891; + vrLoc = 6275; + }; + 72484DCF0FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848550F941ADC00AB3C99 /* w_wad.h */; + name = "w_wad.h: 118"; + rLen = 57; + rLoc = 3242; + rType = 0; + vrLen = 918; + vrLoc = 2721; + }; + 72484DD10FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848580F941ADC00AB3C99 /* z_bmalloc.c */; + name = "z_bmalloc.c: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1443; + vrLoc = 0; + }; + 72484DD20FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848590F941ADC00AB3C99 /* z_bmalloc.h */; + name = "z_bmalloc.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1469; + vrLoc = 0; + }; + 72484DD40FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8485B0F941ADC00AB3C99 /* z_zone.h */; + name = "z_zone.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1468; + vrLoc = 0; + }; + 72484DD50FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8482B0F941AAC00AB3C99 /* r_filter.h */; + name = "r_filter.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1383; + vrLoc = 0; + }; + 72484DDA0FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848310F941AAC00AB3C99 /* r_patch.h */; + name = "r_patch.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1381; + vrLoc = 0; + }; + 72484DDB0FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848320F941AAC00AB3C99 /* r_plane.c */; + name = "r_plane.c: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1462; + vrLoc = 0; + }; + 72484DDC0FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848330F941AAC00AB3C99 /* r_plane.h */; + name = "r_plane.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1414; + vrLoc = 0; + }; + 72484DDD0FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848340F941AAC00AB3C99 /* r_segs.c */; + name = "r_segs.c: 497"; + rLen = 26; + rLoc = 16588; + rType = 0; + vrLen = 938; + vrLoc = 15939; + }; + 72484DDE0FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848360F941AAC00AB3C99 /* r_sky.c */; + name = "r_sky.c: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1476; + vrLoc = 0; + }; + 72484DDF0FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848370F941AAC00AB3C99 /* r_sky.h */; + name = "r_sky.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1386; + vrLoc = 0; + }; + 72484DE20FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8483A0F941AAC00AB3C99 /* r_things.h */; + name = "r_things.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1409; + vrLoc = 0; + }; + 72484DE30FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8483C0F941AAC00AB3C99 /* s_sound.h */; + name = "s_sound.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1415; + vrLoc = 0; + }; + 72484DE40FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8481C0F941A8300AB3C99 /* protocol.h */; + name = "protocol.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1428; + vrLoc = 0; + }; + 72484DE50FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8481D0F941A8300AB3C99 /* r_bsp.c */; + name = "r_bsp.c: 393"; + rLen = 15; + rLoc = 12731; + rType = 0; + vrLen = 759; + vrLoc = 12246; + }; + 72484DE60FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8481E0F941A8300AB3C99 /* r_bsp.h */; + name = "r_bsp.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1415; + vrLoc = 0; + }; + 72484DEB0FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848230F941A8300AB3C99 /* r_demo.h */; + name = "r_demo.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1389; + vrLoc = 0; + }; + 72484DED0FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848250F941A8300AB3C99 /* r_draw.h */; + name = "r_draw.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1404; + vrLoc = 0; + }; + 72484DEE0FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847E00F941A5900AB3C99 /* md5.c */; + name = "md5.c: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1164; + vrLoc = 0; + }; + 72484DEF0FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847E10F941A5900AB3C99 /* md5.h */; + name = "md5.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1093; + vrLoc = 0; + }; + 72484DF00FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847E40F941A5900AB3C99 /* p_ceilng.c */; + name = "p_ceilng.c: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1417; + vrLoc = 0; + }; + 72484DF20FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847E60F941A5900AB3C99 /* p_checksum.h */; + name = "p_checksum.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 151; + vrLoc = 0; + }; + 72484DF30FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847E70F941A5900AB3C99 /* p_doors.c */; + name = "p_doors.c: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1406; + vrLoc = 0; + }; + 72484E080FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7229CE450F6C89F8004123C5 /* EAGLView.h */; + name = "EAGLView.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1184; + vrLoc = 0; + }; + 72484E0C0FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 434669A40F8D08C000EA7D6D /* doomAppDelegate.h */; + name = "doomAppDelegate.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1043; + vrLoc = 0; + }; + 72484E0D0FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 434669A30F8D08C000EA7D6D /* doom_Prefix.pch */; + name = "doom_Prefix.pch: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 173; + vrLoc = 0; + }; + 72484E0E0FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8495F0F942B9300AB3C99 /* misc.h */; + name = "misc.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 910; + vrLoc = 0; + }; + 72484E0F0FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8495E0F942B9300AB3C99 /* misc.c */; + name = "misc.c: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 528; + vrLoc = 0; + }; + 72484E100FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E84A280F9503F100AB3C99 /* cmd.c */; + name = "cmd.c: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 584; + vrLoc = 0; + }; + 72484E130FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848460F941ADC00AB3C99 /* sounds.c */; + name = "sounds.c: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1438; + vrLoc = 0; + }; + 72484E140FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848470F941ADC00AB3C99 /* sounds.h */; + name = "sounds.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1471; + vrLoc = 0; + }; + 72484E150FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848480F941ADC00AB3C99 /* st_lib.c */; + name = "st_lib.c: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1399; + vrLoc = 0; + }; + 72484E160FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848490F941ADC00AB3C99 /* st_lib.h */; + name = "st_lib.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1416; + vrLoc = 0; + }; + 72484E170FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8484B0F941ADC00AB3C99 /* st_stuff.h */; + name = "st_stuff.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1431; + vrLoc = 0; + }; + 72484E180FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8484C0F941ADC00AB3C99 /* tables.c */; + name = "tables.c: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1379; + vrLoc = 0; + }; + 72484E190FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8484D0F941ADC00AB3C99 /* tables.h */; + name = "tables.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1379; + vrLoc = 0; + }; + 72484E1C0FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848500F941ADC00AB3C99 /* version.c */; + name = "version.c: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1379; + vrLoc = 0; + }; + 72484E1D0FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848510F941ADC00AB3C99 /* version.h */; + name = "version.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1392; + vrLoc = 0; + }; + 72484E210FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848560F941ADC00AB3C99 /* wi_stuff.c */; + name = "wi_stuff.c: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1390; + vrLoc = 0; + }; + 72484E220FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848580F941ADC00AB3C99 /* z_bmalloc.c */; + name = "z_bmalloc.c: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1443; + vrLoc = 0; + }; + 72484E230FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848590F941ADC00AB3C99 /* z_bmalloc.h */; + name = "z_bmalloc.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1469; + vrLoc = 0; + }; + 72484E240FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8485A0F941ADC00AB3C99 /* z_zone.c */; + name = "z_zone.c: 340"; + rLen = 0; + rLoc = 8941; + rType = 0; + vrLen = 906; + vrLoc = 8527; + }; + 72484E250FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8485B0F941ADC00AB3C99 /* z_zone.h */; + name = "z_zone.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1468; + vrLoc = 0; + }; + 72484E260FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8482B0F941AAC00AB3C99 /* r_filter.h */; + name = "r_filter.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1383; + vrLoc = 0; + }; + 72484E270FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8482C0F941AAC00AB3C99 /* r_fps.c */; + name = "r_fps.c: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1403; + vrLoc = 0; + }; + 72484E280FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8482D0F941AAC00AB3C99 /* r_fps.h */; + name = "r_fps.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1403; + vrLoc = 0; + }; + 72484E2B0FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848310F941AAC00AB3C99 /* r_patch.h */; + name = "r_patch.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1381; + vrLoc = 0; + }; + 72484E2C0FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848320F941AAC00AB3C99 /* r_plane.c */; + name = "r_plane.c: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1462; + vrLoc = 0; + }; + 72484E2D0FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848330F941AAC00AB3C99 /* r_plane.h */; + name = "r_plane.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1414; + vrLoc = 0; + }; + 72484E2F0FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848360F941AAC00AB3C99 /* r_sky.c */; + name = "r_sky.c: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1476; + vrLoc = 0; + }; + 72484E300FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848370F941AAC00AB3C99 /* r_sky.h */; + name = "r_sky.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1386; + vrLoc = 0; + }; + 72484E310FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848380F941AAC00AB3C99 /* r_state.h */; + name = "r_state.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1421; + vrLoc = 0; + }; + 72484E330FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8483A0F941AAC00AB3C99 /* r_things.h */; + name = "r_things.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1409; + vrLoc = 0; + }; + 72484E340FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8483C0F941AAC00AB3C99 /* s_sound.h */; + name = "s_sound.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1415; + vrLoc = 0; + }; + 72484E350FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8481C0F941A8300AB3C99 /* protocol.h */; + name = "protocol.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1428; + vrLoc = 0; + }; + 72484E370FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8481E0F941A8300AB3C99 /* r_bsp.h */; + name = "r_bsp.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1415; + vrLoc = 0; + }; + 72484E390FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848200F941A8300AB3C99 /* r_data.h */; + name = "r_data.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1436; + vrLoc = 0; + }; + 72484E3B0FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848220F941A8300AB3C99 /* r_demo.c */; + name = "r_demo.c: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1389; + vrLoc = 0; + }; + 72484E3C0FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848230F941A8300AB3C99 /* r_demo.h */; + name = "r_demo.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1389; + vrLoc = 0; + }; + 72484E3D0FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848240F941A8300AB3C99 /* r_draw.c */; + name = "r_draw.c: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1438; + vrLoc = 0; + }; + 72484E3E0FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848250F941A8300AB3C99 /* r_draw.h */; + name = "r_draw.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1404; + vrLoc = 0; + }; + 72484E3F0FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847E00F941A5900AB3C99 /* md5.c */; + name = "md5.c: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1164; + vrLoc = 0; + }; + 72484E400FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847E10F941A5900AB3C99 /* md5.h */; + name = "md5.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1093; + vrLoc = 0; + }; + 72484E410FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847E40F941A5900AB3C99 /* p_ceilng.c */; + name = "p_ceilng.c: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1417; + vrLoc = 0; + }; + 72484E420FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847E50F941A5900AB3C99 /* p_checksum.c */; + name = "p_checksum.c: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 775; + vrLoc = 0; + }; + 72484E430FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847E60F941A5900AB3C99 /* p_checksum.h */; + name = "p_checksum.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 151; + vrLoc = 0; + }; + 72484E440FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847E70F941A5900AB3C99 /* p_doors.c */; + name = "p_doors.c: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1406; + vrLoc = 0; + }; + 72484E450FB0E95C00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847E80F941A5900AB3C99 /* p_enemy.c */; + name = "p_enemy.c: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1394; + vrLoc = 0; + }; + 72484E5D0FB0E99900124E1C /* iphone_render.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1099, 33231}}"; + sepNavSelRange = "{46271, 0}"; + sepNavVisRange = "{45803, 729}"; + sepNavWindowFrame = "{{456, 77}, {907, 950}}"; + }; + }; + 72484E8D0FB1F22E00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847E90F941A5900AB3C99 /* p_enemy.h */; + name = "p_enemy.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1389; + vrLoc = 0; + }; + 72484E900FB1F22E00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8482D0F941AAC00AB3C99 /* r_fps.h */; + name = "r_fps.h: 58"; + rLen = 8; + rLoc = 1772; + rType = 0; + vrLen = 351; + vrLoc = 1463; + }; + 72484E940FB1F22E00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8482F0F941AAC00AB3C99 /* r_main.h */; + name = "r_main.h: 115"; + rLen = 39; + rLoc = 3370; + rType = 0; + vrLen = 891; + vrLoc = 2895; + }; + 72484E980FB1F22E00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847E90F941A5900AB3C99 /* p_enemy.h */; + name = "p_enemy.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1389; + vrLoc = 0; + }; + 72484E990FB1F22E00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72484E5D0FB0E99900124E1C /* iphone_render.c */; + name = "iphoneRender.c: 603"; + rLen = 0; + rLoc = 50402; + rType = 0; + vrLen = 760; + vrLoc = 17305; + }; + 72484EA60FB1F22E00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847910F9400D700AB3C99 /* gl_intern.h */; + name = "gl_intern.h: 61"; + rLen = 0; + rLoc = 1848; + rType = 0; + vrLen = 484; + vrLoc = 1537; + }; + 72484EAA0FB1F22E00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8482F0F941AAC00AB3C99 /* r_main.h */; + name = "r_main.h: 115"; + rLen = 0; + rLoc = 3473; + rType = 0; + vrLen = 808; + vrLoc = 2946; + }; + 72484F5D0FB1F8DA00124E1C /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8482C0F941AAC00AB3C99 /* r_fps.c */; + name = "r_fps.c: 104"; + rLen = 0; + rLoc = 3100; + rType = 0; + vrLen = 1096; + vrLoc = 2379; + }; + 724C531E0FBDBCEE000E4348 /* BackgroundMusic.cpp */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1092, 10773}}"; + sepNavSelRange = "{16673, 15}"; + sepNavVisRange = "{16120, 654}"; + sepNavWindowFrame = "{{123, 31}, {907, 950}}"; + }; + }; + 724C53220FBDBD31000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 724C53230FBDBD31000E4348 /* SoundEngine.h */; + name = "SoundEngine.h: 5"; + rLen = 6; + rLoc = 116; + rType = 0; + vrLen = 1936; + vrLoc = 0; + }; + 724C53230FBDBD31000E4348 /* SoundEngine.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = SoundEngine.h; + path = /Users/johnc/dev/iphone/doom/code/iphone/SoundEngine.h; + sourceTree = ""; + }; + 724C532A0FBDBD31000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 724C532B0FBDBD31000E4348 /* SoundEngine.h */; + name = "SoundEngine.h: 5"; + rLen = 6; + rLoc = 116; + rType = 0; + vrLen = 1936; + vrLoc = 0; + }; + 724C532B0FBDBD31000E4348 /* SoundEngine.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = SoundEngine.h; + path = /Users/johnc/dev/iphone/doom/code/iphone/SoundEngine.h; + sourceTree = ""; + }; + 724C532F0FBDBD31000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 724C531E0FBDBCEE000E4348 /* BackgroundMusic.cpp */; + name = "BackgroundMusic.cpp: 11"; + rLen = 0; + rLoc = 16492; + rType = 0; + vrLen = 141; + vrLoc = 0; + }; + 724C536A0FBDC094000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 724C536B0FBDC094000E4348 /* stl_vector.h */; + name = "stl_vector.h: 604"; + rLen = 0; + rLoc = 20815; + rType = 0; + vrLen = 1083; + vrLoc = 11957; + }; + 724C536B0FBDC094000E4348 /* stl_vector.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = stl_vector.h; + path = "/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.0.sdk/usr/include/c++/4.0.0/bits/stl_vector.h"; + sourceTree = ""; + }; + 724C536C0FBDC094000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 724C536D0FBDC094000E4348 /* stl_iterator.h */; + name = "stl_iterator.h: 603"; + rLen = 0; + rLoc = 19181; + rType = 0; + vrLen = 1136; + vrLoc = 18585; + }; + 724C536D0FBDC094000E4348 /* stl_iterator.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = stl_iterator.h; + path = "/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.0.sdk/usr/include/c++/4.0.0/bits/stl_iterator.h"; + sourceTree = ""; + }; + 724C53740FBDC094000E4348 /* stl_iterator.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = stl_iterator.h; + path = "/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.0.sdk/usr/include/c++/4.0.0/bits/stl_iterator.h"; + sourceTree = ""; + }; + 724C53760FBDC094000E4348 /* stl_vector.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = stl_vector.h; + path = "/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.0.sdk/usr/include/c++/4.0.0/bits/stl_vector.h"; + sourceTree = ""; + }; + 724C53AB0FBDC6B6000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 724C53AC0FBDC6B6000E4348 /* stl_algobase.h */; + name = "stl_algobase.h: 354"; + rLen = 0; + rLoc = 11553; + rType = 0; + vrLen = 1147; + vrLoc = 12390; + }; + 724C53AC0FBDC6B6000E4348 /* stl_algobase.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = stl_algobase.h; + path = "/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.0.sdk/usr/include/c++/4.0.0/bits/stl_algobase.h"; + sourceTree = ""; + }; + 724C53AD0FBDC6B6000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 724C53AE0FBDC6B6000E4348 /* vector.tcc */; + name = "vector.tcc: 125"; + rLen = 0; + rLoc = 4580; + rType = 0; + vrLen = 1069; + vrLoc = 4007; + }; + 724C53AE0FBDC6B6000E4348 /* vector.tcc */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + name = vector.tcc; + path = "/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.0.sdk/usr/include/c++/4.0.0/bits/vector.tcc"; + sourceTree = ""; + }; + 724C53AF0FBDC6B6000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 724C53B00FBDC6B6000E4348 /* allocator.h */; + name = "allocator.h: 100"; + rLen = 0; + rLoc = 3412; + rType = 0; + vrLen = 928; + vrLoc = 2869; + }; + 724C53B00FBDC6B6000E4348 /* allocator.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = allocator.h; + path = "/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.0.sdk/usr/include/c++/4.0.0/bits/allocator.h"; + sourceTree = ""; + }; + 724C53B20FBDC6B6000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 724C53B30FBDC6B6000E4348 /* stl_construct.h */; + name = "stl_construct.h: 174"; + rLen = 0; + rLoc = 5768; + rType = 0; + vrLen = 1018; + vrLoc = 5006; + }; + 724C53B30FBDC6B6000E4348 /* stl_construct.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = stl_construct.h; + path = "/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.0.sdk/usr/include/c++/4.0.0/bits/stl_construct.h"; + sourceTree = ""; + }; + 724C53B40FBDC6B6000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 724C53740FBDC094000E4348 /* stl_iterator.h */; + name = "stl_iterator.h: 614"; + rLen = 0; + rLoc = 19531; + rType = 0; + vrLen = 1022; + vrLoc = 18746; + }; + 724C53CD0FBDC6B6000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 724C53CE0FBDC6B6000E4348 /* vector.tcc */; + name = "vector.tcc: 124"; + rLen = 0; + rLoc = 4525; + rType = 0; + vrLen = 1069; + vrLoc = 4007; + }; + 724C53CE0FBDC6B6000E4348 /* vector.tcc */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + name = vector.tcc; + path = "/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.0.sdk/usr/include/c++/4.0.0/bits/vector.tcc"; + sourceTree = ""; + }; + 724C53D20FBDC6B6000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 724C53D30FBDC6B6000E4348 /* stl_algobase.h */; + name = "stl_algobase.h: 384"; + rLen = 0; + rLoc = 12773; + rType = 0; + vrLen = 1240; + vrLoc = 11056; + }; + 724C53D30FBDC6B6000E4348 /* stl_algobase.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = stl_algobase.h; + path = "/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.0.sdk/usr/include/c++/4.0.0/bits/stl_algobase.h"; + sourceTree = ""; + }; + 724C53E50FBDC6B6000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 724C53E60FBDC6B6000E4348 /* allocator.h */; + name = "allocator.h: 100"; + rLen = 0; + rLoc = 3412; + rType = 0; + vrLen = 928; + vrLoc = 2869; + }; + 724C53E60FBDC6B6000E4348 /* allocator.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = allocator.h; + path = "/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.0.sdk/usr/include/c++/4.0.0/bits/allocator.h"; + sourceTree = ""; + }; + 724C53E70FBDC6B6000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 724C53E80FBDC6B6000E4348 /* new_allocator.h */; + name = "new_allocator.h: 67"; + rLen = 0; + rLoc = 2377; + rType = 0; + vrLen = 981; + vrLoc = 1851; + }; + 724C53E80FBDC6B6000E4348 /* new_allocator.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = new_allocator.h; + path = "/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.0.sdk/usr/include/c++/4.0.0/ext/new_allocator.h"; + sourceTree = ""; + }; + 724C53EC0FBDC6B6000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 724C53ED0FBDC6B6000E4348 /* stl_construct.h */; + name = "stl_construct.h: 173"; + rLen = 0; + rLoc = 5725; + rType = 0; + vrLen = 953; + vrLoc = 5075; + }; + 724C53ED0FBDC6B6000E4348 /* stl_construct.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = stl_construct.h; + path = "/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.0.sdk/usr/include/c++/4.0.0/bits/stl_construct.h"; + sourceTree = ""; + }; + 724C53F30FBDC6B6000E4348 /* new_allocator.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = new_allocator.h; + path = "/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.0.sdk/usr/include/c++/4.0.0/ext/new_allocator.h"; + sourceTree = ""; + }; + 724C54190FBDC908000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 724C53F30FBDC6B6000E4348 /* new_allocator.h */; + name = "new_allocator.h: 107"; + rLen = 0; + rLoc = 3499; + rType = 0; + vrLen = 864; + vrLoc = 2986; + }; + 724C54B70FBDEB53000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847AC0F9400D700AB3C99 /* m_misc.c */; + name = "m_misc.c: 772"; + rLen = 6; + rLoc = 38172; + rType = 0; + vrLen = 1351; + vrLoc = 37503; + }; + 724C55470FBDF916000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847F30F941A5900AB3C99 /* p_mobj.c */; + name = "p_mobj.c: 1500"; + rLen = 15; + rLoc = 40259; + rType = 0; + vrLen = 808; + vrLoc = 39741; + }; + 724C55FB0FBE0A75000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 724C53760FBDC094000E4348 /* stl_vector.h */; + name = "stl_vector.h: 403"; + rLen = 0; + rLoc = 14113; + rType = 0; + vrLen = 985; + vrLoc = 13640; + }; + 724C565B0FBE1019000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847680F93FF2F00AB3C99 /* config.h */; + name = "config.h: 29"; + rLen = 11; + rLoc = 691; + rType = 0; + vrLen = 683; + vrLoc = 0; + }; + 724C565E0FBE1019000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847680F93FF2F00AB3C99 /* config.h */; + name = "config.h: 29"; + rLen = 11; + rLoc = 691; + rType = 0; + vrLen = 683; + vrLoc = 0; + }; + 724C56670FBE6194000E4348 /* BackgroundMusic.cpp:503 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 724C531E0FBDBCEE000E4348 /* BackgroundMusic.cpp */; + functionName = "iphonePlayMusic( const char *name )"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 503; + location = doom; + modificationTime = 277182472.287683; + state = 2; + }; + 724C567A0FBE6314000E4348 /* g_game.c:632 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E8478F0F9400D700AB3C99 /* g_game.c */; + functionName = "G_DoLoadLevel()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 632; + location = doom; + modificationTime = 277182472.287994; + state = 2; + }; + 724C56B30FBE6AE0000E4348 /* BackgroundMusic.cpp:285 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 724C531E0FBDBCEE000E4348 /* BackgroundMusic.cpp */; + functionName = "BackgroundTrackMgr::QueueCallback( void * inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inCompleteAQBuffer )"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 285; + location = doom; + modificationTime = 277182472.288079; + state = 2; + }; + 724C56C00FBE6B54000E4348 /* BackgroundMusic.cpp:251 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 724C531E0FBDBCEE000E4348 /* BackgroundMusic.cpp */; + functionName = "BackgroundTrackMgr::QueueCallback( void * inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inCompleteAQBuffer )"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 251; + location = doom; + modificationTime = 277182472.288191; + state = 2; + }; + 724C56D80FBE6C7D000E4348 /* BackgroundMusic.cpp:503 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 724C531E0FBDBCEE000E4348 /* BackgroundMusic.cpp */; + functionName = "iphonePlayMusic( const char *name )"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 503; + location = doom; + modificationTime = 277182472.288297; + state = 2; + }; + 724C57210FC18C12000E4348 /* BackgroundMusic.cpp:344 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 724C531E0FBDBCEE000E4348 /* BackgroundMusic.cpp */; + functionName = "BackgroundTrackMgr::SetupBuffers(BG_FileInfo *inFileInfo)"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 344; + location = doom; + modificationTime = 277182472.288407; + state = 2; + }; + 724C57290FC18C90000E4348 /* BackgroundMusic.cpp:355 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 724C531E0FBDBCEE000E4348 /* BackgroundMusic.cpp */; + functionName = "BackgroundTrackMgr::SetupBuffers(BG_FileInfo *inFileInfo)"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 355; + location = doom; + modificationTime = 277182472.288511; + state = 2; + }; + 724C57390FC18DAC000E4348 /* BackgroundMusic.cpp:312 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 724C531E0FBDBCEE000E4348 /* BackgroundMusic.cpp */; + functionName = "BackgroundTrackMgr::SetupQueue(BG_FileInfo *inFileInfo)"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 312; + location = doom; + modificationTime = 277182472.288618; + state = 2; + }; + 724C573B0FC18E01000E4348 /* BackgroundMusic.cpp:249 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 724C531E0FBDBCEE000E4348 /* BackgroundMusic.cpp */; + functionName = "BackgroundTrackMgr::AttachNewCookie(AudioQueueRef inQueue, BG_FileInfo *inFileInfo)"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 249; + location = doom; + modificationTime = 277182472.288726; + state = 2; + }; + 724C574A0FC18F72000E4348 /* BackgroundMusic.cpp:250 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 724C531E0FBDBCEE000E4348 /* BackgroundMusic.cpp */; + functionName = "BackgroundTrackMgr::QueueStoppedProc( void * inUserData, AudioQueueRef inAQ, AudioQueuePropertyID inID )"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 250; + location = doom; + modificationTime = 277182472.288838; + state = 2; + }; + 724C57520FC193AD000E4348 /* BackgroundMusic.cpp:376 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 724C531E0FBDBCEE000E4348 /* BackgroundMusic.cpp */; + functionName = "BackgroundTrackMgr::SetupBuffers(BG_FileInfo *inFileInfo)"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 376; + location = doom; + modificationTime = 277182472.288944; + state = 2; + }; + 724C57670FC1AD29000E4348 /* arialGlyphRects.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = arialGlyphRects.h; + path = /Users/johnc/dev/iphone/doom/code/iphone/arialGlyphRects.h; + sourceTree = ""; + }; + 724C576D0FC1B041000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 724C57670FC1AD29000E4348 /* arialGlyphRects.h */; + name = "arialGlyphRects.h: 8"; + rLen = 2; + rLoc = 291; + rType = 0; + vrLen = 2061; + vrLoc = 0; + }; + 724C576F0FC1B041000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 724C57670FC1AD29000E4348 /* arialGlyphRects.h */; + name = "arialGlyphRects.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 2061; + vrLoc = 0; + }; + 724C57F60FC1B36B000E4348 /* iphone_main.c:237 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43E8D2DF0F4FC61E003F09B2 /* iphone_main.c */; + functionName = "iphoneStartup()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 237; + location = doom; + modificationTime = 277182472.28905; + state = 2; + }; + 724C58020FC1B3D6000E4348 /* iphone_loop.c:66 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneDrawText()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 66; + location = doom; + modificationTime = 277182472.2892; + state = 2; + }; + 724C58110FC1B5B4000E4348 /* iphone_loop.c:66 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneDrawText()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 66; + location = doom; + modificationTime = 277182472.289282; + state = 2; + }; + 724C58300FC1C408000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72D50DBA0F8ED98000BB49E6 /* ipak.h */; + name = "ipak.h: 61"; + rLen = 0; + rLoc = 1822; + rType = 0; + vrLen = 837; + vrLoc = 1358; + }; + 724C58470FC1C649000E4348 /* iphone_loop.c:66 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneDrawText()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 66; + location = doom; + modificationTime = 277182472.289361; + state = 2; + }; + 724C58710FC1CD56000E4348 /* r_things.c:260 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E848390F941AAC00AB3C99 /* r_things.c */; + functionName = "R_InitSpriteDefs()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 260; + location = doom; + modificationTime = 277182472.289441; + state = 2; + }; + 724C587C0FC1CDC1000E4348 /* r_things.c:174 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E848390F941AAC00AB3C99 /* r_things.c */; + functionName = "R_InitSpriteDefs()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 174; + location = doom; + modificationTime = 277182472.289526; + state = 2; + }; + 724C58AB0FC1D0E6000E4348 /* BackgroundMusic.cpp:252 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 724C531E0FBDBCEE000E4348 /* BackgroundMusic.cpp */; + functionName = "BackgroundTrackMgr::QueueCallback( void * inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inCompleteAQBuffer )"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 252; + location = doom; + modificationTime = 277182472.28969; + state = 2; + }; + 724C58B10FC1D13D000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848390F941AAC00AB3C99 /* r_things.c */; + name = "r_things.c: 174"; + rLen = 0; + rLoc = 5083; + rType = 0; + vrLen = 932; + vrLoc = 4731; + }; + 724C58CB0FC1D2E1000E4348 /* BackgroundMusic.cpp:502 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 724C531E0FBDBCEE000E4348 /* BackgroundMusic.cpp */; + functionName = "iphonePlayMusic( const char *name )"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 502; + location = doom; + modificationTime = 277182472.289804; + state = 2; + }; + 724C58D70FC1D555000E4348 /* iphone_loop.c:66 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneBuildTiccmd()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 66; + location = doom; + modificationTime = 277182472.289926; + state = 2; + }; + 724C58D90FC1D563000E4348 /* iphone_loop.c:66 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneBuildTiccmd()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 66; + location = doom; + modificationTime = 277182472.290014; + state = 2; + }; + 724C58F10FC1D925000E4348 /* EAGLView.m:212 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 7229CE460F6C89F8004123C5 /* EAGLView.m */; + functionName = "-handleTouches:"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 212; + location = doom; + modificationTime = 277182472.290097; + state = 2; + }; + 724C59250FC1E488000E4348 /* BackgroundMusic.cpp:487 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 724C531E0FBDBCEE000E4348 /* BackgroundMusic.cpp */; + functionName = "iphoneStartMusic()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 487; + location = doom; + modificationTime = 277182472.290179; + state = 2; + }; + 724C59330FC1E4DF000E4348 /* BackgroundMusic.cpp:496 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 724C531E0FBDBCEE000E4348 /* BackgroundMusic.cpp */; + functionName = "iphoneStartMusic()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 496; + location = doom; + modificationTime = 277182472.290288; + state = 2; + }; + 724C59350FC1E4E1000E4348 /* BackgroundMusic.cpp:497 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 724C531E0FBDBCEE000E4348 /* BackgroundMusic.cpp */; + functionName = "iphoneStartMusic()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 497; + location = doom; + modificationTime = 277182472.290405; + state = 2; + }; + 724C595E0FC20D2A000E4348 /* BackgroundMusic.cpp:483 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 724C531E0FBDBCEE000E4348 /* BackgroundMusic.cpp */; + functionName = "iphoneStartMusic()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 483; + location = doom; + modificationTime = 277182472.29052; + state = 2; + }; + 724C59710FC20DC9000E4348 /* EAGLView.m:206 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 7229CE460F6C89F8004123C5 /* EAGLView.m */; + functionName = "-handleTouches:"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 206; + location = doom; + modificationTime = 277182472.290634; + state = 2; + }; + 724C59730FC20DD2000E4348 /* EAGLView.m:204 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 7229CE460F6C89F8004123C5 /* EAGLView.m */; + functionName = "-handleTouches:"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 204; + location = doom; + modificationTime = 277182472.290721; + state = 2; + }; + 724C59820FC20EA4000E4348 /* EAGLView.m:149 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 7229CE460F6C89F8004123C5 /* EAGLView.m */; + functionName = "-handleTouches:"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 149; + location = doom; + modificationTime = 277182472.29081; + state = 2; + }; + 724C59870FC20F72000E4348 /* iphone_loop.c:66 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneFrame()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 66; + location = doom; + modificationTime = 277182472.290898; + state = 2; + }; + 724C59A40FC211A2000E4348 /* EAGLView.m:128 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 7229CE460F6C89F8004123C5 /* EAGLView.m */; + functionName = "-handleTouches:"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 128; + location = doom; + modificationTime = 277182472.290983; + state = 2; + }; + 724C59BD0FC2132D000E4348 /* EAGLView.m:127 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 7229CE460F6C89F8004123C5 /* EAGLView.m */; + functionName = "-handleTouches:"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 127; + location = doom; + modificationTime = 277182472.291071; + state = 2; + }; + 724C59F60FC2145D000E4348 /* EAGLView.m:171 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 7229CE460F6C89F8004123C5 /* EAGLView.m */; + functionName = "-handleTouches:"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 171; + location = doom; + modificationTime = 277182472.291157; + state = 2; + }; + 724C59F90FC214B5000E4348 /* EAGLView.m:169 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 7229CE460F6C89F8004123C5 /* EAGLView.m */; + functionName = "-handleTouches:"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 169; + location = doom; + modificationTime = 277182472.291248; + state = 2; + }; + 724C5A0B0FC2169B000E4348 /* EAGLView.m:175 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 7229CE460F6C89F8004123C5 /* EAGLView.m */; + functionName = "-handleTouches:"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 175; + location = doom; + modificationTime = 277182472.291338; + state = 2; + }; + 724C5A1D0FC21A02000E4348 /* EAGLView.m:122 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 7229CE460F6C89F8004123C5 /* EAGLView.m */; + functionName = "-handleTouches:"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 122; + location = doom; + modificationTime = 277182472.291426; + state = 2; + }; + 724C5A340FC21A79000E4348 /* iphone_loop.c:66 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneFrame()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 66; + location = doom; + modificationTime = 277182472.291514; + state = 2; + }; + 724C5A9B0FC21CFA000E4348 /* iphone_loop.c:66 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "UpdateHudTouch()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 66; + location = doom; + modificationTime = 277182472.291606; + state = 2; + }; + 724C5A9F0FC21D09000E4348 /* iphone_loop.c:66 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "UpdateHudTouch()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 66; + location = doom; + modificationTime = 277182472.291698; + state = 2; + }; + 724C5AE30FC229F4000E4348 /* iphone_render.c:350 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72484E5D0FB0E99900124E1C /* iphone_render.c */; + functionName = "IR_ProjectSprite()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 350; + location = doom; + modificationTime = 277182472.291795; + state = 2; + }; + 724C5AFC0FC2536D000E4348 /* iphone_render.c:1466 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72484E5D0FB0E99900124E1C /* iphone_render.c */; + functionName = "NewDrawScene()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1466; + location = doom; + modificationTime = 277182472.291892; + state = 2; + }; + 724C5B100FC2548C000E4348 /* iphone_render.c:1466 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72484E5D0FB0E99900124E1C /* iphone_render.c */; + functionName = "NewDrawScene()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1466; + location = doom; + modificationTime = 277182472.291996; + state = 2; + }; + 724C5B1D0FC254C9000E4348 /* iphone_render.c:216 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72484E5D0FB0E99900124E1C /* iphone_render.c */; + functionName = "FadedLighting()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 216; + location = doom; + modificationTime = 277182472.292093; + state = 2; + }; + 724C5B200FC254E2000E4348 /* iphone_render.c:216 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72484E5D0FB0E99900124E1C /* iphone_render.c */; + functionName = "FadedLighting()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 216; + location = doom; + modificationTime = 277182472.292184; + state = 2; + }; + 724C5B220FC255B5000E4348 /* iphone_render.c:216 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72484E5D0FB0E99900124E1C /* iphone_render.c */; + functionName = "FadedLighting()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 216; + location = doom; + modificationTime = 277182472.292275; + state = 2; + }; + 724C5B280FC25893000E4348 /* iphone_render.c:1447 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72484E5D0FB0E99900124E1C /* iphone_render.c */; + functionName = "NewDrawScene()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1447; + location = doom; + modificationTime = 277182472.292371; + state = 2; + }; + 724C5B2D0FC259C3000E4348 /* iphone_render.c:216 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72484E5D0FB0E99900124E1C /* iphone_render.c */; + functionName = "FadedLighting()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 216; + location = doom; + modificationTime = 277182472.292465; + state = 2; + }; + 724C5B6C0FC2D000000E4348 /* iphone_render.c:886 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72484E5D0FB0E99900124E1C /* iphone_render.c */; + functionName = "IR_Subsector()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 886; + location = doom; + modificationTime = 277182472.292558; + state = 2; + }; + 724C5B750FC2D12F000E4348 /* iphone_render.c:1733 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72484E5D0FB0E99900124E1C /* iphone_render.c */; + functionName = "IR_RenderPlayerView()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1733; + location = doom; + modificationTime = 277182472.292651; + state = 2; + }; + 724C5B770FC2D141000E4348 /* iphone_render.c:1729 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72484E5D0FB0E99900124E1C /* iphone_render.c */; + functionName = "IR_RenderPlayerView()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1729; + location = doom; + modificationTime = 277182472.292748; + state = 2; + }; + 724C5B7C0FC2D161000E4348 /* iphone_render.c:1735 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72484E5D0FB0E99900124E1C /* iphone_render.c */; + functionName = "IR_RenderPlayerView()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1735; + location = doom; + modificationTime = 277182472.292843; + state = 2; + }; + 724C5B890FC2D261000E4348 /* iphone_render.c:1451 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72484E5D0FB0E99900124E1C /* iphone_render.c */; + functionName = "NewDrawScene()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1451; + location = doom; + modificationTime = 277182472.292937; + state = 2; + }; + 724C5B990FC2D7DF000E4348 /* iphone_loop.c:1641 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneDrawScreen()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1641; + location = doom; + modificationTime = 277182472.293032; + state = 2; + }; + 724C5B9E0FC2D818000E4348 /* iphone_loop.c:1559 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneDrawScreen()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1559; + location = doom; + modificationTime = 277182472.293127; + state = 2; + }; + 724C5BE90FC47EFB000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847870F9400D700AB3C99 /* doomstat.h */; + name = "doomstat.h: 145"; + rLen = 0; + rLoc = 4390; + rType = 0; + vrLen = 869; + vrLoc = 4093; + }; + 724C5BEF0FC47F0E000E4348 /* g_game.c:850 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E8478F0F9400D700AB3C99 /* g_game.c */; + functionName = "G_Ticker()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 850; + location = doom; + modificationTime = 277182472.293226; + state = 2; + }; + 724C5BFE0FC48768000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847A80F9400D700AB3C99 /* m_cheat.h */; + name = "m_cheat.h: 49"; + rLen = 4; + rLoc = 1701; + rType = 0; + vrLen = 554; + vrLoc = 1277; + }; + 724C5C030FC48768000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847AA0F9400D700AB3C99 /* m_menu.c */; + name = "m_menu.c: 3238"; + rLen = 4; + rLoc = 86478; + rType = 0; + vrLen = 1085; + vrLoc = 86098; + }; + 724C5C110FC48768000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847A80F9400D700AB3C99 /* m_cheat.h */; + name = "m_cheat.h: 49"; + rLen = 4; + rLoc = 1701; + rType = 0; + vrLen = 554; + vrLoc = 1277; + }; + 724C5C4B0FC48C2D000E4348 /* st_stuff.c:857 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E8484A0F941ADC00AB3C99 /* st_stuff.c */; + functionName = "ST_Drawer()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 857; + location = doom; + modificationTime = 277182472.293325; + state = 2; + }; + 724C5C8F0FC48DE7000E4348 /* p_user.c:300 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E848030F941A5900AB3C99 /* p_user.c */; + functionName = "P_DeathThink()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 300; + location = doom; + modificationTime = 277182472.293421; + state = 2; + }; + 724C5C9E0FC48E9D000E4348 /* p_mobj.c:1059 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E847F30F941A5900AB3C99 /* p_mobj.c */; + functionName = "P_SpawnPlayer()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1059; + location = doom; + modificationTime = 277182472.293522; + state = 2; + }; + 724C5CA00FC48EB7000E4348 /* g_game.c:773 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E8478F0F9400D700AB3C99 /* g_game.c */; + functionName = "G_Ticker()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 773; + location = doom; + modificationTime = 277182472.293621; + state = 2; + }; + 724C5CA20FC48EBF000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848220F941A8300AB3C99 /* r_demo.c */; + name = "r_demo.c: 49"; + rLen = 0; + rLoc = 1728; + rType = 0; + vrLen = 762; + vrLoc = 1515; + }; + 724C5CC80FC4909E000E4348 /* p_spec.c:2328 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E847FD0F941A5900AB3C99 /* p_spec.c */; + functionName = "P_UpdateSpecials()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 2328; + location = doom; + modificationTime = 277182472.293723; + state = 2; + }; + 724C5CCE0FC490AE000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848030F941A5900AB3C99 /* p_user.c */; + name = "p_user.c: 300"; + rLen = 0; + rLoc = 8199; + rType = 0; + vrLen = 498; + vrLoc = 7851; + }; + 724C5D240FC5D5AA000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847970F9400D700AB3C99 /* hu_stuff.c */; + name = "hu_stuff.c: 742"; + rLen = 13; + rLoc = 20829; + rType = 0; + vrLen = 708; + vrLoc = 20534; + }; + 724C5D250FC5D5AA000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847F40F941A5900AB3C99 /* p_mobj.h */; + name = "p_mobj.h: 200"; + rLen = 12; + rLoc = 7877; + rType = 0; + vrLen = 1028; + vrLoc = 7319; + }; + 724C5D260FC5D5AA000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8484A0F941ADC00AB3C99 /* st_stuff.c */; + name = "st_stuff.c: 402"; + rLen = 1; + rLoc = 12234; + rType = 0; + vrLen = 839; + vrLoc = 11763; + }; + 724C5D270FC5D5AA000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8484F0F941ADC00AB3C99 /* v_video.h */; + name = "v_video.h: 71"; + rLen = 9; + rLoc = 2189; + rType = 0; + vrLen = 665; + vrLoc = 1789; + }; + 724C5D380FC5D5AA000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847F40F941A5900AB3C99 /* p_mobj.h */; + name = "p_mobj.h: 200"; + rLen = 12; + rLoc = 7877; + rType = 0; + vrLen = 1028; + vrLoc = 7319; + }; + 724C5D760FC7AAC4000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8495D0F942B9300AB3C99 /* cvar.h */; + name = "cvar.h: 87"; + rLen = 0; + rLoc = 2181; + rType = 0; + vrLen = 821; + vrLoc = 2159; + }; + 724C5D870FC7AAC4000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 724C5D880FC7AAC4000E4348 /* socket.h */; + name = "socket.h: 229"; + rLen = 0; + rLoc = 8929; + rType = 0; + vrLen = 1485; + vrLoc = 8715; + }; + 724C5D880FC7AAC4000E4348 /* socket.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = socket.h; + path = /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.0.sdk/usr/include/sys/socket.h; + sourceTree = ""; + }; + 724C5D960FC7AB77000E4348 /* iphone_main.c:237 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43E8D2DF0F4FC61E003F09B2 /* iphone_main.c */; + functionName = "iphoneStartup()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 237; + location = doom; + modificationTime = 277182472.293823; + state = 2; + }; + 724C5DE80FC7B5AF000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 724C5DE90FC7B5AF000E4348 /* types.h */; + name = "types.h: 126"; + rLen = 68; + rLoc = 4791; + rType = 0; + vrLen = 803; + vrLoc = 4458; + }; + 724C5DE90FC7B5AF000E4348 /* types.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = types.h; + path = /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.0.sdk/usr/include/sys/types.h; + sourceTree = ""; + }; + 724C5DEF0FC7B5AF000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 724C5DF00FC7B5AF000E4348 /* in.h */; + name = "in.h: 72"; + rLen = 0; + rLoc = 3538; + rType = 0; + vrLen = 1297; + vrLoc = 2626; + }; + 724C5DF00FC7B5AF000E4348 /* in.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = in.h; + path = /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.0.sdk/usr/include/netinet/in.h; + sourceTree = ""; + }; + 724C5DF40FC7B5AF000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 724C5DF50FC7B5AF000E4348 /* types.h */; + name = "types.h: 126"; + rLen = 68; + rLoc = 4791; + rType = 0; + vrLen = 803; + vrLoc = 4458; + }; + 724C5DF50FC7B5AF000E4348 /* types.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = types.h; + path = /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.0.sdk/usr/include/sys/types.h; + sourceTree = ""; + }; + 724C5E150FC7B910000E4348 /* iphone_loop.c:66 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneFrame()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 66; + location = doom; + modificationTime = 277182472.29398; + state = 2; + }; + 724C5E170FC7B91B000E4348 /* iphone_loop.c:66 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneFrame()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 66; + location = doom; + modificationTime = 277182472.294084; + state = 2; + }; + 724C5E210FC7B9D6000E4348 /* iphone_loop.c:66 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneFrame()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 66; + location = doom; + modificationTime = 277182472.294188; + state = 2; + }; + 724C5E2C0FC7BA6F000E4348 /* iphone_loop.c:66 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneFrame()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 66; + location = doom; + modificationTime = 277182472.294289; + state = 2; + }; + 724C5E2E0FC7BA76000E4348 /* iphone_loop.c:66 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneFrame()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 66; + location = doom; + modificationTime = 277182472.29439; + state = 2; + }; + 724C5E340FC7BE09000E4348 /* iphone_loop.c:66 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneFrame()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 66; + location = doom; + modificationTime = 277182472.294491; + state = 2; + }; + 724C5E670FC7C28C000E4348 /* iphone_loop.c:1509 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneFrame()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1509; + location = doom; + modificationTime = 277182472.294596; + state = 2; + }; + 724C5E8B0FC9A14A000E4348 /* iphone_loop.c:66 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneFrame()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 66; + location = doom; + modificationTime = 277182472.294702; + state = 2; + }; + 724C5E9F0FC9A2BB000E4348 /* gl_texture.c:1010 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E847940F9400D700AB3C99 /* gl_texture.c */; + functionName = "gld_Precache()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1010; + location = doom; + modificationTime = 277182472.294805; + state = 2; + }; + 724C5EAE0FC9A3A8000E4348 /* gl_texture.c:1061 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E847940F9400D700AB3C99 /* gl_texture.c */; + functionName = "gld_Precache()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1061; + location = doom; + modificationTime = 277182472.294911; + state = 2; + }; + 724C5ED70FC9A4A5000E4348 /* gl_texture.c:183 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E847940F9400D700AB3C99 /* gl_texture.c */; + functionName = "gld_AddNewGLPatchTexture()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 183; + location = doom; + modificationTime = 277182472.295016; + state = 2; + }; + 724C5F040FC9BE0E000E4348 /* iphone_loop.c:66 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneFrame()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 66; + location = doom; + modificationTime = 277182472.295157; + state = 2; + }; + 724C5F060FC9BE48000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847FC0F941A5900AB3C99 /* p_sight.c */; + name = "p_sight.c: 65"; + rLen = 0; + rLoc = 2231; + rType = 0; + vrLen = 832; + vrLoc = 1818; + }; + 724C5F0A0FC9BE48000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847FC0F941A5900AB3C99 /* p_sight.c */; + name = "p_sight.c: 65"; + rLen = 0; + rLoc = 2231; + rType = 0; + vrLen = 832; + vrLoc = 1818; + }; + 724C5F150FC9BEE1000E4348 /* iphone_loop.c:66 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneFrame()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 66; + location = doom; + modificationTime = 277182472.295272; + state = 2; + }; + 724C5F1A0FC9BEF7000E4348 /* iphone_loop.c:66 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneFrame()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 66; + location = doom; + modificationTime = 277182472.295396; + state = 2; + }; + 724C5F2B0FC9BFD7000E4348 /* iphone_loop.c:66 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneFrame()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 66; + location = doom; + modificationTime = 277182472.295505; + state = 2; + }; + 724C5F560FC9C9B4000E4348 /* iphone_menus.c:27 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "iphoneMultiplayerMenu()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 27; + location = doom; + modificationTime = 277182472.295612; + state = 2; + }; + 724C5F580FC9C9C6000E4348 /* iphone_menus.c:27 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "iphoneMultiplayerMenu()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 27; + location = doom; + modificationTime = 277182472.295722; + state = 2; + }; + 724C5F910FC9E520000E4348 /* iphone_loop.c:66 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneFrame()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 66; + location = doom; + modificationTime = 277182472.295832; + state = 2; + }; + 724C5FD70FC9E846000E4348 /* iphone_loop.c:1673 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneDrawScreen()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1673; + location = doom; + modificationTime = 277182472.295938; + state = 2; + }; + 724C5FE00FC9E96A000E4348 /* g_game.c:1172 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E8478F0F9400D700AB3C99 /* g_game.c */; + functionName = "G_DeathMatchSpawnPlayer()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1172; + location = doom; + modificationTime = 277182472.296047; + state = 2; + }; + 724C5FE60FC9EB5B000E4348 /* m_random.c:143 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E847AE0F9400D700AB3C99 /* m_random.c */; + functionName = "M_ClearRandom()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 143; + location = doom; + modificationTime = 277182472.296155; + state = 2; + }; + 724C5FE80FC9EBAE000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847940F9400D700AB3C99 /* gl_texture.c */; + name = "gl_texture.c: 957"; + rLen = 7; + rLoc = 30428; + rType = 0; + vrLen = 584; + vrLoc = 30020; + }; + 724C5FF10FC9EBAE000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847AE0F9400D700AB3C99 /* m_random.c */; + name = "m_random.c: 140"; + rLen = 13; + rLoc = 5293; + rType = 0; + vrLen = 696; + vrLoc = 4920; + }; + 724C600E0FC9EC9B000E4348 /* m_random.c:130 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E847AE0F9400D700AB3C99 /* m_random.c */; + hitCount = 0; + ignoreCount = 0; + lineNumber = 130; + location = doom; + modificationTime = 277182472.296268; + state = 2; + }; + 724C600F0FC9ECA0000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847AF0F9400D700AB3C99 /* m_random.h */; + name = "m_random.h: 129"; + rLen = 10; + rLoc = 5208; + rType = 0; + vrLen = 961; + vrLoc = 4461; + }; + 724C60140FC9ECA0000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847AF0F9400D700AB3C99 /* m_random.h */; + name = "m_random.h: 129"; + rLen = 10; + rLoc = 5208; + rType = 0; + vrLen = 961; + vrLoc = 4461; + }; + 724C604B0FC9F13B000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847AE0F9400D700AB3C99 /* m_random.c */; + name = "m_random.c: 117"; + rLen = 0; + rLoc = 4610; + rType = 0; + vrLen = 752; + vrLoc = 4864; + }; + 724C60540FCA1E3B000E4348 /* iphone_mapSelect.c:421 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 7239452B0F9C0E7500EADD62 /* iphone_mapSelect.c */; + functionName = "iphoneMapSelectMenu()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 421; + location = doom; + modificationTime = 277182472.296379; + state = 2; + }; + 724C605B0FCA1E6E000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8477D0F9400D700AB3C99 /* d_main.h */; + name = "d_main.h: 56"; + rLen = 5; + rLoc = 2001; + rType = 0; + vrLen = 699; + vrLoc = 1583; + }; + 724C60690FCA1E6E000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8477D0F9400D700AB3C99 /* d_main.h */; + name = "d_main.h: 56"; + rLen = 5; + rLoc = 2001; + rType = 0; + vrLen = 699; + vrLoc = 1583; + }; + 724C606A0FCA1E6E000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8476F0F93FFDB00AB3C99 /* d_client.c */; + name = "d_client.c: 338"; + rLen = 5; + rLoc = 9989; + rType = 0; + vrLen = 896; + vrLoc = 8584; + }; + 724C60860FCA1F05000E4348 /* iphone_mapSelect.c:421 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 7239452B0F9C0E7500EADD62 /* iphone_mapSelect.c */; + functionName = "iphoneMapSelectMenu()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 421; + location = doom; + modificationTime = 277182472.296492; + state = 2; + }; + 724C60890FCA1F07000E4348 /* iphone_mapSelect.c:421 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 7239452B0F9C0E7500EADD62 /* iphone_mapSelect.c */; + functionName = "iphoneMapSelectMenu()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 421; + location = doom; + modificationTime = 277182472.296604; + state = 2; + }; + 724C608B0FCA1F24000E4348 /* iphone_mapSelect.c:361 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 7239452B0F9C0E7500EADD62 /* iphone_mapSelect.c */; + functionName = "iphoneMapSelectMenu()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 361; + location = doom; + modificationTime = 277182472.296716; + state = 2; + }; + 724C608D0FCA1FA8000E4348 /* iphone_loop.c:66 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneBuildTiccmd()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 66; + location = doom; + modificationTime = 277182472.296825; + state = 2; + }; + 724C60A10FCA20D0000E4348 /* iphone_loop.c:1508 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneFrame()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1508; + location = doom; + modificationTime = 277182472.296935; + state = 2; + }; + 724C60CC0FCB061C000E4348 /* iphone_menus.c:27 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "iphoneMultiplayerMenu()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 27; + location = doom; + modificationTime = 277182472.297068; + state = 2; + }; + 724C60CF0FCB062D000E4348 /* iphone_menus.c:27 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "TakeSetupOwnership()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 27; + location = doom; + modificationTime = 277182472.29718; + state = 2; + }; + 724C61200FCB0CFC000E4348 /* iphone_menus.c:27 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "iphoneMultiplayerMenu()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 27; + location = doom; + modificationTime = 277182472.297291; + state = 2; + }; + 724C61370FCB0E32000E4348 /* iphone_menus.c:27 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "iphoneDrawMenus()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 27; + location = doom; + modificationTime = 277182472.297403; + state = 2; + }; + 724C61390FCB0E3E000E4348 /* iphone_menus.c:27 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "iphoneDrawMenus()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 27; + location = doom; + modificationTime = 277182472.297521; + state = 2; + }; + 724C61690FCB1395000E4348 /* iphone_menus.c:27 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "iphoneMultiplayerMenu()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 27; + location = doom; + modificationTime = 277182472.297664; + state = 2; + }; + 724C61A60FCB17CD000E4348 /* iphone_menus.c:27 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "iphoneMainMenu()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 27; + location = doom; + modificationTime = 277182472.297784; + state = 2; + }; + 724C61A80FCB17DE000E4348 /* iphone_menus.c:27 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "iphoneMainMenu()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 27; + location = doom; + modificationTime = 277182472.2979; + state = 2; + }; + 724C61BF0FCB1A6D000E4348 /* iphone_menus.c:27 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "iphoneMultiplayerMenu()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 27; + location = doom; + modificationTime = 277182472.298023; + state = 2; + }; + 724C61EC0FCB1FB2000E4348 /* iphone_menus.c:27 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "iphoneDrawMenus()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 27; + location = doom; + modificationTime = 277182472.298144; + state = 2; + }; + 724C62170FCB25F5000E4348 /* iphone_menus.c:27 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "iphoneDrawMenus()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 27; + location = doom; + modificationTime = 277182472.298264; + state = 2; + }; + 724C621D0FCB26F3000E4348 /* iphone_menus.c:27 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "iphoneMultiplayerMenu()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 27; + location = doom; + modificationTime = 277182472.298379; + state = 2; + }; + 724C62580FCB3C8D000E4348 /* asm iphoneFrame 0x00007c98 */ = { + isa = PBXFileReference; + lastKnownFileType = text; + path = "asm iphoneFrame 0x00007c98"; + sourceTree = ""; + }; + 724C625A0FCB3C8D000E4348 /* asm iphoneFrame 0x00007c98:64 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 724C62580FCB3C8D000E4348 /* asm iphoneFrame 0x00007c98 */; + hitCount = 0; + ignoreCount = 0; + lineNumber = 64; + modificationTime = 277182472.298496; + state = 1; + }; + 724C625B0FCB3C8E000E4348 /* asm iphoneFrame 0x00007c98 */ = { + isa = PBXFileReference; + lastKnownFileType = text; + path = "asm iphoneFrame 0x00007c98"; + sourceTree = ""; + }; + 724C625D0FCB3C8E000E4348 /* asm iphoneFrame 0x00007c98:64 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 724C625B0FCB3C8E000E4348 /* asm iphoneFrame 0x00007c98 */; + hitCount = 0; + ignoreCount = 0; + lineNumber = 64; + modificationTime = 277182472.298613; + state = 1; + }; + 724C62800FCB3EBF000E4348 /* iphone_loop.c:1439 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneFrame()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1439; + location = doom; + modificationTime = 277182472.29873; + state = 2; + }; + 724C62A90FCB41BE000E4348 /* iphone_loop.c:1475 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneFrame()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1475; + location = doom; + modificationTime = 277182472.298848; + state = 2; + }; + 724C62AC0FCB49BE000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 724C62AD0FCB49BE000E4348 /* time.h */; + name = "time.h: 77"; + rLen = 26; + rLoc = 3605; + rType = 0; + vrLen = 712; + vrLoc = 2992; + }; + 724C62AD0FCB49BE000E4348 /* time.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = time.h; + path = /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.0.sdk/usr/include/sys/time.h; + sourceTree = ""; + }; + 724C62B50FCB49BE000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 724C62B60FCB49BE000E4348 /* time.h */; + name = "time.h: 77"; + rLen = 26; + rLoc = 3605; + rType = 0; + vrLen = 712; + vrLoc = 2992; + }; + 724C62B60FCB49BE000E4348 /* time.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = time.h; + path = /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.0.sdk/usr/include/sys/time.h; + sourceTree = ""; + }; + 724C62D50FCB654C000E4348 /* iphone_menus.c:27 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "iphonePacketTester()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 27; + location = doom; + modificationTime = 277182472.298964; + state = 2; + }; + 724C62F50FCB6C65000E4348 /* iphone_main.c:237 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43E8D2DF0F4FC61E003F09B2 /* iphone_main.c */; + functionName = "iphoneStartup()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 237; + location = doom; + modificationTime = 277182472.299121; + state = 2; + }; + 724C63380FCB6D31000E4348 /* iphone_main.c:237 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43E8D2DF0F4FC61E003F09B2 /* iphone_main.c */; + functionName = "iphoneStartup()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 237; + modificationTime = 277182472.299306; + state = 2; + }; + 724C633A0FCB6D36000E4348 /* iphone_main.c:237 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43E8D2DF0F4FC61E003F09B2 /* iphone_main.c */; + functionName = "iphoneStartup()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 237; + location = doom; + modificationTime = 277182472.299484; + state = 2; + }; + 724C63A20FCC3A8B000E4348 /* iphone_main.c:237 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43E8D2DF0F4FC61E003F09B2 /* iphone_main.c */; + functionName = "iphoneStartup()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 237; + modificationTime = 277182472.299661; + state = 2; + }; + 724C63A50FCC3A91000E4348 /* iphone_main.c:237 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43E8D2DF0F4FC61E003F09B2 /* iphone_main.c */; + functionName = "iphoneStartup()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 237; + location = doom; + modificationTime = 277182472.299839; + state = 2; + }; + 724C63AF0FCC3CE2000E4348 /* iphone_main.c:237 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43E8D2DF0F4FC61E003F09B2 /* iphone_main.c */; + functionName = "iphoneStartup()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 237; + location = doom; + modificationTime = 277182472.300017; + state = 2; + }; + 724C63C50FCC3ED5000E4348 /* iphone_main.c:237 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43E8D2DF0F4FC61E003F09B2 /* iphone_main.c */; + functionName = "iphoneStartup()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 237; + location = doom; + modificationTime = 277182472.300202; + state = 2; + }; + 724C63E70FCC4104000E4348 /* iphone_menus.c:27 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "SendSetupPacket()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 27; + location = doom; + modificationTime = 277182472.300383; + state = 2; + }; + 724C63F20FCC414A000E4348 /* iphone_menus.c:27 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "SendSetupPacket()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 27; + location = doom; + modificationTime = 277182472.300528; + state = 2; + }; + 724C64060FCC4257000E4348 /* iphone_menus.c:27 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "SendSetupPacket()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 27; + location = doom; + modificationTime = 277182472.300661; + state = 2; + }; + 724C643A0FCC46E2000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 724C643B0FCC46E2000E4348 /* OSByteOrder.h */; + name = "OSByteOrder.h: 28"; + rLen = 0; + rLoc = 511; + rType = 0; + vrLen = 279; + vrLoc = 376; + }; + 724C643B0FCC46E2000E4348 /* OSByteOrder.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = OSByteOrder.h; + path = /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.0.sdk/usr/include/libkern/arm/OSByteOrder.h; + sourceTree = ""; + }; + 724C64790FCD7A1F000E4348 /* iphone_render.c:1425 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72484E5D0FB0E99900124E1C /* iphone_render.c */; + functionName = "NewDrawScene()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1425; + location = doom; + modificationTime = 277182472.300788; + state = 2; + }; + 724C64D50FCD7D98000E4348 /* gl_main.c:1306 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E847920F9400D700AB3C99 /* gl_main.c */; + functionName = "gld_PrecalculateSector()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1306; + location = doom; + modificationTime = 277182472.300922; + state = 2; + }; + 724C64E00FCD7E61000E4348 /* gl_main.c:1336 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E847920F9400D700AB3C99 /* gl_main.c */; + functionName = "gld_PrecalculateSector()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1336; + location = doom; + modificationTime = 277182472.301052; + state = 2; + }; + 724C64E20FCD7E63000E4348 /* gl_main.c:1342 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E847920F9400D700AB3C99 /* gl_main.c */; + functionName = "gld_PrecalculateSector()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1342; + location = doom; + modificationTime = 277182472.301179; + state = 2; + }; + 724C64EB0FCD7FCB000E4348 /* gl_main.c:1411 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E847920F9400D700AB3C99 /* gl_main.c */; + functionName = "gld_PrecalculateSector()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1411; + location = doom; + modificationTime = 277182472.301304; + state = 2; + }; + 724C64ED0FCD8008000E4348 /* gl_main.c:1494 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E847920F9400D700AB3C99 /* gl_main.c */; + functionName = "gld_PrecalculateSector()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1494; + location = doom; + modificationTime = 277182472.301429; + state = 2; + }; + 724C64F20FCD8180000E4348 /* gl_main.c:1856 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E847920F9400D700AB3C99 /* gl_main.c */; + functionName = "gld_PreprocessSectors()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1856; + location = doom; + modificationTime = 277182472.301561; + state = 2; + }; + 724C64F50FCD818B000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72F1F9B00F96C18800AD49AC /* tess.c */; + name = "tess.c: 461"; + rLen = 0; + rLoc = 13178; + rType = 0; + vrLen = 355; + vrLoc = 12994; + }; + 724C64F90FCD818B000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72F1F9B00F96C18800AD49AC /* tess.c */; + name = "tess.c: 461"; + rLen = 0; + rLoc = 13178; + rType = 0; + vrLen = 355; + vrLoc = 12994; + }; + 724C65030FCD8287000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847830F9400D700AB3C99 /* doomdata.h */; + name = "doomdata.h: 100"; + rLen = 38; + rLoc = 3430; + rType = 0; + vrLen = 485; + vrLoc = 3183; + }; + 724C65070FCD8287000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847830F9400D700AB3C99 /* doomdata.h */; + name = "doomdata.h: 100"; + rLen = 38; + rLoc = 3430; + rType = 0; + vrLen = 485; + vrLoc = 3183; + }; + 724C651A0FCD8435000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848210F941A8300AB3C99 /* r_defs.h */; + name = "r_defs.h: 163"; + rLen = 12; + rLoc = 5362; + rType = 0; + vrLen = 1275; + vrLoc = 3372; + }; + 724C652B0FCD8702000E4348 /* iphone_render.c:1047 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72484E5D0FB0E99900124E1C /* iphone_render.c */; + functionName = "IR_Subsector()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1047; + location = doom; + modificationTime = 277182472.301688; + state = 2; + }; + 724C658C0FCD9455000E4348 /* iphone_render.c:124 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72484E5D0FB0E99900124E1C /* iphone_render.c */; + functionName = "IR_MergeSectors()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 124; + location = doom; + modificationTime = 277182472.301816; + state = 2; + }; + 724C65930FCD9482000E4348 /* gl_main.c:1863 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E847920F9400D700AB3C99 /* gl_main.c */; + functionName = "gld_PreprocessSectors()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1863; + location = doom; + modificationTime = 277182472.301944; + state = 2; + }; + 724C65D60FCD9922000E4348 /* iphone_render.c:142 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72484E5D0FB0E99900124E1C /* iphone_render.c */; + functionName = "IR_MergeSectors()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 142; + location = doom; + modificationTime = 277182472.302079; + state = 2; + }; + 724C65F10FCD9B5F000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8485A0F941ADC00AB3C99 /* z_zone.c */; + name = "z_zone.c: 643"; + rLen = 0; + rLoc = 16093; + rType = 0; + vrLen = 718; + vrLoc = 15827; + }; + 724C65F20FCD9B5F000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847FA0F941A5900AB3C99 /* p_setup.c */; + name = "p_setup.c: 1359"; + rLen = 7; + rLoc = 41926; + rType = 0; + vrLen = 707; + vrLoc = 41379; + }; + 724C65FE0FCD9BB0000E4348 /* iphone_loop.c:1439 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneFrame()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1439; + location = doom; + modificationTime = 277182472.302217; + state = 2; + }; + 724C66070FCD9EA8000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847850F9400D700AB3C99 /* doomdef.h */; + name = "doomdef.h: 145"; + rLen = 8; + rLoc = 4259; + rType = 0; + vrLen = 660; + vrLoc = 3935; + }; + 724C66240FCDA0BE000E4348 /* iphone_sound.c:221 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E731EA0F97E68100E702CD /* iphone_sound.c */; + functionName = "I_StartSound()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 221; + location = doom; + modificationTime = 277182472.302347; + state = 2; + }; + 724C662B0FCDA169000E4348 /* p_mobj.c:1518 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E847F30F941A5900AB3C99 /* p_mobj.c */; + functionName = "P_SpawnPlayerMissile()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1518; + location = doom; + modificationTime = 277182472.302477; + state = 2; + }; + 724C664F0FCDA2B3000E4348 /* iphone_sound.c:226 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E731EA0F97E68100E702CD /* iphone_sound.c */; + functionName = "I_StartSound()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 226; + location = doom; + modificationTime = 277182472.302607; + state = 2; + }; + 724C66520FCDA2C3000E4348 /* s_sound.c:295 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E8483B0F941AAC00AB3C99 /* s_sound.c */; + functionName = "S_StartSoundAtVolume()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 295; + location = doom; + modificationTime = 277182472.302743; + state = 2; + }; + 724C66560FCDA3DA000E4348 /* s_sound.c:627 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E8483B0F941AAC00AB3C99 /* s_sound.c */; + functionName = "S_StopChannel()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 627; + location = doom; + modificationTime = 277182472.302934; + state = 2; + }; + 724C66710FCDAB26000E4348 /* iphone_render.c:1281 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72484E5D0FB0E99900124E1C /* iphone_render.c */; + functionName = "NewDrawScene()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1281; + location = doom; + modificationTime = 277182472.303125; + state = 2; + }; + 724C66980FCDB407000E4348 /* iphone_menus.c:27 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "iphoneMainMenu()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 27; + location = doom; + modificationTime = 277182472.303266; + state = 2; + }; + 724C669A0FCDB413000E4348 /* iphone_loop.c:346 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "HandleButton()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 346; + location = doom; + modificationTime = 277182472.3034; + state = 2; + }; + 724C66D20FCDB610000E4348 /* doomAppDelegate.m:184 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 434669A50F8D08C000EA7D6D /* doomAppDelegate.m */; + functionName = "-applicationWillResignActive:"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 184; + location = doom; + modificationTime = 277182472.303552; + state = 2; + }; + 724C66D40FCDB612000E4348 /* doomAppDelegate.m:191 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 434669A50F8D08C000EA7D6D /* doomAppDelegate.m */; + functionName = "-applicationWillTerminate:"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 191; + location = doom; + modificationTime = 277182472.303765; + state = 2; + }; + 724C66D80FCDB702000E4348 /* iphone_main.c:237 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43E8D2DF0F4FC61E003F09B2 /* iphone_main.c */; + functionName = "iphoneShutdown()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 237; + location = doom; + modificationTime = 277182472.303968; + state = 2; + }; + 724C66DB0FCDB77F000E4348 /* doomAppDelegate.m:195 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 434669A50F8D08C000EA7D6D /* doomAppDelegate.m */; + functionName = "-applicationDidReceiveMemoryWarning:"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 195; + location = doom; + modificationTime = 277182472.304182; + state = 2; + }; + 724C678D0FCDC379000E4348 /* ipak.c:76 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72D50DBB0F8ED98000BB49E6 /* ipak.c */; + functionName = "PK_Init()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 76; + location = doom; + modificationTime = 277182472.304395; + state = 2; + }; + 724C678F0FCDC37A000E4348 /* ipak.c:78 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72D50DBB0F8ED98000BB49E6 /* ipak.c */; + functionName = "PK_Init()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 78; + location = doom; + modificationTime = 277182472.304555; + state = 2; + }; + 724C67910FCDC37C000E4348 /* ipak.c:82 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72D50DBB0F8ED98000BB49E6 /* ipak.c */; + functionName = "PK_Init()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 82; + location = doom; + modificationTime = 277182472.304715; + state = 2; + }; + 724C67930FCDC37F000E4348 /* ipak.c:84 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72D50DBB0F8ED98000BB49E6 /* ipak.c */; + functionName = "PK_Init()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 84; + location = doom; + modificationTime = 277182472.304853; + state = 2; + }; + 724C679C0FCDCAE4000E4348 /* opengl_error_break */ = { + isa = PBXSymbolicBreakpoint; + actions = ( + ); + breakpointStyle = 1; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + hitCount = 0; + ignoreCount = 0; + location = MBXGLEngine; + modificationTime = 277182472.353837; + state = 2; + symbolName = opengl_error_break; + }; + 724C67C00FCDD6EF000E4348 /* iphone_render.c:220 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72484E5D0FB0E99900124E1C /* iphone_render.c */; + functionName = "FadedLighting()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 220; + location = doom; + modificationTime = 277182472.304989; + state = 2; + }; + 724C68030FCDE782000E4348 /* iphone_menus.c:27 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "iphoneControlMenu()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 27; + location = doom; + modificationTime = 277182472.305128; + state = 2; + }; + 72540ED61006849B00925CFB /* iphone_net.c:38 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A560E11004FAEE00F788A5 /* iphone_net.c */; + functionName = "DNSServiceResolveReplyCallback()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 38; + location = doom; + modificationTime = 277182472.329045; + state = 2; + }; + 72540EE81006863400925CFB /* iphone_net.c:38 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A560E11004FAEE00F788A5 /* iphone_net.c */; + functionName = "DNSServiceResolveReplyCallback()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 38; + location = doom; + modificationTime = 277182472.329256; + state = 2; + }; + 72540F2010068B4800925CFB /* iphone_net.c:38 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A560E11004FAEE00F788A5 /* iphone_net.c */; + functionName = "ResolveLocalServer()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 38; + location = doom; + modificationTime = 277182472.32947; + state = 2; + }; + 72540F5B1006938400925CFB /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72A55EEE1003A94300F788A5 /* iphone_start.c */; + name = "iphone_start.c: 56"; + rLen = 0; + rLoc = 1014; + rType = 0; + vrLen = 591; + vrLoc = 692; + }; + 72540F741006994500925CFB /* iphone_async.c:946 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43DD8391100295F70006E1DD /* iphone_async.c */; + functionName = "iphoneAsyncTic()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 946; + location = doom; + modificationTime = 277182472.32967; + state = 2; + }; + 72540F8310069BEB00925CFB /* iphone_net.c:38 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A560E11004FAEE00F788A5 /* iphone_net.c */; + functionName = "DNSServiceResolveReplyCallback()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 38; + location = doom; + modificationTime = 277182472.329871; + state = 2; + }; + 72540FA210069F2D00925CFB /* iphone_net.c:38 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A560E11004FAEE00F788A5 /* iphone_net.c */; + functionName = "DNSServiceResolveReplyCallback()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 38; + location = doom; + modificationTime = 277182472.330065; + state = 2; + }; + 72541053100795CB00925CFB /* iphone_mapSelect.c:262 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 7239452B0F9C0E7500EADD62 /* iphone_mapSelect.c */; + functionName = "iphoneMapSelectMenu()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 262; + location = doom; + modificationTime = 277182472.330269; + state = 2; + }; + 725410561007961500925CFB /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847A70F9400D700AB3C99 /* m_cheat.c */; + name = "m_cheat.c: 364"; + rLen = 145; + rLoc = 11614; + rType = 0; + vrLen = 924; + vrLoc = 11119; + }; + 725410571007961500925CFB /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8477F0F9400D700AB3C99 /* d_player.h */; + name = "d_player.h: 131"; + rLen = 11; + rLoc = 3755; + rType = 0; + vrLen = 894; + vrLoc = 3369; + }; + 725410581007961500925CFB /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847EC0F941A5900AB3C99 /* p_inter.c */; + name = "p_inter.c: 211"; + rLen = 38; + rLoc = 6157; + rType = 0; + vrLen = 701; + vrLoc = 5661; + }; + 7254109D10079DDE00925CFB /* iphone_loop.c:614 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "TouchReleased()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 614; + location = doom; + modificationTime = 277182472.330467; + state = 2; + }; + 725410AA10079E2E00925CFB /* iphone_loop.c:616 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "TouchReleased()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 616; + location = doom; + modificationTime = 277182472.330666; + state = 2; + }; + 725410C11007AC0C00925CFB /* hud.c:194 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72B5FF380F7E5C3D00C8A372 /* hud.c */; + functionName = "HudEditFrame()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 194; + location = doom; + modificationTime = 277182472.330865; + state = 2; + }; + 725410EE1007AFE100925CFB /* iphone_loop.c:309 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "HandleButton()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 309; + location = doom; + modificationTime = 277182472.33107; + state = 2; + }; + 725410F81007AFF800925CFB /* iphone_loop.c:313 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "HandleButton()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 313; + location = doom; + modificationTime = 277182472.33127; + state = 2; + }; + 725411031007B02300925CFB /* iphone_sound.c:29 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E731EA0F97E68100E702CD /* iphone_sound.c */; + functionName = "Sound_StartLocalSound()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 29; + location = doom; + modificationTime = 277182472.331516; + state = 2; + }; + 7254113F1007B14E00925CFB /* iphone_sound.c:43 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E731EA0F97E68100E702CD /* iphone_sound.c */; + functionName = "Sound_StartLocalSoundAtVolume()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 43; + location = doom; + modificationTime = 277182472.33172; + state = 2; + }; + 725411431007B19000925CFB /* iphone_mapSelect.c:386 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 7239452B0F9C0E7500EADD62 /* iphone_mapSelect.c */; + functionName = "iphoneMapSelectMenu()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 386; + location = doom; + modificationTime = 277182472.331918; + state = 2; + }; + 725411471007B1A200925CFB /* iphone_loop.c:128 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "TouchInBounds()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 128; + location = doom; + modificationTime = 277182472.332132; + state = 2; + }; + 725411491007B1A600925CFB /* iphone_mapSelect.c:388 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 7239452B0F9C0E7500EADD62 /* iphone_mapSelect.c */; + functionName = "iphoneMapSelectMenu()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 388; + location = doom; + modificationTime = 277182472.33234; + state = 2; + }; + 725411881007B40200925CFB /* iphone_loop.c:254 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "HandleButton()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 254; + location = doom; + modificationTime = 277182472.332542; + state = 2; + }; + 7254118A1007B40900925CFB /* iphone_loop.c:252 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "HandleButton()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 252; + location = doom; + modificationTime = 277182472.332765; + state = 2; + }; + 725411AD1007B8F300925CFB /* iphone_loop.c:1079 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "AutomapControls()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1079; + location = doom; + modificationTime = 277182472.332985; + state = 2; + }; + 725411BE1007B93800925CFB /* iphone_loop.c:1050 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "AutomapControls()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1050; + location = doom; + modificationTime = 277182472.333187; + state = 2; + }; + 725412071007C19A00925CFB /* iphone_loop.c:1056 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "AutomapControls()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1056; + location = doom; + modificationTime = 277182472.333391; + state = 2; + }; + 725412181007C3EC00925CFB /* s_sound.c:730 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E8483B0F941AAC00AB3C99 /* s_sound.c */; + functionName = "S_getChannel()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 730; + location = Doom; + modificationTime = 277182472.720047; + state = 0; + }; + 725412251007C6F100925CFB /* s_sound.c:303 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E8483B0F941AAC00AB3C99 /* s_sound.c */; + functionName = "S_StartSoundAtVolume()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 303; + location = doom; + modificationTime = 277182472.333856; + state = 2; + }; + 7254122F1007C71F00925CFB /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847F60F941A5900AB3C99 /* p_pspr.c */; + name = "p_pspr.c: 688"; + rLen = 0; + rLoc = 18483; + rType = 0; + vrLen = 614; + vrLoc = 18247; + }; + 725412E11007D63200925CFB /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 724C531E0FBDBCEE000E4348 /* BackgroundMusic.cpp */; + name = "BackgroundMusic.cpp: 49"; + rLen = 0; + rLoc = 1063; + rType = 0; + vrLen = 981; + vrLoc = 741; + }; + 725413041007DC0B00925CFB /* iphone_async.c:206 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43DD8391100295F70006E1DD /* iphone_async.c */; + functionName = "iphoneProcessPacket()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 206; + location = doom; + modificationTime = 277182472.334119; + state = 2; + }; + 725413061007DC0D00925CFB /* iphone_async.c:244 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43DD8391100295F70006E1DD /* iphone_async.c */; + functionName = "iphoneProcessPacket()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 244; + location = doom; + modificationTime = 277182472.334337; + state = 2; + }; + 725D1D20107EAE6800B86564 /* PlistBookmark */ = { + isa = PlistBookmark; + fRef = 8D1107310486CEB800E47090 /* Info.plist */; + fallbackIsa = PBXBookmark; + isK = 0; + kPath = ( + ); + name = /Users/johnc/dev/iphone/doom/code/iphone/Info.plist; + rLen = 0; + rLoc = 2147483647; + }; + 725D1D22107EAE6800B86564 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43E8D2DF0F4FC61E003F09B2 /* iphone_main.c */; + name = "iphone_main.c: 145"; + rLen = 0; + rLoc = 3966; + rType = 0; + vrLen = 925; + vrLoc = 3014; + }; + 725D1D23107EAE6800B86564 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 434669A50F8D08C000EA7D6D /* doomAppDelegate.m */; + name = "doomAppDelegate.m: 129"; + rLen = 0; + rLoc = 3905; + rType = 0; + vrLen = 1730; + vrLoc = 3028; + }; + 725D1D31107EB60E00B86564 /* iphone_sound.c:229 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E731EA0F97E68100E702CD /* iphone_sound.c */; + functionName = "I_StartSound()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 229; + location = doom; + modificationTime = 277182472.348154; + state = 2; + }; + 725D1D33107EB61800B86564 /* iphone_sound.c:46 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E731EA0F97E68100E702CD /* iphone_sound.c */; + functionName = "Sound_StartLocalSoundAtVolume()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 46; + location = doom; + modificationTime = 277182472.348387; + state = 2; + }; + 725D1D48107EBA1600B86564 /* iphone_net.c:455 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A560E11004FAEE00F788A5 /* iphone_net.c */; + functionName = "NetworkAvailable()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 455; + location = doom; + modificationTime = 277182472.348615; + state = 2; + }; + 725E00150FFD261F00A7D6A7 /* iphone_loop.c:1557 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneDrawScreen()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1557; + location = doom; + modificationTime = 277182472.315115; + state = 2; + }; + 725E00330FFD299400A7D6A7 /* iphone_menus.c:490 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "iphoneMultiplayerMenu()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 490; + location = doom; + modificationTime = 277182472.315309; + state = 2; + }; + 725E00350FFD29A400A7D6A7 /* iphone_menus.c:415 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "iphoneMultiplayerMenu()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 415; + location = doom; + modificationTime = 277182472.315498; + state = 2; + }; + 725E003A0FFD29C400A7D6A7 /* iphone_menus.c:449 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "iphoneMultiplayerMenu()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 449; + location = doom; + modificationTime = 277182472.315676; + state = 2; + }; + 725E00500FFD29DE00A7D6A7 /* iphone_menus.c:478 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "iphoneMultiplayerMenu()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 478; + modificationTime = 277182472.315849; + state = 2; + }; + 725E00520FFD29E700A7D6A7 /* iphone_menus.c:418 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "iphoneMultiplayerMenu()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 418; + modificationTime = 277182472.316015; + state = 2; + }; + 725E00850FFD2F3600A7D6A7 /* iphone_loop.c:1410 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneFrame()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1410; + location = doom; + modificationTime = 277182472.316181; + state = 2; + }; + 725E00A20FFD312B00A7D6A7 /* iphone_loop.c:1413 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneFrame()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1413; + location = doom; + modificationTime = 277182472.316348; + state = 2; + }; + 725E00C40FFD31D800A7D6A7 /* doomAppDelegate.m:133 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 434669A50F8D08C000EA7D6D /* doomAppDelegate.m */; + functionName = "-applicationDidFinishLaunching:"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 133; + location = doom; + modificationTime = 277182472.316516; + state = 2; + }; + 725E00C90FFD335500A7D6A7 /* doomAppDelegate.m:134 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 434669A50F8D08C000EA7D6D /* doomAppDelegate.m */; + functionName = "-applicationDidFinishLaunching:"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 134; + location = doom; + modificationTime = 277182472.316763; + state = 2; + }; + 725E01E90FFD522100A7D6A7 /* doomAppDelegate.m:145 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 434669A50F8D08C000EA7D6D /* doomAppDelegate.m */; + functionName = "-applicationDidFinishLaunching:"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 145; + location = doom; + modificationTime = 277182472.317002; + state = 2; + }; + 725E01ED0FFD528100A7D6A7 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 725E01EE0FFD528100A7D6A7 /* pthread.h */; + name = "pthread.h: 307"; + rLen = 96; + rLoc = 9789; + rType = 0; + vrLen = 1070; + vrLoc = 13281; + }; + 725E01EE0FFD528100A7D6A7 /* pthread.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = pthread.h; + path = /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.0.sdk/usr/include/pthread.h; + sourceTree = ""; + }; + 725E01EF0FFD528100A7D6A7 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 725E01F00FFD528100A7D6A7 /* sched.h */; + name = "sched.h: 35"; + rLen = 82; + rLoc = 1139; + rType = 0; + vrLen = 749; + vrLoc = 626; + }; + 725E01F00FFD528100A7D6A7 /* sched.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = sched.h; + path = /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.0.sdk/usr/include/sched.h; + sourceTree = ""; + }; + 725E01F30FFD528100A7D6A7 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 725E01F40FFD528100A7D6A7 /* pthread.h */; + name = "pthread.h: 307"; + rLen = 96; + rLoc = 9789; + rType = 0; + vrLen = 1070; + vrLoc = 13281; + }; + 725E01F40FFD528100A7D6A7 /* pthread.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = pthread.h; + path = /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.0.sdk/usr/include/pthread.h; + sourceTree = ""; + }; + 725E01F60FFD528100A7D6A7 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 725E01F70FFD528100A7D6A7 /* sched.h */; + name = "sched.h: 35"; + rLen = 82; + rLoc = 1139; + rType = 0; + vrLen = 749; + vrLoc = 626; + }; + 725E01F70FFD528100A7D6A7 /* sched.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = sched.h; + path = /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.0.sdk/usr/include/sched.h; + sourceTree = ""; + }; + 725E02070FFD554600A7D6A7 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 725E02080FFD554600A7D6A7 /* sched.h */; + name = "sched.h: 27"; + rLen = 14; + rLoc = 1032; + rType = 0; + vrLen = 611; + vrLoc = 765; + }; + 725E02080FFD554600A7D6A7 /* sched.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = sched.h; + path = /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.2.1.sdk/usr/include/sched.h; + sourceTree = ""; + }; + 725E02090FFD554600A7D6A7 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 725E020A0FFD554600A7D6A7 /* pthread_impl.h */; + name = "pthread_impl.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 705; + vrLoc = 839; + }; + 725E020A0FFD554600A7D6A7 /* pthread_impl.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = pthread_impl.h; + path = /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.2.1.sdk/usr/include/pthread_impl.h; + sourceTree = ""; + }; + 725E020D0FFD554600A7D6A7 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 725E020E0FFD554600A7D6A7 /* sched.h */; + name = "sched.h: 27"; + rLen = 14; + rLoc = 1032; + rType = 0; + vrLen = 611; + vrLoc = 765; + }; + 725E020E0FFD554600A7D6A7 /* sched.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = sched.h; + path = /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.2.1.sdk/usr/include/sched.h; + sourceTree = ""; + }; + 725E020F0FFD554600A7D6A7 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 725E02100FFD554600A7D6A7 /* pthread_impl.h */; + name = "pthread_impl.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 705; + vrLoc = 839; + }; + 725E02100FFD554600A7D6A7 /* pthread_impl.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = pthread_impl.h; + path = /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.2.1.sdk/usr/include/pthread_impl.h; + sourceTree = ""; + }; + 725E02190FFD55DC00A7D6A7 /* doomAppDelegate.m:146 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 434669A50F8D08C000EA7D6D /* doomAppDelegate.m */; + functionName = "-applicationDidFinishLaunching:"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 146; + location = doom; + modificationTime = 277182472.317249; + state = 2; + }; + 725E02890FFD66D100A7D6A7 /* iphone_menus.c:919 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "iphoneDrawMenus()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 919; + location = doom; + modificationTime = 277182472.317496; + state = 2; + }; + 725E028E0FFD66EC00A7D6A7 /* iphone_menus.c:883 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "ProcessSetupPackets()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 883; + location = doom; + modificationTime = 277182472.317674; + state = 2; + }; + 725E02900FFD672A00A7D6A7 /* iphone_menus.c:883 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "ProcessSetupPackets()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 883; + location = doom; + modificationTime = 277182472.317856; + state = 2; + }; + 725E02C4100242F200A7D6A7 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 725E02C5100242F200A7D6A7 /* basic_string.h */; + name = "basic_string.h: 2029"; + rLen = 0; + rLoc = 76306; + rType = 0; + vrLen = 667; + vrLoc = 75916; + }; + 725E02C5100242F200A7D6A7 /* basic_string.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = basic_string.h; + path = "/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.0.sdk/usr/include/c++/4.0.0/bits/basic_string.h"; + sourceTree = ""; + }; + 725E02C9100242F200A7D6A7 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 725E02CA100242F200A7D6A7 /* basic_string.h */; + name = "basic_string.h: 2029"; + rLen = 0; + rLoc = 76306; + rType = 0; + vrLen = 667; + vrLoc = 75916; + }; + 725E02CA100242F200A7D6A7 /* basic_string.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = basic_string.h; + path = "/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.0.sdk/usr/include/c++/4.0.0/bits/basic_string.h"; + sourceTree = ""; + }; + 725E033410024FC300A7D6A7 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847820F9400D700AB3C99 /* d_ticcmd.h */; + name = "d_ticcmd.h: 54"; + rLen = 57; + rLoc = 1975; + rType = 0; + vrLen = 770; + vrLoc = 1317; + }; + 725E03601002577600A7D6A7 /* iphone_menus.c:883 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "ProcessSetupPackets()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 883; + location = doom; + modificationTime = 277182472.318045; + state = 2; + }; + 725E03731002582400A7D6A7 /* iphone_menus.c:363 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "SendSetupPacket()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 363; + location = doom; + modificationTime = 277182472.318233; + state = 2; + }; + 725E03781002586500A7D6A7 /* iphone_menus.c:883 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "ProcessSetupPackets()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 883; + location = doom; + modificationTime = 277182472.318411; + state = 2; + }; + 725E03811002592E00A7D6A7 /* iphone_menus.c:363 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "SendSetupPacket()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 363; + location = doom; + modificationTime = 277182472.318595; + state = 2; + }; + 725E03FA100279FF00A7D6A7 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847870F9400D700AB3C99 /* doomstat.h */; + name = "doomstat.h: 146"; + rLen = 8; + rLoc = 4446; + rType = 0; + vrLen = 796; + vrLoc = 4000; + }; + 725E03FD100279FF00A7D6A7 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8478F0F9400D700AB3C99 /* g_game.c */; + name = "g_game.c: 217"; + rLen = 29; + rLoc = 7415; + rType = 0; + vrLen = 1025; + vrLoc = 6935; + }; + 725E041A10027B6500A7D6A7 /* gl_main.c:2910 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E847920F9400D700AB3C99 /* gl_main.c */; + functionName = "gld_DrawScene()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 2910; + location = Doom; + modificationTime = 277182472.57818; + state = 0; + }; + 725E042210027E9800A7D6A7 /* gl_main.c:1705 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E847920F9400D700AB3C99 /* gl_main.c */; + functionName = "BuildIndexedTriangles()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1705; + location = doom; + modificationTime = 277182472.318979; + state = 2; + }; + 725E042410027EA700A7D6A7 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + name = "iphone_async.c: 373"; + rLen = 0; + rLoc = 9568; + rType = 0; + vrLen = 997; + vrLoc = 9098; + }; + 725E042510027EA700A7D6A7 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8482E0F941AAC00AB3C99 /* r_main.c */; + name = "r_main.c: 646"; + rLen = 13; + rLoc = 17250; + rType = 0; + vrLen = 600; + vrLoc = 15894; + }; + 725E042610027EA700A7D6A7 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847930F9400D700AB3C99 /* gl_struct.h */; + name = "gl_struct.h: 63"; + rLen = 13; + rLoc = 2282; + rType = 0; + vrLen = 960; + vrLoc = 1427; + }; + 725E04611002857800A7D6A7 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847640F93C61900AB3C99 /* am_map.c */; + name = "am_map.c: 77"; + rLen = 87; + rLoc = 2998; + rType = 0; + vrLen = 1049; + vrLoc = 2610; + }; + 725E049E10028B1800A7D6A7 /* PBXBookmark */ = { + isa = PBXBookmark; + fRef = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + }; + 725E04A310028FCE00A7D6A7 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848560F941ADC00AB3C99 /* wi_stuff.c */; + name = "wi_stuff.c: 1171"; + rLen = 10; + rLoc = 28092; + rType = 0; + vrLen = 499; + vrLoc = 27782; + }; + 725E04A410028FCE00A7D6A7 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8477C0F9400D700AB3C99 /* d_main.c */; + name = "d_main.c: 1212"; + rLen = 14; + rLoc = 33438; + rType = 0; + vrLen = 739; + vrLoc = 33057; + }; + 725EFEA30FFC17BA00A7D6A7 /* PBXBookmarkGroup */ = { + isa = PBXBookmarkGroup; + children = ( + 725E049E10028B1800A7D6A7 /* PBXBookmark */, + ); + name = Root; + }; + 725EFEC20FFC197500A7D6A7 /* iphone_loop.c:1286 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneAsyncTic()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1286; + location = doom; + modificationTime = 277182472.313091; + state = 2; + }; + 725EFEDA0FFC1FDA00A7D6A7 /* iphone_loop.c:1286 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneAsyncTic()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1286; + location = doom; + modificationTime = 277182472.31325; + state = 2; + }; + 725EFF0F0FFC272B00A7D6A7 /* iphone_loop.c:1286 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneAsyncTic()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1286; + location = doom; + modificationTime = 277182472.313444; + state = 2; + }; + 725EFF320FFC30C300A7D6A7 /* iphone_loop.c:1286 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneAsyncTic()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1286; + location = doom; + modificationTime = 277182472.313607; + state = 2; + }; + 725EFF4C0FFC34AC00A7D6A7 /* iphone_loop.c:1125 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneBuildTiccmd()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1125; + location = doom; + modificationTime = 277182472.313769; + state = 2; + }; + 725EFF4E0FFC34BB00A7D6A7 /* iphone_loop.c:1647 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneDrawScreen()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1647; + location = doom; + modificationTime = 277182472.313936; + state = 2; + }; + 725EFF510FFC34C100A7D6A7 /* iphone_loop.c:1650 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneDrawScreen()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1650; + location = doom; + modificationTime = 277182472.314101; + state = 2; + }; + 725EFF540FFC34ED00A7D6A7 /* iphone_loop.c:1125 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneBuildTiccmd()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1125; + location = doom; + modificationTime = 277182472.314263; + state = 2; + }; + 725EFF6C0FFC3EDE00A7D6A7 /* iphone_loop.c:1716 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneDrawScreen()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1716; + location = doom; + modificationTime = 277182472.314426; + state = 2; + }; + 725EFF790FFC3F8400A7D6A7 /* iphone_loop.c:1299 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneFrame()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1299; + location = doom; + modificationTime = 277182472.314599; + state = 2; + }; + 725EFFB40FFD05AB00A7D6A7 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + name = "iphone_async.c: 11"; + rLen = 0; + rLoc = 18879; + rType = 0; + vrLen = 135; + vrLoc = 0; + }; + 725EFFD40FFD0F6500A7D6A7 /* iphone_menus.c:425 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "iphoneMultiplayerMenu()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 425; + location = doom; + modificationTime = 277182472.314771; + state = 2; + }; + 725EFFF80FFD173300A7D6A7 /* iphone_menus.c:883 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "ProcessSetupPackets()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 883; + location = doom; + modificationTime = 277182472.314947; + state = 2; + }; + 72679959101E92F600CEA3A2 /* iphone_async.c:136 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43DD8391100295F70006E1DD /* iphone_async.c */; + functionName = "iphoneProcessPacket()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 136; + location = doom; + modificationTime = 277182472.342401; + state = 2; + }; + 7267998F101E9AFD00CEA3A2 /* iphone_async.c:112 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43DD8391100295F70006E1DD /* iphone_async.c */; + functionName = "iphoneProcessPacket()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 112; + location = doom; + modificationTime = 277182472.342629; + state = 2; + }; + 726799F8102879A100CEA3A2 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847920F9400D700AB3C99 /* gl_main.c */; + name = "gl_main.c: 1763"; + rLen = 0; + rLoc = 63904; + rType = 0; + vrLen = 1392; + vrLoc = 78318; + }; + 7278865F0FBDAF4B0020D469 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 727886600FBDAF4B0020D469 /* oalMacOSX_OALExtensions.h */; + name = "oalMacOSX_OALExtensions.h: 40"; + rLen = 74; + rLoc = 2653; + rType = 0; + vrLen = 1562; + vrLoc = 1267; + }; + 727886600FBDAF4B0020D469 /* oalMacOSX_OALExtensions.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = oalMacOSX_OALExtensions.h; + path = /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.0.sdk/System/Library/Frameworks/OpenAL.framework/Headers/oalMacOSX_OALExtensions.h; + sourceTree = ""; + }; + 727886650FBDAF4B0020D469 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 727886660FBDAF4B0020D469 /* oalMacOSX_OALExtensions.h */; + name = "oalMacOSX_OALExtensions.h: 40"; + rLen = 74; + rLoc = 2653; + rType = 0; + vrLen = 1562; + vrLoc = 1267; + }; + 727886660FBDAF4B0020D469 /* oalMacOSX_OALExtensions.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = oalMacOSX_OALExtensions.h; + path = /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.0.sdk/System/Library/Frameworks/OpenAL.framework/Headers/oalMacOSX_OALExtensions.h; + sourceTree = ""; + }; + 7280FC2110052E3A000F05FD /* iphone_net.c:38 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A560E11004FAEE00F788A5 /* iphone_net.c */; + functionName = "DNSServiceResolveReplyCallback()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 38; + location = doom; + modificationTime = 277182472.323665; + state = 2; + }; + 7280FC2310052E8C000F05FD /* iphone_menus.c:247 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "iphoneMainMenu()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 247; + location = doom; + modificationTime = 277182472.323893; + state = 2; + }; + 7280FC5210052F94000F05FD /* iphone_net.c:363 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A560E11004FAEE00F788A5 /* iphone_net.c */; + functionName = "ProcessDNSMessages()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 363; + location = doom; + modificationTime = 277182472.324101; + state = 2; + }; + 7280FC5B10053042000F05FD /* iphone_net.c:38 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A560E11004FAEE00F788A5 /* iphone_net.c */; + functionName = "DNSServiceBrowseReplyCallback()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 38; + location = doom; + modificationTime = 277182472.32429; + state = 2; + }; + 7280FC841005358B000F05FD /* iphone_net.c:38 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A560E11004FAEE00F788A5 /* iphone_net.c */; + functionName = "DNSServiceQueryRecordReplyCallback()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 38; + location = doom; + modificationTime = 277182472.324494; + state = 2; + }; + 7280FC8A100536FA000F05FD /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7280FC8B100536FA000F05FD /* dns_sd.h */; + name = "dns_sd.h: 357"; + rLen = 17; + rLoc = 17939; + rType = 0; + vrLen = 1565; + vrLoc = 17720; + }; + 7280FC8B100536FA000F05FD /* dns_sd.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = dns_sd.h; + path = /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.0.sdk/usr/include/dns_sd.h; + sourceTree = ""; + }; + 7280FC8E100536FA000F05FD /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7280FC8F100536FA000F05FD /* dns_sd.h */; + name = "dns_sd.h: 357"; + rLen = 17; + rLoc = 17939; + rType = 0; + vrLen = 1565; + vrLoc = 17720; + }; + 7280FC8F100536FA000F05FD /* dns_sd.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = dns_sd.h; + path = /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.0.sdk/usr/include/dns_sd.h; + sourceTree = ""; + }; + 7280FCCD10053D90000F05FD /* iphone_main.c:314 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43E8D2DF0F4FC61E003F09B2 /* iphone_main.c */; + functionName = "iphoneStartup()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 314; + location = doom; + modificationTime = 277182472.324686; + state = 2; + }; + 7280FD0E10053E70000F05FD /* iphone_menus.c:407 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "iphoneMultiplayerMenu()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 407; + location = doom; + modificationTime = 277182472.324946; + state = 2; + }; + 7280FD3010054021000F05FD /* iphone_menus.c:466 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "iphoneMultiplayerMenu()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 466; + location = doom; + modificationTime = 277182472.325139; + state = 2; + }; + 7280FD4B10054074000F05FD /* iphone_menus.c:243 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "iphoneMainMenu()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 243; + location = doom; + modificationTime = 277182472.325357; + state = 2; + }; + 7280FD661005414A000F05FD /* iphone_async.c:106 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43DD8391100295F70006E1DD /* iphone_async.c */; + functionName = "iphoneProcessPacket()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 106; + location = doom; + modificationTime = 277182472.3256; + state = 2; + }; + 7280FD811005486D000F05FD /* iphone_main.c:299 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43E8D2DF0F4FC61E003F09B2 /* iphone_main.c */; + functionName = "UDPSocket()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 299; + location = doom; + modificationTime = 277182472.325806; + state = 2; + }; + 7280FD9310054B9F000F05FD /* iphone_main.c:314 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43E8D2DF0F4FC61E003F09B2 /* iphone_main.c */; + functionName = "iphoneStartup()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 314; + location = doom; + modificationTime = 277182472.32605; + state = 2; + }; + 7280FD9E10054C2D000F05FD /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7280FD9F10054C2D000F05FD /* ifaddrs.h */; + name = "ifaddrs.h: 31"; + rLen = 201; + rLoc = 1324; + rType = 0; + vrLen = 839; + vrLoc = 830; + }; + 7280FD9F10054C2D000F05FD /* ifaddrs.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = ifaddrs.h; + path = /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.0.sdk/usr/include/ifaddrs.h; + sourceTree = ""; + }; + 7280FDD310054DAB000F05FD /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 724C5DF00FC7B5AF000E4348 /* in.h */; + name = "in.h: 364"; + rLen = 10; + rLoc = 15078; + rType = 0; + vrLen = 731; + vrLoc = 14709; + }; + 7280FDFD100560E2000F05FD /* iphone_async.c:810 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43DD8391100295F70006E1DD /* iphone_async.c */; + functionName = "iphoneAsyncTic()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 810; + location = doom; + modificationTime = 277182472.326321; + state = 2; + }; + 7280FE00100560FE000F05FD /* iphone_menus.c:363 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "SendSetupPacket()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 363; + location = doom; + modificationTime = 277182472.326508; + state = 2; + }; + 7280FE0210056104000F05FD /* iphone_menus.c:385 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "SendJoinPacket()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 385; + location = doom; + modificationTime = 277182472.326702; + state = 2; + }; + 7280FE041005610F000F05FD /* iphone_async.c:850 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43DD8391100295F70006E1DD /* iphone_async.c */; + functionName = "iphoneAsyncTic()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 850; + location = doom; + modificationTime = 277182472.326902; + state = 2; + }; + 7280FE0610056115000F05FD /* iphone_async.c:950 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43DD8391100295F70006E1DD /* iphone_async.c */; + functionName = "iphoneAsyncTic()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 950; + location = doom; + modificationTime = 277182472.327094; + state = 2; + }; + 7280FEC110057E63000F05FD /* iphone_async.c:756 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43DD8391100295F70006E1DD /* iphone_async.c */; + functionName = "iphoneAsyncTic()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 756; + location = doom; + modificationTime = 277182472.327288; + state = 2; + }; + 7280FF051005903F000F05FD /* iphone_async.c:96 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43DD8391100295F70006E1DD /* iphone_async.c */; + functionName = "UpdatePeerTiming()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 96; + location = doom; + modificationTime = 277182472.327484; + state = 2; + }; + 7280FF13100591F0000F05FD /* iphone_async.c:91 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43DD8391100295F70006E1DD /* iphone_async.c */; + functionName = "UpdatePeerTiming()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 91; + location = doom; + modificationTime = 277182472.327694; + state = 2; + }; + 7280FF1B1005924B000F05FD /* iphone_async.c:86 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43DD8391100295F70006E1DD /* iphone_async.c */; + functionName = "UpdatePeerTiming()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 86; + location = doom; + modificationTime = 277182472.327881; + state = 2; + }; + 7280FF1F10059290000F05FD /* iphone_async.c:88 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43DD8391100295F70006E1DD /* iphone_async.c */; + functionName = "UpdatePeerTiming()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 88; + location = doom; + modificationTime = 277182472.328086; + state = 2; + }; + 7285881F0FE3E44C007D4FCD /* iphone_mapSelect.c:361 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 7239452B0F9C0E7500EADD62 /* iphone_mapSelect.c */; + functionName = "iphoneMapSelectMenu()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 361; + location = doom; + modificationTime = 277182472.306351; + state = 2; + }; + 728588440FE53F70007D4FCD /* iphone_mapSelect.c:361 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 7239452B0F9C0E7500EADD62 /* iphone_mapSelect.c */; + functionName = "iphoneMapSelectMenu()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 361; + location = doom; + modificationTime = 277182472.306506; + state = 2; + }; + 7285886D0FE7BF39007D4FCD /* iphone_loop.c:1285 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "DropPlayer()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1285; + location = doom; + modificationTime = 277182472.306661; + state = 2; + }; + 728588970FEFE103007D4FCD /* iphone_loop.c:1286 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneAsyncTic()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1286; + location = doom; + modificationTime = 277182472.306816; + state = 2; + }; + 728818D5108575100049CC03 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72B5FF380F7E5C3D00C8A372 /* hud.c */; + name = "hud.c: 100"; + rLen = 0; + rLoc = 3535; + rType = 0; + vrLen = 1464; + vrLoc = 1621; + }; + 728818D6108575100049CC03 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43E8D2DF0F4FC61E003F09B2 /* iphone_main.c */; + name = "iphone_main.c: 139"; + rLen = 0; + rLoc = 3809; + rType = 0; + vrLen = 1026; + vrLoc = 3419; + }; + 728818D7108575100049CC03 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72B5FF380F7E5C3D00C8A372 /* hud.c */; + name = "hud.c: 100"; + rLen = 0; + rLoc = 3535; + rType = 0; + vrLen = 1464; + vrLoc = 1621; + }; + 728818D8108575100049CC03 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43E8D2DF0F4FC61E003F09B2 /* iphone_main.c */; + name = "iphone_main.c: 134"; + rLen = 0; + rLoc = 3661; + rType = 0; + vrLen = 775; + vrLoc = 3185; + }; + 728818E3108576640049CC03 /* BackgroundMusic.cpp:493 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 724C531E0FBDBCEE000E4348 /* BackgroundMusic.cpp */; + functionName = "iphoneStartMusic()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 493; + location = Doom; + modificationTime = 277182472.869842; + state = 0; + }; + 728818E5108576800049CC03 /* BackgroundMusic.cpp:515 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 724C531E0FBDBCEE000E4348 /* BackgroundMusic.cpp */; + functionName = "iphonePlayMusic( const char *name )"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 515; + location = Doom; + modificationTime = 277182473.015704; + state = 0; + }; + 728818E7108576840049CC03 /* BackgroundMusic.cpp:509 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 724C531E0FBDBCEE000E4348 /* BackgroundMusic.cpp */; + functionName = "iphoneStartMusic()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 509; + location = Doom; + modificationTime = 277182472.350323; + state = 2; + }; + 728818EB108577430049CC03 /* s_sound.c:528 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E8483B0F941AAC00AB3C99 /* s_sound.c */; + functionName = "S_ChangeMusic()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 528; + location = Doom; + modificationTime = 277182473.174669; + state = 0; + }; + 728818EC1085775C0049CC03 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43E8D2DF0F4FC61E003F09B2 /* iphone_main.c */; + name = "iphone_main.c: 119"; + rLen = 0; + rLoc = 3262; + rType = 0; + vrLen = 723; + vrLoc = 3208; + }; + 728818ED1085775C0049CC03 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 724C531E0FBDBCEE000E4348 /* BackgroundMusic.cpp */; + name = "BackgroundMusic.cpp: 514"; + rLen = 15; + rLoc = 16673; + rType = 0; + vrLen = 652; + vrLoc = 16120; + }; + 728818EE1085775C0049CC03 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8483B0F941AAC00AB3C99 /* s_sound.c */; + rLen = 15; + rLoc = 14050; + rType = 0; + }; + 728818EF1085775C0049CC03 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43E8D2DF0F4FC61E003F09B2 /* iphone_main.c */; + name = "iphone_main.c: 119"; + rLen = 0; + rLoc = 3262; + rType = 0; + vrLen = 723; + vrLoc = 3208; + }; + 728818F01085775C0049CC03 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 724C531E0FBDBCEE000E4348 /* BackgroundMusic.cpp */; + name = "BackgroundMusic.cpp: 514"; + rLen = 15; + rLoc = 16673; + rType = 0; + vrLen = 652; + vrLoc = 16120; + }; + 728818F11085775C0049CC03 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8483B0F941AAC00AB3C99 /* s_sound.c */; + name = "s_sound.c: 532"; + rLen = 0; + rLoc = 13983; + rType = 0; + vrLen = 663; + vrLoc = 13481; + }; + 728818F2108577850049CC03 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 728818F3108577850049CC03 /* asm __dyld__dyld_start 0x2fe01028 */; + name = "asm __dyld__dyld_start 0x2fe01028: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 589; + vrLoc = 0; + }; + 728818F3108577850049CC03 /* asm __dyld__dyld_start 0x2fe01028 */ = { + isa = PBXFileReference; + path = "asm __dyld__dyld_start 0x2fe01028"; + sourceTree = ""; + }; + 728818F4108577850049CC03 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8483B0F941AAC00AB3C99 /* s_sound.c */; + name = "s_sound.c: 532"; + rLen = 0; + rLoc = 13983; + rType = 0; + vrLen = 478; + vrLoc = 13592; + }; + 728818F6108577980049CC03 /* BackgroundMusic.cpp:482 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 724C531E0FBDBCEE000E4348 /* BackgroundMusic.cpp */; + functionName = "iphoneResumeMusic()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 482; + location = Doom; + modificationTime = 277182473.324706; + state = 0; + }; + 728818F7108577A30049CC03 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8483B0F941AAC00AB3C99 /* s_sound.c */; + name = "s_sound.c: 532"; + rLen = 0; + rLoc = 13983; + rType = 0; + vrLen = 644; + vrLoc = 13555; + }; + 728818F8108577A30049CC03 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 724C531E0FBDBCEE000E4348 /* BackgroundMusic.cpp */; + name = "BackgroundMusic.cpp: 514"; + rLen = 15; + rLoc = 16673; + rType = 0; + vrLen = 653; + vrLoc = 16119; + }; + 728818F9108577A30049CC03 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8483B0F941AAC00AB3C99 /* s_sound.c */; + name = "s_sound.c: 532"; + rLen = 0; + rLoc = 13983; + rType = 0; + vrLen = 644; + vrLoc = 13555; + }; + 728818FA108577A30049CC03 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 724C531E0FBDBCEE000E4348 /* BackgroundMusic.cpp */; + name = "BackgroundMusic.cpp: 494"; + rLen = 0; + rLoc = 16196; + rType = 0; + vrLen = 592; + vrLoc = 15777; + }; + 728818FB108577BE0049CC03 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8483B0F941AAC00AB3C99 /* s_sound.c */; + name = "s_sound.c: 532"; + rLen = 0; + rLoc = 13983; + rType = 0; + vrLen = 437; + vrLoc = 13639; + }; + 728818FC108577BE0049CC03 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 724C531E0FBDBCEE000E4348 /* BackgroundMusic.cpp */; + name = "BackgroundMusic.cpp: 514"; + rLen = 15; + rLoc = 16673; + rType = 0; + vrLen = 330; + vrLoc = 16445; + }; + 728818FF108578270049CC03 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 724C531E0FBDBCEE000E4348 /* BackgroundMusic.cpp */; + name = "BackgroundMusic.cpp: 514"; + rLen = 15; + rLoc = 16673; + rType = 0; + vrLen = 568; + vrLoc = 16207; + }; + 72881900108578270049CC03 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8483B0F941AAC00AB3C99 /* s_sound.c */; + rLen = 15; + rLoc = 14012; + rType = 0; + }; + 72881901108578270049CC03 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 724C531E0FBDBCEE000E4348 /* BackgroundMusic.cpp */; + name = "BackgroundMusic.cpp: 514"; + rLen = 15; + rLoc = 16673; + rType = 0; + vrLen = 568; + vrLoc = 16207; + }; + 72881902108578270049CC03 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8483B0F941AAC00AB3C99 /* s_sound.c */; + name = "s_sound.c: 529"; + rLen = 0; + rLoc = 13821; + rType = 0; + vrLen = 773; + vrLoc = 13592; + }; + 728819031085784E0049CC03 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 724C531E0FBDBCEE000E4348 /* BackgroundMusic.cpp */; + name = "BackgroundMusic.cpp: 514"; + rLen = 15; + rLoc = 16673; + rType = 0; + vrLen = 330; + vrLoc = 16445; + }; + 728819041085784E0049CC03 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 728819051085784E0049CC03 /* asm __dyld__dyld_start 0x2fe01028 */; + name = "asm __dyld__dyld_start 0x2fe01028: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 589; + vrLoc = 0; + }; + 728819051085784E0049CC03 /* asm __dyld__dyld_start 0x2fe01028 */ = { + isa = PBXFileReference; + path = "asm __dyld__dyld_start 0x2fe01028"; + sourceTree = ""; + }; + 728819061085784E0049CC03 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 724C531E0FBDBCEE000E4348 /* BackgroundMusic.cpp */; + name = "BackgroundMusic.cpp: 514"; + rLen = 15; + rLoc = 16673; + rType = 0; + vrLen = 330; + vrLoc = 16445; + }; + 728819071085784E0049CC03 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8483B0F941AAC00AB3C99 /* s_sound.c */; + name = "s_sound.c: 529"; + rLen = 0; + rLoc = 13821; + rType = 0; + vrLen = 569; + vrLoc = 13481; + }; + 72881909108578560049CC03 /* BackgroundMusic.cpp:500 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 724C531E0FBDBCEE000E4348 /* BackgroundMusic.cpp */; + functionName = "iphoneStartMusic()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 500; + location = Doom; + modificationTime = 277182558.068104; + state = 2; + }; + 7288D1111018CBE900678FAC /* iphone_async.c:615 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43DD8391100295F70006E1DD /* iphone_async.c */; + functionName = "iphoneBuildTiccmd()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 615; + location = doom; + modificationTime = 277182472.336765; + state = 2; + }; + 7288D11F1018F64000678FAC /* iphone_loop.c:1657 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneDrawScreen()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1657; + location = doom; + modificationTime = 277182472.336992; + state = 2; + }; + 7288D1901019115700678FAC /* iphone_async.c:435 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43DD8391100295F70006E1DD /* iphone_async.c */; + functionName = "AxisHit()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 435; + location = doom; + modificationTime = 277182472.337212; + state = 2; + }; + 7288D1951019131400678FAC /* iphone_async.c:388 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43DD8391100295F70006E1DD /* iphone_async.c */; + functionName = "AxisHit()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 388; + location = doom; + modificationTime = 277182472.337431; + state = 2; + }; + 7288D1A61019133200678FAC /* iphone_loop.c:157 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "UpdateHudTouch()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 157; + location = doom; + modificationTime = 277182472.337645; + state = 2; + }; + 7288D1EA101A165800678FAC /* s_sound.c:335 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E8483B0F941AAC00AB3C99 /* s_sound.c */; + functionName = "S_StartSoundAtVolume()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 335; + location = doom; + modificationTime = 277182472.337859; + state = 2; + }; + 7288D1EF101A16CD00678FAC /* s_sound.c:426 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E8483B0F941AAC00AB3C99 /* s_sound.c */; + functionName = "S_UpdateSounds()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 426; + location = doom; + modificationTime = 277182472.338137; + state = 2; + }; + 7288D22B101A16FD00678FAC /* iphone_loop.c:1471 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneFrame()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1471; + location = doom; + modificationTime = 277182472.338403; + state = 2; + }; + 7288D22E101A172100678FAC /* iphone_loop.c:1473 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneFrame()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1473; + location = doom; + modificationTime = 277182472.338635; + state = 2; + }; + 72973A2E0FF1784300F813E6 /* iphone_loop.c:1401 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneFrame()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1401; + location = doom; + modificationTime = 277182472.306964; + state = 2; + }; + 72973A560FF2AF0C00F813E6 /* iphone_loop.c:1443 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneFrame()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1443; + location = doom; + modificationTime = 277182472.307113; + state = 2; + }; + 72973ACF0FF51FC300F813E6 /* iphone_loop.c:1125 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneBuildTiccmd()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1125; + location = doom; + modificationTime = 277182472.30727; + state = 2; + }; + 72973ADA0FF51FD700F813E6 /* iphone_loop.c:1286 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneAsyncTic()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1286; + location = doom; + modificationTime = 277182472.307442; + state = 2; + }; + 72973B310FF5259E00F813E6 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8476F0F93FFDB00AB3C99 /* d_client.c */; + name = "d_client.c: 287"; + rLen = 0; + rLoc = 8451; + rType = 0; + vrLen = 674; + vrLoc = 8223; + }; + 72973B410FF52D1A00F813E6 /* iphone_menus.c:27 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "iphoneDrawMenus()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 27; + location = doom; + modificationTime = 277182472.307593; + state = 2; + }; + 72973B730FF52F2500F813E6 /* iphone_main.c:237 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43E8D2DF0F4FC61E003F09B2 /* iphone_main.c */; + functionName = "iphoneStartup()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 237; + location = doom; + modificationTime = 277182472.307746; + state = 2; + }; + 72973B7A0FF52F5800F813E6 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 724C643B0FCC46E2000E4348 /* OSByteOrder.h */; + name = "OSByteOrder.h: 28"; + rLen = 0; + rLoc = 511; + rType = 0; + vrLen = 374; + vrLoc = 324; + }; + 72973BC00FF5471D00F813E6 /* iphone_main.c:237 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43E8D2DF0F4FC61E003F09B2 /* iphone_main.c */; + functionName = "iphoneStartup()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 237; + location = doom; + modificationTime = 277182472.307959; + state = 2; + }; + 72973C0E0FF54A9700F813E6 /* iphone_sound.c:27 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E731EA0F97E68100E702CD /* iphone_sound.c */; + functionName = "Sound_StopChannel()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 27; + location = doom; + modificationTime = 277182472.308167; + state = 2; + }; + 72A55D361002AC4A00F788A5 /* iphone_async.c:110 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43DD8391100295F70006E1DD /* iphone_async.c */; + functionName = "iphoneProcessPacket()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 110; + location = doom; + modificationTime = 277182472.319181; + state = 2; + }; + 72A55D451002ACBB00F788A5 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43DD8391100295F70006E1DD /* iphone_async.c */; + name = "iphone_async.c: 54"; + rLen = 0; + rLoc = 5788; + rType = 0; + vrLen = 896; + vrLoc = 14870; + }; + 72A55DB81002B04600F788A5 /* iphone_menus.c:883 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "ProcessSetupPackets()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 883; + location = doom; + modificationTime = 277182472.319357; + state = 2; + }; + 72A55DCE1002B27400F788A5 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8484E0F941ADC00AB3C99 /* v_video.c */; + name = "v_video.c: 576"; + rLen = 0; + rLoc = 18456; + rType = 0; + vrLen = 1203; + vrLoc = 18023; + }; + 72A55DDC1002C17900F788A5 /* iphone_menus.c:883 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "ProcessSetupPackets()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 883; + location = doom; + modificationTime = 277182472.319533; + state = 2; + }; + 72A55DDE1002C18000F788A5 /* iphone_menus.c:883 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "ProcessSetupPackets()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 883; + location = doom; + modificationTime = 277182472.319719; + state = 2; + }; + 72A55E031002C44500F788A5 /* iphone_menus.c:363 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "SendSetupPacket()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 363; + location = doom; + modificationTime = 277182472.319905; + state = 2; + }; + 72A55E1A1002C7C800F788A5 /* iphone_menus.c:363 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "SendSetupPacket()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 363; + location = doom; + modificationTime = 277182472.320083; + state = 2; + }; + 72A55E2E1002C8BA00F788A5 /* iphone_menus.c:883 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "ProcessSetupPackets()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 883; + location = doom; + modificationTime = 277182472.320264; + state = 2; + }; + 72A55E3E1002CFEC00F788A5 /* iphone_menus.c:883 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "ProcessSetupPackets()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 883; + location = doom; + modificationTime = 277182472.320453; + state = 2; + }; + 72A55E4C1002D02A00F788A5 /* iphone_main.c:314 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43E8D2DF0F4FC61E003F09B2 /* iphone_main.c */; + functionName = "iphoneStartup()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 314; + location = doom; + modificationTime = 277182472.320643; + state = 2; + }; + 72A55E7110039E9700F788A5 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8479B0F9400D700AB3C99 /* i_network.h */; + name = "i_network.h: 67"; + rLen = 11; + rLoc = 2235; + rType = 0; + vrLen = 700; + vrLoc = 1691; + }; + 72A55E851003A05700F788A5 /* iphone_loop.c:1486 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneFrame()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1486; + location = doom; + modificationTime = 277182472.320884; + state = 2; + }; + 72A55EBB1003A31100F788A5 /* iphone_async.c:808 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43DD8391100295F70006E1DD /* iphone_async.c */; + functionName = "iphoneAsyncTic()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 808; + location = doom; + modificationTime = 277182472.32106; + state = 2; + }; + 72A55ED41003A56700F788A5 /* iphone_main.c:468 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43E8D2DF0F4FC61E003F09B2 /* iphone_main.c */; + functionName = "iphoneShutdown()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 468; + location = doom; + modificationTime = 277182472.321238; + state = 2; + }; + 72A55EEE1003A94300F788A5 /* iphone_start.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {885, 4123}}"; + sepNavSelRange = "{332, 16}"; + sepNavVisRange = "{73, 631}"; + sepNavWindowFrame = "{{98, 25}, {882, 977}}"; + }; + }; + 72A55EF31003B06400F788A5 /* iphone_menus.c:726 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "iphoneStartLevel()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 726; + location = doom; + modificationTime = 277182472.321485; + state = 2; + }; + 72A55EF51003B07200F788A5 /* iphone_start.c:108 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A55EEE1003A94300F788A5 /* iphone_start.c */; + functionName = "StartSinglePlayerGame()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 108; + location = doom; + modificationTime = 277182472.321671; + state = 2; + }; + 72A55F381003B1E200F788A5 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E84A280F9503F100AB3C99 /* cmd.c */; + name = "cmd.c: 127"; + rLen = 12; + rLoc = 2450; + rType = 0; + vrLen = 699; + vrLoc = 2141; + }; + 72A55F391003B1E200F788A5 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8495C0F942B9300AB3C99 /* cvar.c */; + name = "cvar.c: 45"; + rLen = 10; + rLoc = 1227; + rType = 0; + vrLen = 617; + vrLoc = 1189; + }; + 72A55F3A1003B1E200F788A5 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8495E0F942B9300AB3C99 /* misc.c */; + name = "misc.c: 50"; + rLen = 0; + rLoc = 906; + rType = 0; + vrLen = 509; + vrLoc = 422; + }; + 72A55F631003BAAA00F788A5 /* iphone_async.c:121 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43DD8391100295F70006E1DD /* iphone_async.c */; + functionName = "iphoneProcessPacket()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 121; + location = doom; + modificationTime = 277182472.321887; + state = 2; + }; + 72A55F991003C0D400F788A5 /* iphone_start.c:208 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A55EEE1003A94300F788A5 /* iphone_start.c */; + functionName = "StartDemoGame()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 208; + location = doom; + modificationTime = 277182472.322088; + state = 2; + }; + 72A55FA51003C16300F788A5 /* iphone_loop.c:1342 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneFrame()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1342; + location = doom; + modificationTime = 277182472.322272; + state = 2; + }; + 72A55FB21003C3C100F788A5 /* iphone_start.c:195 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A55EEE1003A94300F788A5 /* iphone_start.c */; + functionName = "StartDemoGame()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 195; + location = doom; + modificationTime = 277182472.32245; + state = 2; + }; + 72A55FD41003D14900F788A5 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 434669A50F8D08C000EA7D6D /* doomAppDelegate.m */; + name = "doomAppDelegate.m: 176"; + rLen = 0; + rLoc = 5720; + rType = 0; + vrLen = 653; + vrLoc = 5373; + }; + 72A5604D1003E44400F788A5 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7229CC8E0F6B3363004123C5 /* doomiphone.h */; + name = "doomiphone.h: 91"; + rLen = 0; + rLoc = 2066; + rType = 0; + vrLen = 629; + vrLoc = 1781; + }; + 72A560551003E44400F788A5 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7229CC8E0F6B3363004123C5 /* doomiphone.h */; + name = "doomiphone.h: 91"; + rLen = 0; + rLoc = 2066; + rType = 0; + vrLen = 629; + vrLoc = 1781; + }; + 72A560BC1004031F00F788A5 /* iphone_async.c:116 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43DD8391100295F70006E1DD /* iphone_async.c */; + functionName = "iphoneProcessPacket()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 116; + location = doom; + modificationTime = 277182472.322642; + state = 2; + }; + 72A560C5100403E900F788A5 /* iphone_async.c:715 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43DD8391100295F70006E1DD /* iphone_async.c */; + functionName = "ShouldSendPacket()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 715; + location = doom; + modificationTime = 277182472.322831; + state = 2; + }; + 72A560E11004FAEE00F788A5 /* iphone_net.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1099, 11324}}"; + sepNavSelRange = "{15868, 0}"; + sepNavVisRange = "{15469, 684}"; + sepNavWindowFrame = "{{75, 46}, {882, 977}}"; + }; + }; + 72A560ED1005212200F788A5 /* iphone_net.c:38 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A560E11004FAEE00F788A5 /* iphone_net.c */; + functionName = "DNSServiceBrowseReplyCallback()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 38; + location = doom; + modificationTime = 277182472.323017; + state = 2; + }; + 72A56111100521C700F788A5 /* iphone_net.c:365 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A560E11004FAEE00F788A5 /* iphone_net.c */; + functionName = "ProcessDNSMessages()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 365; + location = doom; + modificationTime = 277182472.323209; + state = 2; + }; + 72A5613810052AD900F788A5 /* iphone_main.c:314 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43E8D2DF0F4FC61E003F09B2 /* iphone_main.c */; + functionName = "iphoneStartup()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 314; + location = doom; + modificationTime = 277182472.323402; + state = 2; + }; + 72A6EEFA0FABCA670000A7A0 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848530F941ADC00AB3C99 /* w_mmap.c */; + name = "w_mmap.c: 272"; + rLen = 0; + rLoc = 6859; + rType = 0; + vrLen = 626; + vrLoc = 6471; + }; + 72A6EEFC0FABCA670000A7A0 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847FA0F941A5900AB3C99 /* p_setup.c */; + name = "p_setup.c: 1673"; + rLen = 0; + rLoc = 52386; + rType = 0; + vrLen = 352; + vrLoc = 52173; + }; + 72A6EF3D0FABCE0D0000A7A0 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847820F9400D700AB3C99 /* d_ticcmd.h */; + name = "d_ticcmd.h: 57"; + rLen = 12; + rLoc = 2067; + rType = 0; + vrLen = 773; + vrLoc = 1314; + }; + 72A6EFEA0FABE6ED0000A7A0 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847980F9400D700AB3C99 /* hu_stuff.h */; + name = "hu_stuff.h: 9"; + rLen = 1; + rLoc = 369; + rType = 0; + vrLen = 1334; + vrLoc = 2061; + }; + 72A6EFEB0FABE6ED0000A7A0 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847960F9400D700AB3C99 /* hu_lib.h */; + name = "hu_lib.h: 224"; + rLen = 10; + rLoc = 6022; + rType = 0; + vrLen = 566; + vrLoc = 5917; + }; + 72A6EFF20FABE6ED0000A7A0 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847980F9400D700AB3C99 /* hu_stuff.h */; + name = "hu_stuff.h: 9"; + rLen = 1; + rLoc = 369; + rType = 0; + vrLen = 1334; + vrLoc = 2061; + }; + 72A6EFF30FABE6ED0000A7A0 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847960F9400D700AB3C99 /* hu_lib.h */; + name = "hu_lib.h: 224"; + rLen = 10; + rLoc = 6022; + rType = 0; + vrLen = 566; + vrLoc = 5917; + }; + 72A6EFF40FABE6ED0000A7A0 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848210F941A8300AB3C99 /* r_defs.h */; + name = "r_defs.h: 332"; + rLen = 0; + rLoc = 10940; + rType = 0; + vrLen = 945; + vrLoc = 4283; + }; + 72A6F0010FABE81E0000A7A0 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8484F0F941ADC00AB3C99 /* v_video.h */; + name = "v_video.h: 158"; + rLen = 40; + rLoc = 5331; + rType = 0; + vrLen = 1205; + vrLoc = 4766; + }; + 72A6F0040FABE81E0000A7A0 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848540F941ADC00AB3C99 /* w_wad.c */; + name = "w_wad.c: 442"; + rLen = 12; + rLoc = 13925; + rType = 0; + vrLen = 510; + vrLoc = 13764; + }; + 72A6F0480FAF3E350000A7A0 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848390F941AAC00AB3C99 /* r_things.c */; + name = "r_things.c: 449"; + rLen = 6330; + rLoc = 14085; + rType = 0; + vrLen = 744; + vrLoc = 13723; + }; + 72A6F0F00FAF7C5F0000A7A0 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847F60F941A5900AB3C99 /* p_pspr.c */; + name = "p_pspr.c: 171"; + rLen = 1253; + rLoc = 5073; + rType = 0; + vrLen = 834; + vrLoc = 4747; + }; + 72A6F11A0FAF7E860000A7A0 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8495D0F942B9300AB3C99 /* cvar.h */; + name = "cvar.h: 99"; + rLen = 0; + rLoc = 2507; + rType = 0; + vrLen = 755; + vrLoc = 2433; + }; + 72A7E8F30F5F2001005B83C0 /* iphone_doom.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {868, 10450}}"; + sepNavSelRange = "{10409, 0}"; + sepNavVisRange = "{9821, 1463}"; + sepNavWindowFrame = "{{110, 47}, {907, 950}}"; + }; + }; + 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {892, 17461}}"; + sepNavSelRange = "{16581, 0}"; + sepNavVisRange = "{16010, 710}"; + sepNavWindowFrame = "{{342, 184}, {838, 824}}"; + }; + }; + 72AC934C107E927700D77CA8 /* iphone_loop.c:1668 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneDrawScreen()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1668; + location = doom; + modificationTime = 277182472.346132; + state = 2; + }; + 72AC9350107E92FC00D77CA8 /* iphone_loop.c:357 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "HandleButton()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 357; + location = doom; + modificationTime = 277182472.346358; + state = 2; + }; + 72AC9353107E934200D77CA8 /* iphone_loop.c:270 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "HandleButton()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 270; + location = doom; + modificationTime = 277182472.346582; + state = 2; + }; + 72AC9368107E967100D77CA8 /* iphone_loop.c:284 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "HandleButton()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 284; + location = doom; + modificationTime = 277182472.346805; + state = 2; + }; + 72AC937B107E985A00D77CA8 /* iphone_loop.c:288 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "HandleButton()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 288; + location = doom; + modificationTime = 277182472.34703; + state = 2; + }; + 72AC937D107E986100D77CA8 /* iphone_loop.c:281 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "HandleButton()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 281; + location = doom; + modificationTime = 277182472.347255; + state = 2; + }; + 72AC937F107E986900D77CA8 /* iphone_loop.c:317 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "HandleButton()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 317; + location = doom; + modificationTime = 277182472.347471; + state = 2; + }; + 72AC9385107E997800D77CA8 /* iphone_loop.c:299 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "HandleButton()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 299; + location = doom; + modificationTime = 277182472.347698; + state = 2; + }; + 72AC938B107E99E300D77CA8 /* iphone_loop.c:318 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "HandleButton()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 318; + location = doom; + modificationTime = 277182472.347924; + state = 2; + }; + 72AC93D7107EA14200D77CA8 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847720F93FFDB00AB3C99 /* d_englsh.h */; + name = "d_englsh.h: 145"; + rLen = 0; + rLoc = 6189; + rType = 0; + vrLen = 1368; + vrLoc = 5374; + }; + 72AD09A80FA224D0000999A0 /* Doom */ = { + isa = PBXExecutable; + activeArgIndices = ( + ); + argumentStrings = ( + ); + autoAttachOnCrash = 1; + breakpointsEnabled = 1; + configStateDict = { + }; + customDataFormattersEnabled = 1; + debuggerPlugin = GDBDebugging; + disassemblyDisplayState = 0; + dylibVariantSuffix = ""; + enableDebugStr = 1; + environmentEntries = ( + ); + executableSystemSymbolLevel = 0; + executableUserSymbolLevel = 0; + libgmallocEnabled = 0; + name = Doom; + savedGlobals = { + }; + sourceDirectories = ( + ); + variableFormatDictionary = { + }; + }; + 72AD09AF0FA224DC000999A0 /* Source Control */ = { + isa = PBXSourceControlManager; + fallbackIsa = XCSourceControlManager; + isSCMEnabled = 0; + scmConfiguration = { + }; + }; + 72AD09B00FA224DC000999A0 /* Code sense */ = { + isa = PBXCodeSenseManager; + indexTemplatePath = ""; + }; + 72AD09B60FA22C8A000999A0 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + name = "iphone_loop.c: 878"; + rLen = 0; + rLoc = 1777; + rType = 0; + vrLen = 1316; + vrLoc = 19895; + }; + 72AD09B70FA22C8A000999A0 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72A7E8F30F5F2001005B83C0 /* iphone_doom.h */; + name = "iphone_wolf.h: 105"; + rLen = 0; + rLoc = 2895; + rType = 0; + vrLen = 978; + vrLoc = 2245; + }; + 72AD09B80FA22C8A000999A0 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43E8D2DF0F4FC61E003F09B2 /* iphone_main.c */; + name = "iphone_main.c: 151"; + rLen = 0; + rLoc = 5563; + rType = 0; + vrLen = 675; + vrLoc = 3818; + }; + 72AD09BB0FA22C8A000999A0 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + name = "iphone_menus.c: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1171; + vrLoc = 0; + }; + 72AD09CC0FA22D58000999A0 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847940F9400D700AB3C99 /* gl_texture.c */; + name = "gl_texture.c: 831"; + rLen = 54; + rLoc = 26227; + rType = 0; + vrLen = 1521; + vrLoc = 25463; + }; + 72AD09DA0FA23046000999A0 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72D50DBB0F8ED98000BB49E6 /* ipak.c */; + name = "ipak.c: 285"; + rLen = 0; + rLoc = 8937; + rType = 0; + vrLen = 566; + vrLoc = 6945; + }; + 72AD09DB0FA23046000999A0 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72B5FF380F7E5C3D00C8A372 /* hud.c */; + name = "hud.c: 54"; + rLen = 0; + rLoc = 1576; + rType = 0; + vrLen = 1263; + vrLoc = 1013; + }; + 72AD0A0B0FA23674000999A0 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72D50DBA0F8ED98000BB49E6 /* ipak.h */; + name = "ipak.h: 112"; + rLen = 11; + rLoc = 3640; + rType = 0; + vrLen = 1074; + vrLoc = 1123; + }; + 72AD0A6C0FA4961E000999A0 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7239452B0F9C0E7500EADD62 /* iphone_mapSelect.c */; + name = "iphone_mapSelect.c: 218"; + rLen = 0; + rLoc = 6963; + rType = 0; + vrLen = 579; + vrLoc = 7029; + }; + 72AD0A810FA4961E000999A0 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7229CE460F6C89F8004123C5 /* EAGLView.m */; + name = "EAGLView.m: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 650; + vrLoc = 0; + }; + 72AD0BEC0FA62D9E000999A0 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72AD0BED0FA62D9E000999A0 /* unistd.h */; + name = "unistd.h: 422"; + rLen = 41; + rLoc = 14661; + rType = 0; + vrLen = 862; + vrLoc = 14159; + }; + 72AD0BED0FA62D9E000999A0 /* unistd.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = unistd.h; + path = /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.0.sdk/usr/include/unistd.h; + sourceTree = ""; + }; + 72AD0BF50FA62D9E000999A0 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848030F941A5900AB3C99 /* p_user.c */; + name = "p_user.c: 407"; + rLen = 10; + rLoc = 11100; + rType = 0; + vrLen = 616; + vrLoc = 10635; + }; + 72AD0BF60FA62D9E000999A0 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847EF0F941A5900AB3C99 /* p_map.c */; + name = "p_map.c: 1730"; + rLen = 721; + rLoc = 49972; + rType = 0; + vrLen = 525; + vrLoc = 49879; + }; + 72AD0BF80FA62D9E000999A0 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847F10F941A5900AB3C99 /* p_maputl.c */; + name = "p_maputl.c: 568"; + rLen = 71; + rLoc = 16660; + rType = 0; + vrLen = 583; + vrLoc = 17224; + }; + 72AD0C020FA62D9E000999A0 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847FE0F941A5900AB3C99 /* p_spec.h */; + name = "p_spec.h: 541"; + rLen = 12; + rLoc = 11085; + rType = 0; + vrLen = 398; + vrLoc = 10835; + }; + 72AD0C060FA62D9E000999A0 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72AD0C070FA62D9E000999A0 /* unistd.h */; + name = "unistd.h: 422"; + rLen = 41; + rLoc = 14661; + rType = 0; + vrLen = 862; + vrLoc = 14159; + }; + 72AD0C070FA62D9E000999A0 /* unistd.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = unistd.h; + path = /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.0.sdk/usr/include/unistd.h; + sourceTree = ""; + }; + 72AD0C2C0FA63091000999A0 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 434669A50F8D08C000EA7D6D /* doomAppDelegate.m */; + name = "doomAppDelegate.m: 174"; + rLen = 15; + rLoc = 6884; + rType = 0; + vrLen = 687; + vrLoc = 4308; + }; + 72AD0CAA0FA64E09000999A0 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 29B97316FDCFA39411CA2CEA /* main.m */; + name = "main.m: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 887; + vrLoc = 0; + }; + 72B0E92F0FBC872600D1D1FA /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847A90F9400D700AB3C99 /* m_fixed.h */; + name = "m_fixed.h: 130"; + rLen = 0; + rLoc = 3521; + rType = 0; + vrLen = 478; + vrLoc = 3217; + }; + 72B0E9300FBC872600D1D1FA /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847F10F941A5900AB3C99 /* p_maputl.c */; + name = "p_maputl.c: 626"; + rLen = 0; + rLoc = 17965; + rType = 0; + vrLen = 772; + vrLoc = 15843; + }; + 72B0E93F0FBC872600D1D1FA /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847FF0F941A5900AB3C99 /* p_switch.c */; + name = "p_switch.c: 240"; + rLen = 0; + rLoc = 7945; + rType = 0; + vrLen = 770; + vrLoc = 12307; + }; + 72B0E9A30FBC8F3600D1D1FA /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8478C0F9400D700AB3C99 /* f_finale.h */; + name = "f_finale.h: 27"; + rLen = 0; + rLoc = 1257; + rType = 0; + vrLen = 808; + vrLoc = 726; + }; + 72B0E9A40FBC8F3600D1D1FA /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8478B0F9400D700AB3C99 /* f_finale.c */; + name = "f_finale.c: 46"; + rLen = 6; + rLoc = 1718; + rType = 0; + vrLen = 1029; + vrLoc = 1329; + }; + 72B0E9A80FBC8F3600D1D1FA /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8478C0F9400D700AB3C99 /* f_finale.h */; + name = "f_finale.h: 27"; + rLen = 0; + rLoc = 1257; + rType = 0; + vrLen = 808; + vrLoc = 726; + }; + 72B0E9D40FBCDCDC00D1D1FA /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847EC0F941A5900AB3C99 /* p_inter.c */; + name = "p_inter.c: 365"; + rLen = 9; + rLoc = 9775; + rType = 0; + vrLen = 778; + vrLoc = 9092; + }; + 72B0EA0A0FBCE5F600D1D1FA /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847FE0F941A5900AB3C99 /* p_spec.h */; + name = "p_spec.h: 101"; + rLen = 37; + rLoc = 2831; + rType = 0; + vrLen = 779; + vrLoc = 2900; + }; + 72B2B1D70FB9BA7D00AAFC45 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8477F0F9400D700AB3C99 /* d_player.h */; + name = "d_player.h: 226"; + rLen = 10; + rLoc = 5899; + rType = 0; + vrLen = 495; + vrLoc = 5532; + }; + 72B2B2C60FB9DC5900AAFC45 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847AB0F9400D700AB3C99 /* m_menu.h */; + name = "m_menu.h: 76"; + rLen = 6; + rLoc = 2387; + rType = 0; + vrLen = 799; + vrLoc = 1874; + }; + 72B2B2CA0FB9DC5900AAFC45 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8478B0F9400D700AB3C99 /* f_finale.c */; + name = "f_finale.c: 75"; + rLen = 26; + rLoc = 2812; + rType = 0; + vrLen = 761; + vrLoc = 2512; + }; + 72B2B2CB0FB9DC5900AAFC45 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847AB0F9400D700AB3C99 /* m_menu.h */; + name = "m_menu.h: 76"; + rLen = 6; + rLoc = 2387; + rType = 0; + vrLen = 799; + vrLoc = 1874; + }; + 72B4A6C40FAB633200DC59D9 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8495C0F942B9300AB3C99 /* cvar.c */; + name = "cvar.c: 180"; + rLen = 0; + rLoc = 4038; + rType = 0; + vrLen = 62; + vrLoc = 7529; + }; + 72B4A6CE0FAB633200DC59D9 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847850F9400D700AB3C99 /* doomdef.h */; + name = "doomdef.h: 196"; + rLen = 124; + rLoc = 5190; + rType = 0; + vrLen = 657; + vrLoc = 4953; + }; + 72B4A7610FAB7B6100DC59D9 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7229CE540F6C8CDE004123C5 /* gles_glue.c */; + name = "gles_glue.c: 55"; + rLen = 419; + rLoc = 1282; + rType = 0; + vrLen = 864; + vrLoc = 1107; + }; + 72B5FF380F7E5C3D00C8A372 /* hud.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {866, 3914}}"; + sepNavSelRange = "{3535, 0}"; + sepNavVisRange = "{1621, 1464}"; + sepNavWindowFrame = "{{100, 52}, {907, 950}}"; + }; + }; + 72B9E7450FCDF4A000939821 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847FF0F941A5900AB3C99 /* p_switch.c */; + name = "p_switch.c: 49"; + rLen = 8; + rLoc = 1806; + rType = 0; + vrLen = 1169; + vrLoc = 1578; + }; + 72B9E7730FCDFB4F00939821 /* iphone_loop.c:1125 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneBuildTiccmd()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1125; + location = doom; + modificationTime = 277182472.305309; + state = 2; + }; + 72B9E7770FCDFB5200939821 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847EF0F941A5900AB3C99 /* p_map.c */; + name = "p_map.c: 1600"; + rLen = 15; + rLoc = 46880; + rType = 0; + vrLen = 615; + vrLoc = 46798; + }; + 72B9E79F0FCDFCC500939821 /* iphone_loop.c:673 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneTouchEvent()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 673; + location = doom; + modificationTime = 277182472.305467; + state = 2; + }; + 72B9E7C60FCDFEB700939821 /* iphone_loop.c:1285 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "DropPlayer()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1285; + location = doom; + modificationTime = 277182472.305609; + state = 2; + }; + 72B9E7C80FCDFEC600939821 /* p_pspr.c:651 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E847F60F941A5900AB3C99 /* p_pspr.c */; + functionName = "P_BulletSlope()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 651; + location = doom; + modificationTime = 277182472.305755; + state = 2; + }; + 72B9E7EC0FCE14B600939821 /* p_pspr.c:628 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E847F60F941A5900AB3C99 /* p_pspr.c */; + functionName = "P_BulletSlope()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 628; + location = doom; + modificationTime = 277182472.305904; + state = 2; + }; + 72B9E7F10FCE18E500939821 /* p_pspr.c:617 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E847F60F941A5900AB3C99 /* p_pspr.c */; + functionName = "P_BulletSlope()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 617; + location = doom; + modificationTime = 277182472.306054; + state = 2; + }; + 72B9E7F50FCE199C00939821 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847880F9400D700AB3C99 /* doomtype.h */; + name = "doomtype.h: 107"; + rLen = 51; + rLoc = 3607; + rType = 0; + vrLen = 1135; + vrLoc = 3206; + }; + 72B9E7FA0FCE199C00939821 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847880F9400D700AB3C99 /* doomtype.h */; + name = "doomtype.h: 107"; + rLen = 51; + rLoc = 3607; + rType = 0; + vrLen = 1135; + vrLoc = 3206; + }; + 72B9E8170FCE1D5000939821 /* iphone_loop.c:1571 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneDrawScreen()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1571; + location = doom; + modificationTime = 277182472.306205; + state = 2; + }; + 72BA12571028B0D100DDB148 /* iphone_render.c:1247 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72484E5D0FB0E99900124E1C /* iphone_render.c */; + functionName = "NewDrawScene()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1247; + location = doom; + modificationTime = 277182472.342849; + state = 2; + }; + 72BA125A1028B0E100DDB148 /* iphone_render.c:912 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72484E5D0FB0E99900124E1C /* iphone_render.c */; + functionName = "IR_Subsector()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 912; + location = doom; + modificationTime = 277182472.343075; + state = 2; + }; + 72BA125C1028B0E300DDB148 /* iphone_render.c:927 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72484E5D0FB0E99900124E1C /* iphone_render.c */; + functionName = "IR_Subsector()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 927; + location = doom; + modificationTime = 277182472.343297; + state = 2; + }; + 72BA12631028B32000DDB148 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72484E5D0FB0E99900124E1C /* iphone_render.c */; + name = "iphone_render.c: 919"; + rLen = 0; + rLoc = 28667; + rType = 0; + vrLen = 1110; + vrLoc = 28234; + }; + 72BA126E1028BE8800DDB148 /* iphone_async.c:554 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43DD8391100295F70006E1DD /* iphone_async.c */; + functionName = "iphoneBuildTiccmd()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 554; + location = doom; + modificationTime = 277182472.343522; + state = 2; + }; + 72BA12711028BED300DDB148 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72A55EEE1003A94300F788A5 /* iphone_start.c */; + name = "iphone_start.c: 22"; + rLen = 16; + rLoc = 332; + rType = 0; + vrLen = 631; + vrLoc = 73; + }; + 72BA127E1028BF8A00DDB148 /* iphone_async.c:561 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43DD8391100295F70006E1DD /* iphone_async.c */; + functionName = "iphoneBuildTiccmd()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 561; + location = doom; + modificationTime = 277182472.343747; + state = 2; + }; + 72BA128E1028C19F00DDB148 /* iphone_async.c:561 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43DD8391100295F70006E1DD /* iphone_async.c */; + functionName = "iphoneBuildTiccmd()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 561; + location = doom; + modificationTime = 277182472.344029; + state = 2; + }; + 72BA129B1028C25200DDB148 /* EAGLView.m:194 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 7229CE460F6C89F8004123C5 /* EAGLView.m */; + functionName = "-handleTouches:"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 194; + location = doom; + modificationTime = 277182472.344244; + state = 2; + }; + 72BA12A61028C2C400DDB148 /* EAGLView.m:100 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 7229CE460F6C89F8004123C5 /* EAGLView.m */; + functionName = "-handleTouches:"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 100; + location = doom; + modificationTime = 277182472.344464; + state = 2; + }; + 72BA13141028C88A00DDB148 /* iphone_loop.c:248 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "HandleButton()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 248; + location = doom; + modificationTime = 277182472.344691; + state = 2; + }; + 72BA131A1028C8D200DDB148 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847F30F941A5900AB3C99 /* p_mobj.c */; + name = "p_mobj.c: 744"; + rLen = 0; + rLoc = 21969; + rType = 0; + vrLen = 1225; + vrLoc = 21541; + }; + 72BA13341028CA0100DDB148 /* iphone_sound.c:168 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E731EA0F97E68100E702CD /* iphone_sound.c */; + functionName = "ShowSound()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 168; + location = doom; + modificationTime = 277182472.344924; + state = 2; + }; + 72BA135A1028D36000DDB148 /* iphone_loop.c:301 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "HandleButton()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 301; + location = doom; + modificationTime = 277182472.34516; + state = 2; + }; + 72BA13661028D38200DDB148 /* iphone_loop.c:1667 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneDrawScreen()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1667; + location = doom; + modificationTime = 277182472.345441; + state = 2; + }; + 72BA139D1028D4E900DDB148 /* iphone_loop.c:1664 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneDrawScreen()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1664; + location = doom; + modificationTime = 277182472.345674; + state = 2; + }; + 72BA13A51028D52000DDB148 /* iphone_loop.c:270 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "HandleButton()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 270; + location = doom; + modificationTime = 277182472.345897; + state = 2; + }; + 72BCB43E0FB8C17C000EC406 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847A30F9400D700AB3C99 /* m_argv.c */; + name = "m_argv.c: 53"; + rLen = 0; + rLoc = 1847; + rType = 0; + vrLen = 567; + vrLoc = 1390; + }; + 72BCB4430FB8C17C000EC406 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847A30F9400D700AB3C99 /* m_argv.c */; + name = "m_argv.c: 53"; + rLen = 0; + rLoc = 1847; + rType = 0; + vrLen = 567; + vrLoc = 1390; + }; + 72BCB4710FB8DCB6000EC406 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847950F9400D700AB3C99 /* hu_lib.c */; + name = "hu_lib.c: 164"; + rLen = 0; + rLoc = 4081; + rType = 0; + vrLen = 793; + vrLoc = 3869; + }; + 72BCB4860FB8DCB6000EC406 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8484A0F941ADC00AB3C99 /* st_stuff.c */; + name = "st_stuff.c: 841"; + rLen = 9; + rLoc = 23635; + rType = 0; + vrLen = 626; + vrLoc = 23508; + }; + 72BCB4E20FB8DEDE000EC406 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848490F941ADC00AB3C99 /* st_lib.h */; + name = "st_lib.h: 44"; + rLen = 0; + rLoc = 1594; + rType = 0; + vrLen = 498; + vrLoc = 1277; + }; + 72BCB54A0FB8E380000EC406 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848480F941ADC00AB3C99 /* st_lib.c */; + name = "st_lib.c: 301"; + rLen = 0; + rLoc = 7775; + rType = 0; + vrLen = 671; + vrLoc = 7299; + }; + 72BCB56A0FB8E4B7000EC406 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848540F941ADC00AB3C99 /* w_wad.c */; + name = "w_wad.c: 370"; + rLen = 0; + rLoc = 12065; + rType = 0; + vrLen = 599; + vrLoc = 11764; + }; + 72BCB5830FB8E5B1000EC406 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848300F941AAC00AB3C99 /* r_patch.c */; + name = "r_patch.c: 670"; + rLen = 0; + rLoc = 23166; + rType = 0; + vrLen = 583; + vrLoc = 22890; + }; + 72BCB5840FB8E5B1000EC406 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8481F0F941A8300AB3C99 /* r_data.c */; + name = "r_data.c: 736"; + rLen = 13; + rLoc = 22491; + rType = 0; + vrLen = 699; + vrLoc = 22128; + }; + 72BCB5860FB8E5B1000EC406 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848200F941A8300AB3C99 /* r_data.h */; + name = "r_data.h: 107"; + rLen = 13; + rLoc = 3676; + rType = 0; + vrLen = 1101; + vrLoc = 2638; + }; + 72BCB5A00FB8E713000EC406 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847730F93FFDB00AB3C99 /* d_event.h */; + name = "d_event.h: 76"; + rLen = 10; + rLoc = 1961; + rType = 0; + vrLen = 332; + vrLoc = 1796; + }; + 72BCB66B0FB8EADA000EC406 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848240F941A8300AB3C99 /* r_draw.c */; + name = "r_draw.c: 1090"; + rLen = 0; + rLoc = 34796; + rType = 0; + vrLen = 666; + vrLoc = 35138; + }; + 72BCB6D00FB8FB83000EC406 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847FD0F941A5900AB3C99 /* p_spec.c */; + name = "p_spec.c: 1086"; + rLen = 0; + rLoc = 30609; + rType = 0; + vrLen = 726; + vrLoc = 30226; + }; + 72BCB7530FB90A87000EC406 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7229CE540F6C8CDE004123C5 /* gles_glue.c */; + name = "gles_glue.c: 194"; + rLen = 0; + rLoc = 4975; + rType = 0; + vrLen = 636; + vrLoc = 4474; + }; + 72BD33100FB486E0002E4055 /* opengl_error_break */ = { + isa = PBXSymbolicBreakpoint; + actions = ( + ); + breakpointStyle = 1; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + hitCount = 0; + ignoreCount = 0; + location = OpenGLES; + modificationTime = 277182472.353758; + state = 2; + symbolName = opengl_error_break; + }; + 72BD33500FB49A10002E4055 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72BD33510FB49A10002E4055 /* TinyGL.cpp */; + name = "TinyGL.cpp: 429"; + rLen = 2; + rLoc = 14484; + rType = 0; + vrLen = 688; + vrLoc = 14329; + }; + 72BD33510FB49A10002E4055 /* TinyGL.cpp */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + name = TinyGL.cpp; + path = /Users/johnc/dev/old/wolfrpg/xcode/Classes/TinyGL.cpp; + sourceTree = ""; + }; + 72BD33540FB49A10002E4055 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72BD33550FB49A10002E4055 /* TinyGL.cpp */; + name = "TinyGL.cpp: 429"; + rLen = 2; + rLoc = 14484; + rType = 0; + vrLen = 688; + vrLoc = 14329; + }; + 72BD33550FB49A10002E4055 /* TinyGL.cpp */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + name = TinyGL.cpp; + path = /Users/johnc/dev/old/wolfrpg/xcode/Classes/TinyGL.cpp; + sourceTree = ""; + }; + 72BD34BB0FB505C4002E4055 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847A60F9400D700AB3C99 /* m_bbox.h */; + name = "m_bbox.h: 47"; + rLen = 0; + rLoc = 1585; + rType = 0; + vrLen = 284; + vrLoc = 1452; + }; + 72BD34C10FB505C4002E4055 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847A60F9400D700AB3C99 /* m_bbox.h */; + name = "m_bbox.h: 47"; + rLen = 0; + rLoc = 1585; + rType = 0; + vrLen = 284; + vrLoc = 1452; + }; + 72C6A5F30FFBFCF20005E863 /* iphone_menus.c:181 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "SendSetupPacket()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 181; + location = doom; + modificationTime = 277182472.311319; + state = 2; + }; + 72C6A6000FFBFDC70005E863 /* iphone_menus.c:181 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "SendSetupPacket()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 181; + location = doom; + modificationTime = 277182472.311514; + state = 2; + }; + 72C6A6020FFBFDFB0005E863 /* iphone_menus.c:181 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "ProcessSetupPackets()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 181; + location = doom; + modificationTime = 277182472.311673; + state = 2; + }; + 72C6A6110FFC001E0005E863 /* iphone_menus.c:181 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "ProcessSetupPackets()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 181; + location = doom; + modificationTime = 277182472.31183; + state = 2; + }; + 72C6A6130FFC00250005E863 /* iphone_menus.c:181 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "ProcessSetupPackets()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 181; + location = doom; + modificationTime = 277182472.311984; + state = 2; + }; + 72C6A6180FFC00D70005E863 /* iphone_menus.c:181 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "SetupEmptyNetGame()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 181; + location = doom; + modificationTime = 277182472.31214; + state = 2; + }; + 72C6A61B0FFC038C0005E863 /* iphone_menus.c:181 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "iphoneMultiplayerMenu()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 181; + location = doom; + modificationTime = 277182472.312296; + state = 2; + }; + 72C6A63A0FFC0C930005E863 /* iphone_menus.c:181 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "iphoneMultiplayerMenu()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 181; + location = doom; + modificationTime = 277182472.312456; + state = 2; + }; + 72C6A64C0FFC0F0D0005E863 /* iphone_menus.c:181 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "SendJoinPacket()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 181; + location = doom; + modificationTime = 277182472.312616; + state = 2; + }; + 72C6A64E0FFC0F120005E863 /* iphone_menus.c:181 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + functionName = "iphoneMultiplayerMenu()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 181; + location = doom; + modificationTime = 277182472.312773; + state = 2; + }; + 72C6A65C0FFC16B20005E863 /* iphone_loop.c:1286 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneAsyncTic()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1286; + location = doom; + modificationTime = 277182472.312932; + state = 2; + }; + 72C6EB1E0FFBD0920085A32E /* iphone_loop.c:1286 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneAsyncTic()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1286; + location = doom; + modificationTime = 277182472.311165; + state = 2; + }; + 72D50DBA0F8ED98000BB49E6 /* ipak.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {848, 3116}}"; + sepNavSelRange = "{1593, 15}"; + sepNavVisRange = "{671, 1213}"; + sepNavWindowFrame = "{{123, 31}, {907, 950}}"; + }; + }; + 72D50DBB0F8ED98000BB49E6 /* ipak.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {868, 7828}}"; + sepNavSelRange = "{9919, 0}"; + sepNavVisRange = "{9547, 664}"; + sepNavWindowFrame = "{{146, 10}, {907, 950}}"; + }; + }; + 72DB56C1101A53BB00A58CED /* s_sound.c:330 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E8483B0F941AAC00AB3C99 /* s_sound.c */; + functionName = "S_StartSoundAtVolume()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 330; + location = doom; + modificationTime = 277182472.338861; + state = 2; + }; + 72DB56C3101A53BD00A58CED /* s_sound.c:334 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E8483B0F941AAC00AB3C99 /* s_sound.c */; + functionName = "S_StartSoundAtVolume()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 334; + location = doom; + modificationTime = 277182472.339126; + state = 2; + }; + 72DB56D1101A56B200A58CED /* s_sound.c:225 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E8483B0F941AAC00AB3C99 /* s_sound.c */; + functionName = "S_StartSoundAtVolume()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 225; + location = doom; + modificationTime = 277182472.339396; + state = 2; + }; + 72DB56D3101A56B500A58CED /* s_sound.c:244 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E8483B0F941AAC00AB3C99 /* s_sound.c */; + functionName = "S_StartSoundAtVolume()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 244; + location = doom; + modificationTime = 277182472.33968; + state = 2; + }; + 72DB56D5101A56BF00A58CED /* s_sound.c:264 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E8483B0F941AAC00AB3C99 /* s_sound.c */; + functionName = "S_StartSoundAtVolume()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 264; + location = doom; + modificationTime = 277182472.33996; + state = 2; + }; + 72DB56D9101A56DD00A58CED /* s_sound.c:262 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E8483B0F941AAC00AB3C99 /* s_sound.c */; + functionName = "S_StartSoundAtVolume()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 262; + location = doom; + modificationTime = 277182472.340243; + state = 2; + }; + 72DB56DC101A571A00A58CED /* s_sound.c:264 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E8483B0F941AAC00AB3C99 /* s_sound.c */; + functionName = "S_StartSoundAtVolume()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 264; + location = doom; + modificationTime = 277182472.340522; + state = 2; + }; + 72DB56EF101A57E700A58CED /* s_sound.c:264 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E8483B0F941AAC00AB3C99 /* s_sound.c */; + functionName = "S_StartSoundAtVolume()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 264; + modificationTime = 277182472.340813; + state = 2; + }; + 72DB56F1101A57E900A58CED /* s_sound.c:264 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72E8483B0F941AAC00AB3C99 /* s_sound.c */; + functionName = "S_StartSoundAtVolume()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 264; + location = doom; + modificationTime = 277182472.341093; + state = 2; + }; + 72DB5702101A58CB00A58CED /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E847E80F941A5900AB3C99 /* p_enemy.c */; + name = "p_enemy.c: 1239"; + rLen = 0; + rLoc = 34871; + rType = 0; + vrLen = 912; + vrLoc = 34353; + }; + 72DB5727101A617200A58CED /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E8483B0F941AAC00AB3C99 /* s_sound.c */; + name = "s_sound.c: 339"; + rLen = 0; + rLoc = 9401; + rType = 0; + vrLen = 736; + vrLoc = 9070; + }; + 72DB5743101A6A4500A58CED /* iphone_async.c:653 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43DD8391100295F70006E1DD /* iphone_async.c */; + functionName = "iphoneBuildTiccmd()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 653; + location = doom; + modificationTime = 277182472.341399; + state = 2; + }; + 72DB578C101A742600A58CED /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72D50DBB0F8ED98000BB49E6 /* ipak.c */; + name = "ipak.c: 360"; + rLen = 0; + rLoc = 9174; + rType = 0; + vrLen = 436; + vrLoc = 8876; + }; + 72DB579B101A78EF00A58CED /* iphone_loop.c:894 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "iphoneDrawHudControl()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 894; + location = doom; + modificationTime = 277182472.341667; + state = 2; + }; + 72DB579D101A78F300A58CED /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E849F50F94ED1100AB3C99 /* prboomInterface.c */; + name = "prboomInterface.c: 134"; + rLen = 0; + rLoc = 3062; + rType = 0; + vrLen = 680; + vrLoc = 2715; + }; + 72DB57CE101A80BB00A58CED /* iphone_mapSelect.c:342 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 7239452B0F9C0E7500EADD62 /* iphone_mapSelect.c */; + functionName = "iphoneMapSelectMenu()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 342; + location = doom; + modificationTime = 277182472.341901; + state = 2; + }; + 72DB57D0101A80E200A58CED /* iphone_mapSelect.c:341 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 7239452B0F9C0E7500EADD62 /* iphone_mapSelect.c */; + functionName = "iphoneMapSelectMenu()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 341; + location = doom; + modificationTime = 277182472.342163; + state = 2; + }; + 72E731EA0F97E68100E702CD /* iphone_sound.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1100, 5282}}"; + sepNavSelRange = "{6571, 0}"; + sepNavVisRange = "{6155, 698}"; + sepNavWindowFrame = "{{128, 6}, {907, 950}}"; + }; + }; + 72E7896F0FB762C1001FACDD /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E848380F941AAC00AB3C99 /* r_state.h */; + name = "r_state.h: 93"; + rLen = 32; + rLoc = 2517; + rType = 0; + vrLen = 686; + vrLoc = 2136; + }; + 72E847640F93C61900AB3C99 /* am_map.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {885, 29716}}"; + sepNavSelRange = "{2998, 87}"; + sepNavVisRange = "{2610, 1049}"; + }; + }; + 72E847680F93FF2F00AB3C99 /* config.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1099, 1995}}"; + sepNavSelRange = "{691, 11}"; + sepNavVisRange = "{116, 567}"; + }; + }; + 72E8476F0F93FFDB00AB3C99 /* d_client.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {885, 9747}}"; + sepNavSelRange = "{8451, 0}"; + sepNavVisRange = "{8223, 674}"; + sepNavWindowFrame = "{{77, 73}, {907, 950}}"; + }; + }; + 72E847700F93FFDB00AB3C99 /* d_deh.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {908, 58330}}"; + sepNavSelRange = "{83280, 5}"; + sepNavVisRange = "{85057, 955}"; + }; + }; + 72E847720F93FFDB00AB3C99 /* d_englsh.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {885, 12730}}"; + sepNavSelRange = "{6099, 0}"; + sepNavVisRange = "{4947, 1465}"; + }; + }; + 72E847730F93FFDB00AB3C99 /* d_event.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {850, 2375}}"; + sepNavSelRange = "{1961, 10}"; + sepNavVisRange = "{1796, 332}"; + }; + }; + 72E8477C0F9400D700AB3C99 /* d_main.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {885, 33402}}"; + sepNavSelRange = "{33438, 14}"; + sepNavVisRange = "{33057, 739}"; + sepNavWindowFrame = "{{124, 39}, {907, 950}}"; + }; + }; + 72E8477D0F9400D700AB3C99 /* d_main.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {885, 1539}}"; + sepNavSelRange = "{2001, 5}"; + sepNavVisRange = "{1583, 699}"; + }; + }; + 72E8477F0F9400D700AB3C99 /* d_player.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {885, 4180}}"; + sepNavSelRange = "{3755, 11}"; + sepNavVisRange = "{3369, 894}"; + }; + }; + 72E847820F9400D700AB3C99 /* d_ticcmd.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1099, 1140}}"; + sepNavSelRange = "{1975, 57}"; + sepNavVisRange = "{1465, 622}"; + }; + }; + 72E847830F9400D700AB3C99 /* doomdata.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {644, 3857}}"; + sepNavSelRange = "{3430, 38}"; + sepNavVisRange = "{3183, 485}"; + }; + }; + 72E847850F9400D700AB3C99 /* doomdef.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {885, 6536}}"; + sepNavSelRange = "{4259, 8}"; + sepNavVisRange = "{3935, 660}"; + }; + }; + 72E847870F9400D700AB3C99 /* doomstat.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {676, 6593}}"; + sepNavSelRange = "{3557, 14}"; + sepNavVisRange = "{3408, 431}"; + sepNavWindowFrame = "{{77, 46}, {882, 977}}"; + }; + }; + 72E847880F9400D700AB3C99 /* doomtype.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {668, 2261}}"; + sepNavSelRange = "{3607, 51}"; + sepNavVisRange = "{3206, 1135}"; + }; + }; + 72E8478B0F9400D700AB3C99 /* f_finale.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {848, 13053}}"; + sepNavSelRange = "{17714, 0}"; + sepNavVisRange = "{17112, 903}"; + sepNavWindowFrame = "{{77, 73}, {907, 950}}"; + }; + }; + 72E8478C0F9400D700AB3C99 /* f_finale.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {850, 1083}}"; + sepNavSelRange = "{1257, 0}"; + sepNavVisRange = "{726, 808}"; + }; + }; + 72E8478F0F9400D700AB3C99 /* g_game.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {885, 56012}}"; + sepNavSelRange = "{7415, 29}"; + sepNavVisRange = "{6935, 1025}"; + sepNavWindowFrame = "{{189, 94}, {838, 824}}"; + }; + }; + 72E847910F9400D700AB3C99 /* gl_intern.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {848, 4332}}"; + sepNavSelRange = "{2139, 0}"; + sepNavVisRange = "{1922, 701}"; + sepNavWindowFrame = "{{75, 45}, {907, 950}}"; + }; + }; + 72E847920F9400D700AB3C99 /* gl_main.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {972, 55347}}"; + sepNavSelRange = "{83427, 0}"; + sepNavVisRange = "{82539, 1515}"; + sepNavWindowFrame = "{{162, 62}, {907, 950}}"; + }; + }; + 72E847930F9400D700AB3C99 /* gl_struct.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {885, 1292}}"; + sepNavSelRange = "{2282, 13}"; + sepNavVisRange = "{1427, 960}"; + sepNavWindowFrame = "{{77, 73}, {907, 950}}"; + }; + }; + 72E847940F9400D700AB3C99 /* gl_texture.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {884, 21096}}"; + sepNavSelRange = "{25141, 0}"; + sepNavVisRange = "{28649, 438}"; + sepNavWindowFrame = "{{204, 23}, {907, 950}}"; + }; + }; + 72E847950F9400D700AB3C99 /* hu_lib.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {850, 14155}}"; + sepNavSelRange = "{4081, 0}"; + sepNavVisRange = "{3869, 793}"; + }; + }; + 72E847960F9400D700AB3C99 /* hu_lib.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1317, 4712}}"; + sepNavSelRange = "{6022, 10}"; + sepNavVisRange = "{5917, 566}"; + }; + }; + 72E847970F9400D700AB3C99 /* hu_stuff.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {885, 30031}}"; + sepNavSelRange = "{20829, 13}"; + sepNavVisRange = "{20534, 708}"; + }; + }; + 72E847980F9400D700AB3C99 /* hu_stuff.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1317, 1729}}"; + sepNavSelRange = "{369, 1}"; + sepNavVisRange = "{2061, 1334}"; + sepNavWindowFrame = "{{75, 73}, {907, 950}}"; + }; + }; + 72E8479B0F9400D700AB3C99 /* i_network.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {885, 1425}}"; + sepNavSelRange = "{1440, 0}"; + sepNavVisRange = "{1277, 775}"; + }; + }; + 72E8479C0F9400D700AB3C99 /* i_sound.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1317, 2204}}"; + sepNavSelRange = "{1909, 12}"; + sepNavVisRange = "{1528, 675}"; + }; + }; + 72E8479F0F9400D700AB3C99 /* info.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {848, 90953}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{5839, 2372}"; + sepNavWindowFrame = "{{75, 73}, {907, 950}}"; + }; + }; + 72E847A00F9400D700AB3C99 /* info.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {850, 26334}}"; + sepNavSelRange = "{20578, 7}"; + sepNavVisRange = "{19879, 1171}"; + }; + }; + 72E847A30F9400D700AB3C99 /* m_argv.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {850, 1121}}"; + sepNavSelRange = "{1847, 0}"; + sepNavVisRange = "{1390, 567}"; + }; + }; + 72E847A60F9400D700AB3C99 /* m_bbox.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {660, 1083}}"; + sepNavSelRange = "{1585, 0}"; + sepNavVisRange = "{1452, 284}"; + }; + }; + 72E847A70F9400D700AB3C99 /* m_cheat.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {885, 14383}}"; + sepNavSelRange = "{11614, 145}"; + sepNavVisRange = "{11119, 924}"; + sepNavWindowFrame = "{{95, 178}, {838, 824}}"; + }; + }; + 72E847A80F9400D700AB3C99 /* m_cheat.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {885, 1121}}"; + sepNavSelRange = "{1701, 4}"; + sepNavVisRange = "{1277, 554}"; + }; + }; + 72E847A90F9400D700AB3C99 /* m_fixed.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {850, 3971}}"; + sepNavSelRange = "{3521, 0}"; + sepNavVisRange = "{3217, 478}"; + }; + }; + 72E847AA0F9400D700AB3C99 /* m_menu.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {885, 106628}}"; + sepNavSelRange = "{86478, 4}"; + sepNavVisRange = "{86098, 1085}"; + }; + }; + 72E847AB0F9400D700AB3C99 /* m_menu.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {850, 3724}}"; + sepNavSelRange = "{2387, 6}"; + sepNavVisRange = "{1874, 799}"; + }; + }; + 72E847AC0F9400D700AB3C99 /* m_misc.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1343, 19855}}"; + sepNavSelRange = "{38172, 6}"; + sepNavVisRange = "{37503, 1351}"; + }; + }; + 72E847AE0F9400D700AB3C99 /* m_random.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1099, 3002}}"; + sepNavSelRange = "{4610, 0}"; + sepNavVisRange = "{4293, 673}"; + }; + }; + 72E847AF0F9400D700AB3C99 /* m_random.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {885, 2869}}"; + sepNavSelRange = "{5208, 10}"; + sepNavVisRange = "{4461, 961}"; + }; + }; + 72E847CA0F94096C00AB3C99 /* SDL_opengl.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1156, 4104}}"; + sepNavSelRange = "{1672, 53}"; + sepNavVisRange = "{1152, 1053}"; + sepNavWindowFrame = "{{75, 73}, {907, 950}}"; + }; + }; + 72E847E00F941A5900AB3C99 /* md5.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {850, 4579}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 1164}"; + }; + }; + 72E847E10F941A5900AB3C99 /* md5.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {850, 931}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 1093}"; + }; + }; + 72E847E40F941A5900AB3C99 /* p_ceilng.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {850, 8664}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 1417}"; + }; + }; + 72E847E50F941A5900AB3C99 /* p_checksum.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {885, 1938}}"; + sepNavSelRange = "{314, 0}"; + sepNavVisRange = "{0, 574}"; + }; + }; + 72E847E60F941A5900AB3C99 /* p_checksum.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {850, 626}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 151}"; + }; + }; + 72E847E70F941A5900AB3C99 /* p_doors.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {850, 13509}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 1406}"; + }; + }; + 72E847E80F941A5900AB3C99 /* p_enemy.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1099, 48241}}"; + sepNavSelRange = "{34871, 0}"; + sepNavVisRange = "{34612, 353}"; + }; + }; + 72E847E90F941A5900AB3C99 /* p_enemy.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {850, 2052}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 1389}"; + }; + }; + 72E847EC0F941A5900AB3C99 /* p_inter.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {885, 17081}}"; + sepNavSelRange = "{6157, 38}"; + sepNavVisRange = "{5661, 701}"; + }; + }; + 72E847EF0F941A5900AB3C99 /* p_map.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {885, 45505}}"; + sepNavSelRange = "{46880, 15}"; + sepNavVisRange = "{46798, 615}"; + sepNavWindowFrame = "{{77, 73}, {907, 950}}"; + }; + }; + 72E847F10F941A5900AB3C99 /* p_maputl.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {848, 13015}}"; + sepNavSelRange = "{5530, 42}"; + sepNavVisRange = "{5041, 1084}"; + sepNavWindowFrame = "{{96, 5}, {907, 950}}"; + }; + }; + 72E847F30F941A5900AB3C99 /* p_mobj.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1099, 28956}}"; + sepNavSelRange = "{21969, 0}"; + sepNavVisRange = "{21643, 880}"; + }; + }; + 72E847F40F941A5900AB3C99 /* p_mobj.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {885, 7410}}"; + sepNavSelRange = "{7877, 12}"; + sepNavVisRange = "{7319, 1028}"; + }; + }; + 72E847F60F941A5900AB3C99 /* p_pspr.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {885, 16416}}"; + sepNavSelRange = "{18483, 0}"; + sepNavVisRange = "{18247, 614}"; + }; + }; + 72E847F70F941A5900AB3C99 /* p_pspr.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {850, 2128}}"; + sepNavSelRange = "{2223, 7}"; + sepNavVisRange = "{1999, 516}"; + }; + }; + 72E847F80F941A5900AB3C99 /* p_saveg.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1313, 19266}}"; + sepNavSelRange = "{31273, 8}"; + sepNavVisRange = "{30844, 860}"; + }; + }; + 72E847FA0F941A5900AB3C99 /* p_setup.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {885, 32224}}"; + sepNavSelRange = "{41926, 7}"; + sepNavVisRange = "{41379, 707}"; + }; + }; + 72E847FC0F941A5900AB3C99 /* p_sight.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1076, 6346}}"; + sepNavSelRange = "{2231, 0}"; + sepNavVisRange = "{1818, 832}"; + }; + }; + 72E847FD0F941A5900AB3C99 /* p_spec.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {644, 62909}}"; + sepNavSelRange = "{65715, 0}"; + sepNavVisRange = "{65531, 529}"; + sepNavWindowFrame = "{{75, 28}, {907, 950}}"; + }; + }; + 72E847FE0F941A5900AB3C99 /* p_spec.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {850, 20995}}"; + sepNavSelRange = "{2831, 37}"; + sepNavVisRange = "{2900, 779}"; + }; + }; + 72E847FF0F941A5900AB3C99 /* p_switch.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {885, 22097}}"; + sepNavSelRange = "{1806, 8}"; + sepNavVisRange = "{1578, 1169}"; + sepNavWindowFrame = "{{123, 31}, {907, 950}}"; + }; + }; + 72E848030F941A5900AB3C99 /* p_user.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {885, 8512}}"; + sepNavSelRange = "{8199, 38}"; + sepNavVisRange = "{7472, 727}"; + }; + }; + 72E8481C0F941A8300AB3C99 /* protocol.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {850, 1805}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 1428}"; + }; + }; + 72E8481D0F941A8300AB3C99 /* r_bsp.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {848, 12901}}"; + sepNavSelRange = "{13022, 10}"; + sepNavVisRange = "{13001, 1139}"; + sepNavWindowFrame = "{{330, 49}, {907, 950}}"; + }; + }; + 72E8481E0F941A8300AB3C99 /* r_bsp.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {850, 1083}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 1415}"; + }; + }; + 72E8481F0F941A8300AB3C99 /* r_data.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {644, 14269}}"; + sepNavSelRange = "{22491, 13}"; + sepNavVisRange = "{22194, 633}"; + }; + }; + 72E848200F941A8300AB3C99 /* r_data.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {850, 2014}}"; + sepNavSelRange = "{3676, 13}"; + sepNavVisRange = "{2638, 1101}"; + }; + }; + 72E848210F941A8300AB3C99 /* r_defs.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {885, 8151}}"; + sepNavSelRange = "{5362, 12}"; + sepNavVisRange = "{3372, 1275}"; + sepNavWindowFrame = "{{75, 73}, {907, 950}}"; + }; + }; + 72E848220F941A8300AB3C99 /* r_demo.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {885, 1596}}"; + sepNavSelRange = "{1728, 0}"; + sepNavVisRange = "{1515, 762}"; + }; + }; + 72E848230F941A8300AB3C99 /* r_demo.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {850, 874}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 1389}"; + }; + }; + 72E848240F941A8300AB3C99 /* r_draw.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {850, 21280}}"; + sepNavSelRange = "{8868, 0}"; + sepNavVisRange = "{8719, 826}"; + }; + }; + 72E848250F941A8300AB3C99 /* r_draw.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {850, 2983}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 1404}"; + }; + }; + 72E8482B0F941AAC00AB3C99 /* r_filter.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {850, 3610}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 1383}"; + }; + }; + 72E8482C0F941AAC00AB3C99 /* r_fps.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1228, 8588}}"; + sepNavSelRange = "{3100, 0}"; + sepNavVisRange = "{2379, 1096}"; + }; + }; + 72E8482D0F941AAC00AB3C99 /* r_fps.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {850, 1463}}"; + sepNavSelRange = "{1772, 8}"; + sepNavVisRange = "{1463, 351}"; + }; + }; + 72E8482E0F941AAC00AB3C99 /* r_main.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {885, 12293}}"; + sepNavSelRange = "{17250, 13}"; + sepNavVisRange = "{15894, 600}"; + }; + }; + 72E8482F0F941AAC00AB3C99 /* r_main.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {850, 2185}}"; + sepNavSelRange = "{3370, 39}"; + sepNavVisRange = "{2895, 891}"; + }; + }; + 72E848300F941AAC00AB3C99 /* r_patch.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {716, 15143}}"; + sepNavSelRange = "{23360, 0}"; + sepNavVisRange = "{23046, 622}"; + }; + }; + 72E848310F941AAC00AB3C99 /* r_patch.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {850, 1881}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 1381}"; + }; + }; + 72E848320F941AAC00AB3C99 /* r_plane.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {850, 8683}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 1462}"; + }; + }; + 72E848330F941AAC00AB3C99 /* r_plane.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {850, 1159}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 1414}"; + }; + }; + 72E848340F941AAC00AB3C99 /* r_segs.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {850, 16302}}"; + sepNavSelRange = "{16330, 100}"; + sepNavVisRange = "{15793, 834}"; + }; + }; + 72E848360F941AAC00AB3C99 /* r_sky.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {850, 855}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 1476}"; + }; + }; + 72E848370F941AAC00AB3C99 /* r_sky.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {850, 893}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 1386}"; + }; + }; + 72E848380F941AAC00AB3C99 /* r_state.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {850, 2185}}"; + sepNavSelRange = "{2517, 32}"; + sepNavVisRange = "{2136, 686}"; + sepNavWindowFrame = "{{98, 52}, {907, 950}}"; + }; + }; + 72E848390F941AAC00AB3C99 /* r_things.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {885, 20140}}"; + sepNavSelRange = "{5083, 0}"; + sepNavVisRange = "{4731, 932}"; + sepNavWindowFrame = "{{100, 52}, {907, 950}}"; + }; + }; + 72E8483A0F941AAC00AB3C99 /* r_things.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {850, 1368}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 1409}"; + }; + }; + 72E8483B0F941AAC00AB3C99 /* s_sound.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1099, 14329}}"; + sepNavSelRange = "{13871, 0}"; + sepNavVisRange = "{13589, 574}"; + sepNavWindowFrame = "{{74, 46}, {882, 977}}"; + }; + }; + 72E8483C0F941AAC00AB3C99 /* s_sound.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {850, 1653}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 1415}"; + }; + }; + 72E848460F941ADC00AB3C99 /* sounds.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {850, 4503}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 1438}"; + }; + }; + 72E848470F941ADC00AB3C99 /* sounds.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {850, 4883}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 1471}"; + }; + }; + 72E848480F941ADC00AB3C99 /* st_lib.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {732, 7049}}"; + sepNavSelRange = "{5056, 0}"; + sepNavVisRange = "{4880, 487}"; + }; + }; + 72E848490F941ADC00AB3C99 /* st_lib.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {850, 3420}}"; + sepNavSelRange = "{1594, 0}"; + sepNavVisRange = "{1277, 498}"; + }; + }; + 72E8484A0F941ADC00AB3C99 /* st_stuff.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {885, 22382}}"; + sepNavSelRange = "{13081, 12}"; + sepNavVisRange = "{12544, 754}"; + }; + }; + 72E8484B0F941ADC00AB3C99 /* st_stuff.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {850, 1767}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 1431}"; + }; + }; + 72E8484C0F941ADC00AB3C99 /* tables.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {850, 2223}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 1379}"; + }; + }; + 72E8484D0F941ADC00AB3C99 /* tables.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {850, 1577}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 1379}"; + }; + }; + 72E8484E0F941ADC00AB3C99 /* v_video.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {885, 19421}}"; + sepNavSelRange = "{18456, 0}"; + sepNavVisRange = "{18023, 1188}"; + }; + }; + 72E8484F0F941ADC00AB3C99 /* v_video.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {885, 3857}}"; + sepNavSelRange = "{2189, 9}"; + sepNavVisRange = "{1789, 665}"; + }; + }; + 72E848500F941ADC00AB3C99 /* version.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {850, 741}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 1379}"; + }; + }; + 72E848510F941ADC00AB3C99 /* version.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {850, 779}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 1392}"; + }; + }; + 72E848530F941ADC00AB3C99 /* w_mmap.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {850, 6137}}"; + sepNavSelRange = "{6859, 0}"; + sepNavVisRange = "{6275, 891}"; + }; + }; + 72E848540F941ADC00AB3C99 /* w_wad.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {850, 9044}}"; + sepNavSelRange = "{12065, 0}"; + sepNavVisRange = "{11764, 599}"; + }; + }; + 72E848550F941ADC00AB3C99 /* w_wad.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {850, 2907}}"; + sepNavSelRange = "{3242, 57}"; + sepNavVisRange = "{2721, 918}"; + }; + }; + 72E848560F941ADC00AB3C99 /* wi_stuff.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {885, 38361}}"; + sepNavSelRange = "{28092, 10}"; + sepNavVisRange = "{27782, 499}"; + }; + }; + 72E848580F941ADC00AB3C99 /* z_bmalloc.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {850, 2242}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 1443}"; + }; + }; + 72E848590F941ADC00AB3C99 /* z_bmalloc.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {850, 988}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 1469}"; + }; + }; + 72E8485A0F941ADC00AB3C99 /* z_zone.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {885, 13224}}"; + sepNavSelRange = "{16093, 0}"; + sepNavVisRange = "{15827, 718}"; + }; + }; + 72E8485B0F941ADC00AB3C99 /* z_zone.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {746, 2508}}"; + sepNavSelRange = "{2121, 71}"; + sepNavVisRange = "{1703, 600}"; + }; + }; + 72E8495C0F942B9300AB3C99 /* cvar.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {848, 7106}}"; + sepNavSelRange = "{7576, 0}"; + sepNavVisRange = "{6851, 728}"; + sepNavWindowFrame = "{{75, 73}, {907, 950}}"; + }; + }; + 72E8495D0F942B9300AB3C99 /* cvar.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {848, 2489}}"; + sepNavSelRange = "{2491, 12}"; + sepNavVisRange = "{1027, 1238}"; + sepNavWindowFrame = "{{98, 52}, {907, 950}}"; + }; + }; + 72E8495E0F942B9300AB3C99 /* misc.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {885, 1083}}"; + sepNavSelRange = "{906, 0}"; + sepNavVisRange = "{422, 509}"; + sepNavWindowFrame = "{{146, 10}, {907, 950}}"; + }; + }; + 72E8495F0F942B9300AB3C99 /* misc.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {850, 1121}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 910}"; + }; + }; + 72E849F50F94ED1100AB3C99 /* prboomInterface.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {885, 6422}}"; + sepNavSelRange = "{3062, 0}"; + sepNavVisRange = "{2715, 680}"; + sepNavWindowFrame = "{{98, 52}, {907, 950}}"; + }; + }; + 72E84A280F9503F100AB3C99 /* cmd.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {885, 2717}}"; + sepNavSelRange = "{2450, 12}"; + sepNavVisRange = "{2141, 699}"; + }; + }; + 72F1F9AC0F96C18800AD49AC /* render.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {747, 9329}}"; + sepNavSelRange = "{14375, 0}"; + sepNavVisRange = "{15201, 549}"; + }; + }; + 72F1F9B00F96C18800AD49AC /* tess.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {636, 12027}}"; + sepNavSelRange = "{13178, 0}"; + sepNavVisRange = "{12994, 355}"; + }; + }; + 72F222C4107F9025000F9D8D /* PlistBookmark */ = { + isa = PlistBookmark; + fRef = 8D1107310486CEB800E47090 /* Info.plist */; + fallbackIsa = PBXBookmark; + isK = 0; + kPath = ( + ); + name = /Users/johnc/dev/iphone/doom/code/iphone/Info.plist; + rLen = 0; + rLoc = 2147483647; + }; + 72F222C6107F9025000F9D8D /* PlistBookmark */ = { + isa = PlistBookmark; + fRef = 8D1107310486CEB800E47090 /* Info.plist */; + fallbackIsa = PBXBookmark; + isK = 0; + kPath = ( + ); + name = /Users/johnc/dev/iphone/doom/code/iphone/Info.plist; + rLen = 0; + rLoc = 2147483647; + }; + 72F222F7107F968D000F9D8D /* iphone_async.c:801 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43DD8391100295F70006E1DD /* iphone_async.c */; + functionName = "iphoneAsyncTic()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 801; + location = doom; + modificationTime = 277182472.348843; + state = 2; + }; + 72F222FE107F96AB000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43E8D2DF0F4FC61E003F09B2 /* iphone_main.c */; + name = "iphone_main.c: 148"; + rLen = 0; + rLoc = 3966; + rType = 0; + vrLen = 1026; + vrLoc = 3451; + }; + 72F222FF107F96AB000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72A560E11004FAEE00F788A5 /* iphone_net.c */; + name = "iphone_net.c: 208"; + rLen = 0; + rLoc = 6085; + rType = 0; + vrLen = 753; + vrLoc = 257; + }; + 72F2230B107F97D5000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43DD8391100295F70006E1DD /* iphone_async.c */; + name = "iphone_async.c: 813"; + rLen = 0; + rLoc = 22546; + rType = 0; + vrLen = 821; + vrLoc = 22248; + }; + 72F2231A107F9A44000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43E8D2DF0F4FC61E003F09B2 /* iphone_main.c */; + name = "iphone_main.c: 142"; + rLen = 0; + rLoc = 3809; + rType = 0; + vrLen = 1026; + vrLoc = 3451; + }; + 72F2231E107F9A44000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72A560E11004FAEE00F788A5 /* iphone_net.c */; + name = "iphone_net.c: 551"; + rLen = 0; + rLoc = 16027; + rType = 0; + vrLen = 905; + vrLoc = 15294; + }; + 72F2231F107F9A44000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43E8D2DF0F4FC61E003F09B2 /* iphone_main.c */; + name = "iphone_main.c: 142"; + rLen = 0; + rLoc = 3809; + rType = 0; + vrLen = 1026; + vrLoc = 3451; + }; + 72F22320107F9A44000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + name = "iphone_menus.c: 380"; + rLen = 0; + rLoc = 10536; + rType = 0; + vrLen = 698; + vrLoc = 9975; + }; + 72F22321107F9A44000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72A560E11004FAEE00F788A5 /* iphone_net.c */; + name = "iphone_net.c: 550"; + rLen = 0; + rLoc = 16027; + rType = 0; + vrLen = 936; + vrLoc = 15264; + }; + 72F22322107F9A44000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + name = "iphone_menus.c: 378"; + rLen = 9; + rLoc = 10359; + rType = 0; + vrLen = 660; + vrLoc = 10014; + }; + 72F22323107F9A44000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72A7E8F30F5F2001005B83C0 /* iphone_doom.h */; + name = "iphone_doom.h: 291"; + rLen = 7; + rLoc = 7943; + rType = 0; + vrLen = 1127; + vrLoc = 7687; + }; + 72F22324107F9A44000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + name = "iphone_menus.c: 381"; + rLen = 0; + rLoc = 10536; + rType = 0; + vrLen = 678; + vrLoc = 10014; + }; + 72F22325107F9A44000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72A560E11004FAEE00F788A5 /* iphone_net.c */; + name = "iphone_net.c: 550"; + rLen = 0; + rLoc = 16027; + rType = 0; + vrLen = 905; + vrLoc = 15294; + }; + 72F22330107F9ACD000F9D8D /* iphone_net.c:545 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72A560E11004FAEE00F788A5 /* iphone_net.c */; + functionName = "UDPSocket()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 545; + location = doom; + modificationTime = 277182472.34907; + state = 2; + }; + 72F22334107F9AD2000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + name = "iphone_menus.c: 381"; + rLen = 0; + rLoc = 10526; + rType = 0; + vrLen = 756; + vrLoc = 10054; + }; + 72F2233C107F9C82000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72A7E8F30F5F2001005B83C0 /* iphone_doom.h */; + name = "iphone_doom.h: 264"; + rLen = 17; + rLoc = 7022; + rType = 0; + vrLen = 788; + vrLoc = 6661; + }; + 72F2233D107F9C82000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7229CE460F6C89F8004123C5 /* EAGLView.m */; + name = "EAGLView.m: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 364; + vrLoc = 0; + }; + 72F2233F107F9C82000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72A560E11004FAEE00F788A5 /* iphone_net.c */; + name = "iphone_net.c: 546"; + rLen = 0; + rLoc = 15851; + rType = 0; + vrLen = 1129; + vrLoc = 15369; + }; + 72F22340107F9C82000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + name = "iphone_menus.c: 590"; + rLen = 0; + rLoc = 16589; + rType = 0; + vrLen = 888; + vrLoc = 16075; + }; + 72F22341107F9C82000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72A560E11004FAEE00F788A5 /* iphone_net.c */; + name = "iphone_net.c: 9"; + rLen = 0; + rLoc = 131; + rType = 0; + vrLen = 931; + vrLoc = 709; + }; + 72F22342107F9C82000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72A7E8F30F5F2001005B83C0 /* iphone_doom.h */; + name = "iphone_doom.h: 311"; + rLen = 9; + rLoc = 8757; + rType = 0; + vrLen = 988; + vrLoc = 7809; + }; + 72F22343107F9C82000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + name = "iphone_menus.c: 239"; + rLen = 9; + rLoc = 6590; + rType = 0; + vrLen = 901; + vrLoc = 6218; + }; + 72F22344107F9C82000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72A560E11004FAEE00F788A5 /* iphone_net.c */; + name = "iphone_net.c: 536"; + rLen = 38; + rLoc = 15311; + rType = 0; + vrLen = 857; + vrLoc = 15172; + }; + 72F22345107F9C82000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72A7E8F30F5F2001005B83C0 /* iphone_doom.h */; + name = "iphone_doom.h: 264"; + rLen = 17; + rLoc = 7022; + rType = 0; + vrLen = 788; + vrLoc = 6661; + }; + 72F22346107F9C82000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + name = "iphone_menus.c: 590"; + rLen = 0; + rLoc = 16562; + rType = 0; + vrLen = 604; + vrLoc = 16115; + }; + 72F22347107F9C82000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7229CE460F6C89F8004123C5 /* EAGLView.m */; + name = "EAGLView.m: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 364; + vrLoc = 0; + }; + 72F22356107F9D12000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7280FD9F10054C2D000F05FD /* ifaddrs.h */; + name = "ifaddrs.h: 24"; + rLen = 0; + rLoc = 1225; + rType = 0; + vrLen = 691; + vrLoc = 978; + }; + 72F22357107F9D12000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + name = "iphone_menus.c: 590"; + rLen = 0; + rLoc = 16581; + rType = 0; + vrLen = 710; + vrLoc = 16010; + }; + 72F22359107F9D12000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72A560E11004FAEE00F788A5 /* iphone_net.c */; + name = "iphone_net.c: 397"; + rLen = 7; + rLoc = 11226; + rType = 0; + vrLen = 979; + vrLoc = 11184; + }; + 72F2235A107F9D12000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7280FD9F10054C2D000F05FD /* ifaddrs.h */; + name = "ifaddrs.h: 24"; + rLen = 0; + rLoc = 1225; + rType = 0; + vrLen = 691; + vrLoc = 978; + }; + 72F2235B107F9D12000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + name = "iphone_menus.c: 590"; + rLen = 0; + rLoc = 16581; + rType = 0; + vrLen = 710; + vrLoc = 16010; + }; + 72F22380107FB264000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72A560E11004FAEE00F788A5 /* iphone_net.c */; + name = "iphone_net.c: 550"; + rLen = 0; + rLoc = 15868; + rType = 0; + vrLen = 763; + vrLoc = 15294; + }; + 72F22384107FB264000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72A560E11004FAEE00F788A5 /* iphone_net.c */; + name = "iphone_net.c: 550"; + rLen = 0; + rLoc = 15868; + rType = 0; + vrLen = 763; + vrLoc = 15294; + }; + 72F22385107FB264000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + name = "iphone_loop.c: 1684"; + rLen = 0; + rLoc = 45884; + rType = 0; + vrLen = 908; + vrLoc = 45515; + }; + 72F22386107FB264000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43DD8391100295F70006E1DD /* iphone_async.c */; + name = "iphone_async.c: 106"; + rLen = 0; + rLoc = 2691; + rType = 0; + vrLen = 1060; + vrLoc = 2124; + }; + 72F2238E107FBD27000F9D8D /* hud.c:73 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 72B5FF380F7E5C3D00C8A372 /* hud.c */; + functionName = "HudSetForScheme()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 73; + location = doom; + modificationTime = 277182472.349305; + state = 2; + }; + 72F22391107FBD4A000F9D8D /* iphone_loop.c:311 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + functionName = "HandleButton()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 311; + location = doom; + modificationTime = 277182472.349535; + state = 2; + }; + 72F22393107FBD55000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E731EA0F97E68100E702CD /* iphone_sound.c */; + name = "iphone_sound.c: 229"; + rLen = 0; + rLoc = 6571; + rType = 0; + vrLen = 1164; + vrLoc = 5858; + }; + 72F22394107FBD55000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43DD8391100295F70006E1DD /* iphone_async.c */; + name = "iphone_async.c: 599"; + rLen = 0; + rLoc = 16313; + rType = 0; + vrLen = 1136; + vrLoc = 15866; + }; + 72F22397107FBD55000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72E731EA0F97E68100E702CD /* iphone_sound.c */; + name = "iphone_sound.c: 229"; + rLen = 0; + rLoc = 6571; + rType = 0; + vrLen = 1164; + vrLoc = 5858; + }; + 72F22398107FBD55000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + name = "iphone_loop.c: 892"; + rLen = 14; + rLoc = 23154; + rType = 0; + vrLen = 1066; + vrLoc = 22835; + }; + 72F22399107FBD55000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43DD8391100295F70006E1DD /* iphone_async.c */; + name = "iphone_async.c: 604"; + rLen = 14; + rLoc = 16516; + rType = 0; + vrLen = 1136; + vrLoc = 15866; + }; + 72F2239A107FBD55000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + name = "iphone_loop.c: 892"; + rLen = 14; + rLoc = 23154; + rType = 0; + vrLen = 873; + vrLoc = 22835; + }; + 72F2239B107FBD55000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72B5FF380F7E5C3D00C8A372 /* hud.c */; + name = "hud.c: 78"; + rLen = 0; + rLoc = 2163; + rType = 0; + vrLen = 1551; + vrLoc = 1822; + }; + 72F2239C107FBD55000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43DD8391100295F70006E1DD /* iphone_async.c */; + name = "iphone_async.c: 599"; + rLen = 0; + rLoc = 16313; + rType = 0; + vrLen = 1136; + vrLoc = 15866; + }; + 72F2239D107FBD55000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + name = "iphone_loop.c: 288"; + rLen = 0; + rLoc = 8619; + rType = 0; + vrLen = 1114; + vrLoc = 7681; + }; + 72F2239E107FBD55000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72B5FF380F7E5C3D00C8A372 /* hud.c */; + name = "hud.c: 78"; + rLen = 0; + rLoc = 2163; + rType = 0; + vrLen = 1551; + vrLoc = 1822; + }; + 72F2239F107FBD55000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + name = "iphone_loop.c: 288"; + rLen = 0; + rLoc = 8619; + rType = 0; + vrLen = 878; + vrLoc = 8727; + }; + 72F223A0107FBD55000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72B5FF380F7E5C3D00C8A372 /* hud.c */; + name = "hud.c: 79"; + rLen = 0; + rLoc = 2163; + rType = 0; + vrLen = 1551; + vrLoc = 1822; + }; + 72F223AC107FBDA6000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7239452B0F9C0E7500EADD62 /* iphone_mapSelect.c */; + name = "iphone_mapSelect.c: 241"; + rLen = 0; + rLoc = 7396; + rType = 0; + vrLen = 890; + vrLoc = 7073; + }; + 72F223AD107FBDA6000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + name = "iphone_loop.c: 311"; + rLen = 0; + rLoc = 9264; + rType = 0; + vrLen = 934; + vrLoc = 8792; + }; + 72F223AF107FBDA6000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + name = "iphone_loop.c: 311"; + rLen = 0; + rLoc = 9264; + rType = 0; + vrLen = 938; + vrLoc = 8788; + }; + 72F223B0107FBDA6000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7239452B0F9C0E7500EADD62 /* iphone_mapSelect.c */; + name = "iphone_mapSelect.c: 241"; + rLen = 0; + rLoc = 7396; + rType = 0; + vrLen = 890; + vrLoc = 7073; + }; + 72F223B1107FBDA6000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72B5FF380F7E5C3D00C8A372 /* hud.c */; + name = "hud.c: 79"; + rLen = 0; + rLoc = 2163; + rType = 0; + vrLen = 1284; + vrLoc = 1673; + }; + 72F223B2107FBDA6000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + name = "iphone_loop.c: 311"; + rLen = 0; + rLoc = 9264; + rType = 0; + vrLen = 934; + vrLoc = 8792; + }; + 72F223B8107FBDD0000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72B5FF380F7E5C3D00C8A372 /* hud.c */; + name = "hud.c: 100"; + rLen = 0; + rLoc = 3535; + rType = 0; + vrLen = 806; + vrLoc = 3031; + }; + 72F223BC107FC076000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72B5FF380F7E5C3D00C8A372 /* hud.c */; + name = "hud.c: 100"; + rLen = 0; + rLoc = 3535; + rType = 0; + vrLen = 1464; + vrLoc = 1621; + }; + 72F223BD107FC076000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72A7E8F30F5F2001005B83C0 /* iphone_doom.h */; + name = "iphone_doom.h: 399"; + rLen = 4; + rLoc = 11360; + rType = 0; + vrLen = 1186; + vrLoc = 10515; + }; + 72F223BE107FC076000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72A7E8F30F5F2001005B83C0 /* iphone_doom.h */; + name = "iphone_doom.h: 365"; + rLen = 0; + rLoc = 10409; + rType = 0; + vrLen = 1479; + vrLoc = 9821; + }; + 72F223BF107FC076000F9D8D /* PlistBookmark */ = { + isa = PlistBookmark; + fRef = 8D1107310486CEB800E47090 /* Info.plist */; + fallbackIsa = PBXBookmark; + isK = 0; + kPath = ( + ); + name = /Users/johnc/dev/iphone/doom/code/iphone/Info.plist; + rLen = 0; + rLoc = 2147483647; + }; + 72F223C0107FC076000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43E8D2DF0F4FC61E003F09B2 /* iphone_main.c */; + name = "iphone_main.c: 148"; + rLen = 0; + rLoc = 3966; + rType = 0; + vrLen = 949; + vrLoc = 3014; + }; + 72F223C1107FC076000F9D8D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 434669A50F8D08C000EA7D6D /* doomAppDelegate.m */; + name = "doomAppDelegate.m: 129"; + rLen = 0; + rLoc = 3905; + rType = 0; + vrLen = 1730; + vrLoc = 3028; + }; + 8D1107310486CEB800E47090 /* Info.plist */ = { + uiCtxt = { + sepNavWindowFrame = "{{248, 75}, {838, 824}}"; + }; + }; +} diff --git a/DoomClassic/code/iphone/Doom.xcodeproj/johnc.perspectivev3 b/DoomClassic/code/iphone/Doom.xcodeproj/johnc.perspectivev3 new file mode 100755 index 0000000..413d2bb --- /dev/null +++ b/DoomClassic/code/iphone/Doom.xcodeproj/johnc.perspectivev3 @@ -0,0 +1,2053 @@ + + + + + ActivePerspectiveName + Debug + 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 + XCProjectFormatConflictsModule + Name + Project Format Conflicts List + + + 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 + + + BundleLoadPath + + MaxInstances + n + Module + XCSnapshotModule + Name + Snapshots Tool + + + BundlePath + /Developer/Library/PrivateFrameworks/DevToolsInterface.framework/Resources + Description + AIODescriptionKey + DockingSystemVisible + + Extension + perspectivev3 + FavBarConfig + + PBXProjectModuleGUID + 72D50EEB0F8F08CE00BB49E6 + XCBarModuleItemNames + + XCBarModuleItems + + + FirstTimeWindowDisplayed + + Identifier + com.apple.perspectives.project.defaultV3 + MajorVersion + 34 + MinorVersion + 0 + Name + All-In-One + Notifications + + + XCObserverAutoDisconnectKey + + XCObserverDefintionKey + + XCObserverFactoryKey + XCPerspectivesSpecificationIdentifier + XCObserverGUIDKey + XCObserverProjectIdentifier + XCObserverNotificationKey + PBXStatusBuildStateMessageNotification + XCObserverTargetKey + XCMainBuildResultsModuleGUID + XCObserverTriggerKey + awakenModuleWithObserver: + XCObserverValidationKey + + + + OpenEditors + + + Content + + PBXProjectModuleGUID + 72AC93E8107EA14200D77CA8 + PBXProjectModuleLabel + iphone_doom.h + PBXSplitModuleInNavigatorKey + + Split0 + + PBXProjectModuleGUID + 72AC93E9107EA14200D77CA8 + PBXProjectModuleLabel + iphone_doom.h + _historyCapacity + 0 + bookmark + 72F223BE107FC076000F9D8D + history + + 72F223BD107FC076000F9D8D + + + SplitCount + 1 + + StatusBarVisibility + + + Geometry + + Frame + {{0, 20}, {907, 853}} + PBXModuleWindowStatusBarHidden2 + + RubberWindowFrame + 110 103 907 894 0 0 1680 1028 + + + + Content + + PBXProjectModuleGUID + 72AC93E5107EA14200D77CA8 + PBXProjectModuleLabel + Info.plist + PBXSplitModuleInNavigatorKey + + Split0 + + PBXProjectModuleGUID + 72AC93E6107EA14200D77CA8 + PBXProjectModuleLabel + Info.plist + _historyCapacity + 0 + bookmark + 72F223BF107FC076000F9D8D + history + + 725D1D20107EAE6800B86564 + + + SplitCount + 1 + + StatusBarVisibility + + + Geometry + + Frame + {{0, 20}, {838, 727}} + PBXModuleWindowStatusBarHidden2 + + RubberWindowFrame + 248 131 838 768 0 0 1680 1028 + + + + Content + + PBXProjectModuleGUID + 72DB5806101E7B6C00A58CED + PBXProjectModuleLabel + iphone_main.c + PBXSplitModuleInNavigatorKey + + Split0 + + PBXProjectModuleGUID + 72DB5807101E7B6C00A58CED + PBXProjectModuleLabel + iphone_main.c + _historyCapacity + 0 + bookmark + 72F223C0107FC076000F9D8D + history + + 725D1D22107EAE6800B86564 + + + SplitCount + 1 + + StatusBarVisibility + + + Geometry + + Frame + {{0, 20}, {907, 853}} + PBXModuleWindowStatusBarHidden2 + + RubberWindowFrame + 101 82 907 894 0 0 1680 1028 + + + + Content + + PBXProjectModuleGUID + 72A55F4F1003B35200F788A5 + PBXProjectModuleLabel + doomAppDelegate.m + PBXSplitModuleInNavigatorKey + + Split0 + + PBXProjectModuleGUID + 72A55F501003B35200F788A5 + PBXProjectModuleLabel + doomAppDelegate.m + _historyCapacity + 0 + bookmark + 72F223C1107FC076000F9D8D + history + + 725D1D23107EAE6800B86564 + + + SplitCount + 1 + + StatusBarVisibility + + + Geometry + + Frame + {{0, 20}, {882, 880}} + PBXModuleWindowStatusBarHidden2 + + RubberWindowFrame + 470 107 882 921 0 0 1680 1028 + + + + PerspectiveWidths + + 1160 + 1160 + + Perspectives + + + ChosenToolbarItems + + XCToolbarPerspectiveControl + NSToolbarSeparatorItem + active-combo-popup + action + NSToolbarFlexibleSpaceItem + buildOrClean + build-and-go + com.apple.ide.PBXToolbarStopButton + clean + toggle-editor + NSToolbarFlexibleSpaceItem + get-info + com.apple.pbx.toolbar.searchfield + + ControllerClassBaseName + + IconName + WindowOfProject + Identifier + perspective.project + IsVertical + + Layout + + + ContentConfiguration + + PBXBottomSmartGroupGIDs + + 1C37FBAC04509CD000000102 + 1C37FAAC04509CD000000102 + 1C08E77C0454961000C914BD + 1C37FABC05509CD000000102 + 1C37FABC05539CD112110102 + E2644B35053B69B200211256 + 1C37FABC04509CD000100104 + 1CC0EA4004350EF90044410B + 1CC0EA4004350EF90041110B + 1C77FABC04509CD000000102 + + PBXProjectModuleGUID + 1CA23ED40692098700951B8B + PBXProjectModuleLabel + Files + PBXProjectStructureProvided + yes + PBXSmartGroupTreeModuleColumnData + + PBXSmartGroupTreeModuleColumnWidthsKey + + 211 + + PBXSmartGroupTreeModuleColumnsKey_v4 + + MainColumn + + + PBXSmartGroupTreeModuleOutlineStateKey_v7 + + PBXSmartGroupTreeModuleOutlineStateExpansionKey + + 29B97314FDCFA39411CA2CEA + 29B97315FDCFA39411CA2CEA + 29B97317FDCFA39411CA2CEA + 1C37FBAC04509CD000000102 + 1C37FAAC04509CD000000102 + 1CC0EA4004350EF90041110B + + PBXSmartGroupTreeModuleOutlineStateSelectionKey + + + 18 + 1 + 0 + + + PBXSmartGroupTreeModuleOutlineStateVisibleRectKey + {{0, 21}, {211, 914}} + + PBXTopSmartGroupGIDs + + XCIncludePerspectivesSwitch + + + GeometryConfiguration + + Frame + {{0, 0}, {228, 932}} + GroupTreeTableConfiguration + + MainColumn + 211 + + + Module + PBXSmartGroupTreeModule + Proportion + 228pt + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + 72D50DEF0F8EFAFB00BB49E6 + PBXProjectModuleLabel + hud.c + PBXSplitModuleInNavigatorKey + + Split0 + + PBXProjectModuleGUID + 72D50DF00F8EFAFB00BB49E6 + PBXProjectModuleLabel + hud.c + _historyCapacity + 0 + bookmark + 72F223BC107FC076000F9D8D + history + + 72AD0BEC0FA62D9E000999A0 + 7201D47A0FA684B400D81683 + 7201D4980FA6862500D81683 + 7201D7B70FA8B04600D81683 + 72A6EFEA0FABE6ED0000A7A0 + 72A6EFEB0FABE6ED0000A7A0 + 72484DB00FB0E95C00124E1C + 72484DB70FB0E95C00124E1C + 72484DB90FB0E95C00124E1C + 72484DBB0FB0E95C00124E1C + 72484DBC0FB0E95C00124E1C + 72484DBD0FB0E95C00124E1C + 72484DC20FB0E95C00124E1C + 72484DC30FB0E95C00124E1C + 72484DC60FB0E95C00124E1C + 72484DC70FB0E95C00124E1C + 72484DC80FB0E95C00124E1C + 72484DCB0FB0E95C00124E1C + 72484DCC0FB0E95C00124E1C + 72484DCD0FB0E95C00124E1C + 72484DCF0FB0E95C00124E1C + 72484DD10FB0E95C00124E1C + 72484DD20FB0E95C00124E1C + 72484DD40FB0E95C00124E1C + 72484DD50FB0E95C00124E1C + 72484DDA0FB0E95C00124E1C + 72484DDB0FB0E95C00124E1C + 72484DDC0FB0E95C00124E1C + 72484DDD0FB0E95C00124E1C + 72484DDE0FB0E95C00124E1C + 72484DDF0FB0E95C00124E1C + 72484DE20FB0E95C00124E1C + 72484DE30FB0E95C00124E1C + 72484DE40FB0E95C00124E1C + 72484DE50FB0E95C00124E1C + 72484DE60FB0E95C00124E1C + 72484DEB0FB0E95C00124E1C + 72484DED0FB0E95C00124E1C + 72484DEE0FB0E95C00124E1C + 72484DEF0FB0E95C00124E1C + 72484DF00FB0E95C00124E1C + 72484DF20FB0E95C00124E1C + 72484DF30FB0E95C00124E1C + 72484E8D0FB1F22E00124E1C + 72484E900FB1F22E00124E1C + 72484E940FB1F22E00124E1C + 72484F5D0FB1F8DA00124E1C + 72BD33500FB49A10002E4055 + 72BD34BB0FB505C4002E4055 + 72E7896F0FB762C1001FACDD + 722DFAE80FB8A419002A6405 + 72BCB43E0FB8C17C000EC406 + 72BCB4710FB8DCB6000EC406 + 72BCB4E20FB8DEDE000EC406 + 72BCB54A0FB8E380000EC406 + 72BCB56A0FB8E4B7000EC406 + 72BCB5830FB8E5B1000EC406 + 72BCB5840FB8E5B1000EC406 + 72BCB5860FB8E5B1000EC406 + 72BCB5A00FB8E713000EC406 + 72BCB66B0FB8EADA000EC406 + 72BCB7530FB90A87000EC406 + 72B2B2C60FB9DC5900AAFC45 + 72B0E92F0FBC872600D1D1FA + 72B0E9300FBC872600D1D1FA + 72B0E9A30FBC8F3600D1D1FA + 72B0E9A40FBC8F3600D1D1FA + 72B0EA0A0FBCE5F600D1D1FA + 7278865F0FBDAF4B0020D469 + 724C53220FBDBD31000E4348 + 724C53AB0FBDC6B6000E4348 + 724C53AD0FBDC6B6000E4348 + 724C53AF0FBDC6B6000E4348 + 724C53B20FBDC6B6000E4348 + 724C53B40FBDC6B6000E4348 + 724C54190FBDC908000E4348 + 724C54B70FBDEB53000E4348 + 724C55FB0FBE0A75000E4348 + 724C565B0FBE1019000E4348 + 724C576D0FC1B041000E4348 + 724C58300FC1C408000E4348 + 724C58B10FC1D13D000E4348 + 724C5BFE0FC48768000E4348 + 724C5C030FC48768000E4348 + 724C5CA20FC48EBF000E4348 + 724C5CCE0FC490AE000E4348 + 724C5D240FC5D5AA000E4348 + 724C5D250FC5D5AA000E4348 + 724C5D260FC5D5AA000E4348 + 724C5D270FC5D5AA000E4348 + 724C5D760FC7AAC4000E4348 + 724C5DE80FC7B5AF000E4348 + 724C5F060FC9BE48000E4348 + 724C5FE80FC9EBAE000E4348 + 724C600F0FC9ECA0000E4348 + 724C604B0FC9F13B000E4348 + 724C605B0FCA1E6E000E4348 + 724C62AC0FCB49BE000E4348 + 724C64F50FCD818B000E4348 + 724C65030FCD8287000E4348 + 724C651A0FCD8435000E4348 + 724C65F10FCD9B5F000E4348 + 724C65F20FCD9B5F000E4348 + 724C66070FCD9EA8000E4348 + 72B9E7450FCDF4A000939821 + 72B9E7770FCDFB5200939821 + 72B9E7F50FCE199C00939821 + 72973B310FF5259E00F813E6 + 72973B7A0FF52F5800F813E6 + 721520CC0FF59671001CDDB7 + 721520F70FF597C4001CDDB7 + 725E01ED0FFD528100A7D6A7 + 725E01EF0FFD528100A7D6A7 + 725E02070FFD554600A7D6A7 + 725E02090FFD554600A7D6A7 + 725E02C4100242F200A7D6A7 + 725E033410024FC300A7D6A7 + 725E03FA100279FF00A7D6A7 + 725E03FD100279FF00A7D6A7 + 725E042410027EA700A7D6A7 + 725E042510027EA700A7D6A7 + 725E042610027EA700A7D6A7 + 725E04611002857800A7D6A7 + 725E04A310028FCE00A7D6A7 + 725E04A410028FCE00A7D6A7 + 72A55DCE1002B27400F788A5 + 72A55F381003B1E200F788A5 + 72A55F391003B1E200F788A5 + 72A55F3A1003B1E200F788A5 + 72A55FD41003D14900F788A5 + 72A5604D1003E44400F788A5 + 7280FC8A100536FA000F05FD + 7280FDD310054DAB000F05FD + 720CBE281006623E00801220 + 725410561007961500925CFB + 725410571007961500925CFB + 725410581007961500925CFB + 7254122F1007C71F00925CFB + 725412E11007D63200925CFB + 7240B2831017A35C00522838 + 7240B29E1017A9B600522838 + 7240B2EF1017B18E00522838 + 7240B32A1017B71400522838 + 7240B36A1017BF1800522838 + 7240B4121017F25A00522838 + 7240B4141017F25A00522838 + 7240B4161017F25A00522838 + 7240B4181017F25A00522838 + 7240B41A1017F25A00522838 + 7240B41C1017F25A00522838 + 7240B4371017F49300522838 + 72DB5702101A58CB00A58CED + 72DB5727101A617200A58CED + 72DB578C101A742600A58CED + 72DB579D101A78F300A58CED + 726799F8102879A100CEA3A2 + 72BA12631028B32000DDB148 + 72BA12711028BED300DDB148 + 72BA131A1028C8D200DDB148 + 72AC93D7107EA14200D77CA8 + 72F222C4107F9025000F9D8D + 72F2231A107F9A44000F9D8D + 72F2233C107F9C82000F9D8D + 72F2233D107F9C82000F9D8D + 72F22356107F9D12000F9D8D + 72F22357107F9D12000F9D8D + 72F22380107FB264000F9D8D + 72F22393107FBD55000F9D8D + 72F22394107FBD55000F9D8D + 72F223AC107FBDA6000F9D8D + 72F223AD107FBDA6000F9D8D + 72F223B8107FBDD0000F9D8D + + prevStack + + 72AD09B60FA22C8A000999A0 + 72AD09B70FA22C8A000999A0 + 72AD09B80FA22C8A000999A0 + 72AD09BB0FA22C8A000999A0 + 72AD09CC0FA22D58000999A0 + 72AD09DA0FA23046000999A0 + 72AD09DB0FA23046000999A0 + 72AD0A0B0FA23674000999A0 + 72AD0A6C0FA4961E000999A0 + 72AD0A810FA4961E000999A0 + 72AD0BF50FA62D9E000999A0 + 72AD0BF60FA62D9E000999A0 + 72AD0BF80FA62D9E000999A0 + 72AD0C020FA62D9E000999A0 + 72AD0C060FA62D9E000999A0 + 72AD0C2C0FA63091000999A0 + 72AD0CAA0FA64E09000999A0 + 7201D45F0FA6828B00D81683 + 7201D4600FA6828B00D81683 + 7201D4610FA6828B00D81683 + 7201D4640FA6828B00D81683 + 7201D47C0FA684B400D81683 + 7201D47E0FA684B400D81683 + 7201D4900FA685CB00D81683 + 7201D49D0FA6862500D81683 + 7201D4D00FA694B500D81683 + 7201D5B00FA79C1800D81683 + 7201D73B0FA7FD3300D81683 + 7201D7620FA7FED300D81683 + 7201D7650FA7FED300D81683 + 7201D7660FA7FED300D81683 + 7201D76D0FA7FED300D81683 + 7201D7BE0FA8B04600D81683 + 7201D7BF0FA8B04600D81683 + 7201D7C10FA8B04600D81683 + 7201D8040FA8C52200D81683 + 7201D8270FA8CBFA00D81683 + 7201D8950FA8E2AD00D81683 + 7201D8DB0FA8ED7D00D81683 + 7201D9CC0FA91DCE00D81683 + 7201D9CD0FA91DCE00D81683 + 7201D9CF0FA91DCE00D81683 + 7201DA4F0FA929DB00D81683 + 7201DA500FA929DB00D81683 + 72B4A6C40FAB633200DC59D9 + 72B4A6CE0FAB633200DC59D9 + 72B4A7610FAB7B6100DC59D9 + 72A6EEFA0FABCA670000A7A0 + 72A6EEFC0FABCA670000A7A0 + 72A6EF3D0FABCE0D0000A7A0 + 72A6EFF20FABE6ED0000A7A0 + 72A6EFF30FABE6ED0000A7A0 + 72A6EFF40FABE6ED0000A7A0 + 72A6F0010FABE81E0000A7A0 + 72A6F0040FABE81E0000A7A0 + 72A6F0480FAF3E350000A7A0 + 72A6F0F00FAF7C5F0000A7A0 + 72A6F11A0FAF7E860000A7A0 + 72484E080FB0E95C00124E1C + 72484E0C0FB0E95C00124E1C + 72484E0D0FB0E95C00124E1C + 72484E0E0FB0E95C00124E1C + 72484E0F0FB0E95C00124E1C + 72484E100FB0E95C00124E1C + 72484E130FB0E95C00124E1C + 72484E140FB0E95C00124E1C + 72484E150FB0E95C00124E1C + 72484E160FB0E95C00124E1C + 72484E170FB0E95C00124E1C + 72484E180FB0E95C00124E1C + 72484E190FB0E95C00124E1C + 72484E1C0FB0E95C00124E1C + 72484E1D0FB0E95C00124E1C + 72484E210FB0E95C00124E1C + 72484E220FB0E95C00124E1C + 72484E230FB0E95C00124E1C + 72484E240FB0E95C00124E1C + 72484E250FB0E95C00124E1C + 72484E260FB0E95C00124E1C + 72484E270FB0E95C00124E1C + 72484E280FB0E95C00124E1C + 72484E2B0FB0E95C00124E1C + 72484E2C0FB0E95C00124E1C + 72484E2D0FB0E95C00124E1C + 72484E2F0FB0E95C00124E1C + 72484E300FB0E95C00124E1C + 72484E310FB0E95C00124E1C + 72484E330FB0E95C00124E1C + 72484E340FB0E95C00124E1C + 72484E350FB0E95C00124E1C + 72484E370FB0E95C00124E1C + 72484E390FB0E95C00124E1C + 72484E3B0FB0E95C00124E1C + 72484E3C0FB0E95C00124E1C + 72484E3D0FB0E95C00124E1C + 72484E3E0FB0E95C00124E1C + 72484E3F0FB0E95C00124E1C + 72484E400FB0E95C00124E1C + 72484E410FB0E95C00124E1C + 72484E420FB0E95C00124E1C + 72484E430FB0E95C00124E1C + 72484E440FB0E95C00124E1C + 72484E450FB0E95C00124E1C + 72484E980FB1F22E00124E1C + 72484E990FB1F22E00124E1C + 72484EA60FB1F22E00124E1C + 72484EAA0FB1F22E00124E1C + 72BD33540FB49A10002E4055 + 72BD34C10FB505C4002E4055 + 72BCB4430FB8C17C000EC406 + 72BCB4860FB8DCB6000EC406 + 72BCB6D00FB8FB83000EC406 + 72B2B1D70FB9BA7D00AAFC45 + 72B2B2CA0FB9DC5900AAFC45 + 72B2B2CB0FB9DC5900AAFC45 + 72B0E93F0FBC872600D1D1FA + 72B0E9A80FBC8F3600D1D1FA + 72B0E9D40FBCDCDC00D1D1FA + 727886650FBDAF4B0020D469 + 724C532A0FBDBD31000E4348 + 724C532F0FBDBD31000E4348 + 724C536A0FBDC094000E4348 + 724C536C0FBDC094000E4348 + 724C53CD0FBDC6B6000E4348 + 724C53D20FBDC6B6000E4348 + 724C53E50FBDC6B6000E4348 + 724C53E70FBDC6B6000E4348 + 724C53EC0FBDC6B6000E4348 + 724C55470FBDF916000E4348 + 724C565E0FBE1019000E4348 + 724C576F0FC1B041000E4348 + 724C5BE90FC47EFB000E4348 + 724C5C110FC48768000E4348 + 724C5D380FC5D5AA000E4348 + 724C5D870FC7AAC4000E4348 + 724C5DEF0FC7B5AF000E4348 + 724C5DF40FC7B5AF000E4348 + 724C5F0A0FC9BE48000E4348 + 724C5FF10FC9EBAE000E4348 + 724C60140FC9ECA0000E4348 + 724C60690FCA1E6E000E4348 + 724C606A0FCA1E6E000E4348 + 724C62B50FCB49BE000E4348 + 724C643A0FCC46E2000E4348 + 724C64F90FCD818B000E4348 + 724C65070FCD8287000E4348 + 72B9E7FA0FCE199C00939821 + 725EFFB40FFD05AB00A7D6A7 + 725E01F30FFD528100A7D6A7 + 725E01F60FFD528100A7D6A7 + 725E020D0FFD554600A7D6A7 + 725E020F0FFD554600A7D6A7 + 725E02C9100242F200A7D6A7 + 72A55D451002ACBB00F788A5 + 72A55E7110039E9700F788A5 + 72A560551003E44400F788A5 + 7280FC8E100536FA000F05FD + 7280FD9E10054C2D000F05FD + 720CBE371006623E00801220 + 72540F5B1006938400925CFB + 7240B28A1017A35C00522838 + 7240B2F61017B18E00522838 + 7240B3381017B71400522838 + 7240B3571017BD1B00522838 + 7240B36E1017BF1800522838 + 7240B4201017F25A00522838 + 7240B4221017F25A00522838 + 7240B4241017F25A00522838 + 7240B4261017F25A00522838 + 7240B4281017F25A00522838 + 7240B42A1017F25A00522838 + 72F222C6107F9025000F9D8D + 72F222FE107F96AB000F9D8D + 72F222FF107F96AB000F9D8D + 72F2230B107F97D5000F9D8D + 72F2231E107F9A44000F9D8D + 72F2231F107F9A44000F9D8D + 72F22320107F9A44000F9D8D + 72F22321107F9A44000F9D8D + 72F22322107F9A44000F9D8D + 72F22323107F9A44000F9D8D + 72F22324107F9A44000F9D8D + 72F22325107F9A44000F9D8D + 72F22334107F9AD2000F9D8D + 72F2233F107F9C82000F9D8D + 72F22340107F9C82000F9D8D + 72F22341107F9C82000F9D8D + 72F22342107F9C82000F9D8D + 72F22343107F9C82000F9D8D + 72F22344107F9C82000F9D8D + 72F22345107F9C82000F9D8D + 72F22346107F9C82000F9D8D + 72F22347107F9C82000F9D8D + 72F22359107F9D12000F9D8D + 72F2235A107F9D12000F9D8D + 72F2235B107F9D12000F9D8D + 72F22384107FB264000F9D8D + 72F22385107FB264000F9D8D + 72F22386107FB264000F9D8D + 72F22397107FBD55000F9D8D + 72F22398107FBD55000F9D8D + 72F22399107FBD55000F9D8D + 72F2239A107FBD55000F9D8D + 72F2239B107FBD55000F9D8D + 72F2239C107FBD55000F9D8D + 72F2239D107FBD55000F9D8D + 72F2239E107FBD55000F9D8D + 72F2239F107FBD55000F9D8D + 72F223A0107FBD55000F9D8D + 72F223AF107FBDA6000F9D8D + 72F223B0107FBDA6000F9D8D + 72F223B1107FBDA6000F9D8D + 72F223B2107FBDA6000F9D8D + + + SplitCount + 1 + + StatusBarVisibility + + XCSharingToken + com.apple.Xcode.CommonNavigatorGroupSharingToken + + GeometryConfiguration + + Frame + {{0, 0}, {927, 658}} + + Module + PBXNavigatorGroup + Proportion + 658pt + + + Proportion + 269pt + Tabs + + + ContentConfiguration + + PBXProjectModuleGUID + 1CA23EDF0692099D00951B8B + PBXProjectModuleLabel + Detail + + GeometryConfiguration + + Frame + {{10, 27}, {370, -27}} + + Module + XCDetailModule + + + ContentConfiguration + + PBXProjectModuleGUID + 1CA23EE00692099D00951B8B + PBXProjectModuleLabel + Project Find + + GeometryConfiguration + + Frame + {{10, 27}, {927, 242}} + + Module + PBXProjectFindModule + + + ContentConfiguration + + PBXCVSModuleFilterTypeKey + 1032 + PBXProjectModuleGUID + 1CA23EE10692099D00951B8B + PBXProjectModuleLabel + SCM Results + + GeometryConfiguration + + Frame + {{10, 31}, {603, 297}} + + Module + PBXCVSModule + + + ContentConfiguration + + PBXProjectModuleGUID + XCMainBuildResultsModuleGUID + PBXProjectModuleLabel + Build + XCBuildResultsTrigger_Collapse + 1021 + XCBuildResultsTrigger_Open + 1010 + + GeometryConfiguration + + Frame + {{10, 27}, {927, 242}} + + Module + PBXBuildResultsModule + + + + + Proportion + 927pt + + + Name + Project + ServiceClasses + + XCModuleDock + PBXSmartGroupTreeModule + XCModuleDock + PBXNavigatorGroup + XCDockableTabModule + XCDetailModule + PBXProjectFindModule + PBXCVSModule + PBXBuildResultsModule + + TableOfContents + + 72F222D0107F9258000F9D8D + 1CA23ED40692098700951B8B + 72F222D1107F9258000F9D8D + 72D50DEF0F8EFAFB00BB49E6 + 72F222D2107F9258000F9D8D + 1CA23EDF0692099D00951B8B + 1CA23EE00692099D00951B8B + 1CA23EE10692099D00951B8B + XCMainBuildResultsModuleGUID + + ToolbarConfiguration + xcode.toolbar.config.defaultV3 + + + ChosenToolbarItems + + XCToolbarPerspectiveControl + NSToolbarSeparatorItem + active-combo-popup + NSToolbarFlexibleSpaceItem + servicesModulefind + servicesModuleproject + servicesModulebuild + build-and-go + com.apple.ide.PBXToolbarStopButton + debugger-restart-executable + debugger-pause + debugger-step-over + debugger-step-into + debugger-step-out + debugger-enable-breakpoints + NSToolbarFlexibleSpaceItem + com.apple.ide.XCBreakpointsToolbarItem + clear-log + + ControllerClassBaseName + PBXDebugSessionModule + IconName + DebugTabIcon + Identifier + perspective.debug + IsVertical + + Layout + + + ContentConfiguration + + PBXProjectModuleGUID + 1CCC7628064C1048000F2A68 + PBXProjectModuleLabel + Debugger Console + + GeometryConfiguration + + Frame + {{0, 0}, {1160, 338}} + RubberWindowFrame + 362 52 1160 973 0 0 1680 1028 + + Module + PBXDebugCLIModule + Proportion + 338pt + + + ContentConfiguration + + Debugger + + HorizontalSplitView + + _collapsingFrameDimension + 0.0 + _indexOfCollapsedView + 0 + _percentageOfCollapsedView + 0.0 + isCollapsed + yes + sizes + + {{0, 0}, {538, 185}} + {{538, 0}, {622, 185}} + + + VerticalSplitView + + _collapsingFrameDimension + 0.0 + _indexOfCollapsedView + 0 + _percentageOfCollapsedView + 0.0 + isCollapsed + yes + sizes + + {{0, 0}, {1160, 185}} + {{0, 185}, {1160, 404}} + + + + LauncherConfigVersion + 8 + PBXProjectModuleGUID + 1CCC7629064C1048000F2A68 + PBXProjectModuleLabel + Debug + + GeometryConfiguration + + DebugConsoleVisible + None + DebugConsoleWindowFrame + {{200, 200}, {500, 300}} + DebugSTDIOWindowFrame + {{200, 200}, {500, 300}} + Frame + {{0, 343}, {1160, 589}} + PBXDebugSessionStackFrameViewKey + + DebugVariablesTableConfiguration + + Name + 120 + Value + 85 + Summary + 631 + + Frame + {{538, 0}, {622, 185}} + RubberWindowFrame + 362 52 1160 973 0 0 1680 1028 + + RubberWindowFrame + 362 52 1160 973 0 0 1680 1028 + + Module + PBXDebugSessionModule + Proportion + 589pt + + + Name + Debug + ServiceClasses + + XCModuleDock + PBXDebugCLIModule + PBXDebugSessionModule + PBXDebugProcessAndThreadModule + PBXDebugProcessViewModule + PBXDebugThreadViewModule + PBXDebugStackFrameViewModule + PBXNavigatorGroup + + TableOfContents + + 72F222D3107F9258000F9D8D + 1CCC7628064C1048000F2A68 + 1CCC7629064C1048000F2A68 + 72F222D4107F9258000F9D8D + 72F222D5107F9258000F9D8D + 72F222D6107F9258000F9D8D + 72F222D7107F9258000F9D8D + 72D50DEF0F8EFAFB00BB49E6 + + ToolbarConfiguration + xcode.toolbar.config.debugV3 + + + PerspectivesBarVisible + + ShelfIsVisible + + SourceDescription + file at '/Developer/Library/PrivateFrameworks/DevToolsInterface.framework/Resources/XCPerspectivesSpecification.xcperspec' + StatusbarIsVisible + + TimeStamp + 276807798.27780402 + ToolbarDisplayMode + 1 + ToolbarIsVisible + + ToolbarSizeMode + 1 + Type + Perspectives + UpdateMessage + + WindowJustification + 5 + WindowOrderList + + 72F222DD107F9258000F9D8D + 72F222DE107F9258000F9D8D + 72A55F4F1003B35200F788A5 + 72DB5806101E7B6C00A58CED + 72AC93E5107EA14200D77CA8 + /Users/johnc/dev/iphone/doom/code/iphone/doom.xcodeproj + 72AC93E8107EA14200D77CA8 + + WindowString + 362 52 1160 973 0 0 1680 1028 + WindowToolsV3 + + + Identifier + windowTool.debugger + Layout + + + Dock + + + ContentConfiguration + + Debugger + + HorizontalSplitView + + _collapsingFrameDimension + 0.0 + _indexOfCollapsedView + 0 + _percentageOfCollapsedView + 0.0 + isCollapsed + yes + sizes + + {{0, 0}, {317, 164}} + {{317, 0}, {377, 164}} + + + VerticalSplitView + + _collapsingFrameDimension + 0.0 + _indexOfCollapsedView + 0 + _percentageOfCollapsedView + 0.0 + isCollapsed + yes + sizes + + {{0, 0}, {694, 164}} + {{0, 164}, {694, 216}} + + + + 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, 380}} + RubberWindowFrame + 321 238 694 422 0 0 1440 878 + + Module + PBXDebugSessionModule + Proportion + 100% + + + Proportion + 100% + + + Name + Debugger + ServiceClasses + + PBXDebugSessionModule + + StatusbarIsVisible + 1 + TableOfContents + + 1CD10A99069EF8BA00B06720 + 1C0AD2AB069F1E9B00FABCE6 + 1C162984064C10D400B95A72 + 1C0AD2AC069F1E9B00FABCE6 + + ToolbarConfiguration + xcode.toolbar.config.debugV3 + WindowString + 321 238 694 422 0 0 1440 878 + WindowToolGUID + 1CD10A99069EF8BA00B06720 + WindowToolIsVisible + 0 + + + Identifier + windowTool.build + Layout + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + 1CD0528F0623707200166675 + PBXProjectModuleLabel + <No Editor> + PBXSplitModuleInNavigatorKey + + Split0 + + PBXProjectModuleGUID + 1CD052900623707200166675 + + SplitCount + 1 + + StatusBarVisibility + 1 + + GeometryConfiguration + + Frame + {{0, 0}, {500, 215}} + RubberWindowFrame + 192 257 500 500 0 0 1280 1002 + + Module + PBXNavigatorGroup + Proportion + 218pt + + + BecomeActive + 1 + ContentConfiguration + + PBXProjectModuleGUID + XCMainBuildResultsModuleGUID + PBXProjectModuleLabel + Build + + GeometryConfiguration + + Frame + {{0, 222}, {500, 236}} + RubberWindowFrame + 192 257 500 500 0 0 1280 1002 + + Module + PBXBuildResultsModule + Proportion + 236pt + + + Proportion + 458pt + + + Name + Build Results + ServiceClasses + + PBXBuildResultsModule + + StatusbarIsVisible + 1 + TableOfContents + + 1C78EAA5065D492600B07095 + 1C78EAA6065D492600B07095 + 1CD0528F0623707200166675 + XCMainBuildResultsModuleGUID + + ToolbarConfiguration + xcode.toolbar.config.buildV3 + WindowString + 192 257 500 500 0 0 1280 1002 + + + Identifier + windowTool.find + Layout + + + Dock + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + 1CDD528C0622207200134675 + PBXProjectModuleLabel + <No Editor> + PBXSplitModuleInNavigatorKey + + Split0 + + PBXProjectModuleGUID + 1CD0528D0623707200166675 + + SplitCount + 1 + + StatusBarVisibility + 1 + + GeometryConfiguration + + Frame + {{0, 0}, {781, 167}} + RubberWindowFrame + 62 385 781 470 0 0 1440 878 + + Module + PBXNavigatorGroup + Proportion + 781pt + + + Proportion + 50% + + + BecomeActive + 1 + ContentConfiguration + + PBXProjectModuleGUID + 1CD0528E0623707200166675 + PBXProjectModuleLabel + Project Find + + GeometryConfiguration + + Frame + {{8, 0}, {773, 254}} + RubberWindowFrame + 62 385 781 470 0 0 1440 878 + + Module + PBXProjectFindModule + Proportion + 50% + + + Proportion + 428pt + + + Name + Project Find + ServiceClasses + + PBXProjectFindModule + + StatusbarIsVisible + 1 + TableOfContents + + 1C530D57069F1CE1000CFCEE + 1C530D58069F1CE1000CFCEE + 1C530D59069F1CE1000CFCEE + 1CDD528C0622207200134675 + 1C530D5A069F1CE1000CFCEE + 1CE0B1FE06471DED0097A5F4 + 1CD0528E0623707200166675 + + WindowString + 62 385 781 470 0 0 1440 878 + WindowToolGUID + 1C530D57069F1CE1000CFCEE + WindowToolIsVisible + 0 + + + Identifier + windowTool.snapshots + Layout + + + Dock + + + Module + XCSnapshotModule + Proportion + 100% + + + Proportion + 100% + + + Name + Snapshots + ServiceClasses + + XCSnapshotModule + + StatusbarIsVisible + Yes + ToolbarConfiguration + xcode.toolbar.config.snapshots + WindowString + 315 824 300 550 0 0 1440 878 + WindowToolIsVisible + Yes + + + FirstTimeWindowDisplayed + + Identifier + windowTool.debuggerConsole + IsVertical + + Layout + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + 1C78EAAC065D492600B07095 + PBXProjectModuleLabel + Debugger Console + + GeometryConfiguration + + Frame + {{0, 0}, {440, 359}} + RubberWindowFrame + 558 599 440 400 0 0 1680 1028 + + Module + PBXDebugCLIModule + Proportion + 359pt + + + Proportion + 359pt + + + Name + Debugger Console + ServiceClasses + + PBXDebugCLIModule + + StatusbarIsVisible + + TableOfContents + + 1C530D5B069F1CE1000CFCEE + 724A98DD1005A13E001B864B + 1C78EAAC065D492600B07095 + + ToolbarConfiguration + xcode.toolbar.config.consoleV3 + WindowString + 558 599 440 400 0 0 1680 1028 + WindowToolGUID + 1C530D5B069F1CE1000CFCEE + 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.scmV3 + 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 + 3 + MinorVersion + 0 + Name + Breakpoints + ServiceClasses + + PBXSmartGroupTreeModule + XCDetailModule + + StatusbarIsVisible + 1 + TableOfContents + + 1CDDB66807F98D9800BB5817 + 1CDDB66907F98D9800BB5817 + 1CE0B1FE06471DED0097A5F4 + 1CA1AED706398EBD00589147 + + ToolbarConfiguration + xcode.toolbar.config.breakpointsV3 + 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.debugAnimatorV3 + WindowString + 100 100 700 500 0 0 1280 1002 + + + Identifier + windowTool.bookmarks + Layout + + + Dock + + + Module + PBXBookmarksModule + Proportion + 166pt + + + Proportion + 166pt + + + Name + Bookmarks + ServiceClasses + + PBXBookmarksModule + + StatusbarIsVisible + 0 + WindowString + 538 42 401 187 0 0 1280 1002 + + + Identifier + windowTool.projectFormatConflicts + Layout + + + Dock + + + Module + XCProjectFormatConflictsModule + Proportion + 100% + + + Proportion + 100% + + + Name + Project Format Conflicts + ServiceClasses + + XCProjectFormatConflictsModule + + StatusbarIsVisible + 0 + WindowContentMinSize + 450 300 + WindowString + 50 850 472 307 0 0 1440 877 + + + Identifier + windowTool.classBrowser + Layout + + + Dock + + + BecomeActive + 1 + ContentConfiguration + + OptionsSetName + Hierarchy, all classes + PBXProjectModuleGUID + 1CA6456E063B45B4001379D8 + PBXProjectModuleLabel + Class Browser - NSObject + + GeometryConfiguration + + ClassesFrame + {{0, 0}, {369, 96}} + ClassesTreeTableConfiguration + + PBXClassNameColumnIdentifier + 208 + PBXClassBookColumnIdentifier + 22 + + Frame + {{0, 0}, {616, 353}} + MembersFrame + {{0, 105}, {369, 395}} + MembersTreeTableConfiguration + + PBXMemberTypeIconColumnIdentifier + 22 + PBXMemberNameColumnIdentifier + 216 + PBXMemberTypeColumnIdentifier + 94 + PBXMemberBookColumnIdentifier + 22 + + PBXModuleWindowStatusBarHidden2 + 1 + RubberWindowFrame + 597 125 616 374 0 0 1280 1002 + + Module + PBXClassBrowserModule + Proportion + 354pt + + + Proportion + 354pt + + + Name + Class Browser + ServiceClasses + + PBXClassBrowserModule + + StatusbarIsVisible + 0 + TableOfContents + + 1C78EABA065D492600B07095 + 1C78EABB065D492600B07095 + 1CA6456E063B45B4001379D8 + + ToolbarConfiguration + xcode.toolbar.config.classbrowser + WindowString + 597 125 616 374 0 0 1280 1002 + + + Identifier + windowTool.refactoring + IncludeInToolsMenu + 0 + Layout + + + Dock + + + BecomeActive + 1 + GeometryConfiguration + + Frame + {0, 0}, {500, 335} + RubberWindowFrame + {0, 0}, {500, 335} + + Module + XCRefactoringModule + Proportion + 100% + + + Proportion + 100% + + + Name + Refactoring + ServiceClasses + + XCRefactoringModule + + WindowString + 200 200 500 356 0 0 1920 1200 + + + + diff --git a/DoomClassic/code/iphone/Doom.xcodeproj/project.pbxproj b/DoomClassic/code/iphone/Doom.xcodeproj/project.pbxproj new file mode 100755 index 0000000..d671a96 --- /dev/null +++ b/DoomClassic/code/iphone/Doom.xcodeproj/project.pbxproj @@ -0,0 +1,1186 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 132AC2D01801D2E600884E11 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 132AC2CF1801D2E600884E11 /* Default-568h@2x.png */; }; + 132AC2DF1802F15C00884E11 /* ControlsMenuViewi5.xib in Resources */ = {isa = PBXBuildFile; fileRef = 132AC2D71802F15C00884E11 /* ControlsMenuViewi5.xib */; }; + 132AC2E01802F15C00884E11 /* CreditsMenuViewi5.xib in Resources */ = {isa = PBXBuildFile; fileRef = 132AC2D81802F15C00884E11 /* CreditsMenuViewi5.xib */; }; + 132AC2E11802F15C00884E11 /* EpisodeMenuViewi5.xib in Resources */ = {isa = PBXBuildFile; fileRef = 132AC2D91802F15C00884E11 /* EpisodeMenuViewi5.xib */; }; + 132AC2E21802F15C00884E11 /* LegalMenuViewi5.xib in Resources */ = {isa = PBXBuildFile; fileRef = 132AC2DA1802F15C00884E11 /* LegalMenuViewi5.xib */; }; + 132AC2E31802F15C00884E11 /* MainMenuViewi5.xib in Resources */ = {isa = PBXBuildFile; fileRef = 132AC2DB1802F15C00884E11 /* MainMenuViewi5.xib */; }; + 132AC2E41802F15C00884E11 /* MissionMenuViewi5.xib in Resources */ = {isa = PBXBuildFile; fileRef = 132AC2DC1802F15C00884E11 /* MissionMenuViewi5.xib */; }; + 132AC2E51802F15C00884E11 /* OpenGLViewi5.xib in Resources */ = {isa = PBXBuildFile; fileRef = 132AC2DD1802F15C00884E11 /* OpenGLViewi5.xib */; }; + 132AC2E61802F15C00884E11 /* SettingsMenuViewi5.xib in Resources */ = {isa = PBXBuildFile; fileRef = 132AC2DE1802F15C00884E11 /* SettingsMenuViewi5.xib */; }; + 133F3E7017F21C8700A12635 /* MainNavController.m in Sources */ = {isa = PBXBuildFile; fileRef = 133F3E6F17F21C8700A12635 /* MainNavController.m */; }; + 138FC9B817F07DAF00D94C5F /* Nightmare.png in Resources */ = {isa = PBXBuildFile; fileRef = 138FC9B717F07DAF00D94C5F /* Nightmare.png */; }; + 138FC9BB17F0813400D94C5F /* doom_wads.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 138FC9B917F0813400D94C5F /* doom_wads.cpp */; }; + 138FC9C917F216C300D94C5F /* base.iPack in Resources */ = {isa = PBXBuildFile; fileRef = 138FC9C617F2165D00D94C5F /* base.iPack */; }; + 138FC9CA17F216C300D94C5F /* doom.wad in Resources */ = {isa = PBXBuildFile; fileRef = 138FC9C717F2165D00D94C5F /* doom.wad */; }; + 138FC9CB17F216C300D94C5F /* prboom.wad in Resources */ = {isa = PBXBuildFile; fileRef = 138FC9C817F2165D00D94C5F /* prboom.wad */; }; + 1391CE151882E5A30049671C /* libidmobilelib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1391CE141882E5A30049671C /* libidmobilelib.a */; }; + 1391CE171882E5F40049671C /* libprboom.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1391CE161882E5F40049671C /* libprboom.a */; }; + 13E3CC5F17F236840075D40A /* GameKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 13E3CC5E17F236840075D40A /* GameKit.framework */; }; + 13E3CC6417F237B80075D40A /* DOOM_76.png in Resources */ = {isa = PBXBuildFile; fileRef = 13E3CC6017F237B80075D40A /* DOOM_76.png */; }; + 13E3CC6517F237B80075D40A /* DOOM_120.png in Resources */ = {isa = PBXBuildFile; fileRef = 13E3CC6117F237B80075D40A /* DOOM_120.png */; }; + 13E3CC6617F237B80075D40A /* DOOM_144.png in Resources */ = {isa = PBXBuildFile; fileRef = 13E3CC6217F237B80075D40A /* DOOM_144.png */; }; + 13E3CC6717F237B80075D40A /* DOOM_152.png in Resources */ = {isa = PBXBuildFile; fileRef = 13E3CC6317F237B80075D40A /* DOOM_152.png */; }; + 1D60589B0D05DD56006BFB54 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; }; + 3DF31FA3148C336400C66CD7 /* libdoomengine.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DF31F8A148C30F100C66CD7 /* libdoomengine.a */; }; + 4333CCE80F5CC23E00AE2B6F /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4333CCE70F5CC23E00AE2B6F /* AudioToolbox.framework */; }; + 4364BF3F0F5CB25900F29317 /* dist.plist in Resources */ = {isa = PBXBuildFile; fileRef = 4364BF3E0F5CB25900F29317 /* dist.plist */; }; + 43CF02FF0F56974E00E4A23D /* Default.png in Resources */ = {isa = PBXBuildFile; fileRef = 43CF02FE0F56974E00E4A23D /* Default.png */; }; + 43E8D4E00F51B48B003F09B2 /* OpenAL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43E8D4DF0F51B48B003F09B2 /* OpenAL.framework */; }; + 720EBBAE0F82E0BB003F989A /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 720EBBAD0F82E0BB003F989A /* QuartzCore.framework */; }; + C8011C6614BF8BA2007AC5C5 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = C8011C6814BF8BA2007AC5C5 /* Localizable.strings */; }; + C8012E5114B5122700B0E213 /* MainMenuViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = C8012E4F14B5122700B0E213 /* MainMenuViewController.mm */; }; + C8012E5214B5122700B0E213 /* MainMenuView.xib in Resources */ = {isa = PBXBuildFile; fileRef = C8012E5014B5122700B0E213 /* MainMenuView.xib */; }; + C8012E6E14B6389B00B0E213 /* EpisodeMenuViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = C8012E6C14B6389B00B0E213 /* EpisodeMenuViewController.mm */; }; + C8012E6F14B6389B00B0E213 /* EpisodeMenuView.xib in Resources */ = {isa = PBXBuildFile; fileRef = C8012E6D14B6389B00B0E213 /* EpisodeMenuView.xib */; }; + C8012E7414B646BD00B0E213 /* OpenGLView.xib in Resources */ = {isa = PBXBuildFile; fileRef = C8012E7214B646BD00B0E213 /* OpenGLView.xib */; }; + C8012E7814B649DB00B0E213 /* CreditsMenuViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = C8012E7614B649DA00B0E213 /* CreditsMenuViewController.mm */; }; + C8012E7914B649DB00B0E213 /* CreditsMenuView.xib in Resources */ = {isa = PBXBuildFile; fileRef = C8012E7714B649DA00B0E213 /* CreditsMenuView.xib */; }; + C8012E7D14B6704500B0E213 /* ControlsMenuViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = C8012E7B14B6704400B0E213 /* ControlsMenuViewController.mm */; }; + C8012E7E14B6704500B0E213 /* ControlsMenuView.xib in Resources */ = {isa = PBXBuildFile; fileRef = C8012E7C14B6704400B0E213 /* ControlsMenuView.xib */; }; + C8012E8214B6709C00B0E213 /* SettingsMenuViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = C8012E8014B6709B00B0E213 /* SettingsMenuViewController.mm */; }; + C8012E8314B6709C00B0E213 /* SettingsMenuView.xib in Resources */ = {isa = PBXBuildFile; fileRef = C8012E8114B6709C00B0E213 /* SettingsMenuView.xib */; }; + C8012E8714B6722B00B0E213 /* LegalMenuViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = C8012E8514B6722900B0E213 /* LegalMenuViewController.mm */; }; + C8012E8814B6722B00B0E213 /* LegalMenuView.xib in Resources */ = {isa = PBXBuildFile; fileRef = C8012E8614B6722A00B0E213 /* LegalMenuView.xib */; }; + C8012E8D14B6750D00B0E213 /* MissionMenuViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = C8012E8B14B6750A00B0E213 /* MissionMenuViewController.mm */; }; + C8012E8E14B6750D00B0E213 /* MissionMenuView.xib in Resources */ = {isa = PBXBuildFile; fileRef = C8012E8C14B6750B00B0E213 /* MissionMenuView.xib */; }; + C8139AB313FADA800094C2C0 /* SliderSkull@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C8139AB213FADA800094C2C0 /* SliderSkull@2x.png */; }; + C8139AB513FADA9D0094C2C0 /* SliderSkull~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = C8139AB413FADA9D0094C2C0 /* SliderSkull~ipad.png */; }; + C81E0E5E13E076E400B1049A /* idGinzaNar-Md2.otf in Resources */ = {isa = PBXBuildFile; fileRef = C81E0E5D13E076E400B1049A /* idGinzaNar-Md2.otf */; }; + C81E104C13E1CCA000B1049A /* BackButton.png in Resources */ = {isa = PBXBuildFile; fileRef = C81E104013E1CCA000B1049A /* BackButton.png */; }; + C81E104D13E1CCA000B1049A /* Button.png in Resources */ = {isa = PBXBuildFile; fileRef = C81E104113E1CCA000B1049A /* Button.png */; }; + C81E104E13E1CCA000B1049A /* DOOM_sigil_decal.png in Resources */ = {isa = PBXBuildFile; fileRef = C81E104213E1CCA000B1049A /* DOOM_sigil_decal.png */; }; + C81E104F13E1CCA000B1049A /* DoomLogo.png in Resources */ = {isa = PBXBuildFile; fileRef = C81E104313E1CCA000B1049A /* DoomLogo.png */; }; + C81E105013E1CCA000B1049A /* Easy.png in Resources */ = {isa = PBXBuildFile; fileRef = C81E104413E1CCA000B1049A /* Easy.png */; }; + C81E105113E1CCA000B1049A /* Hard.png in Resources */ = {isa = PBXBuildFile; fileRef = C81E104513E1CCA000B1049A /* Hard.png */; }; + C81E105213E1CCA000B1049A /* MapOverlay.png in Resources */ = {isa = PBXBuildFile; fileRef = C81E104613E1CCA000B1049A /* MapOverlay.png */; }; + C81E105313E1CCA000B1049A /* Medium.png in Resources */ = {isa = PBXBuildFile; fileRef = C81E104713E1CCA000B1049A /* Medium.png */; }; + C81E105413E1CCA000B1049A /* MenuBackground.png in Resources */ = {isa = PBXBuildFile; fileRef = C81E104813E1CCA000B1049A /* MenuBackground.png */; }; + C81E105613E1CCA000B1049A /* ResumeButton.png in Resources */ = {isa = PBXBuildFile; fileRef = C81E104A13E1CCA000B1049A /* ResumeButton.png */; }; + C81E105713E1CCA000B1049A /* SelectedBracket.png in Resources */ = {isa = PBXBuildFile; fileRef = C81E104B13E1CCA000B1049A /* SelectedBracket.png */; }; + C86CA86414B4FF2B0057FF54 /* Doom_App.m in Sources */ = {isa = PBXBuildFile; fileRef = C86CA86314B4FF2B0057FF54 /* Doom_App.m */; }; + C8792ED813F5AFE5003D834F /* BackButton_Highlighted.png in Resources */ = {isa = PBXBuildFile; fileRef = C8792ED113F5AFE5003D834F /* BackButton_Highlighted.png */; }; + C8792ED913F5AFE6003D834F /* Button_Highlighted.png in Resources */ = {isa = PBXBuildFile; fileRef = C8792ED213F5AFE5003D834F /* Button_Highlighted.png */; }; + C8792EDA13F5AFE6003D834F /* NextButton_Highlighted.png in Resources */ = {isa = PBXBuildFile; fileRef = C8792ED313F5AFE5003D834F /* NextButton_Highlighted.png */; }; + C8792EDB13F5AFE6003D834F /* NextButton.png in Resources */ = {isa = PBXBuildFile; fileRef = C8792ED413F5AFE5003D834F /* NextButton.png */; }; + C8792EDC13F5AFE6003D834F /* SubMenuBackground.png in Resources */ = {isa = PBXBuildFile; fileRef = C8792ED513F5AFE5003D834F /* SubMenuBackground.png */; }; + C8792EDD13F5AFE6003D834F /* SubMenuButton_Highlighted.png in Resources */ = {isa = PBXBuildFile; fileRef = C8792ED613F5AFE5003D834F /* SubMenuButton_Highlighted.png */; }; + C8792EDE13F5AFE6003D834F /* SubMenuButton.png in Resources */ = {isa = PBXBuildFile; fileRef = C8792ED713F5AFE5003D834F /* SubMenuButton.png */; }; + C879308F13F5D8AA003D834F /* DifficultyBackground.png in Resources */ = {isa = PBXBuildFile; fileRef = C879308513F5D8AA003D834F /* DifficultyBackground.png */; }; + C879309013F5D8AA003D834F /* DownArrow_Highlighted.png in Resources */ = {isa = PBXBuildFile; fileRef = C879308613F5D8AA003D834F /* DownArrow_Highlighted.png */; }; + C879309113F5D8AA003D834F /* DownArrow.png in Resources */ = {isa = PBXBuildFile; fileRef = C879308713F5D8AA003D834F /* DownArrow.png */; }; + C879309213F5D8AA003D834F /* Episode1Background.png in Resources */ = {isa = PBXBuildFile; fileRef = C879308813F5D8AA003D834F /* Episode1Background.png */; }; + C879309313F5D8AA003D834F /* Episode2Background.png in Resources */ = {isa = PBXBuildFile; fileRef = C879308913F5D8AA003D834F /* Episode2Background.png */; }; + C879309413F5D8AA003D834F /* Episode3Background.png in Resources */ = {isa = PBXBuildFile; fileRef = C879308A13F5D8AA003D834F /* Episode3Background.png */; }; + C879309513F5D8AA003D834F /* Episode4Background.png in Resources */ = {isa = PBXBuildFile; fileRef = C879308B13F5D8AA003D834F /* Episode4Background.png */; }; + C879309613F5D8AA003D834F /* MissonBackground.png in Resources */ = {isa = PBXBuildFile; fileRef = C879308C13F5D8AA003D834F /* MissonBackground.png */; }; + C879309713F5D8AA003D834F /* UpArrow_Highlighted.png in Resources */ = {isa = PBXBuildFile; fileRef = C879308D13F5D8AA003D834F /* UpArrow_Highlighted.png */; }; + C879309813F5D8AA003D834F /* UpArrow.png in Resources */ = {isa = PBXBuildFile; fileRef = C879308E13F5D8AA003D834F /* UpArrow.png */; }; + C87930E513F5EC1B003D834F /* Episode1Background_Highlighted.png in Resources */ = {isa = PBXBuildFile; fileRef = C87930E113F5EC1B003D834F /* Episode1Background_Highlighted.png */; }; + C87930E613F5EC1B003D834F /* Episode2Background_Highlighted.png in Resources */ = {isa = PBXBuildFile; fileRef = C87930E213F5EC1B003D834F /* Episode2Background_Highlighted.png */; }; + C87930E713F5EC1B003D834F /* Episode3Background_Highlighted.png in Resources */ = {isa = PBXBuildFile; fileRef = C87930E313F5EC1B003D834F /* Episode3Background_Highlighted.png */; }; + C87930E813F5EC1B003D834F /* Episode4Background_Highlighted.png in Resources */ = {isa = PBXBuildFile; fileRef = C87930E413F5EC1B003D834F /* Episode4Background_Highlighted.png */; }; + C87931EC13F610B9003D834F /* AdvancedButton_Highlighted.png in Resources */ = {isa = PBXBuildFile; fileRef = C87931DE13F610B9003D834F /* AdvancedButton_Highlighted.png */; }; + C87931ED13F610B9003D834F /* AdvancedButton.png in Resources */ = {isa = PBXBuildFile; fileRef = C87931DF13F610B9003D834F /* AdvancedButton.png */; }; + C87931EE13F610B9003D834F /* Divide.png in Resources */ = {isa = PBXBuildFile; fileRef = C87931E013F610B9003D834F /* Divide.png */; }; + C87931EF13F610B9003D834F /* LayoutDualButton_Highlighted.png in Resources */ = {isa = PBXBuildFile; fileRef = C87931E113F610B9003D834F /* LayoutDualButton_Highlighted.png */; }; + C87931F013F610B9003D834F /* LayoutDualButton.png in Resources */ = {isa = PBXBuildFile; fileRef = C87931E213F610B9003D834F /* LayoutDualButton.png */; }; + C87931F113F610B9003D834F /* LayoutSingleButton_Highlighted.png in Resources */ = {isa = PBXBuildFile; fileRef = C87931E313F610B9003D834F /* LayoutSingleButton_Highlighted.png */; }; + C87931F213F610B9003D834F /* LayoutSingleButton.png in Resources */ = {isa = PBXBuildFile; fileRef = C87931E413F610B9003D834F /* LayoutSingleButton.png */; }; + C87931F313F610B9003D834F /* LayoutWheelButton_Highlighted.png in Resources */ = {isa = PBXBuildFile; fileRef = C87931E513F610B9003D834F /* LayoutWheelButton_Highlighted.png */; }; + C87931F413F610B9003D834F /* LayoutWheelButton.png in Resources */ = {isa = PBXBuildFile; fileRef = C87931E613F610B9003D834F /* LayoutWheelButton.png */; }; + C87931F513F610B9003D834F /* SettingsButton_Highlighted.png in Resources */ = {isa = PBXBuildFile; fileRef = C87931E713F610B9003D834F /* SettingsButton_Highlighted.png */; }; + C87931F613F610B9003D834F /* SettingsButton.png in Resources */ = {isa = PBXBuildFile; fileRef = C87931E813F610B9003D834F /* SettingsButton.png */; }; + C87931F913F610B9003D834F /* SliderSkull.png in Resources */ = {isa = PBXBuildFile; fileRef = C87931EB13F610B9003D834F /* SliderSkull.png */; }; + C8D1CF6813DE1EB600F0EAC6 /* DOOM_57.png in Resources */ = {isa = PBXBuildFile; fileRef = C8D1CF6713DE1EB600F0EAC6 /* DOOM_57.png */; }; + C8D1CF6A13DE1EF500F0EAC6 /* DOOM_114.png in Resources */ = {isa = PBXBuildFile; fileRef = C8D1CF6913DE1EF500F0EAC6 /* DOOM_114.png */; }; + C8D1CF6C13DE1F0600F0EAC6 /* DOOM_72.png in Resources */ = {isa = PBXBuildFile; fileRef = C8D1CF6B13DE1F0600F0EAC6 /* DOOM_72.png */; }; + C8D1CF8613DF792D00F0EAC6 /* Default@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C8D1CF8513DF792D00F0EAC6 /* Default@2x.png */; }; + C8D1CF8813DF79BC00F0EAC6 /* Default~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = C8D1CF8713DF79BC00F0EAC6 /* Default~ipad.png */; }; + C8D1CFA813E1CDBD00F0EAC6 /* Default-Portrait~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = C8D1CFA713E1CDBD00F0EAC6 /* Default-Portrait~ipad.png */; }; + C8D1CFAA13E1CDC600F0EAC6 /* Default-Landscape~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = C8D1CFA913E1CDC600F0EAC6 /* Default-Landscape~ipad.png */; }; + C8DB8A5914BB88AC0006467C /* ControlsMenuView~ipad.xib in Resources */ = {isa = PBXBuildFile; fileRef = C8DB8A5114BB88AC0006467C /* ControlsMenuView~ipad.xib */; }; + C8DB8A5A14BB88AC0006467C /* CreditsMenuView~ipad.xib in Resources */ = {isa = PBXBuildFile; fileRef = C8DB8A5214BB88AC0006467C /* CreditsMenuView~ipad.xib */; }; + C8DB8A5B14BB88AC0006467C /* EpisodeMenuView~ipad.xib in Resources */ = {isa = PBXBuildFile; fileRef = C8DB8A5314BB88AC0006467C /* EpisodeMenuView~ipad.xib */; }; + C8DB8A5C14BB88AC0006467C /* LegalMenuView~ipad.xib in Resources */ = {isa = PBXBuildFile; fileRef = C8DB8A5414BB88AC0006467C /* LegalMenuView~ipad.xib */; }; + C8DB8A5D14BB88AC0006467C /* MainMenuView~ipad.xib in Resources */ = {isa = PBXBuildFile; fileRef = C8DB8A5514BB88AC0006467C /* MainMenuView~ipad.xib */; }; + C8DB8A5E14BB88AC0006467C /* MissionMenuView~ipad.xib in Resources */ = {isa = PBXBuildFile; fileRef = C8DB8A5614BB88AC0006467C /* MissionMenuView~ipad.xib */; }; + C8DB8A5F14BB88AC0006467C /* OpenGLView~ipad.xib in Resources */ = {isa = PBXBuildFile; fileRef = C8DB8A5714BB88AC0006467C /* OpenGLView~ipad.xib */; }; + C8DB8A6014BB88AC0006467C /* SettingsMenuView~ipad.xib in Resources */ = {isa = PBXBuildFile; fileRef = C8DB8A5814BB88AC0006467C /* SettingsMenuView~ipad.xib */; }; + EDD2760511C2B19E004A9B9B /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EDD2760411C2B19E004A9B9B /* CoreGraphics.framework */; }; + EDD2760711C2B19E004A9B9B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EDD2760611C2B19E004A9B9B /* Foundation.framework */; }; + EDD2760911C2B19E004A9B9B /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EDD2760811C2B19E004A9B9B /* OpenGLES.framework */; }; + EDD2760B11C2B19E004A9B9B /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EDD2760A11C2B19E004A9B9B /* UIKit.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 3DACFC1B148C591500EB17BA /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 3DF31F85148C30F100C66CD7 /* doomengine.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = 3DE694381489AFDE0049CAA4; + remoteInfo = doomengine; + }; + 3DF31F89148C30F100C66CD7 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 3DF31F85148C30F100C66CD7 /* doomengine.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 3DE694391489AFDE0049CAA4; + remoteInfo = doomengine; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 132AC2CF1801D2E600884E11 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; }; + 132AC2D71802F15C00884E11 /* ControlsMenuViewi5.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ControlsMenuViewi5.xib; sourceTree = ""; }; + 132AC2D81802F15C00884E11 /* CreditsMenuViewi5.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = CreditsMenuViewi5.xib; sourceTree = ""; }; + 132AC2D91802F15C00884E11 /* EpisodeMenuViewi5.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = EpisodeMenuViewi5.xib; sourceTree = ""; }; + 132AC2DA1802F15C00884E11 /* LegalMenuViewi5.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = LegalMenuViewi5.xib; sourceTree = ""; }; + 132AC2DB1802F15C00884E11 /* MainMenuViewi5.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MainMenuViewi5.xib; sourceTree = ""; }; + 132AC2DC1802F15C00884E11 /* MissionMenuViewi5.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MissionMenuViewi5.xib; sourceTree = ""; }; + 132AC2DD1802F15C00884E11 /* OpenGLViewi5.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = OpenGLViewi5.xib; sourceTree = ""; }; + 132AC2DE1802F15C00884E11 /* SettingsMenuViewi5.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SettingsMenuViewi5.xib; sourceTree = ""; }; + 133F3E6E17F21C8700A12635 /* MainNavController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MainNavController.h; sourceTree = ""; }; + 133F3E6F17F21C8700A12635 /* MainNavController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MainNavController.m; sourceTree = ""; }; + 138FC9B717F07DAF00D94C5F /* Nightmare.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Nightmare.png; path = "../../IB Images/Nightmare.png"; sourceTree = ""; }; + 138FC9B917F0813400D94C5F /* doom_wads.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = doom_wads.cpp; sourceTree = ""; }; + 138FC9BA17F0813400D94C5F /* doom_wads.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = doom_wads.h; sourceTree = ""; }; + 138FC9C617F2165D00D94C5F /* base.iPack */ = {isa = PBXFileReference; lastKnownFileType = file; name = base.iPack; path = ../../base/base.iPack; sourceTree = ""; }; + 138FC9C717F2165D00D94C5F /* doom.wad */ = {isa = PBXFileReference; lastKnownFileType = file; name = doom.wad; path = ../../base/doom.wad; sourceTree = ""; }; + 138FC9C817F2165D00D94C5F /* prboom.wad */ = {isa = PBXFileReference; lastKnownFileType = file; name = prboom.wad; path = ../../base/prboom.wad; sourceTree = ""; }; + 1391CE141882E5A30049671C /* libidmobilelib.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libidmobilelib.a; path = "../../../../DerivedData/Build/Products/Debug-iphoneos/libidmobilelib.a"; sourceTree = ""; }; + 1391CE161882E5F40049671C /* libprboom.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libprboom.a; path = "../../../../DerivedData/Build/Products/Debug-iphoneos/libprboom.a"; sourceTree = ""; }; + 13E3CC5E17F236840075D40A /* GameKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GameKit.framework; path = System/Library/Frameworks/GameKit.framework; sourceTree = SDKROOT; }; + 13E3CC6017F237B80075D40A /* DOOM_76.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = DOOM_76.png; sourceTree = ""; }; + 13E3CC6117F237B80075D40A /* DOOM_120.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = DOOM_120.png; sourceTree = ""; }; + 13E3CC6217F237B80075D40A /* DOOM_144.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = DOOM_144.png; sourceTree = ""; }; + 13E3CC6317F237B80075D40A /* DOOM_152.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = DOOM_152.png; sourceTree = ""; }; + 1D6058910D05DD3D006BFB54 /* Doom.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Doom.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 3DF31F85148C30F100C66CD7 /* doomengine.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = doomengine.xcodeproj; path = ../../../common/ios/doomengine.xcodeproj; sourceTree = ""; }; + 4333CCE70F5CC23E00AE2B6F /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = /System/Library/Frameworks/AudioToolbox.framework; sourceTree = ""; }; + 434669A30F8D08C000EA7D6D /* doom_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = doom_Prefix.pch; sourceTree = ""; }; + 4364BF3E0F5CB25900F29317 /* dist.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = dist.plist; sourceTree = ""; }; + 43CF02FE0F56974E00E4A23D /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Default.png; sourceTree = ""; }; + 43E8D4DF0F51B48B003F09B2 /* OpenAL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenAL.framework; path = /System/Library/Frameworks/OpenAL.framework; sourceTree = ""; }; + 720EBBAD0F82E0BB003F989A /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = /System/Library/Frameworks/QuartzCore.framework; sourceTree = ""; }; + 8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + C8011C6714BF8BA2007AC5C5 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; + C8011C6914BF8BAB007AC5C5 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = ""; }; + C8011C6A14BF8BB1007AC5C5 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = ""; }; + C8011C6B14BF8BB4007AC5C5 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = ""; }; + C8011C6C14BF8BBC007AC5C5 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = ""; }; + C8012E4E14B5122700B0E213 /* MainMenuViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MainMenuViewController.h; sourceTree = ""; }; + C8012E4F14B5122700B0E213 /* MainMenuViewController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MainMenuViewController.mm; sourceTree = ""; }; + C8012E5014B5122700B0E213 /* MainMenuView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MainMenuView.xib; sourceTree = ""; }; + C8012E6B14B6389B00B0E213 /* EpisodeMenuViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EpisodeMenuViewController.h; sourceTree = ""; }; + C8012E6C14B6389B00B0E213 /* EpisodeMenuViewController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = EpisodeMenuViewController.mm; sourceTree = ""; }; + C8012E6D14B6389B00B0E213 /* EpisodeMenuView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = EpisodeMenuView.xib; sourceTree = ""; }; + C8012E7214B646BD00B0E213 /* OpenGLView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = OpenGLView.xib; sourceTree = ""; }; + C8012E7514B649D900B0E213 /* CreditsMenuViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CreditsMenuViewController.h; sourceTree = ""; }; + C8012E7614B649DA00B0E213 /* CreditsMenuViewController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CreditsMenuViewController.mm; sourceTree = ""; }; + C8012E7714B649DA00B0E213 /* CreditsMenuView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = CreditsMenuView.xib; sourceTree = ""; }; + C8012E7A14B6704300B0E213 /* ControlsMenuViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ControlsMenuViewController.h; sourceTree = ""; }; + C8012E7B14B6704400B0E213 /* ControlsMenuViewController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ControlsMenuViewController.mm; sourceTree = ""; }; + C8012E7C14B6704400B0E213 /* ControlsMenuView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ControlsMenuView.xib; sourceTree = ""; }; + C8012E7F14B6709B00B0E213 /* SettingsMenuViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SettingsMenuViewController.h; sourceTree = ""; }; + C8012E8014B6709B00B0E213 /* SettingsMenuViewController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = SettingsMenuViewController.mm; sourceTree = ""; }; + C8012E8114B6709C00B0E213 /* SettingsMenuView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SettingsMenuView.xib; sourceTree = ""; }; + C8012E8414B6722800B0E213 /* LegalMenuViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LegalMenuViewController.h; sourceTree = ""; }; + C8012E8514B6722900B0E213 /* LegalMenuViewController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = LegalMenuViewController.mm; sourceTree = ""; }; + C8012E8614B6722A00B0E213 /* LegalMenuView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = LegalMenuView.xib; sourceTree = ""; }; + C8012E8A14B6750900B0E213 /* MissionMenuViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MissionMenuViewController.h; sourceTree = ""; }; + C8012E8B14B6750A00B0E213 /* MissionMenuViewController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MissionMenuViewController.mm; sourceTree = ""; }; + C8012E8C14B6750B00B0E213 /* MissionMenuView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MissionMenuView.xib; sourceTree = ""; }; + C8139AB213FADA800094C2C0 /* SliderSkull@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "SliderSkull@2x.png"; path = "../../IB Images/SliderSkull@2x.png"; sourceTree = SOURCE_ROOT; }; + C8139AB413FADA9D0094C2C0 /* SliderSkull~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "SliderSkull~ipad.png"; path = "../../IB Images/SliderSkull~ipad.png"; sourceTree = SOURCE_ROOT; }; + C81E0E5D13E076E400B1049A /* idGinzaNar-Md2.otf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "idGinzaNar-Md2.otf"; path = "../../idGinzaNar-Md2.otf"; sourceTree = SOURCE_ROOT; }; + C81E104013E1CCA000B1049A /* BackButton.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = BackButton.png; path = "../../IB Images/BackButton.png"; sourceTree = SOURCE_ROOT; }; + C81E104113E1CCA000B1049A /* Button.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Button.png; path = "../../IB Images/Button.png"; sourceTree = SOURCE_ROOT; }; + C81E104213E1CCA000B1049A /* DOOM_sigil_decal.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = DOOM_sigil_decal.png; path = "../../IB Images/DOOM_sigil_decal.png"; sourceTree = SOURCE_ROOT; }; + C81E104313E1CCA000B1049A /* DoomLogo.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = DoomLogo.png; path = "../../IB Images/DoomLogo.png"; sourceTree = SOURCE_ROOT; }; + C81E104413E1CCA000B1049A /* Easy.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Easy.png; path = "../../IB Images/Easy.png"; sourceTree = SOURCE_ROOT; }; + C81E104513E1CCA000B1049A /* Hard.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Hard.png; path = "../../IB Images/Hard.png"; sourceTree = SOURCE_ROOT; }; + C81E104613E1CCA000B1049A /* MapOverlay.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = MapOverlay.png; path = "../../IB Images/MapOverlay.png"; sourceTree = SOURCE_ROOT; }; + C81E104713E1CCA000B1049A /* Medium.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Medium.png; path = "../../IB Images/Medium.png"; sourceTree = SOURCE_ROOT; }; + C81E104813E1CCA000B1049A /* MenuBackground.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = MenuBackground.png; path = "../../IB Images/MenuBackground.png"; sourceTree = SOURCE_ROOT; }; + C81E104A13E1CCA000B1049A /* ResumeButton.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = ResumeButton.png; path = "../../IB Images/ResumeButton.png"; sourceTree = SOURCE_ROOT; }; + C81E104B13E1CCA000B1049A /* SelectedBracket.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = SelectedBracket.png; path = "../../IB Images/SelectedBracket.png"; sourceTree = SOURCE_ROOT; }; + C86CA86214B4FF2B0057FF54 /* Doom_App.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Doom_App.h; sourceTree = ""; }; + C86CA86314B4FF2B0057FF54 /* Doom_App.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Doom_App.m; sourceTree = ""; }; + C8792ED113F5AFE5003D834F /* BackButton_Highlighted.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = BackButton_Highlighted.png; path = "../../IB Images/BackButton_Highlighted.png"; sourceTree = SOURCE_ROOT; }; + C8792ED213F5AFE5003D834F /* Button_Highlighted.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Button_Highlighted.png; path = "../../IB Images/Button_Highlighted.png"; sourceTree = SOURCE_ROOT; }; + C8792ED313F5AFE5003D834F /* NextButton_Highlighted.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = NextButton_Highlighted.png; path = "../../IB Images/NextButton_Highlighted.png"; sourceTree = SOURCE_ROOT; }; + C8792ED413F5AFE5003D834F /* NextButton.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = NextButton.png; path = "../../IB Images/NextButton.png"; sourceTree = SOURCE_ROOT; }; + C8792ED513F5AFE5003D834F /* SubMenuBackground.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = SubMenuBackground.png; path = "../../IB Images/SubMenuBackground.png"; sourceTree = SOURCE_ROOT; }; + C8792ED613F5AFE5003D834F /* SubMenuButton_Highlighted.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = SubMenuButton_Highlighted.png; path = "../../IB Images/SubMenuButton_Highlighted.png"; sourceTree = SOURCE_ROOT; }; + C8792ED713F5AFE5003D834F /* SubMenuButton.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = SubMenuButton.png; path = "../../IB Images/SubMenuButton.png"; sourceTree = SOURCE_ROOT; }; + C879308513F5D8AA003D834F /* DifficultyBackground.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = DifficultyBackground.png; path = "../../IB Images/DifficultyBackground.png"; sourceTree = SOURCE_ROOT; }; + C879308613F5D8AA003D834F /* DownArrow_Highlighted.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = DownArrow_Highlighted.png; path = "../../IB Images/DownArrow_Highlighted.png"; sourceTree = SOURCE_ROOT; }; + C879308713F5D8AA003D834F /* DownArrow.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = DownArrow.png; path = "../../IB Images/DownArrow.png"; sourceTree = SOURCE_ROOT; }; + C879308813F5D8AA003D834F /* Episode1Background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Episode1Background.png; path = "../../IB Images/Episode1Background.png"; sourceTree = SOURCE_ROOT; }; + C879308913F5D8AA003D834F /* Episode2Background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Episode2Background.png; path = "../../IB Images/Episode2Background.png"; sourceTree = SOURCE_ROOT; }; + C879308A13F5D8AA003D834F /* Episode3Background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Episode3Background.png; path = "../../IB Images/Episode3Background.png"; sourceTree = SOURCE_ROOT; }; + C879308B13F5D8AA003D834F /* Episode4Background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Episode4Background.png; path = "../../IB Images/Episode4Background.png"; sourceTree = SOURCE_ROOT; }; + C879308C13F5D8AA003D834F /* MissonBackground.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = MissonBackground.png; path = "../../IB Images/MissonBackground.png"; sourceTree = SOURCE_ROOT; }; + C879308D13F5D8AA003D834F /* UpArrow_Highlighted.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = UpArrow_Highlighted.png; path = "../../IB Images/UpArrow_Highlighted.png"; sourceTree = SOURCE_ROOT; }; + C879308E13F5D8AA003D834F /* UpArrow.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = UpArrow.png; path = "../../IB Images/UpArrow.png"; sourceTree = SOURCE_ROOT; }; + C87930E113F5EC1B003D834F /* Episode1Background_Highlighted.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Episode1Background_Highlighted.png; path = "../../IB Images/Episode1Background_Highlighted.png"; sourceTree = SOURCE_ROOT; }; + C87930E213F5EC1B003D834F /* Episode2Background_Highlighted.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Episode2Background_Highlighted.png; path = "../../IB Images/Episode2Background_Highlighted.png"; sourceTree = SOURCE_ROOT; }; + C87930E313F5EC1B003D834F /* Episode3Background_Highlighted.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Episode3Background_Highlighted.png; path = "../../IB Images/Episode3Background_Highlighted.png"; sourceTree = SOURCE_ROOT; }; + C87930E413F5EC1B003D834F /* Episode4Background_Highlighted.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Episode4Background_Highlighted.png; path = "../../IB Images/Episode4Background_Highlighted.png"; sourceTree = SOURCE_ROOT; }; + C87931DE13F610B9003D834F /* AdvancedButton_Highlighted.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = AdvancedButton_Highlighted.png; path = "../../IB Images/AdvancedButton_Highlighted.png"; sourceTree = SOURCE_ROOT; }; + C87931DF13F610B9003D834F /* AdvancedButton.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = AdvancedButton.png; path = "../../IB Images/AdvancedButton.png"; sourceTree = SOURCE_ROOT; }; + C87931E013F610B9003D834F /* Divide.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Divide.png; path = "../../IB Images/Divide.png"; sourceTree = SOURCE_ROOT; }; + C87931E113F610B9003D834F /* LayoutDualButton_Highlighted.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = LayoutDualButton_Highlighted.png; path = "../../IB Images/LayoutDualButton_Highlighted.png"; sourceTree = SOURCE_ROOT; }; + C87931E213F610B9003D834F /* LayoutDualButton.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = LayoutDualButton.png; path = "../../IB Images/LayoutDualButton.png"; sourceTree = SOURCE_ROOT; }; + C87931E313F610B9003D834F /* LayoutSingleButton_Highlighted.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = LayoutSingleButton_Highlighted.png; path = "../../IB Images/LayoutSingleButton_Highlighted.png"; sourceTree = SOURCE_ROOT; }; + C87931E413F610B9003D834F /* LayoutSingleButton.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = LayoutSingleButton.png; path = "../../IB Images/LayoutSingleButton.png"; sourceTree = SOURCE_ROOT; }; + C87931E513F610B9003D834F /* LayoutWheelButton_Highlighted.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = LayoutWheelButton_Highlighted.png; path = "../../IB Images/LayoutWheelButton_Highlighted.png"; sourceTree = SOURCE_ROOT; }; + C87931E613F610B9003D834F /* LayoutWheelButton.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = LayoutWheelButton.png; path = "../../IB Images/LayoutWheelButton.png"; sourceTree = SOURCE_ROOT; }; + C87931E713F610B9003D834F /* SettingsButton_Highlighted.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = SettingsButton_Highlighted.png; path = "../../IB Images/SettingsButton_Highlighted.png"; sourceTree = SOURCE_ROOT; }; + C87931E813F610B9003D834F /* SettingsButton.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = SettingsButton.png; path = "../../IB Images/SettingsButton.png"; sourceTree = SOURCE_ROOT; }; + C87931EB13F610B9003D834F /* SliderSkull.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = SliderSkull.png; path = "../../IB Images/SliderSkull.png"; sourceTree = SOURCE_ROOT; }; + C8D1CF6713DE1EB600F0EAC6 /* DOOM_57.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = DOOM_57.png; sourceTree = ""; }; + C8D1CF6913DE1EF500F0EAC6 /* DOOM_114.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = DOOM_114.png; sourceTree = ""; }; + C8D1CF6B13DE1F0600F0EAC6 /* DOOM_72.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = DOOM_72.png; sourceTree = ""; }; + C8D1CF8513DF792D00F0EAC6 /* Default@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default@2x.png"; sourceTree = ""; }; + C8D1CF8713DF79BC00F0EAC6 /* Default~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default~ipad.png"; sourceTree = ""; }; + C8D1CFA713E1CDBD00F0EAC6 /* Default-Portrait~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-Portrait~ipad.png"; sourceTree = ""; }; + C8D1CFA913E1CDC600F0EAC6 /* Default-Landscape~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-Landscape~ipad.png"; sourceTree = ""; }; + C8DB8A5114BB88AC0006467C /* ControlsMenuView~ipad.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = "ControlsMenuView~ipad.xib"; sourceTree = ""; }; + C8DB8A5214BB88AC0006467C /* CreditsMenuView~ipad.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = "CreditsMenuView~ipad.xib"; sourceTree = ""; }; + C8DB8A5314BB88AC0006467C /* EpisodeMenuView~ipad.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = "EpisodeMenuView~ipad.xib"; sourceTree = ""; }; + C8DB8A5414BB88AC0006467C /* LegalMenuView~ipad.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = "LegalMenuView~ipad.xib"; sourceTree = ""; }; + C8DB8A5514BB88AC0006467C /* MainMenuView~ipad.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = "MainMenuView~ipad.xib"; sourceTree = ""; }; + C8DB8A5614BB88AC0006467C /* MissionMenuView~ipad.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = "MissionMenuView~ipad.xib"; sourceTree = ""; }; + C8DB8A5714BB88AC0006467C /* OpenGLView~ipad.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = "OpenGLView~ipad.xib"; sourceTree = ""; }; + C8DB8A5814BB88AC0006467C /* SettingsMenuView~ipad.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = "SettingsMenuView~ipad.xib"; sourceTree = ""; }; + EDD2760411C2B19E004A9B9B /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; + EDD2760611C2B19E004A9B9B /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + EDD2760811C2B19E004A9B9B /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = System/Library/Frameworks/OpenGLES.framework; sourceTree = SDKROOT; }; + EDD2760A11C2B19E004A9B9B /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 1D60588F0D05DD3D006BFB54 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 1391CE171882E5F40049671C /* libprboom.a in Frameworks */, + 1391CE151882E5A30049671C /* libidmobilelib.a in Frameworks */, + 13E3CC5F17F236840075D40A /* GameKit.framework in Frameworks */, + 3DF31FA3148C336400C66CD7 /* libdoomengine.a in Frameworks */, + 43E8D4E00F51B48B003F09B2 /* OpenAL.framework in Frameworks */, + 4333CCE80F5CC23E00AE2B6F /* AudioToolbox.framework in Frameworks */, + 720EBBAE0F82E0BB003F989A /* QuartzCore.framework in Frameworks */, + EDD2760511C2B19E004A9B9B /* CoreGraphics.framework in Frameworks */, + EDD2760711C2B19E004A9B9B /* Foundation.framework in Frameworks */, + EDD2760911C2B19E004A9B9B /* OpenGLES.framework in Frameworks */, + EDD2760B11C2B19E004A9B9B /* UIKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 132AC2D61802F12200884E11 /* iPhone4Inch */ = { + isa = PBXGroup; + children = ( + 132AC2D71802F15C00884E11 /* ControlsMenuViewi5.xib */, + 132AC2D81802F15C00884E11 /* CreditsMenuViewi5.xib */, + 132AC2D91802F15C00884E11 /* EpisodeMenuViewi5.xib */, + 132AC2DA1802F15C00884E11 /* LegalMenuViewi5.xib */, + 132AC2DB1802F15C00884E11 /* MainMenuViewi5.xib */, + 132AC2DC1802F15C00884E11 /* MissionMenuViewi5.xib */, + 132AC2DD1802F15C00884E11 /* OpenGLViewi5.xib */, + 132AC2DE1802F15C00884E11 /* SettingsMenuViewi5.xib */, + ); + name = iPhone4Inch; + sourceTree = ""; + }; + 19C28FACFE9D520D11CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + 1D6058910D05DD3D006BFB54 /* Doom.app */, + 4364BF3E0F5CB25900F29317 /* dist.plist */, + ); + name = Products; + sourceTree = ""; + }; + 29B97314FDCFA39411CA2CEA /* CustomTemplate */ = { + isa = PBXGroup; + children = ( + 132AC2CF1801D2E600884E11 /* Default-568h@2x.png */, + 3DF31F85148C30F100C66CD7 /* doomengine.xcodeproj */, + 29B97315FDCFA39411CA2CEA /* Source */, + 29B97317FDCFA39411CA2CEA /* App Resources */, + 29B97323FDCFA39411CA2CEA /* Frameworks */, + 19C28FACFE9D520D11CA2CBB /* Products */, + ); + name = CustomTemplate; + sourceTree = ""; + }; + 29B97315FDCFA39411CA2CEA /* Source */ = { + isa = PBXGroup; + children = ( + C86CA85E14B4F5CC0057FF54 /* Doom */, + C86F965213D615BB0069B7B6 /* Interface Builder */, + ); + name = Source; + sourceTree = ""; + }; + 29B97317FDCFA39411CA2CEA /* App Resources */ = { + isa = PBXGroup; + children = ( + 138FC9C617F2165D00D94C5F /* base.iPack */, + 138FC9C717F2165D00D94C5F /* doom.wad */, + 138FC9C817F2165D00D94C5F /* prboom.wad */, + C86CA86714B502C90057FF54 /* Icons & Defaults */, + C86CA86114B4FD230057FF54 /* Menus */, + C84F820613D73D28006D01AB /* Images */, + C81E0E5D13E076E400B1049A /* idGinzaNar-Md2.otf */, + 43CF02FE0F56974E00E4A23D /* Default.png */, + 8D1107310486CEB800E47090 /* Info.plist */, + C8011C6814BF8BA2007AC5C5 /* Localizable.strings */, + ); + name = "App Resources"; + sourceTree = ""; + }; + 29B97323FDCFA39411CA2CEA /* Frameworks */ = { + isa = PBXGroup; + children = ( + 1391CE161882E5F40049671C /* libprboom.a */, + 1391CE141882E5A30049671C /* libidmobilelib.a */, + 13E3CC5E17F236840075D40A /* GameKit.framework */, + 4333CCE70F5CC23E00AE2B6F /* AudioToolbox.framework */, + EDD2760411C2B19E004A9B9B /* CoreGraphics.framework */, + EDD2760611C2B19E004A9B9B /* Foundation.framework */, + 43E8D4DF0F51B48B003F09B2 /* OpenAL.framework */, + EDD2760811C2B19E004A9B9B /* OpenGLES.framework */, + 720EBBAD0F82E0BB003F989A /* QuartzCore.framework */, + EDD2760A11C2B19E004A9B9B /* UIKit.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 3DF31F86148C30F100C66CD7 /* Products */ = { + isa = PBXGroup; + children = ( + 3DF31F8A148C30F100C66CD7 /* libdoomengine.a */, + ); + name = Products; + sourceTree = ""; + }; + C8012E4B14B510BA00B0E213 /* iPhone */ = { + isa = PBXGroup; + children = ( + C8012E8C14B6750B00B0E213 /* MissionMenuView.xib */, + C8012E8614B6722A00B0E213 /* LegalMenuView.xib */, + C8012E8114B6709C00B0E213 /* SettingsMenuView.xib */, + C8012E7C14B6704400B0E213 /* ControlsMenuView.xib */, + C8012E7714B649DA00B0E213 /* CreditsMenuView.xib */, + C8012E6D14B6389B00B0E213 /* EpisodeMenuView.xib */, + C8012E5014B5122700B0E213 /* MainMenuView.xib */, + C8012E7214B646BD00B0E213 /* OpenGLView.xib */, + ); + name = iPhone; + sourceTree = ""; + }; + C8012E4C14B510C600B0E213 /* iPad */ = { + isa = PBXGroup; + children = ( + C8DB8A5114BB88AC0006467C /* ControlsMenuView~ipad.xib */, + C8DB8A5214BB88AC0006467C /* CreditsMenuView~ipad.xib */, + C8DB8A5314BB88AC0006467C /* EpisodeMenuView~ipad.xib */, + C8DB8A5414BB88AC0006467C /* LegalMenuView~ipad.xib */, + C8DB8A5514BB88AC0006467C /* MainMenuView~ipad.xib */, + C8DB8A5614BB88AC0006467C /* MissionMenuView~ipad.xib */, + C8DB8A5714BB88AC0006467C /* OpenGLView~ipad.xib */, + C8DB8A5814BB88AC0006467C /* SettingsMenuView~ipad.xib */, + ); + name = iPad; + sourceTree = ""; + }; + C84F820613D73D28006D01AB /* Images */ = { + isa = PBXGroup; + children = ( + 138FC9B717F07DAF00D94C5F /* Nightmare.png */, + C8139AB413FADA9D0094C2C0 /* SliderSkull~ipad.png */, + C8139AB213FADA800094C2C0 /* SliderSkull@2x.png */, + C87931DE13F610B9003D834F /* AdvancedButton_Highlighted.png */, + C87931DF13F610B9003D834F /* AdvancedButton.png */, + C87931E013F610B9003D834F /* Divide.png */, + C87931E113F610B9003D834F /* LayoutDualButton_Highlighted.png */, + C87931E213F610B9003D834F /* LayoutDualButton.png */, + C87931E313F610B9003D834F /* LayoutSingleButton_Highlighted.png */, + C87931E413F610B9003D834F /* LayoutSingleButton.png */, + C87931E513F610B9003D834F /* LayoutWheelButton_Highlighted.png */, + C87931E613F610B9003D834F /* LayoutWheelButton.png */, + C87931E713F610B9003D834F /* SettingsButton_Highlighted.png */, + C87931E813F610B9003D834F /* SettingsButton.png */, + C87931EB13F610B9003D834F /* SliderSkull.png */, + C87930E113F5EC1B003D834F /* Episode1Background_Highlighted.png */, + C87930E213F5EC1B003D834F /* Episode2Background_Highlighted.png */, + C87930E313F5EC1B003D834F /* Episode3Background_Highlighted.png */, + C87930E413F5EC1B003D834F /* Episode4Background_Highlighted.png */, + C879308513F5D8AA003D834F /* DifficultyBackground.png */, + C879308613F5D8AA003D834F /* DownArrow_Highlighted.png */, + C879308713F5D8AA003D834F /* DownArrow.png */, + C879308813F5D8AA003D834F /* Episode1Background.png */, + C879308913F5D8AA003D834F /* Episode2Background.png */, + C879308A13F5D8AA003D834F /* Episode3Background.png */, + C879308B13F5D8AA003D834F /* Episode4Background.png */, + C879308C13F5D8AA003D834F /* MissonBackground.png */, + C879308D13F5D8AA003D834F /* UpArrow_Highlighted.png */, + C879308E13F5D8AA003D834F /* UpArrow.png */, + C8792ED113F5AFE5003D834F /* BackButton_Highlighted.png */, + C8792ED213F5AFE5003D834F /* Button_Highlighted.png */, + C8792ED313F5AFE5003D834F /* NextButton_Highlighted.png */, + C8792ED413F5AFE5003D834F /* NextButton.png */, + C8792ED513F5AFE5003D834F /* SubMenuBackground.png */, + C8792ED613F5AFE5003D834F /* SubMenuButton_Highlighted.png */, + C8792ED713F5AFE5003D834F /* SubMenuButton.png */, + C81E104013E1CCA000B1049A /* BackButton.png */, + C81E104113E1CCA000B1049A /* Button.png */, + C81E104213E1CCA000B1049A /* DOOM_sigil_decal.png */, + C81E104313E1CCA000B1049A /* DoomLogo.png */, + C81E104413E1CCA000B1049A /* Easy.png */, + C81E104513E1CCA000B1049A /* Hard.png */, + C81E104613E1CCA000B1049A /* MapOverlay.png */, + C81E104713E1CCA000B1049A /* Medium.png */, + C81E104813E1CCA000B1049A /* MenuBackground.png */, + C81E104A13E1CCA000B1049A /* ResumeButton.png */, + C81E104B13E1CCA000B1049A /* SelectedBracket.png */, + ); + name = Images; + sourceTree = ""; + }; + C86CA85E14B4F5CC0057FF54 /* Doom */ = { + isa = PBXGroup; + children = ( + 138FC9B917F0813400D94C5F /* doom_wads.cpp */, + 138FC9BA17F0813400D94C5F /* doom_wads.h */, + 434669A30F8D08C000EA7D6D /* doom_Prefix.pch */, + C86CA86214B4FF2B0057FF54 /* Doom_App.h */, + C86CA86314B4FF2B0057FF54 /* Doom_App.m */, + 29B97316FDCFA39411CA2CEA /* main.m */, + ); + name = Doom; + sourceTree = ""; + }; + C86CA86114B4FD230057FF54 /* Menus */ = { + isa = PBXGroup; + children = ( + 132AC2D61802F12200884E11 /* iPhone4Inch */, + C8012E4C14B510C600B0E213 /* iPad */, + C8012E4B14B510BA00B0E213 /* iPhone */, + ); + name = Menus; + sourceTree = ""; + }; + C86CA86514B501620057FF54 /* View Controllers */ = { + isa = PBXGroup; + children = ( + C8DB88F814BB5FA40006467C /* About menus */, + C8DB88F714BB5F940006467C /* Setting menus */, + C8DB88F614BB5F840006467C /* Play menus */, + C8012E4E14B5122700B0E213 /* MainMenuViewController.h */, + C8012E4F14B5122700B0E213 /* MainMenuViewController.mm */, + ); + name = "View Controllers"; + sourceTree = ""; + }; + C86CA86714B502C90057FF54 /* Icons & Defaults */ = { + isa = PBXGroup; + children = ( + 13E3CC6017F237B80075D40A /* DOOM_76.png */, + 13E3CC6117F237B80075D40A /* DOOM_120.png */, + 13E3CC6217F237B80075D40A /* DOOM_144.png */, + 13E3CC6317F237B80075D40A /* DOOM_152.png */, + C8D1CFA913E1CDC600F0EAC6 /* Default-Landscape~ipad.png */, + C8D1CFA713E1CDBD00F0EAC6 /* Default-Portrait~ipad.png */, + C8D1CF8713DF79BC00F0EAC6 /* Default~ipad.png */, + C8D1CF8513DF792D00F0EAC6 /* Default@2x.png */, + C8D1CF6B13DE1F0600F0EAC6 /* DOOM_72.png */, + C8D1CF6913DE1EF500F0EAC6 /* DOOM_114.png */, + C8D1CF6713DE1EB600F0EAC6 /* DOOM_57.png */, + ); + name = "Icons & Defaults"; + sourceTree = ""; + }; + C86F965213D615BB0069B7B6 /* Interface Builder */ = { + isa = PBXGroup; + children = ( + C86CA86514B501620057FF54 /* View Controllers */, + 133F3E6E17F21C8700A12635 /* MainNavController.h */, + 133F3E6F17F21C8700A12635 /* MainNavController.m */, + ); + name = "Interface Builder"; + sourceTree = ""; + }; + C8DB88F614BB5F840006467C /* Play menus */ = { + isa = PBXGroup; + children = ( + C8012E6B14B6389B00B0E213 /* EpisodeMenuViewController.h */, + C8012E6C14B6389B00B0E213 /* EpisodeMenuViewController.mm */, + C8012E8A14B6750900B0E213 /* MissionMenuViewController.h */, + C8012E8B14B6750A00B0E213 /* MissionMenuViewController.mm */, + ); + name = "Play menus"; + sourceTree = ""; + }; + C8DB88F714BB5F940006467C /* Setting menus */ = { + isa = PBXGroup; + children = ( + C8012E7A14B6704300B0E213 /* ControlsMenuViewController.h */, + C8012E7B14B6704400B0E213 /* ControlsMenuViewController.mm */, + C8012E7F14B6709B00B0E213 /* SettingsMenuViewController.h */, + C8012E8014B6709B00B0E213 /* SettingsMenuViewController.mm */, + ); + name = "Setting menus"; + sourceTree = ""; + }; + C8DB88F814BB5FA40006467C /* About menus */ = { + isa = PBXGroup; + children = ( + C8012E7514B649D900B0E213 /* CreditsMenuViewController.h */, + C8012E7614B649DA00B0E213 /* CreditsMenuViewController.mm */, + C8012E8414B6722800B0E213 /* LegalMenuViewController.h */, + C8012E8514B6722900B0E213 /* LegalMenuViewController.mm */, + ); + name = "About menus"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 1D6058900D05DD3D006BFB54 /* Doom */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "Doom" */; + buildPhases = ( + 1D60588D0D05DD3D006BFB54 /* Resources */, + 1D60588E0D05DD3D006BFB54 /* Sources */, + 1D60588F0D05DD3D006BFB54 /* Frameworks */, + 435F41A90F532CA300887552 /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + 3DACFC1C148C591500EB17BA /* PBXTargetDependency */, + ); + name = Doom; + productName = Doom; + productReference = 1D6058910D05DD3D006BFB54 /* Doom.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 29B97313FDCFA39411CA2CEA /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0500; + TargetAttributes = { + 1D6058900D05DD3D006BFB54 = { + DevelopmentTeam = VH3C8HCNLH; + SystemCapabilities = { + com.apple.GameCenter = { + enabled = 1; + }; + com.apple.InAppPurchase = { + enabled = 0; + }; + }; + }; + }; + }; + buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "Doom" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 1; + knownRegions = ( + English, + Japanese, + French, + German, + fr, + it, + de, + es, + ); + mainGroup = 29B97314FDCFA39411CA2CEA /* CustomTemplate */; + projectDirPath = ""; + projectReferences = ( + { + ProductGroup = 3DF31F86148C30F100C66CD7 /* Products */; + ProjectRef = 3DF31F85148C30F100C66CD7 /* doomengine.xcodeproj */; + }, + ); + projectRoot = ../..; + targets = ( + 1D6058900D05DD3D006BFB54 /* Doom */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXReferenceProxy section */ + 3DF31F8A148C30F100C66CD7 /* libdoomengine.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libdoomengine.a; + remoteRef = 3DF31F89148C30F100C66CD7 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; +/* End PBXReferenceProxy section */ + +/* Begin PBXResourcesBuildPhase section */ + 1D60588D0D05DD3D006BFB54 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 138FC9C917F216C300D94C5F /* base.iPack in Resources */, + 138FC9CA17F216C300D94C5F /* doom.wad in Resources */, + 138FC9CB17F216C300D94C5F /* prboom.wad in Resources */, + 43CF02FF0F56974E00E4A23D /* Default.png in Resources */, + 4364BF3F0F5CB25900F29317 /* dist.plist in Resources */, + 132AC2D01801D2E600884E11 /* Default-568h@2x.png in Resources */, + C8D1CF6813DE1EB600F0EAC6 /* DOOM_57.png in Resources */, + 138FC9B817F07DAF00D94C5F /* Nightmare.png in Resources */, + C8D1CF6A13DE1EF500F0EAC6 /* DOOM_114.png in Resources */, + C8D1CF6C13DE1F0600F0EAC6 /* DOOM_72.png in Resources */, + C8D1CF8613DF792D00F0EAC6 /* Default@2x.png in Resources */, + C8D1CF8813DF79BC00F0EAC6 /* Default~ipad.png in Resources */, + C81E0E5E13E076E400B1049A /* idGinzaNar-Md2.otf in Resources */, + C81E104C13E1CCA000B1049A /* BackButton.png in Resources */, + C81E104D13E1CCA000B1049A /* Button.png in Resources */, + C81E104E13E1CCA000B1049A /* DOOM_sigil_decal.png in Resources */, + C81E104F13E1CCA000B1049A /* DoomLogo.png in Resources */, + C81E105013E1CCA000B1049A /* Easy.png in Resources */, + C81E105113E1CCA000B1049A /* Hard.png in Resources */, + C81E105213E1CCA000B1049A /* MapOverlay.png in Resources */, + C81E105313E1CCA000B1049A /* Medium.png in Resources */, + 132AC2E51802F15C00884E11 /* OpenGLViewi5.xib in Resources */, + C81E105413E1CCA000B1049A /* MenuBackground.png in Resources */, + C81E105613E1CCA000B1049A /* ResumeButton.png in Resources */, + C81E105713E1CCA000B1049A /* SelectedBracket.png in Resources */, + C8D1CFA813E1CDBD00F0EAC6 /* Default-Portrait~ipad.png in Resources */, + C8D1CFAA13E1CDC600F0EAC6 /* Default-Landscape~ipad.png in Resources */, + C8792ED813F5AFE5003D834F /* BackButton_Highlighted.png in Resources */, + 13E3CC6617F237B80075D40A /* DOOM_144.png in Resources */, + C8792ED913F5AFE6003D834F /* Button_Highlighted.png in Resources */, + C8792EDA13F5AFE6003D834F /* NextButton_Highlighted.png in Resources */, + C8792EDB13F5AFE6003D834F /* NextButton.png in Resources */, + C8792EDC13F5AFE6003D834F /* SubMenuBackground.png in Resources */, + C8792EDD13F5AFE6003D834F /* SubMenuButton_Highlighted.png in Resources */, + C8792EDE13F5AFE6003D834F /* SubMenuButton.png in Resources */, + C879308F13F5D8AA003D834F /* DifficultyBackground.png in Resources */, + C879309013F5D8AA003D834F /* DownArrow_Highlighted.png in Resources */, + C879309113F5D8AA003D834F /* DownArrow.png in Resources */, + C879309213F5D8AA003D834F /* Episode1Background.png in Resources */, + C879309313F5D8AA003D834F /* Episode2Background.png in Resources */, + C879309413F5D8AA003D834F /* Episode3Background.png in Resources */, + 132AC2DF1802F15C00884E11 /* ControlsMenuViewi5.xib in Resources */, + C879309513F5D8AA003D834F /* Episode4Background.png in Resources */, + C879309613F5D8AA003D834F /* MissonBackground.png in Resources */, + C879309713F5D8AA003D834F /* UpArrow_Highlighted.png in Resources */, + C879309813F5D8AA003D834F /* UpArrow.png in Resources */, + 13E3CC6517F237B80075D40A /* DOOM_120.png in Resources */, + C87930E513F5EC1B003D834F /* Episode1Background_Highlighted.png in Resources */, + 132AC2E21802F15C00884E11 /* LegalMenuViewi5.xib in Resources */, + C87930E613F5EC1B003D834F /* Episode2Background_Highlighted.png in Resources */, + C87930E713F5EC1B003D834F /* Episode3Background_Highlighted.png in Resources */, + C87930E813F5EC1B003D834F /* Episode4Background_Highlighted.png in Resources */, + 132AC2E01802F15C00884E11 /* CreditsMenuViewi5.xib in Resources */, + C87931EC13F610B9003D834F /* AdvancedButton_Highlighted.png in Resources */, + C87931ED13F610B9003D834F /* AdvancedButton.png in Resources */, + C87931EE13F610B9003D834F /* Divide.png in Resources */, + C87931EF13F610B9003D834F /* LayoutDualButton_Highlighted.png in Resources */, + C87931F013F610B9003D834F /* LayoutDualButton.png in Resources */, + C87931F113F610B9003D834F /* LayoutSingleButton_Highlighted.png in Resources */, + C87931F213F610B9003D834F /* LayoutSingleButton.png in Resources */, + C87931F313F610B9003D834F /* LayoutWheelButton_Highlighted.png in Resources */, + 132AC2E31802F15C00884E11 /* MainMenuViewi5.xib in Resources */, + C87931F413F610B9003D834F /* LayoutWheelButton.png in Resources */, + 132AC2E11802F15C00884E11 /* EpisodeMenuViewi5.xib in Resources */, + C87931F513F610B9003D834F /* SettingsButton_Highlighted.png in Resources */, + C87931F613F610B9003D834F /* SettingsButton.png in Resources */, + 13E3CC6417F237B80075D40A /* DOOM_76.png in Resources */, + C87931F913F610B9003D834F /* SliderSkull.png in Resources */, + C8139AB313FADA800094C2C0 /* SliderSkull@2x.png in Resources */, + C8139AB513FADA9D0094C2C0 /* SliderSkull~ipad.png in Resources */, + C8012E5214B5122700B0E213 /* MainMenuView.xib in Resources */, + C8012E6F14B6389B00B0E213 /* EpisodeMenuView.xib in Resources */, + C8012E7414B646BD00B0E213 /* OpenGLView.xib in Resources */, + C8012E7914B649DB00B0E213 /* CreditsMenuView.xib in Resources */, + 13E3CC6717F237B80075D40A /* DOOM_152.png in Resources */, + C8012E7E14B6704500B0E213 /* ControlsMenuView.xib in Resources */, + C8012E8314B6709C00B0E213 /* SettingsMenuView.xib in Resources */, + C8012E8814B6722B00B0E213 /* LegalMenuView.xib in Resources */, + C8012E8E14B6750D00B0E213 /* MissionMenuView.xib in Resources */, + 132AC2E41802F15C00884E11 /* MissionMenuViewi5.xib in Resources */, + 132AC2E61802F15C00884E11 /* SettingsMenuViewi5.xib in Resources */, + C8DB8A5914BB88AC0006467C /* ControlsMenuView~ipad.xib in Resources */, + C8DB8A5A14BB88AC0006467C /* CreditsMenuView~ipad.xib in Resources */, + C8DB8A5B14BB88AC0006467C /* EpisodeMenuView~ipad.xib in Resources */, + C8DB8A5C14BB88AC0006467C /* LegalMenuView~ipad.xib in Resources */, + C8DB8A5D14BB88AC0006467C /* MainMenuView~ipad.xib in Resources */, + C8DB8A5E14BB88AC0006467C /* MissionMenuView~ipad.xib in Resources */, + C8DB8A5F14BB88AC0006467C /* OpenGLView~ipad.xib in Resources */, + C8DB8A6014BB88AC0006467C /* SettingsMenuView~ipad.xib in Resources */, + C8011C6614BF8BA2007AC5C5 /* Localizable.strings in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 435F41A90F532CA300887552 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = "/bin/sh -x"; + shellScript = " +"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 1D60588E0D05DD3D006BFB54 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1D60589B0D05DD56006BFB54 /* main.m in Sources */, + C86CA86414B4FF2B0057FF54 /* Doom_App.m in Sources */, + C8012E5114B5122700B0E213 /* MainMenuViewController.mm in Sources */, + C8012E6E14B6389B00B0E213 /* EpisodeMenuViewController.mm in Sources */, + C8012E7814B649DB00B0E213 /* CreditsMenuViewController.mm in Sources */, + 133F3E7017F21C8700A12635 /* MainNavController.m in Sources */, + 138FC9BB17F0813400D94C5F /* doom_wads.cpp in Sources */, + C8012E7D14B6704500B0E213 /* ControlsMenuViewController.mm in Sources */, + C8012E8214B6709C00B0E213 /* SettingsMenuViewController.mm in Sources */, + C8012E8714B6722B00B0E213 /* LegalMenuViewController.mm in Sources */, + C8012E8D14B6750D00B0E213 /* MissionMenuViewController.mm in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 3DACFC1C148C591500EB17BA /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = doomengine; + targetProxy = 3DACFC1B148C591500EB17BA /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + C8011C6814BF8BA2007AC5C5 /* Localizable.strings */ = { + isa = PBXVariantGroup; + children = ( + C8011C6714BF8BA2007AC5C5 /* en */, + C8011C6914BF8BAB007AC5C5 /* fr */, + C8011C6A14BF8BB1007AC5C5 /* it */, + C8011C6B14BF8BB4007AC5C5 /* de */, + C8011C6C14BF8BBC007AC5C5 /* es */, + ); + name = Localizable.strings; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 1D6058940D05DD3E006BFB54 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = doom_Prefix.pch; + GCC_PREPROCESSOR_DEFINITIONS = ( + _DEBUG, + HAVE_CONFIG_H, + IPHONE, + ); + GCC_THUMB_SUPPORT = NO; + GCC_TREAT_WARNINGS_AS_ERRORS = NO; + HEADER_SEARCH_PATHS = ""; + INFOPLIST_FILE = Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 6.1; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "/Work/DerivedData/Build/Products/Debug-iphoneos", + ); + PROFILE_PREFIX = com.idsoftware; + PROVISIONING_PROFILE = ""; + "PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + USER_HEADER_SEARCH_PATHS = "../../../common/ios/doomengine ../../../common ../../../common/idmobilelib"; + }; + name = Debug; + }; + 1D6058950D05DD3E006BFB54 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = YES; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = doom_Prefix.pch; + GCC_PREPROCESSOR_DEFINITIONS = ( + HAVE_CONFIG_H, + IPHONE, + ); + GCC_THUMB_SUPPORT = NO; + GCC_TREAT_WARNINGS_AS_ERRORS = NO; + HEADER_SEARCH_PATHS = ""; + INFOPLIST_FILE = Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 6.1; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "/Work/DerivedData/Build/Products/Debug-iphoneos", + ); + PROFILE_PREFIX = com.idsoftware; + PROVISIONING_PROFILE = ""; + "PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + USER_HEADER_SEARCH_PATHS = "../../../common/ios/doomengine ../../../common ../../../common/idmobilelib"; + }; + name = Release; + }; + 4364BF480F5CB27300F29317 /* AdHocDist */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES; + CLANG_WARN_OBJCPP_ARC_ABI = YES; + CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES; + CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; + CODE_SIGN_ENTITLEMENTS = dist.plist; + CODE_SIGN_IDENTITY = "iPhone Distribution"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_PREPROCESSOR_DEFINITIONS = NDEBUG; + GCC_THUMB_SUPPORT = NO; + GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; + GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES; + GCC_TREAT_WARNINGS_AS_ERRORS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; + GCC_WARN_ABOUT_MISSING_NEWLINE = YES; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES; + GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES; + GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; + GCC_WARN_MULTIPLE_DEFINITION_TYPES_FOR_SELECTOR = YES; + GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES; + GCC_WARN_PEDANTIC = YES; + GCC_WARN_SHADOW = YES; + GCC_WARN_SIGN_COMPARE = YES; + GCC_WARN_STRICT_SELECTOR_MATCH = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNKNOWN_PRAGMAS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_LABEL = YES; + GCC_WARN_UNUSED_PARAMETER = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + INFOPLIST_FILE = Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 3.2; + MACOSX_DEPLOYMENT_TARGET = ""; + PRODUCT_NAME = Doom; + PROVISIONING_PROFILE = ""; + "PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; + SDKROOT = iphoneos; + USER_HEADER_SEARCH_PATHS = "../../../common/ios/doomengine ../../../common ../../../../idTechM/idTechM/shared/idmobilelib"; + WARNING_CFLAGS = ( + "-Wall", + "-Wextra", + "-pedantic-errors", + ); + }; + name = AdHocDist; + }; + 4364BF490F5CB27300F29317 /* AdHocDist */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = YES; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = doom_Prefix.pch; + GCC_PREPROCESSOR_DEFINITIONS = ( + HAVE_CONFIG_H, + IPHONE, + ); + GCC_THUMB_SUPPORT = NO; + GCC_TREAT_WARNINGS_AS_ERRORS = NO; + HEADER_SEARCH_PATHS = ""; + INFOPLIST_FILE = Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 6.1; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "/Work/DerivedData/Build/Products/Debug-iphoneos", + ); + PROFILE_PREFIX = com.idsoftware; + PROVISIONING_PROFILE = ""; + "PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + USER_HEADER_SEARCH_PATHS = "../../../common/ios/doomengine ../../../common ../../../common/idmobilelib"; + }; + name = AdHocDist; + }; + C01FCF4F08A954540054247B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES; + CLANG_WARN_OBJCPP_ARC_ABI = YES; + CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES; + CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_PREPROCESSOR_DEFINITIONS = "HAVE_CONFIG_H=1"; + GCC_THUMB_SUPPORT = NO; + GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; + GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES; + GCC_TREAT_WARNINGS_AS_ERRORS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; + GCC_WARN_ABOUT_MISSING_NEWLINE = YES; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES; + GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES; + GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; + GCC_WARN_MULTIPLE_DEFINITION_TYPES_FOR_SELECTOR = YES; + GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES; + GCC_WARN_PEDANTIC = YES; + GCC_WARN_SHADOW = YES; + GCC_WARN_SIGN_COMPARE = YES; + GCC_WARN_STRICT_SELECTOR_MATCH = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNKNOWN_PRAGMAS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_LABEL = YES; + GCC_WARN_UNUSED_PARAMETER = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + INFOPLIST_FILE = Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 3.2; + MACOSX_DEPLOYMENT_TARGET = ""; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = Doom; + PROVISIONING_PROFILE = ""; + "PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; + SDKROOT = iphoneos; + USER_HEADER_SEARCH_PATHS = "../../../common/ios/doomengine ../../../common ../../../../idTechM/idTechM/shared/idmobilelib"; + WARNING_CFLAGS = ( + "-Wall", + "-Wextra", + "-pedantic-errors", + ); + }; + name = Debug; + }; + C01FCF5008A954540054247B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES; + CLANG_WARN_OBJCPP_ARC_ABI = YES; + CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES; + CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_PREPROCESSOR_DEFINITIONS = ( + HAVE_CONFIG_H, + NDEBUG, + ); + GCC_THUMB_SUPPORT = NO; + GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; + GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES; + GCC_TREAT_WARNINGS_AS_ERRORS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; + GCC_WARN_ABOUT_MISSING_NEWLINE = YES; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES; + GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES; + GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; + GCC_WARN_MULTIPLE_DEFINITION_TYPES_FOR_SELECTOR = YES; + GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES; + GCC_WARN_PEDANTIC = YES; + GCC_WARN_SHADOW = YES; + GCC_WARN_SIGN_COMPARE = YES; + GCC_WARN_STRICT_SELECTOR_MATCH = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNKNOWN_PRAGMAS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_LABEL = YES; + GCC_WARN_UNUSED_PARAMETER = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + INFOPLIST_FILE = Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 3.2; + MACOSX_DEPLOYMENT_TARGET = ""; + PRODUCT_NAME = Doom; + PROVISIONING_PROFILE = ""; + "PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; + SDKROOT = iphoneos; + USER_HEADER_SEARCH_PATHS = "../../../common/ios/doomengine ../../../common ../../../../idTechM/idTechM/shared/idmobilelib"; + WARNING_CFLAGS = ( + "-Wall", + "-Wextra", + "-pedantic-errors", + ); + }; + name = Release; + }; + ED06595B1087C51800E5450B /* Distribution */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES; + CLANG_WARN_OBJCPP_ARC_ABI = YES; + CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES; + CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; + CODE_SIGN_IDENTITY = "iPhone Distribution: id Software"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution: id Software"; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_PREPROCESSOR_DEFINITIONS = ( + HAVE_CONFIG_H, + NDEBUG, + ); + GCC_THUMB_SUPPORT = NO; + GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; + GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES; + GCC_TREAT_WARNINGS_AS_ERRORS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; + GCC_WARN_ABOUT_MISSING_NEWLINE = YES; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES; + GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES; + GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; + GCC_WARN_MULTIPLE_DEFINITION_TYPES_FOR_SELECTOR = YES; + GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES; + GCC_WARN_PEDANTIC = YES; + GCC_WARN_SHADOW = YES; + GCC_WARN_SIGN_COMPARE = YES; + GCC_WARN_STRICT_SELECTOR_MATCH = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNKNOWN_PRAGMAS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_LABEL = YES; + GCC_WARN_UNUSED_PARAMETER = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + INFOPLIST_FILE = Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 3.2; + MACOSX_DEPLOYMENT_TARGET = ""; + PRODUCT_NAME = Doom; + PROVISIONING_PROFILE = "31C73095-0DD9-4ABA-BB25-8D23F661F10F"; + "PROVISIONING_PROFILE[sdk=iphoneos*]" = "31C73095-0DD9-4ABA-BB25-8D23F661F10F"; + SDKROOT = iphoneos; + USER_HEADER_SEARCH_PATHS = "../../../common/ios/doomengine ../../../common ../../../../idTechM/idTechM/shared/idmobilelib"; + WARNING_CFLAGS = ( + "-Wall", + "-Wextra", + "-pedantic-errors", + ); + }; + name = Distribution; + }; + ED06595C1087C51800E5450B /* Distribution */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = YES; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = doom_Prefix.pch; + GCC_PREPROCESSOR_DEFINITIONS = ( + HAVE_CONFIG_H, + IPHONE, + ); + GCC_THUMB_SUPPORT = NO; + GCC_TREAT_WARNINGS_AS_ERRORS = NO; + HEADER_SEARCH_PATHS = ""; + INFOPLIST_FILE = Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 6.1; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "/Work/DerivedData/Build/Products/Debug-iphoneos", + ); + PROFILE_PREFIX = com.idsoftware; + PROVISIONING_PROFILE = ""; + "PROVISIONING_PROFILE[sdk=iphoneos*]" = "CF005E47-190F-43B8-B89D-59AD4EF04B31"; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + USER_HEADER_SEARCH_PATHS = "../../../common/ios/doomengine ../../../common ../../../common/idmobilelib"; + }; + name = Distribution; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "Doom" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1D6058940D05DD3E006BFB54 /* Debug */, + 1D6058950D05DD3E006BFB54 /* Release */, + 4364BF490F5CB27300F29317 /* AdHocDist */, + ED06595C1087C51800E5450B /* Distribution */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + C01FCF4E08A954540054247B /* Build configuration list for PBXProject "Doom" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C01FCF4F08A954540054247B /* Debug */, + C01FCF5008A954540054247B /* Release */, + 4364BF480F5CB27300F29317 /* AdHocDist */, + ED06595B1087C51800E5450B /* Distribution */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; +} diff --git a/DoomClassic/code/iphone/Doom.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/DoomClassic/code/iphone/Doom.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100755 index 0000000..618f2d7 --- /dev/null +++ b/DoomClassic/code/iphone/Doom.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/DoomClassic/code/iphone/Doom.xcodeproj/project.xcworkspace/xcuserdata/jeff.farrand.xcuserdatad/UserInterfaceState.xcuserstate b/DoomClassic/code/iphone/Doom.xcodeproj/project.xcworkspace/xcuserdata/jeff.farrand.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100755 index 0000000..4e8422d --- /dev/null +++ b/DoomClassic/code/iphone/Doom.xcodeproj/project.xcworkspace/xcuserdata/jeff.farrand.xcuserdatad/UserInterfaceState.xcuserstate @@ -0,0 +1,11874 @@ + + + + + $archiver + NSKeyedArchiver + $objects + + $null + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 2 + + + CF$UID + 3 + + + CF$UID + 4 + + + CF$UID + 5 + + + CF$UID + 6 + + + CF$UID + 7 + + + NS.objects + + + CF$UID + 8 + + + CF$UID + 222 + + + CF$UID + 373 + + + CF$UID + 463 + + + CF$UID + 544 + + + CF$UID + 629 + + + + F620643C-D996-4514-A5EC-32FA5319E3DF + 3389C048-DD3B-44D1-902F-60508F9DAB33 + F250263C-8A31-4895-A3EE-4376EBF8104C + 65CBB683-F3F0-4A75-BFB7-71FDE4195621 + AE63F0E4-6A65-4B22-B927-D6D8F1317553 + IDEWorkspaceDocument + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 9 + + + CF$UID + 10 + + + CF$UID + 11 + + + CF$UID + 12 + + + CF$UID + 13 + + + CF$UID + 14 + + + NS.objects + + + CF$UID + 13 + + + CF$UID + 15 + + + CF$UID + 17 + + + CF$UID + 18 + + + CF$UID + 19 + + + CF$UID + 2 + + + + IDEActiveWorkspaceTabController + IDEOrderedWorkspaceTabControllers + IDEWindowToolbarIsVisible + IDEWindowFrame + IDEWorkspaceTabController_82449F16-BA75-4815-8930-B45D67BCE0FA + IDEWorkspaceWindowControllerUniqueIdentifier + + $class + + CF$UID + 16 + + NS.objects + + + CF$UID + 13 + + + + + $classes + + NSArray + NSObject + + $classname + NSArray + + + {{148, 138}, {1400, 944}} + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 20 + + + CF$UID + 21 + + + CF$UID + 22 + + + CF$UID + 23 + + + CF$UID + 24 + + + CF$UID + 25 + + + CF$UID + 26 + + + CF$UID + 27 + + + NS.objects + + + CF$UID + 28 + + + CF$UID + 17 + + + CF$UID + 106 + + + CF$UID + 156 + + + CF$UID + 162 + + + CF$UID + 212 + + + CF$UID + 17 + + + CF$UID + 221 + + + + IDEEditorArea + IDEShowNavigator + AssistantEditorsLayout + IDEWorkspaceTabControllerUtilityAreaSplitView + IDENavigatorArea + IDEWorkspaceTabControllerDesignAreaSplitView + IDEShowUtilities + IDETabLabel + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 29 + + + CF$UID + 30 + + + CF$UID + 31 + + + CF$UID + 32 + + + CF$UID + 33 + + + CF$UID + 34 + + + CF$UID + 35 + + + CF$UID + 36 + + + NS.objects + + + CF$UID + 17 + + + CF$UID + 37 + + + CF$UID + 109 + + + CF$UID + 17 + + + CF$UID + 106 + + + CF$UID + 136 + + + CF$UID + 144 + + + CF$UID + 145 + + + + ShowDebuggerArea + IDEEditorMode_Standard + IDEEDitorArea_DebugArea + IDEShowEditor + EditorMode + DebuggerSplitView + DefaultPersistentRepresentations + layoutTree + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 38 + + + NS.objects + + + CF$UID + 39 + + + + EditorLayout_PersistentRepresentation + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 40 + + + NS.objects + + + CF$UID + 41 + + + + Main + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 42 + + + CF$UID + 43 + + + CF$UID + 44 + + + NS.objects + + + CF$UID + 45 + + + CF$UID + 106 + + + CF$UID + 107 + + + + EditorLayout_StateSavingStateDictionaries + EditorLayout_Selected + EditorLayout_Geometry + + $class + + CF$UID + 16 + + NS.objects + + + CF$UID + 46 + + + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 47 + + + CF$UID + 48 + + + CF$UID + 49 + + + CF$UID + 50 + + + CF$UID + 51 + + + CF$UID + 52 + + + CF$UID + 53 + + + NS.objects + + + CF$UID + 54 + + + CF$UID + 55 + + + CF$UID + 67 + + + CF$UID + 101 + + + CF$UID + 101 + + + CF$UID + 102 + + + CF$UID + 103 + + + + FileDataType + ArchivableRepresentation + EditorState + NavigableItemName + DocumentNavigableItemName + DocumentExtensionIdentifier + DocumentURL + com.apple.xcode.project + + $class + + CF$UID + 66 + + DocumentLocation + + CF$UID + 62 + + DomainIdentifier + + CF$UID + 56 + + IdentifierPath + + CF$UID + 57 + + IndexOfDocumentIdentifier + + CF$UID + 61 + + + Xcode.IDENavigableItemDomain.WorkspaceStructure + + $class + + CF$UID + 16 + + NS.objects + + + CF$UID + 58 + + + + + $class + + CF$UID + 60 + + Identifier + + CF$UID + 59 + + + Doom + + $classes + + IDEArchivableStringIndexPair + NSObject + + $classname + IDEArchivableStringIndexPair + + 9223372036854775807 + + $class + + CF$UID + 65 + + documentURL + + CF$UID + 63 + + timestamp + + CF$UID + 0 + + + + $class + + CF$UID + 64 + + NS.string + file://localhost/Volumes/Work/idMobileDepot/Archive/DoomClassicDepot/code/iphone/Doom.xcodeproj/ + + + $classes + + NSMutableString + NSString + NSObject + + $classname + NSMutableString + + + $classes + + DVTDocumentLocation + NSObject + + $classname + DVTDocumentLocation + + + $classes + + IDENavigableItemArchivableRepresentation + NSObject + + $classname + IDENavigableItemArchivableRepresentation + + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 68 + + + CF$UID + 69 + + + CF$UID + 70 + + + CF$UID + 71 + + + CF$UID + 72 + + + CF$UID + 73 + + + NS.objects + + + CF$UID + 74 + + + CF$UID + 75 + + + CF$UID + 88 + + + CF$UID + 89 + + + CF$UID + 99 + + + CF$UID + 100 + + + + Xcode3ProjectEditorPreviousProjectEditorClass + Xcode3ProjectEditor.sourceList.splitview + Xcode3ProjectEditorPreviousTargetEditorClass + Xcode3ProjectEditorSelectedDocumentLocations + Xcode3ProjectEditor_Xcode3ProjectInfoEditor + Xcode3ProjectEditor_Xcode3TargetEditor + Xcode3ProjectInfoEditor + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 76 + + + NS.objects + + + CF$UID + 77 + + + + DVTSplitViewItems + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 78 + + + CF$UID + 84 + + + + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 79 + + + CF$UID + 80 + + + NS.objects + + + CF$UID + 81 + + + CF$UID + 82 + + + + DVTIdentifier + DVTViewMagnitude + + 170 + + $classes + + NSDictionary + NSObject + + $classname + NSDictionary + + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 79 + + + CF$UID + 80 + + + NS.objects + + + CF$UID + 81 + + + CF$UID + 85 + + + + 710 + + $classes + + NSMutableArray + NSArray + NSObject + + $classname + NSMutableArray + + + $classes + + NSMutableDictionary + NSDictionary + NSObject + + $classname + NSMutableDictionary + + Xcode3TargetEditor + + $class + + CF$UID + 16 + + NS.objects + + + CF$UID + 90 + + + + + $class + + CF$UID + 98 + + documentURL + + CF$UID + 91 + + selection + + CF$UID + 93 + + timestamp + + CF$UID + 92 + + + file://localhost/Volumes/Work/idMobileDepot/Archive/DoomClassicDepot/code/iphone/Doom.xcodeproj/ + 333652380.07012099 + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 94 + + + CF$UID + 95 + + + NS.objects + + + CF$UID + 96 + + + CF$UID + 97 + + + + Project + Editor + Doom + Xcode3ProjectInfoEditor + + $classes + + Xcode3ProjectDocumentLocation + DVTDocumentLocation + NSObject + + $classname + Xcode3ProjectDocumentLocation + + + $class + + CF$UID + 87 + + NS.keys + + NS.objects + + + + $class + + CF$UID + 87 + + NS.keys + + NS.objects + + + Doom + Xcode.Xcode3ProjectSupport.EditorDocument.Xcode3Project + + $class + + CF$UID + 105 + + NS.base + + CF$UID + 0 + + NS.relative + + CF$UID + 104 + + + file://localhost/Volumes/Work/idMobileDepot/Archive/DoomClassicDepot/code/iphone/Doom.xcodeproj/ + + $classes + + NSURL + NSObject + + $classname + NSURL + + 0 + + $class + + CF$UID + 16 + + NS.objects + + + CF$UID + 108 + + + + {{0, 0}, {880, 586}} + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 110 + + + CF$UID + 111 + + + CF$UID + 112 + + + CF$UID + 113 + + + CF$UID + 114 + + + CF$UID + 115 + + + NS.objects + + + CF$UID + 116 + + + CF$UID + 117 + + + CF$UID + 119 + + + CF$UID + 116 + + + CF$UID + 127 + + + CF$UID + 133 + + + + LayoutFocusMode + console + IDEDebugArea_SplitView + LayoutMode + IDEDebuggerAreaSplitView + variables + 1 + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 118 + + + NS.objects + + + CF$UID + 106 + + + + ConsoleFilterMode + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 76 + + + NS.objects + + + CF$UID + 120 + + + + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 121 + + + CF$UID + 124 + + + + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 79 + + + CF$UID + 80 + + + NS.objects + + + CF$UID + 122 + + + CF$UID + 123 + + + + VariablesView + 298 + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 79 + + + CF$UID + 80 + + + NS.objects + + + CF$UID + 125 + + + CF$UID + 126 + + + + ConsoleArea + 581 + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 76 + + + NS.objects + + + CF$UID + 128 + + + + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 129 + + + CF$UID + 131 + + + + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 79 + + + CF$UID + 80 + + + NS.objects + + + CF$UID + 122 + + + CF$UID + 130 + + + + 298 + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 79 + + + CF$UID + 80 + + + NS.objects + + + CF$UID + 125 + + + CF$UID + 132 + + + + 581 + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 134 + + + NS.objects + + + CF$UID + 135 + + + + DBGVariablesViewFilterMode + 2 + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 76 + + + NS.objects + + + CF$UID + 137 + + + + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 138 + + + CF$UID + 141 + + + + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 79 + + + CF$UID + 80 + + + NS.objects + + + CF$UID + 139 + + + CF$UID + 140 + + + + IDEEditor + 608 + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 79 + + + CF$UID + 80 + + + NS.objects + + + CF$UID + 142 + + + CF$UID + 143 + + + + IDEDebuggerArea + 238 + + $class + + CF$UID + 87 + + NS.keys + + NS.objects + + + + $class + + CF$UID + 155 + + geniusEditorContextNode + + CF$UID + 0 + + primaryEditorContextNode + + CF$UID + 146 + + rootLayoutTreeNode + + CF$UID + 152 + + + + $class + + CF$UID + 154 + + children + + CF$UID + 0 + + contentType + 1 + documentArchivableRepresentation + + CF$UID + 147 + + orientation + 0 + parent + + CF$UID + 152 + + + + $class + + CF$UID + 66 + + DocumentLocation + + CF$UID + 62 + + DomainIdentifier + + CF$UID + 56 + + IdentifierPath + + CF$UID + 148 + + IndexOfDocumentIdentifier + + CF$UID + 151 + + + + $class + + CF$UID + 16 + + NS.objects + + + CF$UID + 149 + + + + + $class + + CF$UID + 60 + + Identifier + + CF$UID + 150 + + + Doom + 9223372036854775807 + + $class + + CF$UID + 154 + + children + + CF$UID + 153 + + contentType + 0 + documentArchivableRepresentation + + CF$UID + 0 + + orientation + 0 + parent + + CF$UID + 0 + + + + $class + + CF$UID + 16 + + NS.objects + + + CF$UID + 146 + + + + + $classes + + IDEWorkspaceTabControllerLayoutTreeNode + NSObject + + $classname + IDEWorkspaceTabControllerLayoutTreeNode + + + $classes + + IDEWorkspaceTabControllerLayoutTree + NSObject + + $classname + IDEWorkspaceTabControllerLayoutTree + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 76 + + + NS.objects + + + CF$UID + 157 + + + + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 158 + + + CF$UID + 160 + + + + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 79 + + + CF$UID + 80 + + + NS.objects + + + CF$UID + 81 + + + CF$UID + 159 + + + + 622 + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 79 + + + CF$UID + 80 + + + NS.objects + + + CF$UID + 81 + + + CF$UID + 161 + + + + 224 + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 163 + + + CF$UID + 164 + + + CF$UID + 165 + + + CF$UID + 166 + + + NS.objects + + + CF$UID + 167 + + + CF$UID + 190 + + + CF$UID + 204 + + + CF$UID + 165 + + + + Xcode.IDEKit.Navigator.Structure + Xcode.IDEKit.Navigator.BatchFind + Xcode.IDEKit.Navigator.Logs + SelectedNavigator + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 168 + + + CF$UID + 169 + + + CF$UID + 170 + + + CF$UID + 171 + + + CF$UID + 172 + + + CF$UID + 173 + + + CF$UID + 174 + + + NS.objects + + + CF$UID + 175 + + + CF$UID + 176 + + + CF$UID + 177 + + + CF$UID + 176 + + + CF$UID + 176 + + + CF$UID + 179 + + + CF$UID + 182 + + + + IDEVisibleRect + IDEUnsavedDocumentFilteringEnabled + IDENavigatorExpandedItemsBeforeFilteringSet + IDERecentDocumentFilteringEnabled + IDESCMStatusFilteringEnabled + IDESelectedObjects + IDEExpandedItemsSet + {{0, 0}, {244, 802}} + + + $class + + CF$UID + 178 + + NS.objects + + + + $classes + + NSSet + NSObject + + $classname + NSSet + + + $class + + CF$UID + 16 + + NS.objects + + + CF$UID + 180 + + + + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 181 + + + + Doom + + $class + + CF$UID + 178 + + NS.objects + + + CF$UID + 183 + + + CF$UID + 184 + + + CF$UID + 186 + + + CF$UID + 189 + + + + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 181 + + + + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 181 + + + CF$UID + 185 + + + + Resources + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 181 + + + CF$UID + 187 + + + CF$UID + 188 + + + + Other Sources + InterfaceBuilder + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 181 + + + CF$UID + 187 + + + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 191 + + + CF$UID + 192 + + + CF$UID + 193 + + + CF$UID + 194 + + + CF$UID + 195 + + + CF$UID + 196 + + + CF$UID + 197 + + + NS.objects + + + CF$UID + 106 + + + CF$UID + 176 + + + CF$UID + 198 + + + CF$UID + 199 + + + CF$UID + 200 + + + CF$UID + 106 + + + CF$UID + 202 + + + + IDEBatchFindNavigatorScrollPosition + IDEBatchFindNavigatorShowsOptions + IDEBatchFindNavigatorReplaceString + IDEBatchFindNavigatorFindString + IDEBatchFindNavigatorSelectedRowIndexes + IDEBatchFindNavigatorFindMode + IDEBatchFindNavigatorCollapsedGroups + + Sound_StartLocalSound + + $class + + CF$UID + 201 + + NSLength + 1 + NSLocation + 21 + NSRangeCount + 1 + + + $classes + + NSIndexSet + NSObject + + $classname + NSIndexSet + + + $class + + CF$UID + 203 + + NSRangeCount + 0 + + + $classes + + NSMutableIndexSet + NSIndexSet + NSObject + + $classname + NSMutableIndexSet + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 205 + + + CF$UID + 206 + + + CF$UID + 207 + + + CF$UID + 208 + + + NS.objects + + + CF$UID + 209 + + + CF$UID + 210 + + + CF$UID + 176 + + + CF$UID + 211 + + + + IDELogNavigatorExpandedItemsStateKey + IDELogNavigatorSelectedObjectsStateKey + IDELogNavigatorRecentFilterStateKey + IDELogNavigatorVisibleRectStateKey + + $class + + CF$UID + 86 + + NS.objects + + + + $class + + CF$UID + 86 + + NS.objects + + + {{0, 0}, {259, 832}} + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 76 + + + NS.objects + + + CF$UID + 213 + + + + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 214 + + + CF$UID + 216 + + + CF$UID + 218 + + + + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 79 + + + CF$UID + 80 + + + NS.objects + + + CF$UID + 24 + + + CF$UID + 215 + + + + 260 + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 79 + + + CF$UID + 80 + + + NS.objects + + + CF$UID + 20 + + + CF$UID + 217 + + + + 880 + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 79 + + + CF$UID + 80 + + + NS.objects + + + CF$UID + 219 + + + CF$UID + 220 + + + + IDEUtilitiesArea + 260 + Doom.xcodeproj + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 223 + + + CF$UID + 224 + + + CF$UID + 225 + + + CF$UID + 226 + + + CF$UID + 14 + + + CF$UID + 227 + + + NS.objects + + + CF$UID + 228 + + + CF$UID + 229 + + + CF$UID + 176 + + + CF$UID + 227 + + + CF$UID + 3 + + + CF$UID + 230 + + + + IDEWindowFrame + IDEOrderedWorkspaceTabControllers + IDEWindowToolbarIsVisible + IDEActiveWorkspaceTabController + IDEWorkspaceTabController_4C97C6F3-2C36-4427-8CFE-360199404C66 + {{327, 333}, {600, 668}} + + $class + + CF$UID + 16 + + NS.objects + + + CF$UID + 227 + + + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 231 + + + CF$UID + 232 + + + CF$UID + 233 + + + CF$UID + 234 + + + CF$UID + 235 + + + CF$UID + 236 + + + CF$UID + 237 + + + CF$UID + 238 + + + NS.objects + + + CF$UID + 106 + + + CF$UID + 176 + + + CF$UID + 239 + + + CF$UID + 339 + + + CF$UID + 345 + + + CF$UID + 364 + + + CF$UID + 176 + + + CF$UID + 253 + + + + AssistantEditorsLayout + IDEShowNavigator + IDEEditorArea + IDEWorkspaceTabControllerUtilityAreaSplitView + IDENavigatorArea + IDEWorkspaceTabControllerDesignAreaSplitView + IDEShowUtilities + IDETabLabel + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 240 + + + CF$UID + 241 + + + CF$UID + 242 + + + CF$UID + 243 + + + CF$UID + 244 + + + CF$UID + 245 + + + CF$UID + 246 + + + CF$UID + 247 + + + NS.objects + + + CF$UID + 248 + + + CF$UID + 264 + + + CF$UID + 302 + + + CF$UID + 17 + + + CF$UID + 106 + + + CF$UID + 330 + + + CF$UID + 338 + + + CF$UID + 176 + + + + layoutTree + IDEEditorMode_Standard + IDEEDitorArea_DebugArea + IDEShowEditor + EditorMode + DebuggerSplitView + DefaultPersistentRepresentations + ShowDebuggerArea + + $class + + CF$UID + 155 + + geniusEditorContextNode + + CF$UID + 0 + + primaryEditorContextNode + + CF$UID + 249 + + rootLayoutTreeNode + + CF$UID + 262 + + + + $class + + CF$UID + 154 + + children + + CF$UID + 0 + + contentType + 1 + documentArchivableRepresentation + + CF$UID + 250 + + orientation + 0 + parent + + CF$UID + 262 + + + + $class + + CF$UID + 66 + + DocumentLocation + + CF$UID + 260 + + DomainIdentifier + + CF$UID + 56 + + IdentifierPath + + CF$UID + 251 + + IndexOfDocumentIdentifier + + CF$UID + 106 + + + + $class + + CF$UID + 16 + + NS.objects + + + CF$UID + 252 + + + CF$UID + 254 + + + CF$UID + 256 + + + CF$UID + 258 + + + + + $class + + CF$UID + 60 + + Identifier + + CF$UID + 253 + + + GenericMenuView.m + + $class + + CF$UID + 60 + + Identifier + + CF$UID + 255 + + + InterfaceBuilder + + $class + + CF$UID + 60 + + Identifier + + CF$UID + 257 + + + Other Sources + + $class + + CF$UID + 60 + + Identifier + + CF$UID + 259 + + + Doom + + $class + + CF$UID + 65 + + documentURL + + CF$UID + 261 + + timestamp + + CF$UID + 0 + + + + $class + + CF$UID + 64 + + NS.string + file://localhost/Volumes/Work/idMobileDepot/Archive/DoomClassicDepot/code/iphone/GenericMenuView.m + + + $class + + CF$UID + 154 + + children + + CF$UID + 263 + + contentType + 0 + documentArchivableRepresentation + + CF$UID + 0 + + orientation + 0 + parent + + CF$UID + 0 + + + + $class + + CF$UID + 16 + + NS.objects + + + CF$UID + 249 + + + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 265 + + + NS.objects + + + CF$UID + 266 + + + + EditorLayout_PersistentRepresentation + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 267 + + + NS.objects + + + CF$UID + 268 + + + + Main + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 269 + + + CF$UID + 270 + + + CF$UID + 271 + + + NS.objects + + + CF$UID + 272 + + + CF$UID + 106 + + + CF$UID + 300 + + + + EditorLayout_StateSavingStateDictionaries + EditorLayout_Selected + EditorLayout_Geometry + + $class + + CF$UID + 16 + + NS.objects + + + CF$UID + 273 + + + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 274 + + + CF$UID + 275 + + + CF$UID + 276 + + + CF$UID + 277 + + + CF$UID + 278 + + + CF$UID + 279 + + + CF$UID + 280 + + + NS.objects + + + CF$UID + 281 + + + CF$UID + 282 + + + CF$UID + 288 + + + CF$UID + 296 + + + CF$UID + 253 + + + CF$UID + 297 + + + CF$UID + 298 + + + + FileDataType + ArchivableRepresentation + EditorState + NavigableItemName + DocumentNavigableItemName + DocumentExtensionIdentifier + DocumentURL + public.objective-c-source + + $class + + CF$UID + 66 + + DocumentLocation + + CF$UID + 260 + + DomainIdentifier + + CF$UID + 56 + + IdentifierPath + + CF$UID + 283 + + IndexOfDocumentIdentifier + + CF$UID + 106 + + + + $class + + CF$UID + 16 + + NS.objects + + + CF$UID + 284 + + + CF$UID + 285 + + + CF$UID + 286 + + + CF$UID + 287 + + + + + $class + + CF$UID + 60 + + Identifier + + CF$UID + 253 + + + + $class + + CF$UID + 60 + + Identifier + + CF$UID + 255 + + + + $class + + CF$UID + 60 + + Identifier + + CF$UID + 257 + + + + $class + + CF$UID + 60 + + Identifier + + CF$UID + 259 + + + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 289 + + + CF$UID + 290 + + + CF$UID + 291 + + + CF$UID + 292 + + + NS.objects + + + CF$UID + 293 + + + CF$UID + 294 + + + CF$UID + 176 + + + CF$UID + 295 + + + + PrimaryDocumentTimestamp + PrimaryDocumentVisibleCharacterRange + HideAllIssues + PrimaryDocumentSelectedCharacterRange + 333326399.194489 + {187, 767} + {945, 0} + -BackToMain + Xcode.IDEKit.EditorDocument.SourceCode + + $class + + CF$UID + 105 + + NS.base + + CF$UID + 0 + + NS.relative + + CF$UID + 299 + + + file://localhost/Volumes/Work/idMobileDepot/Archive/DoomClassicDepot/code/iphone/GenericMenuView.m + + $class + + CF$UID + 16 + + NS.objects + + + CF$UID + 301 + + + + {{0, 0}, {600, 600}} + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 303 + + + CF$UID + 304 + + + CF$UID + 305 + + + CF$UID + 306 + + + CF$UID + 307 + + + CF$UID + 308 + + + NS.objects + + + CF$UID + 116 + + + CF$UID + 309 + + + CF$UID + 311 + + + CF$UID + 116 + + + CF$UID + 313 + + + CF$UID + 324 + + + + LayoutFocusMode + console + variables + LayoutMode + IDEDebuggerAreaSplitView + IDEDebugArea_SplitView + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 310 + + + NS.objects + + + CF$UID + 106 + + + + ConsoleFilterMode + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 312 + + + NS.objects + + + CF$UID + 135 + + + + DBGVariablesViewFilterMode + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 314 + + + NS.objects + + + CF$UID + 315 + + + + DVTSplitViewItems + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 316 + + + CF$UID + 321 + + + + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 317 + + + CF$UID + 318 + + + NS.objects + + + CF$UID + 319 + + + CF$UID + 320 + + + + DVTIdentifier + DVTViewMagnitude + VariablesView + 298 + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 317 + + + CF$UID + 318 + + + NS.objects + + + CF$UID + 322 + + + CF$UID + 323 + + + + ConsoleArea + 301 + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 314 + + + NS.objects + + + CF$UID + 325 + + + + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 326 + + + CF$UID + 328 + + + + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 317 + + + CF$UID + 318 + + + NS.objects + + + CF$UID + 319 + + + CF$UID + 327 + + + + 298 + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 317 + + + CF$UID + 318 + + + NS.objects + + + CF$UID + 322 + + + CF$UID + 329 + + + + 301 + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 314 + + + NS.objects + + + CF$UID + 331 + + + + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 332 + + + CF$UID + 335 + + + + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 317 + + + CF$UID + 318 + + + NS.objects + + + CF$UID + 333 + + + CF$UID + 334 + + + + IDEEditor + 203 + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 317 + + + CF$UID + 318 + + + NS.objects + + + CF$UID + 336 + + + CF$UID + 337 + + + + IDEDebuggerArea + 115 + + $class + + CF$UID + 87 + + NS.keys + + NS.objects + + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 314 + + + NS.objects + + + CF$UID + 340 + + + + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 341 + + + CF$UID + 343 + + + + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 317 + + + CF$UID + 318 + + + NS.objects + + + CF$UID + 198 + + + CF$UID + 342 + + + + 411 + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 317 + + + CF$UID + 318 + + + NS.objects + + + CF$UID + 198 + + + CF$UID + 344 + + + + 211 + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 346 + + + CF$UID + 347 + + + NS.objects + + + CF$UID + 347 + + + CF$UID + 348 + + + + SelectedNavigator + Xcode.IDEKit.Navigator.Structure + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 349 + + + CF$UID + 350 + + + CF$UID + 351 + + + CF$UID + 352 + + + CF$UID + 353 + + + CF$UID + 354 + + + CF$UID + 355 + + + NS.objects + + + CF$UID + 356 + + + CF$UID + 176 + + + CF$UID + 177 + + + CF$UID + 176 + + + CF$UID + 176 + + + CF$UID + 357 + + + CF$UID + 359 + + + + IDEVisibleRect + IDEUnsavedDocumentFilteringEnabled + IDENavigatorExpandedItemsBeforeFilteringSet + IDERecentDocumentFilteringEnabled + IDESCMStatusFilteringEnabled + IDESelectedObjects + IDEExpandedItemsSet + {{0, 0}, {0, 0}} + + $class + + CF$UID + 16 + + NS.objects + + + CF$UID + 358 + + + + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 259 + + + CF$UID + 257 + + + CF$UID + 255 + + + CF$UID + 253 + + + + + $class + + CF$UID + 178 + + NS.objects + + + CF$UID + 360 + + + CF$UID + 361 + + + CF$UID + 362 + + + CF$UID + 363 + + + + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 259 + + + + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 259 + + + CF$UID + 257 + + + + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 259 + + + CF$UID + 257 + + + CF$UID + 255 + + + + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 259 + + + CF$UID + 185 + + + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 314 + + + NS.objects + + + CF$UID + 365 + + + + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 366 + + + CF$UID + 368 + + + CF$UID + 370 + + + + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 317 + + + CF$UID + 318 + + + NS.objects + + + CF$UID + 235 + + + CF$UID + 367 + + + + 260 + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 317 + + + CF$UID + 318 + + + NS.objects + + + CF$UID + 233 + + + CF$UID + 369 + + + + 1341 + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 317 + + + CF$UID + 318 + + + NS.objects + + + CF$UID + 371 + + + CF$UID + 372 + + + + IDEUtilitiesArea + 260 + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 223 + + + CF$UID + 225 + + + CF$UID + 374 + + + CF$UID + 224 + + + CF$UID + 14 + + + CF$UID + 226 + + + NS.objects + + + CF$UID + 375 + + + CF$UID + 176 + + + CF$UID + 376 + + + CF$UID + 462 + + + CF$UID + 4 + + + CF$UID + 374 + + + + IDEWorkspaceTabController_2E57CB2E-881C-48BE-803E-9AA60543F8D6 + {{285, 379}, {600, 668}} + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 238 + + + CF$UID + 232 + + + CF$UID + 233 + + + CF$UID + 234 + + + CF$UID + 235 + + + CF$UID + 236 + + + CF$UID + 237 + + + CF$UID + 231 + + + NS.objects + + + CF$UID + 377 + + + CF$UID + 176 + + + CF$UID + 378 + + + CF$UID + 441 + + + CF$UID + 447 + + + CF$UID + 454 + + + CF$UID + 176 + + + CF$UID + 106 + + + + MainWindow.xib + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 240 + + + CF$UID + 241 + + + CF$UID + 242 + + + CF$UID + 243 + + + CF$UID + 244 + + + CF$UID + 245 + + + CF$UID + 246 + + + CF$UID + 247 + + + NS.objects + + + CF$UID + 379 + + + CF$UID + 390 + + + CF$UID + 419 + + + CF$UID + 17 + + + CF$UID + 106 + + + CF$UID + 434 + + + CF$UID + 440 + + + CF$UID + 176 + + + + + $class + + CF$UID + 155 + + geniusEditorContextNode + + CF$UID + 0 + + primaryEditorContextNode + + CF$UID + 380 + + rootLayoutTreeNode + + CF$UID + 388 + + + + $class + + CF$UID + 154 + + children + + CF$UID + 0 + + contentType + 1 + documentArchivableRepresentation + + CF$UID + 381 + + orientation + 0 + parent + + CF$UID + 388 + + + + $class + + CF$UID + 66 + + DocumentLocation + + CF$UID + 386 + + DomainIdentifier + + CF$UID + 56 + + IdentifierPath + + CF$UID + 382 + + IndexOfDocumentIdentifier + + CF$UID + 106 + + + + $class + + CF$UID + 16 + + NS.objects + + + CF$UID + 383 + + + CF$UID + 384 + + + CF$UID + 385 + + + + + $class + + CF$UID + 60 + + Identifier + + CF$UID + 377 + + + + $class + + CF$UID + 60 + + Identifier + + CF$UID + 185 + + + + $class + + CF$UID + 60 + + Identifier + + CF$UID + 259 + + + + $class + + CF$UID + 65 + + documentURL + + CF$UID + 387 + + timestamp + + CF$UID + 0 + + + + $class + + CF$UID + 64 + + NS.string + file://localhost/Volumes/Work/idMobileDepot/Archive/DoomClassicDepot/code/iphone/MainWindow.xib + + + $class + + CF$UID + 154 + + children + + CF$UID + 389 + + contentType + 0 + documentArchivableRepresentation + + CF$UID + 0 + + orientation + 0 + parent + + CF$UID + 0 + + + + $class + + CF$UID + 16 + + NS.objects + + + CF$UID + 380 + + + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 265 + + + NS.objects + + + CF$UID + 391 + + + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 267 + + + NS.objects + + + CF$UID + 392 + + + + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 269 + + + CF$UID + 270 + + + CF$UID + 271 + + + NS.objects + + + CF$UID + 393 + + + CF$UID + 106 + + + CF$UID + 418 + + + + + $class + + CF$UID + 16 + + NS.objects + + + CF$UID + 394 + + + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 274 + + + CF$UID + 275 + + + CF$UID + 276 + + + CF$UID + 277 + + + CF$UID + 278 + + + CF$UID + 279 + + + CF$UID + 280 + + + NS.objects + + + CF$UID + 395 + + + CF$UID + 396 + + + CF$UID + 401 + + + CF$UID + 377 + + + CF$UID + 377 + + + CF$UID + 415 + + + CF$UID + 416 + + + + com.apple.InterfaceBuilder3.CocoaTouch.XIB + + $class + + CF$UID + 66 + + DocumentLocation + + CF$UID + 386 + + DomainIdentifier + + CF$UID + 56 + + IdentifierPath + + CF$UID + 397 + + IndexOfDocumentIdentifier + + CF$UID + 106 + + + + $class + + CF$UID + 16 + + NS.objects + + + CF$UID + 398 + + + CF$UID + 399 + + + CF$UID + 400 + + + + + $class + + CF$UID + 60 + + Identifier + + CF$UID + 377 + + + + $class + + CF$UID + 60 + + Identifier + + CF$UID + 185 + + + + $class + + CF$UID + 60 + + Identifier + + CF$UID + 259 + + + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 402 + + + CF$UID + 403 + + + CF$UID + 404 + + + CF$UID + 405 + + + NS.objects + + + CF$UID + 406 + + + CF$UID + 407 + + + CF$UID + 405 + + + CF$UID + 408 + + + + IBDockViewController + SelectedObjectIDs + SelectionProvider + IBCanvasViewController + + $class + + CF$UID + 87 + + NS.keys + + NS.objects + + + + $class + + CF$UID + 16 + + NS.objects + + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 409 + + + CF$UID + 410 + + + NS.objects + + + CF$UID + 411 + + + CF$UID + 414 + + + + ObjectIDToLastKnownCanvasPositionMap + EditedTopLevelObjectIDs + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 412 + + + NS.objects + + + CF$UID + 413 + + + + 170 + {53, 163} + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 135 + + + + Xcode.IDEKit.CocoaTouchIntegration.EditorDocument.CocoaTouch + + $class + + CF$UID + 105 + + NS.base + + CF$UID + 0 + + NS.relative + + CF$UID + 417 + + + file://localhost/Volumes/Work/idMobileDepot/Archive/DoomClassicDepot/code/iphone/MainWindow.xib + + $class + + CF$UID + 16 + + NS.objects + + + CF$UID + 301 + + + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 303 + + + CF$UID + 304 + + + CF$UID + 305 + + + CF$UID + 306 + + + CF$UID + 307 + + + CF$UID + 308 + + + NS.objects + + + CF$UID + 116 + + + CF$UID + 420 + + + CF$UID + 421 + + + CF$UID + 116 + + + CF$UID + 422 + + + CF$UID + 428 + + + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 310 + + + NS.objects + + + CF$UID + 106 + + + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 312 + + + NS.objects + + + CF$UID + 135 + + + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 314 + + + NS.objects + + + CF$UID + 423 + + + + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 424 + + + CF$UID + 426 + + + + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 317 + + + CF$UID + 318 + + + NS.objects + + + CF$UID + 319 + + + CF$UID + 425 + + + + 298 + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 317 + + + CF$UID + 318 + + + NS.objects + + + CF$UID + 322 + + + CF$UID + 427 + + + + 301 + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 314 + + + NS.objects + + + CF$UID + 429 + + + + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 430 + + + CF$UID + 432 + + + + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 317 + + + CF$UID + 318 + + + NS.objects + + + CF$UID + 319 + + + CF$UID + 431 + + + + 298 + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 317 + + + CF$UID + 318 + + + NS.objects + + + CF$UID + 322 + + + CF$UID + 433 + + + + 301 + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 314 + + + NS.objects + + + CF$UID + 435 + + + + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 436 + + + CF$UID + 438 + + + + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 317 + + + CF$UID + 318 + + + NS.objects + + + CF$UID + 333 + + + CF$UID + 437 + + + + 203 + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 317 + + + CF$UID + 318 + + + NS.objects + + + CF$UID + 336 + + + CF$UID + 439 + + + + 115 + + $class + + CF$UID + 87 + + NS.keys + + NS.objects + + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 314 + + + NS.objects + + + CF$UID + 442 + + + + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 443 + + + CF$UID + 445 + + + + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 317 + + + CF$UID + 318 + + + NS.objects + + + CF$UID + 198 + + + CF$UID + 444 + + + + 398 + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 317 + + + CF$UID + 318 + + + NS.objects + + + CF$UID + 198 + + + CF$UID + 446 + + + + 224 + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 346 + + + CF$UID + 347 + + + NS.objects + + + CF$UID + 347 + + + CF$UID + 448 + + + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 349 + + + CF$UID + 350 + + + CF$UID + 351 + + + CF$UID + 352 + + + CF$UID + 353 + + + CF$UID + 354 + + + CF$UID + 355 + + + NS.objects + + + CF$UID + 356 + + + CF$UID + 176 + + + CF$UID + 177 + + + CF$UID + 176 + + + CF$UID + 176 + + + CF$UID + 449 + + + CF$UID + 451 + + + + + $class + + CF$UID + 16 + + NS.objects + + + CF$UID + 450 + + + + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 259 + + + CF$UID + 185 + + + CF$UID + 377 + + + + + $class + + CF$UID + 178 + + NS.objects + + + CF$UID + 452 + + + CF$UID + 453 + + + + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 259 + + + + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 259 + + + CF$UID + 185 + + + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 314 + + + NS.objects + + + CF$UID + 455 + + + + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 456 + + + CF$UID + 458 + + + CF$UID + 460 + + + + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 317 + + + CF$UID + 318 + + + NS.objects + + + CF$UID + 235 + + + CF$UID + 457 + + + + 260 + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 317 + + + CF$UID + 318 + + + NS.objects + + + CF$UID + 233 + + + CF$UID + 459 + + + + 1140 + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 317 + + + CF$UID + 318 + + + NS.objects + + + CF$UID + 371 + + + CF$UID + 461 + + + + 260 + + $class + + CF$UID + 16 + + NS.objects + + + CF$UID + 374 + + + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 223 + + + CF$UID + 225 + + + CF$UID + 464 + + + CF$UID + 224 + + + CF$UID + 14 + + + CF$UID + 226 + + + NS.objects + + + CF$UID + 465 + + + CF$UID + 176 + + + CF$UID + 466 + + + CF$UID + 543 + + + CF$UID + 5 + + + CF$UID + 464 + + + + IDEWorkspaceTabController_EB14B1F1-732B-4B6C-B2A1-050CB7EF3E11 + {{306, 356}, {600, 668}} + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 231 + + + CF$UID + 232 + + + CF$UID + 233 + + + CF$UID + 234 + + + CF$UID + 235 + + + CF$UID + 236 + + + CF$UID + 237 + + + CF$UID + 238 + + + NS.objects + + + CF$UID + 106 + + + CF$UID + 176 + + + CF$UID + 467 + + + CF$UID + 520 + + + CF$UID + 526 + + + CF$UID + 535 + + + CF$UID + 176 + + + CF$UID + 473 + + + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 240 + + + CF$UID + 241 + + + CF$UID + 242 + + + CF$UID + 243 + + + CF$UID + 244 + + + CF$UID + 245 + + + CF$UID + 246 + + + CF$UID + 247 + + + NS.objects + + + CF$UID + 468 + + + CF$UID + 480 + + + CF$UID + 498 + + + CF$UID + 17 + + + CF$UID + 106 + + + CF$UID + 513 + + + CF$UID + 519 + + + CF$UID + 176 + + + + + $class + + CF$UID + 155 + + geniusEditorContextNode + + CF$UID + 0 + + primaryEditorContextNode + + CF$UID + 469 + + rootLayoutTreeNode + + CF$UID + 478 + + + + $class + + CF$UID + 154 + + children + + CF$UID + 0 + + contentType + 1 + documentArchivableRepresentation + + CF$UID + 470 + + orientation + 0 + parent + + CF$UID + 478 + + + + $class + + CF$UID + 66 + + DocumentLocation + + CF$UID + 476 + + DomainIdentifier + + CF$UID + 56 + + IdentifierPath + + CF$UID + 471 + + IndexOfDocumentIdentifier + + CF$UID + 106 + + + + $class + + CF$UID + 16 + + NS.objects + + + CF$UID + 472 + + + CF$UID + 474 + + + CF$UID + 475 + + + + + $class + + CF$UID + 60 + + Identifier + + CF$UID + 473 + + + iphone_menus.c + + $class + + CF$UID + 60 + + Identifier + + CF$UID + 257 + + + + $class + + CF$UID + 60 + + Identifier + + CF$UID + 259 + + + + $class + + CF$UID + 65 + + documentURL + + CF$UID + 477 + + timestamp + + CF$UID + 0 + + + + $class + + CF$UID + 64 + + NS.string + file://localhost/Volumes/Work/idMobileDepot/Archive/DoomClassicDepot/code/iphone/iphone_menus.c + + + $class + + CF$UID + 154 + + children + + CF$UID + 479 + + contentType + 0 + documentArchivableRepresentation + + CF$UID + 0 + + orientation + 0 + parent + + CF$UID + 0 + + + + $class + + CF$UID + 16 + + NS.objects + + + CF$UID + 469 + + + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 265 + + + NS.objects + + + CF$UID + 481 + + + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 267 + + + NS.objects + + + CF$UID + 482 + + + + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 269 + + + CF$UID + 270 + + + CF$UID + 271 + + + NS.objects + + + CF$UID + 483 + + + CF$UID + 106 + + + CF$UID + 497 + + + + + $class + + CF$UID + 16 + + NS.objects + + + CF$UID + 484 + + + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 274 + + + CF$UID + 275 + + + CF$UID + 276 + + + CF$UID + 277 + + + CF$UID + 278 + + + CF$UID + 279 + + + CF$UID + 280 + + + NS.objects + + + CF$UID + 485 + + + CF$UID + 486 + + + CF$UID + 491 + + + CF$UID + 473 + + + CF$UID + 473 + + + CF$UID + 297 + + + CF$UID + 495 + + + + public.c-source + + $class + + CF$UID + 66 + + DocumentLocation + + CF$UID + 476 + + DomainIdentifier + + CF$UID + 56 + + IdentifierPath + + CF$UID + 487 + + IndexOfDocumentIdentifier + + CF$UID + 106 + + + + $class + + CF$UID + 16 + + NS.objects + + + CF$UID + 488 + + + CF$UID + 489 + + + CF$UID + 490 + + + + + $class + + CF$UID + 60 + + Identifier + + CF$UID + 473 + + + + $class + + CF$UID + 60 + + Identifier + + CF$UID + 257 + + + + $class + + CF$UID + 60 + + Identifier + + CF$UID + 259 + + + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 289 + + + CF$UID + 290 + + + CF$UID + 291 + + + CF$UID + 292 + + + NS.objects + + + CF$UID + 492 + + + CF$UID + 493 + + + CF$UID + 176 + + + CF$UID + 494 + + + + 333326075.250848 + {0, 1636} + {0, 0} + + $class + + CF$UID + 105 + + NS.base + + CF$UID + 0 + + NS.relative + + CF$UID + 496 + + + file://localhost/Volumes/Work/idMobileDepot/Archive/DoomClassicDepot/code/iphone/iphone_menus.c + + $class + + CF$UID + 16 + + NS.objects + + + CF$UID + 301 + + + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 303 + + + CF$UID + 304 + + + CF$UID + 305 + + + CF$UID + 306 + + + CF$UID + 307 + + + CF$UID + 308 + + + NS.objects + + + CF$UID + 116 + + + CF$UID + 499 + + + CF$UID + 500 + + + CF$UID + 116 + + + CF$UID + 501 + + + CF$UID + 507 + + + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 310 + + + NS.objects + + + CF$UID + 106 + + + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 312 + + + NS.objects + + + CF$UID + 135 + + + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 314 + + + NS.objects + + + CF$UID + 502 + + + + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 503 + + + CF$UID + 505 + + + + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 317 + + + CF$UID + 318 + + + NS.objects + + + CF$UID + 319 + + + CF$UID + 504 + + + + 298 + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 317 + + + CF$UID + 318 + + + NS.objects + + + CF$UID + 322 + + + CF$UID + 506 + + + + 301 + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 314 + + + NS.objects + + + CF$UID + 508 + + + + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 509 + + + CF$UID + 511 + + + + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 317 + + + CF$UID + 318 + + + NS.objects + + + CF$UID + 319 + + + CF$UID + 510 + + + + 298 + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 317 + + + CF$UID + 318 + + + NS.objects + + + CF$UID + 322 + + + CF$UID + 512 + + + + 301 + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 314 + + + NS.objects + + + CF$UID + 514 + + + + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 515 + + + CF$UID + 517 + + + + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 317 + + + CF$UID + 318 + + + NS.objects + + + CF$UID + 333 + + + CF$UID + 516 + + + + 203 + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 317 + + + CF$UID + 318 + + + NS.objects + + + CF$UID + 336 + + + CF$UID + 518 + + + + 115 + + $class + + CF$UID + 87 + + NS.keys + + NS.objects + + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 314 + + + NS.objects + + + CF$UID + 521 + + + + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 522 + + + CF$UID + 524 + + + + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 317 + + + CF$UID + 318 + + + NS.objects + + + CF$UID + 198 + + + CF$UID + 523 + + + + 411 + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 317 + + + CF$UID + 318 + + + NS.objects + + + CF$UID + 198 + + + CF$UID + 525 + + + + 211 + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 346 + + + CF$UID + 347 + + + NS.objects + + + CF$UID + 347 + + + CF$UID + 527 + + + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 349 + + + CF$UID + 350 + + + CF$UID + 351 + + + CF$UID + 352 + + + CF$UID + 353 + + + CF$UID + 354 + + + CF$UID + 355 + + + NS.objects + + + CF$UID + 356 + + + CF$UID + 176 + + + CF$UID + 177 + + + CF$UID + 176 + + + CF$UID + 176 + + + CF$UID + 528 + + + CF$UID + 530 + + + + + $class + + CF$UID + 16 + + NS.objects + + + CF$UID + 529 + + + + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 259 + + + CF$UID + 257 + + + CF$UID + 473 + + + + + $class + + CF$UID + 178 + + NS.objects + + + CF$UID + 531 + + + CF$UID + 532 + + + CF$UID + 533 + + + CF$UID + 534 + + + + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 259 + + + + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 259 + + + CF$UID + 185 + + + + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 259 + + + CF$UID + 257 + + + + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 259 + + + CF$UID + 257 + + + CF$UID + 255 + + + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 314 + + + NS.objects + + + CF$UID + 536 + + + + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 537 + + + CF$UID + 539 + + + CF$UID + 541 + + + + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 317 + + + CF$UID + 318 + + + NS.objects + + + CF$UID + 235 + + + CF$UID + 538 + + + + 260 + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 317 + + + CF$UID + 318 + + + NS.objects + + + CF$UID + 233 + + + CF$UID + 540 + + + + 1341 + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 317 + + + CF$UID + 318 + + + NS.objects + + + CF$UID + 371 + + + CF$UID + 542 + + + + 260 + + $class + + CF$UID + 16 + + NS.objects + + + CF$UID + 464 + + + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 223 + + + CF$UID + 225 + + + CF$UID + 545 + + + CF$UID + 224 + + + CF$UID + 14 + + + CF$UID + 226 + + + NS.objects + + + CF$UID + 546 + + + CF$UID + 176 + + + CF$UID + 547 + + + CF$UID + 628 + + + CF$UID + 6 + + + CF$UID + 545 + + + + IDEWorkspaceTabController_B0E0B3DC-5AAF-4BFF-AF1E-B69835241B26 + {{264, 424}, {600, 646}} + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 231 + + + CF$UID + 232 + + + CF$UID + 233 + + + CF$UID + 234 + + + CF$UID + 235 + + + CF$UID + 236 + + + CF$UID + 237 + + + CF$UID + 238 + + + NS.objects + + + CF$UID + 106 + + + CF$UID + 176 + + + CF$UID + 548 + + + CF$UID + 607 + + + CF$UID + 613 + + + CF$UID + 620 + + + CF$UID + 176 + + + CF$UID + 554 + + + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 240 + + + CF$UID + 241 + + + CF$UID + 242 + + + CF$UID + 243 + + + CF$UID + 244 + + + CF$UID + 245 + + + CF$UID + 246 + + + CF$UID + 247 + + + NS.objects + + + CF$UID + 549 + + + CF$UID + 561 + + + CF$UID + 585 + + + CF$UID + 17 + + + CF$UID + 106 + + + CF$UID + 600 + + + CF$UID + 606 + + + CF$UID + 176 + + + + + $class + + CF$UID + 155 + + geniusEditorContextNode + + CF$UID + 0 + + primaryEditorContextNode + + CF$UID + 550 + + rootLayoutTreeNode + + CF$UID + 559 + + + + $class + + CF$UID + 154 + + children + + CF$UID + 0 + + contentType + 1 + documentArchivableRepresentation + + CF$UID + 551 + + orientation + 0 + parent + + CF$UID + 559 + + + + $class + + CF$UID + 66 + + DocumentLocation + + CF$UID + 557 + + DomainIdentifier + + CF$UID + 56 + + IdentifierPath + + CF$UID + 552 + + IndexOfDocumentIdentifier + + CF$UID + 106 + + + + $class + + CF$UID + 16 + + NS.objects + + + CF$UID + 553 + + + CF$UID + 555 + + + CF$UID + 556 + + + + + $class + + CF$UID + 60 + + Identifier + + CF$UID + 554 + + + Info.plist + + $class + + CF$UID + 60 + + Identifier + + CF$UID + 185 + + + + $class + + CF$UID + 60 + + Identifier + + CF$UID + 259 + + + + $class + + CF$UID + 65 + + documentURL + + CF$UID + 558 + + timestamp + + CF$UID + 0 + + + + $class + + CF$UID + 64 + + NS.string + file://localhost/Volumes/Work/idMobileDepot/Archive/DoomClassicDepot/code/iphone/Info.plist + + + $class + + CF$UID + 154 + + children + + CF$UID + 560 + + contentType + 0 + documentArchivableRepresentation + + CF$UID + 0 + + orientation + 0 + parent + + CF$UID + 0 + + + + $class + + CF$UID + 16 + + NS.objects + + + CF$UID + 550 + + + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 265 + + + NS.objects + + + CF$UID + 562 + + + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 267 + + + NS.objects + + + CF$UID + 563 + + + + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 269 + + + CF$UID + 270 + + + CF$UID + 271 + + + NS.objects + + + CF$UID + 564 + + + CF$UID + 106 + + + CF$UID + 584 + + + + + $class + + CF$UID + 16 + + NS.objects + + + CF$UID + 565 + + + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 274 + + + CF$UID + 275 + + + CF$UID + 276 + + + CF$UID + 277 + + + CF$UID + 278 + + + CF$UID + 279 + + + CF$UID + 280 + + + NS.objects + + + CF$UID + 566 + + + CF$UID + 567 + + + CF$UID + 572 + + + CF$UID + 554 + + + CF$UID + 554 + + + CF$UID + 581 + + + CF$UID + 582 + + + + com.apple.xml-property-list + + $class + + CF$UID + 66 + + DocumentLocation + + CF$UID + 557 + + DomainIdentifier + + CF$UID + 56 + + IdentifierPath + + CF$UID + 568 + + IndexOfDocumentIdentifier + + CF$UID + 106 + + + + $class + + CF$UID + 16 + + NS.objects + + + CF$UID + 569 + + + CF$UID + 570 + + + CF$UID + 571 + + + + + $class + + CF$UID + 60 + + Identifier + + CF$UID + 554 + + + + $class + + CF$UID + 60 + + Identifier + + CF$UID + 185 + + + + $class + + CF$UID + 60 + + Identifier + + CF$UID + 259 + + + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 573 + + + CF$UID + 574 + + + CF$UID + 575 + + + NS.objects + + + CF$UID + 576 + + + CF$UID + 578 + + + CF$UID + 579 + + + + IDE_PLIST_EDITOR_SELECTION_KEY + IDE_PLIST_EDITOR_VISIBLERECT_KEY + IDE_PLIST_EDITOR_EXPANSION_KEY + + $class + + CF$UID + 16 + + NS.objects + + + CF$UID + 577 + + + + CFBundleIconFile + {{0, 0}, {600, 561}} + + $class + + CF$UID + 580 + + NS.objects + + + + $classes + + NSMutableSet + NSSet + NSObject + + $classname + NSMutableSet + + Xcode.IDEKit.EditorDocument.PlistEditor + + $class + + CF$UID + 105 + + NS.base + + CF$UID + 0 + + NS.relative + + CF$UID + 583 + + + file://localhost/Volumes/Work/idMobileDepot/Archive/DoomClassicDepot/code/iphone/Info.plist + + $class + + CF$UID + 16 + + NS.objects + + + CF$UID + 301 + + + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 303 + + + CF$UID + 304 + + + CF$UID + 305 + + + CF$UID + 306 + + + CF$UID + 307 + + + CF$UID + 308 + + + NS.objects + + + CF$UID + 116 + + + CF$UID + 586 + + + CF$UID + 587 + + + CF$UID + 116 + + + CF$UID + 588 + + + CF$UID + 594 + + + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 310 + + + NS.objects + + + CF$UID + 106 + + + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 312 + + + NS.objects + + + CF$UID + 135 + + + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 314 + + + NS.objects + + + CF$UID + 589 + + + + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 590 + + + CF$UID + 592 + + + + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 317 + + + CF$UID + 318 + + + NS.objects + + + CF$UID + 319 + + + CF$UID + 591 + + + + 298 + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 317 + + + CF$UID + 318 + + + NS.objects + + + CF$UID + 322 + + + CF$UID + 593 + + + + 301 + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 314 + + + NS.objects + + + CF$UID + 595 + + + + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 596 + + + CF$UID + 598 + + + + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 317 + + + CF$UID + 318 + + + NS.objects + + + CF$UID + 319 + + + CF$UID + 597 + + + + 298 + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 317 + + + CF$UID + 318 + + + NS.objects + + + CF$UID + 322 + + + CF$UID + 599 + + + + 301 + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 314 + + + NS.objects + + + CF$UID + 601 + + + + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 602 + + + CF$UID + 604 + + + + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 317 + + + CF$UID + 318 + + + NS.objects + + + CF$UID + 333 + + + CF$UID + 603 + + + + 203 + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 317 + + + CF$UID + 318 + + + NS.objects + + + CF$UID + 336 + + + CF$UID + 605 + + + + 115 + + $class + + CF$UID + 87 + + NS.keys + + NS.objects + + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 314 + + + NS.objects + + + CF$UID + 608 + + + + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 609 + + + CF$UID + 611 + + + + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 317 + + + CF$UID + 318 + + + NS.objects + + + CF$UID + 198 + + + CF$UID + 610 + + + + 376 + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 317 + + + CF$UID + 318 + + + NS.objects + + + CF$UID + 198 + + + CF$UID + 612 + + + + 224 + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 346 + + + CF$UID + 347 + + + NS.objects + + + CF$UID + 347 + + + CF$UID + 614 + + + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 349 + + + CF$UID + 350 + + + CF$UID + 351 + + + CF$UID + 352 + + + CF$UID + 353 + + + CF$UID + 354 + + + CF$UID + 355 + + + NS.objects + + + CF$UID + 356 + + + CF$UID + 176 + + + CF$UID + 177 + + + CF$UID + 176 + + + CF$UID + 176 + + + CF$UID + 615 + + + CF$UID + 617 + + + + + $class + + CF$UID + 16 + + NS.objects + + + CF$UID + 616 + + + + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 259 + + + CF$UID + 185 + + + CF$UID + 554 + + + + + $class + + CF$UID + 178 + + NS.objects + + + CF$UID + 618 + + + CF$UID + 619 + + + + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 259 + + + + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 259 + + + CF$UID + 185 + + + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 314 + + + NS.objects + + + CF$UID + 621 + + + + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 622 + + + CF$UID + 624 + + + CF$UID + 626 + + + + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 317 + + + CF$UID + 318 + + + NS.objects + + + CF$UID + 235 + + + CF$UID + 623 + + + + 260 + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 317 + + + CF$UID + 318 + + + NS.objects + + + CF$UID + 233 + + + CF$UID + 625 + + + + 1140 + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 317 + + + CF$UID + 318 + + + NS.objects + + + CF$UID + 371 + + + CF$UID + 627 + + + + 260 + + $class + + CF$UID + 16 + + NS.objects + + + CF$UID + 545 + + + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 630 + + + CF$UID + 631 + + + CF$UID + 632 + + + CF$UID + 633 + + + CF$UID + 634 + + + CF$UID + 635 + + + CF$UID + 636 + + + CF$UID + 637 + + + CF$UID + 638 + + + CF$UID + 639 + + + CF$UID + 640 + + + NS.objects + + + CF$UID + 176 + + + CF$UID + 641 + + + CF$UID + 106 + + + CF$UID + 781 + + + CF$UID + 786 + + + CF$UID + 789 + + + CF$UID + 820 + + + CF$UID + 821 + + + CF$UID + 840 + + + CF$UID + 176 + + + CF$UID + 176 + + + + BreakpointsActivated + DefaultEditorStatesForURLs + DebuggingWindowBehavior + ActiveRunDestination + ActiveScheme + LastCompletedPersistentSchemeBasedActivityReport + DocumentWindows + DefaultEditorFrameSizeForURLs + RecentEditorDocumentURLs + AppFocusInMiniDebugging + MiniDebuggingConsole + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 642 + + + CF$UID + 581 + + + CF$UID + 643 + + + CF$UID + 297 + + + CF$UID + 644 + + + CF$UID + 415 + + + NS.objects + + + CF$UID + 645 + + + CF$UID + 683 + + + CF$UID + 692 + + + CF$UID + 710 + + + CF$UID + 753 + + + CF$UID + 757 + + + + IDEQuickLookEditor.Editor + Xcode.Xcode3ProjectSupport.EditorDocument.Xcode3Project + Xcode.IDEKit.EditorDocument.LogDocument + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 646 + + + CF$UID + 648 + + + CF$UID + 650 + + + CF$UID + 652 + + + CF$UID + 654 + + + NS.objects + + + CF$UID + 656 + + + CF$UID + 663 + + + CF$UID + 668 + + + CF$UID + 673 + + + CF$UID + 678 + + + + + $class + + CF$UID + 105 + + NS.base + + CF$UID + 0 + + NS.relative + + CF$UID + 647 + + + + $class + + CF$UID + 64 + + NS.string + file://localhost/Volumes/Work/idMobileDepot/Archive/DoomClassicDepot/code/iphone/Doom_icon.png + + + $class + + CF$UID + 105 + + NS.base + + CF$UID + 0 + + NS.relative + + CF$UID + 649 + + + + $class + + CF$UID + 64 + + NS.string + file://localhost/Volumes/Work/idMobileDepot/Archive/DoomClassicDepot/code/iphone/DOOM_57.png + + + $class + + CF$UID + 105 + + NS.base + + CF$UID + 0 + + NS.relative + + CF$UID + 651 + + + + $class + + CF$UID + 64 + + NS.string + file://localhost/Volumes/Work/idMobileDepot/Archive/DoomClassicDepot/code/iphone/Default.png + + + $class + + CF$UID + 105 + + NS.base + + CF$UID + 0 + + NS.relative + + CF$UID + 653 + + + + $class + + CF$UID + 64 + + NS.string + file://localhost/Volumes/Work/idMobileDepot/Archive/DoomClassicDepot/code/iphone/DOOM_72.png + + + $class + + CF$UID + 105 + + NS.base + + CF$UID + 0 + + NS.relative + + CF$UID + 655 + + + + $class + + CF$UID + 64 + + NS.string + file://localhost/Volumes/Work/idMobileDepot/Archive/DoomClassicDepot/code/iphone/DOOM_114.png + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 657 + + + NS.objects + + + CF$UID + 658 + + + + SelectedDocumentLocations + + $class + + CF$UID + 16 + + NS.objects + + + CF$UID + 659 + + + + + $class + + CF$UID + 662 + + IDEQuickLookPageNumber + + CF$UID + 106 + + documentURL + + CF$UID + 660 + + timestamp + + CF$UID + 661 + + + file://localhost/Volumes/Work/idMobileDepot/Archive/DoomClassicDepot/code/iphone/Doom_icon.png + 333323936.54352701 + + $classes + + IDEQuickLookDocumentLocation + DVTDocumentLocation + NSObject + + $classname + IDEQuickLookDocumentLocation + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 657 + + + NS.objects + + + CF$UID + 664 + + + + + $class + + CF$UID + 16 + + NS.objects + + + CF$UID + 665 + + + + + $class + + CF$UID + 662 + + IDEQuickLookPageNumber + + CF$UID + 106 + + documentURL + + CF$UID + 666 + + timestamp + + CF$UID + 667 + + + file://localhost/Volumes/Work/idMobileDepot/Archive/DoomClassicDepot/code/iphone/DOOM_57.png + 333323944.43125302 + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 657 + + + NS.objects + + + CF$UID + 669 + + + + + $class + + CF$UID + 16 + + NS.objects + + + CF$UID + 670 + + + + + $class + + CF$UID + 662 + + IDEQuickLookPageNumber + + CF$UID + 106 + + documentURL + + CF$UID + 671 + + timestamp + + CF$UID + 672 + + + file://localhost/Volumes/Work/idMobileDepot/Archive/DoomClassicDepot/code/iphone/Default.png + 333578761.91734701 + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 657 + + + NS.objects + + + CF$UID + 674 + + + + + $class + + CF$UID + 16 + + NS.objects + + + CF$UID + 675 + + + + + $class + + CF$UID + 662 + + IDEQuickLookPageNumber + + CF$UID + 106 + + documentURL + + CF$UID + 676 + + timestamp + + CF$UID + 677 + + + file://localhost/Volumes/Work/idMobileDepot/Archive/DoomClassicDepot/code/iphone/DOOM_72.png + 333323919.06361401 + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 657 + + + NS.objects + + + CF$UID + 679 + + + + + $class + + CF$UID + 16 + + NS.objects + + + CF$UID + 680 + + + + + $class + + CF$UID + 662 + + IDEQuickLookPageNumber + + CF$UID + 106 + + documentURL + + CF$UID + 681 + + timestamp + + CF$UID + 682 + + + file://localhost/Volumes/Work/idMobileDepot/Archive/DoomClassicDepot/code/iphone/DOOM_114.png + 333323919.79163003 + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 684 + + + NS.objects + + + CF$UID + 686 + + + + + $class + + CF$UID + 105 + + NS.base + + CF$UID + 0 + + NS.relative + + CF$UID + 685 + + + + $class + + CF$UID + 64 + + NS.string + file://localhost/Volumes/Work/idMobileDepot/Archive/DoomClassicDepot/code/iphone/Info.plist + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 687 + + + CF$UID + 688 + + + CF$UID + 689 + + + NS.objects + + + CF$UID + 407 + + + CF$UID + 690 + + + CF$UID + 691 + + + + IDE_PLIST_EDITOR_SELECTION_KEY + IDE_PLIST_EDITOR_VISIBLERECT_KEY + IDE_PLIST_EDITOR_EXPANSION_KEY + {{0, 0}, {880, 547}} + + $class + + CF$UID + 580 + + NS.objects + + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 693 + + + NS.objects + + + CF$UID + 694 + + + + + $class + + CF$UID + 105 + + NS.base + + CF$UID + 0 + + NS.relative + + CF$UID + 63 + + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 68 + + + CF$UID + 69 + + + CF$UID + 70 + + + CF$UID + 71 + + + CF$UID + 72 + + + CF$UID + 73 + + + NS.objects + + + CF$UID + 695 + + + CF$UID + 696 + + + CF$UID + 702 + + + CF$UID + 703 + + + CF$UID + 709 + + + CF$UID + 100 + + + + Xcode3ProjectInfoEditor + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 76 + + + NS.objects + + + CF$UID + 697 + + + + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 698 + + + CF$UID + 700 + + + + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 79 + + + CF$UID + 80 + + + NS.objects + + + CF$UID + 81 + + + CF$UID + 699 + + + + 170 + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 79 + + + CF$UID + 80 + + + NS.objects + + + CF$UID + 81 + + + CF$UID + 701 + + + + 710 + Xcode3TargetEditor + + $class + + CF$UID + 16 + + NS.objects + + + CF$UID + 704 + + + + + $class + + CF$UID + 98 + + documentURL + + CF$UID + 91 + + selection + + CF$UID + 706 + + timestamp + + CF$UID + 705 + + + 333652380.06829602 + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 94 + + + CF$UID + 95 + + + NS.objects + + + CF$UID + 707 + + + CF$UID + 708 + + + + Doom + Xcode3ProjectInfoEditor + + $class + + CF$UID + 87 + + NS.keys + + NS.objects + + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 711 + + + CF$UID + 713 + + + CF$UID + 715 + + + CF$UID + 717 + + + CF$UID + 719 + + + CF$UID + 721 + + + CF$UID + 723 + + + CF$UID + 725 + + + NS.objects + + + CF$UID + 727 + + + CF$UID + 729 + + + CF$UID + 732 + + + CF$UID + 736 + + + CF$UID + 739 + + + CF$UID + 743 + + + CF$UID + 747 + + + CF$UID + 750 + + + + + $class + + CF$UID + 105 + + NS.base + + CF$UID + 0 + + NS.relative + + CF$UID + 712 + + + + $class + + CF$UID + 64 + + NS.string + file://localhost/Volumes/Work/idMobileDepot/Archive/DoomClassicDepot/code/iphone/GenericMenuView.m + + + $class + + CF$UID + 105 + + NS.base + + CF$UID + 0 + + NS.relative + + CF$UID + 714 + + + + $class + + CF$UID + 64 + + NS.string + file://localhost/Volumes/Work/idMobileDepot/Archive/DoomClassicDepot/code/iphone/MainMenuView.h + + + $class + + CF$UID + 105 + + NS.base + + CF$UID + 0 + + NS.relative + + CF$UID + 716 + + + + $class + + CF$UID + 64 + + NS.string + file://localhost/Volumes/Work/idMobileDepot/Archive/DoomClassicDepot/code/iphone/iphone_menus.c + + + $class + + CF$UID + 105 + + NS.base + + CF$UID + 0 + + NS.relative + + CF$UID + 718 + + + + $class + + CF$UID + 64 + + NS.string + file://localhost/Volumes/Work/idMobileDepot/Archive/DoomClassicDepot/code/iphone/iphone_net.c + + + $class + + CF$UID + 105 + + NS.base + + CF$UID + 0 + + NS.relative + + CF$UID + 720 + + + + $class + + CF$UID + 64 + + NS.string + file://localhost/Volumes/Work/idMobileDepot/Archive/DoomClassicDepot/code/iphone/iphone_mapSelect.c + + + $class + + CF$UID + 105 + + NS.base + + CF$UID + 0 + + NS.relative + + CF$UID + 722 + + + + $class + + CF$UID + 64 + + NS.string + file://localhost/Volumes/Work/idMobileDepot/Archive/DoomClassicDepot/code/iphone/MainMenuView.m + + + $class + + CF$UID + 105 + + NS.base + + CF$UID + 0 + + NS.relative + + CF$UID + 724 + + + + $class + + CF$UID + 64 + + NS.string + file://localhost/Volumes/Work/idMobileDepot/Archive/DoomClassicDepot/code/iphone/ControlsMenuView.m + + + $class + + CF$UID + 105 + + NS.base + + CF$UID + 0 + + NS.relative + + CF$UID + 726 + + + + $class + + CF$UID + 64 + + NS.string + file://localhost/Volumes/Work/idMobileDepot/Archive/DoomClassicDepot/code/iphone/GenericMenuView.h + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 289 + + + CF$UID + 290 + + + CF$UID + 291 + + + CF$UID + 292 + + + NS.objects + + + CF$UID + 728 + + + CF$UID + 294 + + + CF$UID + 176 + + + CF$UID + 295 + + + + 333326387.39224499 + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 289 + + + CF$UID + 290 + + + CF$UID + 291 + + + CF$UID + 292 + + + NS.objects + + + CF$UID + 730 + + + CF$UID + 731 + + + CF$UID + 176 + + + CF$UID + 494 + + + + 333325963.820427 + {0, 1403} + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 289 + + + CF$UID + 290 + + + CF$UID + 291 + + + CF$UID + 292 + + + NS.objects + + + CF$UID + 733 + + + CF$UID + 734 + + + CF$UID + 176 + + + CF$UID + 735 + + + + 333326121.00765198 + {3309, 1668} + {4660, 21} + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 289 + + + CF$UID + 290 + + + CF$UID + 291 + + + CF$UID + 292 + + + NS.objects + + + CF$UID + 737 + + + CF$UID + 738 + + + CF$UID + 176 + + + CF$UID + 494 + + + + 333326077.15981197 + {0, 1833} + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 289 + + + CF$UID + 290 + + + CF$UID + 291 + + + CF$UID + 292 + + + NS.objects + + + CF$UID + 740 + + + CF$UID + 741 + + + CF$UID + 176 + + + CF$UID + 742 + + + + 333326166.33271098 + {11410, 1723} + {12411, 92} + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 289 + + + CF$UID + 290 + + + CF$UID + 291 + + + CF$UID + 292 + + + NS.objects + + + CF$UID + 744 + + + CF$UID + 745 + + + CF$UID + 176 + + + CF$UID + 746 + + + + 333326321.58882499 + {664, 1881} + {5662, 0} + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 289 + + + CF$UID + 290 + + + CF$UID + 291 + + + CF$UID + 292 + + + NS.objects + + + CF$UID + 748 + + + CF$UID + 749 + + + CF$UID + 176 + + + CF$UID + 494 + + + + 333565450.35472602 + {0, 1464} + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 289 + + + CF$UID + 290 + + + CF$UID + 291 + + + CF$UID + 292 + + + NS.objects + + + CF$UID + 751 + + + CF$UID + 752 + + + CF$UID + 176 + + + CF$UID + 494 + + + + 333399353.99927002 + {0, 354} + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 754 + + + NS.objects + + + CF$UID + 756 + + + + + $class + + CF$UID + 105 + + NS.base + + CF$UID + 0 + + NS.relative + + CF$UID + 755 + + + x-xcode-log://DFDD5CA1-7D47-4609-9C5C-B32E826175D7 + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 657 + + + NS.objects + + + CF$UID + 407 + + + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 758 + + + CF$UID + 760 + + + NS.objects + + + CF$UID + 762 + + + CF$UID + 772 + + + + + $class + + CF$UID + 105 + + NS.base + + CF$UID + 0 + + NS.relative + + CF$UID + 759 + + + + $class + + CF$UID + 64 + + NS.string + file://localhost/Volumes/Work/idMobileDepot/Archive/DoomClassicDepot/code/iphone/Resources-iPad/MainWindow-iPad.xib + + + $class + + CF$UID + 105 + + NS.base + + CF$UID + 0 + + NS.relative + + CF$UID + 761 + + + + $class + + CF$UID + 64 + + NS.string + file://localhost/Volumes/Work/idMobileDepot/Archive/DoomClassicDepot/code/iphone/MainWindow.xib + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 402 + + + CF$UID + 403 + + + CF$UID + 404 + + + CF$UID + 405 + + + NS.objects + + + CF$UID + 763 + + + CF$UID + 764 + + + CF$UID + 766 + + + CF$UID + 767 + + + + + $class + + CF$UID + 87 + + NS.keys + + NS.objects + + + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 765 + + + + 8 + IBStructureViewController + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 409 + + + CF$UID + 410 + + + NS.objects + + + CF$UID + 768 + + + CF$UID + 769 + + + + + $class + + CF$UID + 87 + + NS.keys + + NS.objects + + + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 770 + + + CF$UID + 771 + + + CF$UID + 765 + + + + 325 + 11 + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 402 + + + CF$UID + 403 + + + CF$UID + 404 + + + CF$UID + 405 + + + NS.objects + + + CF$UID + 773 + + + CF$UID + 776 + + + CF$UID + 405 + + + CF$UID + 778 + + + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 774 + + + NS.objects + + + CF$UID + 775 + + + + LastKnownOutlineViewWidth + 270 + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 777 + + + + 252 + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 409 + + + CF$UID + 410 + + + NS.objects + + + CF$UID + 411 + + + CF$UID + 779 + + + + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 780 + + + + 170 + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 782 + + + CF$UID + 783 + + + NS.objects + + + CF$UID + 784 + + + CF$UID + 785 + + + + IDEDeviceLocation + IDEDeviceArchitecture + dvtdevice-iphone:2826d1c37988eed0d2318d50b590ecba088e5c32 + armv7 + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 787 + + + NS.objects + + + CF$UID + 788 + + + + IDENameString + Doom + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 790 + + + CF$UID + 791 + + + CF$UID + 792 + + + NS.objects + + + CF$UID + 793 + + + CF$UID + 819 + + + CF$UID + 800 + + + + IDEActivityReportCompletionSummaryStringSegments + IDEActivityReportOptions + IDEActivityReportTitle + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 794 + + + CF$UID + 801 + + + CF$UID + 805 + + + CF$UID + 810 + + + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 795 + + + CF$UID + 796 + + + CF$UID + 797 + + + NS.objects + + + CF$UID + 798 + + + CF$UID + 799 + + + CF$UID + 800 + + + + IDEActivityReportStringSegmentPriority + IDEActivityReportStringSegmentBackSeparator + IDEActivityReportStringSegmentStringValue + 2 + + Archive + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 795 + + + CF$UID + 796 + + + CF$UID + 797 + + + NS.objects + + + CF$UID + 802 + + + CF$UID + 803 + + + CF$UID + 804 + + + + 4 + : + Doom + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 795 + + + CF$UID + 796 + + + CF$UID + 797 + + + NS.objects + + + CF$UID + 806 + + + CF$UID + 807 + + + CF$UID + 808 + + + + 1 + │ + + $class + + CF$UID + 809 + + NS.data + + YnBsaXN0MDDUAQIDBAUGOzxYJHZlcnNpb25YJG9iamVjdHNZJGFy + Y2hpdmVyVCR0b3ASAAGGoK0HCA8QGhscJCUrMTQ3VSRudWxs0wkK + CwwNDlxOU0F0dHJpYnV0ZXNWJGNsYXNzWE5TU3RyaW5ngAOADIAC + WVN1Y2NlZWRlZNMKERITFBdXTlMua2V5c1pOUy5vYmplY3RzgAui + FRaABIAFohgZgAaACVZOU0ZvbnRXTlNDb2xvctQKHR4fICEiI1ZO + U05hbWVWTlNTaXplWE5TZkZsYWdzgAiAByNAJgAAAAAAABENEF8Q + EUx1Y2lkYUdyYW5kZS1Cb2xk0iYnKClaJGNsYXNzbmFtZVgkY2xh + c3Nlc1ZOU0ZvbnSiKCpYTlNPYmplY3TTCiwtLi8wXE5TQ29sb3JT + cGFjZVdOU1doaXRlgAoQA0IwANImJzIzV05TQ29sb3KiMirSJic1 + NlxOU0RpY3Rpb25hcnmiNSrSJic4OV8QEk5TQXR0cmlidXRlZFN0 + cmluZ6I6Kl8QEk5TQXR0cmlidXRlZFN0cmluZ18QD05TS2V5ZWRB + cmNoaXZlctE9PlRyb290gAEACAARABoAIwAtADIANwBFAEsAUgBf + AGYAbwBxAHMAdQB/AIYAjgCZAJsAngCgAKIApQCnAKkAsAC4AMEA + yADPANgA2gDcAOUA6AD8AQEBDAEVARwBHwEoAS8BPAFEAUYBSAFL + AVABWAFbAWABbQFwAXUBigGNAaIBtAG3AbwAAAAAAAACAQAAAAAA + AAA/AAAAAAAAAAAAAAAAAAABvg== + + + + $classes + + NSMutableData + NSData + NSObject + + $classname + NSMutableData + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 795 + + + CF$UID + 811 + + + CF$UID + 812 + + + CF$UID + 797 + + + CF$UID + 813 + + + CF$UID + 814 + + + NS.objects + + + CF$UID + 815 + + + CF$UID + 116 + + + CF$UID + 816 + + + CF$UID + 818 + + + CF$UID + 116 + + + CF$UID + 116 + + + + IDEActivityReportStringSegmentType + IDEActivityReportStringSegmentDate + IDEActivityReportStringSegmentDateStyle + IDEActivityReportStringSegmentTimeStyle + 3 + + $class + + CF$UID + 817 + + NS.time + 333652063.56631202 + + + $classes + + NSDate + NSObject + + $classname + NSDate + + Today at 12:07 PM + 106 + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 2 + + + + + $class + + CF$UID + 87 + + NS.keys + + + CF$UID + 822 + + + CF$UID + 823 + + + CF$UID + 824 + + + CF$UID + 825 + + + NS.objects + + + CF$UID + 826 + + + CF$UID + 831 + + + CF$UID + 834 + + + CF$UID + 837 + + + + + $class + + CF$UID + 105 + + NS.base + + CF$UID + 0 + + NS.relative + + CF$UID + 417 + + + + $class + + CF$UID + 105 + + NS.base + + CF$UID + 0 + + NS.relative + + CF$UID + 299 + + + + $class + + CF$UID + 105 + + NS.base + + CF$UID + 0 + + NS.relative + + CF$UID + 496 + + + + $class + + CF$UID + 105 + + NS.base + + CF$UID + 0 + + NS.relative + + CF$UID + 583 + + + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 827 + + + CF$UID + 828 + + + NS.objects + + + CF$UID + 829 + + + CF$UID + 830 + + + + width + height + 600 + 600 + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 827 + + + CF$UID + 828 + + + NS.objects + + + CF$UID + 832 + + + CF$UID + 833 + + + + 600 + 600 + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 827 + + + CF$UID + 828 + + + NS.objects + + + CF$UID + 835 + + + CF$UID + 836 + + + + 600 + 600 + + $class + + CF$UID + 83 + + NS.keys + + + CF$UID + 827 + + + CF$UID + 828 + + + NS.objects + + + CF$UID + 838 + + + CF$UID + 839 + + + + 600 + 600 + + $class + + CF$UID + 86 + + NS.objects + + + CF$UID + 841 + + + CF$UID + 842 + + + CF$UID + 844 + + + CF$UID + 754 + + + CF$UID + 845 + + + CF$UID + 847 + + + CF$UID + 849 + + + CF$UID + 851 + + + CF$UID + 852 + + + CF$UID + 854 + + + + + $class + + CF$UID + 105 + + NS.base + + CF$UID + 0 + + NS.relative + + CF$UID + 91 + + + + $class + + CF$UID + 105 + + NS.base + + CF$UID + 0 + + NS.relative + + CF$UID + 843 + + + file://localhost/Volumes/Work/idMobileDepot/Archive/DoomClassicDepot/code/iphone/Info.plist + + $class + + CF$UID + 105 + + NS.base + + CF$UID + 0 + + NS.relative + + CF$UID + 671 + + + + $class + + CF$UID + 105 + + NS.base + + CF$UID + 0 + + NS.relative + + CF$UID + 846 + + + file://localhost/Volumes/Work/idMobileDepot/Archive/DoomClassicDepot/code/iphone/ControlsMenuView.m + + $class + + CF$UID + 105 + + NS.base + + CF$UID + 0 + + NS.relative + + CF$UID + 848 + + + file://localhost/Volumes/Work/idMobileDepot/Archive/DoomClassicDepot/code/iphone/Resources-iPad/MainWindow-iPad.xib + + $class + + CF$UID + 105 + + NS.base + + CF$UID + 0 + + NS.relative + + CF$UID + 850 + + + file://localhost/Volumes/Work/idMobileDepot/Archive/DoomClassicDepot/code/iphone/GenericMenuView.h + + $class + + CF$UID + 105 + + NS.base + + CF$UID + 0 + + NS.relative + + CF$UID + 299 + + + + $class + + CF$UID + 105 + + NS.base + + CF$UID + 0 + + NS.relative + + CF$UID + 853 + + + file://localhost/Volumes/Work/idMobileDepot/Archive/DoomClassicDepot/code/iphone/MainMenuView.m + + $class + + CF$UID + 105 + + NS.base + + CF$UID + 0 + + NS.relative + + CF$UID + 855 + + + file://localhost/Volumes/Work/idMobileDepot/Archive/DoomClassicDepot/code/iphone/iphone_mapSelect.c + + $top + + State + + CF$UID + 1 + + + $version + 100000 + + diff --git a/DoomClassic/code/iphone/Doom.xcodeproj/project.xcworkspace/xcuserdata/ryan.gerleve.xcuserdatad/UserInterfaceState.xcuserstate b/DoomClassic/code/iphone/Doom.xcodeproj/project.xcworkspace/xcuserdata/ryan.gerleve.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100755 index 0000000..0ccb56f Binary files /dev/null and b/DoomClassic/code/iphone/Doom.xcodeproj/project.xcworkspace/xcuserdata/ryan.gerleve.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/DoomClassic/code/iphone/Doom.xcodeproj/xcshareddata/xcschemes/DOOM.xcscheme b/DoomClassic/code/iphone/Doom.xcodeproj/xcshareddata/xcschemes/DOOM.xcscheme new file mode 100755 index 0000000..14ff0ba --- /dev/null +++ b/DoomClassic/code/iphone/Doom.xcodeproj/xcshareddata/xcschemes/DOOM.xcscheme @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/DoomClassic/code/iphone/Doom.xcodeproj/xcuserdata/Farrand.xcuserdatad/xcschemes/xcschememanagement.plist b/DoomClassic/code/iphone/Doom.xcodeproj/xcuserdata/Farrand.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..e80c962 --- /dev/null +++ b/DoomClassic/code/iphone/Doom.xcodeproj/xcuserdata/Farrand.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,22 @@ + + + + + SchemeUserState + + DOOM.xcscheme_^#shared#^_ + + orderHint + 0 + + + SuppressBuildableAutocreation + + 1D6058900D05DD3D006BFB54 + + primary + + + + + diff --git a/DoomClassic/code/iphone/Doom.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/Doom.xcscheme b/DoomClassic/code/iphone/Doom.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/Doom.xcscheme new file mode 100755 index 0000000..6799bf0 --- /dev/null +++ b/DoomClassic/code/iphone/Doom.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/Doom.xcscheme @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/DoomClassic/code/iphone/Doom.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/xcschememanagement.plist b/DoomClassic/code/iphone/Doom.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100755 index 0000000..82c98a8 --- /dev/null +++ b/DoomClassic/code/iphone/Doom.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,22 @@ + + + + + SchemeUserState + + Doom.xcscheme + + orderHint + 0 + + + SuppressBuildableAutocreation + + 1D6058900D05DD3D006BFB54 + + primary + + + + + diff --git a/DoomClassic/code/iphone/Doom.xcodeproj/xcuserdata/ryan.gerleve.xcuserdatad/xcschemes/xcschememanagement.plist b/DoomClassic/code/iphone/Doom.xcodeproj/xcuserdata/ryan.gerleve.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100755 index 0000000..3a57826 --- /dev/null +++ b/DoomClassic/code/iphone/Doom.xcodeproj/xcuserdata/ryan.gerleve.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,22 @@ + + + + + SchemeUserState + + DOOM.xcscheme_^#shared#^_ + + orderHint + 3 + + + SuppressBuildableAutocreation + + 1D6058900D05DD3D006BFB54 + + primary + + + + + diff --git a/DoomClassic/code/iphone/Doom_App.h b/DoomClassic/code/iphone/Doom_App.h new file mode 100755 index 0000000..88e491f --- /dev/null +++ b/DoomClassic/code/iphone/Doom_App.h @@ -0,0 +1,26 @@ +/* + + Copyright (C) 2009 Id Software, 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 + 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 "iphone_delegate.h" + + + + +@interface DoomApp : iphoneApp + +@end diff --git a/DoomClassic/code/iphone/Doom_App.m b/DoomClassic/code/iphone/Doom_App.m new file mode 100755 index 0000000..bc34021 --- /dev/null +++ b/DoomClassic/code/iphone/Doom_App.m @@ -0,0 +1,53 @@ +/* + + Copyright (C) 2009 Id Software, 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 + 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. + */ + +#import "Doom_App.h" +#import "MainMenuViewController.h" +#import "MainNavController.h" +#include "doomiphone.h" + +@implementation DoomApp + +- (void) InitializeInterfaceBuilder { + + // Create the Main Menu View controller. + + Doom_MainMenuViewController *rootController = nil; + if ( IS_IPHONE_5 ) { + rootController = [[Doom_MainMenuViewController alloc] initWithNibName:@"MainMenuViewi5" bundle:nil]; + } else { + rootController = [[Doom_MainMenuViewController alloc] initWithNibName:@"MainMenuView" bundle:nil]; + } + + // Create a Navigation Controller for Pushing/Popping Views. + navigationController = [[MainNavController alloc] initWithRootViewController:rootController]; + [navigationController setNavigationBarHidden:YES]; + [rootController release]; + + // Create the OpenGLView so that our context is created. Don't push it on yet though. + if ( IS_IPHONE_5 ) { + openGLViewController = [ [ iphone_glViewController alloc] initWithNibName:@"OpenGLViewi5" bundle:nil ]; + } else { + openGLViewController = [ [ iphone_glViewController alloc] initWithNibName:@"OpenGLView" bundle:nil ]; + } + + [ openGLViewController StopDisplay]; +} + +@end diff --git a/DoomClassic/code/iphone/EpisodeMenuView.xib b/DoomClassic/code/iphone/EpisodeMenuView.xib new file mode 100755 index 0000000..a20879a --- /dev/null +++ b/DoomClassic/code/iphone/EpisodeMenuView.xib @@ -0,0 +1,227 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DoomClassic/code/iphone/EpisodeMenuViewController.h b/DoomClassic/code/iphone/EpisodeMenuViewController.h new file mode 100755 index 0000000..f12b60c --- /dev/null +++ b/DoomClassic/code/iphone/EpisodeMenuViewController.h @@ -0,0 +1,52 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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. + + */ + +#import +#import "ios/LabelButton.h" + +/* + ================================================================================================ + EpisodeMenuViewController + + ================================================================================================ + */ +@interface Doom_EpisodeMenuViewController : UIViewController { + + IBOutlet idLabelButton * epi1Button; + IBOutlet idLabelButton * epi2Button; + IBOutlet idLabelButton * epi3Button; + IBOutlet idLabelButton * epi4Button; + + int episodeSelection; + IBOutlet idLabelButton * nextButton; + IBOutlet idLabel * nextLabel; + +} + +- (IBAction) BackToMain; +- (IBAction) NextToMissions; + + +- (IBAction) SelectEpisode1; +- (IBAction) SelectEpisode2; +- (IBAction) SelectEpisode3; +- (IBAction) SelectEpisode4; + +@end diff --git a/DoomClassic/code/iphone/EpisodeMenuViewController.mm b/DoomClassic/code/iphone/EpisodeMenuViewController.mm new file mode 100755 index 0000000..909c07f --- /dev/null +++ b/DoomClassic/code/iphone/EpisodeMenuViewController.mm @@ -0,0 +1,188 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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. + + */ + +#import "EpisodeMenuViewController.h" +#include "doomiphone.h" +#include "iphone_delegate.h" +#import "MissionMenuViewController.h" +/* + ================================================================================================ + EpisodeMenuViewController + + ================================================================================================ + */ +@implementation Doom_EpisodeMenuViewController + +/* + ======================== + Doom_EpisodeMenuViewController::initWithNibName + ======================== + */ +- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil +{ + self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; + if (self) { + + episodeSelection = -1; + [ nextButton setEnabled: NO ]; + [ nextLabel setEnabled: NO ]; + + } + return self; +} + +/* + ======================== + Doom_EpisodeMenuViewController::didReceiveMemoryWarning + ======================== + */ +- (void)didReceiveMemoryWarning +{ + // Releases the view if it doesn't have a superview. + [super didReceiveMemoryWarning]; + + // Release any cached data, images, etc that aren't in use. +} + +#pragma mark - View lifecycle + +/* + ======================== + Doom_EpisodeMenuViewController::viewDidLoad + ======================== + */ +- (void)viewDidLoad +{ + [super viewDidLoad]; + // Do any additional setup after loading the view from its nib. + + [ nextButton setEnabled: NO ]; + [ nextLabel setEnabled: NO ]; +} + +/* + ======================== + Doom_EpisodeMenuViewController::viewDidUnload + ======================== + */ +- (void)viewDidUnload +{ + [super viewDidUnload]; + // Release any retained subviews of the main view. + // e.g. self.myOutlet = nil; +} + +/* + ======================== + Doom_EpisodeMenuViewController::BackToMain + ======================== + */ +- (IBAction) BackToMain { + + [self.navigationController popViewControllerAnimated:NO]; + Sound_StartLocalSound( "iphone/controller_down_01_SILENCE.wav" ); +} + +/* + ======================== + Doom_EpisodeMenuViewController::NextToMissions + ======================== + */ +- (IBAction) NextToMissions { + + Doom_MissionMenuViewController *vc = nil; + + + if ( IS_IPHONE_5 ) { + vc = [[Doom_MissionMenuViewController alloc] initWithNibName:@"MissionMenuViewi5" bundle:nil]; + } else { + vc = [[Doom_MissionMenuViewController alloc] initWithNibName:@"MissionMenuView" bundle:nil]; + } + + + [self.navigationController pushViewController:vc animated:NO]; + [vc setEpisode:episodeSelection ]; + [vc release]; + + Sound_StartLocalSound( "iphone/controller_down_01_SILENCE.wav" ); +} + +/* + ======================== + Doom_EpisodeMenuViewController::SelectEpisode1 + ======================== + */ +- (IBAction) SelectEpisode1 { + + [ nextButton setEnabled: YES ]; + [ nextLabel setEnabled: YES ]; + episodeSelection = 0; + [ epi1Button setEnabled: NO ]; + [ epi2Button setEnabled: YES ]; + [ epi3Button setEnabled: YES ]; + [ epi4Button setEnabled: YES ]; +} + +/* + ======================== + Doom_EpisodeMenuViewController::SelectEpisode2 + ======================== + */ +- (IBAction) SelectEpisode2 { + [ nextButton setEnabled: YES ]; + [ nextLabel setEnabled: YES ]; + episodeSelection = 1; + [ epi1Button setEnabled: YES ]; + [ epi2Button setEnabled: NO ]; + [ epi3Button setEnabled: YES ]; + [ epi4Button setEnabled: YES ]; +} + +/* + ======================== + Doom_EpisodeMenuViewController::SelectEpisode3 + ======================== + */ +- (IBAction) SelectEpisode3 { + [ nextButton setEnabled: YES ]; + [ nextLabel setEnabled: YES ]; + episodeSelection = 2; + [ epi1Button setEnabled: YES ]; + [ epi2Button setEnabled: YES ]; + [ epi3Button setEnabled: NO ]; + [ epi4Button setEnabled: YES ]; +} + +/* + ======================== + Doom_EpisodeMenuViewController::SelectEpisode4 + ======================== + */ +- (IBAction) SelectEpisode4 { + [ nextButton setEnabled: YES ]; + [ nextLabel setEnabled: YES ]; + episodeSelection = 3; + [ epi1Button setEnabled: YES ]; + [ epi2Button setEnabled: YES ]; + [ epi3Button setEnabled: YES ]; + [ epi4Button setEnabled: NO ]; +} + +@end diff --git a/DoomClassic/code/iphone/EpisodeMenuViewi5.xib b/DoomClassic/code/iphone/EpisodeMenuViewi5.xib new file mode 100755 index 0000000..5bfd0a4 --- /dev/null +++ b/DoomClassic/code/iphone/EpisodeMenuViewi5.xib @@ -0,0 +1,228 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DoomClassic/code/iphone/EpisodeMenuView~ipad.xib b/DoomClassic/code/iphone/EpisodeMenuView~ipad.xib new file mode 100755 index 0000000..55057d8 --- /dev/null +++ b/DoomClassic/code/iphone/EpisodeMenuView~ipad.xib @@ -0,0 +1,1018 @@ + + + + 1280 + 11C74 + 1938 + 1138.23 + 567.00 + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + 933 + + + IBUIScrollView + IBUIButton + IBUIImageView + IBUIView + IBUILabel + IBProxyObject + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + PluginDependencyRecalculationVersion + + + + + IBFilesOwner + IBIPadFramework + + + IBFirstResponder + IBIPadFramework + + + + 274 + + + + 292 + {1024, 768} + + + + 1 + NO + IBIPadFramework + + NSImage + MenuBackground.png + + + + + 292 + {{904, 21}, {100, 100}} + + + + NO + IBIPadFramework + 0 + 0 + + 3 + MQA + + + 1 + MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA + + + 3 + MC41AA + + + NSImage + NextButton.png + + + Helvetica-Bold + Helvetica + 2 + 15 + + + Helvetica-Bold + 15 + 16 + + + + + 292 + {{15, 21}, {100, 100}} + + + + NO + IBIPadFramework + 0 + 0 + + + 1 + MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA + + + + NSImage + Episode1Background.png + + + NSImage + BackButton.png + + + + + + + 292 + {{927, 14}, {53, 24}} + + + + NO + YES + 7 + NO + IBIPadFramework + #Next + + 1 + MC43MjU0OTAyMTI0IDAuNDIzNTI5NDE2MyAwLjA2NjY2NjY3MDE0AA + + + 1 + MC43MjU0OTAyMTI0IDAuNDIzNTI5NDE2MyAwLjA2NjY2NjY3MDE0AA + + 1 + 10 + 1 + + Helvetica + Helvetica + 0 + 24 + + + Helvetica + 24 + 16 + + + + + 292 + {{38, 14}, {55, 24}} + + + + NO + YES + 7 + NO + IBIPadFramework + #Back + + + 1 + MSAwLjgwMDAwMDAxMTkgMAA + + 1 + 10 + 1 + + + + + + 292 + + + + 292 + {{24, 5}, {640, 158}} + + + + NO + IBIPadFramework + 0 + 0 + + + 1 + MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA + + + + NSImage + Episode1Background_Highlighted.png + + + + + + + + + 292 + {{24, 150}, {640, 158}} + + + + NO + IBIPadFramework + 0 + 0 + + + 1 + MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA + + + + NSImage + Episode2Background_Highlighted.png + + + + NSImage + Episode2Background.png + + + + + + + 292 + {{24, 297}, {640, 158}} + + + + NO + IBIPadFramework + 0 + 0 + + + 1 + MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA + + + + NSImage + Episode3Background_Highlighted.png + + + + NSImage + Episode3Background.png + + + + + + + 292 + {{24, 440}, {640, 158}} + + + + NO + IBIPadFramework + 0 + 0 + + + 1 + MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA + + + + NSImage + Episode4Background_Highlighted.png + + + + NSImage + Episode4Background.png + + + + + + + 292 + {{90, 473}, {141, 24}} + + + + NO + YES + 7 + NO + IBIPadFramework + #EPISODE_IV + + 1 + MC40OTQxMTc2NDc0IDAuMTkyMTU2ODY2MiAwLjAwNzg0MzEzNzcxOQA + + + 1 + MC44NzA1ODgyNDMgMC43MTM3MjU1MDczIDAuMzQ1MDk4MDQ4NAA + + 1 + 10 + + + + + + 292 + {{90, 501}, {327, 34}} + + + + NO + YES + 7 + NO + IBIPadFramework + Thy Flesh Consumed + + 1 + MC44NTg4MjM1Mzc4IDAuMzQxMTc2NDgwMSAwAA + + + 1 + MSAwLjgwMDAwMDAxMTkgMAA + + 1 + 10 + + Helvetica + Helvetica + 0 + 34 + + + Helvetica + 34 + 16 + + + + + 292 + {{90, 358}, {111, 34}} + + + + NO + YES + 7 + NO + IBIPadFramework + Inferno + + + 1 + 10 + + + + + + 292 + {{90, 332}, {140, 24}} + + + + NO + YES + 7 + NO + IBIPadFramework + #EPISODE_III + + + 1 + 10 + + + + + + 292 + {{90, 215}, {287, 30}} + + + + NO + YES + 7 + NO + IBIPadFramework + The Shores of Hell + + + 1 + 10 + + + + + + 292 + {{90, 184}, {130, 24}} + + + + NO + YES + 7 + NO + IBIPadFramework + #EPISODE_II + + + 1 + 10 + + + + + + 292 + {{90, 65}, {358, 34}} + + + + NO + YES + 7 + NO + IBIPadFramework + Knee-Deep in the Dead + + + 1 + 10 + + + + + + 292 + {{90, 38}, {123, 24}} + + + + NO + YES + 7 + NO + IBIPadFramework + #EPISODE_I + + + 1 + 10 + + + + + {{168, 80}, {688, 608}} + + + + YES + YES + IBIPadFramework + + + {1024, 768} + + + + + 1 + MCAwIDAAA + + + 3 + 3 + + IBIPadFramework + + + + + + + view + + + + 3 + + + + epi1Button + + + + 60 + + + + epi2Button + + + + 61 + + + + epi3Button + + + + 62 + + + + epi4Button + + + + 63 + + + + nextButton + + + + 64 + + + + nextLabel + + + + 65 + + + + label + + + + 59 + + + + NextToMissions + + + 7 + + 68 + + + + label + + + + 58 + + + + BackToMain + + + 7 + + 67 + + + + label + + + + 56 + + + + label2 + + + + 57 + + + + SelectEpisode4 + + + 7 + + 72 + + + + label + + + + 54 + + + + label2 + + + + 55 + + + + SelectEpisode3 + + + 7 + + 71 + + + + label + + + + 52 + + + + label2 + + + + 53 + + + + SelectEpisode2 + + + 7 + + 70 + + + + label + + + + 50 + + + + label2 + + + + 51 + + + + SelectEpisode1 + + + 7 + + 69 + + + + + + 0 + + + + + + 1 + + + + + + + + + + + + + -1 + + + File's Owner + + + -2 + + + + + 32 + + + Background + + + 33 + + + + + 34 + + + + + 35 + + + + + 36 + + + + + 37 + + + + + + + + + + + + + + + + + + + 38 + + + + + 39 + + + + + 40 + + + + + 41 + + + + + 42 + + + + + 43 + + + + + 44 + + + + + 45 + + + + + 46 + + + + + 47 + + + + + 48 + + + + + 49 + + + + + + + Doom_EpisodeMenuViewController + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + UIResponder + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + idLabelButton + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + idLabelButton + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + idLabel + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + idLabel + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + idLabel + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + idLabel + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + idLabel + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + idLabel + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + idLabel + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + idLabel + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + idLabel + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + idLabel + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + idLabelButton + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + idLabelButton + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + idLabelButton + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + idLabelButton + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + + 72 + + + + + Doom_EpisodeMenuViewController + UIViewController + + id + id + id + id + id + id + + + + BackToMain + id + + + NextToMissions + id + + + SelectEpisode1 + id + + + SelectEpisode2 + id + + + SelectEpisode3 + id + + + SelectEpisode4 + id + + + + idLabelButton + idLabelButton + idLabelButton + idLabelButton + idLabelButton + idLabel + + + + epi1Button + idLabelButton + + + epi2Button + idLabelButton + + + epi3Button + idLabelButton + + + epi4Button + idLabelButton + + + nextButton + idLabelButton + + + nextLabel + idLabel + + + + IBProjectSource + ./Classes/Doom_EpisodeMenuViewController.h + + + + idLabel + UILabel + + IBProjectSource + ./Classes/idLabel.h + + + + idLabelButton + UIButton + + idLabel + idLabel + + + + label + idLabel + + + label2 + idLabel + + + + IBProjectSource + ./Classes/idLabelButton.h + + + + + 0 + IBIPadFramework + + com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS + + + YES + 3 + + {93, 94} + {601, 150} + {601, 150} + {601, 150} + {601, 150} + {601, 150} + {601, 150} + {601, 150} + {601, 150} + {960, 640} + {93, 94} + + 933 + + diff --git a/DoomClassic/code/iphone/Info.plist b/DoomClassic/code/iphone/Info.plist new file mode 100755 index 0000000..c7e6af9 --- /dev/null +++ b/DoomClassic/code/iphone/Info.plist @@ -0,0 +1,75 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleDisplayName + DOOM + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIconFile + DOOM_57.png + CFBundleIconFiles + + DOOM_120 + DOOM_57.png + DOOM_114.png + DOOM_72.png + + CFBundleIconFiles~ipad + + DOOM_152 + DOOM_76 + DOOM_144 + DOOM_120 + DOOM_57.png + DOOM_114.png + DOOM_72.png + + CFBundleIdentifier + com.idsoftware.Doom + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 2.7 + CFBundleSignature + ???? + CFBundleVersion + 2.7 + LSRequiresIPhoneOS + + UIAppFonts + + idGinzaNar-Md2.otf + + UIInterfaceOrientation + UIInterfaceOrientationLandscapeLeft + UIPrerenderedIcon + + UIRequiredDeviceCapabilities + + gamekit + + UIRequiresPersistentWiFi + + UIStatusBarHidden + + UISupportedInterfaceOrientations + + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + + diff --git a/DoomClassic/code/iphone/LegalMenuView.xib b/DoomClassic/code/iphone/LegalMenuView.xib new file mode 100755 index 0000000..1a3e2ca --- /dev/null +++ b/DoomClassic/code/iphone/LegalMenuView.xib @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DoomClassic/code/iphone/LegalMenuViewController.h b/DoomClassic/code/iphone/LegalMenuViewController.h new file mode 100755 index 0000000..497c85a --- /dev/null +++ b/DoomClassic/code/iphone/LegalMenuViewController.h @@ -0,0 +1,35 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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. + + */ + +#import + +/* + ================================================================================================ + Doom_LegalMenuViewController + + ================================================================================================ + */ +@interface Doom_LegalMenuViewController : UIViewController { + +} + +- (IBAction) BackToMain; + +@end diff --git a/DoomClassic/code/iphone/LegalMenuViewController.mm b/DoomClassic/code/iphone/LegalMenuViewController.mm new file mode 100755 index 0000000..d7ef558 --- /dev/null +++ b/DoomClassic/code/iphone/LegalMenuViewController.mm @@ -0,0 +1,90 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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. + + */ + +#import "LegalMenuViewController.h" +#include "doomiphone.h" +#include "iphone_delegate.h" + +@implementation Doom_LegalMenuViewController + +/* + ======================== + Doom_LegalMenuViewController::initWithNibName + ======================== + */ +- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil +{ + self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; + if (self) { + // Custom initialization + } + return self; +} + +/* + ======================== + Doom_LegalMenuViewController::didReceiveMemoryWarning + ======================== + */ +- (void)didReceiveMemoryWarning +{ + // Releases the view if it doesn't have a superview. + [super didReceiveMemoryWarning]; + + // Release any cached data, images, etc that aren't in use. +} + +#pragma mark - View lifecycle + +/* + ======================== + Doom_LegalMenuViewController::viewDidLoad + ======================== + */ +- (void)viewDidLoad +{ + [super viewDidLoad]; + // Do any additional setup after loading the view from its nib. +} + +/* + ======================== + Doom_LegalMenuViewController::viewDidUnload + ======================== + */ +- (void)viewDidUnload +{ + [super viewDidUnload]; + // Release any retained subviews of the main view. + // e.g. self.myOutlet = nil; +} + +/* + ======================== + Doom_LegalMenuViewController::BackToMain + ======================== + */ +- (IBAction) BackToMain { + + [self.navigationController popViewControllerAnimated:NO]; + Sound_StartLocalSound( "iphone/controller_down_01_SILENCE.wav" ); +} + +@end diff --git a/DoomClassic/code/iphone/LegalMenuViewi5.xib b/DoomClassic/code/iphone/LegalMenuViewi5.xib new file mode 100755 index 0000000..3558ad1 --- /dev/null +++ b/DoomClassic/code/iphone/LegalMenuViewi5.xib @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DoomClassic/code/iphone/LegalMenuView~ipad.xib b/DoomClassic/code/iphone/LegalMenuView~ipad.xib new file mode 100755 index 0000000..2e8456c --- /dev/null +++ b/DoomClassic/code/iphone/LegalMenuView~ipad.xib @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DoomClassic/code/iphone/MainMenuView.xib b/DoomClassic/code/iphone/MainMenuView.xib new file mode 100755 index 0000000..68b5760 --- /dev/null +++ b/DoomClassic/code/iphone/MainMenuView.xib @@ -0,0 +1,419 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DoomClassic/code/iphone/MainMenuViewController.h b/DoomClassic/code/iphone/MainMenuViewController.h new file mode 100755 index 0000000..252627e --- /dev/null +++ b/DoomClassic/code/iphone/MainMenuViewController.h @@ -0,0 +1,84 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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. + + */ + +#import +#include "ios/LabelButton.h" + +/* + ================================================================================================ + Doom Sub Menu Banner Interface object + ================================================================================================ + */ +@interface Banner_SubItem : idLabelButton { +@public + +} +@end + +@interface Banner_SubMenu: UIView { +@public + + BOOL isHidden; +} + +- (void) Hide; +- (void) Show; + +@end + +/* + ================================================================================================ + MainMenuViewController + + ================================================================================================ +*/ +@interface Doom_MainMenuViewController : UIViewController { + + + IBOutlet idLabelButton * mPlayButton; + IBOutlet idLabelButton * mSettingsButton; + IBOutlet idLabelButton * mAboutButton; + IBOutlet idLabelButton * mExtrasButton; + + IBOutlet Banner_SubMenu * mPlaySubMenu; + IBOutlet Banner_SubMenu * mSettingsSubMenu; + IBOutlet Banner_SubMenu * mAboutSubMenu; + IBOutlet Banner_SubMenu * mExtrasSubMenu; +} + +// Sub Menu Banner Actions +- (IBAction) ShowPlayBanner; +- (IBAction) ShowSettingsBanner; +- (IBAction) ShowAboutBanner; +- (IBAction) ShowExtrasBanner; + +// Interface Builder Actions ( Connected through IB ) +- (IBAction) ResumeGamePressed; +- (IBAction) NewGamePressed; +- (IBAction) MultiplayerPressed; +- (IBAction) CreditsPressed; +- (IBAction) SupportPressed; +- (IBAction) LegalPressed; +- (IBAction) DemoPressed; +- (IBAction) OtherIdGamesPressed; +- (IBAction) ControlsOptionsPressed; +- (IBAction) SettingsOptionsPressed; + +@end diff --git a/DoomClassic/code/iphone/MainMenuViewController.mm b/DoomClassic/code/iphone/MainMenuViewController.mm new file mode 100755 index 0000000..a097b57 --- /dev/null +++ b/DoomClassic/code/iphone/MainMenuViewController.mm @@ -0,0 +1,463 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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. + + */ + +#import "MainMenuViewController.h" +#include "iphone_delegate.h" +#include "doomiphone.h" +#import "EpisodeMenuViewController.h" +#import "CreditsMenuViewController.h" +#import "SettingsMenuViewController.h" +#import "ControlsMenuViewController.h" +#import "LegalMenuViewController.h" + +/* + ================================================================================================ + Doom Sub Menu Banner Interface object + ================================================================================================ + */ + +@implementation Banner_SubItem +@end + +@implementation Banner_SubMenu + +/* + ======================== + Banner_SubMenu::awakeFromNib + ======================== + */ +- (void)awakeFromNib { + isHidden = YES; + + char full_iwad[1024]; + I_FindFile( "doom.wad", ".wad", full_iwad ); + + iphoneDoomStartup( full_iwad, NULL ); +} + +/* + ======================== + Banner_SubMenu::hitTest + ======================== + */ +- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { + UIView *hitView = [super hitTest:point withEvent:event]; + + if (hitView != self) { + return hitView; + } + + return nil; +} + +/* + ======================== + Banner_SubMenu::Hide + ======================== + */ +- (void) Hide { + + if( !isHidden ) { + + isHidden = YES; + + [UIView beginAnimations:@"Show" context:nil]; + [UIView setAnimationDuration:0.5f]; + [UIView setAnimationCurve: UIViewAnimationCurveEaseInOut]; + [UIView setAnimationBeginsFromCurrentState:NO]; + [UIView setAnimationDelegate:self]; + //[UIView setAnimationDidStopSelector:@selector(Disable)]; + + self.alpha = 1.0f; + [ self viewWithTag: 0 ].alpha = 0.0f; + + [UIView commitAnimations]; + + } +} + +/* + ======================== + Banner_SubMenu::Show + ======================== + */ +- (void) Show { + + if( isHidden ) { + + isHidden = NO; + + [UIView beginAnimations:@"Show" context:nil]; + [UIView setAnimationDuration:0.5f]; + [UIView setAnimationCurve: UIViewAnimationCurveEaseInOut]; + [UIView setAnimationBeginsFromCurrentState:NO]; + [UIView setAnimationDelegate:self]; + //[UIView setAnimationDidStopSelector:@selector(Enable)]; + + self.alpha = 1.0f; + [ self viewWithTag: 0 ].alpha = 1.0f; + + [UIView commitAnimations]; + } +} + +@end + + +/* + ================================================================================================ + MainMenuViewController + ================================================================================================ + */ +@implementation Doom_MainMenuViewController + +/* + ======================== + MainMenuViewController::initWithNibName + ======================== + */ +- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil +{ + self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; + if (self) { + + } + return self; +} + +/* + ======================== + MainMenuViewController::didReceiveMemoryWarning + ======================== + */ +- (void)didReceiveMemoryWarning +{ + // Releases the view if it doesn't have a superview. + [super didReceiveMemoryWarning]; + + // Release any cached data, images, etc that aren't in use. +} + +#pragma mark - View lifecycle + +/* + ======================== + MainMenuViewController::viewDidLoad + ======================== + */ +- (void)viewDidLoad +{ + [super viewDidLoad]; + // Do any additional setup after loading the view from its nib. +} + +/* + ======================== + MainMenuViewController::viewDidUnload + ======================== + */ +- (void)viewDidUnload +{ + [super viewDidUnload]; + // Release any retained subviews of the main view. + // e.g. self.myOutlet = nil; +} + + + +/* + ======================== + MainMenuViewController::ResumeGamePressed + ======================== + */ +- (IBAction) ResumeGamePressed { + + [ gAppDelegate ShowGLView ]; + + ResumeGame(); + + Sound_StartLocalSound( "iphone/baborted_01.wav" ); + +} + +/* + ======================== + MainMenuViewController::NewGamePressed + ======================== + */ +- (IBAction) NewGamePressed { + + // Switch to episode view menu. + Doom_EpisodeMenuViewController *vc = nil; + + if ( IS_IPHONE_5 ) { + vc = [[Doom_EpisodeMenuViewController alloc] initWithNibName:@"EpisodeMenuViewi5" bundle:nil]; + } else { + vc = [[Doom_EpisodeMenuViewController alloc] initWithNibName:@"EpisodeMenuView" bundle:nil]; + } + + + [self.navigationController pushViewController:vc animated:NO]; + [vc release]; + + Sound_StartLocalSound( "iphone/baborted_01.wav" ); + +} + +/* + ======================== + MainMenuViewController::MultiplayerPressed + ======================== + */ +- (IBAction) MultiplayerPressed { + + + //ShowMatchmaker( self, 2, 4 ); + return; + + // Go to the MP Menu. + // get the address for the local service, which may + // start up a bluetooth personal area network + //bool serverResolved = ResolveNetworkServer( &netServer.address ); + + // open our socket now that the network interfaces have been configured + // Explicitly open on interface 1, which is en0. If bluetooth ever starts + // working better, we can handle multiple interfaces. + if ( gameSocket <= 0 ) { + gameSocket = UDPSocket( "en0", DOOM_PORT ); + } + + /* + // get the address for the local service + if ( !serverResolved ) { + // nobody else is acting as a server, so start one here + RegisterGameService(); + SetupEmptyNetGame(); + } + */ + + menuState = IPM_MULTIPLAYER; + + [gAppDelegate ShowGLView]; + + Sound_StartLocalSound( "iphone/baborted_01.wav" ); + +} + +/* + ======================== + MainMenuViewController::CreditsPressed + ======================== + */ +- (IBAction) CreditsPressed { + + Doom_CreditsMenuViewController *vc = nil; + + if ( IS_IPHONE_5 ) { + vc = [[Doom_CreditsMenuViewController alloc] initWithNibName:@"CreditsMenuViewi5" bundle:nil]; + } else { + vc = [[Doom_CreditsMenuViewController alloc] initWithNibName:@"CreditsMenuView" bundle:nil]; + } + + [self.navigationController pushViewController:vc animated:NO]; + [vc release]; + + Sound_StartLocalSound( "iphone/baborted_01.wav" ); +} + +/* + ======================== + MainMenuViewController::SupportPressed + ======================== + */ +- (IBAction) SupportPressed { + + SysIPhoneOpenURL("http://www.idsoftware.com/doom-classic/index.html"); + + Sound_StartLocalSound( "iphone/baborted_01.wav" ); +} + +/* + ======================== + MainMenuViewController::LegalPressed + ======================== + */ +- (IBAction) LegalPressed { + + Doom_LegalMenuViewController *vc = nil; + + if ( IS_IPHONE_5 ) { + vc = [[Doom_LegalMenuViewController alloc] initWithNibName:@"LegalMenuViewi5" bundle:nil]; + } else { + vc = [[Doom_LegalMenuViewController alloc] initWithNibName:@"LegalMenuView" bundle:nil]; + } + + + [self.navigationController pushViewController:vc animated:NO]; + [vc release]; + + Sound_StartLocalSound( "iphone/baborted_01.wav" ); +} + +/* + ======================== + MainMenuViewController::DemoPressed + ======================== + */ +- (IBAction) DemoPressed { + + StartDemoGame( false ); + + [gAppDelegate ShowGLView]; + + Sound_StartLocalSound( "iphone/baborted_01.wav" ); +} + +/* + ======================== + MainMenuViewController::OtherIdGamesPressed + ======================== + */ +- (IBAction) OtherIdGamesPressed { + + SysIPhoneOpenURL("http://itunes.com/apps/idsoftware"); + + Sound_StartLocalSound( "iphone/baborted_01.wav" ); +} + +/* + ======================== + MainMenuViewController::ControlsOptionsPressed + ======================== + */ +- (IBAction) ControlsOptionsPressed { + + Doom_ControlsMenuViewController *vc = nil; + + if ( IS_IPHONE_5 ) { + vc = [[Doom_ControlsMenuViewController alloc] initWithNibName:@"ControlsMenuViewi5" bundle:nil]; + } else { + vc = [[Doom_ControlsMenuViewController alloc] initWithNibName:@"ControlsMenuView" bundle:nil]; + } + + [self.navigationController pushViewController:vc animated:NO]; + [vc release]; + + Sound_StartLocalSound( "iphone/baborted_01.wav" ); + +} + +/* + ======================== + MainMenuViewController::SettingsOptionsPressed + ======================== + */ +- (IBAction) SettingsOptionsPressed { + + + Doom_SettingsMenuViewController *vc = nil; + + if ( IS_IPHONE_5 ) { + vc = [[Doom_SettingsMenuViewController alloc] initWithNibName:@"SettingsMenuViewi5" bundle:nil]; + } else { + vc = [[Doom_SettingsMenuViewController alloc] initWithNibName:@"SettingsMenuView" bundle:nil]; + } + + [self.navigationController pushViewController:vc animated:NO]; + [vc release]; + + Sound_StartLocalSound( "iphone/baborted_01.wav" ); +} + +/* + ======================== + MainMenuViewController::ShowPlayBanner + ======================== + */ +- (void) ShowPlayBanner { + + [ mPlayButton setEnabled: NO ]; + [ mSettingsButton setEnabled: YES ]; + [ mAboutButton setEnabled: YES ]; + [ mExtrasButton setEnabled: YES ]; + + [ mPlaySubMenu Show ]; + [ mSettingsSubMenu Hide ]; + [ mExtrasSubMenu Hide ]; + [ mAboutSubMenu Hide ]; + +} + +/* + ======================== + MainMenuViewController::ShowSettingsBanner + ======================== + */ +- (void) ShowSettingsBanner { + + [ mPlayButton setEnabled: YES ]; + [ mSettingsButton setEnabled: NO ]; + [ mAboutButton setEnabled: YES ]; + [ mExtrasButton setEnabled: YES ]; + + [ mSettingsSubMenu Show ]; + [ mPlaySubMenu Hide ]; + [ mExtrasSubMenu Hide ]; + [ mAboutSubMenu Hide ]; +} + +/* + ======================== + MainMenuViewController::ShowAboutBanner + ======================== + */ +- (void) ShowAboutBanner { + + [ mPlayButton setEnabled: YES ]; + [ mSettingsButton setEnabled: YES ]; + [ mAboutButton setEnabled: NO ]; + [ mExtrasButton setEnabled: YES ]; + + [ mAboutSubMenu Show ]; + [ mPlaySubMenu Hide ]; + [ mSettingsSubMenu Hide ]; + [ mExtrasSubMenu Hide ]; +} + +/* + ======================== + MainMenuViewController::ShowExtrasBanner + ======================== + */ +- (void) ShowExtrasBanner { + + [ mPlayButton setEnabled: YES ]; + [ mSettingsButton setEnabled: YES ]; + [ mAboutButton setEnabled: YES ]; + [ mExtrasButton setEnabled: NO ]; + + [ mExtrasSubMenu Show ]; + [ mPlaySubMenu Hide ]; + [ mSettingsSubMenu Hide ]; + [ mAboutSubMenu Hide ]; +} + + +@end diff --git a/DoomClassic/code/iphone/MainMenuViewi5.xib b/DoomClassic/code/iphone/MainMenuViewi5.xib new file mode 100755 index 0000000..21ac1d7 --- /dev/null +++ b/DoomClassic/code/iphone/MainMenuViewi5.xib @@ -0,0 +1,419 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DoomClassic/code/iphone/MainMenuView~ipad.xib b/DoomClassic/code/iphone/MainMenuView~ipad.xib new file mode 100755 index 0000000..12d481a --- /dev/null +++ b/DoomClassic/code/iphone/MainMenuView~ipad.xib @@ -0,0 +1,419 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DoomClassic/code/iphone/MainNavController.h b/DoomClassic/code/iphone/MainNavController.h new file mode 100644 index 0000000..25cbc8a --- /dev/null +++ b/DoomClassic/code/iphone/MainNavController.h @@ -0,0 +1,25 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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. + + */ + +#import + +@interface MainNavController : UINavigationController + +@end diff --git a/DoomClassic/code/iphone/MainNavController.m b/DoomClassic/code/iphone/MainNavController.m new file mode 100644 index 0000000..d18cc55 --- /dev/null +++ b/DoomClassic/code/iphone/MainNavController.m @@ -0,0 +1,50 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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. + + */ + +#import "MainNavController.h" + +@interface MainNavController () + +@end + +@implementation MainNavController + +- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil +{ + self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; + if (self) { + // Custom initialization + } + return self; +} + +- (void)viewDidLoad +{ + [super viewDidLoad]; + // Do any additional setup after loading the view. +} + +- (void)didReceiveMemoryWarning +{ + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +@end diff --git a/DoomClassic/code/iphone/MissionMenuView.xib b/DoomClassic/code/iphone/MissionMenuView.xib new file mode 100755 index 0000000..6c93489 --- /dev/null +++ b/DoomClassic/code/iphone/MissionMenuView.xib @@ -0,0 +1,980 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DoomClassic/code/iphone/MissionMenuViewController.h b/DoomClassic/code/iphone/MissionMenuViewController.h new file mode 100755 index 0000000..77e5691 --- /dev/null +++ b/DoomClassic/code/iphone/MissionMenuViewController.h @@ -0,0 +1,124 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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. + + */ + +#import +#import "ios/Label.h" +#import "ios/LabelButton.h" +/* + ================================================================================================ + Doom_MissionMenuViewController + + ================================================================================================ + */ +@interface Doom_MissionMenuViewController : UIViewController { + + IBOutlet UIScrollView * mapScroller1; + IBOutlet UIScrollView * mapScroller2; + IBOutlet UIScrollView * mapScroller3; + IBOutlet UIScrollView * mapScroller4; + + IBOutlet UIButton * lastElement1; + IBOutlet UIButton * lastElement2; + IBOutlet UIButton * lastElement3; + IBOutlet UIButton * lastElement4; + + + IBOutlet UIImageView * easySelection; + IBOutlet UIImageView * mediumSelection; + IBOutlet UIImageView * hardSelection; + IBOutlet UIImageView * NightmareSelection; + + UIScrollView * selectedScroller; + + IBOutlet idLabel * easySelectionLabel; + IBOutlet idLabel * mediumSelectionLabel; + IBOutlet idLabel * hardSelectionLabel; + IBOutlet idLabel * nightmareSelectionLabel; + + IBOutlet idLabelButton * playButton; + IBOutlet idLabel * playLabel; + + idLabelButton * selectedMap; + int episodeSelected; + int mapSelected; +} + +- (int) getSkill; +- (void) playMap:(int)dataset + :(int)episode + :(int)map; + +- (void) setEpisode: (int) episode; + +-(IBAction) BackPressed; +-(IBAction) Play; + +-(IBAction) UpMission; +-(IBAction) DownMission; + +// Difficulty Setting +-(IBAction) EasyPressed; +-(IBAction) MediumPressed; +-(IBAction) HardPressed; +-(IBAction) NightmarePressed; + + +// DOOM EPISODES +-(IBAction) E1M1; +-(IBAction) E1M2; +-(IBAction) E1M3; +-(IBAction) E1M4; +-(IBAction) E1M5; +-(IBAction) E1M6; +-(IBAction) E1M7; +-(IBAction) E1M8; +-(IBAction) E1M9; + +-(IBAction) E2M1; +-(IBAction) E2M2; +-(IBAction) E2M3; +-(IBAction) E2M4; +-(IBAction) E2M5; +-(IBAction) E2M6; +-(IBAction) E2M7; +-(IBAction) E2M8; +-(IBAction) E2M9; + +-(IBAction) E3M1; +-(IBAction) E3M2; +-(IBAction) E3M3; +-(IBAction) E3M4; +-(IBAction) E3M5; +-(IBAction) E3M6; +-(IBAction) E3M7; +-(IBAction) E3M8; +-(IBAction) E3M9; + +-(IBAction) E4M1; +-(IBAction) E4M2; +-(IBAction) E4M3; +-(IBAction) E4M4; +-(IBAction) E4M5; +-(IBAction) E4M6; +-(IBAction) E4M7; +-(IBAction) E4M8; +-(IBAction) E4M9; + +@end diff --git a/DoomClassic/code/iphone/MissionMenuViewController.mm b/DoomClassic/code/iphone/MissionMenuViewController.mm new file mode 100755 index 0000000..daae094 --- /dev/null +++ b/DoomClassic/code/iphone/MissionMenuViewController.mm @@ -0,0 +1,468 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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. + + */ + +#import "MissionMenuViewController.h" +#include "doomiphone.h" +#include "iphone_delegate.h" + +/* + ================================================================================================ + Doom_MissionMenuViewController + + ================================================================================================ + */ +@implementation Doom_MissionMenuViewController + +/* + ======================== + Doom_MissionMenuViewController::initWithNibName + ======================== + */ +- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil +{ + self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; + if (self) { + // Custom initialization + } + return self; +} + +/* + ======================== + Doom_MissionMenuViewController::didReceiveMemoryWarning + ======================== + */ +- (void)didReceiveMemoryWarning +{ + // Releases the view if it doesn't have a superview. + [super didReceiveMemoryWarning]; + + // Release any cached data, images, etc that aren't in use. +} + +#pragma mark - View lifecycle + +/* + ======================== + Doom_MissionMenuViewController::viewDidLoad + ======================== + */ +- (void)viewDidLoad +{ + [super viewDidLoad]; + + [mapScroller1 setContentSize:CGSizeMake( + mapScroller1.bounds.size.width, + CGRectGetMaxY(lastElement1.frame) + )]; + + [mapScroller2 setContentSize:CGSizeMake( + mapScroller2.bounds.size.width, + CGRectGetMaxY(lastElement2.frame) + )]; + + [mapScroller3 setContentSize:CGSizeMake( + mapScroller3.bounds.size.width, + CGRectGetMaxY(lastElement3.frame) + )]; + + [mapScroller4 setContentSize:CGSizeMake( + mapScroller4.bounds.size.width, + CGRectGetMaxY(lastElement4.frame) + )]; + + [ playButton setEnabled: NO ]; + [ playLabel setEnabled: NO ]; + + selectedMap = nil; + mapSelected = -1; + + easySelection.hidden = NO; + easySelectionLabel.hidden = NO; + mediumSelection.hidden = YES; + mediumSelectionLabel.hidden = YES; + hardSelection.hidden = YES; + hardSelectionLabel.hidden = YES; + NightmareSelection.hidden = YES; + nightmareSelectionLabel.hidden = YES; + + mapScroller1.alpha = 0.0f; + mapScroller2.alpha = 0.0f; + mapScroller3.alpha = 0.0f; + mapScroller4.alpha = 0.0f; + + + switch( episodeSelected ) { + + case 0: + selectedScroller = mapScroller1; + break; + case 1: + selectedScroller = mapScroller2; + break; + case 2: + selectedScroller = mapScroller3; + break; + case 3: + selectedScroller = mapScroller4; + break; + + }; + + selectedScroller.alpha = 1.0f; +} + +/* + ======================== + Doom_MissionMenuViewController::viewDidUnload + ======================== + */ +- (void)viewDidUnload +{ + [super viewDidUnload]; + // Release any retained subviews of the main view. + // e.g. self.myOutlet = nil; +} + +/* + ======================== + Doom_MissionMenuViewController::setEpisode + ======================== + */ +- (void) setEpisode: (int) episode { + + episodeSelected = episode; +} + +/* + ======================== + Doom_MissionMenuViewController::BackPressed + ======================== + */ +-(IBAction) BackPressed { + + [self.navigationController popViewControllerAnimated:NO]; + + Sound_StartLocalSound( "iphone/controller_down_01_SILENCE.wav" ); + +} + +/* + ======================== + Doom_MissionMenuViewController::getSkill + ======================== + */ +- (int) getSkill { + + if( easySelection.hidden == NO ) { + return 0; + } else if( mediumSelection.hidden == NO ) { + return 1; + } else if( hardSelection.hidden == NO ) { + return 2; + } else if( NightmareSelection.hidden == NO ) { + return 3; + } + + return 0; +} + +/* + ======================== + Doom_MissionMenuViewController::UpMission + ======================== + */ +-(IBAction) UpMission { + + CGFloat xOffset = selectedScroller.contentOffset.x; + CGFloat yOffset = selectedScroller.contentOffset.y; + + if (selectedScroller.contentOffset.y > 10 ) + { + [selectedScroller setContentOffset:CGPointMake(xOffset, yOffset - 50 ) animated:YES]; + } +} + +/* + ======================== + Doom_MissionMenuViewController::DownMission + ======================== + */ +-(IBAction) DownMission { + + CGFloat xOffset = selectedScroller.contentOffset.x; + CGFloat yOffset = selectedScroller.contentOffset.y; + + if (selectedScroller.contentOffset.y < 300 ) + { + [selectedScroller setContentOffset:CGPointMake(xOffset, yOffset + 50 ) animated:YES]; + } + +} + +/* + ======================== + Doom_MissionMenuViewController::Play + ======================== + */ +-(IBAction) Play { + + int skillLevel = [self getSkill]; + mapStart_t localStartmap; + + localStartmap.map = mapSelected; + localStartmap.episode = episodeSelected; + localStartmap.dataset = 0; + localStartmap.skill = skillLevel; + + StartSinglePlayerGame( localStartmap ); + + [ gAppDelegate ShowGLView ]; +} + +/* + ======================== + Doom_MissionMenuViewController::playMap + ======================== + */ +- (void) playMap:(int)dataset + :(int)episode + :(int) map { + + (void)dataset; + + [ playButton setEnabled: YES ]; + [ playLabel setEnabled: YES ]; + + if( selectedMap != nil ) { + [ selectedMap setEnabled: YES ]; + } + episodeSelected = episode; + mapSelected = map; + + int mapTag = episode * 10 + ( map - 1 ); + selectedMap = (idLabelButton *)[ self.view viewWithTag: mapTag ]; + + [selectedMap setEnabled: NO]; + + Sound_StartLocalSound( "iphone/controller_down_01_SILENCE.wav" ); +} + +/* + ======================== + Doom_MissionMenuViewController::EasyPressed + ======================== + */ +-(IBAction) EasyPressed { + + easySelection.hidden = NO; + easySelectionLabel.hidden = NO; + mediumSelection.hidden = YES; + mediumSelectionLabel.hidden = YES; + hardSelection.hidden = YES; + hardSelectionLabel.hidden = YES; + NightmareSelection.hidden = YES; + nightmareSelectionLabel.hidden = YES; + + Sound_StartLocalSound( "iphone/controller_down_01_SILENCE.wav" ); +} + +/* + ======================== + Doom_MissionMenuViewController::MediumPressed + ======================== + */ +-(IBAction) MediumPressed { + + easySelection.hidden = YES; + mediumSelection.hidden = NO; + hardSelection.hidden = YES; + NightmareSelection.hidden = YES; + + easySelectionLabel.hidden = YES; + mediumSelectionLabel.hidden = NO; + hardSelectionLabel.hidden = YES; + nightmareSelectionLabel.hidden = YES; + + Sound_StartLocalSound( "iphone/controller_down_01_SILENCE.wav" ); + +} + +/* + ======================== + Doom_MissionMenuViewController::HardPressed + ======================== + */ +-(IBAction) HardPressed { + + easySelection.hidden = YES; + mediumSelection.hidden = YES; + hardSelection.hidden = NO; + NightmareSelection.hidden = YES; + + easySelectionLabel.hidden = YES; + mediumSelectionLabel.hidden = YES; + hardSelectionLabel.hidden = NO; + nightmareSelectionLabel.hidden = YES; + + Sound_StartLocalSound( "iphone/controller_down_01_SILENCE.wav" ); + +} + +/* + ======================== + Doom_MissionMenuViewController::NightmarePressed + ======================== + */ +-(IBAction) NightmarePressed{ + + easySelection.hidden = YES; + mediumSelection.hidden = YES; + hardSelection.hidden = YES; + NightmareSelection.hidden = NO; + + easySelectionLabel.hidden = YES; + mediumSelectionLabel.hidden = YES; + hardSelectionLabel.hidden = YES; + nightmareSelectionLabel.hidden = NO; + + Sound_StartLocalSound( "iphone/controller_down_01_SILENCE.wav" ); +} + + +/* + ======================== + Doom_MissionMenuViewController DOOM EPISODES + ======================== + */ +-(IBAction) E1M1 { + [ self playMap: 0: 1: 1 ]; +} +-(IBAction) E1M2{ + [ self playMap: 0: 1: 2 ]; +} +-(IBAction) E1M3{ + [ self playMap: 0: 1: 3 ]; +} +-(IBAction) E1M4{ + [ self playMap: 0: 1: 4 ]; +} +-(IBAction) E1M5{ + [ self playMap: 0: 1: 5 ]; +} +-(IBAction) E1M6{ + [ self playMap: 0: 1: 6 ]; +} +-(IBAction) E1M7{ + [ self playMap: 0: 1: 7 ]; +} +-(IBAction) E1M8{ + [ self playMap: 0: 1: 8 ]; +} +-(IBAction) E1M9{ + [ self playMap: 0: 1: 9 ]; +} + +-(IBAction) E2M1{ + [ self playMap: 0: 2: 1 ]; +} +-(IBAction) E2M2{ + [ self playMap: 0: 2: 2 ]; +} +-(IBAction) E2M3{ + [ self playMap: 0: 2: 3 ]; +} +-(IBAction) E2M4{ + [ self playMap: 0: 2: 4 ]; +} +-(IBAction) E2M5{ + [ self playMap: 0: 2: 5 ]; +} +-(IBAction) E2M6{ + [ self playMap: 0: 2: 6 ]; +} +-(IBAction) E2M7{ + [ self playMap: 0: 2: 7 ]; +} +-(IBAction) E2M8{ + [ self playMap: 0: 2: 8 ]; +} +-(IBAction) E2M9{ + [ self playMap: 0: 2: 9 ]; +} + +-(IBAction) E3M1{ + [ self playMap: 0: 3: 1 ]; +} +-(IBAction) E3M2{ + [ self playMap: 0: 3: 2 ]; +} +-(IBAction) E3M3{ + [ self playMap: 0: 3: 3 ]; +} +-(IBAction) E3M4{ + [ self playMap: 0: 3: 4 ]; +} +-(IBAction) E3M5{ + [ self playMap: 0: 3: 5 ]; +} +-(IBAction) E3M6{ + [ self playMap: 0: 3: 6 ]; +} +-(IBAction) E3M7 { + [ self playMap: 0: 3: 7 ]; +} +-(IBAction) E3M8{ + [ self playMap: 0: 3: 8 ]; +} +-(IBAction) E3M9{ + [ self playMap: 0: 3: 9 ]; +} + +-(IBAction) E4M1{ + [ self playMap: 0: 4: 1 ]; +} +-(IBAction) E4M2{ + [ self playMap: 0: 4: 2 ]; +} +-(IBAction) E4M3{ + [ self playMap: 0: 4: 3 ]; +} +-(IBAction) E4M4{ + [ self playMap: 0: 4: 4 ]; +} +-(IBAction) E4M5{ + [ self playMap: 0: 4: 5 ]; +} +-(IBAction) E4M6{ + [ self playMap: 0: 4: 6 ]; +} +-(IBAction) E4M7{ + [ self playMap: 0: 4: 7 ]; +} +-(IBAction) E4M8{ + [ self playMap: 0: 4: 8 ]; +} +-(IBAction) E4M9{ + [ self playMap: 0: 4: 9 ]; +} + + +@end diff --git a/DoomClassic/code/iphone/MissionMenuViewi5.xib b/DoomClassic/code/iphone/MissionMenuViewi5.xib new file mode 100755 index 0000000..0ceb963 --- /dev/null +++ b/DoomClassic/code/iphone/MissionMenuViewi5.xib @@ -0,0 +1,977 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DoomClassic/code/iphone/MissionMenuView~ipad.xib b/DoomClassic/code/iphone/MissionMenuView~ipad.xib new file mode 100755 index 0000000..f3f6c62 --- /dev/null +++ b/DoomClassic/code/iphone/MissionMenuView~ipad.xib @@ -0,0 +1,980 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DoomClassic/code/iphone/OpenGLView.xib b/DoomClassic/code/iphone/OpenGLView.xib new file mode 100755 index 0000000..9d7dfe5 --- /dev/null +++ b/DoomClassic/code/iphone/OpenGLView.xib @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DoomClassic/code/iphone/OpenGLViewi5.xib b/DoomClassic/code/iphone/OpenGLViewi5.xib new file mode 100755 index 0000000..9d7dfe5 --- /dev/null +++ b/DoomClassic/code/iphone/OpenGLViewi5.xib @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DoomClassic/code/iphone/OpenGLView~ipad.xib b/DoomClassic/code/iphone/OpenGLView~ipad.xib new file mode 100755 index 0000000..84d8295 --- /dev/null +++ b/DoomClassic/code/iphone/OpenGLView~ipad.xib @@ -0,0 +1,149 @@ + + + + 1280 + 11C74 + 1938 + 1138.23 + 567.00 + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + 933 + + + IBProxyObject + IBUIView + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + PluginDependencyRecalculationVersion + + + + + IBFilesOwner + IBIPadFramework + + + IBFirstResponder + IBIPadFramework + + + + 274 + {1024, 768} + + + + 3 + MQA + + 2 + + + + 3 + 3 + + IBIPadFramework + + + + + + + view + + + + 3 + + + + + + 0 + + + + + + 1 + + + + + -1 + + + File's Owner + + + -2 + + + + + + + iphone_glViewController + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + UIResponder + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + EAGLView + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + + 3 + + + + + CADisplayLink + NSObject + + IBProjectSource + ./Classes/CADisplayLink.h + + + + EAGLView + UIView + + IBProjectSource + ./Classes/EAGLView.h + + + + iphone_glViewController + UIViewController + + displayLink + CADisplayLink + + + displayLink + + displayLink + CADisplayLink + + + + IBProjectSource + ./Classes/iphone_glViewController.h + + + + + 0 + IBIPadFramework + YES + 3 + 933 + + diff --git a/DoomClassic/code/iphone/SettingsMenuView.xib b/DoomClassic/code/iphone/SettingsMenuView.xib new file mode 100755 index 0000000..9956fa7 --- /dev/null +++ b/DoomClassic/code/iphone/SettingsMenuView.xib @@ -0,0 +1,300 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DoomClassic/code/iphone/SettingsMenuViewController.h b/DoomClassic/code/iphone/SettingsMenuViewController.h new file mode 100755 index 0000000..f563940 --- /dev/null +++ b/DoomClassic/code/iphone/SettingsMenuViewController.h @@ -0,0 +1,56 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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. + + */ + +#import +#import "ios/switch.h" + +/* + ================================================================================================ + Doom_SettingsMenuViewController + + ================================================================================================ + */ +@interface Doom_SettingsMenuViewController : UIViewController { + + + IBOutlet idSwitch * autoUseSwitch; + IBOutlet idSwitch * statusbarSwitch; + IBOutlet idSwitch * touchclickSwitch; + IBOutlet idSwitch * textMessageSwitch; + IBOutlet idSwitch * drawControlsSwitch; + IBOutlet idSwitch * musicSwitch; + IBOutlet idSwitch * centerSticksSwitch; + IBOutlet idSwitch * rampTurnSwitch; + + +} + +- (IBAction) BackToMain; +- (IBAction) ResetToDefaults; +- (IBAction) AutoUseChanged; +- (IBAction) StatusBarChanged; +- (IBAction) TouchClickChanged; +- (IBAction) TextMessagesChanged; +- (IBAction) DrawControlsChanged; +- (IBAction) MusicChanged; +- (IBAction) CenterSticksChanged; +- (IBAction) RampTurnChanged; + +@end diff --git a/DoomClassic/code/iphone/SettingsMenuViewController.mm b/DoomClassic/code/iphone/SettingsMenuViewController.mm new file mode 100755 index 0000000..aa23ae4 --- /dev/null +++ b/DoomClassic/code/iphone/SettingsMenuViewController.mm @@ -0,0 +1,216 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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. + + */ +#import "SettingsMenuViewController.h" +#include "doomiphone.h" +#include "iphone_delegate.h" + +/* + ================================================================================================ + Doom_SettingsMenuViewController + + ================================================================================================ + */ +@implementation Doom_SettingsMenuViewController + +/* + ======================== + Doom_SettingsMenuViewController::initWithNibName + ======================== + */ +- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil +{ + self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; + if (self) { + // Custom initialization + } + return self; +} + +/* + ======================== + Doom_SettingsMenuViewController::didReceiveMemoryWarning + ======================== + */ +- (void)didReceiveMemoryWarning +{ + // Releases the view if it doesn't have a superview. + [super didReceiveMemoryWarning]; + + // Release any cached data, images, etc that aren't in use. +} + +#pragma mark - View lifecycle + +/* + ======================== + Doom_SettingsMenuViewController::viewDidLoad + ======================== + */ +- (void)viewDidLoad +{ + [super viewDidLoad]; + + [ autoUseSwitch setOn: (BOOL)autoUse->value ]; + [ statusbarSwitch setOn: (BOOL)statusBar->value ]; + [ touchclickSwitch setOn: (BOOL)touchClick->value ]; + [ textMessageSwitch setOn: (BOOL)messages->value ]; + [ drawControlsSwitch setOn: (BOOL)drawControls->value ]; + [ musicSwitch setOn: (BOOL)music->value ]; + [ centerSticksSwitch setOn: (BOOL)centerSticks->value ]; + [ rampTurnSwitch setOn: (BOOL)rampTurn->value ]; +} + +/* + ======================== + Doom_SettingsMenuViewController::viewDidUnload + ======================== + */ +- (void)viewDidUnload +{ + [super viewDidUnload]; + // Release any retained subviews of the main view. + // e.g. self.myOutlet = nil; +} + +/* + ======================== + Doom_SettingsMenuViewController::BackToMain + ======================== + */ +- (IBAction) BackToMain { + [self.navigationController popViewControllerAnimated:NO]; + Sound_StartLocalSound( "iphone/controller_down_01_SILENCE.wav" ); +} + +/* + ======================== + Doom_SettingsMenuViewController::ResetToDefaults + ======================== + */ +- (IBAction) ResetToDefaults { + + // reset all cvars + Cvar_Reset_f(); + HudSetForScheme(0); + iphoneStartMusic(); + + mus_on = true; + mus_pause_opt = 1; + S_ResumeSound(); + + Sound_StartLocalSound( "iphone/controller_down_01_SILENCE.wav" ); + + [ autoUseSwitch setOn: (BOOL)autoUse->value ]; + [ statusbarSwitch setOn: (BOOL)statusBar->value ]; + [ touchclickSwitch setOn: (BOOL)touchClick->value ]; + [ textMessageSwitch setOn: (BOOL)messages->value ]; + [ drawControlsSwitch setOn: (BOOL)drawControls->value ]; + [ musicSwitch setOn: (BOOL)music->value ]; + [ centerSticksSwitch setOn: (BOOL)centerSticks->value ]; + [ rampTurnSwitch setOn: (BOOL)rampTurn->value ]; +} + +/* + ======================== + Doom_SettingsMenuViewController::AutoUseChanged + ======================== + */ +- (IBAction) AutoUseChanged { + Cvar_SetValue( autoUse->name, !autoUse->value ); +} + +/* + ======================== + Doom_SettingsMenuViewController::StatusBarChanged + ======================== + */ +- (IBAction) StatusBarChanged { + Cvar_SetValue( statusBar->name, !statusBar->value ); +} + +/* + ======================== + Doom_SettingsMenuViewController::TouchClickChanged + ======================== + */ +- (IBAction) TouchClickChanged { + Cvar_SetValue( touchClick->name, !touchClick->value ); +} + +/* + ======================== + Doom_SettingsMenuViewController::TextMessagesChanged + ======================== + */ +- (IBAction) TextMessagesChanged { + Cvar_SetValue( messages->name, !messages->value ); +} + +/* + ======================== + Doom_SettingsMenuViewController::DrawControlsChanged + ======================== + */ +- (IBAction) DrawControlsChanged { + Cvar_SetValue( drawControls->name, !drawControls->value ); +} +extern int mus_pause_opt; // From m_misc.c +extern bool mus_on; + +/* + ======================== + Doom_SettingsMenuViewController::MusicChanged + ======================== + */ +- (IBAction) MusicChanged { + if ( !SysIPhoneOtherAudioIsPlaying() ) { + Cvar_SetValue( music->name, !music->value ); + if ( music->value ) { + mus_on = true; + mus_pause_opt = 1; + S_ResumeSound(); + } else { + mus_on = false; + mus_pause_opt = 1; + S_PauseSound(); + } + } + +} + +/* + ======================== + Doom_SettingsMenuViewController::CenterSticksChanged + ======================== + */ +- (IBAction) CenterSticksChanged { + Cvar_SetValue( centerSticks->name, !centerSticks->value ); +} + +/* + ======================== + Doom_SettingsMenuViewController::RampTurnChanged + ======================== + */ +- (IBAction) RampTurnChanged { + Cvar_SetValue( rampTurn->name, !rampTurn->value ); +} + +@end diff --git a/DoomClassic/code/iphone/SettingsMenuViewi5.xib b/DoomClassic/code/iphone/SettingsMenuViewi5.xib new file mode 100755 index 0000000..3b799b6 --- /dev/null +++ b/DoomClassic/code/iphone/SettingsMenuViewi5.xib @@ -0,0 +1,300 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DoomClassic/code/iphone/SettingsMenuView~ipad.xib b/DoomClassic/code/iphone/SettingsMenuView~ipad.xib new file mode 100755 index 0000000..f6eab10 --- /dev/null +++ b/DoomClassic/code/iphone/SettingsMenuView~ipad.xib @@ -0,0 +1,299 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DoomClassic/code/iphone/dist.plist b/DoomClassic/code/iphone/dist.plist new file mode 100755 index 0000000..ce373e1 --- /dev/null +++ b/DoomClassic/code/iphone/dist.plist @@ -0,0 +1,8 @@ + + + + + get-task-allow + + + diff --git a/DoomClassic/code/iphone/doom_Prefix.pch b/DoomClassic/code/iphone/doom_Prefix.pch new file mode 100755 index 0000000..2cd5422 --- /dev/null +++ b/DoomClassic/code/iphone/doom_Prefix.pch @@ -0,0 +1,28 @@ +/* + + Copyright (C) 2009 Id Software, 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 + 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. + + */ + +// +// Prefix header for all source files of the 'doom' target in the 'doom' project +// + +#ifdef __OBJC__ +#import +#import +#endif diff --git a/DoomClassic/code/iphone/doom_wads.cpp b/DoomClassic/code/iphone/doom_wads.cpp new file mode 100755 index 0000000..3ad2207 --- /dev/null +++ b/DoomClassic/code/iphone/doom_wads.cpp @@ -0,0 +1,186 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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 "doom_wads.h" +#include "stdio.h" +#include "iphone_doom.h" +#include "prboom/i_system.h" + +iphoneMissionPack_t iphoneMissionPack = MISSION_NONE; +int iphoneMasterLevel = 1; + + +/* + ================== + iphoneFindIWADFile + + Returns the IWAD to load for the selected mission pack. String MUST be freed by caller :( + ================== + */ + +static const char * MasterLevels_WADS[] = { + "ATTACK.WAD", + "CANYON.WAD" , + "CATWALK.WAD" , + "COMBINE.WAD" , + "FISTULA.WAD" , + "GARRISON.WAD", + "MANOR.WAD" , + "PARADOX.WAD", + "SUBSPACE.WAD", + "SUBTERRA.WAD" , + "TTRAP.WAD" , + "VIRGIL.WAD" , + "MINOS.WAD" , + "BLOODSEA.WAD", + "MEPHISTO.WAD", + "NESSUS.WAD" , + "GERYON.WAD" , + "VESPERAS.WAD", + "BLACKTWR.WAD" , + "TEETH.WAD", + "TEETH.WAD", +}; + +void iphoneFindIWADFile( iphoneMissionPack_t mission, char * returnFileName ) { + + switch ( mission ) { + case MISSION_HELL_ON_EARTH: + sprintf( returnFileName, "doom2.wad" ); + return; + + case MISSION_PLUTONIA: + sprintf( returnFileName, "plutonia.wad" ); + return; + + case MISSION_TNT_EVILUTION: + sprintf( returnFileName, "tnt.wad" ); + return; + + case MISSION_NO_REST_FOR_THE_LIVING: + sprintf( returnFileName, "doom2.wad" ); + return; + + case MISSION_MASTER_LEVELS: + sprintf( returnFileName, "doom2.wad" ); + return; + + default: + sprintf( returnFileName, "doom2.wad" );; + } +} + +/* + ================== + iphoneFindPWADFile + + Returns the name of the pwad that needs to be loaded for the user's selected mission. + ================== + */ +void iphoneFindPWADFile( iphoneMissionPack_t mission, char * returnFileName ) { + + switch ( mission ) { + case MISSION_NO_REST_FOR_THE_LIVING: { + sprintf( returnFileName, "nerve.wad" ); + return; + break; + } + case MISSION_MASTER_LEVELS: { + sprintf( returnFileName, "%s", MasterLevels_WADS[ iphoneMasterLevel ] ); + return; + break; + } + default: + break; + } + + returnFileName[0] = '\0'; +} + +/* +================== +GetNumberOfMapsInExpansion + +Returns the total number of maps contained in an expansion dataset. +================== +*/ +int GetNumberOfMapsInExpansion( iphoneMissionPack_t expansion ) { + switch( expansion ) { + case MISSION_HELL_ON_EARTH: { + return TOTAL_HOE_MISSIONS; + } + + case MISSION_ULTIMATE_DOOM: { + return TOTAL_PLUT_MISSIONS; + } + + case MISSION_NONE: { + return 0; + } + + case MISSION_MASTER_LEVELS: { + return TOTAL_MAST_MISSIONS; + } + + case MISSION_TNT_EVILUTION: { + return TOTAL_TNT_MISSIONS; + } + + case MISSION_NO_REST_FOR_THE_LIVING: { + return TOTAL_NOREST_MISSIONS; + } + + case MISSION_PLUTONIA: { + return TOTAL_PLUT_MISSIONS; + } + }; + + return 0; +} + + +/* + ======================= + StartupWithIWADandPWAD + ======================= + */ +void StartupWithCorrectWads( int mission ) { + // Look for the iwad file corresponding to the current mission. + char iwad[ 1024 ]; + char expansion[ 1024 ]; + iphoneFindIWADFile( static_cast(mission), expansion ); + I_FindFile( expansion, ".wad", iwad ); + + // Look for the pwad corresponding to the current mission. Will be NULL if we don't + // need a pwad for the mission. + char mission_pwad[ 1024 ]; + iphoneFindPWADFile( static_cast(mission), mission_pwad ); + + char full_pwad[ 1024 ]; + + if ( mission_pwad[0] != '\0' ) { + I_FindFile( mission_pwad, ".wad", full_pwad ); + iphoneDoomStartup( iwad, full_pwad ); + } else { + iphoneDoomStartup( iwad, NULL ); + } +} diff --git a/DoomClassic/code/iphone/doom_wads.h b/DoomClassic/code/iphone/doom_wads.h new file mode 100755 index 0000000..d2d5852 --- /dev/null +++ b/DoomClassic/code/iphone/doom_wads.h @@ -0,0 +1,89 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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. + + */ + +#ifndef DoomII_doom2_wads_h +#define DoomII_doom2_wads_h + + +#ifdef __cplusplus +extern "C" { +#endif + +const static int TOTAL_HOE_MISSIONS = 32; +const static int TOTAL_PLUT_MISSIONS = 32; +const static int TOTAL_TNT_MISSIONS = 32; +const static int TOTAL_MAST_MISSIONS = 21; +const static int TOTAL_NOREST_MISSIONS = 9; +const static int TOTAL_DOOM_MISSIONS = 32; + +const int MASTERLEVELS_MAPNUM[21] = { + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 3, + 5, + 7, + 7, + 7, + 8, + 9, + 25, + 31, + 32 +}; + +//--------------------------------------- +// iPhone mission pack management +//--------------------------------------- +typedef enum { + MISSION_HELL_ON_EARTH, + MISSION_PLUTONIA, + MISSION_TNT_EVILUTION, + MISSION_MASTER_LEVELS, + MISSION_NO_REST_FOR_THE_LIVING, + MISSION_ULTIMATE_DOOM, + + // None must be the last entry in this enum for the menu to work correctly. + MISSION_NONE +} iphoneMissionPack_t; + +extern iphoneMissionPack_t iphoneMissionPack; +extern int iphoneMasterLevel; + + +void iphoneFindIWADFile( iphoneMissionPack_t mission, char * returnFileName ); +void iphoneFindPWADFile( iphoneMissionPack_t mission, char * returnFileName ); + +int GetNumberOfMapsInExpansion( iphoneMissionPack_t expansion ); + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/DoomClassic/code/iphone/main.m b/DoomClassic/code/iphone/main.m new file mode 100755 index 0000000..6c02e52 --- /dev/null +++ b/DoomClassic/code/iphone/main.m @@ -0,0 +1,50 @@ +/* + + Copyright (C) 2009 Id Software, 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 + 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. + + */ + +#import +#import "Doom_App.h" +#include +#include + +extern char iphoneAppDirectory[1024]; +extern int myargc; +extern char **myargv; + +int main(int argc, char *argv[]) { + // save for doom + myargc = argc; + myargv = argv; + + // get the app directory based on argv[0] + strcpy( iphoneAppDirectory, argv[0] ); + + char * slashPosition = strrchr( iphoneAppDirectory, '/' ); + if ( slashPosition != NULL ) { + *slashPosition = 0; + } else { + iphoneAppDirectory[0] = 0; + } + + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; + NSString * classString = NSStringFromClass([DoomApp class]); + int retVal = UIApplicationMain(argc, argv, nil, classString ); + [pool release]; + return retVal; +} diff --git a/DoomClassic/doomtool/doomtool.1 b/DoomClassic/doomtool/doomtool.1 new file mode 100755 index 0000000..0f2d25a --- /dev/null +++ b/DoomClassic/doomtool/doomtool.1 @@ -0,0 +1,79 @@ +.\"Modified from man(1) of FreeBSD, the NetBSD mdoc.template, and mdoc.samples. +.\"See Also: +.\"man mdoc.samples for a complete listing of options +.\"man mdoc for the short list of editing options +.\"/usr/share/misc/mdoc.template +.Dd 4/6/09 \" DATE +.Dt doomtool 1 \" Program name and manual section number +.Os Darwin +.Sh NAME \" Section Header - required - don't modify +.Nm doomtool, +.\" The following lines are read in generating the apropos(man -k) database. Use only key +.\" words here as the database is built based on the words here and in the .ND line. +.Nm Other_name_for_same_program(), +.Nm Yet another name for the same program. +.\" Use .Nm macro to designate other names for the documented program. +.Nd This line parsed for whatis database. +.Sh SYNOPSIS \" Section Header - required - don't modify +.Nm +.Op Fl abcd \" [-abcd] +.Op Fl a Ar path \" [-a path] +.Op Ar file \" [file] +.Op Ar \" [file ...] +.Ar arg0 \" Underlined argument - use .Ar anywhere to underline +arg2 ... \" Arguments +.Sh DESCRIPTION \" Section Header - required - don't modify +Use the .Nm macro to refer to your program throughout the man page like such: +.Nm +Underlining is accomplished with the .Ar macro like this: +.Ar underlined text . +.Pp \" Inserts a space +A list of items with descriptions: +.Bl -tag -width -indent \" Begins a tagged list +.It item a \" Each item preceded by .It macro +Description of item a +.It item b +Description of item b +.El \" Ends the list +.Pp +A list of flags and their descriptions: +.Bl -tag -width -indent \" Differs from above in tag removed +.It Fl a \"-a flag as a list item +Description of -a flag +.It Fl b +Description of -b flag +.El \" Ends the list +.Pp +.\" .Sh ENVIRONMENT \" May not be needed +.\" .Bl -tag -width "ENV_VAR_1" -indent \" ENV_VAR_1 is width of the string ENV_VAR_1 +.\" .It Ev ENV_VAR_1 +.\" Description of ENV_VAR_1 +.\" .It Ev ENV_VAR_2 +.\" Description of ENV_VAR_2 +.\" .El +.Sh FILES \" File used or created by the topic of the man page +.Bl -tag -width "/Users/joeuser/Library/really_long_file_name" -compact +.It Pa /usr/share/file_name +FILE_1 description +.It Pa /Users/joeuser/Library/really_long_file_name +FILE_2 description +.El \" Ends the list +.\" .Sh DIAGNOSTICS \" May not be needed +.\" .Bl -diag +.\" .It Diagnostic Tag +.\" Diagnostic informtion here. +.\" .It Diagnostic Tag +.\" Diagnostic informtion here. +.\" .El +.Sh SEE ALSO +.\" List links in ascending order by section, alphabetically within a section. +.\" Please do not reference files that do not exist without filing a bug report +.Xr a 1 , +.Xr b 1 , +.Xr c 1 , +.Xr a 2 , +.Xr b 2 , +.Xr a 3 , +.Xr b 3 +.\" .Sh BUGS \" Document known, unremedied bugs +.\" .Sh HISTORY \" Document history if command behaves in a unique manner \ No newline at end of file diff --git a/DoomClassic/doomtool/doomtool.h b/DoomClassic/doomtool/doomtool.h new file mode 100755 index 0000000..27934a7 --- /dev/null +++ b/DoomClassic/doomtool/doomtool.h @@ -0,0 +1,160 @@ +/* + * ipak.h + * General purpose data file management intended to be used + * as a read-only memory mapped file to play nice with iPhone OS's + * non-swapping and variable memory management. + * + * Created by John Carmack on 4/9/09. + * Copyright 2009 id Software. All rights reserved. + * + */ + +//============================================================ +// +// In-file structures +// +// These stuctures are in the mapped data file, and shared +// between the app and utility. +// +// Type headers are stored separately from the bulk data to minimize the +// number of active pages. +// +// The full hash of the name is stored in nameHash, and nameHash&(PK_HASH_BUCKETS-1) is +// used to chain structures of a particular type together. +// +//============================================================ + +#define MAX_PK_NAME 64 +typedef struct { + int nameHash; // PK_HashName( name ) + int nextOnHashChain; // -1 = end of chain + char name[MAX_PK_NAME]; // in canonical form: backslashes to slashes and lowercase +} pkName_t; + +#define PK_HASH_CHAINS 256 +typedef struct { + int tableOfs; // // &firstStruct = (byte *)dfHeader + tableOfs + int count; + int structSize; // sizeof( pkWavData_t ), etc + int hashChains[PK_HASH_CHAINS]; // -1 = end of chain +} pkType_t; + +// dfWavData holds everything necessary to fully create an OpenAL sample buffer +typedef struct { + pkName_t name; + int wavDataOfs; + int wavChannels; // 1 or 2 + int wavChannelBytes; // 1 or 2 + int wavRate; // 22050, etc + int wavNumSamples; // each sample holds all the channels + // we may want looping information here later +} pkWavData_t; + +// iPhone does not natively support palettized textures, but we +// might conceivably want to support luminance and intensity textures +// in the future. +typedef enum { + TF_565, + TF_5551, + TF_4444, + TF_8888, + TF_LA, + TF_PVR4, + TF_PVR4A, + TF_PVR2, + TF_PVR2A, +} textureFormat_t; + +// dfImageData_t holds everything necessary to fully create an OpenGL texture object +typedef struct { + pkName_t name; + int picDataOfs; // the raw bits to pass to gl, mipmaps appended + // for PVR formats, the minimum size of each level is 32 bytes + + int format; + int uploadWidth; + int uploadHeight; + int numLevels; // 1 for non mipmapped, otherwise log2( largest dimension ) + + // glTexParameters + int wrapS; + int wrapT; + int minFilter; + int magFilter; + int aniso; + + // The upload sizes can be larger than the source sizes for + // non power of two sources, or for non square sources in the + // case of PVR compression. + int srcWidth; + int srcHeight; + + float maxS; // srcWidth / uploadWidth + float maxT; + + // Track the outlines of up to two boxes of non-transparent pixels + // to allow optimized drawing of sprites with large empty areas. + // The reason for two boxes is that the common lights have something + // at the top and something at the bottom, with nothing inbetween. + // These are inclusive bounds of the rows / columns in + // uploadWidth / uploadHeight with non-0 alpha + int numBounds; + int bounds[2][2][2]; +} pkTextureData_t; + +typedef struct { + pkName_t name; + int rawDataOfs; // (byte *)pkHeader + dataOfs + int rawDataLen; // there will always be a 0 byte appended to terminate strings + // that is not counted in this length +} pkRawData_t; + +#define PKFILE_VERSION 0x12340002 +typedef struct { + int version; + + pkType_t textures; + pkType_t wavs; + pkType_t raws; +} pkHeader_t; + + +//============================================================ +// +// In-memory, writable structures +// +//============================================================ + +typedef struct { + unsigned glTexNum; + const pkTextureData_t *textureData; + // we will need to add LRU links if texture caching is needed +} pkTexture_t; + +typedef struct { + unsigned alBufferNum; // created with the staticBuffer extension directly in the mapped memory + const pkWavData_t *wavData; +} pkWav_t; + +void PK_Init( const char *pakFileName ); +const pkName_t *PK_FindType( const char *rawName, const pkType_t *type, int *index ); +const byte * PK_FindRaw( const char *rawName, int *len ); // len can be NULL if you don't need it +pkTexture_t * PK_FindTexture( const char *imageName ); +pkWav_t * PK_FindWav( const char *soundName ); + +// The name will be converted to canonical name (backslashes converted to slashes and lowercase) +// before generating a hash. +int PK_HashName( const char *name, char canonical[MAX_PK_NAME] ); + +void PK_BindTexture( pkTexture_t *tex ); +void PK_DrawTexture( pkTexture_t *tex, int x, int y ); +void PK_StretchTexture( pkTexture_t *tex, float x, float y, float w, float h ); + +extern pkHeader_t * pkHeader; +extern int pkSize; + +// images and wavs have writable state, so they need separate +// structs that also point to the source in the pak file +extern pkTexture_t *pkTextures; +extern pkWav_t * pkWavs; + diff --git a/DoomClassic/doomtool/doomtool.xcodeproj/greghodges.mode1v3 b/DoomClassic/doomtool/doomtool.xcodeproj/greghodges.mode1v3 new file mode 100755 index 0000000..2c84b12 --- /dev/null +++ b/DoomClassic/doomtool/doomtool.xcodeproj/greghodges.mode1v3 @@ -0,0 +1,1393 @@ + + + + + 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 + XCProjectFormatConflictsModule + Name + Project Format Conflicts List + + + 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 + + + BundleLoadPath + + MaxInstances + n + Module + XCSnapshotModule + Name + Snapshots Tool + + + BundlePath + /Developer/Library/PrivateFrameworks/DevToolsInterface.framework/Resources + Description + DefaultDescriptionKey + DockingSystemVisible + + Extension + mode1v3 + FavBarConfig + + PBXProjectModuleGUID + ED845A9A109F3FFA00F673AC + XCBarModuleItemNames + + XCBarModuleItems + + + FirstTimeWindowDisplayed + + Identifier + com.apple.perspectives.project.mode1v3 + MajorVersion + 33 + MinorVersion + 0 + Name + Default + Notifications + + OpenEditors + + PerspectiveWidths + + -1 + -1 + + Perspectives + + + ChosenToolbarItems + + active-combo-popup + action + NSToolbarFlexibleSpaceItem + debugger-enable-breakpoints + build-and-go + com.apple.ide.PBXToolbarStopButton + get-info + NSToolbarFlexibleSpaceItem + com.apple.pbx.toolbar.searchfield + + ControllerClassBaseName + + IconName + WindowOfProjectWithEditor + Identifier + perspective.project + IsVertical + + Layout + + + BecomeActive + + ContentConfiguration + + PBXBottomSmartGroupGIDs + + 1C37FBAC04509CD000000102 + 1C37FAAC04509CD000000102 + 1C37FABC05509CD000000102 + 1C37FABC05539CD112110102 + E2644B35053B69B200211256 + 1C37FABC04509CD000100104 + 1CC0EA4004350EF90044410B + 1CC0EA4004350EF90041110B + + PBXProjectModuleGUID + 1CE0B1FE06471DED0097A5F4 + PBXProjectModuleLabel + Files + PBXProjectStructureProvided + yes + PBXSmartGroupTreeModuleColumnData + + PBXSmartGroupTreeModuleColumnWidthsKey + + 186 + + PBXSmartGroupTreeModuleColumnsKey_v4 + + MainColumn + + + PBXSmartGroupTreeModuleOutlineStateKey_v7 + + PBXSmartGroupTreeModuleOutlineStateExpansionKey + + 08FB7794FE84155DC02AAC07 + 08FB7795FE84155DC02AAC07 + C6A0FF2B0290797F04C91782 + 1C37FABC05509CD000000102 + + PBXSmartGroupTreeModuleOutlineStateSelectionKey + + + 3 + 2 + 0 + + + PBXSmartGroupTreeModuleOutlineStateVisibleRectKey + {{0, 0}, {186, 778}} + + PBXTopSmartGroupGIDs + + XCIncludePerspectivesSwitch + + XCSharingToken + com.apple.Xcode.GFSharingToken + + GeometryConfiguration + + Frame + {{0, 0}, {203, 796}} + GroupTreeTableConfiguration + + MainColumn + 186 + + RubberWindowFrame + 72 240 1138 837 0 0 1920 1178 + + Module + PBXSmartGroupTreeModule + Proportion + 203pt + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + 1CE0B20306471E060097A5F4 + PBXProjectModuleLabel + doomtool.h + PBXSplitModuleInNavigatorKey + + Split0 + + PBXProjectModuleGUID + 1CE0B20406471E060097A5F4 + PBXProjectModuleLabel + doomtool.h + _historyCapacity + 0 + bookmark + EDFA7E9911A1E5920098FFFC + history + + ED845A90109F3FFA00F673AC + EDFA7657119A0EBE0098FFFC + EDFA7658119A0EBE0098FFFC + + + SplitCount + 1 + + StatusBarVisibility + + + GeometryConfiguration + + Frame + {{0, 0}, {930, 752}} + RubberWindowFrame + 72 240 1138 837 0 0 1920 1178 + + Module + PBXNavigatorGroup + Proportion + 752pt + + + ContentConfiguration + + PBXProjectModuleGUID + 1CE0B20506471E060097A5F4 + PBXProjectModuleLabel + Detail + + GeometryConfiguration + + Frame + {{0, 757}, {930, 39}} + RubberWindowFrame + 72 240 1138 837 0 0 1920 1178 + + Module + XCDetailModule + Proportion + 39pt + + + Proportion + 930pt + + + Name + Project + ServiceClasses + + XCModuleDock + PBXSmartGroupTreeModule + XCModuleDock + PBXNavigatorGroup + XCDetailModule + + TableOfContents + + EDFA765A119A0EBE0098FFFC + 1CE0B1FE06471DED0097A5F4 + EDFA765B119A0EBE0098FFFC + 1CE0B20306471E060097A5F4 + 1CE0B20506471E060097A5F4 + + ToolbarConfigUserDefaultsMinorVersion + 2 + ToolbarConfiguration + xcode.toolbar.config.defaultV3 + + + 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.shortV3 + + + PerspectivesBarVisible + + ShelfIsVisible + + SourceDescription + file at '/Developer/Library/PrivateFrameworks/DevToolsInterface.framework/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 + + ED845A9B109F3FFA00F673AC + /Volumes/Work/idMobileDepot/DoomClassicDepot/doomtool/doomtool.xcodeproj + + WindowString + 72 240 1138 837 0 0 1920 1178 + WindowToolsV3 + + + FirstTimeWindowDisplayed + + Identifier + windowTool.build + IsVertical + + Layout + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + 1CD0528F0623707200166675 + PBXProjectModuleLabel + + StatusBarVisibility + + + GeometryConfiguration + + Frame + {{0, 0}, {500, 218}} + RubberWindowFrame + 111 554 500 500 0 0 1920 1178 + + Module + PBXNavigatorGroup + Proportion + 218pt + + + ContentConfiguration + + PBXProjectModuleGUID + XCMainBuildResultsModuleGUID + PBXProjectModuleLabel + Build Results + XCBuildResultsTrigger_Collapse + 1021 + XCBuildResultsTrigger_Open + 1011 + + GeometryConfiguration + + Frame + {{0, 223}, {500, 236}} + RubberWindowFrame + 111 554 500 500 0 0 1920 1178 + + Module + PBXBuildResultsModule + Proportion + 236pt + + + Proportion + 459pt + + + Name + Build Results + ServiceClasses + + PBXBuildResultsModule + + StatusbarIsVisible + + TableOfContents + + ED845A9B109F3FFA00F673AC + EDFA765C119A0EBE0098FFFC + 1CD0528F0623707200166675 + XCMainBuildResultsModuleGUID + + ToolbarConfiguration + xcode.toolbar.config.buildV3 + WindowString + 111 554 500 500 0 0 1920 1178 + WindowToolGUID + ED845A9B109F3FFA00F673AC + WindowToolIsVisible + + + + FirstTimeWindowDisplayed + + Identifier + windowTool.debugger + IsVertical + + Layout + + + Dock + + + ContentConfiguration + + Debugger + + HorizontalSplitView + + _collapsingFrameDimension + 0.0 + _indexOfCollapsedView + 0 + _percentageOfCollapsedView + 0.0 + isCollapsed + yes + sizes + + {{0, 0}, {316, 185}} + {{316, 0}, {378, 185}} + + + VerticalSplitView + + _collapsingFrameDimension + 0.0 + _indexOfCollapsedView + 0 + _percentageOfCollapsedView + 0.0 + isCollapsed + yes + sizes + + {{0, 0}, {694, 185}} + {{0, 185}, {694, 196}} + + + + LauncherConfigVersion + 8 + PBXProjectModuleGUID + 1C162984064C10D400B95A72 + PBXProjectModuleLabel + Debug - GLUTExamples (Underwater) + + GeometryConfiguration + + DebugConsoleVisible + None + DebugConsoleWindowFrame + {{200, 200}, {500, 300}} + DebugSTDIOWindowFrame + {{200, 200}, {500, 300}} + Frame + {{0, 0}, {694, 381}} + PBXDebugSessionStackFrameViewKey + + DebugVariablesTableConfiguration + + Name + 120 + Value + 85 + Summary + 148 + + Frame + {{316, 0}, {378, 185}} + RubberWindowFrame + 92 512 694 422 0 0 1680 1028 + + RubberWindowFrame + 92 512 694 422 0 0 1680 1028 + + Module + PBXDebugSessionModule + Proportion + 381pt + + + Proportion + 381pt + + + Name + Debugger + ServiceClasses + + PBXDebugSessionModule + + StatusbarIsVisible + + TableOfContents + + 1CD10A99069EF8BA00B06720 + ED845A9D109F3FFA00F673AC + 1C162984064C10D400B95A72 + ED845A9E109F3FFA00F673AC + ED845A9F109F3FFA00F673AC + ED845AA0109F3FFA00F673AC + ED845AA1109F3FFA00F673AC + ED845AA2109F3FFA00F673AC + + ToolbarConfiguration + xcode.toolbar.config.debugV3 + WindowString + 92 512 694 422 0 0 1680 1028 + WindowToolGUID + 1CD10A99069EF8BA00B06720 + WindowToolIsVisible + + + + Identifier + windowTool.find + Layout + + + Dock + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + 1CDD528C0622207200134675 + PBXProjectModuleLabel + <No Editor> + PBXSplitModuleInNavigatorKey + + Split0 + + PBXProjectModuleGUID + 1CD0528D0623707200166675 + + SplitCount + 1 + + StatusBarVisibility + 1 + + GeometryConfiguration + + Frame + {{0, 0}, {781, 167}} + RubberWindowFrame + 62 385 781 470 0 0 1440 878 + + Module + PBXNavigatorGroup + Proportion + 781pt + + + Proportion + 50% + + + BecomeActive + 1 + ContentConfiguration + + PBXProjectModuleGUID + 1CD0528E0623707200166675 + PBXProjectModuleLabel + Project Find + + GeometryConfiguration + + Frame + {{8, 0}, {773, 254}} + RubberWindowFrame + 62 385 781 470 0 0 1440 878 + + Module + PBXProjectFindModule + Proportion + 50% + + + Proportion + 428pt + + + Name + Project Find + ServiceClasses + + PBXProjectFindModule + + StatusbarIsVisible + 1 + TableOfContents + + 1C530D57069F1CE1000CFCEE + 1C530D58069F1CE1000CFCEE + 1C530D59069F1CE1000CFCEE + 1CDD528C0622207200134675 + 1C530D5A069F1CE1000CFCEE + 1CE0B1FE06471DED0097A5F4 + 1CD0528E0623707200166675 + + WindowString + 62 385 781 470 0 0 1440 878 + WindowToolGUID + 1C530D57069F1CE1000CFCEE + WindowToolIsVisible + 0 + + + Identifier + MENUSEPARATOR + + + FirstTimeWindowDisplayed + + Identifier + windowTool.debuggerConsole + IsVertical + + Layout + + + Dock + + + BecomeActive + + ContentConfiguration + + PBXProjectModuleGUID + 1C78EAAC065D492600B07095 + PBXProjectModuleLabel + Debugger Console + + GeometryConfiguration + + Frame + {{0, 0}, {650, 209}} + RubberWindowFrame + 71 707 650 250 0 0 1680 1028 + + Module + PBXDebugCLIModule + Proportion + 209pt + + + Proportion + 209pt + + + Name + Debugger Console + ServiceClasses + + PBXDebugCLIModule + + StatusbarIsVisible + + TableOfContents + + 1C78EAAD065D492600B07095 + ED845AA3109F3FFA00F673AC + 1C78EAAC065D492600B07095 + + ToolbarConfiguration + xcode.toolbar.config.consoleV3 + WindowString + 71 707 650 250 0 0 1680 1028 + WindowToolGUID + 1C78EAAD065D492600B07095 + WindowToolIsVisible + + + + Identifier + windowTool.snapshots + Layout + + + Dock + + + Module + XCSnapshotModule + Proportion + 100% + + + Proportion + 100% + + + Name + Snapshots + ServiceClasses + + XCSnapshotModule + + StatusbarIsVisible + Yes + ToolbarConfiguration + xcode.toolbar.config.snapshots + WindowString + 315 824 300 550 0 0 1440 878 + WindowToolIsVisible + Yes + + + 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.0950012207031 + + 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 + 3 + MinorVersion + 0 + Name + Breakpoints + ServiceClasses + + PBXSmartGroupTreeModule + XCDetailModule + + StatusbarIsVisible + 1 + TableOfContents + + 1CDDB66807F98D9800BB5817 + 1CDDB66907F98D9800BB5817 + 1CE0B1FE06471DED0097A5F4 + 1CA1AED706398EBD00589147 + + ToolbarConfiguration + xcode.toolbar.config.breakpointsV3 + 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.debugAnimatorV3 + 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.projectFormatConflicts + Layout + + + Dock + + + Module + XCProjectFormatConflictsModule + Proportion + 100% + + + Proportion + 100% + + + Name + Project Format Conflicts + ServiceClasses + + XCProjectFormatConflictsModule + + StatusbarIsVisible + 0 + WindowContentMinSize + 450 300 + WindowString + 50 850 472 307 0 0 1440 877 + + + 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 + + + Identifier + windowTool.refactoring + IncludeInToolsMenu + 0 + Layout + + + Dock + + + BecomeActive + 1 + GeometryConfiguration + + Frame + {0, 0}, {500, 335} + RubberWindowFrame + {0, 0}, {500, 335} + + Module + XCRefactoringModule + Proportion + 100% + + + Proportion + 100% + + + Name + Refactoring + ServiceClasses + + XCRefactoringModule + + WindowString + 200 200 500 356 0 0 1920 1200 + + + + diff --git a/DoomClassic/doomtool/doomtool.xcodeproj/greghodges.pbxuser b/DoomClassic/doomtool/doomtool.xcodeproj/greghodges.pbxuser new file mode 100755 index 0000000..1688bf6 --- /dev/null +++ b/DoomClassic/doomtool/doomtool.xcodeproj/greghodges.pbxuser @@ -0,0 +1,193 @@ +// !$*UTF8*$! +{ + 08FB7793FE84155DC02AAC07 /* Project object */ = { + activeBuildConfigurationName = Debug; + activeExecutable = EDAFC835109A7D48002C3487 /* doomtool */; + activeTarget = 8DD76FA90486AB0100D96B5E /* doomtool */; + codeSenseManager = EDAFC839109A7D66002C3487 /* Code sense */; + executables = ( + EDAFC835109A7D48002C3487 /* doomtool */, + ); + perUserDictionary = { + PBXConfiguration.PBXFileTableDataSource3.PBXFileTableDataSource = { + PBXFileTableDataSourceColumnSortingDirectionKey = "-1"; + PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID; + PBXFileTableDataSourceColumnWidthsKey = ( + 20, + 691, + 20, + 48.16259765625, + 43, + 43, + 20, + ); + PBXFileTableDataSourceColumnsKey = ( + PBXFileDataSource_FiletypeID, + PBXFileDataSource_Filename_ColumnID, + PBXFileDataSource_Built_ColumnID, + PBXFileDataSource_ObjectSize_ColumnID, + PBXFileDataSource_Errors_ColumnID, + PBXFileDataSource_Warnings_ColumnID, + PBXFileDataSource_Target_ColumnID, + ); + }; + PBXPerProjectTemplateStateSaveDate = 278560770; + PBXWorkspaceStateSaveDate = 278560770; + }; + perUserProjectItems = { + ED845A90109F3FFA00F673AC /* PBXTextBookmark */ = ED845A90109F3FFA00F673AC /* PBXTextBookmark */; + ED845A91109F3FFA00F673AC /* PBXTextBookmark */ = ED845A91109F3FFA00F673AC /* PBXTextBookmark */; + ED845A92109F3FFA00F673AC /* PBXTextBookmark */ = ED845A92109F3FFA00F673AC /* PBXTextBookmark */; + ED845A93109F3FFA00F673AC /* PBXTextBookmark */ = ED845A93109F3FFA00F673AC /* PBXTextBookmark */; + ED845A94109F3FFA00F673AC /* PBXTextBookmark */ = ED845A94109F3FFA00F673AC /* PBXTextBookmark */; + ED845A95109F3FFA00F673AC /* PBXTextBookmark */ = ED845A95109F3FFA00F673AC /* PBXTextBookmark */; + ED845A96109F3FFA00F673AC /* PBXTextBookmark */ = ED845A96109F3FFA00F673AC /* PBXTextBookmark */; + ED845A97109F3FFA00F673AC /* PBXTextBookmark */ = ED845A97109F3FFA00F673AC /* PBXTextBookmark */; + }; + sourceControlManager = EDAFC838109A7D66002C3487 /* Source Control */; + userBuildSettings = { + }; + }; + 08FB7796FE84155DC02AAC07 /* main.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {869, 23968}}"; + sepNavSelRange = "{39996, 0}"; + sepNavVisRange = "{41755, 1531}"; + }; + }; + 72C01AB40F8CFCA900DE72D8 /* doomtool.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {869, 2254}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{1823, 1224}"; + }; + }; + 8DD76FA90486AB0100D96B5E /* doomtool */ = { + activeExec = 0; + executables = ( + EDAFC835109A7D48002C3487 /* doomtool */, + ); + }; + C6A0FF2C0290799A04C91782 /* doomtool.1 */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {869, 1106}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 1868}"; + }; + }; + ED845A90109F3FFA00F673AC /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = C6A0FF2C0290799A04C91782 /* doomtool.1 */; + name = "doomtool.1: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1868; + vrLoc = 0; + }; + ED845A91109F3FFA00F673AC /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72C01AB40F8CFCA900DE72D8 /* doomtool.h */; + name = "doomtool.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1224; + vrLoc = 1823; + }; + ED845A92109F3FFA00F673AC /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 08FB7796FE84155DC02AAC07 /* main.c */; + name = "main.c: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 835; + vrLoc = 0; + }; + ED845A93109F3FFA00F673AC /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 08FB7796FE84155DC02AAC07 /* main.c */; + name = "main.c: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 393; + vrLoc = 0; + }; + ED845A94109F3FFA00F673AC /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = C6A0FF2C0290799A04C91782 /* doomtool.1 */; + name = "doomtool.1: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1868; + vrLoc = 0; + }; + ED845A95109F3FFA00F673AC /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 08FB7796FE84155DC02AAC07 /* main.c */; + name = "main.c: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 835; + vrLoc = 0; + }; + ED845A96109F3FFA00F673AC /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72C01AB40F8CFCA900DE72D8 /* doomtool.h */; + name = "doomtool.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1224; + vrLoc = 1823; + }; + ED845A97109F3FFA00F673AC /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 08FB7796FE84155DC02AAC07 /* main.c */; + name = "main.c: 1606"; + rLen = 0; + rLoc = 39996; + rType = 0; + vrLen = 1531; + vrLoc = 41755; + }; + EDAFC835109A7D48002C3487 /* doomtool */ = { + isa = PBXExecutable; + activeArgIndices = ( + ); + argumentStrings = ( + ); + autoAttachOnCrash = 1; + breakpointsEnabled = 0; + configStateDict = { + }; + customDataFormattersEnabled = 1; + debuggerPlugin = GDBDebugging; + disassemblyDisplayState = 0; + dylibVariantSuffix = ""; + enableDebugStr = 1; + environmentEntries = ( + ); + executableSystemSymbolLevel = 0; + executableUserSymbolLevel = 0; + libgmallocEnabled = 0; + name = doomtool; + sourceDirectories = ( + ); + }; + EDAFC838109A7D66002C3487 /* Source Control */ = { + isa = PBXSourceControlManager; + fallbackIsa = XCSourceControlManager; + isSCMEnabled = 0; + scmConfiguration = { + }; + }; + EDAFC839109A7D66002C3487 /* Code sense */ = { + isa = PBXCodeSenseManager; + indexTemplatePath = ""; + }; +} diff --git a/DoomClassic/doomtool/doomtool.xcodeproj/johnc.pbxuser b/DoomClassic/doomtool/doomtool.xcodeproj/johnc.pbxuser new file mode 100755 index 0000000..cb4bbe0 --- /dev/null +++ b/DoomClassic/doomtool/doomtool.xcodeproj/johnc.pbxuser @@ -0,0 +1,602 @@ +// !$*UTF8*$! +{ + 08FB7793FE84155DC02AAC07 /* Project object */ = { + activeBuildConfigurationName = Debug; + activeExecutable = 72AFDC180F8AF03E0096A523 /* doomtool */; + activeTarget = 8DD76FA90486AB0100D96B5E /* doomtool */; + addToTargets = ( + ); + breakpoints = ( + 72C01AB60F8E56DB00DE72D8 /* main.c:1715 */, + 72C01B050F8E783400DE72D8 /* main.c:60 */, + 72C01B160F8E78D400DE72D8 /* main.c:60 */, + 72C01B180F8E78D500DE72D8 /* main.c:60 */, + 72C01C410F8EA48F00DE72D8 /* main.c:60 */, + 72D50E490F8EFD6E00BB49E6 /* main.c:1279 */, + 72D50E660F8F021500BB49E6 /* main.c:1327 */, + 721DBA7F0F920C3D001906DB /* main.c:1691 */, + 721DBAB20F9218A8001906DB /* main.c:1429 */, + 721DBACC0F92DC12001906DB /* main.c:384 */, + 721DBADE0F92DDCE001906DB /* main.c:1433 */, + 72C8D1C60F936A5A00C6F3E2 /* main.c:1516 */, + 72B0EAC70FBD18E200D1D1FA /* main.c:1577 */, + 72B0EAD00FBD190000D1D1FA /* main.c:1588 */, + ); + codeSenseManager = 72AFDC1E0F8AF05D0096A523 /* Code sense */; + executables = ( + 72AFDC180F8AF03E0096A523 /* doomtool */, + ); + perUserDictionary = { + "PBXConfiguration.PBXBreakpointsDataSource.v1:1CA23EDF0692099D00951B8B" = { + PBXFileTableDataSourceColumnSortingDirectionKey = "-1"; + PBXFileTableDataSourceColumnSortingKey = PBXBreakpointsDataSource_BreakpointID; + PBXFileTableDataSourceColumnWidthsKey = ( + 20, + 20, + 267, + 20, + 167, + 167, + 131, + 20, + ); + PBXFileTableDataSourceColumnsKey = ( + PBXBreakpointsDataSource_ActionID, + PBXBreakpointsDataSource_TypeID, + PBXBreakpointsDataSource_BreakpointID, + PBXBreakpointsDataSource_UseID, + PBXBreakpointsDataSource_LocationID, + PBXBreakpointsDataSource_ConditionID, + PBXBreakpointsDataSource_IgnoreCountID, + PBXBreakpointsDataSource_ContinueID, + ); + }; + PBXConfiguration.PBXFileTableDataSource3.PBXFileTableDataSource = { + PBXFileTableDataSourceColumnSortingDirectionKey = "-1"; + PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID; + PBXFileTableDataSourceColumnWidthsKey = ( + 20, + 138, + 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, + ); + }; + PBXPerProjectTemplateStateSaveDate = 278554695; + PBXWorkspaceStateSaveDate = 278554695; + }; + perUserProjectItems = { + 721817A0109A684D00B6E7D0 /* PBXTextBookmark */ = 721817A0109A684D00B6E7D0 /* PBXTextBookmark */; + 721817A1109A685300B6E7D0 /* PBXTextBookmark */ = 721817A1109A685300B6E7D0 /* PBXTextBookmark */; + 721817A2109A766E00B6E7D0 /* PBXTextBookmark */ = 721817A2109A766E00B6E7D0 /* PBXTextBookmark */; + 721DBA820F920C96001906DB = 721DBA820F920C96001906DB /* PBXTextBookmark */; + 721DBA890F920C96001906DB = 721DBA890F920C96001906DB /* PBXTextBookmark */; + 721DBA9C0F920D42001906DB = 721DBA9C0F920D42001906DB /* PBXTextBookmark */; + 721DBAB40F9218C5001906DB = 721DBAB40F9218C5001906DB /* PBXTextBookmark */; + 721DBAB80F9218C5001906DB = 721DBAB80F9218C5001906DB /* PBXTextBookmark */; + 724C57980FC1B1AF000E4348 = 724C57980FC1B1AF000E4348 /* PBXTextBookmark */; + 725412D31007CD1700925CFB = 725412D31007CD1700925CFB /* PBXTextBookmark */; + 72541334100BA26300925CFB = 72541334100BA26300925CFB /* PBXTextBookmark */; + 72B0EA900FBD175200D1D1FA = 72B0EA900FBD175200D1D1FA /* PBXTextBookmark */; + 72B0EA930FBD175200D1D1FA = 72B0EA930FBD175200D1D1FA /* PBXTextBookmark */; + 72C01AEE0F8E772800DE72D8 = 72C01AEE0F8E772800DE72D8 /* PBXTextBookmark */; + 72C01CA20F8EBD0400DE72D8 = 72C01CA20F8EBD0400DE72D8 /* PBXTextBookmark */; + 72D50DDD0F8EF90500BB49E6 = 72D50DDD0F8EF90500BB49E6 /* PBXTextBookmark */; + }; + sourceControlManager = 72AFDC1D0F8AF05D0096A523 /* Source Control */; + userBuildSettings = { + }; + }; + 08FB7796FE84155DC02AAC07 /* main.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {800, 32946}}"; + sepNavSelRange = "{4800, 0}"; + sepNavVisRange = "{4620, 1028}"; + sepNavWindowFrame = "{{202, 118}, {857, 908}}"; + }; + }; + 721817A0109A684D00B6E7D0 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 08FB7796FE84155DC02AAC07 /* main.c */; + name = "main.c: 231"; + rLen = 0; + rLoc = 4800; + rType = 0; + vrLen = 1028; + vrLoc = 4620; + }; + 721817A1109A685300B6E7D0 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 08FB7796FE84155DC02AAC07 /* main.c */; + name = "main.c: 231"; + rLen = 0; + rLoc = 4800; + rType = 0; + vrLen = 990; + vrLoc = 4620; + }; + 721817A2109A766E00B6E7D0 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 08FB7796FE84155DC02AAC07 /* main.c */; + name = "main.c: 231"; + rLen = 0; + rLoc = 4800; + rType = 0; + vrLen = 1028; + vrLoc = 4620; + }; + 721DBA7F0F920C3D001906DB /* main.c:1691 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 08FB7796FE84155DC02AAC07 /* main.c */; + functionName = "main()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1691; + location = doomtool; + modificationTime = 268950856.78839; + state = 2; + }; + 721DBA820F920C96001906DB /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72C01CA30F8EBD0400DE72D8 /* Image_files.cpp */; + name = "Image_files.cpp: 142"; + rLen = 5268; + rLoc = 4644; + rType = 0; + vrLen = 706; + vrLoc = 9577; + }; + 721DBA840F920C96001906DB /* Common_printf.cpp */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + name = Common_printf.cpp; + path = /Volumes/Untitled/alienbrainWork/Rage/code/framework/Common_printf.cpp; + sourceTree = ""; + }; + 721DBA890F920C96001906DB /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 721DBA8A0F920C96001906DB /* Common_printf.cpp */; + name = "Common_printf.cpp: 81"; + rLen = 14; + rLoc = 2665; + rType = 0; + vrLen = 901; + vrLoc = 2318; + }; + 721DBA8A0F920C96001906DB /* Common_printf.cpp */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + name = Common_printf.cpp; + path = /Volumes/Untitled/alienbrainWork/Rage/code/framework/Common_printf.cpp; + sourceTree = ""; + }; + 721DBA9C0F920D42001906DB /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 721DBA840F920C96001906DB /* Common_printf.cpp */; + name = "Common_printf.cpp: 215"; + rLen = 45; + rLoc = 6185; + rType = 0; + vrLen = 885; + vrLoc = 5703; + }; + 721DBAB20F9218A8001906DB /* main.c:1429 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 08FB7796FE84155DC02AAC07 /* main.c */; + functionName = "FinishAtlas()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1429; + location = doomtool; + modificationTime = 268950856.78876; + state = 2; + }; + 721DBAB40F9218C5001906DB /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 721DBAB50F9218C5001906DB /* BitBlockAllocator.cpp */; + name = "BitBlockAllocator.cpp: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 869; + vrLoc = 5194; + }; + 721DBAB50F9218C5001906DB /* BitBlockAllocator.cpp */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + name = BitBlockAllocator.cpp; + path = /Volumes/Untitled/alienbrainWork/Rage/code/renderer/BitBlockAllocator.cpp; + sourceTree = ""; + }; + 721DBAB80F9218C5001906DB /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 721DBAB90F9218C5001906DB /* BitBlockAllocator.cpp */; + name = "BitBlockAllocator.cpp: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 869; + vrLoc = 5194; + }; + 721DBAB90F9218C5001906DB /* BitBlockAllocator.cpp */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + name = BitBlockAllocator.cpp; + path = /Volumes/Untitled/alienbrainWork/Rage/code/renderer/BitBlockAllocator.cpp; + sourceTree = ""; + }; + 721DBACC0F92DC12001906DB /* main.c:384 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 08FB7796FE84155DC02AAC07 /* main.c */; + functionName = "LoadBMP()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 384; + location = doomtool; + modificationTime = 268950856.7891361; + state = 2; + }; + 721DBADE0F92DDCE001906DB /* main.c:1433 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 08FB7796FE84155DC02AAC07 /* main.c */; + functionName = "FinishAtlas()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1433; + location = doomtool; + modificationTime = 268950856.7895089; + state = 2; + }; + 724C57980FC1B1AF000E4348 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72C01AB40F8CFCA900DE72D8 /* doomtool.h */; + name = "doomtool.h: 61"; + rLen = 0; + rLoc = 1821; + rType = 0; + vrLen = 960; + vrLoc = 2425; + }; + 725412D31007CD1700925CFB /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 08FB7796FE84155DC02AAC07 /* main.c */; + name = "main.c: 231"; + rLen = 0; + rLoc = 4800; + rType = 0; + vrLen = 1028; + vrLoc = 4620; + }; + 72541334100BA26300925CFB /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 08FB7796FE84155DC02AAC07 /* main.c */; + name = "main.c: 231"; + rLen = 0; + rLoc = 4800; + rType = 0; + vrLen = 1028; + vrLoc = 4620; + }; + 72AFDC180F8AF03E0096A523 /* doomtool */ = { + isa = PBXExecutable; + activeArgIndices = ( + ); + argumentStrings = ( + ); + autoAttachOnCrash = 1; + breakpointsEnabled = 0; + configStateDict = { + }; + customDataFormattersEnabled = 1; + debuggerPlugin = GDBDebugging; + disassemblyDisplayState = 0; + dylibVariantSuffix = ""; + enableDebugStr = 1; + environmentEntries = ( + ); + executableSystemSymbolLevel = 0; + executableUserSymbolLevel = 0; + libgmallocEnabled = 0; + name = doomtool; + savedGlobals = { + }; + sourceDirectories = ( + ); + variableFormatDictionary = { + }; + }; + 72AFDC1D0F8AF05D0096A523 /* Source Control */ = { + isa = PBXSourceControlManager; + fallbackIsa = XCSourceControlManager; + isSCMEnabled = 0; + scmConfiguration = { + }; + }; + 72AFDC1E0F8AF05D0096A523 /* Code sense */ = { + isa = PBXCodeSenseManager; + indexTemplatePath = ""; + }; + 72B0EA900FBD175200D1D1FA /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72B4A70A0FAB70B100DC59D9 /* base.parm */; + name = "base.parm: 2"; + rLen = 0; + rLoc = 55; + rType = 0; + vrLen = 27; + vrLoc = 0; + }; + 72B0EA930FBD175200D1D1FA /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72B4A70A0FAB70B100DC59D9 /* base.parm */; + name = "base.parm: 2"; + rLen = 0; + rLoc = 55; + rType = 0; + vrLen = 27; + vrLoc = 0; + }; + 72B0EAC70FBD18E200D1D1FA /* main.c:1577 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 08FB7796FE84155DC02AAC07 /* main.c */; + functionName = "WriteType()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1577; + location = doomtool; + modificationTime = 268950856.790318; + state = 2; + }; + 72B0EAD00FBD190000D1D1FA /* main.c:1588 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 08FB7796FE84155DC02AAC07 /* main.c */; + functionName = "WriteType()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1588; + location = doomtool; + modificationTime = 268950856.790709; + state = 2; + }; + 72B4A70A0FAB70B100DC59D9 /* base.parm */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {848, 822}}"; + sepNavSelRange = "{55, 0}"; + sepNavVisRange = "{0, 55}"; + sepNavWindowFrame = "{{509, 37}, {907, 950}}"; + }; + }; + 72C01AB40F8CFCA900DE72D8 /* doomtool.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {908, 3040}}"; + sepNavSelRange = "{1821, 0}"; + sepNavVisRange = "{2425, 960}"; + sepNavWindowFrame = "{{781, -387}, {857, 908}}"; + }; + }; + 72C01AB60F8E56DB00DE72D8 /* main.c:1715 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 08FB7796FE84155DC02AAC07 /* main.c */; + functionName = "main()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1715; + modificationTime = 268950856.785729; + state = 2; + }; + 72C01AEE0F8E772800DE72D8 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 08FB7796FE84155DC02AAC07 /* main.c */; + name = "main.c: 53"; + rLen = 0; + rLoc = 1295; + rType = 0; + vrLen = 403; + vrLoc = 18328; + }; + 72C01B050F8E783400DE72D8 /* main.c:60 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 08FB7796FE84155DC02AAC07 /* main.c */; + functionName = "AddDirectoryToPak_r()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 60; + location = doomtool; + modificationTime = 268950856.7861239; + state = 2; + }; + 72C01B160F8E78D400DE72D8 /* main.c:60 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 08FB7796FE84155DC02AAC07 /* main.c */; + functionName = "AddDirectoryToPak_r()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 60; + location = doomtool; + modificationTime = 268950856.786502; + state = 2; + }; + 72C01B180F8E78D500DE72D8 /* main.c:60 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 08FB7796FE84155DC02AAC07 /* main.c */; + functionName = "AddDirectoryToPak_r()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 60; + location = doomtool; + modificationTime = 268950856.786876; + state = 2; + }; + 72C01C410F8EA48F00DE72D8 /* main.c:60 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 08FB7796FE84155DC02AAC07 /* main.c */; + functionName = "AddWAV()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 60; + location = doomtool; + modificationTime = 268950856.787272; + state = 2; + }; + 72C01CA20F8EBD0400DE72D8 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72C01CA30F8EBD0400DE72D8 /* Image_files.cpp */; + name = "Image_files.cpp: 72"; + rLen = 2290; + rLoc = 2352; + rType = 0; + vrLen = 1236; + vrLoc = 2163; + }; + 72C01CA30F8EBD0400DE72D8 /* Image_files.cpp */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + name = Image_files.cpp; + path = /Volumes/Untitled/alienbrainWork/Rage/code/renderer/Image_files.cpp; + sourceTree = ""; + }; + 72C8D1C60F936A5A00C6F3E2 /* main.c:1516 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 08FB7796FE84155DC02AAC07 /* main.c */; + functionName = "AtlasDirectory()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1516; + location = doomtool; + modificationTime = 268950856.789892; + state = 2; + }; + 72D50DDD0F8EF90500BB49E6 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72C01AB40F8CFCA900DE72D8 /* doomtool.h */; + name = "doomtool.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 828; + vrLoc = 0; + }; + 72D50E490F8EFD6E00BB49E6 /* main.c:1279 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 08FB7796FE84155DC02AAC07 /* main.c */; + functionName = "AddRAW()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1279; + location = doomtool; + modificationTime = 268950856.787639; + state = 2; + }; + 72D50E660F8F021500BB49E6 /* main.c:1327 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 08FB7796FE84155DC02AAC07 /* main.c */; + functionName = "AddDirectoryToPak_r()"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 1327; + location = doomtool; + modificationTime = 268950856.78801; + state = 2; + }; + 8DD76FA90486AB0100D96B5E /* doomtool */ = { + activeExec = 0; + executables = ( + 72AFDC180F8AF03E0096A523 /* doomtool */, + ); + }; +} diff --git a/DoomClassic/doomtool/doomtool.xcodeproj/johnc.perspectivev3 b/DoomClassic/doomtool/doomtool.xcodeproj/johnc.perspectivev3 new file mode 100755 index 0000000..89a9b67 --- /dev/null +++ b/DoomClassic/doomtool/doomtool.xcodeproj/johnc.perspectivev3 @@ -0,0 +1,1505 @@ + + + + + ActivePerspectiveName + Debug + 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 + XCProjectFormatConflictsModule + Name + Project Format Conflicts List + + + 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 + + + BundleLoadPath + + MaxInstances + n + Module + XCSnapshotModule + Name + Snapshots Tool + + + BundlePath + /Developer/Library/PrivateFrameworks/DevToolsInterface.framework/Resources + Description + AIODescriptionKey + DockingSystemVisible + + Extension + perspectivev3 + FavBarConfig + + PBXProjectModuleGUID + 72AFDC310F8B059C0096A523 + XCBarModuleItemNames + + XCBarModuleItems + + + FirstTimeWindowDisplayed + + Identifier + com.apple.perspectives.project.defaultV3 + MajorVersion + 34 + MinorVersion + 0 + Name + All-In-One + Notifications + + + XCObserverAutoDisconnectKey + + XCObserverDefintionKey + + XCObserverFactoryKey + XCPerspectivesSpecificationIdentifier + XCObserverGUIDKey + XCObserverProjectIdentifier + XCObserverNotificationKey + PBXStatusBuildStateMessageNotification + XCObserverTargetKey + XCMainBuildResultsModuleGUID + XCObserverTriggerKey + awakenModuleWithObserver: + XCObserverValidationKey + + + + OpenEditors + + PerspectiveWidths + + 1068 + 1068 + + Perspectives + + + ChosenToolbarItems + + XCToolbarPerspectiveControl + NSToolbarSeparatorItem + active-combo-popup + action + NSToolbarFlexibleSpaceItem + buildOrClean + build-and-go + com.apple.ide.PBXToolbarStopButton + clean + toggle-editor + NSToolbarFlexibleSpaceItem + get-info + com.apple.pbx.toolbar.searchfield + + ControllerClassBaseName + + IconName + WindowOfProject + Identifier + perspective.project + IsVertical + + Layout + + + ContentConfiguration + + PBXBottomSmartGroupGIDs + + 1C37FBAC04509CD000000102 + 1C37FAAC04509CD000000102 + 1C08E77C0454961000C914BD + 1C37FABC05509CD000000102 + 1C37FABC05539CD112110102 + E2644B35053B69B200211256 + 1C37FABC04509CD000100104 + 1CC0EA4004350EF90044410B + 1CC0EA4004350EF90041110B + 1C77FABC04509CD000000102 + + PBXProjectModuleGUID + 1CA23ED40692098700951B8B + PBXProjectModuleLabel + Files + PBXProjectStructureProvided + yes + PBXSmartGroupTreeModuleColumnData + + PBXSmartGroupTreeModuleColumnWidthsKey + + 185 + + PBXSmartGroupTreeModuleColumnsKey_v4 + + MainColumn + + + PBXSmartGroupTreeModuleOutlineStateKey_v7 + + PBXSmartGroupTreeModuleOutlineStateExpansionKey + + 08FB7794FE84155DC02AAC07 + 08FB7795FE84155DC02AAC07 + + PBXSmartGroupTreeModuleOutlineStateSelectionKey + + + 4 + 2 + 0 + + + PBXSmartGroupTreeModuleOutlineStateVisibleRectKey + {{0, 0}, {185, 862}} + + PBXTopSmartGroupGIDs + + XCIncludePerspectivesSwitch + + + GeometryConfiguration + + Frame + {{0, 0}, {202, 880}} + GroupTreeTableConfiguration + + MainColumn + 185 + + + Module + PBXSmartGroupTreeModule + Proportion + 202pt + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + 72AFDC2A0F8B059C0096A523 + PBXProjectModuleLabel + main.c + PBXSplitModuleInNavigatorKey + + Split0 + + PBXProjectModuleGUID + 72AFDC2B0F8B059C0096A523 + PBXProjectModuleLabel + main.c + _historyCapacity + 0 + bookmark + 721817A2109A766E00B6E7D0 + history + + 72B0EA900FBD175200D1D1FA + 724C57980FC1B1AF000E4348 + 721817A0109A684D00B6E7D0 + + prevStack + + 72C01AEE0F8E772800DE72D8 + 72D50DDD0F8EF90500BB49E6 + 72B0EA930FBD175200D1D1FA + + + SplitCount + 1 + + StatusBarVisibility + + XCSharingToken + com.apple.Xcode.CommonNavigatorGroupSharingToken + + GeometryConfiguration + + Frame + {{0, 0}, {861, 629}} + + Module + PBXNavigatorGroup + Proportion + 629pt + + + Proportion + 246pt + Tabs + + + ContentConfiguration + + PBXProjectModuleGUID + 1CA23EDF0692099D00951B8B + PBXProjectModuleLabel + Detail + + GeometryConfiguration + + Frame + {{10, 27}, {377, -27}} + + Module + XCDetailModule + + + ContentConfiguration + + PBXProjectModuleGUID + 1CA23EE00692099D00951B8B + PBXProjectModuleLabel + Project Find + + GeometryConfiguration + + Frame + {{10, 27}, {861, 219}} + + Module + PBXProjectFindModule + + + ContentConfiguration + + PBXCVSModuleFilterTypeKey + 1032 + PBXProjectModuleGUID + 1CA23EE10692099D00951B8B + PBXProjectModuleLabel + SCM Results + + GeometryConfiguration + + Frame + {{10, 31}, {603, 297}} + + Module + PBXCVSModule + + + ContentConfiguration + + PBXProjectModuleGUID + XCMainBuildResultsModuleGUID + PBXProjectModuleLabel + Build + XCBuildResultsTrigger_Collapse + 1021 + XCBuildResultsTrigger_Open + 1010 + + GeometryConfiguration + + Frame + {{10, 27}, {861, 219}} + + Module + PBXBuildResultsModule + + + + + Proportion + 861pt + + + Name + Project + ServiceClasses + + XCModuleDock + PBXSmartGroupTreeModule + XCModuleDock + PBXNavigatorGroup + XCDockableTabModule + XCDetailModule + PBXProjectFindModule + PBXCVSModule + PBXBuildResultsModule + + TableOfContents + + 721817A3109A766E00B6E7D0 + 1CA23ED40692098700951B8B + 721817A4109A766E00B6E7D0 + 72AFDC2A0F8B059C0096A523 + 721817A5109A766E00B6E7D0 + 1CA23EDF0692099D00951B8B + 1CA23EE00692099D00951B8B + 1CA23EE10692099D00951B8B + XCMainBuildResultsModuleGUID + + ToolbarConfiguration + xcode.toolbar.config.defaultV3 + + + ChosenToolbarItems + + XCToolbarPerspectiveControl + NSToolbarSeparatorItem + active-combo-popup + NSToolbarFlexibleSpaceItem + servicesModulefind + servicesModuleproject + servicesModulebuild + build-and-go + com.apple.ide.PBXToolbarStopButton + debugger-restart-executable + debugger-pause + debugger-step-over + debugger-step-into + debugger-step-out + debugger-enable-breakpoints + NSToolbarFlexibleSpaceItem + com.apple.ide.XCBreakpointsToolbarItem + clear-log + + ControllerClassBaseName + PBXDebugSessionModule + IconName + DebugTabIcon + Identifier + perspective.debug + IsVertical + + Layout + + + BecomeActive + + ContentConfiguration + + PBXProjectModuleGUID + 1CCC7628064C1048000F2A68 + PBXProjectModuleLabel + Debugger Console + + GeometryConfiguration + + Frame + {{0, 0}, {1068, 280}} + RubberWindowFrame + 478 100 1068 921 0 0 1680 1028 + + Module + PBXDebugCLIModule + Proportion + 280pt + + + ContentConfiguration + + Debugger + + HorizontalSplitView + + _collapsingFrameDimension + 0.0 + _indexOfCollapsedView + 0 + _percentageOfCollapsedView + 0.0 + isCollapsed + yes + sizes + + {{0, 0}, {525, 194}} + {{525, 0}, {543, 194}} + + + VerticalSplitView + + _collapsingFrameDimension + 0.0 + _indexOfCollapsedView + 0 + _percentageOfCollapsedView + 0.0 + isCollapsed + yes + sizes + + {{0, 0}, {1068, 194}} + {{0, 194}, {1068, 401}} + + + + LauncherConfigVersion + 8 + PBXProjectModuleGUID + 1CCC7629064C1048000F2A68 + PBXProjectModuleLabel + Debug + + GeometryConfiguration + + DebugConsoleVisible + None + DebugConsoleWindowFrame + {{200, 200}, {500, 300}} + DebugSTDIOWindowFrame + {{200, 200}, {500, 300}} + Frame + {{0, 285}, {1068, 595}} + PBXDebugSessionStackFrameViewKey + + DebugVariablesTableConfiguration + + Name + 149 + Value + 114 + Summary + 255 + + Frame + {{525, 0}, {543, 194}} + RubberWindowFrame + 478 100 1068 921 0 0 1680 1028 + + RubberWindowFrame + 478 100 1068 921 0 0 1680 1028 + + Module + PBXDebugSessionModule + Proportion + 595pt + + + Name + Debug + ServiceClasses + + XCModuleDock + PBXDebugCLIModule + PBXDebugSessionModule + PBXDebugProcessAndThreadModule + PBXDebugProcessViewModule + PBXDebugThreadViewModule + PBXDebugStackFrameViewModule + PBXNavigatorGroup + + TableOfContents + + 721817A6109A766E00B6E7D0 + 1CCC7628064C1048000F2A68 + 1CCC7629064C1048000F2A68 + 721817A7109A766E00B6E7D0 + 721817A8109A766E00B6E7D0 + 721817A9109A766E00B6E7D0 + 721817AA109A766E00B6E7D0 + 72AFDC2A0F8B059C0096A523 + + ToolbarConfiguration + xcode.toolbar.config.debugV3 + + + PerspectivesBarVisible + + ShelfIsVisible + + SourceDescription + file at '/Developer/Library/PrivateFrameworks/DevToolsInterface.framework/Resources/XCPerspectivesSpecification.xcperspec' + StatusbarIsVisible + + TimeStamp + 278558318.435175 + ToolbarDisplayMode + 1 + ToolbarIsVisible + + ToolbarSizeMode + 1 + Type + Perspectives + UpdateMessage + + WindowJustification + 5 + WindowOrderList + + /Users/johnc/dev/utils/doomtool/doomtool.xcodeproj + + WindowString + 478 100 1068 921 0 0 1680 1028 + WindowToolsV3 + + + Identifier + windowTool.debugger + Layout + + + Dock + + + ContentConfiguration + + Debugger + + HorizontalSplitView + + _collapsingFrameDimension + 0.0 + _indexOfCollapsedView + 0 + _percentageOfCollapsedView + 0.0 + isCollapsed + yes + sizes + + {{0, 0}, {317, 164}} + {{317, 0}, {377, 164}} + + + VerticalSplitView + + _collapsingFrameDimension + 0.0 + _indexOfCollapsedView + 0 + _percentageOfCollapsedView + 0.0 + isCollapsed + yes + sizes + + {{0, 0}, {694, 164}} + {{0, 164}, {694, 216}} + + + + 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, 380}} + RubberWindowFrame + 321 238 694 422 0 0 1440 878 + + Module + PBXDebugSessionModule + Proportion + 100% + + + Proportion + 100% + + + Name + Debugger + ServiceClasses + + PBXDebugSessionModule + + StatusbarIsVisible + 1 + TableOfContents + + 1CD10A99069EF8BA00B06720 + 1C0AD2AB069F1E9B00FABCE6 + 1C162984064C10D400B95A72 + 1C0AD2AC069F1E9B00FABCE6 + + ToolbarConfiguration + xcode.toolbar.config.debugV3 + WindowString + 321 238 694 422 0 0 1440 878 + WindowToolGUID + 1CD10A99069EF8BA00B06720 + WindowToolIsVisible + 0 + + + Identifier + windowTool.build + Layout + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + 1CD0528F0623707200166675 + PBXProjectModuleLabel + <No Editor> + PBXSplitModuleInNavigatorKey + + Split0 + + PBXProjectModuleGUID + 1CD052900623707200166675 + + SplitCount + 1 + + StatusBarVisibility + 1 + + GeometryConfiguration + + Frame + {{0, 0}, {500, 215}} + RubberWindowFrame + 192 257 500 500 0 0 1280 1002 + + Module + PBXNavigatorGroup + Proportion + 218pt + + + BecomeActive + 1 + ContentConfiguration + + PBXProjectModuleGUID + XCMainBuildResultsModuleGUID + PBXProjectModuleLabel + Build + + GeometryConfiguration + + Frame + {{0, 222}, {500, 236}} + RubberWindowFrame + 192 257 500 500 0 0 1280 1002 + + Module + PBXBuildResultsModule + Proportion + 236pt + + + Proportion + 458pt + + + Name + Build Results + ServiceClasses + + PBXBuildResultsModule + + StatusbarIsVisible + 1 + TableOfContents + + 1C78EAA5065D492600B07095 + 1C78EAA6065D492600B07095 + 1CD0528F0623707200166675 + XCMainBuildResultsModuleGUID + + ToolbarConfiguration + xcode.toolbar.config.buildV3 + WindowString + 192 257 500 500 0 0 1280 1002 + + + Identifier + windowTool.find + Layout + + + Dock + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + 1CDD528C0622207200134675 + PBXProjectModuleLabel + <No Editor> + PBXSplitModuleInNavigatorKey + + Split0 + + PBXProjectModuleGUID + 1CD0528D0623707200166675 + + SplitCount + 1 + + StatusBarVisibility + 1 + + GeometryConfiguration + + Frame + {{0, 0}, {781, 167}} + RubberWindowFrame + 62 385 781 470 0 0 1440 878 + + Module + PBXNavigatorGroup + Proportion + 781pt + + + Proportion + 50% + + + BecomeActive + 1 + ContentConfiguration + + PBXProjectModuleGUID + 1CD0528E0623707200166675 + PBXProjectModuleLabel + Project Find + + GeometryConfiguration + + Frame + {{8, 0}, {773, 254}} + RubberWindowFrame + 62 385 781 470 0 0 1440 878 + + Module + PBXProjectFindModule + Proportion + 50% + + + Proportion + 428pt + + + Name + Project Find + ServiceClasses + + PBXProjectFindModule + + StatusbarIsVisible + 1 + TableOfContents + + 1C530D57069F1CE1000CFCEE + 1C530D58069F1CE1000CFCEE + 1C530D59069F1CE1000CFCEE + 1CDD528C0622207200134675 + 1C530D5A069F1CE1000CFCEE + 1CE0B1FE06471DED0097A5F4 + 1CD0528E0623707200166675 + + WindowString + 62 385 781 470 0 0 1440 878 + WindowToolGUID + 1C530D57069F1CE1000CFCEE + WindowToolIsVisible + 0 + + + Identifier + windowTool.snapshots + Layout + + + Dock + + + Module + XCSnapshotModule + Proportion + 100% + + + Proportion + 100% + + + Name + Snapshots + ServiceClasses + + XCSnapshotModule + + StatusbarIsVisible + Yes + ToolbarConfiguration + xcode.toolbar.config.snapshots + WindowString + 315 824 300 550 0 0 1440 878 + WindowToolIsVisible + Yes + + + FirstTimeWindowDisplayed + + Identifier + windowTool.debuggerConsole + IsVertical + + Layout + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + 1C78EAAC065D492600B07095 + PBXProjectModuleLabel + Debugger Console + + GeometryConfiguration + + Frame + {{0, 0}, {440, 359}} + RubberWindowFrame + 1052 594 440 400 0 0 1680 1028 + + Module + PBXDebugCLIModule + Proportion + 359pt + + + Proportion + 359pt + + + Name + Debugger Console + ServiceClasses + + PBXDebugCLIModule + + StatusbarIsVisible + + TableOfContents + + 1C530D5B069F1CE1000CFCEE + 72C8D1E00F93918C00C6F3E2 + 1C78EAAC065D492600B07095 + + ToolbarConfiguration + xcode.toolbar.config.consoleV3 + WindowString + 1052 594 440 400 0 0 1680 1028 + WindowToolGUID + 1C530D5B069F1CE1000CFCEE + 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.scmV3 + 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 + 3 + MinorVersion + 0 + Name + Breakpoints + ServiceClasses + + PBXSmartGroupTreeModule + XCDetailModule + + StatusbarIsVisible + 1 + TableOfContents + + 1CDDB66807F98D9800BB5817 + 1CDDB66907F98D9800BB5817 + 1CE0B1FE06471DED0097A5F4 + 1CA1AED706398EBD00589147 + + ToolbarConfiguration + xcode.toolbar.config.breakpointsV3 + 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.debugAnimatorV3 + WindowString + 100 100 700 500 0 0 1280 1002 + + + Identifier + windowTool.bookmarks + Layout + + + Dock + + + Module + PBXBookmarksModule + Proportion + 166pt + + + Proportion + 166pt + + + Name + Bookmarks + ServiceClasses + + PBXBookmarksModule + + StatusbarIsVisible + 0 + WindowString + 538 42 401 187 0 0 1280 1002 + + + Identifier + windowTool.projectFormatConflicts + Layout + + + Dock + + + Module + XCProjectFormatConflictsModule + Proportion + 100% + + + Proportion + 100% + + + Name + Project Format Conflicts + ServiceClasses + + XCProjectFormatConflictsModule + + StatusbarIsVisible + 0 + WindowContentMinSize + 450 300 + WindowString + 50 850 472 307 0 0 1440 877 + + + Identifier + windowTool.classBrowser + Layout + + + Dock + + + BecomeActive + 1 + ContentConfiguration + + OptionsSetName + Hierarchy, all classes + PBXProjectModuleGUID + 1CA6456E063B45B4001379D8 + PBXProjectModuleLabel + Class Browser - NSObject + + GeometryConfiguration + + ClassesFrame + {{0, 0}, {369, 96}} + ClassesTreeTableConfiguration + + PBXClassNameColumnIdentifier + 208 + PBXClassBookColumnIdentifier + 22 + + Frame + {{0, 0}, {616, 353}} + MembersFrame + {{0, 105}, {369, 395}} + MembersTreeTableConfiguration + + PBXMemberTypeIconColumnIdentifier + 22 + PBXMemberNameColumnIdentifier + 216 + PBXMemberTypeColumnIdentifier + 94 + PBXMemberBookColumnIdentifier + 22 + + PBXModuleWindowStatusBarHidden2 + 1 + RubberWindowFrame + 597 125 616 374 0 0 1280 1002 + + Module + PBXClassBrowserModule + Proportion + 354pt + + + Proportion + 354pt + + + Name + Class Browser + ServiceClasses + + PBXClassBrowserModule + + StatusbarIsVisible + 0 + TableOfContents + + 1C78EABA065D492600B07095 + 1C78EABB065D492600B07095 + 1CA6456E063B45B4001379D8 + + ToolbarConfiguration + xcode.toolbar.config.classbrowser + WindowString + 597 125 616 374 0 0 1280 1002 + + + Identifier + windowTool.refactoring + IncludeInToolsMenu + 0 + Layout + + + Dock + + + BecomeActive + 1 + GeometryConfiguration + + Frame + {0, 0}, {500, 335} + RubberWindowFrame + {0, 0}, {500, 335} + + Module + XCRefactoringModule + Proportion + 100% + + + Proportion + 100% + + + Name + Refactoring + ServiceClasses + + XCRefactoringModule + + WindowString + 200 200 500 356 0 0 1920 1200 + + + + diff --git a/DoomClassic/doomtool/doomtool.xcodeproj/project.pbxproj b/DoomClassic/doomtool/doomtool.xcodeproj/project.pbxproj new file mode 100755 index 0000000..f3b594b --- /dev/null +++ b/DoomClassic/doomtool/doomtool.xcodeproj/project.pbxproj @@ -0,0 +1,207 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 45; + objects = { + +/* Begin PBXBuildFile section */ + 8DD76FAC0486AB0100D96B5E /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 08FB7796FE84155DC02AAC07 /* main.c */; settings = {ATTRIBUTES = (); }; }; + 8DD76FB00486AB0100D96B5E /* doomtool.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = C6A0FF2C0290799A04C91782 /* doomtool.1 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 8DD76FAF0486AB0100D96B5E /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + 8DD76FB00486AB0100D96B5E /* doomtool.1 in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 08FB7796FE84155DC02AAC07 /* main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = ""; }; + 72B4A70A0FAB70B100DC59D9 /* base.parm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = base.parm; path = ../../iphone/doom/base.parm; sourceTree = SOURCE_ROOT; }; + 72C01AB40F8CFCA900DE72D8 /* doomtool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = doomtool.h; sourceTree = ""; }; + 8DD76FB20486AB0100D96B5E /* doomtool */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = doomtool; sourceTree = BUILT_PRODUCTS_DIR; }; + C6A0FF2C0290799A04C91782 /* doomtool.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = doomtool.1; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 8DD76FAD0486AB0100D96B5E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 08FB7794FE84155DC02AAC07 /* doomtool */ = { + isa = PBXGroup; + children = ( + 72B4A70A0FAB70B100DC59D9 /* base.parm */, + 08FB7795FE84155DC02AAC07 /* Source */, + C6A0FF2B0290797F04C91782 /* Documentation */, + 1AB674ADFE9D54B511CA2CBB /* Products */, + ); + name = doomtool; + sourceTree = ""; + }; + 08FB7795FE84155DC02AAC07 /* Source */ = { + isa = PBXGroup; + children = ( + 72C01AB40F8CFCA900DE72D8 /* doomtool.h */, + 08FB7796FE84155DC02AAC07 /* main.c */, + ); + name = Source; + sourceTree = ""; + }; + 1AB674ADFE9D54B511CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + 8DD76FB20486AB0100D96B5E /* doomtool */, + ); + name = Products; + sourceTree = ""; + }; + C6A0FF2B0290797F04C91782 /* Documentation */ = { + isa = PBXGroup; + children = ( + C6A0FF2C0290799A04C91782 /* doomtool.1 */, + ); + name = Documentation; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 8DD76FA90486AB0100D96B5E /* doomtool */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1DEB928508733DD80010E9CD /* Build configuration list for PBXNativeTarget "doomtool" */; + buildPhases = ( + 8DD76FAB0486AB0100D96B5E /* Sources */, + 8DD76FAD0486AB0100D96B5E /* Frameworks */, + 8DD76FAF0486AB0100D96B5E /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = doomtool; + productInstallPath = "$(HOME)/bin"; + productName = doomtool; + productReference = 8DD76FB20486AB0100D96B5E /* doomtool */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 08FB7793FE84155DC02AAC07 /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "doomtool" */; + compatibilityVersion = "Xcode 3.1"; + hasScannedForEncodings = 1; + mainGroup = 08FB7794FE84155DC02AAC07 /* doomtool */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 8DD76FA90486AB0100D96B5E /* doomtool */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 8DD76FAB0486AB0100D96B5E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8DD76FAC0486AB0100D96B5E /* main.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 1DEB928608733DD80010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_MODEL_TUNING = G5; + GCC_OPTIMIZATION_LEVEL = 0; + INSTALL_PATH = /usr/local/bin; + PRODUCT_NAME = doomtool; + }; + name = Debug; + }; + 1DEB928708733DD80010E9CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_MODEL_TUNING = G5; + INSTALL_PATH = /usr/local/bin; + PRODUCT_NAME = doomtool; + }; + name = Release; + }; + 1DEB928A08733DD80010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + ONLY_ACTIVE_ARCH = YES; + PREBINDING = NO; + SDKROOT = macosx10.5; + }; + name = Debug; + }; + 1DEB928B08733DD80010E9CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + PREBINDING = NO; + SDKROOT = macosx10.5; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1DEB928508733DD80010E9CD /* Build configuration list for PBXNativeTarget "doomtool" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB928608733DD80010E9CD /* Debug */, + 1DEB928708733DD80010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "doomtool" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB928A08733DD80010E9CD /* Debug */, + 1DEB928B08733DD80010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 08FB7793FE84155DC02AAC07 /* Project object */; +} diff --git a/DoomClassic/doomtool/doomtool.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/doomtool.xcscheme b/DoomClassic/doomtool/doomtool.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/doomtool.xcscheme new file mode 100755 index 0000000..e570846 --- /dev/null +++ b/DoomClassic/doomtool/doomtool.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/doomtool.xcscheme @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/DoomClassic/doomtool/doomtool.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/xcschememanagement.plist b/DoomClassic/doomtool/doomtool.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100755 index 0000000..73b7004 --- /dev/null +++ b/DoomClassic/doomtool/doomtool.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,22 @@ + + + + + SchemeUserState + + doomtool.xcscheme + + orderHint + 14 + + + SuppressBuildableAutocreation + + 8DD76FA90486AB0100D96B5E + + primary + + + + + diff --git a/DoomClassic/doomtool/main.c b/DoomClassic/doomtool/main.c new file mode 100755 index 0000000..e353e57 --- /dev/null +++ b/DoomClassic/doomtool/main.c @@ -0,0 +1,1716 @@ +#include +#include +#include + +/* + + store sprites in an atlas, or as discrete textures? + + store audio as 16 bit for direct mmap access, or 4 bit adpcm with dynamic decompress? + + render without a depth buffer? NO: it wold defeat the deferred rendering ability + + optional script file with extra parameters + + + youtube script + -------------- + ipod music + music icon + landscape orientation + skill level + start game on any episode / map combination + controls + doors opening + shooting + damage indicators + leave game at any time + custom controls + items in the world (ammo, health, treasure, weapons, keys) + changing weapons + secret doors + finishing the level + awards + + + + TASKS: + Web page time check + Data download + Hardware mp3 playback, remove tremor + Independent volume adjustment + Broadcast packet tests + Good console + web media type for game launch and download + Instrumented play data recording + + */ + +#include +#include // for repeat and filter enums +#include +typedef unsigned char byte; + +#include "doomtool.h" + +const char *assetDirectory = "/Volumes/Work/idMobileDepot/Archive/DoomClassicDepot/assets"; +const char *outputFile = "/Volumes/Work/idMobileDepot/Archive/DoomClassicDepot/base.iPack"; +const char *parmFile = "/Volumes/Work/idMobileDepot/Archive/DoomClassicDepot/base.parm"; + +pkHeader_t buildHeader; +FILE *pakFile; +#define MAX_IMAGE_TABLE 10000 +pkTextureData_t buildTextureTable[MAX_IMAGE_TABLE]; +#define MAX_WAV_TABLE 10000 +pkWavData_t buildWavTable[MAX_WAV_TABLE]; +#define MAX_RAW_TABLE 10000 +pkRawData_t buildRawTable[MAX_RAW_TABLE]; + +// the doom extractor tool writes this out for alpha texels +#define DOOM_ALPHA_TEXEL 0xff00ffff + +// the parm file is parsed for modifiers to specify image formats, etc +#define MAX_ARGV 16 +typedef struct { + int argc; + char *argv[MAX_ARGV]; // argv[0] should be a filename local to the asset base +} parmLine_t; + +#define MAX_PARM_LINES 10000 +parmLine_t parmLines[MAX_PARM_LINES]; +int numParmLines; + +void Error( const char *fmt, ... ) { + va_list argptr; + va_start( argptr, fmt ); + + vprintf( fmt, argptr ); + exit( 1 ); +} + +int FileLength( FILE *f ) { + fseek( f, 0, SEEK_END ); + int len = ftell( f ); + fseek( f, 0, SEEK_SET ); + return len; +} + +//==================================================================== + +const byte *iff_pdata; +const byte *iff_end; +const byte *iff_last_chunk; +const byte *iff_data; +int iff_chunk_len; + + +short Wav_GetLittleShort( void ) +{ + short val = 0; + + val = *iff_pdata; + val += (*(iff_pdata + 1) << 8); + + iff_pdata += 2; + + return val; +} + + +int Wav_GetLittleLong( void ) +{ + int val = 0; + + val = *iff_pdata; + val += (*(iff_pdata + 1) << 8); + val += (*(iff_pdata + 2) << 16); + val += (*(iff_pdata + 3) << 24); + + iff_pdata += 4; + + return val; +} + + +void Wav_FindNextChunk( const char *name ) +{ + while( 1 ) + { + iff_pdata = iff_last_chunk; + + if( iff_pdata >= iff_end ) + { + // Didn't find the chunk + iff_pdata = NULL; + return; + } + + iff_pdata += 4; + iff_chunk_len = Wav_GetLittleLong(); + if( iff_chunk_len < 0 ) + { + iff_pdata = NULL; + return; + } + + iff_pdata -= 8; + iff_last_chunk = iff_pdata + 8 + ((iff_chunk_len + 1) & ~1); + if( ! strncasecmp((const char *)iff_pdata, name, 4) ) + { + return; + } + } +} + + +void Wav_FindChunk( const char *name ) +{ + iff_last_chunk = iff_data; + + Wav_FindNextChunk( name ); +} + +/* + ======================== + AddWAV + + ======================== + */ +void AddWAV( const char *localName, const byte *data, int wavlength ) { + assert( buildHeader.wavs.count < MAX_WAV_TABLE ); + pkWavData_t *wav = &buildWavTable[buildHeader.wavs.count++]; + + iff_data = data; + iff_end = data + wavlength; + + // look for RIFF signature + Wav_FindChunk( "RIFF" ); + if( ! (iff_pdata && ! strncasecmp( (const char *)iff_pdata + 8, "WAVE", 4 ) ) ) { + Error( "[LoadWavInfo]: Missing RIFF/WAVE chunks (%s)\n", localName ); + } + + // Get "fmt " chunk + iff_data = iff_pdata + 12; + + Wav_FindChunk( "fmt " ); + if( ! iff_pdata ) { + Error( "[LoadWavInfo]: Missing fmt chunk (%s)\n", localName ); + } + + iff_pdata += 8; + + if( Wav_GetLittleShort() != 1 ) { + Error( "[LoadWavInfo]: Microsoft PCM format only (%s)\n", localName ); + } + + int channels = Wav_GetLittleShort(); + int sample_rate = Wav_GetLittleLong(); + + iff_pdata += 4; + + // bytes per sample, which includes all channels + // 16 bit stereo = 4 bytes per sample + int sample_size = Wav_GetLittleShort(); + int channelBytes = sample_size / channels; + + if ( channelBytes != 1 && channelBytes != 2 ) { + Error( "[LoadWavInfo]: only 8 and 16 bit WAV files supported (%s)\n", localName ); + } + + iff_pdata += 2; + + // Find data chunk + Wav_FindChunk( "data" ); + if( ! iff_pdata ) { + Error( "[LoadWavInfo]: missing 'data' chunk (%s)\n", localName ); + } + + iff_pdata += 4; + int numSamples = Wav_GetLittleLong() / sample_size; + + if( numSamples <= 0 ) { + Error( "[LoadWavInfo]: file with 0 samples (%s)\n", localName ); + } + + // as of iphone OS 2.2.1, 8 bit samples cause audible pops at the beginning and end, so + // convert them to 16 bit here + const void *samples = data + (iff_pdata - data); +#if 0 + if ( channelBytes == 1 ) { + int numChannelSamples = numSamples * channels; + channelBytes = 2; + sample_size = channelBytes * channels; + short *newSamples = alloca( numChannelSamples * sample_size ); + for ( int i = 0; i < numChannelSamples ; i++ ) { + newSamples[i] = ((short)((const byte *)samples)[i] - 128) * 256; + } + samples = newSamples; + } +#endif + // write out the raw data + strcpy( wav->name.name, localName ); + wav->wavDataOfs = ftell( pakFile ); + fwrite( samples, numSamples, sample_size, pakFile ); + wav->wavChannels = channels; + wav->wavChannelBytes = channelBytes; + wav->wavRate = sample_rate; + wav->wavNumSamples = numSamples; +} + + +/* + ================================================================================================ + + Bitmap Loading (.bmp) + + ================================================================================================ + */ + +typedef struct { + char id[2]; + unsigned int fileSize; + unsigned int reserved0; + unsigned int bitmapDataOffset; + unsigned int bitmapHeaderSize; + unsigned int width; + unsigned int height; + unsigned short planes; + unsigned short bitsPerPixel; + unsigned int compression; + unsigned int bitmapDataSize; + unsigned int hRes; + unsigned int vRes; + unsigned int colors; + unsigned int importantColors; + unsigned char palette[256][4]; +} BMPHeader_t; + +/* + ======================== + LoadBMP + ======================== + */ +static void LoadBMP( const char *name, byte **pic, int *width, int *height ) { + int columns, rows, numPixels; + byte *pixbuf; + int row, column; + byte *buf_p; + byte *buffer; + int length; + BMPHeader_t bmpHeader; + byte *bmpRGBA; + + *pic = NULL; + + // + // load the file + // + FILE *f = fopen( name, "rb" ); + if ( !f ) { + Error( "Can't open '%s'\n", name ); + } + length = FileLength( f ); + buffer = malloc( length ); + fread( buffer, 1, length, f ); + fclose( f ); + + buf_p = buffer; + + bmpHeader.id[0] = *buf_p++; + bmpHeader.id[1] = *buf_p++; + bmpHeader.fileSize = * ( int * ) buf_p; + buf_p += 4; + bmpHeader.reserved0 = * ( int * ) buf_p; + buf_p += 4; + bmpHeader.bitmapDataOffset = * ( int * ) buf_p; + buf_p += 4; + bmpHeader.bitmapHeaderSize = * ( int * ) buf_p; + buf_p += 4; + bmpHeader.width = * ( int * ) buf_p; + buf_p += 4; + bmpHeader.height = * ( int * ) buf_p; + buf_p += 4; + bmpHeader.planes = * ( short * ) buf_p; + buf_p += 2; + bmpHeader.bitsPerPixel = * ( short * ) buf_p; + buf_p += 2; + bmpHeader.compression = * ( int * ) buf_p; + buf_p += 4; + bmpHeader.bitmapDataSize = * ( int * ) buf_p; + buf_p += 4; + bmpHeader.hRes = * ( int * ) buf_p; + buf_p += 4; + bmpHeader.vRes = * ( int * ) buf_p; + buf_p += 4; + bmpHeader.colors = * ( int * ) buf_p; + buf_p += 4; + bmpHeader.importantColors = * ( int * ) buf_p; + buf_p += 4; + + memcpy( bmpHeader.palette, buf_p, sizeof( bmpHeader.palette ) ); + + if ( bmpHeader.bitsPerPixel == 8 ) { + buf_p += 1024; + } + + if ( bmpHeader.id[0] != 'B' && bmpHeader.id[1] != 'M' ) { + Error( "LoadBMP: only Windows-style BMP files supported (%s)\n", name ); + } + if ( bmpHeader.fileSize != length ) { + Error( "LoadBMP: header size does not match file size (%d vs. %d) (%s)\n", bmpHeader.fileSize, length, name ); + } + if ( bmpHeader.compression != 0 ) { + Error( "LoadBMP: only uncompressed BMP files supported (%s)\n", name ); + } + if ( bmpHeader.bitsPerPixel < 8 ) { + Error( "LoadBMP: monochrome and 4-bit BMP files not supported (%s)\n", name ); + } + + columns = bmpHeader.width; + rows = bmpHeader.height; + if ( rows < 0 ) { + rows = -rows; + } + numPixels = columns * rows; + + if ( width ) { + *width = columns; + } + if ( height ) { + *height = rows; + } + + bmpRGBA = (byte *)malloc( numPixels * 4 ); + *pic = bmpRGBA; + + byte *rowStart = buf_p; + for ( row = rows-1; row >= 0; row-- ) { + pixbuf = bmpRGBA + row*columns*4; + buf_p = rowStart; + for ( column = 0; column < columns; column++ ) { + unsigned char red, green, blue, alpha; + int palIndex; + unsigned short shortPixel; + + switch ( bmpHeader.bitsPerPixel ) { + case 8: + palIndex = *buf_p++; + *pixbuf++ = bmpHeader.palette[palIndex][0]; + *pixbuf++ = bmpHeader.palette[palIndex][1]; + *pixbuf++ = bmpHeader.palette[palIndex][2]; + *pixbuf++ = 0xff; + break; + case 16: + shortPixel = * ( unsigned short * ) pixbuf; + pixbuf += 2; + *pixbuf++ = ( shortPixel & ( 31 << 10 ) ) >> 7; + *pixbuf++ = ( shortPixel & ( 31 << 5 ) ) >> 2; + *pixbuf++ = ( shortPixel & ( 31 ) ) << 3; + *pixbuf++ = 0xff; + break; + + case 24: + blue = *buf_p++; + green = *buf_p++; + red = *buf_p++; + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = 255; + break; + case 32: + blue = *buf_p++; + green = *buf_p++; + red = *buf_p++; + alpha = *buf_p++; + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = alpha; + break; + default: + Error( "LoadBMP: illegal pixel_size '%d' in file '%s'\n", bmpHeader.bitsPerPixel, name ); + break; + } + } + // rows are always 32 bit aligned + rowStart += ( ( buf_p - rowStart ) + 3 ) &~3; + } + + free( buffer ); +} + + +//===================================================================================== + +typedef struct TargaHeader_s { + unsigned char id_length; + unsigned char colormap_type; + unsigned char image_type; + unsigned short colormap_index; + unsigned short colormap_length; + unsigned char colormap_size; + unsigned short x_origin; + unsigned short y_origin; + unsigned short width, height; + unsigned char pixel_size; + unsigned char attributes; +} TargaHeaeder_t; + +static const int TGA_HEADER_SIZE = 18; + +/* + ======================== + WriteTGA + + Write a TGA to a buffer. + ======================== + */ +void WriteTGA( byte **bufferOut, size_t *bufferSizeOut, const byte *data, int width, int height, + int sourceDepth, int flipVertical, int swapRGB ) { + size_t i; + int imgStart = TGA_HEADER_SIZE; + + assert( sourceDepth == 1 || sourceDepth == 3 || sourceDepth == 4 ); + + size_t bufferSize = width * height * sourceDepth + TGA_HEADER_SIZE; + *bufferSizeOut = bufferSize; + + byte *buffer = (byte*)malloc( bufferSize ); + *bufferOut = buffer; + + memset( buffer, 0, TGA_HEADER_SIZE ); + + static const int TGA_IMAGETYPE_GREYSCALE = 3; + static const int TGA_IMAGETYPE_RGB = 2; + + buffer[ 2 ] = sourceDepth == 1 ? TGA_IMAGETYPE_GREYSCALE : TGA_IMAGETYPE_RGB; + buffer[ 12 ] = width & 255; + buffer[ 13 ] = width >> 8; + buffer[ 14 ] = height & 255; + buffer[ 15 ] = height >> 8; + buffer[ 16 ] = sourceDepth * 8; // pixel size + if ( !flipVertical ) { + buffer[ 17 ] = ( 1 << 5 ); // flip bit, for normal top to bottom raster order + } + + if ( sourceDepth == 4 ) { + if ( swapRGB ) { + // swap rgb to bgr + for ( i = imgStart ; i < bufferSize ; i += sourceDepth ) { + buffer[ i ] = data[ i - imgStart + 2 ]; // blue + buffer[ i + 1 ] = data[ i - imgStart + 1 ]; // green + buffer[ i + 2 ] = data[ i - imgStart ]; // red + buffer[ i + 3 ] = data[ i - imgStart + 3 ]; // alpha + } + } else { + memcpy( buffer + imgStart, data, bufferSize - TGA_HEADER_SIZE ); + } + } else if ( sourceDepth == 3 ) { + if ( swapRGB ) { + for ( i = imgStart ; i < bufferSize ; i += sourceDepth ) { + buffer[ i ] = data[ i - imgStart + 2 ]; // blue + buffer[ i + 1 ] = data[ i - imgStart + 1 ]; // green + buffer[ i + 2 ] = data[ i - imgStart + 0 ]; // red + } + } else { + for ( i = imgStart ; i < bufferSize ; i += sourceDepth ) { + buffer[ i ] = data[ i - imgStart ]; // blue + buffer[ i + 1 ] = data[ i - imgStart + 1 ]; // green + buffer[ i + 2 ] = data[ i - imgStart + 2 ]; // red + } + } + } else if ( sourceDepth == 1 ) { + memcpy( buffer + imgStart, data, bufferSize - TGA_HEADER_SIZE ); + } +} + +void WriteTGAFile( const char *filename, const byte *pic, int w, int h ) { + byte *buf; + size_t bufLen; + WriteTGA( &buf, &bufLen, pic, w, h, 4, 0, 0 ); + FILE * f = fopen( filename, "wb" ); + assert( f ); + fwrite( buf, bufLen, 1, f ); + fclose( f ); + free( buf ); +} + +/* + ======================== + LoadTGAFromBuffer + + Load a TGA from a buffer containing a TGA file. + ======================== + */ +int LoadTGAFromBuffer( const char *name, const unsigned char *buffer, const int bufferSize, + unsigned char **pic, int *width, int *height ) { + int columns, rows, numPixels; + size_t numBytes; + unsigned char *pixbuf; + int row, column; + const unsigned char *buf_p; + struct TargaHeader_s targa_header; + unsigned char *targa_rgba; + + *pic = NULL; + + buf_p = buffer; + + targa_header.id_length = *buf_p++; + targa_header.colormap_type = *buf_p++; + targa_header.image_type = *buf_p++; + + targa_header.colormap_index = *(short *)buf_p; + buf_p += 2; + targa_header.colormap_length = *(short *)buf_p; + buf_p += 2; + targa_header.colormap_size = *buf_p++; + targa_header.x_origin = *(short *)buf_p; + buf_p += 2; + targa_header.y_origin = *(short *)buf_p; + buf_p += 2; + targa_header.width = *(short *)buf_p; + buf_p += 2; + targa_header.height = *(short *)buf_p; + buf_p += 2; + targa_header.pixel_size = *buf_p++; + targa_header.attributes = *buf_p++; + + if ( targa_header.image_type != 2 && targa_header.image_type != 10 && targa_header.image_type != 3 ) { + printf( "LoadTGA( %s ): Only type 2 (RGB), 3 (gray), and 10 (RGB) TGA images supported", name ); + return 0; + } + + if ( targa_header.colormap_type != 0 ) { + printf( "LoadTGA( %s ): colormaps not supported", name ); + return 0; + } + + if ( ( targa_header.pixel_size != 32 && targa_header.pixel_size != 24 ) && targa_header.image_type != 3 ) { + printf( "LoadTGA( %s ): Only 32 or 24 bit images supported (no colormaps)", name ); + return 0; + } + + if ( targa_header.image_type == 2 || targa_header.image_type == 3 ) { + numBytes = targa_header.width * targa_header.height * ( targa_header.pixel_size >> 3 ); + if ( numBytes > bufferSize - TGA_HEADER_SIZE - targa_header.id_length ) { + printf( "LoadTGA( %s ): incomplete file", name ); + return 0; + } + } + + columns = targa_header.width; + rows = targa_header.height; + numPixels = columns * rows; + + if ( width ) { + *width = columns; + } + if ( height ) { + *height = rows; + } + + targa_rgba = (unsigned char *)malloc( numPixels*4 ); + *pic = targa_rgba; + + if ( targa_header.id_length != 0 ) { + buf_p += targa_header.id_length; // skip TARGA image comment + } + + if ( targa_header.image_type == 2 || targa_header.image_type == 3 ) { + unsigned char red,green,blue,alphabyte; + switch( targa_header.pixel_size ) { + case 8: + // Uncompressed gray scale image + for( row = rows - 1; row >= 0; row-- ) { + pixbuf = targa_rgba + row*columns*4; + for( column = 0; column < columns; column++ ) { + blue = *buf_p++; + green = blue; + red = blue; + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = 255; + } + } + break; + case 24: + // Uncompressed RGB image + for( row = rows - 1; row >= 0; row-- ) { + pixbuf = targa_rgba + row*columns*4; + for( column = 0; column < columns; column++ ) { + blue = *buf_p++; + green = *buf_p++; + red = *buf_p++; + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = 255; + } + } + break; + case 32: + // Uncompressed RGBA image + for( row = rows - 1; row >= 0; row-- ) { + pixbuf = targa_rgba + row*columns*4; + for( column = 0; column < columns; column++ ) { + blue = *buf_p++; + green = *buf_p++; + red = *buf_p++; + alphabyte = *buf_p++; + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = alphabyte; + } + } + break; + default: + printf( "LoadTGA( %s ): illegal pixel_size '%d'", name, targa_header.pixel_size ); + free( *pic ); + *pic = NULL; + return 0; + } + } + else if ( targa_header.image_type == 10 ) { // Runlength encoded RGB images + unsigned char red,green,blue,alphabyte,packetHeader,packetSize,j; + + red = 0; + green = 0; + blue = 0; + alphabyte = 0xff; + + for( row = rows - 1; row >= 0; row-- ) { + pixbuf = targa_rgba + row*columns*4; + for( column = 0; column < columns; ) { + packetHeader= *buf_p++; + packetSize = 1 + (packetHeader & 0x7f); + if ( packetHeader & 0x80 ) { // run-length packet + switch( targa_header.pixel_size ) { + case 24: + blue = *buf_p++; + green = *buf_p++; + red = *buf_p++; + alphabyte = 255; + break; + case 32: + blue = *buf_p++; + green = *buf_p++; + red = *buf_p++; + alphabyte = *buf_p++; + break; + default: + printf( "LoadTGA( %s ): illegal pixel_size '%d'", name, targa_header.pixel_size ); + free( *pic ); + *pic = NULL; + return 0; + } + + for( j = 0; j < packetSize; j++ ) { + *pixbuf++=red; + *pixbuf++=green; + *pixbuf++=blue; + *pixbuf++=alphabyte; + column++; + if ( column == columns ) { // run spans across rows + column = 0; + if ( row > 0) { + row--; + } + else { + goto breakOut; + } + pixbuf = targa_rgba + row*columns*4; + } + } + } else { // non run-length packet + for( j = 0; j < packetSize; j++ ) { + switch( targa_header.pixel_size ) { + case 24: + blue = *buf_p++; + green = *buf_p++; + red = *buf_p++; + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = 255; + break; + case 32: + blue = *buf_p++; + green = *buf_p++; + red = *buf_p++; + alphabyte = *buf_p++; + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = alphabyte; + break; + default: + printf( "LoadTGA( %s ): illegal pixel_size '%d'", name, targa_header.pixel_size ); + free( *pic ); + *pic = NULL; + return 0; + } + column++; + if ( column == columns ) { // pixel packet run spans across rows + column = 0; + if ( row > 0 ) { + row--; + } + else { + goto breakOut; + } + pixbuf = targa_rgba + row*columns*4; + } + } + } + } + breakOut: ; + } + } + + if ( (targa_header.attributes & (1<<5)) ) { // image flp bit + byte *temp = malloc( *width * *height * 4 ); + memcpy( temp, *pic, *width * *height * 4 ); + + for ( int y = 0 ; y < *height ; y++ ) { + memcpy( *pic + y * *width * 4, temp + (*height-1-y) * *width * 4, *width * 4 ); + } + free( temp ); + } + + return 1; +} + +/* + ======================== + LoadTGA + + Load TGA directly from a file. + ======================== + */ +int LoadTGA( const char *name, unsigned char **pic, int *width, int *height ) { + int len; + unsigned char *buf; + int ret; + + FILE *f = fopen( name, "rb" ); + if ( !f ) { + return 0; + } + len = FileLength( f ); + buf = malloc( len ); + fread( buf, 1, len, f ); + fclose( f ); + + ret = LoadTGAFromBuffer( name, buf, len, pic, width, height ); + + free( buf ); + + return ret; +} + +void OutlineImage( unsigned char *rgba, int width, int height ) { + unsigned char *data_p; + unsigned char *copy_p; + unsigned char *copy = (unsigned char *)alloca( width * height * 4 ); + int x, y; + + memcpy( copy, rgba, width * height * 4 ); + data_p = rgba; + copy_p = copy; + + for ( y = 0 ; y < height ; y++ ) { + for ( x = 0 ; x < width ; x++, data_p+=4, copy_p+=4 ) { + if ( data_p[3] != 0 ) { + continue; + } + if ( x < width-1 && copy_p[7] != 0 ) { + *(int *)data_p = ((int *)copy_p)[1]; + } else if ( x > 0 && copy_p[-1] != 0 ) { + *(int *)data_p = ((int *)copy_p)[-1]; + } else if ( y < height-1 && copy_p[width*4+3] != 0 ) { + *(int *)data_p = ((int *)copy_p)[width]; + } else if ( y > 0 && copy_p[-width*4+3] != 0 ) { + *(int *)data_p = ((int *)copy_p)[-width]; + } + data_p[3] = 1; + } + } +} + +int RowClear( unsigned char *rgba, int w, int h, int y ) { + int x; + for ( x = 0 ; x < w ; x++ ) { + if ( rgba[(y*w+x)*4+3] != 0 ) { + return 0; + } + } + return 1; +} + + + +int NextPowerOfTwo( int n ) { + int p = 1; + + while ( p < n ) { + p <<= 1; + } + return p; +} + +/* + ======================== + AddTGA + + ======================== + */ +void AddTGA( const char *localName, const byte *data, int dataLen ) { + assert( buildHeader.textures.count < MAX_IMAGE_TABLE ); + pkTextureData_t *image = &buildTextureTable[buildHeader.textures.count++]; + strcpy( image->name.name, localName ); + image->picDataOfs = ftell( pakFile ); + + // load it + unsigned char *pic; + int width, height; + + if ( !LoadTGAFromBuffer( localName, data, dataLen, &pic, &width, &height ) ) { + Error( "failed.\n" ); + } + + // scan for alpha + int hasAlpha = 0; + for ( int i = 0 ; i < width*height ; i++ ) { + if ( pic[i*4+3] != 255 ) { + hasAlpha = 1; + break; + } + } + + // default image format + image->format = TF_5551; + + // scan the parmLines for this filename + for ( int i = 0 ; i < numParmLines ; i++ ) { + if ( !strcasecmp( parmLines[i].argv[0], localName ) ) { + for ( int j = 1 ; j < parmLines[i].argc ; j++ ) { + if ( !strcmp( parmLines[i].argv[j], "5551" ) ) { + image->format = TF_5551; + } else if ( !strcmp( parmLines[i].argv[j], "4444" ) ) { + image->format = TF_4444; + } else if ( !strcmp( parmLines[i].argv[j], "565" ) ) { + image->format = TF_565; + } else if ( !strcmp( parmLines[i].argv[j], "8888" ) ) { + image->format = TF_8888; + } else if ( !strcmp( parmLines[i].argv[j], "LA" ) ) { + image->format = TF_LA; + } else if ( !strcmp( parmLines[i].argv[j], "PVR4" ) ) { + if ( hasAlpha ) { + image->format = TF_PVR4; + } else { + image->format = TF_PVR4A; + } + } else if ( !strcmp( parmLines[i].argv[j], "PVR2" ) ) { + if ( hasAlpha ) { + image->format = TF_PVR2; + } else { + image->format = TF_PVR2A; + } + } else { + printf( "bad parm '%s'\n", parmLines[i].argv[j] ); + } + } + break; + } + } + + + + // set this true if we need to write a new tga out for compression + // because we modified it in some way from the original (make power of 2, sprite outline, etc) + int imageModified = 0; + + // make sure it is a power of two + int potW = NextPowerOfTwo( width ); + int potH = NextPowerOfTwo( height ); + + // the texturetool compressor only supports square textures as of iphone OS 2.2.1 + // Not sure if that is a hardware limit or just software. This throws away + // some of the space savings, but it is still a speed savings to use. + if ( image->format == TF_PVR4 || image->format == TF_PVR2 ) { + if ( potW > potH ) { + potH = potW; + } + if ( potH > potW ) { + potW = potH; + } + } + + if ( potW > width || potH > height ) { + printf( "Insetting %i x %i image in %i x %i block\n", width, height, potW, potH ); + unsigned char *newPic = (unsigned char *)malloc( potW * potH * 4 ); + // replicating the last row or column might be better + if ( hasAlpha ) { + memset( newPic, 0, potW * potH * 4 ); + } else { + memset( newPic, 255, potW * potH * 4 ); + } + for ( int y = 0 ; y < height ; y++ ) { + memcpy( newPic + y * potW * 4, pic + y * width * 4, width * 4 ); + } + free( pic ); + pic = newPic; + imageModified = 1; + } + + image->srcWidth = width; + image->srcHeight = height; + image->uploadWidth = potW; + image->uploadHeight = potH; + + image->wrapS = GL_REPEAT; + image->wrapT = GL_REPEAT; + image->minFilter = GL_LINEAR_MIPMAP_NEAREST; + image->magFilter = GL_LINEAR; + image->aniso = 1; + image->numLevels = 0; + image->maxS = (float)image->srcWidth / image->uploadWidth; + image->maxT = (float)image->srcHeight / image->uploadHeight; + + int w = image->uploadWidth; + int h = image->uploadHeight; + + // determine the number of mip levels. We can't just count as + // we create them, because the PVRTC texturetool creates them + // all in one run + int max = w > h ? w : h; + while ( max >= 1 ) { + image->numLevels++; + max >>= 1; + } + + // checkerboard debug tool for testing texel centers + int checker = 0; + if ( checker ) { + for ( int y = 0 ; y < height ; y++ ) { + for ( int x = 0 ; x < width ; x++ ) { + if ( (x^y)&1 ) { + *((int *)pic+y*potW+x) = -1; + } else { + *((int *)pic+y*potW+x) = 0; + } + } + } + imageModified = 1; + } + + // sprite image outlining to avoid bilinear filter halos + int sprite = 0; + if ( sprite ) { + for ( int i = 0 ; i < 8 ; i++ ) { + OutlineImage( pic, width, height ); + } + for ( int i = 0 ; i < width*height ; i++ ) { + if ( pic[i*4+3] == 1 ) { + pic[i*4+3] = 0; + } + } + imageModified = 1; + } + + //----------------------------------------- + // scan for bounding box of opaque texels + //----------------------------------------- + if ( !hasAlpha ) { + image->numBounds = 0; + } else { + int x, y; + + // find the bounding boxes for more efficient drawing + image->numBounds = 1; + for ( y = 0 ; y < h ; y++ ) { + if ( !RowClear( pic, w, h, y ) ) { + // this row is needed + image->bounds[0][0][1] = y; + break; + } + } + for ( y = h-1 ; y >= 0 ; y-- ) { + if ( !RowClear( pic, w, h, y ) ) { + // this row is needed + image->bounds[0][1][1] = y; + break; + } + } + + // if the middle row is clear, make two boxes + // We could make a better test, but this catches the ones we care about... + if ( image->bounds[0][0][1] < h/2 && image->bounds[0][1][1] > h / 2 + && RowClear( pic, w, h, h/2 ) ) { + image->numBounds = 2; + image->bounds[1][1][1] = image->bounds[0][1][1]; + + for ( y = h/2-1 ; y >= 0 ; y-- ) { + if ( !RowClear( pic, w, h, y ) ) { + image->bounds[0][1][1] = y; + break; + } + } + for ( y = h/2+1 ; y < h ; y++ ) { + if ( !RowClear( pic, w, h, y ) ) { + image->bounds[1][0][1] = y; + break; + } + } + } + + for ( int b = 0 ; b < image->numBounds ; b++ ) { + for ( x = 0 ; x < w ; x++ ) { + for ( y = image->bounds[b][0][1] ; y <= image->bounds[b][1][1] ; y++ ) { + if ( pic[(y*w+x)*4+3] != 0 ) { + // this column is needed + image->bounds[b][0][0] = x; + break; + } + } + if ( y <= image->bounds[b][1][1] ) { + break; + } + } + for ( x = w-1 ; x >= 0 ; x-- ) { + for ( y = image->bounds[b][0][1] ; y <= image->bounds[b][1][1] ; y++ ) { + if ( pic[(y*w+x)*4+3] != 0 ) { + // this column is needed + image->bounds[b][1][0] = x; + break; + } + } + if ( y <= image->bounds[b][1][1] ) { + break; + } + } + } + } + + //----------------------------------------- + // run texturetool to PVR compress and generate all mip levels + // Arguably, we should do the sprite outlining on each mip level + // independently, and PVR compress each layer seperately. + //----------------------------------------- + if ( image->format == TF_PVR4 || image->format == TF_PVR2 + || image->format == TF_PVR4A || image->format == TF_PVR2A ) { + char tempTGAname[L_tmpnam]; + + // write the modified image data out if necessary + if ( imageModified ) { + tmpnam( tempTGAname ); + + WriteTGAFile( tempTGAname, pic, w, h ); + } else { + sprintf( tempTGAname, "%s/%s", assetDirectory, localName ); + } + + // run the external compression tool + // FIXME: use an explicit name and timestamp check + char tempPVRname[L_tmpnam]; + tmpnam( tempPVRname ); + char cmd[1024]; + sprintf( cmd, "/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/texturetool -m -e PVRTC %s -f Raw -o %s %s", + ( image->format == TF_PVR2 || image->format == TF_PVR2A ) ? "--bits-per-pixel-2" : "--bits-per-pixel-4", + tempPVRname, tempTGAname ); + printf( "%s\n", cmd ); + system( cmd ); + + FILE *f = fopen( tempPVRname, "rb" ); + if ( !f ) { + Error( "Can't open '%s'\n", tempPVRname ); + } + int len = FileLength( f ); + unsigned char *raw = alloca( len ); + fread( raw, 1, len, f ); + fclose( f ); + + // write to the pak file + fwrite( raw, 1, len, pakFile ); + + if ( imageModified ) { + remove( tempTGAname ); + } + remove( tempPVRname ); + return; + } + + //----------------------------------------- + // create mip maps and write out simple image formats + //----------------------------------------- + while ( 1 ) { + byte *rgba_p = pic; + + // convert to target format + switch ( image->format ) { + case TF_8888: + { + int * processed = alloca( w * h * 4 ); + int * s_p = processed; + + for ( int i = 0 ; i < w*h ; i++, rgba_p+=4 ) { + int r = rgba_p[0]; + int g = rgba_p[1]; + int b = rgba_p[2]; + int a = rgba_p[3]; + + *s_p++ = (b<<24) | (g<<16) | (r<<8) | a; + } + // write it out + fwrite( processed, w * h, 4, pakFile ); + break; + } + case TF_LA: + { + byte * processed = alloca( w * h * 2 ); + byte * s_p = processed; + + for ( int i = 0 ; i < w*h ; i++, rgba_p+=4 ) { + int l = rgba_p[0]; + int a = rgba_p[1]; // this should probably be [3], but Cass's font renderer saved it out as LA01 + + *s_p++ = l; + *s_p++ = a; + } + // write it out + fwrite( processed, w * h, 2, pakFile ); + break; + } + case TF_5551: + { + short * processed = alloca( w * h * 2 ); + short * s_p = processed; + + for ( int i = 0 ; i < w*h ; i++, rgba_p+=4 ) { + int r = rgba_p[0]; + int g = rgba_p[1]; + int b = rgba_p[2]; + int a = rgba_p[3]; + + *s_p++ = ((r>>3)<<11) | ((g>>3)<<6) | ((b>>3)<<1) | (a>>7); + } + // write it out + fwrite( processed, w * h, 2, pakFile ); + break; + } + case TF_565: + { + short * processed = alloca( w * h * 2 ); + short * s_p = processed; + + for ( int i = 0 ; i < w*h ; i++, rgba_p+=4 ) { + int r = rgba_p[0]; + int g = rgba_p[1]; + int b = rgba_p[2]; + + *s_p++ = ((r>>3)<<11) | ((g>>2)<<5) | (b>>3); + } + // write it out + fwrite( processed, w * h, 2, pakFile ); + break; + } + case TF_4444: + { + short * processed = alloca( w * h * 2 ); + short * s_p = processed; + + for ( int i = 0 ; i < w*h ; i++, rgba_p+=4 ) { + int r = rgba_p[0]; + int g = rgba_p[1]; + int b = rgba_p[2]; + int a = rgba_p[3]; + + *s_p++ = ((r>>4)<<12) | ((g>>4)<<8) | ((b>>4)<<4) | (a>>4); + } + // write it out + fwrite( processed, w * h, 2, pakFile ); + break; + } + default: + Error( "unimplemented format: %i\n", image->format ); + } + + if ( w == 1 && h == 1 ) { + break; + } + // mip map + w >>= 1; + if ( w == 0 ) { + w = 1; + } + h >>= 1; + if ( h == 0 ) { + h = 1; + } + byte *tempMip = alloca( w * h * 4 ); + // FIXME: doesn't handle 2x1 and 1x2 cases properly... + for ( int y = 0 ; y < h ; y++ ) { + for ( int x = 0 ; x < w ; x++ ) { + for ( int c = 0 ; c < 4 ; c++ ) { + tempMip[(y*w+x)*4+c] = ( + pic[((y*2+0)*w*2+(x*2+0))*4+c] + + pic[((y*2+0)*w*2+(x*2+1))*4+c] + + pic[((y*2+1)*w*2+(x*2+0))*4+c] + + pic[((y*2+1)*w*2+(x*2+1))*4+c] ) >> 2; + } + } + } + pic = tempMip; + } + +} + +/* + ======================== + AddRAW + + ======================== + */ +void AddRAW( const char *localName, const byte *data, int dataLen ) { + assert( buildHeader.raws.count < MAX_RAW_TABLE ); + pkRawData_t *raw = &buildRawTable[buildHeader.raws.count++]; + strcpy( raw->name.name, localName ); + raw->rawDataOfs = ftell( pakFile ); + raw->rawDataLen = dataLen; + + fwrite( data, 1, dataLen, pakFile ); + + // always add a 0 after each raw file so text files can be assumed to be + // c-string terminated + byte zero = 0; + fwrite( &zero, 1, 1, pakFile ); +} + +/* + ======================== + AddDirectoryToPak_r + + ======================== + */ +void AddDirectoryToPak_r( const char *localDirName ) { + char fullDirName[MAXPATHLEN]; + + if ( localDirName[0] == '/' ) { + localDirName++; + } + sprintf( fullDirName, "%s/%s", assetDirectory, localDirName ); + printf( "entering %s\n", fullDirName ); + DIR *dir = opendir( fullDirName ); + assert( dir ); + + while( 1 ) { + // make sure the file pointer is 16 byte aligned, since + // we will be referencing it with mmap. Alignment greater than + // 4 might be wasted on iPhone, but it won't be all that much space. + int ofs = ftell( pakFile ); + if ( ofs & 15 ) { + byte pad[16]; + memset( pad, 0, sizeof( pad ) ); + fwrite( pad, 16 - ( ofs & 15 ), 1, pakFile ); + } + + // get the next file in the directory + struct dirent *file = readdir( dir ); + if ( !file ) { + return; + } + + char localFileName[MAXPATHLEN]; + if ( localDirName[0] ) { + sprintf( localFileName, "%s/%s", localDirName, file->d_name ); + } else { + sprintf( localFileName, "%s", file->d_name ); + } + + if ( file->d_name[0] == '.' ) { + // ignore . and .. and hidden files + continue; + } + if ( file->d_type == DT_DIR ) { + // recurse into another directory + AddDirectoryToPak_r( localFileName ); + continue; + } + + // make sure name length fits + assert( strlen( localFileName ) < MAX_PK_NAME - 1 ); + + // load the file + char fullFileName[MAXPATHLEN]; + sprintf( fullFileName, "%s/%s", assetDirectory, localFileName ); + FILE *f = fopen( fullFileName, "rb" ); + if ( !f ) { + Error( "Can't open '%s'\n", localFileName ); + } + int len = FileLength( f ); + unsigned char *raw = malloc( len ); + fread( raw, 1, len, f ); + fclose( f ); + printf( "%8i %s\n", len, localFileName ); + if ( strstr( localFileName, ".tga" ) ) { + AddTGA( localFileName, raw, len ); + } else if ( strstr( localFileName, ".wav" ) ) { + AddWAV( localFileName, raw, len ); + } else { + AddRAW( localFileName, raw, len ); + } + free( raw ); + } +} + +//====================================================================================== + +#define ATLAS_SIZE 1024 +#define ATLAS_EMPTY_ALPHA 128 + +byte atlas[ATLAS_SIZE*ATLAS_SIZE*4]; +int atlasNum = 0; + +int FindSpotInAtlas( int w, int h, int *spotX, int *spotY ) { + int x = 0; + int y = 0; + int maxX = ATLAS_SIZE - w; + int maxY = ATLAS_SIZE - h; + + while( 1 ) { + retry: + for ( int yy = 0 ; yy < h ; yy++ ) { + for ( int xx = 0 ; xx < w ; xx++ ) { + if ( atlas[((y+yy)*ATLAS_SIZE+x+xx)*4+3] != ATLAS_EMPTY_ALPHA ) { + // can't use this spot, skip ahead past this solid mark + x = x + xx + 1; + if ( x > maxX ) { + x = 0; + y++; + if ( y > maxY ) { + return 0; + } + } + goto retry; + } + } + } + *spotX = x; + *spotY = y; + return 1; + } + return 0; +} + +void EmptyAtlas() { + // fill with alpha 128 to signify empty + memset( atlas, 0, sizeof( atlas ) ); + for ( int i = 0 ; i < ATLAS_SIZE * ATLAS_SIZE ; i++ ) { + atlas[i*4+3] = ATLAS_EMPTY_ALPHA; + } +} + +void ClearBlock( int x, int y, int w, int h ) { + // fill with black / alpha 0 + for ( int yy = 0 ; yy < h ; yy++ ) { + memset( atlas + ((y+yy)*ATLAS_SIZE+x)*4, 0, w*4 ); + } +} + +void FinishAtlas() { + char filename[1024]; + + sprintf( filename, "%s/atlas%i.tga", assetDirectory, atlasNum ); + printf( "Writing %s.\n", filename ); + WriteTGAFile( filename, atlas, ATLAS_SIZE, ATLAS_SIZE ); + // this atlas is complete, write it out + atlasNum++; + // clear it and retry the allocation + EmptyAtlas(); +} + + +/* + ======================== + AtlasDirectory + + ======================== + */ +void AtlasDirectory( const char *fullDirName, const char *prefix ) { + printf( "atlasing %s* from %s\n", prefix, fullDirName ); + DIR *dir = opendir( fullDirName ); + assert( dir ); + + int totalSourceTexels = 0; + int totalSourceImages = 0; + int totalBorderedSourceTexels = 0; + int totalPotTexels = 0; + + EmptyAtlas(); + + while( 1 ) { + // get the next file in the directory + struct dirent *file = readdir( dir ); + if ( !file ) { + break; + } + if ( file->d_name[0] == '.' ) { + // ignore . and .. and hidden files + continue; + } +#if 0 + if ( file->d_type == DT_DIR ) { + // recurse into another directory + AddDirectoryToPak_r( localFileName ); + continue; + } +#endif + if ( !strstr( file->d_name, ".BMP" ) && !strstr( file->d_name, ".bmp" ) ) { + continue; + } + + // only grab the specified images + if ( strncmp( file->d_name, prefix, strlen( prefix ) ) ) { + continue; + } + + // load the image + char fullFileName[MAXPATHLEN]; + sprintf( fullFileName, "%s/%s", fullDirName, file->d_name ); + + byte *pic; + int width, height; + LoadBMP( fullFileName, &pic, &width, &height ); + + // add a four pixel border around each sprite for mip map outlines + static const int OUTLINE_WIDTH = 4; + int widthInAtlas = width + 2*OUTLINE_WIDTH; + int heightInAtlas = height + 2*OUTLINE_WIDTH; + + int ax, ay; + + if ( !FindSpotInAtlas( widthInAtlas, heightInAtlas, &ax, &ay ) ) { + FinishAtlas(); + if ( !FindSpotInAtlas( widthInAtlas, heightInAtlas, &ax, &ay ) ) { + Error( "Couldn't allocate %s: %i,%i in empty atlas", fullFileName, width, height ); + } + } + + printf( "%4i, %4i at %4i,%4i: %s\n", width, height, ax, ay, fullFileName ); + totalSourceTexels += width * height; + totalSourceImages++; + totalBorderedSourceTexels += widthInAtlas * heightInAtlas; + totalPotTexels += NextPowerOfTwo( width ) * NextPowerOfTwo( height ); + + // clear the extended border area to fully transparent + ClearBlock( ax, ay, widthInAtlas, heightInAtlas ); + + // copy the actual image into the inset area past the added borders + // for Doom graphics, the color key alpha value is always the top left corner texel + ax += OUTLINE_WIDTH; + ay += OUTLINE_WIDTH; + for ( int y = 0 ; y < height ; y++ ) { + for ( int x = 0 ; x < width ; x++ ) { + int p = ((int *)pic)[y*width+x]; + if ( p == DOOM_ALPHA_TEXEL ) { + ((int *)atlas)[ (ay+y)*ATLAS_SIZE+ax+x ] = 0; + } else { + ((int *)atlas)[ (ay+y)*ATLAS_SIZE+ax+x ] = p; + } + } + } + } + + // process and write out the partially filled atlas + FinishAtlas(); + + printf ("%i soource images\n", totalSourceImages ); + printf ("%i atlas images\n", atlasNum ); + printf ("%6.1fk source texels\n", totalSourceTexels*0.001f ); + printf ("%6.1fk bordered source texels\n", totalBorderedSourceTexels*0.001f ); + printf ("%6.1fk atlas texels\n", atlasNum*ATLAS_SIZE*ATLAS_SIZE*0.001f ); + printf ("%6.1fk power of two inset texels\n", totalPotTexels*0.001f ); +} + +/* + ================== + PK_HashName + + ================== + */ +int PK_HashName( const char *name, char canonical[MAX_PK_NAME] ) { + int o = 0; + int hash = 0; + + do { + int c = name[o]; + if ( c == 0 ) { + break; + } + // backslashes to forward slashes + if ( c == '\\' ) { + c = '/'; + } + // to lowercase + c = tolower( c ); + canonical[o++] = c; + hash = (hash << 5) - hash + c; + } while ( o < MAX_PK_NAME-1 ); + canonical[o] = 0; + + return hash; +} + + +/* + ======================== + WriteType + + ======================== + */ +void WriteType( FILE *pakFile, pkType_t *type, int structSize, pkName_t *table ) { + type->structSize = structSize; + type->tableOfs = ftell( pakFile ); + + // build hash chains for everything + for ( int i = 0 ; i < PK_HASH_CHAINS ; i++ ) { + type->hashChains[i] = -1; + } + for ( int i = 0 ; i < type->count ; i++ ) { + pkName_t *name = (pkName_t *)((unsigned char *)table + i * structSize ); + char original[MAX_PK_NAME]; + strcpy( original, name->name ); + // make the name canonical and get the hash + name->nameHash = PK_HashName( original, name->name ); + + // add it to the hash chain + int chain = name->nameHash & (PK_HASH_CHAINS-1); + name->nextOnHashChain = type->hashChains[chain]; + type->hashChains[chain] = i; + } + + fwrite( table, type->count, type->structSize, pakFile ); +} + +/* + ======================== + main + + ======================== + */ +int main (int argc, const char * argv[]) { + int arg; + + for ( arg = 1 ; arg < argc ; arg++ ) { + if ( argv[arg][0] != '-' ) { + break; + } + if ( !strcmp( argv[arg], "-i" ) ) { + assetDirectory = argv[arg+1]; + arg++; + continue; + } + if ( !strcmp( argv[arg], "-o" ) ) { + outputFile = argv[arg+1]; + arg++; + continue; + } + if ( !strcmp( argv[arg], "-p" ) ) { + parmFile = argv[arg+1]; + arg++; + continue; + } + if ( !strcmp( argv[arg], "-?" ) ) { + Error( "doomtool [-i inputDirectory] [-o outputFile] [-p parmfile]\n" ); + } + Error( "unknown option '%s'\n", argv[arg] ); + } + + //----------------------------- + // parse the parm file + //----------------------------- + FILE *f = fopen( parmFile, "rb" ); + numParmLines = 0; + if ( f ) { + char line[1024]; + while( fgets( line, sizeof( line ), f ) ) { + // remove trailing newline + if ( line[strlen(line)-1] == '\n' ) { + line[strlen(line)-1] = 0; + } + + parmLine_t *pl = &parmLines[numParmLines]; + // tokenize + char *inputString = line; + char *ap; + while( ap = strsep( &inputString, " \t" ) ) { + if ( *ap == '\0' ) { + continue; + } + pl->argv[pl->argc] = strdup( ap ); + if ( ++pl->argc == MAX_ARGV ) { + break; + } + } + if ( pl->argc > 0 ) { + numParmLines++; + } + } + fclose( f ); + } + +// AtlasDirectory( "/Users/johnc/DOOM2/SPRITES", "" ); +#if 0 + AtlasDirectory( "/Users/johnc/DOOM2/SPRITES", "BOS2" ); + AtlasDirectory( "/Users/johnc/DOOM2/SPRITES", "BOSS" ); + AtlasDirectory( "/Users/johnc/DOOM2/SPRITES", "BSPI" ); + AtlasDirectory( "/Users/johnc/DOOM2/SPRITES", "CPOS" ); + AtlasDirectory( "/Users/johnc/DOOM2/SPRITES", "CYBR" ); + AtlasDirectory( "/Users/johnc/DOOM2/SPRITES", "FAT" ); + AtlasDirectory( "/Users/johnc/DOOM2/SPRITES", "HEAD" ); + AtlasDirectory( "/Users/johnc/DOOM2/SPRITES", "PAIN" ); + AtlasDirectory( "/Users/johnc/DOOM2/SPRITES", "PLAY" ); + AtlasDirectory( "/Users/johnc/DOOM2/SPRITES", "POSS" ); + AtlasDirectory( "/Users/johnc/DOOM2/SPRITES", "SARG" ); + AtlasDirectory( "/Users/johnc/DOOM2/SPRITES", "SKEL" ); + AtlasDirectory( "/Users/johnc/DOOM2/SPRITES", "SKUL" ); + AtlasDirectory( "/Users/johnc/DOOM2/SPRITES", "SPID" ); + AtlasDirectory( "/Users/johnc/DOOM2/SPRITES", "SPOS" ); + AtlasDirectory( "/Users/johnc/DOOM2/SPRITES", "SSWV" ); + AtlasDirectory( "/Users/johnc/DOOM2/SPRITES", "TROO" ); + AtlasDirectory( "/Users/johnc/DOOM2/SPRITES", "VILE" ); +#endif + //----------------------------- + // start writing the outputFile + //----------------------------- + + pakFile = fopen( outputFile, "wb" ); + assert( pakFile ); + + // leave space for the header, which will be written at the end + fwrite( &buildHeader, 1, sizeof( buildHeader ), pakFile ); + + // recursively process everything under the asset directory + AddDirectoryToPak_r( "" ); + + // write out the tables + WriteType( pakFile, &buildHeader.textures, sizeof( pkTextureData_t ), &buildTextureTable[0].name ); + WriteType( pakFile, &buildHeader.wavs, sizeof( pkWavData_t ), &buildWavTable[0].name ); + WriteType( pakFile, &buildHeader.raws, sizeof( pkRawData_t ), &buildRawTable[0].name ); + + buildHeader.version = PKFILE_VERSION; + + printf( "%s : %i bytes\n", outputFile, ftell( pakFile ) ); + + // go back and write the header + fseek( pakFile, 0, SEEK_SET ); + fwrite( &buildHeader, 1, sizeof( buildHeader ), pakFile ); + + fclose( pakFile ); + + return 0; +} diff --git a/DoomClassics.xcworkspace/contents.xcworkspacedata b/DoomClassics.xcworkspace/contents.xcworkspacedata new file mode 100755 index 0000000..a1fffaa --- /dev/null +++ b/DoomClassics.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/DoomClassics.xcworkspace/xcshareddata/DoomClassics.xccheckout b/DoomClassics.xcworkspace/xcshareddata/DoomClassics.xccheckout new file mode 100644 index 0000000..a72d7df --- /dev/null +++ b/DoomClassics.xcworkspace/xcshareddata/DoomClassics.xccheckout @@ -0,0 +1,41 @@ + + + + + IDESourceControlProjectFavoriteDictionaryKey + + IDESourceControlProjectIdentifier + 7533C1F3-4B38-47A4-BB3C-25F8CE6F1AA8 + IDESourceControlProjectName + DoomClassics + IDESourceControlProjectOriginsDictionary + + 40E496C3-3EE7-4817-AA8A-3CCAB01855DC + https://github.com/JFareal/id-Mobile.git + + IDESourceControlProjectPath + DoomClassics/DoomClassics.xcworkspace + IDESourceControlProjectRelativeInstallPathDictionary + + 40E496C3-3EE7-4817-AA8A-3CCAB01855DC + ../.. + + IDESourceControlProjectURL + https://github.com/JFareal/id-Mobile.git + IDESourceControlProjectVersion + 110 + IDESourceControlProjectWCCIdentifier + 40E496C3-3EE7-4817-AA8A-3CCAB01855DC + IDESourceControlProjectWCConfigurations + + + IDESourceControlRepositoryExtensionIdentifierKey + public.vcs.git + IDESourceControlWCCIdentifierKey + 40E496C3-3EE7-4817-AA8A-3CCAB01855DC + IDESourceControlWCCName + id Mobile + + + + diff --git a/DoomClassics.xcworkspace/xcuserdata/Farrand.xcuserdatad/UserInterfaceState.xcuserstate b/DoomClassics.xcworkspace/xcuserdata/Farrand.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..34da770 Binary files /dev/null and b/DoomClassics.xcworkspace/xcuserdata/Farrand.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/DoomClassics.xcworkspace/xcuserdata/Farrand.xcuserdatad/WorkspaceSettings.xcsettings b/DoomClassics.xcworkspace/xcuserdata/Farrand.xcuserdatad/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..bfffcfe --- /dev/null +++ b/DoomClassics.xcworkspace/xcuserdata/Farrand.xcuserdatad/WorkspaceSettings.xcsettings @@ -0,0 +1,10 @@ + + + + + HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges + + SnapshotAutomaticallyBeforeSignificantChanges + + + diff --git a/DoomClassics.xcworkspace/xcuserdata/Farrand.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/DoomClassics.xcworkspace/xcuserdata/Farrand.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 0000000..49913e8 --- /dev/null +++ b/DoomClassics.xcworkspace/xcuserdata/Farrand.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/DoomClassics.xcworkspace/xcuserdata/Farrand.xcuserdatad/xcdebugger/Expressions.xcexplist b/DoomClassics.xcworkspace/xcuserdata/Farrand.xcuserdatad/xcdebugger/Expressions.xcexplist new file mode 100644 index 0000000..2170308 --- /dev/null +++ b/DoomClassics.xcworkspace/xcuserdata/Farrand.xcuserdatad/xcdebugger/Expressions.xcexplist @@ -0,0 +1,14 @@ + + + + + + + + + + + diff --git a/DoomClassics.xcworkspace/xcuserdata/jeff.farrand.xcuserdatad/UserInterfaceState.xcuserstate b/DoomClassics.xcworkspace/xcuserdata/jeff.farrand.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100755 index 0000000..d09f61b Binary files /dev/null and b/DoomClassics.xcworkspace/xcuserdata/jeff.farrand.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/DoomClassics.xcworkspace/xcuserdata/jeff.farrand.xcuserdatad/xcdebugger/Breakpoints.xcbkptlist b/DoomClassics.xcworkspace/xcuserdata/jeff.farrand.xcuserdatad/xcdebugger/Breakpoints.xcbkptlist new file mode 100755 index 0000000..5664a6d --- /dev/null +++ b/DoomClassics.xcworkspace/xcuserdata/jeff.farrand.xcuserdatad/xcdebugger/Breakpoints.xcbkptlist @@ -0,0 +1,5 @@ + + + diff --git a/DoomClassics.xcworkspace/xcuserdata/jeff.farrand.xcuserdatad/xcdebugger/Expressions.xcexplist b/DoomClassics.xcworkspace/xcuserdata/jeff.farrand.xcuserdatad/xcdebugger/Expressions.xcexplist new file mode 100755 index 0000000..20b38df --- /dev/null +++ b/DoomClassics.xcworkspace/xcuserdata/jeff.farrand.xcuserdatad/xcdebugger/Expressions.xcexplist @@ -0,0 +1,14 @@ + + + + + + + + + + + diff --git a/DoomClassics.xcworkspace/xcuserdata/ryan.gerleve.xcuserdatad/UserInterfaceState.xcuserstate b/DoomClassics.xcworkspace/xcuserdata/ryan.gerleve.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100755 index 0000000..453efb5 Binary files /dev/null and b/DoomClassics.xcworkspace/xcuserdata/ryan.gerleve.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/DoomClassics.xcworkspace/xcuserdata/ryan.gerleve.xcuserdatad/xcdebugger/Breakpoints.xcbkptlist b/DoomClassics.xcworkspace/xcuserdata/ryan.gerleve.xcuserdatad/xcdebugger/Breakpoints.xcbkptlist new file mode 100755 index 0000000..a8d2202 --- /dev/null +++ b/DoomClassics.xcworkspace/xcuserdata/ryan.gerleve.xcuserdatad/xcdebugger/Breakpoints.xcbkptlist @@ -0,0 +1,21 @@ + + + + + + + diff --git a/README.txt b/README.txt new file mode 100755 index 0000000..e651e2d --- /dev/null +++ b/README.txt @@ -0,0 +1,24 @@ +DOOM Classic iOS v3.0 GPL source release +=============================================== + +This file contains the following sections: + +GENERAL NOTES +LICENSE + +GENERAL NOTES +============= + +DOOM Classic iOS v3.0 is a free release, and can be downloaded from +http://http://www.idsoftware.com/idstuff/doom/doomclassic_ios_v30_src.zip + +This source release does not contain any game data, the game data remains subject to the original EULA and applicable law. + + +LICENSE +======= + +See COPYING.txt for the GNU GENERAL PUBLIC LICENSE. If COPYING.txt does not accompany, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + + diff --git a/common/SDL_shim/SDL_Mixer.h b/common/SDL_shim/SDL_Mixer.h new file mode 100755 index 0000000..672148a --- /dev/null +++ b/common/SDL_shim/SDL_Mixer.h @@ -0,0 +1,102 @@ +/* + + Copyright (C) 2011 Id Software, 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 + 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. + + */ + +#ifndef doomengine_SDL_Mixer_h +#define doomengine_SDL_Mixer_h + +#ifdef __cplusplus +extern "C" { +#endif + +/* +=============================== + +This is a minimal implemenation of SDL_Mixer for iOS, just to get MIDI files +playing so that we can play the music directly from the WADs. + +=============================== +*/ + +#include + +typedef struct Mix_Music_tag { + char unused; +} Mix_Music; + + +/* Open the mixer with a certain audio format */ +extern int Mix_OpenAudio(int frequency, uint16_t format, int channels, + int chunksize); + + +/* Close the mixer, halting all playing audio */ +extern void Mix_CloseAudio(void); + + +/* Set a function that is called after all mixing is performed. + This can be used to provide real-time visual display of the audio stream + or add a custom mixer filter for the stream data. +*/ +extern void Mix_SetPostMix(void (*mix_func) + (void *udata, uint8_t *stream, int len), void *arg); + + +/* Fade in music or a channel over "ms" milliseconds, same semantics as the "Play" functions */ +extern int Mix_FadeInMusic(Mix_Music *music, int loops, int ms); + + +/* Pause/Resume the music stream */ +extern void Mix_PauseMusic(void); +extern void Mix_ResumeMusic(void); + + +/* Halt a channel, fading it out progressively till it's silent + The ms parameter indicates the number of milliseconds the fading + will take. + */ +extern int Mix_FadeOutMusic(int ms); + + +/* Free an audio chunk previously loaded */ +extern void Mix_FreeMusic(Mix_Music *music); + + +/* Load a wave file or a music (.mod .s3m .it .xm) file */ +extern Mix_Music * Mix_LoadMUS(const char *file); + + +extern const char * Mix_GetError(void); + + + + +/* Set the volume in the range of 0-128 of a specific channel or chunk. + If the specified channel is -1, set volume for all channels. + Returns the original volume. + If the specified volume is -1, just return the current volume. +*/ +extern int Mix_VolumeMusic(int volume); + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/common/SDL_shim/ios/SDL_Mixer.m b/common/SDL_shim/ios/SDL_Mixer.m new file mode 100755 index 0000000..83805d8 --- /dev/null +++ b/common/SDL_shim/ios/SDL_Mixer.m @@ -0,0 +1,517 @@ +/* + + Copyright (C) 2011 Id Software, 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 + 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. + + */ + + +/* +=============================== + +iOS implementation of our SDL_Mixer shim for playing MIDI files. + +=============================== +*/ + +#include + +#include "SDL_Mixer.h" + + +// Use the Embedded Audio Synthesis library as the backend MIDI renderer. +#include "embeddedaudiosynthesis/EASGlue.h" + + +// Use Core Audio Units for sound output on the device. +#import +#import + + +/* +=============================== + +"Constants" + +=============================== +*/ +#define ID_GRAPH_SAMPLE_RATE 22050 + + +/* +=============================== + +Internal Structures + +=============================== +*/ + +// Data structure for mono or stereo sound, to pass to the application's render callback function, +// which gets invoked by a Mixer unit input bus when it needs more audio to play. +typedef struct { + + BOOL isStereo; // set to true if there is data in the audioDataRight member + UInt32 frameCount; // the total number of frames in the audio data + UInt32 sampleNumber; // the next audio sample to play +} soundStruct, *soundStructPtr; + + + +typedef struct MIDIPlayerGraph_tag { + + AUGraph processingGraph; + AudioUnit ioUnit; + BOOL playing; + + AudioStreamBasicDescription streamFormat; + + soundStruct soundStructInst; +} MIDIPlayerGraph; + +static MIDIPlayerGraph midiPlayer; + + + +/* +=============================== + +Internal prototypes + +=============================== +*/ +AudioStreamBasicDescription getStreamFormat( void ); +static void printASBD( AudioStreamBasicDescription asbd ); +static void printErrorMessage( NSString * errorString, OSStatus result ); +static void configureAndInitializeAudioProcessingGraph( MIDIPlayerGraph * player ); +static void startMIDIPlayer( MIDIPlayerGraph * player ); + +// AU graph callback. +static OSStatus inputRenderCallback ( + + void *inRefCon, // A pointer to a struct containing the complete audio data + // to play, as well as state information such as the + // first sample to play on this invocation of the callback. + AudioUnitRenderActionFlags *ioActionFlags, // Unused here. When generating audio, use ioActionFlags to indicate silence + // between sounds; for silence, also memset the ioData buffers to 0. + const AudioTimeStamp *inTimeStamp, // Unused here. + UInt32 inBusNumber, // The mixer unit input bus that is requesting some new + // frames of audio data to play. + UInt32 inNumberFrames, // The number of frames of audio to provide to the buffer(s) + // pointed to by the ioData parameter. + AudioBufferList *ioData // On output, the audio data to play. The callback's primary + // responsibility is to fill the buffer(s) in the + // AudioBufferList. +); + + + +/* Open the mixer with a certain audio format */ +int Mix_OpenAudio(int frequency, uint16_t format, int channels, + int chunksize) { + + EASGlueInit(); + + midiPlayer.streamFormat = getStreamFormat(); + midiPlayer.playing = FALSE; + + configureAndInitializeAudioProcessingGraph( &midiPlayer ); + + return 0; +} + + +/* Close the mixer, halting all playing audio */ +void Mix_CloseAudio(void) { + AUGraphStop( midiPlayer.processingGraph ); + EASGlueShutdown(); +} + + +/* Set a function that is called after all mixing is performed. + This can be used to provide real-time visual display of the audio stream + or add a custom mixer filter for the stream data. +*/ +void Mix_SetPostMix(void (*mix_func) + (void *udata, uint8_t *stream, int len), void *arg) { + +} + + +/* Fade in music or a channel over "ms" milliseconds, same semantics as the "Play" functions */ +int Mix_FadeInMusic(Mix_Music *music, int loops, int ms) { + + + startMIDIPlayer( &midiPlayer ); + + + return 0; +} + + +/* Pause/Resume the music stream */ +void Mix_PauseMusic(void) { + EASGluePause(); +} + + +void Mix_ResumeMusic(void) { + EASGlueResume(); +} + + +/* Halt a channel, fading it out progressively till it's silent + The ms parameter indicates the number of milliseconds the fading + will take. + */ +int Mix_FadeOutMusic(int ms) { + + EASGlueCloseFile(); + + AUGraphStop( midiPlayer.processingGraph ); + + return 1; +} + + +/* Free an audio chunk previously loaded */ +void Mix_FreeMusic(Mix_Music *music) { + free(music); +} + + +/* Load a wave file or a music (.mod .s3m .it .xm) file */ +Mix_Music * Mix_LoadMUS(const char *file) { + + EASGlueOpenFile( file ); + + Mix_Music * musicStruct = malloc( sizeof(Mix_Music) ); + + return musicStruct; +} + + +const char * Mix_GetError(void) { + return ""; +} + + +/* Set the volume in the range of 0-128 of a specific channel or chunk. + If the specified channel is -1, set volume for all channels. + Returns the original volume. + If the specified volume is -1, just return the current volume. +*/ +int Mix_VolumeMusic(int volume) { + + return 0; + +} + + + + + + +/* +================================= + Audio Unit helper functions +================================= +*/ + + +AudioStreamBasicDescription getStreamFormat( void ) { + + AudioStreamBasicDescription streamFormat = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + // The AudioUnitSampleType data type is the recommended type for sample data in audio + // units. This obtains the byte size of the type for use in filling in the ASBD. + size_t bytesPerSample = sizeof (AudioUnitSampleType); + + // Fill the application audio format struct's fields to define a linear PCM, + // stereo, noninterleaved stream at the hardware sample rate. + streamFormat.mFormatID = kAudioFormatLinearPCM; + streamFormat.mFormatFlags = kAudioFormatFlagsAudioUnitCanonical; + streamFormat.mBytesPerPacket = bytesPerSample; + streamFormat.mFramesPerPacket = 1; + streamFormat.mBytesPerFrame = bytesPerSample; + streamFormat.mChannelsPerFrame = 2; // 2 indicates stereo + streamFormat.mBitsPerChannel = 8 * bytesPerSample; + streamFormat.mSampleRate = ID_GRAPH_SAMPLE_RATE; + + + NSLog (@"The stereo stream format for the I/O unit:"); + printASBD( streamFormat ); + + return streamFormat; +} + +static void startMIDIPlayer( MIDIPlayerGraph * player ) { + + if ( player == 0 ) { + NSLog( @"NULL player object, can't start!" ); + return; + } + + NSLog (@"Starting audio processing graph"); + OSStatus result = AUGraphStart (player->processingGraph); + if (noErr != result) { printErrorMessage( @"AUGraphStart", result ); return;} + + player->playing = YES; + +} + +// You can use this method during development and debugging to look at the +// fields of an AudioStreamBasicDescription struct. +static void printASBD( AudioStreamBasicDescription asbd ) { + + char formatIDString[5]; + UInt32 formatID = CFSwapInt32HostToBig (asbd.mFormatID); + bcopy (&formatID, formatIDString, 4); + formatIDString[4] = '\0'; + + NSLog (@" Sample Rate: %10.0f", asbd.mSampleRate); + NSLog (@" Format ID: %10s", formatIDString); + NSLog (@" Format Flags: %10lX", asbd.mFormatFlags); + NSLog (@" Bytes per Packet: %10lu", asbd.mBytesPerPacket); + NSLog (@" Frames per Packet: %10lu", asbd.mFramesPerPacket); + NSLog (@" Bytes per Frame: %10lu", asbd.mBytesPerFrame); + NSLog (@" Channels per Frame: %10lu", asbd.mChannelsPerFrame); + NSLog (@" Bits per Channel: %10lu", asbd.mBitsPerChannel); +} + + +static void printErrorMessage( NSString * errorString, OSStatus result ) { + + char resultString[5]; + UInt32 swappedResult = CFSwapInt32HostToBig (result); + bcopy (&swappedResult, resultString, 4); + resultString[4] = '\0'; + + NSLog ( + @"*** %@ error: %s\n", + errorString, + (char*) &resultString + ); +} + + +// This method performs all the work needed to set up the audio processing graph: + + // 1. Instantiate and open an audio processing graph + // 2. Obtain the audio unit nodes for the graph + // 3. Configure the Multichannel Mixer unit + // * specify the number of input buses + // * specify the output sample rate + // * specify the maximum frames-per-slice + // 4. Initialize the audio processing graph + +static void configureAndInitializeAudioProcessingGraph( MIDIPlayerGraph * player ) { + + if ( player == 0 ) { + NSLog( @"NULL player graph object, can't initialize it!" ); + return; + } + + + NSLog (@"Configuring and then initializing audio processing graph"); + OSStatus result = noErr; + +//............................................................................ +// Create a new audio processing graph. + result = NewAUGraph (&player->processingGraph); + + if (noErr != result) { printErrorMessage( @"NewAUGraph", result ); return;} + + +//............................................................................ +// Specify the audio unit component descriptions for the audio units to be +// added to the graph. + + // I/O unit + AudioComponentDescription iOUnitDescription; + iOUnitDescription.componentType = kAudioUnitType_Output; + iOUnitDescription.componentSubType = kAudioUnitSubType_RemoteIO; + iOUnitDescription.componentManufacturer = kAudioUnitManufacturer_Apple; + iOUnitDescription.componentFlags = 0; + iOUnitDescription.componentFlagsMask = 0; + + +//............................................................................ +// Add nodes to the audio processing graph. + NSLog (@"Adding nodes to audio processing graph"); + + AUNode iONode; // node for I/O unit + + // Add the nodes to the audio processing graph + result = AUGraphAddNode ( + player->processingGraph, + &iOUnitDescription, + &iONode); + + if (noErr != result) { printErrorMessage( @"AUGraphNewNode failed for I/O unit", result ); return;} + +//............................................................................ +// Open the audio processing graph + + // Following this call, the audio units are instantiated but not initialized + // (no resource allocation occurs and the audio units are not in a state to + // process audio). + result = AUGraphOpen (player->processingGraph); + + if (noErr != result) { printErrorMessage( @"AUGraphOpen", result ); return;} + + +//............................................................................ +// Obtain the mixer unit instance from its corresponding node. + + result = AUGraphNodeInfo ( + player->processingGraph, + iONode, + NULL, + &player->ioUnit + ); + + if (noErr != result) { printErrorMessage( @"AUGraphNodeInfo", result ); return;} + + +//............................................................................ +// Multichannel Mixer unit Setup + + + // Setup the struture that contains the input render callback + AURenderCallbackStruct inputCallbackStruct; + inputCallbackStruct.inputProc = &inputRenderCallback; + inputCallbackStruct.inputProcRefCon = &player->soundStructInst; + + NSLog (@"Registering the render callback with the I/O unit" ); + // Set a callback for the specified node's specified input + result = AUGraphSetNodeInputCallback ( + player->processingGraph, + iONode, + 0, + &inputCallbackStruct + ); + + if (noErr != result) { printErrorMessage( @"AUGraphSetNodeInputCallback", result ); return;} + + + NSLog (@"Setting stereo stream format for I/O unit input bus"); + result = AudioUnitSetProperty ( + player->ioUnit, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Input, + 0, + &player->streamFormat, + sizeof (player->streamFormat) + ); + + if (noErr != result) { printErrorMessage( @"AudioUnitSetProperty (set input bus stream format)", result ); return;} + +//............................................................................ +// Initialize audio processing graph + + // Diagnostic code + // Call CAShow if you want to look at the state of the audio processing + // graph. + NSLog (@"Audio processing graph state immediately before initializing it:"); + CAShow (player->processingGraph); + + NSLog (@"Initializing the audio processing graph"); + // Initialize the audio processing graph, configure audio data stream formats for + // each input and output, and validate the connections between audio units. + result = AUGraphInitialize (player->processingGraph); + + if (noErr != result) { printErrorMessage( @"AUGraphInitialize", result ); return;} +} + +#define RAW_EAS_BUFFER_FRAMES 128 + +static OSStatus inputRenderCallback ( + + void *inRefCon, // A pointer to a struct containing the complete audio data + // to play, as well as state information such as the + // first sample to play on this invocation of the callback. + AudioUnitRenderActionFlags *ioActionFlags, // Unused here. When generating audio, use ioActionFlags to indicate silence + // between sounds; for silence, also memset the ioData buffers to 0. + const AudioTimeStamp *inTimeStamp, // Unused here. + UInt32 inBusNumber, // The mixer unit input bus that is requesting some new + // frames of audio data to play. + UInt32 inNumberFrames, // The number of frames of audio to provide to the buffer(s) + // pointed to by the ioData parameter. + AudioBufferList *ioData // On output, the audio data to play. The callback's primary + // responsibility is to fill the buffer(s) in the + // AudioBufferList. +) { + + //printf( "Need %lu samples in %lu buffers!\n", inNumberFrames, ioData->mNumberBuffers ); + + EAS_I32 generatedThisRender = 0; + EAS_I32 totalGenerated = 0; + + // It looks like EAS interleaves stereo samples, so we have to separate them into the two + // different buffers that the audio unit provides. + //const UInt32 totalInterleavedSamplesNeeded = inNumberFrames * 2; + + AudioBuffer * audioBufferLeft = &ioData->mBuffers[0]; + AudioBuffer * audioBufferRight = &ioData->mBuffers[1]; + + /* + printf( "Need %lu samples in %lu buffers!\n" + "audioBuffer byte size: %lu channels: %lu\n", + inNumberFrames, ioData->mNumberBuffers, + audioBuffer->mDataByteSize, audioBuffer->mNumberChannels ); + */ + AudioUnitSampleType * hardwareBufferLeft = (AudioUnitSampleType *) audioBufferLeft->mData; + AudioUnitSampleType * hardwareBufferRight = (AudioUnitSampleType *) audioBufferRight->mData; + + + // EAS_Render always produces BUFFER_SIZE_IN_MONO_SAMPLES frames per call. Currently, this + // is defined to 128. Let's fill up a 128 frame buffer, then do a conversion from EAS_PCM + // (which is signed 16-bit integer) to AudioUnitSampleType (which is 8.24 fixed-point with + // a range of -1 to +1). + // + // Note that EAS renders interleaved stereo, so we actually a buffer size of + // 2 * BUFFER_SIZE_IN_MONO_SAMPLES. + + EAS_PCM rawEASSamples[RAW_EAS_BUFFER_FRAMES * 2]; + + + // EAS generates interleaved stereo samples, but the AudioUnit wants noninterleaved. + while ( totalGenerated < inNumberFrames ) { + //EASGlueRender( hardwareBuffer + totalGenerated*2, &generatedThisRender ); + EASGlueRender( rawEASSamples, &generatedThisRender ); + + + // Convert from EAS's signed 16-bit format to the AudioUnit's 8.24 fixed-point format. + // Couldn't find this in the Apple docs, but the 8.24 format should be in the range of + // -1.0 to 1.0, wasting 6 bits of precision. + // All we have to do here is left-shift by 9 bits. This will not overflow, because the + // destination is a 32-bit value. + // Also take this opportunity to de-interleave the EAS-rendered samples. + for ( int i = 0; i < RAW_EAS_BUFFER_FRAMES; ++i ) { + hardwareBufferLeft[totalGenerated + i] = rawEASSamples[i * 2 + 0] << 9; + hardwareBufferRight[totalGenerated + i] = rawEASSamples[i * 2 + 1] << 9; + } + + totalGenerated += generatedThisRender; + } + + return noErr; +} + + + + + diff --git a/common/embeddedaudiosynthesis/Android.mk b/common/embeddedaudiosynthesis/Android.mk new file mode 100755 index 0000000..6571161 --- /dev/null +++ b/common/embeddedaudiosynthesis/Android.mk @@ -0,0 +1 @@ +include $(all-subdir-makefiles) diff --git a/common/embeddedaudiosynthesis/EASGlue.c b/common/embeddedaudiosynthesis/EASGlue.c new file mode 100755 index 0000000..005e1ef --- /dev/null +++ b/common/embeddedaudiosynthesis/EASGlue.c @@ -0,0 +1,211 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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 "EASGlue.h" + +#include +#include +#include +#include + +#include "eas.h" +#include "eas_wave.h" +#include "eas_report.h" + +#define NUM_BUFFERS 1 + +#ifndef NDEBUG +static EAS_BOOL EASLibraryCheck (const S_EAS_LIB_CONFIG *pLibConfig); +#endif + +static EAS_DATA_HANDLE pEASData; +static const S_EAS_LIB_CONFIG *pLibConfig; +static int polyphony; +static int bufferSize; + +static EAS_FILE file; +static EAS_HANDLE handle; + +void EASGlueInit(void) { + EAS_RESULT result; + + /* get the library configuration */ + pLibConfig = EAS_Config(); + assert( EASLibraryCheck(pLibConfig) ); + + if (polyphony > pLibConfig->maxVoices) + polyphony = pLibConfig->maxVoices; + + EAS_I32 mixSize = pLibConfig->mixBufferSize; + + bufferSize = mixSize * pLibConfig->numChannels * (EAS_I32)sizeof(EAS_PCM) * NUM_BUFFERS; + + /* calculate buffer size */ + //bufferSize = pLibConfig->mixBufferSize * pLibConfig->numChannels * (EAS_I32)sizeof(EAS_PCM) * NUM_BUFFERS; + + + if ( (result = EAS_Init(&pEASData)) != EAS_SUCCESS ) { + printf( "Error initializing EAS: %li\n", result ); + } +} + + +void EASGlueShutdown(void) { + EAS_RESULT result; + + EASGlueCloseFile(); + if ( (result = EAS_Shutdown(pEASData)) != EAS_SUCCESS ) { + printf( "Error shutting down EAS: %li\n", result ); + } +} + +void EASGlueOpenFile( const char * filename ) { + + EAS_RESULT result; + + + /* open the file */ + file.path = filename; + file.fd = 0; + if ((result = EAS_OpenFile(pEASData, &file, &handle)) != EAS_SUCCESS) { + printf( "Error opening EAS file: %li\n", result ); + return; + } + + EAS_SetRepeat( pEASData, handle, -1 ); + + /* prepare for playback */ + if ((result = EAS_Prepare(pEASData, handle)) != EAS_SUCCESS) { + printf( "Error preparing EAS file: %li\n", result ); + return; + } +} + +void EASGluePause(void) { + EAS_RESULT result; + + if ( handle == 0 ) { + return; + } + + result = EAS_Pause( pEASData, handle ); + + if ( result != EAS_SUCCESS ) { + printf( "Error pausing EAS file: %li\n", result ); + } +} + +void EASGlueResume(void) { + EAS_RESULT result; + + result = EAS_Resume( pEASData, handle ); + + if ( result != EAS_SUCCESS ) { + printf( "Error pausing EAS file: %li\n", result ); + } +} + +void EASGlueCloseFile(void) { + + if ( handle == 0 ) { + return; + } + + // File must be paused or stopped before closing it. + EASGluePause(); + + EAS_RESULT result; + + result = EAS_CloseFile( pEASData, handle ); + + if ( result != EAS_SUCCESS ) { + printf( "Error closing EAS file: %li\n", result ); + } + + handle = 0; +} + +void EASGlueRender( EAS_PCM * outputBuffer, EAS_I32 * generatedSamples ) { + EAS_RESULT result; + + if ( ( result = EAS_Render( pEASData, outputBuffer, pLibConfig->mixBufferSize, generatedSamples ) ) != EAS_SUCCESS ) { + printf( "Error rendering EAS: %li\n.", result ); + return; + } +} + + +#ifndef NDEBUG +/*---------------------------------------------------------------------------- + * EASLibraryCheck() + *---------------------------------------------------------------------------- + * Purpose: + * Displays the library version and checks it against the header + * file used to build this code. + * + * Inputs: + * pLibConfig - library configuration retrieved from the library + * + * Outputs: + * returns EAS_TRUE if matched + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL EASLibraryCheck (const S_EAS_LIB_CONFIG *libConfig) +{ + + /* display the library version */ + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "EAS Library Version %d.%d.%d.%d\n", + libConfig->libVersion >> 24, + (libConfig->libVersion >> 16) & 0x0f, + (libConfig->libVersion >> 8) & 0x0f, + libConfig->libVersion & 0x0f); */ } + + /* display some info about the library build */ + if (libConfig->checkedVersion) + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tChecked library\n"); */ } + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tMaximum polyphony: %d\n", libConfig->maxVoices); */ } + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tNumber of channels: %d\n", libConfig->numChannels); */ } + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tSample rate: %d\n", libConfig->sampleRate); */ } + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tMix buffer size: %d\n", libConfig->mixBufferSize); */ } + if (libConfig->filterEnabled) + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tFilter enabled\n"); */ } +#ifndef _WIN32_WCE + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tLibrary Build Timestamp: %s", ctime((time_t*)&libConfig->buildTimeStamp)); */ } +#endif + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tLibrary Build ID: %s\n", libConfig->buildGUID); */ } + + /* check it against the header file used to build this code */ + /*lint -e{778} constant expression used for display purposes may evaluate to zero */ + if (LIB_VERSION != libConfig->libVersion) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Library version does not match header files. EAS Header Version %d.%d.%d.%d\n", + LIB_VERSION >> 24, + (LIB_VERSION >> 16) & 0x0f, + (LIB_VERSION >> 8) & 0x0f, + LIB_VERSION & 0x0f); */ } + return EAS_FALSE; + } + return EAS_TRUE; +} /* end EASLibraryCheck */ + +#endif diff --git a/common/embeddedaudiosynthesis/EASGlue.h b/common/embeddedaudiosynthesis/EASGlue.h new file mode 100755 index 0000000..d0d4e65 --- /dev/null +++ b/common/embeddedaudiosynthesis/EASGlue.h @@ -0,0 +1,36 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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. + + */ + +#ifndef EAS_GLUE_H +#define EAS_GLUE_H + +#include "arm-wt-22k/host_src/eas.h" + +void EASGlueInit( void ); +void EASGlueShutdown( void ); + +void EASGlueOpenFile( const char * filename ); +void EASGluePause(); +void EASGlueResume(); +void EASGlueCloseFile(); + +void EASGlueRender( EAS_PCM * outputBuffer, EAS_I32 * generatedSamples ); + +#endif diff --git a/common/embeddedaudiosynthesis/MODULE_LICENSE_APACHE2 b/common/embeddedaudiosynthesis/MODULE_LICENSE_APACHE2 new file mode 100755 index 0000000..e69de29 diff --git a/common/embeddedaudiosynthesis/NOTICE b/common/embeddedaudiosynthesis/NOTICE new file mode 100755 index 0000000..1f00f30 --- /dev/null +++ b/common/embeddedaudiosynthesis/NOTICE @@ -0,0 +1,14 @@ +Copyright (c) 2004-2006 Sonic Network Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + diff --git a/common/embeddedaudiosynthesis/ThirdPartyProject.prop b/common/embeddedaudiosynthesis/ThirdPartyProject.prop new file mode 100755 index 0000000..56281bb --- /dev/null +++ b/common/embeddedaudiosynthesis/ThirdPartyProject.prop @@ -0,0 +1,9 @@ +# Copyright 2010 Google Inc. All Rights Reserved. +#Fri Jul 16 10:03:09 PDT 2010 +currentVersion=Unknown +version=3.6.10.14? +isNative=true +name=sonivox +keywords=sonivox +onDevice=true +homepage=http\://source.android.com/ diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/Makefile b/common/embeddedaudiosynthesis/arm-fm-22k/Makefile new file mode 100755 index 0000000..8b76c55 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/Makefile @@ -0,0 +1,63 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES = \ + lib_src/eas_chorus.c \ + lib_src/eas_chorusdata.c \ + lib_src/eas_data.c \ + lib_src/eas_fmengine.c \ + lib_src/eas_fmsndlib.c \ + lib_src/eas_fmsynth.c \ + lib_src/eas_fmtables.c \ + lib_src/eas_ima_tables.c \ + lib_src/eas_imaadpcm.c \ + lib_src/eas_imelody.c \ + lib_src/eas_imelodydata.c \ + lib_src/eas_math.c \ + lib_src/eas_midi.c \ + lib_src/eas_mididata.c \ + lib_src/eas_mixbuf.c \ + lib_src/eas_mixer.c \ + lib_src/eas_ota.c \ + lib_src/eas_otadata.c \ + lib_src/eas_pan.c \ + lib_src/eas_pcm.c \ + lib_src/eas_pcmdata.c \ + lib_src/eas_public.c \ + lib_src/eas_reverb.c \ + lib_src/eas_reverbdata.c \ + lib_src/eas_rtttl.c \ + lib_src/eas_rtttldata.c \ + lib_src/eas_smf.c \ + lib_src/eas_smfdata.c \ + lib_src/eas_voicemgt.c \ + lib_src/eas_wavefile.c \ + lib_src/eas_wavefiledata.c \ + host_src/eas_config.c \ + host_src/eas_hostmm.c \ + host_src/eas_main.c \ + host_src/eas_report.c \ + host_src/eas_wave.c + +LOCAL_CFLAGS+= -O2 -D NUM_OUTPUT_CHANNELS=2 \ + -D _SAMPLE_RATE_22050 -D EAS_FM_SYNTH \ + -D MAX_SYNTH_VOICES=16 -D _IMELODY_PARSER \ + -D _RTTTL_PARSER -D _OTA_PARSER \ + -D _WAVE_PARSER -D _REVERB_ENABLED \ + -D _CHORUS_ENABLED -D _IMA_DECODER \ + -D UNIFIED_DEBUG_MESSAGES + +LOCAL_C_INCLUDES:= \ + $(LOCAL_PATH)/host_src/ \ + $(LOCAL_PATH)/lib_src/ + +LOCAL_ARM_MODE := arm + +LOCAL_MODULE := libsonivox + +LOCAL_COPY_HEADERS_TO := libsonivox +LOCAL_COPY_HEADERS := \ + host_src/eas.h \ + host_src/eas_types.h + +include $(BUILD_SHARED_LIBRARY) diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/bin/arm-fm-22k b/common/embeddedaudiosynthesis/arm-fm-22k/bin/arm-fm-22k new file mode 100755 index 0000000..50ba4ba Binary files /dev/null and b/common/embeddedaudiosynthesis/arm-fm-22k/bin/arm-fm-22k differ diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/host_src/arm-fm-22k.mak b/common/embeddedaudiosynthesis/arm-fm-22k/host_src/arm-fm-22k.mak new file mode 100755 index 0000000..da12d71 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/host_src/arm-fm-22k.mak @@ -0,0 +1,25 @@ +# +# Auto-generated sample makefile +# +# This makefile is intended for use with GNU make. +# Set the paths to the tools (CC, AR, LD, etc.) +# + +vpath %.c host_src + +CC = C:\Program Files\GNUARM\bin\arm-elf-gcc.exe +AS = C:\Program Files\GNUARM\bin\arm-elf-as.exe +LD = C:\Program Files\GNUARM\bin\arm-elf-gcc.exe +AR = C:\Program Files\GNUARM\bin\arm-elf-ar.exe + +%.o: %.c + $(CC) -c -O2 -o $@ -I host_src -D UNIFIED_DEBUG_MESSAGES -D EAS_FM_SYNTH -D _IMELODY_PARSER -D _RTTTL_PARSER -D _OTA_PARSER -D _WAVE_PARSER -D _REVERB_ENABLED -D _CHORUS_ENABLED $< + +%.o: %.s + $(AS) -o $@ -EL -mcpu=arm946e-s -mfpu=softfpa $< + +OBJS = eas_main.o eas_report.o eas_wave.o eas_hostmm.o eas_config.o + +arm-fm-22k: $(OBJS) + $(LD) -o $@ $(OBJS) libarm-fm-22k.a -lm + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas.h b/common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas.h new file mode 100755 index 0000000..c64af49 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas.h @@ -0,0 +1,1062 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas.h + * + * Contents and purpose: + * The public interface header for the EAS synthesizer. + * + * This header only contains declarations that are specific + * to this implementation. + * + * DO NOT MODIFY THIS FILE! + * + * Copyright Sonic Network Inc. 2005, 2006 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 852 $ + * $Date: 2007-09-04 11:43:49 -0700 (Tue, 04 Sep 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_H +#define _EAS_H + +#include "eas_types.h" + +/* for C++ linkage */ +#ifdef __cplusplus +extern "C" { +#endif + +/* library version macro */ +#define MAKE_LIB_VERSION(a,b,c,d) (((((((EAS_U32) a <<8) | (EAS_U32) b) << 8) | (EAS_U32) c) << 8) | (EAS_U32) d) +#define LIB_VERSION MAKE_LIB_VERSION(3, 6, 10, 14) + +typedef struct +{ + EAS_U32 libVersion; + EAS_BOOL checkedVersion; + EAS_I32 maxVoices; + EAS_I32 numChannels; + EAS_I32 sampleRate; + EAS_I32 mixBufferSize; + EAS_BOOL filterEnabled; + EAS_U32 buildTimeStamp; + EAS_CHAR *buildGUID; +} S_EAS_LIB_CONFIG; + +/* enumerated effects module numbers for configuration */ +typedef enum +{ + EAS_MODULE_ENHANCER = 0, + EAS_MODULE_COMPRESSOR, + EAS_MODULE_REVERB, + EAS_MODULE_CHORUS, + EAS_MODULE_WIDENER, + EAS_MODULE_GRAPHIC_EQ, + EAS_MODULE_WOW, + EAS_MODULE_MAXIMIZER, + EAS_MODULE_TONECONTROLEQ, + NUM_EFFECTS_MODULES +} E_FX_MODULES; + +/* enumerated optional module numbers for configuration */ +typedef enum +{ + EAS_MODULE_MMAPI_TONE_CONTROL = 0, + EAS_MODULE_METRICS +} E_OPT_MODULES; +#define NUM_OPTIONAL_MODULES 2 + +/* enumerated audio decoders for configuration */ +typedef enum +{ + EAS_DECODER_PCM = 0, + EAS_DECODER_SMAF_ADPCM, + EAS_DECODER_IMA_ADPCM, + EAS_DECODER_7BIT_SMAF_ADPCM, + EAS_DECODER_NOT_SUPPORTED +} E_DECODER_MODULES; +#define NUM_DECODER_MODULES 4 + +/* defines for EAS_PEOpenStream flags parameter */ +#define PCM_FLAGS_STEREO 0x00000100 /* stream is stereo */ +#define PCM_FLAGS_8_BIT 0x00000001 /* 8-bit format */ +#define PCM_FLAGS_UNSIGNED 0x00000010 /* unsigned format */ +#define PCM_FLAGS_STREAMING 0x80000000 /* streaming mode */ + +/* maximum volume setting */ +#define EAS_MAX_VOLUME 100 + +/*---------------------------------------------------------------------------- + * EAS_Init() + *---------------------------------------------------------------------------- + * Purpose: + * Initialize the synthesizer library + * + * Inputs: + * polyphony - number of voices to play (dynamic memory model only) + * ppLibData - pointer to data handle variable for this instance + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Init (EAS_DATA_HANDLE *ppEASData); + +/*---------------------------------------------------------------------------- + * EAS_Config() + *---------------------------------------------------------------------------- + * Purpose: + * Returns a pointer to a structure containing the configuration options + * in this library build. + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC const S_EAS_LIB_CONFIG *EAS_Config (void); + +/*---------------------------------------------------------------------------- + * EAS_Shutdown() + *---------------------------------------------------------------------------- + * Purpose: + * Shuts down the library. Deallocates any memory associated with the + * synthesizer (dynamic memory model only) + * + * Inputs: + * pEASData - handle to data for this instance + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Shutdown (EAS_DATA_HANDLE pEASData); + +/*---------------------------------------------------------------------------- + * EAS_Render() + *---------------------------------------------------------------------------- + * Purpose: + * Parse the Midi data and render PCM audio data. + * + * Inputs: + * pEASData - buffer for internal EAS data + * pOut - output buffer pointer + * nNumRequested - requested num samples to generate + * pnNumGenerated - actual number of samples generated + * + * Outputs: + * EAS_SUCCESS if PCM data was successfully rendered + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Render (EAS_DATA_HANDLE pEASData, EAS_PCM *pOut, EAS_I32 numRequested, EAS_I32 *pNumGenerated); + +/*---------------------------------------------------------------------------- + * EAS_SetRepeat() + *---------------------------------------------------------------------------- + * Purpose: + * Set the selected stream to repeat. + * + * Inputs: + * pEASData - handle to data for this instance + * streamHandle - handle to stream + * repeatCount - repeat count (0 = no repeat, -1 = repeat forever) + * + * Outputs: + * + * Side Effects: + * + * Notes: + * 0 = no repeat + * 1 = repeat once, i.e. play through twice + * -1 = repeat forever + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetRepeat (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 repeatCount); + +/*---------------------------------------------------------------------------- + * EAS_GetRepeat() + *---------------------------------------------------------------------------- + * Purpose: + * Gets the current repeat count for the selected stream. + * + * Inputs: + * pEASData - handle to data for this instance + * streamHandle - handle to stream + * pRrepeatCount - pointer to variable to hold repeat count + * + * Outputs: + * + * Side Effects: + * + * Notes: + * 0 = no repeat + * 1 = repeat once, i.e. play through twice + * -1 = repeat forever + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetRepeat (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 *pRepeatCount); + +/*---------------------------------------------------------------------------- + * EAS_SetPlaybackRate() + *---------------------------------------------------------------------------- + * Purpose: + * Set the playback rate. + * + * Inputs: + * pEASData - handle to data for this instance + * streamHandle - handle to stream + * rate - rate (28-bit fractional amount) + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetPlaybackRate (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_U32 rate); +#define MAX_PLAYBACK_RATE (EAS_U32)(1L << 29) +#define MIN_PLAYBACK_RATE (EAS_U32)(1L << 27) + +/*---------------------------------------------------------------------------- + * EAS_SetTransposition) + *---------------------------------------------------------------------------- + * Purpose: + * Sets the key tranposition for the synthesizer. Transposes all + * melodic instruments by the specified amount. Range is limited + * to +/-12 semitones. + * + * Inputs: + * pEASData - handle to data for this instance + * streamHandle - handle to stream + * transposition - +/-12 semitones + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetTransposition (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 transposition); +#define MAX_TRANSPOSE 12 + +/*---------------------------------------------------------------------------- + * EAS_SetSynthPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Set the polyphony of the synthesizer. Value must be >= 1 and <= the + * maximum number of voices. This function will pin the polyphony + * at those limits + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * synthNum - synthesizer number (0 = onboard, 1 = DSP) + * polyphonyCount - the desired polyphony count + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetSynthPolyphony (EAS_DATA_HANDLE pEASData, EAS_I32 synthNum, EAS_I32 polyphonyCount); + +/*---------------------------------------------------------------------------- + * EAS_GetSynthPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current polyphony setting of the synthesizer + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * synthNum - synthesizer number (0 = onboard, 1 = DSP) + * pPolyphonyCount - pointer to variable to receive polyphony count + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetSynthPolyphony (EAS_DATA_HANDLE pEASData, EAS_I32 synthNum, EAS_I32 *pPolyphonyCount); + +/*---------------------------------------------------------------------------- + * EAS_SetPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Set the polyphony of the stream. Value must be >= 1 and <= the + * maximum number of voices. This function will pin the polyphony + * at those limits + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - handle returned by EAS_OpenFile + * polyphonyCount - the desired polyphony count + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetPolyphony (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 polyphonyCount); + +/*---------------------------------------------------------------------------- + * EAS_GetPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current polyphony setting of the stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - handle returned by EAS_OpenFile + * pPolyphonyCount - pointer to variable to receive polyphony count + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetPolyphony (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 *pPolyphonyCount); + +/*---------------------------------------------------------------------------- + * EAS_SetPriority() + *---------------------------------------------------------------------------- + * Purpose: + * Set the priority of the stream. Determines which stream's voices + * are stolen when there are insufficient voices for all notes. + * Value must be in the range of 1-255, lower values are higher + * priority. The default priority is 50. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - handle returned by EAS_OpenFile + * polyphonyCount - the desired polyphony count + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetPriority (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 priority); + +/*---------------------------------------------------------------------------- + * EAS_GetPriority() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current priority setting of the stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - handle returned by EAS_OpenFile + * pPriority - pointer to variable to receive priority + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetPriority (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 *pPriority); + +/*---------------------------------------------------------------------------- + * EAS_SetVolume() + *---------------------------------------------------------------------------- + * Purpose: + * Set the master volume for the mixer. The default volume setting is + * 90 (-10 dB). The volume range is 0 to 100 in 1dB increments. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * volume - the desired master volume + * + * Outputs: + * + * + * Side Effects: + * overrides any previously set master volume from sysex + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetVolume (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 volume); + +/*---------------------------------------------------------------------------- + * EAS_GetVolume() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the master volume for the mixer in 1dB increments. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * volume - the desired master volume + * + * Outputs: + * + * + * Side Effects: + * overrides any previously set master volume from sysex + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_I32 EAS_GetVolume (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle); + +/*---------------------------------------------------------------------------- + * EAS_SetMaxLoad() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the maximum workload the parsers will do in a single call to + * EAS_Render. The units are currently arbitrary, but should correlate + * well to the actual CPU cycles consumed. The primary effect is to + * reduce the occasional peaks in CPU cycles consumed when parsing + * dense parts of a MIDI score. Setting maxWorkLoad to zero disables + * the workload limiting function. + * + * Inputs: + * pEASData - handle to data for this instance + * maxLoad - the desired maximum workload + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetMaxLoad (EAS_DATA_HANDLE pEASData, EAS_I32 maxLoad); + +/*---------------------------------------------------------------------------- + * EAS_SetMaxPCMStreams() + *---------------------------------------------------------------------------- + * Sets the maximum number of PCM streams allowed in parsers that + * use PCM streaming. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - handle returned by EAS_OpenFile + * maxNumStreams - maximum number of PCM streams + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetMaxPCMStreams (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 maxNumStreams); + +/*---------------------------------------------------------------------------- + * EAS_OpenFile() + *---------------------------------------------------------------------------- + * Purpose: + * Opens a file for audio playback. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * locator - pointer to filename or other locating information + * pStreamHandle - pointer to stream handle variable + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_OpenFile (EAS_DATA_HANDLE pEASData, EAS_FILE_LOCATOR locator, EAS_HANDLE *pStreamHandle); + +#ifdef MMAPI_SUPPORT +/*---------------------------------------------------------------------------- + * EAS_MMAPIToneControl() + *---------------------------------------------------------------------------- + * Purpose: + * Opens a ToneControl file for audio playback. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * locator - pointer to filename or other locating information + * pStreamHandle - pointer to stream handle variable + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_MMAPIToneControl (EAS_DATA_HANDLE pEASData, EAS_FILE_LOCATOR locator, EAS_HANDLE *pStreamHandle); + +/*---------------------------------------------------------------------------- + * EAS_GetWaveFmtChunk + *---------------------------------------------------------------------------- + * Helper function to retrieve WAVE file fmt chunk for MMAPI + *---------------------------------------------------------------------------- + * pEASData - pointer to EAS persistent data object + * streamHandle - stream handle + * pFmtChunk - pointer to pointer to FMT chunk data + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetWaveFmtChunk (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_VOID_PTR *ppFmtChunk); +#endif + +/*---------------------------------------------------------------------------- + * EAS_GetFileType + *---------------------------------------------------------------------------- + * Returns the file type (see eas_types.h for enumerations) + *---------------------------------------------------------------------------- + * pEASData - pointer to EAS persistent data object + * streamHandle - stream handle + * pFileType - pointer to variable to receive file type + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetFileType (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 *pFileType); + +/*---------------------------------------------------------------------------- + * EAS_ParseMetaData() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - file or stream handle + * playLength - pointer to variable to store the play length (in msecs) + * + * Outputs: + * + * + * Side Effects: + * - resets the parser to the start of the file + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_ParseMetaData (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 *pPlayLength); + +/*---------------------------------------------------------------------------- + * EAS_Prepare() + *---------------------------------------------------------------------------- + * Purpose: + * Prepares the synthesizer to play the file or stream. Parses the first + * frame of data from the file and arms the synthesizer. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - file or stream handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Prepare (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle); + +/*---------------------------------------------------------------------------- + * EAS_State() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the state of an audio file or stream. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - file or stream handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_State (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_STATE *pState); + +/*---------------------------------------------------------------------------- + * EAS_RegisterMetaDataCallback() + *---------------------------------------------------------------------------- + * Purpose: + * Registers a metadata callback function for parsed metadata. To + * de-register the callback, call this function again with parameter + * cbFunc set to NULL. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - file or stream handle + * cbFunc - pointer to host callback function + * metaDataBuffer - pointer to metadata buffer + * metaDataBufSize - maximum size of the metadata buffer + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_RegisterMetaDataCallback ( + EAS_DATA_HANDLE pEASData, + EAS_HANDLE streamHandle, + EAS_METADATA_CBFUNC cbFunc, + char *metaDataBuffer, + EAS_I32 metaDataBufSize, + EAS_VOID_PTR pUserData); + +/*---------------------------------------------------------------------------- + * EAS_GetNoteCount () + *---------------------------------------------------------------------------- + * Returns the total number of notes played in this stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - file or stream handle + * pNoteCount - pointer to variable to receive note count + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetNoteCount (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 *pNoteCount); + +/*---------------------------------------------------------------------------- + * EAS_CloseFile() + *---------------------------------------------------------------------------- + * Purpose: + * Closes an audio file or stream. Playback should have either paused or + * completed (EAS_State returns EAS_PAUSED or EAS_STOPPED). + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - file or stream handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_CloseFile (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle); + +/*---------------------------------------------------------------------------- + * EAS_OpenMIDIStream() + *---------------------------------------------------------------------------- + * Purpose: + * Opens a raw MIDI stream allowing the host to route MIDI cable data directly to the synthesizer + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * pStreamHandle - pointer to variable to hold file or stream handle + * streamHandle - open stream or NULL for new synthesizer instance + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_OpenMIDIStream (EAS_DATA_HANDLE pEASData, EAS_HANDLE *pStreamHandle, EAS_HANDLE streamHandle); + +/*---------------------------------------------------------------------------- + * EAS_WriteMIDIStream() + *---------------------------------------------------------------------------- + * Purpose: + * Send data to the MIDI stream device + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - stream handle + * pBuffer - pointer to buffer + * count - number of bytes to write + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_WriteMIDIStream(EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_U8 *pBuffer, EAS_I32 count); + +/*---------------------------------------------------------------------------- + * EAS_CloseMIDIStream() + *---------------------------------------------------------------------------- + * Purpose: + * Closes a raw MIDI stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - stream handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_CloseMIDIStream (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle); + +/*---------------------------------------------------------------------------- + * EAS_Locate() + *---------------------------------------------------------------------------- + * Purpose: + * Locate into the file associated with the handle. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - file handle + * milliseconds - playback offset from start of file in milliseconds + * + * Outputs: + * + * + * Side Effects: + * the actual offset will be quantized to the closest update period, typically + * a resolution of 5.9ms. Notes that are started prior to this time will not + * sound. Any notes currently playing will be shut off. + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Locate (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 milliseconds, EAS_BOOL offset); + +/*---------------------------------------------------------------------------- + * EAS_GetRenderTime() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current playback offset + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * + * Outputs: + * Gets the render time clock in msecs. + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetRenderTime (EAS_DATA_HANDLE pEASData, EAS_I32 *pTime); + +/*---------------------------------------------------------------------------- + * EAS_GetLocation() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current playback offset + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - file handle + * + * Outputs: + * The offset in milliseconds from the start of the current sequence, quantized + * to the nearest update period. Actual resolution is typically 5.9 ms. + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetLocation (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 *pTime); + +/*---------------------------------------------------------------------------- + * EAS_Pause() + *---------------------------------------------------------------------------- + * Purpose: + * Pauses the playback of the data associated with this handle. The audio + * is gracefully ramped down to prevent clicks and pops. It may take several + * buffers of audio before the audio is muted. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * streamHandle - file or stream handle + * + * Outputs: + * + * + * Side Effects: + * + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Pause (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle); + +/*---------------------------------------------------------------------------- + * EAS_Resume() + *---------------------------------------------------------------------------- + * Purpose: + * Resumes the playback of the data associated with this handle. The audio + * is gracefully ramped up to prevent clicks and pops. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * streamHandle - file or stream handle + * + * Outputs: + * + * + * Side Effects: + * + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Resume (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle); + +/*---------------------------------------------------------------------------- + * EAS_GetParameter() + *---------------------------------------------------------------------------- + * Purpose: + * Set the parameter of a module. See E_MODULES for a list of modules + * and the header files of the modules for a list of parameters. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * module - enumerated module number + * param - enumerated parameter number + * pValue - pointer to variable to receive parameter value + * + * Outputs: + * + * + * Side Effects: + * + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetParameter (EAS_DATA_HANDLE pEASData, EAS_I32 module, EAS_I32 param, EAS_I32 *pValue); + +/*---------------------------------------------------------------------------- + * EAS_SetParameter() + *---------------------------------------------------------------------------- + * Purpose: + * Set the parameter of a module. See E_MODULES for a list of modules + * and the header files of the modules for a list of parameters. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * handle - file or stream handle + * module - enumerated module number + * param - enumerated parameter number + * value - new parameter value + * + * Outputs: + * + * + * Side Effects: + * + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetParameter (EAS_DATA_HANDLE pEASData, EAS_I32 module, EAS_I32 param, EAS_I32 value); + +#ifdef _METRICS_ENABLED +/*---------------------------------------------------------------------------- + * EAS_MetricsReport() + *---------------------------------------------------------------------------- + * Purpose: + * Displays the current metrics through the EAS_Report interface. + * + * Inputs: + * pEASData - instance data handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_MetricsReport (EAS_DATA_HANDLE pEASData); + +/*---------------------------------------------------------------------------- + * EAS_MetricsReset() + *---------------------------------------------------------------------------- + * Purpose: + * Displays the current metrics through the EAS_Report interface. + * + * Inputs: + * pEASData - instance data handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_MetricsReset (EAS_DATA_HANDLE pEASData); +#endif + +/*---------------------------------------------------------------------------- + * EAS_SetSoundLibrary() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the location of the sound library. + * + * Inputs: + * pEASData - instance data handle + * streamHandle - file or stream handle + * pSoundLib - pointer to sound library + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetSoundLibrary (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_SNDLIB_HANDLE pSndLib); + +/*---------------------------------------------------------------------------- + * EAS_SetHeaderSearchFlag() + *---------------------------------------------------------------------------- + * By default, when EAS_OpenFile is called, the parsers check the + * first few bytes of the file looking for a specific header. Some + * mobile devices may add a header to the start of a file, which + * will prevent the parser from recognizing the file. If the + * searchFlag is set to EAS_TRUE, the parser will search the entire + * file looking for the header. This may enable EAS to recognize + * some files that it would ordinarily reject. The negative is that + * it make take slightly longer to process the EAS_OpenFile request. + * + * Inputs: + * pEASData - instance data handle + * searchFlag - search flag (EAS_TRUE or EAS_FALSE) + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetHeaderSearchFlag (EAS_DATA_HANDLE pEASData, EAS_BOOL searchFlag); + +/*---------------------------------------------------------------------------- + * EAS_SetPlayMode() + *---------------------------------------------------------------------------- + * Some file formats support special play modes, such as iMode partial + * play mode. This call can be used to change the play mode. The + * default play mode (usually straight playback) is always zero. + * + * Inputs: + * pEASData - instance data handle + * handle - file or stream handle + * playMode - play mode (see eas_types.h for enumerations) + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetPlayMode (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 playMode); + +#ifdef DLS_SYNTHESIZER +/*---------------------------------------------------------------------------- + * EAS_LoadDLSCollection() + *---------------------------------------------------------------------------- + * Purpose: + * Downloads a DLS collection + * + * Inputs: + * pEASData - instance data handle + * streamHandle - file or stream handle + * locator - file locator + * + * Outputs: + * + * + * Side Effects: + * May overlay instruments in the GM sound set + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_LoadDLSCollection (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_FILE_LOCATOR locator); +#endif + +/*---------------------------------------------------------------------------- + * EAS_SetFrameBuffer() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the frame buffer pointer passed to the IPC communications functions + * + * Inputs: + * pEASData - instance data handle + * locator - file locator + * + * Outputs: + * + * + * Side Effects: + * May overlay instruments in the GM sound set + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetFrameBuffer (EAS_DATA_HANDLE pEASData, EAS_FRAME_BUFFER_HANDLE pFrameBuffer); + +#ifdef EXTERNAL_AUDIO +/*---------------------------------------------------------------------------- + * EAS_RegExtAudioCallback() + *---------------------------------------------------------------------------- + * Purpose: + * Registers callback functions for audio events. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - file or stream handle + * cbProgChgFunc - pointer to host callback function for program change + * cbEventFunc - pointer to host callback functio for note events + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_RegExtAudioCallback (EAS_DATA_HANDLE pEASData, + EAS_HANDLE streamHandle, + EAS_VOID_PTR pInstData, + EAS_EXT_PRG_CHG_FUNC cbProgChgFunc, + EAS_EXT_EVENT_FUNC cbEventFunc); + +/*---------------------------------------------------------------------------- + * EAS_GetMIDIControllers() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current state of MIDI controllers on the requested channel. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - file or stream handle + * pControl - pointer to structure to receive data + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetMIDIControllers (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_U8 channel, S_MIDI_CONTROLLERS *pControl); +#endif + +/*---------------------------------------------------------------------------- + * EAS_SearchFile + *---------------------------------------------------------------------------- + * Search file for specific sequence starting at current file + * position. Returns offset to start of sequence. + * + * Inputs: + * pEASData - pointer to EAS persistent data object + * fileHandle - file handle + * searchString - pointer to search sequence + * len - length of search sequence + * pOffset - pointer to variable to store offset to sequence + * + * Returns EAS_EOF if end-of-file is reached + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_SearchFile (EAS_DATA_HANDLE pEASData, EAS_FILE_HANDLE fileHandle, const EAS_U8 *searchString, EAS_I32 len, EAS_I32 *pOffset); + +#ifdef __cplusplus +} /* end extern "C" */ +#endif + +#endif /* #ifndef _EAS_H */ diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_build.h b/common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_build.h new file mode 100755 index 0000000..5b058e7 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_build.h @@ -0,0 +1,36 @@ +/*---------------------------------------------------------------------------- + * + * File: + * host_src\eas_build.h + * + * Contents and purpose: + * This file contains the build configuration for this + * build. The buildGUIDStr is a GUID created during + * the build process and is guaranteed to be unique + * for each build. + * + * Copyright Sonic Network Inc. 2006 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file was autogenerated by buildid.exe + *---------------------------------------------------------------------------- +*/ + +#ifndef _GUID_53c2509edf8f42e3975a054126c0cc1b_ +#define _GUID_53c2509edf8f42e3975a054126c0cc1b_ + +#define _BUILD_VERSION_ "53c2509e-df8f-42e3-975a-054126c0cc1b" +#define _BUILD_TIME_ 0x4743b8c9 + +#endif /* _GUID_53c2509edf8f42e3975a054126c0cc1b_ */ diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_chorus.h b/common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_chorus.h new file mode 100755 index 0000000..998a828 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_chorus.h @@ -0,0 +1,53 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_chorus.h + * + * Contents and purpose: + * Contains parameter enumerations for the Chorus effect + * + * + * Copyright Sonic Network Inc. 2006 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 309 $ + * $Date: 2006-09-12 18:52:45 -0700 (Tue, 12 Sep 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef EAS_CHORUS_H +#define EAS_CHORUS_H + +/* enumerated parameter settings for Chorus effect */ +typedef enum +{ + EAS_PARAM_CHORUS_BYPASS, + EAS_PARAM_CHORUS_PRESET, + EAS_PARAM_CHORUS_RATE, + EAS_PARAM_CHORUS_DEPTH, + EAS_PARAM_CHORUS_LEVEL +} E_CHORUS_PARAMS; + +typedef enum +{ + EAS_PARAM_CHORUS_PRESET1, + EAS_PARAM_CHORUS_PRESET2, + EAS_PARAM_CHORUS_PRESET3, + EAS_PARAM_CHORUS_PRESET4 +} E_CHORUS_PRESETS; + + +#endif \ No newline at end of file diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_config.c b/common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_config.c new file mode 100755 index 0000000..0b92357 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_config.c @@ -0,0 +1,619 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_config.c + * + * Contents and purpose: + * This file contains the Configuration Module interface (CM). The CM + * is a module compiled external to the library that sets the configuration + * for this build. It allows the library to find optional components and + * links to static memory allocations (when used in a static configuration). + * + * DO NOT MODIFY THIS FILE! + * + * NOTE: This module is not intended to be modified by the customer. It + * needs to be included in the build process with the correct configuration + * defines (see the library documentation for information on how to configure + * the library). + * + * Copyright Sonic Network Inc. 2004-2006 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 796 $ + * $Date: 2007-08-01 00:15:25 -0700 (Wed, 01 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas.h" +#include "eas_config.h" + + +#ifdef _MFI_PARSER +/*---------------------------------------------------------------------------- + * Vendor/Device ID for MFi Extensions + * + * Define the preprocessor symbols to establish the vendor ID and + * device ID for the MFi PCM/ADPCM extensions. + *---------------------------------------------------------------------------- +*/ +const EAS_U8 eas_MFIVendorIDMSB = (MFI_VENDOR_ID >> 8) & 0xff; +const EAS_U8 eas_MFIVendorIDLSB = MFI_VENDOR_ID & 0xff; +const EAS_U8 eas_MFIDeviceID = MFI_DEVICE_ID; +#endif + +/*---------------------------------------------------------------------------- + * + * parserModules + * + * This structure is used by the EAS library to locate file parsing + * modules. + *---------------------------------------------------------------------------- +*/ + +/* define the external file parsers */ +extern EAS_VOID_PTR EAS_SMF_Parser; + +#ifdef _XMF_PARSER +extern EAS_VOID_PTR EAS_XMF_Parser; +#endif + +#ifdef _SMAF_PARSER +extern EAS_VOID_PTR EAS_SMAF_Parser; +#endif + +#ifdef _WAVE_PARSER +extern EAS_VOID_PTR EAS_Wave_Parser; +#endif + +#ifdef _OTA_PARSER +extern EAS_VOID_PTR EAS_OTA_Parser; +#endif + +#ifdef _IMELODY_PARSER +extern EAS_VOID_PTR EAS_iMelody_Parser; +#endif + +#ifdef _RTTTL_PARSER +extern EAS_VOID_PTR EAS_RTTTL_Parser; +#endif + +#if defined (_CMX_PARSER) || defined(_MFI_PARSER) +extern EAS_VOID_PTR EAS_CMF_Parser; +#endif + +/* initalize pointers to parser interfaces */ +/*lint -e{605} not pretty, but it works */ +EAS_VOID_PTR const parserModules[] = +{ + &EAS_SMF_Parser, + +#ifdef _XMF_PARSER + &EAS_XMF_Parser, +#endif + +#ifdef _WAVE_PARSER + &EAS_Wave_Parser, +#endif + +#ifdef _SMAF_PARSER + &EAS_SMAF_Parser, +#endif + +#ifdef _OTA_PARSER + &EAS_OTA_Parser, +#endif + +#ifdef _IMELODY_PARSER + &EAS_iMelody_Parser, +#endif + +#ifdef _RTTTL_PARSER + &EAS_RTTTL_Parser, +#endif + +#if defined (_CMX_PARSER) || defined(_MFI_PARSER) + &EAS_CMF_Parser +#endif +}; +#define NUM_PARSER_MODULES (sizeof(parserModules) / sizeof(EAS_VOID_PTR)) + +/*---------------------------------------------------------------------------- + * Data Modules + *---------------------------------------------------------------------------- +*/ + +#ifdef _STATIC_MEMORY +extern EAS_VOID_PTR eas_SMFData; +extern EAS_VOID_PTR eas_Data; +extern EAS_VOID_PTR eas_MixBuffer; +extern EAS_VOID_PTR eas_Synth; +extern EAS_VOID_PTR eas_MIDI; +extern EAS_VOID_PTR eas_PCMData; +extern EAS_VOID_PTR eas_MIDIData; + +#ifdef _XMF_PARSER +extern EAS_VOID_PTR eas_XMFData; +#endif + +#ifdef _SMAF_PARSER +extern EAS_VOID_PTR eas_SMAFData; +#endif + +#ifdef _OTA_PARSER +extern EAS_VOID_PTR eas_OTAData; +#endif + +#ifdef _IMELODY_PARSER +extern EAS_VOID_PTR eas_iMelodyData; +#endif + +#ifdef _RTTTL_PARSER +extern EAS_VOID_PTR eas_RTTTLData; +#endif + +#ifdef _WAVE_PARSER +extern EAS_VOID_PTR eas_WaveData; +#endif + +#if defined (_CMX_PARSER) || defined(_MFI_PARSER) +extern EAS_VOID_PTR eas_CMFData; +#endif +#endif + +/*---------------------------------------------------------------------------- + * + * Effects Modules + * + * These declarations are used by the EAS library to locate + * effects modules. + *---------------------------------------------------------------------------- +*/ + +#ifdef _ENHANCER_ENABLED +extern EAS_VOID_PTR EAS_Enhancer; +#define EAS_ENHANCER_INTERFACE &EAS_Enhancer +#ifdef _STATIC_MEMORY +extern EAS_VOID_PTR eas_EnhancerData; +#define EAS_ENHANCER_DATA &eas_EnhancerData +#else +#define EAS_ENHANCER_DATA NULL +#endif +#else +#define EAS_ENHANCER_INTERFACE NULL +#define EAS_ENHANCER_DATA NULL +#endif + +#ifdef _COMPRESSOR_ENABLED +extern EAS_VOID_PTR EAS_Compressor; +#define EAS_COMPRESSOR_INTERFACE &EAS_Compressor +#ifdef _STATIC_MEMORY +extern EAS_VOID_PTR eas_CompressorData; +#define EAS_COMPRESSOR_DATA &eas_CompressorData +#else +#define EAS_COMPRESSOR_DATA NULL +#endif +#else +#define EAS_COMPRESSOR_INTERFACE NULL +#define EAS_COMPRESSOR_DATA NULL +#endif + +#ifdef _MAXIMIZER_ENABLED +extern EAS_VOID_PTR EAS_Maximizer; +#define EAS_MAXIMIZER_INTERFACE &EAS_Maximizer +#ifdef _STATIC_MEMORY +extern EAS_VOID_PTR eas_MaximizerData; +#define EAS_MAXIMIZER_DATA &eas_MaximizerData +#else +#define EAS_MAXIMIZER_DATA NULL +#endif +#else +#define EAS_MAXIMIZER_INTERFACE NULL +#define EAS_MAXIMIZER_DATA NULL +#endif + + +#ifdef _REVERB_ENABLED +extern EAS_VOID_PTR EAS_Reverb; +#define EAS_REVERB_INTERFACE &EAS_Reverb +#ifdef _STATIC_MEMORY +extern EAS_VOID_PTR eas_ReverbData; +#define EAS_REVERB_DATA &eas_ReverbData +#else +#define EAS_REVERB_DATA NULL +#endif +#else +#define EAS_REVERB_INTERFACE NULL +#define EAS_REVERB_DATA NULL +#endif + +#ifdef _CHORUS_ENABLED +extern EAS_VOID_PTR EAS_Chorus; +#define EAS_CHORUS_INTERFACE &EAS_Chorus +#ifdef _STATIC_MEMORY +extern EAS_VOID_PTR eas_ChorusData; +#define EAS_CHORUS_DATA &eas_ChorusData +#else +#define EAS_CHORUS_DATA NULL +#endif +#else +#define EAS_CHORUS_INTERFACE NULL +#define EAS_CHORUS_DATA NULL +#endif + +#ifdef _WIDENER_ENABLED +extern EAS_VOID_PTR EAS_Widener; +#define EAS_WIDENER_INTERFACE &EAS_Widener +#ifdef _STATIC_MEMORY +extern EAS_VOID_PTR eas_WidenerData; +#define EAS_WIDENER_DATA &eas_WidenerData +#else +#define EAS_WIDENER_DATA NULL +#endif +#else +#define EAS_WIDENER_INTERFACE NULL +#define EAS_WIDENER_DATA NULL +#endif + +#ifdef _GRAPHIC_EQ_ENABLED +extern EAS_VOID_PTR EAS_GraphicEQ; +#define EAS_GRAPHIC_EQ_INTERFACE &EAS_GraphicEQ +#ifdef _STATIC_MEMORY +extern EAS_VOID_PTR eas_GraphicEQData; +#define EAS_GRAPHIC_EQ_DATA &eas_GraphicEQData +#else +#define EAS_GRAPHIC_EQ_DATA NULL +#endif +#else +#define EAS_GRAPHIC_EQ_INTERFACE NULL +#define EAS_GRAPHIC_EQ_DATA NULL +#endif + +#ifdef _WOW_ENABLED +extern EAS_VOID_PTR EAS_Wow; +#define EAS_WOW_INTERFACE &EAS_Wow +#ifdef _STATIC_MEMORY +#error "WOW module requires dynamic memory model" +#else +#define EAS_WOW_DATA NULL +#endif +#else +#define EAS_WOW_INTERFACE NULL +#define EAS_WOW_DATA NULL +#endif + +#ifdef _TONECONTROLEQ_ENABLED +extern EAS_VOID_PTR EAS_ToneControlEQ; +#define EAS_TONECONTROLEQ_INTERFACE &EAS_ToneControlEQ +#ifdef _STATIC_MEMORY +extern EAS_VOID_PTR eas_ToneControlEQData; +#define EAS_TONECONTROLEQ_DATA &eas_ToneControlEQData +#else +#define EAS_TONECONTROLEQ_DATA NULL +#endif +#else +#define EAS_TONECONTROLEQ_INTERFACE NULL +#define EAS_TONECONTROLEQ_DATA NULL +#endif + +/*lint -e{605} not pretty, but it works */ +EAS_VOID_PTR const effectsModules[] = +{ + EAS_ENHANCER_INTERFACE, + EAS_COMPRESSOR_INTERFACE, + EAS_REVERB_INTERFACE, + EAS_CHORUS_INTERFACE, + EAS_WIDENER_INTERFACE, + EAS_GRAPHIC_EQ_INTERFACE, + EAS_WOW_INTERFACE, + EAS_MAXIMIZER_INTERFACE, + EAS_TONECONTROLEQ_INTERFACE +}; + +EAS_VOID_PTR const effectsData[] = +{ + EAS_ENHANCER_DATA, + EAS_COMPRESSOR_DATA, + EAS_REVERB_DATA, + EAS_CHORUS_DATA, + EAS_WIDENER_DATA, + EAS_GRAPHIC_EQ_DATA, + EAS_WOW_DATA, + EAS_MAXIMIZER_DATA, + EAS_TONECONTROLEQ_DATA +}; + +/*---------------------------------------------------------------------------- + * + * Optional Modules + * + * These declarations are used by the EAS library to locate + * effects modules. + *---------------------------------------------------------------------------- +*/ + +#ifdef _METRICS_ENABLED +extern EAS_VOID_PTR EAS_Metrics; +#define EAS_METRICS_INTERFACE &EAS_Metrics +#ifdef _STATIC_MEMORY +extern EAS_VOID_PTR eas_MetricsData; +#define EAS_METRICS_DATA &eas_MetricsData +#else +#define EAS_METRICS_DATA NULL +#endif +#else +#define EAS_METRICS_INTERFACE NULL +#define EAS_METRICS_DATA NULL +#endif + +#ifdef MMAPI_SUPPORT +extern EAS_VOID_PTR EAS_TC_Parser; +#define EAS_TONE_CONTROL_PARSER &EAS_TC_Parser +#ifdef _STATIC_MEMORY +extern EAS_VOID_PTR eas_TCData; +#define EAS_TONE_CONTROL_DATA &eas_TCData +#else +#define EAS_TONE_CONTROL_DATA NULL +#endif +#else +#define EAS_TONE_CONTROL_PARSER NULL +#define EAS_TONE_CONTROL_DATA NULL +#endif + +/*lint -e{605} not pretty, but it works */ +EAS_VOID_PTR const optionalModules[] = +{ + EAS_TONE_CONTROL_PARSER, + EAS_METRICS_INTERFACE +}; + +EAS_VOID_PTR const optionalData[] = +{ + EAS_TONE_CONTROL_DATA, + EAS_METRICS_DATA +}; + +/*---------------------------------------------------------------------------- + * EAS_CMStaticMemoryModel() + *---------------------------------------------------------------------------- + * Purpose: + * This function returns true if EAS has been configured for + * a static memory model. There are some limitations in the + * static memory model, see the documentation for more + * information. + * + * Outputs: + * returns EAS_TRUE if a module is found + *---------------------------------------------------------------------------- +*/ +EAS_BOOL EAS_CMStaticMemoryModel (void) +{ +#ifdef _STATIC_MEMORY + return EAS_TRUE; +#else + return EAS_FALSE; +#endif +} + +/*---------------------------------------------------------------------------- + * EAS_CMEnumModules() + *---------------------------------------------------------------------------- + * Purpose: + * This function is used to find pointers to optional modules. + * + * Inputs: + * module - module number + * + * Outputs: + * returns a pointer to the module function table or NULL if no module + *---------------------------------------------------------------------------- +*/ +EAS_VOID_PTR EAS_CMEnumModules (EAS_INT module) +{ + + if (module >= (EAS_INT) NUM_PARSER_MODULES) + return NULL; + return parserModules[module]; +} + +/*---------------------------------------------------------------------------- + * EAS_CMEnumData() + *---------------------------------------------------------------------------- + * Purpose: + * This function is used to find pointers to static memory allocations. + * + * Inputs: + * dataModule - enumerated module number + * + * Outputs: + * Returns handle to data or NULL if not found + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, dataModule) used only when _STATIC_MEMORY is defined */ +EAS_VOID_PTR EAS_CMEnumData (EAS_INT dataModule) +{ + +#ifdef _STATIC_MEMORY + switch (dataModule) + { + + /* main instance data for synthesizer */ + case EAS_CM_EAS_DATA: + return &eas_Data; + + /* mix buffer for mix engine */ + case EAS_CM_MIX_BUFFER: + /*lint -e{545} lint doesn't like this because it sees the underlying type */ + return &eas_MixBuffer; + + /* instance data for synth */ + case EAS_CM_SYNTH_DATA: + return &eas_Synth; + + /* instance data for MIDI parser */ + case EAS_CM_MIDI_DATA: + return &eas_MIDI; + + /* instance data for SMF parser */ + case EAS_CM_SMF_DATA: + return &eas_SMFData; + +#ifdef _XMF_PARSER + /* instance data for XMF parser */ + case EAS_CM_XMF_DATA: + return &eas_XMFData; +#endif + +#ifdef _SMAF_PARSER + /* instance data for SMAF parser */ + case EAS_CM_SMAF_DATA: + return &eas_SMAFData; +#endif + + /* instance data for the PCM engine */ + case EAS_CM_PCM_DATA: + /*lint -e{545} lint doesn't like this because it sees the underlying type */ + return &eas_PCMData; + + case EAS_CM_MIDI_STREAM_DATA: + return &eas_MIDIData; + +#ifdef _OTA_PARSER + /* instance data for OTA parser */ + case EAS_CM_OTA_DATA: + return &eas_OTAData; +#endif + +#ifdef _IMELODY_PARSER + /* instance data for iMelody parser */ + case EAS_CM_IMELODY_DATA: + return &eas_iMelodyData; +#endif + +#ifdef _RTTTL_PARSER + /* instance data for RTTTL parser */ + case EAS_CM_RTTTL_DATA: + return &eas_RTTTLData; +#endif + +#ifdef _WAVE_PARSER + /* instance data for WAVE parser */ + case EAS_CM_WAVE_DATA: + return &eas_WaveData; +#endif + +#if defined (_CMX_PARSER) || defined(_MFI_PARSER) + /* instance data for CMF parser */ + case EAS_CM_CMF_DATA: + return &eas_CMFData; +#endif + + default: + return NULL; + } + +#else + return NULL; +#endif +} + +/*---------------------------------------------------------------------------- + * EAS_CMEnumFXModules() + *---------------------------------------------------------------------------- + * Purpose: + * This function is used to find pointers to optional effects modules. + * + * Inputs: + * module - enumerated module number + * pModule - pointer to module interface + * + * Outputs: + * Returns pointer to function table or NULL if not found + *---------------------------------------------------------------------------- +*/ +EAS_VOID_PTR EAS_CMEnumFXModules (EAS_INT module) +{ + + if (module >= NUM_EFFECTS_MODULES) + return NULL; + return effectsModules[module]; +} + +/*---------------------------------------------------------------------------- + * EAS_CMEnumFXData() + *---------------------------------------------------------------------------- + * Purpose: + * This function is used to find pointers to static memory allocations. + * + * Inputs: + * dataModule - enumerated module number + * pData - pointer to handle variable + * + * Outputs: + * Returns handle to data or NULL if not found + *---------------------------------------------------------------------------- +*/ +EAS_VOID_PTR EAS_CMEnumFXData (EAS_INT dataModule) +{ + + if (dataModule >= NUM_EFFECTS_MODULES) + return NULL; + return effectsData[dataModule]; +} + +/*---------------------------------------------------------------------------- + * EAS_CMEnumOptModules() + *---------------------------------------------------------------------------- + * Purpose: + * This function is used to find pointers to optional modules. + * + * Inputs: + * module - enumerated module number + * + * Outputs: + * returns pointer to function table or NULL if no module + *---------------------------------------------------------------------------- +*/ +EAS_VOID_PTR EAS_CMEnumOptModules (EAS_INT module) +{ + + /* sanity check */ + if (module >= NUM_OPTIONAL_MODULES) + return EAS_FALSE; + return optionalModules[module]; +} + +/*---------------------------------------------------------------------------- + * EAS_CMEnumOptData() + *---------------------------------------------------------------------------- + * Purpose: + * This function is used to find pointers to static memory allocations. + * + * Inputs: + * dataModule - enumerated module number + * + * Outputs: + * Returns handle to data or NULL if not found + *---------------------------------------------------------------------------- +*/ +EAS_VOID_PTR EAS_CMEnumOptData (EAS_INT dataModule) +{ + + if (dataModule >= NUM_OPTIONAL_MODULES) + return NULL; + return optionalData[dataModule]; +} + + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_config.h b/common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_config.h new file mode 100755 index 0000000..49c2ef2 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_config.h @@ -0,0 +1,191 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_config.h + * + * Contents and purpose: + * This header declares the Configuration Module interface (CM). The CM + * is a module compiled external to the library that sets the configuration + * for this build. It allows the library to find optional components and + * links to static memory allocations (when used in a static configuration). + * + * NOTE: This module is not intended to be modified by the customer. It + * needs to be included in the build process with the correct configuration + * defines (see the library documentation for information on how to configure + * the library). + * + * DO NOT MODIFY THIS FILE! + * + * Copyright 2005 Sonic Network Inc. + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +// sentinel +#ifndef _EAS_CONFIG_H +#define _EAS_CONFIG_H + +#include "eas_types.h" + +/* list of enumerators for optional modules */ +typedef enum { + EAS_CM_FILE_PARSERS = 1 +} E_CM_ENUM_MODULES; + +/* list of enumerators for module and memory pointers */ +typedef enum { + EAS_CM_EAS_DATA = 1, + EAS_CM_MIX_BUFFER, + EAS_CM_SYNTH_DATA, + EAS_CM_MIDI_DATA, + EAS_CM_SMF_DATA, + EAS_CM_XMF_DATA, + EAS_CM_SMAF_DATA, + EAS_CM_PCM_DATA, + EAS_CM_MIDI_STREAM_DATA, + EAS_CM_METRICS_DATA, + EAS_CM_OTA_DATA, + EAS_CM_IMELODY_DATA, + EAS_CM_RTTTL_DATA, + EAS_CM_WAVE_DATA, + EAS_CM_CMF_DATA +} E_CM_DATA_MODULES; + +typedef struct +{ + int maxSMFStreams; + void *pSMFData; + void *pSMFStream; +} S_EAS_SMF_PTRS; + +typedef struct +{ + int maxSMAFStreams; + void *pSMAFData; + void *pSMAFStream; +} S_EAS_SMAF_PTRS; + +/*---------------------------------------------------------------------------- + * EAS_CMStaticMemoryModel() + *---------------------------------------------------------------------------- + * Purpose: + * This function returns true if EAS has been configured for + * a static memory model. There are some limitations in the + * static memory model, see the documentation for more + * information. + * + * Outputs: + * returns EAS_TRUE if a module is found + *---------------------------------------------------------------------------- +*/ +EAS_BOOL EAS_CMStaticMemoryModel (void); + +/*---------------------------------------------------------------------------- + * EAS_CMEnumModules() + *---------------------------------------------------------------------------- + * Purpose: + * This function is used to find pointers to optional modules. + * + * Inputs: + * module - module number + * + * Outputs: + * returns a pointer to the module function table or NULL if no module + *---------------------------------------------------------------------------- +*/ +EAS_VOID_PTR EAS_CMEnumModules (EAS_INT module); + +/*---------------------------------------------------------------------------- + * EAS_CMEnumData() + *---------------------------------------------------------------------------- + * Purpose: + * This function is used to find pointers to static memory allocations. + * + * Inputs: + * dataModule - enumerated module number + * + * Outputs: + * Returns handle to data or NULL if not found + *---------------------------------------------------------------------------- +*/ +EAS_VOID_PTR EAS_CMEnumData (EAS_INT dataModule); + +/*---------------------------------------------------------------------------- + * EAS_CMEnumFXModules() + *---------------------------------------------------------------------------- + * Purpose: + * This function is used to find pointers to optional effects modules. + * + * Inputs: + * module - enumerated module number + * pModule - pointer to module interface + * + * Outputs: + * Returns pointer to function table or NULL if not found + *---------------------------------------------------------------------------- +*/ +EAS_VOID_PTR EAS_CMEnumFXModules (EAS_INT module); + +/*---------------------------------------------------------------------------- + * EAS_CMEnumFXData() + *---------------------------------------------------------------------------- + * Purpose: + * This function is used to find pointers to static memory allocations. + * + * Inputs: + * dataModule - enumerated module number + * pData - pointer to handle variable + * + * Outputs: + * Returns handle to data or NULL if not found + *---------------------------------------------------------------------------- +*/ +EAS_VOID_PTR EAS_CMEnumFXData (EAS_INT dataModule); + +/*---------------------------------------------------------------------------- + * EAS_CMEnumOptModules() + *---------------------------------------------------------------------------- + * Purpose: + * This function is used to find pointers to optional modules. + * + * Inputs: + * module - enumerated module number + * + * Outputs: + * returns pointer to function table or NULL if no module + *---------------------------------------------------------------------------- +*/ +EAS_VOID_PTR EAS_CMEnumOptModules (EAS_INT module); + +/*---------------------------------------------------------------------------- + * EAS_CMEnumOptData() + *---------------------------------------------------------------------------- + * Purpose: + * This function is used to find pointers to static memory allocations. + * + * Inputs: + * dataModule - enumerated module number + * + * Outputs: + * Returns handle to data or NULL if not found + *---------------------------------------------------------------------------- +*/ +EAS_VOID_PTR EAS_CMEnumOptData (EAS_INT dataModule); + +#endif /* end _EAS_CONFIG_H */ diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_debugmsgs.h b/common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_debugmsgs.h new file mode 100755 index 0000000..de60259 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_debugmsgs.h @@ -0,0 +1,43 @@ +/* Auto-generated from source file: eas_chorusdata.c */ +/* Auto-generated from source file: eas_imelodydata.c */ +/* Auto-generated from source file: eas_mididata.c */ +/* Auto-generated from source file: eas_pan.c */ +/* Auto-generated from source file: eas_wavefiledata.c */ +/* Auto-generated from source file: eas_voicemgt.c */ +/* Auto-generated from source file: eas_ota.c */ +/* Auto-generated from source file: eas_mixbuf.c */ +/* Auto-generated from source file: eas_fmsndlib.c */ +/* Auto-generated from source file: eas_rtttl.c */ +/* Auto-generated from source file: eas_reverb.c */ +/* Auto-generated from source file: eas_fmsynth.c */ +/* Auto-generated from source file: eas_pcmdata.c */ +/* Auto-generated from source file: eas_chorus.c */ +/* Auto-generated from source file: eas_math.c */ +/* Auto-generated from source file: eas_fmengine.c */ +/* Auto-generated from source file: eas_smfdata.c */ +/* Auto-generated from source file: eas_fmtables.c */ +/* Auto-generated from source file: eas_imelody.c */ +/* Auto-generated from source file: eas_public.c */ +/* Auto-generated from source file: eas_rtttldata.c */ +/* Auto-generated from source file: eas_reverbdata.c */ +/* Auto-generated from source file: eas_imaadpcm.c */ +{ 0x2380b977, 0x00000006, "eas_imaadpcm.c[305]: IMADecoderLocate: Time=%d, samples=%d\n" }, +{ 0x2380b977, 0x00000007, "eas_imaadpcm.c[328]: IMADecoderLocate: Looped sample, numBlocks=%d, samplesPerLoop=%d, samplesInLastBlock=%d, samples=%d\n" }, +{ 0x2380b977, 0x00000008, "eas_imaadpcm.c[335]: IMADecoderLocate: Byte location in audio = %d\n" }, +{ 0x2380b977, 0x00000009, "eas_imaadpcm.c[345]: IMADecoderLocate: bytesLeft = %d\n" }, +/* Auto-generated from source file: eas_midi.c */ +/* Auto-generated from source file: eas_otadata.c */ +/* Auto-generated from source file: eas_ima_tables.c */ +/* Auto-generated from source file: eas_data.c */ +/* Auto-generated from source file: eas_pcm.c */ +/* Auto-generated from source file: eas_mixer.c */ +/* Auto-generated from source file: eas_wavefile.c */ +/* Auto-generated from source file: eas_smf.c */ +/* Auto-generated from source file: eas_wave.c */ +/* Auto-generated from source file: eas_hostmm.c */ +{ 0x1a54b6e8, 0x00000001, "eas_hostmm.c[586]: Vibrate state: %d\n" }, +{ 0x1a54b6e8, 0x00000002, "eas_hostmm.c[601]: LED state: %d\n" }, +{ 0x1a54b6e8, 0x00000003, "eas_hostmm.c[616]: Backlight state: %d\n" }, +/* Auto-generated from source file: eas_config.c */ +/* Auto-generated from source file: eas_main.c */ +{ 0xe624f4d9, 0x00000005, "eas_main.c[106]: Play length: %d.%03d (secs)\n" }, diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_host.h b/common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_host.h new file mode 100755 index 0000000..b356982 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_host.h @@ -0,0 +1,83 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_host.h + * + * Contents and purpose: + * This header defines the host wrapper functions for stdio, stdlib, etc. + * The host application must provide an abstraction layer for these functions + * to support certain features, such as SMAF and SMF-1 conversion. + * + * DO NOT MODIFY THIS FILE! + * + * Copyright 2005 Sonic Network Inc. + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +// sentinel +#ifndef _EAS_HOST_H +#define _EAS_HOST_H + +#include "eas_types.h" + +/* for C++ linkage */ +#ifdef __cplusplus +extern "C" { +#endif + +/* initialization and shutdown routines */ +extern EAS_RESULT EAS_HWInit(EAS_HW_DATA_HANDLE *hwInstData); +extern EAS_RESULT EAS_HWShutdown(EAS_HW_DATA_HANDLE hwInstData); + +/* memory functions */ +extern void *EAS_HWMemSet(void *s, int c, EAS_I32 n); +extern void *EAS_HWMemCpy(void *s1, const void *s2, EAS_I32 n); +extern EAS_I32 EAS_HWMemCmp(const void *s1, const void *s2, EAS_I32 n); + +/* memory allocation */ +extern void *EAS_HWMalloc(EAS_HW_DATA_HANDLE hwInstData, EAS_I32 size); +extern void EAS_HWFree(EAS_HW_DATA_HANDLE hwInstData, void *p); + +/* file I/O */ +extern EAS_RESULT EAS_HWOpenFile(EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_LOCATOR locator, EAS_FILE_HANDLE *pFile, EAS_FILE_MODE mode); +extern EAS_RESULT EAS_HWReadFile(EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *pBuffer, EAS_I32 n, EAS_I32 *pBytesRead); +extern EAS_RESULT EAS_HWGetByte(EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *p); +extern EAS_RESULT EAS_HWGetWord (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *p, EAS_BOOL msbFirst); +extern EAS_RESULT EAS_HWGetDWord (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *p, EAS_BOOL msbFirst); +extern EAS_RESULT EAS_HWFilePos (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 *pPosition); +extern EAS_RESULT EAS_HWFileSeek (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 position); +extern EAS_RESULT EAS_HWFileSeekOfs (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 position); +extern EAS_RESULT EAS_HWFileLength (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 *pLength); +extern EAS_RESULT EAS_HWDupHandle (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_FILE_HANDLE* pFile); +extern EAS_RESULT EAS_HWCloseFile (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file); + +/* vibrate, LED, and backlight functions */ +extern EAS_RESULT EAS_HWVibrate(EAS_HW_DATA_HANDLE hwInstData, EAS_BOOL state); +extern EAS_RESULT EAS_HWLED(EAS_HW_DATA_HANDLE hwInstData, EAS_BOOL state); +extern EAS_RESULT EAS_HWBackLight(EAS_HW_DATA_HANDLE hwInstData, EAS_BOOL state); + +#ifdef __cplusplus +} /* end extern "C" */ +#endif + + +/* host yield function */ +extern EAS_BOOL EAS_HWYield(EAS_HW_DATA_HANDLE hwInstData); +#endif /* end _EAS_HOST_H */ diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_hostmm.c b/common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_hostmm.c new file mode 100755 index 0000000..df24cf2 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_hostmm.c @@ -0,0 +1,660 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_hostmm.c + * + * Contents and purpose: + * This file contains the host wrapper functions for stdio, stdlib, etc. + * This is a sample version that maps the requested files to an + * allocated memory block and uses in-memory pointers to replace + * file system calls. The file locator (EAS_FILE_LOCATOR) handle passed + * HWOpenFile is the same one that is passed to EAS_OpenFile. If your + * system stores data in fixed locations (such as flash) instead of + * using a file system, you can use the locator handle to point to + * your memory. You will need a way of knowing the length of the + * data stored at that location in order to respond correctly in the + * HW_FileLength function. + * + * Modify this file to suit the needs of your particular system. + * + * EAS_MAX_FILE_HANDLES sets the maximum number of MIDI streams within + * a MIDI type 1 file that can be played. + * + * EAS_HW_FILE is a structure to support the file I/O functions. It + * comprises the base memory pointer, the file read pointer, and + * the dup flag, which when sets, indicates that the file handle has + * been duplicated. If your system uses in-memory resources, you + * can eliminate the duplicate handle logic, and simply copy the + * base memory pointer and file read pointer to the duplicate handle. + * + * Copyright 2005 Sonic Network Inc. + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 795 $ + * $Date: 2007-08-01 00:14:45 -0700 (Wed, 01 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifdef _lint +#include "lint_stdlib.h" +#else +#include +#include +#include +#endif + +#include "eas_host.h" + +/* Only for debugging LED, vibrate, and backlight functions */ +#include "eas_report.h" + +/* this module requires dynamic memory support */ +#ifdef _STATIC_MEMORY +#error "eas_hostmm.c requires the dynamic memory model!\n" +#endif + +#ifndef EAS_MAX_FILE_HANDLES +#define EAS_MAX_FILE_HANDLES 32 +#endif + +/* + * this structure and the related function are here + * to support the ability to create duplicate handles + * and buffering it in memory. If your system uses + * in-memory resources, you can eliminate the calls + * to malloc and free, the dup flag, and simply track + * the file size and read position. + */ +typedef struct eas_hw_file_tag +{ + EAS_I32 fileSize; + EAS_I32 filePos; + EAS_BOOL dup; + EAS_U8 *buffer; +} EAS_HW_FILE; + +typedef struct eas_hw_inst_data_tag +{ + EAS_HW_FILE files[EAS_MAX_FILE_HANDLES]; +} EAS_HW_INST_DATA; + +/*---------------------------------------------------------------------------- + * EAS_HWInit + * + * Initialize host wrapper interface + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_HWInit (EAS_HW_DATA_HANDLE *pHWInstData) +{ + + /* need to track file opens for duplicate handles */ + *pHWInstData = malloc(sizeof(EAS_HW_INST_DATA)); + if (!(*pHWInstData)) + return EAS_ERROR_MALLOC_FAILED; + + EAS_HWMemSet(*pHWInstData, 0, sizeof(EAS_HW_INST_DATA)); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_HWShutdown + * + * Shut down host wrapper interface + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_HWShutdown (EAS_HW_DATA_HANDLE hwInstData) +{ + + free(hwInstData); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWMalloc + * + * Allocates dynamic memory + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +void *EAS_HWMalloc (EAS_HW_DATA_HANDLE hwInstData, EAS_I32 size) +{ + return malloc((size_t) size); +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWFree + * + * Frees dynamic memory + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +void EAS_HWFree (EAS_HW_DATA_HANDLE hwInstData, void *p) +{ + free(p); +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWMemCpy + * + * Copy memory wrapper + * + *---------------------------------------------------------------------------- +*/ +void *EAS_HWMemCpy (void *dest, const void *src, EAS_I32 amount) +{ + return memcpy(dest, src, (size_t) amount); +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWMemSet + * + * Set memory wrapper + * + *---------------------------------------------------------------------------- +*/ +void *EAS_HWMemSet (void *dest, int val, EAS_I32 amount) +{ + return memset(dest, val, (size_t) amount); +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWMemCmp + * + * Compare memory wrapper + * + *---------------------------------------------------------------------------- +*/ +EAS_I32 EAS_HWMemCmp (const void *s1, const void *s2, EAS_I32 amount) +{ + return (EAS_I32) memcmp(s1, s2, (size_t) amount); +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWOpenFile + * + * Open a file for read or write + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_HWOpenFile (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_LOCATOR locator, EAS_FILE_HANDLE *pFile, EAS_FILE_MODE mode) +{ + EAS_HW_FILE *file; + FILE *ioFile; + int i, temp; + + /* set return value to NULL */ + *pFile = NULL; + + /* only support read mode at this time */ + if (mode != EAS_FILE_READ) + return EAS_ERROR_INVALID_FILE_MODE; + + /* find an empty entry in the file table */ + file = hwInstData->files; + for (i = 0; i < EAS_MAX_FILE_HANDLES; i++) + { + /* is this slot being used? */ + if (file->buffer == NULL) + { + /* open the file */ + if ((ioFile = fopen(locator,"rb")) == NULL) + return EAS_ERROR_FILE_OPEN_FAILED; + + /* determine the file size */ + if (fseek(ioFile, 0L, SEEK_END) != 0) + return EAS_ERROR_FILE_LENGTH; + if ((file->fileSize = ftell(ioFile)) == -1L) + return EAS_ERROR_FILE_LENGTH; + if (fseek(ioFile, 0L, SEEK_SET) != 0) + return EAS_ERROR_FILE_LENGTH; + + /* allocate a buffer */ + file->buffer = EAS_HWMalloc(hwInstData, file->fileSize); + if (file->buffer == NULL) + { + fclose(ioFile); + return EAS_ERROR_MALLOC_FAILED; + } + + /* read the file into memory */ + temp = (int) fread(file->buffer, (size_t) file->fileSize, 1, ioFile); + + /* close the file - don't need it any more */ + fclose(ioFile); + + /* check for error reading file */ + if (temp != 1) + return EAS_ERROR_FILE_READ_FAILED; + + /* initialize some values */ + file->filePos = 0; + file->dup = EAS_FALSE; + + *pFile = file; + return EAS_SUCCESS; + } + file++; + } + + /* too many open files */ + return EAS_ERROR_MAX_FILES_OPEN; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWReadFile + * + * Read data from a file + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWReadFile (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *pBuffer, EAS_I32 n, EAS_I32 *pBytesRead) +{ + EAS_I32 count; + + /* make sure we have a valid handle */ + if (file->buffer == NULL) + return EAS_ERROR_INVALID_HANDLE; + + /* calculate the bytes to read */ + count = file->fileSize - file->filePos; + if (n < count) + count = n; + + /* copy the data to the requested location, and advance the pointer */ + if (count) + EAS_HWMemCpy(pBuffer, &file->buffer[file->filePos], count); + file->filePos += count; + *pBytesRead = count; + + /* were n bytes read? */ + if (count!= n) + return EAS_EOF; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWGetByte + * + * Read a byte from a file + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWGetByte (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *p) +{ + + /* make sure we have a valid handle */ + if (file->buffer == NULL) + return EAS_ERROR_INVALID_HANDLE; + + /* check for end of file */ + if (file->filePos >= file->fileSize) + { + *((EAS_U8*) p) = 0; + return EAS_EOF; + } + + /* get a character from the buffer */ + *((EAS_U8*) p) = file->buffer[file->filePos++]; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWGetWord + * + * Returns the current location in the file + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWGetWord (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *p, EAS_BOOL msbFirst) +{ + EAS_RESULT result; + EAS_U8 c1, c2; + + /* read 2 bytes from the file */ + if ((result = EAS_HWGetByte(hwInstData, file, &c1)) != EAS_SUCCESS) + return result; + if ((result = EAS_HWGetByte(hwInstData, file, &c2)) != EAS_SUCCESS) + return result; + + /* order them as requested */ + if (msbFirst) + *((EAS_U16*) p) = ((EAS_U16) c1 << 8) | c2; + else + *((EAS_U16*) p) = ((EAS_U16) c2 << 8) | c1; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWGetDWord + * + * Returns the current location in the file + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWGetDWord (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *p, EAS_BOOL msbFirst) +{ + EAS_RESULT result; + EAS_U8 c1, c2,c3,c4; + + /* read 4 bytes from the file */ + if ((result = EAS_HWGetByte(hwInstData, file, &c1)) != EAS_SUCCESS) + return result; + if ((result = EAS_HWGetByte(hwInstData, file, &c2)) != EAS_SUCCESS) + return result; + if ((result = EAS_HWGetByte(hwInstData, file, &c3)) != EAS_SUCCESS) + return result; + if ((result = EAS_HWGetByte(hwInstData, file, &c4)) != EAS_SUCCESS) + return result; + + /* order them as requested */ + if (msbFirst) + *((EAS_U32*) p) = ((EAS_U32) c1 << 24) | ((EAS_U32) c2 << 16) | ((EAS_U32) c3 << 8) | c4; + else + *((EAS_U32*) p)= ((EAS_U32) c4 << 24) | ((EAS_U32) c3 << 16) | ((EAS_U32) c2 << 8) | c1; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWFilePos + * + * Returns the current location in the file + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWFilePos (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 *pPosition) +{ + + /* make sure we have a valid handle */ + if (file->buffer == NULL) + return EAS_ERROR_INVALID_HANDLE; + + *pPosition = file->filePos; + return EAS_SUCCESS; +} /* end EAS_HWFilePos */ + +/*---------------------------------------------------------------------------- + * + * EAS_HWFileSeek + * + * Seek to a specific location in the file + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWFileSeek (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 position) +{ + + /* make sure we have a valid handle */ + if (file->buffer == NULL) + return EAS_ERROR_INVALID_HANDLE; + + /* validate new position */ + if ((position < 0) || (position > file->fileSize)) + return EAS_ERROR_FILE_SEEK; + + /* save new position */ + file->filePos = position; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWFileSeekOfs + * + * Seek forward or back relative to the current position + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWFileSeekOfs (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 position) +{ + + /* make sure we have a valid handle */ + if (file->buffer == NULL) + return EAS_ERROR_INVALID_HANDLE; + + /* determine the file position */ + position += file->filePos; + if ((position < 0) || (position > file->fileSize)) + return EAS_ERROR_FILE_SEEK; + + /* save new position */ + file->filePos = position; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWFileLength + * + * Return the file length + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWFileLength (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 *pLength) +{ + + /* make sure we have a valid handle */ + if (file->buffer == NULL) + return EAS_ERROR_INVALID_HANDLE; + + *pLength = file->fileSize; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWDupHandle + * + * Duplicate a file handle + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_HWDupHandle (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_FILE_HANDLE *pDupFile) +{ + EAS_HW_FILE *dupFile; + int i; + + /* make sure we have a valid handle */ + if (file->buffer == NULL) + return EAS_ERROR_INVALID_HANDLE; + + /* find an empty entry in the file table */ + dupFile = hwInstData->files; + for (i = 0; i < EAS_MAX_FILE_HANDLES; i++) + { + /* is this slot being used? */ + if (dupFile->buffer == NULL) + { + + /* copy info from the handle to be duplicated */ + dupFile->filePos = file->filePos; + dupFile->fileSize = file->fileSize; + dupFile->buffer = file->buffer; + + /* set the duplicate handle flag */ + dupFile->dup = file->dup = EAS_TRUE; + + *pDupFile = dupFile; + return EAS_SUCCESS; + } + dupFile++; + } + + /* too many open files */ + return EAS_ERROR_MAX_FILES_OPEN; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWClose + * + * Wrapper for fclose function + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_HWCloseFile (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file1) +{ + EAS_HW_FILE *file2,*dupFile; + int i; + + + /* make sure we have a valid handle */ + if (file1->buffer == NULL) + return EAS_ERROR_INVALID_HANDLE; + + /* check for duplicate handle */ + if (file1->dup) + { + dupFile = NULL; + file2 = hwInstData->files; + for (i = 0; i < EAS_MAX_FILE_HANDLES; i++) + { + /* check for duplicate */ + if ((file1 != file2) && (file2->buffer == file1->buffer)) + { + /* is there more than one duplicate? */ + if (dupFile != NULL) + { + /* clear this entry and return */ + file1->buffer = NULL; + return EAS_SUCCESS; + } + + /* this is the first duplicate found */ + else + dupFile = file2; + } + file2++; + } + + /* there is only one duplicate, clear the dup flag */ + if (dupFile) + dupFile->dup = EAS_FALSE; + else + /* if we get here, there's a serious problem */ + return EAS_ERROR_HANDLE_INTEGRITY; + + /* clear this entry and return */ + file1->buffer = NULL; + return EAS_SUCCESS; + } + + /* no duplicates -free the buffer */ + EAS_HWFree(hwInstData, file1->buffer); + + /* clear this entry and return */ + file1->buffer = NULL; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWVibrate + * + * Turn on/off vibrate function + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWVibrate (EAS_HW_DATA_HANDLE hwInstData, EAS_BOOL state) +{ + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x1a54b6e8, 0x00000001 , state); + return EAS_SUCCESS; +} /* end EAS_HWVibrate */ + +/*---------------------------------------------------------------------------- + * + * EAS_HWLED + * + * Turn on/off LED + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWLED (EAS_HW_DATA_HANDLE hwInstData, EAS_BOOL state) +{ + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x1a54b6e8, 0x00000002 , state); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWBackLight + * + * Turn on/off backlight + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWBackLight (EAS_HW_DATA_HANDLE hwInstData, EAS_BOOL state) +{ + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x1a54b6e8, 0x00000003 , state); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWYield + * + * This function is called periodically by the EAS library to give the + * host an opportunity to allow other tasks to run. There are two ways to + * use this call: + * + * If you have a multi-tasking OS, you can call the yield function in the + * OS to allow other tasks to run. In this case, return EAS_FALSE to tell + * the EAS library to continue processing when control returns from this + * function. + * + * If tasks run in a single thread by sequential function calls (sometimes + * call a "commutator loop"), return EAS_TRUE to cause the EAS Library to + * return to the caller. Be sure to check the number of bytes rendered + * before passing the audio buffer to the codec - it may not be filled. + * The next call to EAS_Render will continue processing until the buffer + * has been filled. + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_BOOL EAS_HWYield (EAS_HW_DATA_HANDLE hwInstData) +{ + /* put your code here */ + return EAS_FALSE; +} + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_main.c b/common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_main.c new file mode 100755 index 0000000..6ebb13e --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_main.c @@ -0,0 +1,461 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_main.c + * + * Contents and purpose: + * The entry point and high-level functions for the EAS Synthesizer test + * harness. + * + * Copyright Sonic Network Inc. 2004 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 775 $ + * $Date: 2007-07-20 10:11:11 -0700 (Fri, 20 Jul 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifdef _lint +#include "lint_stdlib.h" +#else +#include +#include +#include +#include +#endif + +#include "eas.h" +#include "eas_wave.h" +#include "eas_report.h" + +/* determines how many EAS buffers to fill a host buffer */ +#define NUM_BUFFERS 8 + +/* default file to play if no filename is specified on the command line */ +static const char defaultTestFile[] = "test.mid"; + +EAS_I32 polyphony; + +/* prototypes for helper functions */ +static void StrCopy(char *dest, const char *src, EAS_I32 size); +static EAS_BOOL ChangeFileExt(char *str, const char *ext, EAS_I32 size); +static EAS_RESULT PlayFile (EAS_DATA_HANDLE easData, const char* filename, const char* outputFile, const S_EAS_LIB_CONFIG *pLibConfig, void *buffer, EAS_I32 bufferSize); +static EAS_BOOL EASLibraryCheck (const S_EAS_LIB_CONFIG *pLibConfig); + +/* main is defined after playfile to avoid the need for two passes through lint */ + +/*---------------------------------------------------------------------------- + * PlayFile() + *---------------------------------------------------------------------------- + * Purpose: + * This function plays the file requested by filename + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ + +static EAS_RESULT PlayFile (EAS_DATA_HANDLE easData, const char* filename, const char* outputFile, const S_EAS_LIB_CONFIG *pLibConfig, void *buffer, EAS_I32 bufferSize) +{ + EAS_HANDLE handle; + EAS_RESULT result, reportResult; + EAS_I32 count; + EAS_STATE state; + EAS_I32 playTime; + char waveFilename[256]; + WAVE_FILE *wFile; + EAS_INT i; + EAS_PCM *p; + + /* determine the name of the output file */ + wFile = NULL; + if (outputFile == NULL) + { + StrCopy(waveFilename, filename, sizeof(waveFilename)); + if (!ChangeFileExt(waveFilename, "wav", sizeof(waveFilename))) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error in output filename %s\n", waveFilename); */ } + return EAS_FAILURE; + } + outputFile = waveFilename; + } + + /* call EAS library to open file */ + if ((reportResult = EAS_OpenFile(easData, filename, &handle)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_OpenFile returned %ld\n", reportResult); */ } + return reportResult; + } + + /* prepare to play the file */ + if ((result = EAS_Prepare(easData, handle)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_Prepare returned %ld\n", result); */ } + reportResult = result; + } + + /* get play length */ + if ((result = EAS_ParseMetaData(easData, handle, &playTime)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_ParseMetaData returned %ld\n", result); */ } + return result; + } + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0xe624f4d9, 0x00000005 , playTime / 1000, playTime % 1000); + + if (reportResult == EAS_SUCCESS) + { + /* create the output file */ + wFile = WaveFileCreate(outputFile, pLibConfig->numChannels, pLibConfig->sampleRate, sizeof(EAS_PCM) * 8); + if (!wFile) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Unable to create output file %s\n", waveFilename); */ } + reportResult = EAS_FAILURE; + } + } + + /* rendering loop */ + while (reportResult == EAS_SUCCESS) + { + + /* we may render several buffers here to fill one host buffer */ + for (i = 0, p = buffer; i < NUM_BUFFERS; i++, p+= pLibConfig->mixBufferSize * pLibConfig->numChannels) + { + + /* get the current time */ + if ((result = EAS_GetLocation(easData, handle, &playTime)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_GetLocation returned %d\n",result); */ } + if (reportResult == EAS_SUCCESS) + reportResult = result; + break; + } + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Parser time: %d.%03d\n", playTime / 1000, playTime % 1000); */ } + + /* render a buffer of audio */ + if ((result = EAS_Render(easData, p, pLibConfig->mixBufferSize, &count)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_Render returned %d\n",result); */ } + if (reportResult == EAS_SUCCESS) + reportResult = result; + } + } + + if (result == EAS_SUCCESS) + { + /* write it to the wave file */ + if (WaveFileWrite(wFile, buffer, bufferSize) != bufferSize) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "WaveFileWrite failed\n"); */ } + reportResult = EAS_FAILURE; + } + } + + if (reportResult == EAS_SUCCESS) + { + /* check stream state */ + if ((result = EAS_State(easData, handle, &state)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_State returned %d\n", result); */ } + reportResult = result; + } + + /* is playback complete */ + if ((state == EAS_STATE_STOPPED) || (state == EAS_STATE_ERROR)) + break; + } + } + + /* close the output file */ + if (wFile) + { + if (!WaveFileClose(wFile)) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error closing wave file %s\n", waveFilename); */ } + if (reportResult == EAS_SUCCESS) + result = EAS_FAILURE; + } + } + + /* close the input file */ + if ((result = EAS_CloseFile(easData,handle)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_Close returned %ld\n", result); */ } + if (reportResult == EAS_SUCCESS) + result = EAS_FAILURE; + } + + return reportResult; +} /* end PlayFile */ + +/*---------------------------------------------------------------------------- + * main() + *---------------------------------------------------------------------------- + * Purpose: The entry point for the EAS sample application + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +int main( int argc, char **argv ) +{ + EAS_DATA_HANDLE easData; + const S_EAS_LIB_CONFIG *pLibConfig; + void *buffer; + EAS_RESULT result, playResult; + EAS_I32 bufferSize; + int i; + int temp; + FILE *debugFile; + char *outputFile = NULL; + + /* set the error reporting level */ + EAS_SetDebugLevel(_EAS_SEVERITY_INFO); + debugFile = NULL; + + /* process command-line arguments */ + for (i = 1; i < argc; i++) + { + /* check for switch */ + if (argv[i][0] == '-') + { + switch (argv[i][1]) + { + case 'd': + temp = argv[i][2]; + if ((temp >= '0') || (temp <= '9')) + EAS_SetDebugLevel(temp); + else + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Invalid debug level %d\n", temp); */ } + break; + case 'f': + if ((debugFile = fopen(&argv[i][2],"w")) == NULL) + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Unable to create debug file %s\n", &argv[i][2]); */ } + else + EAS_SetDebugFile(debugFile, EAS_TRUE); + break; + case 'o': + outputFile = &argv[i][2]; + break; + case 'p': + polyphony = atoi(&argv[i][2]); + if (polyphony < 1) + polyphony = 1; + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "Polyphony set to %d\n", polyphony); */ } + break; + default: + break; + } + continue; + } + } + + /* assume success */ + playResult = EAS_SUCCESS; + + /* get the library configuration */ + pLibConfig = EAS_Config(); + if (!EASLibraryCheck(pLibConfig)) + return -1; + if (polyphony > pLibConfig->maxVoices) + polyphony = pLibConfig->maxVoices; + + /* calculate buffer size */ + bufferSize = pLibConfig->mixBufferSize * pLibConfig->numChannels * (EAS_I32)sizeof(EAS_PCM) * NUM_BUFFERS; + + /* allocate output buffer memory */ + buffer = malloc((EAS_U32)bufferSize); + if (!buffer) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Error allocating memory for audio buffer\n"); */ } + return EAS_FAILURE; + } + + /* initialize the EAS library */ + polyphony = pLibConfig->maxVoices; + if ((result = EAS_Init(&easData)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "EAS_Init returned %ld - aborting!\n", result); */ } + free(buffer); + return result; + } + + /* + * Some debugging environments don't allow for passed parameters. + * In this case, just play the default MIDI file "test.mid" + */ + if (argc < 2) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "Playing '%s'\n", defaultTestFile); */ } + if ((playResult = PlayFile(easData, defaultTestFile, NULL, pLibConfig, buffer, bufferSize)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %d playing file %s\n", playResult, defaultTestFile); */ } + } + } + /* iterate through the list of files to be played */ + else + { + for (i = 1; i < argc; i++) + { + /* check for switch */ + if (argv[i][0] != '-') + { + + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "Playing '%s'\n", argv[i]); */ } + if ((playResult = PlayFile(easData, argv[i], outputFile, pLibConfig, buffer, bufferSize)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %d playing file %s\n", playResult, argv[i]); */ } + break; + } + } + } + } + + /* shutdown the EAS library */ + if ((result = EAS_Shutdown(easData)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "EAS_Shutdown returned %ld\n", result); */ } + } + + /* free the output buffer */ + free(buffer); + + /* close the debug file */ + if (debugFile) + fclose(debugFile); + + /* play errors take precedence over shutdown errors */ + if (playResult != EAS_SUCCESS) + return playResult; + return result; +} /* end main */ + +/*---------------------------------------------------------------------------- + * StrCopy() + *---------------------------------------------------------------------------- + * Purpose: + * Safe string copy + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static void StrCopy(char *dest, const char *src, EAS_I32 size) +{ + int len; + + strncpy(dest, src, (size_t) size-1); + len = (int) strlen(src); + if (len < size) + dest[len] = 0; +} /* end StrCopy */ + +/*---------------------------------------------------------------------------- + * ChangeFileExt() + *---------------------------------------------------------------------------- + * Purpose: + * Changes the file extension of a filename + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL ChangeFileExt(char *str, const char *ext, EAS_I32 size) +{ + char *p; + + /* find the extension, if any */ + p = strrchr(str,'.'); + if (!p) + { + if ((EAS_I32)(strlen(str) + 5) > size) + return EAS_FALSE; + strcat(str,"."); + strcat(str,ext); + return EAS_TRUE; + } + + /* make sure there's room for the extension */ + p++; + *p = 0; + if ((EAS_I32)(strlen(str) + 4) > size) + return EAS_FALSE; + strcat(str,ext); + return EAS_TRUE; +} /* end ChangeFileExt */ + +/*---------------------------------------------------------------------------- + * EASLibraryCheck() + *---------------------------------------------------------------------------- + * Purpose: + * Displays the library version and checks it against the header + * file used to build this code. + * + * Inputs: + * pLibConfig - library configuration retrieved from the library + * + * Outputs: + * returns EAS_TRUE if matched + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL EASLibraryCheck (const S_EAS_LIB_CONFIG *pLibConfig) +{ + + /* display the library version */ + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "EAS Library Version %d.%d.%d.%d\n", + pLibConfig->libVersion >> 24, + (pLibConfig->libVersion >> 16) & 0x0f, + (pLibConfig->libVersion >> 8) & 0x0f, + pLibConfig->libVersion & 0x0f); */ } + + /* display some info about the library build */ + if (pLibConfig->checkedVersion) + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tChecked library\n"); */ } + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tMaximum polyphony: %d\n", pLibConfig->maxVoices); */ } + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tNumber of channels: %d\n", pLibConfig->numChannels); */ } + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tSample rate: %d\n", pLibConfig->sampleRate); */ } + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tMix buffer size: %d\n", pLibConfig->mixBufferSize); */ } + if (pLibConfig->filterEnabled) + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tFilter enabled\n"); */ } +#ifndef _WIN32_WCE + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tLibrary Build Timestamp: %s", ctime((time_t*)&pLibConfig->buildTimeStamp)); */ } +#endif + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tLibrary Build ID: %s\n", pLibConfig->buildGUID); */ } + + /* check it against the header file used to build this code */ + /*lint -e{778} constant expression used for display purposes may evaluate to zero */ + if (LIB_VERSION != pLibConfig->libVersion) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Library version does not match header files. EAS Header Version %d.%d.%d.%d\n", + LIB_VERSION >> 24, + (LIB_VERSION >> 16) & 0x0f, + (LIB_VERSION >> 8) & 0x0f, + LIB_VERSION & 0x0f); */ } + return EAS_FALSE; + } + return EAS_TRUE; +} /* end EASLibraryCheck */ + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_report.c b/common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_report.c new file mode 100755 index 0000000..04a828c --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_report.c @@ -0,0 +1,264 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_report.c + * + * Contents and purpose: + * This file contains the debug message handling routines for the EAS library. + * These routines should be modified as needed for your system. + * + * Copyright 2005 Sonic Network Inc. + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 659 $ + * $Date: 2007-04-24 13:36:35 -0700 (Tue, 24 Apr 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifdef _lint +#include "lint_stdlib.h" +#else +#include +#include +#include +#endif + +#include "eas_report.h" + +static int severityLevel = 9999; + +/* debug file */ +static FILE *debugFile = NULL; +int flush = 0; + +#ifndef _NO_DEBUG_PREPROCESSOR + +/* structure should have an #include for each error message header file */ +S_DEBUG_MESSAGES debugMessages[] = +{ +#ifndef UNIFIED_DEBUG_MESSAGES +#include "eas_config_msgs.h" + + +#include "eas_host_msgs.h" +#include "eas_hostmm_msgs.h" +#include "eas_math_msgs.h" +#include "eas_midi_msgs.h" +#include "eas_mixer_msgs.h" +#include "eas_pcm_msgs.h" +#include "eas_public_msgs.h" +#include "eas_smf_msgs.h" +#include "eas_wave_msgs.h" +#include "eas_voicemgt_msgs.h" + +#ifdef _FM_SYNTH +#include "eas_fmsynth_msgs.h" +#include "eas_fmengine_msgs.h" +#endif + +#ifdef _WT_SYNTH +#include "eas_wtsynth_msgs.h" +#include "eas_wtengine_msgs.h" +#endif + +#ifdef _ARM_TEST_MAIN +#include "arm_main_msgs.h" +#endif + +#ifdef _EAS_MAIN +#include "eas_main_msgs.h" +#endif + +#ifdef _EAS_MAIN_IPC +#include "eas_main_ipc_msgs.h" +#endif + +#ifdef _METRICS_ENABLED +#include "eas_perf_msgs.h" +#endif + +#ifdef _COMPRESSOR_ENABLED +#include "eas_compressor_msgs.h" +#endif + +#ifdef _ENHANCER_ENABLED +#include "eas_enhancer_msgs.h" +#endif + +#ifdef _WOW_ENABLED +#include "eas_wow_msgs.h" +#endif + +#ifdef _SMAF_PARSER +#include "eas_smaf_msgs.h" +#endif + +#ifdef _OTA_PARSER +#include "eas_ota_msgs.h" +#endif + +#ifdef _IMELODY_PARSER +#include "eas_imelody_msgs.h" +#endif + +#ifdef _WAVE_PARSER +#include "eas_wavefile_msgs.h" +#endif + +#if defined(_CMX_PARSER) || defined(_MFI_PARSER) +#include "eas_cmf_msgs.h" +#endif + +#if defined(_CMX_PARSER) || defined(_MFI_PARSER) || defined(_WAVE_PARSER) +#include "eas_imaadpcm_msgs.h" +#endif + +#else +#include "eas_debugmsgs.h" +#endif + +/* denotes end of error messages */ +{ 0,0,0 } +}; + +/*---------------------------------------------------------------------------- + * EAS_ReportEx() + * + * This is the error message handler. The default handler outputs error + * messages to stdout. Modify this as needed for your system. + *---------------------------------------------------------------------------- +*/ +void EAS_ReportEx (int severity, unsigned long hashCode, int serialNum, ...) +{ + va_list vargs; + int i; + + /* check severity level */ + if (severity > severityLevel) + return; + + /* find the error message and output to stdout */ + /*lint -e{661} we check for NULL pointer - no fence post error here */ + for (i = 0; debugMessages[i].m_pDebugMsg; i++) + { + if ((debugMessages[i].m_nHashCode == hashCode) && + (debugMessages[i].m_nSerialNum == serialNum)) + { + /*lint -e{826} */ + va_start(vargs, serialNum); + if (debugFile) + { + vfprintf(debugFile, debugMessages[i].m_pDebugMsg, vargs); + if (flush) + fflush(debugFile); + } + else + { + vprintf(debugMessages[i].m_pDebugMsg, vargs); + } + va_end(vargs); + return; + } + } + printf("Unrecognized error: Severity=%d; HashCode=%lu; SerialNum=%d\n", severity, hashCode, serialNum); +} /* end EAS_ReportEx */ + +#else +/*---------------------------------------------------------------------------- + * EAS_Report() + * + * This is the error message handler. The default handler outputs error + * messages to stdout. Modify this as needed for your system. + *---------------------------------------------------------------------------- +*/ +void EAS_Report (int severity, const char *fmt, ...) +{ + va_list vargs; + + /* check severity level */ + if (severity > severityLevel) + return; + + /*lint -e{826} */ + va_start(vargs, fmt); + if (debugFile) + { + vfprintf(debugFile, fmt, vargs); + if (flush) + fflush(debugFile); + } + else + { + vprintf(fmt, vargs); + } + va_end(vargs); +} /* end EAS_Report */ + +/*---------------------------------------------------------------------------- + * EAS_ReportX() + * + * This is the error message handler. The default handler outputs error + * messages to stdout. Modify this as needed for your system. + *---------------------------------------------------------------------------- +*/ +void EAS_ReportX (int severity, const char *fmt, ...) +{ + va_list vargs; + + /* check severity level */ + if (severity > severityLevel) + return; + + /*lint -e{826} */ + va_start(vargs, fmt); + if (debugFile) + { + vfprintf(debugFile, fmt, vargs); + if (flush) + fflush(debugFile); + } + else + { + vprintf(fmt, vargs); + } + va_end(vargs); +} /* end EAS_ReportX */ +#endif + +/*---------------------------------------------------------------------------- + * EAS_SetDebugLevel() + * + * Sets the level for debug message output + *---------------------------------------------------------------------------- +*/ + +void EAS_SetDebugLevel (int severity) +{ + severityLevel = severity; +} /* end EAS_SetDebugLevel */ + +/*---------------------------------------------------------------------------- + * EAS_SetDebugFile() + * + * Redirect debugger output to the specified file. + *---------------------------------------------------------------------------- +*/ +void EAS_SetDebugFile (void *file, int flushAfterWrite) +{ + debugFile = (FILE*) file; + flush = flushAfterWrite; +} /* end EAS_SetDebugFile */ + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_report.h b/common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_report.h new file mode 100755 index 0000000..b603b12 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_report.h @@ -0,0 +1,77 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_report.h + * + * Contents and purpose: + * This file contains the debug message handling routines for the EAS library. + * These routines should be modified as needed for your system. + * + * DO NOT MODIFY THIS FILE! + * + * Copyright 2005 Sonic Network Inc. + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +/* sentinel */ +#ifndef _EAS_REPORT_H +#define _EAS_REPORT_H + +#define _EAS_SEVERITY_NOFILTER 0 +#define _EAS_SEVERITY_FATAL 1 +#define _EAS_SEVERITY_ERROR 2 +#define _EAS_SEVERITY_WARNING 3 +#define _EAS_SEVERITY_INFO 4 +#define _EAS_SEVERITY_DETAIL 5 + +/* for C++ linkage */ +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _NO_DEBUG_PREPROCESSOR + +/* structure for included debug message header files */ +typedef struct +{ + unsigned long m_nHashCode; + int m_nSerialNum; + char *m_pDebugMsg; +} S_DEBUG_MESSAGES; + +/* debug message handling prototypes */ +extern void EAS_ReportEx (int severity, unsigned long hashCode, int serialNum, ...); + +#else + +/* these prototypes are used if the debug preprocessor is not used */ +extern void EAS_Report (int severity, const char* fmt, ...); +extern void EAS_ReportX (int severity, const char* fmt, ...); + +#endif + +extern void EAS_SetDebugLevel (int severity); +extern void EAS_SetDebugFile (void *file, int flushAfterWrite); + +#ifdef __cplusplus +} /* end extern "C" */ +#endif + +#endif diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_reverb.h b/common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_reverb.h new file mode 100755 index 0000000..559abed --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_reverb.h @@ -0,0 +1,54 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_reverb.h + * + * Contents and purpose: + * Contains parameter enumerations for the Reverb effect + * + * + * Copyright Sonic Network Inc. 2006 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 300 $ + * $Date: 2006-09-11 17:37:20 -0700 (Mon, 11 Sep 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_REVERB_H +#define _EAS_REVERB_H + + +/* enumerated parameter settings for Reverb effect */ +typedef enum +{ + EAS_PARAM_REVERB_BYPASS, + EAS_PARAM_REVERB_PRESET, + EAS_PARAM_REVERB_WET, + EAS_PARAM_REVERB_DRY +} E_REVERB_PARAMS; + + +typedef enum +{ + EAS_PARAM_REVERB_LARGE_HALL, + EAS_PARAM_REVERB_HALL, + EAS_PARAM_REVERB_CHAMBER, + EAS_PARAM_REVERB_ROOM, +} E_REVERB_PRESETS; + + +#endif /* _REVERB_H */ diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_types.h b/common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_types.h new file mode 100755 index 0000000..45fa4b2 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_types.h @@ -0,0 +1,268 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_types.h + * + * Contents and purpose: + * The public interface header for the EAS synthesizer. + * + * This header only contains declarations that are specific + * to this implementation. + * + * DO NOT MODIFY THIS FILE! + * + * Copyright Sonic Network Inc. 2004 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 726 $ + * $Date: 2007-06-14 23:10:46 -0700 (Thu, 14 Jun 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_TYPES_H +#define _EAS_TYPES_H + +/* EAS_RESULT return codes */ +typedef long EAS_RESULT; +#define EAS_SUCCESS 0 +#define EAS_FAILURE -1 +#define EAS_ERROR_INVALID_MODULE -2 +#define EAS_ERROR_MALLOC_FAILED -3 +#define EAS_ERROR_FILE_POS -4 +#define EAS_ERROR_INVALID_FILE_MODE -5 +#define EAS_ERROR_FILE_SEEK -6 +#define EAS_ERROR_FILE_LENGTH -7 +#define EAS_ERROR_NOT_IMPLEMENTED -8 +#define EAS_ERROR_CLOSE_FAILED -9 +#define EAS_ERROR_FILE_OPEN_FAILED -10 +#define EAS_ERROR_INVALID_HANDLE -11 +#define EAS_ERROR_NO_MIX_BUFFER -12 +#define EAS_ERROR_PARAMETER_RANGE -13 +#define EAS_ERROR_MAX_FILES_OPEN -14 +#define EAS_ERROR_UNRECOGNIZED_FORMAT -15 +#define EAS_BUFFER_SIZE_MISMATCH -16 +#define EAS_ERROR_FILE_FORMAT -17 +#define EAS_ERROR_SMF_NOT_INITIALIZED -18 +#define EAS_ERROR_LOCATE_BEYOND_END -19 +#define EAS_ERROR_INVALID_PCM_TYPE -20 +#define EAS_ERROR_MAX_PCM_STREAMS -21 +#define EAS_ERROR_NO_VOICE_ALLOCATED -22 +#define EAS_ERROR_INVALID_CHANNEL -23 +#define EAS_ERROR_ALREADY_STOPPED -24 +#define EAS_ERROR_FILE_READ_FAILED -25 +#define EAS_ERROR_HANDLE_INTEGRITY -26 +#define EAS_ERROR_MAX_STREAMS_OPEN -27 +#define EAS_ERROR_INVALID_PARAMETER -28 +#define EAS_ERROR_FEATURE_NOT_AVAILABLE -29 +#define EAS_ERROR_SOUND_LIBRARY -30 +#define EAS_ERROR_NOT_VALID_IN_THIS_STATE -31 +#define EAS_ERROR_NO_VIRTUAL_SYNTHESIZER -32 +#define EAS_ERROR_FILE_ALREADY_OPEN -33 +#define EAS_ERROR_FILE_ALREADY_CLOSED -34 +#define EAS_ERROR_INCOMPATIBLE_VERSION -35 +#define EAS_ERROR_QUEUE_IS_FULL -36 +#define EAS_ERROR_QUEUE_IS_EMPTY -37 +#define EAS_ERROR_FEATURE_ALREADY_ACTIVE -38 + +/* special return codes */ +#define EAS_EOF 3 +#define EAS_STREAM_BUFFERING 4 +#define EAS_BUFFER_FULL 5 + +/* EAS_STATE return codes */ +typedef long EAS_STATE; +typedef enum +{ + EAS_STATE_READY = 0, + EAS_STATE_PLAY, + EAS_STATE_STOPPING, + EAS_STATE_PAUSING, + EAS_STATE_STOPPED, + EAS_STATE_PAUSED, + EAS_STATE_OPEN, + EAS_STATE_ERROR, + EAS_STATE_EMPTY +} E_EAS_STATE; + +/* constants */ +#ifndef EAS_CONST +#define EAS_CONST const +#endif + +/* definition for public interface functions */ +#ifndef EAS_PUBLIC +#define EAS_PUBLIC +#endif + +/* boolean values */ +typedef unsigned EAS_BOOL; +typedef unsigned char EAS_BOOL8; + +#define EAS_FALSE 0 +#define EAS_TRUE 1 + +/* scalar variable definitions */ +typedef unsigned char EAS_U8; +typedef signed char EAS_I8; +typedef char EAS_CHAR; + +typedef unsigned short EAS_U16; +typedef short EAS_I16; + +typedef unsigned long EAS_U32; +typedef long EAS_I32; + +typedef unsigned EAS_UINT; +typedef int EAS_INT; +typedef long EAS_LONG; + +/* audio output type */ +typedef short EAS_PCM; + +/* file open modes */ +typedef EAS_I32 EAS_FILE_MODE; +#define EAS_FILE_READ 1 +#define EAS_FILE_WRITE 2 + +/* file locator e.g. filename or memory pointer */ +typedef const void *EAS_FILE_LOCATOR; + +/* handle to stream */ +typedef struct s_eas_stream_tag *EAS_HANDLE; + +/* handle to file */ +typedef struct eas_hw_file_tag *EAS_FILE_HANDLE; + +/* handle for synthesizer data */ +typedef struct s_eas_data_tag *EAS_DATA_HANDLE; + +/* handle to persistent data for host wrapper interface */ +typedef struct eas_hw_inst_data_tag *EAS_HW_DATA_HANDLE; + +/* handle to sound library */ +typedef struct s_eas_sndlib_tag *EAS_SNDLIB_HANDLE; +typedef struct s_eas_dls_tag *EAS_DLSLIB_HANDLE; + +/* pointer to frame buffer - used in split architecture only */ +typedef struct s_eas_frame_buffer_tag *EAS_FRAME_BUFFER_HANDLE; + +/* untyped pointer for instance data */ +typedef void *EAS_VOID_PTR; + +/* inline functions */ +#ifndef EAS_INLINE +#if defined (__XCC__) +#define EAS_INLINE __inline__ +#elif defined (__GNUC__) +#define EAS_INLINE inline static +#else +#define EAS_INLINE __inline +#endif +#endif + +/* define NULL value */ +#ifndef NULL +#define NULL 0 +#endif + +/* metadata types for metadata return codes */ +typedef enum +{ + EAS_METADATA_UNKNOWN = 0, + EAS_METADATA_TITLE, + EAS_METADATA_AUTHOR, + EAS_METADATA_COPYRIGHT, + EAS_METADATA_LYRIC, + EAS_METADATA_TEXT +} E_EAS_METADATA_TYPE; + +/* metadata callback function */ +typedef void (*EAS_METADATA_CBFUNC) (E_EAS_METADATA_TYPE metaDataType, char *metaDataBuf, EAS_VOID_PTR pUserData); + +/* file types for metadata return codes */ +typedef enum +{ + EAS_FILE_UNKNOWN = 0, + EAS_FILE_SMF0, + EAS_FILE_SMF1, + EAS_FILE_SMAF_UNKNOWN, + EAS_FILE_SMAF_MA2, + EAS_FILE_SMAF_MA3, + EAS_FILE_SMAF_MA5, + EAS_FILE_CMX, + EAS_FILE_MFI, + EAS_FILE_OTA, + EAS_FILE_IMELODY, + EAS_FILE_RTTTL, + EAS_FILE_XMF0, + EAS_FILE_XMF1, + EAS_FILE_WAVE_PCM, + EAS_FILE_WAVE_IMA_ADPCM, + EAS_FILE_MMAPI_TONE_CONTROL +} E_EAS_FILE_TYPE; + +/* enumeration for synthesizers */ +typedef enum +{ + EAS_MCU_SYNTH = 0, + EAS_DSP_SYNTH +} E_SYNTHESIZER; + +/* external audio callback program change */ +typedef struct s_ext_audio_prg_chg_tag +{ + EAS_U16 bank; + EAS_U8 program; + EAS_U8 channel; +} S_EXT_AUDIO_PRG_CHG; + +/* external audio callback event */ +typedef struct s_ext_audio_event_tag +{ + EAS_U8 channel; + EAS_U8 note; + EAS_U8 velocity; + EAS_BOOL8 noteOn; +} S_EXT_AUDIO_EVENT; + +typedef struct s_midi_controllers_tag +{ + EAS_U8 modWheel; /* CC1 */ + EAS_U8 volume; /* CC7 */ + EAS_U8 pan; /* CC10 */ + EAS_U8 expression; /* CC11 */ + EAS_U8 channelPressure; /* MIDI channel pressure */ + +#ifdef _REVERB + EAS_U8 reverbSend; /* CC91 */ +#endif + +#ifdef _CHORUS + EAS_U8 chorusSend; /* CC93 */ +#endif +} S_MIDI_CONTROLLERS; + +/* iMode play modes enumeration for EAS_SetPlayMode */ +typedef enum +{ + IMODE_PLAY_ALL = 0, + IMODE_PLAY_PARTIAL +} E_I_MODE_PLAY_MODE; + +typedef EAS_BOOL (*EAS_EXT_PRG_CHG_FUNC) (EAS_VOID_PTR pInstData, S_EXT_AUDIO_PRG_CHG *pPrgChg); +typedef EAS_BOOL (*EAS_EXT_EVENT_FUNC) (EAS_VOID_PTR pInstData, S_EXT_AUDIO_EVENT *pEvent); + +#endif /* #ifndef _EAS_TYPES_H */ diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_wave.c b/common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_wave.c new file mode 100755 index 0000000..4f6ffbd --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_wave.c @@ -0,0 +1,423 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_wave.c + * + * Contents and purpose: + * This module contains .WAV file functions for the EAS synthesizer + * test harness. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 658 $ + * $Date: 2007-04-24 13:35:49 -0700 (Tue, 24 Apr 2007) $ + *---------------------------------------------------------------------------- +*/ + +/* lint complaints about most C library headers, so we use our own during lint step */ +#ifdef _lint +#include "lint_stdlib.h" +#else +#include +#include +#endif + +#include "eas_wave.h" + +/* .WAV file format tags */ +const EAS_U32 riffTag = 0x46464952; +const EAS_U32 waveTag = 0x45564157; +const EAS_U32 fmtTag = 0x20746d66; +const EAS_U32 dataTag = 0x61746164; + +#ifdef _BIG_ENDIAN +/*---------------------------------------------------------------------------- + * FlipDWord() + *---------------------------------------------------------------------------- + * Purpose: Endian flip a DWORD for big-endian processors + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static void FlipDWord (EAS_U32 *pValue) +{ + EAS_U8 *p; + EAS_U32 temp; + + p = (EAS_U8*) pValue; + temp = (((((p[3] << 8) | p[2]) << 8) | p[1]) << 8) | p[0]; + *pValue = temp; +} + +/*---------------------------------------------------------------------------- + * FlipWord() + *---------------------------------------------------------------------------- + * Purpose: Endian flip a WORD for big-endian processors + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static void FlipWord (EAS_U16 *pValue) +{ + EAS_U8 *p; + EAS_U16 temp; + + p = (EAS_U8*) pValue; + temp = (p[1] << 8) | p[0]; + *pValue = temp; +} + +/*---------------------------------------------------------------------------- + * FlipWaveHeader() + *---------------------------------------------------------------------------- + * Purpose: Endian flip the wave header for big-endian processors + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static void FlipWaveHeader (WAVE_HEADER *p) +{ + + FlipDWord(&p->nRiffTag); + FlipDWord(&p->nRiffSize); + FlipDWord(&p->nWaveTag); + FlipDWord(&p->nFmtTag); + FlipDWord(&p->nFmtSize); + FlipDWord(&p->nDataTag); + FlipDWord(&p->nDataSize); + FlipWord(&p->fc.wFormatTag); + FlipWord(&p->fc.nChannels); + FlipDWord(&p->fc.nSamplesPerSec); + FlipDWord(&p->fc.nAvgBytesPerSec); + FlipWord(&p->fc.nBlockAlign); + FlipWord(&p->fc.wBitsPerSample); + +} +#endif + +/*---------------------------------------------------------------------------- + * WaveFileCreate() + *---------------------------------------------------------------------------- + * Purpose: Opens a wave file for writing and writes the header + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ + +WAVE_FILE *WaveFileCreate (const char *filename, EAS_I32 nChannels, EAS_I32 nSamplesPerSec, EAS_I32 wBitsPerSample) +{ + WAVE_FILE *wFile; + + /* allocate memory */ + wFile = malloc(sizeof(WAVE_FILE)); + if (!wFile) + return NULL; + wFile->write = EAS_TRUE; + + /* create the file */ + wFile->file = fopen(filename,"wb"); + if (!wFile->file) + { + free(wFile); + return NULL; + } + + /* initialize PCM format .WAV file header */ + wFile->wh.nRiffTag = riffTag; + wFile->wh.nRiffSize = sizeof(WAVE_HEADER) - 8; + wFile->wh.nWaveTag = waveTag; + wFile->wh.nFmtTag = fmtTag; + wFile->wh.nFmtSize = sizeof(FMT_CHUNK); + + /* initalize 'fmt' chunk */ + wFile->wh.fc.wFormatTag = 1; + wFile->wh.fc.nChannels = (EAS_U16) nChannels; + wFile->wh.fc.nSamplesPerSec = (EAS_U32) nSamplesPerSec; + wFile->wh.fc.wBitsPerSample = (EAS_U16) wBitsPerSample; + wFile->wh.fc.nBlockAlign = (EAS_U16) (nChannels * (EAS_U16) (wBitsPerSample / 8)); + wFile->wh.fc.nAvgBytesPerSec = wFile->wh.fc.nBlockAlign * (EAS_U32) nSamplesPerSec; + + /* initialize 'data' chunk */ + wFile->wh.nDataTag = dataTag; + wFile->wh.nDataSize = 0; + +#ifdef _BIG_ENDIAN + FlipWaveHeader(&wFile->wh); +#endif + + /* write the header */ + if (fwrite(&wFile->wh, sizeof(WAVE_HEADER), 1, wFile->file) != 1) + { + fclose(wFile->file); + free(wFile); + return NULL; + } + +#ifdef _BIG_ENDIAN + FlipWaveHeader(&wFile->wh); +#endif + + /* return the file handle */ + return wFile; +} /* end WaveFileCreate */ + +/*---------------------------------------------------------------------------- + * WaveFileWrite() + *---------------------------------------------------------------------------- + * Purpose: Writes data to the wave file + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_I32 WaveFileWrite (WAVE_FILE *wFile, void *buffer, EAS_I32 n) +{ + EAS_I32 count; + + /* make sure we have an open file */ + if (wFile == NULL) + { + return 0; + } + +#ifdef _BIG_ENDIAN + { + EAS_I32 i; + EAS_U16 *p; + p = buffer; + i = n >> 1; + while (i--) + FlipWord(p++); + } +#endif + + /* write the data */ + count = (EAS_I32) fwrite(buffer, 1, (size_t) n, wFile->file); + + /* add the number of bytes written */ + wFile->wh.nRiffSize += (EAS_U32) count; + wFile->wh.nDataSize += (EAS_U32) count; + + /* return the count of bytes written */ + return count; +} /* end WriteWaveHeader */ + +/*---------------------------------------------------------------------------- + * WaveFileClose() + *---------------------------------------------------------------------------- + * Purpose: Opens a wave file for writing and writes the header + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ + +EAS_BOOL WaveFileClose (WAVE_FILE *wFile) +{ + EAS_I32 count = 1; + + /* return to beginning of file and write the header */ + if (wFile->write) + { + if (fseek(wFile->file, 0L, SEEK_SET) == 0) + { + +#ifdef _BIG_ENDIAN + FlipWaveHeader(&wFile->wh); +#endif + count = (EAS_I32) fwrite(&wFile->wh, sizeof(WAVE_HEADER), 1, wFile->file); +#ifdef _BIG_ENDIAN + FlipWaveHeader(&wFile->wh); +#endif + } + } + + /* close the file */ + if (fclose(wFile->file) != 0) + count = 0; + + /* free the memory */ + free(wFile); + + /* return the file handle */ + return (count == 1 ? EAS_TRUE : EAS_FALSE); +} /* end WaveFileClose */ + +#ifdef _WAVE_FILE_READ +#ifdef _BIG_ENDIAN +#error "WaveFileOpen not currently supported on big-endian processors" +#endif +/*---------------------------------------------------------------------------- + * WaveFileOpen() + *---------------------------------------------------------------------------- + * Purpose: Opens a wave file for reading and reads the header + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ + +WAVE_FILE *WaveFileOpen (const char *filename) +{ + WAVE_FILE *wFile; + struct + { + EAS_U32 tag; + EAS_U32 size; + } chunk; + EAS_U32 tag; + EAS_I32 startChunkPos; + EAS_INT state; + EAS_BOOL done; + + /* allocate memory */ + wFile = malloc(sizeof(WAVE_FILE)); + if (!wFile) + return NULL; + + /* open the file */ + wFile->write = EAS_FALSE; + wFile->file = fopen(filename,"rb"); + if (!wFile->file) + { + free(wFile); + return NULL; + } + + /* make lint happy */ + chunk.tag = chunk.size = 0; + startChunkPos = 0; + + /* read the RIFF tag and file size */ + state = 0; + done = EAS_FALSE; + while (!done) + { + + switch(state) + { + /* read the RIFF tag */ + case 0: + if (fread(&chunk, sizeof(chunk), 1, wFile->file) != 1) + done = EAS_TRUE; + else + { + if (chunk.tag != riffTag) + done = EAS_TRUE; + else + state++; + } + break; + + /* read the WAVE tag */ + case 1: + if (fread(&tag, sizeof(tag), 1, wFile->file) != 1) + done = EAS_TRUE; + else + { + if (tag != waveTag) + done = EAS_TRUE; + else + state++; + } + break; + + /* looking for fmt chunk */ + case 2: + if (fread(&chunk, sizeof(chunk), 1, wFile->file) != 1) + done = EAS_TRUE; + else + { + startChunkPos = ftell(wFile->file); + + /* not fmt tag, skip it */ + if (chunk.tag != fmtTag) + fseek(wFile->file, startChunkPos + (EAS_I32) chunk.size, SEEK_SET); + else + state++; + } + break; + + /* read fmt chunk */ + case 3: + if (fread(&wFile->wh.fc, sizeof(FMT_CHUNK), 1, wFile->file) != 1) + done = EAS_TRUE; + else + { + fseek(wFile->file, startChunkPos + (EAS_I32) chunk.size, SEEK_SET); + state++; + } + break; + + /* looking for data chunk */ + case 4: + if (fread(&chunk, sizeof(chunk), 1, wFile->file) != 1) + done = EAS_TRUE; + else + { + startChunkPos = ftell(wFile->file); + + /* not data tag, skip it */ + if (chunk.tag != dataTag) + fseek(wFile->file, startChunkPos + (EAS_I32) chunk.size, SEEK_SET); + else + { + wFile->dataSize = chunk.size; + state++; + done = EAS_TRUE; + } + } + break; + + default: + done = EAS_TRUE; + break; + } + } + + /* if not final state, an error occurred */ + if (state != 5) + { + fclose(wFile->file); + free(wFile); + return NULL; + } + + /* return the file handle */ + return wFile; +} /* end WaveFileOpen */ +#endif + + + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_wave.h b/common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_wave.h new file mode 100755 index 0000000..968782f --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/host_src/eas_wave.h @@ -0,0 +1,74 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_wave.h + * + * Contents and purpose: + * Writes output to a .WAV file + * + * DO NOT MODIFY THIS FILE! + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_types.h" + +/* sentinel */ +#ifndef _EAS_WAVE_H +#define _EAS_WAVE_H + +/* .WAV file format chunk */ +typedef struct { + EAS_U16 wFormatTag; + EAS_U16 nChannels; + EAS_U32 nSamplesPerSec; + EAS_U32 nAvgBytesPerSec; + EAS_U16 nBlockAlign; + EAS_U16 wBitsPerSample; +} FMT_CHUNK; + +/* .WAV file header */ +typedef struct { + EAS_U32 nRiffTag; + EAS_U32 nRiffSize; + EAS_U32 nWaveTag; + EAS_U32 nFmtTag; + EAS_U32 nFmtSize; + FMT_CHUNK fc; + EAS_U32 nDataTag; + EAS_U32 nDataSize; +} WAVE_HEADER; + +typedef struct { + WAVE_HEADER wh; + FILE *file; + EAS_BOOL write; + EAS_U32 dataSize; +} WAVE_FILE; + +WAVE_FILE *WaveFileCreate (const char *filename, EAS_I32 nChannels, EAS_I32 nSamplesPerSec, EAS_I32 wBitsPerSample); +EAS_I32 WaveFileWrite (WAVE_FILE *wFile, void *buffer, EAS_I32 n); +EAS_BOOL WaveFileClose (WAVE_FILE *wFile); +WAVE_FILE *WaveFileOpen (const char *filename); + +#endif /* end #ifndef _EAS_WAVE_H */ + + + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib/libarm-fm-22k.a b/common/embeddedaudiosynthesis/arm-fm-22k/lib/libarm-fm-22k.a new file mode 100755 index 0000000..303b6b3 Binary files /dev/null and b/common/embeddedaudiosynthesis/arm-fm-22k/lib/libarm-fm-22k.a differ diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/arm-fm-22k_lib.mak b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/arm-fm-22k_lib.mak new file mode 100755 index 0000000..e4bc63d --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/arm-fm-22k_lib.mak @@ -0,0 +1,25 @@ +# +# Auto-generated sample makefile +# +# This makefile is intended for use with GNU make. +# Set the paths to the tools (CC, AR, LD, etc.) +# + +vpath %.c lib_src + +CC = C:\Program Files\GNUARM\bin\arm-elf-gcc.exe +AS = C:\Program Files\GNUARM\bin\arm-elf-as.exe +LD = C:\Program Files\GNUARM\bin\arm-elf-gcc.exe +AR = C:\Program Files\GNUARM\bin\arm-elf-ar.exe + +%.o: %.c + $(CC) -c -O2 -o $@ -I lib_src -I host_src -D NUM_OUTPUT_CHANNELS=2 -D _SAMPLE_RATE_22050 -D MAX_SYNTH_VOICES=16 -D EAS_FM_SYNTH -D _IMELODY_PARSER -D _RTTTL_PARSER -D _OTA_PARSER -D _WAVE_PARSER -D _REVERB_ENABLED -D _CHORUS_ENABLED -D _IMA_DECODER $< + +%.o: %.s + $(AS) -o $@ -EL -mcpu=arm946e-s -mfpu=softfpa $< + +OBJS = eas_mididata.o eas_pan.o eas_wavefiledata.o eas_smfdata.o eas_imelody.o eas_math.o eas_fmengine.o eas_chorusdata.o eas_ima_tables.o eas_ota.o eas_rtttldata.o eas_imelodydata.o eas_fmtables.o eas_public.o eas_rtttl.o eas_reverb.o eas_fmsynth.o eas_midi.o eas_otadata.o eas_mixbuf.o eas_fmsndlib.o eas_imaadpcm.o eas_smf.o eas_chorus.o eas_pcm.o eas_mixer.o eas_wavefile.o eas_pcmdata.o eas_data.o eas_reverbdata.o eas_voicemgt.o + +arm-fm-22k.a: $(OBJS) + $(AR) rc lib$@ $(OBJS) + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_audioconst.h b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_audioconst.h new file mode 100755 index 0000000..066148e --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_audioconst.h @@ -0,0 +1,97 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_audioconst.h + * + * Contents and purpose: + * Defines audio constants related to the sample rate, bit size, etc. + * + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_AUDIOCONST_H +#define _EAS_AUDIOCONST_H + +/*---------------------------------------------------------------------------- + * These macros define the various characteristics of the defined sample rates + *---------------------------------------------------------------------------- + * BUFFER_SIZE_IN_MONO_SAMPLES size of buffer in samples + * _OUTPUT_SAMPLE_RATE compiled output sample rate + * AUDIO_FRAME_LENGTH length of an audio frame in 256ths of a millisecond + * SYNTH_UPDATE_PERIOD_IN_BITS length of an audio frame (2^x samples) + *---------------------------------------------------------------------------- +*/ + +#if defined (_SAMPLE_RATE_8000) +#define BUFFER_SIZE_IN_MONO_SAMPLES 32 +#define _OUTPUT_SAMPLE_RATE 8000 +#define AUDIO_FRAME_LENGTH 1024 +#define SYNTH_UPDATE_PERIOD_IN_BITS 5 + +#elif defined (_SAMPLE_RATE_16000) +#define BUFFER_SIZE_IN_MONO_SAMPLES 64 +#define _OUTPUT_SAMPLE_RATE 16000 +#define AUDIO_FRAME_LENGTH 1024 +#define SYNTH_UPDATE_PERIOD_IN_BITS 6 + +#elif defined (_SAMPLE_RATE_20000) +#define BUFFER_SIZE_IN_MONO_SAMPLES 128 +#define _OUTPUT_SAMPLE_RATE 20000 +#define AUDIO_FRAME_LENGTH 1638 +#define SYNTH_UPDATE_PERIOD_IN_BITS 7 + +#elif defined (_SAMPLE_RATE_22050) +#define BUFFER_SIZE_IN_MONO_SAMPLES 128 +#define _OUTPUT_SAMPLE_RATE 22050 +#define AUDIO_FRAME_LENGTH 1486 +#define SYNTH_UPDATE_PERIOD_IN_BITS 7 + +#elif defined (_SAMPLE_RATE_24000) +#define BUFFER_SIZE_IN_MONO_SAMPLES 128 +#define _OUTPUT_SAMPLE_RATE 24000 +#define AUDIO_FRAME_LENGTH 1365 +#define SYNTH_UPDATE_PERIOD_IN_BITS 7 + +#elif defined (_SAMPLE_RATE_32000) +#define BUFFER_SIZE_IN_MONO_SAMPLES 128 +#define _OUTPUT_SAMPLE_RATE 32000 +#define AUDIO_FRAME_LENGTH 1024 +#define SYNTH_UPDATE_PERIOD_IN_BITS 7 + +#elif defined (_SAMPLE_RATE_44100) +#define BUFFER_SIZE_IN_MONO_SAMPLES 256 +#define _OUTPUT_SAMPLE_RATE 44100 +#define AUDIO_FRAME_LENGTH 1486 +#define SYNTH_UPDATE_PERIOD_IN_BITS 8 + +#elif defined (_SAMPLE_RATE_48000) +#define BUFFER_SIZE_IN_MONO_SAMPLES 256 +#define _OUTPUT_SAMPLE_RATE 48000 +#define AUDIO_FRAME_LENGTH 1365 +#define SYNTH_UPDATE_PERIOD_IN_BITS 8 + +#else +#error "_SAMPLE_RATE_XXXXX must be defined to valid rate" +#endif + +#endif /* #ifndef _EAS_AUDIOCONST_H */ + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_chorus.c b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_chorus.c new file mode 100755 index 0000000..4a2c8d0 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_chorus.c @@ -0,0 +1,604 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_chorus.c + * + * Contents and purpose: + * Contains the implementation of the Chorus effect. + * + * + * Copyright Sonic Network Inc. 2006 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 499 $ + * $Date: 2006-12-11 16:07:20 -0800 (Mon, 11 Dec 2006) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_data.h" +#include "eas_effects.h" +#include "eas_math.h" +#include "eas_chorusdata.h" +#include "eas_chorus.h" +#include "eas_config.h" +#include "eas_host.h" +#include "eas_report.h" + +/* prototypes for effects interface */ +static EAS_RESULT ChorusInit (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR *pInstData); +static void ChorusProcess (EAS_VOID_PTR pInstData, EAS_PCM *pSrc, EAS_PCM *pDst, EAS_I32 numSamples); +static EAS_RESULT ChorusShutdown (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT ChorusGetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue); +static EAS_RESULT ChorusSetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value); + +/* common effects interface for configuration module */ +const S_EFFECTS_INTERFACE EAS_Chorus = +{ + ChorusInit, + ChorusProcess, + ChorusShutdown, + ChorusGetParam, + ChorusSetParam +}; + + + +//LFO shape table used by the chorus, larger table would sound better +//this is a sine wave, where 32767 = 1.0 +static const EAS_I16 EAS_chorusShape[CHORUS_SHAPE_SIZE] = { + 0, 1608, 3212, 4808, 6393, 7962, 9512, 11309, 12539, 14010, 15446, 16846, 18204, 19519, 20787, 22005, 23170, + 24279, 25329, 26319, 27245, 28105, 28898, 29621, 30273, 30852, 31356, 31785, 32137, 32412, 32609, 32728, + 32767, 32728, 32609, 32412, 32137, 31785, 31356, 30852, 30273, 29621, 28898, 28105, 27245, 26319, 25329, + 24279, 23170, 22005, 20787, 19519, 18204, 16846, 15446, 14010, 12539, 11039, 9512, 7962, 6393, 4808, 3212, + 1608, 0, -1608, -3212, -4808, -6393, -7962, -9512, -11309, -12539, -14010, -15446, -16846, -18204, -19519, + -20787, -22005, -23170, -24279, -25329, -26319, -27245, -28105, -28898, -29621, -30273, -30852, -31356, -31785, + -32137, -32412, -32609, -32728, -32767, -32728, -32609, -32412, -32137, -31785, -31356, -30852, -30273, -29621, + -28898, -28105, -27245, -26319, -25329, -24279, -23170, -22005, -20787, -19519, -18204, -16846, -15446, -14010, + -12539, -11039, -9512, -7962, -6393, -4808, -3212, -1608 +}; + +/*---------------------------------------------------------------------------- + * InitializeChorus() + *---------------------------------------------------------------------------- + * Purpose: Initializes chorus parameters + * + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ChorusInit (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR *pInstData) +{ + S_CHORUS_OBJECT *pChorusData; + S_CHORUS_PRESET *pPreset; + EAS_I32 index; + + /* check Configuration Module for data allocation */ + if (pEASData->staticMemoryModel) + pChorusData = EAS_CMEnumFXData(EAS_MODULE_CHORUS); + + /* allocate dynamic memory */ + else + pChorusData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_CHORUS_OBJECT)); + + if (pChorusData == NULL) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Failed to allocate Chorus memory\n"); */ } + return EAS_ERROR_MALLOC_FAILED; + } + + /* clear the structure */ + EAS_HWMemSet(pChorusData, 0, sizeof(S_CHORUS_OBJECT)); + + ChorusReadInPresets(pChorusData); + + /* set some default values */ + pChorusData->bypass = EAS_CHORUS_BYPASS_DEFAULT; + pChorusData->preset = EAS_CHORUS_PRESET_DEFAULT; + pChorusData->m_nLevel = EAS_CHORUS_LEVEL_DEFAULT; + pChorusData->m_nRate = EAS_CHORUS_RATE_DEFAULT; + pChorusData->m_nDepth = EAS_CHORUS_DEPTH_DEFAULT; + + //chorus rate and depth need some massaging from preset value (which is sample rate independent) + + //convert rate from steps of .05 Hz to value which can be used as phase increment, + //with current CHORUS_SHAPE_SIZE and rate limits, this fits into 16 bits + //want to compute ((shapeSize * 65536) * (storedRate/20))/sampleRate; + //computing it as below allows rate steps to be evenly spaced + //uses 32 bit divide, but only once when new value is selected + pChorusData->m_nRate = (EAS_I16) + ((((EAS_I32)CHORUS_SHAPE_SIZE<<16)/(20*(EAS_I32)_OUTPUT_SAMPLE_RATE)) * pChorusData->m_nRate); + + //convert depth from steps of .05 ms, to samples, with 16 bit whole part, discard fraction + //want to compute ((depth * sampleRate)/20000) + //use the following approximation since 105/32 is roughly 65536/20000 + /*lint -e{704} use shift for performance */ + pChorusData->m_nDepth = (EAS_I16) + (((((EAS_I32)pChorusData->m_nDepth * _OUTPUT_SAMPLE_RATE)>>5) * 105) >> 16); + + pChorusData->m_nLevel = pChorusData->m_nLevel; + + //zero delay memory for chorus + for (index = CHORUS_L_SIZE - 1; index >= 0; index--) + { + pChorusData->chorusDelayL[index] = 0; + } + for (index = CHORUS_R_SIZE - 1; index >= 0; index--) + { + pChorusData->chorusDelayR[index] = 0; + } + + //init delay line index, these are used to implement circular delay buffer + pChorusData->chorusIndexL = 0; + pChorusData->chorusIndexR = 0; + + //init LFO phase + //16 bit whole part, 16 bit fraction + pChorusData->lfoLPhase = 0; + pChorusData->lfoRPhase = (CHORUS_SHAPE_SIZE << 16) >> 2; // 1/4 of total, i.e. 90 degrees out of phase; + + //init chorus delay position + //right now chorus delay is a compile-time value, as is sample rate + pChorusData->chorusTapPosition = (EAS_I16)((CHORUS_DELAY_MS * _OUTPUT_SAMPLE_RATE)/1000); + + //now copy from the new preset into Chorus + pPreset = &pChorusData->m_sPreset.m_sPreset[pChorusData->m_nNextChorus]; + + pChorusData->m_nLevel = pPreset->m_nLevel; + pChorusData->m_nRate = pPreset->m_nRate; + pChorusData->m_nDepth = pPreset->m_nDepth; + + pChorusData->m_nRate = (EAS_I16) + ((((EAS_I32)CHORUS_SHAPE_SIZE<<16)/(20*(EAS_I32)_OUTPUT_SAMPLE_RATE)) * pChorusData->m_nRate); + + /*lint -e{704} use shift for performance */ + pChorusData->m_nDepth = (EAS_I16) + (((((EAS_I32)pChorusData->m_nDepth * _OUTPUT_SAMPLE_RATE)>>5) * 105) >> 16); + + *pInstData = pChorusData; + + return EAS_SUCCESS; +} /* end ChorusInit */ + +/*---------------------------------------------------------------------------- + * WeightedTap() + *---------------------------------------------------------------------------- + * Purpose: Does fractional array look-up using linear interpolation + * + * first convert indexDesired to actual desired index by taking into account indexReference + * then do linear interpolation between two actual samples using fractional part + * + * Inputs: + * array: pointer to array of signed 16 bit values, typically either PCM data or control data + * indexReference: the circular buffer relative offset + * indexDesired: the fractional index we are looking up (16 bits index + 16 bits fraction) + * indexLimit: the total size of the array, used to compute buffer wrap + * + * Outputs: + * Value from the input array, linearly interpolated between two actual data values + * + *---------------------------------------------------------------------------- +*/ +static EAS_I16 WeightedTap(const EAS_I16 *array, EAS_I16 indexReference, EAS_I32 indexDesired, EAS_I16 indexLimit) +{ + EAS_I16 index; + EAS_I16 fraction; + EAS_I16 val1; + EAS_I16 val2; + + //separate indexDesired into whole and fractional parts + /*lint -e{704} use shift for performance */ + index = (EAS_I16)(indexDesired >> 16); + /*lint -e{704} use shift for performance */ + fraction = (EAS_I16)((indexDesired>>1) & 0x07FFF); //just use 15 bits of fractional part + + //adjust whole part by indexReference + index = indexReference - index; + //make sure we stay within array bounds, this implements circular buffer + while (index < 0) + { + index += indexLimit; + } + + //get two adjacent values from the array + val1 = array[index]; + + //handle special case when index == 0, else typical case + if (index == 0) + { + val2 = array[indexLimit-1]; //get last value from array + } + else + { + val2 = array[index-1]; //get previous value from array + } + + //compute linear interpolation as (val1 + ((val2-val1)*fraction)) + return(val1 + (EAS_I16)MULT_EG1_EG1(val2-val1,fraction)); +} + +/*---------------------------------------------------------------------------- + * ChorusProcess() + *---------------------------------------------------------------------------- + * Purpose: compute the chorus on the input buffer, and mix into output buffer + * + * + * Inputs: + * src: pointer to input buffer of PCM values to be processed + * dst: pointer to output buffer of PCM values we are to sume the result with + * bufSize: the number of sample frames (i.e. stereo samples) in the buffer + * + * Outputs: + * None + * + *---------------------------------------------------------------------------- +*/ +//compute the chorus, and mix into output buffer +static void ChorusProcess (EAS_VOID_PTR pInstData, EAS_PCM *pSrc, EAS_PCM *pDst, EAS_I32 numSamples) +{ + EAS_I32 ix; + EAS_I32 nChannelNumber; + EAS_I16 lfoValueLeft; + EAS_I16 lfoValueRight; + EAS_I32 positionOffsetL; + EAS_I32 positionOffsetR; + EAS_PCM tapL; + EAS_PCM tapR; + EAS_I32 tempValue; + EAS_PCM nInputSample; + EAS_I32 nOutputSample; + EAS_PCM *pIn; + EAS_PCM *pOut; + + S_CHORUS_OBJECT *pChorusData; + + pChorusData = (S_CHORUS_OBJECT*) pInstData; + + //if the chorus is disabled or turned all the way down + if (pChorusData->bypass == EAS_TRUE || pChorusData->m_nLevel == 0) + { + if (pSrc != pDst) + EAS_HWMemCpy(pSrc, pDst, numSamples * NUM_OUTPUT_CHANNELS * (EAS_I32) sizeof(EAS_PCM)); + return; + } + + if (pChorusData->m_nNextChorus != pChorusData->m_nCurrentChorus) + { + ChorusUpdate(pChorusData); + } + + for (nChannelNumber = 0; nChannelNumber < NUM_OUTPUT_CHANNELS; nChannelNumber++) + { + + pIn = pSrc + nChannelNumber; + pOut = pDst + nChannelNumber; + + if(nChannelNumber==0) + { + for (ix = 0; ix < numSamples; ix++) + { + nInputSample = *pIn; + pIn += NUM_OUTPUT_CHANNELS; + + //feed input into chorus delay line + pChorusData->chorusDelayL[pChorusData->chorusIndexL] = nInputSample; + + //compute chorus lfo value using phase as fractional index into chorus shape table + //resulting value is between -1.0 and 1.0, expressed as signed 16 bit number + lfoValueLeft = WeightedTap(EAS_chorusShape, 0, pChorusData->lfoLPhase, CHORUS_SHAPE_SIZE); + + //scale chorus depth by lfo value to get relative fractional sample index + //index is expressed as 32 bit number with 16 bit fractional part + /*lint -e{703} use shift for performance */ + positionOffsetL = pChorusData->m_nDepth * (((EAS_I32)lfoValueLeft) << 1); + + //add fixed chorus delay to get actual fractional sample index + positionOffsetL += ((EAS_I32)pChorusData->chorusTapPosition) << 16; + + //get tap value from chorus delay using fractional sample index + tapL = WeightedTap(pChorusData->chorusDelayL, pChorusData->chorusIndexL, positionOffsetL, CHORUS_L_SIZE); + + //scale by chorus level, then sum with input buffer contents and saturate + tempValue = MULT_EG1_EG1(tapL, pChorusData->m_nLevel); + nOutputSample = SATURATE(tempValue + nInputSample); + + *pOut = (EAS_I16)SATURATE(nOutputSample); + pOut += NUM_OUTPUT_CHANNELS; + + + //increment chorus delay index and make it wrap as needed + //this implements circular buffer + if ((pChorusData->chorusIndexL+=1) >= CHORUS_L_SIZE) + pChorusData->chorusIndexL = 0; + + //increment fractional lfo phase, and make it wrap as needed + pChorusData->lfoLPhase += pChorusData->m_nRate; + while (pChorusData->lfoLPhase >= (CHORUS_SHAPE_SIZE<<16)) + { + pChorusData->lfoLPhase -= (CHORUS_SHAPE_SIZE<<16); + } + } + } + else + { + for (ix = 0; ix < numSamples; ix++) + { + nInputSample = *pIn; + pIn += NUM_OUTPUT_CHANNELS; + + //feed input into chorus delay line + pChorusData->chorusDelayR[pChorusData->chorusIndexR] = nInputSample; + + //compute chorus lfo value using phase as fractional index into chorus shape table + //resulting value is between -1.0 and 1.0, expressed as signed 16 bit number + lfoValueRight = WeightedTap(EAS_chorusShape, 0, pChorusData->lfoRPhase, CHORUS_SHAPE_SIZE); + + //scale chorus depth by lfo value to get relative fractional sample index + //index is expressed as 32 bit number with 16 bit fractional part + /*lint -e{703} use shift for performance */ + positionOffsetR = pChorusData->m_nDepth * (((EAS_I32)lfoValueRight) << 1); + + //add fixed chorus delay to get actual fractional sample index + positionOffsetR += ((EAS_I32)pChorusData->chorusTapPosition) << 16; + + //get tap value from chorus delay using fractional sample index + tapR = WeightedTap(pChorusData->chorusDelayR, pChorusData->chorusIndexR, positionOffsetR, CHORUS_R_SIZE); + + //scale by chorus level, then sum with output buffer contents and saturate + tempValue = MULT_EG1_EG1(tapR, pChorusData->m_nLevel); + nOutputSample = SATURATE(tempValue + nInputSample); + + *pOut = (EAS_I16)SATURATE(nOutputSample); + pOut += NUM_OUTPUT_CHANNELS; + + //increment chorus delay index and make it wrap as needed + //this implements circular buffer + if ((pChorusData->chorusIndexR+=1) >= CHORUS_R_SIZE) + pChorusData->chorusIndexR = 0; + + //increment fractional lfo phase, and make it wrap as needed + pChorusData->lfoRPhase += pChorusData->m_nRate; + while (pChorusData->lfoRPhase >= (CHORUS_SHAPE_SIZE<<16)) + { + pChorusData->lfoRPhase -= (CHORUS_SHAPE_SIZE<<16); + } + } + } + + } +} /* end ChorusProcess */ + + + +/*---------------------------------------------------------------------------- + * ChorusShutdown() + *---------------------------------------------------------------------------- + * Purpose: + * Initializes the Chorus effect. + * + * Inputs: + * pInstData - handle to instance data + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ChorusShutdown (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR pInstData) +{ + /* check Configuration Module for static memory allocation */ + if (!pEASData->staticMemoryModel) + EAS_HWFree(pEASData->hwInstData, pInstData); + return EAS_SUCCESS; +} /* end ChorusShutdown */ + +/*---------------------------------------------------------------------------- + * ChorusGetParam() + *---------------------------------------------------------------------------- + * Purpose: + * Get a Chorus parameter + * + * Inputs: + * pInstData - handle to instance data + * param - parameter index + * *pValue - pointer to variable to hold retrieved value + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ChorusGetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue) +{ + S_CHORUS_OBJECT *p; + + p = (S_CHORUS_OBJECT*) pInstData; + + switch (param) + { + case EAS_PARAM_CHORUS_BYPASS: + *pValue = (EAS_I32) p->bypass; + break; + case EAS_PARAM_CHORUS_PRESET: + *pValue = (EAS_I8) p->m_nCurrentChorus; + break; + case EAS_PARAM_CHORUS_RATE: + *pValue = (EAS_I32) p->m_nRate; + break; + case EAS_PARAM_CHORUS_DEPTH: + *pValue = (EAS_I32) p->m_nDepth; + break; + case EAS_PARAM_CHORUS_LEVEL: + *pValue = (EAS_I32) p->m_nLevel; + break; + default: + return EAS_ERROR_INVALID_PARAMETER; + } + return EAS_SUCCESS; +} /* end ChorusGetParam */ + + +/*---------------------------------------------------------------------------- + * ChorusSetParam() + *---------------------------------------------------------------------------- + * Purpose: + * Set a Chorus parameter + * + * Inputs: + * pInstData - handle to instance data + * param - parameter index + * *pValue - new paramter value + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ChorusSetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value) +{ + S_CHORUS_OBJECT *p; + + p = (S_CHORUS_OBJECT*) pInstData; + + switch (param) + { + case EAS_PARAM_CHORUS_BYPASS: + p->bypass = (EAS_BOOL) value; + break; + case EAS_PARAM_CHORUS_PRESET: + if(value!=EAS_PARAM_CHORUS_PRESET1 && value!=EAS_PARAM_CHORUS_PRESET2 && + value!=EAS_PARAM_CHORUS_PRESET3 && value!=EAS_PARAM_CHORUS_PRESET4) + return EAS_ERROR_INVALID_PARAMETER; + p->m_nNextChorus = (EAS_I8)value; + break; + case EAS_PARAM_CHORUS_RATE: + if(valueEAS_CHORUS_RATE_MAX) + return EAS_ERROR_INVALID_PARAMETER; + p->m_nRate = (EAS_I16) value; + break; + case EAS_PARAM_CHORUS_DEPTH: + if(valueEAS_CHORUS_DEPTH_MAX) + return EAS_ERROR_INVALID_PARAMETER; + p->m_nDepth = (EAS_I16) value; + break; + case EAS_PARAM_CHORUS_LEVEL: + if(valueEAS_CHORUS_LEVEL_MAX) + return EAS_ERROR_INVALID_PARAMETER; + p->m_nLevel = (EAS_I16) value; + break; + + default: + return EAS_ERROR_INVALID_PARAMETER; + } + return EAS_SUCCESS; +} /* end ChorusSetParam */ + + +/*---------------------------------------------------------------------------- + * ChorusReadInPresets() + *---------------------------------------------------------------------------- + * Purpose: sets global Chorus preset bank to defaults + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ChorusReadInPresets(S_CHORUS_OBJECT *pChorusData) +{ + + int preset = 0; + int defaultPreset = 0; + + //now init any remaining presets to defaults + for (defaultPreset = preset; defaultPreset < CHORUS_MAX_TYPE; defaultPreset++) + { + S_CHORUS_PRESET *pPreset = &pChorusData->m_sPreset.m_sPreset[defaultPreset]; + if (defaultPreset == 0 || defaultPreset > CHORUS_MAX_TYPE-1) + { + pPreset->m_nDepth = 39; + pPreset->m_nRate = 30; + pPreset->m_nLevel = 32767; + } + else if (defaultPreset == 1) + { + pPreset->m_nDepth = 21; + pPreset->m_nRate = 45; + pPreset->m_nLevel = 25000; + } + else if (defaultPreset == 2) + { + pPreset->m_nDepth = 53; + pPreset->m_nRate = 25; + pPreset->m_nLevel = 32000; + } + else if (defaultPreset == 3) + { + pPreset->m_nDepth = 32; + pPreset->m_nRate = 37; + pPreset->m_nLevel = 29000; + } + } + + return EAS_SUCCESS; +} + + +/*---------------------------------------------------------------------------- + * ChorusUpdate + *---------------------------------------------------------------------------- + * Purpose: + * Update the Chorus preset parameters as required + * + * Inputs: + * + * Outputs: + * + * + * Side Effects: + * - chorus paramters will be changed + * - m_nCurrentRoom := m_nNextRoom + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ChorusUpdate(S_CHORUS_OBJECT *pChorusData) +{ + S_CHORUS_PRESET *pPreset = &pChorusData->m_sPreset.m_sPreset[pChorusData->m_nNextChorus]; + + pChorusData->m_nLevel = pPreset->m_nLevel; + pChorusData->m_nRate = pPreset->m_nRate; + pChorusData->m_nDepth = pPreset->m_nDepth; + + pChorusData->m_nRate = (EAS_I16) + ((((EAS_I32)CHORUS_SHAPE_SIZE<<16)/(20*(EAS_I32)_OUTPUT_SAMPLE_RATE)) * pChorusData->m_nRate); + + /*lint -e{704} use shift for performance */ + pChorusData->m_nDepth = (EAS_I16) + (((((EAS_I32)pChorusData->m_nDepth * _OUTPUT_SAMPLE_RATE)>>5) * 105) >> 16); + + pChorusData->m_nCurrentChorus = pChorusData->m_nNextChorus; + + return EAS_SUCCESS; + +} /* end ChorusUpdate */ diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_chorusdata.c b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_chorusdata.c new file mode 100755 index 0000000..ec71ff8 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_chorusdata.c @@ -0,0 +1,34 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_chorusdata.c + * + * Contents and purpose: + * Contains the static data allocation for the Chorus effect + * + * + * Copyright Sonic Network Inc. 2006 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 550 $ + * $Date: 2007-02-02 09:37:03 -0800 (Fri, 02 Feb 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_chorusdata.h" + +S_CHORUS_OBJECT eas_ChorusData; + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_chorusdata.h b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_chorusdata.h new file mode 100755 index 0000000..ec8daa4 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_chorusdata.h @@ -0,0 +1,160 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_chorusdata.h + * + * Contents and purpose: + * Contains the prototypes for the Chorus effect. + * + * + * Copyright Sonic Network Inc. 2006 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 309 $ + * $Date: 2006-09-12 18:52:45 -0700 (Tue, 12 Sep 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_CHORUS_H +#define _EAS_CHORUS_H + +#include "eas_types.h" +#include "eas_audioconst.h" + +//defines for chorus + +#define EAS_CHORUS_BYPASS_DEFAULT 1 +#define EAS_CHORUS_PRESET_DEFAULT 0 +#define EAS_CHORUS_RATE_DEFAULT 30 +#define EAS_CHORUS_DEPTH_DEFAULT 39 +#define EAS_CHORUS_LEVEL_DEFAULT 32767 + +#define EAS_CHORUS_LEVEL_MIN 0 +#define EAS_CHORUS_LEVEL_MAX 32767 + +#define EAS_CHORUS_RATE_MIN 10 +#define EAS_CHORUS_RATE_MAX 50 + +#define EAS_CHORUS_DEPTH_MIN 15 +#define EAS_CHORUS_DEPTH_MAX 60 + +#define CHORUS_SIZE_MS 20 +#define CHORUS_L_SIZE ((CHORUS_SIZE_MS*_OUTPUT_SAMPLE_RATE)/1000) +#define CHORUS_R_SIZE CHORUS_L_SIZE +#define CHORUS_SHAPE_SIZE 128 +#define CHORUS_DELAY_MS 10 + +#define CHORUS_MAX_TYPE 4 // any Chorus numbers larger than this are invalid + +typedef struct +{ + EAS_I16 m_nRate; + EAS_I16 m_nDepth; + EAS_I16 m_nLevel; + +} S_CHORUS_PRESET; + +typedef struct +{ + S_CHORUS_PRESET m_sPreset[CHORUS_MAX_TYPE]; //array of presets + +} S_CHORUS_PRESET_BANK; + +/* parameters for each Chorus */ +typedef struct +{ + EAS_I32 lfoLPhase; + EAS_I32 lfoRPhase; + EAS_I16 chorusIndexL; + EAS_I16 chorusIndexR; + EAS_U16 chorusTapPosition; + + EAS_I16 m_nRate; + EAS_I16 m_nDepth; + EAS_I16 m_nLevel; + + //delay lines used by the chorus, longer would sound better + EAS_PCM chorusDelayL[CHORUS_L_SIZE]; + EAS_PCM chorusDelayR[CHORUS_R_SIZE]; + + EAS_BOOL bypass; + EAS_I8 preset; + + EAS_I16 m_nCurrentChorus; // preset number for current Chorus + EAS_I16 m_nNextChorus; // preset number for next Chorus + + S_CHORUS_PRESET pPreset; + + S_CHORUS_PRESET_BANK m_sPreset; + +} S_CHORUS_OBJECT; + + +/*---------------------------------------------------------------------------- + * WeightedTap() + *---------------------------------------------------------------------------- + * Purpose: Does fractional array look-up using linear interpolation + * + * first convert indexDesired to actual desired index by taking into account indexReference + * then do linear interpolation between two actual samples using fractional part + * + * Inputs: + * array: pointer to array of signed 16 bit values, typically either PCM data or control data + * indexReference: the circular buffer relative offset + * indexDesired: the fractional index we are looking up (16 bits index + 16 bits fraction) + * indexLimit: the total size of the array, used to compute buffer wrap + * + * Outputs: + * Value from the input array, linearly interpolated between two actual data values + * + *---------------------------------------------------------------------------- +*/ +static EAS_I16 WeightedTap(const EAS_I16 *array, EAS_I16 indexReference, EAS_I32 indexDesired, EAS_I16 indexLimit); + +/*---------------------------------------------------------------------------- + * ChorusReadInPresets() + *---------------------------------------------------------------------------- + * Purpose: sets global Chorus preset bank to defaults + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ChorusReadInPresets(S_CHORUS_OBJECT *pChorusData); + +/*---------------------------------------------------------------------------- + * ChorusUpdate + *---------------------------------------------------------------------------- + * Purpose: + * Update the Chorus preset parameters as required + * + * Inputs: + * + * Outputs: + * + * + * Side Effects: + * - chorus paramters will be changed + * - m_nCurrentChorus := m_nNextChorus + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ChorusUpdate(S_CHORUS_OBJECT* pChorusData); + +#endif /* #ifndef _EAS_CHORUSDATA_H */ + + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_ctype.h b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_ctype.h new file mode 100755 index 0000000..14fa96f --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_ctype.h @@ -0,0 +1,41 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_ctype.h + * + * Contents and purpose: + * This is a replacement for the CRT ctype.h functions. These + * functions are currently ASCII only, but eventually, we will want + * to support wide-characters for localization. + * + * Copyright (c) 2005 Sonic Network Inc. + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 429 $ + * $Date: 2006-10-19 23:50:15 -0700 (Thu, 19 Oct 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_CTYPE_H +#define _EAS_CTYPE_H + +EAS_INLINE EAS_I8 IsDigit (EAS_I8 c) { return ((c >= '0') && (c <= '9')); } +EAS_INLINE EAS_I8 IsSpace (EAS_I8 c) { return (((c >= 9) && (c <= 13)) || (c == ' ')); } +EAS_INLINE EAS_I8 ToUpper (EAS_I8 c) { if ((c >= 'a') && (c <= 'z')) return c & ~0x20; else return c; } +EAS_INLINE EAS_I8 ToLower (EAS_I8 c) { if ((c >= 'A') && (c <= 'Z')) return c |= 0x20; else return c; } + +#endif + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_data.c b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_data.c new file mode 100755 index 0000000..31a4e6a --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_data.c @@ -0,0 +1,37 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_data.c + * + * Contents and purpose: + * Contains a data allocation for synthesizer + * + * Copyright Sonic Network Inc. 2004 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 547 $ + * $Date: 2007-01-31 16:30:17 -0800 (Wed, 31 Jan 2007) $ + *---------------------------------------------------------------------------- +*/ + +// includes +#include "eas_data.h" + +// globals +S_EAS_DATA eas_Data; +S_VOICE_MGR eas_Synth; +S_SYNTH eas_MIDI; + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_data.h b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_data.h new file mode 100755 index 0000000..e2fcb1a --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_data.h @@ -0,0 +1,131 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_data.h + * + * Contents and purpose: + * This header defines all types, to support dynamic allocation of the + * memory resources needed for persistent EAS data. + * + * Copyright 2004 Sonic Network Inc. + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 842 $ + * $Date: 2007-08-23 14:32:31 -0700 (Thu, 23 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_DATA_H +#define _EAS_DATA_H + +#include "eas_types.h" +#include "eas_synthcfg.h" +#include "eas.h" +#include "eas_audioconst.h" +#include "eas_sndlib.h" +#include "eas_pcm.h" +#include "eas_pcmdata.h" +#include "eas_synth.h" +#include "eas_miditypes.h" +#include "eas_effects.h" + +#ifdef AUX_MIXER +#include "eas_auxmixdata.h" +#endif + +#ifdef JET_INTERFACE +#include "jet.h" +#endif + +#ifdef _METRICS_ENABLED +#include "eas_perf.h" +#endif + +#ifndef MAX_NUMBER_STREAMS +#define MAX_NUMBER_STREAMS 4 +#endif + +/* flags for S_EAS_STREAM */ +#define STREAM_FLAGS_PARSED 1 +#define STREAM_FLAGS_PAUSE 2 +#define STREAM_FLAGS_LOCATE 4 +#define STREAM_FLAGS_RESUME 8 + +/* structure for parsing a stream */ +typedef struct s_eas_stream_tag +{ + void *pParserModule; + EAS_U32 time; + EAS_U32 frameLength; + EAS_I32 repeatCount; + EAS_VOID_PTR handle; + EAS_U8 volume; + EAS_BOOL8 streamFlags; +} S_EAS_STREAM; + +/* default master volume is -10dB */ +#define DEFAULT_VOLUME 90 +#define DEFAULT_STREAM_VOLUME 100 +#define DEFAULT_STREAM_GAIN 14622 + +/* 10 dB of boost available for individual parsers */ +#define STREAM_VOLUME_HEADROOM 10 + +/* amalgamated persistent data type */ +typedef struct s_eas_data_tag +{ +#ifdef _CHECKED_BUILD + EAS_U32 handleCheck; +#endif + EAS_HW_DATA_HANDLE hwInstData; + + S_EFFECTS_MODULE effectsModules[NUM_EFFECTS_MODULES]; + +#ifdef _METRICS_ENABLED + S_METRICS_INTERFACE *pMetricsModule; + EAS_VOID_PTR pMetricsData; +#endif + + EAS_I32 *pMixBuffer; + EAS_PCM *pOutputAudioBuffer; + +#ifdef AUX_MIXER + S_EAS_AUX_MIXER auxMixer; +#endif + +#ifdef _MAXIMIZER_ENABLED + EAS_VOID_PTR pMaximizerData; +#endif + + S_EAS_STREAM streams[MAX_NUMBER_STREAMS]; + + S_PCM_STATE *pPCMStreams; + + S_VOICE_MGR *pVoiceMgr; + +#ifdef JET_INTERFACE + JET_DATA_HANDLE jetHandle; +#endif + + EAS_U32 renderTime; + EAS_I16 masterGain; + EAS_U8 masterVolume; + EAS_BOOL8 staticMemoryModel; + EAS_BOOL8 searchHeaderFlag; +} S_EAS_DATA; + +#endif + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_effects.h b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_effects.h new file mode 100755 index 0000000..86dedac --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_effects.h @@ -0,0 +1,61 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_effects.h + * + * Contents and purpose: + * Defines a generic effects interface. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_EFFECTS_H +#define _EAS_EFFECTS_H + +#include "eas_types.h" + +typedef struct +{ + EAS_RESULT (*pfInit)(EAS_DATA_HANDLE pEASData, EAS_VOID_PTR *pInstData); + void (*pfProcess)(EAS_VOID_PTR pInstData, EAS_PCM *in, EAS_PCM *out, EAS_I32 numSamples); + EAS_RESULT (*pfShutdown)(EAS_DATA_HANDLE pEASData, EAS_VOID_PTR pInstData); + EAS_RESULT (*pFGetParam)(EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue); + EAS_RESULT (*pFSetParam)(EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value); +} S_EFFECTS_INTERFACE; + +typedef struct +{ + EAS_RESULT (*pfInit)(EAS_DATA_HANDLE pEASData, EAS_VOID_PTR *pInstData); + void (*pfProcess)(EAS_VOID_PTR pInstData, EAS_I32 *in, EAS_I32 *out, EAS_I32 numSamples); + EAS_RESULT (*pfShutdown)(EAS_DATA_HANDLE pEASData, EAS_VOID_PTR pInstData); + EAS_RESULT (*pFGetParam)(EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue); + EAS_RESULT (*pFSetParam)(EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value); +} S_EFFECTS32_INTERFACE; + +/* mixer instance data */ +typedef struct +{ + S_EFFECTS_INTERFACE *effect; + EAS_VOID_PTR effectData; +} S_EFFECTS_MODULE; + +#endif /* end _EAS_EFFECTS_H */ + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_fmengine.c b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_fmengine.c new file mode 100755 index 0000000..ea7f69c --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_fmengine.c @@ -0,0 +1,785 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_fmengine.c + * + * Contents and purpose: + * Implements the low-level FM synthesizer functions. + * + * Copyright Sonic Network Inc. 2004, 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 795 $ + * $Date: 2007-08-01 00:14:45 -0700 (Wed, 01 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +/* includes */ +#include "eas_types.h" +#include "eas_math.h" +#include "eas_audioconst.h" +#include "eas_fmengine.h" + +#if defined(EAS_FM_SYNTH) || defined(EAS_HYBRID_SYNTH) || defined(EAS_SPLIT_HYBRID_SYNTH) || defined(EAS_SPLIT_FM_SYNTH) +#include "eas_data.h" +#endif + +/* externals */ +extern const EAS_I16 sineTable[]; +extern const EAS_U8 fmScaleTable[16]; + +// saturation constants for 32-bit to 16-bit conversion +#define _EAS_MAX_OUTPUT 32767 +#define _EAS_MIN_OUTPUT -32767 + +static S_FM_ENG_VOICE voices[NUM_FM_VOICES]; + +/* local prototypes */ +void FM_SynthMixVoice (S_FM_ENG_VOICE *p, EAS_U16 gainTarget, EAS_I32 numSamplesToAdd, EAS_PCM *pInputBuffer, EAS_I32 *pBuffer); + +/* used in development environment */ +#if defined(_SATURATION_MONITOR) +static EAS_BOOL bSaturated = EAS_FALSE; + +/*---------------------------------------------------------------------------- + * FM_CheckSaturation() + *---------------------------------------------------------------------------- + * Purpose: + * Allows the sound development tool to check for saturation at the voice + * level. Useful for tuning the level controls. + * + * Inputs: + * + * Outputs: + * Returns true if saturation has occurred since the last time the function + * was called. + * + * Side Effects: + * Resets the saturation flag + *---------------------------------------------------------------------------- +*/ +EAS_BOOL FM_CheckSaturation () +{ + EAS_BOOL bTemp; + bTemp = bSaturated; + bSaturated = EAS_FALSE; + return bTemp; +} +#endif + +/*---------------------------------------------------------------------------- + * FM_Saturate() + *---------------------------------------------------------------------------- + * Purpose: + * This inline function saturates a 32-bit number to 16-bits + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * Returns a 16-bit integer + *---------------------------------------------------------------------------- +*/ +EAS_INLINE EAS_I16 FM_Saturate (EAS_I32 nValue) +{ + if (nValue > _EAS_MAX_OUTPUT) + { +#if defined(_SATURATION_MONITOR) + bSaturated = EAS_TRUE; +#endif + return _EAS_MAX_OUTPUT; + } + if (nValue < _EAS_MIN_OUTPUT) + { +#if defined(_SATURATION_MONITOR) + bSaturated = EAS_TRUE; +#endif + return _EAS_MIN_OUTPUT; + } + return (EAS_I16) nValue; +} + +/*---------------------------------------------------------------------------- + * FM_Noise() + *---------------------------------------------------------------------------- + * Purpose: + * A 31-bit low-cost linear congruential PRNG algorithm used to + * generate noise. + * + * Inputs: + * pnSeed - pointer to 32-bit PRNG seed + * + * Outputs: + * Returns a 16-bit integer + *---------------------------------------------------------------------------- +*/ +EAS_INLINE EAS_I16 FM_Noise (EAS_U32 *pnSeed) +{ + *pnSeed = *pnSeed * 214013L + 2531011L; + return (EAS_I16) ((*pnSeed >> 15) & 0xffff); +} + +/*---------------------------------------------------------------------------- + * FM_PhaseInc() + *---------------------------------------------------------------------------- + * Purpose: + * Transform pitch cents to linear phase increment + * + * Inputs: + * nCents - measured in cents + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * nResult - int.frac result (where frac has NUM_DENTS_FRAC_BITS) + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_I32 FM_PhaseInc (EAS_I32 nCents) +{ + EAS_I32 nDents; + EAS_I32 nExponentInt, nExponentFrac; + EAS_I32 nTemp1, nTemp2; + EAS_I32 nResult; + + /* convert cents to dents */ + nDents = FMUL_15x15(nCents, CENTS_TO_DENTS); + nExponentInt = GET_DENTS_INT_PART(nDents) + (32 - SINE_TABLE_SIZE_IN_BITS - NUM_EG1_FRAC_BITS); + nExponentFrac = GET_DENTS_FRAC_PART(nDents); + + /* implement 2^(fracPart) as a power series */ + nTemp1 = GN2_TO_X2 + MULT_DENTS_COEF(nExponentFrac, GN2_TO_X3); + nTemp2 = GN2_TO_X1 + MULT_DENTS_COEF(nExponentFrac, nTemp1); + nTemp1 = GN2_TO_X0 + MULT_DENTS_COEF(nExponentFrac, nTemp2); + + /* + implement 2^(intPart) as + a left shift for intPart >= 0 or + a left shift for intPart < 0 + */ + if (nExponentInt >= 0) + { + /* left shift for positive exponents */ + /*lint -e{703} */ + nResult = nTemp1 << nExponentInt; + } + else + { + /* right shift for negative exponents */ + nExponentInt = -nExponentInt; + nResult = nTemp1 >> nExponentInt; + } + + return nResult; +} + +#if (NUM_OUTPUT_CHANNELS == 2) +/*---------------------------------------------------------------------------- + * FM_CalculatePan() + *---------------------------------------------------------------------------- + * Purpose: + * Assign the left and right gain values corresponding to the given pan value. + * + * Inputs: + * psVoice - ptr to the voice we have assigned for this channel + * psArticulation - ptr to this voice's articulation + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * the given voice's m_nGainLeft and m_nGainRight are assigned + *---------------------------------------------------------------------------- +*/ +static void FM_CalculatePan (EAS_I16 pan, EAS_U16 *pGainLeft, EAS_U16 *pGainRight) +{ + EAS_I32 nTemp; + EAS_INT nNetAngle; + + /* + Implement the following + sin(x) = (2-4*c)*x^2 + c + x + cos(x) = (2-4*c)*x^2 + c - x + + where c = 1/sqrt(2) + using the a0 + x*(a1 + x*a2) approach + */ + + /* + Get the Midi CC10 pan value for this voice's channel + convert the pan value to an "angle" representation suitable for + our sin, cos calculator. This representation is NOT necessarily the same + as the transform in the GM manuals because of our sin, cos calculator. + "angle" = (CC10 - 64)/128 + */ + /*lint -e{703} */ + nNetAngle = ((EAS_I32) pan) << (NUM_EG1_FRAC_BITS -7); + + /* calculate sin */ + nTemp = EG1_ONE + FMUL_15x15(COEFF_PAN_G2, nNetAngle); + nTemp = COEFF_PAN_G0 + FMUL_15x15(nTemp, nNetAngle); + + if (nTemp > SYNTH_FULL_SCALE_EG1_GAIN) + nTemp = SYNTH_FULL_SCALE_EG1_GAIN; + else if (nTemp < 0) + nTemp = 0; + + *pGainRight = (EAS_U16) nTemp; + + /* calculate cos */ + nTemp = -EG1_ONE + FMUL_15x15(COEFF_PAN_G2, nNetAngle); + nTemp = COEFF_PAN_G0 + FMUL_15x15(nTemp, nNetAngle); + + if (nTemp > SYNTH_FULL_SCALE_EG1_GAIN) + nTemp = SYNTH_FULL_SCALE_EG1_GAIN; + else if (nTemp < 0) + nTemp = 0; + + *pGainLeft = (EAS_U16) nTemp; +} +#endif /* #if (NUM_OUTPUT_CHANNELS == 2) */ + +/*---------------------------------------------------------------------------- + * FM_Operator() + *---------------------------------------------------------------------------- + * Purpose: + * Synthesizes a buffer of samples based on passed parameters. + * + * Inputs: + * nNumSamplesToAdd - number of samples to synthesize + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void FM_Operator ( + S_FM_ENG_OPER *p, + EAS_I32 numSamplesToAdd, + EAS_PCM *pBuffer, + EAS_PCM *pModBuffer, + EAS_BOOL mix, + EAS_U16 gainTarget, + EAS_I16 pitch, + EAS_U8 feedback, + EAS_I16 *pLastOutput) +{ + EAS_I32 gain; + EAS_I32 gainInc; + EAS_U32 phase; + EAS_U32 phaseInc; + EAS_U32 phaseTemp; + EAS_I32 temp; + EAS_I32 temp2; + + /* establish local gain variable */ + gain = (EAS_I32) p->gain << 16; + + /* calculate gain increment */ + /*lint -e{703} use shift for performance */ + gainInc = ((EAS_I32) gainTarget - (EAS_I32) p->gain) << (16 - SYNTH_UPDATE_PERIOD_IN_BITS); + + /* establish local phase variables */ + phase = p->phase; + + /* calculate the new phase increment */ + phaseInc = (EAS_U32) FM_PhaseInc(pitch); + + /* restore final output from previous frame for feedback loop */ + if (pLastOutput) + temp = *pLastOutput; + else + temp = 0; + + /* generate a buffer of samples */ + while (numSamplesToAdd--) + { + + /* incorporate modulation */ + if (pModBuffer) + { + /*lint -e{701} use shift for performance */ + temp = *pModBuffer++ << FM_MODULATOR_INPUT_SHIFT; + } + + /* incorporate feedback */ + else + { + /*lint -e{703} use shift for performance */ + temp = (temp * (EAS_I32) feedback) << FM_FEEDBACK_SHIFT; + } + + /*lint -e{737} */ + phaseTemp = phase + temp; + + /* fetch sample from wavetable */ + temp = sineTable[phaseTemp >> (32 - SINE_TABLE_SIZE_IN_BITS)]; + + /* increment operator phase */ + phase += phaseInc; + + /* internal gain for modulation effects */ + temp = FMUL_15x15(temp, (gain >> 16)); + + /* output gain calculation */ + temp2 = FMUL_15x15(temp, p->outputGain); + + /* saturating add to buffer */ + if (mix) + { + temp2 += *pBuffer; + *pBuffer++ = FM_Saturate(temp2); + } + + /* output to buffer */ + else + *pBuffer++ = (EAS_I16) temp2; + + /* increment gain */ + gain += gainInc; + + } + + /* save phase and gain */ + p->phase = phase; + p->gain = gainTarget; + + /* save last output for feedback in next frame */ + if (pLastOutput) + *pLastOutput = (EAS_I16) temp; +} + +/*---------------------------------------------------------------------------- + * FM_NoiseOperator() + *---------------------------------------------------------------------------- + * Purpose: + * Synthesizes a buffer of samples based on passed parameters. + * + * Inputs: + * nNumSamplesToAdd - number of samples to synthesize + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void FM_NoiseOperator ( + S_FM_ENG_OPER *p, + EAS_I32 numSamplesToAdd, + EAS_PCM *pBuffer, + EAS_BOOL mix, + EAS_U16 gainTarget, + EAS_U8 feedback, + EAS_I16 *pLastOutput) +{ + EAS_I32 gain; + EAS_I32 gainInc; + EAS_U32 phase; + EAS_I32 temp; + EAS_I32 temp2; + + /* establish local gain variable */ + gain = (EAS_I32) p->gain << 16; + + /* calculate gain increment */ + /*lint -e{703} use shift for performance */ + gainInc = ((EAS_I32) gainTarget - (EAS_I32) p->gain) << (16 - SYNTH_UPDATE_PERIOD_IN_BITS); + + /* establish local phase variables */ + phase = p->phase; + + /* establish local phase variables */ + phase = p->phase; + + /* recall last sample for filter Z-1 term */ + temp = 0; + if (pLastOutput) + temp = *pLastOutput; + + /* generate a buffer of samples */ + while (numSamplesToAdd--) + { + + /* if using filter */ + if (pLastOutput) + { + /* use PRNG for noise */ + temp2 = FM_Noise(&phase); + + /*lint -e{704} use shift for performance */ + temp += ((temp2 -temp) * feedback) >> 8; + } + else + { + temp = FM_Noise(&phase); + } + + /* internal gain for modulation effects */ + temp2 = FMUL_15x15(temp, (gain >> 16)); + + /* output gain calculation */ + temp2 = FMUL_15x15(temp2, p->outputGain); + + /* saturating add to buffer */ + if (mix) + { + temp2 += *pBuffer; + *pBuffer++ = FM_Saturate(temp2); + } + + /* output to buffer */ + else + *pBuffer++ = (EAS_I16) temp2; + + /* increment gain */ + gain += gainInc; + + } + + /* save phase and gain */ + p->phase = phase; + p->gain = gainTarget; + + /* save last output for feedback in next frame */ + if (pLastOutput) + *pLastOutput = (EAS_I16) temp; +} + +/*---------------------------------------------------------------------------- + * FM_ConfigVoice() + *---------------------------------------------------------------------------- + * Purpose: + * Receives parameters to start a new voice. + * + * Inputs: + * voiceNum - voice number to start + * vCfg - configuration data + * pMixBuffer - pointer to host supplied buffer + * + * Outputs: + * + * Side Effects: + * + * Notes: + * pFrameBuffer is not used in the test version, but is passed as a + * courtesy to split architecture implementations. It can be used as + * as pointer to the interprocessor communications buffer when the + * synthesis parameters are passed off to a DSP for synthesis. + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pFrameBuffer) pFrameBuffer not used in test version - see above */ +void FM_ConfigVoice (EAS_I32 voiceNum, S_FM_VOICE_CONFIG *vCfg, EAS_FRAME_BUFFER_HANDLE pFrameBuffer) +{ + S_FM_ENG_VOICE *pVoice; + EAS_INT i; + + /* establish pointer to voice data */ + pVoice = &voices[voiceNum]; + + /* save data */ + pVoice->feedback = vCfg->feedback; + pVoice->flags = vCfg->flags; + pVoice->voiceGain = vCfg->voiceGain; + + /* initialize Z-1 terms */ + pVoice->op1Out = 0; + pVoice->op3Out = 0; + + /* initialize operators */ + for (i = 0; i < 4; i++) + { + /* save operator data */ + pVoice->oper[i].gain = vCfg->gain[i]; + pVoice->oper[i].outputGain = vCfg->outputGain[i]; + pVoice->oper[i].outputGain = vCfg->outputGain[i]; + + /* initalize operator */ + pVoice->oper[i].phase = 0; + } + + /* calculate pan */ +#if NUM_OUTPUT_CHANNELS == 2 + FM_CalculatePan(vCfg->pan, &pVoice->gainLeft, &pVoice->gainRight); +#endif +} + +/*---------------------------------------------------------------------------- + * FM_ProcessVoice() + *---------------------------------------------------------------------------- + * Purpose: + * Synthesizes a buffer of samples based on calculated parameters. + * + * Inputs: + * nNumSamplesToAdd - number of samples to synthesize + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * + * Notes: + * pOut is not used in the test version, but is passed as a + * courtesy to split architecture implementations. It can be used as + * as pointer to the interprocessor communications buffer when the + * synthesis parameters are passed off to a DSP for synthesis. + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pOut) pOut not used in test version - see above */ +void FM_ProcessVoice ( + EAS_I32 voiceNum, + S_FM_VOICE_FRAME *pFrame, + EAS_I32 numSamplesToAdd, + EAS_PCM *pTempBuffer, + EAS_PCM *pBuffer, + EAS_I32 *pMixBuffer, + EAS_FRAME_BUFFER_HANDLE pFrameBuffer) +{ + S_FM_ENG_VOICE *p; + EAS_PCM *pOutBuf; + EAS_PCM *pMod; + EAS_BOOL mix; + EAS_U8 feedback1; + EAS_U8 feedback3; + EAS_U8 mode; + + /* establish pointer to voice data */ + p = &voices[voiceNum]; + mode = p->flags & 0x07; + + /* lookup feedback values */ + feedback1 = fmScaleTable[p->feedback >> 4]; + feedback3 = fmScaleTable[p->feedback & 0x0f]; + + /* operator 3 is on output bus in modes 0, 1, and 3 */ + if ((mode == 0) || (mode == 1) || (mode == 3)) + pOutBuf = pBuffer; + else + pOutBuf = pTempBuffer; + + if (p->flags & FLAG_FM_ENG_VOICE_OP3_NOISE) + { + FM_NoiseOperator( + p->oper + 2, + numSamplesToAdd, + pOutBuf, + EAS_FALSE, + pFrame->gain[2], + feedback3, + &p->op3Out); + } + else + { + FM_Operator( + p->oper + 2, + numSamplesToAdd, + pOutBuf, + 0, + EAS_FALSE, + pFrame->gain[2], + pFrame->pitch[2], + feedback3, + &p->op3Out); + } + + /* operator 4 is on output bus in modes 0, 1, and 2 */ + if (mode < 3) + pOutBuf = pBuffer; + else + pOutBuf = pTempBuffer; + + /* operator 4 is modulated in modes 2, 4, and 5 */ + if ((mode == 2) || (mode == 4) || (mode == 5)) + pMod = pTempBuffer; + else + pMod = 0; + + /* operator 4 is in mix mode in modes 0 and 1 */ + mix = (mode < 2); + + if (p->flags & FLAG_FM_ENG_VOICE_OP4_NOISE) + { + FM_NoiseOperator( + p->oper + 3, + numSamplesToAdd, + pOutBuf, + mix, + pFrame->gain[3], + 0, + 0); + } + else + { + FM_Operator( + p->oper + 3, + numSamplesToAdd, + pOutBuf, + pMod, + mix, + pFrame->gain[3], + pFrame->pitch[3], + 0, + 0); + } + + /* operator 1 is on output bus in mode 0 */ + if (mode == 0) + pOutBuf = pBuffer; + else + pOutBuf = pTempBuffer; + + /* operator 1 is modulated in modes 3 and 4 */ + if ((mode == 3) || (mode == 4)) + pMod = pTempBuffer; + else + pMod = 0; + + /* operator 1 is in mix mode in modes 0 and 5 */ + mix = ((mode == 0) || (mode == 5)); + + if (p->flags & FLAG_FM_ENG_VOICE_OP1_NOISE) + { + FM_NoiseOperator( + p->oper, + numSamplesToAdd, + pOutBuf, + mix, + pFrame->gain[0], + feedback1, + &p->op1Out); + } + else + { + FM_Operator( + p->oper, + numSamplesToAdd, + pOutBuf, + pMod, + mix, + pFrame->gain[0], + pFrame->pitch[0], + feedback1, + &p->op1Out); + } + + /* operator 2 is modulated in all modes except 0 */ + if (mode != 0) + pMod = pTempBuffer; + else + pMod = 0; + + /* operator 1 is in mix mode in modes 0 -3 */ + mix = (mode < 4); + + if (p->flags & FLAG_FM_ENG_VOICE_OP2_NOISE) + { + FM_NoiseOperator( + p->oper + 1, + numSamplesToAdd, + pBuffer, + mix, + pFrame->gain[1], + 0, + 0); + } + else + { + FM_Operator( + p->oper + 1, + numSamplesToAdd, + pBuffer, + pMod, + mix, + pFrame->gain[1], + pFrame->pitch[1], + 0, + 0); + } + + /* mix voice output to synthesizer output buffer */ + FM_SynthMixVoice(p, pFrame->voiceGain, numSamplesToAdd, pBuffer, pMixBuffer); +} + +/*---------------------------------------------------------------------------- + * FM_SynthMixVoice() + *---------------------------------------------------------------------------- + * Purpose: + * Mixes the voice output buffer into the final mix using an anti-zipper + * filter. + * + * Inputs: + * nNumSamplesToAdd - number of samples to synthesize + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void FM_SynthMixVoice(S_FM_ENG_VOICE *p, EAS_U16 nGainTarget, EAS_I32 numSamplesToAdd, EAS_PCM *pInputBuffer, EAS_I32 *pBuffer) +{ + EAS_I32 nGain; + EAS_I32 nGainInc; + EAS_I32 nTemp; + + /* restore previous gain */ + /*lint -e{703} */ + nGain = (EAS_I32) p->voiceGain << 16; + + /* calculate gain increment */ + /*lint -e{703} */ + nGainInc = ((EAS_I32) nGainTarget - (EAS_I32) p->voiceGain) << (16 - SYNTH_UPDATE_PERIOD_IN_BITS); + + /* mix the output buffer */ + while (numSamplesToAdd--) + { + /* output gain calculation */ + nTemp = *pInputBuffer++; + + /* sum to output buffer */ +#if (NUM_OUTPUT_CHANNELS == 2) + + /*lint -e{704} */ + nTemp = ((EAS_I32) nTemp * (nGain >> 16)) >> FM_GAIN_SHIFT; + + /*lint -e{704} */ + { + EAS_I32 nTemp2; + nTemp = nTemp >> FM_STEREO_PRE_GAIN_SHIFT; + nTemp2 = (nTemp * p->gainLeft) >> FM_STEREO_POST_GAIN_SHIFT; + *pBuffer++ += nTemp2; + nTemp2 = (nTemp * p->gainRight) >> FM_STEREO_POST_GAIN_SHIFT; + *pBuffer++ += nTemp2; + } +#else + /*lint -e{704} */ + nTemp = ((EAS_I32) nTemp * (nGain >> 16)) >> FM_MONO_GAIN_SHIFT; + *pBuffer++ += nTemp; +#endif + + /* increment gain for anti-zipper filter */ + nGain += nGainInc; + } + + /* save gain */ + p->voiceGain = nGainTarget; +} + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_fmengine.h b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_fmengine.h new file mode 100755 index 0000000..dd248f8 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_fmengine.h @@ -0,0 +1,121 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_fmengine.h + * + * Contents and purpose: + * Declarations, interfaces, and prototypes for FM synthesize low-level. + * + * Copyright Sonic Network Inc. 2004 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 664 $ + * $Date: 2007-04-25 13:11:22 -0700 (Wed, 25 Apr 2007) $ + *---------------------------------------------------------------------------- +*/ + +/* sentinel */ +#ifndef _FMENGINE_H +#define _FMENGINE_H + +/* check for split architecture */ +#if defined (EAS_SPLIT_HYBRID_SYNTH) || defined(EAS_SPLIT_FM_SYNTH) +#define FM_OFFBOARD +#endif + +/* output level to mix buffer (3 = -24dB) */ +#define FM_GAIN_SHIFT 3 +#define FM_MONO_GAIN_SHIFT 9 + +/* voice output level for stereo 15 = +6dB */ +#define FM_STEREO_PRE_GAIN_SHIFT 11 +#define FM_STEREO_POST_GAIN_SHIFT 10 + +/* modulator input level shift (21 = -30dB) */ +#define FM_MODULATOR_INPUT_SHIFT 21 + +/* feedback control level shift (7 = 0dB) */ +#define FM_FEEDBACK_SHIFT 7 + +/* synth final output level */ +#define SYNTH_POST_GAIN_SHIFT 14 + +/* LFO modulation to gain control */ +#define FM_LFO_GAIN_SHIFT 12 + +/* sine table is always a power of 2 - saves cycles in inner loop */ +#define SINE_TABLE_SIZE_IN_BITS 11 +#define SINE_TABLE_SIZE 2048 + +/* operator structure for FM engine */ +typedef struct +{ + EAS_U32 phase; /* current waveform phase */ + EAS_U16 gain; /* current internal gain */ + EAS_U16 outputGain; /* current output gain */ +} S_FM_ENG_OPER; + +typedef struct +{ + S_FM_ENG_OPER oper[4]; /* operator data */ + EAS_I16 op1Out; /* op1 output for feedback loop */ + EAS_I16 op3Out; /* op3 output for feedback loop */ + EAS_U16 voiceGain; /* LFO + channel parameters */ +#if (NUM_OUTPUT_CHANNELS == 2) + EAS_U16 gainLeft; /* left gain multiplier */ + EAS_U16 gainRight; /* right gain multiplier */ +#endif + EAS_U8 flags; /* mode bits and noise waveform flags */ + EAS_U8 feedback; /* feedback for Op1 and Op3 */ +} S_FM_ENG_VOICE; + +typedef struct +{ + EAS_U16 gain[4]; /* initial operator gain value */ + EAS_U16 outputGain[4]; /* initial operator output gain value */ + EAS_U16 voiceGain; /* initial voice gain */ + EAS_U8 flags; /* mode bits and noise waveform flags */ + EAS_U8 feedback; /* feedback for Op1 and Op3 */ +#if (NUM_OUTPUT_CHANNELS == 2) + EAS_I8 pan; /* pan value +/-64 */ +#endif +} S_FM_VOICE_CONFIG; + +typedef struct +{ + EAS_U16 gain[4]; /* new operator gain value */ + EAS_I16 pitch[4]; /* new pitch value */ + EAS_U16 voiceGain; /* new voice gain */ +} S_FM_VOICE_FRAME; + +/* bit definitions for S_FM_ENG_VOICE.flags */ +#define FLAG_FM_ENG_VOICE_OP1_NOISE 0x10 /* operator 1 source is PRNG */ +#define FLAG_FM_ENG_VOICE_OP2_NOISE 0x20 /* operator 2 source is PRNG */ +#define FLAG_FM_ENG_VOICE_OP3_NOISE 0x40 /* operator 3 source is PRNG */ +#define FLAG_FM_ENG_VOICE_OP4_NOISE 0x80 /* operator 4 source is PRNG */ + +#ifdef FM_OFFBOARD +extern EAS_BOOL FM_StartFrame (EAS_FRAME_BUFFER_HANDLE pFrameBuffer); +extern EAS_BOOL FM_EndFrame (EAS_FRAME_BUFFER_HANDLE pFrameBuffe, EAS_I32 *pMixBuffer, EAS_I16 masterGain); +#endif + +/* FM engine prototypes */ +extern void FM_ConfigVoice (EAS_I32 voiceNum, S_FM_VOICE_CONFIG *vCfg, EAS_FRAME_BUFFER_HANDLE pFrameBuffer); +extern void FM_ProcessVoice (EAS_I32 voiceNum, S_FM_VOICE_FRAME *pFrame, EAS_I32 numSamplesToAdd, EAS_PCM *pTempBuffer, EAS_PCM *pBuffer, EAS_I32 *pMixBuffer, EAS_FRAME_BUFFER_HANDLE pFrameBuffer); + +#endif +/* #ifndef _FMENGINE_H */ + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_fmsndlib.c b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_fmsndlib.c new file mode 100755 index 0000000..dcde967 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_fmsndlib.c @@ -0,0 +1,1674 @@ +/******************************************************************** + * + * fmsndlib.c + * + * (c) Copyright 2005 Sonic Network, Inc. All Rights Reserved + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Source: C:\Sonic\Source\Gen3.3\FMSynth\GMdblib-3.fml + ********************************************************************/ + + +#include "eas_data.h" + +/* begin region data */ +/*lint -e{651} lint complains about unnecessary brackets */ +const S_FM_REGION regions[] = +{ + + /* Region 0 */ + { + 0x8005, 0, 127, 0, 255, 8, 0, + 514, 239, 47, 97, 0, 184, 3, + 1, 244, 89, 114, 0, 248, 2, + 3370, 244, 49, 76, 40, 192, 2, + -1, 227, 97, 51, 160, 212, 2 + }, + + /* Region 1 */ + { + 0x8005, 0, 127, 160, 255, 8, 0, + 2514, 223, 95, 72, 0, 176, 3, + 1, 244, 73, 145, 0, 244, 2, + 3600, 245, 81, 198, 40, 192, 2, + 3, 246, 81, 163, 108, 212, 2 + }, + + /* Region 2 */ + { + 0x8005, 0, 127, 160, 255, 119, 0, + 0, 216, 79, 72, 0, 216, 2, + 2, 244, 73, 145, 0, 244, 2, + 3370, 247, 33, 182, 60, 204, 2, + 1200, 246, 65, 163, 108, 204, 2 + }, + + /* Region 3 */ + { + 0x8005, 0, 127, 160, 255, 1, 0, + 3369, 248, 65, 71, 40, 208, 2, + -3, 245, 88, 113, 0, 244, 2, + 2784, 225, 65, 133, 80, 192, 2, + 3, 241, 81, 113, 80, 216, 2 + }, + + /* Region 4 */ + { + 0x8002, 0, 127, 0, 255, 128, 0, + 0, 229, 155, 183, 0, 228, 2, + -3, 243, 90, 81, 0, 244, 2, + 4800, 248, 109, 180, 36, 192, 2, + 3, 245, 90, 85, 16, 244, 2 + }, + + /* Region 5 */ + { + 0x8002, 0, 127, 9, 96, 192, 0, + 1200, 229, 157, 180, 0, 216, 2, + -3, 244, 90, 81, 0, 244, 2, + 1902, 255, 111, 182, 80, 208, 2, + 3, 246, 92, 83, 0, 244, 2 + }, + + /* Region 6 */ + { + 0x8002, 0, 127, 0, 255, 154, 0, + 3102, 244, 63, 102, 228, 228, 2, + 1200, 247, 93, 97, 0, 236, 2, + 1902, 255, 63, 98, 156, 220, 2, + 1200, 244, 92, 98, 0, 236, 2 + }, + + /* Region 7 */ + { + 0x8005, 0, 127, 0, 255, 202, 0, + 0, 251, 131, 19, 216, 220, 2, + 1201, 247, 62, 113, 0, 240, 2, + 0, 243, 154, 36, 240, 224, 2, + 2784, 250, 61, 36, 240, 208, 2 + }, + + /* Region 8 */ + { + 0x8001, 0, 127, 0, 255, 80, 0, + -1, 213, 191, 183, 0, 204, 2, + 1, 245, 154, 129, 0, 244, 2, + 3831, 252, 159, 100, 0, 200, 2, + 1197, 246, 91, 182, 0, 244, 2 + }, + + /* Region 9 */ + { + 0x8002, 0, 127, 48, 80, 21, 0, + 2982, 255, 43, 96, 0, 196, 3, + 3, 247, 71, 130, 0, 244, 2, + 3358, 253, 40, 98, 144, 208, 2, + -2, 246, 70, 130, 0, 236, 2 + }, + + /* Region 10 */ + { + 0x8002, 0, 127, 48, 80, 26, 0, + 3096, 249, 72, 100, 0, 208, 2, + 2185, 249, 102, 130, 0, 240, 2, + 3386, 247, 66, 100, 144, 212, 2, + -2, 247, 102, 130, 0, 240, 2 + }, + + /* Region 11 */ + { + 0x8002, 0, 127, 92, 67, 21, 0, + 2982, 255, 27, 146, 0, 200, 3, + 3, 246, 68, 146, 0, 240, 2, + 3358, 250, 149, 116, 144, 208, 2, + -3, 245, 68, 146, 0, 240, 0 + }, + + /* Region 12 */ + { + 0x8002, 0, 127, 0, 67, 0, 0, + 1500, 239, 60, 151, 0, 220, 2, + 0, 247, 76, 146, 0, 240, 2, + 2398, 234, 156, 151, 0, 212, 2, + 0, 246, 105, 146, 0, 244, 2 + }, + + /* Region 13 */ + { + 0x8002, 0, 127, 0, 67, 0, 0, + 2500, 255, 60, 151, 0, 220, 2, + 0, 249, 92, 146, 0, 244, 2, + 3369, 250, 156, 151, 0, 196, 2, + 0, 248, 89, 146, 0, 244, 2 + }, + + /* Region 14 */ + { + 0x8005, 0, 127, 160, 255, 0, 0, + 2300, 229, 112, 49, 0, 208, 2, + -3, 247, 67, 50, 0, 248, 2, + 1074, 255, 41, 49, 0, 196, 2, + 686, 240, 97, 18, 0, 196, 2 + }, + + /* Region 15 */ + { + 0x8005, 0, 127, 160, 255, 219, 0, + 3369, 255, 65, 70, 40, 216, 2, + 1, 246, 72, 113, 0, 240, 2, + 1902, 225, 33, 129, 80, 204, 2, + 2400, 225, 97, 113, 80, 200, 2 + }, + + /* Region 16 */ + { + 0x8003, 0, 127, 32, 48, 151, 0, + 1201, 215, 35, 66, 252, 208, 0, + -9581, 254, 63, 177, 240, 240, 3, + 1902, 248, 47, 64, 112, 244, 2, + 0, 247, 35, 66, 208, 212, 2 + }, + + /* Region 17 */ + { + 0x8001, 0, 127, 0, 255, 153, 0, + 1, 252, 31, 3, 244, 196, 2, + -1, 208, 31, 4, 248, 244, 2, + 1205, 209, 31, 4, 248, 236, 2, + 1899, 250, 31, 32, 0, 240, 2 + }, + + /* Region 18 */ + { + 0x8002, 0, 127, 32, 49, 201, 0, + 1, 220, 47, 3, 244, 220, 0, + -10000, 208, 63, 1, 248, 240, 3, + 1586, 255, 47, 3, 188, 216, 2, + -1, 202, 63, 32, 80, 232, 2 + }, + + /* Region 19 */ + { + 0x8001, 0, 127, 0, 143, 29, 0, + -1200, 223, 64, 0, 252, 216, 2, + 1200, 96, 41, 35, 248, 240, 2, + 1200, 143, 41, 64, 252, 224, 2, + 3102, 161, 41, 96, 248, 216, 2 + }, + + /* Region 20 */ + { + 0x8002, 0, 127, 0, 143, 34, 0, + -1200, 133, 79, 1, 252, 212, 2, + 1201, 112, 46, 34, 248, 232, 2, + 0, 116, 79, 65, 252, 200, 2, + 1900, 161, 46, 98, 248, 232, 2 + }, + + /* Region 21 */ + { + 0x8002, 0, 127, 0, 143, 187, 0, + 1202, 80, 74, 1, 252, 216, 2, + 2402, 112, 46, 34, 248, 232, 2, + 0, 99, 78, 97, 184, 216, 2, + 1899, 81, 46, 98, 236, 232, 2 + }, + + /* Region 22 */ + { + 0x8005, 0, 127, 22, 141, 34, 0, + 2787, 176, 79, 4, 252, 208, 2, + 2785, 144, 45, 34, 248, 236, 2, + 3369, 83, 77, 100, 184, 172, 2, + 1902, 102, 45, 100, 172, 212, 0 + }, + + /* Region 23 */ + { + 0x8002, 0, 127, 0, 143, 135, 0, + 1900, 112, 79, 3, 252, 220, 2, + 2400, 128, 45, 34, 248, 232, 2, + 1200, 115, 77, 98, 184, 220, 2, + 1904, 97, 45, 98, 236, 232, 2 + }, + + /* Region 24 */ + { + 0x8005, 0, 127, 0, 255, 157, 0, + 1200, 244, 54, 4, 20, 200, 2, + 0, 245, 92, 130, 0, 244, 2, + 3802, 247, 68, 21, 0, 196, 2, + 1, 245, 43, 114, 0, 204, 2 + }, + + /* Region 25 */ + { + 0x8005, 0, 127, 0, 128, 83, 0, + 0, 244, 51, 4, 200, 204, 0, + 0, 247, 108, 129, 0, 248, 0, + 2786, 243, 31, 70, 200, 220, 0, + 1902, 246, 44, 113, 12, 188, 0 + }, + + /* Region 26 */ + { + 0x8005, 0, 127, 0, 128, 61, 0, + 0, 246, 51, 97, 76, 204, 0, + 0, 244, 60, 97, 0, 240, 0, + 1786, 255, 31, 64, 0, 180, 0, + 1200, 247, 60, 97, 12, 204, 0 + }, + + /* Region 27 */ + { + 0x8005, 0, 127, 0, 128, 153, 0, + -2, 243, 53, 99, 96, 200, 0, + 0, 243, 60, 97, 0, 240, 0, + 3983, 247, 63, 100, 24, 204, 0, + 2, 242, 53, 99, 52, 212, 0 + }, + + /* Region 28 */ + { + 0x8005, 0, 127, 0, 128, 205, 0, + -2, 244, 47, 97, 20, 208, 0, + 0, 252, 75, 193, 0, 248, 0, + 0, 254, 63, 98, 132, 224, 0, + 2786, 251, 63, 98, 52, 192, 0 + }, + + /* Region 29 */ + { + 0x8005, 0, 127, 0, 128, 221, 0, + -1, 208, 191, 99, 220, 224, 0, + 1200, 243, 92, 97, 0, 244, 0, + 3984, 212, 11, 96, 168, 196, 0, + 1, 242, 127, 98, 108, 204, 0 + }, + + /* Region 30 */ + { + 0x8005, 0, 127, 0, 128, 174, 0, + -3, 212, 207, 99, 0, 228, 0, + 1902, 241, 108, 97, 0, 248, 0, + 3805, 212, 59, 98, 0, 220, 0, + 1902, 146, 107, 98, 144, 196, 0 + }, + + /* Region 31 */ + { + 0x8009, 0, 127, 0, 255, 128, 0, + 1206, 239, 43, 69, 0, 216, 2, + 4, 254, 42, 66, 0, 244, 2, + 702, 88, 55, 66, 0, 204, 2, + -4, 71, 55, 66, 0, 240, 2 + }, + + /* Region 32 */ + { + 0x8005, 0, 127, 0, 255, 85, 0, + 500, 239, 95, 82, 0, 184, 3, + 0, 248, 73, 132, 0, 252, 2, + 2786, 203, 59, 130, 0, 176, 2, + 0, 216, 42, 100, 0, 208, 2 + }, + + /* Region 33 */ + { + 0x8005, 0, 127, 0, 128, 73, 0, + 1, 229, 54, 131, 160, 208, 0, + -1, 244, 62, 97, 0, 248, 0, + 3986, 227, 127, 69, 140, 184, 0, + 1201, 249, 92, 114, 0, 204, 0 + }, + + /* Region 34 */ + { + 0x8005, 0, 127, 0, 128, 73, 0, + 1, 225, 54, 100, 200, 212, 0, + -1, 244, 94, 97, 0, 248, 0, + 3986, 249, 127, 88, 112, 188, 0, + 1201, 249, 92, 85, 52, 208, 0 + }, + + /* Region 35 */ + { + 0x8005, 0, 127, 0, 128, 188, 0, + -3, 198, 92, 179, 28, 212, 0, + 0, 243, 90, 145, 0, 248, 0, + 1901, 215, 95, 69, 28, 196, 0, + 3, 84, 108, 196, 32, 208, 0 + }, + + /* Region 36 */ + { + 0x8005, 0, 127, 0, 136, 6, 0, + 0, 226, 99, 36, 224, 216, 0, + 1902, 248, 78, 33, 0, 252, 0, + 3369, 239, 250, 33, 0, 204, 0, + 0, 230, 253, 33, 0, 208, 0 + }, + + /* Region 37 */ + { + 0x8005, 0, 127, 0, 136, 195, 0, + 0, 245, 99, 36, 152, 208, 0, + 1200, 248, 78, 33, 0, 252, 0, + 3369, 246, 250, 33, 0, 216, 0, + 0, 246, 61, 33, 0, 180, 0 + }, + + /* Region 38 */ + { + 0x8002, 0, 127, 0, 133, 221, 0, + 1, 244, 67, 35, 80, 220, 0, + 3, 246, 94, 33, 0, 244, 0, + -1, 245, 70, 35, 80, 236, 2, + -3, 246, 63, 33, 0, 236, 2 + }, + + /* Region 39 */ + { + 0x8002, 0, 127, 0, 133, 220, 0, + 0, 114, 51, 34, 132, 208, 0, + 3, 214, 62, 33, 0, 248, 0, + 0, 85, 54, 34, 44, 224, 2, + -3, 214, 63, 33, 0, 236, 2 + }, + + /* Region 40 */ + { + 0x8005, 0, 127, 48, 142, 187, 0, + -1, 33, 22, 33, 200, 208, 0, + 0, 81, 105, 33, 220, 240, 0, + 2786, 245, 19, 50, 208, 192, 0, + 1, 245, 21, 82, 200, 220, 0 + }, + + /* Region 41 */ + { + 0x8005, 0, 127, 48, 126, 103, 0, + -1, 193, 22, 33, 228, 212, 0, + 0, 81, 105, 33, 220, 244, 0, + 0, 245, 19, 50, 216, 228, 0, + 1200, 245, 19, 82, 200, 188, 0 + }, + + /* Region 42 */ + { + 0x8005, 0, 127, 16, 126, 202, 0, + -1, 49, 24, 41, 200, 212, 0, + 0, 81, 71, 49, 220, 244, 0, + 3371, 243, 19, 36, 232, 192, 0, + 1, 242, 24, 36, 220, 212, 0 + }, + + /* Region 43 */ + { + 0x8005, 0, 127, 16, 124, 205, 0, + 0, 129, 24, 49, 208, 200, 0, + 0, 67, 102, 81, 224, 244, 0, + 3804, 246, 23, 36, 160, 196, 0, + 1200, 244, 24, 35, 208, 200, 0 + }, + + /* Region 44 */ + { + 0x8005, 0, 127, 48, 144, 208, 0, + -3, 209, 22, 33, 200, 204, 2, + 0, 81, 89, 33, 220, 240, 2, + -5000, 208, 6, 33, 244, 188, 3, + 3, 97, 89, 33, 224, 200, 0 + }, + + /* Region 45 */ + { + 0x8005, 0, 127, 0, 255, 186, 0, + 500, 223, 95, 0, 0, 192, 3, + 0, 247, 89, 100, 0, 248, 2, + 3369, 255, 59, 168, 0, 212, 2, + 0, 216, 42, 97, 0, 212, 2 + }, + + /* Region 46 */ + { + 0x8002, 0, 127, 0, 255, 221, 0, + 1206, 235, 70, 69, 0, 216, 2, + 4, 248, 84, 66, 0, 244, 2, + 1902, 247, 52, 137, 80, 216, 2, + -4, 245, 84, 131, 0, 240, 2 + }, + + /* Region 47 */ + { + 0x8005, 0, 127, 0, 255, 105, 0, + 387, 231, 115, 34, 4, 216, 2, + 0, 248, 37, 65, 0, 252, 2, + 3308, 248, 117, 34, 8, 200, 2, + 1900, 213, 82, 50, 0, 192, 2 + }, + + /* Region 48 */ + { + 0x8002, 0, 127, 32, 160, 221, 0, + -7, 209, 22, 33, 200, 204, 2, + -7, 81, 73, 33, 220, 244, 0, + 7, 209, 22, 33, 200, 208, 0, + 7, 97, 73, 33, 224, 244, 2 + }, + + /* Region 49 */ + { + 0x8002, 0, 127, 64, 128, 189, 0, + -2, 209, 54, 32, 224, 216, 2, + -7726, 97, 105, 33, 220, 240, 3, + 1902, 209, 54, 34, 216, 208, 0, + 2, 81, 105, 33, 224, 236, 0 + }, + + /* Region 50 */ + { + 0x8002, 0, 127, 80, 144, 206, 0, + -3, 179, 38, 33, 160, 220, 2, + -7726, 81, 69, 34, 220, 244, 3, + 3, 193, 38, 33, 240, 212, 0, + -8000, 65, 69, 34, 224, 236, 3 + }, + + /* Region 51 */ + { + 0x8005, 0, 127, 96, 128, 204, 0, + -3, 97, 38, 33, 180, 216, 0, + 0, 81, 69, 34, 220, 240, 2, + 3369, 145, 38, 33, 240, 196, 2, + -13190, 65, 69, 34, 240, 200, 3 + }, + + /* Region 52 */ + { + 0x8002, 0, 127, 64, 128, 108, 0, + -3, 193, 37, 35, 236, 208, 0, + 2394, 97, 90, 36, 224, 232, 2, + 3, 65, 40, 35, 236, 204, 2, + 1203, 97, 89, 33, 224, 240, 0 + }, + + /* Region 53 */ + { + 0x8005, 0, 127, 128, 128, 122, 0, + 0, 193, 21, 34, 236, 188, 0, + 3, 97, 74, 36, 224, 248, 2, + 1906, 251, 24, 32, 96, 192, 3, + 1200, 97, 73, 32, 224, 184, 0 + }, + + /* Region 54 */ + { + 0x8002, 0, 127, 64, 133, 135, 0, + 0, 194, 25, 35, 120, 200, 2, + 0, 97, 75, 36, 224, 240, 0, + 2906, 254, 28, 48, 0, 184, 3, + 0, 216, 75, 80, 204, 240, 2 + }, + + /* Region 55 */ + { + 0x8009, 0, 127, 208, 64, 255, 0, + 475, 249, 16, 32, 252, 240, 2, + 702, 248, 71, 32, 0, 244, 2, + 1136, 232, 27, 32, 216, 248, 0, + 0, 249, 23, 48, 0, 248, 2 + }, + + /* Region 56 */ + { + 0x8005, 0, 127, 0, 132, 233, 0, + 0, 195, 95, 64, 240, 208, 0, + 0, 225, 94, 64, 248, 240, 0, + 0, 254, 127, 0, 4, 196, 4, + 1902, 228, 95, 1, 248, 200, 0 + }, + + /* Region 57 */ + { + 0x8005, 0, 127, 16, 140, 238, 0, + 0, 163, 90, 67, 228, 208, 0, + 0, 209, 77, 65, 248, 240, 0, + 1969, 173, 58, 65, 0, 176, 0, + 0, 210, 61, 52, 204, 220, 0 + }, + + /* Region 58 */ + { + 0x8005, 0, 127, 16, 140, 222, 0, + 0, 119, 74, 67, 160, 212, 0, + 0, 146, 61, 65, 248, 244, 0, + 1900, 137, 58, 65, 100, 196, 0, + 0, 119, 61, 52, 120, 200, 0 + }, + + /* Region 59 */ + { + 0x8005, 0, 127, 16, 135, 219, 0, + 0, 176, 79, 69, 240, 216, 0, + 0, 193, 79, 64, 248, 236, 0, + 0, 178, 123, 54, 92, 228, 0, + 3369, 212, 95, 38, 144, 212, 0 + }, + + /* Region 60 */ + { + 0x8002, 0, 127, 0, 119, 203, 0, + 2, 65, 77, 66, 228, 204, 0, + 2, 161, 74, 64, 240, 240, 0, + -2, 85, 60, 66, 180, 216, 2, + -2, 162, 74, 64, 220, 240, 2 + }, + + /* Region 61 */ + { + 0x8002, 0, 127, 16, 154, 237, 0, + 0, 179, 42, 64, 216, 208, 0, + 0, 209, 61, 64, 248, 244, 0, + -1200, 226, 55, 65, 244, 220, 2, + 1902, 162, 62, 52, 204, 236, 2 + }, + + /* Region 62 */ + { + 0x8002, 0, 127, 48, 119, 221, 0, + 2, 119, 79, 64, 208, 212, 0, + 2, 209, 110, 64, 248, 236, 0, + -2, 84, 79, 64, 136, 212, 2, + -2, 209, 110, 64, 240, 240, 2 + }, + + /* Region 63 */ + { + 0x8002, 0, 127, 32, 135, 221, 0, + 2, 165, 79, 64, 152, 216, 0, + 2, 225, 110, 64, 248, 236, 0, + -2, 132, 79, 64, 72, 224, 2, + -2, 241, 110, 64, 252, 236, 2 + }, + + /* Region 64 */ + { + 0x8005, 0, 127, 17, 127, 190, 0, + 0, 209, 60, 67, 244, 208, 0, + 1200, 145, 94, 65, 248, 244, 2, + 3369, 197, 47, 4, 128, 192, 0, + 1902, 167, 94, 6, 200, 200, 0 + }, + + /* Region 65 */ + { + 0x8005, 0, 127, 17, 143, 190, 0, + 0, 209, 60, 67, 244, 216, 0, + 1902, 145, 62, 65, 248, 240, 2, + 3369, 197, 47, 4, 128, 196, 0, + 2400, 167, 94, 6, 200, 212, 2 + }, + + /* Region 66 */ + { + 0x8005, 0, 127, 17, 143, 190, 0, + 0, 209, 60, 67, 244, 208, 0, + 1902, 145, 62, 65, 248, 240, 2, + 3369, 197, 47, 4, 128, 192, 0, + 1902, 167, 94, 6, 200, 216, 2 + }, + + /* Region 67 */ + { + 0x8005, 0, 127, 17, 125, 190, 0, + 0, 114, 109, 67, 244, 224, 0, + 1902, 166, 93, 97, 200, 240, 0, + 2786, 165, 95, 52, 160, 200, 0, + 2400, 173, 78, 54, 240, 212, 2 + }, + + /* Region 68 */ + { + 0x8002, 0, 127, 16, 140, 205, 0, + 0, 211, 55, 66, 244, 208, 0, + 1902, 193, 93, 65, 248, 240, 0, + 0, 204, 47, 4, 244, 216, 0, + 3600, 183, 95, 6, 160, 232, 0 + }, + + /* Region 69 */ + { + 0x8002, 0, 127, 16, 126, 222, 0, + 0, 243, 36, 66, 172, 200, 0, + 1200, 193, 110, 67, 248, 244, 0, + 0, 215, 33, 2, 232, 212, 0, + 3369, 178, 63, 6, 184, 240, 0 + }, + + /* Region 70 */ + { + 0x8002, 0, 127, 16, 140, 221, 0, + 1200, 213, 61, 66, 136, 200, 0, + 1902, 193, 93, 68, 248, 240, 0, + 0, 197, 47, 2, 228, 216, 0, + 3369, 183, 95, 2, 160, 236, 0 + }, + + /* Region 71 */ + { + 0x8002, 0, 127, 16, 124, 201, 0, + 1200, 195, 55, 68, 240, 208, 0, + 0, 209, 76, 65, 248, 236, 0, + 1902, 147, 47, 19, 208, 212, 0, + 0, 183, 79, 22, 156, 228, 0 + }, + + /* Region 72 */ + { + 0x8005, 0, 127, 32, 110, 234, 0, + 500, 237, 60, 68, 0, 192, 1, + 1, 161, 93, 65, 248, 240, 2, + 3365, 154, 47, 16, 48, 180, 6, + 1200, 165, 92, 52, 160, 212, 2 + }, + + /* Region 73 */ + { + 0x8005, 0, 127, 32, 142, 200, 0, + 0, 193, 60, 68, 248, 200, 0, + 1, 129, 61, 65, 248, 240, 2, + 3365, 154, 47, 16, 68, 184, 6, + 1200, 169, 92, 52, 160, 204, 2 + }, + + /* Region 74 */ + { + 0x8003, 0, 127, 32, 135, 36, 0, + 1199, 165, 79, 66, 152, 192, 2, + -3, 145, 110, 64, 248, 240, 2, + 0, 199, 79, 66, 44, 236, 2, + 2986, 136, 110, 67, 100, 196, 2 + }, + + /* Region 75 */ + { + 0x8005, 0, 127, 32, 190, 71, 0, + 868, 202, 140, 16, 24, 188, 2, + 0, 176, 77, 65, 248, 240, 2, + 3750, 169, 127, 16, 36, 228, 6, + 2400, 195, 60, 17, 232, 172, 2 + }, + + /* Region 76 */ + { + 0x8005, 0, 127, 224, 16, 123, 0, + 275, 202, 14, 2, 44, 196, 2, + 0, 165, 89, 65, 56, 244, 2, + 0, 255, 12, 2, 64, 216, 6, + 963, 169, 14, 4, 40, 196, 2 + }, + + /* Region 77 */ + { + 0x8012, 0, 127, 192, 128, 100, 0, + 1500, 202, 79, 68, 76, 204, 2, + -2, 97, 26, 64, 248, 232, 2, + 1588, 202, 223, 69, 4, 220, 0, + 3, 188, 121, 67, 48, 252, 2 + }, + + /* Region 78 */ + { + 0x8002, 0, 127, 112, 140, 205, 0, + 0, 68, 47, 66, 60, 176, 2, + -2, 113, 94, 64, 248, 236, 0, + 5000, 121, 47, 64, 32, 168, 7, + 3, 136, 94, 64, 0, 236, 0 + }, + + /* Region 79 */ + { + 0x8003, 0, 127, 32, 135, 33, 0, + 1199, 197, 79, 66, 152, 184, 2, + 0, 161, 110, 64, 248, 240, 2, + 0, 199, 79, 66, 44, 236, 2, + 2400, 255, 110, 65, 36, 208, 6 + }, + + /* Region 80 */ + { + 0x8002, 0, 127, 0, 192, 170, 0, + 1199, 192, 77, 33, 200, 212, 0, + 0, 209, 107, 33, 232, 240, 0, + 1201, 80, 77, 33, 200, 212, 0, + 0, 241, 107, 33, 232, 240, 0 + }, + + /* Region 81 */ + { + 0x8002, 0, 127, 0, 192, 221, 0, + -1, 192, 45, 33, 200, 212, 0, + -1, 209, 107, 33, 232, 244, 0, + 1, 80, 45, 33, 200, 212, 0, + 1, 241, 107, 33, 232, 244, 0 + }, + + /* Region 82 */ + { + 0x8005, 0, 127, 0, 112, 255, 0, + 4750, 221, 45, 34, 48, 172, 4, + -10000, 161, 107, 33, 200, 244, 3, + 2204, 137, 45, 37, 64, 184, 0, + -2, 211, 107, 33, 160, 208, 0 + }, + + /* Region 83 */ + { + 0x8005, 0, 127, 16, 127, 238, 0, + 2, 248, 45, 32, 204, 208, 0, + -9500, 241, 107, 33, 200, 240, 3, + 3369, 186, 45, 38, 24, 208, 0, + -2, 211, 107, 32, 220, 212, 0 + }, + + /* Region 84 */ + { + 0x8005, 0, 127, 0, 128, 221, 0, + -1, 192, 191, 99, 220, 216, 0, + 1200, 243, 92, 97, 0, 244, 0, + 3984, 200, 11, 96, 168, 192, 0, + 1, 194, 127, 98, 108, 200, 0 + }, + + /* Region 85 */ + { + 0x8002, 0, 127, 128, 128, 111, 0, + 1, 194, 25, 35, 120, 204, 2, + -9750, 193, 107, 36, 224, 244, 3, + 3906, 255, 28, 50, 12, 188, 3, + -1, 216, 107, 80, 204, 240, 2 + }, + + /* Region 86 */ + { + 0x8002, 0, 127, 32, 134, 222, 0, + 0, 195, 52, 33, 200, 208, 0, + 0, 177, 90, 33, 232, 240, 2, + 702, 195, 52, 33, 200, 208, 2, + 702, 177, 90, 34, 232, 240, 2 + }, + + /* Region 87 */ + { + 0x8002, 0, 127, 32, 134, 205, 0, + 0, 198, 75, 36, 120, 220, 2, + 0, 225, 78, 52, 40, 244, 2, + 0, 246, 47, 32, 220, 208, 2, + 1902, 241, 124, 32, 240, 236, 2 + }, + + /* Region 88 */ + { + 0x8003, 0, 127, 32, 120, 14, 0, + 3600, 244, 67, 34, 88, 208, 0, + 3, 194, 84, 33, 84, 240, 2, + -3, 194, 84, 33, 172, 236, 2, + 902, 254, 114, 34, 0, 224, 3 + }, + + /* Region 89 */ + { + 0x8002, 0, 127, 64, 169, 170, 0, + -3, 83, 69, 34, 184, 212, 0, + -7500, 50, 69, 33, 176, 244, 3, + 3, 81, 69, 34, 212, 212, 2, + -8500, 66, 69, 33, 176, 244, 3 + }, + + /* Region 90 */ + { + 0x8002, 0, 127, 64, 120, 221, 0, + -2, 82, 69, 34, 244, 216, 0, + 0, 145, 102, 33, 228, 240, 0, + 2, 81, 69, 34, 244, 208, 2, + 0, 145, 102, 33, 224, 240, 2 + }, + + /* Region 91 */ + { + 0x8003, 0, 127, 32, 138, 14, 0, + 2400, 148, 67, 34, 176, 200, 0, + 3, 194, 85, 33, 220, 236, 2, + -3, 194, 69, 33, 220, 236, 2, + 1905, 254, 114, 34, 48, 224, 2 + }, + + /* Region 92 */ + { + 0x8002, 0, 127, 82, 67, 71, 0, + 2982, 228, 22, 146, 88, 192, 3, + 3, 102, 84, 146, 196, 240, 2, + 3358, 50, 149, 116, 144, 208, 2, + -3, 85, 84, 146, 120, 240, 0 + }, + + /* Region 93 */ + { + 0x8005, 0, 127, 48, 126, 219, 0, + -3, 49, 19, 33, 120, 200, 0, + 0, 81, 70, 33, 220, 240, 0, + 3804, 242, 18, 50, 200, 200, 0, + 1203, 82, 19, 82, 200, 176, 0 + }, + + /* Region 94 */ + { + 0x8003, 0, 127, 32, 138, 13, 0, + 2786, 116, 67, 34, 204, 184, 0, + 1902, 114, 69, 33, 192, 232, 2, + -3, 178, 69, 33, 188, 232, 2, + 3804, 254, 82, 34, 164, 228, 2 + }, + + /* Region 95 */ + { + 0x8002, 0, 127, 48, 135, 238, 0, + -2, 34, 85, 34, 184, 224, 0, + 1, 113, 70, 33, 228, 236, 0, + 2, 19, 85, 34, 156, 224, 2, + -1, 129, 70, 33, 224, 236, 2 + }, + + /* Region 96 */ + { + 0x8012, 0, 127, 240, 112, 221, 0, + 3369, 213, 69, 32, 0, 204, 0, + 0, 193, 70, 33, 112, 232, 2, + 0, 145, 69, 34, 244, 208, 2, + -9000, 145, 70, 33, 224, 236, 3 + }, + + /* Region 97 */ + { + 0x8002, 0, 127, 96, 122, 168, 0, + -1, 99, 51, 33, 200, 208, 0, + -8500, 81, 83, 33, 232, 240, 3, + 702, 99, 52, 33, 200, 208, 2, + -9500, 65, 83, 34, 224, 240, 3 + }, + + /* Region 98 */ + { + 0x8002, 0, 127, 0, 67, 0, 0, + 1500, 217, 55, 151, 20, 224, 2, + 3, 231, 70, 146, 88, 220, 2, + 2369, 115, 148, 151, 32, 196, 2, + -3, 118, 36, 146, 64, 244, 2 + }, + + /* Region 99 */ + { + 0x8002, 0, 127, 64, 169, 204, 0, + -3, 228, 69, 34, 148, 220, 0, + -7448, 243, 69, 33, 200, 240, 3, + 3, 81, 68, 34, 212, 212, 2, + -8526, 65, 68, 33, 196, 240, 3 + }, + + /* Region 100 */ + { + 0x8002, 0, 127, 64, 119, 187, 0, + 2786, 228, 22, 146, 176, 192, 0, + 3, 102, 68, 146, 196, 236, 2, + 3369, 178, 149, 116, 176, 208, 2, + -3, 231, 68, 146, 120, 240, 0 + }, + + /* Region 101 */ + { + 0x8002, 0, 127, 240, 144, 239, 0, + -2, 49, 69, 34, 236, 208, 2, + -9000, 113, 102, 33, 228, 236, 3, + 2400, 149, 69, 34, 12, 216, 1, + 0, 145, 102, 33, 224, 236, 2 + }, + + /* Region 102 */ + { + 0x8012, 0, 127, 241, 176, 6, 0, + 1200, 247, 49, 64, 252, 204, 0, + 3804, 246, 101, 32, 0, 232, 2, + 1902, 247, 32, 32, 112, 188, 2, + 0, 228, 84, 32, 0, 240, 2 + }, + + /* Region 103 */ + { + 0x8005, 0, 127, 64, 101, 221, 0, + 1, 194, 68, 97, 196, 200, 2, + -10001, 247, 100, 114, 176, 240, 3, + 3370, 213, 33, 70, 52, 200, 2, + -1, 178, 68, 49, 208, 212, 0 + }, + + /* Region 104 */ + { + 0x8002, 0, 127, 0, 255, 203, 0, + -3, 245, 82, 99, 200, 232, 2, + 2787, 244, 84, 96, 0, 236, 2, + 1198, 133, 81, 100, 196, 220, 2, + 1902, 147, 67, 80, 0, 232, 2 + }, + + /* Region 105 */ + { + 0x8005, 0, 127, 0, 255, 140, 0, + 500, 255, 137, 179, 0, 200, 3, + 1902, 248, 90, 160, 0, 244, 2, + 3804, 245, 57, 35, 164, 204, 2, + 0, 245, 38, 51, 196, 208, 2 + }, + + /* Region 106 */ + { + 0x8005, 0, 127, 0, 255, 72, 0, + 1000, 238, 57, 65, 0, 188, 3, + 1902, 247, 103, 112, 0, 244, 2, + 2786, 250, 36, 81, 68, 212, 2, + 0, 249, 50, 49, 172, 204, 2 + }, + + /* Region 107 */ + { + 0x8005, 0, 127, 16, 119, 72, 0, + 1500, 255, 89, 65, 0, 196, 3, + 2790, 246, 39, 112, 0, 240, 0, + 1905, 246, 36, 81, 168, 208, 0, + 0, 249, 114, 49, 172, 212, 0 + }, + + /* Region 108 */ + { + 0x8005, 0, 127, 0, 255, 237, 0, + 1902, 254, 89, 65, 0, 212, 2, + 0, 248, 87, 112, 0, 240, 2, + 3369, 231, 62, 81, 0, 208, 2, + 3, 245, 118, 49, 96, 196, 2 + }, + + /* Region 109 */ + { + 0x8002, 0, 127, 16, 188, 205, 0, + -2, 179, 47, 50, 244, 224, 2, + 1900, 145, 94, 49, 248, 232, 2, + 3, 210, 46, 2, 244, 208, 2, + 2789, 133, 93, 4, 180, 244, 2 + }, + + /* Region 110 */ + { + 0x8005, 0, 127, 48, 135, 220, 0, + 1901, 162, 25, 35, 144, 208, 0, + 0, 113, 105, 65, 220, 240, 0, + 3369, 233, 88, 51, 120, 212, 0, + 0, 229, 24, 84, 200, 208, 0 + }, + + /* Region 111 */ + { + 0x8002, 0, 127, 112, 32, 190, 0, + 0, 53, 79, 66, 152, 212, 2, + 1200, 53, 75, 64, 136, 244, 2, + 500, 149, 60, 66, 16, 208, 2, + 1902, 200, 78, 64, 0, 248, 0 + }, + + /* Region 112 */ + { + 0x8005, 0, 127, 0, 144, 130, 0, + 2514, 255, 68, 53, 0, 204, 2, + 2400, 247, 133, 48, 0, 240, 2, + 4151, 243, 67, 50, 0, 212, 2, + 3369, 243, 66, 56, 0, 204, 2 + }, + + /* Region 113 */ + { + 0x8005, 0, 127, 0, 255, 0, 0, + 514, 253, 79, 51, 0, 196, 3, + 1905, 252, 89, 51, 0, 244, 2, + 4349, 245, 35, 51, 0, 208, 2, + 1205, 247, 34, 51, 0, 208, 2 + }, + + /* Region 114 */ + { + 0x8005, 0, 127, 0, 255, 0, 0, + 514, 221, 69, 35, 0, 204, 3, + 0, 250, 86, 115, 0, 252, 2, + 1884, 244, 116, 51, 0, 200, 2, + 1208, 210, 35, 51, 0, 208, 2 + }, + + /* Region 115 */ + { + 0x8005, 0, 127, 0, 255, 16, 0, + 514, 222, 85, 163, 0, 192, 3, + 0, 254, 108, 163, 0, 252, 2, + 3800, 255, 143, 160, 0, 176, 2, + 1200, 250, 105, 163, 0, 212, 2 + }, + + /* Region 116 */ + { + 0x8005, 0, 127, 0, 255, 16, 0, + 1514, 249, 101, 163, 0, 204, 3, + -1200, 249, 87, 160, 0, 252, 2, + 0, 235, 143, 160, 0, 204, 2, + 1200, 234, 73, 163, 0, 204, 2 + }, + + /* Region 117 */ + { + 0x8005, 0, 127, 0, 255, 16, 0, + 500, 239, 101, 160, 0, 204, 3, + -1195, 248, 104, 160, 0, 252, 2, + 1898, 252, 72, 163, 0, 216, 2, + 1239, 248, 87, 163, 0, 196, 2 + }, + + /* Region 118 */ + { + 0x8005, 0, 127, 0, 255, 255, 0, + 500, 255, 98, 160, 0, 196, 3, + -1, 249, 105, 160, 0, 252, 2, + 1907, 250, 71, 160, 0, 252, 2, + 1182, 249, 87, 161, 0, 192, 2 + }, + + /* Region 119 */ + { + 0x8005, 0, 127, 0, 0, 100, 0, + 600, 32, 15, 0, 252, 224, 6, + 0, 47, 111, 65, 0, 244, 2, + 1826, 16, 47, 0, 252, 216, 2, + 3551, 240, 47, 0, 252, 212, 2 + }, + + /* Region 120 */ + { + 0x8014, 0, 127, 240, 128, 235, 0, + 1228, 161, 47, 17, 196, 200, 3, + 3000, 123, 75, 17, 0, 240, 2, + 7022, 72, 43, 17, 0, 216, 0, + 4000, 150, 79, 17, 48, 196, 3 + }, + + /* Region 121 */ + { + 0x8005, 0, 127, 224, 16, 86, 0, + 275, 251, 6, 0, 36, 200, 2, + 0, 101, 104, 65, 56, 240, 2, + 0, 240, 6, 0, 252, 208, 6, + 1000, 195, 8, 0, 248, 200, 2 + }, + + /* Region 122 */ + { + 0x8002, 0, 127, 0, 0, 185, 0, + 600, 35, 66, 17, 72, 224, 4, + -13000, 81, 67, 17, 228, 244, 2, + 702, 97, 38, 17, 212, 196, 6, + -14000, 81, 65, 17, 224, 244, 3 + }, + + /* Region 123 */ + { + 0x8012, 0, 127, 240, 112, 237, 0, + -6528, 153, 127, 16, 0, 252, 3, + 1200, 105, 109, 16, 0, 216, 2, + -6022, 179, 139, 17, 0, 248, 3, + 2000, 104, 79, 17, 0, 240, 0 + }, + + /* Region 124 */ + { + 0x8012, 0, 127, 240, 240, 16, 0, + 1914, 240, 64, 160, 240, 208, 2, + 1200, 240, 73, 163, 240, 244, 0, + 1900, 240, 64, 160, 240, 148, 2, + 4151, 240, 73, 163, 240, 244, 0 + }, + + /* Region 125 */ + { + 0x8002, 0, 127, 240, 56, 235, 0, + -5522, 97, 32, 17, 196, 240, 3, + 0, 84, 75, 17, 180, 248, 3, + 702, 65, 38, 17, 224, 212, 6, + -4000, 161, 73, 17, 224, 252, 1 + }, + + /* Region 126 */ + { + 0x8015, 0, 127, 240, 248, 37, 0, + 1050, 243, 0, 0, 252, 224, 7, + 2000, 49, 68, 0, 224, 236, 3, + 350, 240, 0, 0, 252, 216, 1, + 700, 240, 0, 0, 252, 212, 3 + }, + + /* Region 127 */ + { + 0x8015, 0, 127, 240, 248, 37, 0, + 1050, 245, 85, 0, 0, 244, 7, + -5000, 247, 71, 0, 0, 252, 3, + 350, 240, 0, 0, 0, 164, 0, + 700, 32, 0, 0, 0, 252, 2 + }, + + /* Region 128 */ + { + 0x0005, 35, 35, 0, 255, 103, 0, + 3, 215, 68, 65, 0, 204, 2, + -1700, 249, 95, 177, 0, 252, 2, + 5374, 236, 144, 204, 0, 176, 3, + 114, 253, 144, 179, 0, 200, 3 + }, + + /* Region 129 */ + { + 0x0005, 36, 36, 0, 255, 103, 0, + 3, 219, 68, 65, 0, 204, 2, + -1700, 251, 95, 177, 0, 252, 2, + 5374, 255, 144, 204, 0, 176, 3, + 114, 255, 144, 179, 0, 208, 3 + }, + + /* Region 130 */ + { + 0x001a, 37, 37, 240, 128, 216, 0, + 2780, 255, 16, 0, 112, 200, 3, + 3800, 255, 32, 0, 0, 240, 3, + 2501, 251, 48, 0, 48, 240, 3, + 2751, 254, 48, 0, 0, 244, 3 + }, + + /* Region 131 */ + { + 0x000d, 38, 38, 0, 255, 190, 0, + -2000, 239, 48, 128, 0, 236, 3, + -2400, 254, 92, 128, 0, 252, 2, + 3374, 255, 33, 192, 240, 244, 2, + 1000, 255, 49, 176, 240, 204, 2 + }, + + /* Region 132 */ + { + 0x001a, 39, 39, 240, 128, 254, -10, + 5780, 186, 16, 0, 112, 240, 3, + 3800, 254, 32, 0, 0, 248, 3, + 5780, 234, 16, 0, 112, 240, 3, + 4829, 254, 32, 0, 0, 252, 3 + }, + + /* Region 133 */ + { + 0x000d, 40, 40, 0, 255, 203, 0, + 0, 254, 74, 128, 0, 176, 3, + -600, 252, 73, 128, 0, 252, 3, + 3368, 251, 80, 192, 0, 244, 3, + 1200, 254, 64, 176, 0, 208, 3 + }, + + /* Region 134 */ + { + 0x000d, 41, 41, 208, 16, 187, -30, + -600, 247, 128, 0, 0, 204, 1, + -890, 248, 88, 0, 0, 252, 3, + 1068, 250, 182, 0, 0, 200, 3, + -100, 249, 116, 0, 0, 208, 3 + }, + + /* Region 135 */ + { + 0x0005, 42, 42, 160, 255, 126, 20, + 3514, 247, 23, 72, 0, 212, 3, + 400, 255, 94, 177, 0, 232, 2, + 2347, 250, 47, 0, 196, 184, 6, + 4388, 248, 26, 0, 136, 224, 2 + }, + + /* Region 136 */ + { + 0x000d, 43, 43, 208, 16, 187, -20, + -500, 247, 128, 0, 0, 204, 1, + -690, 249, 88, 0, 0, 252, 3, + 1068, 254, 182, 0, 0, 200, 3, + 0, 249, 116, 0, 0, 208, 3 + }, + + /* Region 137 */ + { + 0x0005, 44, 44, 160, 255, 126, 20, + 3514, 151, 20, 72, 0, 244, 3, + 400, 223, 92, 177, 0, 240, 2, + 2347, 134, 34, 0, 176, 208, 6, + 4388, 200, 21, 0, 100, 220, 2 + }, + + /* Region 138 */ + { + 0x000d, 45, 45, 208, 16, 187, -10, + -350, 246, 128, 0, 0, 204, 1, + -590, 249, 88, 0, 0, 252, 3, + 2368, 254, 182, 0, 0, 196, 3, + 500, 249, 116, 0, 0, 208, 3 + }, + + /* Region 139 */ + { + 0x0005, 46, 46, 160, 255, 126, 20, + 3510, 147, 51, 72, 0, 236, 3, + 400, 219, 90, 177, 0, 240, 2, + 2347, 134, 66, 0, 176, 224, 6, + 4388, 200, 84, 0, 100, 212, 2 + }, + + /* Region 140 */ + { + 0x000d, 47, 47, 176, 32, 187, 10, + 0, 247, 128, 0, 0, 204, 1, + -280, 249, 88, 0, 0, 252, 3, + 2968, 255, 182, 0, 0, 200, 3, + 700, 250, 116, 0, 0, 204, 3 + }, + + /* Region 141 */ + { + 0x000d, 48, 48, 0, 255, 187, 20, + 10, 247, 128, 0, 0, 204, 3, + -130, 249, 88, 0, 0, 252, 3, + 3068, 255, 182, 0, 0, 188, 3, + 800, 250, 116, 0, 0, 204, 3 + }, + + /* Region 142 */ + { + 0x000d, 49, 49, 160, 255, 215, 20, + 3986, 18, 6, 8, 0, 252, 2, + 0, 247, 70, 1, 0, 240, 2, + 5354, 242, 48, 0, 252, 216, 2, + 3868, 193, 48, 0, 212, 208, 2 + }, + + /* Region 143 */ + { + 0x000d, 50, 50, 0, 255, 201, 30, + 200, 247, 128, 0, 0, 208, 3, + 20, 249, 88, 0, 0, 252, 3, + 3368, 255, 182, 0, 0, 200, 3, + 1100, 250, 116, 0, 0, 204, 3 + }, + + /* Region 144 */ + { + 0x000d, 51, 51, 160, 255, 97, -20, + 3831, 240, 39, 0, 232, 224, 3, + 1258, 246, 102, 0, 0, 232, 3, + 4323, 242, 32, 0, 0, 216, 3, + 868, 243, 64, 0, 0, 204, 3 + }, + + /* Region 145 */ + { + 0x000d, 52, 52, 112, 128, 234, -20, + 725, 228, 32, 0, 0, 208, 1, + 400, 248, 86, 0, 0, 248, 3, + 2003, 53, 32, 0, 0, 236, 3, + 100, 209, 32, 0, 0, 212, 1 + }, + + /* Region 146 */ + { + 0x000d, 53, 53, 160, 255, 97, -20, + 3831, 240, 39, 0, 232, 224, 3, + 1258, 246, 102, 0, 0, 232, 3, + 4323, 242, 32, 0, 0, 224, 3, + 868, 243, 64, 0, 0, 196, 3 + }, + + /* Region 147 */ + { + 0x001d, 54, 54, 240, 240, 242, 10, + -1, 245, 71, 1, 24, 236, 0, + 1200, 218, 102, 1, 0, 236, 2, + 1354, 255, 48, 0, 0, 208, 2, + 5868, 209, 48, 0, 160, 212, 0 + }, + + /* Region 148 */ + { + 0x000d, 55, 55, 48, 32, 234, -10, + 725, 228, 32, 0, 0, 208, 3, + 900, 249, 86, 0, 0, 240, 3, + 2303, 69, 32, 0, 0, 236, 1, + 400, 177, 32, 0, 0, 212, 3 + }, + + /* Region 149 */ + { + 0x000d, 56, 56, 0, 255, 149, 20, + 414, 254, 123, 48, 0, 204, 3, + 1986, 252, 118, 48, 0, 244, 3, + 4383, 242, 67, 48, 0, 200, 3, + 4205, 243, 81, 48, 0, 204, 3 + }, + + /* Region 150 */ + { + 0x000d, 57, 57, 48, 32, 234, -20, + 526, 210, 32, 0, 0, 200, 3, + 719, 246, 86, 0, 0, 240, 3, + 1303, 48, 32, 0, 0, 236, 1, + 202, 98, 32, 0, 0, 212, 3 + }, + + /* Region 151 */ + { + 0x001d, 58, 58, 240, 240, 204, -40, + 5650, 247, 16, 0, 84, 220, 1, + 3800, 248, 32, 0, 0, 248, 3, + 1780, 252, 16, 0, 0, 152, 3, + 6825, 245, 32, 0, 0, 208, 1 + }, + + /* Region 152 */ + { + 0x000d, 59, 59, 144, 0, 108, -20, + 3531, 240, 103, 0, 232, 220, 3, + 1058, 246, 102, 0, 0, 232, 3, + 5331, 242, 64, 0, 0, 220, 3, + 1968, 243, 64, 0, 0, 204, 1 + }, + + /* Region 153 */ + { + 0x000d, 60, 60, 192, 64, 155, 40, + 700, 214, 84, 0, 0, 208, 1, + 950, 253, 76, 0, 0, 248, 3, + 2803, 255, 127, 0, 0, 200, 3, + 750, 255, 89, 0, 0, 204, 3 + }, + + /* Region 154 */ + { + 0x000d, 61, 61, 224, 48, 91, 40, + 400, 229, 68, 0, 0, 204, 1, + 700, 251, 76, 0, 0, 248, 3, + 1803, 255, 95, 0, 0, 196, 3, + 450, 255, 89, 0, 0, 208, 3 + }, + + /* Region 155 */ + { + 0x000d, 62, 62, 240, 32, 191, 25, + 214, 237, 69, 0, 0, 204, 1, + 400, 252, 78, 0, 0, 248, 3, + 2830, 255, 95, 0, 0, 208, 3, + 2500, 255, 25, 0, 0, 192, 3 + }, + + /* Region 156 */ + { + 0x000d, 63, 63, 240, 32, 91, 25, + 400, 229, 68, 0, 0, 188, 1, + -100, 250, 76, 0, 0, 248, 3, + 1803, 254, 95, 0, 0, 200, 3, + 450, 238, 89, 0, 0, 200, 3 + }, + + /* Region 157 */ + { + 0x000d, 64, 64, 240, 16, 91, 20, + 300, 210, 68, 0, 0, 196, 1, + -400, 250, 76, 0, 0, 248, 3, + 1803, 254, 95, 0, 0, 200, 3, + 550, 238, 89, 0, 0, 200, 3 + }, + + /* Region 158 */ + { + 0x001c, 65, 65, 240, 128, 223, 20, + 1780, 234, 16, 0, 112, 208, 3, + 800, 251, 32, 0, 0, 248, 3, + 5501, 231, 48, 0, 48, 200, 3, + 2751, 232, 48, 0, 0, 220, 3 + }, + + /* Region 159 */ + { + 0x001c, 66, 66, 240, 128, 223, 20, + 1580, 234, 16, 0, 112, 208, 3, + 600, 250, 32, 0, 0, 248, 3, + 5201, 231, 48, 0, 48, 200, 3, + 2510, 232, 48, 0, 0, 220, 3 + }, + + /* Region 160 */ + { + 0x000d, 67, 67, 0, 255, 0, -35, + 1514, 255, 63, 51, 0, 184, 3, + 4830, 251, 73, 51, 0, 252, 3, + 4349, 245, 67, 51, 0, 212, 3, + 5267, 246, 65, 51, 0, 200, 3 + }, + + /* Region 161 */ + { + 0x000d, 68, 68, 0, 255, 0, -35, + 1514, 255, 63, 51, 0, 196, 3, + 4905, 251, 73, 51, 0, 252, 3, + 4349, 245, 67, 51, 0, 196, 3, + 5214, 246, 65, 51, 0, 208, 3 + }, + + /* Region 162 */ + { + 0x000a, 69, 69, 240, 240, 243, -35, + 10000, 160, 68, 0, 0, 200, 3, + 7000, 156, 140, 0, 0, 228, 3, + 1586, 176, 16, 0, 0, 228, 7, + 8000, 140, 80, 0, 0, 236, 3 + }, + + /* Region 163 */ + { + 0x001a, 70, 70, 240, 240, 227, -38, + 500, 240, 52, 0, 0, 220, 1, + 8000, 188, 124, 0, 0, 228, 3, + 1586, 240, 16, 0, 0, 224, 7, + 8000, 203, 80, 0, 0, 228, 3 + }, + + /* Region 164 */ + { + 0x0004, 71, 71, 226, 240, 181, 35, + 7253, 224, 32, 48, 0, 184, 3, + 3594, 224, 79, 48, 0, 248, 1, + 220, 97, 19, 48, 156, 152, 3, + 5243, 172, 16, 48, 92, 204, 1 + }, + + /* Region 165 */ + { + 0x0004, 72, 72, 240, 241, 181, 35, + 6253, 134, 32, 48, 0, 184, 3, + 3994, 176, 76, 48, 160, 248, 1, + 22, 183, 19, 48, 156, 172, 3, + 1243, 160, 16, 48, 240, 188, 3 + }, + + /* Region 166 */ + { + 0x001a, 73, 73, 240, 224, 155, 30, + -2145, 240, 70, 0, 0, 252, 3, + 600, 109, 111, 0, 0, 240, 3, + -1800, 240, 71, 0, 0, 248, 3, + 200, 173, 111, 0, 0, 240, 3 + }, + + /* Region 167 */ + { + 0x0012, 74, 74, 240, 224, 119, 30, + -2545, 240, 70, 0, 252, 252, 3, + 0, 153, 111, 0, 0, 240, 3, + -2400, 240, 71, 0, 252, 252, 3, + 100, 137, 111, 0, 0, 240, 3 + }, + + /* Region 168 */ + { + 0x001a, 75, 75, 240, 128, 240, 20, + 3780, 255, 16, 0, 252, 188, 2, + 800, 255, 64, 0, 0, 248, 2, + 2501, 255, 48, 0, 252, 208, 0, + 751, 255, 48, 0, 0, 236, 2 + }, + + /* Region 169 */ + { + 0x000d, 76, 76, 0, 255, 68, 35, + 1100, 239, 69, 0, 0, 184, 3, + 2600, 255, 76, 0, 0, 252, 3, + 5000, 255, 111, 0, 0, 204, 3, + 3400, 254, 73, 0, 0, 184, 3 + }, + + /* Region 170 */ + { + 0x000d, 77, 77, 0, 255, 68, 35, + 914, 239, 69, 0, 0, 180, 3, + 1801, 254, 76, 0, 0, 252, 3, + 4800, 255, 111, 0, 0, 192, 3, + 3200, 254, 73, 0, 0, 192, 3 + }, + + /* Region 171 */ + { + 0x000d, 78, 78, 240, 32, 197, -20, + 1200, 216, 86, 0, 0, 180, 1, + 1800, 189, 127, 0, 0, 244, 3, + 2700, 156, 102, 0, 0, 196, 1, + 700, 109, 104, 0, 0, 196, 1 + }, + + /* Region 172 */ + { + 0x000d, 79, 79, 240, 32, 197, -20, + 1200, 216, 86, 0, 0, 196, 1, + 2200, 171, 127, 0, 0, 244, 3, + 2700, 145, 102, 0, 0, 192, 1, + 700, 106, 104, 0, 0, 192, 1 + }, + + /* Region 173 */ + { + 0x000d, 80, 80, 0, 255, 0, -40, + 3514, 254, 79, 51, 0, 196, 3, + 5905, 252, 73, 51, 0, 248, 3, + 6348, 245, 35, 51, 0, 176, 3, + 2203, 244, 33, 51, 0, 216, 3 + }, + + /* Region 174 */ + { + 0x800d, 81, 81, 0, 255, 0, -40, + 3514, 255, 79, 51, 0, 192, 3, + 5905, 246, 73, 51, 0, 252, 3, + 6348, 241, 35, 51, 0, 180, 3, + 2203, 242, 33, 51, 0, 212, 3 + } +}; + + +/*---------------------------------------------------------------------------- + * Programs + *---------------------------------------------------------------------------- +*/ +const S_PROGRAM programs[] = +{ + { 7864320, 128 } /* program 0 */ +}; /* end Programs */ + +/*---------------------------------------------------------------------------- + * Banks + *---------------------------------------------------------------------------- +*/ +const S_BANK banks[] = +{ + { /* bank 0 */ + 30976, + { + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127 + } + } +}; /* end Banks */ + +/*---------------------------------------------------------------------------- + * S_EAS + *---------------------------------------------------------------------------- +*/ +const S_EAS easSoundLib = +{ + 0x01534145, + 0x00105622, + + banks, + programs, + + NULL, + NULL, + NULL, + NULL, + NULL, + + regions, + + 1, + 1, + + 0, + 0, + 0, + + 175 +}; /* end S_EAS */ +/* end sound library */ diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_fmsynth.c b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_fmsynth.c new file mode 100755 index 0000000..629506a --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_fmsynth.c @@ -0,0 +1,910 @@ +/*---------------------------------------------------------------------------- + * + * File: + * fmsynth.c + * + * Contents and purpose: + * Implements the high-level FM synthesizer functions. + * + * Copyright Sonic Network Inc. 2004 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 795 $ + * $Date: 2007-08-01 00:14:45 -0700 (Wed, 01 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +// includes +#include "eas_host.h" +#include "eas_report.h" + +#include "eas_data.h" +#include "eas_synth_protos.h" +#include "eas_audioconst.h" +#include "eas_fmengine.h" +#include "eas_math.h" + +/* option sanity check */ +#ifdef _REVERB +#error "No reverb for FM synthesizer" +#endif +#ifdef _CHORUS +#error "No chorus for FM synthesizer" +#endif + +/* + * WARNING: These macros can cause unwanted side effects. Use them + * with care. For example, min(x++,y++) will cause either x or y to be + * incremented twice. + */ +#define min(a,b) ((a) < (b) ? (a) : (b)) +#define max(a,b) ((a) > (b) ? (a) : (b)) + +/* pivot point for keyboard scalars */ +#define EG_SCALE_PIVOT_POINT 64 +#define KEY_SCALE_PIVOT_POINT 36 + +/* This number is the negative of the frequency of the note (in cents) of + * the sine wave played at unity. The number can be calculated as follows: + * + * MAGIC_NUMBER = 1200 * log(base2) (SINE_TABLE_SIZE * 8.175798916 / SAMPLE_RATE) + * + * 8.17578 is a reference to the frequency of MIDI note 0 + */ +#if defined (_SAMPLE_RATE_8000) +#define MAGIC_NUMBER 1279 +#elif defined (_SAMPLE_RATE_16000) +#define MAGIC_NUMBER 79 +#elif defined (_SAMPLE_RATE_20000) +#define MAGIC_NUMBER -308 +#elif defined (_SAMPLE_RATE_22050) +#define MAGIC_NUMBER -477 +#elif defined (_SAMPLE_RATE_24000) +#define MAGIC_NUMBER -623 +#elif defined (_SAMPLE_RATE_32000) +#define MAGIC_NUMBER -1121 +#elif defined (_SAMPLE_RATE_44100) +#define MAGIC_NUMBER -1677 +#elif defined (_SAMPLE_RATE_48000) +#define MAGIC_NUMBER -1823 +#endif + +/* externs */ +extern const EAS_I16 fmControlTable[128]; +extern const EAS_U16 fmRateTable[256]; +extern const EAS_U16 fmAttackTable[16]; +extern const EAS_U8 fmDecayTable[16]; +extern const EAS_U8 fmReleaseTable[16]; +extern const EAS_U8 fmScaleTable[16]; + +/* local prototypes */ +/*lint -esym(715, pVoiceMgr) standard synthesizer interface - pVoiceMgr not used */ +static EAS_RESULT FM_Initialize (S_VOICE_MGR *pVoiceMgr) { return EAS_SUCCESS; } +static EAS_RESULT FM_StartVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_U16 regionIndex); +static EAS_BOOL FM_UpdateVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_I32 *pMixBuffer, EAS_I32 numSamples); +static void FM_ReleaseVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum); +static void FM_MuteVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum); +static void FM_SustainPedal (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, S_SYNTH_CHANNEL *pChannel, EAS_I32 voiceNum); +static void FM_UpdateChannel (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel); + + +/*---------------------------------------------------------------------------- + * Synthesizer interface + *---------------------------------------------------------------------------- +*/ +const S_SYNTH_INTERFACE fmSynth = +{ + FM_Initialize, + FM_StartVoice, + FM_UpdateVoice, + FM_ReleaseVoice, + FM_MuteVoice, + FM_SustainPedal, + FM_UpdateChannel +}; + +#ifdef FM_OFFBOARD +const S_FRAME_INTERFACE fmFrameInterface = +{ + FM_StartFrame, + FM_EndFrame +}; +#endif + +/*---------------------------------------------------------------------------- + * inline functions + *---------------------------------------------------------------------------- + */ +EAS_INLINE S_FM_VOICE *GetFMVoicePtr (S_VOICE_MGR *pVoiceMgr, EAS_INT voiceNum) +{ + return &pVoiceMgr->fmVoices[voiceNum]; +} +EAS_INLINE S_SYNTH_CHANNEL *GetChannelPtr (S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice) +{ + return &pSynth->channels[pVoice->channel & 15]; +} +EAS_INLINE const S_FM_REGION *GetFMRegionPtr (S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice) +{ +#ifdef _SECONDARY_SYNTH + return &pSynth->pEAS->pFMRegions[pVoice->regionIndex & REGION_INDEX_MASK]; +#else + return &pSynth->pEAS->pFMRegions[pVoice->regionIndex]; +#endif +} + +/*---------------------------------------------------------------------------- + * FM_SynthIsOutputOperator + *---------------------------------------------------------------------------- + * Purpose: + * Returns true if the operator is a direct output and not muted + * + * Inputs: + * + * Outputs: + * Returns boolean + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL FM_SynthIsOutputOperator (const S_FM_REGION *pRegion, EAS_INT operIndex) +{ + + /* see if voice is muted */ + if ((pRegion->oper[operIndex].gain & 0xfc) == 0) + return 0; + + /* check based on mode */ + switch (pRegion->region.keyGroupAndFlags & 7) + { + + /* mode 0 - all operators are external */ + case 0: + return EAS_TRUE; + + /* mode 1 - operators 1-3 are external */ + case 1: + if (operIndex != 0) + return EAS_TRUE; + break; + + /* mode 2 - operators 1 & 3 are external */ + case 2: + if ((operIndex == 1) || (operIndex == 3)) + return EAS_TRUE; + break; + + /* mode 2 - operators 1 & 2 are external */ + case 3: + if ((operIndex == 1) || (operIndex == 2)) + return EAS_TRUE; + break; + + /* modes 4 & 5 - operator 1 is external */ + case 4: + case 5: + if (operIndex == 1) + return EAS_TRUE; + break; + + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL,"Invalid voice mode: %d", + pRegion->region.keyGroupAndFlags & 7); */ } + } + + return EAS_FALSE; +} + +/*---------------------------------------------------------------------------- + * FM_CalcEGRate() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * nKeyNumber - MIDI note + * nLogRate - logarithmic scale rate from patch data + * nKeyScale - key scaling factor for this EG + * + * Outputs: + * 16-bit linear multiplier + *---------------------------------------------------------------------------- +*/ + +static EAS_U16 FM_CalcEGRate (EAS_U8 nKeyNumber, EAS_U8 nLogRate, EAS_U8 nEGScale) +{ + EAS_I32 temp; + + /* incorporate key scaling on release rate */ + temp = (EAS_I32) nLogRate << 7; + temp += ((EAS_I32) nKeyNumber - EG_SCALE_PIVOT_POINT) * (EAS_I32) nEGScale; + + /* saturate */ + temp = max(temp, 0); + temp = min(temp, 32767); + + /* look up in rate table */ + /*lint -e{704} use shift for performance */ + return fmRateTable[temp >> 8]; +} + +/*---------------------------------------------------------------------------- + * FM_ReleaseVoice() + *---------------------------------------------------------------------------- + * Purpose: + * The selected voice is being released. + * + * Inputs: + * psEASData - pointer to S_EAS_DATA + * pVoice - pointer to voice to release + * + * Outputs: + * None + *---------------------------------------------------------------------------- +*/ +static void FM_ReleaseVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum) +{ + EAS_INT operIndex; + const S_FM_REGION *pRegion; + S_FM_VOICE *pFMVoice; + + /* check to see if voice responds to NOTE-OFF's */ + pRegion = GetFMRegionPtr(pSynth, pVoice); + if (pRegion->region.keyGroupAndFlags & REGION_FLAG_ONE_SHOT) + return; + + /* set all envelopes to release state */ + pFMVoice = GetFMVoicePtr(pVoiceMgr, voiceNum); + for (operIndex = 0; operIndex < 4; operIndex++) + { + pFMVoice->oper[operIndex].envState = eFMEnvelopeStateRelease; + + /* incorporate key scaling on release rate */ + pFMVoice->oper[operIndex].envRate = FM_CalcEGRate( + pVoice->note, + fmReleaseTable[pRegion->oper[operIndex].velocityRelease & 0x0f], + fmScaleTable[pRegion->oper[operIndex].egKeyScale >> 4]); + } /* end for (operIndex = 0; operIndex < 4; operIndex++) */ +} + +/*---------------------------------------------------------------------------- + * FM_MuteVoice() + *---------------------------------------------------------------------------- + * Purpose: + * The selected voice is being muted. + * + * Inputs: + * pVoice - pointer to voice to release + * + * Outputs: + * None + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pSynth) standard interface, pVoiceMgr not used */ +static void FM_MuteVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum) +{ + S_FM_VOICE *pFMVoice; + + /* clear deferred action flags */ + pVoice->voiceFlags &= + ~(VOICE_FLAG_DEFER_MIDI_NOTE_OFF | + VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF | + VOICE_FLAG_DEFER_MUTE); + + /* set all envelopes to muted state */ + pFMVoice = GetFMVoicePtr(pVoiceMgr, voiceNum); + pFMVoice->oper[0].envState = eFMEnvelopeStateMuted; + pFMVoice->oper[1].envState = eFMEnvelopeStateMuted; + pFMVoice->oper[2].envState = eFMEnvelopeStateMuted; + pFMVoice->oper[3].envState = eFMEnvelopeStateMuted; +} + +/*---------------------------------------------------------------------------- + * FM_SustainPedal() + *---------------------------------------------------------------------------- + * Purpose: + * The selected voice is held due to sustain pedal + * + * Inputs: + * pVoice - pointer to voice to sustain + * + * Outputs: + * None + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pChannel) standard interface, pVoiceMgr not used */ +static void FM_SustainPedal (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, S_SYNTH_CHANNEL *pChannel, EAS_I32 voiceNum) +{ + const S_FM_REGION *pRegion; + S_FM_VOICE *pFMVoice; + EAS_INT operIndex; + + pRegion = GetFMRegionPtr(pSynth, pVoice); + pFMVoice = GetFMVoicePtr(pVoiceMgr, voiceNum); + + /* check to see if any envelopes are above the sustain level */ + for (operIndex = 0; operIndex < 4; operIndex++) + { + + /* if level control or envelope gain is zero, skip this envelope */ + if (((pRegion->oper[operIndex].gain & 0xfc) == 0) || + (pFMVoice->oper[operIndex].envGain == 0)) + { + continue; + } + + /* if the envelope gain is above the sustain level, we need to catch this voice */ + if (pFMVoice->oper[operIndex].envGain >= ((EAS_U16) (pRegion->oper[operIndex].sustain & 0xfc) << 7)) + { + + /* reset envelope to decay state */ + pFMVoice->oper[operIndex].envState = eFMEnvelopeStateDecay; + + pFMVoice->oper[operIndex].envRate = FM_CalcEGRate( + pVoice->note, + fmDecayTable[pRegion->oper[operIndex].attackDecay & 0x0f], + fmScaleTable[pRegion->oper[operIndex].egKeyScale >> 4]); + + /* set voice to decay state */ + pVoice->voiceState = eVoiceStatePlay; + + /* set sustain flag */ + pVoice->voiceFlags |= VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF; + } + } /* end for (operIndex = 0; operIndex < 4; operIndex++) */ +} + +/*---------------------------------------------------------------------------- + * FM_StartVoice() + *---------------------------------------------------------------------------- + * Purpose: + * Assign the region for the given instrument using the midi key number + * and the RPN2 (coarse tuning) value. By using RPN2 as part of the + * region selection process, we reduce the amount a given sample has + * to be transposed by selecting the closest recorded root instead. + * + * This routine is the second half of SynthAssignRegion(). + * If the region was successfully found by SynthFindRegionIndex(), + * then assign the region's parameters to the voice. + * + * Setup and initialize the following voice parameters: + * m_nRegionIndex + * + * Inputs: + * pVoice - ptr to the voice we have assigned for this channel + * nRegionIndex - index of the region + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * success - could find and assign the region for this voice's note otherwise + * failure - could not find nor assign the region for this voice's note + * + * Side Effects: + * psSynthObject->m_sVoice[].m_nRegionIndex is assigned + * psSynthObject->m_sVoice[] parameters are assigned + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT FM_StartVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_U16 regionIndex) +{ + S_FM_VOICE *pFMVoice; + S_SYNTH_CHANNEL *pChannel; + const S_FM_REGION *pRegion; + EAS_I32 temp; + EAS_INT operIndex; + + /* establish pointers to data */ + pVoice->regionIndex = regionIndex; + pFMVoice = GetFMVoicePtr(pVoiceMgr, voiceNum); + pChannel = GetChannelPtr(pSynth, pVoice); + pRegion = GetFMRegionPtr(pSynth, pVoice); + + /* update static channel parameters */ + if (pChannel->channelFlags & CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS) + FM_UpdateChannel(pVoiceMgr, pSynth, pVoice->channel & 15); + + /* init the LFO */ + pFMVoice->lfoValue = 0; + pFMVoice->lfoPhase = 0; + pFMVoice->lfoDelay = (EAS_U16) (fmScaleTable[pRegion->lfoFreqDelay & 0x0f] >> 1); + +#if (NUM_OUTPUT_CHANNELS == 2) + /* calculate pan gain values only if stereo output */ + /* set up panning only at note start */ + temp = (EAS_I32) pChannel->pan - 64; + temp += (EAS_I32) pRegion->pan; + if (temp < -64) + temp = -64; + if (temp > 64) + temp = 64; + pFMVoice->pan = (EAS_I8) temp; +#endif /* #if (NUM_OUTPUT_CHANNELS == 2) */ + + /* no samples have been synthesized for this note yet */ + pVoice->voiceFlags = VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET; + + /* initialize gain value for anti-zipper filter */ + pFMVoice->voiceGain = (EAS_I16) EAS_LogToLinear16(pChannel->staticGain); + pFMVoice->voiceGain = (EAS_I16) FMUL_15x15(pFMVoice->voiceGain, pSynth->masterVolume); + + /* initialize the operators */ + for (operIndex = 0; operIndex < 4; operIndex++) + { + + /* establish operator output gain level */ + /*lint -e{701} */ + pFMVoice->oper[operIndex].outputGain = EAS_LogToLinear16(((EAS_I16) (pRegion->oper[operIndex].gain & 0xfc) - 0xfc) << 7); + + /* check for linear velocity flag */ + /*lint -e{703} */ + if (pRegion->oper[operIndex].flags & FM_OPER_FLAG_LINEAR_VELOCITY) + temp = (EAS_I32) (pVoice->velocity - 127) << 5; + else + temp = (EAS_I32) fmControlTable[pVoice->velocity]; + + /* scale velocity */ + /*lint -e{704} use shift for performance */ + temp = (temp * (EAS_I32)(pRegion->oper[operIndex].velocityRelease & 0xf0)) >> 7; + + /* include key scalar */ + temp -= ((EAS_I32) pVoice->note - KEY_SCALE_PIVOT_POINT) * (EAS_I32) fmScaleTable[pRegion->oper[operIndex].egKeyScale & 0x0f]; + + /* saturate */ + temp = min(temp, 0); + temp = max(temp, -32768); + + /* save static gain parameters */ + pFMVoice->oper[operIndex].baseGain = (EAS_I16) EAS_LogToLinear16(temp); + + /* incorporate key scaling on decay rate */ + pFMVoice->oper[operIndex].envRate = FM_CalcEGRate( + pVoice->note, + fmDecayTable[pRegion->oper[operIndex].attackDecay & 0x0f], + fmScaleTable[pRegion->oper[operIndex].egKeyScale >> 4]); + + /* if zero attack time, max out envelope and jump to decay state */ + if ((pRegion->oper[operIndex].attackDecay & 0xf0) == 0xf0) + { + + /* start out envelope at max */ + pFMVoice->oper[operIndex].envGain = 0x7fff; + + /* set envelope to decay state */ + pFMVoice->oper[operIndex].envState = eFMEnvelopeStateDecay; + } + + /* start envelope at zero and start in attack state */ + else + { + pFMVoice->oper[operIndex].envGain = 0; + pFMVoice->oper[operIndex].envState = eFMEnvelopeStateAttack; + } + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * FM_UpdateChannel() + *---------------------------------------------------------------------------- + * Purpose: + * Calculate and assign static channel parameters + * These values only need to be updated if one of the controller values + * for this channel changes. + * Called when CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS flag is set. + * + * Inputs: + * nChannel - channel to update + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * - the given channel's static gain and static pitch are updated + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pVoiceMgr) standard interface, pVoiceMgr not used */ +static void FM_UpdateChannel (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel) +{ + S_SYNTH_CHANNEL *pChannel; + EAS_I32 temp; + + pChannel = &pSynth->channels[channel]; + + /* convert CC7 volume controller to log scale */ + temp = fmControlTable[pChannel->volume]; + + /* incorporate CC11 expression controller */ + temp += fmControlTable[pChannel->expression]; + + /* saturate */ + pChannel->staticGain = (EAS_I16) max(temp,-32768); + + /* calculate pitch bend */ + /*lint -e{703} */ + temp = (((EAS_I32)(pChannel->pitchBend) << 2) - 32768); + + temp = FMUL_15x15(temp, pChannel->pitchBendSensitivity); + + /* include "magic number" compensation for sample rate and lookup table size */ + temp += MAGIC_NUMBER; + + /* if this is not a drum channel, then add in the per-channel tuning */ + if (!(pChannel->channelFlags & CHANNEL_FLAG_RHYTHM_CHANNEL)) + temp += (pChannel->finePitch + (pChannel->coarsePitch * 100)); + + /* save static pitch */ + pChannel->staticPitch = temp; + + /* Calculate LFO modulation depth */ + /* mod wheel to LFO depth */ + temp = FMUL_15x15(DEFAULT_LFO_MOD_WHEEL_TO_PITCH_CENTS, + pChannel->modWheel << (NUM_EG1_FRAC_BITS -7)); + + /* channel pressure to LFO depth */ + pChannel->lfoAmt = (EAS_I16) (temp + + FMUL_15x15(DEFAULT_LFO_CHANNEL_PRESSURE_TO_PITCH_CENTS, + pChannel->channelPressure << (NUM_EG1_FRAC_BITS -7))); + + /* clear update flag */ + pChannel->channelFlags &= ~CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS; + return; +} + +/*---------------------------------------------------------------------------- + * FM_UpdateLFO() + *---------------------------------------------------------------------------- + * Purpose: + * Calculate the LFO for the given voice + * + * Inputs: + * pVoice - ptr to the voice whose LFO we want to update + * psEASData - pointer to overall EAS data structure - used for debug only + * + * Outputs: + * + * Side Effects: + * - updates LFO values for the given voice + *---------------------------------------------------------------------------- +*/ +static void FM_UpdateLFO (S_FM_VOICE *pFMVoice, const S_FM_REGION *pRegion) +{ + + /* increment the LFO phase if the delay time has elapsed */ + if (!pFMVoice->lfoDelay) + { + /*lint -e{701} */ + pFMVoice->lfoPhase = pFMVoice->lfoPhase + (EAS_U16) (-fmControlTable[((15 - (pRegion->lfoFreqDelay >> 4)) << 3) + 4]); + + /* square wave LFO? */ + if (pRegion->region.keyGroupAndFlags & REGION_FLAG_SQUARE_WAVE) + pFMVoice->lfoValue = (EAS_I16)(pFMVoice->lfoPhase & 0x8000 ? -32767 : 32767); + + /* trick to get a triangle wave out of a sawtooth */ + else + { + pFMVoice->lfoValue = (EAS_I16) (pFMVoice->lfoPhase << 1); + /*lint -e{502} */ + if ((pFMVoice->lfoPhase > 0x3fff) && (pFMVoice->lfoPhase < 0xC000)) + pFMVoice->lfoValue = ~pFMVoice->lfoValue; + } + } + + /* still in delay */ + else + pFMVoice->lfoDelay--; + + return; +} + +/*---------------------------------------------------------------------------- + * FM_UpdateEG() + *---------------------------------------------------------------------------- + * Purpose: + * Calculate the synthesis parameters for an operator to be used during + * the next buffer + * + * Inputs: + * pVoice - pointer to the voice being updated + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL FM_UpdateEG (S_SYNTH_VOICE *pVoice, S_OPERATOR *pOper, const S_FM_OPER *pOperData, EAS_BOOL oneShot) +{ + EAS_U32 temp; + EAS_BOOL done; + + /* set flag assuming the envelope is not done */ + done = EAS_FALSE; + + /* take appropriate action based on state */ + switch (pOper->envState) + { + + case eFMEnvelopeStateAttack: + + /* the envelope is linear during the attack, so add the value */ + temp = pOper->envGain + fmAttackTable[pOperData->attackDecay >> 4]; + + /* check for end of attack */ + if (temp >= 0x7fff) + { + pOper->envGain = 0x7fff; + pOper->envState = eFMEnvelopeStateDecay; + } + else + pOper->envGain = (EAS_U16) temp; + break; + + case eFMEnvelopeStateDecay: + + /* decay is exponential, multiply by decay rate */ + pOper->envGain = (EAS_U16) FMUL_15x15(pOper->envGain, pOper->envRate); + + /* check for sustain level reached */ + temp = (EAS_U32) (pOperData->sustain & 0xfc) << 7; + if (pOper->envGain <= (EAS_U16) temp) + { + /* if this is a one-shot patch, go directly to release phase */ + if (oneShot) + { + pOper->envRate = FM_CalcEGRate( + pVoice->note, + fmReleaseTable[pOperData->velocityRelease & 0x0f], + fmScaleTable[pOperData->egKeyScale >> 4]); + pOper->envState = eFMEnvelopeStateRelease; + } + + /* normal sustaining type */ + else + { + pOper->envGain = (EAS_U16) temp; + pOper->envState = eFMEnvelopeStateSustain; + } + } + break; + + case eFMEnvelopeStateSustain: + pOper->envGain = (EAS_U16)((EAS_U16)(pOperData->sustain & 0xfc) << 7); + break; + + case eFMEnvelopeStateRelease: + + /* release is exponential, multiply by release rate */ + pOper->envGain = (EAS_U16) FMUL_15x15(pOper->envGain, pOper->envRate); + + /* fully released */ + if (pOper->envGain == 0) + { + pOper->envGain = 0; + pOper->envState = eFMEnvelopeStateMuted; + done = EAS_TRUE; + } + break; + + case eFMEnvelopeStateMuted: + pOper->envGain = 0; + done = EAS_TRUE; + break; + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL,"Invalid operator state: %d", pOper->envState); */ } + } /* end switch (pOper->m_eState) */ + + return done; +} + +/*---------------------------------------------------------------------------- + * FM_UpdateDynamic() + *---------------------------------------------------------------------------- + * Purpose: + * Calculate the synthesis parameters for this voice that will be used to + * synthesize the next buffer + * + * Inputs: + * pVoice - pointer to the voice being updated + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * Returns EAS_TRUE if voice will be fully ramped to zero at the end of + * the next synthesized buffer. + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL FM_UpdateDynamic (S_SYNTH_VOICE *pVoice, S_FM_VOICE *pFMVoice, const S_FM_REGION *pRegion, S_SYNTH_CHANNEL *pChannel) +{ + EAS_I32 temp; + EAS_I32 pitch; + EAS_I32 lfoPitch; + EAS_INT operIndex; + EAS_BOOL done; + + /* increment LFO phase */ + FM_UpdateLFO(pFMVoice, pRegion); + + /* base pitch in cents */ + pitch = pVoice->note * 100; + + /* LFO amount includes LFO depth from programming + channel dynamics */ + temp = (fmScaleTable[pRegion->vibTrem >> 4] >> 1) + pChannel->lfoAmt; + + /* multiply by LFO output to get final pitch modulation */ + lfoPitch = FMUL_15x15(pFMVoice->lfoValue, temp); + + /* flag to indicate this voice is done */ + done = EAS_TRUE; + + /* iterate through operators to establish parameters */ + for (operIndex = 0; operIndex < 4; operIndex++) + { + EAS_BOOL bTemp; + + /* set base phase increment for each operator */ + temp = pRegion->oper[operIndex].tuning + + pChannel->staticPitch; + + /* add vibrato effect unless it is disabled for this operator */ + if ((pRegion->oper[operIndex].flags & FM_OPER_FLAG_NO_VIBRATO) == 0) + temp += lfoPitch; + + /* if note is monotonic, bias to MIDI note 60 */ + if (pRegion->oper[operIndex].flags & FM_OPER_FLAG_MONOTONE) + temp += 6000; + else + temp += pitch; + pFMVoice->oper[operIndex].pitch = (EAS_I16) temp; + + /* calculate envelope, returns true if done */ + bTemp = FM_UpdateEG(pVoice, &pFMVoice->oper[operIndex], &pRegion->oper[operIndex], pRegion->region.keyGroupAndFlags & REGION_FLAG_ONE_SHOT); + + /* check if all output envelopes have completed */ + if (FM_SynthIsOutputOperator(pRegion, operIndex)) + done = done && bTemp; + } + + return done; +} + +/*---------------------------------------------------------------------------- + * FM_UpdateVoice() + *---------------------------------------------------------------------------- + * Purpose: + * Synthesize a block of samples for the given voice. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * number of samples actually written to buffer + * + * Side Effects: + * - samples are added to the presently free buffer + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL FM_UpdateVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_I32 *pMixBuffer, EAS_I32 numSamples) +{ + S_SYNTH_CHANNEL *pChannel; + const S_FM_REGION *pRegion; + S_FM_VOICE *pFMVoice; + S_FM_VOICE_CONFIG vCfg; + S_FM_VOICE_FRAME vFrame; + EAS_I32 temp; + EAS_INT oper; + EAS_U16 voiceGainTarget; + EAS_BOOL done; + + /* setup some pointers */ + pChannel = GetChannelPtr(pSynth, pVoice); + pRegion = GetFMRegionPtr(pSynth, pVoice); + pFMVoice = GetFMVoicePtr(pVoiceMgr, voiceNum); + + /* if the voice is just starting, get the voice configuration data */ + if (pVoice->voiceFlags & VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET) + { + + /* split architecture may limit the number of voice starts */ +#ifdef MAX_VOICE_STARTS + if (pVoiceMgr->numVoiceStarts == MAX_VOICE_STARTS) + return EAS_FALSE; + pVoiceMgr->numVoiceStarts++; +#endif + + /* get initial parameters */ + vCfg.feedback = pRegion->feedback; + vCfg.voiceGain = (EAS_U16) pFMVoice->voiceGain; + +#if (NUM_OUTPUT_CHANNELS == 2) + vCfg.pan = pFMVoice->pan; +#endif + + /* get voice mode */ + vCfg.flags = pRegion->region.keyGroupAndFlags & 7; + + /* get operator parameters */ + for (oper = 0; oper < 4; oper++) + { + /* calculate initial gain */ + vCfg.gain[oper] = (EAS_U16) FMUL_15x15(pFMVoice->oper[oper].baseGain, pFMVoice->oper[oper].envGain); + vCfg.outputGain[oper] = pFMVoice->oper[oper].outputGain; + + /* copy noise waveform flag */ + if (pRegion->oper[oper].flags & FM_OPER_FLAG_NOISE) + vCfg.flags |= (EAS_U8) (FLAG_FM_ENG_VOICE_OP1_NOISE << oper); + } + +#ifdef FM_OFFBOARD + FM_ConfigVoice(voiceNum, &vCfg, pVoiceMgr->pFrameBuffer); +#else + FM_ConfigVoice(voiceNum, &vCfg, NULL); +#endif + + /* clear startup flag */ + pVoice->voiceFlags &= ~VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET; + } + + /* calculate new synthesis parameters */ + done = FM_UpdateDynamic(pVoice, pFMVoice, pRegion, pChannel); + + /* calculate LFO gain modulation */ + /*lint -e{702} */ + temp = ((fmScaleTable[pRegion->vibTrem & 0x0f] >> 1) * pFMVoice->lfoValue) >> FM_LFO_GAIN_SHIFT; + + /* include channel gain */ + temp += pChannel->staticGain; + + /* -32768 or lower is infinite attenuation */ + if (temp < -32767) + voiceGainTarget = 0; + + /* translate to linear gain multiplier */ + else + voiceGainTarget = EAS_LogToLinear16(temp); + + /* include synth master volume */ + voiceGainTarget = (EAS_U16) FMUL_15x15(voiceGainTarget, pSynth->masterVolume); + + /* save target values for this frame */ + vFrame.voiceGain = voiceGainTarget; + + /* assume voice output is zero */ + pVoice->gain = 0; + + /* save operator targets for this frame */ + for (oper = 0; oper < 4; oper++) + { + vFrame.gain[oper] = (EAS_U16) FMUL_15x15(pFMVoice->oper[oper].baseGain, pFMVoice->oper[oper].envGain); + vFrame.pitch[oper] = pFMVoice->oper[oper].pitch; + + /* use the highest output envelope level as the gain for the voice stealing algorithm */ + if (FM_SynthIsOutputOperator(pRegion, oper)) + pVoice->gain = max(pVoice->gain, (EAS_I16) vFrame.gain[oper]); + } + + /* consider voice gain multiplier in calculating gain for stealing algorithm */ + pVoice->gain = (EAS_I16) FMUL_15x15(voiceGainTarget, pVoice->gain); + + /* synthesize samples */ +#ifdef FM_OFFBOARD + FM_ProcessVoice(voiceNum, &vFrame, numSamples, pVoiceMgr->operMixBuffer, pVoiceMgr->voiceBuffer, pMixBuffer, pVoiceMgr->pFrameBuffer); +#else + FM_ProcessVoice(voiceNum, &vFrame, numSamples, pVoiceMgr->operMixBuffer, pVoiceMgr->voiceBuffer, pMixBuffer, NULL); +#endif + + return done; +} + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_fmsynth.h b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_fmsynth.h new file mode 100755 index 0000000..8ceda46 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_fmsynth.h @@ -0,0 +1,81 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_fmsynth.h + * + * Contents and purpose: + * Implements the FM synthesizer functions. + * + * Copyright Sonic Network Inc. 2004 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 90 $ + * $Date: 2006-07-11 20:18:13 -0700 (Tue, 11 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef fmsynthH +#define fmsynthH + +#include "eas_data.h" + +#if defined (_FM_SYNTH) + +/* FM envelope state */ +typedef enum { + eFMEnvelopeStateAttack = 0, + eFMEnvelopeStateDecay, + eFMEnvelopeStateSustain, + eFMEnvelopeStateRelease, + eFMEnvelopeStateMuted, + eFMEnvelopeStateInvalid /* should never be in this state! */ +} E_FM_ENVELOPE_STATE; + +/*------------------------------------ + * S_OPERATOR data structure + *------------------------------------ +*/ +typedef struct s_operator_tag +{ + EAS_I16 pitch; /* operator pitch in cents */ + EAS_U16 envGain; /* envelope target */ + EAS_I16 baseGain; /* patch gain (inc. vel & key scale) */ + EAS_U16 outputGain; /* current output gain */ + EAS_U16 envRate; /* calculated envelope rate */ + EAS_U8 envState; /* envelope state */ + EAS_U8 pad; /* pad to 16-bits */ +} S_OPERATOR; +#endif + +typedef struct s_fm_voice_tag +{ + S_OPERATOR oper[4]; /* operator data */ + EAS_I16 voiceGain; /* LFO + channel parameters */ + EAS_U16 lfoPhase; /* LFO current phase */ + EAS_I16 lfoValue; /* LFO current value */ + EAS_U16 lfoDelay; /* keeps track of elapsed delay time */ + EAS_I8 pan; /* stereo pan value (-64 to +64) */ + EAS_I8 pad; /* reserved to maintain alignment */ +} S_FM_VOICE; + +#ifdef _FM_EDITOR +extern S_FM_REGION newPatch; +extern S_FM_REGION OriginalPatch; +#endif + +extern EAS_U32 freqTable[]; + +#endif diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_fmtables.c b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_fmtables.c new file mode 100755 index 0000000..a8ff0a2 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_fmtables.c @@ -0,0 +1,368 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_fmtables.c + * + * Contents and purpose: + * Contains lookup tables for the FM synthesizer + * + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + * + *---------------------------------------------------------------------------- +*/ + + +#include "eas_types.h" + +/* this table is needed by the DSP and the main processor */ +const EAS_U8 fmScaleTable[16] = +{ + 0,8,16,24,32,40,48,56,64,72,80,96,128,160,192,255 +}; + +/* these tables are needed on the main processor */ +#ifndef _DSP_CODE +const EAS_I16 fmControlTable[128] = +{ + -32768,-14313,-12265,-11067,-10217,-9558,-9019,-8563, + -8169,-7821,-7510,-7228,-6971,-6734,-6515,-6312, + -6121,-5942,-5773,-5613,-5462,-5317,-5180,-5049, + -4923,-4802,-4686,-4575,-4467,-4364,-4264,-4167, + -4073,-3982,-3894,-3808,-3725,-3644,-3565,-3488, + -3414,-3341,-3269,-3200,-3132,-3066,-3001,-2937, + -2875,-2814,-2754,-2696,-2638,-2582,-2527,-2473, + -2419,-2367,-2316,-2265,-2216,-2167,-2119,-2071, + -2025,-1979,-1934,-1889,-1846,-1803,-1760,-1718, + -1677,-1636,-1596,-1556,-1517,-1478,-1440,-1403, + -1366,-1329,-1293,-1257,-1221,-1186,-1152,-1118, + -1084,-1051,-1018,-985,-953,-921,-889,-858, + -827,-796,-766,-736,-706,-677,-648,-619, + -590,-562,-534,-506,-479,-452,-425,-398, + -371,-345,-319,-293,-268,-242,-217,-192, + -168,-143,-119,-95,-71,-47,-23,0 +}; + +const EAS_U16 fmRateTable[128] = +{ + 32767,32764,32758,32747,32731,32712,32688,32659, + 32627,32590,32548,32503,32453,32398,32340,32277, + 32211,32140,32065,31985,31902,31815,31724,31628, + 31529,31426,31319,31208,31094,30976,30854,30728, + 30599,30466,30330,30191,30048,29902,29752,29599, + 29443,29285,29123,28958,28790,28619,28445,28269, + 28090,27909,27725,27538,27349,27158,26964,26769, + 26571,26371,26169,25965,25760,25552,25343,25132, + 24920,24706,24490,24274,24056,23836,23616,23394, + 23172,22948,22724,22499,22273,22046,21819,21591, + 21363,21135,20906,20676,20447,20217,19987,19758, + 19528,19298,19069,18840,18610,18382,18153,17926, + 17698,17471,17245,17020,16795,16571,16347,16125, + 15903,15683,15463,15245,15027,14811,14596,14382, + 14169,13957,13747,13538,13331,13125,12920,12717, + 12516,12316,12117,11921,11725,11532,11340,0 +}; + +const EAS_U16 fmAttackTable[15] = +{ + 27,54,109,327,655,1310,2730,4095, + 4681,5461,6553,8191,10922,16383,32767 +}; + +const EAS_U8 fmDecayTable[16] = +{ + 4,7,10,15,20,25,30,35,40,50,60,70,80,90,100,127 +}; + +const EAS_U8 fmReleaseTable[16] = +{ + 10,15,20,25,30,35,40,45,50,60,70,80,90,100,113,127 +}; +#endif + +/* this table is needed only on the DSP */ +#if defined(_DSP_CODE) || !defined(_SPLIT_ARCHITECTURE) +//--------------------------------------------------------------------- +// sineTable +// +// Contains sine lookup table +//--------------------------------------------------------------------- + +const EAS_I16 sineTable[2048] = +{ + 0,101,201,302,402,503,603,704, + 804,905,1005,1106,1206,1307,1407,1507, + 1608,1708,1809,1909,2009,2110,2210,2310, + 2410,2511,2611,2711,2811,2911,3012,3112, + 3212,3312,3412,3512,3612,3712,3811,3911, + 4011,4111,4210,4310,4410,4509,4609,4708, + 4808,4907,5007,5106,5205,5305,5404,5503, + 5602,5701,5800,5899,5998,6096,6195,6294, + 6393,6491,6590,6688,6786,6885,6983,7081, + 7179,7277,7375,7473,7571,7669,7767,7864, + 7962,8059,8157,8254,8351,8448,8545,8642, + 8739,8836,8933,9030,9126,9223,9319,9416, + 9512,9608,9704,9800,9896,9992,10087,10183, + 10278,10374,10469,10564,10659,10754,10849,10944, + 11039,11133,11228,11322,11417,11511,11605,11699, + 11793,11886,11980,12074,12167,12260,12353,12446, + 12539,12632,12725,12817,12910,13002,13094,13187, + 13279,13370,13462,13554,13645,13736,13828,13919, + 14010,14101,14191,14282,14372,14462,14553,14643, + 14732,14822,14912,15001,15090,15180,15269,15358, + 15446,15535,15623,15712,15800,15888,15976,16063, + 16151,16238,16325,16413,16499,16586,16673,16759, + 16846,16932,17018,17104,17189,17275,17360,17445, + 17530,17615,17700,17784,17869,17953,18037,18121, + 18204,18288,18371,18454,18537,18620,18703,18785, + 18868,18950,19032,19113,19195,19276,19357,19438, + 19519,19600,19680,19761,19841,19921,20000,20080, + 20159,20238,20317,20396,20475,20553,20631,20709, + 20787,20865,20942,21019,21096,21173,21250,21326, + 21403,21479,21554,21630,21705,21781,21856,21930, + 22005,22079,22154,22227,22301,22375,22448,22521, + 22594,22667,22739,22812,22884,22956,23027,23099, + 23170,23241,23311,23382,23452,23522,23592,23662, + 23731,23801,23870,23938,24007,24075,24143,24211, + 24279,24346,24413,24480,24547,24613,24680,24746, + 24811,24877,24942,25007,25072,25137,25201,25265, + 25329,25393,25456,25519,25582,25645,25708,25770, + 25832,25893,25955,26016,26077,26138,26198,26259, + 26319,26378,26438,26497,26556,26615,26674,26732, + 26790,26848,26905,26962,27019,27076,27133,27189, + 27245,27300,27356,27411,27466,27521,27575,27629, + 27683,27737,27790,27843,27896,27949,28001,28053, + 28105,28157,28208,28259,28310,28360,28411,28460, + 28510,28560,28609,28658,28706,28755,28803,28850, + 28898,28945,28992,29039,29085,29131,29177,29223, + 29268,29313,29358,29403,29447,29491,29534,29578, + 29621,29664,29706,29749,29791,29832,29874,29915, + 29956,29997,30037,30077,30117,30156,30195,30234, + 30273,30311,30349,30387,30424,30462,30498,30535, + 30571,30607,30643,30679,30714,30749,30783,30818, + 30852,30885,30919,30952,30985,31017,31050,31082, + 31113,31145,31176,31206,31237,31267,31297,31327, + 31356,31385,31414,31442,31470,31498,31526,31553, + 31580,31607,31633,31659,31685,31710,31736,31760, + 31785,31809,31833,31857,31880,31903,31926,31949, + 31971,31993,32014,32036,32057,32077,32098,32118, + 32137,32157,32176,32195,32213,32232,32250,32267, + 32285,32302,32318,32335,32351,32367,32382,32397, + 32412,32427,32441,32455,32469,32482,32495,32508, + 32521,32533,32545,32556,32567,32578,32589,32599, + 32609,32619,32628,32637,32646,32655,32663,32671, + 32678,32685,32692,32699,32705,32711,32717,32722, + 32728,32732,32737,32741,32745,32748,32752,32755, + 32757,32759,32761,32763,32765,32766,32766,32767, + 32767,32767,32766,32766,32765,32763,32761,32759, + 32757,32755,32752,32748,32745,32741,32737,32732, + 32728,32722,32717,32711,32705,32699,32692,32685, + 32678,32671,32663,32655,32646,32637,32628,32619, + 32609,32599,32589,32578,32567,32556,32545,32533, + 32521,32508,32495,32482,32469,32455,32441,32427, + 32412,32397,32382,32367,32351,32335,32318,32302, + 32285,32267,32250,32232,32213,32195,32176,32157, + 32137,32118,32098,32077,32057,32036,32014,31993, + 31971,31949,31926,31903,31880,31857,31833,31809, + 31785,31760,31736,31710,31685,31659,31633,31607, + 31580,31553,31526,31498,31470,31442,31414,31385, + 31356,31327,31297,31267,31237,31206,31176,31145, + 31113,31082,31050,31017,30985,30952,30919,30885, + 30852,30818,30783,30749,30714,30679,30643,30607, + 30571,30535,30498,30462,30424,30387,30349,30311, + 30273,30234,30195,30156,30117,30077,30037,29997, + 29956,29915,29874,29832,29791,29749,29706,29664, + 29621,29578,29534,29491,29447,29403,29358,29313, + 29268,29223,29177,29131,29085,29039,28992,28945, + 28898,28850,28803,28755,28706,28658,28609,28560, + 28510,28460,28411,28360,28310,28259,28208,28157, + 28105,28053,28001,27949,27896,27843,27790,27737, + 27683,27629,27575,27521,27466,27411,27356,27300, + 27245,27189,27133,27076,27019,26962,26905,26848, + 26790,26732,26674,26615,26556,26497,26438,26378, + 26319,26259,26198,26138,26077,26016,25955,25893, + 25832,25770,25708,25645,25582,25519,25456,25393, + 25329,25265,25201,25137,25072,25007,24942,24877, + 24811,24746,24680,24613,24547,24480,24413,24346, + 24279,24211,24143,24075,24007,23938,23870,23801, + 23731,23662,23592,23522,23452,23382,23311,23241, + 23170,23099,23027,22956,22884,22812,22739,22667, + 22594,22521,22448,22375,22301,22227,22154,22079, + 22005,21930,21856,21781,21705,21630,21554,21479, + 21403,21326,21250,21173,21096,21019,20942,20865, + 20787,20709,20631,20553,20475,20396,20317,20238, + 20159,20080,20000,19921,19841,19761,19680,19600, + 19519,19438,19357,19276,19195,19113,19032,18950, + 18868,18785,18703,18620,18537,18454,18371,18288, + 18204,18121,18037,17953,17869,17784,17700,17615, + 17530,17445,17360,17275,17189,17104,17018,16932, + 16846,16759,16673,16586,16499,16413,16325,16238, + 16151,16063,15976,15888,15800,15712,15623,15535, + 15446,15358,15269,15180,15090,15001,14912,14822, + 14732,14643,14553,14462,14372,14282,14191,14101, + 14010,13919,13828,13736,13645,13554,13462,13370, + 13279,13187,13094,13002,12910,12817,12725,12632, + 12539,12446,12353,12260,12167,12074,11980,11886, + 11793,11699,11605,11511,11417,11322,11228,11133, + 11039,10944,10849,10754,10659,10564,10469,10374, + 10278,10183,10087,9992,9896,9800,9704,9608, + 9512,9416,9319,9223,9126,9030,8933,8836, + 8739,8642,8545,8448,8351,8254,8157,8059, + 7962,7864,7767,7669,7571,7473,7375,7277, + 7179,7081,6983,6885,6786,6688,6590,6491, + 6393,6294,6195,6096,5998,5899,5800,5701, + 5602,5503,5404,5305,5205,5106,5007,4907, + 4808,4708,4609,4509,4410,4310,4210,4111, + 4011,3911,3811,3712,3612,3512,3412,3312, + 3212,3112,3012,2911,2811,2711,2611,2511, + 2410,2310,2210,2110,2009,1909,1809,1708, + 1608,1507,1407,1307,1206,1106,1005,905, + 804,704,603,503,402,302,201,101, + 0,-101,-201,-302,-402,-503,-603,-704, + -804,-905,-1005,-1106,-1206,-1307,-1407,-1507, + -1608,-1708,-1809,-1909,-2009,-2110,-2210,-2310, + -2410,-2511,-2611,-2711,-2811,-2911,-3012,-3112, + -3212,-3312,-3412,-3512,-3612,-3712,-3811,-3911, + -4011,-4111,-4210,-4310,-4410,-4509,-4609,-4708, + -4808,-4907,-5007,-5106,-5205,-5305,-5404,-5503, + -5602,-5701,-5800,-5899,-5998,-6096,-6195,-6294, + -6393,-6491,-6590,-6688,-6786,-6885,-6983,-7081, + -7179,-7277,-7375,-7473,-7571,-7669,-7767,-7864, + -7962,-8059,-8157,-8254,-8351,-8448,-8545,-8642, + -8739,-8836,-8933,-9030,-9126,-9223,-9319,-9416, + -9512,-9608,-9704,-9800,-9896,-9992,-10087,-10183, + -10278,-10374,-10469,-10564,-10659,-10754,-10849,-10944, + -11039,-11133,-11228,-11322,-11417,-11511,-11605,-11699, + -11793,-11886,-11980,-12074,-12167,-12260,-12353,-12446, + -12539,-12632,-12725,-12817,-12910,-13002,-13094,-13187, + -13279,-13370,-13462,-13554,-13645,-13736,-13828,-13919, + -14010,-14101,-14191,-14282,-14372,-14462,-14553,-14643, + -14732,-14822,-14912,-15001,-15090,-15180,-15269,-15358, + -15446,-15535,-15623,-15712,-15800,-15888,-15976,-16063, + -16151,-16238,-16325,-16413,-16499,-16586,-16673,-16759, + -16846,-16932,-17018,-17104,-17189,-17275,-17360,-17445, + -17530,-17615,-17700,-17784,-17869,-17953,-18037,-18121, + -18204,-18288,-18371,-18454,-18537,-18620,-18703,-18785, + -18868,-18950,-19032,-19113,-19195,-19276,-19357,-19438, + -19519,-19600,-19680,-19761,-19841,-19921,-20000,-20080, + -20159,-20238,-20317,-20396,-20475,-20553,-20631,-20709, + -20787,-20865,-20942,-21019,-21096,-21173,-21250,-21326, + -21403,-21479,-21554,-21630,-21705,-21781,-21856,-21930, + -22005,-22079,-22154,-22227,-22301,-22375,-22448,-22521, + -22594,-22667,-22739,-22812,-22884,-22956,-23027,-23099, + -23170,-23241,-23311,-23382,-23452,-23522,-23592,-23662, + -23731,-23801,-23870,-23938,-24007,-24075,-24143,-24211, + -24279,-24346,-24413,-24480,-24547,-24613,-24680,-24746, + -24811,-24877,-24942,-25007,-25072,-25137,-25201,-25265, + -25329,-25393,-25456,-25519,-25582,-25645,-25708,-25770, + -25832,-25893,-25955,-26016,-26077,-26138,-26198,-26259, + -26319,-26378,-26438,-26497,-26556,-26615,-26674,-26732, + -26790,-26848,-26905,-26962,-27019,-27076,-27133,-27189, + -27245,-27300,-27356,-27411,-27466,-27521,-27575,-27629, + -27683,-27737,-27790,-27843,-27896,-27949,-28001,-28053, + -28105,-28157,-28208,-28259,-28310,-28360,-28411,-28460, + -28510,-28560,-28609,-28658,-28706,-28755,-28803,-28850, + -28898,-28945,-28992,-29039,-29085,-29131,-29177,-29223, + -29268,-29313,-29358,-29403,-29447,-29491,-29534,-29578, + -29621,-29664,-29706,-29749,-29791,-29832,-29874,-29915, + -29956,-29997,-30037,-30077,-30117,-30156,-30195,-30234, + -30273,-30311,-30349,-30387,-30424,-30462,-30498,-30535, + -30571,-30607,-30643,-30679,-30714,-30749,-30783,-30818, + -30852,-30885,-30919,-30952,-30985,-31017,-31050,-31082, + -31113,-31145,-31176,-31206,-31237,-31267,-31297,-31327, + -31356,-31385,-31414,-31442,-31470,-31498,-31526,-31553, + -31580,-31607,-31633,-31659,-31685,-31710,-31736,-31760, + -31785,-31809,-31833,-31857,-31880,-31903,-31926,-31949, + -31971,-31993,-32014,-32036,-32057,-32077,-32098,-32118, + -32137,-32157,-32176,-32195,-32213,-32232,-32250,-32267, + -32285,-32302,-32318,-32335,-32351,-32367,-32382,-32397, + -32412,-32427,-32441,-32455,-32469,-32482,-32495,-32508, + -32521,-32533,-32545,-32556,-32567,-32578,-32589,-32599, + -32609,-32619,-32628,-32637,-32646,-32655,-32663,-32671, + -32678,-32685,-32692,-32699,-32705,-32711,-32717,-32722, + -32728,-32732,-32737,-32741,-32745,-32748,-32752,-32755, + -32757,-32759,-32761,-32763,-32765,-32766,-32766,-32767, + -32767,-32767,-32766,-32766,-32765,-32763,-32761,-32759, + -32757,-32755,-32752,-32748,-32745,-32741,-32737,-32732, + -32728,-32722,-32717,-32711,-32705,-32699,-32692,-32685, + -32678,-32671,-32663,-32655,-32646,-32637,-32628,-32619, + -32609,-32599,-32589,-32578,-32567,-32556,-32545,-32533, + -32521,-32508,-32495,-32482,-32469,-32455,-32441,-32427, + -32412,-32397,-32382,-32367,-32351,-32335,-32318,-32302, + -32285,-32267,-32250,-32232,-32213,-32195,-32176,-32157, + -32137,-32118,-32098,-32077,-32057,-32036,-32014,-31993, + -31971,-31949,-31926,-31903,-31880,-31857,-31833,-31809, + -31785,-31760,-31736,-31710,-31685,-31659,-31633,-31607, + -31580,-31553,-31526,-31498,-31470,-31442,-31414,-31385, + -31356,-31327,-31297,-31267,-31237,-31206,-31176,-31145, + -31113,-31082,-31050,-31017,-30985,-30952,-30919,-30885, + -30852,-30818,-30783,-30749,-30714,-30679,-30643,-30607, + -30571,-30535,-30498,-30462,-30424,-30387,-30349,-30311, + -30273,-30234,-30195,-30156,-30117,-30077,-30037,-29997, + -29956,-29915,-29874,-29832,-29791,-29749,-29706,-29664, + -29621,-29578,-29534,-29491,-29447,-29403,-29358,-29313, + -29268,-29223,-29177,-29131,-29085,-29039,-28992,-28945, + -28898,-28850,-28803,-28755,-28706,-28658,-28609,-28560, + -28510,-28460,-28411,-28360,-28310,-28259,-28208,-28157, + -28105,-28053,-28001,-27949,-27896,-27843,-27790,-27737, + -27683,-27629,-27575,-27521,-27466,-27411,-27356,-27300, + -27245,-27189,-27133,-27076,-27019,-26962,-26905,-26848, + -26790,-26732,-26674,-26615,-26556,-26497,-26438,-26378, + -26319,-26259,-26198,-26138,-26077,-26016,-25955,-25893, + -25832,-25770,-25708,-25645,-25582,-25519,-25456,-25393, + -25329,-25265,-25201,-25137,-25072,-25007,-24942,-24877, + -24811,-24746,-24680,-24613,-24547,-24480,-24413,-24346, + -24279,-24211,-24143,-24075,-24007,-23938,-23870,-23801, + -23731,-23662,-23592,-23522,-23452,-23382,-23311,-23241, + -23170,-23099,-23027,-22956,-22884,-22812,-22739,-22667, + -22594,-22521,-22448,-22375,-22301,-22227,-22154,-22079, + -22005,-21930,-21856,-21781,-21705,-21630,-21554,-21479, + -21403,-21326,-21250,-21173,-21096,-21019,-20942,-20865, + -20787,-20709,-20631,-20553,-20475,-20396,-20317,-20238, + -20159,-20080,-20000,-19921,-19841,-19761,-19680,-19600, + -19519,-19438,-19357,-19276,-19195,-19113,-19032,-18950, + -18868,-18785,-18703,-18620,-18537,-18454,-18371,-18288, + -18204,-18121,-18037,-17953,-17869,-17784,-17700,-17615, + -17530,-17445,-17360,-17275,-17189,-17104,-17018,-16932, + -16846,-16759,-16673,-16586,-16499,-16413,-16325,-16238, + -16151,-16063,-15976,-15888,-15800,-15712,-15623,-15535, + -15446,-15358,-15269,-15180,-15090,-15001,-14912,-14822, + -14732,-14643,-14553,-14462,-14372,-14282,-14191,-14101, + -14010,-13919,-13828,-13736,-13645,-13554,-13462,-13370, + -13279,-13187,-13094,-13002,-12910,-12817,-12725,-12632, + -12539,-12446,-12353,-12260,-12167,-12074,-11980,-11886, + -11793,-11699,-11605,-11511,-11417,-11322,-11228,-11133, + -11039,-10944,-10849,-10754,-10659,-10564,-10469,-10374, + -10278,-10183,-10087,-9992,-9896,-9800,-9704,-9608, + -9512,-9416,-9319,-9223,-9126,-9030,-8933,-8836, + -8739,-8642,-8545,-8448,-8351,-8254,-8157,-8059, + -7962,-7864,-7767,-7669,-7571,-7473,-7375,-7277, + -7179,-7081,-6983,-6885,-6786,-6688,-6590,-6491, + -6393,-6294,-6195,-6096,-5998,-5899,-5800,-5701, + -5602,-5503,-5404,-5305,-5205,-5106,-5007,-4907, + -4808,-4708,-4609,-4509,-4410,-4310,-4210,-4111, + -4011,-3911,-3811,-3712,-3612,-3512,-3412,-3312, + -3212,-3112,-3012,-2911,-2811,-2711,-2611,-2511, + -2410,-2310,-2210,-2110,-2009,-1909,-1809,-1708, + -1608,-1507,-1407,-1307,-1206,-1106,-1005,-905, + -804,-704,-603,-503,-402,-302,-201,-101 +}; +#endif + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_ima_tables.c b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_ima_tables.c new file mode 100755 index 0000000..b03b4d4 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_ima_tables.c @@ -0,0 +1,54 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_ima_tables.c + * + * Contents and purpose: + * Contains the constant tables for IMA encode/decode + * + * Copyright (c) 2005 Sonic Network Inc. + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 760 $ + * $Date: 2007-07-17 23:09:36 -0700 (Tue, 17 Jul 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_types.h" + +/*---------------------------------------------------------------------------- + * ADPCM decode tables + *---------------------------------------------------------------------------- +*/ +const EAS_I16 imaIndexTable[16] = +{ + -1, -1, -1, -1, 2, 4, 6, 8, + -1, -1, -1, -1, 2, 4, 6, 8 +}; + +const EAS_I16 imaStepSizeTable[89] = +{ + 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, + 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, + 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, + 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, + 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, + 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, + 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, + 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, + 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 +}; + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_imaadpcm.c b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_imaadpcm.c new file mode 100755 index 0000000..41280b5 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_imaadpcm.c @@ -0,0 +1,368 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_imaadpcm.c + * + * Contents and purpose: + * Implements the IMA ADPCM decoder + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 847 $ + * $Date: 2007-08-27 21:30:08 -0700 (Mon, 27 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_data.h" +#include "eas_host.h" +#include "eas_pcm.h" +#include "eas_math.h" +#include "eas_report.h" + +// #define _DEBUG_IMA_ADPCM_LOCATE + +/*---------------------------------------------------------------------------- + * externs + *---------------------------------------------------------------------------- +*/ +extern const EAS_I16 imaIndexTable[]; +extern const EAS_I16 imaStepSizeTable[]; + +/*---------------------------------------------------------------------------- + * prototypes + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT IMADecoderInit (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState); +static EAS_RESULT IMADecoderSample (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState); +static void IMADecoderADPCM (S_DECODER_STATE *pState, EAS_U8 nibble); +static EAS_RESULT IMADecoderLocate (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState, EAS_I32 time); + +/*---------------------------------------------------------------------------- + * IMA ADPCM Decoder interface + *---------------------------------------------------------------------------- +*/ +const S_DECODER_INTERFACE IMADecoder = +{ + IMADecoderInit, + IMADecoderSample, + IMADecoderLocate +}; + +/*---------------------------------------------------------------------------- + * IMADecoderInit() + *---------------------------------------------------------------------------- + * Purpose: + * Initializes the IMA ADPCM decoder + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ +static EAS_RESULT IMADecoderInit (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState) +{ + pState->decoderL.step = 0; + pState->decoderR.step = 0; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMADecoderSample() + *---------------------------------------------------------------------------- + * Purpose: + * Decodes an IMA ADPCM sample + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT IMADecoderSample (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState) +{ + EAS_RESULT result; + EAS_I16 sTemp; + + /* if high nibble, decode */ + if (pState->hiNibble) + { + IMADecoderADPCM(&pState->decoderL, (EAS_U8)(pState->srcByte >> 4)); + pState->hiNibble = EAS_FALSE; + } + + /* low nibble, need to fetch another byte */ + else + { + /* check for loop */ + if ((pState->bytesLeft == 0) && (pState->loopSamples != 0)) + { + /* seek to start of loop */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pState->fileHandle, (EAS_I32) (pState->startPos + pState->loopLocation))) != EAS_SUCCESS) + return result; + pState->bytesLeft = pState->byteCount = (EAS_I32) pState->bytesLeftLoop; + pState->blockCount = 0; + pState->flags &= ~PCM_FLAGS_EMPTY; + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMADecoderSample: Rewind file to %d, bytesLeft = %d\n", pState->startPos, pState->bytesLeft); */ } + } + + /* if start of block, fetch new predictor and step index */ + if ((pState->blockSize != 0) && (pState->blockCount == 0) && (pState->bytesLeft != 0)) + { + + /* get predicted sample for left channel */ + if ((result = EAS_HWGetWord(pEASData->hwInstData, pState->fileHandle, &sTemp, EAS_FALSE)) != EAS_SUCCESS) + return result; +#ifdef _DEBUG_IMA_ADPCM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Predictor: Was %d, now %d\n", pState->decoderL.acc, sTemp); */ } +#endif + pState->decoderL.acc = pState->decoderL.x1 = sTemp; + + /* get step index for left channel - upper 8 bits are reserved */ + if ((result = EAS_HWGetWord(pEASData->hwInstData, pState->fileHandle, &sTemp, EAS_FALSE)) != EAS_SUCCESS) + return result; +#ifdef _DEBUG_IMA_ADPCM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Step: Was %d, now %d\n", pState->decoderL.step, sTemp); */ } +#endif + pState->decoderL.step = sTemp & 0xff; + + if (pState->flags & PCM_FLAGS_STEREO) + { + /* get predicted sample for right channel */ + if ((result = EAS_HWGetWord(pEASData->hwInstData, pState->fileHandle, &sTemp, EAS_FALSE)) != EAS_SUCCESS) + return result; + pState->decoderR.acc = pState->decoderR.x1 = sTemp; + + /* get step index for right channel - upper 8 bits are reserved */ + if ((result = EAS_HWGetWord(pEASData->hwInstData, pState->fileHandle, &sTemp, EAS_FALSE)) != EAS_SUCCESS) + return result; +#ifdef _DEBUG_IMA_ADPCM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Step: Was %d, now %d\n", pState->decoderR.step, sTemp); */ } +#endif + pState->decoderR.step = sTemp & 0xff; + + pState->blockCount = pState->blockSize - 8; + pState->bytesLeft -= 8; + } + else + { + pState->blockCount = pState->blockSize - 4; + pState->bytesLeft -= 4; + } + } + else + { + + /* get another ADPCM data pair */ + if (pState->bytesLeft) + { + + if ((result = EAS_HWGetByte(pEASData->hwInstData, pState->fileHandle, &pState->srcByte)) != EAS_SUCCESS) + return result; + + /* decode the low nibble */ + pState->bytesLeft--; + pState->blockCount--; + IMADecoderADPCM(&pState->decoderL, (EAS_U8)(pState->srcByte & 0x0f)); + + if (pState->flags & PCM_FLAGS_STEREO) + IMADecoderADPCM(&pState->decoderR, (EAS_U8)(pState->srcByte >> 4)); + else + pState->hiNibble = EAS_TRUE; + } + + /* out of ADPCM data, generate enough samples to fill buffer */ + else + { + pState->decoderL.x1 = pState->decoderL.x0; + pState->decoderR.x1 = pState->decoderR.x0; + } + } + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMADecoderADPCM() + *---------------------------------------------------------------------------- + * Purpose: + * Decodes an IMA ADPCM sample + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static void IMADecoderADPCM (S_DECODER_STATE *pState, EAS_U8 nibble) +{ + EAS_INT delta; + EAS_INT stepSize; + + /* get stepsize from table */ + stepSize = imaStepSizeTable[pState->step]; + + /* delta = (abs(delta) + 0.5) * step / 4 */ + delta = 0; + if (nibble & 4) + delta += stepSize; + + if (nibble & 2) + /*lint -e{702} use shift for performance */ + delta += stepSize >> 1; + + if (nibble & 1) + /*lint -e{702} use shift for performance */ + delta += stepSize >> 2; + + /*lint -e{702} use shift for performance */ + delta += stepSize >> 3; + + /* integrate the delta */ + if (nibble & 8) + pState->acc -= delta; + else + pState->acc += delta; + + /* saturate */ + if (pState->acc > 32767) + pState->acc = 32767; + if (pState->acc < -32768) + pState->acc = -32768; + pState->x1 = (EAS_PCM) pState->acc; + + /* compute new step size */ + pState->step += imaIndexTable[nibble]; + if (pState->step < 0) + pState->step = 0; + if (pState->step > 88) + pState->step = 88; + +#ifdef _DEBUG_IMA_ADPCM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "In=%u, Pred=%d, Step=%d\n", nibble, pState->acc, imaStepSizeTable[pState->step]); */ } +#endif +} + +/*---------------------------------------------------------------------------- + * IMADecoderLocate() + *---------------------------------------------------------------------------- + * Locate in an IMA ADPCM stream + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT IMADecoderLocate (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState, EAS_I32 time) +{ + EAS_RESULT result; + EAS_I32 temp; + EAS_I32 samplesPerBlock; + EAS_I32 secs, msecs; + + /* no need to calculate if time is zero */ + if (time == 0) + temp = 0; + + /* not zero */ + else + { + + /* can't seek if not a blocked file */ + if (pState->blockSize == 0) + return EAS_ERROR_FEATURE_NOT_AVAILABLE; + + /* calculate number of samples per block */ + if (pState->flags & PCM_FLAGS_STEREO) + samplesPerBlock = pState->blockSize - 7; + else + samplesPerBlock = (pState->blockSize << 1) - 7; + + /* break down into secs and msecs */ + secs = time / 1000; + msecs = time - (secs * 1000); + + /* calculate sample number fraction from msecs */ + temp = (msecs * pState->sampleRate); + temp = (temp >> 10) + ((temp * 49) >> 21); + + /* add integer sample count */ + temp += secs * pState->sampleRate; + +#ifdef _DEBUG_IMA_ADPCM_LOCATE + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x2380b977, 0x00000006 , time, temp); +#endif + + /* for looped samples, calculate position in the loop */ + if ((temp > pState->byteCount) && (pState->loopSamples != 0)) + { + EAS_I32 numBlocks; + EAS_I32 samplesPerLoop; + EAS_I32 samplesInLastBlock; + + numBlocks = (EAS_I32) (pState->loopStart / pState->blockSize); + samplesInLastBlock = (EAS_I32) pState->loopStart - (numBlocks * pState->blockSize); + if (samplesInLastBlock) + { + if (pState->flags & PCM_FLAGS_STEREO) + samplesInLastBlock = samplesInLastBlock - 7; + else + /*lint -e{703} use shift for performance */ + samplesInLastBlock = (samplesInLastBlock << 1) - 7; + } + samplesPerLoop = numBlocks * samplesPerBlock + samplesInLastBlock; + temp = temp % samplesPerLoop; +#ifdef _DEBUG_IMA_ADPCM_LOCATE + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x2380b977, 0x00000007 , numBlocks, samplesPerLoop, samplesInLastBlock, temp); +#endif + } + + /* find start of block for requested sample */ + temp = (temp / samplesPerBlock) * pState->blockSize; +#ifdef _DEBUG_IMA_ADPCM_LOCATE + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x2380b977, 0x00000008 , temp); +#endif + + } + + /* seek to new location */ + if ((result = EAS_PESeek(pEASData, pState, &temp)) != EAS_SUCCESS) + return result; + +#ifdef _DEBUG_IMA_ADPCM_LOCATE + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x2380b977, 0x00000009 , pState->bytesLeft); +#endif + + /* reset state */ + pState->blockCount = 0; + pState->hiNibble = EAS_FALSE; + if ((pState->state != EAS_STATE_PAUSING) && (pState->state != EAS_STATE_PAUSED)) + pState->state = EAS_STATE_READY; + + return EAS_SUCCESS; +} + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_imelody.c b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_imelody.c new file mode 100755 index 0000000..698c7df --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_imelody.c @@ -0,0 +1,1738 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_imelody.c + * + * Contents and purpose: + * iMelody parser + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 797 $ + * $Date: 2007-08-01 00:15:56 -0700 (Wed, 01 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +/* lint doesn't like the way some string.h files look */ +#ifdef _lint +#include "lint_stdlib.h" +#else +#include +#endif + +#include "eas_data.h" +#include "eas_miditypes.h" +#include "eas_parser.h" +#include "eas_report.h" +#include "eas_host.h" +#include "eas_midi.h" +#include "eas_config.h" +#include "eas_vm_protos.h" +#include "eas_imelodydata.h" +#include "eas_ctype.h" + +// #define _DEBUG_IMELODY + +/* increase gain for mono ringtones */ +#define IMELODY_GAIN_OFFSET 8 + +/* length of 32nd note in 1/256ths of a msec for 120 BPM tempo */ +#define DEFAULT_TICK_CONV 16000 +#define TICK_CONVERT 1920000 + +/* default channel and program for iMelody playback */ +#define IMELODY_CHANNEL 0 +#define IMELODY_PROGRAM 80 +#define IMELODY_VEL_MUL 4 +#define IMELODY_VEL_OFS 67 + +/* multiplier for fixed point triplet conversion */ +#define TRIPLET_MULTIPLIER 683 +#define TRIPLET_SHIFT 10 + +static const char* const tokens[] = +{ + "BEGIN:IMELODY", + "VERSION:", + "FORMAT:CLASS", + "NAME:", + "COMPOSER:", + "BEAT:", + "STYLE:", + "VOLUME:", + "MELODY:", + "END:IMELODY" +}; + +/* ledon or ledoff */ +static const char ledStr[] = "edo"; + +/* vibeon or vibeoff */ +static const char vibeStr[] = "ibeo"; + +/* backon or backoff */ +static const char backStr[] = "cko"; + +typedef enum +{ + TOKEN_BEGIN, + TOKEN_VERSION, + TOKEN_FORMAT, + TOKEN_NAME, + TOKEN_COMPOSER, + TOKEN_BEAT, + TOKEN_STYLE, + TOKEN_VOLUME, + TOKEN_MELODY, + TOKEN_END, + TOKEN_INVALID +} ENUM_IMELODY_TOKENS; + +/* lookup table for note values */ +static const EAS_I8 noteTable[] = { 9, 11, 0, 2, 4, 5, 7 }; + +/* inline functions */ +#ifdef _DEBUG_IMELODY +static void PutBackChar (S_IMELODY_DATA *pData) +{ + if (pData->index) + pData->index--; + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "PutBackChar '%c'\n", pData->buffer[pData->index]); */ } +} +#else +EAS_INLINE void PutBackChar (S_IMELODY_DATA *pData) { if (pData->index) pData->index--; } +#endif + + +/* local prototypes */ +static EAS_RESULT IMY_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset); +static EAS_RESULT IMY_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT IMY_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime); +static EAS_RESULT IMY_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode); +static EAS_RESULT IMY_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_STATE *pState); +static EAS_RESULT IMY_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT IMY_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT IMY_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT IMY_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT IMY_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value); +static EAS_RESULT IMY_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue); +static EAS_BOOL IMY_PlayNote (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData, EAS_I8 note, EAS_INT parserMode); +static EAS_BOOL IMY_PlayRest (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData); +static EAS_BOOL IMY_GetDuration (EAS_HW_DATA_HANDLE hwInstData, S_IMELODY_DATA *pData, EAS_I32 *pDuration); +static EAS_BOOL IMY_GetLEDState (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData); +static EAS_BOOL IMY_GetVibeState (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData); +static EAS_BOOL IMY_GetBackState (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData); +static EAS_BOOL IMY_GetVolume (EAS_HW_DATA_HANDLE hwInstData, S_IMELODY_DATA *pData, EAS_BOOL inHeader); +static EAS_BOOL IMY_GetNumber (EAS_HW_DATA_HANDLE hwInstData, S_IMELODY_DATA *pData, EAS_INT *temp, EAS_BOOL inHeader); +static EAS_RESULT IMY_ParseHeader (S_EAS_DATA *pEASData, S_IMELODY_DATA* pData); +static EAS_I8 IMY_GetNextChar (EAS_HW_DATA_HANDLE hwInstData, S_IMELODY_DATA *pData, EAS_BOOL inHeader); +static EAS_RESULT IMY_ReadLine (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle, EAS_I8 *buffer, EAS_I32 *pStartLine); +static EAS_INT IMY_ParseLine (EAS_I8 *buffer, EAS_U8 *pIndex); + + +/*---------------------------------------------------------------------------- + * + * EAS_iMelody_Parser + * + * This structure contains the functional interface for the iMelody parser + *---------------------------------------------------------------------------- +*/ +const S_FILE_PARSER_INTERFACE EAS_iMelody_Parser = +{ + IMY_CheckFileType, + IMY_Prepare, + IMY_Time, + IMY_Event, + IMY_State, + IMY_Close, + IMY_Reset, + IMY_Pause, + IMY_Resume, + NULL, + IMY_SetData, + IMY_GetData, + NULL +}; + +/*---------------------------------------------------------------------------- + * IMY_CheckFileType() + *---------------------------------------------------------------------------- + * Purpose: + * Check the file type to see if we can parse it + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT IMY_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset) +{ + S_IMELODY_DATA* pData; + EAS_I8 buffer[MAX_LINE_SIZE+1]; + EAS_U8 index; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_CheckFileType\n"); */ } +#endif + + /* read the first line of the file */ + *ppHandle = NULL; + if (IMY_ReadLine(pEASData->hwInstData, fileHandle, buffer, NULL) != EAS_SUCCESS) + return EAS_SUCCESS; + + /* check for header string */ + if (IMY_ParseLine(buffer, &index) == TOKEN_BEGIN) + { + + /* check for static memory allocation */ + if (pEASData->staticMemoryModel) + pData = EAS_CMEnumData(EAS_CM_IMELODY_DATA); + else + pData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_IMELODY_DATA)); + if (!pData) + return EAS_ERROR_MALLOC_FAILED; + EAS_HWMemSet(pData, 0, sizeof(S_IMELODY_DATA)); + + /* initialize */ + pData->fileHandle = fileHandle; + pData->fileOffset = offset; + pData->state = EAS_STATE_ERROR; + pData->state = EAS_STATE_OPEN; + + /* return a pointer to the instance data */ + *ppHandle = pData; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMY_Prepare() + *---------------------------------------------------------------------------- + * Purpose: + * Prepare to parse the file. Allocates instance data (or uses static allocation for + * static memory model). + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT IMY_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_IMELODY_DATA* pData; + EAS_RESULT result; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_Prepare\n"); */ } +#endif + + /* check for valid state */ + pData = (S_IMELODY_DATA*) pInstData; + if (pData->state != EAS_STATE_OPEN) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + /* instantiate a synthesizer */ + if ((result = VMInitMIDI(pEASData, &pData->pSynth)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitMIDI returned %d\n", result); */ } + return result; + } + + /* parse the header */ + if ((result = IMY_ParseHeader(pEASData, pData)) != EAS_SUCCESS) + return result; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Prepare: state set to EAS_STATE_READY\n"); */ } +#endif + + pData ->state = EAS_STATE_READY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMY_Time() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the time of the next event in msecs + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * pTime - pointer to variable to hold time of next event (in msecs) + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ +static EAS_RESULT IMY_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime) +{ + S_IMELODY_DATA *pData; + + pData = (S_IMELODY_DATA*) pInstData; + + /* return time in milliseconds */ + /*lint -e{704} use shift instead of division */ + *pTime = pData->time >> 8; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMY_Event() + *---------------------------------------------------------------------------- + * Purpose: + * Parse the next event in the file + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT IMY_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode) +{ + S_IMELODY_DATA* pData; + EAS_RESULT result; + EAS_I8 c; + EAS_BOOL eof; + EAS_INT temp; + + pData = (S_IMELODY_DATA*) pInstData; + if (pData->state >= EAS_STATE_OPEN) + return EAS_SUCCESS; + + /* initialize MIDI channel when the track starts playing */ + if (pData->time == 0) + { + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Event: Reset\n"); */ } +#endif + /* set program to square lead */ + VMProgramChange(pEASData->pVoiceMgr, pData->pSynth, IMELODY_CHANNEL, IMELODY_PROGRAM); + + /* set channel volume to max */ + VMControlChange(pEASData->pVoiceMgr, pData->pSynth, IMELODY_CHANNEL, 7, 127); + } + + /* check for end of note */ + if (pData->note) + { + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Stopping note %d\n", pData->note); */ } +#endif + /* stop the note */ + VMStopNote(pEASData->pVoiceMgr, pData->pSynth, IMELODY_CHANNEL, pData->note, 0); + pData->note = 0; + + /* check for rest between notes */ + if (pData->restTicks) + { + pData->time += pData->restTicks; + pData->restTicks = 0; + return EAS_SUCCESS; + } + } + + /* parse the next event */ + eof = EAS_FALSE; + while (!eof) + { + + /* get next character */ + c = IMY_GetNextChar(pEASData->hwInstData, pData, EAS_FALSE); + + switch (c) + { + /* start repeat */ + case '(': + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter repeat section\n", c); */ } +#endif + + if (pData->repeatOffset < 0) + { + pData->repeatOffset = pData->startLine + (EAS_I32) pData->index; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Repeat offset = %d\n", pData->repeatOffset); */ } +#endif + } + else + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Ignoring nested repeat section\n"); */ } + break; + + /* end repeat */ + case ')': + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "End repeat section, repeat offset = %d\n", pData->repeatOffset); */ } +#endif + /* ignore invalid repeats */ + if (pData->repeatCount >= 0) + { + + /* decrement repeat count (repeatCount == 0 means infinite loop) */ + if (pData->repeatCount > 0) + { + if (--pData->repeatCount == 0) + { + pData->repeatCount = -1; +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Repeat loop complete\n"); */ } +#endif + } + } + +//2 TEMPORARY FIX: If locating, don't do infinite loops. +//3 We need a different mode for metadata parsing where we don't loop at all + if ((parserMode == eParserModePlay) || (pData->repeatCount != 0)) + { + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Rewinding file for repeat\n"); */ } +#endif + /* rewind to start of loop */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pData->fileHandle, pData->repeatOffset)) != EAS_SUCCESS) + return result; + IMY_ReadLine(pEASData->hwInstData, pData->fileHandle, pData->buffer, &pData->startLine); + pData->index = 0; + + /* if last loop, prevent future loops */ + if (pData->repeatCount == -1) + pData->repeatOffset = -1; + } + } + break; + + /* repeat count */ + case '@': + if (!IMY_GetNumber(pEASData->hwInstData, pData, &temp, EAS_FALSE)) + eof = EAS_TRUE; + else if (pData->repeatOffset > 0) + { + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Repeat count = %dt", pData->repeatCount); */ } +#endif + if (pData->repeatCount < 0) + pData->repeatCount = (EAS_I16) temp; + } + break; + + /* volume */ + case 'V': + if (!IMY_GetVolume(pEASData->hwInstData, pData, EAS_FALSE)) + eof = EAS_TRUE; + break; + + /* flat */ + case '&': + pData->noteModifier = -1; + break; + + /* sharp */ + case '#': + pData->noteModifier = +1; + break; + + /* octave */ + case '*': + c = IMY_GetNextChar(pEASData->hwInstData, pData, EAS_FALSE); + if (IsDigit(c)) + pData->octave = (EAS_U8) ((c - '0' + 1) * 12); + else if (!c) + eof = EAS_TRUE; + break; + + /* ledon or ledoff */ + case 'l': + if (!IMY_GetLEDState(pEASData, pData)) + eof = EAS_TRUE; + break; + + /* vibeon or vibeoff */ + case 'v': + if (!IMY_GetVibeState(pEASData, pData)) + eof = EAS_TRUE; + break; + + /* either a B note or backon or backoff */ + case 'b': + if (IMY_GetNextChar(pEASData->hwInstData, pData, EAS_FALSE) == 'a') + { + if (!IMY_GetBackState(pEASData, pData)) + eof = EAS_TRUE; + } + else + { + PutBackChar(pData); + if (IMY_PlayNote(pEASData, pData, c, parserMode)) + return EAS_SUCCESS; + eof = EAS_TRUE; + } + break; + + /* rest */ + case 'r': + case 'R': + if (IMY_PlayRest(pEASData, pData)) + return EAS_SUCCESS; + eof = EAS_TRUE; + break; + + /* EOF */ + case 0: +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Event: end of iMelody file detected\n"); */ } +#endif + eof = EAS_TRUE; + break; + + /* must be a note */ + default: + c = ToLower(c); + if ((c >= 'a') && (c <= 'g')) + { + if (IMY_PlayNote(pEASData, pData, c, parserMode)) + return EAS_SUCCESS; + eof = EAS_TRUE; + } + else + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Ignoring unexpected character '%c' [0x%02x]\n", c, c); */ } + break; + } + } + + /* handle EOF */ +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Event: state set to EAS_STATE_STOPPING\n"); */ } +#endif + pData->state = EAS_STATE_STOPPING; + VMReleaseAllVoices(pEASData->pVoiceMgr, pData->pSynth); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMY_State() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current state of the stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * pState - pointer to variable to store state + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ +static EAS_RESULT IMY_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pState) +{ + S_IMELODY_DATA* pData; + + /* establish pointer to instance data */ + pData = (S_IMELODY_DATA*) pInstData; + + /* if stopping, check to see if synth voices are active */ + if (pData->state == EAS_STATE_STOPPING) + { + if (VMActiveVoices(pData->pSynth) == 0) + { + pData->state = EAS_STATE_STOPPED; +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_State: state set to EAS_STATE_STOPPED\n"); */ } +#endif + } + } + + if (pData->state == EAS_STATE_PAUSING) + { + if (VMActiveVoices(pData->pSynth) == 0) + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_State: state set to EAS_STATE_PAUSED\n"); */ } +#endif + pData->state = EAS_STATE_PAUSED; + } + } + + /* return current state */ + *pState = pData->state; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMY_Close() + *---------------------------------------------------------------------------- + * Purpose: + * Close the file and clean up + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT IMY_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_IMELODY_DATA* pData; + EAS_RESULT result; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Close: close file\n"); */ } +#endif + + pData = (S_IMELODY_DATA*) pInstData; + + /* close the file */ + if ((result = EAS_HWCloseFile(pEASData->hwInstData, pData->fileHandle)) != EAS_SUCCESS) + return result; + + /* free the synth */ + if (pData->pSynth != NULL) + VMMIDIShutdown(pEASData, pData->pSynth); + + /* if using dynamic memory, free it */ + if (!pEASData->staticMemoryModel) + EAS_HWFree(pEASData->hwInstData, pData); + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMY_Reset() + *---------------------------------------------------------------------------- + * Purpose: + * Reset the sequencer. Used for locating backwards in the file. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT IMY_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_IMELODY_DATA* pData; + EAS_RESULT result; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Reset: reset file\n"); */ } +#endif + pData = (S_IMELODY_DATA*) pInstData; + + /* reset the synth */ + VMReset(pEASData->pVoiceMgr, pData->pSynth, EAS_TRUE); + + /* reset time to zero */ + pData->time = 0; + pData->note = 0; + + /* reset file position and re-parse header */ + pData->state = EAS_STATE_ERROR; + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pData->fileHandle, pData->fileOffset)) != EAS_SUCCESS) + return result; + if ((result = IMY_ParseHeader (pEASData, pData)) != EAS_SUCCESS) + return result; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Reset: state set to EAS_STATE_ERROR\n"); */ } +#endif + + pData->state = EAS_STATE_READY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMY_Pause() + *---------------------------------------------------------------------------- + * Purpose: + * Pauses the sequencer. Mutes all voices and sets state to pause. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT IMY_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_IMELODY_DATA *pData; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Pause: pause file\n"); */ } +#endif + + /* can't pause a stopped stream */ + pData = (S_IMELODY_DATA*) pInstData; + if (pData->state == EAS_STATE_STOPPED) + return EAS_ERROR_ALREADY_STOPPED; + + /* mute the synthesizer */ + VMMuteAllVoices(pEASData->pVoiceMgr, pData->pSynth); + pData->state = EAS_STATE_PAUSING; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMY_Resume() + *---------------------------------------------------------------------------- + * Purpose: + * Resume playing after a pause, sets state back to playing. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ +static EAS_RESULT IMY_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_IMELODY_DATA *pData; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Resume: resume file\n"); */ } +#endif + + /* can't resume a stopped stream */ + pData = (S_IMELODY_DATA*) pInstData; + if (pData->state == EAS_STATE_STOPPED) + return EAS_ERROR_ALREADY_STOPPED; + + /* nothing to do but resume playback */ + pData->state = EAS_STATE_PLAY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMY_SetData() + *---------------------------------------------------------------------------- + * Purpose: + * Adjust tempo relative to song tempo + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * pInstData - pointer to iMelody instance data + * rate - rate (28-bit fractional amount) + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ +static EAS_RESULT IMY_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value) +{ + S_IMELODY_DATA *pData; + + pData = (S_IMELODY_DATA*) pInstData; + switch (param) + { + + /* set metadata callback */ + case PARSER_DATA_METADATA_CB: + EAS_HWMemCpy(&pData->metadata, (void*) value, sizeof(S_METADATA_CB)); + break; + + default: + return EAS_ERROR_INVALID_PARAMETER; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMY_GetData() + *---------------------------------------------------------------------------- + * Purpose: + * Return the file type + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * pInstData - pointer to iMelody instance data + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ +static EAS_RESULT IMY_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue) +{ + S_IMELODY_DATA *pData; + + pData = (S_IMELODY_DATA*) pInstData; + + switch (param) + { + /* return file type as iMelody */ + case PARSER_DATA_FILE_TYPE: + *pValue = EAS_FILE_IMELODY; + break; + + case PARSER_DATA_SYNTH_HANDLE: + *pValue = (EAS_I32) pData->pSynth; + break; + + case PARSER_DATA_GAIN_OFFSET: + *pValue = IMELODY_GAIN_OFFSET; + break; + + default: + return EAS_ERROR_INVALID_PARAMETER; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMY_PlayNote() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL IMY_PlayNote (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData, EAS_I8 note, EAS_INT parserMode) +{ + EAS_I32 duration; + EAS_U8 velocity; + + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_PlayNote: start note %d\n", note); */ } +#endif + + /* get the duration */ + if (!IMY_GetDuration(pEASData->hwInstData, pData, &duration)) + return EAS_FALSE; + + /* save note value */ + pData->note = (EAS_U8) (pData->octave + noteTable[note - 'a'] + pData->noteModifier); + velocity = (EAS_U8) (pData->volume ? pData->volume * IMELODY_VEL_MUL + IMELODY_VEL_OFS : 0); + + /* start note only if in play mode */ + if (parserMode == eParserModePlay) + VMStartNote(pEASData->pVoiceMgr, pData->pSynth, IMELODY_CHANNEL, pData->note, velocity); + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_PlayNote: Start note %d, duration %d\n", pData->note, duration); */ } +#endif + + /* determine note length */ + switch (pData->style) + { + case 0: + /*lint -e{704} shift for performance */ + pData->restTicks = duration >> 4; + break; + case 1: + pData->restTicks = 0; + break; + case 2: + /*lint -e{704} shift for performance */ + pData->restTicks = duration >> 1; + break; + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "IMY_PlayNote: Note style out of range: %d\n", pData->style); */ } + /*lint -e{704} shift for performance */ + pData->restTicks = duration >> 4; + break; + } + + /* next event is at end of this note */ + pData->time += duration - pData->restTicks; + + /* reset the flat/sharp modifier */ + pData->noteModifier = 0; + + return EAS_TRUE; +} + +/*---------------------------------------------------------------------------- + * IMY_PlayRest() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL IMY_PlayRest (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData) +{ + EAS_I32 duration; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_PlayRest]n"); */ } +#endif + + /* get the duration */ + if (!IMY_GetDuration(pEASData->hwInstData, pData, &duration)) + return EAS_FALSE; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_PlayRest: note duration %d\n", duration); */ } +#endif + + /* next event is at end of this note */ + pData->time += duration; + return EAS_TRUE; +} + +/*---------------------------------------------------------------------------- + * IMY_GetDuration() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ + +static EAS_BOOL IMY_GetDuration (EAS_HW_DATA_HANDLE hwInstData, S_IMELODY_DATA *pData, EAS_I32 *pDuration) +{ + EAS_I32 duration; + EAS_I8 c; + + /* get the duration */ + *pDuration = 0; + c = IMY_GetNextChar(hwInstData, pData, EAS_FALSE); + if (!c) + return EAS_FALSE; + if ((c < '0') || (c > '5')) + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetDuration: error in duration '%c'\n", c); */ } +#endif + return EAS_FALSE; + } + + /* calculate total length of note */ + duration = pData->tick * (1 << ('5' - c)); + + /* check for duration modifier */ + c = IMY_GetNextChar(hwInstData, pData, EAS_FALSE); + if (c) + { + if (c == '.') + /*lint -e{704} shift for performance */ + duration += duration >> 1; + else if (c == ':') + /*lint -e{704} shift for performance */ + duration += (duration >> 1) + (duration >> 2); + else if (c == ';') + /*lint -e{704} shift for performance */ + duration = (duration * TRIPLET_MULTIPLIER) >> TRIPLET_SHIFT; + else + PutBackChar(pData); + } + + *pDuration = duration; + return EAS_TRUE; +} + +/*---------------------------------------------------------------------------- + * IMY_GetLEDState() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL IMY_GetLEDState (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData) +{ + EAS_I8 c; + EAS_INT i; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_GetLEDState\n"); */ } +#endif + + for (i = 0; i < 5; i++) + { + c = IMY_GetNextChar(pEASData->hwInstData, pData, EAS_FALSE); + if (!c) + return EAS_FALSE; + switch (i) + { + case 3: + if (c == 'n') + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetLEDState: LED on\n"); */ } +#endif + EAS_HWLED(pEASData->hwInstData, EAS_TRUE); + return EAS_TRUE; + } + else if (c != 'f') + return EAS_FALSE; + break; + + case 4: + if (c == 'f') + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetLEDState: LED off\n"); */ } +#endif + EAS_HWLED(pEASData->hwInstData, EAS_FALSE); + return EAS_TRUE; + } + return EAS_FALSE; + + default: + if (c != ledStr[i]) + return EAS_FALSE; + break; + } + } + return EAS_FALSE; +} + +/*---------------------------------------------------------------------------- + * IMY_GetVibeState() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL IMY_GetVibeState (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData) +{ + EAS_I8 c; + EAS_INT i; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_GetVibeState\n"); */ } +#endif + + for (i = 0; i < 6; i++) + { + c = IMY_GetNextChar(pEASData->hwInstData, pData, EAS_FALSE); + if (!c) + return EAS_FALSE; + switch (i) + { + case 4: + if (c == 'n') + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetVibeState: vibrate on\n"); */ } +#endif + EAS_HWVibrate(pEASData->hwInstData, EAS_TRUE); + return EAS_TRUE; + } + else if (c != 'f') + return EAS_FALSE; + break; + + case 5: + if (c == 'f') + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetVibeState: vibrate off\n"); */ } +#endif + EAS_HWVibrate(pEASData->hwInstData, EAS_FALSE); + return EAS_TRUE; + } + return EAS_FALSE; + + default: + if (c != vibeStr[i]) + return EAS_FALSE; + break; + } + } + return EAS_FALSE; +} + +/*---------------------------------------------------------------------------- + * IMY_GetBackState() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL IMY_GetBackState (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData) +{ + EAS_I8 c; + EAS_INT i; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_GetBackState\n"); */ } +#endif + + for (i = 0; i < 5; i++) + { + c = IMY_GetNextChar(pEASData->hwInstData, pData, EAS_FALSE); + if (!c) + return EAS_FALSE; + switch (i) + { + case 3: + if (c == 'n') + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetBackState: backlight on\n"); */ } +#endif + EAS_HWBackLight(pEASData->hwInstData, EAS_TRUE); + return EAS_TRUE; + } + else if (c != 'f') + return EAS_FALSE; + break; + + case 4: + if (c == 'f') + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetBackState: backlight off\n"); */ } +#endif + EAS_HWBackLight(pEASData->hwInstData, EAS_FALSE); + return EAS_TRUE; + } + return EAS_FALSE; + + default: + if (c != backStr[i]) + return EAS_FALSE; + break; + } + } + return EAS_FALSE; +} + +/*---------------------------------------------------------------------------- + * IMY_GetVolume() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL IMY_GetVolume (EAS_HW_DATA_HANDLE hwInstData, S_IMELODY_DATA *pData, EAS_BOOL inHeader) +{ + EAS_INT temp; + EAS_I8 c; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_GetVolume\n"); */ } +#endif + + c = IMY_GetNextChar(hwInstData, pData, inHeader); + if (c == '+') + { + if (pData->volume < 15) + pData->volume++; + return EAS_TRUE; + } + else if (c == '-') + { + if (pData->volume > 0) + pData->volume--; + return EAS_TRUE; + } + else if (IsDigit(c)) + temp = c - '0'; + else + return EAS_FALSE; + + c = IMY_GetNextChar(hwInstData, pData, inHeader); + if (IsDigit(c)) + temp = temp * 10 + c - '0'; + else if (c) + PutBackChar(pData); + if ((temp >= 0) && (temp <= 15)) + { + if (inHeader && (temp == 0)) + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Ignoring V0 encountered in header\n"); */ } + else + pData->volume = (EAS_U8) temp; + } + return EAS_TRUE; +} + +/*---------------------------------------------------------------------------- + * IMY_GetNumber() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL IMY_GetNumber (EAS_HW_DATA_HANDLE hwInstData, S_IMELODY_DATA *pData, EAS_INT *temp, EAS_BOOL inHeader) +{ + EAS_BOOL ok; + EAS_I8 c; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_GetNumber\n"); */ } +#endif + + *temp = 0; + ok = EAS_FALSE; + for (;;) + { + c = IMY_GetNextChar(hwInstData, pData, inHeader); + if (IsDigit(c)) + { + *temp = *temp * 10 + c - '0'; + ok = EAS_TRUE; + } + else + { + if (c) + PutBackChar(pData); + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetNumber: value %d\n", *temp); */ } +#endif + + return ok; + } + } +} + +/*---------------------------------------------------------------------------- + * IMY_GetVersion() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL IMY_GetVersion (S_IMELODY_DATA *pData, EAS_INT *pVersion) +{ + EAS_I8 c; + EAS_INT temp; + EAS_INT version; + + version = temp = 0; + for (;;) + { + c = pData->buffer[pData->index++]; + if ((c == 0) || (c == '.')) + { + /*lint -e{701} use shift for performance */ + version = (version << 8) + temp; + if (c == 0) + { + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetVersion: version 0x%04x\n", version); */ } +#endif + + *pVersion = version; + return EAS_TRUE; + } + temp = 0; + } + else if (IsDigit(c)) + temp = (temp * 10) + c - '0'; + } +} + +/*---------------------------------------------------------------------------- + * IMY_MetaData() + *---------------------------------------------------------------------------- + * Purpose: + * Prepare to parse the file. Allocates instance data (or uses static allocation for + * static memory model). + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static void IMY_MetaData (S_IMELODY_DATA *pData, E_EAS_METADATA_TYPE metaType, EAS_I8 *buffer) +{ + EAS_I32 len; + + /* check for callback */ + if (!pData->metadata.callback) + return; + + /* copy data to host buffer */ + len = (EAS_I32) strlen((char*) buffer); + if (len >pData->metadata.bufferSize) + len = pData->metadata.bufferSize; + strncpy((char*) pData->metadata.buffer, (char*) buffer, (size_t) len); + pData->metadata.buffer[len] = 0; + + /* callback to host */ + pData->metadata.callback(metaType, pData->metadata.buffer, pData->metadata.pUserData); +} + +/*---------------------------------------------------------------------------- + * IMY_ParseHeader() + *---------------------------------------------------------------------------- + * Purpose: + * Prepare to parse the file. Allocates instance data (or uses static allocation for + * static memory model). + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT IMY_ParseHeader (S_EAS_DATA *pEASData, S_IMELODY_DATA* pData) +{ + EAS_RESULT result; + EAS_INT token; + EAS_INT temp; + EAS_I8 c; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_ParseHeader\n"); */ } +#endif + + /* initialize some defaults */ + pData->time = 0; + pData->tick = DEFAULT_TICK_CONV; + pData->note = 0; + pData->noteModifier = 0; + pData ->restTicks = 0; + pData->volume = 7; + pData->octave = 60; + pData->repeatOffset = -1; + pData->repeatCount = -1; + pData->style = 0; + + /* force the read of the first line */ + pData->index = 1; + + /* read data until we get to melody */ + for (;;) + { + /* read a line from the file and parse the token */ + if (pData->index != 0) + { + if ((result = IMY_ReadLine(pEASData->hwInstData, pData->fileHandle, pData->buffer, &pData->startLine)) != EAS_SUCCESS) + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_ParseHeader: IMY_ReadLine returned %d\n", result); */ } +#endif + return result; + } + } + token = IMY_ParseLine(pData->buffer, &pData->index); + + switch (token) + { + /* ignore these valid tokens */ + case TOKEN_BEGIN: + break; + + case TOKEN_FORMAT: + if (!IMY_GetVersion(pData, &temp)) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Invalid FORMAT field '%s'\n", pData->buffer); */ } + return EAS_ERROR_FILE_FORMAT; + } + if ((temp != 0x0100) && (temp != 0x0200)) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Unsupported FORMAT %02x\n", temp); */ } + return EAS_ERROR_UNRECOGNIZED_FORMAT; + } + break; + + case TOKEN_VERSION: + if (!IMY_GetVersion(pData, &temp)) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Invalid VERSION field '%s'\n", pData->buffer); */ } + return EAS_ERROR_FILE_FORMAT; + } + if ((temp != 0x0100) && (temp != 0x0102)) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Unsupported VERSION %02x\n", temp); */ } + return EAS_ERROR_UNRECOGNIZED_FORMAT; + } + break; + + case TOKEN_NAME: + IMY_MetaData(pData, EAS_METADATA_TITLE, pData->buffer + pData->index); + break; + + case TOKEN_COMPOSER: + IMY_MetaData(pData, EAS_METADATA_AUTHOR, pData->buffer + pData->index); + break; + + /* handle beat */ + case TOKEN_BEAT: + IMY_GetNumber(pEASData->hwInstData, pData, &temp, EAS_TRUE); + if ((temp >= 25) && (temp <= 900)) + pData->tick = TICK_CONVERT / temp; + break; + + /* handle style */ + case TOKEN_STYLE: + c = IMY_GetNextChar(pEASData->hwInstData, pData, EAS_TRUE); + if (c == 'S') + c = IMY_GetNextChar(pEASData->hwInstData, pData, EAS_TRUE); + if ((c >= '0') && (c <= '2')) + pData->style = (EAS_U8) (c - '0'); + else + { + PutBackChar(pData); + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Error in style command: %s\n", pData->buffer); */ } + } + break; + + /* handle volume */ + case TOKEN_VOLUME: + c = IMY_GetNextChar(pEASData->hwInstData, pData, EAS_TRUE); + if (c != 'V') + { + PutBackChar(pData); + if (!IsDigit(c)) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Error in volume command: %s\n", pData->buffer); */ } + break; + } + } + IMY_GetVolume(pEASData->hwInstData, pData, EAS_TRUE); + break; + + case TOKEN_MELODY: +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Header successfully parsed\n"); */ } +#endif + return EAS_SUCCESS; + + case TOKEN_END: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Unexpected END:IMELODY encountered\n"); */ } + return EAS_ERROR_FILE_FORMAT; + + default: + /* force a read of the next line */ + pData->index = 1; + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Ignoring unrecognized token in iMelody file: %s\n", pData->buffer); */ } + break; + } + } +} + +/*---------------------------------------------------------------------------- + * IMY_GetNextChar() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_I8 IMY_GetNextChar (EAS_HW_DATA_HANDLE hwInstData, S_IMELODY_DATA *pData, EAS_BOOL inHeader) +{ + EAS_I8 c; + EAS_U8 index; + + for (;;) + { + /* get next character */ + c = pData->buffer[pData->index++]; + + /* buffer empty, read more */ + if (!c) + { + /* don't read the next line in the header */ + if (inHeader) + return 0; + + pData->index = 0; + pData->buffer[0] = 0; + if (IMY_ReadLine(hwInstData, pData->fileHandle, pData->buffer, &pData->startLine) != EAS_SUCCESS) + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetNextChar: EOF\n"); */ } +#endif + return 0; + } + + /* check for END:IMELODY token */ + if (IMY_ParseLine(pData->buffer, &index) == TOKEN_END) + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetNextChar: found END:IMELODY\n"); */ } +#endif + pData->buffer[0] = 0; + return 0; + } + continue; + } + + /* ignore white space */ + if (!IsSpace(c)) + { + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetNextChar returned '%c'\n", c); */ } +#endif + return c; + } + } +} + +/*---------------------------------------------------------------------------- + * IMY_ReadLine() + *---------------------------------------------------------------------------- + * Purpose: + * Reads a line of input from the file, discarding the CR/LF + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT IMY_ReadLine (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle, EAS_I8 *buffer, EAS_I32 *pStartLine) +{ + EAS_RESULT result; + EAS_INT i; + EAS_I8 c; + + /* fetch current file position and save it */ + if (pStartLine != NULL) + { + if ((result = EAS_HWFilePos(hwInstData, fileHandle, pStartLine)) != EAS_SUCCESS) + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_ParseHeader: EAS_HWFilePos returned %d\n", result); */ } +#endif + return result; + } + } + + buffer[0] = 0; + for (i = 0; i < MAX_LINE_SIZE; ) + { + if ((result = EAS_HWGetByte(hwInstData, fileHandle, &c)) != EAS_SUCCESS) + { + if ((result == EAS_EOF) && (i > 0)) + break; + return result; + } + + /* return on LF or end of data */ + if (c == '\n') + break; + + /* store characters in buffer */ + if (c != '\r') + buffer[i++] = c; + } + buffer[i] = 0; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_ReadLine read %s\n", buffer); */ } +#endif + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMY_ParseLine() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_INT IMY_ParseLine (EAS_I8 *buffer, EAS_U8 *pIndex) +{ + EAS_INT i; + EAS_INT j; + + /* there's no strnicmp() in stdlib, so we have to roll our own */ + for (i = 0; i < TOKEN_INVALID; i++) + { + for (j = 0; ; j++) + { + /* end of token, must be a match */ + if (tokens[i][j] == 0) + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_ParseLine found token %d\n", i); */ } +#endif + *pIndex = (EAS_U8) j; + return i; + } + if (tokens[i][j] != ToUpper(buffer[j])) + break; + } + } +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_ParseLine: no token found\n"); */ } +#endif + return TOKEN_INVALID; +} + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_imelodydata.c b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_imelodydata.c new file mode 100755 index 0000000..9437e08 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_imelodydata.c @@ -0,0 +1,43 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_imelodydata.c + * + * Contents and purpose: + * SMF File Parser + * + * This file contains data definitions for the SMF parser. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 547 $ + * $Date: 2007-01-31 16:30:17 -0800 (Wed, 31 Jan 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_types.h" +#include "eas_imelodydata.h" + +/*---------------------------------------------------------------------------- + * + * eas_iMelodyData + * + * Static memory allocation for iMelody parser + *---------------------------------------------------------------------------- +*/ +S_IMELODY_DATA eas_iMelodyData; + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_imelodydata.h b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_imelodydata.h new file mode 100755 index 0000000..57c1ed0 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_imelodydata.h @@ -0,0 +1,73 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_imelodydata.h + * + * Contents and purpose: + * SMF File Parser + * + * This file contains data declarations for the iMelody parser. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 778 $ + * $Date: 2007-07-23 16:45:17 -0700 (Mon, 23 Jul 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef EAS_IMELODYDATA_H +#define EAS_IMELODYDATA_H + +#include "eas_data.h" + +/* maximum line size as specified in iMelody V1.2 spec */ +#define MAX_LINE_SIZE 75 + +/*---------------------------------------------------------------------------- + * + * S_IMELODY_DATA + * + * This structure contains the state data for the iMelody parser + *---------------------------------------------------------------------------- +*/ + +typedef struct +{ + EAS_FILE_HANDLE fileHandle; /* file handle */ + S_SYNTH *pSynth; /* pointer to synth */ + EAS_I32 fileOffset; /* offset to start of data */ + EAS_I32 time; /* current time in 256ths of a msec */ + EAS_I32 tickBase; /* basline length of 32nd note in 256th of a msec */ + EAS_I32 tick; /* actual length of 32nd note in 256th of a msec */ + EAS_I32 restTicks; /* ticks to rest after current note */ + EAS_I32 startLine; /* file offset at start of line (for repeats) */ + EAS_I32 repeatOffset; /* file offset to start of repeat section */ + S_METADATA_CB metadata; /* metadata callback */ + EAS_I16 repeatCount; /* repeat counter */ + EAS_U8 state; /* current state EAS_STATE_XXXX */ + EAS_U8 style; /* from STYLE */ + EAS_U8 index; /* index into buffer */ + EAS_U8 octave; /* octave prefix */ + EAS_U8 volume; /* current volume */ + EAS_U8 note; /* MIDI note number */ + EAS_I8 noteModifier; /* sharp or flat */ + EAS_I8 buffer[MAX_LINE_SIZE+1]; /* buffer for ASCII data */ +} S_IMELODY_DATA; + +#endif + + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_math.c b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_math.c new file mode 100755 index 0000000..dc85051 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_math.c @@ -0,0 +1,168 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_math.c + * + * Contents and purpose: + * Contains common math routines for the various audio engines. + * + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 586 $ + * $Date: 2007-03-08 20:33:04 -0800 (Thu, 08 Mar 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas.h" +#include "eas_math.h" + +/* anything less than this converts to a fraction too small to represent in 32-bits */ +#define MIN_CENTS -18000 + +/*---------------------------------------------------------------------------- + * EAS_Calculate2toX() + *---------------------------------------------------------------------------- + * Purpose: + * Calculate 2^x + * + * Inputs: + * nCents - measured in cents + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * nResult - int.frac result (where frac has NUM_DENTS_FRAC_BITS) + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_I32 EAS_Calculate2toX (EAS_I32 nCents) +{ + EAS_I32 nDents; + EAS_I32 nExponentInt, nExponentFrac; + EAS_I32 nTemp1, nTemp2; + EAS_I32 nResult; + + /* check for minimum value */ + if (nCents < MIN_CENTS) + return 0; + + /* for the time being, convert cents to dents */ + nDents = FMUL_15x15(nCents, CENTS_TO_DENTS); + + nExponentInt = GET_DENTS_INT_PART(nDents); + nExponentFrac = GET_DENTS_FRAC_PART(nDents); + + /* + implement 2^(fracPart) as a power series + */ + nTemp1 = GN2_TO_X2 + MULT_DENTS_COEF(nExponentFrac, GN2_TO_X3); + nTemp2 = GN2_TO_X1 + MULT_DENTS_COEF(nExponentFrac, nTemp1); + nTemp1 = GN2_TO_X0 + MULT_DENTS_COEF(nExponentFrac, nTemp2); + + /* + implement 2^(intPart) as + a left shift for intPart >= 0 or + a left shift for intPart < 0 + */ + if (nExponentInt >= 0) + { + /* left shift for positive exponents */ + /*lint -e{703} */ + nResult = nTemp1 << nExponentInt; + } + else + { + /* right shift for negative exponents */ + nExponentInt = -nExponentInt; + nResult = nTemp1 >> nExponentInt; + } + + return nResult; +} + +/*---------------------------------------------------------------------------- + * EAS_LogToLinear16() + *---------------------------------------------------------------------------- + * Purpose: + * Transform log value to linear gain multiplier using piece-wise linear + * approximation + * + * Inputs: + * nGain - log scale value in 20.10 format. Even though gain is normally + * stored in 6.10 (16-bit) format we use 32-bit numbers here to eliminate + * the need for saturation checking when combining gain values. + * + * Outputs: + * Returns a 16-bit linear value approximately equal to 2^(nGain/1024) + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_U16 EAS_LogToLinear16 (EAS_I32 nGain) +{ + EAS_INT nExp; + EAS_U16 nTemp; + + /* bias to positive */ + nGain += 32767; + + /* check for infinite attenuation */ + if (nGain < 0) + return 0; + + /* extract the exponent */ + nExp = 31 - (nGain >> 10); + + /* check for maximum output */ + if (nExp < 0) + return 0x7fff; + + /* extract mantissa and restore implied 1 bit */ + nTemp = (EAS_U16)((((nGain & 0x3ff) << 4) | 0x4000) >> nExp); + + /* use shift to approximate power-of-2 operation */ + return nTemp; +} + +/*---------------------------------------------------------------------------- + * EAS_VolumeToGain() + *---------------------------------------------------------------------------- + * Purpose: + * Transform volume control in 1dB increments to gain multiplier + * + * Inputs: + * volume - 100 = 0dB, 99 = -1dB, 0 = -inf + * + * Outputs: + * Returns a 16-bit linear value + *---------------------------------------------------------------------------- +*/ +EAS_I16 EAS_VolumeToGain (EAS_INT volume) +{ + /* check for limits */ + if (volume <= 0) + return 0; + if (volume >= 100) + return 0x7fff; + + /*lint -e{702} use shift instead of division */ + return (EAS_I16) EAS_Calculate2toX((((volume - EAS_MAX_VOLUME) * 204099) >> 10) - 1); +} + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_math.h b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_math.h new file mode 100755 index 0000000..f240b51 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_math.h @@ -0,0 +1,412 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_math.h + * + * Contents and purpose: + * Contains common math routines for the various audio engines. + * + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 584 $ + * $Date: 2007-03-08 09:49:24 -0800 (Thu, 08 Mar 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_MATH_H +#define _EAS_MATH_H + + +/** coefs for pan, generates sin, cos */ +#define COEFF_PAN_G2 -27146 /* -0.82842712474619 = 2 - 4/sqrt(2) */ +#define COEFF_PAN_G0 23170 /* 0.707106781186547 = 1/sqrt(2) */ + +/* +coefficients for approximating +2^x = gn2toX0 + gn2toX1*x + gn2toX2*x^2 + gn2toX3*x^3 +where x is a int.frac number representing number of octaves. +Actually, we approximate only the 2^(frac) using the power series +and implement the 2^(int) as a shift, so that +2^x == 2^(int.frac) == 2^(int) * 2^(fract) + == (gn2toX0 + gn2toX1*x + gn2toX2*x^2 + gn2toX3*x^3) << (int) + +The gn2toX.. were generated using a best fit for a 3rd +order polynomial, instead of taking the coefficients from +a truncated Taylor (or Maclaurin?) series. +*/ + +#define GN2_TO_X0 32768 /* 1 */ +#define GN2_TO_X1 22833 /* 0.696807861328125 */ +#define GN2_TO_X2 7344 /* 0.22412109375 */ +#define GN2_TO_X3 2588 /* 0.0789794921875 */ + +/*---------------------------------------------------------------------------- + * Fixed Point Math + *---------------------------------------------------------------------------- + * These macros are used for fixed point multiplies. If the processor + * supports fixed point multiplies, replace these macros with inline + * assembly code to improve performance. + *---------------------------------------------------------------------------- +*/ + +/* Fixed point multiply 0.15 x 0.15 = 0.15 returned as 32-bits */ +#define FMUL_15x15(a,b) \ + /*lint -e(704) */ \ + (((EAS_I32)(a) * (EAS_I32)(b)) >> 15) + +/* Fixed point multiply 0.7 x 0.7 = 0.15 returned as 32-bits */ +#define FMUL_7x7(a,b) \ + /*lint -e(704) */ \ + (((EAS_I32)(a) * (EAS_I32)(b) ) << 1) + +/* Fixed point multiply 0.8 x 0.8 = 0.15 returned as 32-bits */ +#define FMUL_8x8(a,b) \ + /*lint -e(704) */ \ + (((EAS_I32)(a) * (EAS_I32)(b) ) >> 1) + +/* Fixed point multiply 0.8 x 1.15 = 0.15 returned as 32-bits */ +#define FMUL_8x15(a,b) \ + /*lint -e(704) */ \ + (((EAS_I32)((a) << 7) * (EAS_I32)(b)) >> 15) + +/* macros for fractional phase accumulator */ +/* +Note: changed the _U32 to _I32 on 03/14/02. This should not +affect the phase calculations, and should allow us to reuse these +macros for other audio sample related math. +*/ +#define HARDWARE_BIT_WIDTH 32 + +#define NUM_PHASE_INT_BITS 1 +#define NUM_PHASE_FRAC_BITS 15 + +#define PHASE_FRAC_MASK (EAS_U32) ((0x1L << NUM_PHASE_FRAC_BITS) -1) + +#define GET_PHASE_INT_PART(x) (EAS_U32)((EAS_U32)(x) >> NUM_PHASE_FRAC_BITS) +#define GET_PHASE_FRAC_PART(x) (EAS_U32)((EAS_U32)(x) & PHASE_FRAC_MASK) + +#define DEFAULT_PHASE_FRAC 0 +#define DEFAULT_PHASE_INT 0 + +/* +Linear interpolation calculates: +output = (1-frac) * sample[n] + (frac) * sample[n+1] + +where conceptually 0 <= frac < 1 + +For a fixed point implementation, frac is actually an integer value +with an implied binary point one position to the left. The value of +one (unity) is given by PHASE_ONE +one half and one quarter are useful for 4-point linear interp. +*/ +#define PHASE_ONE (EAS_I32) (0x1L << NUM_PHASE_FRAC_BITS) + +/* + Multiply the signed audio sample by the unsigned fraction. +- a is the signed audio sample +- b is the unsigned fraction (cast to signed int as long as coef + uses (n-1) or less bits, where n == hardware bit width) +*/ +#define MULT_AUDIO_COEF(audio,coef) /*lint -e704 */ \ + (EAS_I32)( \ + ( \ + ((EAS_I32)(audio)) * ((EAS_I32)(coef)) \ + ) \ + >> NUM_PHASE_FRAC_BITS \ + ) \ + /* lint +704 */ + +/* wet / dry calculation macros */ +#define NUM_WET_DRY_FRAC_BITS 7 // 15 +#define NUM_WET_DRY_INT_BITS 9 // 1 + +/* define a 1.0 */ +#define WET_DRY_ONE (EAS_I32) ((0x1L << NUM_WET_DRY_FRAC_BITS)) +#define WET_DRY_MINUS_ONE (EAS_I32) (~WET_DRY_ONE) +#define WET_DRY_FULL_SCALE (EAS_I32) (WET_DRY_ONE - 1) + +#define MULT_AUDIO_WET_DRY_COEF(audio,coef) /*lint -e(702) */ \ + (EAS_I32)( \ + ( \ + ((EAS_I32)(audio)) * ((EAS_I32)(coef)) \ + ) \ + >> NUM_WET_DRY_FRAC_BITS \ + ) + +/* Envelope 1 (EG1) calculation macros */ +#define NUM_EG1_INT_BITS 1 +#define NUM_EG1_FRAC_BITS 15 + +/* the max positive gain used in the synth for EG1 */ +/* SYNTH_FULL_SCALE_EG1_GAIN must match the value in the dls2eas +converter, otherwise, the values we read from the .eas file are bogus. */ +#define SYNTH_FULL_SCALE_EG1_GAIN (EAS_I32) ((0x1L << NUM_EG1_FRAC_BITS) -1) + +/* define a 1.0 */ +#define EG1_ONE (EAS_I32) ((0x1L << NUM_EG1_FRAC_BITS)) +#define EG1_MINUS_ONE (EAS_I32) (~SYNTH_FULL_SCALE_EG1_GAIN) + +#define EG1_HALF (EAS_I32) (EG1_ONE/2) +#define EG1_MINUS_HALF (EAS_I32) (EG1_MINUS_ONE/2) + +/* +We implement the EG1 using a linear gain value, which means that the +attack segment is handled by incrementing (adding) the linear gain. +However, EG1 treats the Decay, Sustain, and Release differently than +the Attack portion. For Decay, Sustain, and Release, the gain is +linear on dB scale, which is equivalent to exponential damping on +a linear scale. Because we use a linear gain for EG1, we implement +the Decay and Release as multiplication (instead of incrementing +as we did for the attack segment). +Therefore, we need the following macro to implement the multiplication +(i.e., exponential damping) during the Decay and Release segments of +the EG1 +*/ +#define MULT_EG1_EG1(gain,damping) /*lint -e(704) */ \ + (EAS_I32)( \ + ( \ + ((EAS_I32)(gain)) * ((EAS_I32)(damping)) \ + ) \ + >> NUM_EG1_FRAC_BITS \ + ) + +// Use the following macro specifically for the filter, when multiplying +// the b1 coefficient. The 0 <= |b1| < 2, which therefore might overflow +// in certain conditions because we store b1 as a 1.15 value. +// Instead, we could store b1 as b1p (b1' == b1 "prime") where +// b1p == b1/2, thus ensuring no potential overflow for b1p because +// 0 <= |b1p| < 1 +// However, during the filter calculation, we must account for the fact +// that we are using b1p instead of b1, and thereby multiply by +// an extra factor of 2. Rather than multiply by an extra factor of 2, +// we can instead shift the result right by one less, hence the +// modified shift right value of (NUM_EG1_FRAC_BITS -1) +#define MULT_EG1_EG1_X2(gain,damping) /*lint -e(702) */ \ + (EAS_I32)( \ + ( \ + ((EAS_I32)(gain)) * ((EAS_I32)(damping)) \ + ) \ + >> (NUM_EG1_FRAC_BITS -1) \ + ) + +#define SATURATE_EG1(x) /*lint -e{734} saturation operation */ \ + ((EAS_I32)(x) > SYNTH_FULL_SCALE_EG1_GAIN) ? (SYNTH_FULL_SCALE_EG1_GAIN) : \ + ((EAS_I32)(x) < EG1_MINUS_ONE) ? (EG1_MINUS_ONE) : (x); + + +/* use "digital cents" == "dents" instead of cents */ +/* we coudl re-use the phase frac macros, but if we do, +we must change the phase macros to cast to _I32 instead of _U32, +because using a _U32 cast causes problems when shifting the exponent +for the 2^x calculation, because right shift a negative values MUST +be sign extended, or else the 2^x calculation is wrong */ + +/* use "digital cents" == "dents" instead of cents */ +#define NUM_DENTS_FRAC_BITS 12 +#define NUM_DENTS_INT_BITS (HARDWARE_BIT_WIDTH - NUM_DENTS_FRAC_BITS) + +#define DENTS_FRAC_MASK (EAS_I32) ((0x1L << NUM_DENTS_FRAC_BITS) -1) + +#define GET_DENTS_INT_PART(x) /*lint -e(704) */ \ + (EAS_I32)((EAS_I32)(x) >> NUM_DENTS_FRAC_BITS) + +#define GET_DENTS_FRAC_PART(x) (EAS_I32)((EAS_I32)(x) & DENTS_FRAC_MASK) + +#define DENTS_ONE (EAS_I32) (0x1L << NUM_DENTS_FRAC_BITS) + +/* use CENTS_TO_DENTS to convert a value in cents to dents */ +#define CENTS_TO_DENTS (EAS_I32) (DENTS_ONE * (0x1L << NUM_EG1_FRAC_BITS) / 1200L) \ + + +/* +For gain, the LFO generates a value that modulates in terms +of dB. However, we use a linear gain value, so we must convert +the LFO value in dB to a linear gain. Normally, we would use +linear gain = 10^x, where x = LFO value in dB / 20. +Instead, we implement 10^x using our 2^x approximation. +because + + 10^x = 2^(log2(10^x)) = 2^(x * log2(10)) + +so we need to multiply by log2(10) which is just a constant. +Ah, but just wait -- our 2^x actually doesn't exactly implement +2^x, but it actually assumes that the input is in cents, and within +the 2^x approximation converts its input from cents to octaves +by dividing its input by 1200. + +So, in order to convert the LFO gain value in dB to something +that our existing 2^x approximation can use, multiply the LFO gain +by log2(10) * 1200 / 20 + +The divide by 20 helps convert dB to linear gain, and we might +as well incorporate that operation into this conversion. +Of course, we need to keep some fractional bits, so multiply +the constant by NUM_EG1_FRAC_BITS +*/ + +/* use LFO_GAIN_TO_CENTS to convert the LFO gain value to cents */ +#if 0 +#define DOUBLE_LOG2_10 (double) (3.32192809488736) /* log2(10) */ + +#define DOUBLE_LFO_GAIN_TO_CENTS (double) \ + ( \ + (DOUBLE_LOG2_10) * \ + 1200.0 / \ + 20.0 \ + ) + +#define LFO_GAIN_TO_CENTS (EAS_I32) \ + ( \ + DOUBLE_LFO_GAIN_TO_CENTS * \ + (0x1L << NUM_EG1_FRAC_BITS) \ + ) +#endif + +#define LFO_GAIN_TO_CENTS (EAS_I32) (1671981156L >> (23 - NUM_EG1_FRAC_BITS)) + + +#define MULT_DENTS_COEF(dents,coef) /*lint -e704 */ \ + (EAS_I32)( \ + ( \ + ((EAS_I32)(dents)) * ((EAS_I32)(coef)) \ + ) \ + >> NUM_DENTS_FRAC_BITS \ + ) \ + /* lint +e704 */ + +/* we use 16-bits in the PC per audio sample */ +#define BITS_PER_AUDIO_SAMPLE 16 + +/* we define 1 as 1.0 - 1 LSbit */ +#define DISTORTION_ONE (EAS_I32)((0x1L << (BITS_PER_AUDIO_SAMPLE-1)) -1) +#define DISTORTION_MINUS_ONE (EAS_I32)(~DISTORTION_ONE) + +/* drive coef is given as int.frac */ +#define NUM_DRIVE_COEF_INT_BITS 1 +#define NUM_DRIVE_COEF_FRAC_BITS 4 + +#define MULT_AUDIO_DRIVE(audio,drive) /*lint -e(702) */ \ + (EAS_I32) ( \ + ( \ + ((EAS_I32)(audio)) * ((EAS_I32)(drive)) \ + ) \ + >> NUM_DRIVE_COEF_FRAC_BITS \ + ) + +#define MULT_AUDIO_AUDIO(audio1,audio2) /*lint -e(702) */ \ + (EAS_I32) ( \ + ( \ + ((EAS_I32)(audio1)) * ((EAS_I32)(audio2)) \ + ) \ + >> (BITS_PER_AUDIO_SAMPLE-1) \ + ) + +#define SATURATE(x) \ + ((((EAS_I32)(x)) > DISTORTION_ONE) ? (DISTORTION_ONE) : \ + (((EAS_I32)(x)) < DISTORTION_MINUS_ONE) ? (DISTORTION_MINUS_ONE) : ((EAS_I32)(x))); + + + +/*---------------------------------------------------------------------------- + * EAS_Calculate2toX() + *---------------------------------------------------------------------------- + * Purpose: + * Calculate 2^x + * + * Inputs: + * nCents - measured in cents + * + * Outputs: + * nResult - int.frac result (where frac has NUM_DENTS_FRAC_BITS) + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_I32 EAS_Calculate2toX (EAS_I32 nCents); + +/*---------------------------------------------------------------------------- + * EAS_LogToLinear16() + *---------------------------------------------------------------------------- + * Purpose: + * Transform log value to linear gain multiplier using piece-wise linear + * approximation + * + * Inputs: + * nGain - log scale value in 20.10 format. Even though gain is normally + * stored in 6.10 (16-bit) format we use 32-bit numbers here to eliminate + * the need for saturation checking when combining gain values. + * + * Outputs: + * Returns a 16-bit linear value approximately equal to 2^(nGain/1024) + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_U16 EAS_LogToLinear16 (EAS_I32 nGain); + +/*---------------------------------------------------------------------------- + * EAS_VolumeToGain() + *---------------------------------------------------------------------------- + * Purpose: + * Transform volume control in 1dB increments to gain multiplier + * + * Inputs: + * volume - 100 = 0dB, 99 = -1dB, 0 = -inf + * + * Outputs: + * Returns a 16-bit linear value + *---------------------------------------------------------------------------- +*/ +EAS_I16 EAS_VolumeToGain (EAS_INT volume); + +/*---------------------------------------------------------------------------- + * EAS_fsqrt() + *---------------------------------------------------------------------------- + * Purpose: + * Calculates the square root of a 32-bit fixed point value + * + * Inputs: + * n = value of interest + * + * Outputs: + * returns the square root of n + * + *---------------------------------------------------------------------------- +*/ +EAS_U16 EAS_fsqrt (EAS_U32 n); + +/*---------------------------------------------------------------------------- + * EAS_flog2() + *---------------------------------------------------------------------------- + * Purpose: + * Calculates the log2 of a 32-bit fixed point value + * + * Inputs: + * n = value of interest + * + * Outputs: + * returns the log2 of n + * + *---------------------------------------------------------------------------- +*/ +EAS_I32 EAS_flog2 (EAS_U32 n); + +#endif + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_midi.c b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_midi.c new file mode 100755 index 0000000..2c0c793 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_midi.c @@ -0,0 +1,569 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_midi.c + * + * Contents and purpose: + * This file implements the MIDI stream parser. It is called by eas_smf.c to parse MIDI messages + * that are streamed out of the file. It can also parse live MIDI streams. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 794 $ + * $Date: 2007-08-01 00:08:48 -0700 (Wed, 01 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_data.h" +#include "eas_report.h" +#include "eas_miditypes.h" +#include "eas_midi.h" +#include "eas_vm_protos.h" +#include "eas_parser.h" + +#ifdef JET_INTERFACE +#include "jet_data.h" +#endif + + +/* state enumerations for ProcessSysExMessage */ +typedef enum +{ + eSysEx, + eSysExUnivNonRealTime, + eSysExUnivNrtTargetID, + eSysExGMControl, + eSysExUnivRealTime, + eSysExUnivRtTargetID, + eSysExDeviceControl, + eSysExMasterVolume, + eSysExMasterVolLSB, + eSysExSPMIDI, + eSysExSPMIDIchan, + eSysExSPMIDIMIP, + eSysExMfgID1, + eSysExMfgID2, + eSysExMfgID3, + eSysExEnhancer, + eSysExEnhancerSubID, + eSysExEnhancerFeedback1, + eSysExEnhancerFeedback2, + eSysExEnhancerDrive, + eSysExEnhancerWet, + eSysExEOX, + eSysExIgnore +} E_SYSEX_STATES; + +/* local prototypes */ +static EAS_RESULT ProcessMIDIMessage (S_EAS_DATA *pEASData, S_SYNTH *pSynth, S_MIDI_STREAM *pMIDIStream, EAS_INT parserMode); +static EAS_RESULT ProcessSysExMessage (S_EAS_DATA *pEASData, S_SYNTH *pSynth, S_MIDI_STREAM *pMIDIStream, EAS_U8 c, EAS_INT parserMode); + +/*---------------------------------------------------------------------------- + * EAS_InitMIDIStream() + *---------------------------------------------------------------------------- + * Purpose: + * Initializes the MIDI stream state for parsing. + * + * Inputs: + * + * Outputs: + * returns EAS_RESULT (EAS_SUCCESS is OK) + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void EAS_InitMIDIStream (S_MIDI_STREAM *pMIDIStream) +{ + pMIDIStream->byte3 = EAS_FALSE; + pMIDIStream->pending = EAS_FALSE; + pMIDIStream->runningStatus = 0; + pMIDIStream->status = 0; +} + +/*---------------------------------------------------------------------------- + * EAS_ParseMIDIStream() + *---------------------------------------------------------------------------- + * Purpose: + * Parses a MIDI input stream character by character. Characters are pushed (rather than pulled) + * so the interface works equally well for both file and stream I/O. + * + * Inputs: + * c - character from MIDI stream + * + * Outputs: + * returns EAS_RESULT (EAS_SUCCESS is OK) + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_ParseMIDIStream (S_EAS_DATA *pEASData, S_SYNTH *pSynth, S_MIDI_STREAM *pMIDIStream, EAS_U8 c, EAS_INT parserMode) +{ + + /* check for new status byte */ + if (c & 0x80) + { + /* save new running status */ + if (c < 0xf8) + { + pMIDIStream->runningStatus = c; + pMIDIStream->byte3 = EAS_FALSE; + + /* deal with SysEx */ + if ((c == 0xf7) || (c == 0xf0)) + { + if (parserMode == eParserModeMetaData) + return EAS_SUCCESS; + return ProcessSysExMessage(pEASData, pSynth, pMIDIStream, c, parserMode); + } + + /* inform the file parser that we're in the middle of a message */ + if ((c < 0xf4) || (c > 0xf6)) + pMIDIStream->pending = EAS_TRUE; + } + + /* real-time message - ignore it */ + return EAS_SUCCESS; + } + + /* 3rd byte of a 3-byte message? */ + if (pMIDIStream->byte3) + { + pMIDIStream->d2 = c; + pMIDIStream->byte3 = EAS_FALSE; + pMIDIStream->pending = EAS_FALSE; + if (parserMode == eParserModeMetaData) + return EAS_SUCCESS; + return ProcessMIDIMessage(pEASData, pSynth, pMIDIStream, parserMode); + } + + /* check for status received */ + if (pMIDIStream->runningStatus) + { + + /* save new status and data byte */ + pMIDIStream->status = pMIDIStream->runningStatus; + + /* check for 3-byte messages */ + if (pMIDIStream->status < 0xc0) + { + pMIDIStream->d1 = c; + pMIDIStream->pending = EAS_TRUE; + pMIDIStream->byte3 = EAS_TRUE; + return EAS_SUCCESS; + } + + /* check for 2-byte messages */ + if (pMIDIStream->status < 0xe0) + { + pMIDIStream->d1 = c; + pMIDIStream->pending = EAS_FALSE; + if (parserMode == eParserModeMetaData) + return EAS_SUCCESS; + return ProcessMIDIMessage(pEASData, pSynth, pMIDIStream, parserMode); + } + + /* check for more 3-bytes message */ + if (pMIDIStream->status < 0xf0) + { + pMIDIStream->d1 = c; + pMIDIStream->pending = EAS_TRUE; + pMIDIStream->byte3 = EAS_TRUE; + return EAS_SUCCESS; + } + + /* SysEx message? */ + if (pMIDIStream->status == 0xF0) + { + if (parserMode == eParserModeMetaData) + return EAS_SUCCESS; + return ProcessSysExMessage(pEASData, pSynth, pMIDIStream, c, parserMode); + } + + /* remaining messages all clear running status */ + pMIDIStream->runningStatus = 0; + + /* F2 is 3-byte message */ + if (pMIDIStream->status == 0xf2) + { + pMIDIStream->byte3 = EAS_TRUE; + return EAS_SUCCESS; + } + } + + /* no status byte received, provide a warning, but we should be able to recover */ + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Received MIDI data without a valid status byte: %d\n",c); */ } + pMIDIStream->pending = EAS_FALSE; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * ProcessMIDIMessage() + *---------------------------------------------------------------------------- + * Purpose: + * This function processes a typical MIDI message. All of the data has been received, just need + * to take appropriate action. + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ProcessMIDIMessage (S_EAS_DATA *pEASData, S_SYNTH *pSynth, S_MIDI_STREAM *pMIDIStream, EAS_INT parserMode) +{ + EAS_U8 channel; + + channel = pMIDIStream->status & 0x0f; + switch (pMIDIStream->status & 0xf0) + { + case 0x80: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"NoteOff: %02x %02x %02x\n", + pMIDIStream->status, pMIDIStream->d1, pMIDIStream->d2); */ } + if (parserMode < eParserModeMute) + VMStopNote(pEASData->pVoiceMgr, pSynth, channel, pMIDIStream->d1, pMIDIStream->d2); + break; + + case 0x90: + if (pMIDIStream->d2) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"NoteOn: %02x %02x %02x\n", + pMIDIStream->status, pMIDIStream->d1, pMIDIStream->d2); */ } + pMIDIStream->flags |= MIDI_FLAG_FIRST_NOTE; + if (parserMode == eParserModePlay) + VMStartNote(pEASData->pVoiceMgr, pSynth, channel, pMIDIStream->d1, pMIDIStream->d2); + } + else + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"NoteOff: %02x %02x %02x\n", + pMIDIStream->status, pMIDIStream->d1, pMIDIStream->d2); */ } + if (parserMode < eParserModeMute) + VMStopNote(pEASData->pVoiceMgr, pSynth, channel, pMIDIStream->d1, pMIDIStream->d2); + } + break; + + case 0xa0: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"PolyPres: %02x %02x %02x\n", + pMIDIStream->status, pMIDIStream->d1, pMIDIStream->d2); */ } + break; + + case 0xb0: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"Control: %02x %02x %02x\n", + pMIDIStream->status, pMIDIStream->d1, pMIDIStream->d2); */ } + if (parserMode < eParserModeMute) + VMControlChange(pEASData->pVoiceMgr, pSynth, channel, pMIDIStream->d1, pMIDIStream->d2); +#ifdef JET_INTERFACE + if (pMIDIStream->jetData & MIDI_FLAGS_JET_CB) + { + JET_Event(pEASData, pMIDIStream->jetData & (JET_EVENT_SEG_MASK | JET_EVENT_TRACK_MASK), + channel, pMIDIStream->d1, pMIDIStream->d2); + } +#endif + break; + + case 0xc0: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"Program: %02x %02x\n", + pMIDIStream->status, pMIDIStream->d1); */ } + if (parserMode < eParserModeMute) + VMProgramChange(pEASData->pVoiceMgr, pSynth, channel, pMIDIStream->d1); + break; + + case 0xd0: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"ChanPres: %02x %02x\n", + pMIDIStream->status, pMIDIStream->d1); */ } + if (parserMode < eParserModeMute) + VMChannelPressure(pSynth, channel, pMIDIStream->d1); + break; + + case 0xe0: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"PBend: %02x %02x %02x\n", + pMIDIStream->status, pMIDIStream->d1, pMIDIStream->d2); */ } + if (parserMode < eParserModeMute) + VMPitchBend(pSynth, channel, pMIDIStream->d1, pMIDIStream->d2); + break; + + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"Unknown: %02x %02x %02x\n", + pMIDIStream->status, pMIDIStream->d1, pMIDIStream->d2); */ } + } + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * ProcessSysExMessage() + *---------------------------------------------------------------------------- + * Purpose: + * Process a SysEx character byte from the MIDI stream. Since we cannot + * simply wait for the next character to arrive, we are forced to save + * state after each character. It would be easier to parse at the file + * level, but then we lose the nice feature of being able to support + * these messages in a real-time MIDI stream. + * + * Inputs: + * pEASData - pointer to synthesizer instance data + * c - character to be processed + * locating - if true, the sequencer is relocating to a new position + * + * Outputs: + * + * + * Side Effects: + * + * Notes: + * These are the SysEx messages we can receive: + * + * SysEx messages + * { f0 7e 7f 09 01 f7 } GM 1 On + * { f0 7e 7f 09 02 f7 } GM 1/2 Off + * { f0 7e 7f 09 03 f7 } GM 2 On + * { f0 7f 7f 04 01 lsb msb } Master Volume + * { f0 7f 7f 0b 01 ch mip [ch mip ...] f7 } SP-MIDI + * { f0 00 01 3a 04 01 fdbk1 fdbk2 drive wet dry f7 } Enhancer + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ProcessSysExMessage (S_EAS_DATA *pEASData, S_SYNTH *pSynth, S_MIDI_STREAM *pMIDIStream, EAS_U8 c, EAS_INT parserMode) +{ + + /* check for start byte */ + if (c == 0xf0) + { + pMIDIStream->sysExState = eSysEx; + } + /* check for end byte */ + else if (c == 0xf7) + { + /* if this was a MIP message, update the MIP table */ + if ((pMIDIStream->sysExState == eSysExSPMIDIchan) && (parserMode != eParserModeMetaData)) + VMUpdateMIPTable(pEASData->pVoiceMgr, pSynth); + pMIDIStream->sysExState = eSysExIgnore; + } + + /* process SysEx message */ + else + { + switch (pMIDIStream->sysExState) + { + case eSysEx: + + /* first byte, determine message class */ + switch (c) + { + case 0x7e: + pMIDIStream->sysExState = eSysExUnivNonRealTime; + break; + case 0x7f: + pMIDIStream->sysExState = eSysExUnivRealTime; + break; + case 0x00: + pMIDIStream->sysExState = eSysExMfgID1; + break; + default: + pMIDIStream->sysExState = eSysExIgnore; + break; + } + break; + + /* process GM message */ + case eSysExUnivNonRealTime: + if (c == 0x7f) + pMIDIStream->sysExState = eSysExUnivNrtTargetID; + else + pMIDIStream->sysExState = eSysExIgnore; + break; + + case eSysExUnivNrtTargetID: + if (c == 0x09) + pMIDIStream->sysExState = eSysExGMControl; + else + pMIDIStream->sysExState = eSysExIgnore; + break; + + case eSysExGMControl: + if ((c == 1) || (c == 3)) + { + /* GM 1 or GM2 On, reset synth */ + if (parserMode != eParserModeMetaData) + { + pMIDIStream->flags |= MIDI_FLAG_GM_ON; + VMReset(pEASData->pVoiceMgr, pSynth, EAS_FALSE); + VMInitMIPTable(pSynth); + } + pMIDIStream->sysExState = eSysExEOX; + } + else + pMIDIStream->sysExState = eSysExIgnore; + break; + + /* Process Master Volume and SP-MIDI */ + case eSysExUnivRealTime: + if (c == 0x7f) + pMIDIStream->sysExState = eSysExUnivRtTargetID; + else + pMIDIStream->sysExState = eSysExIgnore; + break; + + case eSysExUnivRtTargetID: + if (c == 0x04) + pMIDIStream->sysExState = eSysExDeviceControl; + else if (c == 0x0b) + pMIDIStream->sysExState = eSysExSPMIDI; + else + pMIDIStream->sysExState = eSysExIgnore; + break; + + /* process master volume */ + case eSysExDeviceControl: + if (c == 0x01) + pMIDIStream->sysExState = eSysExMasterVolume; + else + pMIDIStream->sysExState = eSysExIgnore; + break; + + case eSysExMasterVolume: + /* save LSB */ + pMIDIStream->d1 = c; + pMIDIStream->sysExState = eSysExMasterVolLSB; + break; + + case eSysExMasterVolLSB: + if (parserMode != eParserModeMetaData) + { + EAS_I32 gain = ((EAS_I32) c << 8) | ((EAS_I32) pMIDIStream->d1 << 1); + gain = (gain * gain) >> 15; + VMSetVolume(pSynth, (EAS_U16) gain); + } + pMIDIStream->sysExState = eSysExEOX; + break; + + /* process SP-MIDI MIP message */ + case eSysExSPMIDI: + if (c == 0x01) + { + /* assume all channels are muted */ + if (parserMode != eParserModeMetaData) + VMInitMIPTable(pSynth); + pMIDIStream->d1 = 0; + pMIDIStream->sysExState = eSysExSPMIDIchan; + } + else + pMIDIStream->sysExState = eSysExIgnore; + break; + + case eSysExSPMIDIchan: + if (c < NUM_SYNTH_CHANNELS) + { + pMIDIStream->d2 = c; + pMIDIStream->sysExState = eSysExSPMIDIMIP; + } + else + { + /* bad MIP message - unmute channels */ + if (parserMode != eParserModeMetaData) + VMInitMIPTable(pSynth); + pMIDIStream->sysExState = eSysExIgnore; + } + break; + + case eSysExSPMIDIMIP: + /* process MIP entry here */ + if (parserMode != eParserModeMetaData) + VMSetMIPEntry(pEASData->pVoiceMgr, pSynth, pMIDIStream->d2, pMIDIStream->d1, c); + pMIDIStream->sysExState = eSysExSPMIDIchan; + + /* if 16 channels received, update MIP table */ + if (++pMIDIStream->d1 == NUM_SYNTH_CHANNELS) + { + if (parserMode != eParserModeMetaData) + VMUpdateMIPTable(pEASData->pVoiceMgr, pSynth); + pMIDIStream->sysExState = eSysExEOX; + } + break; + + /* process Enhancer */ + case eSysExMfgID1: + if (c == 0x01) + pMIDIStream->sysExState = eSysExMfgID1; + else + pMIDIStream->sysExState = eSysExIgnore; + break; + + case eSysExMfgID2: + if (c == 0x3a) + pMIDIStream->sysExState = eSysExMfgID1; + else + pMIDIStream->sysExState = eSysExIgnore; + break; + + case eSysExMfgID3: + if (c == 0x04) + pMIDIStream->sysExState = eSysExEnhancer; + else + pMIDIStream->sysExState = eSysExIgnore; + break; + + case eSysExEnhancer: + if (c == 0x01) + pMIDIStream->sysExState = eSysExEnhancerSubID; + else + pMIDIStream->sysExState = eSysExIgnore; + break; + + case eSysExEnhancerSubID: + pMIDIStream->sysExState = eSysExEnhancerFeedback1; + break; + + case eSysExEnhancerFeedback1: + pMIDIStream->sysExState = eSysExEnhancerFeedback2; + break; + + case eSysExEnhancerFeedback2: + pMIDIStream->sysExState = eSysExEnhancerDrive; + break; + + case eSysExEnhancerDrive: + pMIDIStream->sysExState = eSysExEnhancerWet; + break; + + case eSysExEnhancerWet: + pMIDIStream->sysExState = eSysExEOX; + break; + + case eSysExEOX: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Expected F7, received %02x\n", c); */ } + pMIDIStream->sysExState = eSysExIgnore; + break; + + case eSysExIgnore: + break; + + default: + pMIDIStream->sysExState = eSysExIgnore; + break; + } + } + + if (pMIDIStream->sysExState == eSysExIgnore) + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Ignoring SysEx byte %02x\n", c); */ } + return EAS_SUCCESS; +} /* end ProcessSysExMessage */ + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_midi.h b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_midi.h new file mode 100755 index 0000000..10649a0 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_midi.h @@ -0,0 +1,71 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_midi.h + * + * Contents and purpose: + * Prototypes for MIDI stream parsing functions + * + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_MIDI_H +#define _EAS_MIDI_H + +/*---------------------------------------------------------------------------- + * EAS_InitMIDIStream() + *---------------------------------------------------------------------------- + * Purpose: + * Initializes the MIDI stream state for parsing. + * + * Inputs: + * + * Outputs: + * returns EAS_RESULT (EAS_SUCCESS is OK) + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void EAS_InitMIDIStream (S_MIDI_STREAM *pMIDIStream); + +/*---------------------------------------------------------------------------- + * EAS_ParseMIDIStream() + *---------------------------------------------------------------------------- + * Purpose: + * Parses a MIDI input stream character by character. Characters are pushed (rather than pulled) + * so the interface works equally well for both file and stream I/O. + * + * Inputs: + * c - character from MIDI stream + * + * Outputs: + * returns EAS_RESULT (EAS_SUCCESS is OK) + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_ParseMIDIStream (S_EAS_DATA *pEASData, S_SYNTH *pSynth, S_MIDI_STREAM *pMIDIStream, EAS_U8 c, EAS_INT parserMode); + +#endif /* #define _EAS_MIDI_H */ + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_midictrl.h b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_midictrl.h new file mode 100755 index 0000000..46fdc4f --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_midictrl.h @@ -0,0 +1,64 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_midictrl.h + * + * Contents and purpose: + * MIDI controller definitions + * + * This header only contains declarations that are specific + * to this implementation. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_MIDICTRL_H +#define _EAS_MIDICTRL_H + +/* define controller types */ +/* + Note that these controller types are specified in base 10 (decimal) + and not in hexadecimal. The above midi messages are specified + in hexadecimal. +*/ +#define MIDI_CONTROLLER_BANK_SELECT 0 +#define MIDI_CONTROLLER_BANK_SELECT_MSB 0 +#define MIDI_CONTROLLER_MOD_WHEEL 1 +#define MIDI_CONTROLLER_ENTER_DATA_MSB 6 +#define MIDI_CONTROLLER_VOLUME 7 +#define MIDI_CONTROLLER_PAN 10 +#define MIDI_CONTROLLER_EXPRESSION 11 +#define MIDI_CONTROLLER_BANK_SELECT_LSB 32 +#define MIDI_CONTROLLER_ENTER_DATA_LSB 38 /* 0x26 */ +#define MIDI_CONTROLLER_SUSTAIN_PEDAL 64 +#define MIDI_CONTROLLER_SELECT_NRPN_LSB 98 +#define MIDI_CONTROLLER_SELECT_NRPN_MSB 99 +#define MIDI_CONTROLLER_SELECT_RPN_LSB 100 /* 0x64 */ +#define MIDI_CONTROLLER_SELECT_RPN_MSB 101 /* 0x65 */ +#define MIDI_CONTROLLER_ALL_SOUND_OFF 120 +#define MIDI_CONTROLLER_RESET_CONTROLLERS 121 +#define MIDI_CONTROLLER_ALL_NOTES_OFF 123 +#define MIDI_CONTROLLER_OMNI_OFF 124 +#define MIDI_CONTROLLER_OMNI_ON 125 +#define MIDI_CONTROLLER_MONO_ON_POLY_OFF 126 +#define MIDI_CONTROLLER_POLY_ON_MONO_OFF 127 + +#endif /* #ifndef _EAS_MIDICTRL_H */ diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_mididata.c b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_mididata.c new file mode 100755 index 0000000..4463b7e --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_mididata.c @@ -0,0 +1,34 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_mididata.c + * + * Contents and purpose: + * Data module for MIDI stream interface + * + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 547 $ + * $Date: 2007-01-31 16:30:17 -0800 (Wed, 31 Jan 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_miditypes.h" + +S_INTERACTIVE_MIDI eas_MIDIData; + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_miditypes.h b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_miditypes.h new file mode 100755 index 0000000..015f08b --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_miditypes.h @@ -0,0 +1,138 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_miditypes.h + * + * Contents and purpose: + * Contains declarations for the MIDI stream parser. + * + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 778 $ + * $Date: 2007-07-23 16:45:17 -0700 (Mon, 23 Jul 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_MIDITYPES_H +#define _EAS_MIDITYPES_H + +#include "eas_data.h" +#include "eas_parser.h" + +/*---------------------------------------------------------------------------- + * S_MIDI_STREAM + * + * Maintains parser state for the MIDI stream parser + * + *---------------------------------------------------------------------------- +*/ + +typedef struct s_midi_stream_tag +{ + EAS_BOOL8 byte3; /* flag indicates 3rd byte expected */ + EAS_BOOL8 pending; /* flag indicates more data expected */ + EAS_U8 sysExState; /* maintains the SysEx state */ + EAS_U8 runningStatus; /* last running status received */ + EAS_U8 status; /* status byte */ + EAS_U8 d1; /* first data byte */ + EAS_U8 d2; /* second data byte */ + EAS_U8 flags; /* flags - see below for definition */ +#ifdef JET_INTERFACE + EAS_U32 jetData; /* JET data */ +#endif +} S_MIDI_STREAM; + +/* flags for S_MIDI_STREAM.flags */ +#define MIDI_FLAG_GM_ON 0x01 /* GM System On message received */ +#define MIDI_FLAG_FIRST_NOTE 0x02 /* first note received */ + +/* flags for S_MIDI_STREAM.jetFlags */ +#define MIDI_FLAGS_JET_MUTE 0x00000001 /* track is muted */ +#define MIDI_FLAGS_JET_CB 0x00000002 /* JET callback enabled */ + +/*---------------------------------------------------------------------------- + * + * S_SMF_STREAM + * + * This structure contains data required to parse an SMF stream. For SMF0 files, there + * will be a single instance of this per file. For SMF1 files, there will be multiple instance, + * one for each separate stream in the file. + * + *---------------------------------------------------------------------------- +*/ + +typedef struct s_smf_stream_tag +{ + EAS_FILE_HANDLE fileHandle; /* host wrapper file handle */ + EAS_U32 ticks; /* time of next event in stream */ + EAS_I32 startFilePos; /* start location of track within file */ + S_MIDI_STREAM midiStream; /* MIDI stream state */ +} S_SMF_STREAM; + +/*---------------------------------------------------------------------------- + * + * S_SMF_DATA + * + * This structure contains the instance data required to parse an SMF stream. + * + *---------------------------------------------------------------------------- +*/ + +typedef struct s_smf_data_tag +{ +#ifdef _CHECKED_BUILD + EAS_U32 handleCheck; /* signature check for checked build */ +#endif + S_SMF_STREAM *streams; /* pointer to individual streams in file */ + S_SMF_STREAM *nextStream; /* pointer to next stream with event */ + S_SYNTH *pSynth; /* pointer to synth */ + EAS_FILE_HANDLE fileHandle; /* file handle */ + S_METADATA_CB metadata; /* metadata callback */ + EAS_I32 fileOffset; /* for embedded files */ + EAS_I32 time; /* current time in milliseconds/256 */ + EAS_U16 numStreams; /* actual number of streams */ + EAS_U16 tickConv; /* current MIDI tick to msec conversion */ + EAS_U16 ppqn; /* ticks per quarter note */ + EAS_U8 state; /* current state EAS_STATE_XXXX */ + EAS_U8 flags; /* flags - see definitions below */ +} S_SMF_DATA; + +#define SMF_FLAGS_CHASE_MODE 0x01 /* chase mode - skip to first note */ +#define SMF_FLAGS_HAS_TIME_SIG 0x02 /* time signature encountered at time 0 */ +#define SMF_FLAGS_HAS_TEMPO 0x04 /* tempo encountered at time 0 */ +#define SMF_FLAGS_HAS_GM_ON 0x08 /* GM System On encountered at time 0 */ +#define SMF_FLAGS_JET_STREAM 0x80 /* JET in use - keep strict timing */ + +/* combo flags indicate setup bar */ +#define SMF_FLAGS_SETUP_BAR (SMF_FLAGS_HAS_TIME_SIG | SMF_FLAGS_HAS_TEMPO | SMF_FLAGS_HAS_GM_ON) + +/*---------------------------------------------------------------------------- + * Interactive MIDI structure + *---------------------------------------------------------------------------- +*/ +typedef struct s_interactive_midi_tag +{ +#ifdef _CHECKED_BUILD + EAS_U32 handleCheck; /* signature check for checked build */ +#endif + S_SYNTH *pSynth; /* pointer to synth */ + S_MIDI_STREAM stream; /* stream data */ +} S_INTERACTIVE_MIDI; + +#endif /* #ifndef _EAS_MIDITYPES_H */ + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_mixbuf.c b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_mixbuf.c new file mode 100755 index 0000000..db5bd02 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_mixbuf.c @@ -0,0 +1,36 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_mixbuf.c + * + * Contents and purpose: + * Contains a data allocation for synthesizer + * + * Copyright Sonic Network Inc. 2004 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +// includes +#include "eas_data.h" +#include "eas_mixer.h" + +// globals +EAS_I32 eas_MixBuffer[BUFFER_SIZE_IN_MONO_SAMPLES * NUM_OUTPUT_CHANNELS]; + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_mixer.c b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_mixer.c new file mode 100755 index 0000000..0a839a8 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_mixer.c @@ -0,0 +1,464 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_mixer.c + * + * Contents and purpose: + * This file contains the critical components of the mix engine that + * must be optimized for best performance. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 706 $ + * $Date: 2007-05-31 17:22:51 -0700 (Thu, 31 May 2007) $ + *---------------------------------------------------------------------------- +*/ + +//3 dls: This module is in the midst of being converted from a synth +//3 specific module to a general purpose mix engine + +/*------------------------------------ + * includes + *------------------------------------ +*/ +#include "eas_data.h" +#include "eas_host.h" +#include "eas_math.h" +#include "eas_mixer.h" +#include "eas_config.h" +#include "eas_report.h" + +#ifdef _MAXIMIZER_ENABLED +EAS_I32 MaximizerProcess (EAS_VOID_PTR pInstData, EAS_I32 *pSrc, EAS_I32 *pDst, EAS_I32 numSamples); +#endif + +/*------------------------------------ + * defines + *------------------------------------ +*/ + +/* need to boost stereo by ~3dB to compensate for the panner */ +#define STEREO_3DB_GAIN_BOOST 512 + +/*---------------------------------------------------------------------------- + * EAS_MixEngineInit() + *---------------------------------------------------------------------------- + * Purpose: + * Prepares the mix engine for work, allocates buffers, locates effects modules, etc. + * + * Inputs: + * pEASData - instance data + * pInstData - pointer to variable to receive instance data handle + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_MixEngineInit (S_EAS_DATA *pEASData) +{ + + /* check Configuration Module for mix buffer allocation */ + if (pEASData->staticMemoryModel) + pEASData->pMixBuffer = EAS_CMEnumData(EAS_CM_MIX_BUFFER); + else + pEASData->pMixBuffer = EAS_HWMalloc(pEASData->hwInstData, BUFFER_SIZE_IN_MONO_SAMPLES * NUM_OUTPUT_CHANNELS * sizeof(EAS_I32)); + if (pEASData->pMixBuffer == NULL) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Failed to allocate mix buffer memory\n"); */ } + return EAS_ERROR_MALLOC_FAILED; + } + EAS_HWMemSet((void *)(pEASData->pMixBuffer), 0, BUFFER_SIZE_IN_MONO_SAMPLES * NUM_OUTPUT_CHANNELS * sizeof(EAS_I32)); + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_MixEnginePrep() + *---------------------------------------------------------------------------- + * Purpose: + * Performs prep before synthesize a buffer of audio, such as clearing + * audio buffers, etc. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void EAS_MixEnginePrep (S_EAS_DATA *pEASData, EAS_I32 numSamples) +{ + + /* clear the mix buffer */ +#if (NUM_OUTPUT_CHANNELS == 2) + EAS_HWMemSet(pEASData->pMixBuffer, 0, numSamples * (EAS_I32) sizeof(long) * 2); +#else + EAS_HWMemSet(pEASData->pMixBuffer, 0, (EAS_I32) numSamples * (EAS_I32) sizeof(long)); +#endif + + /* need to clear other side-chain effect buffers (chorus & reverb) */ +} + +/*---------------------------------------------------------------------------- + * EAS_MixEnginePost + *---------------------------------------------------------------------------- + * Purpose: + * This routine does the post-processing after all voices have been + * synthesized. It calls any sweeteners and does the final mixdown to + * the output buffer. + * + * Inputs: + * + * Outputs: + * + * Notes: + *---------------------------------------------------------------------------- +*/ +void EAS_MixEnginePost (S_EAS_DATA *pEASData, EAS_I32 numSamples) +{ + EAS_U16 gain; + +//3 dls: Need to restore the mix engine metrics + + /* calculate the gain multiplier */ +#ifdef _MAXIMIZER_ENABLED + if (pEASData->effectsModules[EAS_MODULE_MAXIMIZER].effect) + { + EAS_I32 temp; + temp = MaximizerProcess(pEASData->effectsModules[EAS_MODULE_MAXIMIZER].effectData, pEASData->pMixBuffer, pEASData->pMixBuffer, numSamples); + temp = (temp * pEASData->masterGain) >> 15; + if (temp > 32767) + gain = 32767; + else + gain = (EAS_U16) temp; + } + else + gain = (EAS_U16) pEASData->masterGain; +#else + gain = (EAS_U16) pEASData->masterGain; +#endif + + /* Not using all the gain bits for now + * Reduce the input to the compressor by 6dB to prevent saturation + */ +#ifdef _COMPRESSOR_ENABLED + if (pEASData->effectsModules[EAS_MODULE_COMPRESSOR].effectData) + gain = gain >> 5; + else + gain = gain >> 4; +#else + gain = gain >> 4; +#endif + + /* convert 32-bit mix buffer to 16-bit output format */ +#if (NUM_OUTPUT_CHANNELS == 2) + SynthMasterGain(pEASData->pMixBuffer, pEASData->pOutputAudioBuffer, gain, (EAS_U16) ((EAS_U16) numSamples * 2)); +#else + SynthMasterGain(pEASData->pMixBuffer, pEASData->pOutputAudioBuffer, gain, (EAS_U16) numSamples); +#endif + +#ifdef _ENHANCER_ENABLED + /* enhancer effect */ + if (pEASData->effectsModules[EAS_MODULE_ENHANCER].effectData) + (*pEASData->effectsModules[EAS_MODULE_ENHANCER].effect->pfProcess) + (pEASData->effectsModules[EAS_MODULE_ENHANCER].effectData, + pEASData->pOutputAudioBuffer, + pEASData->pOutputAudioBuffer, + numSamples); +#endif + +#ifdef _GRAPHIC_EQ_ENABLED + /* graphic EQ effect */ + if (pEASData->effectsModules[EAS_MODULE_GRAPHIC_EQ].effectData) + (*pEASData->effectsModules[EAS_MODULE_GRAPHIC_EQ].effect->pfProcess) + (pEASData->effectsModules[EAS_MODULE_GRAPHIC_EQ].effectData, + pEASData->pOutputAudioBuffer, + pEASData->pOutputAudioBuffer, + numSamples); +#endif + +#ifdef _COMPRESSOR_ENABLED + /* compressor effect */ + if (pEASData->effectsModules[EAS_MODULE_COMPRESSOR].effectData) + (*pEASData->effectsModules[EAS_MODULE_COMPRESSOR].effect->pfProcess) + (pEASData->effectsModules[EAS_MODULE_COMPRESSOR].effectData, + pEASData->pOutputAudioBuffer, + pEASData->pOutputAudioBuffer, + numSamples); +#endif + +#ifdef _WOW_ENABLED + /* WOW requires a 32-bit buffer, borrow the mix buffer and + * pass it as the destination buffer + */ + /*lint -e{740} temporarily passing a parameter through an existing I/F */ + if (pEASData->effectsModules[EAS_MODULE_WOW].effectData) + (*pEASData->effectsModules[EAS_MODULE_WOW].effect->pfProcess) + (pEASData->effectsModules[EAS_MODULE_WOW].effectData, + pEASData->pOutputAudioBuffer, + (EAS_PCM*) pEASData->pMixBuffer, + numSamples); +#endif + +#ifdef _TONECONTROLEQ_ENABLED + /* ToneControlEQ effect */ + if (pEASData->effectsModules[EAS_MODULE_TONECONTROLEQ].effectData) + (*pEASData->effectsModules[EAS_MODULE_TONECONTROLEQ].effect->pfProcess) + (pEASData->effectsModules[EAS_MODULE_TONECONTROLEQ].effectData, + pEASData->pOutputAudioBuffer, + pEASData->pOutputAudioBuffer, + numSamples); +#endif + +#ifdef _REVERB_ENABLED + /* Reverb effect */ + if (pEASData->effectsModules[EAS_MODULE_REVERB].effectData) + (*pEASData->effectsModules[EAS_MODULE_REVERB].effect->pfProcess) + (pEASData->effectsModules[EAS_MODULE_REVERB].effectData, + pEASData->pOutputAudioBuffer, + pEASData->pOutputAudioBuffer, + numSamples); +#endif + +#ifdef _CHORUS_ENABLED + /* Chorus effect */ + if (pEASData->effectsModules[EAS_MODULE_CHORUS].effectData) + (*pEASData->effectsModules[EAS_MODULE_CHORUS].effect->pfProcess) + (pEASData->effectsModules[EAS_MODULE_CHORUS].effectData, + pEASData->pOutputAudioBuffer, + pEASData->pOutputAudioBuffer, + numSamples); +#endif + +} + +#ifndef NATIVE_EAS_KERNEL +/*---------------------------------------------------------------------------- + * SynthMasterGain + *---------------------------------------------------------------------------- + * Purpose: + * Mixes down audio from 32-bit to 16-bit target buffer + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +void SynthMasterGain (long *pInputBuffer, EAS_PCM *pOutputBuffer, EAS_U16 nGain, EAS_U16 numSamples) { + + /* loop through the buffer */ + while (numSamples--) { + long s; + + /* read a sample from the input buffer and add some guard bits */ + s = *pInputBuffer++; + + /* add some guard bits */ + /*lint -e{704} */ + s = s >> 7; + + /* apply master gain */ + s *= (long) nGain; + + /* shift to lower 16-bits */ + /*lint -e{704} */ + s = s >> 9; + + /* saturate */ + s = SATURATE(s); + + *pOutputBuffer++ = (EAS_PCM)s; + } +} +#endif + +/*---------------------------------------------------------------------------- + * EAS_MixEngineShutdown() + *---------------------------------------------------------------------------- + * Purpose: + * Shuts down effects modules and deallocates memory + * + * Inputs: + * pEASData - instance data + * pInstData - instance data handle + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_MixEngineShutdown (S_EAS_DATA *pEASData) +{ + + /* check Configuration Module for static memory allocation */ + if (!pEASData->staticMemoryModel && (pEASData->pMixBuffer != NULL)) + EAS_HWFree(pEASData->hwInstData, pEASData->pMixBuffer); + + return EAS_SUCCESS; +} + +#ifdef UNIFIED_MIXER +#ifndef NATIVE_MIX_STREAM +/*---------------------------------------------------------------------------- + * EAS_MixStream + *---------------------------------------------------------------------------- + * Mix a 16-bit stream into a 32-bit buffer + * + * pInputBuffer 16-bit input buffer + * pMixBuffer 32-bit mix buffer + * numSamples number of samples to mix + * gainLeft initial gain left or mono + * gainRight initial gain right + * gainLeft left gain increment per sample + * gainRight right gain increment per sample + * flags bit 0 = stereo source + * bit 1 = stereo output + *---------------------------------------------------------------------------- +*/ +void EAS_MixStream (EAS_PCM *pInputBuffer, EAS_I32 *pMixBuffer, EAS_I32 numSamples, EAS_I32 gainLeft, EAS_I32 gainRight, EAS_I32 gainIncLeft, EAS_I32 gainIncRight, EAS_I32 flags) +{ + EAS_I32 temp; + EAS_INT src, dest; + + /* NOTE: There are a lot of optimizations that can be done + * in the native implementations based on register + * availability, etc. For example, it may make sense to + * break this down into 8 separate routines: + * + * 1. Mono source to mono output + * 2. Mono source to stereo output + * 3. Stereo source to mono output + * 4. Stereo source to stereo output + * 5. Mono source to mono output - no gain change + * 6. Mono source to stereo output - no gain change + * 7. Stereo source to mono output - no gain change + * 8. Stereo source to stereo output - no gain change + * + * Other possibilities include loop unrolling, skipping + * a gain calculation every 2 or 4 samples, etc. + */ + + /* no gain change, use fast loops */ + if ((gainIncLeft == 0) && (gainIncRight == 0)) + { + switch (flags & (MIX_FLAGS_STEREO_SOURCE | MIX_FLAGS_STEREO_OUTPUT)) + { + /* mono to mono */ + case 0: + gainLeft >>= 15; + for (src = dest = 0; src < numSamples; src++, dest++) + { + + pMixBuffer[dest] += (pInputBuffer[src] * gainLeft) >> NUM_MIXER_GUARD_BITS; + } + break; + + /* mono to stereo */ + case MIX_FLAGS_STEREO_OUTPUT: + gainLeft >>= 15; + gainRight >>= 15; + for (src = dest = 0; src < numSamples; src++, dest+=2) + { + pMixBuffer[dest] += (pInputBuffer[src] * gainLeft) >> NUM_MIXER_GUARD_BITS; + pMixBuffer[dest+1] += (pInputBuffer[src] * gainRight) >> NUM_MIXER_GUARD_BITS; + } + break; + + /* stereo to mono */ + case MIX_FLAGS_STEREO_SOURCE: + gainLeft >>= 15; + gainRight >>= 15; + for (src = dest = 0; src < numSamples; src+=2, dest++) + { + temp = (pInputBuffer[src] * gainLeft) >> NUM_MIXER_GUARD_BITS; + temp += ((pInputBuffer[src+1] * gainRight) >> NUM_MIXER_GUARD_BITS); + pMixBuffer[dest] += temp; + } + break; + + /* stereo to stereo */ + case MIX_FLAGS_STEREO_SOURCE | MIX_FLAGS_STEREO_OUTPUT: + gainLeft >>= 15; + gainRight >>= 15; + for (src = dest = 0; src < numSamples; src+=2, dest+=2) + { + pMixBuffer[dest] += (pInputBuffer[src] * gainLeft) >> NUM_MIXER_GUARD_BITS; + pMixBuffer[dest+1] += (pInputBuffer[src+1] * gainRight) >> NUM_MIXER_GUARD_BITS; + } + break; + } + } + + /* gain change - do gain increment */ + else + { + switch (flags & (MIX_FLAGS_STEREO_SOURCE | MIX_FLAGS_STEREO_OUTPUT)) + { + /* mono to mono */ + case 0: + for (src = dest = 0; src < numSamples; src++, dest++) + { + gainLeft += gainIncLeft; + pMixBuffer[dest] += (pInputBuffer[src] * (gainLeft >> 15)) >> NUM_MIXER_GUARD_BITS; + } + break; + + /* mono to stereo */ + case MIX_FLAGS_STEREO_OUTPUT: + for (src = dest = 0; src < numSamples; src++, dest+=2) + { + gainLeft += gainIncLeft; + gainRight += gainIncRight; + pMixBuffer[dest] += (pInputBuffer[src] * (gainLeft >> 15)) >> NUM_MIXER_GUARD_BITS; + pMixBuffer[dest+1] += (pInputBuffer[src] * (gainRight >> 15)) >> NUM_MIXER_GUARD_BITS; + } + break; + + /* stereo to mono */ + case MIX_FLAGS_STEREO_SOURCE: + for (src = dest = 0; src < numSamples; src+=2, dest++) + { + gainLeft += gainIncLeft; + gainRight += gainIncRight; + temp = (pInputBuffer[src] * (gainLeft >> 15)) >> NUM_MIXER_GUARD_BITS; + temp += ((pInputBuffer[src+1] * (gainRight >> 15)) >> NUM_MIXER_GUARD_BITS); + pMixBuffer[dest] += temp; + } + break; + + /* stereo to stereo */ + case MIX_FLAGS_STEREO_SOURCE | MIX_FLAGS_STEREO_OUTPUT: + for (src = dest = 0; src < numSamples; src+=2, dest+=2) + { + gainLeft += gainIncLeft; + gainRight += gainIncRight; + pMixBuffer[dest] += (pInputBuffer[src] * (gainLeft >> 15)) >> NUM_MIXER_GUARD_BITS; + pMixBuffer[dest+1] += (pInputBuffer[src+1] * (gainRight >> 15)) >> NUM_MIXER_GUARD_BITS; + } + break; + } + } +} +#endif +#endif + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_mixer.h b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_mixer.h new file mode 100755 index 0000000..b2eb33b --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_mixer.h @@ -0,0 +1,137 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_mixer.h + * + * Contents and purpose: + * This file contains the critical components of the mix engine that + * must be optimized for best performance. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 706 $ + * $Date: 2007-05-31 17:22:51 -0700 (Thu, 31 May 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_MIXER_H +#define _EAS_MIXER_H + +//3 dls: This module is in the midst of being converted from a synth +//3 specific module to a general purpose mix engine + +#define MIX_FLAGS_STEREO_SOURCE 1 +#define MIX_FLAGS_STEREO_OUTPUT 2 +#define NUM_MIXER_GUARD_BITS 4 + +#include "eas_effects.h" + +extern void SynthMasterGain( long *pInputBuffer, EAS_PCM *pOutputBuffer, EAS_U16 nGain, EAS_U16 nNumLoopSamples); + +/*---------------------------------------------------------------------------- + * EAS_MixEngineInit() + *---------------------------------------------------------------------------- + * Purpose: + * Prepares the mix engine for work, allocates buffers, locates effects modules, etc. + * + * Inputs: + * pEASData - instance data + * pInstData - pointer to variable to receive instance data handle + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_MixEngineInit (EAS_DATA_HANDLE pEASData); + +/*---------------------------------------------------------------------------- + * EAS_MixEnginePrep() + *---------------------------------------------------------------------------- + * Purpose: + * Performs prep before synthesize a buffer of audio, such as clearing + * audio buffers, etc. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void EAS_MixEnginePrep (EAS_DATA_HANDLE pEASData, EAS_I32 nNumSamplesToAdd); + +/*---------------------------------------------------------------------------- + * EAS_MixEnginePost + *---------------------------------------------------------------------------- + * Purpose: + * This routine does the post-processing after all voices have been + * synthesized. It calls any sweeteners and does the final mixdown to + * the output buffer. + * + * Inputs: + * + * Outputs: + * + * Notes: + *---------------------------------------------------------------------------- +*/ +void EAS_MixEnginePost (EAS_DATA_HANDLE pEASData, EAS_I32 nNumSamplesToAdd); + +/*---------------------------------------------------------------------------- + * EAS_MixEngineShutdown() + *---------------------------------------------------------------------------- + * Purpose: + * Shuts down effects modules and deallocates memory + * + * Inputs: + * pEASData - instance data + * pInstData - instance data handle + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_MixEngineShutdown (EAS_DATA_HANDLE pEASData); + +#ifdef UNIFIED_MIXER +/*---------------------------------------------------------------------------- + * EAS_MixStream + *---------------------------------------------------------------------------- + * Mix a 16-bit stream into a 32-bit buffer + * + * pInputBuffer 16-bit input buffer + * pMixBuffer 32-bit mix buffer + * numSamples number of samples to mix + * gainLeft initial gain left or mono + * gainRight initial gain right + * gainLeft left gain increment per sample + * gainRight right gain increment per sample + * flags bit 0 = stereo source + * bit 1 = stereo output + *---------------------------------------------------------------------------- +*/ +void EAS_MixStream (EAS_PCM *pInputBuffer, EAS_I32 *pMixBuffer, EAS_I32 numSamples, EAS_I32 gainLeft, EAS_I32 gainRight, EAS_I32 gainIncLeft, EAS_I32 gainIncRight, EAS_I32 flags); +#endif + +#endif /* #ifndef _EAS_MIXER_H */ + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_ota.c b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_ota.c new file mode 100755 index 0000000..5bc9062 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_ota.c @@ -0,0 +1,1077 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_ota.c + * + * Contents and purpose: + * OTA parser + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 795 $ + * $Date: 2007-08-01 00:14:45 -0700 (Wed, 01 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_data.h" +#include "eas_miditypes.h" +#include "eas_parser.h" +#include "eas_report.h" +#include "eas_host.h" +#include "eas_midi.h" +#include "eas_config.h" +#include "eas_vm_protos.h" +#include "eas_otadata.h" + +/* increase gain for mono ringtones */ +#define OTA_GAIN_OFFSET 8 + +/* file definitions */ +#define OTA_RINGTONE 0x25 +#define OTA_SOUND 0x1d +#define OTA_UNICODE 0x22 + +/* song type definitions */ +#define OTA_BASIC_SONG_TYPE 0x01 +#define OTA_TEMPORARY_SONG_TYPE 0x02 + +/* instruction ID coding */ +#define OTA_PATTERN_HEADER_ID 0x00 +#define OTA_NOTE_INST_ID 0x01 +#define OTA_SCALE_INST_ID 0x02 +#define OTA_STYLE_INST_ID 0x03 +#define OTA_TEMPO_INST_ID 0x04 +#define OTA_VOLUME_INST_ID 0x05 + +/* note durations */ +#define OTA_NORMAL_DURATION 0x00 +#define OTA_DOTTED_NOTE 0x01 +#define OTA_DOUBLE_DOTTED_NOTE 0x02 +#define OTA_TRIPLET_NOTE 0x03 + +/* loop count value for infinite loop */ +#define OTA_INFINITE_LOOP 0x0f + +/* length of 32nd note in 1/256ths of a msec for 63 BPM tempo */ +#define DEFAULT_TICK_CONV 30476 + +/* default channel and program for OTA playback */ +#define OTA_CHANNEL 0 +#define OTA_PROGRAM 80 +#define OTA_VEL_MUL 4 +#define OTA_VEL_OFS 67 +#define OTA_VEL_DEFAULT 95 + +/* multiplier for fixed point triplet conversion */ +#define TRIPLET_MULTIPLIER 683 +#define TRIPLET_SHIFT 10 + +/* local prototypes */ +static EAS_RESULT OTA_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset); +static EAS_RESULT OTA_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT OTA_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime); +static EAS_RESULT OTA_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode); +static EAS_RESULT OTA_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_STATE *pState); +static EAS_RESULT OTA_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT OTA_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT OTA_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT OTA_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT OTA_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value); +static EAS_RESULT OTA_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue); +static EAS_RESULT OTA_ParseHeader (S_EAS_DATA *pEASData, S_OTA_DATA* pData); +static EAS_RESULT OTA_FetchBitField (EAS_HW_DATA_HANDLE hwInstData, S_OTA_DATA *pData, EAS_I32 numBits, EAS_U8 *pValue); +static EAS_RESULT OTA_SavePosition (EAS_HW_DATA_HANDLE hwInstData, S_OTA_DATA *pData, S_OTA_LOC *pLoc); +static EAS_RESULT OTA_RestorePosition (EAS_HW_DATA_HANDLE hwInstData, S_OTA_DATA *pData, S_OTA_LOC *pLoc); + + +/*---------------------------------------------------------------------------- + * + * EAS_OTA_Parser + * + * This structure contains the functional interface for the OTA parser + *---------------------------------------------------------------------------- +*/ +const S_FILE_PARSER_INTERFACE EAS_OTA_Parser = +{ + OTA_CheckFileType, + OTA_Prepare, + OTA_Time, + OTA_Event, + OTA_State, + OTA_Close, + OTA_Reset, + OTA_Pause, + OTA_Resume, + NULL, + OTA_SetData, + OTA_GetData, + NULL +}; + +/*---------------------------------------------------------------------------- + * + * bpmTable + * + * BPM conversion table. Converts bpm values to 256ths of a millisecond for a 32nd note + *---------------------------------------------------------------------------- +*/ +static const EAS_U32 bpmTable[32] = +{ + 76800, 68571, 61935, 54857, + 48000, 42667, 38400, 34286, + 30476, 27429, 24000, 21333, + 19200, 17143, 15360, 13714, + 12000, 10667, 9600, 8533, + 7680, 6737, 6000, 5408, + 4800, 4267, 3840, 3398, + 3024, 2685, 2400, 2133 +}; + +/*---------------------------------------------------------------------------- + * OTA_CheckFileType() + *---------------------------------------------------------------------------- + * Purpose: + * Check the file type to see if we can parse it + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT OTA_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset) +{ + S_OTA_DATA* pData; + EAS_RESULT result; + EAS_INT cmdLen; + EAS_INT state; + EAS_U8 temp; + + /* read the first byte, should be command length */ + *ppHandle = NULL; + if ((result = EAS_HWGetByte(pEASData->hwInstData, fileHandle, &temp)) != EAS_SUCCESS) + return result; + + /* read all the commands */ + cmdLen = temp; + state = 0; + while (cmdLen--) + { + + /* read the command, upper 7 bits */ + if ((result = EAS_HWGetByte(pEASData->hwInstData, fileHandle, &temp)) != EAS_SUCCESS) + return result; + temp = temp >> 1; + + if (state == 0) + { + if (temp != OTA_RINGTONE) + break; + state++; + } + else + { + + if (temp == OTA_SOUND) + { + + /* check for static memory allocation */ + if (pEASData->staticMemoryModel) + pData = EAS_CMEnumData(EAS_CM_OTA_DATA); + else + pData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_OTA_DATA)); + if (!pData) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Malloc failed in OTA_Prepare\n"); */ } + return EAS_ERROR_MALLOC_FAILED; + } + EAS_HWMemSet(pData, 0, sizeof(S_OTA_DATA)); + + /* return a pointer to the instance data */ + pData->fileHandle = fileHandle; + pData->fileOffset = offset; + pData->state = EAS_STATE_OPEN; + *ppHandle = pData; + break; + } + + if (temp != OTA_UNICODE) + break; + } + } + + /* not recognized */ + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_Prepare() + *---------------------------------------------------------------------------- + * Purpose: + * Prepare to parse the file. Allocates instance data (or uses static allocation for + * static memory model). + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT OTA_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_OTA_DATA* pData; + EAS_RESULT result; + + /* check for valid state */ + pData = (S_OTA_DATA*) pInstData; + if (pData->state != EAS_STATE_OPEN) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + /* instantiate a synthesizer */ + if ((result = VMInitMIDI(pEASData, &pData->pSynth)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitMIDI returned %d\n", result); */ } + return result; + } + + pData->state = EAS_STATE_ERROR; + if ((result = OTA_ParseHeader(pEASData, pData)) != EAS_SUCCESS) + return result; + + pData->state = EAS_STATE_READY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_Time() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the time of the next event in msecs + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * pTime - pointer to variable to hold time of next event (in msecs) + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ +static EAS_RESULT OTA_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime) +{ + S_OTA_DATA *pData; + + pData = (S_OTA_DATA*) pInstData; + + /* return time in milliseconds */ + /*lint -e{704} use shift instead of division */ + *pTime = pData->time >> 8; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_Event() + *---------------------------------------------------------------------------- + * Purpose: + * Parse the next event in the file + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT OTA_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode) +{ + S_OTA_DATA* pData; + EAS_RESULT result; + EAS_U32 duration; + EAS_U8 temp; + + pData = (S_OTA_DATA*) pInstData; + if (pData->state >= EAS_STATE_OPEN) + return EAS_SUCCESS; + + /* initialize MIDI channel when the track starts playing */ + if (pData->time == 0) + { + /* set program to square lead */ + if (parserMode != eParserModeMetaData) + VMProgramChange(pEASData->pVoiceMgr, pData->pSynth, OTA_CHANNEL, OTA_PROGRAM); + + /* set channel volume to max */ + if (parserMode != eParserModeMetaData) + VMControlChange(pEASData->pVoiceMgr, pData->pSynth, OTA_CHANNEL, 7, 127); + } + + /* check for end of note */ + if (pData->note) + { + /* stop the note */ + VMStopNote(pEASData->pVoiceMgr, pData->pSynth, OTA_CHANNEL, pData->note, 0); + pData->note = 0; + + /* check for rest between notes */ + if (pData->restTicks) + { + pData->time += (EAS_I32) pData->restTicks; + pData->restTicks = 0; + return EAS_SUCCESS; + } + } + + /* if not in a pattern, read the pattern header */ + while (pData->current.patternLen == 0) + { + + /* check for loop - don't do infinite loops when locating */ + if (pData->loopCount && ((parserMode == eParserModePlay) || (pData->loopCount != OTA_INFINITE_LOOP))) + { + /* if not infinite loop, decrement loop count */ + if (pData->loopCount != OTA_INFINITE_LOOP) + pData->loopCount--; + + /* back to start of pattern*/ + if ((result = OTA_RestorePosition(pEASData->hwInstData, pData, &pData->patterns[pData->currentPattern])) != EAS_SUCCESS) + return result; + } + + /* if no previous position to restore, continue forward */ + else if (pData->restore.fileOffset < 0) + { + + /* check for end of song */ + if (pData->numPatterns == 0) + { + pData->state = EAS_STATE_STOPPING; + VMReleaseAllVoices(pEASData->pVoiceMgr, pData->pSynth); + return EAS_SUCCESS; + } + + /* read the next pattern header */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 3, &temp)) != EAS_SUCCESS) + return result; + if (temp != OTA_PATTERN_HEADER_ID) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Expected OTA pattern header\n"); */ } + return EAS_ERROR_FILE_FORMAT; + } + + /* get the pattern ID */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 2, &pData->currentPattern)) != EAS_SUCCESS) + return result; + + /* get the loop count */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 4, &pData->loopCount)) != EAS_SUCCESS) + return result; + + /* get the pattern length */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 8, &pData->current.patternLen)) != EAS_SUCCESS) + return result; + + /* if pattern definition, save the current position */ + if (pData->current.patternLen) + { + if ((result = OTA_SavePosition(pEASData->hwInstData, pData, &pData->patterns[pData->currentPattern])) != EAS_SUCCESS) + return result; + } + + /* if pattern length is zero, repeat a previous pattern */ + else + { + /* make sure it's a valid pattern */ + if (pData->patterns[pData->currentPattern].fileOffset < 0) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "OTA pattern error, invalid pattern specified\n"); */ } + return EAS_ERROR_FILE_FORMAT; + } + + /* save current position and data */ + if ((result = OTA_SavePosition(pEASData->hwInstData, pData, &pData->restore)) != EAS_SUCCESS) + return result; + + /* seek to the pattern in the file */ + if ((result = OTA_RestorePosition(pEASData->hwInstData, pData, &pData->patterns[pData->currentPattern])) != EAS_SUCCESS) + return result; + } + + /* decrement pattern count */ + pData->numPatterns--; + } + + /* restore previous position */ + else + { + if ((result = OTA_RestorePosition(pEASData->hwInstData, pData, &pData->restore)) != EAS_SUCCESS) + return result; + } + } + + /* get the next event */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 3, &temp)) != EAS_SUCCESS) + return result; + + switch (temp) + { + case OTA_NOTE_INST_ID: + /* fetch note value */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 4, &pData->note)) != EAS_SUCCESS) + return result; + + /* fetch note duration */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 3, &temp)) != EAS_SUCCESS) + return result; + duration = pData->tick * (0x20 >> temp); + + /* fetch note duration modifier */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 2, &temp)) != EAS_SUCCESS) + return result; + switch (temp) + { + case OTA_NORMAL_DURATION: + break; + + case OTA_DOTTED_NOTE: + duration += duration >> 1; + break; + + case OTA_DOUBLE_DOTTED_NOTE: + duration += (duration >> 1) + (duration >> 2); + break; + + case OTA_TRIPLET_NOTE: + duration = (duration * TRIPLET_MULTIPLIER) >> TRIPLET_SHIFT; + break; + + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Unrecognized note duration ignored\n"); */ } + break; + } + + /* check for note */ + if (pData->note) + { + + /* determine note length based on style */ + switch (pData->style) + { + case 0: + pData->restTicks = duration >> 4; + break; + case 1: + pData->restTicks = 0; + break; + case 2: + pData->restTicks = duration >> 1; + break; + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Unrecognized note style ignored\n"); */ } + } + + /* add octave */ + pData->note += pData->octave; + if (parserMode == eParserModePlay) + VMStartNote(pEASData->pVoiceMgr, pData->pSynth, OTA_CHANNEL, pData->note, pData->velocity); + pData->time += (EAS_I32) duration - (EAS_I32) pData->restTicks; + } + + /* this is a rest */ + else + pData->time += (EAS_I32) duration; + break; + + case OTA_SCALE_INST_ID: + /* fetch octave */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 2, &temp)) != EAS_SUCCESS) + return result; + pData->octave = (EAS_U8) (temp * 12 + 59); + break; + + case OTA_STYLE_INST_ID: + /* fetch note style */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 2, &pData->style)) != EAS_SUCCESS) + return result; + break; + + case OTA_TEMPO_INST_ID: + /* fetch tempo */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 5, &temp)) != EAS_SUCCESS) + return result; + pData->tick = bpmTable[temp]; + break; + + case OTA_VOLUME_INST_ID: + /* fetch volume */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 4, &temp)) != EAS_SUCCESS) + return result; + pData->velocity = temp ? (EAS_U8) (temp * OTA_VEL_MUL + OTA_VEL_OFS) : 0; + break; + + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Unexpected instruction ID in OTA stream\n"); */ } + return EAS_ERROR_FILE_FORMAT; + } + + /* decrement pattern length */ + pData->current.patternLen--; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_State() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current state of the stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * pState - pointer to variable to store state + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ +static EAS_RESULT OTA_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pState) +{ + S_OTA_DATA* pData; + + /* establish pointer to instance data */ + pData = (S_OTA_DATA*) pInstData; + + /* if stopping, check to see if synth voices are active */ + if (pData->state == EAS_STATE_STOPPING) + { + if (VMActiveVoices(pData->pSynth) == 0) + pData->state = EAS_STATE_STOPPED; + } + + if (pData->state == EAS_STATE_PAUSING) + { + if (VMActiveVoices(pData->pSynth) == 0) + pData->state = EAS_STATE_PAUSED; + } + + /* return current state */ + *pState = pData->state; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_Close() + *---------------------------------------------------------------------------- + * Purpose: + * Close the file and clean up + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT OTA_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_OTA_DATA* pData; + EAS_RESULT result; + + pData = (S_OTA_DATA*) pInstData; + + /* close the file */ + if ((result = EAS_HWCloseFile(pEASData->hwInstData, pData->fileHandle)) != EAS_SUCCESS) + return result; + + /* free the synth */ + if (pData->pSynth != NULL) + VMMIDIShutdown(pEASData, pData->pSynth); + + /* if using dynamic memory, free it */ + if (!pEASData->staticMemoryModel) + EAS_HWFree(pEASData->hwInstData, pData); + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_Reset() + *---------------------------------------------------------------------------- + * Purpose: + * Reset the sequencer. Used for locating backwards in the file. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT OTA_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_OTA_DATA* pData; + EAS_RESULT result; + + pData = (S_OTA_DATA*) pInstData; + + /* reset the synth */ + VMReset(pEASData->pVoiceMgr, pData->pSynth, EAS_TRUE); + pData->note = 0; + + /* reset file position and re-parse header */ + pData->state = EAS_STATE_ERROR; + if ((result = OTA_ParseHeader (pEASData, pData)) != EAS_SUCCESS) + return result; + + pData->state = EAS_STATE_READY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_Pause() + *---------------------------------------------------------------------------- + * Purpose: + * Pauses the sequencer. Mutes all voices and sets state to pause. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT OTA_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_OTA_DATA *pData; + + /* can't pause a stopped stream */ + pData = (S_OTA_DATA*) pInstData; + if (pData->state == EAS_STATE_STOPPED) + return EAS_ERROR_ALREADY_STOPPED; + + /* mute the synthesizer */ + VMMuteAllVoices(pEASData->pVoiceMgr, pData->pSynth); + pData->state = EAS_STATE_PAUSING; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_Resume() + *---------------------------------------------------------------------------- + * Purpose: + * Resume playing after a pause, sets state back to playing. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ +static EAS_RESULT OTA_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_OTA_DATA *pData; + + /* can't resume a stopped stream */ + pData = (S_OTA_DATA*) pInstData; + if (pData->state == EAS_STATE_STOPPED) + return EAS_ERROR_ALREADY_STOPPED; + + /* nothing to do but resume playback */ + pData->state = EAS_STATE_PLAY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_SetData() + *---------------------------------------------------------------------------- + * Purpose: + * Return file type + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ +static EAS_RESULT OTA_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value) +{ + S_OTA_DATA *pData; + + pData = (S_OTA_DATA *) pInstData; + switch (param) + { + + /* set metadata callback */ + case PARSER_DATA_METADATA_CB: + EAS_HWMemCpy(&pData->metadata, (void*) value, sizeof(S_METADATA_CB)); + break; + + default: + return EAS_ERROR_INVALID_PARAMETER; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_GetData() + *---------------------------------------------------------------------------- + * Purpose: + * Return file type + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ +static EAS_RESULT OTA_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue) +{ + S_OTA_DATA *pData; + + pData = (S_OTA_DATA*) pInstData; + switch (param) + { + /* return file type as OTA */ + case PARSER_DATA_FILE_TYPE: + *pValue = EAS_FILE_OTA; + break; + +#if 0 + /* set transposition */ + case PARSER_DATA_TRANSPOSITION: + *pValue = pData->transposition; + break; +#endif + + case PARSER_DATA_SYNTH_HANDLE: + *pValue = (EAS_I32) pData->pSynth; + break; + + case PARSER_DATA_GAIN_OFFSET: + *pValue = OTA_GAIN_OFFSET; + break; + + default: + return EAS_ERROR_INVALID_PARAMETER; + } + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_ParseHeader() + *---------------------------------------------------------------------------- + * Purpose: + * Prepare to parse the file. Allocates instance data (or uses static allocation for + * static memory model). + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT OTA_ParseHeader (S_EAS_DATA *pEASData, S_OTA_DATA* pData) +{ + EAS_RESULT result; + EAS_INT i; + EAS_INT state; + EAS_U8 temp; + EAS_U8 titleLen; + + /* initialize some data */ + pData->flags = 0; + pData->time = 0; + pData->tick = DEFAULT_TICK_CONV; + pData->patterns[0].fileOffset = pData->patterns[1].fileOffset = + pData->patterns[2].fileOffset = pData->patterns[3].fileOffset = -1; + pData->current.bitCount = 0; + pData->current.patternLen = 0; + pData->loopCount = 0; + pData->restore.fileOffset = -1; + pData->note = 0; + pData->restTicks = 0; + pData->velocity = OTA_VEL_DEFAULT; + pData->style = 0; + pData->octave = 59; + + /* seek to start of data */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pData->fileHandle, pData->fileOffset)) != EAS_SUCCESS) + return result; + + /* read the first byte, should be command length */ + if ((result = EAS_HWGetByte(pEASData->hwInstData, pData->fileHandle, &temp)) != EAS_SUCCESS) + return result; + + /* read all the commands */ + i = temp; + state = 0; + while (i--) + { + + /* fetch command, always starts on byte boundary */ + pData->current.bitCount = 0; + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 7, &temp)) != EAS_SUCCESS) + return result; + + if (state == 0) + { + if (temp != OTA_RINGTONE) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Expected OTA Ring Tone Programming type\n"); */ } + return EAS_ERROR_FILE_FORMAT; + } + state++; + } + else + { + + if (temp == OTA_SOUND) + break; + + if (temp == OTA_UNICODE) + pData->flags |= OTA_FLAGS_UNICODE; + else + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Expected OTA Sound or Unicode type\n"); */ } + return EAS_ERROR_FILE_FORMAT; + } + } + } + + /* get song type */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 3, &temp)) != EAS_SUCCESS) + return result; + + /* check for basic song type */ + if (temp == OTA_BASIC_SONG_TYPE) + { + /* fetch title length */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 4, &titleLen)) != EAS_SUCCESS) + return result; + + /* if unicode, double the length */ + if (pData->flags & OTA_FLAGS_UNICODE) + titleLen = (EAS_U8) (titleLen << 1); + + /* zero the metadata buffer */ + if (pData->metadata.buffer) + EAS_HWMemSet(pData->metadata.buffer, 0, pData->metadata.bufferSize); + + /* read the song title */ + for (i = 0; i < titleLen; i++) + { + /* fetch character */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 8, &temp)) != EAS_SUCCESS) + return result; + + /* check for metadata callback */ + if (pData->metadata.callback) + { + if (i < (pData->metadata.bufferSize - 1)) + pData->metadata.buffer[i] = (char) temp; + } + } + + /* if host has registered callback, call it now */ + if (pData->metadata.callback) + (*pData->metadata.callback)(EAS_METADATA_TITLE, pData->metadata.buffer, pData->metadata.pUserData); + } + + /* must be temporary song */ + else if (temp != OTA_TEMPORARY_SONG_TYPE) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Expected OTA basic or temporary song type\n"); */ } + return EAS_ERROR_FILE_FORMAT; + } + + /* get the song length */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 8, &pData->numPatterns)) != EAS_SUCCESS) + return result; + + /* sanity check */ + if (pData->numPatterns == 0) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "OTA number of patterns is zero\n"); */ } + return EAS_ERROR_FILE_FORMAT; + } + + /* at start of first pattern */ + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_FetchBitField() + *---------------------------------------------------------------------------- + * Purpose: + * Fetch a specified number of bits from the input stream + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT OTA_FetchBitField (EAS_HW_DATA_HANDLE hwInstData, S_OTA_DATA *pData, EAS_I32 numBits, EAS_U8 *pValue) +{ + EAS_RESULT result; + EAS_I32 bitsLeft; + EAS_U8 value; + + value = 0; + + /* do we have enough bits? */ + bitsLeft = pData->current.bitCount - numBits; + + /* not enough bits, assemble them from 2 characters */ + if (bitsLeft < 0) + { + /* grab the remaining bits from the previous byte */ + if (pData->current.bitCount) + /*lint -e{504,734} this is a legitimate shift operation */ + value = pData->current.dataByte << -bitsLeft; + + /* read the next byte */ + if ((result = EAS_HWGetByte(hwInstData, pData->fileHandle, &pData->current.dataByte)) != EAS_SUCCESS) + return result; + bitsLeft += 8; + } + + /* more bits than needed? */ + if (bitsLeft > 0) + { + value |= pData->current.dataByte >> bitsLeft; + pData->current.bitCount = (EAS_U8) bitsLeft; + pData->current.dataByte = pData->current.dataByte & (0xff >> (8 - bitsLeft)); + } + + /* exactly the right number of bits */ + else + { + value |= pData->current.dataByte; + pData->current.bitCount = 0; + } + + *pValue = value; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_SavePosition() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT OTA_SavePosition (EAS_HW_DATA_HANDLE hwInstData, S_OTA_DATA *pData, S_OTA_LOC *pLoc) +{ + EAS_HWMemCpy(pLoc, &pData->current, sizeof(S_OTA_LOC)); + return EAS_HWFilePos(hwInstData, pData->fileHandle, &pLoc->fileOffset); +} + +/*---------------------------------------------------------------------------- + * OTA_RestorePosition() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT OTA_RestorePosition (EAS_HW_DATA_HANDLE hwInstData, S_OTA_DATA *pData, S_OTA_LOC *pLoc) +{ + EAS_HWMemCpy(&pData->current, pLoc, sizeof(S_OTA_LOC)); + pData->restore.fileOffset = -1; + return EAS_HWFileSeek(hwInstData, pData->fileHandle, pLoc->fileOffset); +} + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_otadata.c b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_otadata.c new file mode 100755 index 0000000..7463a0c --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_otadata.c @@ -0,0 +1,41 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_otadata..c + * + * Contents and purpose: + * OTA Stream Parser data module for static memory model + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 547 $ + * $Date: 2007-01-31 16:30:17 -0800 (Wed, 31 Jan 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_types.h" +#include "eas_otadata.h" + +/*---------------------------------------------------------------------------- + * + * eas_OTAData + * + * Static memory allocation for OTA parser + *---------------------------------------------------------------------------- +*/ +S_OTA_DATA eas_OTAData; + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_otadata.h b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_otadata.h new file mode 100755 index 0000000..c06e3d3 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_otadata.h @@ -0,0 +1,81 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_otadata.h + * + * Contents and purpose: + * OTA File Parser + * + * This file contains data declarations for the OTA parser. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef EAS_OTADATA_H +#define EAS_OTADATA_H + +#include "eas_data.h" + +/* definition for state flags */ +#define OTA_FLAGS_UNICODE 0x01 /* unicode text */ + +/*---------------------------------------------------------------------------- + * + * S_OTA_DATA + * + * This structure contains the state data for the OTA parser + *---------------------------------------------------------------------------- +*/ + +typedef struct +{ + EAS_I32 fileOffset; /* offset to location in file */ + EAS_U8 patternLen; /* length of current pattern */ + EAS_U8 dataByte; /* previous char from file */ + EAS_U8 bitCount; /* bit count in char */ +} S_OTA_LOC; + +typedef struct +{ + EAS_FILE_HANDLE fileHandle; /* file handle */ + S_SYNTH *pSynth; /* synth handle */ + EAS_I32 fileOffset; /* offset to start of data */ + EAS_I32 time; /* current time in 256ths of a msec */ + EAS_U32 tick; /* length of 32nd note in 256th of a msec */ + EAS_U32 restTicks; /* ticks to rest after current note */ + S_OTA_LOC patterns[4]; /* pattern locations */ + S_OTA_LOC current; /* current location */ + S_OTA_LOC restore; /* previous location */ + S_METADATA_CB metadata; /* metadata callback */ + EAS_U8 flags; /* bit flags */ + EAS_U8 numPatterns; /* number of patterns left in song */ + EAS_U8 currentPattern; /* current pattern for loop */ + EAS_U8 note; /* MIDI note number */ + EAS_U8 octave; /* octave modifier */ + EAS_U8 style; /* from STYLE */ + EAS_U8 velocity; /* current volume */ + EAS_U8 state; /* current state EAS_STATE_XXXX */ + EAS_U8 loopCount; /* loop count for pattern */ +} S_OTA_DATA; + +#endif + + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_pan.c b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_pan.c new file mode 100755 index 0000000..ae4c69d --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_pan.c @@ -0,0 +1,98 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_pan.c + * + * Contents and purpose: + * Calculates left and right gain multipliers based on a pan value from -63 to +63 + * + * NOTES: + * The _CMX_PARSER and _MFI_PARSER preprocessor symbols determine + * whether the parser works for those particular file formats. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_pan.h" +#include "eas_math.h" + +/*---------------------------------------------------------------------------- + * EAS_CalcPanControl() + *---------------------------------------------------------------------------- + * Purpose: + * Assign the left and right gain values corresponding to the given pan value. + * + * This routine uses sin/cos approximations for an equal power curve: + * + * sin(x) = (2-4*c)*x^2 + c + x + * cos(x) = (2-4*c)*x^2 + c - x + * + * where c = 1/sqrt(2) + * using the a0 + x*(a1 + x*a2) approach + * + * Inputs: + * pan - pan value (-63 to + 63) + * + * Outputs: + * pGainLeft linear gain multiplier for left channel (15-bit fraction) + * pGainRight linear gain multiplier for left channel (15-bit fraction) + * + * Side Effects: + *---------------------------------------------------------------------------- +*/ +void EAS_CalcPanControl (EAS_INT pan, EAS_I16 *pGainLeft, EAS_I16 *pGainRight) +{ + EAS_INT temp; + EAS_INT netAngle; + + /* impose hard limit */ + if (pan < -63) + netAngle = -63; + else if (pan > 63) + netAngle = 63; + else + netAngle = pan; + + /*lint -e{701} */ + netAngle = netAngle << 8; + + /* calculate sin */ + temp = EG1_ONE + FMUL_15x15(COEFF_PAN_G2, netAngle); + temp = COEFF_PAN_G0 + FMUL_15x15(temp, netAngle); + + if (temp > SYNTH_FULL_SCALE_EG1_GAIN) + temp = SYNTH_FULL_SCALE_EG1_GAIN; + else if (temp < 0) + temp = 0; + + *pGainRight = (EAS_I16) temp; + + /* calculate cos */ + temp = -EG1_ONE + FMUL_15x15(COEFF_PAN_G2, netAngle); + temp = COEFF_PAN_G0 + FMUL_15x15(temp, netAngle); + if (temp > SYNTH_FULL_SCALE_EG1_GAIN) + temp = SYNTH_FULL_SCALE_EG1_GAIN; + else if (temp < 0) + temp = 0; + + *pGainLeft = (EAS_I16) temp; +} + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_pan.h b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_pan.h new file mode 100755 index 0000000..cb0a90d --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_pan.h @@ -0,0 +1,66 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_pan.h + * + * Contents and purpose: + * Calculates left and right gain multipliers based on a pan value from -63 to +63 + * + * NOTES: + * The _CMX_PARSER and _MFI_PARSER preprocessor symbols determine + * whether the parser works for those particular file formats. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef EAS_PAN_H +#define _EAS_PAN_H + +#include "eas_types.h" + +/*---------------------------------------------------------------------------- + * EAS_CalcPanControl() + *---------------------------------------------------------------------------- + * Purpose: + * Assign the left and right gain values corresponding to the given pan value. + * + * This routine uses sin/cos approximations for an equal power curve: + * + * sin(x) = (2-4*c)*x^2 + c + x + * cos(x) = (2-4*c)*x^2 + c - x + * + * where c = 1/sqrt(2) + * using the a0 + x*(a1 + x*a2) approach + * + * Inputs: + * pan - pan value (-63 to + 63) + * + * Outputs: + * pGainLeft linear gain multiplier for left channel (15-bit fraction) + * pGainRight linear gain multiplier for left channel (15-bit fraction) + * + * Side Effects: + *---------------------------------------------------------------------------- +*/ +void EAS_CalcPanControl (EAS_INT pan, EAS_I16 *pGainLeft, EAS_I16 *pGainRight); + +#endif + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_parser.h b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_parser.h new file mode 100755 index 0000000..96ec35b --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_parser.h @@ -0,0 +1,98 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_parser.h + * + * Contents and purpose: + * Interface declarations for the generic parser interface + * + * This header only contains declarations that are specific + * to this implementation. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 767 $ + * $Date: 2007-07-19 13:47:31 -0700 (Thu, 19 Jul 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_PARSER_H +#define _EAS_PARSER_H + +#include "eas_types.h" + + +/* metadata callback */ +typedef struct s_metadata_cb_tag +{ + EAS_METADATA_CBFUNC callback; + char *buffer; + EAS_VOID_PTR pUserData; + EAS_I32 bufferSize; +} S_METADATA_CB; + +/* generic parser interface */ +typedef struct +{ + EAS_RESULT (* EAS_CONST pfCheckFileType)(struct s_eas_data_tag *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset); + EAS_RESULT (* EAS_CONST pfPrepare)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData); + EAS_RESULT (* EAS_CONST pfTime)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime); + EAS_RESULT (* EAS_CONST pfEvent)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData, EAS_INT parseMode); + EAS_RESULT (* EAS_CONST pfState)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData, EAS_STATE *pState); + EAS_RESULT (* EAS_CONST pfClose)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData); + EAS_RESULT (* EAS_CONST pfReset)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData); + EAS_RESULT (* EAS_CONST pfPause)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData); + EAS_RESULT (* EAS_CONST pfResume)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData); + EAS_RESULT (* EAS_CONST pfLocate)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData, EAS_I32 time, EAS_BOOL *pParserLocate); + EAS_RESULT (* EAS_CONST pfSetData)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value); + EAS_RESULT (* EAS_CONST pfGetData)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue); + EAS_RESULT (* EAS_CONST pfGetMetaData)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pMediaLength); +} S_FILE_PARSER_INTERFACE; + +typedef enum +{ + eParserModePlay, + eParserModeLocate, + eParserModeMute, + eParserModeMetaData +} E_PARSE_MODE; + +typedef enum +{ + PARSER_DATA_FILE_TYPE, + PARSER_DATA_PLAYBACK_RATE, + PARSER_DATA_TRANSPOSITION, + PARSER_DATA_VOLUME, + PARSER_DATA_SYNTH_HANDLE, + PARSER_DATA_METADATA_CB, + PARSER_DATA_DLS_COLLECTION, + PARSER_DATA_EAS_LIBRARY, + PARSER_DATA_POLYPHONY, + PARSER_DATA_PRIORITY, + PARSER_DATA_FORMAT, + PARSER_DATA_MEDIA_LENGTH, + PARSER_DATA_JET_CB, + PARSER_DATA_MUTE_FLAGS, + PARSER_DATA_SET_MUTE, + PARSER_DATA_CLEAR_MUTE, + PARSER_DATA_NOTE_COUNT, + PARSER_DATA_MAX_PCM_STREAMS, + PARSER_DATA_GAIN_OFFSET, + PARSER_DATA_PLAY_MODE +} E_PARSER_DATA; + +#endif /* #ifndef _EAS_PARSER_H */ diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_pcm.c b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_pcm.c new file mode 100755 index 0000000..ff3f6f9 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_pcm.c @@ -0,0 +1,1482 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_pcm.c + * + * Contents and purpose: + * Implements the PCM engine including ADPCM decode for SMAF and CMX audio playback. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 849 $ + * $Date: 2007-08-28 08:59:11 -0700 (Tue, 28 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_data.h" +#include "eas_report.h" +#include "eas_host.h" +#include "eas_config.h" +#include "eas_parser.h" +#include "eas_pcm.h" +#include "eas_math.h" +#include "eas_mixer.h" + +#define PCM_MIXER_GUARD_BITS (NUM_MIXER_GUARD_BITS + 1) + +/*---------------------------------------------------------------------------- + * Decoder interfaces + *---------------------------------------------------------------------------- +*/ + +static EAS_RESULT LinearPCMDecode (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState); +static EAS_RESULT LinearPCMLocate (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState, EAS_I32 time); + +static const S_DECODER_INTERFACE PCMDecoder = +{ + NULL, + LinearPCMDecode, + LinearPCMLocate, +}; + +/* SMAF ADPCM decoder */ +#ifdef _SMAF_PARSER +extern S_DECODER_INTERFACE SmafDecoder; +#define SMAF_DECODER &SmafDecoder +extern S_DECODER_INTERFACE Smaf7BitDecoder; +#define SMAF_7BIT_DECODER &Smaf7BitDecoder +#else +#define SMAF_DECODER NULL +#define SMAF_7BIT_DECODER NULL +#endif + +/* IMA ADPCM decoder */ +#ifdef _IMA_DECODER +extern S_DECODER_INTERFACE IMADecoder; +#define IMA_DECODER &IMADecoder +#else +#define IMA_DECODER NULL +#endif + +static const S_DECODER_INTERFACE * const decoders[] = +{ + &PCMDecoder, + SMAF_DECODER, + IMA_DECODER, + SMAF_7BIT_DECODER +}; + +/*---------------------------------------------------------------------------- + * Sample rate conversion + *---------------------------------------------------------------------------- +*/ + +#define SRC_RATE_MULTIPLER (0x40000000 / _OUTPUT_SAMPLE_RATE) + +#ifdef _LOOKUP_SAMPLE_RATE +static const EAS_U32 srcConvRate[][2] = +{ + 4000L, (4000L << 15) / _OUTPUT_SAMPLE_RATE, + 8000L, (8000L << 15) / _OUTPUT_SAMPLE_RATE, + 11025L, (11025L << 15) / _OUTPUT_SAMPLE_RATE, + 12000L, (12000L << 15) / _OUTPUT_SAMPLE_RATE, + 16000L, (16000L << 15) / _OUTPUT_SAMPLE_RATE, + 22050L, (22050L << 15) / _OUTPUT_SAMPLE_RATE, + 24000L, (24000L << 15) / _OUTPUT_SAMPLE_RATE, + 32000L, (32000L << 15) / _OUTPUT_SAMPLE_RATE +}; +static EAS_U32 CalcBaseFreq (EAS_U32 sampleRate); +#define SRC_CONV_RATE_ENTRIES (sizeof(srcConvRate)/sizeof(EAS_U32)/2) +#endif + + +/* interface prototypes */ +static EAS_RESULT RenderPCMStream (S_EAS_DATA *pEASData, S_PCM_STATE *pState, EAS_I32 numSamples); + + +/* local prototypes */ +static S_PCM_STATE *FindSlot (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_PCM_CALLBACK pCallbackFunc, EAS_VOID_PTR cbInstData); +static EAS_RESULT InitPCMStream (S_EAS_DATA *pEASData, S_PCM_STATE *pState); + +/*---------------------------------------------------------------------------- + * EAS_PEInit() + *---------------------------------------------------------------------------- + * Purpose: + * Initializes the PCM engine + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEInit (S_EAS_DATA *pEASData) +{ + S_PCM_STATE *pState; + EAS_INT i; + + /* check for static memory allocation */ + if (pEASData->staticMemoryModel) + pEASData->pPCMStreams = EAS_CMEnumData(EAS_CM_PCM_DATA); + /* allocate dynamic memory */ + else + pEASData->pPCMStreams = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_PCM_STATE) * MAX_PCM_STREAMS); + + if (!pEASData->pPCMStreams) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Failed to allocate memory for PCM streams\n"); */ } + return EAS_ERROR_MALLOC_FAILED; + } + + //zero the memory to insure complete initialization + EAS_HWMemSet((void *)(pEASData->pPCMStreams),0, sizeof(S_PCM_STATE) * MAX_PCM_STREAMS); + + /* initialize the state data */ + for (i = 0, pState = pEASData->pPCMStreams; i < MAX_PCM_STREAMS; i++, pState++) + pState->fileHandle = NULL; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_PEShutdown() + *---------------------------------------------------------------------------- + * Purpose: + * Shuts down the PCM engine + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEShutdown (S_EAS_DATA *pEASData) +{ + + /* free any dynamic memory */ + if (!pEASData->staticMemoryModel) + { + if (pEASData->pPCMStreams) + { + EAS_HWFree(pEASData->hwInstData, pEASData->pPCMStreams); + pEASData->pPCMStreams = NULL; + } + } + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_PERender() + *---------------------------------------------------------------------------- + * Purpose: + * Render a buffer of PCM audio + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PERender (S_EAS_DATA* pEASData, EAS_I32 numSamples) +{ + S_PCM_STATE *pState; + EAS_RESULT result; + EAS_INT i; + + /* render all the active streams */ + for (i = 0, pState = pEASData->pPCMStreams; i < MAX_PCM_STREAMS; i++, pState++) + { + if ((pState->fileHandle) && (pState->state != EAS_STATE_STOPPED) && (pState->state != EAS_STATE_PAUSED)) + if ((result = RenderPCMStream(pEASData, pState, numSamples)) != EAS_SUCCESS) + return result; + } + return EAS_SUCCESS; +} + + +/*---------------------------------------------------------------------------- + * EAS_PEState() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current state of the stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * pState - pointer to variable to store state + * + * Outputs: + * + * + * Side Effects: + * + * Notes: + * This interface is also exposed in the internal library for use by the other modules. + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT EAS_PEState (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pInstData, EAS_STATE *pState) +{ + /* return current state */ + *pState = pInstData->state; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_PEClose() + *---------------------------------------------------------------------------- + * Purpose: + * Close the file and clean up + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEClose (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pState) +{ + EAS_RESULT result; + + if ((result = EAS_HWCloseFile(pEASData->hwInstData, pState->fileHandle)) != EAS_SUCCESS) + return result; + + pState->fileHandle = NULL; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * PCM_Reset() + *---------------------------------------------------------------------------- + * Purpose: + * Reset the sequencer. Used for locating backwards in the file. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEReset (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pState) +{ + EAS_RESULT result; + + /* reset file position to first byte of data in the stream */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pState->fileHandle, pState->startPos)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %d seeking to start of PCM file\n", result); */ } + return result; + } + + /* re-initialize stream */ + return InitPCMStream(pEASData, pState); +} + +/*---------------------------------------------------------------------------- + * EAS_PEOpenStream() + *---------------------------------------------------------------------------- + * Purpose: + * Starts up a PCM playback + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEOpenStream (S_EAS_DATA *pEASData, S_PCM_OPEN_PARAMS *pParams, EAS_PCM_HANDLE *pHandle) +{ + EAS_RESULT result; + S_PCM_STATE *pState; + EAS_I32 filePos; + + /* make sure we support this decoder */ + if (pParams->decoder >= NUM_DECODER_MODULES) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Decoder selector out of range\n"); */ } + return EAS_ERROR_PARAMETER_RANGE; + } + if (decoders[pParams->decoder] == NULL) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Decoder module not available\n"); */ } + return EAS_ERROR_FEATURE_NOT_AVAILABLE; + } + + /* find a slot for the new stream */ + if ((pState = FindSlot(pEASData, pParams->fileHandle, pParams->pCallbackFunc, pParams->cbInstData)) == NULL) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Unable to open ADPCM stream, too many streams open\n"); */ } + return EAS_ERROR_MAX_PCM_STREAMS; + } + + /* get the current file position */ + if ((result = EAS_HWFilePos(pEASData->hwInstData, pState->fileHandle, &filePos)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_HWFilePos returned %ld\n",result); */ } + pState->fileHandle = NULL; + return result; + } + + pState->pDecoder = decoders[pParams->decoder]; + pState->startPos = filePos; + pState->bytesLeftLoop = pState->byteCount = pParams->size; + pState->loopStart = pParams->loopStart; + pState->samplesTilLoop = (EAS_I32) pState->loopStart; + pState->loopSamples = pParams->loopSamples; + pState->samplesInLoop = 0; + pState->blockSize = (EAS_U16) pParams->blockSize; + pState->flags = pParams->flags; + pState->envData = pParams->envData; + pState->volume = pParams->volume; + pState->sampleRate = (EAS_U16) pParams->sampleRate; + + /* set the base frequency */ + pState->basefreq = (SRC_RATE_MULTIPLER * (EAS_U32) pParams->sampleRate) >> 15; + + /* calculate shift for frequencies > 1.0 */ + pState->rateShift = 0; + while (pState->basefreq > 32767) + { + pState->basefreq = pState->basefreq >> 1; + pState->rateShift++; + } + + /* initialize */ + if ((result = InitPCMStream(pEASData, pState)) != EAS_SUCCESS) + return result; + + *pHandle = pState; + + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "EAS_PEOpenStream: StartPos=%d, byteCount = %d, loopSamples=%d\n", + pState->startPos, pState->byteCount, pState->loopSamples); */ } + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_PEContinueStream() + *---------------------------------------------------------------------------- + * Purpose: + * Continues a PCM stream + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -e{715} reserved for future use */ +EAS_RESULT EAS_PEContinueStream (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pState, EAS_I32 size) +{ + + /* add new samples to count */ + pState->bytesLeft += size; + if (pState->bytesLeft > 0) + pState->flags &= ~PCM_FLAGS_EMPTY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_PEGetFileHandle() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the file handle of a stream + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT EAS_PEGetFileHandle (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pState, EAS_FILE_HANDLE *pFileHandle) +{ + *pFileHandle = pState->fileHandle; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_PEUpdateParams() + *---------------------------------------------------------------------------- + * Purpose: + * Update the pitch and volume parameters for a PCM stream + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_PCM_STATE for this stream + * gainLeft - linear gain multipler in 1.15 fraction format + * gainRight - linear gain multipler in 1.15 fraction format + * pitch - pitch shift in cents + * initial - initial settings, set current gain + * + * Outputs: + * + * + * Side Effects: + * + * Notes + * In mono mode, leftGain controls the output gain and rightGain is ignored + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +/*lint -esym(715, gainRight) used only in 2-channel version */ +EAS_RESULT EAS_PEUpdateParams (S_EAS_DATA* pEASData, EAS_PCM_HANDLE pState, EAS_I16 pitch, EAS_I16 gainLeft, EAS_I16 gainRight) +{ + + pState->gainLeft = gainLeft; + +#if (NUM_OUTPUT_CHANNELS == 2) + pState->gainRight = gainRight; +#endif + + pState->pitch = pitch; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_PELocate() + *---------------------------------------------------------------------------- + * Purpose: + * This function seeks to the requested place in the file. Accuracy + * is dependent on the sample rate and block size. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * pState - stream handle + * time - media time in milliseconds + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PELocate (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pState, EAS_I32 time) +{ + if (pState->pDecoder->pfLocate == NULL) + return EAS_ERROR_FEATURE_NOT_AVAILABLE; + + return pState->pDecoder->pfLocate(pEASData, pState, time); +} + +/*---------------------------------------------------------------------------- + * EAS_PEUpdateVolume() + *---------------------------------------------------------------------------- + * Purpose: + * Update the volume parameters for a PCM stream + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_PCM_STATE for this stream + * gainLeft - linear gain multipler in 1.15 fraction format + * gainRight - linear gain multipler in 1.15 fraction format + * initial - initial settings, set current gain + * + * Outputs: + * + * + * Side Effects: + * + * Notes + * In mono mode, leftGain controls the output gain and rightGain is ignored + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT EAS_PEUpdateVolume (S_EAS_DATA* pEASData, EAS_PCM_HANDLE pState, EAS_I16 volume) +{ + pState->volume = volume; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_PEUpdatePitch() + *---------------------------------------------------------------------------- + * Purpose: + * Update the pitch parameter for a PCM stream + * + * Inputs: + * pEASData - pointer to EAS library instance data + * pState - pointer to S_PCM_STATE for this stream + * pitch - new pitch value in pitch cents + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT EAS_PEUpdatePitch (S_EAS_DATA* pEASData, EAS_PCM_HANDLE pState, EAS_I16 pitch) +{ + pState->pitch = pitch; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_PEPause() + *---------------------------------------------------------------------------- + * Purpose: + * Mute and stop rendering a PCM stream. Sets the gain target to zero and stops the playback + * at the end of the next audio frame. + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_PCM_STATE for this stream + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT EAS_PEPause (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pState) +{ + /* set state to stopping */ + pState->state = EAS_STATE_PAUSING; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_PEResume() + *---------------------------------------------------------------------------- + * Purpose: + * Resume rendering a PCM stream. Sets the gain target back to its + * previous setting and restarts playback at the end of the next audio + * frame. + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_PCM_STATE for this stream + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT EAS_PEResume (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pState) +{ + /* set state to stopping */ + pState->state = EAS_STATE_PLAY; + return EAS_SUCCESS; +} + +EAS_U32 getDecayScale(EAS_U32 index) +{ + EAS_U32 utemp; + + //envelope decay segment + switch (index) + { + case 0: //no decay + utemp = 512;//32768; + break; + case 1: //.0156 dB per update + utemp = 511;//32709; + break; + case 2: //.03125 + utemp = 510;//32649; + break; + case 3: //.0625 + utemp = 508;//32532; + break; + case 4: //.125 + utemp = 505;//32298; + break; + case 5: //.25 + utemp = 497;//31835; + break; + case 6: //.5 + utemp = 483;//30929; + break; + case 7: //1.0 + utemp = 456;//29193; + break; + case 8: //2.0 + utemp = 406;//26008; + break; + case 9: //4.0 + utemp = 323;//20642; + break; + case 10: //8.0 + utemp = 203;//13004; + break; + case 11: //16.0 + utemp = 81;//5160; + break; + case 12: //32.0 + utemp = 13;//813; + break; + case 13: //64.0 + utemp = 0;//20; + break; + case 14: //128.0 + utemp = 0; + break; + case 15: //256.0 + default: + utemp = 0; + break; + } + //printf("getdecayscale returned %d\n",utemp); + return utemp; +} + +EAS_U32 getAttackIncrement(EAS_U32 index) +{ + EAS_U32 utemp; + + //envelope decay segment + switch (index) + { + case 0: + utemp = 32; + break; + case 1: + utemp = 64; + break; + case 2: + utemp = 128; + break; + case 3: + utemp = 256; + break; + case 4: + utemp = 512; + break; + case 5: + utemp = 1024; + break; + case 6: + utemp = 2048; + break; + case 7: + utemp = 4096; + break; + case 8: + utemp = 8192; + break; + case 9: + utemp = 16384; + break; + case 10: + utemp = 32768; + break; + case 11: + utemp = 65536; + break; + case 12: + utemp = 65536; + break; + case 13: + utemp = 65536; + break; + case 14: + utemp = 65535; + break; + case 15: + default: + utemp = 0; + break; + } + //printf("getattackincrement returned %d\n",utemp); + return utemp; +} + +/*---------------------------------------------------------------------------- + * EAS_PERelease() + *---------------------------------------------------------------------------- + * Purpose: + * Put the PCM stream envelope into release. + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_PCM_STATE for this stream + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT EAS_PERelease (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pState) +{ + EAS_U32 utemp; + + //printf("handling note-off part of envelope\n"); + /*if the note is not ignore release or sustained*/ + if (((pState->envData >> 24) & 0x0F)==0) + { + /* set envelope state to release */ + pState->envState = PCM_ENV_RELEASE; + utemp = ((pState->envData >> 20) & 0x0F); + pState->envScale = getDecayScale(utemp); //getReleaseScale(utemp); + } + else + { + /*else change envelope state to sustain */ + pState->envState = PCM_ENV_SUSTAIN; + utemp = ((pState->envData >> 28) & 0x0F); + pState->envScale = getDecayScale(utemp); //getSustainScale(utemp); + } + //since we are in release, don't let anything hang around too long + //printf("checking env scale, val = %d\n",((S_PCM_STATE*) handle)->envScale); + if (pState->envScale > 505) + pState->envScale = 505; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * FindSlot() + *---------------------------------------------------------------------------- + * Purpose: + * Locates an empty stream slot and assigns the file handle + * + * Inputs: + * pEASData - pointer to EAS library instance data + * fileHandle - file handle + * pCallbackFunc - function to be called back upon EAS_STATE_STOPPED + * + * Outputs: + * returns handle to slot or NULL if all slots are used + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static S_PCM_STATE *FindSlot (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_PCM_CALLBACK pCallbackFunc, EAS_VOID_PTR cbInstData) +{ + EAS_INT i; + S_PCM_STATE *pState; + +#ifndef NO_PCM_STEAL + S_PCM_STATE *foundState = NULL; + EAS_INT count = 0; + EAS_U32 startOrder = 0xFFFFFFFF; + S_PCM_STATE *stealState = NULL; + EAS_U32 youngest = 0; + + /* find an empty slot, count total in use, and find oldest in use (lowest start order) */ + for (i = 0, pState = pEASData->pPCMStreams; i < MAX_PCM_STREAMS; i++, pState++) + { + /* if this one is available */ + if (pState->fileHandle == NULL) + { + foundState = pState; + } + /* else this one is in use, so see if it is the oldest, and count total in use */ + /* also find youngest */ + else + { + /*one more voice in use*/ + count++; + /* is this the oldest? (lowest start order) */ + if ((pState->state != EAS_STATE_STOPPING) && (pState->startOrder < startOrder)) + { + /* remember this one */ + stealState = pState; + /* remember the oldest so far */ + startOrder = pState->startOrder; + } + /* is this the youngest? (highest start order) */ + if (pState->startOrder >= youngest) + { + youngest = pState->startOrder; + } + } + } + + /* if there are too many voices active, stop the oldest one */ + if (count > PCM_STREAM_THRESHOLD) + { + //printf("stealing!!!\n"); + /* make sure we got one, although we should always have one at this point */ + if (stealState != NULL) + { + //flag this as stopping, so it will get shut off + stealState->state = EAS_STATE_STOPPING; + } + } + + /* if there are no available open streams (we won't likely see this, due to stealing) */ + if (foundState == NULL) + return NULL; + + /* save info */ + foundState->startOrder = youngest + 1; + foundState->fileHandle = fileHandle; + foundState->pCallback = pCallbackFunc; + foundState->cbInstData = cbInstData; + return foundState; +#else + /* find an empty slot*/ + for (i = 0; i < MAX_PCM_STREAMS; i++) + { + pState = &pEASData->pPCMStreams[i]; + if (pState->fileHandle != NULL) + continue; + + pState->fileHandle = fileHandle; + pState->pCallback = pCallbackFunc; + pState->cbInstData = cbInstData; + return pState; + } + return NULL; +#endif +} + +#ifdef _LOOKUP_SAMPLE_RATE +/*---------------------------------------------------------------------------- + * CalcBaseFreq() + *---------------------------------------------------------------------------- + * Purpose: + * Calculates the fractional phase increment for the sample rate converter + * + * Inputs: + * sampleRate - sample rate in samples/sec + * + * Outputs: + * Returns fractional sample rate with a 15-bit fraction + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_U32 CalcBaseFreq (EAS_U32 sampleRate) +{ + EAS_INT i; + + /* look up the conversion rate */ + for (i = 0; i < (EAS_INT)(SRC_CONV_RATE_ENTRIES); i ++) + { + if (srcConvRate[i][0] == sampleRate) + return srcConvRate[i][1]; + } + + /* if not found in table, do it the long way */ + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Sample rate %u not in table, calculating by division\n", sampleRate); */ } + + return (SRC_RATE_MULTIPLER * (EAS_U32) sampleRate) >> 15; +} +#endif + +/*---------------------------------------------------------------------------- + * InitPCMStream() + *---------------------------------------------------------------------------- + * Purpose: + * Start an ADPCM stream playback. Decodes the header, preps the engine. + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT InitPCMStream (S_EAS_DATA *pEASData, S_PCM_STATE *pState) +{ + + /* initialize the data structure */ + pState->bytesLeft = pState->byteCount; + pState->phase = 0; + pState->srcByte = 0; + pState->decoderL.acc = 0; + pState->decoderL.output = 0; + pState->decoderL.x0 = pState->decoderL.x1 = 0; + pState->decoderL.step = 0; + pState->decoderR.acc = 0; + pState->decoderR.output = 0; + pState->decoderR.x0 = pState->decoderR.x1 = 0; + pState->decoderR.step = 0; + pState->hiNibble = EAS_FALSE; + pState->pitch = 0; + pState->blockCount = 0; + pState->gainLeft = PCM_DEFAULT_GAIN_SETTING; +// pState->currentGainLeft = PCM_DEFAULT_GAIN_SETTING; + pState->envValue = 0; + pState->envState = PCM_ENV_START; + +#if (NUM_OUTPUT_CHANNELS == 2) + pState->gainRight = PCM_DEFAULT_GAIN_SETTING; +// pState->currentGainRight = PCM_DEFAULT_GAIN_SETTING; +#endif + pState->state = EAS_STATE_READY; + + /* initialize the decoder */ + if (pState->pDecoder->pfInit) + return (*pState->pDecoder->pfInit)(pEASData, pState); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RenderPCMStream() + *---------------------------------------------------------------------------- + * Purpose: + * Decodes a buffer of ADPCM data. + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RenderPCMStream (S_EAS_DATA *pEASData, S_PCM_STATE *pState, EAS_I32 numSamples) +{ + EAS_RESULT result; + EAS_U32 phaseInc; + EAS_I32 gainLeft, gainIncLeft; + EAS_I32 *pOut; + EAS_I32 temp; + EAS_U32 utemp; + +#if (NUM_OUTPUT_CHANNELS == 2) + EAS_I32 gainRight, gainIncRight; +#endif + +#if 0 + printf("env data: AR = %d, DR = %d, SL = %d, SR = %d, RR = %d\n", + ((pState->envData >> 12) & 0x0F), + ((pState->envData >> 16) & 0x0F), + ((pState->envData >> 8) & 0x0F), + ((pState->envData >> 28) & 0x0F), + ((pState->envData >> 20) & 0x0F)); +#endif + + if (pState->envState == PCM_ENV_START) + { + //printf("env start\n"); + utemp = ((pState->envData >> 12) & 0x0F); + //if fastest rate, attack is already completed + //do the same for slowest rate, since that allows zero to be passed for default envelope + if (utemp == 0x0F || utemp == 0x00) + { + //start envelope at full + pState->envValue = (32768<<7); + //jump right into decay + utemp = ((pState->envData >> 16) & 0x0F); + pState->envScale = getDecayScale(utemp); + pState->envState = PCM_ENV_DECAY; + pState->currentGainLeft = (EAS_I16) FMUL_15x15(pState->gainLeft, pState->volume); + pState->currentGainRight = (EAS_I16) FMUL_15x15(pState->gainRight, pState->volume); + } + //else attack has a ramp + else + { + //start the envelope very low + pState->envValue = (2<<7); + pState->currentGainLeft = 0; + pState->currentGainRight = 0; + //get envelope attack scaling value + pState->envScale = getAttackIncrement(utemp); + //go to attack state + pState->envState = PCM_ENV_ATTACK; + } + } + if (pState->envState == PCM_ENV_ATTACK) + { + //printf("env attack, env value = %d, env scale = %d\n",pState->envValue>>7,pState->envScale); + //update envelope value + pState->envValue = pState->envValue + (pState->envScale << 7); + //check envelope level and update state if needed + if (pState->envValue >= (32768<<7)) + { + pState->envValue = (32768<<7); + utemp = ((pState->envData >> 16) & 0x0F); + pState->envScale = getDecayScale(utemp); + pState->envState = PCM_ENV_DECAY; + } + } + else if (pState->envState == PCM_ENV_DECAY) + { + //printf("env decay, env value = %d, env scale = %d\n",pState->envValue>>7,pState->envScale); + //update envelope value + pState->envValue = (pState->envValue * pState->envScale)>>9; + //check envelope level against sustain level and update state if needed + utemp = ((pState->envData >> 8) & 0x0F); + if (utemp == (EAS_U32)0x0F) + utemp = (2<<7); + else + { + utemp = ((32769<<7) >> (utemp>>1)); + } + if (pState->envValue <= utemp) + { + utemp = ((pState->envData >> 28) & 0x0F); + pState->envScale = getDecayScale(utemp); //getSustainScale(utemp); + pState->envState = PCM_ENV_SUSTAIN; + } + } + else if (pState->envState == PCM_ENV_SUSTAIN) + { + //printf("env sustain, env value = %d, env scale = %d\n",pState->envValue>>7,pState->envScale); + //update envelope value + pState->envValue = (pState->envValue * pState->envScale)>>9; + //check envelope level against bottom level and update state if needed + if (pState->envValue <= (2<<7)) + { + //no more decay + pState->envScale = 512; + pState->envState = PCM_ENV_END; + } + } + else if (pState->envState == PCM_ENV_RELEASE) + { + //printf("env release, env value = %d, env scale = %d\n",pState->envValue>>7,pState->envScale); + //update envelope value + pState->envValue = (pState->envValue * pState->envScale)>>9; + //check envelope level against bottom level and update state if needed + if (pState->envValue <= (2<<7)) + { + //no more decay + pState->envScale = 512; + pState->envState = PCM_ENV_END; + } + } + else if (pState->envState == PCM_ENV_END) + { + //printf("env end\n"); + /* set state to stopping, already ramped down */ + pState->state = EAS_STATE_STOPPING; + } + + //pState->gainLeft = (EAS_U16)((pState->gainLeft * (pState->envValue>>7))>>15); + //pState->gainRight = (EAS_U16)((pState->gainRight * (pState->envValue>>7))>>15); + + /* gain to 32-bits to increase resolution on anti-zipper filter */ + /*lint -e{703} use shift for performance */ + gainLeft = (EAS_I32) pState->currentGainLeft << SYNTH_UPDATE_PERIOD_IN_BITS; +#if (NUM_OUTPUT_CHANNELS == 2) + /*lint -e{703} use shift for performance */ + gainRight = (EAS_I32) pState->currentGainRight << SYNTH_UPDATE_PERIOD_IN_BITS; +#endif + + /* calculate a new gain increment, gain target is zero if pausing */ + if ((pState->state == EAS_STATE_PAUSING) || (pState->state == EAS_STATE_PAUSED)) + { + gainIncLeft = -pState->currentGainLeft; +#if (NUM_OUTPUT_CHANNELS == 2) + gainIncRight= -pState->currentGainRight; +#endif + } + else + { + EAS_I32 gain = FMUL_15x15(pState->envValue >> 7, pState->volume); + gainIncLeft = FMUL_15x15(pState->gainLeft, gain) - pState->currentGainLeft; +#if (NUM_OUTPUT_CHANNELS == 2) + gainIncRight = FMUL_15x15(pState->gainRight, gain) - pState->currentGainRight; +#endif + } + + /* calculate phase increment */ + phaseInc = pState->basefreq; + + /* convert pitch cents to linear multiplier */ + if (pState->pitch) + { + temp = EAS_Calculate2toX(pState->pitch); + phaseInc = FMUL_15x15(phaseInc, temp); + } + phaseInc = phaseInc << pState->rateShift; + + /* pointer to mix buffer */ + pOut = pEASData->pMixBuffer; + + /* render a buffer of samples */ + while (numSamples--) + { + + /* interpolate an output sample */ + pState->decoderL.output = pState->decoderL.x0 + FMUL_15x15((pState->decoderL.x1 - pState->decoderL.x0), pState->phase & PHASE_FRAC_MASK); + + /* stereo output */ +#if (NUM_OUTPUT_CHANNELS == 2) + + /* stereo stream? */ + if (pState->flags & PCM_FLAGS_STEREO) + pState->decoderR.output = pState->decoderR.x0 + FMUL_15x15((pState->decoderR.x1 - pState->decoderR.x0), pState->phase & PHASE_FRAC_MASK); + + /* gain scale and mix */ + /*lint -e{704} use shift instead of division */ + *pOut++ += (pState->decoderL.output * (gainLeft >> SYNTH_UPDATE_PERIOD_IN_BITS)) >> PCM_MIXER_GUARD_BITS; + gainLeft += gainIncLeft; + + /*lint -e{704} use shift instead of division */ + if (pState->flags & PCM_FLAGS_STEREO) + *pOut++ += (pState->decoderR.output * (gainRight >> SYNTH_UPDATE_PERIOD_IN_BITS)) >> PCM_MIXER_GUARD_BITS; + else + *pOut++ += (pState->decoderL.output * (gainRight >> SYNTH_UPDATE_PERIOD_IN_BITS)) >> PCM_MIXER_GUARD_BITS; + + gainRight += gainIncRight; + + /* mono output */ +#else + /* if stereo stream, decode right channel and mix to mono */ + if (pState->flags & PCM_FLAGS_STEREO) + { + pState->decoderR.output= pState->decoderR.x0 + FMUL_15x15((pState->decoderR.x1 - pState->decoderR.x0), pState->phase & PHASE_FRAC_MASK); + + /* for mono, sum stereo ADPCM to mono */ + /*lint -e{704} use shift instead of division */ + *pOut++ += ((pState->decoderL.output + pState->decoderR.output) * (gainLeft >> SYNTH_UPDATE_PERIOD_IN_BITS)) >> PCM_MIXER_GUARD_BITS; + } + else + /*lint -e{704} use shift instead of division */ + *pOut++ += (pState->decoderL.output * (gainLeft >> SYNTH_UPDATE_PERIOD_IN_BITS)) >> PCM_MIXER_GUARD_BITS; + + gainLeft += gainIncLeft; +#endif + + /* advance phase accumulator */ + pState->phase += phaseInc; + + /* if integer part of phase accumulator is non-zero, advance to next sample */ + while (pState->phase & ~PHASE_FRAC_MASK) + { + pState->decoderL.x0 = pState->decoderL.x1; + pState->decoderR.x0 = pState->decoderR.x1; + + /* give the source a chance to continue the stream */ + if (!pState->bytesLeft && pState->pCallback && ((pState->flags & PCM_FLAGS_EMPTY) == 0)) + { + pState->flags |= PCM_FLAGS_EMPTY; + (*pState->pCallback)(pEASData, pState->cbInstData, pState, EAS_STATE_EMPTY); + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "RenderPCMStream: After empty callback, bytesLeft = %d\n", pState->bytesLeft); */ } + } + + /* decode the next sample */ + if ((result = (*pState->pDecoder->pfDecodeSample)(pEASData, pState)) != EAS_SUCCESS) + return result; + + /* adjust phase by one sample */ + pState->phase -= (1L << NUM_PHASE_FRAC_BITS); + } + + } + + /* save new gain */ + /*lint -e{704} use shift instead of division */ + pState->currentGainLeft = (EAS_I16) (gainLeft >> SYNTH_UPDATE_PERIOD_IN_BITS); + +#if (NUM_OUTPUT_CHANNELS == 2) + /*lint -e{704} use shift instead of division */ + pState->currentGainRight = (EAS_I16) (gainRight >> SYNTH_UPDATE_PERIOD_IN_BITS); +#endif + + /* if pausing, set new state and notify */ + if (pState->state == EAS_STATE_PAUSING) + { + pState->state = EAS_STATE_PAUSED; + if (pState->pCallback) + (*pState->pCallback)(pEASData, pState->cbInstData, pState, pState->state); + } + + /* if out of data, set stopped state and notify */ + if (pState->bytesLeft == 0 || pState->state == EAS_STATE_STOPPING) + { + pState->state = EAS_STATE_STOPPED; + + /* do callback unless the file has already been closed */ + if (pState->pCallback && pState->fileHandle) + (*pState->pCallback)(pEASData, pState->cbInstData, pState, pState->state); + } + + if (pState->state == EAS_STATE_READY) + pState->state = EAS_STATE_PLAY; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * LinearPCMDecode() + *---------------------------------------------------------------------------- + * Purpose: + * Decodes a PCM sample + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT LinearPCMDecode (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState) +{ + EAS_RESULT result; + EAS_HW_DATA_HANDLE hwInstData; + + hwInstData = ((S_EAS_DATA*) pEASData)->hwInstData; + + /* if out of data, check for loop */ + if ((pState->bytesLeft == 0) && (pState->loopSamples != 0)) + { + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pState->fileHandle, (EAS_I32) (pState->startPos + pState->loopLocation))) != EAS_SUCCESS) + return result; + pState->bytesLeft = pState->byteCount = (EAS_I32) pState->bytesLeftLoop; + pState->flags &= ~PCM_FLAGS_EMPTY; + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "LinearPCMDecode: Rewind file to %d, bytesLeft = %d\n", pState->startPos, pState->bytesLeft); */ } + } + + if (pState->bytesLeft) + { + + /* check format byte for 8-bit samples */ + if (pState->flags & PCM_FLAGS_8_BIT) + { + /* fetch left or mono sample */ + if ((result = EAS_HWGetByte(hwInstData, pState->fileHandle, &pState->srcByte)) != EAS_SUCCESS) + return result; + + /* if unsigned */ + if (pState->flags & PCM_FLAGS_UNSIGNED) + { + /*lint -e{734} converting unsigned 8-bit to signed 16-bit */ + pState->decoderL.x1 = (EAS_PCM)(((EAS_PCM) pState->srcByte << 8) ^ 0x8000); + } + else + { + /*lint -e{734} converting signed 8-bit to signed 16-bit */ + pState->decoderL.x1 = (EAS_PCM)((EAS_PCM) pState->srcByte << 8); + } + pState->bytesLeft--; + + /* fetch right sample */ + if(pState->flags & PCM_FLAGS_STEREO) + { + if ((result = EAS_HWGetByte(hwInstData, pState->fileHandle, &pState->srcByte)) != EAS_SUCCESS) + return result; + + /* if unsigned */ + if (pState->flags & PCM_FLAGS_UNSIGNED) + { + /*lint -e{734} converting unsigned 8-bit to signed 16-bit */ + pState->decoderR.x1 = (EAS_PCM)(((EAS_PCM) pState->srcByte << 8) ^ 0x8000); + } + else + { + /*lint -e{734} converting signed 8-bit to signed 16-bit */ + pState->decoderR.x1 = (EAS_PCM)((EAS_PCM) pState->srcByte << 8); + } + pState->bytesLeft--; + } + } + + /* must be 16-bit samples */ + else + { + //unsigned 16 bit currently not supported + if (pState->flags & PCM_FLAGS_UNSIGNED) + { + return EAS_ERROR_INVALID_PCM_TYPE; + } + + /* fetch left or mono sample */ + if ((result = EAS_HWGetWord(hwInstData, pState->fileHandle, &pState->decoderL.x1, EAS_FALSE)) != EAS_SUCCESS) + return result; + pState->bytesLeft -= 2; + + /* fetch right sample */ + if(pState->flags & PCM_FLAGS_STEREO) + { + if ((result = EAS_HWGetWord(hwInstData, pState->fileHandle, &pState->decoderR.x1, EAS_FALSE)) != EAS_SUCCESS) + return result; + pState->bytesLeft -= 2; + } + } + } + + /* no more data, force zero samples */ + else + pState->decoderL.x1 = pState->decoderR.x1 = 0; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * LinearPCMLocate() + *---------------------------------------------------------------------------- + * Purpose: + * Locate in a linear PCM stream + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT LinearPCMLocate (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState, EAS_I32 time) +{ + EAS_RESULT result; + EAS_I32 temp; + EAS_I32 secs, msecs; + EAS_INT shift; + + /* calculate size of sample frame */ + if (pState->flags & PCM_FLAGS_8_BIT) + shift = 0; + else + shift = 1; + if (pState->flags & PCM_FLAGS_STEREO) + shift++; + + /* break down into secs and msecs */ + secs = time / 1000; + msecs = time - (secs * 1000); + + /* calculate sample number fraction from msecs */ + temp = (msecs * pState->sampleRate); + temp = (temp >> 10) + ((temp * 49) >> 21); + + /* add integer sample count */ + temp += secs * pState->sampleRate; + + /* calculate the position based on sample frame size */ + /*lint -e{703} use shift for performance */ + temp <<= shift; + + /* past end of sample? */ + if (temp > (EAS_I32) pState->loopStart) + { + /* if not looped, flag error */ + if (pState->loopSamples == 0) + { + pState->bytesLeft = 0; + pState->flags |= PCM_FLAGS_EMPTY; + return EAS_ERROR_LOCATE_BEYOND_END; + } + + /* looped sample - calculate position in loop */ + while (temp > (EAS_I32) pState->loopStart) + temp -= (EAS_I32) pState->loopStart; + } + + /* seek to new position */ + if ((result = EAS_PESeek(pEASData, pState, &temp)) != EAS_SUCCESS) + return result; + + /* reset state */ + if ((pState->state != EAS_STATE_PAUSING) && (pState->state != EAS_STATE_PAUSED)) + pState->state = EAS_STATE_READY; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_PESeek + *---------------------------------------------------------------------------- + * Purpose: + * Locate to a particular byte in a PCM stream + *---------------------------------------------------------------------------- + * This bit is tricky because the chunks may not be contiguous, + * so we have to rely on the parser to position in the file. We + * do this by seeking to the end of each chunk and simulating an + * empty buffer condition until we get to where we want to go. + * + * A better solution would be a parser API for re-positioning, + * but there isn't time at the moment to re-factor all the + * parsers to support a new API. + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PESeek (S_EAS_DATA *pEASData, S_PCM_STATE *pState, EAS_I32 *pLocation) +{ + EAS_RESULT result; + + /* seek to start of audio */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pState->fileHandle, pState->startPos)) != EAS_SUCCESS) + { + pState->state = EAS_STATE_ERROR; + return result; + } + pState->bytesLeft = pState->bytesLeftLoop; + + /* skip through chunks until we find the right chunk */ + while (*pLocation > (EAS_I32) pState->bytesLeft) + { + /* seek to end of audio chunk */ + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "EAS_PESeek: Seek to offset = %d\n", pState->bytesLeft); */ } + if ((result = EAS_HWFileSeekOfs(pEASData->hwInstData, pState->fileHandle, pState->bytesLeft)) != EAS_SUCCESS) + { + pState->state = EAS_STATE_ERROR; + return result; + } + *pLocation -= pState->bytesLeft; + pState->bytesLeft = 0; + pState->flags |= PCM_FLAGS_EMPTY; + + /* retrieve more data */ + if (pState->pCallback) + (*pState->pCallback)(pEASData, pState->cbInstData, pState, EAS_STATE_EMPTY); + + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "EAS_PESeek: bytesLeft=%d, byte location = %d\n", pState->bytesLeft, *pLocation); */ } + + /* no more samples */ + if (pState->bytesLeft == 0) + return EAS_ERROR_LOCATE_BEYOND_END; + } + + /* seek to new offset in current chunk */ + if (*pLocation > 0) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "EAS_PESeek: Seek to offset = %d\n", *pLocation); */ } + if ((result = EAS_HWFileSeekOfs(pEASData->hwInstData, pState->fileHandle, *pLocation)) != EAS_SUCCESS) + { + pState->state = EAS_STATE_ERROR; + return result; + } + + /* if not streamed, calculate number of bytes left */ + if (pState->flags & PCM_FLAGS_STREAMING) + pState->bytesLeft = 0x7fffffff; + else + pState->bytesLeft -= *pLocation; + } + return EAS_SUCCESS; +} + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_pcm.h b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_pcm.h new file mode 100755 index 0000000..4fc77e9 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_pcm.h @@ -0,0 +1,359 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_pcm.h + * + * Contents and purpose: + * External function prototypes for eas_pcm.c module + * + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 847 $ + * $Date: 2007-08-27 21:30:08 -0700 (Mon, 27 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_PCM_H +#define _EAS_PCM_H + +/* default gain setting - roughly unity gain */ +#define PCM_DEFAULT_GAIN_SETTING 0x6000 + +typedef struct s_pcm_state_tag *EAS_PCM_HANDLE; +typedef void (*EAS_PCM_CALLBACK) (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR cbInstData, EAS_PCM_HANDLE pcmHandle, EAS_STATE state); + +/* parameters for EAS_PEOpenStream */ +typedef struct s_pcm_open_params_tag +{ + EAS_FILE_HANDLE fileHandle; + EAS_I32 decoder; + EAS_U32 sampleRate; + EAS_I32 size; + EAS_U32 loopStart; + EAS_U32 loopSamples; + EAS_I32 blockSize; + EAS_U32 flags; + EAS_U32 envData; + EAS_I16 volume; + EAS_PCM_CALLBACK pCallbackFunc; + EAS_VOID_PTR cbInstData; + } S_PCM_OPEN_PARAMS; + +/*---------------------------------------------------------------------------- + * EAS_PEInit() + *---------------------------------------------------------------------------- + * Purpose: + * Initializes the PCM engine + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEInit (EAS_DATA_HANDLE pEASData); + +/*---------------------------------------------------------------------------- + * EAS_PEShutdown() + *---------------------------------------------------------------------------- + * Purpose: + * Shuts down the PCM engine + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEShutdown (EAS_DATA_HANDLE pEASData); + +/*---------------------------------------------------------------------------- + * EAS_PEOpenStream() + *---------------------------------------------------------------------------- + * Purpose: + * Starts up a PCM playback + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEOpenStream (EAS_DATA_HANDLE pEASData, S_PCM_OPEN_PARAMS *pParams, EAS_PCM_HANDLE *pHandle); + +/*---------------------------------------------------------------------------- + * EAS_PEContinueStream() + *---------------------------------------------------------------------------- + * Purpose: + * Continues a PCM stream + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEContinueStream (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE handle, EAS_I32 size); + +/*---------------------------------------------------------------------------- + * EAS_PEGetFileHandle() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the file handle of a stream + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEGetFileHandle (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE handle, EAS_FILE_HANDLE *pFileHandle); + +/*---------------------------------------------------------------------------- + * EAS_PERender() + *---------------------------------------------------------------------------- + * Purpose: + * Render a buffer of PCM audio + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PERender (EAS_DATA_HANDLE pEASData, EAS_I32 numSamples); + +/*---------------------------------------------------------------------------- + * EAS_PEUpdateParams() + *---------------------------------------------------------------------------- + * Purpose: + * Update the pitch and volume parameters using MIDI controls + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEUpdateParams (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE pState, EAS_I16 pitch, EAS_I16 gainLeft, EAS_I16 gainRight); + +/*---------------------------------------------------------------------------- + * EAS_PELocate() + *---------------------------------------------------------------------------- + * Purpose: + * This function seeks to the requested place in the file. Accuracy + * is dependent on the sample rate and block size. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * pState - stream handle + * time - media time in milliseconds + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PELocate (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE pState, EAS_I32 time); + +/*---------------------------------------------------------------------------- + * EAS_PEUpdateVolume() + *---------------------------------------------------------------------------- + * Purpose: + * Update the volume parameters for a PCM stream + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_PCM_STATE for this stream + * gainLeft - linear gain multipler in 1.15 fraction format + * gainRight - linear gain multipler in 1.15 fraction format + * initial - initial settings, set current gain + * + * Outputs: + * + * + * Side Effects: + * + * Notes + * In mono mode, leftGain controls the output gain and rightGain is ignored + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT EAS_PEUpdateVolume (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE pState, EAS_I16 volume); + +/*---------------------------------------------------------------------------- + * EAS_PEUpdatePitch() + *---------------------------------------------------------------------------- + * Purpose: + * Update the pitch parameter for a PCM stream + * + * Inputs: + * pEASData - pointer to EAS library instance data + * pState - pointer to S_PCM_STATE for this stream + * pitch - new pitch value in pitch cents + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT EAS_PEUpdatePitch (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE pState, EAS_I16 pitch); + +/*---------------------------------------------------------------------------- + * EAS_PEState() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current state of the stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * pState - pointer to variable to store state + * + * Outputs: + * + * + * Side Effects: + * + * Notes: + * This interface is also exposed in the internal library for use by the other modules. + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEState (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE handle, EAS_STATE *pState); + +/*---------------------------------------------------------------------------- + * EAS_PEClose() + *---------------------------------------------------------------------------- + * Purpose: + * Close the file and clean up + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEClose (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE handle); + +/*---------------------------------------------------------------------------- + * EAS_PEReset() + *---------------------------------------------------------------------------- + * Purpose: + * Reset the sequencer. Used for locating backwards in the file. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEReset (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE handle); + +/*---------------------------------------------------------------------------- + * EAS_PEPause() + *---------------------------------------------------------------------------- + * Purpose: + * Mute and pause rendering a PCM stream. Sets the gain target to zero and stops the playback + * at the end of the next audio frame. + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_PCM_STATE for this stream + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEPause (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE handle); + +/*---------------------------------------------------------------------------- + * EAS_PEResume() + *---------------------------------------------------------------------------- + * Purpose: + * Resume rendering a PCM stream. Sets the gain target back to its + * previous setting and restarts playback at the end of the next audio + * frame. + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_PCM_STATE for this stream + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEResume (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE handle); + +/*---------------------------------------------------------------------------- + * EAS_PERelease() + *---------------------------------------------------------------------------- + * Purpose: + * Put the PCM stream envelope into release. + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_PCM_STATE for this stream + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PERelease (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE handle); + +#endif /* end _EAS_PCM_H */ + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_pcmdata.c b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_pcmdata.c new file mode 100755 index 0000000..2d85ac2 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_pcmdata.c @@ -0,0 +1,35 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_pcmdata.c + * + * Contents and purpose: + * Contains the static data for the PCM engine. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 547 $ + * $Date: 2007-01-31 16:30:17 -0800 (Wed, 31 Jan 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_data.h" + +/* static data allocation */ +S_PCM_STATE eas_PCMData[MAX_PCM_STREAMS]; + + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_pcmdata.h b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_pcmdata.h new file mode 100755 index 0000000..ae18d6d --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_pcmdata.h @@ -0,0 +1,157 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_pcmdata.h + * + * Contents and purpose: + * Data declarations for the PCM engine + * + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 847 $ + * $Date: 2007-08-27 21:30:08 -0700 (Mon, 27 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_PCMDATA_H +#define _EAS_PCMDATA_H + +/* sets the maximum number of simultaneous PCM streams */ +#ifndef MAX_PCM_STREAMS +#define MAX_PCM_STREAMS 16 +#define PCM_STREAM_THRESHOLD (MAX_PCM_STREAMS - 4) +#endif + +/* coefficents for high-pass filter in ADPCM */ +#define INTEGRATOR_COEFFICIENT 100 /* coefficient for leaky integrator */ + +/* additional flags in S_PCM_STATE.flags used internal to module */ +#define PCM_FLAGS_EMPTY 0x01000000 /* unsigned format */ + +/*---------------------------------------------------------------------------- + * S_PCM_STATE + * + * Retains state information for PCM streams. + *---------------------------------------------------------------------------- +*/ +typedef struct s_decoder_state_tag +{ + EAS_I32 output; /* last output for DC offset filter */ + EAS_I32 acc; /* accumulator for DC offset filter */ + EAS_I32 step; /* current ADPCM step size */ + EAS_PCM x1; /* current generated sample */ + EAS_PCM x0; /* previous generated sample */ +} S_DECODER_STATE; + +typedef enum +{ + PCM_ENV_START = 0, + PCM_ENV_ATTACK, + PCM_ENV_DECAY, + PCM_ENV_SUSTAIN, + PCM_ENV_RELEASE, + PCM_ENV_END +} E_PCM_ENV_STATE; + +typedef struct s_pcm_state_tag +{ +#ifdef _CHECKED_BUILD + EAS_U32 handleCheck; /* signature check for checked build */ +#endif + EAS_FILE_HANDLE fileHandle; /* pointer to input file */ + EAS_PCM_CALLBACK pCallback; /* pointer to callback function */ + EAS_VOID_PTR cbInstData; /* instance data for callback function */ + struct s_decoder_interface_tag EAS_CONST * pDecoder; /* pointer to decoder interface */ + EAS_STATE state; /* stream state */ + EAS_I32 time; /* media time */ + EAS_I32 startPos; /* start of PCM stream */ + EAS_I32 loopLocation; /* file location where loop starts */ + EAS_I32 byteCount; /* size of file */ + EAS_U32 loopStart; /* loop start, offset in samples from startPos */ + /* NOTE: For CMF, we use this to store total sample size */ + EAS_U32 loopSamples; /* total loop length, in samples, 0 means no loop */ + /* NOTE: For CMF, non-zero means looped */ + EAS_U32 samplesInLoop; /* samples left in the loop to play back */ + EAS_I32 samplesTilLoop; /* samples left to play until top of loop */ + EAS_I32 bytesLeft; /* count of bytes left in stream */ + EAS_I32 bytesLeftLoop; /* count of bytes left in stream, value at start of loop */ + EAS_U32 phase; /* current phase for interpolator */ + EAS_U32 basefreq; /* frequency multiplier */ + EAS_U32 flags; /* stream flags */ + EAS_U32 envData; /* envelope data (and LFO data) */ + EAS_U32 envValue; /* current envelope value */ + EAS_U32 envScale; /* current envelope scale */ + EAS_U32 startOrder; /* start order index, first is 0, next is 1, etc. */ + S_DECODER_STATE decoderL; /* left (mono) ADPCM state */ + S_DECODER_STATE decoderR; /* right ADPCM state */ + S_DECODER_STATE decoderLLoop; /* left (mono) ADPCM state, value at start of loop */ + S_DECODER_STATE decoderRLoop; /* right ADPCM state, value at start of loop */ + E_PCM_ENV_STATE envState; /* current envelope state */ + EAS_I16 volume; /* volume for stream */ + EAS_I16 pitch; /* relative pitch in cents - zero is unity playback */ + EAS_I16 gainLeft; /* requested gain */ + EAS_I16 gainRight; /* requested gain */ + EAS_I16 currentGainLeft; /* current gain for anti-zipper filter */ + EAS_I16 currentGainRight; /* current gain for anti-zipper filter */ + EAS_U16 blockSize; /* block size for ADPCM decoder */ + EAS_U16 blockCount; /* block counter for ADPCM decoder */ + EAS_U16 sampleRate; /* input sample rate */ + EAS_U8 srcByte; /* source byte */ + EAS_U8 msBitCount; /* count keeps track of MS bits */ + EAS_U8 msBitMask; /* mask keeps track of MS bits */ + EAS_U8 msBitValue; /* value keeps track of MS bits */ + EAS_U8 msBitCountLoop; /* count keeps track of MS bits, value at loop start */ + EAS_U8 msBitMaskLoop; /* mask keeps track of MS bits, value at loop start */ + EAS_U8 msBitValueLoop; /* value keeps track of MS bits, value at loop start */ + EAS_BOOL8 hiNibble; /* indicates high/low nibble is next */ + EAS_BOOL8 hiNibbleLoop; /* indicates high/low nibble is next, value loop start */ + EAS_U8 rateShift; /* for playback rate greater than 1.0 */ +} S_PCM_STATE; + +/*---------------------------------------------------------------------------- + * S_DECODER_INTERFACE + * + * Generic interface for audio decoders + *---------------------------------------------------------------------------- +*/ +typedef struct s_decoder_interface_tag +{ + EAS_RESULT (* EAS_CONST pfInit)(EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState); + EAS_RESULT (* EAS_CONST pfDecodeSample)(EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState); + EAS_RESULT (* EAS_CONST pfLocate)(EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState, EAS_I32 time); +} S_DECODER_INTERFACE; + + +/* header chunk for SMAF ADPCM */ +#define TAG_YAMAHA_ADPCM 0x4d776100 +#define TAG_MASK 0xffffff00 +#define TAG_RIFF_FILE 0x52494646 +#define TAG_WAVE_CHUNK 0x57415645 +#define TAG_FMT_CHUNK 0x666d7420 + +/*---------------------------------------------------------------------------- + * EAS_PESeek + *---------------------------------------------------------------------------- + * Purpose: + * Locate to a particular byte in a PCM stream + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PESeek (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState, EAS_I32 *pLocation); + +#endif /* _EAS_PCMDATA_H */ + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_public.c b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_public.c new file mode 100755 index 0000000..394a9a1 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_public.c @@ -0,0 +1,2597 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_public.c + * + * Contents and purpose: + * Contains EAS library public interface + * + * Copyright Sonic Network Inc. 2004 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 842 $ + * $Date: 2007-08-23 14:32:31 -0700 (Thu, 23 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_synthcfg.h" +#include "eas.h" +#include "eas_config.h" +#include "eas_host.h" +#include "eas_report.h" +#include "eas_data.h" +#include "eas_parser.h" +#include "eas_pcm.h" +#include "eas_midi.h" +#include "eas_mixer.h" +#include "eas_build.h" +#include "eas_vm_protos.h" +#include "eas_math.h" + +#ifdef JET_INTERFACE +#include "jet_data.h" +#endif + +#ifdef DLS_SYNTHESIZER +#include "eas_mdls.h" +#endif + +/* number of events to parse before calling EAS_HWYield function */ +#define YIELD_EVENT_COUNT 10 + +/*---------------------------------------------------------------------------- + * easLibConfig + * + * This structure is available through the EAS public interface to allow + * the user to check the configuration of the library. + *---------------------------------------------------------------------------- +*/ +static const S_EAS_LIB_CONFIG easLibConfig = +{ + LIB_VERSION, +#ifdef _CHECKED_BUILD + EAS_TRUE, +#else + EAS_FALSE, +#endif + MAX_SYNTH_VOICES, + NUM_OUTPUT_CHANNELS, + _OUTPUT_SAMPLE_RATE, + BUFFER_SIZE_IN_MONO_SAMPLES, +#ifdef _FILTER_ENABLED + EAS_TRUE, +#else + EAS_FALSE, +#endif + _BUILD_TIME_, + _BUILD_VERSION_ +}; + +/* local prototypes */ +static EAS_RESULT EAS_ParseEvents (S_EAS_DATA *pEASData, S_EAS_STREAM *pStream, EAS_U32 endTime, EAS_INT parseMode); + +/*---------------------------------------------------------------------------- + * EAS_SetStreamParameter + *---------------------------------------------------------------------------- + * Sets the specified parameter in the stream. Allows access to + * customizable settings within the individual file parsers. + *---------------------------------------------------------------------------- + * pEASData - pointer to EAS persistent data object + * pStream - stream handle + * param - enumerated parameter (see eas_parser.h) + * value - new value + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_SetStreamParameter (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_I32 param, EAS_I32 value) +{ + S_FILE_PARSER_INTERFACE *pParserModule; + + pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; + if (pParserModule->pfSetData) + return (*pParserModule->pfSetData)(pEASData, pStream->handle, param, value); + return EAS_ERROR_FEATURE_NOT_AVAILABLE; +} + +/*---------------------------------------------------------------------------- + * EAS_GetStreamParameter + *---------------------------------------------------------------------------- + * Sets the specified parameter in the stream. Allows access to + * customizable settings within the individual file parsers. + *---------------------------------------------------------------------------- + * pEASData - pointer to EAS persistent data object + * pStream - stream handle + * param - enumerated parameter (see eas_parser.h) + * pValue - pointer to variable to receive current setting + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_GetStreamParameter (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_I32 param, EAS_I32 *pValue) +{ + S_FILE_PARSER_INTERFACE *pParserModule; + + pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; + if (pParserModule->pfGetData) + return (*pParserModule->pfGetData)(pEASData, pStream->handle, param, pValue); + return EAS_ERROR_FEATURE_NOT_AVAILABLE; +} + +/*---------------------------------------------------------------------------- + * EAS_StreamReady() + *---------------------------------------------------------------------------- + * This routine sets common parameters like transpose, volume, etc. + * First, it attempts to use the parser EAS_SetStreamParameter interface. If that + * fails, it attempts to get the synth handle from the parser and + * set the parameter directly on the synth. This eliminates duplicate + * code in the parser. + *---------------------------------------------------------------------------- +*/ +EAS_BOOL EAS_StreamReady (S_EAS_DATA *pEASData, EAS_HANDLE pStream) +{ + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_STATE state; + + pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; + if (pParserModule->pfState(pEASData, pStream->handle, &state) != EAS_SUCCESS) + return EAS_FALSE; + return (state < EAS_STATE_OPEN); +} + +/*---------------------------------------------------------------------------- + * EAS_IntSetStrmParam() + *---------------------------------------------------------------------------- + * This routine sets common parameters like transpose, volume, etc. + * First, it attempts to use the parser EAS_SetStreamParameter interface. If that + * fails, it attempts to get the synth handle from the parser and + * set the parameter directly on the synth. This eliminates duplicate + * code in the parser. + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_IntSetStrmParam (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_INT param, EAS_I32 value) +{ + S_SYNTH *pSynth; + + /* try to set the parameter using stream interface */ + if (EAS_SetStreamParameter(pEASData, pStream, param, value) == EAS_SUCCESS) + return EAS_SUCCESS; + + /* get a pointer to the synth object and set it directly */ + /*lint -e{740} we are cheating by passing a pointer through this interface */ + if (EAS_GetStreamParameter(pEASData, pStream, PARSER_DATA_SYNTH_HANDLE, (EAS_I32*) &pSynth) != EAS_SUCCESS) + return EAS_ERROR_INVALID_PARAMETER; + + if (pSynth == NULL) + return EAS_ERROR_INVALID_PARAMETER; + + switch (param) + { + +#ifdef DLS_SYNTHESIZER + case PARSER_DATA_DLS_COLLECTION: + { + EAS_RESULT result = VMSetDLSLib(pSynth, (EAS_DLSLIB_HANDLE) value); + if (result == EAS_SUCCESS) + { + DLSAddRef((S_DLS*) value); + VMInitializeAllChannels(pEASData->pVoiceMgr, pSynth); + } + return result; + } +#endif + + case PARSER_DATA_EAS_LIBRARY: + return VMSetEASLib(pSynth, (EAS_SNDLIB_HANDLE) value); + + case PARSER_DATA_POLYPHONY: + return VMSetPolyphony(pEASData->pVoiceMgr, pSynth, value); + + case PARSER_DATA_PRIORITY: + return VMSetPriority(pEASData->pVoiceMgr, pSynth, value); + + case PARSER_DATA_TRANSPOSITION: + VMSetTranposition(pSynth, value); + break; + + case PARSER_DATA_VOLUME: + VMSetVolume(pSynth, (EAS_U16) value); + break; + + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Invalid paramter %d in call to EAS_IntSetStrmParam", param); */ } + return EAS_ERROR_INVALID_PARAMETER; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_IntGetStrmParam() + *---------------------------------------------------------------------------- + * This routine gets common parameters like transpose, volume, etc. + * First, it attempts to use the parser EAS_GetStreamParameter interface. If that + * fails, it attempts to get the synth handle from the parser and + * get the parameter directly on the synth. + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_IntGetStrmParam (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_INT param, EAS_I32 *pValue) +{ + S_SYNTH *pSynth; + + /* try to set the parameter */ + if (EAS_GetStreamParameter(pEASData, pStream, param, pValue) == EAS_SUCCESS) + return EAS_SUCCESS; + + /* get a pointer to the synth object and retrieve data directly */ + /*lint -e{740} we are cheating by passing a pointer through this interface */ + if (EAS_GetStreamParameter(pEASData, pStream, PARSER_DATA_SYNTH_HANDLE, (EAS_I32*) &pSynth) != EAS_SUCCESS) + return EAS_ERROR_INVALID_PARAMETER; + + if (pSynth == NULL) + return EAS_ERROR_INVALID_PARAMETER; + + switch (param) + { + case PARSER_DATA_POLYPHONY: + return VMGetPolyphony(pEASData->pVoiceMgr, pSynth, pValue); + + case PARSER_DATA_PRIORITY: + return VMGetPriority(pEASData->pVoiceMgr, pSynth, pValue); + + case PARSER_DATA_TRANSPOSITION: + VMGetTranposition(pSynth, pValue); + break; + + case PARSER_DATA_NOTE_COUNT: + *pValue = VMGetNoteCount(pSynth); + break; + + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Invalid paramter %d in call to EAS_IntSetStrmParam", param); */ } + return EAS_ERROR_INVALID_PARAMETER; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_AllocateStream() + *---------------------------------------------------------------------------- + * Purpose: + * Allocates a stream handle + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static EAS_INT EAS_AllocateStream (EAS_DATA_HANDLE pEASData) +{ + EAS_INT streamNum; + + /* check for static allocation, only one stream allowed */ + if (pEASData->staticMemoryModel) + { + if (pEASData->streams[0].handle != NULL) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Attempt to open multiple streams in static model\n"); */ } + return -1; + } + return 0; + } + + /* dynamic model */ + for (streamNum = 0; streamNum < MAX_NUMBER_STREAMS; streamNum++) + if (pEASData->streams[streamNum].handle == NULL) + break; + if (streamNum == MAX_NUMBER_STREAMS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Exceeded maximum number of open streams\n"); */ } + return -1; + } + return streamNum; +} + +/*---------------------------------------------------------------------------- + * EAS_InitStream() + *---------------------------------------------------------------------------- + * Purpose: + * Initialize a stream + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static void EAS_InitStream (S_EAS_STREAM *pStream, EAS_VOID_PTR pParserModule, EAS_VOID_PTR streamHandle) +{ + pStream->pParserModule = pParserModule; + pStream->handle = streamHandle; + pStream->time = 0; + pStream->frameLength = AUDIO_FRAME_LENGTH; + pStream->repeatCount = 0; + pStream->volume = DEFAULT_STREAM_VOLUME; +} + +/*---------------------------------------------------------------------------- + * EAS_Config() + *---------------------------------------------------------------------------- + * Purpose: + * Returns a pointer to a structure containing the configuration options + * in this library build. + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC const S_EAS_LIB_CONFIG *EAS_Config (void) +{ + return &easLibConfig; +} + +/*---------------------------------------------------------------------------- + * EAS_Init() + *---------------------------------------------------------------------------- + * Purpose: + * Initialize the synthesizer library + * + * Inputs: + * ppEASData - pointer to data handle variable for this instance + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Init (EAS_DATA_HANDLE *ppEASData) +{ + EAS_HW_DATA_HANDLE pHWInstData; + EAS_RESULT result; + S_EAS_DATA *pEASData; + EAS_INT module; + EAS_BOOL staticMemoryModel; + + /* get the memory model */ + staticMemoryModel = EAS_CMStaticMemoryModel(); + + /* initialize the host wrapper interface */ + *ppEASData = NULL; + if ((result = EAS_HWInit(&pHWInstData)) != EAS_SUCCESS) + return result; + + /* check Configuration Module for S_EAS_DATA allocation */ + if (staticMemoryModel) + pEASData = EAS_CMEnumData(EAS_CM_EAS_DATA); + else + pEASData = EAS_HWMalloc(pHWInstData, sizeof(S_EAS_DATA)); + if (!pEASData) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Failed to allocate EAS library memory\n"); */ } + return EAS_ERROR_MALLOC_FAILED; + } + + /* initialize some data */ + EAS_HWMemSet(pEASData, 0, sizeof(S_EAS_DATA)); + pEASData->staticMemoryModel = (EAS_BOOL8) staticMemoryModel; + pEASData->hwInstData = pHWInstData; + pEASData->renderTime = 0; + + /* set header search flag */ +#ifdef FILE_HEADER_SEARCH + pEASData->searchHeaderFlag = EAS_TRUE; +#endif + + /* initalize parameters */ + EAS_SetVolume(pEASData, NULL, DEFAULT_VOLUME); + +#ifdef _METRICS_ENABLED + /* initalize the metrics module */ + pEASData->pMetricsModule = EAS_CMEnumOptModules(EAS_MODULE_METRICS); + if (pEASData->pMetricsModule != NULL) + { + if ((result = (*pEASData->pMetricsModule->pfInit)(pEASData, &pEASData->pMetricsData)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld initializing metrics module\n", result); */ } + return result; + } + } +#endif + + /* initailize the voice manager & synthesizer */ + if ((result = VMInitialize(pEASData)) != EAS_SUCCESS) + return result; + + /* initialize mix engine */ + if ((result = EAS_MixEngineInit(pEASData)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld starting up mix engine\n", result); */ } + return result; + } + + /* initialize effects modules */ + for (module = 0; module < NUM_EFFECTS_MODULES; module++) + { + pEASData->effectsModules[module].effect = EAS_CMEnumFXModules(module); + if (pEASData->effectsModules[module].effect != NULL) + { + if ((result = (*pEASData->effectsModules[module].effect->pfInit)(pEASData, &pEASData->effectsModules[module].effectData)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Initialization of effects module %d returned %d\n", module, result); */ } + return result; + } + } + } + + /* initialize PCM engine */ + if ((result = EAS_PEInit(pEASData)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "EAS_PEInit failed with error code %ld\n", result); */ } + return result; + } + + /* return instance data pointer to host */ + *ppEASData = pEASData; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_Shutdown() + *---------------------------------------------------------------------------- + * Purpose: + * Shuts down the library. Deallocates any memory associated with the + * synthesizer (dynamic memory model only) + * + * Inputs: + * pEASData - handle to data for this instance + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Shutdown (EAS_DATA_HANDLE pEASData) +{ + EAS_HW_DATA_HANDLE hwInstData; + EAS_RESULT result, reportResult; + EAS_INT i; + + /* establish pointers */ + hwInstData = pEASData->hwInstData; + + /* check for NULL handle */ + if (!pEASData) + return EAS_ERROR_HANDLE_INTEGRITY; + + /* if there are streams open, close them */ + reportResult = EAS_SUCCESS; + for (i = 0; i < MAX_NUMBER_STREAMS; i++) + { + if (pEASData->streams[i].pParserModule && pEASData->streams[i].handle) + { + if ((result = (*((S_FILE_PARSER_INTERFACE*)(pEASData->streams[i].pParserModule))->pfClose)(pEASData, pEASData->streams[i].handle)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld shutting down parser module\n", result); */ } + reportResult = result; + } + } + } + + /* shutdown PCM engine */ + if ((result = EAS_PEShutdown(pEASData)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld shutting down PCM engine\n", result); */ } + if (reportResult == EAS_SUCCESS) + reportResult = result; + } + + /* shutdown mix engine */ + if ((result = EAS_MixEngineShutdown(pEASData)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld shutting down mix engine\n", result); */ } + if (reportResult == EAS_SUCCESS) + reportResult = result; + } + + /* shutdown effects modules */ + for (i = 0; i < NUM_EFFECTS_MODULES; i++) + { + if (pEASData->effectsModules[i].effect) + { + if ((result = (*pEASData->effectsModules[i].effect->pfShutdown)(pEASData, pEASData->effectsModules[i].effectData)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Shutdown of effects module %d returned %d\n", i, result); */ } + if (reportResult == EAS_SUCCESS) + reportResult = result; + } + } + } + + /* shutdown the voice manager & synthesizer */ + VMShutdown(pEASData); + +#ifdef _METRICS_ENABLED + /* shutdown the metrics module */ + if (pEASData->pMetricsModule != NULL) + { + if ((result = (*pEASData->pMetricsModule->pfShutdown)(pEASData, pEASData->pMetricsData)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld shutting down metrics module\n", result); */ } + if (reportResult == EAS_SUCCESS) + reportResult = result; + } + } +#endif + + /* release allocated memory */ + if (!pEASData->staticMemoryModel) + EAS_HWFree(hwInstData, pEASData); + + /* shutdown host wrappers */ + if (hwInstData) + { + if ((result = EAS_HWShutdown(hwInstData)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld shutting down host wrappers\n", result); */ } + if (reportResult == EAS_SUCCESS) + reportResult = result; + } + } + + return reportResult; +} + +#ifdef JET_INTERFACE +/*---------------------------------------------------------------------------- + * EAS_OpenJETStream() + *---------------------------------------------------------------------------- + * Private interface for JET to open an SMF stream with an offset + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_OpenJETStream (EAS_DATA_HANDLE pEASData, EAS_FILE_HANDLE fileHandle, EAS_I32 offset, EAS_HANDLE *ppStream) +{ + EAS_RESULT result; + EAS_VOID_PTR streamHandle; + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_INT streamNum; + + /* allocate a stream */ + if ((streamNum = EAS_AllocateStream(pEASData)) < 0) + return EAS_ERROR_MAX_STREAMS_OPEN; + + /* check Configuration Module for SMF parser */ + *ppStream = NULL; + streamHandle = NULL; + pParserModule = (S_FILE_PARSER_INTERFACE *) EAS_CMEnumModules(0); + if (pParserModule == NULL) + return EAS_ERROR_UNRECOGNIZED_FORMAT; + + /* see if SMF parser recognizes the file */ + if ((result = (*pParserModule->pfCheckFileType)(pEASData, fileHandle, &streamHandle, offset)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "CheckFileType returned error %ld\n", result); */ } + return result; + } + + /* parser recognized the file, return the handle */ + if (streamHandle) + { + EAS_InitStream(&pEASData->streams[streamNum], pParserModule, streamHandle); + *ppStream = &pEASData->streams[streamNum]; + return EAS_SUCCESS; + } + + return EAS_ERROR_UNRECOGNIZED_FORMAT; +} +#endif + +/*---------------------------------------------------------------------------- + * EAS_OpenFile() + *---------------------------------------------------------------------------- + * Purpose: + * Opens a file for audio playback. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * pHandle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_OpenFile (EAS_DATA_HANDLE pEASData, EAS_FILE_LOCATOR locator, EAS_HANDLE *ppStream) +{ + EAS_RESULT result; + EAS_FILE_HANDLE fileHandle; + EAS_VOID_PTR streamHandle; + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_INT streamNum; + EAS_INT moduleNum; + + /* open the file */ + if ((result = EAS_HWOpenFile(pEASData->hwInstData, locator, &fileHandle, EAS_FILE_READ)) != EAS_SUCCESS) + return result; + + /* allocate a stream */ + if ((streamNum = EAS_AllocateStream(pEASData)) < 0) + return EAS_ERROR_MAX_STREAMS_OPEN; + + /* check Configuration Module for file parsers */ + pParserModule = NULL; + *ppStream = NULL; + streamHandle = NULL; + for (moduleNum = 0; ; moduleNum++) + { + pParserModule = (S_FILE_PARSER_INTERFACE *) EAS_CMEnumModules(moduleNum); + if (pParserModule == NULL) + break; + + /* see if this parser recognizes it */ + if ((result = (*pParserModule->pfCheckFileType)(pEASData, fileHandle, &streamHandle, 0L)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "CheckFileType returned error %ld\n", result); */ } + return result; + } + + /* parser recognized the file, return the handle */ + if (streamHandle) + { + + /* save the parser pointer and file handle */ + EAS_InitStream(&pEASData->streams[streamNum], pParserModule, streamHandle); + *ppStream = &pEASData->streams[streamNum]; + return EAS_SUCCESS; + } + + /* rewind the file for the next parser */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, 0L)) != EAS_SUCCESS) + return result; + } + + /* no parser was able to recognize the file, close it and return an error */ + EAS_HWCloseFile(pEASData->hwInstData, fileHandle); + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "No parser recognized the requested file\n"); */ } + return EAS_ERROR_UNRECOGNIZED_FORMAT; +} + +#ifdef MMAPI_SUPPORT +/*---------------------------------------------------------------------------- + * EAS_MMAPIToneControl() + *---------------------------------------------------------------------------- + * Purpose: + * Opens a ToneControl file for audio playback. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * pHandle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_MMAPIToneControl (EAS_DATA_HANDLE pEASData, EAS_FILE_LOCATOR locator, EAS_HANDLE *ppStream) +{ + EAS_RESULT result; + EAS_FILE_HANDLE fileHandle; + EAS_VOID_PTR streamHandle; + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_INT streamNum; + + /* check if the tone control parser is available */ + *ppStream = NULL; + streamHandle = NULL; + pParserModule = EAS_CMEnumOptModules(EAS_MODULE_MMAPI_TONE_CONTROL); + if (pParserModule == NULL) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_MMAPIToneControl: ToneControl parser not available\n"); */ } + return EAS_ERROR_FEATURE_NOT_AVAILABLE; + } + + /* open the file */ + if ((result = EAS_HWOpenFile(pEASData->hwInstData, locator, &fileHandle, EAS_FILE_READ)) != EAS_SUCCESS) + return result; + + /* allocate a stream */ + if ((streamNum = EAS_AllocateStream(pEASData)) < 0) + return EAS_ERROR_MAX_STREAMS_OPEN; + + /* see if ToneControl parser recognizes it */ + if ((result = (*pParserModule->pfCheckFileType)(pEASData, fileHandle, &streamHandle, 0L)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "CheckFileType returned error %ld\n", result); */ } + return result; + } + + /* parser accepted the file, return the handle */ + if (streamHandle) + { + + /* save the parser pointer and file handle */ + EAS_InitStream(&pEASData->streams[streamNum], pParserModule, streamHandle); + *ppStream = &pEASData->streams[streamNum]; + return EAS_SUCCESS; + } + + /* parser did not recognize the file, close it and return an error */ + EAS_HWCloseFile(pEASData->hwInstData, fileHandle); + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "No parser recognized the requested file\n"); */ } + return EAS_ERROR_UNRECOGNIZED_FORMAT; +} + +/*---------------------------------------------------------------------------- + * EAS_GetWaveFmtChunk + *---------------------------------------------------------------------------- + * Helper function to retrieve WAVE file fmt chunk for MMAPI + *---------------------------------------------------------------------------- + * pEASData - pointer to EAS persistent data object + * pStream - stream handle + * pFmtChunk - pointer to variable to receive current setting + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetWaveFmtChunk (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_VOID_PTR *ppFmtChunk) +{ + EAS_RESULT result; + EAS_I32 value; + + if ((result = EAS_GetStreamParameter(pEASData, pStream, PARSER_DATA_FORMAT, &value)) != EAS_SUCCESS) + return result; + *ppFmtChunk = (EAS_VOID_PTR) value; + return EAS_SUCCESS; +} +#endif + +/*---------------------------------------------------------------------------- + * EAS_GetFileType + *---------------------------------------------------------------------------- + * Returns the file type (see eas_types.h for enumerations) + *---------------------------------------------------------------------------- + * pEASData - pointer to EAS persistent data object + * pStream - stream handle + * pFileType - pointer to variable to receive file type + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetFileType (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_I32 *pFileType) +{ + if (!EAS_StreamReady (pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + return EAS_GetStreamParameter(pEASData, pStream, PARSER_DATA_FILE_TYPE, pFileType); +} + +/*---------------------------------------------------------------------------- + * EAS_Prepare() + *---------------------------------------------------------------------------- + * Purpose: + * Prepares the synthesizer to play the file or stream. Parses the first + * frame of data from the file and arms the synthesizer. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - file or stream handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Prepare (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream) +{ + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_STATE state; + EAS_RESULT result; + + pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; + if (pParserModule == NULL) + return EAS_ERROR_FEATURE_NOT_AVAILABLE; + + /* check for valid state */ + result = pParserModule->pfState(pEASData, pStream->handle, &state); + if (result == EAS_SUCCESS) + { + /* prepare the stream */ + if (state == EAS_STATE_OPEN) + { + pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; + result = (*pParserModule->pfPrepare)(pEASData, pStream->handle); + + /* set volume */ + if (result == EAS_SUCCESS) + result = EAS_SetVolume(pEASData, pStream, pStream->volume); + } + else + result = EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + } + + return result; +} + +/*---------------------------------------------------------------------------- + * EAS_Render() + *---------------------------------------------------------------------------- + * Purpose: + * Parse the Midi data and render PCM audio data. + * + * Inputs: + * pEASData - buffer for internal EAS data + * pOut - output buffer pointer + * nNumRequested - requested num samples to generate + * pnNumGenerated - actual number of samples generated + * + * Outputs: + * EAS_SUCCESS if PCM data was successfully rendered + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Render (EAS_DATA_HANDLE pEASData, EAS_PCM *pOut, EAS_I32 numRequested, EAS_I32 *pNumGenerated) +{ + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_RESULT result; + EAS_I32 voicesRendered; + EAS_STATE parserState; + EAS_INT streamNum; + + /* assume no samples generated and reset workload */ + *pNumGenerated = 0; + VMInitWorkload(pEASData->pVoiceMgr); + + /* no support for other buffer sizes yet */ + if (numRequested != BUFFER_SIZE_IN_MONO_SAMPLES) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "This library supports only %ld samples in buffer, host requested %ld samples\n", + (EAS_I32) BUFFER_SIZE_IN_MONO_SAMPLES, numRequested); */ } + return EAS_BUFFER_SIZE_MISMATCH; + } + +#ifdef _METRICS_ENABLED + /* start performance counter */ + if (pEASData->pMetricsData) + (*pEASData->pMetricsModule->pfStartTimer)(pEASData->pMetricsData, EAS_PM_TOTAL_TIME); +#endif + + /* prep the frame buffer, do mix engine prep only if TRUE */ +#ifdef _SPLIT_ARCHITECTURE + if (VMStartFrame(pEASData)) + EAS_MixEnginePrep(pEASData, numRequested); +#else + /* prep the mix engine */ + EAS_MixEnginePrep(pEASData, numRequested); +#endif + + /* save the output buffer pointer */ + pEASData->pOutputAudioBuffer = pOut; + + +#ifdef _METRICS_ENABLED + /* start performance counter */ + if (pEASData->pMetricsData) + (*pEASData->pMetricsModule->pfStartTimer)(pEASData->pMetricsData, EAS_PM_PARSE_TIME); +#endif + + /* if we haven't finished parsing from last time, do it now */ + /* need to parse another frame of events before we render again */ + for (streamNum = 0; streamNum < MAX_NUMBER_STREAMS; streamNum++) + { + /* clear the locate flag */ + pEASData->streams[streamNum].streamFlags &= ~STREAM_FLAGS_LOCATE; + + if (pEASData->streams[streamNum].pParserModule) + { + + /* establish pointer to parser module */ + pParserModule = pEASData->streams[streamNum].pParserModule; + + /* handle pause */ + if (pEASData->streams[streamNum].streamFlags & STREAM_FLAGS_PAUSE) + { + if (pParserModule->pfPause) + result = pParserModule->pfPause(pEASData, pEASData->streams[streamNum].handle); + pEASData->streams[streamNum].streamFlags &= ~STREAM_FLAGS_PAUSE; + } + + /* get current state */ + if ((result = (*pParserModule->pfState)(pEASData, pEASData->streams[streamNum].handle, &parserState)) != EAS_SUCCESS) + return result; + + /* handle resume */ + if (parserState == EAS_STATE_PAUSED) + { + if (pEASData->streams[streamNum].streamFlags & STREAM_FLAGS_RESUME) + { + if (pParserModule->pfResume) + result = pParserModule->pfResume(pEASData, pEASData->streams[streamNum].handle); + pEASData->streams[streamNum].streamFlags &= ~STREAM_FLAGS_RESUME; + } + } + + /* if necessary, parse stream */ + if ((pEASData->streams[streamNum].streamFlags & STREAM_FLAGS_PARSED) == 0) + if ((result = EAS_ParseEvents(pEASData, &pEASData->streams[streamNum], pEASData->streams[streamNum].time + pEASData->streams[streamNum].frameLength, eParserModePlay)) != EAS_SUCCESS) + return result; + + /* check for an early abort */ + if ((pEASData->streams[streamNum].streamFlags) == 0) + { + +#ifdef _METRICS_ENABLED + /* stop performance counter */ + if (pEASData->pMetricsData) + (*pEASData->pMetricsModule->pfStartTimer)(pEASData->pMetricsData, EAS_PM_TOTAL_TIME); +#endif + + return EAS_SUCCESS; + } + + /* check for repeat */ + if (pEASData->streams[streamNum].repeatCount) + { + + /* check for stopped state */ + if ((result = (*pParserModule->pfState)(pEASData, pEASData->streams[streamNum].handle, &parserState)) != EAS_SUCCESS) + return result; + if (parserState == EAS_STATE_STOPPED) + { + + /* decrement repeat count, unless it is negative */ + if (pEASData->streams[streamNum].repeatCount > 0) + pEASData->streams[streamNum].repeatCount--; + + /* reset the parser */ + if ((result = (*pParserModule->pfReset)(pEASData, pEASData->streams[streamNum].handle)) != EAS_SUCCESS) + return result; + pEASData->streams[streamNum].time = 0; + } + } + } + } + +#ifdef _METRICS_ENABLED + /* stop performance counter */ + if (pEASData->pMetricsData) + (void)(*pEASData->pMetricsModule->pfStopTimer)(pEASData->pMetricsData, EAS_PM_PARSE_TIME); +#endif + +#ifdef _METRICS_ENABLED + /* start the render timer */ + if (pEASData->pMetricsData) + (*pEASData->pMetricsModule->pfStartTimer)(pEASData->pMetricsData, EAS_PM_RENDER_TIME); +#endif + + /* render audio */ + if ((result = VMRender(pEASData->pVoiceMgr, BUFFER_SIZE_IN_MONO_SAMPLES, pEASData->pMixBuffer, &voicesRendered)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "pfRender function returned error %ld\n", result); */ } + return result; + } + +#ifdef _METRICS_ENABLED + /* stop the render timer */ + if (pEASData->pMetricsData) { + (*pEASData->pMetricsModule->pfIncrementCounter)(pEASData->pMetricsData, EAS_PM_FRAME_COUNT, 1); + (void)(*pEASData->pMetricsModule->pfStopTimer)(pEASData->pMetricsData, EAS_PM_RENDER_TIME); + (*pEASData->pMetricsModule->pfIncrementCounter)(pEASData->pMetricsData, EAS_PM_TOTAL_VOICE_COUNT, (EAS_U32) voicesRendered); + (void)(*pEASData->pMetricsModule->pfRecordMaxValue)(pEASData->pMetricsData, EAS_PM_MAX_VOICES, (EAS_U32) voicesRendered); + } +#endif + + //2 Do we really need frameParsed? + /* need to parse another frame of events before we render again */ + for (streamNum = 0; streamNum < MAX_NUMBER_STREAMS; streamNum++) + if (pEASData->streams[streamNum].pParserModule != NULL) + pEASData->streams[streamNum].streamFlags &= ~STREAM_FLAGS_PARSED; + +#ifdef _METRICS_ENABLED + /* start performance counter */ + if (pEASData->pMetricsData) + (*pEASData->pMetricsModule->pfStartTimer)(pEASData->pMetricsData, EAS_PM_STREAM_TIME); +#endif + + /* render PCM audio */ + if ((result = EAS_PERender(pEASData, numRequested)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_PERender returned error %ld\n", result); */ } + return result; + } + +#ifdef _METRICS_ENABLED + /* stop the stream timer */ + if (pEASData->pMetricsData) + (void)(*pEASData->pMetricsModule->pfStopTimer)(pEASData->pMetricsData, EAS_PM_STREAM_TIME); +#endif + +#ifdef _METRICS_ENABLED + /* start the post timer */ + if (pEASData->pMetricsData) + (*pEASData->pMetricsModule->pfStartTimer)(pEASData->pMetricsData, EAS_PM_POST_TIME); +#endif + + /* for split architecture, send DSP vectors. Do post only if return is TRUE */ +#ifdef _SPLIT_ARCHITECTURE + if (VMEndFrame(pEASData)) + { + /* now do post-processing */ + EAS_MixEnginePost(pEASData, numRequested); + *pNumGenerated = numRequested; + } +#else + /* now do post-processing */ + EAS_MixEnginePost(pEASData, numRequested); + *pNumGenerated = numRequested; +#endif + +#ifdef _METRICS_ENABLED + /* stop the post timer */ + if (pEASData->pMetricsData) + (void)(*pEASData->pMetricsModule->pfStopTimer)(pEASData->pMetricsData, EAS_PM_POST_TIME); +#endif + + /* advance render time */ + pEASData->renderTime += AUDIO_FRAME_LENGTH; + +#if 0 + /* dump workload for debug */ + if (pEASData->pVoiceMgr->workload) + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Workload = %d\n", pEASData->pVoiceMgr->workload); */ } +#endif + +#ifdef _METRICS_ENABLED + /* stop performance counter */ + if (pEASData->pMetricsData) + { + PERF_TIMER temp; + temp = (*pEASData->pMetricsModule->pfStopTimer)(pEASData->pMetricsData, EAS_PM_TOTAL_TIME); + + /* if max render time, record the number of voices and time */ + if ((*pEASData->pMetricsModule->pfRecordMaxValue) + (pEASData->pMetricsData, EAS_PM_MAX_CYCLES, (EAS_U32) temp)) + { + (*pEASData->pMetricsModule->pfRecordValue)(pEASData->pMetricsData, EAS_PM_MAX_CYCLES_VOICES, (EAS_U32) voicesRendered); + (*pEASData->pMetricsModule->pfRecordValue)(pEASData->pMetricsData, EAS_PM_MAX_CYCLES_TIME, (EAS_I32) (pEASData->renderTime >> 8)); + } + } +#endif + +#ifdef JET_INTERFACE + /* let JET to do its thing */ + if (pEASData->jetHandle != NULL) + { + result = JET_Process(pEASData); + if (result != EAS_SUCCESS) + return result; + } +#endif + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_SetRepeat() + *---------------------------------------------------------------------------- + * Purpose: + * Set the selected stream to repeat. + * + * Inputs: + * pEASData - handle to data for this instance + * handle - handle to stream + * repeatCount - repeat count + * + * Outputs: + * + * Side Effects: + * + * Notes: + * 0 = no repeat + * 1 = repeat once, i.e. play through twice + * -1 = repeat forever + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_PUBLIC EAS_RESULT EAS_SetRepeat (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 repeatCount) +{ + pStream->repeatCount = repeatCount; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_GetRepeat() + *---------------------------------------------------------------------------- + * Purpose: + * Gets the current repeat count for the selected stream. + * + * Inputs: + * pEASData - handle to data for this instance + * handle - handle to stream + * pRrepeatCount - pointer to variable to hold repeat count + * + * Outputs: + * + * Side Effects: + * + * Notes: + * 0 = no repeat + * 1 = repeat once, i.e. play through twice + * -1 = repeat forever + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_PUBLIC EAS_RESULT EAS_GetRepeat (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 *pRepeatCount) +{ + *pRepeatCount = pStream->repeatCount; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_SetPlaybackRate() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the playback rate. + * + * Inputs: + * pEASData - handle to data for this instance + * handle - handle to stream + * rate - rate (28-bit fractional amount) + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_PUBLIC EAS_RESULT EAS_SetPlaybackRate (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_U32 rate) +{ + + /* check range */ + if ((rate < (1 << 27)) || (rate > (1 << 29))) + return EAS_ERROR_INVALID_PARAMETER; + + /* calculate new frame length + * + * NOTE: The maximum frame length we can accomodate based on a + * maximum rate of 2.0 (2^28) is 2047 (2^13-1). To accomodate a + * longer frame length or a higher maximum rate, the fixed point + * divide below will need to be adjusted + */ + pStream->frameLength = (AUDIO_FRAME_LENGTH * (rate >> 8)) >> 20; + + /* notify stream of new playback rate */ + EAS_SetStreamParameter(pEASData, pStream, PARSER_DATA_PLAYBACK_RATE, (EAS_I32) rate); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_SetTransposition) + *---------------------------------------------------------------------------- + * Purpose: + * Sets the key tranposition for the synthesizer. Transposes all + * melodic instruments by the specified amount. Range is limited + * to +/-12 semitones. + * + * Inputs: + * pEASData - handle to data for this instance + * handle - handle to stream + * transposition - +/-12 semitones + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetTransposition (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 transposition) +{ + + /* check range */ + if ((transposition < -12) || (transposition > 12)) + return EAS_ERROR_INVALID_PARAMETER; + + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + return EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_TRANSPOSITION, transposition); +} + +/*---------------------------------------------------------------------------- + * EAS_ParseEvents() + *---------------------------------------------------------------------------- + * Purpose: + * Parse events in the current streams until the desired time is reached. + * + * Inputs: + * pEASData - buffer for internal EAS data + * endTime - stop parsing if this time is reached + * parseMode - play, locate, or metadata + * + * Outputs: + * EAS_SUCCESS if PCM data was successfully rendered + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT EAS_ParseEvents (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_U32 endTime, EAS_INT parseMode) +{ + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_RESULT result; + EAS_I32 parserState; + EAS_BOOL done; + EAS_INT yieldCount = YIELD_EVENT_COUNT; + EAS_U32 time = 0; + + /* does this parser have a time function? */ + pParserModule = pStream->pParserModule; + if (pParserModule->pfTime == NULL) + { + /* check state */ + if ((result = (*pParserModule->pfState)(pEASData, pStream->handle, &parserState)) != EAS_SUCCESS) + return result; + /* if play state, advance time */ + if ((parserState >= EAS_STATE_READY) && (parserState <= EAS_STATE_PAUSING)) + pStream->time += pStream->frameLength; + done = EAS_TRUE; + } + + /* assume we're not done, in case we abort out */ + else + { + pStream->streamFlags &= ~STREAM_FLAGS_PARSED; + done = EAS_FALSE; + } + + while (!done) + { + + /* check for stopped state */ + if ((result = (*pParserModule->pfState)(pEASData, pStream->handle, &parserState)) != EAS_SUCCESS) + return result; + if (parserState > EAS_STATE_PLAY) + { + /* save current time if we're not in play mode */ + if (parseMode != eParserModePlay) + pStream->time = time << 8; + done = EAS_TRUE; + break; + } + + /* get the next event time */ + if (pParserModule->pfTime) + { + if ((result = (*pParserModule->pfTime)(pEASData, pStream->handle, &time)) != EAS_SUCCESS) + return result; + + /* if next event is within this frame, parse it */ + if (time < (endTime >> 8)) + { + + /* parse the next event */ + if (pParserModule->pfEvent) + if ((result = (*pParserModule->pfEvent)(pEASData, pStream->handle, parseMode)) != EAS_SUCCESS) + return result; + } + + /* no more events in this frame, advance time */ + else + { + pStream->time = endTime; + done = EAS_TRUE; + } + } + + /* check for max workload exceeded */ + if (VMCheckWorkload(pEASData->pVoiceMgr)) + { + /* stop even though we may not have parsed + * all the events in this frame. The parser will try to + * catch up on the next frame. + */ + break; + } + + /* give host a chance for an early abort */ + if (--yieldCount == 0) + { + if (EAS_HWYield(pEASData->hwInstData)) + break; + yieldCount = YIELD_EVENT_COUNT; + } + } + + /* if no early abort, parsing is complete for this frame */ + if (done) + pStream->streamFlags |= STREAM_FLAGS_PARSED; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_ParseMetaData() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - file or stream handle + * playLength - pointer to variable to store the play length (in msecs) + * + * Outputs: + * + * + * Side Effects: + * - resets the parser to the start of the file + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_ParseMetaData (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 *playLength) +{ + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_RESULT result; + EAS_STATE state; + + pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; + if (pParserModule == NULL) + return EAS_ERROR_FEATURE_NOT_AVAILABLE; + + /* check parser state */ + if ((result = (*pParserModule->pfState)(pEASData, pStream->handle, &state)) != EAS_SUCCESS) + return result; + if (state >= EAS_STATE_OPEN) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + /* if parser has metadata function, use that */ + if (pParserModule->pfGetMetaData != NULL) + return pParserModule->pfGetMetaData(pEASData, pStream->handle, playLength); + + /* reset the parser to the beginning */ + if ((result = (*pParserModule->pfReset)(pEASData, pStream->handle)) != EAS_SUCCESS) + return result; + + /* parse the file to end */ + pStream->time = 0; + VMInitWorkload(pEASData->pVoiceMgr); + if ((result = EAS_ParseEvents(pEASData, pStream, 0x7fffffff, eParserModeMetaData)) != EAS_SUCCESS) + return result; + + /* get the parser time */ + if ((result = EAS_GetLocation(pEASData, pStream, playLength)) != EAS_SUCCESS) + return result; + + /* reset the parser to the beginning */ + pStream->time = 0; + return (*pParserModule->pfReset)(pEASData, pStream->handle); +} + +/*---------------------------------------------------------------------------- + * EAS_RegisterMetaDataCallback() + *---------------------------------------------------------------------------- + * Purpose: + * Registers a metadata callback function for parsed metadata. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - file or stream handle + * cbFunc - pointer to host callback function + * metaDataBuffer - pointer to metadata buffer + * metaDataBufSize - maximum size of the metadata buffer + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_RegisterMetaDataCallback ( + EAS_DATA_HANDLE pEASData, + EAS_HANDLE pStream, + EAS_METADATA_CBFUNC cbFunc, + char *metaDataBuffer, + EAS_I32 metaDataBufSize, + EAS_VOID_PTR pUserData) +{ + S_METADATA_CB metadata; + + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + /* register callback function */ + metadata.callback = cbFunc; + metadata.buffer = metaDataBuffer; + metadata.bufferSize = metaDataBufSize; + metadata.pUserData = pUserData; + return EAS_SetStreamParameter(pEASData, pStream, PARSER_DATA_METADATA_CB, (EAS_I32) &metadata); +} + +/*---------------------------------------------------------------------------- + * EAS_GetNoteCount () + *---------------------------------------------------------------------------- + * Returns the total number of notes played in this stream + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetNoteCount (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 *pNoteCount) +{ + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + return EAS_IntGetStrmParam(pEASData, pStream, PARSER_DATA_NOTE_COUNT, pNoteCount); +} + +/*---------------------------------------------------------------------------- + * EAS_CloseFile() + *---------------------------------------------------------------------------- + * Purpose: + * Closes an audio file or stream. Playback should have either paused or + * completed (EAS_State returns EAS_PAUSED or EAS_STOPPED). + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - file or stream handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_CloseFile (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream) +{ + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_RESULT result; + + /* call the close function */ + pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; + if (pParserModule == NULL) + return EAS_ERROR_FEATURE_NOT_AVAILABLE; + + result = (*pParserModule->pfClose)(pEASData, pStream->handle); + + /* clear the handle and parser interface pointer */ + pStream->handle = NULL; + pStream->pParserModule = NULL; + return result; +} + +/*---------------------------------------------------------------------------- + * EAS_OpenMIDIStream() + *---------------------------------------------------------------------------- + * Purpose: + * Opens a raw MIDI stream allowing the host to route MIDI cable data directly to the synthesizer + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * pHandle - pointer to variable to hold file or stream handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_OpenMIDIStream (EAS_DATA_HANDLE pEASData, EAS_HANDLE *ppStream, EAS_HANDLE streamHandle) +{ + EAS_RESULT result; + S_INTERACTIVE_MIDI *pMIDIStream; + EAS_INT streamNum; + + /* initialize some pointers */ + *ppStream = NULL; + + /* allocate a stream */ + if ((streamNum = EAS_AllocateStream(pEASData)) < 0) + return EAS_ERROR_MAX_STREAMS_OPEN; + + /* check Configuration Module for S_EAS_DATA allocation */ + if (pEASData->staticMemoryModel) + pMIDIStream = EAS_CMEnumData(EAS_CM_MIDI_STREAM_DATA); + else + pMIDIStream = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_INTERACTIVE_MIDI)); + + /* allocate dynamic memory */ + if (!pMIDIStream) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Failed to allocate MIDI stream data\n"); */ } + return EAS_ERROR_MALLOC_FAILED; + } + + /* zero the memory to insure complete initialization */ + EAS_HWMemSet(pMIDIStream, 0, sizeof(S_INTERACTIVE_MIDI)); + EAS_InitStream(&pEASData->streams[streamNum], NULL, pMIDIStream); + + /* instantiate a new synthesizer */ + if (streamHandle == NULL) + { + result = VMInitMIDI(pEASData, &pMIDIStream->pSynth); + } + + /* use an existing synthesizer */ + else + { + EAS_I32 value; + result = EAS_GetStreamParameter(pEASData, streamHandle, PARSER_DATA_SYNTH_HANDLE, &value); + pMIDIStream->pSynth = (S_SYNTH*) value; + VMIncRefCount(pMIDIStream->pSynth); + } + if (result != EAS_SUCCESS) + { + EAS_CloseMIDIStream(pEASData, &pEASData->streams[streamNum]); + return result; + } + + /* initialize the MIDI stream data */ + EAS_InitMIDIStream(&pMIDIStream->stream); + + *ppStream = (EAS_HANDLE) &pEASData->streams[streamNum]; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_WriteMIDIStream() + *---------------------------------------------------------------------------- + * Purpose: + * Send data to the MIDI stream device + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - stream handle + * pBuffer - pointer to buffer + * count - number of bytes to write + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_WriteMIDIStream (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_U8 *pBuffer, EAS_I32 count) +{ + S_INTERACTIVE_MIDI *pMIDIStream; + EAS_RESULT result; + + pMIDIStream = (S_INTERACTIVE_MIDI*) pStream->handle; + + /* send the entire buffer */ + while (count--) + { + if ((result = EAS_ParseMIDIStream(pEASData, pMIDIStream->pSynth, &pMIDIStream->stream, *pBuffer++, eParserModePlay)) != EAS_SUCCESS) + return result; + } + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_CloseMIDIStream() + *---------------------------------------------------------------------------- + * Purpose: + * Closes a raw MIDI stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - stream handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_CloseMIDIStream (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream) +{ + S_INTERACTIVE_MIDI *pMIDIStream; + + pMIDIStream = (S_INTERACTIVE_MIDI*) pStream->handle; + + /* close synth */ + if (pMIDIStream->pSynth != NULL) + { + VMMIDIShutdown(pEASData, pMIDIStream->pSynth); + pMIDIStream->pSynth = NULL; + } + + /* release allocated memory */ + if (!pEASData->staticMemoryModel) + EAS_HWFree(((S_EAS_DATA*) pEASData)->hwInstData, pMIDIStream); + + pStream->handle = NULL; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_State() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the state of an audio file or stream. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - file or stream handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_State (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_STATE *pState) +{ + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_RESULT result; + + /* call the parser to return state */ + pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; + if (pParserModule == NULL) + return EAS_ERROR_FEATURE_NOT_AVAILABLE; + + if ((result = (*pParserModule->pfState)(pEASData, pStream->handle, pState)) != EAS_SUCCESS) + return result; + + /* if repeat count is set for this parser, mask the stopped state from the application */ + if (pStream->repeatCount && (*pState == EAS_STATE_STOPPED)) + *pState = EAS_STATE_PLAY; + + /* if we're not ready or playing, we don't need to hide state from host */ + if (*pState > EAS_STATE_PLAY) + return EAS_SUCCESS; + + /* if stream is about to be paused, report it as paused */ + if (pStream->streamFlags & STREAM_FLAGS_PAUSE) + { + if (pStream->streamFlags & STREAM_FLAGS_LOCATE) + *pState = EAS_STATE_PAUSED; + else + *pState = EAS_STATE_PAUSING; + } + + /* if stream is about to resume, report it as playing */ + if (pStream->streamFlags & STREAM_FLAGS_RESUME) + *pState = EAS_STATE_PLAY; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_SetPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Set the polyphony of the stream. A value of 0 allows the stream + * to use all voices (set by EAS_SetSynthPolyphony). + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - handle returned by EAS_OpenFile + * polyphonyCount - the desired polyphony count + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetPolyphony (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 polyphonyCount) +{ + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + return EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_POLYPHONY, polyphonyCount); +} + +/*---------------------------------------------------------------------------- + * EAS_GetPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current polyphony setting of the stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - handle returned by EAS_OpenFile + * pPolyphonyCount - pointer to variable to receive polyphony count + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetPolyphony (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 *pPolyphonyCount) +{ + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + return EAS_IntGetStrmParam(pEASData, pStream, PARSER_DATA_POLYPHONY, pPolyphonyCount); +} + +/*---------------------------------------------------------------------------- + * EAS_SetSynthPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Set the polyphony of the synth . Value must be >= 1 and <= the + * maximum number of voices. This function will pin the polyphony + * at those limits + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * synthNum - synthesizer number (0 = onboard, 1 = DSP) + * polyphonyCount - the desired polyphony count + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetSynthPolyphony (EAS_DATA_HANDLE pEASData, EAS_I32 synthNum, EAS_I32 polyphonyCount) +{ + return VMSetSynthPolyphony(pEASData->pVoiceMgr, synthNum, polyphonyCount); +} + +/*---------------------------------------------------------------------------- + * EAS_GetSynthPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current polyphony setting of the synth + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * synthNum - synthesizer number (0 = onboard, 1 = DSP) + * pPolyphonyCount - pointer to variable to receive polyphony count + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetSynthPolyphony (EAS_DATA_HANDLE pEASData, EAS_I32 synthNum, EAS_I32 *pPolyphonyCount) +{ + return VMGetSynthPolyphony(pEASData->pVoiceMgr, synthNum, pPolyphonyCount); +} + +/*---------------------------------------------------------------------------- + * EAS_SetPriority() + *---------------------------------------------------------------------------- + * Purpose: + * Set the priority of the stream. Determines which stream's voices + * are stolen when there are insufficient voices for all notes. + * Value must be in the range of 1-15, lower values are higher + * priority. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - handle returned by EAS_OpenFile + * polyphonyCount - the desired polyphony count + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetPriority (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 priority) +{ + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + return EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_PRIORITY, priority); +} + +/*---------------------------------------------------------------------------- + * EAS_GetPriority() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current priority setting of the stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - handle returned by EAS_OpenFile + * pPriority - pointer to variable to receive priority + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetPriority (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 *pPriority) +{ + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + return EAS_IntGetStrmParam(pEASData, pStream, PARSER_DATA_PRIORITY, pPriority); +} + +/*---------------------------------------------------------------------------- + * EAS_SetVolume() + *---------------------------------------------------------------------------- + * Purpose: + * Set the master gain for the mix engine in 1dB increments + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * volume - the desired master gain (100 is max) + * handle - file or stream handle + * + * Outputs: + * + * + * Side Effects: + * overrides any previously set master volume from sysex + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetVolume (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 volume) +{ + EAS_I16 gain; + + /* check range */ + if ((volume < 0) || (volume > EAS_MAX_VOLUME)) + return EAS_ERROR_PARAMETER_RANGE; + + /* stream volume */ + if (pStream != NULL) + { + EAS_I32 gainOffset; + EAS_RESULT result; + + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + /* get gain offset */ + pStream->volume = (EAS_U8) volume; + result = EAS_GetStreamParameter(pEASData, pStream, PARSER_DATA_GAIN_OFFSET, &gainOffset); + if (result == EAS_SUCCESS) + volume += gainOffset; + + /* set stream volume */ + gain = EAS_VolumeToGain(volume - STREAM_VOLUME_HEADROOM); + + /* convert to linear scalar */ + return EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_VOLUME, gain); + } + + /* master volume */ + pEASData->masterVolume = (EAS_U8) volume; +#if (NUM_OUTPUT_CHANNELS == 1) + /* leave 3dB headroom for mono output */ + volume -= 3; +#endif + + gain = EAS_VolumeToGain(volume - STREAM_VOLUME_HEADROOM); + pEASData->masterGain = gain; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_GetVolume() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the master volume for the synthesizer. The default volume setting is + * 50. The volume range is 0 to 100; + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * volume - the desired master volume + * handle - file or stream handle + * + * Outputs: + * + * + * Side Effects: + * overrides any previously set master volume from sysex + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_I32 EAS_GetVolume (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream) +{ + if (pStream == NULL) + return pEASData->masterVolume; + + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + return pStream->volume; +} + +/*---------------------------------------------------------------------------- + * EAS_SetMaxLoad() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the maximum workload the parsers will do in a single call to + * EAS_Render. The units are currently arbitrary, but should correlate + * well to the actual CPU cycles consumed. The primary effect is to + * reduce the occasional peaks in CPU cycles consumed when parsing + * dense parts of a MIDI score. + * + * Inputs: + * pEASData - handle to data for this instance + * maxLoad - the desired maximum workload + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetMaxLoad (EAS_DATA_HANDLE pEASData, EAS_I32 maxLoad) +{ + VMSetWorkload(pEASData->pVoiceMgr, maxLoad); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_SetMaxPCMStreams() + *---------------------------------------------------------------------------- + * Sets the maximum number of PCM streams allowed in parsers that + * use PCM streaming. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - handle returned by EAS_OpenFile + * maxNumStreams - maximum number of PCM streams + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetMaxPCMStreams (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 maxNumStreams) +{ + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + return EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_MAX_PCM_STREAMS, maxNumStreams); +} + +/*---------------------------------------------------------------------------- + * EAS_Locate() + *---------------------------------------------------------------------------- + * Purpose: + * Locate into the file associated with the handle. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - file handle + * milliseconds - playback offset from start of file in milliseconds + * + * Outputs: + * + * + * Side Effects: + * the actual offset will be quantized to the closest update period, typically + * a resolution of 5.9ms. Notes that are started prior to this time will not + * sound. Any notes currently playing will be shut off. + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Locate (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 milliseconds, EAS_BOOL offset) +{ + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_RESULT result; + EAS_U32 requestedTime; + EAS_STATE state; + + /* get pointer to parser function table */ + pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; + if (pParserModule == NULL) + return EAS_ERROR_FEATURE_NOT_AVAILABLE; + + if ((result = (*pParserModule->pfState)(pEASData, pStream->handle, &state)) != EAS_SUCCESS) + return result; + if (state >= EAS_STATE_OPEN) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + /* handle offset and limit to start of file */ + /*lint -e{704} use shift for performance*/ + if (offset) + milliseconds += (EAS_I32) pStream->time >> 8; + if (milliseconds < 0) + milliseconds = 0; + + /* check to see if the request is different from the current time */ + requestedTime = (EAS_U32) milliseconds; + if (requestedTime == (pStream->time >> 8)) + return EAS_SUCCESS; + + /* set the locate flag */ + pStream->streamFlags |= STREAM_FLAGS_LOCATE; + + /* use the parser locate function, if available */ + if (pParserModule->pfLocate != NULL) + { + EAS_BOOL parserLocate = EAS_FALSE; + result = pParserModule->pfLocate(pEASData, pStream->handle, (EAS_I32) requestedTime, &parserLocate); + if (!parserLocate) + { + if (result == EAS_SUCCESS) + pStream->time = requestedTime << 8; + return result; + } + } + + /* if we were paused and not going to resume, set pause request flag */ + if (((state == EAS_STATE_PAUSING) || (state == EAS_STATE_PAUSED)) && ((pStream->streamFlags & STREAM_FLAGS_RESUME) == 0)) + pStream->streamFlags |= STREAM_FLAGS_PAUSE; + + /* reset the synth and parser */ + if ((result = (*pParserModule->pfReset)(pEASData, pStream->handle)) != EAS_SUCCESS) + return result; + pStream->time = 0; + + /* locating forward, clear parsed flag and parse data until we get to the requested location */ + if ((result = EAS_ParseEvents(pEASData, pStream, requestedTime << 8, eParserModeLocate)) != EAS_SUCCESS) + return result; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_GetLocation() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current playback offset + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - file handle + * + * Outputs: + * The offset in milliseconds from the start of the current sequence, quantized + * to the nearest update period. Actual resolution is typically 5.9 ms. + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_PUBLIC EAS_RESULT EAS_GetLocation (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 *pTime) +{ + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + *pTime = pStream->time >> 8; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_GetRenderTime() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current playback offset + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * + * Outputs: + * Gets the render time clock in msecs. + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetRenderTime (EAS_DATA_HANDLE pEASData, EAS_I32 *pTime) +{ + *pTime = pEASData->renderTime >> 8; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_Pause() + *---------------------------------------------------------------------------- + * Purpose: + * Pauses the playback of the data associated with this handle. The audio + * is gracefully ramped down to prevent clicks and pops. It may take several + * buffers of audio before the audio is muted. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * handle - file or stream handle + * + * Outputs: + * + * + * Side Effects: + * + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Pause (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream) +{ + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_STATE state; + EAS_RESULT result; + + pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; + if (pParserModule == NULL) + return EAS_ERROR_FEATURE_NOT_AVAILABLE; + + /* check for valid state */ + result = pParserModule->pfState(pEASData, pStream->handle, &state); + if (result == EAS_SUCCESS) + { + if ((state != EAS_STATE_PLAY) && (state != EAS_STATE_READY) && ((pStream->streamFlags & STREAM_FLAGS_RESUME) == 0)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + /* make sure parser implements pause */ + if (pParserModule->pfPause == NULL) + result = EAS_ERROR_NOT_IMPLEMENTED; + + /* clear resume flag */ + pStream->streamFlags &= ~STREAM_FLAGS_RESUME; + + /* set pause flag */ + pStream->streamFlags |= STREAM_FLAGS_PAUSE; + +#if 0 + /* pause the stream */ + if (pParserModule->pfPause) + result = pParserModule->pfPause(pEASData, pStream->handle); + else + result = EAS_ERROR_NOT_IMPLEMENTED; +#endif + } + + return result; +} + +/*---------------------------------------------------------------------------- + * EAS_Resume() + *---------------------------------------------------------------------------- + * Purpose: + * Resumes the playback of the data associated with this handle. The audio + * is gracefully ramped up to prevent clicks and pops. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * handle - file or stream handle + * + * Outputs: + * + * + * Side Effects: + * + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Resume (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream) +{ + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_STATE state; + EAS_RESULT result; + + pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; + if (pParserModule == NULL) + return EAS_ERROR_FEATURE_NOT_AVAILABLE; + + /* check for valid state */ + result = pParserModule->pfState(pEASData, pStream->handle, &state); + if (result == EAS_SUCCESS) + { + if ((state != EAS_STATE_PAUSED) && (state != EAS_STATE_PAUSING) && ((pStream->streamFlags & STREAM_FLAGS_PAUSE) == 0)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + /* make sure parser implements this function */ + if (pParserModule->pfResume == NULL) + result = EAS_ERROR_NOT_IMPLEMENTED; + + /* clear pause flag */ + pStream->streamFlags &= ~STREAM_FLAGS_PAUSE; + + /* set resume flag */ + pStream->streamFlags |= STREAM_FLAGS_RESUME; + +#if 0 + /* resume the stream */ + if (pParserModule->pfResume) + result = pParserModule->pfResume(pEASData, pStream->handle); + else + result = EAS_ERROR_NOT_IMPLEMENTED; +#endif + } + + return result; +} + +/*---------------------------------------------------------------------------- + * EAS_GetParameter() + *---------------------------------------------------------------------------- + * Purpose: + * Set the parameter of a module. See E_MODULES for a list of modules + * and the header files of the modules for a list of parameters. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * handle - file or stream handle + * module - enumerated module number + * param - enumerated parameter number + * pValue - pointer to variable to receive parameter value + * + * Outputs: + * + * + * Side Effects: + * + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetParameter (EAS_DATA_HANDLE pEASData, EAS_I32 module, EAS_I32 param, EAS_I32 *pValue) +{ + + if (module >= NUM_EFFECTS_MODULES) + return EAS_ERROR_INVALID_MODULE; + + if (pEASData->effectsModules[module].effectData == NULL) + return EAS_ERROR_INVALID_MODULE; + + return (*pEASData->effectsModules[module].effect->pFGetParam) + (pEASData->effectsModules[module].effectData, param, pValue); +} + +/*---------------------------------------------------------------------------- + * EAS_SetParameter() + *---------------------------------------------------------------------------- + * Purpose: + * Set the parameter of a module. See E_MODULES for a list of modules + * and the header files of the modules for a list of parameters. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * handle - file or stream handle + * module - enumerated module number + * param - enumerated parameter number + * value - new parameter value + * + * Outputs: + * + * + * Side Effects: + * + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetParameter (EAS_DATA_HANDLE pEASData, EAS_I32 module, EAS_I32 param, EAS_I32 value) +{ + + if (module >= NUM_EFFECTS_MODULES) + return EAS_ERROR_INVALID_MODULE; + + if (pEASData->effectsModules[module].effectData == NULL) + return EAS_ERROR_INVALID_MODULE; + + return (*pEASData->effectsModules[module].effect->pFSetParam) + (pEASData->effectsModules[module].effectData, param, value); +} + +#ifdef _METRICS_ENABLED +/*---------------------------------------------------------------------------- + * EAS_MetricsReport() + *---------------------------------------------------------------------------- + * Purpose: + * Displays the current metrics through the metrics interface. + * + * Inputs: + * p - instance data handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_MetricsReport (EAS_DATA_HANDLE pEASData) +{ + if (!pEASData->pMetricsModule) + return EAS_ERROR_INVALID_MODULE; + + return (*pEASData->pMetricsModule->pfReport)(pEASData->pMetricsData); +} + +/*---------------------------------------------------------------------------- + * EAS_MetricsReset() + *---------------------------------------------------------------------------- + * Purpose: + * Resets the metrics. + * + * Inputs: + * p - instance data handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_MetricsReset (EAS_DATA_HANDLE pEASData) +{ + + if (!pEASData->pMetricsModule) + return EAS_ERROR_INVALID_MODULE; + + return (*pEASData->pMetricsModule->pfReset)(pEASData->pMetricsData); +} +#endif + +/*---------------------------------------------------------------------------- + * EAS_SetSoundLibrary() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the location of the sound library. + * + * Inputs: + * pEASData - instance data handle + * pSoundLib - pointer to sound library + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetSoundLibrary (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_SNDLIB_HANDLE pSndLib) +{ + if (pStream) + { + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + return EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_EAS_LIBRARY, (EAS_I32) pSndLib); + } + + return VMSetGlobalEASLib(pEASData->pVoiceMgr, pSndLib); +} + +/*---------------------------------------------------------------------------- + * EAS_SetHeaderSearchFlag() + *---------------------------------------------------------------------------- + * By default, when EAS_OpenFile is called, the parsers check the + * first few bytes of the file looking for a specific header. Some + * mobile devices may add a header to the start of a file, which + * will prevent the parser from recognizing the file. If the + * searchFlag is set to EAS_TRUE, the parser will search the entire + * file looking for the header. This may enable EAS to recognize + * some files that it would ordinarily reject. The negative is that + * it make take slightly longer to process the EAS_OpenFile request. + * + * Inputs: + * pEASData - instance data handle + * searchFlag - search flag (EAS_TRUE or EAS_FALSE) + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetHeaderSearchFlag (EAS_DATA_HANDLE pEASData, EAS_BOOL searchFlag) +{ + pEASData->searchHeaderFlag = (EAS_BOOL8) searchFlag; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_SetPlayMode() + *---------------------------------------------------------------------------- + * Some file formats support special play modes, such as iMode partial + * play mode. This call can be used to change the play mode. The + * default play mode (usually straight playback) is always zero. + * + * Inputs: + * pEASData - instance data handle + * handle - file or stream handle + * playMode - play mode (see file parser for specifics) + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetPlayMode (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 playMode) +{ + return EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_PLAY_MODE, playMode); +} + +#ifdef DLS_SYNTHESIZER +/*---------------------------------------------------------------------------- + * EAS_LoadDLSCollection() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the location of the sound library. + * + * Inputs: + * pEASData - instance data handle + * pSoundLib - pointer to sound library + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_LoadDLSCollection (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_FILE_LOCATOR locator) +{ + EAS_FILE_HANDLE fileHandle; + EAS_RESULT result; + EAS_DLSLIB_HANDLE pDLS; + + if (pStream != NULL) + { + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + } + + /* open the file */ + if ((result = EAS_HWOpenFile(pEASData->hwInstData, locator, &fileHandle, EAS_FILE_READ)) != EAS_SUCCESS) + return result; + + /* parse the file */ + result = DLSParser(pEASData->hwInstData, fileHandle, 0, &pDLS); + EAS_HWCloseFile(pEASData->hwInstData, fileHandle); + + if (result == EAS_SUCCESS) + { + + /* if a stream pStream is specified, point it to the DLS collection */ + if (pStream) + result = EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_DLS_COLLECTION, (EAS_I32) pDLS); + + /* global DLS load */ + else + result = VMSetGlobalDLSLib(pEASData, pDLS); + } + + return result; +} +#endif + +#ifdef EXTERNAL_AUDIO +/*---------------------------------------------------------------------------- + * EAS_RegExtAudioCallback() + *---------------------------------------------------------------------------- + * Purpose: + * Registers callback functions for audio events. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - file or stream handle + * cbProgChgFunc - pointer to host callback function for program change + * cbEventFunc - pointer to host callback functio for note events + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_RegExtAudioCallback (EAS_DATA_HANDLE pEASData, + EAS_HANDLE pStream, + EAS_VOID_PTR pInstData, + EAS_EXT_PRG_CHG_FUNC cbProgChgFunc, + EAS_EXT_EVENT_FUNC cbEventFunc) +{ + S_SYNTH *pSynth; + + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + if (EAS_GetStreamParameter(pEASData, pStream, PARSER_DATA_SYNTH_HANDLE, (EAS_I32*) &pSynth) != EAS_SUCCESS) + return EAS_ERROR_INVALID_PARAMETER; + + if (pSynth == NULL) + return EAS_ERROR_INVALID_PARAMETER; + + VMRegExtAudioCallback(pSynth, pInstData, cbProgChgFunc, cbEventFunc); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_GetMIDIControllers() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current state of MIDI controllers on the requested channel. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - file or stream handle + * pControl - pointer to structure to receive data + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetMIDIControllers (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_U8 channel, S_MIDI_CONTROLLERS *pControl) +{ + S_SYNTH *pSynth; + + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + if (EAS_GetStreamParameter(pEASData, pStream, PARSER_DATA_SYNTH_HANDLE, (EAS_I32*) &pSynth) != EAS_SUCCESS) + return EAS_ERROR_INVALID_PARAMETER; + + if (pSynth == NULL) + return EAS_ERROR_INVALID_PARAMETER; + + VMGetMIDIControllers(pSynth, channel, pControl); + return EAS_SUCCESS; +} +#endif + +#ifdef _SPLIT_ARCHITECTURE +/*---------------------------------------------------------------------------- + * EAS_SetFrameBuffer() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the frame buffer pointer passed to the IPC communications functions + * + * Inputs: + * pEASData - instance data handle + * locator - file locator + * + * Outputs: + * + * + * Side Effects: + * May overlay instruments in the GM sound set + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetFrameBuffer (EAS_DATA_HANDLE pEASData, EAS_FRAME_BUFFER_HANDLE pFrameBuffer) +{ + if (pEASData->pVoiceMgr) + pEASData->pVoiceMgr->pFrameBuffer = pFrameBuffer; + return EAS_SUCCESS; +} +#endif + +/*---------------------------------------------------------------------------- + * EAS_SearchFile + *---------------------------------------------------------------------------- + * Search file for specific sequence starting at current file + * position. Returns offset to start of sequence. + * + * Inputs: + * pEASData - pointer to EAS persistent data object + * fileHandle - file handle + * searchString - pointer to search sequence + * len - length of search sequence + * pOffset - pointer to variable to store offset to sequence + * + * Returns EAS_EOF if end-of-file is reached + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_SearchFile (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, const EAS_U8 *searchString, EAS_I32 len, EAS_I32 *pOffset) +{ + EAS_RESULT result; + EAS_INT index; + EAS_U8 c; + + *pOffset = -1; + index = 0; + for (;;) + { + result = EAS_HWGetByte(pEASData->hwInstData, fileHandle, &c); + if (result != EAS_SUCCESS) + return result; + if (c == searchString[index]) + { + index++; + if (index == 4) + { + result = EAS_HWFilePos(pEASData->hwInstData, fileHandle, pOffset); + if (result != EAS_SUCCESS) + return result; + *pOffset -= len; + break; + } + } + else + index = 0; + } + return EAS_SUCCESS; +} + + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_reverb.c b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_reverb.c new file mode 100755 index 0000000..cd5befe --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_reverb.c @@ -0,0 +1,1154 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_reverb.c + * + * Contents and purpose: + * Contains the implementation of the Reverb effect. + * + * + * Copyright Sonic Network Inc. 2006 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 510 $ + * $Date: 2006-12-19 01:47:33 -0800 (Tue, 19 Dec 2006) $ + *---------------------------------------------------------------------------- +*/ + +/*------------------------------------ + * includes + *------------------------------------ +*/ + +#include "eas_data.h" +#include "eas_effects.h" +#include "eas_math.h" +#include "eas_reverbdata.h" +#include "eas_reverb.h" +#include "eas_config.h" +#include "eas_host.h" +#include "eas_report.h" + +/* prototypes for effects interface */ +static EAS_RESULT ReverbInit (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR *pInstData); +static void ReverbProcess (EAS_VOID_PTR pInstData, EAS_PCM *pSrc, EAS_PCM *pDst, EAS_I32 numSamples); +static EAS_RESULT ReverbShutdown (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT ReverbGetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue); +static EAS_RESULT ReverbSetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value); + +/* common effects interface for configuration module */ +const S_EFFECTS_INTERFACE EAS_Reverb = +{ + ReverbInit, + ReverbProcess, + ReverbShutdown, + ReverbGetParam, + ReverbSetParam +}; + + + +/*---------------------------------------------------------------------------- + * InitializeReverb() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ReverbInit(EAS_DATA_HANDLE pEASData, EAS_VOID_PTR *pInstData) +{ + EAS_I32 i; + EAS_U16 nOffset; + EAS_INT temp; + + S_REVERB_OBJECT *pReverbData; + S_REVERB_PRESET *pPreset; + + /* check Configuration Module for data allocation */ + if (pEASData->staticMemoryModel) + pReverbData = EAS_CMEnumFXData(EAS_MODULE_REVERB); + + /* allocate dynamic memory */ + else + pReverbData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_REVERB_OBJECT)); + + if (pReverbData == NULL) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Failed to allocate Reverb memory\n"); */ } + return EAS_ERROR_MALLOC_FAILED; + } + + /* clear the structure */ + EAS_HWMemSet(pReverbData, 0, sizeof(S_REVERB_OBJECT)); + + ReverbReadInPresets(pReverbData); + + pReverbData->m_nMinSamplesToAdd = REVERB_UPDATE_PERIOD_IN_SAMPLES; + + pReverbData->m_nRevOutFbkR = 0; + pReverbData->m_nRevOutFbkL = 0; + + pReverbData->m_sAp0.m_zApIn = AP0_IN; + pReverbData->m_sAp0.m_zApOut = AP0_IN + DEFAULT_AP0_LENGTH; + pReverbData->m_sAp0.m_nApGain = DEFAULT_AP0_GAIN; + + pReverbData->m_zD0In = DELAY0_IN; + + pReverbData->m_sAp1.m_zApIn = AP1_IN; + pReverbData->m_sAp1.m_zApOut = AP1_IN + DEFAULT_AP1_LENGTH; + pReverbData->m_sAp1.m_nApGain = DEFAULT_AP1_GAIN; + + pReverbData->m_zD1In = DELAY1_IN; + + pReverbData->m_zLpf0 = 0; + pReverbData->m_zLpf1 = 0; + pReverbData->m_nLpfFwd = 8837; + pReverbData->m_nLpfFbk = 6494; + + pReverbData->m_nSin = 0; + pReverbData->m_nCos = 0; + pReverbData->m_nSinIncrement = 0; + pReverbData->m_nCosIncrement = 0; + + // set xfade parameters + pReverbData->m_nXfadeInterval = (EAS_U16)REVERB_XFADE_PERIOD_IN_SAMPLES; + pReverbData->m_nXfadeCounter = pReverbData->m_nXfadeInterval + 1; // force update on first iteration + pReverbData->m_nPhase = -32768; + pReverbData->m_nPhaseIncrement = REVERB_XFADE_PHASE_INCREMENT; + + pReverbData->m_nNoise = (EAS_I16)0xABCD; + + pReverbData->m_nMaxExcursion = 0x007F; + + // set delay tap lengths + nOffset = ReverbCalculateNoise( pReverbData->m_nMaxExcursion, + &pReverbData->m_nNoise ); + + pReverbData->m_zD1Cross = + DELAY1_OUT - pReverbData->m_nMaxExcursion + nOffset; + + nOffset = ReverbCalculateNoise( pReverbData->m_nMaxExcursion, + &pReverbData->m_nNoise ); + + pReverbData->m_zD0Cross = + DELAY1_OUT - pReverbData->m_nMaxExcursion - nOffset; + + nOffset = ReverbCalculateNoise( pReverbData->m_nMaxExcursion, + &pReverbData->m_nNoise ); + + pReverbData->m_zD0Self = + DELAY0_OUT - pReverbData->m_nMaxExcursion - nOffset; + + nOffset = ReverbCalculateNoise( pReverbData->m_nMaxExcursion, + &pReverbData->m_nNoise ); + + pReverbData->m_zD1Self = + DELAY1_OUT - pReverbData->m_nMaxExcursion + nOffset; + + // for debugging purposes, allow noise generator + pReverbData->m_bUseNoise = EAS_FALSE; + + // for debugging purposes, allow bypass + pReverbData->m_bBypass = EAS_TRUE; //EAS_FALSE; + + pReverbData->m_nNextRoom = 1; + + pReverbData->m_nCurrentRoom = pReverbData->m_nNextRoom + 1; // force update on first iteration + + pReverbData->m_nWet = REVERB_DEFAULT_WET; + + pReverbData->m_nDry = REVERB_DEFAULT_DRY; + + // set base index into circular buffer + pReverbData->m_nBaseIndex = 0; + + // set the early reflections, L + pReverbData->m_sEarlyL.m_nLpfFbk = 4915; + pReverbData->m_sEarlyL.m_nLpfFwd = 27852; + pReverbData->m_sEarlyL.m_zLpf = 0; + + for (i=0; i < REVERB_MAX_NUM_REFLECTIONS; i++) + { + pReverbData->m_sEarlyL.m_nGain[i] = 0; + pReverbData->m_sEarlyL.m_zDelay[i] = 0; + } + + // set the early reflections, R + pReverbData->m_sEarlyR.m_nLpfFbk = 4915; + pReverbData->m_sEarlyR.m_nLpfFwd = 27852; + pReverbData->m_sEarlyR.m_zLpf = 0; + + for (i=0; i < REVERB_MAX_NUM_REFLECTIONS; i++) + { + pReverbData->m_sEarlyR.m_nGain[i] = 0; + pReverbData->m_sEarlyR.m_zDelay[i] = 0; + } + + // clear the reverb delay line + for (i=0; i < REVERB_BUFFER_SIZE_IN_SAMPLES; i++) + { + pReverbData->m_nDelayLine[i] = 0; + } + + //////////////////////////////// + ///code from the EAS DEMO Reverb + //now copy from the new preset into the reverb + pPreset = &pReverbData->m_sPreset.m_sPreset[pReverbData->m_nNextRoom]; + + pReverbData->m_nLpfFbk = pPreset->m_nLpfFbk; + pReverbData->m_nLpfFwd = pPreset->m_nLpfFwd; + + pReverbData->m_nEarly = pPreset->m_nEarly; + pReverbData->m_nWet = pPreset->m_nWet; + pReverbData->m_nDry = pPreset->m_nDry; + + pReverbData->m_nMaxExcursion = pPreset->m_nMaxExcursion; + //stored as time based, convert to sample based + temp = pPreset->m_nXfadeInterval; + /*lint -e{702} shift for performance */ + temp = (temp * _OUTPUT_SAMPLE_RATE) >> 16; + pReverbData->m_nXfadeInterval = (EAS_U16) temp; + //gsReverbObject.m_nXfadeInterval = pPreset->m_nXfadeInterval; + + pReverbData->m_sAp0.m_nApGain = pPreset->m_nAp0_ApGain; + //stored as time based, convert to absolute sample value + temp = pPreset->m_nAp0_ApOut; + /*lint -e{702} shift for performance */ + temp = (temp * _OUTPUT_SAMPLE_RATE) >> 16; + pReverbData->m_sAp0.m_zApOut = (EAS_U16) (pReverbData->m_sAp0.m_zApIn + temp); + //gsReverbObject.m_sAp0.m_zApOut = pPreset->m_nAp0_ApOut; + + pReverbData->m_sAp1.m_nApGain = pPreset->m_nAp1_ApGain; + //stored as time based, convert to absolute sample value + temp = pPreset->m_nAp1_ApOut; + /*lint -e{702} shift for performance */ + temp = (temp * _OUTPUT_SAMPLE_RATE) >> 16; + pReverbData->m_sAp1.m_zApOut = (EAS_U16) (pReverbData->m_sAp1.m_zApIn + temp); + //gsReverbObject.m_sAp1.m_zApOut = pPreset->m_nAp1_ApOut; + ///code from the EAS DEMO Reverb + //////////////////////////////// + + *pInstData = pReverbData; + + return EAS_SUCCESS; + +} /* end InitializeReverb */ + + + +/*---------------------------------------------------------------------------- + * ReverbProcess() + *---------------------------------------------------------------------------- + * Purpose: + * Reverberate the requested number of samples (block based processing) + * + * Inputs: + * pInputBuffer - src buffer + * pOutputBuffer - dst buffer + * nNumSamplesToAdd - number of samples to write to buffer + * + * Outputs: + * number of samples actually written to buffer + * + * Side Effects: + * - samples are added to the presently free buffer + * + *---------------------------------------------------------------------------- +*/ +static void ReverbProcess(EAS_VOID_PTR pInstData, EAS_PCM *pSrc, EAS_PCM *pDst, EAS_I32 numSamples) +{ + S_REVERB_OBJECT *pReverbData; + + pReverbData = (S_REVERB_OBJECT*) pInstData; + + //if bypassed or the preset forces the signal to be completely dry + if (pReverbData->m_bBypass || + (pReverbData->m_nWet == 0 && pReverbData->m_nDry == 32767)) + { + if (pSrc != pDst) + EAS_HWMemCpy(pSrc, pDst, numSamples * NUM_OUTPUT_CHANNELS * (EAS_I32) sizeof(EAS_PCM)); + return; + } + + if (pReverbData->m_nNextRoom != pReverbData->m_nCurrentRoom) + { + ReverbUpdateRoom(pReverbData); + } + + ReverbUpdateXfade(pReverbData, numSamples); + + Reverb(pReverbData, numSamples, pDst, pSrc); + + /* check if update counter needs to be reset */ + if (pReverbData->m_nUpdateCounter >= REVERB_MODULO_UPDATE_PERIOD_IN_SAMPLES) + { + /* update interval has elapsed, so reset counter */ + pReverbData->m_nUpdateCounter = 0; + } /* end if m_nUpdateCounter >= update interval */ + + /* increment update counter */ + pReverbData->m_nUpdateCounter += (EAS_I16)numSamples; + +} /* end ComputeReverb */ + +/*---------------------------------------------------------------------------- + * ReverbUpdateXfade + *---------------------------------------------------------------------------- + * Purpose: + * Update the xfade parameters as required + * + * Inputs: + * nNumSamplesToAdd - number of samples to write to buffer + * + * Outputs: + * + * + * Side Effects: + * - xfade parameters will be changed + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ReverbUpdateXfade(S_REVERB_OBJECT *pReverbData, EAS_INT nNumSamplesToAdd) +{ + EAS_U16 nOffset; + EAS_I16 tempCos; + EAS_I16 tempSin; + + if (pReverbData->m_nXfadeCounter >= pReverbData->m_nXfadeInterval) + { + /* update interval has elapsed, so reset counter */ + pReverbData->m_nXfadeCounter = 0; + + // Pin the sin,cos values to min / max values to ensure that the + // modulated taps' coefs are zero (thus no clicks) + if (pReverbData->m_nPhaseIncrement > 0) + { + // if phase increment > 0, then sin -> 1, cos -> 0 + pReverbData->m_nSin = 32767; + pReverbData->m_nCos = 0; + + // reset the phase to match the sin, cos values + pReverbData->m_nPhase = 32767; + + // modulate the cross taps because their tap coefs are zero + nOffset = ReverbCalculateNoise( pReverbData->m_nMaxExcursion, &pReverbData->m_nNoise ); + + pReverbData->m_zD1Cross = + DELAY1_OUT - pReverbData->m_nMaxExcursion + nOffset; + + nOffset = ReverbCalculateNoise( pReverbData->m_nMaxExcursion, &pReverbData->m_nNoise ); + + pReverbData->m_zD0Cross = + DELAY0_OUT - pReverbData->m_nMaxExcursion - nOffset; + } + else + { + // if phase increment < 0, then sin -> 0, cos -> 1 + pReverbData->m_nSin = 0; + pReverbData->m_nCos = 32767; + + // reset the phase to match the sin, cos values + pReverbData->m_nPhase = -32768; + + // modulate the self taps because their tap coefs are zero + nOffset = ReverbCalculateNoise( pReverbData->m_nMaxExcursion, &pReverbData->m_nNoise ); + + pReverbData->m_zD0Self = + DELAY0_OUT - pReverbData->m_nMaxExcursion - nOffset; + + nOffset = ReverbCalculateNoise( pReverbData->m_nMaxExcursion, &pReverbData->m_nNoise ); + + pReverbData->m_zD1Self = + DELAY1_OUT - pReverbData->m_nMaxExcursion + nOffset; + + } // end if-else (pReverbData->m_nPhaseIncrement > 0) + + // Reverse the direction of the sin,cos so that the + // tap whose coef was previously increasing now decreases + // and vice versa + pReverbData->m_nPhaseIncrement = -pReverbData->m_nPhaseIncrement; + + } // end if counter >= update interval + + //compute what phase will be next time + pReverbData->m_nPhase += pReverbData->m_nPhaseIncrement; + + //calculate what the new sin and cos need to reach by the next update + ReverbCalculateSinCos(pReverbData->m_nPhase, &tempSin, &tempCos); + + //calculate the per-sample increment required to get there by the next update + /*lint -e{702} shift for performance */ + pReverbData->m_nSinIncrement = + (tempSin - pReverbData->m_nSin) >> REVERB_UPDATE_PERIOD_IN_BITS; + + /*lint -e{702} shift for performance */ + pReverbData->m_nCosIncrement = + (tempCos - pReverbData->m_nCos) >> REVERB_UPDATE_PERIOD_IN_BITS; + + + /* increment update counter */ + pReverbData->m_nXfadeCounter += (EAS_U16) nNumSamplesToAdd; + + return EAS_SUCCESS; + +} /* end ReverbUpdateXfade */ + + +/*---------------------------------------------------------------------------- + * ReverbCalculateNoise + *---------------------------------------------------------------------------- + * Purpose: + * Calculate a noise sample and limit its value + * + * Inputs: + * nMaxExcursion - noise value is limited to this value + * pnNoise - return new noise sample in this (not limited) + * + * Outputs: + * new limited noise value + * + * Side Effects: + * - *pnNoise noise value is updated + * + *---------------------------------------------------------------------------- +*/ +static EAS_U16 ReverbCalculateNoise(EAS_U16 nMaxExcursion, EAS_I16 *pnNoise) +{ + // calculate new noise value + *pnNoise = (EAS_I16) (*pnNoise * 5 + 1); + +#if 0 // 1xxx, test + *pnNoise = 0; +#endif // 1xxx, test + + // return the limited noise value + return (nMaxExcursion & (*pnNoise)); + +} /* end ReverbCalculateNoise */ + +/*---------------------------------------------------------------------------- + * ReverbCalculateSinCos + *---------------------------------------------------------------------------- + * Purpose: + * Calculate a new sin and cosine value based on the given phase + * + * Inputs: + * nPhase - phase angle + * pnSin - input old value, output new value + * pnCos - input old value, output new value + * + * Outputs: + * + * Side Effects: + * - *pnSin, *pnCos are updated + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ReverbCalculateSinCos(EAS_I16 nPhase, EAS_I16 *pnSin, EAS_I16 *pnCos) +{ + EAS_I32 nTemp; + EAS_I32 nNetAngle; + + // -1 <= nPhase < 1 + // However, for the calculation, we need a value + // that ranges from -1/2 to +1/2, so divide the phase by 2 + /*lint -e{702} shift for performance */ + nNetAngle = nPhase >> 1; + + /* + Implement the following + sin(x) = (2-4*c)*x^2 + c + x + cos(x) = (2-4*c)*x^2 + c - x + + where c = 1/sqrt(2) + using the a0 + x*(a1 + x*a2) approach + */ + + /* limit the input "angle" to be between -0.5 and +0.5 */ + if (nNetAngle > EG1_HALF) + { + nNetAngle = EG1_HALF; + } + else if (nNetAngle < EG1_MINUS_HALF) + { + nNetAngle = EG1_MINUS_HALF; + } + + /* calculate sin */ + nTemp = EG1_ONE + MULT_EG1_EG1(REVERB_PAN_G2, nNetAngle); + nTemp = REVERB_PAN_G0 + MULT_EG1_EG1(nTemp, nNetAngle); + *pnSin = (EAS_I16) SATURATE_EG1(nTemp); + + /* calculate cos */ + nTemp = -EG1_ONE + MULT_EG1_EG1(REVERB_PAN_G2, nNetAngle); + nTemp = REVERB_PAN_G0 + MULT_EG1_EG1(nTemp, nNetAngle); + *pnCos = (EAS_I16) SATURATE_EG1(nTemp); + + return EAS_SUCCESS; +} /* end ReverbCalculateSinCos */ + +/*---------------------------------------------------------------------------- + * Reverb + *---------------------------------------------------------------------------- + * Purpose: + * apply reverb to the given signal + * + * Inputs: + * nNu + * pnSin - input old value, output new value + * pnCos - input old value, output new value + * + * Outputs: + * number of samples actually reverberated + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT Reverb(S_REVERB_OBJECT *pReverbData, EAS_INT nNumSamplesToAdd, EAS_PCM *pOutputBuffer, EAS_PCM *pInputBuffer) +{ + EAS_I32 i; + EAS_I32 nDelayOut; + EAS_U16 nBase; + + EAS_U32 nAddr; + EAS_I32 nTemp1; + EAS_I32 nTemp2; + EAS_I32 nApIn; + EAS_I32 nApOut; + + EAS_I32 j; + EAS_I32 nEarlyOut; + + EAS_I32 tempValue; + + + // get the base address + nBase = pReverbData->m_nBaseIndex; + + for (i=0; i < nNumSamplesToAdd; i++) + { + // ********** Left Allpass - start + // left input = (left dry/4) + right feedback from previous period + /*lint -e{702} use shift for performance */ + nApIn = ((*pInputBuffer++)>>2) + pReverbData->m_nRevOutFbkR; +// nApIn = *pInputBuffer++; // 1xxx test and debug ap + + // fetch allpass delay line out + //nAddr = CIRCULAR(nBase, psAp0->m_zApOut, REVERB_BUFFER_MASK); + nAddr = CIRCULAR(nBase, pReverbData->m_sAp0.m_zApOut, REVERB_BUFFER_MASK); + nDelayOut = pReverbData->m_nDelayLine[nAddr]; + + // calculate allpass feedforward; subtract the feedforward result + nTemp1 = MULT_EG1_EG1(nApIn, pReverbData->m_sAp0.m_nApGain); + nApOut = SATURATE(nDelayOut - nTemp1); // allpass output + + // calculate allpass feedback; add the feedback result + nTemp1 = MULT_EG1_EG1(nApOut, pReverbData->m_sAp0.m_nApGain); + nTemp1 = SATURATE(nApIn + nTemp1); + + // inject into allpass delay + nAddr = CIRCULAR(nBase, pReverbData->m_sAp0.m_zApIn, REVERB_BUFFER_MASK); + pReverbData->m_nDelayLine[nAddr] = (EAS_PCM) nTemp1; + + // inject allpass output into delay line + nAddr = CIRCULAR(nBase, pReverbData->m_zD0In, REVERB_BUFFER_MASK); + pReverbData->m_nDelayLine[nAddr] = (EAS_PCM) nApOut; + + // ********** Left Allpass - end + + // ********** Right Allpass - start + // right input = (right dry/4) + left feedback from previous period + /*lint -e{702} use shift for performance */ + nApIn = ((*pInputBuffer++)>>2) + pReverbData->m_nRevOutFbkL; +// nApIn = *pInputBuffer++; // 1xxx test and debug ap + + // fetch allpass delay line out + nAddr = CIRCULAR(nBase, pReverbData->m_sAp1.m_zApOut, REVERB_BUFFER_MASK); + nDelayOut = pReverbData->m_nDelayLine[nAddr]; + + // calculate allpass feedforward; subtract the feedforward result + nTemp1 = MULT_EG1_EG1(nApIn, pReverbData->m_sAp1.m_nApGain); + nApOut = SATURATE(nDelayOut - nTemp1); // allpass output + + // calculate allpass feedback; add the feedback result + nTemp1 = MULT_EG1_EG1(nApOut, pReverbData->m_sAp1.m_nApGain); + nTemp1 = SATURATE(nApIn + nTemp1); + + // inject into allpass delay + nAddr = CIRCULAR(nBase, pReverbData->m_sAp1.m_zApIn, REVERB_BUFFER_MASK); + pReverbData->m_nDelayLine[nAddr] = (EAS_PCM) nTemp1; + + // inject allpass output into delay line + nAddr = CIRCULAR(nBase, pReverbData->m_zD1In, REVERB_BUFFER_MASK); + pReverbData->m_nDelayLine[nAddr] = (EAS_PCM) nApOut; + + // ********** Right Allpass - end + + // ********** D0 output - start + // fetch delay line self out + nAddr = CIRCULAR(nBase, pReverbData->m_zD0Self, REVERB_BUFFER_MASK); + nDelayOut = pReverbData->m_nDelayLine[nAddr]; + + // calculate delay line self out + nTemp1 = MULT_EG1_EG1(nDelayOut, pReverbData->m_nSin); + + // fetch delay line cross out + nAddr = CIRCULAR(nBase, pReverbData->m_zD1Cross, REVERB_BUFFER_MASK); + nDelayOut = pReverbData->m_nDelayLine[nAddr]; + + // calculate delay line self out + nTemp2 = MULT_EG1_EG1(nDelayOut, pReverbData->m_nCos); + + // calculate unfiltered delay out + nDelayOut = SATURATE(nTemp1 + nTemp2); + + // calculate lowpass filter (mixer scale factor included in LPF feedforward) + nTemp1 = MULT_EG1_EG1(nDelayOut, pReverbData->m_nLpfFwd); + + nTemp2 = MULT_EG1_EG1(pReverbData->m_zLpf0, pReverbData->m_nLpfFbk); + + // calculate filtered delay out and simultaneously update LPF state variable + // filtered delay output is stored in m_zLpf0 + pReverbData->m_zLpf0 = (EAS_PCM) SATURATE(nTemp1 + nTemp2); + + // ********** D0 output - end + + // ********** D1 output - start + // fetch delay line self out + nAddr = CIRCULAR(nBase, pReverbData->m_zD1Self, REVERB_BUFFER_MASK); + nDelayOut = pReverbData->m_nDelayLine[nAddr]; + + // calculate delay line self out + nTemp1 = MULT_EG1_EG1(nDelayOut, pReverbData->m_nSin); + + // fetch delay line cross out + nAddr = CIRCULAR(nBase, pReverbData->m_zD0Cross, REVERB_BUFFER_MASK); + nDelayOut = pReverbData->m_nDelayLine[nAddr]; + + // calculate delay line self out + nTemp2 = MULT_EG1_EG1(nDelayOut, pReverbData->m_nCos); + + // calculate unfiltered delay out + nDelayOut = SATURATE(nTemp1 + nTemp2); + + // calculate lowpass filter (mixer scale factor included in LPF feedforward) + nTemp1 = MULT_EG1_EG1(nDelayOut, pReverbData->m_nLpfFwd); + + nTemp2 = MULT_EG1_EG1(pReverbData->m_zLpf1, pReverbData->m_nLpfFbk); + + // calculate filtered delay out and simultaneously update LPF state variable + // filtered delay output is stored in m_zLpf1 + pReverbData->m_zLpf1 = (EAS_PCM)SATURATE(nTemp1 + nTemp2); + + // ********** D1 output - end + + // ********** mixer and feedback - start + // sum is fedback to right input (R + L) + pReverbData->m_nRevOutFbkL = + (EAS_PCM)SATURATE((EAS_I32)pReverbData->m_zLpf1 + (EAS_I32)pReverbData->m_zLpf0); + + // difference is feedback to left input (R - L) + /*lint -e{685} lint complains that it can't saturate negative */ + pReverbData->m_nRevOutFbkR = + (EAS_PCM)SATURATE((EAS_I32)pReverbData->m_zLpf1 - (EAS_I32)pReverbData->m_zLpf0); + + // ********** mixer and feedback - end + + // ********** start early reflection generator, left + //psEarly = &(pReverbData->m_sEarlyL); + + nEarlyOut = 0; + + for (j=0; j < REVERB_MAX_NUM_REFLECTIONS; j++) + { + // fetch delay line out + //nAddr = CIRCULAR(nBase, psEarly->m_zDelay[j], REVERB_BUFFER_MASK); + nAddr = CIRCULAR(nBase, pReverbData->m_sEarlyL.m_zDelay[j], REVERB_BUFFER_MASK); + + nDelayOut = pReverbData->m_nDelayLine[nAddr]; + + // calculate reflection + //nTemp1 = MULT_EG1_EG1(nDelayOut, psEarly->m_nGain[j]); + nTemp1 = MULT_EG1_EG1(nDelayOut, pReverbData->m_sEarlyL.m_nGain[j]); + + nEarlyOut = SATURATE(nEarlyOut + nTemp1); + + } // end for (j=0; j < REVERB_MAX_NUM_REFLECTIONS; j++) + + // apply lowpass to early reflections + //nTemp1 = MULT_EG1_EG1(nEarlyOut, psEarly->m_nLpfFwd); + nTemp1 = MULT_EG1_EG1(nEarlyOut, pReverbData->m_sEarlyL.m_nLpfFwd); + + //nTemp2 = MULT_EG1_EG1(psEarly->m_zLpf, psEarly->m_nLpfFbk); + nTemp2 = MULT_EG1_EG1(pReverbData->m_sEarlyL.m_zLpf, pReverbData->m_sEarlyL.m_nLpfFbk); + + + // calculate filtered out and simultaneously update LPF state variable + // filtered output is stored in m_zLpf1 + //psEarly->m_zLpf = SATURATE(nTemp1 + nTemp2); + pReverbData->m_sEarlyL.m_zLpf = (EAS_PCM) SATURATE(nTemp1 + nTemp2); + + // combine filtered early and late reflections for output + //*pOutputBuffer++ = inL; + //tempValue = SATURATE(psEarly->m_zLpf + pReverbData->m_nRevOutFbkL); + tempValue = SATURATE((EAS_I32)pReverbData->m_sEarlyL.m_zLpf + (EAS_I32)pReverbData->m_nRevOutFbkL); + //scale reverb output by wet level + /*lint -e{701} use shift for performance */ + tempValue = MULT_EG1_EG1(tempValue, (pReverbData->m_nWet<<1)); + //sum with output buffer + tempValue += *pOutputBuffer; + *pOutputBuffer++ = (EAS_PCM)SATURATE(tempValue); + + // ********** end early reflection generator, left + + // ********** start early reflection generator, right + //psEarly = &(pReverbData->m_sEarlyR); + + nEarlyOut = 0; + + for (j=0; j < REVERB_MAX_NUM_REFLECTIONS; j++) + { + // fetch delay line out + nAddr = CIRCULAR(nBase, pReverbData->m_sEarlyR.m_zDelay[j], REVERB_BUFFER_MASK); + nDelayOut = pReverbData->m_nDelayLine[nAddr]; + + // calculate reflection + nTemp1 = MULT_EG1_EG1(nDelayOut, pReverbData->m_sEarlyR.m_nGain[j]); + + nEarlyOut = SATURATE(nEarlyOut + nTemp1); + + } // end for (j=0; j < REVERB_MAX_NUM_REFLECTIONS; j++) + + // apply lowpass to early reflections + nTemp1 = MULT_EG1_EG1(nEarlyOut, pReverbData->m_sEarlyR.m_nLpfFwd); + + nTemp2 = MULT_EG1_EG1(pReverbData->m_sEarlyR.m_zLpf, pReverbData->m_sEarlyR.m_nLpfFbk); + + // calculate filtered out and simultaneously update LPF state variable + // filtered output is stored in m_zLpf1 + pReverbData->m_sEarlyR.m_zLpf = (EAS_PCM)SATURATE(nTemp1 + nTemp2); + + // combine filtered early and late reflections for output + //*pOutputBuffer++ = inR; + tempValue = SATURATE((EAS_I32)pReverbData->m_sEarlyR.m_zLpf + (EAS_I32)pReverbData->m_nRevOutFbkR); + //scale reverb output by wet level + /*lint -e{701} use shift for performance */ + tempValue = MULT_EG1_EG1(tempValue, (pReverbData->m_nWet << 1)); + //sum with output buffer + tempValue = tempValue + *pOutputBuffer; + *pOutputBuffer++ = (EAS_PCM)SATURATE(tempValue); + + // ********** end early reflection generator, right + + // decrement base addr for next sample period + nBase--; + + pReverbData->m_nSin += pReverbData->m_nSinIncrement; + pReverbData->m_nCos += pReverbData->m_nCosIncrement; + + } // end for (i=0; i < nNumSamplesToAdd; i++) + + // store the most up to date version + pReverbData->m_nBaseIndex = nBase; + + return EAS_SUCCESS; +} /* end Reverb */ + + + +/*---------------------------------------------------------------------------- + * ReverbShutdown() + *---------------------------------------------------------------------------- + * Purpose: + * Initializes the Reverb effect. + * + * Inputs: + * pInstData - handle to instance data + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ReverbShutdown (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR pInstData) +{ + /* check Configuration Module for static memory allocation */ + if (!pEASData->staticMemoryModel) + EAS_HWFree(pEASData->hwInstData, pInstData); + return EAS_SUCCESS; +} /* end ReverbShutdown */ + +/*---------------------------------------------------------------------------- + * ReverbGetParam() + *---------------------------------------------------------------------------- + * Purpose: + * Get a Reverb parameter + * + * Inputs: + * pInstData - handle to instance data + * param - parameter index + * *pValue - pointer to variable to hold retrieved value + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ReverbGetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue) +{ + S_REVERB_OBJECT *p; + + p = (S_REVERB_OBJECT*) pInstData; + + switch (param) + { + case EAS_PARAM_REVERB_BYPASS: + *pValue = (EAS_I32) p->m_bBypass; + break; + case EAS_PARAM_REVERB_PRESET: + *pValue = (EAS_I8) p->m_nCurrentRoom; + break; + case EAS_PARAM_REVERB_WET: + *pValue = p->m_nWet; + break; + case EAS_PARAM_REVERB_DRY: + *pValue = p->m_nDry; + break; + default: + return EAS_ERROR_INVALID_PARAMETER; + } + return EAS_SUCCESS; +} /* end ReverbGetParam */ + + +/*---------------------------------------------------------------------------- + * ReverbSetParam() + *---------------------------------------------------------------------------- + * Purpose: + * Set a Reverb parameter + * + * Inputs: + * pInstData - handle to instance data + * param - parameter index + * *pValue - new paramter value + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ReverbSetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value) +{ + S_REVERB_OBJECT *p; + + p = (S_REVERB_OBJECT*) pInstData; + + switch (param) + { + case EAS_PARAM_REVERB_BYPASS: + p->m_bBypass = (EAS_BOOL) value; + break; + case EAS_PARAM_REVERB_PRESET: + if(value!=EAS_PARAM_REVERB_LARGE_HALL && value!=EAS_PARAM_REVERB_HALL && + value!=EAS_PARAM_REVERB_CHAMBER && value!=EAS_PARAM_REVERB_ROOM) + return EAS_ERROR_INVALID_PARAMETER; + p->m_nNextRoom = (EAS_I16)value; + break; + case EAS_PARAM_REVERB_WET: + if(value>EAS_REVERB_WET_MAX || valuem_nWet = (EAS_I16)value; + break; + case EAS_PARAM_REVERB_DRY: + if(value>EAS_REVERB_DRY_MAX || valuem_nDry = (EAS_I16)value; + break; + default: + return EAS_ERROR_INVALID_PARAMETER; + } + return EAS_SUCCESS; +} /* end ReverbSetParam */ + + +/*---------------------------------------------------------------------------- + * ReverbUpdateRoom + *---------------------------------------------------------------------------- + * Purpose: + * Update the room's preset parameters as required + * + * Inputs: + * + * Outputs: + * + * + * Side Effects: + * - reverb paramters (fbk, fwd, etc) will be changed + * - m_nCurrentRoom := m_nNextRoom + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ReverbUpdateRoom(S_REVERB_OBJECT *pReverbData) +{ + EAS_INT temp; + + S_REVERB_PRESET *pPreset = &pReverbData->m_sPreset.m_sPreset[pReverbData->m_nNextRoom]; + + pReverbData->m_nLpfFwd = pPreset->m_nLpfFwd; + pReverbData->m_nLpfFbk = pPreset->m_nLpfFbk; + + pReverbData->m_nEarly = pPreset->m_nEarly; + pReverbData->m_nWet = pPreset->m_nWet; + pReverbData->m_nDry = pPreset->m_nDry; + + + pReverbData->m_nMaxExcursion = pPreset->m_nMaxExcursion; + //stored as time based, convert to sample based + temp = pPreset->m_nXfadeInterval; + /*lint -e{702} shift for performance */ + temp = (temp * _OUTPUT_SAMPLE_RATE) >> 16; + pReverbData->m_nXfadeInterval = (EAS_U16) temp; + //gpsReverbObject->m_nXfadeInterval = pPreset->m_nXfadeInterval; + pReverbData->m_sAp0.m_nApGain = pPreset->m_nAp0_ApGain; + //stored as time based, convert to absolute sample value + temp = pPreset->m_nAp0_ApOut; + /*lint -e{702} shift for performance */ + temp = (temp * _OUTPUT_SAMPLE_RATE) >> 16; + pReverbData->m_sAp0.m_zApOut = (EAS_U16) (pReverbData->m_sAp0.m_zApIn + temp); + //gpsReverbObject->m_sAp0.m_zApOut = pPreset->m_nAp0_ApOut; + pReverbData->m_sAp1.m_nApGain = pPreset->m_nAp1_ApGain; + //stored as time based, convert to absolute sample value + temp = pPreset->m_nAp1_ApOut; + /*lint -e{702} shift for performance */ + temp = (temp * _OUTPUT_SAMPLE_RATE) >> 16; + pReverbData->m_sAp1.m_zApOut = (EAS_U16) (pReverbData->m_sAp1.m_zApIn + temp); + //gpsReverbObject->m_sAp1.m_zApOut = pPreset->m_nAp1_ApOut; + + pReverbData->m_nCurrentRoom = pReverbData->m_nNextRoom; + + return EAS_SUCCESS; + +} /* end ReverbUpdateRoom */ + + +/*---------------------------------------------------------------------------- + * ReverbReadInPresets() + *---------------------------------------------------------------------------- + * Purpose: sets global reverb preset bank to defaults + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ReverbReadInPresets(S_REVERB_OBJECT *pReverbData) +{ + + int preset = 0; + int defaultPreset = 0; + + //now init any remaining presets to defaults + for (defaultPreset = preset; defaultPreset < REVERB_MAX_ROOM_TYPE; defaultPreset++) + { + S_REVERB_PRESET *pPreset = &pReverbData->m_sPreset.m_sPreset[defaultPreset]; + if (defaultPreset == 0 || defaultPreset > REVERB_MAX_ROOM_TYPE-1) + { + pPreset->m_nLpfFbk = 8307; + pPreset->m_nLpfFwd = 14768; + pPreset->m_nEarly = 0; + pPreset->m_nWet = 27690; + pPreset->m_nDry = 32767; + pPreset->m_nEarlyL_LpfFbk = 3692; + pPreset->m_nEarlyL_LpfFwd = 29075; + pPreset->m_nEarlyL_Delay0 = 922; + pPreset->m_nEarlyL_Gain0 = 22152; + pPreset->m_nEarlyL_Delay1 = 1462; + pPreset->m_nEarlyL_Gain1 = 17537; + pPreset->m_nEarlyL_Delay2 = 0; + pPreset->m_nEarlyL_Gain2 = 14768; + pPreset->m_nEarlyL_Delay3 = 1221; + pPreset->m_nEarlyL_Gain3 = 14307; + pPreset->m_nEarlyL_Delay4 = 0; + pPreset->m_nEarlyL_Gain4 = 13384; + pPreset->m_nEarlyR_Delay0 = 502; + pPreset->m_nEarlyR_Gain0 = 20306; + pPreset->m_nEarlyR_Delay1 = 1762; + pPreset->m_nEarlyR_Gain1 = 17537; + pPreset->m_nEarlyR_Delay2 = 0; + pPreset->m_nEarlyR_Gain2 = 14768; + pPreset->m_nEarlyR_Delay3 = 0; + pPreset->m_nEarlyR_Gain3 = 16153; + pPreset->m_nEarlyR_Delay4 = 0; + pPreset->m_nEarlyR_Gain4 = 13384; + pPreset->m_nMaxExcursion = 127; + pPreset->m_nXfadeInterval = 6388; + pPreset->m_nAp0_ApGain = 15691; + pPreset->m_nAp0_ApOut = 711; + pPreset->m_nAp1_ApGain = 17999; + pPreset->m_nAp1_ApOut = 1113; + pPreset->m_rfu4 = 0; + pPreset->m_rfu5 = 0; + pPreset->m_rfu6 = 0; + pPreset->m_rfu7 = 0; + pPreset->m_rfu8 = 0; + pPreset->m_rfu9 = 0; + pPreset->m_rfu10 = 0; + } + else if (defaultPreset == 1) + { + pPreset->m_nLpfFbk = 6461; + pPreset->m_nLpfFwd = 14307; + pPreset->m_nEarly = 0; + pPreset->m_nWet = 27690; + pPreset->m_nDry = 32767; + pPreset->m_nEarlyL_LpfFbk = 3692; + pPreset->m_nEarlyL_LpfFwd = 29075; + pPreset->m_nEarlyL_Delay0 = 922; + pPreset->m_nEarlyL_Gain0 = 22152; + pPreset->m_nEarlyL_Delay1 = 1462; + pPreset->m_nEarlyL_Gain1 = 17537; + pPreset->m_nEarlyL_Delay2 = 0; + pPreset->m_nEarlyL_Gain2 = 14768; + pPreset->m_nEarlyL_Delay3 = 1221; + pPreset->m_nEarlyL_Gain3 = 14307; + pPreset->m_nEarlyL_Delay4 = 0; + pPreset->m_nEarlyL_Gain4 = 13384; + pPreset->m_nEarlyR_Delay0 = 502; + pPreset->m_nEarlyR_Gain0 = 20306; + pPreset->m_nEarlyR_Delay1 = 1762; + pPreset->m_nEarlyR_Gain1 = 17537; + pPreset->m_nEarlyR_Delay2 = 0; + pPreset->m_nEarlyR_Gain2 = 14768; + pPreset->m_nEarlyR_Delay3 = 0; + pPreset->m_nEarlyR_Gain3 = 16153; + pPreset->m_nEarlyR_Delay4 = 0; + pPreset->m_nEarlyR_Gain4 = 13384; + pPreset->m_nMaxExcursion = 127; + pPreset->m_nXfadeInterval = 6391; + pPreset->m_nAp0_ApGain = 15230; + pPreset->m_nAp0_ApOut = 708; + pPreset->m_nAp1_ApGain = 9692; + pPreset->m_nAp1_ApOut = 1113; + pPreset->m_rfu4 = 0; + pPreset->m_rfu5 = 0; + pPreset->m_rfu6 = 0; + pPreset->m_rfu7 = 0; + pPreset->m_rfu8 = 0; + pPreset->m_rfu9 = 0; + pPreset->m_rfu10 = 0; + } + else if (defaultPreset == 2) + { + pPreset->m_nLpfFbk = 5077; + pPreset->m_nLpfFwd = 12922; + pPreset->m_nEarly = 0; + pPreset->m_nWet = 24460; + pPreset->m_nDry = 32767; + pPreset->m_nEarlyL_LpfFbk = 3692; + pPreset->m_nEarlyL_LpfFwd = 29075; + pPreset->m_nEarlyL_Delay0 = 922; + pPreset->m_nEarlyL_Gain0 = 22152; + pPreset->m_nEarlyL_Delay1 = 1462; + pPreset->m_nEarlyL_Gain1 = 17537; + pPreset->m_nEarlyL_Delay2 = 0; + pPreset->m_nEarlyL_Gain2 = 14768; + pPreset->m_nEarlyL_Delay3 = 1221; + pPreset->m_nEarlyL_Gain3 = 14307; + pPreset->m_nEarlyL_Delay4 = 0; + pPreset->m_nEarlyL_Gain4 = 13384; + pPreset->m_nEarlyR_Delay0 = 502; + pPreset->m_nEarlyR_Gain0 = 20306; + pPreset->m_nEarlyR_Delay1 = 1762; + pPreset->m_nEarlyR_Gain1 = 17537; + pPreset->m_nEarlyR_Delay2 = 0; + pPreset->m_nEarlyR_Gain2 = 14768; + pPreset->m_nEarlyR_Delay3 = 0; + pPreset->m_nEarlyR_Gain3 = 16153; + pPreset->m_nEarlyR_Delay4 = 0; + pPreset->m_nEarlyR_Gain4 = 13384; + pPreset->m_nMaxExcursion = 127; + pPreset->m_nXfadeInterval = 6449; + pPreset->m_nAp0_ApGain = 15691; + pPreset->m_nAp0_ApOut = 774; + pPreset->m_nAp1_ApGain = 15691; + pPreset->m_nAp1_ApOut = 1113; + pPreset->m_rfu4 = 0; + pPreset->m_rfu5 = 0; + pPreset->m_rfu6 = 0; + pPreset->m_rfu7 = 0; + pPreset->m_rfu8 = 0; + pPreset->m_rfu9 = 0; + pPreset->m_rfu10 = 0; + } + else if (defaultPreset == 3) + { + pPreset->m_nLpfFbk = 5077; + pPreset->m_nLpfFwd = 11076; + pPreset->m_nEarly = 0; + pPreset->m_nWet = 23075; + pPreset->m_nDry = 32767; + pPreset->m_nEarlyL_LpfFbk = 3692; + pPreset->m_nEarlyL_LpfFwd = 29075; + pPreset->m_nEarlyL_Delay0 = 922; + pPreset->m_nEarlyL_Gain0 = 22152; + pPreset->m_nEarlyL_Delay1 = 1462; + pPreset->m_nEarlyL_Gain1 = 17537; + pPreset->m_nEarlyL_Delay2 = 0; + pPreset->m_nEarlyL_Gain2 = 14768; + pPreset->m_nEarlyL_Delay3 = 1221; + pPreset->m_nEarlyL_Gain3 = 14307; + pPreset->m_nEarlyL_Delay4 = 0; + pPreset->m_nEarlyL_Gain4 = 13384; + pPreset->m_nEarlyR_Delay0 = 502; + pPreset->m_nEarlyR_Gain0 = 20306; + pPreset->m_nEarlyR_Delay1 = 1762; + pPreset->m_nEarlyR_Gain1 = 17537; + pPreset->m_nEarlyR_Delay2 = 0; + pPreset->m_nEarlyR_Gain2 = 14768; + pPreset->m_nEarlyR_Delay3 = 0; + pPreset->m_nEarlyR_Gain3 = 16153; + pPreset->m_nEarlyR_Delay4 = 0; + pPreset->m_nEarlyR_Gain4 = 13384; + pPreset->m_nMaxExcursion = 127; + pPreset->m_nXfadeInterval = 6470; //6483; + pPreset->m_nAp0_ApGain = 14768; + pPreset->m_nAp0_ApOut = 792; + pPreset->m_nAp1_ApGain = 15783; + pPreset->m_nAp1_ApOut = 1113; + pPreset->m_rfu4 = 0; + pPreset->m_rfu5 = 0; + pPreset->m_rfu6 = 0; + pPreset->m_rfu7 = 0; + pPreset->m_rfu8 = 0; + pPreset->m_rfu9 = 0; + pPreset->m_rfu10 = 0; + + } + } + + return EAS_SUCCESS; +} diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_reverbdata.c b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_reverbdata.c new file mode 100755 index 0000000..db34b48 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_reverbdata.c @@ -0,0 +1,34 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_reverbdata.c + * + * Contents and purpose: + * Contains the static data allocation for the Reverb effect + * + * + * Copyright Sonic Network Inc. 2006 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 550 $ + * $Date: 2007-02-02 09:37:03 -0800 (Fri, 02 Feb 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_reverbdata.h" + +S_REVERB_OBJECT eas_ReverbData; + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_reverbdata.h b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_reverbdata.h new file mode 100755 index 0000000..926ea2e --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_reverbdata.h @@ -0,0 +1,486 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_reverbdata.h + * + * Contents and purpose: + * Contains the prototypes for the Reverb effect. + * + * + * Copyright Sonic Network Inc. 2006 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 499 $ + * $Date: 2006-12-11 16:07:20 -0800 (Mon, 11 Dec 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_REVERBDATA_H +#define _EAS_REVERBDATA_H + +#include "eas_types.h" +#include "eas_audioconst.h" + +/*------------------------------------ + * defines + *------------------------------------ +*/ + +/* +CIRCULAR() calculates the array index using modulo arithmetic. +The "trick" is that modulo arithmetic is simplified by masking +the effective address where the mask is (2^n)-1. This only works +if the buffer size is a power of two. +*/ +#define CIRCULAR(base,offset,size) (EAS_U32)( \ + ( \ + ((EAS_I32)(base)) + ((EAS_I32)(offset)) \ + ) \ + & size \ + ) + +/* reverb parameters are updated every 2^(REVERB_UPDATE_PERIOD_IN_BITS) samples */ +#if defined (_SAMPLE_RATE_8000) + +#define REVERB_UPDATE_PERIOD_IN_BITS 5 +#define REVERB_BUFFER_SIZE_IN_SAMPLES 2048 + +#elif defined (_SAMPLE_RATE_16000) + +#define REVERB_UPDATE_PERIOD_IN_BITS 6 +#define REVERB_BUFFER_SIZE_IN_SAMPLES 4096 + +#elif defined (_SAMPLE_RATE_22050) + +#define REVERB_UPDATE_PERIOD_IN_BITS 7 +#define REVERB_BUFFER_SIZE_IN_SAMPLES 4096 + +#elif defined (_SAMPLE_RATE_32000) + +#define REVERB_UPDATE_PERIOD_IN_BITS 7 +#define REVERB_BUFFER_SIZE_IN_SAMPLES 8192 + +#elif defined (_SAMPLE_RATE_44100) + +#define REVERB_UPDATE_PERIOD_IN_BITS 8 +#define REVERB_BUFFER_SIZE_IN_SAMPLES 8192 + +#elif defined (_SAMPLE_RATE_48000) + +#define REVERB_UPDATE_PERIOD_IN_BITS 8 +#define REVERB_BUFFER_SIZE_IN_SAMPLES 8192 + +#endif + +// Define a mask for circular addressing, so that array index +// can wraparound and stay in array boundary of 0, 1, ..., (buffer size -1) +// The buffer size MUST be a power of two +#define REVERB_BUFFER_MASK (REVERB_BUFFER_SIZE_IN_SAMPLES -1) + +#define REVERB_MAX_ROOM_TYPE 4 // any room numbers larger than this are invalid +#define REVERB_MAX_NUM_REFLECTIONS 5 // max num reflections per channel + +/* synth parameters are updated every SYNTH_UPDATE_PERIOD_IN_SAMPLES */ +#define REVERB_UPDATE_PERIOD_IN_SAMPLES (EAS_I32)(0x1L << REVERB_UPDATE_PERIOD_IN_BITS) + +/* +calculate the update counter by bitwise ANDING with this value to +generate a 2^n modulo value +*/ +#define REVERB_MODULO_UPDATE_PERIOD_IN_SAMPLES (EAS_I32)(REVERB_UPDATE_PERIOD_IN_SAMPLES -1) + +/* synth parameters are updated every SYNTH_UPDATE_PERIOD_IN_SECONDS seconds */ +#define REVERB_UPDATE_PERIOD_IN_SECONDS (REVERB_UPDATE_PERIOD_IN_SAMPLES / _OUTPUT_SAMPLE_RATE) + +// xfade parameters +#define REVERB_XFADE_PERIOD_IN_SECONDS (100.0 / 1000.0) // xfade once every this many seconds + +#define REVERB_XFADE_PERIOD_IN_SAMPLES (REVERB_XFADE_PERIOD_IN_SECONDS * _OUTPUT_SAMPLE_RATE) + +#define REVERB_XFADE_PHASE_INCREMENT (EAS_I16)(65536 / ((EAS_I16)REVERB_XFADE_PERIOD_IN_SAMPLES/(EAS_I16)REVERB_UPDATE_PERIOD_IN_SAMPLES)) + +/**********/ +/* the entire synth uses various flags in a bit field */ + +/* if flag is set, synth reset has been requested */ +#define REVERB_FLAG_RESET_IS_REQUESTED 0x01 /* bit 0 */ +#define MASK_REVERB_RESET_IS_REQUESTED 0x01 +#define MASK_REVERB_RESET_IS_NOT_REQUESTED (EAS_U32)(~MASK_REVERB_RESET_IS_REQUESTED) + +/* +by default, we always want to update ALL channel parameters +when we reset the synth (e.g., during GM ON) +*/ +#define DEFAULT_REVERB_FLAGS 0x0 + +/* coefficients for generating sin, cos */ +#define REVERB_PAN_G2 4294940151 /* -0.82842712474619 = 2 - 4/sqrt(2) */ +/* +EAS_I32 nPanG1 = +1.0 for sin +EAS_I32 nPanG1 = -1.0 for cos +*/ +#define REVERB_PAN_G0 23170 /* 0.707106781186547 = 1/sqrt(2) */ + +/*************************************************************/ +// define the input injection points +#define GUARD 5 // safety guard of this many samples + +#define MAX_AP_TIME (double) (20.0/1000.0) // delay time in milliseconds +#define MAX_DELAY_TIME (double) (65.0/1000.0) // delay time in milliseconds + +#define MAX_AP_SAMPLES (int)(((double) MAX_AP_TIME) * ((double) _OUTPUT_SAMPLE_RATE)) +#define MAX_DELAY_SAMPLES (int)(((double) MAX_DELAY_TIME) * ((double) _OUTPUT_SAMPLE_RATE)) + +#define AP0_IN 0 +#define AP1_IN (AP0_IN + MAX_AP_SAMPLES + GUARD) +#define DELAY0_IN (AP1_IN + MAX_AP_SAMPLES + GUARD) +#define DELAY1_IN (DELAY0_IN + MAX_DELAY_SAMPLES + GUARD) + +// Define the max offsets for the end points of each section +// i.e., we don't expect a given section's taps to go beyond +// the following limits +#define AP0_OUT (AP0_IN + MAX_AP_SAMPLES -1) +#define AP1_OUT (AP1_IN + MAX_AP_SAMPLES -1) +#define DELAY0_OUT (DELAY0_IN + MAX_DELAY_SAMPLES -1) +#define DELAY1_OUT (DELAY1_IN + MAX_DELAY_SAMPLES -1) + +#define REVERB_DEFAULT_ROOM_NUMBER 1 // default preset number +#define DEFAULT_AP0_LENGTH (int)(((double) (17.0/1000.0)) * ((double) _OUTPUT_SAMPLE_RATE)) +#define DEFAULT_AP0_GAIN 19400 +#define DEFAULT_AP1_LENGTH (int)(((double) (16.5/1000.0)) * ((double) _OUTPUT_SAMPLE_RATE)) +#define DEFAULT_AP1_GAIN -19400 + +#define REVERB_DEFAULT_WET 32767 +#define REVERB_DEFAULT_DRY 0 + +#define EAS_REVERB_WET_MAX 32767 +#define EAS_REVERB_WET_MIN 0 +#define EAS_REVERB_DRY_MAX 32767 +#define EAS_REVERB_DRY_MIN 0 + +/* parameters for each allpass */ +typedef struct +{ + EAS_U16 m_zApOut; // delay offset for ap out + + EAS_I16 m_nApGain; // gain for ap + + EAS_U16 m_zApIn; // delay offset for ap in + +} S_ALLPASS_OBJECT; + + +/* parameters for each allpass */ +typedef struct +{ + EAS_PCM m_zLpf; // actual state variable, not a length + + EAS_I16 m_nLpfFwd; // lpf forward gain + + EAS_I16 m_nLpfFbk; // lpf feedback gain + + EAS_U16 m_zDelay[REVERB_MAX_NUM_REFLECTIONS]; // delay offset for ap out + + EAS_I16 m_nGain[REVERB_MAX_NUM_REFLECTIONS]; // gain for ap + +} S_EARLY_REFLECTION_OBJECT; + +//demo +typedef struct +{ + EAS_I16 m_nLpfFbk; + EAS_I16 m_nLpfFwd; + + EAS_I16 m_nEarly; + EAS_I16 m_nWet; + EAS_I16 m_nDry; + + EAS_I16 m_nEarlyL_LpfFbk; + EAS_I16 m_nEarlyL_LpfFwd; + + EAS_I16 m_nEarlyL_Delay0; //8 + EAS_I16 m_nEarlyL_Gain0; + EAS_I16 m_nEarlyL_Delay1; + EAS_I16 m_nEarlyL_Gain1; + EAS_I16 m_nEarlyL_Delay2; + EAS_I16 m_nEarlyL_Gain2; + EAS_I16 m_nEarlyL_Delay3; + EAS_I16 m_nEarlyL_Gain3; + EAS_I16 m_nEarlyL_Delay4; + EAS_I16 m_nEarlyL_Gain4; + + EAS_I16 m_nEarlyR_Delay0; //18 + EAS_I16 m_nEarlyR_Gain0; + EAS_I16 m_nEarlyR_Delay1; + EAS_I16 m_nEarlyR_Gain1; + EAS_I16 m_nEarlyR_Delay2; + EAS_I16 m_nEarlyR_Gain2; + EAS_I16 m_nEarlyR_Delay3; + EAS_I16 m_nEarlyR_Gain3; + EAS_I16 m_nEarlyR_Delay4; + EAS_I16 m_nEarlyR_Gain4; + + EAS_U16 m_nMaxExcursion; //28 + EAS_I16 m_nXfadeInterval; + + EAS_I16 m_nAp0_ApGain; //30 + EAS_I16 m_nAp0_ApOut; + EAS_I16 m_nAp1_ApGain; + EAS_I16 m_nAp1_ApOut; + + EAS_I16 m_rfu4; + EAS_I16 m_rfu5; + EAS_I16 m_rfu6; + EAS_I16 m_rfu7; + EAS_I16 m_rfu8; + EAS_I16 m_rfu9; + EAS_I16 m_rfu10; //43 + +} S_REVERB_PRESET; + +typedef struct +{ + S_REVERB_PRESET m_sPreset[REVERB_MAX_ROOM_TYPE]; //array of presets + +} S_REVERB_PRESET_BANK; + +/* parameters for each reverb */ +typedef struct +{ + /* controls entire reverb playback volume */ + /* to conserve memory, use the MSB and ignore the LSB */ + EAS_U8 m_nMasterVolume; + + /* update counter keeps track of when synth params need updating */ + /* only needs to be as large as REVERB_UPDATE_PERIOD_IN_SAMPLES */ + EAS_I16 m_nUpdateCounter; + + EAS_U16 m_nMinSamplesToAdd; /* ComputeReverb() generates this many samples */ + + EAS_U8 m_nFlags; /* misc flags/bit fields */ + + EAS_PCM *m_pOutputBuffer; + EAS_PCM *m_pInputBuffer; + + EAS_U16 m_nNumSamplesInOutputBuffer; + EAS_U16 m_nNumSamplesInInputBuffer; + + EAS_U16 m_nNumInputSamplesRead; // if m_nNumInputSamplesRead >= NumSamplesInInputBuffer + // then get a new input buffer + EAS_PCM *m_pNextInputSample; + + EAS_U16 m_nBaseIndex; // base index for circular buffer + + // reverb delay line offsets, allpass parameters, etc: + + EAS_PCM m_nRevOutFbkR; // combine feedback reverb right out with dry left in + + S_ALLPASS_OBJECT m_sAp0; // allpass 0 (left channel) + + EAS_U16 m_zD0In; // delay offset for delay line D0 in + + EAS_PCM m_nRevOutFbkL; // combine feedback reverb left out with dry right in + + S_ALLPASS_OBJECT m_sAp1; // allpass 1 (right channel) + + EAS_U16 m_zD1In; // delay offset for delay line D1 in + + // delay output taps, notice criss cross order + EAS_U16 m_zD0Self; // self feeds forward d0 --> d0 + + EAS_U16 m_zD1Cross; // cross feeds across d1 --> d0 + + EAS_PCM m_zLpf0; // actual state variable, not a length + + EAS_U16 m_zD1Self; // self feeds forward d1 --> d1 + + EAS_U16 m_zD0Cross; // cross feeds across d0 --> d1 + + EAS_PCM m_zLpf1; // actual state variable, not a length + + EAS_I16 m_nSin; // gain for self taps + + EAS_I16 m_nCos; // gain for cross taps + + EAS_I16 m_nSinIncrement; // increment for gain + + EAS_I16 m_nCosIncrement; // increment for gain + + EAS_I16 m_nLpfFwd; // lpf forward gain (includes scaling for mixer) + + EAS_I16 m_nLpfFbk; // lpf feedback gain + + EAS_U16 m_nXfadeInterval; // update/xfade after this many samples + + EAS_U16 m_nXfadeCounter; // keep track of when to xfade + + EAS_I16 m_nPhase; // -1 <= m_nPhase < 1 + // but during sin,cos calculations + // use m_nPhase/2 + + EAS_I16 m_nPhaseIncrement; // add this to m_nPhase each frame + + EAS_I16 m_nNoise; // random noise sample + + EAS_U16 m_nMaxExcursion; // the taps can excurse +/- this amount + + EAS_BOOL m_bUseNoise; // if EAS_TRUE, use noise as input signal + + EAS_BOOL m_bBypass; // if EAS_TRUE, then bypass reverb and copy input to output + + EAS_I16 m_nCurrentRoom; // preset number for current room + + EAS_I16 m_nNextRoom; // preset number for next room + + EAS_I16 m_nWet; // gain for wet (processed) signal + + EAS_I16 m_nDry; // gain for dry (unprocessed) signal + + EAS_I16 m_nEarly; // gain for early (widen) signal + + S_EARLY_REFLECTION_OBJECT m_sEarlyL; // left channel early reflections + S_EARLY_REFLECTION_OBJECT m_sEarlyR; // right channel early reflections + + EAS_PCM m_nDelayLine[REVERB_BUFFER_SIZE_IN_SAMPLES]; // one large delay line for all reverb elements + + S_REVERB_PRESET pPreset; + + S_REVERB_PRESET_BANK m_sPreset; + + //EAS_I8 preset; + +} S_REVERB_OBJECT; + + +/*------------------------------------ + * prototypes + *------------------------------------ +*/ + +/*---------------------------------------------------------------------------- + * ReverbUpdateXfade + *---------------------------------------------------------------------------- + * Purpose: + * Update the xfade parameters as required + * + * Inputs: + * nNumSamplesToAdd - number of samples to write to buffer + * + * Outputs: + * + * + * Side Effects: + * - xfade parameters will be changed + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ReverbUpdateXfade(S_REVERB_OBJECT* pReverbData, EAS_INT nNumSamplesToAdd); + +/*---------------------------------------------------------------------------- + * ReverbCalculateNoise + *---------------------------------------------------------------------------- + * Purpose: + * Calculate a noise sample and limit its value + * + * Inputs: + * nMaxExcursion - noise value is limited to this value + * pnNoise - return new noise sample in this (not limited) + * + * Outputs: + * new limited noise value + * + * Side Effects: + * - *pnNoise noise value is updated + * + *---------------------------------------------------------------------------- +*/ +static EAS_U16 ReverbCalculateNoise(EAS_U16 nMaxExcursion, EAS_I16 *pnNoise); + +/*---------------------------------------------------------------------------- + * ReverbCalculateSinCos + *---------------------------------------------------------------------------- + * Purpose: + * Calculate a new sin and cosine value based on the given phase + * + * Inputs: + * nPhase - phase angle + * pnSin - input old value, output new value + * pnCos - input old value, output new value + * + * Outputs: + * + * Side Effects: + * - *pnSin, *pnCos are updated + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ReverbCalculateSinCos(EAS_I16 nPhase, EAS_I16 *pnSin, EAS_I16 *pnCos); + +/*---------------------------------------------------------------------------- + * Reverb + *---------------------------------------------------------------------------- + * Purpose: + * apply reverb to the given signal + * + * Inputs: + * nNu + * pnSin - input old value, output new value + * pnCos - input old value, output new value + * + * Outputs: + * number of samples actually reverberated + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT Reverb(S_REVERB_OBJECT* pReverbData, EAS_INT nNumSamplesToAdd, EAS_PCM *pOutputBuffer, EAS_PCM *pInputBuffer); + +/*---------------------------------------------------------------------------- + * ReverbReadInPresets() + *---------------------------------------------------------------------------- + * Purpose: sets global reverb preset bank to defaults + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ReverbReadInPresets(S_REVERB_OBJECT* pReverbData); + + +/*---------------------------------------------------------------------------- + * ReverbUpdateRoom + *---------------------------------------------------------------------------- + * Purpose: + * Update the room's preset parameters as required + * + * Inputs: + * + * Outputs: + * + * + * Side Effects: + * - reverb paramters (fbk, fwd, etc) will be changed + * - m_nCurrentRoom := m_nNextRoom + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ReverbUpdateRoom(S_REVERB_OBJECT* pReverbData); + +#endif /* #ifndef _EAS_REVERBDATA_H */ + + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_rtttl.c b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_rtttl.c new file mode 100755 index 0000000..d8253fb --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_rtttl.c @@ -0,0 +1,1197 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_rtttl.c + * + * Contents and purpose: + * RTTTL parser + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 795 $ + * $Date: 2007-08-01 00:14:45 -0700 (Wed, 01 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_data.h" +#include "eas_miditypes.h" +#include "eas_parser.h" +#include "eas_report.h" +#include "eas_host.h" +#include "eas_midi.h" +#include "eas_config.h" +#include "eas_vm_protos.h" +#include "eas_rtttldata.h" +#include "eas_ctype.h" + +/* increase gain for mono ringtones */ +#define RTTTL_GAIN_OFFSET 8 + +/* maximum title length including colon separator */ +#define RTTTL_MAX_TITLE_LEN 32 +#define RTTTL_INFINITE_LOOP 15 + +/* length of 32nd note in 1/256ths of a msec for 63 BPM tempo */ +#define DEFAULT_TICK_CONV 30476 +#define TICK_CONVERT 1920000 + +/* default channel and program for RTTTL playback */ +#define RTTTL_CHANNEL 0 +#define RTTTL_PROGRAM 80 +#define RTTTL_VELOCITY 127 + +/* note used for rest */ +#define RTTTL_REST 1 + +/* multiplier for fixed point triplet conversion */ +#define TRIPLET_MULTIPLIER 683 +#define TRIPLET_SHIFT 10 + +/* local prototypes */ +static EAS_RESULT RTTTL_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset); +static EAS_RESULT RTTTL_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT RTTTL_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime); +static EAS_RESULT RTTTL_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode); +static EAS_RESULT RTTTL_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_STATE *pState); +static EAS_RESULT RTTTL_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT RTTTL_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT RTTTL_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT RTTTL_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT RTTTL_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value); +static EAS_RESULT RTTTL_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue); +static EAS_RESULT RTTTL_GetStyle (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData); +static EAS_RESULT RTTTL_GetDuration (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData, EAS_I8 *pDuration); +static EAS_RESULT RTTTL_GetOctave (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData, EAS_U8 *pOctave); +static EAS_RESULT RTTTL_GetTempo (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData); +static EAS_RESULT RTTTL_GetNumber (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData, EAS_I32 *pValue); +static EAS_RESULT RTTTL_ParseHeader (S_EAS_DATA *pEASData, S_RTTTL_DATA* pData, EAS_BOOL metaData); +static EAS_RESULT RTTTL_GetNextChar (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData, EAS_I8 *pValue); +static EAS_RESULT RTTTL_PeekNextChar (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData, EAS_I8 *pValue); + +/* inline functions */ +EAS_INLINE void RTTTL_PutBackChar (S_RTTTL_DATA *pData, EAS_I8 value) { pData->dataByte = value; } + + +/* lookup table for note values */ +static const EAS_U8 noteTable[] = { 21, 23, 12, 14, 16, 17, 19, 23 }; + +/*---------------------------------------------------------------------------- + * + * EAS_RTTTL_Parser + * + * This structure contains the functional interface for the iMelody parser + *---------------------------------------------------------------------------- +*/ +const S_FILE_PARSER_INTERFACE EAS_RTTTL_Parser = +{ + RTTTL_CheckFileType, + RTTTL_Prepare, + RTTTL_Time, + RTTTL_Event, + RTTTL_State, + RTTTL_Close, + RTTTL_Reset, + RTTTL_Pause, + RTTTL_Resume, + NULL, + RTTTL_SetData, + RTTTL_GetData, + NULL +}; + +/*---------------------------------------------------------------------------- + * RTTTL_CheckFileType() + *---------------------------------------------------------------------------- + * Purpose: + * Check the file type to see if we can parse it + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset) +{ + S_RTTTL_DATA data; + S_RTTTL_DATA *pData; + + /* see if we can parse the header */ + data.fileHandle = fileHandle; + data.fileOffset = offset; + *ppHandle= NULL; + if (RTTTL_ParseHeader (pEASData, &data, EAS_FALSE) == EAS_SUCCESS) + { + + /* check for static memory allocation */ + if (pEASData->staticMemoryModel) + pData = EAS_CMEnumData(EAS_CM_RTTTL_DATA); + else + pData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_RTTTL_DATA)); + if (!pData) + return EAS_ERROR_MALLOC_FAILED; + EAS_HWMemSet(pData, 0, sizeof(S_RTTTL_DATA)); + + /* return a pointer to the instance data */ + pData->fileHandle = fileHandle; + pData->fileOffset = offset; + pData->state = EAS_STATE_OPEN; + *ppHandle = pData; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_Prepare() + *---------------------------------------------------------------------------- + * Purpose: + * Prepare to parse the file. Allocates instance data (or uses static allocation for + * static memory model). + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_RTTTL_DATA* pData; + EAS_RESULT result; + + /* check for valid state */ + pData = (S_RTTTL_DATA*) pInstData; + if (pData->state != EAS_STATE_OPEN) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + /* instantiate a synthesizer */ + if ((result = VMInitMIDI(pEASData, &pData->pSynth)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitMIDI returned %d\n", result); */ } + return result; + } + + pData->state = EAS_STATE_ERROR; + if ((result = RTTTL_ParseHeader (pEASData, pData, (EAS_BOOL) (pData->metadata.callback != NULL))) != EAS_SUCCESS) + { + /* if using dynamic memory, free it */ + if (!pEASData->staticMemoryModel) + EAS_HWFree(pEASData->hwInstData, pData); + return result; + } + + pData->state = EAS_STATE_READY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_Time() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the time of the next event in msecs + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * pTime - pointer to variable to hold time of next event (in msecs) + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +static EAS_RESULT RTTTL_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime) +{ + S_RTTTL_DATA *pData; + + pData = (S_RTTTL_DATA*) pInstData; + + /* return time in milliseconds */ + /*lint -e{704} use shift instead of division */ + *pTime = pData->time >> 8; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_Event() + *---------------------------------------------------------------------------- + * Purpose: + * Parse the next event in the file + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode) +{ + S_RTTTL_DATA* pData; + EAS_RESULT result; + EAS_I32 ticks; + EAS_I32 temp; + EAS_I8 c; + EAS_U8 note; + EAS_U8 octave; + + pData = (S_RTTTL_DATA*) pInstData; + if (pData->state >= EAS_STATE_OPEN) + return EAS_SUCCESS; + + /* initialize MIDI channel when the track starts playing */ + if (pData->time == 0) + { + /* set program to square lead */ + VMProgramChange(pEASData->pVoiceMgr, pData->pSynth, RTTTL_CHANNEL, RTTTL_PROGRAM); + + /* set channel volume to max */ + VMControlChange(pEASData->pVoiceMgr, pData->pSynth, RTTTL_CHANNEL, 7, 127); + } + + /* check for end of note */ + if (pData->note) + { + /* stop the note */ + VMStopNote(pEASData->pVoiceMgr, pData->pSynth, RTTTL_CHANNEL, pData->note, 0); + pData->note = 0; + + /* check for rest between notes */ + if (pData->restTicks) + { + pData->time += pData->restTicks; + pData->restTicks = 0; + return EAS_SUCCESS; + } + } + + /* parse the next event */ + octave = pData->octave; + note = 0; + ticks = pData->duration * pData->tick; + for (;;) + { + + /* get next character */ + if ((result = RTTTL_GetNextChar(pEASData->hwInstData, pData, &c)) != EAS_SUCCESS) + { + if (result != EAS_EOF) + return result; + + /* end of file, if no notes to process, check for looping */ + if (!note) + { + /* if no loop set state to stopping */ + if (pData->repeatCount == 0) + { + pData->state = EAS_STATE_STOPPING; + VMReleaseAllVoices(pEASData->pVoiceMgr, pData->pSynth); + return EAS_SUCCESS; + } + + /* decrement loop count */ + if (pData->repeatCount != RTTTL_INFINITE_LOOP) + pData->repeatCount--; + + /* if locating, ignore infinite loops */ + else if (parserMode != eParserModePlay) + { + pData->state = EAS_STATE_STOPPING; + VMReleaseAllVoices(pEASData->pVoiceMgr, pData->pSynth); + return EAS_SUCCESS; + } + + /* loop back to start of notes */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pData->fileHandle, pData->repeatOffset)) != EAS_SUCCESS) + return result; + continue; + } + + /* still have a note to process */ + else + c = ','; + } + + /* bpm */ + if (c == 'b') + { + /* peek at next character */ + if ((result = RTTTL_PeekNextChar(pEASData->hwInstData, pData, &c)) != EAS_SUCCESS) + return result; + + /* if a number, must be octave or tempo */ + if (IsDigit(c)) + { + if ((result = RTTTL_GetNumber(pEASData->hwInstData, pData, &temp)) != EAS_SUCCESS) + return result; + + /* check for octave first */ + if ((temp >= 4) && (temp <= 7)) + { + octave = (EAS_U8) temp; + } + + /* check for tempo */ + else if ((temp >= 25) && (temp <= 900)) + { + pData->tick = TICK_CONVERT / (EAS_U32) temp; + } + + /* don't know what it was */ + else + return EAS_ERROR_FILE_FORMAT; + } + + /* must be a note */ + else + { + note = noteTable[1]; + } + } + + /* octave */ + else if (c == 'o') + { + if ((result = RTTTL_GetOctave(pEASData->hwInstData, pData, &pData->octave)) != EAS_SUCCESS) + return result; + } + + /* style */ + else if (c == 's') + { + if ((result = RTTTL_GetStyle(pEASData->hwInstData, pData)) != EAS_SUCCESS) + return result; + } + + /* duration or octave */ + else if (IsDigit(c)) + { + RTTTL_PutBackChar(pData, c); + + /* duration comes before note */ + if (!note) + { + if ((result = RTTTL_GetDuration(pEASData->hwInstData, pData, &c)) != EAS_SUCCESS) + return result; + ticks = c * pData->tick; + } + + /* octave comes after note */ + else + { + if ((result = RTTTL_GetOctave(pEASData->hwInstData, pData, &octave)) != EAS_SUCCESS) + return result; + } + } + + /* note or rest */ + else if ((c >= 'a') && (c <= 'h')) + { + note = noteTable[c - 'a']; + } + + else if (c == 'p') + { + note = RTTTL_REST; + } + + /* dotted note */ + else if (c == '.') + { + /*lint -e{704} shift for performance */ + ticks += ticks >> 1; + } + + /* accidental */ + else if (c == '#') + { + if (note) + note++; + } + + /* end of event */ + else if ((c == ',') && note) + { + + /* handle note events */ + if (note != RTTTL_REST) + { + + /* save note and start it */ + pData->note = note + octave; + if (parserMode == eParserModePlay) + VMStartNote(pEASData->pVoiceMgr, pData->pSynth, RTTTL_CHANNEL, pData->note, RTTTL_VELOCITY); + + /* determine note length */ + switch (pData->style) + { + /* natural */ + case 'n': + /*lint -e{704} shift for performance */ + pData->restTicks = ticks >> 4; + break; + /* continuous */ + + case 'c': + pData->restTicks = 0; + break; + + /* staccato */ + case 's': + /*lint -e{704} shift for performance */ + pData->restTicks = ticks >> 1; + break; + + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "RTTTL_Event: Unexpected style type %c\n", pData->style); */ } + break; + } + + /* next event is at end of this note */ + pData->time += ticks - pData->restTicks; + } + + /* rest */ + else + pData->time += ticks; + + /* event found, return to caller */ + break; + } + } + + pData->state = EAS_STATE_PLAY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_State() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current state of the stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * pState - pointer to variable to store state + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +static EAS_RESULT RTTTL_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pState) +{ + S_RTTTL_DATA* pData; + + /* establish pointer to instance data */ + pData = (S_RTTTL_DATA*) pInstData; + + /* if stopping, check to see if synth voices are active */ + if (pData->state == EAS_STATE_STOPPING) + { + if (VMActiveVoices(pData->pSynth) == 0) + pData->state = EAS_STATE_STOPPED; + } + + if (pData->state == EAS_STATE_PAUSING) + { + if (VMActiveVoices(pData->pSynth) == 0) + pData->state = EAS_STATE_PAUSED; + } + + /* return current state */ + *pState = pData->state; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_Close() + *---------------------------------------------------------------------------- + * Purpose: + * Close the file and clean up + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_RTTTL_DATA* pData; + EAS_RESULT result; + + pData = (S_RTTTL_DATA*) pInstData; + + /* close the file */ + if ((result = EAS_HWCloseFile(pEASData->hwInstData, pData->fileHandle)) != EAS_SUCCESS) + return result; + + /* free the synth */ + if (pData->pSynth != NULL) + VMMIDIShutdown(pEASData, pData->pSynth); + + /* if using dynamic memory, free it */ + if (!pEASData->staticMemoryModel) + EAS_HWFree(pEASData->hwInstData, pData); + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_Reset() + *---------------------------------------------------------------------------- + * Purpose: + * Reset the sequencer. Used for locating backwards in the file. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_RTTTL_DATA* pData; + EAS_RESULT result; + + pData = (S_RTTTL_DATA*) pInstData; + + /* reset the synth */ + VMReset(pEASData->pVoiceMgr, pData->pSynth, EAS_TRUE); + + /* reset time to zero */ + pData->time = 0; + pData->note = 0; + + /* reset file position and re-parse header */ + pData->state = EAS_STATE_ERROR; + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pData->fileHandle, pData->fileOffset)) != EAS_SUCCESS) + return result; + if ((result = RTTTL_ParseHeader (pEASData, pData, EAS_TRUE)) != EAS_SUCCESS) + return result; + + pData->state = EAS_STATE_READY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_Pause() + *---------------------------------------------------------------------------- + * Purpose: + * Pauses the sequencer. Mutes all voices and sets state to pause. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_RTTTL_DATA *pData; + + /* can't pause a stopped stream */ + pData = (S_RTTTL_DATA*) pInstData; + if (pData->state == EAS_STATE_STOPPED) + return EAS_ERROR_ALREADY_STOPPED; + + /* mute the synthesizer */ + VMMuteAllVoices(pEASData->pVoiceMgr, pData->pSynth); + pData->state = EAS_STATE_PAUSING; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_Resume() + *---------------------------------------------------------------------------- + * Purpose: + * Resume playing after a pause, sets state back to playing. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +static EAS_RESULT RTTTL_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_RTTTL_DATA *pData; + + /* can't resume a stopped stream */ + pData = (S_RTTTL_DATA*) pInstData; + if (pData->state == EAS_STATE_STOPPED) + return EAS_ERROR_ALREADY_STOPPED; + + /* nothing to do but resume playback */ + pData->state = EAS_STATE_PLAY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_SetData() + *---------------------------------------------------------------------------- + * Purpose: + * Return file type + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +static EAS_RESULT RTTTL_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value) +{ + S_RTTTL_DATA *pData; + + pData = (S_RTTTL_DATA *) pInstData; + switch (param) + { + + /* set metadata callback */ + case PARSER_DATA_METADATA_CB: + EAS_HWMemCpy(&pData->metadata, (void*) value, sizeof(S_METADATA_CB)); + break; + + default: + return EAS_ERROR_INVALID_PARAMETER; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_GetData() + *---------------------------------------------------------------------------- + * Purpose: + * Return file type + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +static EAS_RESULT RTTTL_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue) +{ + S_RTTTL_DATA *pData; + + pData = (S_RTTTL_DATA *) pInstData; + switch (param) + { + /* return file type as RTTTL */ + case PARSER_DATA_FILE_TYPE: + *pValue = EAS_FILE_RTTTL; + break; + +#if 0 + /* set transposition */ + case PARSER_DATA_TRANSPOSITION: + *pValue = pData->transposition; + break; +#endif + + case PARSER_DATA_SYNTH_HANDLE: + *pValue = (EAS_I32) pData->pSynth; + break; + + case PARSER_DATA_GAIN_OFFSET: + *pValue = RTTTL_GAIN_OFFSET; + break; + + default: + return EAS_ERROR_INVALID_PARAMETER; + } + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_GetStyle() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_GetStyle (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData) +{ + EAS_RESULT result; + EAS_I8 style; + + /* get style */ + if ((result = RTTTL_GetNextChar(hwInstData, pData, &style)) != EAS_SUCCESS) + return result; + + if ((style != 's') && (style != 'n') && (style != 'c')) + return EAS_ERROR_FILE_FORMAT; + + pData->style = style; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_GetDuration() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_GetDuration (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData, EAS_I8 *pDuration) +{ + EAS_RESULT result; + EAS_I32 duration; + EAS_I8 temp; + + /* get the duration */ + if ((result = RTTTL_GetNumber(hwInstData, pData, &duration)) != EAS_SUCCESS) + return result; + + if ((duration != 1) && (duration != 2) && (duration != 4) && (duration != 8) && (duration != 16) && (duration != 32)) + return EAS_ERROR_FILE_FORMAT; + + temp = 64; + while (duration) + { + /*lint -e{704} shift for performance */ + duration = duration >> 1; + /*lint -e{702} use shift for performance */ + temp = temp >> 1; + } + + *pDuration = temp; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_GetOctave() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_GetOctave (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData, EAS_U8 *pOctave) +{ + EAS_RESULT result; + EAS_I32 octave; + + /* get the tempo */ + if ((result = RTTTL_GetNumber(hwInstData, pData, &octave)) != EAS_SUCCESS) + return result; + + if ((octave < 4) || (octave > 7)) + return EAS_ERROR_FILE_FORMAT; + + *pOctave = (EAS_U8) (octave * 12); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_GetTempo() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_GetTempo (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData) +{ + EAS_RESULT result; + EAS_I32 tempo; + + /* get the tempo */ + if ((result = RTTTL_GetNumber(hwInstData, pData, &tempo)) != EAS_SUCCESS) + return result; + + if ((tempo < 25) || (tempo > 900)) + return EAS_ERROR_FILE_FORMAT; + + pData->tick = TICK_CONVERT / (EAS_U32) tempo; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_GetNumber() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_GetNumber (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData, EAS_I32 *pValue) +{ + EAS_RESULT result; + EAS_INT temp; + EAS_I8 c; + + *pValue = -1; + temp = 0; + for (;;) + { + if ((result = RTTTL_PeekNextChar(hwInstData, pData, &c)) != EAS_SUCCESS) + { + if ((result == EAS_EOF) && (*pValue != -1)) + return EAS_SUCCESS; + return result; + } + + if (IsDigit(c)) + { + pData->dataByte = 0; + temp = temp * 10 + c - '0'; + *pValue = temp; + } + else + return EAS_SUCCESS; + } +} + +/*---------------------------------------------------------------------------- + * RTTTL_ParseHeader() + *---------------------------------------------------------------------------- + * Purpose: + * Prepare to parse the file. Allocates instance data (or uses static allocation for + * static memory model). + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_ParseHeader (S_EAS_DATA *pEASData, S_RTTTL_DATA* pData, EAS_BOOL metaData) +{ + EAS_RESULT result; + EAS_I32 i; + EAS_I8 temp; + EAS_I8 control; + + /* initialize some defaults */ + pData->time = 0; + pData->tick = DEFAULT_TICK_CONV; + pData->note = 0; + pData->duration = 4; + pData ->restTicks = 0; + pData->octave = 60; + pData->repeatOffset = -1; + pData->repeatCount = 0; + pData->style = 'n'; + pData->dataByte = 0; + + metaData = metaData && (pData->metadata.buffer != NULL) && (pData->metadata.callback != NULL); + + /* seek to start of data */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pData->fileHandle, pData->fileOffset)) != EAS_SUCCESS) + return result; + + /* zero the metadata buffer */ + if (metaData) + EAS_HWMemSet(pData->metadata.buffer, 0, pData->metadata.bufferSize); + + /* read the title */ + for (i = 0; i < RTTTL_MAX_TITLE_LEN; i++) + { + if ((result = EAS_HWGetByte(pEASData->hwInstData, pData->fileHandle, &temp)) != EAS_SUCCESS) + return result; + + if (temp == ':') + break; + + /* pass along metadata */ + if (metaData) + { + if (i < (pData->metadata.bufferSize- 1)) + pData->metadata.buffer[i] = (char) temp; + } + } + + /* check for error in title */ + if (i == RTTTL_MAX_TITLE_LEN) + return EAS_ERROR_FILE_FORMAT; + + /* pass along metadata */ + if (metaData) + (*pData->metadata.callback)(EAS_METADATA_TITLE, pData->metadata.buffer, pData->metadata.pUserData); + + /* control fields */ + for (;;) + { + + /* get control type */ + if ((result = RTTTL_GetNextChar(pEASData->hwInstData, pData, &control)) != EAS_SUCCESS) + return result; + + /* next char should be equal sign */ + if ((result = RTTTL_GetNextChar(pEASData->hwInstData, pData, &temp)) != EAS_SUCCESS) + return result; + if (temp != '=') + return EAS_ERROR_FILE_FORMAT; + + /* get the control value */ + switch (control) + { + + /* bpm */ + case 'b': + if ((result = RTTTL_GetTempo(pEASData->hwInstData, pData)) != EAS_SUCCESS) + return result; + break; + + /* duration */ + case 'd': + if ((result = RTTTL_GetDuration(pEASData->hwInstData, pData, &temp)) != EAS_SUCCESS) + return result; + pData->duration = temp; + break; + + /* loop */ + case 'l': + if ((result = RTTTL_GetNumber(pEASData->hwInstData, pData, &i)) != EAS_SUCCESS) + return result; + if ((i < 0) || (i > 15)) + return EAS_ERROR_FILE_FORMAT; + pData->repeatCount = (EAS_U8) i; + break; + + /* octave */ + case 'o': + if ((result = RTTTL_GetOctave(pEASData->hwInstData, pData, &pData->octave)) != EAS_SUCCESS) + return result; + break; + + /* get style */ + case 's': + if ((result = RTTTL_GetStyle(pEASData->hwInstData, pData)) != EAS_SUCCESS) + return result; + break; + + /* unrecognized control */ + default: + return EAS_ERROR_FILE_FORMAT; + } + + /* next character should be comma or colon */ + if ((result = RTTTL_GetNextChar(pEASData->hwInstData, pData, &temp)) != EAS_SUCCESS) + return result; + + /* check for end of control field */ + if (temp == ':') + break; + + /* must be a comma */ + if (temp != ',') + return EAS_ERROR_FILE_FORMAT; + } + + /* should be at the start of the music block */ + if ((result = EAS_HWFilePos(pEASData->hwInstData, pData->fileHandle, &pData->repeatOffset)) != EAS_SUCCESS) + return result; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_GetNextChar() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_GetNextChar (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData, EAS_I8 *pValue) +{ + EAS_RESULT result; + EAS_I8 temp; + + *pValue = 0; + for(;;) + { + + /* check for character that has been put back */ + if (pData->dataByte) + { + temp = pData->dataByte; + pData->dataByte = 0; + } + else + { + if ((result = EAS_HWGetByte(hwInstData, pData->fileHandle, &temp)) != EAS_SUCCESS) + return result; + } + + /* ignore white space */ + if (!IsSpace(temp)) + { + *pValue = ToLower(temp); + return EAS_SUCCESS; + } + } +} + +/*---------------------------------------------------------------------------- + * RTTTL_PeekNextChar() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_PeekNextChar (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData, EAS_I8 *pValue) +{ + EAS_RESULT result; + EAS_I8 temp; + + *pValue = 0; + for(;;) + { + + /* read a character from the file, if necessary */ + if (!pData->dataByte) + { + if ((result = EAS_HWGetByte(hwInstData, pData->fileHandle, &pData->dataByte)) != EAS_SUCCESS) + return result; + + } + temp = pData->dataByte; + + /* ignore white space */ + if (!IsSpace(temp)) + { + *pValue = ToLower(temp); + return EAS_SUCCESS; + } + pData->dataByte = 0; + } +} + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_rtttldata.c b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_rtttldata.c new file mode 100755 index 0000000..708a1d9 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_rtttldata.c @@ -0,0 +1,41 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_rtttldata.c + * + * Contents and purpose: + * RTTTL File Parser data module for static memory models + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 547 $ + * $Date: 2007-01-31 16:30:17 -0800 (Wed, 31 Jan 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_types.h" +#include "eas_rtttldata.h" + +/*---------------------------------------------------------------------------- + * + * eas_RTTTLData + * + * Static memory allocation for RTTTL parser + *---------------------------------------------------------------------------- +*/ +S_RTTTL_DATA eas_RTTTLData; + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_rtttldata.h b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_rtttldata.h new file mode 100755 index 0000000..31dd522 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_rtttldata.h @@ -0,0 +1,70 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_rtttldata.h + * + * Contents and purpose: + * SMF File Parser + * + * This file contains data declarations for the RTTTL parser. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef EAS_RTTTLDATA_H +#define EAS_RTTTLDATA_H + +#include "eas_data.h" + + +/* maximum line size as specified in iMelody V1.2 spec */ +#define MAX_LINE_SIZE 75 + +/*---------------------------------------------------------------------------- + * + * S_RTTTL_DATA + * + * This structure contains the state data for the iMelody parser + *---------------------------------------------------------------------------- +*/ + +typedef struct +{ + EAS_FILE_HANDLE fileHandle; /* file handle */ + S_SYNTH *pSynth; /* synthesizer handle */ + S_METADATA_CB metadata; /* metadata callback */ + EAS_I32 fileOffset; /* offset to start of data */ + EAS_I32 time; /* current time in 256ths of a msec */ + EAS_I32 tick; /* length of 32nd note in 256th of a msec */ + EAS_I32 restTicks; /* ticks to rest after current note */ + EAS_I32 repeatOffset; /* file offset to start of repeat section */ + EAS_U8 repeatCount; /* repeat counter */ + EAS_I8 dataByte; /* storage for characters that are "put back" */ + EAS_U8 state; /* current state EAS_STATE_XXXX */ + EAS_I8 style; /* from STYLE */ + EAS_U8 note; /* MIDI note number */ + EAS_U8 octave; /* decault octave prefix */ + EAS_I8 duration; /* default note duration */ +} S_RTTTL_DATA; + +#endif + + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_smf.c b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_smf.c new file mode 100755 index 0000000..e609583 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_smf.c @@ -0,0 +1,1203 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_smf.c + * + * Contents and purpose: + * SMF Type 0 and 1 File Parser + * + * For SMF timebase analysis, see "MIDI Sequencer Analysis.xls". + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 803 $ + * $Date: 2007-08-01 09:57:00 -0700 (Wed, 01 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_data.h" +#include "eas_miditypes.h" +#include "eas_parser.h" +#include "eas_report.h" +#include "eas_host.h" +#include "eas_midi.h" +#include "eas_config.h" +#include "eas_vm_protos.h" +#include "eas_smfdata.h" +#include "eas_smf.h" + +#ifdef JET_INTERFACE +#include "jet_data.h" +#endif + +//3 dls: The timebase for this module is adequate to keep MIDI and +//3 digital audio synchronized for only a few minutes. It should be +//3 sufficient for most mobile applications. If better accuracy is +//3 required, more fractional bits should be added to the timebase. + +static const EAS_U8 smfHeader[] = { 'M', 'T', 'h', 'd' }; + +/* local prototypes */ +static EAS_RESULT SMF_GetVarLenData (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle, EAS_U32 *pData); +static EAS_RESULT SMF_ParseMetaEvent (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream); +static EAS_RESULT SMF_ParseSysEx (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream, EAS_U8 f0, EAS_INT parserMode); +static EAS_RESULT SMF_ParseEvent (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream, EAS_INT parserMode); +static EAS_RESULT SMF_GetDeltaTime (EAS_HW_DATA_HANDLE hwInstData, S_SMF_STREAM *pSMFStream); +static void SMF_UpdateTime (S_SMF_DATA *pSMFData, EAS_U32 ticks); + + +/*---------------------------------------------------------------------------- + * + * SMF_Parser + * + * This structure contains the functional interface for the SMF parser + *---------------------------------------------------------------------------- +*/ +const S_FILE_PARSER_INTERFACE EAS_SMF_Parser = +{ + SMF_CheckFileType, + SMF_Prepare, + SMF_Time, + SMF_Event, + SMF_State, + SMF_Close, + SMF_Reset, + SMF_Pause, + SMF_Resume, + NULL, + SMF_SetData, + SMF_GetData, + NULL +}; + +/*---------------------------------------------------------------------------- + * SMF_CheckFileType() + *---------------------------------------------------------------------------- + * Purpose: + * Check the file type to see if we can parse it + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT SMF_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset) +{ + S_SMF_DATA* pSMFData; + EAS_RESULT result; + + /* seek to starting offset - usually 0 */ + *ppHandle = NULL; + if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, offset)) != EAS_SUCCESS) + return result; + + /* search through file for header - slow method */ + if (pEASData->searchHeaderFlag) + { + result = EAS_SearchFile(pEASData, fileHandle, smfHeader, sizeof(smfHeader), &offset); + if (result != EAS_SUCCESS) + return (result == EAS_EOF) ? EAS_SUCCESS : result; + } + + /* read the first 4 bytes of the file - quick method */ + else { + EAS_U8 header[4]; + EAS_I32 count; + if ((result = EAS_HWReadFile(pEASData->hwInstData, fileHandle, header, sizeof(header), &count)) != EAS_SUCCESS) + return result; + + /* check for 'MTrk' - return if no match */ + if ((header[0] != 'M') || (header[1] != 'T') || (header[2] != 'h') || (header[3] != 'd')) + return EAS_SUCCESS; + } + + /* check for static memory allocation */ + if (pEASData->staticMemoryModel) + pSMFData = EAS_CMEnumData(EAS_CM_SMF_DATA); + else + { + pSMFData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_SMF_DATA)); + EAS_HWMemSet((void *)pSMFData,0, sizeof(S_SMF_DATA)); + } + if (!pSMFData) + return EAS_ERROR_MALLOC_FAILED; + + /* initialize some critical data */ + pSMFData->fileHandle = fileHandle; + pSMFData->fileOffset = offset; + pSMFData->pSynth = NULL; + pSMFData->time = 0; + pSMFData->state = EAS_STATE_OPEN; + *ppHandle = pSMFData; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_Prepare() + *---------------------------------------------------------------------------- + * Purpose: + * Prepare to parse the file. Allocates instance data (or uses static allocation for + * static memory model). + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT SMF_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_SMF_DATA* pSMFData; + EAS_RESULT result; + + /* check for valid state */ + pSMFData = (S_SMF_DATA *) pInstData; + if (pSMFData->state != EAS_STATE_OPEN) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + /* instantiate a synthesizer */ + if ((result = VMInitMIDI(pEASData, &pSMFData->pSynth)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitMIDI returned %d\n", result); */ } + return result; + } + + /* parse the file header and setup the individual stream parsers */ + if ((result = SMF_ParseHeader(pEASData->hwInstData, pSMFData)) != EAS_SUCCESS) + return result; + + /* ready to play */ + pSMFData->state = EAS_STATE_READY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_Time() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the time of the next event in msecs + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * pTime - pointer to variable to hold time of next event (in msecs) + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT SMF_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime) +{ + S_SMF_DATA *pSMFData; + + pSMFData = (S_SMF_DATA*) pInstData; + + /* sanity check */ +#ifdef _CHECKED_BUILD + if (pSMFData->state == EAS_STATE_STOPPED) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Can't ask for time on a stopped stream\n"); */ } + } + + if (pSMFData->nextStream == NULL) + { + { /* dpp: EAS_ReportEx( _EAS_SEVERITY_ERROR, "no is NULL\n"); */ } + } +#endif + +#if 0 + /* return time in milliseconds */ + /* if chase mode, lie about time */ + if (pSMFData->flags & SMF_FLAGS_CHASE_MODE) + *pTime = 0; + + else +#endif + + /*lint -e{704} use shift instead of division */ + *pTime = pSMFData->time >> 8; + + *pTime = pSMFData->time >> 8; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_Event() + *---------------------------------------------------------------------------- + * Purpose: + * Parse the next event in the file + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT SMF_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode) +{ + S_SMF_DATA* pSMFData; + EAS_RESULT result; + EAS_I32 i; + EAS_U32 ticks; + EAS_U32 temp; + + /* establish pointer to instance data */ + pSMFData = (S_SMF_DATA*) pInstData; + if (pSMFData->state >= EAS_STATE_OPEN) + return EAS_SUCCESS; + + /* get current ticks */ + ticks = pSMFData->nextStream->ticks; + + /* assume that an error occurred */ + pSMFData->state = EAS_STATE_ERROR; + +#ifdef JET_INTERFACE + /* if JET has track muted, set parser mode to mute */ + if (pSMFData->nextStream->midiStream.jetData & MIDI_FLAGS_JET_MUTE) + parserMode = eParserModeMute; +#endif + + /* parse the next event from all the streams */ + if ((result = SMF_ParseEvent(pEASData, pSMFData, pSMFData->nextStream, parserMode)) != EAS_SUCCESS) + { + /* check for unexpected end-of-file */ + if (result != EAS_EOF) + return result; + + /* indicate end of track for this stream */ + pSMFData->nextStream->ticks = SMF_END_OF_TRACK; + } + + /* get next delta time, unless already at end of track */ + else if (pSMFData->nextStream->ticks != SMF_END_OF_TRACK) + { + if ((result = SMF_GetDeltaTime(pEASData->hwInstData, pSMFData->nextStream)) != EAS_SUCCESS) + { + /* check for unexpected end-of-file */ + if (result != EAS_EOF) + return result; + + /* indicate end of track for this stream */ + pSMFData->nextStream->ticks = SMF_END_OF_TRACK; + } + + /* if zero delta to next event, stay with this stream */ + else if (pSMFData->nextStream->ticks == ticks) + { + pSMFData->state = EAS_STATE_PLAY; + return EAS_SUCCESS; + } + } + + /* find next event in all streams */ + temp = 0x7ffffff; + pSMFData->nextStream = NULL; + for (i = 0; i < pSMFData->numStreams; i++) + { + if (pSMFData->streams[i].ticks < temp) + { + temp = pSMFData->streams[i].ticks; + pSMFData->nextStream = &pSMFData->streams[i]; + } + } + + /* are there any more events to parse? */ + if (pSMFData->nextStream) + { + pSMFData->state = EAS_STATE_PLAY; + + /* update the time of the next event */ + SMF_UpdateTime(pSMFData, pSMFData->nextStream->ticks - ticks); + } + else + { + pSMFData->state = EAS_STATE_STOPPING; + VMReleaseAllVoices(pEASData->pVoiceMgr, pSMFData->pSynth); + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_State() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current state of the stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * pState - pointer to variable to store state + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT SMF_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pState) +{ + S_SMF_DATA* pSMFData; + + /* establish pointer to instance data */ + pSMFData = (S_SMF_DATA*) pInstData; + + /* if stopping, check to see if synth voices are active */ + if (pSMFData->state == EAS_STATE_STOPPING) + { + if (VMActiveVoices(pSMFData->pSynth) == 0) + pSMFData->state = EAS_STATE_STOPPED; + } + + if (pSMFData->state == EAS_STATE_PAUSING) + { + if (VMActiveVoices(pSMFData->pSynth) == 0) + pSMFData->state = EAS_STATE_PAUSED; + } + + /* return current state */ + *pState = pSMFData->state; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_Close() + *---------------------------------------------------------------------------- + * Purpose: + * Close the file and clean up + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT SMF_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_SMF_DATA* pSMFData; + EAS_I32 i; + EAS_RESULT result; + + pSMFData = (S_SMF_DATA*) pInstData; + + /* close all the streams */ + for (i = 0; i < pSMFData->numStreams; i++) + { + if (pSMFData->streams[i].fileHandle != NULL) + { + if ((result = EAS_HWCloseFile(pEASData->hwInstData, pSMFData->streams[i].fileHandle)) != EAS_SUCCESS) + return result; + } + } + if (pSMFData->fileHandle != NULL) + if ((result = EAS_HWCloseFile(pEASData->hwInstData, pSMFData->fileHandle)) != EAS_SUCCESS) + return result; + + /* free the synth */ + if (pSMFData->pSynth != NULL) + VMMIDIShutdown(pEASData, pSMFData->pSynth); + + /* if using dynamic memory, free it */ + if (!pEASData->staticMemoryModel) + { + if (pSMFData->streams) + EAS_HWFree(pEASData->hwInstData, pSMFData->streams); + + /* free the instance data */ + EAS_HWFree(pEASData->hwInstData, pSMFData); + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_Reset() + *---------------------------------------------------------------------------- + * Purpose: + * Reset the sequencer. Used for locating backwards in the file. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT SMF_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_SMF_DATA* pSMFData; + EAS_I32 i; + EAS_RESULT result; + EAS_U32 ticks; + + pSMFData = (S_SMF_DATA*) pInstData; + + /* reset time to zero */ + pSMFData->time = 0; + + /* reset the synth */ + VMReset(pEASData->pVoiceMgr, pSMFData->pSynth, EAS_TRUE); + + /* find the start of each track */ + ticks = 0x7fffffffL; + pSMFData->nextStream = NULL; + for (i = 0; i < pSMFData->numStreams; i++) + { + + /* reset file position to first byte of data in track */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pSMFData->streams[i].fileHandle, pSMFData->streams[i].startFilePos)) != EAS_SUCCESS) + return result; + + /* initalize some data */ + pSMFData->streams[i].ticks = 0; + + /* initalize the MIDI parser data */ + EAS_InitMIDIStream(&pSMFData->streams[i].midiStream); + + /* parse the first delta time in each stream */ + if ((result = SMF_GetDeltaTime(pEASData->hwInstData,&pSMFData->streams[i])) != EAS_SUCCESS) + return result; + if (pSMFData->streams[i].ticks < ticks) + { + ticks = pSMFData->streams[i].ticks; + pSMFData->nextStream = &pSMFData->streams[i]; + } + } + + + pSMFData->state = EAS_STATE_READY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_Pause() + *---------------------------------------------------------------------------- + * Purpose: + * Pauses the sequencer. Mutes all voices and sets state to pause. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT SMF_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_SMF_DATA *pSMFData; + + /* can't pause a stopped stream */ + pSMFData = (S_SMF_DATA*) pInstData; + if (pSMFData->state == EAS_STATE_STOPPED) + return EAS_ERROR_ALREADY_STOPPED; + + /* mute the synthesizer */ + VMMuteAllVoices(pEASData->pVoiceMgr, pSMFData->pSynth); + pSMFData->state = EAS_STATE_PAUSING; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_Resume() + *---------------------------------------------------------------------------- + * Purpose: + * Resume playing after a pause, sets state back to playing. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT SMF_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_SMF_DATA *pSMFData; + + /* can't resume a stopped stream */ + pSMFData = (S_SMF_DATA*) pInstData; + if (pSMFData->state == EAS_STATE_STOPPED) + return EAS_ERROR_ALREADY_STOPPED; + + /* nothing to do but resume playback */ + pSMFData->state = EAS_STATE_PLAY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_SetData() + *---------------------------------------------------------------------------- + * Purpose: + * Sets parser parameters + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT SMF_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value) +{ + S_SMF_DATA *pSMFData; + + pSMFData = (S_SMF_DATA*) pInstData; + switch (param) + { + + /* set metadata callback */ + case PARSER_DATA_METADATA_CB: + EAS_HWMemCpy(&pSMFData->metadata, (void*) value, sizeof(S_METADATA_CB)); + break; + +#ifdef JET_INTERFACE + /* set jet segment and track ID of all tracks for callback function */ + case PARSER_DATA_JET_CB: + { + EAS_U32 i; + EAS_U32 bit = (EAS_U32) value; + bit = (bit << JET_EVENT_SEG_SHIFT) & JET_EVENT_SEG_MASK; + for (i = 0; i < pSMFData->numStreams; i++) + pSMFData->streams[i].midiStream.jetData = + (pSMFData->streams[i].midiStream.jetData & + ~(JET_EVENT_TRACK_MASK | JET_EVENT_SEG_MASK)) | + i << JET_EVENT_TRACK_SHIFT | bit | MIDI_FLAGS_JET_CB; + pSMFData->flags |= SMF_FLAGS_JET_STREAM; + } + break; + + /* set state of all mute flags at once */ + case PARSER_DATA_MUTE_FLAGS: + { + EAS_INT i; + EAS_U32 bit = (EAS_U32) value; + for (i = 0; i < pSMFData->numStreams; i++) + { + if (bit & 1) + pSMFData->streams[i].midiStream.jetData |= MIDI_FLAGS_JET_MUTE; + else + pSMFData->streams[i].midiStream.jetData &= ~MIDI_FLAGS_JET_MUTE; + bit >>= 1; + } + } + break; + + /* set track mute */ + case PARSER_DATA_SET_MUTE: + if (value < pSMFData->numStreams) + pSMFData->streams[value].midiStream.jetData |= MIDI_FLAGS_JET_MUTE; + else + return EAS_ERROR_PARAMETER_RANGE; + break; + + /* clear track mute */ + case PARSER_DATA_CLEAR_MUTE: + if (value < pSMFData->numStreams) + pSMFData->streams[value].midiStream.jetData &= ~MIDI_FLAGS_JET_MUTE; + else + return EAS_ERROR_PARAMETER_RANGE; + break; +#endif + + default: + return EAS_ERROR_INVALID_PARAMETER; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_GetData() + *---------------------------------------------------------------------------- + * Purpose: + * Retrieves parser parameters + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT SMF_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue) +{ + S_SMF_DATA *pSMFData; + + pSMFData = (S_SMF_DATA*) pInstData; + switch (param) + { + /* return file type */ + case PARSER_DATA_FILE_TYPE: + if (pSMFData->numStreams == 1) + *pValue = EAS_FILE_SMF0; + else + *pValue = EAS_FILE_SMF1; + break; + +/* now handled in eas_public.c */ +#if 0 + case PARSER_DATA_POLYPHONY: + if (pSMFData->pSynth) + VMGetPolyphony(pEASData->pVoiceMgr, pSMFData->pSynth, pValue); + else + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + break; + + case PARSER_DATA_PRIORITY: + if (pSMFData->pSynth) + VMGetPriority(pEASData->pVoiceMgr, pSMFData->pSynth, pValue); + break; + + /* set transposition */ + case PARSER_DATA_TRANSPOSITION: + *pValue = pSMFData->transposition; + break; +#endif + + case PARSER_DATA_SYNTH_HANDLE: + *pValue = (EAS_I32) pSMFData->pSynth; + break; + + default: + return EAS_ERROR_INVALID_PARAMETER; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_GetVarLenData() + *---------------------------------------------------------------------------- + * Purpose: + * Reads a varible length quantity from an SMF file + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT SMF_GetVarLenData (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle, EAS_U32 *pData) +{ + EAS_RESULT result; + EAS_U32 data; + EAS_U8 c; + + /* read until bit 7 is zero */ + data = 0; + do + { + if ((result = EAS_HWGetByte(hwInstData, fileHandle,&c)) != EAS_SUCCESS) + return result; + data = (data << 7) | (c & 0x7f); + } while (c & 0x80); + *pData = data; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_GetDeltaTime() + *---------------------------------------------------------------------------- + * Purpose: + * Reads a varible length quantity from an SMF file + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT SMF_GetDeltaTime (EAS_HW_DATA_HANDLE hwInstData, S_SMF_STREAM *pSMFStream) +{ + EAS_RESULT result; + EAS_U32 ticks; + + if ((result = SMF_GetVarLenData(hwInstData, pSMFStream->fileHandle, &ticks)) != EAS_SUCCESS) + return result; + + pSMFStream->ticks += ticks; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_ParseMetaEvent() + *---------------------------------------------------------------------------- + * Purpose: + * Reads a varible length quantity from an SMF file + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT SMF_ParseMetaEvent (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream) +{ + EAS_RESULT result; + EAS_U32 len; + EAS_I32 pos; + EAS_U32 temp; + EAS_U8 c; + + /* get the meta-event type */ + if ((result = EAS_HWGetByte(pEASData->hwInstData, pSMFStream->fileHandle, &c)) != EAS_SUCCESS) + return result; + + /* get the length */ + if ((result = SMF_GetVarLenData(pEASData->hwInstData, pSMFStream->fileHandle, &len)) != EAS_SUCCESS) + return result; + + /* get the current file position so we can skip the event */ + if ((result = EAS_HWFilePos(pEASData->hwInstData, pSMFStream->fileHandle, &pos)) != EAS_SUCCESS) + return result; + pos += (EAS_I32) len; + + /* end of track? */ + if (c == SMF_META_END_OF_TRACK) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Meta-event: end of track\n", c, len); */ } + pSMFStream->ticks = SMF_END_OF_TRACK; + } + + /* tempo event? */ + else if (c == SMF_META_TEMPO) + { + /* read the 3-byte timebase value */ + temp = 0; + while (len--) + { + if ((result = EAS_HWGetByte(pEASData->hwInstData, pSMFStream->fileHandle, &c)) != EAS_SUCCESS) + return result; + temp = (temp << 8) | c; + } + + pSMFData->tickConv = (EAS_U16) (((temp * 1024) / pSMFData->ppqn + 500) / 1000); + pSMFData->flags |= SMF_FLAGS_HAS_TEMPO; + } + + /* check for time signature - see iMelody spec V1.4 section 4.1.2.2.3.6 */ + else if (c == SMF_META_TIME_SIGNATURE) + { + pSMFData->flags |= SMF_FLAGS_HAS_TIME_SIG; + } + + /* if the host has registered a metadata callback return the metadata */ + else if (pSMFData->metadata.callback) + { + EAS_I32 readLen; + E_EAS_METADATA_TYPE metaType; + + metaType = EAS_METADATA_UNKNOWN; + + /* only process title on the first track */ + if (c == SMF_META_SEQTRK_NAME) + metaType = EAS_METADATA_TITLE; + else if (c == SMF_META_TEXT) + metaType = EAS_METADATA_TEXT; + else if (c == SMF_META_COPYRIGHT) + metaType = EAS_METADATA_COPYRIGHT; + else if (c == SMF_META_LYRIC) + metaType = EAS_METADATA_LYRIC; + + if (metaType != EAS_METADATA_UNKNOWN) + { + readLen = pSMFData->metadata.bufferSize - 1; + if ((EAS_I32) len < readLen) + readLen = (EAS_I32) len; + if ((result = EAS_HWReadFile(pEASData->hwInstData, pSMFStream->fileHandle, pSMFData->metadata.buffer, readLen, &readLen)) != EAS_SUCCESS) + return result; + pSMFData->metadata.buffer[readLen] = 0; + pSMFData->metadata.callback(metaType, pSMFData->metadata.buffer, pSMFData->metadata.pUserData); + } + } + + /* position file to next event - in case we ignored all or part of the meta-event */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pSMFStream->fileHandle, pos)) != EAS_SUCCESS) + return result; + + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Meta-event: type=%02x, len=%d\n", c, len); */ } + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_ParseSysEx() + *---------------------------------------------------------------------------- + * Purpose: + * Reads a varible length quantity from an SMF file + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT SMF_ParseSysEx (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream, EAS_U8 f0, EAS_INT parserMode) +{ + EAS_RESULT result; + EAS_U32 len; + EAS_U8 c; + + /* get the length */ + if ((result = SMF_GetVarLenData(pEASData->hwInstData, pSMFStream->fileHandle, &len)) != EAS_SUCCESS) + return result; + + /* start of SysEx message? */ + if (f0 == 0xf0) + { + if ((result = EAS_ParseMIDIStream(pEASData, pSMFData->pSynth, &pSMFStream->midiStream, f0, parserMode)) != EAS_SUCCESS) + return result; + } + + /* feed the SysEx to the stream parser */ + while (len--) + { + if ((result = EAS_HWGetByte(pEASData->hwInstData, pSMFStream->fileHandle, &c)) != EAS_SUCCESS) + return result; + if ((result = EAS_ParseMIDIStream(pEASData, pSMFData->pSynth, &pSMFStream->midiStream, c, parserMode)) != EAS_SUCCESS) + return result; + + /* check for GM system ON */ + if (pSMFStream->midiStream.flags & MIDI_FLAG_GM_ON) + pSMFData->flags |= SMF_FLAGS_HAS_GM_ON; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_ParseEvent() + *---------------------------------------------------------------------------- + * Purpose: + * Reads a varible length quantity from an SMF file + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT SMF_ParseEvent (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream, EAS_INT parserMode) +{ + EAS_RESULT result; + EAS_U8 c; + + /* get the event type */ + if ((result = EAS_HWGetByte(pEASData->hwInstData, pSMFStream->fileHandle, &c)) != EAS_SUCCESS) + return result; + + /* parse meta-event */ + if (c == 0xff) + { + if ((result = SMF_ParseMetaEvent(pEASData, pSMFData, pSMFStream)) != EAS_SUCCESS) + return result; + } + + /* parse SysEx */ + else if ((c == 0xf0) || (c == 0xf7)) + { + if ((result = SMF_ParseSysEx(pEASData, pSMFData, pSMFStream, c, parserMode)) != EAS_SUCCESS) + return result; + } + + /* parse MIDI message */ + else + { + if ((result = EAS_ParseMIDIStream(pEASData, pSMFData->pSynth, &pSMFStream->midiStream, c, parserMode)) != EAS_SUCCESS) + return result; + + /* keep streaming data to the MIDI parser until the message is complete */ + while (pSMFStream->midiStream.pending) + { + if ((result = EAS_HWGetByte(pEASData->hwInstData, pSMFStream->fileHandle, &c)) != EAS_SUCCESS) + return result; + if ((result = EAS_ParseMIDIStream(pEASData, pSMFData->pSynth, &pSMFStream->midiStream, c, parserMode)) != EAS_SUCCESS) + return result; + } + + } + + /* chase mode logic */ + if (pSMFData->time == 0) + { + if (pSMFData->flags & SMF_FLAGS_CHASE_MODE) + { + if (pSMFStream->midiStream.flags & MIDI_FLAG_FIRST_NOTE) + pSMFData->flags &= ~SMF_FLAGS_CHASE_MODE; + } + else if ((pSMFData->flags & SMF_FLAGS_SETUP_BAR) == SMF_FLAGS_SETUP_BAR) + pSMFData->flags = (pSMFData->flags & ~SMF_FLAGS_SETUP_BAR) | SMF_FLAGS_CHASE_MODE; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_ParseHeader() + *---------------------------------------------------------------------------- + * Purpose: + * Parses the header of an SMF file, allocates memory the stream parsers and initializes the + * stream parsers. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * pSMFData - pointer to parser instance data + * fileHandle - file handle + * fileOffset - offset in the file where the header data starts, usually 0 + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -e{801} we know that 'goto' is deprecated - but it's cleaner in this case */ +EAS_RESULT SMF_ParseHeader (EAS_HW_DATA_HANDLE hwInstData, S_SMF_DATA *pSMFData) +{ + EAS_RESULT result; + EAS_I32 i; + EAS_U16 division; + EAS_U32 chunkSize; + EAS_U32 chunkStart; + EAS_U32 temp; + EAS_U32 ticks; + + /* rewind the file and find the end of the header chunk */ + if ((result = EAS_HWFileSeek(hwInstData, pSMFData->fileHandle, pSMFData->fileOffset + SMF_OFS_HEADER_SIZE)) != EAS_SUCCESS) + goto ReadError; + if ((result = EAS_HWGetDWord(hwInstData, pSMFData->fileHandle, &chunkSize, EAS_TRUE)) != EAS_SUCCESS) + goto ReadError; + + /* determine the number of tracks */ + if ((result = EAS_HWFileSeek(hwInstData, pSMFData->fileHandle, pSMFData->fileOffset + SMF_OFS_NUM_TRACKS)) != EAS_SUCCESS) + goto ReadError; + if ((result = EAS_HWGetWord(hwInstData, pSMFData->fileHandle, &pSMFData->numStreams, EAS_TRUE)) != EAS_SUCCESS) + goto ReadError; + + /* limit the number of tracks */ + if (pSMFData->numStreams > MAX_SMF_STREAMS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "SMF file contains %u tracks, playing %d tracks\n", pSMFData->numStreams, MAX_SMF_STREAMS); */ } + pSMFData->numStreams = MAX_SMF_STREAMS; + } + + /* get the time division */ + if ((result = EAS_HWGetWord(hwInstData, pSMFData->fileHandle, &division, EAS_TRUE)) != EAS_SUCCESS) + goto ReadError; + + /* setup default timebase for 120 bpm */ + pSMFData->ppqn = 192; + if (division & 0x8000) + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING,"No support for SMPTE code timebase\n"); */ } + else + pSMFData->ppqn = (division & 0x7fff); + pSMFData->tickConv = (EAS_U16) (((SMF_DEFAULT_TIMEBASE * 1024) / pSMFData->ppqn + 500) / 1000); + + /* dynamic memory allocation, allocate memory for streams */ + if (pSMFData->streams == NULL) + { + pSMFData->streams = EAS_HWMalloc(hwInstData,sizeof(S_SMF_STREAM) * pSMFData->numStreams); + if (pSMFData->streams == NULL) + return EAS_ERROR_MALLOC_FAILED; + + /* zero the memory to insure complete initialization */ + EAS_HWMemSet((void *)(pSMFData->streams), 0, sizeof(S_SMF_STREAM) * pSMFData->numStreams); + } + + /* find the start of each track */ + chunkStart = (EAS_U32) pSMFData->fileOffset; + ticks = 0x7fffffffL; + pSMFData->nextStream = NULL; + for (i = 0; i < pSMFData->numStreams; i++) + { + + for (;;) + { + + /* calculate start of next chunk - checking for errors */ + temp = chunkStart + SMF_CHUNK_INFO_SIZE + chunkSize; + if (temp <= chunkStart) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING,"Error in chunk size at offset %d\n", chunkStart); */ } + return EAS_ERROR_FILE_FORMAT; + } + chunkStart = temp; + + /* seek to the start of the next chunk */ + if ((result = EAS_HWFileSeek(hwInstData, pSMFData->fileHandle, (EAS_I32) chunkStart)) != EAS_SUCCESS) + goto ReadError; + + /* read the chunk identifier */ + if ((result = EAS_HWGetDWord(hwInstData, pSMFData->fileHandle, &temp, EAS_TRUE)) != EAS_SUCCESS) + goto ReadError; + + /* read the chunk size */ + if ((result = EAS_HWGetDWord(hwInstData, pSMFData->fileHandle, &chunkSize, EAS_TRUE)) != EAS_SUCCESS) + goto ReadError; + + /* make sure this is an 'MTrk' chunk */ + if (temp == SMF_CHUNK_TYPE_TRACK) + break; + + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING,"Unexpected chunk type: 0x%08x\n", temp); */ } + } + + /* initalize some data */ + pSMFData->streams[i].ticks = 0; + pSMFData->streams[i].fileHandle = pSMFData->fileHandle; + + /* NULL the file handle so we don't try to close it twice */ + pSMFData->fileHandle = NULL; + + /* save this file position as the start of the track */ + pSMFData->streams[i].startFilePos = (EAS_I32) chunkStart + SMF_CHUNK_INFO_SIZE; + + /* initalize the MIDI parser data */ + EAS_InitMIDIStream(&pSMFData->streams[i].midiStream); + + /* parse the first delta time in each stream */ + if ((result = SMF_GetDeltaTime(hwInstData, &pSMFData->streams[i])) != EAS_SUCCESS) + goto ReadError; + + if (pSMFData->streams[i].ticks < ticks) + { + ticks = pSMFData->streams[i].ticks; + pSMFData->nextStream = &pSMFData->streams[i]; + } + + /* more tracks to do, create a duplicate file handle */ + if (i < (pSMFData->numStreams - 1)) + { + if ((result = EAS_HWDupHandle(hwInstData, pSMFData->streams[i].fileHandle, &pSMFData->fileHandle)) != EAS_SUCCESS) + goto ReadError; + } + } + + /* update the time of the next event */ + if (pSMFData->nextStream) + SMF_UpdateTime(pSMFData, pSMFData->nextStream->ticks); + + return EAS_SUCCESS; + + /* ugly goto: but simpler than structured */ + ReadError: + if (result == EAS_EOF) + return EAS_ERROR_FILE_FORMAT; + return result; +} + +/*---------------------------------------------------------------------------- + * SMF_UpdateTime() + *---------------------------------------------------------------------------- + * Purpose: + * Update the millisecond time base by converting the ticks into millieconds + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static void SMF_UpdateTime (S_SMF_DATA *pSMFData, EAS_U32 ticks) +{ + EAS_U32 temp1, temp2; + + if (pSMFData->flags & SMF_FLAGS_CHASE_MODE) + return; + + temp1 = (ticks >> 10) * pSMFData->tickConv; + temp2 = (ticks & 0x3ff) * pSMFData->tickConv; + pSMFData->time += (EAS_I32)((temp1 << 8) + (temp2 >> 2)); +} + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_smf.h b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_smf.h new file mode 100755 index 0000000..37c0790 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_smf.h @@ -0,0 +1,49 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_smf.h + * + * Contents and purpose: + * SMF Type 0 and 1 File Parser + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_SMF_H +#define _EAS_SMF_H + +/* prototypes for private interface to SMF parser */ +EAS_RESULT SMF_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset); +EAS_RESULT SMF_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +EAS_RESULT SMF_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime); +EAS_RESULT SMF_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode); +EAS_RESULT SMF_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_STATE *pState); +EAS_RESULT SMF_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +EAS_RESULT SMF_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +EAS_RESULT SMF_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +EAS_RESULT SMF_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +EAS_RESULT SMF_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value); +EAS_RESULT SMF_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue); +EAS_RESULT SMF_ParseHeader (EAS_HW_DATA_HANDLE hwInstData, S_SMF_DATA *pSMFData); + +#endif /* end _EAS_SMF_H */ + + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_smfdata.c b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_smfdata.c new file mode 100755 index 0000000..383d7f3 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_smfdata.c @@ -0,0 +1,66 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_smfdata.c + * + * Contents and purpose: + * SMF File Parser + * + * This file contains data definitions for the SMF parser. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 778 $ + * $Date: 2007-07-23 16:45:17 -0700 (Mon, 23 Jul 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_miditypes.h" +#include "eas_smfdata.h" + +/*---------------------------------------------------------------------------- + * + * S_SMF_STREAM + * + * Static memory allocation for SMF parser + *---------------------------------------------------------------------------- +*/ +static S_SMF_STREAM eas_SMFStreams[MAX_SMF_STREAMS]; + +/*---------------------------------------------------------------------------- + * + * eas_SMFData + * + * Static memory allocation for SMF parser + *---------------------------------------------------------------------------- +*/ +S_SMF_DATA eas_SMFData = +{ + eas_SMFStreams, /* pointer to individual streams in file */ + 0, /* pointer to next stream with event */ + 0, /* pointer to synth */ + 0, /* file handle */ + { 0, 0, 0, 0}, /* metadata callback */ + 0, /* file offset */ + 0, /* current time in milliseconds/256 */ + 0, /* actual number of streams */ + 0, /* current MIDI tick to msec conversion */ + 0, /* ticks per quarter note */ + 0, /* current state EAS_STATE_XXXX */ + 0 /* flags */ +}; + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_smfdata.h b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_smfdata.h new file mode 100755 index 0000000..8861d90 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_smfdata.h @@ -0,0 +1,66 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_smfdata.h + * + * Contents and purpose: + * SMF File Parser + * + * This file contains data definitions for the SMF parser. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 686 $ + * $Date: 2007-05-03 14:10:54 -0700 (Thu, 03 May 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_SMF_DATA_H +#define _EAS_SMF_DATA_H + +#ifndef MAX_SMF_STREAMS +#define MAX_SMF_STREAMS 17 +#endif + +/* offsets in to the SMF file */ +#define SMF_OFS_HEADER_SIZE 4 +#define SMF_OFS_FILE_TYPE 8 +#define SMF_OFS_NUM_TRACKS 10 + +/* size of chunk info (chunk ID + chunk size) */ +#define SMF_CHUNK_INFO_SIZE 8 + +/* 'MTrk' track chunk ID */ +#define SMF_CHUNK_TYPE_TRACK 0x4d54726bL + +/* some useful meta-events */ +#define SMF_META_TEXT 0x01 +#define SMF_META_COPYRIGHT 0x02 +#define SMF_META_SEQTRK_NAME 0x03 +#define SMF_META_LYRIC 0x05 +#define SMF_META_END_OF_TRACK 0x2f +#define SMF_META_TEMPO 0x51 +#define SMF_META_TIME_SIGNATURE 0x58 + +/* default timebase (120BPM) */ +#define SMF_DEFAULT_TIMEBASE 500000L + +/* value for pSMFStream->ticks to signify end of track */ +#define SMF_END_OF_TRACK 0xffffffff + +#endif + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_sndlib.h b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_sndlib.h new file mode 100755 index 0000000..416be6e --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_sndlib.h @@ -0,0 +1,406 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_sndlib.h + * + * Contents and purpose: + * Declarations for the sound library + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 550 $ + * $Date: 2007-02-02 09:37:03 -0800 (Fri, 02 Feb 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_SNDLIB_H +#define _EAS_SNDLIB_H + +#include "eas_types.h" +#include "eas_synthcfg.h" + +#ifdef _WT_SYNTH +#include "eas_wtengine.h" +#endif + +/*---------------------------------------------------------------------------- + * This is bit of a hack to allow us to keep the same structure + * declarations for the DLS parser. Normally, the data is located + * in read-only memory, but for DLS, we store the data in RW + * memory. + *---------------------------------------------------------------------------- +*/ +#ifndef SCNST +#define SCNST const +#endif + +/*---------------------------------------------------------------------------- + * sample size + *---------------------------------------------------------------------------- +*/ +#ifdef _16_BIT_SAMPLES +typedef EAS_I16 EAS_SAMPLE; +#else +typedef EAS_I8 EAS_SAMPLE; +#endif + +/*---------------------------------------------------------------------------- + * EAS Library ID - quick check for valid library and version + *---------------------------------------------------------------------------- +*/ +#define _EAS_LIBRARY_VERSION 0x01534145 + +#define NUM_PROGRAMS_IN_BANK 128 +#define INVALID_REGION_INDEX 0xffff + +/* this bit in region index indicates that region is for secondary synth */ +#define FLAG_RGN_IDX_FM_SYNTH 0x8000 +#define FLAG_RGN_IDX_DLS_SYNTH 0x4000 +#define REGION_INDEX_MASK 0x3fff + +/*---------------------------------------------------------------------------- + * Generic region data structure + * + * This must be the first element in each region structure + *---------------------------------------------------------------------------- +*/ +typedef struct s_region_tag +{ + EAS_U16 keyGroupAndFlags; + EAS_U8 rangeLow; + EAS_U8 rangeHigh; +} S_REGION; + +/* + * Bit fields for m_nKeyGroupAndFlags + * Bits 0-2 are mode bits in FM synth + * Bits 8-11 are the key group + */ +#define REGION_FLAG_IS_LOOPED 0x01 +#define REGION_FLAG_USE_WAVE_GENERATOR 0x02 +#define REGION_FLAG_USE_ADPCM 0x04 +#define REGION_FLAG_ONE_SHOT 0x08 +#define REGION_FLAG_SQUARE_WAVE 0x10 +#define REGION_FLAG_OFF_CHIP 0x20 +#define REGION_FLAG_NON_SELF_EXCLUSIVE 0x40 +#define REGION_FLAG_LAST_REGION 0x8000 + +/*---------------------------------------------------------------------------- + * Envelope data structure + *---------------------------------------------------------------------------- +*/ +typedef struct s_envelope_tag +{ + EAS_I16 attackTime; + EAS_I16 decayTime; + EAS_I16 sustainLevel; + EAS_I16 releaseTime; +} S_ENVELOPE; + +/*---------------------------------------------------------------------------- + * DLS envelope data structure + *---------------------------------------------------------------------------- +*/ +typedef struct s_dls_envelope_tag +{ + EAS_I16 delayTime; + EAS_I16 attackTime; + EAS_I16 holdTime; + EAS_I16 decayTime; + EAS_I16 sustainLevel; + EAS_I16 releaseTime; + EAS_I16 velToAttack; + EAS_I16 keyNumToDecay; + EAS_I16 keyNumToHold; +} S_DLS_ENVELOPE; + +/*---------------------------------------------------------------------------- + * LFO data structure + *---------------------------------------------------------------------------- +*/ +typedef struct s_lfo_params_tag +{ + EAS_I16 lfoFreq; + EAS_I16 lfoDelay; +} S_LFO_PARAMS; + +/*---------------------------------------------------------------------------- + * Articulation data structure + *---------------------------------------------------------------------------- +*/ +typedef struct s_articulation_tag +{ + S_ENVELOPE eg1; + S_ENVELOPE eg2; + EAS_I16 lfoToPitch; + EAS_I16 lfoDelay; + EAS_I16 lfoFreq; + EAS_I16 eg2ToPitch; + EAS_I16 eg2ToFc; + EAS_I16 filterCutoff; + EAS_I8 lfoToGain; + EAS_U8 filterQ; + EAS_I8 pan; +} S_ARTICULATION; + +/*---------------------------------------------------------------------------- + * DLS articulation data structure + *---------------------------------------------------------------------------- +*/ + +typedef struct s_dls_articulation_tag +{ + S_LFO_PARAMS modLFO; + S_LFO_PARAMS vibLFO; + + S_DLS_ENVELOPE eg1; + S_DLS_ENVELOPE eg2; + + EAS_I16 eg1ShutdownTime; + + EAS_I16 filterCutoff; + EAS_I16 modLFOToFc; + EAS_I16 modLFOCC1ToFc; + EAS_I16 modLFOChanPressToFc; + EAS_I16 eg2ToFc; + EAS_I16 velToFc; + EAS_I16 keyNumToFc; + + EAS_I16 modLFOToGain; + EAS_I16 modLFOCC1ToGain; + EAS_I16 modLFOChanPressToGain; + + EAS_I16 tuning; + EAS_I16 keyNumToPitch; + EAS_I16 vibLFOToPitch; + EAS_I16 vibLFOCC1ToPitch; + EAS_I16 vibLFOChanPressToPitch; + EAS_I16 modLFOToPitch; + EAS_I16 modLFOCC1ToPitch; + EAS_I16 modLFOChanPressToPitch; + EAS_I16 eg2ToPitch; + + /* pad to 4-byte boundary */ + EAS_U16 pad; + + EAS_I8 pan; + EAS_U8 filterQandFlags; + +#ifdef _REVERB + EAS_I16 reverbSend; + EAS_I16 cc91ToReverbSend; +#endif + +#ifdef _CHORUS + EAS_I16 chorusSend; + EAS_I16 cc93ToChorusSend; +#endif +} S_DLS_ARTICULATION; + +/* flags in filterQandFlags + * NOTE: Q is stored in bottom 5 bits + */ +#define FLAG_DLS_VELOCITY_SENSITIVE 0x80 +#define FILTER_Q_MASK 0x1f + +/*---------------------------------------------------------------------------- + * Wavetable region data structure + *---------------------------------------------------------------------------- +*/ +typedef struct s_wt_region_tag +{ + S_REGION region; + EAS_I16 tuning; + EAS_I16 gain; + EAS_U32 loopStart; + EAS_U32 loopEnd; + EAS_U16 waveIndex; + EAS_U16 artIndex; +} S_WT_REGION; + +/*---------------------------------------------------------------------------- + * DLS region data structure + *---------------------------------------------------------------------------- +*/ +typedef struct s_dls_region_tag +{ + S_WT_REGION wtRegion; + EAS_U8 velLow; + EAS_U8 velHigh; +} S_DLS_REGION; + +/*---------------------------------------------------------------------------- + * FM synthesizer data structures + *---------------------------------------------------------------------------- +*/ +typedef struct s_fm_oper_tag +{ + EAS_I16 tuning; + EAS_U8 attackDecay; + EAS_U8 velocityRelease; + EAS_U8 egKeyScale; + EAS_U8 sustain; + EAS_U8 gain; + EAS_U8 flags; +} S_FM_OPER; + +/* defines for S_FM_OPER.m_nFlags */ +#define FM_OPER_FLAG_MONOTONE 0x01 +#define FM_OPER_FLAG_NO_VIBRATO 0x02 +#define FM_OPER_FLAG_NOISE 0x04 +#define FM_OPER_FLAG_LINEAR_VELOCITY 0x08 + +/* NOTE: The first two structure elements are common with S_WT_REGION + * and we will rely on that in the voice management code and must + * remain there unless the voice management code is revisited. + */ +typedef struct s_fm_region_tag +{ + S_REGION region; + EAS_U8 vibTrem; + EAS_U8 lfoFreqDelay; + EAS_U8 feedback; + EAS_I8 pan; + S_FM_OPER oper[4]; +} S_FM_REGION; + +/*---------------------------------------------------------------------------- + * Common data structures + *---------------------------------------------------------------------------- +*/ + +/*---------------------------------------------------------------------------- + * Program data structure + * Used for individual programs not stored as a complete bank. + *---------------------------------------------------------------------------- +*/ +typedef struct s_program_tag +{ + EAS_U32 locale; + EAS_U16 regionIndex; +} S_PROGRAM; + +/*---------------------------------------------------------------------------- + * Bank data structure + * + * A bank always consists of 128 programs. If a bank is less than 128 + * programs, it should be stored as a spare matrix in the pPrograms + * array. + * + * bankNum: MSB/LSB of MIDI bank select controller + * regionIndex: Index of first region in program + *---------------------------------------------------------------------------- +*/ +typedef struct s_bank_tag +{ + EAS_U16 locale; + EAS_U16 regionIndex[NUM_PROGRAMS_IN_BANK]; +} S_BANK; + + +/* defines for libFormat field + * bits 0-17 are the sample rate + * bit 18 is true if wavetable is present + * bit 19 is true if FM is present + * bit 20 is true if filter is enabled + * bit 21 is sample depth (0 = 8-bits, 1 = 16-bits) + * bits 22-31 are reserved + */ +#define LIBFORMAT_SAMPLE_RATE_MASK 0x0003ffff +#define LIB_FORMAT_TYPE_MASK 0x000c0000 +#define LIB_FORMAT_WAVETABLE 0x00000000 +#define LIB_FORMAT_FM 0x00040000 +#define LIB_FORMAT_HYBRID 0x00080000 +#define LIB_FORMAT_FILTER_ENABLED 0x00100000 +#define LIB_FORMAT_16_BIT_SAMPLES 0x00200000 + +#ifdef DLS_SYNTHESIZER +/*---------------------------------------------------------------------------- + * DLS data structure + * + * pDLSPrograms pointer to array of DLS programs + * pDLSRegions pointer to array of DLS regions + * pDLSArticulations pointer to array of DLS articulations + * pSampleLen pointer to array of sample lengths + * ppSamples pointer to array of sample pointers + * numDLSPrograms number of DLS programs + * numDLSRegions number of DLS regions + * numDLSArticulations number of DLS articulations + * numDLSSamples number of DLS samples + *---------------------------------------------------------------------------- +*/ +typedef struct s_eas_dls_tag +{ + S_PROGRAM *pDLSPrograms; + S_DLS_REGION *pDLSRegions; + S_DLS_ARTICULATION *pDLSArticulations; + EAS_U32 *pDLSSampleLen; + EAS_U32 *pDLSSampleOffsets; + EAS_SAMPLE *pDLSSamples; + EAS_U16 numDLSPrograms; + EAS_U16 numDLSRegions; + EAS_U16 numDLSArticulations; + EAS_U16 numDLSSamples; + EAS_U8 refCount; +} S_DLS; +#endif + +/*---------------------------------------------------------------------------- + * Sound library data structure + * + * pBanks pointer to array of banks + * pPrograms pointer to array of programs + * pWTRegions pointer to array of wavetable regions + * pFMRegions pointer to array of FM regions + * pArticulations pointer to array of articulations + * pSampleLen pointer to array of sample lengths + * ppSamples pointer to array of sample pointers + * numBanks number of banks + * numPrograms number of individual program + * numRegions number of regions + * numArticulations number of articulations + * numSamples number of samples + *---------------------------------------------------------------------------- +*/ +typedef struct s_eas_sndlib_tag +{ + SCNST EAS_U32 identifier; + SCNST EAS_U32 libAttr; + + SCNST S_BANK *pBanks; + SCNST S_PROGRAM *pPrograms; + + SCNST S_WT_REGION *pWTRegions; + SCNST S_ARTICULATION *pArticulations; + SCNST EAS_U32 *pSampleLen; + SCNST EAS_U32 *pSampleOffsets; + SCNST EAS_SAMPLE *pSamples; + + SCNST S_FM_REGION *pFMRegions; + + SCNST EAS_U16 numBanks; + SCNST EAS_U16 numPrograms; + + SCNST EAS_U16 numWTRegions; + SCNST EAS_U16 numArticulations; + SCNST EAS_U16 numSamples; + + SCNST EAS_U16 numFMRegions; +} S_EAS; + +#endif + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_synth.h b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_synth.h new file mode 100755 index 0000000..6274b7d --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_synth.h @@ -0,0 +1,395 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_synth.h + * + * Contents and purpose: + * Declarations, interfaces, and prototypes for synth. + * + * Copyright Sonic Network Inc. 2004, 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 718 $ + * $Date: 2007-06-08 16:43:16 -0700 (Fri, 08 Jun 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_SYNTH_H +#define _EAS_SYNTH_H + +#include "eas_types.h" +#include "eas_sndlib.h" + +#ifdef _WT_SYNTH +#include "eas_wtsynth.h" +#endif + +#ifdef _FM_SYNTH +#include "eas_fmsynth.h" +#endif + +#ifndef NUM_OUTPUT_CHANNELS +#define NUM_OUTPUT_CHANNELS 2 +#endif + +#ifndef MAX_SYNTH_VOICES +#define MAX_SYNTH_VOICES 64 +#endif + +#ifndef MAX_VIRTUAL_SYNTHESIZERS +#define MAX_VIRTUAL_SYNTHESIZERS 4 +#endif + +/* defines */ +#ifndef NUM_PRIMARY_VOICES +#define NUM_PRIMARY_VOICES MAX_SYNTH_VOICES +#elif !defined(NUM_SECONDARY_VOICES) +#define NUM_SECONDARY_VOICES (MAX_SYNTH_VOICES - NUM_PRIMARY_VOICES) +#endif + +#if defined(EAS_WT_SYNTH) +#define NUM_WT_VOICES MAX_SYNTH_VOICES + +/* FM on MCU */ +#elif defined(EAS_FM_SYNTH) +#define NUM_FM_VOICES MAX_SYNTH_VOICES + +/* wavetable drums on MCU, wavetable melodic on DSP */ +#elif defined(EAS_SPLIT_WT_SYNTH) +#define NUM_WT_VOICES MAX_SYNTH_VOICES + +/* wavetable drums and FM melodic on MCU */ +#elif defined(EAS_HYBRID_SYNTH) +#define NUM_WT_VOICES NUM_PRIMARY_VOICES +#define NUM_FM_VOICES NUM_SECONDARY_VOICES + +/* wavetable drums on MCU, FM melodic on DSP */ +#elif defined(EAS_SPLIT_HYBRID_SYNTH) +#define NUM_WT_VOICES NUM_PRIMARY_VOICES +#define NUM_FM_VOICES NUM_SECONDARY_VOICES + +/* FM synth on DSP */ +#elif defined(EAS_SPLIT_FM_SYNTH) +#define NUM_FM_VOICES MAX_SYNTH_VOICES + +#else +#error "Unrecognized architecture option" +#endif + +#define NUM_SYNTH_CHANNELS 16 + +#define DEFAULT_SYNTH_VOICES MAX_SYNTH_VOICES + +/* use the following values to specify unassigned channels or voices */ +#define UNASSIGNED_SYNTH_CHANNEL NUM_SYNTH_CHANNELS +#define UNASSIGNED_SYNTH_VOICE MAX_SYNTH_VOICES + + +/* synth parameters are updated every SYNTH_UPDATE_PERIOD_IN_SAMPLES */ +#define SYNTH_UPDATE_PERIOD_IN_SAMPLES (EAS_I32)(0x1L << SYNTH_UPDATE_PERIOD_IN_BITS) + +/* stealing weighting factors */ +#define NOTE_AGE_STEAL_WEIGHT 1 +#define NOTE_GAIN_STEAL_WEIGHT 4 +#define CHANNEL_POLY_STEAL_WEIGHT 12 +#define CHANNEL_PRIORITY_STEAL_WEIGHT 2 +#define NOTE_MATCH_PENALTY 128 +#define SYNTH_PRIORITY_WEIGHT 8 + +/* default synth master volume */ +#define DEFAULT_SYNTH_MASTER_VOLUME 0x7fff + +#define DEFAULT_SYNTH_PRIORITY 5 + +/* default tuning values */ +#define DEFAULT_PITCH_BEND_SENSITIVITY 200 /* 2 semitones */ +#define DEFAULT_FINE_PITCH 0 /* 0 cents */ +#define DEFAULT_COARSE_PITCH 0 /* 0 semitones */ + +/* default drum channel is 10, but is internally 9 due to unit offset */ +#define DEFAULT_DRUM_CHANNEL 9 + +/* drum channel can simultaneously play this many voices at most */ +#define DEFAULT_CHANNEL_POLYPHONY_LIMIT 2 + +/* default instrument is acoustic piano */ +#define DEFAULT_MELODY_BANK_MSB 0x79 +#define DEFAULT_RHYTHM_BANK_MSB 0x78 +#define DEFAULT_MELODY_BANK_NUMBER (DEFAULT_MELODY_BANK_MSB << 8) +#define DEFAULT_RHYTHM_BANK_NUMBER (DEFAULT_RHYTHM_BANK_MSB << 8) +#define DEFAULT_SYNTH_PROGRAM_NUMBER 0 + +#define DEFAULT_PITCH_BEND 0x2000 /* 0x2000 == (0x40 << 7) | 0x00 */ +#define DEFAULT_MOD_WHEEL 0 +#define DEFAULT_CHANNEL_VOLUME 0x64 +#define DEFAULT_PAN 0x40 /* decimal 64, center */ + +#ifdef _REVERB +#define DEFAULT_REVERB_SEND 40 /* some reverb */ +#endif + +#ifdef _CHORUS +#define DEFAULT_CHORUS_SEND 0 /* no chorus */ +#endif + +#define DEFAULT_EAS_FILTER_CUTOFF_FREQUENCY 0 /* EAS synth uses a different default */ +#define DEFAULT_FILTER_RESONANCE 0 +#define DEFAULT_EXPRESSION 0x7F + +#define DEFAULT_CHANNEL_PRESSURE 0 + +#define DEFAULT_REGISTERED_PARAM 0x3FFF + +#define DEFAULT_CHANNEL_STATIC_GAIN 0 +#define DEFAULT_CHANNEL_STATIC_PITCH 0 + +#define DEFAULT_LFO_MOD_WHEEL_TO_PITCH_CENTS 50 +#define DEFAULT_LFO_CHANNEL_PRESSURE_TO_PITCH_CENTS 50 + +#define DEFAULT_KEY_NUMBER 0x69 +#define DEFAULT_VELOCITY 0x64 +#define DEFAULT_REGION_INDEX 0 +#define DEFAULT_ARTICULATION_INDEX 0 +#define DEFAULT_VOICE_GAIN 0 +#define DEFAULT_AGE 0 +#define DEFAULT_SP_MIDI_PRIORITY 16 + + +/* filter defines */ +#define DEFAULT_FILTER_ZERO 0 +#define FILTER_CUTOFF_MAX_PITCH_CENTS 1919 +#define FILTER_CUTOFF_MIN_PITCH_CENTS -4467 +#define A5_PITCH_OFFSET_IN_CENTS 6900 + +/*------------------------------------ + * S_SYNTH_CHANNEL data structure + *------------------------------------ +*/ + +/* S_SYNTH_CHANNEL.m_nFlags */ +#define CHANNEL_FLAG_SUSTAIN_PEDAL 0x01 +#define CHANNEL_FLAG_MUTE 0x02 +#define CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS 0x04 +#define CHANNEL_FLAG_RHYTHM_CHANNEL 0x08 +#define CHANNEL_FLAG_EXTERNAL_AUDIO 0x10 +#define DEFAULT_CHANNEL_FLAGS 0 + +/* macros for extracting virtual synth and channel numbers */ +#define GET_VSYNTH(a) ((a) >> 4) +#define GET_CHANNEL(a) ((a) & 15) + +typedef struct s_synth_channel_tag +{ + /* use static channel parameters to reduce MIPs */ + /* parameters shared by multiple voices assigned to same channel */ + EAS_I32 staticPitch; /* (pitch bend * pitch sens) + fine pitch */ + EAS_I16 staticGain; /* (CC7 * CC11 * master vol)^2 */ + + EAS_U16 regionIndex; /* index of first region in program */ + + EAS_U16 bankNum; /* play programs from this bank */ + EAS_I16 pitchBend; /* pitch wheel value */ + EAS_I16 pitchBendSensitivity; + EAS_I16 registeredParam; /* currently selected registered param */ + + +#if defined(_FM_SYNTH) + EAS_I16 lfoAmt; /* amount of LFO to apply to voice */ +#endif + + EAS_U8 programNum; /* play this instrument number */ + EAS_U8 modWheel; /* CC1 */ + EAS_U8 volume; /* CC7 */ + EAS_U8 pan; /* CC10 */ + + EAS_U8 expression; /* CC11 */ + + /* the following parameters are controlled by RPNs */ + EAS_I8 finePitch; + EAS_I8 coarsePitch; + + EAS_U8 channelPressure; /* applied to all voices on a given channel */ + + EAS_U8 channelFlags; /* bit field channelFlags for */ + /* CC64, SP-MIDI channel masking */ + + EAS_U8 pool; /* SPMIDI channel voice pool */ + EAS_U8 mip; /* SPMIDI MIP setting */ + +#ifdef _REVERB + EAS_U8 reverbSend; /* CC91 */ +#endif + +#ifdef _CHORUS + EAS_U8 chorusSend; /* CC93 */ +#endif +} S_SYNTH_CHANNEL; + +/*------------------------------------ + * S_SYNTH_VOICE data structure + *------------------------------------ +*/ + +/* S_SYNTH_VOICE.m_nFlags */ +#define VOICE_FLAG_UPDATE_VOICE_PARAMETERS 0x01 +#define VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF 0x02 +#define VOICE_FLAG_DEFER_MIDI_NOTE_OFF 0x04 +#define VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET 0x08 +#define VOICE_FLAG_DEFER_MUTE 0x40 +#define DEFAULT_VOICE_FLAGS 0 + +/* S_SYNTH_VOICE.m_eState */ +typedef enum { + + eVoiceStateFree = 0, + eVoiceStateStart, + eVoiceStatePlay, + eVoiceStateRelease, + eVoiceStateMuting, + eVoiceStateStolen, + eVoiceStateInvalid /* should never be in this state! */ + +} E_VOICE_STATE; +#define DEFAULT_VOICE_STATE eVoiceStateFree + +typedef struct s_synth_voice_tag +{ + +/* These parameters are common to both wavetable and FM + * synthesizers. The voice manager should only access this data. + * Any other data should be manipulated by the code that is + * specific to that synthesizer and reflected back through the + * common state data available here. + */ + EAS_U16 regionIndex; /* index to wave and playback params */ + EAS_I16 gain; /* current gain */ + EAS_U16 age; /* large value means old note */ + EAS_U16 nextRegionIndex; /* index to wave and playback params */ + EAS_U8 voiceState; /* current voice state */ + EAS_U8 voiceFlags; /* misc flags/bit fields */ + EAS_U8 channel; /* this voice plays on this synth channel */ + EAS_U8 note; /* 12 <= key number <= 108 */ + EAS_U8 velocity; /* 0 <= velocity <= 127 */ + EAS_U8 nextChannel; /* play stolen voice on this channel */ + EAS_U8 nextNote; /* 12 <= key number <= 108 */ + EAS_U8 nextVelocity; /* 0 <= velocity <= 127 */ +} S_SYNTH_VOICE; + +/*------------------------------------ + * S_SYNTH data structure + * + * One instance for each MIDI stream + *------------------------------------ +*/ + +/* S_SYNTH.m_nFlags */ +#define SYNTH_FLAG_RESET_IS_REQUESTED 0x01 +#define SYNTH_FLAG_SP_MIDI_ON 0x02 +#define SYNTH_FLAG_UPDATE_ALL_CHANNEL_PARAMETERS 0x04 +#define SYNTH_FLAG_DEFERRED_MIDI_NOTE_OFF_PENDING 0x08 +#define DEFAULT_SYNTH_FLAGS SYNTH_FLAG_UPDATE_ALL_CHANNEL_PARAMETERS + +typedef struct s_synth_tag +{ + struct s_eas_data_tag *pEASData; + const S_EAS *pEAS; + +#ifdef DLS_SYNTHESIZER + S_DLS *pDLS; +#endif + +#ifdef EXTERNAL_AUDIO + EAS_EXT_PRG_CHG_FUNC cbProgChgFunc; + EAS_EXT_EVENT_FUNC cbEventFunc; + EAS_VOID_PTR *pExtAudioInstData; +#endif + + S_SYNTH_CHANNEL channels[NUM_SYNTH_CHANNELS]; + EAS_I32 totalNoteCount; + EAS_U16 maxPolyphony; + EAS_U16 numActiveVoices; + EAS_U16 masterVolume; + EAS_U8 channelsByPriority[NUM_SYNTH_CHANNELS]; + EAS_U8 poolCount[NUM_SYNTH_CHANNELS]; + EAS_U8 poolAlloc[NUM_SYNTH_CHANNELS]; + EAS_U8 synthFlags; + EAS_I8 globalTranspose; + EAS_U8 vSynthNum; + EAS_U8 refCount; + EAS_U8 priority; +} S_SYNTH; + +/*------------------------------------ + * S_VOICE_MGR data structure + * + * One instance for each EAS library instance + *------------------------------------ +*/ +typedef struct s_voice_mgr_tag +{ + S_SYNTH *pSynth[MAX_VIRTUAL_SYNTHESIZERS]; + EAS_PCM voiceBuffer[SYNTH_UPDATE_PERIOD_IN_SAMPLES]; + +#ifdef _FM_SYNTH + EAS_PCM operMixBuffer[SYNTH_UPDATE_PERIOD_IN_SAMPLES]; + S_FM_VOICE fmVoices[NUM_FM_VOICES]; +#endif + +#ifdef _WT_SYNTH + S_WT_VOICE wtVoices[NUM_WT_VOICES]; +#endif + +#ifdef _REVERB + EAS_PCM reverbSendBuffer[NUM_OUTPUT_CHANNELS * SYNTH_UPDATE_PERIOD_IN_SAMPLES]; +#endif + +#ifdef _CHORUS + EAS_PCM chorusSendBuffer[NUM_OUTPUT_CHANNELS * SYNTH_UPDATE_PERIOD_IN_SAMPLES]; +#endif + S_SYNTH_VOICE voices[MAX_SYNTH_VOICES]; + + EAS_SNDLIB_HANDLE pGlobalEAS; + +#ifdef DLS_SYNTHESIZER + S_DLS *pGlobalDLS; +#endif + +#ifdef _SPLIT_ARCHITECTURE + EAS_FRAME_BUFFER_HANDLE pFrameBuffer; +#endif + +#if defined(_SECONDARY_SYNTH) || defined(EAS_SPLIT_WT_SYNTH) + EAS_U16 maxPolyphonyPrimary; + EAS_U16 maxPolyphonySecondary; +#endif + + EAS_I32 workload; + EAS_I32 maxWorkLoad; + + EAS_U16 activeVoices; + EAS_U16 maxPolyphony; + + EAS_U16 age; + +/* limits the number of voice starts in a frame for split architecture */ +#ifdef MAX_VOICE_STARTS + EAS_U16 numVoiceStarts; +#endif +} S_VOICE_MGR; + +#endif /* #ifdef _EAS_SYNTH_H */ + + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_synth_protos.h b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_synth_protos.h new file mode 100755 index 0000000..b03af0f --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_synth_protos.h @@ -0,0 +1,60 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_synth_protos.h + * + * Contents and purpose: + * Declarations, interfaces, and prototypes for synth. + * + * Copyright Sonic Network Inc. 2004 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_SYNTH_PROTOS_H +#define _EAS_SYNTH_PROTOS_H + +/* includes */ +#include "eas_data.h" +#include "eas_sndlib.h" + +#ifdef _SPLIT_ARCHITECTURE +typedef struct s_frame_interface_tag +{ + EAS_BOOL (* EAS_CONST pfStartFrame)(EAS_FRAME_BUFFER_HANDLE pFrameBuffer); + EAS_BOOL (* EAS_CONST pfEndFrame)(EAS_FRAME_BUFFER_HANDLE pFrameBuffer, EAS_I32 *pMixBuffer, EAS_I16 masterGain); +} S_FRAME_INTERFACE; +#endif + +/* generic synthesizer interface */ +typedef struct +{ + EAS_RESULT (* EAS_CONST pfInitialize)(S_VOICE_MGR *pVoiceMgr); + EAS_RESULT (* EAS_CONST pfStartVoice)(S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_U16 regionIndex); + EAS_BOOL (* EAS_CONST pfUpdateVoice)(S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_I32 *pMixBuffer, EAS_I32 numSamples); + void (* EAS_CONST pfReleaseVoice)(S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum); + void (* EAS_CONST pfMuteVoice)(S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum); + void (* EAS_CONST pfSustainPedal)(S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, S_SYNTH_CHANNEL *pChannel, EAS_I32 voiceNum); + void (* EAS_CONST pfUpdateChannel)(S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel); +} S_SYNTH_INTERFACE; + +#endif + + + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_synthcfg.h b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_synthcfg.h new file mode 100755 index 0000000..78a4178 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_synthcfg.h @@ -0,0 +1,70 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_synthcfg.h + * + * Contents and purpose: + * Defines for various synth configurations + * + * Copyright Sonic Network Inc. 2004, 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 664 $ + * $Date: 2007-04-25 13:11:22 -0700 (Wed, 25 Apr 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_SYNTHCFG_H +#define _EAS_SYNTHCFG_H + +#if defined(EAS_WT_SYNTH) +#define _WT_SYNTH + +/* FM on MCU */ +#elif defined(EAS_FM_SYNTH) +#define _FM_SYNTH + +/* wavetable drums and FM melodic on MCU */ +#elif defined(EAS_HYBRID_SYNTH) +#define _WT_SYNTH +#define _FM_SYNTH +#define _SECONDARY_SYNTH +#define _HYBRID_SYNTH + +/* wavetable drums on MCU, wavetable melodic on DSP */ +#elif defined(EAS_SPLIT_WT_SYNTH) +#define _WT_SYNTH +#define _SPLIT_ARCHITECTURE + +/* wavetable drums on MCU, FM melodic on DSP */ +#elif defined(EAS_SPLIT_HYBRID_SYNTH) +#define _WT_SYNTH +#define _FM_SYNTH +#define _SECONDARY_SYNTH +#define _SPLIT_ARCHITECTURE +#define _HYBRID_SYNTH + +/* FM synth on DSP */ +#elif defined(EAS_SPLIT_FM_SYNTH) +#define _FM_SYNTH +#define _SPLIT_ARCHITECTURE + +#else +#error "Unrecognized architecture option" +#endif + +#endif + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_vm_protos.h b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_vm_protos.h new file mode 100755 index 0000000..20f7c09 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_vm_protos.h @@ -0,0 +1,1086 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_vm_protos.h + * + * Contents and purpose: + * Declarations, interfaces, and prototypes for voice manager. + * + * Copyright Sonic Network Inc. 2004 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 736 $ + * $Date: 2007-06-22 13:51:24 -0700 (Fri, 22 Jun 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_VM_PROTOS_H +#define _EAS_VM_PROTOS_H + +// includes +#include "eas_data.h" +#include "eas_sndlib.h" + +/*---------------------------------------------------------------------------- + * VMInitialize() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMInitialize (S_EAS_DATA *pEASData); + +/*---------------------------------------------------------------------------- + * VMInitMIDI() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMInitMIDI (S_EAS_DATA *pEASData, S_SYNTH **ppSynth); + +/*---------------------------------------------------------------------------- + * VMInitializeAllChannels() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +void VMInitializeAllChannels (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth); + +/*---------------------------------------------------------------------------- + * VMResetControllers() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +void VMResetControllers (S_SYNTH *pSynth); + +/*---------------------------------------------------------------------------- + * VMInitMIPTable() + *---------------------------------------------------------------------------- + * Purpose: + * Initialize the SP-MIDI MIP table + * + * Inputs: + * pEASData - pointer to synthesizer instance data + * mute - EAS_FALSE to unmute channels, EAS_TRUE to mute + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMInitMIPTable (S_SYNTH *pSynth); + +/*---------------------------------------------------------------------------- + * VMSetMIPEntry() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the priority and MIP level for a MIDI channel + * + * Inputs: + * pEASData - pointer to synthesizer instance data + * channel - MIDI channel number + * priority - priority (0-15 with 0 = highest priority) + * mip - maximum instantaneous polyphony + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMSetMIPEntry (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 priority, EAS_U8 mip); + +/*---------------------------------------------------------------------------- + * VMUpdateMIPTable() + *---------------------------------------------------------------------------- + * Purpose: + * This routine is called when the polyphony count in the synthesizer changes + * + * Inputs: + * pEASData - pointer to synthesizer instance data + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMUpdateMIPTable (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth); + +/*---------------------------------------------------------------------------- + * VMInitializeAllVoices() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +void VMInitializeAllVoices (S_VOICE_MGR *pVoiceMgr, EAS_INT vSynthNum); + +/*---------------------------------------------------------------------------- + * VMStartNote() + *---------------------------------------------------------------------------- + * Purpose: + * Update the synth's state to play the requested note on the requested + * channel if possible. + * + * Inputs: + * nChannel - the MIDI channel + * nKeyNumber - the MIDI key number for this note + * nNoteVelocity - the key velocity for this note + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +void VMStartNote (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 note, EAS_U8 velocity); + +/*---------------------------------------------------------------------------- + * VMCheckKeyGroup() + *---------------------------------------------------------------------------- + * Purpose: + * If the note that we've been asked to start is in the same key group as + * any currently playing notes, then we must shut down the currently playing + * note in the same key group and then start the newly requested note. + * + * Inputs: + * nChannel - synth channel that wants to start a new note + * nKeyNumber - new note's midi note number + * nRegionIndex - calling routine finds this index and gives to us + * nNoteVelocity - new note's velocity + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * pbVoiceStealingRequired - flag: this routine sets true if we needed to + * steal a voice + * + * Side Effects: + * gsSynthObject.m_sVoice[free voice num].m_nKeyNumber may be assigned + * gsSynthObject.m_sVoice[free voice num].m_nVelocity may be assigned + *---------------------------------------------------------------------------- +*/ +void VMCheckKeyGroup (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U16 keyGroup, EAS_U8 channel); + +/*---------------------------------------------------------------------------- + * VMCheckPolyphonyLimiting() + *---------------------------------------------------------------------------- + * Purpose: + * We only play at most 2 of the same note on a MIDI channel. + * E.g., if we are asked to start note 36, and there are already two voices + * that are playing note 36, then we must steal the voice playing + * the oldest note 36 and use that stolen voice to play the new note 36. + * + * Inputs: + * nChannel - synth channel that wants to start a new note + * nKeyNumber - new note's midi note number + * nNoteVelocity - new note's velocity + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * pbVoiceStealingRequired - flag: this routine sets true if we needed to + * steal a voice + * * + * Side Effects: + * psSynthObject->m_sVoice[free voice num].m_nKeyNumber may be assigned + * psSynthObject->m_sVoice[free voice num].m_nVelocity may be assigned + *---------------------------------------------------------------------------- +*/ +EAS_BOOL VMCheckPolyphonyLimiting (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 note, EAS_U8 velocity, EAS_U16 regionIndex, EAS_I32 lowVoice, EAS_I32 highVoice); + +/*---------------------------------------------------------------------------- + * VMStopNote() + *---------------------------------------------------------------------------- + * Purpose: + * Update the synth's state to end the requested note on the requested + * channel. + * + * Inputs: + * nChannel - the MIDI channel + * nKeyNumber - the key number of the note to stop + * nNoteVelocity - the note-off velocity + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * Side Effects: + * gsSynthObject.m_sVoice[free voice num].m_nSynthChannel may be assigned + * gsSynthObject.m_sVoice[free voice num].m_nKeyNumber is assigned + * gsSynthObject.m_sVoice[free voice num].m_nVelocity is assigned + *---------------------------------------------------------------------------- +*/ +void VMStopNote (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 key, EAS_U8 velocity); + +/*---------------------------------------------------------------------------- + * VMFindAvailableVoice() + *---------------------------------------------------------------------------- + * Purpose: + * Find an available voice and return the voice number if available. + * + * Inputs: + * pnVoiceNumber - really an output, see below + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * pnVoiceNumber - returns the voice number of available voice if found + * success - if there is an available voice + * failure - otherwise + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMFindAvailableVoice (S_VOICE_MGR *pVoiceMgr, EAS_INT *pVoiceNumber, EAS_I32 lowVoice, EAS_I32 highVoice); + +/*---------------------------------------------------------------------------- + * VMStealVoice() + *---------------------------------------------------------------------------- + * Purpose: + * Steal a voice and return the voice number + * + * Stealing algorithm: steal the best choice with minimal work, taking into + * account SP-Midi channel priorities and polyphony allocation. + * + * In one pass through all the voices, figure out which voice to steal + * taking into account a number of different factors: + * Priority of the voice's MIDI channel + * Number of voices over the polyphony allocation for voice's MIDI channel + * Amplitude of the voice + * Note age + * Key velocity (for voices that haven't been started yet) + * If any matching notes are found + * + * Inputs: + * nChannel - the channel that this voice wants to be started on + * nKeyNumber - the key number for this new voice + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * pnVoiceNumber - voice stolen + * EAS_RESULT EAS_SUCCESS - always successful + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMStealVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_INT *pVoiceNumber, EAS_U8 channel, EAS_U8 note, EAS_I32 lowVoice, EAS_I32 highVoice); + +/*---------------------------------------------------------------------------- + * VMAddSamples() + *---------------------------------------------------------------------------- + * Purpose: + * Synthesize the requested number of samples. + * + * Inputs: + * nNumSamplesToAdd - number of samples to write to buffer + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * number of samples actually written to buffer + * + * Side Effects: + * - samples are added to the presently free buffer + * + *---------------------------------------------------------------------------- +*/ +EAS_I32 VMAddSamples (S_VOICE_MGR *pVoiceMgr, EAS_I32 *pMixBuffer, EAS_I32 numSamplesToAdd); + +/*---------------------------------------------------------------------------- + * VMProgramChange() + *---------------------------------------------------------------------------- + * Purpose: + * Change the instrument (program) for the given channel. + * + * Depending on the program number, and the bank selected for this channel, the + * program may be in ROM, RAM (from SMAF or CMX related RAM wavetable), or + * Alternate wavetable (from mobile DLS or other DLS file) + * + * This function figures out what wavetable should be used, and sets it up as the + * wavetable to use for this channel. Also the channel may switch from a melodic + * channel to a rhythm channel, or vice versa. + * + * Inputs: + * + * Outputs: + * Side Effects: + * gsSynthObject.m_sChannel[nChannel].m_nProgramNumber is likely changed + * gsSynthObject.m_sChannel[nChannel].m_psEAS may be changed + * gsSynthObject.m_sChannel[nChannel].m_bRhythmChannel may be changed + * + *---------------------------------------------------------------------------- +*/ +void VMProgramChange (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 program); + +/*---------------------------------------------------------------------------- + * VMChannelPressure() + *---------------------------------------------------------------------------- + * Purpose: + * Change the channel pressure for the given channel + * + * Inputs: + * nChannel - the MIDI channel + * nVelocity - the channel pressure value + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * Side Effects: + * gsSynthObject.m_sChannel[nChannel].m_nChannelPressure is updated + *---------------------------------------------------------------------------- +*/ +void VMChannelPressure (S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 value); + +/*---------------------------------------------------------------------------- + * VMPitchBend() + *---------------------------------------------------------------------------- + * Purpose: + * Change the pitch wheel value for the given channel. + * This routine constructs the proper 14-bit argument when the calling routine + * passes the pitch LSB and MSB. + * + * Note: some midi disassemblers display a bipolar pitch bend value. + * We can display the bipolar value using + * if m_nPitchBend >= 0x2000 + * bipolar pitch bend = postive (m_nPitchBend - 0x2000) + * else + * bipolar pitch bend = negative (0x2000 - m_nPitchBend) + * + * Inputs: + * nChannel - the MIDI channel + * nPitchLSB - the LSB byte from the pitch bend message + * nPitchMSB - the MSB byte from the message + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * gsSynthObject.m_sChannel[nChannel].m_nPitchBend is changed + * + *---------------------------------------------------------------------------- +*/ +void VMPitchBend (S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 pitchLSB, EAS_U8 pitchMSB); + +/*---------------------------------------------------------------------------- + * VMControlChange() + *---------------------------------------------------------------------------- + * Purpose: + * Change the controller (or mode) for the given channel. + * + * Inputs: + * nChannel - the MIDI channel + * nControllerNumber - the controller number + * nControlValue - the controller number for this control change + * nControlValue - the value for this control change + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * Side Effects: + * gsSynthObject.m_sChannel[nChannel] controller is changed + * + *---------------------------------------------------------------------------- +*/ +void VMControlChange (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 controller, EAS_U8 value); + +/*---------------------------------------------------------------------------- + * VMUpdateRPNStateMachine() + *---------------------------------------------------------------------------- + * Purpose: + * Call this function when we want to parse a stream of RPN messages. + * NOTE: The synth has only one set of global RPN data instead of RPN data + * per channel. + * So actually, we don't really need to look at the nChannel parameter, + * but we pass it to facilitate future upgrades. Furthermore, we only + * support RPN0 (pitch bend sensitivity), RPN1 (fine tuning) and + * RPN2 (coarse tuning). Any other RPNs are rejected. + * + * Inputs: + * nChannel - the MIDI channel + * nControllerNumber - the RPN controller number + * nControlValue - the value for this control change + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * gsSynthObject.m_RPN0 (or m_RPN1 or m_RPN2) may be updated if the + * proper RPN message sequence is parsed. + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMUpdateRPNStateMachine (S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 controller, EAS_U8 value); + +/*---------------------------------------------------------------------------- + * VMUpdateStaticChannelParameters() + *---------------------------------------------------------------------------- + * Purpose: + * Update all of the static channel parameters for channels that have had + * a controller change values + * Or if the synth has signalled that all channels must forcibly + * be updated + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * none + * + * Side Effects: + * - psSynthObject->m_sChannel[].m_nStaticGain and m_nStaticPitch + * are updated for channels whose controller values have changed + * or if the synth has signalled that all channels must forcibly + * be updated + *---------------------------------------------------------------------------- +*/ +void VMUpdateStaticChannelParameters (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth); + +/*---------------------------------------------------------------------------- + * VMReleaseAllDeferredNoteOffs() + *---------------------------------------------------------------------------- + * Purpose: + * Call this functin when the sustain flag is presently set but + * we are now transitioning from damper pedal on to + * damper pedal off. This means all notes in this channel + * that received a note off while the damper pedal was on, and + * had their note-off requests deferred, should now proceed to + * the release state. + * + * Inputs: + * nChannel - this channel has its sustain pedal transitioning from on to off + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * Side Effects: + * any voice with deferred note offs on this channel are updated such that + * + * + *---------------------------------------------------------------------------- +*/ +void VMReleaseAllDeferredNoteOffs (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel); + +/*---------------------------------------------------------------------------- + * VMCatchNotesForSustainPedal() + *---------------------------------------------------------------------------- + * Purpose: + * Call this function when the sustain flag is presently clear and + * the damper pedal is off and we are transitioning from damper pedal OFF to + * damper pedal ON. Currently sounding notes should be left + * unchanged. However, we should try to "catch" notes if possible. + * If any notes have levels >= sustain level, catch them, + * otherwise, let them continue to release. + * + * Inputs: + * nChannel - this channel has its sustain pedal transitioning from on to off + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * Side Effects: + * any voice with deferred note offs on this channel are updated such that + * psVoice->m_sEG1.m_eState = eEnvelopeStateSustainPedal + *---------------------------------------------------------------------------- +*/ +void VMCatchNotesForSustainPedal (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel); + +/*---------------------------------------------------------------------------- + * VMUpdateAllNotesAge() + *---------------------------------------------------------------------------- + * Purpose: + * Increment the note age for all voices older than the age of the voice + * that is stopping, effectively making the voices "younger". + * + * Inputs: + * nAge - age of voice that is going away + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * m_nAge for some voices is incremented + *---------------------------------------------------------------------------- +*/ +void VMUpdateAllNotesAge (S_VOICE_MGR *pVoiceMgr, EAS_U16 nAge); + +/*---------------------------------------------------------------------------- + * VMFindRegionIndex() + *---------------------------------------------------------------------------- + * Purpose: + * Find the region index for the given instrument using the midi key number + * and the RPN2 (coarse tuning) value. By using RPN2 as part of the + * region selection process, we reduce the amount a given sample has + * to be transposed by selecting the closest recorded root instead. + * + * Inputs: + * nChannel - current channel for this note + * nKeyNumber - current midi note number + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * pnRegionIndex - valid only if we returned success + * success if we found the region index number, otherwise + * failure + * + * Side Effects: + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMFindRegionIndex (S_VOICE_MGR *pVoiceMgr, EAS_U8 channel, EAS_U8 note, EAS_U16 *pRegionIndex); + +/*---------------------------------------------------------------------------- + * VMIncRefCount() + *---------------------------------------------------------------------------- + * Increment reference count for virtual synth + *---------------------------------------------------------------------------- +*/ +void VMIncRefCount (S_SYNTH *pSynth); + +/*---------------------------------------------------------------------------- + * VMReset() + *---------------------------------------------------------------------------- + * Purpose: + * We call this routine to start the process of reseting the synth. + * This routine sets a flag for the entire synth indicating that we want + * to reset. + * We also force all voices to mute quickly. + * However, we do not actually perform any synthesis in this routine. That + * is, we do not ramp the voices down from this routine, but instead, we + * let the "regular" synth processing steps take care of adding the ramp + * down samples to the output buffer. After we are sure that all voices + * have completed ramping down, we continue the process of resetting the + * synth (from another routine). + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * - set a flag (in gsSynthObject.m_nFlags) indicating synth reset requested. + * - force all voices to update their envelope states to mute + * + *---------------------------------------------------------------------------- +*/ +void VMReset (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_BOOL force); + +/*---------------------------------------------------------------------------- + * VMMuteAllVoices() + *---------------------------------------------------------------------------- + * Purpose: + * We call this in an emergency reset situation. + * This forces all voices to mute quickly. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * - forces all voices to update their envelope states to mute + * + *---------------------------------------------------------------------------- +*/ +void VMMuteVoice (S_VOICE_MGR *pVoiceMgr, EAS_I32 voiceNum); +void VMMuteAllVoices (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth); + +/*---------------------------------------------------------------------------- + * VMReleaseAllVoices() + *---------------------------------------------------------------------------- + * Purpose: + * We call this after we've encountered the end of the Midi file. + * This ensures all voice are either in release (because we received their + * note off already) or forces them to mute quickly. + * We use this as a safety to prevent bad midi files from playing forever. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * - forces all voices to update their envelope states to release or mute + * + *---------------------------------------------------------------------------- +*/ +void VMReleaseAllVoices (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth); + +/*---------------------------------------------------------------------------- + * VMAllNotesOff() + *---------------------------------------------------------------------------- + * Purpose: + * Quickly mute all notes on the given channel. + * + * Inputs: + * nChannel - quickly turn off all notes on this channel + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * - forces all voices on this channel to update their envelope states to mute + * + *---------------------------------------------------------------------------- +*/ +void VMAllNotesOff (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel); + +/*---------------------------------------------------------------------------- + * VMDeferredStopNote() + *---------------------------------------------------------------------------- + * Purpose: + * Stop the notes that had deferred note-off requests. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * None. + * + * Side Effects: + * voices that have had deferred note-off requests are now put into release + * gsSynthObject.m_sVoice[i].m_nFlags has the VOICE_FLAG_DEFER_MIDI_NOTE_OFF + * cleared + *---------------------------------------------------------------------------- +*/ +void VMDeferredStopNote (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth); + +/*---------------------------------------------------------------------------- + * VMSetSynthPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Set the synth to a new polyphony value. Value must be >= 1 and + * <= MAX_SYNTH_VOICES. This function will pin the polyphony at those limits + * + * Inputs: + * pVoiceMgr pointer to synthesizer data + * synth synthesizer number (0 = onboard, 1 = DSP) + * polyphonyCount desired polyphony count + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMSetSynthPolyphony (S_VOICE_MGR *pVoiceMgr, EAS_I32 synth, EAS_I32 polyphonyCount); + +/*---------------------------------------------------------------------------- + * VMGetSynthPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Set the synth to a new polyphony value. Value must be >= 1 and + * <= MAX_SYNTH_VOICES. This function will pin the polyphony at those limits + * + * Inputs: + * pVoiceMgr pointer to synthesizer data + * synth synthesizer number (0 = onboard, 1 = DSP) + * polyphonyCount desired polyphony count + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMGetSynthPolyphony (S_VOICE_MGR *pVoiceMgr, EAS_I32 synth, EAS_I32 *pPolyphonyCount); + +/*---------------------------------------------------------------------------- + * VMSetPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Set the virtual synth polyphony. 0 = no limit (i.e. can use + * all available voices). + * + * Inputs: + * pVoiceMgr pointer to synthesizer data + * polyphonyCount desired polyphony count + * pSynth pointer to virtual synth + * + * Outputs: + * Returns error code + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMSetPolyphony (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 polyphonyCount); + +/*---------------------------------------------------------------------------- + * VMGetPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current polyphony setting + * + * Inputs: + * pVoiceMgr pointer to synthesizer data + * pSynth pointer to virtual synth + * pPolyphonyCount pointer to variable to receive data + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMGetPolyphony (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 *pPolyphonyCount); + +/*---------------------------------------------------------------------------- + * VMSetPriority() + *---------------------------------------------------------------------------- + * Purpose: + * Set the virtual synth priority + * + * Inputs: + * pVoiceMgr pointer to synthesizer data + * priority new priority + * pSynth pointer to virtual synth + * + * Outputs: + * Returns error code + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMSetPriority (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 priority); + +/*---------------------------------------------------------------------------- + * VMGetPriority() + *---------------------------------------------------------------------------- + * Purpose: + * Get the virtual synth priority + * + * Inputs: + * pVoiceMgr pointer to synthesizer data + * pPriority pointer to variable to hold priority + * pSynth pointer to virtual synth + * + * Outputs: + * Returns error code + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMGetPriority (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 *pPriority); + +/*---------------------------------------------------------------------------- + * VMSetVolume() + *---------------------------------------------------------------------------- + * Purpose: + * Set the master volume for this sequence + * + * Inputs: + * nSynthVolume - the desired master volume + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * + * Side Effects: + * overrides any previously set master volume from sysex + * + *---------------------------------------------------------------------------- +*/ +void VMSetVolume (S_SYNTH *pSynth, EAS_U16 masterVolume); + +/*---------------------------------------------------------------------------- + * VMSetPitchBendRange() + *---------------------------------------------------------------------------- + * Set the pitch bend range for the given channel. + *---------------------------------------------------------------------------- +*/ +void VMSetPitchBendRange (S_SYNTH *pSynth, EAS_INT channel, EAS_I16 pitchBendRange); + +/*---------------------------------------------------------------------------- + * VMSetEASLib() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the pointer to the sound library + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMSetGlobalEASLib (S_VOICE_MGR *pVoiceMgr, EAS_SNDLIB_HANDLE pEAS); +EAS_RESULT VMSetEASLib (S_SYNTH *pSynth, EAS_SNDLIB_HANDLE pEAS); + +#ifdef DLS_SYNTHESIZER +/*---------------------------------------------------------------------------- + * VMSetDLSLib() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the pointer to the sound library + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMSetGlobalDLSLib (EAS_DATA_HANDLE pEASData, EAS_DLSLIB_HANDLE pDLS); +EAS_RESULT VMSetDLSLib (S_SYNTH *pSynth, EAS_DLSLIB_HANDLE pDLS); +#endif + +/*---------------------------------------------------------------------------- + * VMSetTranposition() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the global key transposition used by the synthesizer. + * Transposes all melodic instruments up or down by the specified + * amount. Range is limited to +/-12 semitones. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * transposition - transpose amount (+/-12) + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMSetTranposition (S_SYNTH *pSynth, EAS_I32 transposition); + +/*---------------------------------------------------------------------------- + * VMGetTranposition() + *---------------------------------------------------------------------------- + * Purpose: + * Gets the global key transposition used by the synthesizer. + * Transposes all melodic instruments up or down by the specified + * amount. Range is limited to +/-12 semitones. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMGetTranposition (S_SYNTH *pSynth, EAS_I32 *pTransposition); + +/*---------------------------------------------------------------------------- + * VMGetNoteCount() + *---------------------------------------------------------------------------- +* Returns the total note count +*---------------------------------------------------------------------------- +*/ +EAS_I32 VMGetNoteCount (S_SYNTH *pSynth); + +/*---------------------------------------------------------------------------- + * VMRender() + *---------------------------------------------------------------------------- + * Purpose: + * This routine renders a frame of audio + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * pVoicesRendered - number of voices rendered this frame + * + * Side Effects: + * sets psMidiObject->m_nMaxWorkloadPerFrame + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMRender (S_VOICE_MGR *pVoiceMgr, EAS_I32 numSamples, EAS_I32 *pMixBuffer, EAS_I32 *pVoicesRendered); + +/*---------------------------------------------------------------------------- + * VMInitWorkload() + *---------------------------------------------------------------------------- + * Purpose: + * Clears the workload counter + * + * Inputs: + * pVoiceMgr - pointer to instance data + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMInitWorkload (S_VOICE_MGR *pVoiceMgr); + +/*---------------------------------------------------------------------------- + * VMSetWorkload() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the max workload for a single frame. + * + * Inputs: + * pVoiceMgr - pointer to instance data + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMSetWorkload (S_VOICE_MGR *pVoiceMgr, EAS_I32 maxWorkLoad); + +/*---------------------------------------------------------------------------- + * VMCheckWorkload() + *---------------------------------------------------------------------------- + * Purpose: + * Checks to see if work load has been exceeded on this frame. + * + * Inputs: + * pVoiceMgr - pointer to instance data + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_BOOL VMCheckWorkload (S_VOICE_MGR *pVoiceMgr); + +/*---------------------------------------------------------------------------- + * VMActiveVoices() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the number of active voices in the synthesizer. + * + * Inputs: + * pEASData - pointer to instance data + * + * Outputs: + * Returns the number of active voices + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_I32 VMActiveVoices (S_SYNTH *pSynth); + +/*---------------------------------------------------------------------------- + * VMMIDIShutdown() + *---------------------------------------------------------------------------- + * Purpose: + * Clean up any Synth related system issues. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * None + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMMIDIShutdown (S_EAS_DATA *pEASData, S_SYNTH *pSynth); + +/*---------------------------------------------------------------------------- + * VMShutdown() + *---------------------------------------------------------------------------- + * Purpose: + * Clean up any Synth related system issues. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * None + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMShutdown (S_EAS_DATA *pEASData); + +#ifdef EXTERNAL_AUDIO +/*---------------------------------------------------------------------------- + * EAS_RegExtAudioCallback() + *---------------------------------------------------------------------------- + * Register a callback for external audio processing + *---------------------------------------------------------------------------- +*/ +void VMRegExtAudioCallback (S_SYNTH *pSynth, EAS_VOID_PTR pInstData, EAS_EXT_PRG_CHG_FUNC cbProgChgFunc, EAS_EXT_EVENT_FUNC cbEventFunc); + +/*---------------------------------------------------------------------------- + * VMGetMIDIControllers() + *---------------------------------------------------------------------------- + * Returns the MIDI controller values on the specified channel + *---------------------------------------------------------------------------- +*/ +void VMGetMIDIControllers (S_SYNTH *pSynth, EAS_U8 channel, S_MIDI_CONTROLLERS *pControl); +#endif + +#ifdef _SPLIT_ARCHITECTURE +/*---------------------------------------------------------------------------- + * VMStartFrame() + *---------------------------------------------------------------------------- + * Purpose: + * Starts an audio frame + * + * Inputs: + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_BOOL VMStartFrame (S_EAS_DATA *pEASData); + +/*---------------------------------------------------------------------------- + * VMEndFrame() + *---------------------------------------------------------------------------- + * Purpose: + * Stops an audio frame + * + * Inputs: + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_BOOL VMEndFrame (S_EAS_DATA *pEASData); +#endif + +#endif /* #ifdef _EAS_VM_PROTOS_H */ + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_voicemgt.c b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_voicemgt.c new file mode 100755 index 0000000..ab0b776 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_voicemgt.c @@ -0,0 +1,3971 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_voicemgt.c + * + * Contents and purpose: + * Implements the synthesizer functions. + * + * Copyright Sonic Network Inc. 2004 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 794 $ + * $Date: 2007-08-01 00:08:48 -0700 (Wed, 01 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +/* includes */ +#include "eas.h" +#include "eas_data.h" +#include "eas_config.h" +#include "eas_report.h" +#include "eas_midictrl.h" +#include "eas_host.h" +#include "eas_synth_protos.h" +#include "eas_vm_protos.h" + +#ifdef DLS_SYNTHESIZER +#include "eas_mdls.h" +#endif + +// #define _DEBUG_VM + +/* some defines for workload */ +#define WORKLOAD_AMOUNT_SMALL_INCREMENT 5 +#define WORKLOAD_AMOUNT_START_NOTE 10 +#define WORKLOAD_AMOUNT_STOP_NOTE 10 +#define WORKLOAD_AMOUNT_KEY_GROUP 10 +#define WORKLOAD_AMOUNT_POLY_LIMIT 10 + +/* pointer to base sound library */ +extern S_EAS easSoundLib; + +#ifdef TEST_HARNESS +extern S_EAS easTestLib; +EAS_SNDLIB_HANDLE VMGetLibHandle(EAS_INT libNum) +{ + switch (libNum) + { + case 0: + return &easSoundLib; +#ifdef _WT_SYNTH + case 1: + return &easTestLib; +#endif + default: + return NULL; + } +} +#endif + +/* pointer to synthesizer interface(s) */ +#ifdef _WT_SYNTH +extern const S_SYNTH_INTERFACE wtSynth; +#endif + +#ifdef _FM_SYNTH +extern const S_SYNTH_INTERFACE fmSynth; +#endif + +typedef S_SYNTH_INTERFACE *S_SYNTH_INTERFACE_HANDLE; + +/* wavetable on MCU */ +#if defined(EAS_WT_SYNTH) +const S_SYNTH_INTERFACE *const pPrimarySynth = &wtSynth; + +/* FM on MCU */ +#elif defined(EAS_FM_SYNTH) +const S_SYNTH_INTERFACE *const pPrimarySynth = &fmSynth; + +/* wavetable drums on MCU, FM melodic on DSP */ +#elif defined(EAS_HYBRID_SYNTH) +const S_SYNTH_INTERFACE *const pPrimarySynth = &wtSynth; +const S_SYNTH_INTERFACE *const pSecondarySynth = &fmSynth; + +/* wavetable drums on MCU, wavetable melodic on DSP */ +#elif defined(EAS_SPLIT_WT_SYNTH) +const S_SYNTH_INTERFACE *const pPrimarySynth = &wtSynth; +extern const S_FRAME_INTERFACE wtFrameInterface; +const S_FRAME_INTERFACE *const pFrameInterface = &wtFrameInterface; + +/* wavetable drums on MCU, FM melodic on DSP */ +#elif defined(EAS_SPLIT_HYBRID_SYNTH) +const S_SYNTH_INTERFACE *const pPrimarySynth = &wtSynth; +const S_SYNTH_INTERFACE *const pSecondarySynth = &fmSynth; +extern const S_FRAME_INTERFACE fmFrameInterface; +const S_FRAME_INTERFACE *const pFrameInterface = &fmFrameInterface; + +/* FM on DSP */ +#elif defined(EAS_SPLIT_FM_SYNTH) +const S_SYNTH_INTERFACE *const pPrimarySynth = &fmSynth; +extern const S_FRAME_INTERFACE fmFrameInterface; +const S_FRAME_INTERFACE *const pFrameInterface = &fmFrameInterface; + +#else +#error "Undefined architecture option" +#endif + +/*---------------------------------------------------------------------------- + * inline functions + *---------------------------------------------------------------------------- +*/ +EAS_INLINE const S_REGION* GetRegionPtr (S_SYNTH *pSynth, EAS_U16 regionIndex) +{ +#if defined(DLS_SYNTHESIZER) + if (regionIndex & FLAG_RGN_IDX_DLS_SYNTH) + return &pSynth->pDLS->pDLSRegions[regionIndex & REGION_INDEX_MASK].wtRegion.region; +#endif +#if defined(_HYBRID_SYNTH) + if (regionIndex & FLAG_RGN_IDX_FM_SYNTH) + return &pSynth->pEAS->pFMRegions[regionIndex & REGION_INDEX_MASK].region; + else + return &pSynth->pEAS->pWTRegions[regionIndex].region; +#elif defined(_WT_SYNTH) + return &pSynth->pEAS->pWTRegions[regionIndex].region; +#elif defined(_FM_SYNTH) + return &pSynth->pEAS->pFMRegions[regionIndex].region; +#endif +} + +/*lint -esym(715, voiceNum) used in some implementation */ +EAS_INLINE const S_SYNTH_INTERFACE* GetSynthPtr (EAS_INT voiceNum) +{ +#if defined(_HYBRID_SYNTH) + if (voiceNum < NUM_PRIMARY_VOICES) + return pPrimarySynth; + else + return pSecondarySynth; +#else + return pPrimarySynth; +#endif +} + +EAS_INLINE EAS_INT GetAdjustedVoiceNum (EAS_INT voiceNum) +{ +#if defined(_HYBRID_SYNTH) + if (voiceNum >= NUM_PRIMARY_VOICES) + return voiceNum - NUM_PRIMARY_VOICES; +#endif + return voiceNum; +} + +EAS_INLINE EAS_U8 VSynthToChannel (S_SYNTH *pSynth, EAS_U8 channel) +{ + /*lint -e{734} synthNum is always 0-15 */ + return channel | (pSynth->vSynthNum << 4); +} + +/*---------------------------------------------------------------------------- + * InitVoice() + *---------------------------------------------------------------------------- + * Initialize a synthesizer voice + *---------------------------------------------------------------------------- +*/ +void InitVoice (S_SYNTH_VOICE *pVoice) +{ + pVoice->channel = UNASSIGNED_SYNTH_CHANNEL; + pVoice->nextChannel = UNASSIGNED_SYNTH_CHANNEL; + pVoice->note = pVoice->nextNote = DEFAULT_KEY_NUMBER; + pVoice->velocity = pVoice->nextVelocity = DEFAULT_VELOCITY; + pVoice->regionIndex = DEFAULT_REGION_INDEX; + pVoice->age = DEFAULT_AGE; + pVoice->voiceFlags = DEFAULT_VOICE_FLAGS; + pVoice->voiceState = DEFAULT_VOICE_STATE; +} + +/*---------------------------------------------------------------------------- + * IncVoicePoolCount() + *---------------------------------------------------------------------------- + * Updates the voice pool count when a voice changes state + *---------------------------------------------------------------------------- +*/ +static void IncVoicePoolCount (S_VOICE_MGR *pVoiceMgr, S_SYNTH_VOICE *pVoice) +{ + S_SYNTH *pSynth; + EAS_INT pool; + + /* ignore muting voices */ + if (pVoice->voiceState == eVoiceStateMuting) + return; + + if (pVoice->voiceState == eVoiceStateStolen) + { + pSynth = pVoiceMgr->pSynth[GET_VSYNTH(pVoice->nextChannel)]; + pool = pSynth->channels[GET_CHANNEL(pVoice->nextChannel)].pool; + } + else + { + pSynth = pVoiceMgr->pSynth[GET_VSYNTH(pVoice->channel)]; + pool = pSynth->channels[GET_CHANNEL(pVoice->channel)].pool; + } + + pSynth->poolCount[pool]++; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IncVoicePoolCount: Synth=%d pool=%d\n", pSynth->vSynthNum, pool); */ } +#endif +} + +/*---------------------------------------------------------------------------- + * DecVoicePoolCount() + *---------------------------------------------------------------------------- + * Updates the voice pool count when a voice changes state + *---------------------------------------------------------------------------- +*/ +static void DecVoicePoolCount (S_VOICE_MGR *pVoiceMgr, S_SYNTH_VOICE *pVoice) +{ + S_SYNTH *pSynth; + EAS_INT pool; + + /* ignore muting voices */ + if (pVoice->voiceState == eVoiceStateMuting) + return; + + if (pVoice->voiceState == eVoiceStateStolen) + { + pSynth = pVoiceMgr->pSynth[GET_VSYNTH(pVoice->nextChannel)]; + pool = pSynth->channels[GET_CHANNEL(pVoice->nextChannel)].pool; + } + else + { + pSynth = pVoiceMgr->pSynth[GET_VSYNTH(pVoice->channel)]; + pool = pSynth->channels[GET_CHANNEL(pVoice->channel)].pool; + } + + pSynth->poolCount[pool]--; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "DecVoicePoolCount: Synth=%d pool=%d\n", pSynth->vSynthNum, pool); */ } +#endif +} + +/*---------------------------------------------------------------------------- + * VMInitialize() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMInitialize (S_EAS_DATA *pEASData) +{ + S_VOICE_MGR *pVoiceMgr; + EAS_INT i; + + /* check Configuration Module for data allocation */ + if (pEASData->staticMemoryModel) + pVoiceMgr = EAS_CMEnumData(EAS_CM_SYNTH_DATA); + else + pVoiceMgr = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_VOICE_MGR)); + if (!pVoiceMgr) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitialize: Failed to allocate synthesizer memory\n"); */ } + return EAS_ERROR_MALLOC_FAILED; + } + EAS_HWMemSet(pVoiceMgr, 0, sizeof(S_VOICE_MGR)); + + /* initialize non-zero variables */ + pVoiceMgr->pGlobalEAS = (S_EAS*) &easSoundLib; + pVoiceMgr->maxPolyphony = (EAS_U16) MAX_SYNTH_VOICES; + +#if defined(_SECONDARY_SYNTH) || defined(EAS_SPLIT_WT_SYNTH) + pVoiceMgr->maxPolyphonyPrimary = NUM_PRIMARY_VOICES; + pVoiceMgr->maxPolyphonySecondary = NUM_SECONDARY_VOICES; +#endif + + /* set max workload to zero */ + pVoiceMgr->maxWorkLoad = 0; + + /* initialize the voice manager parameters */ + for (i = 0; i < MAX_SYNTH_VOICES; i++) + InitVoice(&pVoiceMgr->voices[i]); + + /* initialize the synth */ + /*lint -e{522} return unused at this time */ + pPrimarySynth->pfInitialize(pVoiceMgr); + + /* initialize the off-chip synth */ +#ifdef _HYBRID_SYNTH + /*lint -e{522} return unused at this time */ + pSecondarySynth->pfInitialize(pVoiceMgr); +#endif + + pEASData->pVoiceMgr = pVoiceMgr; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMInitMIDI() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMInitMIDI (S_EAS_DATA *pEASData, S_SYNTH **ppSynth) +{ + EAS_RESULT result; + S_SYNTH *pSynth; + EAS_INT virtualSynthNum; + + *ppSynth = NULL; + + /* static memory model only allows one synth */ + if (pEASData->staticMemoryModel) + { + if (pEASData->pVoiceMgr->pSynth[0] != NULL) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitMIDI: No virtual synthesizer support for static memory model\n"); */ } + return EAS_ERROR_NO_VIRTUAL_SYNTHESIZER; + } + + /* check Configuration Module for data allocation */ + pSynth = EAS_CMEnumData(EAS_CM_MIDI_DATA); + virtualSynthNum = 0; + } + + /* dynamic memory model */ + else + { + for (virtualSynthNum = 0; virtualSynthNum < MAX_VIRTUAL_SYNTHESIZERS; virtualSynthNum++) + if (pEASData->pVoiceMgr->pSynth[virtualSynthNum] == NULL) + break; + if (virtualSynthNum == MAX_VIRTUAL_SYNTHESIZERS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitMIDI: Exceeded number of active virtual synthesizers"); */ } + return EAS_ERROR_NO_VIRTUAL_SYNTHESIZER; + } + pSynth = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_SYNTH)); + } + + /* make sure we have a valid memory pointer */ + if (pSynth == NULL) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitMIDI: Failed to allocate synthesizer memory\n"); */ } + return EAS_ERROR_MALLOC_FAILED; + } + EAS_HWMemSet(pSynth, 0, sizeof(S_SYNTH)); + + /* set the sound library pointer */ + if ((result = VMSetEASLib(pSynth, pEASData->pVoiceMgr->pGlobalEAS)) != EAS_SUCCESS) + { + VMMIDIShutdown(pEASData, pSynth); + return result; + } + + /* link in DLS bank if downloaded */ +#ifdef DLS_SYNTHESIZER + if (pEASData->pVoiceMgr->pGlobalDLS) + { + pSynth->pDLS = pEASData->pVoiceMgr->pGlobalDLS; + DLSAddRef(pSynth->pDLS); + } +#endif + + /* initialize MIDI state variables */ + pSynth->synthFlags = DEFAULT_SYNTH_FLAGS; + pSynth->masterVolume = DEFAULT_SYNTH_MASTER_VOLUME; + pSynth->refCount = 1; + pSynth->priority = DEFAULT_SYNTH_PRIORITY; + pSynth->poolAlloc[0] = (EAS_U8) pEASData->pVoiceMgr->maxPolyphony; + + VMInitializeAllChannels(pEASData->pVoiceMgr, pSynth); + + pSynth->vSynthNum = (EAS_U8) virtualSynthNum; + pEASData->pVoiceMgr->pSynth[virtualSynthNum] = pSynth; + + *ppSynth = pSynth; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMIncRefCount() + *---------------------------------------------------------------------------- + * Increment reference count for virtual synth + *---------------------------------------------------------------------------- +*/ +void VMIncRefCount (S_SYNTH *pSynth) +{ + pSynth->refCount++; +} + +/*---------------------------------------------------------------------------- + * VMReset() + *---------------------------------------------------------------------------- + * Purpose: + * We call this routine to start the process of reseting the synth. + * This routine sets a flag for the entire synth indicating that we want + * to reset. + * We also force all voices to mute quickly. + * However, we do not actually perform any synthesis in this routine. That + * is, we do not ramp the voices down from this routine, but instead, we + * let the "regular" synth processing steps take care of adding the ramp + * down samples to the output buffer. After we are sure that all voices + * have completed ramping down, we continue the process of resetting the + * synth (from another routine). + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * force - force reset even if voices are active + * + * Outputs: + * + * Side Effects: + * - set a flag (in psSynthObject->m_nFlags) indicating synth reset requested. + * - force all voices to update their envelope states to mute + * + *---------------------------------------------------------------------------- +*/ +void VMReset (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_BOOL force) +{ + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMReset: request to reset synth. Force = %d\n", force); */ } +#endif + + /* force voices to off state - may cause audio artifacts */ + if (force) + { + pVoiceMgr->activeVoices -= pSynth->numActiveVoices; + pSynth->numActiveVoices = 0; + VMInitializeAllVoices(pVoiceMgr, pSynth->vSynthNum); + } + else + VMMuteAllVoices(pVoiceMgr, pSynth); + + /* don't reset if voices are still playing */ + if (pSynth->numActiveVoices == 0) + { + EAS_INT i; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMReset: complete the reset process\n"); */ } +#endif + + VMInitializeAllChannels(pVoiceMgr, pSynth); + for (i = 0; i < NUM_SYNTH_CHANNELS; i++) + pSynth->poolCount[i] = 0; + + /* set polyphony */ + if (pSynth->maxPolyphony < pVoiceMgr->maxPolyphony) + pSynth->poolAlloc[0] = (EAS_U8) pVoiceMgr->maxPolyphony; + else + pSynth->poolAlloc[0] = (EAS_U8) pSynth->maxPolyphony; + + /* clear reset flag */ + pSynth->synthFlags &= ~SYNTH_FLAG_RESET_IS_REQUESTED; + } + + /* handle reset after voices are muted */ + else + pSynth->synthFlags |= SYNTH_FLAG_RESET_IS_REQUESTED; +} + +/*---------------------------------------------------------------------------- + * VMInitializeAllChannels() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +void VMInitializeAllChannels (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth) +{ + S_SYNTH_CHANNEL *pChannel; + EAS_INT i; + + VMResetControllers(pSynth); + + /* init each channel */ + pChannel = pSynth->channels; + + for (i = 0; i < NUM_SYNTH_CHANNELS; i++, pChannel++) + { + pChannel->channelFlags = DEFAULT_CHANNEL_FLAGS; + pChannel->staticGain = DEFAULT_CHANNEL_STATIC_GAIN; + pChannel->staticPitch = DEFAULT_CHANNEL_STATIC_PITCH; + pChannel->pool = 0; + + /* the drum channel needs a different init */ + if (i == DEFAULT_DRUM_CHANNEL) + { + pChannel->bankNum = DEFAULT_RHYTHM_BANK_NUMBER; + pChannel->channelFlags |= CHANNEL_FLAG_RHYTHM_CHANNEL; + } + else + pChannel->bankNum = DEFAULT_MELODY_BANK_NUMBER; + + VMProgramChange(pVoiceMgr, pSynth, (EAS_U8) i, DEFAULT_SYNTH_PROGRAM_NUMBER); + } + +} + +/*---------------------------------------------------------------------------- + * VMResetControllers() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +void VMResetControllers (S_SYNTH *pSynth) +{ + S_SYNTH_CHANNEL *pChannel; + EAS_INT i; + + pChannel = pSynth->channels; + + for (i = 0; i < NUM_SYNTH_CHANNELS; i++, pChannel++) + { + pChannel->pitchBend = DEFAULT_PITCH_BEND; + pChannel->modWheel = DEFAULT_MOD_WHEEL; + pChannel->volume = DEFAULT_CHANNEL_VOLUME; + pChannel->pan = DEFAULT_PAN; + pChannel->expression = DEFAULT_EXPRESSION; + +#ifdef _REVERB + pSynth->channels[i].reverbSend = DEFAULT_REVERB_SEND; +#endif + +#ifdef _CHORUS + pSynth->channels[i].chorusSend = DEFAULT_CHORUS_SEND; +#endif + + pChannel->channelPressure = DEFAULT_CHANNEL_PRESSURE; + pChannel->registeredParam = DEFAULT_REGISTERED_PARAM; + pChannel->pitchBendSensitivity = DEFAULT_PITCH_BEND_SENSITIVITY; + pChannel->finePitch = DEFAULT_FINE_PITCH; + pChannel->coarsePitch = DEFAULT_COARSE_PITCH; + + /* update all voices on this channel */ + pChannel->channelFlags |= CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS; + } +} + +/*---------------------------------------------------------------------------- + * VMInitializeAllVoices() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +void VMInitializeAllVoices (S_VOICE_MGR *pVoiceMgr, EAS_INT vSynthNum) +{ + EAS_INT i; + + /* initialize the voice manager parameters */ + for (i = 0; i < MAX_SYNTH_VOICES; i++) + { + if (pVoiceMgr->voices[i].voiceState != eVoiceStateStolen) + { + if (GET_VSYNTH(pVoiceMgr->voices[i].channel) == vSynthNum) + InitVoice(&pVoiceMgr->voices[i]); + } + else + { + if (GET_VSYNTH(pVoiceMgr->voices[i].nextChannel) == vSynthNum) + InitVoice(&pVoiceMgr->voices[i]); + } + } +} + +/*---------------------------------------------------------------------------- + * VMMuteVoice() + *---------------------------------------------------------------------------- + * Mute the selected voice + *---------------------------------------------------------------------------- +*/ +void VMMuteVoice (S_VOICE_MGR *pVoiceMgr, EAS_I32 voiceNum) +{ + S_SYNTH *pSynth; + S_SYNTH_VOICE *pVoice; + + /* take no action if voice is already muted */ + pVoice = &pVoiceMgr->voices[voiceNum]; + if ((pVoice->voiceState == eVoiceStateMuting) || (pVoice->voiceState == eVoiceStateFree)) + return; + + /* one less voice in pool */ + DecVoicePoolCount(pVoiceMgr, pVoice); + + pSynth = pVoiceMgr->pSynth[GET_VSYNTH(pVoice->channel)]; + GetSynthPtr(voiceNum)->pfMuteVoice(pVoiceMgr, pSynth, pVoice, GetAdjustedVoiceNum(voiceNum)); + pVoice->voiceState = eVoiceStateMuting; + +} + +/*---------------------------------------------------------------------------- + * VMReleaseVoice() + *---------------------------------------------------------------------------- + * Release the selected voice + *---------------------------------------------------------------------------- +*/ +void VMReleaseVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 voiceNum) +{ + S_SYNTH_VOICE *pVoice = &pVoiceMgr->voices[voiceNum]; + + /* take no action if voice is already free, muting, or releasing */ + if (( pVoice->voiceState == eVoiceStateMuting) || + (pVoice->voiceState == eVoiceStateFree) || + (pVoice->voiceState == eVoiceStateRelease)) + return; + + /* stolen voices should just be muted */ + if (pVoice->voiceState == eVoiceStateStolen) + VMMuteVoice(pVoiceMgr, voiceNum); + + /* release this voice */ + GetSynthPtr(voiceNum)->pfReleaseVoice(pVoiceMgr, pSynth, &pVoiceMgr->voices[voiceNum], GetAdjustedVoiceNum(voiceNum)); + pVoice->voiceState = eVoiceStateRelease; +} + +/*---------------------------------------------------------------------------- + * VMInitMIPTable() + *---------------------------------------------------------------------------- + * Initialize the SP-MIDI MIP table in preparation for receiving MIP message + *---------------------------------------------------------------------------- +*/ +void VMInitMIPTable (S_SYNTH *pSynth) +{ + EAS_INT i; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMInitMIPTable\n"); */ } +#endif + + /* clear SP-MIDI flag */ + pSynth->synthFlags &= ~SYNTH_FLAG_SP_MIDI_ON; + for (i = 0; i < NUM_SYNTH_CHANNELS; i++) + { + pSynth->channels[i].pool = 0; + pSynth->channels[i].mip = 0; + } +} + +/*---------------------------------------------------------------------------- + * VMSetMIPEntry() + *---------------------------------------------------------------------------- + * Sets the priority and MIP level for a MIDI channel + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pVoiceMgr) reserved for future use */ +void VMSetMIPEntry (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 priority, EAS_U8 mip) +{ + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMSetMIPEntry: channel=%d, priority=%d, MIP=%d\n", channel, priority, mip); */ } +#endif + + /* save data for use by MIP message processing */ + if (priority < NUM_SYNTH_CHANNELS) + { + pSynth->channels[channel].pool = priority; + pSynth->channels[channel].mip = mip; + } +} + +/*---------------------------------------------------------------------------- + * VMMIPUpdateChannelMuting() + *---------------------------------------------------------------------------- + * This routine is called after an SP-MIDI message is received and + * any time the allocated polyphony changes. It mutes or unmutes + * channels based on polyphony. + *---------------------------------------------------------------------------- +*/ +void VMMIPUpdateChannelMuting (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth) +{ + EAS_INT i; + EAS_INT maxPolyphony; + EAS_INT channel; + EAS_INT vSynthNum; + EAS_INT pool; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMUpdateMIPTable\n"); */ } +#endif + + /* determine max polyphony */ + if (pSynth->maxPolyphony) + maxPolyphony = pSynth->maxPolyphony; + else + maxPolyphony = pVoiceMgr->maxPolyphony; + + /* process channels */ + for (i = 0; i < NUM_SYNTH_CHANNELS; i++) + { + + /* channel must be in MIP message and must meet allocation target */ + if ((pSynth->channels[i].mip != 0) && (pSynth->channels[i].mip <= maxPolyphony)) + pSynth->channels[i].channelFlags &= ~CHANNEL_FLAG_MUTE; + else + pSynth->channels[i].channelFlags |= CHANNEL_FLAG_MUTE; + + /* reset voice pool count */ + pSynth->poolCount[i] = 0; + } + + /* mute any voices on muted channels, and count unmuted voices */ + for (i = 0; i < MAX_SYNTH_VOICES; i++) + { + + /* ignore free voices */ + if (pVoiceMgr->voices[i].voiceState == eVoiceStateFree) + continue; + + /* get channel and virtual synth */ + if (pVoiceMgr->voices[i].voiceState != eVoiceStateStolen) + { + vSynthNum = GET_VSYNTH(pVoiceMgr->voices[i].channel); + channel = GET_CHANNEL(pVoiceMgr->voices[i].channel); + } + else + { + vSynthNum = GET_VSYNTH(pVoiceMgr->voices[i].nextChannel); + channel = GET_CHANNEL(pVoiceMgr->voices[i].nextChannel); + } + + /* ignore voices on other synths */ + if (vSynthNum != pSynth->vSynthNum) + continue; + + /* count voices */ + pool = pSynth->channels[channel].pool; + + /* deal with muted channels */ + if (pSynth->channels[channel].channelFlags & CHANNEL_FLAG_MUTE) + { + /* mute stolen voices scheduled to play on this channel */ + if (pVoiceMgr->voices[i].voiceState == eVoiceStateStolen) + pVoiceMgr->voices[i].voiceState = eVoiceStateMuting; + + /* release voices that aren't already muting */ + else if (pVoiceMgr->voices[i].voiceState != eVoiceStateMuting) + { + VMReleaseVoice(pVoiceMgr, pSynth, i); + pSynth->poolCount[pool]++; + } + } + + /* not muted, count this voice */ + else + pSynth->poolCount[pool]++; + } +} + +/*---------------------------------------------------------------------------- + * VMUpdateMIPTable() + *---------------------------------------------------------------------------- + * This routine is called at the end of the SysEx message to allow + * the Voice Manager to complete the initialization of the MIP + * table. It assigns channels to the appropriate voice pool based + * on the MIP setting and calculates the voices allocated for each + * pool. + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pVoiceMgr) reserved for future use */ +void VMUpdateMIPTable (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth) +{ + S_SYNTH_CHANNEL *pChannel; + EAS_INT i; + EAS_INT currentMIP; + EAS_INT currentPool; + EAS_INT priority[NUM_SYNTH_CHANNELS]; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMUpdateMIPTable\n"); */ } +#endif + + /* set SP-MIDI flag */ + pSynth->synthFlags |= SYNTH_FLAG_SP_MIDI_ON; + + /* sort channels into priority order */ + for (i = 0; i < NUM_SYNTH_CHANNELS; i++) + priority[i] = -1; + for (i = 0; i < NUM_SYNTH_CHANNELS; i++) + { + if (pSynth->channels[i].pool != DEFAULT_SP_MIDI_PRIORITY) + priority[pSynth->channels[i].pool] = i; + } + + /* process channels in priority order */ + currentMIP = 0; + currentPool = -1; + for (i = 0; i < NUM_SYNTH_CHANNELS; i++) + { + /* stop when we run out of channels */ + if (priority[i] == -1) + break; + + pChannel = &pSynth->channels[priority[i]]; + + /* when 2 or more channels have the same MIP setting, they + * share a common voice pool + */ + if (pChannel->mip == currentMIP) + pChannel->pool = (EAS_U8) currentPool; + + /* new voice pool */ + else + { + currentPool++; + pSynth->poolAlloc[currentPool] = (EAS_U8) (pChannel->mip - currentMIP); + currentMIP = pChannel->mip; + } + } + + /* set SP-MIDI flag */ + pSynth->synthFlags |= SYNTH_FLAG_SP_MIDI_ON; + + /* update channel muting */ + VMMIPUpdateChannelMuting (pVoiceMgr, pSynth); +} + +/*---------------------------------------------------------------------------- + * VMMuteAllVoices() + *---------------------------------------------------------------------------- + * Purpose: + * We call this in an emergency reset situation. + * This forces all voices to mute quickly. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * - forces all voices to update their envelope states to mute + * + *---------------------------------------------------------------------------- +*/ +void VMMuteAllVoices (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth) +{ + EAS_INT i; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMMuteAllVoices: about to mute all voices!!\n"); */ } +#endif + + for (i = 0; i < MAX_SYNTH_VOICES; i++) + { + /* for stolen voices, check new channel */ + if (pVoiceMgr->voices[i].voiceState == eVoiceStateStolen) + { + if (GET_VSYNTH(pVoiceMgr->voices[i].nextChannel) == pSynth->vSynthNum) + VMMuteVoice(pVoiceMgr, i); + } + + else if (pSynth->vSynthNum == GET_VSYNTH(pVoiceMgr->voices[i].channel)) + VMMuteVoice(pVoiceMgr, i); + } +} + +/*---------------------------------------------------------------------------- + * VMReleaseAllVoices() + *---------------------------------------------------------------------------- + * Purpose: + * We call this after we've encountered the end of the Midi file. + * This ensures all voices are either in release (because we received their + * note off already) or forces them to mute quickly. + * We use this as a safety to prevent bad midi files from playing forever. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * - forces all voices to update their envelope states to release or mute + * + *---------------------------------------------------------------------------- +*/ +void VMReleaseAllVoices (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth) +{ + EAS_INT i; + + /* release sustain pedal on all channels */ + for (i = 0; i < NUM_SYNTH_CHANNELS; i++) + { + if (pSynth->channels[ i ].channelFlags & CHANNEL_FLAG_SUSTAIN_PEDAL) + { + VMReleaseAllDeferredNoteOffs(pVoiceMgr, pSynth, (EAS_U8) i); + pSynth->channels[i].channelFlags &= ~CHANNEL_FLAG_SUSTAIN_PEDAL; + } + } + + /* release all voices */ + for (i = 0; i < MAX_SYNTH_VOICES; i++) + { + + switch (pVoiceMgr->voices[i].voiceState) + { + case eVoiceStateStart: + case eVoiceStatePlay: + /* only release voices on this synth */ + if (GET_VSYNTH(pVoiceMgr->voices[i].channel) == pSynth->vSynthNum) + VMReleaseVoice(pVoiceMgr, pSynth, i); + break; + + case eVoiceStateStolen: + if (GET_VSYNTH(pVoiceMgr->voices[i].nextChannel) == pSynth->vSynthNum) + VMMuteVoice(pVoiceMgr, i); + break; + + case eVoiceStateFree: + case eVoiceStateRelease: + case eVoiceStateMuting: + break; + + case eVoiceStateInvalid: + default: +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMReleaseAllVoices: error, %d is an unrecognized state\n", + pVoiceMgr->voices[i].voiceState); */ } +#endif + break; + } + } +} + +/*---------------------------------------------------------------------------- + * VMAllNotesOff() + *---------------------------------------------------------------------------- + * Purpose: + * Quickly mute all notes on the given channel. + * + * Inputs: + * nChannel - quickly turn off all notes on this channel + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * - forces all voices on this channel to update their envelope states to mute + * + *---------------------------------------------------------------------------- +*/ +void VMAllNotesOff (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel) +{ + EAS_INT voiceNum; + S_SYNTH_VOICE *pVoice; + +#ifdef _DEBUG_VM + if (channel >= NUM_SYNTH_CHANNELS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMAllNotesOff: error, %d invalid channel number\n", + channel); */ } + return; + } +#endif + + /* increment workload */ + pVoiceMgr->workload += WORKLOAD_AMOUNT_SMALL_INCREMENT; + + /* check each voice */ + channel = VSynthToChannel(pSynth, channel); + for (voiceNum = 0; voiceNum < MAX_SYNTH_VOICES; voiceNum++) + { + pVoice = &pVoiceMgr->voices[voiceNum]; + if (pVoice->voiceState != eVoiceStateFree) + { + if (((pVoice->voiceState != eVoiceStateStolen) && (channel == pVoice->channel)) || + ((pVoice->voiceState == eVoiceStateStolen) && (channel == pVoice->nextChannel))) + { + /* this voice is assigned to the requested channel */ + GetSynthPtr(voiceNum)->pfMuteVoice(pVoiceMgr, pSynth, pVoice, GetAdjustedVoiceNum(voiceNum)); + pVoice->voiceState = eVoiceStateMuting; + } + } + } +} + +/*---------------------------------------------------------------------------- + * VMDeferredStopNote() + *---------------------------------------------------------------------------- + * Purpose: + * Stop the notes that had deferred note-off requests. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * None. + * + * Side Effects: + * voices that have had deferred note-off requests are now put into release + * psSynthObject->m_sVoice[i].m_nFlags has the VOICE_FLAG_DEFER_MIDI_NOTE_OFF + * cleared + *---------------------------------------------------------------------------- +*/ +void VMDeferredStopNote (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth) +{ + EAS_INT voiceNum; + EAS_INT channel; + EAS_BOOL deferredNoteOff; + + deferredNoteOff = EAS_FALSE; + + /* check each voice to see if it requires a deferred note off */ + for (voiceNum=0; voiceNum < MAX_SYNTH_VOICES; voiceNum++) + { + if (pVoiceMgr->voices[voiceNum].voiceFlags & VOICE_FLAG_DEFER_MIDI_NOTE_OFF) + { + /* check if this voice was stolen */ + if (pVoiceMgr->voices[voiceNum].voiceState == eVoiceStateStolen) + { + /* + This voice was stolen, AND it also has a deferred note-off. + The stolen note must be completely ramped down at this point. + The note that caused the stealing to occur, however, must + have received a note-off request before the note that caused + stealing ever had a chance to even start. We want to give + the note that caused the stealing a chance to play, so we + start it on the next update interval, and we defer sending + the note-off request until the subsequent update interval. + So do not send the note-off request for this voice because + this voice was stolen and should have completed ramping down, + Also, do not clear the global flag nor this voice's flag + because we must indicate that the subsequent update interval, + after the note that caused stealing has started, should + then send the deferred note-off request. + */ + deferredNoteOff = EAS_TRUE; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMDeferredStopNote: defer request to stop voice %d (channel=%d note=%d) - voice not started\n", + voiceNum, + pVoiceMgr->voices[voiceNum].nextChannel, + pVoiceMgr->voices[voiceNum].note); */ } + + /* sanity check: this stolen voice better be ramped to zero */ + if (0 != pVoiceMgr->voices[voiceNum].gain) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMDeferredStopNote: warning, this voice did not complete its ramp to zero\n"); */ } + } +#endif // #ifdef _DEBUG_VM + + } + else + { + /* clear the flag using exor */ + pVoiceMgr->voices[voiceNum].voiceFlags ^= + VOICE_FLAG_DEFER_MIDI_NOTE_OFF; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMDeferredStopNote: Stop voice %d (channel=%d note=%d)\n", + voiceNum, + pVoiceMgr->voices[voiceNum].nextChannel, + pVoiceMgr->voices[voiceNum].note); */ } +#endif + + channel = pVoiceMgr->voices[voiceNum].channel & 15; + + /* check if sustain pedal is on */ + if (pSynth->channels[channel].channelFlags & CHANNEL_FLAG_SUSTAIN_PEDAL) + { + GetSynthPtr(voiceNum)->pfSustainPedal(pVoiceMgr, pSynth, &pVoiceMgr->voices[voiceNum], &pSynth->channels[channel], GetAdjustedVoiceNum(voiceNum)); + } + + /* release this voice */ + else + VMReleaseVoice(pVoiceMgr, pSynth, voiceNum); + + } + + } + + } + + /* clear the deferred note-off flag, unless there's another one pending */ + if (deferredNoteOff == EAS_FALSE) + pSynth->synthFlags ^= SYNTH_FLAG_DEFERRED_MIDI_NOTE_OFF_PENDING; +} + +/*---------------------------------------------------------------------------- + * VMReleaseAllDeferredNoteOffs() + *---------------------------------------------------------------------------- + * Purpose: + * Call this functin when the sustain flag is presently set but + * we are now transitioning from damper pedal on to + * damper pedal off. This means all notes in this channel + * that received a note off while the damper pedal was on, and + * had their note-off requests deferred, should now proceed to + * the release state. + * + * Inputs: + * nChannel - this channel has its sustain pedal transitioning from on to off + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * Side Effects: + * any voice with deferred note offs on this channel are updated such that + * pVoice->m_sEG1.m_eState = eEnvelopeStateRelease + * pVoice->m_sEG1.m_nIncrement = release increment + * pVoice->m_nFlags = clear the deferred note off flag + *---------------------------------------------------------------------------- +*/ +void VMReleaseAllDeferredNoteOffs (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel) +{ + S_SYNTH_VOICE *pVoice; + EAS_INT voiceNum; + +#ifdef _DEBUG_VM + if (channel >= NUM_SYNTH_CHANNELS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMReleaseAllDeferredNoteOffs: error, %d invalid channel number\n", + channel); */ } + return; + } +#endif /* #ifdef _DEBUG_VM */ + + /* increment workload */ + pVoiceMgr->workload += WORKLOAD_AMOUNT_SMALL_INCREMENT; + + /* find all the voices assigned to this channel */ + channel = VSynthToChannel(pSynth, channel); + for (voiceNum = 0; voiceNum < MAX_SYNTH_VOICES; voiceNum++) + { + + pVoice = &pVoiceMgr->voices[voiceNum]; + if (channel == pVoice->channel) + { + + /* does this voice have a deferred note off? */ + if (pVoice->voiceFlags & VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF) + { + /* release voice */ + VMReleaseVoice(pVoiceMgr, pSynth, voiceNum); + + /* use exor to flip bit, clear the flag */ + pVoice->voiceFlags &= ~VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF; + + } + + } + } + + return; +} + +/*---------------------------------------------------------------------------- + * VMCatchNotesForSustainPedal() + *---------------------------------------------------------------------------- + * Purpose: + * Call this function when the sustain flag is presently clear and + * the damper pedal is off and we are transitioning from damper pedal OFF to + * damper pedal ON. Currently sounding notes should be left + * unchanged. However, we should try to "catch" notes if possible. + * If any notes are in release and have levels >= sustain level, catch them, + * otherwise, let them continue to release. + * + * Inputs: + * nChannel - this channel has its sustain pedal transitioning from on to off + * psEASData - pointer to overall EAS data structure + * + * Outputs: + *---------------------------------------------------------------------------- +*/ +void VMCatchNotesForSustainPedal (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel) +{ + EAS_INT voiceNum; + +#ifdef _DEBUG_VM + if (channel >= NUM_SYNTH_CHANNELS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMCatchNotesForSustainPedal: error, %d invalid channel number\n", + channel); */ } + return; + } +#endif + + pVoiceMgr->workload += WORKLOAD_AMOUNT_SMALL_INCREMENT; + channel = VSynthToChannel(pSynth, channel); + + /* find all the voices assigned to this channel */ + for (voiceNum = 0; voiceNum < MAX_SYNTH_VOICES; voiceNum++) + { + if (channel == pVoiceMgr->voices[voiceNum].channel) + { + if (eVoiceStateRelease == pVoiceMgr->voices[voiceNum].voiceState) + GetSynthPtr(voiceNum)->pfSustainPedal(pVoiceMgr, pSynth, &pVoiceMgr->voices[voiceNum], &pSynth->channels[channel], GetAdjustedVoiceNum(voiceNum)); + } + } +} + +/*---------------------------------------------------------------------------- + * VMUpdateAllNotesAge() + *---------------------------------------------------------------------------- + * Purpose: + * Increment the note age for all of the active voices. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * m_nAge for all voices is incremented + *---------------------------------------------------------------------------- +*/ +void VMUpdateAllNotesAge (S_VOICE_MGR *pVoiceMgr, EAS_U16 age) +{ + EAS_INT i; + + for (i = 0; i < MAX_SYNTH_VOICES; i++) + { + if (age - pVoiceMgr->voices[i].age > 0) + pVoiceMgr->voices[i].age++; + } +} + +/*---------------------------------------------------------------------------- + * VMStolenVoice() + *---------------------------------------------------------------------------- + * Purpose: + * The selected voice is being stolen. Sets the parameters so that the + * voice will begin playing the new sound on the next buffer. + * + * Inputs: + * pVoice - pointer to voice to steal + * nChannel - the channel to start a note on + * nKeyNumber - the key number to start a note for + * nNoteVelocity - the key velocity from this note + * + * Outputs: + * None + *---------------------------------------------------------------------------- +*/ +static void VMStolenVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 voiceNum, EAS_U8 channel, EAS_U8 note, EAS_U8 velocity, EAS_U16 regionIndex) +{ + S_SYNTH_VOICE *pVoice = &pVoiceMgr->voices[voiceNum]; + + /* one less voice in old pool */ + DecVoicePoolCount(pVoiceMgr, pVoice); + + /* mute the sound that is currently playing */ + GetSynthPtr(voiceNum)->pfMuteVoice(pVoiceMgr, pVoiceMgr->pSynth[GET_VSYNTH(pVoice->channel)], &pVoiceMgr->voices[voiceNum], GetAdjustedVoiceNum(voiceNum)); + pVoice->voiceState = eVoiceStateStolen; + + /* set new note data */ + pVoice->nextChannel = VSynthToChannel(pSynth, channel); + pVoice->nextNote = note; + pVoice->nextVelocity = velocity; + pVoice->nextRegionIndex = regionIndex; + + /* one more voice in new pool */ + IncVoicePoolCount(pVoiceMgr, pVoice); + + /* clear the deferred flags */ + pVoice->voiceFlags &= + ~(VOICE_FLAG_DEFER_MIDI_NOTE_OFF | + VOICE_FLAG_DEFER_MUTE | + VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF); + + /* all notes older than this one get "younger" */ + VMUpdateAllNotesAge(pVoiceMgr, pVoice->age); + + /* assign current age to this note and increment for the next note */ + pVoice->age = pVoiceMgr->age++; +} + +/*---------------------------------------------------------------------------- + * VMFreeVoice() + *---------------------------------------------------------------------------- + * Purpose: + * The selected voice is done playing and being returned to the + * pool of free voices + * + * Inputs: + * pVoice - pointer to voice to free + * + * Outputs: + * None + *---------------------------------------------------------------------------- +*/ +static void VMFreeVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice) +{ + + /* do nothing if voice is already free */ + if (pVoice->voiceState == eVoiceStateFree) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "VMFreeVoice: Attempt to free voice that is already free\n"); */ } + return; + } + + /* if we jump directly to free without passing muting stage, + * we need to adjust the voice count */ + DecVoicePoolCount(pVoiceMgr, pVoice); + + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "VMFreeVoice: Synth=%d\n", pSynth->vSynthNum); */ } +#endif + + /* return to free voice pool */ + pVoiceMgr->activeVoices--; + pSynth->numActiveVoices--; + InitVoice(pVoice); + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMFreeVoice: free voice %d\n", pVoice - pVoiceMgr->voices); */ } +#endif + + /* all notes older than this one get "younger" */ + VMUpdateAllNotesAge(pVoiceMgr, pVoice->age); + } + +/*---------------------------------------------------------------------------- + * VMRetargetStolenVoice() + *---------------------------------------------------------------------------- + * Purpose: + * The selected voice has been stolen and needs to be initalized with + * the paramters of its new note. + * + * Inputs: + * pVoice - pointer to voice to retarget + * + * Outputs: + * None + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL VMRetargetStolenVoice (S_VOICE_MGR *pVoiceMgr, EAS_I32 voiceNum) +{ + EAS_U8 flags; + S_SYNTH_CHANNEL *pMIDIChannel; + S_SYNTH_VOICE *pVoice; + S_SYNTH *pSynth; + S_SYNTH *pNextSynth; + + /* establish some pointers */ + pVoice = &pVoiceMgr->voices[voiceNum]; + pSynth = pVoiceMgr->pSynth[GET_VSYNTH(pVoice->channel)]; + pMIDIChannel = &pSynth->channels[pVoice->channel & 15]; + pNextSynth = pVoiceMgr->pSynth[GET_VSYNTH(pVoice->nextChannel)]; + +#ifdef _DEBUG_VM +{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMRetargetStolenVoice: retargeting stolen voice %d on channel %d\n", + voiceNum, pVoice->channel); */ } + + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\to channel %d note: %d velocity: %d\n", + pVoice->nextChannel, pVoice->nextNote, pVoice->nextVelocity); */ } +#endif + + /* make sure new channel hasn't been muted by SP-MIDI since the voice was stolen */ + if ((pSynth->synthFlags & SYNTH_FLAG_SP_MIDI_ON) && + (pMIDIChannel->channelFlags & CHANNEL_FLAG_MUTE)) + { + VMFreeVoice(pVoiceMgr, pSynth, &pVoiceMgr->voices[voiceNum]); + return EAS_FALSE; + } + + /* if assigned to a new synth, correct the active voice count */ + if (pVoice->channel != pVoice->nextChannel) + { +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMRetargetStolenVoice: Note assigned to different virtual synth, adjusting numActiveVoices\n"); */ } +#endif + pSynth->numActiveVoices--; + pNextSynth->numActiveVoices++; + } + + /* assign new channel number, and increase channel voice count */ + pVoice->channel = pVoice->nextChannel; + pMIDIChannel = &pNextSynth->channels[pVoice->channel & 15]; + + /* assign other data */ + pVoice->note = pVoice->nextNote; + pVoice->velocity = pVoice->nextVelocity; + pVoice->nextChannel = UNASSIGNED_SYNTH_CHANNEL; + pVoice->regionIndex = pVoice->nextRegionIndex; + + /* save the flags, pfStartVoice() will clear them */ + flags = pVoice->voiceFlags; + + /* keep track of the note-start related workload */ + pVoiceMgr->workload += WORKLOAD_AMOUNT_START_NOTE; + + /* setup the voice parameters */ + pVoice->voiceState = eVoiceStateStart; + + /*lint -e{522} return not used at this time */ + GetSynthPtr(voiceNum)->pfStartVoice(pVoiceMgr, pNextSynth, &pVoiceMgr->voices[voiceNum], GetAdjustedVoiceNum(voiceNum), pVoice->regionIndex); + + /* did the new note already receive a MIDI note-off request? */ + if (flags & VOICE_FLAG_DEFER_MIDI_NOTE_OFF) + { +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMRetargetVoice: stolen note note-off request deferred\n"); */ } +#endif + pVoice->voiceFlags |= VOICE_FLAG_DEFER_MIDI_NOTE_OFF; + pNextSynth->synthFlags |= SYNTH_FLAG_DEFERRED_MIDI_NOTE_OFF_PENDING; + } + + return EAS_TRUE; +} + +/*---------------------------------------------------------------------------- + * VMCheckKeyGroup() + *---------------------------------------------------------------------------- + * If the note that we've been asked to start is in the same key group as + * any currently playing notes, then we must shut down the currently playing + * note in the same key group + *---------------------------------------------------------------------------- +*/ +void VMCheckKeyGroup (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U16 keyGroup, EAS_U8 channel) +{ + const S_REGION *pRegion; + EAS_INT voiceNum; + + /* increment frame workload */ + pVoiceMgr->workload += WORKLOAD_AMOUNT_KEY_GROUP; + + /* need to check all voices in case this is a layered sound */ + channel = VSynthToChannel(pSynth, channel); + for (voiceNum = 0; voiceNum < MAX_SYNTH_VOICES; voiceNum++) + { + if (pVoiceMgr->voices[voiceNum].voiceState != eVoiceStateStolen) + { + /* voice must be on the same channel */ + if (channel == pVoiceMgr->voices[voiceNum].channel) + { + /* check key group */ + pRegion = GetRegionPtr(pSynth, pVoiceMgr->voices[voiceNum].regionIndex); + if (keyGroup == (pRegion->keyGroupAndFlags & 0x0f00)) + { +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMCheckKeyGroup: voice %d matches key group %d\n", voiceNum, keyGroup >> 8); */ } +#endif + + /* if this voice was just started, set it to mute on the next buffer */ + if (pVoiceMgr->voices[voiceNum].voiceFlags & VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET) + pVoiceMgr->voices[voiceNum].voiceFlags |= VOICE_FLAG_DEFER_MUTE; + + /* mute immediately */ + else + VMMuteVoice(pVoiceMgr, voiceNum); + } + } + } + + /* for stolen voice, check new values */ + else + { + /* voice must be on the same channel */ + if (channel == pVoiceMgr->voices[voiceNum].nextChannel) + { + /* check key group */ + pRegion = GetRegionPtr(pSynth, pVoiceMgr->voices[voiceNum].nextRegionIndex); + if (keyGroup == (pRegion->keyGroupAndFlags & 0x0f00)) + { +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMCheckKeyGroup: voice %d matches key group %d\n", voiceNum, keyGroup >> 8); */ } +#endif + + /* if this voice was just started, set it to mute on the next buffer */ + if (pVoiceMgr->voices[voiceNum].voiceFlags & VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET) + pVoiceMgr->voices[voiceNum].voiceFlags |= VOICE_FLAG_DEFER_MUTE; + + /* mute immediately */ + else + VMMuteVoice(pVoiceMgr, voiceNum); + } + } + + } + } +} + +/*---------------------------------------------------------------------------- + * VMCheckPolyphonyLimiting() + *---------------------------------------------------------------------------- + * Purpose: + * We only play at most 2 of the same note on a MIDI channel. + * E.g., if we are asked to start note 36, and there are already two voices + * that are playing note 36, then we must steal the voice playing + * the oldest note 36 and use that stolen voice to play the new note 36. + * + * Inputs: + * nChannel - synth channel that wants to start a new note + * nKeyNumber - new note's midi note number + * nNoteVelocity - new note's velocity + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * pbVoiceStealingRequired - flag: this routine sets true if we needed to + * steal a voice + * * + * Side Effects: + * psSynthObject->m_sVoice[free voice num].m_nKeyNumber may be assigned + * psSynthObject->m_sVoice[free voice num].m_nVelocity may be assigned + *---------------------------------------------------------------------------- +*/ +EAS_BOOL VMCheckPolyphonyLimiting (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 note, EAS_U8 velocity, EAS_U16 regionIndex, EAS_I32 lowVoice, EAS_I32 highVoice) +{ + EAS_INT voiceNum; + EAS_INT oldestVoiceNum; + EAS_INT numVoicesPlayingNote; + EAS_U16 age; + EAS_U16 oldestNoteAge; + + pVoiceMgr->workload += WORKLOAD_AMOUNT_POLY_LIMIT; + + numVoicesPlayingNote = 0; + oldestVoiceNum = MAX_SYNTH_VOICES; + oldestNoteAge = 0; + channel = VSynthToChannel(pSynth, channel); + + /* examine each voice on this channel playing this note */ + for (voiceNum = lowVoice; voiceNum <= highVoice; voiceNum++) + { + /* check stolen notes separately */ + if (pVoiceMgr->voices[voiceNum].voiceState != eVoiceStateStolen) + { + + /* same channel and note ? */ + if ((channel == pVoiceMgr->voices[voiceNum].channel) && (note == pVoiceMgr->voices[voiceNum].note)) + { + numVoicesPlayingNote++; + age = pVoiceMgr->age - pVoiceMgr->voices[voiceNum].age; + + /* is this the oldest voice for this note? */ + if (age >= oldestNoteAge) + { + oldestNoteAge = age; + oldestVoiceNum = voiceNum; + } + } + } + + /* handle stolen voices */ + else + { + /* same channel and note ? */ + if ((channel == pVoiceMgr->voices[voiceNum].nextChannel) && (note == pVoiceMgr->voices[voiceNum].nextNote)) + { + numVoicesPlayingNote++; + } + } + } + + /* check to see if we exceeded poly limit */ + if (numVoicesPlayingNote < DEFAULT_CHANNEL_POLYPHONY_LIMIT) + return EAS_FALSE; + + /* make sure we have a voice to steal */ + if (oldestVoiceNum != MAX_SYNTH_VOICES) + { +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMCheckPolyphonyLimiting: voice %d has the oldest note\n", oldestVoiceNum); */ } + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "VMCheckPolyphonyLimiting: polyphony limiting requires shutting down note %d \n", pVoiceMgr->voices[oldestVoiceNum].note); */ } +#endif + VMStolenVoice(pVoiceMgr, pSynth, oldestVoiceNum, channel, note, velocity, regionIndex); + return EAS_TRUE; + } + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "VMCheckPolyphonyLimiting: No oldest voice to steal\n"); */ } +#endif + return EAS_FALSE; +} + +/*---------------------------------------------------------------------------- + * VMStartVoice() + *---------------------------------------------------------------------------- + * Starts a voice given a region index + *---------------------------------------------------------------------------- +*/ +void VMStartVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 note, EAS_U8 velocity, EAS_U16 regionIndex) +{ + const S_REGION *pRegion; + S_SYNTH_CHANNEL *pChannel; + EAS_INT voiceNum; + EAS_INT maxSynthPoly; + EAS_I32 lowVoice, highVoice; + EAS_U16 keyGroup; + + pChannel = &pSynth->channels[channel]; + pRegion = GetRegionPtr(pSynth, regionIndex); + + /* select correct synth */ +#if defined(_SECONDARY_SYNTH) || defined(EAS_SPLIT_WT_SYNTH) + { +#ifdef EAS_SPLIT_WT_SYNTH + if ((pRegion->keyGroupAndFlags & REGION_FLAG_OFF_CHIP) == 0) +#else + if ((regionIndex & FLAG_RGN_IDX_FM_SYNTH) == 0) +#endif + { + lowVoice = 0; + highVoice = NUM_PRIMARY_VOICES - 1; + } + else + { + lowVoice = NUM_PRIMARY_VOICES; + highVoice = MAX_SYNTH_VOICES - 1; + } + } +#else + lowVoice = 0; + highVoice = MAX_SYNTH_VOICES - 1; +#endif + + /* keep track of the note-start related workload */ + pVoiceMgr->workload+= WORKLOAD_AMOUNT_START_NOTE; + + /* other voices in pool, check for key group and poly limiting */ + if (pSynth->poolCount[pChannel->pool] != 0) + { + + /* check for key group exclusivity */ + keyGroup = pRegion->keyGroupAndFlags & 0x0f00; + if (keyGroup!= 0) + VMCheckKeyGroup(pVoiceMgr, pSynth, keyGroup, channel); + + /* check polyphony limit and steal a voice if necessary */ + if ((pRegion->keyGroupAndFlags & REGION_FLAG_NON_SELF_EXCLUSIVE) == 0) + { + if (VMCheckPolyphonyLimiting(pVoiceMgr, pSynth, channel, note, velocity, regionIndex, lowVoice, highVoice) == EAS_TRUE) + return; + } + } + + /* check max poly allocation */ + if ((pSynth->maxPolyphony == 0) || (pVoiceMgr->maxPolyphony < pSynth->maxPolyphony)) + maxSynthPoly = pVoiceMgr->maxPolyphony; + else + maxSynthPoly = pSynth->maxPolyphony; + + /* any free voices? */ + if ((pVoiceMgr->activeVoices < pVoiceMgr->maxPolyphony) && + (pSynth->numActiveVoices < maxSynthPoly) && + (EAS_SUCCESS == VMFindAvailableVoice(pVoiceMgr, &voiceNum, lowVoice, highVoice))) + { + S_SYNTH_VOICE *pVoice = &pVoiceMgr->voices[voiceNum]; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "VMStartVoice: Synth=%d\n", pSynth->vSynthNum); */ } +#endif + + /* bump voice counts */ + pVoiceMgr->activeVoices++; + pSynth->numActiveVoices++; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMStartVoice: voice %d assigned to channel %d note %d velocity %d\n", + voiceNum, channel, note, velocity); */ } +#endif + + /* save parameters */ + pVoiceMgr->voices[voiceNum].channel = VSynthToChannel(pSynth, channel); + pVoiceMgr->voices[voiceNum].note = note; + pVoiceMgr->voices[voiceNum].velocity = velocity; + + /* establish note age for voice stealing */ + pVoiceMgr->voices[voiceNum].age = pVoiceMgr->age++; + + /* setup the synthesis parameters */ + pVoiceMgr->voices[voiceNum].voiceState = eVoiceStateStart; + + /* increment voice pool count */ + IncVoicePoolCount(pVoiceMgr, pVoice); + + /* start voice on correct synth */ + /*lint -e{522} return not used at this time */ + GetSynthPtr(voiceNum)->pfStartVoice(pVoiceMgr, pSynth, &pVoiceMgr->voices[voiceNum], GetAdjustedVoiceNum(voiceNum), regionIndex); + return; + } + + /* no free voices, we have to steal one using appropriate algorithm */ + if (VMStealVoice(pVoiceMgr, pSynth, &voiceNum, channel, note, lowVoice, highVoice) == EAS_SUCCESS) + VMStolenVoice(pVoiceMgr, pSynth, voiceNum, channel, note, velocity, regionIndex); + +#ifdef _DEBUG_VM + else + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMStartVoice: Could not steal a voice for channel %d note %d velocity %d\n", + channel, note, velocity); */ } + } +#endif + + return; +} + +/*---------------------------------------------------------------------------- + * VMStartNote() + *---------------------------------------------------------------------------- + * Purpose: + * Update the synth's state to play the requested note on the requested + * channel if possible. + * + * Inputs: + * nChannel - the channel to start a note on + * nKeyNumber - the key number to start a note for + * nNoteVelocity - the key velocity from this note + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * Side Effects: + * psSynthObject->m_nNumActiveVoices may be incremented + * psSynthObject->m_sVoice[free voice num].m_nSynthChannel may be assigned + * psSynthObject->m_sVoice[free voice num].m_nKeyNumber is assigned + * psSynthObject->m_sVoice[free voice num].m_nVelocity is assigned + *---------------------------------------------------------------------------- +*/ +void VMStartNote (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 note, EAS_U8 velocity) +{ + S_SYNTH_CHANNEL *pChannel; + EAS_U16 regionIndex; + EAS_I16 adjustedNote; + + /* bump note count */ + pSynth->totalNoteCount++; + + pChannel = &pSynth->channels[channel]; + + /* check channel mute */ + if (pChannel->channelFlags & CHANNEL_FLAG_MUTE) + return; + +#ifdef EXTERNAL_AUDIO + /* pass event to external audio when requested */ + if ((pChannel->channelFlags & CHANNEL_FLAG_EXTERNAL_AUDIO) && (pSynth->cbEventFunc != NULL)) + { + S_EXT_AUDIO_EVENT event; + event.channel = channel; + event.note = note; + event.velocity = velocity; + event.noteOn = EAS_TRUE; + if (pSynth->cbEventFunc(pSynth->pExtAudioInstData, &event)) + return; + } +#endif + + /* start search at first region */ + regionIndex = pChannel->regionIndex; + + /* handle transposition */ + adjustedNote = note; + if (pChannel->channelFlags & CHANNEL_FLAG_RHYTHM_CHANNEL) + adjustedNote += pChannel->coarsePitch; + else + adjustedNote += pChannel->coarsePitch + pSynth->globalTranspose; + + /* limit adjusted key number so it does not wraparound, over/underflow */ + if (adjustedNote < 0) + { + adjustedNote = 0; + } + else if (adjustedNote > 127) + { + adjustedNote = 127; + } + +#if defined(DLS_SYNTHESIZER) + if (regionIndex & FLAG_RGN_IDX_DLS_SYNTH) + { + /* DLS voice */ + for (;;) + { + /*lint -e{740,826} cast OK, we know this is actually a DLS region */ + const S_DLS_REGION *pDLSRegion = (S_DLS_REGION*) GetRegionPtr(pSynth, regionIndex); + + /* check key against this region's key and velocity range */ + if (((adjustedNote >= pDLSRegion->wtRegion.region.rangeLow) && (adjustedNote <= pDLSRegion->wtRegion.region.rangeHigh)) && + ((velocity >= pDLSRegion->velLow) && (velocity <= pDLSRegion->velHigh))) + { + VMStartVoice(pVoiceMgr, pSynth, channel, note, velocity, regionIndex); + } + + /* last region in program? */ + if (pDLSRegion->wtRegion.region.keyGroupAndFlags & REGION_FLAG_LAST_REGION) + break; + + /* advance to next region */ + regionIndex++; + } + } + else +#endif + + /* braces here for #if clause */ + { + /* EAS voice */ + for (;;) + { + const S_REGION *pRegion = GetRegionPtr(pSynth, regionIndex); + + /* check key against this region's keyrange */ + if ((adjustedNote >= pRegion->rangeLow) && (adjustedNote <= pRegion->rangeHigh)) + { + VMStartVoice(pVoiceMgr, pSynth, channel, note, velocity, regionIndex); + break; + } + + /* last region in program? */ + if (pRegion->keyGroupAndFlags & REGION_FLAG_LAST_REGION) + break; + + /* advance to next region */ + regionIndex++; + } + } +} + +/*---------------------------------------------------------------------------- + * VMStopNote() + *---------------------------------------------------------------------------- + * Purpose: + * Update the synth's state to end the requested note on the requested + * channel. + * + * Inputs: + * nChannel - the channel to stop a note on + * nKeyNumber - the key number for this note off + * nNoteVelocity - the note-off velocity + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * Side Effects: + * psSynthObject->m_sVoice[free voice num].m_nSynthChannel may be assigned + * psSynthObject->m_sVoice[free voice num].m_nKeyNumber is assigned + * psSynthObject->m_sVoice[free voice num].m_nVelocity is assigned + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, velocity) reserved for future use */ +void VMStopNote (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 note, EAS_U8 velocity) +{ + S_SYNTH_CHANNEL *pChannel; + EAS_INT voiceNum; + + pChannel = &(pSynth->channels[channel]); + +#ifdef EXTERNAL_AUDIO + if ((pChannel->channelFlags & CHANNEL_FLAG_EXTERNAL_AUDIO) && (pSynth->cbEventFunc != NULL)) + { + S_EXT_AUDIO_EVENT event; + event.channel = channel; + event.note = note; + event.velocity = velocity; + event.noteOn = EAS_FALSE; + if (pSynth->cbEventFunc(pSynth->pExtAudioInstData, &event)) + return; + } +#endif + + /* keep track of the note-start workload */ + pVoiceMgr->workload += WORKLOAD_AMOUNT_STOP_NOTE; + + channel = VSynthToChannel(pSynth, channel); + + for (voiceNum=0; voiceNum < MAX_SYNTH_VOICES; voiceNum++) + { + + /* stolen notes are handled separately */ + if (eVoiceStateStolen != pVoiceMgr->voices[voiceNum].voiceState) + { + + /* channel and key number must match */ + if ((channel == pVoiceMgr->voices[voiceNum].channel) && (note == pVoiceMgr->voices[voiceNum].note)) + { +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMStopNote: voice %d channel %d note %d\n", + voiceNum, channel, note); */ } +#endif + + /* if sustain pedal is down, set deferred note-off flag */ + if (pChannel->channelFlags & CHANNEL_FLAG_SUSTAIN_PEDAL) + { + pVoiceMgr->voices[voiceNum].voiceFlags |= VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF; + continue; + } + + /* if this note just started, wait before we stop it */ + if (pVoiceMgr->voices[voiceNum].voiceFlags & VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET) + { +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tDeferred: Not started yet\n"); */ } +#endif + pVoiceMgr->voices[voiceNum].voiceFlags |= VOICE_FLAG_DEFER_MIDI_NOTE_OFF; + pSynth->synthFlags |= SYNTH_FLAG_DEFERRED_MIDI_NOTE_OFF_PENDING; + } + + /* release voice */ + else + VMReleaseVoice(pVoiceMgr, pSynth, voiceNum); + + } + } + + /* process stolen notes, new channel and key number must match */ + else if ((channel == pVoiceMgr->voices[voiceNum].nextChannel) && (note == pVoiceMgr->voices[voiceNum].nextNote)) + { + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMStopNote: voice %d channel %d note %d\n\tDeferred: Stolen voice\n", + voiceNum, channel, note); */ } +#endif + pVoiceMgr->voices[voiceNum].voiceFlags |= VOICE_FLAG_DEFER_MIDI_NOTE_OFF; + } + } +} + +/*---------------------------------------------------------------------------- + * VMFindAvailableVoice() + *---------------------------------------------------------------------------- + * Purpose: + * Find an available voice and return the voice number if available. + * + * Inputs: + * pnVoiceNumber - really an output, returns the voice number found + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * success - if there is an available voice + * failure - otherwise + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMFindAvailableVoice (S_VOICE_MGR *pVoiceMgr, EAS_INT *pVoiceNumber, EAS_I32 lowVoice, EAS_I32 highVoice) +{ + EAS_INT voiceNum; + + /* Check each voice to see if it has been assigned to a synth channel */ + for (voiceNum = lowVoice; voiceNum <= highVoice; voiceNum++) + { + /* check if this voice has been assigned to a synth channel */ + if ( pVoiceMgr->voices[voiceNum].voiceState == eVoiceStateFree) + { + *pVoiceNumber = voiceNum; /* this voice is available */ + return EAS_SUCCESS; + } + } + + /* if we reach here, we have not found a free voice */ + *pVoiceNumber = UNASSIGNED_SYNTH_VOICE; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMFindAvailableVoice: error, could not find an available voice\n"); */ } +#endif + return EAS_FAILURE; +} + +/*---------------------------------------------------------------------------- + * VMStealVoice() + *---------------------------------------------------------------------------- + * Purpose: + * Steal a voice and return the voice number + * + * Stealing algorithm: steal the best choice with minimal work, taking into + * account SP-Midi channel priorities and polyphony allocation. + * + * In one pass through all the voices, figure out which voice to steal + * taking into account a number of different factors: + * Priority of the voice's MIDI channel + * Number of voices over the polyphony allocation for voice's MIDI channel + * Amplitude of the voice + * Note age + * Key velocity (for voices that haven't been started yet) + * If any matching notes are found + * + * Inputs: + * pnVoiceNumber - really an output, see below + * nChannel - the channel that this voice wants to be started on + * nKeyNumber - the key number for this new voice + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * pnVoiceNumber - voice number of the voice that was stolen + * EAS_RESULT EAS_SUCCESS - always successful + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMStealVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_INT *pVoiceNumber, EAS_U8 channel, EAS_U8 note, EAS_I32 lowVoice, EAS_I32 highVoice) +{ + S_SYNTH_VOICE *pCurrVoice; + S_SYNTH *pCurrSynth; + EAS_INT voiceNum; + EAS_INT bestCandidate; + EAS_U8 currChannel; + EAS_U8 currNote; + EAS_I32 bestPriority; + EAS_I32 currentPriority; + + /* determine which voice to steal */ + bestPriority = 0; + bestCandidate = MAX_SYNTH_VOICES; + + for (voiceNum = lowVoice; voiceNum <= highVoice; voiceNum++) + { + pCurrVoice = &pVoiceMgr->voices[voiceNum]; + + /* ignore free voices */ + if (pCurrVoice->voiceState == eVoiceStateFree) + continue; + + /* for stolen voices, use the new parameters, not the old */ + if (pCurrVoice->voiceState == eVoiceStateStolen) + { + pCurrSynth = pVoiceMgr->pSynth[GET_VSYNTH(pCurrVoice->nextChannel)]; + currChannel = pCurrVoice->nextChannel; + currNote = pCurrVoice->nextNote; + } + else + { + pCurrSynth = pVoiceMgr->pSynth[GET_VSYNTH(pCurrVoice->channel)]; + currChannel = pCurrVoice->channel; + currNote = pCurrVoice->note; + } + + /* ignore voices that are higher priority */ + if (pSynth->priority > pCurrSynth->priority) + continue; +#ifdef _DEBUG_VM +// { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMStealVoice: New priority = %d exceeds old priority = %d\n", pSynth->priority, pCurrSynth->priority); */ } +#endif + + /* if voice is stolen or just started, reduce the likelihood it will be stolen */ + if (( pCurrVoice->voiceState == eVoiceStateStolen) || (pCurrVoice->voiceFlags & VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET)) + { + currentPriority = 128 - pCurrVoice->nextVelocity; + } + else + { + /* compute the priority of this voice, higher means better for stealing */ + /* use not age */ + currentPriority = (EAS_I32) pCurrVoice->age << NOTE_AGE_STEAL_WEIGHT; + + /* include note gain -higher gain is lower steal value */ + /*lint -e{704} use shift for performance */ + currentPriority += ((32768 >> (12 - NOTE_GAIN_STEAL_WEIGHT)) + 256) - + ((EAS_I32) pCurrVoice->gain >> (12 - NOTE_GAIN_STEAL_WEIGHT)); + } + + /* in SP-MIDI mode, include over poly allocation and channel priority */ + if (pSynth->synthFlags & SYNTH_FLAG_SP_MIDI_ON) + { + S_SYNTH_CHANNEL *pChannel = &pCurrSynth->channels[GET_CHANNEL(currChannel)]; + /*lint -e{701} use shift for performance */ + if (pSynth->poolCount[pChannel->pool] >= pSynth->poolAlloc[pChannel->pool]) + currentPriority += (pSynth->poolCount[pChannel->pool] -pSynth->poolAlloc[pChannel->pool] + 1) << CHANNEL_POLY_STEAL_WEIGHT; + + /* include channel priority */ + currentPriority += (EAS_I32)(pChannel->pool << CHANNEL_PRIORITY_STEAL_WEIGHT); + } + + /* if a note is already playing that matches this note, consider stealing it more readily */ + if ((note == currNote) && (channel == currChannel)) + currentPriority += NOTE_MATCH_PENALTY; + + /* is this the best choice so far? */ + if (currentPriority >= bestPriority) + { + bestPriority = currentPriority; + bestCandidate = voiceNum; + } + } + + /* may happen if all voices are allocated to a higher priority virtual synth */ + if (bestCandidate == MAX_SYNTH_VOICES) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMStealVoice: Unable to allocate a voice\n"); */ } + return EAS_ERROR_NO_VOICE_ALLOCATED; + } + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMStealVoice: Voice %d stolen\n", bestCandidate); */ } + + /* are we stealing a stolen voice? */ + if (pVoiceMgr->voices[bestCandidate].voiceState == eVoiceStateStolen) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "VMStealVoice: Voice %d is already marked as stolen and was scheduled to play ch: %d note: %d vel: %d\n", + bestCandidate, + pVoiceMgr->voices[bestCandidate].nextChannel, + pVoiceMgr->voices[bestCandidate].nextNote, + pVoiceMgr->voices[bestCandidate].nextVelocity); */ } + } +#endif + + *pVoiceNumber = (EAS_U16) bestCandidate; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMChannelPressure() + *---------------------------------------------------------------------------- + * Purpose: + * Change the channel pressure for the given channel + * + * Inputs: + * nChannel - the MIDI channel + * nVelocity - the channel pressure value + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * Side Effects: + * psSynthObject->m_sChannel[nChannel].m_nChannelPressure is updated + *---------------------------------------------------------------------------- +*/ +void VMChannelPressure (S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 value) +{ + S_SYNTH_CHANNEL *pChannel; + + pChannel = &(pSynth->channels[channel]); + pChannel->channelPressure = value; + + /* + set a channel flag to request parameter updates + for all the voices associated with this channel + */ + pChannel->channelFlags |= CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS; +} + +/*---------------------------------------------------------------------------- + * VMPitchBend() + *---------------------------------------------------------------------------- + * Purpose: + * Change the pitch wheel value for the given channel. + * This routine constructs the proper 14-bit argument when the calling routine + * passes the pitch LSB and MSB. + * + * Note: some midi disassemblers display a bipolar pitch bend value. + * We can display the bipolar value using + * if m_nPitchBend >= 0x2000 + * bipolar pitch bend = postive (m_nPitchBend - 0x2000) + * else + * bipolar pitch bend = negative (0x2000 - m_nPitchBend) + * + * Inputs: + * nChannel - the MIDI channel + * nPitchLSB - the LSB byte of the pitch bend message + * nPitchMSB - the MSB byte of the pitch bend message + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * psSynthObject->m_sChannel[nChannel].m_nPitchBend is changed + * + *---------------------------------------------------------------------------- +*/ +void VMPitchBend (S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 nPitchLSB, EAS_U8 nPitchMSB) +{ + S_SYNTH_CHANNEL *pChannel; + + pChannel = &(pSynth->channels[channel]); + pChannel->pitchBend = (EAS_I16) ((nPitchMSB << 7) | nPitchLSB); + + /* + set a channel flag to request parameter updates + for all the voices associated with this channel + */ + pChannel->channelFlags |= CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS; +} + +/*---------------------------------------------------------------------------- + * VMControlChange() + *---------------------------------------------------------------------------- + * Purpose: + * Change the controller (or mode) for the given channel. + * + * Inputs: + * nChannel - the MIDI channel + * nControllerNumber - the MIDI controller number + * nControlValue - the value for this controller message + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * Side Effects: + * psSynthObject->m_sChannel[nChannel] controller is changed + * + *---------------------------------------------------------------------------- +*/ +void VMControlChange (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 controller, EAS_U8 value) +{ + S_SYNTH_CHANNEL *pChannel; + + pChannel = &(pSynth->channels[channel]); + + /* + set a channel flag to request parameter updates + for all the voices associated with this channel + */ + pChannel->channelFlags |= CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS; + + switch ( controller ) + { + case MIDI_CONTROLLER_BANK_SELECT_MSB: +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMControlChange: Bank Select MSB: msb 0x%X\n", value); */ } +#endif + /* use this MSB with a zero LSB, until we get an LSB message */ + pChannel->bankNum = value << 8; + break; + + case MIDI_CONTROLLER_MOD_WHEEL: + /* we treat mod wheel as a 7-bit controller and only use the MSB */ + pChannel->modWheel = value; + break; + + case MIDI_CONTROLLER_VOLUME: + /* we treat volume as a 7-bit controller and only use the MSB */ + pChannel->volume = value; + break; + + case MIDI_CONTROLLER_PAN: + /* we treat pan as a 7-bit controller and only use the MSB */ + pChannel->pan = value; + break; + + case MIDI_CONTROLLER_EXPRESSION: + /* we treat expression as a 7-bit controller and only use the MSB */ + pChannel->expression = value; + break; + + case MIDI_CONTROLLER_BANK_SELECT_LSB: +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMControlChange: Bank Select LSB: lsb 0x%X\n", value); */ } +#endif + /* + construct bank number as 7-bits (stored as 8) of existing MSB + and 7-bits of new LSB (also stored as 8( + */ + pChannel->bankNum = + (pChannel->bankNum & 0xFF00) | value; + + break; + + case MIDI_CONTROLLER_SUSTAIN_PEDAL: + /* we treat sustain pedal as a boolean on/off bit flag */ + if (value < 64) + { + /* + we are requested to turn the pedal off, but first check + if the pedal is already on + */ + if (0 != + (pChannel->channelFlags & CHANNEL_FLAG_SUSTAIN_PEDAL) + ) + { + /* + The sustain flag is presently set and the damper pedal is on. + We are therefore transitioning from damper pedal ON to + damper pedal OFF. This means all notes in this channel + that received a note off while the damper pedal was on, and + had their note-off requests deferred, should now proceed to + the release state. + */ + VMReleaseAllDeferredNoteOffs(pVoiceMgr, pSynth, channel); + } /* end if sustain pedal is already on */ + + /* turn the sustain pedal off */ + pChannel->channelFlags &= ~CHANNEL_FLAG_SUSTAIN_PEDAL; + } + else + { + /* + we are requested to turn the pedal on, but first check + if the pedal is already off + */ + if (0 == + (pChannel->channelFlags & CHANNEL_FLAG_SUSTAIN_PEDAL) + ) + { + /* + The sustain flag is presently clear and the damper pedal is off. + We are therefore transitioning from damper pedal OFF to + damper pedal ON. Currently sounding notes should be left + unchanged. However, we should try to "catch" notes if possible. + If any notes have levels >= sustain level, catch them, + otherwise, let them continue to release. + */ + VMCatchNotesForSustainPedal(pVoiceMgr, pSynth, channel); + } + + /* turn the sustain pedal on */ + pChannel->channelFlags |= CHANNEL_FLAG_SUSTAIN_PEDAL; + } + + break; +#ifdef _REVERB + case MIDI_CONTROLLER_REVERB_SEND: + /* we treat send as a 7-bit controller and only use the MSB */ + pSynth->channels[channel].reverbSend = value; + break; +#endif +#ifdef _CHORUS + case MIDI_CONTROLLER_CHORUS_SEND: + /* we treat send as a 7-bit controller and only use the MSB */ + pSynth->channels[channel].chorusSend = value; + break; +#endif + case MIDI_CONTROLLER_RESET_CONTROLLERS: + /* despite the Midi message name, not ALL controllers are reset */ + pChannel->modWheel = DEFAULT_MOD_WHEEL; + pChannel->expression = DEFAULT_EXPRESSION; + + /* turn the sustain pedal off as default/reset */ + pChannel->channelFlags &= ~CHANNEL_FLAG_SUSTAIN_PEDAL; + pChannel->pitchBend = DEFAULT_PITCH_BEND; + + /* reset channel pressure */ + pChannel->channelPressure = DEFAULT_CHANNEL_PRESSURE; + + /* reset RPN values */ + pChannel->registeredParam = DEFAULT_REGISTERED_PARAM; + pChannel->pitchBendSensitivity = DEFAULT_PITCH_BEND_SENSITIVITY; + pChannel->finePitch = DEFAULT_FINE_PITCH; + pChannel->coarsePitch = DEFAULT_COARSE_PITCH; + + /* + program change, bank select, channel volume CC7, pan CC10 + are NOT reset + */ + break; + + /* + For logical reasons, the RPN data entry are grouped together. + However, keep in mind that these cases are not necessarily in + ascending order. + e.g., MIDI_CONTROLLER_DATA_ENTRY_MSB == 6, + whereas MIDI_CONTROLLER_SUSTAIN_PEDAL == 64. + So arrange these case statements in whatever manner is more efficient for + the processor / compiler. + */ + case MIDI_CONTROLLER_ENTER_DATA_MSB: + case MIDI_CONTROLLER_ENTER_DATA_LSB: + case MIDI_CONTROLLER_SELECT_RPN_LSB: + case MIDI_CONTROLLER_SELECT_RPN_MSB: + case MIDI_CONTROLLER_SELECT_NRPN_MSB: + case MIDI_CONTROLLER_SELECT_NRPN_LSB: + VMUpdateRPNStateMachine(pSynth, channel, controller, value); + break; + + case MIDI_CONTROLLER_ALL_SOUND_OFF: + case MIDI_CONTROLLER_ALL_NOTES_OFF: + case MIDI_CONTROLLER_OMNI_OFF: + case MIDI_CONTROLLER_OMNI_ON: + case MIDI_CONTROLLER_MONO_ON_POLY_OFF: + case MIDI_CONTROLLER_POLY_ON_MONO_OFF: + /* NOTE: we treat all sounds off the same as all notes off */ + VMAllNotesOff(pVoiceMgr, pSynth, channel); + break; + + default: +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMControlChange: controller %d not yet implemented\n", controller); */ } +#endif + break; + + } + + return; +} + +/*---------------------------------------------------------------------------- + * VMUpdateRPNStateMachine() + *---------------------------------------------------------------------------- + * Purpose: + * Call this function when we want to parse RPN related controller messages. + * We only support RPN0 (pitch bend sensitivity), RPN1 (fine tuning) and + * RPN2 (coarse tuning). Any other RPNs or NRPNs are ignored for now. + *. + * Supports any order, so not a state machine anymore. This function was + * rewritten to work correctly regardless of order. + * + * Inputs: + * nChannel - the channel this controller message is coming from + * nControllerNumber - which RPN related controller + * nControlValue - the value of the RPN related controller + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * returns EAS_RESULT, which is typically EAS_SUCCESS, since there are + * few possible errors + * + * Side Effects: + * gsSynthObject.m_sChannel[nChannel].m_nPitchBendSensitivity + * (or m_nFinePitch or m_nCoarsePitch) + * will be updated if the proper RPN message is received. + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMUpdateRPNStateMachine (S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 controller, EAS_U8 value) +{ + S_SYNTH_CHANNEL *pChannel; + +#ifdef _DEBUG_VM + if (channel >= NUM_SYNTH_CHANNELS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMUpdateRPNStateMachines: error, %d invalid channel number\n", + channel); */ } + return EAS_FAILURE; + } +#endif + + pChannel = &(pSynth->channels[channel]); + + switch (controller) + { + case MIDI_CONTROLLER_SELECT_NRPN_MSB: + case MIDI_CONTROLLER_SELECT_NRPN_LSB: + pChannel->registeredParam = DEFAULT_REGISTERED_PARAM; + break; + case MIDI_CONTROLLER_SELECT_RPN_MSB: + pChannel->registeredParam = + (pChannel->registeredParam & 0x7F) | (value<<7); + break; + case MIDI_CONTROLLER_SELECT_RPN_LSB: + pChannel->registeredParam = + (pChannel->registeredParam & 0x7F00) | value; + break; + case MIDI_CONTROLLER_ENTER_DATA_MSB: + switch (pChannel->registeredParam) + { + case 0: + pChannel->pitchBendSensitivity = value * 100; + break; + case 1: + /*lint -e{702} */ + pChannel->finePitch = (EAS_I8)((((value << 7) - 8192) * 100) >> 13); + break; + case 2: + pChannel->coarsePitch = (EAS_I8)(value - 64); + break; + default: + break; + } + break; + case MIDI_CONTROLLER_ENTER_DATA_LSB: + switch (pChannel->registeredParam) + { + case 0: + //ignore lsb + break; + case 1: + //ignore lsb + break; + case 2: + //ignore lsb + break; + default: + break; + } + break; + default: + return EAS_FAILURE; //not a RPN related controller + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMUpdateStaticChannelParameters() + *---------------------------------------------------------------------------- + * Purpose: + * Update all of the static channel parameters for channels that have had + * a controller change values + * Or if the synth has signalled that all channels must forcibly + * be updated + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * none + * + * Side Effects: + * - psSynthObject->m_sChannel[].m_nStaticGain and m_nStaticPitch + * are updated for channels whose controller values have changed + * or if the synth has signalled that all channels must forcibly + * be updated + *---------------------------------------------------------------------------- +*/ +void VMUpdateStaticChannelParameters (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth) +{ + EAS_INT channel; + + if (pSynth->synthFlags & SYNTH_FLAG_UPDATE_ALL_CHANNEL_PARAMETERS) + { + /* + the synth wants us to forcibly update all channel + parameters. This event occurs when we are about to + finish resetting the synth + */ + for (channel = 0; channel < NUM_SYNTH_CHANNELS; channel++) + { +#ifdef _HYBRID_SYNTH + if (pSynth->channels[channel].regionIndex & FLAG_RGN_IDX_FM_SYNTH) + pSecondarySynth->pfUpdateChannel(pVoiceMgr, pSynth, (EAS_U8) channel); + else + pPrimarySynth->pfUpdateChannel(pVoiceMgr, pSynth, (EAS_U8) channel); +#else + pPrimarySynth->pfUpdateChannel(pVoiceMgr, pSynth, (EAS_U8) channel); +#endif + } + + /* + clear the flag to indicates we have now forcibly + updated all channel parameters + */ + pSynth->synthFlags &= ~SYNTH_FLAG_UPDATE_ALL_CHANNEL_PARAMETERS; + } + else + { + + /* only update channel params if signalled by a channel flag */ + for (channel = 0; channel < NUM_SYNTH_CHANNELS; channel++) + { + if ( 0 != (pSynth->channels[channel].channelFlags & CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS)) + { +#ifdef _HYBRID_SYNTH + if (pSynth->channels[channel].regionIndex & FLAG_RGN_IDX_FM_SYNTH) + pSecondarySynth->pfUpdateChannel(pVoiceMgr, pSynth, (EAS_U8) channel); + else + pPrimarySynth->pfUpdateChannel(pVoiceMgr, pSynth, (EAS_U8) channel); +#else + pPrimarySynth->pfUpdateChannel(pVoiceMgr, pSynth, (EAS_U8) channel); +#endif + } + } + + } + + return; +} + +/*---------------------------------------------------------------------------- + * VMFindProgram() + *---------------------------------------------------------------------------- + * Purpose: + * Look up an individual program in sound library. This function + * searches the bank list for a program, then the individual program + * list. + * + * Inputs: + * + * Outputs: + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT VMFindProgram (const S_EAS *pEAS, EAS_U32 bank, EAS_U8 programNum, EAS_U16 *pRegionIndex) +{ + EAS_U32 locale; + const S_PROGRAM *p; + EAS_U16 i; + EAS_U16 regionIndex; + + /* make sure we have a valid sound library */ + if (pEAS == NULL) + return EAS_FAILURE; + + /* search the banks */ + for (i = 0; i < pEAS->numBanks; i++) + { + if (bank == (EAS_U32) pEAS->pBanks[i].locale) + { + regionIndex = pEAS->pBanks[i].regionIndex[programNum]; + if (regionIndex != INVALID_REGION_INDEX) + { + *pRegionIndex = regionIndex; + return EAS_SUCCESS; + } + break; + } + } + + /* establish locale */ + locale = ( bank << 8) | programNum; + + /* search for program */ + for (i = 0, p = pEAS->pPrograms; i < pEAS->numPrograms; i++, p++) + { + if (p->locale == locale) + { + *pRegionIndex = p->regionIndex; + return EAS_SUCCESS; + } + } + + return EAS_FAILURE; +} + +#ifdef DLS_SYNTHESIZER +/*---------------------------------------------------------------------------- + * VMFindDLSProgram() + *---------------------------------------------------------------------------- + * Purpose: + * Look up an individual program in sound library. This function + * searches the bank list for a program, then the individual program + * list. + * + * Inputs: + * + * Outputs: + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT VMFindDLSProgram (const S_DLS *pDLS, EAS_U32 bank, EAS_U8 programNum, EAS_U16 *pRegionIndex) +{ + EAS_U32 locale; + const S_PROGRAM *p; + EAS_U16 i; + + /* make sure we have a valid sound library */ + if (pDLS == NULL) + return EAS_FAILURE; + + /* establish locale */ + locale = (bank << 8) | programNum; + + /* search for program */ + for (i = 0, p = pDLS->pDLSPrograms; i < pDLS->numDLSPrograms; i++, p++) + { + if (p->locale == locale) + { + *pRegionIndex = p->regionIndex; + return EAS_SUCCESS; + } + } + + return EAS_FAILURE; +} +#endif + +/*---------------------------------------------------------------------------- + * VMProgramChange() + *---------------------------------------------------------------------------- + * Purpose: + * Change the instrument (program) for the given channel. + * + * Depending on the program number, and the bank selected for this channel, the + * program may be in ROM, RAM (from SMAF or CMX related RAM wavetable), or + * Alternate wavetable (from mobile DLS or other DLS file) + * + * This function figures out what wavetable should be used, and sets it up as the + * wavetable to use for this channel. Also the channel may switch from a melodic + * channel to a rhythm channel, or vice versa. + * + * Inputs: + * + * Outputs: + * Side Effects: + * gsSynthObject.m_sChannel[nChannel].m_nProgramNumber is likely changed + * gsSynthObject.m_sChannel[nChannel].m_psEAS may be changed + * gsSynthObject.m_sChannel[nChannel].m_bRhythmChannel may be changed + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pVoiceMgr) reserved for future use */ +void VMProgramChange (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 program) +{ + S_SYNTH_CHANNEL *pChannel; + EAS_U32 bank; + EAS_U16 regionIndex; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "VMProgramChange: vSynthNum=%d, channel=%d, program=%d\n", pSynth->vSynthNum, channel, program); */ } +#endif + + /* setup pointer to MIDI channel data */ + pChannel = &pSynth->channels[channel]; + bank = pChannel->bankNum; + + /* allow channels to switch between being melodic or rhythm channels, using GM2 CC values */ + if ((bank & 0xFF00) == DEFAULT_RHYTHM_BANK_NUMBER) + { + /* make it a rhythm channel */ + pChannel->channelFlags |= CHANNEL_FLAG_RHYTHM_CHANNEL; + } + else if ((bank & 0xFF00) == DEFAULT_MELODY_BANK_NUMBER) + { + /* make it a melody channel */ + pChannel->channelFlags &= ~CHANNEL_FLAG_RHYTHM_CHANNEL; + } + + regionIndex = DEFAULT_REGION_INDEX; + +#ifdef EXTERNAL_AUDIO + /* give the external audio interface a chance to handle it */ + if (pSynth->cbProgChgFunc != NULL) + { + S_EXT_AUDIO_PRG_CHG prgChg; + prgChg.channel = channel; + prgChg.bank = (EAS_U16) bank; + prgChg.program = program; + if (pSynth->cbProgChgFunc(pSynth->pExtAudioInstData, &prgChg)) + pChannel->channelFlags |= CHANNEL_FLAG_EXTERNAL_AUDIO; + } + +#endif + + +#ifdef DLS_SYNTHESIZER + /* first check for DLS program that may overlay the internal instrument */ + if (VMFindDLSProgram(pSynth->pDLS, bank, program, ®ionIndex) != EAS_SUCCESS) +#endif + + /* braces to support 'if' clause above */ + { + + /* look in the internal banks */ + if (VMFindProgram(pSynth->pEAS, bank, program, ®ionIndex) != EAS_SUCCESS) + + /* fall back to default bank */ + { + if (pSynth->channels[channel].channelFlags & CHANNEL_FLAG_RHYTHM_CHANNEL) + bank = DEFAULT_RHYTHM_BANK_NUMBER; + else + bank = DEFAULT_MELODY_BANK_NUMBER; + + if (VMFindProgram(pSynth->pEAS, bank, program, ®ionIndex) != EAS_SUCCESS) + + /* switch to program 0 in the default bank */ + { + if (VMFindProgram(pSynth->pEAS, bank, 0, ®ionIndex) != EAS_SUCCESS) + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "VMProgramChange: No program @ %03d:%03d:%03d\n", + (bank >> 8) & 0x7f, bank & 0x7f, program); */ } + } + } + } + + /* we have our new program change for this channel */ + pChannel->programNum = program; + pChannel->regionIndex = regionIndex; + + /* + set a channel flag to request parameter updates + for all the voices associated with this channel + */ + pChannel->channelFlags |= CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS; + + return; +} + +/*---------------------------------------------------------------------------- + * VMAddSamples() + *---------------------------------------------------------------------------- + * Purpose: + * Synthesize the requested number of samples (block based processing) + * + * Inputs: + * nNumSamplesToAdd - number of samples to write to buffer + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * number of voices rendered + * + * Side Effects: + * - samples are added to the presently free buffer + * + *---------------------------------------------------------------------------- +*/ +EAS_I32 VMAddSamples (S_VOICE_MGR *pVoiceMgr, EAS_I32 *pMixBuffer, EAS_I32 numSamples) +{ + S_SYNTH *pSynth; + EAS_INT voicesRendered; + EAS_INT voiceNum; + EAS_BOOL done; + +#ifdef _REVERB + EAS_PCM *pReverbSendBuffer; +#endif // ifdef _REVERB + +#ifdef _CHORUS + EAS_PCM *pChorusSendBuffer; +#endif // ifdef _CHORUS + + voicesRendered = 0; + for (voiceNum = 0; voiceNum < MAX_SYNTH_VOICES; voiceNum++) + { + + /* retarget stolen voices */ + if ((pVoiceMgr->voices[voiceNum].voiceState == eVoiceStateStolen) && (pVoiceMgr->voices[voiceNum].gain <= 0)) + VMRetargetStolenVoice(pVoiceMgr, voiceNum); + + /* get pointer to virtual synth */ + pSynth = pVoiceMgr->pSynth[pVoiceMgr->voices[voiceNum].channel >> 4]; + + /* synthesize active voices */ + if (pVoiceMgr->voices[voiceNum].voiceState != eVoiceStateFree) + { + done = GetSynthPtr(voiceNum)->pfUpdateVoice(pVoiceMgr, pSynth, &pVoiceMgr->voices[voiceNum], GetAdjustedVoiceNum(voiceNum), pMixBuffer, numSamples); + voicesRendered++; + + /* voice is finished */ + if (done == EAS_TRUE) + { + /* set gain of stolen voice to zero so it will be restarted */ + if (pVoiceMgr->voices[voiceNum].voiceState == eVoiceStateStolen) + pVoiceMgr->voices[voiceNum].gain = 0; + + /* or return it to the free voice pool */ + else + VMFreeVoice(pVoiceMgr, pSynth, &pVoiceMgr->voices[voiceNum]); + } + + /* if this voice is scheduled to be muted, set the mute flag */ + if (pVoiceMgr->voices[voiceNum].voiceFlags & VOICE_FLAG_DEFER_MUTE) + { + pVoiceMgr->voices[voiceNum].voiceFlags &= ~(VOICE_FLAG_DEFER_MUTE | VOICE_FLAG_DEFER_MIDI_NOTE_OFF); + VMMuteVoice(pVoiceMgr, voiceNum); + } + + /* if voice just started, advance state to play */ + if (pVoiceMgr->voices[voiceNum].voiceState == eVoiceStateStart) + pVoiceMgr->voices[voiceNum].voiceState = eVoiceStatePlay; + } + } + + return voicesRendered; +} + +/*---------------------------------------------------------------------------- + * VMRender() + *---------------------------------------------------------------------------- + * Purpose: + * This routine renders a frame of audio + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * pVoicesRendered - number of voices rendered this frame + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMRender (S_VOICE_MGR *pVoiceMgr, EAS_I32 numSamples, EAS_I32 *pMixBuffer, EAS_I32 *pVoicesRendered) +{ + S_SYNTH *pSynth; + EAS_INT i; + EAS_INT channel; + +#ifdef _CHECKED_BUILD + SanityCheck(pVoiceMgr); +#endif + + /* update MIDI channel parameters */ + *pVoicesRendered = 0; + for (i = 0; i < MAX_VIRTUAL_SYNTHESIZERS; i++) + { + if (pVoiceMgr->pSynth[i] != NULL) + VMUpdateStaticChannelParameters(pVoiceMgr, pVoiceMgr->pSynth[i]); + } + + /* synthesize a buffer of audio */ + *pVoicesRendered = VMAddSamples(pVoiceMgr, pMixBuffer, numSamples); + + /* + * check for deferred note-off messages + * If flag is set, that means one or more voices are expecting deferred + * midi note-off messages because the midi note-on and corresponding midi + * note-off requests occurred during the same update interval. The goal + * is the defer the note-off request so that the note can at least start. + */ + for (i = 0; i < MAX_VIRTUAL_SYNTHESIZERS; i++) + { + pSynth = pVoiceMgr->pSynth[i]; + + if (pSynth== NULL) + continue; + + if (pSynth->synthFlags & SYNTH_FLAG_DEFERRED_MIDI_NOTE_OFF_PENDING) + VMDeferredStopNote(pVoiceMgr, pSynth); + + /* check if we need to reset the synth */ + if ((pSynth->synthFlags & SYNTH_FLAG_RESET_IS_REQUESTED) && + (pSynth->numActiveVoices == 0)) + { + /* + complete the process of resetting the synth now that + all voices have muted + */ +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMAddSamples: complete the reset process\n"); */ } +#endif + + VMInitializeAllChannels(pVoiceMgr, pSynth); + VMInitializeAllVoices(pVoiceMgr, pSynth->vSynthNum); + + /* clear the reset flag */ + pSynth->synthFlags &= ~SYNTH_FLAG_RESET_IS_REQUESTED; + } + + /* clear channel update flags */ + for (channel = 0; channel < NUM_SYNTH_CHANNELS; channel++) + pSynth->channels[channel].channelFlags &= ~CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS; + + } + +#ifdef _CHECKED_BUILD + SanityCheck(pVoiceMgr); +#endif + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMInitWorkload() + *---------------------------------------------------------------------------- + * Purpose: + * Clears the workload counter + * + * Inputs: + * pVoiceMgr - pointer to instance data + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMInitWorkload (S_VOICE_MGR *pVoiceMgr) +{ + pVoiceMgr->workload = 0; +} + +/*---------------------------------------------------------------------------- + * VMSetWorkload() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the max workload for a single frame. + * + * Inputs: + * pVoiceMgr - pointer to instance data + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMSetWorkload (S_VOICE_MGR *pVoiceMgr, EAS_I32 maxWorkLoad) +{ + pVoiceMgr->maxWorkLoad = maxWorkLoad; +} + +/*---------------------------------------------------------------------------- + * VMCheckWorkload() + *---------------------------------------------------------------------------- + * Purpose: + * Checks to see if work load has been exceeded on this frame. + * + * Inputs: + * pVoiceMgr - pointer to instance data + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_BOOL VMCheckWorkload (S_VOICE_MGR *pVoiceMgr) +{ + if (pVoiceMgr->maxWorkLoad > 0) + return (EAS_BOOL) (pVoiceMgr->workload >= pVoiceMgr->maxWorkLoad); + return EAS_FALSE; +} + +/*---------------------------------------------------------------------------- + * VMActiveVoices() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the number of active voices in the synthesizer. + * + * Inputs: + * pEASData - pointer to instance data + * + * Outputs: + * Returns the number of active voices + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_I32 VMActiveVoices (S_SYNTH *pSynth) +{ + return pSynth->numActiveVoices; +} + +/*---------------------------------------------------------------------------- + * VMSetSynthPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Set the synth to a new polyphony value. Value must be >= 1 and + * <= MAX_SYNTH_VOICES. This function will pin the polyphony at those limits + * + * Inputs: + * pVoiceMgr pointer to synthesizer data + * polyphonyCount desired polyphony count + * synth synthesizer number (0 = onboard, 1 = DSP) + * + * Outputs: + * Returns error code + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMSetSynthPolyphony (S_VOICE_MGR *pVoiceMgr, EAS_I32 synth, EAS_I32 polyphonyCount) +{ + EAS_INT i; + EAS_INT activeVoices; + + /* lower limit */ + if (polyphonyCount < 1) + polyphonyCount = 1; + + /* split architecture */ +#if defined(_SECONDARY_SYNTH) || defined(EAS_SPLIT_WT_SYNTH) + if (synth == EAS_MCU_SYNTH) + { + if (polyphonyCount > NUM_PRIMARY_VOICES) + polyphonyCount = NUM_PRIMARY_VOICES; + if (pVoiceMgr->maxPolyphonyPrimary == polyphonyCount) + return EAS_SUCCESS; + pVoiceMgr->maxPolyphonyPrimary = (EAS_U16) polyphonyCount; + } + else if (synth == EAS_DSP_SYNTH) + { + if (polyphonyCount > NUM_SECONDARY_VOICES) + polyphonyCount = NUM_SECONDARY_VOICES; + if (pVoiceMgr->maxPolyphonySecondary == polyphonyCount) + return EAS_SUCCESS; + pVoiceMgr->maxPolyphonySecondary = (EAS_U16) polyphonyCount; + } + else + return EAS_ERROR_PARAMETER_RANGE; + + /* setting for SP-MIDI */ + pVoiceMgr->maxPolyphony = pVoiceMgr->maxPolyphonyPrimary + pVoiceMgr->maxPolyphonySecondary; + + /* standard architecture */ +#else + if (synth != EAS_MCU_SYNTH) + return EAS_ERROR_PARAMETER_RANGE; + + /* pin desired value to possible limits */ + if (polyphonyCount > MAX_SYNTH_VOICES) + polyphonyCount = MAX_SYNTH_VOICES; + + /* set polyphony, if value is different than current value */ + if (pVoiceMgr->maxPolyphony == polyphonyCount) + return EAS_SUCCESS; + + pVoiceMgr->maxPolyphony = (EAS_U16) polyphonyCount; +#endif + + /* if SPMIDI enabled, update channel masking based on new polyphony */ + for (i = 0; i < MAX_VIRTUAL_SYNTHESIZERS; i++) + { + if (pVoiceMgr->pSynth[i]) + { + if (pVoiceMgr->pSynth[i]->synthFlags & SYNTH_FLAG_SP_MIDI_ON) + VMMIPUpdateChannelMuting(pVoiceMgr, pVoiceMgr->pSynth[i]); + else + pVoiceMgr->pSynth[i]->poolAlloc[0] = (EAS_U8) polyphonyCount; + } + } + + /* are we under polyphony limit? */ + if (pVoiceMgr->activeVoices <= polyphonyCount) + return EAS_SUCCESS; + + /* count the number of active voices */ + activeVoices = 0; + for (i = 0; i < MAX_SYNTH_VOICES; i++) + { + + /* is voice active? */ + if ((pVoiceMgr->voices[i].voiceState != eVoiceStateFree) && (pVoiceMgr->voices[i].voiceState != eVoiceStateMuting)) + activeVoices++; + } + + /* we may have to mute voices to reach new target */ + while (activeVoices > polyphonyCount) + { + S_SYNTH *pSynth; + S_SYNTH_VOICE *pVoice; + EAS_I32 currentPriority, bestPriority; + EAS_INT bestCandidate; + + /* find the lowest priority voice */ + bestPriority = bestCandidate = -1; + for (i = 0; i < MAX_SYNTH_VOICES; i++) + { + + pVoice = &pVoiceMgr->voices[i]; + + /* ignore free and muting voices */ + if ((pVoice->voiceState == eVoiceStateFree) || (pVoice->voiceState == eVoiceStateMuting)) + continue; + + pSynth = pVoiceMgr->pSynth[GET_VSYNTH(pVoice->channel)]; + + /* if voice is stolen or just started, reduce the likelihood it will be stolen */ + if (( pVoice->voiceState == eVoiceStateStolen) || (pVoice->voiceFlags & VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET)) + { + /* include velocity */ + currentPriority = 128 - pVoice->nextVelocity; + + /* include channel priority */ + currentPriority += pSynth->channels[GET_CHANNEL(pVoice->nextChannel)].pool << CHANNEL_PRIORITY_STEAL_WEIGHT; + } + else + { + /* include age */ + currentPriority = (EAS_I32) pVoice->age << NOTE_AGE_STEAL_WEIGHT; + + /* include note gain -higher gain is lower steal value */ + /*lint -e{704} use shift for performance */ + currentPriority += ((32768 >> (12 - NOTE_GAIN_STEAL_WEIGHT)) + 256) - + ((EAS_I32) pVoice->gain >> (12 - NOTE_GAIN_STEAL_WEIGHT)); + + /* include channel priority */ + currentPriority += pSynth->channels[GET_CHANNEL(pVoice->channel)].pool << CHANNEL_PRIORITY_STEAL_WEIGHT; + } + + /* include synth priority */ + currentPriority += pSynth->priority << SYNTH_PRIORITY_WEIGHT; + + /* is this the best choice so far? */ + if (currentPriority > bestPriority) + { + bestPriority = currentPriority; + bestCandidate = i; + } + } + + /* shutdown best candidate */ + if (bestCandidate < 0) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "VMSetPolyphony: Unable to reduce polyphony\n"); */ } + break; + } + + /* shut down this voice */ + /*lint -e{771} pSynth is initialized if bestCandidate >= 0 */ + VMMuteVoice(pVoiceMgr, bestCandidate); + activeVoices--; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMGetSynthPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current polyphony setting + * + * Inputs: + * pVoiceMgr pointer to synthesizer data + * synth synthesizer number (0 = onboard, 1 = DSP) + * + * Outputs: + * Returns actual polyphony value set, as pinned by limits + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMGetSynthPolyphony (S_VOICE_MGR *pVoiceMgr, EAS_I32 synth, EAS_I32 *pPolyphonyCount) +{ + +#if defined(_SECONDARY_SYNTH) || defined(EAS_SPLIT_WT_SYNTH) + if (synth == EAS_MCU_SYNTH) + *pPolyphonyCount = pVoiceMgr->maxPolyphonyPrimary; + else if (synth == EAS_DSP_SYNTH) + *pPolyphonyCount = pVoiceMgr->maxPolyphonySecondary; + else + return EAS_ERROR_PARAMETER_RANGE; +#else + if (synth != EAS_MCU_SYNTH) + return EAS_ERROR_PARAMETER_RANGE; + *pPolyphonyCount = pVoiceMgr->maxPolyphony; +#endif + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMSetPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Set the virtual synth polyphony. 0 = no limit (i.e. can use + * all available voices). + * + * Inputs: + * pVoiceMgr pointer to synthesizer data + * polyphonyCount desired polyphony count + * pSynth pointer to virtual synth + * + * Outputs: + * Returns error code + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMSetPolyphony (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 polyphonyCount) +{ + EAS_INT i; + EAS_INT activeVoices; + + /* check limits */ + if (polyphonyCount < 0) + return EAS_ERROR_PARAMETER_RANGE; + + /* zero is max polyphony */ + if ((polyphonyCount == 0) || (polyphonyCount > MAX_SYNTH_VOICES)) + { + pSynth->maxPolyphony = 0; + return EAS_SUCCESS; + } + + /* set new polyphony */ + pSynth->maxPolyphony = (EAS_U16) polyphonyCount; + + /* max polyphony is minimum of virtual synth and actual synth */ + if (polyphonyCount > pVoiceMgr->maxPolyphony) + polyphonyCount = pVoiceMgr->maxPolyphony; + + /* if SP-MIDI mode, update the channel muting */ + if (pSynth->synthFlags & SYNTH_FLAG_SP_MIDI_ON) + VMMIPUpdateChannelMuting(pVoiceMgr, pSynth); + else + pSynth->poolAlloc[0] = (EAS_U8) polyphonyCount; + + /* are we under polyphony limit? */ + if (pSynth->numActiveVoices <= polyphonyCount) + return EAS_SUCCESS; + + /* count the number of active voices */ + activeVoices = 0; + for (i = 0; i < MAX_SYNTH_VOICES; i++) + { + /* this synth? */ + if (GET_VSYNTH(pVoiceMgr->voices[i].nextChannel) != pSynth->vSynthNum) + continue; + + /* is voice active? */ + if ((pVoiceMgr->voices[i].voiceState != eVoiceStateFree) && (pVoiceMgr->voices[i].voiceState != eVoiceStateMuting)) + activeVoices++; + } + + /* we may have to mute voices to reach new target */ + while (activeVoices > polyphonyCount) + { + S_SYNTH_VOICE *pVoice; + EAS_I32 currentPriority, bestPriority; + EAS_INT bestCandidate; + + /* find the lowest priority voice */ + bestPriority = bestCandidate = -1; + for (i = 0; i < MAX_SYNTH_VOICES; i++) + { + pVoice = &pVoiceMgr->voices[i]; + + /* this synth? */ + if (GET_VSYNTH(pVoice->nextChannel) != pSynth->vSynthNum) + continue; + + /* if voice is stolen or just started, reduce the likelihood it will be stolen */ + if (( pVoice->voiceState == eVoiceStateStolen) || (pVoice->voiceFlags & VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET)) + { + /* include velocity */ + currentPriority = 128 - pVoice->nextVelocity; + + /* include channel priority */ + currentPriority += pSynth->channels[GET_CHANNEL(pVoice->nextChannel)].pool << CHANNEL_PRIORITY_STEAL_WEIGHT; + } + else + { + /* include age */ + currentPriority = (EAS_I32) pVoice->age << NOTE_AGE_STEAL_WEIGHT; + + /* include note gain -higher gain is lower steal value */ + /*lint -e{704} use shift for performance */ + currentPriority += ((32768 >> (12 - NOTE_GAIN_STEAL_WEIGHT)) + 256) - + ((EAS_I32) pVoice->gain >> (12 - NOTE_GAIN_STEAL_WEIGHT)); + + /* include channel priority */ + currentPriority += pSynth->channels[GET_CHANNEL(pVoice->nextChannel)].pool << CHANNEL_PRIORITY_STEAL_WEIGHT; + } + + /* is this the best choice so far? */ + if (currentPriority > bestPriority) + { + bestPriority = currentPriority; + bestCandidate = i; + } + } + + /* shutdown best candidate */ + if (bestCandidate < 0) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "VMSetPolyphony: Unable to reduce polyphony\n"); */ } + break; + } + + /* shut down this voice */ + VMMuteVoice(pVoiceMgr, bestCandidate); + activeVoices--; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMGetPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Get the virtual synth polyphony + * + * Inputs: + * pVoiceMgr pointer to synthesizer data + * pPolyphonyCount pointer to variable to hold polyphony count + * pSynth pointer to virtual synth + * + * Outputs: + * Returns error code + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pVoiceMgr) reserved for future use */ +EAS_RESULT VMGetPolyphony (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 *pPolyphonyCount) +{ + *pPolyphonyCount = (EAS_U16) pSynth->maxPolyphony; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMSetPriority() + *---------------------------------------------------------------------------- + * Purpose: + * Set the virtual synth priority + * + * Inputs: + * pVoiceMgr pointer to synthesizer data + * priority new priority + * pSynth pointer to virtual synth + * + * Outputs: + * Returns error code + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pVoiceMgr) reserved for future use */ +EAS_RESULT VMSetPriority (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 priority) +{ + pSynth->priority = (EAS_U8) priority ; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMGetPriority() + *---------------------------------------------------------------------------- + * Purpose: + * Get the virtual synth priority + * + * Inputs: + * pVoiceMgr pointer to synthesizer data + * pPriority pointer to variable to hold priority + * pSynth pointer to virtual synth + * + * Outputs: + * Returns error code + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pVoiceMgr) reserved for future use */ +EAS_RESULT VMGetPriority (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 *pPriority) +{ + *pPriority = pSynth->priority; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMSetVolume() + *---------------------------------------------------------------------------- + * Purpose: + * Set the master volume for this synthesizer for this sequence. + * + * Inputs: + * nSynthVolume - the desired master volume + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * + * Side Effects: + * overrides any previously set master volume from sysex + * + *---------------------------------------------------------------------------- +*/ +void VMSetVolume (S_SYNTH *pSynth, EAS_U16 masterVolume) +{ + pSynth->masterVolume = masterVolume; + pSynth->synthFlags |= SYNTH_FLAG_UPDATE_ALL_CHANNEL_PARAMETERS; +} + +/*---------------------------------------------------------------------------- + * VMSetPitchBendRange() + *---------------------------------------------------------------------------- + * Set the pitch bend range for the given channel. + *---------------------------------------------------------------------------- +*/ +void VMSetPitchBendRange (S_SYNTH *pSynth, EAS_INT channel, EAS_I16 pitchBendRange) +{ + pSynth->channels[channel].pitchBendSensitivity = pitchBendRange; +} + +/*---------------------------------------------------------------------------- + * VMValidateEASLib() + *---------------------------------------------------------------------------- + * Validates an EAS library + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMValidateEASLib (EAS_SNDLIB_HANDLE pEAS) +{ + /* validate the sound library */ + if (pEAS) + { + if (pEAS->identifier != _EAS_LIBRARY_VERSION) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMValidateEASLib: Sound library mismatch in sound library: Read 0x%08x, expected 0x%08x\n", + pEAS->identifier, _EAS_LIBRARY_VERSION); */ } + return EAS_ERROR_SOUND_LIBRARY; + } + + /* check sample rate */ + if ((pEAS->libAttr & LIBFORMAT_SAMPLE_RATE_MASK) != _OUTPUT_SAMPLE_RATE) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMValidateEASLib: Sample rate mismatch in sound library: Read %lu, expected %lu\n", + pEAS->libAttr & LIBFORMAT_SAMPLE_RATE_MASK, _OUTPUT_SAMPLE_RATE); */ } + return EAS_ERROR_SOUND_LIBRARY; + } + +#ifdef _WT_SYNTH + /* check sample bit depth */ +#ifdef _8_BIT_SAMPLES + if (pEAS->libAttr & LIB_FORMAT_16_BIT_SAMPLES) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMValidateEASLib: Expected 8-bit samples and found 16-bit\n", + pEAS->libAttr & LIBFORMAT_SAMPLE_RATE_MASK, _OUTPUT_SAMPLE_RATE); */ } + return EAS_ERROR_SOUND_LIBRARY; + } +#endif +#ifdef _16_BIT_SAMPLES + if ((pEAS->libAttr & LIB_FORMAT_16_BIT_SAMPLES) == 0) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMValidateEASLib: Expected 16-bit samples and found 8-bit\n", + pEAS->libAttr & LIBFORMAT_SAMPLE_RATE_MASK, _OUTPUT_SAMPLE_RATE); */ } + return EAS_ERROR_SOUND_LIBRARY; + } +#endif +#endif + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMSetGlobalEASLib() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the EAS library to be used by the synthesizer + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMSetGlobalEASLib (S_VOICE_MGR *pVoiceMgr, EAS_SNDLIB_HANDLE pEAS) +{ + EAS_RESULT result; + + result = VMValidateEASLib(pEAS); + if (result != EAS_SUCCESS) + return result; + + pVoiceMgr->pGlobalEAS = pEAS; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMSetEASLib() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the EAS library to be used by the synthesizer + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMSetEASLib (S_SYNTH *pSynth, EAS_SNDLIB_HANDLE pEAS) +{ + EAS_RESULT result; + + result = VMValidateEASLib(pEAS); + if (result != EAS_SUCCESS) + return result; + + pSynth->pEAS = pEAS; + return EAS_SUCCESS; +} + +#ifdef DLS_SYNTHESIZER +/*---------------------------------------------------------------------------- + * VMSetGlobalDLSLib() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the DLS library to be used by the synthesizer + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMSetGlobalDLSLib (EAS_DATA_HANDLE pEASData, EAS_DLSLIB_HANDLE pDLS) +{ + + if (pEASData->pVoiceMgr->pGlobalDLS) + DLSCleanup(pEASData->hwInstData, pEASData->pVoiceMgr->pGlobalDLS); + + pEASData->pVoiceMgr->pGlobalDLS = pDLS; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMSetDLSLib() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the DLS library to be used by the synthesizer + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMSetDLSLib (S_SYNTH *pSynth, EAS_DLSLIB_HANDLE pDLS) +{ + pSynth->pDLS = pDLS; + return EAS_SUCCESS; +} +#endif + +/*---------------------------------------------------------------------------- + * VMSetTranposition() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the global key transposition used by the synthesizer. + * Transposes all melodic instruments up or down by the specified + * amount. Range is limited to +/-12 semitones. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMSetTranposition (S_SYNTH *pSynth, EAS_I32 transposition) +{ + pSynth->globalTranspose = (EAS_I8) transposition; +} + +/*---------------------------------------------------------------------------- + * VMGetTranposition() + *---------------------------------------------------------------------------- + * Purpose: + * Gets the global key transposition used by the synthesizer. + * Transposes all melodic instruments up or down by the specified + * amount. Range is limited to +/-12 semitones. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMGetTranposition (S_SYNTH *pSynth, EAS_I32 *pTransposition) +{ + *pTransposition = pSynth->globalTranspose; +} + +/*---------------------------------------------------------------------------- + * VMGetNoteCount() + *---------------------------------------------------------------------------- +* Returns the total note count +*---------------------------------------------------------------------------- +*/ +EAS_I32 VMGetNoteCount (S_SYNTH *pSynth) +{ + return pSynth->totalNoteCount; +} + +/*---------------------------------------------------------------------------- + * VMMIDIShutdown() + *---------------------------------------------------------------------------- + * Purpose: + * Clean up any Synth related system issues. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * None + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMMIDIShutdown (S_EAS_DATA *pEASData, S_SYNTH *pSynth) +{ + EAS_INT vSynthNum; + + /* decrement reference count, free if all references are gone */ + if (--pSynth->refCount > 0) + return; + + vSynthNum = pSynth->vSynthNum; + + /* cleanup DLS load */ +#ifdef DLS_SYNTHESIZER + /*lint -e{550} result used only in debugging code */ + if (pSynth->pDLS != NULL) + { + EAS_RESULT result; + if ((result = DLSCleanup(pEASData->hwInstData, pSynth->pDLS)) != EAS_SUCCESS) + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMMIDIShutdown: Error %ld cleaning up DLS collection\n", result); */ } + pSynth->pDLS = NULL; + } +#endif + + VMReset(pEASData->pVoiceMgr, pSynth, EAS_TRUE); + + /* check Configuration Module for static memory allocation */ + if (!pEASData->staticMemoryModel) + EAS_HWFree(pEASData->hwInstData, pSynth); + + /* clear pointer to MIDI state */ + pEASData->pVoiceMgr->pSynth[vSynthNum] = NULL; +} + +/*---------------------------------------------------------------------------- + * VMShutdown() + *---------------------------------------------------------------------------- + * Purpose: + * Clean up any Synth related system issues. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * None + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMShutdown (S_EAS_DATA *pEASData) +{ + + /* don't free a NULL pointer */ + if (pEASData->pVoiceMgr == NULL) + return; + +#ifdef DLS_SYNTHESIZER + /* if we have a global DLS collection, clean it up */ + if (pEASData->pVoiceMgr->pGlobalDLS) + { + DLSCleanup(pEASData->hwInstData, pEASData->pVoiceMgr->pGlobalDLS); + pEASData->pVoiceMgr->pGlobalDLS = NULL; + } +#endif + + /* check Configuration Module for static memory allocation */ + if (!pEASData->staticMemoryModel) + EAS_HWFree(pEASData->hwInstData, pEASData->pVoiceMgr); + pEASData->pVoiceMgr = NULL; +} + +#ifdef EXTERNAL_AUDIO +/*---------------------------------------------------------------------------- + * EAS_RegExtAudioCallback() + *---------------------------------------------------------------------------- + * Register a callback for external audio processing + *---------------------------------------------------------------------------- +*/ +void VMRegExtAudioCallback (S_SYNTH *pSynth, EAS_VOID_PTR pInstData, EAS_EXT_PRG_CHG_FUNC cbProgChgFunc, EAS_EXT_EVENT_FUNC cbEventFunc) +{ + pSynth->pExtAudioInstData = pInstData; + pSynth->cbProgChgFunc = cbProgChgFunc; + pSynth->cbEventFunc = cbEventFunc; +} + +/*---------------------------------------------------------------------------- + * VMGetMIDIControllers() + *---------------------------------------------------------------------------- + * Returns the MIDI controller values on the specified channel + *---------------------------------------------------------------------------- +*/ +void VMGetMIDIControllers (S_SYNTH *pSynth, EAS_U8 channel, S_MIDI_CONTROLLERS *pControl) +{ + pControl->modWheel = pSynth->channels[channel].modWheel; + pControl->volume = pSynth->channels[channel].volume; + pControl->pan = pSynth->channels[channel].pan; + pControl->expression = pSynth->channels[channel].expression; + pControl->channelPressure = pSynth->channels[channel].channelPressure; + +#ifdef _REVERB + pControl->reverbSend = pSynth->channels[channel].reverbSend; +#endif + +#ifdef _CHORUSE + pControl->chorusSend = pSynth->channels[channel].chorusSend; +#endif +} +#endif + +#ifdef _SPLIT_ARCHITECTURE +/*---------------------------------------------------------------------------- + * VMStartFrame() + *---------------------------------------------------------------------------- + * Purpose: + * Starts an audio frame + * + * Inputs: + * + * Outputs: + * Returns true if EAS_MixEnginePrep should be called (onboard mixing) + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_BOOL VMStartFrame (S_EAS_DATA *pEASData) +{ + + /* init counter for voices starts in split architecture */ +#ifdef MAX_VOICE_STARTS + pVoiceMgr->numVoiceStarts = 0; +#endif + + return pFrameInterface->pfStartFrame(pEASData->pVoiceMgr->pFrameBuffer); +} + +/*---------------------------------------------------------------------------- + * VMEndFrame() + *---------------------------------------------------------------------------- + * Purpose: + * Stops an audio frame + * + * Inputs: + * + * Outputs: + * Returns true if EAS_MixEnginePost should be called (onboard mixing) + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_BOOL VMEndFrame (S_EAS_DATA *pEASData) +{ + + return pFrameInterface->pfEndFrame(pEASData->pVoiceMgr->pFrameBuffer, pEASData->pMixBuffer, pEASData->masterGain); +} +#endif + +#ifdef TEST_HARNESS +/*---------------------------------------------------------------------------- + * SanityCheck() + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMSanityCheck (EAS_DATA_HANDLE pEASData) +{ + S_SYNTH_VOICE *pVoice; + S_SYNTH *pSynth; + EAS_INT i; + EAS_INT j; + EAS_INT freeVoices; + EAS_INT activeVoices; + EAS_INT playingVoices; + EAS_INT stolenVoices; + EAS_INT releasingVoices; + EAS_INT mutingVoices; + EAS_INT poolCount[MAX_VIRTUAL_SYNTHESIZERS][NUM_SYNTH_CHANNELS]; + EAS_INT vSynthNum; + EAS_RESULT result = EAS_SUCCESS; + + /* initialize counts */ + EAS_HWMemSet(poolCount, 0, sizeof(poolCount)); + freeVoices = activeVoices = playingVoices = stolenVoices = releasingVoices = mutingVoices = 0; + + /* iterate through all voices */ + for (i = 0; i < MAX_SYNTH_VOICES; i++) + { + pVoice = &pEASData->pVoiceMgr->voices[i]; + if (pVoice->voiceState != eVoiceStateFree) + { + vSynthNum = GET_VSYNTH(pVoice->channel); + if (vSynthNum >= MAX_VIRTUAL_SYNTHESIZERS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMSanityCheck: Voice %d has invalid virtual synth number %d\n", i, vSynthNum); */ } + result = EAS_FAILURE; + continue; + } + pSynth = pEASData->pVoiceMgr->pSynth[vSynthNum]; + + switch (pVoice->voiceState) + { + case eVoiceStateMuting: + activeVoices++; + mutingVoices++; + break; + + case eVoiceStateStolen: + vSynthNum = GET_VSYNTH(pVoice->nextChannel); + if (vSynthNum >= MAX_VIRTUAL_SYNTHESIZERS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMSanityCheck: Voice %d has invalid virtual synth number %d\n", i, vSynthNum); */ } + result = EAS_FAILURE; + continue; + } + pSynth = pEASData->pVoiceMgr->pSynth[vSynthNum]; + activeVoices++; + stolenVoices++; + poolCount[vSynthNum][pSynth->channels[GET_CHANNEL(pVoice->nextChannel)].pool]++; + break; + + case eVoiceStateStart: + case eVoiceStatePlay: + activeVoices++; + playingVoices++; + poolCount[vSynthNum][pSynth->channels[GET_CHANNEL(pVoice->channel)].pool]++; + break; + + case eVoiceStateRelease: + activeVoices++; + releasingVoices++; + poolCount[vSynthNum][pSynth->channels[GET_CHANNEL(pVoice->channel)].pool]++; + break; + + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMSanityCheck : voice %d in invalid state\n", i); */ } + result = EAS_FAILURE; + break; + } + } + + /* count free voices */ + else + freeVoices++; + } + + /* dump state info */ + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "%d free\n", freeVoices); */ } + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "%d active\n", activeVoices); */ } + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "%d playing\n", playingVoices); */ } + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "%d releasing\n", releasingVoices); */ } + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "%d muting\n", mutingVoices); */ } + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "%d stolen\n", stolenVoices); */ } + + if (pEASData->pVoiceMgr->activeVoices != activeVoices) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Active voice mismatch was %d should be %d\n", + pEASData->pVoiceMgr->activeVoices, activeVoices); */ } + result = EAS_FAILURE; + } + + /* check virtual synth status */ + for (i = 0; i < MAX_VIRTUAL_SYNTHESIZERS; i++) + { + if (pEASData->pVoiceMgr->pSynth[i] == NULL) + continue; + + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Synth %d numActiveVoices: %d\n", i, pEASData->pVoiceMgr->pSynth[i]->numActiveVoices); */ } + if (pEASData->pVoiceMgr->pSynth[i]->numActiveVoices > MAX_SYNTH_VOICES) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMSanityCheck: Synth %d illegal count for numActiveVoices: %d\n", i, pEASData->pVoiceMgr->pSynth[i]->numActiveVoices); */ } + result = EAS_FAILURE; + } + for (j = 0; j < NUM_SYNTH_CHANNELS; j++) + { + if (poolCount[i][j] != pEASData->pVoiceMgr->pSynth[i]->poolCount[j]) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Pool count mismatch synth %d pool %d, was %d, should be %d\n", + i, j, pEASData->pVoiceMgr->pSynth[i]->poolCount[j], poolCount[i][j]); */ } + result = EAS_FAILURE; + } + } + } + + return result; +} +#endif + + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_wavefile.c b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_wavefile.c new file mode 100755 index 0000000..f24bde2 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_wavefile.c @@ -0,0 +1,867 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_wavefile.c + * + * Contents and purpose: + * This file implements the wave file parser. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 852 $ + * $Date: 2007-09-04 11:43:49 -0700 (Tue, 04 Sep 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_data.h" +#include "eas_report.h" +#include "eas_host.h" +#include "eas_config.h" +#include "eas_parser.h" +#include "eas_pcm.h" +#include "eas_wavefile.h" + +/* lint is choking on the ARM math.h file, so we declare the log10 function here */ +extern double log10(double x); + +/* increase gain to compensate for loss in mixer */ +#define WAVE_GAIN_OFFSET 6 + +/* constant for 1200 / log10(2.0) */ +#define PITCH_CENTS_CONVERSION 3986.313714 + +/*---------------------------------------------------------------------------- + * WAVE file defines + *---------------------------------------------------------------------------- +*/ +/* RIFF chunks */ +#define CHUNK_TYPE(a,b,c,d) ( \ + ( ((EAS_U32)(a) & 0xFF) << 24 ) \ + + ( ((EAS_U32)(b) & 0xFF) << 16 ) \ + + ( ((EAS_U32)(c) & 0xFF) << 8 ) \ + + ( ((EAS_U32)(d) & 0xFF) ) ) + +#define CHUNK_RIFF CHUNK_TYPE('R','I','F','F') +#define CHUNK_WAVE CHUNK_TYPE('W','A','V','E') +#define CHUNK_FMT CHUNK_TYPE('f','m','t',' ') +#define CHUNK_DATA CHUNK_TYPE('d','a','t','a') +#define CHUNK_LIST CHUNK_TYPE('L','I','S','T') +#define CHUNK_INFO CHUNK_TYPE('I','N','F','O') +#define CHUNK_INAM CHUNK_TYPE('I','N','A','M') +#define CHUNK_ICOP CHUNK_TYPE('I','C','O','P') +#define CHUNK_IART CHUNK_TYPE('I','A','R','T') + +/* wave file format identifiers */ +#define WAVE_FORMAT_PCM 0x0001 +#define WAVE_FORMAT_IMA_ADPCM 0x0011 + +/* file size for streamed file */ +#define FILE_SIZE_STREAMING 0x80000000 + +/*---------------------------------------------------------------------------- + * prototypes + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT WaveCheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *pHandle, EAS_I32 offset); +static EAS_RESULT WavePrepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT WaveState (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_STATE *pState); +static EAS_RESULT WaveClose (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT WaveReset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT WaveLocate (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 time, EAS_BOOL *pParserLocate); +static EAS_RESULT WavePause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT WaveResume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT WaveSetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value); +static EAS_RESULT WaveGetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue); +static EAS_RESULT WaveParseHeader (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, S_WAVE_STATE *pWaveData); +static EAS_RESULT WaveGetMetaData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pMediaLength); + +#ifdef MMAPI_SUPPORT +static EAS_RESULT SaveFmtChunk (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, S_WAVE_STATE *pWaveData, EAS_I32 size); +#endif + +/*---------------------------------------------------------------------------- + * + * EAS_Wave_Parser + * + * This structure contains the functional interface for the Wave file parser + *---------------------------------------------------------------------------- +*/ +const S_FILE_PARSER_INTERFACE EAS_Wave_Parser = +{ + WaveCheckFileType, + WavePrepare, + NULL, + NULL, + WaveState, + WaveClose, + WaveReset, + WavePause, + WaveResume, + WaveLocate, + WaveSetData, + WaveGetData, + WaveGetMetaData +}; + +/*---------------------------------------------------------------------------- + * WaveCheckFileType() + *---------------------------------------------------------------------------- + * Purpose: + * Check the file type to see if we can parse it + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT WaveCheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *pHandle, EAS_I32 offset) +{ + S_WAVE_STATE *pWaveData; + + /* zero the memory to insure complete initialization */ + *pHandle = NULL; + + /* read the file header */ + if (WaveParseHeader(pEASData, fileHandle, NULL) == EAS_SUCCESS) + { + + /* check for static memory allocation */ + if (pEASData->staticMemoryModel) + pWaveData = EAS_CMEnumData(EAS_CM_WAVE_DATA); + else + pWaveData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_WAVE_STATE)); + if (!pWaveData) + return EAS_ERROR_MALLOC_FAILED; + EAS_HWMemSet(pWaveData, 0, sizeof(S_WAVE_STATE)); + + /* return a pointer to the instance data */ + pWaveData->fileHandle = fileHandle; + pWaveData->fileOffset = offset; + *pHandle = pWaveData; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * WavePrepare() + *---------------------------------------------------------------------------- + * Purpose: + * Prepare to parse the file. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT WavePrepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_WAVE_STATE *pWaveData; + EAS_RESULT result; + + /* validate parser state */ + pWaveData = (S_WAVE_STATE*) pInstData; + if (pWaveData->streamHandle != NULL) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + /* back to start of file */ + pWaveData->time = 0; + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pWaveData->fileHandle, pWaveData->fileOffset)) != EAS_SUCCESS) + return result; + + /* parse the file header */ + if ((result = WaveParseHeader(pEASData, pWaveData->fileHandle, pWaveData)) != EAS_SUCCESS) + return result; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * WaveState() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current state of the stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * pState - pointer to variable to store state + * + * Outputs: + * + * + * Side Effects: + * + * Notes: + * This interface is also exposed in the internal library for use by the other modules. + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT WaveState (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_STATE *pState) +{ + S_WAVE_STATE *pWaveData; + + /* return current state */ + pWaveData = (S_WAVE_STATE*) pInstData; + if (pWaveData->streamHandle) + return EAS_PEState(pEASData, pWaveData->streamHandle, pState); + + /* if no stream handle, and time is not zero, we are done */ + if (pWaveData->time > 0) + *pState = EAS_STATE_STOPPED; + else + *pState = EAS_STATE_OPEN; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * WaveClose() + *---------------------------------------------------------------------------- + * Purpose: + * Close the file and clean up + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT WaveClose (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_WAVE_STATE *pWaveData; + EAS_RESULT result; + + pWaveData = (S_WAVE_STATE*) pInstData; + + /* close the stream */ + if (pWaveData->streamHandle) + { + if ((result = EAS_PEClose(pEASData, pWaveData->streamHandle)) != EAS_SUCCESS) + return result; + pWaveData->streamHandle = NULL; + } + + /* if using dynamic memory, free it */ + if (!pEASData->staticMemoryModel) + { + +#ifdef MMAPI_SUPPORT + /* need to free the fmt chunk */ + if (pWaveData->fmtChunk != NULL) + EAS_HWFree(pEASData->hwInstData, pWaveData->fmtChunk); +#endif + + /* free the instance data */ + EAS_HWFree(pEASData->hwInstData, pWaveData); + + } + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * WaveReset() + *---------------------------------------------------------------------------- + * Purpose: + * Reset the sequencer. Used for locating backwards in the file. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT WaveReset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + EAS_PCM_HANDLE streamHandle; + + /* reset to first byte of data in the stream */ + streamHandle = ((S_WAVE_STATE*)pInstData)->streamHandle; + if (streamHandle) + return EAS_PEReset(pEASData, streamHandle); + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; +} + +/*---------------------------------------------------------------------------- + * WaveLocate() + *---------------------------------------------------------------------------- + * Purpose: + * Rewind/fast-forward in file. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * time - time (in msecs) + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pParserLocate) reserved for future use */ +static EAS_RESULT WaveLocate (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 time, EAS_BOOL *pParserLocate) +{ + EAS_PCM_HANDLE streamHandle; + + /* reset to first byte of data in the stream */ + streamHandle = ((S_WAVE_STATE*)pInstData)->streamHandle; + if (streamHandle) + return EAS_PELocate(pEASData, streamHandle, time); + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; +} + +/*---------------------------------------------------------------------------- + * WavePause() + *---------------------------------------------------------------------------- + * Purpose: + * Mute and stop rendering a PCM stream. Sets the gain target to zero and stops the playback + * at the end of the next audio frame. + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_WAVE_STATE for this stream + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +static EAS_RESULT WavePause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + EAS_PCM_HANDLE streamHandle; + + /* pause the stream */ + streamHandle = ((S_WAVE_STATE*)pInstData)->streamHandle; + if (streamHandle) + return EAS_PEPause(pEASData, streamHandle); + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; +} + +/*---------------------------------------------------------------------------- + * WaveResume() + *---------------------------------------------------------------------------- + * Purpose: + * Resume rendering a PCM stream. Sets the gain target back to its + * previous setting and restarts playback at the end of the next audio + * frame. + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_WAVE_STATE for this stream + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +static EAS_RESULT WaveResume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + EAS_PCM_HANDLE streamHandle; + + /* resume the stream */ + streamHandle = ((S_WAVE_STATE*)pInstData)->streamHandle; + if (streamHandle) + return EAS_PEResume(pEASData, streamHandle); + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; +} + +/*---------------------------------------------------------------------------- + * WaveSetData() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_WAVE_STATE for this stream + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT WaveSetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value) +{ + S_WAVE_STATE *pWaveData = (S_WAVE_STATE*) pInstData; + + switch (param) + { + /* set metadata callback */ + case PARSER_DATA_METADATA_CB: + EAS_HWMemCpy(&pWaveData->metadata, (void*) value, sizeof(S_METADATA_CB)); + return EAS_SUCCESS; + + case PARSER_DATA_PLAYBACK_RATE: + value = (EAS_I32) (PITCH_CENTS_CONVERSION * log10((double) value / (double) (1 << 28))); + return EAS_PEUpdatePitch(pEASData, pWaveData->streamHandle, (EAS_I16) value); + + case PARSER_DATA_VOLUME: + return EAS_PEUpdateVolume(pEASData, pWaveData->streamHandle, (EAS_I16) value); + + default: + return EAS_ERROR_INVALID_PARAMETER; + } +} + +/*---------------------------------------------------------------------------- + * WaveGetData() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_WAVE_STATE for this stream + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +static EAS_RESULT WaveGetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue) +{ + S_WAVE_STATE *pWaveData; + + pWaveData = (S_WAVE_STATE*) pInstData; + switch (param) + { + /* return file type as WAVE */ + case PARSER_DATA_FILE_TYPE: + *pValue = pWaveData->fileType; + break; + +#ifdef MMAPI_SUPPORT + /* return pointer to 'fmt' chunk */ + case PARSER_DATA_FORMAT: + *pValue = (EAS_I32) pWaveData->fmtChunk; + break; +#endif + + case PARSER_DATA_GAIN_OFFSET: + *pValue = WAVE_GAIN_OFFSET; + break; + + default: + return EAS_ERROR_INVALID_PARAMETER; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * WaveParseHeader() + *---------------------------------------------------------------------------- + * Purpose: + * Parse the WAVE file header. + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_WAVE_STATE for this stream + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT WaveParseHeader (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, S_WAVE_STATE *pWaveData) +{ + S_PCM_OPEN_PARAMS params; + EAS_RESULT result; + EAS_U32 tag; + EAS_U32 fileSize; + EAS_U32 size; + EAS_I32 pos; + EAS_I32 audioOffset; + EAS_U16 usTemp; + EAS_BOOL parseDone; + EAS_U32 avgBytesPerSec; + + /* init some data (and keep lint happy) */ + params.sampleRate = 0; + params.size = 0; + audioOffset = 0; + params.decoder = 0; + params.blockSize = 0; + params.pCallbackFunc = NULL; + params.cbInstData = NULL; + params.loopSamples = 0; + params.fileHandle = fileHandle; + params.volume = 0x7fff; + params.envData = 0; + avgBytesPerSec = 8000; + + /* check for 'RIFF' tag */ + if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &tag, EAS_TRUE)) != EAS_FALSE) + return result; + if (tag != CHUNK_RIFF) + return EAS_ERROR_UNRECOGNIZED_FORMAT; + + /* get size */ + if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &fileSize, EAS_FALSE)) != EAS_FALSE) + return result; + + /* check for 'WAVE' tag */ + if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &tag, EAS_TRUE)) != EAS_FALSE) + return result; + if (tag != CHUNK_WAVE) + return EAS_ERROR_UNRECOGNIZED_FORMAT; + + /* this is enough to say we recognize the file */ + if (pWaveData == NULL) + return EAS_SUCCESS; + + /* check for streaming mode */ + pWaveData->flags = 0; + pWaveData->mediaLength = -1; + pWaveData->infoChunkPos = -1; + pWaveData->infoChunkSize = -1; + if (fileSize== FILE_SIZE_STREAMING) + { + pWaveData->flags |= PCM_FLAGS_STREAMING; + fileSize = 0x7fffffff; + } + + /* find out where we're at */ + if ((result = EAS_HWFilePos(pEASData->hwInstData, fileHandle, &pos)) != EAS_SUCCESS) + return result; + fileSize -= 4; + + parseDone = EAS_FALSE; + for (;;) + { + /* get tag and size for next chunk */ + if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &tag, EAS_TRUE)) != EAS_FALSE) + return result; + if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &size, EAS_FALSE)) != EAS_FALSE) + return result; + + /* process chunk */ + pos += 8; + switch (tag) + { + case CHUNK_FMT: + +#ifdef MMAPI_SUPPORT + if ((result = SaveFmtChunk(pEASData, fileHandle, pWaveData, (EAS_I32) size)) != EAS_SUCCESS) + return result; +#endif + + /* get audio format */ + if ((result = EAS_HWGetWord(pEASData->hwInstData, fileHandle, &usTemp, EAS_FALSE)) != EAS_FALSE) + return result; + if (usTemp == WAVE_FORMAT_PCM) + { + params.decoder = EAS_DECODER_PCM; + pWaveData->fileType = EAS_FILE_WAVE_PCM; + } + else if (usTemp == WAVE_FORMAT_IMA_ADPCM) + { + params.decoder = EAS_DECODER_IMA_ADPCM; + pWaveData->fileType = EAS_FILE_WAVE_IMA_ADPCM; + } + else + return EAS_ERROR_UNRECOGNIZED_FORMAT; + + /* get number of channels */ + if ((result = EAS_HWGetWord(pEASData->hwInstData, fileHandle, &usTemp, EAS_FALSE)) != EAS_FALSE) + return result; + if (usTemp == 2) + pWaveData->flags |= PCM_FLAGS_STEREO; + else if (usTemp != 1) + return EAS_ERROR_UNRECOGNIZED_FORMAT; + + /* get sample rate */ + if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, ¶ms.sampleRate, EAS_FALSE)) != EAS_FALSE) + return result; + + /* get stream rate */ + if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &avgBytesPerSec, EAS_FALSE)) != EAS_FALSE) + return result; + + /* get block alignment */ + if ((result = EAS_HWGetWord(pEASData->hwInstData, fileHandle, &usTemp, EAS_FALSE)) != EAS_FALSE) + return result; + params.blockSize = usTemp; + + /* get bits per sample */ + if ((result = EAS_HWGetWord(pEASData->hwInstData, fileHandle, &usTemp, EAS_FALSE)) != EAS_FALSE) + return result; + + /* PCM, must be 8 or 16 bit samples */ + if (params.decoder == EAS_DECODER_PCM) + { + if (usTemp == 8) + pWaveData->flags |= PCM_FLAGS_8_BIT | PCM_FLAGS_UNSIGNED; + else if (usTemp != 16) + return EAS_ERROR_UNRECOGNIZED_FORMAT; + } + + /* for IMA ADPCM, we only support mono 4-bit ADPCM */ + else + { + if ((usTemp != 4) || (pWaveData->flags & PCM_FLAGS_STEREO)) + return EAS_ERROR_UNRECOGNIZED_FORMAT; + } + + break; + + case CHUNK_DATA: + audioOffset = pos; + if (pWaveData->flags & PCM_FLAGS_STREAMING) + { + params.size = 0x7fffffff; + parseDone = EAS_TRUE; + } + else + { + params.size = (EAS_I32) size; + params.loopStart = size; + /* use more accurate method if possible */ + if (size <= (0x7fffffff / 1000)) + pWaveData->mediaLength = (EAS_I32) ((size * 1000) / avgBytesPerSec); + else + pWaveData->mediaLength = (EAS_I32) (size / (avgBytesPerSec / 1000)); + } + break; + + case CHUNK_LIST: + /* get the list type */ + if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &tag, EAS_TRUE)) != EAS_FALSE) + return result; + if (tag == CHUNK_INFO) + { + pWaveData->infoChunkPos = pos + 4; + pWaveData->infoChunkSize = (EAS_I32) size - 4; + } + break; + + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WaveParseHeader: %c%c%c%c chunk - %d byte(s) ignored\n", + (char) (tag >> 24), (char) (tag >> 16), (char) (tag >> 8), (char) tag, size); */ } + break; + } + + if (parseDone) + break; + + /* subtract header size */ + fileSize -= 8; + + /* account for zero-padding on odd length chunks */ + if (size & 1) + size++; + + /* this check works for files with odd length last chunk and no zero-pad */ + if (size >= fileSize) + { + if (size > fileSize) + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WaveParseHeader: '%c%c%c%c' chunk size exceeds length of file or is not zero-padded\n", + (char) (tag >> 24), (char) (tag >> 16), (char) (tag >> 8), (char) tag, size); */ } + break; + } + + /* subtract size of data chunk (including any zero-pad) */ + fileSize -= size; + + /* seek to next chunk */ + pos += (EAS_I32) size; + if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, pos)) != EAS_SUCCESS) + return result; + } + + /* check for valid header */ + if ((params.sampleRate == 0) || (params.size == 0)) + return EAS_ERROR_UNRECOGNIZED_FORMAT; + + /* save the pertinent information */ + pWaveData->audioOffset = audioOffset; + params.flags = pWaveData->flags; + + /* seek to data */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, audioOffset)) != EAS_SUCCESS) + return result; + + /* open a stream in the PCM engine */ + return EAS_PEOpenStream(pEASData, ¶ms, &pWaveData->streamHandle); +} + +/*---------------------------------------------------------------------------- + * WaveGetMetaData() + *---------------------------------------------------------------------------- + * Purpose: + * Process the INFO chunk and return metadata to host + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT WaveGetMetaData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pMediaLength) +{ + S_WAVE_STATE *pWaveData; + EAS_RESULT result; + EAS_I32 pos; + EAS_U32 size; + EAS_I32 infoSize; + EAS_U32 tag; + EAS_I32 restorePos; + E_EAS_METADATA_TYPE metaType; + EAS_I32 metaLen; + + /* get current position so we can restore it */ + pWaveData = (S_WAVE_STATE*) pInstData; + + /* return media length */ + *pMediaLength = pWaveData->mediaLength; + + /* did we encounter an INFO chunk? */ + if (pWaveData->infoChunkPos < 0) + return EAS_SUCCESS; + + if ((result = EAS_HWFilePos(pEASData->hwInstData, pWaveData->fileHandle, &restorePos)) != EAS_SUCCESS) + return result; + + /* offset to start of first chunk in INFO chunk */ + pos = pWaveData->infoChunkPos; + infoSize = pWaveData->infoChunkSize; + + /* read all the chunks in the INFO chunk */ + for (;;) + { + + /* seek to next chunk */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pWaveData->fileHandle, pos)) != EAS_SUCCESS) + return result; + + /* get tag and size for next chunk */ + if ((result = EAS_HWGetDWord(pEASData->hwInstData, pWaveData->fileHandle, &tag, EAS_TRUE)) != EAS_FALSE) + return result; + if ((result = EAS_HWGetDWord(pEASData->hwInstData, pWaveData->fileHandle, &size, EAS_FALSE)) != EAS_FALSE) + return result; + + /* process chunk */ + pos += 8; + metaType = EAS_METADATA_UNKNOWN; + switch (tag) + { + case CHUNK_INAM: + metaType = EAS_METADATA_TITLE; + break; + + case CHUNK_IART: + metaType = EAS_METADATA_AUTHOR; + break; + + case CHUNK_ICOP: + metaType = EAS_METADATA_COPYRIGHT; + break; + + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WaveParseHeader: %c%c%c%c chunk - %d byte(s) ignored\n", + (char) (tag >> 24), (char) (tag >> 16), (char) (tag >> 8), (char) tag, size); */ } + break; + } + + /* process known metadata */ + if (metaType != EAS_METADATA_UNKNOWN) + { + metaLen = pWaveData->metadata.bufferSize - 1; + if (metaLen > (EAS_I32) size) + metaLen = (EAS_I32) size; + if ((result = EAS_HWReadFile(pEASData->hwInstData, pWaveData->fileHandle, pWaveData->metadata.buffer, metaLen, &metaLen)) != EAS_SUCCESS) + return result; + pWaveData->metadata.buffer[metaLen] = 0; + pWaveData->metadata.callback(metaType, pWaveData->metadata.buffer, pWaveData->metadata.pUserData); + } + + /* subtract this block */ + if (size & 1) + size++; + infoSize -= (EAS_I32) size + 8; + if (infoSize == 0) + break; + pos += (EAS_I32) size; + } + + + /* restore original position */ + return EAS_HWFileSeek(pEASData->hwInstData, pWaveData->fileHandle, restorePos); +} + +#ifdef MMAPI_SUPPORT +/*---------------------------------------------------------------------------- + * SaveFmtChunk() + *---------------------------------------------------------------------------- + * Purpose: + * Save the fmt chunk for the MMAPI library + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT SaveFmtChunk (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, S_WAVE_STATE *pWaveData, EAS_I32 fmtSize) +{ + EAS_RESULT result; + EAS_I32 pos; + EAS_I32 count; + + /* save current file position */ + if ((result = EAS_HWFilePos(pEASData->hwInstData, fileHandle, &pos)) != EAS_SUCCESS) + return result; + + /* allocate a chunk of memory */ + pWaveData->fmtChunk = EAS_HWMalloc(pEASData->hwInstData, fmtSize); + if (!pWaveData->fmtChunk) + return EAS_ERROR_MALLOC_FAILED; + + /* read the fmt chunk into memory */ + if ((result = EAS_HWReadFile(pEASData->hwInstData, fileHandle, pWaveData->fmtChunk, fmtSize, &count)) != EAS_SUCCESS) + return result; + if (count != fmtSize) + return EAS_ERROR_FILE_READ_FAILED; + + /* restore file position */ + return EAS_HWFileSeek(pEASData->hwInstData, fileHandle, pos); +} +#endif + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_wavefile.h b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_wavefile.h new file mode 100755 index 0000000..f8814a8 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_wavefile.h @@ -0,0 +1,63 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_wavefile.h + * + * Contents and purpose: + * Static data block for wave file parser. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 439 $ + * $Date: 2006-10-26 11:53:18 -0700 (Thu, 26 Oct 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_WAVEFILE_H +#define _EAS_WAVEFILE_H + +#include "eas_data.h" +#include "eas_pcm.h" + +/*---------------------------------------------------------------------------- + * + * S_WAVE_STATE + * + * This structure contains the WAVE file parser state information + *---------------------------------------------------------------------------- +*/ +typedef struct s_wave_state_tag +{ + EAS_FILE_HANDLE fileHandle; + EAS_PCM_HANDLE streamHandle; + S_METADATA_CB metadata; + EAS_U32 time; + EAS_I32 fileOffset; + EAS_I32 audioOffset; + EAS_I32 mediaLength; + EAS_U32 audioSize; + EAS_U32 flags; + EAS_I16 fileType; +#ifdef MMAPI_SUPPORT + EAS_VOID_PTR fmtChunk; +#endif + EAS_I32 infoChunkPos; + EAS_I32 infoChunkSize; +} S_WAVE_STATE; + +#endif + diff --git a/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_wavefiledata.c b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_wavefiledata.c new file mode 100755 index 0000000..c224a6c --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_wavefiledata.c @@ -0,0 +1,33 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_wavefiledata.c + * + * Contents and purpose: + * Static data block for wave file parser. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 547 $ + * $Date: 2007-01-31 16:30:17 -0800 (Wed, 31 Jan 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_wavefile.h" + +S_WAVE_STATE eas_WaveData; + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/Makefile b/common/embeddedaudiosynthesis/arm-hybrid-22k/Makefile new file mode 100755 index 0000000..5648139 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/Makefile @@ -0,0 +1,66 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES = \ + lib_src/eas_chorus.c \ + lib_src/eas_chorusdata.c \ + lib_src/eas_data.c \ + lib_src/eas_fmengine.c \ + lib_src/eas_fmsynth.c \ + lib_src/eas_fmtables.c \ + lib_src/eas_ima_tables.c \ + lib_src/eas_imaadpcm.c \ + lib_src/eas_imelody.c \ + lib_src/eas_imelodydata.c \ + lib_src/eas_math.c \ + lib_src/eas_midi.c \ + lib_src/eas_mididata.c \ + lib_src/eas_mixbuf.c \ + lib_src/eas_mixer.c \ + lib_src/eas_ota.c \ + lib_src/eas_otadata.c \ + lib_src/eas_pan.c \ + lib_src/eas_pcm.c \ + lib_src/eas_pcmdata.c \ + lib_src/eas_public.c \ + lib_src/eas_reverb.c \ + lib_src/eas_reverbdata.c \ + lib_src/eas_rtttl.c \ + lib_src/eas_rtttldata.c \ + lib_src/eas_smf.c \ + lib_src/eas_smfdata.c \ + lib_src/eas_voicemgt.c \ + lib_src/eas_wavefile.c \ + lib_src/eas_wavefiledata.c \ + lib_src/eas_wtengine.c \ + lib_src/eas_wtsynth.c \ + lib_src/hybrid_22khz_mcu.c \ + host_src/eas_config.c \ + host_src/eas_hostmm.c \ + host_src/eas_main.c \ + host_src/eas_report.c \ + host_src/eas_wave.c + +LOCAL_CFLAGS+= -O2 -D UNIFIED_DEBUG_MESSAGES -D EAS_HYBRID_SYNTH \ + -D _IMELODY_PARSER -D _RTTTL_PARSER -D _OTA_PARSER \ + -D _WAVE_PARSER -D _REVERB_ENABLED \ + -D _CHORUS_ENABLED -D NUM_OUTPUT_CHANNELS=2 \ + -D _SAMPLE_RATE_22050 -D MAX_SYNTH_VOICES=32 \ + -D NUM_PRIMARY_VOICES=8 \ + -D _8_BIT_SAMPLES -D _FILTER_ENABLED -D _IMELODY_PARSER \ + -D _IMA_DECODER + +LOCAL_C_INCLUDES:= \ + $(LOCAL_PATH)/host_src/ \ + $(LOCAL_PATH)/lib_src/ + +LOCAL_ARM_MODE := arm + +LOCAL_MODULE := libsonivox + +LOCAL_COPY_HEADERS_TO := libsonivox +LOCAL_COPY_HEADERS := \ + host_src/eas.h \ + host_src/eas_types.h + +include $(BUILD_SHARED_LIBRARY) diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/bin/arm-hybrid-22k b/common/embeddedaudiosynthesis/arm-hybrid-22k/bin/arm-hybrid-22k new file mode 100755 index 0000000..ea80a08 Binary files /dev/null and b/common/embeddedaudiosynthesis/arm-hybrid-22k/bin/arm-hybrid-22k differ diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/arm-hybrid-22k.mak b/common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/arm-hybrid-22k.mak new file mode 100755 index 0000000..8874f31 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/arm-hybrid-22k.mak @@ -0,0 +1,25 @@ +# +# Auto-generated sample makefile +# +# This makefile is intended for use with GNU make. +# Set the paths to the tools (CC, AR, LD, etc.) +# + +vpath %.c host_src + +CC = C:\Program Files\GNUARM\bin\arm-elf-gcc.exe +AS = C:\Program Files\GNUARM\bin\arm-elf-as.exe +LD = C:\Program Files\GNUARM\bin\arm-elf-gcc.exe +AR = C:\Program Files\GNUARM\bin\arm-elf-ar.exe + +%.o: %.c + $(CC) -c -O2 -o $@ -I host_src -D UNIFIED_DEBUG_MESSAGES -D EAS_HYBRID_SYNTH -D _IMELODY_PARSER -D _RTTTL_PARSER -D _OTA_PARSER -D _WAVE_PARSER -D _REVERB_ENABLED -D _CHORUS_ENABLED $< + +%.o: %.s + $(AS) -o $@ -EL -mcpu=arm946e-s -mfpu=softfpa -I lib_src --defsym CHECK_STACK=0 --defsym REVERB=0 --defsym CHORUS=0 --defsym STEREO_OUTPUT=1 --defsym SAMPLE_RATE_22050=1 --defsym SAMPLES_8_BIT=1 --defsym FILTER_ENABLED=1 $< + +OBJS = eas_main.o eas_report.o eas_wave.o eas_hostmm.o eas_config.o + +arm-hybrid-22k: $(OBJS) + $(LD) -o $@ $(OBJS) libarm-hybrid-22k.a -lm + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas.h b/common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas.h new file mode 100755 index 0000000..c64af49 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas.h @@ -0,0 +1,1062 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas.h + * + * Contents and purpose: + * The public interface header for the EAS synthesizer. + * + * This header only contains declarations that are specific + * to this implementation. + * + * DO NOT MODIFY THIS FILE! + * + * Copyright Sonic Network Inc. 2005, 2006 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 852 $ + * $Date: 2007-09-04 11:43:49 -0700 (Tue, 04 Sep 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_H +#define _EAS_H + +#include "eas_types.h" + +/* for C++ linkage */ +#ifdef __cplusplus +extern "C" { +#endif + +/* library version macro */ +#define MAKE_LIB_VERSION(a,b,c,d) (((((((EAS_U32) a <<8) | (EAS_U32) b) << 8) | (EAS_U32) c) << 8) | (EAS_U32) d) +#define LIB_VERSION MAKE_LIB_VERSION(3, 6, 10, 14) + +typedef struct +{ + EAS_U32 libVersion; + EAS_BOOL checkedVersion; + EAS_I32 maxVoices; + EAS_I32 numChannels; + EAS_I32 sampleRate; + EAS_I32 mixBufferSize; + EAS_BOOL filterEnabled; + EAS_U32 buildTimeStamp; + EAS_CHAR *buildGUID; +} S_EAS_LIB_CONFIG; + +/* enumerated effects module numbers for configuration */ +typedef enum +{ + EAS_MODULE_ENHANCER = 0, + EAS_MODULE_COMPRESSOR, + EAS_MODULE_REVERB, + EAS_MODULE_CHORUS, + EAS_MODULE_WIDENER, + EAS_MODULE_GRAPHIC_EQ, + EAS_MODULE_WOW, + EAS_MODULE_MAXIMIZER, + EAS_MODULE_TONECONTROLEQ, + NUM_EFFECTS_MODULES +} E_FX_MODULES; + +/* enumerated optional module numbers for configuration */ +typedef enum +{ + EAS_MODULE_MMAPI_TONE_CONTROL = 0, + EAS_MODULE_METRICS +} E_OPT_MODULES; +#define NUM_OPTIONAL_MODULES 2 + +/* enumerated audio decoders for configuration */ +typedef enum +{ + EAS_DECODER_PCM = 0, + EAS_DECODER_SMAF_ADPCM, + EAS_DECODER_IMA_ADPCM, + EAS_DECODER_7BIT_SMAF_ADPCM, + EAS_DECODER_NOT_SUPPORTED +} E_DECODER_MODULES; +#define NUM_DECODER_MODULES 4 + +/* defines for EAS_PEOpenStream flags parameter */ +#define PCM_FLAGS_STEREO 0x00000100 /* stream is stereo */ +#define PCM_FLAGS_8_BIT 0x00000001 /* 8-bit format */ +#define PCM_FLAGS_UNSIGNED 0x00000010 /* unsigned format */ +#define PCM_FLAGS_STREAMING 0x80000000 /* streaming mode */ + +/* maximum volume setting */ +#define EAS_MAX_VOLUME 100 + +/*---------------------------------------------------------------------------- + * EAS_Init() + *---------------------------------------------------------------------------- + * Purpose: + * Initialize the synthesizer library + * + * Inputs: + * polyphony - number of voices to play (dynamic memory model only) + * ppLibData - pointer to data handle variable for this instance + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Init (EAS_DATA_HANDLE *ppEASData); + +/*---------------------------------------------------------------------------- + * EAS_Config() + *---------------------------------------------------------------------------- + * Purpose: + * Returns a pointer to a structure containing the configuration options + * in this library build. + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC const S_EAS_LIB_CONFIG *EAS_Config (void); + +/*---------------------------------------------------------------------------- + * EAS_Shutdown() + *---------------------------------------------------------------------------- + * Purpose: + * Shuts down the library. Deallocates any memory associated with the + * synthesizer (dynamic memory model only) + * + * Inputs: + * pEASData - handle to data for this instance + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Shutdown (EAS_DATA_HANDLE pEASData); + +/*---------------------------------------------------------------------------- + * EAS_Render() + *---------------------------------------------------------------------------- + * Purpose: + * Parse the Midi data and render PCM audio data. + * + * Inputs: + * pEASData - buffer for internal EAS data + * pOut - output buffer pointer + * nNumRequested - requested num samples to generate + * pnNumGenerated - actual number of samples generated + * + * Outputs: + * EAS_SUCCESS if PCM data was successfully rendered + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Render (EAS_DATA_HANDLE pEASData, EAS_PCM *pOut, EAS_I32 numRequested, EAS_I32 *pNumGenerated); + +/*---------------------------------------------------------------------------- + * EAS_SetRepeat() + *---------------------------------------------------------------------------- + * Purpose: + * Set the selected stream to repeat. + * + * Inputs: + * pEASData - handle to data for this instance + * streamHandle - handle to stream + * repeatCount - repeat count (0 = no repeat, -1 = repeat forever) + * + * Outputs: + * + * Side Effects: + * + * Notes: + * 0 = no repeat + * 1 = repeat once, i.e. play through twice + * -1 = repeat forever + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetRepeat (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 repeatCount); + +/*---------------------------------------------------------------------------- + * EAS_GetRepeat() + *---------------------------------------------------------------------------- + * Purpose: + * Gets the current repeat count for the selected stream. + * + * Inputs: + * pEASData - handle to data for this instance + * streamHandle - handle to stream + * pRrepeatCount - pointer to variable to hold repeat count + * + * Outputs: + * + * Side Effects: + * + * Notes: + * 0 = no repeat + * 1 = repeat once, i.e. play through twice + * -1 = repeat forever + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetRepeat (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 *pRepeatCount); + +/*---------------------------------------------------------------------------- + * EAS_SetPlaybackRate() + *---------------------------------------------------------------------------- + * Purpose: + * Set the playback rate. + * + * Inputs: + * pEASData - handle to data for this instance + * streamHandle - handle to stream + * rate - rate (28-bit fractional amount) + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetPlaybackRate (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_U32 rate); +#define MAX_PLAYBACK_RATE (EAS_U32)(1L << 29) +#define MIN_PLAYBACK_RATE (EAS_U32)(1L << 27) + +/*---------------------------------------------------------------------------- + * EAS_SetTransposition) + *---------------------------------------------------------------------------- + * Purpose: + * Sets the key tranposition for the synthesizer. Transposes all + * melodic instruments by the specified amount. Range is limited + * to +/-12 semitones. + * + * Inputs: + * pEASData - handle to data for this instance + * streamHandle - handle to stream + * transposition - +/-12 semitones + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetTransposition (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 transposition); +#define MAX_TRANSPOSE 12 + +/*---------------------------------------------------------------------------- + * EAS_SetSynthPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Set the polyphony of the synthesizer. Value must be >= 1 and <= the + * maximum number of voices. This function will pin the polyphony + * at those limits + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * synthNum - synthesizer number (0 = onboard, 1 = DSP) + * polyphonyCount - the desired polyphony count + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetSynthPolyphony (EAS_DATA_HANDLE pEASData, EAS_I32 synthNum, EAS_I32 polyphonyCount); + +/*---------------------------------------------------------------------------- + * EAS_GetSynthPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current polyphony setting of the synthesizer + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * synthNum - synthesizer number (0 = onboard, 1 = DSP) + * pPolyphonyCount - pointer to variable to receive polyphony count + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetSynthPolyphony (EAS_DATA_HANDLE pEASData, EAS_I32 synthNum, EAS_I32 *pPolyphonyCount); + +/*---------------------------------------------------------------------------- + * EAS_SetPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Set the polyphony of the stream. Value must be >= 1 and <= the + * maximum number of voices. This function will pin the polyphony + * at those limits + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - handle returned by EAS_OpenFile + * polyphonyCount - the desired polyphony count + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetPolyphony (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 polyphonyCount); + +/*---------------------------------------------------------------------------- + * EAS_GetPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current polyphony setting of the stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - handle returned by EAS_OpenFile + * pPolyphonyCount - pointer to variable to receive polyphony count + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetPolyphony (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 *pPolyphonyCount); + +/*---------------------------------------------------------------------------- + * EAS_SetPriority() + *---------------------------------------------------------------------------- + * Purpose: + * Set the priority of the stream. Determines which stream's voices + * are stolen when there are insufficient voices for all notes. + * Value must be in the range of 1-255, lower values are higher + * priority. The default priority is 50. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - handle returned by EAS_OpenFile + * polyphonyCount - the desired polyphony count + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetPriority (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 priority); + +/*---------------------------------------------------------------------------- + * EAS_GetPriority() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current priority setting of the stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - handle returned by EAS_OpenFile + * pPriority - pointer to variable to receive priority + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetPriority (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 *pPriority); + +/*---------------------------------------------------------------------------- + * EAS_SetVolume() + *---------------------------------------------------------------------------- + * Purpose: + * Set the master volume for the mixer. The default volume setting is + * 90 (-10 dB). The volume range is 0 to 100 in 1dB increments. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * volume - the desired master volume + * + * Outputs: + * + * + * Side Effects: + * overrides any previously set master volume from sysex + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetVolume (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 volume); + +/*---------------------------------------------------------------------------- + * EAS_GetVolume() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the master volume for the mixer in 1dB increments. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * volume - the desired master volume + * + * Outputs: + * + * + * Side Effects: + * overrides any previously set master volume from sysex + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_I32 EAS_GetVolume (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle); + +/*---------------------------------------------------------------------------- + * EAS_SetMaxLoad() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the maximum workload the parsers will do in a single call to + * EAS_Render. The units are currently arbitrary, but should correlate + * well to the actual CPU cycles consumed. The primary effect is to + * reduce the occasional peaks in CPU cycles consumed when parsing + * dense parts of a MIDI score. Setting maxWorkLoad to zero disables + * the workload limiting function. + * + * Inputs: + * pEASData - handle to data for this instance + * maxLoad - the desired maximum workload + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetMaxLoad (EAS_DATA_HANDLE pEASData, EAS_I32 maxLoad); + +/*---------------------------------------------------------------------------- + * EAS_SetMaxPCMStreams() + *---------------------------------------------------------------------------- + * Sets the maximum number of PCM streams allowed in parsers that + * use PCM streaming. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - handle returned by EAS_OpenFile + * maxNumStreams - maximum number of PCM streams + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetMaxPCMStreams (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 maxNumStreams); + +/*---------------------------------------------------------------------------- + * EAS_OpenFile() + *---------------------------------------------------------------------------- + * Purpose: + * Opens a file for audio playback. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * locator - pointer to filename or other locating information + * pStreamHandle - pointer to stream handle variable + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_OpenFile (EAS_DATA_HANDLE pEASData, EAS_FILE_LOCATOR locator, EAS_HANDLE *pStreamHandle); + +#ifdef MMAPI_SUPPORT +/*---------------------------------------------------------------------------- + * EAS_MMAPIToneControl() + *---------------------------------------------------------------------------- + * Purpose: + * Opens a ToneControl file for audio playback. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * locator - pointer to filename or other locating information + * pStreamHandle - pointer to stream handle variable + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_MMAPIToneControl (EAS_DATA_HANDLE pEASData, EAS_FILE_LOCATOR locator, EAS_HANDLE *pStreamHandle); + +/*---------------------------------------------------------------------------- + * EAS_GetWaveFmtChunk + *---------------------------------------------------------------------------- + * Helper function to retrieve WAVE file fmt chunk for MMAPI + *---------------------------------------------------------------------------- + * pEASData - pointer to EAS persistent data object + * streamHandle - stream handle + * pFmtChunk - pointer to pointer to FMT chunk data + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetWaveFmtChunk (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_VOID_PTR *ppFmtChunk); +#endif + +/*---------------------------------------------------------------------------- + * EAS_GetFileType + *---------------------------------------------------------------------------- + * Returns the file type (see eas_types.h for enumerations) + *---------------------------------------------------------------------------- + * pEASData - pointer to EAS persistent data object + * streamHandle - stream handle + * pFileType - pointer to variable to receive file type + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetFileType (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 *pFileType); + +/*---------------------------------------------------------------------------- + * EAS_ParseMetaData() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - file or stream handle + * playLength - pointer to variable to store the play length (in msecs) + * + * Outputs: + * + * + * Side Effects: + * - resets the parser to the start of the file + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_ParseMetaData (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 *pPlayLength); + +/*---------------------------------------------------------------------------- + * EAS_Prepare() + *---------------------------------------------------------------------------- + * Purpose: + * Prepares the synthesizer to play the file or stream. Parses the first + * frame of data from the file and arms the synthesizer. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - file or stream handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Prepare (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle); + +/*---------------------------------------------------------------------------- + * EAS_State() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the state of an audio file or stream. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - file or stream handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_State (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_STATE *pState); + +/*---------------------------------------------------------------------------- + * EAS_RegisterMetaDataCallback() + *---------------------------------------------------------------------------- + * Purpose: + * Registers a metadata callback function for parsed metadata. To + * de-register the callback, call this function again with parameter + * cbFunc set to NULL. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - file or stream handle + * cbFunc - pointer to host callback function + * metaDataBuffer - pointer to metadata buffer + * metaDataBufSize - maximum size of the metadata buffer + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_RegisterMetaDataCallback ( + EAS_DATA_HANDLE pEASData, + EAS_HANDLE streamHandle, + EAS_METADATA_CBFUNC cbFunc, + char *metaDataBuffer, + EAS_I32 metaDataBufSize, + EAS_VOID_PTR pUserData); + +/*---------------------------------------------------------------------------- + * EAS_GetNoteCount () + *---------------------------------------------------------------------------- + * Returns the total number of notes played in this stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - file or stream handle + * pNoteCount - pointer to variable to receive note count + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetNoteCount (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 *pNoteCount); + +/*---------------------------------------------------------------------------- + * EAS_CloseFile() + *---------------------------------------------------------------------------- + * Purpose: + * Closes an audio file or stream. Playback should have either paused or + * completed (EAS_State returns EAS_PAUSED or EAS_STOPPED). + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - file or stream handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_CloseFile (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle); + +/*---------------------------------------------------------------------------- + * EAS_OpenMIDIStream() + *---------------------------------------------------------------------------- + * Purpose: + * Opens a raw MIDI stream allowing the host to route MIDI cable data directly to the synthesizer + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * pStreamHandle - pointer to variable to hold file or stream handle + * streamHandle - open stream or NULL for new synthesizer instance + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_OpenMIDIStream (EAS_DATA_HANDLE pEASData, EAS_HANDLE *pStreamHandle, EAS_HANDLE streamHandle); + +/*---------------------------------------------------------------------------- + * EAS_WriteMIDIStream() + *---------------------------------------------------------------------------- + * Purpose: + * Send data to the MIDI stream device + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - stream handle + * pBuffer - pointer to buffer + * count - number of bytes to write + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_WriteMIDIStream(EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_U8 *pBuffer, EAS_I32 count); + +/*---------------------------------------------------------------------------- + * EAS_CloseMIDIStream() + *---------------------------------------------------------------------------- + * Purpose: + * Closes a raw MIDI stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - stream handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_CloseMIDIStream (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle); + +/*---------------------------------------------------------------------------- + * EAS_Locate() + *---------------------------------------------------------------------------- + * Purpose: + * Locate into the file associated with the handle. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - file handle + * milliseconds - playback offset from start of file in milliseconds + * + * Outputs: + * + * + * Side Effects: + * the actual offset will be quantized to the closest update period, typically + * a resolution of 5.9ms. Notes that are started prior to this time will not + * sound. Any notes currently playing will be shut off. + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Locate (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 milliseconds, EAS_BOOL offset); + +/*---------------------------------------------------------------------------- + * EAS_GetRenderTime() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current playback offset + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * + * Outputs: + * Gets the render time clock in msecs. + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetRenderTime (EAS_DATA_HANDLE pEASData, EAS_I32 *pTime); + +/*---------------------------------------------------------------------------- + * EAS_GetLocation() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current playback offset + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - file handle + * + * Outputs: + * The offset in milliseconds from the start of the current sequence, quantized + * to the nearest update period. Actual resolution is typically 5.9 ms. + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetLocation (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 *pTime); + +/*---------------------------------------------------------------------------- + * EAS_Pause() + *---------------------------------------------------------------------------- + * Purpose: + * Pauses the playback of the data associated with this handle. The audio + * is gracefully ramped down to prevent clicks and pops. It may take several + * buffers of audio before the audio is muted. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * streamHandle - file or stream handle + * + * Outputs: + * + * + * Side Effects: + * + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Pause (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle); + +/*---------------------------------------------------------------------------- + * EAS_Resume() + *---------------------------------------------------------------------------- + * Purpose: + * Resumes the playback of the data associated with this handle. The audio + * is gracefully ramped up to prevent clicks and pops. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * streamHandle - file or stream handle + * + * Outputs: + * + * + * Side Effects: + * + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Resume (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle); + +/*---------------------------------------------------------------------------- + * EAS_GetParameter() + *---------------------------------------------------------------------------- + * Purpose: + * Set the parameter of a module. See E_MODULES for a list of modules + * and the header files of the modules for a list of parameters. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * module - enumerated module number + * param - enumerated parameter number + * pValue - pointer to variable to receive parameter value + * + * Outputs: + * + * + * Side Effects: + * + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetParameter (EAS_DATA_HANDLE pEASData, EAS_I32 module, EAS_I32 param, EAS_I32 *pValue); + +/*---------------------------------------------------------------------------- + * EAS_SetParameter() + *---------------------------------------------------------------------------- + * Purpose: + * Set the parameter of a module. See E_MODULES for a list of modules + * and the header files of the modules for a list of parameters. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * handle - file or stream handle + * module - enumerated module number + * param - enumerated parameter number + * value - new parameter value + * + * Outputs: + * + * + * Side Effects: + * + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetParameter (EAS_DATA_HANDLE pEASData, EAS_I32 module, EAS_I32 param, EAS_I32 value); + +#ifdef _METRICS_ENABLED +/*---------------------------------------------------------------------------- + * EAS_MetricsReport() + *---------------------------------------------------------------------------- + * Purpose: + * Displays the current metrics through the EAS_Report interface. + * + * Inputs: + * pEASData - instance data handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_MetricsReport (EAS_DATA_HANDLE pEASData); + +/*---------------------------------------------------------------------------- + * EAS_MetricsReset() + *---------------------------------------------------------------------------- + * Purpose: + * Displays the current metrics through the EAS_Report interface. + * + * Inputs: + * pEASData - instance data handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_MetricsReset (EAS_DATA_HANDLE pEASData); +#endif + +/*---------------------------------------------------------------------------- + * EAS_SetSoundLibrary() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the location of the sound library. + * + * Inputs: + * pEASData - instance data handle + * streamHandle - file or stream handle + * pSoundLib - pointer to sound library + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetSoundLibrary (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_SNDLIB_HANDLE pSndLib); + +/*---------------------------------------------------------------------------- + * EAS_SetHeaderSearchFlag() + *---------------------------------------------------------------------------- + * By default, when EAS_OpenFile is called, the parsers check the + * first few bytes of the file looking for a specific header. Some + * mobile devices may add a header to the start of a file, which + * will prevent the parser from recognizing the file. If the + * searchFlag is set to EAS_TRUE, the parser will search the entire + * file looking for the header. This may enable EAS to recognize + * some files that it would ordinarily reject. The negative is that + * it make take slightly longer to process the EAS_OpenFile request. + * + * Inputs: + * pEASData - instance data handle + * searchFlag - search flag (EAS_TRUE or EAS_FALSE) + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetHeaderSearchFlag (EAS_DATA_HANDLE pEASData, EAS_BOOL searchFlag); + +/*---------------------------------------------------------------------------- + * EAS_SetPlayMode() + *---------------------------------------------------------------------------- + * Some file formats support special play modes, such as iMode partial + * play mode. This call can be used to change the play mode. The + * default play mode (usually straight playback) is always zero. + * + * Inputs: + * pEASData - instance data handle + * handle - file or stream handle + * playMode - play mode (see eas_types.h for enumerations) + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetPlayMode (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 playMode); + +#ifdef DLS_SYNTHESIZER +/*---------------------------------------------------------------------------- + * EAS_LoadDLSCollection() + *---------------------------------------------------------------------------- + * Purpose: + * Downloads a DLS collection + * + * Inputs: + * pEASData - instance data handle + * streamHandle - file or stream handle + * locator - file locator + * + * Outputs: + * + * + * Side Effects: + * May overlay instruments in the GM sound set + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_LoadDLSCollection (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_FILE_LOCATOR locator); +#endif + +/*---------------------------------------------------------------------------- + * EAS_SetFrameBuffer() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the frame buffer pointer passed to the IPC communications functions + * + * Inputs: + * pEASData - instance data handle + * locator - file locator + * + * Outputs: + * + * + * Side Effects: + * May overlay instruments in the GM sound set + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetFrameBuffer (EAS_DATA_HANDLE pEASData, EAS_FRAME_BUFFER_HANDLE pFrameBuffer); + +#ifdef EXTERNAL_AUDIO +/*---------------------------------------------------------------------------- + * EAS_RegExtAudioCallback() + *---------------------------------------------------------------------------- + * Purpose: + * Registers callback functions for audio events. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - file or stream handle + * cbProgChgFunc - pointer to host callback function for program change + * cbEventFunc - pointer to host callback functio for note events + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_RegExtAudioCallback (EAS_DATA_HANDLE pEASData, + EAS_HANDLE streamHandle, + EAS_VOID_PTR pInstData, + EAS_EXT_PRG_CHG_FUNC cbProgChgFunc, + EAS_EXT_EVENT_FUNC cbEventFunc); + +/*---------------------------------------------------------------------------- + * EAS_GetMIDIControllers() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current state of MIDI controllers on the requested channel. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - file or stream handle + * pControl - pointer to structure to receive data + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetMIDIControllers (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_U8 channel, S_MIDI_CONTROLLERS *pControl); +#endif + +/*---------------------------------------------------------------------------- + * EAS_SearchFile + *---------------------------------------------------------------------------- + * Search file for specific sequence starting at current file + * position. Returns offset to start of sequence. + * + * Inputs: + * pEASData - pointer to EAS persistent data object + * fileHandle - file handle + * searchString - pointer to search sequence + * len - length of search sequence + * pOffset - pointer to variable to store offset to sequence + * + * Returns EAS_EOF if end-of-file is reached + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_SearchFile (EAS_DATA_HANDLE pEASData, EAS_FILE_HANDLE fileHandle, const EAS_U8 *searchString, EAS_I32 len, EAS_I32 *pOffset); + +#ifdef __cplusplus +} /* end extern "C" */ +#endif + +#endif /* #ifndef _EAS_H */ diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_build.h b/common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_build.h new file mode 100755 index 0000000..0e26211 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_build.h @@ -0,0 +1,36 @@ +/*---------------------------------------------------------------------------- + * + * File: + * host_src\eas_build.h + * + * Contents and purpose: + * This file contains the build configuration for this + * build. The buildGUIDStr is a GUID created during + * the build process and is guaranteed to be unique + * for each build. + * + * Copyright Sonic Network Inc. 2006 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file was autogenerated by buildid.exe + *---------------------------------------------------------------------------- +*/ + +#ifndef _GUID_0cbd200ab054487f9ece7d3c8852e426_ +#define _GUID_0cbd200ab054487f9ece7d3c8852e426_ + +#define _BUILD_VERSION_ "0cbd200a-b054-487f-9ece-7d3c8852e426" +#define _BUILD_TIME_ 0x4743b9dc + +#endif /* _GUID_0cbd200ab054487f9ece7d3c8852e426_ */ diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_chorus.h b/common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_chorus.h new file mode 100755 index 0000000..998a828 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_chorus.h @@ -0,0 +1,53 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_chorus.h + * + * Contents and purpose: + * Contains parameter enumerations for the Chorus effect + * + * + * Copyright Sonic Network Inc. 2006 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 309 $ + * $Date: 2006-09-12 18:52:45 -0700 (Tue, 12 Sep 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef EAS_CHORUS_H +#define EAS_CHORUS_H + +/* enumerated parameter settings for Chorus effect */ +typedef enum +{ + EAS_PARAM_CHORUS_BYPASS, + EAS_PARAM_CHORUS_PRESET, + EAS_PARAM_CHORUS_RATE, + EAS_PARAM_CHORUS_DEPTH, + EAS_PARAM_CHORUS_LEVEL +} E_CHORUS_PARAMS; + +typedef enum +{ + EAS_PARAM_CHORUS_PRESET1, + EAS_PARAM_CHORUS_PRESET2, + EAS_PARAM_CHORUS_PRESET3, + EAS_PARAM_CHORUS_PRESET4 +} E_CHORUS_PRESETS; + + +#endif \ No newline at end of file diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_config.c b/common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_config.c new file mode 100755 index 0000000..0b92357 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_config.c @@ -0,0 +1,619 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_config.c + * + * Contents and purpose: + * This file contains the Configuration Module interface (CM). The CM + * is a module compiled external to the library that sets the configuration + * for this build. It allows the library to find optional components and + * links to static memory allocations (when used in a static configuration). + * + * DO NOT MODIFY THIS FILE! + * + * NOTE: This module is not intended to be modified by the customer. It + * needs to be included in the build process with the correct configuration + * defines (see the library documentation for information on how to configure + * the library). + * + * Copyright Sonic Network Inc. 2004-2006 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 796 $ + * $Date: 2007-08-01 00:15:25 -0700 (Wed, 01 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas.h" +#include "eas_config.h" + + +#ifdef _MFI_PARSER +/*---------------------------------------------------------------------------- + * Vendor/Device ID for MFi Extensions + * + * Define the preprocessor symbols to establish the vendor ID and + * device ID for the MFi PCM/ADPCM extensions. + *---------------------------------------------------------------------------- +*/ +const EAS_U8 eas_MFIVendorIDMSB = (MFI_VENDOR_ID >> 8) & 0xff; +const EAS_U8 eas_MFIVendorIDLSB = MFI_VENDOR_ID & 0xff; +const EAS_U8 eas_MFIDeviceID = MFI_DEVICE_ID; +#endif + +/*---------------------------------------------------------------------------- + * + * parserModules + * + * This structure is used by the EAS library to locate file parsing + * modules. + *---------------------------------------------------------------------------- +*/ + +/* define the external file parsers */ +extern EAS_VOID_PTR EAS_SMF_Parser; + +#ifdef _XMF_PARSER +extern EAS_VOID_PTR EAS_XMF_Parser; +#endif + +#ifdef _SMAF_PARSER +extern EAS_VOID_PTR EAS_SMAF_Parser; +#endif + +#ifdef _WAVE_PARSER +extern EAS_VOID_PTR EAS_Wave_Parser; +#endif + +#ifdef _OTA_PARSER +extern EAS_VOID_PTR EAS_OTA_Parser; +#endif + +#ifdef _IMELODY_PARSER +extern EAS_VOID_PTR EAS_iMelody_Parser; +#endif + +#ifdef _RTTTL_PARSER +extern EAS_VOID_PTR EAS_RTTTL_Parser; +#endif + +#if defined (_CMX_PARSER) || defined(_MFI_PARSER) +extern EAS_VOID_PTR EAS_CMF_Parser; +#endif + +/* initalize pointers to parser interfaces */ +/*lint -e{605} not pretty, but it works */ +EAS_VOID_PTR const parserModules[] = +{ + &EAS_SMF_Parser, + +#ifdef _XMF_PARSER + &EAS_XMF_Parser, +#endif + +#ifdef _WAVE_PARSER + &EAS_Wave_Parser, +#endif + +#ifdef _SMAF_PARSER + &EAS_SMAF_Parser, +#endif + +#ifdef _OTA_PARSER + &EAS_OTA_Parser, +#endif + +#ifdef _IMELODY_PARSER + &EAS_iMelody_Parser, +#endif + +#ifdef _RTTTL_PARSER + &EAS_RTTTL_Parser, +#endif + +#if defined (_CMX_PARSER) || defined(_MFI_PARSER) + &EAS_CMF_Parser +#endif +}; +#define NUM_PARSER_MODULES (sizeof(parserModules) / sizeof(EAS_VOID_PTR)) + +/*---------------------------------------------------------------------------- + * Data Modules + *---------------------------------------------------------------------------- +*/ + +#ifdef _STATIC_MEMORY +extern EAS_VOID_PTR eas_SMFData; +extern EAS_VOID_PTR eas_Data; +extern EAS_VOID_PTR eas_MixBuffer; +extern EAS_VOID_PTR eas_Synth; +extern EAS_VOID_PTR eas_MIDI; +extern EAS_VOID_PTR eas_PCMData; +extern EAS_VOID_PTR eas_MIDIData; + +#ifdef _XMF_PARSER +extern EAS_VOID_PTR eas_XMFData; +#endif + +#ifdef _SMAF_PARSER +extern EAS_VOID_PTR eas_SMAFData; +#endif + +#ifdef _OTA_PARSER +extern EAS_VOID_PTR eas_OTAData; +#endif + +#ifdef _IMELODY_PARSER +extern EAS_VOID_PTR eas_iMelodyData; +#endif + +#ifdef _RTTTL_PARSER +extern EAS_VOID_PTR eas_RTTTLData; +#endif + +#ifdef _WAVE_PARSER +extern EAS_VOID_PTR eas_WaveData; +#endif + +#if defined (_CMX_PARSER) || defined(_MFI_PARSER) +extern EAS_VOID_PTR eas_CMFData; +#endif +#endif + +/*---------------------------------------------------------------------------- + * + * Effects Modules + * + * These declarations are used by the EAS library to locate + * effects modules. + *---------------------------------------------------------------------------- +*/ + +#ifdef _ENHANCER_ENABLED +extern EAS_VOID_PTR EAS_Enhancer; +#define EAS_ENHANCER_INTERFACE &EAS_Enhancer +#ifdef _STATIC_MEMORY +extern EAS_VOID_PTR eas_EnhancerData; +#define EAS_ENHANCER_DATA &eas_EnhancerData +#else +#define EAS_ENHANCER_DATA NULL +#endif +#else +#define EAS_ENHANCER_INTERFACE NULL +#define EAS_ENHANCER_DATA NULL +#endif + +#ifdef _COMPRESSOR_ENABLED +extern EAS_VOID_PTR EAS_Compressor; +#define EAS_COMPRESSOR_INTERFACE &EAS_Compressor +#ifdef _STATIC_MEMORY +extern EAS_VOID_PTR eas_CompressorData; +#define EAS_COMPRESSOR_DATA &eas_CompressorData +#else +#define EAS_COMPRESSOR_DATA NULL +#endif +#else +#define EAS_COMPRESSOR_INTERFACE NULL +#define EAS_COMPRESSOR_DATA NULL +#endif + +#ifdef _MAXIMIZER_ENABLED +extern EAS_VOID_PTR EAS_Maximizer; +#define EAS_MAXIMIZER_INTERFACE &EAS_Maximizer +#ifdef _STATIC_MEMORY +extern EAS_VOID_PTR eas_MaximizerData; +#define EAS_MAXIMIZER_DATA &eas_MaximizerData +#else +#define EAS_MAXIMIZER_DATA NULL +#endif +#else +#define EAS_MAXIMIZER_INTERFACE NULL +#define EAS_MAXIMIZER_DATA NULL +#endif + + +#ifdef _REVERB_ENABLED +extern EAS_VOID_PTR EAS_Reverb; +#define EAS_REVERB_INTERFACE &EAS_Reverb +#ifdef _STATIC_MEMORY +extern EAS_VOID_PTR eas_ReverbData; +#define EAS_REVERB_DATA &eas_ReverbData +#else +#define EAS_REVERB_DATA NULL +#endif +#else +#define EAS_REVERB_INTERFACE NULL +#define EAS_REVERB_DATA NULL +#endif + +#ifdef _CHORUS_ENABLED +extern EAS_VOID_PTR EAS_Chorus; +#define EAS_CHORUS_INTERFACE &EAS_Chorus +#ifdef _STATIC_MEMORY +extern EAS_VOID_PTR eas_ChorusData; +#define EAS_CHORUS_DATA &eas_ChorusData +#else +#define EAS_CHORUS_DATA NULL +#endif +#else +#define EAS_CHORUS_INTERFACE NULL +#define EAS_CHORUS_DATA NULL +#endif + +#ifdef _WIDENER_ENABLED +extern EAS_VOID_PTR EAS_Widener; +#define EAS_WIDENER_INTERFACE &EAS_Widener +#ifdef _STATIC_MEMORY +extern EAS_VOID_PTR eas_WidenerData; +#define EAS_WIDENER_DATA &eas_WidenerData +#else +#define EAS_WIDENER_DATA NULL +#endif +#else +#define EAS_WIDENER_INTERFACE NULL +#define EAS_WIDENER_DATA NULL +#endif + +#ifdef _GRAPHIC_EQ_ENABLED +extern EAS_VOID_PTR EAS_GraphicEQ; +#define EAS_GRAPHIC_EQ_INTERFACE &EAS_GraphicEQ +#ifdef _STATIC_MEMORY +extern EAS_VOID_PTR eas_GraphicEQData; +#define EAS_GRAPHIC_EQ_DATA &eas_GraphicEQData +#else +#define EAS_GRAPHIC_EQ_DATA NULL +#endif +#else +#define EAS_GRAPHIC_EQ_INTERFACE NULL +#define EAS_GRAPHIC_EQ_DATA NULL +#endif + +#ifdef _WOW_ENABLED +extern EAS_VOID_PTR EAS_Wow; +#define EAS_WOW_INTERFACE &EAS_Wow +#ifdef _STATIC_MEMORY +#error "WOW module requires dynamic memory model" +#else +#define EAS_WOW_DATA NULL +#endif +#else +#define EAS_WOW_INTERFACE NULL +#define EAS_WOW_DATA NULL +#endif + +#ifdef _TONECONTROLEQ_ENABLED +extern EAS_VOID_PTR EAS_ToneControlEQ; +#define EAS_TONECONTROLEQ_INTERFACE &EAS_ToneControlEQ +#ifdef _STATIC_MEMORY +extern EAS_VOID_PTR eas_ToneControlEQData; +#define EAS_TONECONTROLEQ_DATA &eas_ToneControlEQData +#else +#define EAS_TONECONTROLEQ_DATA NULL +#endif +#else +#define EAS_TONECONTROLEQ_INTERFACE NULL +#define EAS_TONECONTROLEQ_DATA NULL +#endif + +/*lint -e{605} not pretty, but it works */ +EAS_VOID_PTR const effectsModules[] = +{ + EAS_ENHANCER_INTERFACE, + EAS_COMPRESSOR_INTERFACE, + EAS_REVERB_INTERFACE, + EAS_CHORUS_INTERFACE, + EAS_WIDENER_INTERFACE, + EAS_GRAPHIC_EQ_INTERFACE, + EAS_WOW_INTERFACE, + EAS_MAXIMIZER_INTERFACE, + EAS_TONECONTROLEQ_INTERFACE +}; + +EAS_VOID_PTR const effectsData[] = +{ + EAS_ENHANCER_DATA, + EAS_COMPRESSOR_DATA, + EAS_REVERB_DATA, + EAS_CHORUS_DATA, + EAS_WIDENER_DATA, + EAS_GRAPHIC_EQ_DATA, + EAS_WOW_DATA, + EAS_MAXIMIZER_DATA, + EAS_TONECONTROLEQ_DATA +}; + +/*---------------------------------------------------------------------------- + * + * Optional Modules + * + * These declarations are used by the EAS library to locate + * effects modules. + *---------------------------------------------------------------------------- +*/ + +#ifdef _METRICS_ENABLED +extern EAS_VOID_PTR EAS_Metrics; +#define EAS_METRICS_INTERFACE &EAS_Metrics +#ifdef _STATIC_MEMORY +extern EAS_VOID_PTR eas_MetricsData; +#define EAS_METRICS_DATA &eas_MetricsData +#else +#define EAS_METRICS_DATA NULL +#endif +#else +#define EAS_METRICS_INTERFACE NULL +#define EAS_METRICS_DATA NULL +#endif + +#ifdef MMAPI_SUPPORT +extern EAS_VOID_PTR EAS_TC_Parser; +#define EAS_TONE_CONTROL_PARSER &EAS_TC_Parser +#ifdef _STATIC_MEMORY +extern EAS_VOID_PTR eas_TCData; +#define EAS_TONE_CONTROL_DATA &eas_TCData +#else +#define EAS_TONE_CONTROL_DATA NULL +#endif +#else +#define EAS_TONE_CONTROL_PARSER NULL +#define EAS_TONE_CONTROL_DATA NULL +#endif + +/*lint -e{605} not pretty, but it works */ +EAS_VOID_PTR const optionalModules[] = +{ + EAS_TONE_CONTROL_PARSER, + EAS_METRICS_INTERFACE +}; + +EAS_VOID_PTR const optionalData[] = +{ + EAS_TONE_CONTROL_DATA, + EAS_METRICS_DATA +}; + +/*---------------------------------------------------------------------------- + * EAS_CMStaticMemoryModel() + *---------------------------------------------------------------------------- + * Purpose: + * This function returns true if EAS has been configured for + * a static memory model. There are some limitations in the + * static memory model, see the documentation for more + * information. + * + * Outputs: + * returns EAS_TRUE if a module is found + *---------------------------------------------------------------------------- +*/ +EAS_BOOL EAS_CMStaticMemoryModel (void) +{ +#ifdef _STATIC_MEMORY + return EAS_TRUE; +#else + return EAS_FALSE; +#endif +} + +/*---------------------------------------------------------------------------- + * EAS_CMEnumModules() + *---------------------------------------------------------------------------- + * Purpose: + * This function is used to find pointers to optional modules. + * + * Inputs: + * module - module number + * + * Outputs: + * returns a pointer to the module function table or NULL if no module + *---------------------------------------------------------------------------- +*/ +EAS_VOID_PTR EAS_CMEnumModules (EAS_INT module) +{ + + if (module >= (EAS_INT) NUM_PARSER_MODULES) + return NULL; + return parserModules[module]; +} + +/*---------------------------------------------------------------------------- + * EAS_CMEnumData() + *---------------------------------------------------------------------------- + * Purpose: + * This function is used to find pointers to static memory allocations. + * + * Inputs: + * dataModule - enumerated module number + * + * Outputs: + * Returns handle to data or NULL if not found + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, dataModule) used only when _STATIC_MEMORY is defined */ +EAS_VOID_PTR EAS_CMEnumData (EAS_INT dataModule) +{ + +#ifdef _STATIC_MEMORY + switch (dataModule) + { + + /* main instance data for synthesizer */ + case EAS_CM_EAS_DATA: + return &eas_Data; + + /* mix buffer for mix engine */ + case EAS_CM_MIX_BUFFER: + /*lint -e{545} lint doesn't like this because it sees the underlying type */ + return &eas_MixBuffer; + + /* instance data for synth */ + case EAS_CM_SYNTH_DATA: + return &eas_Synth; + + /* instance data for MIDI parser */ + case EAS_CM_MIDI_DATA: + return &eas_MIDI; + + /* instance data for SMF parser */ + case EAS_CM_SMF_DATA: + return &eas_SMFData; + +#ifdef _XMF_PARSER + /* instance data for XMF parser */ + case EAS_CM_XMF_DATA: + return &eas_XMFData; +#endif + +#ifdef _SMAF_PARSER + /* instance data for SMAF parser */ + case EAS_CM_SMAF_DATA: + return &eas_SMAFData; +#endif + + /* instance data for the PCM engine */ + case EAS_CM_PCM_DATA: + /*lint -e{545} lint doesn't like this because it sees the underlying type */ + return &eas_PCMData; + + case EAS_CM_MIDI_STREAM_DATA: + return &eas_MIDIData; + +#ifdef _OTA_PARSER + /* instance data for OTA parser */ + case EAS_CM_OTA_DATA: + return &eas_OTAData; +#endif + +#ifdef _IMELODY_PARSER + /* instance data for iMelody parser */ + case EAS_CM_IMELODY_DATA: + return &eas_iMelodyData; +#endif + +#ifdef _RTTTL_PARSER + /* instance data for RTTTL parser */ + case EAS_CM_RTTTL_DATA: + return &eas_RTTTLData; +#endif + +#ifdef _WAVE_PARSER + /* instance data for WAVE parser */ + case EAS_CM_WAVE_DATA: + return &eas_WaveData; +#endif + +#if defined (_CMX_PARSER) || defined(_MFI_PARSER) + /* instance data for CMF parser */ + case EAS_CM_CMF_DATA: + return &eas_CMFData; +#endif + + default: + return NULL; + } + +#else + return NULL; +#endif +} + +/*---------------------------------------------------------------------------- + * EAS_CMEnumFXModules() + *---------------------------------------------------------------------------- + * Purpose: + * This function is used to find pointers to optional effects modules. + * + * Inputs: + * module - enumerated module number + * pModule - pointer to module interface + * + * Outputs: + * Returns pointer to function table or NULL if not found + *---------------------------------------------------------------------------- +*/ +EAS_VOID_PTR EAS_CMEnumFXModules (EAS_INT module) +{ + + if (module >= NUM_EFFECTS_MODULES) + return NULL; + return effectsModules[module]; +} + +/*---------------------------------------------------------------------------- + * EAS_CMEnumFXData() + *---------------------------------------------------------------------------- + * Purpose: + * This function is used to find pointers to static memory allocations. + * + * Inputs: + * dataModule - enumerated module number + * pData - pointer to handle variable + * + * Outputs: + * Returns handle to data or NULL if not found + *---------------------------------------------------------------------------- +*/ +EAS_VOID_PTR EAS_CMEnumFXData (EAS_INT dataModule) +{ + + if (dataModule >= NUM_EFFECTS_MODULES) + return NULL; + return effectsData[dataModule]; +} + +/*---------------------------------------------------------------------------- + * EAS_CMEnumOptModules() + *---------------------------------------------------------------------------- + * Purpose: + * This function is used to find pointers to optional modules. + * + * Inputs: + * module - enumerated module number + * + * Outputs: + * returns pointer to function table or NULL if no module + *---------------------------------------------------------------------------- +*/ +EAS_VOID_PTR EAS_CMEnumOptModules (EAS_INT module) +{ + + /* sanity check */ + if (module >= NUM_OPTIONAL_MODULES) + return EAS_FALSE; + return optionalModules[module]; +} + +/*---------------------------------------------------------------------------- + * EAS_CMEnumOptData() + *---------------------------------------------------------------------------- + * Purpose: + * This function is used to find pointers to static memory allocations. + * + * Inputs: + * dataModule - enumerated module number + * + * Outputs: + * Returns handle to data or NULL if not found + *---------------------------------------------------------------------------- +*/ +EAS_VOID_PTR EAS_CMEnumOptData (EAS_INT dataModule) +{ + + if (dataModule >= NUM_OPTIONAL_MODULES) + return NULL; + return optionalData[dataModule]; +} + + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_config.h b/common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_config.h new file mode 100755 index 0000000..49c2ef2 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_config.h @@ -0,0 +1,191 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_config.h + * + * Contents and purpose: + * This header declares the Configuration Module interface (CM). The CM + * is a module compiled external to the library that sets the configuration + * for this build. It allows the library to find optional components and + * links to static memory allocations (when used in a static configuration). + * + * NOTE: This module is not intended to be modified by the customer. It + * needs to be included in the build process with the correct configuration + * defines (see the library documentation for information on how to configure + * the library). + * + * DO NOT MODIFY THIS FILE! + * + * Copyright 2005 Sonic Network Inc. + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +// sentinel +#ifndef _EAS_CONFIG_H +#define _EAS_CONFIG_H + +#include "eas_types.h" + +/* list of enumerators for optional modules */ +typedef enum { + EAS_CM_FILE_PARSERS = 1 +} E_CM_ENUM_MODULES; + +/* list of enumerators for module and memory pointers */ +typedef enum { + EAS_CM_EAS_DATA = 1, + EAS_CM_MIX_BUFFER, + EAS_CM_SYNTH_DATA, + EAS_CM_MIDI_DATA, + EAS_CM_SMF_DATA, + EAS_CM_XMF_DATA, + EAS_CM_SMAF_DATA, + EAS_CM_PCM_DATA, + EAS_CM_MIDI_STREAM_DATA, + EAS_CM_METRICS_DATA, + EAS_CM_OTA_DATA, + EAS_CM_IMELODY_DATA, + EAS_CM_RTTTL_DATA, + EAS_CM_WAVE_DATA, + EAS_CM_CMF_DATA +} E_CM_DATA_MODULES; + +typedef struct +{ + int maxSMFStreams; + void *pSMFData; + void *pSMFStream; +} S_EAS_SMF_PTRS; + +typedef struct +{ + int maxSMAFStreams; + void *pSMAFData; + void *pSMAFStream; +} S_EAS_SMAF_PTRS; + +/*---------------------------------------------------------------------------- + * EAS_CMStaticMemoryModel() + *---------------------------------------------------------------------------- + * Purpose: + * This function returns true if EAS has been configured for + * a static memory model. There are some limitations in the + * static memory model, see the documentation for more + * information. + * + * Outputs: + * returns EAS_TRUE if a module is found + *---------------------------------------------------------------------------- +*/ +EAS_BOOL EAS_CMStaticMemoryModel (void); + +/*---------------------------------------------------------------------------- + * EAS_CMEnumModules() + *---------------------------------------------------------------------------- + * Purpose: + * This function is used to find pointers to optional modules. + * + * Inputs: + * module - module number + * + * Outputs: + * returns a pointer to the module function table or NULL if no module + *---------------------------------------------------------------------------- +*/ +EAS_VOID_PTR EAS_CMEnumModules (EAS_INT module); + +/*---------------------------------------------------------------------------- + * EAS_CMEnumData() + *---------------------------------------------------------------------------- + * Purpose: + * This function is used to find pointers to static memory allocations. + * + * Inputs: + * dataModule - enumerated module number + * + * Outputs: + * Returns handle to data or NULL if not found + *---------------------------------------------------------------------------- +*/ +EAS_VOID_PTR EAS_CMEnumData (EAS_INT dataModule); + +/*---------------------------------------------------------------------------- + * EAS_CMEnumFXModules() + *---------------------------------------------------------------------------- + * Purpose: + * This function is used to find pointers to optional effects modules. + * + * Inputs: + * module - enumerated module number + * pModule - pointer to module interface + * + * Outputs: + * Returns pointer to function table or NULL if not found + *---------------------------------------------------------------------------- +*/ +EAS_VOID_PTR EAS_CMEnumFXModules (EAS_INT module); + +/*---------------------------------------------------------------------------- + * EAS_CMEnumFXData() + *---------------------------------------------------------------------------- + * Purpose: + * This function is used to find pointers to static memory allocations. + * + * Inputs: + * dataModule - enumerated module number + * pData - pointer to handle variable + * + * Outputs: + * Returns handle to data or NULL if not found + *---------------------------------------------------------------------------- +*/ +EAS_VOID_PTR EAS_CMEnumFXData (EAS_INT dataModule); + +/*---------------------------------------------------------------------------- + * EAS_CMEnumOptModules() + *---------------------------------------------------------------------------- + * Purpose: + * This function is used to find pointers to optional modules. + * + * Inputs: + * module - enumerated module number + * + * Outputs: + * returns pointer to function table or NULL if no module + *---------------------------------------------------------------------------- +*/ +EAS_VOID_PTR EAS_CMEnumOptModules (EAS_INT module); + +/*---------------------------------------------------------------------------- + * EAS_CMEnumOptData() + *---------------------------------------------------------------------------- + * Purpose: + * This function is used to find pointers to static memory allocations. + * + * Inputs: + * dataModule - enumerated module number + * + * Outputs: + * Returns handle to data or NULL if not found + *---------------------------------------------------------------------------- +*/ +EAS_VOID_PTR EAS_CMEnumOptData (EAS_INT dataModule); + +#endif /* end _EAS_CONFIG_H */ diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_debugmsgs.h b/common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_debugmsgs.h new file mode 100755 index 0000000..df120bc --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_debugmsgs.h @@ -0,0 +1,44 @@ +/* Auto-generated from source file: eas_chorusdata.c */ +/* Auto-generated from source file: eas_imelodydata.c */ +/* Auto-generated from source file: eas_mididata.c */ +/* Auto-generated from source file: eas_pan.c */ +/* Auto-generated from source file: eas_wavefiledata.c */ +/* Auto-generated from source file: eas_voicemgt.c */ +/* Auto-generated from source file: eas_ota.c */ +/* Auto-generated from source file: eas_mixbuf.c */ +/* Auto-generated from source file: eas_rtttl.c */ +/* Auto-generated from source file: eas_reverb.c */ +/* Auto-generated from source file: eas_fmsynth.c */ +/* Auto-generated from source file: eas_pcmdata.c */ +/* Auto-generated from source file: eas_chorus.c */ +/* Auto-generated from source file: eas_math.c */ +/* Auto-generated from source file: eas_fmengine.c */ +/* Auto-generated from source file: eas_smfdata.c */ +/* Auto-generated from source file: eas_fmtables.c */ +/* Auto-generated from source file: eas_imelody.c */ +/* Auto-generated from source file: eas_public.c */ +/* Auto-generated from source file: eas_rtttldata.c */ +/* Auto-generated from source file: eas_reverbdata.c */ +/* Auto-generated from source file: eas_wtengine.c */ +/* Auto-generated from source file: eas_imaadpcm.c */ +{ 0x2380b977, 0x00000006, "eas_imaadpcm.c[305]: IMADecoderLocate: Time=%d, samples=%d\n" }, +{ 0x2380b977, 0x00000007, "eas_imaadpcm.c[328]: IMADecoderLocate: Looped sample, numBlocks=%d, samplesPerLoop=%d, samplesInLastBlock=%d, samples=%d\n" }, +{ 0x2380b977, 0x00000008, "eas_imaadpcm.c[335]: IMADecoderLocate: Byte location in audio = %d\n" }, +{ 0x2380b977, 0x00000009, "eas_imaadpcm.c[345]: IMADecoderLocate: bytesLeft = %d\n" }, +/* Auto-generated from source file: eas_midi.c */ +/* Auto-generated from source file: eas_otadata.c */ +/* Auto-generated from source file: eas_ima_tables.c */ +/* Auto-generated from source file: eas_data.c */ +/* Auto-generated from source file: eas_pcm.c */ +/* Auto-generated from source file: eas_mixer.c */ +/* Auto-generated from source file: eas_wavefile.c */ +/* Auto-generated from source file: eas_wtsynth.c */ +/* Auto-generated from source file: eas_smf.c */ +/* Auto-generated from source file: eas_wave.c */ +/* Auto-generated from source file: eas_hostmm.c */ +{ 0x1a54b6e8, 0x00000001, "eas_hostmm.c[586]: Vibrate state: %d\n" }, +{ 0x1a54b6e8, 0x00000002, "eas_hostmm.c[601]: LED state: %d\n" }, +{ 0x1a54b6e8, 0x00000003, "eas_hostmm.c[616]: Backlight state: %d\n" }, +/* Auto-generated from source file: eas_config.c */ +/* Auto-generated from source file: eas_main.c */ +{ 0xe624f4d9, 0x00000005, "eas_main.c[106]: Play length: %d.%03d (secs)\n" }, diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_host.h b/common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_host.h new file mode 100755 index 0000000..b356982 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_host.h @@ -0,0 +1,83 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_host.h + * + * Contents and purpose: + * This header defines the host wrapper functions for stdio, stdlib, etc. + * The host application must provide an abstraction layer for these functions + * to support certain features, such as SMAF and SMF-1 conversion. + * + * DO NOT MODIFY THIS FILE! + * + * Copyright 2005 Sonic Network Inc. + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +// sentinel +#ifndef _EAS_HOST_H +#define _EAS_HOST_H + +#include "eas_types.h" + +/* for C++ linkage */ +#ifdef __cplusplus +extern "C" { +#endif + +/* initialization and shutdown routines */ +extern EAS_RESULT EAS_HWInit(EAS_HW_DATA_HANDLE *hwInstData); +extern EAS_RESULT EAS_HWShutdown(EAS_HW_DATA_HANDLE hwInstData); + +/* memory functions */ +extern void *EAS_HWMemSet(void *s, int c, EAS_I32 n); +extern void *EAS_HWMemCpy(void *s1, const void *s2, EAS_I32 n); +extern EAS_I32 EAS_HWMemCmp(const void *s1, const void *s2, EAS_I32 n); + +/* memory allocation */ +extern void *EAS_HWMalloc(EAS_HW_DATA_HANDLE hwInstData, EAS_I32 size); +extern void EAS_HWFree(EAS_HW_DATA_HANDLE hwInstData, void *p); + +/* file I/O */ +extern EAS_RESULT EAS_HWOpenFile(EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_LOCATOR locator, EAS_FILE_HANDLE *pFile, EAS_FILE_MODE mode); +extern EAS_RESULT EAS_HWReadFile(EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *pBuffer, EAS_I32 n, EAS_I32 *pBytesRead); +extern EAS_RESULT EAS_HWGetByte(EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *p); +extern EAS_RESULT EAS_HWGetWord (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *p, EAS_BOOL msbFirst); +extern EAS_RESULT EAS_HWGetDWord (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *p, EAS_BOOL msbFirst); +extern EAS_RESULT EAS_HWFilePos (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 *pPosition); +extern EAS_RESULT EAS_HWFileSeek (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 position); +extern EAS_RESULT EAS_HWFileSeekOfs (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 position); +extern EAS_RESULT EAS_HWFileLength (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 *pLength); +extern EAS_RESULT EAS_HWDupHandle (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_FILE_HANDLE* pFile); +extern EAS_RESULT EAS_HWCloseFile (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file); + +/* vibrate, LED, and backlight functions */ +extern EAS_RESULT EAS_HWVibrate(EAS_HW_DATA_HANDLE hwInstData, EAS_BOOL state); +extern EAS_RESULT EAS_HWLED(EAS_HW_DATA_HANDLE hwInstData, EAS_BOOL state); +extern EAS_RESULT EAS_HWBackLight(EAS_HW_DATA_HANDLE hwInstData, EAS_BOOL state); + +#ifdef __cplusplus +} /* end extern "C" */ +#endif + + +/* host yield function */ +extern EAS_BOOL EAS_HWYield(EAS_HW_DATA_HANDLE hwInstData); +#endif /* end _EAS_HOST_H */ diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_hostmm.c b/common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_hostmm.c new file mode 100755 index 0000000..df24cf2 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_hostmm.c @@ -0,0 +1,660 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_hostmm.c + * + * Contents and purpose: + * This file contains the host wrapper functions for stdio, stdlib, etc. + * This is a sample version that maps the requested files to an + * allocated memory block and uses in-memory pointers to replace + * file system calls. The file locator (EAS_FILE_LOCATOR) handle passed + * HWOpenFile is the same one that is passed to EAS_OpenFile. If your + * system stores data in fixed locations (such as flash) instead of + * using a file system, you can use the locator handle to point to + * your memory. You will need a way of knowing the length of the + * data stored at that location in order to respond correctly in the + * HW_FileLength function. + * + * Modify this file to suit the needs of your particular system. + * + * EAS_MAX_FILE_HANDLES sets the maximum number of MIDI streams within + * a MIDI type 1 file that can be played. + * + * EAS_HW_FILE is a structure to support the file I/O functions. It + * comprises the base memory pointer, the file read pointer, and + * the dup flag, which when sets, indicates that the file handle has + * been duplicated. If your system uses in-memory resources, you + * can eliminate the duplicate handle logic, and simply copy the + * base memory pointer and file read pointer to the duplicate handle. + * + * Copyright 2005 Sonic Network Inc. + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 795 $ + * $Date: 2007-08-01 00:14:45 -0700 (Wed, 01 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifdef _lint +#include "lint_stdlib.h" +#else +#include +#include +#include +#endif + +#include "eas_host.h" + +/* Only for debugging LED, vibrate, and backlight functions */ +#include "eas_report.h" + +/* this module requires dynamic memory support */ +#ifdef _STATIC_MEMORY +#error "eas_hostmm.c requires the dynamic memory model!\n" +#endif + +#ifndef EAS_MAX_FILE_HANDLES +#define EAS_MAX_FILE_HANDLES 32 +#endif + +/* + * this structure and the related function are here + * to support the ability to create duplicate handles + * and buffering it in memory. If your system uses + * in-memory resources, you can eliminate the calls + * to malloc and free, the dup flag, and simply track + * the file size and read position. + */ +typedef struct eas_hw_file_tag +{ + EAS_I32 fileSize; + EAS_I32 filePos; + EAS_BOOL dup; + EAS_U8 *buffer; +} EAS_HW_FILE; + +typedef struct eas_hw_inst_data_tag +{ + EAS_HW_FILE files[EAS_MAX_FILE_HANDLES]; +} EAS_HW_INST_DATA; + +/*---------------------------------------------------------------------------- + * EAS_HWInit + * + * Initialize host wrapper interface + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_HWInit (EAS_HW_DATA_HANDLE *pHWInstData) +{ + + /* need to track file opens for duplicate handles */ + *pHWInstData = malloc(sizeof(EAS_HW_INST_DATA)); + if (!(*pHWInstData)) + return EAS_ERROR_MALLOC_FAILED; + + EAS_HWMemSet(*pHWInstData, 0, sizeof(EAS_HW_INST_DATA)); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_HWShutdown + * + * Shut down host wrapper interface + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_HWShutdown (EAS_HW_DATA_HANDLE hwInstData) +{ + + free(hwInstData); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWMalloc + * + * Allocates dynamic memory + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +void *EAS_HWMalloc (EAS_HW_DATA_HANDLE hwInstData, EAS_I32 size) +{ + return malloc((size_t) size); +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWFree + * + * Frees dynamic memory + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +void EAS_HWFree (EAS_HW_DATA_HANDLE hwInstData, void *p) +{ + free(p); +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWMemCpy + * + * Copy memory wrapper + * + *---------------------------------------------------------------------------- +*/ +void *EAS_HWMemCpy (void *dest, const void *src, EAS_I32 amount) +{ + return memcpy(dest, src, (size_t) amount); +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWMemSet + * + * Set memory wrapper + * + *---------------------------------------------------------------------------- +*/ +void *EAS_HWMemSet (void *dest, int val, EAS_I32 amount) +{ + return memset(dest, val, (size_t) amount); +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWMemCmp + * + * Compare memory wrapper + * + *---------------------------------------------------------------------------- +*/ +EAS_I32 EAS_HWMemCmp (const void *s1, const void *s2, EAS_I32 amount) +{ + return (EAS_I32) memcmp(s1, s2, (size_t) amount); +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWOpenFile + * + * Open a file for read or write + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_HWOpenFile (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_LOCATOR locator, EAS_FILE_HANDLE *pFile, EAS_FILE_MODE mode) +{ + EAS_HW_FILE *file; + FILE *ioFile; + int i, temp; + + /* set return value to NULL */ + *pFile = NULL; + + /* only support read mode at this time */ + if (mode != EAS_FILE_READ) + return EAS_ERROR_INVALID_FILE_MODE; + + /* find an empty entry in the file table */ + file = hwInstData->files; + for (i = 0; i < EAS_MAX_FILE_HANDLES; i++) + { + /* is this slot being used? */ + if (file->buffer == NULL) + { + /* open the file */ + if ((ioFile = fopen(locator,"rb")) == NULL) + return EAS_ERROR_FILE_OPEN_FAILED; + + /* determine the file size */ + if (fseek(ioFile, 0L, SEEK_END) != 0) + return EAS_ERROR_FILE_LENGTH; + if ((file->fileSize = ftell(ioFile)) == -1L) + return EAS_ERROR_FILE_LENGTH; + if (fseek(ioFile, 0L, SEEK_SET) != 0) + return EAS_ERROR_FILE_LENGTH; + + /* allocate a buffer */ + file->buffer = EAS_HWMalloc(hwInstData, file->fileSize); + if (file->buffer == NULL) + { + fclose(ioFile); + return EAS_ERROR_MALLOC_FAILED; + } + + /* read the file into memory */ + temp = (int) fread(file->buffer, (size_t) file->fileSize, 1, ioFile); + + /* close the file - don't need it any more */ + fclose(ioFile); + + /* check for error reading file */ + if (temp != 1) + return EAS_ERROR_FILE_READ_FAILED; + + /* initialize some values */ + file->filePos = 0; + file->dup = EAS_FALSE; + + *pFile = file; + return EAS_SUCCESS; + } + file++; + } + + /* too many open files */ + return EAS_ERROR_MAX_FILES_OPEN; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWReadFile + * + * Read data from a file + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWReadFile (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *pBuffer, EAS_I32 n, EAS_I32 *pBytesRead) +{ + EAS_I32 count; + + /* make sure we have a valid handle */ + if (file->buffer == NULL) + return EAS_ERROR_INVALID_HANDLE; + + /* calculate the bytes to read */ + count = file->fileSize - file->filePos; + if (n < count) + count = n; + + /* copy the data to the requested location, and advance the pointer */ + if (count) + EAS_HWMemCpy(pBuffer, &file->buffer[file->filePos], count); + file->filePos += count; + *pBytesRead = count; + + /* were n bytes read? */ + if (count!= n) + return EAS_EOF; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWGetByte + * + * Read a byte from a file + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWGetByte (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *p) +{ + + /* make sure we have a valid handle */ + if (file->buffer == NULL) + return EAS_ERROR_INVALID_HANDLE; + + /* check for end of file */ + if (file->filePos >= file->fileSize) + { + *((EAS_U8*) p) = 0; + return EAS_EOF; + } + + /* get a character from the buffer */ + *((EAS_U8*) p) = file->buffer[file->filePos++]; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWGetWord + * + * Returns the current location in the file + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWGetWord (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *p, EAS_BOOL msbFirst) +{ + EAS_RESULT result; + EAS_U8 c1, c2; + + /* read 2 bytes from the file */ + if ((result = EAS_HWGetByte(hwInstData, file, &c1)) != EAS_SUCCESS) + return result; + if ((result = EAS_HWGetByte(hwInstData, file, &c2)) != EAS_SUCCESS) + return result; + + /* order them as requested */ + if (msbFirst) + *((EAS_U16*) p) = ((EAS_U16) c1 << 8) | c2; + else + *((EAS_U16*) p) = ((EAS_U16) c2 << 8) | c1; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWGetDWord + * + * Returns the current location in the file + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWGetDWord (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *p, EAS_BOOL msbFirst) +{ + EAS_RESULT result; + EAS_U8 c1, c2,c3,c4; + + /* read 4 bytes from the file */ + if ((result = EAS_HWGetByte(hwInstData, file, &c1)) != EAS_SUCCESS) + return result; + if ((result = EAS_HWGetByte(hwInstData, file, &c2)) != EAS_SUCCESS) + return result; + if ((result = EAS_HWGetByte(hwInstData, file, &c3)) != EAS_SUCCESS) + return result; + if ((result = EAS_HWGetByte(hwInstData, file, &c4)) != EAS_SUCCESS) + return result; + + /* order them as requested */ + if (msbFirst) + *((EAS_U32*) p) = ((EAS_U32) c1 << 24) | ((EAS_U32) c2 << 16) | ((EAS_U32) c3 << 8) | c4; + else + *((EAS_U32*) p)= ((EAS_U32) c4 << 24) | ((EAS_U32) c3 << 16) | ((EAS_U32) c2 << 8) | c1; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWFilePos + * + * Returns the current location in the file + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWFilePos (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 *pPosition) +{ + + /* make sure we have a valid handle */ + if (file->buffer == NULL) + return EAS_ERROR_INVALID_HANDLE; + + *pPosition = file->filePos; + return EAS_SUCCESS; +} /* end EAS_HWFilePos */ + +/*---------------------------------------------------------------------------- + * + * EAS_HWFileSeek + * + * Seek to a specific location in the file + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWFileSeek (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 position) +{ + + /* make sure we have a valid handle */ + if (file->buffer == NULL) + return EAS_ERROR_INVALID_HANDLE; + + /* validate new position */ + if ((position < 0) || (position > file->fileSize)) + return EAS_ERROR_FILE_SEEK; + + /* save new position */ + file->filePos = position; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWFileSeekOfs + * + * Seek forward or back relative to the current position + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWFileSeekOfs (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 position) +{ + + /* make sure we have a valid handle */ + if (file->buffer == NULL) + return EAS_ERROR_INVALID_HANDLE; + + /* determine the file position */ + position += file->filePos; + if ((position < 0) || (position > file->fileSize)) + return EAS_ERROR_FILE_SEEK; + + /* save new position */ + file->filePos = position; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWFileLength + * + * Return the file length + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWFileLength (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 *pLength) +{ + + /* make sure we have a valid handle */ + if (file->buffer == NULL) + return EAS_ERROR_INVALID_HANDLE; + + *pLength = file->fileSize; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWDupHandle + * + * Duplicate a file handle + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_HWDupHandle (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_FILE_HANDLE *pDupFile) +{ + EAS_HW_FILE *dupFile; + int i; + + /* make sure we have a valid handle */ + if (file->buffer == NULL) + return EAS_ERROR_INVALID_HANDLE; + + /* find an empty entry in the file table */ + dupFile = hwInstData->files; + for (i = 0; i < EAS_MAX_FILE_HANDLES; i++) + { + /* is this slot being used? */ + if (dupFile->buffer == NULL) + { + + /* copy info from the handle to be duplicated */ + dupFile->filePos = file->filePos; + dupFile->fileSize = file->fileSize; + dupFile->buffer = file->buffer; + + /* set the duplicate handle flag */ + dupFile->dup = file->dup = EAS_TRUE; + + *pDupFile = dupFile; + return EAS_SUCCESS; + } + dupFile++; + } + + /* too many open files */ + return EAS_ERROR_MAX_FILES_OPEN; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWClose + * + * Wrapper for fclose function + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_HWCloseFile (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file1) +{ + EAS_HW_FILE *file2,*dupFile; + int i; + + + /* make sure we have a valid handle */ + if (file1->buffer == NULL) + return EAS_ERROR_INVALID_HANDLE; + + /* check for duplicate handle */ + if (file1->dup) + { + dupFile = NULL; + file2 = hwInstData->files; + for (i = 0; i < EAS_MAX_FILE_HANDLES; i++) + { + /* check for duplicate */ + if ((file1 != file2) && (file2->buffer == file1->buffer)) + { + /* is there more than one duplicate? */ + if (dupFile != NULL) + { + /* clear this entry and return */ + file1->buffer = NULL; + return EAS_SUCCESS; + } + + /* this is the first duplicate found */ + else + dupFile = file2; + } + file2++; + } + + /* there is only one duplicate, clear the dup flag */ + if (dupFile) + dupFile->dup = EAS_FALSE; + else + /* if we get here, there's a serious problem */ + return EAS_ERROR_HANDLE_INTEGRITY; + + /* clear this entry and return */ + file1->buffer = NULL; + return EAS_SUCCESS; + } + + /* no duplicates -free the buffer */ + EAS_HWFree(hwInstData, file1->buffer); + + /* clear this entry and return */ + file1->buffer = NULL; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWVibrate + * + * Turn on/off vibrate function + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWVibrate (EAS_HW_DATA_HANDLE hwInstData, EAS_BOOL state) +{ + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x1a54b6e8, 0x00000001 , state); + return EAS_SUCCESS; +} /* end EAS_HWVibrate */ + +/*---------------------------------------------------------------------------- + * + * EAS_HWLED + * + * Turn on/off LED + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWLED (EAS_HW_DATA_HANDLE hwInstData, EAS_BOOL state) +{ + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x1a54b6e8, 0x00000002 , state); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWBackLight + * + * Turn on/off backlight + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWBackLight (EAS_HW_DATA_HANDLE hwInstData, EAS_BOOL state) +{ + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x1a54b6e8, 0x00000003 , state); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWYield + * + * This function is called periodically by the EAS library to give the + * host an opportunity to allow other tasks to run. There are two ways to + * use this call: + * + * If you have a multi-tasking OS, you can call the yield function in the + * OS to allow other tasks to run. In this case, return EAS_FALSE to tell + * the EAS library to continue processing when control returns from this + * function. + * + * If tasks run in a single thread by sequential function calls (sometimes + * call a "commutator loop"), return EAS_TRUE to cause the EAS Library to + * return to the caller. Be sure to check the number of bytes rendered + * before passing the audio buffer to the codec - it may not be filled. + * The next call to EAS_Render will continue processing until the buffer + * has been filled. + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_BOOL EAS_HWYield (EAS_HW_DATA_HANDLE hwInstData) +{ + /* put your code here */ + return EAS_FALSE; +} + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_main.c b/common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_main.c new file mode 100755 index 0000000..6ebb13e --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_main.c @@ -0,0 +1,461 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_main.c + * + * Contents and purpose: + * The entry point and high-level functions for the EAS Synthesizer test + * harness. + * + * Copyright Sonic Network Inc. 2004 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 775 $ + * $Date: 2007-07-20 10:11:11 -0700 (Fri, 20 Jul 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifdef _lint +#include "lint_stdlib.h" +#else +#include +#include +#include +#include +#endif + +#include "eas.h" +#include "eas_wave.h" +#include "eas_report.h" + +/* determines how many EAS buffers to fill a host buffer */ +#define NUM_BUFFERS 8 + +/* default file to play if no filename is specified on the command line */ +static const char defaultTestFile[] = "test.mid"; + +EAS_I32 polyphony; + +/* prototypes for helper functions */ +static void StrCopy(char *dest, const char *src, EAS_I32 size); +static EAS_BOOL ChangeFileExt(char *str, const char *ext, EAS_I32 size); +static EAS_RESULT PlayFile (EAS_DATA_HANDLE easData, const char* filename, const char* outputFile, const S_EAS_LIB_CONFIG *pLibConfig, void *buffer, EAS_I32 bufferSize); +static EAS_BOOL EASLibraryCheck (const S_EAS_LIB_CONFIG *pLibConfig); + +/* main is defined after playfile to avoid the need for two passes through lint */ + +/*---------------------------------------------------------------------------- + * PlayFile() + *---------------------------------------------------------------------------- + * Purpose: + * This function plays the file requested by filename + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ + +static EAS_RESULT PlayFile (EAS_DATA_HANDLE easData, const char* filename, const char* outputFile, const S_EAS_LIB_CONFIG *pLibConfig, void *buffer, EAS_I32 bufferSize) +{ + EAS_HANDLE handle; + EAS_RESULT result, reportResult; + EAS_I32 count; + EAS_STATE state; + EAS_I32 playTime; + char waveFilename[256]; + WAVE_FILE *wFile; + EAS_INT i; + EAS_PCM *p; + + /* determine the name of the output file */ + wFile = NULL; + if (outputFile == NULL) + { + StrCopy(waveFilename, filename, sizeof(waveFilename)); + if (!ChangeFileExt(waveFilename, "wav", sizeof(waveFilename))) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error in output filename %s\n", waveFilename); */ } + return EAS_FAILURE; + } + outputFile = waveFilename; + } + + /* call EAS library to open file */ + if ((reportResult = EAS_OpenFile(easData, filename, &handle)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_OpenFile returned %ld\n", reportResult); */ } + return reportResult; + } + + /* prepare to play the file */ + if ((result = EAS_Prepare(easData, handle)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_Prepare returned %ld\n", result); */ } + reportResult = result; + } + + /* get play length */ + if ((result = EAS_ParseMetaData(easData, handle, &playTime)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_ParseMetaData returned %ld\n", result); */ } + return result; + } + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0xe624f4d9, 0x00000005 , playTime / 1000, playTime % 1000); + + if (reportResult == EAS_SUCCESS) + { + /* create the output file */ + wFile = WaveFileCreate(outputFile, pLibConfig->numChannels, pLibConfig->sampleRate, sizeof(EAS_PCM) * 8); + if (!wFile) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Unable to create output file %s\n", waveFilename); */ } + reportResult = EAS_FAILURE; + } + } + + /* rendering loop */ + while (reportResult == EAS_SUCCESS) + { + + /* we may render several buffers here to fill one host buffer */ + for (i = 0, p = buffer; i < NUM_BUFFERS; i++, p+= pLibConfig->mixBufferSize * pLibConfig->numChannels) + { + + /* get the current time */ + if ((result = EAS_GetLocation(easData, handle, &playTime)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_GetLocation returned %d\n",result); */ } + if (reportResult == EAS_SUCCESS) + reportResult = result; + break; + } + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Parser time: %d.%03d\n", playTime / 1000, playTime % 1000); */ } + + /* render a buffer of audio */ + if ((result = EAS_Render(easData, p, pLibConfig->mixBufferSize, &count)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_Render returned %d\n",result); */ } + if (reportResult == EAS_SUCCESS) + reportResult = result; + } + } + + if (result == EAS_SUCCESS) + { + /* write it to the wave file */ + if (WaveFileWrite(wFile, buffer, bufferSize) != bufferSize) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "WaveFileWrite failed\n"); */ } + reportResult = EAS_FAILURE; + } + } + + if (reportResult == EAS_SUCCESS) + { + /* check stream state */ + if ((result = EAS_State(easData, handle, &state)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_State returned %d\n", result); */ } + reportResult = result; + } + + /* is playback complete */ + if ((state == EAS_STATE_STOPPED) || (state == EAS_STATE_ERROR)) + break; + } + } + + /* close the output file */ + if (wFile) + { + if (!WaveFileClose(wFile)) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error closing wave file %s\n", waveFilename); */ } + if (reportResult == EAS_SUCCESS) + result = EAS_FAILURE; + } + } + + /* close the input file */ + if ((result = EAS_CloseFile(easData,handle)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_Close returned %ld\n", result); */ } + if (reportResult == EAS_SUCCESS) + result = EAS_FAILURE; + } + + return reportResult; +} /* end PlayFile */ + +/*---------------------------------------------------------------------------- + * main() + *---------------------------------------------------------------------------- + * Purpose: The entry point for the EAS sample application + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +int main( int argc, char **argv ) +{ + EAS_DATA_HANDLE easData; + const S_EAS_LIB_CONFIG *pLibConfig; + void *buffer; + EAS_RESULT result, playResult; + EAS_I32 bufferSize; + int i; + int temp; + FILE *debugFile; + char *outputFile = NULL; + + /* set the error reporting level */ + EAS_SetDebugLevel(_EAS_SEVERITY_INFO); + debugFile = NULL; + + /* process command-line arguments */ + for (i = 1; i < argc; i++) + { + /* check for switch */ + if (argv[i][0] == '-') + { + switch (argv[i][1]) + { + case 'd': + temp = argv[i][2]; + if ((temp >= '0') || (temp <= '9')) + EAS_SetDebugLevel(temp); + else + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Invalid debug level %d\n", temp); */ } + break; + case 'f': + if ((debugFile = fopen(&argv[i][2],"w")) == NULL) + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Unable to create debug file %s\n", &argv[i][2]); */ } + else + EAS_SetDebugFile(debugFile, EAS_TRUE); + break; + case 'o': + outputFile = &argv[i][2]; + break; + case 'p': + polyphony = atoi(&argv[i][2]); + if (polyphony < 1) + polyphony = 1; + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "Polyphony set to %d\n", polyphony); */ } + break; + default: + break; + } + continue; + } + } + + /* assume success */ + playResult = EAS_SUCCESS; + + /* get the library configuration */ + pLibConfig = EAS_Config(); + if (!EASLibraryCheck(pLibConfig)) + return -1; + if (polyphony > pLibConfig->maxVoices) + polyphony = pLibConfig->maxVoices; + + /* calculate buffer size */ + bufferSize = pLibConfig->mixBufferSize * pLibConfig->numChannels * (EAS_I32)sizeof(EAS_PCM) * NUM_BUFFERS; + + /* allocate output buffer memory */ + buffer = malloc((EAS_U32)bufferSize); + if (!buffer) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Error allocating memory for audio buffer\n"); */ } + return EAS_FAILURE; + } + + /* initialize the EAS library */ + polyphony = pLibConfig->maxVoices; + if ((result = EAS_Init(&easData)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "EAS_Init returned %ld - aborting!\n", result); */ } + free(buffer); + return result; + } + + /* + * Some debugging environments don't allow for passed parameters. + * In this case, just play the default MIDI file "test.mid" + */ + if (argc < 2) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "Playing '%s'\n", defaultTestFile); */ } + if ((playResult = PlayFile(easData, defaultTestFile, NULL, pLibConfig, buffer, bufferSize)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %d playing file %s\n", playResult, defaultTestFile); */ } + } + } + /* iterate through the list of files to be played */ + else + { + for (i = 1; i < argc; i++) + { + /* check for switch */ + if (argv[i][0] != '-') + { + + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "Playing '%s'\n", argv[i]); */ } + if ((playResult = PlayFile(easData, argv[i], outputFile, pLibConfig, buffer, bufferSize)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %d playing file %s\n", playResult, argv[i]); */ } + break; + } + } + } + } + + /* shutdown the EAS library */ + if ((result = EAS_Shutdown(easData)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "EAS_Shutdown returned %ld\n", result); */ } + } + + /* free the output buffer */ + free(buffer); + + /* close the debug file */ + if (debugFile) + fclose(debugFile); + + /* play errors take precedence over shutdown errors */ + if (playResult != EAS_SUCCESS) + return playResult; + return result; +} /* end main */ + +/*---------------------------------------------------------------------------- + * StrCopy() + *---------------------------------------------------------------------------- + * Purpose: + * Safe string copy + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static void StrCopy(char *dest, const char *src, EAS_I32 size) +{ + int len; + + strncpy(dest, src, (size_t) size-1); + len = (int) strlen(src); + if (len < size) + dest[len] = 0; +} /* end StrCopy */ + +/*---------------------------------------------------------------------------- + * ChangeFileExt() + *---------------------------------------------------------------------------- + * Purpose: + * Changes the file extension of a filename + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL ChangeFileExt(char *str, const char *ext, EAS_I32 size) +{ + char *p; + + /* find the extension, if any */ + p = strrchr(str,'.'); + if (!p) + { + if ((EAS_I32)(strlen(str) + 5) > size) + return EAS_FALSE; + strcat(str,"."); + strcat(str,ext); + return EAS_TRUE; + } + + /* make sure there's room for the extension */ + p++; + *p = 0; + if ((EAS_I32)(strlen(str) + 4) > size) + return EAS_FALSE; + strcat(str,ext); + return EAS_TRUE; +} /* end ChangeFileExt */ + +/*---------------------------------------------------------------------------- + * EASLibraryCheck() + *---------------------------------------------------------------------------- + * Purpose: + * Displays the library version and checks it against the header + * file used to build this code. + * + * Inputs: + * pLibConfig - library configuration retrieved from the library + * + * Outputs: + * returns EAS_TRUE if matched + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL EASLibraryCheck (const S_EAS_LIB_CONFIG *pLibConfig) +{ + + /* display the library version */ + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "EAS Library Version %d.%d.%d.%d\n", + pLibConfig->libVersion >> 24, + (pLibConfig->libVersion >> 16) & 0x0f, + (pLibConfig->libVersion >> 8) & 0x0f, + pLibConfig->libVersion & 0x0f); */ } + + /* display some info about the library build */ + if (pLibConfig->checkedVersion) + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tChecked library\n"); */ } + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tMaximum polyphony: %d\n", pLibConfig->maxVoices); */ } + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tNumber of channels: %d\n", pLibConfig->numChannels); */ } + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tSample rate: %d\n", pLibConfig->sampleRate); */ } + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tMix buffer size: %d\n", pLibConfig->mixBufferSize); */ } + if (pLibConfig->filterEnabled) + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tFilter enabled\n"); */ } +#ifndef _WIN32_WCE + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tLibrary Build Timestamp: %s", ctime((time_t*)&pLibConfig->buildTimeStamp)); */ } +#endif + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tLibrary Build ID: %s\n", pLibConfig->buildGUID); */ } + + /* check it against the header file used to build this code */ + /*lint -e{778} constant expression used for display purposes may evaluate to zero */ + if (LIB_VERSION != pLibConfig->libVersion) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Library version does not match header files. EAS Header Version %d.%d.%d.%d\n", + LIB_VERSION >> 24, + (LIB_VERSION >> 16) & 0x0f, + (LIB_VERSION >> 8) & 0x0f, + LIB_VERSION & 0x0f); */ } + return EAS_FALSE; + } + return EAS_TRUE; +} /* end EASLibraryCheck */ + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_report.c b/common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_report.c new file mode 100755 index 0000000..04a828c --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_report.c @@ -0,0 +1,264 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_report.c + * + * Contents and purpose: + * This file contains the debug message handling routines for the EAS library. + * These routines should be modified as needed for your system. + * + * Copyright 2005 Sonic Network Inc. + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 659 $ + * $Date: 2007-04-24 13:36:35 -0700 (Tue, 24 Apr 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifdef _lint +#include "lint_stdlib.h" +#else +#include +#include +#include +#endif + +#include "eas_report.h" + +static int severityLevel = 9999; + +/* debug file */ +static FILE *debugFile = NULL; +int flush = 0; + +#ifndef _NO_DEBUG_PREPROCESSOR + +/* structure should have an #include for each error message header file */ +S_DEBUG_MESSAGES debugMessages[] = +{ +#ifndef UNIFIED_DEBUG_MESSAGES +#include "eas_config_msgs.h" + + +#include "eas_host_msgs.h" +#include "eas_hostmm_msgs.h" +#include "eas_math_msgs.h" +#include "eas_midi_msgs.h" +#include "eas_mixer_msgs.h" +#include "eas_pcm_msgs.h" +#include "eas_public_msgs.h" +#include "eas_smf_msgs.h" +#include "eas_wave_msgs.h" +#include "eas_voicemgt_msgs.h" + +#ifdef _FM_SYNTH +#include "eas_fmsynth_msgs.h" +#include "eas_fmengine_msgs.h" +#endif + +#ifdef _WT_SYNTH +#include "eas_wtsynth_msgs.h" +#include "eas_wtengine_msgs.h" +#endif + +#ifdef _ARM_TEST_MAIN +#include "arm_main_msgs.h" +#endif + +#ifdef _EAS_MAIN +#include "eas_main_msgs.h" +#endif + +#ifdef _EAS_MAIN_IPC +#include "eas_main_ipc_msgs.h" +#endif + +#ifdef _METRICS_ENABLED +#include "eas_perf_msgs.h" +#endif + +#ifdef _COMPRESSOR_ENABLED +#include "eas_compressor_msgs.h" +#endif + +#ifdef _ENHANCER_ENABLED +#include "eas_enhancer_msgs.h" +#endif + +#ifdef _WOW_ENABLED +#include "eas_wow_msgs.h" +#endif + +#ifdef _SMAF_PARSER +#include "eas_smaf_msgs.h" +#endif + +#ifdef _OTA_PARSER +#include "eas_ota_msgs.h" +#endif + +#ifdef _IMELODY_PARSER +#include "eas_imelody_msgs.h" +#endif + +#ifdef _WAVE_PARSER +#include "eas_wavefile_msgs.h" +#endif + +#if defined(_CMX_PARSER) || defined(_MFI_PARSER) +#include "eas_cmf_msgs.h" +#endif + +#if defined(_CMX_PARSER) || defined(_MFI_PARSER) || defined(_WAVE_PARSER) +#include "eas_imaadpcm_msgs.h" +#endif + +#else +#include "eas_debugmsgs.h" +#endif + +/* denotes end of error messages */ +{ 0,0,0 } +}; + +/*---------------------------------------------------------------------------- + * EAS_ReportEx() + * + * This is the error message handler. The default handler outputs error + * messages to stdout. Modify this as needed for your system. + *---------------------------------------------------------------------------- +*/ +void EAS_ReportEx (int severity, unsigned long hashCode, int serialNum, ...) +{ + va_list vargs; + int i; + + /* check severity level */ + if (severity > severityLevel) + return; + + /* find the error message and output to stdout */ + /*lint -e{661} we check for NULL pointer - no fence post error here */ + for (i = 0; debugMessages[i].m_pDebugMsg; i++) + { + if ((debugMessages[i].m_nHashCode == hashCode) && + (debugMessages[i].m_nSerialNum == serialNum)) + { + /*lint -e{826} */ + va_start(vargs, serialNum); + if (debugFile) + { + vfprintf(debugFile, debugMessages[i].m_pDebugMsg, vargs); + if (flush) + fflush(debugFile); + } + else + { + vprintf(debugMessages[i].m_pDebugMsg, vargs); + } + va_end(vargs); + return; + } + } + printf("Unrecognized error: Severity=%d; HashCode=%lu; SerialNum=%d\n", severity, hashCode, serialNum); +} /* end EAS_ReportEx */ + +#else +/*---------------------------------------------------------------------------- + * EAS_Report() + * + * This is the error message handler. The default handler outputs error + * messages to stdout. Modify this as needed for your system. + *---------------------------------------------------------------------------- +*/ +void EAS_Report (int severity, const char *fmt, ...) +{ + va_list vargs; + + /* check severity level */ + if (severity > severityLevel) + return; + + /*lint -e{826} */ + va_start(vargs, fmt); + if (debugFile) + { + vfprintf(debugFile, fmt, vargs); + if (flush) + fflush(debugFile); + } + else + { + vprintf(fmt, vargs); + } + va_end(vargs); +} /* end EAS_Report */ + +/*---------------------------------------------------------------------------- + * EAS_ReportX() + * + * This is the error message handler. The default handler outputs error + * messages to stdout. Modify this as needed for your system. + *---------------------------------------------------------------------------- +*/ +void EAS_ReportX (int severity, const char *fmt, ...) +{ + va_list vargs; + + /* check severity level */ + if (severity > severityLevel) + return; + + /*lint -e{826} */ + va_start(vargs, fmt); + if (debugFile) + { + vfprintf(debugFile, fmt, vargs); + if (flush) + fflush(debugFile); + } + else + { + vprintf(fmt, vargs); + } + va_end(vargs); +} /* end EAS_ReportX */ +#endif + +/*---------------------------------------------------------------------------- + * EAS_SetDebugLevel() + * + * Sets the level for debug message output + *---------------------------------------------------------------------------- +*/ + +void EAS_SetDebugLevel (int severity) +{ + severityLevel = severity; +} /* end EAS_SetDebugLevel */ + +/*---------------------------------------------------------------------------- + * EAS_SetDebugFile() + * + * Redirect debugger output to the specified file. + *---------------------------------------------------------------------------- +*/ +void EAS_SetDebugFile (void *file, int flushAfterWrite) +{ + debugFile = (FILE*) file; + flush = flushAfterWrite; +} /* end EAS_SetDebugFile */ + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_report.h b/common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_report.h new file mode 100755 index 0000000..b603b12 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_report.h @@ -0,0 +1,77 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_report.h + * + * Contents and purpose: + * This file contains the debug message handling routines for the EAS library. + * These routines should be modified as needed for your system. + * + * DO NOT MODIFY THIS FILE! + * + * Copyright 2005 Sonic Network Inc. + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +/* sentinel */ +#ifndef _EAS_REPORT_H +#define _EAS_REPORT_H + +#define _EAS_SEVERITY_NOFILTER 0 +#define _EAS_SEVERITY_FATAL 1 +#define _EAS_SEVERITY_ERROR 2 +#define _EAS_SEVERITY_WARNING 3 +#define _EAS_SEVERITY_INFO 4 +#define _EAS_SEVERITY_DETAIL 5 + +/* for C++ linkage */ +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _NO_DEBUG_PREPROCESSOR + +/* structure for included debug message header files */ +typedef struct +{ + unsigned long m_nHashCode; + int m_nSerialNum; + char *m_pDebugMsg; +} S_DEBUG_MESSAGES; + +/* debug message handling prototypes */ +extern void EAS_ReportEx (int severity, unsigned long hashCode, int serialNum, ...); + +#else + +/* these prototypes are used if the debug preprocessor is not used */ +extern void EAS_Report (int severity, const char* fmt, ...); +extern void EAS_ReportX (int severity, const char* fmt, ...); + +#endif + +extern void EAS_SetDebugLevel (int severity); +extern void EAS_SetDebugFile (void *file, int flushAfterWrite); + +#ifdef __cplusplus +} /* end extern "C" */ +#endif + +#endif diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_reverb.h b/common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_reverb.h new file mode 100755 index 0000000..559abed --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_reverb.h @@ -0,0 +1,54 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_reverb.h + * + * Contents and purpose: + * Contains parameter enumerations for the Reverb effect + * + * + * Copyright Sonic Network Inc. 2006 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 300 $ + * $Date: 2006-09-11 17:37:20 -0700 (Mon, 11 Sep 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_REVERB_H +#define _EAS_REVERB_H + + +/* enumerated parameter settings for Reverb effect */ +typedef enum +{ + EAS_PARAM_REVERB_BYPASS, + EAS_PARAM_REVERB_PRESET, + EAS_PARAM_REVERB_WET, + EAS_PARAM_REVERB_DRY +} E_REVERB_PARAMS; + + +typedef enum +{ + EAS_PARAM_REVERB_LARGE_HALL, + EAS_PARAM_REVERB_HALL, + EAS_PARAM_REVERB_CHAMBER, + EAS_PARAM_REVERB_ROOM, +} E_REVERB_PRESETS; + + +#endif /* _REVERB_H */ diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_types.h b/common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_types.h new file mode 100755 index 0000000..45fa4b2 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_types.h @@ -0,0 +1,268 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_types.h + * + * Contents and purpose: + * The public interface header for the EAS synthesizer. + * + * This header only contains declarations that are specific + * to this implementation. + * + * DO NOT MODIFY THIS FILE! + * + * Copyright Sonic Network Inc. 2004 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 726 $ + * $Date: 2007-06-14 23:10:46 -0700 (Thu, 14 Jun 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_TYPES_H +#define _EAS_TYPES_H + +/* EAS_RESULT return codes */ +typedef long EAS_RESULT; +#define EAS_SUCCESS 0 +#define EAS_FAILURE -1 +#define EAS_ERROR_INVALID_MODULE -2 +#define EAS_ERROR_MALLOC_FAILED -3 +#define EAS_ERROR_FILE_POS -4 +#define EAS_ERROR_INVALID_FILE_MODE -5 +#define EAS_ERROR_FILE_SEEK -6 +#define EAS_ERROR_FILE_LENGTH -7 +#define EAS_ERROR_NOT_IMPLEMENTED -8 +#define EAS_ERROR_CLOSE_FAILED -9 +#define EAS_ERROR_FILE_OPEN_FAILED -10 +#define EAS_ERROR_INVALID_HANDLE -11 +#define EAS_ERROR_NO_MIX_BUFFER -12 +#define EAS_ERROR_PARAMETER_RANGE -13 +#define EAS_ERROR_MAX_FILES_OPEN -14 +#define EAS_ERROR_UNRECOGNIZED_FORMAT -15 +#define EAS_BUFFER_SIZE_MISMATCH -16 +#define EAS_ERROR_FILE_FORMAT -17 +#define EAS_ERROR_SMF_NOT_INITIALIZED -18 +#define EAS_ERROR_LOCATE_BEYOND_END -19 +#define EAS_ERROR_INVALID_PCM_TYPE -20 +#define EAS_ERROR_MAX_PCM_STREAMS -21 +#define EAS_ERROR_NO_VOICE_ALLOCATED -22 +#define EAS_ERROR_INVALID_CHANNEL -23 +#define EAS_ERROR_ALREADY_STOPPED -24 +#define EAS_ERROR_FILE_READ_FAILED -25 +#define EAS_ERROR_HANDLE_INTEGRITY -26 +#define EAS_ERROR_MAX_STREAMS_OPEN -27 +#define EAS_ERROR_INVALID_PARAMETER -28 +#define EAS_ERROR_FEATURE_NOT_AVAILABLE -29 +#define EAS_ERROR_SOUND_LIBRARY -30 +#define EAS_ERROR_NOT_VALID_IN_THIS_STATE -31 +#define EAS_ERROR_NO_VIRTUAL_SYNTHESIZER -32 +#define EAS_ERROR_FILE_ALREADY_OPEN -33 +#define EAS_ERROR_FILE_ALREADY_CLOSED -34 +#define EAS_ERROR_INCOMPATIBLE_VERSION -35 +#define EAS_ERROR_QUEUE_IS_FULL -36 +#define EAS_ERROR_QUEUE_IS_EMPTY -37 +#define EAS_ERROR_FEATURE_ALREADY_ACTIVE -38 + +/* special return codes */ +#define EAS_EOF 3 +#define EAS_STREAM_BUFFERING 4 +#define EAS_BUFFER_FULL 5 + +/* EAS_STATE return codes */ +typedef long EAS_STATE; +typedef enum +{ + EAS_STATE_READY = 0, + EAS_STATE_PLAY, + EAS_STATE_STOPPING, + EAS_STATE_PAUSING, + EAS_STATE_STOPPED, + EAS_STATE_PAUSED, + EAS_STATE_OPEN, + EAS_STATE_ERROR, + EAS_STATE_EMPTY +} E_EAS_STATE; + +/* constants */ +#ifndef EAS_CONST +#define EAS_CONST const +#endif + +/* definition for public interface functions */ +#ifndef EAS_PUBLIC +#define EAS_PUBLIC +#endif + +/* boolean values */ +typedef unsigned EAS_BOOL; +typedef unsigned char EAS_BOOL8; + +#define EAS_FALSE 0 +#define EAS_TRUE 1 + +/* scalar variable definitions */ +typedef unsigned char EAS_U8; +typedef signed char EAS_I8; +typedef char EAS_CHAR; + +typedef unsigned short EAS_U16; +typedef short EAS_I16; + +typedef unsigned long EAS_U32; +typedef long EAS_I32; + +typedef unsigned EAS_UINT; +typedef int EAS_INT; +typedef long EAS_LONG; + +/* audio output type */ +typedef short EAS_PCM; + +/* file open modes */ +typedef EAS_I32 EAS_FILE_MODE; +#define EAS_FILE_READ 1 +#define EAS_FILE_WRITE 2 + +/* file locator e.g. filename or memory pointer */ +typedef const void *EAS_FILE_LOCATOR; + +/* handle to stream */ +typedef struct s_eas_stream_tag *EAS_HANDLE; + +/* handle to file */ +typedef struct eas_hw_file_tag *EAS_FILE_HANDLE; + +/* handle for synthesizer data */ +typedef struct s_eas_data_tag *EAS_DATA_HANDLE; + +/* handle to persistent data for host wrapper interface */ +typedef struct eas_hw_inst_data_tag *EAS_HW_DATA_HANDLE; + +/* handle to sound library */ +typedef struct s_eas_sndlib_tag *EAS_SNDLIB_HANDLE; +typedef struct s_eas_dls_tag *EAS_DLSLIB_HANDLE; + +/* pointer to frame buffer - used in split architecture only */ +typedef struct s_eas_frame_buffer_tag *EAS_FRAME_BUFFER_HANDLE; + +/* untyped pointer for instance data */ +typedef void *EAS_VOID_PTR; + +/* inline functions */ +#ifndef EAS_INLINE +#if defined (__XCC__) +#define EAS_INLINE __inline__ +#elif defined (__GNUC__) +#define EAS_INLINE inline static +#else +#define EAS_INLINE __inline +#endif +#endif + +/* define NULL value */ +#ifndef NULL +#define NULL 0 +#endif + +/* metadata types for metadata return codes */ +typedef enum +{ + EAS_METADATA_UNKNOWN = 0, + EAS_METADATA_TITLE, + EAS_METADATA_AUTHOR, + EAS_METADATA_COPYRIGHT, + EAS_METADATA_LYRIC, + EAS_METADATA_TEXT +} E_EAS_METADATA_TYPE; + +/* metadata callback function */ +typedef void (*EAS_METADATA_CBFUNC) (E_EAS_METADATA_TYPE metaDataType, char *metaDataBuf, EAS_VOID_PTR pUserData); + +/* file types for metadata return codes */ +typedef enum +{ + EAS_FILE_UNKNOWN = 0, + EAS_FILE_SMF0, + EAS_FILE_SMF1, + EAS_FILE_SMAF_UNKNOWN, + EAS_FILE_SMAF_MA2, + EAS_FILE_SMAF_MA3, + EAS_FILE_SMAF_MA5, + EAS_FILE_CMX, + EAS_FILE_MFI, + EAS_FILE_OTA, + EAS_FILE_IMELODY, + EAS_FILE_RTTTL, + EAS_FILE_XMF0, + EAS_FILE_XMF1, + EAS_FILE_WAVE_PCM, + EAS_FILE_WAVE_IMA_ADPCM, + EAS_FILE_MMAPI_TONE_CONTROL +} E_EAS_FILE_TYPE; + +/* enumeration for synthesizers */ +typedef enum +{ + EAS_MCU_SYNTH = 0, + EAS_DSP_SYNTH +} E_SYNTHESIZER; + +/* external audio callback program change */ +typedef struct s_ext_audio_prg_chg_tag +{ + EAS_U16 bank; + EAS_U8 program; + EAS_U8 channel; +} S_EXT_AUDIO_PRG_CHG; + +/* external audio callback event */ +typedef struct s_ext_audio_event_tag +{ + EAS_U8 channel; + EAS_U8 note; + EAS_U8 velocity; + EAS_BOOL8 noteOn; +} S_EXT_AUDIO_EVENT; + +typedef struct s_midi_controllers_tag +{ + EAS_U8 modWheel; /* CC1 */ + EAS_U8 volume; /* CC7 */ + EAS_U8 pan; /* CC10 */ + EAS_U8 expression; /* CC11 */ + EAS_U8 channelPressure; /* MIDI channel pressure */ + +#ifdef _REVERB + EAS_U8 reverbSend; /* CC91 */ +#endif + +#ifdef _CHORUS + EAS_U8 chorusSend; /* CC93 */ +#endif +} S_MIDI_CONTROLLERS; + +/* iMode play modes enumeration for EAS_SetPlayMode */ +typedef enum +{ + IMODE_PLAY_ALL = 0, + IMODE_PLAY_PARTIAL +} E_I_MODE_PLAY_MODE; + +typedef EAS_BOOL (*EAS_EXT_PRG_CHG_FUNC) (EAS_VOID_PTR pInstData, S_EXT_AUDIO_PRG_CHG *pPrgChg); +typedef EAS_BOOL (*EAS_EXT_EVENT_FUNC) (EAS_VOID_PTR pInstData, S_EXT_AUDIO_EVENT *pEvent); + +#endif /* #ifndef _EAS_TYPES_H */ diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_wave.c b/common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_wave.c new file mode 100755 index 0000000..4f6ffbd --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_wave.c @@ -0,0 +1,423 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_wave.c + * + * Contents and purpose: + * This module contains .WAV file functions for the EAS synthesizer + * test harness. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 658 $ + * $Date: 2007-04-24 13:35:49 -0700 (Tue, 24 Apr 2007) $ + *---------------------------------------------------------------------------- +*/ + +/* lint complaints about most C library headers, so we use our own during lint step */ +#ifdef _lint +#include "lint_stdlib.h" +#else +#include +#include +#endif + +#include "eas_wave.h" + +/* .WAV file format tags */ +const EAS_U32 riffTag = 0x46464952; +const EAS_U32 waveTag = 0x45564157; +const EAS_U32 fmtTag = 0x20746d66; +const EAS_U32 dataTag = 0x61746164; + +#ifdef _BIG_ENDIAN +/*---------------------------------------------------------------------------- + * FlipDWord() + *---------------------------------------------------------------------------- + * Purpose: Endian flip a DWORD for big-endian processors + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static void FlipDWord (EAS_U32 *pValue) +{ + EAS_U8 *p; + EAS_U32 temp; + + p = (EAS_U8*) pValue; + temp = (((((p[3] << 8) | p[2]) << 8) | p[1]) << 8) | p[0]; + *pValue = temp; +} + +/*---------------------------------------------------------------------------- + * FlipWord() + *---------------------------------------------------------------------------- + * Purpose: Endian flip a WORD for big-endian processors + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static void FlipWord (EAS_U16 *pValue) +{ + EAS_U8 *p; + EAS_U16 temp; + + p = (EAS_U8*) pValue; + temp = (p[1] << 8) | p[0]; + *pValue = temp; +} + +/*---------------------------------------------------------------------------- + * FlipWaveHeader() + *---------------------------------------------------------------------------- + * Purpose: Endian flip the wave header for big-endian processors + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static void FlipWaveHeader (WAVE_HEADER *p) +{ + + FlipDWord(&p->nRiffTag); + FlipDWord(&p->nRiffSize); + FlipDWord(&p->nWaveTag); + FlipDWord(&p->nFmtTag); + FlipDWord(&p->nFmtSize); + FlipDWord(&p->nDataTag); + FlipDWord(&p->nDataSize); + FlipWord(&p->fc.wFormatTag); + FlipWord(&p->fc.nChannels); + FlipDWord(&p->fc.nSamplesPerSec); + FlipDWord(&p->fc.nAvgBytesPerSec); + FlipWord(&p->fc.nBlockAlign); + FlipWord(&p->fc.wBitsPerSample); + +} +#endif + +/*---------------------------------------------------------------------------- + * WaveFileCreate() + *---------------------------------------------------------------------------- + * Purpose: Opens a wave file for writing and writes the header + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ + +WAVE_FILE *WaveFileCreate (const char *filename, EAS_I32 nChannels, EAS_I32 nSamplesPerSec, EAS_I32 wBitsPerSample) +{ + WAVE_FILE *wFile; + + /* allocate memory */ + wFile = malloc(sizeof(WAVE_FILE)); + if (!wFile) + return NULL; + wFile->write = EAS_TRUE; + + /* create the file */ + wFile->file = fopen(filename,"wb"); + if (!wFile->file) + { + free(wFile); + return NULL; + } + + /* initialize PCM format .WAV file header */ + wFile->wh.nRiffTag = riffTag; + wFile->wh.nRiffSize = sizeof(WAVE_HEADER) - 8; + wFile->wh.nWaveTag = waveTag; + wFile->wh.nFmtTag = fmtTag; + wFile->wh.nFmtSize = sizeof(FMT_CHUNK); + + /* initalize 'fmt' chunk */ + wFile->wh.fc.wFormatTag = 1; + wFile->wh.fc.nChannels = (EAS_U16) nChannels; + wFile->wh.fc.nSamplesPerSec = (EAS_U32) nSamplesPerSec; + wFile->wh.fc.wBitsPerSample = (EAS_U16) wBitsPerSample; + wFile->wh.fc.nBlockAlign = (EAS_U16) (nChannels * (EAS_U16) (wBitsPerSample / 8)); + wFile->wh.fc.nAvgBytesPerSec = wFile->wh.fc.nBlockAlign * (EAS_U32) nSamplesPerSec; + + /* initialize 'data' chunk */ + wFile->wh.nDataTag = dataTag; + wFile->wh.nDataSize = 0; + +#ifdef _BIG_ENDIAN + FlipWaveHeader(&wFile->wh); +#endif + + /* write the header */ + if (fwrite(&wFile->wh, sizeof(WAVE_HEADER), 1, wFile->file) != 1) + { + fclose(wFile->file); + free(wFile); + return NULL; + } + +#ifdef _BIG_ENDIAN + FlipWaveHeader(&wFile->wh); +#endif + + /* return the file handle */ + return wFile; +} /* end WaveFileCreate */ + +/*---------------------------------------------------------------------------- + * WaveFileWrite() + *---------------------------------------------------------------------------- + * Purpose: Writes data to the wave file + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_I32 WaveFileWrite (WAVE_FILE *wFile, void *buffer, EAS_I32 n) +{ + EAS_I32 count; + + /* make sure we have an open file */ + if (wFile == NULL) + { + return 0; + } + +#ifdef _BIG_ENDIAN + { + EAS_I32 i; + EAS_U16 *p; + p = buffer; + i = n >> 1; + while (i--) + FlipWord(p++); + } +#endif + + /* write the data */ + count = (EAS_I32) fwrite(buffer, 1, (size_t) n, wFile->file); + + /* add the number of bytes written */ + wFile->wh.nRiffSize += (EAS_U32) count; + wFile->wh.nDataSize += (EAS_U32) count; + + /* return the count of bytes written */ + return count; +} /* end WriteWaveHeader */ + +/*---------------------------------------------------------------------------- + * WaveFileClose() + *---------------------------------------------------------------------------- + * Purpose: Opens a wave file for writing and writes the header + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ + +EAS_BOOL WaveFileClose (WAVE_FILE *wFile) +{ + EAS_I32 count = 1; + + /* return to beginning of file and write the header */ + if (wFile->write) + { + if (fseek(wFile->file, 0L, SEEK_SET) == 0) + { + +#ifdef _BIG_ENDIAN + FlipWaveHeader(&wFile->wh); +#endif + count = (EAS_I32) fwrite(&wFile->wh, sizeof(WAVE_HEADER), 1, wFile->file); +#ifdef _BIG_ENDIAN + FlipWaveHeader(&wFile->wh); +#endif + } + } + + /* close the file */ + if (fclose(wFile->file) != 0) + count = 0; + + /* free the memory */ + free(wFile); + + /* return the file handle */ + return (count == 1 ? EAS_TRUE : EAS_FALSE); +} /* end WaveFileClose */ + +#ifdef _WAVE_FILE_READ +#ifdef _BIG_ENDIAN +#error "WaveFileOpen not currently supported on big-endian processors" +#endif +/*---------------------------------------------------------------------------- + * WaveFileOpen() + *---------------------------------------------------------------------------- + * Purpose: Opens a wave file for reading and reads the header + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ + +WAVE_FILE *WaveFileOpen (const char *filename) +{ + WAVE_FILE *wFile; + struct + { + EAS_U32 tag; + EAS_U32 size; + } chunk; + EAS_U32 tag; + EAS_I32 startChunkPos; + EAS_INT state; + EAS_BOOL done; + + /* allocate memory */ + wFile = malloc(sizeof(WAVE_FILE)); + if (!wFile) + return NULL; + + /* open the file */ + wFile->write = EAS_FALSE; + wFile->file = fopen(filename,"rb"); + if (!wFile->file) + { + free(wFile); + return NULL; + } + + /* make lint happy */ + chunk.tag = chunk.size = 0; + startChunkPos = 0; + + /* read the RIFF tag and file size */ + state = 0; + done = EAS_FALSE; + while (!done) + { + + switch(state) + { + /* read the RIFF tag */ + case 0: + if (fread(&chunk, sizeof(chunk), 1, wFile->file) != 1) + done = EAS_TRUE; + else + { + if (chunk.tag != riffTag) + done = EAS_TRUE; + else + state++; + } + break; + + /* read the WAVE tag */ + case 1: + if (fread(&tag, sizeof(tag), 1, wFile->file) != 1) + done = EAS_TRUE; + else + { + if (tag != waveTag) + done = EAS_TRUE; + else + state++; + } + break; + + /* looking for fmt chunk */ + case 2: + if (fread(&chunk, sizeof(chunk), 1, wFile->file) != 1) + done = EAS_TRUE; + else + { + startChunkPos = ftell(wFile->file); + + /* not fmt tag, skip it */ + if (chunk.tag != fmtTag) + fseek(wFile->file, startChunkPos + (EAS_I32) chunk.size, SEEK_SET); + else + state++; + } + break; + + /* read fmt chunk */ + case 3: + if (fread(&wFile->wh.fc, sizeof(FMT_CHUNK), 1, wFile->file) != 1) + done = EAS_TRUE; + else + { + fseek(wFile->file, startChunkPos + (EAS_I32) chunk.size, SEEK_SET); + state++; + } + break; + + /* looking for data chunk */ + case 4: + if (fread(&chunk, sizeof(chunk), 1, wFile->file) != 1) + done = EAS_TRUE; + else + { + startChunkPos = ftell(wFile->file); + + /* not data tag, skip it */ + if (chunk.tag != dataTag) + fseek(wFile->file, startChunkPos + (EAS_I32) chunk.size, SEEK_SET); + else + { + wFile->dataSize = chunk.size; + state++; + done = EAS_TRUE; + } + } + break; + + default: + done = EAS_TRUE; + break; + } + } + + /* if not final state, an error occurred */ + if (state != 5) + { + fclose(wFile->file); + free(wFile); + return NULL; + } + + /* return the file handle */ + return wFile; +} /* end WaveFileOpen */ +#endif + + + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_wave.h b/common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_wave.h new file mode 100755 index 0000000..968782f --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/host_src/eas_wave.h @@ -0,0 +1,74 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_wave.h + * + * Contents and purpose: + * Writes output to a .WAV file + * + * DO NOT MODIFY THIS FILE! + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_types.h" + +/* sentinel */ +#ifndef _EAS_WAVE_H +#define _EAS_WAVE_H + +/* .WAV file format chunk */ +typedef struct { + EAS_U16 wFormatTag; + EAS_U16 nChannels; + EAS_U32 nSamplesPerSec; + EAS_U32 nAvgBytesPerSec; + EAS_U16 nBlockAlign; + EAS_U16 wBitsPerSample; +} FMT_CHUNK; + +/* .WAV file header */ +typedef struct { + EAS_U32 nRiffTag; + EAS_U32 nRiffSize; + EAS_U32 nWaveTag; + EAS_U32 nFmtTag; + EAS_U32 nFmtSize; + FMT_CHUNK fc; + EAS_U32 nDataTag; + EAS_U32 nDataSize; +} WAVE_HEADER; + +typedef struct { + WAVE_HEADER wh; + FILE *file; + EAS_BOOL write; + EAS_U32 dataSize; +} WAVE_FILE; + +WAVE_FILE *WaveFileCreate (const char *filename, EAS_I32 nChannels, EAS_I32 nSamplesPerSec, EAS_I32 wBitsPerSample); +EAS_I32 WaveFileWrite (WAVE_FILE *wFile, void *buffer, EAS_I32 n); +EAS_BOOL WaveFileClose (WAVE_FILE *wFile); +WAVE_FILE *WaveFileOpen (const char *filename); + +#endif /* end #ifndef _EAS_WAVE_H */ + + + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib/libarm-hybrid-22k.a b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib/libarm-hybrid-22k.a new file mode 100755 index 0000000..f3999f0 Binary files /dev/null and b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib/libarm-hybrid-22k.a differ diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/ARM-E_filter_gnu.s b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/ARM-E_filter_gnu.s new file mode 100755 index 0000000..871cd7d --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/ARM-E_filter_gnu.s @@ -0,0 +1,134 @@ +@*********************************************************** +@ Function: WT_VoiceFilter +@ Processor: ARM +@ Description: +@ Implements a 2-pole low-pass filter with resonanance +@ +@ Usage: +@ void WT_VoiceFilter( +@ S_FILTER CONTROL *pFilter, +@ S_WT_FRAME *pWTFrame); +@ +@ Copyright 2005 Sonic Network, Inc. +@**************************************************************** +@ Revision Control: +@ $Revision: 496 $ +@ $Date: 2006-12-11 14:33:26 -0800 (Mon, 11 Dec 2006) $ +@**************************************************************** +@ +@ where: +@ S_FILTER_CONTROL *pFilter +@ PASSED IN: r0 +@ +@ S_WT_FRAME *pWTFrame +@ PASSED IN: r1 +@**************************************************************** + + .include "ARM_synth_constants_gnu.inc" + + .arm + .text + + + .global WT_VoiceFilter + + +@ Register usage +@ -------------- +pFilter .req r0 +pWTFrame .req r1 +pBuffer .req r2 +numSamples .req r3 + +z1 .req r4 +z2 .req r5 +b1 .req r6 +b2 .req r7 +K .req r8 + +tmp0 .req r1 @ reuse register +tmp1 .req r9 +tmp2 .req r10 + + +@SaveRegs RLIST {r4-r10, lr} +@RestoreRegs RLIST {r4-r10, pc} + + + .func WT_VoiceFilter +WT_VoiceFilter: + + STMFD sp!, {r4-r10, lr} + +@ +@ Setup passed parameters in their destination registers +@---------------------------------------------------------------- + + LDR pBuffer, [pWTFrame, #m_pAudioBuffer] + LDR numSamples, [pWTFrame, #m_numSamples] + + @load state variables from pFilter structure + LDRSH z1, [pFilter, #m_z1] + LDRSH z2, [pFilter, #m_z2] + + @load coefficients from pWTFrame structure + LDR K, [pWTFrame, #m_k] + LDR b1, [pWTFrame, #m_b1] + LDR b2, [pWTFrame, #m_b2] + + RSB b1, b1, #0 @ b1 = -b1 + RSB b2, b2, #0 @ b2 = -b2 + MOV b2, b2, ASR #1 @ b2 = b2 >> 1 + MOV K, K, ASR #1 @ K = K >> 1 + +@ +@ Start processing +@---------------------------------------------------------------- + + LDRSH tmp0, [pBuffer] @ fetch sample + +FilterLoop: + SMULBB tmp2, z1, b1 @ tmp2 = z1 * -b1 + SMLABB tmp2, z2, b2, tmp2 @ tmp2 = (-b1 * z1) + (-b2 * z2) + + MOV z2, z1 @ delay line + + SMLABB tmp0, tmp0, K, tmp2 @ tmp1 = (K * x[n]) + (-b1 * z1) + (-b2 * z2) + + LDRSH tmp1, [pBuffer, #NEXT_OUTPUT_PCM] @ fetch next sample + + MOV z1, tmp0, ASR #14 @ shift result to low word + STRH z1, [pBuffer], #NEXT_OUTPUT_PCM @ write back to buffer + + SMULBB tmp2, z1, b1 @ tmp2 = z1 * -b1 + + SUBS numSamples, numSamples, #2 @ unroll loop once + + SMLABB tmp2, z2, b2, tmp2 @ tmp2 = (-b1 * z1) + (-b2 * z2) + + SMLABB tmp1, tmp1, K, tmp2 @ tmp1 = (K * x[n]) + (-b1 * z1) + (-b2 * z2) + + MOV z2, z1 @ delay line + + MOV z1, tmp1, ASR #14 @ shift result to low word + + LDRGTSH tmp0, [pBuffer, #NEXT_OUTPUT_PCM] @ fetch next sample + + STRH z1, [pBuffer], #NEXT_OUTPUT_PCM @ write back to buffer + + BGT FilterLoop +@ save z terms +@---------------------------------------------------------------- + + STRH z1, [pFilter, #m_z1] + STRH z2, [pFilter, #m_z2] + +@ Return to calling function +@---------------------------------------------------------------- + + LDMFD sp!,{r4-r10, lr} + BX lr + + .endfunc + .end + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/ARM-E_interpolate_loop_gnu.s b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/ARM-E_interpolate_loop_gnu.s new file mode 100755 index 0000000..847a7f0 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/ARM-E_interpolate_loop_gnu.s @@ -0,0 +1,131 @@ +@*********************************************************** +@ Function: WT_Interpolate +@ Processor: ARM-E +@ Description: the main synthesis function when fetching +@ wavetable samples. +@ C-callable. +@ +@ Usage: +@ void WT_Interpolate( +@ S_WT_VOICE *pWTVoice, +@ S_WT_FRAME *pWTFrame); +@ +@ Copyright Sonic Network Inc. 2004 +@**************************************************************** +@ Revision Control: +@ $Revision: 496 $ +@ $Date: 2006-12-11 14:33:26 -0800 (Mon, 11 Dec 2006) $ +@**************************************************************** +@ +@ where: +@ S_WT_VOICE *pWTVoice +@ PASSED IN: r0 +@ +@ S_WT_FRAME *pWTFrame; +@ PASSED IN: r1 +@**************************************************************** + + .include "ARM_synth_constants_gnu.inc" + + .arm + .text + + .global WT_Interpolate + + +@ Register usage +@ -------------- +pWTVoice .req r0 +pWTFrame .req r1 + +numSamples .req r2 +phaseIncrement .req r3 +pOutputBuffer .req r4 + +tmp0 .req r1 @reuse register +tmp1 .req r5 +tmp2 .req r6 + +pLoopEnd .req r7 +pLoopStart .req r8 + +pPhaseAccum .req r9 +phaseFrac .req r10 +phaseFracMask .req r11 + +@SaveRegs RLIST {r4-r11,lr} +@RestoreRegs RLIST {r4-r11,pc} + + .func WT_Interpolate +WT_Interpolate: + + STMFD sp!,{r4-r11,lr} + +@ +@ Fetch parameters from structures +@---------------------------------------------------------------- + + LDR pOutputBuffer, [pWTFrame, #m_pAudioBuffer] + LDR numSamples, [pWTFrame, #m_numSamples] + + LDR phaseIncrement, [pWTFrame, #m_phaseIncrement] + LDR pPhaseAccum, [pWTVoice, #m_pPhaseAccum] + LDR phaseFrac, [pWTVoice, #m_phaseFrac] + LDR phaseFracMask,=PHASE_FRAC_MASK + + LDR pLoopStart, [pWTVoice, #m_pLoopStart] + LDR pLoopEnd, [pWTVoice, #m_pLoopEnd] + ADD pLoopEnd, pLoopEnd, #1 @ need loop end to equal last sample + 1 + +InterpolationLoop: + SUBS tmp0, pPhaseAccum, pLoopEnd @ check for loop end + ADDGE pPhaseAccum, pLoopStart, tmp0 @ loop back to start + + .ifdef SAMPLES_8_BIT + LDRSB tmp0, [pPhaseAccum] @ tmp0 = x0 + LDRSB tmp1, [pPhaseAccum, #1] @ tmp1 = x1 + .else + LDRSH tmp0, [pPhaseAccum] @ tmp0 = x0 + LDRSH tmp1, [pPhaseAccum, #2] @ tmp1 = x1 + .endif + + ADD tmp2, phaseIncrement, phaseFrac @ increment pointer here to avoid pipeline stall + + SUB tmp1, tmp1, tmp0 @ tmp1 = x1 - x0 + SMULBB tmp1, phaseFrac, tmp1 @ tmp1 = phaseFrac * tmp2 + +@ This section performs a gain adjustment of -12dB for 16-bit samples +@ or +36dB for 8-bit samples. For a high quality synthesizer, the output +@ can be set to full scale, however if the filter is used, it can overflow +@ with certain coefficients and signal sources. In this case, either a +@ saturation operation should take in the filter before scaling back to +@ 16 bits or the signal path should be increased to 18 bits or more. + + .ifdef SAMPLES_8_BIT + MOV tmp0, tmp0, LSL #6 @ boost 8-bit signal by 36dB + .else + MOV tmp0, tmp0, ASR #2 @ reduce 16-bit signal by 12dB + .endif + + ADD tmp1, tmp0, tmp1, ASR #(NUM_EG1_FRAC_BITS-6) @ tmp1 = tmp0 + (tmp1 >> (15-6)) + @ = x0 + f * (x1 - x0) == interpolated result + + STRH tmp1, [pOutputBuffer], #NEXT_OUTPUT_PCM @ *pOutputBuffer++ = interpolated result + +@ carry overflow from fraction to integer portion + ADD pPhaseAccum, pPhaseAccum, tmp2, LSR #(NUM_PHASE_FRAC_BITS - NEXT_INPUT_PCM_SHIFT) + AND phaseFrac, tmp2, phaseFracMask @ nphaseFrac = frac part + + SUBS numSamples, numSamples, #1 + BGT InterpolationLoop + +@ update and store phase + STR pPhaseAccum, [pWTVoice, #m_pPhaseAccum] + STR phaseFrac, [pWTVoice, #m_phaseFrac] + + LDMFD sp!,{r4-r11,lr} + BX lr + + .endfunc + .end + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/ARM-E_interpolate_noloop_gnu.s b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/ARM-E_interpolate_noloop_gnu.s new file mode 100755 index 0000000..6343762 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/ARM-E_interpolate_noloop_gnu.s @@ -0,0 +1,130 @@ +@*********************************************************** +@ Function: WT_InterpolateNoLoop +@ Processor: ARM-E +@ Description: the main synthesis function when fetching +@ wavetable samples. +@ C-callable. +@ +@ Usage: +@ void WT_InterpolateNoLoop( +@ S_WT_VOICE *pWTVoice, +@ S_WT_FRAME *pWTFrame); +@ +@ Copyright Sonic Network Inc. 2004 +@**************************************************************** +@ Revision Control: +@ $Revision: 496 $ +@ $Date: 2006-12-11 14:33:26 -0800 (Mon, 11 Dec 2006) $ +@**************************************************************** +@ +@ where: +@ S_WT_VOICE *pWTVoice +@ PASSED IN: r0 +@ +@ S_WT_FRAME *pWTFrame; +@ PASSED IN: r1 +@**************************************************************** + + .include "ARM_synth_constants_gnu.inc" + + .arm + .text + + + .global WT_InterpolateNoLoop + + +@ Register usage +@ -------------- +pWTVoice .req r0 +pWTFrame .req r1 +pOutputBuffer .req r2 +numSamples .req r3 + +phaseIncrement .req r4 +pPhaseAccum .req r5 +phaseFrac .req r6 +phaseFracMask .req r7 + +tmp0 .req r1 @ reuse register +tmp1 .req r8 +tmp2 .req r9 + + +@SaveRegs RLIST {r4-r9,lr} +@RestoreRegs RLIST {r4-r9,pc} + + .func WT_InterpolateNoLoop +WT_InterpolateNoLoop: + + STMFD sp!, {r4-r9,lr} + +@ +@ Fetch parameters from structures +@---------------------------------------------------------------- + + LDR pOutputBuffer, [pWTFrame, #m_pAudioBuffer] + LDR numSamples, [pWTFrame, #m_numSamples] + + LDR phaseIncrement, [pWTFrame, #m_phaseIncrement] + LDR pPhaseAccum, [pWTVoice, #m_pPhaseAccum] + LDR phaseFrac, [pWTVoice, #m_phaseFrac] + LDR phaseFracMask,=PHASE_FRAC_MASK + +InterpolationLoop: + + .ifdef SAMPLES_8_BIT + LDRSB tmp0, [pPhaseAccum] @ tmp0 = x0 + LDRSB tmp1, [pPhaseAccum, #1] @ tmp1 = x1 + .else + LDRSH tmp0, [pPhaseAccum] @ tmp0 = x0 + LDRSH tmp1, [pPhaseAccum, #2] @ tmp1 = x1 + .endif + + ADD tmp2, phaseIncrement, phaseFrac @ increment pointer here to avoid pipeline stall + + SUB tmp1, tmp1, tmp0 @ tmp1 = x1 - x0 + SMULBB tmp1, phaseFrac, tmp1 @ tmp1 = phaseFrac * tmp2 + +@ This section performs a gain adjustment of -12dB for 16-bit samples +@ or +36dB for 8-bit samples. For a high quality synthesizer, the output +@ can be set to full scale, however if the filter is used, it can overflow +@ with certain coefficients and signal sources. In this case, either a +@ saturation operation should take in the filter before scaling back to +@ 16 bits or the signal path should be increased to 18 bits or more. + + .ifdef SAMPLES_8_BIT + MOV tmp0, tmp0, LSL #6 @ boost 8-bit signal by 36dB + .else + MOV tmp0, tmp0, ASR #2 @ reduce 16-bit signal by 12dB + .endif + + ADD tmp1, tmp0, tmp1, ASR #(NUM_EG1_FRAC_BITS-6) @ tmp1 = tmp0 + (tmp1 >> (15-6)) + @ = x0 + f * (x1 - x0) == interpolated result + + STRH tmp1, [pOutputBuffer], #NEXT_OUTPUT_PCM @ *pOutputBuffer++ = interpolated result + +@ carry overflow from fraction to integer portion + ADD pPhaseAccum, pPhaseAccum, tmp2, LSR #(NUM_PHASE_FRAC_BITS - NEXT_INPUT_PCM_SHIFT) + AND phaseFrac, tmp2, phaseFracMask @ nphaseFrac = frac part + + SUBS numSamples, numSamples, #1 + BGT InterpolationLoop + +@ Clean up and store any changes that were caused during the loop +@---------------------------------------------------------------- + + @ update and store phase + STR pPhaseAccum, [pWTVoice, #m_pPhaseAccum] + STR phaseFrac, [pWTVoice, #m_phaseFrac] + +@ +@ Return to calling function +@---------------------------------------------------------------- + + LDMFD sp!,{r4-r9,lr} + BX lr + + .endfunc + .end + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/ARM-E_mastergain_gnu.s b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/ARM-E_mastergain_gnu.s new file mode 100755 index 0000000..b4e905b --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/ARM-E_mastergain_gnu.s @@ -0,0 +1,109 @@ +@*********************************************************** +@ Function: SynthMasterGain +@ Processor: ARM-E +@ Description: Copies 32-bit synth output to 16-bit buffer +@ with saturated gain control +@ C-callable. +@ +@ Usage: +@ SynthMasterGain( +@ pInputBuffer +@ pOutputBuffer, +@ nGain, +@ nNumLoopSamples +@ ); +@ +@ Copyright Sonic Network Inc. 2004 +@**************************************************************** +@ Revision Control: +@ $Revision: 496 $ +@ $Date: 2006-12-11 14:33:26 -0800 (Mon, 11 Dec 2006) $ +@**************************************************************** +@ +@ where: +@ long *pInputBuffer +@ PASSED IN: r0 +@ +@ EAS_PCM *pOutputBuffer +@ PASSED IN: r1 +@ +@ short nGain +@ PASSED IN: r2 +@ +@ EAS_U16 nNumLoopSamples +@ PASSED IN: r3 +@ +@**************************************************************** + + .include "ARM_synth_constants_gnu.inc" + + .arm + .text + + .func SynthMasterGain +SynthMasterGain: + + .global SynthMasterGain @ allow other files to use this function + + + + + +@ Stack frame +@ ----------- + .equ RET_ADDR_SZ, 0 @return address + .equ REG_SAVE_SZ, 0 @save-on-entry registers saved + .equ FRAME_SZ, (8) @local variables + .equ ARG_BLK_SZ, 0 @argument block + + .equ PARAM_OFFSET, (ARG_BLK_SZ + FRAME_SZ + REG_SAVE_SZ + RET_ADDR_SZ) + +@ Register usage +@ -------------- +pnInputBuffer .req r0 +pnOutputBuffer .req r1 +nGain .req r2 +nNumLoopSamples .req r3 + + STMFD sp!,{r4-r6,r14} @Save any save-on-entry registers that are used + + LDR r6, =0x7fff @constant for saturation tests + +loop: + LDR r4, [pnInputBuffer], #4 @fetch 1st output sample + + LDR r5, [pnInputBuffer], #4 @fetch 2nd output sample + + SMULWB r4, r4, nGain @output = gain * input + + CMP r4, r6 @check for positive saturation + MOVGT r4, r6 @saturate + CMN r4, r6 @check for negative saturation + MVNLT r4, r6 @saturate + + SMULWB r5, r5, nGain @output = gain * input + + STRH r4, [pnOutputBuffer], #NEXT_OUTPUT_PCM @save 1st output sample + + CMP r5, r6 @check for positive saturation + MOVGT r5, r6 @saturate + CMN r5, r6 @check for negative saturation + MVNLT r5, r6 @saturate + STRH r5, [pnOutputBuffer], #NEXT_OUTPUT_PCM @save 2nd output sample + + SUBS nNumLoopSamples, nNumLoopSamples, #2 + BGT loop + +@ +@ Return to calling function +@---------------------------------------------------------------- + + LDMFD sp!,{r4-r6, lr} @ return to calling function + BX lr + +@***************************************************************************** + + .endfunc @ end of function/procedure + + .end @ end of assembly code + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/ARM-E_voice_gain_gnu.s b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/ARM-E_voice_gain_gnu.s new file mode 100755 index 0000000..4517a3d --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/ARM-E_voice_gain_gnu.s @@ -0,0 +1,166 @@ +@*********************************************************** +@ Function: WT_VoiceGain +@ Processor: ARM-E +@ Description: the main synthesis function when fetching +@ wavetable samples. +@ C-callable. +@ +@ Usage: +@ Usage: +@ WT_VoiceGain( +@ S_WT_VOICE *pWTVoice, +@ S_WT_FRAME *pWTFrame); +@ +@ Copyright 2004, 2005 Sonic Network, Inc. +@**************************************************************** +@ Revision Control: +@ $Revision: 814 $ +@ $Date: 2007-08-02 10:34:53 -0700 (Thu, 02 Aug 2007) $ +@**************************************************************** +@ +@ where: +@ S_WT_VOICE *psVoice +@ PASSED IN: r0 +@ +@ S_WT_FRAME *pWTFrame +@ PASSED IN: r1 +@**************************************************************** + + + + .include "ARM_synth_constants_gnu.inc" + + .arm + .text + + .global WT_VoiceGain + +@ Register usage +@ -------------- +pWTVoice .req r0 +pWTFrame .req r1 +pInputBuffer .req r2 +pMixBuffer .req r3 + +tmp0 .req r4 +tmp1 .req r5 +tmp2 .req r1 @ reuse register +tmp3 .req r6 + +numSamples .req r9 + + .if STEREO_OUTPUT +gainIncLeft .req r7 +gainIncRight .req r8 +gainLeft .req r10 +gainRight .req r11 + .else +gainIncrement .req r7 +gain .req r8 + .endif + + +@ register context for local variables +@SaveRegs RLIST {r4-r11,lr} +@RestoreRegs RLIST {r4-r11,pc} + + .func WT_VoiceGain +WT_VoiceGain: + + STMFD sp!, {r4-r11,lr} + + LDR pInputBuffer, [pWTFrame, #m_pAudioBuffer] + LDR pMixBuffer, [pWTFrame, #m_pMixBuffer] + LDR numSamples, [pWTFrame, #m_numSamples] + +@---------------------------------------------------------------- +@ Stereo version +@---------------------------------------------------------------- +@ NOTE: instructions are reordered to reduce the effect of latency +@ due to storage and computational dependencies. +@---------------------------------------------------------------- + + .if STEREO_OUTPUT + + LDR tmp0, [pWTFrame, #m_prevGain] + LDR tmp1, [pWTFrame, #m_gainTarget] + + LDRSH gainLeft, [pWTVoice, #m_gainLeft] + LDRSH gainRight, [pWTVoice, #m_gainRight] + + MOV gainIncLeft, gainLeft + SMULBB gainLeft, tmp0, gainLeft + + SMULBB gainIncLeft, tmp1, gainIncLeft + SUB gainIncLeft, gainIncLeft, gainLeft + MOV gainLeft, gainLeft, ASR #(NUM_MIXER_GUARD_BITS - 2) + MOV gainIncLeft, gainIncLeft, ASR #(SYNTH_UPDATE_PERIOD_IN_BITS + NUM_MIXER_GUARD_BITS - 2) + + MOV gainIncRight, gainRight + SMULBB gainRight, tmp0, gainRight + + SMULBB gainIncRight, tmp1, gainIncRight + SUB gainIncRight, gainIncRight, gainRight + MOV gainRight, gainRight, ASR #(NUM_MIXER_GUARD_BITS - 2) + MOV gainIncRight, gainIncRight, ASR #(SYNTH_UPDATE_PERIOD_IN_BITS + NUM_MIXER_GUARD_BITS - 2) + + LDRSH tmp0, [pInputBuffer], #2 + +StereoGainLoop: + LDR tmp1, [pMixBuffer] + + ADD gainLeft, gainLeft, gainIncLeft + + SMLAWB tmp1, gainLeft, tmp0, tmp1 + + LDR tmp2, [pMixBuffer, #4] + + ADD gainRight, gainRight, gainIncRight + + STR tmp1, [pMixBuffer], #4 + + SMLAWB tmp2, gainRight, tmp0, tmp2 + + SUBS numSamples, numSamples, #1 + + LDRGTSH tmp0, [pInputBuffer], #2 + + STR tmp2, [pMixBuffer], #4 + + BGT StereoGainLoop + +@---------------------------------------------------------------- +@ Mono version +@---------------------------------------------------------------- + .else + + LDR gain, [pWTFrame, #m_prevGain] + MOV gain, gain, LSL #(NUM_MIXER_GUARD_BITS + 4) + LDR gainIncrement, [pWTFrame, #m_gainTarget] + MOV gainIncrement, gainIncrement, LSL #(NUM_MIXER_GUARD_BITS + 4) + SUB gainIncrement, gainIncrement, gain + MOV gainIncrement, gainIncrement, ASR #SYNTH_UPDATE_PERIOD_IN_BITS + +MonoGainLoop: + + LDRSH tmp0, [pInputBuffer], #NEXT_OUTPUT_PCM @ fetch voice output + + LDR tmp1, [pMixBuffer] @ get left channel output sample + ADD gain, gain, gainIncrement @ gain step to eliminate zipper noise + SMULWB tmp0, gain, tmp0 @ sample * local gain + + MOV tmp0, tmp0, ASR #1 @ add 6dB headroom + ADD tmp1, tmp0, tmp1 + STR tmp1, [pMixBuffer], #4 @ save and bump pointer + + SUBS numSamples, numSamples, #1 + BGT MonoGainLoop + + .endif @end Mono version + + LDMFD sp!,{r4-r11,lr} + BX lr + + .endfunc + .end + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/ARM_synth_constants_gnu.inc b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/ARM_synth_constants_gnu.inc new file mode 100755 index 0000000..c0f8df3 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/ARM_synth_constants_gnu.inc @@ -0,0 +1,153 @@ +@*********************************************************** +@ File: ARM_synth_constants.inc +@ Processor: ARM +@ Description: Contains constants and defines, most of which +@ are mirrored in synth.h +@ +@ Copyright Sonic Network Inc. 2004 +@**************************************************************** +@ Revision Control: +@ $Revision: 741 $ +@ $Date: 2007-06-22 16:39:21 -0700 (Fri, 22 Jun 2007) $ +@**************************************************************** + + + .ifdef SAMPLE_RATE_8000 + .equ SYNTH_UPDATE_PERIOD_IN_BITS, 5 + .equ BUFFER_SIZE_IN_MONO_SAMPLES, 32 + .endif + + .ifdef SAMPLE_RATE_16000 + .equ SYNTH_UPDATE_PERIOD_IN_BITS, 6 + .equ BUFFER_SIZE_IN_MONO_SAMPLES, 64 + .endif + + .ifdef SAMPLE_RATE_20000 + .equ SYNTH_UPDATE_PERIOD_IN_BITS, 7 + .equ BUFFER_SIZE_IN_MONO_SAMPLES, 128 + .endif + + .ifdef SAMPLE_RATE_22050 + .equ SYNTH_UPDATE_PERIOD_IN_BITS, 7 + .equ BUFFER_SIZE_IN_MONO_SAMPLES, 128 + .endif + + .ifdef SAMPLE_RATE_24000 + .equ SYNTH_UPDATE_PERIOD_IN_BITS, 7 + .equ BUFFER_SIZE_IN_MONO_SAMPLES, 128 + .endif + + .ifdef SAMPLE_RATE_32000 + .equ SYNTH_UPDATE_PERIOD_IN_BITS, 7 + .equ BUFFER_SIZE_IN_MONO_SAMPLES, 128 + .endif + + .ifdef SAMPLE_RATE_44100 + .equ SYNTH_UPDATE_PERIOD_IN_BITS, 8 + .equ BUFFER_SIZE_IN_MONO_SAMPLES, 256 + .endif + + .ifdef SAMPLE_RATE_48000 + .equ SYNTH_UPDATE_PERIOD_IN_BITS, 8 + .equ BUFFER_SIZE_IN_MONO_SAMPLES, 256 + .endif + + +@ if the OUTPUT PCM sample is 16-bits, then when using indexed addressing, +@ the next sample is this many bytes away + .equ NEXT_OUTPUT_PCM, 2 + +@**************************************************************************** +@/* macros for fractional phase accumulator */ + .equ NUM_PHASE_FRAC_BITS, 15 + + .equ PHASE_FRAC_MASK, 0x7FFF + +@ shift for phase accumulator when fraction carries over + .ifdef SAMPLES_8_BIT + .equ NEXT_INPUT_PCM_SHIFT, 0 + .endif + + .ifdef SAMPLES_16_BIT + .equ NEXT_INPUT_PCM_SHIFT, 1 + .endif + +@**************************************************************************** + .equ NUM_MIXER_GUARD_BITS, 4 + +@**************************************************************************** +@/* Envelope 1 (EG1) calculation macros */ + .equ NUM_EG1_FRAC_BITS, 15 + +@**************************************************************************** + + .equ NUM_ENHANCER_FILTER_COEF_FRAC_BITS, 5 + +@**************************************************************************** + +@ +@ I've temporarily given up on the idea of getting ADS/RV and gcc to +@ handle a struct in a compatible fashion. Switching to old fashion EQU +@ + + .if FILTER_ENABLED +@************************************** +@ typedef struct s_filter_tag + .equ m_z1, 0 + .equ m_z2, 2 + .endif + +@************************************** +@ typedef struct s_wt_frame_tag + .equ m_gainTarget, 0 + .equ m_phaseIncrement, 4 + + .if FILTER_ENABLED + .equ m_k, 8 + .equ m_b1, 12 + .equ m_b2, 16 + .equ m_pAudioBuffer, 20 + .equ m_pMixBuffer, 24 + .equ m_numSamples, 28 + .equ m_prevGain, 32 + .else + .equ m_pAudioBuffer, 8 + .equ m_pMixBuffer, 12 + .equ m_numSamples, 16 + .equ m_prevGain, 20 + .endif + + +@************************************** +@ typedef struct s_wt_voice_tag + .equ m_pLoopEnd, 0 @ /* points to last PCM sample (not 1 beyond last) */ + .equ m_pLoopStart, 4 @ /* points to first sample at start of loop */ + .equ m_pPhaseAccum, 8 @ /* points to first sample at start of loop */ + .equ m_phaseFrac, 12 @ /* points to first sample at start of loop */ + + .if STEREO_OUTPUT + .equ m_gainLeft, 16 @ /* current gain, left ch */ + .equ m_gainRight, 18 @ /* current gain, right ch */ + .endif + + +@**************************************************************************** +@ enhancer + .equ m_nEnhancerFeedForward1, 0 + .equ m_nEnhancerFeedback1, 1 + .equ m_nDriveCoef, 2 + .equ m_nEnhancerFeedback2, 3 + .equ m_nWet, 4 + .equ m_nDry, 5 + + .equ m_zF0L, 6 @ filter 1 zero state var, left + .equ m_zF1L, 8 @ filter 1 pole state var, left + .equ m_zF2L, 10 @ filter 2 zero state var, left + .equ m_zF0R, 12 @ filter 1 zero state var, right + .equ m_zF1R, 14 @ filter 1 pole state var, right + .equ m_zF2R, 16 @ filter 2 zero state var, right + +@**************************************************************************** + + + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/arm-hybrid-22k_lib.mak b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/arm-hybrid-22k_lib.mak new file mode 100755 index 0000000..43edd6d --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/arm-hybrid-22k_lib.mak @@ -0,0 +1,25 @@ +# +# Auto-generated sample makefile +# +# This makefile is intended for use with GNU make. +# Set the paths to the tools (CC, AR, LD, etc.) +# + +vpath %.c lib_src + +CC = C:\Program Files\GNUARM\bin\arm-elf-gcc.exe +AS = C:\Program Files\GNUARM\bin\arm-elf-as.exe +LD = C:\Program Files\GNUARM\bin\arm-elf-gcc.exe +AR = C:\Program Files\GNUARM\bin\arm-elf-ar.exe + +%.o: %.c + $(CC) -c -O2 -o $@ -I lib_src -I host_src -D NUM_OUTPUT_CHANNELS=2 -D _SAMPLE_RATE_22050 -D MAX_SYNTH_VOICES=32 -D NUM_PRIMARY_VOICES=8 -D EAS_HYBRID_SYNTH -D _8_BIT_SAMPLES -D _FILTER_ENABLED -D _IMELODY_PARSER -D _RTTTL_PARSER -D _OTA_PARSER -D _WAVE_PARSER -D _REVERB_ENABLED -D _CHORUS_ENABLED -D _IMA_DECODER -D NATIVE_EAS_KERNEL $< + +%.o: %.s + $(AS) -o $@ -EL -mcpu=arm946e-s -mfpu=softfpa -I lib_src --defsym CHECK_STACK=0 --defsym REVERB=0 --defsym CHORUS=0 --defsym STEREO_OUTPUT=1 --defsym SAMPLE_RATE_22050=1 --defsym SAMPLES_8_BIT=1 --defsym FILTER_ENABLED=1 $< + +OBJS = eas_mididata.o eas_pan.o eas_wavefiledata.o eas_wavefile.o eas_smfdata.o eas_imelody.o eas_math.o eas_fmengine.o ARM-E_filter_gnu.o eas_chorusdata.o eas_wtengine.o eas_ota.o eas_rtttldata.o eas_reverbdata.o eas_public.o ARM-E_interpolate_loop_gnu.o eas_rtttl.o eas_reverb.o ARM-E_voice_gain_gnu.o eas_fmsynth.o eas_midi.o eas_otadata.o eas_wtsynth.o eas_mixbuf.o eas_imaadpcm.o hybrid_22khz_mcu.o eas_smf.o eas_chorus.o eas_pcm.o eas_mixer.o eas_data.o eas_imelodydata.o eas_pcmdata.o eas_ima_tables.o eas_fmtables.o ARM-E_interpolate_noloop_gnu.o ARM-E_mastergain_gnu.o eas_voicemgt.o + +arm-hybrid-22k.a: $(OBJS) + $(AR) rc lib$@ $(OBJS) + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_audioconst.h b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_audioconst.h new file mode 100755 index 0000000..066148e --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_audioconst.h @@ -0,0 +1,97 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_audioconst.h + * + * Contents and purpose: + * Defines audio constants related to the sample rate, bit size, etc. + * + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_AUDIOCONST_H +#define _EAS_AUDIOCONST_H + +/*---------------------------------------------------------------------------- + * These macros define the various characteristics of the defined sample rates + *---------------------------------------------------------------------------- + * BUFFER_SIZE_IN_MONO_SAMPLES size of buffer in samples + * _OUTPUT_SAMPLE_RATE compiled output sample rate + * AUDIO_FRAME_LENGTH length of an audio frame in 256ths of a millisecond + * SYNTH_UPDATE_PERIOD_IN_BITS length of an audio frame (2^x samples) + *---------------------------------------------------------------------------- +*/ + +#if defined (_SAMPLE_RATE_8000) +#define BUFFER_SIZE_IN_MONO_SAMPLES 32 +#define _OUTPUT_SAMPLE_RATE 8000 +#define AUDIO_FRAME_LENGTH 1024 +#define SYNTH_UPDATE_PERIOD_IN_BITS 5 + +#elif defined (_SAMPLE_RATE_16000) +#define BUFFER_SIZE_IN_MONO_SAMPLES 64 +#define _OUTPUT_SAMPLE_RATE 16000 +#define AUDIO_FRAME_LENGTH 1024 +#define SYNTH_UPDATE_PERIOD_IN_BITS 6 + +#elif defined (_SAMPLE_RATE_20000) +#define BUFFER_SIZE_IN_MONO_SAMPLES 128 +#define _OUTPUT_SAMPLE_RATE 20000 +#define AUDIO_FRAME_LENGTH 1638 +#define SYNTH_UPDATE_PERIOD_IN_BITS 7 + +#elif defined (_SAMPLE_RATE_22050) +#define BUFFER_SIZE_IN_MONO_SAMPLES 128 +#define _OUTPUT_SAMPLE_RATE 22050 +#define AUDIO_FRAME_LENGTH 1486 +#define SYNTH_UPDATE_PERIOD_IN_BITS 7 + +#elif defined (_SAMPLE_RATE_24000) +#define BUFFER_SIZE_IN_MONO_SAMPLES 128 +#define _OUTPUT_SAMPLE_RATE 24000 +#define AUDIO_FRAME_LENGTH 1365 +#define SYNTH_UPDATE_PERIOD_IN_BITS 7 + +#elif defined (_SAMPLE_RATE_32000) +#define BUFFER_SIZE_IN_MONO_SAMPLES 128 +#define _OUTPUT_SAMPLE_RATE 32000 +#define AUDIO_FRAME_LENGTH 1024 +#define SYNTH_UPDATE_PERIOD_IN_BITS 7 + +#elif defined (_SAMPLE_RATE_44100) +#define BUFFER_SIZE_IN_MONO_SAMPLES 256 +#define _OUTPUT_SAMPLE_RATE 44100 +#define AUDIO_FRAME_LENGTH 1486 +#define SYNTH_UPDATE_PERIOD_IN_BITS 8 + +#elif defined (_SAMPLE_RATE_48000) +#define BUFFER_SIZE_IN_MONO_SAMPLES 256 +#define _OUTPUT_SAMPLE_RATE 48000 +#define AUDIO_FRAME_LENGTH 1365 +#define SYNTH_UPDATE_PERIOD_IN_BITS 8 + +#else +#error "_SAMPLE_RATE_XXXXX must be defined to valid rate" +#endif + +#endif /* #ifndef _EAS_AUDIOCONST_H */ + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_chorus.c b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_chorus.c new file mode 100755 index 0000000..4a2c8d0 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_chorus.c @@ -0,0 +1,604 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_chorus.c + * + * Contents and purpose: + * Contains the implementation of the Chorus effect. + * + * + * Copyright Sonic Network Inc. 2006 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 499 $ + * $Date: 2006-12-11 16:07:20 -0800 (Mon, 11 Dec 2006) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_data.h" +#include "eas_effects.h" +#include "eas_math.h" +#include "eas_chorusdata.h" +#include "eas_chorus.h" +#include "eas_config.h" +#include "eas_host.h" +#include "eas_report.h" + +/* prototypes for effects interface */ +static EAS_RESULT ChorusInit (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR *pInstData); +static void ChorusProcess (EAS_VOID_PTR pInstData, EAS_PCM *pSrc, EAS_PCM *pDst, EAS_I32 numSamples); +static EAS_RESULT ChorusShutdown (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT ChorusGetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue); +static EAS_RESULT ChorusSetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value); + +/* common effects interface for configuration module */ +const S_EFFECTS_INTERFACE EAS_Chorus = +{ + ChorusInit, + ChorusProcess, + ChorusShutdown, + ChorusGetParam, + ChorusSetParam +}; + + + +//LFO shape table used by the chorus, larger table would sound better +//this is a sine wave, where 32767 = 1.0 +static const EAS_I16 EAS_chorusShape[CHORUS_SHAPE_SIZE] = { + 0, 1608, 3212, 4808, 6393, 7962, 9512, 11309, 12539, 14010, 15446, 16846, 18204, 19519, 20787, 22005, 23170, + 24279, 25329, 26319, 27245, 28105, 28898, 29621, 30273, 30852, 31356, 31785, 32137, 32412, 32609, 32728, + 32767, 32728, 32609, 32412, 32137, 31785, 31356, 30852, 30273, 29621, 28898, 28105, 27245, 26319, 25329, + 24279, 23170, 22005, 20787, 19519, 18204, 16846, 15446, 14010, 12539, 11039, 9512, 7962, 6393, 4808, 3212, + 1608, 0, -1608, -3212, -4808, -6393, -7962, -9512, -11309, -12539, -14010, -15446, -16846, -18204, -19519, + -20787, -22005, -23170, -24279, -25329, -26319, -27245, -28105, -28898, -29621, -30273, -30852, -31356, -31785, + -32137, -32412, -32609, -32728, -32767, -32728, -32609, -32412, -32137, -31785, -31356, -30852, -30273, -29621, + -28898, -28105, -27245, -26319, -25329, -24279, -23170, -22005, -20787, -19519, -18204, -16846, -15446, -14010, + -12539, -11039, -9512, -7962, -6393, -4808, -3212, -1608 +}; + +/*---------------------------------------------------------------------------- + * InitializeChorus() + *---------------------------------------------------------------------------- + * Purpose: Initializes chorus parameters + * + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ChorusInit (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR *pInstData) +{ + S_CHORUS_OBJECT *pChorusData; + S_CHORUS_PRESET *pPreset; + EAS_I32 index; + + /* check Configuration Module for data allocation */ + if (pEASData->staticMemoryModel) + pChorusData = EAS_CMEnumFXData(EAS_MODULE_CHORUS); + + /* allocate dynamic memory */ + else + pChorusData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_CHORUS_OBJECT)); + + if (pChorusData == NULL) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Failed to allocate Chorus memory\n"); */ } + return EAS_ERROR_MALLOC_FAILED; + } + + /* clear the structure */ + EAS_HWMemSet(pChorusData, 0, sizeof(S_CHORUS_OBJECT)); + + ChorusReadInPresets(pChorusData); + + /* set some default values */ + pChorusData->bypass = EAS_CHORUS_BYPASS_DEFAULT; + pChorusData->preset = EAS_CHORUS_PRESET_DEFAULT; + pChorusData->m_nLevel = EAS_CHORUS_LEVEL_DEFAULT; + pChorusData->m_nRate = EAS_CHORUS_RATE_DEFAULT; + pChorusData->m_nDepth = EAS_CHORUS_DEPTH_DEFAULT; + + //chorus rate and depth need some massaging from preset value (which is sample rate independent) + + //convert rate from steps of .05 Hz to value which can be used as phase increment, + //with current CHORUS_SHAPE_SIZE and rate limits, this fits into 16 bits + //want to compute ((shapeSize * 65536) * (storedRate/20))/sampleRate; + //computing it as below allows rate steps to be evenly spaced + //uses 32 bit divide, but only once when new value is selected + pChorusData->m_nRate = (EAS_I16) + ((((EAS_I32)CHORUS_SHAPE_SIZE<<16)/(20*(EAS_I32)_OUTPUT_SAMPLE_RATE)) * pChorusData->m_nRate); + + //convert depth from steps of .05 ms, to samples, with 16 bit whole part, discard fraction + //want to compute ((depth * sampleRate)/20000) + //use the following approximation since 105/32 is roughly 65536/20000 + /*lint -e{704} use shift for performance */ + pChorusData->m_nDepth = (EAS_I16) + (((((EAS_I32)pChorusData->m_nDepth * _OUTPUT_SAMPLE_RATE)>>5) * 105) >> 16); + + pChorusData->m_nLevel = pChorusData->m_nLevel; + + //zero delay memory for chorus + for (index = CHORUS_L_SIZE - 1; index >= 0; index--) + { + pChorusData->chorusDelayL[index] = 0; + } + for (index = CHORUS_R_SIZE - 1; index >= 0; index--) + { + pChorusData->chorusDelayR[index] = 0; + } + + //init delay line index, these are used to implement circular delay buffer + pChorusData->chorusIndexL = 0; + pChorusData->chorusIndexR = 0; + + //init LFO phase + //16 bit whole part, 16 bit fraction + pChorusData->lfoLPhase = 0; + pChorusData->lfoRPhase = (CHORUS_SHAPE_SIZE << 16) >> 2; // 1/4 of total, i.e. 90 degrees out of phase; + + //init chorus delay position + //right now chorus delay is a compile-time value, as is sample rate + pChorusData->chorusTapPosition = (EAS_I16)((CHORUS_DELAY_MS * _OUTPUT_SAMPLE_RATE)/1000); + + //now copy from the new preset into Chorus + pPreset = &pChorusData->m_sPreset.m_sPreset[pChorusData->m_nNextChorus]; + + pChorusData->m_nLevel = pPreset->m_nLevel; + pChorusData->m_nRate = pPreset->m_nRate; + pChorusData->m_nDepth = pPreset->m_nDepth; + + pChorusData->m_nRate = (EAS_I16) + ((((EAS_I32)CHORUS_SHAPE_SIZE<<16)/(20*(EAS_I32)_OUTPUT_SAMPLE_RATE)) * pChorusData->m_nRate); + + /*lint -e{704} use shift for performance */ + pChorusData->m_nDepth = (EAS_I16) + (((((EAS_I32)pChorusData->m_nDepth * _OUTPUT_SAMPLE_RATE)>>5) * 105) >> 16); + + *pInstData = pChorusData; + + return EAS_SUCCESS; +} /* end ChorusInit */ + +/*---------------------------------------------------------------------------- + * WeightedTap() + *---------------------------------------------------------------------------- + * Purpose: Does fractional array look-up using linear interpolation + * + * first convert indexDesired to actual desired index by taking into account indexReference + * then do linear interpolation between two actual samples using fractional part + * + * Inputs: + * array: pointer to array of signed 16 bit values, typically either PCM data or control data + * indexReference: the circular buffer relative offset + * indexDesired: the fractional index we are looking up (16 bits index + 16 bits fraction) + * indexLimit: the total size of the array, used to compute buffer wrap + * + * Outputs: + * Value from the input array, linearly interpolated between two actual data values + * + *---------------------------------------------------------------------------- +*/ +static EAS_I16 WeightedTap(const EAS_I16 *array, EAS_I16 indexReference, EAS_I32 indexDesired, EAS_I16 indexLimit) +{ + EAS_I16 index; + EAS_I16 fraction; + EAS_I16 val1; + EAS_I16 val2; + + //separate indexDesired into whole and fractional parts + /*lint -e{704} use shift for performance */ + index = (EAS_I16)(indexDesired >> 16); + /*lint -e{704} use shift for performance */ + fraction = (EAS_I16)((indexDesired>>1) & 0x07FFF); //just use 15 bits of fractional part + + //adjust whole part by indexReference + index = indexReference - index; + //make sure we stay within array bounds, this implements circular buffer + while (index < 0) + { + index += indexLimit; + } + + //get two adjacent values from the array + val1 = array[index]; + + //handle special case when index == 0, else typical case + if (index == 0) + { + val2 = array[indexLimit-1]; //get last value from array + } + else + { + val2 = array[index-1]; //get previous value from array + } + + //compute linear interpolation as (val1 + ((val2-val1)*fraction)) + return(val1 + (EAS_I16)MULT_EG1_EG1(val2-val1,fraction)); +} + +/*---------------------------------------------------------------------------- + * ChorusProcess() + *---------------------------------------------------------------------------- + * Purpose: compute the chorus on the input buffer, and mix into output buffer + * + * + * Inputs: + * src: pointer to input buffer of PCM values to be processed + * dst: pointer to output buffer of PCM values we are to sume the result with + * bufSize: the number of sample frames (i.e. stereo samples) in the buffer + * + * Outputs: + * None + * + *---------------------------------------------------------------------------- +*/ +//compute the chorus, and mix into output buffer +static void ChorusProcess (EAS_VOID_PTR pInstData, EAS_PCM *pSrc, EAS_PCM *pDst, EAS_I32 numSamples) +{ + EAS_I32 ix; + EAS_I32 nChannelNumber; + EAS_I16 lfoValueLeft; + EAS_I16 lfoValueRight; + EAS_I32 positionOffsetL; + EAS_I32 positionOffsetR; + EAS_PCM tapL; + EAS_PCM tapR; + EAS_I32 tempValue; + EAS_PCM nInputSample; + EAS_I32 nOutputSample; + EAS_PCM *pIn; + EAS_PCM *pOut; + + S_CHORUS_OBJECT *pChorusData; + + pChorusData = (S_CHORUS_OBJECT*) pInstData; + + //if the chorus is disabled or turned all the way down + if (pChorusData->bypass == EAS_TRUE || pChorusData->m_nLevel == 0) + { + if (pSrc != pDst) + EAS_HWMemCpy(pSrc, pDst, numSamples * NUM_OUTPUT_CHANNELS * (EAS_I32) sizeof(EAS_PCM)); + return; + } + + if (pChorusData->m_nNextChorus != pChorusData->m_nCurrentChorus) + { + ChorusUpdate(pChorusData); + } + + for (nChannelNumber = 0; nChannelNumber < NUM_OUTPUT_CHANNELS; nChannelNumber++) + { + + pIn = pSrc + nChannelNumber; + pOut = pDst + nChannelNumber; + + if(nChannelNumber==0) + { + for (ix = 0; ix < numSamples; ix++) + { + nInputSample = *pIn; + pIn += NUM_OUTPUT_CHANNELS; + + //feed input into chorus delay line + pChorusData->chorusDelayL[pChorusData->chorusIndexL] = nInputSample; + + //compute chorus lfo value using phase as fractional index into chorus shape table + //resulting value is between -1.0 and 1.0, expressed as signed 16 bit number + lfoValueLeft = WeightedTap(EAS_chorusShape, 0, pChorusData->lfoLPhase, CHORUS_SHAPE_SIZE); + + //scale chorus depth by lfo value to get relative fractional sample index + //index is expressed as 32 bit number with 16 bit fractional part + /*lint -e{703} use shift for performance */ + positionOffsetL = pChorusData->m_nDepth * (((EAS_I32)lfoValueLeft) << 1); + + //add fixed chorus delay to get actual fractional sample index + positionOffsetL += ((EAS_I32)pChorusData->chorusTapPosition) << 16; + + //get tap value from chorus delay using fractional sample index + tapL = WeightedTap(pChorusData->chorusDelayL, pChorusData->chorusIndexL, positionOffsetL, CHORUS_L_SIZE); + + //scale by chorus level, then sum with input buffer contents and saturate + tempValue = MULT_EG1_EG1(tapL, pChorusData->m_nLevel); + nOutputSample = SATURATE(tempValue + nInputSample); + + *pOut = (EAS_I16)SATURATE(nOutputSample); + pOut += NUM_OUTPUT_CHANNELS; + + + //increment chorus delay index and make it wrap as needed + //this implements circular buffer + if ((pChorusData->chorusIndexL+=1) >= CHORUS_L_SIZE) + pChorusData->chorusIndexL = 0; + + //increment fractional lfo phase, and make it wrap as needed + pChorusData->lfoLPhase += pChorusData->m_nRate; + while (pChorusData->lfoLPhase >= (CHORUS_SHAPE_SIZE<<16)) + { + pChorusData->lfoLPhase -= (CHORUS_SHAPE_SIZE<<16); + } + } + } + else + { + for (ix = 0; ix < numSamples; ix++) + { + nInputSample = *pIn; + pIn += NUM_OUTPUT_CHANNELS; + + //feed input into chorus delay line + pChorusData->chorusDelayR[pChorusData->chorusIndexR] = nInputSample; + + //compute chorus lfo value using phase as fractional index into chorus shape table + //resulting value is between -1.0 and 1.0, expressed as signed 16 bit number + lfoValueRight = WeightedTap(EAS_chorusShape, 0, pChorusData->lfoRPhase, CHORUS_SHAPE_SIZE); + + //scale chorus depth by lfo value to get relative fractional sample index + //index is expressed as 32 bit number with 16 bit fractional part + /*lint -e{703} use shift for performance */ + positionOffsetR = pChorusData->m_nDepth * (((EAS_I32)lfoValueRight) << 1); + + //add fixed chorus delay to get actual fractional sample index + positionOffsetR += ((EAS_I32)pChorusData->chorusTapPosition) << 16; + + //get tap value from chorus delay using fractional sample index + tapR = WeightedTap(pChorusData->chorusDelayR, pChorusData->chorusIndexR, positionOffsetR, CHORUS_R_SIZE); + + //scale by chorus level, then sum with output buffer contents and saturate + tempValue = MULT_EG1_EG1(tapR, pChorusData->m_nLevel); + nOutputSample = SATURATE(tempValue + nInputSample); + + *pOut = (EAS_I16)SATURATE(nOutputSample); + pOut += NUM_OUTPUT_CHANNELS; + + //increment chorus delay index and make it wrap as needed + //this implements circular buffer + if ((pChorusData->chorusIndexR+=1) >= CHORUS_R_SIZE) + pChorusData->chorusIndexR = 0; + + //increment fractional lfo phase, and make it wrap as needed + pChorusData->lfoRPhase += pChorusData->m_nRate; + while (pChorusData->lfoRPhase >= (CHORUS_SHAPE_SIZE<<16)) + { + pChorusData->lfoRPhase -= (CHORUS_SHAPE_SIZE<<16); + } + } + } + + } +} /* end ChorusProcess */ + + + +/*---------------------------------------------------------------------------- + * ChorusShutdown() + *---------------------------------------------------------------------------- + * Purpose: + * Initializes the Chorus effect. + * + * Inputs: + * pInstData - handle to instance data + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ChorusShutdown (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR pInstData) +{ + /* check Configuration Module for static memory allocation */ + if (!pEASData->staticMemoryModel) + EAS_HWFree(pEASData->hwInstData, pInstData); + return EAS_SUCCESS; +} /* end ChorusShutdown */ + +/*---------------------------------------------------------------------------- + * ChorusGetParam() + *---------------------------------------------------------------------------- + * Purpose: + * Get a Chorus parameter + * + * Inputs: + * pInstData - handle to instance data + * param - parameter index + * *pValue - pointer to variable to hold retrieved value + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ChorusGetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue) +{ + S_CHORUS_OBJECT *p; + + p = (S_CHORUS_OBJECT*) pInstData; + + switch (param) + { + case EAS_PARAM_CHORUS_BYPASS: + *pValue = (EAS_I32) p->bypass; + break; + case EAS_PARAM_CHORUS_PRESET: + *pValue = (EAS_I8) p->m_nCurrentChorus; + break; + case EAS_PARAM_CHORUS_RATE: + *pValue = (EAS_I32) p->m_nRate; + break; + case EAS_PARAM_CHORUS_DEPTH: + *pValue = (EAS_I32) p->m_nDepth; + break; + case EAS_PARAM_CHORUS_LEVEL: + *pValue = (EAS_I32) p->m_nLevel; + break; + default: + return EAS_ERROR_INVALID_PARAMETER; + } + return EAS_SUCCESS; +} /* end ChorusGetParam */ + + +/*---------------------------------------------------------------------------- + * ChorusSetParam() + *---------------------------------------------------------------------------- + * Purpose: + * Set a Chorus parameter + * + * Inputs: + * pInstData - handle to instance data + * param - parameter index + * *pValue - new paramter value + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ChorusSetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value) +{ + S_CHORUS_OBJECT *p; + + p = (S_CHORUS_OBJECT*) pInstData; + + switch (param) + { + case EAS_PARAM_CHORUS_BYPASS: + p->bypass = (EAS_BOOL) value; + break; + case EAS_PARAM_CHORUS_PRESET: + if(value!=EAS_PARAM_CHORUS_PRESET1 && value!=EAS_PARAM_CHORUS_PRESET2 && + value!=EAS_PARAM_CHORUS_PRESET3 && value!=EAS_PARAM_CHORUS_PRESET4) + return EAS_ERROR_INVALID_PARAMETER; + p->m_nNextChorus = (EAS_I8)value; + break; + case EAS_PARAM_CHORUS_RATE: + if(valueEAS_CHORUS_RATE_MAX) + return EAS_ERROR_INVALID_PARAMETER; + p->m_nRate = (EAS_I16) value; + break; + case EAS_PARAM_CHORUS_DEPTH: + if(valueEAS_CHORUS_DEPTH_MAX) + return EAS_ERROR_INVALID_PARAMETER; + p->m_nDepth = (EAS_I16) value; + break; + case EAS_PARAM_CHORUS_LEVEL: + if(valueEAS_CHORUS_LEVEL_MAX) + return EAS_ERROR_INVALID_PARAMETER; + p->m_nLevel = (EAS_I16) value; + break; + + default: + return EAS_ERROR_INVALID_PARAMETER; + } + return EAS_SUCCESS; +} /* end ChorusSetParam */ + + +/*---------------------------------------------------------------------------- + * ChorusReadInPresets() + *---------------------------------------------------------------------------- + * Purpose: sets global Chorus preset bank to defaults + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ChorusReadInPresets(S_CHORUS_OBJECT *pChorusData) +{ + + int preset = 0; + int defaultPreset = 0; + + //now init any remaining presets to defaults + for (defaultPreset = preset; defaultPreset < CHORUS_MAX_TYPE; defaultPreset++) + { + S_CHORUS_PRESET *pPreset = &pChorusData->m_sPreset.m_sPreset[defaultPreset]; + if (defaultPreset == 0 || defaultPreset > CHORUS_MAX_TYPE-1) + { + pPreset->m_nDepth = 39; + pPreset->m_nRate = 30; + pPreset->m_nLevel = 32767; + } + else if (defaultPreset == 1) + { + pPreset->m_nDepth = 21; + pPreset->m_nRate = 45; + pPreset->m_nLevel = 25000; + } + else if (defaultPreset == 2) + { + pPreset->m_nDepth = 53; + pPreset->m_nRate = 25; + pPreset->m_nLevel = 32000; + } + else if (defaultPreset == 3) + { + pPreset->m_nDepth = 32; + pPreset->m_nRate = 37; + pPreset->m_nLevel = 29000; + } + } + + return EAS_SUCCESS; +} + + +/*---------------------------------------------------------------------------- + * ChorusUpdate + *---------------------------------------------------------------------------- + * Purpose: + * Update the Chorus preset parameters as required + * + * Inputs: + * + * Outputs: + * + * + * Side Effects: + * - chorus paramters will be changed + * - m_nCurrentRoom := m_nNextRoom + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ChorusUpdate(S_CHORUS_OBJECT *pChorusData) +{ + S_CHORUS_PRESET *pPreset = &pChorusData->m_sPreset.m_sPreset[pChorusData->m_nNextChorus]; + + pChorusData->m_nLevel = pPreset->m_nLevel; + pChorusData->m_nRate = pPreset->m_nRate; + pChorusData->m_nDepth = pPreset->m_nDepth; + + pChorusData->m_nRate = (EAS_I16) + ((((EAS_I32)CHORUS_SHAPE_SIZE<<16)/(20*(EAS_I32)_OUTPUT_SAMPLE_RATE)) * pChorusData->m_nRate); + + /*lint -e{704} use shift for performance */ + pChorusData->m_nDepth = (EAS_I16) + (((((EAS_I32)pChorusData->m_nDepth * _OUTPUT_SAMPLE_RATE)>>5) * 105) >> 16); + + pChorusData->m_nCurrentChorus = pChorusData->m_nNextChorus; + + return EAS_SUCCESS; + +} /* end ChorusUpdate */ diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_chorusdata.c b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_chorusdata.c new file mode 100755 index 0000000..ec71ff8 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_chorusdata.c @@ -0,0 +1,34 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_chorusdata.c + * + * Contents and purpose: + * Contains the static data allocation for the Chorus effect + * + * + * Copyright Sonic Network Inc. 2006 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 550 $ + * $Date: 2007-02-02 09:37:03 -0800 (Fri, 02 Feb 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_chorusdata.h" + +S_CHORUS_OBJECT eas_ChorusData; + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_chorusdata.h b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_chorusdata.h new file mode 100755 index 0000000..ec8daa4 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_chorusdata.h @@ -0,0 +1,160 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_chorusdata.h + * + * Contents and purpose: + * Contains the prototypes for the Chorus effect. + * + * + * Copyright Sonic Network Inc. 2006 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 309 $ + * $Date: 2006-09-12 18:52:45 -0700 (Tue, 12 Sep 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_CHORUS_H +#define _EAS_CHORUS_H + +#include "eas_types.h" +#include "eas_audioconst.h" + +//defines for chorus + +#define EAS_CHORUS_BYPASS_DEFAULT 1 +#define EAS_CHORUS_PRESET_DEFAULT 0 +#define EAS_CHORUS_RATE_DEFAULT 30 +#define EAS_CHORUS_DEPTH_DEFAULT 39 +#define EAS_CHORUS_LEVEL_DEFAULT 32767 + +#define EAS_CHORUS_LEVEL_MIN 0 +#define EAS_CHORUS_LEVEL_MAX 32767 + +#define EAS_CHORUS_RATE_MIN 10 +#define EAS_CHORUS_RATE_MAX 50 + +#define EAS_CHORUS_DEPTH_MIN 15 +#define EAS_CHORUS_DEPTH_MAX 60 + +#define CHORUS_SIZE_MS 20 +#define CHORUS_L_SIZE ((CHORUS_SIZE_MS*_OUTPUT_SAMPLE_RATE)/1000) +#define CHORUS_R_SIZE CHORUS_L_SIZE +#define CHORUS_SHAPE_SIZE 128 +#define CHORUS_DELAY_MS 10 + +#define CHORUS_MAX_TYPE 4 // any Chorus numbers larger than this are invalid + +typedef struct +{ + EAS_I16 m_nRate; + EAS_I16 m_nDepth; + EAS_I16 m_nLevel; + +} S_CHORUS_PRESET; + +typedef struct +{ + S_CHORUS_PRESET m_sPreset[CHORUS_MAX_TYPE]; //array of presets + +} S_CHORUS_PRESET_BANK; + +/* parameters for each Chorus */ +typedef struct +{ + EAS_I32 lfoLPhase; + EAS_I32 lfoRPhase; + EAS_I16 chorusIndexL; + EAS_I16 chorusIndexR; + EAS_U16 chorusTapPosition; + + EAS_I16 m_nRate; + EAS_I16 m_nDepth; + EAS_I16 m_nLevel; + + //delay lines used by the chorus, longer would sound better + EAS_PCM chorusDelayL[CHORUS_L_SIZE]; + EAS_PCM chorusDelayR[CHORUS_R_SIZE]; + + EAS_BOOL bypass; + EAS_I8 preset; + + EAS_I16 m_nCurrentChorus; // preset number for current Chorus + EAS_I16 m_nNextChorus; // preset number for next Chorus + + S_CHORUS_PRESET pPreset; + + S_CHORUS_PRESET_BANK m_sPreset; + +} S_CHORUS_OBJECT; + + +/*---------------------------------------------------------------------------- + * WeightedTap() + *---------------------------------------------------------------------------- + * Purpose: Does fractional array look-up using linear interpolation + * + * first convert indexDesired to actual desired index by taking into account indexReference + * then do linear interpolation between two actual samples using fractional part + * + * Inputs: + * array: pointer to array of signed 16 bit values, typically either PCM data or control data + * indexReference: the circular buffer relative offset + * indexDesired: the fractional index we are looking up (16 bits index + 16 bits fraction) + * indexLimit: the total size of the array, used to compute buffer wrap + * + * Outputs: + * Value from the input array, linearly interpolated between two actual data values + * + *---------------------------------------------------------------------------- +*/ +static EAS_I16 WeightedTap(const EAS_I16 *array, EAS_I16 indexReference, EAS_I32 indexDesired, EAS_I16 indexLimit); + +/*---------------------------------------------------------------------------- + * ChorusReadInPresets() + *---------------------------------------------------------------------------- + * Purpose: sets global Chorus preset bank to defaults + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ChorusReadInPresets(S_CHORUS_OBJECT *pChorusData); + +/*---------------------------------------------------------------------------- + * ChorusUpdate + *---------------------------------------------------------------------------- + * Purpose: + * Update the Chorus preset parameters as required + * + * Inputs: + * + * Outputs: + * + * + * Side Effects: + * - chorus paramters will be changed + * - m_nCurrentChorus := m_nNextChorus + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ChorusUpdate(S_CHORUS_OBJECT* pChorusData); + +#endif /* #ifndef _EAS_CHORUSDATA_H */ + + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_ctype.h b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_ctype.h new file mode 100755 index 0000000..14fa96f --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_ctype.h @@ -0,0 +1,41 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_ctype.h + * + * Contents and purpose: + * This is a replacement for the CRT ctype.h functions. These + * functions are currently ASCII only, but eventually, we will want + * to support wide-characters for localization. + * + * Copyright (c) 2005 Sonic Network Inc. + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 429 $ + * $Date: 2006-10-19 23:50:15 -0700 (Thu, 19 Oct 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_CTYPE_H +#define _EAS_CTYPE_H + +EAS_INLINE EAS_I8 IsDigit (EAS_I8 c) { return ((c >= '0') && (c <= '9')); } +EAS_INLINE EAS_I8 IsSpace (EAS_I8 c) { return (((c >= 9) && (c <= 13)) || (c == ' ')); } +EAS_INLINE EAS_I8 ToUpper (EAS_I8 c) { if ((c >= 'a') && (c <= 'z')) return c & ~0x20; else return c; } +EAS_INLINE EAS_I8 ToLower (EAS_I8 c) { if ((c >= 'A') && (c <= 'Z')) return c |= 0x20; else return c; } + +#endif + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_data.c b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_data.c new file mode 100755 index 0000000..31a4e6a --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_data.c @@ -0,0 +1,37 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_data.c + * + * Contents and purpose: + * Contains a data allocation for synthesizer + * + * Copyright Sonic Network Inc. 2004 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 547 $ + * $Date: 2007-01-31 16:30:17 -0800 (Wed, 31 Jan 2007) $ + *---------------------------------------------------------------------------- +*/ + +// includes +#include "eas_data.h" + +// globals +S_EAS_DATA eas_Data; +S_VOICE_MGR eas_Synth; +S_SYNTH eas_MIDI; + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_data.h b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_data.h new file mode 100755 index 0000000..e2fcb1a --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_data.h @@ -0,0 +1,131 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_data.h + * + * Contents and purpose: + * This header defines all types, to support dynamic allocation of the + * memory resources needed for persistent EAS data. + * + * Copyright 2004 Sonic Network Inc. + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 842 $ + * $Date: 2007-08-23 14:32:31 -0700 (Thu, 23 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_DATA_H +#define _EAS_DATA_H + +#include "eas_types.h" +#include "eas_synthcfg.h" +#include "eas.h" +#include "eas_audioconst.h" +#include "eas_sndlib.h" +#include "eas_pcm.h" +#include "eas_pcmdata.h" +#include "eas_synth.h" +#include "eas_miditypes.h" +#include "eas_effects.h" + +#ifdef AUX_MIXER +#include "eas_auxmixdata.h" +#endif + +#ifdef JET_INTERFACE +#include "jet.h" +#endif + +#ifdef _METRICS_ENABLED +#include "eas_perf.h" +#endif + +#ifndef MAX_NUMBER_STREAMS +#define MAX_NUMBER_STREAMS 4 +#endif + +/* flags for S_EAS_STREAM */ +#define STREAM_FLAGS_PARSED 1 +#define STREAM_FLAGS_PAUSE 2 +#define STREAM_FLAGS_LOCATE 4 +#define STREAM_FLAGS_RESUME 8 + +/* structure for parsing a stream */ +typedef struct s_eas_stream_tag +{ + void *pParserModule; + EAS_U32 time; + EAS_U32 frameLength; + EAS_I32 repeatCount; + EAS_VOID_PTR handle; + EAS_U8 volume; + EAS_BOOL8 streamFlags; +} S_EAS_STREAM; + +/* default master volume is -10dB */ +#define DEFAULT_VOLUME 90 +#define DEFAULT_STREAM_VOLUME 100 +#define DEFAULT_STREAM_GAIN 14622 + +/* 10 dB of boost available for individual parsers */ +#define STREAM_VOLUME_HEADROOM 10 + +/* amalgamated persistent data type */ +typedef struct s_eas_data_tag +{ +#ifdef _CHECKED_BUILD + EAS_U32 handleCheck; +#endif + EAS_HW_DATA_HANDLE hwInstData; + + S_EFFECTS_MODULE effectsModules[NUM_EFFECTS_MODULES]; + +#ifdef _METRICS_ENABLED + S_METRICS_INTERFACE *pMetricsModule; + EAS_VOID_PTR pMetricsData; +#endif + + EAS_I32 *pMixBuffer; + EAS_PCM *pOutputAudioBuffer; + +#ifdef AUX_MIXER + S_EAS_AUX_MIXER auxMixer; +#endif + +#ifdef _MAXIMIZER_ENABLED + EAS_VOID_PTR pMaximizerData; +#endif + + S_EAS_STREAM streams[MAX_NUMBER_STREAMS]; + + S_PCM_STATE *pPCMStreams; + + S_VOICE_MGR *pVoiceMgr; + +#ifdef JET_INTERFACE + JET_DATA_HANDLE jetHandle; +#endif + + EAS_U32 renderTime; + EAS_I16 masterGain; + EAS_U8 masterVolume; + EAS_BOOL8 staticMemoryModel; + EAS_BOOL8 searchHeaderFlag; +} S_EAS_DATA; + +#endif + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_effects.h b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_effects.h new file mode 100755 index 0000000..86dedac --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_effects.h @@ -0,0 +1,61 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_effects.h + * + * Contents and purpose: + * Defines a generic effects interface. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_EFFECTS_H +#define _EAS_EFFECTS_H + +#include "eas_types.h" + +typedef struct +{ + EAS_RESULT (*pfInit)(EAS_DATA_HANDLE pEASData, EAS_VOID_PTR *pInstData); + void (*pfProcess)(EAS_VOID_PTR pInstData, EAS_PCM *in, EAS_PCM *out, EAS_I32 numSamples); + EAS_RESULT (*pfShutdown)(EAS_DATA_HANDLE pEASData, EAS_VOID_PTR pInstData); + EAS_RESULT (*pFGetParam)(EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue); + EAS_RESULT (*pFSetParam)(EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value); +} S_EFFECTS_INTERFACE; + +typedef struct +{ + EAS_RESULT (*pfInit)(EAS_DATA_HANDLE pEASData, EAS_VOID_PTR *pInstData); + void (*pfProcess)(EAS_VOID_PTR pInstData, EAS_I32 *in, EAS_I32 *out, EAS_I32 numSamples); + EAS_RESULT (*pfShutdown)(EAS_DATA_HANDLE pEASData, EAS_VOID_PTR pInstData); + EAS_RESULT (*pFGetParam)(EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue); + EAS_RESULT (*pFSetParam)(EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value); +} S_EFFECTS32_INTERFACE; + +/* mixer instance data */ +typedef struct +{ + S_EFFECTS_INTERFACE *effect; + EAS_VOID_PTR effectData; +} S_EFFECTS_MODULE; + +#endif /* end _EAS_EFFECTS_H */ + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_fmengine.c b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_fmengine.c new file mode 100755 index 0000000..ea7f69c --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_fmengine.c @@ -0,0 +1,785 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_fmengine.c + * + * Contents and purpose: + * Implements the low-level FM synthesizer functions. + * + * Copyright Sonic Network Inc. 2004, 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 795 $ + * $Date: 2007-08-01 00:14:45 -0700 (Wed, 01 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +/* includes */ +#include "eas_types.h" +#include "eas_math.h" +#include "eas_audioconst.h" +#include "eas_fmengine.h" + +#if defined(EAS_FM_SYNTH) || defined(EAS_HYBRID_SYNTH) || defined(EAS_SPLIT_HYBRID_SYNTH) || defined(EAS_SPLIT_FM_SYNTH) +#include "eas_data.h" +#endif + +/* externals */ +extern const EAS_I16 sineTable[]; +extern const EAS_U8 fmScaleTable[16]; + +// saturation constants for 32-bit to 16-bit conversion +#define _EAS_MAX_OUTPUT 32767 +#define _EAS_MIN_OUTPUT -32767 + +static S_FM_ENG_VOICE voices[NUM_FM_VOICES]; + +/* local prototypes */ +void FM_SynthMixVoice (S_FM_ENG_VOICE *p, EAS_U16 gainTarget, EAS_I32 numSamplesToAdd, EAS_PCM *pInputBuffer, EAS_I32 *pBuffer); + +/* used in development environment */ +#if defined(_SATURATION_MONITOR) +static EAS_BOOL bSaturated = EAS_FALSE; + +/*---------------------------------------------------------------------------- + * FM_CheckSaturation() + *---------------------------------------------------------------------------- + * Purpose: + * Allows the sound development tool to check for saturation at the voice + * level. Useful for tuning the level controls. + * + * Inputs: + * + * Outputs: + * Returns true if saturation has occurred since the last time the function + * was called. + * + * Side Effects: + * Resets the saturation flag + *---------------------------------------------------------------------------- +*/ +EAS_BOOL FM_CheckSaturation () +{ + EAS_BOOL bTemp; + bTemp = bSaturated; + bSaturated = EAS_FALSE; + return bTemp; +} +#endif + +/*---------------------------------------------------------------------------- + * FM_Saturate() + *---------------------------------------------------------------------------- + * Purpose: + * This inline function saturates a 32-bit number to 16-bits + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * Returns a 16-bit integer + *---------------------------------------------------------------------------- +*/ +EAS_INLINE EAS_I16 FM_Saturate (EAS_I32 nValue) +{ + if (nValue > _EAS_MAX_OUTPUT) + { +#if defined(_SATURATION_MONITOR) + bSaturated = EAS_TRUE; +#endif + return _EAS_MAX_OUTPUT; + } + if (nValue < _EAS_MIN_OUTPUT) + { +#if defined(_SATURATION_MONITOR) + bSaturated = EAS_TRUE; +#endif + return _EAS_MIN_OUTPUT; + } + return (EAS_I16) nValue; +} + +/*---------------------------------------------------------------------------- + * FM_Noise() + *---------------------------------------------------------------------------- + * Purpose: + * A 31-bit low-cost linear congruential PRNG algorithm used to + * generate noise. + * + * Inputs: + * pnSeed - pointer to 32-bit PRNG seed + * + * Outputs: + * Returns a 16-bit integer + *---------------------------------------------------------------------------- +*/ +EAS_INLINE EAS_I16 FM_Noise (EAS_U32 *pnSeed) +{ + *pnSeed = *pnSeed * 214013L + 2531011L; + return (EAS_I16) ((*pnSeed >> 15) & 0xffff); +} + +/*---------------------------------------------------------------------------- + * FM_PhaseInc() + *---------------------------------------------------------------------------- + * Purpose: + * Transform pitch cents to linear phase increment + * + * Inputs: + * nCents - measured in cents + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * nResult - int.frac result (where frac has NUM_DENTS_FRAC_BITS) + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_I32 FM_PhaseInc (EAS_I32 nCents) +{ + EAS_I32 nDents; + EAS_I32 nExponentInt, nExponentFrac; + EAS_I32 nTemp1, nTemp2; + EAS_I32 nResult; + + /* convert cents to dents */ + nDents = FMUL_15x15(nCents, CENTS_TO_DENTS); + nExponentInt = GET_DENTS_INT_PART(nDents) + (32 - SINE_TABLE_SIZE_IN_BITS - NUM_EG1_FRAC_BITS); + nExponentFrac = GET_DENTS_FRAC_PART(nDents); + + /* implement 2^(fracPart) as a power series */ + nTemp1 = GN2_TO_X2 + MULT_DENTS_COEF(nExponentFrac, GN2_TO_X3); + nTemp2 = GN2_TO_X1 + MULT_DENTS_COEF(nExponentFrac, nTemp1); + nTemp1 = GN2_TO_X0 + MULT_DENTS_COEF(nExponentFrac, nTemp2); + + /* + implement 2^(intPart) as + a left shift for intPart >= 0 or + a left shift for intPart < 0 + */ + if (nExponentInt >= 0) + { + /* left shift for positive exponents */ + /*lint -e{703} */ + nResult = nTemp1 << nExponentInt; + } + else + { + /* right shift for negative exponents */ + nExponentInt = -nExponentInt; + nResult = nTemp1 >> nExponentInt; + } + + return nResult; +} + +#if (NUM_OUTPUT_CHANNELS == 2) +/*---------------------------------------------------------------------------- + * FM_CalculatePan() + *---------------------------------------------------------------------------- + * Purpose: + * Assign the left and right gain values corresponding to the given pan value. + * + * Inputs: + * psVoice - ptr to the voice we have assigned for this channel + * psArticulation - ptr to this voice's articulation + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * the given voice's m_nGainLeft and m_nGainRight are assigned + *---------------------------------------------------------------------------- +*/ +static void FM_CalculatePan (EAS_I16 pan, EAS_U16 *pGainLeft, EAS_U16 *pGainRight) +{ + EAS_I32 nTemp; + EAS_INT nNetAngle; + + /* + Implement the following + sin(x) = (2-4*c)*x^2 + c + x + cos(x) = (2-4*c)*x^2 + c - x + + where c = 1/sqrt(2) + using the a0 + x*(a1 + x*a2) approach + */ + + /* + Get the Midi CC10 pan value for this voice's channel + convert the pan value to an "angle" representation suitable for + our sin, cos calculator. This representation is NOT necessarily the same + as the transform in the GM manuals because of our sin, cos calculator. + "angle" = (CC10 - 64)/128 + */ + /*lint -e{703} */ + nNetAngle = ((EAS_I32) pan) << (NUM_EG1_FRAC_BITS -7); + + /* calculate sin */ + nTemp = EG1_ONE + FMUL_15x15(COEFF_PAN_G2, nNetAngle); + nTemp = COEFF_PAN_G0 + FMUL_15x15(nTemp, nNetAngle); + + if (nTemp > SYNTH_FULL_SCALE_EG1_GAIN) + nTemp = SYNTH_FULL_SCALE_EG1_GAIN; + else if (nTemp < 0) + nTemp = 0; + + *pGainRight = (EAS_U16) nTemp; + + /* calculate cos */ + nTemp = -EG1_ONE + FMUL_15x15(COEFF_PAN_G2, nNetAngle); + nTemp = COEFF_PAN_G0 + FMUL_15x15(nTemp, nNetAngle); + + if (nTemp > SYNTH_FULL_SCALE_EG1_GAIN) + nTemp = SYNTH_FULL_SCALE_EG1_GAIN; + else if (nTemp < 0) + nTemp = 0; + + *pGainLeft = (EAS_U16) nTemp; +} +#endif /* #if (NUM_OUTPUT_CHANNELS == 2) */ + +/*---------------------------------------------------------------------------- + * FM_Operator() + *---------------------------------------------------------------------------- + * Purpose: + * Synthesizes a buffer of samples based on passed parameters. + * + * Inputs: + * nNumSamplesToAdd - number of samples to synthesize + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void FM_Operator ( + S_FM_ENG_OPER *p, + EAS_I32 numSamplesToAdd, + EAS_PCM *pBuffer, + EAS_PCM *pModBuffer, + EAS_BOOL mix, + EAS_U16 gainTarget, + EAS_I16 pitch, + EAS_U8 feedback, + EAS_I16 *pLastOutput) +{ + EAS_I32 gain; + EAS_I32 gainInc; + EAS_U32 phase; + EAS_U32 phaseInc; + EAS_U32 phaseTemp; + EAS_I32 temp; + EAS_I32 temp2; + + /* establish local gain variable */ + gain = (EAS_I32) p->gain << 16; + + /* calculate gain increment */ + /*lint -e{703} use shift for performance */ + gainInc = ((EAS_I32) gainTarget - (EAS_I32) p->gain) << (16 - SYNTH_UPDATE_PERIOD_IN_BITS); + + /* establish local phase variables */ + phase = p->phase; + + /* calculate the new phase increment */ + phaseInc = (EAS_U32) FM_PhaseInc(pitch); + + /* restore final output from previous frame for feedback loop */ + if (pLastOutput) + temp = *pLastOutput; + else + temp = 0; + + /* generate a buffer of samples */ + while (numSamplesToAdd--) + { + + /* incorporate modulation */ + if (pModBuffer) + { + /*lint -e{701} use shift for performance */ + temp = *pModBuffer++ << FM_MODULATOR_INPUT_SHIFT; + } + + /* incorporate feedback */ + else + { + /*lint -e{703} use shift for performance */ + temp = (temp * (EAS_I32) feedback) << FM_FEEDBACK_SHIFT; + } + + /*lint -e{737} */ + phaseTemp = phase + temp; + + /* fetch sample from wavetable */ + temp = sineTable[phaseTemp >> (32 - SINE_TABLE_SIZE_IN_BITS)]; + + /* increment operator phase */ + phase += phaseInc; + + /* internal gain for modulation effects */ + temp = FMUL_15x15(temp, (gain >> 16)); + + /* output gain calculation */ + temp2 = FMUL_15x15(temp, p->outputGain); + + /* saturating add to buffer */ + if (mix) + { + temp2 += *pBuffer; + *pBuffer++ = FM_Saturate(temp2); + } + + /* output to buffer */ + else + *pBuffer++ = (EAS_I16) temp2; + + /* increment gain */ + gain += gainInc; + + } + + /* save phase and gain */ + p->phase = phase; + p->gain = gainTarget; + + /* save last output for feedback in next frame */ + if (pLastOutput) + *pLastOutput = (EAS_I16) temp; +} + +/*---------------------------------------------------------------------------- + * FM_NoiseOperator() + *---------------------------------------------------------------------------- + * Purpose: + * Synthesizes a buffer of samples based on passed parameters. + * + * Inputs: + * nNumSamplesToAdd - number of samples to synthesize + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void FM_NoiseOperator ( + S_FM_ENG_OPER *p, + EAS_I32 numSamplesToAdd, + EAS_PCM *pBuffer, + EAS_BOOL mix, + EAS_U16 gainTarget, + EAS_U8 feedback, + EAS_I16 *pLastOutput) +{ + EAS_I32 gain; + EAS_I32 gainInc; + EAS_U32 phase; + EAS_I32 temp; + EAS_I32 temp2; + + /* establish local gain variable */ + gain = (EAS_I32) p->gain << 16; + + /* calculate gain increment */ + /*lint -e{703} use shift for performance */ + gainInc = ((EAS_I32) gainTarget - (EAS_I32) p->gain) << (16 - SYNTH_UPDATE_PERIOD_IN_BITS); + + /* establish local phase variables */ + phase = p->phase; + + /* establish local phase variables */ + phase = p->phase; + + /* recall last sample for filter Z-1 term */ + temp = 0; + if (pLastOutput) + temp = *pLastOutput; + + /* generate a buffer of samples */ + while (numSamplesToAdd--) + { + + /* if using filter */ + if (pLastOutput) + { + /* use PRNG for noise */ + temp2 = FM_Noise(&phase); + + /*lint -e{704} use shift for performance */ + temp += ((temp2 -temp) * feedback) >> 8; + } + else + { + temp = FM_Noise(&phase); + } + + /* internal gain for modulation effects */ + temp2 = FMUL_15x15(temp, (gain >> 16)); + + /* output gain calculation */ + temp2 = FMUL_15x15(temp2, p->outputGain); + + /* saturating add to buffer */ + if (mix) + { + temp2 += *pBuffer; + *pBuffer++ = FM_Saturate(temp2); + } + + /* output to buffer */ + else + *pBuffer++ = (EAS_I16) temp2; + + /* increment gain */ + gain += gainInc; + + } + + /* save phase and gain */ + p->phase = phase; + p->gain = gainTarget; + + /* save last output for feedback in next frame */ + if (pLastOutput) + *pLastOutput = (EAS_I16) temp; +} + +/*---------------------------------------------------------------------------- + * FM_ConfigVoice() + *---------------------------------------------------------------------------- + * Purpose: + * Receives parameters to start a new voice. + * + * Inputs: + * voiceNum - voice number to start + * vCfg - configuration data + * pMixBuffer - pointer to host supplied buffer + * + * Outputs: + * + * Side Effects: + * + * Notes: + * pFrameBuffer is not used in the test version, but is passed as a + * courtesy to split architecture implementations. It can be used as + * as pointer to the interprocessor communications buffer when the + * synthesis parameters are passed off to a DSP for synthesis. + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pFrameBuffer) pFrameBuffer not used in test version - see above */ +void FM_ConfigVoice (EAS_I32 voiceNum, S_FM_VOICE_CONFIG *vCfg, EAS_FRAME_BUFFER_HANDLE pFrameBuffer) +{ + S_FM_ENG_VOICE *pVoice; + EAS_INT i; + + /* establish pointer to voice data */ + pVoice = &voices[voiceNum]; + + /* save data */ + pVoice->feedback = vCfg->feedback; + pVoice->flags = vCfg->flags; + pVoice->voiceGain = vCfg->voiceGain; + + /* initialize Z-1 terms */ + pVoice->op1Out = 0; + pVoice->op3Out = 0; + + /* initialize operators */ + for (i = 0; i < 4; i++) + { + /* save operator data */ + pVoice->oper[i].gain = vCfg->gain[i]; + pVoice->oper[i].outputGain = vCfg->outputGain[i]; + pVoice->oper[i].outputGain = vCfg->outputGain[i]; + + /* initalize operator */ + pVoice->oper[i].phase = 0; + } + + /* calculate pan */ +#if NUM_OUTPUT_CHANNELS == 2 + FM_CalculatePan(vCfg->pan, &pVoice->gainLeft, &pVoice->gainRight); +#endif +} + +/*---------------------------------------------------------------------------- + * FM_ProcessVoice() + *---------------------------------------------------------------------------- + * Purpose: + * Synthesizes a buffer of samples based on calculated parameters. + * + * Inputs: + * nNumSamplesToAdd - number of samples to synthesize + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * + * Notes: + * pOut is not used in the test version, but is passed as a + * courtesy to split architecture implementations. It can be used as + * as pointer to the interprocessor communications buffer when the + * synthesis parameters are passed off to a DSP for synthesis. + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pOut) pOut not used in test version - see above */ +void FM_ProcessVoice ( + EAS_I32 voiceNum, + S_FM_VOICE_FRAME *pFrame, + EAS_I32 numSamplesToAdd, + EAS_PCM *pTempBuffer, + EAS_PCM *pBuffer, + EAS_I32 *pMixBuffer, + EAS_FRAME_BUFFER_HANDLE pFrameBuffer) +{ + S_FM_ENG_VOICE *p; + EAS_PCM *pOutBuf; + EAS_PCM *pMod; + EAS_BOOL mix; + EAS_U8 feedback1; + EAS_U8 feedback3; + EAS_U8 mode; + + /* establish pointer to voice data */ + p = &voices[voiceNum]; + mode = p->flags & 0x07; + + /* lookup feedback values */ + feedback1 = fmScaleTable[p->feedback >> 4]; + feedback3 = fmScaleTable[p->feedback & 0x0f]; + + /* operator 3 is on output bus in modes 0, 1, and 3 */ + if ((mode == 0) || (mode == 1) || (mode == 3)) + pOutBuf = pBuffer; + else + pOutBuf = pTempBuffer; + + if (p->flags & FLAG_FM_ENG_VOICE_OP3_NOISE) + { + FM_NoiseOperator( + p->oper + 2, + numSamplesToAdd, + pOutBuf, + EAS_FALSE, + pFrame->gain[2], + feedback3, + &p->op3Out); + } + else + { + FM_Operator( + p->oper + 2, + numSamplesToAdd, + pOutBuf, + 0, + EAS_FALSE, + pFrame->gain[2], + pFrame->pitch[2], + feedback3, + &p->op3Out); + } + + /* operator 4 is on output bus in modes 0, 1, and 2 */ + if (mode < 3) + pOutBuf = pBuffer; + else + pOutBuf = pTempBuffer; + + /* operator 4 is modulated in modes 2, 4, and 5 */ + if ((mode == 2) || (mode == 4) || (mode == 5)) + pMod = pTempBuffer; + else + pMod = 0; + + /* operator 4 is in mix mode in modes 0 and 1 */ + mix = (mode < 2); + + if (p->flags & FLAG_FM_ENG_VOICE_OP4_NOISE) + { + FM_NoiseOperator( + p->oper + 3, + numSamplesToAdd, + pOutBuf, + mix, + pFrame->gain[3], + 0, + 0); + } + else + { + FM_Operator( + p->oper + 3, + numSamplesToAdd, + pOutBuf, + pMod, + mix, + pFrame->gain[3], + pFrame->pitch[3], + 0, + 0); + } + + /* operator 1 is on output bus in mode 0 */ + if (mode == 0) + pOutBuf = pBuffer; + else + pOutBuf = pTempBuffer; + + /* operator 1 is modulated in modes 3 and 4 */ + if ((mode == 3) || (mode == 4)) + pMod = pTempBuffer; + else + pMod = 0; + + /* operator 1 is in mix mode in modes 0 and 5 */ + mix = ((mode == 0) || (mode == 5)); + + if (p->flags & FLAG_FM_ENG_VOICE_OP1_NOISE) + { + FM_NoiseOperator( + p->oper, + numSamplesToAdd, + pOutBuf, + mix, + pFrame->gain[0], + feedback1, + &p->op1Out); + } + else + { + FM_Operator( + p->oper, + numSamplesToAdd, + pOutBuf, + pMod, + mix, + pFrame->gain[0], + pFrame->pitch[0], + feedback1, + &p->op1Out); + } + + /* operator 2 is modulated in all modes except 0 */ + if (mode != 0) + pMod = pTempBuffer; + else + pMod = 0; + + /* operator 1 is in mix mode in modes 0 -3 */ + mix = (mode < 4); + + if (p->flags & FLAG_FM_ENG_VOICE_OP2_NOISE) + { + FM_NoiseOperator( + p->oper + 1, + numSamplesToAdd, + pBuffer, + mix, + pFrame->gain[1], + 0, + 0); + } + else + { + FM_Operator( + p->oper + 1, + numSamplesToAdd, + pBuffer, + pMod, + mix, + pFrame->gain[1], + pFrame->pitch[1], + 0, + 0); + } + + /* mix voice output to synthesizer output buffer */ + FM_SynthMixVoice(p, pFrame->voiceGain, numSamplesToAdd, pBuffer, pMixBuffer); +} + +/*---------------------------------------------------------------------------- + * FM_SynthMixVoice() + *---------------------------------------------------------------------------- + * Purpose: + * Mixes the voice output buffer into the final mix using an anti-zipper + * filter. + * + * Inputs: + * nNumSamplesToAdd - number of samples to synthesize + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void FM_SynthMixVoice(S_FM_ENG_VOICE *p, EAS_U16 nGainTarget, EAS_I32 numSamplesToAdd, EAS_PCM *pInputBuffer, EAS_I32 *pBuffer) +{ + EAS_I32 nGain; + EAS_I32 nGainInc; + EAS_I32 nTemp; + + /* restore previous gain */ + /*lint -e{703} */ + nGain = (EAS_I32) p->voiceGain << 16; + + /* calculate gain increment */ + /*lint -e{703} */ + nGainInc = ((EAS_I32) nGainTarget - (EAS_I32) p->voiceGain) << (16 - SYNTH_UPDATE_PERIOD_IN_BITS); + + /* mix the output buffer */ + while (numSamplesToAdd--) + { + /* output gain calculation */ + nTemp = *pInputBuffer++; + + /* sum to output buffer */ +#if (NUM_OUTPUT_CHANNELS == 2) + + /*lint -e{704} */ + nTemp = ((EAS_I32) nTemp * (nGain >> 16)) >> FM_GAIN_SHIFT; + + /*lint -e{704} */ + { + EAS_I32 nTemp2; + nTemp = nTemp >> FM_STEREO_PRE_GAIN_SHIFT; + nTemp2 = (nTemp * p->gainLeft) >> FM_STEREO_POST_GAIN_SHIFT; + *pBuffer++ += nTemp2; + nTemp2 = (nTemp * p->gainRight) >> FM_STEREO_POST_GAIN_SHIFT; + *pBuffer++ += nTemp2; + } +#else + /*lint -e{704} */ + nTemp = ((EAS_I32) nTemp * (nGain >> 16)) >> FM_MONO_GAIN_SHIFT; + *pBuffer++ += nTemp; +#endif + + /* increment gain for anti-zipper filter */ + nGain += nGainInc; + } + + /* save gain */ + p->voiceGain = nGainTarget; +} + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_fmengine.h b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_fmengine.h new file mode 100755 index 0000000..dd248f8 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_fmengine.h @@ -0,0 +1,121 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_fmengine.h + * + * Contents and purpose: + * Declarations, interfaces, and prototypes for FM synthesize low-level. + * + * Copyright Sonic Network Inc. 2004 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 664 $ + * $Date: 2007-04-25 13:11:22 -0700 (Wed, 25 Apr 2007) $ + *---------------------------------------------------------------------------- +*/ + +/* sentinel */ +#ifndef _FMENGINE_H +#define _FMENGINE_H + +/* check for split architecture */ +#if defined (EAS_SPLIT_HYBRID_SYNTH) || defined(EAS_SPLIT_FM_SYNTH) +#define FM_OFFBOARD +#endif + +/* output level to mix buffer (3 = -24dB) */ +#define FM_GAIN_SHIFT 3 +#define FM_MONO_GAIN_SHIFT 9 + +/* voice output level for stereo 15 = +6dB */ +#define FM_STEREO_PRE_GAIN_SHIFT 11 +#define FM_STEREO_POST_GAIN_SHIFT 10 + +/* modulator input level shift (21 = -30dB) */ +#define FM_MODULATOR_INPUT_SHIFT 21 + +/* feedback control level shift (7 = 0dB) */ +#define FM_FEEDBACK_SHIFT 7 + +/* synth final output level */ +#define SYNTH_POST_GAIN_SHIFT 14 + +/* LFO modulation to gain control */ +#define FM_LFO_GAIN_SHIFT 12 + +/* sine table is always a power of 2 - saves cycles in inner loop */ +#define SINE_TABLE_SIZE_IN_BITS 11 +#define SINE_TABLE_SIZE 2048 + +/* operator structure for FM engine */ +typedef struct +{ + EAS_U32 phase; /* current waveform phase */ + EAS_U16 gain; /* current internal gain */ + EAS_U16 outputGain; /* current output gain */ +} S_FM_ENG_OPER; + +typedef struct +{ + S_FM_ENG_OPER oper[4]; /* operator data */ + EAS_I16 op1Out; /* op1 output for feedback loop */ + EAS_I16 op3Out; /* op3 output for feedback loop */ + EAS_U16 voiceGain; /* LFO + channel parameters */ +#if (NUM_OUTPUT_CHANNELS == 2) + EAS_U16 gainLeft; /* left gain multiplier */ + EAS_U16 gainRight; /* right gain multiplier */ +#endif + EAS_U8 flags; /* mode bits and noise waveform flags */ + EAS_U8 feedback; /* feedback for Op1 and Op3 */ +} S_FM_ENG_VOICE; + +typedef struct +{ + EAS_U16 gain[4]; /* initial operator gain value */ + EAS_U16 outputGain[4]; /* initial operator output gain value */ + EAS_U16 voiceGain; /* initial voice gain */ + EAS_U8 flags; /* mode bits and noise waveform flags */ + EAS_U8 feedback; /* feedback for Op1 and Op3 */ +#if (NUM_OUTPUT_CHANNELS == 2) + EAS_I8 pan; /* pan value +/-64 */ +#endif +} S_FM_VOICE_CONFIG; + +typedef struct +{ + EAS_U16 gain[4]; /* new operator gain value */ + EAS_I16 pitch[4]; /* new pitch value */ + EAS_U16 voiceGain; /* new voice gain */ +} S_FM_VOICE_FRAME; + +/* bit definitions for S_FM_ENG_VOICE.flags */ +#define FLAG_FM_ENG_VOICE_OP1_NOISE 0x10 /* operator 1 source is PRNG */ +#define FLAG_FM_ENG_VOICE_OP2_NOISE 0x20 /* operator 2 source is PRNG */ +#define FLAG_FM_ENG_VOICE_OP3_NOISE 0x40 /* operator 3 source is PRNG */ +#define FLAG_FM_ENG_VOICE_OP4_NOISE 0x80 /* operator 4 source is PRNG */ + +#ifdef FM_OFFBOARD +extern EAS_BOOL FM_StartFrame (EAS_FRAME_BUFFER_HANDLE pFrameBuffer); +extern EAS_BOOL FM_EndFrame (EAS_FRAME_BUFFER_HANDLE pFrameBuffe, EAS_I32 *pMixBuffer, EAS_I16 masterGain); +#endif + +/* FM engine prototypes */ +extern void FM_ConfigVoice (EAS_I32 voiceNum, S_FM_VOICE_CONFIG *vCfg, EAS_FRAME_BUFFER_HANDLE pFrameBuffer); +extern void FM_ProcessVoice (EAS_I32 voiceNum, S_FM_VOICE_FRAME *pFrame, EAS_I32 numSamplesToAdd, EAS_PCM *pTempBuffer, EAS_PCM *pBuffer, EAS_I32 *pMixBuffer, EAS_FRAME_BUFFER_HANDLE pFrameBuffer); + +#endif +/* #ifndef _FMENGINE_H */ + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_fmsynth.c b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_fmsynth.c new file mode 100755 index 0000000..629506a --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_fmsynth.c @@ -0,0 +1,910 @@ +/*---------------------------------------------------------------------------- + * + * File: + * fmsynth.c + * + * Contents and purpose: + * Implements the high-level FM synthesizer functions. + * + * Copyright Sonic Network Inc. 2004 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 795 $ + * $Date: 2007-08-01 00:14:45 -0700 (Wed, 01 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +// includes +#include "eas_host.h" +#include "eas_report.h" + +#include "eas_data.h" +#include "eas_synth_protos.h" +#include "eas_audioconst.h" +#include "eas_fmengine.h" +#include "eas_math.h" + +/* option sanity check */ +#ifdef _REVERB +#error "No reverb for FM synthesizer" +#endif +#ifdef _CHORUS +#error "No chorus for FM synthesizer" +#endif + +/* + * WARNING: These macros can cause unwanted side effects. Use them + * with care. For example, min(x++,y++) will cause either x or y to be + * incremented twice. + */ +#define min(a,b) ((a) < (b) ? (a) : (b)) +#define max(a,b) ((a) > (b) ? (a) : (b)) + +/* pivot point for keyboard scalars */ +#define EG_SCALE_PIVOT_POINT 64 +#define KEY_SCALE_PIVOT_POINT 36 + +/* This number is the negative of the frequency of the note (in cents) of + * the sine wave played at unity. The number can be calculated as follows: + * + * MAGIC_NUMBER = 1200 * log(base2) (SINE_TABLE_SIZE * 8.175798916 / SAMPLE_RATE) + * + * 8.17578 is a reference to the frequency of MIDI note 0 + */ +#if defined (_SAMPLE_RATE_8000) +#define MAGIC_NUMBER 1279 +#elif defined (_SAMPLE_RATE_16000) +#define MAGIC_NUMBER 79 +#elif defined (_SAMPLE_RATE_20000) +#define MAGIC_NUMBER -308 +#elif defined (_SAMPLE_RATE_22050) +#define MAGIC_NUMBER -477 +#elif defined (_SAMPLE_RATE_24000) +#define MAGIC_NUMBER -623 +#elif defined (_SAMPLE_RATE_32000) +#define MAGIC_NUMBER -1121 +#elif defined (_SAMPLE_RATE_44100) +#define MAGIC_NUMBER -1677 +#elif defined (_SAMPLE_RATE_48000) +#define MAGIC_NUMBER -1823 +#endif + +/* externs */ +extern const EAS_I16 fmControlTable[128]; +extern const EAS_U16 fmRateTable[256]; +extern const EAS_U16 fmAttackTable[16]; +extern const EAS_U8 fmDecayTable[16]; +extern const EAS_U8 fmReleaseTable[16]; +extern const EAS_U8 fmScaleTable[16]; + +/* local prototypes */ +/*lint -esym(715, pVoiceMgr) standard synthesizer interface - pVoiceMgr not used */ +static EAS_RESULT FM_Initialize (S_VOICE_MGR *pVoiceMgr) { return EAS_SUCCESS; } +static EAS_RESULT FM_StartVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_U16 regionIndex); +static EAS_BOOL FM_UpdateVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_I32 *pMixBuffer, EAS_I32 numSamples); +static void FM_ReleaseVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum); +static void FM_MuteVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum); +static void FM_SustainPedal (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, S_SYNTH_CHANNEL *pChannel, EAS_I32 voiceNum); +static void FM_UpdateChannel (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel); + + +/*---------------------------------------------------------------------------- + * Synthesizer interface + *---------------------------------------------------------------------------- +*/ +const S_SYNTH_INTERFACE fmSynth = +{ + FM_Initialize, + FM_StartVoice, + FM_UpdateVoice, + FM_ReleaseVoice, + FM_MuteVoice, + FM_SustainPedal, + FM_UpdateChannel +}; + +#ifdef FM_OFFBOARD +const S_FRAME_INTERFACE fmFrameInterface = +{ + FM_StartFrame, + FM_EndFrame +}; +#endif + +/*---------------------------------------------------------------------------- + * inline functions + *---------------------------------------------------------------------------- + */ +EAS_INLINE S_FM_VOICE *GetFMVoicePtr (S_VOICE_MGR *pVoiceMgr, EAS_INT voiceNum) +{ + return &pVoiceMgr->fmVoices[voiceNum]; +} +EAS_INLINE S_SYNTH_CHANNEL *GetChannelPtr (S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice) +{ + return &pSynth->channels[pVoice->channel & 15]; +} +EAS_INLINE const S_FM_REGION *GetFMRegionPtr (S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice) +{ +#ifdef _SECONDARY_SYNTH + return &pSynth->pEAS->pFMRegions[pVoice->regionIndex & REGION_INDEX_MASK]; +#else + return &pSynth->pEAS->pFMRegions[pVoice->regionIndex]; +#endif +} + +/*---------------------------------------------------------------------------- + * FM_SynthIsOutputOperator + *---------------------------------------------------------------------------- + * Purpose: + * Returns true if the operator is a direct output and not muted + * + * Inputs: + * + * Outputs: + * Returns boolean + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL FM_SynthIsOutputOperator (const S_FM_REGION *pRegion, EAS_INT operIndex) +{ + + /* see if voice is muted */ + if ((pRegion->oper[operIndex].gain & 0xfc) == 0) + return 0; + + /* check based on mode */ + switch (pRegion->region.keyGroupAndFlags & 7) + { + + /* mode 0 - all operators are external */ + case 0: + return EAS_TRUE; + + /* mode 1 - operators 1-3 are external */ + case 1: + if (operIndex != 0) + return EAS_TRUE; + break; + + /* mode 2 - operators 1 & 3 are external */ + case 2: + if ((operIndex == 1) || (operIndex == 3)) + return EAS_TRUE; + break; + + /* mode 2 - operators 1 & 2 are external */ + case 3: + if ((operIndex == 1) || (operIndex == 2)) + return EAS_TRUE; + break; + + /* modes 4 & 5 - operator 1 is external */ + case 4: + case 5: + if (operIndex == 1) + return EAS_TRUE; + break; + + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL,"Invalid voice mode: %d", + pRegion->region.keyGroupAndFlags & 7); */ } + } + + return EAS_FALSE; +} + +/*---------------------------------------------------------------------------- + * FM_CalcEGRate() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * nKeyNumber - MIDI note + * nLogRate - logarithmic scale rate from patch data + * nKeyScale - key scaling factor for this EG + * + * Outputs: + * 16-bit linear multiplier + *---------------------------------------------------------------------------- +*/ + +static EAS_U16 FM_CalcEGRate (EAS_U8 nKeyNumber, EAS_U8 nLogRate, EAS_U8 nEGScale) +{ + EAS_I32 temp; + + /* incorporate key scaling on release rate */ + temp = (EAS_I32) nLogRate << 7; + temp += ((EAS_I32) nKeyNumber - EG_SCALE_PIVOT_POINT) * (EAS_I32) nEGScale; + + /* saturate */ + temp = max(temp, 0); + temp = min(temp, 32767); + + /* look up in rate table */ + /*lint -e{704} use shift for performance */ + return fmRateTable[temp >> 8]; +} + +/*---------------------------------------------------------------------------- + * FM_ReleaseVoice() + *---------------------------------------------------------------------------- + * Purpose: + * The selected voice is being released. + * + * Inputs: + * psEASData - pointer to S_EAS_DATA + * pVoice - pointer to voice to release + * + * Outputs: + * None + *---------------------------------------------------------------------------- +*/ +static void FM_ReleaseVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum) +{ + EAS_INT operIndex; + const S_FM_REGION *pRegion; + S_FM_VOICE *pFMVoice; + + /* check to see if voice responds to NOTE-OFF's */ + pRegion = GetFMRegionPtr(pSynth, pVoice); + if (pRegion->region.keyGroupAndFlags & REGION_FLAG_ONE_SHOT) + return; + + /* set all envelopes to release state */ + pFMVoice = GetFMVoicePtr(pVoiceMgr, voiceNum); + for (operIndex = 0; operIndex < 4; operIndex++) + { + pFMVoice->oper[operIndex].envState = eFMEnvelopeStateRelease; + + /* incorporate key scaling on release rate */ + pFMVoice->oper[operIndex].envRate = FM_CalcEGRate( + pVoice->note, + fmReleaseTable[pRegion->oper[operIndex].velocityRelease & 0x0f], + fmScaleTable[pRegion->oper[operIndex].egKeyScale >> 4]); + } /* end for (operIndex = 0; operIndex < 4; operIndex++) */ +} + +/*---------------------------------------------------------------------------- + * FM_MuteVoice() + *---------------------------------------------------------------------------- + * Purpose: + * The selected voice is being muted. + * + * Inputs: + * pVoice - pointer to voice to release + * + * Outputs: + * None + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pSynth) standard interface, pVoiceMgr not used */ +static void FM_MuteVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum) +{ + S_FM_VOICE *pFMVoice; + + /* clear deferred action flags */ + pVoice->voiceFlags &= + ~(VOICE_FLAG_DEFER_MIDI_NOTE_OFF | + VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF | + VOICE_FLAG_DEFER_MUTE); + + /* set all envelopes to muted state */ + pFMVoice = GetFMVoicePtr(pVoiceMgr, voiceNum); + pFMVoice->oper[0].envState = eFMEnvelopeStateMuted; + pFMVoice->oper[1].envState = eFMEnvelopeStateMuted; + pFMVoice->oper[2].envState = eFMEnvelopeStateMuted; + pFMVoice->oper[3].envState = eFMEnvelopeStateMuted; +} + +/*---------------------------------------------------------------------------- + * FM_SustainPedal() + *---------------------------------------------------------------------------- + * Purpose: + * The selected voice is held due to sustain pedal + * + * Inputs: + * pVoice - pointer to voice to sustain + * + * Outputs: + * None + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pChannel) standard interface, pVoiceMgr not used */ +static void FM_SustainPedal (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, S_SYNTH_CHANNEL *pChannel, EAS_I32 voiceNum) +{ + const S_FM_REGION *pRegion; + S_FM_VOICE *pFMVoice; + EAS_INT operIndex; + + pRegion = GetFMRegionPtr(pSynth, pVoice); + pFMVoice = GetFMVoicePtr(pVoiceMgr, voiceNum); + + /* check to see if any envelopes are above the sustain level */ + for (operIndex = 0; operIndex < 4; operIndex++) + { + + /* if level control or envelope gain is zero, skip this envelope */ + if (((pRegion->oper[operIndex].gain & 0xfc) == 0) || + (pFMVoice->oper[operIndex].envGain == 0)) + { + continue; + } + + /* if the envelope gain is above the sustain level, we need to catch this voice */ + if (pFMVoice->oper[operIndex].envGain >= ((EAS_U16) (pRegion->oper[operIndex].sustain & 0xfc) << 7)) + { + + /* reset envelope to decay state */ + pFMVoice->oper[operIndex].envState = eFMEnvelopeStateDecay; + + pFMVoice->oper[operIndex].envRate = FM_CalcEGRate( + pVoice->note, + fmDecayTable[pRegion->oper[operIndex].attackDecay & 0x0f], + fmScaleTable[pRegion->oper[operIndex].egKeyScale >> 4]); + + /* set voice to decay state */ + pVoice->voiceState = eVoiceStatePlay; + + /* set sustain flag */ + pVoice->voiceFlags |= VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF; + } + } /* end for (operIndex = 0; operIndex < 4; operIndex++) */ +} + +/*---------------------------------------------------------------------------- + * FM_StartVoice() + *---------------------------------------------------------------------------- + * Purpose: + * Assign the region for the given instrument using the midi key number + * and the RPN2 (coarse tuning) value. By using RPN2 as part of the + * region selection process, we reduce the amount a given sample has + * to be transposed by selecting the closest recorded root instead. + * + * This routine is the second half of SynthAssignRegion(). + * If the region was successfully found by SynthFindRegionIndex(), + * then assign the region's parameters to the voice. + * + * Setup and initialize the following voice parameters: + * m_nRegionIndex + * + * Inputs: + * pVoice - ptr to the voice we have assigned for this channel + * nRegionIndex - index of the region + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * success - could find and assign the region for this voice's note otherwise + * failure - could not find nor assign the region for this voice's note + * + * Side Effects: + * psSynthObject->m_sVoice[].m_nRegionIndex is assigned + * psSynthObject->m_sVoice[] parameters are assigned + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT FM_StartVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_U16 regionIndex) +{ + S_FM_VOICE *pFMVoice; + S_SYNTH_CHANNEL *pChannel; + const S_FM_REGION *pRegion; + EAS_I32 temp; + EAS_INT operIndex; + + /* establish pointers to data */ + pVoice->regionIndex = regionIndex; + pFMVoice = GetFMVoicePtr(pVoiceMgr, voiceNum); + pChannel = GetChannelPtr(pSynth, pVoice); + pRegion = GetFMRegionPtr(pSynth, pVoice); + + /* update static channel parameters */ + if (pChannel->channelFlags & CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS) + FM_UpdateChannel(pVoiceMgr, pSynth, pVoice->channel & 15); + + /* init the LFO */ + pFMVoice->lfoValue = 0; + pFMVoice->lfoPhase = 0; + pFMVoice->lfoDelay = (EAS_U16) (fmScaleTable[pRegion->lfoFreqDelay & 0x0f] >> 1); + +#if (NUM_OUTPUT_CHANNELS == 2) + /* calculate pan gain values only if stereo output */ + /* set up panning only at note start */ + temp = (EAS_I32) pChannel->pan - 64; + temp += (EAS_I32) pRegion->pan; + if (temp < -64) + temp = -64; + if (temp > 64) + temp = 64; + pFMVoice->pan = (EAS_I8) temp; +#endif /* #if (NUM_OUTPUT_CHANNELS == 2) */ + + /* no samples have been synthesized for this note yet */ + pVoice->voiceFlags = VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET; + + /* initialize gain value for anti-zipper filter */ + pFMVoice->voiceGain = (EAS_I16) EAS_LogToLinear16(pChannel->staticGain); + pFMVoice->voiceGain = (EAS_I16) FMUL_15x15(pFMVoice->voiceGain, pSynth->masterVolume); + + /* initialize the operators */ + for (operIndex = 0; operIndex < 4; operIndex++) + { + + /* establish operator output gain level */ + /*lint -e{701} */ + pFMVoice->oper[operIndex].outputGain = EAS_LogToLinear16(((EAS_I16) (pRegion->oper[operIndex].gain & 0xfc) - 0xfc) << 7); + + /* check for linear velocity flag */ + /*lint -e{703} */ + if (pRegion->oper[operIndex].flags & FM_OPER_FLAG_LINEAR_VELOCITY) + temp = (EAS_I32) (pVoice->velocity - 127) << 5; + else + temp = (EAS_I32) fmControlTable[pVoice->velocity]; + + /* scale velocity */ + /*lint -e{704} use shift for performance */ + temp = (temp * (EAS_I32)(pRegion->oper[operIndex].velocityRelease & 0xf0)) >> 7; + + /* include key scalar */ + temp -= ((EAS_I32) pVoice->note - KEY_SCALE_PIVOT_POINT) * (EAS_I32) fmScaleTable[pRegion->oper[operIndex].egKeyScale & 0x0f]; + + /* saturate */ + temp = min(temp, 0); + temp = max(temp, -32768); + + /* save static gain parameters */ + pFMVoice->oper[operIndex].baseGain = (EAS_I16) EAS_LogToLinear16(temp); + + /* incorporate key scaling on decay rate */ + pFMVoice->oper[operIndex].envRate = FM_CalcEGRate( + pVoice->note, + fmDecayTable[pRegion->oper[operIndex].attackDecay & 0x0f], + fmScaleTable[pRegion->oper[operIndex].egKeyScale >> 4]); + + /* if zero attack time, max out envelope and jump to decay state */ + if ((pRegion->oper[operIndex].attackDecay & 0xf0) == 0xf0) + { + + /* start out envelope at max */ + pFMVoice->oper[operIndex].envGain = 0x7fff; + + /* set envelope to decay state */ + pFMVoice->oper[operIndex].envState = eFMEnvelopeStateDecay; + } + + /* start envelope at zero and start in attack state */ + else + { + pFMVoice->oper[operIndex].envGain = 0; + pFMVoice->oper[operIndex].envState = eFMEnvelopeStateAttack; + } + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * FM_UpdateChannel() + *---------------------------------------------------------------------------- + * Purpose: + * Calculate and assign static channel parameters + * These values only need to be updated if one of the controller values + * for this channel changes. + * Called when CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS flag is set. + * + * Inputs: + * nChannel - channel to update + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * - the given channel's static gain and static pitch are updated + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pVoiceMgr) standard interface, pVoiceMgr not used */ +static void FM_UpdateChannel (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel) +{ + S_SYNTH_CHANNEL *pChannel; + EAS_I32 temp; + + pChannel = &pSynth->channels[channel]; + + /* convert CC7 volume controller to log scale */ + temp = fmControlTable[pChannel->volume]; + + /* incorporate CC11 expression controller */ + temp += fmControlTable[pChannel->expression]; + + /* saturate */ + pChannel->staticGain = (EAS_I16) max(temp,-32768); + + /* calculate pitch bend */ + /*lint -e{703} */ + temp = (((EAS_I32)(pChannel->pitchBend) << 2) - 32768); + + temp = FMUL_15x15(temp, pChannel->pitchBendSensitivity); + + /* include "magic number" compensation for sample rate and lookup table size */ + temp += MAGIC_NUMBER; + + /* if this is not a drum channel, then add in the per-channel tuning */ + if (!(pChannel->channelFlags & CHANNEL_FLAG_RHYTHM_CHANNEL)) + temp += (pChannel->finePitch + (pChannel->coarsePitch * 100)); + + /* save static pitch */ + pChannel->staticPitch = temp; + + /* Calculate LFO modulation depth */ + /* mod wheel to LFO depth */ + temp = FMUL_15x15(DEFAULT_LFO_MOD_WHEEL_TO_PITCH_CENTS, + pChannel->modWheel << (NUM_EG1_FRAC_BITS -7)); + + /* channel pressure to LFO depth */ + pChannel->lfoAmt = (EAS_I16) (temp + + FMUL_15x15(DEFAULT_LFO_CHANNEL_PRESSURE_TO_PITCH_CENTS, + pChannel->channelPressure << (NUM_EG1_FRAC_BITS -7))); + + /* clear update flag */ + pChannel->channelFlags &= ~CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS; + return; +} + +/*---------------------------------------------------------------------------- + * FM_UpdateLFO() + *---------------------------------------------------------------------------- + * Purpose: + * Calculate the LFO for the given voice + * + * Inputs: + * pVoice - ptr to the voice whose LFO we want to update + * psEASData - pointer to overall EAS data structure - used for debug only + * + * Outputs: + * + * Side Effects: + * - updates LFO values for the given voice + *---------------------------------------------------------------------------- +*/ +static void FM_UpdateLFO (S_FM_VOICE *pFMVoice, const S_FM_REGION *pRegion) +{ + + /* increment the LFO phase if the delay time has elapsed */ + if (!pFMVoice->lfoDelay) + { + /*lint -e{701} */ + pFMVoice->lfoPhase = pFMVoice->lfoPhase + (EAS_U16) (-fmControlTable[((15 - (pRegion->lfoFreqDelay >> 4)) << 3) + 4]); + + /* square wave LFO? */ + if (pRegion->region.keyGroupAndFlags & REGION_FLAG_SQUARE_WAVE) + pFMVoice->lfoValue = (EAS_I16)(pFMVoice->lfoPhase & 0x8000 ? -32767 : 32767); + + /* trick to get a triangle wave out of a sawtooth */ + else + { + pFMVoice->lfoValue = (EAS_I16) (pFMVoice->lfoPhase << 1); + /*lint -e{502} */ + if ((pFMVoice->lfoPhase > 0x3fff) && (pFMVoice->lfoPhase < 0xC000)) + pFMVoice->lfoValue = ~pFMVoice->lfoValue; + } + } + + /* still in delay */ + else + pFMVoice->lfoDelay--; + + return; +} + +/*---------------------------------------------------------------------------- + * FM_UpdateEG() + *---------------------------------------------------------------------------- + * Purpose: + * Calculate the synthesis parameters for an operator to be used during + * the next buffer + * + * Inputs: + * pVoice - pointer to the voice being updated + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL FM_UpdateEG (S_SYNTH_VOICE *pVoice, S_OPERATOR *pOper, const S_FM_OPER *pOperData, EAS_BOOL oneShot) +{ + EAS_U32 temp; + EAS_BOOL done; + + /* set flag assuming the envelope is not done */ + done = EAS_FALSE; + + /* take appropriate action based on state */ + switch (pOper->envState) + { + + case eFMEnvelopeStateAttack: + + /* the envelope is linear during the attack, so add the value */ + temp = pOper->envGain + fmAttackTable[pOperData->attackDecay >> 4]; + + /* check for end of attack */ + if (temp >= 0x7fff) + { + pOper->envGain = 0x7fff; + pOper->envState = eFMEnvelopeStateDecay; + } + else + pOper->envGain = (EAS_U16) temp; + break; + + case eFMEnvelopeStateDecay: + + /* decay is exponential, multiply by decay rate */ + pOper->envGain = (EAS_U16) FMUL_15x15(pOper->envGain, pOper->envRate); + + /* check for sustain level reached */ + temp = (EAS_U32) (pOperData->sustain & 0xfc) << 7; + if (pOper->envGain <= (EAS_U16) temp) + { + /* if this is a one-shot patch, go directly to release phase */ + if (oneShot) + { + pOper->envRate = FM_CalcEGRate( + pVoice->note, + fmReleaseTable[pOperData->velocityRelease & 0x0f], + fmScaleTable[pOperData->egKeyScale >> 4]); + pOper->envState = eFMEnvelopeStateRelease; + } + + /* normal sustaining type */ + else + { + pOper->envGain = (EAS_U16) temp; + pOper->envState = eFMEnvelopeStateSustain; + } + } + break; + + case eFMEnvelopeStateSustain: + pOper->envGain = (EAS_U16)((EAS_U16)(pOperData->sustain & 0xfc) << 7); + break; + + case eFMEnvelopeStateRelease: + + /* release is exponential, multiply by release rate */ + pOper->envGain = (EAS_U16) FMUL_15x15(pOper->envGain, pOper->envRate); + + /* fully released */ + if (pOper->envGain == 0) + { + pOper->envGain = 0; + pOper->envState = eFMEnvelopeStateMuted; + done = EAS_TRUE; + } + break; + + case eFMEnvelopeStateMuted: + pOper->envGain = 0; + done = EAS_TRUE; + break; + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL,"Invalid operator state: %d", pOper->envState); */ } + } /* end switch (pOper->m_eState) */ + + return done; +} + +/*---------------------------------------------------------------------------- + * FM_UpdateDynamic() + *---------------------------------------------------------------------------- + * Purpose: + * Calculate the synthesis parameters for this voice that will be used to + * synthesize the next buffer + * + * Inputs: + * pVoice - pointer to the voice being updated + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * Returns EAS_TRUE if voice will be fully ramped to zero at the end of + * the next synthesized buffer. + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL FM_UpdateDynamic (S_SYNTH_VOICE *pVoice, S_FM_VOICE *pFMVoice, const S_FM_REGION *pRegion, S_SYNTH_CHANNEL *pChannel) +{ + EAS_I32 temp; + EAS_I32 pitch; + EAS_I32 lfoPitch; + EAS_INT operIndex; + EAS_BOOL done; + + /* increment LFO phase */ + FM_UpdateLFO(pFMVoice, pRegion); + + /* base pitch in cents */ + pitch = pVoice->note * 100; + + /* LFO amount includes LFO depth from programming + channel dynamics */ + temp = (fmScaleTable[pRegion->vibTrem >> 4] >> 1) + pChannel->lfoAmt; + + /* multiply by LFO output to get final pitch modulation */ + lfoPitch = FMUL_15x15(pFMVoice->lfoValue, temp); + + /* flag to indicate this voice is done */ + done = EAS_TRUE; + + /* iterate through operators to establish parameters */ + for (operIndex = 0; operIndex < 4; operIndex++) + { + EAS_BOOL bTemp; + + /* set base phase increment for each operator */ + temp = pRegion->oper[operIndex].tuning + + pChannel->staticPitch; + + /* add vibrato effect unless it is disabled for this operator */ + if ((pRegion->oper[operIndex].flags & FM_OPER_FLAG_NO_VIBRATO) == 0) + temp += lfoPitch; + + /* if note is monotonic, bias to MIDI note 60 */ + if (pRegion->oper[operIndex].flags & FM_OPER_FLAG_MONOTONE) + temp += 6000; + else + temp += pitch; + pFMVoice->oper[operIndex].pitch = (EAS_I16) temp; + + /* calculate envelope, returns true if done */ + bTemp = FM_UpdateEG(pVoice, &pFMVoice->oper[operIndex], &pRegion->oper[operIndex], pRegion->region.keyGroupAndFlags & REGION_FLAG_ONE_SHOT); + + /* check if all output envelopes have completed */ + if (FM_SynthIsOutputOperator(pRegion, operIndex)) + done = done && bTemp; + } + + return done; +} + +/*---------------------------------------------------------------------------- + * FM_UpdateVoice() + *---------------------------------------------------------------------------- + * Purpose: + * Synthesize a block of samples for the given voice. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * number of samples actually written to buffer + * + * Side Effects: + * - samples are added to the presently free buffer + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL FM_UpdateVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_I32 *pMixBuffer, EAS_I32 numSamples) +{ + S_SYNTH_CHANNEL *pChannel; + const S_FM_REGION *pRegion; + S_FM_VOICE *pFMVoice; + S_FM_VOICE_CONFIG vCfg; + S_FM_VOICE_FRAME vFrame; + EAS_I32 temp; + EAS_INT oper; + EAS_U16 voiceGainTarget; + EAS_BOOL done; + + /* setup some pointers */ + pChannel = GetChannelPtr(pSynth, pVoice); + pRegion = GetFMRegionPtr(pSynth, pVoice); + pFMVoice = GetFMVoicePtr(pVoiceMgr, voiceNum); + + /* if the voice is just starting, get the voice configuration data */ + if (pVoice->voiceFlags & VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET) + { + + /* split architecture may limit the number of voice starts */ +#ifdef MAX_VOICE_STARTS + if (pVoiceMgr->numVoiceStarts == MAX_VOICE_STARTS) + return EAS_FALSE; + pVoiceMgr->numVoiceStarts++; +#endif + + /* get initial parameters */ + vCfg.feedback = pRegion->feedback; + vCfg.voiceGain = (EAS_U16) pFMVoice->voiceGain; + +#if (NUM_OUTPUT_CHANNELS == 2) + vCfg.pan = pFMVoice->pan; +#endif + + /* get voice mode */ + vCfg.flags = pRegion->region.keyGroupAndFlags & 7; + + /* get operator parameters */ + for (oper = 0; oper < 4; oper++) + { + /* calculate initial gain */ + vCfg.gain[oper] = (EAS_U16) FMUL_15x15(pFMVoice->oper[oper].baseGain, pFMVoice->oper[oper].envGain); + vCfg.outputGain[oper] = pFMVoice->oper[oper].outputGain; + + /* copy noise waveform flag */ + if (pRegion->oper[oper].flags & FM_OPER_FLAG_NOISE) + vCfg.flags |= (EAS_U8) (FLAG_FM_ENG_VOICE_OP1_NOISE << oper); + } + +#ifdef FM_OFFBOARD + FM_ConfigVoice(voiceNum, &vCfg, pVoiceMgr->pFrameBuffer); +#else + FM_ConfigVoice(voiceNum, &vCfg, NULL); +#endif + + /* clear startup flag */ + pVoice->voiceFlags &= ~VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET; + } + + /* calculate new synthesis parameters */ + done = FM_UpdateDynamic(pVoice, pFMVoice, pRegion, pChannel); + + /* calculate LFO gain modulation */ + /*lint -e{702} */ + temp = ((fmScaleTable[pRegion->vibTrem & 0x0f] >> 1) * pFMVoice->lfoValue) >> FM_LFO_GAIN_SHIFT; + + /* include channel gain */ + temp += pChannel->staticGain; + + /* -32768 or lower is infinite attenuation */ + if (temp < -32767) + voiceGainTarget = 0; + + /* translate to linear gain multiplier */ + else + voiceGainTarget = EAS_LogToLinear16(temp); + + /* include synth master volume */ + voiceGainTarget = (EAS_U16) FMUL_15x15(voiceGainTarget, pSynth->masterVolume); + + /* save target values for this frame */ + vFrame.voiceGain = voiceGainTarget; + + /* assume voice output is zero */ + pVoice->gain = 0; + + /* save operator targets for this frame */ + for (oper = 0; oper < 4; oper++) + { + vFrame.gain[oper] = (EAS_U16) FMUL_15x15(pFMVoice->oper[oper].baseGain, pFMVoice->oper[oper].envGain); + vFrame.pitch[oper] = pFMVoice->oper[oper].pitch; + + /* use the highest output envelope level as the gain for the voice stealing algorithm */ + if (FM_SynthIsOutputOperator(pRegion, oper)) + pVoice->gain = max(pVoice->gain, (EAS_I16) vFrame.gain[oper]); + } + + /* consider voice gain multiplier in calculating gain for stealing algorithm */ + pVoice->gain = (EAS_I16) FMUL_15x15(voiceGainTarget, pVoice->gain); + + /* synthesize samples */ +#ifdef FM_OFFBOARD + FM_ProcessVoice(voiceNum, &vFrame, numSamples, pVoiceMgr->operMixBuffer, pVoiceMgr->voiceBuffer, pMixBuffer, pVoiceMgr->pFrameBuffer); +#else + FM_ProcessVoice(voiceNum, &vFrame, numSamples, pVoiceMgr->operMixBuffer, pVoiceMgr->voiceBuffer, pMixBuffer, NULL); +#endif + + return done; +} + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_fmsynth.h b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_fmsynth.h new file mode 100755 index 0000000..8ceda46 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_fmsynth.h @@ -0,0 +1,81 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_fmsynth.h + * + * Contents and purpose: + * Implements the FM synthesizer functions. + * + * Copyright Sonic Network Inc. 2004 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 90 $ + * $Date: 2006-07-11 20:18:13 -0700 (Tue, 11 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef fmsynthH +#define fmsynthH + +#include "eas_data.h" + +#if defined (_FM_SYNTH) + +/* FM envelope state */ +typedef enum { + eFMEnvelopeStateAttack = 0, + eFMEnvelopeStateDecay, + eFMEnvelopeStateSustain, + eFMEnvelopeStateRelease, + eFMEnvelopeStateMuted, + eFMEnvelopeStateInvalid /* should never be in this state! */ +} E_FM_ENVELOPE_STATE; + +/*------------------------------------ + * S_OPERATOR data structure + *------------------------------------ +*/ +typedef struct s_operator_tag +{ + EAS_I16 pitch; /* operator pitch in cents */ + EAS_U16 envGain; /* envelope target */ + EAS_I16 baseGain; /* patch gain (inc. vel & key scale) */ + EAS_U16 outputGain; /* current output gain */ + EAS_U16 envRate; /* calculated envelope rate */ + EAS_U8 envState; /* envelope state */ + EAS_U8 pad; /* pad to 16-bits */ +} S_OPERATOR; +#endif + +typedef struct s_fm_voice_tag +{ + S_OPERATOR oper[4]; /* operator data */ + EAS_I16 voiceGain; /* LFO + channel parameters */ + EAS_U16 lfoPhase; /* LFO current phase */ + EAS_I16 lfoValue; /* LFO current value */ + EAS_U16 lfoDelay; /* keeps track of elapsed delay time */ + EAS_I8 pan; /* stereo pan value (-64 to +64) */ + EAS_I8 pad; /* reserved to maintain alignment */ +} S_FM_VOICE; + +#ifdef _FM_EDITOR +extern S_FM_REGION newPatch; +extern S_FM_REGION OriginalPatch; +#endif + +extern EAS_U32 freqTable[]; + +#endif diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_fmtables.c b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_fmtables.c new file mode 100755 index 0000000..a8ff0a2 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_fmtables.c @@ -0,0 +1,368 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_fmtables.c + * + * Contents and purpose: + * Contains lookup tables for the FM synthesizer + * + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + * + *---------------------------------------------------------------------------- +*/ + + +#include "eas_types.h" + +/* this table is needed by the DSP and the main processor */ +const EAS_U8 fmScaleTable[16] = +{ + 0,8,16,24,32,40,48,56,64,72,80,96,128,160,192,255 +}; + +/* these tables are needed on the main processor */ +#ifndef _DSP_CODE +const EAS_I16 fmControlTable[128] = +{ + -32768,-14313,-12265,-11067,-10217,-9558,-9019,-8563, + -8169,-7821,-7510,-7228,-6971,-6734,-6515,-6312, + -6121,-5942,-5773,-5613,-5462,-5317,-5180,-5049, + -4923,-4802,-4686,-4575,-4467,-4364,-4264,-4167, + -4073,-3982,-3894,-3808,-3725,-3644,-3565,-3488, + -3414,-3341,-3269,-3200,-3132,-3066,-3001,-2937, + -2875,-2814,-2754,-2696,-2638,-2582,-2527,-2473, + -2419,-2367,-2316,-2265,-2216,-2167,-2119,-2071, + -2025,-1979,-1934,-1889,-1846,-1803,-1760,-1718, + -1677,-1636,-1596,-1556,-1517,-1478,-1440,-1403, + -1366,-1329,-1293,-1257,-1221,-1186,-1152,-1118, + -1084,-1051,-1018,-985,-953,-921,-889,-858, + -827,-796,-766,-736,-706,-677,-648,-619, + -590,-562,-534,-506,-479,-452,-425,-398, + -371,-345,-319,-293,-268,-242,-217,-192, + -168,-143,-119,-95,-71,-47,-23,0 +}; + +const EAS_U16 fmRateTable[128] = +{ + 32767,32764,32758,32747,32731,32712,32688,32659, + 32627,32590,32548,32503,32453,32398,32340,32277, + 32211,32140,32065,31985,31902,31815,31724,31628, + 31529,31426,31319,31208,31094,30976,30854,30728, + 30599,30466,30330,30191,30048,29902,29752,29599, + 29443,29285,29123,28958,28790,28619,28445,28269, + 28090,27909,27725,27538,27349,27158,26964,26769, + 26571,26371,26169,25965,25760,25552,25343,25132, + 24920,24706,24490,24274,24056,23836,23616,23394, + 23172,22948,22724,22499,22273,22046,21819,21591, + 21363,21135,20906,20676,20447,20217,19987,19758, + 19528,19298,19069,18840,18610,18382,18153,17926, + 17698,17471,17245,17020,16795,16571,16347,16125, + 15903,15683,15463,15245,15027,14811,14596,14382, + 14169,13957,13747,13538,13331,13125,12920,12717, + 12516,12316,12117,11921,11725,11532,11340,0 +}; + +const EAS_U16 fmAttackTable[15] = +{ + 27,54,109,327,655,1310,2730,4095, + 4681,5461,6553,8191,10922,16383,32767 +}; + +const EAS_U8 fmDecayTable[16] = +{ + 4,7,10,15,20,25,30,35,40,50,60,70,80,90,100,127 +}; + +const EAS_U8 fmReleaseTable[16] = +{ + 10,15,20,25,30,35,40,45,50,60,70,80,90,100,113,127 +}; +#endif + +/* this table is needed only on the DSP */ +#if defined(_DSP_CODE) || !defined(_SPLIT_ARCHITECTURE) +//--------------------------------------------------------------------- +// sineTable +// +// Contains sine lookup table +//--------------------------------------------------------------------- + +const EAS_I16 sineTable[2048] = +{ + 0,101,201,302,402,503,603,704, + 804,905,1005,1106,1206,1307,1407,1507, + 1608,1708,1809,1909,2009,2110,2210,2310, + 2410,2511,2611,2711,2811,2911,3012,3112, + 3212,3312,3412,3512,3612,3712,3811,3911, + 4011,4111,4210,4310,4410,4509,4609,4708, + 4808,4907,5007,5106,5205,5305,5404,5503, + 5602,5701,5800,5899,5998,6096,6195,6294, + 6393,6491,6590,6688,6786,6885,6983,7081, + 7179,7277,7375,7473,7571,7669,7767,7864, + 7962,8059,8157,8254,8351,8448,8545,8642, + 8739,8836,8933,9030,9126,9223,9319,9416, + 9512,9608,9704,9800,9896,9992,10087,10183, + 10278,10374,10469,10564,10659,10754,10849,10944, + 11039,11133,11228,11322,11417,11511,11605,11699, + 11793,11886,11980,12074,12167,12260,12353,12446, + 12539,12632,12725,12817,12910,13002,13094,13187, + 13279,13370,13462,13554,13645,13736,13828,13919, + 14010,14101,14191,14282,14372,14462,14553,14643, + 14732,14822,14912,15001,15090,15180,15269,15358, + 15446,15535,15623,15712,15800,15888,15976,16063, + 16151,16238,16325,16413,16499,16586,16673,16759, + 16846,16932,17018,17104,17189,17275,17360,17445, + 17530,17615,17700,17784,17869,17953,18037,18121, + 18204,18288,18371,18454,18537,18620,18703,18785, + 18868,18950,19032,19113,19195,19276,19357,19438, + 19519,19600,19680,19761,19841,19921,20000,20080, + 20159,20238,20317,20396,20475,20553,20631,20709, + 20787,20865,20942,21019,21096,21173,21250,21326, + 21403,21479,21554,21630,21705,21781,21856,21930, + 22005,22079,22154,22227,22301,22375,22448,22521, + 22594,22667,22739,22812,22884,22956,23027,23099, + 23170,23241,23311,23382,23452,23522,23592,23662, + 23731,23801,23870,23938,24007,24075,24143,24211, + 24279,24346,24413,24480,24547,24613,24680,24746, + 24811,24877,24942,25007,25072,25137,25201,25265, + 25329,25393,25456,25519,25582,25645,25708,25770, + 25832,25893,25955,26016,26077,26138,26198,26259, + 26319,26378,26438,26497,26556,26615,26674,26732, + 26790,26848,26905,26962,27019,27076,27133,27189, + 27245,27300,27356,27411,27466,27521,27575,27629, + 27683,27737,27790,27843,27896,27949,28001,28053, + 28105,28157,28208,28259,28310,28360,28411,28460, + 28510,28560,28609,28658,28706,28755,28803,28850, + 28898,28945,28992,29039,29085,29131,29177,29223, + 29268,29313,29358,29403,29447,29491,29534,29578, + 29621,29664,29706,29749,29791,29832,29874,29915, + 29956,29997,30037,30077,30117,30156,30195,30234, + 30273,30311,30349,30387,30424,30462,30498,30535, + 30571,30607,30643,30679,30714,30749,30783,30818, + 30852,30885,30919,30952,30985,31017,31050,31082, + 31113,31145,31176,31206,31237,31267,31297,31327, + 31356,31385,31414,31442,31470,31498,31526,31553, + 31580,31607,31633,31659,31685,31710,31736,31760, + 31785,31809,31833,31857,31880,31903,31926,31949, + 31971,31993,32014,32036,32057,32077,32098,32118, + 32137,32157,32176,32195,32213,32232,32250,32267, + 32285,32302,32318,32335,32351,32367,32382,32397, + 32412,32427,32441,32455,32469,32482,32495,32508, + 32521,32533,32545,32556,32567,32578,32589,32599, + 32609,32619,32628,32637,32646,32655,32663,32671, + 32678,32685,32692,32699,32705,32711,32717,32722, + 32728,32732,32737,32741,32745,32748,32752,32755, + 32757,32759,32761,32763,32765,32766,32766,32767, + 32767,32767,32766,32766,32765,32763,32761,32759, + 32757,32755,32752,32748,32745,32741,32737,32732, + 32728,32722,32717,32711,32705,32699,32692,32685, + 32678,32671,32663,32655,32646,32637,32628,32619, + 32609,32599,32589,32578,32567,32556,32545,32533, + 32521,32508,32495,32482,32469,32455,32441,32427, + 32412,32397,32382,32367,32351,32335,32318,32302, + 32285,32267,32250,32232,32213,32195,32176,32157, + 32137,32118,32098,32077,32057,32036,32014,31993, + 31971,31949,31926,31903,31880,31857,31833,31809, + 31785,31760,31736,31710,31685,31659,31633,31607, + 31580,31553,31526,31498,31470,31442,31414,31385, + 31356,31327,31297,31267,31237,31206,31176,31145, + 31113,31082,31050,31017,30985,30952,30919,30885, + 30852,30818,30783,30749,30714,30679,30643,30607, + 30571,30535,30498,30462,30424,30387,30349,30311, + 30273,30234,30195,30156,30117,30077,30037,29997, + 29956,29915,29874,29832,29791,29749,29706,29664, + 29621,29578,29534,29491,29447,29403,29358,29313, + 29268,29223,29177,29131,29085,29039,28992,28945, + 28898,28850,28803,28755,28706,28658,28609,28560, + 28510,28460,28411,28360,28310,28259,28208,28157, + 28105,28053,28001,27949,27896,27843,27790,27737, + 27683,27629,27575,27521,27466,27411,27356,27300, + 27245,27189,27133,27076,27019,26962,26905,26848, + 26790,26732,26674,26615,26556,26497,26438,26378, + 26319,26259,26198,26138,26077,26016,25955,25893, + 25832,25770,25708,25645,25582,25519,25456,25393, + 25329,25265,25201,25137,25072,25007,24942,24877, + 24811,24746,24680,24613,24547,24480,24413,24346, + 24279,24211,24143,24075,24007,23938,23870,23801, + 23731,23662,23592,23522,23452,23382,23311,23241, + 23170,23099,23027,22956,22884,22812,22739,22667, + 22594,22521,22448,22375,22301,22227,22154,22079, + 22005,21930,21856,21781,21705,21630,21554,21479, + 21403,21326,21250,21173,21096,21019,20942,20865, + 20787,20709,20631,20553,20475,20396,20317,20238, + 20159,20080,20000,19921,19841,19761,19680,19600, + 19519,19438,19357,19276,19195,19113,19032,18950, + 18868,18785,18703,18620,18537,18454,18371,18288, + 18204,18121,18037,17953,17869,17784,17700,17615, + 17530,17445,17360,17275,17189,17104,17018,16932, + 16846,16759,16673,16586,16499,16413,16325,16238, + 16151,16063,15976,15888,15800,15712,15623,15535, + 15446,15358,15269,15180,15090,15001,14912,14822, + 14732,14643,14553,14462,14372,14282,14191,14101, + 14010,13919,13828,13736,13645,13554,13462,13370, + 13279,13187,13094,13002,12910,12817,12725,12632, + 12539,12446,12353,12260,12167,12074,11980,11886, + 11793,11699,11605,11511,11417,11322,11228,11133, + 11039,10944,10849,10754,10659,10564,10469,10374, + 10278,10183,10087,9992,9896,9800,9704,9608, + 9512,9416,9319,9223,9126,9030,8933,8836, + 8739,8642,8545,8448,8351,8254,8157,8059, + 7962,7864,7767,7669,7571,7473,7375,7277, + 7179,7081,6983,6885,6786,6688,6590,6491, + 6393,6294,6195,6096,5998,5899,5800,5701, + 5602,5503,5404,5305,5205,5106,5007,4907, + 4808,4708,4609,4509,4410,4310,4210,4111, + 4011,3911,3811,3712,3612,3512,3412,3312, + 3212,3112,3012,2911,2811,2711,2611,2511, + 2410,2310,2210,2110,2009,1909,1809,1708, + 1608,1507,1407,1307,1206,1106,1005,905, + 804,704,603,503,402,302,201,101, + 0,-101,-201,-302,-402,-503,-603,-704, + -804,-905,-1005,-1106,-1206,-1307,-1407,-1507, + -1608,-1708,-1809,-1909,-2009,-2110,-2210,-2310, + -2410,-2511,-2611,-2711,-2811,-2911,-3012,-3112, + -3212,-3312,-3412,-3512,-3612,-3712,-3811,-3911, + -4011,-4111,-4210,-4310,-4410,-4509,-4609,-4708, + -4808,-4907,-5007,-5106,-5205,-5305,-5404,-5503, + -5602,-5701,-5800,-5899,-5998,-6096,-6195,-6294, + -6393,-6491,-6590,-6688,-6786,-6885,-6983,-7081, + -7179,-7277,-7375,-7473,-7571,-7669,-7767,-7864, + -7962,-8059,-8157,-8254,-8351,-8448,-8545,-8642, + -8739,-8836,-8933,-9030,-9126,-9223,-9319,-9416, + -9512,-9608,-9704,-9800,-9896,-9992,-10087,-10183, + -10278,-10374,-10469,-10564,-10659,-10754,-10849,-10944, + -11039,-11133,-11228,-11322,-11417,-11511,-11605,-11699, + -11793,-11886,-11980,-12074,-12167,-12260,-12353,-12446, + -12539,-12632,-12725,-12817,-12910,-13002,-13094,-13187, + -13279,-13370,-13462,-13554,-13645,-13736,-13828,-13919, + -14010,-14101,-14191,-14282,-14372,-14462,-14553,-14643, + -14732,-14822,-14912,-15001,-15090,-15180,-15269,-15358, + -15446,-15535,-15623,-15712,-15800,-15888,-15976,-16063, + -16151,-16238,-16325,-16413,-16499,-16586,-16673,-16759, + -16846,-16932,-17018,-17104,-17189,-17275,-17360,-17445, + -17530,-17615,-17700,-17784,-17869,-17953,-18037,-18121, + -18204,-18288,-18371,-18454,-18537,-18620,-18703,-18785, + -18868,-18950,-19032,-19113,-19195,-19276,-19357,-19438, + -19519,-19600,-19680,-19761,-19841,-19921,-20000,-20080, + -20159,-20238,-20317,-20396,-20475,-20553,-20631,-20709, + -20787,-20865,-20942,-21019,-21096,-21173,-21250,-21326, + -21403,-21479,-21554,-21630,-21705,-21781,-21856,-21930, + -22005,-22079,-22154,-22227,-22301,-22375,-22448,-22521, + -22594,-22667,-22739,-22812,-22884,-22956,-23027,-23099, + -23170,-23241,-23311,-23382,-23452,-23522,-23592,-23662, + -23731,-23801,-23870,-23938,-24007,-24075,-24143,-24211, + -24279,-24346,-24413,-24480,-24547,-24613,-24680,-24746, + -24811,-24877,-24942,-25007,-25072,-25137,-25201,-25265, + -25329,-25393,-25456,-25519,-25582,-25645,-25708,-25770, + -25832,-25893,-25955,-26016,-26077,-26138,-26198,-26259, + -26319,-26378,-26438,-26497,-26556,-26615,-26674,-26732, + -26790,-26848,-26905,-26962,-27019,-27076,-27133,-27189, + -27245,-27300,-27356,-27411,-27466,-27521,-27575,-27629, + -27683,-27737,-27790,-27843,-27896,-27949,-28001,-28053, + -28105,-28157,-28208,-28259,-28310,-28360,-28411,-28460, + -28510,-28560,-28609,-28658,-28706,-28755,-28803,-28850, + -28898,-28945,-28992,-29039,-29085,-29131,-29177,-29223, + -29268,-29313,-29358,-29403,-29447,-29491,-29534,-29578, + -29621,-29664,-29706,-29749,-29791,-29832,-29874,-29915, + -29956,-29997,-30037,-30077,-30117,-30156,-30195,-30234, + -30273,-30311,-30349,-30387,-30424,-30462,-30498,-30535, + -30571,-30607,-30643,-30679,-30714,-30749,-30783,-30818, + -30852,-30885,-30919,-30952,-30985,-31017,-31050,-31082, + -31113,-31145,-31176,-31206,-31237,-31267,-31297,-31327, + -31356,-31385,-31414,-31442,-31470,-31498,-31526,-31553, + -31580,-31607,-31633,-31659,-31685,-31710,-31736,-31760, + -31785,-31809,-31833,-31857,-31880,-31903,-31926,-31949, + -31971,-31993,-32014,-32036,-32057,-32077,-32098,-32118, + -32137,-32157,-32176,-32195,-32213,-32232,-32250,-32267, + -32285,-32302,-32318,-32335,-32351,-32367,-32382,-32397, + -32412,-32427,-32441,-32455,-32469,-32482,-32495,-32508, + -32521,-32533,-32545,-32556,-32567,-32578,-32589,-32599, + -32609,-32619,-32628,-32637,-32646,-32655,-32663,-32671, + -32678,-32685,-32692,-32699,-32705,-32711,-32717,-32722, + -32728,-32732,-32737,-32741,-32745,-32748,-32752,-32755, + -32757,-32759,-32761,-32763,-32765,-32766,-32766,-32767, + -32767,-32767,-32766,-32766,-32765,-32763,-32761,-32759, + -32757,-32755,-32752,-32748,-32745,-32741,-32737,-32732, + -32728,-32722,-32717,-32711,-32705,-32699,-32692,-32685, + -32678,-32671,-32663,-32655,-32646,-32637,-32628,-32619, + -32609,-32599,-32589,-32578,-32567,-32556,-32545,-32533, + -32521,-32508,-32495,-32482,-32469,-32455,-32441,-32427, + -32412,-32397,-32382,-32367,-32351,-32335,-32318,-32302, + -32285,-32267,-32250,-32232,-32213,-32195,-32176,-32157, + -32137,-32118,-32098,-32077,-32057,-32036,-32014,-31993, + -31971,-31949,-31926,-31903,-31880,-31857,-31833,-31809, + -31785,-31760,-31736,-31710,-31685,-31659,-31633,-31607, + -31580,-31553,-31526,-31498,-31470,-31442,-31414,-31385, + -31356,-31327,-31297,-31267,-31237,-31206,-31176,-31145, + -31113,-31082,-31050,-31017,-30985,-30952,-30919,-30885, + -30852,-30818,-30783,-30749,-30714,-30679,-30643,-30607, + -30571,-30535,-30498,-30462,-30424,-30387,-30349,-30311, + -30273,-30234,-30195,-30156,-30117,-30077,-30037,-29997, + -29956,-29915,-29874,-29832,-29791,-29749,-29706,-29664, + -29621,-29578,-29534,-29491,-29447,-29403,-29358,-29313, + -29268,-29223,-29177,-29131,-29085,-29039,-28992,-28945, + -28898,-28850,-28803,-28755,-28706,-28658,-28609,-28560, + -28510,-28460,-28411,-28360,-28310,-28259,-28208,-28157, + -28105,-28053,-28001,-27949,-27896,-27843,-27790,-27737, + -27683,-27629,-27575,-27521,-27466,-27411,-27356,-27300, + -27245,-27189,-27133,-27076,-27019,-26962,-26905,-26848, + -26790,-26732,-26674,-26615,-26556,-26497,-26438,-26378, + -26319,-26259,-26198,-26138,-26077,-26016,-25955,-25893, + -25832,-25770,-25708,-25645,-25582,-25519,-25456,-25393, + -25329,-25265,-25201,-25137,-25072,-25007,-24942,-24877, + -24811,-24746,-24680,-24613,-24547,-24480,-24413,-24346, + -24279,-24211,-24143,-24075,-24007,-23938,-23870,-23801, + -23731,-23662,-23592,-23522,-23452,-23382,-23311,-23241, + -23170,-23099,-23027,-22956,-22884,-22812,-22739,-22667, + -22594,-22521,-22448,-22375,-22301,-22227,-22154,-22079, + -22005,-21930,-21856,-21781,-21705,-21630,-21554,-21479, + -21403,-21326,-21250,-21173,-21096,-21019,-20942,-20865, + -20787,-20709,-20631,-20553,-20475,-20396,-20317,-20238, + -20159,-20080,-20000,-19921,-19841,-19761,-19680,-19600, + -19519,-19438,-19357,-19276,-19195,-19113,-19032,-18950, + -18868,-18785,-18703,-18620,-18537,-18454,-18371,-18288, + -18204,-18121,-18037,-17953,-17869,-17784,-17700,-17615, + -17530,-17445,-17360,-17275,-17189,-17104,-17018,-16932, + -16846,-16759,-16673,-16586,-16499,-16413,-16325,-16238, + -16151,-16063,-15976,-15888,-15800,-15712,-15623,-15535, + -15446,-15358,-15269,-15180,-15090,-15001,-14912,-14822, + -14732,-14643,-14553,-14462,-14372,-14282,-14191,-14101, + -14010,-13919,-13828,-13736,-13645,-13554,-13462,-13370, + -13279,-13187,-13094,-13002,-12910,-12817,-12725,-12632, + -12539,-12446,-12353,-12260,-12167,-12074,-11980,-11886, + -11793,-11699,-11605,-11511,-11417,-11322,-11228,-11133, + -11039,-10944,-10849,-10754,-10659,-10564,-10469,-10374, + -10278,-10183,-10087,-9992,-9896,-9800,-9704,-9608, + -9512,-9416,-9319,-9223,-9126,-9030,-8933,-8836, + -8739,-8642,-8545,-8448,-8351,-8254,-8157,-8059, + -7962,-7864,-7767,-7669,-7571,-7473,-7375,-7277, + -7179,-7081,-6983,-6885,-6786,-6688,-6590,-6491, + -6393,-6294,-6195,-6096,-5998,-5899,-5800,-5701, + -5602,-5503,-5404,-5305,-5205,-5106,-5007,-4907, + -4808,-4708,-4609,-4509,-4410,-4310,-4210,-4111, + -4011,-3911,-3811,-3712,-3612,-3512,-3412,-3312, + -3212,-3112,-3012,-2911,-2811,-2711,-2611,-2511, + -2410,-2310,-2210,-2110,-2009,-1909,-1809,-1708, + -1608,-1507,-1407,-1307,-1206,-1106,-1005,-905, + -804,-704,-603,-503,-402,-302,-201,-101 +}; +#endif + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_ima_tables.c b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_ima_tables.c new file mode 100755 index 0000000..b03b4d4 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_ima_tables.c @@ -0,0 +1,54 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_ima_tables.c + * + * Contents and purpose: + * Contains the constant tables for IMA encode/decode + * + * Copyright (c) 2005 Sonic Network Inc. + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 760 $ + * $Date: 2007-07-17 23:09:36 -0700 (Tue, 17 Jul 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_types.h" + +/*---------------------------------------------------------------------------- + * ADPCM decode tables + *---------------------------------------------------------------------------- +*/ +const EAS_I16 imaIndexTable[16] = +{ + -1, -1, -1, -1, 2, 4, 6, 8, + -1, -1, -1, -1, 2, 4, 6, 8 +}; + +const EAS_I16 imaStepSizeTable[89] = +{ + 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, + 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, + 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, + 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, + 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, + 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, + 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, + 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, + 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 +}; + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_imaadpcm.c b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_imaadpcm.c new file mode 100755 index 0000000..41280b5 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_imaadpcm.c @@ -0,0 +1,368 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_imaadpcm.c + * + * Contents and purpose: + * Implements the IMA ADPCM decoder + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 847 $ + * $Date: 2007-08-27 21:30:08 -0700 (Mon, 27 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_data.h" +#include "eas_host.h" +#include "eas_pcm.h" +#include "eas_math.h" +#include "eas_report.h" + +// #define _DEBUG_IMA_ADPCM_LOCATE + +/*---------------------------------------------------------------------------- + * externs + *---------------------------------------------------------------------------- +*/ +extern const EAS_I16 imaIndexTable[]; +extern const EAS_I16 imaStepSizeTable[]; + +/*---------------------------------------------------------------------------- + * prototypes + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT IMADecoderInit (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState); +static EAS_RESULT IMADecoderSample (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState); +static void IMADecoderADPCM (S_DECODER_STATE *pState, EAS_U8 nibble); +static EAS_RESULT IMADecoderLocate (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState, EAS_I32 time); + +/*---------------------------------------------------------------------------- + * IMA ADPCM Decoder interface + *---------------------------------------------------------------------------- +*/ +const S_DECODER_INTERFACE IMADecoder = +{ + IMADecoderInit, + IMADecoderSample, + IMADecoderLocate +}; + +/*---------------------------------------------------------------------------- + * IMADecoderInit() + *---------------------------------------------------------------------------- + * Purpose: + * Initializes the IMA ADPCM decoder + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ +static EAS_RESULT IMADecoderInit (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState) +{ + pState->decoderL.step = 0; + pState->decoderR.step = 0; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMADecoderSample() + *---------------------------------------------------------------------------- + * Purpose: + * Decodes an IMA ADPCM sample + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT IMADecoderSample (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState) +{ + EAS_RESULT result; + EAS_I16 sTemp; + + /* if high nibble, decode */ + if (pState->hiNibble) + { + IMADecoderADPCM(&pState->decoderL, (EAS_U8)(pState->srcByte >> 4)); + pState->hiNibble = EAS_FALSE; + } + + /* low nibble, need to fetch another byte */ + else + { + /* check for loop */ + if ((pState->bytesLeft == 0) && (pState->loopSamples != 0)) + { + /* seek to start of loop */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pState->fileHandle, (EAS_I32) (pState->startPos + pState->loopLocation))) != EAS_SUCCESS) + return result; + pState->bytesLeft = pState->byteCount = (EAS_I32) pState->bytesLeftLoop; + pState->blockCount = 0; + pState->flags &= ~PCM_FLAGS_EMPTY; + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMADecoderSample: Rewind file to %d, bytesLeft = %d\n", pState->startPos, pState->bytesLeft); */ } + } + + /* if start of block, fetch new predictor and step index */ + if ((pState->blockSize != 0) && (pState->blockCount == 0) && (pState->bytesLeft != 0)) + { + + /* get predicted sample for left channel */ + if ((result = EAS_HWGetWord(pEASData->hwInstData, pState->fileHandle, &sTemp, EAS_FALSE)) != EAS_SUCCESS) + return result; +#ifdef _DEBUG_IMA_ADPCM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Predictor: Was %d, now %d\n", pState->decoderL.acc, sTemp); */ } +#endif + pState->decoderL.acc = pState->decoderL.x1 = sTemp; + + /* get step index for left channel - upper 8 bits are reserved */ + if ((result = EAS_HWGetWord(pEASData->hwInstData, pState->fileHandle, &sTemp, EAS_FALSE)) != EAS_SUCCESS) + return result; +#ifdef _DEBUG_IMA_ADPCM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Step: Was %d, now %d\n", pState->decoderL.step, sTemp); */ } +#endif + pState->decoderL.step = sTemp & 0xff; + + if (pState->flags & PCM_FLAGS_STEREO) + { + /* get predicted sample for right channel */ + if ((result = EAS_HWGetWord(pEASData->hwInstData, pState->fileHandle, &sTemp, EAS_FALSE)) != EAS_SUCCESS) + return result; + pState->decoderR.acc = pState->decoderR.x1 = sTemp; + + /* get step index for right channel - upper 8 bits are reserved */ + if ((result = EAS_HWGetWord(pEASData->hwInstData, pState->fileHandle, &sTemp, EAS_FALSE)) != EAS_SUCCESS) + return result; +#ifdef _DEBUG_IMA_ADPCM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Step: Was %d, now %d\n", pState->decoderR.step, sTemp); */ } +#endif + pState->decoderR.step = sTemp & 0xff; + + pState->blockCount = pState->blockSize - 8; + pState->bytesLeft -= 8; + } + else + { + pState->blockCount = pState->blockSize - 4; + pState->bytesLeft -= 4; + } + } + else + { + + /* get another ADPCM data pair */ + if (pState->bytesLeft) + { + + if ((result = EAS_HWGetByte(pEASData->hwInstData, pState->fileHandle, &pState->srcByte)) != EAS_SUCCESS) + return result; + + /* decode the low nibble */ + pState->bytesLeft--; + pState->blockCount--; + IMADecoderADPCM(&pState->decoderL, (EAS_U8)(pState->srcByte & 0x0f)); + + if (pState->flags & PCM_FLAGS_STEREO) + IMADecoderADPCM(&pState->decoderR, (EAS_U8)(pState->srcByte >> 4)); + else + pState->hiNibble = EAS_TRUE; + } + + /* out of ADPCM data, generate enough samples to fill buffer */ + else + { + pState->decoderL.x1 = pState->decoderL.x0; + pState->decoderR.x1 = pState->decoderR.x0; + } + } + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMADecoderADPCM() + *---------------------------------------------------------------------------- + * Purpose: + * Decodes an IMA ADPCM sample + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static void IMADecoderADPCM (S_DECODER_STATE *pState, EAS_U8 nibble) +{ + EAS_INT delta; + EAS_INT stepSize; + + /* get stepsize from table */ + stepSize = imaStepSizeTable[pState->step]; + + /* delta = (abs(delta) + 0.5) * step / 4 */ + delta = 0; + if (nibble & 4) + delta += stepSize; + + if (nibble & 2) + /*lint -e{702} use shift for performance */ + delta += stepSize >> 1; + + if (nibble & 1) + /*lint -e{702} use shift for performance */ + delta += stepSize >> 2; + + /*lint -e{702} use shift for performance */ + delta += stepSize >> 3; + + /* integrate the delta */ + if (nibble & 8) + pState->acc -= delta; + else + pState->acc += delta; + + /* saturate */ + if (pState->acc > 32767) + pState->acc = 32767; + if (pState->acc < -32768) + pState->acc = -32768; + pState->x1 = (EAS_PCM) pState->acc; + + /* compute new step size */ + pState->step += imaIndexTable[nibble]; + if (pState->step < 0) + pState->step = 0; + if (pState->step > 88) + pState->step = 88; + +#ifdef _DEBUG_IMA_ADPCM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "In=%u, Pred=%d, Step=%d\n", nibble, pState->acc, imaStepSizeTable[pState->step]); */ } +#endif +} + +/*---------------------------------------------------------------------------- + * IMADecoderLocate() + *---------------------------------------------------------------------------- + * Locate in an IMA ADPCM stream + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT IMADecoderLocate (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState, EAS_I32 time) +{ + EAS_RESULT result; + EAS_I32 temp; + EAS_I32 samplesPerBlock; + EAS_I32 secs, msecs; + + /* no need to calculate if time is zero */ + if (time == 0) + temp = 0; + + /* not zero */ + else + { + + /* can't seek if not a blocked file */ + if (pState->blockSize == 0) + return EAS_ERROR_FEATURE_NOT_AVAILABLE; + + /* calculate number of samples per block */ + if (pState->flags & PCM_FLAGS_STEREO) + samplesPerBlock = pState->blockSize - 7; + else + samplesPerBlock = (pState->blockSize << 1) - 7; + + /* break down into secs and msecs */ + secs = time / 1000; + msecs = time - (secs * 1000); + + /* calculate sample number fraction from msecs */ + temp = (msecs * pState->sampleRate); + temp = (temp >> 10) + ((temp * 49) >> 21); + + /* add integer sample count */ + temp += secs * pState->sampleRate; + +#ifdef _DEBUG_IMA_ADPCM_LOCATE + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x2380b977, 0x00000006 , time, temp); +#endif + + /* for looped samples, calculate position in the loop */ + if ((temp > pState->byteCount) && (pState->loopSamples != 0)) + { + EAS_I32 numBlocks; + EAS_I32 samplesPerLoop; + EAS_I32 samplesInLastBlock; + + numBlocks = (EAS_I32) (pState->loopStart / pState->blockSize); + samplesInLastBlock = (EAS_I32) pState->loopStart - (numBlocks * pState->blockSize); + if (samplesInLastBlock) + { + if (pState->flags & PCM_FLAGS_STEREO) + samplesInLastBlock = samplesInLastBlock - 7; + else + /*lint -e{703} use shift for performance */ + samplesInLastBlock = (samplesInLastBlock << 1) - 7; + } + samplesPerLoop = numBlocks * samplesPerBlock + samplesInLastBlock; + temp = temp % samplesPerLoop; +#ifdef _DEBUG_IMA_ADPCM_LOCATE + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x2380b977, 0x00000007 , numBlocks, samplesPerLoop, samplesInLastBlock, temp); +#endif + } + + /* find start of block for requested sample */ + temp = (temp / samplesPerBlock) * pState->blockSize; +#ifdef _DEBUG_IMA_ADPCM_LOCATE + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x2380b977, 0x00000008 , temp); +#endif + + } + + /* seek to new location */ + if ((result = EAS_PESeek(pEASData, pState, &temp)) != EAS_SUCCESS) + return result; + +#ifdef _DEBUG_IMA_ADPCM_LOCATE + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x2380b977, 0x00000009 , pState->bytesLeft); +#endif + + /* reset state */ + pState->blockCount = 0; + pState->hiNibble = EAS_FALSE; + if ((pState->state != EAS_STATE_PAUSING) && (pState->state != EAS_STATE_PAUSED)) + pState->state = EAS_STATE_READY; + + return EAS_SUCCESS; +} + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_imelody.c b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_imelody.c new file mode 100755 index 0000000..698c7df --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_imelody.c @@ -0,0 +1,1738 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_imelody.c + * + * Contents and purpose: + * iMelody parser + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 797 $ + * $Date: 2007-08-01 00:15:56 -0700 (Wed, 01 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +/* lint doesn't like the way some string.h files look */ +#ifdef _lint +#include "lint_stdlib.h" +#else +#include +#endif + +#include "eas_data.h" +#include "eas_miditypes.h" +#include "eas_parser.h" +#include "eas_report.h" +#include "eas_host.h" +#include "eas_midi.h" +#include "eas_config.h" +#include "eas_vm_protos.h" +#include "eas_imelodydata.h" +#include "eas_ctype.h" + +// #define _DEBUG_IMELODY + +/* increase gain for mono ringtones */ +#define IMELODY_GAIN_OFFSET 8 + +/* length of 32nd note in 1/256ths of a msec for 120 BPM tempo */ +#define DEFAULT_TICK_CONV 16000 +#define TICK_CONVERT 1920000 + +/* default channel and program for iMelody playback */ +#define IMELODY_CHANNEL 0 +#define IMELODY_PROGRAM 80 +#define IMELODY_VEL_MUL 4 +#define IMELODY_VEL_OFS 67 + +/* multiplier for fixed point triplet conversion */ +#define TRIPLET_MULTIPLIER 683 +#define TRIPLET_SHIFT 10 + +static const char* const tokens[] = +{ + "BEGIN:IMELODY", + "VERSION:", + "FORMAT:CLASS", + "NAME:", + "COMPOSER:", + "BEAT:", + "STYLE:", + "VOLUME:", + "MELODY:", + "END:IMELODY" +}; + +/* ledon or ledoff */ +static const char ledStr[] = "edo"; + +/* vibeon or vibeoff */ +static const char vibeStr[] = "ibeo"; + +/* backon or backoff */ +static const char backStr[] = "cko"; + +typedef enum +{ + TOKEN_BEGIN, + TOKEN_VERSION, + TOKEN_FORMAT, + TOKEN_NAME, + TOKEN_COMPOSER, + TOKEN_BEAT, + TOKEN_STYLE, + TOKEN_VOLUME, + TOKEN_MELODY, + TOKEN_END, + TOKEN_INVALID +} ENUM_IMELODY_TOKENS; + +/* lookup table for note values */ +static const EAS_I8 noteTable[] = { 9, 11, 0, 2, 4, 5, 7 }; + +/* inline functions */ +#ifdef _DEBUG_IMELODY +static void PutBackChar (S_IMELODY_DATA *pData) +{ + if (pData->index) + pData->index--; + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "PutBackChar '%c'\n", pData->buffer[pData->index]); */ } +} +#else +EAS_INLINE void PutBackChar (S_IMELODY_DATA *pData) { if (pData->index) pData->index--; } +#endif + + +/* local prototypes */ +static EAS_RESULT IMY_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset); +static EAS_RESULT IMY_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT IMY_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime); +static EAS_RESULT IMY_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode); +static EAS_RESULT IMY_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_STATE *pState); +static EAS_RESULT IMY_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT IMY_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT IMY_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT IMY_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT IMY_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value); +static EAS_RESULT IMY_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue); +static EAS_BOOL IMY_PlayNote (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData, EAS_I8 note, EAS_INT parserMode); +static EAS_BOOL IMY_PlayRest (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData); +static EAS_BOOL IMY_GetDuration (EAS_HW_DATA_HANDLE hwInstData, S_IMELODY_DATA *pData, EAS_I32 *pDuration); +static EAS_BOOL IMY_GetLEDState (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData); +static EAS_BOOL IMY_GetVibeState (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData); +static EAS_BOOL IMY_GetBackState (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData); +static EAS_BOOL IMY_GetVolume (EAS_HW_DATA_HANDLE hwInstData, S_IMELODY_DATA *pData, EAS_BOOL inHeader); +static EAS_BOOL IMY_GetNumber (EAS_HW_DATA_HANDLE hwInstData, S_IMELODY_DATA *pData, EAS_INT *temp, EAS_BOOL inHeader); +static EAS_RESULT IMY_ParseHeader (S_EAS_DATA *pEASData, S_IMELODY_DATA* pData); +static EAS_I8 IMY_GetNextChar (EAS_HW_DATA_HANDLE hwInstData, S_IMELODY_DATA *pData, EAS_BOOL inHeader); +static EAS_RESULT IMY_ReadLine (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle, EAS_I8 *buffer, EAS_I32 *pStartLine); +static EAS_INT IMY_ParseLine (EAS_I8 *buffer, EAS_U8 *pIndex); + + +/*---------------------------------------------------------------------------- + * + * EAS_iMelody_Parser + * + * This structure contains the functional interface for the iMelody parser + *---------------------------------------------------------------------------- +*/ +const S_FILE_PARSER_INTERFACE EAS_iMelody_Parser = +{ + IMY_CheckFileType, + IMY_Prepare, + IMY_Time, + IMY_Event, + IMY_State, + IMY_Close, + IMY_Reset, + IMY_Pause, + IMY_Resume, + NULL, + IMY_SetData, + IMY_GetData, + NULL +}; + +/*---------------------------------------------------------------------------- + * IMY_CheckFileType() + *---------------------------------------------------------------------------- + * Purpose: + * Check the file type to see if we can parse it + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT IMY_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset) +{ + S_IMELODY_DATA* pData; + EAS_I8 buffer[MAX_LINE_SIZE+1]; + EAS_U8 index; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_CheckFileType\n"); */ } +#endif + + /* read the first line of the file */ + *ppHandle = NULL; + if (IMY_ReadLine(pEASData->hwInstData, fileHandle, buffer, NULL) != EAS_SUCCESS) + return EAS_SUCCESS; + + /* check for header string */ + if (IMY_ParseLine(buffer, &index) == TOKEN_BEGIN) + { + + /* check for static memory allocation */ + if (pEASData->staticMemoryModel) + pData = EAS_CMEnumData(EAS_CM_IMELODY_DATA); + else + pData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_IMELODY_DATA)); + if (!pData) + return EAS_ERROR_MALLOC_FAILED; + EAS_HWMemSet(pData, 0, sizeof(S_IMELODY_DATA)); + + /* initialize */ + pData->fileHandle = fileHandle; + pData->fileOffset = offset; + pData->state = EAS_STATE_ERROR; + pData->state = EAS_STATE_OPEN; + + /* return a pointer to the instance data */ + *ppHandle = pData; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMY_Prepare() + *---------------------------------------------------------------------------- + * Purpose: + * Prepare to parse the file. Allocates instance data (or uses static allocation for + * static memory model). + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT IMY_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_IMELODY_DATA* pData; + EAS_RESULT result; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_Prepare\n"); */ } +#endif + + /* check for valid state */ + pData = (S_IMELODY_DATA*) pInstData; + if (pData->state != EAS_STATE_OPEN) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + /* instantiate a synthesizer */ + if ((result = VMInitMIDI(pEASData, &pData->pSynth)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitMIDI returned %d\n", result); */ } + return result; + } + + /* parse the header */ + if ((result = IMY_ParseHeader(pEASData, pData)) != EAS_SUCCESS) + return result; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Prepare: state set to EAS_STATE_READY\n"); */ } +#endif + + pData ->state = EAS_STATE_READY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMY_Time() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the time of the next event in msecs + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * pTime - pointer to variable to hold time of next event (in msecs) + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ +static EAS_RESULT IMY_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime) +{ + S_IMELODY_DATA *pData; + + pData = (S_IMELODY_DATA*) pInstData; + + /* return time in milliseconds */ + /*lint -e{704} use shift instead of division */ + *pTime = pData->time >> 8; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMY_Event() + *---------------------------------------------------------------------------- + * Purpose: + * Parse the next event in the file + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT IMY_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode) +{ + S_IMELODY_DATA* pData; + EAS_RESULT result; + EAS_I8 c; + EAS_BOOL eof; + EAS_INT temp; + + pData = (S_IMELODY_DATA*) pInstData; + if (pData->state >= EAS_STATE_OPEN) + return EAS_SUCCESS; + + /* initialize MIDI channel when the track starts playing */ + if (pData->time == 0) + { + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Event: Reset\n"); */ } +#endif + /* set program to square lead */ + VMProgramChange(pEASData->pVoiceMgr, pData->pSynth, IMELODY_CHANNEL, IMELODY_PROGRAM); + + /* set channel volume to max */ + VMControlChange(pEASData->pVoiceMgr, pData->pSynth, IMELODY_CHANNEL, 7, 127); + } + + /* check for end of note */ + if (pData->note) + { + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Stopping note %d\n", pData->note); */ } +#endif + /* stop the note */ + VMStopNote(pEASData->pVoiceMgr, pData->pSynth, IMELODY_CHANNEL, pData->note, 0); + pData->note = 0; + + /* check for rest between notes */ + if (pData->restTicks) + { + pData->time += pData->restTicks; + pData->restTicks = 0; + return EAS_SUCCESS; + } + } + + /* parse the next event */ + eof = EAS_FALSE; + while (!eof) + { + + /* get next character */ + c = IMY_GetNextChar(pEASData->hwInstData, pData, EAS_FALSE); + + switch (c) + { + /* start repeat */ + case '(': + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter repeat section\n", c); */ } +#endif + + if (pData->repeatOffset < 0) + { + pData->repeatOffset = pData->startLine + (EAS_I32) pData->index; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Repeat offset = %d\n", pData->repeatOffset); */ } +#endif + } + else + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Ignoring nested repeat section\n"); */ } + break; + + /* end repeat */ + case ')': + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "End repeat section, repeat offset = %d\n", pData->repeatOffset); */ } +#endif + /* ignore invalid repeats */ + if (pData->repeatCount >= 0) + { + + /* decrement repeat count (repeatCount == 0 means infinite loop) */ + if (pData->repeatCount > 0) + { + if (--pData->repeatCount == 0) + { + pData->repeatCount = -1; +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Repeat loop complete\n"); */ } +#endif + } + } + +//2 TEMPORARY FIX: If locating, don't do infinite loops. +//3 We need a different mode for metadata parsing where we don't loop at all + if ((parserMode == eParserModePlay) || (pData->repeatCount != 0)) + { + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Rewinding file for repeat\n"); */ } +#endif + /* rewind to start of loop */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pData->fileHandle, pData->repeatOffset)) != EAS_SUCCESS) + return result; + IMY_ReadLine(pEASData->hwInstData, pData->fileHandle, pData->buffer, &pData->startLine); + pData->index = 0; + + /* if last loop, prevent future loops */ + if (pData->repeatCount == -1) + pData->repeatOffset = -1; + } + } + break; + + /* repeat count */ + case '@': + if (!IMY_GetNumber(pEASData->hwInstData, pData, &temp, EAS_FALSE)) + eof = EAS_TRUE; + else if (pData->repeatOffset > 0) + { + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Repeat count = %dt", pData->repeatCount); */ } +#endif + if (pData->repeatCount < 0) + pData->repeatCount = (EAS_I16) temp; + } + break; + + /* volume */ + case 'V': + if (!IMY_GetVolume(pEASData->hwInstData, pData, EAS_FALSE)) + eof = EAS_TRUE; + break; + + /* flat */ + case '&': + pData->noteModifier = -1; + break; + + /* sharp */ + case '#': + pData->noteModifier = +1; + break; + + /* octave */ + case '*': + c = IMY_GetNextChar(pEASData->hwInstData, pData, EAS_FALSE); + if (IsDigit(c)) + pData->octave = (EAS_U8) ((c - '0' + 1) * 12); + else if (!c) + eof = EAS_TRUE; + break; + + /* ledon or ledoff */ + case 'l': + if (!IMY_GetLEDState(pEASData, pData)) + eof = EAS_TRUE; + break; + + /* vibeon or vibeoff */ + case 'v': + if (!IMY_GetVibeState(pEASData, pData)) + eof = EAS_TRUE; + break; + + /* either a B note or backon or backoff */ + case 'b': + if (IMY_GetNextChar(pEASData->hwInstData, pData, EAS_FALSE) == 'a') + { + if (!IMY_GetBackState(pEASData, pData)) + eof = EAS_TRUE; + } + else + { + PutBackChar(pData); + if (IMY_PlayNote(pEASData, pData, c, parserMode)) + return EAS_SUCCESS; + eof = EAS_TRUE; + } + break; + + /* rest */ + case 'r': + case 'R': + if (IMY_PlayRest(pEASData, pData)) + return EAS_SUCCESS; + eof = EAS_TRUE; + break; + + /* EOF */ + case 0: +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Event: end of iMelody file detected\n"); */ } +#endif + eof = EAS_TRUE; + break; + + /* must be a note */ + default: + c = ToLower(c); + if ((c >= 'a') && (c <= 'g')) + { + if (IMY_PlayNote(pEASData, pData, c, parserMode)) + return EAS_SUCCESS; + eof = EAS_TRUE; + } + else + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Ignoring unexpected character '%c' [0x%02x]\n", c, c); */ } + break; + } + } + + /* handle EOF */ +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Event: state set to EAS_STATE_STOPPING\n"); */ } +#endif + pData->state = EAS_STATE_STOPPING; + VMReleaseAllVoices(pEASData->pVoiceMgr, pData->pSynth); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMY_State() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current state of the stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * pState - pointer to variable to store state + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ +static EAS_RESULT IMY_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pState) +{ + S_IMELODY_DATA* pData; + + /* establish pointer to instance data */ + pData = (S_IMELODY_DATA*) pInstData; + + /* if stopping, check to see if synth voices are active */ + if (pData->state == EAS_STATE_STOPPING) + { + if (VMActiveVoices(pData->pSynth) == 0) + { + pData->state = EAS_STATE_STOPPED; +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_State: state set to EAS_STATE_STOPPED\n"); */ } +#endif + } + } + + if (pData->state == EAS_STATE_PAUSING) + { + if (VMActiveVoices(pData->pSynth) == 0) + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_State: state set to EAS_STATE_PAUSED\n"); */ } +#endif + pData->state = EAS_STATE_PAUSED; + } + } + + /* return current state */ + *pState = pData->state; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMY_Close() + *---------------------------------------------------------------------------- + * Purpose: + * Close the file and clean up + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT IMY_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_IMELODY_DATA* pData; + EAS_RESULT result; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Close: close file\n"); */ } +#endif + + pData = (S_IMELODY_DATA*) pInstData; + + /* close the file */ + if ((result = EAS_HWCloseFile(pEASData->hwInstData, pData->fileHandle)) != EAS_SUCCESS) + return result; + + /* free the synth */ + if (pData->pSynth != NULL) + VMMIDIShutdown(pEASData, pData->pSynth); + + /* if using dynamic memory, free it */ + if (!pEASData->staticMemoryModel) + EAS_HWFree(pEASData->hwInstData, pData); + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMY_Reset() + *---------------------------------------------------------------------------- + * Purpose: + * Reset the sequencer. Used for locating backwards in the file. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT IMY_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_IMELODY_DATA* pData; + EAS_RESULT result; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Reset: reset file\n"); */ } +#endif + pData = (S_IMELODY_DATA*) pInstData; + + /* reset the synth */ + VMReset(pEASData->pVoiceMgr, pData->pSynth, EAS_TRUE); + + /* reset time to zero */ + pData->time = 0; + pData->note = 0; + + /* reset file position and re-parse header */ + pData->state = EAS_STATE_ERROR; + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pData->fileHandle, pData->fileOffset)) != EAS_SUCCESS) + return result; + if ((result = IMY_ParseHeader (pEASData, pData)) != EAS_SUCCESS) + return result; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Reset: state set to EAS_STATE_ERROR\n"); */ } +#endif + + pData->state = EAS_STATE_READY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMY_Pause() + *---------------------------------------------------------------------------- + * Purpose: + * Pauses the sequencer. Mutes all voices and sets state to pause. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT IMY_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_IMELODY_DATA *pData; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Pause: pause file\n"); */ } +#endif + + /* can't pause a stopped stream */ + pData = (S_IMELODY_DATA*) pInstData; + if (pData->state == EAS_STATE_STOPPED) + return EAS_ERROR_ALREADY_STOPPED; + + /* mute the synthesizer */ + VMMuteAllVoices(pEASData->pVoiceMgr, pData->pSynth); + pData->state = EAS_STATE_PAUSING; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMY_Resume() + *---------------------------------------------------------------------------- + * Purpose: + * Resume playing after a pause, sets state back to playing. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ +static EAS_RESULT IMY_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_IMELODY_DATA *pData; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Resume: resume file\n"); */ } +#endif + + /* can't resume a stopped stream */ + pData = (S_IMELODY_DATA*) pInstData; + if (pData->state == EAS_STATE_STOPPED) + return EAS_ERROR_ALREADY_STOPPED; + + /* nothing to do but resume playback */ + pData->state = EAS_STATE_PLAY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMY_SetData() + *---------------------------------------------------------------------------- + * Purpose: + * Adjust tempo relative to song tempo + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * pInstData - pointer to iMelody instance data + * rate - rate (28-bit fractional amount) + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ +static EAS_RESULT IMY_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value) +{ + S_IMELODY_DATA *pData; + + pData = (S_IMELODY_DATA*) pInstData; + switch (param) + { + + /* set metadata callback */ + case PARSER_DATA_METADATA_CB: + EAS_HWMemCpy(&pData->metadata, (void*) value, sizeof(S_METADATA_CB)); + break; + + default: + return EAS_ERROR_INVALID_PARAMETER; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMY_GetData() + *---------------------------------------------------------------------------- + * Purpose: + * Return the file type + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * pInstData - pointer to iMelody instance data + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ +static EAS_RESULT IMY_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue) +{ + S_IMELODY_DATA *pData; + + pData = (S_IMELODY_DATA*) pInstData; + + switch (param) + { + /* return file type as iMelody */ + case PARSER_DATA_FILE_TYPE: + *pValue = EAS_FILE_IMELODY; + break; + + case PARSER_DATA_SYNTH_HANDLE: + *pValue = (EAS_I32) pData->pSynth; + break; + + case PARSER_DATA_GAIN_OFFSET: + *pValue = IMELODY_GAIN_OFFSET; + break; + + default: + return EAS_ERROR_INVALID_PARAMETER; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMY_PlayNote() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL IMY_PlayNote (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData, EAS_I8 note, EAS_INT parserMode) +{ + EAS_I32 duration; + EAS_U8 velocity; + + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_PlayNote: start note %d\n", note); */ } +#endif + + /* get the duration */ + if (!IMY_GetDuration(pEASData->hwInstData, pData, &duration)) + return EAS_FALSE; + + /* save note value */ + pData->note = (EAS_U8) (pData->octave + noteTable[note - 'a'] + pData->noteModifier); + velocity = (EAS_U8) (pData->volume ? pData->volume * IMELODY_VEL_MUL + IMELODY_VEL_OFS : 0); + + /* start note only if in play mode */ + if (parserMode == eParserModePlay) + VMStartNote(pEASData->pVoiceMgr, pData->pSynth, IMELODY_CHANNEL, pData->note, velocity); + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_PlayNote: Start note %d, duration %d\n", pData->note, duration); */ } +#endif + + /* determine note length */ + switch (pData->style) + { + case 0: + /*lint -e{704} shift for performance */ + pData->restTicks = duration >> 4; + break; + case 1: + pData->restTicks = 0; + break; + case 2: + /*lint -e{704} shift for performance */ + pData->restTicks = duration >> 1; + break; + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "IMY_PlayNote: Note style out of range: %d\n", pData->style); */ } + /*lint -e{704} shift for performance */ + pData->restTicks = duration >> 4; + break; + } + + /* next event is at end of this note */ + pData->time += duration - pData->restTicks; + + /* reset the flat/sharp modifier */ + pData->noteModifier = 0; + + return EAS_TRUE; +} + +/*---------------------------------------------------------------------------- + * IMY_PlayRest() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL IMY_PlayRest (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData) +{ + EAS_I32 duration; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_PlayRest]n"); */ } +#endif + + /* get the duration */ + if (!IMY_GetDuration(pEASData->hwInstData, pData, &duration)) + return EAS_FALSE; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_PlayRest: note duration %d\n", duration); */ } +#endif + + /* next event is at end of this note */ + pData->time += duration; + return EAS_TRUE; +} + +/*---------------------------------------------------------------------------- + * IMY_GetDuration() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ + +static EAS_BOOL IMY_GetDuration (EAS_HW_DATA_HANDLE hwInstData, S_IMELODY_DATA *pData, EAS_I32 *pDuration) +{ + EAS_I32 duration; + EAS_I8 c; + + /* get the duration */ + *pDuration = 0; + c = IMY_GetNextChar(hwInstData, pData, EAS_FALSE); + if (!c) + return EAS_FALSE; + if ((c < '0') || (c > '5')) + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetDuration: error in duration '%c'\n", c); */ } +#endif + return EAS_FALSE; + } + + /* calculate total length of note */ + duration = pData->tick * (1 << ('5' - c)); + + /* check for duration modifier */ + c = IMY_GetNextChar(hwInstData, pData, EAS_FALSE); + if (c) + { + if (c == '.') + /*lint -e{704} shift for performance */ + duration += duration >> 1; + else if (c == ':') + /*lint -e{704} shift for performance */ + duration += (duration >> 1) + (duration >> 2); + else if (c == ';') + /*lint -e{704} shift for performance */ + duration = (duration * TRIPLET_MULTIPLIER) >> TRIPLET_SHIFT; + else + PutBackChar(pData); + } + + *pDuration = duration; + return EAS_TRUE; +} + +/*---------------------------------------------------------------------------- + * IMY_GetLEDState() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL IMY_GetLEDState (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData) +{ + EAS_I8 c; + EAS_INT i; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_GetLEDState\n"); */ } +#endif + + for (i = 0; i < 5; i++) + { + c = IMY_GetNextChar(pEASData->hwInstData, pData, EAS_FALSE); + if (!c) + return EAS_FALSE; + switch (i) + { + case 3: + if (c == 'n') + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetLEDState: LED on\n"); */ } +#endif + EAS_HWLED(pEASData->hwInstData, EAS_TRUE); + return EAS_TRUE; + } + else if (c != 'f') + return EAS_FALSE; + break; + + case 4: + if (c == 'f') + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetLEDState: LED off\n"); */ } +#endif + EAS_HWLED(pEASData->hwInstData, EAS_FALSE); + return EAS_TRUE; + } + return EAS_FALSE; + + default: + if (c != ledStr[i]) + return EAS_FALSE; + break; + } + } + return EAS_FALSE; +} + +/*---------------------------------------------------------------------------- + * IMY_GetVibeState() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL IMY_GetVibeState (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData) +{ + EAS_I8 c; + EAS_INT i; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_GetVibeState\n"); */ } +#endif + + for (i = 0; i < 6; i++) + { + c = IMY_GetNextChar(pEASData->hwInstData, pData, EAS_FALSE); + if (!c) + return EAS_FALSE; + switch (i) + { + case 4: + if (c == 'n') + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetVibeState: vibrate on\n"); */ } +#endif + EAS_HWVibrate(pEASData->hwInstData, EAS_TRUE); + return EAS_TRUE; + } + else if (c != 'f') + return EAS_FALSE; + break; + + case 5: + if (c == 'f') + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetVibeState: vibrate off\n"); */ } +#endif + EAS_HWVibrate(pEASData->hwInstData, EAS_FALSE); + return EAS_TRUE; + } + return EAS_FALSE; + + default: + if (c != vibeStr[i]) + return EAS_FALSE; + break; + } + } + return EAS_FALSE; +} + +/*---------------------------------------------------------------------------- + * IMY_GetBackState() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL IMY_GetBackState (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData) +{ + EAS_I8 c; + EAS_INT i; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_GetBackState\n"); */ } +#endif + + for (i = 0; i < 5; i++) + { + c = IMY_GetNextChar(pEASData->hwInstData, pData, EAS_FALSE); + if (!c) + return EAS_FALSE; + switch (i) + { + case 3: + if (c == 'n') + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetBackState: backlight on\n"); */ } +#endif + EAS_HWBackLight(pEASData->hwInstData, EAS_TRUE); + return EAS_TRUE; + } + else if (c != 'f') + return EAS_FALSE; + break; + + case 4: + if (c == 'f') + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetBackState: backlight off\n"); */ } +#endif + EAS_HWBackLight(pEASData->hwInstData, EAS_FALSE); + return EAS_TRUE; + } + return EAS_FALSE; + + default: + if (c != backStr[i]) + return EAS_FALSE; + break; + } + } + return EAS_FALSE; +} + +/*---------------------------------------------------------------------------- + * IMY_GetVolume() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL IMY_GetVolume (EAS_HW_DATA_HANDLE hwInstData, S_IMELODY_DATA *pData, EAS_BOOL inHeader) +{ + EAS_INT temp; + EAS_I8 c; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_GetVolume\n"); */ } +#endif + + c = IMY_GetNextChar(hwInstData, pData, inHeader); + if (c == '+') + { + if (pData->volume < 15) + pData->volume++; + return EAS_TRUE; + } + else if (c == '-') + { + if (pData->volume > 0) + pData->volume--; + return EAS_TRUE; + } + else if (IsDigit(c)) + temp = c - '0'; + else + return EAS_FALSE; + + c = IMY_GetNextChar(hwInstData, pData, inHeader); + if (IsDigit(c)) + temp = temp * 10 + c - '0'; + else if (c) + PutBackChar(pData); + if ((temp >= 0) && (temp <= 15)) + { + if (inHeader && (temp == 0)) + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Ignoring V0 encountered in header\n"); */ } + else + pData->volume = (EAS_U8) temp; + } + return EAS_TRUE; +} + +/*---------------------------------------------------------------------------- + * IMY_GetNumber() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL IMY_GetNumber (EAS_HW_DATA_HANDLE hwInstData, S_IMELODY_DATA *pData, EAS_INT *temp, EAS_BOOL inHeader) +{ + EAS_BOOL ok; + EAS_I8 c; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_GetNumber\n"); */ } +#endif + + *temp = 0; + ok = EAS_FALSE; + for (;;) + { + c = IMY_GetNextChar(hwInstData, pData, inHeader); + if (IsDigit(c)) + { + *temp = *temp * 10 + c - '0'; + ok = EAS_TRUE; + } + else + { + if (c) + PutBackChar(pData); + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetNumber: value %d\n", *temp); */ } +#endif + + return ok; + } + } +} + +/*---------------------------------------------------------------------------- + * IMY_GetVersion() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL IMY_GetVersion (S_IMELODY_DATA *pData, EAS_INT *pVersion) +{ + EAS_I8 c; + EAS_INT temp; + EAS_INT version; + + version = temp = 0; + for (;;) + { + c = pData->buffer[pData->index++]; + if ((c == 0) || (c == '.')) + { + /*lint -e{701} use shift for performance */ + version = (version << 8) + temp; + if (c == 0) + { + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetVersion: version 0x%04x\n", version); */ } +#endif + + *pVersion = version; + return EAS_TRUE; + } + temp = 0; + } + else if (IsDigit(c)) + temp = (temp * 10) + c - '0'; + } +} + +/*---------------------------------------------------------------------------- + * IMY_MetaData() + *---------------------------------------------------------------------------- + * Purpose: + * Prepare to parse the file. Allocates instance data (or uses static allocation for + * static memory model). + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static void IMY_MetaData (S_IMELODY_DATA *pData, E_EAS_METADATA_TYPE metaType, EAS_I8 *buffer) +{ + EAS_I32 len; + + /* check for callback */ + if (!pData->metadata.callback) + return; + + /* copy data to host buffer */ + len = (EAS_I32) strlen((char*) buffer); + if (len >pData->metadata.bufferSize) + len = pData->metadata.bufferSize; + strncpy((char*) pData->metadata.buffer, (char*) buffer, (size_t) len); + pData->metadata.buffer[len] = 0; + + /* callback to host */ + pData->metadata.callback(metaType, pData->metadata.buffer, pData->metadata.pUserData); +} + +/*---------------------------------------------------------------------------- + * IMY_ParseHeader() + *---------------------------------------------------------------------------- + * Purpose: + * Prepare to parse the file. Allocates instance data (or uses static allocation for + * static memory model). + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT IMY_ParseHeader (S_EAS_DATA *pEASData, S_IMELODY_DATA* pData) +{ + EAS_RESULT result; + EAS_INT token; + EAS_INT temp; + EAS_I8 c; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_ParseHeader\n"); */ } +#endif + + /* initialize some defaults */ + pData->time = 0; + pData->tick = DEFAULT_TICK_CONV; + pData->note = 0; + pData->noteModifier = 0; + pData ->restTicks = 0; + pData->volume = 7; + pData->octave = 60; + pData->repeatOffset = -1; + pData->repeatCount = -1; + pData->style = 0; + + /* force the read of the first line */ + pData->index = 1; + + /* read data until we get to melody */ + for (;;) + { + /* read a line from the file and parse the token */ + if (pData->index != 0) + { + if ((result = IMY_ReadLine(pEASData->hwInstData, pData->fileHandle, pData->buffer, &pData->startLine)) != EAS_SUCCESS) + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_ParseHeader: IMY_ReadLine returned %d\n", result); */ } +#endif + return result; + } + } + token = IMY_ParseLine(pData->buffer, &pData->index); + + switch (token) + { + /* ignore these valid tokens */ + case TOKEN_BEGIN: + break; + + case TOKEN_FORMAT: + if (!IMY_GetVersion(pData, &temp)) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Invalid FORMAT field '%s'\n", pData->buffer); */ } + return EAS_ERROR_FILE_FORMAT; + } + if ((temp != 0x0100) && (temp != 0x0200)) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Unsupported FORMAT %02x\n", temp); */ } + return EAS_ERROR_UNRECOGNIZED_FORMAT; + } + break; + + case TOKEN_VERSION: + if (!IMY_GetVersion(pData, &temp)) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Invalid VERSION field '%s'\n", pData->buffer); */ } + return EAS_ERROR_FILE_FORMAT; + } + if ((temp != 0x0100) && (temp != 0x0102)) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Unsupported VERSION %02x\n", temp); */ } + return EAS_ERROR_UNRECOGNIZED_FORMAT; + } + break; + + case TOKEN_NAME: + IMY_MetaData(pData, EAS_METADATA_TITLE, pData->buffer + pData->index); + break; + + case TOKEN_COMPOSER: + IMY_MetaData(pData, EAS_METADATA_AUTHOR, pData->buffer + pData->index); + break; + + /* handle beat */ + case TOKEN_BEAT: + IMY_GetNumber(pEASData->hwInstData, pData, &temp, EAS_TRUE); + if ((temp >= 25) && (temp <= 900)) + pData->tick = TICK_CONVERT / temp; + break; + + /* handle style */ + case TOKEN_STYLE: + c = IMY_GetNextChar(pEASData->hwInstData, pData, EAS_TRUE); + if (c == 'S') + c = IMY_GetNextChar(pEASData->hwInstData, pData, EAS_TRUE); + if ((c >= '0') && (c <= '2')) + pData->style = (EAS_U8) (c - '0'); + else + { + PutBackChar(pData); + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Error in style command: %s\n", pData->buffer); */ } + } + break; + + /* handle volume */ + case TOKEN_VOLUME: + c = IMY_GetNextChar(pEASData->hwInstData, pData, EAS_TRUE); + if (c != 'V') + { + PutBackChar(pData); + if (!IsDigit(c)) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Error in volume command: %s\n", pData->buffer); */ } + break; + } + } + IMY_GetVolume(pEASData->hwInstData, pData, EAS_TRUE); + break; + + case TOKEN_MELODY: +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Header successfully parsed\n"); */ } +#endif + return EAS_SUCCESS; + + case TOKEN_END: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Unexpected END:IMELODY encountered\n"); */ } + return EAS_ERROR_FILE_FORMAT; + + default: + /* force a read of the next line */ + pData->index = 1; + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Ignoring unrecognized token in iMelody file: %s\n", pData->buffer); */ } + break; + } + } +} + +/*---------------------------------------------------------------------------- + * IMY_GetNextChar() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_I8 IMY_GetNextChar (EAS_HW_DATA_HANDLE hwInstData, S_IMELODY_DATA *pData, EAS_BOOL inHeader) +{ + EAS_I8 c; + EAS_U8 index; + + for (;;) + { + /* get next character */ + c = pData->buffer[pData->index++]; + + /* buffer empty, read more */ + if (!c) + { + /* don't read the next line in the header */ + if (inHeader) + return 0; + + pData->index = 0; + pData->buffer[0] = 0; + if (IMY_ReadLine(hwInstData, pData->fileHandle, pData->buffer, &pData->startLine) != EAS_SUCCESS) + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetNextChar: EOF\n"); */ } +#endif + return 0; + } + + /* check for END:IMELODY token */ + if (IMY_ParseLine(pData->buffer, &index) == TOKEN_END) + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetNextChar: found END:IMELODY\n"); */ } +#endif + pData->buffer[0] = 0; + return 0; + } + continue; + } + + /* ignore white space */ + if (!IsSpace(c)) + { + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetNextChar returned '%c'\n", c); */ } +#endif + return c; + } + } +} + +/*---------------------------------------------------------------------------- + * IMY_ReadLine() + *---------------------------------------------------------------------------- + * Purpose: + * Reads a line of input from the file, discarding the CR/LF + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT IMY_ReadLine (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle, EAS_I8 *buffer, EAS_I32 *pStartLine) +{ + EAS_RESULT result; + EAS_INT i; + EAS_I8 c; + + /* fetch current file position and save it */ + if (pStartLine != NULL) + { + if ((result = EAS_HWFilePos(hwInstData, fileHandle, pStartLine)) != EAS_SUCCESS) + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_ParseHeader: EAS_HWFilePos returned %d\n", result); */ } +#endif + return result; + } + } + + buffer[0] = 0; + for (i = 0; i < MAX_LINE_SIZE; ) + { + if ((result = EAS_HWGetByte(hwInstData, fileHandle, &c)) != EAS_SUCCESS) + { + if ((result == EAS_EOF) && (i > 0)) + break; + return result; + } + + /* return on LF or end of data */ + if (c == '\n') + break; + + /* store characters in buffer */ + if (c != '\r') + buffer[i++] = c; + } + buffer[i] = 0; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_ReadLine read %s\n", buffer); */ } +#endif + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMY_ParseLine() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_INT IMY_ParseLine (EAS_I8 *buffer, EAS_U8 *pIndex) +{ + EAS_INT i; + EAS_INT j; + + /* there's no strnicmp() in stdlib, so we have to roll our own */ + for (i = 0; i < TOKEN_INVALID; i++) + { + for (j = 0; ; j++) + { + /* end of token, must be a match */ + if (tokens[i][j] == 0) + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_ParseLine found token %d\n", i); */ } +#endif + *pIndex = (EAS_U8) j; + return i; + } + if (tokens[i][j] != ToUpper(buffer[j])) + break; + } + } +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_ParseLine: no token found\n"); */ } +#endif + return TOKEN_INVALID; +} + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_imelodydata.c b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_imelodydata.c new file mode 100755 index 0000000..9437e08 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_imelodydata.c @@ -0,0 +1,43 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_imelodydata.c + * + * Contents and purpose: + * SMF File Parser + * + * This file contains data definitions for the SMF parser. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 547 $ + * $Date: 2007-01-31 16:30:17 -0800 (Wed, 31 Jan 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_types.h" +#include "eas_imelodydata.h" + +/*---------------------------------------------------------------------------- + * + * eas_iMelodyData + * + * Static memory allocation for iMelody parser + *---------------------------------------------------------------------------- +*/ +S_IMELODY_DATA eas_iMelodyData; + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_imelodydata.h b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_imelodydata.h new file mode 100755 index 0000000..57c1ed0 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_imelodydata.h @@ -0,0 +1,73 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_imelodydata.h + * + * Contents and purpose: + * SMF File Parser + * + * This file contains data declarations for the iMelody parser. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 778 $ + * $Date: 2007-07-23 16:45:17 -0700 (Mon, 23 Jul 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef EAS_IMELODYDATA_H +#define EAS_IMELODYDATA_H + +#include "eas_data.h" + +/* maximum line size as specified in iMelody V1.2 spec */ +#define MAX_LINE_SIZE 75 + +/*---------------------------------------------------------------------------- + * + * S_IMELODY_DATA + * + * This structure contains the state data for the iMelody parser + *---------------------------------------------------------------------------- +*/ + +typedef struct +{ + EAS_FILE_HANDLE fileHandle; /* file handle */ + S_SYNTH *pSynth; /* pointer to synth */ + EAS_I32 fileOffset; /* offset to start of data */ + EAS_I32 time; /* current time in 256ths of a msec */ + EAS_I32 tickBase; /* basline length of 32nd note in 256th of a msec */ + EAS_I32 tick; /* actual length of 32nd note in 256th of a msec */ + EAS_I32 restTicks; /* ticks to rest after current note */ + EAS_I32 startLine; /* file offset at start of line (for repeats) */ + EAS_I32 repeatOffset; /* file offset to start of repeat section */ + S_METADATA_CB metadata; /* metadata callback */ + EAS_I16 repeatCount; /* repeat counter */ + EAS_U8 state; /* current state EAS_STATE_XXXX */ + EAS_U8 style; /* from STYLE */ + EAS_U8 index; /* index into buffer */ + EAS_U8 octave; /* octave prefix */ + EAS_U8 volume; /* current volume */ + EAS_U8 note; /* MIDI note number */ + EAS_I8 noteModifier; /* sharp or flat */ + EAS_I8 buffer[MAX_LINE_SIZE+1]; /* buffer for ASCII data */ +} S_IMELODY_DATA; + +#endif + + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_math.c b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_math.c new file mode 100755 index 0000000..dc85051 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_math.c @@ -0,0 +1,168 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_math.c + * + * Contents and purpose: + * Contains common math routines for the various audio engines. + * + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 586 $ + * $Date: 2007-03-08 20:33:04 -0800 (Thu, 08 Mar 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas.h" +#include "eas_math.h" + +/* anything less than this converts to a fraction too small to represent in 32-bits */ +#define MIN_CENTS -18000 + +/*---------------------------------------------------------------------------- + * EAS_Calculate2toX() + *---------------------------------------------------------------------------- + * Purpose: + * Calculate 2^x + * + * Inputs: + * nCents - measured in cents + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * nResult - int.frac result (where frac has NUM_DENTS_FRAC_BITS) + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_I32 EAS_Calculate2toX (EAS_I32 nCents) +{ + EAS_I32 nDents; + EAS_I32 nExponentInt, nExponentFrac; + EAS_I32 nTemp1, nTemp2; + EAS_I32 nResult; + + /* check for minimum value */ + if (nCents < MIN_CENTS) + return 0; + + /* for the time being, convert cents to dents */ + nDents = FMUL_15x15(nCents, CENTS_TO_DENTS); + + nExponentInt = GET_DENTS_INT_PART(nDents); + nExponentFrac = GET_DENTS_FRAC_PART(nDents); + + /* + implement 2^(fracPart) as a power series + */ + nTemp1 = GN2_TO_X2 + MULT_DENTS_COEF(nExponentFrac, GN2_TO_X3); + nTemp2 = GN2_TO_X1 + MULT_DENTS_COEF(nExponentFrac, nTemp1); + nTemp1 = GN2_TO_X0 + MULT_DENTS_COEF(nExponentFrac, nTemp2); + + /* + implement 2^(intPart) as + a left shift for intPart >= 0 or + a left shift for intPart < 0 + */ + if (nExponentInt >= 0) + { + /* left shift for positive exponents */ + /*lint -e{703} */ + nResult = nTemp1 << nExponentInt; + } + else + { + /* right shift for negative exponents */ + nExponentInt = -nExponentInt; + nResult = nTemp1 >> nExponentInt; + } + + return nResult; +} + +/*---------------------------------------------------------------------------- + * EAS_LogToLinear16() + *---------------------------------------------------------------------------- + * Purpose: + * Transform log value to linear gain multiplier using piece-wise linear + * approximation + * + * Inputs: + * nGain - log scale value in 20.10 format. Even though gain is normally + * stored in 6.10 (16-bit) format we use 32-bit numbers here to eliminate + * the need for saturation checking when combining gain values. + * + * Outputs: + * Returns a 16-bit linear value approximately equal to 2^(nGain/1024) + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_U16 EAS_LogToLinear16 (EAS_I32 nGain) +{ + EAS_INT nExp; + EAS_U16 nTemp; + + /* bias to positive */ + nGain += 32767; + + /* check for infinite attenuation */ + if (nGain < 0) + return 0; + + /* extract the exponent */ + nExp = 31 - (nGain >> 10); + + /* check for maximum output */ + if (nExp < 0) + return 0x7fff; + + /* extract mantissa and restore implied 1 bit */ + nTemp = (EAS_U16)((((nGain & 0x3ff) << 4) | 0x4000) >> nExp); + + /* use shift to approximate power-of-2 operation */ + return nTemp; +} + +/*---------------------------------------------------------------------------- + * EAS_VolumeToGain() + *---------------------------------------------------------------------------- + * Purpose: + * Transform volume control in 1dB increments to gain multiplier + * + * Inputs: + * volume - 100 = 0dB, 99 = -1dB, 0 = -inf + * + * Outputs: + * Returns a 16-bit linear value + *---------------------------------------------------------------------------- +*/ +EAS_I16 EAS_VolumeToGain (EAS_INT volume) +{ + /* check for limits */ + if (volume <= 0) + return 0; + if (volume >= 100) + return 0x7fff; + + /*lint -e{702} use shift instead of division */ + return (EAS_I16) EAS_Calculate2toX((((volume - EAS_MAX_VOLUME) * 204099) >> 10) - 1); +} + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_math.h b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_math.h new file mode 100755 index 0000000..f240b51 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_math.h @@ -0,0 +1,412 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_math.h + * + * Contents and purpose: + * Contains common math routines for the various audio engines. + * + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 584 $ + * $Date: 2007-03-08 09:49:24 -0800 (Thu, 08 Mar 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_MATH_H +#define _EAS_MATH_H + + +/** coefs for pan, generates sin, cos */ +#define COEFF_PAN_G2 -27146 /* -0.82842712474619 = 2 - 4/sqrt(2) */ +#define COEFF_PAN_G0 23170 /* 0.707106781186547 = 1/sqrt(2) */ + +/* +coefficients for approximating +2^x = gn2toX0 + gn2toX1*x + gn2toX2*x^2 + gn2toX3*x^3 +where x is a int.frac number representing number of octaves. +Actually, we approximate only the 2^(frac) using the power series +and implement the 2^(int) as a shift, so that +2^x == 2^(int.frac) == 2^(int) * 2^(fract) + == (gn2toX0 + gn2toX1*x + gn2toX2*x^2 + gn2toX3*x^3) << (int) + +The gn2toX.. were generated using a best fit for a 3rd +order polynomial, instead of taking the coefficients from +a truncated Taylor (or Maclaurin?) series. +*/ + +#define GN2_TO_X0 32768 /* 1 */ +#define GN2_TO_X1 22833 /* 0.696807861328125 */ +#define GN2_TO_X2 7344 /* 0.22412109375 */ +#define GN2_TO_X3 2588 /* 0.0789794921875 */ + +/*---------------------------------------------------------------------------- + * Fixed Point Math + *---------------------------------------------------------------------------- + * These macros are used for fixed point multiplies. If the processor + * supports fixed point multiplies, replace these macros with inline + * assembly code to improve performance. + *---------------------------------------------------------------------------- +*/ + +/* Fixed point multiply 0.15 x 0.15 = 0.15 returned as 32-bits */ +#define FMUL_15x15(a,b) \ + /*lint -e(704) */ \ + (((EAS_I32)(a) * (EAS_I32)(b)) >> 15) + +/* Fixed point multiply 0.7 x 0.7 = 0.15 returned as 32-bits */ +#define FMUL_7x7(a,b) \ + /*lint -e(704) */ \ + (((EAS_I32)(a) * (EAS_I32)(b) ) << 1) + +/* Fixed point multiply 0.8 x 0.8 = 0.15 returned as 32-bits */ +#define FMUL_8x8(a,b) \ + /*lint -e(704) */ \ + (((EAS_I32)(a) * (EAS_I32)(b) ) >> 1) + +/* Fixed point multiply 0.8 x 1.15 = 0.15 returned as 32-bits */ +#define FMUL_8x15(a,b) \ + /*lint -e(704) */ \ + (((EAS_I32)((a) << 7) * (EAS_I32)(b)) >> 15) + +/* macros for fractional phase accumulator */ +/* +Note: changed the _U32 to _I32 on 03/14/02. This should not +affect the phase calculations, and should allow us to reuse these +macros for other audio sample related math. +*/ +#define HARDWARE_BIT_WIDTH 32 + +#define NUM_PHASE_INT_BITS 1 +#define NUM_PHASE_FRAC_BITS 15 + +#define PHASE_FRAC_MASK (EAS_U32) ((0x1L << NUM_PHASE_FRAC_BITS) -1) + +#define GET_PHASE_INT_PART(x) (EAS_U32)((EAS_U32)(x) >> NUM_PHASE_FRAC_BITS) +#define GET_PHASE_FRAC_PART(x) (EAS_U32)((EAS_U32)(x) & PHASE_FRAC_MASK) + +#define DEFAULT_PHASE_FRAC 0 +#define DEFAULT_PHASE_INT 0 + +/* +Linear interpolation calculates: +output = (1-frac) * sample[n] + (frac) * sample[n+1] + +where conceptually 0 <= frac < 1 + +For a fixed point implementation, frac is actually an integer value +with an implied binary point one position to the left. The value of +one (unity) is given by PHASE_ONE +one half and one quarter are useful for 4-point linear interp. +*/ +#define PHASE_ONE (EAS_I32) (0x1L << NUM_PHASE_FRAC_BITS) + +/* + Multiply the signed audio sample by the unsigned fraction. +- a is the signed audio sample +- b is the unsigned fraction (cast to signed int as long as coef + uses (n-1) or less bits, where n == hardware bit width) +*/ +#define MULT_AUDIO_COEF(audio,coef) /*lint -e704 */ \ + (EAS_I32)( \ + ( \ + ((EAS_I32)(audio)) * ((EAS_I32)(coef)) \ + ) \ + >> NUM_PHASE_FRAC_BITS \ + ) \ + /* lint +704 */ + +/* wet / dry calculation macros */ +#define NUM_WET_DRY_FRAC_BITS 7 // 15 +#define NUM_WET_DRY_INT_BITS 9 // 1 + +/* define a 1.0 */ +#define WET_DRY_ONE (EAS_I32) ((0x1L << NUM_WET_DRY_FRAC_BITS)) +#define WET_DRY_MINUS_ONE (EAS_I32) (~WET_DRY_ONE) +#define WET_DRY_FULL_SCALE (EAS_I32) (WET_DRY_ONE - 1) + +#define MULT_AUDIO_WET_DRY_COEF(audio,coef) /*lint -e(702) */ \ + (EAS_I32)( \ + ( \ + ((EAS_I32)(audio)) * ((EAS_I32)(coef)) \ + ) \ + >> NUM_WET_DRY_FRAC_BITS \ + ) + +/* Envelope 1 (EG1) calculation macros */ +#define NUM_EG1_INT_BITS 1 +#define NUM_EG1_FRAC_BITS 15 + +/* the max positive gain used in the synth for EG1 */ +/* SYNTH_FULL_SCALE_EG1_GAIN must match the value in the dls2eas +converter, otherwise, the values we read from the .eas file are bogus. */ +#define SYNTH_FULL_SCALE_EG1_GAIN (EAS_I32) ((0x1L << NUM_EG1_FRAC_BITS) -1) + +/* define a 1.0 */ +#define EG1_ONE (EAS_I32) ((0x1L << NUM_EG1_FRAC_BITS)) +#define EG1_MINUS_ONE (EAS_I32) (~SYNTH_FULL_SCALE_EG1_GAIN) + +#define EG1_HALF (EAS_I32) (EG1_ONE/2) +#define EG1_MINUS_HALF (EAS_I32) (EG1_MINUS_ONE/2) + +/* +We implement the EG1 using a linear gain value, which means that the +attack segment is handled by incrementing (adding) the linear gain. +However, EG1 treats the Decay, Sustain, and Release differently than +the Attack portion. For Decay, Sustain, and Release, the gain is +linear on dB scale, which is equivalent to exponential damping on +a linear scale. Because we use a linear gain for EG1, we implement +the Decay and Release as multiplication (instead of incrementing +as we did for the attack segment). +Therefore, we need the following macro to implement the multiplication +(i.e., exponential damping) during the Decay and Release segments of +the EG1 +*/ +#define MULT_EG1_EG1(gain,damping) /*lint -e(704) */ \ + (EAS_I32)( \ + ( \ + ((EAS_I32)(gain)) * ((EAS_I32)(damping)) \ + ) \ + >> NUM_EG1_FRAC_BITS \ + ) + +// Use the following macro specifically for the filter, when multiplying +// the b1 coefficient. The 0 <= |b1| < 2, which therefore might overflow +// in certain conditions because we store b1 as a 1.15 value. +// Instead, we could store b1 as b1p (b1' == b1 "prime") where +// b1p == b1/2, thus ensuring no potential overflow for b1p because +// 0 <= |b1p| < 1 +// However, during the filter calculation, we must account for the fact +// that we are using b1p instead of b1, and thereby multiply by +// an extra factor of 2. Rather than multiply by an extra factor of 2, +// we can instead shift the result right by one less, hence the +// modified shift right value of (NUM_EG1_FRAC_BITS -1) +#define MULT_EG1_EG1_X2(gain,damping) /*lint -e(702) */ \ + (EAS_I32)( \ + ( \ + ((EAS_I32)(gain)) * ((EAS_I32)(damping)) \ + ) \ + >> (NUM_EG1_FRAC_BITS -1) \ + ) + +#define SATURATE_EG1(x) /*lint -e{734} saturation operation */ \ + ((EAS_I32)(x) > SYNTH_FULL_SCALE_EG1_GAIN) ? (SYNTH_FULL_SCALE_EG1_GAIN) : \ + ((EAS_I32)(x) < EG1_MINUS_ONE) ? (EG1_MINUS_ONE) : (x); + + +/* use "digital cents" == "dents" instead of cents */ +/* we coudl re-use the phase frac macros, but if we do, +we must change the phase macros to cast to _I32 instead of _U32, +because using a _U32 cast causes problems when shifting the exponent +for the 2^x calculation, because right shift a negative values MUST +be sign extended, or else the 2^x calculation is wrong */ + +/* use "digital cents" == "dents" instead of cents */ +#define NUM_DENTS_FRAC_BITS 12 +#define NUM_DENTS_INT_BITS (HARDWARE_BIT_WIDTH - NUM_DENTS_FRAC_BITS) + +#define DENTS_FRAC_MASK (EAS_I32) ((0x1L << NUM_DENTS_FRAC_BITS) -1) + +#define GET_DENTS_INT_PART(x) /*lint -e(704) */ \ + (EAS_I32)((EAS_I32)(x) >> NUM_DENTS_FRAC_BITS) + +#define GET_DENTS_FRAC_PART(x) (EAS_I32)((EAS_I32)(x) & DENTS_FRAC_MASK) + +#define DENTS_ONE (EAS_I32) (0x1L << NUM_DENTS_FRAC_BITS) + +/* use CENTS_TO_DENTS to convert a value in cents to dents */ +#define CENTS_TO_DENTS (EAS_I32) (DENTS_ONE * (0x1L << NUM_EG1_FRAC_BITS) / 1200L) \ + + +/* +For gain, the LFO generates a value that modulates in terms +of dB. However, we use a linear gain value, so we must convert +the LFO value in dB to a linear gain. Normally, we would use +linear gain = 10^x, where x = LFO value in dB / 20. +Instead, we implement 10^x using our 2^x approximation. +because + + 10^x = 2^(log2(10^x)) = 2^(x * log2(10)) + +so we need to multiply by log2(10) which is just a constant. +Ah, but just wait -- our 2^x actually doesn't exactly implement +2^x, but it actually assumes that the input is in cents, and within +the 2^x approximation converts its input from cents to octaves +by dividing its input by 1200. + +So, in order to convert the LFO gain value in dB to something +that our existing 2^x approximation can use, multiply the LFO gain +by log2(10) * 1200 / 20 + +The divide by 20 helps convert dB to linear gain, and we might +as well incorporate that operation into this conversion. +Of course, we need to keep some fractional bits, so multiply +the constant by NUM_EG1_FRAC_BITS +*/ + +/* use LFO_GAIN_TO_CENTS to convert the LFO gain value to cents */ +#if 0 +#define DOUBLE_LOG2_10 (double) (3.32192809488736) /* log2(10) */ + +#define DOUBLE_LFO_GAIN_TO_CENTS (double) \ + ( \ + (DOUBLE_LOG2_10) * \ + 1200.0 / \ + 20.0 \ + ) + +#define LFO_GAIN_TO_CENTS (EAS_I32) \ + ( \ + DOUBLE_LFO_GAIN_TO_CENTS * \ + (0x1L << NUM_EG1_FRAC_BITS) \ + ) +#endif + +#define LFO_GAIN_TO_CENTS (EAS_I32) (1671981156L >> (23 - NUM_EG1_FRAC_BITS)) + + +#define MULT_DENTS_COEF(dents,coef) /*lint -e704 */ \ + (EAS_I32)( \ + ( \ + ((EAS_I32)(dents)) * ((EAS_I32)(coef)) \ + ) \ + >> NUM_DENTS_FRAC_BITS \ + ) \ + /* lint +e704 */ + +/* we use 16-bits in the PC per audio sample */ +#define BITS_PER_AUDIO_SAMPLE 16 + +/* we define 1 as 1.0 - 1 LSbit */ +#define DISTORTION_ONE (EAS_I32)((0x1L << (BITS_PER_AUDIO_SAMPLE-1)) -1) +#define DISTORTION_MINUS_ONE (EAS_I32)(~DISTORTION_ONE) + +/* drive coef is given as int.frac */ +#define NUM_DRIVE_COEF_INT_BITS 1 +#define NUM_DRIVE_COEF_FRAC_BITS 4 + +#define MULT_AUDIO_DRIVE(audio,drive) /*lint -e(702) */ \ + (EAS_I32) ( \ + ( \ + ((EAS_I32)(audio)) * ((EAS_I32)(drive)) \ + ) \ + >> NUM_DRIVE_COEF_FRAC_BITS \ + ) + +#define MULT_AUDIO_AUDIO(audio1,audio2) /*lint -e(702) */ \ + (EAS_I32) ( \ + ( \ + ((EAS_I32)(audio1)) * ((EAS_I32)(audio2)) \ + ) \ + >> (BITS_PER_AUDIO_SAMPLE-1) \ + ) + +#define SATURATE(x) \ + ((((EAS_I32)(x)) > DISTORTION_ONE) ? (DISTORTION_ONE) : \ + (((EAS_I32)(x)) < DISTORTION_MINUS_ONE) ? (DISTORTION_MINUS_ONE) : ((EAS_I32)(x))); + + + +/*---------------------------------------------------------------------------- + * EAS_Calculate2toX() + *---------------------------------------------------------------------------- + * Purpose: + * Calculate 2^x + * + * Inputs: + * nCents - measured in cents + * + * Outputs: + * nResult - int.frac result (where frac has NUM_DENTS_FRAC_BITS) + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_I32 EAS_Calculate2toX (EAS_I32 nCents); + +/*---------------------------------------------------------------------------- + * EAS_LogToLinear16() + *---------------------------------------------------------------------------- + * Purpose: + * Transform log value to linear gain multiplier using piece-wise linear + * approximation + * + * Inputs: + * nGain - log scale value in 20.10 format. Even though gain is normally + * stored in 6.10 (16-bit) format we use 32-bit numbers here to eliminate + * the need for saturation checking when combining gain values. + * + * Outputs: + * Returns a 16-bit linear value approximately equal to 2^(nGain/1024) + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_U16 EAS_LogToLinear16 (EAS_I32 nGain); + +/*---------------------------------------------------------------------------- + * EAS_VolumeToGain() + *---------------------------------------------------------------------------- + * Purpose: + * Transform volume control in 1dB increments to gain multiplier + * + * Inputs: + * volume - 100 = 0dB, 99 = -1dB, 0 = -inf + * + * Outputs: + * Returns a 16-bit linear value + *---------------------------------------------------------------------------- +*/ +EAS_I16 EAS_VolumeToGain (EAS_INT volume); + +/*---------------------------------------------------------------------------- + * EAS_fsqrt() + *---------------------------------------------------------------------------- + * Purpose: + * Calculates the square root of a 32-bit fixed point value + * + * Inputs: + * n = value of interest + * + * Outputs: + * returns the square root of n + * + *---------------------------------------------------------------------------- +*/ +EAS_U16 EAS_fsqrt (EAS_U32 n); + +/*---------------------------------------------------------------------------- + * EAS_flog2() + *---------------------------------------------------------------------------- + * Purpose: + * Calculates the log2 of a 32-bit fixed point value + * + * Inputs: + * n = value of interest + * + * Outputs: + * returns the log2 of n + * + *---------------------------------------------------------------------------- +*/ +EAS_I32 EAS_flog2 (EAS_U32 n); + +#endif + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_midi.c b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_midi.c new file mode 100755 index 0000000..2c0c793 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_midi.c @@ -0,0 +1,569 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_midi.c + * + * Contents and purpose: + * This file implements the MIDI stream parser. It is called by eas_smf.c to parse MIDI messages + * that are streamed out of the file. It can also parse live MIDI streams. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 794 $ + * $Date: 2007-08-01 00:08:48 -0700 (Wed, 01 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_data.h" +#include "eas_report.h" +#include "eas_miditypes.h" +#include "eas_midi.h" +#include "eas_vm_protos.h" +#include "eas_parser.h" + +#ifdef JET_INTERFACE +#include "jet_data.h" +#endif + + +/* state enumerations for ProcessSysExMessage */ +typedef enum +{ + eSysEx, + eSysExUnivNonRealTime, + eSysExUnivNrtTargetID, + eSysExGMControl, + eSysExUnivRealTime, + eSysExUnivRtTargetID, + eSysExDeviceControl, + eSysExMasterVolume, + eSysExMasterVolLSB, + eSysExSPMIDI, + eSysExSPMIDIchan, + eSysExSPMIDIMIP, + eSysExMfgID1, + eSysExMfgID2, + eSysExMfgID3, + eSysExEnhancer, + eSysExEnhancerSubID, + eSysExEnhancerFeedback1, + eSysExEnhancerFeedback2, + eSysExEnhancerDrive, + eSysExEnhancerWet, + eSysExEOX, + eSysExIgnore +} E_SYSEX_STATES; + +/* local prototypes */ +static EAS_RESULT ProcessMIDIMessage (S_EAS_DATA *pEASData, S_SYNTH *pSynth, S_MIDI_STREAM *pMIDIStream, EAS_INT parserMode); +static EAS_RESULT ProcessSysExMessage (S_EAS_DATA *pEASData, S_SYNTH *pSynth, S_MIDI_STREAM *pMIDIStream, EAS_U8 c, EAS_INT parserMode); + +/*---------------------------------------------------------------------------- + * EAS_InitMIDIStream() + *---------------------------------------------------------------------------- + * Purpose: + * Initializes the MIDI stream state for parsing. + * + * Inputs: + * + * Outputs: + * returns EAS_RESULT (EAS_SUCCESS is OK) + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void EAS_InitMIDIStream (S_MIDI_STREAM *pMIDIStream) +{ + pMIDIStream->byte3 = EAS_FALSE; + pMIDIStream->pending = EAS_FALSE; + pMIDIStream->runningStatus = 0; + pMIDIStream->status = 0; +} + +/*---------------------------------------------------------------------------- + * EAS_ParseMIDIStream() + *---------------------------------------------------------------------------- + * Purpose: + * Parses a MIDI input stream character by character. Characters are pushed (rather than pulled) + * so the interface works equally well for both file and stream I/O. + * + * Inputs: + * c - character from MIDI stream + * + * Outputs: + * returns EAS_RESULT (EAS_SUCCESS is OK) + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_ParseMIDIStream (S_EAS_DATA *pEASData, S_SYNTH *pSynth, S_MIDI_STREAM *pMIDIStream, EAS_U8 c, EAS_INT parserMode) +{ + + /* check for new status byte */ + if (c & 0x80) + { + /* save new running status */ + if (c < 0xf8) + { + pMIDIStream->runningStatus = c; + pMIDIStream->byte3 = EAS_FALSE; + + /* deal with SysEx */ + if ((c == 0xf7) || (c == 0xf0)) + { + if (parserMode == eParserModeMetaData) + return EAS_SUCCESS; + return ProcessSysExMessage(pEASData, pSynth, pMIDIStream, c, parserMode); + } + + /* inform the file parser that we're in the middle of a message */ + if ((c < 0xf4) || (c > 0xf6)) + pMIDIStream->pending = EAS_TRUE; + } + + /* real-time message - ignore it */ + return EAS_SUCCESS; + } + + /* 3rd byte of a 3-byte message? */ + if (pMIDIStream->byte3) + { + pMIDIStream->d2 = c; + pMIDIStream->byte3 = EAS_FALSE; + pMIDIStream->pending = EAS_FALSE; + if (parserMode == eParserModeMetaData) + return EAS_SUCCESS; + return ProcessMIDIMessage(pEASData, pSynth, pMIDIStream, parserMode); + } + + /* check for status received */ + if (pMIDIStream->runningStatus) + { + + /* save new status and data byte */ + pMIDIStream->status = pMIDIStream->runningStatus; + + /* check for 3-byte messages */ + if (pMIDIStream->status < 0xc0) + { + pMIDIStream->d1 = c; + pMIDIStream->pending = EAS_TRUE; + pMIDIStream->byte3 = EAS_TRUE; + return EAS_SUCCESS; + } + + /* check for 2-byte messages */ + if (pMIDIStream->status < 0xe0) + { + pMIDIStream->d1 = c; + pMIDIStream->pending = EAS_FALSE; + if (parserMode == eParserModeMetaData) + return EAS_SUCCESS; + return ProcessMIDIMessage(pEASData, pSynth, pMIDIStream, parserMode); + } + + /* check for more 3-bytes message */ + if (pMIDIStream->status < 0xf0) + { + pMIDIStream->d1 = c; + pMIDIStream->pending = EAS_TRUE; + pMIDIStream->byte3 = EAS_TRUE; + return EAS_SUCCESS; + } + + /* SysEx message? */ + if (pMIDIStream->status == 0xF0) + { + if (parserMode == eParserModeMetaData) + return EAS_SUCCESS; + return ProcessSysExMessage(pEASData, pSynth, pMIDIStream, c, parserMode); + } + + /* remaining messages all clear running status */ + pMIDIStream->runningStatus = 0; + + /* F2 is 3-byte message */ + if (pMIDIStream->status == 0xf2) + { + pMIDIStream->byte3 = EAS_TRUE; + return EAS_SUCCESS; + } + } + + /* no status byte received, provide a warning, but we should be able to recover */ + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Received MIDI data without a valid status byte: %d\n",c); */ } + pMIDIStream->pending = EAS_FALSE; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * ProcessMIDIMessage() + *---------------------------------------------------------------------------- + * Purpose: + * This function processes a typical MIDI message. All of the data has been received, just need + * to take appropriate action. + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ProcessMIDIMessage (S_EAS_DATA *pEASData, S_SYNTH *pSynth, S_MIDI_STREAM *pMIDIStream, EAS_INT parserMode) +{ + EAS_U8 channel; + + channel = pMIDIStream->status & 0x0f; + switch (pMIDIStream->status & 0xf0) + { + case 0x80: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"NoteOff: %02x %02x %02x\n", + pMIDIStream->status, pMIDIStream->d1, pMIDIStream->d2); */ } + if (parserMode < eParserModeMute) + VMStopNote(pEASData->pVoiceMgr, pSynth, channel, pMIDIStream->d1, pMIDIStream->d2); + break; + + case 0x90: + if (pMIDIStream->d2) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"NoteOn: %02x %02x %02x\n", + pMIDIStream->status, pMIDIStream->d1, pMIDIStream->d2); */ } + pMIDIStream->flags |= MIDI_FLAG_FIRST_NOTE; + if (parserMode == eParserModePlay) + VMStartNote(pEASData->pVoiceMgr, pSynth, channel, pMIDIStream->d1, pMIDIStream->d2); + } + else + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"NoteOff: %02x %02x %02x\n", + pMIDIStream->status, pMIDIStream->d1, pMIDIStream->d2); */ } + if (parserMode < eParserModeMute) + VMStopNote(pEASData->pVoiceMgr, pSynth, channel, pMIDIStream->d1, pMIDIStream->d2); + } + break; + + case 0xa0: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"PolyPres: %02x %02x %02x\n", + pMIDIStream->status, pMIDIStream->d1, pMIDIStream->d2); */ } + break; + + case 0xb0: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"Control: %02x %02x %02x\n", + pMIDIStream->status, pMIDIStream->d1, pMIDIStream->d2); */ } + if (parserMode < eParserModeMute) + VMControlChange(pEASData->pVoiceMgr, pSynth, channel, pMIDIStream->d1, pMIDIStream->d2); +#ifdef JET_INTERFACE + if (pMIDIStream->jetData & MIDI_FLAGS_JET_CB) + { + JET_Event(pEASData, pMIDIStream->jetData & (JET_EVENT_SEG_MASK | JET_EVENT_TRACK_MASK), + channel, pMIDIStream->d1, pMIDIStream->d2); + } +#endif + break; + + case 0xc0: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"Program: %02x %02x\n", + pMIDIStream->status, pMIDIStream->d1); */ } + if (parserMode < eParserModeMute) + VMProgramChange(pEASData->pVoiceMgr, pSynth, channel, pMIDIStream->d1); + break; + + case 0xd0: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"ChanPres: %02x %02x\n", + pMIDIStream->status, pMIDIStream->d1); */ } + if (parserMode < eParserModeMute) + VMChannelPressure(pSynth, channel, pMIDIStream->d1); + break; + + case 0xe0: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"PBend: %02x %02x %02x\n", + pMIDIStream->status, pMIDIStream->d1, pMIDIStream->d2); */ } + if (parserMode < eParserModeMute) + VMPitchBend(pSynth, channel, pMIDIStream->d1, pMIDIStream->d2); + break; + + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"Unknown: %02x %02x %02x\n", + pMIDIStream->status, pMIDIStream->d1, pMIDIStream->d2); */ } + } + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * ProcessSysExMessage() + *---------------------------------------------------------------------------- + * Purpose: + * Process a SysEx character byte from the MIDI stream. Since we cannot + * simply wait for the next character to arrive, we are forced to save + * state after each character. It would be easier to parse at the file + * level, but then we lose the nice feature of being able to support + * these messages in a real-time MIDI stream. + * + * Inputs: + * pEASData - pointer to synthesizer instance data + * c - character to be processed + * locating - if true, the sequencer is relocating to a new position + * + * Outputs: + * + * + * Side Effects: + * + * Notes: + * These are the SysEx messages we can receive: + * + * SysEx messages + * { f0 7e 7f 09 01 f7 } GM 1 On + * { f0 7e 7f 09 02 f7 } GM 1/2 Off + * { f0 7e 7f 09 03 f7 } GM 2 On + * { f0 7f 7f 04 01 lsb msb } Master Volume + * { f0 7f 7f 0b 01 ch mip [ch mip ...] f7 } SP-MIDI + * { f0 00 01 3a 04 01 fdbk1 fdbk2 drive wet dry f7 } Enhancer + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ProcessSysExMessage (S_EAS_DATA *pEASData, S_SYNTH *pSynth, S_MIDI_STREAM *pMIDIStream, EAS_U8 c, EAS_INT parserMode) +{ + + /* check for start byte */ + if (c == 0xf0) + { + pMIDIStream->sysExState = eSysEx; + } + /* check for end byte */ + else if (c == 0xf7) + { + /* if this was a MIP message, update the MIP table */ + if ((pMIDIStream->sysExState == eSysExSPMIDIchan) && (parserMode != eParserModeMetaData)) + VMUpdateMIPTable(pEASData->pVoiceMgr, pSynth); + pMIDIStream->sysExState = eSysExIgnore; + } + + /* process SysEx message */ + else + { + switch (pMIDIStream->sysExState) + { + case eSysEx: + + /* first byte, determine message class */ + switch (c) + { + case 0x7e: + pMIDIStream->sysExState = eSysExUnivNonRealTime; + break; + case 0x7f: + pMIDIStream->sysExState = eSysExUnivRealTime; + break; + case 0x00: + pMIDIStream->sysExState = eSysExMfgID1; + break; + default: + pMIDIStream->sysExState = eSysExIgnore; + break; + } + break; + + /* process GM message */ + case eSysExUnivNonRealTime: + if (c == 0x7f) + pMIDIStream->sysExState = eSysExUnivNrtTargetID; + else + pMIDIStream->sysExState = eSysExIgnore; + break; + + case eSysExUnivNrtTargetID: + if (c == 0x09) + pMIDIStream->sysExState = eSysExGMControl; + else + pMIDIStream->sysExState = eSysExIgnore; + break; + + case eSysExGMControl: + if ((c == 1) || (c == 3)) + { + /* GM 1 or GM2 On, reset synth */ + if (parserMode != eParserModeMetaData) + { + pMIDIStream->flags |= MIDI_FLAG_GM_ON; + VMReset(pEASData->pVoiceMgr, pSynth, EAS_FALSE); + VMInitMIPTable(pSynth); + } + pMIDIStream->sysExState = eSysExEOX; + } + else + pMIDIStream->sysExState = eSysExIgnore; + break; + + /* Process Master Volume and SP-MIDI */ + case eSysExUnivRealTime: + if (c == 0x7f) + pMIDIStream->sysExState = eSysExUnivRtTargetID; + else + pMIDIStream->sysExState = eSysExIgnore; + break; + + case eSysExUnivRtTargetID: + if (c == 0x04) + pMIDIStream->sysExState = eSysExDeviceControl; + else if (c == 0x0b) + pMIDIStream->sysExState = eSysExSPMIDI; + else + pMIDIStream->sysExState = eSysExIgnore; + break; + + /* process master volume */ + case eSysExDeviceControl: + if (c == 0x01) + pMIDIStream->sysExState = eSysExMasterVolume; + else + pMIDIStream->sysExState = eSysExIgnore; + break; + + case eSysExMasterVolume: + /* save LSB */ + pMIDIStream->d1 = c; + pMIDIStream->sysExState = eSysExMasterVolLSB; + break; + + case eSysExMasterVolLSB: + if (parserMode != eParserModeMetaData) + { + EAS_I32 gain = ((EAS_I32) c << 8) | ((EAS_I32) pMIDIStream->d1 << 1); + gain = (gain * gain) >> 15; + VMSetVolume(pSynth, (EAS_U16) gain); + } + pMIDIStream->sysExState = eSysExEOX; + break; + + /* process SP-MIDI MIP message */ + case eSysExSPMIDI: + if (c == 0x01) + { + /* assume all channels are muted */ + if (parserMode != eParserModeMetaData) + VMInitMIPTable(pSynth); + pMIDIStream->d1 = 0; + pMIDIStream->sysExState = eSysExSPMIDIchan; + } + else + pMIDIStream->sysExState = eSysExIgnore; + break; + + case eSysExSPMIDIchan: + if (c < NUM_SYNTH_CHANNELS) + { + pMIDIStream->d2 = c; + pMIDIStream->sysExState = eSysExSPMIDIMIP; + } + else + { + /* bad MIP message - unmute channels */ + if (parserMode != eParserModeMetaData) + VMInitMIPTable(pSynth); + pMIDIStream->sysExState = eSysExIgnore; + } + break; + + case eSysExSPMIDIMIP: + /* process MIP entry here */ + if (parserMode != eParserModeMetaData) + VMSetMIPEntry(pEASData->pVoiceMgr, pSynth, pMIDIStream->d2, pMIDIStream->d1, c); + pMIDIStream->sysExState = eSysExSPMIDIchan; + + /* if 16 channels received, update MIP table */ + if (++pMIDIStream->d1 == NUM_SYNTH_CHANNELS) + { + if (parserMode != eParserModeMetaData) + VMUpdateMIPTable(pEASData->pVoiceMgr, pSynth); + pMIDIStream->sysExState = eSysExEOX; + } + break; + + /* process Enhancer */ + case eSysExMfgID1: + if (c == 0x01) + pMIDIStream->sysExState = eSysExMfgID1; + else + pMIDIStream->sysExState = eSysExIgnore; + break; + + case eSysExMfgID2: + if (c == 0x3a) + pMIDIStream->sysExState = eSysExMfgID1; + else + pMIDIStream->sysExState = eSysExIgnore; + break; + + case eSysExMfgID3: + if (c == 0x04) + pMIDIStream->sysExState = eSysExEnhancer; + else + pMIDIStream->sysExState = eSysExIgnore; + break; + + case eSysExEnhancer: + if (c == 0x01) + pMIDIStream->sysExState = eSysExEnhancerSubID; + else + pMIDIStream->sysExState = eSysExIgnore; + break; + + case eSysExEnhancerSubID: + pMIDIStream->sysExState = eSysExEnhancerFeedback1; + break; + + case eSysExEnhancerFeedback1: + pMIDIStream->sysExState = eSysExEnhancerFeedback2; + break; + + case eSysExEnhancerFeedback2: + pMIDIStream->sysExState = eSysExEnhancerDrive; + break; + + case eSysExEnhancerDrive: + pMIDIStream->sysExState = eSysExEnhancerWet; + break; + + case eSysExEnhancerWet: + pMIDIStream->sysExState = eSysExEOX; + break; + + case eSysExEOX: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Expected F7, received %02x\n", c); */ } + pMIDIStream->sysExState = eSysExIgnore; + break; + + case eSysExIgnore: + break; + + default: + pMIDIStream->sysExState = eSysExIgnore; + break; + } + } + + if (pMIDIStream->sysExState == eSysExIgnore) + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Ignoring SysEx byte %02x\n", c); */ } + return EAS_SUCCESS; +} /* end ProcessSysExMessage */ + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_midi.h b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_midi.h new file mode 100755 index 0000000..10649a0 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_midi.h @@ -0,0 +1,71 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_midi.h + * + * Contents and purpose: + * Prototypes for MIDI stream parsing functions + * + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_MIDI_H +#define _EAS_MIDI_H + +/*---------------------------------------------------------------------------- + * EAS_InitMIDIStream() + *---------------------------------------------------------------------------- + * Purpose: + * Initializes the MIDI stream state for parsing. + * + * Inputs: + * + * Outputs: + * returns EAS_RESULT (EAS_SUCCESS is OK) + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void EAS_InitMIDIStream (S_MIDI_STREAM *pMIDIStream); + +/*---------------------------------------------------------------------------- + * EAS_ParseMIDIStream() + *---------------------------------------------------------------------------- + * Purpose: + * Parses a MIDI input stream character by character. Characters are pushed (rather than pulled) + * so the interface works equally well for both file and stream I/O. + * + * Inputs: + * c - character from MIDI stream + * + * Outputs: + * returns EAS_RESULT (EAS_SUCCESS is OK) + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_ParseMIDIStream (S_EAS_DATA *pEASData, S_SYNTH *pSynth, S_MIDI_STREAM *pMIDIStream, EAS_U8 c, EAS_INT parserMode); + +#endif /* #define _EAS_MIDI_H */ + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_midictrl.h b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_midictrl.h new file mode 100755 index 0000000..46fdc4f --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_midictrl.h @@ -0,0 +1,64 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_midictrl.h + * + * Contents and purpose: + * MIDI controller definitions + * + * This header only contains declarations that are specific + * to this implementation. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_MIDICTRL_H +#define _EAS_MIDICTRL_H + +/* define controller types */ +/* + Note that these controller types are specified in base 10 (decimal) + and not in hexadecimal. The above midi messages are specified + in hexadecimal. +*/ +#define MIDI_CONTROLLER_BANK_SELECT 0 +#define MIDI_CONTROLLER_BANK_SELECT_MSB 0 +#define MIDI_CONTROLLER_MOD_WHEEL 1 +#define MIDI_CONTROLLER_ENTER_DATA_MSB 6 +#define MIDI_CONTROLLER_VOLUME 7 +#define MIDI_CONTROLLER_PAN 10 +#define MIDI_CONTROLLER_EXPRESSION 11 +#define MIDI_CONTROLLER_BANK_SELECT_LSB 32 +#define MIDI_CONTROLLER_ENTER_DATA_LSB 38 /* 0x26 */ +#define MIDI_CONTROLLER_SUSTAIN_PEDAL 64 +#define MIDI_CONTROLLER_SELECT_NRPN_LSB 98 +#define MIDI_CONTROLLER_SELECT_NRPN_MSB 99 +#define MIDI_CONTROLLER_SELECT_RPN_LSB 100 /* 0x64 */ +#define MIDI_CONTROLLER_SELECT_RPN_MSB 101 /* 0x65 */ +#define MIDI_CONTROLLER_ALL_SOUND_OFF 120 +#define MIDI_CONTROLLER_RESET_CONTROLLERS 121 +#define MIDI_CONTROLLER_ALL_NOTES_OFF 123 +#define MIDI_CONTROLLER_OMNI_OFF 124 +#define MIDI_CONTROLLER_OMNI_ON 125 +#define MIDI_CONTROLLER_MONO_ON_POLY_OFF 126 +#define MIDI_CONTROLLER_POLY_ON_MONO_OFF 127 + +#endif /* #ifndef _EAS_MIDICTRL_H */ diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_mididata.c b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_mididata.c new file mode 100755 index 0000000..4463b7e --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_mididata.c @@ -0,0 +1,34 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_mididata.c + * + * Contents and purpose: + * Data module for MIDI stream interface + * + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 547 $ + * $Date: 2007-01-31 16:30:17 -0800 (Wed, 31 Jan 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_miditypes.h" + +S_INTERACTIVE_MIDI eas_MIDIData; + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_miditypes.h b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_miditypes.h new file mode 100755 index 0000000..015f08b --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_miditypes.h @@ -0,0 +1,138 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_miditypes.h + * + * Contents and purpose: + * Contains declarations for the MIDI stream parser. + * + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 778 $ + * $Date: 2007-07-23 16:45:17 -0700 (Mon, 23 Jul 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_MIDITYPES_H +#define _EAS_MIDITYPES_H + +#include "eas_data.h" +#include "eas_parser.h" + +/*---------------------------------------------------------------------------- + * S_MIDI_STREAM + * + * Maintains parser state for the MIDI stream parser + * + *---------------------------------------------------------------------------- +*/ + +typedef struct s_midi_stream_tag +{ + EAS_BOOL8 byte3; /* flag indicates 3rd byte expected */ + EAS_BOOL8 pending; /* flag indicates more data expected */ + EAS_U8 sysExState; /* maintains the SysEx state */ + EAS_U8 runningStatus; /* last running status received */ + EAS_U8 status; /* status byte */ + EAS_U8 d1; /* first data byte */ + EAS_U8 d2; /* second data byte */ + EAS_U8 flags; /* flags - see below for definition */ +#ifdef JET_INTERFACE + EAS_U32 jetData; /* JET data */ +#endif +} S_MIDI_STREAM; + +/* flags for S_MIDI_STREAM.flags */ +#define MIDI_FLAG_GM_ON 0x01 /* GM System On message received */ +#define MIDI_FLAG_FIRST_NOTE 0x02 /* first note received */ + +/* flags for S_MIDI_STREAM.jetFlags */ +#define MIDI_FLAGS_JET_MUTE 0x00000001 /* track is muted */ +#define MIDI_FLAGS_JET_CB 0x00000002 /* JET callback enabled */ + +/*---------------------------------------------------------------------------- + * + * S_SMF_STREAM + * + * This structure contains data required to parse an SMF stream. For SMF0 files, there + * will be a single instance of this per file. For SMF1 files, there will be multiple instance, + * one for each separate stream in the file. + * + *---------------------------------------------------------------------------- +*/ + +typedef struct s_smf_stream_tag +{ + EAS_FILE_HANDLE fileHandle; /* host wrapper file handle */ + EAS_U32 ticks; /* time of next event in stream */ + EAS_I32 startFilePos; /* start location of track within file */ + S_MIDI_STREAM midiStream; /* MIDI stream state */ +} S_SMF_STREAM; + +/*---------------------------------------------------------------------------- + * + * S_SMF_DATA + * + * This structure contains the instance data required to parse an SMF stream. + * + *---------------------------------------------------------------------------- +*/ + +typedef struct s_smf_data_tag +{ +#ifdef _CHECKED_BUILD + EAS_U32 handleCheck; /* signature check for checked build */ +#endif + S_SMF_STREAM *streams; /* pointer to individual streams in file */ + S_SMF_STREAM *nextStream; /* pointer to next stream with event */ + S_SYNTH *pSynth; /* pointer to synth */ + EAS_FILE_HANDLE fileHandle; /* file handle */ + S_METADATA_CB metadata; /* metadata callback */ + EAS_I32 fileOffset; /* for embedded files */ + EAS_I32 time; /* current time in milliseconds/256 */ + EAS_U16 numStreams; /* actual number of streams */ + EAS_U16 tickConv; /* current MIDI tick to msec conversion */ + EAS_U16 ppqn; /* ticks per quarter note */ + EAS_U8 state; /* current state EAS_STATE_XXXX */ + EAS_U8 flags; /* flags - see definitions below */ +} S_SMF_DATA; + +#define SMF_FLAGS_CHASE_MODE 0x01 /* chase mode - skip to first note */ +#define SMF_FLAGS_HAS_TIME_SIG 0x02 /* time signature encountered at time 0 */ +#define SMF_FLAGS_HAS_TEMPO 0x04 /* tempo encountered at time 0 */ +#define SMF_FLAGS_HAS_GM_ON 0x08 /* GM System On encountered at time 0 */ +#define SMF_FLAGS_JET_STREAM 0x80 /* JET in use - keep strict timing */ + +/* combo flags indicate setup bar */ +#define SMF_FLAGS_SETUP_BAR (SMF_FLAGS_HAS_TIME_SIG | SMF_FLAGS_HAS_TEMPO | SMF_FLAGS_HAS_GM_ON) + +/*---------------------------------------------------------------------------- + * Interactive MIDI structure + *---------------------------------------------------------------------------- +*/ +typedef struct s_interactive_midi_tag +{ +#ifdef _CHECKED_BUILD + EAS_U32 handleCheck; /* signature check for checked build */ +#endif + S_SYNTH *pSynth; /* pointer to synth */ + S_MIDI_STREAM stream; /* stream data */ +} S_INTERACTIVE_MIDI; + +#endif /* #ifndef _EAS_MIDITYPES_H */ + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_mixbuf.c b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_mixbuf.c new file mode 100755 index 0000000..db5bd02 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_mixbuf.c @@ -0,0 +1,36 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_mixbuf.c + * + * Contents and purpose: + * Contains a data allocation for synthesizer + * + * Copyright Sonic Network Inc. 2004 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +// includes +#include "eas_data.h" +#include "eas_mixer.h" + +// globals +EAS_I32 eas_MixBuffer[BUFFER_SIZE_IN_MONO_SAMPLES * NUM_OUTPUT_CHANNELS]; + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_mixer.c b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_mixer.c new file mode 100755 index 0000000..0a839a8 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_mixer.c @@ -0,0 +1,464 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_mixer.c + * + * Contents and purpose: + * This file contains the critical components of the mix engine that + * must be optimized for best performance. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 706 $ + * $Date: 2007-05-31 17:22:51 -0700 (Thu, 31 May 2007) $ + *---------------------------------------------------------------------------- +*/ + +//3 dls: This module is in the midst of being converted from a synth +//3 specific module to a general purpose mix engine + +/*------------------------------------ + * includes + *------------------------------------ +*/ +#include "eas_data.h" +#include "eas_host.h" +#include "eas_math.h" +#include "eas_mixer.h" +#include "eas_config.h" +#include "eas_report.h" + +#ifdef _MAXIMIZER_ENABLED +EAS_I32 MaximizerProcess (EAS_VOID_PTR pInstData, EAS_I32 *pSrc, EAS_I32 *pDst, EAS_I32 numSamples); +#endif + +/*------------------------------------ + * defines + *------------------------------------ +*/ + +/* need to boost stereo by ~3dB to compensate for the panner */ +#define STEREO_3DB_GAIN_BOOST 512 + +/*---------------------------------------------------------------------------- + * EAS_MixEngineInit() + *---------------------------------------------------------------------------- + * Purpose: + * Prepares the mix engine for work, allocates buffers, locates effects modules, etc. + * + * Inputs: + * pEASData - instance data + * pInstData - pointer to variable to receive instance data handle + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_MixEngineInit (S_EAS_DATA *pEASData) +{ + + /* check Configuration Module for mix buffer allocation */ + if (pEASData->staticMemoryModel) + pEASData->pMixBuffer = EAS_CMEnumData(EAS_CM_MIX_BUFFER); + else + pEASData->pMixBuffer = EAS_HWMalloc(pEASData->hwInstData, BUFFER_SIZE_IN_MONO_SAMPLES * NUM_OUTPUT_CHANNELS * sizeof(EAS_I32)); + if (pEASData->pMixBuffer == NULL) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Failed to allocate mix buffer memory\n"); */ } + return EAS_ERROR_MALLOC_FAILED; + } + EAS_HWMemSet((void *)(pEASData->pMixBuffer), 0, BUFFER_SIZE_IN_MONO_SAMPLES * NUM_OUTPUT_CHANNELS * sizeof(EAS_I32)); + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_MixEnginePrep() + *---------------------------------------------------------------------------- + * Purpose: + * Performs prep before synthesize a buffer of audio, such as clearing + * audio buffers, etc. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void EAS_MixEnginePrep (S_EAS_DATA *pEASData, EAS_I32 numSamples) +{ + + /* clear the mix buffer */ +#if (NUM_OUTPUT_CHANNELS == 2) + EAS_HWMemSet(pEASData->pMixBuffer, 0, numSamples * (EAS_I32) sizeof(long) * 2); +#else + EAS_HWMemSet(pEASData->pMixBuffer, 0, (EAS_I32) numSamples * (EAS_I32) sizeof(long)); +#endif + + /* need to clear other side-chain effect buffers (chorus & reverb) */ +} + +/*---------------------------------------------------------------------------- + * EAS_MixEnginePost + *---------------------------------------------------------------------------- + * Purpose: + * This routine does the post-processing after all voices have been + * synthesized. It calls any sweeteners and does the final mixdown to + * the output buffer. + * + * Inputs: + * + * Outputs: + * + * Notes: + *---------------------------------------------------------------------------- +*/ +void EAS_MixEnginePost (S_EAS_DATA *pEASData, EAS_I32 numSamples) +{ + EAS_U16 gain; + +//3 dls: Need to restore the mix engine metrics + + /* calculate the gain multiplier */ +#ifdef _MAXIMIZER_ENABLED + if (pEASData->effectsModules[EAS_MODULE_MAXIMIZER].effect) + { + EAS_I32 temp; + temp = MaximizerProcess(pEASData->effectsModules[EAS_MODULE_MAXIMIZER].effectData, pEASData->pMixBuffer, pEASData->pMixBuffer, numSamples); + temp = (temp * pEASData->masterGain) >> 15; + if (temp > 32767) + gain = 32767; + else + gain = (EAS_U16) temp; + } + else + gain = (EAS_U16) pEASData->masterGain; +#else + gain = (EAS_U16) pEASData->masterGain; +#endif + + /* Not using all the gain bits for now + * Reduce the input to the compressor by 6dB to prevent saturation + */ +#ifdef _COMPRESSOR_ENABLED + if (pEASData->effectsModules[EAS_MODULE_COMPRESSOR].effectData) + gain = gain >> 5; + else + gain = gain >> 4; +#else + gain = gain >> 4; +#endif + + /* convert 32-bit mix buffer to 16-bit output format */ +#if (NUM_OUTPUT_CHANNELS == 2) + SynthMasterGain(pEASData->pMixBuffer, pEASData->pOutputAudioBuffer, gain, (EAS_U16) ((EAS_U16) numSamples * 2)); +#else + SynthMasterGain(pEASData->pMixBuffer, pEASData->pOutputAudioBuffer, gain, (EAS_U16) numSamples); +#endif + +#ifdef _ENHANCER_ENABLED + /* enhancer effect */ + if (pEASData->effectsModules[EAS_MODULE_ENHANCER].effectData) + (*pEASData->effectsModules[EAS_MODULE_ENHANCER].effect->pfProcess) + (pEASData->effectsModules[EAS_MODULE_ENHANCER].effectData, + pEASData->pOutputAudioBuffer, + pEASData->pOutputAudioBuffer, + numSamples); +#endif + +#ifdef _GRAPHIC_EQ_ENABLED + /* graphic EQ effect */ + if (pEASData->effectsModules[EAS_MODULE_GRAPHIC_EQ].effectData) + (*pEASData->effectsModules[EAS_MODULE_GRAPHIC_EQ].effect->pfProcess) + (pEASData->effectsModules[EAS_MODULE_GRAPHIC_EQ].effectData, + pEASData->pOutputAudioBuffer, + pEASData->pOutputAudioBuffer, + numSamples); +#endif + +#ifdef _COMPRESSOR_ENABLED + /* compressor effect */ + if (pEASData->effectsModules[EAS_MODULE_COMPRESSOR].effectData) + (*pEASData->effectsModules[EAS_MODULE_COMPRESSOR].effect->pfProcess) + (pEASData->effectsModules[EAS_MODULE_COMPRESSOR].effectData, + pEASData->pOutputAudioBuffer, + pEASData->pOutputAudioBuffer, + numSamples); +#endif + +#ifdef _WOW_ENABLED + /* WOW requires a 32-bit buffer, borrow the mix buffer and + * pass it as the destination buffer + */ + /*lint -e{740} temporarily passing a parameter through an existing I/F */ + if (pEASData->effectsModules[EAS_MODULE_WOW].effectData) + (*pEASData->effectsModules[EAS_MODULE_WOW].effect->pfProcess) + (pEASData->effectsModules[EAS_MODULE_WOW].effectData, + pEASData->pOutputAudioBuffer, + (EAS_PCM*) pEASData->pMixBuffer, + numSamples); +#endif + +#ifdef _TONECONTROLEQ_ENABLED + /* ToneControlEQ effect */ + if (pEASData->effectsModules[EAS_MODULE_TONECONTROLEQ].effectData) + (*pEASData->effectsModules[EAS_MODULE_TONECONTROLEQ].effect->pfProcess) + (pEASData->effectsModules[EAS_MODULE_TONECONTROLEQ].effectData, + pEASData->pOutputAudioBuffer, + pEASData->pOutputAudioBuffer, + numSamples); +#endif + +#ifdef _REVERB_ENABLED + /* Reverb effect */ + if (pEASData->effectsModules[EAS_MODULE_REVERB].effectData) + (*pEASData->effectsModules[EAS_MODULE_REVERB].effect->pfProcess) + (pEASData->effectsModules[EAS_MODULE_REVERB].effectData, + pEASData->pOutputAudioBuffer, + pEASData->pOutputAudioBuffer, + numSamples); +#endif + +#ifdef _CHORUS_ENABLED + /* Chorus effect */ + if (pEASData->effectsModules[EAS_MODULE_CHORUS].effectData) + (*pEASData->effectsModules[EAS_MODULE_CHORUS].effect->pfProcess) + (pEASData->effectsModules[EAS_MODULE_CHORUS].effectData, + pEASData->pOutputAudioBuffer, + pEASData->pOutputAudioBuffer, + numSamples); +#endif + +} + +#ifndef NATIVE_EAS_KERNEL +/*---------------------------------------------------------------------------- + * SynthMasterGain + *---------------------------------------------------------------------------- + * Purpose: + * Mixes down audio from 32-bit to 16-bit target buffer + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +void SynthMasterGain (long *pInputBuffer, EAS_PCM *pOutputBuffer, EAS_U16 nGain, EAS_U16 numSamples) { + + /* loop through the buffer */ + while (numSamples--) { + long s; + + /* read a sample from the input buffer and add some guard bits */ + s = *pInputBuffer++; + + /* add some guard bits */ + /*lint -e{704} */ + s = s >> 7; + + /* apply master gain */ + s *= (long) nGain; + + /* shift to lower 16-bits */ + /*lint -e{704} */ + s = s >> 9; + + /* saturate */ + s = SATURATE(s); + + *pOutputBuffer++ = (EAS_PCM)s; + } +} +#endif + +/*---------------------------------------------------------------------------- + * EAS_MixEngineShutdown() + *---------------------------------------------------------------------------- + * Purpose: + * Shuts down effects modules and deallocates memory + * + * Inputs: + * pEASData - instance data + * pInstData - instance data handle + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_MixEngineShutdown (S_EAS_DATA *pEASData) +{ + + /* check Configuration Module for static memory allocation */ + if (!pEASData->staticMemoryModel && (pEASData->pMixBuffer != NULL)) + EAS_HWFree(pEASData->hwInstData, pEASData->pMixBuffer); + + return EAS_SUCCESS; +} + +#ifdef UNIFIED_MIXER +#ifndef NATIVE_MIX_STREAM +/*---------------------------------------------------------------------------- + * EAS_MixStream + *---------------------------------------------------------------------------- + * Mix a 16-bit stream into a 32-bit buffer + * + * pInputBuffer 16-bit input buffer + * pMixBuffer 32-bit mix buffer + * numSamples number of samples to mix + * gainLeft initial gain left or mono + * gainRight initial gain right + * gainLeft left gain increment per sample + * gainRight right gain increment per sample + * flags bit 0 = stereo source + * bit 1 = stereo output + *---------------------------------------------------------------------------- +*/ +void EAS_MixStream (EAS_PCM *pInputBuffer, EAS_I32 *pMixBuffer, EAS_I32 numSamples, EAS_I32 gainLeft, EAS_I32 gainRight, EAS_I32 gainIncLeft, EAS_I32 gainIncRight, EAS_I32 flags) +{ + EAS_I32 temp; + EAS_INT src, dest; + + /* NOTE: There are a lot of optimizations that can be done + * in the native implementations based on register + * availability, etc. For example, it may make sense to + * break this down into 8 separate routines: + * + * 1. Mono source to mono output + * 2. Mono source to stereo output + * 3. Stereo source to mono output + * 4. Stereo source to stereo output + * 5. Mono source to mono output - no gain change + * 6. Mono source to stereo output - no gain change + * 7. Stereo source to mono output - no gain change + * 8. Stereo source to stereo output - no gain change + * + * Other possibilities include loop unrolling, skipping + * a gain calculation every 2 or 4 samples, etc. + */ + + /* no gain change, use fast loops */ + if ((gainIncLeft == 0) && (gainIncRight == 0)) + { + switch (flags & (MIX_FLAGS_STEREO_SOURCE | MIX_FLAGS_STEREO_OUTPUT)) + { + /* mono to mono */ + case 0: + gainLeft >>= 15; + for (src = dest = 0; src < numSamples; src++, dest++) + { + + pMixBuffer[dest] += (pInputBuffer[src] * gainLeft) >> NUM_MIXER_GUARD_BITS; + } + break; + + /* mono to stereo */ + case MIX_FLAGS_STEREO_OUTPUT: + gainLeft >>= 15; + gainRight >>= 15; + for (src = dest = 0; src < numSamples; src++, dest+=2) + { + pMixBuffer[dest] += (pInputBuffer[src] * gainLeft) >> NUM_MIXER_GUARD_BITS; + pMixBuffer[dest+1] += (pInputBuffer[src] * gainRight) >> NUM_MIXER_GUARD_BITS; + } + break; + + /* stereo to mono */ + case MIX_FLAGS_STEREO_SOURCE: + gainLeft >>= 15; + gainRight >>= 15; + for (src = dest = 0; src < numSamples; src+=2, dest++) + { + temp = (pInputBuffer[src] * gainLeft) >> NUM_MIXER_GUARD_BITS; + temp += ((pInputBuffer[src+1] * gainRight) >> NUM_MIXER_GUARD_BITS); + pMixBuffer[dest] += temp; + } + break; + + /* stereo to stereo */ + case MIX_FLAGS_STEREO_SOURCE | MIX_FLAGS_STEREO_OUTPUT: + gainLeft >>= 15; + gainRight >>= 15; + for (src = dest = 0; src < numSamples; src+=2, dest+=2) + { + pMixBuffer[dest] += (pInputBuffer[src] * gainLeft) >> NUM_MIXER_GUARD_BITS; + pMixBuffer[dest+1] += (pInputBuffer[src+1] * gainRight) >> NUM_MIXER_GUARD_BITS; + } + break; + } + } + + /* gain change - do gain increment */ + else + { + switch (flags & (MIX_FLAGS_STEREO_SOURCE | MIX_FLAGS_STEREO_OUTPUT)) + { + /* mono to mono */ + case 0: + for (src = dest = 0; src < numSamples; src++, dest++) + { + gainLeft += gainIncLeft; + pMixBuffer[dest] += (pInputBuffer[src] * (gainLeft >> 15)) >> NUM_MIXER_GUARD_BITS; + } + break; + + /* mono to stereo */ + case MIX_FLAGS_STEREO_OUTPUT: + for (src = dest = 0; src < numSamples; src++, dest+=2) + { + gainLeft += gainIncLeft; + gainRight += gainIncRight; + pMixBuffer[dest] += (pInputBuffer[src] * (gainLeft >> 15)) >> NUM_MIXER_GUARD_BITS; + pMixBuffer[dest+1] += (pInputBuffer[src] * (gainRight >> 15)) >> NUM_MIXER_GUARD_BITS; + } + break; + + /* stereo to mono */ + case MIX_FLAGS_STEREO_SOURCE: + for (src = dest = 0; src < numSamples; src+=2, dest++) + { + gainLeft += gainIncLeft; + gainRight += gainIncRight; + temp = (pInputBuffer[src] * (gainLeft >> 15)) >> NUM_MIXER_GUARD_BITS; + temp += ((pInputBuffer[src+1] * (gainRight >> 15)) >> NUM_MIXER_GUARD_BITS); + pMixBuffer[dest] += temp; + } + break; + + /* stereo to stereo */ + case MIX_FLAGS_STEREO_SOURCE | MIX_FLAGS_STEREO_OUTPUT: + for (src = dest = 0; src < numSamples; src+=2, dest+=2) + { + gainLeft += gainIncLeft; + gainRight += gainIncRight; + pMixBuffer[dest] += (pInputBuffer[src] * (gainLeft >> 15)) >> NUM_MIXER_GUARD_BITS; + pMixBuffer[dest+1] += (pInputBuffer[src+1] * (gainRight >> 15)) >> NUM_MIXER_GUARD_BITS; + } + break; + } + } +} +#endif +#endif + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_mixer.h b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_mixer.h new file mode 100755 index 0000000..b2eb33b --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_mixer.h @@ -0,0 +1,137 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_mixer.h + * + * Contents and purpose: + * This file contains the critical components of the mix engine that + * must be optimized for best performance. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 706 $ + * $Date: 2007-05-31 17:22:51 -0700 (Thu, 31 May 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_MIXER_H +#define _EAS_MIXER_H + +//3 dls: This module is in the midst of being converted from a synth +//3 specific module to a general purpose mix engine + +#define MIX_FLAGS_STEREO_SOURCE 1 +#define MIX_FLAGS_STEREO_OUTPUT 2 +#define NUM_MIXER_GUARD_BITS 4 + +#include "eas_effects.h" + +extern void SynthMasterGain( long *pInputBuffer, EAS_PCM *pOutputBuffer, EAS_U16 nGain, EAS_U16 nNumLoopSamples); + +/*---------------------------------------------------------------------------- + * EAS_MixEngineInit() + *---------------------------------------------------------------------------- + * Purpose: + * Prepares the mix engine for work, allocates buffers, locates effects modules, etc. + * + * Inputs: + * pEASData - instance data + * pInstData - pointer to variable to receive instance data handle + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_MixEngineInit (EAS_DATA_HANDLE pEASData); + +/*---------------------------------------------------------------------------- + * EAS_MixEnginePrep() + *---------------------------------------------------------------------------- + * Purpose: + * Performs prep before synthesize a buffer of audio, such as clearing + * audio buffers, etc. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void EAS_MixEnginePrep (EAS_DATA_HANDLE pEASData, EAS_I32 nNumSamplesToAdd); + +/*---------------------------------------------------------------------------- + * EAS_MixEnginePost + *---------------------------------------------------------------------------- + * Purpose: + * This routine does the post-processing after all voices have been + * synthesized. It calls any sweeteners and does the final mixdown to + * the output buffer. + * + * Inputs: + * + * Outputs: + * + * Notes: + *---------------------------------------------------------------------------- +*/ +void EAS_MixEnginePost (EAS_DATA_HANDLE pEASData, EAS_I32 nNumSamplesToAdd); + +/*---------------------------------------------------------------------------- + * EAS_MixEngineShutdown() + *---------------------------------------------------------------------------- + * Purpose: + * Shuts down effects modules and deallocates memory + * + * Inputs: + * pEASData - instance data + * pInstData - instance data handle + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_MixEngineShutdown (EAS_DATA_HANDLE pEASData); + +#ifdef UNIFIED_MIXER +/*---------------------------------------------------------------------------- + * EAS_MixStream + *---------------------------------------------------------------------------- + * Mix a 16-bit stream into a 32-bit buffer + * + * pInputBuffer 16-bit input buffer + * pMixBuffer 32-bit mix buffer + * numSamples number of samples to mix + * gainLeft initial gain left or mono + * gainRight initial gain right + * gainLeft left gain increment per sample + * gainRight right gain increment per sample + * flags bit 0 = stereo source + * bit 1 = stereo output + *---------------------------------------------------------------------------- +*/ +void EAS_MixStream (EAS_PCM *pInputBuffer, EAS_I32 *pMixBuffer, EAS_I32 numSamples, EAS_I32 gainLeft, EAS_I32 gainRight, EAS_I32 gainIncLeft, EAS_I32 gainIncRight, EAS_I32 flags); +#endif + +#endif /* #ifndef _EAS_MIXER_H */ + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_ota.c b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_ota.c new file mode 100755 index 0000000..5bc9062 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_ota.c @@ -0,0 +1,1077 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_ota.c + * + * Contents and purpose: + * OTA parser + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 795 $ + * $Date: 2007-08-01 00:14:45 -0700 (Wed, 01 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_data.h" +#include "eas_miditypes.h" +#include "eas_parser.h" +#include "eas_report.h" +#include "eas_host.h" +#include "eas_midi.h" +#include "eas_config.h" +#include "eas_vm_protos.h" +#include "eas_otadata.h" + +/* increase gain for mono ringtones */ +#define OTA_GAIN_OFFSET 8 + +/* file definitions */ +#define OTA_RINGTONE 0x25 +#define OTA_SOUND 0x1d +#define OTA_UNICODE 0x22 + +/* song type definitions */ +#define OTA_BASIC_SONG_TYPE 0x01 +#define OTA_TEMPORARY_SONG_TYPE 0x02 + +/* instruction ID coding */ +#define OTA_PATTERN_HEADER_ID 0x00 +#define OTA_NOTE_INST_ID 0x01 +#define OTA_SCALE_INST_ID 0x02 +#define OTA_STYLE_INST_ID 0x03 +#define OTA_TEMPO_INST_ID 0x04 +#define OTA_VOLUME_INST_ID 0x05 + +/* note durations */ +#define OTA_NORMAL_DURATION 0x00 +#define OTA_DOTTED_NOTE 0x01 +#define OTA_DOUBLE_DOTTED_NOTE 0x02 +#define OTA_TRIPLET_NOTE 0x03 + +/* loop count value for infinite loop */ +#define OTA_INFINITE_LOOP 0x0f + +/* length of 32nd note in 1/256ths of a msec for 63 BPM tempo */ +#define DEFAULT_TICK_CONV 30476 + +/* default channel and program for OTA playback */ +#define OTA_CHANNEL 0 +#define OTA_PROGRAM 80 +#define OTA_VEL_MUL 4 +#define OTA_VEL_OFS 67 +#define OTA_VEL_DEFAULT 95 + +/* multiplier for fixed point triplet conversion */ +#define TRIPLET_MULTIPLIER 683 +#define TRIPLET_SHIFT 10 + +/* local prototypes */ +static EAS_RESULT OTA_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset); +static EAS_RESULT OTA_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT OTA_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime); +static EAS_RESULT OTA_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode); +static EAS_RESULT OTA_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_STATE *pState); +static EAS_RESULT OTA_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT OTA_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT OTA_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT OTA_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT OTA_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value); +static EAS_RESULT OTA_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue); +static EAS_RESULT OTA_ParseHeader (S_EAS_DATA *pEASData, S_OTA_DATA* pData); +static EAS_RESULT OTA_FetchBitField (EAS_HW_DATA_HANDLE hwInstData, S_OTA_DATA *pData, EAS_I32 numBits, EAS_U8 *pValue); +static EAS_RESULT OTA_SavePosition (EAS_HW_DATA_HANDLE hwInstData, S_OTA_DATA *pData, S_OTA_LOC *pLoc); +static EAS_RESULT OTA_RestorePosition (EAS_HW_DATA_HANDLE hwInstData, S_OTA_DATA *pData, S_OTA_LOC *pLoc); + + +/*---------------------------------------------------------------------------- + * + * EAS_OTA_Parser + * + * This structure contains the functional interface for the OTA parser + *---------------------------------------------------------------------------- +*/ +const S_FILE_PARSER_INTERFACE EAS_OTA_Parser = +{ + OTA_CheckFileType, + OTA_Prepare, + OTA_Time, + OTA_Event, + OTA_State, + OTA_Close, + OTA_Reset, + OTA_Pause, + OTA_Resume, + NULL, + OTA_SetData, + OTA_GetData, + NULL +}; + +/*---------------------------------------------------------------------------- + * + * bpmTable + * + * BPM conversion table. Converts bpm values to 256ths of a millisecond for a 32nd note + *---------------------------------------------------------------------------- +*/ +static const EAS_U32 bpmTable[32] = +{ + 76800, 68571, 61935, 54857, + 48000, 42667, 38400, 34286, + 30476, 27429, 24000, 21333, + 19200, 17143, 15360, 13714, + 12000, 10667, 9600, 8533, + 7680, 6737, 6000, 5408, + 4800, 4267, 3840, 3398, + 3024, 2685, 2400, 2133 +}; + +/*---------------------------------------------------------------------------- + * OTA_CheckFileType() + *---------------------------------------------------------------------------- + * Purpose: + * Check the file type to see if we can parse it + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT OTA_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset) +{ + S_OTA_DATA* pData; + EAS_RESULT result; + EAS_INT cmdLen; + EAS_INT state; + EAS_U8 temp; + + /* read the first byte, should be command length */ + *ppHandle = NULL; + if ((result = EAS_HWGetByte(pEASData->hwInstData, fileHandle, &temp)) != EAS_SUCCESS) + return result; + + /* read all the commands */ + cmdLen = temp; + state = 0; + while (cmdLen--) + { + + /* read the command, upper 7 bits */ + if ((result = EAS_HWGetByte(pEASData->hwInstData, fileHandle, &temp)) != EAS_SUCCESS) + return result; + temp = temp >> 1; + + if (state == 0) + { + if (temp != OTA_RINGTONE) + break; + state++; + } + else + { + + if (temp == OTA_SOUND) + { + + /* check for static memory allocation */ + if (pEASData->staticMemoryModel) + pData = EAS_CMEnumData(EAS_CM_OTA_DATA); + else + pData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_OTA_DATA)); + if (!pData) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Malloc failed in OTA_Prepare\n"); */ } + return EAS_ERROR_MALLOC_FAILED; + } + EAS_HWMemSet(pData, 0, sizeof(S_OTA_DATA)); + + /* return a pointer to the instance data */ + pData->fileHandle = fileHandle; + pData->fileOffset = offset; + pData->state = EAS_STATE_OPEN; + *ppHandle = pData; + break; + } + + if (temp != OTA_UNICODE) + break; + } + } + + /* not recognized */ + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_Prepare() + *---------------------------------------------------------------------------- + * Purpose: + * Prepare to parse the file. Allocates instance data (or uses static allocation for + * static memory model). + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT OTA_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_OTA_DATA* pData; + EAS_RESULT result; + + /* check for valid state */ + pData = (S_OTA_DATA*) pInstData; + if (pData->state != EAS_STATE_OPEN) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + /* instantiate a synthesizer */ + if ((result = VMInitMIDI(pEASData, &pData->pSynth)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitMIDI returned %d\n", result); */ } + return result; + } + + pData->state = EAS_STATE_ERROR; + if ((result = OTA_ParseHeader(pEASData, pData)) != EAS_SUCCESS) + return result; + + pData->state = EAS_STATE_READY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_Time() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the time of the next event in msecs + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * pTime - pointer to variable to hold time of next event (in msecs) + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ +static EAS_RESULT OTA_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime) +{ + S_OTA_DATA *pData; + + pData = (S_OTA_DATA*) pInstData; + + /* return time in milliseconds */ + /*lint -e{704} use shift instead of division */ + *pTime = pData->time >> 8; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_Event() + *---------------------------------------------------------------------------- + * Purpose: + * Parse the next event in the file + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT OTA_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode) +{ + S_OTA_DATA* pData; + EAS_RESULT result; + EAS_U32 duration; + EAS_U8 temp; + + pData = (S_OTA_DATA*) pInstData; + if (pData->state >= EAS_STATE_OPEN) + return EAS_SUCCESS; + + /* initialize MIDI channel when the track starts playing */ + if (pData->time == 0) + { + /* set program to square lead */ + if (parserMode != eParserModeMetaData) + VMProgramChange(pEASData->pVoiceMgr, pData->pSynth, OTA_CHANNEL, OTA_PROGRAM); + + /* set channel volume to max */ + if (parserMode != eParserModeMetaData) + VMControlChange(pEASData->pVoiceMgr, pData->pSynth, OTA_CHANNEL, 7, 127); + } + + /* check for end of note */ + if (pData->note) + { + /* stop the note */ + VMStopNote(pEASData->pVoiceMgr, pData->pSynth, OTA_CHANNEL, pData->note, 0); + pData->note = 0; + + /* check for rest between notes */ + if (pData->restTicks) + { + pData->time += (EAS_I32) pData->restTicks; + pData->restTicks = 0; + return EAS_SUCCESS; + } + } + + /* if not in a pattern, read the pattern header */ + while (pData->current.patternLen == 0) + { + + /* check for loop - don't do infinite loops when locating */ + if (pData->loopCount && ((parserMode == eParserModePlay) || (pData->loopCount != OTA_INFINITE_LOOP))) + { + /* if not infinite loop, decrement loop count */ + if (pData->loopCount != OTA_INFINITE_LOOP) + pData->loopCount--; + + /* back to start of pattern*/ + if ((result = OTA_RestorePosition(pEASData->hwInstData, pData, &pData->patterns[pData->currentPattern])) != EAS_SUCCESS) + return result; + } + + /* if no previous position to restore, continue forward */ + else if (pData->restore.fileOffset < 0) + { + + /* check for end of song */ + if (pData->numPatterns == 0) + { + pData->state = EAS_STATE_STOPPING; + VMReleaseAllVoices(pEASData->pVoiceMgr, pData->pSynth); + return EAS_SUCCESS; + } + + /* read the next pattern header */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 3, &temp)) != EAS_SUCCESS) + return result; + if (temp != OTA_PATTERN_HEADER_ID) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Expected OTA pattern header\n"); */ } + return EAS_ERROR_FILE_FORMAT; + } + + /* get the pattern ID */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 2, &pData->currentPattern)) != EAS_SUCCESS) + return result; + + /* get the loop count */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 4, &pData->loopCount)) != EAS_SUCCESS) + return result; + + /* get the pattern length */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 8, &pData->current.patternLen)) != EAS_SUCCESS) + return result; + + /* if pattern definition, save the current position */ + if (pData->current.patternLen) + { + if ((result = OTA_SavePosition(pEASData->hwInstData, pData, &pData->patterns[pData->currentPattern])) != EAS_SUCCESS) + return result; + } + + /* if pattern length is zero, repeat a previous pattern */ + else + { + /* make sure it's a valid pattern */ + if (pData->patterns[pData->currentPattern].fileOffset < 0) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "OTA pattern error, invalid pattern specified\n"); */ } + return EAS_ERROR_FILE_FORMAT; + } + + /* save current position and data */ + if ((result = OTA_SavePosition(pEASData->hwInstData, pData, &pData->restore)) != EAS_SUCCESS) + return result; + + /* seek to the pattern in the file */ + if ((result = OTA_RestorePosition(pEASData->hwInstData, pData, &pData->patterns[pData->currentPattern])) != EAS_SUCCESS) + return result; + } + + /* decrement pattern count */ + pData->numPatterns--; + } + + /* restore previous position */ + else + { + if ((result = OTA_RestorePosition(pEASData->hwInstData, pData, &pData->restore)) != EAS_SUCCESS) + return result; + } + } + + /* get the next event */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 3, &temp)) != EAS_SUCCESS) + return result; + + switch (temp) + { + case OTA_NOTE_INST_ID: + /* fetch note value */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 4, &pData->note)) != EAS_SUCCESS) + return result; + + /* fetch note duration */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 3, &temp)) != EAS_SUCCESS) + return result; + duration = pData->tick * (0x20 >> temp); + + /* fetch note duration modifier */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 2, &temp)) != EAS_SUCCESS) + return result; + switch (temp) + { + case OTA_NORMAL_DURATION: + break; + + case OTA_DOTTED_NOTE: + duration += duration >> 1; + break; + + case OTA_DOUBLE_DOTTED_NOTE: + duration += (duration >> 1) + (duration >> 2); + break; + + case OTA_TRIPLET_NOTE: + duration = (duration * TRIPLET_MULTIPLIER) >> TRIPLET_SHIFT; + break; + + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Unrecognized note duration ignored\n"); */ } + break; + } + + /* check for note */ + if (pData->note) + { + + /* determine note length based on style */ + switch (pData->style) + { + case 0: + pData->restTicks = duration >> 4; + break; + case 1: + pData->restTicks = 0; + break; + case 2: + pData->restTicks = duration >> 1; + break; + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Unrecognized note style ignored\n"); */ } + } + + /* add octave */ + pData->note += pData->octave; + if (parserMode == eParserModePlay) + VMStartNote(pEASData->pVoiceMgr, pData->pSynth, OTA_CHANNEL, pData->note, pData->velocity); + pData->time += (EAS_I32) duration - (EAS_I32) pData->restTicks; + } + + /* this is a rest */ + else + pData->time += (EAS_I32) duration; + break; + + case OTA_SCALE_INST_ID: + /* fetch octave */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 2, &temp)) != EAS_SUCCESS) + return result; + pData->octave = (EAS_U8) (temp * 12 + 59); + break; + + case OTA_STYLE_INST_ID: + /* fetch note style */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 2, &pData->style)) != EAS_SUCCESS) + return result; + break; + + case OTA_TEMPO_INST_ID: + /* fetch tempo */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 5, &temp)) != EAS_SUCCESS) + return result; + pData->tick = bpmTable[temp]; + break; + + case OTA_VOLUME_INST_ID: + /* fetch volume */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 4, &temp)) != EAS_SUCCESS) + return result; + pData->velocity = temp ? (EAS_U8) (temp * OTA_VEL_MUL + OTA_VEL_OFS) : 0; + break; + + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Unexpected instruction ID in OTA stream\n"); */ } + return EAS_ERROR_FILE_FORMAT; + } + + /* decrement pattern length */ + pData->current.patternLen--; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_State() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current state of the stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * pState - pointer to variable to store state + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ +static EAS_RESULT OTA_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pState) +{ + S_OTA_DATA* pData; + + /* establish pointer to instance data */ + pData = (S_OTA_DATA*) pInstData; + + /* if stopping, check to see if synth voices are active */ + if (pData->state == EAS_STATE_STOPPING) + { + if (VMActiveVoices(pData->pSynth) == 0) + pData->state = EAS_STATE_STOPPED; + } + + if (pData->state == EAS_STATE_PAUSING) + { + if (VMActiveVoices(pData->pSynth) == 0) + pData->state = EAS_STATE_PAUSED; + } + + /* return current state */ + *pState = pData->state; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_Close() + *---------------------------------------------------------------------------- + * Purpose: + * Close the file and clean up + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT OTA_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_OTA_DATA* pData; + EAS_RESULT result; + + pData = (S_OTA_DATA*) pInstData; + + /* close the file */ + if ((result = EAS_HWCloseFile(pEASData->hwInstData, pData->fileHandle)) != EAS_SUCCESS) + return result; + + /* free the synth */ + if (pData->pSynth != NULL) + VMMIDIShutdown(pEASData, pData->pSynth); + + /* if using dynamic memory, free it */ + if (!pEASData->staticMemoryModel) + EAS_HWFree(pEASData->hwInstData, pData); + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_Reset() + *---------------------------------------------------------------------------- + * Purpose: + * Reset the sequencer. Used for locating backwards in the file. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT OTA_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_OTA_DATA* pData; + EAS_RESULT result; + + pData = (S_OTA_DATA*) pInstData; + + /* reset the synth */ + VMReset(pEASData->pVoiceMgr, pData->pSynth, EAS_TRUE); + pData->note = 0; + + /* reset file position and re-parse header */ + pData->state = EAS_STATE_ERROR; + if ((result = OTA_ParseHeader (pEASData, pData)) != EAS_SUCCESS) + return result; + + pData->state = EAS_STATE_READY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_Pause() + *---------------------------------------------------------------------------- + * Purpose: + * Pauses the sequencer. Mutes all voices and sets state to pause. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT OTA_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_OTA_DATA *pData; + + /* can't pause a stopped stream */ + pData = (S_OTA_DATA*) pInstData; + if (pData->state == EAS_STATE_STOPPED) + return EAS_ERROR_ALREADY_STOPPED; + + /* mute the synthesizer */ + VMMuteAllVoices(pEASData->pVoiceMgr, pData->pSynth); + pData->state = EAS_STATE_PAUSING; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_Resume() + *---------------------------------------------------------------------------- + * Purpose: + * Resume playing after a pause, sets state back to playing. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ +static EAS_RESULT OTA_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_OTA_DATA *pData; + + /* can't resume a stopped stream */ + pData = (S_OTA_DATA*) pInstData; + if (pData->state == EAS_STATE_STOPPED) + return EAS_ERROR_ALREADY_STOPPED; + + /* nothing to do but resume playback */ + pData->state = EAS_STATE_PLAY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_SetData() + *---------------------------------------------------------------------------- + * Purpose: + * Return file type + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ +static EAS_RESULT OTA_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value) +{ + S_OTA_DATA *pData; + + pData = (S_OTA_DATA *) pInstData; + switch (param) + { + + /* set metadata callback */ + case PARSER_DATA_METADATA_CB: + EAS_HWMemCpy(&pData->metadata, (void*) value, sizeof(S_METADATA_CB)); + break; + + default: + return EAS_ERROR_INVALID_PARAMETER; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_GetData() + *---------------------------------------------------------------------------- + * Purpose: + * Return file type + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ +static EAS_RESULT OTA_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue) +{ + S_OTA_DATA *pData; + + pData = (S_OTA_DATA*) pInstData; + switch (param) + { + /* return file type as OTA */ + case PARSER_DATA_FILE_TYPE: + *pValue = EAS_FILE_OTA; + break; + +#if 0 + /* set transposition */ + case PARSER_DATA_TRANSPOSITION: + *pValue = pData->transposition; + break; +#endif + + case PARSER_DATA_SYNTH_HANDLE: + *pValue = (EAS_I32) pData->pSynth; + break; + + case PARSER_DATA_GAIN_OFFSET: + *pValue = OTA_GAIN_OFFSET; + break; + + default: + return EAS_ERROR_INVALID_PARAMETER; + } + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_ParseHeader() + *---------------------------------------------------------------------------- + * Purpose: + * Prepare to parse the file. Allocates instance data (or uses static allocation for + * static memory model). + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT OTA_ParseHeader (S_EAS_DATA *pEASData, S_OTA_DATA* pData) +{ + EAS_RESULT result; + EAS_INT i; + EAS_INT state; + EAS_U8 temp; + EAS_U8 titleLen; + + /* initialize some data */ + pData->flags = 0; + pData->time = 0; + pData->tick = DEFAULT_TICK_CONV; + pData->patterns[0].fileOffset = pData->patterns[1].fileOffset = + pData->patterns[2].fileOffset = pData->patterns[3].fileOffset = -1; + pData->current.bitCount = 0; + pData->current.patternLen = 0; + pData->loopCount = 0; + pData->restore.fileOffset = -1; + pData->note = 0; + pData->restTicks = 0; + pData->velocity = OTA_VEL_DEFAULT; + pData->style = 0; + pData->octave = 59; + + /* seek to start of data */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pData->fileHandle, pData->fileOffset)) != EAS_SUCCESS) + return result; + + /* read the first byte, should be command length */ + if ((result = EAS_HWGetByte(pEASData->hwInstData, pData->fileHandle, &temp)) != EAS_SUCCESS) + return result; + + /* read all the commands */ + i = temp; + state = 0; + while (i--) + { + + /* fetch command, always starts on byte boundary */ + pData->current.bitCount = 0; + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 7, &temp)) != EAS_SUCCESS) + return result; + + if (state == 0) + { + if (temp != OTA_RINGTONE) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Expected OTA Ring Tone Programming type\n"); */ } + return EAS_ERROR_FILE_FORMAT; + } + state++; + } + else + { + + if (temp == OTA_SOUND) + break; + + if (temp == OTA_UNICODE) + pData->flags |= OTA_FLAGS_UNICODE; + else + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Expected OTA Sound or Unicode type\n"); */ } + return EAS_ERROR_FILE_FORMAT; + } + } + } + + /* get song type */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 3, &temp)) != EAS_SUCCESS) + return result; + + /* check for basic song type */ + if (temp == OTA_BASIC_SONG_TYPE) + { + /* fetch title length */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 4, &titleLen)) != EAS_SUCCESS) + return result; + + /* if unicode, double the length */ + if (pData->flags & OTA_FLAGS_UNICODE) + titleLen = (EAS_U8) (titleLen << 1); + + /* zero the metadata buffer */ + if (pData->metadata.buffer) + EAS_HWMemSet(pData->metadata.buffer, 0, pData->metadata.bufferSize); + + /* read the song title */ + for (i = 0; i < titleLen; i++) + { + /* fetch character */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 8, &temp)) != EAS_SUCCESS) + return result; + + /* check for metadata callback */ + if (pData->metadata.callback) + { + if (i < (pData->metadata.bufferSize - 1)) + pData->metadata.buffer[i] = (char) temp; + } + } + + /* if host has registered callback, call it now */ + if (pData->metadata.callback) + (*pData->metadata.callback)(EAS_METADATA_TITLE, pData->metadata.buffer, pData->metadata.pUserData); + } + + /* must be temporary song */ + else if (temp != OTA_TEMPORARY_SONG_TYPE) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Expected OTA basic or temporary song type\n"); */ } + return EAS_ERROR_FILE_FORMAT; + } + + /* get the song length */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 8, &pData->numPatterns)) != EAS_SUCCESS) + return result; + + /* sanity check */ + if (pData->numPatterns == 0) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "OTA number of patterns is zero\n"); */ } + return EAS_ERROR_FILE_FORMAT; + } + + /* at start of first pattern */ + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_FetchBitField() + *---------------------------------------------------------------------------- + * Purpose: + * Fetch a specified number of bits from the input stream + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT OTA_FetchBitField (EAS_HW_DATA_HANDLE hwInstData, S_OTA_DATA *pData, EAS_I32 numBits, EAS_U8 *pValue) +{ + EAS_RESULT result; + EAS_I32 bitsLeft; + EAS_U8 value; + + value = 0; + + /* do we have enough bits? */ + bitsLeft = pData->current.bitCount - numBits; + + /* not enough bits, assemble them from 2 characters */ + if (bitsLeft < 0) + { + /* grab the remaining bits from the previous byte */ + if (pData->current.bitCount) + /*lint -e{504,734} this is a legitimate shift operation */ + value = pData->current.dataByte << -bitsLeft; + + /* read the next byte */ + if ((result = EAS_HWGetByte(hwInstData, pData->fileHandle, &pData->current.dataByte)) != EAS_SUCCESS) + return result; + bitsLeft += 8; + } + + /* more bits than needed? */ + if (bitsLeft > 0) + { + value |= pData->current.dataByte >> bitsLeft; + pData->current.bitCount = (EAS_U8) bitsLeft; + pData->current.dataByte = pData->current.dataByte & (0xff >> (8 - bitsLeft)); + } + + /* exactly the right number of bits */ + else + { + value |= pData->current.dataByte; + pData->current.bitCount = 0; + } + + *pValue = value; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_SavePosition() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT OTA_SavePosition (EAS_HW_DATA_HANDLE hwInstData, S_OTA_DATA *pData, S_OTA_LOC *pLoc) +{ + EAS_HWMemCpy(pLoc, &pData->current, sizeof(S_OTA_LOC)); + return EAS_HWFilePos(hwInstData, pData->fileHandle, &pLoc->fileOffset); +} + +/*---------------------------------------------------------------------------- + * OTA_RestorePosition() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT OTA_RestorePosition (EAS_HW_DATA_HANDLE hwInstData, S_OTA_DATA *pData, S_OTA_LOC *pLoc) +{ + EAS_HWMemCpy(&pData->current, pLoc, sizeof(S_OTA_LOC)); + pData->restore.fileOffset = -1; + return EAS_HWFileSeek(hwInstData, pData->fileHandle, pLoc->fileOffset); +} + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_otadata.c b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_otadata.c new file mode 100755 index 0000000..7463a0c --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_otadata.c @@ -0,0 +1,41 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_otadata..c + * + * Contents and purpose: + * OTA Stream Parser data module for static memory model + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 547 $ + * $Date: 2007-01-31 16:30:17 -0800 (Wed, 31 Jan 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_types.h" +#include "eas_otadata.h" + +/*---------------------------------------------------------------------------- + * + * eas_OTAData + * + * Static memory allocation for OTA parser + *---------------------------------------------------------------------------- +*/ +S_OTA_DATA eas_OTAData; + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_otadata.h b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_otadata.h new file mode 100755 index 0000000..c06e3d3 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_otadata.h @@ -0,0 +1,81 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_otadata.h + * + * Contents and purpose: + * OTA File Parser + * + * This file contains data declarations for the OTA parser. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef EAS_OTADATA_H +#define EAS_OTADATA_H + +#include "eas_data.h" + +/* definition for state flags */ +#define OTA_FLAGS_UNICODE 0x01 /* unicode text */ + +/*---------------------------------------------------------------------------- + * + * S_OTA_DATA + * + * This structure contains the state data for the OTA parser + *---------------------------------------------------------------------------- +*/ + +typedef struct +{ + EAS_I32 fileOffset; /* offset to location in file */ + EAS_U8 patternLen; /* length of current pattern */ + EAS_U8 dataByte; /* previous char from file */ + EAS_U8 bitCount; /* bit count in char */ +} S_OTA_LOC; + +typedef struct +{ + EAS_FILE_HANDLE fileHandle; /* file handle */ + S_SYNTH *pSynth; /* synth handle */ + EAS_I32 fileOffset; /* offset to start of data */ + EAS_I32 time; /* current time in 256ths of a msec */ + EAS_U32 tick; /* length of 32nd note in 256th of a msec */ + EAS_U32 restTicks; /* ticks to rest after current note */ + S_OTA_LOC patterns[4]; /* pattern locations */ + S_OTA_LOC current; /* current location */ + S_OTA_LOC restore; /* previous location */ + S_METADATA_CB metadata; /* metadata callback */ + EAS_U8 flags; /* bit flags */ + EAS_U8 numPatterns; /* number of patterns left in song */ + EAS_U8 currentPattern; /* current pattern for loop */ + EAS_U8 note; /* MIDI note number */ + EAS_U8 octave; /* octave modifier */ + EAS_U8 style; /* from STYLE */ + EAS_U8 velocity; /* current volume */ + EAS_U8 state; /* current state EAS_STATE_XXXX */ + EAS_U8 loopCount; /* loop count for pattern */ +} S_OTA_DATA; + +#endif + + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_pan.c b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_pan.c new file mode 100755 index 0000000..ae4c69d --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_pan.c @@ -0,0 +1,98 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_pan.c + * + * Contents and purpose: + * Calculates left and right gain multipliers based on a pan value from -63 to +63 + * + * NOTES: + * The _CMX_PARSER and _MFI_PARSER preprocessor symbols determine + * whether the parser works for those particular file formats. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_pan.h" +#include "eas_math.h" + +/*---------------------------------------------------------------------------- + * EAS_CalcPanControl() + *---------------------------------------------------------------------------- + * Purpose: + * Assign the left and right gain values corresponding to the given pan value. + * + * This routine uses sin/cos approximations for an equal power curve: + * + * sin(x) = (2-4*c)*x^2 + c + x + * cos(x) = (2-4*c)*x^2 + c - x + * + * where c = 1/sqrt(2) + * using the a0 + x*(a1 + x*a2) approach + * + * Inputs: + * pan - pan value (-63 to + 63) + * + * Outputs: + * pGainLeft linear gain multiplier for left channel (15-bit fraction) + * pGainRight linear gain multiplier for left channel (15-bit fraction) + * + * Side Effects: + *---------------------------------------------------------------------------- +*/ +void EAS_CalcPanControl (EAS_INT pan, EAS_I16 *pGainLeft, EAS_I16 *pGainRight) +{ + EAS_INT temp; + EAS_INT netAngle; + + /* impose hard limit */ + if (pan < -63) + netAngle = -63; + else if (pan > 63) + netAngle = 63; + else + netAngle = pan; + + /*lint -e{701} */ + netAngle = netAngle << 8; + + /* calculate sin */ + temp = EG1_ONE + FMUL_15x15(COEFF_PAN_G2, netAngle); + temp = COEFF_PAN_G0 + FMUL_15x15(temp, netAngle); + + if (temp > SYNTH_FULL_SCALE_EG1_GAIN) + temp = SYNTH_FULL_SCALE_EG1_GAIN; + else if (temp < 0) + temp = 0; + + *pGainRight = (EAS_I16) temp; + + /* calculate cos */ + temp = -EG1_ONE + FMUL_15x15(COEFF_PAN_G2, netAngle); + temp = COEFF_PAN_G0 + FMUL_15x15(temp, netAngle); + if (temp > SYNTH_FULL_SCALE_EG1_GAIN) + temp = SYNTH_FULL_SCALE_EG1_GAIN; + else if (temp < 0) + temp = 0; + + *pGainLeft = (EAS_I16) temp; +} + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_pan.h b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_pan.h new file mode 100755 index 0000000..cb0a90d --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_pan.h @@ -0,0 +1,66 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_pan.h + * + * Contents and purpose: + * Calculates left and right gain multipliers based on a pan value from -63 to +63 + * + * NOTES: + * The _CMX_PARSER and _MFI_PARSER preprocessor symbols determine + * whether the parser works for those particular file formats. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef EAS_PAN_H +#define _EAS_PAN_H + +#include "eas_types.h" + +/*---------------------------------------------------------------------------- + * EAS_CalcPanControl() + *---------------------------------------------------------------------------- + * Purpose: + * Assign the left and right gain values corresponding to the given pan value. + * + * This routine uses sin/cos approximations for an equal power curve: + * + * sin(x) = (2-4*c)*x^2 + c + x + * cos(x) = (2-4*c)*x^2 + c - x + * + * where c = 1/sqrt(2) + * using the a0 + x*(a1 + x*a2) approach + * + * Inputs: + * pan - pan value (-63 to + 63) + * + * Outputs: + * pGainLeft linear gain multiplier for left channel (15-bit fraction) + * pGainRight linear gain multiplier for left channel (15-bit fraction) + * + * Side Effects: + *---------------------------------------------------------------------------- +*/ +void EAS_CalcPanControl (EAS_INT pan, EAS_I16 *pGainLeft, EAS_I16 *pGainRight); + +#endif + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_parser.h b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_parser.h new file mode 100755 index 0000000..96ec35b --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_parser.h @@ -0,0 +1,98 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_parser.h + * + * Contents and purpose: + * Interface declarations for the generic parser interface + * + * This header only contains declarations that are specific + * to this implementation. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 767 $ + * $Date: 2007-07-19 13:47:31 -0700 (Thu, 19 Jul 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_PARSER_H +#define _EAS_PARSER_H + +#include "eas_types.h" + + +/* metadata callback */ +typedef struct s_metadata_cb_tag +{ + EAS_METADATA_CBFUNC callback; + char *buffer; + EAS_VOID_PTR pUserData; + EAS_I32 bufferSize; +} S_METADATA_CB; + +/* generic parser interface */ +typedef struct +{ + EAS_RESULT (* EAS_CONST pfCheckFileType)(struct s_eas_data_tag *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset); + EAS_RESULT (* EAS_CONST pfPrepare)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData); + EAS_RESULT (* EAS_CONST pfTime)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime); + EAS_RESULT (* EAS_CONST pfEvent)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData, EAS_INT parseMode); + EAS_RESULT (* EAS_CONST pfState)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData, EAS_STATE *pState); + EAS_RESULT (* EAS_CONST pfClose)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData); + EAS_RESULT (* EAS_CONST pfReset)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData); + EAS_RESULT (* EAS_CONST pfPause)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData); + EAS_RESULT (* EAS_CONST pfResume)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData); + EAS_RESULT (* EAS_CONST pfLocate)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData, EAS_I32 time, EAS_BOOL *pParserLocate); + EAS_RESULT (* EAS_CONST pfSetData)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value); + EAS_RESULT (* EAS_CONST pfGetData)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue); + EAS_RESULT (* EAS_CONST pfGetMetaData)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pMediaLength); +} S_FILE_PARSER_INTERFACE; + +typedef enum +{ + eParserModePlay, + eParserModeLocate, + eParserModeMute, + eParserModeMetaData +} E_PARSE_MODE; + +typedef enum +{ + PARSER_DATA_FILE_TYPE, + PARSER_DATA_PLAYBACK_RATE, + PARSER_DATA_TRANSPOSITION, + PARSER_DATA_VOLUME, + PARSER_DATA_SYNTH_HANDLE, + PARSER_DATA_METADATA_CB, + PARSER_DATA_DLS_COLLECTION, + PARSER_DATA_EAS_LIBRARY, + PARSER_DATA_POLYPHONY, + PARSER_DATA_PRIORITY, + PARSER_DATA_FORMAT, + PARSER_DATA_MEDIA_LENGTH, + PARSER_DATA_JET_CB, + PARSER_DATA_MUTE_FLAGS, + PARSER_DATA_SET_MUTE, + PARSER_DATA_CLEAR_MUTE, + PARSER_DATA_NOTE_COUNT, + PARSER_DATA_MAX_PCM_STREAMS, + PARSER_DATA_GAIN_OFFSET, + PARSER_DATA_PLAY_MODE +} E_PARSER_DATA; + +#endif /* #ifndef _EAS_PARSER_H */ diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_pcm.c b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_pcm.c new file mode 100755 index 0000000..ff3f6f9 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_pcm.c @@ -0,0 +1,1482 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_pcm.c + * + * Contents and purpose: + * Implements the PCM engine including ADPCM decode for SMAF and CMX audio playback. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 849 $ + * $Date: 2007-08-28 08:59:11 -0700 (Tue, 28 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_data.h" +#include "eas_report.h" +#include "eas_host.h" +#include "eas_config.h" +#include "eas_parser.h" +#include "eas_pcm.h" +#include "eas_math.h" +#include "eas_mixer.h" + +#define PCM_MIXER_GUARD_BITS (NUM_MIXER_GUARD_BITS + 1) + +/*---------------------------------------------------------------------------- + * Decoder interfaces + *---------------------------------------------------------------------------- +*/ + +static EAS_RESULT LinearPCMDecode (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState); +static EAS_RESULT LinearPCMLocate (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState, EAS_I32 time); + +static const S_DECODER_INTERFACE PCMDecoder = +{ + NULL, + LinearPCMDecode, + LinearPCMLocate, +}; + +/* SMAF ADPCM decoder */ +#ifdef _SMAF_PARSER +extern S_DECODER_INTERFACE SmafDecoder; +#define SMAF_DECODER &SmafDecoder +extern S_DECODER_INTERFACE Smaf7BitDecoder; +#define SMAF_7BIT_DECODER &Smaf7BitDecoder +#else +#define SMAF_DECODER NULL +#define SMAF_7BIT_DECODER NULL +#endif + +/* IMA ADPCM decoder */ +#ifdef _IMA_DECODER +extern S_DECODER_INTERFACE IMADecoder; +#define IMA_DECODER &IMADecoder +#else +#define IMA_DECODER NULL +#endif + +static const S_DECODER_INTERFACE * const decoders[] = +{ + &PCMDecoder, + SMAF_DECODER, + IMA_DECODER, + SMAF_7BIT_DECODER +}; + +/*---------------------------------------------------------------------------- + * Sample rate conversion + *---------------------------------------------------------------------------- +*/ + +#define SRC_RATE_MULTIPLER (0x40000000 / _OUTPUT_SAMPLE_RATE) + +#ifdef _LOOKUP_SAMPLE_RATE +static const EAS_U32 srcConvRate[][2] = +{ + 4000L, (4000L << 15) / _OUTPUT_SAMPLE_RATE, + 8000L, (8000L << 15) / _OUTPUT_SAMPLE_RATE, + 11025L, (11025L << 15) / _OUTPUT_SAMPLE_RATE, + 12000L, (12000L << 15) / _OUTPUT_SAMPLE_RATE, + 16000L, (16000L << 15) / _OUTPUT_SAMPLE_RATE, + 22050L, (22050L << 15) / _OUTPUT_SAMPLE_RATE, + 24000L, (24000L << 15) / _OUTPUT_SAMPLE_RATE, + 32000L, (32000L << 15) / _OUTPUT_SAMPLE_RATE +}; +static EAS_U32 CalcBaseFreq (EAS_U32 sampleRate); +#define SRC_CONV_RATE_ENTRIES (sizeof(srcConvRate)/sizeof(EAS_U32)/2) +#endif + + +/* interface prototypes */ +static EAS_RESULT RenderPCMStream (S_EAS_DATA *pEASData, S_PCM_STATE *pState, EAS_I32 numSamples); + + +/* local prototypes */ +static S_PCM_STATE *FindSlot (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_PCM_CALLBACK pCallbackFunc, EAS_VOID_PTR cbInstData); +static EAS_RESULT InitPCMStream (S_EAS_DATA *pEASData, S_PCM_STATE *pState); + +/*---------------------------------------------------------------------------- + * EAS_PEInit() + *---------------------------------------------------------------------------- + * Purpose: + * Initializes the PCM engine + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEInit (S_EAS_DATA *pEASData) +{ + S_PCM_STATE *pState; + EAS_INT i; + + /* check for static memory allocation */ + if (pEASData->staticMemoryModel) + pEASData->pPCMStreams = EAS_CMEnumData(EAS_CM_PCM_DATA); + /* allocate dynamic memory */ + else + pEASData->pPCMStreams = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_PCM_STATE) * MAX_PCM_STREAMS); + + if (!pEASData->pPCMStreams) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Failed to allocate memory for PCM streams\n"); */ } + return EAS_ERROR_MALLOC_FAILED; + } + + //zero the memory to insure complete initialization + EAS_HWMemSet((void *)(pEASData->pPCMStreams),0, sizeof(S_PCM_STATE) * MAX_PCM_STREAMS); + + /* initialize the state data */ + for (i = 0, pState = pEASData->pPCMStreams; i < MAX_PCM_STREAMS; i++, pState++) + pState->fileHandle = NULL; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_PEShutdown() + *---------------------------------------------------------------------------- + * Purpose: + * Shuts down the PCM engine + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEShutdown (S_EAS_DATA *pEASData) +{ + + /* free any dynamic memory */ + if (!pEASData->staticMemoryModel) + { + if (pEASData->pPCMStreams) + { + EAS_HWFree(pEASData->hwInstData, pEASData->pPCMStreams); + pEASData->pPCMStreams = NULL; + } + } + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_PERender() + *---------------------------------------------------------------------------- + * Purpose: + * Render a buffer of PCM audio + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PERender (S_EAS_DATA* pEASData, EAS_I32 numSamples) +{ + S_PCM_STATE *pState; + EAS_RESULT result; + EAS_INT i; + + /* render all the active streams */ + for (i = 0, pState = pEASData->pPCMStreams; i < MAX_PCM_STREAMS; i++, pState++) + { + if ((pState->fileHandle) && (pState->state != EAS_STATE_STOPPED) && (pState->state != EAS_STATE_PAUSED)) + if ((result = RenderPCMStream(pEASData, pState, numSamples)) != EAS_SUCCESS) + return result; + } + return EAS_SUCCESS; +} + + +/*---------------------------------------------------------------------------- + * EAS_PEState() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current state of the stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * pState - pointer to variable to store state + * + * Outputs: + * + * + * Side Effects: + * + * Notes: + * This interface is also exposed in the internal library for use by the other modules. + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT EAS_PEState (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pInstData, EAS_STATE *pState) +{ + /* return current state */ + *pState = pInstData->state; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_PEClose() + *---------------------------------------------------------------------------- + * Purpose: + * Close the file and clean up + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEClose (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pState) +{ + EAS_RESULT result; + + if ((result = EAS_HWCloseFile(pEASData->hwInstData, pState->fileHandle)) != EAS_SUCCESS) + return result; + + pState->fileHandle = NULL; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * PCM_Reset() + *---------------------------------------------------------------------------- + * Purpose: + * Reset the sequencer. Used for locating backwards in the file. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEReset (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pState) +{ + EAS_RESULT result; + + /* reset file position to first byte of data in the stream */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pState->fileHandle, pState->startPos)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %d seeking to start of PCM file\n", result); */ } + return result; + } + + /* re-initialize stream */ + return InitPCMStream(pEASData, pState); +} + +/*---------------------------------------------------------------------------- + * EAS_PEOpenStream() + *---------------------------------------------------------------------------- + * Purpose: + * Starts up a PCM playback + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEOpenStream (S_EAS_DATA *pEASData, S_PCM_OPEN_PARAMS *pParams, EAS_PCM_HANDLE *pHandle) +{ + EAS_RESULT result; + S_PCM_STATE *pState; + EAS_I32 filePos; + + /* make sure we support this decoder */ + if (pParams->decoder >= NUM_DECODER_MODULES) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Decoder selector out of range\n"); */ } + return EAS_ERROR_PARAMETER_RANGE; + } + if (decoders[pParams->decoder] == NULL) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Decoder module not available\n"); */ } + return EAS_ERROR_FEATURE_NOT_AVAILABLE; + } + + /* find a slot for the new stream */ + if ((pState = FindSlot(pEASData, pParams->fileHandle, pParams->pCallbackFunc, pParams->cbInstData)) == NULL) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Unable to open ADPCM stream, too many streams open\n"); */ } + return EAS_ERROR_MAX_PCM_STREAMS; + } + + /* get the current file position */ + if ((result = EAS_HWFilePos(pEASData->hwInstData, pState->fileHandle, &filePos)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_HWFilePos returned %ld\n",result); */ } + pState->fileHandle = NULL; + return result; + } + + pState->pDecoder = decoders[pParams->decoder]; + pState->startPos = filePos; + pState->bytesLeftLoop = pState->byteCount = pParams->size; + pState->loopStart = pParams->loopStart; + pState->samplesTilLoop = (EAS_I32) pState->loopStart; + pState->loopSamples = pParams->loopSamples; + pState->samplesInLoop = 0; + pState->blockSize = (EAS_U16) pParams->blockSize; + pState->flags = pParams->flags; + pState->envData = pParams->envData; + pState->volume = pParams->volume; + pState->sampleRate = (EAS_U16) pParams->sampleRate; + + /* set the base frequency */ + pState->basefreq = (SRC_RATE_MULTIPLER * (EAS_U32) pParams->sampleRate) >> 15; + + /* calculate shift for frequencies > 1.0 */ + pState->rateShift = 0; + while (pState->basefreq > 32767) + { + pState->basefreq = pState->basefreq >> 1; + pState->rateShift++; + } + + /* initialize */ + if ((result = InitPCMStream(pEASData, pState)) != EAS_SUCCESS) + return result; + + *pHandle = pState; + + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "EAS_PEOpenStream: StartPos=%d, byteCount = %d, loopSamples=%d\n", + pState->startPos, pState->byteCount, pState->loopSamples); */ } + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_PEContinueStream() + *---------------------------------------------------------------------------- + * Purpose: + * Continues a PCM stream + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -e{715} reserved for future use */ +EAS_RESULT EAS_PEContinueStream (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pState, EAS_I32 size) +{ + + /* add new samples to count */ + pState->bytesLeft += size; + if (pState->bytesLeft > 0) + pState->flags &= ~PCM_FLAGS_EMPTY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_PEGetFileHandle() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the file handle of a stream + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT EAS_PEGetFileHandle (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pState, EAS_FILE_HANDLE *pFileHandle) +{ + *pFileHandle = pState->fileHandle; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_PEUpdateParams() + *---------------------------------------------------------------------------- + * Purpose: + * Update the pitch and volume parameters for a PCM stream + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_PCM_STATE for this stream + * gainLeft - linear gain multipler in 1.15 fraction format + * gainRight - linear gain multipler in 1.15 fraction format + * pitch - pitch shift in cents + * initial - initial settings, set current gain + * + * Outputs: + * + * + * Side Effects: + * + * Notes + * In mono mode, leftGain controls the output gain and rightGain is ignored + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +/*lint -esym(715, gainRight) used only in 2-channel version */ +EAS_RESULT EAS_PEUpdateParams (S_EAS_DATA* pEASData, EAS_PCM_HANDLE pState, EAS_I16 pitch, EAS_I16 gainLeft, EAS_I16 gainRight) +{ + + pState->gainLeft = gainLeft; + +#if (NUM_OUTPUT_CHANNELS == 2) + pState->gainRight = gainRight; +#endif + + pState->pitch = pitch; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_PELocate() + *---------------------------------------------------------------------------- + * Purpose: + * This function seeks to the requested place in the file. Accuracy + * is dependent on the sample rate and block size. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * pState - stream handle + * time - media time in milliseconds + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PELocate (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pState, EAS_I32 time) +{ + if (pState->pDecoder->pfLocate == NULL) + return EAS_ERROR_FEATURE_NOT_AVAILABLE; + + return pState->pDecoder->pfLocate(pEASData, pState, time); +} + +/*---------------------------------------------------------------------------- + * EAS_PEUpdateVolume() + *---------------------------------------------------------------------------- + * Purpose: + * Update the volume parameters for a PCM stream + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_PCM_STATE for this stream + * gainLeft - linear gain multipler in 1.15 fraction format + * gainRight - linear gain multipler in 1.15 fraction format + * initial - initial settings, set current gain + * + * Outputs: + * + * + * Side Effects: + * + * Notes + * In mono mode, leftGain controls the output gain and rightGain is ignored + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT EAS_PEUpdateVolume (S_EAS_DATA* pEASData, EAS_PCM_HANDLE pState, EAS_I16 volume) +{ + pState->volume = volume; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_PEUpdatePitch() + *---------------------------------------------------------------------------- + * Purpose: + * Update the pitch parameter for a PCM stream + * + * Inputs: + * pEASData - pointer to EAS library instance data + * pState - pointer to S_PCM_STATE for this stream + * pitch - new pitch value in pitch cents + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT EAS_PEUpdatePitch (S_EAS_DATA* pEASData, EAS_PCM_HANDLE pState, EAS_I16 pitch) +{ + pState->pitch = pitch; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_PEPause() + *---------------------------------------------------------------------------- + * Purpose: + * Mute and stop rendering a PCM stream. Sets the gain target to zero and stops the playback + * at the end of the next audio frame. + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_PCM_STATE for this stream + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT EAS_PEPause (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pState) +{ + /* set state to stopping */ + pState->state = EAS_STATE_PAUSING; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_PEResume() + *---------------------------------------------------------------------------- + * Purpose: + * Resume rendering a PCM stream. Sets the gain target back to its + * previous setting and restarts playback at the end of the next audio + * frame. + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_PCM_STATE for this stream + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT EAS_PEResume (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pState) +{ + /* set state to stopping */ + pState->state = EAS_STATE_PLAY; + return EAS_SUCCESS; +} + +EAS_U32 getDecayScale(EAS_U32 index) +{ + EAS_U32 utemp; + + //envelope decay segment + switch (index) + { + case 0: //no decay + utemp = 512;//32768; + break; + case 1: //.0156 dB per update + utemp = 511;//32709; + break; + case 2: //.03125 + utemp = 510;//32649; + break; + case 3: //.0625 + utemp = 508;//32532; + break; + case 4: //.125 + utemp = 505;//32298; + break; + case 5: //.25 + utemp = 497;//31835; + break; + case 6: //.5 + utemp = 483;//30929; + break; + case 7: //1.0 + utemp = 456;//29193; + break; + case 8: //2.0 + utemp = 406;//26008; + break; + case 9: //4.0 + utemp = 323;//20642; + break; + case 10: //8.0 + utemp = 203;//13004; + break; + case 11: //16.0 + utemp = 81;//5160; + break; + case 12: //32.0 + utemp = 13;//813; + break; + case 13: //64.0 + utemp = 0;//20; + break; + case 14: //128.0 + utemp = 0; + break; + case 15: //256.0 + default: + utemp = 0; + break; + } + //printf("getdecayscale returned %d\n",utemp); + return utemp; +} + +EAS_U32 getAttackIncrement(EAS_U32 index) +{ + EAS_U32 utemp; + + //envelope decay segment + switch (index) + { + case 0: + utemp = 32; + break; + case 1: + utemp = 64; + break; + case 2: + utemp = 128; + break; + case 3: + utemp = 256; + break; + case 4: + utemp = 512; + break; + case 5: + utemp = 1024; + break; + case 6: + utemp = 2048; + break; + case 7: + utemp = 4096; + break; + case 8: + utemp = 8192; + break; + case 9: + utemp = 16384; + break; + case 10: + utemp = 32768; + break; + case 11: + utemp = 65536; + break; + case 12: + utemp = 65536; + break; + case 13: + utemp = 65536; + break; + case 14: + utemp = 65535; + break; + case 15: + default: + utemp = 0; + break; + } + //printf("getattackincrement returned %d\n",utemp); + return utemp; +} + +/*---------------------------------------------------------------------------- + * EAS_PERelease() + *---------------------------------------------------------------------------- + * Purpose: + * Put the PCM stream envelope into release. + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_PCM_STATE for this stream + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT EAS_PERelease (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pState) +{ + EAS_U32 utemp; + + //printf("handling note-off part of envelope\n"); + /*if the note is not ignore release or sustained*/ + if (((pState->envData >> 24) & 0x0F)==0) + { + /* set envelope state to release */ + pState->envState = PCM_ENV_RELEASE; + utemp = ((pState->envData >> 20) & 0x0F); + pState->envScale = getDecayScale(utemp); //getReleaseScale(utemp); + } + else + { + /*else change envelope state to sustain */ + pState->envState = PCM_ENV_SUSTAIN; + utemp = ((pState->envData >> 28) & 0x0F); + pState->envScale = getDecayScale(utemp); //getSustainScale(utemp); + } + //since we are in release, don't let anything hang around too long + //printf("checking env scale, val = %d\n",((S_PCM_STATE*) handle)->envScale); + if (pState->envScale > 505) + pState->envScale = 505; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * FindSlot() + *---------------------------------------------------------------------------- + * Purpose: + * Locates an empty stream slot and assigns the file handle + * + * Inputs: + * pEASData - pointer to EAS library instance data + * fileHandle - file handle + * pCallbackFunc - function to be called back upon EAS_STATE_STOPPED + * + * Outputs: + * returns handle to slot or NULL if all slots are used + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static S_PCM_STATE *FindSlot (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_PCM_CALLBACK pCallbackFunc, EAS_VOID_PTR cbInstData) +{ + EAS_INT i; + S_PCM_STATE *pState; + +#ifndef NO_PCM_STEAL + S_PCM_STATE *foundState = NULL; + EAS_INT count = 0; + EAS_U32 startOrder = 0xFFFFFFFF; + S_PCM_STATE *stealState = NULL; + EAS_U32 youngest = 0; + + /* find an empty slot, count total in use, and find oldest in use (lowest start order) */ + for (i = 0, pState = pEASData->pPCMStreams; i < MAX_PCM_STREAMS; i++, pState++) + { + /* if this one is available */ + if (pState->fileHandle == NULL) + { + foundState = pState; + } + /* else this one is in use, so see if it is the oldest, and count total in use */ + /* also find youngest */ + else + { + /*one more voice in use*/ + count++; + /* is this the oldest? (lowest start order) */ + if ((pState->state != EAS_STATE_STOPPING) && (pState->startOrder < startOrder)) + { + /* remember this one */ + stealState = pState; + /* remember the oldest so far */ + startOrder = pState->startOrder; + } + /* is this the youngest? (highest start order) */ + if (pState->startOrder >= youngest) + { + youngest = pState->startOrder; + } + } + } + + /* if there are too many voices active, stop the oldest one */ + if (count > PCM_STREAM_THRESHOLD) + { + //printf("stealing!!!\n"); + /* make sure we got one, although we should always have one at this point */ + if (stealState != NULL) + { + //flag this as stopping, so it will get shut off + stealState->state = EAS_STATE_STOPPING; + } + } + + /* if there are no available open streams (we won't likely see this, due to stealing) */ + if (foundState == NULL) + return NULL; + + /* save info */ + foundState->startOrder = youngest + 1; + foundState->fileHandle = fileHandle; + foundState->pCallback = pCallbackFunc; + foundState->cbInstData = cbInstData; + return foundState; +#else + /* find an empty slot*/ + for (i = 0; i < MAX_PCM_STREAMS; i++) + { + pState = &pEASData->pPCMStreams[i]; + if (pState->fileHandle != NULL) + continue; + + pState->fileHandle = fileHandle; + pState->pCallback = pCallbackFunc; + pState->cbInstData = cbInstData; + return pState; + } + return NULL; +#endif +} + +#ifdef _LOOKUP_SAMPLE_RATE +/*---------------------------------------------------------------------------- + * CalcBaseFreq() + *---------------------------------------------------------------------------- + * Purpose: + * Calculates the fractional phase increment for the sample rate converter + * + * Inputs: + * sampleRate - sample rate in samples/sec + * + * Outputs: + * Returns fractional sample rate with a 15-bit fraction + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_U32 CalcBaseFreq (EAS_U32 sampleRate) +{ + EAS_INT i; + + /* look up the conversion rate */ + for (i = 0; i < (EAS_INT)(SRC_CONV_RATE_ENTRIES); i ++) + { + if (srcConvRate[i][0] == sampleRate) + return srcConvRate[i][1]; + } + + /* if not found in table, do it the long way */ + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Sample rate %u not in table, calculating by division\n", sampleRate); */ } + + return (SRC_RATE_MULTIPLER * (EAS_U32) sampleRate) >> 15; +} +#endif + +/*---------------------------------------------------------------------------- + * InitPCMStream() + *---------------------------------------------------------------------------- + * Purpose: + * Start an ADPCM stream playback. Decodes the header, preps the engine. + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT InitPCMStream (S_EAS_DATA *pEASData, S_PCM_STATE *pState) +{ + + /* initialize the data structure */ + pState->bytesLeft = pState->byteCount; + pState->phase = 0; + pState->srcByte = 0; + pState->decoderL.acc = 0; + pState->decoderL.output = 0; + pState->decoderL.x0 = pState->decoderL.x1 = 0; + pState->decoderL.step = 0; + pState->decoderR.acc = 0; + pState->decoderR.output = 0; + pState->decoderR.x0 = pState->decoderR.x1 = 0; + pState->decoderR.step = 0; + pState->hiNibble = EAS_FALSE; + pState->pitch = 0; + pState->blockCount = 0; + pState->gainLeft = PCM_DEFAULT_GAIN_SETTING; +// pState->currentGainLeft = PCM_DEFAULT_GAIN_SETTING; + pState->envValue = 0; + pState->envState = PCM_ENV_START; + +#if (NUM_OUTPUT_CHANNELS == 2) + pState->gainRight = PCM_DEFAULT_GAIN_SETTING; +// pState->currentGainRight = PCM_DEFAULT_GAIN_SETTING; +#endif + pState->state = EAS_STATE_READY; + + /* initialize the decoder */ + if (pState->pDecoder->pfInit) + return (*pState->pDecoder->pfInit)(pEASData, pState); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RenderPCMStream() + *---------------------------------------------------------------------------- + * Purpose: + * Decodes a buffer of ADPCM data. + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RenderPCMStream (S_EAS_DATA *pEASData, S_PCM_STATE *pState, EAS_I32 numSamples) +{ + EAS_RESULT result; + EAS_U32 phaseInc; + EAS_I32 gainLeft, gainIncLeft; + EAS_I32 *pOut; + EAS_I32 temp; + EAS_U32 utemp; + +#if (NUM_OUTPUT_CHANNELS == 2) + EAS_I32 gainRight, gainIncRight; +#endif + +#if 0 + printf("env data: AR = %d, DR = %d, SL = %d, SR = %d, RR = %d\n", + ((pState->envData >> 12) & 0x0F), + ((pState->envData >> 16) & 0x0F), + ((pState->envData >> 8) & 0x0F), + ((pState->envData >> 28) & 0x0F), + ((pState->envData >> 20) & 0x0F)); +#endif + + if (pState->envState == PCM_ENV_START) + { + //printf("env start\n"); + utemp = ((pState->envData >> 12) & 0x0F); + //if fastest rate, attack is already completed + //do the same for slowest rate, since that allows zero to be passed for default envelope + if (utemp == 0x0F || utemp == 0x00) + { + //start envelope at full + pState->envValue = (32768<<7); + //jump right into decay + utemp = ((pState->envData >> 16) & 0x0F); + pState->envScale = getDecayScale(utemp); + pState->envState = PCM_ENV_DECAY; + pState->currentGainLeft = (EAS_I16) FMUL_15x15(pState->gainLeft, pState->volume); + pState->currentGainRight = (EAS_I16) FMUL_15x15(pState->gainRight, pState->volume); + } + //else attack has a ramp + else + { + //start the envelope very low + pState->envValue = (2<<7); + pState->currentGainLeft = 0; + pState->currentGainRight = 0; + //get envelope attack scaling value + pState->envScale = getAttackIncrement(utemp); + //go to attack state + pState->envState = PCM_ENV_ATTACK; + } + } + if (pState->envState == PCM_ENV_ATTACK) + { + //printf("env attack, env value = %d, env scale = %d\n",pState->envValue>>7,pState->envScale); + //update envelope value + pState->envValue = pState->envValue + (pState->envScale << 7); + //check envelope level and update state if needed + if (pState->envValue >= (32768<<7)) + { + pState->envValue = (32768<<7); + utemp = ((pState->envData >> 16) & 0x0F); + pState->envScale = getDecayScale(utemp); + pState->envState = PCM_ENV_DECAY; + } + } + else if (pState->envState == PCM_ENV_DECAY) + { + //printf("env decay, env value = %d, env scale = %d\n",pState->envValue>>7,pState->envScale); + //update envelope value + pState->envValue = (pState->envValue * pState->envScale)>>9; + //check envelope level against sustain level and update state if needed + utemp = ((pState->envData >> 8) & 0x0F); + if (utemp == (EAS_U32)0x0F) + utemp = (2<<7); + else + { + utemp = ((32769<<7) >> (utemp>>1)); + } + if (pState->envValue <= utemp) + { + utemp = ((pState->envData >> 28) & 0x0F); + pState->envScale = getDecayScale(utemp); //getSustainScale(utemp); + pState->envState = PCM_ENV_SUSTAIN; + } + } + else if (pState->envState == PCM_ENV_SUSTAIN) + { + //printf("env sustain, env value = %d, env scale = %d\n",pState->envValue>>7,pState->envScale); + //update envelope value + pState->envValue = (pState->envValue * pState->envScale)>>9; + //check envelope level against bottom level and update state if needed + if (pState->envValue <= (2<<7)) + { + //no more decay + pState->envScale = 512; + pState->envState = PCM_ENV_END; + } + } + else if (pState->envState == PCM_ENV_RELEASE) + { + //printf("env release, env value = %d, env scale = %d\n",pState->envValue>>7,pState->envScale); + //update envelope value + pState->envValue = (pState->envValue * pState->envScale)>>9; + //check envelope level against bottom level and update state if needed + if (pState->envValue <= (2<<7)) + { + //no more decay + pState->envScale = 512; + pState->envState = PCM_ENV_END; + } + } + else if (pState->envState == PCM_ENV_END) + { + //printf("env end\n"); + /* set state to stopping, already ramped down */ + pState->state = EAS_STATE_STOPPING; + } + + //pState->gainLeft = (EAS_U16)((pState->gainLeft * (pState->envValue>>7))>>15); + //pState->gainRight = (EAS_U16)((pState->gainRight * (pState->envValue>>7))>>15); + + /* gain to 32-bits to increase resolution on anti-zipper filter */ + /*lint -e{703} use shift for performance */ + gainLeft = (EAS_I32) pState->currentGainLeft << SYNTH_UPDATE_PERIOD_IN_BITS; +#if (NUM_OUTPUT_CHANNELS == 2) + /*lint -e{703} use shift for performance */ + gainRight = (EAS_I32) pState->currentGainRight << SYNTH_UPDATE_PERIOD_IN_BITS; +#endif + + /* calculate a new gain increment, gain target is zero if pausing */ + if ((pState->state == EAS_STATE_PAUSING) || (pState->state == EAS_STATE_PAUSED)) + { + gainIncLeft = -pState->currentGainLeft; +#if (NUM_OUTPUT_CHANNELS == 2) + gainIncRight= -pState->currentGainRight; +#endif + } + else + { + EAS_I32 gain = FMUL_15x15(pState->envValue >> 7, pState->volume); + gainIncLeft = FMUL_15x15(pState->gainLeft, gain) - pState->currentGainLeft; +#if (NUM_OUTPUT_CHANNELS == 2) + gainIncRight = FMUL_15x15(pState->gainRight, gain) - pState->currentGainRight; +#endif + } + + /* calculate phase increment */ + phaseInc = pState->basefreq; + + /* convert pitch cents to linear multiplier */ + if (pState->pitch) + { + temp = EAS_Calculate2toX(pState->pitch); + phaseInc = FMUL_15x15(phaseInc, temp); + } + phaseInc = phaseInc << pState->rateShift; + + /* pointer to mix buffer */ + pOut = pEASData->pMixBuffer; + + /* render a buffer of samples */ + while (numSamples--) + { + + /* interpolate an output sample */ + pState->decoderL.output = pState->decoderL.x0 + FMUL_15x15((pState->decoderL.x1 - pState->decoderL.x0), pState->phase & PHASE_FRAC_MASK); + + /* stereo output */ +#if (NUM_OUTPUT_CHANNELS == 2) + + /* stereo stream? */ + if (pState->flags & PCM_FLAGS_STEREO) + pState->decoderR.output = pState->decoderR.x0 + FMUL_15x15((pState->decoderR.x1 - pState->decoderR.x0), pState->phase & PHASE_FRAC_MASK); + + /* gain scale and mix */ + /*lint -e{704} use shift instead of division */ + *pOut++ += (pState->decoderL.output * (gainLeft >> SYNTH_UPDATE_PERIOD_IN_BITS)) >> PCM_MIXER_GUARD_BITS; + gainLeft += gainIncLeft; + + /*lint -e{704} use shift instead of division */ + if (pState->flags & PCM_FLAGS_STEREO) + *pOut++ += (pState->decoderR.output * (gainRight >> SYNTH_UPDATE_PERIOD_IN_BITS)) >> PCM_MIXER_GUARD_BITS; + else + *pOut++ += (pState->decoderL.output * (gainRight >> SYNTH_UPDATE_PERIOD_IN_BITS)) >> PCM_MIXER_GUARD_BITS; + + gainRight += gainIncRight; + + /* mono output */ +#else + /* if stereo stream, decode right channel and mix to mono */ + if (pState->flags & PCM_FLAGS_STEREO) + { + pState->decoderR.output= pState->decoderR.x0 + FMUL_15x15((pState->decoderR.x1 - pState->decoderR.x0), pState->phase & PHASE_FRAC_MASK); + + /* for mono, sum stereo ADPCM to mono */ + /*lint -e{704} use shift instead of division */ + *pOut++ += ((pState->decoderL.output + pState->decoderR.output) * (gainLeft >> SYNTH_UPDATE_PERIOD_IN_BITS)) >> PCM_MIXER_GUARD_BITS; + } + else + /*lint -e{704} use shift instead of division */ + *pOut++ += (pState->decoderL.output * (gainLeft >> SYNTH_UPDATE_PERIOD_IN_BITS)) >> PCM_MIXER_GUARD_BITS; + + gainLeft += gainIncLeft; +#endif + + /* advance phase accumulator */ + pState->phase += phaseInc; + + /* if integer part of phase accumulator is non-zero, advance to next sample */ + while (pState->phase & ~PHASE_FRAC_MASK) + { + pState->decoderL.x0 = pState->decoderL.x1; + pState->decoderR.x0 = pState->decoderR.x1; + + /* give the source a chance to continue the stream */ + if (!pState->bytesLeft && pState->pCallback && ((pState->flags & PCM_FLAGS_EMPTY) == 0)) + { + pState->flags |= PCM_FLAGS_EMPTY; + (*pState->pCallback)(pEASData, pState->cbInstData, pState, EAS_STATE_EMPTY); + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "RenderPCMStream: After empty callback, bytesLeft = %d\n", pState->bytesLeft); */ } + } + + /* decode the next sample */ + if ((result = (*pState->pDecoder->pfDecodeSample)(pEASData, pState)) != EAS_SUCCESS) + return result; + + /* adjust phase by one sample */ + pState->phase -= (1L << NUM_PHASE_FRAC_BITS); + } + + } + + /* save new gain */ + /*lint -e{704} use shift instead of division */ + pState->currentGainLeft = (EAS_I16) (gainLeft >> SYNTH_UPDATE_PERIOD_IN_BITS); + +#if (NUM_OUTPUT_CHANNELS == 2) + /*lint -e{704} use shift instead of division */ + pState->currentGainRight = (EAS_I16) (gainRight >> SYNTH_UPDATE_PERIOD_IN_BITS); +#endif + + /* if pausing, set new state and notify */ + if (pState->state == EAS_STATE_PAUSING) + { + pState->state = EAS_STATE_PAUSED; + if (pState->pCallback) + (*pState->pCallback)(pEASData, pState->cbInstData, pState, pState->state); + } + + /* if out of data, set stopped state and notify */ + if (pState->bytesLeft == 0 || pState->state == EAS_STATE_STOPPING) + { + pState->state = EAS_STATE_STOPPED; + + /* do callback unless the file has already been closed */ + if (pState->pCallback && pState->fileHandle) + (*pState->pCallback)(pEASData, pState->cbInstData, pState, pState->state); + } + + if (pState->state == EAS_STATE_READY) + pState->state = EAS_STATE_PLAY; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * LinearPCMDecode() + *---------------------------------------------------------------------------- + * Purpose: + * Decodes a PCM sample + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT LinearPCMDecode (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState) +{ + EAS_RESULT result; + EAS_HW_DATA_HANDLE hwInstData; + + hwInstData = ((S_EAS_DATA*) pEASData)->hwInstData; + + /* if out of data, check for loop */ + if ((pState->bytesLeft == 0) && (pState->loopSamples != 0)) + { + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pState->fileHandle, (EAS_I32) (pState->startPos + pState->loopLocation))) != EAS_SUCCESS) + return result; + pState->bytesLeft = pState->byteCount = (EAS_I32) pState->bytesLeftLoop; + pState->flags &= ~PCM_FLAGS_EMPTY; + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "LinearPCMDecode: Rewind file to %d, bytesLeft = %d\n", pState->startPos, pState->bytesLeft); */ } + } + + if (pState->bytesLeft) + { + + /* check format byte for 8-bit samples */ + if (pState->flags & PCM_FLAGS_8_BIT) + { + /* fetch left or mono sample */ + if ((result = EAS_HWGetByte(hwInstData, pState->fileHandle, &pState->srcByte)) != EAS_SUCCESS) + return result; + + /* if unsigned */ + if (pState->flags & PCM_FLAGS_UNSIGNED) + { + /*lint -e{734} converting unsigned 8-bit to signed 16-bit */ + pState->decoderL.x1 = (EAS_PCM)(((EAS_PCM) pState->srcByte << 8) ^ 0x8000); + } + else + { + /*lint -e{734} converting signed 8-bit to signed 16-bit */ + pState->decoderL.x1 = (EAS_PCM)((EAS_PCM) pState->srcByte << 8); + } + pState->bytesLeft--; + + /* fetch right sample */ + if(pState->flags & PCM_FLAGS_STEREO) + { + if ((result = EAS_HWGetByte(hwInstData, pState->fileHandle, &pState->srcByte)) != EAS_SUCCESS) + return result; + + /* if unsigned */ + if (pState->flags & PCM_FLAGS_UNSIGNED) + { + /*lint -e{734} converting unsigned 8-bit to signed 16-bit */ + pState->decoderR.x1 = (EAS_PCM)(((EAS_PCM) pState->srcByte << 8) ^ 0x8000); + } + else + { + /*lint -e{734} converting signed 8-bit to signed 16-bit */ + pState->decoderR.x1 = (EAS_PCM)((EAS_PCM) pState->srcByte << 8); + } + pState->bytesLeft--; + } + } + + /* must be 16-bit samples */ + else + { + //unsigned 16 bit currently not supported + if (pState->flags & PCM_FLAGS_UNSIGNED) + { + return EAS_ERROR_INVALID_PCM_TYPE; + } + + /* fetch left or mono sample */ + if ((result = EAS_HWGetWord(hwInstData, pState->fileHandle, &pState->decoderL.x1, EAS_FALSE)) != EAS_SUCCESS) + return result; + pState->bytesLeft -= 2; + + /* fetch right sample */ + if(pState->flags & PCM_FLAGS_STEREO) + { + if ((result = EAS_HWGetWord(hwInstData, pState->fileHandle, &pState->decoderR.x1, EAS_FALSE)) != EAS_SUCCESS) + return result; + pState->bytesLeft -= 2; + } + } + } + + /* no more data, force zero samples */ + else + pState->decoderL.x1 = pState->decoderR.x1 = 0; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * LinearPCMLocate() + *---------------------------------------------------------------------------- + * Purpose: + * Locate in a linear PCM stream + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT LinearPCMLocate (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState, EAS_I32 time) +{ + EAS_RESULT result; + EAS_I32 temp; + EAS_I32 secs, msecs; + EAS_INT shift; + + /* calculate size of sample frame */ + if (pState->flags & PCM_FLAGS_8_BIT) + shift = 0; + else + shift = 1; + if (pState->flags & PCM_FLAGS_STEREO) + shift++; + + /* break down into secs and msecs */ + secs = time / 1000; + msecs = time - (secs * 1000); + + /* calculate sample number fraction from msecs */ + temp = (msecs * pState->sampleRate); + temp = (temp >> 10) + ((temp * 49) >> 21); + + /* add integer sample count */ + temp += secs * pState->sampleRate; + + /* calculate the position based on sample frame size */ + /*lint -e{703} use shift for performance */ + temp <<= shift; + + /* past end of sample? */ + if (temp > (EAS_I32) pState->loopStart) + { + /* if not looped, flag error */ + if (pState->loopSamples == 0) + { + pState->bytesLeft = 0; + pState->flags |= PCM_FLAGS_EMPTY; + return EAS_ERROR_LOCATE_BEYOND_END; + } + + /* looped sample - calculate position in loop */ + while (temp > (EAS_I32) pState->loopStart) + temp -= (EAS_I32) pState->loopStart; + } + + /* seek to new position */ + if ((result = EAS_PESeek(pEASData, pState, &temp)) != EAS_SUCCESS) + return result; + + /* reset state */ + if ((pState->state != EAS_STATE_PAUSING) && (pState->state != EAS_STATE_PAUSED)) + pState->state = EAS_STATE_READY; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_PESeek + *---------------------------------------------------------------------------- + * Purpose: + * Locate to a particular byte in a PCM stream + *---------------------------------------------------------------------------- + * This bit is tricky because the chunks may not be contiguous, + * so we have to rely on the parser to position in the file. We + * do this by seeking to the end of each chunk and simulating an + * empty buffer condition until we get to where we want to go. + * + * A better solution would be a parser API for re-positioning, + * but there isn't time at the moment to re-factor all the + * parsers to support a new API. + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PESeek (S_EAS_DATA *pEASData, S_PCM_STATE *pState, EAS_I32 *pLocation) +{ + EAS_RESULT result; + + /* seek to start of audio */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pState->fileHandle, pState->startPos)) != EAS_SUCCESS) + { + pState->state = EAS_STATE_ERROR; + return result; + } + pState->bytesLeft = pState->bytesLeftLoop; + + /* skip through chunks until we find the right chunk */ + while (*pLocation > (EAS_I32) pState->bytesLeft) + { + /* seek to end of audio chunk */ + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "EAS_PESeek: Seek to offset = %d\n", pState->bytesLeft); */ } + if ((result = EAS_HWFileSeekOfs(pEASData->hwInstData, pState->fileHandle, pState->bytesLeft)) != EAS_SUCCESS) + { + pState->state = EAS_STATE_ERROR; + return result; + } + *pLocation -= pState->bytesLeft; + pState->bytesLeft = 0; + pState->flags |= PCM_FLAGS_EMPTY; + + /* retrieve more data */ + if (pState->pCallback) + (*pState->pCallback)(pEASData, pState->cbInstData, pState, EAS_STATE_EMPTY); + + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "EAS_PESeek: bytesLeft=%d, byte location = %d\n", pState->bytesLeft, *pLocation); */ } + + /* no more samples */ + if (pState->bytesLeft == 0) + return EAS_ERROR_LOCATE_BEYOND_END; + } + + /* seek to new offset in current chunk */ + if (*pLocation > 0) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "EAS_PESeek: Seek to offset = %d\n", *pLocation); */ } + if ((result = EAS_HWFileSeekOfs(pEASData->hwInstData, pState->fileHandle, *pLocation)) != EAS_SUCCESS) + { + pState->state = EAS_STATE_ERROR; + return result; + } + + /* if not streamed, calculate number of bytes left */ + if (pState->flags & PCM_FLAGS_STREAMING) + pState->bytesLeft = 0x7fffffff; + else + pState->bytesLeft -= *pLocation; + } + return EAS_SUCCESS; +} + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_pcm.h b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_pcm.h new file mode 100755 index 0000000..4fc77e9 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_pcm.h @@ -0,0 +1,359 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_pcm.h + * + * Contents and purpose: + * External function prototypes for eas_pcm.c module + * + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 847 $ + * $Date: 2007-08-27 21:30:08 -0700 (Mon, 27 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_PCM_H +#define _EAS_PCM_H + +/* default gain setting - roughly unity gain */ +#define PCM_DEFAULT_GAIN_SETTING 0x6000 + +typedef struct s_pcm_state_tag *EAS_PCM_HANDLE; +typedef void (*EAS_PCM_CALLBACK) (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR cbInstData, EAS_PCM_HANDLE pcmHandle, EAS_STATE state); + +/* parameters for EAS_PEOpenStream */ +typedef struct s_pcm_open_params_tag +{ + EAS_FILE_HANDLE fileHandle; + EAS_I32 decoder; + EAS_U32 sampleRate; + EAS_I32 size; + EAS_U32 loopStart; + EAS_U32 loopSamples; + EAS_I32 blockSize; + EAS_U32 flags; + EAS_U32 envData; + EAS_I16 volume; + EAS_PCM_CALLBACK pCallbackFunc; + EAS_VOID_PTR cbInstData; + } S_PCM_OPEN_PARAMS; + +/*---------------------------------------------------------------------------- + * EAS_PEInit() + *---------------------------------------------------------------------------- + * Purpose: + * Initializes the PCM engine + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEInit (EAS_DATA_HANDLE pEASData); + +/*---------------------------------------------------------------------------- + * EAS_PEShutdown() + *---------------------------------------------------------------------------- + * Purpose: + * Shuts down the PCM engine + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEShutdown (EAS_DATA_HANDLE pEASData); + +/*---------------------------------------------------------------------------- + * EAS_PEOpenStream() + *---------------------------------------------------------------------------- + * Purpose: + * Starts up a PCM playback + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEOpenStream (EAS_DATA_HANDLE pEASData, S_PCM_OPEN_PARAMS *pParams, EAS_PCM_HANDLE *pHandle); + +/*---------------------------------------------------------------------------- + * EAS_PEContinueStream() + *---------------------------------------------------------------------------- + * Purpose: + * Continues a PCM stream + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEContinueStream (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE handle, EAS_I32 size); + +/*---------------------------------------------------------------------------- + * EAS_PEGetFileHandle() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the file handle of a stream + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEGetFileHandle (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE handle, EAS_FILE_HANDLE *pFileHandle); + +/*---------------------------------------------------------------------------- + * EAS_PERender() + *---------------------------------------------------------------------------- + * Purpose: + * Render a buffer of PCM audio + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PERender (EAS_DATA_HANDLE pEASData, EAS_I32 numSamples); + +/*---------------------------------------------------------------------------- + * EAS_PEUpdateParams() + *---------------------------------------------------------------------------- + * Purpose: + * Update the pitch and volume parameters using MIDI controls + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEUpdateParams (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE pState, EAS_I16 pitch, EAS_I16 gainLeft, EAS_I16 gainRight); + +/*---------------------------------------------------------------------------- + * EAS_PELocate() + *---------------------------------------------------------------------------- + * Purpose: + * This function seeks to the requested place in the file. Accuracy + * is dependent on the sample rate and block size. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * pState - stream handle + * time - media time in milliseconds + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PELocate (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE pState, EAS_I32 time); + +/*---------------------------------------------------------------------------- + * EAS_PEUpdateVolume() + *---------------------------------------------------------------------------- + * Purpose: + * Update the volume parameters for a PCM stream + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_PCM_STATE for this stream + * gainLeft - linear gain multipler in 1.15 fraction format + * gainRight - linear gain multipler in 1.15 fraction format + * initial - initial settings, set current gain + * + * Outputs: + * + * + * Side Effects: + * + * Notes + * In mono mode, leftGain controls the output gain and rightGain is ignored + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT EAS_PEUpdateVolume (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE pState, EAS_I16 volume); + +/*---------------------------------------------------------------------------- + * EAS_PEUpdatePitch() + *---------------------------------------------------------------------------- + * Purpose: + * Update the pitch parameter for a PCM stream + * + * Inputs: + * pEASData - pointer to EAS library instance data + * pState - pointer to S_PCM_STATE for this stream + * pitch - new pitch value in pitch cents + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT EAS_PEUpdatePitch (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE pState, EAS_I16 pitch); + +/*---------------------------------------------------------------------------- + * EAS_PEState() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current state of the stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * pState - pointer to variable to store state + * + * Outputs: + * + * + * Side Effects: + * + * Notes: + * This interface is also exposed in the internal library for use by the other modules. + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEState (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE handle, EAS_STATE *pState); + +/*---------------------------------------------------------------------------- + * EAS_PEClose() + *---------------------------------------------------------------------------- + * Purpose: + * Close the file and clean up + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEClose (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE handle); + +/*---------------------------------------------------------------------------- + * EAS_PEReset() + *---------------------------------------------------------------------------- + * Purpose: + * Reset the sequencer. Used for locating backwards in the file. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEReset (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE handle); + +/*---------------------------------------------------------------------------- + * EAS_PEPause() + *---------------------------------------------------------------------------- + * Purpose: + * Mute and pause rendering a PCM stream. Sets the gain target to zero and stops the playback + * at the end of the next audio frame. + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_PCM_STATE for this stream + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEPause (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE handle); + +/*---------------------------------------------------------------------------- + * EAS_PEResume() + *---------------------------------------------------------------------------- + * Purpose: + * Resume rendering a PCM stream. Sets the gain target back to its + * previous setting and restarts playback at the end of the next audio + * frame. + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_PCM_STATE for this stream + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEResume (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE handle); + +/*---------------------------------------------------------------------------- + * EAS_PERelease() + *---------------------------------------------------------------------------- + * Purpose: + * Put the PCM stream envelope into release. + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_PCM_STATE for this stream + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PERelease (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE handle); + +#endif /* end _EAS_PCM_H */ + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_pcmdata.c b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_pcmdata.c new file mode 100755 index 0000000..2d85ac2 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_pcmdata.c @@ -0,0 +1,35 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_pcmdata.c + * + * Contents and purpose: + * Contains the static data for the PCM engine. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 547 $ + * $Date: 2007-01-31 16:30:17 -0800 (Wed, 31 Jan 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_data.h" + +/* static data allocation */ +S_PCM_STATE eas_PCMData[MAX_PCM_STREAMS]; + + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_pcmdata.h b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_pcmdata.h new file mode 100755 index 0000000..ae18d6d --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_pcmdata.h @@ -0,0 +1,157 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_pcmdata.h + * + * Contents and purpose: + * Data declarations for the PCM engine + * + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 847 $ + * $Date: 2007-08-27 21:30:08 -0700 (Mon, 27 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_PCMDATA_H +#define _EAS_PCMDATA_H + +/* sets the maximum number of simultaneous PCM streams */ +#ifndef MAX_PCM_STREAMS +#define MAX_PCM_STREAMS 16 +#define PCM_STREAM_THRESHOLD (MAX_PCM_STREAMS - 4) +#endif + +/* coefficents for high-pass filter in ADPCM */ +#define INTEGRATOR_COEFFICIENT 100 /* coefficient for leaky integrator */ + +/* additional flags in S_PCM_STATE.flags used internal to module */ +#define PCM_FLAGS_EMPTY 0x01000000 /* unsigned format */ + +/*---------------------------------------------------------------------------- + * S_PCM_STATE + * + * Retains state information for PCM streams. + *---------------------------------------------------------------------------- +*/ +typedef struct s_decoder_state_tag +{ + EAS_I32 output; /* last output for DC offset filter */ + EAS_I32 acc; /* accumulator for DC offset filter */ + EAS_I32 step; /* current ADPCM step size */ + EAS_PCM x1; /* current generated sample */ + EAS_PCM x0; /* previous generated sample */ +} S_DECODER_STATE; + +typedef enum +{ + PCM_ENV_START = 0, + PCM_ENV_ATTACK, + PCM_ENV_DECAY, + PCM_ENV_SUSTAIN, + PCM_ENV_RELEASE, + PCM_ENV_END +} E_PCM_ENV_STATE; + +typedef struct s_pcm_state_tag +{ +#ifdef _CHECKED_BUILD + EAS_U32 handleCheck; /* signature check for checked build */ +#endif + EAS_FILE_HANDLE fileHandle; /* pointer to input file */ + EAS_PCM_CALLBACK pCallback; /* pointer to callback function */ + EAS_VOID_PTR cbInstData; /* instance data for callback function */ + struct s_decoder_interface_tag EAS_CONST * pDecoder; /* pointer to decoder interface */ + EAS_STATE state; /* stream state */ + EAS_I32 time; /* media time */ + EAS_I32 startPos; /* start of PCM stream */ + EAS_I32 loopLocation; /* file location where loop starts */ + EAS_I32 byteCount; /* size of file */ + EAS_U32 loopStart; /* loop start, offset in samples from startPos */ + /* NOTE: For CMF, we use this to store total sample size */ + EAS_U32 loopSamples; /* total loop length, in samples, 0 means no loop */ + /* NOTE: For CMF, non-zero means looped */ + EAS_U32 samplesInLoop; /* samples left in the loop to play back */ + EAS_I32 samplesTilLoop; /* samples left to play until top of loop */ + EAS_I32 bytesLeft; /* count of bytes left in stream */ + EAS_I32 bytesLeftLoop; /* count of bytes left in stream, value at start of loop */ + EAS_U32 phase; /* current phase for interpolator */ + EAS_U32 basefreq; /* frequency multiplier */ + EAS_U32 flags; /* stream flags */ + EAS_U32 envData; /* envelope data (and LFO data) */ + EAS_U32 envValue; /* current envelope value */ + EAS_U32 envScale; /* current envelope scale */ + EAS_U32 startOrder; /* start order index, first is 0, next is 1, etc. */ + S_DECODER_STATE decoderL; /* left (mono) ADPCM state */ + S_DECODER_STATE decoderR; /* right ADPCM state */ + S_DECODER_STATE decoderLLoop; /* left (mono) ADPCM state, value at start of loop */ + S_DECODER_STATE decoderRLoop; /* right ADPCM state, value at start of loop */ + E_PCM_ENV_STATE envState; /* current envelope state */ + EAS_I16 volume; /* volume for stream */ + EAS_I16 pitch; /* relative pitch in cents - zero is unity playback */ + EAS_I16 gainLeft; /* requested gain */ + EAS_I16 gainRight; /* requested gain */ + EAS_I16 currentGainLeft; /* current gain for anti-zipper filter */ + EAS_I16 currentGainRight; /* current gain for anti-zipper filter */ + EAS_U16 blockSize; /* block size for ADPCM decoder */ + EAS_U16 blockCount; /* block counter for ADPCM decoder */ + EAS_U16 sampleRate; /* input sample rate */ + EAS_U8 srcByte; /* source byte */ + EAS_U8 msBitCount; /* count keeps track of MS bits */ + EAS_U8 msBitMask; /* mask keeps track of MS bits */ + EAS_U8 msBitValue; /* value keeps track of MS bits */ + EAS_U8 msBitCountLoop; /* count keeps track of MS bits, value at loop start */ + EAS_U8 msBitMaskLoop; /* mask keeps track of MS bits, value at loop start */ + EAS_U8 msBitValueLoop; /* value keeps track of MS bits, value at loop start */ + EAS_BOOL8 hiNibble; /* indicates high/low nibble is next */ + EAS_BOOL8 hiNibbleLoop; /* indicates high/low nibble is next, value loop start */ + EAS_U8 rateShift; /* for playback rate greater than 1.0 */ +} S_PCM_STATE; + +/*---------------------------------------------------------------------------- + * S_DECODER_INTERFACE + * + * Generic interface for audio decoders + *---------------------------------------------------------------------------- +*/ +typedef struct s_decoder_interface_tag +{ + EAS_RESULT (* EAS_CONST pfInit)(EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState); + EAS_RESULT (* EAS_CONST pfDecodeSample)(EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState); + EAS_RESULT (* EAS_CONST pfLocate)(EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState, EAS_I32 time); +} S_DECODER_INTERFACE; + + +/* header chunk for SMAF ADPCM */ +#define TAG_YAMAHA_ADPCM 0x4d776100 +#define TAG_MASK 0xffffff00 +#define TAG_RIFF_FILE 0x52494646 +#define TAG_WAVE_CHUNK 0x57415645 +#define TAG_FMT_CHUNK 0x666d7420 + +/*---------------------------------------------------------------------------- + * EAS_PESeek + *---------------------------------------------------------------------------- + * Purpose: + * Locate to a particular byte in a PCM stream + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PESeek (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState, EAS_I32 *pLocation); + +#endif /* _EAS_PCMDATA_H */ + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_public.c b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_public.c new file mode 100755 index 0000000..394a9a1 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_public.c @@ -0,0 +1,2597 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_public.c + * + * Contents and purpose: + * Contains EAS library public interface + * + * Copyright Sonic Network Inc. 2004 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 842 $ + * $Date: 2007-08-23 14:32:31 -0700 (Thu, 23 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_synthcfg.h" +#include "eas.h" +#include "eas_config.h" +#include "eas_host.h" +#include "eas_report.h" +#include "eas_data.h" +#include "eas_parser.h" +#include "eas_pcm.h" +#include "eas_midi.h" +#include "eas_mixer.h" +#include "eas_build.h" +#include "eas_vm_protos.h" +#include "eas_math.h" + +#ifdef JET_INTERFACE +#include "jet_data.h" +#endif + +#ifdef DLS_SYNTHESIZER +#include "eas_mdls.h" +#endif + +/* number of events to parse before calling EAS_HWYield function */ +#define YIELD_EVENT_COUNT 10 + +/*---------------------------------------------------------------------------- + * easLibConfig + * + * This structure is available through the EAS public interface to allow + * the user to check the configuration of the library. + *---------------------------------------------------------------------------- +*/ +static const S_EAS_LIB_CONFIG easLibConfig = +{ + LIB_VERSION, +#ifdef _CHECKED_BUILD + EAS_TRUE, +#else + EAS_FALSE, +#endif + MAX_SYNTH_VOICES, + NUM_OUTPUT_CHANNELS, + _OUTPUT_SAMPLE_RATE, + BUFFER_SIZE_IN_MONO_SAMPLES, +#ifdef _FILTER_ENABLED + EAS_TRUE, +#else + EAS_FALSE, +#endif + _BUILD_TIME_, + _BUILD_VERSION_ +}; + +/* local prototypes */ +static EAS_RESULT EAS_ParseEvents (S_EAS_DATA *pEASData, S_EAS_STREAM *pStream, EAS_U32 endTime, EAS_INT parseMode); + +/*---------------------------------------------------------------------------- + * EAS_SetStreamParameter + *---------------------------------------------------------------------------- + * Sets the specified parameter in the stream. Allows access to + * customizable settings within the individual file parsers. + *---------------------------------------------------------------------------- + * pEASData - pointer to EAS persistent data object + * pStream - stream handle + * param - enumerated parameter (see eas_parser.h) + * value - new value + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_SetStreamParameter (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_I32 param, EAS_I32 value) +{ + S_FILE_PARSER_INTERFACE *pParserModule; + + pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; + if (pParserModule->pfSetData) + return (*pParserModule->pfSetData)(pEASData, pStream->handle, param, value); + return EAS_ERROR_FEATURE_NOT_AVAILABLE; +} + +/*---------------------------------------------------------------------------- + * EAS_GetStreamParameter + *---------------------------------------------------------------------------- + * Sets the specified parameter in the stream. Allows access to + * customizable settings within the individual file parsers. + *---------------------------------------------------------------------------- + * pEASData - pointer to EAS persistent data object + * pStream - stream handle + * param - enumerated parameter (see eas_parser.h) + * pValue - pointer to variable to receive current setting + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_GetStreamParameter (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_I32 param, EAS_I32 *pValue) +{ + S_FILE_PARSER_INTERFACE *pParserModule; + + pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; + if (pParserModule->pfGetData) + return (*pParserModule->pfGetData)(pEASData, pStream->handle, param, pValue); + return EAS_ERROR_FEATURE_NOT_AVAILABLE; +} + +/*---------------------------------------------------------------------------- + * EAS_StreamReady() + *---------------------------------------------------------------------------- + * This routine sets common parameters like transpose, volume, etc. + * First, it attempts to use the parser EAS_SetStreamParameter interface. If that + * fails, it attempts to get the synth handle from the parser and + * set the parameter directly on the synth. This eliminates duplicate + * code in the parser. + *---------------------------------------------------------------------------- +*/ +EAS_BOOL EAS_StreamReady (S_EAS_DATA *pEASData, EAS_HANDLE pStream) +{ + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_STATE state; + + pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; + if (pParserModule->pfState(pEASData, pStream->handle, &state) != EAS_SUCCESS) + return EAS_FALSE; + return (state < EAS_STATE_OPEN); +} + +/*---------------------------------------------------------------------------- + * EAS_IntSetStrmParam() + *---------------------------------------------------------------------------- + * This routine sets common parameters like transpose, volume, etc. + * First, it attempts to use the parser EAS_SetStreamParameter interface. If that + * fails, it attempts to get the synth handle from the parser and + * set the parameter directly on the synth. This eliminates duplicate + * code in the parser. + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_IntSetStrmParam (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_INT param, EAS_I32 value) +{ + S_SYNTH *pSynth; + + /* try to set the parameter using stream interface */ + if (EAS_SetStreamParameter(pEASData, pStream, param, value) == EAS_SUCCESS) + return EAS_SUCCESS; + + /* get a pointer to the synth object and set it directly */ + /*lint -e{740} we are cheating by passing a pointer through this interface */ + if (EAS_GetStreamParameter(pEASData, pStream, PARSER_DATA_SYNTH_HANDLE, (EAS_I32*) &pSynth) != EAS_SUCCESS) + return EAS_ERROR_INVALID_PARAMETER; + + if (pSynth == NULL) + return EAS_ERROR_INVALID_PARAMETER; + + switch (param) + { + +#ifdef DLS_SYNTHESIZER + case PARSER_DATA_DLS_COLLECTION: + { + EAS_RESULT result = VMSetDLSLib(pSynth, (EAS_DLSLIB_HANDLE) value); + if (result == EAS_SUCCESS) + { + DLSAddRef((S_DLS*) value); + VMInitializeAllChannels(pEASData->pVoiceMgr, pSynth); + } + return result; + } +#endif + + case PARSER_DATA_EAS_LIBRARY: + return VMSetEASLib(pSynth, (EAS_SNDLIB_HANDLE) value); + + case PARSER_DATA_POLYPHONY: + return VMSetPolyphony(pEASData->pVoiceMgr, pSynth, value); + + case PARSER_DATA_PRIORITY: + return VMSetPriority(pEASData->pVoiceMgr, pSynth, value); + + case PARSER_DATA_TRANSPOSITION: + VMSetTranposition(pSynth, value); + break; + + case PARSER_DATA_VOLUME: + VMSetVolume(pSynth, (EAS_U16) value); + break; + + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Invalid paramter %d in call to EAS_IntSetStrmParam", param); */ } + return EAS_ERROR_INVALID_PARAMETER; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_IntGetStrmParam() + *---------------------------------------------------------------------------- + * This routine gets common parameters like transpose, volume, etc. + * First, it attempts to use the parser EAS_GetStreamParameter interface. If that + * fails, it attempts to get the synth handle from the parser and + * get the parameter directly on the synth. + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_IntGetStrmParam (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_INT param, EAS_I32 *pValue) +{ + S_SYNTH *pSynth; + + /* try to set the parameter */ + if (EAS_GetStreamParameter(pEASData, pStream, param, pValue) == EAS_SUCCESS) + return EAS_SUCCESS; + + /* get a pointer to the synth object and retrieve data directly */ + /*lint -e{740} we are cheating by passing a pointer through this interface */ + if (EAS_GetStreamParameter(pEASData, pStream, PARSER_DATA_SYNTH_HANDLE, (EAS_I32*) &pSynth) != EAS_SUCCESS) + return EAS_ERROR_INVALID_PARAMETER; + + if (pSynth == NULL) + return EAS_ERROR_INVALID_PARAMETER; + + switch (param) + { + case PARSER_DATA_POLYPHONY: + return VMGetPolyphony(pEASData->pVoiceMgr, pSynth, pValue); + + case PARSER_DATA_PRIORITY: + return VMGetPriority(pEASData->pVoiceMgr, pSynth, pValue); + + case PARSER_DATA_TRANSPOSITION: + VMGetTranposition(pSynth, pValue); + break; + + case PARSER_DATA_NOTE_COUNT: + *pValue = VMGetNoteCount(pSynth); + break; + + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Invalid paramter %d in call to EAS_IntSetStrmParam", param); */ } + return EAS_ERROR_INVALID_PARAMETER; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_AllocateStream() + *---------------------------------------------------------------------------- + * Purpose: + * Allocates a stream handle + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static EAS_INT EAS_AllocateStream (EAS_DATA_HANDLE pEASData) +{ + EAS_INT streamNum; + + /* check for static allocation, only one stream allowed */ + if (pEASData->staticMemoryModel) + { + if (pEASData->streams[0].handle != NULL) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Attempt to open multiple streams in static model\n"); */ } + return -1; + } + return 0; + } + + /* dynamic model */ + for (streamNum = 0; streamNum < MAX_NUMBER_STREAMS; streamNum++) + if (pEASData->streams[streamNum].handle == NULL) + break; + if (streamNum == MAX_NUMBER_STREAMS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Exceeded maximum number of open streams\n"); */ } + return -1; + } + return streamNum; +} + +/*---------------------------------------------------------------------------- + * EAS_InitStream() + *---------------------------------------------------------------------------- + * Purpose: + * Initialize a stream + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static void EAS_InitStream (S_EAS_STREAM *pStream, EAS_VOID_PTR pParserModule, EAS_VOID_PTR streamHandle) +{ + pStream->pParserModule = pParserModule; + pStream->handle = streamHandle; + pStream->time = 0; + pStream->frameLength = AUDIO_FRAME_LENGTH; + pStream->repeatCount = 0; + pStream->volume = DEFAULT_STREAM_VOLUME; +} + +/*---------------------------------------------------------------------------- + * EAS_Config() + *---------------------------------------------------------------------------- + * Purpose: + * Returns a pointer to a structure containing the configuration options + * in this library build. + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC const S_EAS_LIB_CONFIG *EAS_Config (void) +{ + return &easLibConfig; +} + +/*---------------------------------------------------------------------------- + * EAS_Init() + *---------------------------------------------------------------------------- + * Purpose: + * Initialize the synthesizer library + * + * Inputs: + * ppEASData - pointer to data handle variable for this instance + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Init (EAS_DATA_HANDLE *ppEASData) +{ + EAS_HW_DATA_HANDLE pHWInstData; + EAS_RESULT result; + S_EAS_DATA *pEASData; + EAS_INT module; + EAS_BOOL staticMemoryModel; + + /* get the memory model */ + staticMemoryModel = EAS_CMStaticMemoryModel(); + + /* initialize the host wrapper interface */ + *ppEASData = NULL; + if ((result = EAS_HWInit(&pHWInstData)) != EAS_SUCCESS) + return result; + + /* check Configuration Module for S_EAS_DATA allocation */ + if (staticMemoryModel) + pEASData = EAS_CMEnumData(EAS_CM_EAS_DATA); + else + pEASData = EAS_HWMalloc(pHWInstData, sizeof(S_EAS_DATA)); + if (!pEASData) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Failed to allocate EAS library memory\n"); */ } + return EAS_ERROR_MALLOC_FAILED; + } + + /* initialize some data */ + EAS_HWMemSet(pEASData, 0, sizeof(S_EAS_DATA)); + pEASData->staticMemoryModel = (EAS_BOOL8) staticMemoryModel; + pEASData->hwInstData = pHWInstData; + pEASData->renderTime = 0; + + /* set header search flag */ +#ifdef FILE_HEADER_SEARCH + pEASData->searchHeaderFlag = EAS_TRUE; +#endif + + /* initalize parameters */ + EAS_SetVolume(pEASData, NULL, DEFAULT_VOLUME); + +#ifdef _METRICS_ENABLED + /* initalize the metrics module */ + pEASData->pMetricsModule = EAS_CMEnumOptModules(EAS_MODULE_METRICS); + if (pEASData->pMetricsModule != NULL) + { + if ((result = (*pEASData->pMetricsModule->pfInit)(pEASData, &pEASData->pMetricsData)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld initializing metrics module\n", result); */ } + return result; + } + } +#endif + + /* initailize the voice manager & synthesizer */ + if ((result = VMInitialize(pEASData)) != EAS_SUCCESS) + return result; + + /* initialize mix engine */ + if ((result = EAS_MixEngineInit(pEASData)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld starting up mix engine\n", result); */ } + return result; + } + + /* initialize effects modules */ + for (module = 0; module < NUM_EFFECTS_MODULES; module++) + { + pEASData->effectsModules[module].effect = EAS_CMEnumFXModules(module); + if (pEASData->effectsModules[module].effect != NULL) + { + if ((result = (*pEASData->effectsModules[module].effect->pfInit)(pEASData, &pEASData->effectsModules[module].effectData)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Initialization of effects module %d returned %d\n", module, result); */ } + return result; + } + } + } + + /* initialize PCM engine */ + if ((result = EAS_PEInit(pEASData)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "EAS_PEInit failed with error code %ld\n", result); */ } + return result; + } + + /* return instance data pointer to host */ + *ppEASData = pEASData; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_Shutdown() + *---------------------------------------------------------------------------- + * Purpose: + * Shuts down the library. Deallocates any memory associated with the + * synthesizer (dynamic memory model only) + * + * Inputs: + * pEASData - handle to data for this instance + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Shutdown (EAS_DATA_HANDLE pEASData) +{ + EAS_HW_DATA_HANDLE hwInstData; + EAS_RESULT result, reportResult; + EAS_INT i; + + /* establish pointers */ + hwInstData = pEASData->hwInstData; + + /* check for NULL handle */ + if (!pEASData) + return EAS_ERROR_HANDLE_INTEGRITY; + + /* if there are streams open, close them */ + reportResult = EAS_SUCCESS; + for (i = 0; i < MAX_NUMBER_STREAMS; i++) + { + if (pEASData->streams[i].pParserModule && pEASData->streams[i].handle) + { + if ((result = (*((S_FILE_PARSER_INTERFACE*)(pEASData->streams[i].pParserModule))->pfClose)(pEASData, pEASData->streams[i].handle)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld shutting down parser module\n", result); */ } + reportResult = result; + } + } + } + + /* shutdown PCM engine */ + if ((result = EAS_PEShutdown(pEASData)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld shutting down PCM engine\n", result); */ } + if (reportResult == EAS_SUCCESS) + reportResult = result; + } + + /* shutdown mix engine */ + if ((result = EAS_MixEngineShutdown(pEASData)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld shutting down mix engine\n", result); */ } + if (reportResult == EAS_SUCCESS) + reportResult = result; + } + + /* shutdown effects modules */ + for (i = 0; i < NUM_EFFECTS_MODULES; i++) + { + if (pEASData->effectsModules[i].effect) + { + if ((result = (*pEASData->effectsModules[i].effect->pfShutdown)(pEASData, pEASData->effectsModules[i].effectData)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Shutdown of effects module %d returned %d\n", i, result); */ } + if (reportResult == EAS_SUCCESS) + reportResult = result; + } + } + } + + /* shutdown the voice manager & synthesizer */ + VMShutdown(pEASData); + +#ifdef _METRICS_ENABLED + /* shutdown the metrics module */ + if (pEASData->pMetricsModule != NULL) + { + if ((result = (*pEASData->pMetricsModule->pfShutdown)(pEASData, pEASData->pMetricsData)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld shutting down metrics module\n", result); */ } + if (reportResult == EAS_SUCCESS) + reportResult = result; + } + } +#endif + + /* release allocated memory */ + if (!pEASData->staticMemoryModel) + EAS_HWFree(hwInstData, pEASData); + + /* shutdown host wrappers */ + if (hwInstData) + { + if ((result = EAS_HWShutdown(hwInstData)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld shutting down host wrappers\n", result); */ } + if (reportResult == EAS_SUCCESS) + reportResult = result; + } + } + + return reportResult; +} + +#ifdef JET_INTERFACE +/*---------------------------------------------------------------------------- + * EAS_OpenJETStream() + *---------------------------------------------------------------------------- + * Private interface for JET to open an SMF stream with an offset + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_OpenJETStream (EAS_DATA_HANDLE pEASData, EAS_FILE_HANDLE fileHandle, EAS_I32 offset, EAS_HANDLE *ppStream) +{ + EAS_RESULT result; + EAS_VOID_PTR streamHandle; + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_INT streamNum; + + /* allocate a stream */ + if ((streamNum = EAS_AllocateStream(pEASData)) < 0) + return EAS_ERROR_MAX_STREAMS_OPEN; + + /* check Configuration Module for SMF parser */ + *ppStream = NULL; + streamHandle = NULL; + pParserModule = (S_FILE_PARSER_INTERFACE *) EAS_CMEnumModules(0); + if (pParserModule == NULL) + return EAS_ERROR_UNRECOGNIZED_FORMAT; + + /* see if SMF parser recognizes the file */ + if ((result = (*pParserModule->pfCheckFileType)(pEASData, fileHandle, &streamHandle, offset)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "CheckFileType returned error %ld\n", result); */ } + return result; + } + + /* parser recognized the file, return the handle */ + if (streamHandle) + { + EAS_InitStream(&pEASData->streams[streamNum], pParserModule, streamHandle); + *ppStream = &pEASData->streams[streamNum]; + return EAS_SUCCESS; + } + + return EAS_ERROR_UNRECOGNIZED_FORMAT; +} +#endif + +/*---------------------------------------------------------------------------- + * EAS_OpenFile() + *---------------------------------------------------------------------------- + * Purpose: + * Opens a file for audio playback. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * pHandle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_OpenFile (EAS_DATA_HANDLE pEASData, EAS_FILE_LOCATOR locator, EAS_HANDLE *ppStream) +{ + EAS_RESULT result; + EAS_FILE_HANDLE fileHandle; + EAS_VOID_PTR streamHandle; + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_INT streamNum; + EAS_INT moduleNum; + + /* open the file */ + if ((result = EAS_HWOpenFile(pEASData->hwInstData, locator, &fileHandle, EAS_FILE_READ)) != EAS_SUCCESS) + return result; + + /* allocate a stream */ + if ((streamNum = EAS_AllocateStream(pEASData)) < 0) + return EAS_ERROR_MAX_STREAMS_OPEN; + + /* check Configuration Module for file parsers */ + pParserModule = NULL; + *ppStream = NULL; + streamHandle = NULL; + for (moduleNum = 0; ; moduleNum++) + { + pParserModule = (S_FILE_PARSER_INTERFACE *) EAS_CMEnumModules(moduleNum); + if (pParserModule == NULL) + break; + + /* see if this parser recognizes it */ + if ((result = (*pParserModule->pfCheckFileType)(pEASData, fileHandle, &streamHandle, 0L)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "CheckFileType returned error %ld\n", result); */ } + return result; + } + + /* parser recognized the file, return the handle */ + if (streamHandle) + { + + /* save the parser pointer and file handle */ + EAS_InitStream(&pEASData->streams[streamNum], pParserModule, streamHandle); + *ppStream = &pEASData->streams[streamNum]; + return EAS_SUCCESS; + } + + /* rewind the file for the next parser */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, 0L)) != EAS_SUCCESS) + return result; + } + + /* no parser was able to recognize the file, close it and return an error */ + EAS_HWCloseFile(pEASData->hwInstData, fileHandle); + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "No parser recognized the requested file\n"); */ } + return EAS_ERROR_UNRECOGNIZED_FORMAT; +} + +#ifdef MMAPI_SUPPORT +/*---------------------------------------------------------------------------- + * EAS_MMAPIToneControl() + *---------------------------------------------------------------------------- + * Purpose: + * Opens a ToneControl file for audio playback. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * pHandle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_MMAPIToneControl (EAS_DATA_HANDLE pEASData, EAS_FILE_LOCATOR locator, EAS_HANDLE *ppStream) +{ + EAS_RESULT result; + EAS_FILE_HANDLE fileHandle; + EAS_VOID_PTR streamHandle; + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_INT streamNum; + + /* check if the tone control parser is available */ + *ppStream = NULL; + streamHandle = NULL; + pParserModule = EAS_CMEnumOptModules(EAS_MODULE_MMAPI_TONE_CONTROL); + if (pParserModule == NULL) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_MMAPIToneControl: ToneControl parser not available\n"); */ } + return EAS_ERROR_FEATURE_NOT_AVAILABLE; + } + + /* open the file */ + if ((result = EAS_HWOpenFile(pEASData->hwInstData, locator, &fileHandle, EAS_FILE_READ)) != EAS_SUCCESS) + return result; + + /* allocate a stream */ + if ((streamNum = EAS_AllocateStream(pEASData)) < 0) + return EAS_ERROR_MAX_STREAMS_OPEN; + + /* see if ToneControl parser recognizes it */ + if ((result = (*pParserModule->pfCheckFileType)(pEASData, fileHandle, &streamHandle, 0L)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "CheckFileType returned error %ld\n", result); */ } + return result; + } + + /* parser accepted the file, return the handle */ + if (streamHandle) + { + + /* save the parser pointer and file handle */ + EAS_InitStream(&pEASData->streams[streamNum], pParserModule, streamHandle); + *ppStream = &pEASData->streams[streamNum]; + return EAS_SUCCESS; + } + + /* parser did not recognize the file, close it and return an error */ + EAS_HWCloseFile(pEASData->hwInstData, fileHandle); + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "No parser recognized the requested file\n"); */ } + return EAS_ERROR_UNRECOGNIZED_FORMAT; +} + +/*---------------------------------------------------------------------------- + * EAS_GetWaveFmtChunk + *---------------------------------------------------------------------------- + * Helper function to retrieve WAVE file fmt chunk for MMAPI + *---------------------------------------------------------------------------- + * pEASData - pointer to EAS persistent data object + * pStream - stream handle + * pFmtChunk - pointer to variable to receive current setting + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetWaveFmtChunk (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_VOID_PTR *ppFmtChunk) +{ + EAS_RESULT result; + EAS_I32 value; + + if ((result = EAS_GetStreamParameter(pEASData, pStream, PARSER_DATA_FORMAT, &value)) != EAS_SUCCESS) + return result; + *ppFmtChunk = (EAS_VOID_PTR) value; + return EAS_SUCCESS; +} +#endif + +/*---------------------------------------------------------------------------- + * EAS_GetFileType + *---------------------------------------------------------------------------- + * Returns the file type (see eas_types.h for enumerations) + *---------------------------------------------------------------------------- + * pEASData - pointer to EAS persistent data object + * pStream - stream handle + * pFileType - pointer to variable to receive file type + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetFileType (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_I32 *pFileType) +{ + if (!EAS_StreamReady (pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + return EAS_GetStreamParameter(pEASData, pStream, PARSER_DATA_FILE_TYPE, pFileType); +} + +/*---------------------------------------------------------------------------- + * EAS_Prepare() + *---------------------------------------------------------------------------- + * Purpose: + * Prepares the synthesizer to play the file or stream. Parses the first + * frame of data from the file and arms the synthesizer. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - file or stream handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Prepare (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream) +{ + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_STATE state; + EAS_RESULT result; + + pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; + if (pParserModule == NULL) + return EAS_ERROR_FEATURE_NOT_AVAILABLE; + + /* check for valid state */ + result = pParserModule->pfState(pEASData, pStream->handle, &state); + if (result == EAS_SUCCESS) + { + /* prepare the stream */ + if (state == EAS_STATE_OPEN) + { + pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; + result = (*pParserModule->pfPrepare)(pEASData, pStream->handle); + + /* set volume */ + if (result == EAS_SUCCESS) + result = EAS_SetVolume(pEASData, pStream, pStream->volume); + } + else + result = EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + } + + return result; +} + +/*---------------------------------------------------------------------------- + * EAS_Render() + *---------------------------------------------------------------------------- + * Purpose: + * Parse the Midi data and render PCM audio data. + * + * Inputs: + * pEASData - buffer for internal EAS data + * pOut - output buffer pointer + * nNumRequested - requested num samples to generate + * pnNumGenerated - actual number of samples generated + * + * Outputs: + * EAS_SUCCESS if PCM data was successfully rendered + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Render (EAS_DATA_HANDLE pEASData, EAS_PCM *pOut, EAS_I32 numRequested, EAS_I32 *pNumGenerated) +{ + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_RESULT result; + EAS_I32 voicesRendered; + EAS_STATE parserState; + EAS_INT streamNum; + + /* assume no samples generated and reset workload */ + *pNumGenerated = 0; + VMInitWorkload(pEASData->pVoiceMgr); + + /* no support for other buffer sizes yet */ + if (numRequested != BUFFER_SIZE_IN_MONO_SAMPLES) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "This library supports only %ld samples in buffer, host requested %ld samples\n", + (EAS_I32) BUFFER_SIZE_IN_MONO_SAMPLES, numRequested); */ } + return EAS_BUFFER_SIZE_MISMATCH; + } + +#ifdef _METRICS_ENABLED + /* start performance counter */ + if (pEASData->pMetricsData) + (*pEASData->pMetricsModule->pfStartTimer)(pEASData->pMetricsData, EAS_PM_TOTAL_TIME); +#endif + + /* prep the frame buffer, do mix engine prep only if TRUE */ +#ifdef _SPLIT_ARCHITECTURE + if (VMStartFrame(pEASData)) + EAS_MixEnginePrep(pEASData, numRequested); +#else + /* prep the mix engine */ + EAS_MixEnginePrep(pEASData, numRequested); +#endif + + /* save the output buffer pointer */ + pEASData->pOutputAudioBuffer = pOut; + + +#ifdef _METRICS_ENABLED + /* start performance counter */ + if (pEASData->pMetricsData) + (*pEASData->pMetricsModule->pfStartTimer)(pEASData->pMetricsData, EAS_PM_PARSE_TIME); +#endif + + /* if we haven't finished parsing from last time, do it now */ + /* need to parse another frame of events before we render again */ + for (streamNum = 0; streamNum < MAX_NUMBER_STREAMS; streamNum++) + { + /* clear the locate flag */ + pEASData->streams[streamNum].streamFlags &= ~STREAM_FLAGS_LOCATE; + + if (pEASData->streams[streamNum].pParserModule) + { + + /* establish pointer to parser module */ + pParserModule = pEASData->streams[streamNum].pParserModule; + + /* handle pause */ + if (pEASData->streams[streamNum].streamFlags & STREAM_FLAGS_PAUSE) + { + if (pParserModule->pfPause) + result = pParserModule->pfPause(pEASData, pEASData->streams[streamNum].handle); + pEASData->streams[streamNum].streamFlags &= ~STREAM_FLAGS_PAUSE; + } + + /* get current state */ + if ((result = (*pParserModule->pfState)(pEASData, pEASData->streams[streamNum].handle, &parserState)) != EAS_SUCCESS) + return result; + + /* handle resume */ + if (parserState == EAS_STATE_PAUSED) + { + if (pEASData->streams[streamNum].streamFlags & STREAM_FLAGS_RESUME) + { + if (pParserModule->pfResume) + result = pParserModule->pfResume(pEASData, pEASData->streams[streamNum].handle); + pEASData->streams[streamNum].streamFlags &= ~STREAM_FLAGS_RESUME; + } + } + + /* if necessary, parse stream */ + if ((pEASData->streams[streamNum].streamFlags & STREAM_FLAGS_PARSED) == 0) + if ((result = EAS_ParseEvents(pEASData, &pEASData->streams[streamNum], pEASData->streams[streamNum].time + pEASData->streams[streamNum].frameLength, eParserModePlay)) != EAS_SUCCESS) + return result; + + /* check for an early abort */ + if ((pEASData->streams[streamNum].streamFlags) == 0) + { + +#ifdef _METRICS_ENABLED + /* stop performance counter */ + if (pEASData->pMetricsData) + (*pEASData->pMetricsModule->pfStartTimer)(pEASData->pMetricsData, EAS_PM_TOTAL_TIME); +#endif + + return EAS_SUCCESS; + } + + /* check for repeat */ + if (pEASData->streams[streamNum].repeatCount) + { + + /* check for stopped state */ + if ((result = (*pParserModule->pfState)(pEASData, pEASData->streams[streamNum].handle, &parserState)) != EAS_SUCCESS) + return result; + if (parserState == EAS_STATE_STOPPED) + { + + /* decrement repeat count, unless it is negative */ + if (pEASData->streams[streamNum].repeatCount > 0) + pEASData->streams[streamNum].repeatCount--; + + /* reset the parser */ + if ((result = (*pParserModule->pfReset)(pEASData, pEASData->streams[streamNum].handle)) != EAS_SUCCESS) + return result; + pEASData->streams[streamNum].time = 0; + } + } + } + } + +#ifdef _METRICS_ENABLED + /* stop performance counter */ + if (pEASData->pMetricsData) + (void)(*pEASData->pMetricsModule->pfStopTimer)(pEASData->pMetricsData, EAS_PM_PARSE_TIME); +#endif + +#ifdef _METRICS_ENABLED + /* start the render timer */ + if (pEASData->pMetricsData) + (*pEASData->pMetricsModule->pfStartTimer)(pEASData->pMetricsData, EAS_PM_RENDER_TIME); +#endif + + /* render audio */ + if ((result = VMRender(pEASData->pVoiceMgr, BUFFER_SIZE_IN_MONO_SAMPLES, pEASData->pMixBuffer, &voicesRendered)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "pfRender function returned error %ld\n", result); */ } + return result; + } + +#ifdef _METRICS_ENABLED + /* stop the render timer */ + if (pEASData->pMetricsData) { + (*pEASData->pMetricsModule->pfIncrementCounter)(pEASData->pMetricsData, EAS_PM_FRAME_COUNT, 1); + (void)(*pEASData->pMetricsModule->pfStopTimer)(pEASData->pMetricsData, EAS_PM_RENDER_TIME); + (*pEASData->pMetricsModule->pfIncrementCounter)(pEASData->pMetricsData, EAS_PM_TOTAL_VOICE_COUNT, (EAS_U32) voicesRendered); + (void)(*pEASData->pMetricsModule->pfRecordMaxValue)(pEASData->pMetricsData, EAS_PM_MAX_VOICES, (EAS_U32) voicesRendered); + } +#endif + + //2 Do we really need frameParsed? + /* need to parse another frame of events before we render again */ + for (streamNum = 0; streamNum < MAX_NUMBER_STREAMS; streamNum++) + if (pEASData->streams[streamNum].pParserModule != NULL) + pEASData->streams[streamNum].streamFlags &= ~STREAM_FLAGS_PARSED; + +#ifdef _METRICS_ENABLED + /* start performance counter */ + if (pEASData->pMetricsData) + (*pEASData->pMetricsModule->pfStartTimer)(pEASData->pMetricsData, EAS_PM_STREAM_TIME); +#endif + + /* render PCM audio */ + if ((result = EAS_PERender(pEASData, numRequested)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_PERender returned error %ld\n", result); */ } + return result; + } + +#ifdef _METRICS_ENABLED + /* stop the stream timer */ + if (pEASData->pMetricsData) + (void)(*pEASData->pMetricsModule->pfStopTimer)(pEASData->pMetricsData, EAS_PM_STREAM_TIME); +#endif + +#ifdef _METRICS_ENABLED + /* start the post timer */ + if (pEASData->pMetricsData) + (*pEASData->pMetricsModule->pfStartTimer)(pEASData->pMetricsData, EAS_PM_POST_TIME); +#endif + + /* for split architecture, send DSP vectors. Do post only if return is TRUE */ +#ifdef _SPLIT_ARCHITECTURE + if (VMEndFrame(pEASData)) + { + /* now do post-processing */ + EAS_MixEnginePost(pEASData, numRequested); + *pNumGenerated = numRequested; + } +#else + /* now do post-processing */ + EAS_MixEnginePost(pEASData, numRequested); + *pNumGenerated = numRequested; +#endif + +#ifdef _METRICS_ENABLED + /* stop the post timer */ + if (pEASData->pMetricsData) + (void)(*pEASData->pMetricsModule->pfStopTimer)(pEASData->pMetricsData, EAS_PM_POST_TIME); +#endif + + /* advance render time */ + pEASData->renderTime += AUDIO_FRAME_LENGTH; + +#if 0 + /* dump workload for debug */ + if (pEASData->pVoiceMgr->workload) + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Workload = %d\n", pEASData->pVoiceMgr->workload); */ } +#endif + +#ifdef _METRICS_ENABLED + /* stop performance counter */ + if (pEASData->pMetricsData) + { + PERF_TIMER temp; + temp = (*pEASData->pMetricsModule->pfStopTimer)(pEASData->pMetricsData, EAS_PM_TOTAL_TIME); + + /* if max render time, record the number of voices and time */ + if ((*pEASData->pMetricsModule->pfRecordMaxValue) + (pEASData->pMetricsData, EAS_PM_MAX_CYCLES, (EAS_U32) temp)) + { + (*pEASData->pMetricsModule->pfRecordValue)(pEASData->pMetricsData, EAS_PM_MAX_CYCLES_VOICES, (EAS_U32) voicesRendered); + (*pEASData->pMetricsModule->pfRecordValue)(pEASData->pMetricsData, EAS_PM_MAX_CYCLES_TIME, (EAS_I32) (pEASData->renderTime >> 8)); + } + } +#endif + +#ifdef JET_INTERFACE + /* let JET to do its thing */ + if (pEASData->jetHandle != NULL) + { + result = JET_Process(pEASData); + if (result != EAS_SUCCESS) + return result; + } +#endif + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_SetRepeat() + *---------------------------------------------------------------------------- + * Purpose: + * Set the selected stream to repeat. + * + * Inputs: + * pEASData - handle to data for this instance + * handle - handle to stream + * repeatCount - repeat count + * + * Outputs: + * + * Side Effects: + * + * Notes: + * 0 = no repeat + * 1 = repeat once, i.e. play through twice + * -1 = repeat forever + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_PUBLIC EAS_RESULT EAS_SetRepeat (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 repeatCount) +{ + pStream->repeatCount = repeatCount; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_GetRepeat() + *---------------------------------------------------------------------------- + * Purpose: + * Gets the current repeat count for the selected stream. + * + * Inputs: + * pEASData - handle to data for this instance + * handle - handle to stream + * pRrepeatCount - pointer to variable to hold repeat count + * + * Outputs: + * + * Side Effects: + * + * Notes: + * 0 = no repeat + * 1 = repeat once, i.e. play through twice + * -1 = repeat forever + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_PUBLIC EAS_RESULT EAS_GetRepeat (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 *pRepeatCount) +{ + *pRepeatCount = pStream->repeatCount; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_SetPlaybackRate() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the playback rate. + * + * Inputs: + * pEASData - handle to data for this instance + * handle - handle to stream + * rate - rate (28-bit fractional amount) + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_PUBLIC EAS_RESULT EAS_SetPlaybackRate (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_U32 rate) +{ + + /* check range */ + if ((rate < (1 << 27)) || (rate > (1 << 29))) + return EAS_ERROR_INVALID_PARAMETER; + + /* calculate new frame length + * + * NOTE: The maximum frame length we can accomodate based on a + * maximum rate of 2.0 (2^28) is 2047 (2^13-1). To accomodate a + * longer frame length or a higher maximum rate, the fixed point + * divide below will need to be adjusted + */ + pStream->frameLength = (AUDIO_FRAME_LENGTH * (rate >> 8)) >> 20; + + /* notify stream of new playback rate */ + EAS_SetStreamParameter(pEASData, pStream, PARSER_DATA_PLAYBACK_RATE, (EAS_I32) rate); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_SetTransposition) + *---------------------------------------------------------------------------- + * Purpose: + * Sets the key tranposition for the synthesizer. Transposes all + * melodic instruments by the specified amount. Range is limited + * to +/-12 semitones. + * + * Inputs: + * pEASData - handle to data for this instance + * handle - handle to stream + * transposition - +/-12 semitones + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetTransposition (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 transposition) +{ + + /* check range */ + if ((transposition < -12) || (transposition > 12)) + return EAS_ERROR_INVALID_PARAMETER; + + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + return EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_TRANSPOSITION, transposition); +} + +/*---------------------------------------------------------------------------- + * EAS_ParseEvents() + *---------------------------------------------------------------------------- + * Purpose: + * Parse events in the current streams until the desired time is reached. + * + * Inputs: + * pEASData - buffer for internal EAS data + * endTime - stop parsing if this time is reached + * parseMode - play, locate, or metadata + * + * Outputs: + * EAS_SUCCESS if PCM data was successfully rendered + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT EAS_ParseEvents (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_U32 endTime, EAS_INT parseMode) +{ + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_RESULT result; + EAS_I32 parserState; + EAS_BOOL done; + EAS_INT yieldCount = YIELD_EVENT_COUNT; + EAS_U32 time = 0; + + /* does this parser have a time function? */ + pParserModule = pStream->pParserModule; + if (pParserModule->pfTime == NULL) + { + /* check state */ + if ((result = (*pParserModule->pfState)(pEASData, pStream->handle, &parserState)) != EAS_SUCCESS) + return result; + /* if play state, advance time */ + if ((parserState >= EAS_STATE_READY) && (parserState <= EAS_STATE_PAUSING)) + pStream->time += pStream->frameLength; + done = EAS_TRUE; + } + + /* assume we're not done, in case we abort out */ + else + { + pStream->streamFlags &= ~STREAM_FLAGS_PARSED; + done = EAS_FALSE; + } + + while (!done) + { + + /* check for stopped state */ + if ((result = (*pParserModule->pfState)(pEASData, pStream->handle, &parserState)) != EAS_SUCCESS) + return result; + if (parserState > EAS_STATE_PLAY) + { + /* save current time if we're not in play mode */ + if (parseMode != eParserModePlay) + pStream->time = time << 8; + done = EAS_TRUE; + break; + } + + /* get the next event time */ + if (pParserModule->pfTime) + { + if ((result = (*pParserModule->pfTime)(pEASData, pStream->handle, &time)) != EAS_SUCCESS) + return result; + + /* if next event is within this frame, parse it */ + if (time < (endTime >> 8)) + { + + /* parse the next event */ + if (pParserModule->pfEvent) + if ((result = (*pParserModule->pfEvent)(pEASData, pStream->handle, parseMode)) != EAS_SUCCESS) + return result; + } + + /* no more events in this frame, advance time */ + else + { + pStream->time = endTime; + done = EAS_TRUE; + } + } + + /* check for max workload exceeded */ + if (VMCheckWorkload(pEASData->pVoiceMgr)) + { + /* stop even though we may not have parsed + * all the events in this frame. The parser will try to + * catch up on the next frame. + */ + break; + } + + /* give host a chance for an early abort */ + if (--yieldCount == 0) + { + if (EAS_HWYield(pEASData->hwInstData)) + break; + yieldCount = YIELD_EVENT_COUNT; + } + } + + /* if no early abort, parsing is complete for this frame */ + if (done) + pStream->streamFlags |= STREAM_FLAGS_PARSED; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_ParseMetaData() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - file or stream handle + * playLength - pointer to variable to store the play length (in msecs) + * + * Outputs: + * + * + * Side Effects: + * - resets the parser to the start of the file + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_ParseMetaData (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 *playLength) +{ + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_RESULT result; + EAS_STATE state; + + pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; + if (pParserModule == NULL) + return EAS_ERROR_FEATURE_NOT_AVAILABLE; + + /* check parser state */ + if ((result = (*pParserModule->pfState)(pEASData, pStream->handle, &state)) != EAS_SUCCESS) + return result; + if (state >= EAS_STATE_OPEN) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + /* if parser has metadata function, use that */ + if (pParserModule->pfGetMetaData != NULL) + return pParserModule->pfGetMetaData(pEASData, pStream->handle, playLength); + + /* reset the parser to the beginning */ + if ((result = (*pParserModule->pfReset)(pEASData, pStream->handle)) != EAS_SUCCESS) + return result; + + /* parse the file to end */ + pStream->time = 0; + VMInitWorkload(pEASData->pVoiceMgr); + if ((result = EAS_ParseEvents(pEASData, pStream, 0x7fffffff, eParserModeMetaData)) != EAS_SUCCESS) + return result; + + /* get the parser time */ + if ((result = EAS_GetLocation(pEASData, pStream, playLength)) != EAS_SUCCESS) + return result; + + /* reset the parser to the beginning */ + pStream->time = 0; + return (*pParserModule->pfReset)(pEASData, pStream->handle); +} + +/*---------------------------------------------------------------------------- + * EAS_RegisterMetaDataCallback() + *---------------------------------------------------------------------------- + * Purpose: + * Registers a metadata callback function for parsed metadata. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - file or stream handle + * cbFunc - pointer to host callback function + * metaDataBuffer - pointer to metadata buffer + * metaDataBufSize - maximum size of the metadata buffer + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_RegisterMetaDataCallback ( + EAS_DATA_HANDLE pEASData, + EAS_HANDLE pStream, + EAS_METADATA_CBFUNC cbFunc, + char *metaDataBuffer, + EAS_I32 metaDataBufSize, + EAS_VOID_PTR pUserData) +{ + S_METADATA_CB metadata; + + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + /* register callback function */ + metadata.callback = cbFunc; + metadata.buffer = metaDataBuffer; + metadata.bufferSize = metaDataBufSize; + metadata.pUserData = pUserData; + return EAS_SetStreamParameter(pEASData, pStream, PARSER_DATA_METADATA_CB, (EAS_I32) &metadata); +} + +/*---------------------------------------------------------------------------- + * EAS_GetNoteCount () + *---------------------------------------------------------------------------- + * Returns the total number of notes played in this stream + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetNoteCount (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 *pNoteCount) +{ + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + return EAS_IntGetStrmParam(pEASData, pStream, PARSER_DATA_NOTE_COUNT, pNoteCount); +} + +/*---------------------------------------------------------------------------- + * EAS_CloseFile() + *---------------------------------------------------------------------------- + * Purpose: + * Closes an audio file or stream. Playback should have either paused or + * completed (EAS_State returns EAS_PAUSED or EAS_STOPPED). + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - file or stream handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_CloseFile (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream) +{ + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_RESULT result; + + /* call the close function */ + pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; + if (pParserModule == NULL) + return EAS_ERROR_FEATURE_NOT_AVAILABLE; + + result = (*pParserModule->pfClose)(pEASData, pStream->handle); + + /* clear the handle and parser interface pointer */ + pStream->handle = NULL; + pStream->pParserModule = NULL; + return result; +} + +/*---------------------------------------------------------------------------- + * EAS_OpenMIDIStream() + *---------------------------------------------------------------------------- + * Purpose: + * Opens a raw MIDI stream allowing the host to route MIDI cable data directly to the synthesizer + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * pHandle - pointer to variable to hold file or stream handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_OpenMIDIStream (EAS_DATA_HANDLE pEASData, EAS_HANDLE *ppStream, EAS_HANDLE streamHandle) +{ + EAS_RESULT result; + S_INTERACTIVE_MIDI *pMIDIStream; + EAS_INT streamNum; + + /* initialize some pointers */ + *ppStream = NULL; + + /* allocate a stream */ + if ((streamNum = EAS_AllocateStream(pEASData)) < 0) + return EAS_ERROR_MAX_STREAMS_OPEN; + + /* check Configuration Module for S_EAS_DATA allocation */ + if (pEASData->staticMemoryModel) + pMIDIStream = EAS_CMEnumData(EAS_CM_MIDI_STREAM_DATA); + else + pMIDIStream = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_INTERACTIVE_MIDI)); + + /* allocate dynamic memory */ + if (!pMIDIStream) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Failed to allocate MIDI stream data\n"); */ } + return EAS_ERROR_MALLOC_FAILED; + } + + /* zero the memory to insure complete initialization */ + EAS_HWMemSet(pMIDIStream, 0, sizeof(S_INTERACTIVE_MIDI)); + EAS_InitStream(&pEASData->streams[streamNum], NULL, pMIDIStream); + + /* instantiate a new synthesizer */ + if (streamHandle == NULL) + { + result = VMInitMIDI(pEASData, &pMIDIStream->pSynth); + } + + /* use an existing synthesizer */ + else + { + EAS_I32 value; + result = EAS_GetStreamParameter(pEASData, streamHandle, PARSER_DATA_SYNTH_HANDLE, &value); + pMIDIStream->pSynth = (S_SYNTH*) value; + VMIncRefCount(pMIDIStream->pSynth); + } + if (result != EAS_SUCCESS) + { + EAS_CloseMIDIStream(pEASData, &pEASData->streams[streamNum]); + return result; + } + + /* initialize the MIDI stream data */ + EAS_InitMIDIStream(&pMIDIStream->stream); + + *ppStream = (EAS_HANDLE) &pEASData->streams[streamNum]; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_WriteMIDIStream() + *---------------------------------------------------------------------------- + * Purpose: + * Send data to the MIDI stream device + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - stream handle + * pBuffer - pointer to buffer + * count - number of bytes to write + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_WriteMIDIStream (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_U8 *pBuffer, EAS_I32 count) +{ + S_INTERACTIVE_MIDI *pMIDIStream; + EAS_RESULT result; + + pMIDIStream = (S_INTERACTIVE_MIDI*) pStream->handle; + + /* send the entire buffer */ + while (count--) + { + if ((result = EAS_ParseMIDIStream(pEASData, pMIDIStream->pSynth, &pMIDIStream->stream, *pBuffer++, eParserModePlay)) != EAS_SUCCESS) + return result; + } + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_CloseMIDIStream() + *---------------------------------------------------------------------------- + * Purpose: + * Closes a raw MIDI stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - stream handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_CloseMIDIStream (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream) +{ + S_INTERACTIVE_MIDI *pMIDIStream; + + pMIDIStream = (S_INTERACTIVE_MIDI*) pStream->handle; + + /* close synth */ + if (pMIDIStream->pSynth != NULL) + { + VMMIDIShutdown(pEASData, pMIDIStream->pSynth); + pMIDIStream->pSynth = NULL; + } + + /* release allocated memory */ + if (!pEASData->staticMemoryModel) + EAS_HWFree(((S_EAS_DATA*) pEASData)->hwInstData, pMIDIStream); + + pStream->handle = NULL; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_State() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the state of an audio file or stream. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - file or stream handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_State (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_STATE *pState) +{ + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_RESULT result; + + /* call the parser to return state */ + pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; + if (pParserModule == NULL) + return EAS_ERROR_FEATURE_NOT_AVAILABLE; + + if ((result = (*pParserModule->pfState)(pEASData, pStream->handle, pState)) != EAS_SUCCESS) + return result; + + /* if repeat count is set for this parser, mask the stopped state from the application */ + if (pStream->repeatCount && (*pState == EAS_STATE_STOPPED)) + *pState = EAS_STATE_PLAY; + + /* if we're not ready or playing, we don't need to hide state from host */ + if (*pState > EAS_STATE_PLAY) + return EAS_SUCCESS; + + /* if stream is about to be paused, report it as paused */ + if (pStream->streamFlags & STREAM_FLAGS_PAUSE) + { + if (pStream->streamFlags & STREAM_FLAGS_LOCATE) + *pState = EAS_STATE_PAUSED; + else + *pState = EAS_STATE_PAUSING; + } + + /* if stream is about to resume, report it as playing */ + if (pStream->streamFlags & STREAM_FLAGS_RESUME) + *pState = EAS_STATE_PLAY; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_SetPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Set the polyphony of the stream. A value of 0 allows the stream + * to use all voices (set by EAS_SetSynthPolyphony). + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - handle returned by EAS_OpenFile + * polyphonyCount - the desired polyphony count + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetPolyphony (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 polyphonyCount) +{ + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + return EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_POLYPHONY, polyphonyCount); +} + +/*---------------------------------------------------------------------------- + * EAS_GetPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current polyphony setting of the stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - handle returned by EAS_OpenFile + * pPolyphonyCount - pointer to variable to receive polyphony count + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetPolyphony (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 *pPolyphonyCount) +{ + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + return EAS_IntGetStrmParam(pEASData, pStream, PARSER_DATA_POLYPHONY, pPolyphonyCount); +} + +/*---------------------------------------------------------------------------- + * EAS_SetSynthPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Set the polyphony of the synth . Value must be >= 1 and <= the + * maximum number of voices. This function will pin the polyphony + * at those limits + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * synthNum - synthesizer number (0 = onboard, 1 = DSP) + * polyphonyCount - the desired polyphony count + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetSynthPolyphony (EAS_DATA_HANDLE pEASData, EAS_I32 synthNum, EAS_I32 polyphonyCount) +{ + return VMSetSynthPolyphony(pEASData->pVoiceMgr, synthNum, polyphonyCount); +} + +/*---------------------------------------------------------------------------- + * EAS_GetSynthPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current polyphony setting of the synth + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * synthNum - synthesizer number (0 = onboard, 1 = DSP) + * pPolyphonyCount - pointer to variable to receive polyphony count + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetSynthPolyphony (EAS_DATA_HANDLE pEASData, EAS_I32 synthNum, EAS_I32 *pPolyphonyCount) +{ + return VMGetSynthPolyphony(pEASData->pVoiceMgr, synthNum, pPolyphonyCount); +} + +/*---------------------------------------------------------------------------- + * EAS_SetPriority() + *---------------------------------------------------------------------------- + * Purpose: + * Set the priority of the stream. Determines which stream's voices + * are stolen when there are insufficient voices for all notes. + * Value must be in the range of 1-15, lower values are higher + * priority. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - handle returned by EAS_OpenFile + * polyphonyCount - the desired polyphony count + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetPriority (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 priority) +{ + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + return EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_PRIORITY, priority); +} + +/*---------------------------------------------------------------------------- + * EAS_GetPriority() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current priority setting of the stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - handle returned by EAS_OpenFile + * pPriority - pointer to variable to receive priority + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetPriority (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 *pPriority) +{ + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + return EAS_IntGetStrmParam(pEASData, pStream, PARSER_DATA_PRIORITY, pPriority); +} + +/*---------------------------------------------------------------------------- + * EAS_SetVolume() + *---------------------------------------------------------------------------- + * Purpose: + * Set the master gain for the mix engine in 1dB increments + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * volume - the desired master gain (100 is max) + * handle - file or stream handle + * + * Outputs: + * + * + * Side Effects: + * overrides any previously set master volume from sysex + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetVolume (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 volume) +{ + EAS_I16 gain; + + /* check range */ + if ((volume < 0) || (volume > EAS_MAX_VOLUME)) + return EAS_ERROR_PARAMETER_RANGE; + + /* stream volume */ + if (pStream != NULL) + { + EAS_I32 gainOffset; + EAS_RESULT result; + + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + /* get gain offset */ + pStream->volume = (EAS_U8) volume; + result = EAS_GetStreamParameter(pEASData, pStream, PARSER_DATA_GAIN_OFFSET, &gainOffset); + if (result == EAS_SUCCESS) + volume += gainOffset; + + /* set stream volume */ + gain = EAS_VolumeToGain(volume - STREAM_VOLUME_HEADROOM); + + /* convert to linear scalar */ + return EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_VOLUME, gain); + } + + /* master volume */ + pEASData->masterVolume = (EAS_U8) volume; +#if (NUM_OUTPUT_CHANNELS == 1) + /* leave 3dB headroom for mono output */ + volume -= 3; +#endif + + gain = EAS_VolumeToGain(volume - STREAM_VOLUME_HEADROOM); + pEASData->masterGain = gain; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_GetVolume() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the master volume for the synthesizer. The default volume setting is + * 50. The volume range is 0 to 100; + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * volume - the desired master volume + * handle - file or stream handle + * + * Outputs: + * + * + * Side Effects: + * overrides any previously set master volume from sysex + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_I32 EAS_GetVolume (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream) +{ + if (pStream == NULL) + return pEASData->masterVolume; + + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + return pStream->volume; +} + +/*---------------------------------------------------------------------------- + * EAS_SetMaxLoad() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the maximum workload the parsers will do in a single call to + * EAS_Render. The units are currently arbitrary, but should correlate + * well to the actual CPU cycles consumed. The primary effect is to + * reduce the occasional peaks in CPU cycles consumed when parsing + * dense parts of a MIDI score. + * + * Inputs: + * pEASData - handle to data for this instance + * maxLoad - the desired maximum workload + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetMaxLoad (EAS_DATA_HANDLE pEASData, EAS_I32 maxLoad) +{ + VMSetWorkload(pEASData->pVoiceMgr, maxLoad); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_SetMaxPCMStreams() + *---------------------------------------------------------------------------- + * Sets the maximum number of PCM streams allowed in parsers that + * use PCM streaming. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - handle returned by EAS_OpenFile + * maxNumStreams - maximum number of PCM streams + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetMaxPCMStreams (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 maxNumStreams) +{ + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + return EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_MAX_PCM_STREAMS, maxNumStreams); +} + +/*---------------------------------------------------------------------------- + * EAS_Locate() + *---------------------------------------------------------------------------- + * Purpose: + * Locate into the file associated with the handle. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - file handle + * milliseconds - playback offset from start of file in milliseconds + * + * Outputs: + * + * + * Side Effects: + * the actual offset will be quantized to the closest update period, typically + * a resolution of 5.9ms. Notes that are started prior to this time will not + * sound. Any notes currently playing will be shut off. + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Locate (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 milliseconds, EAS_BOOL offset) +{ + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_RESULT result; + EAS_U32 requestedTime; + EAS_STATE state; + + /* get pointer to parser function table */ + pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; + if (pParserModule == NULL) + return EAS_ERROR_FEATURE_NOT_AVAILABLE; + + if ((result = (*pParserModule->pfState)(pEASData, pStream->handle, &state)) != EAS_SUCCESS) + return result; + if (state >= EAS_STATE_OPEN) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + /* handle offset and limit to start of file */ + /*lint -e{704} use shift for performance*/ + if (offset) + milliseconds += (EAS_I32) pStream->time >> 8; + if (milliseconds < 0) + milliseconds = 0; + + /* check to see if the request is different from the current time */ + requestedTime = (EAS_U32) milliseconds; + if (requestedTime == (pStream->time >> 8)) + return EAS_SUCCESS; + + /* set the locate flag */ + pStream->streamFlags |= STREAM_FLAGS_LOCATE; + + /* use the parser locate function, if available */ + if (pParserModule->pfLocate != NULL) + { + EAS_BOOL parserLocate = EAS_FALSE; + result = pParserModule->pfLocate(pEASData, pStream->handle, (EAS_I32) requestedTime, &parserLocate); + if (!parserLocate) + { + if (result == EAS_SUCCESS) + pStream->time = requestedTime << 8; + return result; + } + } + + /* if we were paused and not going to resume, set pause request flag */ + if (((state == EAS_STATE_PAUSING) || (state == EAS_STATE_PAUSED)) && ((pStream->streamFlags & STREAM_FLAGS_RESUME) == 0)) + pStream->streamFlags |= STREAM_FLAGS_PAUSE; + + /* reset the synth and parser */ + if ((result = (*pParserModule->pfReset)(pEASData, pStream->handle)) != EAS_SUCCESS) + return result; + pStream->time = 0; + + /* locating forward, clear parsed flag and parse data until we get to the requested location */ + if ((result = EAS_ParseEvents(pEASData, pStream, requestedTime << 8, eParserModeLocate)) != EAS_SUCCESS) + return result; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_GetLocation() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current playback offset + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - file handle + * + * Outputs: + * The offset in milliseconds from the start of the current sequence, quantized + * to the nearest update period. Actual resolution is typically 5.9 ms. + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_PUBLIC EAS_RESULT EAS_GetLocation (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 *pTime) +{ + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + *pTime = pStream->time >> 8; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_GetRenderTime() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current playback offset + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * + * Outputs: + * Gets the render time clock in msecs. + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetRenderTime (EAS_DATA_HANDLE pEASData, EAS_I32 *pTime) +{ + *pTime = pEASData->renderTime >> 8; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_Pause() + *---------------------------------------------------------------------------- + * Purpose: + * Pauses the playback of the data associated with this handle. The audio + * is gracefully ramped down to prevent clicks and pops. It may take several + * buffers of audio before the audio is muted. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * handle - file or stream handle + * + * Outputs: + * + * + * Side Effects: + * + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Pause (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream) +{ + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_STATE state; + EAS_RESULT result; + + pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; + if (pParserModule == NULL) + return EAS_ERROR_FEATURE_NOT_AVAILABLE; + + /* check for valid state */ + result = pParserModule->pfState(pEASData, pStream->handle, &state); + if (result == EAS_SUCCESS) + { + if ((state != EAS_STATE_PLAY) && (state != EAS_STATE_READY) && ((pStream->streamFlags & STREAM_FLAGS_RESUME) == 0)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + /* make sure parser implements pause */ + if (pParserModule->pfPause == NULL) + result = EAS_ERROR_NOT_IMPLEMENTED; + + /* clear resume flag */ + pStream->streamFlags &= ~STREAM_FLAGS_RESUME; + + /* set pause flag */ + pStream->streamFlags |= STREAM_FLAGS_PAUSE; + +#if 0 + /* pause the stream */ + if (pParserModule->pfPause) + result = pParserModule->pfPause(pEASData, pStream->handle); + else + result = EAS_ERROR_NOT_IMPLEMENTED; +#endif + } + + return result; +} + +/*---------------------------------------------------------------------------- + * EAS_Resume() + *---------------------------------------------------------------------------- + * Purpose: + * Resumes the playback of the data associated with this handle. The audio + * is gracefully ramped up to prevent clicks and pops. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * handle - file or stream handle + * + * Outputs: + * + * + * Side Effects: + * + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Resume (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream) +{ + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_STATE state; + EAS_RESULT result; + + pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; + if (pParserModule == NULL) + return EAS_ERROR_FEATURE_NOT_AVAILABLE; + + /* check for valid state */ + result = pParserModule->pfState(pEASData, pStream->handle, &state); + if (result == EAS_SUCCESS) + { + if ((state != EAS_STATE_PAUSED) && (state != EAS_STATE_PAUSING) && ((pStream->streamFlags & STREAM_FLAGS_PAUSE) == 0)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + /* make sure parser implements this function */ + if (pParserModule->pfResume == NULL) + result = EAS_ERROR_NOT_IMPLEMENTED; + + /* clear pause flag */ + pStream->streamFlags &= ~STREAM_FLAGS_PAUSE; + + /* set resume flag */ + pStream->streamFlags |= STREAM_FLAGS_RESUME; + +#if 0 + /* resume the stream */ + if (pParserModule->pfResume) + result = pParserModule->pfResume(pEASData, pStream->handle); + else + result = EAS_ERROR_NOT_IMPLEMENTED; +#endif + } + + return result; +} + +/*---------------------------------------------------------------------------- + * EAS_GetParameter() + *---------------------------------------------------------------------------- + * Purpose: + * Set the parameter of a module. See E_MODULES for a list of modules + * and the header files of the modules for a list of parameters. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * handle - file or stream handle + * module - enumerated module number + * param - enumerated parameter number + * pValue - pointer to variable to receive parameter value + * + * Outputs: + * + * + * Side Effects: + * + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetParameter (EAS_DATA_HANDLE pEASData, EAS_I32 module, EAS_I32 param, EAS_I32 *pValue) +{ + + if (module >= NUM_EFFECTS_MODULES) + return EAS_ERROR_INVALID_MODULE; + + if (pEASData->effectsModules[module].effectData == NULL) + return EAS_ERROR_INVALID_MODULE; + + return (*pEASData->effectsModules[module].effect->pFGetParam) + (pEASData->effectsModules[module].effectData, param, pValue); +} + +/*---------------------------------------------------------------------------- + * EAS_SetParameter() + *---------------------------------------------------------------------------- + * Purpose: + * Set the parameter of a module. See E_MODULES for a list of modules + * and the header files of the modules for a list of parameters. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * handle - file or stream handle + * module - enumerated module number + * param - enumerated parameter number + * value - new parameter value + * + * Outputs: + * + * + * Side Effects: + * + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetParameter (EAS_DATA_HANDLE pEASData, EAS_I32 module, EAS_I32 param, EAS_I32 value) +{ + + if (module >= NUM_EFFECTS_MODULES) + return EAS_ERROR_INVALID_MODULE; + + if (pEASData->effectsModules[module].effectData == NULL) + return EAS_ERROR_INVALID_MODULE; + + return (*pEASData->effectsModules[module].effect->pFSetParam) + (pEASData->effectsModules[module].effectData, param, value); +} + +#ifdef _METRICS_ENABLED +/*---------------------------------------------------------------------------- + * EAS_MetricsReport() + *---------------------------------------------------------------------------- + * Purpose: + * Displays the current metrics through the metrics interface. + * + * Inputs: + * p - instance data handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_MetricsReport (EAS_DATA_HANDLE pEASData) +{ + if (!pEASData->pMetricsModule) + return EAS_ERROR_INVALID_MODULE; + + return (*pEASData->pMetricsModule->pfReport)(pEASData->pMetricsData); +} + +/*---------------------------------------------------------------------------- + * EAS_MetricsReset() + *---------------------------------------------------------------------------- + * Purpose: + * Resets the metrics. + * + * Inputs: + * p - instance data handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_MetricsReset (EAS_DATA_HANDLE pEASData) +{ + + if (!pEASData->pMetricsModule) + return EAS_ERROR_INVALID_MODULE; + + return (*pEASData->pMetricsModule->pfReset)(pEASData->pMetricsData); +} +#endif + +/*---------------------------------------------------------------------------- + * EAS_SetSoundLibrary() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the location of the sound library. + * + * Inputs: + * pEASData - instance data handle + * pSoundLib - pointer to sound library + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetSoundLibrary (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_SNDLIB_HANDLE pSndLib) +{ + if (pStream) + { + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + return EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_EAS_LIBRARY, (EAS_I32) pSndLib); + } + + return VMSetGlobalEASLib(pEASData->pVoiceMgr, pSndLib); +} + +/*---------------------------------------------------------------------------- + * EAS_SetHeaderSearchFlag() + *---------------------------------------------------------------------------- + * By default, when EAS_OpenFile is called, the parsers check the + * first few bytes of the file looking for a specific header. Some + * mobile devices may add a header to the start of a file, which + * will prevent the parser from recognizing the file. If the + * searchFlag is set to EAS_TRUE, the parser will search the entire + * file looking for the header. This may enable EAS to recognize + * some files that it would ordinarily reject. The negative is that + * it make take slightly longer to process the EAS_OpenFile request. + * + * Inputs: + * pEASData - instance data handle + * searchFlag - search flag (EAS_TRUE or EAS_FALSE) + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetHeaderSearchFlag (EAS_DATA_HANDLE pEASData, EAS_BOOL searchFlag) +{ + pEASData->searchHeaderFlag = (EAS_BOOL8) searchFlag; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_SetPlayMode() + *---------------------------------------------------------------------------- + * Some file formats support special play modes, such as iMode partial + * play mode. This call can be used to change the play mode. The + * default play mode (usually straight playback) is always zero. + * + * Inputs: + * pEASData - instance data handle + * handle - file or stream handle + * playMode - play mode (see file parser for specifics) + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetPlayMode (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 playMode) +{ + return EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_PLAY_MODE, playMode); +} + +#ifdef DLS_SYNTHESIZER +/*---------------------------------------------------------------------------- + * EAS_LoadDLSCollection() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the location of the sound library. + * + * Inputs: + * pEASData - instance data handle + * pSoundLib - pointer to sound library + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_LoadDLSCollection (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_FILE_LOCATOR locator) +{ + EAS_FILE_HANDLE fileHandle; + EAS_RESULT result; + EAS_DLSLIB_HANDLE pDLS; + + if (pStream != NULL) + { + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + } + + /* open the file */ + if ((result = EAS_HWOpenFile(pEASData->hwInstData, locator, &fileHandle, EAS_FILE_READ)) != EAS_SUCCESS) + return result; + + /* parse the file */ + result = DLSParser(pEASData->hwInstData, fileHandle, 0, &pDLS); + EAS_HWCloseFile(pEASData->hwInstData, fileHandle); + + if (result == EAS_SUCCESS) + { + + /* if a stream pStream is specified, point it to the DLS collection */ + if (pStream) + result = EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_DLS_COLLECTION, (EAS_I32) pDLS); + + /* global DLS load */ + else + result = VMSetGlobalDLSLib(pEASData, pDLS); + } + + return result; +} +#endif + +#ifdef EXTERNAL_AUDIO +/*---------------------------------------------------------------------------- + * EAS_RegExtAudioCallback() + *---------------------------------------------------------------------------- + * Purpose: + * Registers callback functions for audio events. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - file or stream handle + * cbProgChgFunc - pointer to host callback function for program change + * cbEventFunc - pointer to host callback functio for note events + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_RegExtAudioCallback (EAS_DATA_HANDLE pEASData, + EAS_HANDLE pStream, + EAS_VOID_PTR pInstData, + EAS_EXT_PRG_CHG_FUNC cbProgChgFunc, + EAS_EXT_EVENT_FUNC cbEventFunc) +{ + S_SYNTH *pSynth; + + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + if (EAS_GetStreamParameter(pEASData, pStream, PARSER_DATA_SYNTH_HANDLE, (EAS_I32*) &pSynth) != EAS_SUCCESS) + return EAS_ERROR_INVALID_PARAMETER; + + if (pSynth == NULL) + return EAS_ERROR_INVALID_PARAMETER; + + VMRegExtAudioCallback(pSynth, pInstData, cbProgChgFunc, cbEventFunc); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_GetMIDIControllers() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current state of MIDI controllers on the requested channel. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - file or stream handle + * pControl - pointer to structure to receive data + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetMIDIControllers (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_U8 channel, S_MIDI_CONTROLLERS *pControl) +{ + S_SYNTH *pSynth; + + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + if (EAS_GetStreamParameter(pEASData, pStream, PARSER_DATA_SYNTH_HANDLE, (EAS_I32*) &pSynth) != EAS_SUCCESS) + return EAS_ERROR_INVALID_PARAMETER; + + if (pSynth == NULL) + return EAS_ERROR_INVALID_PARAMETER; + + VMGetMIDIControllers(pSynth, channel, pControl); + return EAS_SUCCESS; +} +#endif + +#ifdef _SPLIT_ARCHITECTURE +/*---------------------------------------------------------------------------- + * EAS_SetFrameBuffer() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the frame buffer pointer passed to the IPC communications functions + * + * Inputs: + * pEASData - instance data handle + * locator - file locator + * + * Outputs: + * + * + * Side Effects: + * May overlay instruments in the GM sound set + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetFrameBuffer (EAS_DATA_HANDLE pEASData, EAS_FRAME_BUFFER_HANDLE pFrameBuffer) +{ + if (pEASData->pVoiceMgr) + pEASData->pVoiceMgr->pFrameBuffer = pFrameBuffer; + return EAS_SUCCESS; +} +#endif + +/*---------------------------------------------------------------------------- + * EAS_SearchFile + *---------------------------------------------------------------------------- + * Search file for specific sequence starting at current file + * position. Returns offset to start of sequence. + * + * Inputs: + * pEASData - pointer to EAS persistent data object + * fileHandle - file handle + * searchString - pointer to search sequence + * len - length of search sequence + * pOffset - pointer to variable to store offset to sequence + * + * Returns EAS_EOF if end-of-file is reached + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_SearchFile (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, const EAS_U8 *searchString, EAS_I32 len, EAS_I32 *pOffset) +{ + EAS_RESULT result; + EAS_INT index; + EAS_U8 c; + + *pOffset = -1; + index = 0; + for (;;) + { + result = EAS_HWGetByte(pEASData->hwInstData, fileHandle, &c); + if (result != EAS_SUCCESS) + return result; + if (c == searchString[index]) + { + index++; + if (index == 4) + { + result = EAS_HWFilePos(pEASData->hwInstData, fileHandle, pOffset); + if (result != EAS_SUCCESS) + return result; + *pOffset -= len; + break; + } + } + else + index = 0; + } + return EAS_SUCCESS; +} + + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_reverb.c b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_reverb.c new file mode 100755 index 0000000..cd5befe --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_reverb.c @@ -0,0 +1,1154 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_reverb.c + * + * Contents and purpose: + * Contains the implementation of the Reverb effect. + * + * + * Copyright Sonic Network Inc. 2006 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 510 $ + * $Date: 2006-12-19 01:47:33 -0800 (Tue, 19 Dec 2006) $ + *---------------------------------------------------------------------------- +*/ + +/*------------------------------------ + * includes + *------------------------------------ +*/ + +#include "eas_data.h" +#include "eas_effects.h" +#include "eas_math.h" +#include "eas_reverbdata.h" +#include "eas_reverb.h" +#include "eas_config.h" +#include "eas_host.h" +#include "eas_report.h" + +/* prototypes for effects interface */ +static EAS_RESULT ReverbInit (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR *pInstData); +static void ReverbProcess (EAS_VOID_PTR pInstData, EAS_PCM *pSrc, EAS_PCM *pDst, EAS_I32 numSamples); +static EAS_RESULT ReverbShutdown (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT ReverbGetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue); +static EAS_RESULT ReverbSetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value); + +/* common effects interface for configuration module */ +const S_EFFECTS_INTERFACE EAS_Reverb = +{ + ReverbInit, + ReverbProcess, + ReverbShutdown, + ReverbGetParam, + ReverbSetParam +}; + + + +/*---------------------------------------------------------------------------- + * InitializeReverb() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ReverbInit(EAS_DATA_HANDLE pEASData, EAS_VOID_PTR *pInstData) +{ + EAS_I32 i; + EAS_U16 nOffset; + EAS_INT temp; + + S_REVERB_OBJECT *pReverbData; + S_REVERB_PRESET *pPreset; + + /* check Configuration Module for data allocation */ + if (pEASData->staticMemoryModel) + pReverbData = EAS_CMEnumFXData(EAS_MODULE_REVERB); + + /* allocate dynamic memory */ + else + pReverbData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_REVERB_OBJECT)); + + if (pReverbData == NULL) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Failed to allocate Reverb memory\n"); */ } + return EAS_ERROR_MALLOC_FAILED; + } + + /* clear the structure */ + EAS_HWMemSet(pReverbData, 0, sizeof(S_REVERB_OBJECT)); + + ReverbReadInPresets(pReverbData); + + pReverbData->m_nMinSamplesToAdd = REVERB_UPDATE_PERIOD_IN_SAMPLES; + + pReverbData->m_nRevOutFbkR = 0; + pReverbData->m_nRevOutFbkL = 0; + + pReverbData->m_sAp0.m_zApIn = AP0_IN; + pReverbData->m_sAp0.m_zApOut = AP0_IN + DEFAULT_AP0_LENGTH; + pReverbData->m_sAp0.m_nApGain = DEFAULT_AP0_GAIN; + + pReverbData->m_zD0In = DELAY0_IN; + + pReverbData->m_sAp1.m_zApIn = AP1_IN; + pReverbData->m_sAp1.m_zApOut = AP1_IN + DEFAULT_AP1_LENGTH; + pReverbData->m_sAp1.m_nApGain = DEFAULT_AP1_GAIN; + + pReverbData->m_zD1In = DELAY1_IN; + + pReverbData->m_zLpf0 = 0; + pReverbData->m_zLpf1 = 0; + pReverbData->m_nLpfFwd = 8837; + pReverbData->m_nLpfFbk = 6494; + + pReverbData->m_nSin = 0; + pReverbData->m_nCos = 0; + pReverbData->m_nSinIncrement = 0; + pReverbData->m_nCosIncrement = 0; + + // set xfade parameters + pReverbData->m_nXfadeInterval = (EAS_U16)REVERB_XFADE_PERIOD_IN_SAMPLES; + pReverbData->m_nXfadeCounter = pReverbData->m_nXfadeInterval + 1; // force update on first iteration + pReverbData->m_nPhase = -32768; + pReverbData->m_nPhaseIncrement = REVERB_XFADE_PHASE_INCREMENT; + + pReverbData->m_nNoise = (EAS_I16)0xABCD; + + pReverbData->m_nMaxExcursion = 0x007F; + + // set delay tap lengths + nOffset = ReverbCalculateNoise( pReverbData->m_nMaxExcursion, + &pReverbData->m_nNoise ); + + pReverbData->m_zD1Cross = + DELAY1_OUT - pReverbData->m_nMaxExcursion + nOffset; + + nOffset = ReverbCalculateNoise( pReverbData->m_nMaxExcursion, + &pReverbData->m_nNoise ); + + pReverbData->m_zD0Cross = + DELAY1_OUT - pReverbData->m_nMaxExcursion - nOffset; + + nOffset = ReverbCalculateNoise( pReverbData->m_nMaxExcursion, + &pReverbData->m_nNoise ); + + pReverbData->m_zD0Self = + DELAY0_OUT - pReverbData->m_nMaxExcursion - nOffset; + + nOffset = ReverbCalculateNoise( pReverbData->m_nMaxExcursion, + &pReverbData->m_nNoise ); + + pReverbData->m_zD1Self = + DELAY1_OUT - pReverbData->m_nMaxExcursion + nOffset; + + // for debugging purposes, allow noise generator + pReverbData->m_bUseNoise = EAS_FALSE; + + // for debugging purposes, allow bypass + pReverbData->m_bBypass = EAS_TRUE; //EAS_FALSE; + + pReverbData->m_nNextRoom = 1; + + pReverbData->m_nCurrentRoom = pReverbData->m_nNextRoom + 1; // force update on first iteration + + pReverbData->m_nWet = REVERB_DEFAULT_WET; + + pReverbData->m_nDry = REVERB_DEFAULT_DRY; + + // set base index into circular buffer + pReverbData->m_nBaseIndex = 0; + + // set the early reflections, L + pReverbData->m_sEarlyL.m_nLpfFbk = 4915; + pReverbData->m_sEarlyL.m_nLpfFwd = 27852; + pReverbData->m_sEarlyL.m_zLpf = 0; + + for (i=0; i < REVERB_MAX_NUM_REFLECTIONS; i++) + { + pReverbData->m_sEarlyL.m_nGain[i] = 0; + pReverbData->m_sEarlyL.m_zDelay[i] = 0; + } + + // set the early reflections, R + pReverbData->m_sEarlyR.m_nLpfFbk = 4915; + pReverbData->m_sEarlyR.m_nLpfFwd = 27852; + pReverbData->m_sEarlyR.m_zLpf = 0; + + for (i=0; i < REVERB_MAX_NUM_REFLECTIONS; i++) + { + pReverbData->m_sEarlyR.m_nGain[i] = 0; + pReverbData->m_sEarlyR.m_zDelay[i] = 0; + } + + // clear the reverb delay line + for (i=0; i < REVERB_BUFFER_SIZE_IN_SAMPLES; i++) + { + pReverbData->m_nDelayLine[i] = 0; + } + + //////////////////////////////// + ///code from the EAS DEMO Reverb + //now copy from the new preset into the reverb + pPreset = &pReverbData->m_sPreset.m_sPreset[pReverbData->m_nNextRoom]; + + pReverbData->m_nLpfFbk = pPreset->m_nLpfFbk; + pReverbData->m_nLpfFwd = pPreset->m_nLpfFwd; + + pReverbData->m_nEarly = pPreset->m_nEarly; + pReverbData->m_nWet = pPreset->m_nWet; + pReverbData->m_nDry = pPreset->m_nDry; + + pReverbData->m_nMaxExcursion = pPreset->m_nMaxExcursion; + //stored as time based, convert to sample based + temp = pPreset->m_nXfadeInterval; + /*lint -e{702} shift for performance */ + temp = (temp * _OUTPUT_SAMPLE_RATE) >> 16; + pReverbData->m_nXfadeInterval = (EAS_U16) temp; + //gsReverbObject.m_nXfadeInterval = pPreset->m_nXfadeInterval; + + pReverbData->m_sAp0.m_nApGain = pPreset->m_nAp0_ApGain; + //stored as time based, convert to absolute sample value + temp = pPreset->m_nAp0_ApOut; + /*lint -e{702} shift for performance */ + temp = (temp * _OUTPUT_SAMPLE_RATE) >> 16; + pReverbData->m_sAp0.m_zApOut = (EAS_U16) (pReverbData->m_sAp0.m_zApIn + temp); + //gsReverbObject.m_sAp0.m_zApOut = pPreset->m_nAp0_ApOut; + + pReverbData->m_sAp1.m_nApGain = pPreset->m_nAp1_ApGain; + //stored as time based, convert to absolute sample value + temp = pPreset->m_nAp1_ApOut; + /*lint -e{702} shift for performance */ + temp = (temp * _OUTPUT_SAMPLE_RATE) >> 16; + pReverbData->m_sAp1.m_zApOut = (EAS_U16) (pReverbData->m_sAp1.m_zApIn + temp); + //gsReverbObject.m_sAp1.m_zApOut = pPreset->m_nAp1_ApOut; + ///code from the EAS DEMO Reverb + //////////////////////////////// + + *pInstData = pReverbData; + + return EAS_SUCCESS; + +} /* end InitializeReverb */ + + + +/*---------------------------------------------------------------------------- + * ReverbProcess() + *---------------------------------------------------------------------------- + * Purpose: + * Reverberate the requested number of samples (block based processing) + * + * Inputs: + * pInputBuffer - src buffer + * pOutputBuffer - dst buffer + * nNumSamplesToAdd - number of samples to write to buffer + * + * Outputs: + * number of samples actually written to buffer + * + * Side Effects: + * - samples are added to the presently free buffer + * + *---------------------------------------------------------------------------- +*/ +static void ReverbProcess(EAS_VOID_PTR pInstData, EAS_PCM *pSrc, EAS_PCM *pDst, EAS_I32 numSamples) +{ + S_REVERB_OBJECT *pReverbData; + + pReverbData = (S_REVERB_OBJECT*) pInstData; + + //if bypassed or the preset forces the signal to be completely dry + if (pReverbData->m_bBypass || + (pReverbData->m_nWet == 0 && pReverbData->m_nDry == 32767)) + { + if (pSrc != pDst) + EAS_HWMemCpy(pSrc, pDst, numSamples * NUM_OUTPUT_CHANNELS * (EAS_I32) sizeof(EAS_PCM)); + return; + } + + if (pReverbData->m_nNextRoom != pReverbData->m_nCurrentRoom) + { + ReverbUpdateRoom(pReverbData); + } + + ReverbUpdateXfade(pReverbData, numSamples); + + Reverb(pReverbData, numSamples, pDst, pSrc); + + /* check if update counter needs to be reset */ + if (pReverbData->m_nUpdateCounter >= REVERB_MODULO_UPDATE_PERIOD_IN_SAMPLES) + { + /* update interval has elapsed, so reset counter */ + pReverbData->m_nUpdateCounter = 0; + } /* end if m_nUpdateCounter >= update interval */ + + /* increment update counter */ + pReverbData->m_nUpdateCounter += (EAS_I16)numSamples; + +} /* end ComputeReverb */ + +/*---------------------------------------------------------------------------- + * ReverbUpdateXfade + *---------------------------------------------------------------------------- + * Purpose: + * Update the xfade parameters as required + * + * Inputs: + * nNumSamplesToAdd - number of samples to write to buffer + * + * Outputs: + * + * + * Side Effects: + * - xfade parameters will be changed + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ReverbUpdateXfade(S_REVERB_OBJECT *pReverbData, EAS_INT nNumSamplesToAdd) +{ + EAS_U16 nOffset; + EAS_I16 tempCos; + EAS_I16 tempSin; + + if (pReverbData->m_nXfadeCounter >= pReverbData->m_nXfadeInterval) + { + /* update interval has elapsed, so reset counter */ + pReverbData->m_nXfadeCounter = 0; + + // Pin the sin,cos values to min / max values to ensure that the + // modulated taps' coefs are zero (thus no clicks) + if (pReverbData->m_nPhaseIncrement > 0) + { + // if phase increment > 0, then sin -> 1, cos -> 0 + pReverbData->m_nSin = 32767; + pReverbData->m_nCos = 0; + + // reset the phase to match the sin, cos values + pReverbData->m_nPhase = 32767; + + // modulate the cross taps because their tap coefs are zero + nOffset = ReverbCalculateNoise( pReverbData->m_nMaxExcursion, &pReverbData->m_nNoise ); + + pReverbData->m_zD1Cross = + DELAY1_OUT - pReverbData->m_nMaxExcursion + nOffset; + + nOffset = ReverbCalculateNoise( pReverbData->m_nMaxExcursion, &pReverbData->m_nNoise ); + + pReverbData->m_zD0Cross = + DELAY0_OUT - pReverbData->m_nMaxExcursion - nOffset; + } + else + { + // if phase increment < 0, then sin -> 0, cos -> 1 + pReverbData->m_nSin = 0; + pReverbData->m_nCos = 32767; + + // reset the phase to match the sin, cos values + pReverbData->m_nPhase = -32768; + + // modulate the self taps because their tap coefs are zero + nOffset = ReverbCalculateNoise( pReverbData->m_nMaxExcursion, &pReverbData->m_nNoise ); + + pReverbData->m_zD0Self = + DELAY0_OUT - pReverbData->m_nMaxExcursion - nOffset; + + nOffset = ReverbCalculateNoise( pReverbData->m_nMaxExcursion, &pReverbData->m_nNoise ); + + pReverbData->m_zD1Self = + DELAY1_OUT - pReverbData->m_nMaxExcursion + nOffset; + + } // end if-else (pReverbData->m_nPhaseIncrement > 0) + + // Reverse the direction of the sin,cos so that the + // tap whose coef was previously increasing now decreases + // and vice versa + pReverbData->m_nPhaseIncrement = -pReverbData->m_nPhaseIncrement; + + } // end if counter >= update interval + + //compute what phase will be next time + pReverbData->m_nPhase += pReverbData->m_nPhaseIncrement; + + //calculate what the new sin and cos need to reach by the next update + ReverbCalculateSinCos(pReverbData->m_nPhase, &tempSin, &tempCos); + + //calculate the per-sample increment required to get there by the next update + /*lint -e{702} shift for performance */ + pReverbData->m_nSinIncrement = + (tempSin - pReverbData->m_nSin) >> REVERB_UPDATE_PERIOD_IN_BITS; + + /*lint -e{702} shift for performance */ + pReverbData->m_nCosIncrement = + (tempCos - pReverbData->m_nCos) >> REVERB_UPDATE_PERIOD_IN_BITS; + + + /* increment update counter */ + pReverbData->m_nXfadeCounter += (EAS_U16) nNumSamplesToAdd; + + return EAS_SUCCESS; + +} /* end ReverbUpdateXfade */ + + +/*---------------------------------------------------------------------------- + * ReverbCalculateNoise + *---------------------------------------------------------------------------- + * Purpose: + * Calculate a noise sample and limit its value + * + * Inputs: + * nMaxExcursion - noise value is limited to this value + * pnNoise - return new noise sample in this (not limited) + * + * Outputs: + * new limited noise value + * + * Side Effects: + * - *pnNoise noise value is updated + * + *---------------------------------------------------------------------------- +*/ +static EAS_U16 ReverbCalculateNoise(EAS_U16 nMaxExcursion, EAS_I16 *pnNoise) +{ + // calculate new noise value + *pnNoise = (EAS_I16) (*pnNoise * 5 + 1); + +#if 0 // 1xxx, test + *pnNoise = 0; +#endif // 1xxx, test + + // return the limited noise value + return (nMaxExcursion & (*pnNoise)); + +} /* end ReverbCalculateNoise */ + +/*---------------------------------------------------------------------------- + * ReverbCalculateSinCos + *---------------------------------------------------------------------------- + * Purpose: + * Calculate a new sin and cosine value based on the given phase + * + * Inputs: + * nPhase - phase angle + * pnSin - input old value, output new value + * pnCos - input old value, output new value + * + * Outputs: + * + * Side Effects: + * - *pnSin, *pnCos are updated + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ReverbCalculateSinCos(EAS_I16 nPhase, EAS_I16 *pnSin, EAS_I16 *pnCos) +{ + EAS_I32 nTemp; + EAS_I32 nNetAngle; + + // -1 <= nPhase < 1 + // However, for the calculation, we need a value + // that ranges from -1/2 to +1/2, so divide the phase by 2 + /*lint -e{702} shift for performance */ + nNetAngle = nPhase >> 1; + + /* + Implement the following + sin(x) = (2-4*c)*x^2 + c + x + cos(x) = (2-4*c)*x^2 + c - x + + where c = 1/sqrt(2) + using the a0 + x*(a1 + x*a2) approach + */ + + /* limit the input "angle" to be between -0.5 and +0.5 */ + if (nNetAngle > EG1_HALF) + { + nNetAngle = EG1_HALF; + } + else if (nNetAngle < EG1_MINUS_HALF) + { + nNetAngle = EG1_MINUS_HALF; + } + + /* calculate sin */ + nTemp = EG1_ONE + MULT_EG1_EG1(REVERB_PAN_G2, nNetAngle); + nTemp = REVERB_PAN_G0 + MULT_EG1_EG1(nTemp, nNetAngle); + *pnSin = (EAS_I16) SATURATE_EG1(nTemp); + + /* calculate cos */ + nTemp = -EG1_ONE + MULT_EG1_EG1(REVERB_PAN_G2, nNetAngle); + nTemp = REVERB_PAN_G0 + MULT_EG1_EG1(nTemp, nNetAngle); + *pnCos = (EAS_I16) SATURATE_EG1(nTemp); + + return EAS_SUCCESS; +} /* end ReverbCalculateSinCos */ + +/*---------------------------------------------------------------------------- + * Reverb + *---------------------------------------------------------------------------- + * Purpose: + * apply reverb to the given signal + * + * Inputs: + * nNu + * pnSin - input old value, output new value + * pnCos - input old value, output new value + * + * Outputs: + * number of samples actually reverberated + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT Reverb(S_REVERB_OBJECT *pReverbData, EAS_INT nNumSamplesToAdd, EAS_PCM *pOutputBuffer, EAS_PCM *pInputBuffer) +{ + EAS_I32 i; + EAS_I32 nDelayOut; + EAS_U16 nBase; + + EAS_U32 nAddr; + EAS_I32 nTemp1; + EAS_I32 nTemp2; + EAS_I32 nApIn; + EAS_I32 nApOut; + + EAS_I32 j; + EAS_I32 nEarlyOut; + + EAS_I32 tempValue; + + + // get the base address + nBase = pReverbData->m_nBaseIndex; + + for (i=0; i < nNumSamplesToAdd; i++) + { + // ********** Left Allpass - start + // left input = (left dry/4) + right feedback from previous period + /*lint -e{702} use shift for performance */ + nApIn = ((*pInputBuffer++)>>2) + pReverbData->m_nRevOutFbkR; +// nApIn = *pInputBuffer++; // 1xxx test and debug ap + + // fetch allpass delay line out + //nAddr = CIRCULAR(nBase, psAp0->m_zApOut, REVERB_BUFFER_MASK); + nAddr = CIRCULAR(nBase, pReverbData->m_sAp0.m_zApOut, REVERB_BUFFER_MASK); + nDelayOut = pReverbData->m_nDelayLine[nAddr]; + + // calculate allpass feedforward; subtract the feedforward result + nTemp1 = MULT_EG1_EG1(nApIn, pReverbData->m_sAp0.m_nApGain); + nApOut = SATURATE(nDelayOut - nTemp1); // allpass output + + // calculate allpass feedback; add the feedback result + nTemp1 = MULT_EG1_EG1(nApOut, pReverbData->m_sAp0.m_nApGain); + nTemp1 = SATURATE(nApIn + nTemp1); + + // inject into allpass delay + nAddr = CIRCULAR(nBase, pReverbData->m_sAp0.m_zApIn, REVERB_BUFFER_MASK); + pReverbData->m_nDelayLine[nAddr] = (EAS_PCM) nTemp1; + + // inject allpass output into delay line + nAddr = CIRCULAR(nBase, pReverbData->m_zD0In, REVERB_BUFFER_MASK); + pReverbData->m_nDelayLine[nAddr] = (EAS_PCM) nApOut; + + // ********** Left Allpass - end + + // ********** Right Allpass - start + // right input = (right dry/4) + left feedback from previous period + /*lint -e{702} use shift for performance */ + nApIn = ((*pInputBuffer++)>>2) + pReverbData->m_nRevOutFbkL; +// nApIn = *pInputBuffer++; // 1xxx test and debug ap + + // fetch allpass delay line out + nAddr = CIRCULAR(nBase, pReverbData->m_sAp1.m_zApOut, REVERB_BUFFER_MASK); + nDelayOut = pReverbData->m_nDelayLine[nAddr]; + + // calculate allpass feedforward; subtract the feedforward result + nTemp1 = MULT_EG1_EG1(nApIn, pReverbData->m_sAp1.m_nApGain); + nApOut = SATURATE(nDelayOut - nTemp1); // allpass output + + // calculate allpass feedback; add the feedback result + nTemp1 = MULT_EG1_EG1(nApOut, pReverbData->m_sAp1.m_nApGain); + nTemp1 = SATURATE(nApIn + nTemp1); + + // inject into allpass delay + nAddr = CIRCULAR(nBase, pReverbData->m_sAp1.m_zApIn, REVERB_BUFFER_MASK); + pReverbData->m_nDelayLine[nAddr] = (EAS_PCM) nTemp1; + + // inject allpass output into delay line + nAddr = CIRCULAR(nBase, pReverbData->m_zD1In, REVERB_BUFFER_MASK); + pReverbData->m_nDelayLine[nAddr] = (EAS_PCM) nApOut; + + // ********** Right Allpass - end + + // ********** D0 output - start + // fetch delay line self out + nAddr = CIRCULAR(nBase, pReverbData->m_zD0Self, REVERB_BUFFER_MASK); + nDelayOut = pReverbData->m_nDelayLine[nAddr]; + + // calculate delay line self out + nTemp1 = MULT_EG1_EG1(nDelayOut, pReverbData->m_nSin); + + // fetch delay line cross out + nAddr = CIRCULAR(nBase, pReverbData->m_zD1Cross, REVERB_BUFFER_MASK); + nDelayOut = pReverbData->m_nDelayLine[nAddr]; + + // calculate delay line self out + nTemp2 = MULT_EG1_EG1(nDelayOut, pReverbData->m_nCos); + + // calculate unfiltered delay out + nDelayOut = SATURATE(nTemp1 + nTemp2); + + // calculate lowpass filter (mixer scale factor included in LPF feedforward) + nTemp1 = MULT_EG1_EG1(nDelayOut, pReverbData->m_nLpfFwd); + + nTemp2 = MULT_EG1_EG1(pReverbData->m_zLpf0, pReverbData->m_nLpfFbk); + + // calculate filtered delay out and simultaneously update LPF state variable + // filtered delay output is stored in m_zLpf0 + pReverbData->m_zLpf0 = (EAS_PCM) SATURATE(nTemp1 + nTemp2); + + // ********** D0 output - end + + // ********** D1 output - start + // fetch delay line self out + nAddr = CIRCULAR(nBase, pReverbData->m_zD1Self, REVERB_BUFFER_MASK); + nDelayOut = pReverbData->m_nDelayLine[nAddr]; + + // calculate delay line self out + nTemp1 = MULT_EG1_EG1(nDelayOut, pReverbData->m_nSin); + + // fetch delay line cross out + nAddr = CIRCULAR(nBase, pReverbData->m_zD0Cross, REVERB_BUFFER_MASK); + nDelayOut = pReverbData->m_nDelayLine[nAddr]; + + // calculate delay line self out + nTemp2 = MULT_EG1_EG1(nDelayOut, pReverbData->m_nCos); + + // calculate unfiltered delay out + nDelayOut = SATURATE(nTemp1 + nTemp2); + + // calculate lowpass filter (mixer scale factor included in LPF feedforward) + nTemp1 = MULT_EG1_EG1(nDelayOut, pReverbData->m_nLpfFwd); + + nTemp2 = MULT_EG1_EG1(pReverbData->m_zLpf1, pReverbData->m_nLpfFbk); + + // calculate filtered delay out and simultaneously update LPF state variable + // filtered delay output is stored in m_zLpf1 + pReverbData->m_zLpf1 = (EAS_PCM)SATURATE(nTemp1 + nTemp2); + + // ********** D1 output - end + + // ********** mixer and feedback - start + // sum is fedback to right input (R + L) + pReverbData->m_nRevOutFbkL = + (EAS_PCM)SATURATE((EAS_I32)pReverbData->m_zLpf1 + (EAS_I32)pReverbData->m_zLpf0); + + // difference is feedback to left input (R - L) + /*lint -e{685} lint complains that it can't saturate negative */ + pReverbData->m_nRevOutFbkR = + (EAS_PCM)SATURATE((EAS_I32)pReverbData->m_zLpf1 - (EAS_I32)pReverbData->m_zLpf0); + + // ********** mixer and feedback - end + + // ********** start early reflection generator, left + //psEarly = &(pReverbData->m_sEarlyL); + + nEarlyOut = 0; + + for (j=0; j < REVERB_MAX_NUM_REFLECTIONS; j++) + { + // fetch delay line out + //nAddr = CIRCULAR(nBase, psEarly->m_zDelay[j], REVERB_BUFFER_MASK); + nAddr = CIRCULAR(nBase, pReverbData->m_sEarlyL.m_zDelay[j], REVERB_BUFFER_MASK); + + nDelayOut = pReverbData->m_nDelayLine[nAddr]; + + // calculate reflection + //nTemp1 = MULT_EG1_EG1(nDelayOut, psEarly->m_nGain[j]); + nTemp1 = MULT_EG1_EG1(nDelayOut, pReverbData->m_sEarlyL.m_nGain[j]); + + nEarlyOut = SATURATE(nEarlyOut + nTemp1); + + } // end for (j=0; j < REVERB_MAX_NUM_REFLECTIONS; j++) + + // apply lowpass to early reflections + //nTemp1 = MULT_EG1_EG1(nEarlyOut, psEarly->m_nLpfFwd); + nTemp1 = MULT_EG1_EG1(nEarlyOut, pReverbData->m_sEarlyL.m_nLpfFwd); + + //nTemp2 = MULT_EG1_EG1(psEarly->m_zLpf, psEarly->m_nLpfFbk); + nTemp2 = MULT_EG1_EG1(pReverbData->m_sEarlyL.m_zLpf, pReverbData->m_sEarlyL.m_nLpfFbk); + + + // calculate filtered out and simultaneously update LPF state variable + // filtered output is stored in m_zLpf1 + //psEarly->m_zLpf = SATURATE(nTemp1 + nTemp2); + pReverbData->m_sEarlyL.m_zLpf = (EAS_PCM) SATURATE(nTemp1 + nTemp2); + + // combine filtered early and late reflections for output + //*pOutputBuffer++ = inL; + //tempValue = SATURATE(psEarly->m_zLpf + pReverbData->m_nRevOutFbkL); + tempValue = SATURATE((EAS_I32)pReverbData->m_sEarlyL.m_zLpf + (EAS_I32)pReverbData->m_nRevOutFbkL); + //scale reverb output by wet level + /*lint -e{701} use shift for performance */ + tempValue = MULT_EG1_EG1(tempValue, (pReverbData->m_nWet<<1)); + //sum with output buffer + tempValue += *pOutputBuffer; + *pOutputBuffer++ = (EAS_PCM)SATURATE(tempValue); + + // ********** end early reflection generator, left + + // ********** start early reflection generator, right + //psEarly = &(pReverbData->m_sEarlyR); + + nEarlyOut = 0; + + for (j=0; j < REVERB_MAX_NUM_REFLECTIONS; j++) + { + // fetch delay line out + nAddr = CIRCULAR(nBase, pReverbData->m_sEarlyR.m_zDelay[j], REVERB_BUFFER_MASK); + nDelayOut = pReverbData->m_nDelayLine[nAddr]; + + // calculate reflection + nTemp1 = MULT_EG1_EG1(nDelayOut, pReverbData->m_sEarlyR.m_nGain[j]); + + nEarlyOut = SATURATE(nEarlyOut + nTemp1); + + } // end for (j=0; j < REVERB_MAX_NUM_REFLECTIONS; j++) + + // apply lowpass to early reflections + nTemp1 = MULT_EG1_EG1(nEarlyOut, pReverbData->m_sEarlyR.m_nLpfFwd); + + nTemp2 = MULT_EG1_EG1(pReverbData->m_sEarlyR.m_zLpf, pReverbData->m_sEarlyR.m_nLpfFbk); + + // calculate filtered out and simultaneously update LPF state variable + // filtered output is stored in m_zLpf1 + pReverbData->m_sEarlyR.m_zLpf = (EAS_PCM)SATURATE(nTemp1 + nTemp2); + + // combine filtered early and late reflections for output + //*pOutputBuffer++ = inR; + tempValue = SATURATE((EAS_I32)pReverbData->m_sEarlyR.m_zLpf + (EAS_I32)pReverbData->m_nRevOutFbkR); + //scale reverb output by wet level + /*lint -e{701} use shift for performance */ + tempValue = MULT_EG1_EG1(tempValue, (pReverbData->m_nWet << 1)); + //sum with output buffer + tempValue = tempValue + *pOutputBuffer; + *pOutputBuffer++ = (EAS_PCM)SATURATE(tempValue); + + // ********** end early reflection generator, right + + // decrement base addr for next sample period + nBase--; + + pReverbData->m_nSin += pReverbData->m_nSinIncrement; + pReverbData->m_nCos += pReverbData->m_nCosIncrement; + + } // end for (i=0; i < nNumSamplesToAdd; i++) + + // store the most up to date version + pReverbData->m_nBaseIndex = nBase; + + return EAS_SUCCESS; +} /* end Reverb */ + + + +/*---------------------------------------------------------------------------- + * ReverbShutdown() + *---------------------------------------------------------------------------- + * Purpose: + * Initializes the Reverb effect. + * + * Inputs: + * pInstData - handle to instance data + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ReverbShutdown (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR pInstData) +{ + /* check Configuration Module for static memory allocation */ + if (!pEASData->staticMemoryModel) + EAS_HWFree(pEASData->hwInstData, pInstData); + return EAS_SUCCESS; +} /* end ReverbShutdown */ + +/*---------------------------------------------------------------------------- + * ReverbGetParam() + *---------------------------------------------------------------------------- + * Purpose: + * Get a Reverb parameter + * + * Inputs: + * pInstData - handle to instance data + * param - parameter index + * *pValue - pointer to variable to hold retrieved value + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ReverbGetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue) +{ + S_REVERB_OBJECT *p; + + p = (S_REVERB_OBJECT*) pInstData; + + switch (param) + { + case EAS_PARAM_REVERB_BYPASS: + *pValue = (EAS_I32) p->m_bBypass; + break; + case EAS_PARAM_REVERB_PRESET: + *pValue = (EAS_I8) p->m_nCurrentRoom; + break; + case EAS_PARAM_REVERB_WET: + *pValue = p->m_nWet; + break; + case EAS_PARAM_REVERB_DRY: + *pValue = p->m_nDry; + break; + default: + return EAS_ERROR_INVALID_PARAMETER; + } + return EAS_SUCCESS; +} /* end ReverbGetParam */ + + +/*---------------------------------------------------------------------------- + * ReverbSetParam() + *---------------------------------------------------------------------------- + * Purpose: + * Set a Reverb parameter + * + * Inputs: + * pInstData - handle to instance data + * param - parameter index + * *pValue - new paramter value + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ReverbSetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value) +{ + S_REVERB_OBJECT *p; + + p = (S_REVERB_OBJECT*) pInstData; + + switch (param) + { + case EAS_PARAM_REVERB_BYPASS: + p->m_bBypass = (EAS_BOOL) value; + break; + case EAS_PARAM_REVERB_PRESET: + if(value!=EAS_PARAM_REVERB_LARGE_HALL && value!=EAS_PARAM_REVERB_HALL && + value!=EAS_PARAM_REVERB_CHAMBER && value!=EAS_PARAM_REVERB_ROOM) + return EAS_ERROR_INVALID_PARAMETER; + p->m_nNextRoom = (EAS_I16)value; + break; + case EAS_PARAM_REVERB_WET: + if(value>EAS_REVERB_WET_MAX || valuem_nWet = (EAS_I16)value; + break; + case EAS_PARAM_REVERB_DRY: + if(value>EAS_REVERB_DRY_MAX || valuem_nDry = (EAS_I16)value; + break; + default: + return EAS_ERROR_INVALID_PARAMETER; + } + return EAS_SUCCESS; +} /* end ReverbSetParam */ + + +/*---------------------------------------------------------------------------- + * ReverbUpdateRoom + *---------------------------------------------------------------------------- + * Purpose: + * Update the room's preset parameters as required + * + * Inputs: + * + * Outputs: + * + * + * Side Effects: + * - reverb paramters (fbk, fwd, etc) will be changed + * - m_nCurrentRoom := m_nNextRoom + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ReverbUpdateRoom(S_REVERB_OBJECT *pReverbData) +{ + EAS_INT temp; + + S_REVERB_PRESET *pPreset = &pReverbData->m_sPreset.m_sPreset[pReverbData->m_nNextRoom]; + + pReverbData->m_nLpfFwd = pPreset->m_nLpfFwd; + pReverbData->m_nLpfFbk = pPreset->m_nLpfFbk; + + pReverbData->m_nEarly = pPreset->m_nEarly; + pReverbData->m_nWet = pPreset->m_nWet; + pReverbData->m_nDry = pPreset->m_nDry; + + + pReverbData->m_nMaxExcursion = pPreset->m_nMaxExcursion; + //stored as time based, convert to sample based + temp = pPreset->m_nXfadeInterval; + /*lint -e{702} shift for performance */ + temp = (temp * _OUTPUT_SAMPLE_RATE) >> 16; + pReverbData->m_nXfadeInterval = (EAS_U16) temp; + //gpsReverbObject->m_nXfadeInterval = pPreset->m_nXfadeInterval; + pReverbData->m_sAp0.m_nApGain = pPreset->m_nAp0_ApGain; + //stored as time based, convert to absolute sample value + temp = pPreset->m_nAp0_ApOut; + /*lint -e{702} shift for performance */ + temp = (temp * _OUTPUT_SAMPLE_RATE) >> 16; + pReverbData->m_sAp0.m_zApOut = (EAS_U16) (pReverbData->m_sAp0.m_zApIn + temp); + //gpsReverbObject->m_sAp0.m_zApOut = pPreset->m_nAp0_ApOut; + pReverbData->m_sAp1.m_nApGain = pPreset->m_nAp1_ApGain; + //stored as time based, convert to absolute sample value + temp = pPreset->m_nAp1_ApOut; + /*lint -e{702} shift for performance */ + temp = (temp * _OUTPUT_SAMPLE_RATE) >> 16; + pReverbData->m_sAp1.m_zApOut = (EAS_U16) (pReverbData->m_sAp1.m_zApIn + temp); + //gpsReverbObject->m_sAp1.m_zApOut = pPreset->m_nAp1_ApOut; + + pReverbData->m_nCurrentRoom = pReverbData->m_nNextRoom; + + return EAS_SUCCESS; + +} /* end ReverbUpdateRoom */ + + +/*---------------------------------------------------------------------------- + * ReverbReadInPresets() + *---------------------------------------------------------------------------- + * Purpose: sets global reverb preset bank to defaults + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ReverbReadInPresets(S_REVERB_OBJECT *pReverbData) +{ + + int preset = 0; + int defaultPreset = 0; + + //now init any remaining presets to defaults + for (defaultPreset = preset; defaultPreset < REVERB_MAX_ROOM_TYPE; defaultPreset++) + { + S_REVERB_PRESET *pPreset = &pReverbData->m_sPreset.m_sPreset[defaultPreset]; + if (defaultPreset == 0 || defaultPreset > REVERB_MAX_ROOM_TYPE-1) + { + pPreset->m_nLpfFbk = 8307; + pPreset->m_nLpfFwd = 14768; + pPreset->m_nEarly = 0; + pPreset->m_nWet = 27690; + pPreset->m_nDry = 32767; + pPreset->m_nEarlyL_LpfFbk = 3692; + pPreset->m_nEarlyL_LpfFwd = 29075; + pPreset->m_nEarlyL_Delay0 = 922; + pPreset->m_nEarlyL_Gain0 = 22152; + pPreset->m_nEarlyL_Delay1 = 1462; + pPreset->m_nEarlyL_Gain1 = 17537; + pPreset->m_nEarlyL_Delay2 = 0; + pPreset->m_nEarlyL_Gain2 = 14768; + pPreset->m_nEarlyL_Delay3 = 1221; + pPreset->m_nEarlyL_Gain3 = 14307; + pPreset->m_nEarlyL_Delay4 = 0; + pPreset->m_nEarlyL_Gain4 = 13384; + pPreset->m_nEarlyR_Delay0 = 502; + pPreset->m_nEarlyR_Gain0 = 20306; + pPreset->m_nEarlyR_Delay1 = 1762; + pPreset->m_nEarlyR_Gain1 = 17537; + pPreset->m_nEarlyR_Delay2 = 0; + pPreset->m_nEarlyR_Gain2 = 14768; + pPreset->m_nEarlyR_Delay3 = 0; + pPreset->m_nEarlyR_Gain3 = 16153; + pPreset->m_nEarlyR_Delay4 = 0; + pPreset->m_nEarlyR_Gain4 = 13384; + pPreset->m_nMaxExcursion = 127; + pPreset->m_nXfadeInterval = 6388; + pPreset->m_nAp0_ApGain = 15691; + pPreset->m_nAp0_ApOut = 711; + pPreset->m_nAp1_ApGain = 17999; + pPreset->m_nAp1_ApOut = 1113; + pPreset->m_rfu4 = 0; + pPreset->m_rfu5 = 0; + pPreset->m_rfu6 = 0; + pPreset->m_rfu7 = 0; + pPreset->m_rfu8 = 0; + pPreset->m_rfu9 = 0; + pPreset->m_rfu10 = 0; + } + else if (defaultPreset == 1) + { + pPreset->m_nLpfFbk = 6461; + pPreset->m_nLpfFwd = 14307; + pPreset->m_nEarly = 0; + pPreset->m_nWet = 27690; + pPreset->m_nDry = 32767; + pPreset->m_nEarlyL_LpfFbk = 3692; + pPreset->m_nEarlyL_LpfFwd = 29075; + pPreset->m_nEarlyL_Delay0 = 922; + pPreset->m_nEarlyL_Gain0 = 22152; + pPreset->m_nEarlyL_Delay1 = 1462; + pPreset->m_nEarlyL_Gain1 = 17537; + pPreset->m_nEarlyL_Delay2 = 0; + pPreset->m_nEarlyL_Gain2 = 14768; + pPreset->m_nEarlyL_Delay3 = 1221; + pPreset->m_nEarlyL_Gain3 = 14307; + pPreset->m_nEarlyL_Delay4 = 0; + pPreset->m_nEarlyL_Gain4 = 13384; + pPreset->m_nEarlyR_Delay0 = 502; + pPreset->m_nEarlyR_Gain0 = 20306; + pPreset->m_nEarlyR_Delay1 = 1762; + pPreset->m_nEarlyR_Gain1 = 17537; + pPreset->m_nEarlyR_Delay2 = 0; + pPreset->m_nEarlyR_Gain2 = 14768; + pPreset->m_nEarlyR_Delay3 = 0; + pPreset->m_nEarlyR_Gain3 = 16153; + pPreset->m_nEarlyR_Delay4 = 0; + pPreset->m_nEarlyR_Gain4 = 13384; + pPreset->m_nMaxExcursion = 127; + pPreset->m_nXfadeInterval = 6391; + pPreset->m_nAp0_ApGain = 15230; + pPreset->m_nAp0_ApOut = 708; + pPreset->m_nAp1_ApGain = 9692; + pPreset->m_nAp1_ApOut = 1113; + pPreset->m_rfu4 = 0; + pPreset->m_rfu5 = 0; + pPreset->m_rfu6 = 0; + pPreset->m_rfu7 = 0; + pPreset->m_rfu8 = 0; + pPreset->m_rfu9 = 0; + pPreset->m_rfu10 = 0; + } + else if (defaultPreset == 2) + { + pPreset->m_nLpfFbk = 5077; + pPreset->m_nLpfFwd = 12922; + pPreset->m_nEarly = 0; + pPreset->m_nWet = 24460; + pPreset->m_nDry = 32767; + pPreset->m_nEarlyL_LpfFbk = 3692; + pPreset->m_nEarlyL_LpfFwd = 29075; + pPreset->m_nEarlyL_Delay0 = 922; + pPreset->m_nEarlyL_Gain0 = 22152; + pPreset->m_nEarlyL_Delay1 = 1462; + pPreset->m_nEarlyL_Gain1 = 17537; + pPreset->m_nEarlyL_Delay2 = 0; + pPreset->m_nEarlyL_Gain2 = 14768; + pPreset->m_nEarlyL_Delay3 = 1221; + pPreset->m_nEarlyL_Gain3 = 14307; + pPreset->m_nEarlyL_Delay4 = 0; + pPreset->m_nEarlyL_Gain4 = 13384; + pPreset->m_nEarlyR_Delay0 = 502; + pPreset->m_nEarlyR_Gain0 = 20306; + pPreset->m_nEarlyR_Delay1 = 1762; + pPreset->m_nEarlyR_Gain1 = 17537; + pPreset->m_nEarlyR_Delay2 = 0; + pPreset->m_nEarlyR_Gain2 = 14768; + pPreset->m_nEarlyR_Delay3 = 0; + pPreset->m_nEarlyR_Gain3 = 16153; + pPreset->m_nEarlyR_Delay4 = 0; + pPreset->m_nEarlyR_Gain4 = 13384; + pPreset->m_nMaxExcursion = 127; + pPreset->m_nXfadeInterval = 6449; + pPreset->m_nAp0_ApGain = 15691; + pPreset->m_nAp0_ApOut = 774; + pPreset->m_nAp1_ApGain = 15691; + pPreset->m_nAp1_ApOut = 1113; + pPreset->m_rfu4 = 0; + pPreset->m_rfu5 = 0; + pPreset->m_rfu6 = 0; + pPreset->m_rfu7 = 0; + pPreset->m_rfu8 = 0; + pPreset->m_rfu9 = 0; + pPreset->m_rfu10 = 0; + } + else if (defaultPreset == 3) + { + pPreset->m_nLpfFbk = 5077; + pPreset->m_nLpfFwd = 11076; + pPreset->m_nEarly = 0; + pPreset->m_nWet = 23075; + pPreset->m_nDry = 32767; + pPreset->m_nEarlyL_LpfFbk = 3692; + pPreset->m_nEarlyL_LpfFwd = 29075; + pPreset->m_nEarlyL_Delay0 = 922; + pPreset->m_nEarlyL_Gain0 = 22152; + pPreset->m_nEarlyL_Delay1 = 1462; + pPreset->m_nEarlyL_Gain1 = 17537; + pPreset->m_nEarlyL_Delay2 = 0; + pPreset->m_nEarlyL_Gain2 = 14768; + pPreset->m_nEarlyL_Delay3 = 1221; + pPreset->m_nEarlyL_Gain3 = 14307; + pPreset->m_nEarlyL_Delay4 = 0; + pPreset->m_nEarlyL_Gain4 = 13384; + pPreset->m_nEarlyR_Delay0 = 502; + pPreset->m_nEarlyR_Gain0 = 20306; + pPreset->m_nEarlyR_Delay1 = 1762; + pPreset->m_nEarlyR_Gain1 = 17537; + pPreset->m_nEarlyR_Delay2 = 0; + pPreset->m_nEarlyR_Gain2 = 14768; + pPreset->m_nEarlyR_Delay3 = 0; + pPreset->m_nEarlyR_Gain3 = 16153; + pPreset->m_nEarlyR_Delay4 = 0; + pPreset->m_nEarlyR_Gain4 = 13384; + pPreset->m_nMaxExcursion = 127; + pPreset->m_nXfadeInterval = 6470; //6483; + pPreset->m_nAp0_ApGain = 14768; + pPreset->m_nAp0_ApOut = 792; + pPreset->m_nAp1_ApGain = 15783; + pPreset->m_nAp1_ApOut = 1113; + pPreset->m_rfu4 = 0; + pPreset->m_rfu5 = 0; + pPreset->m_rfu6 = 0; + pPreset->m_rfu7 = 0; + pPreset->m_rfu8 = 0; + pPreset->m_rfu9 = 0; + pPreset->m_rfu10 = 0; + + } + } + + return EAS_SUCCESS; +} diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_reverbdata.c b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_reverbdata.c new file mode 100755 index 0000000..db34b48 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_reverbdata.c @@ -0,0 +1,34 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_reverbdata.c + * + * Contents and purpose: + * Contains the static data allocation for the Reverb effect + * + * + * Copyright Sonic Network Inc. 2006 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 550 $ + * $Date: 2007-02-02 09:37:03 -0800 (Fri, 02 Feb 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_reverbdata.h" + +S_REVERB_OBJECT eas_ReverbData; + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_reverbdata.h b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_reverbdata.h new file mode 100755 index 0000000..926ea2e --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_reverbdata.h @@ -0,0 +1,486 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_reverbdata.h + * + * Contents and purpose: + * Contains the prototypes for the Reverb effect. + * + * + * Copyright Sonic Network Inc. 2006 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 499 $ + * $Date: 2006-12-11 16:07:20 -0800 (Mon, 11 Dec 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_REVERBDATA_H +#define _EAS_REVERBDATA_H + +#include "eas_types.h" +#include "eas_audioconst.h" + +/*------------------------------------ + * defines + *------------------------------------ +*/ + +/* +CIRCULAR() calculates the array index using modulo arithmetic. +The "trick" is that modulo arithmetic is simplified by masking +the effective address where the mask is (2^n)-1. This only works +if the buffer size is a power of two. +*/ +#define CIRCULAR(base,offset,size) (EAS_U32)( \ + ( \ + ((EAS_I32)(base)) + ((EAS_I32)(offset)) \ + ) \ + & size \ + ) + +/* reverb parameters are updated every 2^(REVERB_UPDATE_PERIOD_IN_BITS) samples */ +#if defined (_SAMPLE_RATE_8000) + +#define REVERB_UPDATE_PERIOD_IN_BITS 5 +#define REVERB_BUFFER_SIZE_IN_SAMPLES 2048 + +#elif defined (_SAMPLE_RATE_16000) + +#define REVERB_UPDATE_PERIOD_IN_BITS 6 +#define REVERB_BUFFER_SIZE_IN_SAMPLES 4096 + +#elif defined (_SAMPLE_RATE_22050) + +#define REVERB_UPDATE_PERIOD_IN_BITS 7 +#define REVERB_BUFFER_SIZE_IN_SAMPLES 4096 + +#elif defined (_SAMPLE_RATE_32000) + +#define REVERB_UPDATE_PERIOD_IN_BITS 7 +#define REVERB_BUFFER_SIZE_IN_SAMPLES 8192 + +#elif defined (_SAMPLE_RATE_44100) + +#define REVERB_UPDATE_PERIOD_IN_BITS 8 +#define REVERB_BUFFER_SIZE_IN_SAMPLES 8192 + +#elif defined (_SAMPLE_RATE_48000) + +#define REVERB_UPDATE_PERIOD_IN_BITS 8 +#define REVERB_BUFFER_SIZE_IN_SAMPLES 8192 + +#endif + +// Define a mask for circular addressing, so that array index +// can wraparound and stay in array boundary of 0, 1, ..., (buffer size -1) +// The buffer size MUST be a power of two +#define REVERB_BUFFER_MASK (REVERB_BUFFER_SIZE_IN_SAMPLES -1) + +#define REVERB_MAX_ROOM_TYPE 4 // any room numbers larger than this are invalid +#define REVERB_MAX_NUM_REFLECTIONS 5 // max num reflections per channel + +/* synth parameters are updated every SYNTH_UPDATE_PERIOD_IN_SAMPLES */ +#define REVERB_UPDATE_PERIOD_IN_SAMPLES (EAS_I32)(0x1L << REVERB_UPDATE_PERIOD_IN_BITS) + +/* +calculate the update counter by bitwise ANDING with this value to +generate a 2^n modulo value +*/ +#define REVERB_MODULO_UPDATE_PERIOD_IN_SAMPLES (EAS_I32)(REVERB_UPDATE_PERIOD_IN_SAMPLES -1) + +/* synth parameters are updated every SYNTH_UPDATE_PERIOD_IN_SECONDS seconds */ +#define REVERB_UPDATE_PERIOD_IN_SECONDS (REVERB_UPDATE_PERIOD_IN_SAMPLES / _OUTPUT_SAMPLE_RATE) + +// xfade parameters +#define REVERB_XFADE_PERIOD_IN_SECONDS (100.0 / 1000.0) // xfade once every this many seconds + +#define REVERB_XFADE_PERIOD_IN_SAMPLES (REVERB_XFADE_PERIOD_IN_SECONDS * _OUTPUT_SAMPLE_RATE) + +#define REVERB_XFADE_PHASE_INCREMENT (EAS_I16)(65536 / ((EAS_I16)REVERB_XFADE_PERIOD_IN_SAMPLES/(EAS_I16)REVERB_UPDATE_PERIOD_IN_SAMPLES)) + +/**********/ +/* the entire synth uses various flags in a bit field */ + +/* if flag is set, synth reset has been requested */ +#define REVERB_FLAG_RESET_IS_REQUESTED 0x01 /* bit 0 */ +#define MASK_REVERB_RESET_IS_REQUESTED 0x01 +#define MASK_REVERB_RESET_IS_NOT_REQUESTED (EAS_U32)(~MASK_REVERB_RESET_IS_REQUESTED) + +/* +by default, we always want to update ALL channel parameters +when we reset the synth (e.g., during GM ON) +*/ +#define DEFAULT_REVERB_FLAGS 0x0 + +/* coefficients for generating sin, cos */ +#define REVERB_PAN_G2 4294940151 /* -0.82842712474619 = 2 - 4/sqrt(2) */ +/* +EAS_I32 nPanG1 = +1.0 for sin +EAS_I32 nPanG1 = -1.0 for cos +*/ +#define REVERB_PAN_G0 23170 /* 0.707106781186547 = 1/sqrt(2) */ + +/*************************************************************/ +// define the input injection points +#define GUARD 5 // safety guard of this many samples + +#define MAX_AP_TIME (double) (20.0/1000.0) // delay time in milliseconds +#define MAX_DELAY_TIME (double) (65.0/1000.0) // delay time in milliseconds + +#define MAX_AP_SAMPLES (int)(((double) MAX_AP_TIME) * ((double) _OUTPUT_SAMPLE_RATE)) +#define MAX_DELAY_SAMPLES (int)(((double) MAX_DELAY_TIME) * ((double) _OUTPUT_SAMPLE_RATE)) + +#define AP0_IN 0 +#define AP1_IN (AP0_IN + MAX_AP_SAMPLES + GUARD) +#define DELAY0_IN (AP1_IN + MAX_AP_SAMPLES + GUARD) +#define DELAY1_IN (DELAY0_IN + MAX_DELAY_SAMPLES + GUARD) + +// Define the max offsets for the end points of each section +// i.e., we don't expect a given section's taps to go beyond +// the following limits +#define AP0_OUT (AP0_IN + MAX_AP_SAMPLES -1) +#define AP1_OUT (AP1_IN + MAX_AP_SAMPLES -1) +#define DELAY0_OUT (DELAY0_IN + MAX_DELAY_SAMPLES -1) +#define DELAY1_OUT (DELAY1_IN + MAX_DELAY_SAMPLES -1) + +#define REVERB_DEFAULT_ROOM_NUMBER 1 // default preset number +#define DEFAULT_AP0_LENGTH (int)(((double) (17.0/1000.0)) * ((double) _OUTPUT_SAMPLE_RATE)) +#define DEFAULT_AP0_GAIN 19400 +#define DEFAULT_AP1_LENGTH (int)(((double) (16.5/1000.0)) * ((double) _OUTPUT_SAMPLE_RATE)) +#define DEFAULT_AP1_GAIN -19400 + +#define REVERB_DEFAULT_WET 32767 +#define REVERB_DEFAULT_DRY 0 + +#define EAS_REVERB_WET_MAX 32767 +#define EAS_REVERB_WET_MIN 0 +#define EAS_REVERB_DRY_MAX 32767 +#define EAS_REVERB_DRY_MIN 0 + +/* parameters for each allpass */ +typedef struct +{ + EAS_U16 m_zApOut; // delay offset for ap out + + EAS_I16 m_nApGain; // gain for ap + + EAS_U16 m_zApIn; // delay offset for ap in + +} S_ALLPASS_OBJECT; + + +/* parameters for each allpass */ +typedef struct +{ + EAS_PCM m_zLpf; // actual state variable, not a length + + EAS_I16 m_nLpfFwd; // lpf forward gain + + EAS_I16 m_nLpfFbk; // lpf feedback gain + + EAS_U16 m_zDelay[REVERB_MAX_NUM_REFLECTIONS]; // delay offset for ap out + + EAS_I16 m_nGain[REVERB_MAX_NUM_REFLECTIONS]; // gain for ap + +} S_EARLY_REFLECTION_OBJECT; + +//demo +typedef struct +{ + EAS_I16 m_nLpfFbk; + EAS_I16 m_nLpfFwd; + + EAS_I16 m_nEarly; + EAS_I16 m_nWet; + EAS_I16 m_nDry; + + EAS_I16 m_nEarlyL_LpfFbk; + EAS_I16 m_nEarlyL_LpfFwd; + + EAS_I16 m_nEarlyL_Delay0; //8 + EAS_I16 m_nEarlyL_Gain0; + EAS_I16 m_nEarlyL_Delay1; + EAS_I16 m_nEarlyL_Gain1; + EAS_I16 m_nEarlyL_Delay2; + EAS_I16 m_nEarlyL_Gain2; + EAS_I16 m_nEarlyL_Delay3; + EAS_I16 m_nEarlyL_Gain3; + EAS_I16 m_nEarlyL_Delay4; + EAS_I16 m_nEarlyL_Gain4; + + EAS_I16 m_nEarlyR_Delay0; //18 + EAS_I16 m_nEarlyR_Gain0; + EAS_I16 m_nEarlyR_Delay1; + EAS_I16 m_nEarlyR_Gain1; + EAS_I16 m_nEarlyR_Delay2; + EAS_I16 m_nEarlyR_Gain2; + EAS_I16 m_nEarlyR_Delay3; + EAS_I16 m_nEarlyR_Gain3; + EAS_I16 m_nEarlyR_Delay4; + EAS_I16 m_nEarlyR_Gain4; + + EAS_U16 m_nMaxExcursion; //28 + EAS_I16 m_nXfadeInterval; + + EAS_I16 m_nAp0_ApGain; //30 + EAS_I16 m_nAp0_ApOut; + EAS_I16 m_nAp1_ApGain; + EAS_I16 m_nAp1_ApOut; + + EAS_I16 m_rfu4; + EAS_I16 m_rfu5; + EAS_I16 m_rfu6; + EAS_I16 m_rfu7; + EAS_I16 m_rfu8; + EAS_I16 m_rfu9; + EAS_I16 m_rfu10; //43 + +} S_REVERB_PRESET; + +typedef struct +{ + S_REVERB_PRESET m_sPreset[REVERB_MAX_ROOM_TYPE]; //array of presets + +} S_REVERB_PRESET_BANK; + +/* parameters for each reverb */ +typedef struct +{ + /* controls entire reverb playback volume */ + /* to conserve memory, use the MSB and ignore the LSB */ + EAS_U8 m_nMasterVolume; + + /* update counter keeps track of when synth params need updating */ + /* only needs to be as large as REVERB_UPDATE_PERIOD_IN_SAMPLES */ + EAS_I16 m_nUpdateCounter; + + EAS_U16 m_nMinSamplesToAdd; /* ComputeReverb() generates this many samples */ + + EAS_U8 m_nFlags; /* misc flags/bit fields */ + + EAS_PCM *m_pOutputBuffer; + EAS_PCM *m_pInputBuffer; + + EAS_U16 m_nNumSamplesInOutputBuffer; + EAS_U16 m_nNumSamplesInInputBuffer; + + EAS_U16 m_nNumInputSamplesRead; // if m_nNumInputSamplesRead >= NumSamplesInInputBuffer + // then get a new input buffer + EAS_PCM *m_pNextInputSample; + + EAS_U16 m_nBaseIndex; // base index for circular buffer + + // reverb delay line offsets, allpass parameters, etc: + + EAS_PCM m_nRevOutFbkR; // combine feedback reverb right out with dry left in + + S_ALLPASS_OBJECT m_sAp0; // allpass 0 (left channel) + + EAS_U16 m_zD0In; // delay offset for delay line D0 in + + EAS_PCM m_nRevOutFbkL; // combine feedback reverb left out with dry right in + + S_ALLPASS_OBJECT m_sAp1; // allpass 1 (right channel) + + EAS_U16 m_zD1In; // delay offset for delay line D1 in + + // delay output taps, notice criss cross order + EAS_U16 m_zD0Self; // self feeds forward d0 --> d0 + + EAS_U16 m_zD1Cross; // cross feeds across d1 --> d0 + + EAS_PCM m_zLpf0; // actual state variable, not a length + + EAS_U16 m_zD1Self; // self feeds forward d1 --> d1 + + EAS_U16 m_zD0Cross; // cross feeds across d0 --> d1 + + EAS_PCM m_zLpf1; // actual state variable, not a length + + EAS_I16 m_nSin; // gain for self taps + + EAS_I16 m_nCos; // gain for cross taps + + EAS_I16 m_nSinIncrement; // increment for gain + + EAS_I16 m_nCosIncrement; // increment for gain + + EAS_I16 m_nLpfFwd; // lpf forward gain (includes scaling for mixer) + + EAS_I16 m_nLpfFbk; // lpf feedback gain + + EAS_U16 m_nXfadeInterval; // update/xfade after this many samples + + EAS_U16 m_nXfadeCounter; // keep track of when to xfade + + EAS_I16 m_nPhase; // -1 <= m_nPhase < 1 + // but during sin,cos calculations + // use m_nPhase/2 + + EAS_I16 m_nPhaseIncrement; // add this to m_nPhase each frame + + EAS_I16 m_nNoise; // random noise sample + + EAS_U16 m_nMaxExcursion; // the taps can excurse +/- this amount + + EAS_BOOL m_bUseNoise; // if EAS_TRUE, use noise as input signal + + EAS_BOOL m_bBypass; // if EAS_TRUE, then bypass reverb and copy input to output + + EAS_I16 m_nCurrentRoom; // preset number for current room + + EAS_I16 m_nNextRoom; // preset number for next room + + EAS_I16 m_nWet; // gain for wet (processed) signal + + EAS_I16 m_nDry; // gain for dry (unprocessed) signal + + EAS_I16 m_nEarly; // gain for early (widen) signal + + S_EARLY_REFLECTION_OBJECT m_sEarlyL; // left channel early reflections + S_EARLY_REFLECTION_OBJECT m_sEarlyR; // right channel early reflections + + EAS_PCM m_nDelayLine[REVERB_BUFFER_SIZE_IN_SAMPLES]; // one large delay line for all reverb elements + + S_REVERB_PRESET pPreset; + + S_REVERB_PRESET_BANK m_sPreset; + + //EAS_I8 preset; + +} S_REVERB_OBJECT; + + +/*------------------------------------ + * prototypes + *------------------------------------ +*/ + +/*---------------------------------------------------------------------------- + * ReverbUpdateXfade + *---------------------------------------------------------------------------- + * Purpose: + * Update the xfade parameters as required + * + * Inputs: + * nNumSamplesToAdd - number of samples to write to buffer + * + * Outputs: + * + * + * Side Effects: + * - xfade parameters will be changed + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ReverbUpdateXfade(S_REVERB_OBJECT* pReverbData, EAS_INT nNumSamplesToAdd); + +/*---------------------------------------------------------------------------- + * ReverbCalculateNoise + *---------------------------------------------------------------------------- + * Purpose: + * Calculate a noise sample and limit its value + * + * Inputs: + * nMaxExcursion - noise value is limited to this value + * pnNoise - return new noise sample in this (not limited) + * + * Outputs: + * new limited noise value + * + * Side Effects: + * - *pnNoise noise value is updated + * + *---------------------------------------------------------------------------- +*/ +static EAS_U16 ReverbCalculateNoise(EAS_U16 nMaxExcursion, EAS_I16 *pnNoise); + +/*---------------------------------------------------------------------------- + * ReverbCalculateSinCos + *---------------------------------------------------------------------------- + * Purpose: + * Calculate a new sin and cosine value based on the given phase + * + * Inputs: + * nPhase - phase angle + * pnSin - input old value, output new value + * pnCos - input old value, output new value + * + * Outputs: + * + * Side Effects: + * - *pnSin, *pnCos are updated + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ReverbCalculateSinCos(EAS_I16 nPhase, EAS_I16 *pnSin, EAS_I16 *pnCos); + +/*---------------------------------------------------------------------------- + * Reverb + *---------------------------------------------------------------------------- + * Purpose: + * apply reverb to the given signal + * + * Inputs: + * nNu + * pnSin - input old value, output new value + * pnCos - input old value, output new value + * + * Outputs: + * number of samples actually reverberated + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT Reverb(S_REVERB_OBJECT* pReverbData, EAS_INT nNumSamplesToAdd, EAS_PCM *pOutputBuffer, EAS_PCM *pInputBuffer); + +/*---------------------------------------------------------------------------- + * ReverbReadInPresets() + *---------------------------------------------------------------------------- + * Purpose: sets global reverb preset bank to defaults + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ReverbReadInPresets(S_REVERB_OBJECT* pReverbData); + + +/*---------------------------------------------------------------------------- + * ReverbUpdateRoom + *---------------------------------------------------------------------------- + * Purpose: + * Update the room's preset parameters as required + * + * Inputs: + * + * Outputs: + * + * + * Side Effects: + * - reverb paramters (fbk, fwd, etc) will be changed + * - m_nCurrentRoom := m_nNextRoom + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ReverbUpdateRoom(S_REVERB_OBJECT* pReverbData); + +#endif /* #ifndef _EAS_REVERBDATA_H */ + + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_rtttl.c b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_rtttl.c new file mode 100755 index 0000000..d8253fb --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_rtttl.c @@ -0,0 +1,1197 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_rtttl.c + * + * Contents and purpose: + * RTTTL parser + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 795 $ + * $Date: 2007-08-01 00:14:45 -0700 (Wed, 01 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_data.h" +#include "eas_miditypes.h" +#include "eas_parser.h" +#include "eas_report.h" +#include "eas_host.h" +#include "eas_midi.h" +#include "eas_config.h" +#include "eas_vm_protos.h" +#include "eas_rtttldata.h" +#include "eas_ctype.h" + +/* increase gain for mono ringtones */ +#define RTTTL_GAIN_OFFSET 8 + +/* maximum title length including colon separator */ +#define RTTTL_MAX_TITLE_LEN 32 +#define RTTTL_INFINITE_LOOP 15 + +/* length of 32nd note in 1/256ths of a msec for 63 BPM tempo */ +#define DEFAULT_TICK_CONV 30476 +#define TICK_CONVERT 1920000 + +/* default channel and program for RTTTL playback */ +#define RTTTL_CHANNEL 0 +#define RTTTL_PROGRAM 80 +#define RTTTL_VELOCITY 127 + +/* note used for rest */ +#define RTTTL_REST 1 + +/* multiplier for fixed point triplet conversion */ +#define TRIPLET_MULTIPLIER 683 +#define TRIPLET_SHIFT 10 + +/* local prototypes */ +static EAS_RESULT RTTTL_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset); +static EAS_RESULT RTTTL_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT RTTTL_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime); +static EAS_RESULT RTTTL_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode); +static EAS_RESULT RTTTL_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_STATE *pState); +static EAS_RESULT RTTTL_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT RTTTL_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT RTTTL_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT RTTTL_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT RTTTL_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value); +static EAS_RESULT RTTTL_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue); +static EAS_RESULT RTTTL_GetStyle (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData); +static EAS_RESULT RTTTL_GetDuration (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData, EAS_I8 *pDuration); +static EAS_RESULT RTTTL_GetOctave (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData, EAS_U8 *pOctave); +static EAS_RESULT RTTTL_GetTempo (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData); +static EAS_RESULT RTTTL_GetNumber (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData, EAS_I32 *pValue); +static EAS_RESULT RTTTL_ParseHeader (S_EAS_DATA *pEASData, S_RTTTL_DATA* pData, EAS_BOOL metaData); +static EAS_RESULT RTTTL_GetNextChar (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData, EAS_I8 *pValue); +static EAS_RESULT RTTTL_PeekNextChar (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData, EAS_I8 *pValue); + +/* inline functions */ +EAS_INLINE void RTTTL_PutBackChar (S_RTTTL_DATA *pData, EAS_I8 value) { pData->dataByte = value; } + + +/* lookup table for note values */ +static const EAS_U8 noteTable[] = { 21, 23, 12, 14, 16, 17, 19, 23 }; + +/*---------------------------------------------------------------------------- + * + * EAS_RTTTL_Parser + * + * This structure contains the functional interface for the iMelody parser + *---------------------------------------------------------------------------- +*/ +const S_FILE_PARSER_INTERFACE EAS_RTTTL_Parser = +{ + RTTTL_CheckFileType, + RTTTL_Prepare, + RTTTL_Time, + RTTTL_Event, + RTTTL_State, + RTTTL_Close, + RTTTL_Reset, + RTTTL_Pause, + RTTTL_Resume, + NULL, + RTTTL_SetData, + RTTTL_GetData, + NULL +}; + +/*---------------------------------------------------------------------------- + * RTTTL_CheckFileType() + *---------------------------------------------------------------------------- + * Purpose: + * Check the file type to see if we can parse it + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset) +{ + S_RTTTL_DATA data; + S_RTTTL_DATA *pData; + + /* see if we can parse the header */ + data.fileHandle = fileHandle; + data.fileOffset = offset; + *ppHandle= NULL; + if (RTTTL_ParseHeader (pEASData, &data, EAS_FALSE) == EAS_SUCCESS) + { + + /* check for static memory allocation */ + if (pEASData->staticMemoryModel) + pData = EAS_CMEnumData(EAS_CM_RTTTL_DATA); + else + pData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_RTTTL_DATA)); + if (!pData) + return EAS_ERROR_MALLOC_FAILED; + EAS_HWMemSet(pData, 0, sizeof(S_RTTTL_DATA)); + + /* return a pointer to the instance data */ + pData->fileHandle = fileHandle; + pData->fileOffset = offset; + pData->state = EAS_STATE_OPEN; + *ppHandle = pData; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_Prepare() + *---------------------------------------------------------------------------- + * Purpose: + * Prepare to parse the file. Allocates instance data (or uses static allocation for + * static memory model). + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_RTTTL_DATA* pData; + EAS_RESULT result; + + /* check for valid state */ + pData = (S_RTTTL_DATA*) pInstData; + if (pData->state != EAS_STATE_OPEN) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + /* instantiate a synthesizer */ + if ((result = VMInitMIDI(pEASData, &pData->pSynth)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitMIDI returned %d\n", result); */ } + return result; + } + + pData->state = EAS_STATE_ERROR; + if ((result = RTTTL_ParseHeader (pEASData, pData, (EAS_BOOL) (pData->metadata.callback != NULL))) != EAS_SUCCESS) + { + /* if using dynamic memory, free it */ + if (!pEASData->staticMemoryModel) + EAS_HWFree(pEASData->hwInstData, pData); + return result; + } + + pData->state = EAS_STATE_READY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_Time() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the time of the next event in msecs + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * pTime - pointer to variable to hold time of next event (in msecs) + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +static EAS_RESULT RTTTL_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime) +{ + S_RTTTL_DATA *pData; + + pData = (S_RTTTL_DATA*) pInstData; + + /* return time in milliseconds */ + /*lint -e{704} use shift instead of division */ + *pTime = pData->time >> 8; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_Event() + *---------------------------------------------------------------------------- + * Purpose: + * Parse the next event in the file + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode) +{ + S_RTTTL_DATA* pData; + EAS_RESULT result; + EAS_I32 ticks; + EAS_I32 temp; + EAS_I8 c; + EAS_U8 note; + EAS_U8 octave; + + pData = (S_RTTTL_DATA*) pInstData; + if (pData->state >= EAS_STATE_OPEN) + return EAS_SUCCESS; + + /* initialize MIDI channel when the track starts playing */ + if (pData->time == 0) + { + /* set program to square lead */ + VMProgramChange(pEASData->pVoiceMgr, pData->pSynth, RTTTL_CHANNEL, RTTTL_PROGRAM); + + /* set channel volume to max */ + VMControlChange(pEASData->pVoiceMgr, pData->pSynth, RTTTL_CHANNEL, 7, 127); + } + + /* check for end of note */ + if (pData->note) + { + /* stop the note */ + VMStopNote(pEASData->pVoiceMgr, pData->pSynth, RTTTL_CHANNEL, pData->note, 0); + pData->note = 0; + + /* check for rest between notes */ + if (pData->restTicks) + { + pData->time += pData->restTicks; + pData->restTicks = 0; + return EAS_SUCCESS; + } + } + + /* parse the next event */ + octave = pData->octave; + note = 0; + ticks = pData->duration * pData->tick; + for (;;) + { + + /* get next character */ + if ((result = RTTTL_GetNextChar(pEASData->hwInstData, pData, &c)) != EAS_SUCCESS) + { + if (result != EAS_EOF) + return result; + + /* end of file, if no notes to process, check for looping */ + if (!note) + { + /* if no loop set state to stopping */ + if (pData->repeatCount == 0) + { + pData->state = EAS_STATE_STOPPING; + VMReleaseAllVoices(pEASData->pVoiceMgr, pData->pSynth); + return EAS_SUCCESS; + } + + /* decrement loop count */ + if (pData->repeatCount != RTTTL_INFINITE_LOOP) + pData->repeatCount--; + + /* if locating, ignore infinite loops */ + else if (parserMode != eParserModePlay) + { + pData->state = EAS_STATE_STOPPING; + VMReleaseAllVoices(pEASData->pVoiceMgr, pData->pSynth); + return EAS_SUCCESS; + } + + /* loop back to start of notes */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pData->fileHandle, pData->repeatOffset)) != EAS_SUCCESS) + return result; + continue; + } + + /* still have a note to process */ + else + c = ','; + } + + /* bpm */ + if (c == 'b') + { + /* peek at next character */ + if ((result = RTTTL_PeekNextChar(pEASData->hwInstData, pData, &c)) != EAS_SUCCESS) + return result; + + /* if a number, must be octave or tempo */ + if (IsDigit(c)) + { + if ((result = RTTTL_GetNumber(pEASData->hwInstData, pData, &temp)) != EAS_SUCCESS) + return result; + + /* check for octave first */ + if ((temp >= 4) && (temp <= 7)) + { + octave = (EAS_U8) temp; + } + + /* check for tempo */ + else if ((temp >= 25) && (temp <= 900)) + { + pData->tick = TICK_CONVERT / (EAS_U32) temp; + } + + /* don't know what it was */ + else + return EAS_ERROR_FILE_FORMAT; + } + + /* must be a note */ + else + { + note = noteTable[1]; + } + } + + /* octave */ + else if (c == 'o') + { + if ((result = RTTTL_GetOctave(pEASData->hwInstData, pData, &pData->octave)) != EAS_SUCCESS) + return result; + } + + /* style */ + else if (c == 's') + { + if ((result = RTTTL_GetStyle(pEASData->hwInstData, pData)) != EAS_SUCCESS) + return result; + } + + /* duration or octave */ + else if (IsDigit(c)) + { + RTTTL_PutBackChar(pData, c); + + /* duration comes before note */ + if (!note) + { + if ((result = RTTTL_GetDuration(pEASData->hwInstData, pData, &c)) != EAS_SUCCESS) + return result; + ticks = c * pData->tick; + } + + /* octave comes after note */ + else + { + if ((result = RTTTL_GetOctave(pEASData->hwInstData, pData, &octave)) != EAS_SUCCESS) + return result; + } + } + + /* note or rest */ + else if ((c >= 'a') && (c <= 'h')) + { + note = noteTable[c - 'a']; + } + + else if (c == 'p') + { + note = RTTTL_REST; + } + + /* dotted note */ + else if (c == '.') + { + /*lint -e{704} shift for performance */ + ticks += ticks >> 1; + } + + /* accidental */ + else if (c == '#') + { + if (note) + note++; + } + + /* end of event */ + else if ((c == ',') && note) + { + + /* handle note events */ + if (note != RTTTL_REST) + { + + /* save note and start it */ + pData->note = note + octave; + if (parserMode == eParserModePlay) + VMStartNote(pEASData->pVoiceMgr, pData->pSynth, RTTTL_CHANNEL, pData->note, RTTTL_VELOCITY); + + /* determine note length */ + switch (pData->style) + { + /* natural */ + case 'n': + /*lint -e{704} shift for performance */ + pData->restTicks = ticks >> 4; + break; + /* continuous */ + + case 'c': + pData->restTicks = 0; + break; + + /* staccato */ + case 's': + /*lint -e{704} shift for performance */ + pData->restTicks = ticks >> 1; + break; + + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "RTTTL_Event: Unexpected style type %c\n", pData->style); */ } + break; + } + + /* next event is at end of this note */ + pData->time += ticks - pData->restTicks; + } + + /* rest */ + else + pData->time += ticks; + + /* event found, return to caller */ + break; + } + } + + pData->state = EAS_STATE_PLAY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_State() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current state of the stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * pState - pointer to variable to store state + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +static EAS_RESULT RTTTL_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pState) +{ + S_RTTTL_DATA* pData; + + /* establish pointer to instance data */ + pData = (S_RTTTL_DATA*) pInstData; + + /* if stopping, check to see if synth voices are active */ + if (pData->state == EAS_STATE_STOPPING) + { + if (VMActiveVoices(pData->pSynth) == 0) + pData->state = EAS_STATE_STOPPED; + } + + if (pData->state == EAS_STATE_PAUSING) + { + if (VMActiveVoices(pData->pSynth) == 0) + pData->state = EAS_STATE_PAUSED; + } + + /* return current state */ + *pState = pData->state; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_Close() + *---------------------------------------------------------------------------- + * Purpose: + * Close the file and clean up + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_RTTTL_DATA* pData; + EAS_RESULT result; + + pData = (S_RTTTL_DATA*) pInstData; + + /* close the file */ + if ((result = EAS_HWCloseFile(pEASData->hwInstData, pData->fileHandle)) != EAS_SUCCESS) + return result; + + /* free the synth */ + if (pData->pSynth != NULL) + VMMIDIShutdown(pEASData, pData->pSynth); + + /* if using dynamic memory, free it */ + if (!pEASData->staticMemoryModel) + EAS_HWFree(pEASData->hwInstData, pData); + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_Reset() + *---------------------------------------------------------------------------- + * Purpose: + * Reset the sequencer. Used for locating backwards in the file. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_RTTTL_DATA* pData; + EAS_RESULT result; + + pData = (S_RTTTL_DATA*) pInstData; + + /* reset the synth */ + VMReset(pEASData->pVoiceMgr, pData->pSynth, EAS_TRUE); + + /* reset time to zero */ + pData->time = 0; + pData->note = 0; + + /* reset file position and re-parse header */ + pData->state = EAS_STATE_ERROR; + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pData->fileHandle, pData->fileOffset)) != EAS_SUCCESS) + return result; + if ((result = RTTTL_ParseHeader (pEASData, pData, EAS_TRUE)) != EAS_SUCCESS) + return result; + + pData->state = EAS_STATE_READY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_Pause() + *---------------------------------------------------------------------------- + * Purpose: + * Pauses the sequencer. Mutes all voices and sets state to pause. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_RTTTL_DATA *pData; + + /* can't pause a stopped stream */ + pData = (S_RTTTL_DATA*) pInstData; + if (pData->state == EAS_STATE_STOPPED) + return EAS_ERROR_ALREADY_STOPPED; + + /* mute the synthesizer */ + VMMuteAllVoices(pEASData->pVoiceMgr, pData->pSynth); + pData->state = EAS_STATE_PAUSING; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_Resume() + *---------------------------------------------------------------------------- + * Purpose: + * Resume playing after a pause, sets state back to playing. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +static EAS_RESULT RTTTL_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_RTTTL_DATA *pData; + + /* can't resume a stopped stream */ + pData = (S_RTTTL_DATA*) pInstData; + if (pData->state == EAS_STATE_STOPPED) + return EAS_ERROR_ALREADY_STOPPED; + + /* nothing to do but resume playback */ + pData->state = EAS_STATE_PLAY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_SetData() + *---------------------------------------------------------------------------- + * Purpose: + * Return file type + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +static EAS_RESULT RTTTL_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value) +{ + S_RTTTL_DATA *pData; + + pData = (S_RTTTL_DATA *) pInstData; + switch (param) + { + + /* set metadata callback */ + case PARSER_DATA_METADATA_CB: + EAS_HWMemCpy(&pData->metadata, (void*) value, sizeof(S_METADATA_CB)); + break; + + default: + return EAS_ERROR_INVALID_PARAMETER; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_GetData() + *---------------------------------------------------------------------------- + * Purpose: + * Return file type + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +static EAS_RESULT RTTTL_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue) +{ + S_RTTTL_DATA *pData; + + pData = (S_RTTTL_DATA *) pInstData; + switch (param) + { + /* return file type as RTTTL */ + case PARSER_DATA_FILE_TYPE: + *pValue = EAS_FILE_RTTTL; + break; + +#if 0 + /* set transposition */ + case PARSER_DATA_TRANSPOSITION: + *pValue = pData->transposition; + break; +#endif + + case PARSER_DATA_SYNTH_HANDLE: + *pValue = (EAS_I32) pData->pSynth; + break; + + case PARSER_DATA_GAIN_OFFSET: + *pValue = RTTTL_GAIN_OFFSET; + break; + + default: + return EAS_ERROR_INVALID_PARAMETER; + } + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_GetStyle() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_GetStyle (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData) +{ + EAS_RESULT result; + EAS_I8 style; + + /* get style */ + if ((result = RTTTL_GetNextChar(hwInstData, pData, &style)) != EAS_SUCCESS) + return result; + + if ((style != 's') && (style != 'n') && (style != 'c')) + return EAS_ERROR_FILE_FORMAT; + + pData->style = style; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_GetDuration() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_GetDuration (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData, EAS_I8 *pDuration) +{ + EAS_RESULT result; + EAS_I32 duration; + EAS_I8 temp; + + /* get the duration */ + if ((result = RTTTL_GetNumber(hwInstData, pData, &duration)) != EAS_SUCCESS) + return result; + + if ((duration != 1) && (duration != 2) && (duration != 4) && (duration != 8) && (duration != 16) && (duration != 32)) + return EAS_ERROR_FILE_FORMAT; + + temp = 64; + while (duration) + { + /*lint -e{704} shift for performance */ + duration = duration >> 1; + /*lint -e{702} use shift for performance */ + temp = temp >> 1; + } + + *pDuration = temp; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_GetOctave() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_GetOctave (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData, EAS_U8 *pOctave) +{ + EAS_RESULT result; + EAS_I32 octave; + + /* get the tempo */ + if ((result = RTTTL_GetNumber(hwInstData, pData, &octave)) != EAS_SUCCESS) + return result; + + if ((octave < 4) || (octave > 7)) + return EAS_ERROR_FILE_FORMAT; + + *pOctave = (EAS_U8) (octave * 12); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_GetTempo() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_GetTempo (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData) +{ + EAS_RESULT result; + EAS_I32 tempo; + + /* get the tempo */ + if ((result = RTTTL_GetNumber(hwInstData, pData, &tempo)) != EAS_SUCCESS) + return result; + + if ((tempo < 25) || (tempo > 900)) + return EAS_ERROR_FILE_FORMAT; + + pData->tick = TICK_CONVERT / (EAS_U32) tempo; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_GetNumber() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_GetNumber (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData, EAS_I32 *pValue) +{ + EAS_RESULT result; + EAS_INT temp; + EAS_I8 c; + + *pValue = -1; + temp = 0; + for (;;) + { + if ((result = RTTTL_PeekNextChar(hwInstData, pData, &c)) != EAS_SUCCESS) + { + if ((result == EAS_EOF) && (*pValue != -1)) + return EAS_SUCCESS; + return result; + } + + if (IsDigit(c)) + { + pData->dataByte = 0; + temp = temp * 10 + c - '0'; + *pValue = temp; + } + else + return EAS_SUCCESS; + } +} + +/*---------------------------------------------------------------------------- + * RTTTL_ParseHeader() + *---------------------------------------------------------------------------- + * Purpose: + * Prepare to parse the file. Allocates instance data (or uses static allocation for + * static memory model). + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_ParseHeader (S_EAS_DATA *pEASData, S_RTTTL_DATA* pData, EAS_BOOL metaData) +{ + EAS_RESULT result; + EAS_I32 i; + EAS_I8 temp; + EAS_I8 control; + + /* initialize some defaults */ + pData->time = 0; + pData->tick = DEFAULT_TICK_CONV; + pData->note = 0; + pData->duration = 4; + pData ->restTicks = 0; + pData->octave = 60; + pData->repeatOffset = -1; + pData->repeatCount = 0; + pData->style = 'n'; + pData->dataByte = 0; + + metaData = metaData && (pData->metadata.buffer != NULL) && (pData->metadata.callback != NULL); + + /* seek to start of data */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pData->fileHandle, pData->fileOffset)) != EAS_SUCCESS) + return result; + + /* zero the metadata buffer */ + if (metaData) + EAS_HWMemSet(pData->metadata.buffer, 0, pData->metadata.bufferSize); + + /* read the title */ + for (i = 0; i < RTTTL_MAX_TITLE_LEN; i++) + { + if ((result = EAS_HWGetByte(pEASData->hwInstData, pData->fileHandle, &temp)) != EAS_SUCCESS) + return result; + + if (temp == ':') + break; + + /* pass along metadata */ + if (metaData) + { + if (i < (pData->metadata.bufferSize- 1)) + pData->metadata.buffer[i] = (char) temp; + } + } + + /* check for error in title */ + if (i == RTTTL_MAX_TITLE_LEN) + return EAS_ERROR_FILE_FORMAT; + + /* pass along metadata */ + if (metaData) + (*pData->metadata.callback)(EAS_METADATA_TITLE, pData->metadata.buffer, pData->metadata.pUserData); + + /* control fields */ + for (;;) + { + + /* get control type */ + if ((result = RTTTL_GetNextChar(pEASData->hwInstData, pData, &control)) != EAS_SUCCESS) + return result; + + /* next char should be equal sign */ + if ((result = RTTTL_GetNextChar(pEASData->hwInstData, pData, &temp)) != EAS_SUCCESS) + return result; + if (temp != '=') + return EAS_ERROR_FILE_FORMAT; + + /* get the control value */ + switch (control) + { + + /* bpm */ + case 'b': + if ((result = RTTTL_GetTempo(pEASData->hwInstData, pData)) != EAS_SUCCESS) + return result; + break; + + /* duration */ + case 'd': + if ((result = RTTTL_GetDuration(pEASData->hwInstData, pData, &temp)) != EAS_SUCCESS) + return result; + pData->duration = temp; + break; + + /* loop */ + case 'l': + if ((result = RTTTL_GetNumber(pEASData->hwInstData, pData, &i)) != EAS_SUCCESS) + return result; + if ((i < 0) || (i > 15)) + return EAS_ERROR_FILE_FORMAT; + pData->repeatCount = (EAS_U8) i; + break; + + /* octave */ + case 'o': + if ((result = RTTTL_GetOctave(pEASData->hwInstData, pData, &pData->octave)) != EAS_SUCCESS) + return result; + break; + + /* get style */ + case 's': + if ((result = RTTTL_GetStyle(pEASData->hwInstData, pData)) != EAS_SUCCESS) + return result; + break; + + /* unrecognized control */ + default: + return EAS_ERROR_FILE_FORMAT; + } + + /* next character should be comma or colon */ + if ((result = RTTTL_GetNextChar(pEASData->hwInstData, pData, &temp)) != EAS_SUCCESS) + return result; + + /* check for end of control field */ + if (temp == ':') + break; + + /* must be a comma */ + if (temp != ',') + return EAS_ERROR_FILE_FORMAT; + } + + /* should be at the start of the music block */ + if ((result = EAS_HWFilePos(pEASData->hwInstData, pData->fileHandle, &pData->repeatOffset)) != EAS_SUCCESS) + return result; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_GetNextChar() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_GetNextChar (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData, EAS_I8 *pValue) +{ + EAS_RESULT result; + EAS_I8 temp; + + *pValue = 0; + for(;;) + { + + /* check for character that has been put back */ + if (pData->dataByte) + { + temp = pData->dataByte; + pData->dataByte = 0; + } + else + { + if ((result = EAS_HWGetByte(hwInstData, pData->fileHandle, &temp)) != EAS_SUCCESS) + return result; + } + + /* ignore white space */ + if (!IsSpace(temp)) + { + *pValue = ToLower(temp); + return EAS_SUCCESS; + } + } +} + +/*---------------------------------------------------------------------------- + * RTTTL_PeekNextChar() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_PeekNextChar (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData, EAS_I8 *pValue) +{ + EAS_RESULT result; + EAS_I8 temp; + + *pValue = 0; + for(;;) + { + + /* read a character from the file, if necessary */ + if (!pData->dataByte) + { + if ((result = EAS_HWGetByte(hwInstData, pData->fileHandle, &pData->dataByte)) != EAS_SUCCESS) + return result; + + } + temp = pData->dataByte; + + /* ignore white space */ + if (!IsSpace(temp)) + { + *pValue = ToLower(temp); + return EAS_SUCCESS; + } + pData->dataByte = 0; + } +} + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_rtttldata.c b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_rtttldata.c new file mode 100755 index 0000000..708a1d9 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_rtttldata.c @@ -0,0 +1,41 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_rtttldata.c + * + * Contents and purpose: + * RTTTL File Parser data module for static memory models + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 547 $ + * $Date: 2007-01-31 16:30:17 -0800 (Wed, 31 Jan 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_types.h" +#include "eas_rtttldata.h" + +/*---------------------------------------------------------------------------- + * + * eas_RTTTLData + * + * Static memory allocation for RTTTL parser + *---------------------------------------------------------------------------- +*/ +S_RTTTL_DATA eas_RTTTLData; + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_rtttldata.h b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_rtttldata.h new file mode 100755 index 0000000..31dd522 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_rtttldata.h @@ -0,0 +1,70 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_rtttldata.h + * + * Contents and purpose: + * SMF File Parser + * + * This file contains data declarations for the RTTTL parser. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef EAS_RTTTLDATA_H +#define EAS_RTTTLDATA_H + +#include "eas_data.h" + + +/* maximum line size as specified in iMelody V1.2 spec */ +#define MAX_LINE_SIZE 75 + +/*---------------------------------------------------------------------------- + * + * S_RTTTL_DATA + * + * This structure contains the state data for the iMelody parser + *---------------------------------------------------------------------------- +*/ + +typedef struct +{ + EAS_FILE_HANDLE fileHandle; /* file handle */ + S_SYNTH *pSynth; /* synthesizer handle */ + S_METADATA_CB metadata; /* metadata callback */ + EAS_I32 fileOffset; /* offset to start of data */ + EAS_I32 time; /* current time in 256ths of a msec */ + EAS_I32 tick; /* length of 32nd note in 256th of a msec */ + EAS_I32 restTicks; /* ticks to rest after current note */ + EAS_I32 repeatOffset; /* file offset to start of repeat section */ + EAS_U8 repeatCount; /* repeat counter */ + EAS_I8 dataByte; /* storage for characters that are "put back" */ + EAS_U8 state; /* current state EAS_STATE_XXXX */ + EAS_I8 style; /* from STYLE */ + EAS_U8 note; /* MIDI note number */ + EAS_U8 octave; /* decault octave prefix */ + EAS_I8 duration; /* default note duration */ +} S_RTTTL_DATA; + +#endif + + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_smf.c b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_smf.c new file mode 100755 index 0000000..e609583 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_smf.c @@ -0,0 +1,1203 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_smf.c + * + * Contents and purpose: + * SMF Type 0 and 1 File Parser + * + * For SMF timebase analysis, see "MIDI Sequencer Analysis.xls". + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 803 $ + * $Date: 2007-08-01 09:57:00 -0700 (Wed, 01 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_data.h" +#include "eas_miditypes.h" +#include "eas_parser.h" +#include "eas_report.h" +#include "eas_host.h" +#include "eas_midi.h" +#include "eas_config.h" +#include "eas_vm_protos.h" +#include "eas_smfdata.h" +#include "eas_smf.h" + +#ifdef JET_INTERFACE +#include "jet_data.h" +#endif + +//3 dls: The timebase for this module is adequate to keep MIDI and +//3 digital audio synchronized for only a few minutes. It should be +//3 sufficient for most mobile applications. If better accuracy is +//3 required, more fractional bits should be added to the timebase. + +static const EAS_U8 smfHeader[] = { 'M', 'T', 'h', 'd' }; + +/* local prototypes */ +static EAS_RESULT SMF_GetVarLenData (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle, EAS_U32 *pData); +static EAS_RESULT SMF_ParseMetaEvent (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream); +static EAS_RESULT SMF_ParseSysEx (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream, EAS_U8 f0, EAS_INT parserMode); +static EAS_RESULT SMF_ParseEvent (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream, EAS_INT parserMode); +static EAS_RESULT SMF_GetDeltaTime (EAS_HW_DATA_HANDLE hwInstData, S_SMF_STREAM *pSMFStream); +static void SMF_UpdateTime (S_SMF_DATA *pSMFData, EAS_U32 ticks); + + +/*---------------------------------------------------------------------------- + * + * SMF_Parser + * + * This structure contains the functional interface for the SMF parser + *---------------------------------------------------------------------------- +*/ +const S_FILE_PARSER_INTERFACE EAS_SMF_Parser = +{ + SMF_CheckFileType, + SMF_Prepare, + SMF_Time, + SMF_Event, + SMF_State, + SMF_Close, + SMF_Reset, + SMF_Pause, + SMF_Resume, + NULL, + SMF_SetData, + SMF_GetData, + NULL +}; + +/*---------------------------------------------------------------------------- + * SMF_CheckFileType() + *---------------------------------------------------------------------------- + * Purpose: + * Check the file type to see if we can parse it + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT SMF_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset) +{ + S_SMF_DATA* pSMFData; + EAS_RESULT result; + + /* seek to starting offset - usually 0 */ + *ppHandle = NULL; + if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, offset)) != EAS_SUCCESS) + return result; + + /* search through file for header - slow method */ + if (pEASData->searchHeaderFlag) + { + result = EAS_SearchFile(pEASData, fileHandle, smfHeader, sizeof(smfHeader), &offset); + if (result != EAS_SUCCESS) + return (result == EAS_EOF) ? EAS_SUCCESS : result; + } + + /* read the first 4 bytes of the file - quick method */ + else { + EAS_U8 header[4]; + EAS_I32 count; + if ((result = EAS_HWReadFile(pEASData->hwInstData, fileHandle, header, sizeof(header), &count)) != EAS_SUCCESS) + return result; + + /* check for 'MTrk' - return if no match */ + if ((header[0] != 'M') || (header[1] != 'T') || (header[2] != 'h') || (header[3] != 'd')) + return EAS_SUCCESS; + } + + /* check for static memory allocation */ + if (pEASData->staticMemoryModel) + pSMFData = EAS_CMEnumData(EAS_CM_SMF_DATA); + else + { + pSMFData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_SMF_DATA)); + EAS_HWMemSet((void *)pSMFData,0, sizeof(S_SMF_DATA)); + } + if (!pSMFData) + return EAS_ERROR_MALLOC_FAILED; + + /* initialize some critical data */ + pSMFData->fileHandle = fileHandle; + pSMFData->fileOffset = offset; + pSMFData->pSynth = NULL; + pSMFData->time = 0; + pSMFData->state = EAS_STATE_OPEN; + *ppHandle = pSMFData; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_Prepare() + *---------------------------------------------------------------------------- + * Purpose: + * Prepare to parse the file. Allocates instance data (or uses static allocation for + * static memory model). + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT SMF_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_SMF_DATA* pSMFData; + EAS_RESULT result; + + /* check for valid state */ + pSMFData = (S_SMF_DATA *) pInstData; + if (pSMFData->state != EAS_STATE_OPEN) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + /* instantiate a synthesizer */ + if ((result = VMInitMIDI(pEASData, &pSMFData->pSynth)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitMIDI returned %d\n", result); */ } + return result; + } + + /* parse the file header and setup the individual stream parsers */ + if ((result = SMF_ParseHeader(pEASData->hwInstData, pSMFData)) != EAS_SUCCESS) + return result; + + /* ready to play */ + pSMFData->state = EAS_STATE_READY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_Time() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the time of the next event in msecs + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * pTime - pointer to variable to hold time of next event (in msecs) + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT SMF_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime) +{ + S_SMF_DATA *pSMFData; + + pSMFData = (S_SMF_DATA*) pInstData; + + /* sanity check */ +#ifdef _CHECKED_BUILD + if (pSMFData->state == EAS_STATE_STOPPED) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Can't ask for time on a stopped stream\n"); */ } + } + + if (pSMFData->nextStream == NULL) + { + { /* dpp: EAS_ReportEx( _EAS_SEVERITY_ERROR, "no is NULL\n"); */ } + } +#endif + +#if 0 + /* return time in milliseconds */ + /* if chase mode, lie about time */ + if (pSMFData->flags & SMF_FLAGS_CHASE_MODE) + *pTime = 0; + + else +#endif + + /*lint -e{704} use shift instead of division */ + *pTime = pSMFData->time >> 8; + + *pTime = pSMFData->time >> 8; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_Event() + *---------------------------------------------------------------------------- + * Purpose: + * Parse the next event in the file + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT SMF_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode) +{ + S_SMF_DATA* pSMFData; + EAS_RESULT result; + EAS_I32 i; + EAS_U32 ticks; + EAS_U32 temp; + + /* establish pointer to instance data */ + pSMFData = (S_SMF_DATA*) pInstData; + if (pSMFData->state >= EAS_STATE_OPEN) + return EAS_SUCCESS; + + /* get current ticks */ + ticks = pSMFData->nextStream->ticks; + + /* assume that an error occurred */ + pSMFData->state = EAS_STATE_ERROR; + +#ifdef JET_INTERFACE + /* if JET has track muted, set parser mode to mute */ + if (pSMFData->nextStream->midiStream.jetData & MIDI_FLAGS_JET_MUTE) + parserMode = eParserModeMute; +#endif + + /* parse the next event from all the streams */ + if ((result = SMF_ParseEvent(pEASData, pSMFData, pSMFData->nextStream, parserMode)) != EAS_SUCCESS) + { + /* check for unexpected end-of-file */ + if (result != EAS_EOF) + return result; + + /* indicate end of track for this stream */ + pSMFData->nextStream->ticks = SMF_END_OF_TRACK; + } + + /* get next delta time, unless already at end of track */ + else if (pSMFData->nextStream->ticks != SMF_END_OF_TRACK) + { + if ((result = SMF_GetDeltaTime(pEASData->hwInstData, pSMFData->nextStream)) != EAS_SUCCESS) + { + /* check for unexpected end-of-file */ + if (result != EAS_EOF) + return result; + + /* indicate end of track for this stream */ + pSMFData->nextStream->ticks = SMF_END_OF_TRACK; + } + + /* if zero delta to next event, stay with this stream */ + else if (pSMFData->nextStream->ticks == ticks) + { + pSMFData->state = EAS_STATE_PLAY; + return EAS_SUCCESS; + } + } + + /* find next event in all streams */ + temp = 0x7ffffff; + pSMFData->nextStream = NULL; + for (i = 0; i < pSMFData->numStreams; i++) + { + if (pSMFData->streams[i].ticks < temp) + { + temp = pSMFData->streams[i].ticks; + pSMFData->nextStream = &pSMFData->streams[i]; + } + } + + /* are there any more events to parse? */ + if (pSMFData->nextStream) + { + pSMFData->state = EAS_STATE_PLAY; + + /* update the time of the next event */ + SMF_UpdateTime(pSMFData, pSMFData->nextStream->ticks - ticks); + } + else + { + pSMFData->state = EAS_STATE_STOPPING; + VMReleaseAllVoices(pEASData->pVoiceMgr, pSMFData->pSynth); + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_State() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current state of the stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * pState - pointer to variable to store state + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT SMF_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pState) +{ + S_SMF_DATA* pSMFData; + + /* establish pointer to instance data */ + pSMFData = (S_SMF_DATA*) pInstData; + + /* if stopping, check to see if synth voices are active */ + if (pSMFData->state == EAS_STATE_STOPPING) + { + if (VMActiveVoices(pSMFData->pSynth) == 0) + pSMFData->state = EAS_STATE_STOPPED; + } + + if (pSMFData->state == EAS_STATE_PAUSING) + { + if (VMActiveVoices(pSMFData->pSynth) == 0) + pSMFData->state = EAS_STATE_PAUSED; + } + + /* return current state */ + *pState = pSMFData->state; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_Close() + *---------------------------------------------------------------------------- + * Purpose: + * Close the file and clean up + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT SMF_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_SMF_DATA* pSMFData; + EAS_I32 i; + EAS_RESULT result; + + pSMFData = (S_SMF_DATA*) pInstData; + + /* close all the streams */ + for (i = 0; i < pSMFData->numStreams; i++) + { + if (pSMFData->streams[i].fileHandle != NULL) + { + if ((result = EAS_HWCloseFile(pEASData->hwInstData, pSMFData->streams[i].fileHandle)) != EAS_SUCCESS) + return result; + } + } + if (pSMFData->fileHandle != NULL) + if ((result = EAS_HWCloseFile(pEASData->hwInstData, pSMFData->fileHandle)) != EAS_SUCCESS) + return result; + + /* free the synth */ + if (pSMFData->pSynth != NULL) + VMMIDIShutdown(pEASData, pSMFData->pSynth); + + /* if using dynamic memory, free it */ + if (!pEASData->staticMemoryModel) + { + if (pSMFData->streams) + EAS_HWFree(pEASData->hwInstData, pSMFData->streams); + + /* free the instance data */ + EAS_HWFree(pEASData->hwInstData, pSMFData); + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_Reset() + *---------------------------------------------------------------------------- + * Purpose: + * Reset the sequencer. Used for locating backwards in the file. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT SMF_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_SMF_DATA* pSMFData; + EAS_I32 i; + EAS_RESULT result; + EAS_U32 ticks; + + pSMFData = (S_SMF_DATA*) pInstData; + + /* reset time to zero */ + pSMFData->time = 0; + + /* reset the synth */ + VMReset(pEASData->pVoiceMgr, pSMFData->pSynth, EAS_TRUE); + + /* find the start of each track */ + ticks = 0x7fffffffL; + pSMFData->nextStream = NULL; + for (i = 0; i < pSMFData->numStreams; i++) + { + + /* reset file position to first byte of data in track */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pSMFData->streams[i].fileHandle, pSMFData->streams[i].startFilePos)) != EAS_SUCCESS) + return result; + + /* initalize some data */ + pSMFData->streams[i].ticks = 0; + + /* initalize the MIDI parser data */ + EAS_InitMIDIStream(&pSMFData->streams[i].midiStream); + + /* parse the first delta time in each stream */ + if ((result = SMF_GetDeltaTime(pEASData->hwInstData,&pSMFData->streams[i])) != EAS_SUCCESS) + return result; + if (pSMFData->streams[i].ticks < ticks) + { + ticks = pSMFData->streams[i].ticks; + pSMFData->nextStream = &pSMFData->streams[i]; + } + } + + + pSMFData->state = EAS_STATE_READY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_Pause() + *---------------------------------------------------------------------------- + * Purpose: + * Pauses the sequencer. Mutes all voices and sets state to pause. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT SMF_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_SMF_DATA *pSMFData; + + /* can't pause a stopped stream */ + pSMFData = (S_SMF_DATA*) pInstData; + if (pSMFData->state == EAS_STATE_STOPPED) + return EAS_ERROR_ALREADY_STOPPED; + + /* mute the synthesizer */ + VMMuteAllVoices(pEASData->pVoiceMgr, pSMFData->pSynth); + pSMFData->state = EAS_STATE_PAUSING; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_Resume() + *---------------------------------------------------------------------------- + * Purpose: + * Resume playing after a pause, sets state back to playing. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT SMF_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_SMF_DATA *pSMFData; + + /* can't resume a stopped stream */ + pSMFData = (S_SMF_DATA*) pInstData; + if (pSMFData->state == EAS_STATE_STOPPED) + return EAS_ERROR_ALREADY_STOPPED; + + /* nothing to do but resume playback */ + pSMFData->state = EAS_STATE_PLAY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_SetData() + *---------------------------------------------------------------------------- + * Purpose: + * Sets parser parameters + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT SMF_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value) +{ + S_SMF_DATA *pSMFData; + + pSMFData = (S_SMF_DATA*) pInstData; + switch (param) + { + + /* set metadata callback */ + case PARSER_DATA_METADATA_CB: + EAS_HWMemCpy(&pSMFData->metadata, (void*) value, sizeof(S_METADATA_CB)); + break; + +#ifdef JET_INTERFACE + /* set jet segment and track ID of all tracks for callback function */ + case PARSER_DATA_JET_CB: + { + EAS_U32 i; + EAS_U32 bit = (EAS_U32) value; + bit = (bit << JET_EVENT_SEG_SHIFT) & JET_EVENT_SEG_MASK; + for (i = 0; i < pSMFData->numStreams; i++) + pSMFData->streams[i].midiStream.jetData = + (pSMFData->streams[i].midiStream.jetData & + ~(JET_EVENT_TRACK_MASK | JET_EVENT_SEG_MASK)) | + i << JET_EVENT_TRACK_SHIFT | bit | MIDI_FLAGS_JET_CB; + pSMFData->flags |= SMF_FLAGS_JET_STREAM; + } + break; + + /* set state of all mute flags at once */ + case PARSER_DATA_MUTE_FLAGS: + { + EAS_INT i; + EAS_U32 bit = (EAS_U32) value; + for (i = 0; i < pSMFData->numStreams; i++) + { + if (bit & 1) + pSMFData->streams[i].midiStream.jetData |= MIDI_FLAGS_JET_MUTE; + else + pSMFData->streams[i].midiStream.jetData &= ~MIDI_FLAGS_JET_MUTE; + bit >>= 1; + } + } + break; + + /* set track mute */ + case PARSER_DATA_SET_MUTE: + if (value < pSMFData->numStreams) + pSMFData->streams[value].midiStream.jetData |= MIDI_FLAGS_JET_MUTE; + else + return EAS_ERROR_PARAMETER_RANGE; + break; + + /* clear track mute */ + case PARSER_DATA_CLEAR_MUTE: + if (value < pSMFData->numStreams) + pSMFData->streams[value].midiStream.jetData &= ~MIDI_FLAGS_JET_MUTE; + else + return EAS_ERROR_PARAMETER_RANGE; + break; +#endif + + default: + return EAS_ERROR_INVALID_PARAMETER; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_GetData() + *---------------------------------------------------------------------------- + * Purpose: + * Retrieves parser parameters + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT SMF_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue) +{ + S_SMF_DATA *pSMFData; + + pSMFData = (S_SMF_DATA*) pInstData; + switch (param) + { + /* return file type */ + case PARSER_DATA_FILE_TYPE: + if (pSMFData->numStreams == 1) + *pValue = EAS_FILE_SMF0; + else + *pValue = EAS_FILE_SMF1; + break; + +/* now handled in eas_public.c */ +#if 0 + case PARSER_DATA_POLYPHONY: + if (pSMFData->pSynth) + VMGetPolyphony(pEASData->pVoiceMgr, pSMFData->pSynth, pValue); + else + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + break; + + case PARSER_DATA_PRIORITY: + if (pSMFData->pSynth) + VMGetPriority(pEASData->pVoiceMgr, pSMFData->pSynth, pValue); + break; + + /* set transposition */ + case PARSER_DATA_TRANSPOSITION: + *pValue = pSMFData->transposition; + break; +#endif + + case PARSER_DATA_SYNTH_HANDLE: + *pValue = (EAS_I32) pSMFData->pSynth; + break; + + default: + return EAS_ERROR_INVALID_PARAMETER; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_GetVarLenData() + *---------------------------------------------------------------------------- + * Purpose: + * Reads a varible length quantity from an SMF file + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT SMF_GetVarLenData (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle, EAS_U32 *pData) +{ + EAS_RESULT result; + EAS_U32 data; + EAS_U8 c; + + /* read until bit 7 is zero */ + data = 0; + do + { + if ((result = EAS_HWGetByte(hwInstData, fileHandle,&c)) != EAS_SUCCESS) + return result; + data = (data << 7) | (c & 0x7f); + } while (c & 0x80); + *pData = data; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_GetDeltaTime() + *---------------------------------------------------------------------------- + * Purpose: + * Reads a varible length quantity from an SMF file + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT SMF_GetDeltaTime (EAS_HW_DATA_HANDLE hwInstData, S_SMF_STREAM *pSMFStream) +{ + EAS_RESULT result; + EAS_U32 ticks; + + if ((result = SMF_GetVarLenData(hwInstData, pSMFStream->fileHandle, &ticks)) != EAS_SUCCESS) + return result; + + pSMFStream->ticks += ticks; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_ParseMetaEvent() + *---------------------------------------------------------------------------- + * Purpose: + * Reads a varible length quantity from an SMF file + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT SMF_ParseMetaEvent (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream) +{ + EAS_RESULT result; + EAS_U32 len; + EAS_I32 pos; + EAS_U32 temp; + EAS_U8 c; + + /* get the meta-event type */ + if ((result = EAS_HWGetByte(pEASData->hwInstData, pSMFStream->fileHandle, &c)) != EAS_SUCCESS) + return result; + + /* get the length */ + if ((result = SMF_GetVarLenData(pEASData->hwInstData, pSMFStream->fileHandle, &len)) != EAS_SUCCESS) + return result; + + /* get the current file position so we can skip the event */ + if ((result = EAS_HWFilePos(pEASData->hwInstData, pSMFStream->fileHandle, &pos)) != EAS_SUCCESS) + return result; + pos += (EAS_I32) len; + + /* end of track? */ + if (c == SMF_META_END_OF_TRACK) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Meta-event: end of track\n", c, len); */ } + pSMFStream->ticks = SMF_END_OF_TRACK; + } + + /* tempo event? */ + else if (c == SMF_META_TEMPO) + { + /* read the 3-byte timebase value */ + temp = 0; + while (len--) + { + if ((result = EAS_HWGetByte(pEASData->hwInstData, pSMFStream->fileHandle, &c)) != EAS_SUCCESS) + return result; + temp = (temp << 8) | c; + } + + pSMFData->tickConv = (EAS_U16) (((temp * 1024) / pSMFData->ppqn + 500) / 1000); + pSMFData->flags |= SMF_FLAGS_HAS_TEMPO; + } + + /* check for time signature - see iMelody spec V1.4 section 4.1.2.2.3.6 */ + else if (c == SMF_META_TIME_SIGNATURE) + { + pSMFData->flags |= SMF_FLAGS_HAS_TIME_SIG; + } + + /* if the host has registered a metadata callback return the metadata */ + else if (pSMFData->metadata.callback) + { + EAS_I32 readLen; + E_EAS_METADATA_TYPE metaType; + + metaType = EAS_METADATA_UNKNOWN; + + /* only process title on the first track */ + if (c == SMF_META_SEQTRK_NAME) + metaType = EAS_METADATA_TITLE; + else if (c == SMF_META_TEXT) + metaType = EAS_METADATA_TEXT; + else if (c == SMF_META_COPYRIGHT) + metaType = EAS_METADATA_COPYRIGHT; + else if (c == SMF_META_LYRIC) + metaType = EAS_METADATA_LYRIC; + + if (metaType != EAS_METADATA_UNKNOWN) + { + readLen = pSMFData->metadata.bufferSize - 1; + if ((EAS_I32) len < readLen) + readLen = (EAS_I32) len; + if ((result = EAS_HWReadFile(pEASData->hwInstData, pSMFStream->fileHandle, pSMFData->metadata.buffer, readLen, &readLen)) != EAS_SUCCESS) + return result; + pSMFData->metadata.buffer[readLen] = 0; + pSMFData->metadata.callback(metaType, pSMFData->metadata.buffer, pSMFData->metadata.pUserData); + } + } + + /* position file to next event - in case we ignored all or part of the meta-event */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pSMFStream->fileHandle, pos)) != EAS_SUCCESS) + return result; + + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Meta-event: type=%02x, len=%d\n", c, len); */ } + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_ParseSysEx() + *---------------------------------------------------------------------------- + * Purpose: + * Reads a varible length quantity from an SMF file + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT SMF_ParseSysEx (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream, EAS_U8 f0, EAS_INT parserMode) +{ + EAS_RESULT result; + EAS_U32 len; + EAS_U8 c; + + /* get the length */ + if ((result = SMF_GetVarLenData(pEASData->hwInstData, pSMFStream->fileHandle, &len)) != EAS_SUCCESS) + return result; + + /* start of SysEx message? */ + if (f0 == 0xf0) + { + if ((result = EAS_ParseMIDIStream(pEASData, pSMFData->pSynth, &pSMFStream->midiStream, f0, parserMode)) != EAS_SUCCESS) + return result; + } + + /* feed the SysEx to the stream parser */ + while (len--) + { + if ((result = EAS_HWGetByte(pEASData->hwInstData, pSMFStream->fileHandle, &c)) != EAS_SUCCESS) + return result; + if ((result = EAS_ParseMIDIStream(pEASData, pSMFData->pSynth, &pSMFStream->midiStream, c, parserMode)) != EAS_SUCCESS) + return result; + + /* check for GM system ON */ + if (pSMFStream->midiStream.flags & MIDI_FLAG_GM_ON) + pSMFData->flags |= SMF_FLAGS_HAS_GM_ON; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_ParseEvent() + *---------------------------------------------------------------------------- + * Purpose: + * Reads a varible length quantity from an SMF file + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT SMF_ParseEvent (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream, EAS_INT parserMode) +{ + EAS_RESULT result; + EAS_U8 c; + + /* get the event type */ + if ((result = EAS_HWGetByte(pEASData->hwInstData, pSMFStream->fileHandle, &c)) != EAS_SUCCESS) + return result; + + /* parse meta-event */ + if (c == 0xff) + { + if ((result = SMF_ParseMetaEvent(pEASData, pSMFData, pSMFStream)) != EAS_SUCCESS) + return result; + } + + /* parse SysEx */ + else if ((c == 0xf0) || (c == 0xf7)) + { + if ((result = SMF_ParseSysEx(pEASData, pSMFData, pSMFStream, c, parserMode)) != EAS_SUCCESS) + return result; + } + + /* parse MIDI message */ + else + { + if ((result = EAS_ParseMIDIStream(pEASData, pSMFData->pSynth, &pSMFStream->midiStream, c, parserMode)) != EAS_SUCCESS) + return result; + + /* keep streaming data to the MIDI parser until the message is complete */ + while (pSMFStream->midiStream.pending) + { + if ((result = EAS_HWGetByte(pEASData->hwInstData, pSMFStream->fileHandle, &c)) != EAS_SUCCESS) + return result; + if ((result = EAS_ParseMIDIStream(pEASData, pSMFData->pSynth, &pSMFStream->midiStream, c, parserMode)) != EAS_SUCCESS) + return result; + } + + } + + /* chase mode logic */ + if (pSMFData->time == 0) + { + if (pSMFData->flags & SMF_FLAGS_CHASE_MODE) + { + if (pSMFStream->midiStream.flags & MIDI_FLAG_FIRST_NOTE) + pSMFData->flags &= ~SMF_FLAGS_CHASE_MODE; + } + else if ((pSMFData->flags & SMF_FLAGS_SETUP_BAR) == SMF_FLAGS_SETUP_BAR) + pSMFData->flags = (pSMFData->flags & ~SMF_FLAGS_SETUP_BAR) | SMF_FLAGS_CHASE_MODE; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_ParseHeader() + *---------------------------------------------------------------------------- + * Purpose: + * Parses the header of an SMF file, allocates memory the stream parsers and initializes the + * stream parsers. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * pSMFData - pointer to parser instance data + * fileHandle - file handle + * fileOffset - offset in the file where the header data starts, usually 0 + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -e{801} we know that 'goto' is deprecated - but it's cleaner in this case */ +EAS_RESULT SMF_ParseHeader (EAS_HW_DATA_HANDLE hwInstData, S_SMF_DATA *pSMFData) +{ + EAS_RESULT result; + EAS_I32 i; + EAS_U16 division; + EAS_U32 chunkSize; + EAS_U32 chunkStart; + EAS_U32 temp; + EAS_U32 ticks; + + /* rewind the file and find the end of the header chunk */ + if ((result = EAS_HWFileSeek(hwInstData, pSMFData->fileHandle, pSMFData->fileOffset + SMF_OFS_HEADER_SIZE)) != EAS_SUCCESS) + goto ReadError; + if ((result = EAS_HWGetDWord(hwInstData, pSMFData->fileHandle, &chunkSize, EAS_TRUE)) != EAS_SUCCESS) + goto ReadError; + + /* determine the number of tracks */ + if ((result = EAS_HWFileSeek(hwInstData, pSMFData->fileHandle, pSMFData->fileOffset + SMF_OFS_NUM_TRACKS)) != EAS_SUCCESS) + goto ReadError; + if ((result = EAS_HWGetWord(hwInstData, pSMFData->fileHandle, &pSMFData->numStreams, EAS_TRUE)) != EAS_SUCCESS) + goto ReadError; + + /* limit the number of tracks */ + if (pSMFData->numStreams > MAX_SMF_STREAMS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "SMF file contains %u tracks, playing %d tracks\n", pSMFData->numStreams, MAX_SMF_STREAMS); */ } + pSMFData->numStreams = MAX_SMF_STREAMS; + } + + /* get the time division */ + if ((result = EAS_HWGetWord(hwInstData, pSMFData->fileHandle, &division, EAS_TRUE)) != EAS_SUCCESS) + goto ReadError; + + /* setup default timebase for 120 bpm */ + pSMFData->ppqn = 192; + if (division & 0x8000) + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING,"No support for SMPTE code timebase\n"); */ } + else + pSMFData->ppqn = (division & 0x7fff); + pSMFData->tickConv = (EAS_U16) (((SMF_DEFAULT_TIMEBASE * 1024) / pSMFData->ppqn + 500) / 1000); + + /* dynamic memory allocation, allocate memory for streams */ + if (pSMFData->streams == NULL) + { + pSMFData->streams = EAS_HWMalloc(hwInstData,sizeof(S_SMF_STREAM) * pSMFData->numStreams); + if (pSMFData->streams == NULL) + return EAS_ERROR_MALLOC_FAILED; + + /* zero the memory to insure complete initialization */ + EAS_HWMemSet((void *)(pSMFData->streams), 0, sizeof(S_SMF_STREAM) * pSMFData->numStreams); + } + + /* find the start of each track */ + chunkStart = (EAS_U32) pSMFData->fileOffset; + ticks = 0x7fffffffL; + pSMFData->nextStream = NULL; + for (i = 0; i < pSMFData->numStreams; i++) + { + + for (;;) + { + + /* calculate start of next chunk - checking for errors */ + temp = chunkStart + SMF_CHUNK_INFO_SIZE + chunkSize; + if (temp <= chunkStart) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING,"Error in chunk size at offset %d\n", chunkStart); */ } + return EAS_ERROR_FILE_FORMAT; + } + chunkStart = temp; + + /* seek to the start of the next chunk */ + if ((result = EAS_HWFileSeek(hwInstData, pSMFData->fileHandle, (EAS_I32) chunkStart)) != EAS_SUCCESS) + goto ReadError; + + /* read the chunk identifier */ + if ((result = EAS_HWGetDWord(hwInstData, pSMFData->fileHandle, &temp, EAS_TRUE)) != EAS_SUCCESS) + goto ReadError; + + /* read the chunk size */ + if ((result = EAS_HWGetDWord(hwInstData, pSMFData->fileHandle, &chunkSize, EAS_TRUE)) != EAS_SUCCESS) + goto ReadError; + + /* make sure this is an 'MTrk' chunk */ + if (temp == SMF_CHUNK_TYPE_TRACK) + break; + + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING,"Unexpected chunk type: 0x%08x\n", temp); */ } + } + + /* initalize some data */ + pSMFData->streams[i].ticks = 0; + pSMFData->streams[i].fileHandle = pSMFData->fileHandle; + + /* NULL the file handle so we don't try to close it twice */ + pSMFData->fileHandle = NULL; + + /* save this file position as the start of the track */ + pSMFData->streams[i].startFilePos = (EAS_I32) chunkStart + SMF_CHUNK_INFO_SIZE; + + /* initalize the MIDI parser data */ + EAS_InitMIDIStream(&pSMFData->streams[i].midiStream); + + /* parse the first delta time in each stream */ + if ((result = SMF_GetDeltaTime(hwInstData, &pSMFData->streams[i])) != EAS_SUCCESS) + goto ReadError; + + if (pSMFData->streams[i].ticks < ticks) + { + ticks = pSMFData->streams[i].ticks; + pSMFData->nextStream = &pSMFData->streams[i]; + } + + /* more tracks to do, create a duplicate file handle */ + if (i < (pSMFData->numStreams - 1)) + { + if ((result = EAS_HWDupHandle(hwInstData, pSMFData->streams[i].fileHandle, &pSMFData->fileHandle)) != EAS_SUCCESS) + goto ReadError; + } + } + + /* update the time of the next event */ + if (pSMFData->nextStream) + SMF_UpdateTime(pSMFData, pSMFData->nextStream->ticks); + + return EAS_SUCCESS; + + /* ugly goto: but simpler than structured */ + ReadError: + if (result == EAS_EOF) + return EAS_ERROR_FILE_FORMAT; + return result; +} + +/*---------------------------------------------------------------------------- + * SMF_UpdateTime() + *---------------------------------------------------------------------------- + * Purpose: + * Update the millisecond time base by converting the ticks into millieconds + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static void SMF_UpdateTime (S_SMF_DATA *pSMFData, EAS_U32 ticks) +{ + EAS_U32 temp1, temp2; + + if (pSMFData->flags & SMF_FLAGS_CHASE_MODE) + return; + + temp1 = (ticks >> 10) * pSMFData->tickConv; + temp2 = (ticks & 0x3ff) * pSMFData->tickConv; + pSMFData->time += (EAS_I32)((temp1 << 8) + (temp2 >> 2)); +} + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_smf.h b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_smf.h new file mode 100755 index 0000000..37c0790 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_smf.h @@ -0,0 +1,49 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_smf.h + * + * Contents and purpose: + * SMF Type 0 and 1 File Parser + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_SMF_H +#define _EAS_SMF_H + +/* prototypes for private interface to SMF parser */ +EAS_RESULT SMF_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset); +EAS_RESULT SMF_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +EAS_RESULT SMF_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime); +EAS_RESULT SMF_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode); +EAS_RESULT SMF_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_STATE *pState); +EAS_RESULT SMF_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +EAS_RESULT SMF_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +EAS_RESULT SMF_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +EAS_RESULT SMF_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +EAS_RESULT SMF_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value); +EAS_RESULT SMF_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue); +EAS_RESULT SMF_ParseHeader (EAS_HW_DATA_HANDLE hwInstData, S_SMF_DATA *pSMFData); + +#endif /* end _EAS_SMF_H */ + + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_smfdata.c b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_smfdata.c new file mode 100755 index 0000000..383d7f3 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_smfdata.c @@ -0,0 +1,66 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_smfdata.c + * + * Contents and purpose: + * SMF File Parser + * + * This file contains data definitions for the SMF parser. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 778 $ + * $Date: 2007-07-23 16:45:17 -0700 (Mon, 23 Jul 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_miditypes.h" +#include "eas_smfdata.h" + +/*---------------------------------------------------------------------------- + * + * S_SMF_STREAM + * + * Static memory allocation for SMF parser + *---------------------------------------------------------------------------- +*/ +static S_SMF_STREAM eas_SMFStreams[MAX_SMF_STREAMS]; + +/*---------------------------------------------------------------------------- + * + * eas_SMFData + * + * Static memory allocation for SMF parser + *---------------------------------------------------------------------------- +*/ +S_SMF_DATA eas_SMFData = +{ + eas_SMFStreams, /* pointer to individual streams in file */ + 0, /* pointer to next stream with event */ + 0, /* pointer to synth */ + 0, /* file handle */ + { 0, 0, 0, 0}, /* metadata callback */ + 0, /* file offset */ + 0, /* current time in milliseconds/256 */ + 0, /* actual number of streams */ + 0, /* current MIDI tick to msec conversion */ + 0, /* ticks per quarter note */ + 0, /* current state EAS_STATE_XXXX */ + 0 /* flags */ +}; + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_smfdata.h b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_smfdata.h new file mode 100755 index 0000000..8861d90 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_smfdata.h @@ -0,0 +1,66 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_smfdata.h + * + * Contents and purpose: + * SMF File Parser + * + * This file contains data definitions for the SMF parser. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 686 $ + * $Date: 2007-05-03 14:10:54 -0700 (Thu, 03 May 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_SMF_DATA_H +#define _EAS_SMF_DATA_H + +#ifndef MAX_SMF_STREAMS +#define MAX_SMF_STREAMS 17 +#endif + +/* offsets in to the SMF file */ +#define SMF_OFS_HEADER_SIZE 4 +#define SMF_OFS_FILE_TYPE 8 +#define SMF_OFS_NUM_TRACKS 10 + +/* size of chunk info (chunk ID + chunk size) */ +#define SMF_CHUNK_INFO_SIZE 8 + +/* 'MTrk' track chunk ID */ +#define SMF_CHUNK_TYPE_TRACK 0x4d54726bL + +/* some useful meta-events */ +#define SMF_META_TEXT 0x01 +#define SMF_META_COPYRIGHT 0x02 +#define SMF_META_SEQTRK_NAME 0x03 +#define SMF_META_LYRIC 0x05 +#define SMF_META_END_OF_TRACK 0x2f +#define SMF_META_TEMPO 0x51 +#define SMF_META_TIME_SIGNATURE 0x58 + +/* default timebase (120BPM) */ +#define SMF_DEFAULT_TIMEBASE 500000L + +/* value for pSMFStream->ticks to signify end of track */ +#define SMF_END_OF_TRACK 0xffffffff + +#endif + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_sndlib.h b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_sndlib.h new file mode 100755 index 0000000..416be6e --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_sndlib.h @@ -0,0 +1,406 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_sndlib.h + * + * Contents and purpose: + * Declarations for the sound library + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 550 $ + * $Date: 2007-02-02 09:37:03 -0800 (Fri, 02 Feb 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_SNDLIB_H +#define _EAS_SNDLIB_H + +#include "eas_types.h" +#include "eas_synthcfg.h" + +#ifdef _WT_SYNTH +#include "eas_wtengine.h" +#endif + +/*---------------------------------------------------------------------------- + * This is bit of a hack to allow us to keep the same structure + * declarations for the DLS parser. Normally, the data is located + * in read-only memory, but for DLS, we store the data in RW + * memory. + *---------------------------------------------------------------------------- +*/ +#ifndef SCNST +#define SCNST const +#endif + +/*---------------------------------------------------------------------------- + * sample size + *---------------------------------------------------------------------------- +*/ +#ifdef _16_BIT_SAMPLES +typedef EAS_I16 EAS_SAMPLE; +#else +typedef EAS_I8 EAS_SAMPLE; +#endif + +/*---------------------------------------------------------------------------- + * EAS Library ID - quick check for valid library and version + *---------------------------------------------------------------------------- +*/ +#define _EAS_LIBRARY_VERSION 0x01534145 + +#define NUM_PROGRAMS_IN_BANK 128 +#define INVALID_REGION_INDEX 0xffff + +/* this bit in region index indicates that region is for secondary synth */ +#define FLAG_RGN_IDX_FM_SYNTH 0x8000 +#define FLAG_RGN_IDX_DLS_SYNTH 0x4000 +#define REGION_INDEX_MASK 0x3fff + +/*---------------------------------------------------------------------------- + * Generic region data structure + * + * This must be the first element in each region structure + *---------------------------------------------------------------------------- +*/ +typedef struct s_region_tag +{ + EAS_U16 keyGroupAndFlags; + EAS_U8 rangeLow; + EAS_U8 rangeHigh; +} S_REGION; + +/* + * Bit fields for m_nKeyGroupAndFlags + * Bits 0-2 are mode bits in FM synth + * Bits 8-11 are the key group + */ +#define REGION_FLAG_IS_LOOPED 0x01 +#define REGION_FLAG_USE_WAVE_GENERATOR 0x02 +#define REGION_FLAG_USE_ADPCM 0x04 +#define REGION_FLAG_ONE_SHOT 0x08 +#define REGION_FLAG_SQUARE_WAVE 0x10 +#define REGION_FLAG_OFF_CHIP 0x20 +#define REGION_FLAG_NON_SELF_EXCLUSIVE 0x40 +#define REGION_FLAG_LAST_REGION 0x8000 + +/*---------------------------------------------------------------------------- + * Envelope data structure + *---------------------------------------------------------------------------- +*/ +typedef struct s_envelope_tag +{ + EAS_I16 attackTime; + EAS_I16 decayTime; + EAS_I16 sustainLevel; + EAS_I16 releaseTime; +} S_ENVELOPE; + +/*---------------------------------------------------------------------------- + * DLS envelope data structure + *---------------------------------------------------------------------------- +*/ +typedef struct s_dls_envelope_tag +{ + EAS_I16 delayTime; + EAS_I16 attackTime; + EAS_I16 holdTime; + EAS_I16 decayTime; + EAS_I16 sustainLevel; + EAS_I16 releaseTime; + EAS_I16 velToAttack; + EAS_I16 keyNumToDecay; + EAS_I16 keyNumToHold; +} S_DLS_ENVELOPE; + +/*---------------------------------------------------------------------------- + * LFO data structure + *---------------------------------------------------------------------------- +*/ +typedef struct s_lfo_params_tag +{ + EAS_I16 lfoFreq; + EAS_I16 lfoDelay; +} S_LFO_PARAMS; + +/*---------------------------------------------------------------------------- + * Articulation data structure + *---------------------------------------------------------------------------- +*/ +typedef struct s_articulation_tag +{ + S_ENVELOPE eg1; + S_ENVELOPE eg2; + EAS_I16 lfoToPitch; + EAS_I16 lfoDelay; + EAS_I16 lfoFreq; + EAS_I16 eg2ToPitch; + EAS_I16 eg2ToFc; + EAS_I16 filterCutoff; + EAS_I8 lfoToGain; + EAS_U8 filterQ; + EAS_I8 pan; +} S_ARTICULATION; + +/*---------------------------------------------------------------------------- + * DLS articulation data structure + *---------------------------------------------------------------------------- +*/ + +typedef struct s_dls_articulation_tag +{ + S_LFO_PARAMS modLFO; + S_LFO_PARAMS vibLFO; + + S_DLS_ENVELOPE eg1; + S_DLS_ENVELOPE eg2; + + EAS_I16 eg1ShutdownTime; + + EAS_I16 filterCutoff; + EAS_I16 modLFOToFc; + EAS_I16 modLFOCC1ToFc; + EAS_I16 modLFOChanPressToFc; + EAS_I16 eg2ToFc; + EAS_I16 velToFc; + EAS_I16 keyNumToFc; + + EAS_I16 modLFOToGain; + EAS_I16 modLFOCC1ToGain; + EAS_I16 modLFOChanPressToGain; + + EAS_I16 tuning; + EAS_I16 keyNumToPitch; + EAS_I16 vibLFOToPitch; + EAS_I16 vibLFOCC1ToPitch; + EAS_I16 vibLFOChanPressToPitch; + EAS_I16 modLFOToPitch; + EAS_I16 modLFOCC1ToPitch; + EAS_I16 modLFOChanPressToPitch; + EAS_I16 eg2ToPitch; + + /* pad to 4-byte boundary */ + EAS_U16 pad; + + EAS_I8 pan; + EAS_U8 filterQandFlags; + +#ifdef _REVERB + EAS_I16 reverbSend; + EAS_I16 cc91ToReverbSend; +#endif + +#ifdef _CHORUS + EAS_I16 chorusSend; + EAS_I16 cc93ToChorusSend; +#endif +} S_DLS_ARTICULATION; + +/* flags in filterQandFlags + * NOTE: Q is stored in bottom 5 bits + */ +#define FLAG_DLS_VELOCITY_SENSITIVE 0x80 +#define FILTER_Q_MASK 0x1f + +/*---------------------------------------------------------------------------- + * Wavetable region data structure + *---------------------------------------------------------------------------- +*/ +typedef struct s_wt_region_tag +{ + S_REGION region; + EAS_I16 tuning; + EAS_I16 gain; + EAS_U32 loopStart; + EAS_U32 loopEnd; + EAS_U16 waveIndex; + EAS_U16 artIndex; +} S_WT_REGION; + +/*---------------------------------------------------------------------------- + * DLS region data structure + *---------------------------------------------------------------------------- +*/ +typedef struct s_dls_region_tag +{ + S_WT_REGION wtRegion; + EAS_U8 velLow; + EAS_U8 velHigh; +} S_DLS_REGION; + +/*---------------------------------------------------------------------------- + * FM synthesizer data structures + *---------------------------------------------------------------------------- +*/ +typedef struct s_fm_oper_tag +{ + EAS_I16 tuning; + EAS_U8 attackDecay; + EAS_U8 velocityRelease; + EAS_U8 egKeyScale; + EAS_U8 sustain; + EAS_U8 gain; + EAS_U8 flags; +} S_FM_OPER; + +/* defines for S_FM_OPER.m_nFlags */ +#define FM_OPER_FLAG_MONOTONE 0x01 +#define FM_OPER_FLAG_NO_VIBRATO 0x02 +#define FM_OPER_FLAG_NOISE 0x04 +#define FM_OPER_FLAG_LINEAR_VELOCITY 0x08 + +/* NOTE: The first two structure elements are common with S_WT_REGION + * and we will rely on that in the voice management code and must + * remain there unless the voice management code is revisited. + */ +typedef struct s_fm_region_tag +{ + S_REGION region; + EAS_U8 vibTrem; + EAS_U8 lfoFreqDelay; + EAS_U8 feedback; + EAS_I8 pan; + S_FM_OPER oper[4]; +} S_FM_REGION; + +/*---------------------------------------------------------------------------- + * Common data structures + *---------------------------------------------------------------------------- +*/ + +/*---------------------------------------------------------------------------- + * Program data structure + * Used for individual programs not stored as a complete bank. + *---------------------------------------------------------------------------- +*/ +typedef struct s_program_tag +{ + EAS_U32 locale; + EAS_U16 regionIndex; +} S_PROGRAM; + +/*---------------------------------------------------------------------------- + * Bank data structure + * + * A bank always consists of 128 programs. If a bank is less than 128 + * programs, it should be stored as a spare matrix in the pPrograms + * array. + * + * bankNum: MSB/LSB of MIDI bank select controller + * regionIndex: Index of first region in program + *---------------------------------------------------------------------------- +*/ +typedef struct s_bank_tag +{ + EAS_U16 locale; + EAS_U16 regionIndex[NUM_PROGRAMS_IN_BANK]; +} S_BANK; + + +/* defines for libFormat field + * bits 0-17 are the sample rate + * bit 18 is true if wavetable is present + * bit 19 is true if FM is present + * bit 20 is true if filter is enabled + * bit 21 is sample depth (0 = 8-bits, 1 = 16-bits) + * bits 22-31 are reserved + */ +#define LIBFORMAT_SAMPLE_RATE_MASK 0x0003ffff +#define LIB_FORMAT_TYPE_MASK 0x000c0000 +#define LIB_FORMAT_WAVETABLE 0x00000000 +#define LIB_FORMAT_FM 0x00040000 +#define LIB_FORMAT_HYBRID 0x00080000 +#define LIB_FORMAT_FILTER_ENABLED 0x00100000 +#define LIB_FORMAT_16_BIT_SAMPLES 0x00200000 + +#ifdef DLS_SYNTHESIZER +/*---------------------------------------------------------------------------- + * DLS data structure + * + * pDLSPrograms pointer to array of DLS programs + * pDLSRegions pointer to array of DLS regions + * pDLSArticulations pointer to array of DLS articulations + * pSampleLen pointer to array of sample lengths + * ppSamples pointer to array of sample pointers + * numDLSPrograms number of DLS programs + * numDLSRegions number of DLS regions + * numDLSArticulations number of DLS articulations + * numDLSSamples number of DLS samples + *---------------------------------------------------------------------------- +*/ +typedef struct s_eas_dls_tag +{ + S_PROGRAM *pDLSPrograms; + S_DLS_REGION *pDLSRegions; + S_DLS_ARTICULATION *pDLSArticulations; + EAS_U32 *pDLSSampleLen; + EAS_U32 *pDLSSampleOffsets; + EAS_SAMPLE *pDLSSamples; + EAS_U16 numDLSPrograms; + EAS_U16 numDLSRegions; + EAS_U16 numDLSArticulations; + EAS_U16 numDLSSamples; + EAS_U8 refCount; +} S_DLS; +#endif + +/*---------------------------------------------------------------------------- + * Sound library data structure + * + * pBanks pointer to array of banks + * pPrograms pointer to array of programs + * pWTRegions pointer to array of wavetable regions + * pFMRegions pointer to array of FM regions + * pArticulations pointer to array of articulations + * pSampleLen pointer to array of sample lengths + * ppSamples pointer to array of sample pointers + * numBanks number of banks + * numPrograms number of individual program + * numRegions number of regions + * numArticulations number of articulations + * numSamples number of samples + *---------------------------------------------------------------------------- +*/ +typedef struct s_eas_sndlib_tag +{ + SCNST EAS_U32 identifier; + SCNST EAS_U32 libAttr; + + SCNST S_BANK *pBanks; + SCNST S_PROGRAM *pPrograms; + + SCNST S_WT_REGION *pWTRegions; + SCNST S_ARTICULATION *pArticulations; + SCNST EAS_U32 *pSampleLen; + SCNST EAS_U32 *pSampleOffsets; + SCNST EAS_SAMPLE *pSamples; + + SCNST S_FM_REGION *pFMRegions; + + SCNST EAS_U16 numBanks; + SCNST EAS_U16 numPrograms; + + SCNST EAS_U16 numWTRegions; + SCNST EAS_U16 numArticulations; + SCNST EAS_U16 numSamples; + + SCNST EAS_U16 numFMRegions; +} S_EAS; + +#endif + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_synth.h b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_synth.h new file mode 100755 index 0000000..6274b7d --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_synth.h @@ -0,0 +1,395 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_synth.h + * + * Contents and purpose: + * Declarations, interfaces, and prototypes for synth. + * + * Copyright Sonic Network Inc. 2004, 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 718 $ + * $Date: 2007-06-08 16:43:16 -0700 (Fri, 08 Jun 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_SYNTH_H +#define _EAS_SYNTH_H + +#include "eas_types.h" +#include "eas_sndlib.h" + +#ifdef _WT_SYNTH +#include "eas_wtsynth.h" +#endif + +#ifdef _FM_SYNTH +#include "eas_fmsynth.h" +#endif + +#ifndef NUM_OUTPUT_CHANNELS +#define NUM_OUTPUT_CHANNELS 2 +#endif + +#ifndef MAX_SYNTH_VOICES +#define MAX_SYNTH_VOICES 64 +#endif + +#ifndef MAX_VIRTUAL_SYNTHESIZERS +#define MAX_VIRTUAL_SYNTHESIZERS 4 +#endif + +/* defines */ +#ifndef NUM_PRIMARY_VOICES +#define NUM_PRIMARY_VOICES MAX_SYNTH_VOICES +#elif !defined(NUM_SECONDARY_VOICES) +#define NUM_SECONDARY_VOICES (MAX_SYNTH_VOICES - NUM_PRIMARY_VOICES) +#endif + +#if defined(EAS_WT_SYNTH) +#define NUM_WT_VOICES MAX_SYNTH_VOICES + +/* FM on MCU */ +#elif defined(EAS_FM_SYNTH) +#define NUM_FM_VOICES MAX_SYNTH_VOICES + +/* wavetable drums on MCU, wavetable melodic on DSP */ +#elif defined(EAS_SPLIT_WT_SYNTH) +#define NUM_WT_VOICES MAX_SYNTH_VOICES + +/* wavetable drums and FM melodic on MCU */ +#elif defined(EAS_HYBRID_SYNTH) +#define NUM_WT_VOICES NUM_PRIMARY_VOICES +#define NUM_FM_VOICES NUM_SECONDARY_VOICES + +/* wavetable drums on MCU, FM melodic on DSP */ +#elif defined(EAS_SPLIT_HYBRID_SYNTH) +#define NUM_WT_VOICES NUM_PRIMARY_VOICES +#define NUM_FM_VOICES NUM_SECONDARY_VOICES + +/* FM synth on DSP */ +#elif defined(EAS_SPLIT_FM_SYNTH) +#define NUM_FM_VOICES MAX_SYNTH_VOICES + +#else +#error "Unrecognized architecture option" +#endif + +#define NUM_SYNTH_CHANNELS 16 + +#define DEFAULT_SYNTH_VOICES MAX_SYNTH_VOICES + +/* use the following values to specify unassigned channels or voices */ +#define UNASSIGNED_SYNTH_CHANNEL NUM_SYNTH_CHANNELS +#define UNASSIGNED_SYNTH_VOICE MAX_SYNTH_VOICES + + +/* synth parameters are updated every SYNTH_UPDATE_PERIOD_IN_SAMPLES */ +#define SYNTH_UPDATE_PERIOD_IN_SAMPLES (EAS_I32)(0x1L << SYNTH_UPDATE_PERIOD_IN_BITS) + +/* stealing weighting factors */ +#define NOTE_AGE_STEAL_WEIGHT 1 +#define NOTE_GAIN_STEAL_WEIGHT 4 +#define CHANNEL_POLY_STEAL_WEIGHT 12 +#define CHANNEL_PRIORITY_STEAL_WEIGHT 2 +#define NOTE_MATCH_PENALTY 128 +#define SYNTH_PRIORITY_WEIGHT 8 + +/* default synth master volume */ +#define DEFAULT_SYNTH_MASTER_VOLUME 0x7fff + +#define DEFAULT_SYNTH_PRIORITY 5 + +/* default tuning values */ +#define DEFAULT_PITCH_BEND_SENSITIVITY 200 /* 2 semitones */ +#define DEFAULT_FINE_PITCH 0 /* 0 cents */ +#define DEFAULT_COARSE_PITCH 0 /* 0 semitones */ + +/* default drum channel is 10, but is internally 9 due to unit offset */ +#define DEFAULT_DRUM_CHANNEL 9 + +/* drum channel can simultaneously play this many voices at most */ +#define DEFAULT_CHANNEL_POLYPHONY_LIMIT 2 + +/* default instrument is acoustic piano */ +#define DEFAULT_MELODY_BANK_MSB 0x79 +#define DEFAULT_RHYTHM_BANK_MSB 0x78 +#define DEFAULT_MELODY_BANK_NUMBER (DEFAULT_MELODY_BANK_MSB << 8) +#define DEFAULT_RHYTHM_BANK_NUMBER (DEFAULT_RHYTHM_BANK_MSB << 8) +#define DEFAULT_SYNTH_PROGRAM_NUMBER 0 + +#define DEFAULT_PITCH_BEND 0x2000 /* 0x2000 == (0x40 << 7) | 0x00 */ +#define DEFAULT_MOD_WHEEL 0 +#define DEFAULT_CHANNEL_VOLUME 0x64 +#define DEFAULT_PAN 0x40 /* decimal 64, center */ + +#ifdef _REVERB +#define DEFAULT_REVERB_SEND 40 /* some reverb */ +#endif + +#ifdef _CHORUS +#define DEFAULT_CHORUS_SEND 0 /* no chorus */ +#endif + +#define DEFAULT_EAS_FILTER_CUTOFF_FREQUENCY 0 /* EAS synth uses a different default */ +#define DEFAULT_FILTER_RESONANCE 0 +#define DEFAULT_EXPRESSION 0x7F + +#define DEFAULT_CHANNEL_PRESSURE 0 + +#define DEFAULT_REGISTERED_PARAM 0x3FFF + +#define DEFAULT_CHANNEL_STATIC_GAIN 0 +#define DEFAULT_CHANNEL_STATIC_PITCH 0 + +#define DEFAULT_LFO_MOD_WHEEL_TO_PITCH_CENTS 50 +#define DEFAULT_LFO_CHANNEL_PRESSURE_TO_PITCH_CENTS 50 + +#define DEFAULT_KEY_NUMBER 0x69 +#define DEFAULT_VELOCITY 0x64 +#define DEFAULT_REGION_INDEX 0 +#define DEFAULT_ARTICULATION_INDEX 0 +#define DEFAULT_VOICE_GAIN 0 +#define DEFAULT_AGE 0 +#define DEFAULT_SP_MIDI_PRIORITY 16 + + +/* filter defines */ +#define DEFAULT_FILTER_ZERO 0 +#define FILTER_CUTOFF_MAX_PITCH_CENTS 1919 +#define FILTER_CUTOFF_MIN_PITCH_CENTS -4467 +#define A5_PITCH_OFFSET_IN_CENTS 6900 + +/*------------------------------------ + * S_SYNTH_CHANNEL data structure + *------------------------------------ +*/ + +/* S_SYNTH_CHANNEL.m_nFlags */ +#define CHANNEL_FLAG_SUSTAIN_PEDAL 0x01 +#define CHANNEL_FLAG_MUTE 0x02 +#define CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS 0x04 +#define CHANNEL_FLAG_RHYTHM_CHANNEL 0x08 +#define CHANNEL_FLAG_EXTERNAL_AUDIO 0x10 +#define DEFAULT_CHANNEL_FLAGS 0 + +/* macros for extracting virtual synth and channel numbers */ +#define GET_VSYNTH(a) ((a) >> 4) +#define GET_CHANNEL(a) ((a) & 15) + +typedef struct s_synth_channel_tag +{ + /* use static channel parameters to reduce MIPs */ + /* parameters shared by multiple voices assigned to same channel */ + EAS_I32 staticPitch; /* (pitch bend * pitch sens) + fine pitch */ + EAS_I16 staticGain; /* (CC7 * CC11 * master vol)^2 */ + + EAS_U16 regionIndex; /* index of first region in program */ + + EAS_U16 bankNum; /* play programs from this bank */ + EAS_I16 pitchBend; /* pitch wheel value */ + EAS_I16 pitchBendSensitivity; + EAS_I16 registeredParam; /* currently selected registered param */ + + +#if defined(_FM_SYNTH) + EAS_I16 lfoAmt; /* amount of LFO to apply to voice */ +#endif + + EAS_U8 programNum; /* play this instrument number */ + EAS_U8 modWheel; /* CC1 */ + EAS_U8 volume; /* CC7 */ + EAS_U8 pan; /* CC10 */ + + EAS_U8 expression; /* CC11 */ + + /* the following parameters are controlled by RPNs */ + EAS_I8 finePitch; + EAS_I8 coarsePitch; + + EAS_U8 channelPressure; /* applied to all voices on a given channel */ + + EAS_U8 channelFlags; /* bit field channelFlags for */ + /* CC64, SP-MIDI channel masking */ + + EAS_U8 pool; /* SPMIDI channel voice pool */ + EAS_U8 mip; /* SPMIDI MIP setting */ + +#ifdef _REVERB + EAS_U8 reverbSend; /* CC91 */ +#endif + +#ifdef _CHORUS + EAS_U8 chorusSend; /* CC93 */ +#endif +} S_SYNTH_CHANNEL; + +/*------------------------------------ + * S_SYNTH_VOICE data structure + *------------------------------------ +*/ + +/* S_SYNTH_VOICE.m_nFlags */ +#define VOICE_FLAG_UPDATE_VOICE_PARAMETERS 0x01 +#define VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF 0x02 +#define VOICE_FLAG_DEFER_MIDI_NOTE_OFF 0x04 +#define VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET 0x08 +#define VOICE_FLAG_DEFER_MUTE 0x40 +#define DEFAULT_VOICE_FLAGS 0 + +/* S_SYNTH_VOICE.m_eState */ +typedef enum { + + eVoiceStateFree = 0, + eVoiceStateStart, + eVoiceStatePlay, + eVoiceStateRelease, + eVoiceStateMuting, + eVoiceStateStolen, + eVoiceStateInvalid /* should never be in this state! */ + +} E_VOICE_STATE; +#define DEFAULT_VOICE_STATE eVoiceStateFree + +typedef struct s_synth_voice_tag +{ + +/* These parameters are common to both wavetable and FM + * synthesizers. The voice manager should only access this data. + * Any other data should be manipulated by the code that is + * specific to that synthesizer and reflected back through the + * common state data available here. + */ + EAS_U16 regionIndex; /* index to wave and playback params */ + EAS_I16 gain; /* current gain */ + EAS_U16 age; /* large value means old note */ + EAS_U16 nextRegionIndex; /* index to wave and playback params */ + EAS_U8 voiceState; /* current voice state */ + EAS_U8 voiceFlags; /* misc flags/bit fields */ + EAS_U8 channel; /* this voice plays on this synth channel */ + EAS_U8 note; /* 12 <= key number <= 108 */ + EAS_U8 velocity; /* 0 <= velocity <= 127 */ + EAS_U8 nextChannel; /* play stolen voice on this channel */ + EAS_U8 nextNote; /* 12 <= key number <= 108 */ + EAS_U8 nextVelocity; /* 0 <= velocity <= 127 */ +} S_SYNTH_VOICE; + +/*------------------------------------ + * S_SYNTH data structure + * + * One instance for each MIDI stream + *------------------------------------ +*/ + +/* S_SYNTH.m_nFlags */ +#define SYNTH_FLAG_RESET_IS_REQUESTED 0x01 +#define SYNTH_FLAG_SP_MIDI_ON 0x02 +#define SYNTH_FLAG_UPDATE_ALL_CHANNEL_PARAMETERS 0x04 +#define SYNTH_FLAG_DEFERRED_MIDI_NOTE_OFF_PENDING 0x08 +#define DEFAULT_SYNTH_FLAGS SYNTH_FLAG_UPDATE_ALL_CHANNEL_PARAMETERS + +typedef struct s_synth_tag +{ + struct s_eas_data_tag *pEASData; + const S_EAS *pEAS; + +#ifdef DLS_SYNTHESIZER + S_DLS *pDLS; +#endif + +#ifdef EXTERNAL_AUDIO + EAS_EXT_PRG_CHG_FUNC cbProgChgFunc; + EAS_EXT_EVENT_FUNC cbEventFunc; + EAS_VOID_PTR *pExtAudioInstData; +#endif + + S_SYNTH_CHANNEL channels[NUM_SYNTH_CHANNELS]; + EAS_I32 totalNoteCount; + EAS_U16 maxPolyphony; + EAS_U16 numActiveVoices; + EAS_U16 masterVolume; + EAS_U8 channelsByPriority[NUM_SYNTH_CHANNELS]; + EAS_U8 poolCount[NUM_SYNTH_CHANNELS]; + EAS_U8 poolAlloc[NUM_SYNTH_CHANNELS]; + EAS_U8 synthFlags; + EAS_I8 globalTranspose; + EAS_U8 vSynthNum; + EAS_U8 refCount; + EAS_U8 priority; +} S_SYNTH; + +/*------------------------------------ + * S_VOICE_MGR data structure + * + * One instance for each EAS library instance + *------------------------------------ +*/ +typedef struct s_voice_mgr_tag +{ + S_SYNTH *pSynth[MAX_VIRTUAL_SYNTHESIZERS]; + EAS_PCM voiceBuffer[SYNTH_UPDATE_PERIOD_IN_SAMPLES]; + +#ifdef _FM_SYNTH + EAS_PCM operMixBuffer[SYNTH_UPDATE_PERIOD_IN_SAMPLES]; + S_FM_VOICE fmVoices[NUM_FM_VOICES]; +#endif + +#ifdef _WT_SYNTH + S_WT_VOICE wtVoices[NUM_WT_VOICES]; +#endif + +#ifdef _REVERB + EAS_PCM reverbSendBuffer[NUM_OUTPUT_CHANNELS * SYNTH_UPDATE_PERIOD_IN_SAMPLES]; +#endif + +#ifdef _CHORUS + EAS_PCM chorusSendBuffer[NUM_OUTPUT_CHANNELS * SYNTH_UPDATE_PERIOD_IN_SAMPLES]; +#endif + S_SYNTH_VOICE voices[MAX_SYNTH_VOICES]; + + EAS_SNDLIB_HANDLE pGlobalEAS; + +#ifdef DLS_SYNTHESIZER + S_DLS *pGlobalDLS; +#endif + +#ifdef _SPLIT_ARCHITECTURE + EAS_FRAME_BUFFER_HANDLE pFrameBuffer; +#endif + +#if defined(_SECONDARY_SYNTH) || defined(EAS_SPLIT_WT_SYNTH) + EAS_U16 maxPolyphonyPrimary; + EAS_U16 maxPolyphonySecondary; +#endif + + EAS_I32 workload; + EAS_I32 maxWorkLoad; + + EAS_U16 activeVoices; + EAS_U16 maxPolyphony; + + EAS_U16 age; + +/* limits the number of voice starts in a frame for split architecture */ +#ifdef MAX_VOICE_STARTS + EAS_U16 numVoiceStarts; +#endif +} S_VOICE_MGR; + +#endif /* #ifdef _EAS_SYNTH_H */ + + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_synth_protos.h b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_synth_protos.h new file mode 100755 index 0000000..b03af0f --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_synth_protos.h @@ -0,0 +1,60 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_synth_protos.h + * + * Contents and purpose: + * Declarations, interfaces, and prototypes for synth. + * + * Copyright Sonic Network Inc. 2004 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_SYNTH_PROTOS_H +#define _EAS_SYNTH_PROTOS_H + +/* includes */ +#include "eas_data.h" +#include "eas_sndlib.h" + +#ifdef _SPLIT_ARCHITECTURE +typedef struct s_frame_interface_tag +{ + EAS_BOOL (* EAS_CONST pfStartFrame)(EAS_FRAME_BUFFER_HANDLE pFrameBuffer); + EAS_BOOL (* EAS_CONST pfEndFrame)(EAS_FRAME_BUFFER_HANDLE pFrameBuffer, EAS_I32 *pMixBuffer, EAS_I16 masterGain); +} S_FRAME_INTERFACE; +#endif + +/* generic synthesizer interface */ +typedef struct +{ + EAS_RESULT (* EAS_CONST pfInitialize)(S_VOICE_MGR *pVoiceMgr); + EAS_RESULT (* EAS_CONST pfStartVoice)(S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_U16 regionIndex); + EAS_BOOL (* EAS_CONST pfUpdateVoice)(S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_I32 *pMixBuffer, EAS_I32 numSamples); + void (* EAS_CONST pfReleaseVoice)(S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum); + void (* EAS_CONST pfMuteVoice)(S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum); + void (* EAS_CONST pfSustainPedal)(S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, S_SYNTH_CHANNEL *pChannel, EAS_I32 voiceNum); + void (* EAS_CONST pfUpdateChannel)(S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel); +} S_SYNTH_INTERFACE; + +#endif + + + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_synthcfg.h b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_synthcfg.h new file mode 100755 index 0000000..78a4178 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_synthcfg.h @@ -0,0 +1,70 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_synthcfg.h + * + * Contents and purpose: + * Defines for various synth configurations + * + * Copyright Sonic Network Inc. 2004, 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 664 $ + * $Date: 2007-04-25 13:11:22 -0700 (Wed, 25 Apr 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_SYNTHCFG_H +#define _EAS_SYNTHCFG_H + +#if defined(EAS_WT_SYNTH) +#define _WT_SYNTH + +/* FM on MCU */ +#elif defined(EAS_FM_SYNTH) +#define _FM_SYNTH + +/* wavetable drums and FM melodic on MCU */ +#elif defined(EAS_HYBRID_SYNTH) +#define _WT_SYNTH +#define _FM_SYNTH +#define _SECONDARY_SYNTH +#define _HYBRID_SYNTH + +/* wavetable drums on MCU, wavetable melodic on DSP */ +#elif defined(EAS_SPLIT_WT_SYNTH) +#define _WT_SYNTH +#define _SPLIT_ARCHITECTURE + +/* wavetable drums on MCU, FM melodic on DSP */ +#elif defined(EAS_SPLIT_HYBRID_SYNTH) +#define _WT_SYNTH +#define _FM_SYNTH +#define _SECONDARY_SYNTH +#define _SPLIT_ARCHITECTURE +#define _HYBRID_SYNTH + +/* FM synth on DSP */ +#elif defined(EAS_SPLIT_FM_SYNTH) +#define _FM_SYNTH +#define _SPLIT_ARCHITECTURE + +#else +#error "Unrecognized architecture option" +#endif + +#endif + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_vm_protos.h b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_vm_protos.h new file mode 100755 index 0000000..20f7c09 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_vm_protos.h @@ -0,0 +1,1086 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_vm_protos.h + * + * Contents and purpose: + * Declarations, interfaces, and prototypes for voice manager. + * + * Copyright Sonic Network Inc. 2004 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 736 $ + * $Date: 2007-06-22 13:51:24 -0700 (Fri, 22 Jun 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_VM_PROTOS_H +#define _EAS_VM_PROTOS_H + +// includes +#include "eas_data.h" +#include "eas_sndlib.h" + +/*---------------------------------------------------------------------------- + * VMInitialize() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMInitialize (S_EAS_DATA *pEASData); + +/*---------------------------------------------------------------------------- + * VMInitMIDI() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMInitMIDI (S_EAS_DATA *pEASData, S_SYNTH **ppSynth); + +/*---------------------------------------------------------------------------- + * VMInitializeAllChannels() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +void VMInitializeAllChannels (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth); + +/*---------------------------------------------------------------------------- + * VMResetControllers() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +void VMResetControllers (S_SYNTH *pSynth); + +/*---------------------------------------------------------------------------- + * VMInitMIPTable() + *---------------------------------------------------------------------------- + * Purpose: + * Initialize the SP-MIDI MIP table + * + * Inputs: + * pEASData - pointer to synthesizer instance data + * mute - EAS_FALSE to unmute channels, EAS_TRUE to mute + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMInitMIPTable (S_SYNTH *pSynth); + +/*---------------------------------------------------------------------------- + * VMSetMIPEntry() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the priority and MIP level for a MIDI channel + * + * Inputs: + * pEASData - pointer to synthesizer instance data + * channel - MIDI channel number + * priority - priority (0-15 with 0 = highest priority) + * mip - maximum instantaneous polyphony + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMSetMIPEntry (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 priority, EAS_U8 mip); + +/*---------------------------------------------------------------------------- + * VMUpdateMIPTable() + *---------------------------------------------------------------------------- + * Purpose: + * This routine is called when the polyphony count in the synthesizer changes + * + * Inputs: + * pEASData - pointer to synthesizer instance data + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMUpdateMIPTable (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth); + +/*---------------------------------------------------------------------------- + * VMInitializeAllVoices() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +void VMInitializeAllVoices (S_VOICE_MGR *pVoiceMgr, EAS_INT vSynthNum); + +/*---------------------------------------------------------------------------- + * VMStartNote() + *---------------------------------------------------------------------------- + * Purpose: + * Update the synth's state to play the requested note on the requested + * channel if possible. + * + * Inputs: + * nChannel - the MIDI channel + * nKeyNumber - the MIDI key number for this note + * nNoteVelocity - the key velocity for this note + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +void VMStartNote (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 note, EAS_U8 velocity); + +/*---------------------------------------------------------------------------- + * VMCheckKeyGroup() + *---------------------------------------------------------------------------- + * Purpose: + * If the note that we've been asked to start is in the same key group as + * any currently playing notes, then we must shut down the currently playing + * note in the same key group and then start the newly requested note. + * + * Inputs: + * nChannel - synth channel that wants to start a new note + * nKeyNumber - new note's midi note number + * nRegionIndex - calling routine finds this index and gives to us + * nNoteVelocity - new note's velocity + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * pbVoiceStealingRequired - flag: this routine sets true if we needed to + * steal a voice + * + * Side Effects: + * gsSynthObject.m_sVoice[free voice num].m_nKeyNumber may be assigned + * gsSynthObject.m_sVoice[free voice num].m_nVelocity may be assigned + *---------------------------------------------------------------------------- +*/ +void VMCheckKeyGroup (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U16 keyGroup, EAS_U8 channel); + +/*---------------------------------------------------------------------------- + * VMCheckPolyphonyLimiting() + *---------------------------------------------------------------------------- + * Purpose: + * We only play at most 2 of the same note on a MIDI channel. + * E.g., if we are asked to start note 36, and there are already two voices + * that are playing note 36, then we must steal the voice playing + * the oldest note 36 and use that stolen voice to play the new note 36. + * + * Inputs: + * nChannel - synth channel that wants to start a new note + * nKeyNumber - new note's midi note number + * nNoteVelocity - new note's velocity + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * pbVoiceStealingRequired - flag: this routine sets true if we needed to + * steal a voice + * * + * Side Effects: + * psSynthObject->m_sVoice[free voice num].m_nKeyNumber may be assigned + * psSynthObject->m_sVoice[free voice num].m_nVelocity may be assigned + *---------------------------------------------------------------------------- +*/ +EAS_BOOL VMCheckPolyphonyLimiting (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 note, EAS_U8 velocity, EAS_U16 regionIndex, EAS_I32 lowVoice, EAS_I32 highVoice); + +/*---------------------------------------------------------------------------- + * VMStopNote() + *---------------------------------------------------------------------------- + * Purpose: + * Update the synth's state to end the requested note on the requested + * channel. + * + * Inputs: + * nChannel - the MIDI channel + * nKeyNumber - the key number of the note to stop + * nNoteVelocity - the note-off velocity + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * Side Effects: + * gsSynthObject.m_sVoice[free voice num].m_nSynthChannel may be assigned + * gsSynthObject.m_sVoice[free voice num].m_nKeyNumber is assigned + * gsSynthObject.m_sVoice[free voice num].m_nVelocity is assigned + *---------------------------------------------------------------------------- +*/ +void VMStopNote (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 key, EAS_U8 velocity); + +/*---------------------------------------------------------------------------- + * VMFindAvailableVoice() + *---------------------------------------------------------------------------- + * Purpose: + * Find an available voice and return the voice number if available. + * + * Inputs: + * pnVoiceNumber - really an output, see below + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * pnVoiceNumber - returns the voice number of available voice if found + * success - if there is an available voice + * failure - otherwise + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMFindAvailableVoice (S_VOICE_MGR *pVoiceMgr, EAS_INT *pVoiceNumber, EAS_I32 lowVoice, EAS_I32 highVoice); + +/*---------------------------------------------------------------------------- + * VMStealVoice() + *---------------------------------------------------------------------------- + * Purpose: + * Steal a voice and return the voice number + * + * Stealing algorithm: steal the best choice with minimal work, taking into + * account SP-Midi channel priorities and polyphony allocation. + * + * In one pass through all the voices, figure out which voice to steal + * taking into account a number of different factors: + * Priority of the voice's MIDI channel + * Number of voices over the polyphony allocation for voice's MIDI channel + * Amplitude of the voice + * Note age + * Key velocity (for voices that haven't been started yet) + * If any matching notes are found + * + * Inputs: + * nChannel - the channel that this voice wants to be started on + * nKeyNumber - the key number for this new voice + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * pnVoiceNumber - voice stolen + * EAS_RESULT EAS_SUCCESS - always successful + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMStealVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_INT *pVoiceNumber, EAS_U8 channel, EAS_U8 note, EAS_I32 lowVoice, EAS_I32 highVoice); + +/*---------------------------------------------------------------------------- + * VMAddSamples() + *---------------------------------------------------------------------------- + * Purpose: + * Synthesize the requested number of samples. + * + * Inputs: + * nNumSamplesToAdd - number of samples to write to buffer + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * number of samples actually written to buffer + * + * Side Effects: + * - samples are added to the presently free buffer + * + *---------------------------------------------------------------------------- +*/ +EAS_I32 VMAddSamples (S_VOICE_MGR *pVoiceMgr, EAS_I32 *pMixBuffer, EAS_I32 numSamplesToAdd); + +/*---------------------------------------------------------------------------- + * VMProgramChange() + *---------------------------------------------------------------------------- + * Purpose: + * Change the instrument (program) for the given channel. + * + * Depending on the program number, and the bank selected for this channel, the + * program may be in ROM, RAM (from SMAF or CMX related RAM wavetable), or + * Alternate wavetable (from mobile DLS or other DLS file) + * + * This function figures out what wavetable should be used, and sets it up as the + * wavetable to use for this channel. Also the channel may switch from a melodic + * channel to a rhythm channel, or vice versa. + * + * Inputs: + * + * Outputs: + * Side Effects: + * gsSynthObject.m_sChannel[nChannel].m_nProgramNumber is likely changed + * gsSynthObject.m_sChannel[nChannel].m_psEAS may be changed + * gsSynthObject.m_sChannel[nChannel].m_bRhythmChannel may be changed + * + *---------------------------------------------------------------------------- +*/ +void VMProgramChange (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 program); + +/*---------------------------------------------------------------------------- + * VMChannelPressure() + *---------------------------------------------------------------------------- + * Purpose: + * Change the channel pressure for the given channel + * + * Inputs: + * nChannel - the MIDI channel + * nVelocity - the channel pressure value + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * Side Effects: + * gsSynthObject.m_sChannel[nChannel].m_nChannelPressure is updated + *---------------------------------------------------------------------------- +*/ +void VMChannelPressure (S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 value); + +/*---------------------------------------------------------------------------- + * VMPitchBend() + *---------------------------------------------------------------------------- + * Purpose: + * Change the pitch wheel value for the given channel. + * This routine constructs the proper 14-bit argument when the calling routine + * passes the pitch LSB and MSB. + * + * Note: some midi disassemblers display a bipolar pitch bend value. + * We can display the bipolar value using + * if m_nPitchBend >= 0x2000 + * bipolar pitch bend = postive (m_nPitchBend - 0x2000) + * else + * bipolar pitch bend = negative (0x2000 - m_nPitchBend) + * + * Inputs: + * nChannel - the MIDI channel + * nPitchLSB - the LSB byte from the pitch bend message + * nPitchMSB - the MSB byte from the message + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * gsSynthObject.m_sChannel[nChannel].m_nPitchBend is changed + * + *---------------------------------------------------------------------------- +*/ +void VMPitchBend (S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 pitchLSB, EAS_U8 pitchMSB); + +/*---------------------------------------------------------------------------- + * VMControlChange() + *---------------------------------------------------------------------------- + * Purpose: + * Change the controller (or mode) for the given channel. + * + * Inputs: + * nChannel - the MIDI channel + * nControllerNumber - the controller number + * nControlValue - the controller number for this control change + * nControlValue - the value for this control change + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * Side Effects: + * gsSynthObject.m_sChannel[nChannel] controller is changed + * + *---------------------------------------------------------------------------- +*/ +void VMControlChange (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 controller, EAS_U8 value); + +/*---------------------------------------------------------------------------- + * VMUpdateRPNStateMachine() + *---------------------------------------------------------------------------- + * Purpose: + * Call this function when we want to parse a stream of RPN messages. + * NOTE: The synth has only one set of global RPN data instead of RPN data + * per channel. + * So actually, we don't really need to look at the nChannel parameter, + * but we pass it to facilitate future upgrades. Furthermore, we only + * support RPN0 (pitch bend sensitivity), RPN1 (fine tuning) and + * RPN2 (coarse tuning). Any other RPNs are rejected. + * + * Inputs: + * nChannel - the MIDI channel + * nControllerNumber - the RPN controller number + * nControlValue - the value for this control change + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * gsSynthObject.m_RPN0 (or m_RPN1 or m_RPN2) may be updated if the + * proper RPN message sequence is parsed. + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMUpdateRPNStateMachine (S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 controller, EAS_U8 value); + +/*---------------------------------------------------------------------------- + * VMUpdateStaticChannelParameters() + *---------------------------------------------------------------------------- + * Purpose: + * Update all of the static channel parameters for channels that have had + * a controller change values + * Or if the synth has signalled that all channels must forcibly + * be updated + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * none + * + * Side Effects: + * - psSynthObject->m_sChannel[].m_nStaticGain and m_nStaticPitch + * are updated for channels whose controller values have changed + * or if the synth has signalled that all channels must forcibly + * be updated + *---------------------------------------------------------------------------- +*/ +void VMUpdateStaticChannelParameters (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth); + +/*---------------------------------------------------------------------------- + * VMReleaseAllDeferredNoteOffs() + *---------------------------------------------------------------------------- + * Purpose: + * Call this functin when the sustain flag is presently set but + * we are now transitioning from damper pedal on to + * damper pedal off. This means all notes in this channel + * that received a note off while the damper pedal was on, and + * had their note-off requests deferred, should now proceed to + * the release state. + * + * Inputs: + * nChannel - this channel has its sustain pedal transitioning from on to off + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * Side Effects: + * any voice with deferred note offs on this channel are updated such that + * + * + *---------------------------------------------------------------------------- +*/ +void VMReleaseAllDeferredNoteOffs (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel); + +/*---------------------------------------------------------------------------- + * VMCatchNotesForSustainPedal() + *---------------------------------------------------------------------------- + * Purpose: + * Call this function when the sustain flag is presently clear and + * the damper pedal is off and we are transitioning from damper pedal OFF to + * damper pedal ON. Currently sounding notes should be left + * unchanged. However, we should try to "catch" notes if possible. + * If any notes have levels >= sustain level, catch them, + * otherwise, let them continue to release. + * + * Inputs: + * nChannel - this channel has its sustain pedal transitioning from on to off + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * Side Effects: + * any voice with deferred note offs on this channel are updated such that + * psVoice->m_sEG1.m_eState = eEnvelopeStateSustainPedal + *---------------------------------------------------------------------------- +*/ +void VMCatchNotesForSustainPedal (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel); + +/*---------------------------------------------------------------------------- + * VMUpdateAllNotesAge() + *---------------------------------------------------------------------------- + * Purpose: + * Increment the note age for all voices older than the age of the voice + * that is stopping, effectively making the voices "younger". + * + * Inputs: + * nAge - age of voice that is going away + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * m_nAge for some voices is incremented + *---------------------------------------------------------------------------- +*/ +void VMUpdateAllNotesAge (S_VOICE_MGR *pVoiceMgr, EAS_U16 nAge); + +/*---------------------------------------------------------------------------- + * VMFindRegionIndex() + *---------------------------------------------------------------------------- + * Purpose: + * Find the region index for the given instrument using the midi key number + * and the RPN2 (coarse tuning) value. By using RPN2 as part of the + * region selection process, we reduce the amount a given sample has + * to be transposed by selecting the closest recorded root instead. + * + * Inputs: + * nChannel - current channel for this note + * nKeyNumber - current midi note number + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * pnRegionIndex - valid only if we returned success + * success if we found the region index number, otherwise + * failure + * + * Side Effects: + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMFindRegionIndex (S_VOICE_MGR *pVoiceMgr, EAS_U8 channel, EAS_U8 note, EAS_U16 *pRegionIndex); + +/*---------------------------------------------------------------------------- + * VMIncRefCount() + *---------------------------------------------------------------------------- + * Increment reference count for virtual synth + *---------------------------------------------------------------------------- +*/ +void VMIncRefCount (S_SYNTH *pSynth); + +/*---------------------------------------------------------------------------- + * VMReset() + *---------------------------------------------------------------------------- + * Purpose: + * We call this routine to start the process of reseting the synth. + * This routine sets a flag for the entire synth indicating that we want + * to reset. + * We also force all voices to mute quickly. + * However, we do not actually perform any synthesis in this routine. That + * is, we do not ramp the voices down from this routine, but instead, we + * let the "regular" synth processing steps take care of adding the ramp + * down samples to the output buffer. After we are sure that all voices + * have completed ramping down, we continue the process of resetting the + * synth (from another routine). + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * - set a flag (in gsSynthObject.m_nFlags) indicating synth reset requested. + * - force all voices to update their envelope states to mute + * + *---------------------------------------------------------------------------- +*/ +void VMReset (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_BOOL force); + +/*---------------------------------------------------------------------------- + * VMMuteAllVoices() + *---------------------------------------------------------------------------- + * Purpose: + * We call this in an emergency reset situation. + * This forces all voices to mute quickly. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * - forces all voices to update their envelope states to mute + * + *---------------------------------------------------------------------------- +*/ +void VMMuteVoice (S_VOICE_MGR *pVoiceMgr, EAS_I32 voiceNum); +void VMMuteAllVoices (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth); + +/*---------------------------------------------------------------------------- + * VMReleaseAllVoices() + *---------------------------------------------------------------------------- + * Purpose: + * We call this after we've encountered the end of the Midi file. + * This ensures all voice are either in release (because we received their + * note off already) or forces them to mute quickly. + * We use this as a safety to prevent bad midi files from playing forever. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * - forces all voices to update their envelope states to release or mute + * + *---------------------------------------------------------------------------- +*/ +void VMReleaseAllVoices (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth); + +/*---------------------------------------------------------------------------- + * VMAllNotesOff() + *---------------------------------------------------------------------------- + * Purpose: + * Quickly mute all notes on the given channel. + * + * Inputs: + * nChannel - quickly turn off all notes on this channel + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * - forces all voices on this channel to update their envelope states to mute + * + *---------------------------------------------------------------------------- +*/ +void VMAllNotesOff (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel); + +/*---------------------------------------------------------------------------- + * VMDeferredStopNote() + *---------------------------------------------------------------------------- + * Purpose: + * Stop the notes that had deferred note-off requests. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * None. + * + * Side Effects: + * voices that have had deferred note-off requests are now put into release + * gsSynthObject.m_sVoice[i].m_nFlags has the VOICE_FLAG_DEFER_MIDI_NOTE_OFF + * cleared + *---------------------------------------------------------------------------- +*/ +void VMDeferredStopNote (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth); + +/*---------------------------------------------------------------------------- + * VMSetSynthPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Set the synth to a new polyphony value. Value must be >= 1 and + * <= MAX_SYNTH_VOICES. This function will pin the polyphony at those limits + * + * Inputs: + * pVoiceMgr pointer to synthesizer data + * synth synthesizer number (0 = onboard, 1 = DSP) + * polyphonyCount desired polyphony count + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMSetSynthPolyphony (S_VOICE_MGR *pVoiceMgr, EAS_I32 synth, EAS_I32 polyphonyCount); + +/*---------------------------------------------------------------------------- + * VMGetSynthPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Set the synth to a new polyphony value. Value must be >= 1 and + * <= MAX_SYNTH_VOICES. This function will pin the polyphony at those limits + * + * Inputs: + * pVoiceMgr pointer to synthesizer data + * synth synthesizer number (0 = onboard, 1 = DSP) + * polyphonyCount desired polyphony count + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMGetSynthPolyphony (S_VOICE_MGR *pVoiceMgr, EAS_I32 synth, EAS_I32 *pPolyphonyCount); + +/*---------------------------------------------------------------------------- + * VMSetPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Set the virtual synth polyphony. 0 = no limit (i.e. can use + * all available voices). + * + * Inputs: + * pVoiceMgr pointer to synthesizer data + * polyphonyCount desired polyphony count + * pSynth pointer to virtual synth + * + * Outputs: + * Returns error code + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMSetPolyphony (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 polyphonyCount); + +/*---------------------------------------------------------------------------- + * VMGetPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current polyphony setting + * + * Inputs: + * pVoiceMgr pointer to synthesizer data + * pSynth pointer to virtual synth + * pPolyphonyCount pointer to variable to receive data + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMGetPolyphony (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 *pPolyphonyCount); + +/*---------------------------------------------------------------------------- + * VMSetPriority() + *---------------------------------------------------------------------------- + * Purpose: + * Set the virtual synth priority + * + * Inputs: + * pVoiceMgr pointer to synthesizer data + * priority new priority + * pSynth pointer to virtual synth + * + * Outputs: + * Returns error code + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMSetPriority (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 priority); + +/*---------------------------------------------------------------------------- + * VMGetPriority() + *---------------------------------------------------------------------------- + * Purpose: + * Get the virtual synth priority + * + * Inputs: + * pVoiceMgr pointer to synthesizer data + * pPriority pointer to variable to hold priority + * pSynth pointer to virtual synth + * + * Outputs: + * Returns error code + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMGetPriority (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 *pPriority); + +/*---------------------------------------------------------------------------- + * VMSetVolume() + *---------------------------------------------------------------------------- + * Purpose: + * Set the master volume for this sequence + * + * Inputs: + * nSynthVolume - the desired master volume + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * + * Side Effects: + * overrides any previously set master volume from sysex + * + *---------------------------------------------------------------------------- +*/ +void VMSetVolume (S_SYNTH *pSynth, EAS_U16 masterVolume); + +/*---------------------------------------------------------------------------- + * VMSetPitchBendRange() + *---------------------------------------------------------------------------- + * Set the pitch bend range for the given channel. + *---------------------------------------------------------------------------- +*/ +void VMSetPitchBendRange (S_SYNTH *pSynth, EAS_INT channel, EAS_I16 pitchBendRange); + +/*---------------------------------------------------------------------------- + * VMSetEASLib() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the pointer to the sound library + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMSetGlobalEASLib (S_VOICE_MGR *pVoiceMgr, EAS_SNDLIB_HANDLE pEAS); +EAS_RESULT VMSetEASLib (S_SYNTH *pSynth, EAS_SNDLIB_HANDLE pEAS); + +#ifdef DLS_SYNTHESIZER +/*---------------------------------------------------------------------------- + * VMSetDLSLib() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the pointer to the sound library + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMSetGlobalDLSLib (EAS_DATA_HANDLE pEASData, EAS_DLSLIB_HANDLE pDLS); +EAS_RESULT VMSetDLSLib (S_SYNTH *pSynth, EAS_DLSLIB_HANDLE pDLS); +#endif + +/*---------------------------------------------------------------------------- + * VMSetTranposition() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the global key transposition used by the synthesizer. + * Transposes all melodic instruments up or down by the specified + * amount. Range is limited to +/-12 semitones. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * transposition - transpose amount (+/-12) + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMSetTranposition (S_SYNTH *pSynth, EAS_I32 transposition); + +/*---------------------------------------------------------------------------- + * VMGetTranposition() + *---------------------------------------------------------------------------- + * Purpose: + * Gets the global key transposition used by the synthesizer. + * Transposes all melodic instruments up or down by the specified + * amount. Range is limited to +/-12 semitones. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMGetTranposition (S_SYNTH *pSynth, EAS_I32 *pTransposition); + +/*---------------------------------------------------------------------------- + * VMGetNoteCount() + *---------------------------------------------------------------------------- +* Returns the total note count +*---------------------------------------------------------------------------- +*/ +EAS_I32 VMGetNoteCount (S_SYNTH *pSynth); + +/*---------------------------------------------------------------------------- + * VMRender() + *---------------------------------------------------------------------------- + * Purpose: + * This routine renders a frame of audio + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * pVoicesRendered - number of voices rendered this frame + * + * Side Effects: + * sets psMidiObject->m_nMaxWorkloadPerFrame + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMRender (S_VOICE_MGR *pVoiceMgr, EAS_I32 numSamples, EAS_I32 *pMixBuffer, EAS_I32 *pVoicesRendered); + +/*---------------------------------------------------------------------------- + * VMInitWorkload() + *---------------------------------------------------------------------------- + * Purpose: + * Clears the workload counter + * + * Inputs: + * pVoiceMgr - pointer to instance data + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMInitWorkload (S_VOICE_MGR *pVoiceMgr); + +/*---------------------------------------------------------------------------- + * VMSetWorkload() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the max workload for a single frame. + * + * Inputs: + * pVoiceMgr - pointer to instance data + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMSetWorkload (S_VOICE_MGR *pVoiceMgr, EAS_I32 maxWorkLoad); + +/*---------------------------------------------------------------------------- + * VMCheckWorkload() + *---------------------------------------------------------------------------- + * Purpose: + * Checks to see if work load has been exceeded on this frame. + * + * Inputs: + * pVoiceMgr - pointer to instance data + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_BOOL VMCheckWorkload (S_VOICE_MGR *pVoiceMgr); + +/*---------------------------------------------------------------------------- + * VMActiveVoices() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the number of active voices in the synthesizer. + * + * Inputs: + * pEASData - pointer to instance data + * + * Outputs: + * Returns the number of active voices + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_I32 VMActiveVoices (S_SYNTH *pSynth); + +/*---------------------------------------------------------------------------- + * VMMIDIShutdown() + *---------------------------------------------------------------------------- + * Purpose: + * Clean up any Synth related system issues. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * None + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMMIDIShutdown (S_EAS_DATA *pEASData, S_SYNTH *pSynth); + +/*---------------------------------------------------------------------------- + * VMShutdown() + *---------------------------------------------------------------------------- + * Purpose: + * Clean up any Synth related system issues. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * None + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMShutdown (S_EAS_DATA *pEASData); + +#ifdef EXTERNAL_AUDIO +/*---------------------------------------------------------------------------- + * EAS_RegExtAudioCallback() + *---------------------------------------------------------------------------- + * Register a callback for external audio processing + *---------------------------------------------------------------------------- +*/ +void VMRegExtAudioCallback (S_SYNTH *pSynth, EAS_VOID_PTR pInstData, EAS_EXT_PRG_CHG_FUNC cbProgChgFunc, EAS_EXT_EVENT_FUNC cbEventFunc); + +/*---------------------------------------------------------------------------- + * VMGetMIDIControllers() + *---------------------------------------------------------------------------- + * Returns the MIDI controller values on the specified channel + *---------------------------------------------------------------------------- +*/ +void VMGetMIDIControllers (S_SYNTH *pSynth, EAS_U8 channel, S_MIDI_CONTROLLERS *pControl); +#endif + +#ifdef _SPLIT_ARCHITECTURE +/*---------------------------------------------------------------------------- + * VMStartFrame() + *---------------------------------------------------------------------------- + * Purpose: + * Starts an audio frame + * + * Inputs: + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_BOOL VMStartFrame (S_EAS_DATA *pEASData); + +/*---------------------------------------------------------------------------- + * VMEndFrame() + *---------------------------------------------------------------------------- + * Purpose: + * Stops an audio frame + * + * Inputs: + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_BOOL VMEndFrame (S_EAS_DATA *pEASData); +#endif + +#endif /* #ifdef _EAS_VM_PROTOS_H */ + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_voicemgt.c b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_voicemgt.c new file mode 100755 index 0000000..ab0b776 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_voicemgt.c @@ -0,0 +1,3971 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_voicemgt.c + * + * Contents and purpose: + * Implements the synthesizer functions. + * + * Copyright Sonic Network Inc. 2004 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 794 $ + * $Date: 2007-08-01 00:08:48 -0700 (Wed, 01 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +/* includes */ +#include "eas.h" +#include "eas_data.h" +#include "eas_config.h" +#include "eas_report.h" +#include "eas_midictrl.h" +#include "eas_host.h" +#include "eas_synth_protos.h" +#include "eas_vm_protos.h" + +#ifdef DLS_SYNTHESIZER +#include "eas_mdls.h" +#endif + +// #define _DEBUG_VM + +/* some defines for workload */ +#define WORKLOAD_AMOUNT_SMALL_INCREMENT 5 +#define WORKLOAD_AMOUNT_START_NOTE 10 +#define WORKLOAD_AMOUNT_STOP_NOTE 10 +#define WORKLOAD_AMOUNT_KEY_GROUP 10 +#define WORKLOAD_AMOUNT_POLY_LIMIT 10 + +/* pointer to base sound library */ +extern S_EAS easSoundLib; + +#ifdef TEST_HARNESS +extern S_EAS easTestLib; +EAS_SNDLIB_HANDLE VMGetLibHandle(EAS_INT libNum) +{ + switch (libNum) + { + case 0: + return &easSoundLib; +#ifdef _WT_SYNTH + case 1: + return &easTestLib; +#endif + default: + return NULL; + } +} +#endif + +/* pointer to synthesizer interface(s) */ +#ifdef _WT_SYNTH +extern const S_SYNTH_INTERFACE wtSynth; +#endif + +#ifdef _FM_SYNTH +extern const S_SYNTH_INTERFACE fmSynth; +#endif + +typedef S_SYNTH_INTERFACE *S_SYNTH_INTERFACE_HANDLE; + +/* wavetable on MCU */ +#if defined(EAS_WT_SYNTH) +const S_SYNTH_INTERFACE *const pPrimarySynth = &wtSynth; + +/* FM on MCU */ +#elif defined(EAS_FM_SYNTH) +const S_SYNTH_INTERFACE *const pPrimarySynth = &fmSynth; + +/* wavetable drums on MCU, FM melodic on DSP */ +#elif defined(EAS_HYBRID_SYNTH) +const S_SYNTH_INTERFACE *const pPrimarySynth = &wtSynth; +const S_SYNTH_INTERFACE *const pSecondarySynth = &fmSynth; + +/* wavetable drums on MCU, wavetable melodic on DSP */ +#elif defined(EAS_SPLIT_WT_SYNTH) +const S_SYNTH_INTERFACE *const pPrimarySynth = &wtSynth; +extern const S_FRAME_INTERFACE wtFrameInterface; +const S_FRAME_INTERFACE *const pFrameInterface = &wtFrameInterface; + +/* wavetable drums on MCU, FM melodic on DSP */ +#elif defined(EAS_SPLIT_HYBRID_SYNTH) +const S_SYNTH_INTERFACE *const pPrimarySynth = &wtSynth; +const S_SYNTH_INTERFACE *const pSecondarySynth = &fmSynth; +extern const S_FRAME_INTERFACE fmFrameInterface; +const S_FRAME_INTERFACE *const pFrameInterface = &fmFrameInterface; + +/* FM on DSP */ +#elif defined(EAS_SPLIT_FM_SYNTH) +const S_SYNTH_INTERFACE *const pPrimarySynth = &fmSynth; +extern const S_FRAME_INTERFACE fmFrameInterface; +const S_FRAME_INTERFACE *const pFrameInterface = &fmFrameInterface; + +#else +#error "Undefined architecture option" +#endif + +/*---------------------------------------------------------------------------- + * inline functions + *---------------------------------------------------------------------------- +*/ +EAS_INLINE const S_REGION* GetRegionPtr (S_SYNTH *pSynth, EAS_U16 regionIndex) +{ +#if defined(DLS_SYNTHESIZER) + if (regionIndex & FLAG_RGN_IDX_DLS_SYNTH) + return &pSynth->pDLS->pDLSRegions[regionIndex & REGION_INDEX_MASK].wtRegion.region; +#endif +#if defined(_HYBRID_SYNTH) + if (regionIndex & FLAG_RGN_IDX_FM_SYNTH) + return &pSynth->pEAS->pFMRegions[regionIndex & REGION_INDEX_MASK].region; + else + return &pSynth->pEAS->pWTRegions[regionIndex].region; +#elif defined(_WT_SYNTH) + return &pSynth->pEAS->pWTRegions[regionIndex].region; +#elif defined(_FM_SYNTH) + return &pSynth->pEAS->pFMRegions[regionIndex].region; +#endif +} + +/*lint -esym(715, voiceNum) used in some implementation */ +EAS_INLINE const S_SYNTH_INTERFACE* GetSynthPtr (EAS_INT voiceNum) +{ +#if defined(_HYBRID_SYNTH) + if (voiceNum < NUM_PRIMARY_VOICES) + return pPrimarySynth; + else + return pSecondarySynth; +#else + return pPrimarySynth; +#endif +} + +EAS_INLINE EAS_INT GetAdjustedVoiceNum (EAS_INT voiceNum) +{ +#if defined(_HYBRID_SYNTH) + if (voiceNum >= NUM_PRIMARY_VOICES) + return voiceNum - NUM_PRIMARY_VOICES; +#endif + return voiceNum; +} + +EAS_INLINE EAS_U8 VSynthToChannel (S_SYNTH *pSynth, EAS_U8 channel) +{ + /*lint -e{734} synthNum is always 0-15 */ + return channel | (pSynth->vSynthNum << 4); +} + +/*---------------------------------------------------------------------------- + * InitVoice() + *---------------------------------------------------------------------------- + * Initialize a synthesizer voice + *---------------------------------------------------------------------------- +*/ +void InitVoice (S_SYNTH_VOICE *pVoice) +{ + pVoice->channel = UNASSIGNED_SYNTH_CHANNEL; + pVoice->nextChannel = UNASSIGNED_SYNTH_CHANNEL; + pVoice->note = pVoice->nextNote = DEFAULT_KEY_NUMBER; + pVoice->velocity = pVoice->nextVelocity = DEFAULT_VELOCITY; + pVoice->regionIndex = DEFAULT_REGION_INDEX; + pVoice->age = DEFAULT_AGE; + pVoice->voiceFlags = DEFAULT_VOICE_FLAGS; + pVoice->voiceState = DEFAULT_VOICE_STATE; +} + +/*---------------------------------------------------------------------------- + * IncVoicePoolCount() + *---------------------------------------------------------------------------- + * Updates the voice pool count when a voice changes state + *---------------------------------------------------------------------------- +*/ +static void IncVoicePoolCount (S_VOICE_MGR *pVoiceMgr, S_SYNTH_VOICE *pVoice) +{ + S_SYNTH *pSynth; + EAS_INT pool; + + /* ignore muting voices */ + if (pVoice->voiceState == eVoiceStateMuting) + return; + + if (pVoice->voiceState == eVoiceStateStolen) + { + pSynth = pVoiceMgr->pSynth[GET_VSYNTH(pVoice->nextChannel)]; + pool = pSynth->channels[GET_CHANNEL(pVoice->nextChannel)].pool; + } + else + { + pSynth = pVoiceMgr->pSynth[GET_VSYNTH(pVoice->channel)]; + pool = pSynth->channels[GET_CHANNEL(pVoice->channel)].pool; + } + + pSynth->poolCount[pool]++; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IncVoicePoolCount: Synth=%d pool=%d\n", pSynth->vSynthNum, pool); */ } +#endif +} + +/*---------------------------------------------------------------------------- + * DecVoicePoolCount() + *---------------------------------------------------------------------------- + * Updates the voice pool count when a voice changes state + *---------------------------------------------------------------------------- +*/ +static void DecVoicePoolCount (S_VOICE_MGR *pVoiceMgr, S_SYNTH_VOICE *pVoice) +{ + S_SYNTH *pSynth; + EAS_INT pool; + + /* ignore muting voices */ + if (pVoice->voiceState == eVoiceStateMuting) + return; + + if (pVoice->voiceState == eVoiceStateStolen) + { + pSynth = pVoiceMgr->pSynth[GET_VSYNTH(pVoice->nextChannel)]; + pool = pSynth->channels[GET_CHANNEL(pVoice->nextChannel)].pool; + } + else + { + pSynth = pVoiceMgr->pSynth[GET_VSYNTH(pVoice->channel)]; + pool = pSynth->channels[GET_CHANNEL(pVoice->channel)].pool; + } + + pSynth->poolCount[pool]--; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "DecVoicePoolCount: Synth=%d pool=%d\n", pSynth->vSynthNum, pool); */ } +#endif +} + +/*---------------------------------------------------------------------------- + * VMInitialize() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMInitialize (S_EAS_DATA *pEASData) +{ + S_VOICE_MGR *pVoiceMgr; + EAS_INT i; + + /* check Configuration Module for data allocation */ + if (pEASData->staticMemoryModel) + pVoiceMgr = EAS_CMEnumData(EAS_CM_SYNTH_DATA); + else + pVoiceMgr = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_VOICE_MGR)); + if (!pVoiceMgr) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitialize: Failed to allocate synthesizer memory\n"); */ } + return EAS_ERROR_MALLOC_FAILED; + } + EAS_HWMemSet(pVoiceMgr, 0, sizeof(S_VOICE_MGR)); + + /* initialize non-zero variables */ + pVoiceMgr->pGlobalEAS = (S_EAS*) &easSoundLib; + pVoiceMgr->maxPolyphony = (EAS_U16) MAX_SYNTH_VOICES; + +#if defined(_SECONDARY_SYNTH) || defined(EAS_SPLIT_WT_SYNTH) + pVoiceMgr->maxPolyphonyPrimary = NUM_PRIMARY_VOICES; + pVoiceMgr->maxPolyphonySecondary = NUM_SECONDARY_VOICES; +#endif + + /* set max workload to zero */ + pVoiceMgr->maxWorkLoad = 0; + + /* initialize the voice manager parameters */ + for (i = 0; i < MAX_SYNTH_VOICES; i++) + InitVoice(&pVoiceMgr->voices[i]); + + /* initialize the synth */ + /*lint -e{522} return unused at this time */ + pPrimarySynth->pfInitialize(pVoiceMgr); + + /* initialize the off-chip synth */ +#ifdef _HYBRID_SYNTH + /*lint -e{522} return unused at this time */ + pSecondarySynth->pfInitialize(pVoiceMgr); +#endif + + pEASData->pVoiceMgr = pVoiceMgr; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMInitMIDI() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMInitMIDI (S_EAS_DATA *pEASData, S_SYNTH **ppSynth) +{ + EAS_RESULT result; + S_SYNTH *pSynth; + EAS_INT virtualSynthNum; + + *ppSynth = NULL; + + /* static memory model only allows one synth */ + if (pEASData->staticMemoryModel) + { + if (pEASData->pVoiceMgr->pSynth[0] != NULL) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitMIDI: No virtual synthesizer support for static memory model\n"); */ } + return EAS_ERROR_NO_VIRTUAL_SYNTHESIZER; + } + + /* check Configuration Module for data allocation */ + pSynth = EAS_CMEnumData(EAS_CM_MIDI_DATA); + virtualSynthNum = 0; + } + + /* dynamic memory model */ + else + { + for (virtualSynthNum = 0; virtualSynthNum < MAX_VIRTUAL_SYNTHESIZERS; virtualSynthNum++) + if (pEASData->pVoiceMgr->pSynth[virtualSynthNum] == NULL) + break; + if (virtualSynthNum == MAX_VIRTUAL_SYNTHESIZERS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitMIDI: Exceeded number of active virtual synthesizers"); */ } + return EAS_ERROR_NO_VIRTUAL_SYNTHESIZER; + } + pSynth = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_SYNTH)); + } + + /* make sure we have a valid memory pointer */ + if (pSynth == NULL) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitMIDI: Failed to allocate synthesizer memory\n"); */ } + return EAS_ERROR_MALLOC_FAILED; + } + EAS_HWMemSet(pSynth, 0, sizeof(S_SYNTH)); + + /* set the sound library pointer */ + if ((result = VMSetEASLib(pSynth, pEASData->pVoiceMgr->pGlobalEAS)) != EAS_SUCCESS) + { + VMMIDIShutdown(pEASData, pSynth); + return result; + } + + /* link in DLS bank if downloaded */ +#ifdef DLS_SYNTHESIZER + if (pEASData->pVoiceMgr->pGlobalDLS) + { + pSynth->pDLS = pEASData->pVoiceMgr->pGlobalDLS; + DLSAddRef(pSynth->pDLS); + } +#endif + + /* initialize MIDI state variables */ + pSynth->synthFlags = DEFAULT_SYNTH_FLAGS; + pSynth->masterVolume = DEFAULT_SYNTH_MASTER_VOLUME; + pSynth->refCount = 1; + pSynth->priority = DEFAULT_SYNTH_PRIORITY; + pSynth->poolAlloc[0] = (EAS_U8) pEASData->pVoiceMgr->maxPolyphony; + + VMInitializeAllChannels(pEASData->pVoiceMgr, pSynth); + + pSynth->vSynthNum = (EAS_U8) virtualSynthNum; + pEASData->pVoiceMgr->pSynth[virtualSynthNum] = pSynth; + + *ppSynth = pSynth; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMIncRefCount() + *---------------------------------------------------------------------------- + * Increment reference count for virtual synth + *---------------------------------------------------------------------------- +*/ +void VMIncRefCount (S_SYNTH *pSynth) +{ + pSynth->refCount++; +} + +/*---------------------------------------------------------------------------- + * VMReset() + *---------------------------------------------------------------------------- + * Purpose: + * We call this routine to start the process of reseting the synth. + * This routine sets a flag for the entire synth indicating that we want + * to reset. + * We also force all voices to mute quickly. + * However, we do not actually perform any synthesis in this routine. That + * is, we do not ramp the voices down from this routine, but instead, we + * let the "regular" synth processing steps take care of adding the ramp + * down samples to the output buffer. After we are sure that all voices + * have completed ramping down, we continue the process of resetting the + * synth (from another routine). + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * force - force reset even if voices are active + * + * Outputs: + * + * Side Effects: + * - set a flag (in psSynthObject->m_nFlags) indicating synth reset requested. + * - force all voices to update their envelope states to mute + * + *---------------------------------------------------------------------------- +*/ +void VMReset (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_BOOL force) +{ + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMReset: request to reset synth. Force = %d\n", force); */ } +#endif + + /* force voices to off state - may cause audio artifacts */ + if (force) + { + pVoiceMgr->activeVoices -= pSynth->numActiveVoices; + pSynth->numActiveVoices = 0; + VMInitializeAllVoices(pVoiceMgr, pSynth->vSynthNum); + } + else + VMMuteAllVoices(pVoiceMgr, pSynth); + + /* don't reset if voices are still playing */ + if (pSynth->numActiveVoices == 0) + { + EAS_INT i; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMReset: complete the reset process\n"); */ } +#endif + + VMInitializeAllChannels(pVoiceMgr, pSynth); + for (i = 0; i < NUM_SYNTH_CHANNELS; i++) + pSynth->poolCount[i] = 0; + + /* set polyphony */ + if (pSynth->maxPolyphony < pVoiceMgr->maxPolyphony) + pSynth->poolAlloc[0] = (EAS_U8) pVoiceMgr->maxPolyphony; + else + pSynth->poolAlloc[0] = (EAS_U8) pSynth->maxPolyphony; + + /* clear reset flag */ + pSynth->synthFlags &= ~SYNTH_FLAG_RESET_IS_REQUESTED; + } + + /* handle reset after voices are muted */ + else + pSynth->synthFlags |= SYNTH_FLAG_RESET_IS_REQUESTED; +} + +/*---------------------------------------------------------------------------- + * VMInitializeAllChannels() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +void VMInitializeAllChannels (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth) +{ + S_SYNTH_CHANNEL *pChannel; + EAS_INT i; + + VMResetControllers(pSynth); + + /* init each channel */ + pChannel = pSynth->channels; + + for (i = 0; i < NUM_SYNTH_CHANNELS; i++, pChannel++) + { + pChannel->channelFlags = DEFAULT_CHANNEL_FLAGS; + pChannel->staticGain = DEFAULT_CHANNEL_STATIC_GAIN; + pChannel->staticPitch = DEFAULT_CHANNEL_STATIC_PITCH; + pChannel->pool = 0; + + /* the drum channel needs a different init */ + if (i == DEFAULT_DRUM_CHANNEL) + { + pChannel->bankNum = DEFAULT_RHYTHM_BANK_NUMBER; + pChannel->channelFlags |= CHANNEL_FLAG_RHYTHM_CHANNEL; + } + else + pChannel->bankNum = DEFAULT_MELODY_BANK_NUMBER; + + VMProgramChange(pVoiceMgr, pSynth, (EAS_U8) i, DEFAULT_SYNTH_PROGRAM_NUMBER); + } + +} + +/*---------------------------------------------------------------------------- + * VMResetControllers() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +void VMResetControllers (S_SYNTH *pSynth) +{ + S_SYNTH_CHANNEL *pChannel; + EAS_INT i; + + pChannel = pSynth->channels; + + for (i = 0; i < NUM_SYNTH_CHANNELS; i++, pChannel++) + { + pChannel->pitchBend = DEFAULT_PITCH_BEND; + pChannel->modWheel = DEFAULT_MOD_WHEEL; + pChannel->volume = DEFAULT_CHANNEL_VOLUME; + pChannel->pan = DEFAULT_PAN; + pChannel->expression = DEFAULT_EXPRESSION; + +#ifdef _REVERB + pSynth->channels[i].reverbSend = DEFAULT_REVERB_SEND; +#endif + +#ifdef _CHORUS + pSynth->channels[i].chorusSend = DEFAULT_CHORUS_SEND; +#endif + + pChannel->channelPressure = DEFAULT_CHANNEL_PRESSURE; + pChannel->registeredParam = DEFAULT_REGISTERED_PARAM; + pChannel->pitchBendSensitivity = DEFAULT_PITCH_BEND_SENSITIVITY; + pChannel->finePitch = DEFAULT_FINE_PITCH; + pChannel->coarsePitch = DEFAULT_COARSE_PITCH; + + /* update all voices on this channel */ + pChannel->channelFlags |= CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS; + } +} + +/*---------------------------------------------------------------------------- + * VMInitializeAllVoices() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +void VMInitializeAllVoices (S_VOICE_MGR *pVoiceMgr, EAS_INT vSynthNum) +{ + EAS_INT i; + + /* initialize the voice manager parameters */ + for (i = 0; i < MAX_SYNTH_VOICES; i++) + { + if (pVoiceMgr->voices[i].voiceState != eVoiceStateStolen) + { + if (GET_VSYNTH(pVoiceMgr->voices[i].channel) == vSynthNum) + InitVoice(&pVoiceMgr->voices[i]); + } + else + { + if (GET_VSYNTH(pVoiceMgr->voices[i].nextChannel) == vSynthNum) + InitVoice(&pVoiceMgr->voices[i]); + } + } +} + +/*---------------------------------------------------------------------------- + * VMMuteVoice() + *---------------------------------------------------------------------------- + * Mute the selected voice + *---------------------------------------------------------------------------- +*/ +void VMMuteVoice (S_VOICE_MGR *pVoiceMgr, EAS_I32 voiceNum) +{ + S_SYNTH *pSynth; + S_SYNTH_VOICE *pVoice; + + /* take no action if voice is already muted */ + pVoice = &pVoiceMgr->voices[voiceNum]; + if ((pVoice->voiceState == eVoiceStateMuting) || (pVoice->voiceState == eVoiceStateFree)) + return; + + /* one less voice in pool */ + DecVoicePoolCount(pVoiceMgr, pVoice); + + pSynth = pVoiceMgr->pSynth[GET_VSYNTH(pVoice->channel)]; + GetSynthPtr(voiceNum)->pfMuteVoice(pVoiceMgr, pSynth, pVoice, GetAdjustedVoiceNum(voiceNum)); + pVoice->voiceState = eVoiceStateMuting; + +} + +/*---------------------------------------------------------------------------- + * VMReleaseVoice() + *---------------------------------------------------------------------------- + * Release the selected voice + *---------------------------------------------------------------------------- +*/ +void VMReleaseVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 voiceNum) +{ + S_SYNTH_VOICE *pVoice = &pVoiceMgr->voices[voiceNum]; + + /* take no action if voice is already free, muting, or releasing */ + if (( pVoice->voiceState == eVoiceStateMuting) || + (pVoice->voiceState == eVoiceStateFree) || + (pVoice->voiceState == eVoiceStateRelease)) + return; + + /* stolen voices should just be muted */ + if (pVoice->voiceState == eVoiceStateStolen) + VMMuteVoice(pVoiceMgr, voiceNum); + + /* release this voice */ + GetSynthPtr(voiceNum)->pfReleaseVoice(pVoiceMgr, pSynth, &pVoiceMgr->voices[voiceNum], GetAdjustedVoiceNum(voiceNum)); + pVoice->voiceState = eVoiceStateRelease; +} + +/*---------------------------------------------------------------------------- + * VMInitMIPTable() + *---------------------------------------------------------------------------- + * Initialize the SP-MIDI MIP table in preparation for receiving MIP message + *---------------------------------------------------------------------------- +*/ +void VMInitMIPTable (S_SYNTH *pSynth) +{ + EAS_INT i; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMInitMIPTable\n"); */ } +#endif + + /* clear SP-MIDI flag */ + pSynth->synthFlags &= ~SYNTH_FLAG_SP_MIDI_ON; + for (i = 0; i < NUM_SYNTH_CHANNELS; i++) + { + pSynth->channels[i].pool = 0; + pSynth->channels[i].mip = 0; + } +} + +/*---------------------------------------------------------------------------- + * VMSetMIPEntry() + *---------------------------------------------------------------------------- + * Sets the priority and MIP level for a MIDI channel + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pVoiceMgr) reserved for future use */ +void VMSetMIPEntry (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 priority, EAS_U8 mip) +{ + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMSetMIPEntry: channel=%d, priority=%d, MIP=%d\n", channel, priority, mip); */ } +#endif + + /* save data for use by MIP message processing */ + if (priority < NUM_SYNTH_CHANNELS) + { + pSynth->channels[channel].pool = priority; + pSynth->channels[channel].mip = mip; + } +} + +/*---------------------------------------------------------------------------- + * VMMIPUpdateChannelMuting() + *---------------------------------------------------------------------------- + * This routine is called after an SP-MIDI message is received and + * any time the allocated polyphony changes. It mutes or unmutes + * channels based on polyphony. + *---------------------------------------------------------------------------- +*/ +void VMMIPUpdateChannelMuting (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth) +{ + EAS_INT i; + EAS_INT maxPolyphony; + EAS_INT channel; + EAS_INT vSynthNum; + EAS_INT pool; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMUpdateMIPTable\n"); */ } +#endif + + /* determine max polyphony */ + if (pSynth->maxPolyphony) + maxPolyphony = pSynth->maxPolyphony; + else + maxPolyphony = pVoiceMgr->maxPolyphony; + + /* process channels */ + for (i = 0; i < NUM_SYNTH_CHANNELS; i++) + { + + /* channel must be in MIP message and must meet allocation target */ + if ((pSynth->channels[i].mip != 0) && (pSynth->channels[i].mip <= maxPolyphony)) + pSynth->channels[i].channelFlags &= ~CHANNEL_FLAG_MUTE; + else + pSynth->channels[i].channelFlags |= CHANNEL_FLAG_MUTE; + + /* reset voice pool count */ + pSynth->poolCount[i] = 0; + } + + /* mute any voices on muted channels, and count unmuted voices */ + for (i = 0; i < MAX_SYNTH_VOICES; i++) + { + + /* ignore free voices */ + if (pVoiceMgr->voices[i].voiceState == eVoiceStateFree) + continue; + + /* get channel and virtual synth */ + if (pVoiceMgr->voices[i].voiceState != eVoiceStateStolen) + { + vSynthNum = GET_VSYNTH(pVoiceMgr->voices[i].channel); + channel = GET_CHANNEL(pVoiceMgr->voices[i].channel); + } + else + { + vSynthNum = GET_VSYNTH(pVoiceMgr->voices[i].nextChannel); + channel = GET_CHANNEL(pVoiceMgr->voices[i].nextChannel); + } + + /* ignore voices on other synths */ + if (vSynthNum != pSynth->vSynthNum) + continue; + + /* count voices */ + pool = pSynth->channels[channel].pool; + + /* deal with muted channels */ + if (pSynth->channels[channel].channelFlags & CHANNEL_FLAG_MUTE) + { + /* mute stolen voices scheduled to play on this channel */ + if (pVoiceMgr->voices[i].voiceState == eVoiceStateStolen) + pVoiceMgr->voices[i].voiceState = eVoiceStateMuting; + + /* release voices that aren't already muting */ + else if (pVoiceMgr->voices[i].voiceState != eVoiceStateMuting) + { + VMReleaseVoice(pVoiceMgr, pSynth, i); + pSynth->poolCount[pool]++; + } + } + + /* not muted, count this voice */ + else + pSynth->poolCount[pool]++; + } +} + +/*---------------------------------------------------------------------------- + * VMUpdateMIPTable() + *---------------------------------------------------------------------------- + * This routine is called at the end of the SysEx message to allow + * the Voice Manager to complete the initialization of the MIP + * table. It assigns channels to the appropriate voice pool based + * on the MIP setting and calculates the voices allocated for each + * pool. + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pVoiceMgr) reserved for future use */ +void VMUpdateMIPTable (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth) +{ + S_SYNTH_CHANNEL *pChannel; + EAS_INT i; + EAS_INT currentMIP; + EAS_INT currentPool; + EAS_INT priority[NUM_SYNTH_CHANNELS]; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMUpdateMIPTable\n"); */ } +#endif + + /* set SP-MIDI flag */ + pSynth->synthFlags |= SYNTH_FLAG_SP_MIDI_ON; + + /* sort channels into priority order */ + for (i = 0; i < NUM_SYNTH_CHANNELS; i++) + priority[i] = -1; + for (i = 0; i < NUM_SYNTH_CHANNELS; i++) + { + if (pSynth->channels[i].pool != DEFAULT_SP_MIDI_PRIORITY) + priority[pSynth->channels[i].pool] = i; + } + + /* process channels in priority order */ + currentMIP = 0; + currentPool = -1; + for (i = 0; i < NUM_SYNTH_CHANNELS; i++) + { + /* stop when we run out of channels */ + if (priority[i] == -1) + break; + + pChannel = &pSynth->channels[priority[i]]; + + /* when 2 or more channels have the same MIP setting, they + * share a common voice pool + */ + if (pChannel->mip == currentMIP) + pChannel->pool = (EAS_U8) currentPool; + + /* new voice pool */ + else + { + currentPool++; + pSynth->poolAlloc[currentPool] = (EAS_U8) (pChannel->mip - currentMIP); + currentMIP = pChannel->mip; + } + } + + /* set SP-MIDI flag */ + pSynth->synthFlags |= SYNTH_FLAG_SP_MIDI_ON; + + /* update channel muting */ + VMMIPUpdateChannelMuting (pVoiceMgr, pSynth); +} + +/*---------------------------------------------------------------------------- + * VMMuteAllVoices() + *---------------------------------------------------------------------------- + * Purpose: + * We call this in an emergency reset situation. + * This forces all voices to mute quickly. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * - forces all voices to update their envelope states to mute + * + *---------------------------------------------------------------------------- +*/ +void VMMuteAllVoices (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth) +{ + EAS_INT i; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMMuteAllVoices: about to mute all voices!!\n"); */ } +#endif + + for (i = 0; i < MAX_SYNTH_VOICES; i++) + { + /* for stolen voices, check new channel */ + if (pVoiceMgr->voices[i].voiceState == eVoiceStateStolen) + { + if (GET_VSYNTH(pVoiceMgr->voices[i].nextChannel) == pSynth->vSynthNum) + VMMuteVoice(pVoiceMgr, i); + } + + else if (pSynth->vSynthNum == GET_VSYNTH(pVoiceMgr->voices[i].channel)) + VMMuteVoice(pVoiceMgr, i); + } +} + +/*---------------------------------------------------------------------------- + * VMReleaseAllVoices() + *---------------------------------------------------------------------------- + * Purpose: + * We call this after we've encountered the end of the Midi file. + * This ensures all voices are either in release (because we received their + * note off already) or forces them to mute quickly. + * We use this as a safety to prevent bad midi files from playing forever. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * - forces all voices to update their envelope states to release or mute + * + *---------------------------------------------------------------------------- +*/ +void VMReleaseAllVoices (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth) +{ + EAS_INT i; + + /* release sustain pedal on all channels */ + for (i = 0; i < NUM_SYNTH_CHANNELS; i++) + { + if (pSynth->channels[ i ].channelFlags & CHANNEL_FLAG_SUSTAIN_PEDAL) + { + VMReleaseAllDeferredNoteOffs(pVoiceMgr, pSynth, (EAS_U8) i); + pSynth->channels[i].channelFlags &= ~CHANNEL_FLAG_SUSTAIN_PEDAL; + } + } + + /* release all voices */ + for (i = 0; i < MAX_SYNTH_VOICES; i++) + { + + switch (pVoiceMgr->voices[i].voiceState) + { + case eVoiceStateStart: + case eVoiceStatePlay: + /* only release voices on this synth */ + if (GET_VSYNTH(pVoiceMgr->voices[i].channel) == pSynth->vSynthNum) + VMReleaseVoice(pVoiceMgr, pSynth, i); + break; + + case eVoiceStateStolen: + if (GET_VSYNTH(pVoiceMgr->voices[i].nextChannel) == pSynth->vSynthNum) + VMMuteVoice(pVoiceMgr, i); + break; + + case eVoiceStateFree: + case eVoiceStateRelease: + case eVoiceStateMuting: + break; + + case eVoiceStateInvalid: + default: +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMReleaseAllVoices: error, %d is an unrecognized state\n", + pVoiceMgr->voices[i].voiceState); */ } +#endif + break; + } + } +} + +/*---------------------------------------------------------------------------- + * VMAllNotesOff() + *---------------------------------------------------------------------------- + * Purpose: + * Quickly mute all notes on the given channel. + * + * Inputs: + * nChannel - quickly turn off all notes on this channel + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * - forces all voices on this channel to update their envelope states to mute + * + *---------------------------------------------------------------------------- +*/ +void VMAllNotesOff (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel) +{ + EAS_INT voiceNum; + S_SYNTH_VOICE *pVoice; + +#ifdef _DEBUG_VM + if (channel >= NUM_SYNTH_CHANNELS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMAllNotesOff: error, %d invalid channel number\n", + channel); */ } + return; + } +#endif + + /* increment workload */ + pVoiceMgr->workload += WORKLOAD_AMOUNT_SMALL_INCREMENT; + + /* check each voice */ + channel = VSynthToChannel(pSynth, channel); + for (voiceNum = 0; voiceNum < MAX_SYNTH_VOICES; voiceNum++) + { + pVoice = &pVoiceMgr->voices[voiceNum]; + if (pVoice->voiceState != eVoiceStateFree) + { + if (((pVoice->voiceState != eVoiceStateStolen) && (channel == pVoice->channel)) || + ((pVoice->voiceState == eVoiceStateStolen) && (channel == pVoice->nextChannel))) + { + /* this voice is assigned to the requested channel */ + GetSynthPtr(voiceNum)->pfMuteVoice(pVoiceMgr, pSynth, pVoice, GetAdjustedVoiceNum(voiceNum)); + pVoice->voiceState = eVoiceStateMuting; + } + } + } +} + +/*---------------------------------------------------------------------------- + * VMDeferredStopNote() + *---------------------------------------------------------------------------- + * Purpose: + * Stop the notes that had deferred note-off requests. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * None. + * + * Side Effects: + * voices that have had deferred note-off requests are now put into release + * psSynthObject->m_sVoice[i].m_nFlags has the VOICE_FLAG_DEFER_MIDI_NOTE_OFF + * cleared + *---------------------------------------------------------------------------- +*/ +void VMDeferredStopNote (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth) +{ + EAS_INT voiceNum; + EAS_INT channel; + EAS_BOOL deferredNoteOff; + + deferredNoteOff = EAS_FALSE; + + /* check each voice to see if it requires a deferred note off */ + for (voiceNum=0; voiceNum < MAX_SYNTH_VOICES; voiceNum++) + { + if (pVoiceMgr->voices[voiceNum].voiceFlags & VOICE_FLAG_DEFER_MIDI_NOTE_OFF) + { + /* check if this voice was stolen */ + if (pVoiceMgr->voices[voiceNum].voiceState == eVoiceStateStolen) + { + /* + This voice was stolen, AND it also has a deferred note-off. + The stolen note must be completely ramped down at this point. + The note that caused the stealing to occur, however, must + have received a note-off request before the note that caused + stealing ever had a chance to even start. We want to give + the note that caused the stealing a chance to play, so we + start it on the next update interval, and we defer sending + the note-off request until the subsequent update interval. + So do not send the note-off request for this voice because + this voice was stolen and should have completed ramping down, + Also, do not clear the global flag nor this voice's flag + because we must indicate that the subsequent update interval, + after the note that caused stealing has started, should + then send the deferred note-off request. + */ + deferredNoteOff = EAS_TRUE; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMDeferredStopNote: defer request to stop voice %d (channel=%d note=%d) - voice not started\n", + voiceNum, + pVoiceMgr->voices[voiceNum].nextChannel, + pVoiceMgr->voices[voiceNum].note); */ } + + /* sanity check: this stolen voice better be ramped to zero */ + if (0 != pVoiceMgr->voices[voiceNum].gain) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMDeferredStopNote: warning, this voice did not complete its ramp to zero\n"); */ } + } +#endif // #ifdef _DEBUG_VM + + } + else + { + /* clear the flag using exor */ + pVoiceMgr->voices[voiceNum].voiceFlags ^= + VOICE_FLAG_DEFER_MIDI_NOTE_OFF; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMDeferredStopNote: Stop voice %d (channel=%d note=%d)\n", + voiceNum, + pVoiceMgr->voices[voiceNum].nextChannel, + pVoiceMgr->voices[voiceNum].note); */ } +#endif + + channel = pVoiceMgr->voices[voiceNum].channel & 15; + + /* check if sustain pedal is on */ + if (pSynth->channels[channel].channelFlags & CHANNEL_FLAG_SUSTAIN_PEDAL) + { + GetSynthPtr(voiceNum)->pfSustainPedal(pVoiceMgr, pSynth, &pVoiceMgr->voices[voiceNum], &pSynth->channels[channel], GetAdjustedVoiceNum(voiceNum)); + } + + /* release this voice */ + else + VMReleaseVoice(pVoiceMgr, pSynth, voiceNum); + + } + + } + + } + + /* clear the deferred note-off flag, unless there's another one pending */ + if (deferredNoteOff == EAS_FALSE) + pSynth->synthFlags ^= SYNTH_FLAG_DEFERRED_MIDI_NOTE_OFF_PENDING; +} + +/*---------------------------------------------------------------------------- + * VMReleaseAllDeferredNoteOffs() + *---------------------------------------------------------------------------- + * Purpose: + * Call this functin when the sustain flag is presently set but + * we are now transitioning from damper pedal on to + * damper pedal off. This means all notes in this channel + * that received a note off while the damper pedal was on, and + * had their note-off requests deferred, should now proceed to + * the release state. + * + * Inputs: + * nChannel - this channel has its sustain pedal transitioning from on to off + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * Side Effects: + * any voice with deferred note offs on this channel are updated such that + * pVoice->m_sEG1.m_eState = eEnvelopeStateRelease + * pVoice->m_sEG1.m_nIncrement = release increment + * pVoice->m_nFlags = clear the deferred note off flag + *---------------------------------------------------------------------------- +*/ +void VMReleaseAllDeferredNoteOffs (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel) +{ + S_SYNTH_VOICE *pVoice; + EAS_INT voiceNum; + +#ifdef _DEBUG_VM + if (channel >= NUM_SYNTH_CHANNELS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMReleaseAllDeferredNoteOffs: error, %d invalid channel number\n", + channel); */ } + return; + } +#endif /* #ifdef _DEBUG_VM */ + + /* increment workload */ + pVoiceMgr->workload += WORKLOAD_AMOUNT_SMALL_INCREMENT; + + /* find all the voices assigned to this channel */ + channel = VSynthToChannel(pSynth, channel); + for (voiceNum = 0; voiceNum < MAX_SYNTH_VOICES; voiceNum++) + { + + pVoice = &pVoiceMgr->voices[voiceNum]; + if (channel == pVoice->channel) + { + + /* does this voice have a deferred note off? */ + if (pVoice->voiceFlags & VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF) + { + /* release voice */ + VMReleaseVoice(pVoiceMgr, pSynth, voiceNum); + + /* use exor to flip bit, clear the flag */ + pVoice->voiceFlags &= ~VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF; + + } + + } + } + + return; +} + +/*---------------------------------------------------------------------------- + * VMCatchNotesForSustainPedal() + *---------------------------------------------------------------------------- + * Purpose: + * Call this function when the sustain flag is presently clear and + * the damper pedal is off and we are transitioning from damper pedal OFF to + * damper pedal ON. Currently sounding notes should be left + * unchanged. However, we should try to "catch" notes if possible. + * If any notes are in release and have levels >= sustain level, catch them, + * otherwise, let them continue to release. + * + * Inputs: + * nChannel - this channel has its sustain pedal transitioning from on to off + * psEASData - pointer to overall EAS data structure + * + * Outputs: + *---------------------------------------------------------------------------- +*/ +void VMCatchNotesForSustainPedal (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel) +{ + EAS_INT voiceNum; + +#ifdef _DEBUG_VM + if (channel >= NUM_SYNTH_CHANNELS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMCatchNotesForSustainPedal: error, %d invalid channel number\n", + channel); */ } + return; + } +#endif + + pVoiceMgr->workload += WORKLOAD_AMOUNT_SMALL_INCREMENT; + channel = VSynthToChannel(pSynth, channel); + + /* find all the voices assigned to this channel */ + for (voiceNum = 0; voiceNum < MAX_SYNTH_VOICES; voiceNum++) + { + if (channel == pVoiceMgr->voices[voiceNum].channel) + { + if (eVoiceStateRelease == pVoiceMgr->voices[voiceNum].voiceState) + GetSynthPtr(voiceNum)->pfSustainPedal(pVoiceMgr, pSynth, &pVoiceMgr->voices[voiceNum], &pSynth->channels[channel], GetAdjustedVoiceNum(voiceNum)); + } + } +} + +/*---------------------------------------------------------------------------- + * VMUpdateAllNotesAge() + *---------------------------------------------------------------------------- + * Purpose: + * Increment the note age for all of the active voices. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * m_nAge for all voices is incremented + *---------------------------------------------------------------------------- +*/ +void VMUpdateAllNotesAge (S_VOICE_MGR *pVoiceMgr, EAS_U16 age) +{ + EAS_INT i; + + for (i = 0; i < MAX_SYNTH_VOICES; i++) + { + if (age - pVoiceMgr->voices[i].age > 0) + pVoiceMgr->voices[i].age++; + } +} + +/*---------------------------------------------------------------------------- + * VMStolenVoice() + *---------------------------------------------------------------------------- + * Purpose: + * The selected voice is being stolen. Sets the parameters so that the + * voice will begin playing the new sound on the next buffer. + * + * Inputs: + * pVoice - pointer to voice to steal + * nChannel - the channel to start a note on + * nKeyNumber - the key number to start a note for + * nNoteVelocity - the key velocity from this note + * + * Outputs: + * None + *---------------------------------------------------------------------------- +*/ +static void VMStolenVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 voiceNum, EAS_U8 channel, EAS_U8 note, EAS_U8 velocity, EAS_U16 regionIndex) +{ + S_SYNTH_VOICE *pVoice = &pVoiceMgr->voices[voiceNum]; + + /* one less voice in old pool */ + DecVoicePoolCount(pVoiceMgr, pVoice); + + /* mute the sound that is currently playing */ + GetSynthPtr(voiceNum)->pfMuteVoice(pVoiceMgr, pVoiceMgr->pSynth[GET_VSYNTH(pVoice->channel)], &pVoiceMgr->voices[voiceNum], GetAdjustedVoiceNum(voiceNum)); + pVoice->voiceState = eVoiceStateStolen; + + /* set new note data */ + pVoice->nextChannel = VSynthToChannel(pSynth, channel); + pVoice->nextNote = note; + pVoice->nextVelocity = velocity; + pVoice->nextRegionIndex = regionIndex; + + /* one more voice in new pool */ + IncVoicePoolCount(pVoiceMgr, pVoice); + + /* clear the deferred flags */ + pVoice->voiceFlags &= + ~(VOICE_FLAG_DEFER_MIDI_NOTE_OFF | + VOICE_FLAG_DEFER_MUTE | + VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF); + + /* all notes older than this one get "younger" */ + VMUpdateAllNotesAge(pVoiceMgr, pVoice->age); + + /* assign current age to this note and increment for the next note */ + pVoice->age = pVoiceMgr->age++; +} + +/*---------------------------------------------------------------------------- + * VMFreeVoice() + *---------------------------------------------------------------------------- + * Purpose: + * The selected voice is done playing and being returned to the + * pool of free voices + * + * Inputs: + * pVoice - pointer to voice to free + * + * Outputs: + * None + *---------------------------------------------------------------------------- +*/ +static void VMFreeVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice) +{ + + /* do nothing if voice is already free */ + if (pVoice->voiceState == eVoiceStateFree) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "VMFreeVoice: Attempt to free voice that is already free\n"); */ } + return; + } + + /* if we jump directly to free without passing muting stage, + * we need to adjust the voice count */ + DecVoicePoolCount(pVoiceMgr, pVoice); + + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "VMFreeVoice: Synth=%d\n", pSynth->vSynthNum); */ } +#endif + + /* return to free voice pool */ + pVoiceMgr->activeVoices--; + pSynth->numActiveVoices--; + InitVoice(pVoice); + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMFreeVoice: free voice %d\n", pVoice - pVoiceMgr->voices); */ } +#endif + + /* all notes older than this one get "younger" */ + VMUpdateAllNotesAge(pVoiceMgr, pVoice->age); + } + +/*---------------------------------------------------------------------------- + * VMRetargetStolenVoice() + *---------------------------------------------------------------------------- + * Purpose: + * The selected voice has been stolen and needs to be initalized with + * the paramters of its new note. + * + * Inputs: + * pVoice - pointer to voice to retarget + * + * Outputs: + * None + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL VMRetargetStolenVoice (S_VOICE_MGR *pVoiceMgr, EAS_I32 voiceNum) +{ + EAS_U8 flags; + S_SYNTH_CHANNEL *pMIDIChannel; + S_SYNTH_VOICE *pVoice; + S_SYNTH *pSynth; + S_SYNTH *pNextSynth; + + /* establish some pointers */ + pVoice = &pVoiceMgr->voices[voiceNum]; + pSynth = pVoiceMgr->pSynth[GET_VSYNTH(pVoice->channel)]; + pMIDIChannel = &pSynth->channels[pVoice->channel & 15]; + pNextSynth = pVoiceMgr->pSynth[GET_VSYNTH(pVoice->nextChannel)]; + +#ifdef _DEBUG_VM +{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMRetargetStolenVoice: retargeting stolen voice %d on channel %d\n", + voiceNum, pVoice->channel); */ } + + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\to channel %d note: %d velocity: %d\n", + pVoice->nextChannel, pVoice->nextNote, pVoice->nextVelocity); */ } +#endif + + /* make sure new channel hasn't been muted by SP-MIDI since the voice was stolen */ + if ((pSynth->synthFlags & SYNTH_FLAG_SP_MIDI_ON) && + (pMIDIChannel->channelFlags & CHANNEL_FLAG_MUTE)) + { + VMFreeVoice(pVoiceMgr, pSynth, &pVoiceMgr->voices[voiceNum]); + return EAS_FALSE; + } + + /* if assigned to a new synth, correct the active voice count */ + if (pVoice->channel != pVoice->nextChannel) + { +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMRetargetStolenVoice: Note assigned to different virtual synth, adjusting numActiveVoices\n"); */ } +#endif + pSynth->numActiveVoices--; + pNextSynth->numActiveVoices++; + } + + /* assign new channel number, and increase channel voice count */ + pVoice->channel = pVoice->nextChannel; + pMIDIChannel = &pNextSynth->channels[pVoice->channel & 15]; + + /* assign other data */ + pVoice->note = pVoice->nextNote; + pVoice->velocity = pVoice->nextVelocity; + pVoice->nextChannel = UNASSIGNED_SYNTH_CHANNEL; + pVoice->regionIndex = pVoice->nextRegionIndex; + + /* save the flags, pfStartVoice() will clear them */ + flags = pVoice->voiceFlags; + + /* keep track of the note-start related workload */ + pVoiceMgr->workload += WORKLOAD_AMOUNT_START_NOTE; + + /* setup the voice parameters */ + pVoice->voiceState = eVoiceStateStart; + + /*lint -e{522} return not used at this time */ + GetSynthPtr(voiceNum)->pfStartVoice(pVoiceMgr, pNextSynth, &pVoiceMgr->voices[voiceNum], GetAdjustedVoiceNum(voiceNum), pVoice->regionIndex); + + /* did the new note already receive a MIDI note-off request? */ + if (flags & VOICE_FLAG_DEFER_MIDI_NOTE_OFF) + { +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMRetargetVoice: stolen note note-off request deferred\n"); */ } +#endif + pVoice->voiceFlags |= VOICE_FLAG_DEFER_MIDI_NOTE_OFF; + pNextSynth->synthFlags |= SYNTH_FLAG_DEFERRED_MIDI_NOTE_OFF_PENDING; + } + + return EAS_TRUE; +} + +/*---------------------------------------------------------------------------- + * VMCheckKeyGroup() + *---------------------------------------------------------------------------- + * If the note that we've been asked to start is in the same key group as + * any currently playing notes, then we must shut down the currently playing + * note in the same key group + *---------------------------------------------------------------------------- +*/ +void VMCheckKeyGroup (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U16 keyGroup, EAS_U8 channel) +{ + const S_REGION *pRegion; + EAS_INT voiceNum; + + /* increment frame workload */ + pVoiceMgr->workload += WORKLOAD_AMOUNT_KEY_GROUP; + + /* need to check all voices in case this is a layered sound */ + channel = VSynthToChannel(pSynth, channel); + for (voiceNum = 0; voiceNum < MAX_SYNTH_VOICES; voiceNum++) + { + if (pVoiceMgr->voices[voiceNum].voiceState != eVoiceStateStolen) + { + /* voice must be on the same channel */ + if (channel == pVoiceMgr->voices[voiceNum].channel) + { + /* check key group */ + pRegion = GetRegionPtr(pSynth, pVoiceMgr->voices[voiceNum].regionIndex); + if (keyGroup == (pRegion->keyGroupAndFlags & 0x0f00)) + { +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMCheckKeyGroup: voice %d matches key group %d\n", voiceNum, keyGroup >> 8); */ } +#endif + + /* if this voice was just started, set it to mute on the next buffer */ + if (pVoiceMgr->voices[voiceNum].voiceFlags & VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET) + pVoiceMgr->voices[voiceNum].voiceFlags |= VOICE_FLAG_DEFER_MUTE; + + /* mute immediately */ + else + VMMuteVoice(pVoiceMgr, voiceNum); + } + } + } + + /* for stolen voice, check new values */ + else + { + /* voice must be on the same channel */ + if (channel == pVoiceMgr->voices[voiceNum].nextChannel) + { + /* check key group */ + pRegion = GetRegionPtr(pSynth, pVoiceMgr->voices[voiceNum].nextRegionIndex); + if (keyGroup == (pRegion->keyGroupAndFlags & 0x0f00)) + { +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMCheckKeyGroup: voice %d matches key group %d\n", voiceNum, keyGroup >> 8); */ } +#endif + + /* if this voice was just started, set it to mute on the next buffer */ + if (pVoiceMgr->voices[voiceNum].voiceFlags & VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET) + pVoiceMgr->voices[voiceNum].voiceFlags |= VOICE_FLAG_DEFER_MUTE; + + /* mute immediately */ + else + VMMuteVoice(pVoiceMgr, voiceNum); + } + } + + } + } +} + +/*---------------------------------------------------------------------------- + * VMCheckPolyphonyLimiting() + *---------------------------------------------------------------------------- + * Purpose: + * We only play at most 2 of the same note on a MIDI channel. + * E.g., if we are asked to start note 36, and there are already two voices + * that are playing note 36, then we must steal the voice playing + * the oldest note 36 and use that stolen voice to play the new note 36. + * + * Inputs: + * nChannel - synth channel that wants to start a new note + * nKeyNumber - new note's midi note number + * nNoteVelocity - new note's velocity + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * pbVoiceStealingRequired - flag: this routine sets true if we needed to + * steal a voice + * * + * Side Effects: + * psSynthObject->m_sVoice[free voice num].m_nKeyNumber may be assigned + * psSynthObject->m_sVoice[free voice num].m_nVelocity may be assigned + *---------------------------------------------------------------------------- +*/ +EAS_BOOL VMCheckPolyphonyLimiting (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 note, EAS_U8 velocity, EAS_U16 regionIndex, EAS_I32 lowVoice, EAS_I32 highVoice) +{ + EAS_INT voiceNum; + EAS_INT oldestVoiceNum; + EAS_INT numVoicesPlayingNote; + EAS_U16 age; + EAS_U16 oldestNoteAge; + + pVoiceMgr->workload += WORKLOAD_AMOUNT_POLY_LIMIT; + + numVoicesPlayingNote = 0; + oldestVoiceNum = MAX_SYNTH_VOICES; + oldestNoteAge = 0; + channel = VSynthToChannel(pSynth, channel); + + /* examine each voice on this channel playing this note */ + for (voiceNum = lowVoice; voiceNum <= highVoice; voiceNum++) + { + /* check stolen notes separately */ + if (pVoiceMgr->voices[voiceNum].voiceState != eVoiceStateStolen) + { + + /* same channel and note ? */ + if ((channel == pVoiceMgr->voices[voiceNum].channel) && (note == pVoiceMgr->voices[voiceNum].note)) + { + numVoicesPlayingNote++; + age = pVoiceMgr->age - pVoiceMgr->voices[voiceNum].age; + + /* is this the oldest voice for this note? */ + if (age >= oldestNoteAge) + { + oldestNoteAge = age; + oldestVoiceNum = voiceNum; + } + } + } + + /* handle stolen voices */ + else + { + /* same channel and note ? */ + if ((channel == pVoiceMgr->voices[voiceNum].nextChannel) && (note == pVoiceMgr->voices[voiceNum].nextNote)) + { + numVoicesPlayingNote++; + } + } + } + + /* check to see if we exceeded poly limit */ + if (numVoicesPlayingNote < DEFAULT_CHANNEL_POLYPHONY_LIMIT) + return EAS_FALSE; + + /* make sure we have a voice to steal */ + if (oldestVoiceNum != MAX_SYNTH_VOICES) + { +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMCheckPolyphonyLimiting: voice %d has the oldest note\n", oldestVoiceNum); */ } + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "VMCheckPolyphonyLimiting: polyphony limiting requires shutting down note %d \n", pVoiceMgr->voices[oldestVoiceNum].note); */ } +#endif + VMStolenVoice(pVoiceMgr, pSynth, oldestVoiceNum, channel, note, velocity, regionIndex); + return EAS_TRUE; + } + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "VMCheckPolyphonyLimiting: No oldest voice to steal\n"); */ } +#endif + return EAS_FALSE; +} + +/*---------------------------------------------------------------------------- + * VMStartVoice() + *---------------------------------------------------------------------------- + * Starts a voice given a region index + *---------------------------------------------------------------------------- +*/ +void VMStartVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 note, EAS_U8 velocity, EAS_U16 regionIndex) +{ + const S_REGION *pRegion; + S_SYNTH_CHANNEL *pChannel; + EAS_INT voiceNum; + EAS_INT maxSynthPoly; + EAS_I32 lowVoice, highVoice; + EAS_U16 keyGroup; + + pChannel = &pSynth->channels[channel]; + pRegion = GetRegionPtr(pSynth, regionIndex); + + /* select correct synth */ +#if defined(_SECONDARY_SYNTH) || defined(EAS_SPLIT_WT_SYNTH) + { +#ifdef EAS_SPLIT_WT_SYNTH + if ((pRegion->keyGroupAndFlags & REGION_FLAG_OFF_CHIP) == 0) +#else + if ((regionIndex & FLAG_RGN_IDX_FM_SYNTH) == 0) +#endif + { + lowVoice = 0; + highVoice = NUM_PRIMARY_VOICES - 1; + } + else + { + lowVoice = NUM_PRIMARY_VOICES; + highVoice = MAX_SYNTH_VOICES - 1; + } + } +#else + lowVoice = 0; + highVoice = MAX_SYNTH_VOICES - 1; +#endif + + /* keep track of the note-start related workload */ + pVoiceMgr->workload+= WORKLOAD_AMOUNT_START_NOTE; + + /* other voices in pool, check for key group and poly limiting */ + if (pSynth->poolCount[pChannel->pool] != 0) + { + + /* check for key group exclusivity */ + keyGroup = pRegion->keyGroupAndFlags & 0x0f00; + if (keyGroup!= 0) + VMCheckKeyGroup(pVoiceMgr, pSynth, keyGroup, channel); + + /* check polyphony limit and steal a voice if necessary */ + if ((pRegion->keyGroupAndFlags & REGION_FLAG_NON_SELF_EXCLUSIVE) == 0) + { + if (VMCheckPolyphonyLimiting(pVoiceMgr, pSynth, channel, note, velocity, regionIndex, lowVoice, highVoice) == EAS_TRUE) + return; + } + } + + /* check max poly allocation */ + if ((pSynth->maxPolyphony == 0) || (pVoiceMgr->maxPolyphony < pSynth->maxPolyphony)) + maxSynthPoly = pVoiceMgr->maxPolyphony; + else + maxSynthPoly = pSynth->maxPolyphony; + + /* any free voices? */ + if ((pVoiceMgr->activeVoices < pVoiceMgr->maxPolyphony) && + (pSynth->numActiveVoices < maxSynthPoly) && + (EAS_SUCCESS == VMFindAvailableVoice(pVoiceMgr, &voiceNum, lowVoice, highVoice))) + { + S_SYNTH_VOICE *pVoice = &pVoiceMgr->voices[voiceNum]; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "VMStartVoice: Synth=%d\n", pSynth->vSynthNum); */ } +#endif + + /* bump voice counts */ + pVoiceMgr->activeVoices++; + pSynth->numActiveVoices++; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMStartVoice: voice %d assigned to channel %d note %d velocity %d\n", + voiceNum, channel, note, velocity); */ } +#endif + + /* save parameters */ + pVoiceMgr->voices[voiceNum].channel = VSynthToChannel(pSynth, channel); + pVoiceMgr->voices[voiceNum].note = note; + pVoiceMgr->voices[voiceNum].velocity = velocity; + + /* establish note age for voice stealing */ + pVoiceMgr->voices[voiceNum].age = pVoiceMgr->age++; + + /* setup the synthesis parameters */ + pVoiceMgr->voices[voiceNum].voiceState = eVoiceStateStart; + + /* increment voice pool count */ + IncVoicePoolCount(pVoiceMgr, pVoice); + + /* start voice on correct synth */ + /*lint -e{522} return not used at this time */ + GetSynthPtr(voiceNum)->pfStartVoice(pVoiceMgr, pSynth, &pVoiceMgr->voices[voiceNum], GetAdjustedVoiceNum(voiceNum), regionIndex); + return; + } + + /* no free voices, we have to steal one using appropriate algorithm */ + if (VMStealVoice(pVoiceMgr, pSynth, &voiceNum, channel, note, lowVoice, highVoice) == EAS_SUCCESS) + VMStolenVoice(pVoiceMgr, pSynth, voiceNum, channel, note, velocity, regionIndex); + +#ifdef _DEBUG_VM + else + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMStartVoice: Could not steal a voice for channel %d note %d velocity %d\n", + channel, note, velocity); */ } + } +#endif + + return; +} + +/*---------------------------------------------------------------------------- + * VMStartNote() + *---------------------------------------------------------------------------- + * Purpose: + * Update the synth's state to play the requested note on the requested + * channel if possible. + * + * Inputs: + * nChannel - the channel to start a note on + * nKeyNumber - the key number to start a note for + * nNoteVelocity - the key velocity from this note + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * Side Effects: + * psSynthObject->m_nNumActiveVoices may be incremented + * psSynthObject->m_sVoice[free voice num].m_nSynthChannel may be assigned + * psSynthObject->m_sVoice[free voice num].m_nKeyNumber is assigned + * psSynthObject->m_sVoice[free voice num].m_nVelocity is assigned + *---------------------------------------------------------------------------- +*/ +void VMStartNote (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 note, EAS_U8 velocity) +{ + S_SYNTH_CHANNEL *pChannel; + EAS_U16 regionIndex; + EAS_I16 adjustedNote; + + /* bump note count */ + pSynth->totalNoteCount++; + + pChannel = &pSynth->channels[channel]; + + /* check channel mute */ + if (pChannel->channelFlags & CHANNEL_FLAG_MUTE) + return; + +#ifdef EXTERNAL_AUDIO + /* pass event to external audio when requested */ + if ((pChannel->channelFlags & CHANNEL_FLAG_EXTERNAL_AUDIO) && (pSynth->cbEventFunc != NULL)) + { + S_EXT_AUDIO_EVENT event; + event.channel = channel; + event.note = note; + event.velocity = velocity; + event.noteOn = EAS_TRUE; + if (pSynth->cbEventFunc(pSynth->pExtAudioInstData, &event)) + return; + } +#endif + + /* start search at first region */ + regionIndex = pChannel->regionIndex; + + /* handle transposition */ + adjustedNote = note; + if (pChannel->channelFlags & CHANNEL_FLAG_RHYTHM_CHANNEL) + adjustedNote += pChannel->coarsePitch; + else + adjustedNote += pChannel->coarsePitch + pSynth->globalTranspose; + + /* limit adjusted key number so it does not wraparound, over/underflow */ + if (adjustedNote < 0) + { + adjustedNote = 0; + } + else if (adjustedNote > 127) + { + adjustedNote = 127; + } + +#if defined(DLS_SYNTHESIZER) + if (regionIndex & FLAG_RGN_IDX_DLS_SYNTH) + { + /* DLS voice */ + for (;;) + { + /*lint -e{740,826} cast OK, we know this is actually a DLS region */ + const S_DLS_REGION *pDLSRegion = (S_DLS_REGION*) GetRegionPtr(pSynth, regionIndex); + + /* check key against this region's key and velocity range */ + if (((adjustedNote >= pDLSRegion->wtRegion.region.rangeLow) && (adjustedNote <= pDLSRegion->wtRegion.region.rangeHigh)) && + ((velocity >= pDLSRegion->velLow) && (velocity <= pDLSRegion->velHigh))) + { + VMStartVoice(pVoiceMgr, pSynth, channel, note, velocity, regionIndex); + } + + /* last region in program? */ + if (pDLSRegion->wtRegion.region.keyGroupAndFlags & REGION_FLAG_LAST_REGION) + break; + + /* advance to next region */ + regionIndex++; + } + } + else +#endif + + /* braces here for #if clause */ + { + /* EAS voice */ + for (;;) + { + const S_REGION *pRegion = GetRegionPtr(pSynth, regionIndex); + + /* check key against this region's keyrange */ + if ((adjustedNote >= pRegion->rangeLow) && (adjustedNote <= pRegion->rangeHigh)) + { + VMStartVoice(pVoiceMgr, pSynth, channel, note, velocity, regionIndex); + break; + } + + /* last region in program? */ + if (pRegion->keyGroupAndFlags & REGION_FLAG_LAST_REGION) + break; + + /* advance to next region */ + regionIndex++; + } + } +} + +/*---------------------------------------------------------------------------- + * VMStopNote() + *---------------------------------------------------------------------------- + * Purpose: + * Update the synth's state to end the requested note on the requested + * channel. + * + * Inputs: + * nChannel - the channel to stop a note on + * nKeyNumber - the key number for this note off + * nNoteVelocity - the note-off velocity + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * Side Effects: + * psSynthObject->m_sVoice[free voice num].m_nSynthChannel may be assigned + * psSynthObject->m_sVoice[free voice num].m_nKeyNumber is assigned + * psSynthObject->m_sVoice[free voice num].m_nVelocity is assigned + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, velocity) reserved for future use */ +void VMStopNote (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 note, EAS_U8 velocity) +{ + S_SYNTH_CHANNEL *pChannel; + EAS_INT voiceNum; + + pChannel = &(pSynth->channels[channel]); + +#ifdef EXTERNAL_AUDIO + if ((pChannel->channelFlags & CHANNEL_FLAG_EXTERNAL_AUDIO) && (pSynth->cbEventFunc != NULL)) + { + S_EXT_AUDIO_EVENT event; + event.channel = channel; + event.note = note; + event.velocity = velocity; + event.noteOn = EAS_FALSE; + if (pSynth->cbEventFunc(pSynth->pExtAudioInstData, &event)) + return; + } +#endif + + /* keep track of the note-start workload */ + pVoiceMgr->workload += WORKLOAD_AMOUNT_STOP_NOTE; + + channel = VSynthToChannel(pSynth, channel); + + for (voiceNum=0; voiceNum < MAX_SYNTH_VOICES; voiceNum++) + { + + /* stolen notes are handled separately */ + if (eVoiceStateStolen != pVoiceMgr->voices[voiceNum].voiceState) + { + + /* channel and key number must match */ + if ((channel == pVoiceMgr->voices[voiceNum].channel) && (note == pVoiceMgr->voices[voiceNum].note)) + { +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMStopNote: voice %d channel %d note %d\n", + voiceNum, channel, note); */ } +#endif + + /* if sustain pedal is down, set deferred note-off flag */ + if (pChannel->channelFlags & CHANNEL_FLAG_SUSTAIN_PEDAL) + { + pVoiceMgr->voices[voiceNum].voiceFlags |= VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF; + continue; + } + + /* if this note just started, wait before we stop it */ + if (pVoiceMgr->voices[voiceNum].voiceFlags & VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET) + { +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tDeferred: Not started yet\n"); */ } +#endif + pVoiceMgr->voices[voiceNum].voiceFlags |= VOICE_FLAG_DEFER_MIDI_NOTE_OFF; + pSynth->synthFlags |= SYNTH_FLAG_DEFERRED_MIDI_NOTE_OFF_PENDING; + } + + /* release voice */ + else + VMReleaseVoice(pVoiceMgr, pSynth, voiceNum); + + } + } + + /* process stolen notes, new channel and key number must match */ + else if ((channel == pVoiceMgr->voices[voiceNum].nextChannel) && (note == pVoiceMgr->voices[voiceNum].nextNote)) + { + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMStopNote: voice %d channel %d note %d\n\tDeferred: Stolen voice\n", + voiceNum, channel, note); */ } +#endif + pVoiceMgr->voices[voiceNum].voiceFlags |= VOICE_FLAG_DEFER_MIDI_NOTE_OFF; + } + } +} + +/*---------------------------------------------------------------------------- + * VMFindAvailableVoice() + *---------------------------------------------------------------------------- + * Purpose: + * Find an available voice and return the voice number if available. + * + * Inputs: + * pnVoiceNumber - really an output, returns the voice number found + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * success - if there is an available voice + * failure - otherwise + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMFindAvailableVoice (S_VOICE_MGR *pVoiceMgr, EAS_INT *pVoiceNumber, EAS_I32 lowVoice, EAS_I32 highVoice) +{ + EAS_INT voiceNum; + + /* Check each voice to see if it has been assigned to a synth channel */ + for (voiceNum = lowVoice; voiceNum <= highVoice; voiceNum++) + { + /* check if this voice has been assigned to a synth channel */ + if ( pVoiceMgr->voices[voiceNum].voiceState == eVoiceStateFree) + { + *pVoiceNumber = voiceNum; /* this voice is available */ + return EAS_SUCCESS; + } + } + + /* if we reach here, we have not found a free voice */ + *pVoiceNumber = UNASSIGNED_SYNTH_VOICE; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMFindAvailableVoice: error, could not find an available voice\n"); */ } +#endif + return EAS_FAILURE; +} + +/*---------------------------------------------------------------------------- + * VMStealVoice() + *---------------------------------------------------------------------------- + * Purpose: + * Steal a voice and return the voice number + * + * Stealing algorithm: steal the best choice with minimal work, taking into + * account SP-Midi channel priorities and polyphony allocation. + * + * In one pass through all the voices, figure out which voice to steal + * taking into account a number of different factors: + * Priority of the voice's MIDI channel + * Number of voices over the polyphony allocation for voice's MIDI channel + * Amplitude of the voice + * Note age + * Key velocity (for voices that haven't been started yet) + * If any matching notes are found + * + * Inputs: + * pnVoiceNumber - really an output, see below + * nChannel - the channel that this voice wants to be started on + * nKeyNumber - the key number for this new voice + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * pnVoiceNumber - voice number of the voice that was stolen + * EAS_RESULT EAS_SUCCESS - always successful + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMStealVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_INT *pVoiceNumber, EAS_U8 channel, EAS_U8 note, EAS_I32 lowVoice, EAS_I32 highVoice) +{ + S_SYNTH_VOICE *pCurrVoice; + S_SYNTH *pCurrSynth; + EAS_INT voiceNum; + EAS_INT bestCandidate; + EAS_U8 currChannel; + EAS_U8 currNote; + EAS_I32 bestPriority; + EAS_I32 currentPriority; + + /* determine which voice to steal */ + bestPriority = 0; + bestCandidate = MAX_SYNTH_VOICES; + + for (voiceNum = lowVoice; voiceNum <= highVoice; voiceNum++) + { + pCurrVoice = &pVoiceMgr->voices[voiceNum]; + + /* ignore free voices */ + if (pCurrVoice->voiceState == eVoiceStateFree) + continue; + + /* for stolen voices, use the new parameters, not the old */ + if (pCurrVoice->voiceState == eVoiceStateStolen) + { + pCurrSynth = pVoiceMgr->pSynth[GET_VSYNTH(pCurrVoice->nextChannel)]; + currChannel = pCurrVoice->nextChannel; + currNote = pCurrVoice->nextNote; + } + else + { + pCurrSynth = pVoiceMgr->pSynth[GET_VSYNTH(pCurrVoice->channel)]; + currChannel = pCurrVoice->channel; + currNote = pCurrVoice->note; + } + + /* ignore voices that are higher priority */ + if (pSynth->priority > pCurrSynth->priority) + continue; +#ifdef _DEBUG_VM +// { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMStealVoice: New priority = %d exceeds old priority = %d\n", pSynth->priority, pCurrSynth->priority); */ } +#endif + + /* if voice is stolen or just started, reduce the likelihood it will be stolen */ + if (( pCurrVoice->voiceState == eVoiceStateStolen) || (pCurrVoice->voiceFlags & VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET)) + { + currentPriority = 128 - pCurrVoice->nextVelocity; + } + else + { + /* compute the priority of this voice, higher means better for stealing */ + /* use not age */ + currentPriority = (EAS_I32) pCurrVoice->age << NOTE_AGE_STEAL_WEIGHT; + + /* include note gain -higher gain is lower steal value */ + /*lint -e{704} use shift for performance */ + currentPriority += ((32768 >> (12 - NOTE_GAIN_STEAL_WEIGHT)) + 256) - + ((EAS_I32) pCurrVoice->gain >> (12 - NOTE_GAIN_STEAL_WEIGHT)); + } + + /* in SP-MIDI mode, include over poly allocation and channel priority */ + if (pSynth->synthFlags & SYNTH_FLAG_SP_MIDI_ON) + { + S_SYNTH_CHANNEL *pChannel = &pCurrSynth->channels[GET_CHANNEL(currChannel)]; + /*lint -e{701} use shift for performance */ + if (pSynth->poolCount[pChannel->pool] >= pSynth->poolAlloc[pChannel->pool]) + currentPriority += (pSynth->poolCount[pChannel->pool] -pSynth->poolAlloc[pChannel->pool] + 1) << CHANNEL_POLY_STEAL_WEIGHT; + + /* include channel priority */ + currentPriority += (EAS_I32)(pChannel->pool << CHANNEL_PRIORITY_STEAL_WEIGHT); + } + + /* if a note is already playing that matches this note, consider stealing it more readily */ + if ((note == currNote) && (channel == currChannel)) + currentPriority += NOTE_MATCH_PENALTY; + + /* is this the best choice so far? */ + if (currentPriority >= bestPriority) + { + bestPriority = currentPriority; + bestCandidate = voiceNum; + } + } + + /* may happen if all voices are allocated to a higher priority virtual synth */ + if (bestCandidate == MAX_SYNTH_VOICES) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMStealVoice: Unable to allocate a voice\n"); */ } + return EAS_ERROR_NO_VOICE_ALLOCATED; + } + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMStealVoice: Voice %d stolen\n", bestCandidate); */ } + + /* are we stealing a stolen voice? */ + if (pVoiceMgr->voices[bestCandidate].voiceState == eVoiceStateStolen) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "VMStealVoice: Voice %d is already marked as stolen and was scheduled to play ch: %d note: %d vel: %d\n", + bestCandidate, + pVoiceMgr->voices[bestCandidate].nextChannel, + pVoiceMgr->voices[bestCandidate].nextNote, + pVoiceMgr->voices[bestCandidate].nextVelocity); */ } + } +#endif + + *pVoiceNumber = (EAS_U16) bestCandidate; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMChannelPressure() + *---------------------------------------------------------------------------- + * Purpose: + * Change the channel pressure for the given channel + * + * Inputs: + * nChannel - the MIDI channel + * nVelocity - the channel pressure value + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * Side Effects: + * psSynthObject->m_sChannel[nChannel].m_nChannelPressure is updated + *---------------------------------------------------------------------------- +*/ +void VMChannelPressure (S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 value) +{ + S_SYNTH_CHANNEL *pChannel; + + pChannel = &(pSynth->channels[channel]); + pChannel->channelPressure = value; + + /* + set a channel flag to request parameter updates + for all the voices associated with this channel + */ + pChannel->channelFlags |= CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS; +} + +/*---------------------------------------------------------------------------- + * VMPitchBend() + *---------------------------------------------------------------------------- + * Purpose: + * Change the pitch wheel value for the given channel. + * This routine constructs the proper 14-bit argument when the calling routine + * passes the pitch LSB and MSB. + * + * Note: some midi disassemblers display a bipolar pitch bend value. + * We can display the bipolar value using + * if m_nPitchBend >= 0x2000 + * bipolar pitch bend = postive (m_nPitchBend - 0x2000) + * else + * bipolar pitch bend = negative (0x2000 - m_nPitchBend) + * + * Inputs: + * nChannel - the MIDI channel + * nPitchLSB - the LSB byte of the pitch bend message + * nPitchMSB - the MSB byte of the pitch bend message + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * psSynthObject->m_sChannel[nChannel].m_nPitchBend is changed + * + *---------------------------------------------------------------------------- +*/ +void VMPitchBend (S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 nPitchLSB, EAS_U8 nPitchMSB) +{ + S_SYNTH_CHANNEL *pChannel; + + pChannel = &(pSynth->channels[channel]); + pChannel->pitchBend = (EAS_I16) ((nPitchMSB << 7) | nPitchLSB); + + /* + set a channel flag to request parameter updates + for all the voices associated with this channel + */ + pChannel->channelFlags |= CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS; +} + +/*---------------------------------------------------------------------------- + * VMControlChange() + *---------------------------------------------------------------------------- + * Purpose: + * Change the controller (or mode) for the given channel. + * + * Inputs: + * nChannel - the MIDI channel + * nControllerNumber - the MIDI controller number + * nControlValue - the value for this controller message + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * Side Effects: + * psSynthObject->m_sChannel[nChannel] controller is changed + * + *---------------------------------------------------------------------------- +*/ +void VMControlChange (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 controller, EAS_U8 value) +{ + S_SYNTH_CHANNEL *pChannel; + + pChannel = &(pSynth->channels[channel]); + + /* + set a channel flag to request parameter updates + for all the voices associated with this channel + */ + pChannel->channelFlags |= CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS; + + switch ( controller ) + { + case MIDI_CONTROLLER_BANK_SELECT_MSB: +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMControlChange: Bank Select MSB: msb 0x%X\n", value); */ } +#endif + /* use this MSB with a zero LSB, until we get an LSB message */ + pChannel->bankNum = value << 8; + break; + + case MIDI_CONTROLLER_MOD_WHEEL: + /* we treat mod wheel as a 7-bit controller and only use the MSB */ + pChannel->modWheel = value; + break; + + case MIDI_CONTROLLER_VOLUME: + /* we treat volume as a 7-bit controller and only use the MSB */ + pChannel->volume = value; + break; + + case MIDI_CONTROLLER_PAN: + /* we treat pan as a 7-bit controller and only use the MSB */ + pChannel->pan = value; + break; + + case MIDI_CONTROLLER_EXPRESSION: + /* we treat expression as a 7-bit controller and only use the MSB */ + pChannel->expression = value; + break; + + case MIDI_CONTROLLER_BANK_SELECT_LSB: +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMControlChange: Bank Select LSB: lsb 0x%X\n", value); */ } +#endif + /* + construct bank number as 7-bits (stored as 8) of existing MSB + and 7-bits of new LSB (also stored as 8( + */ + pChannel->bankNum = + (pChannel->bankNum & 0xFF00) | value; + + break; + + case MIDI_CONTROLLER_SUSTAIN_PEDAL: + /* we treat sustain pedal as a boolean on/off bit flag */ + if (value < 64) + { + /* + we are requested to turn the pedal off, but first check + if the pedal is already on + */ + if (0 != + (pChannel->channelFlags & CHANNEL_FLAG_SUSTAIN_PEDAL) + ) + { + /* + The sustain flag is presently set and the damper pedal is on. + We are therefore transitioning from damper pedal ON to + damper pedal OFF. This means all notes in this channel + that received a note off while the damper pedal was on, and + had their note-off requests deferred, should now proceed to + the release state. + */ + VMReleaseAllDeferredNoteOffs(pVoiceMgr, pSynth, channel); + } /* end if sustain pedal is already on */ + + /* turn the sustain pedal off */ + pChannel->channelFlags &= ~CHANNEL_FLAG_SUSTAIN_PEDAL; + } + else + { + /* + we are requested to turn the pedal on, but first check + if the pedal is already off + */ + if (0 == + (pChannel->channelFlags & CHANNEL_FLAG_SUSTAIN_PEDAL) + ) + { + /* + The sustain flag is presently clear and the damper pedal is off. + We are therefore transitioning from damper pedal OFF to + damper pedal ON. Currently sounding notes should be left + unchanged. However, we should try to "catch" notes if possible. + If any notes have levels >= sustain level, catch them, + otherwise, let them continue to release. + */ + VMCatchNotesForSustainPedal(pVoiceMgr, pSynth, channel); + } + + /* turn the sustain pedal on */ + pChannel->channelFlags |= CHANNEL_FLAG_SUSTAIN_PEDAL; + } + + break; +#ifdef _REVERB + case MIDI_CONTROLLER_REVERB_SEND: + /* we treat send as a 7-bit controller and only use the MSB */ + pSynth->channels[channel].reverbSend = value; + break; +#endif +#ifdef _CHORUS + case MIDI_CONTROLLER_CHORUS_SEND: + /* we treat send as a 7-bit controller and only use the MSB */ + pSynth->channels[channel].chorusSend = value; + break; +#endif + case MIDI_CONTROLLER_RESET_CONTROLLERS: + /* despite the Midi message name, not ALL controllers are reset */ + pChannel->modWheel = DEFAULT_MOD_WHEEL; + pChannel->expression = DEFAULT_EXPRESSION; + + /* turn the sustain pedal off as default/reset */ + pChannel->channelFlags &= ~CHANNEL_FLAG_SUSTAIN_PEDAL; + pChannel->pitchBend = DEFAULT_PITCH_BEND; + + /* reset channel pressure */ + pChannel->channelPressure = DEFAULT_CHANNEL_PRESSURE; + + /* reset RPN values */ + pChannel->registeredParam = DEFAULT_REGISTERED_PARAM; + pChannel->pitchBendSensitivity = DEFAULT_PITCH_BEND_SENSITIVITY; + pChannel->finePitch = DEFAULT_FINE_PITCH; + pChannel->coarsePitch = DEFAULT_COARSE_PITCH; + + /* + program change, bank select, channel volume CC7, pan CC10 + are NOT reset + */ + break; + + /* + For logical reasons, the RPN data entry are grouped together. + However, keep in mind that these cases are not necessarily in + ascending order. + e.g., MIDI_CONTROLLER_DATA_ENTRY_MSB == 6, + whereas MIDI_CONTROLLER_SUSTAIN_PEDAL == 64. + So arrange these case statements in whatever manner is more efficient for + the processor / compiler. + */ + case MIDI_CONTROLLER_ENTER_DATA_MSB: + case MIDI_CONTROLLER_ENTER_DATA_LSB: + case MIDI_CONTROLLER_SELECT_RPN_LSB: + case MIDI_CONTROLLER_SELECT_RPN_MSB: + case MIDI_CONTROLLER_SELECT_NRPN_MSB: + case MIDI_CONTROLLER_SELECT_NRPN_LSB: + VMUpdateRPNStateMachine(pSynth, channel, controller, value); + break; + + case MIDI_CONTROLLER_ALL_SOUND_OFF: + case MIDI_CONTROLLER_ALL_NOTES_OFF: + case MIDI_CONTROLLER_OMNI_OFF: + case MIDI_CONTROLLER_OMNI_ON: + case MIDI_CONTROLLER_MONO_ON_POLY_OFF: + case MIDI_CONTROLLER_POLY_ON_MONO_OFF: + /* NOTE: we treat all sounds off the same as all notes off */ + VMAllNotesOff(pVoiceMgr, pSynth, channel); + break; + + default: +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMControlChange: controller %d not yet implemented\n", controller); */ } +#endif + break; + + } + + return; +} + +/*---------------------------------------------------------------------------- + * VMUpdateRPNStateMachine() + *---------------------------------------------------------------------------- + * Purpose: + * Call this function when we want to parse RPN related controller messages. + * We only support RPN0 (pitch bend sensitivity), RPN1 (fine tuning) and + * RPN2 (coarse tuning). Any other RPNs or NRPNs are ignored for now. + *. + * Supports any order, so not a state machine anymore. This function was + * rewritten to work correctly regardless of order. + * + * Inputs: + * nChannel - the channel this controller message is coming from + * nControllerNumber - which RPN related controller + * nControlValue - the value of the RPN related controller + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * returns EAS_RESULT, which is typically EAS_SUCCESS, since there are + * few possible errors + * + * Side Effects: + * gsSynthObject.m_sChannel[nChannel].m_nPitchBendSensitivity + * (or m_nFinePitch or m_nCoarsePitch) + * will be updated if the proper RPN message is received. + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMUpdateRPNStateMachine (S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 controller, EAS_U8 value) +{ + S_SYNTH_CHANNEL *pChannel; + +#ifdef _DEBUG_VM + if (channel >= NUM_SYNTH_CHANNELS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMUpdateRPNStateMachines: error, %d invalid channel number\n", + channel); */ } + return EAS_FAILURE; + } +#endif + + pChannel = &(pSynth->channels[channel]); + + switch (controller) + { + case MIDI_CONTROLLER_SELECT_NRPN_MSB: + case MIDI_CONTROLLER_SELECT_NRPN_LSB: + pChannel->registeredParam = DEFAULT_REGISTERED_PARAM; + break; + case MIDI_CONTROLLER_SELECT_RPN_MSB: + pChannel->registeredParam = + (pChannel->registeredParam & 0x7F) | (value<<7); + break; + case MIDI_CONTROLLER_SELECT_RPN_LSB: + pChannel->registeredParam = + (pChannel->registeredParam & 0x7F00) | value; + break; + case MIDI_CONTROLLER_ENTER_DATA_MSB: + switch (pChannel->registeredParam) + { + case 0: + pChannel->pitchBendSensitivity = value * 100; + break; + case 1: + /*lint -e{702} */ + pChannel->finePitch = (EAS_I8)((((value << 7) - 8192) * 100) >> 13); + break; + case 2: + pChannel->coarsePitch = (EAS_I8)(value - 64); + break; + default: + break; + } + break; + case MIDI_CONTROLLER_ENTER_DATA_LSB: + switch (pChannel->registeredParam) + { + case 0: + //ignore lsb + break; + case 1: + //ignore lsb + break; + case 2: + //ignore lsb + break; + default: + break; + } + break; + default: + return EAS_FAILURE; //not a RPN related controller + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMUpdateStaticChannelParameters() + *---------------------------------------------------------------------------- + * Purpose: + * Update all of the static channel parameters for channels that have had + * a controller change values + * Or if the synth has signalled that all channels must forcibly + * be updated + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * none + * + * Side Effects: + * - psSynthObject->m_sChannel[].m_nStaticGain and m_nStaticPitch + * are updated for channels whose controller values have changed + * or if the synth has signalled that all channels must forcibly + * be updated + *---------------------------------------------------------------------------- +*/ +void VMUpdateStaticChannelParameters (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth) +{ + EAS_INT channel; + + if (pSynth->synthFlags & SYNTH_FLAG_UPDATE_ALL_CHANNEL_PARAMETERS) + { + /* + the synth wants us to forcibly update all channel + parameters. This event occurs when we are about to + finish resetting the synth + */ + for (channel = 0; channel < NUM_SYNTH_CHANNELS; channel++) + { +#ifdef _HYBRID_SYNTH + if (pSynth->channels[channel].regionIndex & FLAG_RGN_IDX_FM_SYNTH) + pSecondarySynth->pfUpdateChannel(pVoiceMgr, pSynth, (EAS_U8) channel); + else + pPrimarySynth->pfUpdateChannel(pVoiceMgr, pSynth, (EAS_U8) channel); +#else + pPrimarySynth->pfUpdateChannel(pVoiceMgr, pSynth, (EAS_U8) channel); +#endif + } + + /* + clear the flag to indicates we have now forcibly + updated all channel parameters + */ + pSynth->synthFlags &= ~SYNTH_FLAG_UPDATE_ALL_CHANNEL_PARAMETERS; + } + else + { + + /* only update channel params if signalled by a channel flag */ + for (channel = 0; channel < NUM_SYNTH_CHANNELS; channel++) + { + if ( 0 != (pSynth->channels[channel].channelFlags & CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS)) + { +#ifdef _HYBRID_SYNTH + if (pSynth->channels[channel].regionIndex & FLAG_RGN_IDX_FM_SYNTH) + pSecondarySynth->pfUpdateChannel(pVoiceMgr, pSynth, (EAS_U8) channel); + else + pPrimarySynth->pfUpdateChannel(pVoiceMgr, pSynth, (EAS_U8) channel); +#else + pPrimarySynth->pfUpdateChannel(pVoiceMgr, pSynth, (EAS_U8) channel); +#endif + } + } + + } + + return; +} + +/*---------------------------------------------------------------------------- + * VMFindProgram() + *---------------------------------------------------------------------------- + * Purpose: + * Look up an individual program in sound library. This function + * searches the bank list for a program, then the individual program + * list. + * + * Inputs: + * + * Outputs: + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT VMFindProgram (const S_EAS *pEAS, EAS_U32 bank, EAS_U8 programNum, EAS_U16 *pRegionIndex) +{ + EAS_U32 locale; + const S_PROGRAM *p; + EAS_U16 i; + EAS_U16 regionIndex; + + /* make sure we have a valid sound library */ + if (pEAS == NULL) + return EAS_FAILURE; + + /* search the banks */ + for (i = 0; i < pEAS->numBanks; i++) + { + if (bank == (EAS_U32) pEAS->pBanks[i].locale) + { + regionIndex = pEAS->pBanks[i].regionIndex[programNum]; + if (regionIndex != INVALID_REGION_INDEX) + { + *pRegionIndex = regionIndex; + return EAS_SUCCESS; + } + break; + } + } + + /* establish locale */ + locale = ( bank << 8) | programNum; + + /* search for program */ + for (i = 0, p = pEAS->pPrograms; i < pEAS->numPrograms; i++, p++) + { + if (p->locale == locale) + { + *pRegionIndex = p->regionIndex; + return EAS_SUCCESS; + } + } + + return EAS_FAILURE; +} + +#ifdef DLS_SYNTHESIZER +/*---------------------------------------------------------------------------- + * VMFindDLSProgram() + *---------------------------------------------------------------------------- + * Purpose: + * Look up an individual program in sound library. This function + * searches the bank list for a program, then the individual program + * list. + * + * Inputs: + * + * Outputs: + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT VMFindDLSProgram (const S_DLS *pDLS, EAS_U32 bank, EAS_U8 programNum, EAS_U16 *pRegionIndex) +{ + EAS_U32 locale; + const S_PROGRAM *p; + EAS_U16 i; + + /* make sure we have a valid sound library */ + if (pDLS == NULL) + return EAS_FAILURE; + + /* establish locale */ + locale = (bank << 8) | programNum; + + /* search for program */ + for (i = 0, p = pDLS->pDLSPrograms; i < pDLS->numDLSPrograms; i++, p++) + { + if (p->locale == locale) + { + *pRegionIndex = p->regionIndex; + return EAS_SUCCESS; + } + } + + return EAS_FAILURE; +} +#endif + +/*---------------------------------------------------------------------------- + * VMProgramChange() + *---------------------------------------------------------------------------- + * Purpose: + * Change the instrument (program) for the given channel. + * + * Depending on the program number, and the bank selected for this channel, the + * program may be in ROM, RAM (from SMAF or CMX related RAM wavetable), or + * Alternate wavetable (from mobile DLS or other DLS file) + * + * This function figures out what wavetable should be used, and sets it up as the + * wavetable to use for this channel. Also the channel may switch from a melodic + * channel to a rhythm channel, or vice versa. + * + * Inputs: + * + * Outputs: + * Side Effects: + * gsSynthObject.m_sChannel[nChannel].m_nProgramNumber is likely changed + * gsSynthObject.m_sChannel[nChannel].m_psEAS may be changed + * gsSynthObject.m_sChannel[nChannel].m_bRhythmChannel may be changed + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pVoiceMgr) reserved for future use */ +void VMProgramChange (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 program) +{ + S_SYNTH_CHANNEL *pChannel; + EAS_U32 bank; + EAS_U16 regionIndex; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "VMProgramChange: vSynthNum=%d, channel=%d, program=%d\n", pSynth->vSynthNum, channel, program); */ } +#endif + + /* setup pointer to MIDI channel data */ + pChannel = &pSynth->channels[channel]; + bank = pChannel->bankNum; + + /* allow channels to switch between being melodic or rhythm channels, using GM2 CC values */ + if ((bank & 0xFF00) == DEFAULT_RHYTHM_BANK_NUMBER) + { + /* make it a rhythm channel */ + pChannel->channelFlags |= CHANNEL_FLAG_RHYTHM_CHANNEL; + } + else if ((bank & 0xFF00) == DEFAULT_MELODY_BANK_NUMBER) + { + /* make it a melody channel */ + pChannel->channelFlags &= ~CHANNEL_FLAG_RHYTHM_CHANNEL; + } + + regionIndex = DEFAULT_REGION_INDEX; + +#ifdef EXTERNAL_AUDIO + /* give the external audio interface a chance to handle it */ + if (pSynth->cbProgChgFunc != NULL) + { + S_EXT_AUDIO_PRG_CHG prgChg; + prgChg.channel = channel; + prgChg.bank = (EAS_U16) bank; + prgChg.program = program; + if (pSynth->cbProgChgFunc(pSynth->pExtAudioInstData, &prgChg)) + pChannel->channelFlags |= CHANNEL_FLAG_EXTERNAL_AUDIO; + } + +#endif + + +#ifdef DLS_SYNTHESIZER + /* first check for DLS program that may overlay the internal instrument */ + if (VMFindDLSProgram(pSynth->pDLS, bank, program, ®ionIndex) != EAS_SUCCESS) +#endif + + /* braces to support 'if' clause above */ + { + + /* look in the internal banks */ + if (VMFindProgram(pSynth->pEAS, bank, program, ®ionIndex) != EAS_SUCCESS) + + /* fall back to default bank */ + { + if (pSynth->channels[channel].channelFlags & CHANNEL_FLAG_RHYTHM_CHANNEL) + bank = DEFAULT_RHYTHM_BANK_NUMBER; + else + bank = DEFAULT_MELODY_BANK_NUMBER; + + if (VMFindProgram(pSynth->pEAS, bank, program, ®ionIndex) != EAS_SUCCESS) + + /* switch to program 0 in the default bank */ + { + if (VMFindProgram(pSynth->pEAS, bank, 0, ®ionIndex) != EAS_SUCCESS) + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "VMProgramChange: No program @ %03d:%03d:%03d\n", + (bank >> 8) & 0x7f, bank & 0x7f, program); */ } + } + } + } + + /* we have our new program change for this channel */ + pChannel->programNum = program; + pChannel->regionIndex = regionIndex; + + /* + set a channel flag to request parameter updates + for all the voices associated with this channel + */ + pChannel->channelFlags |= CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS; + + return; +} + +/*---------------------------------------------------------------------------- + * VMAddSamples() + *---------------------------------------------------------------------------- + * Purpose: + * Synthesize the requested number of samples (block based processing) + * + * Inputs: + * nNumSamplesToAdd - number of samples to write to buffer + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * number of voices rendered + * + * Side Effects: + * - samples are added to the presently free buffer + * + *---------------------------------------------------------------------------- +*/ +EAS_I32 VMAddSamples (S_VOICE_MGR *pVoiceMgr, EAS_I32 *pMixBuffer, EAS_I32 numSamples) +{ + S_SYNTH *pSynth; + EAS_INT voicesRendered; + EAS_INT voiceNum; + EAS_BOOL done; + +#ifdef _REVERB + EAS_PCM *pReverbSendBuffer; +#endif // ifdef _REVERB + +#ifdef _CHORUS + EAS_PCM *pChorusSendBuffer; +#endif // ifdef _CHORUS + + voicesRendered = 0; + for (voiceNum = 0; voiceNum < MAX_SYNTH_VOICES; voiceNum++) + { + + /* retarget stolen voices */ + if ((pVoiceMgr->voices[voiceNum].voiceState == eVoiceStateStolen) && (pVoiceMgr->voices[voiceNum].gain <= 0)) + VMRetargetStolenVoice(pVoiceMgr, voiceNum); + + /* get pointer to virtual synth */ + pSynth = pVoiceMgr->pSynth[pVoiceMgr->voices[voiceNum].channel >> 4]; + + /* synthesize active voices */ + if (pVoiceMgr->voices[voiceNum].voiceState != eVoiceStateFree) + { + done = GetSynthPtr(voiceNum)->pfUpdateVoice(pVoiceMgr, pSynth, &pVoiceMgr->voices[voiceNum], GetAdjustedVoiceNum(voiceNum), pMixBuffer, numSamples); + voicesRendered++; + + /* voice is finished */ + if (done == EAS_TRUE) + { + /* set gain of stolen voice to zero so it will be restarted */ + if (pVoiceMgr->voices[voiceNum].voiceState == eVoiceStateStolen) + pVoiceMgr->voices[voiceNum].gain = 0; + + /* or return it to the free voice pool */ + else + VMFreeVoice(pVoiceMgr, pSynth, &pVoiceMgr->voices[voiceNum]); + } + + /* if this voice is scheduled to be muted, set the mute flag */ + if (pVoiceMgr->voices[voiceNum].voiceFlags & VOICE_FLAG_DEFER_MUTE) + { + pVoiceMgr->voices[voiceNum].voiceFlags &= ~(VOICE_FLAG_DEFER_MUTE | VOICE_FLAG_DEFER_MIDI_NOTE_OFF); + VMMuteVoice(pVoiceMgr, voiceNum); + } + + /* if voice just started, advance state to play */ + if (pVoiceMgr->voices[voiceNum].voiceState == eVoiceStateStart) + pVoiceMgr->voices[voiceNum].voiceState = eVoiceStatePlay; + } + } + + return voicesRendered; +} + +/*---------------------------------------------------------------------------- + * VMRender() + *---------------------------------------------------------------------------- + * Purpose: + * This routine renders a frame of audio + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * pVoicesRendered - number of voices rendered this frame + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMRender (S_VOICE_MGR *pVoiceMgr, EAS_I32 numSamples, EAS_I32 *pMixBuffer, EAS_I32 *pVoicesRendered) +{ + S_SYNTH *pSynth; + EAS_INT i; + EAS_INT channel; + +#ifdef _CHECKED_BUILD + SanityCheck(pVoiceMgr); +#endif + + /* update MIDI channel parameters */ + *pVoicesRendered = 0; + for (i = 0; i < MAX_VIRTUAL_SYNTHESIZERS; i++) + { + if (pVoiceMgr->pSynth[i] != NULL) + VMUpdateStaticChannelParameters(pVoiceMgr, pVoiceMgr->pSynth[i]); + } + + /* synthesize a buffer of audio */ + *pVoicesRendered = VMAddSamples(pVoiceMgr, pMixBuffer, numSamples); + + /* + * check for deferred note-off messages + * If flag is set, that means one or more voices are expecting deferred + * midi note-off messages because the midi note-on and corresponding midi + * note-off requests occurred during the same update interval. The goal + * is the defer the note-off request so that the note can at least start. + */ + for (i = 0; i < MAX_VIRTUAL_SYNTHESIZERS; i++) + { + pSynth = pVoiceMgr->pSynth[i]; + + if (pSynth== NULL) + continue; + + if (pSynth->synthFlags & SYNTH_FLAG_DEFERRED_MIDI_NOTE_OFF_PENDING) + VMDeferredStopNote(pVoiceMgr, pSynth); + + /* check if we need to reset the synth */ + if ((pSynth->synthFlags & SYNTH_FLAG_RESET_IS_REQUESTED) && + (pSynth->numActiveVoices == 0)) + { + /* + complete the process of resetting the synth now that + all voices have muted + */ +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMAddSamples: complete the reset process\n"); */ } +#endif + + VMInitializeAllChannels(pVoiceMgr, pSynth); + VMInitializeAllVoices(pVoiceMgr, pSynth->vSynthNum); + + /* clear the reset flag */ + pSynth->synthFlags &= ~SYNTH_FLAG_RESET_IS_REQUESTED; + } + + /* clear channel update flags */ + for (channel = 0; channel < NUM_SYNTH_CHANNELS; channel++) + pSynth->channels[channel].channelFlags &= ~CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS; + + } + +#ifdef _CHECKED_BUILD + SanityCheck(pVoiceMgr); +#endif + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMInitWorkload() + *---------------------------------------------------------------------------- + * Purpose: + * Clears the workload counter + * + * Inputs: + * pVoiceMgr - pointer to instance data + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMInitWorkload (S_VOICE_MGR *pVoiceMgr) +{ + pVoiceMgr->workload = 0; +} + +/*---------------------------------------------------------------------------- + * VMSetWorkload() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the max workload for a single frame. + * + * Inputs: + * pVoiceMgr - pointer to instance data + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMSetWorkload (S_VOICE_MGR *pVoiceMgr, EAS_I32 maxWorkLoad) +{ + pVoiceMgr->maxWorkLoad = maxWorkLoad; +} + +/*---------------------------------------------------------------------------- + * VMCheckWorkload() + *---------------------------------------------------------------------------- + * Purpose: + * Checks to see if work load has been exceeded on this frame. + * + * Inputs: + * pVoiceMgr - pointer to instance data + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_BOOL VMCheckWorkload (S_VOICE_MGR *pVoiceMgr) +{ + if (pVoiceMgr->maxWorkLoad > 0) + return (EAS_BOOL) (pVoiceMgr->workload >= pVoiceMgr->maxWorkLoad); + return EAS_FALSE; +} + +/*---------------------------------------------------------------------------- + * VMActiveVoices() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the number of active voices in the synthesizer. + * + * Inputs: + * pEASData - pointer to instance data + * + * Outputs: + * Returns the number of active voices + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_I32 VMActiveVoices (S_SYNTH *pSynth) +{ + return pSynth->numActiveVoices; +} + +/*---------------------------------------------------------------------------- + * VMSetSynthPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Set the synth to a new polyphony value. Value must be >= 1 and + * <= MAX_SYNTH_VOICES. This function will pin the polyphony at those limits + * + * Inputs: + * pVoiceMgr pointer to synthesizer data + * polyphonyCount desired polyphony count + * synth synthesizer number (0 = onboard, 1 = DSP) + * + * Outputs: + * Returns error code + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMSetSynthPolyphony (S_VOICE_MGR *pVoiceMgr, EAS_I32 synth, EAS_I32 polyphonyCount) +{ + EAS_INT i; + EAS_INT activeVoices; + + /* lower limit */ + if (polyphonyCount < 1) + polyphonyCount = 1; + + /* split architecture */ +#if defined(_SECONDARY_SYNTH) || defined(EAS_SPLIT_WT_SYNTH) + if (synth == EAS_MCU_SYNTH) + { + if (polyphonyCount > NUM_PRIMARY_VOICES) + polyphonyCount = NUM_PRIMARY_VOICES; + if (pVoiceMgr->maxPolyphonyPrimary == polyphonyCount) + return EAS_SUCCESS; + pVoiceMgr->maxPolyphonyPrimary = (EAS_U16) polyphonyCount; + } + else if (synth == EAS_DSP_SYNTH) + { + if (polyphonyCount > NUM_SECONDARY_VOICES) + polyphonyCount = NUM_SECONDARY_VOICES; + if (pVoiceMgr->maxPolyphonySecondary == polyphonyCount) + return EAS_SUCCESS; + pVoiceMgr->maxPolyphonySecondary = (EAS_U16) polyphonyCount; + } + else + return EAS_ERROR_PARAMETER_RANGE; + + /* setting for SP-MIDI */ + pVoiceMgr->maxPolyphony = pVoiceMgr->maxPolyphonyPrimary + pVoiceMgr->maxPolyphonySecondary; + + /* standard architecture */ +#else + if (synth != EAS_MCU_SYNTH) + return EAS_ERROR_PARAMETER_RANGE; + + /* pin desired value to possible limits */ + if (polyphonyCount > MAX_SYNTH_VOICES) + polyphonyCount = MAX_SYNTH_VOICES; + + /* set polyphony, if value is different than current value */ + if (pVoiceMgr->maxPolyphony == polyphonyCount) + return EAS_SUCCESS; + + pVoiceMgr->maxPolyphony = (EAS_U16) polyphonyCount; +#endif + + /* if SPMIDI enabled, update channel masking based on new polyphony */ + for (i = 0; i < MAX_VIRTUAL_SYNTHESIZERS; i++) + { + if (pVoiceMgr->pSynth[i]) + { + if (pVoiceMgr->pSynth[i]->synthFlags & SYNTH_FLAG_SP_MIDI_ON) + VMMIPUpdateChannelMuting(pVoiceMgr, pVoiceMgr->pSynth[i]); + else + pVoiceMgr->pSynth[i]->poolAlloc[0] = (EAS_U8) polyphonyCount; + } + } + + /* are we under polyphony limit? */ + if (pVoiceMgr->activeVoices <= polyphonyCount) + return EAS_SUCCESS; + + /* count the number of active voices */ + activeVoices = 0; + for (i = 0; i < MAX_SYNTH_VOICES; i++) + { + + /* is voice active? */ + if ((pVoiceMgr->voices[i].voiceState != eVoiceStateFree) && (pVoiceMgr->voices[i].voiceState != eVoiceStateMuting)) + activeVoices++; + } + + /* we may have to mute voices to reach new target */ + while (activeVoices > polyphonyCount) + { + S_SYNTH *pSynth; + S_SYNTH_VOICE *pVoice; + EAS_I32 currentPriority, bestPriority; + EAS_INT bestCandidate; + + /* find the lowest priority voice */ + bestPriority = bestCandidate = -1; + for (i = 0; i < MAX_SYNTH_VOICES; i++) + { + + pVoice = &pVoiceMgr->voices[i]; + + /* ignore free and muting voices */ + if ((pVoice->voiceState == eVoiceStateFree) || (pVoice->voiceState == eVoiceStateMuting)) + continue; + + pSynth = pVoiceMgr->pSynth[GET_VSYNTH(pVoice->channel)]; + + /* if voice is stolen or just started, reduce the likelihood it will be stolen */ + if (( pVoice->voiceState == eVoiceStateStolen) || (pVoice->voiceFlags & VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET)) + { + /* include velocity */ + currentPriority = 128 - pVoice->nextVelocity; + + /* include channel priority */ + currentPriority += pSynth->channels[GET_CHANNEL(pVoice->nextChannel)].pool << CHANNEL_PRIORITY_STEAL_WEIGHT; + } + else + { + /* include age */ + currentPriority = (EAS_I32) pVoice->age << NOTE_AGE_STEAL_WEIGHT; + + /* include note gain -higher gain is lower steal value */ + /*lint -e{704} use shift for performance */ + currentPriority += ((32768 >> (12 - NOTE_GAIN_STEAL_WEIGHT)) + 256) - + ((EAS_I32) pVoice->gain >> (12 - NOTE_GAIN_STEAL_WEIGHT)); + + /* include channel priority */ + currentPriority += pSynth->channels[GET_CHANNEL(pVoice->channel)].pool << CHANNEL_PRIORITY_STEAL_WEIGHT; + } + + /* include synth priority */ + currentPriority += pSynth->priority << SYNTH_PRIORITY_WEIGHT; + + /* is this the best choice so far? */ + if (currentPriority > bestPriority) + { + bestPriority = currentPriority; + bestCandidate = i; + } + } + + /* shutdown best candidate */ + if (bestCandidate < 0) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "VMSetPolyphony: Unable to reduce polyphony\n"); */ } + break; + } + + /* shut down this voice */ + /*lint -e{771} pSynth is initialized if bestCandidate >= 0 */ + VMMuteVoice(pVoiceMgr, bestCandidate); + activeVoices--; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMGetSynthPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current polyphony setting + * + * Inputs: + * pVoiceMgr pointer to synthesizer data + * synth synthesizer number (0 = onboard, 1 = DSP) + * + * Outputs: + * Returns actual polyphony value set, as pinned by limits + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMGetSynthPolyphony (S_VOICE_MGR *pVoiceMgr, EAS_I32 synth, EAS_I32 *pPolyphonyCount) +{ + +#if defined(_SECONDARY_SYNTH) || defined(EAS_SPLIT_WT_SYNTH) + if (synth == EAS_MCU_SYNTH) + *pPolyphonyCount = pVoiceMgr->maxPolyphonyPrimary; + else if (synth == EAS_DSP_SYNTH) + *pPolyphonyCount = pVoiceMgr->maxPolyphonySecondary; + else + return EAS_ERROR_PARAMETER_RANGE; +#else + if (synth != EAS_MCU_SYNTH) + return EAS_ERROR_PARAMETER_RANGE; + *pPolyphonyCount = pVoiceMgr->maxPolyphony; +#endif + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMSetPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Set the virtual synth polyphony. 0 = no limit (i.e. can use + * all available voices). + * + * Inputs: + * pVoiceMgr pointer to synthesizer data + * polyphonyCount desired polyphony count + * pSynth pointer to virtual synth + * + * Outputs: + * Returns error code + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMSetPolyphony (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 polyphonyCount) +{ + EAS_INT i; + EAS_INT activeVoices; + + /* check limits */ + if (polyphonyCount < 0) + return EAS_ERROR_PARAMETER_RANGE; + + /* zero is max polyphony */ + if ((polyphonyCount == 0) || (polyphonyCount > MAX_SYNTH_VOICES)) + { + pSynth->maxPolyphony = 0; + return EAS_SUCCESS; + } + + /* set new polyphony */ + pSynth->maxPolyphony = (EAS_U16) polyphonyCount; + + /* max polyphony is minimum of virtual synth and actual synth */ + if (polyphonyCount > pVoiceMgr->maxPolyphony) + polyphonyCount = pVoiceMgr->maxPolyphony; + + /* if SP-MIDI mode, update the channel muting */ + if (pSynth->synthFlags & SYNTH_FLAG_SP_MIDI_ON) + VMMIPUpdateChannelMuting(pVoiceMgr, pSynth); + else + pSynth->poolAlloc[0] = (EAS_U8) polyphonyCount; + + /* are we under polyphony limit? */ + if (pSynth->numActiveVoices <= polyphonyCount) + return EAS_SUCCESS; + + /* count the number of active voices */ + activeVoices = 0; + for (i = 0; i < MAX_SYNTH_VOICES; i++) + { + /* this synth? */ + if (GET_VSYNTH(pVoiceMgr->voices[i].nextChannel) != pSynth->vSynthNum) + continue; + + /* is voice active? */ + if ((pVoiceMgr->voices[i].voiceState != eVoiceStateFree) && (pVoiceMgr->voices[i].voiceState != eVoiceStateMuting)) + activeVoices++; + } + + /* we may have to mute voices to reach new target */ + while (activeVoices > polyphonyCount) + { + S_SYNTH_VOICE *pVoice; + EAS_I32 currentPriority, bestPriority; + EAS_INT bestCandidate; + + /* find the lowest priority voice */ + bestPriority = bestCandidate = -1; + for (i = 0; i < MAX_SYNTH_VOICES; i++) + { + pVoice = &pVoiceMgr->voices[i]; + + /* this synth? */ + if (GET_VSYNTH(pVoice->nextChannel) != pSynth->vSynthNum) + continue; + + /* if voice is stolen or just started, reduce the likelihood it will be stolen */ + if (( pVoice->voiceState == eVoiceStateStolen) || (pVoice->voiceFlags & VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET)) + { + /* include velocity */ + currentPriority = 128 - pVoice->nextVelocity; + + /* include channel priority */ + currentPriority += pSynth->channels[GET_CHANNEL(pVoice->nextChannel)].pool << CHANNEL_PRIORITY_STEAL_WEIGHT; + } + else + { + /* include age */ + currentPriority = (EAS_I32) pVoice->age << NOTE_AGE_STEAL_WEIGHT; + + /* include note gain -higher gain is lower steal value */ + /*lint -e{704} use shift for performance */ + currentPriority += ((32768 >> (12 - NOTE_GAIN_STEAL_WEIGHT)) + 256) - + ((EAS_I32) pVoice->gain >> (12 - NOTE_GAIN_STEAL_WEIGHT)); + + /* include channel priority */ + currentPriority += pSynth->channels[GET_CHANNEL(pVoice->nextChannel)].pool << CHANNEL_PRIORITY_STEAL_WEIGHT; + } + + /* is this the best choice so far? */ + if (currentPriority > bestPriority) + { + bestPriority = currentPriority; + bestCandidate = i; + } + } + + /* shutdown best candidate */ + if (bestCandidate < 0) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "VMSetPolyphony: Unable to reduce polyphony\n"); */ } + break; + } + + /* shut down this voice */ + VMMuteVoice(pVoiceMgr, bestCandidate); + activeVoices--; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMGetPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Get the virtual synth polyphony + * + * Inputs: + * pVoiceMgr pointer to synthesizer data + * pPolyphonyCount pointer to variable to hold polyphony count + * pSynth pointer to virtual synth + * + * Outputs: + * Returns error code + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pVoiceMgr) reserved for future use */ +EAS_RESULT VMGetPolyphony (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 *pPolyphonyCount) +{ + *pPolyphonyCount = (EAS_U16) pSynth->maxPolyphony; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMSetPriority() + *---------------------------------------------------------------------------- + * Purpose: + * Set the virtual synth priority + * + * Inputs: + * pVoiceMgr pointer to synthesizer data + * priority new priority + * pSynth pointer to virtual synth + * + * Outputs: + * Returns error code + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pVoiceMgr) reserved for future use */ +EAS_RESULT VMSetPriority (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 priority) +{ + pSynth->priority = (EAS_U8) priority ; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMGetPriority() + *---------------------------------------------------------------------------- + * Purpose: + * Get the virtual synth priority + * + * Inputs: + * pVoiceMgr pointer to synthesizer data + * pPriority pointer to variable to hold priority + * pSynth pointer to virtual synth + * + * Outputs: + * Returns error code + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pVoiceMgr) reserved for future use */ +EAS_RESULT VMGetPriority (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 *pPriority) +{ + *pPriority = pSynth->priority; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMSetVolume() + *---------------------------------------------------------------------------- + * Purpose: + * Set the master volume for this synthesizer for this sequence. + * + * Inputs: + * nSynthVolume - the desired master volume + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * + * Side Effects: + * overrides any previously set master volume from sysex + * + *---------------------------------------------------------------------------- +*/ +void VMSetVolume (S_SYNTH *pSynth, EAS_U16 masterVolume) +{ + pSynth->masterVolume = masterVolume; + pSynth->synthFlags |= SYNTH_FLAG_UPDATE_ALL_CHANNEL_PARAMETERS; +} + +/*---------------------------------------------------------------------------- + * VMSetPitchBendRange() + *---------------------------------------------------------------------------- + * Set the pitch bend range for the given channel. + *---------------------------------------------------------------------------- +*/ +void VMSetPitchBendRange (S_SYNTH *pSynth, EAS_INT channel, EAS_I16 pitchBendRange) +{ + pSynth->channels[channel].pitchBendSensitivity = pitchBendRange; +} + +/*---------------------------------------------------------------------------- + * VMValidateEASLib() + *---------------------------------------------------------------------------- + * Validates an EAS library + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMValidateEASLib (EAS_SNDLIB_HANDLE pEAS) +{ + /* validate the sound library */ + if (pEAS) + { + if (pEAS->identifier != _EAS_LIBRARY_VERSION) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMValidateEASLib: Sound library mismatch in sound library: Read 0x%08x, expected 0x%08x\n", + pEAS->identifier, _EAS_LIBRARY_VERSION); */ } + return EAS_ERROR_SOUND_LIBRARY; + } + + /* check sample rate */ + if ((pEAS->libAttr & LIBFORMAT_SAMPLE_RATE_MASK) != _OUTPUT_SAMPLE_RATE) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMValidateEASLib: Sample rate mismatch in sound library: Read %lu, expected %lu\n", + pEAS->libAttr & LIBFORMAT_SAMPLE_RATE_MASK, _OUTPUT_SAMPLE_RATE); */ } + return EAS_ERROR_SOUND_LIBRARY; + } + +#ifdef _WT_SYNTH + /* check sample bit depth */ +#ifdef _8_BIT_SAMPLES + if (pEAS->libAttr & LIB_FORMAT_16_BIT_SAMPLES) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMValidateEASLib: Expected 8-bit samples and found 16-bit\n", + pEAS->libAttr & LIBFORMAT_SAMPLE_RATE_MASK, _OUTPUT_SAMPLE_RATE); */ } + return EAS_ERROR_SOUND_LIBRARY; + } +#endif +#ifdef _16_BIT_SAMPLES + if ((pEAS->libAttr & LIB_FORMAT_16_BIT_SAMPLES) == 0) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMValidateEASLib: Expected 16-bit samples and found 8-bit\n", + pEAS->libAttr & LIBFORMAT_SAMPLE_RATE_MASK, _OUTPUT_SAMPLE_RATE); */ } + return EAS_ERROR_SOUND_LIBRARY; + } +#endif +#endif + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMSetGlobalEASLib() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the EAS library to be used by the synthesizer + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMSetGlobalEASLib (S_VOICE_MGR *pVoiceMgr, EAS_SNDLIB_HANDLE pEAS) +{ + EAS_RESULT result; + + result = VMValidateEASLib(pEAS); + if (result != EAS_SUCCESS) + return result; + + pVoiceMgr->pGlobalEAS = pEAS; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMSetEASLib() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the EAS library to be used by the synthesizer + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMSetEASLib (S_SYNTH *pSynth, EAS_SNDLIB_HANDLE pEAS) +{ + EAS_RESULT result; + + result = VMValidateEASLib(pEAS); + if (result != EAS_SUCCESS) + return result; + + pSynth->pEAS = pEAS; + return EAS_SUCCESS; +} + +#ifdef DLS_SYNTHESIZER +/*---------------------------------------------------------------------------- + * VMSetGlobalDLSLib() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the DLS library to be used by the synthesizer + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMSetGlobalDLSLib (EAS_DATA_HANDLE pEASData, EAS_DLSLIB_HANDLE pDLS) +{ + + if (pEASData->pVoiceMgr->pGlobalDLS) + DLSCleanup(pEASData->hwInstData, pEASData->pVoiceMgr->pGlobalDLS); + + pEASData->pVoiceMgr->pGlobalDLS = pDLS; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMSetDLSLib() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the DLS library to be used by the synthesizer + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMSetDLSLib (S_SYNTH *pSynth, EAS_DLSLIB_HANDLE pDLS) +{ + pSynth->pDLS = pDLS; + return EAS_SUCCESS; +} +#endif + +/*---------------------------------------------------------------------------- + * VMSetTranposition() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the global key transposition used by the synthesizer. + * Transposes all melodic instruments up or down by the specified + * amount. Range is limited to +/-12 semitones. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMSetTranposition (S_SYNTH *pSynth, EAS_I32 transposition) +{ + pSynth->globalTranspose = (EAS_I8) transposition; +} + +/*---------------------------------------------------------------------------- + * VMGetTranposition() + *---------------------------------------------------------------------------- + * Purpose: + * Gets the global key transposition used by the synthesizer. + * Transposes all melodic instruments up or down by the specified + * amount. Range is limited to +/-12 semitones. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMGetTranposition (S_SYNTH *pSynth, EAS_I32 *pTransposition) +{ + *pTransposition = pSynth->globalTranspose; +} + +/*---------------------------------------------------------------------------- + * VMGetNoteCount() + *---------------------------------------------------------------------------- +* Returns the total note count +*---------------------------------------------------------------------------- +*/ +EAS_I32 VMGetNoteCount (S_SYNTH *pSynth) +{ + return pSynth->totalNoteCount; +} + +/*---------------------------------------------------------------------------- + * VMMIDIShutdown() + *---------------------------------------------------------------------------- + * Purpose: + * Clean up any Synth related system issues. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * None + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMMIDIShutdown (S_EAS_DATA *pEASData, S_SYNTH *pSynth) +{ + EAS_INT vSynthNum; + + /* decrement reference count, free if all references are gone */ + if (--pSynth->refCount > 0) + return; + + vSynthNum = pSynth->vSynthNum; + + /* cleanup DLS load */ +#ifdef DLS_SYNTHESIZER + /*lint -e{550} result used only in debugging code */ + if (pSynth->pDLS != NULL) + { + EAS_RESULT result; + if ((result = DLSCleanup(pEASData->hwInstData, pSynth->pDLS)) != EAS_SUCCESS) + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMMIDIShutdown: Error %ld cleaning up DLS collection\n", result); */ } + pSynth->pDLS = NULL; + } +#endif + + VMReset(pEASData->pVoiceMgr, pSynth, EAS_TRUE); + + /* check Configuration Module for static memory allocation */ + if (!pEASData->staticMemoryModel) + EAS_HWFree(pEASData->hwInstData, pSynth); + + /* clear pointer to MIDI state */ + pEASData->pVoiceMgr->pSynth[vSynthNum] = NULL; +} + +/*---------------------------------------------------------------------------- + * VMShutdown() + *---------------------------------------------------------------------------- + * Purpose: + * Clean up any Synth related system issues. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * None + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMShutdown (S_EAS_DATA *pEASData) +{ + + /* don't free a NULL pointer */ + if (pEASData->pVoiceMgr == NULL) + return; + +#ifdef DLS_SYNTHESIZER + /* if we have a global DLS collection, clean it up */ + if (pEASData->pVoiceMgr->pGlobalDLS) + { + DLSCleanup(pEASData->hwInstData, pEASData->pVoiceMgr->pGlobalDLS); + pEASData->pVoiceMgr->pGlobalDLS = NULL; + } +#endif + + /* check Configuration Module for static memory allocation */ + if (!pEASData->staticMemoryModel) + EAS_HWFree(pEASData->hwInstData, pEASData->pVoiceMgr); + pEASData->pVoiceMgr = NULL; +} + +#ifdef EXTERNAL_AUDIO +/*---------------------------------------------------------------------------- + * EAS_RegExtAudioCallback() + *---------------------------------------------------------------------------- + * Register a callback for external audio processing + *---------------------------------------------------------------------------- +*/ +void VMRegExtAudioCallback (S_SYNTH *pSynth, EAS_VOID_PTR pInstData, EAS_EXT_PRG_CHG_FUNC cbProgChgFunc, EAS_EXT_EVENT_FUNC cbEventFunc) +{ + pSynth->pExtAudioInstData = pInstData; + pSynth->cbProgChgFunc = cbProgChgFunc; + pSynth->cbEventFunc = cbEventFunc; +} + +/*---------------------------------------------------------------------------- + * VMGetMIDIControllers() + *---------------------------------------------------------------------------- + * Returns the MIDI controller values on the specified channel + *---------------------------------------------------------------------------- +*/ +void VMGetMIDIControllers (S_SYNTH *pSynth, EAS_U8 channel, S_MIDI_CONTROLLERS *pControl) +{ + pControl->modWheel = pSynth->channels[channel].modWheel; + pControl->volume = pSynth->channels[channel].volume; + pControl->pan = pSynth->channels[channel].pan; + pControl->expression = pSynth->channels[channel].expression; + pControl->channelPressure = pSynth->channels[channel].channelPressure; + +#ifdef _REVERB + pControl->reverbSend = pSynth->channels[channel].reverbSend; +#endif + +#ifdef _CHORUSE + pControl->chorusSend = pSynth->channels[channel].chorusSend; +#endif +} +#endif + +#ifdef _SPLIT_ARCHITECTURE +/*---------------------------------------------------------------------------- + * VMStartFrame() + *---------------------------------------------------------------------------- + * Purpose: + * Starts an audio frame + * + * Inputs: + * + * Outputs: + * Returns true if EAS_MixEnginePrep should be called (onboard mixing) + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_BOOL VMStartFrame (S_EAS_DATA *pEASData) +{ + + /* init counter for voices starts in split architecture */ +#ifdef MAX_VOICE_STARTS + pVoiceMgr->numVoiceStarts = 0; +#endif + + return pFrameInterface->pfStartFrame(pEASData->pVoiceMgr->pFrameBuffer); +} + +/*---------------------------------------------------------------------------- + * VMEndFrame() + *---------------------------------------------------------------------------- + * Purpose: + * Stops an audio frame + * + * Inputs: + * + * Outputs: + * Returns true if EAS_MixEnginePost should be called (onboard mixing) + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_BOOL VMEndFrame (S_EAS_DATA *pEASData) +{ + + return pFrameInterface->pfEndFrame(pEASData->pVoiceMgr->pFrameBuffer, pEASData->pMixBuffer, pEASData->masterGain); +} +#endif + +#ifdef TEST_HARNESS +/*---------------------------------------------------------------------------- + * SanityCheck() + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMSanityCheck (EAS_DATA_HANDLE pEASData) +{ + S_SYNTH_VOICE *pVoice; + S_SYNTH *pSynth; + EAS_INT i; + EAS_INT j; + EAS_INT freeVoices; + EAS_INT activeVoices; + EAS_INT playingVoices; + EAS_INT stolenVoices; + EAS_INT releasingVoices; + EAS_INT mutingVoices; + EAS_INT poolCount[MAX_VIRTUAL_SYNTHESIZERS][NUM_SYNTH_CHANNELS]; + EAS_INT vSynthNum; + EAS_RESULT result = EAS_SUCCESS; + + /* initialize counts */ + EAS_HWMemSet(poolCount, 0, sizeof(poolCount)); + freeVoices = activeVoices = playingVoices = stolenVoices = releasingVoices = mutingVoices = 0; + + /* iterate through all voices */ + for (i = 0; i < MAX_SYNTH_VOICES; i++) + { + pVoice = &pEASData->pVoiceMgr->voices[i]; + if (pVoice->voiceState != eVoiceStateFree) + { + vSynthNum = GET_VSYNTH(pVoice->channel); + if (vSynthNum >= MAX_VIRTUAL_SYNTHESIZERS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMSanityCheck: Voice %d has invalid virtual synth number %d\n", i, vSynthNum); */ } + result = EAS_FAILURE; + continue; + } + pSynth = pEASData->pVoiceMgr->pSynth[vSynthNum]; + + switch (pVoice->voiceState) + { + case eVoiceStateMuting: + activeVoices++; + mutingVoices++; + break; + + case eVoiceStateStolen: + vSynthNum = GET_VSYNTH(pVoice->nextChannel); + if (vSynthNum >= MAX_VIRTUAL_SYNTHESIZERS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMSanityCheck: Voice %d has invalid virtual synth number %d\n", i, vSynthNum); */ } + result = EAS_FAILURE; + continue; + } + pSynth = pEASData->pVoiceMgr->pSynth[vSynthNum]; + activeVoices++; + stolenVoices++; + poolCount[vSynthNum][pSynth->channels[GET_CHANNEL(pVoice->nextChannel)].pool]++; + break; + + case eVoiceStateStart: + case eVoiceStatePlay: + activeVoices++; + playingVoices++; + poolCount[vSynthNum][pSynth->channels[GET_CHANNEL(pVoice->channel)].pool]++; + break; + + case eVoiceStateRelease: + activeVoices++; + releasingVoices++; + poolCount[vSynthNum][pSynth->channels[GET_CHANNEL(pVoice->channel)].pool]++; + break; + + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMSanityCheck : voice %d in invalid state\n", i); */ } + result = EAS_FAILURE; + break; + } + } + + /* count free voices */ + else + freeVoices++; + } + + /* dump state info */ + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "%d free\n", freeVoices); */ } + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "%d active\n", activeVoices); */ } + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "%d playing\n", playingVoices); */ } + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "%d releasing\n", releasingVoices); */ } + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "%d muting\n", mutingVoices); */ } + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "%d stolen\n", stolenVoices); */ } + + if (pEASData->pVoiceMgr->activeVoices != activeVoices) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Active voice mismatch was %d should be %d\n", + pEASData->pVoiceMgr->activeVoices, activeVoices); */ } + result = EAS_FAILURE; + } + + /* check virtual synth status */ + for (i = 0; i < MAX_VIRTUAL_SYNTHESIZERS; i++) + { + if (pEASData->pVoiceMgr->pSynth[i] == NULL) + continue; + + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Synth %d numActiveVoices: %d\n", i, pEASData->pVoiceMgr->pSynth[i]->numActiveVoices); */ } + if (pEASData->pVoiceMgr->pSynth[i]->numActiveVoices > MAX_SYNTH_VOICES) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMSanityCheck: Synth %d illegal count for numActiveVoices: %d\n", i, pEASData->pVoiceMgr->pSynth[i]->numActiveVoices); */ } + result = EAS_FAILURE; + } + for (j = 0; j < NUM_SYNTH_CHANNELS; j++) + { + if (poolCount[i][j] != pEASData->pVoiceMgr->pSynth[i]->poolCount[j]) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Pool count mismatch synth %d pool %d, was %d, should be %d\n", + i, j, pEASData->pVoiceMgr->pSynth[i]->poolCount[j], poolCount[i][j]); */ } + result = EAS_FAILURE; + } + } + } + + return result; +} +#endif + + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_wavefile.c b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_wavefile.c new file mode 100755 index 0000000..f24bde2 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_wavefile.c @@ -0,0 +1,867 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_wavefile.c + * + * Contents and purpose: + * This file implements the wave file parser. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 852 $ + * $Date: 2007-09-04 11:43:49 -0700 (Tue, 04 Sep 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_data.h" +#include "eas_report.h" +#include "eas_host.h" +#include "eas_config.h" +#include "eas_parser.h" +#include "eas_pcm.h" +#include "eas_wavefile.h" + +/* lint is choking on the ARM math.h file, so we declare the log10 function here */ +extern double log10(double x); + +/* increase gain to compensate for loss in mixer */ +#define WAVE_GAIN_OFFSET 6 + +/* constant for 1200 / log10(2.0) */ +#define PITCH_CENTS_CONVERSION 3986.313714 + +/*---------------------------------------------------------------------------- + * WAVE file defines + *---------------------------------------------------------------------------- +*/ +/* RIFF chunks */ +#define CHUNK_TYPE(a,b,c,d) ( \ + ( ((EAS_U32)(a) & 0xFF) << 24 ) \ + + ( ((EAS_U32)(b) & 0xFF) << 16 ) \ + + ( ((EAS_U32)(c) & 0xFF) << 8 ) \ + + ( ((EAS_U32)(d) & 0xFF) ) ) + +#define CHUNK_RIFF CHUNK_TYPE('R','I','F','F') +#define CHUNK_WAVE CHUNK_TYPE('W','A','V','E') +#define CHUNK_FMT CHUNK_TYPE('f','m','t',' ') +#define CHUNK_DATA CHUNK_TYPE('d','a','t','a') +#define CHUNK_LIST CHUNK_TYPE('L','I','S','T') +#define CHUNK_INFO CHUNK_TYPE('I','N','F','O') +#define CHUNK_INAM CHUNK_TYPE('I','N','A','M') +#define CHUNK_ICOP CHUNK_TYPE('I','C','O','P') +#define CHUNK_IART CHUNK_TYPE('I','A','R','T') + +/* wave file format identifiers */ +#define WAVE_FORMAT_PCM 0x0001 +#define WAVE_FORMAT_IMA_ADPCM 0x0011 + +/* file size for streamed file */ +#define FILE_SIZE_STREAMING 0x80000000 + +/*---------------------------------------------------------------------------- + * prototypes + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT WaveCheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *pHandle, EAS_I32 offset); +static EAS_RESULT WavePrepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT WaveState (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_STATE *pState); +static EAS_RESULT WaveClose (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT WaveReset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT WaveLocate (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 time, EAS_BOOL *pParserLocate); +static EAS_RESULT WavePause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT WaveResume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT WaveSetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value); +static EAS_RESULT WaveGetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue); +static EAS_RESULT WaveParseHeader (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, S_WAVE_STATE *pWaveData); +static EAS_RESULT WaveGetMetaData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pMediaLength); + +#ifdef MMAPI_SUPPORT +static EAS_RESULT SaveFmtChunk (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, S_WAVE_STATE *pWaveData, EAS_I32 size); +#endif + +/*---------------------------------------------------------------------------- + * + * EAS_Wave_Parser + * + * This structure contains the functional interface for the Wave file parser + *---------------------------------------------------------------------------- +*/ +const S_FILE_PARSER_INTERFACE EAS_Wave_Parser = +{ + WaveCheckFileType, + WavePrepare, + NULL, + NULL, + WaveState, + WaveClose, + WaveReset, + WavePause, + WaveResume, + WaveLocate, + WaveSetData, + WaveGetData, + WaveGetMetaData +}; + +/*---------------------------------------------------------------------------- + * WaveCheckFileType() + *---------------------------------------------------------------------------- + * Purpose: + * Check the file type to see if we can parse it + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT WaveCheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *pHandle, EAS_I32 offset) +{ + S_WAVE_STATE *pWaveData; + + /* zero the memory to insure complete initialization */ + *pHandle = NULL; + + /* read the file header */ + if (WaveParseHeader(pEASData, fileHandle, NULL) == EAS_SUCCESS) + { + + /* check for static memory allocation */ + if (pEASData->staticMemoryModel) + pWaveData = EAS_CMEnumData(EAS_CM_WAVE_DATA); + else + pWaveData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_WAVE_STATE)); + if (!pWaveData) + return EAS_ERROR_MALLOC_FAILED; + EAS_HWMemSet(pWaveData, 0, sizeof(S_WAVE_STATE)); + + /* return a pointer to the instance data */ + pWaveData->fileHandle = fileHandle; + pWaveData->fileOffset = offset; + *pHandle = pWaveData; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * WavePrepare() + *---------------------------------------------------------------------------- + * Purpose: + * Prepare to parse the file. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT WavePrepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_WAVE_STATE *pWaveData; + EAS_RESULT result; + + /* validate parser state */ + pWaveData = (S_WAVE_STATE*) pInstData; + if (pWaveData->streamHandle != NULL) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + /* back to start of file */ + pWaveData->time = 0; + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pWaveData->fileHandle, pWaveData->fileOffset)) != EAS_SUCCESS) + return result; + + /* parse the file header */ + if ((result = WaveParseHeader(pEASData, pWaveData->fileHandle, pWaveData)) != EAS_SUCCESS) + return result; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * WaveState() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current state of the stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * pState - pointer to variable to store state + * + * Outputs: + * + * + * Side Effects: + * + * Notes: + * This interface is also exposed in the internal library for use by the other modules. + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT WaveState (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_STATE *pState) +{ + S_WAVE_STATE *pWaveData; + + /* return current state */ + pWaveData = (S_WAVE_STATE*) pInstData; + if (pWaveData->streamHandle) + return EAS_PEState(pEASData, pWaveData->streamHandle, pState); + + /* if no stream handle, and time is not zero, we are done */ + if (pWaveData->time > 0) + *pState = EAS_STATE_STOPPED; + else + *pState = EAS_STATE_OPEN; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * WaveClose() + *---------------------------------------------------------------------------- + * Purpose: + * Close the file and clean up + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT WaveClose (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_WAVE_STATE *pWaveData; + EAS_RESULT result; + + pWaveData = (S_WAVE_STATE*) pInstData; + + /* close the stream */ + if (pWaveData->streamHandle) + { + if ((result = EAS_PEClose(pEASData, pWaveData->streamHandle)) != EAS_SUCCESS) + return result; + pWaveData->streamHandle = NULL; + } + + /* if using dynamic memory, free it */ + if (!pEASData->staticMemoryModel) + { + +#ifdef MMAPI_SUPPORT + /* need to free the fmt chunk */ + if (pWaveData->fmtChunk != NULL) + EAS_HWFree(pEASData->hwInstData, pWaveData->fmtChunk); +#endif + + /* free the instance data */ + EAS_HWFree(pEASData->hwInstData, pWaveData); + + } + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * WaveReset() + *---------------------------------------------------------------------------- + * Purpose: + * Reset the sequencer. Used for locating backwards in the file. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT WaveReset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + EAS_PCM_HANDLE streamHandle; + + /* reset to first byte of data in the stream */ + streamHandle = ((S_WAVE_STATE*)pInstData)->streamHandle; + if (streamHandle) + return EAS_PEReset(pEASData, streamHandle); + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; +} + +/*---------------------------------------------------------------------------- + * WaveLocate() + *---------------------------------------------------------------------------- + * Purpose: + * Rewind/fast-forward in file. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * time - time (in msecs) + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pParserLocate) reserved for future use */ +static EAS_RESULT WaveLocate (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 time, EAS_BOOL *pParserLocate) +{ + EAS_PCM_HANDLE streamHandle; + + /* reset to first byte of data in the stream */ + streamHandle = ((S_WAVE_STATE*)pInstData)->streamHandle; + if (streamHandle) + return EAS_PELocate(pEASData, streamHandle, time); + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; +} + +/*---------------------------------------------------------------------------- + * WavePause() + *---------------------------------------------------------------------------- + * Purpose: + * Mute and stop rendering a PCM stream. Sets the gain target to zero and stops the playback + * at the end of the next audio frame. + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_WAVE_STATE for this stream + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +static EAS_RESULT WavePause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + EAS_PCM_HANDLE streamHandle; + + /* pause the stream */ + streamHandle = ((S_WAVE_STATE*)pInstData)->streamHandle; + if (streamHandle) + return EAS_PEPause(pEASData, streamHandle); + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; +} + +/*---------------------------------------------------------------------------- + * WaveResume() + *---------------------------------------------------------------------------- + * Purpose: + * Resume rendering a PCM stream. Sets the gain target back to its + * previous setting and restarts playback at the end of the next audio + * frame. + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_WAVE_STATE for this stream + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +static EAS_RESULT WaveResume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + EAS_PCM_HANDLE streamHandle; + + /* resume the stream */ + streamHandle = ((S_WAVE_STATE*)pInstData)->streamHandle; + if (streamHandle) + return EAS_PEResume(pEASData, streamHandle); + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; +} + +/*---------------------------------------------------------------------------- + * WaveSetData() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_WAVE_STATE for this stream + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT WaveSetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value) +{ + S_WAVE_STATE *pWaveData = (S_WAVE_STATE*) pInstData; + + switch (param) + { + /* set metadata callback */ + case PARSER_DATA_METADATA_CB: + EAS_HWMemCpy(&pWaveData->metadata, (void*) value, sizeof(S_METADATA_CB)); + return EAS_SUCCESS; + + case PARSER_DATA_PLAYBACK_RATE: + value = (EAS_I32) (PITCH_CENTS_CONVERSION * log10((double) value / (double) (1 << 28))); + return EAS_PEUpdatePitch(pEASData, pWaveData->streamHandle, (EAS_I16) value); + + case PARSER_DATA_VOLUME: + return EAS_PEUpdateVolume(pEASData, pWaveData->streamHandle, (EAS_I16) value); + + default: + return EAS_ERROR_INVALID_PARAMETER; + } +} + +/*---------------------------------------------------------------------------- + * WaveGetData() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_WAVE_STATE for this stream + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +static EAS_RESULT WaveGetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue) +{ + S_WAVE_STATE *pWaveData; + + pWaveData = (S_WAVE_STATE*) pInstData; + switch (param) + { + /* return file type as WAVE */ + case PARSER_DATA_FILE_TYPE: + *pValue = pWaveData->fileType; + break; + +#ifdef MMAPI_SUPPORT + /* return pointer to 'fmt' chunk */ + case PARSER_DATA_FORMAT: + *pValue = (EAS_I32) pWaveData->fmtChunk; + break; +#endif + + case PARSER_DATA_GAIN_OFFSET: + *pValue = WAVE_GAIN_OFFSET; + break; + + default: + return EAS_ERROR_INVALID_PARAMETER; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * WaveParseHeader() + *---------------------------------------------------------------------------- + * Purpose: + * Parse the WAVE file header. + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_WAVE_STATE for this stream + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT WaveParseHeader (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, S_WAVE_STATE *pWaveData) +{ + S_PCM_OPEN_PARAMS params; + EAS_RESULT result; + EAS_U32 tag; + EAS_U32 fileSize; + EAS_U32 size; + EAS_I32 pos; + EAS_I32 audioOffset; + EAS_U16 usTemp; + EAS_BOOL parseDone; + EAS_U32 avgBytesPerSec; + + /* init some data (and keep lint happy) */ + params.sampleRate = 0; + params.size = 0; + audioOffset = 0; + params.decoder = 0; + params.blockSize = 0; + params.pCallbackFunc = NULL; + params.cbInstData = NULL; + params.loopSamples = 0; + params.fileHandle = fileHandle; + params.volume = 0x7fff; + params.envData = 0; + avgBytesPerSec = 8000; + + /* check for 'RIFF' tag */ + if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &tag, EAS_TRUE)) != EAS_FALSE) + return result; + if (tag != CHUNK_RIFF) + return EAS_ERROR_UNRECOGNIZED_FORMAT; + + /* get size */ + if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &fileSize, EAS_FALSE)) != EAS_FALSE) + return result; + + /* check for 'WAVE' tag */ + if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &tag, EAS_TRUE)) != EAS_FALSE) + return result; + if (tag != CHUNK_WAVE) + return EAS_ERROR_UNRECOGNIZED_FORMAT; + + /* this is enough to say we recognize the file */ + if (pWaveData == NULL) + return EAS_SUCCESS; + + /* check for streaming mode */ + pWaveData->flags = 0; + pWaveData->mediaLength = -1; + pWaveData->infoChunkPos = -1; + pWaveData->infoChunkSize = -1; + if (fileSize== FILE_SIZE_STREAMING) + { + pWaveData->flags |= PCM_FLAGS_STREAMING; + fileSize = 0x7fffffff; + } + + /* find out where we're at */ + if ((result = EAS_HWFilePos(pEASData->hwInstData, fileHandle, &pos)) != EAS_SUCCESS) + return result; + fileSize -= 4; + + parseDone = EAS_FALSE; + for (;;) + { + /* get tag and size for next chunk */ + if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &tag, EAS_TRUE)) != EAS_FALSE) + return result; + if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &size, EAS_FALSE)) != EAS_FALSE) + return result; + + /* process chunk */ + pos += 8; + switch (tag) + { + case CHUNK_FMT: + +#ifdef MMAPI_SUPPORT + if ((result = SaveFmtChunk(pEASData, fileHandle, pWaveData, (EAS_I32) size)) != EAS_SUCCESS) + return result; +#endif + + /* get audio format */ + if ((result = EAS_HWGetWord(pEASData->hwInstData, fileHandle, &usTemp, EAS_FALSE)) != EAS_FALSE) + return result; + if (usTemp == WAVE_FORMAT_PCM) + { + params.decoder = EAS_DECODER_PCM; + pWaveData->fileType = EAS_FILE_WAVE_PCM; + } + else if (usTemp == WAVE_FORMAT_IMA_ADPCM) + { + params.decoder = EAS_DECODER_IMA_ADPCM; + pWaveData->fileType = EAS_FILE_WAVE_IMA_ADPCM; + } + else + return EAS_ERROR_UNRECOGNIZED_FORMAT; + + /* get number of channels */ + if ((result = EAS_HWGetWord(pEASData->hwInstData, fileHandle, &usTemp, EAS_FALSE)) != EAS_FALSE) + return result; + if (usTemp == 2) + pWaveData->flags |= PCM_FLAGS_STEREO; + else if (usTemp != 1) + return EAS_ERROR_UNRECOGNIZED_FORMAT; + + /* get sample rate */ + if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, ¶ms.sampleRate, EAS_FALSE)) != EAS_FALSE) + return result; + + /* get stream rate */ + if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &avgBytesPerSec, EAS_FALSE)) != EAS_FALSE) + return result; + + /* get block alignment */ + if ((result = EAS_HWGetWord(pEASData->hwInstData, fileHandle, &usTemp, EAS_FALSE)) != EAS_FALSE) + return result; + params.blockSize = usTemp; + + /* get bits per sample */ + if ((result = EAS_HWGetWord(pEASData->hwInstData, fileHandle, &usTemp, EAS_FALSE)) != EAS_FALSE) + return result; + + /* PCM, must be 8 or 16 bit samples */ + if (params.decoder == EAS_DECODER_PCM) + { + if (usTemp == 8) + pWaveData->flags |= PCM_FLAGS_8_BIT | PCM_FLAGS_UNSIGNED; + else if (usTemp != 16) + return EAS_ERROR_UNRECOGNIZED_FORMAT; + } + + /* for IMA ADPCM, we only support mono 4-bit ADPCM */ + else + { + if ((usTemp != 4) || (pWaveData->flags & PCM_FLAGS_STEREO)) + return EAS_ERROR_UNRECOGNIZED_FORMAT; + } + + break; + + case CHUNK_DATA: + audioOffset = pos; + if (pWaveData->flags & PCM_FLAGS_STREAMING) + { + params.size = 0x7fffffff; + parseDone = EAS_TRUE; + } + else + { + params.size = (EAS_I32) size; + params.loopStart = size; + /* use more accurate method if possible */ + if (size <= (0x7fffffff / 1000)) + pWaveData->mediaLength = (EAS_I32) ((size * 1000) / avgBytesPerSec); + else + pWaveData->mediaLength = (EAS_I32) (size / (avgBytesPerSec / 1000)); + } + break; + + case CHUNK_LIST: + /* get the list type */ + if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &tag, EAS_TRUE)) != EAS_FALSE) + return result; + if (tag == CHUNK_INFO) + { + pWaveData->infoChunkPos = pos + 4; + pWaveData->infoChunkSize = (EAS_I32) size - 4; + } + break; + + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WaveParseHeader: %c%c%c%c chunk - %d byte(s) ignored\n", + (char) (tag >> 24), (char) (tag >> 16), (char) (tag >> 8), (char) tag, size); */ } + break; + } + + if (parseDone) + break; + + /* subtract header size */ + fileSize -= 8; + + /* account for zero-padding on odd length chunks */ + if (size & 1) + size++; + + /* this check works for files with odd length last chunk and no zero-pad */ + if (size >= fileSize) + { + if (size > fileSize) + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WaveParseHeader: '%c%c%c%c' chunk size exceeds length of file or is not zero-padded\n", + (char) (tag >> 24), (char) (tag >> 16), (char) (tag >> 8), (char) tag, size); */ } + break; + } + + /* subtract size of data chunk (including any zero-pad) */ + fileSize -= size; + + /* seek to next chunk */ + pos += (EAS_I32) size; + if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, pos)) != EAS_SUCCESS) + return result; + } + + /* check for valid header */ + if ((params.sampleRate == 0) || (params.size == 0)) + return EAS_ERROR_UNRECOGNIZED_FORMAT; + + /* save the pertinent information */ + pWaveData->audioOffset = audioOffset; + params.flags = pWaveData->flags; + + /* seek to data */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, audioOffset)) != EAS_SUCCESS) + return result; + + /* open a stream in the PCM engine */ + return EAS_PEOpenStream(pEASData, ¶ms, &pWaveData->streamHandle); +} + +/*---------------------------------------------------------------------------- + * WaveGetMetaData() + *---------------------------------------------------------------------------- + * Purpose: + * Process the INFO chunk and return metadata to host + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT WaveGetMetaData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pMediaLength) +{ + S_WAVE_STATE *pWaveData; + EAS_RESULT result; + EAS_I32 pos; + EAS_U32 size; + EAS_I32 infoSize; + EAS_U32 tag; + EAS_I32 restorePos; + E_EAS_METADATA_TYPE metaType; + EAS_I32 metaLen; + + /* get current position so we can restore it */ + pWaveData = (S_WAVE_STATE*) pInstData; + + /* return media length */ + *pMediaLength = pWaveData->mediaLength; + + /* did we encounter an INFO chunk? */ + if (pWaveData->infoChunkPos < 0) + return EAS_SUCCESS; + + if ((result = EAS_HWFilePos(pEASData->hwInstData, pWaveData->fileHandle, &restorePos)) != EAS_SUCCESS) + return result; + + /* offset to start of first chunk in INFO chunk */ + pos = pWaveData->infoChunkPos; + infoSize = pWaveData->infoChunkSize; + + /* read all the chunks in the INFO chunk */ + for (;;) + { + + /* seek to next chunk */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pWaveData->fileHandle, pos)) != EAS_SUCCESS) + return result; + + /* get tag and size for next chunk */ + if ((result = EAS_HWGetDWord(pEASData->hwInstData, pWaveData->fileHandle, &tag, EAS_TRUE)) != EAS_FALSE) + return result; + if ((result = EAS_HWGetDWord(pEASData->hwInstData, pWaveData->fileHandle, &size, EAS_FALSE)) != EAS_FALSE) + return result; + + /* process chunk */ + pos += 8; + metaType = EAS_METADATA_UNKNOWN; + switch (tag) + { + case CHUNK_INAM: + metaType = EAS_METADATA_TITLE; + break; + + case CHUNK_IART: + metaType = EAS_METADATA_AUTHOR; + break; + + case CHUNK_ICOP: + metaType = EAS_METADATA_COPYRIGHT; + break; + + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WaveParseHeader: %c%c%c%c chunk - %d byte(s) ignored\n", + (char) (tag >> 24), (char) (tag >> 16), (char) (tag >> 8), (char) tag, size); */ } + break; + } + + /* process known metadata */ + if (metaType != EAS_METADATA_UNKNOWN) + { + metaLen = pWaveData->metadata.bufferSize - 1; + if (metaLen > (EAS_I32) size) + metaLen = (EAS_I32) size; + if ((result = EAS_HWReadFile(pEASData->hwInstData, pWaveData->fileHandle, pWaveData->metadata.buffer, metaLen, &metaLen)) != EAS_SUCCESS) + return result; + pWaveData->metadata.buffer[metaLen] = 0; + pWaveData->metadata.callback(metaType, pWaveData->metadata.buffer, pWaveData->metadata.pUserData); + } + + /* subtract this block */ + if (size & 1) + size++; + infoSize -= (EAS_I32) size + 8; + if (infoSize == 0) + break; + pos += (EAS_I32) size; + } + + + /* restore original position */ + return EAS_HWFileSeek(pEASData->hwInstData, pWaveData->fileHandle, restorePos); +} + +#ifdef MMAPI_SUPPORT +/*---------------------------------------------------------------------------- + * SaveFmtChunk() + *---------------------------------------------------------------------------- + * Purpose: + * Save the fmt chunk for the MMAPI library + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT SaveFmtChunk (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, S_WAVE_STATE *pWaveData, EAS_I32 fmtSize) +{ + EAS_RESULT result; + EAS_I32 pos; + EAS_I32 count; + + /* save current file position */ + if ((result = EAS_HWFilePos(pEASData->hwInstData, fileHandle, &pos)) != EAS_SUCCESS) + return result; + + /* allocate a chunk of memory */ + pWaveData->fmtChunk = EAS_HWMalloc(pEASData->hwInstData, fmtSize); + if (!pWaveData->fmtChunk) + return EAS_ERROR_MALLOC_FAILED; + + /* read the fmt chunk into memory */ + if ((result = EAS_HWReadFile(pEASData->hwInstData, fileHandle, pWaveData->fmtChunk, fmtSize, &count)) != EAS_SUCCESS) + return result; + if (count != fmtSize) + return EAS_ERROR_FILE_READ_FAILED; + + /* restore file position */ + return EAS_HWFileSeek(pEASData->hwInstData, fileHandle, pos); +} +#endif + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_wavefile.h b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_wavefile.h new file mode 100755 index 0000000..f8814a8 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_wavefile.h @@ -0,0 +1,63 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_wavefile.h + * + * Contents and purpose: + * Static data block for wave file parser. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 439 $ + * $Date: 2006-10-26 11:53:18 -0700 (Thu, 26 Oct 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_WAVEFILE_H +#define _EAS_WAVEFILE_H + +#include "eas_data.h" +#include "eas_pcm.h" + +/*---------------------------------------------------------------------------- + * + * S_WAVE_STATE + * + * This structure contains the WAVE file parser state information + *---------------------------------------------------------------------------- +*/ +typedef struct s_wave_state_tag +{ + EAS_FILE_HANDLE fileHandle; + EAS_PCM_HANDLE streamHandle; + S_METADATA_CB metadata; + EAS_U32 time; + EAS_I32 fileOffset; + EAS_I32 audioOffset; + EAS_I32 mediaLength; + EAS_U32 audioSize; + EAS_U32 flags; + EAS_I16 fileType; +#ifdef MMAPI_SUPPORT + EAS_VOID_PTR fmtChunk; +#endif + EAS_I32 infoChunkPos; + EAS_I32 infoChunkSize; +} S_WAVE_STATE; + +#endif + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_wavefiledata.c b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_wavefiledata.c new file mode 100755 index 0000000..c224a6c --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_wavefiledata.c @@ -0,0 +1,33 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_wavefiledata.c + * + * Contents and purpose: + * Static data block for wave file parser. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 547 $ + * $Date: 2007-01-31 16:30:17 -0800 (Wed, 31 Jan 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_wavefile.h" + +S_WAVE_STATE eas_WaveData; + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_wt_IPC_frame.h b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_wt_IPC_frame.h new file mode 100755 index 0000000..29d77aa --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_wt_IPC_frame.h @@ -0,0 +1,82 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_wt_IPC_frame.h + * + * Contents and purpose: + * This module contains data definitions for the interprocessor + * communications framework for a split-architecture synthesizer. + * + * This sample version writes IPC data to a file that can be used + * as a test vector for the DSP simulator. For a real-time system + * the file I/O is replaced with an IPC protocol in the hardware. + * + * Synchronization with the DSP is accomplished at the API level, + * i.e. the host code should call EAS_Render when it is ready to + * buffer another block of data for transmission to the DSP. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 818 $ + * $Date: 2007-08-02 15:19:41 -0700 (Thu, 02 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_WT_IPC_FRAME_H +#define _EAS_WT_IPC_FRAME_H + +/*---------------------------------------------------------------------------- + * S_WT_FRAME + * + * This structure contains the common parameters that are updated + *for each frame of audio. + *---------------------------------------------------------------------------- +*/ +typedef struct s_wt_frame_tag +{ + EAS_I32 gainTarget; + EAS_I32 phaseIncrement; + +#if defined(_FILTER_ENABLED) + EAS_I32 k; + EAS_I32 b1; + EAS_I32 b2; +#endif +} S_WT_FRAME; + +/*---------------------------------------------------------------------------- + * S_WT_CONFIG + * + * This structure contains state data for the wavetable engine + *---------------------------------------------------------------------------- +*/ +typedef struct s_wt_config_tag +{ + EAS_U32 loopEnd; /* points to last PCM sample (not 1 beyond last) */ + EAS_U32 loopStart; /* points to first sample at start of loop */ + EAS_U32 phaseAccum; /* current sample, integer portion of phase */ + +#if (NUM_OUTPUT_CHANNELS == 2) + EAS_I16 gainLeft; /* left channel gain */ + EAS_I16 gainRight; /* right channel gain */ +#endif + + EAS_I16 gain; /* current voice gain */ +} S_WT_CONFIG; + +#endif + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_wtengine.c b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_wtengine.c new file mode 100755 index 0000000..8407634 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_wtengine.c @@ -0,0 +1,661 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_wtengine.c + * + * Contents and purpose: + * This file contains the critical synthesizer components that need to + * be optimized for best performance. + * + * Copyright Sonic Network Inc. 2004-2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 844 $ + * $Date: 2007-08-23 14:33:32 -0700 (Thu, 23 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +/*------------------------------------ + * includes + *------------------------------------ +*/ +#include "eas_types.h" +#include "eas_math.h" +#include "eas_audioconst.h" +#include "eas_sndlib.h" +#include "eas_wtengine.h" +#include "eas_mixer.h" + +/*---------------------------------------------------------------------------- + * prototypes + *---------------------------------------------------------------------------- +*/ +extern void WT_NoiseGenerator (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame); +extern void WT_VoiceGain (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame); + +#if defined(_OPTIMIZED_MONO) +extern void WT_InterpolateMono (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame); +#else +extern void WT_InterpolateNoLoop (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame); +extern void WT_Interpolate (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame); +#endif + +#if defined(_FILTER_ENABLED) +extern void WT_VoiceFilter (S_FILTER_CONTROL*pFilter, S_WT_INT_FRAME *pWTIntFrame); +#endif + +#if defined(_OPTIMIZED_MONO) || !defined(NATIVE_EAS_KERNEL) +/*---------------------------------------------------------------------------- + * WT_VoiceGain + *---------------------------------------------------------------------------- + * Purpose: + * Output gain for individual voice + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pWTVoice) reserved for future use */ +void WT_VoiceGain (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame) +{ + EAS_I32 *pMixBuffer; + EAS_PCM *pInputBuffer; + EAS_I32 gain; + EAS_I32 gainIncrement; + EAS_I32 tmp0; + EAS_I32 tmp1; + EAS_I32 tmp2; + EAS_I32 numSamples; + +#if (NUM_OUTPUT_CHANNELS == 2) + EAS_I32 gainLeft, gainRight; +#endif + + /* initialize some local variables */ + numSamples = pWTIntFrame->numSamples; + pMixBuffer = pWTIntFrame->pMixBuffer; + pInputBuffer = pWTIntFrame->pAudioBuffer; + + /*lint -e{703} */ + gainIncrement = (pWTIntFrame->frame.gainTarget - pWTIntFrame->prevGain) << (16 - SYNTH_UPDATE_PERIOD_IN_BITS); + if (gainIncrement < 0) + gainIncrement++; + /*lint -e{703} */ + gain = pWTIntFrame->prevGain << 16; + +#if (NUM_OUTPUT_CHANNELS == 2) + gainLeft = pWTVoice->gainLeft; + gainRight = pWTVoice->gainRight; +#endif + + while (numSamples--) { + + /* incremental gain step to prevent zipper noise */ + tmp0 = *pInputBuffer++; + gain += gainIncrement; + /*lint -e{704} */ + tmp2 = gain >> 16; + + /* scale sample by gain */ + tmp2 *= tmp0; + + + /* stereo output */ +#if (NUM_OUTPUT_CHANNELS == 2) + /*lint -e{704} */ + tmp2 = tmp2 >> 14; + + /* get the current sample in the final mix buffer */ + tmp1 = *pMixBuffer; + + /* left channel */ + tmp0 = tmp2 * gainLeft; + /*lint -e{704} */ + tmp0 = tmp0 >> NUM_MIXER_GUARD_BITS; + tmp1 += tmp0; + *pMixBuffer++ = tmp1; + + /* get the current sample in the final mix buffer */ + tmp1 = *pMixBuffer; + + /* right channel */ + tmp0 = tmp2 * gainRight; + /*lint -e{704} */ + tmp0 = tmp0 >> NUM_MIXER_GUARD_BITS; + tmp1 += tmp0; + *pMixBuffer++ = tmp1; + + /* mono output */ +#else + + /* get the current sample in the final mix buffer */ + tmp1 = *pMixBuffer; + /*lint -e{704} */ + tmp2 = tmp2 >> (NUM_MIXER_GUARD_BITS - 1); + tmp1 += tmp2; + *pMixBuffer++ = tmp1; +#endif + + } +} +#endif + +#ifndef NATIVE_EAS_KERNEL +/*---------------------------------------------------------------------------- + * WT_Interpolate + *---------------------------------------------------------------------------- + * Purpose: + * Interpolation engine for wavetable synth + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +void WT_Interpolate (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame) +{ + EAS_PCM *pOutputBuffer; + EAS_I32 phaseInc; + EAS_I32 phaseFrac; + EAS_I32 acc0; + const EAS_SAMPLE *pSamples; + const EAS_SAMPLE *loopEnd; + EAS_I32 samp1; + EAS_I32 samp2; + EAS_I32 numSamples; + + /* initialize some local variables */ + numSamples = pWTIntFrame->numSamples; + pOutputBuffer = pWTIntFrame->pAudioBuffer; + + loopEnd = (const EAS_SAMPLE*) pWTVoice->loopEnd + 1; + pSamples = (const EAS_SAMPLE*) pWTVoice->phaseAccum; + /*lint -e{713} truncation is OK */ + phaseFrac = pWTVoice->phaseFrac; + phaseInc = pWTIntFrame->frame.phaseIncrement; + + /* fetch adjacent samples */ +#if defined(_8_BIT_SAMPLES) + /*lint -e{701} */ + samp1 = pSamples[0] << 8; + /*lint -e{701} */ + samp2 = pSamples[1] << 8; +#else + samp1 = pSamples[0]; + samp2 = pSamples[1]; +#endif + + while (numSamples--) { + + /* linear interpolation */ + acc0 = samp2 - samp1; + acc0 = acc0 * phaseFrac; + /*lint -e{704} */ + acc0 = samp1 + (acc0 >> NUM_PHASE_FRAC_BITS); + + /* save new output sample in buffer */ + /*lint -e{704} */ + *pOutputBuffer++ = (EAS_I16)(acc0 >> 2); + + /* increment phase */ + phaseFrac += phaseInc; + /*lint -e{704} */ + acc0 = phaseFrac >> NUM_PHASE_FRAC_BITS; + + /* next sample */ + if (acc0 > 0) { + + /* advance sample pointer */ + pSamples += acc0; + phaseFrac = (EAS_I32)((EAS_U32)phaseFrac & PHASE_FRAC_MASK); + + /* check for loop end */ + acc0 = (EAS_I32) (pSamples - loopEnd); + if (acc0 >= 0) + pSamples = (const EAS_SAMPLE*) pWTVoice->loopStart + acc0; + + /* fetch new samples */ +#if defined(_8_BIT_SAMPLES) + /*lint -e{701} */ + samp1 = pSamples[0] << 8; + /*lint -e{701} */ + samp2 = pSamples[1] << 8; +#else + samp1 = pSamples[0]; + samp2 = pSamples[1]; +#endif + } + } + + /* save pointer and phase */ + pWTVoice->phaseAccum = (EAS_U32) pSamples; + pWTVoice->phaseFrac = (EAS_U32) phaseFrac; +} +#endif + +#ifndef NATIVE_EAS_KERNEL +/*---------------------------------------------------------------------------- + * WT_InterpolateNoLoop + *---------------------------------------------------------------------------- + * Purpose: + * Interpolation engine for wavetable synth + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +void WT_InterpolateNoLoop (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame) +{ + EAS_PCM *pOutputBuffer; + EAS_I32 phaseInc; + EAS_I32 phaseFrac; + EAS_I32 acc0; + const EAS_SAMPLE *pSamples; + EAS_I32 samp1; + EAS_I32 samp2; + EAS_I32 numSamples; + + /* initialize some local variables */ + numSamples = pWTIntFrame->numSamples; + pOutputBuffer = pWTIntFrame->pAudioBuffer; + + phaseInc = pWTIntFrame->frame.phaseIncrement; + pSamples = (const EAS_SAMPLE*) pWTVoice->phaseAccum; + phaseFrac = (EAS_I32)pWTVoice->phaseFrac; + + /* fetch adjacent samples */ +#if defined(_8_BIT_SAMPLES) + /*lint -e{701} */ + samp1 = pSamples[0] << 8; + /*lint -e{701} */ + samp2 = pSamples[1] << 8; +#else + samp1 = pSamples[0]; + samp2 = pSamples[1]; +#endif + + while (numSamples--) { + + + /* linear interpolation */ + acc0 = samp2 - samp1; + acc0 = acc0 * phaseFrac; + /*lint -e{704} */ + acc0 = samp1 + (acc0 >> NUM_PHASE_FRAC_BITS); + + /* save new output sample in buffer */ + /*lint -e{704} */ + *pOutputBuffer++ = (EAS_I16)(acc0 >> 2); + + /* increment phase */ + phaseFrac += phaseInc; + /*lint -e{704} */ + acc0 = phaseFrac >> NUM_PHASE_FRAC_BITS; + + /* next sample */ + if (acc0 > 0) { + + /* advance sample pointer */ + pSamples += acc0; + phaseFrac = (EAS_I32)((EAS_U32)phaseFrac & PHASE_FRAC_MASK); + + /* fetch new samples */ +#if defined(_8_BIT_SAMPLES) + /*lint -e{701} */ + samp1 = pSamples[0] << 8; + /*lint -e{701} */ + samp2 = pSamples[1] << 8; +#else + samp1 = pSamples[0]; + samp2 = pSamples[1]; +#endif + } + } + + /* save pointer and phase */ + pWTVoice->phaseAccum = (EAS_U32) pSamples; + pWTVoice->phaseFrac = (EAS_U32) phaseFrac; +} +#endif + +#if defined(_FILTER_ENABLED) && !defined(NATIVE_EAS_KERNEL) +/*---------------------------------------------------------------------------- + * WT_VoiceFilter + *---------------------------------------------------------------------------- + * Purpose: + * Implements a 2-pole filter + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +void WT_VoiceFilter (S_FILTER_CONTROL *pFilter, S_WT_INT_FRAME *pWTIntFrame) +{ + EAS_PCM *pAudioBuffer; + EAS_I32 k; + EAS_I32 b1; + EAS_I32 b2; + EAS_I32 z1; + EAS_I32 z2; + EAS_I32 acc0; + EAS_I32 acc1; + EAS_I32 numSamples; + + /* initialize some local variables */ + numSamples = pWTIntFrame->numSamples; + pAudioBuffer = pWTIntFrame->pAudioBuffer; + + z1 = pFilter->z1; + z2 = pFilter->z2; + b1 = -pWTIntFrame->frame.b1; + + /*lint -e{702} */ + b2 = -pWTIntFrame->frame.b2 >> 1; + + /*lint -e{702} */ + k = pWTIntFrame->frame.k >> 1; + + while (numSamples--) + { + + /* do filter calculations */ + acc0 = *pAudioBuffer; + acc1 = z1 * b1; + acc1 += z2 * b2; + acc0 = acc1 + k * acc0; + z2 = z1; + + /*lint -e{702} */ + z1 = acc0 >> 14; + *pAudioBuffer++ = (EAS_I16) z1; + } + + /* save delay values */ + pFilter->z1 = (EAS_I16) z1; + pFilter->z2 = (EAS_I16) z2; +} +#endif + +/*---------------------------------------------------------------------------- + * WT_NoiseGenerator + *---------------------------------------------------------------------------- + * Purpose: + * Generate pseudo-white noise using PRNG and interpolation engine + * + * Inputs: + * + * Outputs: + * + * Notes: + * This output is scaled -12dB to prevent saturation in the filter. For a + * high quality synthesizer, the output can be set to full scale, however + * if the filter is used, it can overflow with certain coefficients. In this + * case, either a saturation operation should take in the filter before + * scaling back to 16 bits or the signal path should be increased to 18 bits + * or more. + *---------------------------------------------------------------------------- +*/ + void WT_NoiseGenerator (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame) + { + EAS_PCM *pOutputBuffer; + EAS_I32 phaseInc; + EAS_I32 tmp0; + EAS_I32 tmp1; + EAS_I32 nInterpolatedSample; + EAS_I32 numSamples; + + /* initialize some local variables */ + numSamples = pWTIntFrame->numSamples; + pOutputBuffer = pWTIntFrame->pAudioBuffer; + phaseInc = pWTIntFrame->frame.phaseIncrement; + + /* get last two samples generated */ + /*lint -e{704} */ + tmp0 = (EAS_I32) (pWTVoice->phaseAccum) >> 18; + /*lint -e{704} */ + tmp1 = (EAS_I32) (pWTVoice->loopEnd) >> 18; + + /* generate a buffer of noise */ + while (numSamples--) { + nInterpolatedSample = MULT_AUDIO_COEF( tmp0, (PHASE_ONE - pWTVoice->phaseFrac)); + nInterpolatedSample += MULT_AUDIO_COEF( tmp1, pWTVoice->phaseFrac); + *pOutputBuffer++ = (EAS_PCM) nInterpolatedSample; + + /* update PRNG */ + pWTVoice->phaseFrac += (EAS_U32) phaseInc; + if (GET_PHASE_INT_PART(pWTVoice->phaseFrac)) { + tmp0 = tmp1; + pWTVoice->phaseAccum = pWTVoice->loopEnd; + pWTVoice->loopEnd = (5 * pWTVoice->loopEnd + 1); + tmp1 = (EAS_I32) (pWTVoice->loopEnd) >> 18; + pWTVoice->phaseFrac = GET_PHASE_FRAC_PART(pWTVoice->phaseFrac); + } + + } +} + +#ifndef _OPTIMIZED_MONO +/*---------------------------------------------------------------------------- + * WT_ProcessVoice + *---------------------------------------------------------------------------- + * Purpose: + * This routine does the block processing for one voice. It is isolated + * from the main synth code to allow for various implementation-specific + * optimizations. It calls the interpolator, filter, and gain routines + * appropriate for a particular configuration. + * + * Inputs: + * + * Outputs: + * + * Notes: + *---------------------------------------------------------------------------- +*/ +void WT_ProcessVoice (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame) +{ + + /* use noise generator */ + if (pWTVoice->loopStart == WT_NOISE_GENERATOR) + WT_NoiseGenerator(pWTVoice, pWTIntFrame); + + /* generate interpolated samples for looped waves */ + else if (pWTVoice->loopStart != pWTVoice->loopEnd) + WT_Interpolate(pWTVoice, pWTIntFrame); + + /* generate interpolated samples for unlooped waves */ + else + { + WT_InterpolateNoLoop(pWTVoice, pWTIntFrame); + } + +#ifdef _FILTER_ENABLED + if (pWTIntFrame->frame.k != 0) + WT_VoiceFilter(&pWTVoice->filter, pWTIntFrame); +#endif + +//2 TEST NEW MIXER FUNCTION +#ifdef UNIFIED_MIXER + { + EAS_I32 gainLeft, gainIncLeft; + +#if (NUM_OUTPUT_CHANNELS == 2) + EAS_I32 gainRight, gainIncRight; +#endif + + gainLeft = (pWTIntFrame->prevGain * pWTVoice->gainLeft) << 1; + gainIncLeft = (((pWTIntFrame->frame.gainTarget * pWTVoice->gainLeft) << 1) - gainLeft) >> SYNTH_UPDATE_PERIOD_IN_BITS; + +#if (NUM_OUTPUT_CHANNELS == 2) + gainRight = (pWTIntFrame->prevGain * pWTVoice->gainRight) << 1; + gainIncRight = (((pWTIntFrame->frame.gainTarget * pWTVoice->gainRight) << 1) - gainRight) >> SYNTH_UPDATE_PERIOD_IN_BITS; + EAS_MixStream( + pWTIntFrame->pAudioBuffer, + pWTIntFrame->pMixBuffer, + pWTIntFrame->numSamples, + gainLeft, + gainRight, + gainIncLeft, + gainIncRight, + MIX_FLAGS_STEREO_OUTPUT); + +#else + EAS_MixStream( + pWTIntFrame->pAudioBuffer, + pWTIntFrame->pMixBuffer, + pWTIntFrame->numSamples, + gainLeft, + 0, + gainIncLeft, + 0, + 0); +#endif + } + +#else + /* apply gain, and left and right gain */ + WT_VoiceGain(pWTVoice, pWTIntFrame); +#endif +} +#endif + +#if defined(_OPTIMIZED_MONO) && !defined(NATIVE_EAS_KERNEL) +/*---------------------------------------------------------------------------- + * WT_InterpolateMono + *---------------------------------------------------------------------------- + * Purpose: + * A C version of the sample interpolation + gain routine, optimized for mono. + * It's not pretty, but it matches the assembly code exactly. + * + * Inputs: + * + * Outputs: + * + * Notes: + *---------------------------------------------------------------------------- +*/ +void WT_InterpolateMono (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame) +{ + EAS_I32 *pMixBuffer; + const EAS_I8 *pLoopEnd; + const EAS_I8 *pCurrentPhaseInt; + EAS_I32 numSamples; + EAS_I32 gain; + EAS_I32 gainIncrement; + EAS_I32 currentPhaseFrac; + EAS_I32 phaseInc; + EAS_I32 tmp0; + EAS_I32 tmp1; + EAS_I32 tmp2; + EAS_I8 *pLoopStart; + + numSamples = pWTIntFrame->numSamples; + pMixBuffer = pWTIntFrame->pMixBuffer; + + /* calculate gain increment */ + gainIncrement = (pWTIntFrame->gainTarget - pWTIntFrame->prevGain) << (16 - SYNTH_UPDATE_PERIOD_IN_BITS); + if (gainIncrement < 0) + gainIncrement++; + gain = pWTIntFrame->prevGain << 16; + + pCurrentPhaseInt = pWTVoice->pPhaseAccum; + currentPhaseFrac = pWTVoice->phaseFrac; + phaseInc = pWTIntFrame->phaseIncrement; + + pLoopStart = pWTVoice->pLoopStart; + pLoopEnd = pWTVoice->pLoopEnd + 1; + +InterpolationLoop: + tmp0 = (EAS_I32)(pCurrentPhaseInt - pLoopEnd); + if (tmp0 >= 0) + pCurrentPhaseInt = pLoopStart + tmp0; + + tmp0 = *pCurrentPhaseInt; + tmp1 = *(pCurrentPhaseInt + 1); + + tmp2 = phaseInc + currentPhaseFrac; + + tmp1 = tmp1 - tmp0; + tmp1 = tmp1 * currentPhaseFrac; + + tmp1 = tmp0 + (tmp1 >> NUM_EG1_FRAC_BITS); + + pCurrentPhaseInt += (tmp2 >> NUM_PHASE_FRAC_BITS); + currentPhaseFrac = tmp2 & PHASE_FRAC_MASK; + + gain += gainIncrement; + tmp2 = (gain >> SYNTH_UPDATE_PERIOD_IN_BITS); + + tmp0 = *pMixBuffer; + tmp2 = tmp1 * tmp2; + tmp2 = (tmp2 >> 9); + tmp0 = tmp2 + tmp0; + *pMixBuffer++ = tmp0; + + numSamples--; + if (numSamples) + goto InterpolationLoop; + + pWTVoice->pPhaseAccum = pCurrentPhaseInt; + pWTVoice->phaseFrac = currentPhaseFrac; + /*lint -e{702} */ + pWTVoice->gain = (EAS_I16)(gain >> SYNTH_UPDATE_PERIOD_IN_BITS); +} +#endif + +#ifdef _OPTIMIZED_MONO +/*---------------------------------------------------------------------------- + * WT_ProcessVoice + *---------------------------------------------------------------------------- + * Purpose: + * This routine does the block processing for one voice. It is isolated + * from the main synth code to allow for various implementation-specific + * optimizations. It calls the interpolator, filter, and gain routines + * appropriate for a particular configuration. + * + * Inputs: + * + * Outputs: + * + * Notes: + * This special version works handles an optimized mono-only signal + * without filters + *---------------------------------------------------------------------------- +*/ +void WT_ProcessVoice (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame) +{ + + /* use noise generator */ + if (pWTVoice->loopStart== WT_NOISE_GENERATOR) + { + WT_NoiseGenerator(pWTVoice, pWTIntFrame); + WT_VoiceGain(pWTVoice, pWTIntFrame); + } + + /* or generate interpolated samples */ + else + { + WT_InterpolateMono(pWTVoice, pWTIntFrame); + } +} +#endif + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_wtengine.h b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_wtengine.h new file mode 100755 index 0000000..bba7a5e --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_wtengine.h @@ -0,0 +1,171 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_wtengine.h + * + * Contents and purpose: + * This file defines the interface for wavetable synthesis engine + * + * Copyright Sonic Network Inc. 2004 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 818 $ + * $Date: 2007-08-02 15:19:41 -0700 (Thu, 02 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_WTENGINE_H +#define _EAS_WTENGINE_H + +/* option sanity check */ +#if defined(_OPTIMIZED_MONO) && defined(_FILTER_ENABLED) +#error "Incompatible build settings: _OPTIMIZED_MONO cannot be used with _FILTER_ENABLED" +#endif + +#if defined(_OPTIMIZED_MONO) && (NUM_OUTPUT_CHANNELS != 1) +#error "Incompatible build settings: _OPTIMIZED_MONO can only be used with NUM_OUTPUT_CHANNELS = 1" +#endif + +#include "eas_wt_IPC_frame.h" + +/*---------------------------------------------------------------------------- + * defines + *---------------------------------------------------------------------------- +*/ +#define WT_NOISE_GENERATOR 0xffffffff + +/*---------------------------------------------------------------------------- + * typedefs + *---------------------------------------------------------------------------- +*/ + +/*---------------------------------------------------------------------------- + * S_WT_INT_FRAME + * + * This structure includes S_WT_FRAME plus the bus mixing + * parameters for the internal voices. + *---------------------------------------------------------------------------- +*/ +typedef struct s_wt_int_frame_tag +{ + S_WT_FRAME frame; + EAS_PCM *pAudioBuffer; + EAS_I32 *pMixBuffer; + EAS_I32 numSamples; + EAS_I32 prevGain; +} S_WT_INT_FRAME; + +#if defined(_FILTER_ENABLED) +/*---------------------------------------------------------------------------- + * S_FILTER_CONTROL data structure + *---------------------------------------------------------------------------- +*/ +typedef struct s_filter_control_tag +{ + EAS_I16 z1; /* 1 sample delay state variable */ + EAS_I16 z2; /* 2 sample delay state variable */ +} S_FILTER_CONTROL; +#endif + +/*------------------------------------ + * S_LFO_CONTROL data structure + *------------------------------------ +*/ +typedef struct s_lfo_control_tag +{ + EAS_I16 lfoValue; /* LFO current output value */ + EAS_I16 lfoPhase; /* LFO current phase */ +} S_LFO_CONTROL; + +/* bit definitions for S_WT_VOICE:flags */ +#define WT_FLAGS_ADPCM_NIBBLE 1 /* high/low nibble flag */ +#define WT_FLAGS_ADPCM_READY 2 /* first 2 samples are decoded */ +#define WT_FLAGS_USE_ADPCM 4 /* sample is ADPCM encoded */ + +/* eg1State and eg2State */ +typedef enum { + eEnvelopeStateInit = 0, + eEnvelopeStateDelay, + eEnvelopeStateAttack, + eEnvelopeStateHold, + eEnvelopeStateDecay, + eEnvelopeStateSustain, + eEnvelopeStateRelease, + eEnvelopeStateMuting, + eEnvelopeStateMuted, + eEnvelopeStateInvalid /* should never be in this state! */ +} E_ENVELOPE_STATE; + +#define DEFAULT_EG1_STATE eEnvelopeStateAttack +#define DEFAULT_EG1_VALUE 0 +#define DEFAULT_EG1_INCREMENT 0 +#define DEFAULT_EG2_STATE eEnvelopeStateAttack +#define DEFAULT_EG2_VALUE 0 +#define DEFAULT_EG2_INCREMENT 0 + +/*---------------------------------------------------------------------------- + * S_WT_VOICE + * + * This structure contains state data for the wavetable engine + *---------------------------------------------------------------------------- +*/ +typedef struct s_wt_voice_tag +{ + EAS_U32 loopEnd; /* points to last PCM sample (not 1 beyond last) */ + EAS_U32 loopStart; /* points to first sample at start of loop */ + EAS_U32 phaseAccum; /* current sample, integer portion of phase */ + EAS_U32 phaseFrac; /* fractional portion of phase */ + +#if (NUM_OUTPUT_CHANNELS == 2) + EAS_I16 gainLeft; /* current gain, left ch */ + EAS_I16 gainRight; /* current gain, right ch */ +#endif + +#if defined(_FILTER_ENABLED) + S_FILTER_CONTROL filter; /* low pass filter */ +#endif + + S_LFO_CONTROL modLFO; /* modulator LFO */ + +#ifdef DLS_SYNTHESIZER + S_LFO_CONTROL vibLFO; /* vibrato LFO */ +#endif + + /* envelope control */ + EAS_I16 eg1Value; + EAS_I16 eg2Value; + EAS_I16 eg1Increment; + EAS_I16 eg2Increment; + EAS_U8 eg1State; + EAS_U8 eg2State; + + EAS_U16 artIndex; /* index to articulation params */ + +} S_WT_VOICE; + +/*---------------------------------------------------------------------------- + * prototypes + *---------------------------------------------------------------------------- +*/ +EAS_BOOL WT_CheckSampleEnd (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame, EAS_BOOL update); +void WT_ProcessVoice (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame); + +#ifdef EAS_SPLIT_WT_SYNTH +void WTE_ConfigVoice (EAS_I32 voiceNum, S_WT_CONFIG *pWTConfig, EAS_FRAME_BUFFER_HANDLE pFrameBuffer); +void WTE_ProcessVoice (EAS_I32 voiceNum, S_WT_FRAME *pWTParams, EAS_FRAME_BUFFER_HANDLE pFrameBuffer); +#endif + +#endif diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_wtsynth.c b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_wtsynth.c new file mode 100755 index 0000000..788b34f --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_wtsynth.c @@ -0,0 +1,1251 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_wtsynth.c + * + * Contents and purpose: + * Implements the synthesizer functions. + * + * Copyright Sonic Network Inc. 2004 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 795 $ + * $Date: 2007-08-01 00:14:45 -0700 (Wed, 01 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +// includes +#include "eas_data.h" +#include "eas_report.h" +#include "eas_host.h" +#include "eas_math.h" +#include "eas_synth_protos.h" +#include "eas_wtsynth.h" +#include "eas_pan.h" + +#ifdef DLS_SYNTHESIZER +#include "eas_dlssynth.h" +#endif + +#ifdef _METRICS_ENABLED +#include "eas_perf.h" +#endif + +/* local prototypes */ +static EAS_RESULT WT_Initialize(S_VOICE_MGR *pVoiceMgr); +static void WT_ReleaseVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum); +static void WT_MuteVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum); +static void WT_SustainPedal (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, S_SYNTH_CHANNEL *pChannel, EAS_I32 voiceNum); +static EAS_RESULT WT_StartVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_U16 regionIndex); +static EAS_BOOL WT_UpdateVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_I32 *pMixBuffer, EAS_I32 numSamples); +static void WT_UpdateChannel (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel); +static EAS_I32 WT_UpdatePhaseInc (S_WT_VOICE *pWTVoice, const S_ARTICULATION *pArt, S_SYNTH_CHANNEL *pChannel, EAS_I32 pitchCents); +static EAS_I32 WT_UpdateGain (S_SYNTH_VOICE *pVoice, S_WT_VOICE *pWTVoice, const S_ARTICULATION *pArt, S_SYNTH_CHANNEL *pChannel, EAS_I32 gain); +static void WT_UpdateEG1 (S_WT_VOICE *pWTVoice, const S_ENVELOPE *pEnv); +static void WT_UpdateEG2 (S_WT_VOICE *pWTVoice, const S_ENVELOPE *pEnv); + +#ifdef EAS_SPLIT_WT_SYNTH +extern EAS_BOOL WTE_StartFrame (EAS_FRAME_BUFFER_HANDLE pFrameBuffer); +extern EAS_BOOL WTE_EndFrame (EAS_FRAME_BUFFER_HANDLE pFrameBuffer, EAS_I32 *pMixBuffer, EAS_I16 masterGain); +#endif + +#ifdef _FILTER_ENABLED +static void WT_UpdateFilter (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pIntFrame, const S_ARTICULATION *pArt); +#endif + +#ifdef _STATS +extern double statsPhaseIncrement; +extern double statsMaxPhaseIncrement; +extern long statsPhaseSampleCount; +extern double statsSampleSize; +extern long statsSampleCount; +#endif + +/*---------------------------------------------------------------------------- + * Synthesizer interface + *---------------------------------------------------------------------------- +*/ + +const S_SYNTH_INTERFACE wtSynth = +{ + WT_Initialize, + WT_StartVoice, + WT_UpdateVoice, + WT_ReleaseVoice, + WT_MuteVoice, + WT_SustainPedal, + WT_UpdateChannel +}; + +#ifdef EAS_SPLIT_WT_SYNTH +const S_FRAME_INTERFACE wtFrameInterface = +{ + WTE_StartFrame, + WTE_EndFrame +}; +#endif + +/*---------------------------------------------------------------------------- + * WT_Initialize() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * pVoice - pointer to voice to initialize + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT WT_Initialize (S_VOICE_MGR *pVoiceMgr) +{ + EAS_INT i; + + for (i = 0; i < NUM_WT_VOICES; i++) + { + + pVoiceMgr->wtVoices[i].artIndex = DEFAULT_ARTICULATION_INDEX; + + pVoiceMgr->wtVoices[i].eg1State = DEFAULT_EG1_STATE; + pVoiceMgr->wtVoices[i].eg1Value = DEFAULT_EG1_VALUE; + pVoiceMgr->wtVoices[i].eg1Increment = DEFAULT_EG1_INCREMENT; + + pVoiceMgr->wtVoices[i].eg2State = DEFAULT_EG2_STATE; + pVoiceMgr->wtVoices[i].eg2Value = DEFAULT_EG2_VALUE; + pVoiceMgr->wtVoices[i].eg2Increment = DEFAULT_EG2_INCREMENT; + + /* left and right gain values are needed only if stereo output */ +#if (NUM_OUTPUT_CHANNELS == 2) + pVoiceMgr->wtVoices[i].gainLeft = DEFAULT_VOICE_GAIN; + pVoiceMgr->wtVoices[i].gainRight = DEFAULT_VOICE_GAIN; +#endif + + pVoiceMgr->wtVoices[i].phaseFrac = DEFAULT_PHASE_FRAC; + pVoiceMgr->wtVoices[i].phaseAccum = DEFAULT_PHASE_INT; + +#ifdef _FILTER_ENABLED + pVoiceMgr->wtVoices[i].filter.z1 = DEFAULT_FILTER_ZERO; + pVoiceMgr->wtVoices[i].filter.z2 = DEFAULT_FILTER_ZERO; +#endif + } + + return EAS_TRUE; +} + +/*---------------------------------------------------------------------------- + * WT_ReleaseVoice() + *---------------------------------------------------------------------------- + * Purpose: + * The selected voice is being released. + * + * Inputs: + * pEASData - pointer to S_EAS_DATA + * pVoice - pointer to voice to release + * + * Outputs: + * None + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pVoice) used in some implementations */ +static void WT_ReleaseVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum) +{ + S_WT_VOICE *pWTVoice; + const S_ARTICULATION *pArticulation; + +#ifdef DLS_SYNTHESIZER + if (pVoice->regionIndex & FLAG_RGN_IDX_DLS_SYNTH) + { + DLS_ReleaseVoice(pVoiceMgr, pSynth, pVoice, voiceNum); + return; + } +#endif + + pWTVoice = &pVoiceMgr->wtVoices[voiceNum]; + pArticulation = &pSynth->pEAS->pArticulations[pWTVoice->artIndex]; + + /* release EG1 */ + pWTVoice->eg1State = eEnvelopeStateRelease; + pWTVoice->eg1Increment = pArticulation->eg1.releaseTime; + + /* + The spec says we should release EG2, but doing so with the current + voicing is causing clicks. This fix will need to be coordinated with + a new sound library release + */ + + /* release EG2 */ + pWTVoice->eg2State = eEnvelopeStateRelease; + pWTVoice->eg2Increment = pArticulation->eg2.releaseTime; +} + +/*---------------------------------------------------------------------------- + * WT_MuteVoice() + *---------------------------------------------------------------------------- + * Purpose: + * The selected voice is being muted. + * + * Inputs: + * pVoice - pointer to voice to release + * + * Outputs: + * None + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pSynth) used in some implementations */ +static void WT_MuteVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum) +{ + +#ifdef DLS_SYNTHESIZER + if (pVoice->regionIndex & FLAG_RGN_IDX_DLS_SYNTH) + { + DLS_MuteVoice(pVoiceMgr, pSynth, pVoice, voiceNum); + return; + } +#endif + + /* clear deferred action flags */ + pVoice->voiceFlags &= + ~(VOICE_FLAG_DEFER_MIDI_NOTE_OFF | + VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF | + VOICE_FLAG_DEFER_MUTE); + + /* set the envelope state */ + pVoiceMgr->wtVoices[voiceNum].eg1State = eEnvelopeStateMuted; + pVoiceMgr->wtVoices[voiceNum].eg2State = eEnvelopeStateMuted; +} + +/*---------------------------------------------------------------------------- + * WT_SustainPedal() + *---------------------------------------------------------------------------- + * Purpose: + * The selected voice is held due to sustain pedal + * + * Inputs: + * pVoice - pointer to voice to sustain + * + * Outputs: + * None + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pChannel) used in some implementations */ +static void WT_SustainPedal (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, S_SYNTH_CHANNEL *pChannel, EAS_I32 voiceNum) +{ + S_WT_VOICE *pWTVoice; + +#ifdef DLS_SYNTHESIZER + if (pVoice->regionIndex & FLAG_RGN_IDX_DLS_SYNTH) + { + DLS_SustainPedal(pVoiceMgr, pSynth, pVoice, pChannel, voiceNum); + return; + } +#endif + + /* don't catch the voice if below the sustain level */ + pWTVoice = &pVoiceMgr->wtVoices[voiceNum]; + if (pWTVoice->eg1Value < pSynth->pEAS->pArticulations[pWTVoice->artIndex].eg1.sustainLevel) + return; + + /* sustain flag is set, damper pedal is on */ + /* defer releasing this note until the damper pedal is off */ + pWTVoice->eg1State = eEnvelopeStateDecay; + pVoice->voiceState = eVoiceStatePlay; + + /* + because sustain pedal is on, this voice + should defer releasing its note + */ + pVoice->voiceFlags |= VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF; + +#ifdef _DEBUG_SYNTH + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WT_SustainPedal: defer note off because sustain pedal is on\n"); */ } +#endif +} + +/*---------------------------------------------------------------------------- + * WT_StartVoice() + *---------------------------------------------------------------------------- + * Purpose: + * Assign the region for the given instrument using the midi key number + * and the RPN2 (coarse tuning) value. By using RPN2 as part of the + * region selection process, we reduce the amount a given sample has + * to be transposed by selecting the closest recorded root instead. + * + * This routine is the second half of SynthAssignRegion(). + * If the region was successfully found by SynthFindRegionIndex(), + * then assign the region's parameters to the voice. + * + * Setup and initialize the following voice parameters: + * m_nRegionIndex + * + * Inputs: + * pVoice - ptr to the voice we have assigned for this channel + * nRegionIndex - index of the region + * pEASData - pointer to overall EAS data structure + * + * Outputs: + * success - could find and assign the region for this voice's note otherwise + * failure - could not find nor assign the region for this voice's note + * + * Side Effects: + * psSynthObject->m_sVoice[].m_nRegionIndex is assigned + * psSynthObject->m_sVoice[] parameters are assigned + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT WT_StartVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_U16 regionIndex) +{ + S_WT_VOICE *pWTVoice; + const S_WT_REGION *pRegion; + const S_ARTICULATION *pArt; + S_SYNTH_CHANNEL *pChannel; + +#if (NUM_OUTPUT_CHANNELS == 2) + EAS_INT pan; +#endif + +#ifdef EAS_SPLIT_WT_SYNTH + S_WT_CONFIG wtConfig; +#endif + + /* no samples have been synthesized for this note yet */ + pVoice->regionIndex = regionIndex; + pVoice->voiceFlags = VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET; + + /* get the articulation index for this region */ + pWTVoice = &pVoiceMgr->wtVoices[voiceNum]; + pChannel = &pSynth->channels[pVoice->channel & 15]; + + /* update static channel parameters */ + if (pChannel->channelFlags & CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS) + WT_UpdateChannel(pVoiceMgr, pSynth, pVoice->channel & 15); + +#ifdef DLS_SYNTHESIZER + if (pVoice->regionIndex & FLAG_RGN_IDX_DLS_SYNTH) + return DLS_StartVoice(pVoiceMgr, pSynth, pVoice, voiceNum, regionIndex); +#endif + + pRegion = &(pSynth->pEAS->pWTRegions[regionIndex]); + pWTVoice->artIndex = pRegion->artIndex; + +#ifdef _DEBUG_SYNTH + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WT_StartVoice: Voice %ld; Region %d\n", (EAS_I32) (pVoice - pVoiceMgr->voices), regionIndex); */ } +#endif + + pArt = &pSynth->pEAS->pArticulations[pWTVoice->artIndex]; + + /* MIDI note on puts this voice into attack state */ + pWTVoice->eg1State = eEnvelopeStateAttack; + pWTVoice->eg1Value = 0; + pWTVoice->eg1Increment = pArt->eg1.attackTime; + pWTVoice->eg2State = eEnvelopeStateAttack; + pWTVoice->eg2Value = 0; + pWTVoice->eg2Increment = pArt->eg2.attackTime; + + /* init the LFO */ + pWTVoice->modLFO.lfoValue = 0; + pWTVoice->modLFO.lfoPhase = -pArt->lfoDelay; + + pVoice->gain = 0; + +#if (NUM_OUTPUT_CHANNELS == 2) + /* + Get the Midi CC10 pan value for this voice's channel + convert the pan value to an "angle" representation suitable for + our sin, cos calculator. This representation is NOT necessarily the same + as the transform in the GM manuals because of our sin, cos calculator. + "angle" = (CC10 - 64)/128 + */ + pan = (EAS_INT) pSynth->channels[pVoice->channel & 15].pan - 64; + pan += pArt->pan; + EAS_CalcPanControl(pan, &pWTVoice->gainLeft, &pWTVoice->gainRight); +#endif + +#ifdef _FILTER_ENABLED + /* clear out the filter states */ + pWTVoice->filter.z1 = 0; + pWTVoice->filter.z2 = 0; +#endif + + /* if this wave is to be generated using noise generator */ + if (pRegion->region.keyGroupAndFlags & REGION_FLAG_USE_WAVE_GENERATOR) + { + pWTVoice->phaseAccum = 4574296; + pWTVoice->loopStart = WT_NOISE_GENERATOR; + pWTVoice->loopEnd = 4574295; + } + + /* normal sample */ + else + { + +#ifdef EAS_SPLIT_WT_SYNTH + if (voiceNum < NUM_PRIMARY_VOICES) + pWTVoice->phaseAccum = (EAS_U32) pSynth->pEAS->pSamples + pSynth->pEAS->pSampleOffsets[pRegion->waveIndex]; + else + pWTVoice->phaseAccum = pSynth->pEAS->pSampleOffsets[pRegion->waveIndex]; +#else + pWTVoice->phaseAccum = (EAS_U32) pSynth->pEAS->pSamples + pSynth->pEAS->pSampleOffsets[pRegion->waveIndex]; +#endif + + if (pRegion->region.keyGroupAndFlags & REGION_FLAG_IS_LOOPED) + { + pWTVoice->loopStart = pWTVoice->phaseAccum + pRegion->loopStart; + pWTVoice->loopEnd = pWTVoice->phaseAccum + pRegion->loopEnd - 1; + } + else + pWTVoice->loopStart = pWTVoice->loopEnd = pWTVoice->phaseAccum + pSynth->pEAS->pSampleLen[pRegion->waveIndex] - 1; + } + +#ifdef EAS_SPLIT_WT_SYNTH + /* configure off-chip voices */ + if (voiceNum >= NUM_PRIMARY_VOICES) + { + wtConfig.phaseAccum = pWTVoice->phaseAccum; + wtConfig.loopStart = pWTVoice->loopStart; + wtConfig.loopEnd = pWTVoice->loopEnd; + wtConfig.gain = pVoice->gain; + +#if (NUM_OUTPUT_CHANNELS == 2) + wtConfig.gainLeft = pWTVoice->gainLeft; + wtConfig.gainRight = pWTVoice->gainRight; +#endif + + WTE_ConfigVoice(voiceNum - NUM_PRIMARY_VOICES, &wtConfig, pVoiceMgr->pFrameBuffer); + } +#endif + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * WT_CheckSampleEnd + *---------------------------------------------------------------------------- + * Purpose: + * Check for end of sample and calculate number of samples to synthesize + * + * Inputs: + * + * Outputs: + * + * Notes: + * + *---------------------------------------------------------------------------- +*/ +EAS_BOOL WT_CheckSampleEnd (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame, EAS_BOOL update) +{ + EAS_U32 endPhaseAccum; + EAS_U32 endPhaseFrac; + EAS_I32 numSamples; + EAS_BOOL done = EAS_FALSE; + + /* check to see if we hit the end of the waveform this time */ + /*lint -e{703} use shift for performance */ + endPhaseFrac = pWTVoice->phaseFrac + (pWTIntFrame->frame.phaseIncrement << SYNTH_UPDATE_PERIOD_IN_BITS); + endPhaseAccum = pWTVoice->phaseAccum + GET_PHASE_INT_PART(endPhaseFrac); + if (endPhaseAccum >= pWTVoice->loopEnd) + { + /* calculate how far current ptr is from end */ + numSamples = (EAS_I32) (pWTVoice->loopEnd - pWTVoice->phaseAccum); + + /* now account for the fractional portion */ + /*lint -e{703} use shift for performance */ + numSamples = (EAS_I32) ((numSamples << NUM_PHASE_FRAC_BITS) - pWTVoice->phaseFrac); + pWTIntFrame->numSamples = 1 + (numSamples / pWTIntFrame->frame.phaseIncrement); + + /* sound will be done this frame */ + done = EAS_TRUE; + } + + /* update data for off-chip synth */ + if (update) + { + pWTVoice->phaseFrac = endPhaseFrac; + pWTVoice->phaseAccum = endPhaseAccum; + } + + return done; +} + +/*---------------------------------------------------------------------------- + * WT_UpdateVoice() + *---------------------------------------------------------------------------- + * Purpose: + * Synthesize a block of samples for the given voice. + * Use linear interpolation. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * + * Outputs: + * number of samples actually written to buffer + * + * Side Effects: + * - samples are added to the presently free buffer + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL WT_UpdateVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_I32 *pMixBuffer, EAS_I32 numSamples) +{ + S_WT_VOICE *pWTVoice; + S_WT_INT_FRAME intFrame; + S_SYNTH_CHANNEL *pChannel; + const S_WT_REGION *pWTRegion; + const S_ARTICULATION *pArt; + EAS_I32 temp; + EAS_BOOL done; + +#ifdef DLS_SYNTHESIZER + if (pVoice->regionIndex & FLAG_RGN_IDX_DLS_SYNTH) + return DLS_UpdateVoice(pVoiceMgr, pSynth, pVoice, voiceNum, pMixBuffer, numSamples); +#endif + + /* establish pointers to critical data */ + pWTVoice = &pVoiceMgr->wtVoices[voiceNum]; + pWTRegion = &pSynth->pEAS->pWTRegions[pVoice->regionIndex & REGION_INDEX_MASK]; + pArt = &pSynth->pEAS->pArticulations[pWTVoice->artIndex]; + pChannel = &pSynth->channels[pVoice->channel & 15]; + intFrame.prevGain = pVoice->gain; + + /* update the envelopes */ + WT_UpdateEG1(pWTVoice, &pArt->eg1); + WT_UpdateEG2(pWTVoice, &pArt->eg2); + + /* update the LFO */ + WT_UpdateLFO(&pWTVoice->modLFO, pArt->lfoFreq); + +#ifdef _FILTER_ENABLED + /* calculate filter if library uses filter */ + if (pSynth->pEAS->libAttr & LIB_FORMAT_FILTER_ENABLED) + WT_UpdateFilter(pWTVoice, &intFrame, pArt); + else + intFrame.frame.k = 0; +#endif + + /* update the gain */ + intFrame.frame.gainTarget = WT_UpdateGain(pVoice, pWTVoice, pArt, pChannel, pWTRegion->gain); + + /* calculate base pitch*/ + temp = pChannel->staticPitch + pWTRegion->tuning; + + /* include global transpose */ + if (pChannel->channelFlags & CHANNEL_FLAG_RHYTHM_CHANNEL) + temp += pVoice->note * 100; + else + temp += (pVoice->note + pSynth->globalTranspose) * 100; + intFrame.frame.phaseIncrement = WT_UpdatePhaseInc(pWTVoice, pArt, pChannel, temp); + + /* call into engine to generate samples */ + intFrame.pAudioBuffer = pVoiceMgr->voiceBuffer; + intFrame.pMixBuffer = pMixBuffer; + intFrame.numSamples = numSamples; + + /* check for end of sample */ + if ((pWTVoice->loopStart != WT_NOISE_GENERATOR) && (pWTVoice->loopStart == pWTVoice->loopEnd)) + done = WT_CheckSampleEnd(pWTVoice, &intFrame, (EAS_BOOL) (voiceNum >= NUM_PRIMARY_VOICES)); + else + done = EAS_FALSE; + +#ifdef EAS_SPLIT_WT_SYNTH + if (voiceNum < NUM_PRIMARY_VOICES) + { +#ifndef _SPLIT_WT_TEST_HARNESS + WT_ProcessVoice(pWTVoice, &intFrame); +#endif + } + else + WTE_ProcessVoice(voiceNum - NUM_PRIMARY_VOICES, &intFrame.frame, pVoiceMgr->pFrameBuffer); +#else + WT_ProcessVoice(pWTVoice, &intFrame); +#endif + + /* clear flag */ + pVoice->voiceFlags &= ~VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET; + + /* if voice has finished, set flag for voice manager */ + if ((pVoice->voiceState != eVoiceStateStolen) && (pWTVoice->eg1State == eEnvelopeStateMuted)) + done = EAS_TRUE; + + /* if the update interval has elapsed, then force the current gain to the next + * gain since we never actually reach the next gain when ramping -- we just get + * very close to the target gain. + */ + pVoice->gain = (EAS_I16) intFrame.frame.gainTarget; + + return done; +} + +/*---------------------------------------------------------------------------- + * WT_UpdatePhaseInc() + *---------------------------------------------------------------------------- + * Purpose: + * Calculate the phase increment + * + * Inputs: + * pVoice - pointer to the voice being updated + * psRegion - pointer to the region + * psArticulation - pointer to the articulation + * nChannelPitchForThisVoice - the portion of the pitch that is fixed for this + * voice during the duration of this synthesis + * pEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * set the phase increment for this voice + *---------------------------------------------------------------------------- +*/ +static EAS_I32 WT_UpdatePhaseInc (S_WT_VOICE *pWTVoice, const S_ARTICULATION *pArt, S_SYNTH_CHANNEL *pChannel, EAS_I32 pitchCents) +{ + EAS_I32 temp; + + /*pitchCents due to CC1 = LFO * (CC1 / 128) * DEFAULT_LFO_MOD_WHEEL_TO_PITCH_CENTS */ + temp = MULT_EG1_EG1(DEFAULT_LFO_MOD_WHEEL_TO_PITCH_CENTS, + ((pChannel->modWheel) << (NUM_EG1_FRAC_BITS -7))); + + /* pitchCents due to channel pressure = LFO * (channel pressure / 128) * DEFAULT_LFO_CHANNEL_PRESSURE_TO_PITCH_CENTS */ + temp += MULT_EG1_EG1(DEFAULT_LFO_CHANNEL_PRESSURE_TO_PITCH_CENTS, + ((pChannel->channelPressure) << (NUM_EG1_FRAC_BITS -7))); + + /* now multiply the (channel pressure + CC1) pitch values by the LFO value */ + temp = MULT_EG1_EG1(pWTVoice->modLFO.lfoValue, temp); + + /* + add in the LFO pitch due to + channel pressure and CC1 along with + the LFO pitch, the EG2 pitch, and the + "static" pitch for this voice on this channel + */ + temp += pitchCents + + (MULT_EG1_EG1(pWTVoice->eg2Value, pArt->eg2ToPitch)) + + (MULT_EG1_EG1(pWTVoice->modLFO.lfoValue, pArt->lfoToPitch)); + + /* convert from cents to linear phase increment */ + return EAS_Calculate2toX(temp); +} + +/*---------------------------------------------------------------------------- + * WT_UpdateChannel() + *---------------------------------------------------------------------------- + * Purpose: + * Calculate and assign static channel parameters + * These values only need to be updated if one of the controller values + * for this channel changes + * + * Inputs: + * nChannel - channel to update + * pEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * - the given channel's static gain and static pitch are updated + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pVoiceMgr) reserved for future use */ +static void WT_UpdateChannel (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel) +{ + EAS_I32 staticGain; + EAS_I32 pitchBend; + S_SYNTH_CHANNEL *pChannel; + + pChannel = &pSynth->channels[channel]; + + /* + nChannelGain = (CC7 * CC11)^2 * master volume + where CC7 == 100 by default, CC11 == 127, master volume == 32767 + */ + staticGain = MULT_EG1_EG1((pChannel->volume) << (NUM_EG1_FRAC_BITS - 7), + (pChannel->expression) << (NUM_EG1_FRAC_BITS - 7)); + + /* staticGain has to be squared */ + staticGain = MULT_EG1_EG1(staticGain, staticGain); + + pChannel->staticGain = (EAS_I16) MULT_EG1_EG1(staticGain, pSynth->masterVolume); + + /* + calculate pitch bend: RPN0 * ((2*pitch wheel)/16384 -1) + However, if we use the EG1 macros, remember that EG1 has a full + scale value of 32768 (instead of 16384). So instead of multiplying + by 2, multiply by 4 (left shift by 2), and subtract by 32768 instead + of 16384. This utilizes the fact that the EG1 macro places a binary + point 15 places to the left instead of 14 places. + */ + /*lint -e{703} */ + pitchBend = + (((EAS_I32)(pChannel->pitchBend) << 2) + - 32768); + + pChannel->staticPitch = + MULT_EG1_EG1(pitchBend, pChannel->pitchBendSensitivity); + + /* if this is not a drum channel, then add in the per-channel tuning */ + if (!(pChannel->channelFlags & CHANNEL_FLAG_RHYTHM_CHANNEL)) + pChannel->staticPitch += pChannel->finePitch + (pChannel->coarsePitch * 100); + + /* clear update flag */ + pChannel->channelFlags &= ~CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS; + return; +} + +/*---------------------------------------------------------------------------- + * WT_UpdateGain() + *---------------------------------------------------------------------------- + * Purpose: + * Calculate and assign static voice parameters as part of WT_UpdateVoice() + * + * Inputs: + * pVoice - ptr to the synth voice that we want to synthesize + * pEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * - various voice parameters are calculated and assigned + * + *---------------------------------------------------------------------------- +*/ +static EAS_I32 WT_UpdateGain (S_SYNTH_VOICE *pVoice, S_WT_VOICE *pWTVoice, const S_ARTICULATION *pArt, S_SYNTH_CHANNEL *pChannel, EAS_I32 gain) +{ + EAS_I32 lfoGain; + EAS_I32 temp; + + /* + If this voice was stolen, then the velocity is actually + for the new note, not the note that we are currently ramping down. + So we really shouldn't use this velocity. However, that would require + more memory to store the velocity value, and the improvement may + not be sufficient to warrant the added memory. + */ + /* velocity is fixed at note start for a given voice and must be squared */ + temp = (pVoice->velocity) << (NUM_EG1_FRAC_BITS - 7); + temp = MULT_EG1_EG1(temp, temp); + + /* region gain is fixed as part of the articulation */ + temp = MULT_EG1_EG1(temp, gain); + + /* include the channel gain */ + temp = MULT_EG1_EG1(temp, pChannel->staticGain); + + /* calculate LFO gain using an approximation for 10^x */ + lfoGain = MULT_EG1_EG1(pWTVoice->modLFO.lfoValue, pArt->lfoToGain); + lfoGain = MULT_EG1_EG1(lfoGain, LFO_GAIN_TO_CENTS); + + /* convert from a dB-like value to linear gain */ + lfoGain = EAS_Calculate2toX(lfoGain); + temp = MULT_EG1_EG1(temp, lfoGain); + + /* calculate the voice's gain */ + temp = (EAS_I16)MULT_EG1_EG1(temp, pWTVoice->eg1Value); + + return temp; +} + +/*---------------------------------------------------------------------------- + * WT_UpdateEG1() + *---------------------------------------------------------------------------- + * Purpose: + * Calculate the EG1 envelope for the given voice (but do not update any + * state) + * + * Inputs: + * pVoice - ptr to the voice whose envelope we want to update + * nVoice - this voice's number - used only for debug + * pEASData - pointer to overall EAS data structure + * + * Outputs: + * nValue - the envelope value + * + * Side Effects: + * - updates EG1 state value for the given voice + *---------------------------------------------------------------------------- +*/ +static void WT_UpdateEG1 (S_WT_VOICE *pWTVoice, const S_ENVELOPE *pEnv) +{ + EAS_I32 temp; + + switch (pWTVoice->eg1State) + { + case eEnvelopeStateAttack: + temp = pWTVoice->eg1Value + pWTVoice->eg1Increment; + + /* check if we have reached peak amplitude */ + if (temp >= SYNTH_FULL_SCALE_EG1_GAIN) + { + /* limit the volume */ + temp = SYNTH_FULL_SCALE_EG1_GAIN; + + /* prepare to move to decay state */ + pWTVoice->eg1State = eEnvelopeStateDecay; + pWTVoice->eg1Increment = pEnv->decayTime; + } + + break; + + /* exponential decay */ + case eEnvelopeStateDecay: + temp = MULT_EG1_EG1(pWTVoice->eg1Value, pWTVoice->eg1Increment); + + /* check if we have reached sustain level */ + if (temp <= pEnv->sustainLevel) + { + /* enforce the sustain level */ + temp = pEnv->sustainLevel; + + /* if sustain level is zero, skip sustain & release the voice */ + if (temp > 0) + pWTVoice->eg1State = eEnvelopeStateSustain; + + /* move to sustain state */ + else + pWTVoice->eg1State = eEnvelopeStateMuted; + } + + break; + + case eEnvelopeStateSustain: + return; + + case eEnvelopeStateRelease: + temp = MULT_EG1_EG1(pWTVoice->eg1Value, pWTVoice->eg1Increment); + + /* if we hit zero, this voice isn't contributing any audio */ + if (temp <= 0) + { + temp = 0; + pWTVoice->eg1State = eEnvelopeStateMuted; + } + break; + + /* voice is muted, set target to zero */ + case eEnvelopeStateMuted: + temp = 0; + break; + + case eEnvelopeStateInvalid: + default: + temp = 0; +#ifdef _DEBUG_SYNTH + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WT_UpdateEG1: error, %d is an unrecognized state\n", + pWTVoice->eg1State); */ } +#endif + break; + + } + + pWTVoice->eg1Value = (EAS_I16) temp; +} + +/*---------------------------------------------------------------------------- + * WT_UpdateEG2() + *---------------------------------------------------------------------------- + * Purpose: + * Update the EG2 envelope for the given voice + * + * Inputs: + * pVoice - ptr to the voice whose envelope we want to update + * pEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * - updates EG2 values for the given voice + *---------------------------------------------------------------------------- +*/ + +static void WT_UpdateEG2 (S_WT_VOICE *pWTVoice, const S_ENVELOPE *pEnv) +{ + EAS_I32 temp; + + switch (pWTVoice->eg2State) + { + case eEnvelopeStateAttack: + temp = pWTVoice->eg2Value + pWTVoice->eg2Increment; + + /* check if we have reached peak amplitude */ + if (temp >= SYNTH_FULL_SCALE_EG1_GAIN) + { + /* limit the volume */ + temp = SYNTH_FULL_SCALE_EG1_GAIN; + + /* prepare to move to decay state */ + pWTVoice->eg2State = eEnvelopeStateDecay; + + pWTVoice->eg2Increment = pEnv->decayTime; + } + + break; + + /* implement linear pitch decay in cents */ + case eEnvelopeStateDecay: + temp = pWTVoice->eg2Value -pWTVoice->eg2Increment; + + /* check if we have reached sustain level */ + if (temp <= pEnv->sustainLevel) + { + /* enforce the sustain level */ + temp = pEnv->sustainLevel; + + /* prepare to move to sustain state */ + pWTVoice->eg2State = eEnvelopeStateSustain; + } + break; + + case eEnvelopeStateSustain: + return; + + case eEnvelopeStateRelease: + temp = pWTVoice->eg2Value - pWTVoice->eg2Increment; + + if (temp <= 0) + { + temp = 0; + pWTVoice->eg2State = eEnvelopeStateMuted; + } + + break; + + /* voice is muted, set target to zero */ + case eEnvelopeStateMuted: + temp = 0; + break; + + case eEnvelopeStateInvalid: + default: + temp = 0; +#ifdef _DEBUG_SYNTH + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WT_UpdateEG2: error, %d is an unrecognized state\n", + pWTVoice->eg2State); */ } +#endif + break; + } + + pWTVoice->eg2Value = (EAS_I16) temp; +} + +/*---------------------------------------------------------------------------- + * WT_UpdateLFO () + *---------------------------------------------------------------------------- + * Purpose: + * Calculate the LFO for the given voice + * + * Inputs: + * pLFO - ptr to the LFO data + * phaseInc - phase increment + * + * Outputs: + * + * Side Effects: + * - updates LFO values for the given voice + *---------------------------------------------------------------------------- +*/ +void WT_UpdateLFO (S_LFO_CONTROL *pLFO, EAS_I16 phaseInc) +{ + + /* To save memory, if m_nPhaseValue is negative, we are in the + * delay phase, and m_nPhaseValue represents the time left + * in the delay. + */ + if (pLFO->lfoPhase < 0) + { + pLFO->lfoPhase++; + return; + } + + /* calculate LFO output from phase value */ + /*lint -e{701} Use shift for performance */ + pLFO->lfoValue = (EAS_I16) (pLFO->lfoPhase << 2); + /*lint -e{502} */ + if ((pLFO->lfoPhase > 0x1fff) && (pLFO->lfoPhase < 0x6000)) + pLFO->lfoValue = ~pLFO->lfoValue; + + /* update LFO phase */ + pLFO->lfoPhase = (pLFO->lfoPhase + phaseInc) & 0x7fff; +} + +#ifdef _FILTER_ENABLED +/*---------------------------------------------------------------------------- + * WT_UpdateFilter() + *---------------------------------------------------------------------------- + * Purpose: + * Update the Filter parameters + * + * Inputs: + * pVoice - ptr to the voice whose filter we want to update + * pEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * - updates Filter values for the given voice + *---------------------------------------------------------------------------- +*/ +static void WT_UpdateFilter (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pIntFrame, const S_ARTICULATION *pArt) +{ + EAS_I32 cutoff; + + /* no need to calculate filter coefficients if it is bypassed */ + if (pArt->filterCutoff == DEFAULT_EAS_FILTER_CUTOFF_FREQUENCY) + { + pIntFrame->frame.k = 0; + return; + } + + /* determine the dynamic cutoff frequency */ + cutoff = MULT_EG1_EG1(pWTVoice->eg2Value, pArt->eg2ToFc); + cutoff += pArt->filterCutoff; + + /* subtract the A5 offset and the sampling frequency */ + cutoff -= FILTER_CUTOFF_FREQ_ADJUST + A5_PITCH_OFFSET_IN_CENTS; + + /* limit the cutoff frequency */ + if (cutoff > FILTER_CUTOFF_MAX_PITCH_CENTS) + cutoff = FILTER_CUTOFF_MAX_PITCH_CENTS; + else if (cutoff < FILTER_CUTOFF_MIN_PITCH_CENTS) + cutoff = FILTER_CUTOFF_MIN_PITCH_CENTS; + + WT_SetFilterCoeffs(pIntFrame, cutoff, pArt->filterQ); +} +#endif + +#if defined(_FILTER_ENABLED) || defined(DLS_SYNTHESIZER) +/*---------------------------------------------------------------------------- + * coef + *---------------------------------------------------------------------------- + * Table of filter coefficients for low-pass filter + *---------------------------------------------------------------------------- + * + * polynomial coefficients are based on 8kHz sampling frequency + * filter coef b2 = k2 = k2g0*k^0 + k2g1*k^1*(2^x) + k2g2*k^2*(2^x) + * + *where k2g0, k2g1, k2g2 are from the truncated power series expansion on theta + *(k*2^x = theta, but we incorporate the k along with the k2g0, k2g1, k2g2) + *note: this is a power series in 2^x, not k*2^x + *where k = (2*pi*440)/8kHz == convert octaves to radians + * + * so actually, the following coefs listed as k2g0, k2g1, k2g2 are really + * k2g0*k^0 = k2g0 + * k2g1*k^1 + * k2g2*k^2 + * + * + * filter coef n1 = numerator = n1g0*k^0 + n1g1*k^1*(2^x) + n1g2*k^2*(2^x) + n1g3*k^3*(2^x) + * + *where n1g0, n1g1, n1g2, n1g3 are from the truncated power series expansion on theta + *(k*2^x = theta, but we incorporate the k along with the n1g0, n1g1, n1g2, n2g3) + *note: this is a power series in 2^x, not k*2^x + *where k = (2*pi*440)/8kHz == convert octaves to radians + *we also include the optimization factor of 0.81 + * + * so actually, the following coefs listed as n1g0, n1g1, n1g2, n2g3 are really + * n1g0*k^0 = n1g0 + * n1g1*k^1 + * n1g2*k^2 + * n1g3*k^3 + * + * NOTE that n1g0 == n1g1 == 0, always, so we only need to store n1g2 and n1g3 + *---------------------------------------------------------------------------- +*/ + +static const EAS_I16 nk1g0 = -32768; +static const EAS_I16 nk1g2 = 1580; +static const EAS_I16 k2g0 = 32767; + +static const EAS_I16 k2g1[] = +{ + -11324, /* k2g1[0] = -0.3455751918948761 */ + -10387, /* k2g1[1] = -0.3169878073928751 */ + -9528, /* k2g1[2] = -0.29076528753345476 */ + -8740, /* k2g1[3] = -0.2667120011011279 */ + -8017, /* k2g1[4] = -0.24464850028971705 */ + -7353, /* k2g1[5] = -0.22441018194495696 */ + -6745, /* k2g1[6] = -0.20584605955455101 */ + -6187, /* k2g1[7] = -0.18881763682420102 */ + -5675, /* k2g1[8] = -0.1731978744360067 */ + -5206, /* k2g1[9] = -0.15887024228080968 */ + -4775, /* k2g1[10] = -0.14572785009373057 */ + -4380, /* k2g1[11] = -0.13367265000706827 */ + -4018, /* k2g1[12] = -0.1226147050712642 */ + -3685, /* k2g1[13] = -0.11247151828678581 */ + -3381, /* k2g1[14] = -0.10316741714122014 */ + -3101, /* k2g1[15] = -0.0946329890599603 */ + -2844, /* k2g1[16] = -0.08680456355870586 */ + -2609, /* k2g1[17] = -0.07962373723441349 */ + -2393, /* k2g1[18] = -0.07303693805092666 */ + -2195, /* k2g1[19] = -0.06699502566866912 */ + -2014, /* k2g1[20] = -0.06145292483669077 */ + -1847, /* k2g1[21] = -0.056369289112013346 */ + -1694, /* k2g1[22] = -0.05170619239747895 */ + -1554, /* k2g1[23] = -0.04742884599684141 */ + -1426, /* k2g1[24] = -0.043505339076210514 */ + -1308, /* k2g1[25] = -0.03990640059558053 */ + -1199, /* k2g1[26] = -0.03660518093435039 */ + -1100, /* k2g1[27] = -0.03357705158166837 */ + -1009, /* k2g1[28] = -0.030799421397205727 */ + -926, /* k2g1[29] = -0.028251568071585884 */ + -849 /* k2g1[30] = -0.025914483529091967 */ +}; + +static const EAS_I16 k2g2[] = +{ + 1957, /* k2g2[0] = 0.059711106626580836 */ + 1646, /* k2g2[1] = 0.05024063501786333 */ + 1385, /* k2g2[2] = 0.042272226217199664 */ + 1165, /* k2g2[3] = 0.03556764576567844 */ + 981, /* k2g2[4] = 0.029926444346999134 */ + 825, /* k2g2[5] = 0.025179964880280382 */ + 694, /* k2g2[6] = 0.02118630011706455 */ + 584, /* k2g2[7] = 0.01782604998793514 */ + 491, /* k2g2[8] = 0.014998751854573014 */ + 414, /* k2g2[9] = 0.012619876941179595 */ + 348, /* k2g2[10] = 0.010618303146468736 */ + 293, /* k2g2[11] = 0.008934188679954682 */ + 246, /* k2g2[12] = 0.007517182949855368 */ + 207, /* k2g2[13] = 0.006324921212866403 */ + 174, /* k2g2[14] = 0.005321757979794424 */ + 147, /* k2g2[15] = 0.004477701309210577 */ + 123, /* k2g2[16] = 0.00376751612730811 */ + 104, /* k2g2[17] = 0.0031699697655869644 */ + 87, /* k2g2[18] = 0.00266719715992703 */ + 74, /* k2g2[19] = 0.0022441667321724647 */ + 62, /* k2g2[20] = 0.0018882309854916855 */ + 52, /* k2g2[21] = 0.0015887483774966232 */ + 44, /* k2g2[22] = 0.0013367651661223448 */ + 37, /* k2g2[23] = 0.0011247477162958733 */ + 31, /* k2g2[24] = 0.0009463572640678758 */ + 26, /* k2g2[25] = 0.0007962604042473498 */ + 22, /* k2g2[26] = 0.0006699696356181593 */ + 18, /* k2g2[27] = 0.0005637091964589207 */ + 16, /* k2g2[28] = 0.00047430217920125243 */ + 13, /* k2g2[29] = 0.00039907554925166274 */ + 11 /* k2g2[30] = 0.00033578022828973666 */ +}; + +static const EAS_I16 n1g2[] = +{ + 3170, /* n1g2[0] = 0.0967319927350769 */ + 3036, /* n1g2[1] = 0.0926446051254155 */ + 2908, /* n1g2[2] = 0.08872992911818503 */ + 2785, /* n1g2[3] = 0.08498066682523227 */ + 2667, /* n1g2[4] = 0.08138982872895201 */ + 2554, /* n1g2[5] = 0.07795072065216213 */ + 2446, /* n1g2[6] = 0.0746569312785634 */ + 2343, /* n1g2[7] = 0.07150232020051943 */ + 2244, /* n1g2[8] = 0.06848100647187474 */ + 2149, /* n1g2[9] = 0.06558735764447099 */ + 2058, /* n1g2[10] = 0.06281597926792246 */ + 1971, /* n1g2[11] = 0.06016170483307614 */ + 1888, /* n1g2[12] = 0.05761958614040857 */ + 1808, /* n1g2[13] = 0.05518488407540374 */ + 1732, /* n1g2[14] = 0.052853059773715245 */ + 1659, /* n1g2[15] = 0.05061976615964251 */ + 1589, /* n1g2[16] = 0.04848083984214659 */ + 1521, /* n1g2[17] = 0.046432293353298 */ + 1457, /* n1g2[18] = 0.04447030771468711 */ + 1396, /* n1g2[19] = 0.04259122531793907 */ + 1337, /* n1g2[20] = 0.040791543106060944 */ + 1280, /* n1g2[21] = 0.03906790604290942 */ + 1226, /* n1g2[22] = 0.037417100858604564 */ + 1174, /* n1g2[23] = 0.035836050059229754 */ + 1125, /* n1g2[24] = 0.03432180618965023 */ + 1077, /* n1g2[25] = 0.03287154633875494 */ + 1032, /* n1g2[26] = 0.03148256687687814 */ + 988, /* n1g2[27] = 0.030152278415589925 */ + 946, /* n1g2[28] = 0.028878200980459685 */ + 906, /* n1g2[29] = 0.02765795938779331 */ + 868 /* n1g2[30] = 0.02648927881672521 */ +}; + +static const EAS_I16 n1g3[] = +{ + -548, /* n1g3[0] = -0.016714088475899017 */ + -481, /* n1g3[1] = -0.014683605122742116 */ + -423, /* n1g3[2] = -0.012899791676436092 */ + -371, /* n1g3[3] = -0.01133268185193299 */ + -326, /* n1g3[4] = -0.00995594976868754 */ + -287, /* n1g3[5] = -0.008746467702146129 */ + -252, /* n1g3[6] = -0.00768391756106361 */ + -221, /* n1g3[7] = -0.006750449563854721 */ + -194, /* n1g3[8] = -0.005930382380083576 */ + -171, /* n1g3[9] = -0.005209939699767622 */ + -150, /* n1g3[10] = -0.004577018805123356 */ + -132, /* n1g3[11] = -0.004020987256990177 */ + -116, /* n1g3[12] = -0.003532504280467257 */ + -102, /* n1g3[13] = -0.00310336384922047 */ + -89, /* n1g3[14] = -0.002726356832432369 */ + -78, /* n1g3[15] = -0.002395149888601605 */ + -69, /* n1g3[16] = -0.0021041790717285314 */ + -61, /* n1g3[17] = -0.0018485563625771063 */ + -53, /* n1g3[18] = -0.001623987554831628 */ + -47, /* n1g3[19] = -0.0014267001167177025 */ + -41, /* n1g3[20] = -0.0012533798162347005 */ + -36, /* n1g3[21] = -0.0011011150453668693 */ + -32, /* n1g3[22] = -0.0009673479079754438 */ + -28, /* n1g3[23] = -0.0008498312496971563 */ + -24, /* n1g3[24] = -0.0007465909079943587 */ + -21, /* n1g3[25] = -0.0006558925481952733 */ + -19, /* n1g3[26] = -0.0005762125284029567 */ + -17, /* n1g3[27] = -0.0005062123038325457 */ + -15, /* n1g3[28] = -0.0004447159405951901 */ + -13, /* n1g3[29] = -0.00039069036118270117 */ + -11 /* n1g3[30] = -0.00034322798979677605 */ +}; + +/*---------------------------------------------------------------------------- + * WT_SetFilterCoeffs() + *---------------------------------------------------------------------------- + * Purpose: + * Update the Filter parameters + * + * Inputs: + * pVoice - ptr to the voice whose filter we want to update + * pEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * - updates Filter values for the given voice + *---------------------------------------------------------------------------- +*/ +void WT_SetFilterCoeffs (S_WT_INT_FRAME *pIntFrame, EAS_I32 cutoff, EAS_I32 resonance) +{ + EAS_I32 temp; + + /* + Convert the cutoff, which has had A5 subtracted, using the 2^x approx + Note, this cutoff is related to theta cutoff by + theta = k * 2^x + We use 2^x and incorporate k in the power series coefs instead + */ + cutoff = EAS_Calculate2toX(cutoff); + + /* calculate b2 coef */ + temp = k2g1[resonance] + MULT_AUDIO_COEF(cutoff, k2g2[resonance]); + temp = k2g0 + MULT_AUDIO_COEF(cutoff, temp); + pIntFrame->frame.b2 = temp; + + /* calculate b1 coef */ + temp = MULT_AUDIO_COEF(cutoff, nk1g2); + temp = nk1g0 + MULT_AUDIO_COEF(cutoff, temp); + temp += MULT_AUDIO_COEF(temp, pIntFrame->frame.b2); + pIntFrame->frame.b1 = temp >> 1; + + /* calculate K coef */ + temp = n1g2[resonance] + MULT_AUDIO_COEF(cutoff, n1g3[resonance]); + temp = MULT_AUDIO_COEF(cutoff, temp); + temp = MULT_AUDIO_COEF(cutoff, temp); + pIntFrame->frame.k = temp; +} +#endif + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_wtsynth.h b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_wtsynth.h new file mode 100755 index 0000000..90a7ad8 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/eas_wtsynth.h @@ -0,0 +1,66 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_wtsynth.h + * + * Contents and purpose: + * This file defines the interface for synthesizer engine + * + * Copyright Sonic Network Inc. 2004 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_WTSYNTH_H +#define _EAS_WTSYNTH_H + +#include "eas_sndlib.h" +#include "eas_wtengine.h" + +/* adjust the filter cutoff frequency to the sample rate */ +#if defined (_SAMPLE_RATE_8000) +#define FILTER_CUTOFF_FREQ_ADJUST 0 +#elif defined (_SAMPLE_RATE_16000) +#define FILTER_CUTOFF_FREQ_ADJUST 1200 +#elif defined (_SAMPLE_RATE_20000) +#define FILTER_CUTOFF_FREQ_ADJUST 1586 +#elif defined (_SAMPLE_RATE_22050) +#define FILTER_CUTOFF_FREQ_ADJUST 1756 +#elif defined (_SAMPLE_RATE_24000) +#define FILTER_CUTOFF_FREQ_ADJUST 1902 +#elif defined (_SAMPLE_RATE_32000) +#define FILTER_CUTOFF_FREQ_ADJUST 2400 +#elif defined (_SAMPLE_RATE_44100) +#define FILTER_CUTOFF_FREQ_ADJUST 2956 +#elif defined (_SAMPLE_RATE_48000) +#define FILTER_CUTOFF_FREQ_ADJUST 3102 +#else +#error "_SAMPLE_RATE_XXXXX must be defined to valid rate" +#endif + +/* function prototypes */ +void WT_UpdateLFO (S_LFO_CONTROL *pLFO, EAS_I16 phaseInc); + +#if defined(_FILTER_ENABLED) || defined(DLS_SYNTHESIZER) +void WT_SetFilterCoeffs (S_WT_INT_FRAME *pIntFrame, EAS_I32 cutoff, EAS_I32 resonance); +#endif + +#endif + + diff --git a/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/hybrid_22khz_mcu.c b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/hybrid_22khz_mcu.c new file mode 100755 index 0000000..1d6816b --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-hybrid-22k/lib_src/hybrid_22khz_mcu.c @@ -0,0 +1,5149 @@ +/*---------------------------------------------------------------------------- + * + * Filename: C:\Sonic\Trunk\EASLib\WTLibrary\hybrid_22khz_mcu.c + * Source: C:\Sonic\Trunk\Wavetables\Sonic_20Khz_Drums.dls + * CmdLine: -w C:\Sonic\Trunk\EASLib\WTLibrary\hybrid_22khz_mcu.c -l C:\Sonic\Trunk\EASLib\WTLibrary\hybrid_22khz.log -d 0 -c -f C:\Sonic\Release3-5\EASLib\FMSynth\GMdblib-3.fml C:\Sonic\Trunk\Wavetables\Sonic_20Khz_Drums.dls -w -l -d -c -f C:\Sonic\Trunk\Wavetables\Sonic_20Khz_Drums.dls + * Purpose: Wavetable sound libary + * + * Copyright (c) 2006 Sonic Network Inc. + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision:$ + * $Date:$ + *---------------------------------------------------------------------------- +*/ + +#include "eas_sndlib.h" + +/*---------------------------------------------------------------------------- + * Articulations + *---------------------------------------------------------------------------- +*/ +const S_ARTICULATION eas_articulations[] = +{ + { /* articulation 0 */ + { 32767, 30725, 0, 30725 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 1 */ + { 32767, 26863, 0, 26863 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 2 */ + { 32767, 30484, 0, 30668 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 3 */ + { 32767, 26439, 0, 26439 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 4 */ + { 32767, 0, 32767, 32715 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 5 */ + { 32767, 21333, 0, 21333 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 6 */ + { 32767, 31882, 0, 31938 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 7 */ + { 32767, 32663, 32767, 32663 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 8 */ + { 32767, 0, 32767, 0 }, + { 32767, 1902, 0, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 9 */ + { 32767, 32349, 0, 32349 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 10 */ + { 32767, 0, 32767, 17213 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -1 + }, + { /* articulation 11 */ + { 32767, 32072, 0, 32072 }, + { 32767, 761, 0, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -56 + }, + { /* articulation 12 */ + { 32767, 23749, 0, 23749 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 56 + }, + { /* articulation 13 */ + { 32767, 32010, 0, 32010 }, + { 32767, 761, 0, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -31 + }, + { /* articulation 14 */ + { 9511, 21333, 0, 21333 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 56 + }, + { /* articulation 15 */ + { 32767, 31844, 0, 31844 }, + { 32767, 761, 0, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -6 + }, + { /* articulation 16 */ + { 32767, 32123, 0, 32194 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 56 + }, + { /* articulation 17 */ + { 32767, 31730, 0, 31730 }, + { 32767, 761, 0, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 6 + }, + { /* articulation 18 */ + { 32767, 31391, 0, 31391 }, + { 32767, 951, 0, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 31 + }, + { /* articulation 19 */ + { 32767, 31964, 0, 31964 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 25 + }, + { /* articulation 20 */ + { 32767, 31056, 0, 31056 }, + { 32767, 951, 0, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 63 + }, + { /* articulation 21 */ + { 32767, 32289, 0, 32271 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -37 + }, + { /* articulation 22 */ + { 19021, 31882, 0, 31911 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -37 + }, + { /* articulation 23 */ + { 32767, 31988, 0, 32032 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -37 + }, + { /* articulation 24 */ + { 32767, 0, 32767, 32663 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 12 + }, + { /* articulation 25 */ + { 32767, 31352, 0, 31352 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -25 + }, + { /* articulation 26 */ + { 32767, 0, 32767, 32663 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 25 + }, + { /* articulation 27 */ + { 32767, 31817, 0, 31781 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -25 + }, + { /* articulation 28 */ + { 32767, 30725, 0, 30725 }, + { 32767, 95, 0, 0 }, + 0, 0, 951, 240, 0, 0, 0, 0, -56 + }, + { /* articulation 29 */ + { 32767, 32230, 0, 32218 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -37 + }, + { /* articulation 30 */ + { 32767, 26439, 0, 26439 }, + { 32767, 3804, 0, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 50 + }, + { /* articulation 31 */ + { 32767, 23749, 0, 23749 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -50 + }, + { /* articulation 32 */ + { 32767, 29434, 0, 29434 }, + { 32767, 3804, 0, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -50 + }, + { /* articulation 33 */ + { 32767, 30240, 0, 30234 }, + { 32767, 3804, 0, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -44 + }, + { /* articulation 34 */ + { 32767, 32558, 0, 32558 }, + { 32767, 254, 0, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 25 + }, + { /* articulation 35 */ + { 32767, 0, 32767, 32663 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -63 + }, + { /* articulation 36 */ + { 3804, 23749, 0, 23749 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -63 + }, + { /* articulation 37 */ + { 32767, 23749, 0, 23749 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -59 + }, + { /* articulation 38 */ + { 32767, 30725, 0, 30725 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 50 + }, + { /* articulation 39 */ + { 32767, 28809, 0, 28809 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 44 + }, + { /* articulation 40 */ + { 1902, 30725, 0, 30725 }, + { 32767, 380, 0, 0 }, + 0, 0, 951, -100, 0, 0, 0, 0, 44 + }, + { /* articulation 41 */ + { 32767, 9042, 0, 9042 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 25 + }, + { /* articulation 42 */ + { 32767, 29889, 0, 29889 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 63 + }, + { /* articulation 43 */ + { 32767, 30240, 0, 30234 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 63 + }, + { /* articulation 44 */ + { 19021, 19970, 0, 19970 }, + { 951, 32767, 32767, 0 }, + 0, 0, 951, 100, 0, 0, 0, 0, -25 + }, + { /* articulation 45 */ + { 3804, 17213, 0, 17213 }, + { 951, 32767, 32767, 0 }, + 0, 0, 951, 500, 0, 0, 0, 0, -25 + }, + { /* articulation 46 */ + { 32767, 17213, 0, 17213 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -56 + }, + { /* articulation 47 */ + { 32767, 30725, 0, 30725 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -56 + }, + { /* articulation 48 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 49 */ + { 32767, 31180, 0, 31180 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 50 */ + { 19021, 31964, 0, 32071 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 51 */ + { 32767, 29669, 0, 29669 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 52 */ + { 32767, 31742, 0, 31352 }, + { 32767, 294, 0, 0 }, + 0, 0, 951, 0, 10000, 7121, 0, 0, 0 + } +}; /*end Articulations */ + +/*---------------------------------------------------------------------------- + * Regions + *---------------------------------------------------------------------------- +*/ +const S_WT_REGION eas_regions[] = +{ + { { 0, 27, 27 }, -2868, 16422, 0, 0, 19, 0 }, /* region 0 */ + { { 0, 28, 28 }, -3568, 32767, 0, 0, 13, 0 }, /* region 1 */ + { { 0, 29, 29 }, -4553, 32767, 0, 0, 9, 1 }, /* region 2 */ + { { 0, 30, 30 }, -4853, 32767, 0, 0, 9, 2 }, /* region 3 */ + { { 0, 31, 31 }, -3868, 23197, 0, 0, 15, 3 }, /* region 4 */ + { { 1536, 32, 32 }, -3368, 20675, 0, 0, 29, 4 }, /* region 5 */ + { { 1537, 33, 33 }, -3868, 20675, 792, 800, 17, 5 }, /* region 6 */ + { { 1537, 34, 34 }, -3968, 16422, 792, 800, 17, 6 }, /* region 7 */ + { { 0, 35, 35 }, -4968, 32767, 0, 0, 20, 7 }, /* region 8 */ + { { 0, 36, 36 }, -4968, 32767, 0, 0, 20, 7 }, /* region 9 */ + { { 0, 37, 37 }, -4051, 18426, 0, 0, 16, 8 }, /* region 10 */ + { { 0, 38, 38 }, -4151, 23197, 0, 0, 5, 9 }, /* region 11 */ + { { 0, 39, 39 }, -4668, 23197, 0, 0, 12, 10 }, /* region 12 */ + { { 0, 40, 40 }, -4151, 23197, 0, 0, 5, 4 }, /* region 13 */ + { { 1, 41, 41 }, -5855, 26028, 798, 993, 14, 11 }, /* region 14 */ + { { 257, 42, 42 }, -4368, 26028, 4288, 6792, 2, 12 }, /* region 15 */ + { { 1, 43, 43 }, -5755, 26028, 798, 993, 14, 13 }, /* region 16 */ + { { 257, 44, 44 }, -4568, 26028, 4288, 6792, 2, 14 }, /* region 17 */ + { { 1, 45, 45 }, -5755, 26028, 798, 993, 14, 15 }, /* region 18 */ + { { 257, 46, 46 }, -4768, 26028, 4288, 6792, 2, 16 }, /* region 19 */ + { { 1, 47, 47 }, -5455, 26028, 798, 993, 14, 17 }, /* region 20 */ + { { 1, 48, 48 }, -5355, 26028, 798, 993, 14, 18 }, /* region 21 */ + { { 1, 49, 49 }, -5368, 16422, 1294, 5241, 3, 19 }, /* region 22 */ + { { 1, 50, 50 }, -5255, 26028, 798, 993, 14, 20 }, /* region 23 */ + { { 1, 51, 51 }, -5268, 16422, 6592, 9921, 0, 21 }, /* region 24 */ + { { 1, 52, 52 }, -5768, 32767, 1294, 5241, 3, 22 }, /* region 25 */ + { { 1, 53, 53 }, -5418, 14636, 6592, 9921, 0, 23 }, /* region 26 */ + { { 0, 54, 54 }, -5751, 26028, 0, 0, 11, 24 }, /* region 27 */ + { { 1, 55, 55 }, -5468, 32767, 1294, 5241, 3, 25 }, /* region 28 */ + { { 0, 56, 56 }, -7255, 32767, 0, 0, 24, 26 }, /* region 29 */ + { { 1, 57, 57 }, -5868, 32767, 1294, 5241, 3, 27 }, /* region 30 */ + { { 1, 58, 58 }, -7053, 23197, 0, 166, 26, 28 }, /* region 31 */ + { { 1, 59, 59 }, -5968, 16422, 6592, 9921, 0, 29 }, /* region 32 */ + { { 1, 60, 60 }, -6453, 23197, 432, 582, 18, 30 }, /* region 33 */ + { { 1, 61, 61 }, -6853, 16422, 432, 582, 18, 30 }, /* region 34 */ + { { 1, 62, 62 }, -7253, 20675, 432, 582, 18, 31 }, /* region 35 */ + { { 1, 63, 63 }, -7353, 23197, 432, 582, 18, 32 }, /* region 36 */ + { { 1, 64, 64 }, -7953, 23197, 432, 582, 18, 33 }, /* region 37 */ + { { 0, 65, 65 }, -7555, 32767, 0, 0, 4, 34 }, /* region 38 */ + { { 0, 66, 66 }, -7955, 20675, 0, 0, 4, 34 }, /* region 39 */ + { { 512, 67, 67 }, -7155, 18426, 0, 0, 24, 35 }, /* region 40 */ + { { 512, 68, 68 }, -7755, 18426, 0, 0, 24, 35 }, /* region 41 */ + { { 0, 69, 69 }, -7755, 32767, 0, 0, 21, 36 }, /* region 42 */ + { { 0, 70, 70 }, -6855, 21900, 0, 0, 21, 37 }, /* region 43 */ + { { 769, 71, 71 }, -6355, 23197, 0, 1226, 10, 38 }, /* region 44 */ + { { 769, 72, 72 }, -6955, 26028, 0, 1226, 10, 38 }, /* region 45 */ + { { 1024, 73, 73 }, -7955, 32767, 0, 0, 7, 39 }, /* region 46 */ + { { 1024, 74, 74 }, -8455, 32767, 0, 0, 7, 40 }, /* region 47 */ + { { 1, 75, 75 }, -8068, 23197, 0, 29, 30, 41 }, /* region 48 */ + { { 0, 76, 76 }, -10455, 23197, 0, 0, 28, 42 }, /* region 49 */ + { { 0, 77, 77 }, -10055, 23197, 0, 0, 28, 43 }, /* region 50 */ + { { 0, 78, 78 }, -8853, 16422, 0, 0, 23, 44 }, /* region 51 */ + { { 0, 79, 79 }, -10253, 16422, 0, 0, 23, 45 }, /* region 52 */ + { { 1280, 80, 80 }, -6468, 13045, 0, 0, 25, 46 }, /* region 53 */ + { { 1280, 81, 81 }, -6568, 16422, 0, 0, 25, 47 }, /* region 54 */ + { { 0, 82, 82 }, -8455, 20675, 0, 0, 22, 48 }, /* region 55 */ + { { 0, 83, 83 }, -9068, 32767, 0, 0, 6, 49 }, /* region 56 */ + { { 1, 84, 84 }, -8568, 23197, 0, 9337, 1, 50 }, /* region 57 */ + { { 0, 85, 85 }, -9655, 32767, 0, 0, 27, 0 }, /* region 58 */ + { { 0, 86, 86 }, -9068, 16422, 0, 0, 8, 51 }, /* region 59 */ + { { 32769, 87, 87 }, -9168, 32767, 1335, 1603, 8, 52 } /* region 60 */ +}; /* end Regions */ + +/*---------------------------------------------------------------------------- + * FM Regions + *---------------------------------------------------------------------------- +*/ +const S_FM_REGION eas_fmRegions[] = +{ + + { /* FM region 0 */ + { 37, 0, 127 }, 0, 255, 8, 0, + { + { 514, 239, 47, 97, 0, 184, 3 }, + { 1, 244, 89, 114, 0, 248, 2 }, + { 3370, 244, 49, 76, 40, 192, 2 }, + { -1, 227, 97, 51, 160, 212, 2 } + } + }, + { /* FM region 1 */ + { 37, 0, 127 }, 160, 255, 8, 0, + { + { 2514, 223, 95, 72, 0, 176, 3 }, + { 1, 244, 73, 145, 0, 244, 2 }, + { 3600, 245, 81, 198, 40, 192, 2 }, + { 3, 246, 81, 163, 108, 212, 2 } + } + }, + { /* FM region 2 */ + { 37, 0, 127 }, 160, 255, 119, 0, + { + { 0, 216, 79, 72, 0, 216, 2 }, + { 2, 244, 73, 145, 0, 244, 2 }, + { 3370, 247, 33, 182, 60, 204, 2 }, + { 1200, 246, 65, 163, 108, 204, 2 } + } + }, + { /* FM region 3 */ + { 37, 0, 127 }, 160, 255, 1, 0, + { + { 3369, 248, 65, 71, 40, 208, 2 }, + { -3, 245, 88, 113, 0, 244, 2 }, + { 2784, 225, 65, 133, 80, 192, 2 }, + { 3, 241, 81, 113, 80, 216, 2 } + } + }, + { /* FM region 4 */ + { 34, 0, 127 }, 0, 255, 128, 0, + { + { 0, 229, 155, 183, 0, 228, 2 }, + { -3, 243, 90, 81, 0, 244, 2 }, + { 4800, 248, 109, 180, 36, 192, 2 }, + { 3, 245, 90, 85, 16, 244, 2 } + } + }, + { /* FM region 5 */ + { 34, 0, 127 }, 9, 96, 192, 0, + { + { 1200, 229, 157, 180, 0, 216, 2 }, + { -3, 244, 90, 81, 0, 244, 2 }, + { 1902, 255, 111, 182, 80, 208, 2 }, + { 3, 246, 92, 83, 0, 244, 2 } + } + }, + { /* FM region 6 */ + { 34, 0, 127 }, 0, 255, 154, 0, + { + { 3102, 244, 63, 102, 228, 228, 2 }, + { 1200, 247, 93, 97, 0, 236, 2 }, + { 1902, 255, 63, 98, 156, 220, 2 }, + { 1200, 244, 92, 98, 0, 236, 2 } + } + }, + { /* FM region 7 */ + { 37, 0, 127 }, 0, 255, 202, 0, + { + { 0, 251, 131, 19, 216, 220, 2 }, + { 1201, 247, 62, 113, 0, 240, 2 }, + { 0, 243, 154, 36, 240, 224, 2 }, + { 2784, 250, 61, 36, 240, 208, 2 } + } + }, + { /* FM region 8 */ + { 33, 0, 127 }, 0, 255, 80, 0, + { + { -1, 213, 191, 183, 0, 204, 2 }, + { 1, 245, 154, 129, 0, 244, 2 }, + { 3831, 252, 159, 100, 0, 200, 2 }, + { 1197, 246, 91, 182, 0, 244, 2 } + } + }, + { /* FM region 9 */ + { 34, 0, 127 }, 48, 80, 21, 0, + { + { 2982, 255, 43, 96, 0, 196, 3 }, + { 3, 247, 71, 130, 0, 244, 2 }, + { 3358, 253, 40, 98, 144, 208, 2 }, + { -2, 246, 70, 130, 0, 236, 2 } + } + }, + { /* FM region 10 */ + { 34, 0, 127 }, 48, 80, 26, 0, + { + { 3096, 249, 72, 100, 0, 208, 2 }, + { 2185, 249, 102, 130, 0, 240, 2 }, + { 3386, 247, 66, 100, 144, 212, 2 }, + { -2, 247, 102, 130, 0, 240, 2 } + } + }, + { /* FM region 11 */ + { 34, 0, 127 }, 92, 67, 21, 0, + { + { 2982, 255, 27, 146, 0, 200, 3 }, + { 3, 246, 68, 146, 0, 240, 2 }, + { 3358, 250, 149, 116, 144, 208, 2 }, + { -3, 245, 68, 146, 0, 240, 0 } + } + }, + { /* FM region 12 */ + { 34, 0, 127 }, 0, 67, 0, 0, + { + { 1500, 239, 60, 151, 0, 220, 2 }, + { 0, 247, 76, 146, 0, 240, 2 }, + { 2398, 234, 156, 151, 0, 212, 2 }, + { 0, 246, 105, 146, 0, 244, 2 } + } + }, + { /* FM region 13 */ + { 34, 0, 127 }, 0, 67, 0, 0, + { + { 2500, 255, 60, 151, 0, 220, 2 }, + { 0, 249, 92, 146, 0, 244, 2 }, + { 3369, 250, 156, 151, 0, 196, 2 }, + { 0, 248, 89, 146, 0, 244, 2 } + } + }, + { /* FM region 14 */ + { 37, 0, 127 }, 160, 255, 0, 0, + { + { 2300, 229, 112, 49, 0, 208, 2 }, + { -3, 247, 67, 50, 0, 248, 2 }, + { 1074, 255, 41, 49, 0, 196, 2 }, + { 686, 240, 97, 18, 0, 196, 2 } + } + }, + { /* FM region 15 */ + { 37, 0, 127 }, 160, 255, 219, 0, + { + { 3369, 255, 65, 70, 40, 216, 2 }, + { 1, 246, 72, 113, 0, 240, 2 }, + { 1902, 225, 33, 129, 80, 204, 2 }, + { 2400, 225, 97, 113, 80, 200, 2 } + } + }, + { /* FM region 16 */ + { 35, 0, 127 }, 32, 48, 151, 0, + { + { 1201, 215, 35, 66, 252, 208, 0 }, + { -9581, 254, 63, 177, 240, 240, 3 }, + { 1902, 248, 47, 64, 112, 244, 2 }, + { 0, 247, 35, 66, 208, 212, 2 } + } + }, + { /* FM region 17 */ + { 33, 0, 127 }, 0, 255, 153, 0, + { + { 1, 252, 31, 3, 244, 196, 2 }, + { -1, 208, 31, 4, 248, 244, 2 }, + { 1205, 209, 31, 4, 248, 236, 2 }, + { 1899, 250, 31, 32, 0, 240, 2 } + } + }, + { /* FM region 18 */ + { 34, 0, 127 }, 32, 49, 201, 0, + { + { 1, 220, 47, 3, 244, 220, 0 }, + { -10000, 208, 63, 1, 248, 240, 3 }, + { 1586, 255, 47, 3, 188, 216, 2 }, + { -1, 202, 63, 32, 80, 232, 2 } + } + }, + { /* FM region 19 */ + { 33, 0, 127 }, 0, 143, 29, 0, + { + { -1200, 223, 64, 0, 252, 216, 2 }, + { 1200, 96, 41, 35, 248, 240, 2 }, + { 1200, 143, 41, 64, 252, 224, 2 }, + { 3102, 161, 41, 96, 248, 216, 2 } + } + }, + { /* FM region 20 */ + { 34, 0, 127 }, 0, 143, 34, 0, + { + { -1200, 133, 79, 1, 252, 212, 2 }, + { 1201, 112, 46, 34, 248, 232, 2 }, + { 0, 116, 79, 65, 252, 200, 2 }, + { 1900, 161, 46, 98, 248, 232, 2 } + } + }, + { /* FM region 21 */ + { 34, 0, 127 }, 0, 143, 187, 0, + { + { 1202, 80, 74, 1, 252, 216, 2 }, + { 2402, 112, 46, 34, 248, 232, 2 }, + { 0, 99, 78, 97, 184, 216, 2 }, + { 1899, 81, 46, 98, 236, 232, 2 } + } + }, + { /* FM region 22 */ + { 37, 0, 127 }, 22, 141, 34, 0, + { + { 2787, 176, 79, 4, 252, 208, 2 }, + { 2785, 144, 45, 34, 248, 236, 2 }, + { 3369, 83, 77, 100, 184, 172, 2 }, + { 1902, 102, 45, 100, 172, 212, 0 } + } + }, + { /* FM region 23 */ + { 34, 0, 127 }, 0, 143, 135, 0, + { + { 1900, 112, 79, 3, 252, 220, 2 }, + { 2400, 128, 45, 34, 248, 232, 2 }, + { 1200, 115, 77, 98, 184, 220, 2 }, + { 1904, 97, 45, 98, 236, 232, 2 } + } + }, + { /* FM region 24 */ + { 37, 0, 127 }, 0, 255, 157, 0, + { + { 1200, 244, 54, 4, 20, 200, 2 }, + { 0, 245, 92, 130, 0, 244, 2 }, + { 3802, 247, 68, 21, 0, 196, 2 }, + { 1, 245, 43, 114, 0, 204, 2 } + } + }, + { /* FM region 25 */ + { 37, 0, 127 }, 0, 128, 83, 0, + { + { 0, 244, 51, 4, 200, 204, 0 }, + { 0, 247, 108, 129, 0, 248, 0 }, + { 2786, 243, 31, 70, 200, 220, 0 }, + { 1902, 246, 44, 113, 12, 188, 0 } + } + }, + { /* FM region 26 */ + { 37, 0, 127 }, 0, 128, 61, 0, + { + { 0, 246, 51, 97, 76, 204, 0 }, + { 0, 244, 60, 97, 0, 240, 0 }, + { 1786, 255, 31, 64, 0, 180, 0 }, + { 1200, 247, 60, 97, 12, 204, 0 } + } + }, + { /* FM region 27 */ + { 37, 0, 127 }, 0, 128, 153, 0, + { + { -2, 243, 53, 99, 96, 200, 0 }, + { 0, 243, 60, 97, 0, 240, 0 }, + { 3983, 247, 63, 100, 24, 204, 0 }, + { 2, 242, 53, 99, 52, 212, 0 } + } + }, + { /* FM region 28 */ + { 37, 0, 127 }, 0, 128, 205, 0, + { + { -2, 244, 47, 97, 20, 208, 0 }, + { 0, 252, 75, 193, 0, 248, 0 }, + { 0, 254, 63, 98, 132, 224, 0 }, + { 2786, 251, 63, 98, 52, 192, 0 } + } + }, + { /* FM region 29 */ + { 37, 0, 127 }, 0, 128, 221, 0, + { + { -1, 208, 191, 99, 220, 224, 0 }, + { 1200, 243, 92, 97, 0, 244, 0 }, + { 3984, 212, 11, 96, 168, 196, 0 }, + { 1, 242, 127, 98, 108, 204, 0 } + } + }, + { /* FM region 30 */ + { 37, 0, 127 }, 0, 128, 174, 0, + { + { -3, 212, 207, 99, 0, 228, 0 }, + { 1902, 241, 108, 97, 0, 248, 0 }, + { 3805, 212, 59, 98, 0, 220, 0 }, + { 1902, 146, 107, 98, 144, 196, 0 } + } + }, + { /* FM region 31 */ + { 41, 0, 127 }, 0, 255, 128, 0, + { + { 1206, 239, 43, 69, 0, 216, 2 }, + { 4, 254, 42, 66, 0, 244, 2 }, + { 702, 88, 55, 66, 0, 204, 2 }, + { -4, 71, 55, 66, 0, 240, 2 } + } + }, + { /* FM region 32 */ + { 37, 0, 127 }, 0, 255, 85, 0, + { + { 500, 239, 95, 82, 0, 184, 3 }, + { 0, 248, 73, 132, 0, 252, 2 }, + { 2786, 203, 59, 130, 0, 176, 2 }, + { 0, 216, 42, 100, 0, 208, 2 } + } + }, + { /* FM region 33 */ + { 37, 0, 127 }, 0, 128, 73, 0, + { + { 1, 229, 54, 131, 160, 208, 0 }, + { -1, 244, 62, 97, 0, 248, 0 }, + { 3986, 227, 127, 69, 140, 184, 0 }, + { 1201, 249, 92, 114, 0, 204, 0 } + } + }, + { /* FM region 34 */ + { 37, 0, 127 }, 0, 128, 73, 0, + { + { 1, 225, 54, 100, 200, 212, 0 }, + { -1, 244, 94, 97, 0, 248, 0 }, + { 3986, 249, 127, 88, 112, 188, 0 }, + { 1201, 249, 92, 85, 52, 208, 0 } + } + }, + { /* FM region 35 */ + { 37, 0, 127 }, 0, 128, 188, 0, + { + { -3, 198, 92, 179, 28, 212, 0 }, + { 0, 243, 90, 145, 0, 248, 0 }, + { 1901, 215, 95, 69, 28, 196, 0 }, + { 3, 84, 108, 196, 32, 208, 0 } + } + }, + { /* FM region 36 */ + { 37, 0, 127 }, 0, 136, 6, 0, + { + { 0, 226, 99, 36, 224, 216, 0 }, + { 1902, 248, 78, 33, 0, 252, 0 }, + { 3369, 239, 250, 33, 0, 204, 0 }, + { 0, 230, 253, 33, 0, 208, 0 } + } + }, + { /* FM region 37 */ + { 37, 0, 127 }, 0, 136, 195, 0, + { + { 0, 245, 99, 36, 152, 208, 0 }, + { 1200, 248, 78, 33, 0, 252, 0 }, + { 3369, 246, 250, 33, 0, 216, 0 }, + { 0, 246, 61, 33, 0, 180, 0 } + } + }, + { /* FM region 38 */ + { 34, 0, 127 }, 0, 133, 221, 0, + { + { 1, 244, 67, 35, 80, 220, 0 }, + { 3, 246, 94, 33, 0, 244, 0 }, + { -1, 245, 70, 35, 80, 236, 2 }, + { -3, 246, 63, 33, 0, 236, 2 } + } + }, + { /* FM region 39 */ + { 34, 0, 127 }, 0, 133, 220, 0, + { + { 0, 114, 51, 34, 132, 208, 0 }, + { 3, 214, 62, 33, 0, 248, 0 }, + { 0, 85, 54, 34, 44, 224, 2 }, + { -3, 214, 63, 33, 0, 236, 2 } + } + }, + { /* FM region 40 */ + { 37, 0, 127 }, 48, 142, 187, 0, + { + { -1, 33, 22, 33, 200, 208, 0 }, + { 0, 81, 105, 33, 220, 240, 0 }, + { 2786, 245, 19, 50, 208, 192, 0 }, + { 1, 245, 21, 82, 200, 220, 0 } + } + }, + { /* FM region 41 */ + { 37, 0, 127 }, 48, 126, 103, 0, + { + { -1, 193, 22, 33, 228, 212, 0 }, + { 0, 81, 105, 33, 220, 244, 0 }, + { 0, 245, 19, 50, 216, 228, 0 }, + { 1200, 245, 19, 82, 200, 188, 0 } + } + }, + { /* FM region 42 */ + { 37, 0, 127 }, 16, 126, 202, 0, + { + { -1, 49, 24, 41, 200, 212, 0 }, + { 0, 81, 71, 49, 220, 244, 0 }, + { 3371, 243, 19, 36, 232, 192, 0 }, + { 1, 242, 24, 36, 220, 212, 0 } + } + }, + { /* FM region 43 */ + { 37, 0, 127 }, 16, 124, 205, 0, + { + { 0, 129, 24, 49, 208, 200, 0 }, + { 0, 67, 102, 81, 224, 244, 0 }, + { 3804, 246, 23, 36, 160, 196, 0 }, + { 1200, 244, 24, 35, 208, 200, 0 } + } + }, + { /* FM region 44 */ + { 37, 0, 127 }, 48, 144, 208, 0, + { + { -3, 209, 22, 33, 200, 204, 2 }, + { 0, 81, 89, 33, 220, 240, 2 }, + { -5000, 208, 6, 33, 244, 188, 3 }, + { 3, 97, 89, 33, 224, 200, 0 } + } + }, + { /* FM region 45 */ + { 37, 0, 127 }, 0, 255, 186, 0, + { + { 500, 223, 95, 0, 0, 192, 3 }, + { 0, 247, 89, 100, 0, 248, 2 }, + { 3369, 255, 59, 168, 0, 212, 2 }, + { 0, 216, 42, 97, 0, 212, 2 } + } + }, + { /* FM region 46 */ + { 34, 0, 127 }, 0, 255, 221, 0, + { + { 1206, 235, 70, 69, 0, 216, 2 }, + { 4, 248, 84, 66, 0, 244, 2 }, + { 1902, 247, 52, 137, 80, 216, 2 }, + { -4, 245, 84, 131, 0, 240, 2 } + } + }, + { /* FM region 47 */ + { 37, 0, 127 }, 0, 255, 105, 0, + { + { 387, 231, 115, 34, 4, 216, 2 }, + { 0, 248, 37, 65, 0, 252, 2 }, + { 3308, 248, 117, 34, 8, 200, 2 }, + { 1900, 213, 82, 50, 0, 192, 2 } + } + }, + { /* FM region 48 */ + { 34, 0, 127 }, 32, 160, 221, 0, + { + { -7, 209, 22, 33, 200, 204, 2 }, + { -7, 81, 73, 33, 220, 244, 0 }, + { 7, 209, 22, 33, 200, 208, 0 }, + { 7, 97, 73, 33, 224, 244, 2 } + } + }, + { /* FM region 49 */ + { 34, 0, 127 }, 64, 128, 189, 0, + { + { -2, 209, 54, 32, 224, 216, 2 }, + { -7726, 97, 105, 33, 220, 240, 3 }, + { 1902, 209, 54, 34, 216, 208, 0 }, + { 2, 81, 105, 33, 224, 236, 0 } + } + }, + { /* FM region 50 */ + { 34, 0, 127 }, 80, 144, 206, 0, + { + { -3, 179, 38, 33, 160, 220, 2 }, + { -7726, 81, 69, 34, 220, 244, 3 }, + { 3, 193, 38, 33, 240, 212, 0 }, + { -8000, 65, 69, 34, 224, 236, 3 } + } + }, + { /* FM region 51 */ + { 37, 0, 127 }, 96, 128, 204, 0, + { + { -3, 97, 38, 33, 180, 216, 0 }, + { 0, 81, 69, 34, 220, 240, 2 }, + { 3369, 145, 38, 33, 240, 196, 2 }, + { -13190, 65, 69, 34, 240, 200, 3 } + } + }, + { /* FM region 52 */ + { 34, 0, 127 }, 64, 128, 108, 0, + { + { -3, 193, 37, 35, 236, 208, 0 }, + { 2394, 97, 90, 36, 224, 232, 2 }, + { 3, 65, 40, 35, 236, 204, 2 }, + { 1203, 97, 89, 33, 224, 240, 0 } + } + }, + { /* FM region 53 */ + { 37, 0, 127 }, 128, 128, 122, 0, + { + { 0, 193, 21, 34, 236, 188, 0 }, + { 3, 97, 74, 36, 224, 248, 2 }, + { 1906, 251, 24, 32, 96, 192, 3 }, + { 1200, 97, 73, 32, 224, 184, 0 } + } + }, + { /* FM region 54 */ + { 34, 0, 127 }, 64, 133, 135, 0, + { + { 0, 194, 25, 35, 120, 200, 2 }, + { 0, 97, 75, 36, 224, 240, 0 }, + { 2906, 254, 28, 48, 0, 184, 3 }, + { 0, 216, 75, 80, 204, 240, 2 } + } + }, + { /* FM region 55 */ + { 41, 0, 127 }, 208, 64, 255, 0, + { + { 475, 249, 16, 32, 252, 240, 2 }, + { 702, 248, 71, 32, 0, 244, 2 }, + { 1136, 232, 27, 32, 216, 248, 0 }, + { 0, 249, 23, 48, 0, 248, 2 } + } + }, + { /* FM region 56 */ + { 37, 0, 127 }, 0, 132, 233, 0, + { + { 0, 195, 95, 64, 240, 208, 0 }, + { 0, 225, 94, 64, 248, 240, 0 }, + { 0, 254, 127, 0, 4, 196, 4 }, + { 1902, 228, 95, 1, 248, 200, 0 } + } + }, + { /* FM region 57 */ + { 37, 0, 127 }, 16, 140, 238, 0, + { + { 0, 163, 90, 67, 228, 208, 0 }, + { 0, 209, 77, 65, 248, 240, 0 }, + { 1969, 173, 58, 65, 0, 176, 0 }, + { 0, 210, 61, 52, 204, 220, 0 } + } + }, + { /* FM region 58 */ + { 37, 0, 127 }, 16, 140, 222, 0, + { + { 0, 119, 74, 67, 160, 212, 0 }, + { 0, 146, 61, 65, 248, 244, 0 }, + { 1900, 137, 58, 65, 100, 196, 0 }, + { 0, 119, 61, 52, 120, 200, 0 } + } + }, + { /* FM region 59 */ + { 37, 0, 127 }, 16, 135, 219, 0, + { + { 0, 176, 79, 69, 240, 216, 0 }, + { 0, 193, 79, 64, 248, 236, 0 }, + { 0, 178, 123, 54, 92, 228, 0 }, + { 3369, 212, 95, 38, 144, 212, 0 } + } + }, + { /* FM region 60 */ + { 34, 0, 127 }, 0, 119, 203, 0, + { + { 2, 65, 77, 66, 228, 204, 0 }, + { 2, 161, 74, 64, 240, 240, 0 }, + { -2, 85, 60, 66, 180, 216, 2 }, + { -2, 162, 74, 64, 220, 240, 2 } + } + }, + { /* FM region 61 */ + { 34, 0, 127 }, 16, 154, 237, 0, + { + { 0, 179, 42, 64, 216, 208, 0 }, + { 0, 209, 61, 64, 248, 244, 0 }, + { -1200, 226, 55, 65, 244, 220, 2 }, + { 1902, 162, 62, 52, 204, 236, 2 } + } + }, + { /* FM region 62 */ + { 34, 0, 127 }, 48, 119, 221, 0, + { + { 2, 119, 79, 64, 208, 212, 0 }, + { 2, 209, 110, 64, 248, 236, 0 }, + { -2, 84, 79, 64, 136, 212, 2 }, + { -2, 209, 110, 64, 240, 240, 2 } + } + }, + { /* FM region 63 */ + { 34, 0, 127 }, 32, 135, 221, 0, + { + { 2, 165, 79, 64, 152, 216, 0 }, + { 2, 225, 110, 64, 248, 236, 0 }, + { -2, 132, 79, 64, 72, 224, 2 }, + { -2, 241, 110, 64, 252, 236, 2 } + } + }, + { /* FM region 64 */ + { 37, 0, 127 }, 17, 127, 190, 0, + { + { 0, 209, 60, 67, 244, 208, 0 }, + { 1200, 145, 94, 65, 248, 244, 2 }, + { 3369, 197, 47, 4, 128, 192, 0 }, + { 1902, 167, 94, 6, 200, 200, 0 } + } + }, + { /* FM region 65 */ + { 37, 0, 127 }, 17, 143, 190, 0, + { + { 0, 209, 60, 67, 244, 216, 0 }, + { 1902, 145, 62, 65, 248, 240, 2 }, + { 3369, 197, 47, 4, 128, 196, 0 }, + { 2400, 167, 94, 6, 200, 212, 2 } + } + }, + { /* FM region 66 */ + { 37, 0, 127 }, 17, 143, 190, 0, + { + { 0, 209, 60, 67, 244, 208, 0 }, + { 1902, 145, 62, 65, 248, 240, 2 }, + { 3369, 197, 47, 4, 128, 192, 0 }, + { 1902, 167, 94, 6, 200, 216, 2 } + } + }, + { /* FM region 67 */ + { 37, 0, 127 }, 17, 125, 190, 0, + { + { 0, 114, 109, 67, 244, 224, 0 }, + { 1902, 166, 93, 97, 200, 240, 0 }, + { 2786, 165, 95, 52, 160, 200, 0 }, + { 2400, 173, 78, 54, 240, 212, 2 } + } + }, + { /* FM region 68 */ + { 34, 0, 127 }, 16, 140, 205, 0, + { + { 0, 211, 55, 66, 244, 208, 0 }, + { 1902, 193, 93, 65, 248, 240, 0 }, + { 0, 204, 47, 4, 244, 216, 0 }, + { 3600, 183, 95, 6, 160, 232, 0 } + } + }, + { /* FM region 69 */ + { 34, 0, 127 }, 16, 126, 222, 0, + { + { 0, 243, 36, 66, 172, 200, 0 }, + { 1200, 193, 110, 67, 248, 244, 0 }, + { 0, 215, 33, 2, 232, 212, 0 }, + { 3369, 178, 63, 6, 184, 240, 0 } + } + }, + { /* FM region 70 */ + { 34, 0, 127 }, 16, 140, 221, 0, + { + { 1200, 213, 61, 66, 136, 200, 0 }, + { 1902, 193, 93, 68, 248, 240, 0 }, + { 0, 197, 47, 2, 228, 216, 0 }, + { 3369, 183, 95, 2, 160, 236, 0 } + } + }, + { /* FM region 71 */ + { 34, 0, 127 }, 16, 124, 201, 0, + { + { 1200, 195, 55, 68, 240, 208, 0 }, + { 0, 209, 76, 65, 248, 236, 0 }, + { 1902, 147, 47, 19, 208, 212, 0 }, + { 0, 183, 79, 22, 156, 228, 0 } + } + }, + { /* FM region 72 */ + { 37, 0, 127 }, 32, 110, 234, 0, + { + { 500, 237, 60, 68, 0, 192, 1 }, + { 1, 161, 93, 65, 248, 240, 2 }, + { 3365, 154, 47, 16, 48, 180, 6 }, + { 1200, 165, 92, 52, 160, 212, 2 } + } + }, + { /* FM region 73 */ + { 37, 0, 127 }, 32, 142, 200, 0, + { + { 0, 193, 60, 68, 248, 200, 0 }, + { 1, 129, 61, 65, 248, 240, 2 }, + { 3365, 154, 47, 16, 68, 184, 6 }, + { 1200, 169, 92, 52, 160, 204, 2 } + } + }, + { /* FM region 74 */ + { 35, 0, 127 }, 32, 135, 36, 0, + { + { 1199, 165, 79, 66, 152, 192, 2 }, + { -3, 145, 110, 64, 248, 240, 2 }, + { 0, 199, 79, 66, 44, 236, 2 }, + { 2986, 136, 110, 67, 100, 196, 2 } + } + }, + { /* FM region 75 */ + { 37, 0, 127 }, 32, 190, 71, 0, + { + { 868, 202, 140, 16, 24, 188, 2 }, + { 0, 176, 77, 65, 248, 240, 2 }, + { 3750, 169, 127, 16, 36, 228, 6 }, + { 2400, 195, 60, 17, 232, 172, 2 } + } + }, + { /* FM region 76 */ + { 37, 0, 127 }, 224, 16, 123, 0, + { + { 275, 202, 14, 2, 44, 196, 2 }, + { 0, 165, 89, 65, 56, 244, 2 }, + { 0, 255, 12, 2, 64, 216, 6 }, + { 963, 169, 14, 4, 40, 196, 2 } + } + }, + { /* FM region 77 */ + { 50, 0, 127 }, 192, 128, 100, 0, + { + { 1500, 202, 79, 68, 76, 204, 2 }, + { -2, 97, 26, 64, 248, 232, 2 }, + { 1588, 202, 223, 69, 4, 220, 0 }, + { 3, 188, 121, 67, 48, 252, 2 } + } + }, + { /* FM region 78 */ + { 34, 0, 127 }, 112, 140, 205, 0, + { + { 0, 68, 47, 66, 60, 176, 2 }, + { -2, 113, 94, 64, 248, 236, 0 }, + { 5000, 121, 47, 64, 32, 168, 7 }, + { 3, 136, 94, 64, 0, 236, 0 } + } + }, + { /* FM region 79 */ + { 35, 0, 127 }, 32, 135, 33, 0, + { + { 1199, 197, 79, 66, 152, 184, 2 }, + { 0, 161, 110, 64, 248, 240, 2 }, + { 0, 199, 79, 66, 44, 236, 2 }, + { 2400, 255, 110, 65, 36, 208, 6 } + } + }, + { /* FM region 80 */ + { 34, 0, 127 }, 0, 192, 170, 0, + { + { 1199, 192, 77, 33, 200, 212, 0 }, + { 0, 209, 107, 33, 232, 240, 0 }, + { 1201, 80, 77, 33, 200, 212, 0 }, + { 0, 241, 107, 33, 232, 240, 0 } + } + }, + { /* FM region 81 */ + { 34, 0, 127 }, 0, 192, 221, 0, + { + { -1, 192, 45, 33, 200, 212, 0 }, + { -1, 209, 107, 33, 232, 244, 0 }, + { 1, 80, 45, 33, 200, 212, 0 }, + { 1, 241, 107, 33, 232, 244, 0 } + } + }, + { /* FM region 82 */ + { 37, 0, 127 }, 0, 112, 255, 0, + { + { 4750, 221, 45, 34, 48, 172, 4 }, + { -10000, 161, 107, 33, 200, 244, 3 }, + { 2204, 137, 45, 37, 64, 184, 0 }, + { -2, 211, 107, 33, 160, 208, 0 } + } + }, + { /* FM region 83 */ + { 37, 0, 127 }, 16, 127, 238, 0, + { + { 2, 248, 45, 32, 204, 208, 0 }, + { -9500, 241, 107, 33, 200, 240, 3 }, + { 3369, 186, 45, 38, 24, 208, 0 }, + { -2, 211, 107, 32, 220, 212, 0 } + } + }, + { /* FM region 84 */ + { 37, 0, 127 }, 0, 128, 221, 0, + { + { -1, 192, 191, 99, 220, 216, 0 }, + { 1200, 243, 92, 97, 0, 244, 0 }, + { 3984, 200, 11, 96, 168, 192, 0 }, + { 1, 194, 127, 98, 108, 200, 0 } + } + }, + { /* FM region 85 */ + { 34, 0, 127 }, 128, 128, 111, 0, + { + { 1, 194, 25, 35, 120, 204, 2 }, + { -9750, 193, 107, 36, 224, 244, 3 }, + { 3906, 255, 28, 50, 12, 188, 3 }, + { -1, 216, 107, 80, 204, 240, 2 } + } + }, + { /* FM region 86 */ + { 34, 0, 127 }, 32, 134, 222, 0, + { + { 0, 195, 52, 33, 200, 208, 0 }, + { 0, 177, 90, 33, 232, 240, 2 }, + { 702, 195, 52, 33, 200, 208, 2 }, + { 702, 177, 90, 34, 232, 240, 2 } + } + }, + { /* FM region 87 */ + { 34, 0, 127 }, 32, 134, 205, 0, + { + { 0, 198, 75, 36, 120, 220, 2 }, + { 0, 225, 78, 52, 40, 244, 2 }, + { 0, 246, 47, 32, 220, 208, 2 }, + { 1902, 241, 124, 32, 240, 236, 2 } + } + }, + { /* FM region 88 */ + { 35, 0, 127 }, 32, 120, 14, 0, + { + { 3600, 244, 67, 34, 88, 208, 0 }, + { 3, 194, 84, 33, 84, 240, 2 }, + { -3, 194, 84, 33, 172, 236, 2 }, + { 902, 254, 114, 34, 0, 224, 3 } + } + }, + { /* FM region 89 */ + { 34, 0, 127 }, 64, 169, 170, 0, + { + { -3, 83, 69, 34, 184, 212, 0 }, + { -7500, 50, 69, 33, 176, 244, 3 }, + { 3, 81, 69, 34, 212, 212, 2 }, + { -8500, 66, 69, 33, 176, 244, 3 } + } + }, + { /* FM region 90 */ + { 34, 0, 127 }, 64, 120, 221, 0, + { + { -2, 82, 69, 34, 244, 216, 0 }, + { 0, 145, 102, 33, 228, 240, 0 }, + { 2, 81, 69, 34, 244, 208, 2 }, + { 0, 145, 102, 33, 224, 240, 2 } + } + }, + { /* FM region 91 */ + { 35, 0, 127 }, 32, 138, 14, 0, + { + { 2400, 148, 67, 34, 176, 200, 0 }, + { 3, 194, 85, 33, 220, 236, 2 }, + { -3, 194, 69, 33, 220, 236, 2 }, + { 1905, 254, 114, 34, 48, 224, 2 } + } + }, + { /* FM region 92 */ + { 34, 0, 127 }, 82, 67, 71, 0, + { + { 2982, 228, 22, 146, 88, 192, 3 }, + { 3, 102, 84, 146, 196, 240, 2 }, + { 3358, 50, 149, 116, 144, 208, 2 }, + { -3, 85, 84, 146, 120, 240, 0 } + } + }, + { /* FM region 93 */ + { 37, 0, 127 }, 48, 126, 219, 0, + { + { -3, 49, 19, 33, 120, 200, 0 }, + { 0, 81, 70, 33, 220, 240, 0 }, + { 3804, 242, 18, 50, 200, 200, 0 }, + { 1203, 82, 19, 82, 200, 176, 0 } + } + }, + { /* FM region 94 */ + { 35, 0, 127 }, 32, 138, 13, 0, + { + { 2786, 116, 67, 34, 204, 184, 0 }, + { 1902, 114, 69, 33, 192, 232, 2 }, + { -3, 178, 69, 33, 188, 232, 2 }, + { 3804, 254, 82, 34, 164, 228, 2 } + } + }, + { /* FM region 95 */ + { 34, 0, 127 }, 48, 135, 238, 0, + { + { -2, 34, 85, 34, 184, 224, 0 }, + { 1, 113, 70, 33, 228, 236, 0 }, + { 2, 19, 85, 34, 156, 224, 2 }, + { -1, 129, 70, 33, 224, 236, 2 } + } + }, + { /* FM region 96 */ + { 50, 0, 127 }, 240, 112, 221, 0, + { + { 3369, 213, 69, 32, 0, 204, 0 }, + { 0, 193, 70, 33, 112, 232, 2 }, + { 0, 145, 69, 34, 244, 208, 2 }, + { -9000, 145, 70, 33, 224, 236, 3 } + } + }, + { /* FM region 97 */ + { 34, 0, 127 }, 96, 122, 168, 0, + { + { -1, 99, 51, 33, 200, 208, 0 }, + { -8500, 81, 83, 33, 232, 240, 3 }, + { 702, 99, 52, 33, 200, 208, 2 }, + { -9500, 65, 83, 34, 224, 240, 3 } + } + }, + { /* FM region 98 */ + { 34, 0, 127 }, 0, 67, 0, 0, + { + { 1500, 217, 55, 151, 20, 224, 2 }, + { 3, 231, 70, 146, 88, 220, 2 }, + { 2369, 115, 148, 151, 32, 196, 2 }, + { -3, 118, 36, 146, 64, 244, 2 } + } + }, + { /* FM region 99 */ + { 34, 0, 127 }, 64, 169, 204, 0, + { + { -3, 228, 69, 34, 148, 220, 0 }, + { -7448, 243, 69, 33, 200, 240, 3 }, + { 3, 81, 68, 34, 212, 212, 2 }, + { -8526, 65, 68, 33, 196, 240, 3 } + } + }, + { /* FM region 100 */ + { 34, 0, 127 }, 64, 119, 187, 0, + { + { 2786, 228, 22, 146, 176, 192, 0 }, + { 3, 102, 68, 146, 196, 236, 2 }, + { 3369, 178, 149, 116, 176, 208, 2 }, + { -3, 231, 68, 146, 120, 240, 0 } + } + }, + { /* FM region 101 */ + { 34, 0, 127 }, 240, 144, 239, 0, + { + { -2, 49, 69, 34, 236, 208, 2 }, + { -9000, 113, 102, 33, 228, 236, 3 }, + { 2400, 149, 69, 34, 12, 216, 1 }, + { 0, 145, 102, 33, 224, 236, 2 } + } + }, + { /* FM region 102 */ + { 50, 0, 127 }, 241, 176, 6, 0, + { + { 1200, 247, 49, 64, 252, 204, 0 }, + { 3804, 246, 101, 32, 0, 232, 2 }, + { 1902, 247, 32, 32, 112, 188, 2 }, + { 0, 228, 84, 32, 0, 240, 2 } + } + }, + { /* FM region 103 */ + { 37, 0, 127 }, 64, 101, 221, 0, + { + { 1, 194, 68, 97, 196, 200, 2 }, + { -10001, 247, 100, 114, 176, 240, 3 }, + { 3370, 213, 33, 70, 52, 200, 2 }, + { -1, 178, 68, 49, 208, 212, 0 } + } + }, + { /* FM region 104 */ + { 34, 0, 127 }, 0, 255, 203, 0, + { + { -3, 245, 82, 99, 200, 232, 2 }, + { 2787, 244, 84, 96, 0, 236, 2 }, + { 1198, 133, 81, 100, 196, 220, 2 }, + { 1902, 147, 67, 80, 0, 232, 2 } + } + }, + { /* FM region 105 */ + { 37, 0, 127 }, 0, 255, 140, 0, + { + { 500, 255, 137, 179, 0, 200, 3 }, + { 1902, 248, 90, 160, 0, 244, 2 }, + { 3804, 245, 57, 35, 164, 204, 2 }, + { 0, 245, 38, 51, 196, 208, 2 } + } + }, + { /* FM region 106 */ + { 37, 0, 127 }, 0, 255, 72, 0, + { + { 1000, 238, 57, 65, 0, 188, 3 }, + { 1902, 247, 103, 112, 0, 244, 2 }, + { 2786, 250, 36, 81, 68, 212, 2 }, + { 0, 249, 50, 49, 172, 204, 2 } + } + }, + { /* FM region 107 */ + { 37, 0, 127 }, 16, 119, 72, 0, + { + { 1500, 255, 89, 65, 0, 196, 3 }, + { 2790, 246, 39, 112, 0, 240, 0 }, + { 1905, 246, 36, 81, 168, 208, 0 }, + { 0, 249, 114, 49, 172, 212, 0 } + } + }, + { /* FM region 108 */ + { 37, 0, 127 }, 0, 255, 237, 0, + { + { 1902, 254, 89, 65, 0, 212, 2 }, + { 0, 248, 87, 112, 0, 240, 2 }, + { 3369, 231, 62, 81, 0, 208, 2 }, + { 3, 245, 118, 49, 96, 196, 2 } + } + }, + { /* FM region 109 */ + { 34, 0, 127 }, 16, 188, 205, 0, + { + { -2, 179, 47, 50, 244, 224, 2 }, + { 1900, 145, 94, 49, 248, 232, 2 }, + { 3, 210, 46, 2, 244, 208, 2 }, + { 2789, 133, 93, 4, 180, 244, 2 } + } + }, + { /* FM region 110 */ + { 37, 0, 127 }, 48, 135, 220, 0, + { + { 1901, 162, 25, 35, 144, 208, 0 }, + { 0, 113, 105, 65, 220, 240, 0 }, + { 3369, 233, 88, 51, 120, 212, 0 }, + { 0, 229, 24, 84, 200, 208, 0 } + } + }, + { /* FM region 111 */ + { 34, 0, 127 }, 112, 32, 190, 0, + { + { 0, 53, 79, 66, 152, 212, 2 }, + { 1200, 53, 75, 64, 136, 244, 2 }, + { 500, 149, 60, 66, 16, 208, 2 }, + { 1902, 200, 78, 64, 0, 248, 0 } + } + }, + { /* FM region 112 */ + { 37, 0, 127 }, 0, 144, 130, 0, + { + { 2514, 255, 68, 53, 0, 204, 2 }, + { 2400, 247, 133, 48, 0, 240, 2 }, + { 4151, 243, 67, 50, 0, 212, 2 }, + { 3369, 243, 66, 56, 0, 204, 2 } + } + }, + { /* FM region 113 */ + { 37, 0, 127 }, 0, 255, 0, 0, + { + { 514, 253, 79, 51, 0, 196, 3 }, + { 1905, 252, 89, 51, 0, 244, 2 }, + { 4349, 245, 35, 51, 0, 208, 2 }, + { 1205, 247, 34, 51, 0, 208, 2 } + } + }, + { /* FM region 114 */ + { 37, 0, 127 }, 0, 255, 0, 0, + { + { 514, 221, 69, 35, 0, 204, 3 }, + { 0, 250, 86, 115, 0, 252, 2 }, + { 1884, 244, 116, 51, 0, 200, 2 }, + { 1208, 210, 35, 51, 0, 208, 2 } + } + }, + { /* FM region 115 */ + { 37, 0, 127 }, 0, 255, 16, 0, + { + { 514, 222, 85, 163, 0, 192, 3 }, + { 0, 254, 108, 163, 0, 252, 2 }, + { 3800, 255, 143, 160, 0, 176, 2 }, + { 1200, 250, 105, 163, 0, 212, 2 } + } + }, + { /* FM region 116 */ + { 37, 0, 127 }, 0, 255, 16, 0, + { + { 1514, 249, 101, 163, 0, 204, 3 }, + { -1200, 249, 87, 160, 0, 252, 2 }, + { 0, 235, 143, 160, 0, 204, 2 }, + { 1200, 234, 73, 163, 0, 204, 2 } + } + }, + { /* FM region 117 */ + { 37, 0, 127 }, 0, 255, 16, 0, + { + { 500, 239, 101, 160, 0, 204, 3 }, + { -1195, 248, 104, 160, 0, 252, 2 }, + { 1898, 252, 72, 163, 0, 216, 2 }, + { 1239, 248, 87, 163, 0, 196, 2 } + } + }, + { /* FM region 118 */ + { 37, 0, 127 }, 0, 255, 255, 0, + { + { 500, 255, 98, 160, 0, 196, 3 }, + { -1, 249, 105, 160, 0, 252, 2 }, + { 1907, 250, 71, 160, 0, 252, 2 }, + { 1182, 249, 87, 161, 0, 192, 2 } + } + }, + { /* FM region 119 */ + { 37, 0, 127 }, 0, 0, 100, 0, + { + { 600, 32, 15, 0, 252, 224, 6 }, + { 0, 47, 111, 65, 0, 244, 2 }, + { 1826, 16, 47, 0, 252, 216, 2 }, + { 3551, 240, 47, 0, 252, 212, 2 } + } + }, + { /* FM region 120 */ + { 52, 0, 127 }, 240, 128, 235, 0, + { + { 1228, 161, 47, 17, 196, 200, 3 }, + { 3000, 123, 75, 17, 0, 240, 2 }, + { 7022, 72, 43, 17, 0, 216, 0 }, + { 4000, 150, 79, 17, 48, 196, 3 } + } + }, + { /* FM region 121 */ + { 37, 0, 127 }, 224, 16, 86, 0, + { + { 275, 251, 6, 0, 36, 200, 2 }, + { 0, 101, 104, 65, 56, 240, 2 }, + { 0, 240, 6, 0, 252, 208, 6 }, + { 1000, 195, 8, 0, 248, 200, 2 } + } + }, + { /* FM region 122 */ + { 34, 0, 127 }, 0, 0, 185, 0, + { + { 600, 35, 66, 17, 72, 224, 4 }, + { -13000, 81, 67, 17, 228, 244, 2 }, + { 702, 97, 38, 17, 212, 196, 6 }, + { -14000, 81, 65, 17, 224, 244, 3 } + } + }, + { /* FM region 123 */ + { 50, 0, 127 }, 240, 112, 237, 0, + { + { -6528, 153, 127, 16, 0, 252, 3 }, + { 1200, 105, 109, 16, 0, 216, 2 }, + { -6022, 179, 139, 17, 0, 248, 3 }, + { 2000, 104, 79, 17, 0, 240, 0 } + } + }, + { /* FM region 124 */ + { 50, 0, 127 }, 240, 240, 16, 0, + { + { 1914, 240, 64, 160, 240, 208, 2 }, + { 1200, 240, 73, 163, 240, 244, 0 }, + { 1900, 240, 64, 160, 240, 148, 2 }, + { 4151, 240, 73, 163, 240, 244, 0 } + } + }, + { /* FM region 125 */ + { 34, 0, 127 }, 240, 56, 235, 0, + { + { -5522, 97, 32, 17, 196, 240, 3 }, + { 0, 84, 75, 17, 180, 248, 3 }, + { 702, 65, 38, 17, 224, 212, 6 }, + { -4000, 161, 73, 17, 224, 252, 1 } + } + }, + { /* FM region 126 */ + { 53, 0, 127 }, 240, 248, 37, 0, + { + { 1050, 243, 0, 0, 252, 224, 7 }, + { 2000, 49, 68, 0, 224, 236, 3 }, + { 350, 240, 0, 0, 252, 216, 1 }, + { 700, 240, 0, 0, 252, 212, 3 } + } + }, + { /* FM region 127 */ + { 53, 0, 127 }, 240, 248, 37, 0, + { + { 1050, 245, 85, 0, 0, 244, 7 }, + { -5000, 247, 71, 0, 0, 252, 3 }, + { 350, 240, 0, 0, 0, 164, 0 }, + { 700, 32, 0, 0, 0, 252, 2 } + } + }}; /* end FM Regions */ + +/*---------------------------------------------------------------------------- + * Programs + *---------------------------------------------------------------------------- +*/ +const S_PROGRAM eas_programs[] = +{ + { 7864320, 0 } /* program 0 */ +}; /* end Programs */ + +/*---------------------------------------------------------------------------- + * Banks + *---------------------------------------------------------------------------- +*/ +const S_BANK eas_banks[] = +{ + { /* bank 0 */ + 30976, + { + 32768, 32769, 32770, 32771, 32772, 32773, 32774, 32775, + 32776, 32777, 32778, 32779, 32780, 32781, 32782, 32783, + 32784, 32785, 32786, 32787, 32788, 32789, 32790, 32791, + 32792, 32793, 32794, 32795, 32796, 32797, 32798, 32799, + 32800, 32801, 32802, 32803, 32804, 32805, 32806, 32807, + 32808, 32809, 32810, 32811, 32812, 32813, 32814, 32815, + 32816, 32817, 32818, 32819, 32820, 32821, 32822, 32823, + 32824, 32825, 32826, 32827, 32828, 32829, 32830, 32831, + 32832, 32833, 32834, 32835, 32836, 32837, 32838, 32839, + 32840, 32841, 32842, 32843, 32844, 32845, 32846, 32847, + 32848, 32849, 32850, 32851, 32852, 32853, 32854, 32855, + 32856, 32857, 32858, 32859, 32860, 32861, 32862, 32863, + 32864, 32865, 32866, 32867, 32868, 32869, 32870, 32871, + 32872, 32873, 32874, 32875, 32876, 32877, 32878, 32879, + 32880, 32881, 32882, 32883, 32884, 32885, 32886, 32887, + 32888, 32889, 32890, 32891, 32892, 32893, 32894, 32895 + } + } +}; /* end Banks */ + +/*---------------------------------------------------------------------------- + * Samples + *---------------------------------------------------------------------------- +*/ + +const EAS_SAMPLE eas_samples[] = +{ + 13, -24, 28, -32, 33, -37, 39, -61, 119, -76, 120, -70, 99, -122, 89, -113, + 91, -123, 122, -123, 77, 86, -116, 6, -118, 123, -23, 64, -93, 17, 24, -125, + 124, -125, 124, -24, -12, 56, 87, -54, 38, -91, 64, -2, -41, 126, -127, 20, + 8, -48, -62, 127, -128, 88, -43, -18, 86, -100, 44, -32, -26, 71, -13, 6, + 51, -33, -50, 106, -59, 33, 5, -20, 69, -56, 54, -48, -6, 38, -5, -38, + 35, -1, 12, -1, 4, 23, -56, 19, -7, 5, -4, 31, -38, 3, -12, -9, + -25, -7, 24, -32, 17, -21, -22, 24, -20, 6, -18, 0, -15, 5, -16, 15, + 3, 2, -10, 3, 27, -31, 37, -12, 32, -5, 2, -21, 27, -14, 20, -8, + 5, 15, -7, -11, 20, -37, 7, -23, 17, -22, 11, -14, 8, -44, 39, -52, + 26, 3, 14, -10, 51, -45, 29, -19, 19, -3, 41, -21, 46, -23, 10, 16, + -25, 3, 7, -30, 19, -9, -5, -1, 1, -19, 1, -24, -23, 51, -48, -10, + 17, -34, -38, 60, -71, 26, -43, 65, -59, 70, -26, 61, -51, 63, -51, 42, + -25, 58, -36, 31, 10, -14, -9, 8, -18, 8, 4, 8, 7, 31, -52, 39, + -53, 53, -56, 24, 11, 1, -20, -8, -32, -18, -10, -25, 4, 1, 37, -37, + 42, -42, 53, -57, 52, -18, 30, 11, 20, -52, 55, -61, 56, -50, 24, -26, + 38, -42, 36, -1, -43, 58, -46, 6, 18, -35, 31, -36, 28, -55, 55, -98, + 52, -41, 26, -24, 48, -31, 48, -26, 30, 19, -17, 23, -8, 13, 15, 19, + -7, -23, 41, -36, 20, -39, 65, -64, 66, -38, -9, 7, -14, -10, -3, 6, + 15, -19, -40, 53, -67, -11, -12, -25, 23, -11, -12, 46, -48, 39, -20, 20, + -14, 31, -54, 71, -25, 2, -8, -5, -9, 1, 7, 27, 17, -14, 43, -31, + 27, 11, -33, 20, -2, -33, 45, -38, 17, -9, -11, -17, -22, -19, 20, -25, + 4, 29, -35, 14, -17, 1, -7, 19, 2, 16, 32, -3, -17, 4, 0, -9, + 17, 5, -8, 52, -32, 40, -39, -5, -18, 14, -21, 31, 10, -17, 8, -34, + -7, 1, -44, 7, 10, -8, -6, -18, -25, -1, -19, 16, -29, 62, 6, 9, + 21, 0, -14, 4, 5, 20, 13, 27, -1, 18, -5, 21, -31, 11, 2, -9, + -4, 21, -27, 8, -21, -28, -19, 14, -12, 5, -20, 20, -36, 4, -18, -27, + -4, -4, 15, 4, 48, -7, -11, 20, -6, 7, 20, 1, 20, 0, 35, -35, + 28, -37, 7, -43, 21, -22, 23, -18, 12, -22, -13, -20, -11, 7, 23, -10, + 19, -18, 17, -41, 4, -16, -8, 21, 11, -4, 10, 30, -24, 32, -15, 15, + -13, 28, -5, 38, -10, 0, -22, -13, -12, 24, -18, 30, -7, 4, -16, 27, + -28, -3, -1, 18, -14, 31, -24, -3, -13, -19, -36, -2, -31, 9, -2, -12, + 17, 12, -50, 46, -49, 43, -15, 13, 22, 15, -25, 10, -8, -6, 14, -2, + 24, 15, 9, 17, -13, 5, 14, -15, 7, 20, 4, 4, 18, -16, 3, -47, + 31, -46, 19, -24, 5, -19, -1, -42, 14, -44, 18, -7, -1, 15, 9, -35, + 32, -44, 39, -46, 23, -16, 36, -25, 45, -34, 32, -8, 10, 5, 28, 0, + 12, 11, 3, 20, -23, 6, -8, 16, 7, 17, -19, 32, -44, 3, -8, -21, + -8, -5, 2, -29, 2, -3, -19, -14, 3, 7, -23, 10, 1, 3, 8, 13, + -44, 20, 21, -16, 23, 3, 5, 10, -11, 32, -11, 13, -7, 30, 4, 16, + -7, -6, -7, 14, -40, 4, -16, -26, 3, -1, 0, -6, 5, -50, 37, -27, + 18, -16, -14, 6, -1, -4, -15, 8, -12, 14, 9, -22, 42, -10, 23, -11, + 36, -15, 13, 30, 1, 47, -20, 33, -14, -12, 1, -20, -9, -9, -11, -13, + 7, -37, 25, -47, 14, -13, 4, -12, 9, -32, 18, -48, -1, -35, -1, -7, + 35, -20, 53, -4, 34, -7, 13, 19, 9, 30, 6, 45, -22, 23, -18, -6, + -1, 3, -30, 14, -15, 9, -39, 10, -33, -13, -24, 10, 14, 14, -10, 2, + -34, -4, -20, -21, -14, 40, -10, 17, -14, 28, -17, 37, -26, 69, -15, 38, + 2, 21, -25, 37, -61, 13, -9, 5, -17, 18, -41, 22, -57, -1, -9, -13, + 24, -10, 38, -5, 8, -16, -2, 1, 12, -25, -2, -13, 2, 2, -16, -19, + 32, -30, 22, 20, -4, 12, 11, -17, 19, -17, -3, 20, -33, 65, -27, 32, + -14, 8, -8, 13, -19, 9, -2, 7, 33, -40, 18, -18, -18, 6, -23, -11, + -11, -28, 4, -11, -15, -14, -8, -5, 34, -6, 19, 1, -3, 9, -1, 5, + 5, 14, -11, 40, -3, 18, -20, 16, -7, 2, -5, 9, -16, 9, -17, 0, + -17, 4, -17, -3, 3, 8, -14, -19, 12, -21, -7, 1, -2, -8, 16, 3, + -6, 35, -23, 33, -13, 11, 12, 3, -7, 26, -11, 19, -18, 23, -22, 39, + -49, 39, -50, 11, -38, 26, -29, 10, -6, -22, 15, -8, 15, -37, 36, -43, + 39, -43, 18, -26, 1, 11, 4, -2, 9, 7, 2, 7, 19, 1, 1, -4, + 16, -5, 16, -9, -3, 4, -4, -1, -17, 0, 11, 16, -27, 12, -15, 15, + -3, 0, 10, -3, -5, 12, -13, -7, -13, -31, -1, -3, -17, 15, -31, 25, + -10, 15, -1, 2, 4, 10, 7, 32, -13, 7, -22, 2, -10, 16, 1, -15, + 19, -24, 16, -18, -12, 18, -9, 9, 24, -8, 8, 11, 0, -31, 17, -55, + 21, -43, 40, -40, 29, -54, 44, -34, 22, 11, 16, 7, 19, 21, -6, 2, + -7, -16, 22, 0, -1, -4, 5, -8, 26, -42, 4, -6, -21, 35, -16, 8, + 0, -22, -13, 11, -31, 7, -28, 4, 17, -12, -18, -2, -23, 23, -1, 19, + 34, 7, 7, 35, -19, 11, -8, -17, 8, 4, 16, -16, -13, 9, -15, -5, + -1, -6, 7, 3, 11, 1, -7, -24, 21, -31, 36, -3, -10, 8, 2, -17, + 12, -24, 6, -3, 9, 15, 3, 13, -8, -13, -3, 6, -19, 14, -33, 16, + -17, -5, -31, 3, -29, 24, -7, -6, 35, -20, -5, 34, -20, 25, -3, 10, + 25, 8, 14, -13, 0, 1, 17, -33, 51, -38, 45, -32, 39, -3, -2, -24, + 3, -18, 14, -4, -44, 2, -25, -15, -2, -23, 3, -2, -2, 20, -14, 8, + -10, -4, 21, 11, -13, 32, -4, 8, 19, -16, -2, -2, -2, 14, -2, -1, + 27, -26, 20, 11, -13, 10, -3, -7, 12, -13, -3, -30, -16, 10, -26, -3, + -10, -2, -9, 15, -17, 1, -2, -7, 14, -8, 12, -3, -1, 2, 47, -26, + 22, -19, 16, 2, 13, -3, 21, -10, 22, -32, 43, -24, 16, 0, 5, -2, + 12, -44, -12, 1, -26, 1, -36, 5, 2, 9, -17, 20, -37, 14, -9, -5, + 6, -3, -13, 23, -19, 25, -33, 6, 17, 10, 19, 15, -4, 12, 5, -9, + 33, -20, 26, -9, 11, -2, 11, -21, -7, -13, -4, -8, -12, 0, -10, -9, + 8, -33, 9, -26, 8, 6, -8, 12, 7, -8, 0, 7, -16, 25, -8, 27, + 12, 0, 9, -9, 4, -17, 14, -16, 11, -8, 18, -2, 4, 2, -20, -18, + 22, -16, -5, 3, -24, 13, -10, -12, -10, 2, -16, 33, -15, 21, -15, -4, + -19, 29, -22, 18, 2, 20, 12, 18, -22, -7, -16, 7, -19, 14, 1, -17, + 33, -22, 38, -8, 3, -3, 21, -17, 51, -43, 15, -22, -23, -6, -12, -14, + 14, 9, 6, 4, -31, 3, -16, -14, 22, -22, 5, 13, -25, 17, -2, -18, + 7, 1, 5, 36, -16, 23, 4, -15, 29, -20, 10, 1, 24, 17, 16, -4, + -16, -37, -11, 1, -33, 27, -36, 17, -22, 2, -33, 16, -29, 32, -7, 24, + -12, 14, -12, 22, -16, 15, -20, 19, 9, 14, 12, -1, -24, 13, -6, -1, + 32, -19, 24, 12, -26, 4, -31, -38, 18, -16, -13, 3, -14, -1, 11, -15, + 15, 0, -2, 30, -6, 35, -23, 10, -35, 5, -14, 17, -21, 20, 4, 7, + 8, -5, -15, 20, -25, 26, 6, -3, 3, 5, -24, 26, -35, 4, 0, -6, + 13, -23, 8, -25, 1, -2, 9, 3, 17, 4, 0, 13, -15, 3, -21, -16, + 4, -5, -10, 11, -2, 7, 23, -22, 25, -19, 18, 25, -9, 14, -21, -7, + 11, -24, 22, -12, -7, 6, 9, -33, 11, -20, 2, -9, 2, 3, -13, 12, + -15, 23, -21, 16, -16, -2, 8, 13, -12, 18, -10, 16, -12, 20, -18, 18, + -1, 21, -21, 20, -30, -6, 10, -2, 13, -6, -15, 6, 2, -1, 1, -19, + 9, -15, -3, -11, 0, -5, 1, 5, 1, -4, -8, 1, -16, 23, 0, -23, + 2, 8, -6, 38, -4, 2, 13, -17, 31, -4, -8, 22, -14, 0, 12, -22, + 7, -7, 11, 4, -4, -12, -9, -22, 2, -17, -17, -11, 7, -17, 19, -24, + 9, -8, -6, 29, -4, 10, 4, 4, 23, -1, 9, -6, -12, 23, 16, -6, + 33, -29, 12, -7, -10, 17, -4, -18, 21, 0, -14, -2, -20, -21, 10, -28, + 5, -18, -4, 0, -11, 1, 5, -17, 3, 9, 20, 6, 1, -7, 2, -7, + 3, 9, -22, 29, 6, -1, 25, -10, 6, -1, 4, 12, 18, -13, 28, -11, + 6, -15, -14, -22, -7, 5, -14, 1, -16, -12, -5, 5, -9, 4, -1, -14, + 21, -10, -5, 0, -17, -7, 2, -10, 6, 11, 1, 37, -17, 6, 21, -24, + 41, 2, 23, 0, 10, -18, 16, -26, 14, -21, -19, 18, -9, -14, -1, -9, + -14, -3, -7, -10, 7, -7, 19, -11, 15, -25, -3, -6, 2, 8, -10, 4, + 12, -3, 11, -2, -2, 5, 31, -9, 39, -21, 14, -23, 18, -16, -1, -3, + -6, 0, 22, -9, -5, -17, -4, -12, 2, -3, -7, 10, -10, 7, -20, -19, + -10, 0, -14, 32, -15, -18, 13, -9, 2, 17, -14, 6, 36, -9, 28, 1, + 0, 17, -10, 5, 17, -8, 12, -2, 3, 2, -22, -6, -14, 6, 8, -11, + -14, 2, -23, 25, -35, 3, -18, 1, -14, 22, -1, -12, -7, -9, 13, -4, + 12, 4, -3, 18, 0, 1, 8, -14, 14, -2, 1, 17, -3, -14, 35, -17, + 19, -14, -6, 1, -9, 18, -17, -4, -13, -2, -14, 10, -10, -6, 0, 3, + 5, -12, -13, -3, -6, -6, 11, -13, -7, 13, -2, 6, 13, -7, 11, -5, + 23, 1, 29, -17, 23, -10, 18, -16, 12, -20, 10, 7, -9, -5, -21, -9, + 5, -13, -2, 0, -15, -11, 3, 0, -18, 5, -25, -2, 3, -2, -3, 4, + 8, 14, -7, 15, 4, 8, 19, 9, 11, 7, -3, 14, -11, 1, 15, -35, + 3, 3, -10, -16, 0, -15, 2, 3, -12, 27, -23, 32, -15, 10, -14, 3, + -27, 10, -15, 12, -24, 7, 2, 9, -2, -2, -1, 3, 1, 1, 8, -4, + 0, 6, -6, 1, 1, -1, 8, -11, 31, -27, 13, 4, -3, 5, -1, 0, + 2, 9, 0, 12, -31, 4, -27, 1, -25, 20, -21, -14, 12, -14, 0, -5, + -23, 18, -1, 15, 19, -5, 20, -8, 14, -7, 16, 3, 0, 8, 10, 0, + -8, -10, 3, -8, 9, -12, 4, 15, -6, 2, -12, -29, -3, -16, -11, 35, + -18, -1, -28, 7, -12, 0, 7, -5, 22, 10, 10, -4, 6, -13, 21, -23, + 20, 8, -13, 11, 15, -6, -6, -22, -1, 3, 14, 7, 11, -27, 12, -17, + -12, 8, -15, 3, -8, 12, -12, 5, -30, 12, -18, 9, -2, 3, 4, 15, + 1, 5, -9, 0, -8, 24, -2, 21, 5, -4, -4, 14, -15, 0, -1, 3, + 17, -5, 13, -19, -10, -4, -6, -4, -7, 18, -27, 8, 1, -12, -21, -13, + 1, -9, 11, 1, -3, -1, 22, -21, 9, 6, -3, 20, -2, 17, 7, -12, + 1, 4, 4, -9, 9, -20, 24, 7, -9, -3, -7, -6, 10, 7, 3, 9, + -2, -3, -4, 1, -19, -8, -16, 0, -12, 0, -25, 4, -22, 10, -9, 0, + -3, 15, -1, 8, 11, -15, 10, 13, 1, 22, -5, 15, 1, 24, 6, 0, + -6, 5, 5, 10, 8, -1, -11, -14, 3, -31, 2, -22, -4, -8, -15, -2, + -31, -12, 6, -7, 5, 2, 3, -4, 19, 3, 4, 7, 7, -8, 31, -6, + 26, 1, -2, 2, -3, -10, -4, -4, 9, 3, 12, -16, 16, -9, -1, 5, + 4, -7, 13, -17, 0, -11, -13, -22, 1, -9, 4, -7, 7, -10, 5, -1, + -6, -3, -21, 7, -10, 18, -3, 1, -7, -11, 11, -8, 12, 20, 3, 13, + 16, -1, 3, 13, -3, 23, 16, -3, 15, -14, 12, -6, -8, -28, 0, -33, + 4, -11, -12, -13, -21, -17, -16, -5, -12, 16, -7, 15, -6, -5, 3, -9, + 21, 17, 13, 14, 11, 21, -12, 31, -18, 7, 12, 8, 9, 7, 1, -3, + -7, -14, 17, -35, -10, -2, -18, -8, -10, -20, -22, 2, -10, -3, 1, -1, + 4, -5, 11, -20, 11, -6, 27, 7, 18, 8, -1, 2, 3, 11, -9, 5, + 5, -7, 29, -6, 20, -21, 23, -15, 19, -19, 2, -22, 11, -26, -7, -10, + -30, -1, -3, -6, 15, -22, 16, -7, -9, -2, -7, -5, 11, 17, -13, 2, + 8, -5, 6, 27, -6, 12, -6, 4, 15, 3, 14, -3, -12, 11, -2, 6, + 5, 4, -6, -12, 0, -32, 2, -22, 22, -12, -5, -7, -11, -7, 6, -1, + -3, -3, -16, 2, -1, 0, 0, -7, -2, 1, 12, -4, 5, 20, 1, 16, + -2, 14, -1, 19, 8, 29, -8, 7, -14, -2, 3, -13, 8, -40, 22, -18, + 2, -14, -8, -11, -8, 12, -21, -1, -10, -12, -6, -4, -14, 6, -19, 7, + 14, 1, 11, 11, -11, 25, 1, 14, -5, 31, 0, 22, 4, 1, 3, 6, + -3, 4, -2, -20, -7, -26, 1, -12, -7, -10, 2, -1, -5, -7, -8, -10, + 6, -7, -6, 10, -17, 6, 3, 15, -8, 15, -7, 12, 1, 9, -4, -2, + 10, 9, -1, 10, -4, 9, -8, 17, 0, -13, -7, -2, -11, 3, -2, -15, + -4, -11, -5, -9, 1, 8, -10, 8, -8, -6, -18, 21, -19, 26, -19, -1, + -11, 10, 4, 12, -10, 16, -10, 17, 8, 13, -1, 17, 1, 5, -1, 11, + -8, 9, 16, -17, 3, -26, -17, -14, 6, -17, 4, -20, 0, -1, -6, -4, + 2, -15, 13, -3, -1, 0, -2, -8, 11, 7, -3, -8, 5, 14, -1, 28, + -19, 13, -4, 8, 1, 11, 7, 6, -8, -2, -13, -10, -22, 6, 11, -1, + -1, -5, -13, 18, 3, -10, 9, -17, -8, 9, -9, 1, -17, -4, -16, 18, + -6, 15, -10, 17, 5, 0, -5, 0, -11, 12, 15, 4, 8, 5, -4, 0, + -2, 3, -17, -2, -1, 11, -6, -7, 2, -33, 23, -6, -1, -2, -2, -1, + -8, 3, -29, -2, -34, 16, -3, 16, 1, 10, -12, 23, 0, -3, 16, 12, + 19, 23, -1, 8, -26, 16, -32, 26, -13, 2, -11, 5, -1, -15, -9, -16, + 7, -6, 14, -15, 5, -10, -7, -9, -9, 6, -17, 13, 18, -5, -3, -4, + -4, -18, 28, -6, 13, 17, 24, -2, 9, -14, 1, -11, 7, 17, 1, -15, + 10, -23, -4, -12, 5, -20, 17, -10, 6, 0, -9, 4, -8, -15, 6, -16, + 7, 9, 3, 6, -12, -17, 0, 4, 13, 22, -4, 10, -8, 7, -12, 5, + 5, 1, 11, 2, 10, -3, -2, 3, -10, -5, -7, -4, -18, 17, -2, -14, + -16, -7, -10, -3, 6, -1, 14, -11, 15, -18, 2, -6, 0, -1, 0, 20, + -17, 1, 6, 2, 6, 12, -3, 7, 25, -5, 17, -14, 0, -6, 0, -2, + -5, -1, -10, 8, 2, -9, -19, -7, -17, 5, 3, -7, 4, -15, -5, 9, + -12, -1, -5, 3, -5, 26, -2, 3, -4, 5, 3, 7, 10, 5, 6, 6, + 26, -17, 0, -1, 3, -3, 10, -7, -7, -9, 11, -18, 0, -16, -6, -5, + 3, 7, -14, -14, 0, -21, 14, -8, -1, -12, 2, 1, 2, -3, -1, -3, + 18, 5, 5, 9, 12, 7, 18, 8, 5, -25, 16, -15, 16, -7, 9, -22, + 1, 14, -13, -5, 2, -6, -8, 13, -17, 6, -16, 1, -5, -14, -6, -6, + -15, -2, 9, -9, -18, 15, -19, 12, 7, 4, 8, 14, 15, 6, 10, -3, + 9, -7, 23, -17, 21, -20, 7, 0, -9, 8, -10, 1, 4, 2, 3, -9, + -9, -15, -6, -21, -16, -6, 0, -11, 19, -8, -9, 5, -6, 0, 5, 14, + 7, 1, 12, 8, 7, -5, 12, 8, -4, 19, 4, -7, 2, 3, -12, -8, + -1, 0, 5, 7, -5, -8, -22, -8, -21, -2, -9, 10, -20, 13, -6, 8, + -17, -9, -6, 2, 5, 8, 6, -3, 10, -9, -2, 15, -6, 20, 7, 11, + 10, -3, -4, -8, 25, -25, 18, -12, 17, -6, 20, -22, -1, -17, -10, 5, + -10, 9, -13, -9, -6, 10, -25, -5, -2, -5, 13, 2, -5, -8, -10, 11, + -27, 10, -4, 11, 0, 33, -4, 10, -14, 1, 12, -2, 27, -8, 6, 11, + 9, -12, -4, -10, -13, 12, 5, 1, -10, -14, -15, -8, -7, -9, 3, -5, + 10, 3, -11, -12, -13, -3, -3, 3, 2, 9, 17, -6, 25, -3, -3, -8, + 19, 3, 30, -10, 12, -22, 7, -5, -10, -3, 21, -8, 12, 6, -5, -13, + -13, -9, -9, -1, -23, 13, -17, 15, -22, -11, -18, 8, -14, 20, 1, 4, + -5, 3, 3, 5, 11, 1, 2, 27, 1, 10, -7, -8, -2, -2, 7, -1, + 17, -5, 24, -7, 5, -10, -20, -6, 5, -4, -5, -1, -18, -5, -14, -1, + -20, 1, 7, -7, 12, -4, -2, -4, 2, 8, 0, 7, 1, 6, -2, 18, + -5, -7, 4, 3, -2, 13, 4, 0, 2, -3, 2, -10, -6, 1, -6, 6, + -7, -3, -21, -2, -12, 5, -1, -9, 7, -3, 13, 5, 5, -8, 0, -8, + 19, -5, 13, 13, -7, 3, 0, -10, 0, -8, 20, -8, 13, -20, -5, -7, + 3, 5, -7, 2, -5, -4, -14, 11, -23, -13, 2, -1, 12, 13, 5, -6, + 23, -9, 9, -6, -9, 18, -13, 16, -3, -7, -17, 3, -13, 12, -9, 4, + 0, 0, 13, -18, -1, 3, -13, 20, -5, 1, -20, 15, -23, 18, -4, -8, + 5, -7, 16, 4, 6, -3, 7, -21, 19, -17, -7, 9, 5, 3, -5, -3, + -16, -9, 25, -9, 12, -5, 10, -5, 9, -4, -6, -3, 4, 10, -2, 11, + -12, -2, -14, 8, -23, -5, 0, -8, 9, -2, -11, -3, -9, 9, 2, 2, + 4, -5, 7, 11, -16, 0, -6, 7, 6, 25, 5, 6, -4, 3, 4, 3, + 2, -8, -3, 5, -1, -11, -4, -9, -3, -15, 10, -12, -5, 11, -4, -7, + 6, -29, -5, 6, 11, 3, 9, -18, 13, -14, 19, -1, -2, 4, 5, 12, + 1, 5, -8, 3, 1, 20, -6, 2, 3, -16, 10, -10, -18, -11, -7, -7, + 9, -4, -8, 9, -15, 13, -13, -3, -7, 3, 8, 11, -6, -16, 1, -8, + 20, 4, 15, -5, -3, 11, -5, 6, 0, -5, 10, 13, 0, -6, -11, 0, + 11, -11, 10, -7, -8, 1, 16, -9, 2, -22, -9, 0, 4, 5, -12, -22, + 2, -8, -8, 14, -16, 0, 13, 0, 9, -7, 2, -1, 7, 8, -3, -3, + 2, 15, 5, 10, -7, 12, -4, 22, -4, -3, -12, -2, -15, 8, -2, -22, + 7, -10, 5, 12, -20, -9, -11, -2, -12, 2, -9, 5, -3, 11, 7, -9, + 4, -4, 24, -7, 21, -15, -3, 2, 14, -1, 5, 18, -12, 13, 3, 5, + -10, -11, 0, -8, -2, -4, 2, -15, 9, -10, -16, -9, -7, 0, -1, 3, + -8, -10, 5, -8, 4, -3, 8, -2, 20, 1, 6, -4, -9, 4, 14, 7, + -1, 3, -5, 18, -7, 20, -6, -10, 8, 1, -2, 3, -4, -5, -3, -6, + 0, -16, -7, 12, 0, -17, 4, -31, -7, 1, 1, -4, 8, -11, 6, -1, + 11, -5, -7, -4, 2, 4, 15, -3, 21, -5, 20, 3, -12, 21, -1, 10, + 5, 6, -20, -1, -18, 2, 3, -4, -5, -1, 6, -2, -11, -17, -15, -13, + 0, 6, -18, 7, -18, 7, -7, 6, 7, -10, 18, 16, 2, -1, 3, -11, + 6, 14, 1, 15, -2, 29, -8, 17, -14, 2, -19, 12, 8, -6, -1, -23, + 6, -11, 7, -19, -18, 0, 1, -8, -8, -4, -20, 8, -8, 4, 10, -12, + 13, 0, 18, -10, -3, -4, 6, 4, 17, 7, -2, 18, -9, 14, -10, -4, + -11, 4, 3, 23, -17, -6, -2, -7, -7, 9, -10, 1, 2, -4, -14, -7, + -6, -8, -4, 7, 2, -3, 3, 0, 13, -10, -4, -9, -6, 18, 11, -4, + 16, -8, -4, 1, -1, 7, 3, 3, 3, 10, -15, -2, -9, 9, 0, 2, + 2, -9, 12, -7, 0, -23, -7, -19, 2, -1, 0, 4, -15, 7, 3, -3, + 0, 9, -12, 19, 4, 8, -13, -6, 5, -1, 14, 10, 9, 13, -3, 16, + -18, 13, -18, 7, -10, 13, -6, -11, -3, 7, -23, -6, -11, -21, 9, -1, + 4, -3, -16, 0, -12, 7, 14, -5, 15, 0, 6, -5, -3, -9, 9, 4, + 10, 4, -2, -7, 10, -1, 10, -6, -14, 15, -4, 13, -4, -4, -14, 5, + -2, 4, -9, 3, -14, 2, 3, -10, -1, -9, 0, 3, -6, 12, -16, 0, + 4, 10, -25, 6, -5, 2, 8, 3, -2, -4, 15, 4, 7, 2, -1, -6, + 10, 11, 2, -2, -14, 6, -3, 0, -3, -9, -10, 1, -1, -15, 9, -29, + 9, -10, 7, -3, -3, -10, -2, 14, 4, -6, 0, 1, 12, 4, 18, -15, + 19, 1, 15, 1, 1, 3, -10, 8, -1, 7, -30, 8, -19, -2, -5, -9, + -10, 0, -1, 6, -4, -12, 1, -18, 10, -1, -12, 2, 7, 12, 11, 0, + -4, -1, 6, 10, 17, -8, 1, -12, 5, -2, 1, -7, -1, 4, 3, -3, + -1, -18, 8, -9, 0, -2, 8, -12, 12, 7, -5, -2, -16, -7, 9, -5, + 11, -9, -4, 3, 1, -9, -1, -2, -6, 7, 12, 0, -8, 9, -10, 3, + 0, 2, -3, 11, 14, 4, 3, -12, 3, -3, 2, 12, -4, -2, -2, 9, + -21, -5, -28, -6, -10, 6, 7, -6, -3, -24, 7, -11, 10, 0, 8, 13, + 10, 6, -7, -2, -5, 7, -1, 9, 18, -2, 12, -4, 7, -26, 13, -6, + 19, 6, 6, -5, -16, -6, -8, -18, -2, 1, -11, 3, 4, -16, -8, -10, + -3, 2, -3, 5, 5, 0, 11, 0, -14, 0, 1, 14, 11, 13, 0, -2, + 5, -1, -4, -2, -4, 5, 21, 3, 14, -5, -22, 5, -11, -3, -6, -3, + -11, 0, -5, -13, -10, -18, 3, 9, -10, 2, 3, -11, 11, -11, 5, -19, + 23, -1, 20, 18, 4, -3, -6, 9, 4, -3, 8, 4, 6, 2, 5, -14, + -6, -3, 2, -6, -4, -3, -11, 0, -5, 0, -21, -2, -10, 11, 5, -4, + -5, -5, -8, 10, -10, 4, -1, 6, 12, 9, 2, 8, -20, 8, -2, 11, + -11, 1, -4, 5, 6, -6, 6, -14, 14, 4, -2, 12, -3, -10, 8, -5, + -15, -9, -1, 5, 8, -3, 0, -23, -9, -11, 4, -12, 3, -4, 4, 1, + 15, -12, 3, 13, 2, 5, 8, -8, 7, 11, -3, 17, -11, 5, 3, 19, + 13, 3, -11, -11, -2, -9, -7, -4, -24, -1, -17, -3, -17, 0, -15, 2, + -1, -5, -4, 3, 2, 2, 11, -4, 3, -6, 11, 8, 3, 6, 3, 7, + 7, 6, -6, 2, 0, 14, 14, 3, 8, -6, 4, -3, 6, -13, -2, -9, + -4, 5, -13, -5, -21, -1, -6, -1, -5, -14, 8, -7, 5, -7, -17, -11, + 7, 3, 20, 7, 1, -3, 4, 5, 14, -3, 5, 3, 10, 8, 6, -6, + -2, 6, 3, 7, -6, -3, -3, -6, -1, -27, -11, -17, 0, 11, 7, 1, + -7, -9, -13, 5, -11, 0, -10, 15, 2, 5, -2, -5, 1, 6, 6, -6, + -5, 6, 2, 5, 3, 10, -16, 11, 8, 18, 3, 13, -11, 7, 5, -7, + -6, -20, 15, -1, 10, -1, -13, -17, -11, -3, -13, -4, -14, -3, -2, -6, + 6, -28, 9, -8, 10, 0, 12, -2, 10, 9, 1, 3, -6, 5, 17, 24, + 18, 3, 4, -9, -4, 2, -8, -4, -2, -11, 1, -8, -12, -9, -10, 5, + 0, -7, -9, 7, -18, 6, -10, -12, -1, -1, 13, 1, 18, 2, -3, 4, + 3, 3, -3, 3, 10, 9, 7, 5, -8, -7, 0, 3, -7, 7, -2, -2, + 5, -10, 2, -5, -3, -1, 4, 1, -2, -10, 4, -9, -5, -12, -18, 3, + 6, -3, 3, -15, -1, -13, 6, -2, 8, 0, 8, 16, -2, 17, -4, 8, + 3, 23, -1, 11, -8, 10, -4, -5, -3, -13, -2, -1, -2, 2, -9, -13, + -13, -2, -11, -2, -20, -5, 0, 3, 2, -1, -10, 1, 8, 3, 9, 6, + 4, -3, 13, 3, 4, 11, 2, 11, 8, -2, -1, -2, -2, -2, -1, -21, + -1, -14, 8, 6, -8, -10, 2, -16, 4, -3, -1, -10, 7, -1, 4, -4, + -12, 3, -2, 13, 2, -3, -9, -2, 6, -7, 8, -8, -5, 12, 7, 8, + -3, 6, -1, 16, 0, 7, -8, 3, -7, -1, 0, -6, -4, -8, 6, -1, + 4, -19, 2, -3, -8, -3, -12, 4, -6, 2, -7, 1, -13, 2, 9, -1, + 17, -19, 3, -3, 23, 9, 6, 3, 6, 6, -5, 11, -11, 1, 0, -5, + 6, -6, -4, -5, -7, 3, -4, -14, -9, -7, -1, 5, -11, 4, -19, 14, + -4, 3, 4, 2, 0, 9, -2, -3, 2, -2, 10, 15, -3, 14, -6, -4, + 6, 1, -8, 11, -9, 4, 3, -9, 2, 2, -2, 2, -2, -9, -2, -2, + 1, -6, -6, -22, -16, -10, 12, 0, 5, -8, -2, -4, -2, 5, -1, 7, + 7, 9, 1, 7, 6, -1, 10, 11, 5, -3, 8, 1, -1, 8, -15, -6, + -10, 12, 0, 2, -5, -9, -12, -7, -4, -14, -4, 0, -1, 5, -7, -8, + -12, 0, 2, 16, -3, 11, -4, 16, 11, 2, -3, 2, 8, -1, 7, -13, + 4, -3, -1, 3, -10, -2, -11, 3, 2, 3, -7, -10, -5, -10, 12, -8, + 5, -7, 15, 1, -10, 7, -16, 1, 3, 4, -5, 7, -7, 4, -2, -1, + -8, 0, -2, 17, 10, -2, 6, -5, 3, 10, -7, 2, -3, 4, 5, 5, + -3, -8, -8, -1, 1, 7, -5, -11, -2, -10, -4, -15, -7, -10, -2, 2, + -4, -10, -8, 0, 2, 6, 3, 2, 3, 10, 14, 8, 7, 3, 5, -5, + 20, -6, -1, -2, 0, 1, -2, -2, -8, 3, -3, 10, -14, 3, -3, -2, + 0, -5, 0, -15, 4, -2, 0, 4, -7, 3, -8, 7, -14, -2, -6, 4, + 2, 3, -10, -2, 5, -3, 12, -2, -5, -9, 1, 4, 1, 11, -12, 15, + 5, 20, 10, -5, 1, 5, 3, -13, 6, -16, 5, 1, -5, -8, -3, -14, + -6, -2, -5, -8, -17, -9, 3, -6, -2, -3, -3, 1, 14, 2, 4, 5, + 3, 8, 7, 12, 0, 11, 4, 16, 2, -3, -9, -1, 1, -1, -3, -6, + -14, 4, -6, 2, -14, -9, -11, -1, 0, 0, -5, -6, -10, 5, -5, 2, + -3, 2, 2, 17, -2, -1, -3, 3, 11, 1, 10, 2, 7, 6, 5, -5, + -3, -3, -2, 7, 2, 1, -18, -5, -2, -3, -5, 0, -2, 0, 8, -9, + -10, -15, -7, -2, -1, 6, -8, 16, -10, 13, -4, 2, -4, 4, 7, 9, + 6, -5, -2, 8, -1, 11, -6, -1, 5, 8, 0, 9, -20, 0, -9, 4, + -3, 1, -4, -11, 2, -6, 0, -12, 0, 1, 5, -2, 1, -7, -4, 3, + -1, -10, 3, -3, 7, 4, 8, -9, -6, -10, 0, 0, 2, -4, 6, 9, + 10, 2, 0, -1, 2, 14, 3, 7, -7, 2, -2, -2, -6, -9, 2, -3, + 6, -3, -7, -9, -10, -2, 2, -1, -11, 2, 1, 7, -4, -7, -19, 3, + -1, 6, 6, 6, 6, 0, 6, 7, 3, -1, 3, 8, 3, 4, -10, -5, + -7, 5, -4, -14, 2, -8, 5, -2, 2, -16, -4, -11, 2, 4, -1, 2, + -1, 0, 5, 4, -12, 3, 9, 7, 13, -3, -7, 2, 6, -1, 7, -1, + -1, 5, -5, 7, -11, -9, -13, 2, 5, 2, -2, -7, 5, 4, -4, -2, + -15, -4, 3, 0, 0, -5, 2, -7, -1, 9, -2, -1, 5, 1, 1, -4, + -5, -4, 6, 8, 7, -5, 4, -7, 4, 0, 1, -6, -5, -2, 5, -1, + 0, 1, 1, 3, 9, -4, -2, -4, -9, -1, 4, -17, 1, -13, 11, -1, + 6, -9, -1, 5, 1, 8, -3, 4, -5, 1, 7, -5, 1, -3, 5, 3, + 4, -7, -11, -7, 1, 5, -13, 11, -11, 1, 3, 6, -9, 6, -5, -7, + 4, -13, 5, -7, 10, 5, 6, -15, -1, 6, 4, 18, -7, -7, -3, -4, + 2, -5, 3, -4, 9, -4, 3, 3, -3, -10, 0, -1, 2, 5, -3, 7, + 3, 2, -6, -11, -2, -1, 4, -5, 4, -5, 0, -5, 5, -5, -4, 2, + 4, 2, 5, -8, -13, -3, 0, -1, -2, 4, 6, 9, 1, 3, -7, -1, + 1, 12, 1, 1, -1, -5, -1, 2, -8, -9, -7, -2, 3, 10, -6, -7, + -12, -7, -4, -5, 6, 0, 10, 5, 7, -4, -2, -8, 10, 5, 9, 4, + -1, -1, -1, -1, -1, -2, -3, 3, 9, -2, 9, -14, -13, -8, -10, 1, + 1, 3, 3, 1, -3, -12, -5, -7, 1, 6, 6, -2, -7, -3, -3, 2, + 2, 4, -9, 14, 8, 11, -3, 5, -11, 1, -1, 5, 3, 8, 2, 8, + -2, -6, -13, -10, 0, 4, 3, 4, -3, -9, 1, -5, -5, -6, 1, -2, + 2, -10, -6, -15, 1, -5, 4, -1, 2, 2, 4, 10, 4, 2, -13, 0, + 4, 8, 17, 2, 5, 4, 2, -6, 5, -5, 0, 8, -2, -1, -5, -4, + -5, -1, -5, -4, -5, 0, 0, 1, -9, -15, -3, -12, 1, -1, -7, 10, + 2, 5, -1, 2, -6, 2, 2, 10, 10, -1, 2, -2, 4, 5, 0, -6, + 12, 5, 3, -1, -8, -8, -4, -4, 3, -11, 0, -1, -1, 0, -2, -14, + -6, -9, 2, 1, 7, -4, 3, -1, 0, -3, 1, 2, 7, 5, 4, 3, + -2, -3, 1, 6, -1, 6, -11, 7, 2, -6, 2, -4, 0, 2, 3, -7, + -9, 3, 0, 4, -6, 0, -21, 0, -5, -1, 0, -1, 1, -6, -1, -1, + 0, -7, 5, 7, -2, 8, -4, -1, 3, 9, -6, 10, -6, 7, 9, 10, + 9, -6, 5, -14, 6, -5, 1, 2, -3, 0, -9, -10, -14, -2, -3, 6, + -8, -15, 3, -9, 0, -3, 0, -6, -1, 3, 9, 10, 3, 3, -10, 6, + 1, 3, -1, 9, 12, 4, 4, -9, -7, -5, 8, 6, 1, 1, -4, -5, + -5, -1, -11, -3, -4, 1, -1, 1, -10, -7, -2, -3, -4, -3, -6, 11, + 5, 3, 2, -8, -5, -2, 3, 9, 13, 5, 4, 4, 0, -5, -1, -5, + 9, 2, 3, -9, -4, 3, -6, 2, 1, -9, 5, -2, 3, -2, -9, -8, + -15, -5, -3, 3, -13, 11, 6, -3, 1, -6, -6, -1, 6, 4, 6, 7, + 1, 5, 0, 8, -6, 7, 2, 6, 2, -5, 0, -3, -1, 3, -7, -1, + -3, 5, 7, 6, -18, -10, -11, -7, -3, 10, -4, 3, -4, -8, -5, -12, + -3, -4, 12, 10, 2, -4, 6, 3, 1, 2, 0, -3, 3, 7, 7, -5, + 2, -4, 1, 3, 11, 2, 3, 4, -2, -7, -5, -17, -11, 4, -3, 5, + -7, -7, -6, -1, -8, -5, -5, 1, 7, 1, 2, -1, -9, 7, 1, 7, + 3, 3, 6, 9, 6, 1, -6, -4, 2, 5, 7, 4, -2, 1, 3, -11, + -1, -16, -2, -6, 1, 3, -8, -15, -11, 4, -1, 9, -2, -5, 0, 6, + 0, -7, 0, -8, 4, 2, 6, 2, 0, 2, 6, 2, -2, 4, -2, 4, + 14, 2, 2, -6, -6, -3, 4, -4, -1, -4, 1, -3, -6, -1, -13, -1, + -2, 7, -8, -7, -10, 0, 4, 3, -8, -3, 1, 4, 6, 4, 6, -3, + 5, 3, 4, 0, 6, 1, 4, 7, -3, -10, 8, -1, 9, -1, 1, -11, + -7, -3, -3, -6, -8, -9, -6, 1, -3, -6, -6, -5, 0, 0, 2, -3, + 0, 6, 4, 3, 2, 7, 4, 11, 14, 5, -1, -5, 1, -2, 7, 3, + 0, 1, 2, -5, -7, -10, -12, -10, -5, -5, -6, -6, -9, 1, -8, -2, + -1, -9, 1, 8, 2, -5, -2, -5, 0, 5, 6, 6, 7, 8, 10, 2, + 0, -3, -1, 2, 13, 3, 0, -6, 0, 1, -3, 0, -12, -2, 4, -4, + 4, -8, -11, -1, -2, 1, -1, 2, -12, 3, -6, 1, -12, -7, -7, 3, + 0, 9, 0, 1, 6, 1, -1, 2, 1, 2, 8, 9, -3, -1, 0, 7, + 3, 8, -1, -4, -1, 1, 3, -9, -1, -17, -3, -2, -4, -4, -3, -4, + -6, -11, -15, -2, -5, 6, 10, 1, 3, -1, -3, 13, 7, 1, 6, 4, + 4, 9, 5, -3, -5, 9, 3, 5, -3, 1, -3, 3, 0, -7, -5, -7, + 0, -5, 0, -1, -15, -11, -4, -5, -10, 2, -7, 5, -4, 1, -9, 2, + 1, 8, 7, 10, 2, 2, 0, 4, 3, -2, 0, 4, 2, 6, 8, -2, + 4, 4, -2, 5, -3, -6, 3, -3, -5, -9, -8, -11, -5, -1, -1, -5, + -7, -5, -8, 0, -3, 5, -7, 11, 1, 0, 2, -3, -1, 3, 9, 6, + -3, 8, 1, 11, 2, 8, -3, -3, 6, 2, 1, 2, -7, -3, -2, -4, + -8, -3, -3, 5, -10, -10, -4, -12, -2, 3, -5, 3, -6, -8, -2, 5, + -3, 0, 1, 4, 8, 4, 5, 0, 4, 8, 1, 7, -3, 0, 3, 4, + 4, -5, -2, -7, -3, 0, 5, -5, -9, 3, -2, -1, -2, -5, -1, -4, + -3, -11, -4, -5, -6, 0, 5, 0, -5, 5, 3, 8, -1, 3, 3, 2, + 5, 7, -4, 3, 1, 3, 10, 2, -7, 1, 0, 6, -4, -3, -5, -7, + -2, -4, -3, -6, 0, -10, 4, -6, -4, -7, -2, 1, -4, -1, -3, -1, + 2, 6, 2, 4, -2, 2, 4, 2, 5, -3, 4, 2, 1, 0, 8, -3, + 2, 5, -5, 3, -5, -2, 5, -5, 3, -1, -4, -3, 4, -10, -5, -7, + -4, -4, 0, 0, -7, -1, -1, 2, 1, -2, -12, -4, -1, 0, 4, -5, + 2, 0, 3, 12, 11, 3, 11, -1, -3, 6, -6, 1, 1, 7, 6, -7, + -1, -7, -4, -4, -7, -8, -1, -6, -6, -2, -3, -5, 0, -4, 8, -7, + 1, 4, -3, 6, 1, -7, 3, 5, 6, 5, 13, 2, 2, -4, 4, -3, + 1, 4, -4, 2, -3, -10, -10, -7, -2, -2, -2, 0, -6, -2, 1, -3, + -4, -2, -5, -2, 7, 1, 6, -5, 6, -1, -1, 2, -3, 4, 11, 2, + -1, 2, -7, -5, 8, 0, 3, -3, -5, -1, -2, 3, 1, -4, 4, 7, + 0, 2, 3, -3, 0, 1, -5, -15, -5, -3, 1, 3, -3, -11, -4, -7, + 1, -2, -1, -1, 0, 1, 1, -5, -1, 3, -2, 7, 1, -4, -1, 0, + 4, 5, 3, 3, -1, 8, 11, 1, 4, 1, -5, 7, -6, -4, -2, -4, + -2, 3, -8, -3, -13, -6, 3, -3, -7, -4, -7, 3, 3, -3, 2, -1, + 1, -4, -2, -2, -5, 1, 11, 9, -2, 6, -3, 7, 7, 1, 1, -7, + 2, -3, 1, 4, -4, -4, 5, 1, 0, -3, -6, 2, -3, 0, -8, -12, + -6, -2, -3, 6, -1, -9, 0, -1, 1, 3, -2, -1, 0, 1, 6, 0, + -3, 5, 1, 6, 1, -1, 4, 1, 7, -3, -1, -1, -4, 4, 14, -1, + -1, 2, -4, -1, -6, -8, -8, -3, -2, 2, -9, -5, -7, -12, 5, 0, + -3, -4, -3, 5, 4, 3, -2, -6, 4, 7, 3, 5, 7, -3, 8, 0, + -5, -1, -1, 11, 10, 3, 4, -8, -3, -3, 1, -3, 0, -4, -3, 1, + -7, -8, -16, -7, -6, -2, 3, -7, -2, 1, -4, 0, -5, -5, 1, 5, + 10, 5, 0, 3, 0, 1, 13, 0, 5, 9, 6, 8, -1, -4, 0, -3, + 6, 4, -4, 0, -3, -15, -2, -12, -15, -3, -6, 2, 1, -3, -4, -9, + -9, -3, -3, -2, 3, 4, 9, 0, 2, 1, 2, 14, 5, 3, 8, 2, + 7, 4, -4, -4, -1, -9, 9, -5, -1, -7, -10, -2, -7, -4, 0, -5, + 2, 5, 1, 0, -5, -5, -1, -1, -3, 4, -8, 5, 3, -4, 4, -5, + -3, 9, 4, 8, 0, 0, 2, 0, -2, 0, -2, -7, 12, -1, 5, -4, + 2, -3, 0, 2, -2, -4, -2, 2, -5, 3, -7, -9, -4, -3, -2, -6, + -6, -2, -6, -1, -7, -8, 1, 3, 6, 10, 4, 5, 0, 5, 8, 1, + 3, 8, 5, 11, 12, -7, 4, 0, -3, 2, -1, -8, -7, -4, -2, -6, + -9, -6, -13, -4, -1, 0, -9, -5, -3, -4, -2, 3, 1, 1, 9, 4, + 2, 6, -1, 3, 6, 2, 0, -3, 3, 2, 6, 3, -1, -4, 4, 1, + 2, 2, -5, -8, -1, -3, -1, -9, -4, 1, -5, 5, -7, -4, 0, 3, + -10, 3, -3, -5, 1, 5, 4, 1, -5, 1, -5, 4, 1, -6, 0, 5, + 8, 8, 1, 6, 0, 3, 4, 2, -3, 1, -3, -3, 3, -10, -6, -8, + -2, -1, -3, -6, -6, -5, -6, -6, -5, 5, -3, 5, 6, -2, -1, -1, + -4, 6, -2, 6, 6, 2, 12, 8, -2, 3, -6, -2, 5, 4, -3, -2, + -5, -4, -7, -6, 1, -5, 2, 2, 0, 1, -7, 0, -4, -2, -1, -2, + -5, 7, -5, -2, -3, -2, -3, 4, 4, 9, 0, 1, 1, -5, -3, -4, + -4, 4, 3, 6, 1, -2, -2, -7, 4, 1, 1, -3, 3, -1, 2, 0, + -7, 0, 0, -1, -3, -2, -1, -5, -2, -3, -8, -5, -5, -1, 5, 5, + 2, 2, -3, 4, 3, 4, 6, 3, -1, 10, -4, -3, -2, -3, 0, -4, + 0, -2, -2, 0, 2, -5, -2, -5, -9, 8, -2, -1, -1, -3, -3, -2, + -6, 2, 1, 2, 9, 0, 1, 4, -5, 2, 4, -6, -1, 2, -1, 6, + 3, 0, -5, -3, -1, 0, 3, -3, 0, -6, -2, -3, -4, -2, 0, 3, + 2, 2, 0, -10, 1, -6, -5, -1, -2, 5, 3, 6, -2, -6, -1, -3, + 2, 4, 1, -1, 0, 1, 1, 3, -1, 5, -1, 7, 6, 1, -2, 0, + -6, -2, -2, -8, -2, -2, -3, -5, -5, -8, -3, -1, 5, -3, 1, 2, + 1, 2, -3, -2, -3, 2, 6, 2, 6, 0, 0, -2, 9, -1, 3, -2, + 3, 0, 0, 0, -6, -6, -1, -5, -7, 1, -3, -6, 2, -2, -1, -5, + -2, 1, 4, 2, 2, -3, -1, 6, -2, 2, 4, -3, 2, 2, 2, -3, + 1, 0, -4, 2, -1, -2, 3, 1, 1, -1, -5, -8, -2, -5, 0, 1, + -6, 3, -4, 2, 3, -6, 3, 0, 2, -2, -1, -4, -2, -4, 4, 0, + -3, 0, -6, -3, 10, -3, 3, 0, 4, 7, 3, 0, 5, 1, 5, 1, + -3, -2, 0, -6, 3, -1, -7, -5, -7, -1, -2, -2, -2, -3, -2, 2, + -2, -1, -3, -3, 2, -2, -6, -3, -3, 4, 3, 2, 0, -1, 5, 5, + 8, 2, 2, -2, 4, 0, 5, -5, -3, -1, -3, -3, -6, -4, -2, 3, + 0, -2, -2, -5, 5, -1, 3, -1, -1, -3, 0, 0, -5, -4, -3, -2, + 5, 0, -4, -4, 1, 2, 6, 0, -3, -1, 2, 3, 7, -3, 0, -4, + -2, 4, 3, 0, 1, 3, -3, 1, -7, -4, 0, 1, 1, -4, -4, -4, + -9, -1, -2, -3, -2, -3, -3, 4, 3, -1, -4, 2, 4, 4, 3, 2, + -1, 0, 9, -1, 4, 2, 7, -1, 6, -2, -2, -5, -1, -9, -2, -2, + -6, -1, -1, 1, -8, -6, -5, -1, -1, 1, -4, -5, 3, 1, 5, 3, + -3, 0, -2, 7, 0, 1, -2, 3, -1, 5, -1, -5, 7, -1, 3, 2, + -5, -6, -2, 4, 2, -1, -3, -1, -1, -1, -1, -2, -4, 1, -5, 3, + -1, -3, -5, 2, 6, -6, -1, -5, -4, 4, -1, -1, -2, -1, 2, 0, + 3, 1, 4, 2, 7, -1, 2, 0, -2, 1, 4, -5, -3, -7, -2, 0, + -1, -1, -3, 0, 0, -2, -6, 2, -4, 2, -4, 1, -7, -2, -1, 5, + 3, -2, -7, -4, 1, 6, 4, 5, 1, 4, 0, 5, 1, -1, 2, 0, + -3, -3, -5, -6, 3, -1, 5, -1, -2, 1, 1, 4, 2, -6, -3, -4, + -3, 2, -2, -8, -3, -6, -4, -2, -11, 0, 0, 1, 6, -3, -2, 1, + 2, 10, 8, 4, -2, -1, 2, 2, 1, -2, 3, 1, 5, 3, -1, 0, + -4, 4, -7, -2, -7, -8, -4, -3, -2, -7, -7, -3, -1, 5, -2, 0, + -7, 2, -1, 3, 1, 4, 6, 5, 8, 3, 2, -1, 3, -3, 0, 0, + -5, -1, 1, 1, -5, -3, -2, 6, 4, 5, -4, -8, -4, -3, -2, -5, + -4, -4, -4, 2, -3, -2, -4, -4, -4, 6, 1, 0, 1, 3, 3, 5, + 2, 1, 0, 6, 2, -1, 1, -3, -3, 2, -1, 0, 1, 3, 1, 4, + -4, -5, -10, -8, 1, -6, -3, -4, -6, -3, 0, 2, -3, -1, 2, 0, + 8, 1, 4, 4, 3, 6, 3, 1, 3, 5, 1, 2, -4, -7, -3, -3, + 3, 0, -7, -5, 0, -3, -1, -2, -4, 0, -5, 1, -6, -1, -5, -3, + 1, 4, -1, -3, 3, 3, 5, -1, -2, 2, -1, 2, 1, -1, -5, 5, + 1, 2, 2, -4, 0, -1, 3, 0, -2, -1, 2, 1, 5, 4, -3, -5, + 0, -2, -2, -6, -3, -3, -4, -1, -5, -4, -1, -2, 0, 2, -2, -6, + -3, 1, 1, 1, -1, 3, 4, 7, 2, 3, 4, -1, 7, 2, 3, 1, + -1, 1, -2, 0, -4, -5, -6, 0, -2, -7, -2, -5, -5, 1, -4, -5, + -5, 3, -1, 1, 2, -2, 0, 1, 4, 1, -4, 2, 2, 0, 9, 2, + 0, 4, 3, 1, 2, -4, -2, -4, 3, -4, -2, -6, 0, -1, 5, 2, + -4, 0, -4, -4, -1, -5, -4, -7, -3, 1, 0, -2, -1, -5, 1, 0, + -1, 0, 2, 4, 0, 3, -2, 1, 2, 6, 0, 1, 5, 0, 3, 3, + 2, -5, -2, 1, 5, 2, -2, -5, -9, 0, -6, -1, -6, -7, -5, -4, + 0, -2, -5, -3, 2, -2, 3, 2, 0, 9, 2, 0, 4, -3, 4, 5, + 8, 6, -2, -4, -1, 0, -2, -2, 1, -5, 2, -5, -1, -4, -3, -4, + 0, -2, -7, -3, -1, 0, -1, 0, -6, 3, -2, 5, 2, -1, -2, 1, + 0, 1, -1, -3, 2, 3, 1, 2, -4, -3, -1, 5, 5, 3, -4, 0, + 1, 2, 5, -5, 1, -5, 2, -2, 2, -4, -3, 0, -4, -3, -9, -7, + -4, 2, -2, 1, -6, -3, 0, 1, 5, 1, -5, 0, 0, 2, 1, 2, + 0, 6, 4, 6, 3, 2, 3, 1, -2, -2, -9, -4, -1, 4, 0, -1, + -5, -8, -5, -4, 0, -4, -1, -3, 0, 0, -4, -3, -1, 1, 2, 0, + -2, -3, 1, 3, 2, 3, 3, 0, 8, 2, 7, -1, 3, -2, 4, 0, + 0, 1, -4, 5, -1, -3, -3, -6, -4, 2, 1, -5, -4, -7, -4, -4, + -7, -2, -10, 1, 0, 1, -3, 4, -2, 5, 2, 1, -3, -1, 2, 8, + 4, 5, 0, 1, 4, 5, 2, 2, -2, 1, -4, 0, -3, -3, -1, 0, + 2, -4, -4, -5, -1, -7, 0, -4, -5, -1, -3, 2, -2, 0, 3, 0, + 2, 0, 1, -2, 2, 4, -1, 0, -3, -1, 1, 3, 2, -3, 2, 0, + 2, 2, -1, 2, -2, -3, 0, 0, -2, 2, -2, 4, -3, -6, -7, -6, + 2, -1, -4, -1, -7, -1, -3, 3, -1, 0, -2, 2, 2, -3, 3, -4, + 5, 7, 6, 3, 1, -1, 6, 2, 1, 0, -1, -1, 1, -3, 1, -3, + -5, -5, -3, -8, -3, -11, -1, -1, 0, -8, -2, -5, 3, 4, 0, 1, + -2, 2, 0, 6, 4, 1, 4, 1, 5, 0, 0, 1, 2, 5, 0, 1, + -10, 0, -5, 2, 0, -6, -6, -2, -2, 2, -3, 0, -4, 2, -4, 1, + -3, -4, 1, -2, 2, 1, -2, 0, 3, 2, -3, -1, -5, -3, 4, 2, + 3, -1, 4, 1, 5, -1, 2, -3, 2, -3, 0, -3, -2, 1, 1, 5, + 1, -2, -5, 1, -1, -4, -3, -7, 0, -5, -4, -4, 0, -4, 4, 0, + -1, 1, -8, 1, 0, 9, 1, 2, -2, 5, 5, 1, 6, -1, 6, 3, + 1, 1, -2, -2, -4, -3, -2, -3, -7, -4, -4, -1, -3, -8, -1, -8, + 4, -5, 0, -3, 1, 0, 4, -1, 0, 1, 3, 3, 4, -4, 6, -2, + 2, 5, 4, -3, 4, -3, 5, 0, -4, 0, 0, -1, 0, -4, -4, 3, + -1, -2, -4, -8, -9, -5, -4, 4, -4, 1, -4, 1, 1, -1, -1, -1, + 3, 2, 3, 0, 1, 2, 1, 5, 3, 1, 0, 5, 3, 3, 0, -5, + -4, -2, 5, 0, -2, -5, -2, -6, -2, -5, -8, -2, 1, -1, -3, -7, + -8, -6, 0, 4, 7, -2, 7, -1, 7, 3, 2, -5, 0, 2, 0, 1, + -3, 2, 2, 3, 3, -3, 0, -2, 3, -1, -1, -4, -6, -2, -3, 4, + -4, 0, -4, 6, -2, -6, -2, -7, 1, 2, -1, -3, -2, -2, 3, -1, + 0, -3, -1, 4, 7, 4, 0, 2, -1, 0, 6, -2, 1, 1, 5, 4, + 1, -3, -3, -2, 2, 2, 1, -6, -6, -3, -4, -2, -6, -5, -4, -5, + -2, -8, -8, -3, 0, 4, 0, 1, -1, 2, 5, 4, 2, 2, 3, 3, + 4, 10, 0, 2, 0, 3, 1, 1, 0, -3, 1, -3, 1, -7, 0, 1, + -2, 1, -6, -4, -10, -1, -4, -2, -2, -3, 2, -4, 1, -5, -4, -4, + 2, 1, 1, -4, -1, 3, 1, 6, 2, -2, -2, 3, 3, 2, 7, -5, + 5, 0, 8, 1, -1, 2, 3, -1, -6, 0, -10, 3, -1, -1, -5, -6, + -8, -2, 0, -3, -5, -8, -4, 2, -3, -1, -2, 0, -1, 7, -1, 3, + 2, 4, 7, 3, 4, -1, 5, 1, 9, 1, -2, -1, -1, 1, -3, -2, + -6, -7, 1, -3, -1, -9, -4, -6, 0, 2, -3, -2, -4, -3, 0, -4, + -1, -4, 0, 1, 6, -1, 1, -1, 3, 5, -1, 3, 4, 5, 7, 4, + -2, 0, -2, 0, 3, 1, -1, -8, -2, -1, -2, -5, -1, -2, -2, 2, + -5, -7, -9, -2, -3, -2, 1, -5, 4, -4, 5, -1, -1, -3, 2, 3, + 7, 3, -1, 3, 4, -1, 5, -4, 0, 4, 4, 3, 4, -9, 1, -5, + 2, -2, -2, -3, -7, -1, -2, -2, -5, -3, -1, 1, -2, -1, -4, -4, + 1, -1, -7, 0, -1, 2, 5, 4, -4, -5, -4, 0, 2, 1, -1, 3, + 5, 4, 0, 0, -1, 3, 8, 3, 3, -4, 0, 1, 0, -2, -6, -2, + -4, 3, -2, -3, -5, -6, -3, -1, -1, -7, 0, 0, 3, -5, -4, -11, + 0, 0, 3, 3, 1, 1, 1, 4, 6, 1, 1, 2, 9, 3, 3, -4, + -4, -3, 2, -1, -6, 1, -5, 2, 0, -1, -8, -5, -6, 1, 0, -2, + -1, -2, -1, 2, 0, -9, 0, 5, 4, 7, -3, -3, 3, 4, 2, 4, + 0, -1, 3, 1, 5, -5, -6, -7, 0, 3, 0, -2, -4, 3, 3, -3, + -4, -7, -2, 4, 1, -1, -4, -1, -6, -2, 3, -2, -3, 1, 4, 1, + -1, -4, -3, 3, 4, 5, -2, 2, -3, 4, 0, 3, -3, -3, 0, 3, + 1, -2, -1, -3, 2, 4, -2, -2, -3, -1, -1, 3, -11, -2, -8, 5, + -1, 3, -5, -2, 2, -1, 3, -3, 0, -1, -1, 5, -2, 0, -2, 3, + 2, 3, -2, -6, -3, 2, 4, -6, 5, -6, 1, 2, 3, -6, 2, -3, + -4, 3, -9, 2, -6, 3, 4, 2, -9, -1, 1, 2, 8, -3, -4, -1, + -2, 2, -2, 2, -3, 3, -1, 1, 2, -1, -6, 1, 2, 2, 1, -2, + 2, 3, 1, -3, -6, -3, 0, 1, -3, 0, -3, -1, -4, 2, -4, -3, + -1, 4, 0, 5, -6, -7, -1, 0, 0, -3, -1, 2, 4, 0, 3, -4, + -1, 1, 7, 4, 2, -1, -4, 0, 2, -4, -5, -5, -1, 1, 4, -5, + -4, -6, -3, -2, -3, 2, -2, 5, 2, 3, -4, -2, -5, 6, 3, 4, + 2, -3, 1, 0, 0, 1, -3, -1, 1, 7, 0, 6, -6, -7, -2, -7, + 0, -1, 0, 2, 1, -2, -7, -2, -5, 0, 2, 0, -3, -5, -1, -3, + 0, -1, 0, -6, 8, 4, 5, -1, 1, -4, 1, 1, 4, 2, 5, 3, + 6, 0, -2, -9, -4, -1, 0, 0, 1, -1, -4, -1, -5, -5, -5, 0, + 0, 1, -6, -5, -9, 0, -3, 0, -2, 0, 0, 3, 4, 2, 1, -7, + 1, 3, 4, 9, 1, 4, 4, 2, -4, 2, -2, 1, 5, -2, 0, -3, + -4, -3, -2, -4, -4, -4, 1, -1, 2, -6, -8, -3, -8, -1, -2, -4, + 5, 2, 3, -1, 0, -4, 2, -1, 5, 5, -1, 3, 0, 3, 3, 0, + -4, 9, 4, 2, -1, -6, -4, -2, -2, 2, -7, 0, 0, -2, -2, -2, + -10, -4, -7, 0, -2, 2, -2, 2, 1, 0, -3, 0, 1, 6, 3, 2, + 0, 0, -1, 2, 3, -1, 4, -5, 6, 2, -3, 0, -3, 0, 1, 0, + -5, -6, 1, 0, 1, -5, -2, -14, 0, -4, -1, -1, -1, 1, -3, 0, + -2, -1, -4, 4, 5, -1, 5, -1, 3, 3, 5, -3, 5, -3, 5, 5, + 6, 4, -6, 2, -9, 4, -4, 0, 1, -2, -1, -8, -6, -11, -2, -3, + 3, -6, -8, 3, -5, 1, -3, 1, -3, 1, 3, 5, 6, 2, 1, -6, + 4, -1, 1, 0, 7, 7, 2, 3, -6, -4, -4, 3, 3, 0, 1, -1, + -2, -4, 0, -8, -2, -3, 1, -2, 1, -5, -2, -1, -3, -3, -4, -3, + 7, 4, 1, -1, -6, -5, -3, 2, 5, 8, 3, 3, 2, 1, -4, -1, + -2, 6, 3, 2, -4, -1, 1, -5, -1, -1, -5, 2, -2, 1, -2, -7, + -5, -11, -4, -3, 3, -8, 8, 4, -2, -2, -4, -4, -1, 4, 3, 5, + 5, 2, 4, -1, 6, -3, 6, 2, 3, 0, -4, 0, -2, -2, 0, -5, + -2, -1, 4, 3, 1, -13, -8, -8, -5, -3, 7, -2, 3, -2, -5, -3, + -8, -2, -3, 8, 6, 1, -2, 5, 3, 1, 2, 0, -1, 2, 4, 3, + -5, 1, -3, 0, 1, 7, 1, 2, 3, -1, -4, -4, -10, -7, 3, 0, + 2, -5, -5, -4, -1, -7, -3, -3, 1, 3, 0, 0, -1, -6, 6, 1, + 4, 1, 2, 5, 6, 4, -1, -4, -3, 1, 2, 5, 2, -1, 1, 3, + -8, -1, -10, -2, -5, 0, -1, -6, -10, -7, 2, -2, 6, -1, -2, 1, + 4, -1, -5, -1, -5, 4, 1, 4, 2, 1, 3, 4, 0, -2, 1, -1, + 3, 8, 2, 1, -4, -3, -3, 3, -3, -1, -4, 0, -4, -6, -2, -8, + 1, -2, 5, -6, -5, -6, 0, 3, 1, -6, -3, 1, 2, 4, 2, 4, + -2, 3, 3, 3, 1, 5, 1, 2, 3, -2, -6, 6, -1, 6, -2, 1, + -7, -5, -2, -3, -6, -6, -6, -4, 0, -2, -4, -4, -3, 0, -1, 1, + -3, -1, 3, 1, 1, 0, 6, 4, 8, 10, 5, 0, -3, 1, -2, 5, + 2, 1, 1, 1, -4, -6, -8, -8, -8, -5, -4, -5, -4, -5, 0, -5, + -3, 0, -7, 0, 4, 1, -4, -1, -4, -2, 4, 4, 5, 6, 6, 7, + 0, 0, -1, 0, 2, 9, 2, 1, -3, 0, 1, -3, 1, -9, -1, 3, + -4, 3, -6, -7, -2, -1, -1, -1, 1, -9, 2, -5, 1, -8, -6, -6, + 1, -1, 6, 0, 2, 5, 2, 0, 2, 1, 2, 6, 5, -2, -1, 0, + 4, 1, 6, 0, -2, 1, 0, 3, -7, -1, -13, -4, -3, -3, -3, -2, + -3, -5, -9, -11, -2, -3, 4, 7, -1, 2, 0, -2, 8, 5, 1, 4, + 3, 2, 7, 3, -2, -4, 7, 2, 3, -2, 1, -1, 2, 0, -5, -4, + -4, 0, -4, 0, -1, -10, -9, -3, -5, -8, 1, -5, 3, -3, 0, -7, + 1, 0, 5, 4, 7, 1, 1, 0, 2, 2, -2, -1, 2, 1, 4, 6, + -1, 4, 3, -1, 4, -2, -3, 3, -1, -2, -6, -6, -7, -3, -1, 0, + -4, -6, -5, -6, 0, -3, 3, -5, 7, 0, -1, 1, -3, -1, 1, 6, + 3, -3, 7, 1, 10, 1, 6, -1, -2, 5, 2, 1, 1, -4, -2, 0, + -3, -7, -2, -4, 4, -8, -8, -4, -10, -2, 2, -4, 1, -5, -7, -1, + 3, -1, 1, 1, 4, 6, 2, 2, 0, 4, 7, 0, 5, -2, 0, 3, + 3, 3, -3, -1, -5, -2, 0, 3, -4, -6, 2, -1, 0, -2, -4, 0, + -4, -3, -9, -3, -4, -4, 0, 3, -1, -4, 3, 1, 5, -2, 1, 2, + 2, 4, 5, -3, 2, 1, 3, 7, 1, -5, 1, 0, 5, -3, -2, -3, + -4, 0, -3, -2, -5, 0, -8, 3, -6, -4, -6, -2, 2, -4, -2, -3, + -2, 1, 4, 2, 3, -2, 2, 4, 1, 4, -2, 3, 2, 1, 1, 7, + -1, 2, 4, -4, 2, -4, -2, 5, -4, 3, -1, -3, -2, 3, -8, -4, + -6, -3, -3, -1, 0, -6, -1, 0, 1, 1, -2, -10, -3, -1, 0, 2, + -5, 1, 1, 2, 10, 8, 2, 8, -1, -2, 4, -5, 2, 2, 7, 6, + -6, -1, -5, -4, -3, -6, -7, 0, -5, -5, -1, -2, -5, 0, -4, 6, + -6, 0, 3, -3, 4, 0, -6, 2, 5, 5, 4, 10, 0, 2, -3, 3, + -2, 0, 3, -3, 2, -3, -8, -8, -5, -1, -1, -1, 0, -5, -2, 0, + -3, -4, -1, -5, -2, 5, 0, 5, -4, 4, -1, -1, 1, -3, 3, 9, + 2, -1, 1, -6, -3, 7, 1, 3, -2, -4, 0, -1, 3, 1, -3, 4, + 6, 0, 1, 2, -3, 0, 0, -5, -13, -4, -2, 1, 2, -3, -10, -4, + -7, 1, -2, -2, -1, 0, 1, 1, -4, -1, 2, -2, 7, 1, -3, 0, + 0, 4, 5, 2, 2, -1, 6, 9, 1, 3, 1, -5, 5, -6, -5, -2, + -4, -2, 2, -7, -4, -11, -5, 3, -3, -6, -4, -6, 3, 3, -3, 2, + 0, 1, -3, -1, -2, -4, 1, 10, 8, -2, 4, -3, 6, 6, 1, 0, + -7, 2, -2, 1, 3, -4, -4, 4, 1, 0, -2, -5, 2, -2, 0, -7, + -11, -5, -2, -2, 5, -1, -8, -1, -1, 1, 2, -2, -1, 1, 1, 5, + 0, -3, 5, 1, 6, 1, -1, 3, 1, 6, -3, -1, -1, -3, 4, 12, + -1, -1, 2, -4, -1, -6, -8, -7, -3, -2, 1, -9, -5, -6, -10, 5, + 1, -2, -3, -2, 5, 4, 3, -1, -5, 4, 6, 3, 4, 6, -2, 7, + 0, -4, -1, -1, 9, 8, 2, 2, -8, -3, -3, 0, -2, 0, -4, -2, + 0, -6, -7, -14, -6, -5, -1, 3, -6, -2, 1, -3, 0, -4, -5, 1, + 5, 9, 4, 0, 3, 0, 1, 12, 0, 4, 8, 5, 7, -1, -4, 0, + -3, 5, 4, -4, 0, -3, -13, -2, -10, -14, -3, -5, 2, 1, -3, -4, + -8, -8, -3, -2, -2, 3, 4, 8, 0, 2, 1, 2, 12, 5, 3, 8, + 2, 6, 3, -4, -4, -2, -8, 8, -5, -2, -6, -10, -2, -6, -4, 0, + -4, 2, 5, 1, 0, -4, -4, -1, -1, -3, 4, -7, 4, 3, -3, 4, + -4, -3, 8, 4, 7, 0, 0, 2, -1, -2, -1, -2, -7, 11, -1, 5, + -4, 2, -2, 0, 2, -2, -4, -2, 1, -5, 3, -6, -9, -3, -3, -2, + -5, -5, -2, -6, -2, -7, -8, 1, 3, 5, 9, 4, 4, 0, 5, 8, + 1, 3, 7, 5, 10, 11, -7, 3, 0, -3, 1, -1, -7, -7, -3, -2, + -6, -9, -6, -12, -4, -1, 0, -8, -5, -3, -3, -2, 3, 1, 1, 9, + 4, 2, 5, -1, 2, 6, 2, 0, -3, 2, 2, 5, 2, -1, -4, 4, + 1, 1, 2, -5, -8, -1, -3, -1, -9, -4, 1, -4, 5, -6, -4, 0, + 3, -9, 3, -3, -5, 1, 4, 4, 1, -4, 1, -4, 4, 1, -6, 0, + 5, 7, 8, 1, 6, 0, 3, 4, 2, -3, 1, -3, -3, 3, -9, -6, + -7, -2, -1, -3, -5, -6, -5, -5, -6, -5, 4, -3, 5, 5, -2, -1, + -1, -3, 6, -2, 5, 6, 2, 11, 8, -1, 3, -6, -2, 5, 4, -3, + -3, -5, -3, -7, -5, 0, -5, 2, 1, 0, 1, -7, 0, -3, -2, -1, + -2, -5, 7, -4, -2, -3, -2, -3, 4, 4, 9, 0, 1, 1, -5, -3, + -4, -4, 4, 3, 6, 0, -2, -2, -6, 4, 1, 1, -3, 3, -1, 2, + 0, -7, 0, 0, -1, -3, -2, -1, -5, -2, -3, -8, -5, -5, -1, 5, + 5, 2, 2, -3, 4, 3, 3, 6, 3, -1, 10, -4, -3, -2, -3, 0, + -4, 0, -2, -2, 0, 1, -4, -2, -5, -9, 8, -2, -1, -1, -3, -3, + -2, -6, 2, 1, 2, 9, 0, 1, 3, -4, 2, 4, -6, -1, 2, -1, + 6, 3, 0, -5, -3, -1, 0, 3, -3, 0, -6, -2, -3, -4, -2, 0, + 3, 2, 2, 0, -10, 1, -6, -5, -1, -2, 5, 3, 6, -2, -6, -1, + -3, 2, 11, 11, -28, -10, 54, -53, 2, 43, -37, 0, 43, -48, 7, 11, + -18, 19, -33, 32, -1, -7, -6, 19, -21, 23, -38, 0, 54, -49, 0, 15, + 20, -28, -20, 53, -28, -48, 70, -6, -60, 51, 5, -32, 1, 31, -10, -33, + 24, 33, -68, 21, 50, -67, -1, 57, -28, -21, 26, 15, -48, 9, 33, -32, + -3, 23, -10, 5, -4, -10, 24, -42, 29, -13, 0, 26, -15, -26, 46, -17, + -38, 45, -26, 8, -1, 4, -5, -3, 15, -27, -2, 39, -37, -25, 74, -33, + -25, 16, 24, -26, -25, 46, 10, -74, 50, 33, -80, 37, 32, -51, 13, 26, + -21, -5, 0, 18, -33, -1, 49, -29, -29, 38, 7, -26, -20, 45, -21, -18, + 26, -6, -6, 17, -29, -5, 41, -38, 10, 19, -18, -7, 15, 2, -24, 1, + 21, -6, -28, 51, -30, -7, 10, 6, -22, -3, 37, -32, -24, 63, -16, -60, + 65, -10, -35, 15, 17, -15, -8, -1, 33, -37, -10, 55, -44, -5, 41, -35, + -9, 20, -5, -18, 13, 19, -27, 2, 34, -34, -7, 21, -27, 27, -25, 26, + 5, -30, 32, -45, 38, -3, -41, 24, 25, -31, 5, 9, 9, -37, 13, 31, + -36, 7, 20, -18, -25, 56, -50, 13, 17, -17, 19, -40, 46, -3, -82, 88, + -1, -73, 66, -10, -4, -18, 13, 5, -27, 14, 7, -7, -10, 37, -39, 11, + 14, -38, 35, -21, 5, 11, -27, 45, -37, -6, 34, -39, 23, 16, -51, 51, + -11, -28, 19, -6, 12, -29, 12, 26, -21, -25, 48, -35, -6, 24, -9, 0, + -31, 54, -19, -47, 73, -33, -43, 81, -59, 12, 15, -28, 22, -26, 33, -2, + -29, 14, 34, -63, 28, 16, -40, 31, -22, 18, 8, -22, 25, -31, 6, 26, + -54, 33, 19, -53, 56, -25, -9, 24, -39, 34, -18, -15, 35, -18, -16, 43, + -41, -3, 47, -54, 9, 33, -13, -24, -2, 41, -26, -35, 73, -49, 1, 32, + -34, 20, -28, 22, -5, -16, 23, 18, -62, 47, 5, -57, 51, -15, -5, 0, + 4, 12, -11, -15, 29, -28, 4, 26, -44, 43, -19, -14, 35, -37, 23, -15, + -11, 45, -54, 17, 42, -67, 18, 47, -58, 17, 25, -35, 14, -6, 11, -3, + -42, 73, -50, -12, 67, -68, 28, -6, -4, 16, -44, 47, 8, -64, 80, -39, + -31, 54, -43, 14, -2, 11, -14, 4, -3, 19, -34, 0, 61, -98, 69, 12, + -61, 48, -35, 28, -12, -38, 85, -86, 42, 25, -76, 77, -31, -37, 39, -2, + -12, 7, -10, 16, -1, -33, 60, -48, -16, 70, -69, 13, 38, -43, 15, 0, + 0, 22, -65, 75, -28, -60, 96, -58, -8, 32, -6, 1, -11, 4, 17, -46, + 17, 46, -86, 66, 9, -69, 67, -21, -30, 33, -32, 42, -34, 1, 50, -74, + 40, 5, -34, 21, 7, -23, 21, -14, 10, -1, -33, 58, -48, -3, 65, -77, + 14, 51, -65, 32, -10, 0, 24, -58, 71, -27, -54, 86, -56, -12, 45, -17, + -18, 21, -1, -5, -14, 12, 19, -75, 78, 1, -80, 84, -25, -33, 48, -50, + 45, -30, -15, 69, -86, 46, 22, -56, 14, 36, -35, 2, 16, -11, 4, -24, + 41, -27, -19, 53, -42, -4, 49, -67, 36, 2, -26, 37, -46, 58, -40, -26, + 82, -70, -7, 55, -30, -20, 36, -1, -32, 11, 7, 7, -41, 39, 18, -68, + 65, -11, -39, 40, -34, 30, -20, -12, 70, -98, 53, 27, -74, 40, 10, -31, + 11, 20, -19, 6, -6, 12, -19, -9, 46, -36, -31, 83, -65, 8, 32, -48, + 42, -45, 49, -23, -32, 68, -59, 5, 39, -31, -1, 23, -20, -8, 17, -7, + -15, -1, 16, 25, -63, 51, 14, -66, 47, -10, -15, 5, -1, 36, -72, 54, + 22, -86, 64, -3, -31, 13, 11, -8, -12, 14, 15, -34, 6, 29, -24, -25, + 62, -49, -9, 49, -56, 45, -31, 18, 4, -37, 57, -41, -11, 38, -38, 7, + 24, -20, 10, -13, 20, -17, -8, 18, -4, -30, 35, 14, -63, 56, -7, -52, + 50, -5, -4, -19, 17, 36, -83, 51, 14, -52, 30, 4, 0, -15, 14, 8, + -43, 32, 3, -20, 2, 19, -11, -20, 45, -42, 14, 3, -5, 9, -31, 43, + -20, -30, 51, -24, -19, 47, -42, 21, -17, 25, -24, -20, 52, -37, 1, 20, + -6, -21, 25, -2, -33, 30, -9, -15, 23, -13, 26, -49, 29, 22, -76, 71, + -12, -37, 27, 4, 7, -41, 30, 10, -45, 28, 13, -13, -21, 31, -1, -33, + 27, 6, -18, -10, 24, -6, -26, 33, -10, -37, 72, -60, 24, 1, -13, 15, + -36, 52, -44, 18, 14, -31, 23, 2, -16, -8, 10, 23, -47, 19, 17, -10, + -17, 10, 29, -69, 56, -5, -38, 47, -28, 14, -21, 6, 32, -55, 33, 12, + -39, 24, 5, -11, -25, 31, 12, -47, 35, 9, -25, 1, 7, 5, -36, 57, + -52, 18, 29, -45, 37, -45, 35, -13, -17, 41, -31, 7, 8, -18, 15, -19, + 19, -22, 2, 33, -37, 20, -4, 2, -25, 27, 0, -34, 37, -13, -6, 3, + 1, 17, -46, 28, 32, -78, 60, -7, -25, 18, -6, 12, -35, 31, 4, -38, + 37, -11, -8, -13, 37, -22, -17, 32, -27, 25, -34, 24, 9, -43, 41, -19, + -1, 29, -48, 29, -6, -8, 10, -11, 27, -35, 18, 9, -19, -7, 12, 4, + -27, 30, 2, -24, 13, 7, -18, -1, 16, 11, -68, 77, -15, -45, 43, -24, + 29, -38, 16, 21, -43, 27, -7, -10, 11, 1, -4, -13, 26, -17, -1, 1, + -1, 3, -19, 34, -24, -13, 49, -51, 22, 3, -23, 29, -33, 28, -7, -15, + 31, -35, 2, 29, -28, -11, 27, -4, -18, 19, 2, -31, 26, -16, 17, -28, + 34, -3, -49, 64, -39, 6, 1, -8, 25, -38, 32, 4, -53, 47, 0, -32, + 16, 14, -1, -37, 31, -4, -7, -8, 9, 7, -20, 36, -34, 4, 25, -39, + 25, -13, 4, 12, -36, 51, -38, 0, 34, -51, 27, 13, -34, 14, 12, -9, + -23, 41, -21, -1, -16, 28, 10, -62, 66, -23, -26, 26, -9, 13, -29, 13, + 31, -62, 49, 1, -49, 49, -18, -7, 2, 14, -10, -19, 20, 5, -8, -17, + 37, -27, -5, 23, -35, 17, 15, -30, 30, -20, 28, -32, -5, 48, -64, 29, + 13, -37, 35, -10, -1, -7, -3, 14, -16, -9, 26, -5, -35, 48, -21, -21, + 40, -26, -11, 21, 3, 0, -42, 47, 8, -71, 72, -21, -21, 25, -15, 7, + -16, 14, -1, -24, 18, 32, -48, 12, 30, -46, 12, 26, -45, 36, -20, 18, + -3, -34, 52, -40, -2, 25, -29, 32, -11, -18, 18, -3, 3, -24, 7, 36, + -40, -10, 50, -35, -19, 47, -30, -4, 22, -17, 8, -22, 29, 4, -72, 85, + -21, -48, 57, -19, -8, -10, 17, 5, -31, 16, 24, -47, 29, 12, -31, 14, + 2, -27, 43, -26, 5, 13, -33, 48, -46, -6, 58, -67, 13, 45, -50, 26, + -6, -6, -2, -9, 24, -20, -7, 40, -37, -5, 36, -29, -17, 38, -21, 2, + -5, 6, 14, -52, 59, -11, -59, 82, -38, -22, 32, -11, -6, -4, 11, 14, + -38, 30, 5, -44, 24, 25, -37, 0, 21, 1, -9, -24, 49, -36, -12, 47, + -49, 20, 34, -70, 43, 6, -31, 21, -20, 24, -13, -10, 37, -35, -8, 37, + -26, -22, 44, -20, -13, 20, -7, 8, -28, 36, -15, -42, 79, -41, -28, 46, + -17, -8, -5, 5, 29, -44, 17, 24, -43, 20, 13, -42, 16, 37, -43, 5, + 22, 4, -31, 6, 26, -40, 11, 31, -45, 24, 9, -27, 26, -29, 26, -13, + -16, 38, -40, 19, 21, -37, -9, 51, -32, -18, 34, -11, -7, -11, 22, 0, + -40, 49, -20, -23, 44, -22, -9, 3, -2, 19, -44, 42, 6, -52, 41, 6, + -43, 20, 28, -48, 31, 8, -23, 10, -7, 7, -19, 4, 31, -41, 15, 28, + -40, 16, -8, 16, -25, -4, 51, -55, 19, 0, 8, -29, 29, -16, -11, 37, + -39, 18, 4, -6, -5, -14, 35, -6, -52, 72, -37, -9, 13, 11, -17, -22, + 53, -32, -20, 42, -19, -18, 12, 19, -29, 12, 12, -24, 15, -6, 6, -12, + -15, 54, -44, -2, 41, -48, 32, -20, -4, 9, 1, 5, -35, 48, -11, -17, + -9, 24, 1, -37, 38, -9, -16, 16, -2, -11, -1, 13, 11, -55, 67, -31, + -19, 37, -26, -4, 12, 16, -34, 11, 21, -22, -10, 12, 0, 0, -21, 37, + -16, -11, 29, -37, 15, -3, 17, -37, 13, 38, -54, 30, -2, -19, 11, -11, + 20, -20, 15, 4, -22, 13, 2, -8, -13, 20, 4, -28, 33, -9, -34, 38, + -13, -6, -14, 46, -33, -9, 36, -34, 4, 8, -9, 11, -9, 5, 1, -17, + 23, -16, -3, 4, 18, -26, -11, 54, -53, 5, 18, -5, -11, 8, 11, -20, + 12, -10, 1, 2, 5, -4, -5, -1, 23, -35, 22, -1, -25, 19, 3, -7, + -11, 22, 1, -37, 45, -26, -12, 20, 2, -23, 17, 13, -23, -4, 18, 1, + -15, -15, 33, 4, -49, 46, -25, 3, 5, 2, -11, 7, 13, -33, 13, 10, + -24, 12, 6, -3, -4, 12, -9, -10, -3, 20, -19, -3, 19, -2, -21, 16, + 5, -33, 35, -17, -3, 2, 17, -12, -21, 27, -17, -6, 19, -8, -6, 14, + -12, 10, -16, 13, 0, -19, 11, 20, -23, -9, 38, -50, 22, 17, -24, -5, + 17, 7, -24, 0, 23, -18, -14, 27, -15, 5, 6, -9, 1, -2, 7, -24, + 16, 10, -12, -9, 26, -19, -14, 30, -18, -13, 19, -10, 10, -8, 6, 1, + -27, 35, -13, -20, 26, -5, -11, -10, 28, -9, -32, 36, -3, -25, 12, 28, + -51, 36, -6, -20, 18, -2, -3, -1, -11, 28, -31, -4, 48, -56, 16, 19, + -18, 6, -4, 1, -10, 11, 0, -4, -6, 25, -26, -9, 30, -26, -6, 23, + -13, 10, -7, -3, 19, -56, 64, -30, -31, 50, -4, -31, 15, 15, -27, 6, + 13, -6, -14, 20, -2, -27, 23, 7, -30, 10, 19, -10, -1, -13, 27, -31, + 3, 38, -56, 29, 20, -45, 24, 5, -17, 0, 5, 3, -9, 2, 24, -25, + -14, 31, -13, -22, 28, -6, -8, 1, 3, 13, -41, 51, -39, -20, 60, -30, + -28, 48, -14, -26, 25, -10, 7, -17, 16, 5, -25, 13, 10, -32, 11, 35, + -46, 17, 10, 5, -32, 10, 21, -44, 19, 30, -39, 15, 7, -18, 11, -11, + 10, -13, 1, 19, -14, -12, 30, -25, -18, 43, -23, -15, 30, -13, -6, -14, + 43, -42, -9, 55, -36, -17, 43, -21, -11, 12, -13, 16, -28, 23, 10, -38, + 27, 17, -47, 22, 20, -46, 30, -7, 6, -10, -6, 26, -34, 15, 22, -39, + 15, 21, -43, 26, -6, 1, -14, 12, 20, -26, -12, 41, -29, -29, 57, -40, + 2, 27, -22, 8, -10, 10, -10, -10, 30, -14, -29, 47, -17, -24, 25, -11, + 3, -17, 30, -3, -32, 28, 7, -44, 35, 12, -46, 39, -6, -10, -2, -3, + 23, -31, -4, 49, -48, 6, 39, -55, 32, -8, -9, 0, 8, 7, -15, -3, + 29, -26, -16, 43, -44, 13, 26, -30, 9, 6, -5, 4, -28, 30, 9, -56, + 64, -19, -33, 43, -25, -8, 14, 8, -14, -8, 18, 11, -44, 23, 17, -39, + 20, 19, -24, -1, 12, 7, -27, -2, 47, -51, 3, 47, -55, 28, 1, -23, + 17, 4, -12, 5, -9, 18, -9, -21, 30, -24, 6, 12, -11, -2, 14, -13, + -3, -10, 26, -10, -45, 74, -31, -31, 51, -26, -14, 19, -8, 2, -4, 3, + 23, -43, 20, 15, -31, 13, 20, -36, 18, 9, -17, -3, 0, 21, -32, 12, + 32, -50, 21, 12, -26, 16, -6, 5, 1, -16, 21, -5, -27, 28, -11, -11, + 19, -2, -20, 28, -17, -2, 4, -5, 9, -26, 43, -31, -11, 47, -42, 1, + 19, -16, 5, -8, 12, 9, -41, 41, -7, -32, 22, 25, -51, 23, 14, -18, + 7, -21, 31, -22, -2, 24, -24, 6, 18, -39, 25, -9, 3, 5, -17, 28, + -13, -17, 27, -21, -12, 25, -12, -12, 32, -19, -6, 11, -24, 29, -21, 11, + -2, -17, 36, -29, -9, 24, -16, -2, 7, -6, 17, -27, 27, -20, -11, 23, + -1, -31, 25, 15, -32, 12, -8, 21, -22, -8, 26, -16, -15, 47, -45, 8, + 12, -12, 14, -28, 33, -10, -15, 15, -11, 6, 2, -17, 5, 23, -20, -5, + 19, -21, 12, -8, -8, 31, -38, 31, -17, -14, 31, -27, -1, 19, -20, 19, + -10, 4, -2, -7, 2, 1, -6, 6, 12, -27, 12, 8, -10, -7, 8, -1, + -3, -15, 47, -53, 15, 25, -40, 24, -7, 12, -13, -11, 22, -7, -22, 14, + 7, -5, -11, 13, 5, -8, -9, 4, 7, -22, 22, -12, 16, -9, -16, 29, + -32, 8, 23, -36, 14, 7, -3, 5, -27, 24, -1, -20, 14, 7, -7, -4, + 9, -21, 6, 23, -27, 7, -1, 23, -30, -3, 31, -39, 26, -17, -3, 30, + -24, 9, -7, -13, 30, -24, 3, 2, 9, -6, -15, 24, -18, 9, -20, 16, + 2, -8, 11, -11, 6, -10, 6, 11, -38, 27, 20, -42, 28, -26, 35, -21, + -29, 51, -32, 8, -3, 15, -19, 3, 14, -33, 24, 4, -9, -9, 4, 23, + -29, 0, 21, -32, 39, -38, 20, 8, -34, 38, -27, 8, 12, -12, 3, -8, + 11, -11, 1, 3, -9, 18, -18, 10, 0, -7, 4, -13, 17, -13, 0, 33, + -56, 42, -11, -7, 7, -17, 36, -50, 24, 21, -25, -7, 14, 9, -27, 8, + 23, -28, 3, 8, 2, -12, -10, 39, -43, 24, -4, -5, 18, -38, 39, -26, + -8, 26, -24, 14, 10, -20, 5, -9, 15, -19, 13, -12, 5, 24, -39, 24, + -8, 8, -16, -14, 53, -49, 16, 5, -22, 26, -28, 18, -13, 7, 18, -31, + 6, 17, -12, -13, 3, 26, -35, 16, 18, -36, 21, -12, 28, -49, 27, 22, + -38, 13, -1, 17, -28, -5, 30, -22, 2, 25, -42, 32, -19, 18, -23, -1, + 21, -20, 22, -31, 25, 3, -25, 9, -6, 27, -29, -3, 32, -35, 19, -7, + -8, 11, -12, 28, -35, 1, 39, -33, -6, 2, 30, -35, -1, 41, -42, 18, + -9, 6, -8, -2, 26, -46, 24, 24, -41, 11, 11, -2, -12, -9, 48, -59, + 31, -10, 6, -12, -5, 34, -43, 33, -12, -7, 11, -11, 1, 7, -12, 17, + -23, 32, -24, -5, 19, -26, 27, -28, 24, -15, -5, 31, -41, 11, 11, -4, + -19, 10, 37, -53, 2, 43, -35, 2, -3, 20, -20, 3, 32, -53, 30, 5, + -24, 10, -7, 41, -53, 10, 33, -31, -8, 11, 12, -30, 28, 4, -37, 28, + 8, -30, 12, -17, 42, -38, 5, 24, -33, 35, -41, 23, -1, -4, 5, -20, + 32, -18, -10, 25, -22, -4, 14, 6, -24, -5, 62, -80, 28, 19, -20, 4, + -14, 41, -49, 14, 34, -45, 3, 13, 17, -37, -4, 66, -61, -5, 35, -15, + -5, -2, 14, -24, 21, 5, -41, 41, -22, 18, -24, 5, 44, -66, 34, -3, + -17, 24, -26, 20, -13, 14, -1, -31, 39, -19, -20, 31, -14, 0, -12, 46, + -61, 29, 19, -44, 36, -26, 30, -31, -7, 49, -41, -15, 54, -42, -1, 12, + 24, -48, 8, 44, -57, 17, 13, 7, -34, 13, 33, -55, 28, 4, -14, 4, + -9, 32, -42, 15, 28, -58, 40, -12, 0, 7, -8, 8, -24, 29, -9, -29, + 38, -23, 9, -8, 13, -7, -14, 24, -37, 32, -7, 3, -17, 1, 39, -46, + -20, 78, -68, 15, 17, -6, -4, -15, 37, -47, 15, 20, -17, -12, 28, 9, + -52, 25, 31, -54, 24, 4, -1, -11, -5, 51, -74, 36, 9, -27, 17, -6, + 8, -12, 3, 6, -16, 14, 0, -15, 10, 3, 7, -31, 34, -22, -2, 17, + -20, 9, 10, -7, -13, -5, 45, -52, 8, 30, -33, 15, -11, 28, -32, -5, + 44, -42, -4, 42, -25, -29, 29, 14, -36, 12, 19, -20, 8, -14, 33, -42, + 16, 23, -48, 32, 2, -14, 2, -1, 14, -21, -9, 42, -47, 24, 0, -10, + 0, 15, -19, -1, 21, -31, 13, 15, -23, 10, -14, 20, -7, -27, 50, -32, + -5, 18, -10, -1, -8, 25, -36, 12, 34, -45, 6, 27, -20, -16, 12, 19, + -22, 0, 12, 0, -13, -8, 31, -41, 17, 16, -29, 17, 11, -19, -4, -2, + 36, -55, 30, 13, -35, 25, -7, -8, 10, -4, -8, 13, -7, 0, 4, -16, + 8, 13, -35, 40, -25, -6, 44, -51, 17, 15, -18, -3, 1, 14, -18, -1, + 24, -23, -9, 20, -6, -9, 1, 24, -30, 6, 6, 10, -29, 8, 31, -48, + 21, 27, -43, 13, 4, -4, -5, -2, 19, -18, 12, -15, 4, 16, -25, 9, + 1, 2, 0, -13, 12, 3, -16, -3, 18, -10, -6, 25, -41, 21, 11, -30, + 20, -3, 0, 1, -14, 27, -19, -21, 38, -28, 9, -3, 14, -22, 13, -4, + -2, -6, 12, 2, -26, 30, -1, -38, 31, 7, -32, 25, -16, 14, -4, -9, + 15, -19, 6, 4, -11, 2, 11, -8, -4, 10, -7, -4, 6, -10, 2, 11, + -9, 0, -5, 15, -16, 0, 9, -2, -7, 0, 11, -11, -12, 35, -44, 20, + 13, -19, 2, 13, -11, -14, 12, 10, -22, -2, 27, -24, -2, 15, 5, -29, + 22, -10, 6, -2, -3, 16, -31, 20, 11, -39, 29, 9, -34, 25, -10, 5, + -2, -15, 14, 0, -5, -6, 19, -18, 13, -22, 5, 24, -30, -1, 35, -23, + -12, 12, 12, -26, 5, 22, -32, 16, 16, -27, 2, 10, -4, -12, 2, 23, + -19, -1, 1, 11, -17, 4, 8, -18, 12, 12, -24, 1, 24, -20, -15, 29, + -5, -31, 42, -23, -8, 20, -18, 19, -33, 24, 8, -22, 0, 32, -38, 9, + 21, -25, 2, 23, -30, 7, 16, -20, 12, -10, 8, -14, 12, 16, -41, 24, + 14, -30, 6, 2, 19, -22, -6, 25, -8, -24, 23, -1, -29, 32, 9, -53, + 50, 4, -42, 12, 12, 3, -24, 15, 14, -25, 5, 4, 7, -25, 26, -5, + -23, 28, 0, -32, 23, -1, -21, 14, 10, -7, -13, 21, -25, 16, -8, 1, + -1, -1, 13, -22, 12, 12, -28, 3, 13, 1, -15, -3, 38, -41, -5, 45, + -37, -9, 30, -4, -35, 42, -10, -25, 19, -4, 3, -18, 12, 22, -43, 25, + 14, -37, 21, 4, -19, 5, 17, -12, -17, 26, -4, -22, 11, 7, 6, -31, + 35, -15, -14, 22, -14, 0, 0, 14, -16, -12, 31, -17, -19, 25, -10, 0, + 2, 12, -23, 8, 16, -44, 37, 0, -19, -2, 21, -5, -25, 22, 12, -38, + 3, 37, -11, -38, 36, 11, -54, 40, -9, -11, 14, -11, 11, -19, 17, 17, + -47, 16, 25, -17, -23, 34, -3, -29, 25, -17, 5, 14, -17, 3, -4, 21, + -23, -11, 35, -31, 7, 13, -17, 13, -6, 6, -22, 13, 5, -8, -8, 16, + 8, -34, 18, 21, -49, 32, 12, -45, 32, 0, 1, -32, 27, 2, -20, 10, + 6, 3, -26, 18, 19, -50, 31, 13, -40, 20, 12, -7, -19, 21, -9, -12, + 24, -21, 6, 7, -6, -2, -9, 23, -19, -8, 15, -7, 18, -26, 13, 5, + -21, 21, -19, 4, 25, -26, -14, 32, -2, -33, 21, 8, -29, 38, -35, 17, + 8, -19, 15, -29, 24, 15, -40, 10, 28, -21, -26, 34, 7, -42, 35, -3, + -14, -1, 18, -6, -30, 29, -1, -11, 8, -8, 16, -22, -2, 25, -27, 14, + 0, -9, 1, 9, 1, -25, 22, -16, 12, 8, -33, 32, 2, -35, 19, 4, + 0, -17, 15, 1, -6, 9, -15, 16, -30, 25, 8, -46, 40, 11, -39, 8, + 11, 2, -21, 10, 11, -17, 15, -6, -4, -10, 18, -6, -23, 29, -2, -7, + -13, 9, 24, -48, 23, 17, -30, 27, -22, 9, 4, -16, 8, 4, -9, -2, + 19, -12, -12, 21, -22, 15, -8, -2, 20, -39, 32, -5, -16, 11, 5, -15, + -8, 30, -5, -36, 34, -5, -13, 1, 3, 22, -37, 14, 6, -8, 0, -6, + 11, -17, 23, -6, -18, 19, -7, -4, -14, 11, 17, -32, 24, -6, -2, 9, + -26, 30, -24, 2, 18, -19, 7, 4, -6, -3, -1, 3, 1, 0, -21, 39, + -20, -33, 51, -27, -6, 24, -18, 8, -10, 12, -3, -23, 25, -11, 5, -19, + 25, 2, -34, 29, -5, -9, -7, 18, -12, -18, 30, -4, -26, 20, -9, 22, + -32, 7, 26, -28, 6, -9, 19, -20, 5, 2, -9, 26, -15, -13, 18, -19, + 15, -3, -26, 34, 2, -33, 6, 36, -36, -12, 36, -32, 29, -24, 10, 13, + -39, 30, -6, -17, 12, 9, -9, -17, 28, -6, -27, 21, 4, -15, 6, 13, + -13, -16, 30, -21, 1, -4, 4, 28, -60, 46, -3, -21, 3, 5, -8, 17, + -17, 3, 11, -6, -9, 11, -8, -17, 44, -36, 0, 20, -9, -4, -13, 29, + -24, 5, -3, 6, 14, -36, 26, -3, -23, 30, -3, -30, 25, 3, -12, -22, + 42, -13, -27, 19, 9, -3, -20, 16, -7, -3, 7, -5, 6, -13, 22, -21, + -15, 39, -17, -21, 30, -23, 19, -6, -20, 31, -24, 0, 8, 12, -31, 20, + 8, -27, 20, -14, 20, -22, -2, 17, 0, -18, 11, 0, 7, -28, 22, -2, + -19, 31, -17, -8, -2, 28, -24, -16, 34, -4, -28, 9, 26, -12, -30, 29, + -7, -6, 10, -1, -10, 5, -3, 6, -23, 29, -18, 10, -16, 7, 28, -48, + 21, 4, -12, 9, 4, -12, 5, -1, -7, 2, 0, -3, 11, -15, -3, 26, + -19, -4, 3, 1, 10, -37, 49, -26, -9, 6, 18, -23, 0, 17, -3, -27, + 25, 3, -22, 10, 6, -3, -19, 32, -23, 9, -3, -3, 11, -31, 27, 12, + -42, 23, 13, -12, -18, 30, -10, -19, 13, -4, 0, 17, -25, 12, -2, -2, + 4, -8, 9, -12, 8, -17, 24, -2, -19, 14, -16, 18, -6, -12, 22, -12, + -17, 20, 0, -4, -13, 19, -5, -18, 30, -19, 8, -17, 19, -9, -6, 8, + 1, 1, -36, 48, -9, -40, 46, 1, -50, 44, -5, -14, -3, 10, 4, -17, + 11, -1, 11, -25, 9, 10, -24, 19, 2, -9, -4, 4, 10, -26, 20, -8, + 6, -3, -12, 17, 7, -31, 18, -14, 17, -7, 0, 2, -8, 9, -15, 19, + -16, 8, 2, -22, 21, 15, -33, 4, 24, -20, -13, 36, -18, -24, 33, -16, + -8, 20, -19, 22, -32, 21, 0, -5, -7, 18, -17, -11, 26, -5, -25, 25, + 3, -17, -3, 15, 7, -35, 22, -3, 2, -2, -6, 7, -3, -4, 4, -13, + 25, -17, 1, -4, 7, -12, 13, -2, -11, 12, 2, -25, 24, 0, -25, 17, + -4, 6, -9, 14, -11, -8, 5, 0, 10, -25, 23, 1, -28, 27, 5, -26, + 0, 23, -11, -20, 21, 10, -30, 12, 9, -5, -16, 25, -12, -19, 26, -3, + -12, 1, 9, -1, -15, 11, 3, -12, 6, -5, 11, -7, -8, 6, 3, -11, + 4, 5, 0, -11, 7, -1, 6, -17, 1, 26, -35, 14, 6, -6, -8, 15, + -7, -9, 13, -2, -20, 19, 6, -11, -14, 24, 7, -36, 19, 11, -24, 1, + 23, -18, -4, 18, -10, -19, 29, -10, -9, -1, 6, 10, -23, 10, 19, -32, + 11, 11, -4, -13, 5, 12, -17, 3, 13, -20, 11, 0, -8, 5, 14, -32, + 19, 1, -22, 28, -16, -8, 13, 3, 0, -11, -10, 38, -40, 3, 22, -9, + -16, 19, -4, -13, 13, 9, -29, 9, 16, -9, -20, 25, -2, -22, 11, 6, + 4, -22, 12, 16, -35, 15, 26, -42, 13, 12, -5, -20, 24, -4, -18, 20, + -7, -11, 9, 5, -7, 1, -2, -2, 10, -18, 9, 11, -17, -2, 7, -5, + 28, -48, 12, 31, -36, 12, 8, -2, -14, 8, 2, -5, -1, 11, -17, -4, + 21, -1, -27, 19, 3, -13, 0, 8, 15, -39, 19, 17, -43, 34, 4, -32, + 16, 8, -10, -8, 21, -10, -12, 6, 9, -4, -10, 3, 9, -13, 8, 2, + -7, 1, 1, 2, -18, 22, -10, 2, 5, -19, 19, -4, -11, 11, -5, 2, + -13, 7, 15, -24, 9, 11, -20, -2, 21, 1, -38, 21, 9, -2, -22, 23, + 6, -41, 34, -2, -19, 27, -10, -23, 20, -3, 13, -34, 20, 10, -15, -3, + 14, -1, -19, 3, 4, 5, 8, -14, 9, -18, 18, -1, -22, 24, -8, -8, + 10, -10, 14, -12, -4, 6, -14, 30, -38, 28, -5, -23, 19, 4, -10, -9, + 22, -7, -22, 17, 8, -5, -19, 25, -9, -23, 31, -6, -26, 31, -20, 18, + -29, 22, 20, -54, 33, -4, 1, -3, 4, -8, 0, -5, 13, -6, -6, 9, + -1, -24, 36, -9, -26, 30, -24, 11, 8, -23, 22, -16, 5, -11, 20, -2, + -26, 23, -9, -3, 0, 9, -10, -6, 13, -3, -17, 25, -12, -2, -8, 16, + 4, -35, 39, -14, -9, -2, 23, -6, -37, 40, -12, -11, 4, 8, 1, -13, + 1, 17, -26, 12, 10, -27, 17, 4, -6, -18, 42, -32, 2, 4, -16, 36, + -31, 0, 10, 0, -1, -12, 15, 0, -28, 22, -3, -1, 6, -6, -9, -3, + 25, -18, -8, 7, 6, 5, -39, 48, -16, -23, 22, -2, -8, 1, 18, -25, + -9, 25, 1, -28, 16, 9, 0, -34, 37, -4, -27, 27, -18, -1, 6, 4, + -5, -8, 16, -9, 10, -21, 6, 12, -14, -4, 6, 9, 3, -31, 33, -14, + -12, 23, -28, 25, -10, 2, -11, 1, 11, 6, -30, 3, 40, -21, -34, 46, + -12, -22, 11, 6, -2, -10, 14, -10, -21, 49, -29, -16, 17, 9, -15, -13, + 32, -19, 0, 0, 8, 0, -14, 8, -4, -16, 30, -17, 2, -1, 0, 9, + -15, 6, -4, 11, -15, -6, 28, -28, 17, -18, 7, 11, -19, 12, 3, -24, + 21, 3, -29, 15, 26, -25, -27, 51, -18, -19, 7, 20, -21, -11, 36, -32, + -3, 35, -27, -4, 6, 8, 2, -31, 18, 18, -29, 1, 25, -16, -8, 19, + -30, 13, 16, -20, 8, -12, 19, -3, -21, 15, 0, -6, -3, 4, 6, 1, + -20, 2, 20, -5, -27, 31, -7, -21, 19, 6, -19, -10, 40, -28, -17, 40, + -15, -22, 12, 13, -23, 6, 14, -12, -7, 10, 11, -11, -30, 45, -9, -44, + 48, -5, -14, -5, 20, -22, 9, 3, -10, 0, 4, 4, -7, -9, 24, -23, + 3, 8, -15, 15, -2, -19, 21, -8, -6, -1, 14, -7, -12, 18, -10, -3, + 3, 21, -37, 2, 29, -23, -7, 22, -10, -2, -7, 20, -10, -20, 15, 5, + -25, 17, 23, -29, -16, 50, -35, -9, 19, 4, -22, 2, 24, -19, -10, 25, + -9, -22, 23, 3, -15, -6, 10, -4, 13, -29, 17, 13, -26, -2, 25, -23, + 14, -16, 12, -2, -2, 4, -11, 1, 11, 0, -22, 14, 18, -28, -6, 11, + 22, -29, -10, 42, -30, -12, 26, -12, -15, 19, 15, -41, 10, 33, -16, -32, + 20, 29, -47, 10, 36, -35, -1, 20, -19, 1, 9, 5, -14, -16, 15, 29, + -38, -6, 35, -16, -20, 18, 6, -9, -7, 1, 4, 6, -4, 0, -9, 2, + 8, 2, -14, -4, 24, -12, -32, 41, -1, -26, 1, 23, -22, 4, 11, -10, + -6, 8, 16, -28, -12, 52, -28, -40, 53, 2, -29, 2, 17, -10, -5, -2, + 8, -1, -13, 25, -10, -33, 51, -16, -32, 12, 29, -27, -11, 25, 7, -27, + 4, 12, 0, -15, 5, -2, 4, -11, 11, 21, -51, 15, 37, -46, 7, 24, + -9, -20, 2, 27, -11, -17, 4, 22, -40, 26, 16, -36, 2, 35, -32, -2, + 12, 14, -23, -17, 26, 10, -26, 3, 20, -20, -9, 28, -16, -9, 19, -4, + -21, 15, 12, -17, -15, 24, -7, -6, 5, -2, 10, -21, 4, 12, -9, -11, + 30, -12, -32, 38, 3, -33, 11, 11, 0, -24, 4, 44, -37, -18, 36, -8, + -25, 21, 5, -24, 10, -1, 18, -22, -2, 30, -38, -8, 41, -24, -3, 4, + 8, -6, -11, 20, -11, -20, 22, -2, 2, -8, 8, -12, 8, -17, 11, 18, + -34, 19, -4, 5, -3, -9, 5, -6, 6, -4, -6, 17, -5, -11, 2, 12, + -8, -16, 15, 3, -21, 13, 8, -7, -8, 12, -5, -5, -17, 33, -1, -44, + 35, 15, -42, 18, 15, -21, 4, -4, 10, -5, -14, 27, -21, -7, 19, 1, + -3, -8, -6, 9, -1, -23, 29, -13, -1, -2, 4, 8, -6, -20, 26, -22, + 5, 21, -25, 9, 3, -11, 16, -12, -4, 20, -20, -8, 25, -13, -5, 6, + -11, 13, 6, -30, 13, 24, -31, -11, 27, 9, -43, 28, 2, -3, -5, -4, + 13, -16, -1, 10, -8, -4, 11, 8, -23, 14, 0, -4, -10, 1, 14, -14, + 3, 2, -3, 20, -35, 26, -6, -25, 38, -32, 12, -10, 16, -10, 14, -24, + 9, 33, -83, 72, -13, -27, 28, -26, 25, -13, 8, -25, 18, 15, -29, 17, + -3, 9, -25, 2, 19, -20, 18, -20, 13, 4, -18, 32, -32, -10, 35, -18, + -12, 16, 10, -15, -5, 4, 13, -21, 1, 0, 14, -18, 9, 12, -26, 27, + -27, 9, 1, -4, -1, 1, 14, -33, 52, -49, -1, 46, -50, 21, -5, 12, + -9, -7, 6, 1, -2, -10, 14, -2, -10, 13, -19, 23, -26, 18, -2, -22, + 34, -30, 8, 20, -38, 14, 18, -18, -5, 9, 3, -6, -13, 24, -1, -28, + 12, 11, -14, -1, 21, -37, 31, -16, 5, 6, -26, 32, -23, 4, 2, 9, + 2, -40, 40, -7, -10, 2, 0, 9, -16, -1, 16, -3, -10, -3, 19, -22, + 6, 7, -9, -4, -10, 39, -38, 5, 27, -28, 0, 13, -8, 1, -3, 5, + -3, -9, 13, -8, -4, 13, -14, -6, 22, -14, -13, 31, -30, 22, -15, -15, + 55, -56, 6, 26, -23, 8, 1, 4, -17, 8, 6, -9, 9, -11, 15, -18, + 5, 14, -18, 9, -22, 26, -2, -23, 25, -11, 1, -16, 15, 12, -28, -4, + 35, -31, -3, 28, -8, -12, -8, 26, -21, -1, 3, -2, 12, -18, 18, -3, + -6, -9, 14, -23, 9, 36, -57, 29, 21, -50, 29, -2, -13, 7, 0, -5, + 6, -1, -4, 10, -25, 23, -3, -19, 28, -20, 11, -17, -5, 37, -39, 19, + -7, 1, 7, -17, 12, 14, -36, 6, 23, -23, 9, 12, -19, 4, 2, 2, + 6, -27, 14, 17, -39, 14, 34, -22, -31, 34, 6, -36, 28, -1, -28, 24, + 1, -18, 24, -20, 9, -2, -15, 21, -4, -23, 23, -10, -4, 15, -12, 3, + -6, 2, 10, -28, 28, -6, -15, 14, -14, 10, 1, -18, 14, 5, -19, 15, + 2, -18, 22, -17, -7, 29, -43, 45, -15, -40, 62, -27, -23, 23, 10, -20, + -20, 41, -7, -20, 9, 10, -22, 8, 5, 9, -21, 0, 22, -11, -18, 27, + -4, -34, 30, 3, -9, -2, 1, 4, -13, 6, 16, -25, 11, -11, 8, 1, + -11, 14, -4, -6, 4, 1, -2, -7, 1, -3, 11, -31, 57, -36, -10, 37, + -44, 22, -2, -10, 4, -1, 7, -2, -7, 7, 14, -33, 5, 24, -29, 7, + 10, -1, -13, 0, 26, -23, -16, 43, -32, -14, 23, 11, -23, -5, 13, 13, + -44, 44, -7, -18, 7, -7, 12, -12, -1, -1, 7, 0, -6, 26, -37, 17, + -6, 4, -19, 18, 13, -37, 24, 4, -7, 0, -13, 15, 3, -28, 22, 14, + -41, 27, 5, -28, 38, -30, 9, -6, -1, 18, -28, 8, 26, -36, 4, 21, + -3, -30, 28, -6, 1, -26, 45, -28, -15, 34, -15, -12, 6, 8, 1, -9, + -16, 26, 1, -50, 65, -34, -12, 25, -9, 4, -14, 21, -17, -2, -6, 10, + 17, -29, -6, 40, -23, -20, 27, 0, -40, 44, -27, 16, -6, 2, 3, -20, + 15, 15, -32, -1, 28, -9, -29, 38, -22, 14, -21, 16, -5, -6, 17, -35, + 20, 13, -19, 0, 2, 2, 16, -32, 0, 47, -61, 16, 31, -37, 21, -8, + 6, -7, 3, -6, 8, -9, -12, 29, -13, -20, 33, -16, 0, -21, 46, -39, + 2, 17, -3, -11, -6, 18, 2, -35, 29, 17, -37, 0, 42, -42, 9, -3, + 16, -19, -2, 24, -17, -2, 0, -1, 6, -12, 19, -12, -16, 27, -2, -27, + 16, 17, -42, 38, -22, 8, 2, -12, -1, 15, -18, 13, -6, -11, 7, 21, + -36, 26, -23, 38, -48, 15, 26, -20, -18, 24, -1, -4, -20, 34, -16, -17, + 18, 11, -30, 15, 7, -10, -10, 12, 15, -31, -1, 28, -6, -32, 30, 4, + -24, 1, 28, -28, 7, -11, 33, -39, 23, -15, 19, -12, -12, 11, 4, -25, + 33, -22, 14, -4, -3, -6, 10, -21, 31, -40, 19, 13, -10, -1, 14, -18, + -3, 10, -4, -5, -2, 10, -6, -14, 21, 14, -40, 15, 6, 3, -31, 28, + 12, -42, 11, 43, -44, 2, 27, -17, -18, 22, -16, 33, -59, 37, 15, -35, + 11, 20, -22, 1, -7, 22, -22, 7, -1, 9, -16, -4, 20, 3, -38, 31, + 9, -31, -3, 39, -34, 8, 4, -19, 41, -41, 11, 21, -40, 19, 18, -47, + 45, -14, -5, -13, 26, -4, -28, 19, 15, -45, 38, -4, -9, -4, 17, -29, + 28, -27, 34, -25, -20, 39, 5, -52, 49, -15, -13, 5, -3, 14, -2, -20, + 17, -3, -12, 18, -7, -9, 1, 10, 7, -31, 19, 13, -29, 12, -22, 52, + -30, -28, 40, 7, -60, 56, -19, -5, -5, 22, -26, 13, 1, 5, -28, 30, + -12, 3, -17, 25, -26, 16, -16, 20, -5, -14, 26, -19, -33, 67, -47, 2, + 20, -19, 21, -22, 12, 12, -25, 0, 17, -26, 24, -4, -15, 6, 9, -8, + 13, -28, 24, -15, 13, -27, 26, 3, -11, -31, 61, -31, -19, 24, 5, -33, + 22, -3, 14, -35, 22, 10, -28, 8, 23, -24, -2, 1, 18, -18, -8, 26, + -15, -12, 26, -31, 15, 10, -24, 18, -19, 35, -32, -1, 15, 7, -40, 36, + -14, -4, 16, -12, -22, 51, -54, 41, -31, 14, 4, -17, 5, 13, -24, 29, + -31, 12, 25, -34, -2, 30, -36, 21, -16, 22, -4, -36, 42, -11, -6, -12, + 31, -16, -29, 34, 6, -29, -4, 37, -23, -25, 51, -34, 9, -11, 23, -25, + 14, -8, 5, -20, 32, -22, 6, 14, -16, -3, 24, -49, 51, -46, 31, -4, + -21, 26, -13, 0, 7, -9, -2, -1, 8, -21, 22, -21, 29, -29, 10, 22, + -41, 37, -24, -7, 15, 3, -25, 26, 1, -15, 5, 2, 14, -33, -3, 54, + -69, 27, 13, 5, -37, 27, 4, -6, -19, 19, -3, -9, 2, 10, -11, 15, + -30, 38, -35, 20, 0, -29, 37, -16, 1, -14, 21, -12, -7, 22, -33, 30, + -19, 4, -7, -1, 31, -57, 46, -15, -8, 20, -21, -1, 18, -21, 17, -12, + 6, 7, -20, 2, 32, -57, 46, -7, -25, 12, 25, -32, -3, 18, 1, -12, + -15, 31, 4, -56, 52, -11, -6, -20, 23, 19, -50, 37, -7, -9, -1, 14, + -22, 10, 14, -36, 37, -18, -8, 25, -31, 20, -16, 21, -26, 10, 7, -15, + 9, 3, -14, 19, -25, 24, -15, -4, -4, 27, -37, 21, 7, -12, 1, -5, + 4, 5, -12, -4, 10, -12, 17, -10, -16, 52, -56, 5, 29, -12, -5, -28, + 56, -30, -19, 34, -3, -30, 20, 4, -21, 12, 9, -17, 21, -35, 43, -19, + -20, 21, -4, -13, 12, -10, 9, 0, -6, -4, 10, -19, 25, -23, 6, -3, + 10, -5, -15, 31, -12, -14, -4, 22, -15, -5, 1, 17, -17, -8, 28, -15, + -8, 6, -10, 2, 7, 8, -31, 25, 3, -20, -2, 26, -10, -22, 12, 20, + -25, 6, -11, 33, -36, -2, 43, -36, -8, 20, -9, -7, 2, 4, 5, -7, + -5, 24, -28, 11, 6, -24, 20, -7, -2, 6, -9, -1, 20, -35, 13, 27, + -31, -7, 31, -13, -12, -6, 27, -14, -24, 33, -6, -10, 15, -14, 6, -13, + 9, 0, -8, -1, 19, -20, 6, 10, -9, -15, 23, -20, -4, 31, -24, 2, + -13, 23, 1, -25, 14, 12, -16, -18, 25, 4, -25, 15, -3, 2, 6, -16, + 21, -12, -19, 19, 1, -18, 21, 1, -30, 25, 3, -15, -5, 6, 18, -34, + 4, 32, -13, -18, 1, 28, -21, -30, 44, -1, -41, 28, 16, -32, 9, 14, + -17, 6, -11, 5, 21, -43, 38, -11, -24, 39, -15, -18, 18, -3, -15, 0, + 20, -15, 2, -1, -6, 32, -43, 13, 19, -26, -3, 17, 10, -29, 19, 1, + -19, 22, -13, 7, -16, 10, 8, -17, -1, 12, 1, -18, 1, 40, -49, 6, + 34, -35, -8, 30, -2, -23, 4, 15, 12, -39, 2, 55, -57, -8, 47, -27, + -7, 18, -7, 2, -11, 0, 19, -21, 4, 2, 10, -32, 34, -16, -12, 20, + -12, 2, -4, 20, -12, -22, 22, -14, 9, -12, 6, 21, -24, -7, 27, -13, + -22, 13, 16, -38, 37, -2, -21, 19, -14, 2, -6, 6, 7, -16, -11, 44, + -22, -35, 52, -10, -41, 24, 16, -13, -19, 14, 21, -20, -29, 55, -20, -21, + 5, 28, -30, -3, 22, -6, -10, 5, 11, -11, -7, 15, -11, -4, -10, 18, + 1, -23, 24, 3, -24, 10, 5, 0, -32, 35, -7, -12, 1, 11, 18, -53, + 36, 7, -26, 0, 24, -27, 0, 26, -24, 6, 6, -13, 16, -21, 13, 1, + -25, 20, 26, -61, 40, 21, -41, -6, 28, 1, -24, -7, 38, -14, -25, 20, + 5, -16, -1, 6, 13, -20, -7, 39, -33, -8, 25, -14, 5, -20, 26, 2, + -28, 14, 14, -18, -23, 64, -60, 11, 24, -9, -13, -2, 17, -5, -25, 16, + 22, -13, -44, 61, -14, -38, 35, -7, -18, 28, -16, -10, 25, -9, -20, 8, + 6, 8, -23, 11, 19, -27, -1, 15, 0, -25, 18, 8, 2, -34, 38, 1, + -41, 23, -7, 13, -6, -19, 45, -20, -27, 24, 14, -61, 53, -13, -13, 21, + -21, 36, -25, -33, 58, -33, -26, 35, 19, -50, 7, 50, -35, -20, 28, 5, + -29, -1, 28, -20, 3, -10, 20, -8, -16, 35, -22, -13, 17, -10, -3, 15, + -25, 24, -7, 0, -8, -3, 29, -32, -7, 30, -16, 9, -29, 24, 10, -27, + -9, 49, -40, 4, 14, -28, 37, -29, -18, 68, -67, 12, 45, -48, 3, 31, + -21, -16, 9, 20, -3, -40, 38, 17, -65, 41, 8, -15, -9, -2, 46, -51, + -7, 64, -51, -31, 57, -21, 5, -10, -7, 35, -36, 0, 20, -20, 14, -16, + 10, 9, -1, -26, 26, -18, -3, 5, 14, -8, -17, 32, -25, 1, 17, -29, + 17, 17, -47, 50, -19, -12, 9, -1, -11, 17, -29, 44, -25, -36, 63, -32, + -18, 29, -7, 9, -38, 32, 14, -50, 21, 37, -57, 13, 37, -17, -16, -9, + 28, -6, -60, 76, -13, -34, 29, 1, -5, 9, -41, 35, -2, -48, 52, -5, + -3, -17, 14, 5, -12, -13, 24, -20, 7, -4, 10, 2, -13, 10, -2, -18, + 20, 2, -33, 37, -18, -9, 25, -21, 14, -15, 9, -2, -14, 15, 10, -44, + 37, 7, -36, 15, 18, -9, -21, 2, 45, -53, 3, 47, -48, 3, 25, -17, + 14, -24, -2, 53, -72, 22, 38, -32, -13, 22, -15, 30, -36, 6, 27, -30, + -4, 21, -3, -20, 8, 13, -3, -29, 43, -10, -41, 33, -14, 20, -22, 9, + 13, -14, -10, 25, -30, 14, 6, -29, 29, 2, -23, 4, 14, -15, -3, 13, + 11, -29, 21, -1, -25, 13, 5, 1, -9, -18, 58, -31, -44, 56, 7, -69, + 46, -10, 11, -3, -27, 41, 1, -58, 46, 7, -33, 14, -14, 30, -22, -24, + 77, -66, 6, 6, 27, -36, -2, 21, 10, -62, 57, 11, -46, 23, 7, -8, + -18, 24, -21, 17, -35, 40, -4, -31, 36, -13, -10, 0, -2, 2, 0, 2, + -14, 18, 22, -53, 11, 43, -45, -13, 39, -7, -12, -6, 22, -8, -27, 19, + 15, -35, 13, 21, -30, 26, -35, 40, -17, -11, -5, 33, -25, -4, -9, 32, + -10, -44, 65, -23, -18, 0, 28, -31, 17, -23, 45, -50, 11, 52, -68, 13, + 23, -10, -32, 41, -13, 4, -13, 5, 9, -11, 4, -8, 6, 12, -25, 4, + 24, -20, -15, 11, 30, -42, 5, 30, -7, -40, 27, 17, -27, -5, 14, 16, + -26, -9, 39, -23, -11, 17, -16, 30, -52, 43, -9, -4, -28, 31, 4, -15, + -15, 34, 6, -69, 65, -3, -40, 6, 42, -40, 8, 11, 18, -29, -28, 62, + -40, -17, 31, 2, -22, 20, -13, 16, -18, 0, -6, 12, -4, -10, 17, 0, + -6, -25, 44, -25, -6, 0, 24, -13, -33, 43, 1, -46, 36, 3, 0, -34, + 38, -11, -14, 5, -11, 30, -19, 3, -12, 45, -56, -3, 41, -20, -21, 17, + 22, -18, -15, 14, 37, -92, 53, 25, -48, -2, 57, -44, -4, 3, 35, -31, + -32, 59, -24, -17, 9, 28, -39, 22, -10, 9, -7, 0, 7, -29, 33, -16, + -17, 37, -24, -17, 43, -14, -28, 18, 18, -33, 5, 4, 21, -34, 13, 4, + -6, 7, -15, 14, -8, 11, -17, -1, 15, 0, -42, 58, -18, -35, 37, 14, + -47, 9, 27, -14, -33, 20, 58, -79, 11, 49, -18, -55, 58, -6, -29, 6, + 12, 16, -55, 61, -29, -20, 37, -15, -1, 9, -26, 22, 3, -25, 0, 31, + -18, -1, -12, 40, -11, -64, 62, -11, -23, 3, 32, -11, -18, 19, 5, -36, + 15, 11, -21, 6, 18, -16, 5, 16, -35, 14, -2, 19, -53, 45, 31, -81, + 31, 46, -51, -14, 44, -13, -23, -11, 67, -62, -3, 50, -23, -26, 24, 16, + -34, -2, 3, 27, -33, 1, 38, -35, 13, 0, -24, 50, -59, 11, 31, -20, + -6, 10, 20, -28, -15, 38, -2, -60, 43, 32, -68, 24, 47, -54, 9, 3, + 23, -46, 11, 36, -56, 34, -2, -20, 12, 24, -36, 9, 7, 18, -45, 11, + 45, -50, -10, 42, 4, -63, 62, -10, -22, -9, 26, 8, -52, 41, 14, -54, + 41, -9, -8, 12, -26, 33, -25, 6, 3, -14, 20, -28, -2, 50, -23, -51, + 64, 11, -86, 57, 17, -39, -5, 19, 41, -79, 33, 43, -64, 2, 40, -21, + -7, -6, 38, -37, -8, 43, -39, 5, 16, 3, -49, 67, -38, -20, 39, -20, + 10, -24, 43, -15, -47, 57, -13, -53, 59, -16, 8, -27, 35, -4, -36, 35, + -29, 13, -5, 5, -13, 32, -5, -48, 57, -29, -15, 30, -26, 23, -34, 33, + 25, -79, 54, 25, -70, 16, 33, -1, -60, 37, 52, -76, 7, 54, -22, -61, + 76, -23, -30, 30, -15, 14, -21, 24, -4, -20, 23, 0, -49, 63, -31, -12, + 28, -15, 9, -17, 26, -25, -1, 4, 15, -31, 22, 8, -23, 18, -8, -7, + 6, -1, 7, -12, -1, 32, -62, 42, 14, -59, 41, 13, -31, -5, 40, -14, + -49, 36, 38, -64, 1, 68, -54, -29, 61, -16, -29, 8, 37, -22, -33, 42, + 18, -75, 47, 6, -25, 26, -33, 42, -32, 1, 4, 3, -2, 5, -20, 27, + 4, -43, 33, 2, -27, 6, 26, -25, 8, 2, 19, -46, 26, 15, -56, 44, + 12, -34, -4, 43, -34, -1, 2, 27, -40, -3, 52, -64, 26, 21, -30, -3, + 30, 1, -37, 13, 27, -28, -31, 49, 4, -63, 61, 2, -23, -10, 22, 7, + -53, 17, 43, -51, 21, 15, -26, 37, -31, -4, 9, 0, -28, 28, 4, -10, + -5, 21, 2, -40, 32, 9, -50, 20, 43, -63, 32, -6, 13, -24, -4, 62, + -87, 46, 12, -27, -14, 25, 13, -44, 25, 24, -29, -8, 13, 18, -56, 46, + 6, -51, 55, -19, -10, -4, 17, 3, -52, 60, -3, -49, 41, -14, 0, -4, + -3, 17, -9, -9, 1, 18, -11, -17, 3, 17, -5, -23, 15, 42, -83, 51, + -1, -17, 6, -16, 57, -83, 48, 16, -46, 10, 24, -8, -32, 32, 15, -49, + 26, 19, -24, -22, 40, 20, -80, 64, -11, -24, 14, -11, 17, -18, 18, -5, + -21, 45, -36, -11, 24, -16, 5, -10, 32, -13, -17, 24, -15, -4, -8, 9, + 0, -16, 33, -36, 36, -7, -39, 46, -35, 33, -61, 51, 10, -63, 50, 11, + -34, -5, 39, -8, -46, 41, 6, -45, 22, 14, -4, -41, 74, -33, -44, 57, + -19, -20, -12, 42, -4, -37, 30, 18, -31, 0, -1, 10, -16, 3, 8, 1, + 9, -31, 21, -2, -11, -1, 3, 24, -40, 15, 31, -52, 20, -1, 13, -32, + 31, 6, -44, 41, -17, -18, 21, 18, -32, -10, 41, -2, -60, 42, 9, -25, + -9, 38, -10, -29, 40, -27, -7, 14, 8, -20, -2, 26, -11, -35, 42, -2, + -36, 28, -1, 3, -33, 39, -7, -24, 9, 4, 4, -10, 7, -2, 0, 15, + -52, 45, 4, -38, 14, 29, -20, -23, 39, -1, -38, 13, 23, -26, -1, 12, + 2, -30, 41, -10, -30, 36, -3, -22, -6, 35, -20, -32, 27, 22, -41, 19, + 23, -18, -18, 22, -5, -34, 39, -19, 5, -3, 29, -26, -21, 47, -38, -23, + 38, -4, -15, 6, 19, -12, -4, 6, -14, 17, -14, -11, 22, 3, -20, -13, + 38, -2, -52, 43, 16, -30, -19, 37, 1, -51, 47, 2, -23, -1, 22, -10, + -24, 17, 21, -62, 51, 11, -38, 19, 8, -3, -50, 61, -18, -15, 4, 16, + -9, -15, 29, -32, -2, 37, -43, 9, 35, -36, 13, -16, 28, -28, -5, 41, + -35, -3, 12, 15, -29, 2, 19, -20, 19, -21, 7, 18, -20, 1, -24, 47, + -17, -45, 54, 10, -43, 0, 37, -3, -63, 58, 4, -55, 43, -2, -6, -31, + 50, -35, -10, 37, -12, -17, 1, 29, -34, -5, 31, -19, -10, 29, -26, 32, + -44, 25, -5, -27, 43, -45, 33, 12, -29, -6, 38, -18, -34, 23, 18, -21, + -12, 17, 27, -52, 18, 32, -49, 42, -19, -24, 40, -26, -7, 0, 32, -12, + -44, 69, -18, -46, 21, 26, -41, -5, 49, -24, -8, 22, 0, -23, -17, 32, + -6, -42, 64, -40, 17, 0, 3, -11, -28, 63, -61, 13, 26, -12, -7, 4, + -5, 8, -2, -5, -14, 18, 13, -38, 6, 36, -7, -71, 86, -10, -56, 45, + -11, -2, -18, 9, 26, -38, 24, 1, -24, 41, -35, -10, 24, -1, -24, 10, + 25, -15, -20, 10, 36, -44, -32, 96, -69, -8, 44, -32, 12, -20, 33, -33, + 11, 24, -24, -15, 40, -23, -27, 20, 18, -19, -4, 28, -23, 9, -9, 4, + -19, 32, -27, -15, 59, -37, -17, 28, 2, -20, -12, 28, 20, -68, 46, 2, + -24, 3, 6, 16, -28, 17, 8, -21, 1, 6, -21, 15, 34, -68, 43, 41, + -81, 31, 10, -5, -28, 1, 51, -37, -21, 64, -40, -23, 44, -25, -12, 15, + 7, -21, 14, 0, 6, -29, 29, 7, -39, 30, -10, 0, -4, -5, 13, 8, + -24, 23, -28, 38, -27, -34, 50, -5, -33, 10, 55, -47, -22, 43, -3, -45, + 11, 38, -37, 15, 16, -25, 24, -22, -4, 0, 4, 14, -41, 33, 35, -67, + 13, 52, -57, 0, 25, -4, -7, -11, 18, 5, -37, 32, 2, -39, 54, -24, + -18, 13, 16, -27, -2, 7, 31, -52, 29, 17, -41, 38, -23, -15, 28, -4, + -28, 40, -13, -20, 8, 13, 0, -40, 37, 20, -53, 14, 39, -34, -21, 27, + 14, -28, 12, 14, -23, 7, 3, -28, 24, 6, -23, 10, 9, 20, -39, -12, + 61, -39, -44, 74, -24, -25, 21, 13, -31, 10, 11, -3, -21, 19, 7, -43, + 46, -26, -2, 22, -16, 0, 13, -16, 10, -9, -20, 33, -30, 29, -2, -29, + 44, -8, -62, 54, 13, -50, 8, 34, 7, -43, 9, 41, -34, -39, 54, -6, + -28, 9, 20, -16, -6, 25, -30, -6, 45, -51, 4, 36, -21, -22, 28, 4, + -25, 18, 6, -5, -33, 37, -9, -19, 14, 8, -5, -4, 5, -1, -13, 0, + 16, -46, 49, -5, -25, 30, -8, -16, 15, -17, -4, 24, -26, 14, -8, 16, + 3, -40, 16, 47, -78, 21, 65, -53, -20, 24, 26, -55, 6, 55, -47, -6, + 35, -4, -28, 14, 1, -19, 15, -9, 20, -22, 19, -6, -31, 32, 7, -36, + 14, 20, -18, -7, 9, 9, -27, 22, -15, 8, 9, -15, 2, -2, 9, -19, + 11, 5, 11, -38, 38, -4, -35, 23, 17, -48, 34, 15, -51, 41, -2, -11, + -30, 35, 20, -65, 33, 34, -37, -23, 48, -2, -48, 21, 19, -12, -34, 42, + 8, -49, 33, 10, -27, 25, -15, -6, 9, -11, 7, -14, 22, -7, -11, 18, + 4, -18, -12, 30, -40, 14, 16, -11, -2, 30, -36, 4, 20, -19, -25, 21, + 17, -39, 38, -11, 13, -32, 19, 13, -49, 41, -2, -25, 8, 24, -23, -16, + 41, -9, -44, 34, 28, -48, -15, 59, -22, -54, 64, -6, -10, -20, 29, 4, + -56, 42, 7, -31, 20, 0, -5, 9, -3, -27, 33, -15, -18, 25, 5, -21, + 10, -6, -4, 1, 5, 14, -42, 47, -10, -14, -15, 30, -6, -53, 64, -4, + -33, 13, 27, -34, -16, 37, -4, -42, 38, 11, -35, 11, 17, -10, -33, 55, + -35, -6, 14, 20, -35, -11, 63, -52, -17, 55, -22, -23, 19, -2, 0, -5, + -10, 21, -5, -14, 12, 1, -10, 6, -15, 11, 13, -37, 43, -14, -17, 11, + 10, -13, -28, 43, -15, -25, 35, 11, -45, 20, 25, -34, -21, 51, -16, -42, + 35, 18, -23, -32, 75, -47, -18, 34, -1, -28, 1, 34, -40, 16, 23, -26, + 4, 18, -22, -4, -7, 18, -8, -25, 41, 0, -24, 13, 9, -30, 14, -4, + -14, 30, -18, 5, 9, -12, -3, -8, 25, -22, -18, 50, -18, -43, 48, 0, + -39, 11, 27, -14, -26, 42, -10, -33, 4, 61, -72, 7, 58, -40, -22, 28, + 24, -62, 19, 31, -22, -23, 41, -13, -16, 5, 11, -13, -4, 23, -21, 4, + 7, -8, -20, 33, -19, -10, 26, -7, -13, 2, 18, -21, -10, 28, -20, -15, + 54, -36, -26, 56, -30, -32, 42, -5, -21, 1, 40, -26, -19, 29, 7, -59, + 34, 24, -43, 20, 3, 12, -36, 23, 23, -48, -1, 61, -49, -25, 62, -27, + -23, 19, 13, -17, 4, 0, 9, -29, 19, -5, -7, 13, -9, 17, -7, 0, + -14, 11, -5, -17, 2, 35, -29, -10, 45, -27, -21, 31, -9, -17, 12, 5, + -10, -12, 26, 0, -37, 34, 6, -36, 18, 8, -2, -42, 39, 16, -47, 25, + 37, -57, 1, 51, -59, 13, 19, -10, -10, 11, 11, -8, -32, 42, -19, -36, + 59, -26, 1, -7, 17, -14, -2, -1, -2, 5, -5, 4, 0, 15, -25, -3, + 30, -28, -15, 36, -13, -5, -13, 26, 2, -45, 41, 2, -38, 21, 20, -29, + -11, 46, -27, -35, 46, 3, -38, 20, 25, -48, 19, 18, -26, 5, 3, 10, + -17, -13, 46, -29, -27, 52, -40, 18, -6, 9, -14, -8, 21, -11, -11, 16, + 14, -42, 33, 5, -31, 14, 0, -14, 19, -9, 11, -5, 2, 2, -39, 58, + -35, -26, 47, -1, -40, 19, 32, -36, -14, 37, -2, -40, 18, 32, -47, -6, + 49, -34, -7, 36, -16, -15, 2, 22, -36, -5, 53, -56, 27, 6, 2, -13, + -8, 28, -40, 4, 22, -2, -33, 46, -14, -36, 51, -10, -47, 40, -2, -18, + 3, 11, 13, -50, 57, -33, -5, 30, -31, -4, 19, -3, -17, 20, -2, -8, + -16, 34, -6, -45, 30, 35, -73, 21, 55, -52, 3, 11, 19, -42, -2, 55, + -57, 13, 23, -11, -16, 12, 16, -45, 25, 9, -22, -2, 37, -23, -29, 49, + -24, -27, 46, -23, -8, 22, -14, 6, -26, 45, -42, -9, 41, -15, -12, 11, + 13, -25, -1, 10, 9, -42, 37, -2, -20, 17, 14, -41, 25, 17, -52, 45, + -14, 1, -23, 21, 30, -74, 44, 35, -53, -4, 42, -18, -36, 30, 9, -26, + 17, 15, -18, -12, 37, -32, -25, 48, -27, -6, 20, -8, 12, -32, 38, -22, + -17, 36, -18, -13, 15, 7, -22, 14, -3, 5, -21, 33, -18, -18, 17, 12, + -31, 10, 34, -51, 33, -12, 15, -23, 1, 19, -50, 51, -7, -41, 47, 11, + -56, 20, 30, -23, -34, 37, 17, -29, -14, 54, -25, -45, 50, -16, -17, 11, + 14, -2, -30, 44, -16, -32, 39, -18, -16, 26, -5, -22, 25, -7, 1, -18, + 27, -8, -21, 23, 0, -30, 16, 27, -54, 46, -1, -24, -9, 28, 8, -62, + 48, 6, -31, 13, 17, -25, 17, -16, -1, 9, 2, 0, -15, 12, 19, -42, + -2, 57, -56, -2, 47, -11, -40, 21, 38, -56, -22, 71, -26, -41, 52, 3, + -29, 14, -1, -7, -20, 29, -3, -34, 41, -1, -35, 26, 12, -38, 25, -6, + -4, 7, -9, 6, -14, 31, -24, -7, 24, 3, -47, 33, 9, -28, -7, 23, + 18, -44, 22, 29, -48, 1, 46, -52, 14, 21, -21, -9, 26, 3, -41, 20, + 34, -52, -14, 75, -39, -40, 53, 0, -35, 6, 29, -15, -36, 44, 0, -39, + 36, -15, -11, 25, -9, -8, 6, 0, 1, -30, 29, -1, -17, 12, 20, -34, + 17, 4, -35, 29, -4, -10, -8, 35, 0, -45, 34, 18, -77, 45, 22, -29, + -9, 24, 14, -50, 29, 15, -34, -1, 47, -52, 3, 58, -54, -12, 40, -7, + -28, 10, 33, -22, -50, 79, -24, -38, 25, 10, -5, -30, 27, 16, -42, 15, + 14, -19, 11, 6, -33, 35, 2, -46, 49, -20, -7, 13, -4, 0, -12, 14, + 3, -50, 58, -8, -44, 40, 17, -22, -41, 60, -13, -48, 25, 50, -62, -3, + 71, -55, -12, 23, 3, -20, -1, 13, 20, -50, 48, -27, -23, 57, -43, -5, + 8, 30, -34, -16, 51, -18, -42, 35, 19, -40, 23, 0, -35, 39, -23, 0, + 21, -24, 16, -6, 2, 14, -53, 43, 1, -46, 51, -2, -19, 3, 25, -32, + -11, 24, -1, -34, 25, 42, -74, 29, 42, -41, -34, 56, -3, -32, -26, 84, + -35, -72, 101, -39, -13, 5, 24, -31, -2, 21, -25, 2, 22, 0, -37, 43, + 2, -41, 23, -6, -9, 9, -7, 24, -19, -8, 24, -33, 31, -11, -37, 57, + -25, -22, 35, -2, -29, 2, 26, -1, -39, 20, 51, -72, 14, 45, -45, -17, + 49, -30, -12, 24, 25, -48, -23, 107, -96, -10, 61, -7, -47, 22, 34, -35, + -13, 21, 17, -55, 40, 12, -43, 23, 6, -21, 19, -10, -4, 10, 3, -2, + -35, 38, -7, -29, 31, 1, -15, 15, -11, 5, -8, -3, 10, -30, 40, 10, + -62, 43, 30, -80, 22, 59, -63, -6, 42, 4, -35, -2, 67, -87, 21, 44, + -44, -6, 34, -6, -39, 26, 28, -26, -47, 87, -25, -74, 69, 15, -63, 22, + 19, 3, -13, -14, 36, -30, 1, 5, -9, 9, 3, -14, 29, -9, -25, 14, + 6, -6, -38, 54, -12, -38, 46, 14, -70, 48, 19, -68, 37, 25, -27, -25, + 29, 39, -81, 27, 50, -53, -12, 44, -4, -46, 23, 27, -32, -24, 67, -34, + -36, 65, -33, -31, 52, -22, -23, 21, 8, 18, -61, 46, 14, -59, 26, 31, + -49, 24, 11, -27, 30, -29, 8, -7, 20, -20, -4, 11, 0, -1, 0, -1, + 0, -1, 1, -2, 2, -1, -4, -2, 1, 19, -2, -20, 3, -10, -11, 12, + 3, -10, -3, 25, -4, 1, 6, 4, -12, 10, 2, -4, -28, -11, 9, 2, + 1, 18, -9, -20, 12, 11, 10, 1, -5, 5, -15, 4, 7, -27, -3, 4, + -8, 38, -31, -15, 7, 13, -34, 37, -6, -19, -6, 20, 41, -31, -20, 28, + -13, 30, -4, 0, -23, -1, 0, -13, 21, 3, -32, 19, 30, -52, 18, -24, + -27, 31, -14, 4, 1, -16, 14, 12, -20, 32, 14, -41, 37, -6, -5, 1, + 27, -34, 42, 9, 2, -34, 20, -25, 11, 15, -10, -14, -19, -24, 5, -12, + 3, -17, 2, 46, -13, -15, 31, -23, -16, 21, 25, -6, -36, 10, 1, 26, + -18, -12, 1, 21, -8, 17, -16, -29, -39, 17, -5, -1, -4, -6, -18, 33, + -21, 24, -17, 31, 0, 4, 0, 6, -26, 18, 24, 46, 5, 19, -10, 11, + 25, -13, 10, 50, -50, -52, 21, -23, -29, -8, 34, -35, -39, 15, -16, -43, + -5, -29, 29, -1, -8, -30, 18, 5, -14, 52, 12, -4, -28, 19, 25, 25, + 16, -44, 53, -20, 49, -23, 25, -32, 1, -63, 50, 37, -52, -13, 13, 4, + -18, 22, -56, 7, 23, -46, -7, 39, -69, -15, 26, 28, 21, 9, -64, 55, + 23, -34, 46, -26, -9, 36, -31, 4, 5, 37, -58, 28, 49, -25, 20, -1, + -12, -25, -6, 12, 9, -23, -34, 0, -2, 14, 3, -4, -13, 25, 23, -11, + 1, -34, 6, 9, 30, -36, -19, 11, -16, 14, 76, -97, 33, 25, -50, 8, + 25, -35, 20, -20, 4, -27, 63, -73, 25, 35, -22, 7, -33, 13, 2, 6, + -3, 5, 1, 17, 1, -36, 40, -4, 10, -28, -9, 14, -16, 5, 20, -32, + -45, 59, -10, 26, -29, -10, -13, -32, 44, -74, 81, -51, -12, 66, -11, -33, + 17, 38, 12, 57, -39, 5, 39, 9, -4, 4, 0, 25, -50, 24, -19, -1, + -30, -21, 24, -46, -20, -35, 19, -10, 1, -45, -7, 29, -8, -70, 51, -4, + -51, 42, 20, 21, 21, -24, 7, 69, 1, 17, 10, 9, 8, 16, -8, 66, + -32, -13, -24, 30, 50, -86, -15, 34, -23, -56, -26, 7, 22, -45, 23, -41, + 50, -84, -19, 50, 0, 2, -20, -31, 49, -12, -8, 12, 63, -20, -23, 57, + -37, 85, -57, -29, 83, -11, -15, -29, 25, -44, 33, -51, 74, -56, 63, -99, + 72, 15, -40, -41, -29, 68, -66, 46, 12, 21, -65, 5, 62, -24, -24, -15, + 7, -25, 7, -4, -16, 47, 13, -38, 3, 55, -31, -40, 31, -1, -35, 22, + 4, 34, -6, -1, -12, 6, 75, -51, 12, 57, -19, -24, -5, 12, -10, 26, + -13, 10, -44, 25, -13, -26, 39, -42, -25, -65, 36, -55, -41, -12, 2, 8, + 22, 22, -24, -27, 51, -38, 36, 1, -14, -8, 88, 2, 15, 28, 6, 46, + 8, 32, -22, 37, -29, 10, 3, -36, 9, -9, 2, 6, -15, -79, 32, -15, + -26, -4, -29, -28, 7, 16, -29, -27, 3, 8, 2, 9, 5, 1, -13, 38, + 16, 26, -16, 0, 19, -14, 20, -29, -3, 43, 17, -14, 39, -34, -15, 24, + 36, -27, -1, 7, -55, 24, 50, -43, 21, 5, -5, -122, 78, -43, -33, 12, + -12, 9, -45, -3, -1, -22, 37, -3, 17, -35, -11, 32, 5, 62, 0, -4, + 20, 18, -33, 93, 2, -77, 45, 33, -29, -35, 45, -55, 48, -12, 15, -54, + 16, -3, -50, 1, -21, -39, 16, -1, -33, -38, 19, -45, 9, 34, 26, -15, + 21, 60, -32, 7, -2, 24, 21, 28, -19, -12, 7, 60, 23, -23, 7, -44, + -54, 54, -17, -42, 38, -24, -23, 18, 9, -31, 4, 24, -26, -27, 33, -53, + 15, 26, -38, 11, 13, -39, 24, 32, 19, 14, 16, -27, -24, 14, 14, 9, + 6, -48, -8, -8, 60, -39, 1, -32, 51, -34, 0, 33, -16, -33, -10, 60, + -40, -1, 3, 31, 50, -16, -32, -40, 45, -34, -8, 54, -80, 0, 19, 21, + -21, 87, -70, -19, 23, 25, -56, 40, -33, 19, -44, -8, 7, -12, 18, -20, + 22, -10, 18, 5, -7, 26, 33, -65, 49, -9, -9, 27, 22, 22, -37, 18, + -19, -1, 61, -23, -39, 4, 4, -32, -3, 27, -39, -3, 38, -19, -12, -8, + -37, 3, -10, -14, -37, 0, 4, 24, 1, 33, -35, 29, -2, 24, 24, -21, + 23, -3, -31, 47, 12, -26, 35, -19, -17, 22, 20, -27, 1, -16, -18, 17, + -2, -19, -22, 25, -2, -11, -3, -60, -2, 30, 64, -76, -7, -29, 45, 1, + 46, -23, -43, 2, 43, 68, -38, -8, 45, -7, -8, 15, -47, -27, 71, -12, + -3, -17, -54, -29, 75, -51, 8, -27, 12, -18, 60, -29, -42, 22, 51, -32, + -27, 28, -11, 48, -34, 30, 26, -19, 20, 14, -16, 2, 7, -36, 70, -14, + -21, -39, 82, -50, -49, 33, -28, 9, -17, -15, -51, 5, 7, -17, 58, -29, + -33, 2, 29, 14, -46, 3, 28, 2, 28, -22, 7, -3, 28, 2, 40, -71, + 2, 23, 24, 19, 11, -62, 56, 1, -24, -7, -10, -26, 30, -49, 18, -40, + 52, -51, 46, -3, -28, -26, 40, 11, -5, 8, -46, 25, -10, 34, -25, 44, + -17, -7, 12, 12, -28, -19, 30, -26, 6, -38, 13, 45, -43, 24, 24, -49, + -13, 19, 3, 27, -5, -8, 5, -6, -4, 39, 7, 1, -38, 22, 20, -20, + 19, -24, -50, 47, -11, -25, 32, -59, 17, 12, 35, -50, -14, -7, 15, 33, + -15, 11, -45, 10, 14, 50, -68, -4, 11, -35, 20, 88, -72, 40, 16, -9, + 3, 55, -44, 25, -24, 6, 14, -66, 9, 7, -10, 9, -7, 1, -42, -24, + -26, 74, -5, -23, -44, 12, 11, 12, 57, -60, -19, 7, -2, 40, 3, -26, + -14, 44, 29, 7, -23, 21, -32, 42, 13, -30, -16, 36, -9, 3, -21, 17, + -67, 30, -4, 23, -19, 8, -32, 5, 31, -4, -26, 18, -24, 6, 39, -7, + -24, -2, -5, 6, -3, 11, -10, -6, 16, -15, -15, 5, -19, -17, 38, -27, + 35, -48, 7, -20, 4, 12, 1, -33, 28, -24, -2, 28, -10, -11, 23, -2, + 5, 21, -5, 8, 0, 21, 12, -24, 36, -40, 36, 29, -2, -19, 1, 3, + -8, 9, -11, -13, -31, 26, -5, 23, -26, -30, 1, 30, -19, -2, -15, 3, + 5, 5, -3, 3, -43, 38, 16, -30, 18, 12, -1, -4, 20, -47, 11, 1, + 21, -15, 1, 0, -43, -5, 37, -28, 11, -51, 21, 2, 20, -24, 22, -46, + 34, -1, 7, 27, -12, -24, 28, 39, -4, 10, -19, 8, 6, 37, -26, 2, + -12, -32, 36, 17, -11, -14, -26, -1, 17, 17, -53, -10, -11, 23, -16, -26, + 10, -33, 1, 61, -5, -21, -14, -28, 50, 13, -41, 17, -12, 38, -19, 24, + 36, -75, 16, 1, 58, -15, -19, -33, 56, -40, 39, -18, 1, 0, -34, 11, + 32, -6, -52, 32, 2, 39, -31, -23, 0, -11, 10, -26, 55, -6, -51, 0, + 36, -33, -14, -9, 30, -11, -5, 14, -17, 6, -34, 28, 16, -3, -21, 7, + 25, 13, -30, 14, 12, 33, 3, -16, 9, -12, -17, 15, 2, 23, 14, -46, + 1, 13, -4, -19, 6, 30, -53, -13, 1, -17, 13, -38, 11, 20, 1, -24, + 19, -10, 7, -28, 48, 25, -59, -33, 51, 12, -4, -3, 13, -23, 64, 0, + -5, -24, -6, 21, -27, 28, -19, -29, 51, -24, -9, -12, 3, -3, 35, 6, + -33, -37, -5, 45, -47, 30, -16, -9, -10, 51, -31, 32, 10, -22, -10, 8, + -13, -28, 8, 15, -25, 39, -36, 2, 50, -30, 36, -40, -14, 35, -9, -3, + 12, -25, 36, -7, -20, -6, 48, -5, 31, -4, -18, -48, 67, -47, 26, -30, + 6, 9, -14, -29, 3, 23, -12, -27, 29, -22, -36, -9, 51, -30, -18, -16, + 47, -4, -25, 18, 16, 13, -11, 15, 10, 2, -36, 42, 3, -9, -21, 52, + -19, 18, -34, -3, -11, 23, 19, -13, -17, -19, 16, -1, 0, -32, -1, -4, + 25, 9, -37, -3, -9, 45, -15, -29, 36, 4, -29, -9, 35, 16, -36, -21, + 25, -12, 10, -21, 25, 5, -17, -8, 12, 35, -56, 4, -15, 47, -32, -5, + 18, 3, 11, 2, 7, 1, 1, -24, 23, 6, 7, -46, -37, 73, 12, -2, + -20, 34, -45, 32, -23, 15, -40, -34, 12, 4, 13, -39, 3, 23, 17, -24, + -15, 16, 19, -30, -9, 12, 53, -64, 1, 23, 40, -11, 8, 33, -36, 42, + -68, 71, -16, -10, -41, 22, 16, -19, -18, 26, -2, 1, 4, -21, -3, -16, + -4, 16, -31, 1, -26, -5, -8, 43, -69, 28, 14, 10, -16, 21, -18, -2, + -14, 0, 32, 23, -28, -21, 68, 0, -40, 24, 32, 1, -10, 8, -20, 32, + -37, 16, -3, 24, -10, -5, -30, 35, -39, 12, 6, -26, -2, -58, 65, -66, + 13, -10, -6, -15, 28, -27, -39, 51, -28, 16, -10, 60, -51, 30, 51, -24, + 11, -9, -7, 14, 39, -33, 4, -14, 25, -13, -8, 35, -40, -1, 27, -9, + 11, -9, -13, 5, 19, -37, -12, 23, 1, -2, -31, 37, -7, -41, 35, 16, + -6, -28, -8, 9, -23, 22, -8, 27, -17, -27, -10, 10, 12, -6, 11, -51, + 21, -19, -29, 23, -10, -4, 32, 3, 25, 7, -25, 23, 35, -21, -2, -3, + 23, -4, 14, 6, -8, -5, -6, 10, 10, 5, -38, -7, 16, -38, -2, 12, + 8, -54, 5, 18, -12, -18, 23, 17, -52, 50, -78, 11, 4, 5, 19, 7, + 27, -24, 5, 3, 35, -20, 34, -15, -10, 4, 21, 16, -14, 12, -8, -2, + 42, -30, -22, 28, -9, -34, -11, 23, -36, 0, 15, -10, 14, -37, -7, -19, + 30, -18, 15, -17, -14, -14, 51, -20, -8, 13, -12, 7, 35, 9, -12, -13, + 48, 1, -2, -32, 13, -5, 1, 15, 40, -66, 18, 1, 49, -45, -38, -8, + 14, -16, -2, 24, -13, -62, 15, 54, -28, -18, -3, 10, 13, -21, -18, -9, + 44, -13, 8, 37, 6, -18, 4, 27, -18, 21, 3, -8, 13, 27, -19, 14, + 2, -27, -11, -8, 17, -38, -26, 29, -31, 5, -7, -5, -9, -4, -11, 9, + -3, -5, -18, 16, 3, 0, -8, -2, -6, -1, 58, -11, 12, 2, 31, -21, + 13, 27, -17, -23, 54, 18, -33, -7, -7, 3, -2, -25, 15, -1, -25, -41, + -13, 46, -71, -15, 40, 10, -14, 0, -10, 18, 0, -31, 25, -8, -10, -13, + 24, 30, -9, 6, 4, 26, -3, 5, 31, -25, 0, -7, 16, 20, -1, -12, + -22, 11, -10, -3, -26, 12, 3, 2, -17, -31, 4, -26, 15, 13, 6, -22, + -5, 5, 8, 11, -23, 17, 17, -33, 0, 12, 21, -20, -3, 20, 21, -7, + -20, 38, 20, -27, -16, 3, 7, -8, -3, 0, 22, -38, -37, 26, 23, -26, + -8, -5, 0, -12, -2, 30, -8, -4, -2, -13, 15, -24, -4, 29, 10, 32, + -7, -57, 48, -13, 41, -13, 16, -20, -20, 33, -13, 26, -17, -18, 20, 10, + -44, 18, 2, -18, 3, -13, -5, -25, -16, 7, 30, -32, 8, -34, 19, -5, + 23, -28, 12, -4, -14, 30, 1, -2, 15, -20, -16, 44, -2, 34, -31, 36, + -25, 15, -3, 13, -10, -36, 39, -5, 0, -16, 1, 27, -28, 24, -26, -8, + -12, -16, 25, -2, -12, -28, 16, -17, 7, -24, 31, -15, -8, 31, -22, -7, + 0, 14, 16, -17, 8, -15, 24, -3, 17, -14, 6, -4, -22, 22, 9, 1, + 3, -21, 18, -8, 11, 0, 10, -3, -12, 3, 15, -15, 1, 2, -13, 3, + -23, -3, 15, -11, -5, 9, -30, -6, -10, 27, -2, -9, -12, 10, 4, 0, + -16, 16, -10, -27, 51, -5, -4, -1, -4, 5, 38, -18, -11, 17, 1, -2, + 8, 0, -7, 6, -6, -4, 9, -12, -11, 11, 1, -14, 1, -31, 13, 3, + -28, 12, 24, -30, 7, -6, 5, -4, -6, 8, 1, 14, -19, -1, 32, -22, + -9, 34, 6, -9, -9, -5, 15, 6, -25, 14, 6, -41, 0, 10, 2, 12, + -18, 6, 5, -1, -16, 4, 26, -33, 5, 4, -4, -9, 5, -2, 14, -10, + -11, 16, -6, 11, -5, -15, 14, 18, -19, 21, -24, 13, 6, -13, 21, -12, + -11, -2, 10, -6, -7, -13, 12, -13, 1, 10, -7, 2, -2, -21, 24, 5, + 2, 5, -24, 17, -17, -15, 9, 20, -12, -9, -15, 14, -1, -2, 14, -13, + 5, -32, 21, 10, 7, -11, 24, -1, -23, 24, -25, 31, 7, -16, -2, -4, + 9, -19, 17, 4, -27, 22, 21, -28, -6, 32, -48, 6, -4, 20, -6, -41, + 11, 31, -16, -14, 2, -8, -13, -13, 35, -15, 15, -20, 1, 26, 7, -13, + 18, 5, -19, 11, -7, 20, 22, -35, -11, 20, -24, 21, -20, 34, -15, -17, + -8, -2, 16, -9, -12, 2, 20, -31, 24, -21, 2, 12, -27, 28, -10, -5, + 24, 7, -29, 4, 6, -24, 33, -4, -8, -16, 1, 32, -28, 13, 7, 2, + -10, -38, 30, 2, -18, -2, 17, 13, -6, -46, -1, 61, -48, 18, 10, 2, + -17, -13, 8, 27, -8, 0, 11, -5, 20, -39, 4, 19, -8, -13, -15, 29, + -36, 29, -16, 14, -25, 17, -14, -15, 18, 5, 3, -5, -2, -19, 31, -12, + 14, -23, 31, -24, -4, 0, 4, 2, 11, -15, 22, -27, -4, 9, -8, 22, + -2, 7, -33, -12, -3, 30, -3, -10, 12, -19, 2, -9, 16, -4, -15, 5, + 32, -13, -13, 22, -11, 1, 3, 18, -12, 3, -17, 16, 15, -36, -2, 10, + -12, 9, -29, 14, 12, -23, 5, 39, -20, -39, 13, 14, -13, 2, -16, 43, + -25, -1, -12, 19, 11, -27, 0, 28, 3, -3, -15, -1, 10, -31, 43, -6, + 5, -10, 4, -18, 24, -6, -14, -8, -5, 4, 1, -5, -20, 21, 5, -19, + 22, -8, -13, -3, 20, -10, 20, -12, -7, 11, -11, -15, 6, 3, 24, -9, + -4, -3, -4, -20, 44, -12, -15, 4, -3, -6, 2, 9, 3, -17, -7, 9, + -2, 2, -22, 18, -8, -2, -10, 4, 6, -1, -4, 9, -1, 6, -9, 8, + 2, 4, 4, -6, 17, -32, 11, -1, 21, -7, -29, 12, 2, -35, 28, 12, + -15, 15, -43, 37, -30, -4, 2, 27, 8, -22, -1, -13, 20, -28, 36, -6, + -12, -4, -8, 14, 2, -12, 5, 12, -3, -11, 3, -1, 2, 18, 12, -11, + 4, -31, 13, 10, -10, 12, 7, -35, 10, -17, -3, 12, -5, 2, 0, -23, + 7, 5, -4, 23, -30, 2, 4, -3, 18, -16, 17, 16, -12, -3, -14, 17, + -1, -5, 9, 19, -23, 11, -8, -19, 34, -7, -13, 1, 3, 19, -23, -15, + 19, -17, 5, -24, 16, 4, -5, -7, 7, -2, -20, 4, 15, 21, -29, -7, + 16, -3, -17, 9, 3, 15, -15, -5, 12, -14, 8, 21, -15, 12, -18, -1, + 17, -19, 2, 16, 16, -11, -30, 22, -12, -12, -1, 21, -28, 29, -30, -6, + 19, -14, -5, 0, 10, 18, -8, -15, -1, 7, -15, 28, -3, -3, -9, -8, + 0, 6, 18, -32, 7, -3, -11, 6, 30, -42, 32, -13, -8, 5, 8, 8, + -15, 3, 4, -22, 27, -6, 6, -11, 1, -6, 13, -5, 2, -12, 29, -30, + 10, -15, 18, -19, 8, 21, 1, -28, 15, -20, 25, -25, -1, 11, -2, 1, + -22, -3, 15, 1, -22, 18, 16, -24, 1, 19, 6, 9, -7, -22, 8, -6, + 2, 14, -9, -4, -13, 10, -12, 13, 0, -11, -12, -2, -6, 20, -9, 4, + 5, -14, 3, 9, -2, 13, -5, 0, 14, -17, -1, -3, 8, -6, 7, 29, + -19, -13, 3, 27, -17, -8, 11, -2, -14, -9, 7, -3, -9, -14, 24, -12, + -35, -13, 40, -10, 1, -7, 1, 2, -1, 1, 16, 3, -13, -11, 30, 2, + -9, 0, -9, 2, 15, -9, 8, 3, -19, 12, 5, -21, 5, -6, 16, -4, + 7, -4, -2, 9, -35, 27, -6, 0, -12, 15, -29, 8, 2, -7, 4, 1, + -15, 28, -15, -13, 18, 4, -1, 1, -4, -7, -16, 21, -11, 25, -19, 2, + -10, 20, -32, 11, 6, 6, -15, 22, 8, -25, -13, 5, 20, 13, 7, -23, + -6, 7, -4, 4, 0, -7, 3, -10, -4, 9, 1, 3, -8, 2, 16, -22, + -7, -3, 12, -4, -4, 8, -10, 6, -13, -5, 3, 3, 6, 4, 4, -9, + -27, 1, 16, 17, -15, 0, -12, 15, -2, -6, 10, 3, -16, -16, 22, 13, + -12, 4, -4, 7, 11, -12, -14, 15, -1, 3, -12, 7, -7, 12, -14, 9, + -9, 2, 2, 9, -12, -17, 12, -17, 14, -2, -18, 2, 16, -5, 1, 8, + -5, -12, 0, -3, 21, -2, -17, 10, 10, -4, -16, 6, 15, -1, -25, -11, + 18, 0, -11, 8, 15, -16, -18, -4, 39, 3, -30, -6, 22, 2, -22, 2, + 21, -9, -9, 12, -3, 19, -24, -12, 20, -8, 4, 3, -3, 15, -20, -3, + 14, -7, -4, -14, 9, -8, 0, 7, -6, -8, -4, -3, 4, 13, -18, 0, + 9, -2, 5, -4, 10, 3, -9, -6, 9, -3, 1, 4, -3, 4, -11, 2, + -3, 5, 11, -13, -1, 4, -7, 1, -11, 1, 17, -17, 2, 13, 1, -21, + -2, 7, -5, -4, -5, 16, -5, -7, 4, 8, 8, -14, 4, 8, -7, -1, + 5, 2, -11, -9, 9, 6, -10, -2, 6, -7, -2, -1, 15, -17, -4, 5, + -2, 2, -3, -5, 11, -3, 1, 16, -12, -3, -7, 6, 5, -4, 5, 0, + -3, -15, 5, 3, -8, 9, 3, -8, 1, -6, -4, 0, -7, 21, -18, 9, + -8, 11, -2, -10, 10, 1, 14, -19, -11, -7, 18, -7, 4, 6, 2, -15, + 2, 4, 5, -3, 0, 0, 12, -2, -15, -4, 18, -7, -9, 18, -7, -6, + -9, 4, 7, -21, 11, -18, 14, -5, -4, 8, 5, 4, -3, -4, -11, 11, + -15, 19, 2, -18, 8, -4, -13, 18, 3, -14, -3, 9, -11, 2, 10, -9, + -5, -1, -15, 13, 16, -9, -4, 29, -15, -14, 6, 9, -1, -15, 12, 12, + -6, -6, 13, -10, 18, -14, 7, -12, 5, -9, -12, 16, -6, -16, 7, -1, + -22, 8, 2, -1, 9, 4, -31, -9, 12, 14, -9, -5, 17, -25, 7, 0, + 13, 4, -1, -17, 10, 13, -7, -11, 17, 2, -23, 27, 5, -10, -3, 13, + 5, -5, -5, -4, 0, -3, -5, 3, 4, -9, -7, 5, 4, -13, -10, 1, + 7, -4, -2, -3, -5, 15, -9, 0, 1, 12, -17, -6, 32, -15, -16, -11, + 20, 0, 2, -11, -5, 25, -21, 3, 10, 15, -24, -4, 8, -5, 0, 15, + -1, -7, 1, -18, 21, -7, 3, -12, 0, 12, -10, 6, -3, -2, 2, -1, + 9, 1, -9, 7, -9, -4, 9, -16, -4, 8, -10, 4, -3, -2, 13, -9, + 4, -16, 4, -3, -5, 14, 7, -8, 2, 9, 0, -2, -12, 7, -3, 2, + -4, -15, 11, -8, -11, -4, 23, -5, -1, 4, -9, 7, -4, 7, 8, -13, + -6, -4, 16, 10, -11, 8, -1, -1, 2, -5, 0, -3, -6, 2, 3, -6, + 13, -19, -9, 19, -11, 6, -12, 12, -10, -3, -11, -10, 14, 2, -19, 14, + 4, -6, 4, 11, -7, 3, -3, -8, 24, -18, 6, -8, 15, -14, -7, 19, + 0, -11, -3, 2, 2, 0, 2, 6, -7, -22, 16, 0, 11, -12, 7, -12, + 10, -16, 4, 8, -11, -11, 4, 16, -19, 13, 1, -19, 12, 19, -15, -4, + 9, -8, -13, 5, 14, -12, 5, -21, 7, 4, 11, -19, -1, 15, -16, -3, + -12, 14, 1, 1, 15, -6, -13, 7, 0, 6, 4, -11, -3, 10, 14, -20, + 7, 3, 1, 5, 17, -17, -5, 3, -4, 6, -1, 3, -18, 10, -10, 0, + 0, 14, -18, -19, 17, -23, -5, -1, 4, -4, -2, 1, -13, 26, -15, 2, + -10, 3, 13, 0, -6, 3, -4, 3, 0, -2, 9, 2, 9, -14, 23, -4, + -10, 15, 7, -16, 0, 9, 3, 0, 14, -12, 0, 4, -10, 1, -11, -13, + -6, 15, -14, -7, 2, -20, 4, -7, 9, -3, 2, -14, -1, 1, -1, 9, + -18, 10, -1, 1, -3, 22, 1, -1, 5, -4, 10, 2, 5, 0, 3, -2, + -1, 5, -2, -3, -5, 10, 2, -16, 2, 3, -1, -1, -11, 7, 6, 0, + -10, 10, -7, -2, -15, 15, 4, -25, 0, 4, 4, -12, 0, 5, -7, -6, + 6, 6, -8, 1, -1, -7, 17, -9, 2, 8, 4, -6, -6, 19, -5, -11, + 12, -12, 3, 3, -5, 9, 11, -26, 0, 0, 7, 5, -8, 11, -5, -6, + -16, 7, 12, -10, 0, -6, 7, -8, 3, -4, 11, -9, -16, 13, 18, -18, + 2, -5, 7, 5, 0, -1, 4, -9, -13, 18, 5, -4, -14, 1, 7, -5, + 4, -9, 15, 3, -10, -4, 5, 3, -11, -17, 18, 4, -9, -3, 3, -5, + -11, -3, 0, 7, -1, -8, -2, 6, -7, 7, -3, 6, 3, -12, 15, -5, + 23, -12, 8, -12, -4, 10, 1, 4, -3, 0, 0, 8, 0, 1, 11, -27, + -9, 9, -4, -3, 12, -19, -2, -8, -6, 1, -1, 2, -12, 5, -11, 3, + -1, -1, -10, 18, 0, 3, 2, 4, -5, 11, -3, 9, -2, -5, 7, -6, + 8, 10, 2, -1, -8, 1, -16, 2, 9, 1, -4, 0, -15, -5, 6, -14, + -9, 14, -22, 3, 7, -1, -2, -2, 0, 1, -2, 1, 9, 0, 7, -1, + 6, 4, 0, -6, -2, 2, 4, -9, 11, 1, -25, 9, -6, 5, 0, -7, + -8, 3, 5, 1, -2, 3, -9, -5, 7, 14, -12, 3, -10, 10, 3, -16, + -3, 26, -8, -9, -2, 15, 0, -21, 8, 11, -17, 3, 8, -8, 10, -19, + -3, 8, -4, 6, -10, 3, 4, -6, -4, 6, 0, 4, -19, 9, 3, -7, + 17, -7, 2, 3, -27, 12, 5, -14, 5, -6, -6, 6, 11, -11, 6, -12, + -2, 9, 8, 1, -18, 18, -9, 0, 13, -8, -10, 24, -11, 4, 13, -4, + -18, -3, 2, 9, -7, -1, 4, -6, 0, -11, 5, -1, -1, -8, -10, -6, + 6, -15, 20, 6, -25, 11, -5, -7, 12, 4, 0, -6, 6, 2, -1, 5, + 1, -11, 9, 20, -11, 14, -6, -15, 11, -11, 7, 1, -5, 2, -8, -2, + 12, -5, -16, 8, -4, -10, 2, 2, -6, -8, 5, 0, 3, 4, -17, 13, + 4, -9, 1, 5, 4, 8, -7, -3, 3, -2, 4, 14, -9, -6, -7, -3, + 11, -17, 0, 9, -10, 0, 1, 0, -9, -7, 8, 7, -3, 15, -22, 2, + 7, 0, 2, 4, -2, -6, -3, -1, 9, 2, -2, 1, -4, -1, -6, 2, + 4, -8, 3, -2, 1, 0, -9, 14, -6, -5, 3, -1, -6, 5, -5, -6, + 5, -5, -1, 12, -10, -6, -3, 9, -7, -8, 14, -5, -11, 9, -1, 5, + -5, 3, 1, 0, 1, 3, -7, 7, -1, 1, 4, 5, -16, 7, 6, -6, + -2, 11, -8, -9, 3, -9, -2, 15, -11, -11, 6, -1, -7, -4, 4, 2, + -9, 1, 1, -2, 0, 6, -3, -3, 6, -7, 6, 11, -11, -9, 0, 15, + -8, 14, -2, -13, 1, 4, 0, 7, -2, -10, -1, 8, -6, -4, 5, 1, + -6, 1, -8, 0, -4, 7, 4, -3, -8, -4, -3, 8, 3, -8, -3, 16, + -7, -1, 0, -1, -4, -2, 2, 6, -1, -2, -4, 5, 5, -4, -2, -8, + -6, 10, 4, -5, -2, -2, -2, 0, -4, 0, 2, 0, -12, 6, 2, 0, + 3, 2, -11, 2, 1, -2, 10, 1, -6, 9, -8, -3, 5, -1, 5, -2, + 0, -5, -7, 8, 5, -4, -9, -1, 1, -2, -7, 4, -12, -4, 5, 0, + -4, 5, -13, 8, 2, 4, 1, -10, -6, -3, 17, 4, 1, -7, 6, 2, + 1, -3, -1, 0, 7, -8, -2, 6, 2, -8, 0, 21, -16, -5, -1, -2, + 4, 0, -18, 11, -10, -4, 11, -4, -1, -2, 2, -3, 2, -2, -8, -1, + 1, -3, 8, 2, 0, 1, 5, -7, 2, -4, -1, 4, 5, 0, 1, -6, + -11, -6, 7, 8, 5, -7, -12, 7, 2, -6, -3, 7, -4, -3, -1, 2, + 9, 0, -7, 9, 5, -15, -3, -7, 2, 3, -2, 0, -3, 6, -13, -2, + 0, -5, 3, 9, -5, 9, -12, -9, 12, 4, 1, 5, 3, -4, -2, 3, + 11, -16, 2, 0, 10, -9, -4, 8, -4, -7, 2, 2, -6, 3, -22, 8, + 11, -7, -6, -2, -5, -5, -8, 3, 7, 12, -8, -1, 4, 8, -14, 4, + 13, -6, -8, 2, 17, -1, -3, 12, -10, -2, -7, 0, -6, 16, -17, -4, + 10, -9, -2, 1, 0, -1, -7, 7, -10, -3, 3, -1, -7, 11, -11, 3, + 3, 8, -6, -2, 1, 0, -15, 15, 5, 0, 7, -5, 4, -3, -2, 2, + -4, 10, -9, -9, 15, -6, -12, 14, 3, -7, 0, -9, -1, -5, 3, -4, + 3, 4, -14, -2, -1, 8, -3, 13, -5, -18, 12, -1, -7, 0, 5, -2, + -6, 14, 3, -9, 3, 1, -10, 0, 7, 3, -7, 4, 2, -14, 4, 4, + -6, 14, -4, -12, 6, 2, -10, 1, 5, -6, -10, 3, 8, -11, 9, -1, + -3, 2, -6, -8, 4, 2, -10, 6, 11, -7, 0, 2, 1, -10, 8, 6, + -5, 2, -2, 3, -4, 1, 4, -11, 6, 4, -8, 4, 4, -13, -4, 2, + 6, -3, 2, -4, -11, 11, 2, -13, 9, 3, -21, -2, 17, -4, -1, 6, + -11, -2, 1, -4, 4, 5, 0, 0, 1, 13, -8, 0, -3, 2, -6, 1, + 7, -4, 2, 2, -5, -5, 8, -14, -4, 8, -10, -1, 3, -4, -6, 6, + 5, -12, -6, 5, 1, -4, 2, -4, -1, 8, -8, 1, 8, -4, 6, -1, + 17, -8, -7, -1, 4, -1, 14, -5, 0, -6, -1, 0, -1, 2, -10, -7, + 0, 6, -6, 4, -12, -1, 7, -5, -2, 0, 3, 0, -9, 10, -8, -1, + -5, 11, -15, 6, 6, -1, 1, 1, -4, 4, -7, 12, -11, 10, 2, -15, + 5, 11, 5, -7, -7, 0, 0, -5, 11, 0, -5, -10, -12, 15, 1, -2, + -4, 2, 6, -9, -8, -3, -1, -5, 5, -4, 1, 5, -13, -1, 10, 0, + 0, -2, 1, 9, 0, 3, -7, 14, -2, 0, -2, 3, -12, 9, 4, 0, + -4, -7, 0, -6, -5, 5, -3, -5, -5, 4, 7, -13, -7, -6, 3, 1, + 0, 6, -3, -5, -4, 7, 1, 3, 1, -3, 5, 3, 3, 2, -1, 2, + 4, -9, 8, 2, -5, 6, -12, 7, -5, -8, -6, 9, -14, 4, -7, 4, + -6, 1, -2, -11, 4, -4, 2, 7, -4, 4, 5, -2, -4, -5, 6, 2, + 0, 5, 9, 3, -4, -7, 1, 6, 3, -2, -7, 1, 1, -6, 0, 8, + -12, -11, 7, -12, 0, 2, -5, 4, -1, -9, -2, 7, -8, 1, 1, 5, + 1, -4, 5, -8, 4, 2, -5, 7, 6, -6, -3, -8, 13, -2, -3, 2, + 0, 0, -5, 6, 5, -6, -3, -3, 2, 8, -12, 4, 7, -12, -10, 13, + -3, -2, 1, -5, 1, 1, -2, 5, -5, -6, -12, 4, 0, 4, 3, 3, + -10, -8, -3, 10, -5, 7, -8, 3, -1, 6, 0, 3, 6, 4, -6, 2, + 5, 5, -6, -4, -2, 4, -2, -9, -4, 7, -1, -12, 10, -5, -9, -11, + 1, 4, -8, 1, 7, -3, 4, -7, -1, 8, -5, -6, 9, -1, 0, 8, + 3, 7, -9, 6, -1, 9, -7, 2, 3, -4, -5, 6, -6, 8, -10, -12, + 4, 3, 1, -1, -9, -1, -4, -5, -3, 6, 7, -11, -4, 6, 0, -3, + 3, 4, -5, -4, 1, -3, 3, -2, 0, 1, -1, 3, -9, 7, 3, -7, + -2, 5, 5, -9, 7, 0, -8, 8, 1, -5, 6, -4, -6, 2, 6, -3, + 0, 0, -3, -9, -6, -2, 9, 2, -2, -11, 7, 9, -9, -7, 8, 0, + -7, 1, 4, -5, -3, -3, 5, 5, -3, -13, 7, 5, -6, 5, -2, 7, + -9, -8, 6, 2, -5, 3, 7, -4, -6, -7, 1, 7, 6, -5, -5, 6, + -10, 10, 1, -4, 4, -4, -2, 1, 9, -10, 0, 4, -8, -1, -5, -1, + 3, -2, 6, 1, -5, -5, -5, 2, -3, 3, 3, -1, 0, -4, 0, 9, + -1, -6, -6, 4, -1, 2, 5, 0, -2, -2, -4, 2, 4, -1, -4, 4, + 0, -3, -9, -2, 6, 0, -7, -1, 3, -2, -1, 2, 2, -7, -2, 0, + 2, 4, -6, 3, -3, 6, 0, 0, -2, -6, 1, 11, -2, -1, -8, 3, + -7, 1, -2, 6, -9, 6, 0, -1, 1, -6, -7, 5, -1, 2, -2, -1, + -1, 0, -3, 1, 2, -1, -3, -5, 3, 7, -9, 5, 3, -5, -5, 5, + -1, 0, 4, 4, -11, 8, -3, -10, 9, -7, -1, 1, -2, 1, -3, 6, + -3, -5, 2, 4, -7, 5, 2, -2, -3, 1, -2, -4, 2, 0, -4, 8, + 2, -12, 0, 6, -10, -2, 8, -6, -3, 6, -4, 2, 9, -4, -7, 2, + 5, -1, 1, 4, 0, -5, 2, -7, 2, 4, 1, -5, -1, 7, -5, -5, + 12, -7, -12, 6, -4, -3, 3, 4, -3, -5, -1, -3, -10, 9, -8, -2, + 6, -3, -4, 6, -1, 0, 3, 2, 1, -3, -5, 2, 0, 4, -3, -3, + 1, 4, -8, 0, 7, 4, -9, 0, 3, 1, 1, -5, -4, 3, -1, -4, + 4, 3, -8, -2, -2, -3, -1, 0, -3, -2, 3, -2, 1, 0, -1, 0, + -6, 8, -5, 5, -5, 5, -3, 5, -7, 1, -3, -1, -1, 2, 8, -2, + -5, 1, -3, -1, -4, -4, 9, -1, 1, -3, -2, 1, -14, 8, 3, -14, + 4, 1, 2, 2, 0, -5, 3, -1, 2, -2, 8, -8, -3, -3, 7, -1, + -3, -1, -3, 1, 5, -7, 7, -12, -1, 1, 4, 3, -7, 5, 6, -2, + 2, -6, -3, 0, -5, 2, 1, -1, 2, -7, 1, 8, -5, -4, -3, 2, + -2, -5, 3, 2, -3, -6, -1, 1, -4, 4, 5, 2, -14, -1, 3, -4, + 3, 10, 2, 2, -4, -1, 4, 3, -6, 2, 1, -2, -9, 7, -2, 1, + -4, -5, 1, -7, -1, 1, 2, 2, -1, -6, 5, -1, -12, -4, 11, -2, + -3, 6, -4, 2, 0, 0, -2, 0, 3, 2, 4, 2, -3, -6, 9, -10, + -4, 2, 4, -1, -5, -1, 2, 1, 2, -7, -2, -4, -4, -2, 7, 5, + -6, 0, 1, -1, -4, 2, -6, 3, 9, -11, -2, 8, 0, -5, 6, -1, + 3, -5, 6, 1, -10, -4, -3, 4, 10, -8, -2, 1, 4, -8, 4, 3, + -8, -5, 2, 4, -5, 6, -2, 2, 2, -3, -10, 0, -6, 2, 4, 12, + -4, -10, 6, 2, -5, 2, -3, 6, -4, 0, -6, -4, 7, 0, -4, 12, + 0, -14, 3, 2, 1, 1, 2, -7, -1, 3, -1, -4, 10, -9, -11, 6, + 4, -9, -5, -1, 5, 0, 6, -5, -5, -4, 3, -7, 9, 0, -1, 0, + 4, -3, -2, -1, -4, 0, 10, 3, -5, 4, -4, -6, 8, 0, -7, -3, + 17, -9, -8, -1, 3, -3, -3, 0, -4, -3, -5, -4, 8, 8, -9, -5, + 4, 0, -7, 6, 7, 3, -6, 3, -3, 1, -4, -4, 4, 10, 1, -5, + -2, 0, -9, 4, 1, 1, -4, -2, 6, -3, -5, 0, -6, 3, 0, -2, + 4, 1, 0, -4, 3, -1, -10, -2, -2, 2, 9, -11, 8, 3, -2, -1, + -1, -3, -1, -8, 4, 6, 2, -7, 2, -1, 3, -6, 0, 1, -1, 2, + 2, 3, -1, -13, 2, 9, 3, -5, -3, 2, -3, 5, -4, -2, 0, -4, + -1, 1, -4, 0, -4, 0, -2, -2, -5, 1, 4, -1, 1, -4, 1, 2, + 0, -2, 2, 1, 1, 0, 7, 0, -3, -4, -2, 5, 0, -3, -2, 3, + 2, -9, -1, -1, -1, -4, 1, 5, -6, 1, -4, 8, -12, 1, -5, 3, + 3, -1, -6, 9, -3, -2, 0, 4, 0, -3, 4, 10, -5, -4, -2, 0, + 2, -3, -2, -2, 0, 0, -3, 0, 3, -8, 0, -5, 1, 0, 5, 1, + 4, -14, -2, 1, 3, 1, 0, -1, 6, -2, 2, -5, 4, 1, -2, -3, + 1, 3, 5, -5, 3, -1, -8, 0, -3, 5, -7, 2, -4, 2, -4, 2, + -3, -2, -7, 4, 2, -2, -4, 5, -5, -3, 0, -4, 3, 5, -6, 5, + 8, -5, 0, 2, 1, -6, 0, 5, 1, -2, 6, -10, 7, -9, 3, -5, + 4, -1, -1, -4, 5, -6, 5, -1, -9, -1, 2, 4, -2, 0, 5, -9, + 1, 0, -2, 1, -1, -3, -1, 9, -1, -9, -2, 2, 1, 2, -2, 3, + -7, 3, -1, 3, -1, -5, -5, 9, 1, -1, -3, 2, -7, 1, 3, -4, + -2, 5, 3, -2, 0, -5, -1, -1, -3, 1, -2, 0, -1, -2, 7, -3, + -12, -1, -2, 0, 5, 4, -4, -2, 6, -3, -5, 8, -5, -4, 2, 6, + 1, -1, -1, -4, 4, 3, -6, -4, 6, -1, -4, 2, 2, -10, -4, 3, + 0, -3, 5, -4, -5, -1, 2, -5, -1, 2, -2, 1, 6, -2, -4, 5, + -2, 1, 4, 0, -2, 0, 3, 0, -2, -4, -6, 6, 3, -2, -1, -1, + 1, -1, 0, 0, -14, -1, 3, 0, 0, 4, -6, -2, 0, -2, -3, -3, + 3, -4, 7, 4, -4, -3, -2, 3, 1, 0, 1, 2, 5, -2, -6, -1, + 1, 1, -4, 3, 0, -2, -3, 2, -8, 1, -2, -5, 0, 2, -2, 6, + 2, -1, -7, 4, -5, 2, -4, -6, 5, 5, 2, -1, -3, -4, -7, 0, + 6, -3, 0, -4, 8, 1, -6, -1, 2, 0, -2, -1, 7, -5, -4, 0, + 7, 0, -5, -4, 3, -2, 3, -3, 1, 3, -1, -6, 2, 3, -7, 3, + 0, -3, -3, -2, -4, 2, -2, -1, -3, 2, -4, 0, 4, 2, -6, 1, + -1, 1, 1, 4, 1, 2, -4, 0, 0, 5, 0, -5, -5, 7, 0, -4, + -4, 2, -6, -4, 5, -1, -1, -4, -3, 3, -1, -6, 1, 4, -1, -3, + -3, 3, 4, -1, 3, 2, 0, -3, -3, 5, 2, -3, -1, 1, -1, -2, + -1, 2, 1, -5, -1, 1, -3, -3, -4, 0, 2, -3, -2, 0, 4, -1, + -2, 0, 3, -6, 0, 3, 5, -1, -2, 3, 0, -3, 0, -3, 8, -4, + -6, 4, 2, -5, 0, -1, 2, -5, -7, -2, 1, 2, 1, 0, -2, -1, + -2, 0, 4, 0, -5, 2, 7, 5, -5, 3, -3, 0, 1, 0, -2, 5, + -10, 0, 1, 3, -12, 1, -2, -1, 1, -2, -4, 3, -6, -2, 3, 0, + -6, 0, 2, 4, 2, -3, 6, 2, -7, 2, 1, -4, 9, 3, -1, 0, + -2, -7, 0, 5, 3, -6, 4, -8, -3, -3, -1, -3, 3, -3, -5, 3, + -3, 3, -1, 2, -7, -2, -1, -4, 2, 2, 4, 3, 0, 0, -1, -2, + 1, 4, -2, 2, -1, 2, -2, -1, -8, 2, 2, -3, -1, 2, -2, -5, + 0, -1, -4, -1, 5, 1, 3, -2, -1, 0, 2, 6, -4, -1, -6, -2, + 2, 4, 1, -2, -5, -4, 0, 3, -4, 1, 4, -1, -9, -1, 1, -1, + -2, -2, 2, 1, -5, 6, -1, 5, -4, -3, -2, 8, -2, 1, 5, 2, + -8, 0, 2, 0, 3, -3, -4, 3, -7, -6, 4, 1, -6, 0, 2, -2, + -4, -2, 2, 4, -5, -2, 3, 0, -5, 1, 7, 6, -4, -7, 4, 3, + -6, -3, 12, -3, -3, -5, -2, 2, -2, -7, -2, 10, -4, -5, 2, 0, + -3, -5, 3, -1, 3, -2, -3, 3, 6, -8, 2, 5, -3, -3, -5, 13, + -3, -1, 1, 1, -4, -3, 0, 3, -3, -2, -1, 1, 2, -7, -6, 3, + -7, -3, 3, 1, 2, 1, -7, 3, -3, -1, -5, 6, 3, -1, -6, 6, + 3, -2, -3, -1, 1, -3, 3, -5, 4, 0, -6, -3, 5, -1, -5, 8, + -2, -1, 0, -4, 5, -4, -5, -1, 1, 4, -1, 1, 5, -5, 3, -2, + -2, -5, -2, 2, 4, -2, 2, 1, -16, 5, 1, -1, -2, -2, 1, -4, + 0, -8, 2, 4, -5, 0, 6, -2, 0, 0, 0, -1, 2, -5, 6, -1, + -1, 2, -1, 4, -5, 1, 0, -4, -2, -3, 2, 2, 4, -3, 1, -9, + -1, 2, 0, 1, -1, -1, -4, 3, -7, 6, -4, 2, -4, 7, -3, -1, + 3, -7, 0, 10, -1, -8, 2, 2, -5, -5, 4, -2, -2, -7, -5, 4, + 2, 3, -11, 10, -6, -5, -4, 0, 9, -1, 0, 4, -6, -1, 3, -1, + 6, -6, -1, -1, 9, -5, -3, 7, -1, -1, 4, 2, -7, 3, -2, 0, + -2, 2, -9, 0, 4, -6, 0, 2, 3, -14, 4, -3, -12, 3, -1, 3, + -4, 4, -8, 6, 5, -3, -2, -4, 8, 0, -3, -1, 1, -4, 4, -3, + 7, 0, 1, -5, 1, 6, -10, 1, 8, -5, -8, 6, 4, -2, 5, 2, + -9, 4, -1, -1, 0, -4, -5, 3, 4, -11, 3, -7, -4, 1, 2, 0, + -3, -2, -7, 4, -9, 4, -6, -1, 2, -2, -1, 3, 9, -6, 2, -1, + 3, 4, 2, 3, -1, 0, -1, 1, 4, 0, -3, 3, 6, -7, -4, 4, + -3, 0, -5, -2, 2, 4, -1, -1, 0, -9, -4, -6, 14, -11, -5, -1, + 5, -6, -3, 3, -2, -6, 3, 5, -1, -4, 5, -7, 7, 4, -7, 6, + 4, -2, -4, 5, 8, -12, 3, -1, -5, 3, -3, 2, 10, -7, -12, 3, + -2, 5, -4, 4, 3, -6, -4, -6, 10, -4, 2, -3, 2, 0, -2, 0, + 2, 2, -12, -2, 13, -2, -6, 0, -5, 10, 1, -1, -2, 0, -12, 3, + 11, 0, -5, -9, 7, -4, 2, -3, 0, 9, -2, -6, 0, 3, -2, -13, + 1, 12, -7, -3, 0, -1, -4, -4, -5, 1, 5, -4, -7, 2, 0, -3, + 5, -2, 10, -12, 5, 1, 10, 8, -6, 4, -12, 7, -1, 5, 0, -1, + -2, 7, 4, -4, 5, -4, -20, 6, 1, -6, 5, 0, -14, 3, -12, 3, + -8, 6, -10, 2, -4, -3, 1, 4, -7, 4, 8, 2, 1, 2, 2, 3, + 3, 0, 7, -7, 3, -1, -1, 11, 3, 1, -6, 0, -8, -10, 8, 6, + -4, -1, -5, -11, 3, -1, -14, 6, -4, -13, 10, 0, 1, -5, 0, 0, + 1, -3, 7, 4, 3, 3, -1, 6, 1, -1, -6, 2, 2, -3, -4, 15, + -17, -4, 1, -3, 4, -4, -6, -2, 4, 4, -4, 3, -4, -7, -2, 13, + -1, -4, -2, -3, 9, -7, -12, 13, 10, -12, -3, 4, 13, -14, -6, 12, + -4, -10, 11, -5, 4, -1, -17, 9, -1, 4, -3, -5, 6, 0, -7, 3, + 2, 4, -9, -9, 13, -8, 7, 6, -8, 11, -15, -11, 16, -10, -2, 1, + -8, -1, 11, -1, -4, 2, -13, 9, 3, 11, -16, 4, 7, -9, 9, 4, + -16, 11, 9, -10, 13, 4, -10, -12, 2, 4, 4, -10, 7, -6, 0, -8, + -3, 3, -1, -4, -9, -9, 3, -5, -3, 24, -19, -5, 7, -11, 4, 9, + 1, -3, -1, 7, -4, 4, 4, -4, -7, 22, 0, -1, 10, -19, 3, 1, + -6, 9, -7, 3, -5, -5, 5, 9, -17, -2, 4, -9, -4, 5, -3, -7, + -3, 6, -4, 10, -12, -3, 13, -6, -5, 5, 3, 8, 0, -7, 0, 2, + -3, 12, 3, -10, -4, -8, 8, -1, -16, 13, -5, -5, 0, 3, -6, -8, + -2, 13, -5, 12, -4, -17, 11, 0, 2, 2, 3, -6, -3, -3, 4, 7, + -3, 1, -2, -2, -3, -4, 7, -3, -4, 4, -5, 6, -11, 5, 7, -10, + 0, 2, -6, -1, 5, -3, 3, -5, 5, -8, 4, 10, -8, 3, -4, 7, + -5, 3, -3, -2, 4, 2, -4, -7, 2, -3, -5, 6, -2, 5, -4, 6, + -10, -5, 5, 0, -8, 6, -6, -1, -3, 5, 2, 0, -4, 10, -12, -5, + -21, -1, -4, 5, 3, 2, 18, -14, 8, 5, 1, -4, -5, -2, -9, 0, + -12, 20, -4, 7, 1, 6, 7, -1, -5, 13, -1, -7, 6, -2, -5, 2, + 1, 4, 6, -7, 6, -9, -3, 6, -3, 8, -10, 8, -6, 0, -20, 1, + -5, 5, -4, -8, -12, -13, 8, -2, 17, 3, -5, -20, -1, -7, 3, 22, + 22, 12, -11, -13, -15, -9, 21, -3, 25, 43, -4, -3, -6, -21, -30, -37, + -9, 8, -5, 8, 53, 50, 1, -5, -13, -15, -41, -23, 6, -34, -47, -17, + -2, 2, -13, 22, 29, 32, 44, 51, 55, 10, 15, 7, 0, -31, -48, -38, + -48, -43, -13, 7, 4, -46, -23, -6, 6, 4, 12, 50, 26, 4, 24, 40, + 33, 20, 17, 17, -7, -30, 10, -2, -17, 5, -36, -7, -38, -30, -13, 1, + 9, -1, -6, -29, -15, -11, 7, 3, 6, 16, 27, -22, -8, 5, 24, 27, + 0, 4, -5, -5, -2, 15, 12, 12, 2, 13, 0, -19, -26, 4, -19, -24, + -33, -21, -28, 0, 6, 18, 20, 15, 40, 2, -8, 17, 21, 47, -2, -12, + 11, -9, 22, -19, 3, -27, -29, -10, -38, -36, -42, 33, 12, -29, 10, -15, + 0, -1, -22, 24, 27, 8, 15, 7, 16, -13, 9, 33, 8, -4, 33, 70, + 21, -26, -18, -15, -22, -76, -2, 15, -35, -4, 8, 5, -3, -45, 6, 24, + -20, 6, -15, 8, -1, 2, 7, -4, 39, 4, 22, 34, -25, 26, -1, -31, + -4, 10, 2, 22, -25, -19, -2, -2, -44, -29, -17, 10, -6, 29, -8, 12, + 18, -9, -6, -36, 4, -14, -8, 10, -12, 28, 9, 16, 17, -29, 26, 0, + 1, 11, -13, 11, 1, 7, -7, -3, -5, 22, -10, 10, -29, 22, -29, -30, + 29, -30, 3, -43, 21, 5, -18, 6, -5, 23, 18, -31, 35, 28, -19, 9, + 13, 10, -3, -10, 37, -69, 7, 11, -16, 8, -76, 11, 58, -57, 18, -7, + -11, 26, -40, 100, -53, -1, 14, 3, -26, -35, 21, 20, -30, 10, -26, 37, + 25, -97, 118, -72, 37, 11, -15, 52, -22, 6, 85, -32, 24, -63, 48, -60, + -19, 3, -28, -19, 7, -28, 15, -22, 7, 20, -7, 16, -13, 8, 25, -27, + 2, 7, -18, 15, -30, 23, -3, 28, -31, 34, 22, -23, -6, -6, 28, -68, + -10, -3, -22, 12, -43, 70, -52, 32, 8, -4, 55, -14, 19, 21, 45, -13, + -33, -9, 20, -22, -14, 9, -21, -2, 6, -56, 17, -26, 23, -13, -8, -1, + 3, 31, 16, 20, -12, -10, 50, -27, -17, -13, -26, 29, -23, -7, 58, -40, + -20, 16, 16, -13, -65, 63, 18, -25, 23, -3, 6, 11, -11, -24, -19, 8, + 32, -44, 47, -50, 26, 6, 43, -58, 15, -21, 46, -81, 60, -28, 65, -37, + 42, 42, -55, -6, -23, -9, -52, -25, -5, 7, -67, 26, 59, -62, 31, 63, + -23, 52, -16, 27, 14, -13, 19, -41, -8, 37, -7, 9, -33, 16, 7, 36, + -40, -26, -26, 49, -3, 3, -50, 33, 23, -10, -13, -14, -19, -13, 1, 2, + -41, -19, 32, -3, -29, 9, 58, 1, 9, 15, 19, -19, 59, 2, 6, -6, + -24, 52, -67, 3, 5, -37, 3, 31, -42, 45, -1, -31, -6, 19, 11, -17, + -5, -2, -22, 3, -35, 35, -39, 8, 17, 6, 7, -32, 2, -1, 40, -32, + -2, 26, -5, 2, -5, -12, 18, 21, -15, 29, -28, 13, -23, 36, 28, -75, + 55, -53, 50, -45, 9, -3, 42, -10, -33, 8, -9, -17, 8, 13, -13, 34, + -48, 39, -5, -26, 24, 19, -34, 29, -41, 22, -42, -11, -15, 37, 0, -31, + 15, 4, 11, 18, -28, 23, -3, -52, 33, -1, -8, 19, -39, 44, -3, -16, + 31, 7, -17, 38, -44, 62, -21, 0, -7, -13, 25, 12, -50, -13, 2, 9, + -47, 43, -29, -12, -3, -3, -37, -22, 0, -6, 60, -69, 27, 9, 12, 13, + -7, 46, 43, -2, 3, -5, -5, 17, 13, -37, 35, -39, -38, 33, -44, -10, + 11, -9, 50, -68, 26, -22, 10, -20, 34, -13, -17, 21, -34, -1, 42, -23, + -7, 9, 3, 1, -1, -9, 36, -15, 5, -21, 40, -47, 25, -11, 20, 24, + -19, 16, -13, 6, -25, -2, 19, -17, 7, -36, 28, -8, -28, -11, 9, 25, + -55, 7, 39, -36, -3, 8, 28, 25, -33, 29, 1, -28, -1, -7, 40, -50, + 22, 15, 21, -2, -1, 18, 8, 46, -52, -1, 14, -39, -10, 18, -10, -27, + -15, -9, 2, -7, -47, 23, 17, -40, 12, 37, -24, 22, 9, 5, 27, -14, + -17, -17, 23, 16, -18, 19, 32, -19, -10, 13, 12, -33, 31, -4, 12, -17, + 22, -3, -8, -33, 16, -45, -17, -13, -24, 23, 19, -22, 52, -63, 23, 26, + 8, -11, 30, 40, -35, 28, -5, 11, -10, -16, 18, -35, -21, -6, 9, 0, + -33, 9, -15, -24, 15, -23, -19, 30, 13, -20, 37, 24, -48, 47, 21, -31, + 51, -22, 40, -24, 47, -55, 31, -21, -57, 15, -7, -28, 5, 25, -12, -42, + 46, -43, -21, 6, 4, 14, -15, 11, 51, -27, 6, 21, -27, 42, 17, -35, + 3, 3, -15, 11, 17, -26, 0, 6, 11, 18, -37, 4, 28, -14, -14, -30, + 43, -50, -17, 55, -50, 16, -32, 51, -35, -13, -4, 54, -22, 23, -48, 51, + 2, 10, -16, 7, -10, 15, -48, 25, -5, -4, 6, 21, -17, -2, 30, -23, + 16, -3, -12, -11, 21, -57, 3, 10, -3, 0, -19, 36, -42, 50, 0, -30, + 55, -15, 12, -10, 28, -47, 29, -16, 6, -37, -1, -6, 3, -45, 35, -30, + 8, -4, -12, 32, 42, -23, 3, 5, 30, -38, 15, 16, -36, 60, -1, -53, + 28, -25, -10, 45, -20, 2, -22, 24, -6, -19, -31, 18, 6, -56, -15, -3, + -5, 1, 12, 5, -7, 70, -9, -7, 49, -31, 48, 36, -15, 5, -23, 35, + -51, 4, -32, -40, 7, -20, -15, -7, 17, -32, -2, 17, 1, -8, 46, -4, + 12, 15, 41, -50, 29, -21, -13, 10, -20, 12, 2, -24, 12, -1, 6, 8, + -29, 19, -27, 51, -67, 83, -44, -22, 21, -2, -14, 13, -52, 72, -37, 19, + -25, 43, -37, -22, 19, -12, -36, 14, 17, -3, 27, -39, 58, -23, 1, 14, + 52, -25, 15, -1, 1, -23, -11, -9, 4, 14, -83, 23, 4, -38, -21, 2, + -1, 17, 2, 48, -30, 24, 29, 9, 19, -44, 46, 22, 5, -32, 39, 0, + -28, -27, 16, -32, -31, 7, -17, -13, -9, -6, 14, -33, -18, 35, -39, 52, + -40, 31, 12, 14, -24, 52, -35, 11, 1, 26, 10, -18, 20, 7, -7, -5, + 7, 5, -15, -10, -7, 8, -10, -26, 21, -16, -14, 13, -27, 27, -44, 6, + 18, 6, -12, -4, -11, 12, -1, 7, 6, 3, 20, -5, 11, 15, 9, -10, + 37, -37, -3, 11, -23, 9, -35, 19, -32, 4, 14, -28, 41, -42, 43, -5, + 11, -20, -16, 20, -10, 6, 6, -4, 1, -6, 7, 20, -42, 25, -29, 34, + -31, -10, 14, -4, -9, -4, 13, 7, -7, -2, -19, 25, -10, 0, 16, -1, + -9, -6, 53, -52, 10, -7, 5, -10, 1, 4, 9, -24, 10, -21, 61, -40, + 3, 3, 12, -38, 31, -3, -7, 8, -13, 8, -15, 4, -33, 44, -29, 5, + 5, 37, -52, 16, -13, 25, 7, -34, 17, -7, 14, -11, 24, -32, 22, -23, + 42, 5, -30, 21, 19, -21, 2, -11, 14, -18, -16, -34, 41, -30, 7, 2, + -23, 20, -37, 26, -17, 18, -37, 64, 0, 14, -19, 5, 12, -8, -13, 22, + -9, -26, 24, 17, -8, 3, -5, -14, -14, 17, -30, 14, 26, -67, 38, -9, + -20, 11, 11, -22, 11, 15, 1, 11, -22, 0, 1, 38, -43, 2, 15, -31, + 2, -5, 29, -18, -27, 21, -8, 15, -20, 46, -24, 20, 16, -7, 24, -63, + 40, -8, 9, -8, 14, -10, -11, -28, 4, 10, 8, -26, 13, 11, -35, -1, + 40, -36, -5, -3, 38, -7, -23, 3, 4, 17, 3, -15, 11, 24, -67, 26, + 2, 21, -54, 30, 14, -34, 12, 25, -16, 12, -13, -7, 47, -24, -23, 7, + 18, -4, -19, 31, -18, -14, -11, 21, -15, 5, -31, 40, -53, 21, -4, 30, + -32, -3, 14, -5, 30, -17, 3, 13, 8, -4, -5, -11, -12, 8, -7, 16, + 10, -21, 35, -59, 13, 10, -3, -7, 1, 2, -16, -4, 27, -43, 35, -16, + -14, 36, 0, -51, 13, 31, -19, 14, 21, -19, 14, -3, -27, 29, -10, 34, + -46, 30, -12, -17, 11, -34, 23, -23, 10, -3, 4, -8, -14, 25, -16, 35, + -12, 22, -7, 3, 9, 0, 11, -5, -10, -16, 9, -21, 7, -36, -4, -13, + 4, -6, -7, -2, -1, 0, 14, 16, -15, 7, 27, -28, 43, -32, 17, 7, + -25, 33, -7, 6, -10, 11, -20, 1, 5, 28, -11, -26, 20, -17, 29, -40, + 1, -6, 13, -23, 23, -23, -28, 18, 5, -22, 16, -19, 41, -9, -16, -11, + 45, -17, 6, -51, 34, 36, -44, 29, -33, 22, -13, 3, 5, -26, 2, 11, + 23, -17, 0, -7, 12, 3, -27, 18, 13, -2, -30, 22, -6, 7, 1, -4, + 5, -1, 12, -14, 1, -15, -5, 12, 6, 3, -13, 15, -14, 14, -1, -12, + 3, 3, -4, -18, 7, 2, -7, -5, 9, -15, 7, 17, -27, 45, -52, 60, + -15, -12, -9, -11, -14, 27, -18, -9, 21, -10, 10, 3, -23, -4, 8, -23, + 19, -31, 12, 18, 12, -7, 1, 15, 3, 27, -38, -7, 42, -9, 1, -7, + -22, 5, -10, 0, -28, 5, 12, -6, 0, -12, -15, 18, 19, -14, -27, 47, + -6, -1, -21, 32, -31, 52, -41, 3, -39, 34, -29, 16, 8, -6, 33, 16, + -23, -10, 16, 9, 2, -33, 40, 0, -21, -2, -18, 1, 13, -32, 24, -11, + -14, 24, -20, 0, -19, 11, 23, 1, -30, 4, 38, -23, 11, 0, 9, 18, + -36, 10, -21, -1, -5, -1, 23, -24, 9, 27, -13, 4, -39, 60, -17, -11, + -12, 25, -9, -36, 26, -7, -3, 28, -27, 26, -12, -20, 8, 13, -40, 7, + -23, 38, -33, 14, 8, -1, -23, 36, -19, 15, 13, -36, 4, 17, -32, 31, + -23, 20, 0, 23, -3, 5, -17, -11, 12, -24, 21, -29, 34, -26, -1, 4, + -14, 21, 9, -1, -1, 21, -33, 29, 1, -28, 28, -20, 22, -24, -13, -13, + -6, 10, -22, 33, -49, 17, -24, 1, 22, -11, 43, -27, 28, 28, -33, 36, + 5, -5, 2, 22, -28, 16, -24, -16, 4, -69, 66, -47, -12, 19, -17, -1, + 24, -32, 46, -36, -3, 50, -26, 24, -22, 9, 39, -53, 0, 32, -1, -21, + 29, -26, -4, 29, -45, 12, -10, 11, -12, 20, -23, -11, 20, 10, -1, -24, + 33, -16, 12, 2, 4, 14, -17, -17, 20, -42, 6, -18, 0, -4, -10, 11, + 2, -10, 4, 7, 2, 27, -35, 11, 12, 4, -11, 19, -19, 40, -6, -16, + 44, 2, -10, 32, -37, 1, -23, -8, 23, -59, 11, -5, -9, -9, -1, -8, + 5, -18, 26, -14, 27, -10, 9, 30, 23, -31, 30, -1, -1, -14, -13, 35, + -76, 42, -79, 43, -29, 1, 2, -5, -6, 5, 30, 15, -20, 23, 25, -37, + 39, -5, -20, 24, -7, 2, 20, -38, 20, -31, -12, -2, -12, 13, -31, 10, + -9, 0, -11, 27, -16, 10, -2, 44, -46, 18, 33, -16, -12, 3, 11, 15, + -26, 8, -22, 19, -3, -11, 5, -48, 31, 16, -15, -5, -2, 17, 6, -9, + -8, 9, 25, -7, 0, 7, -8, -5, 10, -11, -26, 26, -15, 17, -31, -11, + 15, -1, -16, 1, 10, 4, -7, 18, -6, 2, 11, -2, 11, -26, -4, 25, + -27, -19, 7, 29, -29, 13, -10, 3, -27, 31, -55, 38, -13, 17, -9, 32, + -27, 17, 18, -3, -10, 17, -45, 58, -12, -18, 25, 4, -40, 35, -61, 10, + -3, 2, -15, -14, 33, -20, -2, -4, -19, 31, -29, 25, 8, -11, -3, 32, + 1, -26, 12, 25, -42, 5, 27, 1, 2, 17, -25, -2, 6, 9, -17, 9, + -11, 9, 9, -21, 11, 15, -55, 34, -24, -6, -1, -9, 17, -13, 1, -11, + 31, -24, -15, 38, -21, 27, -30, 30, -35, 28, 15, -30, 56, -40, -17, 39, + -9, -7, 4, -18, 7, 13, -25, 3, -9, -13, -13, 27, -35, 13, 0, 6, + -3, 26, -20, 27, -23, 25, -25, 38, -2, -3, 8, -11, 0, 0, 0, -28, + 28, -27, -6, 23, -33, -8, -1, -29, 0, 2, 26, -40, 15, 2, 23, 28, + -32, 17, 26, -17, 10, 1, -14, 17, 1, 14, -9, -10, -15, 12, -3, -19, + 2, 20, -19, -19, -14, 4, -2, -8, 13, -16, 22, -9, 28, 7, -9, -22, + 49, -28, 3, -5, 9, -2, 5, -26, 39, -12, -29, 19, -11, 7, -33, 27, + -32, 15, -9, -9, 16, -7, -3, 27, -4, -18, 19, 23, -20, 3, 2, 11, + -21, 14, 4, -13, 8, -15, 9, 4, -37, 9, -11, 22, -20, -12, 17, 12, + -20, -2, 13, 18, -19, -1, 19, -28, 12, 2, 12, 2, -37, 12, 21, -19, + -23, 17, 21, -35, 9, 26, -20, -15, 12, 14, 23, -20, 17, 9, -16, -4, + 5, 3, -8, -24, 13, -5, 5, -7, -11, 31, -24, -34, 28, -8, -26, 16, + -7, 2, -2, 9, -21, 42, -54, 34, 42, -22, 16, -1, 14, -15, -12, 21, + -16, -3, -18, 55, -46, 11, 6, -19, 18, -36, -9, 12, -21, 23, -41, 37, + -12, -10, 1, 13, -5, -7, 42, 2, 1, -2, 4, -3, 15, -53, 27, -3, + -26, -14, 32, -30, -5, 11, 12, -3, -4, -24, 35, -37, 12, 4, 5, -17, + 32, 0, -18, 41, -41, 43, -2, 22, -36, 7, -5, 11, -25, 7, -29, 9, + 2, -4, -11, 5, -2, 15, -31, -11, 24, 3, -15, 26, 11, -10, 18, 5, + -8, -2, -43, 43, 2, -43, -20, 25, 4, -3, 39, -11, -6, -3, -1, -12, + 22, -21, 6, 22, -7, -17, -5, 18, -4, -14, 3, 18, -11, -18, -3, -2, + 2, -5, 1, 10, -28, 17, 8, -8, -12, 23, -13, 10, 0, -12, 14, 11, + -11, 34, -21, 3, 1, -9, -17, 1, 9, -28, 5, -34, 21, -8, 8, 8, + -13, 18, 2, -15, 5, -3, 11, -2, 11, -2, 15, -10, 14, 5, -1, 18, + -6, 1, -26, 13, -25, 2, 6, -39, -14, 0, -5, 13, -22, -14, 34, -22, + -1, 16, -13, 11, 32, -10, 31, -5, 18, -21, 34, -47, 32, -9, 10, 8, + -31, 5, 4, -9, 5, -52, 16, -14, 4, 20, -11, -13, 13, -10, -12, 11, + 16, -20, 13, -12, 14, 10, 1, -15, 32, -24, 18, 0, 5, -26, 6, 16, + -23, -10, 12, -40, 17, -14, -13, 38, -5, 5, -19, -3, 17, 14, -8, 8, + -15, 21, -6, 10, -12, -16, 27, 6, -35, 16, -26, 45, -25, -1, -9, 29, + -25, 8, -31, 9, 25, -10, 4, 11, -22, -5, 1, -12, 6, -10, -11, 17, + -31, 5, 21, -6, 33, -55, 47, 6, -6, 2, 11, 14, -11, 10, -14, -26, + 8, -18, 4, 11, 6, -4, -2, -20, -2, -26, 38, 4, -24, -6, 7, 22, + -15, 30, 0, 13, 3, -11, 4, -10, -28, 38, -14, -9, -5, -45, 40, -21, + -28, 31, 0, -9, 18, -45, 20, 12, -20, 39, -25, 14, 1, 17, -4, 29, + -12, 26, -8, -21, -19, 10, 3, -31, 34, -16, -12, 5, -14, -4, -13, 13, + -7, 13, -15, -23, 40, -27, 15, 4, -11, 23, -20, -2, 7, 8, 3, 2, + -4, 1, 7, -22, 42, -37, 24, 1, -9, 16, -31, 9, 6, -3, -25, 40, + -41, 0, 2, -7, 18, 0, -10, 21, -5, -17, 29, -37, 27, 3, -22, 10, + 11, -5, 13, -17, 15, -19, -23, 17, -10, -35, 20, 4, -4, 3, -10, 7, + 15, -14, 10, -3, 10, -25, 13, 1, 20, -13, 13, 19, -38, 18, -4, 19, + -10, 9, -27, 19, -35, -8, -10, 39, -14, 2, 14, 36, -16, -8, -8, -7, + -2, -11, 4, 1, -42, 51, -17, 10, -15, -33, 29, -25, -7, 6, 2, 11, + 3, -20, 37, -28, 6, 34, -22, 5, 28, -4, 17, 5, -47, 28, 1, -3, + -21, 8, -6, -7, 10, -15, 6, -30, 6, -19, 1, -4, 30, -22, 29, -13, + -4, -2, 11, -1, -15, 38, -4, -9, 25, -29, -17, 10, -2, -3, 7, -15, + 24, -26, 21, 2, 6, -20, 10, -26, 41, -33, 19, -11, 6, -3, -9, 5, + 3, -21, 8, -5, -7, 10, 13, -10, -3, -4, -10, 26, -1, 1, 5, 11, + -3, 2, 23, -35, 21, -43, 17, -4, 2, -24, 14, -22, -3, 3, -5, -2, + 12, -13, 16, -5, 7, 17, 4, -44, 26, 17, -4, 36, -58, 43, -20, 8, + 3, -23, -18, -17, 16, 4, 3, -33, 15, -4, -10, 19, -20, 23, 13, -6, + -4, 25, -12, 21, -9, -4, 6, -1, 23, -7, -15, 3, -15, 3, -13, -23, + -3, -32, 4, 6, -18, 0, 11, -14, 42, -37, 26, -20, 50, -18, 18, 11, + 4, 18, -5, 8, -22, 30, 5, -20, 16, -20, -28, 2, 4, -10, -10, -10, + -27, 38, -38, 14, -17, -20, 34, -11, -5, -5, 10, 5, 25, -20, -2, 28, + -8, 26, -39, 68, -50, 53, -35, -5, 3, -23, 24, 8, -21, -28, 19, 6, + -18, -13, -7, 26, -7, 0, -4, 7, -7, -15, 29, -10, -12, 13, 9, -4, + -34, 39, -49, 38, -31, 29, -26, 2, -18, 45, 3, -16, -2, 29, 4, -27, + 2, 17, 6, -12, -3, 12, -12, -14, -22, 11, -13, 6, -2, 30, -39, 12, + 5, 10, -18, 3, -5, 24, -39, 15, 49, -42, 19, 9, -25, 5, -60, 31, + -19, -8, 9, 28, 28, -34, 21, -4, 25, 24, -18, 17, -35, 1, 7, -28, + 32, -29, 6, 7, 4, -23, 21, -17, -14, 16, -29, 21, -43, -24, 2, 58, + -33, 60, -20, 24, -29, 18, -24, 29, -14, -6, 10, -19, 15, 38, -38, 35, + -15, -11, 20, 9, -57, -4, 0, -8, 15, -8, -20, -6, 9, 21, 8, -21, + 12, 1, 6, -29, 24, 17, 6, -33, 26, 20, -12, 14, -17, 3, -2, -19, + -6, 13, -55, -5, 5, 8, 21, -12, 11, -13, 15, -34, 45, -47, 43, -6, + 5, 34, -32, 28, -15, 12, -38, 30, -16, 1, -4, -2, 6, 4, -26, 2, + 21, -42, 5, 19, -20, 44, -70, 38, -5, -4, -8, 20, -16, 22, -25, 46, + -21, 1, -31, 48, -32, 7, -23, 62, -48, 38, -2, -30, 41, -57, 41, -41, + 9, -5, 16, 9, 1, -50, 80, -48, 5, -20, 11, -9, -19, -8, 1, 20, + -24, 4, 36, -42, 42, -32, 39, 6, -12, 1, 12, 3, -17, 2, -13, 57, + -70, 26, 6, 0, -23, 8, 4, -17, -10, -41, 34, -10, -46, 51, 23, -10, + -4, -10, 16, -9, 4, 32, -14, 6, -7, 23, -18, -9, 5, -14, 4, 15, + -29, 10, 15, -14, 19, -28, 40, -30, -20, 17, 3, 5, 37, -32, 12, 0, + -18, 1, -7, -23, 4, -51, 69, -22, -43, 30, -39, 54, -64, 29, 21, -2, + 2, -22, 29, 2, 14, 5, 8, -7, 7, 34, 2, -25, 10, -7, -5, 24, + -64, -1, -18, -7, 23, -24, 26, -23, -35, -17, 51, -60, 53, -2, 14, 17, + 6, 5, 11, -9, 15, 21, -1, 21, -49, 45, -34, -16, 12, 0, -34, 2, + -67, 50, -48, 23, -20, -12, 20, -22, 32, -15, 15, -23, 65, -9, 33, 26, + -3, 4, 14, 8, -17, -17, -47, 57, -63, 13, 8, -30, -8, -31, -12, 28, + -45, 9, -3, 19, -31, 31, -2, 41, -46, 38, 38, -23, 21, -13, 9, 35, + -2, 5, 13, -36, -2, -10, 15, -16, -48, 22, 29, -49, -21, 15, -10, -15, + -23, 26, 40, -39, 26, -10, 13, 21, -46, 35, -20, 8, -1, 30, 17, -64, + 22, 2, 22, -30, 6, 19, -18, -34, 38, -4, 13, 0, -11, 50, -51, 21, + -10, 13, -42, -9, 45, 4, -82, 12, 37, -11, -12, -8, 21, 6, -33, 32, + -14, 6, 13, -44, 37, -22, 20, 2, 12, -15, 26, 30, -17, -11, -30, 18, + -4, -5, 11, -2, -22, -15, 25, -16, 11, -15, 21, -8, -17, -9, 27, 11, + -43, 2, 4, 31, -59, -5, 44, -16, 26, -13, 3, 1, -1, -40, 70, -44, + 43, -15, 2, 22, -36, 13, 41, -43, -12, 4, 12, -34, -22, 9, 22, -23, + -22, 27, -24, 22, -18, 45, 12, -32, 7, 17, -24, -15, 4, 20, 6, -40, + 29, 48, -64, 28, -3, -6, 43, -22, -34, 36, -41, 13, -2, -59, 72, -53, + 39, -30, -3, 16, 29, -40, 5, 30, -21, 15, -35, 9, 14, 2, 4, -16, + 4, 8, 14, 1, 30, -32, 5, -14, 28, -26, -1, -12, -16, -4, -22, -5, + 28, -8, -24, 7, 42, -22, -3, -9, 16, 38, -42, 25, 8, 10, -9, 38, + -28, 31, -8, -34, 22, -70, 21, 15, -36, -10, -15, -1, 49, -37, -17, 51, + -24, 11, 30, -27, 33, -39, -12, 36, -4, -49, 38, 12, 10, -17, -11, 59, + -26, -59, 33, 28, -37, 17, -39, 40, -16, -29, 28, 14, -19, -14, 18, 23, + -17, -16, 15, -11, 9, -16, 45, -25, -27, -1, 40, -36, 1, 19, -1, -14, + -3, 1, 29, -9, -58, 54, -12, -19, 16, 13, 29, -74, 48, -20, 22, -66, + 3, 23, 2, -31, 11, 41, -41, 2, 25, 4, 8, -3, 8, 23, -10, -6, + 27, -1, -67, 31, -29, 29, -29, 0, 17, -20, -18, -10, 29, -45, 43, -35, + 61, 4, -49, 31, -10, 53, -60, 19, 11, 15, -22, -3, -20, 26, 3, -60, + 59, -41, -26, 17, 22, 12, -6, -12, 30, -14, -8, -7, 16, 54, -34, -18, + 26, -15, -11, 7, -44, 39, -52, 48, -53, 18, -38, 3, 13, -11, 37, -12, + 11, 9, 14, -7, 40, -19, -6, 6, -15, 29, -34, 1, 18, -18, -9, -24, + -30, 17, -50, 31, 4, 8, 17, -7, -5, 0, 17, 25, 16, 15, 43, -54, + 39, -10, 2, -40, -23, 26, 3, -61, -2, 15, -6, -56, 46, -2, 16, -80, + 43, 52, -9, -30, 41, 17, 2, -33, -7, 52, -7, -29, 31, 0, -23, 10, + -24, 44, -82, 18, 45, -14, -40, -40, 40, 12, -66, 0, 74, -35, -5, 17, + 67, -59, 32, -4, 29, -1, -48, 39, 1, 8, -63, 43, -12, -37, -5, -12, + 25, 2, -21, 7, 24, -34, -11, 19, 28, 6, -34, 44, 13, -35, -19, 28, + -50, -13, 56, 7, -32, -12, 19, 6, -1, -6, 6, 0, 17, -26, 41, -20, + -5, -6, 43, -58, 10, -12, -14, 74, -84, 74, -28, -15, -27, 19, -15, -3, + 17, 24, 10, -60, 64, 0, -9, -39, 1, 25, -12, -25, 22, 8, -21, -40, + 73, -32, -18, -11, 6, 57, -52, 36, -19, 37, -40, 9, 2, 14, -15, 27, + -33, 35, 7, -37, 24, 10, -66, 17, 1, -10, 13, -38, 15, -9, 43, -30, + 19, -15, 17, -8, 7, 8, -38, 66, -55, 10, 9, -37, 37, -32, -11, 47, + -14, 11, 37, -41, -33, 12, 3, 34, -59, 35, 14, -4, -7, -2, -21, 48, + -52, 49, -8, -44, 0, 11, -6, -2, 11, -35, 64, -38, -35, 64, 7, -32, + 15, 15, 19, -39, 18, -31, 25, 6, -28, 25, 17, -34, -26, 21, -18, 15, + -15, -31, 24, -4, -26, 41, -2, -18, -24, 75, -21, 1, -6, -2, 16, 12, + -24, 15, 8, -14, 7, 7, -4, -37, 45, -67, 39, -41, 9, 19, 13, -60, + 44, -22, 23, 2, -35, 14, 35, -25, 7, 21, -39, 15, 1, 39, -43, 26, + -18, -14, 36, -10, -16, -15, 29, -34, 16, -1, -13, 24, 0, -43, 55, -18, + -31, 22, -15, -15, 43, -33, 50, -10, -43, 22, -27, 60, -30, 14, 0, 10, + -3, 10, -20, 11, -34, -7, 70, -59, -26, 25, -23, 7, -29, 8, 11, -13, + -8, 3, 13, -13, 35, -8, 34, -33, 9, 30, -5, 33, -37, -10, 56, -38, + -5, 14, -50, -24, 39, -11, -11, -27, -22, 46, -13, -6, -1, -6, 37, -56, + 48, -11, 24, -14, 32, -13, -1, 5, 8, 37, -86, 36, -1, -6, -12, 13, + -40, 3, 9, 15, -13, -23, 3, -15, 61, -50, -12, 29, -14, -2, 25, -31, + 52, -41, 31, 31, -27, -10, 9, 22, -15, 3, -11, 22, -25, 8, -40, 0, + -5, 2, -9, 40, -62, 5, 16, -6, -7, -21, 31, 29, -28, -3, 47, -31, + 51, -34, 59, -32, -8, 44, -7, -2, -20, 3, 64, -51, -58, -3, 0, -39, + 26, -22, 14, -39, 8, 20, -30, -2, 7, 8, 37, 15, -9, 43, -5, 2, + 11, -5, 10, 2, -37, 56, -59, -11, 8, -14, -30, -29, -3, 29, -1, -33, + 42, -44, 53, -58, 85, -28, -5, -2, 41, 5, 15, -49, 30, 26, -46, 17, + 9, -55, 0, 38, -46, 32, -32, 10, 15, -60, 8, 23, -1, 7, -35, 71, + -11, -39, 39, -22, -8, -3, 10, 36, 13, -73, 53, -15, 7, -7, -15, 25, + -7, -24, 21, 9, -51, -11, 27, -15, 11, -6, 26, -26, 27, 16, -33, 47, + -29, -18, 53, -53, -2, 38, -29, 12, -37, 18, 10, -10, -20, -8, 12, 15, + -43, 32, 3, -44, 35, 29, -38, 17, -16, 13, 45, -37, 21, 18, -7, -38, + 32, -21, -6, -4, 20, -14, -9, -16, 14, 1, -19, -13, 22, -4, -39, 58, + -34, 3, 17, -10, 50, -3, -47, 36, 29, -27, -13, 39, -20, -8, 12, -40, + -20, 1, 0, -24, 23, -40, 38, 4, -1, -19, 16, 10, -4, 28, -25, 44, + -17, 19, -21, 50, -10, -16, -13, 7, -28, 11, -9, -17, 13, -52, 22, -3, + -21, -49, 75, -42, 34, -3, 18, 1, 10, -20, 13, 13, 22, -11, -35, 46, + -29, 44, -39, -31, 37, -22, -27, 42, -57, 40, -34, 4, 12, 9, -29, 13, + 6, -10, 4, 21, 7, -17, 3, 25, -18, 44, -26, -1, 20, -38, 19, 24, + -35, -18, -6, -14, 23, -32, -15, 24, -6, -50, 62, -39, -3, 0, -23, 87, + -44, 37, -9, -4, 67, -73, 46, 45, -32, -14, 8, -4, -22, -5, -22, -20, + 36, -34, 6, 26, -35, -18, 15, 0, -12, 0, 12, -10, 28, -15, 24, 13, + -21, 19, 15, -17, 20, -7, 0, -21, 7, -16, 5, -12, -1, -11, 7, 32, + -68, 69, -55, 24, 2, -3, 21, -47, 28, 20, -15, -29, -2, 23, 4, -18, + 15, -22, 36, -38, 17, -23, 14, -18, 17, 31, -37, 30, 8, -1, -3, -5, + -12, 22, -18, -28, 33, 0, -9, -16, 20, 9, -26, -20, 21, 2, -4, 14, + -24, 16, -11, 12, -1, -39, 7, 51, -2, 1, -12, -30, 63, -43, -19, -2, + -6, 20, 10, -18, -2, 23, 15, -3, -34, 1, 9, 10, -22, -29, 28, 28, + -32, -2, 23, -26, 2, 11, 25, -35, -14, 15, 23, -48, 12, 7, 22, -52, + 25, 17, 16, -47, 29, 13, -19, 12, -67, 65, -6, -30, 32, 7, -12, 14, + -19, 27, -52, -2, 15, 40, -69, -5, 33, 15, 6, -51, 36, 21, -2, -24, + 15, -3, -9, -4, 30, -34, -2, -19, 27, -23, 3, -12, 2, 18, -15, -6, + -3, 22, -30, 55, -21, 26, -35, 44, -27, 25, -21, 4, 14, -20, -1, 10, + -42, 12, 7, -12, 5, -37, 13, 1, 3, -33, 24, 15, 0, -4, 10, -14, + -6, 35, -6, -4, -8, 13, 26, -7, -32, 36, -9, 5, -15, 14, -15, -36, + 8, 2, -15, -22, -7, 28, -4, -25, 17, 39, -16, 4, 20, 8, 4, -2, + 4, 31, -46, -12, 15, 0, -9, -36, 18, -10, -12, 7, -17, 3, -13, -4, + 37, -27, 6, -16, 76, -41, 13, -14, 25, 28, -21, -10, 31, -4, -39, 21, + -9, -35, 12, 3, -16, 7, -54, 51, -34, 44, -45, 30, -7, -30, 49, -21, + -1, 27, 12, -8, 9, 8, 5, -27, 42, -30, 32, -28, -27, 19, -18, -36, + 10, -25, 19, -9, -14, -5, 13, 31, -21, 22, -28, 15, 13, 10, -12, 6, + 32, 1, 24, -47, 36, -4, -23, 0, -16, 6, -41, 1, 17, -33, -9, 5, + 34, -5, -15, -1, 30, 13, -30, 20, 7, -12, -16, 11, 20, -4, -19, 21, + 26, -25, -17, -5, 23, -32, -3, -12, 18, -5, -28, 8, 15, -14, -10, 31, + 11, -43, 12, 35, -5, 3, -33, 48, -1, -11, -6, 28, -23, -13, 13, 9, + -7, -22, 2, -25, 32, -38, 17, -16, 10, -54, 69, -62, 61, -30, 4, 24, + 3, -12, 4, 27, -22, 22, 0, 4, -15, 4, -46, 20, -16, 29, -30, 14, + -25, 30, -18, 16, -12, -7, 21, -10, 16, -23, 15, 9, -12, 12, 13, -21, + 19, -28, -2, 5, -15, 0, 3, -17, 6, -6, 18, -11, 6, 13, -1, 15, + -23, 14, 5, -17, -14, 5, 24, -23, 15, -26, 9, -10, 15, -29, 2, -12, + 23, 8, 10, -37, 26, 7, -5, -25, 3, 16, 14, -10, -5, -16, 22, -7, + -8, 18, -58, 86, -15, -5, 4, -30, 40, -7, -21, -12, 9, -10, 16, -48, + 40, -29, -6, -5, -22, 21, 3, -20, 39, -36, 29, -5, 2, 3, 15, 2, + 6, 21, -11, 28, -13, 2, -33, 24, 1, -28, 12, -33, 12, 11, 0, -41, + 11, -5, -9, 26, -34, 15, 2, 18, -7, -25, 5, 11, -4, -7, 35, -6, + 23, 12, -42, 33, -32, 26, -41, 25, -23, 15, -13, 11, -5, -4, 0, -8, + -4, 1, 10, 6, -8, -7, 18, 8, -11, -19, 9, 17, -2, -13, 8, -21, + 31, -16, -24, 3, -12, 10, 23, -8, 12, 8, 23, -7, -22, -8, 5, -5, + -14, -33, 4, 7, -11, -11, 15, -22, 38, -2, -11, 24, -16, 38, 14, -6, + 7, -14, 18, -13, 2, -8, -14, 13, -19, -13, 2, 2, -23, -9, 11, 1, + -12, 16, 1, 2, 18, 1, -20, 9, -5, -14, 16, -11, 2, 8, -2, -9, + 0, 11, 13, -22, 18, -16, 35, -39, 45, -22, -18, 12, 1, -19, 21, -48, + 42, -20, 9, -23, 20, -11, -27, 21, -13, -14, -11, 29, -13, 25, -25, 36, + -13, 8, 17, 34, -14, 11, 4, -4, -15, -9, -12, 1, 19, -69, 7, 10, + -34, -20, 1, -5, 13, 6, 34, -17, 5, 40, -1, 21, -38, 35, 22, 11, + -28, 28, 11, -25, -26, 12, -20, -38, 10, -16, -11, -11, -6, 13, -22, -31, + 43, -42, 49, -33, 20, 17, 13, -22, 44, -21, -4, 14, 9, 33, 10, 0, + -1, 0, 0, -2, 11, 23, 22, 24, 25, 20, 21, 15, 40, -1, -24, -42, + -5, -19, -11, -8, 4, -46, -31, -14, -33, -40, -44, -48, -89, -63, -47, -33, + -27, -10, -6, 22, 25, 26, 28, 37, 11, 15, 51, 44, 54, 66, 66, 71, + 111, 84, 70, 63, 47, 39, 22, 47, -28, -79, -111, -90, -91, -112, -81, -87, + -49, -46, -5, -24, 26, 24, 47, 29, 23, 30, 30, 13, -1, 4, -14, 17, + 35, 62, 31, 53, 59, 72, 64, 27, 26, 9, 9, -61, -44, -88, -74, -81, + -83, -124, -96, -37, -78, -48, -56, -68, -60, 7, 44, 39, 54, 77, 102, 110, + 108, 89, 101, 100, 105, 64, 22, -1, 44, 40, -19, -29, -35, -16, -27, -40, + -77, -82, -113, -104, -93, -57, -72, -56, -3, 1, 7, -1, 49, 39, 30, 31, + 23, 10, 31, 11, 7, -19, -2, -2, 28, 62, 92, 75, 33, 34, -20, -47, + -61, -85, -105, -93, -119, -112, -54, -70, -67, -32, -1, 4, 4, 20, 29, 62, + 70, 54, 62, 78, 115, 92, 85, 78, 52, 21, 19, 27, 2, -8, 13, 0, + 5, 3, 9, 18, 0, -59, -61, -45, -57, -65, -76, -89, -102, -48, -24, 17, + 6, 26, 33, 35, 26, 41, 63, 20, 12, 29, 34, 8, 7, 31, 21, 31, + 39, 33, -5, -8, -55, -57, -98, -94, -88, -64, -82, -74, -39, -14, 3, 16, + 22, 8, 2, 17, 5, 36, 76, 74, 71, 57, 73, 62, 47, 30, 32, 19, + 4, 7, -14, -18, -2, 17, -5, 13, 22, 31, 10, 8, -13, -47, -80, -85, + -86, -71, -73, -60, -35, -10, 9, 19, 49, 53, 47, 60, 73, 43, 33, 20, + 13, -1, -7, -7, 7, 9, -2, 5, -14, -40, -69, -61, -66, -67, -84, -58, + -58, -33, 2, -7, -5, 12, 32, 18, 25, 19, 24, 65, 59, 62, 64, 63, + 55, 60, 52, 31, 19, -12, -26, -4, -7, -10, -3, 6, -22, -14, 12, 19, + 4, -26, -38, -40, -56, -61, -66, -59, -65, -51, -20, 29, 40, 51, 52, 62, + 61, 53, 26, 20, 6, 8, 6, 9, -14, -14, -15, -2, -11, -23, -36, -38, + -60, -77, -69, -60, -51, -56, -44, -27, 10, -2, 14, 10, 22, 16, 41, 60, + 39, 35, 60, 62, 43, 45, 63, 52, 17, 12, 15, -1, -2, 0, -38, -48, + -32, -22, -7, 3, 13, 10, -2, -1, -8, -12, -25, -48, -46, -52, -49, -36, + -17, 9, 17, 26, 48, 57, 55, 69, 60, 32, 6, 4, -6, -20, -24, -9, + -21, -25, -14, -18, -38, -38, -32, -51, -52, -60, -34, -6, -6, -16, -11, -2, + -1, 17, 19, 3, 11, 25, 31, 41, 39, 33, 33, 41, 34, 34, 23, 21, + 15, 6, -13, -24, -28, -20, -8, -12, -19, -12, -5, 9, 14, 2, -12, -25, + -28, -21, -28, -23, -22, -18, -26, -5, 24, 45, 46, 47, 39, 33, 36, 42, + 29, 7, -5, -10, -21, -29, -39, -39, -31, -24, -29, -39, -51, -43, -27, -22, + -18, -25, -26, -20, 9, 19, 18, 4, -2, 19, 30, 38, 25, 24, 28, 33, + 41, 38, 34, 32, 38, 24, 8, 4, -8, -11, -15, -25, -31, -25, -20, -22, + -15, -11, -9, -12, -17, -20, -20, -15, -6, -11, -8, 0, 11, 29, 19, 17, + 17, 18, 28, 31, 25, 18, 23, 18, 10, 1, -7, -18, -26, -24, -30, -41, + -38, -44, -32, -31, -31, -35, -25, -12, -2, -8, -11, -13, -13, -2, 8, 15, + 19, 29, 35, 37, 39, 43, 42, 40, 35, 27, 25, 18, 15, 9, 4, -4, + -15, -28, -28, -26, -28, -18, -15, -25, -23, -12, -11, -14, -10, -2, -4, -1, + 8, 15, 19, 22, 25, 16, 16, 17, 5, 7, 13, 18, 13, 9, 6, 6, + 4, -4, -21, -31, -28, -37, -39, -34, -38, -38, -32, -17, -6, -4, -14, -19, + -9, 3, -2, 3, 4, 7, 8, 13, 23, 35, 38, 43, 42, 31, 25, 23, + 17, 8, 3, 4, -7, -7, -10, -13, -20, -19, -28, -33, -30, -23, -18, -13, + -17, -12, 3, 14, 23, 31, 27, 23, 21, 22, 19, 12, 4, 2, 2, -2, + 0, 4, 11, 11, 6, 4, -2, -5, -14, -17, -30, -38, -44, -42, -28, -21, + -23, -21, -15, -15, -4, 8, 11, 4, -7, -15, -7, 5, 10, 21, 26, 28, + 27, 34, 37, 36, 28, 19, 10, 11, 8, -2, -18, -17, -19, -19, -22, -24, + -21, -24, -18, -17, -13, -19, -13, -1, 12, 19, 22, 21, 19, 19, 30, 34, + 24, 13, 7, 2, 1, 1, 2, -1, -2, -6, 0, 0, -2, -15, -21, -17, + -21, -28, -32, -31, -31, -32, -27, -24, -17, -4, 1, -3, -1, 1, 4, 7, + 8, 15, 16, 15, 15, 20, 32, 36, 38, 32, 19, 12, 3, 2, -2, -4, + -11, -19, -17, -15, -11, -16, -20, -27, -30, -28, -22, -13, -6, -2, 2, 12, + 23, 29, 45, 44, 36, 32, 21, 16, 14, 10, 1, -9, -8, -2, -1, -7, + -13, -13, -12, -9, -11, -18, -24, -26, -28, -30, -24, -21, -21, -21, -11, -11, + -10, 0, -2, 0, 4, 12, 13, 14, 12, 17, 22, 28, 30, 28, 20, 16, + 13, 8, 2, -2, -6, -15, -14, -18, -15, -15, -16, -18, -18, -16, -19, -18, + -17, -10, 0, -1, 4, 13, 22, 37, 39, 36, 27, 27, 32, 26, 15, 6, + -1, -4, -5, -7, -11, -11, -9, -15, -15, -14, -18, -21, -19, -17, -21, -19, + -15, -15, -10, -15, -14, -12, -11, -6, -2, 1, -2, 1, 5, 14, 22, 33, + 35, 23, 18, 16, 13, 11, 6, 1, -9, -18, -11, -6, -7, -8, -9, -11, + -11, -12, -13, -17, -21, -24, -24, -15, -4, 7, 12, 17, 25, 30, 28, 31, + 32, 31, 27, 22, 15, 12, 3, -2, -8, -6, -3, -9, -13, -22, -24, -20, + -18, -22, -24, -18, -14, -13, -10, -11, -9, -3, -2, -3, -5, -10, -10, -5, + -1, 4, 11, 15, 19, 22, 27, 23, 20, 16, 14, 5, -3, -11, -15, -16, + -12, -12, -11, -5, 1, -3, -10, -13, -15, -11, -10, -10, -11, -8, -3, 2, + 7, 9, 15, 25, 30, 33, 31, 25, 21, 20, 16, 13, 7, -2, -8, -5, + -4, -11, -20, -21, -22, -21, -17, -20, -21, -22, -19, -19, -11, -4, -2, -2, + -2, 2, 5, 2, 0, 0, -3, 1, 8, 16, 13, 14, 17, 15, 13, 8, + 5, -1, -6, -10, -13, -14, -14, -13, -10, -7, -8, -8, -6, -6, -3, -1, + -1, -9, -12, -7, 3, 13, 17, 14, 13, 17, 22, 23, 24, 18, 15, 18, + 18, 18, 15, 8, 0, -5, -8, -11, -15, -17, -21, -26, -26, -24, -26, -24, + -13, -9, -6, -3, -2, 3, 4, 6, 7, 5, 2, 4, 2, -2, -4, -3, + 5, 13, 17, 10, 3, -1, -2, -4, -5, -11, -14, -13, -11, -8, -8, -8, + -6, -3, 0, -1, -5, -5, 0, 4, 3, 1, 2, 0, 0, 6, 13, 20, + 17, 17, 18, 21, 18, 14, 13, 11, 11, 7, 9, 3, -5, -12, -14, -18, + -21, -23, -26, -26, -13, -3, -6, -13, -14, -5, 5, 8, 3, 0, 1, 3, + 6, 4, -1, -1, 1, 3, 7, 5, 3, 0, 1, -1, 3, 0, -3, -11, + -11, -9, -10, -9, -8, -5, -7, -7, -10, -9, -6, -1, 4, 6, 4, 2, + 5, 10, 13, 9, 12, 13, 14, 15, 16, 13, 12, 10, 13, 14, 13, 8, + 2, -1, -4, -6, -9, -15, -20, -21, -19, -14, -16, -22, -21, -13, -5, -3, + -3, -1, 3, 5, 10, 9, 9, 6, 8, 7, 7, 7, 3, -4, -6, -4, + -1, -4, -8, -10, -11, -8, -4, -6, -10, -7, -8, -11, -11, -8, -5, -4, + 0, 3, 3, 8, 10, 10, 12, 12, 11, 10, 13, 12, 10, 6, 8, 9, + 9, 11, 13, 11, 9, 10, 7, 2, -3, -8, -9, -14, -16, -16, -19, -18, + -14, -13, -11, -11, -10, -5, -1, 3, 5, 2, 2, 9, 14, 11, 9, 10, + 7, 2, 0, 2, -2, -9, -13, -15, -18, -17, -15, -13, -10, -5, -5, -7, + -7, -4, -1, 0, -2, -4, -2, 1, 4, 9, 10, 10, 11, 11, 13, 14, + 10, 11, 9, 9, 4, 6, 5, 4, 5, 7, 8, 10, 9, 4, -4, -8, + -9, -10, -11, -12, -14, -15, -17, -15, -9, -4, -1, -6, -5, 2, 8, 8, + 6, 5, 3, 4, 5, 9, 10, 10, 5, -1, -5, -10, -12, -14, -16, -18, + -17, -11, -10, -11, -8, -5, -2, -2, 0, 3, 4, 5, 3, 2, 3, 5, + 9, 12, 12, 11, 10, 12, 14, 12, 8, 5, 0, -1, 1, 3, 0, 1, + 3, 5, 6, 5, 0, -5, -11, -10, -13, -12, -13, -15, -14, -8, -4, -3, + -3, -4, 0, 4, 5, 3, 6, 4, 4, 7, 10, 9, 9, 8, 5, 5, + 2, -4, -10, -15, -17, -20, -22, -22, -19, -14, -11, -10, -8, -6, 0, 3, + 5, 3, 4, 8, 11, 11, 12, 13, 12, 12, 15, 15, 16, 16, 13, 11, + 6, 3, -2, -5, -5, -3, -2, -1, 2, 0, -3, -4, -5, -7, -10, -12, + -11, -12, -11, -8, -4, -2, 0, 1, 2, 2, 2, 4, 3, 3, 4, 5, + 9, 10, 6, 2, 1, 2, 0, -3, -7, -13, -18, -19, -18, -16, -18, -20, + -19, -14, -8, -4, -1, 3, 3, 5, 7, 9, 9, 10, 12, 13, 13, 13, + 13, 16, 15, 13, 9, 6, 3, 2, 1, 0, -3, -5, -6, -4, -2, -2, + -4, -4, -5, -5, -3, -3, -4, -6, -6, -7, -4, 0, 2, 3, 2, 2, + 1, 2, 2, 1, 4, 5, 4, 1, 0, 2, 2, 0, -2, -6, -8, -6, + -7, -9, -11, -15, -18, -19, -18, -18, -17, -13, -9, -2, 2, 3, 5, 10, + 12, 13, 14, 14, 15, 17, 17, 16, 16, 15, 13, 11, 7, 2, -6, -10, + -8, -6, -8, -8, -7, -6, -6, -3, -4, -6, -5, -3, -2, -2, 0, 1, + 0, 2, 2, 3, 2, 3, 2, 3, 3, 5, 2, 0, 4, 6, 5, -1, + -4, -2, -1, -2, -6, -8, -9, -10, -12, -10, -14, -17, -22, -22, -21, -19, + -15, -8, -3, 1, 7, 12, 12, 15, 19, 22, 21, 18, 16, 16, 16, 13, + 12, 6, 3, 3, 2, -3, -6, -7, -12, -12, -11, -8, -9, -8, -7, -3, + 0, 0, 0, 0, -2, -2, 0, 1, 2, 2, 4, 6, 6, 7, 5, 4, + 3, 4, 5, 3, 0, -2, -2, -4, -6, -10, -8, -8, -10, -11, -12, -12, + -12, -13, -16, -16, -16, -14, -11, -8, -4, -2, 1, 6, 12, 17, 19, 20, + 20, 21, 21, 19, 13, 10, 9, 5, 0, -3, -4, -4, -5, -6, -6, -4, + -7, -10, -12, -12, -12, -10, -7, -4, -2, 4, 6, 8, 7, 7, 7, 7, + 8, 8, 7, 5, 6, 6, 4, 1, -1, -1, 0, -3, -7, -10, -10, -8, + -11, -14, -14, -12, -11, -9, -6, -8, -8, -8, -11, -13, -12, -9, -8, -5, + 0, 4, 8, 11, 14, 18, 18, 20, 23, 23, 20, 14, 9, 4, 0, -3, + -6, -8, -8, -8, -8, -9, -10, -11, -10, -9, -8, -8, -7, -6, -3, 0, + 3, 6, 12, 16, 16, 14, 10, 8, 9, 7, 4, 1, 0, 0, -2, -1, + 0, 0, -3, -7, -10, -13, -13, -12, -13, -15, -14, -13, -9, -6, -5, -5, + -7, -8, -9, -7, -6, -5, -7, -5, 1, 8, 13, 17, 19, 20, 21, 22, + 22, 18, 12, 9, 5, -1, -5, -9, -11, -13, -12, -12, -11, -10, -8, -7, + -7, -6, -7, -6, -3, 0, 1, 3, 7, 10, 11, 12, 15, 15, 14, 9, + 6, 3, 1, 0, -2, -2, -2, -3, -6, -8, -10, -11, -13, -15, -15, -15, + -13, -12, -12, -7, -5, -5, -5, -4, -3, -3, -4, -4, -1, -1, 1, 4, + 7, 10, 12, 14, 17, 20, 22, 19, 14, 8, 5, 2, -2, -5, -10, -14, + -13, -11, -10, -10, -10, -10, -8, -6, -3, -3, -3, -1, -1, 2, 6, 10, + 13, 14, 15, 15, 15, 13, 11, 8, 5, 1, -1, -3, -3, -6, -10, -12, + -12, -12, -12, -13, -15, -18, -19, -15, -11, -6, -4, -3, -4, -4, -2, 1, + 4, 2, -1, -2, 1, 4, 6, 8, 7, 7, 11, 14, 15, 15, 15, 13, + 10, 6, 1, -3, -6, -9, -13, -15, -15, -13, -11, -9, -9, -9, -7, -3, + 0, 2, 2, 4, 7, 11, 15, 16, 14, 11, 12, 13, 15, 13, 9, 4, + 1, -1, -4, -6, -8, -11, -15, -17, -17, -17, -17, -15, -13, -13, -12, -10, + -7, -6, -4, 1, 2, 2, 3, 4, 5, 4, 4, 3, 5, 6, 6, 8, + 7, 7, 9, 11, 10, 9, 8, 5, 2, 0, -2, -6, -10, -13, -13, -14, + -14, -13, -11, -9, -4, -1, -1, -1, 2, 6, 8, 10, 11, 12, 14, 14, + 14, 13, 11, 10, 7, 4, 2, 3, 1, -3, -6, -10, -14, -17, -18, -18, + -19, -19, -17, -15, -13, -9, -5, -1, 1, 0, 1, 3, 5, 6, 6, 6, + 7, 8, 9, 8, 4, 1, 0, 2, 4, 5, 6, 5, 4, 4, 4, 3, + 1, -3, -7, -9, -11, -12, -12, -12, -11, -10, -7, -4, -2, 1, 4, 5, + 8, 11, 13, 14, 14, 11, 11, 11, 10, 10, 9, 6, 5, 3, 1, -2, + -5, -10, -14, -16, -17, -18, -19, -20, -19, -17, -14, -10, -5, -1, 1, 3, + 5, 6, 6, 6, 6, 6, 6, 6, 6, 8, 7, 6, 4, 2, 0, -1, + 0, 0, 1, 2, 1, 1, 2, 1, -2, -5, -8, -9, -10, -11, -12, -12, + -10, -7, -4, -1, 2, 8, 11, 13, 15, 15, 13, 12, 11, 10, 9, 8, + 6, 5, 4, 4, 3, 0, -3, -6, -10, -14, -18, -21, -22, -21, -18, -16, + -13, -10, -6, -3, 0, 3, 5, 5, 5, 6, 7, 8, 8, 8, 7, 8, + 7, 6, 5, 4, 1, 0, -2, -4, -4, -5, -4, -4, -3, -2, -1, -2, + -3, -4, -7, -8, -9, -9, -9, -8, -5, -2, 2, 4, 8, 11, 14, 15, + 15, 14, 12, 10, 7, 5, 4, 4, 2, 1, 1, 2, -1, -3, -7, -10, + -15, -18, -18, -18, -18, -17, -15, -11, -7, -3, 1, 3, 4, 5, 6, 7, + 7, 8, 8, 9, 10, 10, 9, 6, 4, 2, 0, -3, -4, -6, -7, -7, + -6, -5, -3, -2, -2, -2, -2, -3, -4, -5, -6, -6, -6, -6, -5, -4, + -1, 4, 7, 9, 11, 12, 12, 11, 10, 9, 8, 7, 5, 3, 3, 2, + 1, 0, -1, -4, -7, -8, -10, -13, -14, -15, -15, -15, -14, -11, -9, -6, + -3, 0, 2, 4, 5, 6, 7, 8, 9, 10, 10, 9, 8, 6, 5, 3, + 1, -3, -6, -8, -8, -7, -7, -7, -6, -4, -2, 0, -1, -2, -3, -3, + -3, -3, -4, -3, -3, -1, 1, 3, 4, 6, 7, 8, 9, 10, 10, 9, + 7, 6, 6, 4, 3, 2, 1, -1, -2, -4, -6, -9, -11, -12, -12, -12, + -11, -11, -10, -9, -8, -7, -5, -4, -1, 1, 3, 5, 7, 9, 10, 11, + 10, 9, 8, 7, 6, 2, -1, -3, -4, -6, -7, -7, -7, -7, -6, -5, + -5, -4, -3, -3, -4, -4, -4, -3, -2, 0, 0, 1, 1, 2, 4, 6, + 6, 7, 7, 8, 7, 7, 7, 7, 7, 6, 5, 2, 0, -2, -4, -5, + -7, -8, -8, -8, -9, -10, -10, -9, -8, -7, -7, -7, -5, -3, -2, 0, + 1, 2, 4, 6, 9, 10, 11, 12, 10, 8, 6, 3, 1, -2, -4, -6, + -7, -7, -7, -7, -8, -7, -7, -6, -6, -5, -4, -3, -3, -2, -1, 1, + 2, 2, 3, 4, 5, 5, 5, 6, 6, 6, 5, 5, 6, 6, 6, 4, + 3, 2, 1, -1, -3, -4, -6, -8, -9, -9, -8, -8, -6, -5, -5, -5, + -6, -6, -6, -5, -4, -2, 0, 2, 4, 6, 7, 8, 9, 9, 9, 9, + 6, 4, 1, -1, -3, -5, -6, -7, -7, -7, -6, -6, -6, -6, -6, -5, + -4, -3, -3, -2, -1, 1, 3, 4, 5, 5, 5, 5, 5, 5, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 2, 1, -1, -3, -4, -5, -6, -7, -7, + -7, -7, -7, -6, -5, -4, -4, -3, -3, -3, -3, -2, -1, 0, 1, 3, + 5, 7, 8, 8, 8, 7, 6, 4, 2, 0, -2, -3, -4, -5, -6, -7, + -7, -7, -7, -6, -6, -5, -5, -5, -3, -2, 0, 1, 2, 3, 4, 5, + 6, 6, 6, 5, 5, 4, 3, 3, 3, 3, 3, 3, 2, 1, 1, -1, + -2, -3, -4, -5, -6, -6, -7, -6, -5, -4, -3, -3, -3, -3, -3, -2, + -1, -1, 0, 1, 1, 1, 2, 3, 5, 6, 6, 6, 5, 4, 2, 1, + 0, -2, -4, -5, -5, -6, -6, -6, -7, -7, -7, -6, -5, -4, -3, -2, + -1, 0, 2, 3, 3, 4, 4, 5, 5, 5, 4, 4, 4, 4, 3, 3, + 2, 1, 1, 0, 0, -1, -1, -2, -3, -4, -5, -5, -5, -5, -5, -4, + -4, -3, -3, -2, -1, -1, -1, -1, 0, 0, 0, 1, 2, 3, 3, 4, + 4, 4, 4, 4, 3, 1, 0, 0, -2, -3, -4, -5, -5, -6, -6, -6, + -5, -4, -4, -4, -3, -2, -2, -1, 0, 2, 3, 3, 4, 4, 4, 4, + 3, 3, 3, 3, 2, 2, 1, 1, 1, 0, -1, -1, -2, -3, -3, -3, + -3, -3, -3, -3, -3, -3, -3, -2, -2, -2, -1, -1, -1, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 0, 0, -1, -1, + -2, -3, -3, -3, -4, -4, -4, -4, -3, -3, -2, -1, -1, -1, 0, 1, + 1, 1, 2, 2, 2, 3, 3, 2, 2, 1, 1, 1, 0, 0, 0, 0, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, -8, -33, -24, -25, -25, -26, -27, -32, -28, -36, -31, -36, -22, -34, + 11, -74, -14, 94, 41, 28, 33, 30, 40, 34, 23, 41, 40, 60, 56, 59, + 60, 44, 39, 54, 45, 52, 17, 44, 62, 34, 33, 19, 18, 43, 35, 22, + 36, -15, -10, 32, -7, -12, -6, -8, -50, -47, -44, -4, -25, -48, -76, -58, + -75, -96, -85, -118, -114, -63, -106, -103, -83, -110, -99, -84, -76, -58, -63, -61, + -51, -53, -36, -32, -41, -27, -11, 11, 8, 27, 19, 30, 35, 28, 57, 53, + 38, 71, 51, 68, 110, 78, 89, 109, 97, 82, 94, 115, 114, 79, 70, 79, + 94, 85, 76, 84, 95, 83, 82, 55, 54, 54, 41, 41, 27, 20, 6, -11, + -21, -16, -14, -33, -33, -52, -54, -59, -62, -71, -79, -88, -88, -78, -78, -72, + -71, -94, -99, -93, -90, -78, -87, -105, -103, -79, -62, -71, -78, -63, -61, -66, + -49, -23, -10, -11, -24, -20, -4, -22, 9, 8, 27, 43, 34, 38, 51, 83, + 65, 58, 74, 75, 70, 73, 71, 65, 100, 89, 94, 65, 84, 49, 49, 61, + 54, 43, 51, 58, 53, 35, 40, 36, 38, 34, 23, 14, -12, -10, -1, -1, + -11, -12, -19, -33, -66, -52, -42, -37, -55, -42, -28, -32, -29, -35, -41, -28, + -25, -46, -85, -64, -62, -55, -49, -68, -55, -53, -52, -47, -43, -26, -32, -41, + -34, -35, -40, -26, -8, -1, -6, -11, 5, -2, 8, 3, 8, 6, 4, 20, + 29, 43, 24, 33, 20, 30, 24, 39, 38, 40, 29, 37, 36, 39, 61, 58, + 41, 51, 59, 51, 55, 58, 48, 32, 45, 40, 27, 30, 41, 44, 26, 19, + 23, -3, 7, 0, -3, 2, 3, -6, -5, -14, -6, -10, -27, -45, -47, -41, + -38, -50, -51, -46, -43, -45, -65, -65, -80, -95, -82, -74, -66, -69, -67, -33, + -31, -53, -48, -51, -43, -18, -24, -24, -33, -26, -10, 0, -17, -6, 17, 31, + 2, 23, 45, 46, 12, 75, 38, 63, 69, 31, 38, 80, 57, 48, 59, 81, + 74, 32, 52, 72, 24, 60, 44, 55, 40, 28, 48, 33, 24, 10, -2, 21, + 34, 13, 18, 7, -1, -12, -20, -18, -30, -9, -7, -30, -27, -26, -38, -20, + -54, -55, -64, -53, -36, -62, -37, -71, -47, -42, -71, -45, -55, -50, -54, -56, + -36, -37, -54, -36, -12, -38, -33, -26, -7, -22, -44, -10, 2, 3, 15, 8, + 18, 6, 12, 8, 15, 28, 22, 50, 35, 55, 42, 36, 49, 52, 64, 48, + 60, 49, 60, 62, 40, 47, 68, 52, 59, 61, 44, 53, 44, 35, 31, 31, + 47, 22, 6, 4, -7, 5, -4, -21, -13, -9, -10, -27, -46, -32, -44, -46, + -62, -44, -51, -67, -53, -59, -63, -74, -67, -61, -61, -65, -47, -58, -57, -45, + -41, -46, -41, -38, -22, -25, -34, -16, -10, -18, 0, 1, -6, 5, 17, 15, + 10, 23, 38, 28, 28, 54, 40, 19, 55, 55, 41, 46, 53, 40, 49, 51, + 52, 41, 56, 39, 53, 38, 33, 35, 18, 15, 38, 30, 23, 27, 13, 11, + 7, 16, -1, 0, 0, 13, -6, -10, -15, -10, -10, -24, -20, -16, -38, -36, + -21, -40, -32, -42, -38, -52, -53, -41, -48, -58, -50, -47, -37, -41, -45, -29, + -41, -6, -48, -24, -25, -15, -9, -10, -10, -10, -1, -17, 4, 3, 10, -4, + 9, 15, 25, 24, 19, 23, 34, 28, 33, 37, 38, 26, 36, 47, 35, 46, + 45, 28, 35, 32, 32, 24, 21, 26, 23, 19, 37, 20, 9, 29, -2, 26, + 24, 8, 4, 14, 21, 11, -9, -8, 4, -9, -31, -11, -15, -21, -24, -29, + -22, -33, -26, -29, -48, -32, -44, -28, -22, -35, -30, -38, -31, -46, -44, -36, + -27, -23, -29, -24, -11, -20, -28, -13, -34, -19, -1, 7, -3, -1, 6, -3, + 5, 4, 8, 17, 26, 19, 33, 27, 16, 35, 14, 36, 39, 22, 32, 31, + 19, 32, 23, 29, 21, 30, 29, 23, 31, 13, 24, 17, 11, 26, 18, 12, + 5, 23, 16, 9, 15, -10, 3, 18, -15, -4, -4, 6, -14, -15, -5, -34, + -11, -20, -18, -8, -17, -29, -30, -29, -19, -34, -35, -20, -36, -20, -16, -21, + -38, -16, -30, -24, -25, -19, -18, -15, -7, -5, -5, -10, -23, -3, -14, 0, + -1, -12, -9, 7, 7, 2, 12, 5, 7, 19, 10, 21, 21, 27, 30, 22, + 18, 34, 22, 11, 26, 24, 20, 21, 25, 29, 22, 27, 27, 20, 10, 20, + 16, 22, 15, 16, 16, 5, 19, 10, 3, 22, -5, -5, -7, -16, -4, -11, + -22, -7, -16, -11, -23, -16, -30, -24, -28, -20, -29, -24, -32, -22, -22, -30, + -17, -23, -28, -22, -20, -21, -21, -17, -30, -15, -14, -20, -9, 3, 6, 5, + -20, 10, 13, -2, 11, 8, -1, 7, 16, 5, 22, 23, 13, 22, 13, 22, + 25, 15, 16, 11, 15, 13, 7, 12, 19, 18, 20, 12, 23, 11, 6, 10, + 1, 11, 19, 5, 20, 0, 11, 11, 1, 14, 15, -3, -1, -7, 6, -6, + -9, -9, 4, -3, -10, -20, -14, -9, -14, -7, -10, -5, -4, -29, -14, -12, + -26, -21, -27, -18, -10, -19, -27, -18, -8, -25, -8, -13, -15, -14, -15, 5, + -13, -7, -11, -4, -12, 0, 15, 5, 4, 1, 11, 6, 4, 3, 6, 21, + 19, 8, 15, 13, 6, 14, 16, 18, 17, 20, 15, 11, 15, 24, 13, 11, + 19, 7, 17, 14, 6, 17, 7, 7, 6, 6, 5, 11, 0, 6, 0, -6, + 5, 1, -11, -6, -1, -8, -9, -15, -7, -4, -16, -17, -13, -13, -17, -14, + -12, -12, -28, -13, -19, -25, -31, -24, -17, -17, -16, -7, -15, -12, -8, -15, + -8, -16, -10, -4, -1, -2, 3, 5, 2, -2, 5, 3, 6, 10, 8, 11, + 14, 14, 13, 15, 22, 16, 14, 18, 13, 17, 19, 16, 10, 17, 8, 17, + 14, 3, 14, 7, 10, 10, 7, 6, 6, -1, 6, 1, 0, 12, -6, 6, + 12, -4, -5, -4, -2, -2, -1, -2, -8, -11, -9, -11, -11, -18, -6, -5, + -16, -9, -14, -10, -13, -10, -11, -15, -14, -14, -12, -17, -17, -17, -7, -11, + -14, -15, -12, -6, -15, -5, -13, -9, 0, 12, -2, -2, 6, 2, -7, 4, + 10, 2, 9, 8, 7, 4, 5, 11, 15, 11, 10, 18, 9, 13, 13, 13, + 21, 11, 18, 19, 13, 14, 16, 6, 8, 1, 19, 11, 10, 11, 1, 3, + -1, -1, 5, -11, 5, -1, -5, -3, -13, -10, -6, -7, -5, -15, -10, -11, + -18, -8, -16, -20, -18, -9, -12, -17, -21, -21, -13, -21, -8, -10, -10, -5, + -16, -7, 2, -6, -6, -9, -7, -2, -9, -5, 6, -7, 1, 3, -1, 2, + 1, 2, 9, 8, 5, 15, 12, 1, 11, 9, 8, 10, 15, 14, 5, 13, + 17, 14, 15, 10, 7, 16, 5, 5, 5, 8, 9, 10, 10, 7, 0, 4, + 6, 9, -10, -4, 5, 2, -1, 0, -3, -4, -5, -10, -5, -8, -9, -10, + -3, -13, -6, -9, -20, -15, -11, -18, -14, -10, -12, -20, -14, -14, -7, -12, + -21, -14, -9, -8, -11, -5, -2, -7, -4, 4, -2, -3, -1, 0, -1, 8, + 6, 9, 7, 10, 6, 3, 4, 7, 10, 11, 6, 9, 17, 11, 9, 7, + -2, 16, 13, 12, 18, 5, 16, 9, 4, 9, 6, 8, 9, 4, 4, 3, + -2, -3, 2, -6, -3, 1, -7, -6, -3, -6, -14, -8, -9, -4, -13, -9, + -8, -16, -10, -12, -13, -11, -7, -8, -12, -9, -8, -7, -11, -4, -8, -7, + -8, -3, -13, -10, -3, 6, -5, -5, 0, -5, -3, 6, -2, -2, 4, -2, + 6, 2, -2, 5, 5, -2, 5, 15, 13, 4, 6, 6, 14, 9, 4, 8, + 7, 3, 11, 12, 2, 10, 7, 10, 8, 4, 6, 2, 0, 3, 2, 4, + 2, -6, -2, 2, -4, 3, -5, -6, -5, -5, -5, -4, -8, -7, -4, -4, + -7, -8, -7, -13, -10, -10, -11, -9, -8, -8, -7, -11, -7, -3, -9, -6, + -7, -3, -4, -5, 3, -3, -1, -2, -4, 1, 4, 0, 3, 0, 5, 2, + 0, 5, 4, 1, 3, 1, 0, 1, 7, 3, 0, 4, 3, 6, 5, 0, + 9, 5, 7, 6, 3, 6, 2, 3, 5, -4, 9, 0, 4, 10, 0, 5, + 1, -2, 4, -3, -3, -2, 0, 2, -7, 3, -10, -1, -6, -9, -2, -4, + -10, -3, -7, -6, -4, -10, -6, -6, -11, -6, 0, -6, -8, -4, -1, -9, + -10, 0, -6, -7, -2, -7, 1, -5, -5, -1, 1, -6, 2, 0, -3, -1, + 7, -4, 0, 7, 0, 8, 2, 3, 4, 4, 2, 5, -1, 6, 7, 5, + 6, 4, 2, 4, 6, 8, 6, 3, 1, 8, 9, 2, -1, 4, 3, 4, + 3, -3, 7, 4, 3, -2, 2, -4, -6, -2, -5, -2, -3, 0, -5, -6, + -13, -5, -6, -11, -9, -10, -5, -4, -9, -9, -7, -7, -8, -8, -6, -5, + -7, -5, -1, -3, -4, -2, -2, 2, -3, 1, 2, -3, 1, 2, 1, 0, + 1, 5, 0, 2, 5, 2, 0, 4, 1, 7, 3, 2, 6, 0, 5, 7, + 5, 5, 1, 3, 3, 5, 10, 3, 4, 8, 2, 7, 3, -2, 3, 0, + -1, -1, 1, 0, 1, -3, -2, -5, -4, -3, -1, -7, -8, -4, -4, -10, + -2, -8, -8, -8, -8, -9, -6, -8, -9, -4, -2, -7, -5, -2, -7, -6, + -9, -2, 0, -4, 4, -6, -3, -4, -1, 2, 1, 2, 9, 0, 3, 0, + 6, 4, 0, 5, 6, 2, 7, 7, 5, 7, 6, 8, 6, 6, 5, 5, + 1, 6, 5, -1, 3, 4, -1, 4, 1, 4, 3, -5, 0, 4, 1, 4, + -2, -3, -4, 0, -4, -8, -2, -5, -4, -8, -6, -5, -3, -3, -7, -9, + -6, -10, -10, -6, -6, -5, -4, -7, -6, -4, -10, -3, -10, 0, -2, -2, + -6, -1, 3, -3, -3, 1, 2, 1, 4, 3, 4, 3, 4, 1, 2, 6, + 5, 5, 5, 7, 9, 1, 5, 4, 4, 7, 2, 9, 2, 4, 8, 2, + 5, 6, 3, -2, -2, -1, -2, -1, 1, -2, -4, 1, -6, -2, -5, -3, + -5, -5, -6, -4, -3, -4, -10, -4, -3, -8, -4, 0, -3, -5, -6, -6, + -3, -1, -7, -3, 1, -1, -4, -2, 1, -2, 0, -1, -2, 0, 0, 5, + -2, 0, 3, 3, 1, 5, 2, 4, 1, 4, 1, 2, 3, 3, 3, 4, + 3, 3, 5, 1, 4, 2, 3, 1, 2, 0, 2, 1, -2, -2, -1, 0, + -2, -1, -1, -3, -5, -2, 0, -5, -1, 0, -5, -2, -2, -2, -3, -3, + -1, -4, -1, -2, -4, -2, -1, -2, -1, 0, -3, -1, -1, 0, 1, -1, + -1, 3, -4, -2, -2, 4, -2, -1, -1, -1, 0, 0, -1, -1, -1, -1, + 2, 0, -1, 2, -1, 0, -1, 2, 0, 3, 5, -2, 1, 2, 0, 5, + 0, -3, 4, -3, 1, 2, 0, 4, -1, -2, 1, 0, 0, 0, -1, 1, + -2, 0, 1, 1, 0, -5, 1, -2, -1, 0, -2, -3, -1, -3, 0, -2, + -3, -4, 1, -2, -3, -2, -2, -1, -1, -2, -1, -4, -5, 2, -4, 0, + 1, -1, 2, -2, -1, 0, 0, 1, -3, 3, 2, 0, -2, 2, 1, 2, + -2, 5, 3, -2, -2, -1, 1, 0, 0, 1, 3, 2, 0, 0, -1, -2, + 1, 1, 2, 1, 1, -1, 0, -1, -1, -1, -3, 1, 1, 2, -2, -1, + 0, 0, -2, 0, -1, -1, 2, -2, 1, -1, 0, 0, -1, -1, -2, 0, + -1, 1, -1, -1, 2, -2, 0, -1, -1, 2, -1, 0, -3, -1, 0, 0, + 0, -3, -3, -2, 0, 0, -1, -1, 0, -4, 2, 0, -2, 0, 1, -3, + -1, 2, 1, 0, -1, 0, 0, -1, 0, 2, -1, -1, 0, 0, -2, 1, + 1, 0, 1, 0, 2, -3, -2, 2, -1, -1, 2, -2, 1, 1, 0, 0, + 1, 1, 0, -4, 3, -1, 2, 0, 2, -1, -2, 0, 1, 1, -1, -1, + -1, -1, -1, -2, -2, -2, -2, -2, -1, -1, 1, 0, -5, 0, -1, -1, + -1, 1, -1, 1, -1, 1, 0, -2, 0, -2, 1, -1, 1, 0, -1, -2, + 0, -1, 0, 0, 2, 0, 0, 0, 1, 0, 0, 2, 0, -1, 0, 0, + 0, 2, -1, 1, 1, -1, -1, 0, 0, 1, 1, 0, 0, 0, 0, -1, + 0, 0, -2, 0, 0, -1, 1, -2, -1, -1, -1, -2, -1, -2, 1, -1, + 0, -2, -2, 1, -2, -1, 1, 0, 1, 1, -1, -1, 0, -1, 0, 0, + 0, -2, 0, -1, 0, 0, -1, -2, -2, -2, 1, -1, 0, 0, -1, 1, + 1, -2, -1, -2, -1, 1, -1, -1, -2, -2, 0, 0, 1, -1, -1, -1, + -1, -2, 2, 0, 0, 1, 1, 1, -2, 0, -1, 0, -1, -1, 2, 0, + -1, -1, -1, 1, -1, 2, 0, -1, 1, 1, 0, 1, 0, -1, -1, -1, + -1, -3, 0, 0, -1, 1, 0, 0, -2, -2, -2, 0, -1, 0, 0, -1, + 0, -1, -2, -1, -2, 0, -2, 0, 0, -1, -2, 1, -2, 0, -1, -2, + 2, 0, -1, 2, -1, 1, -1, 0, 0, -1, 0, 0, 0, -1, 0, 1, + 0, 0, 1, 0, -1, -1, 0, -2, -1, 0, 0, 1, 0, 0, 0, 0, + -1, -1, 1, -1, -2, -1, 0, 0, -2, 0, -1, 0, 0, 0, 1, 0, + 0, -1, 1, 0, -1, 0, 1, -1, 0, -1, -2, 0, -1, 0, -1, -1, + -1, 0, -1, 0, 0, 0, -1, -1, 0, -2, 0, 0, 0, -2, -2, 0, + -2, -1, -1, -1, -2, 0, -1, -1, -1, 0, 0, -1, -1, 0, 1, -1, + -1, 0, -1, 0, 0, 1, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, + -1, 0, 0, 0, 1, 0, 0, -1, 0, 0, -1, -1, 0, -1, -1, 0, + -1, 0, -1, -1, 0, -2, -1, 0, -1, -1, -1, -1, 0, -1, 0, 0, + 0, 0, -1, 1, 0, 0, 0, -1, -1, 0, -1, -1, 0, 0, 0, 0, + 0, -1, -1, 0, -1, -1, 0, 0, -1, 0, -2, 0, -1, -1, -1, 0, + -1, -1, 0, -1, 0, 0, 0, -2, -1, 0, -1, -1, 0, 1, -1, -1, + 0, 0, 0, 0, -1, -1, -1, -1, 0, 1, 0, 0, 0, 0, 0, -1, + 0, 0, 0, 0, 0, 0, -1, 0, 0, -1, 0, 0, -1, -1, -1, 0, + 0, -1, -1, 0, -1, 0, 0, 0, -1, 0, -1, -1, 0, -2, -1, -1, + -1, 0, -1, 0, -1, -1, 0, 0, -1, 0, -1, 0, -1, -1, -1, 0, + -1, 0, -1, 0, 0, -1, 0, -1, 0, 0, -1, -1, 0, 0, 0, -1, + 0, -1, 0, 1, -1, 0, 0, 0, 0, 0, -1, 0, 0, 0, -1, 0, + 0, -1, -1, 0, 0, 0, -1, 0, 1, -1, -1, -1, 0, 0, -1, -1, + -1, -1, 0, -1, 0, 0, 0, 0, 0, 0, -1, -1, 0, -1, -1, 0, + -1, 0, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, -1, -1, 0, -1, + 0, -1, 0, 0, -1, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, -1, + -1, 0, -1, 0, 0, 0, 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, + 0, 0, -1, 0, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, + -1, -1, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, -1, + -1, -1, 0, 0, 0, -1, 0, -1, -1, 0, -1, 0, 0, -1, -1, -1, + -1, -1, 0, 0, -1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, -1, + 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, + 0, -1, 0, -1, 0, 0, -1, -1, -1, 0, -1, -1, 0, -1, -1, 0, + 0, -1, -1, -1, -1, 0, -1, -1, 0, 0, -1, 0, 0, 0, -1, -1, + 0, -1, -1, -1, 0, 0, -1, -1, -1, -1, -1, 0, -1, 0, 0, -1, + -1, 0, 0, -1, 0, 0, -1, -1, -1, 0, -1, 0, 0, -1, -1, 0, + 0, -1, -1, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, -1, -1, 0, 0, 0, -1, 0, -1, 0, + -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 0, 11, -3, 47, -12, -15, -34, 3, 12, 38, 5, -24, -26, -9, -12, + 63, -18, 12, -17, -50, 34, -6, 40, -2, -8, -37, -6, 9, 12, 32, -4, + -33, 2, -33, 35, 20, 6, -11, -33, -11, 12, 23, 30, -21, -13, -28, -6, + 33, 14, 7, -18, -22, -11, 18, 23, 5, -4, -22, -30, 29, -11, 40, -12, + -15, -5, -11, 16, 13, -9, 5, -19, 3, 4, 2, 19, -28, 24, -41, 40, + -9, -8, 4, -29, 28, -1, 22, -16, -32, 16, -22, 45, 19, -45, 17, -54, + 25, 28, 33, -19, -30, -21, -25, 83, -20, 15, -3, -74, 12, 33, 4, 53, + -26, -57, -9, 0, 36, 33, 8, -67, -2, -17, 27, 55, -17, -11, -31, -23, + 24, 22, 6, 19, -55, 27, -48, 55, -8, 14, 7, -61, 26, -25, 34, 32, + -26, 11, -50, 5, 14, -1, 67, -75, 47, -79, 29, 15, 8, 42, -49, 2, + -34, -3, 51, -23, 52, -33, -32, -7, -14, 52, 6, 29, -73, 5, -9, -2, + 64, -39, -6, 25, -60, 30, 5, 16, -13, 40, -61, 7, 20, -50, 75, -36, + 10, -12, -4, -17, 23, 16, -18, 31, -38, -21, 33, -37, 56, -11, -5, -1, + -43, 43, -56, 93, -67, 40, -17, -46, 60, -56, 62, -24, 14, -18, -23, 9, + -16, 44, 19, -53, 58, -124, 81, -18, 32, 26, -43, -23, -28, 42, 1, 60, + -27, -61, 14, -37, 42, 64, -32, -2, -43, -31, 25, 59, -7, -1, -19, -73, + 51, 23, 18, 7, -24, -65, 29, 18, -2, 57, -47, -27, 4, -2, 16, 41, + -25, -47, 36, -51, 49, 24, -37, 13, -15, -11, 12, 26, -58, 52, -20, -16, + 31, -24, -20, 52, -16, -9, 32, -69, 5, 48, -34, 52, -12, -59, 20, -10, + 30, 16, 21, -75, 1, 8, -33, 126, -57, 9, -37, -49, 32, 24, 62, -59, + 19, -85, -2, 91, -23, 65, -49, -75, 19, -16, 68, 9, 16, -77, -3, 3, + -13, 111, -69, 17, -30, -59, 56, 1, 19, 23, -26, -21, -24, 25, -31, 97, + -59, 4, -16, -34, 40, 17, 16, -24, -6, -40, 26, 17, 3, 4, -23, -3, + -1, 23, -8, 6, -29, -2, 21, -13, 22, -11, -31, 40, -35, 48, -27, 7, + -39, 4, 28, -12, 55, -68, 9, -9, 2, 51, -21, -20, -18, -15, 33, 20, + 15, -57, 41, -78, 72, -2, -7, 13, -60, 11, 13, 49, -19, 10, -55, -23, + 59, -6, 22, 2, -79, 40, -11, 46, -11, 11, -66, 13, 24, -24, 80, -65, + 5, -22, 1, 19, 23, -8, -27, -11, 2, 0, 64, -61, 21, -52, 34, 23, + 7, -1, -51, 21, -41, 86, -45, 49, -62, -6, 0, 11, 51, -33, 16, -62, + -1, 23, 8, 62, -45, -35, 7, -39, 88, -54, 70, -86, 33, -27, -1, 61, + -60, 58, -62, 10, 15, -28, 65, -48, 11, -2, -44, 78, -64, 75, -78, 26, + -29, 22, 40, -30, 16, -53, -12, 56, -15, 48, -51, -22, -10, 9, 52, -20, + 40, -92, 16, -3, 26, 43, -19, -35, -31, 15, 13, 49, -11, -34, -24, -1, + 9, 50, -12, -25, -17, -10, 15, 44, -20, 0, -28, -22, 32, 5, 27, -33, + 15, -67, 61, -19, 19, 18, -46, -1, -1, 7, 18, 14, -27, -21, 18, -27, + 42, 22, -56, 38, -56, 21, 17, 2, 5, -3, -11, -38, 48, -27, 32, 8, + -50, 1, 10, -3, 38, -10, -16, -36, 34, -45, 74, -12, -30, 16, -52, 22, + 24, 17, -1, -13, -41, -10, 50, -5, 41, -32, -62, 25, -5, 48, 24, -26, + -61, 4, -2, 44, 62, -59, -23, -38, -4, 61, 34, 0, -57, -18, -41, 63, + 36, 6, -1, -69, -11, 10, 19, 60, -31, 3, -64, 18, -19, 61, 10, -17, + 10, -73, 13, 30, -7, 64, -39, -27, -34, 8, 20, 46, 24, -87, 29, -70, + 51, 51, -12, 6, -44, -30, 10, 52, -7, 2, -6, -72, 63, -9, 17, 15, + -37, -24, 14, 24, -11, 43, -55, -29, 42, -19, 47, 1, -49, -13, 13, 6, + 38, 4, -59, -2, 7, 5, 61, -31, -42, 11, -32, 54, 14, -11, -23, -10, + -20, 40, 19, -18, 0, -19, -28, 52, -14, -5, 29, -70, 53, -17, 19, -18, + 15, -30, -2, 37, -41, 38, 7, -61, 67, -67, 35, 11, -12, 11, -34, 38, + -61, 89, -59, 10, 28, -60, 52, -19, -22, 34, -30, 42, -42, 45, -68, 35, + 19, -45, 80, -81, 26, -16, 4, 30, 0, -13, -19, -14, 23, -22, 75, -77, + 47, -45, -5, 48, -36, 48, -50, 18, -35, 25, 5, 4, 14, -16, -33, 40, + -49, 71, -38, 17, -30, -6, 12, 4, 31, -27, -6, -12, -11, 27, 15, -13, + 12, -54, 32, -19, 53, -17, -1, -16, -39, 39, -5, 30, -3, -29, -13, -2, + 23, 16, 4, -18, -41, 26, -11, 35, 18, -48, 13, -33, 28, 1, 38, -45, + 5, -13, -18, 49, 1, -21, 16, -44, 14, 16, 7, -6, -5, -10, -18, 52, + -33, 25, -11, -36, 31, -15, 14, 11, -22, 9, -27, 41, -42, 56, -50, 15, + 10, -28, 30, -18, 3, 7, -7, 7, -16, 13, -27, 29, 5, -25, 42, -71, + 44, -18, 21, 8, -7, -21, -15, 21, -9, 36, -2, -43, 17, -26, 14, 45, + -33, 19, -40, 1, -3, 37, -5, -5, -2, -46, 38, 0, 7, 18, -33, -12, + 11, -11, 33, 2, -16, -15, -3, 1, 18, 26, -32, -4, -14, -17, 54, -1, + -1, -17, -35, 10, 12, 40, -12, -10, -30, -31, 51, -12, 65, -35, -34, -12, + -32, 60, 22, 19, -33, -39, -20, 2, 75, 2, 9, -42, -72, 35, 13, 65, + 5, -28, -60, -15, 23, 40, 44, -33, -34, -34, -5, 48, 33, 2, -21, -47, + -15, 25, 33, 12, 7, -55, -12, 7, 19, 28, 9, -34, -28, 5, 7, 32, + 15, -41, 8, -32, 10, 36, -4, 14, -40, 16, -45, 56, -15, 17, 0, -33, + 2, 0, 7, 23, -12, -1, -26, 3, 6, 10, 24, -32, 21, -50, 33, -9, + 15, 11, -24, 1, -12, 12, 4, 13, -10, -11, -2, -5, 7, 17, -23, 25, + -27, 12, -6, 0, 8, -16, 18, -24, 31, -27, 9, -3, -2, 18, -4, -7, + -11, -12, 10, 12, 15, -17, 7, -34, 18, 8, 4, 9, -18, -14, -3, 15, + 9, 7, 0, -37, 21, -13, 16, 18, -32, 12, -23, 21, 3, 12, -14, -14, + 3, -5, 24, 4, -21, 9, -32, 26, 14, -1, 12, -40, 0, -6, 24, 11, + 3, -11, -34, 17, -8, 28, 18, -36, 9, -38, 13, 26, 11, 7, -20, -13, + -34, 49, -24, 41, -8, -36, 4, -8, 3, 47, -11, -5, -24, -15, -9, 44, + 8, -5, 8, -61, 17, 14, 14, 23, -15, -43, 1, -1, 28, 27, 1, -40, + -6, -20, 18, 45, -22, 4, -20, -34, 39, 12, 3, 9, -31, -23, 15, 17, + -7, 36, -36, -19, 30, -30, 36, 1, -16, -8, 5, -14, 20, 10, -13, 0, + 6, -30, 37, -22, 3, 14, -27, 24, -15, 14, -15, 19, -22, 4, 17, -31, + 29, -14, -10, 27, -26, 22, -14, 8, -17, 9, -2, -11, 33, -27, 14, 0, + -29, 31, -21, 21, -7, -2, -14, -4, 20, -15, 37, -27, -9, 7, -24, 24, + 8, -9, 12, -23, 7, -14, 30, -22, 25, -16, -20, 24, -27, 23, 8, -9, + 6, -11, -18, 12, -3, 22, -14, 28, -61, 41, -32, 21, 29, -26, 8, -31, + 2, 5, 28, 3, -9, -14, -21, -3, 48, -33, 49, -62, 9, -1, 6, 33, + -24, 11, -44, 24, -2, 6, 25, -40, 8, 1, -16, 49, -41, 27, -41, 18, + 0, 3, 31, -50, 36, -42, 22, 15, -18, 24, -34, 5, 12, -21, 52, -56, + 52, -58, 29, -8, -8, 39, -51, 48, -47, 24, 4, -16, 22, -28, 6, 7, + -22, 48, -55, 51, -44, 31, -10, -5, 8, -36, 41, -31, 35, -9, -16, 10, + -17, 6, 21, -13, 10, -26, 5, -17, 39, -3, 3, 1, -43, 12, 1, 17, + 15, -7, -24, -9, 5, 15, 17, 8, -38, 2, -25, 25, 15, 12, -13, -16, + -11, 3, 19, 9, -9, -9, -15, 1, 19, -1, 14, -20, -1, -12, 15, -7, + 11, -10, -2, -3, 10, -9, 18, -17, 2, -4, -3, 4, 3, -2, -5, 9, + -9, 4, 5, -13, 5, 5, -21, 22, -16, 11, -4, 13, -22, 5, 3, -23, + 35, -14, -6, 13, -24, 4, 17, -6, 6, -7, -6, -27, 43, -28, 25, 9, + -45, 28, -23, 8, 25, -14, 0, -15, -4, -3, 27, 3, -15, 18, -59, 34, + 3, -3, 38, -39, -11, 4, -9, 27, 9, -2, -38, 21, -31, 19, 47, -53, + 43, -47, -11, 29, -2, 19, -7, -9, -36, 19, 12, -8, 53, -58, 1, 2, + -33, 67, -23, 25, -44, 5, -25, 28, 32, -29, 32, -60, 0, 25, -7, 39, + -14, -29, -12, 2, 11, 20, 23, -54, 18, -25, 1, 45, -10, -10, -4, -29, + 7, 28, 7, -11, 9, -46, 16, 11, 8, 8, -7, -25, -3, 16, -3, 32, + -25, -7, -20, 12, 0, 30, -14, -4, -15, -6, 6, 24, -9, 3, -16, -24, + 23, -3, 27, -20, 15, -56, 42, -17, 21, 13, -27, -8, -2, 5, 8, 21, + -21, -12, 4, -14, 15, 24, -39, 31, -38, 19, -2, 16, -16, 3, -6, -21, + 30, -14, 16, 4, -30, 11, -7, 7, 12, -5, -10, -9, 9, -17, 37, -15, + -5, 6, -26, 12, 13, -8, 7, -2, -18, 1, 17, -13, 15, 4, -37, 25, + -18, 8, 13, 1, -23, 21, -25, 10, 7, -1, -6, 10, -15, -7, 21, -26, + 29, -12, -3, -3, 0, -16, 29, -18, 21, -15, 1, -23, 22, -4, 3, 21, + -43, 22, -19, 4, 21, -8, 4, -11, -7, -5, 7, 19, -20, 31, -47, 11, + 2, -9, 44, -28, 8, -31, 5, -1, 20, 24, -38, 14, -32, -4, 47, -30, + 38, -41, -1, -12, 12, 27, -16, 29, -57, 12, -1, 3, 38, -29, 3, -25, + -1, 28, -10, 36, -52, 20, -33, 27, 14, -11, 18, -42, 13, 3, 3, 20, + -21, 0, -20, 15, 4, 0, 23, -49, 28, -24, 18, 16, -15, -2, -26, 22, + -10, 33, -7, -26, 11, -25, 19, 21, -14, 8, -33, 6, -2, 30, 2, -12, + -6, -37, 34, -4, 22, 1, -33, -3, -4, 15, 20, 3, -20, -16, 2, -14, + 38, -3, -7, 2, -24, -4, 22, -4, 11, -2, -15, -19, 21, -15, 24, 8, + -21, 1, -12, -3, 9, 21, -22, 17, -26, -2, 6, 14, -8, 19, -24, -10, + 8, -10, 17, 9, -7, -12, 8, -27, 29, -3, 4, -4, -3, -26, 25, -9, + 13, 9, -19, -7, 2, -4, 10, 19, -29, 13, -16, -3, 18, 4, -12, 10, + -24, 1, 6, 10, -9, 19, -26, -3, 16, -15, 20, -4, -16, 1, 3, -4, + 9, 6, -19, 7, 3, -18, 26, -13, -7, 12, -13, 2, 9, -5, -7, 15, + -18, 6, 8, -18, 13, -2, -12, 15, -12, 9, -6, -2, -16, 25, -14, 18, + 1, -29, 11, -4, 14, 2, 3, -26, 6, -3, 1, 19, -3, -15, 12, -29, + 17, -2, 12, -2, -4, -3, -28, 34, -21, 31, -7, -17, -3, -13, 20, 1, + 14, -14, -22, 11, -13, 33, -2, -11, -4, -30, 33, -12, 30, -17, -17, -4, + -4, 25, 2, 3, -20, -22, 20, -13, 42, -15, -11, -9, -16, 23, 8, 16, + -28, -3, -11, 4, 27, -8, 5, -17, -9, 8, -2, 25, -27, 17, -32, 19, + -4, 16, -8, -16, 6, -20, 32, 0, -14, 8, -34, 18, 12, 3, 13, -36, + 11, -34, 49, -14, 22, -12, -38, 17, -21, 42, 5, -10, -12, -34, 8, 18, + 18, 26, -50, 9, -50, 42, 16, 10, 10, -51, 2, -21, 38, 16, 7, -17, + -29, -12, 13, 19, 25, -16, -7, -40, 14, 5, 23, 6, -11, -23, -3, 11, + 2, 25, -26, 0, -12, 5, 4, 9, 2, -18, 10, -15, 5, 20, -26, 23, + -28, 6, 8, 1, 12, -26, 10, -19, 20, 7, -14, 17, -37, 18, 1, -1, + 23, -28, 9, -25, 20, 1, 6, 6, -23, 9, -15, 12, 10, -11, 5, -5, + -12, 15, -8, 4, 4, -4, -6, 8, -11, 3, 6, -6, 0, 6, -12, 1, + 14, -26, 27, -17, -3, 15, -18, 15, -10, 1, -6, 4, 9, -17, 28, -42, + 18, 3, -17, 45, -38, 9, -12, -7, 19, 8, 7, -31, 8, -18, 6, 53, + -51, 34, -41, -13, 32, -4, 17, -10, -6, -28, 25, 0, -2, 23, -32, -7, + 21, -28, 36, -7, -14, 7, -10, -4, 13, -3, -7, 7, -5, -6, 14, -10, + -10, 22, -29, 22, 0, -23, 24, -25, 15, 3, 3, -4, -9, 5, -23, 33, + -10, -6, 22, -48, 31, -8, 7, 10, -15, -5, -14, 20, -7, 16, 3, -32, + 20, -21, 13, 18, -20, 9, -25, 13, -3, 21, -4, -10, -4, -18, 18, 6, + 2, 6, -32, 8, -4, 18, 10, -3, -21, -12, 3, 3, 28, -3, -18, -4, + -14, 10, 19, 5, -9, -10, -21, 8, 21, 2, 11, -23, -12, -8, 14, 12, + -1, 5, -31, 14, -9, 15, 7, -14, 5, -19, 11, -3, 5, 1, -11, 12, + -13, 14, -6, -10, 5, -9, 16, -4, 3, -15, -5, 9, 2, 14, -11, -9, + -7, -7, 22, -2, 12, -14, -15, -2, 2, 19, 0, 6, -28, -3, 0, 5, + 27, -10, -8, -15, -9, 12, 10, 20, -25, 5, -23, 0, 27, -10, 21, -27, + -3, -14, 17, 8, 1, 6, -28, 2, 7, -2, 21, -14, -6, -9, 3, 6, + 2, 16, -33, 19, -17, 7, 10, -6, -3, -4, 0, 0, 11, -1, -13, 5, + -9, -1, 25, -27, 19, -20, 3, 9, 1, 2, -11, 5, -19, 26, -4, -6, + 13, -28, 10, 13, -11, 17, -19, -1, -10, 22, -4, -1, 13, -43, 29, -8, + 3, 18, -25, 5, -13, 16, -5, 12, 0, -29, 25, -23, 14, 17, -29, 23, + -23, 8, 2, 0, 4, -8, 11, -25, 22, -8, -6, 28, -35, 19, -6, -17, + 25, -15, 9, -5, 1, -12, 10, 5, -14, 22, -24, 0, 18, -23, 23, -9, + -10, 8, -1, -1, 4, -4, -13, 8, 6, -7, 22, -27, -8, 10, -6, 23, + 1, -17, -10, -9, 15, 14, 15, -17, -24, -1, -11, 41, 4, -4, -12, -35, + 12, 13, 19, 12, -22, -25, -6, 8, 22, 17, -3, -36, 7, -21, 21, 32, + -22, 8, -23, -17, 17, 15, 1, 10, -19, -20, 2, 10, 3, 23, -13, -21, + 7, -19, 26, 12, -10, 4, -35, 4, 7, 12, 19, -17, -3, -24, 14, 7, + 7, 15, -43, 12, -13, 8, 37, -29, 13, -34, 11, 2, 11, 14, -34, 22, + -31, 20, 14, -14, 18, -29, 5, -4, 3, 13, -11, 13, -23, 9, -3, -5, + 22, -22, 12, -10, -11, 15, -2, 6, 4, -10, -15, 11, -5, 10, 8, -14, + -12, 12, -10, 16, 17, -37, 16, -18, -3, 31, -11, -1, -9, -8, 0, 22, + 6, -21, 9, -32, 14, 26, -19, 27, -40, 6, -4, 13, 14, -14, 3, -34, + 21, 1, 10, 15, -32, 5, -10, 5, 19, -10, 3, -21, 10, -7, 14, 9, + -23, 18, -25, 9, 7, -5, 4, -1, -8, -2, 15, -17, 16, -5, -17, 16, + -13, 9, 3, 2, -17, 13, -10, -2, 29, -33, 17, -15, -10, 23, -6, 12, + -14, -3, -9, 2, 26, -23, 28, -45, 14, -1, 1, 33, -35, 17, -34, 15, + 10, 3, 12, -31, 7, -15, 18, 19, -19, 12, -39, 16, 5, 8, 17, -37, + 16, -35, 39, -3, 8, -5, -31, 9, -4, 26, 0, -3, -18, -15, 19, -2, + 25, -12, -21, 1, -16, 26, 4, 6, -20, -1, -14, 11, 21, -20, 22, -32, + 0, 14, -9, 19, -10, -2, -13, 14, -9, 4, 17, -36, 30, -20, -2, 22, + -21, 13, -11, 7, -12, 15, -6, -15, 25, -29, 20, 3, -18, 17, -17, 7, + -3, 11, -9, -4, 13, -33, 34, -10, -5, 22, -34, 11, -4, 8, -1, 11, + -14, -16, 24, -27, 31, 3, -29, 19, -23, 2, 26, -11, 1, -3, -14, -4, + 27, -14, 3, 9, -38, 26, -1, -7, 20, -15, -12, 14, -8, 4, 7, -11, + -10, 12, -3, 0, 16, -28, 7, 1, -2, 14, -7, -10, -5, 4, 5, 9, + 3, -22, 4, -5, 0, 27, -18, 1, -9, -10, 13, 10, 1, -9, -1, -21, + 15, 11, -8, 15, -21, -8, 12, -4, 13, 0, -12, -5, 2, -1, 9, 2, + -8, 0, -4, 1, 4, -1, -1, -1, -1, -2, -15, 21, -17, 23, -30, 1, + 34, -34, 6, 5, -15, 19, 1, -25, 6, 20, -2, -28, 15, 10, -15, 0, + -7, 10, 7, -5, -9, -6, 19, -3, -21, 3, 20, -4, -20, 1, 16, -3, + -8, -2, 5, 1, -8, -6, 3, 9, 2, -13, -4, 15, -7, -9, 0, 3, + 6, -7, -7, 5, 8, -8, -4, 0, 1, 1, -6, -4, 7, 2, -2, -7, + 0, 4, -3, -4, 0, 2, 0, -2, -4, 1, 4, -2, -4, -3, 1, 3, + -5, -4, 4, 3, -6, -5, 4, -1, -2, -3, 0, 3, -3, -1, -4, 3, + 3, -5, -3, 1, 1, -2, -3, 1, 2, -2, -4, 0, 0, 0, -1, -3, + 1, 1, -3, -2, 1, 0, -2, -2, 0, 0, -2, -1, 0, -1, 1, -2, + -2, 1, 0, -2, 0, -1, 0, -1, -1, -1, 0, 0, -1, -3, 1, 1, + -2, -2, 0, 1, -1, -2, -1, 0, 0, 0, -2, -1, 1, 0, -3, 0, + 2, -1, -2, 0, 0, 0, -2, 0, -1, 0, -1, -1, 1, 0, -1, 0, + -1, 1, 0, -13, 5, 7, -11, 24, -50, 41, 4, -29, 14, -11, 8, 11, + -15, -12, 15, 18, -21, -14, 22, -2, -11, -3, -3, 18, -3, -5, -14, 9, + 22, -24, -16, 23, 12, -23, -8, 9, 10, -4, -8, -3, 11, -4, -14, 0, + 8, 8, -5, -14, 8, 10, -12, -4, -2, 10, 0, -11, -3, 11, 0, -7, + -2, -1, 7, -6, -8, 3, 6, 0, -3, -8, 7, 2, -7, -2, 2, 1, + -2, -4, -1, 3, 3, -4, -5, 1, 3, -3, -6, 2, 5, -1, -7, -1, + 3, -1, -4, -3, 5, 0, -3, -2, -1, 4, -1, -5, -1, 3, -1, -4, + -1, 3, 1, -4, -2, 1, 0, -2, -3, 0, 2, -1, -4, 1, 1, -1, + -2, -2, 1, -1, -3, 0, 0, 0, -1, -2, 0, 0, -2, -1, 0, -1, + 0, -2, -1, 0, -1, 0, -1, -2, 2, -1, -2, -1, 0, 1, -2, 0, + -1, -1, 0, -1, -2, 0, 1, -1, -3, 0, 1, -1, -3, 0, 1, -2, + -1, 0, 0, -1, -1, 0, -1, -1, -1, -1, 0, 0, -1, -1, 0, 0, + -2, 0, 0, 0, 0, -2, 1, -1, 0, -1, 0, 0, 0, -1, 0, 0, + 0, 0, -1, 0, 0, -1, 0, -1, 1, 0, 0, 0, 1, -1, -1, 0, + 0, 0, 1, -2, 4, -3, 3, -40, 71, -73, 67, -27, -68, 127, -80, 3, + 5, 1, 17, -14, 1, -30, 53, -3, -42, 15, 19, -9, -17, -1, 13, 16, + -17, 4, -32, 43, 15, -68, 18, 54, -38, -7, -1, 11, 7, -3, -18, 5, + 25, -27, -9, 9, 19, -6, -12, -8, 20, -1, -15, -1, 1, 17, -10, -16, + 12, 12, -13, 0, -6, 10, 2, -16, -1, 14, -4, 4, -11, -2, 12, -6, + -8, 4, 4, -2, -4, 1, -2, 4, 3, -7, -5, 8, 0, -10, 1, 4, + 2, -4, -6, 4, 1, -1, -7, 1, 8, -9, 2, -5, 3, 3, -4, -3, + 0, 3, -3, -5, 4, 3, -3, -4, 0, 2, 0, -3, -4, 5, 0, -5, + -1, 2, 0, -3, 0, -1, 2, -2, -4, 3, 0, -1, -2, -1, 2, -2, + -2, 1, -1, 0, -1, -3, 1, 1, -2, 1, -3, 1, 1, -3, -1, 1, + 0, -1, -2, 1, -1, -1, 1, -2, 1, -1, -1, -1, -1, 0, 1, -3, + 0, 0, 1, -4, 0, 1, -2, 0, -2, 0, 0, 0, -2, 1, -1, 0, + -2, 0, 2, -2, -1, 0, -1, 2, -2, -1, 1, -2, 0, -1, 1, -1, + -1, -1, 1, -2, 1, -1, -1, 2, -3, 0, 0, -1, 1, -1, 0, 1, + 0, -2, 0, -1, 1, -2, 0, 0, -1, 1, 0, -2, 0, 1, -2, 1, + 0, 0, -1, 0, 1, -1, -1, -1, 1, 1, -1, 0, 0, 0, -1, 1, + 0, -1, 1, 0, 0, 1, 0, -1, 1, 0, 3, -40, 58, -39, 12, 42, + -117, 108, 1, -66, 22, 17, 0, -9, 10, -39, 42, 4, -23, -12, 28, 3, + -34, 9, 17, 3, -9, 10, -29, 13, 53, -79, 3, 64, -26, -24, 16, -9, + 14, 2, -8, -15, 31, -9, -30, 11, 29, -15, -7, 0, 3, 6, -4, -9, + -6, 22, 1, -24, 9, 11, -8, 0, -2, 2, 8, -12, -6, 10, 2, 2, + -9, -4, 11, -2, -10, 3, 2, 3, -5, -1, 1, -1, 6, -4, -8, 9, + 2, -8, -3, 6, 3, -4, -3, -1, 6, -2, -8, 0, 9, -4, -3, -2, + 2, 4, -4, -1, -1, 4, -2, -6, 4, 2, -1, -4, 0, 1, 2, -3, + -5, 3, 3, -3, -4, 3, 0, -1, 0, -2, 2, 0, -3, 0, 3, 0, + -3, -1, 2, 0, -3, 1, 0, -1, 2, -2, -2, 2, -1, 0, -1, -1, + 1, -1, -2, 0, 0, 1, -3, 1, 0, -1, 1, -2, -1, 2, -2, -1, + 0, -1, 2, -3, -1, 1, 1, -2, -2, 2, 1, -2, -1, 0, 0, 1, + -3, 1, 0, 0, 0, -2, 3, 0, -2, 0, 0, 1, 0, -1, 1, -2, + 0, 0, 0, -1, 1, 0, 0, 0, -1, 1, -1, 1, 0, -1, 1, -2, + 0, 1, 1, 0, 1, -2, 1, 0, 1, 0, 0, 3, -1, 0, 1, 0, + 0, 3, -29, 35, -12, -16, 56, -88, 39, 62, -79, 5, 29, 1, -13, 12, + -29, 26, 17, -28, -3, 12, 5, -11, -19, 28, 1, -5, 9, -21, -7, 60, + -56, -20, 57, -10, -27, 21, -21, 16, 12, -12, -21, 24, 6, -29, 4, 19, + 2, -7, -5, -3, 7, 6, -11, -9, 11, 13, -18, -4, 13, 1, -3, -6, + -1, 10, -8, -6, 5, 3, 5, -3, -11, 4, 9, -11, 0, 4, 3, -4, + -1, 0, 0, 7, 0, -14, 7, 5, -7, -4, 4, 5, -1, -4, -4, 4, + 1, -4, -4, 7, -1, -1, -3, 0, 5, -1, -4, -1, 2, 0, -3, 1, + 1, 2, -2, -4, 1, 2, 0, -5, 2, 3, -2, -2, 1, 1, -2, 2, + -3, 0, 0, -1, -1, 0, 1, 0, -3, 0, 0, -1, 1, -1, -2, 1, + -1, 0, -2, 2, 1, -2, -1, 1, 0, -1, -1, 0, 1, -1, 0, -2, + 1, 1, -1, 0, -1, -1, 0, 0, -1, -1, 0, -1, -1, 2, -2, -1, + 1, 0, 0, -1, -1, 1, 0, -1, 1, -1, 0, 1, -3, 1, 1, -1, + -1, 0, 1, 0, 0, 0, -1, 0, 0, -1, 0, 1, 0, 0, 2, -2, + 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, -1, -1, -7, -9, + 35, -52, 59, -33, -32, 64, -15, -41, 19, 22, -20, 9, -11, -3, 33, -27, + 2, 7, -9, 19, -37, 24, 7, -11, 11, -1, -30, 37, 8, -57, 36, 19, + -33, 14, 0, -17, 26, 1, -20, -5, 26, -18, -13, 14, 7, -6, 4, -9, + -4, 11, 3, -14, -7, 20, 0, -18, 10, 1, 4, -5, -7, 6, 0, -3, + -2, -2, 8, 5, -11, -6, 10, -1, -10, 6, -2, -1, 1, -3, 0, 3, + 5, -9, -5, 9, -3, -4, 1, 1, 3, -1, -4, -1, 2, -2, -5, 5, + -3, 0, 1, -5, 4, 2, -3, -3, 0, 0, -2, 1, 0, -2, 3, -2, + -5, 2, 2, -2, -4, 3, 0, -2, 1, -2, -2, 5, -2, -6, 1, 2, + -1, -1, 0, 1, -1, -2, -1, -1, 2, 0, -4, 0, 1, 0, -3, 0, + 2, 0, -3, 0, 0, 1, -1, -1, 1, 0, -1, -2, 1, 0, 0, -1, + 0, -2, 1, 0, -1, 1, -1, 0, -2, 1, 1, -2, -1, 2, -2, 1, + -3, 1, 1, -1, 0, 0, -1, 1, 0, -2, 2, -1, -1, 0, 0, 1, + 0, 1, 0, -2, 1, 0, 0, -1, 1, 0, 0, 0, 0, -3, -20, 45, + -56, 40, -5, -34, 27, 24, -42, -1, 29, -14, -4, 2, -7, 24, -20, -1, + 18, -25, 25, -29, 9, 21, -26, 14, 4, -20, 7, 27, -42, 5, 31, -24, + -2, 19, -30, 21, 8, -11, -17, 20, 1, -22, 11, 7, -7, 6, -5, -7, + 3, 11, -6, -18, 11, 16, -20, 1, 5, 2, -3, -3, 0, -3, 4, -1, + -7, 2, 10, -9, -8, 7, 2, -9, 5, -1, -5, 2, 1, -3, -2, 9, + -5, -8, 4, 1, -5, 0, 1, 2, -1, 0, -5, 4, -1, -5, 4, -3, + 1, 1, -5, 3, 0, 0, -3, 0, -1, -2, 1, 2, -5, 2, 1, -5, + -2, 3, -1, -5, 2, 1, -4, 2, -1, -4, 2, 3, -7, -1, 2, 0, + -2, 1, 0, -2, -1, 0, -3, 1, 2, -3, -2, 3, 0, -3, -1, 1, + 0, -1, -2, -1, 1, 0, 0, -1, 0, 0, -2, 0, 0, 1, -2, 2, + -3, 1, 0, 0, -2, 1, 0, -1, 0, 0, -1, -1, 2, -3, 0, 0, + -1, 0, 0, -1, 1, 0, -4, -13, 32, -41, 31, -10, -10, 4, 22, -25, + -8, 21, -3, -14, 5, 1, 12, -23, 8, 18, -31, 25, -26, 10, 17, -23, + 8, 5, -9, 0, 16, -25, 2, 23, -22, -2, 22, -30, 15, 7, -6, -13, + 12, 1, -17, 9, 5, -6, 4, -3, -7, 5, 7, -6, -13, 7, 10, -11, + 0, 0, 4, -3, -3, 2, -7, 4, 2, -5, 0, 6, -3, -8, 4, 2, + -8, 7, 0, -8, -1, 6, 0, -8, 6, 0, -5, 1, 0, -5, 3, 2, + -3, -2, 4, -5, -1, -1, -2, 3, -4, 1, -1, -3, 3, -1, -2, -2, + 1, -2, -2, 1, 1, -4, 1, 2, -5, -3, 5, -3, -4, 4, -1, -4, + 2, -1, -4, 3, 1, -5, -2, 2, 0, -2, 2, -1, -4, 3, -1, -3, + 0, 1, -2, -2, 1, -1, -1, -1, 0, 0, -1, -1, -1, 0, -1, 1, + -1, -1, 0, -2, 1, 0, -1, -1, 0, -1, -1, -1, 2, -2, -1, 1, + -1, -2, 1, -1, -1, 1, -2, 1, -7, -3, 15, -23, 20, -16, 9, -12, + 16, -12, -8, 11, 5, -18, 6, 8, 0, -18, 16, 4, -19, 16, -17, 10, + 5, -8, -2, 9, -5, -4, 10, -17, 5, 13, -18, 2, 12, -17, 10, 0, + -2, -8, 7, -4, -7, 6, 1, -3, 1, 3, -9, -2, 10, -7, -8, 4, + 6, -6, 1, 0, 0, -2, 1, -1, -8, 6, 1, -5, 2, 4, -2, -4, + 1, 1, -7, 5, -1, -4, -2, 4, 0, -4, 4, -3, -4, 1, 0, -3, + 0, 2, -1, -2, 2, -2, -1, -3, 0, 3, -4, 3, -3, 0, 2, 0, + -3, -1, 1, -3, -1, 2, 0, -1, 0, 0, -3, 0, 1, -4, -1, 2, + 0, -2, 0, 1, -3, 1, 1, -3, -2, 2, -1, -1, 2, -1, -2, 1, + 0, -1, -1, 0, 2, 33, 42, 58, 71, 79, 85, 88, 91, 94, 79, 95, + 82, 106, 86, 105, 47, 16, -6, 13, 44, 31, -15, -38, -36, 20, 70, 41, + 48, 58, 24, -57, -127, -119, -102, -126, -128, -111, -78, -82, -88, -87, -60, -66, + -98, -104, -99, -97, -99, -104, -101, -88, -87, -91, -61, -27, -34, -54, -55, -45, + -24, -10, -5, -4, 5, 34, 63, 101, 94, 78, 52, 51, 52, 74, 81, 77, + 59, 46, 17, 7, 39, 53, 47, 42, 66, 83, 73, 52, 28, 22, 11, 8, + 11, 0, -15, -23, -15, -14, -6, 16, 46, 62, 71, 76, 90, 102, 103, 103, + 101, 100, 90, 75, 63, 67, 49, 37, 28, 12, 5, 6, 15, 15, 8, -7, + -12, -4, -10, -28, -24, -17, -25, -50, -64, -81, -103, -116, -116, -113, -95, -72, + -54, -41, -47, -65, -65, -50, -33, -24, -7, 11, 8, -4, -13, -28, -51, -75, + -90, -91, -90, -90, -87, -88, -83, -84, -82, -81, -81, -76, -65, -71, -85, -84, + -79, -83, -81, -77, -72, -70, -65, -66, -66, -65, -66, -68, -61, -56, -51, -36, + -13, -3, -5, -8, -12, -12, 3, 16, 21, 31, 50, 69, 77, 82, 90, 102, + 110, 114, 116, 117, 118, 119, 116, 112, 109, 105, 98, 99, 103, 102, 91, 73, + 64, 63, 61, 57, 51, 40, 24, 35, 57, 75, 84, 79, 65, 37, 4, -26, + -45, -57, -54, -46, -45, -54, -67, -67, -48, -16, 15, 35, 44, 45, 44, 45, + 46, 38, 23, 2, -15, -34, -52, -60, -70, -77, -80, -79, -74, -77, -84, -86, + -80, -72, -68, -72, -80, -87, -92, -96, -101, -104, -104, -101, -93, -90, -89, -86, + -85, -84, -83, -82, -81, -79, -77, -76, -73, -71, -66, -62, -55, -39, -31, -27, + -25, -31, -37, -46, -51, -53, -54, -48, -45, -38, -20, 3, 24, 35, 39, 32, + 16, 5, 3, 0, -6, -13, -13, -11, -2, 14, 28, 40, 50, 53, 50, 55, + 64, 74, 90, 105, 108, 112, 106, 104, 109, 112, 123, 127, 127, 127, 127, 127, + 127, 118, 113, 107, 110, 114, 111, 104, 101, 101, 102, 103, 99, 99, 89, 73, + 53, 35, 20, 0, -22, -43, -63, -77, -82, -76, -65, -48, -36, -29, -24, -25, + -29, -37, -40, -49, -59, -67, -73, -76, -78, -79, -75, -73, -74, -75, -68, -52, + -44, -30, -19, -9, -6, -9, -13, -24, -33, -35, -31, -30, -35, -40, -44, -45, + -51, -53, -54, -50, -50, -47, -42, -50, -55, -54, -56, -56, -54, -54, -49, -48, + -41, -32, -28, -18, -13, -5, 6, 18, 33, 49, 60, 71, 78, 88, 95, 97, + 93, 88, 91, 93, 97, 98, 97, 94, 91, 85, 81, 72, 70, 66, 61, 60, + 64, 66, 74, 83, 92, 102, 108, 109, 107, 102, 97, 95, 91, 87, 80, 74, + 67, 62, 61, 58, 61, 61, 57, 53, 43, 35, 27, 25, 24, 20, 20, 22, + 27, 34, 36, 32, 21, 8, -3, -10, -16, -18, -16, -16, -19, -15, -11, -11, + -12, -20, -34, -45, -59, -72, -80, -89, -94, -95, -102, -111, -114, -111, -111, -108, + -106, -104, -101, -98, -93, -90, -86, -86, -83, -82, -81, -79, -76, -73, -70, -72, + -78, -81, -79, -79, -72, -60, -43, -31, -25, -27, -34, -37, -40, -42, -41, -39, + -36, -34, -25, -12, -4, 5, 12, 16, 17, 15, 13, 6, -4, -7, -8, -6, + -1, 4, 7, 9, 12, 16, 19, 19, 22, 28, 29, 28, 29, 30, 34, 40, + 49, 57, 71, 78, 85, 92, 96, 95, 89, 85, 86, 93, 99, 104, 102, 100, + 94, 85, 77, 73, 69, 66, 63, 60, 60, 59, 57, 52, 47, 41, 31, 18, + 6, -3, -7, -11, -12, -14, -18, -22, -23, -22, -24, -30, -37, -41, -44, -50, + -56, -64, -67, -65, -62, -58, -58, -58, -59, -61, -62, -66, -72, -78, -79, -77, + -73, -68, -64, -61, -56, -53, -54, -52, -52, -57, -63, -69, -70, -68, -65, -62, + -59, -57, -56, -58, -60, -61, -63, -64, -62, -61, -60, -58, -54, -49, -45, -42, + -39, -36, -32, -28, -22, -13, -7, -3, 2, 13, 28, 41, 52, 64, 71, 73, + 73, 70, 64, 61, 60, 64, 66, 65, 66, 64, 61, 60, 62, 65, 64, 66, + 67, 67, 68, 66, 64, 66, 68, 73, 76, 74, 72, 66, 58, 52, 46, 42, + 38, 38, 41, 47, 52, 52, 48, 45, 42, 40, 38, 34, 29, 27, 26, 28, + 29, 28, 29, 30, 31, 28, 24, 21, 19, 17, 14, 10, 6, 3, -4, -9, + -15, -19, -26, -33, -40, -49, -55, -60, -65, -70, -73, -72, -72, -71, -70, -71, + -75, -78, -81, -83, -86, -86, -85, -84, -82, -80, -77, -72, -69, -66, -63, -61, + -61, -61, -61, -61, -60, -58, -53, -48, -42, -36, -30, -28, -30, -32, -33, -32, + -31, -28, -22, -18, -10, -5, 0, 3, 6, 11, 16, 19, 22, 24, 26, 27, + 29, 34, 40, 46, 48, 48, 48, 45, 40, 36, 33, 31, 33, 35, 40, 48, + 55, 62, 68, 73, 76, 78, 78, 77, 79, 82, 85, 87, 87, 87, 86, 86, + 86, 83, 78, 71, 63, 55, 48, 44, 39, 36, 36, 36, 35, 32, 28, 24, + 18, 13, 9, 6, 4, 1, -2, -5, -11, -17, -20, -21, -20, -21, -24, -28, + -32, -34, -33, -33, -35, -37, -40, -43, -47, -52, -58, -63, -69, -74, -77, -80, + -81, -82, -81, -80, -77, -74, -69, -62, -54, -48, -48, -51, -54, -57, -57, -57, + -56, -55, -55, -56, -57, -56, -55, -54, -54, -54, -54, -52, -49, -45, -41, -38, + -34, -31, -29, -27, -24, -20, -17, -11, -7, -3, 0, 5, 10, 16, 22, 27, + 31, 34, 38, 42, 44, 45, 48, 50, 52, 57, 61, 64, 64, 65, 65, 63, + 60, 57, 55, 55, 58, 61, 63, 65, 67, 69, 71, 74, 77, 79, 79, 77, + 74, 71, 68, 66, 63, 60, 57, 55, 51, 46, 40, 36, 30, 25, 20, 17, + 16, 17, 16, 14, 12, 10, 7, 3, -1, -5, -11, -15, -17, -18, -18, -19, + -21, -25, -29, -32, -33, -33, -36, -39, -43, -46, -50, -53, -56, -58, -59, -60, + -61, -62, -63, -65, -66, -67, -68, -70, -72, -72, -70, -67, -63, -61, -60, -60, + -58, -56, -54, -53, -52, -52, -52, -51, -50, -49, -47, -45, -43, -40, -37, -35, + -34, -32, -29, -25, -21, -18, -14, -9, -4, 0, 4, 7, 11, 15, 18, 21, + 25, 28, 33, 37, 41, 44, 46, 47, 47, 46, 46, 45, 43, 42, 42, 43, + 46, 48, 49, 50, 52, 55, 59, 62, 65, 66, 67, 68, 69, 69, 70, 72, + 74, 74, 73, 72, 71, 69, 65, 61, 57, 53, 50, 46, 43, 38, 35, 32, + 28, 23, 19, 17, 17, 15, 13, 11, 9, 5, 1, -3, -6, -9, -12, -14, + -17, -19, -23, -27, -31, -35, -38, -40, -43, -46, -48, -52, -55, -57, -61, -64, + -66, -67, -68, -69, -70, -70, -70, -69, -69, -70, -71, -70, -66, -62, -59, -55, + -52, -50, -46, -43, -41, -38, -36, -35, -35, -34, -33, -33, -33, -33, -31, -30, + -28, -26, -25, -24, -21, -20, -20, -19, -19, -18, -17, -16, -15, -13, -11, -8, + -3, 2, 9, 15, 21, 27, 33, 38, 41, 45, 48, 51, 53, 55, 56, 56, + 56, 56, 56, 56, 56, 55, 57, 58, 60, 61, 62, 62, 64, 66, 68, 69, + 71, 72, 73, 74, 72, 70, 67, 63, 60, 57, 54, 50, 46, 41, 36, 31, + 27, 23, 19, 16, 14, 12, 11, 9, 8, 5, 2, -1, -4, -8, -10, -15, + -18, -19, -20, -22, -22, -23, -23, -24, -26, -29, -31, -33, -35, -36, -37, -38, + -41, -44, -46, -48, -50, -52, -54, -56, -59, -61, -63, -63, -64, -65, -64, -63, + -62, -61, -60, -59, -58, -57, -58, -57, -57, -55, -53, -50, -49, -47, -46, -43, + -40, -37, -33, -31, -28, -26, -23, -20, -16, -14, -12, -9, -5, -2, 1, 5, + 9, 13, 17, 21, 24, 26, 29, 32, 35, 37, 37, 38, 39, 41, 43, 44, + 45, 46, 48, 50, 51, 53, 52, 52, 50, 48, 47, 46, 46, 46, 46, 47, + 48, 49, 51, 54, 56, 58, 60, 61, 62, 62, 62, 61, 59, 57, 55, 54, + 53, 52, 51, 49, 46, 41, 36, 31, 27, 22, 18, 14, 11, 9, 6, 3, + 0, -2, -5, -8, -11, -16, -20, -25, -28, -31, -34, -37, -39, -41, -41, -42, + -42, -42, -43, -45, -46, -47, -49, -50, -52, -54, -56, -57, -58, -60, -61, -63, + -64, -64, -64, -63, -63, -61, -59, -58, -57, -55, -54, -53, -52, -52, -51, -50, + -49, -47, -46, -45, -44, -42, -40, -38, -35, -32, -30, -28, -25, -22, -19, -17, + -15, -12, -9, -5, -1, 3, 7, 11, 15, 19, 23, 25, 27, 30, 34, 36, + 37, 38, 39, 40, 42, 44, 45, 46, 47, 49, 50, 52, 53, 52, 51, 49, + 47, 47, 46, 46, 46, 47, 47, 48, 50, 52, 55, 57, 59, 61, 62, 62, + 62, 61, 60, 58, 56, 54, 54, 53, 51, 50, 47, 44, 39, 34, 29, 25, + 20, 16, 13, 10, 7, 4, 2, -1, -3, -6, -9, -14, -18, -22, -26, -30, + -33, -35, -38, -40, -41, -41, -42, -42, -43, -44, -46, -47, -48, -49, -51, -53, + -55, -56, -57, -59, -60, -62, -63, -64, -64, -63, -63, -62, -60, -59, -57, -56, + -55, -53, -52, -52, -51, -51, -50, -48, -46, -45, -44, -43, -41, -39, -36, -34, + -31, -29, -26, -24, -21, -16, 1, -2, -1, -9, -9, -6, 5, 6, -1, -10, + 8, 24, 11, -2, -14, -9, -15, -13, 5, 14, 12, -6, -1, -12, 1, -9, + 12, 12, 10, 5, -19, -11, -13, -2, 8, 5, 1, -2, -3, 9, -6, 6, + 5, 6, -3, -17, -7, 3, 2, -1, 0, 7, -7, 5, 4, 6, -18, -24, + 6, 20, -1, -4, -1, 10, 3, -10, 8, 7, -11, -17, -15, 5, 18, 4, + 1, 8, -16, -4, 0, 11, 9, -10, -15, 0, -22, -12, 19, 34, 16, -9, + -16, -7, -12, -10, 13, 23, -1, -10, -2, -3, -11, 13, 7, -6, -9, 3, + 11, -10, -18, 12, 22, 7, -27, -29, -4, 20, 20, 10, 8, -16, -26, -6, + 22, 21, 7, 15, 8, -50, -50, -7, 35, 22, -13, 32, 41, -33, -46, -10, + 23, -7, -25, 23, 21, -38, -36, 14, 44, 2, 2, 34, -14, -51, -29, 11, + 19, 7, 22, 13, -23, -21, -8, -9, 1, 14, 26, 26, -8, -34, -33, 4, + 1, -6, -2, 16, -7, -23, 12, 27, 5, 6, 6, 0, -8, 0, -1, -17, + -13, -12, 3, 9, 4, 11, 23, 36, 0, -43, -16, 4, -21, -26, 27, 16, + -25, 3, 65, 4, -34, 24, -10, -38, -14, 13, 4, -15, 36, 44, -42, -51, + 20, -5, -6, 68, 20, -18, -39, -11, 9, 17, 6, -33, -20, -13, 48, 30, + 22, -4, -9, -53, -20, 32, 32, -16, 17, -11, -36, -8, -5, 39, 28, 33, + 21, -64, -48, 3, -22, 15, 62, -26, 0, 3, 5, 73, -14, -48, -20, -59, + 4, 70, 60, -7, -2, -88, -22, -17, 39, 17, 33, -3, 15, 28, -47, -80, + -37, 5, 7, 104, 16, -99, -92, -36, 109, 78, 26, -15, -92, -21, 62, 48, + -51, -81, -25, 55, 63, 35, 21, -115, -54, 101, 73, -41, -110, -66, 50, 107, + 45, -8, -109, -38, 12, 102, 3, 17, -45, -2, -36, 39, 46, -12, -28, -27, + -17, 17, -18, 82, -5, -3, -25, -5, -14, 15, 9, -3, -17, -6, 2, 7, + -36, -13, 6, 21, -23, -20, 16, -18, 3, -2, 26, 0, 13, -23, -2, -19, + -28, -18, 15, 12, 22, -4, 23, -17, -22, -9, -18, -4, 11, 13, 0, 34, + -16, -20, 26, 23, 15, -4, -25, 7, 8, -9, 8, 44, 1, -40, 17, -32, + 9, -30, -52, 52, 3, 2, -21, 83, 58, -14, -46, -61, -12, -67, -20, 64, + 72, 57, -10, 5, 1, -77, 31, -47, -39, 12, 22, 57, 28, 0, 9, -76, + 15, -74, 33, -12, 39, 114, -35, -36, -38, -23, 27, -21, 14, 56, 47, 6, + -72, -61, -4, 18, -4, 19, 13, 45, 71, 48, -1, -125, -52, -56, -20, -18, + -12, 51, 78, 68, -46, 32, -40, -29, -28, -81, -25, 75, 42, 58, -38, 1, + -29, -34, 31, -36, -14, 10, 64, 37, 2, -31, -72, -17, -33, 30, -52, -54, + 25, 43, 70, 81, -9, -73, 4, -65, 15, -28, 25, 0, 28, 19, 51, -26, + 6, 0, -37, -15, -22, -20, -16, -5, 50, 56, 67, 25, 16, -35, -29, -14, + -39, 19, -24, -52, -13, -32, -10, 39, 33, 59, 6, 37, 55, 11, -9, -35, + -15, -57, -56, -36, -34, 19, 19, 6, 20, 17, -11, 5, 26, 19, 16, 7, + -20, -26, -55, -62, -36, -18, 19, 37, 47, 25, -6, -14, 1, -4, -13, 12, + 23, 34, 38, 41, 33, 31, -10, -56, -52, -49, -31, -40, -21, -12, 0, 5, + 12, 22, 22, 21, 31, 12, 2, -8, -4, -18, -7, 3, 1, -1, 11, 12, + 18, 17, 9, -2, -12, -13, -11, -1, 8, 3, 3, 2, 5, -5, -16, -15, + -13, -8, -12, -9, -2, -1, 2, 7, 10, 7, 11, 14, 7, -1, -4, 5, + -3, -2, 0, -6, -10, -1, -5, 3, 9, 0, -8, -9, -6, -6, 0, 6, + 3, 6, 7, 10, 0, -8, -3, -5, -1, -8, -7, -4, -3, -3, 0, -1, + -6, 2, 7, 7, 5, 4, 10, 5, 8, -1, -11, -15, -11, -15, -10, -1, + -8, -12, -5, 1, 3, 6, 8, 11, 18, 22, 26, 10, -10, -1, -15, -3, + -21, -16, -14, -12, -7, -8, -18, -20, -11, 9, 20, 27, 26, 11, 1, 21, + 6, 3, -9, -15, -9, -20, 3, 5, 21, 14, 6, 11, -21, -22, -6, -21, + -23, -18, 11, 6, 5, 21, 9, 23, 16, -3, -30, -7, -27, -4, 5, 18, + 22, 16, 2, 7, -1, -2, -10, -14, -10, -17, -10, -15, -16, 3, 12, 30, + 18, -1, -6, -15, -3, 5, 11, -18, -2, 8, 21, 11, -13, -4, -30, -7, + 0, 12, 25, -3, 17, 14, -20, -6, -27, -41, -11, -12, 23, -8, 13, 24, + 18, 27, -11, -8, -12, -2, 17, 23, 13, -20, -21, -2, -21, -34, -46, -23, + 28, 48, 9, -10, 8, 29, 27, 5, -29, -12, 13, -5, -2, -35, 1, 3, + 24, 13, 17, -18, -30, -21, 14, -1, 6, -8, 48, 45, -7, -34, -49, -32, + -6, -26, 20, 29, 76, 30, -21, -66, -36, -15, 40, -5, 29, 3, 10, -39, + -25, -2, 24, 19, 19, -4, -8, 3, -22, -23, -18, 13, 17, -3, -25, 23, + 66, 26, -18, -27, -34, -30, -30, 36, 25, 28, -22, -17, -7, -22, 21, 18, + 42, 8, -25, -28, -31, -10, 15, 18, 0, -1, -5, 16, -12, 13, 13, 12, + -8, -37, -9, 13, -5, 8, -3, 13, -8, 4, 24, -16, -43, -18, 26, 26, + -11, -9, 19, 9, -15, 9, 15, -12, -31, -27, 8, 29, 5, 7, 17, -33, + -14, 14, 23, -1, -18, -18, -4, -35, -17, 47, 71, -16, -20, -11, -16, -25, + 6, 37, 14, -18, 1, -8, -14, 10, 14, 2, -20, 0, 20, -10, -25, 14, + 32, 7, -39, -38, -3, 34, 25, 13, 3, -24, -34, 5, 38, 18, 7, 29, + -30, -74, -41, 36, 40, -12, 26, 55, -17, -59, -26, 28, -2, -31, 24, 25, + -44, -39, 21, 44, -1, 10, 33, -34, -50, -12, 18, 13, 20, 17, -6, -31, + -10, -6, -1, 7, 12, 14, 6, -16, -24, 6, 9, -16, -16, 6, 2, -10, + 13, 12, -10, 0, 11, 11, 10, -3, -22, -22, -12, -7, 19, 17, -2, -12, + 6, 16, 7, -11, -1, -20, -22, -8, 26, 16, -3, 12, 1, -33, 2, 30, + -23, -5, 28, -17, -19, 21, 9, -28, -14, 25, -1, 4, 24, 0, -26, -9, + 7, 2, -2, 20, -10, -11, 5, -3, -4, 8, -9, 14, 18, 25, -22, -15, + -22, -3, -12, 27, 30, 15, -11, -26, -4, 15, -7, -14, 23, -23, -4, 34, + -2, -38, 14, -11, -24, 16, 34, 11, -13, 3, -3, -19, -34, 0, -3, 24, + 43, 1, -12, -38, -25, -11, 23, 35, 12, -28, -25, -16, 7, 22, 1, -10, + 8, 8, -3, 6, -24, -20, -13, 9, 31, 12, -16, 7, -29, 5, 8, -28, + 3, 4, 12, 26, -9, -15, -5, -20, 9, 21, 0, 1, -9, 0, 8, -3, + -7, -9, -3, 22, 8, 3, -11, -9, -11, 3, 15, 9, -10, 1, -3, -3, + -2, -5, 9, 0, 12, 7, -15, -7, 0, -8, 5, 9, -5, 7, -7, 10, + 4, -11, -2, -8, -4, 9, 9, 0, -2, -11, -3, -4, 3, 4, 3, -2, + 3, 3, -8, -9, -2, 0, 3, 5, -1, -10, -7, 2, 8, 3, 0, -5, + -5, 2, 4, -2, -5, -3, 2, 3, 0, 2, -5, -3, 3, 2, -2, -4, + -2, 1, 2, 1, 0, -1, 1, -2, -5, 0, 0, 2, 0, -3, -2, 0, + 1, 0, -2, -2, -2, 0, 3, 3, -2, -5, -1, -1, -1, -4, 3, 9, + 1, -1, -2, -11, -7, 1, 9, 11, 8, -4, -11, -12, -9, -4, 18, 15, + 14, 1, -22, -29, -14, 3, 30, 29, 14, -2, -35, -43, -11, 13, 36, 42, + 15, -16, -49, -44, -10, 28, 47, 38, 11, -25, -66, -39, 4, 36, 58, 33, + -3, -44, -65, -29, 19, 52, 54, 23, -13, -59, -65, -15, 32, 69, 49, 8, + -30, -74, -51, 3, 43, 71, 40, -5, -48, -77, -31, 16, 57, 67, 24, -15, + -67, -72, -12, 36, 66, 59, 5, -31, -80, -51, 3, 49, 75, 37, -2, -59, + -81, -28, 20, 67, 66, 22, -23, -76, -65, -10, 41, 78, 48, 4, -36, -85, + -47, 6, 59, 80, 31, -8, -69, -82, -22, 29, 73, 63, 17, -31, -81, -63, + -1, 47, 79, 47, 3, -56, -90, -40, 19, 75, 73, 28, -25, -86, -74, -10, + 48, 85, 56, 6, -51, -93, -48, 11, 67, 86, 33, -11, -78, -87, -29, 36, + 89, 66, 13, -38, -91, -60, 2, 50, 83, 48, 0, -56, -90, -41, 16, 71, + 78, 30, -17, -80, -75, -20, 31, 82, 62, 15, -32, -85, -66, -7, 48, 84, + 50, 4, -53, -87, -44, 8, 62, 78, 35, -8, -65, -83, -30, 23, 70, 71, + 24, -20, -76, -75, -12, 32, 73, 62, 15, -30, -85, -62, -2, 41, 76, 51, + 9, -39, -86, -52, 1, 45, 79, 46, 8, -49, -89, -46, 3, 54, 80, 43, + 7, -55, -83, -50, 0, 53, 76, 54, 11, -52, -83, -55, 0, 40, 67, 58, + 22, -32, -79, -67, -11, 28, 63, 52, 37, -9, -70, -63, -28, 10, 42, 49, + 53, 8, -46, -64, -41, 1, 22, 38, 51, 39, -16, -63, -46, -23, 5, 33, + 38, 48, 14, -42, -57, -29, -5, 22, 37, 40, 28, -23, -53, -39, -10, 14, + 30, 40, 31, -1, -48, -40, -18, 11, 19, 31, 26, 14, -20, -50, -25, -5, + 11, 31, 30, 14, 0, -35, -39, -4, -1, 19, 27, 17, 9, -10, -39, -21, + -8, 9, 24, 26, 13, -5, -19, -30, -12, -1, 17, 25, 16, 3, -19, -26, + -13, -6, 17, 22, 20, 5, -16, -32, -19, -1, 23, 27, 23, 4, -30, -33, + -23, -1, 35, 35, 24, -2, -41, -45, -21, 9, 45, 41, 22, -12, -50, -46, + -18, 28, 55, 45, 10, -27, -78, -42, 0, 53, 66, 32, -1, -61, -74, -28, + 27, 64, 64, 24, -28, -80, -66, -15, 53, 84, 48, 5, -59, -94, -41, 17, + 75, 80, 26, -21, -91, -79, -12, 48, 87, 55, 10, -58, -96, -46, 9, 80, + 81, 30, -23, -84, -80, -15, 49, 90, 49, 9, -57, -95, -45, 17, 76, 79, + 26, -20, -91, -75, -18, 52, 90, 52, 6, -59, -92, -41, 15, 68, 80, 31, + -21, -87, -76, -13, 45, 87, 49, 11, -60, -94, -35, 14, 80, 68, 22, -23, + -89, -66, -7, 47, 93, 44, -8, -61, -95, -31, 24, 86, 75, 10, -35, -96, + -66, -1, 61, 100, 44, -12, -77, -105, -33, 32, 97, 92, 16, -44, -111, -90, + -5, 65, 121, 65, -3, -80, -123, -59, 17, 98, 111, 46, -25, -112, -109, -33, + 42, 112, 90, 30, -55, -115, -84, -17, 66, 105, 71, 13, -73, -113, -61, 0, + 77, 96, 56, 4, -80, -108, -50, 8, 78, 93, 47, 3, -88, -98, -40, 7, + 65, 76, 53, 18, -71, -90, -44, 0, 39, 57, 43, 34, -19, -69, -54, -19, + 18, 32, 31, 34, 7, -40, -36, -21, -1, 12, 12, 25, 27, -9, -32, -14, + -14, 2, 0, 1, 20, 19, -2, -13, -11, -18, -12, -2, 18, 24, 12, -2, + -14, -19, -19, -12, 18, 24, 22, -2, -15, -32, -20, 3, 22, 26, 17, -13, + -31, -27, -13, 17, 33, 32, 5, -29, -47, -29, 2, 33, 42, 32, -6, -53, + -52, -24, 22, 51, 41, 27, -32, -74, -45, 0, 45, 59, 33, -1, -62, -66, + -31, 26, 73, 49, 17, -42, -80, -42, -8, 63, 72, 28, -10, -75, -72, -23, + 32, 88, 47, 13, -56, -93, -38, 10, 76, 69, 26, -20, -96, -66, -10, 48, + 90, 47, 0, -69, -103, -29, 25, 87, 73, 18, -35, -104, -68, -2, 61, 93, + 47, -5, -83, -98, -31, 30, 92, 68, 17, -39, -97, -63, -5, 64, 88, 35, + -9, -74, -86, -22, 31, 85, 54, 13, -44, -93, -46, 9, 65, 75, 23, -17, + -75, -78, -15, 39, 84, 54, 3, -52, -96, -46, 12, 71, 90, 29, -18, -89, + -87, -26, 36, 86, 72, 26, -37, -106, -77, -12, 45, 99, 68, 22, -46, -108, + -73, -10, 43, 87, 69, 19, -27, -92, -79, -12, 27, 63, 57, 26, 4, -53, + -75, -35, 12, 33, 37, 31, 26, -9, -53, -39, -16, 6, 20, 23, 22, 13, + -8, -22, -23, -18, -3, 9, 25, 19, 4, -8, -20, -17, -10, 6, 16, 17, + 13, -8, -34, -21, -6, 17, 33, 23, 6, -32, -51, -23, 11, 36, 46, 31, + -11, -46, -65, -31, 15, 59, 55, 28, -20, -73, -64, -26, 42, 78, 51, 14, + -53, -85, -48, -4, 70, 80, 38, -16, -80, -76, -32, 39, 90, 58, 19, -59, + -99, -50, 14, 71, 75, 36, -21, -94, -70, -23, 51, 88, 53, 9, -68, -97, + -40, 16, 83, 73, 29, -33, -100, -61, -13, 58, 87, 41, 0, -74, -81, -35, + 24, 87, 55, 20, -41, -88, -58, 0, 69, 73, 34, -5, -86, -75, -20, 38, + 79, 49, 13, -48, -90, -39, 2, 71, 68, 31, -16, -84, -67, -15, 38, 79, + 42, 12, -50, -85, -37, 2, 62, 71, 34, -5, -83, -75, -24, 27, 82, 51, + 27, -30, -88, -54, -15, 44, 73, 50, 16, -49, -81, -47, -6, 38, 58, 50, + 27, -31, -69, -52, -13, 15, 36, 45, 33, -5, -41, -44, -23, 2, 14, 27, + 33, 10, -25, -20, -18, -6, 1, -1, 17, 22, 3, -13, -10, -17, -13, -6, + 13, 24, 15, 1, -11, -19, -19, -16, 12, 24, 24, 3, -12, -29, -26, -1, + 18, 27, 19, -4, -31, -28, -19, 11, 30, 35, 12, -21, -46, -35, -6, 28, + 42, 36, 5, -46, -57, -31, 10, 50, 43, 33, -16, -71, -55, -9, 35, 62, + 38, 10, -51, -71, -40, 11, 69, 58, 24, -26, -81, -50, -18, 48, 79, 37, + 1, -62, -81, -32, 16, 84, 59, 20, -37, -96, -50, -2, 63, 78, 33, -4, + -85, -80, -20, 33, 88, 59, 10, -50, -107, -47, 14, 75, 85, 27, -19, -95, + -83, -15, 47, 94, 60, 8, -66, -105, -46, 15, 83, 81, 26, -23, -91, -76, + -18, 48, 92, 47, 1, -59, -94, -36, 18, 78, 66, 19, -27, -91, -60, -3, + 53, 80, 35, -8, -62, -86, -28, 27, 79, 66, 13, -38, -94, -62, 1, 56, + 95, 42, -6, -75, -96, -39, 22, 80, 80, 36, -20, -97, -92, -24, 30, 93, + 79, 32, -27, -102, -87, -22, 31, 81, 79, 29, -14, -81, -91, -25, 19, 56, + 63, 31, 11, -39, -77, -47, 3, 31, 37, 33, 27, 3, -48, -46, -20, 0, + 18, 22, 23, 16, -3, -20, -19, -15, -4, 2, 8, 5, 0, 0, 0, 1, + -1, -1, 3, -4, -2, 1, -1, -2, 2, 3, -6, 1, 2, -6, 2, 2, + -4, -1, 2, -5, 1, 4, -4, 0, -1, 0, -1, -2, 2, 2, -6, 0, + 4, -3, -3, 4, -2, -3, -2, 0, 1, 1, -2, -2, 3, -8, 27, -42, + 11, 21, -35, 34, -25, 12, 9, -24, 14, 13, -38, 53, -42, -3, 46, -73, + 55, -16, -9, 28, -49, 38, -12, -21, 49, -51, 20, 32, -73, 64, -28, -7, + 32, -50, 42, -11, -30, 49, -21, -31, 46, -25, -7, 20, -22, 18, -16, -10, + 21, -23, 5, 28, -35, 8, 0, 8, -26, 19, 6, -11, -20, 64, -46, -18, + 51, -73, 119, -117, 46, 36, -80, 67, -46, 22, 0, -24, 56, -59, 14, 26, + -40, 24, -9, 20, -20, -15, 43, -26, -11, 9, 14, -3, -31, 6, 54, -62, + 3, 67, -78, 20, 21, -25, 31, -41, 18, 27, -53, 32, 15, -48, 37, -11, + 4, -12, -3, 31, -24, -21, 42, -10, -45, 55, -32, 34, -43, -14, 86, -78, + 8, 39, -35, -2, 13, 2, 5, -11, -4, 7, 5, -31, 37, -4, -28, 28, + -9, -11, 10, -1, 4, -18, 17, -9, -13, 24, -18, 20, -18, -30, 59, -25, + -29, 48, -15, -29, 23, 4, -3, -18, 14, 6, -8, -19, 19, 8, -13, 0, + 13, -18, 4, 1, 0, 0, 10, -14, -12, 39, -46, 23, 9, -22, 23, -20, + -22, 63, -42, -28, 77, -66, 12, 38, -56, 31, 27, -77, 66, -11, -39, 59, + -33, -41, 92, -54, -50, 96, -36, -46, 46, -17, 31, -43, -28, 98, -57, -50, + 84, -22, -44, 39, -8, 17, -28, -13, 63, -67, 16, 10, 3, -15, -4, 36, + -34, -1, 26, -27, -2, 13, 7, -22, 0, 27, -11, -19, 6, 26, -42, 14, + 18, -7, -14, -10, 37, -14, -24, 25, -4, -5, -10, 3, 35, -39, -7, 31, + -8, -23, 15, 4, -1, -25, 28, 7, -35, 34, -16, -1, 9, -35, 45, -22, + -17, 48, -52, 24, 22, -65, 48, 7, -45, 47, -19, -33, 71, -70, 46, -7, + -52, 68, -25, -35, 48, -13, -17, 14, 2, -12, 8, -10, 1, 22, -32, 4, + 34, -26, -18, 29, -7, -19, 15, -7, 15, -8, -29, 50, -22, -35, 53, -19, + -37, 47, -9, -40, 41, 1, -27, 7, 3, 0, 0, -7, 13, -7, -21, 26, + 14, -44, 11, 40, -51, 10, 26, -28, 16, -13, -3, 31, -42, 11, 34, -52, + 11, 34, -43, 10, 29, -19, -21, 27, -10, -5, 10, -14, 11, 3, -35, 43, + 3, -52, 37, 22, -66, 49, -12, -19, 50, -58, 16, 42, -70, 50, -2, -42, + 60, -69, 43, 11, -57, 54, -8, -31, 23, -8, -7, 24, -32, 11, 21, -51, + 60, -44, -6, 68, -87, 33, 45, -79, 50, -7, -13, 21, -40, 31, 12, -41, + 18, 24, -39, 15, 7, -17, 25, -20, -12, 43, -47, 17, 6, -16, 10, 4, + -11, -1, 14, -10, -7, 6, 9, -23, 9, 3, 13, -30, 16, 16, -33, 17, + 4, -17, 23, -29, 3, 54, -86, 50, 11, -41, 30, -23, 15, 18, -60, 56, + 7, -65, 49, -4, -12, 1, -6, 19, -4, -33, 35, -10, -12, 13, -2, -2, + -2, 2, -10, 16, -8, -11, 19, -6, -19, 24, -14, 9, 3, -24, 24, -6, + -13, 19, -11, -6, 6, -9, 16, -8, -10, 14, -10, -1, -5, 16, -8, -25, + 37, -11, -27, 37, -14, -13, 19, -17, 14, -5, -15, 26, -27, 10, 11, -23, + 22, -5, -19, 25, -7, -28, 44, -35, 0, 25, -31, 31, -10, -26, 46, -41, + 2, 33, -40, 24, 8, -43, 44, -12, -25, 37, -25, -6, 29, -27, 5, 24, + -40, 24, -1, -25, 23, -1, -6, -2, -1, 14, -24, 8, 13, -11, 0, -13, + 16, 15, -56, 43, 12, -35, 14, -9, 18, -10, -19, 28, -3, -27, 23, -2, + -14, 27, -35, 10, 35, -68, 44, 7, -43, 46, -21, -25, 56, -35, -21, 51, + -33, -8, 28, -27, 19, -2, -26, 36, -26, 3, 13, -12, 6, -10, 8, -14, + 15, -12, 0, 13, -9, -16, 32, -27, 3, 23, -49, 49, -17, -31, 63, -64, + 25, 36, -76, 61, -11, -47, 75, -54, -9, 69, -81, 32, 29, -63, 46, -7, + -26, 39, -31, 6, 18, -26, 13, -5, 5, -5, -2, 5, -12, 17, -17, -2, + 22, -25, 1, 20, -19, 3, 6, -6, 3, -9, 10, -6, -3, 7, -7, -3, + 12, -5, -5, -11, 24, -7, -23, 24, 0, -14, 0, 12, -10, -2, 5, 0, + 1, -10, 10, -2, -17, 26, -11, -16, 28, -22, 6, 4, -17, 30, -27, -7, + 46, -54, 15, 29, -42, 25, -4, -15, 26, -29, 11, 15, -28, 19, -7, 1, + 8, -20, 14, 1, -15, 11, -2, -2, 0, -10, 15, -5, -12, 15, -1, -15, + 12, 4, -15, 9, -1, -9, 9, -5, -6, 13, -12, 1, 6, -6, -3, 6, + -4, 0, -6, 11, -9, -2, 13, -12, -2, -1, 8, -11, 4, 2, -6, 4, + -4, 4, 0, -13, 15, 0, -21, 23, -5, -15, 15, -2, -9, 6, -2, -4, + 2, 3, -1, -7, 7, -2, -9, 6, 2, -9, 4, 5, -12, 10, -9, 4, + 5, -16, 12, -2, -13, 20, -13, -4, 17, -23, 14, 2, -20, 22, -13, -3, + 15, -22, 12, 4, -18, 17, -7, -7, 13, -14, 6, 4, -10, 9, -5, -6, + 7, 0, -7, 8, -4, -1, 0, -6, 4, 7, -14, 2, 13, -16, 3, 10, + -15, 7, -1, -10, 14, -10, -2, 11, -9, -4, 7, -6, 3, -3, -5, 9, + -6, -3, 5, 1, -7, 3, -2, 0, -2, 0, 4, -3, -2, 4, -6, 4, + -2, -2, 0, 1, 0, -7, 7, -2, -7, 9, -7, -4, 11, -15, 11, -2, + -9, 9, -4, -3, 2, 3, -7, 5, 0, -5, 6, -7, 1, 7, -10, -2, + 13, -9, -4, 8, -4, -2, -1, 1, 1, -7, 4, 5, -8, 0, 6, -6, + 0, 3, -4, 0, 1, -2, 2, -4, -4, 8, -7, -1, 6, -9, 8, -3, + -6, 12, -12, 1, 10, -11, 1, 5, -6, 3, -2, -3, 7, -10, 2, 7, + -12, 5, 2, -5, 3, -5, 0, 6, -10, 3, 4, -8, 2, 2, -3, 3, + -8, 8, 2, -14, 10, 3, -12, 8, 2, -11, 8, -2, -6, 9, -7, -4, + 10, -9, -1, 7, -7, 1, 3, -8, 8, -2, -8, 10, -3, -5, 5, -6, + 3, 1, -8, 10, -5, -5, 7, -4, -2, 2, -3, 1, -1, -3, 4, -3, + 0, 0, 0, 0, -4, 3, -2, -3, 3, -5, 3, 0, -7, 5, 1, -8, + 5, 1, -6, 6, -5, 0, 3, -7, 3, 2, -6, 3, 2, -6, 3, 1, + -3, -2, 5, -4, -1, 3, -4, 0, 0, -3, 5, -5, -3, 7, -5, -3, + 6, -4, 0, -1, -3, 3, -2, -1, 2, -1, -2, 1, -2, 1, -1, -7, + 8, -1, 5, -7, 13, -22, 8, -7, 8, -110, -28, 24, 54, 36, 2, 60, + -45, 57, 42, -43, 20, 41, -66, 24, -11, 18, -18, -38, -63, -36, 30, -11, + 33, 25, 30, 18, 11, -18, -5, 5, -46, 40, 1, -13, -18, -20, -31, 20, + 10, 29, -7, -18, 40, -29, -17, 42, -19, 6, -4, 6, -8, 10, -26, -5, + 3, 1, -17, 6, 0, 19, -1, 8, 0, -6, -10, -1, -12, -1, 1, -3, + 8, -7, 4, 11, 4, 14, -13, 16, -19, -4, -13, -13, -14, 6, 4, -1, + 4, 11, -1, 11, -1, 1, -4, -1, -15, 6, -9, 1, -1, 0, 3, 1, + -8, 3, -1, -1, 2, -2, 2, -2, 1, -5, -7, 3, -3, 6, -3, 4, + -1, 0, -4, 2, -7, 3, -6, -1, -1, 4, 0, 3, -2, 2, -5, 5, + -8, -3, -3, 2, -5, 7, -1, 4, -2, 4, -10, 6, -6, -1, -4, 5, + -13, 7, -6, 5, -8, 17, -20, 14, -6, 9, -40, 71, -127, 9, -73, 127, + 76, -28, 74, -32, 8, -62, -49, -38, 40, -68, 22, -12, 68, 10, 39, -10, + 0, 35, -23, 0, -59, -15, -7, -3, -23, 1, -20, 37, 27, 2, 30, -2, + 17, 2, -5, -7, -27, -29, 16, -3, -11, 1, -16, -5, -8, -10, 7, 32, + 9, 5, -4, 16, 5, -8, -17, -16, 5, -13, 8, 11, 15, -10, -9, 0, + -1, 2, 7, -3, -23, 9, 2, 3, 1, -13, -1, -6, 11, -6, 8, 1, + 12, -12, 9, -14, 8, -1, 0, -3, -13, 4, -7, -4, 8, 5, -5, -7, + 4, -2, -3, 2, 3, -6, 8, -3, 1, -3, -2, 2, -6, 2, -4, -3, + -4, 3, 1, 0, 0, 1, -1, -1, 2, -2, 0, -4, -2, 1, 2, 0, + -3, 1, -3, 0, -1, -3, -6, 2, -2, 3, -4, 10, -8, 9, -5, 12, + -19, 46, 37, -128, 60, -90, 102, -65, 40, -57, 39, -6, 23, -8, 19, 24, + 15, -17, -47, -27, -36, -16, 21, 3, 23, 14, 50, -8, 19, 25, 7, -9, + -28, -63, -37, 0, -42, 54, -17, 68, -3, 30, -12, -4, 11, -15, 9, -25, + -15, -2, -27, -25, 38, -8, -13, 33, 24, 12, -38, 39, -12, -3, -17, -44, + 38, 2, 27, 3, -5, -4, -13, -30, -56, -4, 11, 1, 9, 17, 46, 25, + -14, 6, -3, -7, -21, 2, 16, -5, -22, 2, -2, 6, -12, -25, -15, 10, + 9, 8, 11, 43, 8, -5, -22, -16, 14, -31, 16, 7, -7, -26, -20, -2, + 9, 11, 26, 7, 6, -20, -13, 0, 4, 17, -17, -18, 10, 2, -10, 27, + -8, 24, -23, -14, 1, 0, 13, -19, 14, 10, -16, 16, -4, -20, 20, -33, + 2, 2, 24, 21, -3, -26, -24, -18, -18, 10, 10, 24, 18, 2, 9, -24, + 16, -14, -8, 9, -5, -14, 8, -5, 30, -11, 11, -13, -15, -12, 7, 4, + -13, -13, 13, -13, 12, 23, 9, 0, 14, -10, -9, -35, -2, -21, 12, -1, + 17, 19, 11, -4, 0, -18, -24, 11, -10, 1, 11, 12, -13, -16, 10, -23, + 21, 9, -9, 3, 12, -6, 3, -5, 12, 0, -2, 0, -19, -9, 5, -11, + -7, 10, 1, -3, 9, 18, -6, 0, -1, 1, -13, 2, 1, -3, -8, 17, + -4, -9, 18, -15, 8, -1, -11, -5, -14, 11, -5, -7, 12, 16, -7, 7, + -3, -11, -5, -6, 1, 4, -3, -3, 15, 5, 0, 3, 6, -16, 4, -14, + -6, -9, -4, 2, 11, 11, 7, -2, 4, -12, -7, -14, -6, -7, 9, 4, + 7, -2, 6, 5, 6, -4, -3, -4, 7, -7, -11, -9, 0, -3, 7, -2, + -2, 3, 13, -4, -6, -15, 9, -7, -1, 4, 6, 5, 8, -6, -8, 0, + -11, -4, 6, -8, 4, 3, 5, 13, -4, -9, -3, 4, -3, -3, 4, -1, + -12, 6, -14, 2, 3, 15, 2, 6, -7, -8, 3, 1, -2, 3, -3, -12, + -6, -14, 7, -2, 13, 6, 10, 6, 0, -2, -10, -12, -8, -6, -7, -6, + 6, 4, -2, 5, 2, 0, -1, 3, -11, 4, 0, 20, -8, -2, 0, -1, + -3, 7, -3, -4, -2, -6, -10, -10, -8, 1, 2, 5, 8, 2, 5, 8, + 3, 4, 3, -2, -15, 0, -1, -7, -2, -5, -10, 10, -1, 5, 3, 5, + -1, -2, -8, -5, -9, 1, -8, 6, 5, 4, 1, 1, 2, 3, -2, 4, + -7, 1, -7, -9, -2, 0, 2, 3, 6, -8, 8, 3, 0, -2, -9, -3, + -2, 0, 3, -1, -2, -3, 7, -3, 10, -8, 1, -12, 3, -7, 2, -3, + 7, 4, 4, 0, 0, -6, -1, -5, -3, -4, -7, 0, 5, 7, 0, 2, + -3, 10, -1, 3, -7, -5, -4, -9, -3, -7, 5, -4, 9, 2, 1, 4, + 5, 0, -5, 1, -8, 4, -9, 5, -5, 0, 3, -2, -1, 1, 1, -7, + 7, 0, 3, -5, 0, -3, -1, -1, -5, -1, 1, -1, 1, -1, 0, 2, + 0, 2, -7, -7, 4, -1, 0, 3, 4, -1, -3, -4, -6, 3, -2, 4, + -1, 5, -2, -1, -5, -2, -4, 1, 3, 2, 2, 0, -3, 1, 1, -3, + -3, -1, 1, -3, -2, -1, -2, -3, -1, 0, 4, 3, 5, 2, 1, -4, + -9, -3, -7, 1, -2, 7, -2, 3, 3, 3, 1, 0, -1, -6, -7, -6, + -4, -1, 1, 0, 5, 2, -2, 2, -3, -1, 3, -1, 1, -4, -4, -5, + 0, -7, 2, -4, 3, 4, 1, 2, -1, -1, -2, -2, 0, -1, 1, -1, + -1, -3, 1, 1, 3, -3, -1, 1, 1, -2, -3, -8, -5, 0, -1, 5, + 2, 3, 1, -2, -1, -1, -3, 1, 1, -2, -3, -3, -1, 0, -1, 1, + 2, 2, 5, 0, -1, -2, -1, -2, 0, -4, 0, -5, -1, -1, 0, 1, + 5, 4, -2, -1, -2, 0, -6, -1, 0, 1, -1, -2, 1, 0, 0, 3, + 1, -2, 1, -2, -4, -1, 0, -1, -1, -4, -2, -4, 2, -1, 1, 0, + 3, 2, 0, 4, -1, 4, -6, 2, -4, -3, -5, -4, -3, 0, 2, 0, + 1, 4, 2, 2, -2, -2, -5, -6, -5, -3, -2, 1, -1, 0, 0, 2, + 2, 2, 0, 4, -2, 3, 2, -1, -2, -3, -3, -3, -5, -5, -5, -1, + -1, 0, 2, 2, 4, 1, 2, 1, 2, -1, -1, -3, -4, -5, -3, -2, + -2, -1, 1, 4, 2, 2, 2, 1, -1, -2, -6, -2, -3, 2, -1, 1, + -2, 0, 2, 1, 2, -2, 1, 0, -2, -2, -3, 0, -2, -1, -1, 0, + -2, -2, 1, 0, 2, -1, 1, -1, 0, -1, -1, -7, 8, -1, 5, -7, + 13, -22, 8, -7, 8, -110, -28, 24, 54, 36, 2, 60, -45, 57, 42, -43, + 20, 41, -66, 24, -11, 18, -18, -38, -63, -36, 30, -11, 33, 25, 30, 18, + 11, -18, -5, 5, -46, 40, 1, -13, -18, -20, -31, 20, 10, 29, -7, -18, + 40, -29, -17, 42, -19, 6, -4, 6, -8, 10, -26, -5, 3, 1, -17, 6, + 0, 19, -1, 8, 0, -6, -10, -1, -12, -1, 1, -3, 8, -7, 4, 11, + 4, 14, -13, 16, -19, -4, -13, -13, -14, 6, 4, -1, 4, 11, -1, 11, + -1, 1, -4, -1, -15, 6, -9, 1, -1, 0, 3, 1, -8, 3, -1, -1, + 2, -2, 2, -2, 1, -5, -7, 3, -3, 6, -3, 4, -1, 0, -4, 2, + -7, 3, -6, -1, -1, 4, 0, 3, -2, 2, -5, 5, -8, -3, -3, 2, + -5, 7, -1, 4, -2, 4, -10, 6, -6, -1, -4, 5, -13, 7, -6, 5, + -8, 17, -20, 14, -6, 9, -40, 71, -127, 9, -73, 127, 76, -28, 74, -32, + 8, -62, -49, -38, 40, -68, 22, -12, 68, 10, 39, -10, 0, 35, -23, 0, + -59, -15, -7, -3, -23, 1, -20, 37, 27, 2, 30, -2, 17, 2, -5, -7, + -27, -29, 16, -3, -11, 1, -16, -5, -8, -10, 7, 32, 9, 5, -4, 16, + 5, -8, -17, -16, 5, -13, 8, 11, 15, -10, -9, 0, -1, 2, 7, -3, + -23, 9, 2, 3, 1, -13, -1, -6, 11, -6, 8, 1, 12, -12, 9, -14, + 8, -1, 0, -3, -13, 4, -7, -4, 8, 5, -5, -7, 4, -2, -3, 2, + 3, -6, 8, -3, 1, -3, -2, 2, -6, 2, -4, -3, -4, 3, 1, 0, + 0, 1, -1, -1, 2, -2, 0, -4, -2, 1, 2, 0, -3, 1, -3, 0, + -1, -3, -6, 2, -2, 3, -4, 10, -8, 9, -5, 12, -19, 46, 37, -128, + 60, -90, 102, -65, 40, -57, 39, -6, 23, -8, 19, 24, 15, -17, -47, -27, + -36, -16, 21, 3, 23, 14, 50, -8, 19, 25, 7, -9, -28, -63, -37, 0, + -42, 54, -17, 68, -3, 30, -12, -4, 11, -15, 9, -25, -15, -2, -27, -25, + 38, -8, -13, 33, 24, 12, -38, 39, -12, -3, -17, -44, 38, 2, 27, 3, + -5, -4, -13, -30, -56, -4, 11, 1, 9, 17, 46, 25, -14, 6, -3, -7, + -21, 2, 16, -5, -22, 2, -2, 6, -12, -25, -15, 10, 9, 8, 11, 43, + 8, -5, -22, -16, 14, -31, 16, 7, -7, -26, -20, -2, 9, 11, 26, 7, + 6, -20, -13, 0, 4, 17, -17, -18, 10, 2, -10, 27, -8, 24, -23, -14, + 1, 0, 13, -19, 14, 10, -16, 16, -4, -20, 20, -33, 2, 2, 24, 21, + -3, -26, -24, -18, -18, 10, 10, 24, 18, 2, 9, -24, 16, -14, -8, 9, + -5, -14, 8, -5, 30, -11, 11, -13, -15, -12, 7, 4, -13, -13, 13, -13, + 12, 23, 9, 0, 14, -10, -9, -35, -2, -21, 12, -1, 17, 19, 11, -4, + 0, -18, -24, 11, -10, 1, 11, 12, -13, -16, 10, -23, 21, 9, -9, 3, + 12, -6, 3, -5, 12, 0, -2, 0, -19, -9, 5, -11, -7, 10, 1, -3, + 9, 18, -6, 0, -1, 1, -13, 2, 1, -3, -8, 17, -4, -9, 18, -15, + 8, -1, -11, -5, -14, 11, -5, -7, 12, 16, -7, 7, -3, -11, -5, -6, + 1, 4, -3, -3, 15, 5, 0, 3, 6, -16, 4, -14, -6, -9, -4, 2, + 11, 11, 7, -2, 4, -12, -7, -14, -6, -7, 9, 4, 7, -2, 6, 5, + 6, -4, -3, -4, 7, -7, -11, -9, 0, -3, 7, -2, -2, 3, 13, -4, + -6, -15, 9, -7, -1, 4, 6, 5, 8, -6, -8, 0, -11, -4, 6, -8, + 4, 3, 5, 13, -4, -9, -3, 4, -3, -3, 4, -1, -12, 6, -14, 2, + 3, 15, 2, 6, -7, -8, 3, 1, -2, 3, -3, -12, -6, -14, 7, -2, + 13, 6, 10, 6, 0, -2, -10, -12, -8, -6, -7, -6, 6, 4, -2, 5, + 2, 0, -1, 3, -11, 4, 0, 20, -8, -2, 0, -1, -3, 7, -3, -4, + -2, -6, -10, -10, -8, 1, 2, 5, 8, 2, 5, 8, 3, 4, 3, -2, + -15, 0, -1, -7, -2, -5, -10, 10, -1, 5, 3, 5, -1, -2, -8, -5, + -9, 1, -8, 6, 5, 4, 1, 1, 2, 3, -2, 4, -7, 1, -7, -9, + -2, 0, 2, 3, 6, -8, 8, 3, 0, -2, -9, -3, -2, 0, 3, -1, + -2, -3, 7, -3, 10, -8, 1, -12, 3, -7, 2, -3, 7, 4, 4, 0, + 0, -6, -1, -5, -3, -4, -7, 0, 5, 7, 0, 2, -3, 10, -1, 3, + -7, -5, -4, -9, -3, -7, 5, -4, 9, 2, 1, 4, 5, 0, -5, 1, + -8, 4, -9, 5, -5, 0, 3, -2, -1, 1, 1, -7, 7, 0, 3, -5, + 0, -3, -1, -1, -5, -1, 1, -1, 1, -1, 0, 2, 0, 2, -7, -7, + 4, -1, 0, 3, 4, -1, -3, -4, -6, 3, -2, 4, -1, 5, -2, -1, + -5, -2, -4, 1, 3, 2, 2, 0, -3, 1, 1, -3, -3, -1, 1, -3, + -2, -1, -2, -3, -1, 0, 4, 3, 5, 2, 1, -4, -9, -3, -7, 1, + -2, 7, -2, 3, 3, 3, 1, 0, -1, -6, -7, -6, -4, -1, 1, 0, + 5, 2, -2, 2, -3, -1, 3, -1, 1, -4, -4, -5, 0, -7, 2, -4, + 3, 4, 1, 2, -1, -1, -2, -2, 0, -1, 1, -1, -1, -3, 1, 1, + 3, -3, -1, 1, 1, -2, -3, -8, -5, 0, -1, 5, 2, 3, 1, -2, + -1, -1, -3, 1, 1, -2, -3, -3, -1, 0, -1, 1, 2, 2, 5, 0, + -1, -2, -1, -2, 0, -4, 0, -5, -1, -1, 0, 1, 5, 4, -2, -1, + -2, 0, -6, -1, 0, 1, -1, -2, 1, 0, 0, 3, 1, -2, 1, -2, + -4, -1, 0, -1, -1, -4, -2, -4, 2, -1, 1, 0, 3, 2, 0, 4, + -1, 4, -6, 2, -4, -3, -5, -4, -3, 0, 2, 0, 1, 4, 2, 2, + -2, -2, -5, -6, -5, -3, -2, 1, -1, 0, 0, 2, 2, 2, 0, 4, + -2, 3, 2, -1, -2, -3, -3, -3, -5, -5, -5, -1, -1, 0, 2, 2, + 4, 1, 2, 1, 2, -1, -1, -3, -4, -5, -3, -2, -2, -1, 1, 4, + 2, 2, 2, 1, -1, -2, -6, -2, -3, 2, -1, 1, -2, 0, 2, 1, + 2, -2, 1, 0, -2, -2, -3, 0, -2, -1, -1, 0, -2, -2, 1, 0, + 2, -1, 1, -1, 0, -1, -1, 1, -7, 5, -22, -32, -35, -32, -43, -35, + -55, -42, -66, -48, -80, -57, -17, -128, -59, -76, 0, -26, 1, -33, 21, 3, + 16, 15, 26, 43, 28, 66, 6, 97, 40, 103, 67, 101, 102, 98, 94, 21, + 98, 90, 57, 78, 89, 81, 61, -6, 54, 4, 62, 19, 27, 34, 12, 16, + 14, -17, 19, -5, -2, -13, -38, -24, -3, -33, -14, -11, -16, 0, -13, 7, + -26, -13, -16, 6, -57, -23, -28, -13, -9, -34, -32, -20, -87, -62, -28, -38, + -75, -37, -27, -41, -71, -48, -30, -44, -83, -67, -52, -48, -45, -46, -45, -63, + -47, -40, -32, -45, -24, -32, -43, -21, -17, 0, 21, 26, 43, 51, 62, 47, + 41, 55, 57, 68, 34, 53, 63, 62, 71, 60, 61, 56, 53, 56, 54, 38, + 50, 58, 50, 40, 28, 54, 39, 41, 38, 22, 32, 20, -3, 19, -1, -7, + -6, -16, -16, -14, -27, -29, -46, -66, -61, -51, -54, -61, -41, -50, -47, -52, + -55, -45, -44, -28, -58, -56, -31, -37, -36, -32, -18, -16, -34, -29, -9, -21, + -20, -30, -22, -17, -19, -8, -12, -14, -6, -14, -6, -11, -2, 4, -6, 9, + 8, 17, 23, 13, 31, 13, 24, 30, 28, 29, 30, 43, 34, 37, 52, 42, + 44, 50, 67, 59, 49, 54, 48, 43, 51, 45, 42, 62, 47, 39, 37, 36, + 24, 28, 13, 3, 9, -11, -3, -9, -14, -18, -34, -27, -29, -39, -42, -38, + -46, -37, -46, -43, -41, -35, -38, -31, -38, -34, -39, -39, -34, -48, -44, -47, + -49, -54, -52, -44, -53, -37, -47, -38, -31, -38, -27, -19, -19, -15, -16, 0, + 0, 2, 7, 13, 29, 22, 32, 32, 39, 47, 41, 40, 55, 48, 41, 44, + 57, 43, 36, 47, 43, 42, 37, 32, 32, 27, 33, 36, 30, 23, 25, 25, + 22, 18, 22, 20, 16, 8, 6, 12, 7, 0, 1, 3, -5, -14, -9, -7, + -8, -19, -15, -16, -23, -21, -21, -32, -31, -29, -26, -27, -29, -33, -26, -29, + -30, -39, -28, -41, -43, -35, -34, -32, -29, -28, -28, -25, -27, -24, -27, -27, + -27, -22, -23, -17, -9, -10, -14, -10, -8, -4, -2, -1, -3, 5, 4, 10, + 11, 7, 13, 11, 14, 27, 22, 22, 22, 27, 36, 34, 36, 37, 45, 44, + 47, 48, 51, 49, 52, 51, 52, 48, 50, 47, 48, 42, 40, 29, 33, 24, + 22, 12, 5, 0, -3, -5, -9, -21, -21, -25, -19, -28, -28, -30, -33, -39, + -42, -42, -46, -46, -45, -42, -43, -47, -47, -36, -32, -30, -34, -31, -22, -29, + -29, -30, -26, -28, -30, -21, -26, -27, -21, -19, -16, -11, -12, -8, -2, 1, + -4, 1, 0, 1, 9, 8, 7, 12, 10, 13, 20, 17, 18, 21, 26, 29, + 30, 30, 29, 34, 33, 34, 33, 30, 32, 33, 28, 33, 29, 35, 32, 31, + 30, 31, 30, 25, 27, 24, 21, 21, 20, 16, 17, 12, 6, 4, -3, 1, + -6, -7, -11, -13, -11, -10, -8, -13, -12, -9, -17, -14, -19, -24, -22, -24, + -30, -32, -30, -33, -37, -39, -40, -42, -39, -41, -39, -40, -41, -35, -35, -35, + -37, -36, -33, -30, -25, -25, -19, -16, -16, -10, -6, -7, -4, -2, 1, 3, + 6, 10, 9, 15, 17, 18, 17, 13, 19, 18, 17, 19, 20, 24, 24, 27, + 27, 29, 30, 26, 28, 28, 27, 28, 26, 25, 24, 25, 20, 19, 17, 18, + 15, 12, 13, 10, 6, 8, 6, 3, 4, 3, 0, -3, 0, -1, -2, -5, + -4, -5, -4, -5, -6, -8, -9, -9, -12, -11, -16, -16, -15, -15, -13, -17, + -16, -17, -17, -21, -20, -25, -24, -24, -24, -26, -30, -30, -27, -30, -26, -26, + -27, -27, -25, -24, -19, -20, -17, -13, -12, -8, -8, -8, -6, -5, -2, -1, + 0, 3, 8, 10, 12, 16, 18, 24, 25, 25, 28, 30, 28, 32, 33, 31, + 32, 31, 35, 33, 31, 31, 27, 28, 26, 23, 23, 20, 22, 18, 16, 13, + 11, 9, 5, 4, -2, -2, -3, -8, -9, -11, -12, -13, -15, -15, -15, -15, + -15, -14, -12, -12, -13, -13, -8, -11, -10, -12, -10, -12, -12, -8, -8, -9, + -9, -9, -8, -9, -10, -11, -11, -10, -13, -14, -13, -16, -16, -17, -17, -18, + -19, -18, -17, -16, -16, -15, -15, -13, -12, -10, -12, -10, -9, -8, -6, -6, + -3, 0, 0, 1, 2, 2, 3, 4, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 12, 13, 14, 14, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 15, 15, 14, 13, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, + 3, 2, 1, 0, -1, -1, -2, -3, -4, -5, -5, -6, -7, -7, -8, -9, + -9, -10, -11, -11, -12, -12, -13, -13, -13, -13, -14, -14, -14, -15, -15, -15, + -15, -15, -15, -16, -16, -16, -15, -15, -15, -14, -13, -13, -12, -11, -10, -9, + -8, -7, -6, -5, -4, -2, -1, 0, 1, 2, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, + 17, 17, 17, 17, 17, 17, 16, 16, 15, 15, 14, 14, 13, 12, 11, 10, + 9, 7, 6, 5, 3, 1, 0, -2, -4, -5, -7, -9, -10, -11, -13, -14, + -15, -15, -16, -17, -17, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, + -18, -17, -17, -16, -16, -15, -14, -14, -13, -12, -11, -10, -9, -8, -7, -6, + -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 10, + 11, 11, 12, 13, 13, 13, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 14, 14, 14, 13, 12, 12, 11, 10, 9, 8, 8, 7, + 6, 5, 4, 3, 2, 1, 0, 0, -1, 10, -20, 30, 25, 21, 14, 4, + 15, -48, -33, 11, -70, 54, -5, -21, -8, -3, 73, -52, 65, -55, 80, -28, + -67, -3, -13, 21, -49, -2, 11, 36, 59, -60, 34, -28, 21, -25, -45, 54, + 5, 0, -19, -12, 20, 54, -51, -23, 22, 36, -59, -20, 8, 28, -9, -54, + 127, -44, 69, -128, 5, 69, -8, -98, 45, 69, 20, -97, 23, -7, 121, -81, + -2, -21, 51, -67, -14, -24, 127, -60, 45, -116, 127, -29, -93, -23, 107, -5, + -21, -62, 37, 41, 29, -74, -63, 103, 24, -59, -44, 62, 43, -28, -46, 7, + 72, 19, -70, -47, 42, 53, -68, -13, 37, 59, -38, -60, 39, 66, 27, -128, + 36, 77, 15, -74, -15, 75, 38, -49, -11, -39, 16, -8, -30, 35, 41, -1, + -2, 17, -68, 99, -97, 60, -49, 32, -44, -29, 82, -26, 39, -35, 10, 38, + -20, -21, -92, 83, -24, 13, 31, -33, 22, 45, -31, -24, 9, -24, -32, 42, + -17, 34, 7, -27, 6, 61, -9, -34, -5, -8, -17, -6, -34, 17, 43, -9, + 35, -34, 16, 27, -24, -17, -17, 5, -17, 42, -31, 22, 17, -26, -22, 32, + 41, -27, -25, -10, -5, 16, -2, 13, -1, 48, -33, -27, 6, 16, 13, -37, + -11, 18, 25, -42, -11, 46, -7, -15, 9, 15, 4, -3, -36, -24, 31, -8, + 14, 12, 27, -19, -17, -14, -7, 42, -5, -15, 5, 1, -15, 14, 43, -19, + 1, -25, -35, 16, 16, 29, -12, 8, -14, 1, 21, -8, -12, -22, -4, 24, + 26, -16, -22, 37, 3, -41, 7, 4, 3, 30, 4, -27, 11, -6, -26, 33, + 23, -23, -14, -20, -7, -4, 36, 0, 18, 10, -27, 1, 1, 16, -1, -4, + -44, -5, 17, 9, 13, -4, -3, 31, 24, -14, -26, 9, -27, -28, 19, 22, + 32, -11, -15, 5, 15, -23, -21, 16, 14, 18, -11, -26, 13, 10, -12, -12, + 11, 14, -6, -13, -3, 6, -6, 3, 12, 32, 14, -22, -45, -10, 37, 11, + -50, -11, 50, 22, -13, -4, -4, 15, -16, -33, 7, 34, -9, -14, -1, 21, + 15, -14, -12, -6, 7, 8, 2, 0, -5, 6, 15, 4, -9, 13, 3, -51, + -18, 27, 10, 5, -11, 6, -1, 5, 22, 2, -14, -39, -12, 19, 17, 4, + 11, 5, -25, 2, 23, 8, 2, -3, -39, -22, 4, 18, 6, 14, 25, 20, + -17, -20, 17, 7, -43, -38, -18, 17, 24, -6, 30, 44, 6, -36, -20, 7, + 24, 1, -69, -25, 47, 15, -4, 35, 19, -18, -22, -12, 20, 39, -36, -49, + 9, 28, -16, 9, 34, 36, -22, -69, -16, 39, 7, -28, -3, 33, -18, -7, + 18, 53, 24, -37, -61, -10, 38, 2, -24, -11, 12, 17, 0, 28, 50, -5, + -59, -57, 22, 14, -15, -5, 22, 9, -20, 19, 33, 31, -33, -62, -13, -2, + 45, -9, -4, -3, 19, 8, -8, 40, 8, -16, -44, -19, 16, 3, 23, -32, + 22, 5, -9, 5, 26, 21, -27, -18, -45, 3, 15, 0, 7, 7, 7, 13, + 18, -10, 3, -5, -30, -30, -3, 9, 31, 17, -10, 19, 28, -33, -20, 31, + 14, -67, -27, 13, 20, 29, 1, -2, 24, -3, -26, -12, 32, -7, -31, -17, + 5, 22, 11, -6, 6, 7, 2, 7, 5, -12, -22, -17, -24, 22, 47, 1, + 2, 10, 5, -29, -5, 13, 1, -30, -28, -5, 23, 25, 6, 5, 1, 7, + 0, 5, 3, -33, -37, -6, 19, 20, 26, -1, -15, 21, 9, -14, -13, 0, + -11, -24, -9, 9, 23, 1, 1, 32, 11, -25, -18, 5, -5, -6, -9, -10, + 2, 18, 4, 12, 6, -2, -8, 2, 2, -7, 2, -22, -5, 17, 25, 15, + -5, -1, -24, -8, -10, -5, 12, 7, -4, -10, 4, 8, 22, 11, -1, -12, + -31, -17, 6, 12, 11, 5, -3, -1, 22, 0, -4, 3, -18, -17, -3, 16, + 9, 2, -5, 0, 4, -9, 18, 17, -22, -19, -8, -6, 21, 11, -6, -16, + 33, 13, -15, -3, -15, 1, -3, -10, -7, 8, 17, -11, 9, 19, 0, 5, + 0, -18, -13, 2, -20, 10, 29, -11, -13, 5, 11, 16, 4, -25, -21, 13, + -5, 1, 3, -1, 6, 13, -7, -1, 17, -6, -6, -9, -6, -3, -1, 1, + 18, 11, -22, 2, 18, -2, -15, 1, 5, -12, -10, -7, 9, 26, 10, -11, + 5, 0, -7, -3, -11, -9, -3, 2, -10, 19, 28, -3, -3, -4, 9, -14, + -5, -7, 8, -3, -27, 5, 37, 11, -2, 3, -27, -15, 12, -2, 14, 2, + -8, -16, 22, 11, -1, 10, -17, -8, -5, -23, 2, 29, 8, -21, 8, 12, + 6, 8, -17, 3, -2, -12, -27, 16, 25, -5, -7, 2, 19, 1, -15, 7, + 2, -5, -34, 2, 18, 17, -10, 2, 18, -1, -12, -10, 5, 1, -16, -9, + 12, 21, 4, -10, 2, 12, 1, -19, -11, 20, 5, -14, -21, 5, 17, -5, + 3, 17, 4, -25, -5, 5, 4, 0, -5, 2, 2, -1, 1, 13, 0, -11, + -8, 3, 2, -1, -3, -3, 11, 8, -6, 2, 7, 4, -5, -23, -2, 14, + -1, -15, -2, 15, 10, 1, -4, 16, 1, -24, -12, 8, 8, -20, -2, 14, + 13, 10, 2, 2, -9, -6, -9, -3, 5, 7, -3, -9, 0, 2, 8, 3, + -1, 2, -4, 0, -2, 0, -2, 3, 5, -4, -28, 22, -43, 36, -13, -127, + -43, 2, -18, 126, 78, -127, -48, 68, -74, -67, 33, 62, 83, 42, -32, -46, + -70, -26, 115, 21, -66, 72, 52, -27, 44, 50, 50, 61, 28, -12, 3, -59, + 49, 3, -19, 39, 94, 16, 31, 6, 29, 3, -100, -1, -4, -60, 19, 7, + -29, -28, -38, -3, -47, -20, -21, -1, 5, -55, -12, -55, -39, 26, 47, -22, + -9, -41, -21, -19, -37, 0, 45, -56, 24, 75, -50, -9, 31, 28, 26, 13, + -3, -15, -27, 1, 1, -31, -10, 38, -1, 7, 43, 19, 21, 41, 33, 9, + -17, -3, -42, -76, -30, -8, -9, -1, 21, 22, 38, 32, 22, 0, -18, -32, + -58, -12, 5, -48, -13, 64, 29, -2, 2, 19, 43, 25, -19, -39, -69, -92, + -15, 23, 30, 30, 51, 37, 35, 37, 30, -27, -63, 5, -30, -56, -16, 26, + 52, 20, 14, 59, 27, -9, 22, -4, -20, -37, -17, -34, -34, -1, 35, 26, + 31, 5, -16, 4, 33, 22, 8, 5, -28, -41, -20, -10, -6, -2, -16, 12, + 31, -23, 7, -2, -39, -28, -13, 8, 5, 16, -4, -6, -18, -24, -27, -50, + -6, 5, 12, 0, -2, -14, -23, 5, -28, -10, 2, 28, 15, 2, 22, 27, + 41, 31, 2, 12, 31, 5, 12, -6, 15, 40, 34, 18, 26, 26, 12, 34, + 23, 34, 30, 22, 10, -26, -22, 1, 0, -1, 12, -4, -21, -5, -5, -20, + -31, -25, -24, -42, -44, -41, -41, -37, -29, -28, -29, -40, -17, -21, -38, -42, + -38, -40, -36, -13, -14, -8, -15, -7, -6, 5, 12, -1, -17, -1, 9, 2, + 16, 30, 27, 37, 36, 38, 36, 36, 19, 45, 45, 33, 26, 33, 28, 36, + 31, 17, 12, 22, 11, 11, 17, 5, -13, 6, 10, 2, -6, 2, 9, 15, + -6, -8, -23, -44, -3, -11, -35, -25, -35, -23, -21, 0, -11, -21, -17, 11, + -6, -11, -17, -33, -16, -16, -4, -7, -7, -9, -4, 1, 1, -3, 6, 7, + 4, -17, -11, -6, -4, 1, 3, 6, 4, 5, -4, 17, 7, 3, 9, -20, + 0, -7, -3, -5, 4, 9, 16, 2, 3, 8, 15, 15, 1, -3, 8, -1, + 5, 14, 7, 4, 8, -8, 2, -3, 5, 11, 5, 3, -4, 10, 17, 13, + -11, -5, 1, -3, 0, -6, -12, 2, -3, 13, -5, -25, -15, -7, 4, 1, + -8, -4, -12, -16, 3, 9, -6, 3, -21, -4, 4, -14, 1, -1, -2, 3, + -8, -5, 0, 7, -2, -3, -1, 3, -9, 5, -4, -17, -1, 9, 3, 7, + 1, -4, -3, 5, 2, -7, -9, 12, -6, -14, -16, 2, -1, 16, 2, 2, + 7, -6, -26, 3, -2, -4, -2, 10, 3, -7, 3, 8, 9, 5, 4, 1, + -5, -5, 11, 8, 7, 11, 12, -1, -5, -16, 13, 7, 2, 11, 4, -4, + 9, -8, -8, 14, 11, -8, 0, -1, -5, -2, -1, -10, -5, -9, -9, -16, + -12, -8, -16, 5, -10, -4, -11, -3, 1, 0, -3, -5, -13, -9, -2, -8, + 5, -9, -7, -2, 2, -11, -7, 13, 8, -3, 2, 7, -2, -1, 5, 0, + 11, 6, 13, 15, 1, -4, 9, 5, 3, 8, -3, -4, 16, 4, 11, 9, + 0, 8, 1, -6, -5, -18, 3, 7, -18, -4, 0, -3, -3, -6, -4, -5, + -5, -10, -2, -9, -5, -2, -4, -11, -2, 1, -5, -2, 11, -6, -9, 1, + 4, -6, -1, -5, 1, 2, 9, 5, 0, 4, 4, -2, 7, 0, -10, 5, + 2, -3, 0, -6, 7, -4, -3, 6, -1, -6, -1, -1, 2, -2, -6, -3, + 0, 8, -6, 4, -1, -5, -3, 3, 1, -5, -6, -2, -3, 5, 6, 0, + 7, -3, 3, -1, 0, -2, 9, 1, 1, -3, 4, 5, -5, 2, -2, 2, + -11, -2, -4, 11, 4, 5, 0, -5, -12, -6, -5, -5, 3, -2, -2, 2, + 2, 1, 0, -1, -8, -5, -5, -3, 2, -1, 3, -1, 3, 0, -1, 0, + -1, 1, 1, -4, -4, 2, -2, 1, -6, 1, 2, 4, 2, 2, -5, -1, + 6, -3, -1, -4, 11, 3, -9, -2, -6, -3, 2, 4, 2, 1, 2, 4, + 3, -6, -4, -3, -2, 0, 2, -2, 5, 2, -1, 3, -9, -3, -3, -4, + -4, -1, 0, -2, 7, 3, 1, 1, -2, -4, -2, -3, -2, -4, 2, 4, + -1, 2, 3, 0, 3, -1, 0, -2, -2, -3, 1, -1, -4, 5, -1, 5, + 0, -3, -2, -1, -4, 3, -1, -3, -2, -2, -1, 0, 0, 1, -1, 0, + -2, -2, 0, -3, -1, 0, 0, 1, 1, -2, -1, 1, -3, 1, 2, 0, + -1, 0, -1, 1, 5, -2, 1, -3, -3, -1, -3, 0, 1, 3, 2, -1, + -1, -2, -2, -1, 1, 30, -9, -44, 13, 26, -53, -41, 2, 76, 47, 40, + -52, -53, -5, 12, -33, 15, 62, 53, -27, -98, -26, -42, 52, 75, 43, -32, + -3, -83, -13, -36, 35, 39, 56, 25, -9, -122, -22, -3, 79, -6, 6, 25, + -20, -12, -40, -19, 15, 74, 37, -14, -33, 6, 25, 7, -10, -4, 42, 4, + -33, -87, -55, 29, 39, 21, -34, -27, 1, 26, 5, -22, -13, 10, 56, 0, + -26, -40, 30, 42, 23, -7, -23, 28, 21, 9, -37, -25, 11, 25, 8, -48, + -19, -15, 41, -2, -30, -28, 4, 30, -12, -23, -28, 17, 38, 3, -12, -8, + 17, 26, 9, -32, 0, 12, 49, -3, -29, -17, 2, 41, -17, -24, -17, 9, + 30, -23, -22, -21, 19, 17, -12, -35, -18, 12, 29, 2, -27, 7, 14, 42, + -11, -24, -3, 15, 40, -23, -24, -17, 21, 22, -10, -23, -10, 23, 13, -4, + -37, 0, 15, 19, -12, -40, -2, 13, 30, -16, -22, -3, 22, 22, -13, -16, + -7, 34, 9, -5, -34, -5, 29, 10, -3, -39, 3, 17, 14, -13, -25, 5, + 21, 12, -18, -22, -8, 31, 8, -5, -27, -9, 30, 1, -3, -30, 6, 27, + 4, -14, -31, 8, 25, 10, -14, -21, -3, 24, 4, -11, -17, -1, 30, -1, + -12, -26, 3, 32, 3, -13, -26, 5, 23, 3, -14, -17, 6, 22, 1, -17, + -16, 4, 25, 4, -18, -19, 4, 23, 5, -17, -14, 5, 21, 1, -20, -11, + 7, 23, 2, -19, -17, 8, 19, 6, -18, -15, 10, 14, 6, -26, -5, 11, + 15, 4, -27, -5, 4, 22, 1, -17, -12, 6, 15, 1, -16, -13, 20, 8, + 4, -28, -7, 17, 9, 10, -31, 3, 1, 13, 0, -18, 0, 6, 17, -10, + -14, -15, 21, 10, 3, -19, -14, 22, -4, 11, -27, 8, 9, 7, -2, -26, + 8, 2, 23, -13, -7, -13, 12, 11, -11, -2, -15, 27, -8, 2, -22, 0, + 18, 0, 6, -27, 10, -4, 19, -13, -7, 1, 2, 19, -26, 7, -17, 28, + -2, -8, -6, -11, 23, -9, 10, -24, 12, -2, 10, -8, -14, 13, -5, 25, + -33, 7, -11, 17, 8, -19, 9, -18, 26, -17, 6, -12, 8, 8, -5, 0, + -23, 20, -10, 25, -24, 2, 0, -2, 17, -30, 22, -16, 25, -15, -7, -2, + -4, 21, -15, 13, -25, 19, -11, 9, -8, -7, 19, -15, 20, -34, 17, -9, + 15, 0, -15, 11, -17, 24, -24, 16, -15, 15, 0, -11, 6, -21, 30, -18, + 18, -22, 6, 3, -6, 10, -20, 23, -17, 20, -23, 7, -3, 2, 16, -24, + 18, -26, 27, -15, 5, -2, -5, 19, -21, 12, -22, 22, -9, 9, -11, -5, + 11, -13, 21, -27, 22, -17, 13, -5, -13, 14, -14, 28, -24, 9, -16, 12, + 3, -7, 5, -14, 22, -20, 14, -21, 14, 3, -2, 6, -26, 20, -17, 23, + -17, 3, 0, -2, 11, -23, 14, -14, 26, -14, 0, -10, -3, 18, -14, 15, + -24, 19, -9, 4, -8, -9, 18, -6, 15, -29, 11, -10, 16, -1, -11, 9, + -13, 23, -23, 8, -13, 12, 10, -11, 0, -20, 22, -7, 12, -19, 4, 4, + 1, 4, -23, 18, -10, 22, -17, -7, 0, -1, 23, -20, 6, -18, 18, 0, + -3, -8, -5, 20, -8, 6, -27, 14, 2, 11, -5, -20, 13, -10, 24, -22, + 3, -5, 11, 8, -20, 1, -12, 28, -7, 0, -19, 2, 15, -5, 6, -25, + 20, -4, 13, -19, -10, 10, 5, 17, -27, 1, -10, 22, -2, -10, -2, -7, + 26, -18, 4, -24, 18, 10, 1, -8, -23, 16, 2, 15, -22, -1, 3, 10, + 5, -27, 9, -8, 35, -19, -3, -18, 7, 19, -7, -3, -16, 14, 6, -5, + -9, -12, 23, -5, 11, -33, 19, -10, 23, -22, 3, -5, 14, -2, -8, -8, + 7, 7, 2, -14, 0, -2, 17, -14, 3, -17, 20, -5, 7, -19, 3, 3, + 10, -5, -9, -4, 6, 6, -2, -10, 1, 2, 12, -13, 0, -11, 18, -3, + 3, -16, 2, 4, 7, -5, -6, 0, 6, 1, -6, -6, 4, 6, 5, -11, + -2, -4, 12, -6, 1, -9, 9, 0, 1, -11, 0, 6, 5, -2, -11, 1, + 2, 7, -5, -7, 3, 1, 8, -13, 0, -6, 15, -3, -2, -11, 1, 9, + 1, -2, -12, 6, 2, 5, -9, -5, 3, 6, 5, -12, -3, -3, 12, 0, + -5, -7, 0, 8, -2, -2, -9, 7, 3, 5, -11, -4, 0, 9, 2, -7, + -6, 0, 7, 1, -6, -3, 1, 8, -4, -5, -7, 7, 4, 4, -11, -1, + -2, 10, -5, -1, -7, 8, 1, 1, -12, 1, 4, 7, -4, -8, -4, 8, + 0, 3, -16, 11, -7, 1, 0, 0, -1, -1, -4, 1, -1, -3, -13, -8, + -14, -3, -2, -2, 1, 8, 5, 7, -21, -13, -2, -6, -8, -22, -6, 5, + 11, 34, 41, 33, 13, 28, 33, 48, 35, 21, -3, -26, -18, -10, 3, 7, + 22, 21, 63, 40, 41, 43, 4, -8, -43, -63, -77, -77, -59, -18, 3, 2, + -21, -46, -74, -90, -108, -101, -94, -89, -84, -85, -77, -59, -50, -33, -7, 18, + 37, 47, 64, 101, 127, 125, 127, 126, 126, 126, 122, 100, 87, 62, 37, 28, + 27, 25, 27, 34, 25, -4, -45, -85, -123, -128, -126, -128, -127, -123, -92, -73, + -55, -45, -37, -33, -32, -33, -43, -53, -55, -43, -20, 3, 20, 34, 42, 49, + 55, 63, 74, 84, 93, 101, 107, 112, 117, 109, 92, 63, 33, 8, -13, -25, + -29, -30, -27, -27, -32, -46, -63, -82, -98, -109, -116, -121, -118, -104, -80, -49, + -12, 21, 45, 58, 64, 66, 66, 61, 51, 44, 37, 32, 32, 33, 33, 28, + 23, 15, 8, 3, 2, 9, 16, 20, 24, 23, 14, -1, -20, -37, -48, -53, + -52, -47, -38, -26, -13, -5, -1, -4, -10, -22, -34, -43, -48, -46, -34, -16, + 5, 25, 45, 65, 78, 84, 83, 71, 55, 39, 24, 9, -3, -12, -23, -34, + -45, -57, -65, -71, -71, -63, -49, -34, -21, -11, -2, 2, 8, 11, 12, 14, + 14, 20, 28, 38, 50, 58, 63, 61, 56, 46, 33, 17, -1, -19, -34, -45, + -48, -44, -32, -19, -5, 5, 7, 4, -2, -7, -11, -15, -18, -21, -23, -26, + -28, -30, -31, -29, -26, -20, -12, -1, 11, 21, 32, 42, 51, 55, 55, 52, + 46, 41, 37, 32, 30, 28, 27, 24, 19, 12, -1, -21, -45, -67, -89, -103, + -107, -101, -90, -70, -51, -33, -18, -2, 11, 23, 33, 39, 44, 49, 52, 57, + 59, 59, 56, 52, 48, 41, 35, 28, 20, 15, 11, 4, 0, -5, -11, -18, + -25, -34, -42, -47, -48, -46, -40, -33, -27, -24, -21, -24, -32, -42, -51, -56, + -58, -56, -47, -35, -18, 2, 24, 48, 70, 88, 99, 104, 102, 97, 89, 79, + 69, 59, 49, 37, 27, 14, 0, -14, -29, -44, -58, -71, -81, -87, -88, -88, + -85, -81, -77, -72, -63, -51, -37, -21, -5, 12, 29, 43, 53, 59, 61, 57, + 48, 36, 24, 13, 8, 8, 15, 25, 38, 48, 54, 54, 50, 43, 33, 22, + 11, 3, -6, -15, -25, -35, -46, -54, -61, -65, -68, -69, -69, -68, -64, -59, + -52, -43, -32, -20, -7, 6, 19, 31, 42, 51, 58, 62, 64, 62, 58, 52, + 44, 35, 26, 17, 9, 1, -5, -10, -15, -18, -19, -20, -19, -18, -16, -15, + -14, -14, -15, -16, -17, -18, -19, -19, -19, -19, -18, -16, -14, -11, -9, -6, + -3, 0, 3, 6, 10, 14, 18, 22, 27, 32, 35, 37, 37, 35, 30, 23, + 14, 4, -6, -15, -24, -31, -36, -39, -40, -39, -37, -32, -26, -19, -10, -1, + 8, 17, 24, 29, 32, 33, 32, 29, 25, 20, 15, 11, 7, 3, -1, -5, + -9, -14, -19, -24, -28, -31, -32, -31, -27, -23, -16, -10, -3, 2, 7, 10, + 12, 13, 13, 13, 12, 10, 8, 7, 5, 5, 5, 5, 6, 8, 10, 13, + 17, 20, 23, 25, 26, 25, 21, 16, 9, 1, -7, -16, -24, -31, -37, -42, + -47, -49, -51, -52, -51, -48, -43, -37, -30, -20, -7, 6, 19, 0, -4, 10, + 10, 11, -15, 4, -1, 3, -11, 11, 2, -12, 3, 18, -10, -62, 89, -16, + -95, 118, -128, 122, -128, 112, -100, 109, -121, 120, -104, 58, 10, -88, 127, -102, + 6, 98, -126, 35, 89, -111, -7, 112, -53, -94, 92, 64, -106, -53, 109, 52, + -100, -75, 86, 95, -45, -119, -12, 111, 74, -58, -118, -27, 97, 100, -4, -107, + -95, 17, 109, 92, -4, -99, -109, -26, 78, 115, 66, -27, -104, -109, -41, 55, + 112, 98, 32, -53, -109, -105, -44, 41, 102, 109, 67, -4, -74, -112, -102, -47, + 27, 88, 112, 93, 45, -19, -78, -110, -105, -65, -4, 59, 101, 110, 87, 43, + -13, -67, -103, -111, -89, -44, 13, 65, 100, 109, 93, 59, 14, -36, -78, -104, + -108, -90, -53, -6, 43, 83, 104, 106, 88, 57, 17, -27, -66, -95, -108, -102, + -80, -44, -2, 41, 77, 99, 106, 98, 77, 46, 10, -29, -64, -91, -105, -105, + -91, -64, -29, 10, 48, 78, 98, 105, 100, 84, 59, 30, -3, -36, -65, -88, + -101, -105, -99, -83, -60, -32, -1, 30, 58, 80, 96, 103, 102, 94, 80, 62, + 40, 16, -10, -35, -58, -78, -92, -101, -104, -100, -91, -77, -58, -36, -13, 12, + 36, 57, 75, 89, 98, 102, 102, 97, 88, 76, 61, 44, 25, 5, -15, -35, + -54, -70, -84, -94, -101, -104, -103, -98, -89, -77, -63, -46, -27, -8, 12, 31, + 49, 65, 79, 90, 97, 102, 104, 102, 97, 90, 81, 70, 57, 42, 27, 10, + -7, -24, -40, -56, -70, -81, -91, -99, -103, -105, -105, -101, -95, -87, -76, -63, + -49, -34, -18, -1, 16, 32, 48, 62, 74, 85, 93, 100, 104, 105, 105, 102, + 97, 90, 82, 72, 61, 48, 35, 21, 6, -9, -24, -38, -52, -65, -76, -86, + -94, -101, -105, -108, -108, -106, -102, -96, -87, -78, -66, -54, -40, -26, -11, 4, + 19, 34, 48, 61, 73, 83, 92, 99, 104, 107, 108, 108, 105, 101, 96, 89, + 80, 70, 60, 48, 36, 22, 9, -5, -19, -33, -46, -58, -69, -80, -89, -96, + -102, -107, -109, -110, -110, -107, -102, -97, -89, -80, -70, -59, -47, -33, -20, -6, + 7, 19, 30, 41, 50, 58, 65, 71, 75, 78, 79, 80, 79, 77, 74, 70, + 65, 60, 54, 48, 42, 36, 29, 22, 16, 10, 4, -2, -7, -12, -16, -19, + -22, -24, -26, -27, -27, -27, -26, -25, -23, -22, -19, -17, -14, -12, -10, 0, + -5, -2, -5, 2, -29, 22, 0, -27, 67, -59, 45, -13, -37, 28, 65, -4, + 6, 60, 5, 58, 44, 60, 27, 43, 96, 71, 81, 48, 96, 70, 23, 90, + 66, 80, 88, 40, 20, 61, 64, 12, 36, 24, 4, 7, 5, -27, -38, -26, + -33, -49, -50, -70, -69, -93, -92, -94, -104, -104, -101, -110, -107, -111, -111, -126, + -87, -119, -100, -94, -112, -93, -93, -80, -81, -76, -58, -56, -70, -30, -21, -42, + -13, -3, 2, 8, 20, 28, 41, 45, 59, 62, 69, 84, 85, 90, 103, 109, + 111, 118, 121, 121, 123, 121, 122, 121, 122, 121, 122, 121, 121, 120, 121, 120, + 121, 120, 121, 120, 120, 119, 120, 119, 120, 118, 105, 106, 110, 83, 89, 92, + 75, 67, 61, 57, 47, 40, 33, 24, 17, 10, 3, -2, -10, -20, -31, -31, + -37, -49, -50, -63, -66, -69, -74, -79, -91, -89, -92, -95, -102, -106, -104, -107, + -113, -113, -110, -113, -116, -114, -115, -114, -115, -114, -113, -114, -113, -114, -113, -112, + -113, -109, -105, -111, -106, -107, -103, -100, -103, -99, -97, -98, -99, -92, -92, -93, + -92, -92, -90, -88, -90, -88, -86, -89, -85, -85, -87, -85, -85, -82, -83, -82, + -80, -78, -79, -76, -74, -73, -73, -69, -68, -66, -64, -65, -62, -58, -56, -56, + -52, -50, -47, -43, -42, -39, -35, -33, -31, -27, -23, -21, -16, -16, -8, -7, + -3, 1, 0, 10, 15, 15, 19, 26, 29, 30, 38, 41, 42, 47, 54, 54, + 57, 63, 68, 69, 72, 77, 78, 80, 85, 84, 86, 87, 86, 87, 86, 85, + 86, 85, 84, 85, 84, 83, 84, 83, 82, 82, 83, 82, 81, 82, 81, 80, + 81, 80, 79, 80, 79, 79, 78, 79, 78, 78, 77, 74, 70, 66, 64, 61, + 55, 52, 49, 45, 40, 35, 32, 29, 24, 19, 15, 12, 8, 4, 0, -4, + -8, -11, -15, -17, -20, -25, -26, -29, -32, -34, -37, -39, -41, -43, -45, -46, + -48, -49, -50, -50, -52, -52, -53, -52, -53, -54, -53, -53, -52, -52, -51, -50, + -50, -49, -48, -48, -46, -45, -44, -42, -41, -40, -39, -37, -35, -34, -32, -30, + -28, -27, -24, -23, -22, -20, -19, -17, -15, -14, -13, -12, -10, -9, -8, -8, + -6, -6, -5, -4, -4, -3, -3, -2, -2, -1, -2, -1, -2, -1, -1, 0, + -1, 0, 1, 6, -11, 19, -25, 24, -15, 11, -6, 1, 9, -6, -3, 11, + -18, 28, -23, 8, 6, -2, -1, 0, -5, 18, -23, 24, -28, 27, -12, -1, + -2, 6, 4, -14, 19, -29, 42, -40, 22, -6, -3, 14, -16, 4, 8, -9, + 13, -22, 17, 5, -24, 37, -34, 20, -4, -11, 19, -20, 21, -16, 1, 17, + -17, 5, -9, 25, -31, 31, -40, 32, -11, -7, 4, -4, 13, -23, 29, -40, + 51, -49, 20, 3, -20, 38, -47, 34, -21, 14, -9, 4, -13, 20, -29, 37, + -57, 59, -48, 23, -5, -7, 5, -6, -5, 13, -17, 9, -4, -12, 22, -19, + -8, 10, -5, -7, 8, -18, 19, -13, 5, -12, 6, -10, 18, -40, 66, -91, + 82, -56, 17, 19, -51, 56, -45, 30, -19, 5, -6, 7, -9, -4, -2, -5, + 13, -19, 1, 20, -28, 13, -6, 0, -17, 33, -48, 38, -16, -20, 53, -75, + 75, -61, 30, -12, -9, 2, 5, -9, -7, 15, -17, 9, 4, -46, 70, -85, + 86, -67, 29, 18, -60, 76, -70, 29, -8, -1, 1, 14, -58, 93, -118, 127, + -125, 85, -36, -2, 17, -39, 46, -61, 70, -99, 122, -120, 56, 15, -85, 116, + -101, 30, 43, -108, 127, -122, 72, -38, -3, 20, -31, 29, -37, 42, -50, 63, + -72, 40, -7, -46, 66, -82, 53, -25, 1, 1, -1, -3, 3, -24, 24, -34, + 27, -24, 36, -49, 37, -38, 35, -42, 13, -4, -14, 14, -29, 42, -58, 58, + -60, 41, -39, 27, -35, 27, -32, 25, -37, 43, -50, 32, -20, -4, 4, -14, + 16, -43, 66, -93, 79, -58, 27, -11, -21, 34, -40, 24, -7, -25, 31, -29, + 19, -18, -2, 1, -6, 4, -31, 47, -63, 62, -64, 32, 2, -29, 23, -21, + 19, -41, 59, -76, 62, -52, 26, -11, -1, -10, 6, -10, -7, 17, -42, 34, + -12, -34, 73, -106, 92, -61, 26, -24, 8, -7, -2, 3, -24, 31, -44, 27, + -9, -22, 38, -43, 15, -4, -3, -2, -12, 5, 1, -7, 7, -25, 17, -17, + 4, -15, 27, -40, 34, -18, 6, -13, 12, -3, -9, -6, 8, -18, 18, -36, + 54, -55, 30, -25, 26, -41, 38, -49, 48, -38, 8, 16, -40, 47, -52, 34, + -12, -4, 2, -13, 0, 1, 6, -11, 19, -25, 24, -15, 11, -6, 1, 9, + -6, -3, 11, -18, 28, -23, 8, 6, -2, -1, 0, -5, 18, -23, 24, -28, + 27, -12, -1, -2, 6, 4, -14, 19, -29, 42, -40, 22, -6, -3, 14, -16, + 4, 8, -9, 13, -22, 17, 5, -24, 37, -34, 20, -4, -11, 19, -20, 21, + -16, 1, 17, -17, 5, -9, 25, -31, 31, -40, 32, -11, -7, 4, -4, 13, + -23, 29, -40, 51, -49, 20, 3, -20, 38, -47, 34, -21, 14, -9, 4, -13, + 20, -29, 37, -57, 59, -48, 23, -5, -7, 5, -6, -5, 13, -17, 9, -4, + -12, 22, -19, -8, 10, -5, -7, 8, -18, 19, -13, 5, -12, 6, -10, 18, + -40, 66, -91, 82, -56, 17, 19, -51, 56, -45, 30, -19, 5, -6, 7, -9, + -4, -2, -5, 13, -19, 1, 20, -28, 13, -6, 0, -17, 33, -48, 38, -16, + -20, 53, -75, 75, -61, 30, -12, -9, 2, 5, -9, -7, 15, -17, 9, 4, + -46, 70, -85, 86, -67, 29, 18, -60, 76, -70, 29, -8, -1, 1, 14, -58, + 93, -118, 127, -125, 85, -36, -2, 17, -39, 46, -61, 70, -99, 122, -120, 56, + 15, -85, 116, -101, 30, 43, -108, 127, -122, 72, -38, -3, 20, -31, 29, -37, + 42, -50, 63, -72, 40, -7, -46, 66, -82, 53, -25, 1, 1, -1, -3, 3, + -24, 24, -34, 27, -24, 36, -49, 37, -38, 35, -42, 13, -4, -14, 14, -29, + 42, -58, 58, -60, 41, -39, 27, -35, 27, -32, 25, -37, 43, -50, 32, -20, + -4, 4, -14, 16, -43, 66, -93, 79, -58, 27, -11, -21, 34, -40, 24, -7, + -25, 31, -29, 19, -18, -2, 1, -6, 4, -31, 47, -63, 62, -64, 32, 2, + -29, 23, -21, 19, -41, 59, -76, 62, -52, 26, -11, -1, -10, 6, -10, -7, + 17, -42, 34, -12, -34, 73, -106, 92, -61, 26, -24, 8, -7, -2, 3, -24, + 31, -44, 27, -9, -22, 38, -43, 15, -4, -3, -2, -12, 5, 1, -7, 7, + -25, 17, -17, 4, -15, 27, -40, 34, -18, 6, -13, 12, -3, -9, -6, 8, + -18, 18, -36, 54, -55, 30, -25, 26, -41, 38, -49, 48, -38, 8, 16, -40, + 47, -52, 34, -12, -4, 2, -13, -1, -9, -21, -32, -43, -55, -58, -40, -8, + 15, 29, 38, 44, 59, 63, 51, 20, -20, -47, -61, -58, -48, -42, -43, -35, + -15, 15, 41, 55, 61, 62, 70, 67, 45, 11, -31, -62, -80, -78, -71, -62, + -54, -39, -15, 18, 50, 68, 79, 83, 92, 88, 57, 16, -31, -71, -94, -95, + -90, -83, -71, -55, -28, 7, 49, 77, 93, 100, 109, 107, 78, 36, -20, -71, + -99, -104, -100, -92, -83, -69, -43, -5, 42, 79, 100, 108, 114, 112, 90, 51, + -9, -65, -100, -110, -105, -95, -87, -76, -52, -11, 35, 75, 100, 107, 111, 106, + 90, 52, -4, -60, -97, -109, -99, -87, -80, -65, -35, 5, 43, 75, 91, 95, + 93, 87, 71, 31, -19, -64, -93, -99, -88, -76, -66, -44, -9, 28, 59, 79, + 84, 80, 71, 59, 35, -5, -45, -76, -96, -95, -77, -59, -39, -9, 28, 61, + 86, 98, 93, 74, 52, 28, -6, -43, -72, -94, -108, -99, -77, -52, -20, 19, + 56, 84, 106, 115, 106, 79, 45, 3, -40, -74, -93, -108, -112, -100, -79, -46, + -1, 45, 78, 100, 113, 118, 108, 81, 39, -19, -67, -93, -103, -108, -104, -94, + -74, -32, 19, 61, 88, 102, 108, 109, 100, 73, 21, -44, -87, -102, -104, -97, + -90, -78, -49, 0, 46, 78, 90, 92, 89, 87, 77, 43, -15, -72, -101, -104, + -93, -79, -69, -47, -3, 47, 84, 96, 89, 74, 65, 58, 37, -7, -61, -99, + -110, -101, -82, -62, -38, 2, 49, 92, 112, 106, 82, 59, 41, 18, -19, -61, + -95, -111, -110, -98, -74, -39, 6, 54, 99, 122, 123, 104, 79, 50, 12, -32, + -72, -100, -111, -110, -106, -90, -54, -4, 49, 99, 123, 126, 113, 95, 69, 24, + -27, -72, -102, -114, -109, -104, -94, -64, -16, 36, 87, 116, 121, 111, 97, 76, + 36, -15, -61, -94, -110, -108, -98, -86, -60, -19, 29, 77, 104, 109, 99, 86, + 67, 35, -7, -47, -82, -98, -101, -92, -77, -48, -14, 25, 67, 92, 95, 83, + 66, 45, 18, -9, -37, -62, -77, -81, -78, -54, -16, 0, 0, 0, 12, -10, + 16, -14, -18, 17, -31, -2, 3, -19, -8, 17, 28, 37, 31, -1, -25, -16, + -47, -13, -43, -22, 6, 34, 41, 49, 41, 27, 6, -33, -62, -54, -59, -32, + -13, 29, 53, 73, 60, 54, 16, -19, -58, -77, -89, -42, -46, 17, 55, 78, + 86, 81, 33, -3, -35, -84, -110, -75, -70, 0, 39, 78, 92, 105, 70, 13, + -15, -82, -107, -103, -84, -41, 20, 81, 85, 127, 86, 39, -4, -63, -103, -99, + -107, -69, 2, 68, 82, 127, 84, 58, 28, -44, -88, -104, -108, -83, -13, 29, + 69, 116, 87, 77, 40, -16, -65, -89, -104, -89, -40, -1, 47, 96, 90, 85, + 52, 9, -38, -62, -96, -95, -62, -22, 21, 73, 78, 86, 65, 35, -15, -41, + -80, -92, -69, -48, 1, 43, 65, 80, 73, 49, 8, -23, -59, -75, -74, -60, + -22, 17, 49, 69, 65, 60, 25, -1, -36, -59, -70, -61, -40, -9, 30, 52, + 57, 63, 37, 17, -12, -41, -61, -57, -50, -30, 9, 30, 49, 60, 47, 28, + 6, -20, -49, -51, -53, -42, -11, 13, 34, 53, 50, 34, 18, -3, -35, -39, + -52, -49, -23, 0, 18, 41, 47, 36, 31, 10, -21, -28, -43, -49, -31, -13, + 2, 28, 39, 35, 38, 19, -7, -18, -33, -42, -36, -26, -12, 19, 30, 34, + 36, 22, 6, -5, -25, -38, -36, -29, -17, 8, 19, 26, 35, 28, 12, 3, + -17, -30, -29, -29, -22, -3, 9, 19, 33, 26, 14, 8, -9, -18, -22, -28, + -25, -9, 3, 15, 22, 20, 18, 12, 1, -11, -22, -24, -21, -13, -3, 8, + 11, 20, 21, 12, 5, -6, -19, -16, -17, -17, -7, 3, 8, 20, 17, 7, + 7, -2, -11, -13, -16, -17, -5, 2, 5, 12, 13, 8, 6, 3, -9, -11, + -9, -14, -5, 1, -3, 6, 11, 6, 7, 2, -6, -4, -4, -10, -6, -3, + -4, 5, 8, 2, 5, 4, -2, 0, -3, -9, -4, -3, -3, 2, 3, 0, + 6, 4, 0, -1, -2, -2, 0, -4, 8, -1, 9, 14, 53, 57, 33, -4, + -20, -14, -31, -71, -112, -43, 30, -22, -102, -74, 38, 90, 35, -22, 20, 99, + 96, 22, -42, -5, 48, 16, -74, -97, -51, 10, -21, -80, -68, 24, 77, 43, + -9, 20, 90, 99, 32, -28, -8, 41, 18, -63, -97, -55, -2, -18, -74, -67, + 11, 69, 44, -1, 17, 83, 98, 40, -20, -8, 35, 20, -55, -95, -60, -8, + -19, -69, -68, 3, 61, 45, 1, 15, 78, 99, 46, -14, -8, 33, 22, -48, + -93, -62, -13, -19, -67, -70, -5, 56, 44, 3, 13, 73, 99, 51, -10, -7, + 32, 25, -42, -91, -66, -15, -18, -65, -73, -11, 51, 44, 3, 9, 69, 100, + 55, -6, -8, 32, 30, -36, -89, -68, -17, -17, -64, -77, -18, 47, 45, 3, + 5, 64, 100, 60, -2, -8, 32, 34, -30, -87, -70, -19, -14, -63, -80, -25, + 43, 45, 3, 1, 59, 100, 66, 1, -9, 31, 39, -23, -84, -74, -20, -12, + -59, -84, -32, 38, 46, 3, -3, 53, 101, 71, 6, -10, 31, 43, -14, -81, + -76, -24, -9, -57, -86, -41, 33, 46, 5, -9, 47, 99, 77, 9, -11, 28, + 49, -6, -76, -79, -25, -9, -50, -91, -46, 9, -41, 2, 6, -33, 33, -4, + -1, 34, -93, 60, -49, 68, -21, 41, -38, -38, 27, -87, 127, -34, 38, -3, + -34, -2, -85, 79, -24, 4, 75, -23, 11, -70, 1, -6, -6, 63, -48, 76, + -71, 2, -7, -15, 46, -32, 48, -25, -5, 10, -31, 18, -23, 5, 6, 17, + 11, 3, 24, -46, -21, -1, -5, 31, 1, 36, -23, -11, -4, -29, 14, -5, + 29, 9, -2, -2, -20, -2, -15, 13, 7, 4, 15, -11, 4, -13, -1, 1, + -13, 15, -6, 9, 9, -2, -4, -11, -2, -11, 7, 12, 9, 5, -6, -6, + -16, -2, 3, 6, 13, 1, 7, -14, -3, -11, -1, 8, 0, 18, -3, -3, + -6, -13, 0, 4, 2, 9, 2, 2, -6, -4, -1, -8, 2, 4, 2, 7, + -4, 2, 1, -7, -3, -2, 0, 2, 8, -2, 2, -1, -7, -3, -1, 3, + 4, 3, 3, -3, -4, -4, 0, 2, 1, 5, -1, -2, 1, -4, -1, 1, + 0, 2, 8, -22, 25, 30, 6, -19, -62, -19, 10, 83, 57, -67, -88, -52, + 63, 127, 42, -63, -121, -70, 82, 111, 46, -43, -114, -35, 45, 73, 39, -19, + -54, -41, 9, 49, 24, -16, -14, -9, -6, 10, 8, -22, 25, 30, 6, -19, + -62, -19, 10, 83, 57, -67, -88, -52, 63, 127, 42, -63, -121, -70, 82, 111, + 46, -43, -114, -35, 45, 73, 39, -19, -54, -41, 9, 49, 24, -16, -14, -9, + -6, 10, 94, 127, 124, 127, 127, 114, 73, 35, -11, -52, -98, -118, -125, -128, + -128, -128, -128, -128, -128, -128, -124, -86, -47, 0, 40, 87, 106, 116, 119, 125, + 37, -7, 122, 72, -57, -71, -88, -28, 48, 127, 36, -30, -53, -126, -16, 71, + 92, 51, -1, -83, -128, 14, 43, 83, 86, -14, -106, -87, -7, 28, 1, 122, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0 +}; + +const EAS_U32 eas_sampleLengths[] = +{ + 9922, 9338, 6793, 5242, 3057, 2818, 2806, 1835, + 1603, 1262, 1227, 1168, 1132, 1132, 994, 907, + 817, 801, 583, 418, 402, 387, 387, 357, + 347, 212, 167, 40, 40, 32, 30 +}; + +const EAS_U32 eas_sampleOffsets[] = +{ + 0x00000000, 0x000026c2, 0x00004b3c, 0x000065c5, 0x00007a3f, 0x00008630, 0x00009132, 0x00009c28, + 0x0000a353, 0x0000a996, 0x0000ae84, 0x0000b34f, 0x0000b7df, 0x0000bc4b, 0x0000c0b7, 0x0000c499, + 0x0000c824, 0x0000cb55, 0x0000ce76, 0x0000d0bd, 0x0000d25f, 0x0000d3f1, 0x0000d574, 0x0000d6f7, + 0x0000d85c, 0x0000d9b7, 0x0000da8b, 0x0000db32, 0x0000db5a, 0x0000db82, 0x0000dba2 +}; + +/*---------------------------------------------------------------------------- + * S_EAS (hybrid) + *---------------------------------------------------------------------------- +*/ +const S_EAS easSoundLib = +{ + 0x01534145, + 0x00105622, + eas_banks, + eas_programs, + eas_regions, + eas_articulations, + eas_sampleLengths, + eas_sampleOffsets, + eas_samples, + eas_fmRegions, + 1, + 1, + 61, + 53, + 31, + 128 +}; /* end S_EAS */ + +/*---------------------------------------------------------------------------- + * Statistics + * + * Number of banks: 1 + * Number of programs: 1 + * Number of regions: 61 + * Number of articulations: 53 + * Number of samples: 31 + * Size of sample pool: 56276 + *---------------------------------------------------------------------------- +*/ +/* end C:\Sonic\Trunk\EASLib\WTLibrary\hybrid_22khz_mcu.c */ diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/Android.mk b/common/embeddedaudiosynthesis/arm-wt-22k/Android.mk new file mode 100755 index 0000000..71fbcf8 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/Android.mk @@ -0,0 +1,104 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES = \ + lib_src/eas_chorus.c \ + lib_src/eas_chorusdata.c \ + lib_src/eas_data.c \ + lib_src/eas_dlssynth.c \ + lib_src/eas_flog.c \ + lib_src/eas_ima_tables.c \ + lib_src/eas_imaadpcm.c \ + lib_src/eas_imelody.c \ + lib_src/eas_imelodydata.c \ + lib_src/eas_math.c \ + lib_src/eas_mdls.c \ + lib_src/eas_midi.c \ + lib_src/eas_mididata.c \ + lib_src/eas_mixbuf.c \ + lib_src/eas_mixer.c \ + lib_src/eas_ota.c \ + lib_src/eas_otadata.c \ + lib_src/eas_pan.c \ + lib_src/eas_pcm.c \ + lib_src/eas_pcmdata.c \ + lib_src/eas_public.c \ + lib_src/eas_reverb.c \ + lib_src/eas_reverbdata.c \ + lib_src/eas_rtttl.c \ + lib_src/eas_rtttldata.c \ + lib_src/eas_smf.c \ + lib_src/eas_smfdata.c \ + lib_src/eas_voicemgt.c \ + lib_src/eas_wtengine.c \ + lib_src/eas_wtsynth.c \ + lib_src/eas_xmf.c \ + lib_src/eas_xmfdata.c \ + lib_src/wt_22khz.c \ + lib_src/jet.c \ + host_src/eas_config.c \ + host_src/eas_hostmm.c \ + host_src/eas_main.c \ + host_src/eas_report.c \ + host_src/eas_wave.c + +# not using these modules +# lib_src/eas_wavefile.c \ +# lib_src/eas_wavefiledata.c \ + +LOCAL_CFLAGS+= -O2 -D UNIFIED_DEBUG_MESSAGES -D EAS_WT_SYNTH \ + -D _IMELODY_PARSER -D _RTTTL_PARSER -D _OTA_PARSER \ + -D _XMF_PARSER -D NUM_OUTPUT_CHANNELS=2 \ + -D _SAMPLE_RATE_22050 -D MAX_SYNTH_VOICES=64 \ + -D _8_BIT_SAMPLES -D _FILTER_ENABLED \ + -D DLS_SYNTHESIZER \ + -D _REVERB_ENABLED + +# not using these options +# -D _WAVE_PARSER +# -D _IMA_DECODER (needed for IMA-ADPCM wave files) +# -D _CHORUS_ENABLED + +LOCAL_C_INCLUDES:= \ + $(LOCAL_PATH)/host_src \ + $(LOCAL_PATH)/lib_src + +LOCAL_ARM_MODE := arm + +LOCAL_MODULE := libsonivox + +LOCAL_COPY_HEADERS_TO := libsonivox +LOCAL_COPY_HEADERS := \ + host_src/eas.h \ + host_src/eas_types.h \ + host_src/eas_reverb.h \ + host_src/jet.h + +ifeq ($(TARGET_ARCH),arm) +LOCAL_SRC_FILES+= \ + lib_src/ARM-E_filter_gnu.s \ + lib_src/ARM-E_interpolate_loop_gnu.s \ + lib_src/ARM-E_interpolate_noloop_gnu.s \ + lib_src/ARM-E_mastergain_gnu.s \ + lib_src/ARM-E_voice_gain_gnu.s + +asm_flags := \ + -I $(LOCAL_PATH)/lib_src \ + --defsym SAMPLE_RATE_22050=1 \ + --defsym STEREO_OUTPUT=1 \ + --defsym FILTER_ENABLED=1 \ + --defsym SAMPLES_8_BIT=1 + +LOCAL_CFLAGS+= -D NATIVE_EAS_KERNEL \ + $(foreach f,$(asm_flags),-Wa,"$(f)") + +LOCAL_COPY_HEADERS += lib_src/ARM_synth_constants_gnu.inc +endif + +LOCAL_SHARED_LIBRARIES := \ + libutils libcutils + +LOCAL_LDLIBS := -lpthread + +include $(BUILD_SHARED_LIBRARY) + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/bin/arm-wt-22k b/common/embeddedaudiosynthesis/arm-wt-22k/bin/arm-wt-22k new file mode 100755 index 0000000..2e54640 Binary files /dev/null and b/common/embeddedaudiosynthesis/arm-wt-22k/bin/arm-wt-22k differ diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/host_src/arm-wt-22k.mak b/common/embeddedaudiosynthesis/arm-wt-22k/host_src/arm-wt-22k.mak new file mode 100755 index 0000000..222d174 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/host_src/arm-wt-22k.mak @@ -0,0 +1,25 @@ +# +# Auto-generated sample makefile +# +# This makefile is intended for use with GNU make. +# Set the paths to the tools (CC, AR, LD, etc.) +# + +vpath %.c host_src + +CC = C:\Program Files\GNUARM\bin\arm-elf-gcc.exe +AS = C:\Program Files\GNUARM\bin\arm-elf-as.exe +LD = C:\Program Files\GNUARM\bin\arm-elf-gcc.exe +AR = C:\Program Files\GNUARM\bin\arm-elf-ar.exe + +%.o: %.c + $(CC) -c -O2 -o $@ -I host_src -D UNIFIED_DEBUG_MESSAGES -D EAS_WT_SYNTH -D _IMELODY_PARSER -D _RTTTL_PARSER -D _OTA_PARSER -D _XMF_PARSER -D _WAVE_PARSER -D _REVERB_ENABLED -D _CHORUS_ENABLED -D MMAPI_SUPPORT -D JET_INTERFACE $< + +%.o: %.s + $(AS) -o $@ -EL -mcpu=arm946e-s -mfpu=softfpa -I lib_src --defsym CHECK_STACK=0 --defsym REVERB=0 --defsym CHORUS=0 --defsym STEREO_OUTPUT=1 --defsym SAMPLE_RATE_22050=1 --defsym SAMPLES_8_BIT=1 --defsym FILTER_ENABLED=1 $< + +OBJS = eas_main.o eas_report.o eas_wave.o eas_hostmm.o eas_config.o + +arm-wt-22k: $(OBJS) + $(LD) -o $@ $(OBJS) libarm-wt-22k.a -lm + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas.h b/common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas.h new file mode 100755 index 0000000..c64af49 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas.h @@ -0,0 +1,1062 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas.h + * + * Contents and purpose: + * The public interface header for the EAS synthesizer. + * + * This header only contains declarations that are specific + * to this implementation. + * + * DO NOT MODIFY THIS FILE! + * + * Copyright Sonic Network Inc. 2005, 2006 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 852 $ + * $Date: 2007-09-04 11:43:49 -0700 (Tue, 04 Sep 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_H +#define _EAS_H + +#include "eas_types.h" + +/* for C++ linkage */ +#ifdef __cplusplus +extern "C" { +#endif + +/* library version macro */ +#define MAKE_LIB_VERSION(a,b,c,d) (((((((EAS_U32) a <<8) | (EAS_U32) b) << 8) | (EAS_U32) c) << 8) | (EAS_U32) d) +#define LIB_VERSION MAKE_LIB_VERSION(3, 6, 10, 14) + +typedef struct +{ + EAS_U32 libVersion; + EAS_BOOL checkedVersion; + EAS_I32 maxVoices; + EAS_I32 numChannels; + EAS_I32 sampleRate; + EAS_I32 mixBufferSize; + EAS_BOOL filterEnabled; + EAS_U32 buildTimeStamp; + EAS_CHAR *buildGUID; +} S_EAS_LIB_CONFIG; + +/* enumerated effects module numbers for configuration */ +typedef enum +{ + EAS_MODULE_ENHANCER = 0, + EAS_MODULE_COMPRESSOR, + EAS_MODULE_REVERB, + EAS_MODULE_CHORUS, + EAS_MODULE_WIDENER, + EAS_MODULE_GRAPHIC_EQ, + EAS_MODULE_WOW, + EAS_MODULE_MAXIMIZER, + EAS_MODULE_TONECONTROLEQ, + NUM_EFFECTS_MODULES +} E_FX_MODULES; + +/* enumerated optional module numbers for configuration */ +typedef enum +{ + EAS_MODULE_MMAPI_TONE_CONTROL = 0, + EAS_MODULE_METRICS +} E_OPT_MODULES; +#define NUM_OPTIONAL_MODULES 2 + +/* enumerated audio decoders for configuration */ +typedef enum +{ + EAS_DECODER_PCM = 0, + EAS_DECODER_SMAF_ADPCM, + EAS_DECODER_IMA_ADPCM, + EAS_DECODER_7BIT_SMAF_ADPCM, + EAS_DECODER_NOT_SUPPORTED +} E_DECODER_MODULES; +#define NUM_DECODER_MODULES 4 + +/* defines for EAS_PEOpenStream flags parameter */ +#define PCM_FLAGS_STEREO 0x00000100 /* stream is stereo */ +#define PCM_FLAGS_8_BIT 0x00000001 /* 8-bit format */ +#define PCM_FLAGS_UNSIGNED 0x00000010 /* unsigned format */ +#define PCM_FLAGS_STREAMING 0x80000000 /* streaming mode */ + +/* maximum volume setting */ +#define EAS_MAX_VOLUME 100 + +/*---------------------------------------------------------------------------- + * EAS_Init() + *---------------------------------------------------------------------------- + * Purpose: + * Initialize the synthesizer library + * + * Inputs: + * polyphony - number of voices to play (dynamic memory model only) + * ppLibData - pointer to data handle variable for this instance + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Init (EAS_DATA_HANDLE *ppEASData); + +/*---------------------------------------------------------------------------- + * EAS_Config() + *---------------------------------------------------------------------------- + * Purpose: + * Returns a pointer to a structure containing the configuration options + * in this library build. + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC const S_EAS_LIB_CONFIG *EAS_Config (void); + +/*---------------------------------------------------------------------------- + * EAS_Shutdown() + *---------------------------------------------------------------------------- + * Purpose: + * Shuts down the library. Deallocates any memory associated with the + * synthesizer (dynamic memory model only) + * + * Inputs: + * pEASData - handle to data for this instance + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Shutdown (EAS_DATA_HANDLE pEASData); + +/*---------------------------------------------------------------------------- + * EAS_Render() + *---------------------------------------------------------------------------- + * Purpose: + * Parse the Midi data and render PCM audio data. + * + * Inputs: + * pEASData - buffer for internal EAS data + * pOut - output buffer pointer + * nNumRequested - requested num samples to generate + * pnNumGenerated - actual number of samples generated + * + * Outputs: + * EAS_SUCCESS if PCM data was successfully rendered + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Render (EAS_DATA_HANDLE pEASData, EAS_PCM *pOut, EAS_I32 numRequested, EAS_I32 *pNumGenerated); + +/*---------------------------------------------------------------------------- + * EAS_SetRepeat() + *---------------------------------------------------------------------------- + * Purpose: + * Set the selected stream to repeat. + * + * Inputs: + * pEASData - handle to data for this instance + * streamHandle - handle to stream + * repeatCount - repeat count (0 = no repeat, -1 = repeat forever) + * + * Outputs: + * + * Side Effects: + * + * Notes: + * 0 = no repeat + * 1 = repeat once, i.e. play through twice + * -1 = repeat forever + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetRepeat (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 repeatCount); + +/*---------------------------------------------------------------------------- + * EAS_GetRepeat() + *---------------------------------------------------------------------------- + * Purpose: + * Gets the current repeat count for the selected stream. + * + * Inputs: + * pEASData - handle to data for this instance + * streamHandle - handle to stream + * pRrepeatCount - pointer to variable to hold repeat count + * + * Outputs: + * + * Side Effects: + * + * Notes: + * 0 = no repeat + * 1 = repeat once, i.e. play through twice + * -1 = repeat forever + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetRepeat (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 *pRepeatCount); + +/*---------------------------------------------------------------------------- + * EAS_SetPlaybackRate() + *---------------------------------------------------------------------------- + * Purpose: + * Set the playback rate. + * + * Inputs: + * pEASData - handle to data for this instance + * streamHandle - handle to stream + * rate - rate (28-bit fractional amount) + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetPlaybackRate (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_U32 rate); +#define MAX_PLAYBACK_RATE (EAS_U32)(1L << 29) +#define MIN_PLAYBACK_RATE (EAS_U32)(1L << 27) + +/*---------------------------------------------------------------------------- + * EAS_SetTransposition) + *---------------------------------------------------------------------------- + * Purpose: + * Sets the key tranposition for the synthesizer. Transposes all + * melodic instruments by the specified amount. Range is limited + * to +/-12 semitones. + * + * Inputs: + * pEASData - handle to data for this instance + * streamHandle - handle to stream + * transposition - +/-12 semitones + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetTransposition (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 transposition); +#define MAX_TRANSPOSE 12 + +/*---------------------------------------------------------------------------- + * EAS_SetSynthPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Set the polyphony of the synthesizer. Value must be >= 1 and <= the + * maximum number of voices. This function will pin the polyphony + * at those limits + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * synthNum - synthesizer number (0 = onboard, 1 = DSP) + * polyphonyCount - the desired polyphony count + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetSynthPolyphony (EAS_DATA_HANDLE pEASData, EAS_I32 synthNum, EAS_I32 polyphonyCount); + +/*---------------------------------------------------------------------------- + * EAS_GetSynthPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current polyphony setting of the synthesizer + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * synthNum - synthesizer number (0 = onboard, 1 = DSP) + * pPolyphonyCount - pointer to variable to receive polyphony count + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetSynthPolyphony (EAS_DATA_HANDLE pEASData, EAS_I32 synthNum, EAS_I32 *pPolyphonyCount); + +/*---------------------------------------------------------------------------- + * EAS_SetPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Set the polyphony of the stream. Value must be >= 1 and <= the + * maximum number of voices. This function will pin the polyphony + * at those limits + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - handle returned by EAS_OpenFile + * polyphonyCount - the desired polyphony count + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetPolyphony (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 polyphonyCount); + +/*---------------------------------------------------------------------------- + * EAS_GetPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current polyphony setting of the stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - handle returned by EAS_OpenFile + * pPolyphonyCount - pointer to variable to receive polyphony count + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetPolyphony (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 *pPolyphonyCount); + +/*---------------------------------------------------------------------------- + * EAS_SetPriority() + *---------------------------------------------------------------------------- + * Purpose: + * Set the priority of the stream. Determines which stream's voices + * are stolen when there are insufficient voices for all notes. + * Value must be in the range of 1-255, lower values are higher + * priority. The default priority is 50. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - handle returned by EAS_OpenFile + * polyphonyCount - the desired polyphony count + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetPriority (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 priority); + +/*---------------------------------------------------------------------------- + * EAS_GetPriority() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current priority setting of the stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - handle returned by EAS_OpenFile + * pPriority - pointer to variable to receive priority + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetPriority (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 *pPriority); + +/*---------------------------------------------------------------------------- + * EAS_SetVolume() + *---------------------------------------------------------------------------- + * Purpose: + * Set the master volume for the mixer. The default volume setting is + * 90 (-10 dB). The volume range is 0 to 100 in 1dB increments. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * volume - the desired master volume + * + * Outputs: + * + * + * Side Effects: + * overrides any previously set master volume from sysex + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetVolume (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 volume); + +/*---------------------------------------------------------------------------- + * EAS_GetVolume() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the master volume for the mixer in 1dB increments. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * volume - the desired master volume + * + * Outputs: + * + * + * Side Effects: + * overrides any previously set master volume from sysex + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_I32 EAS_GetVolume (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle); + +/*---------------------------------------------------------------------------- + * EAS_SetMaxLoad() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the maximum workload the parsers will do in a single call to + * EAS_Render. The units are currently arbitrary, but should correlate + * well to the actual CPU cycles consumed. The primary effect is to + * reduce the occasional peaks in CPU cycles consumed when parsing + * dense parts of a MIDI score. Setting maxWorkLoad to zero disables + * the workload limiting function. + * + * Inputs: + * pEASData - handle to data for this instance + * maxLoad - the desired maximum workload + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetMaxLoad (EAS_DATA_HANDLE pEASData, EAS_I32 maxLoad); + +/*---------------------------------------------------------------------------- + * EAS_SetMaxPCMStreams() + *---------------------------------------------------------------------------- + * Sets the maximum number of PCM streams allowed in parsers that + * use PCM streaming. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - handle returned by EAS_OpenFile + * maxNumStreams - maximum number of PCM streams + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetMaxPCMStreams (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 maxNumStreams); + +/*---------------------------------------------------------------------------- + * EAS_OpenFile() + *---------------------------------------------------------------------------- + * Purpose: + * Opens a file for audio playback. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * locator - pointer to filename or other locating information + * pStreamHandle - pointer to stream handle variable + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_OpenFile (EAS_DATA_HANDLE pEASData, EAS_FILE_LOCATOR locator, EAS_HANDLE *pStreamHandle); + +#ifdef MMAPI_SUPPORT +/*---------------------------------------------------------------------------- + * EAS_MMAPIToneControl() + *---------------------------------------------------------------------------- + * Purpose: + * Opens a ToneControl file for audio playback. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * locator - pointer to filename or other locating information + * pStreamHandle - pointer to stream handle variable + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_MMAPIToneControl (EAS_DATA_HANDLE pEASData, EAS_FILE_LOCATOR locator, EAS_HANDLE *pStreamHandle); + +/*---------------------------------------------------------------------------- + * EAS_GetWaveFmtChunk + *---------------------------------------------------------------------------- + * Helper function to retrieve WAVE file fmt chunk for MMAPI + *---------------------------------------------------------------------------- + * pEASData - pointer to EAS persistent data object + * streamHandle - stream handle + * pFmtChunk - pointer to pointer to FMT chunk data + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetWaveFmtChunk (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_VOID_PTR *ppFmtChunk); +#endif + +/*---------------------------------------------------------------------------- + * EAS_GetFileType + *---------------------------------------------------------------------------- + * Returns the file type (see eas_types.h for enumerations) + *---------------------------------------------------------------------------- + * pEASData - pointer to EAS persistent data object + * streamHandle - stream handle + * pFileType - pointer to variable to receive file type + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetFileType (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 *pFileType); + +/*---------------------------------------------------------------------------- + * EAS_ParseMetaData() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - file or stream handle + * playLength - pointer to variable to store the play length (in msecs) + * + * Outputs: + * + * + * Side Effects: + * - resets the parser to the start of the file + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_ParseMetaData (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 *pPlayLength); + +/*---------------------------------------------------------------------------- + * EAS_Prepare() + *---------------------------------------------------------------------------- + * Purpose: + * Prepares the synthesizer to play the file or stream. Parses the first + * frame of data from the file and arms the synthesizer. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - file or stream handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Prepare (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle); + +/*---------------------------------------------------------------------------- + * EAS_State() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the state of an audio file or stream. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - file or stream handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_State (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_STATE *pState); + +/*---------------------------------------------------------------------------- + * EAS_RegisterMetaDataCallback() + *---------------------------------------------------------------------------- + * Purpose: + * Registers a metadata callback function for parsed metadata. To + * de-register the callback, call this function again with parameter + * cbFunc set to NULL. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - file or stream handle + * cbFunc - pointer to host callback function + * metaDataBuffer - pointer to metadata buffer + * metaDataBufSize - maximum size of the metadata buffer + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_RegisterMetaDataCallback ( + EAS_DATA_HANDLE pEASData, + EAS_HANDLE streamHandle, + EAS_METADATA_CBFUNC cbFunc, + char *metaDataBuffer, + EAS_I32 metaDataBufSize, + EAS_VOID_PTR pUserData); + +/*---------------------------------------------------------------------------- + * EAS_GetNoteCount () + *---------------------------------------------------------------------------- + * Returns the total number of notes played in this stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - file or stream handle + * pNoteCount - pointer to variable to receive note count + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetNoteCount (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 *pNoteCount); + +/*---------------------------------------------------------------------------- + * EAS_CloseFile() + *---------------------------------------------------------------------------- + * Purpose: + * Closes an audio file or stream. Playback should have either paused or + * completed (EAS_State returns EAS_PAUSED or EAS_STOPPED). + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - file or stream handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_CloseFile (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle); + +/*---------------------------------------------------------------------------- + * EAS_OpenMIDIStream() + *---------------------------------------------------------------------------- + * Purpose: + * Opens a raw MIDI stream allowing the host to route MIDI cable data directly to the synthesizer + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * pStreamHandle - pointer to variable to hold file or stream handle + * streamHandle - open stream or NULL for new synthesizer instance + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_OpenMIDIStream (EAS_DATA_HANDLE pEASData, EAS_HANDLE *pStreamHandle, EAS_HANDLE streamHandle); + +/*---------------------------------------------------------------------------- + * EAS_WriteMIDIStream() + *---------------------------------------------------------------------------- + * Purpose: + * Send data to the MIDI stream device + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - stream handle + * pBuffer - pointer to buffer + * count - number of bytes to write + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_WriteMIDIStream(EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_U8 *pBuffer, EAS_I32 count); + +/*---------------------------------------------------------------------------- + * EAS_CloseMIDIStream() + *---------------------------------------------------------------------------- + * Purpose: + * Closes a raw MIDI stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - stream handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_CloseMIDIStream (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle); + +/*---------------------------------------------------------------------------- + * EAS_Locate() + *---------------------------------------------------------------------------- + * Purpose: + * Locate into the file associated with the handle. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - file handle + * milliseconds - playback offset from start of file in milliseconds + * + * Outputs: + * + * + * Side Effects: + * the actual offset will be quantized to the closest update period, typically + * a resolution of 5.9ms. Notes that are started prior to this time will not + * sound. Any notes currently playing will be shut off. + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Locate (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 milliseconds, EAS_BOOL offset); + +/*---------------------------------------------------------------------------- + * EAS_GetRenderTime() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current playback offset + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * + * Outputs: + * Gets the render time clock in msecs. + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetRenderTime (EAS_DATA_HANDLE pEASData, EAS_I32 *pTime); + +/*---------------------------------------------------------------------------- + * EAS_GetLocation() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current playback offset + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - file handle + * + * Outputs: + * The offset in milliseconds from the start of the current sequence, quantized + * to the nearest update period. Actual resolution is typically 5.9 ms. + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetLocation (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_I32 *pTime); + +/*---------------------------------------------------------------------------- + * EAS_Pause() + *---------------------------------------------------------------------------- + * Purpose: + * Pauses the playback of the data associated with this handle. The audio + * is gracefully ramped down to prevent clicks and pops. It may take several + * buffers of audio before the audio is muted. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * streamHandle - file or stream handle + * + * Outputs: + * + * + * Side Effects: + * + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Pause (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle); + +/*---------------------------------------------------------------------------- + * EAS_Resume() + *---------------------------------------------------------------------------- + * Purpose: + * Resumes the playback of the data associated with this handle. The audio + * is gracefully ramped up to prevent clicks and pops. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * streamHandle - file or stream handle + * + * Outputs: + * + * + * Side Effects: + * + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Resume (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle); + +/*---------------------------------------------------------------------------- + * EAS_GetParameter() + *---------------------------------------------------------------------------- + * Purpose: + * Set the parameter of a module. See E_MODULES for a list of modules + * and the header files of the modules for a list of parameters. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * module - enumerated module number + * param - enumerated parameter number + * pValue - pointer to variable to receive parameter value + * + * Outputs: + * + * + * Side Effects: + * + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetParameter (EAS_DATA_HANDLE pEASData, EAS_I32 module, EAS_I32 param, EAS_I32 *pValue); + +/*---------------------------------------------------------------------------- + * EAS_SetParameter() + *---------------------------------------------------------------------------- + * Purpose: + * Set the parameter of a module. See E_MODULES for a list of modules + * and the header files of the modules for a list of parameters. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * handle - file or stream handle + * module - enumerated module number + * param - enumerated parameter number + * value - new parameter value + * + * Outputs: + * + * + * Side Effects: + * + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetParameter (EAS_DATA_HANDLE pEASData, EAS_I32 module, EAS_I32 param, EAS_I32 value); + +#ifdef _METRICS_ENABLED +/*---------------------------------------------------------------------------- + * EAS_MetricsReport() + *---------------------------------------------------------------------------- + * Purpose: + * Displays the current metrics through the EAS_Report interface. + * + * Inputs: + * pEASData - instance data handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_MetricsReport (EAS_DATA_HANDLE pEASData); + +/*---------------------------------------------------------------------------- + * EAS_MetricsReset() + *---------------------------------------------------------------------------- + * Purpose: + * Displays the current metrics through the EAS_Report interface. + * + * Inputs: + * pEASData - instance data handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_MetricsReset (EAS_DATA_HANDLE pEASData); +#endif + +/*---------------------------------------------------------------------------- + * EAS_SetSoundLibrary() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the location of the sound library. + * + * Inputs: + * pEASData - instance data handle + * streamHandle - file or stream handle + * pSoundLib - pointer to sound library + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetSoundLibrary (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_SNDLIB_HANDLE pSndLib); + +/*---------------------------------------------------------------------------- + * EAS_SetHeaderSearchFlag() + *---------------------------------------------------------------------------- + * By default, when EAS_OpenFile is called, the parsers check the + * first few bytes of the file looking for a specific header. Some + * mobile devices may add a header to the start of a file, which + * will prevent the parser from recognizing the file. If the + * searchFlag is set to EAS_TRUE, the parser will search the entire + * file looking for the header. This may enable EAS to recognize + * some files that it would ordinarily reject. The negative is that + * it make take slightly longer to process the EAS_OpenFile request. + * + * Inputs: + * pEASData - instance data handle + * searchFlag - search flag (EAS_TRUE or EAS_FALSE) + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetHeaderSearchFlag (EAS_DATA_HANDLE pEASData, EAS_BOOL searchFlag); + +/*---------------------------------------------------------------------------- + * EAS_SetPlayMode() + *---------------------------------------------------------------------------- + * Some file formats support special play modes, such as iMode partial + * play mode. This call can be used to change the play mode. The + * default play mode (usually straight playback) is always zero. + * + * Inputs: + * pEASData - instance data handle + * handle - file or stream handle + * playMode - play mode (see eas_types.h for enumerations) + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetPlayMode (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 playMode); + +#ifdef DLS_SYNTHESIZER +/*---------------------------------------------------------------------------- + * EAS_LoadDLSCollection() + *---------------------------------------------------------------------------- + * Purpose: + * Downloads a DLS collection + * + * Inputs: + * pEASData - instance data handle + * streamHandle - file or stream handle + * locator - file locator + * + * Outputs: + * + * + * Side Effects: + * May overlay instruments in the GM sound set + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_LoadDLSCollection (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_FILE_LOCATOR locator); +#endif + +/*---------------------------------------------------------------------------- + * EAS_SetFrameBuffer() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the frame buffer pointer passed to the IPC communications functions + * + * Inputs: + * pEASData - instance data handle + * locator - file locator + * + * Outputs: + * + * + * Side Effects: + * May overlay instruments in the GM sound set + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetFrameBuffer (EAS_DATA_HANDLE pEASData, EAS_FRAME_BUFFER_HANDLE pFrameBuffer); + +#ifdef EXTERNAL_AUDIO +/*---------------------------------------------------------------------------- + * EAS_RegExtAudioCallback() + *---------------------------------------------------------------------------- + * Purpose: + * Registers callback functions for audio events. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - file or stream handle + * cbProgChgFunc - pointer to host callback function for program change + * cbEventFunc - pointer to host callback functio for note events + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_RegExtAudioCallback (EAS_DATA_HANDLE pEASData, + EAS_HANDLE streamHandle, + EAS_VOID_PTR pInstData, + EAS_EXT_PRG_CHG_FUNC cbProgChgFunc, + EAS_EXT_EVENT_FUNC cbEventFunc); + +/*---------------------------------------------------------------------------- + * EAS_GetMIDIControllers() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current state of MIDI controllers on the requested channel. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - file or stream handle + * pControl - pointer to structure to receive data + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetMIDIControllers (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_U8 channel, S_MIDI_CONTROLLERS *pControl); +#endif + +/*---------------------------------------------------------------------------- + * EAS_SearchFile + *---------------------------------------------------------------------------- + * Search file for specific sequence starting at current file + * position. Returns offset to start of sequence. + * + * Inputs: + * pEASData - pointer to EAS persistent data object + * fileHandle - file handle + * searchString - pointer to search sequence + * len - length of search sequence + * pOffset - pointer to variable to store offset to sequence + * + * Returns EAS_EOF if end-of-file is reached + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_SearchFile (EAS_DATA_HANDLE pEASData, EAS_FILE_HANDLE fileHandle, const EAS_U8 *searchString, EAS_I32 len, EAS_I32 *pOffset); + +#ifdef __cplusplus +} /* end extern "C" */ +#endif + +#endif /* #ifndef _EAS_H */ diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_build.h b/common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_build.h new file mode 100755 index 0000000..a65f8a6 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_build.h @@ -0,0 +1,36 @@ +/*---------------------------------------------------------------------------- + * + * File: + * host_src\eas_build.h + * + * Contents and purpose: + * This file contains the build configuration for this + * build. The buildGUIDStr is a GUID created during + * the build process and is guaranteed to be unique + * for each build. + * + * Copyright Sonic Network Inc. 2006 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file was autogenerated by buildid.exe + *---------------------------------------------------------------------------- +*/ + +#ifndef _GUID_1feda229b9a845e996f473c0a80e7220_ +#define _GUID_1feda229b9a845e996f473c0a80e7220_ + +#define _BUILD_VERSION_ "1feda229-b9a8-45e9-96f4-73c0a80e7220" +#define _BUILD_TIME_ 0x4743badd + +#endif /* _GUID_1feda229b9a845e996f473c0a80e7220_ */ diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_chorus.h b/common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_chorus.h new file mode 100755 index 0000000..d84a53b --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_chorus.h @@ -0,0 +1,53 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_chorus.h + * + * Contents and purpose: + * Contains parameter enumerations for the Chorus effect + * + * + * Copyright Sonic Network Inc. 2006 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 309 $ + * $Date: 2006-09-12 18:52:45 -0700 (Tue, 12 Sep 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef EAS_CHORUS_H +#define EAS_CHORUS_H + +/* enumerated parameter settings for Chorus effect */ +typedef enum +{ + EAS_PARAM_CHORUS_BYPASS, + EAS_PARAM_CHORUS_PRESET, + EAS_PARAM_CHORUS_RATE, + EAS_PARAM_CHORUS_DEPTH, + EAS_PARAM_CHORUS_LEVEL +} E_CHORUS_PARAMS; + +typedef enum +{ + EAS_PARAM_CHORUS_PRESET1, + EAS_PARAM_CHORUS_PRESET2, + EAS_PARAM_CHORUS_PRESET3, + EAS_PARAM_CHORUS_PRESET4 +} E_CHORUS_PRESETS; + + +#endif diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_config.c b/common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_config.c new file mode 100755 index 0000000..0b92357 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_config.c @@ -0,0 +1,619 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_config.c + * + * Contents and purpose: + * This file contains the Configuration Module interface (CM). The CM + * is a module compiled external to the library that sets the configuration + * for this build. It allows the library to find optional components and + * links to static memory allocations (when used in a static configuration). + * + * DO NOT MODIFY THIS FILE! + * + * NOTE: This module is not intended to be modified by the customer. It + * needs to be included in the build process with the correct configuration + * defines (see the library documentation for information on how to configure + * the library). + * + * Copyright Sonic Network Inc. 2004-2006 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 796 $ + * $Date: 2007-08-01 00:15:25 -0700 (Wed, 01 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas.h" +#include "eas_config.h" + + +#ifdef _MFI_PARSER +/*---------------------------------------------------------------------------- + * Vendor/Device ID for MFi Extensions + * + * Define the preprocessor symbols to establish the vendor ID and + * device ID for the MFi PCM/ADPCM extensions. + *---------------------------------------------------------------------------- +*/ +const EAS_U8 eas_MFIVendorIDMSB = (MFI_VENDOR_ID >> 8) & 0xff; +const EAS_U8 eas_MFIVendorIDLSB = MFI_VENDOR_ID & 0xff; +const EAS_U8 eas_MFIDeviceID = MFI_DEVICE_ID; +#endif + +/*---------------------------------------------------------------------------- + * + * parserModules + * + * This structure is used by the EAS library to locate file parsing + * modules. + *---------------------------------------------------------------------------- +*/ + +/* define the external file parsers */ +extern EAS_VOID_PTR EAS_SMF_Parser; + +#ifdef _XMF_PARSER +extern EAS_VOID_PTR EAS_XMF_Parser; +#endif + +#ifdef _SMAF_PARSER +extern EAS_VOID_PTR EAS_SMAF_Parser; +#endif + +#ifdef _WAVE_PARSER +extern EAS_VOID_PTR EAS_Wave_Parser; +#endif + +#ifdef _OTA_PARSER +extern EAS_VOID_PTR EAS_OTA_Parser; +#endif + +#ifdef _IMELODY_PARSER +extern EAS_VOID_PTR EAS_iMelody_Parser; +#endif + +#ifdef _RTTTL_PARSER +extern EAS_VOID_PTR EAS_RTTTL_Parser; +#endif + +#if defined (_CMX_PARSER) || defined(_MFI_PARSER) +extern EAS_VOID_PTR EAS_CMF_Parser; +#endif + +/* initalize pointers to parser interfaces */ +/*lint -e{605} not pretty, but it works */ +EAS_VOID_PTR const parserModules[] = +{ + &EAS_SMF_Parser, + +#ifdef _XMF_PARSER + &EAS_XMF_Parser, +#endif + +#ifdef _WAVE_PARSER + &EAS_Wave_Parser, +#endif + +#ifdef _SMAF_PARSER + &EAS_SMAF_Parser, +#endif + +#ifdef _OTA_PARSER + &EAS_OTA_Parser, +#endif + +#ifdef _IMELODY_PARSER + &EAS_iMelody_Parser, +#endif + +#ifdef _RTTTL_PARSER + &EAS_RTTTL_Parser, +#endif + +#if defined (_CMX_PARSER) || defined(_MFI_PARSER) + &EAS_CMF_Parser +#endif +}; +#define NUM_PARSER_MODULES (sizeof(parserModules) / sizeof(EAS_VOID_PTR)) + +/*---------------------------------------------------------------------------- + * Data Modules + *---------------------------------------------------------------------------- +*/ + +#ifdef _STATIC_MEMORY +extern EAS_VOID_PTR eas_SMFData; +extern EAS_VOID_PTR eas_Data; +extern EAS_VOID_PTR eas_MixBuffer; +extern EAS_VOID_PTR eas_Synth; +extern EAS_VOID_PTR eas_MIDI; +extern EAS_VOID_PTR eas_PCMData; +extern EAS_VOID_PTR eas_MIDIData; + +#ifdef _XMF_PARSER +extern EAS_VOID_PTR eas_XMFData; +#endif + +#ifdef _SMAF_PARSER +extern EAS_VOID_PTR eas_SMAFData; +#endif + +#ifdef _OTA_PARSER +extern EAS_VOID_PTR eas_OTAData; +#endif + +#ifdef _IMELODY_PARSER +extern EAS_VOID_PTR eas_iMelodyData; +#endif + +#ifdef _RTTTL_PARSER +extern EAS_VOID_PTR eas_RTTTLData; +#endif + +#ifdef _WAVE_PARSER +extern EAS_VOID_PTR eas_WaveData; +#endif + +#if defined (_CMX_PARSER) || defined(_MFI_PARSER) +extern EAS_VOID_PTR eas_CMFData; +#endif +#endif + +/*---------------------------------------------------------------------------- + * + * Effects Modules + * + * These declarations are used by the EAS library to locate + * effects modules. + *---------------------------------------------------------------------------- +*/ + +#ifdef _ENHANCER_ENABLED +extern EAS_VOID_PTR EAS_Enhancer; +#define EAS_ENHANCER_INTERFACE &EAS_Enhancer +#ifdef _STATIC_MEMORY +extern EAS_VOID_PTR eas_EnhancerData; +#define EAS_ENHANCER_DATA &eas_EnhancerData +#else +#define EAS_ENHANCER_DATA NULL +#endif +#else +#define EAS_ENHANCER_INTERFACE NULL +#define EAS_ENHANCER_DATA NULL +#endif + +#ifdef _COMPRESSOR_ENABLED +extern EAS_VOID_PTR EAS_Compressor; +#define EAS_COMPRESSOR_INTERFACE &EAS_Compressor +#ifdef _STATIC_MEMORY +extern EAS_VOID_PTR eas_CompressorData; +#define EAS_COMPRESSOR_DATA &eas_CompressorData +#else +#define EAS_COMPRESSOR_DATA NULL +#endif +#else +#define EAS_COMPRESSOR_INTERFACE NULL +#define EAS_COMPRESSOR_DATA NULL +#endif + +#ifdef _MAXIMIZER_ENABLED +extern EAS_VOID_PTR EAS_Maximizer; +#define EAS_MAXIMIZER_INTERFACE &EAS_Maximizer +#ifdef _STATIC_MEMORY +extern EAS_VOID_PTR eas_MaximizerData; +#define EAS_MAXIMIZER_DATA &eas_MaximizerData +#else +#define EAS_MAXIMIZER_DATA NULL +#endif +#else +#define EAS_MAXIMIZER_INTERFACE NULL +#define EAS_MAXIMIZER_DATA NULL +#endif + + +#ifdef _REVERB_ENABLED +extern EAS_VOID_PTR EAS_Reverb; +#define EAS_REVERB_INTERFACE &EAS_Reverb +#ifdef _STATIC_MEMORY +extern EAS_VOID_PTR eas_ReverbData; +#define EAS_REVERB_DATA &eas_ReverbData +#else +#define EAS_REVERB_DATA NULL +#endif +#else +#define EAS_REVERB_INTERFACE NULL +#define EAS_REVERB_DATA NULL +#endif + +#ifdef _CHORUS_ENABLED +extern EAS_VOID_PTR EAS_Chorus; +#define EAS_CHORUS_INTERFACE &EAS_Chorus +#ifdef _STATIC_MEMORY +extern EAS_VOID_PTR eas_ChorusData; +#define EAS_CHORUS_DATA &eas_ChorusData +#else +#define EAS_CHORUS_DATA NULL +#endif +#else +#define EAS_CHORUS_INTERFACE NULL +#define EAS_CHORUS_DATA NULL +#endif + +#ifdef _WIDENER_ENABLED +extern EAS_VOID_PTR EAS_Widener; +#define EAS_WIDENER_INTERFACE &EAS_Widener +#ifdef _STATIC_MEMORY +extern EAS_VOID_PTR eas_WidenerData; +#define EAS_WIDENER_DATA &eas_WidenerData +#else +#define EAS_WIDENER_DATA NULL +#endif +#else +#define EAS_WIDENER_INTERFACE NULL +#define EAS_WIDENER_DATA NULL +#endif + +#ifdef _GRAPHIC_EQ_ENABLED +extern EAS_VOID_PTR EAS_GraphicEQ; +#define EAS_GRAPHIC_EQ_INTERFACE &EAS_GraphicEQ +#ifdef _STATIC_MEMORY +extern EAS_VOID_PTR eas_GraphicEQData; +#define EAS_GRAPHIC_EQ_DATA &eas_GraphicEQData +#else +#define EAS_GRAPHIC_EQ_DATA NULL +#endif +#else +#define EAS_GRAPHIC_EQ_INTERFACE NULL +#define EAS_GRAPHIC_EQ_DATA NULL +#endif + +#ifdef _WOW_ENABLED +extern EAS_VOID_PTR EAS_Wow; +#define EAS_WOW_INTERFACE &EAS_Wow +#ifdef _STATIC_MEMORY +#error "WOW module requires dynamic memory model" +#else +#define EAS_WOW_DATA NULL +#endif +#else +#define EAS_WOW_INTERFACE NULL +#define EAS_WOW_DATA NULL +#endif + +#ifdef _TONECONTROLEQ_ENABLED +extern EAS_VOID_PTR EAS_ToneControlEQ; +#define EAS_TONECONTROLEQ_INTERFACE &EAS_ToneControlEQ +#ifdef _STATIC_MEMORY +extern EAS_VOID_PTR eas_ToneControlEQData; +#define EAS_TONECONTROLEQ_DATA &eas_ToneControlEQData +#else +#define EAS_TONECONTROLEQ_DATA NULL +#endif +#else +#define EAS_TONECONTROLEQ_INTERFACE NULL +#define EAS_TONECONTROLEQ_DATA NULL +#endif + +/*lint -e{605} not pretty, but it works */ +EAS_VOID_PTR const effectsModules[] = +{ + EAS_ENHANCER_INTERFACE, + EAS_COMPRESSOR_INTERFACE, + EAS_REVERB_INTERFACE, + EAS_CHORUS_INTERFACE, + EAS_WIDENER_INTERFACE, + EAS_GRAPHIC_EQ_INTERFACE, + EAS_WOW_INTERFACE, + EAS_MAXIMIZER_INTERFACE, + EAS_TONECONTROLEQ_INTERFACE +}; + +EAS_VOID_PTR const effectsData[] = +{ + EAS_ENHANCER_DATA, + EAS_COMPRESSOR_DATA, + EAS_REVERB_DATA, + EAS_CHORUS_DATA, + EAS_WIDENER_DATA, + EAS_GRAPHIC_EQ_DATA, + EAS_WOW_DATA, + EAS_MAXIMIZER_DATA, + EAS_TONECONTROLEQ_DATA +}; + +/*---------------------------------------------------------------------------- + * + * Optional Modules + * + * These declarations are used by the EAS library to locate + * effects modules. + *---------------------------------------------------------------------------- +*/ + +#ifdef _METRICS_ENABLED +extern EAS_VOID_PTR EAS_Metrics; +#define EAS_METRICS_INTERFACE &EAS_Metrics +#ifdef _STATIC_MEMORY +extern EAS_VOID_PTR eas_MetricsData; +#define EAS_METRICS_DATA &eas_MetricsData +#else +#define EAS_METRICS_DATA NULL +#endif +#else +#define EAS_METRICS_INTERFACE NULL +#define EAS_METRICS_DATA NULL +#endif + +#ifdef MMAPI_SUPPORT +extern EAS_VOID_PTR EAS_TC_Parser; +#define EAS_TONE_CONTROL_PARSER &EAS_TC_Parser +#ifdef _STATIC_MEMORY +extern EAS_VOID_PTR eas_TCData; +#define EAS_TONE_CONTROL_DATA &eas_TCData +#else +#define EAS_TONE_CONTROL_DATA NULL +#endif +#else +#define EAS_TONE_CONTROL_PARSER NULL +#define EAS_TONE_CONTROL_DATA NULL +#endif + +/*lint -e{605} not pretty, but it works */ +EAS_VOID_PTR const optionalModules[] = +{ + EAS_TONE_CONTROL_PARSER, + EAS_METRICS_INTERFACE +}; + +EAS_VOID_PTR const optionalData[] = +{ + EAS_TONE_CONTROL_DATA, + EAS_METRICS_DATA +}; + +/*---------------------------------------------------------------------------- + * EAS_CMStaticMemoryModel() + *---------------------------------------------------------------------------- + * Purpose: + * This function returns true if EAS has been configured for + * a static memory model. There are some limitations in the + * static memory model, see the documentation for more + * information. + * + * Outputs: + * returns EAS_TRUE if a module is found + *---------------------------------------------------------------------------- +*/ +EAS_BOOL EAS_CMStaticMemoryModel (void) +{ +#ifdef _STATIC_MEMORY + return EAS_TRUE; +#else + return EAS_FALSE; +#endif +} + +/*---------------------------------------------------------------------------- + * EAS_CMEnumModules() + *---------------------------------------------------------------------------- + * Purpose: + * This function is used to find pointers to optional modules. + * + * Inputs: + * module - module number + * + * Outputs: + * returns a pointer to the module function table or NULL if no module + *---------------------------------------------------------------------------- +*/ +EAS_VOID_PTR EAS_CMEnumModules (EAS_INT module) +{ + + if (module >= (EAS_INT) NUM_PARSER_MODULES) + return NULL; + return parserModules[module]; +} + +/*---------------------------------------------------------------------------- + * EAS_CMEnumData() + *---------------------------------------------------------------------------- + * Purpose: + * This function is used to find pointers to static memory allocations. + * + * Inputs: + * dataModule - enumerated module number + * + * Outputs: + * Returns handle to data or NULL if not found + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, dataModule) used only when _STATIC_MEMORY is defined */ +EAS_VOID_PTR EAS_CMEnumData (EAS_INT dataModule) +{ + +#ifdef _STATIC_MEMORY + switch (dataModule) + { + + /* main instance data for synthesizer */ + case EAS_CM_EAS_DATA: + return &eas_Data; + + /* mix buffer for mix engine */ + case EAS_CM_MIX_BUFFER: + /*lint -e{545} lint doesn't like this because it sees the underlying type */ + return &eas_MixBuffer; + + /* instance data for synth */ + case EAS_CM_SYNTH_DATA: + return &eas_Synth; + + /* instance data for MIDI parser */ + case EAS_CM_MIDI_DATA: + return &eas_MIDI; + + /* instance data for SMF parser */ + case EAS_CM_SMF_DATA: + return &eas_SMFData; + +#ifdef _XMF_PARSER + /* instance data for XMF parser */ + case EAS_CM_XMF_DATA: + return &eas_XMFData; +#endif + +#ifdef _SMAF_PARSER + /* instance data for SMAF parser */ + case EAS_CM_SMAF_DATA: + return &eas_SMAFData; +#endif + + /* instance data for the PCM engine */ + case EAS_CM_PCM_DATA: + /*lint -e{545} lint doesn't like this because it sees the underlying type */ + return &eas_PCMData; + + case EAS_CM_MIDI_STREAM_DATA: + return &eas_MIDIData; + +#ifdef _OTA_PARSER + /* instance data for OTA parser */ + case EAS_CM_OTA_DATA: + return &eas_OTAData; +#endif + +#ifdef _IMELODY_PARSER + /* instance data for iMelody parser */ + case EAS_CM_IMELODY_DATA: + return &eas_iMelodyData; +#endif + +#ifdef _RTTTL_PARSER + /* instance data for RTTTL parser */ + case EAS_CM_RTTTL_DATA: + return &eas_RTTTLData; +#endif + +#ifdef _WAVE_PARSER + /* instance data for WAVE parser */ + case EAS_CM_WAVE_DATA: + return &eas_WaveData; +#endif + +#if defined (_CMX_PARSER) || defined(_MFI_PARSER) + /* instance data for CMF parser */ + case EAS_CM_CMF_DATA: + return &eas_CMFData; +#endif + + default: + return NULL; + } + +#else + return NULL; +#endif +} + +/*---------------------------------------------------------------------------- + * EAS_CMEnumFXModules() + *---------------------------------------------------------------------------- + * Purpose: + * This function is used to find pointers to optional effects modules. + * + * Inputs: + * module - enumerated module number + * pModule - pointer to module interface + * + * Outputs: + * Returns pointer to function table or NULL if not found + *---------------------------------------------------------------------------- +*/ +EAS_VOID_PTR EAS_CMEnumFXModules (EAS_INT module) +{ + + if (module >= NUM_EFFECTS_MODULES) + return NULL; + return effectsModules[module]; +} + +/*---------------------------------------------------------------------------- + * EAS_CMEnumFXData() + *---------------------------------------------------------------------------- + * Purpose: + * This function is used to find pointers to static memory allocations. + * + * Inputs: + * dataModule - enumerated module number + * pData - pointer to handle variable + * + * Outputs: + * Returns handle to data or NULL if not found + *---------------------------------------------------------------------------- +*/ +EAS_VOID_PTR EAS_CMEnumFXData (EAS_INT dataModule) +{ + + if (dataModule >= NUM_EFFECTS_MODULES) + return NULL; + return effectsData[dataModule]; +} + +/*---------------------------------------------------------------------------- + * EAS_CMEnumOptModules() + *---------------------------------------------------------------------------- + * Purpose: + * This function is used to find pointers to optional modules. + * + * Inputs: + * module - enumerated module number + * + * Outputs: + * returns pointer to function table or NULL if no module + *---------------------------------------------------------------------------- +*/ +EAS_VOID_PTR EAS_CMEnumOptModules (EAS_INT module) +{ + + /* sanity check */ + if (module >= NUM_OPTIONAL_MODULES) + return EAS_FALSE; + return optionalModules[module]; +} + +/*---------------------------------------------------------------------------- + * EAS_CMEnumOptData() + *---------------------------------------------------------------------------- + * Purpose: + * This function is used to find pointers to static memory allocations. + * + * Inputs: + * dataModule - enumerated module number + * + * Outputs: + * Returns handle to data or NULL if not found + *---------------------------------------------------------------------------- +*/ +EAS_VOID_PTR EAS_CMEnumOptData (EAS_INT dataModule) +{ + + if (dataModule >= NUM_OPTIONAL_MODULES) + return NULL; + return optionalData[dataModule]; +} + + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_config.h b/common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_config.h new file mode 100755 index 0000000..49c2ef2 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_config.h @@ -0,0 +1,191 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_config.h + * + * Contents and purpose: + * This header declares the Configuration Module interface (CM). The CM + * is a module compiled external to the library that sets the configuration + * for this build. It allows the library to find optional components and + * links to static memory allocations (when used in a static configuration). + * + * NOTE: This module is not intended to be modified by the customer. It + * needs to be included in the build process with the correct configuration + * defines (see the library documentation for information on how to configure + * the library). + * + * DO NOT MODIFY THIS FILE! + * + * Copyright 2005 Sonic Network Inc. + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +// sentinel +#ifndef _EAS_CONFIG_H +#define _EAS_CONFIG_H + +#include "eas_types.h" + +/* list of enumerators for optional modules */ +typedef enum { + EAS_CM_FILE_PARSERS = 1 +} E_CM_ENUM_MODULES; + +/* list of enumerators for module and memory pointers */ +typedef enum { + EAS_CM_EAS_DATA = 1, + EAS_CM_MIX_BUFFER, + EAS_CM_SYNTH_DATA, + EAS_CM_MIDI_DATA, + EAS_CM_SMF_DATA, + EAS_CM_XMF_DATA, + EAS_CM_SMAF_DATA, + EAS_CM_PCM_DATA, + EAS_CM_MIDI_STREAM_DATA, + EAS_CM_METRICS_DATA, + EAS_CM_OTA_DATA, + EAS_CM_IMELODY_DATA, + EAS_CM_RTTTL_DATA, + EAS_CM_WAVE_DATA, + EAS_CM_CMF_DATA +} E_CM_DATA_MODULES; + +typedef struct +{ + int maxSMFStreams; + void *pSMFData; + void *pSMFStream; +} S_EAS_SMF_PTRS; + +typedef struct +{ + int maxSMAFStreams; + void *pSMAFData; + void *pSMAFStream; +} S_EAS_SMAF_PTRS; + +/*---------------------------------------------------------------------------- + * EAS_CMStaticMemoryModel() + *---------------------------------------------------------------------------- + * Purpose: + * This function returns true if EAS has been configured for + * a static memory model. There are some limitations in the + * static memory model, see the documentation for more + * information. + * + * Outputs: + * returns EAS_TRUE if a module is found + *---------------------------------------------------------------------------- +*/ +EAS_BOOL EAS_CMStaticMemoryModel (void); + +/*---------------------------------------------------------------------------- + * EAS_CMEnumModules() + *---------------------------------------------------------------------------- + * Purpose: + * This function is used to find pointers to optional modules. + * + * Inputs: + * module - module number + * + * Outputs: + * returns a pointer to the module function table or NULL if no module + *---------------------------------------------------------------------------- +*/ +EAS_VOID_PTR EAS_CMEnumModules (EAS_INT module); + +/*---------------------------------------------------------------------------- + * EAS_CMEnumData() + *---------------------------------------------------------------------------- + * Purpose: + * This function is used to find pointers to static memory allocations. + * + * Inputs: + * dataModule - enumerated module number + * + * Outputs: + * Returns handle to data or NULL if not found + *---------------------------------------------------------------------------- +*/ +EAS_VOID_PTR EAS_CMEnumData (EAS_INT dataModule); + +/*---------------------------------------------------------------------------- + * EAS_CMEnumFXModules() + *---------------------------------------------------------------------------- + * Purpose: + * This function is used to find pointers to optional effects modules. + * + * Inputs: + * module - enumerated module number + * pModule - pointer to module interface + * + * Outputs: + * Returns pointer to function table or NULL if not found + *---------------------------------------------------------------------------- +*/ +EAS_VOID_PTR EAS_CMEnumFXModules (EAS_INT module); + +/*---------------------------------------------------------------------------- + * EAS_CMEnumFXData() + *---------------------------------------------------------------------------- + * Purpose: + * This function is used to find pointers to static memory allocations. + * + * Inputs: + * dataModule - enumerated module number + * pData - pointer to handle variable + * + * Outputs: + * Returns handle to data or NULL if not found + *---------------------------------------------------------------------------- +*/ +EAS_VOID_PTR EAS_CMEnumFXData (EAS_INT dataModule); + +/*---------------------------------------------------------------------------- + * EAS_CMEnumOptModules() + *---------------------------------------------------------------------------- + * Purpose: + * This function is used to find pointers to optional modules. + * + * Inputs: + * module - enumerated module number + * + * Outputs: + * returns pointer to function table or NULL if no module + *---------------------------------------------------------------------------- +*/ +EAS_VOID_PTR EAS_CMEnumOptModules (EAS_INT module); + +/*---------------------------------------------------------------------------- + * EAS_CMEnumOptData() + *---------------------------------------------------------------------------- + * Purpose: + * This function is used to find pointers to static memory allocations. + * + * Inputs: + * dataModule - enumerated module number + * + * Outputs: + * Returns handle to data or NULL if not found + *---------------------------------------------------------------------------- +*/ +EAS_VOID_PTR EAS_CMEnumOptData (EAS_INT dataModule); + +#endif /* end _EAS_CONFIG_H */ diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_debugmsgs.h b/common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_debugmsgs.h new file mode 100755 index 0000000..25913bd --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_debugmsgs.h @@ -0,0 +1,87 @@ +/* Auto-generated from source file: eas_chorusdata.c */ +/* Auto-generated from source file: eas_xmfdata.c */ +/* Auto-generated from source file: eas_mdls.c */ +{ 0x19299ed4, 0x00000022, "eas_mdls.c[2561]: #Instruments: %u\n" }, +{ 0x19299ed4, 0x00000023, "eas_mdls.c[2562]: #Regions: %u\n" }, +{ 0x19299ed4, 0x00000024, "eas_mdls.c[2563]: #Articulations: %u\n" }, +{ 0x19299ed4, 0x00000025, "eas_mdls.c[2564]: #Waves: %u\n" }, +{ 0x19299ed4, 0x00000026, "eas_mdls.c[2569]: Locale: %lu:%lu:%lu\n" }, +{ 0x19299ed4, 0x00000027, "eas_mdls.c[2576]: \tRegion: %u\n" }, +{ 0x19299ed4, 0x00000028, "eas_mdls.c[2578]: \t\tm_nGain: %d\n" }, +{ 0x19299ed4, 0x00000029, "eas_mdls.c[2579]: \t\trangeLow:rangeHigh %u:%u\n" }, +{ 0x19299ed4, 0x0000002a, "eas_mdls.c[2580]: \t\tm_nKeyGroupAndFlags: %04x\n" }, +{ 0x19299ed4, 0x0000002b, "eas_mdls.c[2581]: \t\tm_nLoopStart: %u\n" }, +{ 0x19299ed4, 0x0000002c, "eas_mdls.c[2582]: \t\tm_nLoopEnd: %u\n" }, +{ 0x19299ed4, 0x0000002d, "eas_mdls.c[2583]: \t\tm_nNetTuningInCents: %d\n" }, +{ 0x19299ed4, 0x0000002e, "eas_mdls.c[2584]: \t\tArt Index: %u\n" }, +{ 0x19299ed4, 0x0000002f, "eas_mdls.c[2585]: \t\tWave Index: %u\n" }, +{ 0x19299ed4, 0x00000030, "eas_mdls.c[2597]: Articulation: %u\n" }, +{ 0x19299ed4, 0x00000031, "eas_mdls.c[2599]: \t\tm_nEG2toFilterDepth: %d\n" }, +{ 0x19299ed4, 0x00000032, "eas_mdls.c[2600]: \t\tm_nEG2toPitchDepth: %d\n" }, +{ 0x19299ed4, 0x00000033, "eas_mdls.c[2601]: \t\tm_nFilterCutoffFrequency: %d\n" }, +{ 0x19299ed4, 0x00000034, "eas_mdls.c[2602]: \t\tm_nFilterResonance: %u\n" }, +{ 0x19299ed4, 0x00000035, "eas_mdls.c[2603]: \t\tm_nLFOAmplitudeDepth: %d\n" }, +{ 0x19299ed4, 0x00000036, "eas_mdls.c[2604]: \t\tm_nLFODelayTime: %d\n" }, +{ 0x19299ed4, 0x00000037, "eas_mdls.c[2605]: \t\tm_nLFOFrequency: %d\n" }, +{ 0x19299ed4, 0x00000038, "eas_mdls.c[2606]: \t\tm_nLFOPitchDepth: %d\n" }, +{ 0x19299ed4, 0x00000039, "eas_mdls.c[2607]: \t\tm_nPan: %d\n" }, +{ 0x19299ed4, 0x0000003a, "eas_mdls.c[2610]: \t\tm_nAttack: %d\n" }, +{ 0x19299ed4, 0x0000003b, "eas_mdls.c[2611]: \t\tm_nDecay: %d\n" }, +{ 0x19299ed4, 0x0000003c, "eas_mdls.c[2612]: \t\tm_nSustain: %d\n" }, +{ 0x19299ed4, 0x0000003d, "eas_mdls.c[2613]: \t\tm_nRelease: %d\n" }, +{ 0x19299ed4, 0x0000003e, "eas_mdls.c[2616]: \t\tm_nAttack: %d\n" }, +{ 0x19299ed4, 0x0000003f, "eas_mdls.c[2617]: \t\tm_nDecay: %d\n" }, +{ 0x19299ed4, 0x00000040, "eas_mdls.c[2618]: \t\tm_nSustain: %d\n" }, +{ 0x19299ed4, 0x00000041, "eas_mdls.c[2619]: \t\tm_nRelease: %d\n" }, +{ 0x19299ed4, 0x00000042, "eas_mdls.c[2626]: Wave Index: %d\n" }, +{ 0x19299ed4, 0x00000043, "eas_mdls.c[2627]: \tSize %u\n" }, +{ 0x19299ed4, 0x00000044, "eas_mdls.c[2628]: \tPointer %08lx\n" }, +/* Auto-generated from source file: eas_mididata.c */ +/* Auto-generated from source file: eas_pan.c */ +/* Auto-generated from source file: eas_wavefiledata.c */ +/* Auto-generated from source file: eas_reverbdata.c */ +/* Auto-generated from source file: eas_imelodydata.c */ +/* Auto-generated from source file: eas_ota.c */ +/* Auto-generated from source file: eas_mixbuf.c */ +/* Auto-generated from source file: eas_tcdata.c */ +/* Auto-generated from source file: jet.c */ +/* Auto-generated from source file: eas_rtttl.c */ +/* Auto-generated from source file: eas_reverb.c */ +/* Auto-generated from source file: eas_pcmdata.c */ +/* Auto-generated from source file: eas_chorus.c */ +/* Auto-generated from source file: eas_math.c */ +/* Auto-generated from source file: eas_xmf.c */ +/* Auto-generated from source file: eas_smfdata.c */ +/* Auto-generated from source file: eas_imelody.c */ +/* Auto-generated from source file: eas_dlssynth.c */ +/* Auto-generated from source file: eas_public.c */ +/* Auto-generated from source file: eas_rtttldata.c */ +/* Auto-generated from source file: eas_voicemgt.c */ +/* Auto-generated from source file: eas_tonecontrol.c */ +/* Auto-generated from source file: eas_wtengine.c */ +/* Auto-generated from source file: eas_imaadpcm.c */ +{ 0x2380b977, 0x00000006, "eas_imaadpcm.c[305]: IMADecoderLocate: Time=%d, samples=%d\n" }, +{ 0x2380b977, 0x00000007, "eas_imaadpcm.c[328]: IMADecoderLocate: Looped sample, numBlocks=%d, samplesPerLoop=%d, samplesInLastBlock=%d, samples=%d\n" }, +{ 0x2380b977, 0x00000008, "eas_imaadpcm.c[335]: IMADecoderLocate: Byte location in audio = %d\n" }, +{ 0x2380b977, 0x00000009, "eas_imaadpcm.c[345]: IMADecoderLocate: bytesLeft = %d\n" }, +/* Auto-generated from source file: eas_flog.c */ +/* Auto-generated from source file: eas_midi.c */ +/* Auto-generated from source file: eas_otadata.c */ +/* Auto-generated from source file: eas_ima_tables.c */ +/* Auto-generated from source file: eas_data.c */ +/* Auto-generated from source file: eas_pcm.c */ +/* Auto-generated from source file: eas_mixer.c */ +/* Auto-generated from source file: eas_wavefile.c */ +/* Auto-generated from source file: eas_wtsynth.c */ +/* Auto-generated from source file: eas_smf.c */ +/* Auto-generated from source file: eas_wave.c */ +/* Auto-generated from source file: eas_hostmm.c */ +{ 0x1a54b6e8, 0x00000001, "eas_hostmm.c[586]: Vibrate state: %d\n" }, +{ 0x1a54b6e8, 0x00000002, "eas_hostmm.c[601]: LED state: %d\n" }, +{ 0x1a54b6e8, 0x00000003, "eas_hostmm.c[616]: Backlight state: %d\n" }, +{ 0x1a54b6e8, 0x00000004, "eas_hostmm.c[162]: HWMemCpy: bad amount: %d\n" }, +{ 0x1a54b6e8, 0x00000005, "eas_hostmm.c[179]: HWMemSet: bad amount: %d\n" }, +{ 0x1a54b6e8, 0x00000006, "eas_hostmm.c[196]: HWMemCmp: bad amount: %d\n" }, +/* Auto-generated from source file: eas_config.c */ +/* Auto-generated from source file: eas_main.c */ +{ 0xe624f4d9, 0x00000005, "eas_main.c[106]: Play length: %d.%03d (secs)\n" }, diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_host.h b/common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_host.h new file mode 100755 index 0000000..8567432 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_host.h @@ -0,0 +1,87 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_host.h + * + * Contents and purpose: + * This header defines the host wrapper functions for stdio, stdlib, etc. + * The host application must provide an abstraction layer for these functions + * to support certain features, such as SMAF and SMF-1 conversion. + * + * DO NOT MODIFY THIS FILE! + * + * Copyright 2005 Sonic Network Inc. + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +// sentinel +#ifndef _EAS_HOST_H +#define _EAS_HOST_H + +#include "eas_types.h" + +/* for C++ linkage */ +#ifdef __cplusplus +extern "C" { +#endif + +/* initialization and shutdown routines */ +extern EAS_RESULT EAS_HWInit(EAS_HW_DATA_HANDLE *hwInstData); +extern EAS_RESULT EAS_HWShutdown(EAS_HW_DATA_HANDLE hwInstData); + +/* threading */ +extern void* EAS_HWRegisterSignalHandler(); +extern EAS_RESULT EAS_HWUnRegisterSignalHandler(void *cookie); + +/* memory functions */ +extern void *EAS_HWMemSet(void *s, int c, EAS_I32 n); +extern void *EAS_HWMemCpy(void *s1, const void *s2, EAS_I32 n); +extern EAS_I32 EAS_HWMemCmp(const void *s1, const void *s2, EAS_I32 n); + +/* memory allocation */ +extern void *EAS_HWMalloc(EAS_HW_DATA_HANDLE hwInstData, EAS_I32 size); +extern void EAS_HWFree(EAS_HW_DATA_HANDLE hwInstData, void *p); + +/* file I/O */ +extern EAS_RESULT EAS_HWOpenFile(EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_LOCATOR locator, EAS_FILE_HANDLE *pFile, EAS_FILE_MODE mode); +extern EAS_RESULT EAS_HWReadFile(EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *pBuffer, EAS_I32 n, EAS_I32 *pBytesRead); +extern EAS_RESULT EAS_HWGetByte(EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *p); +extern EAS_RESULT EAS_HWGetWord (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *p, EAS_BOOL msbFirst); +extern EAS_RESULT EAS_HWGetDWord (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *p, EAS_BOOL msbFirst); +extern EAS_RESULT EAS_HWFilePos (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 *pPosition); +extern EAS_RESULT EAS_HWFileSeek (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 position); +extern EAS_RESULT EAS_HWFileSeekOfs (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 position); +extern EAS_RESULT EAS_HWFileLength (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 *pLength); +extern EAS_RESULT EAS_HWDupHandle (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_FILE_HANDLE* pFile); +extern EAS_RESULT EAS_HWCloseFile (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file); + +/* vibrate, LED, and backlight functions */ +extern EAS_RESULT EAS_HWVibrate(EAS_HW_DATA_HANDLE hwInstData, EAS_BOOL state); +extern EAS_RESULT EAS_HWLED(EAS_HW_DATA_HANDLE hwInstData, EAS_BOOL state); +extern EAS_RESULT EAS_HWBackLight(EAS_HW_DATA_HANDLE hwInstData, EAS_BOOL state); + +#ifdef __cplusplus +} /* end extern "C" */ +#endif + + +/* host yield function */ +extern EAS_BOOL EAS_HWYield(EAS_HW_DATA_HANDLE hwInstData); +#endif /* end _EAS_HOST_H */ diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_hostmm.c b/common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_hostmm.c new file mode 100755 index 0000000..ea4fcf7 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_hostmm.c @@ -0,0 +1,688 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_hostmm.c + * + * Contents and purpose: + * This file contains the host wrapper functions for stdio, stdlib, etc. + * This is a sample version that reads from a filedescriptor. + * The file locator (EAS_FILE_LOCATOR) handle passed to + * HWOpenFile is the same one that is passed to EAS_OpenFile. + * + * Modify this file to suit the needs of your particular system. + * + * EAS_MAX_FILE_HANDLES sets the maximum number of MIDI streams within + * a MIDI type 1 file that can be played. + * + * EAS_HW_FILE is a structure to support the file I/O functions. It + * comprises the file descriptor, the file read pointer, and + * the dup flag, which when set, indicates that the file handle has + * been duplicated, and offset and length within the file. + * + * Copyright 2005 Sonic Network Inc. + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 795 $ + * $Date: 2007-08-01 00:14:45 -0700 (Wed, 01 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifdef _lint +#include "lint_stdlib.h" +#else +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define LOG_TAG "Sonivox" +#endif + +#include "eas_host.h" + +/* Only for debugging LED, vibrate, and backlight functions */ +#include "eas_report.h" + +/* this module requires dynamic memory support */ +#ifdef _STATIC_MEMORY +#error "eas_hostmm.c requires the dynamic memory model!\n" +#endif + +#ifndef EAS_MAX_FILE_HANDLES +// 100 max file handles == 3 * (nb tracks(32) + 1 for the segment) + 1 for jet file +// 3 == 1(playing segment) + 1(prepared segment) +// + 1(after end of playing segment, before files closed) +#define EAS_MAX_FILE_HANDLES 100 +#endif + +/* + * this structure and the related function are here + * to support the ability to create duplicate handles + * and buffering it in memory. If your system uses + * in-memory resources, you can eliminate the calls + * to malloc and free, the dup flag, and simply track + * the file size and read position. + */ +typedef struct eas_hw_file_tag +{ + EAS_I32 fileSize; + EAS_I32 filePos; + EAS_BOOL dup; + int fd; + EAS_I32 offset; +} EAS_HW_FILE; + +typedef struct eas_hw_inst_data_tag +{ + EAS_HW_FILE files[EAS_MAX_FILE_HANDLES]; +} EAS_HW_INST_DATA; + +pthread_key_t EAS_sigbuskey; + +/*---------------------------------------------------------------------------- + * EAS_HWInit + * + * Initialize host wrapper interface + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_HWInit (EAS_HW_DATA_HANDLE *pHWInstData) +{ + EAS_HW_FILE *file; + int i; + + /* need to track file opens for duplicate handles */ + *pHWInstData = malloc(sizeof(EAS_HW_INST_DATA)); + if (!(*pHWInstData)) + return EAS_ERROR_MALLOC_FAILED; + + EAS_HWMemSet(*pHWInstData, 0, sizeof(EAS_HW_INST_DATA)); + + file = (*pHWInstData)->files; + for (i = 0; i < EAS_MAX_FILE_HANDLES; i++) + { + file->fd = -1; + file++; + } + + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_HWShutdown + * + * Shut down host wrapper interface + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_HWShutdown (EAS_HW_DATA_HANDLE hwInstData) +{ + + free(hwInstData); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWMalloc + * + * Allocates dynamic memory + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +void *EAS_HWMalloc (EAS_HW_DATA_HANDLE hwInstData, EAS_I32 size) +{ + /* Since this whole library loves signed sizes, let's not let + * negative or 0 values through */ + if (size <= 0) + return NULL; + return malloc((size_t) size); +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWFree + * + * Frees dynamic memory + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +void EAS_HWFree (EAS_HW_DATA_HANDLE hwInstData, void *p) +{ + free(p); +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWMemCpy + * + * Copy memory wrapper + * + *---------------------------------------------------------------------------- +*/ +void *EAS_HWMemCpy (void *dest, const void *src, EAS_I32 amount) +{ + if (amount < 0) { + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x1a54b6e8, 0x00000004 , amount); + exit(255); + } + return memcpy(dest, src, (size_t) amount); +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWMemSet + * + * Set memory wrapper + * + *---------------------------------------------------------------------------- +*/ +void *EAS_HWMemSet (void *dest, int val, EAS_I32 amount) +{ + if (amount < 0) { + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x1a54b6e8, 0x00000005 , amount); + exit(255); + } + return memset(dest, val, (size_t) amount); +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWMemCmp + * + * Compare memory wrapper + * + *---------------------------------------------------------------------------- +*/ +EAS_I32 EAS_HWMemCmp (const void *s1, const void *s2, EAS_I32 amount) +{ + if (amount < 0) { + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x1a54b6e8, 0x00000006 , amount); + exit(255); + } + return (EAS_I32) memcmp(s1, s2, (size_t) amount); +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWOpenFile + * + * Open a file for read or write + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_HWOpenFile (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_LOCATOR locator, EAS_FILE_HANDLE *pFile, EAS_FILE_MODE mode) +{ + EAS_HW_FILE *file; + int fd; + int i; + + /* set return value to NULL */ + *pFile = NULL; + + /* only support read mode at this time */ + if (mode != EAS_FILE_READ) + return EAS_ERROR_INVALID_FILE_MODE; + + /* find an empty entry in the file table */ + file = hwInstData->files; + for (i = 0; i < EAS_MAX_FILE_HANDLES; i++) + { + /* is this slot being used? */ + if (file->fd < 0) + { + if (locator->path) { + /* open the file */ + if ((fd = open(locator->path, O_RDONLY)) < 0) { + return EAS_ERROR_FILE_OPEN_FAILED; + } + } else { + /* else file is already open */ + fd = dup(locator->fd); + } + + /* determine the file size */ + if (locator->length == 0) { + if (lseek(fd, 0, SEEK_END) < 0) { + close(fd); + return EAS_ERROR_FILE_LENGTH; + } + if ((file->fileSize = (EAS_I32)lseek(fd, 0, SEEK_CUR)) == -1L) { + close(fd); + return EAS_ERROR_FILE_LENGTH; + } + } + + // file size was passed in + else { + file->fileSize = (EAS_I32) locator->length; + } + + file->fd = fd; + file->offset = (EAS_I32)locator->offset; + + /* initialize some values */ + file->filePos = 0; + file->dup = EAS_FALSE; + + *pFile = file; + return EAS_SUCCESS; + } + file++; + } + + /* too many open files */ + return EAS_ERROR_MAX_FILES_OPEN; +} + + +/*---------------------------------------------------------------------------- + * + * EAS_HWReadFile + * + * Read data from a file + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWReadFile (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *pBuffer, EAS_I32 n, EAS_I32 *pBytesRead) +{ + EAS_I32 count; + + /* make sure we have a valid handle */ + if (file->fd < 0) + return EAS_ERROR_INVALID_HANDLE; + + if (n < 0) + return EAS_EOF; + + /* calculate the bytes to read */ + count = file->fileSize - file->filePos; + if (n < count) + count = n; + if (count < 0) + return EAS_EOF; + + /* copy the data to the requested location, and advance the pointer */ + if (count) { + lseek(file->fd, file->filePos + file->offset, SEEK_SET); + count = read(file->fd, pBuffer, count); + } + file->filePos += count; + *pBytesRead = count; + + /* were n bytes read? */ + if (count!= n) + return EAS_EOF; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWGetByte + * + * Read a byte from a file + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWGetByte (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *p) +{ + EAS_I32 numread; + return EAS_HWReadFile(hwInstData, file, p, 1, &numread); +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWGetWord + * + * Read a 16 bit word from a file + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWGetWord (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *p, EAS_BOOL msbFirst) +{ + EAS_RESULT result; + EAS_U8 c1, c2; + + /* read 2 bytes from the file */ + if ((result = EAS_HWGetByte(hwInstData, file, &c1)) != EAS_SUCCESS) + return result; + if ((result = EAS_HWGetByte(hwInstData, file, &c2)) != EAS_SUCCESS) + return result; + + /* order them as requested */ + if (msbFirst) + *((EAS_U16*) p) = ((EAS_U16) c1 << 8) | c2; + else + *((EAS_U16*) p) = ((EAS_U16) c2 << 8) | c1; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWGetDWord + * + * Returns the current location in the file + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWGetDWord (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *p, EAS_BOOL msbFirst) +{ + EAS_RESULT result; + EAS_U8 c1, c2,c3,c4; + + /* read 4 bytes from the file */ + if ((result = EAS_HWGetByte(hwInstData, file, &c1)) != EAS_SUCCESS) + return result; + if ((result = EAS_HWGetByte(hwInstData, file, &c2)) != EAS_SUCCESS) + return result; + if ((result = EAS_HWGetByte(hwInstData, file, &c3)) != EAS_SUCCESS) + return result; + if ((result = EAS_HWGetByte(hwInstData, file, &c4)) != EAS_SUCCESS) + return result; + + /* order them as requested */ + if (msbFirst) + *((EAS_U32*) p) = ((EAS_U32) c1 << 24) | ((EAS_U32) c2 << 16) | ((EAS_U32) c3 << 8) | c4; + else + *((EAS_U32*) p)= ((EAS_U32) c4 << 24) | ((EAS_U32) c3 << 16) | ((EAS_U32) c2 << 8) | c1; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWFilePos + * + * Returns the current location in the file + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWFilePos (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 *pPosition) +{ + + /* make sure we have a valid handle */ + if (file->fd < 0) + return EAS_ERROR_INVALID_HANDLE; + + *pPosition = file->filePos; + return EAS_SUCCESS; +} /* end EAS_HWFilePos */ + +/*---------------------------------------------------------------------------- + * + * EAS_HWFileSeek + * + * Seek to a specific location in the file + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWFileSeek (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 position) +{ + + /* make sure we have a valid handle */ + if (file->fd < 0) + return EAS_ERROR_INVALID_HANDLE; + + /* validate new position */ + if ((position < 0) || (position > file->fileSize)) + return EAS_ERROR_FILE_SEEK; + + /* save new position */ + file->filePos = position; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWFileSeekOfs + * + * Seek forward or back relative to the current position + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWFileSeekOfs (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 position) +{ + + /* make sure we have a valid handle */ + if (file->fd < 0) + return EAS_ERROR_INVALID_HANDLE; + + /* determine the file position */ + position += file->filePos; + if ((position < 0) || (position > file->fileSize)) + return EAS_ERROR_FILE_SEEK; + + /* save new position */ + file->filePos = position; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWFileLength + * + * Return the file length + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWFileLength (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 *pLength) +{ + + /* make sure we have a valid handle */ + if (file->fd < 0) + return EAS_ERROR_INVALID_HANDLE; + + *pLength = file->fileSize; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWDupHandle + * + * Duplicate a file handle + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_HWDupHandle (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_FILE_HANDLE *pDupFile) +{ + EAS_HW_FILE *dupFile; + int i; + + /* make sure we have a valid handle */ + if (file->fd < 0) + return EAS_ERROR_INVALID_HANDLE; + + /* find an empty entry in the file table */ + dupFile = hwInstData->files; + for (i = 0; i < EAS_MAX_FILE_HANDLES; i++) + { + /* is this slot being used? */ + if (dupFile->fd < 0) + { + /* copy info from the handle to be duplicated */ + dupFile->filePos = file->filePos; + dupFile->fileSize = file->fileSize; + dupFile->fd = file->fd; + dupFile->offset = file->offset; + + /* set the duplicate handle flag */ + dupFile->dup = file->dup = EAS_TRUE; + + *pDupFile = dupFile; + return EAS_SUCCESS; + } + dupFile++; + } + + /* too many open files */ + return EAS_ERROR_MAX_FILES_OPEN; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWClose + * + * Wrapper for fclose function + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_HWCloseFile (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file1) +{ + EAS_HW_FILE *file2,*dupFile; + int i; + + + /* make sure we have a valid handle */ + if (file1->fd < 0) + return EAS_ERROR_INVALID_HANDLE; + + /* check for duplicate handle */ + if (file1->dup) + { + dupFile = NULL; + file2 = hwInstData->files; + for (i = 0; i < EAS_MAX_FILE_HANDLES; i++) + { + /* check for duplicate */ + if ((file1 != file2) && (file2->fd == file1->fd)) + { + /* is there more than one duplicate? */ + if (dupFile != NULL) + { + /* clear this entry and return */ + file1->fd = -1; + return EAS_SUCCESS; + } + + /* this is the first duplicate found */ + else + dupFile = file2; + } + file2++; + } + + /* there is only one duplicate, clear the dup flag */ + if (dupFile) + dupFile->dup = EAS_FALSE; + else + /* if we get here, there's a serious problem */ + return EAS_ERROR_HANDLE_INTEGRITY; + + /* clear this entry and return */ + file1->fd = -1; + return EAS_SUCCESS; + } + + /* no duplicates - close the file */ + close(file1->fd); + /* clear this entry and return */ + file1->fd = -1; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWVibrate + * + * Turn on/off vibrate function + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWVibrate (EAS_HW_DATA_HANDLE hwInstData, EAS_BOOL state) +{ + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x1a54b6e8, 0x00000001 , state); + return EAS_SUCCESS; +} /* end EAS_HWVibrate */ + +/*---------------------------------------------------------------------------- + * + * EAS_HWLED + * + * Turn on/off LED + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWLED (EAS_HW_DATA_HANDLE hwInstData, EAS_BOOL state) +{ + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x1a54b6e8, 0x00000002 , state); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWBackLight + * + * Turn on/off backlight + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWBackLight (EAS_HW_DATA_HANDLE hwInstData, EAS_BOOL state) +{ + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x1a54b6e8, 0x00000003 , state); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWYield + * + * This function is called periodically by the EAS library to give the + * host an opportunity to allow other tasks to run. There are two ways to + * use this call: + * + * If you have a multi-tasking OS, you can call the yield function in the + * OS to allow other tasks to run. In this case, return EAS_FALSE to tell + * the EAS library to continue processing when control returns from this + * function. + * + * If tasks run in a single thread by sequential function calls (sometimes + * call a "commutator loop"), return EAS_TRUE to cause the EAS Library to + * return to the caller. Be sure to check the number of bytes rendered + * before passing the audio buffer to the codec - it may not be filled. + * The next call to EAS_Render will continue processing until the buffer + * has been filled. + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_BOOL EAS_HWYield (EAS_HW_DATA_HANDLE hwInstData) +{ + /* put your code here */ + return EAS_FALSE; +} + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_main.c b/common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_main.c new file mode 100755 index 0000000..5cbf064 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_main.c @@ -0,0 +1,464 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_main.c + * + * Contents and purpose: + * The entry point and high-level functions for the EAS Synthesizer test + * harness. + * + * Copyright Sonic Network Inc. 2004 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 775 $ + * $Date: 2007-07-20 10:11:11 -0700 (Fri, 20 Jul 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifdef _lint +#include "lint_stdlib.h" +#else +#include +#include +#include +#include +#endif + +#include "eas.h" +#include "eas_wave.h" +#include "eas_report.h" + +/* determines how many EAS buffers to fill a host buffer */ +#define NUM_BUFFERS 8 + +/* default file to play if no filename is specified on the command line */ +static const char defaultTestFile[] = "test.mid"; + +EAS_I32 polyphony; + +/* prototypes for helper functions */ +static void StrCopy(char *dest, const char *src, EAS_I32 size); +static EAS_BOOL ChangeFileExt(char *str, const char *ext, EAS_I32 size); +static EAS_RESULT PlayFile (EAS_DATA_HANDLE easData, const char* filename, const char* outputFile, const S_EAS_LIB_CONFIG *pLibConfig, void *buffer, EAS_I32 bufferSize); +static EAS_BOOL EASLibraryCheck (const S_EAS_LIB_CONFIG *pLibConfig); + +/* main is defined after playfile to avoid the need for two passes through lint */ + +/*---------------------------------------------------------------------------- + * PlayFile() + *---------------------------------------------------------------------------- + * Purpose: + * This function plays the file requested by filename + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ + +static EAS_RESULT PlayFile (EAS_DATA_HANDLE easData, const char* filename, const char* outputFile, const S_EAS_LIB_CONFIG *pLibConfig, void *buffer, EAS_I32 bufferSize) +{ + EAS_HANDLE handle; + EAS_RESULT result, reportResult; + EAS_I32 count; + EAS_STATE state; + EAS_I32 playTime; + char waveFilename[256]; + WAVE_FILE *wFile; + EAS_INT i; + EAS_PCM *p; + EAS_FILE file; + + /* determine the name of the output file */ + wFile = NULL; + if (outputFile == NULL) + { + StrCopy(waveFilename, filename, sizeof(waveFilename)); + if (!ChangeFileExt(waveFilename, "wav", sizeof(waveFilename))) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error in output filename %s\n", waveFilename); */ } + return EAS_FAILURE; + } + outputFile = waveFilename; + } + + /* call EAS library to open file */ + file.path = filename; + file.fd = 0; + if ((reportResult = EAS_OpenFile(easData, &file, &handle)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_OpenFile returned %ld\n", reportResult); */ } + return reportResult; + } + + /* prepare to play the file */ + if ((result = EAS_Prepare(easData, handle)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_Prepare returned %ld\n", result); */ } + reportResult = result; + } + + /* get play length */ + if ((result = EAS_ParseMetaData(easData, handle, &playTime)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_ParseMetaData returned %ld\n", result); */ } + return result; + } + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0xe624f4d9, 0x00000005 , playTime / 1000, playTime % 1000); + + if (reportResult == EAS_SUCCESS) + { + /* create the output file */ + wFile = WaveFileCreate(outputFile, pLibConfig->numChannels, pLibConfig->sampleRate, sizeof(EAS_PCM) * 8); + if (!wFile) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Unable to create output file %s\n", waveFilename); */ } + reportResult = EAS_FAILURE; + } + } + + /* rendering loop */ + while (reportResult == EAS_SUCCESS) + { + + /* we may render several buffers here to fill one host buffer */ + for (i = 0, p = buffer; i < NUM_BUFFERS; i++, p+= pLibConfig->mixBufferSize * pLibConfig->numChannels) + { + + /* get the current time */ + if ((result = EAS_GetLocation(easData, handle, &playTime)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_GetLocation returned %d\n",result); */ } + if (reportResult == EAS_SUCCESS) + reportResult = result; + break; + } + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Parser time: %d.%03d\n", playTime / 1000, playTime % 1000); */ } + + /* render a buffer of audio */ + if ((result = EAS_Render(easData, p, pLibConfig->mixBufferSize, &count)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_Render returned %d\n",result); */ } + if (reportResult == EAS_SUCCESS) + reportResult = result; + } + } + + if (result == EAS_SUCCESS) + { + /* write it to the wave file */ + if (WaveFileWrite(wFile, buffer, bufferSize) != bufferSize) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "WaveFileWrite failed\n"); */ } + reportResult = EAS_FAILURE; + } + } + + if (reportResult == EAS_SUCCESS) + { + /* check stream state */ + if ((result = EAS_State(easData, handle, &state)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_State returned %d\n", result); */ } + reportResult = result; + } + + /* is playback complete */ + if ((state == EAS_STATE_STOPPED) || (state == EAS_STATE_ERROR)) + break; + } + } + + /* close the output file */ + if (wFile) + { + if (!WaveFileClose(wFile)) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error closing wave file %s\n", waveFilename); */ } + if (reportResult == EAS_SUCCESS) + result = EAS_FAILURE; + } + } + + /* close the input file */ + if ((result = EAS_CloseFile(easData,handle)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_Close returned %ld\n", result); */ } + if (reportResult == EAS_SUCCESS) + result = EAS_FAILURE; + } + + return reportResult; +} /* end PlayFile */ + +/*---------------------------------------------------------------------------- + * main() + *---------------------------------------------------------------------------- + * Purpose: The entry point for the EAS sample application + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +int main( int argc, char **argv ) +{ + EAS_DATA_HANDLE easData; + const S_EAS_LIB_CONFIG *pLibConfig; + void *buffer; + EAS_RESULT result, playResult; + EAS_I32 bufferSize; + int i; + int temp; + FILE *debugFile; + char *outputFile = NULL; + + /* set the error reporting level */ + EAS_SetDebugLevel(_EAS_SEVERITY_INFO); + debugFile = NULL; + + /* process command-line arguments */ + for (i = 1; i < argc; i++) + { + /* check for switch */ + if (argv[i][0] == '-') + { + switch (argv[i][1]) + { + case 'd': + temp = argv[i][2]; + if ((temp >= '0') || (temp <= '9')) + EAS_SetDebugLevel(temp); + else + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Invalid debug level %d\n", temp); */ } + break; + case 'f': + if ((debugFile = fopen(&argv[i][2],"w")) == NULL) + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Unable to create debug file %s\n", &argv[i][2]); */ } + else + EAS_SetDebugFile(debugFile, EAS_TRUE); + break; + case 'o': + outputFile = &argv[i][2]; + break; + case 'p': + polyphony = atoi(&argv[i][2]); + if (polyphony < 1) + polyphony = 1; + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "Polyphony set to %d\n", polyphony); */ } + break; + default: + break; + } + continue; + } + } + + /* assume success */ + playResult = EAS_SUCCESS; + + /* get the library configuration */ + pLibConfig = EAS_Config(); + if (!EASLibraryCheck(pLibConfig)) + return -1; + if (polyphony > pLibConfig->maxVoices) + polyphony = pLibConfig->maxVoices; + + /* calculate buffer size */ + bufferSize = pLibConfig->mixBufferSize * pLibConfig->numChannels * (EAS_I32)sizeof(EAS_PCM) * NUM_BUFFERS; + + /* allocate output buffer memory */ + buffer = malloc((EAS_U32)bufferSize); + if (!buffer) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Error allocating memory for audio buffer\n"); */ } + return EAS_FAILURE; + } + + /* initialize the EAS library */ + polyphony = pLibConfig->maxVoices; + if ((result = EAS_Init(&easData)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "EAS_Init returned %ld - aborting!\n", result); */ } + free(buffer); + return result; + } + + /* + * Some debugging environments don't allow for passed parameters. + * In this case, just play the default MIDI file "test.mid" + */ + if (argc < 2) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "Playing '%s'\n", defaultTestFile); */ } + if ((playResult = PlayFile(easData, defaultTestFile, NULL, pLibConfig, buffer, bufferSize)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %d playing file %s\n", playResult, defaultTestFile); */ } + } + } + /* iterate through the list of files to be played */ + else + { + for (i = 1; i < argc; i++) + { + /* check for switch */ + if (argv[i][0] != '-') + { + + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "Playing '%s'\n", argv[i]); */ } + if ((playResult = PlayFile(easData, argv[i], outputFile, pLibConfig, buffer, bufferSize)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %d playing file %s\n", playResult, argv[i]); */ } + break; + } + } + } + } + + /* shutdown the EAS library */ + if ((result = EAS_Shutdown(easData)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "EAS_Shutdown returned %ld\n", result); */ } + } + + /* free the output buffer */ + free(buffer); + + /* close the debug file */ + if (debugFile) + fclose(debugFile); + + /* play errors take precedence over shutdown errors */ + if (playResult != EAS_SUCCESS) + return playResult; + return result; +} /* end main */ + +/*---------------------------------------------------------------------------- + * StrCopy() + *---------------------------------------------------------------------------- + * Purpose: + * Safe string copy + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static void StrCopy(char *dest, const char *src, EAS_I32 size) +{ + int len; + + strncpy(dest, src, (size_t) size-1); + len = (int) strlen(src); + if (len < size) + dest[len] = 0; +} /* end StrCopy */ + +/*---------------------------------------------------------------------------- + * ChangeFileExt() + *---------------------------------------------------------------------------- + * Purpose: + * Changes the file extension of a filename + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL ChangeFileExt(char *str, const char *ext, EAS_I32 size) +{ + char *p; + + /* find the extension, if any */ + p = strrchr(str,'.'); + if (!p) + { + if ((EAS_I32)(strlen(str) + 5) > size) + return EAS_FALSE; + strcat(str,"."); + strcat(str,ext); + return EAS_TRUE; + } + + /* make sure there's room for the extension */ + p++; + *p = 0; + if ((EAS_I32)(strlen(str) + 4) > size) + return EAS_FALSE; + strcat(str,ext); + return EAS_TRUE; +} /* end ChangeFileExt */ + +/*---------------------------------------------------------------------------- + * EASLibraryCheck() + *---------------------------------------------------------------------------- + * Purpose: + * Displays the library version and checks it against the header + * file used to build this code. + * + * Inputs: + * pLibConfig - library configuration retrieved from the library + * + * Outputs: + * returns EAS_TRUE if matched + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL EASLibraryCheck (const S_EAS_LIB_CONFIG *pLibConfig) +{ + + /* display the library version */ + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "EAS Library Version %d.%d.%d.%d\n", + pLibConfig->libVersion >> 24, + (pLibConfig->libVersion >> 16) & 0x0f, + (pLibConfig->libVersion >> 8) & 0x0f, + pLibConfig->libVersion & 0x0f); */ } + + /* display some info about the library build */ + if (pLibConfig->checkedVersion) + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tChecked library\n"); */ } + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tMaximum polyphony: %d\n", pLibConfig->maxVoices); */ } + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tNumber of channels: %d\n", pLibConfig->numChannels); */ } + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tSample rate: %d\n", pLibConfig->sampleRate); */ } + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tMix buffer size: %d\n", pLibConfig->mixBufferSize); */ } + if (pLibConfig->filterEnabled) + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tFilter enabled\n"); */ } +#ifndef _WIN32_WCE + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tLibrary Build Timestamp: %s", ctime((time_t*)&pLibConfig->buildTimeStamp)); */ } +#endif + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tLibrary Build ID: %s\n", pLibConfig->buildGUID); */ } + + /* check it against the header file used to build this code */ + /*lint -e{778} constant expression used for display purposes may evaluate to zero */ + if (LIB_VERSION != pLibConfig->libVersion) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Library version does not match header files. EAS Header Version %d.%d.%d.%d\n", + LIB_VERSION >> 24, + (LIB_VERSION >> 16) & 0x0f, + (LIB_VERSION >> 8) & 0x0f, + LIB_VERSION & 0x0f); */ } + return EAS_FALSE; + } + return EAS_TRUE; +} /* end EASLibraryCheck */ + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_report.c b/common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_report.c new file mode 100755 index 0000000..04a828c --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_report.c @@ -0,0 +1,264 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_report.c + * + * Contents and purpose: + * This file contains the debug message handling routines for the EAS library. + * These routines should be modified as needed for your system. + * + * Copyright 2005 Sonic Network Inc. + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 659 $ + * $Date: 2007-04-24 13:36:35 -0700 (Tue, 24 Apr 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifdef _lint +#include "lint_stdlib.h" +#else +#include +#include +#include +#endif + +#include "eas_report.h" + +static int severityLevel = 9999; + +/* debug file */ +static FILE *debugFile = NULL; +int flush = 0; + +#ifndef _NO_DEBUG_PREPROCESSOR + +/* structure should have an #include for each error message header file */ +S_DEBUG_MESSAGES debugMessages[] = +{ +#ifndef UNIFIED_DEBUG_MESSAGES +#include "eas_config_msgs.h" + + +#include "eas_host_msgs.h" +#include "eas_hostmm_msgs.h" +#include "eas_math_msgs.h" +#include "eas_midi_msgs.h" +#include "eas_mixer_msgs.h" +#include "eas_pcm_msgs.h" +#include "eas_public_msgs.h" +#include "eas_smf_msgs.h" +#include "eas_wave_msgs.h" +#include "eas_voicemgt_msgs.h" + +#ifdef _FM_SYNTH +#include "eas_fmsynth_msgs.h" +#include "eas_fmengine_msgs.h" +#endif + +#ifdef _WT_SYNTH +#include "eas_wtsynth_msgs.h" +#include "eas_wtengine_msgs.h" +#endif + +#ifdef _ARM_TEST_MAIN +#include "arm_main_msgs.h" +#endif + +#ifdef _EAS_MAIN +#include "eas_main_msgs.h" +#endif + +#ifdef _EAS_MAIN_IPC +#include "eas_main_ipc_msgs.h" +#endif + +#ifdef _METRICS_ENABLED +#include "eas_perf_msgs.h" +#endif + +#ifdef _COMPRESSOR_ENABLED +#include "eas_compressor_msgs.h" +#endif + +#ifdef _ENHANCER_ENABLED +#include "eas_enhancer_msgs.h" +#endif + +#ifdef _WOW_ENABLED +#include "eas_wow_msgs.h" +#endif + +#ifdef _SMAF_PARSER +#include "eas_smaf_msgs.h" +#endif + +#ifdef _OTA_PARSER +#include "eas_ota_msgs.h" +#endif + +#ifdef _IMELODY_PARSER +#include "eas_imelody_msgs.h" +#endif + +#ifdef _WAVE_PARSER +#include "eas_wavefile_msgs.h" +#endif + +#if defined(_CMX_PARSER) || defined(_MFI_PARSER) +#include "eas_cmf_msgs.h" +#endif + +#if defined(_CMX_PARSER) || defined(_MFI_PARSER) || defined(_WAVE_PARSER) +#include "eas_imaadpcm_msgs.h" +#endif + +#else +#include "eas_debugmsgs.h" +#endif + +/* denotes end of error messages */ +{ 0,0,0 } +}; + +/*---------------------------------------------------------------------------- + * EAS_ReportEx() + * + * This is the error message handler. The default handler outputs error + * messages to stdout. Modify this as needed for your system. + *---------------------------------------------------------------------------- +*/ +void EAS_ReportEx (int severity, unsigned long hashCode, int serialNum, ...) +{ + va_list vargs; + int i; + + /* check severity level */ + if (severity > severityLevel) + return; + + /* find the error message and output to stdout */ + /*lint -e{661} we check for NULL pointer - no fence post error here */ + for (i = 0; debugMessages[i].m_pDebugMsg; i++) + { + if ((debugMessages[i].m_nHashCode == hashCode) && + (debugMessages[i].m_nSerialNum == serialNum)) + { + /*lint -e{826} */ + va_start(vargs, serialNum); + if (debugFile) + { + vfprintf(debugFile, debugMessages[i].m_pDebugMsg, vargs); + if (flush) + fflush(debugFile); + } + else + { + vprintf(debugMessages[i].m_pDebugMsg, vargs); + } + va_end(vargs); + return; + } + } + printf("Unrecognized error: Severity=%d; HashCode=%lu; SerialNum=%d\n", severity, hashCode, serialNum); +} /* end EAS_ReportEx */ + +#else +/*---------------------------------------------------------------------------- + * EAS_Report() + * + * This is the error message handler. The default handler outputs error + * messages to stdout. Modify this as needed for your system. + *---------------------------------------------------------------------------- +*/ +void EAS_Report (int severity, const char *fmt, ...) +{ + va_list vargs; + + /* check severity level */ + if (severity > severityLevel) + return; + + /*lint -e{826} */ + va_start(vargs, fmt); + if (debugFile) + { + vfprintf(debugFile, fmt, vargs); + if (flush) + fflush(debugFile); + } + else + { + vprintf(fmt, vargs); + } + va_end(vargs); +} /* end EAS_Report */ + +/*---------------------------------------------------------------------------- + * EAS_ReportX() + * + * This is the error message handler. The default handler outputs error + * messages to stdout. Modify this as needed for your system. + *---------------------------------------------------------------------------- +*/ +void EAS_ReportX (int severity, const char *fmt, ...) +{ + va_list vargs; + + /* check severity level */ + if (severity > severityLevel) + return; + + /*lint -e{826} */ + va_start(vargs, fmt); + if (debugFile) + { + vfprintf(debugFile, fmt, vargs); + if (flush) + fflush(debugFile); + } + else + { + vprintf(fmt, vargs); + } + va_end(vargs); +} /* end EAS_ReportX */ +#endif + +/*---------------------------------------------------------------------------- + * EAS_SetDebugLevel() + * + * Sets the level for debug message output + *---------------------------------------------------------------------------- +*/ + +void EAS_SetDebugLevel (int severity) +{ + severityLevel = severity; +} /* end EAS_SetDebugLevel */ + +/*---------------------------------------------------------------------------- + * EAS_SetDebugFile() + * + * Redirect debugger output to the specified file. + *---------------------------------------------------------------------------- +*/ +void EAS_SetDebugFile (void *file, int flushAfterWrite) +{ + debugFile = (FILE*) file; + flush = flushAfterWrite; +} /* end EAS_SetDebugFile */ + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_report.h b/common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_report.h new file mode 100755 index 0000000..b603b12 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_report.h @@ -0,0 +1,77 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_report.h + * + * Contents and purpose: + * This file contains the debug message handling routines for the EAS library. + * These routines should be modified as needed for your system. + * + * DO NOT MODIFY THIS FILE! + * + * Copyright 2005 Sonic Network Inc. + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +/* sentinel */ +#ifndef _EAS_REPORT_H +#define _EAS_REPORT_H + +#define _EAS_SEVERITY_NOFILTER 0 +#define _EAS_SEVERITY_FATAL 1 +#define _EAS_SEVERITY_ERROR 2 +#define _EAS_SEVERITY_WARNING 3 +#define _EAS_SEVERITY_INFO 4 +#define _EAS_SEVERITY_DETAIL 5 + +/* for C++ linkage */ +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _NO_DEBUG_PREPROCESSOR + +/* structure for included debug message header files */ +typedef struct +{ + unsigned long m_nHashCode; + int m_nSerialNum; + char *m_pDebugMsg; +} S_DEBUG_MESSAGES; + +/* debug message handling prototypes */ +extern void EAS_ReportEx (int severity, unsigned long hashCode, int serialNum, ...); + +#else + +/* these prototypes are used if the debug preprocessor is not used */ +extern void EAS_Report (int severity, const char* fmt, ...); +extern void EAS_ReportX (int severity, const char* fmt, ...); + +#endif + +extern void EAS_SetDebugLevel (int severity); +extern void EAS_SetDebugFile (void *file, int flushAfterWrite); + +#ifdef __cplusplus +} /* end extern "C" */ +#endif + +#endif diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_reverb.h b/common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_reverb.h new file mode 100755 index 0000000..559abed --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_reverb.h @@ -0,0 +1,54 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_reverb.h + * + * Contents and purpose: + * Contains parameter enumerations for the Reverb effect + * + * + * Copyright Sonic Network Inc. 2006 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 300 $ + * $Date: 2006-09-11 17:37:20 -0700 (Mon, 11 Sep 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_REVERB_H +#define _EAS_REVERB_H + + +/* enumerated parameter settings for Reverb effect */ +typedef enum +{ + EAS_PARAM_REVERB_BYPASS, + EAS_PARAM_REVERB_PRESET, + EAS_PARAM_REVERB_WET, + EAS_PARAM_REVERB_DRY +} E_REVERB_PARAMS; + + +typedef enum +{ + EAS_PARAM_REVERB_LARGE_HALL, + EAS_PARAM_REVERB_HALL, + EAS_PARAM_REVERB_CHAMBER, + EAS_PARAM_REVERB_ROOM, +} E_REVERB_PRESETS; + + +#endif /* _REVERB_H */ diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_types.h b/common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_types.h new file mode 100755 index 0000000..d66a2b7 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_types.h @@ -0,0 +1,273 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_types.h + * + * Contents and purpose: + * The public interface header for the EAS synthesizer. + * + * This header only contains declarations that are specific + * to this implementation. + * + * DO NOT MODIFY THIS FILE! + * + * Copyright Sonic Network Inc. 2004 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 726 $ + * $Date: 2007-06-14 23:10:46 -0700 (Thu, 14 Jun 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_TYPES_H +#define _EAS_TYPES_H + +/* EAS_RESULT return codes */ +typedef long EAS_RESULT; +#define EAS_SUCCESS 0 +#define EAS_FAILURE -1 +#define EAS_ERROR_INVALID_MODULE -2 +#define EAS_ERROR_MALLOC_FAILED -3 +#define EAS_ERROR_FILE_POS -4 +#define EAS_ERROR_INVALID_FILE_MODE -5 +#define EAS_ERROR_FILE_SEEK -6 +#define EAS_ERROR_FILE_LENGTH -7 +#define EAS_ERROR_NOT_IMPLEMENTED -8 +#define EAS_ERROR_CLOSE_FAILED -9 +#define EAS_ERROR_FILE_OPEN_FAILED -10 +#define EAS_ERROR_INVALID_HANDLE -11 +#define EAS_ERROR_NO_MIX_BUFFER -12 +#define EAS_ERROR_PARAMETER_RANGE -13 +#define EAS_ERROR_MAX_FILES_OPEN -14 +#define EAS_ERROR_UNRECOGNIZED_FORMAT -15 +#define EAS_BUFFER_SIZE_MISMATCH -16 +#define EAS_ERROR_FILE_FORMAT -17 +#define EAS_ERROR_SMF_NOT_INITIALIZED -18 +#define EAS_ERROR_LOCATE_BEYOND_END -19 +#define EAS_ERROR_INVALID_PCM_TYPE -20 +#define EAS_ERROR_MAX_PCM_STREAMS -21 +#define EAS_ERROR_NO_VOICE_ALLOCATED -22 +#define EAS_ERROR_INVALID_CHANNEL -23 +#define EAS_ERROR_ALREADY_STOPPED -24 +#define EAS_ERROR_FILE_READ_FAILED -25 +#define EAS_ERROR_HANDLE_INTEGRITY -26 +#define EAS_ERROR_MAX_STREAMS_OPEN -27 +#define EAS_ERROR_INVALID_PARAMETER -28 +#define EAS_ERROR_FEATURE_NOT_AVAILABLE -29 +#define EAS_ERROR_SOUND_LIBRARY -30 +#define EAS_ERROR_NOT_VALID_IN_THIS_STATE -31 +#define EAS_ERROR_NO_VIRTUAL_SYNTHESIZER -32 +#define EAS_ERROR_FILE_ALREADY_OPEN -33 +#define EAS_ERROR_FILE_ALREADY_CLOSED -34 +#define EAS_ERROR_INCOMPATIBLE_VERSION -35 +#define EAS_ERROR_QUEUE_IS_FULL -36 +#define EAS_ERROR_QUEUE_IS_EMPTY -37 +#define EAS_ERROR_FEATURE_ALREADY_ACTIVE -38 + +/* special return codes */ +#define EAS_EOF 3 +#define EAS_STREAM_BUFFERING 4 +#define EAS_BUFFER_FULL 5 + +/* EAS_STATE return codes */ +typedef long EAS_STATE; +typedef enum +{ + EAS_STATE_READY = 0, + EAS_STATE_PLAY, + EAS_STATE_STOPPING, + EAS_STATE_PAUSING, + EAS_STATE_STOPPED, + EAS_STATE_PAUSED, + EAS_STATE_OPEN, + EAS_STATE_ERROR, + EAS_STATE_EMPTY +} E_EAS_STATE; + +/* constants */ +#ifndef EAS_CONST +#define EAS_CONST const +#endif + +/* definition for public interface functions */ +#ifndef EAS_PUBLIC +#define EAS_PUBLIC +#endif + +/* boolean values */ +typedef unsigned EAS_BOOL; +typedef unsigned char EAS_BOOL8; + +#define EAS_FALSE 0 +#define EAS_TRUE 1 + +/* scalar variable definitions */ +typedef unsigned char EAS_U8; +typedef signed char EAS_I8; +typedef char EAS_CHAR; + +typedef unsigned short EAS_U16; +typedef short EAS_I16; + +typedef unsigned long EAS_U32; +typedef long EAS_I32; + +typedef unsigned EAS_UINT; +typedef int EAS_INT; +typedef long EAS_LONG; + +/* audio output type */ +typedef short EAS_PCM; + +/* file open modes */ +typedef EAS_I32 EAS_FILE_MODE; +#define EAS_FILE_READ 1 +#define EAS_FILE_WRITE 2 + +/* file locator e.g. filename or memory pointer */ +typedef struct s_eas_file_tag { + const char* path; + int fd; + long long offset; + long long length; +} EAS_FILE, *EAS_FILE_LOCATOR; + +/* handle to stream */ +typedef struct s_eas_stream_tag *EAS_HANDLE; + +/* handle to file */ +typedef struct eas_hw_file_tag *EAS_FILE_HANDLE; + +/* handle for synthesizer data */ +typedef struct s_eas_data_tag *EAS_DATA_HANDLE; + +/* handle to persistent data for host wrapper interface */ +typedef struct eas_hw_inst_data_tag *EAS_HW_DATA_HANDLE; + +/* handle to sound library */ +typedef struct s_eas_sndlib_tag *EAS_SNDLIB_HANDLE; +typedef struct s_eas_dls_tag *EAS_DLSLIB_HANDLE; + +/* pointer to frame buffer - used in split architecture only */ +typedef struct s_eas_frame_buffer_tag *EAS_FRAME_BUFFER_HANDLE; + +/* untyped pointer for instance data */ +typedef void *EAS_VOID_PTR; + +/* inline functions */ +#ifndef EAS_INLINE +#if defined (__XCC__) +#define EAS_INLINE __inline__ +#elif defined (__GNUC__) +#define EAS_INLINE inline static +#else +#define EAS_INLINE __inline +#endif +#endif + +/* define NULL value */ +#ifndef NULL +#define NULL 0 +#endif + +/* metadata types for metadata return codes */ +typedef enum +{ + EAS_METADATA_UNKNOWN = 0, + EAS_METADATA_TITLE, + EAS_METADATA_AUTHOR, + EAS_METADATA_COPYRIGHT, + EAS_METADATA_LYRIC, + EAS_METADATA_TEXT +} E_EAS_METADATA_TYPE; + +/* metadata callback function */ +typedef void (*EAS_METADATA_CBFUNC) (E_EAS_METADATA_TYPE metaDataType, char *metaDataBuf, EAS_VOID_PTR pUserData); + +/* file types for metadata return codes */ +typedef enum +{ + EAS_FILE_UNKNOWN = 0, + EAS_FILE_SMF0, + EAS_FILE_SMF1, + EAS_FILE_SMAF_UNKNOWN, + EAS_FILE_SMAF_MA2, + EAS_FILE_SMAF_MA3, + EAS_FILE_SMAF_MA5, + EAS_FILE_CMX, + EAS_FILE_MFI, + EAS_FILE_OTA, + EAS_FILE_IMELODY, + EAS_FILE_RTTTL, + EAS_FILE_XMF0, + EAS_FILE_XMF1, + EAS_FILE_WAVE_PCM, + EAS_FILE_WAVE_IMA_ADPCM, + EAS_FILE_MMAPI_TONE_CONTROL +} E_EAS_FILE_TYPE; + +/* enumeration for synthesizers */ +typedef enum +{ + EAS_MCU_SYNTH = 0, + EAS_DSP_SYNTH +} E_SYNTHESIZER; + +/* external audio callback program change */ +typedef struct s_ext_audio_prg_chg_tag +{ + EAS_U16 bank; + EAS_U8 program; + EAS_U8 channel; +} S_EXT_AUDIO_PRG_CHG; + +/* external audio callback event */ +typedef struct s_ext_audio_event_tag +{ + EAS_U8 channel; + EAS_U8 note; + EAS_U8 velocity; + EAS_BOOL8 noteOn; +} S_EXT_AUDIO_EVENT; + +typedef struct s_midi_controllers_tag +{ + EAS_U8 modWheel; /* CC1 */ + EAS_U8 volume; /* CC7 */ + EAS_U8 pan; /* CC10 */ + EAS_U8 expression; /* CC11 */ + EAS_U8 channelPressure; /* MIDI channel pressure */ + +#ifdef _REVERB + EAS_U8 reverbSend; /* CC91 */ +#endif + +#ifdef _CHORUS + EAS_U8 chorusSend; /* CC93 */ +#endif +} S_MIDI_CONTROLLERS; + +/* iMode play modes enumeration for EAS_SetPlayMode */ +typedef enum +{ + IMODE_PLAY_ALL = 0, + IMODE_PLAY_PARTIAL +} E_I_MODE_PLAY_MODE; + +typedef EAS_BOOL (*EAS_EXT_PRG_CHG_FUNC) (EAS_VOID_PTR pInstData, S_EXT_AUDIO_PRG_CHG *pPrgChg); +typedef EAS_BOOL (*EAS_EXT_EVENT_FUNC) (EAS_VOID_PTR pInstData, S_EXT_AUDIO_EVENT *pEvent); + +#endif /* #ifndef _EAS_TYPES_H */ diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_wave.c b/common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_wave.c new file mode 100755 index 0000000..4f6ffbd --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_wave.c @@ -0,0 +1,423 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_wave.c + * + * Contents and purpose: + * This module contains .WAV file functions for the EAS synthesizer + * test harness. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 658 $ + * $Date: 2007-04-24 13:35:49 -0700 (Tue, 24 Apr 2007) $ + *---------------------------------------------------------------------------- +*/ + +/* lint complaints about most C library headers, so we use our own during lint step */ +#ifdef _lint +#include "lint_stdlib.h" +#else +#include +#include +#endif + +#include "eas_wave.h" + +/* .WAV file format tags */ +const EAS_U32 riffTag = 0x46464952; +const EAS_U32 waveTag = 0x45564157; +const EAS_U32 fmtTag = 0x20746d66; +const EAS_U32 dataTag = 0x61746164; + +#ifdef _BIG_ENDIAN +/*---------------------------------------------------------------------------- + * FlipDWord() + *---------------------------------------------------------------------------- + * Purpose: Endian flip a DWORD for big-endian processors + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static void FlipDWord (EAS_U32 *pValue) +{ + EAS_U8 *p; + EAS_U32 temp; + + p = (EAS_U8*) pValue; + temp = (((((p[3] << 8) | p[2]) << 8) | p[1]) << 8) | p[0]; + *pValue = temp; +} + +/*---------------------------------------------------------------------------- + * FlipWord() + *---------------------------------------------------------------------------- + * Purpose: Endian flip a WORD for big-endian processors + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static void FlipWord (EAS_U16 *pValue) +{ + EAS_U8 *p; + EAS_U16 temp; + + p = (EAS_U8*) pValue; + temp = (p[1] << 8) | p[0]; + *pValue = temp; +} + +/*---------------------------------------------------------------------------- + * FlipWaveHeader() + *---------------------------------------------------------------------------- + * Purpose: Endian flip the wave header for big-endian processors + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static void FlipWaveHeader (WAVE_HEADER *p) +{ + + FlipDWord(&p->nRiffTag); + FlipDWord(&p->nRiffSize); + FlipDWord(&p->nWaveTag); + FlipDWord(&p->nFmtTag); + FlipDWord(&p->nFmtSize); + FlipDWord(&p->nDataTag); + FlipDWord(&p->nDataSize); + FlipWord(&p->fc.wFormatTag); + FlipWord(&p->fc.nChannels); + FlipDWord(&p->fc.nSamplesPerSec); + FlipDWord(&p->fc.nAvgBytesPerSec); + FlipWord(&p->fc.nBlockAlign); + FlipWord(&p->fc.wBitsPerSample); + +} +#endif + +/*---------------------------------------------------------------------------- + * WaveFileCreate() + *---------------------------------------------------------------------------- + * Purpose: Opens a wave file for writing and writes the header + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ + +WAVE_FILE *WaveFileCreate (const char *filename, EAS_I32 nChannels, EAS_I32 nSamplesPerSec, EAS_I32 wBitsPerSample) +{ + WAVE_FILE *wFile; + + /* allocate memory */ + wFile = malloc(sizeof(WAVE_FILE)); + if (!wFile) + return NULL; + wFile->write = EAS_TRUE; + + /* create the file */ + wFile->file = fopen(filename,"wb"); + if (!wFile->file) + { + free(wFile); + return NULL; + } + + /* initialize PCM format .WAV file header */ + wFile->wh.nRiffTag = riffTag; + wFile->wh.nRiffSize = sizeof(WAVE_HEADER) - 8; + wFile->wh.nWaveTag = waveTag; + wFile->wh.nFmtTag = fmtTag; + wFile->wh.nFmtSize = sizeof(FMT_CHUNK); + + /* initalize 'fmt' chunk */ + wFile->wh.fc.wFormatTag = 1; + wFile->wh.fc.nChannels = (EAS_U16) nChannels; + wFile->wh.fc.nSamplesPerSec = (EAS_U32) nSamplesPerSec; + wFile->wh.fc.wBitsPerSample = (EAS_U16) wBitsPerSample; + wFile->wh.fc.nBlockAlign = (EAS_U16) (nChannels * (EAS_U16) (wBitsPerSample / 8)); + wFile->wh.fc.nAvgBytesPerSec = wFile->wh.fc.nBlockAlign * (EAS_U32) nSamplesPerSec; + + /* initialize 'data' chunk */ + wFile->wh.nDataTag = dataTag; + wFile->wh.nDataSize = 0; + +#ifdef _BIG_ENDIAN + FlipWaveHeader(&wFile->wh); +#endif + + /* write the header */ + if (fwrite(&wFile->wh, sizeof(WAVE_HEADER), 1, wFile->file) != 1) + { + fclose(wFile->file); + free(wFile); + return NULL; + } + +#ifdef _BIG_ENDIAN + FlipWaveHeader(&wFile->wh); +#endif + + /* return the file handle */ + return wFile; +} /* end WaveFileCreate */ + +/*---------------------------------------------------------------------------- + * WaveFileWrite() + *---------------------------------------------------------------------------- + * Purpose: Writes data to the wave file + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_I32 WaveFileWrite (WAVE_FILE *wFile, void *buffer, EAS_I32 n) +{ + EAS_I32 count; + + /* make sure we have an open file */ + if (wFile == NULL) + { + return 0; + } + +#ifdef _BIG_ENDIAN + { + EAS_I32 i; + EAS_U16 *p; + p = buffer; + i = n >> 1; + while (i--) + FlipWord(p++); + } +#endif + + /* write the data */ + count = (EAS_I32) fwrite(buffer, 1, (size_t) n, wFile->file); + + /* add the number of bytes written */ + wFile->wh.nRiffSize += (EAS_U32) count; + wFile->wh.nDataSize += (EAS_U32) count; + + /* return the count of bytes written */ + return count; +} /* end WriteWaveHeader */ + +/*---------------------------------------------------------------------------- + * WaveFileClose() + *---------------------------------------------------------------------------- + * Purpose: Opens a wave file for writing and writes the header + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ + +EAS_BOOL WaveFileClose (WAVE_FILE *wFile) +{ + EAS_I32 count = 1; + + /* return to beginning of file and write the header */ + if (wFile->write) + { + if (fseek(wFile->file, 0L, SEEK_SET) == 0) + { + +#ifdef _BIG_ENDIAN + FlipWaveHeader(&wFile->wh); +#endif + count = (EAS_I32) fwrite(&wFile->wh, sizeof(WAVE_HEADER), 1, wFile->file); +#ifdef _BIG_ENDIAN + FlipWaveHeader(&wFile->wh); +#endif + } + } + + /* close the file */ + if (fclose(wFile->file) != 0) + count = 0; + + /* free the memory */ + free(wFile); + + /* return the file handle */ + return (count == 1 ? EAS_TRUE : EAS_FALSE); +} /* end WaveFileClose */ + +#ifdef _WAVE_FILE_READ +#ifdef _BIG_ENDIAN +#error "WaveFileOpen not currently supported on big-endian processors" +#endif +/*---------------------------------------------------------------------------- + * WaveFileOpen() + *---------------------------------------------------------------------------- + * Purpose: Opens a wave file for reading and reads the header + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ + +WAVE_FILE *WaveFileOpen (const char *filename) +{ + WAVE_FILE *wFile; + struct + { + EAS_U32 tag; + EAS_U32 size; + } chunk; + EAS_U32 tag; + EAS_I32 startChunkPos; + EAS_INT state; + EAS_BOOL done; + + /* allocate memory */ + wFile = malloc(sizeof(WAVE_FILE)); + if (!wFile) + return NULL; + + /* open the file */ + wFile->write = EAS_FALSE; + wFile->file = fopen(filename,"rb"); + if (!wFile->file) + { + free(wFile); + return NULL; + } + + /* make lint happy */ + chunk.tag = chunk.size = 0; + startChunkPos = 0; + + /* read the RIFF tag and file size */ + state = 0; + done = EAS_FALSE; + while (!done) + { + + switch(state) + { + /* read the RIFF tag */ + case 0: + if (fread(&chunk, sizeof(chunk), 1, wFile->file) != 1) + done = EAS_TRUE; + else + { + if (chunk.tag != riffTag) + done = EAS_TRUE; + else + state++; + } + break; + + /* read the WAVE tag */ + case 1: + if (fread(&tag, sizeof(tag), 1, wFile->file) != 1) + done = EAS_TRUE; + else + { + if (tag != waveTag) + done = EAS_TRUE; + else + state++; + } + break; + + /* looking for fmt chunk */ + case 2: + if (fread(&chunk, sizeof(chunk), 1, wFile->file) != 1) + done = EAS_TRUE; + else + { + startChunkPos = ftell(wFile->file); + + /* not fmt tag, skip it */ + if (chunk.tag != fmtTag) + fseek(wFile->file, startChunkPos + (EAS_I32) chunk.size, SEEK_SET); + else + state++; + } + break; + + /* read fmt chunk */ + case 3: + if (fread(&wFile->wh.fc, sizeof(FMT_CHUNK), 1, wFile->file) != 1) + done = EAS_TRUE; + else + { + fseek(wFile->file, startChunkPos + (EAS_I32) chunk.size, SEEK_SET); + state++; + } + break; + + /* looking for data chunk */ + case 4: + if (fread(&chunk, sizeof(chunk), 1, wFile->file) != 1) + done = EAS_TRUE; + else + { + startChunkPos = ftell(wFile->file); + + /* not data tag, skip it */ + if (chunk.tag != dataTag) + fseek(wFile->file, startChunkPos + (EAS_I32) chunk.size, SEEK_SET); + else + { + wFile->dataSize = chunk.size; + state++; + done = EAS_TRUE; + } + } + break; + + default: + done = EAS_TRUE; + break; + } + } + + /* if not final state, an error occurred */ + if (state != 5) + { + fclose(wFile->file); + free(wFile); + return NULL; + } + + /* return the file handle */ + return wFile; +} /* end WaveFileOpen */ +#endif + + + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_wave.h b/common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_wave.h new file mode 100755 index 0000000..968782f --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/host_src/eas_wave.h @@ -0,0 +1,74 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_wave.h + * + * Contents and purpose: + * Writes output to a .WAV file + * + * DO NOT MODIFY THIS FILE! + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_types.h" + +/* sentinel */ +#ifndef _EAS_WAVE_H +#define _EAS_WAVE_H + +/* .WAV file format chunk */ +typedef struct { + EAS_U16 wFormatTag; + EAS_U16 nChannels; + EAS_U32 nSamplesPerSec; + EAS_U32 nAvgBytesPerSec; + EAS_U16 nBlockAlign; + EAS_U16 wBitsPerSample; +} FMT_CHUNK; + +/* .WAV file header */ +typedef struct { + EAS_U32 nRiffTag; + EAS_U32 nRiffSize; + EAS_U32 nWaveTag; + EAS_U32 nFmtTag; + EAS_U32 nFmtSize; + FMT_CHUNK fc; + EAS_U32 nDataTag; + EAS_U32 nDataSize; +} WAVE_HEADER; + +typedef struct { + WAVE_HEADER wh; + FILE *file; + EAS_BOOL write; + EAS_U32 dataSize; +} WAVE_FILE; + +WAVE_FILE *WaveFileCreate (const char *filename, EAS_I32 nChannels, EAS_I32 nSamplesPerSec, EAS_I32 wBitsPerSample); +EAS_I32 WaveFileWrite (WAVE_FILE *wFile, void *buffer, EAS_I32 n); +EAS_BOOL WaveFileClose (WAVE_FILE *wFile); +WAVE_FILE *WaveFileOpen (const char *filename); + +#endif /* end #ifndef _EAS_WAVE_H */ + + + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/host_src/jet.h b/common/embeddedaudiosynthesis/arm-wt-22k/host_src/jet.h new file mode 100755 index 0000000..2e97a13 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/host_src/jet.h @@ -0,0 +1,199 @@ +/*---------------------------------------------------------------------------- + * + * File: + * jet.h + * + * Contents and purpose: + * Public interface for JET sound engine + * + * Copyright (c) 2006 Sonic Network Inc. + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 554 $ + * $Date: 2007-02-02 11:06:10 -0800 (Fri, 02 Feb 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _JET_H +#define _JET_H + +#include "eas_types.h" +#include "eas.h" + +/* for C++ linkage */ +#ifdef __cplusplus +extern "C" { +#endif + +/* opaque handle types for JET interface */ +typedef struct s_jet_data_tag *JET_DATA_HANDLE; + +typedef struct s_jet_config_tag +{ + EAS_U8 appEventRangeLow; + EAS_U8 appEventRangeHigh; +} S_JET_CONFIG; + +typedef struct s_jet_status_tag +{ + EAS_INT currentUserID; + EAS_INT segmentRepeatCount; + EAS_INT numQueuedSegments; + EAS_BOOL paused; + EAS_I32 location; + EAS_U8 currentPlayingSegment; + EAS_U8 currentQueuedSegment; +} S_JET_STATUS; + +typedef struct s_jet_event_tag +{ + EAS_U8 segment; + EAS_U8 channel; + EAS_U8 track; + EAS_U8 controller; + EAS_U8 value; +} S_JET_EVENT; + +/*---------------------------------------------------------------------------- + * JET_Init() + *---------------------------------------------------------------------------- + * Initializes the JET library, allocates memory, etc. Call + * JET_Shutdown to de-allocate memory. Pass NULL for pConfig + * to use defaults. If passing config data, configSize should be + * sizeof(S_JET_CONFIG). This allows for future expansion of the + * config structure while maintaining compatibility. + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT JET_Init (EAS_DATA_HANDLE easHandle, const S_JET_CONFIG *pConfig, EAS_INT configSize); + +/*---------------------------------------------------------------------------- + * JET_Shutdown() + *---------------------------------------------------------------------------- + * Frees any memory used by the JET library + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT JET_Shutdown (EAS_DATA_HANDLE easHandle); + +/*---------------------------------------------------------------------------- + * JET_OpenFile() + *---------------------------------------------------------------------------- + * Opens a JET content file for playback + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT JET_OpenFile (EAS_DATA_HANDLE easHandle, EAS_FILE_LOCATOR locator); + +/*---------------------------------------------------------------------------- + * JET_GetAppData() + *---------------------------------------------------------------------------- + * Returns location and size of application data in the JET file + *---------------------------------------------------------------------------- +*/ +EAS_RESULT JET_GetAppData (EAS_DATA_HANDLE easHandle, EAS_I32 *pAppDataOffset, EAS_I32 *pAppDataSize); + +/*---------------------------------------------------------------------------- + * JET_CloseFile() + *---------------------------------------------------------------------------- + * Closes a JET content file and releases associated resources + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT JET_CloseFile (EAS_DATA_HANDLE easHandle); + +/*---------------------------------------------------------------------------- + * JET_Status() + *---------------------------------------------------------------------------- + * Returns current status + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT JET_Status (EAS_DATA_HANDLE easHandle, S_JET_STATUS *pStatus); + +/*---------------------------------------------------------------------------- + * JET_GetEvent() + *---------------------------------------------------------------------------- + * Checks for application events + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_BOOL JET_GetEvent (EAS_DATA_HANDLE easHandle, EAS_U32 *pEventRaw, S_JET_EVENT *pEvent); + +/*---------------------------------------------------------------------------- + * JET_ParseEvent() + *---------------------------------------------------------------------------- + * Returns current status + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC void JET_ParseEvent (EAS_U32 event, S_JET_EVENT *pEvent); + +/*---------------------------------------------------------------------------- + * JET_QueueSegment() + *---------------------------------------------------------------------------- + * Queue a segment for playback + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT JET_QueueSegment (EAS_DATA_HANDLE easHandle, EAS_INT segmentNum, EAS_INT libNum, EAS_INT repeatCount, EAS_INT transpose, EAS_U32 muteFlags, EAS_U8 userID); + +/*---------------------------------------------------------------------------- + * JET_Play() + *---------------------------------------------------------------------------- + * Starts playback of the file + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT JET_Play (EAS_DATA_HANDLE easHandle); + +/*---------------------------------------------------------------------------- + * JET_Pause() + *---------------------------------------------------------------------------- + * Pauses playback of the file + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT JET_Pause (EAS_DATA_HANDLE easHandle); + +/*---------------------------------------------------------------------------- + * JET_SetMuteFlags() + *---------------------------------------------------------------------------- + * Change the state of the mute flags + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT JET_SetMuteFlags (EAS_DATA_HANDLE easHandle, EAS_U32 muteFlags, EAS_BOOL sync); + +/*---------------------------------------------------------------------------- + * JET_SetMuteFlag() + *---------------------------------------------------------------------------- + * Change the state of a single mute flag + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT JET_SetMuteFlag (EAS_DATA_HANDLE easHandle, EAS_INT trackNum, EAS_BOOL muteFlag, EAS_BOOL sync); + +/*---------------------------------------------------------------------------- + * JET_TriggerClip() + *---------------------------------------------------------------------------- + * Unmute a track and then mute it when it is complete + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT JET_TriggerClip (EAS_DATA_HANDLE easHandle, EAS_INT clipID); + +/*---------------------------------------------------------------------------- + * JET_Clear_Queue() + *---------------------------------------------------------------------------- + * Clears all segments in the queue + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT JET_Clear_Queue (EAS_DATA_HANDLE easHandle); + +#ifdef __cplusplus +} /* end extern "C" */ +#endif + + +#endif + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/EASLIb.xcodeproj/project.pbxproj b/common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/EASLIb.xcodeproj/project.pbxproj new file mode 100755 index 0000000..29a353c --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/EASLIb.xcodeproj/project.pbxproj @@ -0,0 +1,361 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 44; + objects = { + +/* Begin PBXBuildFile section */ + 9A56ACEA0F72B84D00D115A7 /* libeaswt_vst_lib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9A56ACD80F72B7D600D115A7 /* libeaswt_vst_lib.a */; }; + C5AB01090E3400DC0051F183 /* EASLib.h in Headers */ = {isa = PBXBuildFile; fileRef = C5AB01070E3400DC0051F183 /* EASLib.h */; }; + C5AB010A0E3400DC0051F183 /* EASLib.c in Sources */ = {isa = PBXBuildFile; fileRef = C5AB01080E3400DC0051F183 /* EASLib.c */; }; + C5AB01240E3406090051F183 /* eas_config.c in Sources */ = {isa = PBXBuildFile; fileRef = C5AB01230E3406090051F183 /* eas_config.c */; }; + C5AB017A0E340DD60051F183 /* AudioUnit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C5AB01790E340DD60051F183 /* AudioUnit.framework */; }; + C5AB018C0E340EAA0051F183 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C5AB018B0E340EAA0051F183 /* AudioToolbox.framework */; }; + C5AB01910E340EC50051F183 /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C5AB01900E340EC50051F183 /* CoreAudio.framework */; }; + C5AB02F60E341AAC0051F183 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C5AB02F50E341AAC0051F183 /* Carbon.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 9A56ACD70F72B7D600D115A7 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 9A56ACD30F72B7D600D115A7 /* easwt_vst_lib.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = D2AAC046055464E500DB518D; + remoteInfo = easwt_vst_lib; + }; + 9A56ACFC0F72B8B200D115A7 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 9A56ACD30F72B7D600D115A7 /* easwt_vst_lib.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = D2AAC045055464E500DB518D; + remoteInfo = easwt_vst_lib; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 9A56ACD30F72B7D600D115A7 /* easwt_vst_lib.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = easwt_vst_lib.xcodeproj; sourceTree = ""; }; + C5AB01070E3400DC0051F183 /* EASLib.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EASLib.h; sourceTree = ""; }; + C5AB01080E3400DC0051F183 /* EASLib.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = EASLib.c; sourceTree = ""; }; + C5AB01230E3406090051F183 /* eas_config.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eas_config.c; path = ../../host_src/eas_config.c; sourceTree = SOURCE_ROOT; }; + C5AB01790E340DD60051F183 /* AudioUnit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioUnit.framework; path = /System/Library/Frameworks/AudioUnit.framework; sourceTree = ""; }; + C5AB018B0E340EAA0051F183 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = /System/Library/Frameworks/AudioToolbox.framework; sourceTree = ""; }; + C5AB01900E340EC50051F183 /* CoreAudio.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudio.framework; path = /System/Library/Frameworks/CoreAudio.framework; sourceTree = ""; }; + C5AB02F50E341AAC0051F183 /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = /System/Library/Frameworks/Carbon.framework; sourceTree = ""; }; + D2AAC0630554660B00DB518D /* libEASLIb.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libEASLIb.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + D289988505E68E00004EDB86 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 9A56ACEA0F72B84D00D115A7 /* libeaswt_vst_lib.a in Frameworks */, + C5AB017A0E340DD60051F183 /* AudioUnit.framework in Frameworks */, + C5AB018C0E340EAA0051F183 /* AudioToolbox.framework in Frameworks */, + C5AB01910E340EC50051F183 /* CoreAudio.framework in Frameworks */, + C5AB02F60E341AAC0051F183 /* Carbon.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 08FB7794FE84155DC02AAC07 /* EASLIb */ = { + isa = PBXGroup; + children = ( + 9A56ACD30F72B7D600D115A7 /* easwt_vst_lib.xcodeproj */, + C5AB02F50E341AAC0051F183 /* Carbon.framework */, + C5AB01900E340EC50051F183 /* CoreAudio.framework */, + C5AB018B0E340EAA0051F183 /* AudioToolbox.framework */, + C5AB01790E340DD60051F183 /* AudioUnit.framework */, + 08FB7795FE84155DC02AAC07 /* Source */, + 1AB674ADFE9D54B511CA2CBB /* Products */, + ); + name = EASLIb; + sourceTree = ""; + }; + 08FB7795FE84155DC02AAC07 /* Source */ = { + isa = PBXGroup; + children = ( + C5AB01230E3406090051F183 /* eas_config.c */, + C5AB01070E3400DC0051F183 /* EASLib.h */, + C5AB01080E3400DC0051F183 /* EASLib.c */, + ); + name = Source; + sourceTree = ""; + }; + 1AB674ADFE9D54B511CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + D2AAC0630554660B00DB518D /* libEASLIb.dylib */, + ); + name = Products; + sourceTree = ""; + }; + 9A56ACD40F72B7D600D115A7 /* Products */ = { + isa = PBXGroup; + children = ( + 9A56ACD80F72B7D600D115A7 /* libeaswt_vst_lib.a */, + ); + name = Products; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + D2AAC0600554660B00DB518D /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + C5AB01090E3400DC0051F183 /* EASLib.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + D2AAC0620554660B00DB518D /* EASLIb */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1DEB914A08733D8E0010E9CD /* Build configuration list for PBXNativeTarget "EASLIb" */; + buildPhases = ( + D2AAC0600554660B00DB518D /* Headers */, + D2AAC0610554660B00DB518D /* Sources */, + D289988505E68E00004EDB86 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 9A56ACFD0F72B8B200D115A7 /* PBXTargetDependency */, + ); + name = EASLIb; + productName = EASLIb; + productReference = D2AAC0630554660B00DB518D /* libEASLIb.dylib */; + productType = "com.apple.product-type.library.dynamic"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 08FB7793FE84155DC02AAC07 /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 1DEB914E08733D8E0010E9CD /* Build configuration list for PBXProject "EASLIb" */; + compatibilityVersion = "Xcode 3.0"; + developmentRegion = English; + hasScannedForEncodings = 1; + knownRegions = ( + en, + ); + mainGroup = 08FB7794FE84155DC02AAC07 /* EASLIb */; + projectDirPath = ""; + projectReferences = ( + { + ProductGroup = 9A56ACD40F72B7D600D115A7 /* Products */; + ProjectRef = 9A56ACD30F72B7D600D115A7 /* easwt_vst_lib.xcodeproj */; + }, + ); + projectRoot = ""; + targets = ( + D2AAC0620554660B00DB518D /* EASLIb */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXReferenceProxy section */ + 9A56ACD80F72B7D600D115A7 /* libeaswt_vst_lib.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libeaswt_vst_lib.a; + remoteRef = 9A56ACD70F72B7D600D115A7 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; +/* End PBXReferenceProxy section */ + +/* Begin PBXSourcesBuildPhase section */ + D2AAC0610554660B00DB518D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + C5AB010A0E3400DC0051F183 /* EASLib.c in Sources */, + C5AB01240E3406090051F183 /* eas_config.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 9A56ACFD0F72B8B200D115A7 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = easwt_vst_lib; + targetProxy = 9A56ACFC0F72B8B200D115A7 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 1DEB914B08733D8E0010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = NO; + EXECUTABLE_PREFIX = lib; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_MODEL_TUNING = G5; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "EAS_MAX_FILE_HANDLES=100", + "_DEBUG_CMF=1", + "JET_INTERFACE=1", + "MAX_SMF_STREAMS=32", + "NUM_OUTPUT_CHANNELS=2", + "_SAMPLE_RATE_44100=1", + "_8_BIT_SAMPLES=1", + "_FILTER_ENABLED=1", + "_NO_DEBUG_PREPROCESSOR=1", + "_CORE_CYCLES_PER_MEMORY_CYCLE=1", + "_IMA_DECODER=1", + "_XMF_PARSER=1", + "_DLS_PARSER=1", + "MAX_DLS_MEMORY=16777216", + "EAS_WT_SYNTH=1", + "MAX_SYNTH_VOICES=64", + "X_ENHANCER_ENABLED=1", + "_REVERB_ENABLED=1", + "_CHORUS_ENABLED=1", + "DLS_SYNTHESIZER=1", + "EXTERNAL_AUDIO=1", + "TEST_HARNESS=1", + "MMAPI_SUPPORT=1", + "X_MAXIMIZER_ENABLED=1", + "X_COMPRESSOR_ENABLED=1", + "X_STATS=1", + "X_DEBUG_DLS=1", + "X_OPTIMIZED_MONO=1", + "X_CHECKED_BUILD=1", + "_NO_ALIGN=1", + "_C_REFERENCE=1", + "XMAXIMIZER_USE_FLOATING_POINT=1", + "BUFFERED_FILE_ACCESS=1", + ); + HEADER_SEARCH_PATHS = ( + "${TARGET_BUILD_DIR}/**", + "../../Common/**", + "../../Parsers/**", + "../../Effects/**", + "../../WTSynth/**", + "../../FMSynth/**", + "../../SplitArch/**", + "../../Jet/**", + ); + INSTALL_PATH = /usr/local/lib; + MACOSX_DEPLOYMENT_TARGET = 10.4; + PRODUCT_NAME = EASLIb; + ZERO_LINK = YES; + }; + name = Debug; + }; + 1DEB914C08733D8E0010E9CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = i386; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + EXECUTABLE_PREFIX = lib; + GCC_AUTO_VECTORIZATION = YES; + GCC_MODEL_TUNING = G5; + GCC_PREPROCESSOR_DEFINITIONS = ( + "BUFFERED_FILE_ACCESS=1", + "EAS_FILE_BUFFER_SIZE=1024", + "EAS_MAX_FILE_HANDLES=100", + "JET_INTERFACE=1", + "MAX_SMF_STREAMS=32", + "EAS_WT_SYNTH=1", + "NUM_OUTPUT_CHANNELS=2", + "_SAMPLE_RATE_44100=1", + "_8_BIT_SAMPLES=1", + "_FILTER_ENABLED=1", + "_NO_DEBUG_PREPROCESSOR=1", + "_CORE_CYCLES_PER_MEMORY_CYCLE=1", + "_IMA_DECODER=1", + "_XMF_PARSER=1", + "_DLS_PARSER=1", + "MAX_DLS_MEMORY=16777216", + "MAX_SYNTH_VOICES=64", + "X_ENHANCER_ENABLED=1", + "_REVERB_ENABLED=1", + "_CHORUS_ENABLED=1", + "DLS_SYNTHESIZER=1", + "EXTERNAL_AUDIO=1", + "TEST_HARNESS=1", + "MMAPI_SUPPORT=1", + "X_MAXIMIZER_ENABLED=1", + "X_COMPRESSOR_ENABLED=1", + "X_STATS=1", + "X_DEBUG_DLS=1", + "X_OPTIMIZED_MONO=1", + "X_CHECKED_BUILD=1", + "_NO_ALIGN=1", + "_C_REFERENCE=1", + "XMAXIMIZER_USE_FLOATING_POINT=1", + ); + GCC_UNROLL_LOOPS = YES; + HEADER_SEARCH_PATHS = ( + "${TARGET_BUILD_DIR}/**", + "../../Common/**", + "../../Parsers/**", + "../../Effects/**", + "../../WTSynth/**", + "../../FMSynth/**", + "../../SplitArch/**", + "../../Jet/**", + ); + INSTALL_PATH = /usr/local/lib; + MACOSX_DEPLOYMENT_TARGET = 10.4; + PRODUCT_NAME = EASLIb; + }; + name = Release; + }; + 1DEB914F08733D8E0010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + PREBINDING = NO; + SDKROOT = "$(DEVELOPER_SDK_DIR)/MacOSX10.5.sdk"; + }; + name = Debug; + }; + 1DEB915008733D8E0010E9CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = i386; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + PREBINDING = NO; + SDKROOT = "$(DEVELOPER_SDK_DIR)/MacOSX10.5.sdk"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1DEB914A08733D8E0010E9CD /* Build configuration list for PBXNativeTarget "EASLIb" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB914B08733D8E0010E9CD /* Debug */, + 1DEB914C08733D8E0010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1DEB914E08733D8E0010E9CD /* Build configuration list for PBXProject "EASLIb" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB914F08733D8E0010E9CD /* Debug */, + 1DEB915008733D8E0010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 08FB7793FE84155DC02AAC07 /* Project object */; +} diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/EASLIb.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/EASLIb.xcscheme b/common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/EASLIb.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/EASLIb.xcscheme new file mode 100755 index 0000000..4770fdf --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/EASLIb.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/EASLIb.xcscheme @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/EASLIb.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/xcschememanagement.plist b/common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/EASLIb.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100755 index 0000000..4f6c235 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/EASLIb.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,22 @@ + + + + + SchemeUserState + + EASLIb.xcscheme + + orderHint + 13 + + + SuppressBuildableAutocreation + + D2AAC0620554660B00DB518D + + primary + + + + + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/EASLIb.xcodeproj/xcuserdata/ryan.gerleve.xcuserdatad/xcschemes/EASLIb.xcscheme b/common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/EASLIb.xcodeproj/xcuserdata/ryan.gerleve.xcuserdatad/xcschemes/EASLIb.xcscheme new file mode 100755 index 0000000..4770fdf --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/EASLIb.xcodeproj/xcuserdata/ryan.gerleve.xcuserdatad/xcschemes/EASLIb.xcscheme @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/EASLIb.xcodeproj/xcuserdata/ryan.gerleve.xcuserdatad/xcschemes/xcschememanagement.plist b/common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/EASLIb.xcodeproj/xcuserdata/ryan.gerleve.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100755 index 0000000..b4f4c7c --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/EASLIb.xcodeproj/xcuserdata/ryan.gerleve.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,22 @@ + + + + + SchemeUserState + + EASLIb.xcscheme + + orderHint + 4 + + + SuppressBuildableAutocreation + + D2AAC0620554660B00DB518D + + primary + + + + + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/EASLib.c b/common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/EASLib.c new file mode 100755 index 0000000..ca19247 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/EASLib.c @@ -0,0 +1,1809 @@ +/* + * EASLib.c + * EASLIb + * + * + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include +#include +#include + +#include "eas.h" +#include "eas_report.h" +#include "eas_host.h" +#include +#include + +#ifdef JET_INTERFACE +#include "jet.h" +#endif + + +#define EAS_EXPORT __attribute__((visibility("default"))) + +// #define DEBUG_FILE_IO + +/* include debug interface */ +#include "eas_host_debug.h" + +#ifdef AUX_MIXER +#include "eas_auxmix.h" +#endif + +/* this module requires dynamic memory support */ +#ifdef _STATIC_MEMORY +#error "eas_hostmm.c requires the dynamic memory model!\n" +#endif + +#ifndef EAS_MAX_FILE_HANDLES +#define EAS_MAX_FILE_HANDLES 32 +#endif + +#ifndef EAS_FILE_BUFFER_SIZE +#define EAS_FILE_BUFFER_SIZE 32 +#endif + +/* + * this structure and the related function are here + * to support the ability to create duplicate handles + * and buffering it in memory. If your system uses + * in-memory resources, you can eliminate the calls + * to malloc and free, the dup flag, and simply track + * the file size and read position. + */ + #ifdef BUFFERED_FILE_ACCESS +typedef struct eas_hw_file_tag +{ + FILE *pFile; + EAS_I32 bytesInBuffer; + EAS_I32 readIndex; + EAS_I32 filePos; + EAS_I32 fileSize; + EAS_BOOL dup; + EAS_U8 buffer[EAS_FILE_BUFFER_SIZE]; +} EAS_HW_FILE; +#else +typedef struct eas_hw_file_tag +{ + EAS_I32 fileSize; + EAS_I32 filePos; + EAS_BOOL dup; + EAS_U8 *buffer; +} EAS_HW_FILE; +#endif + +typedef struct eas_hw_inst_data_tag +{ + EAS_HW_FILE files[EAS_MAX_FILE_HANDLES]; +} EAS_HW_INST_DATA; + +EAS_BOOL errorConditions[eNumErrorConditions]; +EAS_BOOL ledState; +EAS_BOOL vibState; +EAS_BOOL backlightState; + +#define MAX_DEBUG_MSG_LEN 1024 + +typedef void (*EAS_LOG_FUNC)(EAS_INT severity, char *msg); + +static EAS_LOG_FUNC logCallback = NULL; +static char messageBuffer[MAX_DEBUG_MSG_LEN]; + +/* error counts */ +static EAS_INT eas_fatalErrors; +static EAS_INT eas_errors; +static EAS_INT eas_warnings; +static int severityLevel = 9999; + + +#define MAX_BUFFERS 8 + +// The output unit +AudioUnit OutputUnit; +AudioStreamBasicDescription streamFormat; + +// sync stuf +pthread_mutex_t mtx; +pthread_cond_t cond; +bool bStopped = true; + +// buffer to hold the data +typedef struct +{ + UInt32 uOutBufferLength; + UInt32 uOutFrames; + int ix; + short* pData[8]; + unsigned int uLength; +} S_BUFFER_INFO; + +static S_BUFFER_INFO *pBuf = NULL; +const S_EAS_LIB_CONFIG *pConfig = NULL; + +/*---------------------------------------------------------------------------- + * ResetErrorCounters() + *---------------------------------------------------------------------------- +*/ +EAS_EXPORT void ResetErrorCounters() +{ + eas_fatalErrors = 0; + eas_errors = 0; + eas_warnings = 0; +} + +/*---------------------------------------------------------------------------- + * SetLogCallback() + *---------------------------------------------------------------------------- +*/ +EAS_EXPORT void SetLogCallback (EAS_LOG_FUNC callback) +{ + logCallback = callback; +} + +#ifndef _NO_DEBUG_PREPROCESSOR +static S_DEBUG_MESSAGES debugMessages[] = +{ +#ifdef UNIFIED_DEBUG_MESSAGES +#include "eas_debugmsgs.h" +#endif + { 0,0,0 } +}; + +/*---------------------------------------------------------------------------- + * EAS_ReportEx() + *---------------------------------------------------------------------------- +*/ +void EAS_ReportEx (int severity, unsigned long hashCode, int serialNum, ...) +{ + va_list vargs; + int i; + + switch (severity) + { + case _EAS_SEVERITY_FATAL: + eas_fatalErrors++; + break; + + case _EAS_SEVERITY_ERROR: + eas_errors++; + break; + + case _EAS_SEVERITY_WARNING: + eas_warnings++; + break; + + default: + break; + } + + /* check severity level */ + if (severity > severityLevel) + return; + + /* check for callback */ + if (logCallback == NULL) + return; + + /* find the error message and output to stdout */ + for (i = 0; debugMessages[i].m_pDebugMsg; i++) + { + if ((debugMessages[i].m_nHashCode == hashCode) && + (debugMessages[i].m_nSerialNum == serialNum)) + { + va_start(vargs, serialNum); +#ifdef WIN32 + vsprintf_s(messageBuffer, sizeof(messageBuffer), fmt, vargs); +#else + vsprintf(messageBuffer, debugMessages[i].m_pDebugMsg, vargs); +#endif + logCallback(severity, messageBuffer); + va_end(vargs); + return; + } + } + printf("Unrecognized error: Severity=%d; HashCode=%lu; SerialNum=%d\n", severity, hashCode, serialNum); +} /* end EAS_ReportEx */ + +#else +/*---------------------------------------------------------------------------- + * EAS_Report() + *---------------------------------------------------------------------------- +*/ +void EAS_Report (int severity, const char *fmt, ...) +{ + va_list vargs; + + switch (severity) + { + case _EAS_SEVERITY_FATAL: + eas_fatalErrors++; + break; + + case _EAS_SEVERITY_ERROR: + eas_errors++; + break; + + case _EAS_SEVERITY_WARNING: + eas_warnings++; + break; + + default: + break; + } + + /* check severity level */ + if (severity > severityLevel) + return; + + /* check for callback */ + if (logCallback == NULL) + return; + + va_start(vargs, fmt); +#ifdef _WIN32 + vsprintf_s(messageBuffer, sizeof(messageBuffer), fmt, vargs); +#else + vsprintf(messageBuffer, fmt, vargs); +#endif + logCallback(severity, messageBuffer); + va_end(vargs); +} /* end EAS_Report */ + +/*---------------------------------------------------------------------------- + * EAS_ReportX() + *---------------------------------------------------------------------------- +*/ +void EAS_ReportX (int severity, const char *fmt, ...) +{ + va_list vargs; + + switch (severity) + { + case _EAS_SEVERITY_FATAL: + eas_fatalErrors++; + break; + + case _EAS_SEVERITY_ERROR: + eas_errors++; + break; + + case _EAS_SEVERITY_WARNING: + eas_warnings++; + break; + + default: + break; + } + + /* check severity level */ + if (severity > severityLevel) + return; + + /* check for callback */ + if (logCallback == NULL) + return; + + va_start(vargs, fmt); +#ifdef _WIN32 + vsprintf_s(messageBuffer, sizeof(messageBuffer), fmt, vargs); +#else + vsprintf(messageBuffer, fmt, vargs); +#endif + logCallback(severity, messageBuffer); + va_end(vargs); +} +#endif + +/*---------------------------------------------------------------------------- + * EAS_DLLSetDebugLevel() + *---------------------------------------------------------------------------- +*/ +EAS_EXPORT void EAS_DLLSetDebugLevel (int severity) +{ + severityLevel = severity; +} + +/*---------------------------------------------------------------------------- + * EAS_ExSetDebugLevel() + *---------------------------------------------------------------------------- +*/ +void EAS_SetDebugLevel (int severity) +{ + severityLevel = severity; +} + +/*---------------------------------------------------------------------------- + * EAS_SelectLibrary() + *---------------------------------------------------------------------------- +*/ +EAS_EXPORT EAS_RESULT EAS_SelectLib (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_BOOL testLib) +{ + extern EAS_SNDLIB_HANDLE VMGetLibHandle(EAS_INT libNum); + return EAS_SetSoundLibrary(pEASData, streamHandle, VMGetLibHandle(testLib ? 1 : 0)); +} + +// Callback proc +static OSStatus RenderProc( void *inRefCon, + AudioUnitRenderActionFlags *ioActionFlags, + const AudioTimeStamp *inTimeStamp, + UInt32 inBusNumber, + UInt32 inNumberFrames, + AudioBufferList *ioData) +{ + // Get the mutex + pthread_mutex_lock(&mtx); + + short* ptrOutL = (short *)ioData->mBuffers[0].mData; + short* ptrOutR = (short *)ioData->mBuffers[1].mData; + + memset(ptrOutL, 0, pBuf->uOutFrames); + memset(ptrOutR, 0, pBuf->uOutFrames); + + // check if there is any data in the buffer + if (pBuf->ix == 0 ) + { + // Release the mutex and signal the python thread + pthread_mutex_unlock(&mtx); + pthread_cond_signal(&cond); + return 0; + } + + // Get a ptr to the data + short* pData = pBuf->pData[--(pBuf->ix)]; + + // Now copy the data + int i; + for (i = 0; i < pBuf->uOutFrames; i+=2 ) + { + *ptrOutL++ = pData[i]; + *ptrOutR++ = pData[i+1]; + } + + // Release the mutex + pthread_mutex_unlock(&mtx); + pthread_cond_signal(&cond); + + return 0; +} + +EAS_RESULT addData(EAS_PCM *pAudioBuffer) +{ + // Copy the data we got from the synth + memcpy(pBuf->pData[(pBuf->ix)++], pAudioBuffer, 2048); + + // Start the output Audio Unit only the first time + if ( bStopped == true ) + { + bStopped = false; + OSStatus err = AudioOutputUnitStart (OutputUnit); + if (err) + { + printf ("AudioDeviceStart=%ld\n", err); + return EAS_FAILURE; + } + } + + return EAS_SUCCESS; +} + + +EAS_EXPORT EAS_RESULT EAS_RenderWaveOut(EAS_DATA_HANDLE easHandle, EAS_PCM *pAudioBuffer, EAS_I32 numRequested, EAS_I32 *pNumGenerated) +{ + // Get the mutex + pthread_mutex_lock(&mtx); + + // Check if our buffer is full + while(pBuf->ix == MAX_BUFFERS - 1) + pthread_cond_wait(&cond, &mtx); + + // Call the synth the render a buffer + EAS_RESULT result = EAS_Render(easHandle, pAudioBuffer, numRequested, pNumGenerated); + addData( pAudioBuffer ); + + // Release the mutex + pthread_mutex_unlock(&mtx); + + //Done + return result; +} + +#ifdef AUX_MIXER +EAS_EXPORT EAS_RESULT EAS_RenderAuxMixerWaveOut (EAS_DATA_HANDLE easHandle, EAS_PCM *pAudioBuffer, EAS_I32 *pNumGenerated) +{ + // Get the mutex + pthread_mutex_lock(&mtx); + + // Check if our buffer is full + while(pBuf->ix == MAX_BUFFERS - 1) + pthread_cond_wait(&cond, &mtx); + + EAS_RESULT result = EAS_RenderAuxMixer(easHandle, pAudioBuffer, pNumGenerated); + addData( pAudioBuffer ); + + // Release the mutex + pthread_mutex_unlock(&mtx); + + return result; +} +#endif + +EAS_EXPORT EAS_RESULT OpenWaveOutDevice(EAS_INT devNum, EAS_INT sampleRate, EAS_INT maxBufSize) +{ + // Open the default output unit + ComponentDescription desc; + desc.componentType = kAudioUnitType_Output; + desc.componentSubType = kAudioUnitSubType_DefaultOutput; + desc.componentManufacturer = kAudioUnitManufacturer_Apple; + desc.componentFlags = 0; + desc.componentFlagsMask = 0; + + Component comp = FindNextComponent(NULL, &desc); + if (comp == NULL) + { + printf ("Could find the default output unit!!!\n"); + return EAS_FAILURE; + } + + OSStatus err = OpenAComponent(comp, &OutputUnit); + if (comp == NULL) + { + printf ("OpenAComponent=%ld\n", err); + return EAS_FAILURE; + } + + // Set up a callback function to generate output to the output unit + AURenderCallbackStruct auRenderCallback; + auRenderCallback.inputProc = RenderProc; + auRenderCallback.inputProcRefCon = NULL; + + err = AudioUnitSetProperty (OutputUnit, + kAudioUnitProperty_SetRenderCallback, + kAudioUnitScope_Input, + 0, + &auRenderCallback, + sizeof(auRenderCallback)); + if (err) + { + printf ("AudioUnitSetProperty-CB=%ld\n", err); + return EAS_FAILURE;; + } + + pConfig = EAS_Config(); + + // The synth engine already uses short* for the buffers so let CoreAudio do any conversions if needed + if (sampleRate != 0) + streamFormat.mSampleRate = sampleRate; + else + streamFormat.mSampleRate = pConfig->sampleRate; + + streamFormat.mFormatID = kAudioFormatLinearPCM; + streamFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger + | kAudioFormatFlagsNativeEndian + | kLinearPCMFormatFlagIsPacked + | kAudioFormatFlagIsNonInterleaved; + + streamFormat.mBytesPerPacket = 2; + streamFormat.mFramesPerPacket = 1; + streamFormat.mBytesPerFrame = 2; + streamFormat.mChannelsPerFrame = 2; + streamFormat.mBitsPerChannel = 16; + + err = AudioUnitSetProperty (OutputUnit, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Input, + 0, + &streamFormat, + sizeof(AudioStreamBasicDescription)); + if (err) + { + printf ("AudioUnitSetProperty-SF= %4.4s, %ld\n", (char*)&err, err); + return EAS_FAILURE; + } + + // Initialize + err = AudioUnitInitialize(OutputUnit); + if (err) + { + printf ("AudioUnitInitialize = %ld\n", err); + return EAS_FAILURE; + } + + pBuf = (S_BUFFER_INFO *) malloc(sizeof(S_BUFFER_INFO)); + if( !pBuf ) + return EAS_FAILURE; + + pBuf->uOutBufferLength = pConfig->mixBufferSize * streamFormat.mBitsPerChannel / 2; + UInt32 uDataSize = sizeof(pBuf->uOutBufferLength); + + err = AudioUnitSetProperty(OutputUnit, kAudioDevicePropertyBufferSize, kAudioUnitScope_Output, 0, &pBuf->uOutBufferLength, uDataSize); + if (err) + { + printf ("AudioUnitSetProperty = %ld\n", err); + return EAS_FAILURE; + } + + err = AudioUnitGetProperty(OutputUnit, kAudioDevicePropertyBufferSize, kAudioUnitScope_Output, 0, &pBuf->uOutBufferLength, &uDataSize); + if (err) + { + printf ("AudioUnitGetProperty = %ld\n", err); + return EAS_FAILURE; + } + + pBuf->uLength = pBuf->uOutBufferLength; + int i; + for ( i = 0; i < MAX_BUFFERS; i++) + pBuf->pData[i] = malloc(pBuf->uLength); + + pBuf->uOutBufferLength /= pConfig->numChannels; + pBuf->uOutFrames = pBuf->uOutBufferLength / sizeof(short); + + pBuf->ix = 0; + + // Init the stop flag + bStopped = true; + + int result = pthread_mutex_init(&mtx, NULL); + if (result) + { + printf("pthread_mutex_init failed\n"); + return EAS_FAILURE; + } + + result = pthread_cond_init(&cond, NULL); + if (result) + { + printf("pthread_cond_init failed\n"); + return EAS_FAILURE; + } + + // Done + return EAS_SUCCESS; +} + + +EAS_EXPORT EAS_RESULT StartStream() +{ + OSStatus err = noErr; + pthread_mutex_lock(&mtx); + if ( bStopped == true ) + { + err = AudioOutputUnitStart (OutputUnit); + if (err) + { + printf ("AudioOutputUnitStart=%ld\n", err); + return EAS_FAILURE; + } + bStopped = false; + } + + return EAS_SUCCESS; +} + + +EAS_EXPORT EAS_RESULT CloseWaveOutDevice() +{ + OSStatus err; + + pthread_mutex_lock(&mtx); + if( false == bStopped ) + { + AudioOutputUnitStop (OutputUnit); + bStopped = true; + + err = AudioUnitUninitialize (OutputUnit); + if (err) + { + printf ("AudioUnitUninitialize=%ld\n", err); + return EAS_FAILURE; + } + + CloseComponent (OutputUnit); + int i = 0; + for(i; i < MAX_BUFFERS; i++) + free(pBuf->pData[i]); + + free(pBuf); + } + + pthread_mutex_unlock(&mtx); + return EAS_SUCCESS; +} + + +#if defined(_DEBUG) && !defined(MSC) +#include +/*---------------------------------------------------------------------------- + * EnableHeapDebug() + *---------------------------------------------------------------------------- +*/ +static void EnableHeapDebug (void) +{ + int temp; + temp = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); + temp |= _CRTDBG_ALLOC_MEM_DF; + temp |= _CRTDBG_CHECK_ALWAYS_DF; + temp |= _CRTDBG_LEAK_CHECK_DF; +// temp |= _CRTDBG_DELAY_FREE_MEM_DF; + _CrtSetDbgFlag(temp); +} + +/*---------------------------------------------------------------------------- + * HeapCheck() + *---------------------------------------------------------------------------- + * Check heap status + *---------------------------------------------------------------------------- +*/ +void HeapCheck (void) +{ + int heapStatus; + + /* Check heap status */ + heapStatus = _heapchk(); + if ((heapStatus == _HEAPOK) || (heapStatus == _HEAPEMPTY)) + return; + + EAS_ReportX(_EAS_SEVERITY_FATAL, "Heap corrupt\n" ); +} +#endif + + +/*---------------------------------------------------------------------------- + * EAS_HWInit + * + * Initialize host wrapper interface + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_HWInit (EAS_HW_DATA_HANDLE *pHWInstData) +{ + +#if defined(_DEBUG) && !defined(MSC) + EnableHeapDebug(); +#endif + + #ifdef BUFFERED_FILE_ACCESS + EAS_ReportX(_EAS_SEVERITY_INFO, "EAS_HWInit: Buffered file access\n"); + #else + EAS_ReportX(_EAS_SEVERITY_INFO, "EAS_HWInit: Memory mapped file access\n"); + #endif + + /* simulate failure */ + if (errorConditions[eInitError]) + return EAS_FAILURE; + + /* need to track file opens for duplicate handles */ + *pHWInstData = malloc(sizeof(EAS_HW_INST_DATA)); + if (!(*pHWInstData)) + return EAS_ERROR_MALLOC_FAILED; + + EAS_HWMemSet(*pHWInstData, 0, sizeof(EAS_HW_INST_DATA)); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_HWShutdown + * + * Shut down host wrapper interface + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_HWShutdown (EAS_HW_DATA_HANDLE hwInstData) +{ + + /* simulate failure */ + if (errorConditions[eShutdownError]) + return EAS_FAILURE; + + free(hwInstData); + +#if defined(_DEBUG) && !defined(MSC) + HeapCheck(); +#endif + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWMalloc + * + * Allocates dynamic memory + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) available for customer use */ +void *EAS_HWMalloc (EAS_HW_DATA_HANDLE hwInstData, EAS_I32 size) +{ + /* simulate failure */ + if (errorConditions[eMallocError]) + return NULL; + + return malloc((size_t) size); +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWFree + * + * Frees dynamic memory + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) available for customer use */ +void EAS_HWFree (EAS_HW_DATA_HANDLE hwInstData, void *p) +{ + free(p); +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWMemCpy + * + * Copy memory wrapper + * + *---------------------------------------------------------------------------- +*/ +void *EAS_HWMemCpy (void *dest, const void *src, EAS_I32 amount) +{ + return memcpy(dest, src, (size_t) amount); +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWMemSet + * + * Set memory wrapper + * + *---------------------------------------------------------------------------- +*/ +void *EAS_HWMemSet (void *dest, int val, EAS_I32 amount) +{ + return memset(dest, val, (size_t) amount); +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWMemCmp + * + * Compare memory wrapper + * + *---------------------------------------------------------------------------- +*/ +EAS_I32 EAS_HWMemCmp (const void *s1, const void *s2, EAS_I32 amount) +{ + return (EAS_I32) memcmp(s1, s2, (size_t) amount); +} + +#ifdef BUFFERED_FILE_ACCESS +/*---------------------------------------------------------------------------- + * + * EAS_HWOpenFile + * + * Open a file for read or write + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_HWOpenFile (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_LOCATOR locator, EAS_FILE_HANDLE *pFile, EAS_FILE_MODE mode) +{ + EAS_HW_FILE *file; + int i; + + /* set return value to NULL */ + *pFile = NULL; + + /* only support read mode at this time */ + if (mode != EAS_FILE_READ) + return EAS_ERROR_INVALID_FILE_MODE; + + /* find an empty entry in the file table */ + file = hwInstData->files; + for (i = 0; i < EAS_MAX_FILE_HANDLES; i++) + { + /* is this slot being used? */ + if (file->pFile == NULL) + { + EAS_RESULT result; + + /* open the file */ + file->pFile = fopen((const char*) locator, "rb"); + if (file->pFile == NULL) + return EAS_ERROR_FILE_OPEN_FAILED; + + /* get file length */ + if ((result = EAS_HWFileLength(hwInstData, file, &file->fileSize)) != EAS_SUCCESS) + { + EAS_HWCloseFile(hwInstData, file); + return result; + } + +#ifdef DEBUG_FILE_IO + EAS_ReportX(_EAS_SEVERITY_NOFILTER, "EAS_HWOpenFile: Open file %d\n", i); +#endif + + /* initialize some values */ + file->bytesInBuffer = 0; + file->readIndex = 0; + file->filePos = 0; + file->dup = EAS_FALSE; + + *pFile = file; + return EAS_SUCCESS; + } + file++; + } + + /* too many open files */ + return EAS_ERROR_MAX_FILES_OPEN; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWFillBuffer + * + * Fill buffer from file + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWFillBuffer (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file) +{ + /* reposition the file pointer */ + if (fseek(file->pFile, file->filePos, SEEK_SET) != 0) + return EAS_ERROR_FILE_SEEK; + + /* read some data from the file */ + file->bytesInBuffer = (EAS_I32) fread(file->buffer, 1, EAS_FILE_BUFFER_SIZE, file->pFile); + file->readIndex = 0; + if (file->bytesInBuffer == 0) + return EAS_EOF; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWReadFile + * + * Read data from a file + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWReadFile (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *pBuffer, EAS_I32 n, EAS_I32 *pBytesRead) +{ + EAS_RESULT result; + EAS_I32 temp; + EAS_U8 *p = pBuffer; + EAS_I32 bytesLeft = n; + + *pBytesRead = 0; + + /* check handle integrity */ + if (file->pFile == NULL) + return EAS_ERROR_INVALID_HANDLE; + +#ifdef DEBUG_FILE_IO + EAS_ReportX(_EAS_SEVERITY_NOFILTER, "EAS_HWReadFile: Reading %d bytes from position %d\n", n, file->filePos); +#endif + + /* try to fulfill request from buffer */ + for (;bytesLeft > 0;) + { + /* how many bytes can we get from buffer? */ + temp = file->bytesInBuffer - file->readIndex; + if (temp > bytesLeft) + temp = bytesLeft; + + /* copy data from buffer */ + EAS_HWMemCpy(p, &file->buffer[file->readIndex], temp); + *pBytesRead += temp; + file->readIndex += temp; + file->filePos += temp; + p += temp; + bytesLeft -= temp; + + /* don't refill buffer if request is bigger than buffer */ + if ((bytesLeft == 0) || (bytesLeft >= EAS_FILE_BUFFER_SIZE)) + break; + + /* refill buffer */ + if ((result = EAS_HWFillBuffer(hwInstData, file)) != EAS_SUCCESS) + return result; + } + + /* more to read? do unbuffered read directly to target memory */ + if (bytesLeft) + { + + /* position the file pointer */ + if (fseek(file->pFile, file->filePos, SEEK_SET) != 0) + return EAS_ERROR_FILE_SEEK; + + /* read data in the buffer */ + temp = (EAS_I32) fread(p, 1, (size_t) bytesLeft, file->pFile); + *pBytesRead += temp; + file->filePos += temp; + + /* reset buffer info */ + file->bytesInBuffer = 0; + file->readIndex = 0; + } + +#ifdef DEBUG_FILE_IO + { +#define BYTES_PER_LINE 16 + char str[BYTES_PER_LINE * 3 + 1]; + EAS_INT i; + for (i = 0; i < (n > BYTES_PER_LINE ? BYTES_PER_LINE : n) ; i ++) + sprintf(&str[i*3], "%02x ", ((EAS_U8*)pBuffer)[i]); + if (i) + EAS_ReportX(_EAS_SEVERITY_NOFILTER, "%s\n", str); + } +#endif + + /* were n bytes read? */ + if (*pBytesRead != n) + return EAS_EOF; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWGetByte + * + * Read a byte from a file + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWGetByte (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *p) +{ + EAS_RESULT result; + + /* check handle integrity */ + if (file->pFile == NULL) + return EAS_ERROR_INVALID_HANDLE; + + /* use local buffer - do we have any data? */ + if (file->readIndex >= file->bytesInBuffer) + { + if ((result = EAS_HWFillBuffer(hwInstData, file)) != EAS_SUCCESS) + return result; + + /* if nothing to read, return EOF */ + if (file->bytesInBuffer == 0) + return EAS_EOF; + } + + /* get a character from the buffer */ + *((EAS_U8*) p) = file->buffer[file->readIndex++]; + +#ifdef DEBUG_FILE_IO + EAS_ReportX(_EAS_SEVERITY_NOFILTER, "EAS_HWGetByte: Reading from position %d, byte = 0x%02x\n", file->filePos, *(EAS_U8*)p); +#endif + + file->filePos++; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWGetWord + * + * Read a 16-bit value from the file + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_HWGetWord (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *p, EAS_BOOL msbFirst) +{ + EAS_RESULT result; + EAS_I32 count; + EAS_U8 c[2]; + +#ifdef DEBUG_FILE_IO + EAS_ReportX(_EAS_SEVERITY_NOFILTER, "EAS_HWGetWord: Reading 2 bytes from position %d\n", file->filePos); +#endif + + /* read 2 bytes from the file */ + if ((result = EAS_HWReadFile(hwInstData, file, c, 2, &count)) != EAS_SUCCESS) + return result; + + /* order them as requested */ + if (msbFirst) + *((EAS_U16*) p) = ((EAS_U16) c[0] << 8) | c[1]; + else + *((EAS_U16*) p) = ((EAS_U16) c[1] << 8) | c[0]; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWGetDWord + * + * Read a 16-bit value from the file + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_HWGetDWord (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *p, EAS_BOOL msbFirst) +{ + EAS_RESULT result; + EAS_I32 count; + EAS_U8 c[4]; + +#ifdef DEBUG_FILE_IO + EAS_ReportX(_EAS_SEVERITY_NOFILTER, "EAS_HWGetDWord: Reading 4 bytes from position %d\n", file->filePos); +#endif + + /* read 4 bytes from the file */ + if ((result = EAS_HWReadFile(hwInstData, file, c, 4, &count)) != EAS_SUCCESS) + return result; + + /* order them as requested */ + if (msbFirst) + *((EAS_U32*) p) = ((EAS_U32) c[0] << 24) | ((EAS_U32) c[1] << 16) | ((EAS_U32) c[2] << 8) | c[3]; + else + *((EAS_U32*) p) = ((EAS_U32) c[3] << 24) | ((EAS_U32) c[2] << 16) | ((EAS_U32) c[1] << 8) | c[0]; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWFilePos + * + * Returns the current location in the file + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWFilePos (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 *pPosition) +{ + + /* check handle integrity */ + if (file->pFile == NULL) + return EAS_ERROR_INVALID_HANDLE; + + *pPosition = file->filePos; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWFileSeek + * + * Seek to a specific location in the file + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWFileSeek (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 position) +{ + EAS_I32 newIndex; + + /* check handle integrity */ + if (file->pFile == NULL) + return EAS_ERROR_INVALID_HANDLE; + + /* check for seek past end */ + if ((position < 0) || (position > file->fileSize)) + return EAS_ERROR_FILE_SEEK; + +#ifdef DEBUG_FILE_IO + EAS_ReportX(_EAS_SEVERITY_NOFILTER, "EAS_HWFileSeek: Seeking to new position %d\n", file->filePos); +#endif + + /* is new position in current buffer? */ + newIndex = position - file->filePos + file->readIndex; + if ((newIndex >= 0) && (newIndex < file->bytesInBuffer)) + { + file->readIndex = newIndex; + file->filePos = position; + return EAS_SUCCESS; + } + + /* save new position and reset buffer info so EAS_HWGetByte doesn't fail */ + file->filePos = position; + file->bytesInBuffer = 0; + file->readIndex = 0; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWFileSeekOfs + * + * Seek forward or back relative to the current position + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWFileSeekOfs (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 position) +{ + EAS_I32 temp; + +#ifdef DEBUG_FILE_IO + EAS_ReportX(_EAS_SEVERITY_NOFILTER, "EAS_HWFileSeekOfs: Seeking to new position %d\n", file->filePos + position); +#endif + + /* check handle integrity */ + if (file->pFile == NULL) + return EAS_ERROR_INVALID_HANDLE; + + /* check for seek past end */ + temp = file->filePos + position; + if ((temp < 0) || (temp > file->fileSize)) + return EAS_ERROR_FILE_SEEK; + + /* is new position in current buffer? */ + temp = position + file->readIndex; + if ((temp >= 0) && (temp < file->bytesInBuffer)) + { + file->readIndex = temp; + file->filePos += position; + return EAS_SUCCESS; + } + + /* save new position and reset buffer info so EAS_HWGetByte doesn't fail */ + file->filePos += position; + file->bytesInBuffer = 0; + file->readIndex = 0; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWFileLength + * + * Return the file length + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWFileLength (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 *pLength) +{ + long pos; + + /* check handle integrity */ + if (file->pFile == NULL) + return EAS_ERROR_INVALID_HANDLE; + + if ((pos = ftell(file->pFile)) == -1L) + return EAS_ERROR_FILE_LENGTH; + if (fseek(file->pFile, 0L, SEEK_END) != 0) + return EAS_ERROR_FILE_LENGTH; + if ((*pLength = ftell(file->pFile)) == -1L) + return EAS_ERROR_FILE_LENGTH; + if (fseek(file->pFile, pos, SEEK_SET) != 0) + return EAS_ERROR_FILE_LENGTH; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWDupHandle + * + * Duplicate a file handle + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_HWDupHandle (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_FILE_HANDLE* pDupFile) +{ + EAS_HW_FILE *dupfile; + int i; + + /* check handle integrity */ + *pDupFile = NULL; + if (file->pFile == NULL) + return EAS_ERROR_INVALID_HANDLE; + + /* find an empty entry in the file table */ + dupfile = hwInstData->files; + for (i = 0; i < EAS_MAX_FILE_HANDLES; i++) + { + /* is this slot being used? */ + if (dupfile->pFile == NULL) + { + + /* copy info from the handle to be duplicated */ + dupfile->filePos = file->filePos; + dupfile->pFile = file->pFile; + dupfile->fileSize = file->fileSize; + + /* set the duplicate handle flag */ + dupfile->dup = file->dup = EAS_TRUE; + + /* initialize some values */ + dupfile->bytesInBuffer = 0; + dupfile->readIndex = 0; + + *pDupFile = dupfile; + return EAS_SUCCESS; + } + dupfile++; + } + + /* too many open files */ + return EAS_ERROR_MAX_FILES_OPEN; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWClose + * + * Wrapper for fclose function + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_HWCloseFile (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file1) +{ + EAS_HW_FILE *file2,*dupFile; + int i; + + /* check handle integrity */ + if (file1->pFile == NULL) + return EAS_ERROR_INVALID_HANDLE; + + /* check for duplicate handle */ + if (file1->dup) + { + dupFile = NULL; + file2 = hwInstData->files; + for (i = 0; i < EAS_MAX_FILE_HANDLES; i++) + { + /* check for duplicate */ + if ((file1 != file2) && (file2->pFile == file1->pFile)) + { + /* is there more than one duplicate? */ + if (dupFile != NULL) + { + /* clear this entry and return */ + file1->pFile = NULL; + return EAS_SUCCESS; + } + + /* this is the first duplicate found */ + dupFile = file2; + } + file2++; + } + + /* there is only one duplicate, clear the dup flag */ + if (dupFile) + dupFile->dup = EAS_FALSE; + else + /* if we get here, there's a serious problem */ + return EAS_ERROR_HANDLE_INTEGRITY; + + /* clear this entry and return */ + file1->pFile = NULL; + return EAS_SUCCESS; + } + + /* no duplicates - close the file */ + if (fclose(file1->pFile) != 0) + return EAS_ERROR_CLOSE_FAILED; + + /* clear this entry and return */ + file1->pFile = NULL; + return EAS_SUCCESS; +} +#else +/*---------------------------------------------------------------------------- + * + * EAS_HWOpenFile + * + * Open a file for read or write + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_HWOpenFile (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_LOCATOR locator, EAS_FILE_HANDLE *pFile, EAS_FILE_MODE mode) +{ + EAS_HW_FILE *file; + FILE *ioFile; + int i, temp; + + /* set return value to NULL */ + *pFile = NULL; + + /* simulate failure */ + if (errorConditions[eOpenError]) + return EAS_FAILURE; + + /* only support read mode at this time */ + if (mode != EAS_FILE_READ) + return EAS_ERROR_INVALID_FILE_MODE; + + /* find an empty entry in the file table */ + file = hwInstData->files; + for (i = 0; i < EAS_MAX_FILE_HANDLES; i++) + { + /* is this slot being used? */ + if (file->buffer == NULL) + { + /* open the file */ + if ((ioFile = fopen(locator,"rb")) == NULL) + return EAS_ERROR_FILE_OPEN_FAILED; + + /* determine the file size */ + if (fseek(ioFile, 0L, SEEK_END) != 0) + return EAS_ERROR_FILE_LENGTH; + if ((file->fileSize = ftell(ioFile)) == -1L) + return EAS_ERROR_FILE_LENGTH; + if (fseek(ioFile, 0L, SEEK_SET) != 0) + return EAS_ERROR_FILE_LENGTH; + + /* allocate a buffer */ + file->buffer = EAS_HWMalloc(hwInstData, file->fileSize); + if (file->buffer == NULL) + { + fclose(ioFile); + return EAS_ERROR_MALLOC_FAILED; + } + + /* read the file into memory */ + temp = (int) fread(file->buffer, (size_t) file->fileSize, 1, ioFile); + + /* close the file - don't need it any more */ + fclose(ioFile); + + /* check for error reading file */ + if (temp != 1) + return EAS_ERROR_FILE_READ_FAILED; + + /* initialize some values */ + file->filePos = 0; + file->dup = EAS_FALSE; + + *pFile = file; + return EAS_SUCCESS; + } + file++; + } + + /* too many open files */ + return EAS_ERROR_MAX_FILES_OPEN; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWReadFile + * + * Read data from a file + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) available for customer use */ +EAS_RESULT EAS_HWReadFile (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *pBuffer, EAS_I32 n, EAS_I32 *pBytesRead) +{ + EAS_I32 count; + + /* simulate failure */ + if (errorConditions[eReadError]) + return EAS_FAILURE; + + /* make sure we have a valid handle */ + if (file->buffer == NULL) + return EAS_ERROR_INVALID_HANDLE; + + /* calculate the bytes to read */ + count = file->fileSize - file->filePos; + if (n < count) + count = n; + + /* copy the data to the requested location, and advance the pointer */ + if (count) + EAS_HWMemCpy(pBuffer, &file->buffer[file->filePos], count); + file->filePos += count; + *pBytesRead = count; + + /* were n bytes read? */ + if (count!= n) + return EAS_EOF; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWGetByte + * + * Read a byte from a file + * + *---------------------------------------------------------------------------- +*/ +/*lint -e{715} hwInstData available for customer use */ +EAS_RESULT EAS_HWGetByte (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *p) +{ + + /* simulate failure */ + if (errorConditions[eReadError]) + return EAS_FAILURE; + + /* make sure we have a valid handle */ + if (file->buffer == NULL) + return EAS_ERROR_INVALID_HANDLE; + + /* check for end of file */ + if (file->filePos >= file->fileSize) + { + *((EAS_U8*) p) = 0; + return EAS_EOF; + } + + /* get a character from the buffer */ + *((EAS_U8*) p) = file->buffer[file->filePos++]; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWGetWord + * + * Returns the current location in the file + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) available for customer use */ +EAS_RESULT EAS_HWGetWord (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *p, EAS_BOOL msbFirst) +{ + EAS_RESULT result; + EAS_U8 c1, c2; + + /* read 2 bytes from the file */ + if ((result = EAS_HWGetByte(hwInstData, file, &c1)) != EAS_SUCCESS) + return result; + if ((result = EAS_HWGetByte(hwInstData, file, &c2)) != EAS_SUCCESS) + return result; + + /* order them as requested */ + if (msbFirst) + *((EAS_U16*) p) = ((EAS_U16) c1 << 8) | c2; + else + *((EAS_U16*) p) = ((EAS_U16) c2 << 8) | c1; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWGetDWord + * + * Returns the current location in the file + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) available for customer use */ +EAS_RESULT EAS_HWGetDWord (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *p, EAS_BOOL msbFirst) +{ + EAS_RESULT result; + EAS_U8 c1, c2,c3,c4; + + /* read 4 bytes from the file */ + if ((result = EAS_HWGetByte(hwInstData, file, &c1)) != EAS_SUCCESS) + return result; + if ((result = EAS_HWGetByte(hwInstData, file, &c2)) != EAS_SUCCESS) + return result; + if ((result = EAS_HWGetByte(hwInstData, file, &c3)) != EAS_SUCCESS) + return result; + if ((result = EAS_HWGetByte(hwInstData, file, &c4)) != EAS_SUCCESS) + return result; + + /* order them as requested */ + if (msbFirst) + *((EAS_U32*) p) = ((EAS_U32) c1 << 24) | ((EAS_U32) c2 << 16) | ((EAS_U32) c3 << 8) | c4; + else + *((EAS_U32*) p)= ((EAS_U32) c4 << 24) | ((EAS_U32) c3 << 16) | ((EAS_U32) c2 << 8) | c1; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWFilePos + * + * Returns the current location in the file + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) available for customer use */ +EAS_RESULT EAS_HWFilePos (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 *pPosition) +{ + + /* simulate failure */ + if (errorConditions[ePosError]) + return EAS_FAILURE; + + /* make sure we have a valid handle */ + if (file->buffer == NULL) + return EAS_ERROR_INVALID_HANDLE; + + *pPosition = file->filePos; + return EAS_SUCCESS; +} /* end EAS_HWFilePos */ + +/*---------------------------------------------------------------------------- + * + * EAS_HWFileSeek + * + * Seek to a specific location in the file + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) available for customer use */ +EAS_RESULT EAS_HWFileSeek (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 position) +{ + + /* simulate failure */ + if (errorConditions[eSeekError]) + return EAS_FAILURE; + + /* make sure we have a valid handle */ + if (file->buffer == NULL) + return EAS_ERROR_INVALID_HANDLE; + + /* validate new position */ + if ((position < 0) || (position > file->fileSize)) + return EAS_ERROR_FILE_SEEK; + + /* save new position */ + file->filePos = position; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWFileSeekOfs + * + * Seek forward or back relative to the current position + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) available for customer use */ +EAS_RESULT EAS_HWFileSeekOfs (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 position) +{ + + /* simulate failure */ + if (errorConditions[eSeekError]) + return EAS_FAILURE; + + /* make sure we have a valid handle */ + if (file->buffer == NULL) + return EAS_ERROR_INVALID_HANDLE; + + /* determine the file position */ + position += file->filePos; + if ((position < 0) || (position > file->fileSize)) + return EAS_ERROR_FILE_SEEK; + + /* save new position */ + file->filePos = position; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWFileLength + * + * Return the file length + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) available for customer use */ +EAS_RESULT EAS_HWFileLength (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 *pLength) +{ + + /* simulate failure */ + if (errorConditions[eLengthError]) + return EAS_FAILURE; + + /* make sure we have a valid handle */ + if (file->buffer == NULL) + return EAS_ERROR_INVALID_HANDLE; + + *pLength = file->fileSize; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWDupHandle + * + * Duplicate a file handle + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_HWDupHandle (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_FILE_HANDLE *pDupFile) +{ + EAS_HW_FILE *dupFile; + int i; + + /* simulate failure */ + if (errorConditions[eDupError]) + return EAS_FAILURE; + + /* make sure we have a valid handle */ + if (file->buffer == NULL) + return EAS_ERROR_INVALID_HANDLE; + + /* find an empty entry in the file table */ + dupFile = hwInstData->files; + for (i = 0; i < EAS_MAX_FILE_HANDLES; i++) + { + /* is this slot being used? */ + if (dupFile->buffer == NULL) + { + + /* copy info from the handle to be duplicated */ + dupFile->filePos = file->filePos; + dupFile->fileSize = file->fileSize; + dupFile->buffer = file->buffer; + + /* set the duplicate handle flag */ + dupFile->dup = file->dup = EAS_TRUE; + + *pDupFile = dupFile; + return EAS_SUCCESS; + } + dupFile++; + } + + /* too many open files */ + return EAS_ERROR_MAX_FILES_OPEN; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWClose + * + * Wrapper for fclose function + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_HWCloseFile (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file1) +{ + EAS_HW_FILE *file2,*dupFile; + int i; + + /* simulate failure */ + if (errorConditions[eCloseError]) + return EAS_FAILURE; + + /* make sure we have a valid handle */ + if (file1->buffer == NULL) + return EAS_ERROR_INVALID_HANDLE; + + /* check for duplicate handle */ + if (file1->dup) + { + dupFile = NULL; + file2 = hwInstData->files; + for (i = 0; i < EAS_MAX_FILE_HANDLES; i++) + { + /* check for duplicate */ + if ((file1 != file2) && (file2->buffer == file1->buffer)) + { + /* is there more than one duplicate? */ + if (dupFile != NULL) + { + /* clear this entry and return */ + file1->buffer = NULL; + return EAS_SUCCESS; + } + + /* this is the first duplicate found */ + else + dupFile = file2; + } + file2++; + } + + /* there is only one duplicate, clear the dup flag */ + if (dupFile) + dupFile->dup = EAS_FALSE; + else + /* if we get here, there's a serious problem */ + return EAS_ERROR_HANDLE_INTEGRITY; + + /* clear this entry and return */ + file1->buffer = NULL; + return EAS_SUCCESS; + } + + /* no duplicates -free the buffer */ + EAS_HWFree(hwInstData, file1->buffer); + + /* clear this entry and return */ + file1->buffer = NULL; + return EAS_SUCCESS; +} +#endif + +/*---------------------------------------------------------------------------- + * + * EAS_HWVibrate + * + * Turn on/off vibrate function + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) available for customer use */ +EAS_RESULT EAS_HWVibrate (EAS_HW_DATA_HANDLE hwInstData, EAS_BOOL state) +{ + vibState = state; +// EAS_ReportX(_EAS_SEVERITY_NOFILTER, "Vibrate state: %d\n", state); + return EAS_SUCCESS; +} /* end EAS_HWVibrate */ + +/*---------------------------------------------------------------------------- + * + * EAS_HWLED + * + * Turn on/off LED + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) available for customer use */ +EAS_RESULT EAS_HWLED (EAS_HW_DATA_HANDLE hwInstData, EAS_BOOL state) +{ + ledState = state; +// EAS_ReportX(_EAS_SEVERITY_NOFILTER, "LED state: %d\n", state); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWBackLight + * + * Turn on/off backlight + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) available for customer use */ +EAS_RESULT EAS_HWBackLight (EAS_HW_DATA_HANDLE hwInstData, EAS_BOOL state) +{ + backlightState = state; +// EAS_ReportX(_EAS_SEVERITY_NOFILTER, "Backlight state: %d\n", state); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWYield + * + * This function is called periodically by the EAS library to give the + * host an opportunity to allow other tasks to run. There are two ways to + * use this call: + * + * If you have a multi-tasking OS, you can call the yield function in the + * OS to allow other tasks to run. In this case, return EAS_FALSE to tell + * the EAS library to continue processing when control returns from this + * function. + * + * If tasks run in a single thread by sequential function calls (sometimes + * call a "commutator loop"), return EAS_TRUE to cause the EAS Library to + * return to the caller. Be sure to check the number of bytes rendered + * before passing the audio buffer to the codec - it may not be filled. + * The next call to EAS_Render will continue processing until the buffer + * has been filled. + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) available for customer use */ +EAS_BOOL EAS_HWYield (EAS_HW_DATA_HANDLE hwInstData) +{ + /* put your code here */ + return EAS_FALSE; +} + + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/EASLib.h b/common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/EASLib.h new file mode 100755 index 0000000..adaaa70 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/EASLib.h @@ -0,0 +1,31 @@ +/* + * EASLib.h + * EASLIb + * + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "eas_types.h" + +extern EAS_RESULT EAS_LibInit (EAS_DATA_HANDLE *pHandle) +{ + return EAS_Init(pEASData); +} + +EAS_EXPORT EAS_LibShutdown (EAS_DATA_HANDLE handle) +{ + EAS_Shutdown(handle); +} diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/EASLibVst.c b/common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/EASLibVst.c new file mode 100755 index 0000000..5bfe774 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/EASLibVst.c @@ -0,0 +1,1504 @@ +/* + * EASLib.c + * EASLIb + * + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + */ + +#include +#include +#include +#include + +#include "eas.h" +#include "eas_report.h" +#include "eas_host.h" + +#ifdef JET_INTERFACE +#include "jet.h" +#endif + + +#define EAS_EXPORT __attribute__((visibility("default"))) + +// #define DEBUG_FILE_IO + +/* include debug interface */ +#include "eas_host_debug.h" + +#ifdef AUX_MIXER +#include "eas_auxmix.h" +#endif + +/* this module requires dynamic memory support */ +#ifdef _STATIC_MEMORY +#error "eas_hostmm.c requires the dynamic memory model!\n" +#endif + +#ifndef EAS_MAX_FILE_HANDLES +#define EAS_MAX_FILE_HANDLES 32 +#endif + +#ifndef EAS_FILE_BUFFER_SIZE +#define EAS_FILE_BUFFER_SIZE 32 +#endif + +/* + * this structure and the related function are here + * to support the ability to create duplicate handles + * and buffering it in memory. If your system uses + * in-memory resources, you can eliminate the calls + * to malloc and free, the dup flag, and simply track + * the file size and read position. + */ + #ifdef BUFFERED_FILE_ACCESS +typedef struct eas_hw_file_tag +{ + FILE *pFile; + EAS_I32 bytesInBuffer; + EAS_I32 readIndex; + EAS_I32 filePos; + EAS_I32 fileSize; + EAS_BOOL dup; + EAS_U8 buffer[EAS_FILE_BUFFER_SIZE]; +} EAS_HW_FILE; +#else +typedef struct eas_hw_file_tag +{ + EAS_I32 fileSize; + EAS_I32 filePos; + EAS_BOOL dup; + EAS_U8 *buffer; +} EAS_HW_FILE; +#endif + +typedef struct eas_hw_inst_data_tag +{ + EAS_HW_FILE files[EAS_MAX_FILE_HANDLES]; +} EAS_HW_INST_DATA; + +EAS_BOOL errorConditions[eNumErrorConditions]; +EAS_BOOL ledState; +EAS_BOOL vibState; +EAS_BOOL backlightState; + +#define MAX_DEBUG_MSG_LEN 1024 + +typedef void (*EAS_LOG_FUNC)(EAS_INT severity, char *msg); + +static EAS_LOG_FUNC logCallback = NULL; +static char messageBuffer[MAX_DEBUG_MSG_LEN]; + +/* error counts */ +static EAS_INT eas_fatalErrors; +static EAS_INT eas_errors; +static EAS_INT eas_warnings; +static int severityLevel = 9999; + +/* wave out device */ +#ifndef MAX_WAVE_OUT_BUFFERS +#define MAX_WAVE_OUT_BUFFERS 8 +#endif + +#ifndef EAS_BUFFERS_PER_WAVE_BUFFER +#define EAS_BUFFERS_PER_WAVE_BUFFER 8 +#endif + +/*---------------------------------------------------------------------------- + * ResetErrorCounters() + *---------------------------------------------------------------------------- +*/ +EAS_EXPORT void ResetErrorCounters() +{ + eas_fatalErrors = 0; + eas_errors = 0; + eas_warnings = 0; +} + +/*---------------------------------------------------------------------------- + * SetLogCallback() + *---------------------------------------------------------------------------- +*/ +EAS_EXPORT void SetLogCallback (EAS_LOG_FUNC callback) +{ + logCallback = callback; +} + +#ifndef _NO_DEBUG_PREPROCESSOR +static S_DEBUG_MESSAGES debugMessages[] = +{ +#ifdef UNIFIED_DEBUG_MESSAGES +#include "eas_debugmsgs.h" +#endif + { 0,0,0 } +}; + +/*---------------------------------------------------------------------------- + * EAS_ReportEx() + *---------------------------------------------------------------------------- +*/ +void EAS_ReportEx (int severity, unsigned long hashCode, int serialNum, ...) +{ + va_list vargs; + int i; + + switch (severity) + { + case _EAS_SEVERITY_FATAL: + eas_fatalErrors++; + break; + + case _EAS_SEVERITY_ERROR: + eas_errors++; + break; + + case _EAS_SEVERITY_WARNING: + eas_warnings++; + break; + + default: + break; + } + + /* check severity level */ + if (severity > severityLevel) + return; + + /* check for callback */ + if (logCallback == NULL) + return; + + /* find the error message and output to stdout */ + for (i = 0; debugMessages[i].m_pDebugMsg; i++) + { + if ((debugMessages[i].m_nHashCode == hashCode) && + (debugMessages[i].m_nSerialNum == serialNum)) + { + va_start(vargs, serialNum); +#ifdef WIN32 + vsprintf_s(messageBuffer, sizeof(messageBuffer), fmt, vargs); +#else + vsprintf(messageBuffer, debugMessages[i].m_pDebugMsg, vargs); +#endif + logCallback(severity, messageBuffer); + va_end(vargs); + return; + } + } + printf("Unrecognized error: Severity=%d; HashCode=%lu; SerialNum=%d\n", severity, hashCode, serialNum); +} /* end EAS_ReportEx */ + +#else +/*---------------------------------------------------------------------------- + * EAS_Report() + *---------------------------------------------------------------------------- +*/ +void EAS_Report (int severity, const char *fmt, ...) +{ + va_list vargs; + + switch (severity) + { + case _EAS_SEVERITY_FATAL: + eas_fatalErrors++; + break; + + case _EAS_SEVERITY_ERROR: + eas_errors++; + break; + + case _EAS_SEVERITY_WARNING: + eas_warnings++; + break; + + default: + break; + } + + /* check severity level */ + if (severity > severityLevel) + return; + + /* check for callback */ + if (logCallback == NULL) + return; + + va_start(vargs, fmt); +#ifdef _WIN32 + vsprintf_s(messageBuffer, sizeof(messageBuffer), fmt, vargs); +#else + vsprintf(messageBuffer, fmt, vargs); +#endif + logCallback(severity, messageBuffer); + va_end(vargs); +} /* end EAS_Report */ + +/*---------------------------------------------------------------------------- + * EAS_ReportX() + *---------------------------------------------------------------------------- +*/ +void EAS_ReportX (int severity, const char *fmt, ...) +{ + va_list vargs; + + switch (severity) + { + case _EAS_SEVERITY_FATAL: + eas_fatalErrors++; + break; + + case _EAS_SEVERITY_ERROR: + eas_errors++; + break; + + case _EAS_SEVERITY_WARNING: + eas_warnings++; + break; + + default: + break; + } + + /* check severity level */ + if (severity > severityLevel) + return; + + /* check for callback */ + if (logCallback == NULL) + return; + + va_start(vargs, fmt); +#ifdef _WIN32 + vsprintf_s(messageBuffer, sizeof(messageBuffer), fmt, vargs); +#else + vsprintf(messageBuffer, fmt, vargs); +#endif + logCallback(severity, messageBuffer); + va_end(vargs); +} +#endif + +/*---------------------------------------------------------------------------- + * EAS_DLLSetDebugLevel() + *---------------------------------------------------------------------------- +*/ +EAS_EXPORT void EAS_DLLSetDebugLevel (int severity) +{ + severityLevel = severity; +} + +/*---------------------------------------------------------------------------- + * EAS_ExSetDebugLevel() + *---------------------------------------------------------------------------- +*/ +void EAS_SetDebugLevel (int severity) +{ + severityLevel = severity; +} + +/*---------------------------------------------------------------------------- + * EAS_SelectLibrary() + *---------------------------------------------------------------------------- +*/ +EAS_EXPORT EAS_RESULT EAS_SelectLib (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_BOOL testLib) +{ + extern EAS_SNDLIB_HANDLE VMGetLibHandle(EAS_INT libNum); + return EAS_SetSoundLibrary(pEASData, streamHandle, VMGetLibHandle(testLib ? 1 : 0)); +} + + +#if defined(_DEBUG) && !defined(MSC) +#include +/*---------------------------------------------------------------------------- + * EnableHeapDebug() + *---------------------------------------------------------------------------- +*/ +static void EnableHeapDebug (void) +{ + int temp; + temp = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); + temp |= _CRTDBG_ALLOC_MEM_DF; + temp |= _CRTDBG_CHECK_ALWAYS_DF; + temp |= _CRTDBG_LEAK_CHECK_DF; +// temp |= _CRTDBG_DELAY_FREE_MEM_DF; + _CrtSetDbgFlag(temp); +} + +/*---------------------------------------------------------------------------- + * HeapCheck() + *---------------------------------------------------------------------------- + * Check heap status + *---------------------------------------------------------------------------- +*/ +void HeapCheck (void) +{ + int heapStatus; + + /* Check heap status */ + heapStatus = _heapchk(); + if ((heapStatus == _HEAPOK) || (heapStatus == _HEAPEMPTY)) + return; + + EAS_ReportX(_EAS_SEVERITY_FATAL, "Heap corrupt\n" ); +} +#endif + + +/*---------------------------------------------------------------------------- + * EAS_HWInit + * + * Initialize host wrapper interface + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_HWInit (EAS_HW_DATA_HANDLE *pHWInstData) +{ + +#if defined(_DEBUG) && !defined(MSC) + EnableHeapDebug(); +#endif + + #ifdef BUFFERED_FILE_ACCESS + EAS_ReportX(_EAS_SEVERITY_INFO, "EAS_HWInit: Buffered file access\n"); + #else + EAS_ReportX(_EAS_SEVERITY_INFO, "EAS_HWInit: Memory mapped file access\n"); + #endif + + /* simulate failure */ + if (errorConditions[eInitError]) + return EAS_FAILURE; + + /* need to track file opens for duplicate handles */ + *pHWInstData = malloc(sizeof(EAS_HW_INST_DATA)); + if (!(*pHWInstData)) + return EAS_ERROR_MALLOC_FAILED; + + EAS_HWMemSet(*pHWInstData, 0, sizeof(EAS_HW_INST_DATA)); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_HWShutdown + * + * Shut down host wrapper interface + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_HWShutdown (EAS_HW_DATA_HANDLE hwInstData) +{ + + /* simulate failure */ + if (errorConditions[eShutdownError]) + return EAS_FAILURE; + + free(hwInstData); + +#if defined(_DEBUG) && !defined(MSC) + HeapCheck(); +#endif + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWMalloc + * + * Allocates dynamic memory + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) available for customer use */ +void *EAS_HWMalloc (EAS_HW_DATA_HANDLE hwInstData, EAS_I32 size) +{ + /* simulate failure */ + if (errorConditions[eMallocError]) + return NULL; + + return malloc((size_t) size); +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWFree + * + * Frees dynamic memory + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) available for customer use */ +void EAS_HWFree (EAS_HW_DATA_HANDLE hwInstData, void *p) +{ + free(p); +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWMemCpy + * + * Copy memory wrapper + * + *---------------------------------------------------------------------------- +*/ +void *EAS_HWMemCpy (void *dest, const void *src, EAS_I32 amount) +{ + return memcpy(dest, src, (size_t) amount); +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWMemSet + * + * Set memory wrapper + * + *---------------------------------------------------------------------------- +*/ +void *EAS_HWMemSet (void *dest, int val, EAS_I32 amount) +{ + return memset(dest, val, (size_t) amount); +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWMemCmp + * + * Compare memory wrapper + * + *---------------------------------------------------------------------------- +*/ +EAS_I32 EAS_HWMemCmp (const void *s1, const void *s2, EAS_I32 amount) +{ + return (EAS_I32) memcmp(s1, s2, (size_t) amount); +} + +#ifdef BUFFERED_FILE_ACCESS +/*---------------------------------------------------------------------------- + * + * EAS_HWOpenFile + * + * Open a file for read or write + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_HWOpenFile (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_LOCATOR locator, EAS_FILE_HANDLE *pFile, EAS_FILE_MODE mode) +{ + EAS_HW_FILE *file; + int i; + + /* set return value to NULL */ + *pFile = NULL; + + /* only support read mode at this time */ + if (mode != EAS_FILE_READ) + return EAS_ERROR_INVALID_FILE_MODE; + + /* find an empty entry in the file table */ + file = hwInstData->files; + for (i = 0; i < EAS_MAX_FILE_HANDLES; i++) + { + /* is this slot being used? */ + if (file->pFile == NULL) + { + EAS_RESULT result; + + /* open the file */ + file->pFile = fopen((const char*) locator, "rb"); + if (file->pFile == NULL) + return EAS_ERROR_FILE_OPEN_FAILED; + + /* get file length */ + if ((result = EAS_HWFileLength(hwInstData, file, &file->fileSize)) != EAS_SUCCESS) + { + EAS_HWCloseFile(hwInstData, file); + return result; + } + +#ifdef DEBUG_FILE_IO + EAS_ReportX(_EAS_SEVERITY_NOFILTER, "EAS_HWOpenFile: Open file %d\n", i); +#endif + + /* initialize some values */ + file->bytesInBuffer = 0; + file->readIndex = 0; + file->filePos = 0; + file->dup = EAS_FALSE; + + *pFile = file; + return EAS_SUCCESS; + } + file++; + } + + /* too many open files */ + return EAS_ERROR_MAX_FILES_OPEN; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWFillBuffer + * + * Fill buffer from file + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWFillBuffer (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file) +{ + /* reposition the file pointer */ + if (fseek(file->pFile, file->filePos, SEEK_SET) != 0) + return EAS_ERROR_FILE_SEEK; + + /* read some data from the file */ + file->bytesInBuffer = (EAS_I32) fread(file->buffer, 1, EAS_FILE_BUFFER_SIZE, file->pFile); + file->readIndex = 0; + if (file->bytesInBuffer == 0) + return EAS_EOF; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWReadFile + * + * Read data from a file + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWReadFile (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *pBuffer, EAS_I32 n, EAS_I32 *pBytesRead) +{ + EAS_RESULT result; + EAS_I32 temp; + EAS_U8 *p = pBuffer; + EAS_I32 bytesLeft = n; + + *pBytesRead = 0; + + /* check handle integrity */ + if (file->pFile == NULL) + return EAS_ERROR_INVALID_HANDLE; + +#ifdef DEBUG_FILE_IO + EAS_ReportX(_EAS_SEVERITY_NOFILTER, "EAS_HWReadFile: Reading %d bytes from position %d\n", n, file->filePos); +#endif + + /* try to fulfill request from buffer */ + for (;bytesLeft > 0;) + { + /* how many bytes can we get from buffer? */ + temp = file->bytesInBuffer - file->readIndex; + if (temp > bytesLeft) + temp = bytesLeft; + + /* copy data from buffer */ + EAS_HWMemCpy(p, &file->buffer[file->readIndex], temp); + *pBytesRead += temp; + file->readIndex += temp; + file->filePos += temp; + p += temp; + bytesLeft -= temp; + + /* don't refill buffer if request is bigger than buffer */ + if ((bytesLeft == 0) || (bytesLeft >= EAS_FILE_BUFFER_SIZE)) + break; + + /* refill buffer */ + if ((result = EAS_HWFillBuffer(hwInstData, file)) != EAS_SUCCESS) + return result; + } + + /* more to read? do unbuffered read directly to target memory */ + if (bytesLeft) + { + + /* position the file pointer */ + if (fseek(file->pFile, file->filePos, SEEK_SET) != 0) + return EAS_ERROR_FILE_SEEK; + + /* read data in the buffer */ + temp = (EAS_I32) fread(p, 1, (size_t) bytesLeft, file->pFile); + *pBytesRead += temp; + file->filePos += temp; + + /* reset buffer info */ + file->bytesInBuffer = 0; + file->readIndex = 0; + } + +#ifdef DEBUG_FILE_IO + { +#define BYTES_PER_LINE 16 + char str[BYTES_PER_LINE * 3 + 1]; + EAS_INT i; + for (i = 0; i < (n > BYTES_PER_LINE ? BYTES_PER_LINE : n) ; i ++) + sprintf(&str[i*3], "%02x ", ((EAS_U8*)pBuffer)[i]); + if (i) + EAS_ReportX(_EAS_SEVERITY_NOFILTER, "%s\n", str); + } +#endif + + /* were n bytes read? */ + if (*pBytesRead != n) + return EAS_EOF; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWGetByte + * + * Read a byte from a file + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWGetByte (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *p) +{ + EAS_RESULT result; + + /* check handle integrity */ + if (file->pFile == NULL) + return EAS_ERROR_INVALID_HANDLE; + + /* use local buffer - do we have any data? */ + if (file->readIndex >= file->bytesInBuffer) + { + if ((result = EAS_HWFillBuffer(hwInstData, file)) != EAS_SUCCESS) + return result; + + /* if nothing to read, return EOF */ + if (file->bytesInBuffer == 0) + return EAS_EOF; + } + + /* get a character from the buffer */ + *((EAS_U8*) p) = file->buffer[file->readIndex++]; + +#ifdef DEBUG_FILE_IO + EAS_ReportX(_EAS_SEVERITY_NOFILTER, "EAS_HWGetByte: Reading from position %d, byte = 0x%02x\n", file->filePos, *(EAS_U8*)p); +#endif + + file->filePos++; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWGetWord + * + * Read a 16-bit value from the file + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_HWGetWord (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *p, EAS_BOOL msbFirst) +{ + EAS_RESULT result; + EAS_I32 count; + EAS_U8 c[2]; + +#ifdef DEBUG_FILE_IO + EAS_ReportX(_EAS_SEVERITY_NOFILTER, "EAS_HWGetWord: Reading 2 bytes from position %d\n", file->filePos); +#endif + + /* read 2 bytes from the file */ + if ((result = EAS_HWReadFile(hwInstData, file, c, 2, &count)) != EAS_SUCCESS) + return result; + + /* order them as requested */ + if (msbFirst) + *((EAS_U16*) p) = ((EAS_U16) c[0] << 8) | c[1]; + else + *((EAS_U16*) p) = ((EAS_U16) c[1] << 8) | c[0]; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWGetDWord + * + * Read a 16-bit value from the file + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_HWGetDWord (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *p, EAS_BOOL msbFirst) +{ + EAS_RESULT result; + EAS_I32 count; + EAS_U8 c[4]; + +#ifdef DEBUG_FILE_IO + EAS_ReportX(_EAS_SEVERITY_NOFILTER, "EAS_HWGetDWord: Reading 4 bytes from position %d\n", file->filePos); +#endif + + /* read 4 bytes from the file */ + if ((result = EAS_HWReadFile(hwInstData, file, c, 4, &count)) != EAS_SUCCESS) + return result; + + /* order them as requested */ + if (msbFirst) + *((EAS_U32*) p) = ((EAS_U32) c[0] << 24) | ((EAS_U32) c[1] << 16) | ((EAS_U32) c[2] << 8) | c[3]; + else + *((EAS_U32*) p) = ((EAS_U32) c[3] << 24) | ((EAS_U32) c[2] << 16) | ((EAS_U32) c[1] << 8) | c[0]; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWFilePos + * + * Returns the current location in the file + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWFilePos (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 *pPosition) +{ + + /* check handle integrity */ + if (file->pFile == NULL) + return EAS_ERROR_INVALID_HANDLE; + + *pPosition = file->filePos; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWFileSeek + * + * Seek to a specific location in the file + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWFileSeek (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 position) +{ + EAS_I32 newIndex; + + /* check handle integrity */ + if (file->pFile == NULL) + return EAS_ERROR_INVALID_HANDLE; + + /* check for seek past end */ + if ((position < 0) || (position > file->fileSize)) + return EAS_ERROR_FILE_SEEK; + +#ifdef DEBUG_FILE_IO + EAS_ReportX(_EAS_SEVERITY_NOFILTER, "EAS_HWFileSeek: Seeking to new position %d\n", file->filePos); +#endif + + /* is new position in current buffer? */ + newIndex = position - file->filePos + file->readIndex; + if ((newIndex >= 0) && (newIndex < file->bytesInBuffer)) + { + file->readIndex = newIndex; + file->filePos = position; + return EAS_SUCCESS; + } + + /* save new position and reset buffer info so EAS_HWGetByte doesn't fail */ + file->filePos = position; + file->bytesInBuffer = 0; + file->readIndex = 0; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWFileSeekOfs + * + * Seek forward or back relative to the current position + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWFileSeekOfs (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 position) +{ + EAS_I32 temp; + +#ifdef DEBUG_FILE_IO + EAS_ReportX(_EAS_SEVERITY_NOFILTER, "EAS_HWFileSeekOfs: Seeking to new position %d\n", file->filePos + position); +#endif + + /* check handle integrity */ + if (file->pFile == NULL) + return EAS_ERROR_INVALID_HANDLE; + + /* check for seek past end */ + temp = file->filePos + position; + if ((temp < 0) || (temp > file->fileSize)) + return EAS_ERROR_FILE_SEEK; + + /* is new position in current buffer? */ + temp = position + file->readIndex; + if ((temp >= 0) && (temp < file->bytesInBuffer)) + { + file->readIndex = temp; + file->filePos += position; + return EAS_SUCCESS; + } + + /* save new position and reset buffer info so EAS_HWGetByte doesn't fail */ + file->filePos += position; + file->bytesInBuffer = 0; + file->readIndex = 0; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWFileLength + * + * Return the file length + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWFileLength (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 *pLength) +{ + long pos; + + /* check handle integrity */ + if (file->pFile == NULL) + return EAS_ERROR_INVALID_HANDLE; + + if ((pos = ftell(file->pFile)) == -1L) + return EAS_ERROR_FILE_LENGTH; + if (fseek(file->pFile, 0L, SEEK_END) != 0) + return EAS_ERROR_FILE_LENGTH; + if ((*pLength = ftell(file->pFile)) == -1L) + return EAS_ERROR_FILE_LENGTH; + if (fseek(file->pFile, pos, SEEK_SET) != 0) + return EAS_ERROR_FILE_LENGTH; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWDupHandle + * + * Duplicate a file handle + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_HWDupHandle (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_FILE_HANDLE* pDupFile) +{ + EAS_HW_FILE *dupfile; + int i; + + /* check handle integrity */ + *pDupFile = NULL; + if (file->pFile == NULL) + return EAS_ERROR_INVALID_HANDLE; + + /* find an empty entry in the file table */ + dupfile = hwInstData->files; + for (i = 0; i < EAS_MAX_FILE_HANDLES; i++) + { + /* is this slot being used? */ + if (dupfile->pFile == NULL) + { + + /* copy info from the handle to be duplicated */ + dupfile->filePos = file->filePos; + dupfile->pFile = file->pFile; + dupfile->fileSize = file->fileSize; + + /* set the duplicate handle flag */ + dupfile->dup = file->dup = EAS_TRUE; + + /* initialize some values */ + dupfile->bytesInBuffer = 0; + dupfile->readIndex = 0; + + *pDupFile = dupfile; + return EAS_SUCCESS; + } + dupfile++; + } + + /* too many open files */ + return EAS_ERROR_MAX_FILES_OPEN; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWClose + * + * Wrapper for fclose function + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_HWCloseFile (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file1) +{ + EAS_HW_FILE *file2,*dupFile; + int i; + + /* check handle integrity */ + if (file1->pFile == NULL) + return EAS_ERROR_INVALID_HANDLE; + + /* check for duplicate handle */ + if (file1->dup) + { + dupFile = NULL; + file2 = hwInstData->files; + for (i = 0; i < EAS_MAX_FILE_HANDLES; i++) + { + /* check for duplicate */ + if ((file1 != file2) && (file2->pFile == file1->pFile)) + { + /* is there more than one duplicate? */ + if (dupFile != NULL) + { + /* clear this entry and return */ + file1->pFile = NULL; + return EAS_SUCCESS; + } + + /* this is the first duplicate found */ + dupFile = file2; + } + file2++; + } + + /* there is only one duplicate, clear the dup flag */ + if (dupFile) + dupFile->dup = EAS_FALSE; + else + /* if we get here, there's a serious problem */ + return EAS_ERROR_HANDLE_INTEGRITY; + + /* clear this entry and return */ + file1->pFile = NULL; + return EAS_SUCCESS; + } + + /* no duplicates - close the file */ + if (fclose(file1->pFile) != 0) + return EAS_ERROR_CLOSE_FAILED; + + /* clear this entry and return */ + file1->pFile = NULL; + return EAS_SUCCESS; +} +#else +/*---------------------------------------------------------------------------- + * + * EAS_HWOpenFile + * + * Open a file for read or write + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_HWOpenFile (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_LOCATOR locator, EAS_FILE_HANDLE *pFile, EAS_FILE_MODE mode) +{ + EAS_HW_FILE *file; + FILE *ioFile; + int i, temp; + + /* set return value to NULL */ + *pFile = NULL; + + /* simulate failure */ + if (errorConditions[eOpenError]) + return EAS_FAILURE; + + /* only support read mode at this time */ + if (mode != EAS_FILE_READ) + return EAS_ERROR_INVALID_FILE_MODE; + + /* find an empty entry in the file table */ + file = hwInstData->files; + for (i = 0; i < EAS_MAX_FILE_HANDLES; i++) + { + /* is this slot being used? */ + if (file->buffer == NULL) + { + /* open the file */ + if ((ioFile = fopen(locator,"rb")) == NULL) + return EAS_ERROR_FILE_OPEN_FAILED; + + /* determine the file size */ + if (fseek(ioFile, 0L, SEEK_END) != 0) + return EAS_ERROR_FILE_LENGTH; + if ((file->fileSize = ftell(ioFile)) == -1L) + return EAS_ERROR_FILE_LENGTH; + if (fseek(ioFile, 0L, SEEK_SET) != 0) + return EAS_ERROR_FILE_LENGTH; + + /* allocate a buffer */ + file->buffer = EAS_HWMalloc(hwInstData, file->fileSize); + if (file->buffer == NULL) + { + fclose(ioFile); + return EAS_ERROR_MALLOC_FAILED; + } + + /* read the file into memory */ + temp = (int) fread(file->buffer, (size_t) file->fileSize, 1, ioFile); + + /* close the file - don't need it any more */ + fclose(ioFile); + + /* check for error reading file */ + if (temp != 1) + return EAS_ERROR_FILE_READ_FAILED; + + /* initialize some values */ + file->filePos = 0; + file->dup = EAS_FALSE; + + *pFile = file; + return EAS_SUCCESS; + } + file++; + } + + /* too many open files */ + return EAS_ERROR_MAX_FILES_OPEN; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWReadFile + * + * Read data from a file + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) available for customer use */ +EAS_RESULT EAS_HWReadFile (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *pBuffer, EAS_I32 n, EAS_I32 *pBytesRead) +{ + EAS_I32 count; + + /* simulate failure */ + if (errorConditions[eReadError]) + return EAS_FAILURE; + + /* make sure we have a valid handle */ + if (file->buffer == NULL) + return EAS_ERROR_INVALID_HANDLE; + + /* calculate the bytes to read */ + count = file->fileSize - file->filePos; + if (n < count) + count = n; + + /* copy the data to the requested location, and advance the pointer */ + if (count) + EAS_HWMemCpy(pBuffer, &file->buffer[file->filePos], count); + file->filePos += count; + *pBytesRead = count; + + /* were n bytes read? */ + if (count!= n) + return EAS_EOF; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWGetByte + * + * Read a byte from a file + * + *---------------------------------------------------------------------------- +*/ +/*lint -e{715} hwInstData available for customer use */ +EAS_RESULT EAS_HWGetByte (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *p) +{ + + /* simulate failure */ + if (errorConditions[eReadError]) + return EAS_FAILURE; + + /* make sure we have a valid handle */ + if (file->buffer == NULL) + return EAS_ERROR_INVALID_HANDLE; + + /* check for end of file */ + if (file->filePos >= file->fileSize) + { + *((EAS_U8*) p) = 0; + return EAS_EOF; + } + + /* get a character from the buffer */ + *((EAS_U8*) p) = file->buffer[file->filePos++]; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWGetWord + * + * Returns the current location in the file + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) available for customer use */ +EAS_RESULT EAS_HWGetWord (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *p, EAS_BOOL msbFirst) +{ + EAS_RESULT result; + EAS_U8 c1, c2; + + /* read 2 bytes from the file */ + if ((result = EAS_HWGetByte(hwInstData, file, &c1)) != EAS_SUCCESS) + return result; + if ((result = EAS_HWGetByte(hwInstData, file, &c2)) != EAS_SUCCESS) + return result; + + /* order them as requested */ + if (msbFirst) + *((EAS_U16*) p) = ((EAS_U16) c1 << 8) | c2; + else + *((EAS_U16*) p) = ((EAS_U16) c2 << 8) | c1; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWGetDWord + * + * Returns the current location in the file + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) available for customer use */ +EAS_RESULT EAS_HWGetDWord (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *p, EAS_BOOL msbFirst) +{ + EAS_RESULT result; + EAS_U8 c1, c2,c3,c4; + + /* read 4 bytes from the file */ + if ((result = EAS_HWGetByte(hwInstData, file, &c1)) != EAS_SUCCESS) + return result; + if ((result = EAS_HWGetByte(hwInstData, file, &c2)) != EAS_SUCCESS) + return result; + if ((result = EAS_HWGetByte(hwInstData, file, &c3)) != EAS_SUCCESS) + return result; + if ((result = EAS_HWGetByte(hwInstData, file, &c4)) != EAS_SUCCESS) + return result; + + /* order them as requested */ + if (msbFirst) + *((EAS_U32*) p) = ((EAS_U32) c1 << 24) | ((EAS_U32) c2 << 16) | ((EAS_U32) c3 << 8) | c4; + else + *((EAS_U32*) p)= ((EAS_U32) c4 << 24) | ((EAS_U32) c3 << 16) | ((EAS_U32) c2 << 8) | c1; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWFilePos + * + * Returns the current location in the file + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) available for customer use */ +EAS_RESULT EAS_HWFilePos (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 *pPosition) +{ + + /* simulate failure */ + if (errorConditions[ePosError]) + return EAS_FAILURE; + + /* make sure we have a valid handle */ + if (file->buffer == NULL) + return EAS_ERROR_INVALID_HANDLE; + + *pPosition = file->filePos; + return EAS_SUCCESS; +} /* end EAS_HWFilePos */ + +/*---------------------------------------------------------------------------- + * + * EAS_HWFileSeek + * + * Seek to a specific location in the file + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) available for customer use */ +EAS_RESULT EAS_HWFileSeek (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 position) +{ + + /* simulate failure */ + if (errorConditions[eSeekError]) + return EAS_FAILURE; + + /* make sure we have a valid handle */ + if (file->buffer == NULL) + return EAS_ERROR_INVALID_HANDLE; + + /* validate new position */ + if ((position < 0) || (position > file->fileSize)) + return EAS_ERROR_FILE_SEEK; + + /* save new position */ + file->filePos = position; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWFileSeekOfs + * + * Seek forward or back relative to the current position + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) available for customer use */ +EAS_RESULT EAS_HWFileSeekOfs (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 position) +{ + + /* simulate failure */ + if (errorConditions[eSeekError]) + return EAS_FAILURE; + + /* make sure we have a valid handle */ + if (file->buffer == NULL) + return EAS_ERROR_INVALID_HANDLE; + + /* determine the file position */ + position += file->filePos; + if ((position < 0) || (position > file->fileSize)) + return EAS_ERROR_FILE_SEEK; + + /* save new position */ + file->filePos = position; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWFileLength + * + * Return the file length + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) available for customer use */ +EAS_RESULT EAS_HWFileLength (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 *pLength) +{ + + /* simulate failure */ + if (errorConditions[eLengthError]) + return EAS_FAILURE; + + /* make sure we have a valid handle */ + if (file->buffer == NULL) + return EAS_ERROR_INVALID_HANDLE; + + *pLength = file->fileSize; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWDupHandle + * + * Duplicate a file handle + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_HWDupHandle (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_FILE_HANDLE *pDupFile) +{ + EAS_HW_FILE *dupFile; + int i; + + /* simulate failure */ + if (errorConditions[eDupError]) + return EAS_FAILURE; + + /* make sure we have a valid handle */ + if (file->buffer == NULL) + return EAS_ERROR_INVALID_HANDLE; + + /* find an empty entry in the file table */ + dupFile = hwInstData->files; + for (i = 0; i < EAS_MAX_FILE_HANDLES; i++) + { + /* is this slot being used? */ + if (dupFile->buffer == NULL) + { + + /* copy info from the handle to be duplicated */ + dupFile->filePos = file->filePos; + dupFile->fileSize = file->fileSize; + dupFile->buffer = file->buffer; + + /* set the duplicate handle flag */ + dupFile->dup = file->dup = EAS_TRUE; + + *pDupFile = dupFile; + return EAS_SUCCESS; + } + dupFile++; + } + + /* too many open files */ + return EAS_ERROR_MAX_FILES_OPEN; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWClose + * + * Wrapper for fclose function + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_HWCloseFile (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file1) +{ + EAS_HW_FILE *file2,*dupFile; + int i; + + /* simulate failure */ + if (errorConditions[eCloseError]) + return EAS_FAILURE; + + /* make sure we have a valid handle */ + if (file1->buffer == NULL) + return EAS_ERROR_INVALID_HANDLE; + + /* check for duplicate handle */ + if (file1->dup) + { + dupFile = NULL; + file2 = hwInstData->files; + for (i = 0; i < EAS_MAX_FILE_HANDLES; i++) + { + /* check for duplicate */ + if ((file1 != file2) && (file2->buffer == file1->buffer)) + { + /* is there more than one duplicate? */ + if (dupFile != NULL) + { + /* clear this entry and return */ + file1->buffer = NULL; + return EAS_SUCCESS; + } + + /* this is the first duplicate found */ + else + dupFile = file2; + } + file2++; + } + + /* there is only one duplicate, clear the dup flag */ + if (dupFile) + dupFile->dup = EAS_FALSE; + else + /* if we get here, there's a serious problem */ + return EAS_ERROR_HANDLE_INTEGRITY; + + /* clear this entry and return */ + file1->buffer = NULL; + return EAS_SUCCESS; + } + + /* no duplicates -free the buffer */ + EAS_HWFree(hwInstData, file1->buffer); + + /* clear this entry and return */ + file1->buffer = NULL; + return EAS_SUCCESS; +} +#endif + +/*---------------------------------------------------------------------------- + * + * EAS_HWVibrate + * + * Turn on/off vibrate function + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) available for customer use */ +EAS_RESULT EAS_HWVibrate (EAS_HW_DATA_HANDLE hwInstData, EAS_BOOL state) +{ + vibState = state; +// EAS_ReportX(_EAS_SEVERITY_NOFILTER, "Vibrate state: %d\n", state); + return EAS_SUCCESS; +} /* end EAS_HWVibrate */ + +/*---------------------------------------------------------------------------- + * + * EAS_HWLED + * + * Turn on/off LED + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) available for customer use */ +EAS_RESULT EAS_HWLED (EAS_HW_DATA_HANDLE hwInstData, EAS_BOOL state) +{ + ledState = state; +// EAS_ReportX(_EAS_SEVERITY_NOFILTER, "LED state: %d\n", state); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWBackLight + * + * Turn on/off backlight + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) available for customer use */ +EAS_RESULT EAS_HWBackLight (EAS_HW_DATA_HANDLE hwInstData, EAS_BOOL state) +{ + backlightState = state; +// EAS_ReportX(_EAS_SEVERITY_NOFILTER, "Backlight state: %d\n", state); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWYield + * + * This function is called periodically by the EAS library to give the + * host an opportunity to allow other tasks to run. There are two ways to + * use this call: + * + * If you have a multi-tasking OS, you can call the yield function in the + * OS to allow other tasks to run. In this case, return EAS_FALSE to tell + * the EAS library to continue processing when control returns from this + * function. + * + * If tasks run in a single thread by sequential function calls (sometimes + * call a "commutator loop"), return EAS_TRUE to cause the EAS Library to + * return to the caller. Be sure to check the number of bytes rendered + * before passing the audio buffer to the codec - it may not be filled. + * The next call to EAS_Render will continue processing until the buffer + * has been filled. + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) available for customer use */ +EAS_BOOL EAS_HWYield (EAS_HW_DATA_HANDLE hwInstData) +{ + /* put your code here */ + return EAS_FALSE; +} + + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/README.txt b/common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/README.txt new file mode 100755 index 0000000..bcc6ef0 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/README.txt @@ -0,0 +1,9 @@ +OS X JetCreator Library Build Instructions + +1/ Open easwt_vst_lib.xcodeproj and build + +2/ Open EASLIb.xcodeproj and build + +3/ Copy build/Release/libEASLIb.dylib to the JetCreator folder + + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/eas_host_debug.h b/common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/eas_host_debug.h new file mode 100755 index 0000000..fb40923 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/eas_host_debug.h @@ -0,0 +1,47 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_host_debug.h + * + * Contents and purpose: + * This header defines the host wrapper functions for simulating + * error conditions. + * + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +// sentinel +#ifndef _EAS_HOST_DEBUG_H +#define _EAS_HOST_DEBUG_H + +#include "eas_types.h" + +typedef enum +{ + eInitError, + eShutdownError, + eMallocError, + eOpenError, + eReadError, + ePosError, + eSeekError, + eLengthError, + eDupError, + eCloseError, + eNumErrorConditions, +} E_ERROR_CONDITIONS; + +#endif + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/eastestv37.c b/common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/eastestv37.c new file mode 100755 index 0000000..f325c04 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/eastestv37.c @@ -0,0 +1,999 @@ +/*---------------------------------------------------------------------------- + * + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +#include "eas_sndlib.h" + +/*---------------------------------------------------------------------------- + * Articulations + *---------------------------------------------------------------------------- +*/ +const S_ARTICULATION testArticulations[] = +{ + { /* articulation 0 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 1 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 100, 0, 19, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 2 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 100, 34, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 3 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 100, 86, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 4 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 100, 172, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 5 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 100, 345, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 6 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 100, 517, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 7 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 100, 689, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 8 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 100, 861, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 9 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 100, 1723, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 10 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 100, 0, 191, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 11 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 100, 0, 382, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 12 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 100, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 13 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 100, 0, 1903, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 14 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 100, 0, 3804, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 15 */ + { 1902, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 16 */ + { 380, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 17 */ + { 190, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 18 */ + { 38, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 19 */ + { 19, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 20 */ + { 10, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 21 */ + { 5, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 22 */ + { 32767, 17213, 0, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 23 */ + { 32767, 28809, 0, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 24 */ + { 32767, 30725, 0, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 25 */ + { 32767, 32349, 0, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 26 */ + { 32767, 32558, 0, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 27 */ + { 32767, 32663, 0, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 28 */ + { 32767, 32715, 0, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 29 */ + { 32767, 30725, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 30 */ + { 32767, 30725, 3566, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 31 */ + { 32767, 30725, 42, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 32 */ + { 32767, 30725, 5, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 33 */ + { 32767, 30725, 2, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 34 */ + { 32767, 0, 32767, 17213 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 35 */ + { 32767, 0, 32767, 28809 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 36 */ + { 32767, 0, 32767, 30725 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 37 */ + { 32767, 0, 32767, 32349 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 38 */ + { 32767, 0, 32767, 32558 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 39 */ + { 32767, 0, 32767, 32663 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 40 */ + { 32767, 0, 32767, 32715 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 41 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 190, 0, 0, 0, 1, 0, 0 + }, + { /* articulation 42 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 189, 0, 0, 0, 3, 0, 0 + }, + { /* articulation 43 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 190, 0, 0, 0, 4, 0, 0 + }, + { /* articulation 44 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 190, 0, 0, 0, 6, 0, 0 + }, + { /* articulation 45 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + -1200, 0, 190, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 46 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + -600, 0, 190, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 47 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + -100, 0, 190, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 48 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + -50, 0, 190, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 49 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 50, 0, 190, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 50 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 100, 0, 190, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 51 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 600, 0, 190, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 52 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 1200, 0, 190, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 53 */ + { 32767, 0, 32767, 0 }, + { 190, 190, 0, 0 }, + 0, 0, 951, -1200, 0, 0, 0, 0, 0 + }, + { /* articulation 54 */ + { 32767, 0, 32767, 0 }, + { 190, 190, 0, 0 }, + 0, 0, 951, -600, 0, 0, 0, 0, 0 + }, + { /* articulation 55 */ + { 32767, 0, 32767, 0 }, + { 190, 190, 0, 0 }, + 0, 0, 951, -100, 0, 0, 0, 0, 0 + }, + { /* articulation 56 */ + { 32767, 0, 32767, 0 }, + { 190, 190, 0, 0 }, + 0, 0, 951, -50, 0, 0, 0, 0, 0 + }, + { /* articulation 57 */ + { 32767, 0, 32767, 0 }, + { 190, 190, 0, 0 }, + 0, 0, 951, 50, 0, 0, 0, 0, 0 + }, + { /* articulation 58 */ + { 32767, 0, 32767, 0 }, + { 190, 190, 0, 0 }, + 0, 0, 951, 100, 0, 0, 0, 0, 0 + }, + { /* articulation 59 */ + { 32767, 0, 32767, 0 }, + { 190, 190, 0, 0 }, + 0, 0, 951, 600, 0, 0, 0, 0, 0 + }, + { /* articulation 60 */ + { 32767, 0, 32767, 0 }, + { 190, 190, 0, 0 }, + 0, 0, 951, 1200, 0, 0, 0, 0, 0 + }, + { /* articulation 61 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 5535, 0, 0, 0 + }, + { /* articulation 62 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 7121, 0, 0, 0 + }, + { /* articulation 63 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 8321, 0, 0, 0 + }, + { /* articulation 64 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 9906, 0, 0, 0 + }, + { /* articulation 65 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 11106, 0, 0, 0 + }, + { /* articulation 66 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 9521, 0, 0, 0 + }, + { /* articulation 67 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 9521, 0, 8, 0 + }, + { /* articulation 68 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 9521, 0, 16, 0 + }, + { /* articulation 69 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 9521, 0, 24, 0 + }, + { /* articulation 70 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 9521, 0, 30, 0 + }, + { /* articulation 71 */ + { 32767, 0, 32767, 0 }, + { 190, 190, 0, 0 }, + 0, 0, 951, 0, -6400, 9521, 0, 0, 0 + }, + { /* articulation 72 */ + { 32767, 0, 32767, 0 }, + { 190, 190, 0, 0 }, + 0, 0, 951, 0, -3200, 9521, 0, 0, 0 + }, + { /* articulation 73 */ + { 32767, 0, 32767, 0 }, + { 190, 190, 0, 0 }, + 0, 0, 951, 0, -1600, 9521, 0, 0, 0 + }, + { /* articulation 74 */ + { 32767, 0, 32767, 0 }, + { 190, 190, 0, 0 }, + 0, 0, 951, 0, -800, 9521, 0, 0, 0 + }, + { /* articulation 75 */ + { 32767, 0, 32767, 0 }, + { 190, 190, 0, 0 }, + 0, 0, 951, 0, 800, 7121, 0, 0, 0 + }, + { /* articulation 76 */ + { 190, 30725, 32767, 0 }, + { 190, 190, 0, 0 }, + 0, 0, 951, 0, 1600, 7121, 0, 0, 0 + }, + { /* articulation 77 */ + { 32767, 0, 32767, 0 }, + { 190, 190, 0, 0 }, + 0, 0, 951, 0, 3200, 7121, 0, 0, 0 + }, + { /* articulation 78 */ + { 32767, 0, 32767, 0 }, + { 190, 190, 0, 0 }, + 0, 0, 951, 0, 6400, 7121, 0, 0, 0 + }, + { /* articulation 79 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 190, 0, 0, 11106, 0, 0, 0 + }, + { /* articulation 80 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 191, 0, 0, 11106, 0, 0, 0 + }, + { /* articulation 81 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 190, 0, 0, 7121, 0, 0, 0 + }, + { /* articulation 82 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -63 + }, + { /* articulation 83 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -50 + }, + { /* articulation 84 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -37 + }, + { /* articulation 85 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -25 + }, + { /* articulation 86 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -12 + }, + { /* articulation 87 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 12 + }, + { /* articulation 88 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 25 + }, + { /* articulation 89 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 37 + }, + { /* articulation 90 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 50 + }, + { /* articulation 91 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 63 + }, + { /* articulation 92 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 9907, 0, 0, 0 + }, + { /* articulation 93 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 10574, 0, 0, 0 + }, + { /* articulation 94 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 11373, 0, 0, 0 + }, + { /* articulation 95 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 11376, 0, 0, 0 + }, + { /* articulation 96 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 100, 0, 949, 0, 0, 0, 0, 0, 0 + } +}; /*end Articulations */ + +/*---------------------------------------------------------------------------- + * Regions + *---------------------------------------------------------------------------- +*/ +const S_WT_REGION testRegions[] = +{ + { { 32769, 0, 127 }, -6000, 32767, 101, 301, 4, 0 }, /* region 0 */ + { { 1, 0, 60 }, -6000, 32767, 101, 301, 4, 2 }, /* region 1 */ + { { 1, 61, 61 }, -6000, 32767, 101, 301, 4, 3 }, /* region 2 */ + { { 1, 62, 62 }, -6000, 32767, 101, 301, 4, 4 }, /* region 3 */ + { { 1, 63, 63 }, -6000, 32767, 101, 301, 4, 5 }, /* region 4 */ + { { 1, 64, 64 }, -6000, 32767, 101, 301, 4, 6 }, /* region 5 */ + { { 1, 65, 65 }, -6000, 32767, 101, 301, 4, 7 }, /* region 6 */ + { { 1, 66, 66 }, -6000, 32767, 101, 301, 4, 8 }, /* region 7 */ + { { 32769, 67, 127 }, -6000, 32767, 101, 301, 4, 9 }, /* region 8 */ + { { 32769, 0, 127 }, -6005, 32767, 3, 171, 5, 0 }, /* region 9 */ + { { 32768, 0, 127 }, -6555, 32767, 0, 0, 2, 0 }, /* region 10 */ + { { 32770, 0, 127 }, -6000, 32767, 0, 0, 0, 0 }, /* region 11 */ + { { 1, 60, 60 }, -6000, 32767, 101, 301, 4, 0 }, /* region 12 */ + { { 1, 61, 61 }, -6100, 16422, 101, 151, 4, 0 }, /* region 13 */ + { { 1, 62, 62 }, -6200, 8231, 101, 151, 4, 0 }, /* region 14 */ + { { 1, 63, 63 }, -6300, 2067, 101, 151, 4, 0 }, /* region 15 */ + { { 1, 64, 64 }, -6400, 130, 101, 151, 4, 0 }, /* region 16 */ + { { 32769, 65, 65 }, -6500, 1, 101, 151, 4, 0 }, /* region 17 */ + { { 1, 60, 60 }, -6000, 32767, 101, 301, 4, 0 }, /* region 18 */ + { { 1, 61, 61 }, -6200, 32767, 101, 151, 4, 0 }, /* region 19 */ + { { 1, 62, 62 }, -6400, 32767, 101, 151, 4, 0 }, /* region 20 */ + { { 1, 63, 63 }, -6600, 32767, 101, 151, 4, 0 }, /* region 21 */ + { { 1, 64, 64 }, -6800, 32767, 101, 151, 4, 0 }, /* region 22 */ + { { 1, 65, 65 }, -7000, 32767, 101, 151, 4, 0 }, /* region 23 */ + { { 1, 66, 66 }, -7200, 32767, 101, 151, 4, 0 }, /* region 24 */ + { { 1, 67, 67 }, -7400, 32767, 101, 151, 4, 0 }, /* region 25 */ + { { 1, 68, 68 }, -7600, 32767, 101, 151, 4, 0 }, /* region 26 */ + { { 1, 69, 69 }, -7800, 32767, 101, 151, 4, 0 }, /* region 27 */ + { { 1, 70, 70 }, -8000, 32767, 101, 151, 4, 0 }, /* region 28 */ + { { 1, 71, 71 }, -8200, 32767, 101, 151, 4, 0 }, /* region 29 */ + { { 32769, 72, 72 }, -8400, 32767, 101, 151, 4, 0 }, /* region 30 */ + { { 1, 60, 60 }, -6000, 32767, 101, 301, 4, 0 }, /* region 31 */ + { { 1, 61, 61 }, -6099, 32767, 101, 151, 4, 0 }, /* region 32 */ + { { 1, 62, 62 }, -6190, 32767, 101, 151, 4, 0 }, /* region 33 */ + { { 1, 63, 63 }, -6250, 32767, 101, 151, 4, 0 }, /* region 34 */ + { { 1, 64, 64 }, -6300, 32767, 101, 151, 4, 0 }, /* region 35 */ + { { 1, 65, 65 }, -6500, 32767, 101, 151, 4, 0 }, /* region 36 */ + { { 1, 66, 66 }, -6601, 32767, 101, 151, 4, 0 }, /* region 37 */ + { { 1, 67, 67 }, -6710, 32767, 101, 151, 4, 0 }, /* region 38 */ + { { 1, 68, 68 }, -6850, 32767, 101, 151, 4, 0 }, /* region 39 */ + { { 32769, 69, 69 }, -7000, 32767, 101, 151, 4, 0 }, /* region 40 */ + { { 1, 0, 0 }, 0, 32767, 101, 151, 4, 1 }, /* region 41 */ + { { 1, 1, 1 }, -100, 32767, 101, 151, 4, 10 }, /* region 42 */ + { { 1, 2, 2 }, -200, 32767, 101, 151, 4, 11 }, /* region 43 */ + { { 1, 3, 3 }, -300, 32767, 101, 151, 4, 12 }, /* region 44 */ + { { 1, 4, 4 }, -400, 32767, 101, 151, 4, 13 }, /* region 45 */ + { { 1, 5, 5 }, -500, 32767, 101, 151, 4, 14 }, /* region 46 */ + { { 1, 6, 6 }, -600, 32767, 101, 151, 4, 0 }, /* region 47 */ + { { 1, 7, 7 }, -700, 32767, 101, 151, 4, 15 }, /* region 48 */ + { { 1, 8, 8 }, -800, 32767, 101, 151, 4, 16 }, /* region 49 */ + { { 1, 9, 9 }, -900, 32767, 101, 151, 4, 17 }, /* region 50 */ + { { 1, 10, 10 }, -1000, 32767, 101, 151, 4, 18 }, /* region 51 */ + { { 1, 11, 11 }, -1100, 32767, 101, 151, 4, 19 }, /* region 52 */ + { { 1, 12, 12 }, -1200, 32767, 101, 151, 4, 20 }, /* region 53 */ + { { 1, 13, 13 }, -1300, 32767, 101, 151, 4, 21 }, /* region 54 */ + { { 1, 14, 14 }, -1400, 32767, 101, 151, 4, 22 }, /* region 55 */ + { { 1, 15, 15 }, -1500, 32767, 101, 151, 4, 23 }, /* region 56 */ + { { 1, 16, 16 }, -1600, 32767, 101, 151, 4, 24 }, /* region 57 */ + { { 1, 17, 17 }, -1700, 32767, 101, 151, 4, 25 }, /* region 58 */ + { { 1, 18, 18 }, -1800, 32767, 101, 151, 4, 26 }, /* region 59 */ + { { 1, 19, 19 }, -1900, 32767, 101, 151, 4, 27 }, /* region 60 */ + { { 1, 20, 20 }, -2000, 32767, 101, 151, 4, 28 }, /* region 61 */ + { { 1, 21, 21 }, -2100, 32767, 101, 151, 4, 29 }, /* region 62 */ + { { 1, 22, 22 }, -2200, 32767, 101, 151, 4, 30 }, /* region 63 */ + { { 1, 23, 23 }, -2300, 32767, 101, 151, 4, 31 }, /* region 64 */ + { { 1, 24, 24 }, -2400, 32767, 101, 151, 4, 32 }, /* region 65 */ + { { 1, 25, 25 }, -2500, 32767, 101, 151, 4, 33 }, /* region 66 */ + { { 1, 26, 26 }, -2600, 32767, 101, 151, 4, 24 }, /* region 67 */ + { { 1, 27, 27 }, -2700, 32767, 101, 151, 4, 0 }, /* region 68 */ + { { 1, 28, 28 }, -2800, 32767, 101, 151, 4, 34 }, /* region 69 */ + { { 1, 29, 29 }, -2900, 32767, 101, 151, 4, 35 }, /* region 70 */ + { { 1, 30, 30 }, -3000, 32767, 101, 151, 4, 36 }, /* region 71 */ + { { 1, 31, 31 }, -3100, 32767, 101, 151, 4, 37 }, /* region 72 */ + { { 1, 32, 32 }, -3200, 32767, 101, 151, 4, 38 }, /* region 73 */ + { { 1, 33, 33 }, -3300, 32767, 101, 151, 4, 39 }, /* region 74 */ + { { 1, 34, 34 }, -3400, 32767, 101, 151, 4, 40 }, /* region 75 */ + { { 1, 35, 35 }, -3500, 32767, 101, 151, 4, 41 }, /* region 76 */ + { { 1, 36, 36 }, -3600, 32767, 101, 151, 4, 42 }, /* region 77 */ + { { 1, 37, 37 }, -3700, 32767, 101, 151, 4, 43 }, /* region 78 */ + { { 1, 38, 38 }, -3800, 32767, 101, 151, 4, 44 }, /* region 79 */ + { { 1, 39, 39 }, -3900, 32767, 101, 151, 4, 45 }, /* region 80 */ + { { 1, 40, 40 }, -4000, 32767, 101, 151, 4, 46 }, /* region 81 */ + { { 1, 41, 41 }, -4100, 32767, 101, 151, 4, 47 }, /* region 82 */ + { { 1, 42, 42 }, -4200, 32767, 101, 151, 4, 48 }, /* region 83 */ + { { 1, 43, 43 }, -4300, 32767, 101, 151, 4, 49 }, /* region 84 */ + { { 1, 44, 44 }, -4400, 32767, 101, 151, 4, 50 }, /* region 85 */ + { { 1, 45, 45 }, -4500, 32767, 101, 151, 4, 51 }, /* region 86 */ + { { 1, 46, 46 }, -4600, 32767, 101, 151, 4, 52 }, /* region 87 */ + { { 1, 47, 47 }, -4700, 32767, 101, 151, 4, 53 }, /* region 88 */ + { { 1, 48, 48 }, -4800, 32767, 101, 151, 4, 54 }, /* region 89 */ + { { 1, 49, 49 }, -4900, 32767, 101, 151, 4, 55 }, /* region 90 */ + { { 1, 50, 50 }, -5000, 32767, 101, 151, 4, 56 }, /* region 91 */ + { { 1, 51, 51 }, -5100, 32767, 101, 151, 4, 57 }, /* region 92 */ + { { 1, 52, 52 }, -5200, 32767, 101, 151, 4, 58 }, /* region 93 */ + { { 1, 53, 53 }, -5300, 32767, 101, 151, 4, 59 }, /* region 94 */ + { { 1, 54, 54 }, -5400, 32767, 101, 151, 4, 60 }, /* region 95 */ + { { 2, 55, 55 }, -5500, 32767, 0, 0, 0, 61 }, /* region 96 */ + { { 2, 56, 56 }, -5600, 32767, 0, 0, 0, 62 }, /* region 97 */ + { { 2, 57, 57 }, -5700, 32767, 0, 0, 0, 63 }, /* region 98 */ + { { 2, 58, 58 }, -5800, 32767, 0, 0, 0, 64 }, /* region 99 */ + { { 2, 59, 59 }, -5900, 32767, 0, 0, 0, 65 }, /* region 100 */ + { { 2, 60, 60 }, -6000, 32767, 0, 0, 0, 0 }, /* region 101 */ + { { 2, 61, 61 }, -6100, 32767, 0, 0, 0, 66 }, /* region 102 */ + { { 2, 62, 62 }, -6200, 32767, 0, 0, 0, 67 }, /* region 103 */ + { { 2, 63, 63 }, -6300, 32767, 0, 0, 0, 68 }, /* region 104 */ + { { 2, 64, 64 }, -6400, 32767, 0, 0, 0, 69 }, /* region 105 */ + { { 2, 65, 65 }, -6500, 32767, 0, 0, 0, 70 }, /* region 106 */ + { { 2, 66, 66 }, -6600, 32767, 0, 0, 0, 71 }, /* region 107 */ + { { 2, 67, 67 }, -6700, 32767, 0, 0, 0, 72 }, /* region 108 */ + { { 2, 68, 68 }, -6800, 32767, 0, 0, 0, 73 }, /* region 109 */ + { { 2, 69, 69 }, -6900, 32767, 0, 0, 0, 74 }, /* region 110 */ + { { 2, 70, 70 }, -7000, 32767, 0, 0, 0, 75 }, /* region 111 */ + { { 2, 71, 71 }, -7100, 32767, 0, 0, 0, 76 }, /* region 112 */ + { { 2, 72, 72 }, -7200, 32767, 0, 0, 0, 77 }, /* region 113 */ + { { 2, 73, 73 }, -7300, 32767, 0, 0, 0, 78 }, /* region 114 */ + { { 2, 74, 74 }, -7400, 32767, 0, 0, 0, 79 }, /* region 115 */ + { { 2, 75, 75 }, -7500, 32767, 0, 0, 0, 79 }, /* region 116 */ + { { 2, 76, 76 }, -7600, 32767, 0, 0, 0, 79 }, /* region 117 */ + { { 2, 77, 77 }, -7700, 32767, 0, 0, 0, 80 }, /* region 118 */ + { { 2, 78, 78 }, -7800, 32767, 0, 0, 0, 81 }, /* region 119 */ + { { 2, 79, 79 }, -7900, 32767, 0, 0, 0, 81 }, /* region 120 */ + { { 2, 80, 80 }, -8000, 32767, 0, 0, 0, 81 }, /* region 121 */ + { { 2, 81, 81 }, -8100, 32767, 0, 0, 0, 81 }, /* region 122 */ + { { 2, 82, 82 }, -8200, 32767, 0, 0, 0, 0 }, /* region 123 */ + { { 257, 83, 83 }, -8300, 32767, 101, 151, 4, 0 }, /* region 124 */ + { { 257, 84, 84 }, -8405, 32767, 0, 171, 5, 0 }, /* region 125 */ + { { 0, 85, 85 }, -9055, 32767, 0, 0, 2, 82 }, /* region 126 */ + { { 0, 86, 86 }, -9155, 32767, 0, 0, 2, 83 }, /* region 127 */ + { { 0, 87, 87 }, -9255, 32767, 0, 0, 2, 84 }, /* region 128 */ + { { 0, 88, 88 }, -9355, 32767, 0, 0, 2, 85 }, /* region 129 */ + { { 0, 89, 89 }, -9455, 32767, 0, 0, 2, 86 }, /* region 130 */ + { { 0, 90, 90 }, -9555, 32767, 0, 0, 2, 0 }, /* region 131 */ + { { 0, 91, 91 }, -9655, 32767, 0, 0, 2, 87 }, /* region 132 */ + { { 0, 92, 92 }, -9755, 32767, 0, 0, 2, 88 }, /* region 133 */ + { { 0, 93, 93 }, -9855, 32767, 0, 0, 2, 89 }, /* region 134 */ + { { 0, 94, 94 }, -9955, 32767, 0, 0, 2, 90 }, /* region 135 */ + { { 0, 95, 95 }, -10055, 32767, 0, 0, 2, 91 }, /* region 136 */ + { { 2, 96, 96 }, -9600, 32767, 0, 0, 0, 63 }, /* region 137 */ + { { 2, 97, 97 }, -9700, 32767, 0, 0, 0, 92 }, /* region 138 */ + { { 2, 98, 98 }, -9800, 32767, 0, 0, 0, 93 }, /* region 139 */ + { { 2, 99, 99 }, -9900, 32767, 0, 0, 0, 94 }, /* region 140 */ + { { 2, 100, 100 }, -10000, 32767, 0, 0, 0, 95 }, /* region 141 */ + { { 32770, 101, 101 }, -10100, 32767, 0, 0, 0, 0 }, /* region 142 */ + { { 1, 36, 60 }, -6000, 32767, 1481, 1565, 0, 0 }, /* region 143 */ + { { 1, 61, 61 }, -7300, 32767, 740, 782, 1, 0 }, /* region 144 */ + { { 32769, 62, 62 }, -8599, 32767, 370, 391, 3, 0 }, /* region 145 */ + { { 32769, 60, 60 }, -6000, 32767, 101, 301, 4, 1 }, /* region 146 */ + { { 32769, 60, 60 }, -6000, 32767, 101, 301, 4, 50 }, /* region 147 */ + { { 32769, 60, 60 }, -6000, 32767, 101, 301, 4, 11 }, /* region 148 */ + { { 32769, 60, 60 }, -6000, 32767, 101, 301, 4, 96 }, /* region 149 */ + { { 32769, 60, 60 }, -6000, 32767, 101, 301, 4, 13 }, /* region 150 */ + { { 32769, 60, 60 }, -6000, 32767, 101, 301, 4, 14 } /* region 151 */ +}; /* end Regions */ + +/*---------------------------------------------------------------------------- + * Programs + *---------------------------------------------------------------------------- +*/ +const S_PROGRAM testPrograms[] = +{ + { 0, 41 } /* program 0 */, + { 1, 10 } /* program 1 */, + { 2, 11 } /* program 2 */, + { 3, 12 } /* program 3 */, + { 4, 18 } /* program 4 */, + { 5, 31 } /* program 5 */, + { 6, 143 } /* program 6 */, + { 7, 146 } /* program 7 */, + { 8, 147 } /* program 8 */, + { 9, 148 } /* program 9 */, + { 10, 149 } /* program 10 */, + { 11, 150 } /* program 11 */, + { 12, 151 } /* program 12 */, + { 13, 0 } /* program 13 */, + { 14, 9 } /* program 14 */, + { 15, 1 } /* program 15 */ +}; /* end Programs */ + +/*---------------------------------------------------------------------------- + * Banks + *---------------------------------------------------------------------------- +*/ +#define testBanks NULL + +/*---------------------------------------------------------------------------- + * Samples + *---------------------------------------------------------------------------- +*/ + +const EAS_SAMPLE testSamples[] = +{ + -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, + 13, 13, 14, 13, 13, 13, 12, 12, 10, 9, 8, 6, 5, 3, 2, 0, + -1, -3, -5, -8, -10, -12, -14, -15, -16, -17, -17, -17, -17, -16, -14, -13, + -11, -10, -8, -6, -5, -4, -4, -3, -3, -2, -1, -1, -1, -1, -1, -1, + -1, -2, -3, -3, -3, -3, -3, -2, -2, -2, -1, -1, -1, -1, 0, 0, + 0, 0, 0, 0, 0, 1, 2, 4, 6, 9, 11, 12, 13, 15, 16, 17, + 19, 20, 22, 23, 25, 28, 32, 34, 36, 36, 35, 31, 25, 18, 11, 3, + -5, -13, -20, -26, -31, -34, -35, -36, -36, -35, -34, -32, -29, -26, -23, -19, + -16, -12, -8, -5, -4, -4, -4, -6, -8, -9, -11, -11, -12, -13, -13, -13, + -12, -11, -10, -9, -7, -5, -4, -3, -2, -1, -1, 0, 0, 2, 4, 5, + 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 7, 9, 12, 14, 17, 20, + 24, 27, 30, 33, 36, 39, 41, 43, 46, 49, 51, 51, 50, 48, 43, 35, + 25, 14, 1, -12, -25, -37, -48, -56, -61, -63, -62, -60, -57, -53, -48, -42, + -35, -29, -23, -17, -12, -8, -5, -3, -3, -4, -5, -7, -9, -11, -12, -14, + -14, -14, -14, -13, -11, -9, -7, -5, -3, -1, 0, 1, 1, 1, 2, 3, + 4, 5, 6, 6, 7, 8, 9, 10, 11, 11, 11, 11, 10, 9, 9, 10, + 12, 14, 17, 20, 23, 26, 30, 34, 38, 40, 43, 46, 49, 52, 55, 57, + 58, 56, 50, 42, 30, 16, 1, -15, -29, -43, -54, -63, -68, -69, -68, -65, + -60, -55, -49, -42, -35, -29, -22, -16, -10, -6, -2, -1, 0, -1, -3, -6, + -9, -12, -16, -18, -20, -21, -21, -21, -19, -17, -14, -11, -8, -5, -2, 1, + 3, 5, 7, 9, 11, 12, 12, 12, 11, 10, 9, 8, 7, 7, 7, 7, + 8, 9, 10, 12, 15, 17, 19, 22, 24, 26, 28, 30, 32, 34, 36, 38, + 42, 44, 47, 49, 53, 56, 55, 52, 45, 35, 22, 8, -8, -23, -37, -50, + -60, -67, -71, -71, -69, -63, -56, -48, -40, -33, -27, -21, -16, -12, -8, -6, + -5, -5, -6, -8, -11, -14, -17, -19, -21, -22, -22, -22, -20, -18, -16, -13, + -9, -6, -2, 1, 5, 7, 8, 9, 10, 11, 11, 11, 10, 10, 9, 9, + 9, 8, 8, 9, 9, 10, 10, 12, 13, 14, 16, 18, 19, 21, 24, 26, + 29, 32, 35, 39, 42, 46, 49, 51, 53, 56, 59, 59, 55, 48, 37, 22, + 5, -12, -29, -45, -58, -68, -74, -77, -77, -75, -69, -62, -53, -44, -35, -28, + -21, -15, -11, -8, -5, -4, -4, -4, -6, -8, -10, -13, -15, -17, -19, -19, + -19, -18, -16, -13, -10, -8, -4, -1, 1, 4, 5, 7, 8, 10, 11, 12, + 13, 14, 14, 13, 12, 12, 11, 9, 8, 7, 6, 6, 7, 8, 10, 12, + 15, 18, 21, 25, 29, 34, 39, 45, 51, 57, 61, 67, 73, 77, 82, 84, + 81, 70, 52, 29, 3, -24, -49, -72, -90, -103, -110, -112, -109, -102, -91, -78, + -64, -49, -35, -23, -13, -5, 1, 5, 8, 9, 9, 7, 4, 0, -4, -9, + -12, -15, -18, -18, -18, -17, -14, -12, -9, -6, -3, 0, 3, 6, 8, 10, + 11, 12, 11, 11, 10, 8, 7, 5, 4, 2, 2, 1, 2, 3, 4, 6, + 8, 11, 13, 15, 18, 21, 26, 31, 36, 42, 48, 53, 60, 66, 72, 77, + 82, 87, 91, 91, 86, 73, 54, 28, -2, -32, -61, -86, -105, -119, -126, -126, + -121, -111, -98, -82, -65, -48, -33, -19, -7, 1, 8, 12, 14, 14, 12, 10, + 6, 1, -4, -9, -14, -18, -20, -21, -22, -21, -19, -17, -14, -11, -8, -4, + 0, 3, 7, 10, 12, 13, 14, 14, 13, 12, 11, 10, 9, 8, 7, 5, + 4, 3, 2, 2, 4, 6, 9, 12, 16, 20, 26, 31, 36, 42, 48, 53, + 58, 64, 69, 74, 79, 82, 84, 83, 80, 72, 59, 39, 14, -14, -43, -70, + -92, -109, -119, -123, -120, -113, -102, -88, -73, -56, -40, -25, -12, -2, 5, 10, + 12, 12, 11, 9, 5, 1, -3, -8, -12, -15, -18, -20, -21, -21, -20, -18, + -16, -13, -9, -6, -2, 1, 5, 8, 11, 13, 15, 16, 16, 16, 15, 14, + 12, 10, 7, 5, 4, 3, 3, 5, 6, 8, 9, 12, 15, 19, 23, 27, + 31, 35, 38, 42, 46, 50, 54, 59, 65, 71, 75, 77, 78, 76, 68, 54, + 34, 10, -16, -43, -68, -88, -103, -112, -114, -112, -105, -94, -80, -65, -50, -35, + -22, -10, -2, 5, 9, 11, 10, 9, 6, 2, -3, -7, -12, -15, -18, -20, + -21, -22, -21, -20, -17, -14, -11, -7, -3, 0, 4, 7, 9, 11, 13, 15, + 17, 17, 17, 16, 14, 12, 11, 10, 8, 7, 5, 5, 5, 6, 7, 8, + 10, 11, 14, 17, 20, 24, 28, 32, 37, 43, 49, 57, 63, 70, 77, 82, + 83, 80, 73, 60, 42, 18, -8, -34, -59, -80, -95, -105, -110, -109, -103, -94, + -81, -67, -53, -38, -24, -13, -3, 4, 9, 11, 11, 9, 6, 3, -2, -6, + -10, -14, -17, -19, -20, -20, -20, -19, -17, -15, -12, -8, -5, -1, 2, 6, + 9, 11, 13, 15, 15, 16, 16, 15, 14, 12, 11, 9, 8, 6, 6, 5, + 5, 5, 6, 7, 8, 10, 12, 15, 19, 23, 28, 32, 38, 44, 50, 58, + 66, 74, 82, 87, 90, 89, 83, 69, 48, 21, -9, -41, -69, -93, -111, -121, + -124, -121, -113, -100, -85, -68, -50, -33, -18, -5, 5, 12, 16, 17, 16, 13, + 9, 4, -1, -6, -11, -15, -18, -20, -21, -21, -21, -19, -17, -15, -12, -8, + -4, -1, 3, 6, 9, 12, 14, 15, 15, 14, 13, 12, 11, 10, 9, 9, + 8, 8, 6, 6, 5, 5, 6, 7, 8, 11, 15, 18, 23, 27, 31, 36, + 41, 46, 51, 58, 66, 74, 82, 88, 91, 90, 83, 68, 46, 16, -16, -48, + -77, -101, -118, -127, -128, -124, -114, -101, -84, -66, -47, -30, -14, -1, 9, 16, + 19, 20, 19, 15, 11, 5, -1, -6, -11, -16, -19, -21, -23, -23, -23, -21, + -19, -16, -12, -8, -4, 0, 4, 8, 11, 13, 14, 15, 15, 14, 13, 12, + 11, 10, 9, 8, 7, 7, 7, 7, 7, 8, 8, 9, 11, 12, 14, 16, + 19, 23, 27, 31, 35, 40, 45, 51, 58, 66, 74, 82, 88, 90, 88, 77, + 58, 32, 1, -31, -62, -87, -107, -119, -125, -123, -117, -105, -90, -73, -56, -38, + -22, -8, 2, 10, 15, 17, 17, 15, 11, 7, 2, -4, -9, -14, -17, -20, + -22, -23, -22, -21, -19, -17, -14, -10, -6, -2, 2, 5, 9, 12, 14, 15, + 17, 18, 18, 18, 17, 15, 12, 10, 8, 6, 4, 4, 4, 5, 6, 7, + 8, 10, 13, 16, 19, 22, 25, 28, 32, 35, 40, 45, 52, 59, 67, 75, + 81, 85, 86, 80, 66, 45, 18, -12, -42, -69, -91, -107, -116, -119, -115, -107, + -95, -80, -64, -47, -31, -17, -5, 4, 10, 13, 14, 14, 11, 7, 3, -2, + -7, -12, -15, -18, -20, -21, -21, -20, -18, -16, -14, -11, -7, -4, 0, 4, + 7, 10, 12, 14, 16, 16, 16, 16, 16, 15, 14, 12, 10, 9, 7, 6, + 5, 4, 4, 5, 6, 7, 8, 10, 12, 15, 19, 23, 27, 31, 36, 41, + 47, 55, 64, 73, 81, 87, 90, 86, 75, 56, 30, 1, -30, -58, -82, -100, + -112, -117, -115, -109, -98, -84, -69, -52, -37, -22, -10, 0, 8, 12, 14, 14, + 13, 10, 6, 2, -3, -8, -12, -16, -18, -20, -20, -20, -19, -17, -15, -12, + -9, -5, -1, 2, 6, 9, 12, 14, 16, 17, 17, 17, 16, 14, 13, 11, + 8, 6, 4, 3, 2, 2, 2, 3, 5, 6, 8, 10, 12, 15, 18, 22, + 26, 30, 35, 40, 47, 55, 63, 71, 80, 87, 90, 88, 78, 59, 34, 4, + -27, -57, -82, -101, -113, -118, -117, -110, -99, -85, -69, -53, -37, -22, -9, 2, + 9, 14, 17, 17, 15, 12, 8, 3, -2, -7, -12, -16, -19, -20, -21, -21, + -19, -18, -15, -12, -9, -6, -2, 2, 6, 9, 12, 14, 16, 17, 17, 16, + 14, 12, 10, 8, 6, 5, 4, 3, 3, 2, 3, 4, 6, 7, 9, 11, + 13, 16, 19, 22, 26, 30, 34, 39, 46, 53, 61, 70, 80, 88, 93, 91, + 80, 61, 34, 3, -30, -59, -84, -102, -114, -119, -117, -110, -99, -84, -68, -51, + -35, -20, -7, 3, 11, 15, 17, 18, 16, 13, 9, 4, -2, -7, -11, -15, + -18, -20, -21, -21, -20, -19, -16, -14, -11, -8, -4, 0, 3, 7, 10, 13, + 15, 16, 17, 16, 14, 12, 10, 9, 7, 6, 5, 4, 4, 4, 5, 6, + 7, 8, 9, 11, 13, 15, 18, 21, 24, 27, 31, 35, 41, 48, 55, 64, + 73, 82, 89, 91, 85, 71, 48, 19, -13, -44, -71, -93, -108, -117, -118, -114, + -105, -92, -77, -60, -43, -27, -13, -1, 8, 14, 17, 18, 17, 14, 8, 13, + -1, -1, 0, 2, 4, 6, 9, 11, 13, 14, 13, 12, 11, 8, 5, 2, + -1, -5, -10, -14, -16, -17, -16, -14, -11, -8, -5, -4, -3, -1, -1, -1, + -1, -3, -3, -3, -2, -1, -1, 0, 0, 0, 0, 2, 6, 11, 14, 16, + 19, 22, 25, 32, 36, 34, 25, 11, -5, -20, -31, -35, -36, -34, -29, -23, + -16, -8, -4, -4, -8, -11, -12, -13, -12, -10, -7, -4, -2, -1, 1, 4, + 7, 7, 6, 6, 6, 7, 12, 17, 24, 30, 36, 41, 46, 51, 50, 43, + 25, 2, -25, -48, -61, -62, -57, -48, -35, -23, -12, -5, -3, -5, -9, -12, + -14, -14, -12, -7, -3, 0, 1, 2, 4, 6, 7, 9, 11, 11, 10, 9, + 12, 17, 23, 30, 37, 43, 49, 55, 58, 50, 30, 1, -29, -54, -68, -68, + -60, -49, -35, -22, -10, -2, 0, -3, -9, -16, -20, -21, -19, -14, -8, -2, + 3, 7, 11, 12, 11, 9, 7, 7, 8, 10, 15, 19, 24, 28, 33, 36, + 42, 47, 53, 56, 45, 23, -8, -37, -60, -71, -69, -56, -40, -27, -16, -8, + -5, -6, -11, -17, -21, -22, -20, -16, -9, -2, 5, 8, 10, 11, 10, 9, + 8, 8, 9, 10, 13, 16, 19, 24, 29, 35, 42, 49, 53, 59, 55, 37, + 5, -29, -58, -74, -77, -69, -53, -35, -21, -11, -5, -4, -6, -10, -15, -19, + -19, -16, -10, -5, 1, 5, 8, 11, 13, 14, 12, 10, 8, 6, 7, 10, + 15, 21, 29, 39, 51, 62, 72, 82, 81, 52, 3, -50, -90, -110, -109, -91, + -64, -35, -13, 1, 8, 9, 4, -4, -12, -18, -18, -14, -9, -3, 3, 8, + 11, 11, 10, 7, 4, 2, 2, 4, 8, 13, 18, 26, 36, 48, 60, 72, + 82, 91, 86, 54, -2, -61, -105, -126, -121, -98, -65, -33, -7, 8, 14, 12, + 6, -4, -14, -20, -22, -19, -14, -8, 0, 7, 12, 14, 13, 11, 9, 7, + 4, 2, 4, 9, 16, 26, 36, 48, 58, 69, 79, 84, 80, 59, 14, -43, + -92, -119, -120, -102, -73, -40, -12, 5, 12, 11, 5, -3, -12, -18, -21, -20, + -16, -9, -2, 5, 11, 15, 16, 15, 12, 7, 4, 4, 6, 9, 15, 23, + 31, 38, 46, 54, 65, 75, 78, 68, 34, -16, -68, -103, -114, -105, -80, -50, + -22, -1, 9, 10, 6, -3, -12, -18, -21, -21, -17, -11, -3, 4, 9, 13, + 16, 17, 14, 11, 8, 5, 5, 7, 10, 14, 20, 28, 37, 49, 64, 77, + 83, 73, 42, -8, -59, -95, -110, -103, -81, -53, -24, -3, 9, 11, 6, -2, + -10, -17, -20, -20, -17, -12, -5, 2, 9, 13, 15, 16, 14, 11, 8, 6, + 5, 6, 8, 12, 19, 28, 38, 50, 66, 82, 90, 83, 48, -9, -69, -111, + -124, -113, -85, -50, -18, 5, 16, 16, 9, -1, -11, -18, -21, -21, -17, -12, + -5, 3, 9, 14, 15, 13, 11, 9, 8, 6, 5, 6, 8, 15, 23, 31, + 41, 52, 66, 82, 91, 83, 46, -16, -77, -118, -128, -114, -84, -47, -14, 9, + 19, 19, 10, -1, -11, -19, -23, -23, -19, -12, -4, 4, 11, 14, 15, 13, + 11, 9, 7, 7, 7, 8, 11, 14, 19, 27, 35, 45, 58, 74, 88, 88, + 58, 1, -62, -107, -125, -116, -90, -56, -22, 2, 15, 17, 11, 2, -9, -17, + -22, -22, -20, -14, -6, 2, 9, 14, 17, 18, 17, 12, 8, 4, 4, 6, + 8, 13, 19, 25, 32, 40, 52, 67, 81, 86, 66, 18, -42, -91, -116, -115, + -95, -64, -31, -5, 10, 14, 11, 3, -7, -15, -20, -21, -18, -14, -7, 0, + 7, 12, 16, 17, 16, 14, 10, 7, 5, 4, 6, 8, 12, 19, 27, 36, + 47, 64, 81, 90, 75, 30, -30, -82, -112, -115, -98, -69, -37, -10, 8, 14, + 13, 6, -3, -12, -18, -20, -19, -15, -9, -1, 6, 12, 16, 17, 16, 13, + 8, 4, 2, 2, 5, 8, 12, 18, 26, 35, 47, 63, 80, 90, 78, 34, + -27, -82, -113, -117, -99, -69, -37, -9, 9, 17, 15, 8, -2, -12, -19, -21, + -19, -15, -9, -2, 6, 12, 16, 17, 14, 10, 6, 4, 3, 3, 6, 9, + 13, 19, 26, 34, 46, 61, 80, 93, 80, 34, -30, -84, -114, -117, -99, -68, + -35, -7, 11, 17, 16, 9, -2, -11, -18, -21, -20, -16, -11, -4, 3, 10, + 15, 17, 14, 10, 7, 5, 4, 5, 7, 9, 13, 18, 24, 31, 41, 55, + 73, 89, 85, 48, -12, -71, -108, -118, -104, -77, -43, -13, 8, 16, 17, 16, + 0, -3, -4, -5, -4, 0, -4, -8, -20, -25, 51, 11, -55, 9, 39, 55, + -76, -19, 92, -23, -58, 2, -15, 57, 71, 34, -41, 20, 51, 22, 63, -21, + 63, 74, 32, 36, 99, -14, 27, 102, 66, 90, 79, 77, 58, 66, 65, 114, + 69, 26, 30, 92, 90, 53, 78, 97, 77, 66, 39, -4, 60, 57, 64, 68, + -16, 36, 49, 12, 19, 12, -12, 21, 11, -32, -19, -41, -44, -12, -36, -44, + -45, -51, -55, -70, -69, -73, -85, -102, -86, -99, -92, -105, -108, -103, -100, -107, + -112, -104, -113, -112, -104, -119, -124, -115, -87, -100, -128, -106, -83, -105, -108, -109, + -91, -95, -90, -83, -80, -79, -83, -68, -59, -53, -63, -69, -57, -28, -11, -38, + -43, -23, -10, -6, 3, 1, 6, 14, 21, 23, 34, 40, 42, 48, 57, 61, + 63, 65, 73, 82, 90, 82, 89, 98, 100, 110, 111, 109, 115, 120, 121, 121, + 123, 123, 123, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 121, 121, + 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 120, 120, 120, 120, 120, 120, + 120, 120, 120, 120, 113, 104, 103, 113, 110, 94, 80, 88, 96, 89, 81, 70, + 68, 64, 59, 59, 54, 44, 44, 39, 31, 31, 21, 18, 16, 8, 6, 2, + -3, -6, -13, -19, -27, -31, -34, -30, -38, -47, -48, -51, -56, -64, -68, -67, + -68, -76, -73, -79, -85, -94, -89, -90, -94, -92, -99, -100, -107, -107, -104, -107, + -106, -112, -114, -113, -112, -111, -112, -116, -116, -115, -115, -115, -115, -115, -115, -115, + -114, -114, -114, -114, -114, -114, -114, -114, -113, -113, -113, -113, -113, -108, -106, -107, + -111, -110, -105, -108, -107, -102, -100, -103, -103, -100, -100, -97, -97, -100, -99, -97, + -94, -90, -94, -94, -93, -93, -92, -92, -90, -89, -89, -90, -91, -87, -87, -88, + -89, -88, -84, -85, -88, -87, -86, -85, -85, -84, -82, -83, -83, -82, -81, -80, + -79, -79, -79, -78, -75, -74, -75, -73, -74, -71, -69, -67, -69, -66, -64, -66, + -65, -64, -62, -58, -57, -57, -57, -56, -52, -51, -50, -48, -46, -43, -43, -42, + -39, -36, -35, -34, -32, -31, -29, -26, -23, -23, -21, -15, -18, -15, -11, -8, + -6, -7, 0, 2, 0, 2, 7, 15, 14, 15, 16, 19, 23, 27, 29, 30, + 31, 34, 41, 41, 42, 44, 45, 51, 55, 54, 56, 57, 60, 65, 67, 69, + 69, 71, 74, 77, 79, 78, 80, 82, 86, 86, 84, 86, 88, 87, 87, 87, + 87, 87, 86, 86, 86, 86, 86, 85, 85, 85, 85, 85, 84, 84, 84, 84, + 84, 83, 83, 83, 83, 83, 83, 82, 82, 82, 82, 82, 81, 81, 81, 81, + 81, 80, 80, 80, 80, 80, 79, 79, 79, 79, 79, 78, 78, 78, 78, 76, + 75, 72, 69, 67, 65, 64, 63, 59, 55, 54, 52, 50, 48, 45, 42, 38, + 36, 34, 31, 30, 27, 24, 21, 18, 16, 14, 12, 9, 7, 4, 1, -2, + -4, -7, -10, -11, -13, -16, -17, -18, -21, -24, -26, -27, -28, -30, -32, -33, + -35, -36, -38, -39, -41, -42, -43, -45, -45, -46, -47, -48, -49, -50, -51, -50, + -51, -52, -53, -53, -53, -53, -53, -53, -53, -54, -54, -54, -54, -53, -53, -52, + -52, -52, -51, -51, -51, -50, -50, -50, -48, -49, -48, -47, -46, -45, -45, -44, + -43, -42, -41, -41, -40, -39, -38, -37, -36, -35, -34, -33, -31, -30, -29, -28, + -27, -26, -24, -24, -23, -22, -21, -20, -19, -18, -17, -16, -15, -14, -13, -13, + -12, -11, -11, -10, -9, -9, -8, -8, -7, -6, -7, -6, -5, -5, -5, -4, + -4, -3, -3, -3, -3, -3, -2, -2, -2, -2, -2, -2, -2, -2, 0, 0, + 0, 0, -1, 0, 4, 9, 13, 13, 11, 5, -1, -10, -16, -17, -11, -5, + -2, -1, -2, -3, -2, -1, 0, 0, 6, 14, 19, 26, 36, 25, -5, -30, + -36, -29, -16, -4, -7, -13, -12, -7, -2, 1, 6, 7, 6, 11, 24, 36, + 46, 50, 26, -25, -60, -57, -36, -12, -3, -9, -14, -12, -3, 1, 4, 7, + 11, 10, 12, 23, 37, 49, 58, 31, -29, -67, -61, -36, -10, 0, -9, -20, + -19, -8, 3, 11, 11, 7, 8, 15, 24, 32, 41, 53, 45, -7, -60, -68, + -41, -16, -5, -11, -21, -20, -10, 4, 10, 10, 8, 9, 13, 19, 29, 42, + 54, 55, 6, -57, -77, -54, -21, -6, -6, -15, -19, -11, 1, 8, 13, 12, + 8, 7, 15, 29, 50, 73, 80, 5, -90, -109, -65, -13, 8, 4, -13, -18, + -10, 3, 11, 10, 4, 2, 8, 18, 36, 60, 82, 86, 1, -105, -121, -66, + -8, 13, 6, -14, -22, -15, -1, 12, 13, 9, 4, 3, 16, 36, 58, 78, + 81, 15, -91, -121, -74, -13, 12, 5, -11, -21, -16, -2, 11, 16, 12, 4, + 6, 15, 31, 46, 64, 79, 36, -66, -115, -81, -23, 9, 6, -11, -21, -17, + -4, 9, 16, 15, 8, 5, 9, 20, 37, 63, 83, 43, -57, -110, -83, -25, + 8, 7, -10, -20, -17, -5, 9, 15, 14, 8, 5, 8, 18, 37, 65, 91, + 50, -67, -124, -86, -19, 16, 9, -10, -21, -18, -5, 9, 15, 11, 8, 5, + 8, 22, 40, 65, 92, 48, -74, -128, -85, -16, 19, 11, -11, -23, -19, -4, + 10, 15, 11, 8, 7, 11, 19, 35, 57, 88, 60, -58, -125, -92, -24, 15, + 12, -8, -22, -20, -7, 9, 17, 17, 8, 4, 8, 18, 31, 51, 81, 67, + -38, -116, -96, -33, 9, 11, -6, -20, -19, -8, 7, 16, 16, 11, 5, 5, + 12, 26, 47, 80, 76, -26, -111, -99, -39, 7, 13, -3, -18, -19, -9, 5, + 16, 16, 8, 2, 4, 12, 25, 46, 79, 79, -23, -112, -101, -39, 9, 15, + -2, -18, -20, -9, 5, 16, 14, 7, 3, 5, 13, 25, 44, 79, 81, -25, + -113, -100, -37, 10, 16, -1, -18, -20, -11, 3, 15, 15, 7, 4, 6, 13, + 23, 40, 72, 86, -7, -107, -106, -46, 7, 16, 0, 16, 31, 47, 61, 75, + 87, 98, 107, 115, 121, 125, 127, 127, 125, 121, 116, 108, 99, 88, 75, 62, + 47, 32, 16, 0, -16, -31, -47, -61, -75, -87, -98, -108, -116, -122, -126, -128, + -128, -126, -123, -117, -109, -100, -89, -77, -64, -49, -34, -18, -2, 14, 29, 45, + 59, 73, 86, 97, 106, 114, 121, 125, 127, 127, 126, 122, 116, 109, 100, 89, + 77, 63, 49, 34, 18, 2, -14, -30, -45, -60, -73, -86, -97, -107, -115, -121, + -126, -128, -128, -127, -123, -118, -110, -101, -91, -79, -65, -51, -36, -20, -4, 12, + 28, 43, 58, 72, 84, 96, 106, 114, 120, 124, 127, 127, 126, 122, 117, 109, + 100, 90, 78, 64, 50, 35, 19, 3, -13, -29, -44, -59, -73, -85, -97, -107, + -115, -121, -125, -128, -128, -127, -123, -118, -110, -101, -91, -79, -65, -51, -36, -20, + -4, 12, 28, 43, 58, 72, 84, 96, 106, 114, 120, 124, 127, 127, 126, 122, + 117, 109, 100, 90, 78, 64, 50, 35, 19, 3, -13, -29, -44, -59, -73, -85, + -97, -107, -115, -121, -125, -128, -128, -127, -123, -118, -110, -101, -91, -79, -65, -51, + -36, -20, -4, 12, 28, 43, 58, 72, 84, 96, 106, 114, 120, 124, 127, 127, + 126, 122, 117, 109, 100, 90, 78, 64, 50, 35, 19, 3, -13, -29, -44, -59, + -73, -85, -97, -107, -115, -121, -125, -128, -128, -127, -123, -118, -110, -101, -91, -79, + -65, -51, -36, -20, -4, 12, 28, 43, 58, 72, 84, 96, 106, 114, 120, 124, + 127, 127, 126, 122, 117, 109, 100, 90, 78, 64, 50, 35, 19, 3, -13, -29, + -44, -59, -73, -85, -97, -107, -115, -121, -125, -128, -128, -127, -123, -118, -110, -101, + -91, -79, -65, -51, -36, -20, -4, 12, 0, -104, -55, -11, 24, 33, 30, 7, + -15, -31, -30, -25, -23, -20, -9, 10, 31, 59, 91, 111, 115, 92, 51, 7, + -33, -64, -81, -81, -71, -51, -22, 16, 52, 74, 82, 81, 68, 38, 0, -40, + -81, -112, -124, -102, -57, -11, 24, 33, 30, 7, -15, -31, -30, -25, -23, -20, + -9, 10, 31, 59, 91, 111, 115, 92, 51, 7, -33, -64, -81, -81, -71, -51, + -22, 16, 52, 74, 82, 81, 68, 38, 0, -40, -81, -112, -124, -102, -57, -11, + 24, 33, 30, 7, -15, -31, -30, -25, -23, -20, -9, 10, 31, 59, 91, 111, + 115, 92, 51, 7, -33, -64, -81, -81, -71, -51, -22, 16, 52, 74, 82, 81, + 68, 38, 0, -40, -81, -112, -124, -102, -57, -11, 24, 33, 30, 7, -15, -31, + -30, -25, -23, -20, -9, 10, 31, 59, 91, 111, 115, 92, 51, 7, -33, -64, + -81, -81, -71, -51, -22, 16, 52, 74, 82, 81, 68, 38, 0, -40, -81, -112, + -124, -102, -57, -11, 0 +}; + +const EAS_U32 testSampleLengths[] = +{ + 1568, 784, 642, 392, 302, 172 +}; + +const EAS_U32 testSampleOffsets[] = +{ + 0x00000000, 0x00000620, 0x00000930, 0x00000bb2, 0x00000d3a, 0x00000e68 +}; + +/*---------------------------------------------------------------------------- + * S_EAS + *---------------------------------------------------------------------------- +*/ +const S_EAS easTestLib = +{ + 0x01534145, + 0x00105622, + testBanks, + testPrograms, + testRegions, + testArticulations, + testSampleLengths, + testSampleOffsets, + testSamples, + 0, + 0, + 16, + 152, + 97, + 6, + 0 +}; /* end S_EAS */ + +/*---------------------------------------------------------------------------- + * Statistics + * + * Number of banks: 0 + * Number of programs: 16 + * Number of regions: 152 + * Number of articulations: 97 + * Number of samples: 6 + * Size of sample pool: 3861 + *---------------------------------------------------------------------------- +*/ +/* end ..\..\EASLib\WTLibrary\eastestv37.c */ diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/easwt_vst_lib.xcodeproj/project.pbxproj b/common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/easwt_vst_lib.xcodeproj/project.pbxproj new file mode 100755 index 0000000..bd0d6ef --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/easwt_vst_lib.xcodeproj/project.pbxproj @@ -0,0 +1,645 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 44; + objects = { + +/* Begin PBXBuildFile section */ + 9A56AB8F0F7197AE00D115A7 /* wt_44khz.c in Sources */ = {isa = PBXBuildFile; fileRef = 9A56AB8E0F7197AE00D115A7 /* wt_44khz.c */; }; + 9A56ABD00F71998600D115A7 /* eas_fmengine.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A56ABCF0F71998600D115A7 /* eas_fmengine.h */; }; + 9A56ABDB0F719D4600D115A7 /* eas_xmf.c in Sources */ = {isa = PBXBuildFile; fileRef = 9A56ABD70F719D4600D115A7 /* eas_xmf.c */; }; + 9A56ABDC0F719D4600D115A7 /* eas_xmf.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A56ABD80F719D4600D115A7 /* eas_xmf.h */; }; + 9A56ABDD0F719D4600D115A7 /* eas_xmfdata.c in Sources */ = {isa = PBXBuildFile; fileRef = 9A56ABD90F719D4600D115A7 /* eas_xmfdata.c */; }; + 9A56ABDE0F719D4600D115A7 /* eas_xmfdata.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A56ABDA0F719D4600D115A7 /* eas_xmfdata.h */; }; + 9A56AC050F71BCFE00D115A7 /* eas_build.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A56AC040F71BCFE00D115A7 /* eas_build.h */; }; + C55B113D0E2D33B4006357C1 /* eas.h in Headers */ = {isa = PBXBuildFile; fileRef = C55B11290E2D33B4006357C1 /* eas.h */; }; + C55B113E0E2D33B4006357C1 /* eas_audioconst.h in Headers */ = {isa = PBXBuildFile; fileRef = C55B112A0E2D33B4006357C1 /* eas_audioconst.h */; }; + C55B11400E2D33B4006357C1 /* eas_config.h in Headers */ = {isa = PBXBuildFile; fileRef = C55B112C0E2D33B4006357C1 /* eas_config.h */; }; + C55B11410E2D33B4006357C1 /* eas_data.h in Headers */ = {isa = PBXBuildFile; fileRef = C55B112D0E2D33B4006357C1 /* eas_data.h */; }; + C55B11420E2D33B4006357C1 /* eas_host.h in Headers */ = {isa = PBXBuildFile; fileRef = C55B112E0E2D33B4006357C1 /* eas_host.h */; }; + C55B11430E2D33B4006357C1 /* eas_math.h in Headers */ = {isa = PBXBuildFile; fileRef = C55B112F0E2D33B4006357C1 /* eas_math.h */; }; + C55B11440E2D33B4006357C1 /* eas_midi.h in Headers */ = {isa = PBXBuildFile; fileRef = C55B11300E2D33B4006357C1 /* eas_midi.h */; }; + C55B11450E2D33B4006357C1 /* eas_midictrl.h in Headers */ = {isa = PBXBuildFile; fileRef = C55B11310E2D33B4006357C1 /* eas_midictrl.h */; }; + C55B11460E2D33B4006357C1 /* eas_mixer.c in Sources */ = {isa = PBXBuildFile; fileRef = C55B11320E2D33B4006357C1 /* eas_mixer.c */; }; + C55B11470E2D33B4006357C1 /* eas_pan.h in Headers */ = {isa = PBXBuildFile; fileRef = C55B11330E2D33B4006357C1 /* eas_pan.h */; }; + C55B11480E2D33B4006357C1 /* eas_pcm.h in Headers */ = {isa = PBXBuildFile; fileRef = C55B11340E2D33B4006357C1 /* eas_pcm.h */; }; + C55B11490E2D33B4006357C1 /* eas_pcmdata.h in Headers */ = {isa = PBXBuildFile; fileRef = C55B11350E2D33B4006357C1 /* eas_pcmdata.h */; }; + C55B114B0E2D33B4006357C1 /* eas_report.h in Headers */ = {isa = PBXBuildFile; fileRef = C55B11370E2D33B4006357C1 /* eas_report.h */; }; + C55B114C0E2D33B4006357C1 /* eas_sndlib.h in Headers */ = {isa = PBXBuildFile; fileRef = C55B11380E2D33B4006357C1 /* eas_sndlib.h */; }; + C55B114D0E2D33B4006357C1 /* eas_synth.h in Headers */ = {isa = PBXBuildFile; fileRef = C55B11390E2D33B4006357C1 /* eas_synth.h */; }; + C55B114E0E2D33B4006357C1 /* eas_synth_protos.h in Headers */ = {isa = PBXBuildFile; fileRef = C55B113A0E2D33B4006357C1 /* eas_synth_protos.h */; }; + C55B114F0E2D33B4006357C1 /* eas_types.h in Headers */ = {isa = PBXBuildFile; fileRef = C55B113B0E2D33B4006357C1 /* eas_types.h */; }; + C55B11500E2D33B4006357C1 /* eas_vm_protos.h in Headers */ = {isa = PBXBuildFile; fileRef = C55B113C0E2D33B4006357C1 /* eas_vm_protos.h */; }; + C55B115B0E2D3796006357C1 /* eas_effects.h in Headers */ = {isa = PBXBuildFile; fileRef = C55B11530E2D3796006357C1 /* eas_effects.h */; }; + C55B11640E2D37FC006357C1 /* eas_imelodydata.h in Headers */ = {isa = PBXBuildFile; fileRef = C55B11620E2D37FC006357C1 /* eas_imelodydata.h */; }; + C55B11760E2D38CE006357C1 /* eas_mdls.h in Headers */ = {isa = PBXBuildFile; fileRef = C55B116B0E2D38CE006357C1 /* eas_mdls.h */; }; + C55B11770E2D38CE006357C1 /* eas_otadata.h in Headers */ = {isa = PBXBuildFile; fileRef = C55B116C0E2D38CE006357C1 /* eas_otadata.h */; }; + C55B11780E2D38CE006357C1 /* eas_parser.h in Headers */ = {isa = PBXBuildFile; fileRef = C55B116D0E2D38CE006357C1 /* eas_parser.h */; }; + C55B11790E2D38CE006357C1 /* eas_rtttldata.h in Headers */ = {isa = PBXBuildFile; fileRef = C55B116E0E2D38CE006357C1 /* eas_rtttldata.h */; }; + C55B117B0E2D38CE006357C1 /* eas_smf.h in Headers */ = {isa = PBXBuildFile; fileRef = C55B11700E2D38CE006357C1 /* eas_smf.h */; }; + C55B117C0E2D38CE006357C1 /* eas_smfdata.h in Headers */ = {isa = PBXBuildFile; fileRef = C55B11710E2D38CE006357C1 /* eas_smfdata.h */; }; + C55B117D0E2D38CE006357C1 /* eas_tcdata.h in Headers */ = {isa = PBXBuildFile; fileRef = C55B11720E2D38CE006357C1 /* eas_tcdata.h */; }; + C55B117E0E2D38CE006357C1 /* eas_wavefile.h in Headers */ = {isa = PBXBuildFile; fileRef = C55B11730E2D38CE006357C1 /* eas_wavefile.h */; }; + C55B11830E2D38FB006357C1 /* jet.h in Headers */ = {isa = PBXBuildFile; fileRef = C55B11810E2D38FB006357C1 /* jet.h */; }; + C55B11840E2D38FB006357C1 /* jet_data.h in Headers */ = {isa = PBXBuildFile; fileRef = C55B11820E2D38FB006357C1 /* jet_data.h */; }; + C55B11860E2D395F006357C1 /* eas_wtengine.h in Headers */ = {isa = PBXBuildFile; fileRef = C55B11850E2D395F006357C1 /* eas_wtengine.h */; }; + C55B11900E2D39ED006357C1 /* eas_reverb.h in Headers */ = {isa = PBXBuildFile; fileRef = C55B118E0E2D39ED006357C1 /* eas_reverb.h */; }; + C55B11910E2D39ED006357C1 /* eas_reverbdata.h in Headers */ = {isa = PBXBuildFile; fileRef = C55B118F0E2D39ED006357C1 /* eas_reverbdata.h */; }; + C55B11940E2D39FE006357C1 /* eas_chorus.h in Headers */ = {isa = PBXBuildFile; fileRef = C55B11920E2D39FE006357C1 /* eas_chorus.h */; }; + C55B11950E2D39FE006357C1 /* eas_chorusdata.h in Headers */ = {isa = PBXBuildFile; fileRef = C55B11930E2D39FE006357C1 /* eas_chorusdata.h */; }; + C55B11AE0E2D3B1B006357C1 /* eas_data.c in Sources */ = {isa = PBXBuildFile; fileRef = C55B119F0E2D3B1B006357C1 /* eas_data.c */; }; + C55B11AF0E2D3B1B006357C1 /* eas_flog.c in Sources */ = {isa = PBXBuildFile; fileRef = C55B11A00E2D3B1B006357C1 /* eas_flog.c */; }; + C55B11B10E2D3B1B006357C1 /* eas_ima_tables.c in Sources */ = {isa = PBXBuildFile; fileRef = C55B11A20E2D3B1B006357C1 /* eas_ima_tables.c */; }; + C55B11B20E2D3B1B006357C1 /* eas_imaadpcm.c in Sources */ = {isa = PBXBuildFile; fileRef = C55B11A30E2D3B1B006357C1 /* eas_imaadpcm.c */; }; + C55B11B30E2D3B1B006357C1 /* eas_math.c in Sources */ = {isa = PBXBuildFile; fileRef = C55B11A40E2D3B1B006357C1 /* eas_math.c */; }; + C55B11B40E2D3B1B006357C1 /* eas_midi.c in Sources */ = {isa = PBXBuildFile; fileRef = C55B11A50E2D3B1B006357C1 /* eas_midi.c */; }; + C55B11B50E2D3B1B006357C1 /* eas_mididata.c in Sources */ = {isa = PBXBuildFile; fileRef = C55B11A60E2D3B1B006357C1 /* eas_mididata.c */; }; + C55B11B60E2D3B1B006357C1 /* eas_mixbuf.c in Sources */ = {isa = PBXBuildFile; fileRef = C55B11A70E2D3B1B006357C1 /* eas_mixbuf.c */; }; + C55B11B70E2D3B1B006357C1 /* eas_pan.c in Sources */ = {isa = PBXBuildFile; fileRef = C55B11A80E2D3B1B006357C1 /* eas_pan.c */; }; + C55B11B80E2D3B1B006357C1 /* eas_pcm.c in Sources */ = {isa = PBXBuildFile; fileRef = C55B11A90E2D3B1B006357C1 /* eas_pcm.c */; }; + C55B11B90E2D3B1B006357C1 /* eas_pcmdata.c in Sources */ = {isa = PBXBuildFile; fileRef = C55B11AA0E2D3B1B006357C1 /* eas_pcmdata.c */; }; + C55B11BA0E2D3B1B006357C1 /* eas_public.c in Sources */ = {isa = PBXBuildFile; fileRef = C55B11AB0E2D3B1B006357C1 /* eas_public.c */; }; + C55B11BB0E2D3B1B006357C1 /* eas_voicemgt.c in Sources */ = {isa = PBXBuildFile; fileRef = C55B11AC0E2D3B1B006357C1 /* eas_voicemgt.c */; }; + C55B11BD0E2D3B55006357C1 /* jet.c in Sources */ = {isa = PBXBuildFile; fileRef = C55B11BC0E2D3B55006357C1 /* jet.c */; }; + C55B11C10E2D3BFD006357C1 /* eas_chorus.c in Sources */ = {isa = PBXBuildFile; fileRef = C55B11C00E2D3BFD006357C1 /* eas_chorus.c */; }; + C55B11E40E2D3C62006357C1 /* eas_imelody.c in Sources */ = {isa = PBXBuildFile; fileRef = C55B11D00E2D3C62006357C1 /* eas_imelody.c */; }; + C55B11E50E2D3C62006357C1 /* eas_imelodydata.c in Sources */ = {isa = PBXBuildFile; fileRef = C55B11D10E2D3C62006357C1 /* eas_imelodydata.c */; }; + C55B11E60E2D3C62006357C1 /* eas_mdls.c in Sources */ = {isa = PBXBuildFile; fileRef = C55B11D20E2D3C62006357C1 /* eas_mdls.c */; }; + C55B11E70E2D3C62006357C1 /* eas_ota.c in Sources */ = {isa = PBXBuildFile; fileRef = C55B11D30E2D3C62006357C1 /* eas_ota.c */; }; + C55B11E80E2D3C62006357C1 /* eas_otadata.c in Sources */ = {isa = PBXBuildFile; fileRef = C55B11D40E2D3C62006357C1 /* eas_otadata.c */; }; + C55B11E90E2D3C62006357C1 /* eas_rtttl.c in Sources */ = {isa = PBXBuildFile; fileRef = C55B11D50E2D3C62006357C1 /* eas_rtttl.c */; }; + C55B11EA0E2D3C62006357C1 /* eas_rtttldata.c in Sources */ = {isa = PBXBuildFile; fileRef = C55B11D60E2D3C62006357C1 /* eas_rtttldata.c */; }; + C55B11EE0E2D3C62006357C1 /* eas_smf.c in Sources */ = {isa = PBXBuildFile; fileRef = C55B11DA0E2D3C62006357C1 /* eas_smf.c */; }; + C55B11EF0E2D3C62006357C1 /* eas_smfdata.c in Sources */ = {isa = PBXBuildFile; fileRef = C55B11DB0E2D3C62006357C1 /* eas_smfdata.c */; }; + C55B11F00E2D3C62006357C1 /* eas_tcdata.c in Sources */ = {isa = PBXBuildFile; fileRef = C55B11DC0E2D3C62006357C1 /* eas_tcdata.c */; }; + C55B11F10E2D3C62006357C1 /* eas_tonecontrol.c in Sources */ = {isa = PBXBuildFile; fileRef = C55B11DD0E2D3C62006357C1 /* eas_tonecontrol.c */; }; + C55B11F20E2D3C62006357C1 /* eas_wavefile.c in Sources */ = {isa = PBXBuildFile; fileRef = C55B11DE0E2D3C62006357C1 /* eas_wavefile.c */; }; + C55B11F30E2D3C62006357C1 /* eas_wavefiledata.c in Sources */ = {isa = PBXBuildFile; fileRef = C55B11DF0E2D3C62006357C1 /* eas_wavefiledata.c */; }; + C55B11F70E2D3C7B006357C1 /* eas_reverb.c in Sources */ = {isa = PBXBuildFile; fileRef = C55B11F60E2D3C7B006357C1 /* eas_reverb.c */; }; + C55B11FA0E2D3CAC006357C1 /* eastestv37.c in Sources */ = {isa = PBXBuildFile; fileRef = C55B11F80E2D3CAC006357C1 /* eastestv37.c */; }; + C55B12050E2D3D56006357C1 /* eas_dlssynth.c in Sources */ = {isa = PBXBuildFile; fileRef = C55B12020E2D3D56006357C1 /* eas_dlssynth.c */; }; + C55B12060E2D3D56006357C1 /* eas_wtengine.c in Sources */ = {isa = PBXBuildFile; fileRef = C55B12030E2D3D56006357C1 /* eas_wtengine.c */; }; + C55B12070E2D3D56006357C1 /* eas_wtsynth.c in Sources */ = {isa = PBXBuildFile; fileRef = C55B12040E2D3D56006357C1 /* eas_wtsynth.c */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 9A56AB8E0F7197AE00D115A7 /* wt_44khz.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = wt_44khz.c; sourceTree = ""; }; + 9A56ABCF0F71998600D115A7 /* eas_fmengine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = eas_fmengine.h; path = "../../../arm-fm-22k/lib_src/eas_fmengine.h"; sourceTree = SOURCE_ROOT; }; + 9A56ABD70F719D4600D115A7 /* eas_xmf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eas_xmf.c; path = ../../lib_src/eas_xmf.c; sourceTree = SOURCE_ROOT; }; + 9A56ABD80F719D4600D115A7 /* eas_xmf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = eas_xmf.h; path = ../../lib_src/eas_xmf.h; sourceTree = SOURCE_ROOT; }; + 9A56ABD90F719D4600D115A7 /* eas_xmfdata.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eas_xmfdata.c; path = ../../lib_src/eas_xmfdata.c; sourceTree = SOURCE_ROOT; }; + 9A56ABDA0F719D4600D115A7 /* eas_xmfdata.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = eas_xmfdata.h; path = ../../lib_src/eas_xmfdata.h; sourceTree = SOURCE_ROOT; }; + 9A56AC040F71BCFE00D115A7 /* eas_build.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = eas_build.h; path = ../../host_src/eas_build.h; sourceTree = SOURCE_ROOT; }; + C55B11290E2D33B4006357C1 /* eas.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = eas.h; path = ../../host_src/eas.h; sourceTree = SOURCE_ROOT; }; + C55B112A0E2D33B4006357C1 /* eas_audioconst.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = eas_audioconst.h; path = ../../lib_src/eas_audioconst.h; sourceTree = SOURCE_ROOT; }; + C55B112C0E2D33B4006357C1 /* eas_config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = eas_config.h; path = ../../host_src/eas_config.h; sourceTree = SOURCE_ROOT; }; + C55B112D0E2D33B4006357C1 /* eas_data.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = eas_data.h; path = ../../lib_src/eas_data.h; sourceTree = SOURCE_ROOT; }; + C55B112E0E2D33B4006357C1 /* eas_host.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = eas_host.h; path = ../../host_src/eas_host.h; sourceTree = SOURCE_ROOT; }; + C55B112F0E2D33B4006357C1 /* eas_math.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = eas_math.h; path = ../../lib_src/eas_math.h; sourceTree = SOURCE_ROOT; }; + C55B11300E2D33B4006357C1 /* eas_midi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = eas_midi.h; path = ../../lib_src/eas_midi.h; sourceTree = SOURCE_ROOT; }; + C55B11310E2D33B4006357C1 /* eas_midictrl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = eas_midictrl.h; path = ../../lib_src/eas_midictrl.h; sourceTree = SOURCE_ROOT; }; + C55B11320E2D33B4006357C1 /* eas_mixer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eas_mixer.c; path = ../../lib_src/eas_mixer.c; sourceTree = SOURCE_ROOT; }; + C55B11330E2D33B4006357C1 /* eas_pan.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = eas_pan.h; path = ../../lib_src/eas_pan.h; sourceTree = SOURCE_ROOT; }; + C55B11340E2D33B4006357C1 /* eas_pcm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = eas_pcm.h; path = ../../lib_src/eas_pcm.h; sourceTree = SOURCE_ROOT; }; + C55B11350E2D33B4006357C1 /* eas_pcmdata.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = eas_pcmdata.h; path = ../../lib_src/eas_pcmdata.h; sourceTree = SOURCE_ROOT; }; + C55B11370E2D33B4006357C1 /* eas_report.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = eas_report.h; path = ../../host_src/eas_report.h; sourceTree = SOURCE_ROOT; }; + C55B11380E2D33B4006357C1 /* eas_sndlib.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = eas_sndlib.h; path = ../../lib_src/eas_sndlib.h; sourceTree = SOURCE_ROOT; }; + C55B11390E2D33B4006357C1 /* eas_synth.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = eas_synth.h; path = ../../lib_src/eas_synth.h; sourceTree = SOURCE_ROOT; }; + C55B113A0E2D33B4006357C1 /* eas_synth_protos.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = eas_synth_protos.h; path = ../../lib_src/eas_synth_protos.h; sourceTree = SOURCE_ROOT; }; + C55B113B0E2D33B4006357C1 /* eas_types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = eas_types.h; path = ../../host_src/eas_types.h; sourceTree = SOURCE_ROOT; }; + C55B113C0E2D33B4006357C1 /* eas_vm_protos.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = eas_vm_protos.h; path = ../../lib_src/eas_vm_protos.h; sourceTree = SOURCE_ROOT; }; + C55B11530E2D3796006357C1 /* eas_effects.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = eas_effects.h; path = ../../lib_src/eas_effects.h; sourceTree = SOURCE_ROOT; }; + C55B11620E2D37FC006357C1 /* eas_imelodydata.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = eas_imelodydata.h; path = ../../lib_src/eas_imelodydata.h; sourceTree = SOURCE_ROOT; }; + C55B116B0E2D38CE006357C1 /* eas_mdls.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = eas_mdls.h; path = ../../lib_src/eas_mdls.h; sourceTree = SOURCE_ROOT; }; + C55B116C0E2D38CE006357C1 /* eas_otadata.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = eas_otadata.h; path = ../../lib_src/eas_otadata.h; sourceTree = SOURCE_ROOT; }; + C55B116D0E2D38CE006357C1 /* eas_parser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = eas_parser.h; path = ../../lib_src/eas_parser.h; sourceTree = SOURCE_ROOT; }; + C55B116E0E2D38CE006357C1 /* eas_rtttldata.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = eas_rtttldata.h; path = ../../lib_src/eas_rtttldata.h; sourceTree = SOURCE_ROOT; }; + C55B11700E2D38CE006357C1 /* eas_smf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = eas_smf.h; path = ../../lib_src/eas_smf.h; sourceTree = SOURCE_ROOT; }; + C55B11710E2D38CE006357C1 /* eas_smfdata.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = eas_smfdata.h; path = ../../lib_src/eas_smfdata.h; sourceTree = SOURCE_ROOT; }; + C55B11720E2D38CE006357C1 /* eas_tcdata.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = eas_tcdata.h; path = ../../lib_src/eas_tcdata.h; sourceTree = SOURCE_ROOT; }; + C55B11730E2D38CE006357C1 /* eas_wavefile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = eas_wavefile.h; path = ../../lib_src/eas_wavefile.h; sourceTree = SOURCE_ROOT; }; + C55B11810E2D38FB006357C1 /* jet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = jet.h; path = ../../host_src/jet.h; sourceTree = SOURCE_ROOT; }; + C55B11820E2D38FB006357C1 /* jet_data.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = jet_data.h; path = ../../lib_src/jet_data.h; sourceTree = SOURCE_ROOT; }; + C55B11850E2D395F006357C1 /* eas_wtengine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = eas_wtengine.h; path = ../../lib_src/eas_wtengine.h; sourceTree = SOURCE_ROOT; }; + C55B118E0E2D39ED006357C1 /* eas_reverb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = eas_reverb.h; path = ../../host_src/eas_reverb.h; sourceTree = SOURCE_ROOT; }; + C55B118F0E2D39ED006357C1 /* eas_reverbdata.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = eas_reverbdata.h; path = ../../lib_src/eas_reverbdata.h; sourceTree = SOURCE_ROOT; }; + C55B11920E2D39FE006357C1 /* eas_chorus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = eas_chorus.h; path = ../../host_src/eas_chorus.h; sourceTree = SOURCE_ROOT; }; + C55B11930E2D39FE006357C1 /* eas_chorusdata.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = eas_chorusdata.h; path = ../../lib_src/eas_chorusdata.h; sourceTree = SOURCE_ROOT; }; + C55B119F0E2D3B1B006357C1 /* eas_data.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eas_data.c; path = ../../lib_src/eas_data.c; sourceTree = SOURCE_ROOT; }; + C55B11A00E2D3B1B006357C1 /* eas_flog.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eas_flog.c; path = ../../lib_src/eas_flog.c; sourceTree = SOURCE_ROOT; }; + C55B11A20E2D3B1B006357C1 /* eas_ima_tables.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eas_ima_tables.c; path = ../../lib_src/eas_ima_tables.c; sourceTree = SOURCE_ROOT; }; + C55B11A30E2D3B1B006357C1 /* eas_imaadpcm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eas_imaadpcm.c; path = ../../lib_src/eas_imaadpcm.c; sourceTree = SOURCE_ROOT; }; + C55B11A40E2D3B1B006357C1 /* eas_math.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eas_math.c; path = ../../lib_src/eas_math.c; sourceTree = SOURCE_ROOT; }; + C55B11A50E2D3B1B006357C1 /* eas_midi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eas_midi.c; path = ../../lib_src/eas_midi.c; sourceTree = SOURCE_ROOT; }; + C55B11A60E2D3B1B006357C1 /* eas_mididata.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eas_mididata.c; path = ../../lib_src/eas_mididata.c; sourceTree = SOURCE_ROOT; }; + C55B11A70E2D3B1B006357C1 /* eas_mixbuf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eas_mixbuf.c; path = ../../lib_src/eas_mixbuf.c; sourceTree = SOURCE_ROOT; }; + C55B11A80E2D3B1B006357C1 /* eas_pan.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eas_pan.c; path = ../../lib_src/eas_pan.c; sourceTree = SOURCE_ROOT; }; + C55B11A90E2D3B1B006357C1 /* eas_pcm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eas_pcm.c; path = ../../lib_src/eas_pcm.c; sourceTree = SOURCE_ROOT; }; + C55B11AA0E2D3B1B006357C1 /* eas_pcmdata.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eas_pcmdata.c; path = ../../lib_src/eas_pcmdata.c; sourceTree = SOURCE_ROOT; }; + C55B11AB0E2D3B1B006357C1 /* eas_public.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eas_public.c; path = ../../lib_src/eas_public.c; sourceTree = ""; }; + C55B11AC0E2D3B1B006357C1 /* eas_voicemgt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eas_voicemgt.c; path = ../../lib_src/eas_voicemgt.c; sourceTree = SOURCE_ROOT; }; + C55B11BC0E2D3B55006357C1 /* jet.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = jet.c; path = ../../lib_src/jet.c; sourceTree = SOURCE_ROOT; }; + C55B11C00E2D3BFD006357C1 /* eas_chorus.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eas_chorus.c; path = ../../lib_src/eas_chorus.c; sourceTree = SOURCE_ROOT; }; + C55B11D00E2D3C62006357C1 /* eas_imelody.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eas_imelody.c; path = ../../lib_src/eas_imelody.c; sourceTree = SOURCE_ROOT; }; + C55B11D10E2D3C62006357C1 /* eas_imelodydata.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eas_imelodydata.c; path = ../../lib_src/eas_imelodydata.c; sourceTree = SOURCE_ROOT; }; + C55B11D20E2D3C62006357C1 /* eas_mdls.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eas_mdls.c; path = ../../lib_src/eas_mdls.c; sourceTree = SOURCE_ROOT; }; + C55B11D30E2D3C62006357C1 /* eas_ota.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eas_ota.c; path = ../../lib_src/eas_ota.c; sourceTree = SOURCE_ROOT; }; + C55B11D40E2D3C62006357C1 /* eas_otadata.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eas_otadata.c; path = ../../lib_src/eas_otadata.c; sourceTree = SOURCE_ROOT; }; + C55B11D50E2D3C62006357C1 /* eas_rtttl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eas_rtttl.c; path = ../../lib_src/eas_rtttl.c; sourceTree = SOURCE_ROOT; }; + C55B11D60E2D3C62006357C1 /* eas_rtttldata.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eas_rtttldata.c; path = ../../lib_src/eas_rtttldata.c; sourceTree = SOURCE_ROOT; }; + C55B11DA0E2D3C62006357C1 /* eas_smf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eas_smf.c; path = ../../lib_src/eas_smf.c; sourceTree = SOURCE_ROOT; }; + C55B11DB0E2D3C62006357C1 /* eas_smfdata.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eas_smfdata.c; path = ../../lib_src/eas_smfdata.c; sourceTree = SOURCE_ROOT; }; + C55B11DC0E2D3C62006357C1 /* eas_tcdata.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eas_tcdata.c; path = ../../lib_src/eas_tcdata.c; sourceTree = SOURCE_ROOT; }; + C55B11DD0E2D3C62006357C1 /* eas_tonecontrol.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eas_tonecontrol.c; path = ../../lib_src/eas_tonecontrol.c; sourceTree = SOURCE_ROOT; }; + C55B11DE0E2D3C62006357C1 /* eas_wavefile.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eas_wavefile.c; path = ../../lib_src/eas_wavefile.c; sourceTree = SOURCE_ROOT; }; + C55B11DF0E2D3C62006357C1 /* eas_wavefiledata.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eas_wavefiledata.c; path = ../../lib_src/eas_wavefiledata.c; sourceTree = SOURCE_ROOT; }; + C55B11F60E2D3C7B006357C1 /* eas_reverb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eas_reverb.c; path = ../../lib_src/eas_reverb.c; sourceTree = SOURCE_ROOT; }; + C55B11F80E2D3CAC006357C1 /* eastestv37.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eastestv37.c; sourceTree = ""; }; + C55B12020E2D3D56006357C1 /* eas_dlssynth.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eas_dlssynth.c; path = ../../lib_src/eas_dlssynth.c; sourceTree = SOURCE_ROOT; }; + C55B12030E2D3D56006357C1 /* eas_wtengine.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eas_wtengine.c; path = ../../lib_src/eas_wtengine.c; sourceTree = SOURCE_ROOT; }; + C55B12040E2D3D56006357C1 /* eas_wtsynth.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eas_wtsynth.c; path = ../../lib_src/eas_wtsynth.c; sourceTree = SOURCE_ROOT; }; + D2AAC046055464E500DB518D /* libeaswt_vst_lib.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libeaswt_vst_lib.a; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + D289987405E68DCB004EDB86 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 08FB7794FE84155DC02AAC07 /* easwt_vst_lib */ = { + isa = PBXGroup; + children = ( + C55B11280E2D31B6006357C1 /* Header Files */, + 08FB7795FE84155DC02AAC07 /* Source */, + C6A0FF2B0290797F04C91782 /* Documentation */, + 1AB674ADFE9D54B511CA2CBB /* Products */, + ); + name = easwt_vst_lib; + sourceTree = ""; + }; + 08FB7795FE84155DC02AAC07 /* Source */ = { + isa = PBXGroup; + children = ( + C55B119F0E2D3B1B006357C1 /* eas_data.c */, + C55B11A00E2D3B1B006357C1 /* eas_flog.c */, + C55B11A20E2D3B1B006357C1 /* eas_ima_tables.c */, + C55B11A30E2D3B1B006357C1 /* eas_imaadpcm.c */, + C55B11A40E2D3B1B006357C1 /* eas_math.c */, + C55B11A50E2D3B1B006357C1 /* eas_midi.c */, + C55B11A60E2D3B1B006357C1 /* eas_mididata.c */, + C55B11A70E2D3B1B006357C1 /* eas_mixbuf.c */, + C55B11320E2D33B4006357C1 /* eas_mixer.c */, + C55B11A80E2D3B1B006357C1 /* eas_pan.c */, + C55B11A90E2D3B1B006357C1 /* eas_pcm.c */, + C55B11AA0E2D3B1B006357C1 /* eas_pcmdata.c */, + C55B11AB0E2D3B1B006357C1 /* eas_public.c */, + C55B11AC0E2D3B1B006357C1 /* eas_voicemgt.c */, + C55B11BC0E2D3B55006357C1 /* jet.c */, + C55B11960E2D3A56006357C1 /* Chorus */, + C55B119A0E2D3A7F006357C1 /* Parsers */, + C55B11970E2D3A5C006357C1 /* Reverb */, + C55B119B0E2D3A99006357C1 /* SoundLibs */, + C55B119D0E2D3AB6006357C1 /* Wavetable */, + ); + name = Source; + sourceTree = ""; + }; + 1AB674ADFE9D54B511CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + D2AAC046055464E500DB518D /* libeaswt_vst_lib.a */, + ); + name = Products; + sourceTree = ""; + }; + C55B11280E2D31B6006357C1 /* Header Files */ = { + isa = PBXGroup; + children = ( + 9A56AC040F71BCFE00D115A7 /* eas_build.h */, + 9A56ABCF0F71998600D115A7 /* eas_fmengine.h */, + C55B11880E2D39B0006357C1 /* Reverb */, + C55B11870E2D39A9006357C1 /* Chorus */, + C55B11850E2D395F006357C1 /* eas_wtengine.h */, + C55B11810E2D38FB006357C1 /* jet.h */, + C55B11820E2D38FB006357C1 /* jet_data.h */, + C55B116B0E2D38CE006357C1 /* eas_mdls.h */, + C55B116C0E2D38CE006357C1 /* eas_otadata.h */, + C55B116D0E2D38CE006357C1 /* eas_parser.h */, + C55B116E0E2D38CE006357C1 /* eas_rtttldata.h */, + C55B11700E2D38CE006357C1 /* eas_smf.h */, + C55B11710E2D38CE006357C1 /* eas_smfdata.h */, + C55B11720E2D38CE006357C1 /* eas_tcdata.h */, + C55B11730E2D38CE006357C1 /* eas_wavefile.h */, + C55B11620E2D37FC006357C1 /* eas_imelodydata.h */, + C55B11530E2D3796006357C1 /* eas_effects.h */, + C55B11290E2D33B4006357C1 /* eas.h */, + C55B112A0E2D33B4006357C1 /* eas_audioconst.h */, + C55B112C0E2D33B4006357C1 /* eas_config.h */, + C55B112D0E2D33B4006357C1 /* eas_data.h */, + C55B112E0E2D33B4006357C1 /* eas_host.h */, + C55B112F0E2D33B4006357C1 /* eas_math.h */, + C55B11300E2D33B4006357C1 /* eas_midi.h */, + C55B11310E2D33B4006357C1 /* eas_midictrl.h */, + C55B11330E2D33B4006357C1 /* eas_pan.h */, + C55B11340E2D33B4006357C1 /* eas_pcm.h */, + C55B11350E2D33B4006357C1 /* eas_pcmdata.h */, + C55B11370E2D33B4006357C1 /* eas_report.h */, + C55B11380E2D33B4006357C1 /* eas_sndlib.h */, + C55B11390E2D33B4006357C1 /* eas_synth.h */, + C55B113A0E2D33B4006357C1 /* eas_synth_protos.h */, + C55B113B0E2D33B4006357C1 /* eas_types.h */, + C55B113C0E2D33B4006357C1 /* eas_vm_protos.h */, + ); + name = "Header Files"; + sourceTree = ""; + }; + C55B11870E2D39A9006357C1 /* Chorus */ = { + isa = PBXGroup; + children = ( + C55B11920E2D39FE006357C1 /* eas_chorus.h */, + C55B11930E2D39FE006357C1 /* eas_chorusdata.h */, + ); + name = Chorus; + sourceTree = ""; + }; + C55B11880E2D39B0006357C1 /* Reverb */ = { + isa = PBXGroup; + children = ( + C55B118E0E2D39ED006357C1 /* eas_reverb.h */, + C55B118F0E2D39ED006357C1 /* eas_reverbdata.h */, + ); + name = Reverb; + sourceTree = ""; + }; + C55B11960E2D3A56006357C1 /* Chorus */ = { + isa = PBXGroup; + children = ( + C55B11C00E2D3BFD006357C1 /* eas_chorus.c */, + ); + name = Chorus; + sourceTree = ""; + }; + C55B11970E2D3A5C006357C1 /* Reverb */ = { + isa = PBXGroup; + children = ( + C55B11F60E2D3C7B006357C1 /* eas_reverb.c */, + ); + name = Reverb; + sourceTree = ""; + }; + C55B119A0E2D3A7F006357C1 /* Parsers */ = { + isa = PBXGroup; + children = ( + 9A56ABD70F719D4600D115A7 /* eas_xmf.c */, + 9A56ABD80F719D4600D115A7 /* eas_xmf.h */, + 9A56ABD90F719D4600D115A7 /* eas_xmfdata.c */, + 9A56ABDA0F719D4600D115A7 /* eas_xmfdata.h */, + C55B11D00E2D3C62006357C1 /* eas_imelody.c */, + C55B11D10E2D3C62006357C1 /* eas_imelodydata.c */, + C55B11D20E2D3C62006357C1 /* eas_mdls.c */, + C55B11D30E2D3C62006357C1 /* eas_ota.c */, + C55B11D40E2D3C62006357C1 /* eas_otadata.c */, + C55B11D50E2D3C62006357C1 /* eas_rtttl.c */, + C55B11D60E2D3C62006357C1 /* eas_rtttldata.c */, + C55B11DA0E2D3C62006357C1 /* eas_smf.c */, + C55B11DB0E2D3C62006357C1 /* eas_smfdata.c */, + C55B11DC0E2D3C62006357C1 /* eas_tcdata.c */, + C55B11DD0E2D3C62006357C1 /* eas_tonecontrol.c */, + C55B11DE0E2D3C62006357C1 /* eas_wavefile.c */, + C55B11DF0E2D3C62006357C1 /* eas_wavefiledata.c */, + ); + name = Parsers; + sourceTree = ""; + }; + C55B119B0E2D3A99006357C1 /* SoundLibs */ = { + isa = PBXGroup; + children = ( + 9A56AB8E0F7197AE00D115A7 /* wt_44khz.c */, + C55B11F80E2D3CAC006357C1 /* eastestv37.c */, + ); + name = SoundLibs; + sourceTree = ""; + }; + C55B119D0E2D3AB6006357C1 /* Wavetable */ = { + isa = PBXGroup; + children = ( + C55B12020E2D3D56006357C1 /* eas_dlssynth.c */, + C55B12030E2D3D56006357C1 /* eas_wtengine.c */, + C55B12040E2D3D56006357C1 /* eas_wtsynth.c */, + ); + name = Wavetable; + sourceTree = ""; + }; + C6A0FF2B0290797F04C91782 /* Documentation */ = { + isa = PBXGroup; + children = ( + ); + name = Documentation; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + D2AAC043055464E500DB518D /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + C55B113D0E2D33B4006357C1 /* eas.h in Headers */, + C55B113E0E2D33B4006357C1 /* eas_audioconst.h in Headers */, + C55B11400E2D33B4006357C1 /* eas_config.h in Headers */, + C55B11410E2D33B4006357C1 /* eas_data.h in Headers */, + C55B11420E2D33B4006357C1 /* eas_host.h in Headers */, + C55B11430E2D33B4006357C1 /* eas_math.h in Headers */, + C55B11440E2D33B4006357C1 /* eas_midi.h in Headers */, + C55B11450E2D33B4006357C1 /* eas_midictrl.h in Headers */, + C55B11470E2D33B4006357C1 /* eas_pan.h in Headers */, + C55B11480E2D33B4006357C1 /* eas_pcm.h in Headers */, + C55B11490E2D33B4006357C1 /* eas_pcmdata.h in Headers */, + C55B114B0E2D33B4006357C1 /* eas_report.h in Headers */, + C55B114C0E2D33B4006357C1 /* eas_sndlib.h in Headers */, + C55B114D0E2D33B4006357C1 /* eas_synth.h in Headers */, + C55B114E0E2D33B4006357C1 /* eas_synth_protos.h in Headers */, + C55B114F0E2D33B4006357C1 /* eas_types.h in Headers */, + C55B11500E2D33B4006357C1 /* eas_vm_protos.h in Headers */, + C55B115B0E2D3796006357C1 /* eas_effects.h in Headers */, + C55B11640E2D37FC006357C1 /* eas_imelodydata.h in Headers */, + C55B11760E2D38CE006357C1 /* eas_mdls.h in Headers */, + C55B11770E2D38CE006357C1 /* eas_otadata.h in Headers */, + C55B11780E2D38CE006357C1 /* eas_parser.h in Headers */, + C55B11790E2D38CE006357C1 /* eas_rtttldata.h in Headers */, + C55B117B0E2D38CE006357C1 /* eas_smf.h in Headers */, + C55B117C0E2D38CE006357C1 /* eas_smfdata.h in Headers */, + C55B117D0E2D38CE006357C1 /* eas_tcdata.h in Headers */, + C55B117E0E2D38CE006357C1 /* eas_wavefile.h in Headers */, + C55B11830E2D38FB006357C1 /* jet.h in Headers */, + C55B11840E2D38FB006357C1 /* jet_data.h in Headers */, + C55B11860E2D395F006357C1 /* eas_wtengine.h in Headers */, + C55B11900E2D39ED006357C1 /* eas_reverb.h in Headers */, + C55B11910E2D39ED006357C1 /* eas_reverbdata.h in Headers */, + C55B11940E2D39FE006357C1 /* eas_chorus.h in Headers */, + C55B11950E2D39FE006357C1 /* eas_chorusdata.h in Headers */, + 9A56ABD00F71998600D115A7 /* eas_fmengine.h in Headers */, + 9A56ABDC0F719D4600D115A7 /* eas_xmf.h in Headers */, + 9A56ABDE0F719D4600D115A7 /* eas_xmfdata.h in Headers */, + 9A56AC050F71BCFE00D115A7 /* eas_build.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + D2AAC045055464E500DB518D /* easwt_vst_lib */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1DEB91EB08733DB70010E9CD /* Build configuration list for PBXNativeTarget "easwt_vst_lib" */; + buildPhases = ( + D2AAC043055464E500DB518D /* Headers */, + D2AAC044055464E500DB518D /* Sources */, + D289987405E68DCB004EDB86 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = easwt_vst_lib; + productName = easwt_vst_lib; + productReference = D2AAC046055464E500DB518D /* libeaswt_vst_lib.a */; + productType = "com.apple.product-type.library.static"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 08FB7793FE84155DC02AAC07 /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 1DEB91EF08733DB70010E9CD /* Build configuration list for PBXProject "easwt_vst_lib" */; + compatibilityVersion = "Xcode 3.0"; + hasScannedForEncodings = 1; + mainGroup = 08FB7794FE84155DC02AAC07 /* easwt_vst_lib */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + D2AAC045055464E500DB518D /* easwt_vst_lib */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + D2AAC044055464E500DB518D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + C55B11460E2D33B4006357C1 /* eas_mixer.c in Sources */, + C55B11AE0E2D3B1B006357C1 /* eas_data.c in Sources */, + C55B11AF0E2D3B1B006357C1 /* eas_flog.c in Sources */, + C55B11B10E2D3B1B006357C1 /* eas_ima_tables.c in Sources */, + C55B11B20E2D3B1B006357C1 /* eas_imaadpcm.c in Sources */, + C55B11B30E2D3B1B006357C1 /* eas_math.c in Sources */, + C55B11B40E2D3B1B006357C1 /* eas_midi.c in Sources */, + C55B11B50E2D3B1B006357C1 /* eas_mididata.c in Sources */, + C55B11B60E2D3B1B006357C1 /* eas_mixbuf.c in Sources */, + C55B11B70E2D3B1B006357C1 /* eas_pan.c in Sources */, + C55B11B80E2D3B1B006357C1 /* eas_pcm.c in Sources */, + C55B11B90E2D3B1B006357C1 /* eas_pcmdata.c in Sources */, + C55B11BA0E2D3B1B006357C1 /* eas_public.c in Sources */, + C55B11BB0E2D3B1B006357C1 /* eas_voicemgt.c in Sources */, + C55B11BD0E2D3B55006357C1 /* jet.c in Sources */, + C55B11C10E2D3BFD006357C1 /* eas_chorus.c in Sources */, + C55B11E40E2D3C62006357C1 /* eas_imelody.c in Sources */, + C55B11E50E2D3C62006357C1 /* eas_imelodydata.c in Sources */, + C55B11E60E2D3C62006357C1 /* eas_mdls.c in Sources */, + C55B11E70E2D3C62006357C1 /* eas_ota.c in Sources */, + C55B11E80E2D3C62006357C1 /* eas_otadata.c in Sources */, + C55B11E90E2D3C62006357C1 /* eas_rtttl.c in Sources */, + C55B11EA0E2D3C62006357C1 /* eas_rtttldata.c in Sources */, + C55B11EE0E2D3C62006357C1 /* eas_smf.c in Sources */, + C55B11EF0E2D3C62006357C1 /* eas_smfdata.c in Sources */, + C55B11F00E2D3C62006357C1 /* eas_tcdata.c in Sources */, + C55B11F10E2D3C62006357C1 /* eas_tonecontrol.c in Sources */, + C55B11F20E2D3C62006357C1 /* eas_wavefile.c in Sources */, + C55B11F30E2D3C62006357C1 /* eas_wavefiledata.c in Sources */, + C55B11F70E2D3C7B006357C1 /* eas_reverb.c in Sources */, + C55B11FA0E2D3CAC006357C1 /* eastestv37.c in Sources */, + C55B12050E2D3D56006357C1 /* eas_dlssynth.c in Sources */, + C55B12060E2D3D56006357C1 /* eas_wtengine.c in Sources */, + C55B12070E2D3D56006357C1 /* eas_wtsynth.c in Sources */, + 9A56AB8F0F7197AE00D115A7 /* wt_44khz.c in Sources */, + 9A56ABDB0F719D4600D115A7 /* eas_xmf.c in Sources */, + 9A56ABDD0F719D4600D115A7 /* eas_xmfdata.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 1DEB91EC08733DB70010E9CD /* 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; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG_JET=1", + "_DEBUG_SMAF=1", + "_DEBUG_CMF=1", + "JET_INTERFACE=1", + "MAX_SMF_STREAMS=32", + "NUM_OUTPUT_CHANNELS=2", + "_SAMPLE_RATE_44100=1", + "_8_BIT_SAMPLES=1", + "_FILTER_ENABLED=1", + "_NO_DEBUG_PREPROCESSOR=1", + "_CORE_CYCLES_PER_MEMORY_CYCLE=1", + "_IMA_DECODER=1", + "_XMF_PARSER=1", + "_DLS_PARSER=1", + "MAX_DLS_MEMORY=16777216", + "EAS_WT_SYNTH=1", + "MAX_SYNTH_VOICES=64", + "X_ENHANCER_ENABLED=1", + "_REVERB_ENABLED=1", + "_CHORUS_ENABLED=1", + "DLS_SYNTHESIZER=1", + "EXTERNAL_AUDIO=1", + "TEST_HARNESS=1", + "MMAPI_SUPPORT=1", + "X_MAXIMIZER_ENABLED=1", + "X_COMPRESSOR_ENABLED=1", + "X_STATS=1", + "X_DEBUG_DLS=1", + "X_OPTIMIZED_MONO=1", + "X_CHECKED_BUILD=1", + "_NO_ALIGN=1", + "_C_REFERENCE=1", + "XMAXIMIZER_USE_FLOATING_POINT=1", + ); + HEADER_SEARCH_PATHS = ( + "${TARGET_BUILD_DIR}/**", + "../../Common/**", + "../../Parsers/**", + "../../Effects/**", + "../../WTSynth/**", + "../../FMSynth/**", + "../../SplitArch/**", + "../../Jet/**", + ); + INSTALL_PATH = /usr/local/lib; + MACOSX_DEPLOYMENT_TARGET = 10.4; + PRODUCT_NAME = easwt_vst_lib; + ZERO_LINK = YES; + }; + name = Debug; + }; + 1DEB91ED08733DB70010E9CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = i386; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_AUTO_VECTORIZATION = YES; + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; + GCC_MODEL_TUNING = G5; + GCC_OPTIMIZATION_LEVEL = 3; + GCC_PREPROCESSOR_DEFINITIONS = ( + "JET_INTERFACE=1", + "MAX_SMF_STREAMS=32", + "NUM_OUTPUT_CHANNELS=2", + "_SAMPLE_RATE_44100=1", + "_8_BIT_SAMPLES=1", + "_FILTER_ENABLED=1", + "_NO_DEBUG_PREPROCESSOR=1", + "_CORE_CYCLES_PER_MEMORY_CYCLE=1", + "_IMA_DECODER=1", + "_XMF_PARSER=1", + "_DLS_PARSER=1", + "MAX_DLS_MEMORY=16777216", + "EAS_WT_SYNTH=1", + "MAX_SYNTH_VOICES=64", + "X_ENHANCER_ENABLED=1", + "_REVERB_ENABLED=1", + "_CHORUS_ENABLED=1", + "DLS_SYNTHESIZER=1", + "EXTERNAL_AUDIO=1", + "TEST_HARNESS=1", + "MMAPI_SUPPORT=1", + "X_MAXIMIZER_ENABLED=1", + "X_COMPRESSOR_ENABLED=1", + "X_STATS=1", + "X_DEBUG_DLS=1", + "X_OPTIMIZED_MONO=1", + "X_CHECKED_BUILD=1", + "_NO_ALIGN=1", + "_C_REFERENCE=1", + "XMAXIMIZER_USE_FLOATING_POINT=1", + ); + GCC_UNROLL_LOOPS = YES; + HEADER_SEARCH_PATHS = ( + "${TARGET_BUILD_DIR}/**", + "../../Common/**", + "../../Parsers/**", + "../../Effects/**", + "../../WTSynth/**", + "../../FMSynth/**", + "../../SplitArch/**", + "../../Jet/**", + ); + INSTALL_PATH = /usr/local/lib; + MACOSX_DEPLOYMENT_TARGET = 10.4; + PRODUCT_NAME = easwt_vst_lib; + }; + name = Release; + }; + 1DEB91F008733DB70010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + PREBINDING = NO; + SDKROOT = "$(DEVELOPER_SDK_DIR)/MacOSX10.5.sdk"; + }; + name = Debug; + }; + 1DEB91F108733DB70010E9CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = i386; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + PREBINDING = NO; + PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = NO; + SDKROOT = "$(DEVELOPER_SDK_DIR)/MacOSX10.5.sdk"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1DEB91EB08733DB70010E9CD /* Build configuration list for PBXNativeTarget "easwt_vst_lib" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB91EC08733DB70010E9CD /* Debug */, + 1DEB91ED08733DB70010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1DEB91EF08733DB70010E9CD /* Build configuration list for PBXProject "easwt_vst_lib" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB91F008733DB70010E9CD /* Debug */, + 1DEB91F108733DB70010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 08FB7793FE84155DC02AAC07 /* Project object */; +} diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/easwt_vst_lib.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/easwt_vst_lib.xcscheme b/common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/easwt_vst_lib.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/easwt_vst_lib.xcscheme new file mode 100755 index 0000000..dc2fe91 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/easwt_vst_lib.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/easwt_vst_lib.xcscheme @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/easwt_vst_lib.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/xcschememanagement.plist b/common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/easwt_vst_lib.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100755 index 0000000..98709ed --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/easwt_vst_lib.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,22 @@ + + + + + SchemeUserState + + easwt_vst_lib.xcscheme + + orderHint + 11 + + + SuppressBuildableAutocreation + + D2AAC045055464E500DB518D + + primary + + + + + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/easwt_vst_lib.xcodeproj/xcuserdata/ryan.gerleve.xcuserdatad/xcschemes/easwt_vst_lib.xcscheme b/common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/easwt_vst_lib.xcodeproj/xcuserdata/ryan.gerleve.xcuserdatad/xcschemes/easwt_vst_lib.xcscheme new file mode 100755 index 0000000..dc2fe91 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/easwt_vst_lib.xcodeproj/xcuserdata/ryan.gerleve.xcuserdatad/xcschemes/easwt_vst_lib.xcscheme @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/easwt_vst_lib.xcodeproj/xcuserdata/ryan.gerleve.xcuserdatad/xcschemes/xcschememanagement.plist b/common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/easwt_vst_lib.xcodeproj/xcuserdata/ryan.gerleve.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100755 index 0000000..101eeec --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/easwt_vst_lib.xcodeproj/xcuserdata/ryan.gerleve.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,22 @@ + + + + + SchemeUserState + + easwt_vst_lib.xcscheme + + orderHint + 3 + + + SuppressBuildableAutocreation + + D2AAC045055464E500DB518D + + primary + + + + + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/wt_44khz.c b/common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/wt_44khz.c new file mode 100755 index 0000000..53cd952 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/jetcreator_lib_src/darwin-x86/wt_44khz.c @@ -0,0 +1,14723 @@ +/*---------------------------------------------------------------------------- + * + * Filename: wt_44khz.c + * Purpose: Wavetable sound libary + * + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +#include "eas_sndlib.h" + +/*---------------------------------------------------------------------------- + * Articulations + *---------------------------------------------------------------------------- +*/ +const S_ARTICULATION eas_articulations[] = +{ + { /* articulation 0 */ + { 32767, 31730, 0, 31730 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 1 */ + { 32767, 29669, 0, 29669 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 2 */ + { 32767, 31605, 0, 31701 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 3 */ + { 32767, 29434, 0, 29434 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 4 */ + { 32767, 0, 32767, 32742 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 5 */ + { 32767, 26439, 0, 26439 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 6 */ + { 32767, 32322, 0, 32350 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 7 */ + { 32767, 32715, 32767, 32715 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 8 */ + { 32767, 0, 32767, 0 }, + { 32767, 951, 0, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 9 */ + { 32767, 32558, 0, 32558 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 10 */ + { 32767, 0, 32767, 23749 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, -1 + }, + { /* articulation 11 */ + { 32767, 32245, 0, 32245 }, + { 32767, 380, 0, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, -44 + }, + { /* articulation 12 */ + { 32767, 27897, 0, 27897 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, 56 + }, + { /* articulation 13 */ + { 32767, 32245, 0, 32245 }, + { 32767, 380, 0, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, -31 + }, + { /* articulation 14 */ + { 4755, 26439, 0, 26439 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, 56 + }, + { /* articulation 15 */ + { 32767, 32187, 0, 32187 }, + { 32767, 380, 0, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, -6 + }, + { /* articulation 16 */ + { 32767, 32444, 0, 32480 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, 56 + }, + { /* articulation 17 */ + { 32767, 32153, 0, 32153 }, + { 32767, 380, 0, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, 6 + }, + { /* articulation 18 */ + { 32767, 32072, 0, 32072 }, + { 32767, 476, 0, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, 31 + }, + { /* articulation 19 */ + { 32767, 32363, 0, 32363 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, 25 + }, + { /* articulation 20 */ + { 32767, 31901, 0, 31901 }, + { 32767, 476, 0, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, 63 + }, + { /* articulation 21 */ + { 32767, 32528, 0, 32518 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, -37 + }, + { /* articulation 22 */ + { 9511, 32322, 0, 32337 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, -37 + }, + { /* articulation 23 */ + { 32767, 32376, 0, 32398 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, -37 + }, + { /* articulation 24 */ + { 32767, 0, 32767, 32715 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, 12 + }, + { /* articulation 25 */ + { 32767, 32052, 0, 32052 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, -25 + }, + { /* articulation 26 */ + { 32767, 0, 32767, 32715 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, 25 + }, + { /* articulation 27 */ + { 32767, 32289, 0, 32271 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, -25 + }, + { /* articulation 28 */ + { 32767, 31730, 0, 31730 }, + { 32767, 48, 0, 0 }, + 0, 0, 476, 240, 0, 0, 0, 0, -56 + }, + { /* articulation 29 */ + { 32767, 32498, 0, 32492 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, -37 + }, + { /* articulation 30 */ + { 32767, 29434, 0, 29434 }, + { 32767, 1902, 0, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, 50 + }, + { /* articulation 31 */ + { 32767, 27897, 0, 27897 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, -50 + }, + { /* articulation 32 */ + { 32767, 31056, 0, 31056 }, + { 32767, 1902, 0, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, -50 + }, + { /* articulation 33 */ + { 32767, 31479, 0, 31476 }, + { 32767, 1902, 0, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, -44 + }, + { /* articulation 34 */ + { 32767, 32663, 0, 32663 }, + { 32767, 127, 0, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, 25 + }, + { /* articulation 35 */ + { 32767, 0, 32767, 32715 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, -63 + }, + { /* articulation 36 */ + { 1902, 27897, 0, 27897 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, -63 + }, + { /* articulation 37 */ + { 32767, 27897, 0, 27897 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, -59 + }, + { /* articulation 38 */ + { 32767, 31730, 0, 31730 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, 50 + }, + { /* articulation 39 */ + { 32767, 30725, 0, 30725 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, 44 + }, + { /* articulation 40 */ + { 951, 31730, 0, 31730 }, + { 32767, 190, 0, 0 }, + 0, 0, 476, -100, 0, 0, 0, 0, 44 + }, + { /* articulation 41 */ + { 32767, 17213, 0, 17213 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, 25 + }, + { /* articulation 42 */ + { 32767, 31295, 0, 31295 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, 63 + }, + { /* articulation 43 */ + { 32767, 31479, 0, 31476 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, 63 + }, + { /* articulation 44 */ + { 9511, 25581, 0, 25581 }, + { 476, 32767, 32767, 0 }, + 0, 0, 476, 100, 0, 0, 0, 0, -25 + }, + { /* articulation 45 */ + { 1902, 23749, 0, 23749 }, + { 476, 32767, 32767, 0 }, + 0, 0, 476, 500, 0, 0, 0, 0, -25 + }, + { /* articulation 46 */ + { 32767, 23749, 0, 23749 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, -56 + }, + { /* articulation 47 */ + { 32767, 31730, 0, 31730 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, -56 + }, + { /* articulation 48 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 49 */ + { 32767, 31964, 0, 31964 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 50 */ + { 9511, 32363, 0, 32418 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 51 */ + { 32767, 31180, 0, 31180 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 52 */ + { 32767, 32251, 0, 32052 }, + { 32767, 147, 0, 0 }, + 0, 0, 476, 0, 10000, 7121, 0, 0, 0 + }, + { /* articulation 53 */ + { 32767, 0, 32767, 32072 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 778, 0, -2300, 11920, 0, 0, 0 + }, + { /* articulation 54 */ + { 587, 0, 32767, 32376 }, + { 32767, 63, 0, 0 }, + 0, 0, 778, 0, 2000, 10721, 0, 8, 15 + }, + { /* articulation 55 */ + { 587, 0, 32767, 32376 }, + { 476, 63, 0, 0 }, + 0, 0, 778, 0, 2000, 9023, 0, 5, 15 + }, + { /* articulation 56 */ + { 3804, 0, 32767, 31477 }, + { 32767, 34, 5898, 0 }, + 0, 0, 778, 0, 6000, 9080, 0, 0, -2 + }, + { /* articulation 57 */ + { 32767, 0, 32767, 31005 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 778, 0, 0, 0, 0, 0, 1 + }, + { /* articulation 58 */ + { 2570, 0, 32767, 31455 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 778, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 59 */ + { 32767, 32663, 0, 29434 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 60 */ + { 32767, 32558, 0, 29434 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 61 */ + { 32767, 32418, 0, 32418 }, + { 32767, 48, 0, 0 }, + 0, 69, 495, 0, 2400, 9521, 0, 0, 0 + }, + { /* articulation 62 */ + { 32767, 31476, 0, 31476 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 476, 0, 0, 11738, 0, 16, 0 + }, + { /* articulation 63 */ + { 32767, 32558, 0, 31391 }, + { 32767, 317, 0, 0 }, + 0, 69, 476, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 64 */ + { 32767, 32245, 0, 32115 }, + { 32767, 317, 0, 0 }, + 0, 69, 476, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 65 */ + { 32767, 32593, 0, 28809 }, + { 32767, 48, 0, 0 }, + 0, 69, 495, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 66 */ + { 32767, 32408, 0, 32363 }, + { 32767, 317, 0, 0 }, + 0, 69, 476, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 67 */ + { 32767, 32350, 0, 32350 }, + { 32767, 317, 0, 0 }, + 0, 69, 476, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 68 */ + { 4755, 32715, 18820, 27897 }, + { 951, 29, 13107, 0 }, + 0, 0, 495, 0, 6000, 5535, 0, 4, 0 + }, + { /* articulation 69 */ + { 32767, 32257, 0, 32245 }, + { 32767, 951, 0, 0 }, + 0, 103, 495, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 70 */ + { 63, 32727, 3811, 32558 }, + { 48, 19, 32767, 0 }, + 0, 0, 495, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 71 */ + { 2378, 32715, 3566, 30725 }, + { 1902, 32767, 32767, 0 }, + 0, 0, 495, 100, 0, 11919, 0, 0, 0 + }, + { /* articulation 72 */ + { 32767, 32349, 0, 32349 }, + { 32767, 168, 0, 0 }, + 0, 34, 495, 0, 7000, 9023, 0, 0, 0 + }, + { /* articulation 73 */ + { 32767, 32072, 0, 32072 }, + { 32767, 168, 0, 0 }, + 0, 3, 476, 0, 7000, 9023, 0, 0, 0 + }, + { /* articulation 74 */ + { 32767, 32698, 6208, 32349 }, + { 190, 48, 0, 0 }, + 0, 0, 495, 0, 3840, 8302, 0, 8, 0 + }, + { /* articulation 75 */ + { 32767, 32418, 0, 32468 }, + { 32767, 190, 0, 0 }, + 0, 0, 495, 0, 5000, 8321, 0, 0, 0 + }, + { /* articulation 76 */ + { 32767, 32349, 0, 32349 }, + { 32767, 190, 0, 0 }, + 0, 0, 476, 0, 5000, 7934, 0, 0, 0 + }, + { /* articulation 77 */ + { 32767, 32441, 0, 31709 }, + { 32767, 32, 0, 0 }, + 0, 34, 495, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 78 */ + { 32767, 32505, 0, 27897 }, + { 32767, 951, 0, 0 }, + 0, 345, 495, 0, 1000, 11107, 0, 0, 0 + }, + { /* articulation 79 */ + { 32767, 32715, 6208, 32349 }, + { 48, 48, 0, 0 }, + 0, 69, 811, 0, 3560, 8834, 1, 8, 0 + }, + { /* articulation 80 */ + { 32767, 32564, 0, 29434 }, + { 32767, 95, 0, 0 }, + 0, 34, 495, 0, 6000, 9907, 0, 0, 0 + }, + { /* articulation 81 */ + { 32767, 32505, 0, 27897 }, + { 32767, 32, 0, 0 }, + 0, 34, 495, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 82 */ + { 32767, 32245, 18820, 17213 }, + { 32767, 32767, 32767, 0 }, + 0, 34, 495, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 83 */ + { 32767, 32742, 128, 32466 }, + { 32767, 63, 0, 0 }, + 0, 0, 495, 0, 0, 11920, 0, 8, 0 + }, + { /* articulation 84 */ + { 32767, 32418, 0, 32418 }, + { 32767, 33, 0, 0 }, + 3, 0, 286, 0, 5000, 5535, 0, 0, 0 + }, + { /* articulation 85 */ + { 1902, 32715, 18820, 27897 }, + { 32767, 1012, 0, 0 }, + 10, 69, 504, -30, 0, 0, 0, 0, 0 + }, + { /* articulation 86 */ + { 9511, 32715, 18820, 27897 }, + { 380, 48, 0, 0 }, + 0, 69, 495, 0, 4473, 7131, 0, 8, 0 + }, + { /* articulation 87 */ + { 951, 32698, 6208, 32468 }, + { 317, 19, 16384, 0 }, + 0, 0, 495, 0, 2987, 7877, 0, 12, 0 + }, + { /* articulation 88 */ + { 32767, 32680, 0, 32349 }, + { 32767, 48, 0, 0 }, + 0, 0, 581, 0, 4053, 7930, 2, 12, 0 + }, + { /* articulation 89 */ + { 190, 32726, 6208, 32349 }, + { 32767, 56, 0, 0 }, + 0, 0, 495, 0, 0, 8887, 0, 0, 0 + }, + { /* articulation 90 */ + { 9511, 32715, 18820, 27897 }, + { 634, 48, 0, 0 }, + 0, 69, 495, 0, 5113, 7981, 0, 4, 0 + }, + { /* articulation 91 */ + { 951, 32715, 6208, 31730 }, + { 951, 63, 0, 0 }, + 0, 69, 495, 0, 3500, 7877, 0, 5, 0 + }, + { /* articulation 92 */ + { 951, 32715, 6208, 31730 }, + { 634, 48, 0, 0 }, + 0, 69, 476, 0, 4773, 8355, 0, 5, 0 + }, + { /* articulation 93 */ + { 238, 32715, 10809, 32349 }, + { 32767, 32767, 32767, 0 }, + 0, 69, 495, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 94 */ + { 1902, 32715, 18820, 31476 }, + { 32767, 32767, 32767, 0 }, + 0, 69, 495, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 95 */ + { 3804, 32715, 18820, 23749 }, + { 1268, 130, 0, 0 }, + 0, 69, 495, 0, 1200, 11690, 0, 4, 0 + }, + { /* articulation 96 */ + { 19021, 32618, 15076, 31476 }, + { 32767, 32767, 32767, 0 }, + 0, 72, 1091, 0, 0, 11919, 1, 0, 0 + }, + { /* articulation 97 */ + { 32767, 0, 32767, 32715 }, + { 190, 32767, 32767, 0 }, + 0, 0, 495, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 98 */ + { 32767, 32072, 0, 32072 }, + { 32767, 317, 0, 0 }, + 0, 0, 495, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 99 */ + { 32767, 32663, 0, 27897 }, + { 634, 95, 13107, 0 }, + 0, 69, 495, 0, 3200, 8321, 0, 0, 0 + }, + { /* articulation 100 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 495, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 101 */ + { 32767, 32418, 0, 27897 }, + { 32767, 543, 0, 0 }, + 0, 69, 495, 0, 8187, 5535, 0, 5, 0 + }, + { /* articulation 102 */ + { 19021, 32663, 0, 31056 }, + { 32767, 95, 7667, 0 }, + 5, 0, 495, 0, 6053, 5535, 0, 5, 0 + }, + { /* articulation 103 */ + { 32767, 32715, 18820, 27897 }, + { 951, 48, 0, 0 }, + 0, 0, 495, 0, 2700, 9852, 0, 0, 0 + }, + { /* articulation 104 */ + { 32767, 32715, 18820, 30234 }, + { 951, 48, 0, 0 }, + 0, 0, 495, 0, 2700, 9852, 0, 0, 0 + }, + { /* articulation 105 */ + { 32767, 32715, 18820, 27897 }, + { 32767, 634, 0, 0 }, + 0, 103, 476, 0, 2500, 10490, 1, 8, 0 + }, + { /* articulation 106 */ + { 32767, 32715, 23493, 27897 }, + { 32767, 190, 0, 0 }, + 0, 69, 494, 0, 4000, 10223, 1, 4, 0 + }, + { /* articulation 107 */ + { 32767, 32715, 18820, 30234 }, + { 32767, 63, 7667, 0 }, + 0, 0, 495, 0, 1813, 9154, 0, 0, 0 + }, + { /* articulation 108 */ + { 19021, 32245, 0, 32245 }, + { 32767, 190, 0, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 109 */ + { 32767, 31964, 0, 31605 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 476, 0, 0, 11690, 0, 0, 0 + }, + { /* articulation 110 */ + { 32767, 31730, 0, 31730 }, + { 32767, 190, 0, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 111 */ + { 32767, 32558, 18820, 30234 }, + { 32767, 48, 0, 0 }, + 12, 69, 476, 0, 3000, 10223, 0, 0, 0 + }, + { /* articulation 112 */ + { 32767, 32558, 18820, 30234 }, + { 32767, 32, 0, 0 }, + 12, 69, 476, 0, 1900, 10031, 0, 0, 0 + }, + { /* articulation 113 */ + { 32767, 32715, 18820, 29434 }, + { 32767, 32, 0, 0 }, + 12, 69, 494, 0, 1000, 11107, 0, 0, 0 + }, + { /* articulation 114 */ + { 32767, 32715, 18820, 29434 }, + { 32767, 32, 0, 0 }, + 12, 69, 494, 0, 2000, 11107, 0, 0, 0 + }, + { /* articulation 115 */ + { 32767, 32636, 0, 29434 }, + { 32767, 95, 0, 0 }, + 0, 34, 495, 0, 4000, 8321, 0, 0, 0 + }, + { /* articulation 116 */ + { 32767, 32297, 19893, 17213 }, + { 32767, 238, 0, 0 }, + 0, 69, 726, 0, 0, 11919, 0, 0, 0 + }, + { /* articulation 117 */ + { 9511, 32418, 23493, 17213 }, + { 32767, 32767, 32767, 0 }, + 0, 69, 678, 0, 0, 11877, 1, 0, 0 + }, + { /* articulation 118 */ + { 32767, 32618, 0, 27897 }, + { 32767, 95, 0, 0 }, + 0, 69, 495, 0, 3500, 9023, 0, 0, 0 + }, + { /* articulation 119 */ + { 32767, 23749, 23493, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 34, 761, 0, 0, 10925, 1, 0, 0 + }, + { /* articulation 120 */ + { 32767, 32636, 0, 29434 }, + { 32767, 95, 0, 0 }, + 0, 103, 495, 0, 3200, 8721, 0, 4, 0 + }, + { /* articulation 121 */ + { 1902, 32715, 18820, 27897 }, + { 32767, 32767, 32767, 0 }, + 0, 69, 495, 0, 0, 0, 1, 0, 0 + }, + { /* articulation 122 */ + { 4755, 32715, 18820, 28809 }, + { 32767, 32767, 32767, 0 }, + 0, 69, 495, 0, 0, 11877, 0, 8, 0 + }, + { /* articulation 123 */ + { 32767, 32715, 18820, 27897 }, + { 32767, 16, 0, 0 }, + 0, 34, 495, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 124 */ + { 32767, 32663, 0, 27897 }, + { 32767, 190, 0, 0 }, + 0, 69, 495, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 125 */ + { 32767, 32715, 18820, 27897 }, + { 32767, 12, 0, 0 }, + 0, 34, 495, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 126 */ + { 32767, 31730, 0, 31730 }, + { 32767, 380, 0, 0 }, + 0, 0, 495, 0, 3000, 10223, 0, 8, 0 + }, + { /* articulation 127 */ + { 63, 0, 32767, 32558 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 761, 0, 0, 11423, 4, 0, 0 + }, + { /* articulation 128 */ + { 476, 32595, 0, 32577 }, + { 32767, 10, 0, 0 }, + 0, 0, 495, 0, 0, 11423, 0, 0, 0 + }, + { /* articulation 129 */ + { 196, 0, 0, 31964 }, + { 95, 32767, 32767, 0 }, + 0, 0, 495, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 130 */ + { 32767, 31730, 0, 31730 }, + { 32767, 380, 0, 0 }, + 0, 0, 495, 1200, 0, 0, 0, 0, 0 + }, + { /* articulation 131 */ + { 32767, 32245, 0, 32349 }, + { 32767, 190, 0, 0 }, + 0, 0, 495, 50, 0, 0, 0, 0, 0 + }, + { /* articulation 132 */ + { 32767, 32418, 0, 32418 }, + { 32767, 9511, 0, 0 }, + 0, 0, 495, 0, 4700, 7769, 0, 0, 0 + }, + { /* articulation 133 */ + { 32767, 31391, 0, 31391 }, + { 32767, 19021, 0, 0 }, + 0, 0, 495, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 134 */ + { 32767, 32663, 32767, 32663 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 476, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 135 */ + { 32767, 32715, 18820, 23749 }, + { 32767, 95, 0, 0 }, + 10, 68, 476, 0, 2000, 10696, 0, 0, 0 + }, + { /* articulation 136 */ + { 32767, 32715, 10809, 23749 }, + { 32767, 95, 0, 0 }, + 12, 69, 491, 0, 0, 10910, 0, 0, 0 + }, + { /* articulation 137 */ + { 32767, 32715, 18820, 23749 }, + { 32767, 95, 0, 0 }, + 10, 69, 476, 0, 1200, 10218, 0, 0, 0 + }, + { /* articulation 138 */ + { 19021, 32715, 18820, 23749 }, + { 32767, 95, 0, 0 }, + 10, 69, 476, 0, 1100, 9525, 0, 0, 0 + }, + { /* articulation 139 */ + { 9511, 32663, 18820, 27897 }, + { 32767, 10, 0, 0 }, + 10, 69, 494, 0, 2000, 10962, 0, 0, 0 + }, + { /* articulation 140 */ + { 32767, 32558, 18820, 27897 }, + { 9511, 317, 0, 0 }, + 10, 63, 504, 0, 1200, 10090, 0, 0, 0 + }, + { /* articulation 141 */ + { 1268, 0, 32767, 30234 }, + { 951, 190, 0, 0 }, + 7, 69, 494, 0, 1620, 8933, 0, 0, 0 + }, + { /* articulation 142 */ + { 32767, 32558, 10809, 27897 }, + { 19021, 190, 0, 0 }, + 7, 69, 494, 0, 2200, 8994, 0, 0, 0 + }, + { /* articulation 143 */ + { 32767, 32715, 15076, 27897 }, + { 32767, 951, 0, 0 }, + 10, 69, 491, 0, 2500, 9525, 0, 0, 0 + }, + { /* articulation 144 */ + { 32767, 32715, 15076, 27897 }, + { 32767, 95, 0, 0 }, + 10, 69, 476, 0, 1500, 11423, 0, 0, 0 + }, + { /* articulation 145 */ + { 32767, 32715, 18820, 27897 }, + { 32767, 951, 0, 0 }, + 9, 69, 491, 0, 1500, 9521, 0, 0, 0 + }, + { /* articulation 146 */ + { 1902, 0, 32767, 30725 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 761, 0, 0, 9521, 0, 0, 0 + }, + { /* articulation 147 */ + { 32767, 32663, 0, 27897 }, + { 32767, 9511, 0, 0 }, + 0, 34, 495, 0, 5000, 10223, 0, 0, 0 + }, + { /* articulation 148 */ + { 32767, 32715, 18820, 27897 }, + { 32767, 32, 0, 0 }, + 10, 69, 476, 0, 1500, 9907, 0, 0, 0 + }, + { /* articulation 149 */ + { 32767, 32733, 11682, 27897 }, + { 32767, 951, 0, 0 }, + 0, 69, 476, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 150 */ + { 32767, 32418, 0, 32418 }, + { 32767, 190, 0, 0 }, + 0, 34, 495, 0, 3440, 9260, 0, 0, 0 + }, + { /* articulation 151 */ + { 32767, 31476, 0, 31730 }, + { 32767, 951, 0, 0 }, + 0, 34, 495, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 152 */ + { 32767, 32245, 0, 31730 }, + { 32767, 190, 0, 0 }, + 0, 34, 495, 0, 4000, 7823, 0, 0, 0 + }, + { /* articulation 153 */ + { 32767, 32663, 3566, 27897 }, + { 391, 32767, 32767, 0 }, + 100, 0, 761, 500, 0, 11877, 0, 0, 0 + }, + { /* articulation 154 */ + { 32767, 32715, 18820, 23749 }, + { 32767, 951, 0, 0 }, + 8, 69, 495, -22, 0, 0, 0, 0, 0 + }, + { /* articulation 155 */ + { 9511, 30830, 6784, 27897 }, + { 32767, 951, 0, 0 }, + 0, 69, 476, 0, 5000, 9521, 1, 0, 0 + }, + { /* articulation 156 */ + { 32767, 32663, 0, 32349 }, + { 951, 127, 16384, 0 }, + 0, 103, 495, 0, 3627, 10547, 0, 5, 0 + }, + { /* articulation 157 */ + { 1902, 0, 32767, 27897 }, + { 951, 951, 0, 0 }, + 0, 69, 495, 27, 0, 11919, 0, 0, 0 + }, + { /* articulation 158 */ + { 32767, 0, 32767, 32245 }, + { 38, 33, 10092, 0 }, + 5, 0, 495, 0, 8007, 5535, 0, 8, 0 + }, + { /* articulation 159 */ + { 32767, 32618, 0, 31056 }, + { 32767, 63, 0, 0 }, + 0, 103, 495, 0, 2500, 9032, 0, 0, 0 + }, + { /* articulation 160 */ + { 4755, 32715, 10809, 28809 }, + { 32767, 32767, 32767, 0 }, + 0, 69, 495, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 161 */ + { 9511, 32663, 18820, 27897 }, + { 32767, 95, 0, 0 }, + 10, 69, 494, 0, 2600, 9513, 0, 0, 0 + }, + { /* articulation 162 */ + { 32767, 32435, 9568, 27897 }, + { 1174, 196, 0, 0 }, + 10, 103, 490, 0, 6500, 9023, 0, 0, 0 + }, + { /* articulation 163 */ + { 32767, 32663, 0, 29434 }, + { 32767, 32, 0, 0 }, + 0, 69, 495, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 164 */ + { 32767, 32418, 15076, 23749 }, + { 32767, 634, 0, 0 }, + 0, 0, 476, 0, 2000, 10223, 0, 0, 0 + }, + { /* articulation 165 */ + { 32767, 32663, 0, 27897 }, + { 32767, 190, 0, 0 }, + 0, 69, 495, 0, 3000, 9366, 0, 0, 0 + }, + { /* articulation 166 */ + { 32767, 32715, 18820, 27897 }, + { 951, 64, 10879, 0 }, + 0, 0, 495, 0, 6000, 7121, 0, 4, 0 + }, + { /* articulation 167 */ + { 32767, 32636, 0, 29434 }, + { 32767, 10, 0, 0 }, + 0, 103, 495, 0, 3500, 6236, 0, 5, 0 + }, + { /* articulation 168 */ + { 32767, 32636, 0, 29434 }, + { 32767, 95, 0, 0 }, + 0, 103, 495, 0, 2800, 7121, 0, 0, 0 + }, + { /* articulation 169 */ + { 32767, 32593, 0, 31056 }, + { 32767, 63, 0, 0 }, + 0, 103, 495, 0, 2100, 9626, 0, 0, 0 + }, + { /* articulation 170 */ + { 32767, 32558, 0, 31476 }, + { 32767, 63, 0, 0 }, + 0, 103, 495, 0, 3000, 9626, 0, 0, 0 + }, + { /* articulation 171 */ + { 32767, 32527, 0, 30506 }, + { 32767, 63, 0, 0 }, + 0, 103, 495, 0, 1000, 9032, 0, 0, 0 + }, + { /* articulation 172 */ + { 32767, 32418, 0, 30725 }, + { 32767, 63, 0, 0 }, + 0, 103, 495, 0, 1000, 9032, 0, 0, 0 + }, + { /* articulation 173 */ + { 1902, 32418, 15076, 23749 }, + { 32767, 634, 0, 0 }, + 0, 103, 496, 0, 0, 11107, 0, 8, 0 + }, + { /* articulation 174 */ + { 32767, 32558, 15076, 27897 }, + { 3804, 73, 0, 0 }, + 0, 0, 495, 0, 4500, 9521, 0, 8, 0 + }, + { /* articulation 175 */ + { 32767, 32715, 18820, 27897 }, + { 32767, 48, 0, 0 }, + 0, 0, 495, 0, 2000, 8321, 0, 8, 0 + }, + { /* articulation 176 */ + { 32767, 32742, 128, 31180 }, + { 32767, 865, 0, 0 }, + 0, 0, 495, 0, 6000, 7823, 0, 8, 0 + }, + { /* articulation 177 */ + { 9511, 32608, 0, 32322 }, + { 32767, 48, 0, 0 }, + 0, 0, 495, 0, 4500, 7121, 0, 8, 0 + }, + { /* articulation 178 */ + { 19021, 32664, 3646, 32436 }, + { 32767, 95, 0, 0 }, + 0, 0, 495, 0, 4000, 8321, 0, 8, 0 + }, + { /* articulation 179 */ + { 32767, 32685, 13644, 29434 }, + { 32767, 32, 0, 0 }, + 12, 69, 494, 0, 2000, 11107, 0, 0, 0 + }, + { /* articulation 180 */ + { 9511, 31605, 0, 27897 }, + { 32767, 951, 0, 0 }, + 0, 0, 495, 0, 5000, 8321, 1, 0, 0 + }, + { /* articulation 181 */ + { 130, 32617, 0, 32350 }, + { 32767, 317, 0, 0 }, + 0, 69, 476, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 182 */ + { 32767, 32593, 0, 32251 }, + { 1174, 20, 0, 0 }, + 0, 69, 495, 0, 3600, 7121, 0, 4, 0 + }, + { /* articulation 183 */ + { 32767, 32427, 0, 32427 }, + { 32767, 317, 0, 0 }, + 0, 69, 476, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 184 */ + { 834, 32742, 19242, 31455 }, + { 32767, 148, 0, 0 }, + 0, 0, 778, 0, 3000, 9907, 0, 4, 0 + } +}; /*end Articulations */ + +/*---------------------------------------------------------------------------- + * Regions + *---------------------------------------------------------------------------- +*/ +const S_WT_REGION eas_regions[] = +{ + { { 0, 27, 27 }, -4068, 16422, 0, 0, 81, 0 }, /* region 0 */ + { { 0, 28, 28 }, -4768, 32767, 0, 0, 40, 0 }, /* region 1 */ + { { 0, 29, 29 }, -5753, 32767, 0, 0, 32, 1 }, /* region 2 */ + { { 0, 30, 30 }, -6053, 32767, 0, 0, 32, 2 }, /* region 3 */ + { { 0, 31, 31 }, -5068, 23197, 0, 0, 48, 3 }, /* region 4 */ + { { 1536, 32, 32 }, -4400, 20675, 0, 0, 137, 4 }, /* region 5 */ + { { 1537, 33, 33 }, -4903, 20675, 792, 879, 50, 5 }, /* region 6 */ + { { 1537, 34, 34 }, -5003, 16422, 792, 879, 50, 6 }, /* region 7 */ + { { 0, 35, 35 }, -6168, 32767, 0, 0, 83, 7 }, /* region 8 */ + { { 0, 36, 36 }, -6168, 32767, 0, 0, 83, 7 }, /* region 9 */ + { { 0, 37, 37 }, -5251, 18426, 0, 0, 53, 8 }, /* region 10 */ + { { 0, 38, 38 }, -5351, 23197, 0, 0, 16, 9 }, /* region 11 */ + { { 0, 39, 39 }, -4768, 32767, 0, 0, 40, 10 }, /* region 12 */ + { { 0, 40, 40 }, -5351, 23197, 0, 0, 16, 4 }, /* region 13 */ + { { 1, 41, 41 }, -7055, 26028, 798, 993, 45, 11 }, /* region 14 */ + { { 257, 42, 42 }, -5400, 26028, 4288, 7488, 7, 12 }, /* region 15 */ + { { 1, 43, 43 }, -6955, 26028, 798, 993, 45, 13 }, /* region 16 */ + { { 257, 44, 44 }, -5600, 26028, 4288, 7488, 7, 14 }, /* region 17 */ + { { 1, 45, 45 }, -6955, 26028, 798, 993, 45, 15 }, /* region 18 */ + { { 257, 46, 46 }, -5800, 26028, 4288, 7488, 7, 16 }, /* region 19 */ + { { 1, 47, 47 }, -6655, 26028, 798, 993, 45, 17 }, /* region 20 */ + { { 1, 48, 48 }, -6555, 26028, 798, 993, 45, 18 }, /* region 21 */ + { { 1, 49, 49 }, -6400, 16422, 1294, 5778, 8, 19 }, /* region 22 */ + { { 1, 50, 50 }, -6455, 26028, 798, 993, 45, 20 }, /* region 23 */ + { { 1, 51, 51 }, -6468, 16422, 6592, 9921, 6, 21 }, /* region 24 */ + { { 1, 52, 52 }, -6800, 32767, 1294, 5778, 8, 22 }, /* region 25 */ + { { 1, 53, 53 }, -6618, 14636, 6592, 9921, 6, 23 }, /* region 26 */ + { { 0, 54, 54 }, -6951, 26028, 0, 0, 39, 24 }, /* region 27 */ + { { 1, 55, 55 }, -6500, 32767, 1294, 5778, 8, 25 }, /* region 28 */ + { { 0, 56, 56 }, -8455, 32767, 0, 0, 90, 26 }, /* region 29 */ + { { 1, 57, 57 }, -6900, 32767, 1294, 5778, 8, 27 }, /* region 30 */ + { { 1, 58, 58 }, -8253, 23197, 0, 166, 113, 28 }, /* region 31 */ + { { 1, 59, 59 }, -7168, 16422, 6592, 9921, 6, 29 }, /* region 32 */ + { { 1, 60, 60 }, -7653, 23197, 432, 582, 63, 30 }, /* region 33 */ + { { 1, 61, 61 }, -8053, 16422, 432, 582, 63, 30 }, /* region 34 */ + { { 1, 62, 62 }, -8453, 20675, 432, 582, 63, 31 }, /* region 35 */ + { { 1, 63, 63 }, -8553, 23197, 432, 582, 63, 32 }, /* region 36 */ + { { 1, 64, 64 }, -9153, 23197, 432, 582, 63, 33 }, /* region 37 */ + { { 0, 65, 65 }, -8755, 32767, 0, 0, 14, 34 }, /* region 38 */ + { { 0, 66, 66 }, -9155, 20675, 0, 0, 14, 34 }, /* region 39 */ + { { 512, 67, 67 }, -8355, 18426, 0, 0, 90, 35 }, /* region 40 */ + { { 512, 68, 68 }, -8955, 18426, 0, 0, 90, 35 }, /* region 41 */ + { { 0, 69, 69 }, -8955, 32767, 0, 0, 86, 36 }, /* region 42 */ + { { 0, 70, 70 }, -8055, 21900, 0, 0, 86, 37 }, /* region 43 */ + { { 769, 71, 71 }, -7555, 23197, 0, 1226, 35, 38 }, /* region 44 */ + { { 769, 72, 72 }, -8155, 26028, 0, 1226, 35, 38 }, /* region 45 */ + { { 1024, 73, 73 }, -9155, 32767, 0, 0, 22, 39 }, /* region 46 */ + { { 1024, 74, 74 }, -9655, 32767, 0, 0, 22, 40 }, /* region 47 */ + { { 1, 75, 75 }, -9100, 23197, 0, 31, 139, 41 }, /* region 48 */ + { { 0, 76, 76 }, -11655, 23197, 0, 0, 134, 42 }, /* region 49 */ + { { 0, 77, 77 }, -11255, 23197, 0, 0, 134, 43 }, /* region 50 */ + { { 0, 78, 78 }, -10053, 16422, 0, 0, 89, 44 }, /* region 51 */ + { { 0, 79, 79 }, -11453, 16422, 0, 0, 89, 45 }, /* region 52 */ + { { 1281, 80, 80 }, -7500, 13045, 209, 230, 103, 46 }, /* region 53 */ + { { 1281, 81, 81 }, -7600, 16422, 209, 230, 103, 47 }, /* region 54 */ + { { 0, 82, 82 }, -9655, 20675, 0, 0, 87, 48 }, /* region 55 */ + { { 0, 83, 83 }, -10100, 32767, 0, 0, 13, 49 }, /* region 56 */ + { { 1, 84, 84 }, -9600, 23197, 0, 10294, 5, 50 }, /* region 57 */ + { { 0, 85, 85 }, -10855, 32767, 0, 0, 135, 4 }, /* region 58 */ + { { 0, 86, 86 }, -10268, 16422, 0, 0, 24, 51 }, /* region 59 */ + { { 32769, 87, 87 }, -10368, 32767, 1335, 1603, 24, 52 }, /* region 60 */ + { { 1, 12, 67 }, -7805, 23197, 437, 16584, 2, 48 }, /* region 61 */ + { { 1, 68, 73 }, -8396, 23197, 452, 16803, 0, 48 }, /* region 62 */ + { { 32769, 74, 108 }, -9667, 23197, 404, 16698, 1, 48 }, /* region 63 */ + { { 1, 12, 78 }, -7805, 16422, 437, 16584, 2, 48 }, /* region 64 */ + { { 1, 79, 91 }, -8396, 16422, 452, 16803, 0, 48 }, /* region 65 */ + { { 32769, 92, 108 }, -9667, 16422, 404, 16698, 1, 48 }, /* region 66 */ + { { 1, 12, 78 }, -7805, 16422, 437, 16584, 2, 48 }, /* region 67 */ + { { 1, 79, 91 }, -8396, 16422, 452, 16803, 0, 48 }, /* region 68 */ + { { 32769, 92, 108 }, -9667, 16422, 404, 16698, 1, 48 }, /* region 69 */ + { { 1, 12, 70 }, -7800, 23197, 437, 16584, 2, 48 }, /* region 70 */ + { { 1, 71, 88 }, -8391, 23197, 452, 16803, 0, 48 }, /* region 71 */ + { { 32769, 89, 108 }, -9662, 23197, 404, 16698, 1, 48 }, /* region 72 */ + { { 1, 12, 54 }, -7156, 13045, 639, 4368, 10, 48 }, /* region 73 */ + { { 32769, 55, 108 }, -7551, 18426, 702, 3112, 12, 48 }, /* region 74 */ + { { 1, 12, 66 }, -7811, 23197, 437, 16584, 2, 48 }, /* region 75 */ + { { 1, 67, 87 }, -8402, 23197, 452, 16803, 0, 48 }, /* region 76 */ + { { 32769, 88, 108 }, -9673, 16422, 404, 16698, 1, 48 }, /* region 77 */ + { { 1, 12, 43 }, -4255, 23197, 920, 1383, 30, 59 }, /* region 78 */ + { { 32769, 44, 96 }, -6260, 18426, 885, 1176, 37, 59 }, /* region 79 */ + { { 1, 12, 48 }, -4661, 18426, 1148, 1514, 26, 60 }, /* region 80 */ + { { 32769, 49, 96 }, -7453, 16422, 1347, 1420, 29, 60 }, /* region 81 */ + { { 1, 33, 56 }, -6800, 26028, 1064, 1170, 38, 61 }, /* region 82 */ + { { 1, 57, 72 }, -7200, 26028, 930, 1014, 44, 61 }, /* region 83 */ + { { 32769, 73, 108 }, -8800, 26028, 726, 826, 52, 61 }, /* region 84 */ + { { 1, 36, 96 }, -8800, 20675, 635, 735, 58, 62 }, /* region 85 */ + { { 32769, 97, 108 }, -11308, 13045, 0, 31, 139, 62 }, /* region 86 */ + { { 1, 36, 96 }, -8800, 14636, 635, 735, 58, 0 }, /* region 87 */ + { { 32769, 97, 108 }, -11308, 13045, 0, 31, 139, 0 }, /* region 88 */ + { { 1, 36, 83 }, -7206, 13045, 838, 922, 47, 63 }, /* region 89 */ + { { 1, 84, 93 }, -9606, 14636, 209, 230, 103, 63 }, /* region 90 */ + { { 32769, 94, 108 }, -11308, 13045, 0, 31, 139, 63 }, /* region 91 */ + { { 1, 36, 83 }, -7206, 13045, 838, 922, 47, 64 }, /* region 92 */ + { { 1, 84, 93 }, -9606, 13045, 209, 230, 103, 64 }, /* region 93 */ + { { 32769, 94, 108 }, -11308, 13045, 0, 31, 139, 64 }, /* region 94 */ + { { 1, 21, 56 }, -6795, 23197, 1064, 1170, 38, 65 }, /* region 95 */ + { { 1, 57, 72 }, -7195, 23197, 930, 1014, 44, 65 }, /* region 96 */ + { { 32769, 73, 108 }, -8798, 23197, 726, 826, 52, 65 }, /* region 97 */ + { { 1, 12, 83 }, -7206, 16422, 838, 922, 47, 66 }, /* region 98 */ + { { 1, 84, 93 }, -9606, 16422, 209, 230, 103, 66 }, /* region 99 */ + { { 32769, 94, 108 }, -11308, 16422, 0, 31, 139, 66 }, /* region 100 */ + { { 1, 24, 83 }, -7206, 16422, 838, 922, 47, 67 }, /* region 101 */ + { { 1, 84, 93 }, -9606, 16422, 209, 230, 103, 67 }, /* region 102 */ + { { 32769, 94, 108 }, -11308, 16422, 0, 31, 139, 67 }, /* region 103 */ + { { 1, 12, 83 }, -7220, 16422, 0, 83, 126, 68 }, /* region 104 */ + { { 1, 84, 90 }, -9682, 16422, 0, 20, 145, 68 }, /* region 105 */ + { { 32769, 91, 108 }, -10301, 16422, 6, 20, 147, 68 }, /* region 106 */ + { { 1, 21, 75 }, -8441, 16422, 419, 460, 76, 69 }, /* region 107 */ + { { 32769, 76, 108 }, -10890, 14636, 254, 264, 101, 69 }, /* region 108 */ + { { 32769, 36, 84 }, -8955, 16422, 0, 2775, 17, 70 }, /* region 109 */ + { { 32769, 12, 108 }, -7855, 23197, 30, 276, 100, 71 }, /* region 110 */ + { { 0, 12, 60 }, -9114, 26028, 0, 0, 15, 72 }, /* region 111 */ + { { 32768, 61, 96 }, -9114, 26028, 0, 0, 15, 73 }, /* region 112 */ + { { 1, 12, 65 }, -8253, 16422, 23, 10953, 4, 74 }, /* region 113 */ + { { 32769, 66, 108 }, -8955, 20675, 11, 11753, 3, 74 }, /* region 114 */ + { { 1, 12, 35 }, -6555, 16422, 2869, 3778, 11, 75 }, /* region 115 */ + { { 1, 36, 48 }, -7755, 20675, 2869, 3778, 11, 75 }, /* region 116 */ + { { 32769, 49, 72 }, -7755, 20675, 2869, 3778, 11, 76 }, /* region 117 */ + { { 1, 16, 55 }, -7424, 20675, 1045, 1119, 41, 77 }, /* region 118 */ + { { 32769, 56, 96 }, -7918, 20675, 907, 963, 46, 77 }, /* region 119 */ + { { 1, 16, 53 }, -7194, 29204, 1140, 1479, 27, 78 }, /* region 120 */ + { { 1, 54, 70 }, -8371, 29204, 726, 812, 55, 78 }, /* region 121 */ + { { 32769, 71, 108 }, -8988, 29204, 718, 748, 56, 78 }, /* region 122 */ + { { 1, 12, 65 }, -8253, 16422, 23, 10953, 4, 79 }, /* region 123 */ + { { 32769, 66, 108 }, -8955, 20675, 11, 11753, 3, 79 }, /* region 124 */ + { { 1, 16, 54 }, -6927, 20675, 5362, 5461, 9, 80 }, /* region 125 */ + { { 1, 55, 63 }, -7051, 26028, 1362, 1454, 28, 80 }, /* region 126 */ + { { 32769, 64, 108 }, -7944, 16422, 311, 366, 88, 80 }, /* region 127 */ + { { 1, 16, 48 }, -5998, 20675, 1132, 1301, 31, 81 }, /* region 128 */ + { { 32769, 49, 108 }, -7188, 20675, 1099, 1184, 36, 81 }, /* region 129 */ + { { 1, 21, 68 }, -9658, 20675, 87, 2170, 18, 82 }, /* region 130 */ + { { 1, 69, 82 }, -10160, 20675, 120, 2167, 19, 82 }, /* region 131 */ + { { 32769, 83, 108 }, -11360, 20675, 376, 2041, 20, 82 }, /* region 132 */ + { { 1, 12, 65 }, -8253, 16422, 23, 10953, 4, 83 }, /* region 133 */ + { { 32769, 66, 108 }, -8955, 20675, 11, 11753, 3, 83 }, /* region 134 */ + { { 32769, 55, 108 }, -8568, 20675, 0, 477, 75, 84 }, /* region 135 */ + { { 32769, 36, 96 }, -8100, 14636, 101, 151, 116, 85 }, /* region 136 */ + { { 1, 24, 83 }, -7220, 13045, 0, 83, 126, 86 }, /* region 137 */ + { { 1, 84, 90 }, -9682, 13045, 0, 20, 145, 86 }, /* region 138 */ + { { 32769, 91, 108 }, -10301, 13045, 6, 20, 147, 86 }, /* region 139 */ + { { 1, 12, 65 }, -8253, 16422, 23, 10953, 4, 87 }, /* region 140 */ + { { 32769, 66, 108 }, -8955, 20675, 11, 11753, 3, 87 }, /* region 141 */ + { { 1, 12, 65 }, -8253, 16422, 23, 10953, 4, 88 }, /* region 142 */ + { { 32769, 66, 108 }, -8955, 20675, 11, 11753, 3, 88 }, /* region 143 */ + { { 1, 12, 65 }, -8253, 16422, 23, 10953, 4, 89 }, /* region 144 */ + { { 32769, 66, 108 }, -8955, 20675, 11, 11753, 3, 89 }, /* region 145 */ + { { 1, 24, 83 }, -7220, 13045, 0, 83, 126, 90 }, /* region 146 */ + { { 1, 84, 90 }, -9682, 13045, 0, 20, 145, 90 }, /* region 147 */ + { { 32769, 91, 108 }, -10301, 13045, 6, 20, 147, 90 }, /* region 148 */ + { { 1, 12, 65 }, -8253, 16422, 23, 10953, 4, 91 }, /* region 149 */ + { { 32769, 66, 108 }, -8955, 20675, 11, 11753, 3, 91 }, /* region 150 */ + { { 1, 12, 65 }, -8253, 16422, 23, 10953, 4, 92 }, /* region 151 */ + { { 32769, 66, 108 }, -8955, 20675, 11, 11753, 3, 92 }, /* region 152 */ + { { 1, 12, 62 }, -8253, 16422, 23, 10953, 4, 93 }, /* region 153 */ + { { 32769, 63, 108 }, -8955, 20675, 11, 11753, 3, 93 }, /* region 154 */ + { { 1, 12, 62 }, -8253, 16422, 23, 10953, 4, 94 }, /* region 155 */ + { { 32769, 63, 108 }, -8955, 16422, 11, 11753, 3, 94 }, /* region 156 */ + { { 1, 24, 79 }, -7220, 13045, 0, 83, 126, 95 }, /* region 157 */ + { { 1, 80, 90 }, -9682, 13045, 0, 20, 145, 95 }, /* region 158 */ + { { 32769, 91, 108 }, -10301, 13045, 6, 20, 147, 95 }, /* region 159 */ + { { 1, 12, 65 }, -8253, 13045, 23, 10953, 4, 96 }, /* region 160 */ + { { 32769, 66, 108 }, -8955, 16422, 11, 11753, 3, 96 }, /* region 161 */ + { { 32768, 36, 84 }, -8700, 20675, 0, 0, 25, 97 }, /* region 162 */ + { { 32769, 36, 96 }, -10055, 20675, 1482, 1613, 23, 98 }, /* region 163 */ + { { 32769, 12, 96 }, -5566, 32767, 818, 1033, 42, 99 }, /* region 164 */ + { { 32769, 36, 84 }, -9768, 18426, 0, 293, 98, 100 }, /* region 165 */ + { { 32769, 12, 96 }, -7220, 26028, 0, 83, 125, 101 }, /* region 166 */ + { { 32769, 12, 96 }, -7220, 20675, 0, 83, 125, 102 }, /* region 167 */ + { { 1, 12, 83 }, -7220, 13045, 0, 83, 125, 104 }, /* region 168 */ + { { 1, 84, 90 }, -9682, 13045, 0, 20, 146, 104 }, /* region 169 */ + { { 32769, 91, 108 }, -10301, 13045, 6, 20, 148, 104 }, /* region 170 */ + { { 32769, 36, 108 }, -9770, 32767, 472, 491, 74, 105 }, /* region 171 */ + { { 32769, 36, 108 }, -9770, 20675, 472, 491, 74, 106 }, /* region 172 */ + { { 1, 12, 72 }, -7212, 7336, 2, 86, 124, 107 }, /* region 173 */ + { { 1, 73, 101 }, -9700, 8231, 2, 22, 143, 107 }, /* region 174 */ + { { 32769, 102, 108 }, -10883, 20675, 173, 183, 110, 107 }, /* region 175 */ + { { 1, 21, 96 }, -8968, 13045, 477, 507, 73, 108 }, /* region 176 */ + { { 32769, 97, 108 }, -10883, 13045, 173, 183, 110, 109 }, /* region 177 */ + { { 32769, 12, 108 }, -8971, 16422, 477, 507, 73, 110 }, /* region 178 */ + { { 1, 12, 53 }, -6171, 16422, 388, 541, 68, 111 }, /* region 179 */ + { { 32769, 54, 60 }, -7149, 11626, 473, 560, 65, 111 }, /* region 180 */ + { { 32769, 36, 72 }, -7149, 16422, 473, 560, 65, 112 }, /* region 181 */ + { { 1, 48, 58 }, -8253, 16422, 356, 402, 82, 113 }, /* region 182 */ + { { 1, 59, 65 }, -8774, 16422, 514, 548, 67, 113 }, /* region 183 */ + { { 1, 66, 78 }, -9374, 16422, 505, 529, 71, 113 }, /* region 184 */ + { { 32769, 79, 96 }, -10433, 16422, 178, 191, 109, 113 }, /* region 185 */ + { { 1, 55, 60 }, -8253, 16422, 356, 402, 82, 114 }, /* region 186 */ + { { 1, 61, 69 }, -8774, 16422, 514, 548, 67, 114 }, /* region 187 */ + { { 1, 70, 79 }, -9374, 16422, 505, 529, 71, 114 }, /* region 188 */ + { { 32769, 80, 108 }, -10433, 16422, 178, 191, 109, 114 }, /* region 189 */ + { { 1, 16, 82 }, -9229, 23197, 180, 206, 106, 115 }, /* region 190 */ + { { 32769, 83, 108 }, -8440, 18426, 3, 44, 131, 115 }, /* region 191 */ + { { 32769, 21, 108 }, -10069, 20675, 483, 515, 72, 116 }, /* region 192 */ + { { 1, 21, 89 }, -8405, 18426, 3, 45, 130, 117 }, /* region 193 */ + { { 32769, 90, 108 }, -10301, 10362, 6, 20, 148, 117 }, /* region 194 */ + { { 1, 21, 42 }, -5886, 20675, 0, 180, 111, 118 }, /* region 195 */ + { { 1, 43, 51 }, -6486, 23197, 0, 127, 120, 118 }, /* region 196 */ + { { 1, 52, 58 }, -7492, 26028, 0, 71, 127, 118 }, /* region 197 */ + { { 1, 59, 68 }, -8668, 23197, 0, 36, 136, 118 }, /* region 198 */ + { { 32769, 69, 108 }, -9774, 20675, 0, 19, 149, 118 }, /* region 199 */ + { { 1, 21, 89 }, -8399, 20675, 3, 45, 130, 119 }, /* region 200 */ + { { 32769, 90, 108 }, -10301, 14636, 6, 20, 148, 119 }, /* region 201 */ + { { 1, 21, 46 }, -6851, 26028, 236, 340, 92, 120 }, /* region 202 */ + { { 1, 47, 71 }, -7763, 20675, 824, 885, 49, 120 }, /* region 203 */ + { { 1, 72, 88 }, -9107, 18426, 719, 747, 57, 120 }, /* region 204 */ + { { 1, 89, 93 }, -10076, 16422, 83, 99, 122, 120 }, /* region 205 */ + { { 32769, 94, 108 }, -10889, 16422, 173, 183, 110, 120 }, /* region 206 */ + { { 1, 60, 71 }, -8405, 16422, 0, 42, 132, 121 }, /* region 207 */ + { { 1, 72, 78 }, -9103, 16422, 0, 28, 141, 121 }, /* region 208 */ + { { 32769, 79, 96 }, -9605, 16422, 0, 21, 144, 121 }, /* region 209 */ + { { 1, 48, 65 }, -7516, 11626, 0, 70, 128, 122 }, /* region 210 */ + { { 1, 66, 79 }, -8924, 14636, 0, 31, 138, 122 }, /* region 211 */ + { { 32769, 80, 96 }, -9230, 11626, 0, 26, 142, 122 }, /* region 212 */ + { { 1, 16, 44 }, -7068, 14636, 163, 254, 102, 123 }, /* region 213 */ + { { 1, 45, 51 }, -7618, 16422, 261, 393, 85, 123 }, /* region 214 */ + { { 1, 52, 58 }, -8533, 18426, 190, 229, 104, 123 }, /* region 215 */ + { { 1, 59, 66 }, -9300, 18426, 168, 193, 108, 123 }, /* region 216 */ + { { 1, 67, 70 }, -9776, 18426, 138, 157, 115, 123 }, /* region 217 */ + { { 1, 71, 80 }, -10303, 18426, 166, 180, 112, 123 }, /* region 218 */ + { { 32769, 81, 108 }, -11274, 18426, 135, 151, 117, 123 }, /* region 219 */ + { { 32769, 12, 96 }, -6204, 23197, 570, 719, 59, 124 }, /* region 220 */ + { { 1, 12, 48 }, -7068, 14636, 163, 254, 102, 125 }, /* region 221 */ + { { 1, 49, 54 }, -7618, 16422, 261, 393, 85, 125 }, /* region 222 */ + { { 1, 55, 63 }, -8533, 18426, 190, 229, 104, 125 }, /* region 223 */ + { { 1, 64, 70 }, -9300, 18426, 168, 193, 108, 125 }, /* region 224 */ + { { 1, 71, 75 }, -9776, 18426, 138, 157, 115, 125 }, /* region 225 */ + { { 1, 76, 82 }, -10303, 18426, 166, 180, 112, 125 }, /* region 226 */ + { { 32769, 83, 108 }, -11274, 18426, 135, 151, 117, 125 }, /* region 227 */ + { { 32770, 36, 84 }, -8400, 29204, 0, 0, 0, 126 }, /* region 228 */ + { { 32770, 36, 84 }, -8800, 8231, 0, 0, 0, 127 }, /* region 229 */ + { { 32770, 36, 84 }, -8400, 20675, 0, 0, 0, 128 }, /* region 230 */ + { { 32769, 36, 84 }, -7200, -24285, 1294, 5778, 8, 129 }, /* region 231 */ + { { 32769, 36, 84 }, -7755, 29204, 798, 993, 45, 130 }, /* region 232 */ + { { 32769, 36, 84 }, -8055, 20675, 798, 993, 45, 131 }, /* region 233 */ + { { 32769, 36, 84 }, -8955, 29204, 798, 993, 45, 132 }, /* region 234 */ + { { 32768, 36, 84 }, -9355, 32767, 0, 0, 133, 133 }, /* region 235 */ + { { 32768, 36, 84 }, -7755, 20675, 0, 0, 91, 134 }, /* region 236 */ + { { 1, 24, 62 }, -8200, 23197, 286, 333, 94, 135 }, /* region 237 */ + { { 1, 63, 66 }, -8564, 26028, 297, 335, 93, 135 }, /* region 238 */ + { { 1, 67, 72 }, -8922, 23197, 368, 399, 84, 135 }, /* region 239 */ + { { 32769, 73, 96 }, -9510, 23197, 116, 138, 119, 135 }, /* region 240 */ + { { 1, 24, 48 }, -6341, 23197, 309, 447, 77, 136 }, /* region 241 */ + { { 1, 49, 56 }, -7466, 26028, 211, 283, 99, 136 }, /* region 242 */ + { { 1, 57, 63 }, -8200, 26028, 286, 333, 94, 136 }, /* region 243 */ + { { 32769, 64, 84 }, -8922, 23197, 368, 399, 84, 136 }, /* region 244 */ + { { 1, 24, 56 }, -7466, 29204, 211, 283, 99, 137 }, /* region 245 */ + { { 1, 57, 63 }, -8200, 29204, 286, 333, 94, 137 }, /* region 246 */ + { { 1, 64, 69 }, -8922, 29204, 368, 399, 84, 137 }, /* region 247 */ + { { 32769, 70, 96 }, -9510, 29204, 116, 138, 119, 137 }, /* region 248 */ + { { 1, 24, 68 }, -8922, 18426, 368, 399, 84, 138 }, /* region 249 */ + { { 1, 69, 76 }, -9510, 26028, 116, 138, 119, 138 }, /* region 250 */ + { { 32769, 77, 108 }, -9958, 23197, 127, 144, 118, 138 }, /* region 251 */ + { { 1, 24, 82 }, -8813, 23197, 389, 422, 80, 139 }, /* region 252 */ + { { 32769, 83, 108 }, -9964, 26028, 146, 163, 114, 139 }, /* region 253 */ + { { 1, 12, 58 }, -8098, 29204, 386, 436, 78, 140 }, /* region 254 */ + { { 32769, 59, 96 }, -8571, 26028, 290, 328, 95, 140 }, /* region 255 */ + { { 1, 12, 58 }, -8098, 16422, 386, 436, 78, 141 }, /* region 256 */ + { { 32769, 59, 96 }, -8571, 18426, 290, 328, 95, 141 }, /* region 257 */ + { { 1, 12, 48 }, -8098, -28771, 386, 436, 78, 142 }, /* region 258 */ + { { 32769, 49, 84 }, -8571, 29204, 290, 328, 95, 142 }, /* region 259 */ + { { 1, 12, 60 }, -6653, 20675, 314, 430, 79, 143 }, /* region 260 */ + { { 32769, 61, 84 }, -7753, 18426, 263, 324, 96, 143 }, /* region 261 */ + { { 1, 24, 60 }, -7753, 16422, 263, 324, 96, 144 }, /* region 262 */ + { { 1, 61, 70 }, -8869, 20675, 279, 311, 97, 144 }, /* region 263 */ + { { 32769, 71, 96 }, -9298, 23197, 179, 204, 107, 144 }, /* region 264 */ + { { 1, 24, 84 }, -9683, 20675, 191, 211, 105, 145 }, /* region 265 */ + { { 32769, 85, 108 }, -10883, 20675, 92, 102, 121, 145 }, /* region 266 */ + { { 1, 21, 69 }, -7753, 13045, 263, 324, 96, 146 }, /* region 267 */ + { { 1, 70, 94 }, -8869, 20675, 279, 311, 97, 146 }, /* region 268 */ + { { 1, 95, 96 }, -9298, -24285, 179, 204, 107, 146 }, /* region 269 */ + { { 32769, 97, 108 }, -10883, -24285, 173, 183, 110, 146 }, /* region 270 */ + { { 1, 16, 55 }, -9300, 20675, 168, 193, 108, 147 }, /* region 271 */ + { { 1, 56, 74 }, -9776, 26028, 138, 157, 115, 147 }, /* region 272 */ + { { 32769, 75, 96 }, -11274, 26028, 135, 151, 117, 147 }, /* region 273 */ + { { 1, 24, 72 }, -9298, 26028, 179, 204, 107, 148 }, /* region 274 */ + { { 1, 73, 85 }, -9683, 20675, 191, 211, 105, 148 }, /* region 275 */ + { { 32769, 86, 108 }, -10883, 18426, 92, 102, 121, 148 }, /* region 276 */ + { { 32769, 36, 108 }, -8930, 18426, 1839, 1901, 21, 149 }, /* region 277 */ + { { 32769, 24, 108 }, -8473, 20675, 494, 534, 69, 150 }, /* region 278 */ + { { 32769, 12, 108 }, -8473, 20675, 494, 534, 69, 151 }, /* region 279 */ + { { 32769, 24, 108 }, -8473, 20675, 494, 534, 69, 152 }, /* region 280 */ + { { 1, 36, 60 }, -6100, 5193, 2, 22, 143, 153 }, /* region 281 */ + { { 32769, 61, 84 }, -7283, 20675, 173, 183, 110, 153 }, /* region 282 */ + { { 32769, 24, 96 }, -7753, 14636, 263, 324, 96, 154 }, /* region 283 */ + { { 32769, 36, 96 }, -8930, 26028, 1839, 1901, 21, 155 }, /* region 284 */ + { { 32769, 24, 108 }, -8473, 20675, 494, 534, 69, 156 }, /* region 285 */ + { { 1, 24, 58 }, -9051, 14636, 0, 29, 140, 157 }, /* region 286 */ + { { 32769, 59, 96 }, -9051, 14636, 0, 29, 140, 157 }, /* region 287 */ + { { 1, 12, 83 }, -7220, 13045, 0, 83, 125, 158 }, /* region 288 */ + { { 1, 84, 90 }, -9682, 13045, 0, 20, 146, 158 }, /* region 289 */ + { { 32769, 91, 108 }, -10301, 13045, 6, 20, 148, 158 }, /* region 290 */ + { { 1, 21, 42 }, -5863, 26028, 1047, 1229, 34, 159 }, /* region 291 */ + { { 1, 43, 48 }, -6656, 29204, 1138, 1253, 33, 159 }, /* region 292 */ + { { 1, 49, 53 }, -7045, 26028, 559, 651, 60, 159 }, /* region 293 */ + { { 1, 54, 60 }, -7932, 26028, 508, 563, 64, 159 }, /* region 294 */ + { { 1, 61, 65 }, -8280, 32767, 819, 864, 51, 159 }, /* region 295 */ + { { 1, 66, 70 }, -8066, 26942, 981, 1032, 43, 159 }, /* region 296 */ + { { 1, 71, 76 }, -9366, 26028, 790, 814, 54, 159 }, /* region 297 */ + { { 1, 77, 82 }, -9966, 26028, 592, 609, 61, 159 }, /* region 298 */ + { { 1, 83, 87 }, -10717, 23197, 543, 554, 66, 159 }, /* region 299 */ + { { 1, 88, 96 }, -11271, 18426, 601, 609, 62, 159 }, /* region 300 */ + { { 32769, 97, 108 }, -11766, 18426, 523, 529, 70, 159 }, /* region 301 */ + { { 1, 48, 69 }, -7513, 14636, 0, 70, 128, 160 }, /* region 302 */ + { { 1, 70, 79 }, -8924, 18426, 0, 31, 138, 160 }, /* region 303 */ + { { 32769, 80, 96 }, -9230, 14636, 0, 26, 142, 160 }, /* region 304 */ + { { 1, 36, 72 }, -8334, 29204, 0, 87, 123, 161 }, /* region 305 */ + { { 32769, 73, 96 }, -9160, 29204, 0, 54, 129, 161 }, /* region 306 */ + { { 32769, 36, 96 }, -8930, 26028, 1839, 1901, 21, 162 }, /* region 307 */ + { { 32769, 12, 96 }, -5572, 32767, 818, 1033, 42, 163 }, /* region 308 */ + { { 32769, 36, 108 }, -9770, 26028, 472, 491, 74, 164 }, /* region 309 */ + { { 32769, 12, 96 }, -6204, 29204, 570, 719, 59, 165 }, /* region 310 */ + { { 1, 12, 83 }, -7220, 13045, 0, 83, 125, 166 }, /* region 311 */ + { { 1, 84, 90 }, -9682, 13045, 0, 20, 146, 166 }, /* region 312 */ + { { 32769, 91, 108 }, -10301, 13045, 6, 20, 148, 166 }, /* region 313 */ + { { 1, 21, 46 }, -6851, 32767, 236, 340, 92, 167 }, /* region 314 */ + { { 1, 47, 75 }, -7763, 26028, 824, 885, 49, 167 }, /* region 315 */ + { { 1, 76, 84 }, -9107, 23197, 719, 747, 57, 167 }, /* region 316 */ + { { 1, 85, 93 }, -10076, 20675, 83, 99, 122, 167 }, /* region 317 */ + { { 32769, 94, 108 }, -10889, 20675, 173, 183, 110, 167 }, /* region 318 */ + { { 1, 21, 46 }, -6851, 26028, 236, 340, 92, 168 }, /* region 319 */ + { { 1, 47, 71 }, -7763, 20675, 824, 885, 49, 168 }, /* region 320 */ + { { 1, 72, 88 }, -9107, 18426, 719, 747, 57, 168 }, /* region 321 */ + { { 1, 89, 93 }, -10076, 16422, 83, 99, 122, 168 }, /* region 322 */ + { { 32769, 94, 108 }, -10889, 16422, 173, 183, 110, 168 }, /* region 323 */ + { { 1, 21, 45 }, -5863, 26028, 1047, 1229, 34, 169 }, /* region 324 */ + { { 1, 46, 51 }, -6656, 29204, 1138, 1253, 33, 169 }, /* region 325 */ + { { 1, 52, 54 }, -7045, 26028, 559, 651, 60, 169 }, /* region 326 */ + { { 1, 55, 63 }, -7932, 26028, 508, 563, 64, 169 }, /* region 327 */ + { { 1, 64, 68 }, -8280, 32767, 819, 864, 51, 169 }, /* region 328 */ + { { 1, 69, 73 }, -8066, 26942, 981, 1032, 43, 169 }, /* region 329 */ + { { 1, 74, 79 }, -9366, 26028, 790, 814, 54, 169 }, /* region 330 */ + { { 1, 80, 88 }, -9966, 23197, 592, 609, 61, 169 }, /* region 331 */ + { { 1, 89, 99 }, -11271, 18426, 601, 609, 62, 169 }, /* region 332 */ + { { 32769, 100, 108 }, -11766, 18426, 523, 529, 70, 169 }, /* region 333 */ + { { 1, 21, 45 }, -5863, 26028, 1047, 1229, 34, 170 }, /* region 334 */ + { { 1, 46, 51 }, -6656, 29204, 1138, 1253, 33, 170 }, /* region 335 */ + { { 1, 52, 54 }, -7045, 26028, 559, 651, 60, 170 }, /* region 336 */ + { { 1, 55, 63 }, -7932, 26028, 508, 563, 64, 170 }, /* region 337 */ + { { 1, 64, 68 }, -8280, 32767, 819, 864, 51, 170 }, /* region 338 */ + { { 1, 69, 73 }, -8066, 26942, 981, 1032, 43, 170 }, /* region 339 */ + { { 1, 74, 79 }, -9366, 26028, 790, 814, 54, 170 }, /* region 340 */ + { { 1, 80, 88 }, -9966, 23197, 592, 609, 61, 170 }, /* region 341 */ + { { 1, 89, 99 }, -11271, 18426, 601, 609, 62, 171 }, /* region 342 */ + { { 32769, 100, 108 }, -11766, 18426, 523, 529, 70, 172 }, /* region 343 */ + { { 32769, 36, 108 }, -9770, 20675, 472, 491, 74, 173 }, /* region 344 */ + { { 32769, 12, 108 }, -8930, 20675, 1839, 1901, 21, 174 }, /* region 345 */ + { { 1, 12, 44 }, -7068, 18426, 163, 254, 102, 175 }, /* region 346 */ + { { 1, 45, 51 }, -7618, 20675, 261, 393, 85, 175 }, /* region 347 */ + { { 1, 52, 58 }, -8533, 23197, 190, 229, 104, 175 }, /* region 348 */ + { { 1, 59, 66 }, -9300, 23197, 168, 193, 108, 175 }, /* region 349 */ + { { 1, 67, 70 }, -9776, 23197, 138, 157, 115, 175 }, /* region 350 */ + { { 1, 71, 80 }, -10303, 23197, 166, 180, 112, 175 }, /* region 351 */ + { { 32769, 81, 108 }, -11274, 23197, 135, 151, 117, 175 }, /* region 352 */ + { { 1, 12, 65 }, -8253, 16422, 23, 10953, 4, 176 }, /* region 353 */ + { { 32769, 66, 108 }, -8955, 20675, 11, 11753, 3, 176 }, /* region 354 */ + { { 1, 12, 48 }, -5998, 29204, 1132, 1301, 31, 177 }, /* region 355 */ + { { 32769, 49, 108 }, -7188, 29204, 1099, 1184, 36, 177 }, /* region 356 */ + { { 1, 12, 83 }, -8441, 20675, 419, 460, 76, 178 }, /* region 357 */ + { { 32769, 84, 108 }, -11323, 20675, 0, 31, 139, 178 }, /* region 358 */ + { { 1, 55, 60 }, -8253, 18426, 356, 402, 82, 179 }, /* region 359 */ + { { 1, 61, 69 }, -8774, 18426, 514, 548, 67, 179 }, /* region 360 */ + { { 1, 70, 79 }, -9374, 18426, 505, 529, 71, 179 }, /* region 361 */ + { { 32769, 80, 108 }, -10433, 23197, 178, 191, 109, 179 }, /* region 362 */ + { { 32769, 36, 96 }, -8930, -24285, 1839, 1901, 21, 180 }, /* region 363 */ + { { 1, 12, 83 }, -7206, 16422, 838, 922, 47, 181 }, /* region 364 */ + { { 1, 84, 93 }, -9606, 18426, 209, 230, 103, 181 }, /* region 365 */ + { { 32769, 94, 108 }, -11308, 16422, 0, 31, 139, 181 }, /* region 366 */ + { { 1, 12, 56 }, -6795, 23197, 1064, 1170, 38, 182 }, /* region 367 */ + { { 1, 57, 72 }, -7195, 23197, 930, 1014, 44, 182 }, /* region 368 */ + { { 32769, 73, 108 }, -8798, 23197, 726, 826, 52, 182 }, /* region 369 */ + { { 32769, 24, 108 }, -8800, 23197, 635, 735, 58, 62 }, /* region 370 */ + { { 1, 36, 83 }, -7206, 13045, 838, 922, 47, 183 }, /* region 371 */ + { { 1, 84, 93 }, -9606, 13045, 209, 230, 103, 183 }, /* region 372 */ + { { 32769, 94, 108 }, -11308, 13045, 0, 31, 139, 183 }, /* region 373 */ + { { 1, 12, 66 }, -7811, 23197, 437, 16584, 2, 184 }, /* region 374 */ + { { 1, 67, 87 }, -8402, 23197, 452, 16803, 0, 184 }, /* region 375 */ + { { 32769, 88, 108 }, -9673, 16422, 404, 16698, 1, 184 } /* region 376 */ +}; /* end Regions */ + +/*---------------------------------------------------------------------------- + * Programs + *---------------------------------------------------------------------------- +*/ +const S_PROGRAM eas_programs[] = +{ + { 7864320, 0 } /* program 0 */ +}; /* end Programs */ + +/*---------------------------------------------------------------------------- + * Banks + *---------------------------------------------------------------------------- +*/ +const S_BANK eas_banks[] = +{ + { /* bank 0 */ + 30976, + { + 291, 324, 314, 334, 202, 319, 95, 195, + 107, 92, 371, 89, 87, 85, 135, 82, + 200, 192, 130, 267, 193, 302, 207, 210, + 128, 125, 190, 120, 118, 213, 221, 271, + 80, 78, 308, 164, 220, 310, 166, 167, + 186, 182, 181, 179, 160, 178, 176, 115, + 155, 153, 151, 149, 75, 73, 374, 111, + 252, 254, 258, 305, 256, 157, 146, 137, + 249, 237, 245, 241, 274, 262, 260, 265, + 172, 171, 309, 277, 284, 307, 136, 344, + 173, 168, 345, 353, 346, 70, 110, 311, + 357, 144, 104, 67, 364, 367, 64, 288, + 142, 140, 98, 355, 133, 123, 61, 113, + 285, 280, 279, 278, 370, 286, 359, 283, + 101, 236, 163, 235, 234, 233, 232, 231, + 162, 363, 230, 281, 165, 229, 109, 228 + } + } +}; /* end Banks */ + +/*---------------------------------------------------------------------------- + * Samples + *---------------------------------------------------------------------------- +*/ + +const EAS_SAMPLE eas_samples[] = +{ + 0, 0, -3, -4, -6, -8, -10, -12, -12, -11, -8, -3, 3, 7, 10, 14, + 16, 16, 15, 12, 9, 4, -4, -12, -18, -21, -21, -19, -18, -15, -10, -3, + 10, 20, 34, 44, 51, 52, 48, 43, 38, 26, 8, -15, -37, -52, -61, -64, + -66, -64, -59, -47, -31, -13, 4, 18, 30, 37, 40, 36, 30, 24, 19, 11, + -2, -17, -24, -28, -28, -21, -18, -16, -10, -3, 12, 27, 39, 49, 53, 53, + 50, 43, 37, 25, 11, -11, -31, -46, -57, -63, -66, -63, -57, -46, -34, -19, + -3, 13, 27, 35, 39, 37, 32, 26, 20, 11, 0, -13, -20, -24, -25, -21, + -19, -14, -8, -2, 9, 23, 37, 47, 53, 52, 49, 42, 35, 25, 13, -6, + -28, -48, -60, -67, -67, -64, -60, -51, -39, -23, -7, 10, 23, 35, 39, 38, + 32, 26, 21, 15, 4, -9, -20, -22, -21, -19, -14, -11, -5, 1, 9, 19, + 31, 45, 51, 52, 47, 39, 35, 25, 15, -3, -23, -42, -58, -70, -71, -66, + -60, -51, -43, -30, -13, 6, 22, 32, 40, 40, 38, 33, 27, 19, 9, -5, + -17, -25, -26, -22, -16, -11, -8, -4, 7, 21, 35, 48, 53, 56, 50, 43, + 34, 22, 13, -2, -22, -44, -63, -75, -76, -69, -61, -51, -43, -29, -13, 6, + 23, 32, 41, 43, 41, 37, 26, 18, 7, -8, -19, -25, -25, -22, -15, -9, + -5, 0, 10, 24, 37, 44, 48, 52, 52, 46, 33, 20, 8, -5, -20, -38, + -59, -74, -79, -73, -67, -55, -43, -26, -11, 4, 18, 29, 41, 45, 45, 38, + 29, 21, 11, -3, -15, -25, -27, -22, -16, -11, -8, 0, 10, 25, 38, 44, + 47, 50, 53, 49, 37, 20, 7, -5, -17, -34, -58, -74, -82, -76, -67, -59, + -47, -29, -12, 3, 14, 25, 38, 50, 52, 46, 33, 23, 14, 3, -11, -25, + -28, -27, -21, -16, -13, -7, 8, 27, 41, 44, 45, 47, 54, 55, 44, 25, + 7, -7, -18, -32, -53, -71, -81, -81, -72, -67, -55, -37, -16, 3, 15, 23, + 34, 48, 57, 56, 44, 30, 19, 5, -12, -26, -33, -31, -25, -19, -16, -11, + 7, 25, 45, 49, 49, 52, 57, 59, 48, 32, 11, -5, -22, -39, -56, -73, + -82, -88, -84, -75, -60, -38, -16, 5, 21, 30, 39, 52, 59, 61, 53, 37, + 22, 7, -12, -28, -35, -36, -30, -22, -19, -16, -2, 21, 41, 52, 51, 52, + 57, 62, 54, 40, 18, -2, -18, -36, -54, -70, -80, -86, -87, -81, -69, -48, + -23, 0, 18, 28, 35, 45, 57, 64, 59, 46, 27, 9, -11, -24, -30, -32, + -29, -25, -20, -16, -5, 15, 36, 47, 50, 49, 53, 57, 54, 43, 24, 5, + -14, -32, -50, -65, -75, -82, -86, -86, -77, -58, -32, -8, 14, 25, 30, 41, + 56, 69, 69, 57, 36, 17, -4, -20, -29, -32, -27, -28, -27, -23, -13, 10, + 33, 46, 50, 48, 50, 54, 55, 48, 34, 16, -6, -29, -50, -68, -75, -78, + -82, -86, -84, -72, -47, -16, 11, 28, 34, 41, 51, 64, 70, 64, 49, 27, + 5, -17, -30, -33, -29, -29, -30, -30, -22, -2, 23, 41, 49, 51, 51, 54, + 56, 50, 42, 25, 4, -20, -44, -62, -70, -76, -83, -87, -89, -78, -56, -29, + 0, 19, 31, 38, 48, 63, 72, 71, 60, 40, 14, -12, -25, -29, -26, -27, + -33, -37, -30, -12, 11, 31, 41, 48, 51, 53, 55, 55, 51, 39, 17, -12, + -38, -58, -67, -74, -82, -92, -98, -89, -69, -41, -13, 10, 29, 41, 50, 64, + 72, 78, 74, 57, 29, 0, -18, -26, -28, -32, -38, -42, -38, -23, -3, 18, + 30, 42, 52, 58, 60, 61, 57, 48, 28, 2, -30, -51, -62, -70, -81, -94, + -101, -93, -75, -49, -23, -2, 18, 36, 50, 61, 69, 77, 78, 66, 42, 11, + -11, -22, -27, -32, -39, -46, -46, -36, -14, 8, 25, 41, 52, 59, 62, 63, + 62, 57, 38, 11, -20, -47, -61, -69, -78, -89, -98, -94, -80, -60, -37, -12, + 13, 33, 48, 62, 70, 78, 81, 72, 52, 23, 0, -14, -24, -33, -43, -49, + -49, -39, -23, -2, 15, 33, 47, 57, 63, 62, 62, 57, 40, 20, -7, -34, + -52, -65, -74, -83, -94, -92, -81, -63, -42, -22, 0, 21, 39, 54, 63, 73, + 79, 76, 61, 37, 12, -5, -19, -28, -37, -46, -51, -47, -32, -13, 7, 25, + 43, 54, 58, 60, 60, 61, 48, 27, 3, -25, -45, -60, -72, -81, -90, -92, + -84, -71, -52, -32, -9, 14, 33, 50, 61, 74, 80, 78, 67, 47, 24, 6, + -12, -26, -37, -50, -56, -52, -37, -19, -2, 16, 35, 52, 61, 63, 61, 59, + 51, 35, 12, -15, -38, -55, -66, -77, -83, -83, -80, -68, -55, -39, -19, 4, + 25, 41, 54, 66, 73, 75, 68, 52, 31, 11, -7, -22, -33, -46, -54, -51, + -39, -24, -5, 12, 32, 48, 56, 60, 61, 58, 50, 36, 17, -8, -30, -46, + -63, -74, -80, -80, -74, -69, -58, -43, -27, -5, 15, 31, 48, 60, 68, 72, + 68, 57, 39, 20, 2, -16, -30, -44, -51, -50, -41, -27, -10, 9, 28, 43, + 53, 57, 57, 54, 48, 37, 19, -3, -25, -41, -56, -69, -75, -73, -69, -63, + -59, -49, -32, -13, 9, 25, 37, 48, 58, 66, 65, 58, 42, 25, 8, -9, + -22, -36, -41, -43, -37, -26, -14, 4, 21, 37, 48, 52, 53, 47, 42, 34, + 21, 3, -18, -39, -51, -64, -67, -62, -60, -60, -58, -50, -36, -16, 3, 17, + 29, 41, 49, 58, 61, 60, 49, 29, 11, -7, -19, -28, -32, -33, -30, -25, + -14, 2, 19, 33, 41, 45, 42, 38, 36, 29, 20, 6, -14, -28, -43, -54, + -58, -55, -50, -51, -54, -51, -41, -22, -4, 11, 19, 30, 37, 47, 55, 56, + 51, 34, 16, 0, -15, -19, -23, -22, -22, -21, -14, 0, 15, 29, 39, 43, + 37, 31, 25, 21, 18, 6, -11, -28, -42, -50, -51, -48, -44, -41, -44, -43, + -41, -25, -8, 9, 16, 22, 26, 35, 43, 50, 48, 33, 16, -3, -13, -16, + -16, -15, -13, -11, -6, 5, 16, 28, 38, 41, 35, 24, 15, 12, 10, 4, + -11, -27, -39, -46, -46, -45, -40, -36, -36, -37, -38, -29, -13, 6, 16, 19, + 22, 27, 37, 43, 42, 32, 19, 2, -10, -13, -12, -7, -4, -2, 2, 10, + 18, 27, 36, 38, 32, 20, 9, 4, -2, -4, -11, -23, -34, -42, -42, -38, + -31, -28, -29, -32, -33, -30, -18, 0, 10, 12, 12, 17, 26, 35, 36, 31, + 19, 5, -6, -11, -9, -2, 7, 14, 13, 13, 16, 23, 31, 34, 29, 15, + -3, -8, -10, -10, -14, -20, -26, -30, -32, -30, -25, -18, -17, -24, -31, -32, + -26, -11, 2, 7, 8, 9, 17, 25, 29, 28, 21, 9, -2, -7, -5, 4, + 12, 21, 24, 23, 25, 26, 29, 31, 27, 15, -2, -15, -21, -23, -23, -23, + -28, -30, -31, -27, -19, -10, -9, -13, -21, -22, -20, -11, -4, -3, -5, -2, + 5, 13, 17, 17, 16, 10, 6, 0, 3, 11, 23, 32, 33, 30, 28, 27, + 24, 24, 19, 9, -6, -19, -29, -29, -26, -20, -19, -22, -24, -23, -16, -10, + -9, -14, -20, -24, -21, -16, -10, -6, -5, 1, 5, 11, 12, 13, 11, 8, + 6, 1, 4, 9, 23, 33, 39, 36, 32, 32, 28, 22, 17, 7, -7, -22, + -31, -33, -31, -24, -19, -18, -18, -16, -13, -7, -6, -8, -14, -21, -24, -20, + -15, -12, -9, -6, 0, 4, 6, 8, 8, 5, 5, 2, 7, 15, 27, 37, + 42, 45, 41, 39, 32, 22, 13, 3, -11, -26, -37, -41, -37, -29, -21, -18, + -15, -11, -6, -2, -2, -4, -7, -13, -16, -20, -21, -16, -14, -10, -6, -3, + -3, 0, 3, 2, 3, 3, 9, 18, 32, 41, 46, 49, 44, 43, 35, 24, + 12, 1, -14, -27, -39, -40, -36, -31, -22, -16, -13, -6, -3, -3, -4, -9, + -9, -13, -16, -20, -21, -16, -15, -11, -6, -4, -4, -5, -5, -3, -3, 0, + 10, 19, 33, 44, 51, 56, 52, 50, 40, 23, 11, -6, -19, -30, -40, -43, + -40, -35, -24, -16, -7, 2, 6, 5, 1, -6, -9, -9, -9, -12, -19, -21, + -21, -17, -9, -7, -9, -11, -15, -14, -9, -7, 7, 19, 36, 51, 57, 61, + 59, 56, 48, 33, 13, -8, -24, -35, -45, -51, -46, -38, -26, -14, -7, 3, + 11, 15, 12, 3, -5, -7, -6, -9, -15, -22, -25, -23, -17, -13, -12, -16, + -19, -21, -18, -12, 3, 21, 38, 50, 58, 67, 65, 64, 55, 41, 21, -4, + -25, -38, -46, -50, -49, -43, -33, -23, -11, 3, 14, 19, 16, 8, 0, -2, + -2, 0, -8, -19, -27, -30, -25, -22, -20, -20, -22, -25, -24, -16, 1, 22, + 43, 56, 62, 67, 68, 65, 60, 46, 24, -3, -25, -40, -45, -49, -50, -46, + -37, -23, -10, 1, 12, 20, 20, 14, 7, 2, 3, 3, -4, -15, -26, -31, + -30, -27, -26, -26, -29, -33, -33, -25, -8, 17, 41, 57, 65, 71, 73, 73, + 66, 53, 33, 5, -23, -41, -48, -50, -48, -48, -40, -30, -14, 1, 12, 21, + 24, 18, 13, 6, 5, 5, 0, -11, -25, -37, -39, -35, -31, -31, -33, -38, + -37, -29, -12, 15, 40, 59, 67, 71, 72, 73, 69, 59, 39, 14, -16, -38, + -50, -51, -50, -48, -45, -36, -21, -4, 12, 25, 30, 25, 18, 11, 11, 10, + 6, -8, -25, -39, -46, -42, -38, -37, -37, -40, -42, -34, -15, 13, 40, 57, + 66, 71, 72, 72, 69, 61, 45, 19, -10, -34, -46, -48, -47, -45, -45, -41, + -28, -12, 7, 23, 27, 25, 18, 15, 17, 17, 12, 1, -20, -37, -47, -50, + -46, -45, -44, -45, -46, -41, -21, 7, 37, 60, 69, 73, 72, 72, 72, 67, + 52, 25, -6, -33, -47, -50, -47, -47, -47, -45, -35, -16, 6, 23, 31, 30, + 24, 23, 24, 25, 18, 4, -15, -33, -50, -56, -57, -53, -48, -49, -49, -45, + -29, 2, 35, 58, 68, 71, 72, 74, 73, 68, 56, 34, 5, -26, -43, -48, + -45, -42, -46, -46, -41, -24, 0, 21, 33, 34, 31, 25, 27, 27, 19, 6, + -14, -36, -55, -64, -64, -60, -50, -47, -45, -44, -31, -4, 32, 58, 71, 72, + 68, 70, 70, 66, 57, 36, 11, -20, -43, -50, -48, -41, -37, -42, -40, -28, + -5, 21, 36, 38, 34, 26, 29, 28, 20, 8, -13, -33, -52, -68, -69, -65, + -55, -49, -47, -44, -31, -3, 30, 55, 67, 70, 68, 70, 70, 65, 57, 39, + 15, -13, -38, -49, -47, -40, -35, -39, -41, -30, -9, 17, 37, 44, 45, 38, + 32, 29, 22, 9, -10, -34, -54, -70, -75, -73, -64, -52, -45, -43, -31, -7, + 25, 53, 67, 72, 70, 72, 70, 62, 53, 38, 16, -10, -32, -49, -50, -43, + -35, -33, -36, -29, -10, 16, 35, 46, 46, 41, 35, 30, 23, 10, -10, -34, + -53, -69, -75, -74, -66, -53, -45, -42, -34, -13, 17, 46, 63, 68, 66, 63, + 65, 63, 54, 43, 24, 0, -20, -40, -43, -42, -36, -32, -32, -28, -16, 7, + 29, 47, 52, 47, 39, 31, 21, 10, -9, -30, -50, -66, -78, -77, -71, -59, + -49, -42, -34, -17, 9, 37, 56, 66, 66, 62, 62, 61, 56, 45, 30, 7, + -13, -31, -39, -40, -36, -33, -32, -28, -18, 1, 21, 41, 54, 52, 44, 36, + 26, 13, -8, -29, -48, -66, -76, -80, -74, -64, -55, -45, -34, -18, 5, 29, + 50, 65, 68, 66, 64, 60, 59, 47, 33, 15, -5, -23, -37, -43, -41, -37, + -35, -31, -21, -4, 16, 36, 52, 59, 54, 45, 33, 17, -5, -25, -45, -60, + -74, -83, -82, -71, -59, -49, -37, -23, -2, 22, 43, 59, 66, 65, 64, 60, + 58, 50, 39, 23, 2, -17, -32, -39, -40, -38, -35, -32, -23, -6, 14, 33, + 49, 59, 58, 49, 34, 16, -5, -25, -43, -60, -74, -83, -83, -76, -63, -53, + -40, -24, -5, 16, 36, 54, 65, 67, 65, 61, 57, 52, 43, 27, 9, -12, + -26, -37, -40, -39, -36, -32, -28, -13, 6, 27, 46, 58, 60, 52, 39, 23, + 5, -16, -36, -53, -66, -77, -84, -81, -72, -60, -45, -32, -15, 5, 25, 48, + 62, 69, 71, 69, 65, 58, 50, 34, 16, -6, -24, -36, -42, -45, -44, -39, + -33, -21, -2, 22, 43, 59, 64, 60, 47, 34, 17, -6, -28, -50, -66, -76, + -84, -86, -82, -72, -57, -40, -21, -2, 21, 42, 58, 66, 73, 76, 71, 64, + 53, 40, 26, 4, -17, -34, -45, -49, -48, -43, -38, -28, -10, 15, 40, 58, + 66, 64, 56, 42, 25, 4, -21, -44, -62, -73, -81, -87, -86, -78, -65, -47, + -31, -9, 15, 34, 52, 62, 72, 79, 80, 72, 61, 49, 34, 12, -12, -32, + -43, -49, -54, -55, -48, -36, -16, 10, 35, 56, 67, 71, 67, 54, 38, 15, + -10, -34, -57, -72, -85, -93, -97, -89, -76, -59, -40, -20, 8, 32, 50, 67, + 77, 87, 89, 81, 66, 52, 35, 16, -6, -30, -47, -58, -61, -57, -50, -37, + -19, 6, 29, 51, 65, 73, 73, 62, 44, 18, -6, -28, -49, -67, -81, -93, + -97, -94, -83, -65, -47, -28, -5, 19, 42, 61, 76, 87, 90, 88, 80, 66, + 48, 27, 3, -17, -40, -56, -65, -66, -58, -49, -30, -6, 17, 41, 59, 71, + 77, 70, 56, 36, 11, -13, -34, -53, -71, -89, -98, -100, -94, -79, -62, -44, + -21, 3, 27, 52, 74, 90, 98, 95, 86, 75, 59, 37, 12, -14, -35, -54, + -64, -67, -64, -51, -34, -10, 11, 32, 50, 65, 73, 71, 58, 37, 14, -10, + -29, -48, -64, -81, -93, -98, -94, -82, -63, -45, -26, -5, 16, 40, 65, 83, + 94, 94, 84, 75, 63, 46, 23, -3, -27, -47, -58, -64, -64, -56, -39, -17, + 3, 20, 38, 57, 71, 72, 61, 45, 24, 1, -19, -37, -56, -73, -91, -99, + -100, -92, -74, -53, -34, -16, 7, 31, 59, 82, 97, 101, 92, 78, 65, 48, + 29, 6, -21, -43, -55, -64, -66, -58, -40, -18, 3, 17, 32, 51, 69, 71, + 62, 45, 27, 6, -15, -34, -50, -64, -81, -93, -99, -96, -80, -59, -40, -23, + -4, 21, 50, 77, 94, 100, 93, 81, 67, 53, 36, 14, -12, -36, -53, -58, + -63, -56, -42, -22, -5, 10, 23, 42, 63, 70, 62, 47, 29, 13, -6, -27, + -43, -57, -72, -84, -98, -99, -87, -66, -44, -27, -11, 10, 38, 67, 91, 99, + 92, 82, 70, 57, 41, 21, -3, -27, -47, -58, -63, -58, -44, -23, -5, 7, + 17, 35, 55, 66, 61, 46, 29, 13, -4, -22, -39, -51, -65, -78, -90, -95, + -85, -69, -47, -30, -12, 9, 30, 57, 83, 96, 91, 81, 67, 57, 42, 26, + 6, -18, -39, -55, -62, -58, -43, -24, -8, 2, 14, 30, 47, 60, 60, 49, + 34, 17, 0, -16, -31, -43, -58, -71, -86, -93, -86, -72, -52, -32, -15, 3, + 22, 48, 76, 90, 89, 78, 69, 59, 46, 32, 14, -6, -27, -47, -57, -56, + -45, -29, -12, -5, 4, 18, 37, 54, 58, 51, 36, 21, 6, -8, -20, -33, + -52, -68, -84, -90, -85, -74, -58, -42, -22, 0, 20, 42, 67, 83, 87, 80, + 68, 58, 47, 34, 19, 0, -20, -40, -52, -53, -45, -27, -13, -4, 6, 17, + 33, 47, 53, 52, 38, 21, 3, -11, -24, -35, -50, -65, -80, -89, -85, -71, + -55, -39, -21, -2, 20, 39, 59, 74, 81, 75, 67, 57, 47, 38, 23, 4, + -17, -32, -43, -45, -39, -26, -14, -4, 4, 12, 26, 38, 47, 48, 35, 19, + 4, -10, -20, -29, -41, -56, -71, -78, -81, -71, -56, -43, -23, -6, 15, 35, + 49, 62, 72, 69, 63, 54, 45, 41, 28, 11, -11, -27, -37, -40, -35, -24, + -17, -7, 2, 9, 22, 35, 46, 49, 37, 21, 4, -9, -18, -27, -41, -55, + -71, -79, -79, -70, -53, -38, -23, -8, 9, 31, 46, 58, 63, 63, 59, 52, + 45, 40, 32, 14, -6, -24, -32, -31, -30, -23, -18, -12, 1, 9, 21, 31, + 41, 44, 33, 21, 5, -6, -20, -29, -43, -57, -69, -77, -73, -65, -52, -41, + -27, -8, 11, 32, 49, 57, 64, 61, 55, 47, 39, 36, 29, 13, -8, -25, + -36, -35, -26, -16, -9, -5, 1, 9, 22, 36, 45, 43, 33, 17, 1, -11, + -21, -32, -45, -57, -71, -78, -73, -61, -45, -33, -23, -8, 11, 31, 46, 53, + 57, 54, 48, 40, 34, 31, 27, 14, -4, -20, -29, -28, -22, -12, -4, 1, + 4, 8, 21, 34, 43, 43, 31, 17, 1, -11, -22, -31, -44, -59, -72, -78, + -70, -54, -40, -28, -19, -8, 10, 28, 45, 53, 57, 53, 43, 34, 28, 27, + 26, 18, 0, -18, -31, -29, -20, -11, -3, 2, 5, 10, 19, 31, 43, 44, + 34, 19, 2, -13, -23, -32, -43, -55, -68, -77, -73, -57, -41, -26, -15, -6, + 11, 28, 43, 52, 52, 49, 41, 33, 24, 22, 21, 14, 1, -14, -25, -24, + -18, -7, -2, 2, 7, 10, 20, 31, 40, 43, 33, 18, 3, -13, -24, -35, + -44, -55, -70, -78, -74, -59, -40, -26, -11, 1, 13, 29, 44, 53, 57, 54, + 45, 32, 24, 18, 13, 9, -4, -16, -26, -29, -22, -10, 1, 8, 13, 18, + 23, 35, 42, 45, 37, 21, 5, -14, -30, -41, -49, -57, -69, -77, -76, -61, + -39, -20, -5, 9, 20, 34, 47, 53, 55, 48, 39, 27, 14, 8, 3, 2, + -4, -15, -23, -24, -16, -3, 6, 11, 19, 24, 30, 34, 41, 43, 35, 18, + 1, -17, -31, -44, -52, -59, -68, -75, -73, -61, -38, -19, 1, 13, 23, 30, + 42, 52, 52, 47, 36, 23, 14, 7, 4, 0, -6, -11, -20, -24, -18, -5, + 7, 15, 18, 22, 28, 36, 43, 43, 38, 24, 4, -13, -30, -44, -55, -64, + -69, -77, -76, -65, -44, -19, 1, 15, 27, 35, 46, 53, 53, 46, 36, 23, + 11, 3, -5, -7, -9, -14, -20, -23, -19, -7, 11, 18, 21, 25, 30, 40, + 43, 43, 38, 24, 7, -14, -30, -41, -55, -65, -73, -77, -74, -66, -49, -24, + -2, 17, 29, 35, 44, 51, 54, 49, 35, 23, 11, 1, -6, -12, -15, -16, + -20, -24, -21, -10, 8, 21, 27, 33, 35, 42, 48, 47, 37, 23, 7, -12, + -28, -44, -60, -69, -75, -78, -74, -65, -49, -25, -2, 17, 30, 40, 48, 54, + 55, 48, 36, 20, 6, -4, -9, -14, -20, -22, -24, -21, -15, -6, 7, 21, + 32, 39, 43, 44, 49, 50, 38, 21, 4, -13, -28, -47, -62, -74, -77, -78, + -77, -65, -48, -26, -4, 15, 28, 40, 50, 56, 54, 46, 33, 20, 9, -2, + -10, -16, -21, -21, -23, -21, -15, -5, 9, 19, 30, 38, 42, 44, 46, 47, + 36, 22, 6, -10, -23, -39, -57, -74, -78, -79, -75, -65, -51, -33, -11, 9, + 25, 37, 46, 55, 56, 48, 34, 21, 10, 4, -4, -14, -20, -25, -24, -21, + -12, -3, 8, 17, 26, 36, 47, 50, 50, 47, 36, 25, 10, -5, -21, -40, + -57, -75, -82, -79, -75, -64, -51, -37, -16, 5, 25, 40, 48, 55, 55, 49, + 37, 25, 15, 6, -6, -18, -26, -29, -25, -20, -16, -7, 5, 17, 29, 39, + 49, 56, 56, 51, 39, 28, 15, 0, -17, -38, -58, -75, -86, -86, -80, -70, + -54, -37, -16, 7, 25, 42, 50, 55, 58, 52, 40, 25, 11, 2, -5, -14, + -21, -26, -26, -18, -12, -5, 4, 13, 25, 34, 45, 53, 55, 48, 39, 25, + 16, 3, -13, -31, -54, -70, -83, -85, -78, -68, -55, -38, -20, 1, 20, 36, + 46, 51, 55, 48, 39, 27, 17, 7, -5, -13, -20, -23, -23, -18, -10, -4, + 3, 10, 21, 29, 40, 48, 52, 50, 40, 28, 20, 10, -5, -24, -48, -67, + -82, -87, -81, -73, -56, -44, -25, -5, 15, 34, 46, 52, 55, 51, 39, 27, + 18, 7, -2, -13, -22, -25, -24, -16, -9, 1, 8, 13, 22, 30, 42, 48, + 50, 47, 38, 26, 15, 6, -8, -22, -41, -61, -77, -86, -81, -70, -54, -40, + -27, -8, 12, 31, 42, 49, 50, 48, 38, 26, 16, 7, -4, -11, -18, -22, + -21, -16, -9, 0, 9, 15, 21, 26, 35, 47, 50, 46, 36, 28, 18, 7, + -7, -22, -37, -53, -70, -81, -83, -72, -58, -43, -30, -14, 5, 22, 37, 44, + 46, 44, 37, 26, 17, 8, 2, -7, -12, -17, -16, -12, -6, 3, 8, 13, + 17, 22, 31, 42, 43, 43, 35, 29, 25, 14, 2, -17, -35, -51, -65, -77, + -80, -75, -63, -47, -34, -18, 4, 21, 32, 38, 41, 41, 36, 28, 17, 8, + 1, -9, -12, -16, -15, -9, -2, 8, 13, 15, 17, 23, 28, 39, 43, 38, + 30, 21, 17, 11, 4, -12, -28, -45, -60, -68, -71, -66, -58, -49, -38, -23, + -5, 15, 27, 34, 34, 32, 28, 23, 18, 13, 4, -2, -7, -9, -7, -4, + 5, 14, 16, 16, 14, 15, 24, 35, 39, 35, 23, 17, 15, 11, 8, -4, + -19, -37, -53, -62, -65, -62, -57, -53, -43, -31, -14, 5, 19, 27, 31, 28, + 26, 23, 20, 18, 11, 5, -2, -5, 0, 3, 8, 14, 16, 15, 11, 7, + 12, 23, 32, 32, 21, 12, 10, 13, 12, 6, -9, -27, -43, -50, -55, -53, + -51, -52, -44, -38, -23, -6, 7, 18, 22, 19, 16, 15, 16, 19, 17, 12, + 6, 3, 7, 10, 16, 20, 23, 20, 14, 8, 9, 17, 27, 26, 17, 6, + 3, 7, 10, 7, -5, -18, -32, -41, -46, -45, -45, -45, -44, -40, -30, -16, + -3, 8, 15, 12, 10, 11, 16, 19, 19, 16, 12, 10, 11, 15, 20, 25, + 26, 24, 18, 11, 6, 11, 17, 21, 15, 3, -6, -2, 4, 7, 2, -14, + -25, -32, -36, -38, -37, -37, -35, -33, -33, -25, -15, -4, 3, 4, 0, -3, + 2, 13, 21, 21, 20, 17, 19, 23, 27, 31, 33, 31, 24, 16, 4, 2, + 7, 13, 13, 3, -10, -9, 0, 8, 7, -3, -15, -22, -24, -30, -32, -37, + -39, -38, -37, -34, -28, -17, -8, -2, -4, -4, 4, 16, 26, 30, 26, 22, + 22, 25, 29, 31, 30, 29, 24, 17, 6, -2, 7, 10, 13, 4, -11, -15, + -10, 3, 8, 2, -10, -17, -17, -17, -23, -29, -35, -37, -34, -36, -35, -28, + -19, -10, -11, -14, -8, 8, 21, 26, 26, 21, 24, 31, 38, 40, 38, 37, + 33, 26, 15, 4, 1, 2, 1, -6, -19, -24, -18, -7, 2, 5, -4, -10, + -9, -6, -7, -16, -27, -33, -35, -38, -41, -38, -32, -22, -20, -18, -10, 4, + 20, 29, 31, 30, 28, 32, 38, 43, 42, 39, 34, 28, 14, 4, 1, 3, + 4, -5, -21, -30, -26, -14, 1, 3, -4, -8, -8, 0, 0, -8, -15, -26, + -29, -35, -40, -40, -36, -30, -28, -29, -22, -10, 9, 22, 28, 28, 27, 30, + 39, 46, 50, 50, 43, 33, 21, 9, 3, 3, 1, -10, -22, -35, -34, -22, + -8, 2, 0, -6, -7, 0, 5, -2, -9, -18, -28, -34, -41, -43, -39, -35, + -33, -33, -25, -12, 5, 19, 26, 29, 31, 31, 39, 46, 51, 52, 47, 38, + 27, 18, 10, 5, -3, -13, -22, -33, -36, -28, -16, -4, -2, -4, -6, 0, + 8, 7, 0, -12, -22, -33, -40, -42, -39, -37, -38, -39, -32, -17, 2, 15, + 24, 25, 28, 33, 39, 47, 51, 53, 51, 44, 35, 23, 15, 8, 1, -12, + -25, -37, -41, -33, -22, -11, -4, -5, -3, 3, 10, 13, 6, -5, -17, -28, + -38, -43, -44, -44, -44, -43, -36, -23, -7, 7, 20, 26, 29, 35, 43, 51, + 54, 58, 56, 52, 44, 29, 18, 9, -2, -12, -28, -39, -45, -38, -26, -16, + -7, -3, 1, 6, 12, 15, 12, 3, -11, -25, -37, -41, -43, -46, -47, -46, + -39, -28, -15, 0, 11, 21, 25, 31, 38, 46, 53, 60, 62, 59, 53, 42, + 32, 19, 6, -10, -27, -41, -47, -47, -39, -31, -21, -9, -2, 5, 11, 16, + 19, 13, 2, -15, -30, -35, -37, -43, -47, -49, -42, -32, -21, -11, 0, 8, + 19, 27, 38, 47, 51, 58, 63, 63, 59, 50, 41, 28, 10, -9, -26, -37, + -43, -44, -40, -33, -23, -11, 0, 6, 9, 14, 15, 13, 1, -15, -25, -32, + -34, -43, -49, -50, -43, -30, -20, -13, -9, 0, 10, 23, 36, 46, 52, 55, + 62, 65, 66, 61, 51, 36, 15, -7, -24, -34, -42, -45, -46, -42, -34, -20, + -5, 5, 11, 14, 16, 13, 2, -10, -18, -24, -31, -39, -49, -48, -42, -34, + -24, -18, -15, -8, 2, 13, 29, 42, 51, 57, 62, 65, 70, 69, 60, 45, + 20, -3, -24, -37, -43, -46, -49, -48, -39, -24, -6, 5, 12, 17, 20, 16, + 6, -9, -15, -21, -26, -38, -50, -56, -50, -37, -26, -23, -19, -14, -4, 11, + 27, 42, 54, 58, 63, 65, 68, 70, 63, 50, 26, 1, -21, -37, -43, -44, + -44, -44, -40, -28, -11, 5, 10, 16, 18, 14, 5, -12, -19, -22, -24, -33, + -47, -52, -52, -38, -25, -17, -17, -16, -10, 4, 22, 39, 53, 59, 62, 63, + 66, 68, 66, 55, 32, 9, -17, -34, -43, -42, -39, -38, -38, -31, -19, -3, + 10, 17, 19, 12, 3, -12, -21, -24, -24, -31, -40, -49, -52, -41, -30, -18, + -15, -17, -10, 0, 16, 33, 47, 59, 65, 64, 65, 67, 63, 56, 38, 13, + -12, -32, -41, -39, -35, -33, -32, -27, -17, -4, 8, 15, 16, 13, 4, -11, + -20, -25, -27, -32, -40, -48, -52, -46, -37, -25, -18, -16, -10, 1, 16, 33, + 49, 59, 66, 67, 65, 66, 62, 51, 38, 15, -9, -30, -38, -41, -33, -29, + -26, -23, -17, -5, 7, 16, 15, 14, 5, -9, -19, -27, -31, -34, -40, -47, + -52, -49, -40, -30, -22, -16, -8, 4, 19, 32, 46, 59, 67, 71, 69, 64, + 57, 49, 36, 17, -7, -27, -38, -40, -35, -28, -23, -19, -12, -5, 6, 12, + 16, 15, 10, -5, -19, -28, -32, -36, -39, -46, -53, -52, -45, -34, -25, -18, + -7, 6, 20, 33, 46, 60, 67, 74, 71, 65, 56, 46, 37, 18, -2, -20, + -33, -38, -38, -30, -22, -16, -12, -6, 2, 6, 15, 15, 11, 1, -11, -19, + -31, -37, -42, -46, -51, -54, -53, -46, -35, -26, -14, 3, 17, 33, 45, 57, + 67, 75, 77, 71, 62, 50, 36, 18, 0, -19, -31, -36, -37, -31, -23, -17, + -11, -6, 1, 6, 11, 15, 14, 8, -3, -16, -27, -37, -41, -47, -52, -58, + -60, -55, -46, -32, -16, 0, 17, 32, 46, 59, 70, 79, 80, 75, 65, 51, + 35, 20, 2, -15, -27, -38, -42, -36, -27, -17, -10, -4, 3, 7, 12, 18, + 19, 14, 5, -7, -22, -37, -46, -53, -57, -62, -67, -65, -58, -43, -22, 1, + 20, 35, 48, 60, 69, 79, 82, 79, 68, 53, 36, 21, 4, -11, -24, -36, + -40, -38, -31, -21, -14, -5, 1, 5, 11, 17, 22, 19, 14, -2, -17, -35, + -48, -55, -63, -67, -73, -72, -64, -49, -27, -4, 19, 36, 52, 64, 73, 81, + 85, 82, 72, 56, 36, 20, 3, -14, -24, -33, -36, -35, -32, -22, -13, -6, + 2, 7, 10, 15, 19, 19, 17, 6, -10, -29, -48, -58, -67, -71, -75, -78, + -72, -58, -35, -10, 16, 35, 52, 65, 74, 80, 86, 87, 79, 62, 39, 21, + 5, -11, -22, -33, -39, -39, -34, -25, -15, -7, 3, 8, 16, 17, 21, 22, + 19, 9, -6, -27, -47, -60, -71, -77, -80, -81, -73, -61, -39, -12, 16, 36, + 52, 63, 73, 80, 85, 87, 76, 59, 41, 23, 8, -7, -18, -29, -36, -38, + -33, -23, -13, -8, 1, 6, 14, 18, 19, 23, 23, 17, 1, -20, -43, -57, + -67, -78, -83, -89, -81, -67, -45, -19, 9, 35, 55, 67, 74, 80, 87, 91, + 83, 68, 44, 24, 6, -9, -21, -29, -36, -39, -39, -31, -20, -10, 1, 13, + 20, 26, 26, 27, 28, 22, 8, -16, -40, -60, -75, -86, -93, -95, -89, -75, + -52, -24, 7, 37, 57, 69, 77, 83, 90, 93, 85, 70, 48, 27, 8, -8, + -19, -26, -32, -35, -39, -37, -28, -17, -2, 9, 19, 21, 27, 31, 32, 29, + 12, -9, -32, -54, -71, -86, -94, -96, -90, -82, -62, -33, 2, 34, 56, 69, + 78, 87, 94, 94, 85, 69, 49, 29, 9, -10, -21, -27, -30, -33, -37, -36, + -29, -17, -5, 9, 19, 25, 27, 31, 33, 33, 21, -2, -25, -51, -71, -86, + -95, -95, -92, -85, -69, -42, -8, 27, 52, 67, 74, 83, 92, 95, 89, 75, + 56, 35, 16, -6, -17, -26, -28, -34, -41, -39, -37, -25, -9, 6, 20, 28, + 31, 37, 37, 34, 24, 3, -20, -46, -69, -85, -96, -99, -97, -89, -73, -47, + -11, 21, 45, 61, 73, 84, 92, 95, 89, 77, 61, 41, 20, -2, -13, -20, + -28, -36, -43, -46, -40, -30, -16, 0, 12, 24, 30, 38, 43, 41, 33, 13, + -14, -39, -63, -80, -93, -98, -100, -94, -76, -52, -19, 14, 38, 56, 70, 80, + 90, 94, 88, 75, 58, 40, 22, 6, -8, -19, -25, -33, -39, -41, -38, -31, + -19, -5, 7, 21, 31, 39, 45, 42, 32, 15, -8, -32, -55, -77, -93, -102, + -101, -94, -80, -57, -29, 5, 34, 54, 70, 78, 88, 96, 92, 80, 62, 41, + 24, 8, -9, -21, -32, -35, -38, -41, -39, -35, -22, -6, 6, 21, 31, 39, + 46, 44, 35, 18, -5, -27, -49, -70, -86, -97, -102, -96, -84, -58, -30, -2, + 26, 45, 62, 74, 82, 89, 89, 80, 66, 46, 28, 12, -3, -14, -26, -36, + -39, -42, -40, -36, -28, -15, 0, 17, 30, 37, 45, 48, 40, 23, 3, -20, + -43, -64, -81, -93, -98, -96, -85, -65, -38, -8, 20, 40, 55, 68, 80, 88, + 88, 82, 68, 54, 35, 18, 2, -12, -24, -35, -40, -45, -45, -41, -33, -20, + -4, 15, 31, 41, 49, 52, 48, 32, 13, -14, -38, -59, -77, -92, -101, -102, + -91, -70, -45, -15, 15, 38, 53, 65, 77, 89, 91, 85, 71, 52, 38, 21, + 5, -12, -26, -36, -42, -45, -45, -43, -34, -22, -7, 9, 26, 39, 50, 56, + 50, 34, 14, -7, -29, -50, -69, -84, -96, -98, -90, -72, -50, -24, 7, 32, + 48, 57, 68, 84, 91, 88, 74, 58, 44, 30, 11, -9, -26, -38, -41, -46, + -45, -44, -38, -23, -7, 9, 24, 36, 49, 55, 51, 35, 18, -3, -24, -45, + -64, -78, -89, -93, -90, -75, -54, -29, 0, 23, 42, 54, 67, 80, 90, 91, + 81, 65, 48, 31, 13, -5, -24, -41, -50, -53, -51, -46, -42, -28, -10, 8, + 23, 36, 50, 59, 56, 44, 26, 8, -13, -35, -56, -77, -89, -94, -92, -80, + -61, -39, -11, 14, 33, 50, 63, 77, 88, 89, 81, 67, 54, 38, 21, 1, + -23, -39, -50, -54, -53, -46, -42, -31, -17, 1, 17, 33, 46, 56, 56, 46, + 33, 16, -4, -24, -46, -67, -82, -92, -94, -87, -67, -45, -19, 4, 22, 43, + 62, 76, 87, 90, 87, 76, 59, 40, 20, 1, -22, -40, -55, -62, -58, -50, + -40, -29, -17, -3, 14, 33, 49, 59, 58, 49, 35, 21, 2, -17, -39, -59, + -76, -90, -93, -86, -70, -49, -29, -8, 12, 33, 57, 75, 84, 87, 84, 78, + 65, 47, 28, 6, -18, -39, -58, -65, -64, -57, -44, -33, -22, -10, 6, 26, + 44, 56, 56, 48, 40, 27, 11, -8, -30, -49, -65, -80, -86, -87, -72, -51, + -31, -13, 5, 24, 48, 70, 81, 86, 83, 79, 69, 51, 30, 8, -16, -37, + -55, -65, -67, -61, -48, -36, -21, -10, 5, 22, 40, 55, 58, 53, 43, 31, + 16, -2, -23, -45, -60, -74, -82, -86, -75, -56, -36, -16, 1, 21, 44, 65, + 81, 88, 85, 81, 72, 54, 33, 8, -18, -41, -58, -71, -74, -70, -56, -41, + -23, -6, 8, 23, 38, 53, 60, 59, 50, 37, 22, 1, -20, -41, -56, -69, + -79, -83, -78, -62, -42, -20, 2, 22, 41, 59, 77, 86, 87, 79, 67, 50, + 31, 10, -15, -36, -52, -63, -69, -69, -59, -41, -23, -9, 4, 15, 29, 44, + 55, 56, 53, 43, 27, 12, -8, -27, -44, -57, -68, -78, -77, -67, -48, -29, + -12, 12, 32, 52, 70, 79, 84, 82, 73, 59, 38, 15, -9, -33, -52, -63, + -71, -72, -66, -50, -30, -13, 2, 12, 27, 42, 50, 54, 54, 46, 34, 19, + -2, -19, -35, -47, -61, -71, -72, -66, -51, -36, -19, 5, 27, 46, 63, 74, + 79, 79, 70, 58, 41, 21, 3, -24, -44, -58, -66, -66, -65, -52, -36, -22, + -10, 4, 18, 34, 43, 49, 52, 48, 43, 31, 14, -4, -21, -35, -51, -61, + -66, -64, -56, -43, -29, -8, 16, 37, 54, 67, 72, 74, 70, 61, 46, 27, + 7, -19, -40, -56, -62, -62, -63, -55, -43, -26, -10, 3, 13, 26, 38, 44, + 47, 43, 39, 30, 19, 5, -12, -24, -40, -47, -51, -53, -51, -44, -32, -14, + 6, 24, 41, 54, 61, 63, 61, 56, 47, 32, 13, -9, -31, -46, -56, -53, + -54, -54, -48, -37, -18, -3, 8, 17, 27, 33, 38, 39, 39, 37, 30, 18, + 1, -16, -29, -35, -39, -42, -47, -47, -39, -22, -3, 14, 29, 42, 51, 57, + 56, 54, 45, 36, 20, -2, -23, -41, -50, -51, -52, -53, -51, -42, -27, -8, + 5, 12, 19, 28, 35, 40, 39, 40, 37, 28, 12, -7, -23, -28, -30, -37, + -43, -49, -45, -32, -15, 3, 19, 34, 45, 49, 49, 51, 47, 41, 26, 6, + -18, -34, -43, -45, -45, -48, -51, -49, -33, -15, -2, 8, 12, 19, 26, 33, + 38, 38, 38, 34, 25, 8, -11, -19, -20, -23, -32, -43, -48, -41, -24, -8, + 10, 21, 31, 38, 43, 47, 48, 45, 34, 16, -9, -31, -41, -42, -42, -46, + -52, -52, -40, -23, -6, 6, 11, 17, 24, 30, 35, 38, 39, 40, 29, 14, + -3, -14, -14, -15, -24, -36, -47, -45, -33, -15, 3, 14, 23, 29, 35, 39, + 44, 45, 38, 22, -3, -26, -38, -37, -37, -41, -50, -56, -45, -26, -8, 5, + 12, 16, 22, 27, 32, 39, 41, 41, 33, 17, 1, -9, -8, -8, -16, -30, + -41, -45, -35, -21, -5, 10, 18, 24, 28, 31, 38, 42, 39, 25, 2, -23, + -36, -36, -37, -39, -47, -53, -47, -31, -11, 3, 12, 16, 23, 27, 32, 37, + 40, 41, 33, 18, 2, -7, -8, -6, -10, -23, -36, -41, -35, -20, -6, 7, + 14, 17, 24, 29, 36, 42, 40, 28, 5, -20, -35, -38, -38, -39, -45, -51, + -46, -33, -15, 2, 13, 22, 27, 28, 27, 30, 37, 41, 35, 20, 5, -4, + -4, -2, -3, -13, -28, -35, -32, -23, -10, 3, 11, 14, 14, 20, 28, 37, + 40, 27, 7, -16, -31, -36, -37, -36, -41, -44, -45, -35, -18, 1, 12, 19, + 25, 26, 27, 31, 34, 39, 34, 20, 8, 0, 0, 1, 0, -9, -23, -33, + -34, -24, -10, 2, 8, 8, 10, 16, 27, 34, 35, 27, 10, -10, -27, -35, + -35, -34, -39, -46, -47, -38, -22, -3, 10, 19, 26, 31, 32, 32, 35, 41, + 39, 25, 9, -2, -3, -2, -2, -7, -19, -30, -33, -26, -14, -3, 6, 6, + 7, 12, 26, 37, 37, 26, 10, -8, -25, -35, -39, -39, -42, -47, -49, -42, + -27, -4, 12, 20, 29, 33, 36, 35, 35, 38, 37, 27, 10, -3, -6, -3, + -2, -7, -16, -24, -28, -24, -13, -4, 4, 5, 7, 9, 19, 30, 33, 28, + 12, -6, -24, -35, -40, -39, -42, -47, -47, -41, -26, -8, 10, 22, 31, 36, + 41, 39, 34, 33, 33, 29, 15, 2, -7, -8, -6, -6, -10, -18, -24, -24, + -15, -5, 6, 7, 7, 10, 17, 23, 23, 18, 9, -7, -23, -36, -42, -41, + -41, -45, -45, -39, -28, -11, 7, 21, 31, 36, 39, 39, 34, 31, 33, 29, + 19, 7, -5, -6, -6, -4, -6, -13, -17, -20, -16, -8, 1, 6, 7, 7, + 11, 16, 20, 18, 9, -7, -24, -37, -43, -42, -42, -42, -45, -41, -28, -11, + 7, 19, 28, 35, 40, 42, 38, 33, 29, 27, 21, 10, -2, -8, -8, -6, + -8, -11, -13, -16, -14, -8, 1, 5, 8, 9, 15, 19, 20, 18, 9, -4, + -18, -34, -42, -46, -47, -45, -47, -45, -36, -20, 0, 13, 26, 36, 45, 48, + 42, 35, 29, 28, 26, 20, 6, -6, -10, -10, -6, -7, -8, -10, -14, -10, + -7, 0, 6, 8, 13, 14, 16, 13, 7, -3, -13, -27, -37, -44, -49, -44, + -42, -40, -37, -25, -9, 9, 23, 31, 41, 44, 44, 37, 30, 27, 28, 27, + 15, 2, -7, -9, -6, -7, -9, -8, -13, -12, -8, -3, 4, 9, 13, 14, + 14, 11, 6, 0, -9, -23, -34, -43, -49, -46, -42, -40, -35, -29, -13, 3, + 19, 31, 41, 45, 43, 37, 31, 29, 30, 28, 19, 4, -5, -7, -7, -5, + -8, -7, -9, -11, -9, -4, 0, 6, 12, 14, 13, 9, 5, -3, -9, -19, + -28, -37, -48, -48, -45, -39, -34, -30, -18, -5, 12, 23, 34, 42, 44, 39, + 34, 32, 31, 33, 30, 18, 8, 1, -5, -6, -5, -5, -8, -13, -16, -14, + -7, 2, 7, 11, 10, 7, 4, -2, -7, -12, -22, -32, -45, -50, -45, -38, + -33, -30, -24, -13, 2, 20, 31, 39, 43, 42, 38, 36, 33, 33, 33, 24, + 14, 1, -8, -9, -7, -4, -5, -11, -16, -16, -11, -4, 2, 9, 8, 7, + 3, -3, -6, -9, -15, -24, -38, -47, -48, -42, -35, -32, -29, -21, -9, 11, + 27, 35, 42, 42, 42, 40, 40, 38, 36, 30, 19, 8, -4, -9, -8, -5, + -5, -12, -18, -20, -15, -5, -2, 3, 4, 5, 6, 1, -3, -8, -12, -19, + -31, -43, -47, -43, -36, -35, -36, -32, -19, 2, 19, 30, 38, 42, 46, 49, + 50, 47, 43, 39, 28, 16, 1, -10, -13, -11, -9, -14, -21, -25, -20, -10, + -4, 1, 3, 4, 7, 4, -3, -7, -7, -10, -23, -38, -47, -46, -41, -37, + -38, -37, -27, -11, 11, 24, 33, 38, 45, 50, 53, 52, 48, 43, 37, 25, + 10, -3, -11, -11, -11, -13, -20, -27, -29, -22, -14, -7, -2, 2, 6, 3, + -2, -3, 0, 0, -11, -28, -41, -45, -39, -35, -36, -39, -37, -24, -7, 11, + 22, 32, 41, 51, 55, 56, 54, 53, 50, 40, 23, 6, -5, -10, -11, -14, + -20, -28, -34, -33, -25, -16, -10, -5, 0, 0, 1, 2, 4, 5, -4, -16, + -29, -35, -37, -37, -35, -39, -39, -32, -19, 0, 13, 23, 36, 46, 54, 58, + 57, 59, 56, 47, 33, 16, 3, -5, -9, -11, -19, -29, -36, -39, -33, -26, + -18, -12, -7, -5, -2, 4, 11, 15, 10, -3, -18, -29, -32, -35, -36, -41, + -44, -40, -30, -18, 0, 13, 28, 41, 50, 59, 63, 66, 66, 60, 44, 26, + 11, 2, -6, -12, -19, -29, -38, -44, -41, -33, -25, -16, -9, -8, -6, 1, + 11, 18, 16, 8, -6, -17, -27, -32, -36, -39, -43, -44, -37, -30, -12, 8, + 26, 39, 46, 56, 64, 70, 72, 66, 51, 36, 18, 7, -4, -11, -18, -29, + -42, -50, -51, -45, -35, -23, -14, -10, -9, 0, 14, 27, 29, 20, 7, -5, + -15, -23, -30, -38, -45, -50, -49, -43, -30, -9, 13, 31, 41, 52, 65, 75, + 79, 77, 66, 50, 30, 13, 3, -6, -14, -26, -41, -53, -57, -54, -44, -32, + -23, -17, -13, -5, 10, 24, 31, 28, 20, 9, -5, -17, -26, -35, -40, -48, + -54, -53, -44, -23, 0, 21, 35, 46, 60, 73, 81, 83, 77, 60, 42, 25, + 11, 1, -11, -25, -42, -57, -64, -62, -54, -43, -33, -24, -17, -6, 9, 23, + 37, 37, 33, 19, 6, -9, -20, -30, -41, -49, -57, -59, -54, -38, -16, 10, + 31, 46, 58, 70, 78, 85, 84, 73, 54, 32, 16, 5, -5, -22, -41, -60, + -72, -71, -66, -54, -43, -30, -19, -6, 10, 25, 41, 47, 43, 32, 20, 7, + -10, -25, -40, -52, -61, -68, -65, -54, -34, -11, 16, 39, 57, 72, 80, 88, + 91, 83, 67, 46, 28, 13, 1, -18, -40, -62, -77, -77, -70, -63, -54, -43, + -30, -12, 7, 25, 40, 51, 51, 42, 31, 19, 3, -13, -32, -48, -60, -68, + -71, -63, -49, -28, -2, 23, 46, 66, 77, 86, 92, 89, 82, 62, 43, 22, + 7, -12, -39, -59, -74, -80, -78, -72, -63, -50, -35, -17, 5, 22, 35, 45, + 49, 49, 42, 31, 13, -7, -25, -38, -49, -59, -66, -65, -57, -42, -20, 8, + 34, 55, 69, 79, 84, 84, 84, 77, 64, 42, 18, -6, -29, -49, -69, -82, + -87, -87, -78, -66, -48, -27, -4, 17, 33, 47, 56, 60, 58, 49, 31, 8, + -18, -36, -47, -57, -67, -75, -74, -60, -36, -3, 25, 48, 65, 76, 83, 87, + 90, 88, 77, 52, 24, -4, -26, -42, -61, -77, -91, -94, -85, -70, -54, -34, + -11, 12, 30, 44, 56, 63, 66, 61, 43, 19, -8, -27, -39, -49, -62, -74, + -80, -71, -49, -20, 9, 34, 56, 70, 79, 86, 93, 96, 91, 70, 41, 11, + -18, -39, -58, -77, -91, -99, -95, -83, -65, -42, -17, 7, 27, 43, 57, 66, + 69, 67, 55, 32, 5, -21, -32, -42, -56, -73, -84, -79, -60, -33, -5, 21, + 44, 61, 72, 80, 92, 100, 99, 82, 54, 23, -10, -31, -51, -71, -87, -101, + -101, -92, -76, -49, -24, 1, 21, 37, 52, 66, 72, 72, 64, 44, 18, -7, + -23, -31, -45, -64, -79, -83, -71, -46, -18, 7, 27, 46, 62, 72, 85, 97, + 100, 92, 65, 35, 2, -22, -40, -60, -78, -92, -100, -96, -82, -59, -29, -6, + 15, 28, 44, 57, 65, 67, 65, 49, 27, 2, -17, -23, -35, -53, -70, -79, + -73, -52, -27, -4, 16, 35, 54, 65, 77, 88, 95, 93, 73, 44, 12, -17, + -38, -54, -74, -86, -97, -98, -89, -69, -37, -11, 9, 27, 42, 56, 65, 68, + 71, 59, 39, 13, -9, -20, -30, -45, -62, -74, -75, -60, -41, -18, 3, 23, + 43, 60, 74, 83, 91, 91, 78, 52, 22, -8, -30, -46, -66, -82, -90, -92, + -85, -70, -44, -17, 5, 22, 33, 45, 56, 60, 63, 56, 39, 21, 5, -9, + -20, -33, -49, -62, -70, -62, -47, -28, -9, 11, 29, 47, 60, 73, 83, 87, + 81, 62, 32, 4, -21, -39, -60, -78, -88, -90, -86, -73, -55, -28, -2, 18, + 30, 42, 50, 57, 58, 53, 44, 27, 15, 4, -10, -24, -40, -53, -59, -57, + -49, -38, -21, -3, 17, 34, 49, 62, 75, 81, 76, 63, 39, 15, -11, -31, + -50, -69, -79, -84, -82, -73, -57, -34, -7, 12, 26, 35, 42, 50, 56, 53, + 42, 31, 20, 13, 1, -16, -30, -43, -50, -51, -49, -42, -28, -11, 7, 23, + 38, 52, 65, 75, 73, 62, 43, 20, -2, -24, -43, -60, -69, -74, -74, -69, + -59, -42, -19, 2, 19, 27, 34, 41, 48, 50, 45, 39, 33, 25, 13, -3, + -18, -32, -42, -47, -49, -47, -40, -27, -8, 11, 28, 43, 57, 69, 73, 65, + 50, 31, 8, -16, -36, -53, -63, -70, -72, -70, -62, -46, -25, -6, 11, 23, + 30, 38, 45, 49, 50, 46, 42, 33, 22, 6, -13, -25, -37, -43, -48, -50, + -45, -35, -18, 2, 21, 39, 51, 61, 64, 63, 53, 38, 19, -6, -30, -49, + -59, -63, -65, -66, -64, -52, -31, -14, 2, 13, 25, 35, 42, 46, 46, 47, + 48, 44, 33, 15, -6, -21, -32, -37, -42, -48, -46, -39, -26, -8, 12, 31, + 45, 55, 58, 57, 51, 39, 22, 2, -21, -39, -49, -56, -59, -62, -59, -52, + -38, -22, -9, 5, 16, 25, 32, 40, 46, 51, 54, 52, 40, 24, 5, -11, + -20, -28, -35, -44, -48, -43, -33, -17, 0, 18, 32, 44, 48, 49, 48, 40, + 28, 11, -10, -26, -37, -45, -52, -58, -57, -51, -41, -29, -19, -10, 3, 15, + 27, 36, 40, 50, 59, 60, 51, 33, 15, 2, -11, -21, -34, -45, -49, -45, + -36, -25, -11, 8, 26, 38, 43, 42, 41, 39, 31, 16, -5, -24, -31, -37, + -43, -51, -54, -49, -40, -31, -24, -13, -3, 12, 22, 29, 33, 43, 55, 60, + 53, 37, 18, 5, -4, -12, -23, -35, -44, -42, -35, -26, -15, -2, 15, 26, + 33, 31, 31, 29, 28, 21, 6, -13, -27, -30, -37, -44, -48, -45, -39, -34, + -28, -18, -8, 4, 17, 23, 31, 40, 51, 58, 56, 42, 25, 12, 2, -7, + -16, -27, -36, -39, -37, -31, -21, -12, 3, 14, 21, 25, 23, 23, 25, 23, + 11, -4, -16, -21, -26, -34, -39, -40, -34, -31, -30, -23, -17, -3, 9, 16, + 23, 31, 42, 54, 57, 49, 29, 14, 7, 4, -3, -15, -26, -32, -32, -31, + -24, -16, -5, 5, 8, 10, 9, 10, 16, 19, 14, 4, -8, -14, -16, -21, + -29, -34, -33, -30, -29, -26, -20, -10, 2, 11, 20, 28, 40, 51, 55, 51, + 33, 17, 9, 6, 4, -9, -20, -28, -32, -29, -25, -20, -11, -2, 3, 4, + 1, 6, 12, 18, 16, 8, -5, -10, -14, -17, -20, -23, -25, -26, -28, -26, + -21, -12, -2, 6, 13, 20, 29, 40, 48, 48, 37, 23, 13, 8, 7, 3, + -6, -15, -22, -24, -24, -21, -16, -10, -6, -11, -15, -10, 1, 12, 15, 9, + 4, 3, 1, -5, -11, -18, -18, -22, -25, -29, -27, -19, -7, 4, 10, 14, + 21, 35, 46, 48, 40, 27, 16, 13, 11, 11, 5, -5, -14, -19, -21, -24, + -19, -14, -13, -17, -21, -21, -11, 1, 11, 12, 5, 3, 2, 5, 6, 0, + -6, -16, -20, -25, -26, -20, -12, -4, 1, 5, 11, 25, 38, 46, 41, 33, + 21, 17, 15, 15, 14, 8, -3, -14, -23, -27, -26, -21, -20, -22, -26, -25, + -20, -7, 5, 10, 10, 8, 5, 6, 6, 5, 1, -7, -14, -20, -23, -21, + -17, -11, -4, 2, 7, 17, 29, 38, 40, 37, 30, 23, 21, 20, 17, 14, + 5, -6, -19, -26, -29, -25, -24, -27, -28, -28, -26, -18, -4, 6, 9, 8, + 4, 5, 10, 12, 11, 3, -8, -15, -18, -18, -15, -11, -10, -5, 1, 8, + 16, 26, 35, 35, 31, 24, 22, 21, 22, 21, 16, 5, -12, -24, -30, -31, + -29, -31, -32, -31, -32, -22, -12, 0, 7, 11, 12, 10, 11, 15, 13, 10, + 2, -10, -13, -16, -17, -14, -14, -12, -6, 0, 10, 20, 26, 32, 30, 29, + 27, 26, 28, 26, 22, 13, -2, -16, -25, -30, -32, -33, -35, -35, -34, -28, + -19, -12, -5, 1, 5, 9, 11, 16, 17, 18, 11, 3, -4, -10, -12, -13, + -12, -13, -14, -10, -4, 8, 20, 27, 31, 31, 28, 29, 31, 30, 26, 17, + 5, -9, -23, -32, -37, -36, -34, -35, -34, -32, -24, -16, -7, 2, 4, 6, + 10, 16, 17, 15, 12, 8, 3, -5, -11, -11, -10, -11, -12, -11, -5, 3, + 13, 22, 30, 32, 27, 25, 25, 28, 27, 19, 7, -8, -22, -31, -34, -32, + -30, -28, -31, -31, -29, -21, -12, -4, 1, 1, 3, 10, 16, 18, 18, 14, + 12, 3, -5, -8, -7, -8, -10, -12, -12, -5, 6, 16, 26, 30, 29, 24, + 25, 26, 29, 23, 13, -2, -16, -26, -32, -33, -30, -30, -30, -30, -29, -25, + -18, -12, -5, -2, 2, 8, 14, 18, 16, 18, 14, 10, 4, 0, -5, -4, + -7, -9, -14, -10, -3, 9, 19, 26, 26, 23, 23, 26, 29, 28, 21, 7, + -10, -19, -25, -26, -27, -27, -29, -30, -32, -31, -27, -19, -13, -9, -7, 0, + 9, 18, 24, 26, 21, 13, 9, 8, 4, -2, -6, -9, -11, -11, -7, 4, + 16, 24, 26, 21, 19, 22, 26, 29, 23, 7, -10, -17, -19, -19, -23, -25, + -25, -25, -26, -26, -29, -26, -17, -14, -9, -7, 1, 12, 21, 26, 23, 18, + 13, 11, 11, 6, -4, -6, -10, -10, -9, -2, 9, 20, 25, 23, 18, 18, + 23, 26, 24, 10, -5, -13, -17, -14, -15, -17, -20, -24, -25, -29, -31, -32, + -28, -22, -16, -13, -8, 2, 14, 25, 27, 27, 22, 17, 15, 13, 10, 5, + -3, -6, -8, -6, 1, 11, 18, 20, 13, 11, 15, 19, 20, 14, 4, -4, + -12, -12, -12, -12, -14, -17, -23, -30, -35, -37, -31, -26, -20, -16, -12, -4, + 9, 22, 28, 26, 22, 17, 14, 15, 11, 8, 6, 2, 0, -2, 4, 11, + 16, 16, 12, 7, 8, 13, 13, 10, 1, -5, -8, -8, -8, -7, -7, -10, + -20, -26, -34, -36, -33, -31, -29, -25, -19, -12, 4, 18, 27, 28, 23, 22, + 18, 19, 17, 14, 9, 7, 4, 0, 2, 8, 14, 16, 12, 2, 0, 2, + 5, 6, 2, -4, -7, -6, -2, -2, -3, -5, -11, -19, -28, -37, -37, -37, + -34, -29, -24, -18, -8, 7, 20, 25, 25, 25, 22, 21, 21, 21, 19, 15, + 11, 6, 6, 6, 10, 11, 6, -2, -5, -5, -2, 0, 0, 0, -4, 0, + 2, 4, 2, -2, -8, -16, -25, -34, -39, -42, -39, -33, -26, -21, -16, -4, + 11, 22, 25, 27, 25, 23, 23, 24, 25, 22, 17, 13, 10, 9, 12, 10, + 4, -5, -12, -12, -11, -9, -8, -6, -5, 1, 4, 8, 10, 7, 4, -7, + -18, -26, -34, -39, -43, -42, -34, -28, -22, -13, 2, 14, 18, 21, 23, 27, + 30, 32, 31, 28, 23, 20, 20, 15, 14, 10, 2, -5, -13, -15, -16, -16, + -12, -12, -5, 1, 5, 8, 8, 10, 8, 0, -13, -23, -27, -33, -40, -44, + -41, -32, -24, -17, -6, 3, 9, 17, 22, 25, 29, 34, 39, 36, 32, 26, + 25, 23, 19, 11, 1, -9, -16, -18, -17, -19, -21, -17, -8, 0, 4, 7, + 8, 10, 11, 6, -4, -13, -21, -25, -35, -40, -41, -37, -26, -21, -13, -8, + -3, 6, 15, 23, 27, 35, 40, 41, 38, 33, 31, 29, 24, 16, 5, -5, + -16, -23, -23, -23, -18, -14, -6, 2, 3, 4, 7, 11, 13, 7, -5, -13, + -21, -25, -32, -40, -42, -37, -28, -21, -14, -13, -9, 1, 11, 22, 27, 33, + 39, 43, 42, 41, 33, 29, 25, 18, 7, -6, -17, -25, -24, -23, -21, -16, + -9, 2, 6, 5, 5, 10, 15, 12, 3, -8, -16, -22, -29, -39, -44, -42, + -34, -27, -22, -21, -17, -8, 4, 19, 29, 40, 48, 53, 51, 49, 43, 38, + 28, 19, 6, -9, -19, -27, -30, -30, -24, -16, -10, -3, 3, 6, 5, 6, + 9, 11, 7, 2, -7, -16, -25, -34, -37, -37, -33, -31, -28, -27, -24, -20, + -10, 8, 22, 35, 46, 52, 53, 54, 49, 46, 37, 23, 9, -7, -18, -24, + -30, -32, -28, -22, -12, -5, 1, 6, 4, 8, 9, 11, 9, 3, -3, -13, + -21, -32, -37, -38, -35, -34, -32, -32, -32, -27, -14, 5, 24, 38, 48, 55, + 56, 56, 54, 50, 40, 23, 4, -10, -18, -24, -26, -29, -29, -24, -17, -5, + 2, 9, 9, 6, 6, 7, 12, 11, 6, -7, -18, -30, -36, -36, -37, -35, + -38, -40, -41, -36, -24, -2, 20, 35, 47, 55, 60, 62, 62, 61, 47, 26, + 7, -12, -18, -22, -24, -28, -33, -31, -24, -12, -2, 7, 9, 5, 4, 5, + 11, 14, 13, 7, -8, -24, -37, -41, -38, -34, -37, -44, -50, -46, -33, -10, + 16, 36, 49, 57, 61, 64, 66, 65, 55, 34, 11, -14, -24, -26, -26, -24, + -30, -34, -33, -24, -7, 5, 12, 10, 5, 6, 9, 16, 22, 21, 10, -10, + -32, -45, -44, -38, -38, -47, -61, -60, -48, -21, 11, 34, 51, 60, 63, 66, + 70, 69, 63, 45, 18, -10, -27, -27, -23, -20, -28, -36, -37, -32, -17, -2, + 8, 9, 5, 6, 8, 15, 24, 30, 25, 5, -22, -41, -44, -40, -38, -50, + -64, -72, -62, -37, -3, 29, 52, 62, 66, 69, 73, 78, 72, 54, 26, -5, + -25, -32, -29, -24, -27, -34, -37, -36, -26, -11, 5, 15, 15, 11, 9, 15, + 26, 35, 33, 14, -14, -37, -49, -47, -45, -51, -63, -72, -66, -42, -10, 22, + 49, 64, 69, 69, 70, 75, 73, 59, 34, 4, -20, -30, -30, -25, -24, -29, + -36, -40, -35, -22, -2, 16, 20, 17, 14, 15, 27, 39, 41, 27, -4, -32, + -48, -54, -53, -59, -65, -73, -71, -55, -23, 16, 49, 67, 70, 68, 71, 77, + 78, 65, 40, 10, -17, -31, -34, -28, -24, -26, -31, -40, -40, -30, -10, 10, + 21, 18, 15, 16, 26, 40, 48, 40, 13, -20, -44, -55, -61, -63, -69, -76, + -76, -63, -35, 6, 41, 66, 75, 71, 71, 75, 77, 67, 44, 17, -10, -25, + -34, -35, -29, -27, -28, -35, -40, -35, -18, 1, 16, 21, 20, 19, 25, 38, + 47, 43, 23, -9, -34, -50, -59, -65, -72, -76, -74, -66, -43, -9, 27, 58, + 71, 69, 70, 71, 73, 67, 48, 25, 2, -18, -28, -33, -29, -25, -25, -31, + -39, -41, -28, -10, 8, 19, 20, 23, 27, 36, 45, 45, 31, 4, -22, -45, + -58, -67, -74, -75, -73, -66, -50, -21, 16, 49, 67, 73, 72, 72, 74, 69, + 53, 33, 9, -11, -25, -34, -35, -31, -27, -30, -38, -43, -33, -16, 6, 18, + 24, 27, 30, 38, 45, 46, 34, 10, -16, -40, -61, -70, -77, -76, -72, -66, + -52, -31, 2, 36, 60, 71, 72, 69, 71, 68, 57, 44, 20, 2, -17, -32, + -36, -33, -31, -31, -40, -46, -41, -29, -5, 16, 27, 34, 35, 41, 49, 51, + 41, 17, -11, -34, -56, -71, -79, -80, -76, -68, -57, -36, -10, 21, 48, 64, + 71, 71, 73, 69, 61, 48, 32, 11, -5, -21, -31, -34, -34, -37, -43, -48, + -45, -34, -14, 8, 25, 34, 41, 43, 49, 51, 43, 26, -2, -27, -49, -65, + -74, -77, -74, -70, -58, -42, -20, 9, 38, 56, 64, 67, 69, 71, 66, 53, + 37, 16, 1, -15, -30, -33, -39, -38, -41, -45, -42, -35, -15, 7, 25, 36, + 41, 45, 49, 49, 40, 23, 1, -20, -41, -59, -71, -75, -73, -65, -57, -45, + -28, -6, 22, 42, 56, 63, 67, 71, 70, 59, 44, 28, 12, -3, -19, -32, + -40, -41, -46, -47, -46, -37, -20, -2, 20, 34, 45, 48, 52, 53, 42, 26, + 4, -15, -35, -51, -65, -70, -70, -68, -61, -50, -34, -15, 9, 28, 45, 54, + 64, 71, 72, 67, 53, 40, 24, 8, -10, -27, -37, -41, -49, -53, -53, -42, + -25, -8, 14, 31, 43, 52, 56, 56, 46, 30, 11, -8, -26, -43, -59, -70, + -69, -68, -62, -55, -44, -25, -4, 17, 36, 48, 62, 69, 69, 67, 57, 47, + 33, 17, -2, -21, -33, -41, -47, -52, -53, -43, -25, -10, 9, 23, 36, 46, + 52, 54, 47, 31, 14, -4, -19, -32, -49, -57, -62, -60, -57, -58, -51, -39, + -19, 6, 23, 38, 51, 60, 68, 71, 67, 58, 44, 27, 7, -17, -32, -41, + -47, -52, -54, -46, -31, -12, 7, 22, 35, 45, 51, 53, 46, 33, 18, 2, + -12, -26, -42, -55, -61, -60, -56, -57, -55, -46, -29, -8, 10, 27, 42, 55, + 65, 70, 69, 61, 49, 34, 16, -5, -23, -36, -45, -51, -54, -50, -35, -17, + 3, 17, 29, 37, 44, 51, 47, 39, 21, 6, -8, -20, -31, -44, -52, -58, + -60, -58, -58, -51, -39, -22, -4, 14, 31, 48, 62, 70, 69, 65, 57, 45, + 28, 7, -15, -31, -44, -50, -53, -50, -39, -24, -6, 11, 24, 33, 43, 46, + 45, 35, 25, 14, 1, -13, -23, -35, -44, -53, -57, -59, -59, -57, -47, -33, + -15, 3, 21, 39, 56, 69, 72, 69, 60, 49, 36, 17, -5, -25, -42, -52, + -52, -48, -40, -26, -9, 9, 20, 29, 34, 39, 40, 34, 25, 16, 6, -6, + -16, -27, -34, -44, -50, -55, -58, -57, -52, -41, -27, -11, 11, 31, 51, 67, + 70, 68, 61, 53, 43, 30, 7, -14, -35, -49, -54, -50, -40, -26, -13, -2, + 9, 22, 30, 38, 41, 36, 28, 20, 12, 4, -5, -15, -26, -41, -52, -58, + -60, -60, -59, -55, -41, -25, -5, 19, 42, 62, 74, 75, 70, 63, 55, 43, + 22, -3, -24, -42, -51, -50, -45, -32, -22, -14, -2, 14, 28, 35, 34, 33, + 30, 25, 21, 11, 4, -6, -18, -32, -46, -56, -61, -61, -62, -60, -51, -39, + -16, 11, 37, 58, 70, 75, 72, 67, 58, 46, 31, 10, -17, -35, -48, -49, + -41, -28, -17, -14, -7, 4, 18, 28, 32, 29, 27, 21, 19, 16, 7, 2, + -11, -22, -35, -48, -57, -61, -60, -60, -56, -47, -30, -5, 23, 48, 63, 72, + 75, 71, 64, 53, 39, 20, -2, -22, -40, -48, -45, -34, -21, -17, -10, -4, + 10, 22, 27, 28, 29, 26, 26, 22, 14, 7, -3, -14, -30, -46, -59, -65, + -65, -65, -64, -56, -41, -17, 15, 42, 62, 73, 77, 75, 69, 57, 43, 25, + 6, -12, -31, -44, -46, -37, -24, -16, -11, -3, 6, 20, 24, 23, 24, 23, + 25, 23, 16, 9, 1, -10, -23, -41, -56, -63, -67, -67, -66, -59, -47, -25, + 3, 32, 54, 70, 75, 76, 70, 62, 47, 32, 15, -3, -21, -38, -44, -41, + -31, -21, -15, -11, -2, 8, 18, 24, 27, 28, 29, 29, 24, 17, 8, -2, + -17, -35, -54, -66, -73, -74, -71, -66, -55, -35, -6, 24, 50, 69, 77, 79, + 74, 63, 51, 38, 22, 2, -17, -35, -42, -39, -32, -24, -17, -11, -5, 6, + 13, 20, 28, 31, 33, 29, 23, 15, 10, 3, -12, -30, -51, -65, -73, -75, + -71, -67, -58, -41, -18, 11, 38, 60, 75, 77, 74, 64, 53, 42, 31, 15, + -7, -25, -38, -40, -37, -29, -24, -15, -11, -2, 9, 17, 28, 33, 36, 33, + 27, 18, 13, 4, -8, -26, -48, -65, -75, -76, -72, -68, -58, -43, -18, 11, + 37, 58, 72, 76, 73, 63, 51, 40, 28, 13, -6, -23, -35, -41, -40, -33, + -24, -16, -9, -2, 7, 18, 29, 38, 42, 38, 31, 21, 11, 3, -10, -26, + -47, -65, -75, -79, -75, -69, -58, -39, -19, 7, 33, 54, 71, 77, 75, 66, + 52, 39, 27, 15, -2, -22, -35, -41, -41, -36, -27, -17, -8, 1, 11, 22, + 33, 41, 47, 45, 35, 21, 11, 4, -7, -24, -46, -66, -77, -81, -79, -73, + -62, -44, -24, -2, 23, 47, 69, 79, 79, 70, 57, 45, 33, 20, 5, -18, + -36, -43, -41, -37, -32, -23, -14, -3, 8, 20, 34, 45, 53, 52, 41, 27, + 16, 7, -5, -24, -47, -69, -83, -86, -84, -74, -62, -44, -22, 1, 24, 47, + 66, 78, 76, 69, 57, 43, 31, 17, 5, -13, -33, -43, -46, -41, -31, -22, + -12, 0, 11, 24, 39, 49, 57, 58, 48, 30, 15, 4, -8, -26, -52, -74, + -86, -89, -83, -74, -60, -43, -21, 1, 22, 45, 65, 78, 79, 68, 54, 40, + 26, 17, 7, -9, -31, -45, -46, -40, -31, -21, -11, 0, 8, 21, 39, 51, + 60, 60, 52, 36, 19, 4, -9, -25, -49, -71, -87, -92, -89, -79, -63, -45, + -24, 0, 22, 43, 65, 75, 80, 70, 57, 44, 30, 16, 2, -14, -31, -46, + -52, -47, -35, -21, -9, 1, 12, 26, 44, 59, 68, 68, 59, 42, 22, 6, + -11, -29, -49, -72, -87, -96, -95, -86, -67, -46, -23, -4, 16, 38, 59, 76, + 82, 74, 61, 45, 31, 20, 3, -14, -30, -44, -51, -51, -41, -26, -11, 3, + 13, 25, 44, 61, 71, 72, 59, 45, 28, 9, -10, -33, -53, -70, -83, -93, + -96, -91, -74, -53, -27, -6, 15, 35, 53, 71, 80, 77, 66, 51, 34, 20, + 3, -15, -30, -45, -53, -55, -48, -32, -17, 1, 16, 29, 47, 62, 73, 77, + 67, 50, 30, 9, -10, -32, -55, -73, -86, -93, -94, -90, -76, -54, -27, -4, + 17, 32, 48, 64, 74, 78, 68, 55, 38, 17, 1, -15, -28, -39, -47, -52, + -49, -37, -21, -3, 16, 31, 46, 61, 70, 75, 70, 55, 36, 13, -9, -32, + -56, -72, -84, -89, -93, -91, -81, -61, -30, -5, 18, 32, 45, 58, 71, 76, + 70, 57, 40, 18, 1, -17, -28, -35, -45, -52, -50, -39, -25, -7, 15, 33, + 48, 60, 67, 73, 70, 60, 42, 19, -8, -34, -57, -69, -77, -83, -87, -92, + -85, -66, -39, -10, 12, 27, 39, 52, 62, 73, 72, 61, 46, 25, 4, -14, + -27, -34, -41, -46, -48, -43, -30, -11, 14, 38, 53, 63, 66, 69, 72, 65, + 48, 23, -4, -31, -56, -72, -81, -83, -87, -91, -87, -72, -46, -15, 11, 28, + 40, 50, 60, 71, 75, 69, 54, 32, 8, -13, -29, -39, -45, -48, -50, -48, + -40, -21, 9, 37, 57, 66, 71, 74, 75, 71, 55, 32, 2, -29, -55, -73, + -81, -84, -87, -89, -88, -75, -49, -19, 10, 29, 39, 48, 53, 62, 72, 68, + 58, 35, 9, -11, -27, -34, -39, -42, -44, -46, -41, -26, 5, 35, 56, 65, + 69, 72, 73, 72, 59, 37, 9, -22, -50, -71, -83, -83, -83, -86, -88, -81, + -55, -24, 5, 24, 37, 48, 54, 59, 64, 66, 59, 41, 17, -9, -27, -36, + -38, -39, -42, -45, -41, -28, -2, 28, 53, 65, 68, 71, 71, 70, 58, 40, + 16, -14, -46, -67, -79, -81, -80, -83, -87, -83, -64, -36, -4, 19, 35, 46, + 51, 58, 65, 69, 64, 49, 26, -2, -25, -38, -41, -39, -40, -43, -45, -33, + -8, 24, 52, 65, 72, 74, 72, 66, 55, 40, 20, -7, -38, -65, -80, -85, + -80, -82, -84, -82, -65, -38, -9, 13, 29, 41, 49, 57, 62, 64, 59, 48, + 29, 6, -19, -36, -39, -37, -35, -38, -39, -31, -11, 19, 47, 63, 70, 71, + 71, 65, 55, 38, 17, -4, -33, -58, -76, -83, -79, -79, -80, -82, -70, -46, + -19, 8, 25, 36, 43, 51, 59, 63, 62, 50, 34, 14, -9, -27, -35, -38, + -36, -38, -39, -30, -15, 10, 34, 52, 67, 73, 74, 68, 54, 37, 21, 2, + -21, -45, -68, -78, -81, -81, -80, -79, -70, -51, -28, -4, 17, 32, 40, 48, + 56, 59, 57, 46, 34, 18, 3, -20, -34, -39, -35, -31, -30, -26, -13, 8, + 31, 48, 61, 67, 69, 66, 53, 38, 16, -4, -23, -41, -58, -72, -78, -80, + -76, -74, -64, -50, -33, -8, 12, 28, 35, 41, 50, 57, 53, 44, 31, 20, + 10, -8, -24, -34, -34, -30, -25, -21, -13, 5, 22, 38, 52, 61, 66, 65, + 53, 36, 15, -4, -18, -33, -45, -61, -73, -79, -78, -72, -62, -49, -33, -13, + 3, 19, 29, 38, 48, 52, 49, 41, 29, 22, 14, 2, -11, -25, -27, -25, + -20, -15, -8, 4, 19, 30, 42, 53, 57, 61, 50, 32, 15, -7, -18, -27, + -37, -50, -65, -73, -72, -66, -57, -49, -37, -19, -3, 13, 23, 32, 41, 44, + 41, 35, 29, 26, 21, 10, -2, -13, -21, -18, -14, -8, -4, 3, 12, 21, + 29, 42, 51, 54, 49, 32, 14, -5, -15, -22, -28, -39, -55, -69, -68, -62, + -52, -44, -37, -25, -11, 4, 16, 24, 32, 37, 35, 28, 23, 23, 23, 18, + 8, -4, -12, -12, -8, -2, 5, 9, 14, 18, 23, 31, 41, 45, 43, 29, + 11, -8, -18, -23, -21, -29, -43, -60, -65, -58, -50, -39, -32, -26, -17, -6, + 8, 18, 25, 31, 29, 24, 17, 20, 24, 25, 19, 8, 0, -5, -3, 4, + 11, 13, 12, 14, 16, 22, 31, 38, 37, 27, 9, -11, -22, -24, -22, -25, + -36, -50, -57, -53, -46, -37, -30, -24, -17, -9, 1, 10, 16, 20, 19, 17, + 13, 14, 21, 24, 24, 19, 10, 8, 9, 13, 18, 20, 15, 12, 11, 14, + 21, 27, 30, 21, 8, -12, -23, -24, -22, -20, -29, -40, -49, -47, -41, -33, + -26, -23, -20, -16, -11, -2, 7, 12, 14, 14, 13, 14, 19, 26, 30, 26, + 20, 11, 11, 16, 21, 26, 22, 18, 15, 14, 15, 19, 20, 16, 4, -15, + -29, -32, -27, -21, -24, -34, -40, -41, -33, -28, -24, -21, -20, -15, -14, -10, + -5, 1, 7, 10, 10, 12, 18, 26, 36, 34, 27, 21, 17, 20, 23, 25, + 24, 19, 11, 10, 9, 12, 16, 14, 3, -16, -32, -34, -27, -19, -20, -27, + -34, -35, -31, -27, -22, -18, -18, -19, -19, -20, -15, -7, 2, 6, 8, 9, + 18, 26, 38, 41, 37, 28, 21, 23, 25, 27, 25, 20, 13, 7, 3, 5, + 9, 11, 4, -14, -31, -35, -29, -20, -18, -23, -26, -32, -29, -25, -23, -15, + -17, -18, -21, -25, -23, -15, -6, 0, 5, 6, 16, 25, 37, 45, 43, 36, + 27, 25, 28, 30, 29, 26, 16, 7, -2, -2, 2, 3, -2, -15, -31, -38, + -35, -23, -15, -15, -19, -23, -26, -23, -21, -15, -12, -18, -24, -27, -25, -19, + -9, -3, 2, 5, 12, 19, 32, 42, 45, 41, 31, 28, 31, 33, 37, 33, + 26, 14, 4, -2, -3, -3, -5, -18, -34, -43, -42, -31, -20, -18, -17, -19, + -18, -16, -13, -9, -8, -13, -22, -32, -32, -28, -19, -11, -6, -2, 7, 18, + 31, 42, 46, 46, 41, 36, 32, 35, 39, 39, 30, 17, 5, -3, -3, -3, + -7, -19, -32, -39, -41, -36, -26, -17, -12, -13, -18, -20, -14, -7, -6, -11, + -23, -32, -34, -28, -23, -15, -9, -2, 9, 17, 28, 37, 44, 48, 45, 38, + 32, 35, 41, 45, 37, 23, 10, 1, -3, -5, -8, -20, -35, -44, -44, -42, + -34, -24, -14, -10, -12, -14, -11, -6, -2, -5, -15, -25, -32, -29, -24, -19, + -15, -10, 1, 10, 20, 31, 40, 45, 48, 43, 39, 39, 45, 51, 43, 28, + 15, 2, -4, -8, -13, -20, -34, -42, -45, -45, -36, -26, -13, -8, -11, -13, + -8, -2, 1, -4, -13, -22, -30, -33, -28, -25, -18, -12, -5, 3, 13, 25, + 37, 46, 47, 45, 40, 41, 47, 53, 49, 35, 21, 10, 2, -6, -11, -22, + -32, -43, -50, -50, -47, -34, -17, -9, -9, -12, -9, 3, 7, 4, -8, -18, + -25, -31, -31, -27, -21, -16, -11, -8, 2, 17, 31, 45, 47, 44, 40, 43, + 54, 60, 58, 42, 26, 14, 4, -5, -14, -26, -37, -47, -54, -53, -49, -38, + -22, -13, -9, -7, -3, 6, 11, 6, -5, -14, -22, -28, -31, -30, -29, -24, + -18, -15, -2, 14, 29, 42, 45, 47, 45, 48, 56, 63, 59, 46, 29, 17, + 5, -4, -11, -23, -36, -49, -53, -52, -48, -40, -29, -21, -16, -11, -2, 5, + 6, 3, -5, -10, -13, -17, -21, -25, -26, -23, -19, -15, -8, 5, 20, 31, + 38, 42, 41, 46, 55, 62, 63, 50, 36, 24, 12, 5, -7, -20, -33, -46, + -51, -51, -48, -40, -33, -27, -20, -15, 0, 9, 7, 1, -6, -10, -11, -16, + -22, -25, -30, -28, -25, -21, -11, 2, 17, 28, 32, 41, 47, 55, 64, 66, + 64, 54, 41, 32, 19, 4, -9, -24, -37, -48, -54, -55, -51, -41, -33, -29, + -24, -15, 0, 13, 14, 8, 1, -5, -6, -10, -17, -24, -30, -32, -33, -32, + -22, -9, 9, 21, 25, 35, 45, 56, 67, 71, 71, 63, 49, 37, 25, 11, + -5, -19, -32, -45, -54, -59, -54, -43, -36, -31, -27, -18, -3, 11, 13, 9, + 2, -3, -6, -9, -13, -20, -25, -29, -33, -30, -23, -9, 2, 11, 19, 28, + 40, 51, 63, 68, 71, 66, 55, 44, 31, 16, 1, -15, -30, -41, -50, -57, + -56, -46, -37, -32, -30, -21, -7, 8, 17, 12, 5, 3, -2, -6, -11, -19, + -23, -27, -33, -34, -28, -19, -6, 3, 13, 24, 38, 51, 62, 70, 72, 68, + 60, 48, 38, 22, 6, -13, -27, -39, -46, -53, -52, -48, -42, -37, -36, -25, + -9, 4, 11, 9, 7, 8, 6, 2, -6, -13, -20, -24, -28, -31, -30, -27, + -19, -10, 4, 19, 33, 45, 57, 67, 74, 74, 70, 60, 47, 31, 10, -8, + -25, -36, -42, -51, -56, -56, -51, -40, -35, -28, -16, -4, 7, 7, 10, 12, + 13, 11, 3, -8, -18, -21, -25, -29, -33, -33, -30, -20, -8, 11, 27, 42, + 54, 64, 72, 77, 76, 69, 56, 34, 14, -5, -20, -32, -43, -50, -57, -59, + -57, -47, -39, -31, -17, -5, 6, 8, 9, 17, 19, 16, 5, -9, -13, -18, + -21, -26, -33, -37, -35, -28, -15, 1, 18, 34, 47, 58, 68, 76, 77, 76, + 65, 47, 25, 6, -12, -24, -37, -49, -57, -62, -64, -58, -50, -40, -24, -12, + 3, 9, 13, 22, 26, 26, 17, 4, -9, -21, -25, -30, -36, -41, -44, -41, + -27, -8, 12, 31, 44, 57, 68, 77, 81, 80, 72, 56, 34, 12, -6, -19, + -30, -41, -53, -65, -68, -65, -56, -44, -30, -17, -8, 2, 10, 23, 31, 32, + 25, 10, -4, -14, -20, -25, -31, -39, -45, -45, -35, -17, 2, 22, 37, 51, + 63, 72, 79, 78, 74, 62, 43, 20, 2, -12, -24, -34, -49, -61, -69, -70, + -63, -48, -35, -23, -11, 0, 9, 20, 31, 36, 32, 20, 7, -9, -18, -24, + -30, -38, -47, -50, -44, -29, -9, 10, 27, 45, 60, 71, 78, 80, 78, 68, + 54, 33, 13, -5, -18, -29, -44, -57, -68, -74, -66, -54, -41, -30, -18, -5, + 8, 19, 26, 33, 32, 24, 13, -4, -15, -22, -24, -29, -40, -44, -42, -29, + -14, 0, 15, 31, 48, 63, 69, 74, 74, 72, 64, 47, 27, 11, -4, -17, + -33, -50, -66, -78, -78, -68, -54, -38, -25, -11, 4, 18, 31, 38, 40, 34, + 21, 5, -12, -23, -28, -34, -43, -50, -51, -39, -22, -6, 10, 26, 46, 61, + 70, 75, 79, 76, 67, 52, 34, 18, 4, -11, -27, -45, -63, -76, -78, -70, + -57, -44, -29, -15, 0, 14, 26, 35, 39, 34, 23, 9, -7, -18, -23, -30, + -40, -49, -51, -41, -24, -9, 5, 19, 39, 55, 67, 74, 77, 79, 72, 56, + 39, 24, 12, -5, -23, -42, -60, -73, -78, -74, -62, -48, -33, -18, -6, 10, + 25, 34, 37, 34, 26, 16, -2, -15, -23, -28, -32, -42, -46, -44, -31, -16, + -4, 11, 28, 44, 56, 64, 69, 75, 73, 63, 50, 37, 22, 6, -10, -27, + -47, -68, -81, -80, -68, -52, -39, -25, -13, 2, 17, 29, 36, 37, 32, 23, + 4, -14, -24, -26, -26, -36, -44, -45, -36, -20, -7, 9, 25, 38, 49, 58, + 66, 75, 77, 67, 52, 39, 26, 14, -3, -21, -43, -65, -81, -84, -74, -56, + -40, -27, -15, -2, 15, 27, 37, 38, 35, 26, 8, -11, -23, -26, -27, -34, + -42, -45, -40, -27, -13, 4, 19, 33, 45, 54, 60, 67, 72, 67, 57, 44, + 32, 20, 5, -11, -32, -55, -72, -82, -76, -62, -46, -31, -21, -5, 6, 19, + 29, 34, 33, 26, 12, -6, -17, -22, -23, -28, -38, -42, -38, -27, -14, 1, + 14, 27, 40, 48, 53, 62, 68, 67, 58, 44, 32, 21, 9, -5, -22, -43, + -63, -76, -75, -62, -46, -30, -24, -13, 0, 10, 20, 28, 31, 27, 12, -5, + -16, -20, -19, -21, -29, -35, -35, -27, -16, -6, 9, 21, 33, 41, 47, 53, + 61, 63, 60, 51, 39, 27, 15, 3, -13, -33, -55, -72, -75, -67, -52, -37, + -26, -18, -7, 4, 15, 26, 27, 25, 14, 0, -10, -15, -16, -19, -24, -31, + -32, -27, -17, -5, 5, 15, 26, 35, 43, 49, 54, 57, 57, 52, 42, 29, + 18, 10, -3, -23, -46, -64, -71, -66, -53, -39, -27, -19, -11, 0, 5, 16, + 22, 23, 15, 1, -10, -15, -18, -17, -17, -20, -24, -22, -14, -4, 7, 16, + 25, 31, 36, 41, 47, 49, 49, 46, 41, 32, 21, 13, 3, -14, -33, -51, + -60, -60, -52, -39, -28, -20, -14, -7, 1, 9, 14, 16, 10, 1, -10, -15, + -14, -15, -15, -15, -17, -14, -11, -4, 5, 13, 22, 29, 33, 35, 39, 43, + 45, 45, 42, 35, 26, 17, 7, -10, -25, -38, -48, -53, -53, -46, -33, -23, + -16, -13, -8, -3, 4, 9, 7, 1, -6, -10, -13, -12, -12, -8, -7, -6, + -2, 3, 6, 10, 14, 23, 28, 29, 30, 29, 34, 39, 40, 36, 30, 21, + 13, 1, -15, -27, -36, -44, -48, -45, -36, -26, -17, -13, -10, -6, -2, 2, + 3, -3, -6, -10, -14, -13, -12, -7, -3, 1, 2, 5, 6, 10, 15, 19, + 25, 25, 26, 26, 29, 34, 35, 32, 29, 20, 13, 4, -12, -20, -27, -33, + -38, -41, -36, -27, -19, -13, -10, -8, -8, -7, -5, -5, -7, -9, -13, -18, + -15, -12, -5, 3, 7, 10, 10, 11, 13, 20, 27, 27, 23, 20, 20, 24, + 27, 25, 26, 23, 17, 7, -6, -13, -16, -20, -26, -32, -33, -28, -20, -13, + -12, -12, -16, -15, -15, -12, -10, -13, -13, -16, -12, -7, 0, 9, 14, 18, + 18, 14, 11, 14, 18, 21, 17, 10, 11, 15, 20, 21, 20, 20, 17, 9, + 2, -5, -10, -14, -21, -25, -29, -27, -23, -17, -13, -13, -16, -18, -20, -20, + -12, -8, -9, -15, -16, -10, -2, 9, 14, 18, 18, 18, 14, 14, 17, 20, + 18, 12, 8, 11, 13, 16, 18, 19, 16, 9, 3, 1, 1, -6, -13, -20, + -23, -21, -19, -15, -15, -14, -17, -21, -22, -22, -17, -11, -11, -13, -18, -14, + -4, 12, 21, 22, 23, 21, 20, 17, 16, 16, 12, 7, 1, 5, 7, 8, + 12, 15, 15, 10, 3, 0, 3, 1, -5, -12, -19, -19, -16, -11, -9, -11, + -14, -23, -28, -29, -24, -17, -13, -15, -19, -18, -10, 7, 22, 29, 30, 24, + 22, 18, 17, 17, 11, 4, -2, -3, 2, 4, 8, 13, 16, 13, 7, 4, + 9, 8, 2, -7, -16, -15, -14, -12, -10, -12, -12, -19, -25, -29, -25, -18, + -15, -18, -21, -19, -12, 1, 16, 28, 34, 32, 29, 23, 18, 15, 11, 4, + -3, -10, -8, -5, 0, 7, 12, 14, 10, 6, 10, 15, 13, 3, -7, -11, + -13, -13, -13, -12, -14, -20, -28, -31, -29, -20, -13, -14, -18, -18, -15, -3, + 12, 24, 33, 32, 29, 25, 22, 16, 11, 3, -3, -6, -7, -8, -3, 2, + 8, 11, 11, 9, 10, 13, 13, 8, 0, -6, -9, -9, -9, -10, -11, -18, + -26, -30, -29, -22, -17, -18, -20, -21, -17, -7, 6, 21, 34, 38, 34, 29, + 21, 17, 13, 8, 1, -8, -13, -15, -10, -3, 5, 10, 11, 10, 11, 15, + 16, 11, 3, -4, -7, -9, -8, -10, -13, -19, -26, -26, -23, -17, -15, -16, + -17, -17, -15, -9, -2, 10, 26, 31, 31, 24, 21, 18, 13, 6, 1, -6, + -8, -9, -8, -4, 0, 6, 10, 12, 15, 14, 13, 9, 5, -2, -7, -8, + -9, -8, -10, -18, -25, -25, -23, -18, -16, -19, -22, -18, -16, -10, 0, 10, + 24, 33, 35, 29, 22, 17, 13, 7, -3, -8, -12, -14, -12, -7, -3, 4, + 10, 14, 16, 17, 16, 16, 11, 3, -7, -11, -10, -7, -10, -19, -26, -27, + -23, -17, -14, -14, -17, -18, -16, -12, -3, 7, 20, 26, 28, 24, 20, 16, + 15, 10, 2, -8, -13, -11, -7, -2, -2, 4, 6, 9, 14, 17, 19, 15, + 8, -4, -12, -15, -11, -5, -8, -18, -25, -24, -17, -9, -6, -7, -11, -15, + -15, -13, -6, 4, 11, 15, 16, 15, 16, 13, 9, 5, 1, -3, -7, -5, + -2, 3, 5, 6, 8, 10, 14, 17, 18, 14, 3, -8, -15, -13, -9, -6, + -9, -19, -22, -19, -13, -6, -4, -5, -8, -13, -15, -10, -5, 5, 8, 8, + 8, 11, 14, 14, 8, 2, 1, 1, 2, -2, 1, 5, 6, 7, 7, 6, + 11, 13, 16, 13, 3, -6, -13, -14, -8, -5, -6, -15, -20, -15, -10, -5, + -2, -6, -6, -8, -12, -10, -8, -3, 5, 3, 3, 5, 7, 10, 6, 2, + -3, -2, 2, 8, 9, 12, 11, 8, 9, 8, 11, 13, 11, 10, 0, -12, + -20, -21, -13, -10, -11, -14, -16, -10, -3, 4, 8, 5, 2, -2, -4, -4, + -7, -4, -4, -5, -7, -8, -5, 0, 2, 2, 0, 1, 6, 11, 15, 19, + 19, 18, 14, 10, 12, 12, 11, 6, -6, -16, -23, -23, -17, -13, -12, -12, + -13, -8, -2, 8, 13, 13, 8, 4, 1, -3, -3, -3, -4, -11, -16, -16, + -13, -9, -5, -4, -2, 1, 6, 13, 17, 21, 24, 23, 18, 14, 10, 11, + 12, 8, -3, -16, -26, -27, -20, -17, -21, -21, -17, -7, 2, 10, 16, 19, + 18, 13, 10, 5, 2, -2, -5, -14, -22, -26, -21, -15, -11, -11, -6, -2, + 6, 16, 22, 27, 28, 28, 23, 17, 13, 10, 12, 7, -4, -18, -29, -32, + -24, -20, -21, -22, -18, -5, 5, 14, 19, 21, 20, 17, 13, 8, 5, -2, + -9, -18, -26, -26, -21, -14, -12, -11, -8, -2, 10, 16, 21, 24, 25, 27, + 24, 16, 11, 6, 7, 6, -4, -16, -25, -29, -25, -19, -19, -22, -18, -7, + 6, 15, 17, 18, 19, 18, 15, 10, 8, 3, -5, -15, -24, -30, -27, -19, + -15, -15, -13, -8, 5, 14, 20, 25, 28, 31, 30, 26, 18, 11, 9, 7, + -2, -14, -27, -33, -30, -25, -25, -27, -26, -15, 2, 17, 22, 23, 23, 22, + 22, 18, 14, 7, -4, -14, -24, -31, -30, -25, -19, -16, -16, -11, -3, 8, + 17, 24, 29, 31, 31, 29, 22, 17, 12, 8, 2, -12, -26, -36, -35, -30, + -26, -26, -29, -20, -5, 13, 24, 26, 26, 26, 28, 23, 19, 11, 1, -9, + -24, -34, -33, -30, -24, -21, -21, -17, -11, 1, 9, 19, 27, 33, 34, 30, + 28, 24, 21, 16, 7, -6, -23, -35, -40, -36, -33, -31, -32, -27, -13, 3, + 17, 25, 29, 34, 34, 30, 23, 17, 11, 0, -14, -27, -32, -33, -30, -26, + -21, -18, -15, -9, 1, 11, 22, 29, 32, 33, 30, 28, 23, 21, 13, 3, + -15, -30, -37, -38, -35, -35, -33, -28, -18, -5, 10, 22, 30, 37, 36, 32, + 26, 21, 14, 7, -6, -19, -28, -34, -32, -27, -21, -20, -21, -20, -11, 5, + 17, 25, 29, 30, 33, 35, 31, 27, 19, 8, -7, -25, -37, -42, -41, -39, + -35, -30, -22, -11, 4, 21, 32, 38, 39, 36, 29, 22, 15, 9, -4, -15, + -24, -32, -35, -31, -24, -18, -18, -19, -14, -3, 11, 21, 27, 31, 32, 34, + 34, 31, 27, 18, 1, -19, -33, -39, -38, -40, -39, -35, -28, -17, -3, 14, + 28, 37, 41, 40, 34, 30, 24, 18, 7, -6, -20, -30, -36, -34, -30, -26, + -26, -27, -26, -16, 0, 16, 26, 30, 33, 36, 42, 43, 38, 27, 10, -10, + -27, -39, -43, -43, -43, -40, -34, -26, -14, 2, 21, 36, 42, 40, 36, 33, + 30, 24, 16, 5, -11, -25, -34, -35, -32, -29, -30, -31, -31, -27, -15, 5, + 21, 27, 30, 34, 42, 51, 48, 40, 20, -3, -21, -32, -38, -40, -43, -42, + -38, -30, -18, -3, 15, 29, 40, 41, 39, 34, 31, 28, 20, 10, -4, -18, + -29, -33, -34, -34, -35, -37, -38, -34, -21, -6, 12, 22, 26, 33, 44, 55, + 56, 46, 26, 5, -11, -25, -36, -42, -47, -47, -43, -37, -24, -11, 9, 25, + 36, 38, 38, 40, 39, 39, 28, 17, 3, -10, -23, -30, -37, -38, -42, -44, + -43, -40, -30, -16, 3, 17, 26, 34, 44, 57, 61, 52, 34, 9, -7, -21, + -30, -38, -46, -49, -48, -39, -27, -13, 5, 22, 32, 35, 35, 37, 41, 43, + 33, 19, 4, -8, -16, -25, -32, -39, -42, -44, -42, -41, -33, -20, -4, 11, + 21, 28, 38, 49, 58, 54, 36, 16, -6, -16, -21, -28, -36, -46, -49, -42, + -29, -17, 0, 13, 26, 30, 30, 35, 41, 47, 41, 25, 9, -4, -12, -17, + -28, -38, -46, -52, -51, -49, -39, -23, -9, 4, 12, 23, 39, 54, 66, 62, + 43, 23, 2, -10, -16, -26, -36, -45, -51, -50, -37, -20, 0, 16, 27, 28, + 29, 38, 47, 50, 44, 28, 13, -2, -10, -16, -26, -35, -45, -55, -57, -56, + -44, -27, -13, -4, 5, 17, 34, 53, 64, 64, 46, 29, 13, 1, -8, -17, + -28, -39, -48, -51, -42, -26, -8, 9, 18, 20, 24, 34, 46, 53, 47, 33, + 15, 4, -4, -13, -22, -35, -47, -56, -59, -56, -48, -32, -18, -8, 3, 14, + 33, 52, 65, 64, 49, 31, 17, 5, -3, -13, -25, -36, -45, -49, -44, -31, + -14, 7, 16, 21, 21, 31, 48, 57, 53, 38, 20, 8, -3, -9, -21, -35, + -47, -57, -62, -62, -54, -38, -22, -12, -5, 7, 26, 49, 66, 69, 56, 37, + 24, 15, 6, -4, -17, -30, -43, -53, -47, -34, -18, -2, 9, 14, 17, 29, + 46, 58, 56, 43, 25, 13, 2, -5, -15, -30, -45, -59, -66, -65, -57, -43, + -28, -16, -10, 2, 21, 44, 66, 71, 62, 43, 28, 19, 13, 3, -12, -25, + -42, -51, -50, -38, -18, -3, 5, 12, 17, 30, 48, 59, 58, 45, 26, 11, + 0, -6, -15, -29, -45, -63, -71, -68, -58, -41, -28, -19, -12, -4, 16, 42, + 62, 70, 61, 43, 29, 21, 16, 8, -6, -20, -35, -45, -45, -37, -21, -6, + 3, 8, 14, 24, 42, 54, 58, 47, 29, 16, 3, -3, -12, -27, -42, -62, + -73, -74, -66, -52, -34, -23, -14, -5, 12, 38, 60, 72, 68, 49, 34, 23, + 17, 10, -3, -18, -31, -42, -42, -36, -20, -4, 5, 9, 11, 22, 37, 51, + 55, 46, 29, 13, 2, -9, -14, -25, -38, -53, -67, -72, -67, -53, -35, -23, + -17, -10, 6, 32, 55, 69, 67, 53, 36, 26, 19, 12, 2, -13, -26, -37, + -40, -36, -24, -7, 3, 9, 13, 20, 36, 49, 52, 47, 32, 17, 3, -12, + -19, -29, -38, -52, -66, -75, -72, -56, -36, -20, -15, -10, 2, 25, 48, 63, + 63, 52, 39, 28, 20, 14, 5, -6, -19, -30, -38, -35, -25, -8, 4, 8, + 11, 17, 33, 47, 54, 47, 34, 18, 4, -9, -19, -28, -40, -53, -65, -75, + -74, -60, -41, -22, -15, -12, -2, 18, 43, 59, 63, 55, 41, 31, 27, 20, + 13, 3, -11, -24, -35, -34, -26, -11, 2, 8, 9, 11, 22, 37, 47, 49, + 39, 22, 6, -7, -19, -26, -36, -48, -60, -74, -77, -66, -47, -26, -13, -8, + 1, 15, 36, 53, 63, 56, 45, 30, 22, 16, 10, 5, -7, -19, -32, -34, + -25, -7, 8, 16, 17, 17, 23, 37, 48, 51, 40, 22, 4, -14, -24, -33, + -39, -49, -61, -72, -77, -66, -47, -27, -13, -5, 1, 13, 30, 47, 59, 57, + 47, 31, 23, 17, 15, 6, -5, -18, -26, -30, -24, -10, 8, 19, 21, 20, + 22, 30, 40, 48, 41, 25, 3, -17, -29, -32, -37, -46, -59, -70, -73, -65, + -46, -27, -14, -4, 3, 15, 29, 41, 52, 54, 45, 31, 19, 15, 15, 9, + 1, -14, -26, -27, -21, -8, 10, 17, 23, 23, 23, 32, 39, 45, 44, 29, + 7, -16, -32, -40, -42, -49, -61, -72, -76, -69, -50, -28, -12, -2, 5, 17, + 31, 43, 48, 49, 44, 34, 24, 15, 13, 9, 5, -8, -24, -27, -21, -7, + 10, 20, 25, 29, 29, 32, 36, 41, 41, 34, 14, -12, -35, -46, -49, -52, + -61, -74, -78, -73, -56, -31, -14, 2, 10, 19, 31, 44, 54, 53, 47, 34, + 24, 16, 9, 4, -2, -12, -25, -28, -22, -7, 9, 23, 32, 36, 36, 36, + 37, 42, 42, 33, 15, -14, -36, -50, -57, -56, -62, -74, -81, -77, -59, -36, + -15, 2, 11, 20, 31, 44, 56, 56, 51, 39, 26, 15, 7, 1, -3, -13, + -26, -33, -31, -14, 9, 25, 36, 41, 40, 41, 40, 44, 44, 35, 17, -13, + -39, -54, -61, -64, -69, -76, -81, -78, -63, -39, -15, 4, 14, 24, 35, 45, + 54, 56, 53, 41, 25, 14, 7, 3, -4, -14, -26, -34, -31, -15, 9, 25, + 36, 41, 43, 44, 43, 46, 45, 35, 16, -9, -31, -49, -63, -69, -75, -78, + -84, -79, -66, -45, -22, 0, 13, 23, 35, 48, 56, 58, 53, 43, 30, 19, + 10, 4, -7, -18, -26, -33, -30, -17, 4, 24, 37, 44, 50, 50, 49, 46, + 43, 35, 16, -7, -30, -52, -65, -75, -78, -83, -85, -82, -70, -50, -26, -4, + 14, 26, 39, 53, 63, 64, 59, 49, 35, 18, 6, -2, -13, -25, -35, -40, + -36, -22, 3, 26, 38, 47, 54, 60, 61, 57, 50, 39, 20, -5, -26, -49, + -66, -80, -87, -91, -93, -88, -74, -54, -34, -12, 8, 24, 40, 55, 68, 70, + 66, 55, 41, 26, 14, 6, -9, -25, -37, -43, -39, -28, -9, 15, 32, 41, + 48, 59, 65, 65, 58, 45, 25, 5, -17, -38, -61, -77, -91, -97, -100, -94, + -79, -64, -44, -23, -2, 24, 42, 57, 72, 77, 74, 63, 48, 33, 21, 10, + -7, -27, -43, -45, -41, -29, -14, 4, 26, 40, 49, 58, 66, 69, 64, 48, + 29, 7, -13, -31, -53, -73, -89, -100, -102, -95, -83, -67, -51, -29, -7, 17, + 37, 55, 72, 81, 77, 67, 55, 40, 25, 12, -4, -22, -40, -45, -42, -31, + -19, -4, 15, 34, 48, 55, 63, 67, 66, 57, 41, 20, -4, -25, -46, -69, + -88, -104, -110, -106, -95, -79, -63, -39, -13, 15, 39, 60, 75, 88, 91, 81, + 66, 44, 27, 13, -3, -22, -41, -50, -48, -38, -26, -13, 6, 29, 46, 55, + 62, 66, 69, 63, 48, 26, 5, -14, -33, -57, -84, -105, -115, -113, -102, -88, + -73, -53, -26, 1, 31, 57, 78, 91, 95, 88, 75, 60, 41, 22, 1, -19, + -38, -51, -53, -48, -36, -22, -6, 19, 39, 53, 62, 65, 69, 67, 55, 36, + 14, -6, -28, -54, -79, -100, -111, -116, -110, -98, -83, -61, -35, -6, 26, 53, + 75, 89, 96, 96, 87, 71, 50, 29, 10, -9, -30, -44, -53, -50, -45, -32, + -19, 2, 23, 43, 55, 62, 66, 66, 62, 49, 30, 11, -12, -39, -70, -95, + -112, -118, -118, -109, -94, -74, -48, -18, 17, 47, 70, 88, 98, 99, 95, 80, + 61, 37, 14, -9, -26, -43, -51, -52, -48, -40, -25, -6, 17, 37, 52, 57, + 63, 64, 62, 55, 36, 17, -8, -34, -62, -86, -106, -117, -118, -110, -99, -83, + -57, -27, 10, 42, 67, 85, 96, 101, 101, 91, 69, 46, 21, 1, -21, -38, + -49, -54, -49, -44, -35, -18, 2, 24, 44, 55, 64, 67, 63, 59, 46, 29, + 7, -21, -51, -79, -104, -117, -122, -117, -108, -94, -70, -40, 0, 34, 63, 85, + 96, 104, 105, 99, 82, 59, 31, 4, -20, -37, -46, -51, -51, -50, -44, -28, + -8, 17, 38, 53, 60, 65, 67, 64, 54, 40, 18, -10, -40, -71, -98, -115, + -121, -118, -113, -103, -82, -52, -14, 22, 53, 77, 94, 106, 109, 104, 93, 76, + 50, 21, -11, -33, -43, -48, -53, -56, -56, -46, -27, 2, 29, 48, 58, 62, + 63, 62, 58, 49, 33, 5, -27, -57, -87, -108, -119, -118, -114, -106, -91, -68, + -31, 8, 42, 69, 88, 102, 110, 110, 100, 83, 60, 33, 3, -23, -39, -46, + -52, -57, -57, -51, -35, -14, 15, 38, 54, 63, 65, 66, 58, 51, 40, 17, + -11, -44, -76, -101, -114, -116, -111, -106, -96, -77, -47, -11, 28, 58, 81, 97, + 109, 112, 105, 95, 77, 53, 23, -9, -30, -45, -52, -58, -64, -61, -52, -35, + -9, 20, 44, 62, 67, 67, 65, 62, 54, 35, 7, -24, -60, -91, -110, -119, + -116, -112, -105, -90, -65, -31, 8, 43, 73, 94, 109, 117, 113, 105, 91, 68, + 39, 4, -24, -43, -56, -64, -67, -67, -61, -47, -21, 9, 35, 55, 63, 66, + 66, 61, 56, 46, 23, -10, -46, -81, -100, -111, -115, -112, -107, -94, -75, -48, + -12, 28, 59, 84, 103, 116, 120, 114, 103, 81, 56, 22, -10, -35, -53, -64, + -71, -73, -71, -59, -39, -10, 19, 43, 60, 66, 68, 67, 64, 53, 33, 7, + -27, -64, -91, -108, -115, -113, -108, -97, -82, -59, -27, 11, 46, 75, 98, 112, + 119, 117, 109, 89, 64, 34, 4, -24, -50, -62, -69, -69, -70, -65, -49, -23, + 8, 32, 52, 61, 64, 65, 64, 55, 39, 15, -16, -46, -76, -97, -109, -110, + -107, -102, -91, -71, -42, -4, 34, 66, 90, 106, 116, 121, 118, 101, 78, 47, + 15, -15, -44, -60, -70, -73, -75, -74, -63, -39, -7, 23, 45, 60, 66, 69, + 69, 62, 49, 29, 1, -32, -65, -94, -108, -112, -109, -102, -97, -83, -58, -22, + 18, 54, 84, 103, 116, 121, 120, 112, 91, 63, 29, -6, -34, -54, -66, -75, + -79, -81, -72, -50, -22, 9, 33, 50, 59, 67, 70, 70, 60, 43, 13, -20, + -51, -78, -97, -107, -111, -109, -105, -94, -72, -37, 5, 42, 72, 96, 114, 124, + 127, 118, 100, 75, 42, 10, -22, -47, -62, -72, -79, -84, -82, -64, -35, -2, + 23, 39, 50, 61, 69, 71, 66, 51, 27, -6, -36, -62, -81, -96, -104, -105, + -106, -101, -83, -52, -11, 27, 57, 82, 103, 120, 127, 122, 107, 82, 53, 19, + -12, -39, -55, -65, -73, -81, -81, -67, -40, -8, 16, 30, 41, 52, 62, 68, + 66, 56, 34, 3, -28, -53, -71, -86, -96, -102, -106, -103, -88, -62, -25, 15, + 47, 72, 90, 109, 120, 123, 115, 93, 63, 31, 1, -24, -40, -52, -64, -76, + -82, -73, -50, -22, 1, 18, 27, 39, 51, 63, 67, 61, 44, 18, -13, -38, + -53, -69, -83, -96, -105, -103, -93, -69, -36, -3, 30, 56, 77, 95, 111, 116, + 113, 97, 72, 42, 13, -12, -25, -38, -54, -70, -79, -74, -57, -32, -11, 4, + 15, 26, 40, 55, 65, 62, 51, 28, 1, -24, -40, -56, -73, -89, -101, -102, + -95, -79, -50, -17, 16, 47, 68, 88, 104, 114, 115, 102, 80, 53, 24, 0, + -18, -31, -45, -60, -73, -74, -63, -42, -21, -6, 6, 16, 28, 45, 56, 59, + 51, 35, 14, -9, -26, -41, -57, -73, -87, -97, -95, -85, -62, -32, -2, 26, + 50, 71, 91, 105, 111, 105, 89, 64, 40, 16, -4, -20, -35, -49, -64, -70, + -68, -53, -35, -18, -6, 5, 14, 29, 45, 55, 54, 39, 21, 4, -13, -25, + -42, -63, -77, -89, -90, -80, -66, -44, -19, 10, 35, 57, 76, 93, 104, 104, + 91, 68, 48, 29, 13, -6, -24, -42, -56, -63, -61, -54, -42, -27, -17, -6, + 5, 18, 33, 44, 47, 39, 25, 10, 0, -14, -29, -50, -67, -79, -85, -81, + -70, -53, -32, -5, 24, 47, 67, 84, 98, 103, 95, 77, 56, 37, 22, 6, + -14, -34, -48, -56, -57, -52, -48, -37, -28, -17, -6, 8, 23, 34, 41, 38, + 28, 15, 4, -4, -16, -38, -59, -73, -78, -75, -66, -54, -37, -19, 7, 32, + 53, 72, 87, 95, 92, 78, 58, 44, 32, 20, 2, -21, -38, -47, -48, -47, + -46, -42, -36, -26, -14, -5, 9, 20, 32, 35, 30, 19, 12, 8, -5, -25, + -48, -63, -71, -70, -63, -58, -44, -26, -6, 20, 40, 59, 79, 92, 93, 83, + 60, 47, 37, 29, 13, -10, -28, -40, -44, -44, -48, -47, -41, -33, -22, -13, + 0, 14, 29, 36, 34, 24, 18, 15, 4, -13, -39, -60, -69, -72, -68, -62, + -51, -34, -13, 9, 31, 52, 73, 88, 95, 87, 70, 55, 45, 35, 20, -2, + -23, -36, -42, -47, -48, -51, -50, -40, -30, -17, -8, 7, 23, 36, 37, 30, + 22, 19, 13, -3, -24, -49, -65, -71, -71, -64, -54, -40, -20, -3, 21, 44, + 65, 85, 92, 87, 72, 57, 48, 39, 29, 11, -12, -27, -36, -41, -42, -47, + -49, -45, -37, -28, -17, -4, 13, 28, 33, 29, 26, 23, 17, 6, -11, -33, + -53, -64, -66, -62, -55, -44, -29, -12, 10, 31, 51, 71, 84, 85, 77, 61, + 50, 41, 36, 22, 2, -17, -33, -38, -42, -45, -48, -46, -41, -34, -23, -9, + 7, 24, 35, 32, 28, 23, 17, 10, -4, -26, -49, -64, -68, -64, -58, -46, + -32, -13, 8, 28, 45, 65, 78, 82, 76, 62, 52, 45, 37, 23, 6, -10, + -26, -35, -41, -45, -46, -48, -48, -39, -27, -11, 3, 14, 23, 27, 28, 25, + 23, 15, 2, -17, -34, -52, -60, -61, -56, -44, -32, -17, -3, 16, 34, 54, + 66, 73, 68, 58, 47, 42, 37, 29, 17, 3, -14, -25, -31, -36, -39, -44, + -48, -44, -33, -20, -9, 2, 13, 22, 26, 24, 20, 14, 5, -7, -22, -39, + -50, -55, -51, -43, -32, -20, -7, 10, 28, 44, 57, 65, 67, 64, 54, 44, + 36, 28, 18, 4, -9, -23, -32, -39, -42, -46, -44, -38, -29, -19, -12, -4, + 10, 22, 27, 22, 14, 8, 1, -6, -17, -30, -43, -49, -47, -38, -26, -18, + -10, 3, 17, 34, 45, 54, 59, 57, 53, 45, 37, 30, 22, 11, -3, -14, + -24, -34, -40, -45, -43, -39, -29, -21, -14, -6, 3, 16, 20, 17, 10, 3, + 0, -6, -15, -25, -33, -38, -37, -31, -21, -12, -6, 5, 15, 27, 39, 46, + 50, 51, 47, 44, 36, 29, 20, 10, 1, -10, -18, -27, -36, -40, -42, -37, + -29, -21, -14, -7, 1, 10, 16, 10, 3, -2, -3, -6, -12, -22, -28, -30, + -28, -23, -16, -11, -7, 0, 7, 19, 31, 42, 47, 47, 46, 46, 40, 33, + 21, 10, 2, -6, -12, -24, -33, -37, -38, -36, -31, -21, -14, -7, -2, 2, + 7, 8, 4, -2, -7, -12, -14, -19, -23, -24, -20, -16, -11, -6, -2, 3, + 9, 16, 24, 33, 37, 40, 44, 44, 40, 33, 22, 13, 5, -3, -8, -21, + -30, -35, -34, -32, -30, -23, -13, -6, -3, -3, -2, -2, -4, -7, -9, -12, + -13, -13, -14, -14, -11, -12, -4, -2, 2, 0, 3, 10, 18, 27, 32, 35, + 38, 40, 37, 32, 23, 13, 8, 2, -4, -11, -22, -27, -31, -30, -29, -24, + -14, -7, -8, -7, -10, -10, -10, -10, -11, -12, -13, -12, -11, -11, -7, -2, + 4, 5, 3, -2, 0, 8, 15, 21, 26, 30, 32, 37, 37, 32, 26, 16, + 10, 4, -4, -9, -16, -21, -26, -29, -28, -23, -15, -11, -9, -11, -13, -14, + -14, -13, -13, -12, -13, -12, -8, -3, 3, 6, 8, 10, 7, 1, -3, 2, + 8, 17, 22, 22, 27, 32, 37, 35, 29, 18, 11, 2, -4, -8, -14, -17, + -21, -23, -25, -22, -17, -11, -9, -11, -16, -16, -16, -16, -14, -15, -14, -11, + -5, 0, 4, 5, 6, 7, 6, 4, 0, 3, 8, 16, 21, 20, 24, 28, + 34, 35, 29, 17, 8, 3, 1, -3, -9, -15, -20, -21, -23, -22, -21, -17, + -13, -14, -18, -23, -22, -17, -13, -10, -9, -8, 0, 6, 9, 10, 8, 6, + 6, 4, 0, -2, 1, 10, 17, 20, 22, 25, 29, 31, 29, 20, 10, 2, + -2, 0, -5, -11, -18, -20, -19, -19, -19, -18, -16, -14, -18, -26, -26, -22, + -16, -13, -9, -6, 1, 7, 10, 10, 7, 7, 7, 5, 0, -4, -2, 7, + 14, 19, 22, 26, 30, 32, 30, 22, 13, 6, 1, -2, -7, -13, -16, -18, + -19, -19, -21, -21, -19, -17, -16, -23, -25, -23, -17, -10, -9, -4, 2, 8, + 10, 12, 9, 7, 5, 4, 2, -3, -2, 3, 9, 18, 23, 28, 29, 28, + 27, 26, 19, 12, 6, 0, -7, -11, -15, -17, -20, -21, -20, -22, -23, -25, + -24, -26, -27, -25, -20, -13, -5, 3, 9, 11, 15, 17, 15, 10, 4, 0, + -4, -5, -4, 2, 5, 13, 19, 25, 29, 28, 26, 25, 20, 16, 11, 2, + -5, -10, -10, -10, -14, -17, -21, -24, -26, -29, -27, -28, -28, -26, -23, -17, + -8, 1, 12, 15, 16, 14, 13, 10, 6, 0, -5, -6, -5, 1, 6, 12, + 20, 27, 30, 28, 24, 23, 21, 17, 11, 4, -6, -9, -10, -10, -11, -16, + -18, -21, -24, -26, -29, -28, -27, -25, -23, -18, -11, -2, 11, 15, 15, 12, + 11, 9, 6, 1, -6, -6, -2, 3, 7, 11, 19, 26, 28, 26, 22, 21, + 23, 24, 17, 10, 4, 0, -2, -5, -10, -15, -20, -25, -32, -36, -36, -35, + -32, -30, -26, -19, -10, 2, 14, 21, 21, 17, 13, 10, 7, 1, -5, -5, + -6, -4, 0, 6, 12, 19, 22, 24, 20, 21, 24, 29, 28, 20, 13, 8, + 3, 2, -4, -9, -16, -27, -34, -41, -44, -41, -38, -35, -31, -27, -18, -3, + 13, 26, 29, 23, 18, 14, 11, 8, 4, -2, -8, -11, -9, -6, 4, 9, + 16, 17, 16, 16, 23, 33, 37, 33, 26, 19, 12, 8, 1, -7, -15, -30, + -41, -50, -53, -50, -43, -38, -34, -28, -17, -3, 13, 26, 30, 26, 19, 14, + 12, 9, 4, -2, -10, -14, -13, -7, 4, 9, 12, 13, 13, 17, 25, 32, + 40, 39, 32, 24, 15, 11, 8, 1, -10, -27, -43, -51, -55, -52, -49, -45, + -40, -32, -21, -8, 9, 23, 31, 30, 24, 19, 17, 16, 11, 4, -7, -15, + -18, -14, -6, 2, 5, 7, 9, 14, 24, 35, 45, 48, 45, 34, 25, 16, + 8, 2, -11, -27, -46, -59, -64, -61, -53, -46, -40, -35, -24, -9, 8, 23, + 30, 31, 27, 24, 21, 17, 12, 4, -6, -15, -19, -17, -12, -3, 3, 4, + 6, 12, 25, 37, 45, 47, 47, 43, 35, 23, 12, 2, -10, -24, -42, -60, + -71, -71, -63, -55, -45, -36, -22, -7, 9, 22, 30, 35, 34, 31, 24, 19, + 13, 6, -3, -13, -20, -21, -16, -9, -3, -2, 4, 11, 26, 38, 45, 50, + 49, 48, 42, 31, 16, 4, -9, -21, -38, -59, -72, -77, -70, -61, -53, -41, + -26, -9, 7, 17, 26, 34, 41, 41, 35, 25, 17, 9, 0, -10, -21, -24, + -22, -15, -9, -7, -2, 10, 25, 39, 44, 47, 49, 52, 50, 39, 22, 6, + -8, -20, -34, -54, -70, -78, -77, -68, -61, -49, -33, -15, 3, 16, 25, 32, + 43, 49, 47, 37, 25, 16, 3, -10, -22, -29, -27, -22, -15, -12, -7, 7, + 25, 42, 47, 50, 53, 57, 57, 46, 31, 11, -5, -22, -39, -56, -72, -81, + -85, -81, -71, -56, -36, -16, 4, 19, 29, 37, 48, 55, 56, 48, 34, 20, + 7, -10, -25, -32, -34, -28, -21, -17, -14, 0, 20, 40, 50, 51, 53, 58, + 61, 53, 39, 18, -2, -18, -36, -53, -70, -80, -85, -86, -79, -67, -46, -23, + -2, 17, 27, 35, 44, 55, 62, 57, 44, 26, 9, -10, -23, -29, -32, -28, + -24, -20, -15, -4, 15, 35, 47, 50, 49, 53, 57, 53, 43, 24, 5, -14, + -32, -50, -64, -5, 0, -2, -3, -3, -3, -3, -2, -2, 1, 2, 3, 5, + 8, 11, 11, 10, 8, 5, 1, -6, -13, -19, -21, -18, -15, -13, -10, -7, + -2, 4, 8, 12, 17, 28, 33, 29, 23, 14, 7, -5, -19, -33, -42, -36, + -28, -24, -17, -13, -8, 1, 7, 15, 23, 33, 42, 42, 35, 26, 15, 0, + -16, -30, -44, -45, -34, -27, -20, -16, -13, -4, 4, 12, 21, 29, 40, 45, + 40, 30, 20, 6, -13, -25, -38, -45, -38, -31, -24, -18, -15, -10, -4, 5, + 17, 27, 35, 44, 43, 37, 27, 15, -4, -19, -31, -44, -44, -35, -30, -22, + -19, -16, -8, 2, 15, 25, 32, 42, 47, 42, 32, 18, 0, -16, -26, -39, + -45, -38, -31, -25, -19, -18, -14, -5, 11, 23, 29, 39, 46, 45, 38, 25, + 7, -8, -18, -31, -44, -43, -35, -30, -25, -25, -20, -9, 7, 21, 27, 36, + 48, 51, 44, 32, 14, -3, -16, -28, -42, -46, -41, -33, -27, -24, -23, -15, + 1, 16, 27, 33, 42, 47, 46, 38, 21, 5, -9, -21, -34, -44, -45, -39, + -31, -28, -26, -20, -8, 9, 25, 34, 41, 49, 51, 47, 31, 11, -6, -18, + -30, -42, -48, -45, -36, -28, -26, -23, -12, 6, 23, 33, 38, 43, 51, 50, + 36, 15, 0, -12, -22, -35, -50, -50, -40, -31, -29, -27, -18, 1, 20, 32, + 36, 43, 52, 56, 45, 23, 2, -10, -20, -33, -48, -56, -49, -36, -30, -26, + -18, -5, 17, 33, 39, 40, 46, 52, 49, 32, 9, -8, -18, -26, -40, -54, + -53, -39, -30, -28, -23, -12, 10, 31, 39, 38, 42, 54, 54, 41, 17, -5, + -15, -22, -35, -53, -59, -47, -36, -30, -24, -14, 6, 27, 40, 42, 43, 51, + 56, 46, 26, 3, -13, -22, -33, -49, -61, -55, -41, -32, -26, -18, 0, 22, + 38, 45, 43, 48, 55, 50, 33, 11, -10, -21, -29, -43, -59, -60, -46, -35, + -28, -18, -6, 15, 35, 45, 46, 45, 52, 53, 41, 20, -6, -19, -26, -38, + -54, -62, -53, -39, -29, -19, -11, 6, 29, 44, 48, 45, 47, 52, 49, 32, + 5, -18, -26, -32, -45, -61, -61, -48, -35, -23, -14, -2, 22, 42, 52, 50, + 46, 50, 50, 38, 12, -15, -26, -31, -43, -59, -65, -53, -37, -25, -16, -6, + 16, 40, 53, 53, 47, 49, 51, 42, 22, -10, -27, -31, -38, -54, -67, -63, + -46, -27, -18, -7, 10, 31, 52, 59, 53, 48, 50, 46, 32, 3, -24, -34, + -39, -50, -66, -68, -54, -35, -20, -8, 6, 23, 47, 62, 59, 52, 50, 48, + 37, 13, -18, -35, -40, -46, -62, -72, -63, -43, -25, -10, 6, 20, 41, 59, + 63, 55, 49, 46, 39, 21, -9, -31, -39, -42, -52, -68, -68, -52, -32, -17, + -4, 9, 31, 54, 66, 63, 54, 51, 44, 32, 6, -26, -40, -44, -51, -65, + -72, -61, -41, -23, -5, 9, 25, 48, 64, 66, 59, 54, 46, 33, 12, -17, + -36, -45, -51, -62, -73, -67, -48, -31, -11, 8, 21, 44, 64, 70, 64, 57, + 49, 36, 20, -8, -34, -47, -52, -58, -68, -73, -59, -40, -19, 4, 17, 36, + 58, 72, 73, 65, 56, 41, 26, 4, -24, -44, -55, -63, -69, -73, -66, -51, + -28, -2, 18, 32, 51, 67, 75, 72, 62, 46, 29, 11, -13, -37, -54, -64, + -70, -71, -70, -58, -38, -13, 14, 30, 48, 64, 73, 76, 69, 52, 34, 15, + -7, -31, -50, -62, -69, -71, -71, -66, -47, -19, 8, 26, 40, 58, 73, 81, + 76, 57, 39, 23, 2, -22, -45, -62, -71, -73, -71, -69, -57, -32, 0, 26, + 41, 55, 70, 81, 83, 64, 41, 24, 6, -15, -39, -60, -71, -73, -69, -69, + -62, -40, -11, 20, 39, 51, 65, 78, 86, 75, 50, 29, 11, -8, -30, -53, + -70, -77, -71, -66, -67, -53, -22, 13, 37, 49, 60, 75, 89, 84, 58, 33, + 16, -2, -22, -47, -68, -77, -72, -67, -68, -60, -34, 0, 29, 47, 56, 69, + 85, 88, 69, 40, 20, 4, -13, -35, -61, -76, -74, -65, -66, -65, -47, -15, + 20, 43, 53, 64, 81, 89, 77, 50, 26, 9, -10, -29, -51, -71, -78, -71, + -66, -64, -52, -27, 9, 38, 54, 62, 73, 85, 82, 60, 34, 13, -3, -19, + -40, -65, -80, -74, -68, -69, -61, -40, -4, 29, 49, 61, 72, 86, 86, 70, + 45, 21, 3, -16, -33, -56, -80, -78, -70, -70, -65, -50, -18, 20, 48, 62, + 68, 80, 88, 78, 53, 26, 5, -12, -26, -45, -72, -81, -71, -67, -64, -56, + -34, 4, 37, 57, 63, 73, 85, 83, 63, 37, 16, 0, -17, -36, -63, -79, + -74, -70, -69, -63, -44, -10, 26, 52, 62, 69, 81, 84, 69, 45, 22, 3, + -15, -28, -52, -75, -76, -69, -67, -64, -52, -24, 14, 45, 60, 65, 74, 82, + 75, 54, 32, 12, -6, -21, -44, -68, -78, -74, -71, -69, -60, -34, 2, 34, + 55, 66, 73, 79, 78, 61, 39, 20, 2, -16, -34, -56, -72, -74, -70, -71, + -66, -47, -14, 21, 48, 61, 68, 76, 80, 69, 46, 27, 11, -7, -26, -50, + -68, -72, -70, -70, -69, -54, -24, 10, 39, 57, 66, 72, 76, 70, 52, 33, + 16, -4, -20, -39, -59, -70, -71, -69, -67, -60, -37, -6, 27, 50, 62, 67, + 72, 74, 61, 41, 25, 10, -10, -31, -51, -67, -74, -73, -73, -68, -48, -16, + 17, 45, 60, 66, 73, 75, 66, 48, 29, 15, -3, -24, -45, -62, -70, -72, + -74, -70, -55, -26, 7, 32, 51, 63, 70, 73, 67, 51, 35, 24, 9, -16, + -38, -54, -64, -68, -75, -75, -62, -36, -5, 22, 45, 60, 69, 74, 68, 57, + 43, 29, 15, -9, -29, -45, -60, -67, -75, -76, -64, -44, -16, 10, 32, 52, + 63, 68, 66, 59, 48, 36, 24, 6, -17, -35, -51, -60, -70, -78, -72, -55, + -27, 1, 20, 39, 56, 65, 68, 60, 51, 41, 31, 15, -9, -27, -44, -58, + -67, -75, -73, -58, -35, -8, 11, 32, 50, 60, 61, 57, 53, 47, 37, 25, + 4, -19, -35, -48, -60, -73, -76, -67, -46, -18, 2, 20, 40, 56, 64, 62, + 56, 49, 43, 34, 15, -10, -31, -45, -57, -70, -78, -69, -52, -27, -4, 13, + 34, 52, 60, 57, 53, 52, 46, 36, 22, 1, -19, -35, -50, -65, -73, -70, + -58, -41, -17, 4, 22, 42, 55, 58, 57, 55, 50, 43, 32, 12, -11, -30, + -47, -61, -71, -72, -63, -46, -26, -6, 13, 30, 47, 53, 54, 56, 52, 46, + 38, 24, 5, -20, -39, -52, -63, -67, -66, -57, -37, -15, 3, 18, 37, 50, + 55, 59, 55, 49, 45, 32, 15, -10, -34, -50, -61, -66, -66, -58, -42, -24, + -4, 11, 27, 44, 50, 54, 57, 53, 49, 39, 23, 2, -23, -43, -57, -64, + -67, -62, -50, -33, -14, 4, 18, 37, 48, 53, 57, 55, 52, 44, 30, 13, + -14, -38, -54, -62, -65, -62, -54, -42, -24, -2, 13, 28, 41, 48, 56, 57, + 52, 45, 37, 23, 0, -28, -47, -57, -62, -63, -59, -50, -34, -14, 1, 16, + 35, 48, 56, 59, 59, 54, 45, 31, 8, -20, -42, -56, -62, -64, -60, -52, + -40, -23, -5, 10, 28, 43, 52, 56, 57, 56, 49, 38, 21, -8, -33, -46, + -56, -60, -59, -56, -47, -32, -15, 0, 17, 34, 47, 55, 58, 57, 53, 43, + 30, 8, -24, -42, -52, -59, -58, -57, -51, -42, -26, -8, 11, 29, 42, 50, + 57, 59, 55, 48, 34, 15, -15, -36, -45, -52, -55, -58, -55, -43, -31, -17, + -2, 16, 37, 50, 56, 58, 58, 54, 43, 23, -8, -33, -40, -47, -54, -57, + -58, -48, -34, -23, -10, 9, 31, 48, 54, 55, 55, 57, 50, 32, 3, -28, + -37, -41, -49, -55, -58, -49, -36, -27, -17, 1, 21, 41, 50, 52, 51, 54, + 55, 41, 13, -18, -32, -35, -42, -50, -57, -55, -41, -32, -24, -10, 10, 33, + 47, 50, 51, 54, 59, 49, 24, -8, -26, -30, -37, -46, -56, -59, -46, -35, + -29, -18, 2, 25, 44, 48, 47, 51, 57, 56, 36, 5, -20, -28, -31, -40, + -51, -58, -52, -39, -33, -25, -8, 15, 38, 49, 47, 50, 56, 60, 46, 15, + -11, -25, -30, -36, -49, -60, -54, -39, -33, -30, -14, 8, 32, 47, 44, 44, + 51, 59, 52, 26, -4, -20, -24, -29, -41, -54, -55, -43, -34, -33, -26, -8, + 17, 37, 43, 42, 48, 59, 60, 42, 13, -11, -21, -25, -36, -51, -59, -51, + -38, -34, -32, -17, 10, 33, 43, 43, 44, 55, 60, 46, 21, -6, -18, -22, + -28, -42, -54, -52, -39, -30, -32, -25, -4, 20, 36, 39, 39, 48, 60, 57, + 36, 10, -11, -19, -22, -34, -51, -58, -48, -35, -36, -34, -13, 13, 35, 41, + 38, 46, 59, 61, 44, 20, -5, -20, -22, -30, -46, -56, -53, -39, -34, -36, + -22, 1, 25, 39, 39, 42, 53, 60, 54, 34, 10, -10, -17, -21, -39, -57, + -59, -48, -38, -43, -35, -11, 16, 37, 43, 42, 52, 61, 58, 41, 19, -3, + -16, -21, -31, -50, -59, -53, -40, -39, -39, -22, 5, 30, 40, 38, 45, 58, + 64, 52, 28, 5, -12, -17, -23, -44, -58, -56, -46, -40, -43, -33, -7, 22, + 39, 41, 44, 55, 64, 60, 40, 13, -7, -16, -21, -35, -56, -60, -52, -44, + -43, -40, -21, 11, 34, 40, 40, 50, 61, 64, 53, 29, 6, -10, -16, -25, + -47, -62, -61, -53, -49, -47, -35, -5, 26, 42, 45, 49, 58, 65, 59, 39, + 15, -5, -16, -22, -37, -56, -61, -56, -50, -47, -42, -21, 11, 33, 40, 44, + 53, 63, 66, 54, 29, 8, -6, -15, -28, -52, -64, -60, -57, -53, -49, -31, + 1, 28, 40, 42, 51, 63, 66, 56, 36, 14, -3, -13, -25, -45, -61, -61, + -58, -54, -47, -38, -11, 20, 36, 41, 44, 55, 64, 60, 47, 28, 9, -4, + -15, -32, -56, -67, -64, -62, -55, -48, -27, 8, 29, 41, 47, 57, 66, 65, + 56, 39, 17, 0, -13, -27, -49, -66, -68, -67, -58, -48, -36, -8, 22, 38, + 45, 53, 63, 65, 61, 51, 28, 11, -4, -20, -40, -62, -70, -71, -68, -55, + -44, -24, 9, 30, 42, 52, 66, 69, 64, 58, 42, 20, 4, -14, -34, -57, + -71, -73, -73, -63, -51, -35, -5, 23, 38, 48, 62, 71, 69, 65, 54, 32, + 14, -6, -26, -48, -68, -79, -82, -72, -57, -42, -18, 11, 33, 48, 63, 73, + 72, 68, 62, 46, 22, 0, -21, -42, -63, -76, -83, -80, -65, -49, -28, -2, + 23, 42, 58, 71, 75, 72, 68, 56, 33, 10, -12, -32, -54, -73, -84, -87, + -73, -54, -36, -15, 11, 34, 52, 67, 73, 73, 72, 66, 48, 21, -6, -26, + -47, -67, -80, -88, -81, -62, -41, -23, 0, 27, 47, 65, 74, 74, 71, 67, + 57, 33, 4, -20, -42, -64, -77, -88, -88, -72, -49, -27, -7, 16, 40, 63, + 75, 75, 74, 69, 64, 46, 16, -13, -35, -57, -74, -87, -93, -81, -58, -35, + -17, 6, 33, 59, 73, 76, 76, 71, 68, 58, 29, -4, -29, -48, -68, -83, + -94, -92, -70, -42, -22, -4, 21, 51, 73, 78, 76, 73, 70, 63, 40, 7, + -24, -42, -60, -79, -91, -92, -76, -52, -30, -12, 9, 39, 66, 76, 76, 75, + 74, 70, 54, 24, -12, -36, -52, -72, -93, -100, -90, -64, -38, -21, -5, 25, + 61, 81, 81, 77, 78, 76, 63, 33, -5, -33, -49, -67, -90, -100, -92, -71, + -44, -21, -8, 14, 49, 75, 82, 77, 76, 75, 66, 45, 10, -27, -45, -59, + -80, -98, -98, -81, -52, -26, -12, 2, 34, 71, 86, 80, 75, 77, 71, 54, + 23, -17, -44, -57, -74, -93, -99, -87, -65, -36, -14, -4, 20, 55, 79, 82, + 78, 78, 75, 65, 41, 1, -34, -52, -67, -88, -104, -98, -76, -47, -23, -12, + 6, 45, 81, 90, 81, 79, 81, 72, 50, 11, -28, -50, -61, -81, -102, -103, + -84, -57, -30, -13, 1, 30, 70, 92, 88, 81, 80, 75, 59, 27, -15, -48, + -62, -76, -97, -106, -94, -69, -39, -16, -4, 17, 59, 92, 94, 87, 86, 83, + 67, 36, -4, -38, -61, -77, -96, -111, -102, -80, -53, -26, -8, 14, 50, 89, + 101, 93, 87, 83, 73, 46, 7, -31, -58, -72, -87, -106, -106, -88, -59, -31, + -12, 5, 33, 74, 99, 99, 90, 84, 78, 57, 22, -18, -49, -70, -84, -100, + -108, -96, -72, -43, -21, -3, 24, 61, 95, 106, 99, 90, 82, 65, 34, -6, + -40, -66, -83, -96, -106, -102, -82, -52, -27, -8, 15, 48, 86, 107, 105, 94, + 85, 73, 45, 6, -32, -61, -80, -91, -102, -106, -92, -63, -35, -15, 8, 37, + 74, 102, 109, 98, 87, 76, 54, 21, -16, -50, -76, -89, -98, -104, -98, -76, + -46, -23, -2, 25, 60, 93, 111, 106, 92, 82, 65, 35, -5, -39, -66, -83, + -95, -105, -105, -86, -57, -33, -11, 15, 50, 86, 111, 115, 102, 88, 71, 43, + 7, -32, -64, -86, -96, -100, -102, -92, -67, -40, -13, 13, 42, 75, 103, 116, + 106, 90, 74, 49, 16, -21, -54, -80, -94, -98, -100, -94, -75, -50, -23, 4, + 30, 62, 95, 117, 115, 100, 81, 57, 28, -10, -46, -75, -95, -102, -101, -97, + -83, -61, -32, -2, 24, 55, 87, 111, 118, 106, 88, 65, 35, 0, -36, -67, + -89, -101, -102, -98, -89, -68, -43, -13, 16, 46, 80, 107, 121, 116, 98, 75, + 47, 11, -27, -62, -87, -101, -104, -100, -93, -77, -51, -18, 13, 36, 67, 99, + 119, 119, 103, 81, 53, 21, -16, -52, -79, -96, -106, -102, -93, -82, -60, -30, + 3, 30, 59, 88, 111, 121, 111, 89, 61, 30, -4, -41, -74, -94, -106, -104, + -95, -87, -70, -41, -8, 22, 49, 81, 106, 120, 118, 98, 73, 41, 8, -30, + -64, -87, -104, -111, -100, -91, -77, -51, -21, 13, 41, 73, 100, 117, 122, 107, + 83, 52, 19, -18, -55, -82, -101, -111, -105, -93, -83, -60, -29, 5, 35, 64, + 92, 112, 121, 112, 88, 61, 29, -7, -45, -75, -94, -108, -108, -96, -87, -67, + -37, -5, 26, 52, 83, 105, 116, 116, 97, 70, 41, 7, -33, -67, -91, -105, + -110, -99, -88, -73, -48, -18, 15, 45, 74, 98, 114, 118, 104, 79, 51, 17, + -21, -58, -86, -102, -109, -103, -90, -77, -54, -23, 9, 36, 62, 88, 107, 114, + 107, 88, 63, 30, -8, -46, -77, -96, -107, -108, -97, -81, -63, -36, -4, 30, + 59, 84, 104, 115, 112, 95, 69, 38, 5, -33, -69, -94, -104, -105, -99, -87, + -72, -44, -11, 21, 47, 71, 97, 113, 113, 99, 77, 49, 17, -19, -57, -87, + -101, -105, -103, -90, -72, -54, -24, 10, 41, 64, 86, 104, 111, 104, 85, 57, + 25, -7, -42, -75, -96, -101, -98, -92, -79, -61, -36, -4, 28, 51, 74, 98, + 110, 107, 94, 70, 38, 5, -30, -64, -89, -101, -101, -95, -79, -63, -43, -14, + 21, 48, 68, 90, 105, 108, 97, 74, 44, 12, -20, -52, -83, -96, -96, -92, + -82, -67, -49, -24, 10, 39, 59, 79, 99, 107, 101, 83, 54, 21, -11, -41, + -71, -92, -98, -95, -84, -68, -54, -35, -5, 28, 54, 73, 92, 103, 103, 90, + 64, 31, -4, -34, -63, -85, -94, -92, -84, -70, -56, -38, -11, 19, 44, 64, + 83, 95, 98, 90, 66, 39, 9, -22, -50, -73, -86, -89, -84, -72, -59, -45, + -23, 6, 35, 58, 75, 89, 96, 92, 75, 49, 19, -14, -42, -63, -80, -88, + -84, -74, -60, -48, -30, -5, 23, 52, 70, 82, 91, 91, 79, 57, 29, -3, + -33, -54, -70, -84, -87, -79, -65, -50, -35, -16, 10, 41, 68, 80, 85, 88, + 82, 64, 36, 3, -28, -49, -60, -72, -83, -81, -66, -49, -37, -22, -2, 28, + 58, 74, 78, 83, 81, 69, 45, 14, -18, -42, -55, -66, -77, -79, -68, -53, + -39, -25, -8, 17, 46, 67, 72, 75, 74, 70, 53, 24, -9, -34, -48, -55, + -64, -74, -70, -55, -40, -28, -17, 3, 33, 61, 70, 71, 69, 68, 61, 37, + 3, -28, -44, -50, -57, -70, -73, -58, -41, -30, -21, -8, 21, 52, 67, 69, + 66, 66, 64, 44, 10, -22, -39, -48, -52, -61, -72, -62, -43, -29, -20, -12, + 7, 38, 62, 68, 61, 56, 60, 51, 23, -12, -36, -43, -44, -49, -65, -65, + -45, -29, -22, -19, -7, 24, 52, 65, 57, 52, 58, 57, 36, 0, -30, -38, + -37, -39, -55, -66, -52, -33, -23, -21, -14, 10, 40, 60, 59, 49, 51, 54, + 43, 11, -21, -35, -37, -33, -42, -55, -49, -29, -19, -20, -19, -5, 23, 49, + 54, 43, 42, 50, 49, 23, -12, -30, -34, -29, -31, -49, -54, -35, -19, -16, + -18, -11, 10, 39, 55, 45, 35, 41, 47, 31, -3, -26, -33, -28, -23, -36, + -47, -36, -18, -11, -16, -16, -3, 21, 42, 42, 32, 32, 40, 35, 13, -13, + -25, -24, -17, -22, -37, -38, -25, -16, -16, -19, -11, 7, 30, 42, 34, 27, + 33, 35, 19, -6, -21, -23, -17, -14, -23, -29, -21, -11, -10, -17, -16, -4, + 14, 30, 31, 20, 21, 29, 24, 6, -11, -16, -11, -5, -10, -20, -22, -15, + -12, -17, -21, -15, 0, 20, 29, 22, 17, 23, 25, 16, -2, -14, -14, -7, + -2, -9, -14, -12, -9, -11, -17, -17, -11, 3, 18, 17, 9, 13, 19, 17, + 7, -5, -5, 3, 8, 3, -7, -10, -12, -14, -20, -22, -17, -7, 9, 17, + 10, 8, 15, 18, 11, 2, -3, 1, 8, 9, 5, -3, -9, -12, -18, -21, + -21, -19, -4, 10, 9, 2, 5, 14, 16, 11, 4, 5, 13, 16, 14, 6, + -8, -14, -19, -23, -24, -21, -13, -2, 7, 3, -2, 8, 12, 11, 9, 10, + 14, 19, 20, 16, 4, -9, -17, -23, -26, -27, -24, -14, -2, 1, -5, 3, + 15, 17, 14, 14, 17, 22, 25, 20, 9, -8, -19, -25, -30, -29, -26, -22, + -11, 0, -3, -3, 9, 16, 19, 20, 21, 24, 28, 28, 20, 2, -16, -25, + -30, -34, -33, -32, -23, -9, -6, -8, 2, 15, 21, 24, 26, 29, 33, 34, + 30, 14, -11, -26, -33, -38, -38, -37, -34, -23, -12, -7, 0, 11, 21, 29, + 34, 35, 37, 39, 35, 21, -5, -26, -34, -39, -40, -42, -42, -31, -17, -9, + -4, 7, 19, 31, 38, 38, 41, 42, 40, 28, 3, -22, -36, -42, -45, -46, + -46, -37, -23, -14, -6, 6, 20, 32, 40, 40, 44, 46, 41, 31, 13, -12, + -32, -44, -47, -48, -49, -44, -32, -20, -8, 3, 15, 27, 40, 45, 47, 50, + 47, 39, 21, -6, -29, -42, -46, -51, -56, -52, -41, -24, -13, -4, 11, 27, + 41, 51, 52, 53, 52, 45, 29, 2, -25, -45, -50, -52, -57, -56, -49, -32, + -16, -4, 9, 22, 36, 49, 55, 56, 56, 50, 35, 11, -14, -37, -51, -57, + -61, -61, -56, -41, -23, -8, 8, 21, 33, 48, 61, 64, 60, 54, 40, 17, + -8, -34, -52, -59, -62, -63, -60, -49, -30, -14, 2, 19, 33, 47, 60, 66, + 67, 65, 50, 25, -3, -26, -47, -59, -68, -72, -66, -57, -38, -20, -5, 14, + 30, 44, 61, 71, 71, 68, 57, 34, 7, -20, -43, -58, -68, -72, -69, -62, + -45, -25, -10, 7, 24, 42, 59, 70, 74, 73, 65, 46, 16, -15, -38, -53, + -65, -77, -77, -70, -54, -34, -19, 0, 20, 41, 60, 74, 82, 80, 71, 54, + 27, -8, -36, -55, -68, -78, -82, -76, -61, -40, -20, -2, 17, 36, 57, 74, + 83, 82, 74, 62, 39, 3, -31, -49, -62, -75, -84, -84, -69, -47, -27, -13, + 6, 31, 56, 73, 82, 86, 80, 68, 49, 14, -24, -46, -60, -74, -83, -86, + -76, -54, -32, -15, 3, 23, 48, 71, 85, 87, 80, 71, 57, 27, -12, -41, + -57, -68, -78, -88, -84, -64, -41, -23, -5, 16, 40, 65, 84, 90, 87, 77, + 63, 36, -3, -34, -57, -69, -76, -85, -87, -73, -48, -27, -8, 13, 34, 60, + 83, 91, 86, 77, 66, 44, 9, -26, -53, -68, -74, -83, -88, -80, -56, -33, + -13, 9, 29, 55, 79, 93, 89, 76, 67, 52, 21, -15, -46, -69, -74, -77, + -84, -86, -67, -42, -20, 4, 23, 43, 71, 94, 95, 80, 67, 56, 32, 0, + -37, -66, -74, -73, -78, -87, -76, -50, -25, 1, 21, 37, 61, 88, 97, 84, + 67, 57, 38, 8, -25, -59, -77, -77, -76, -81, -80, -61, -34, -6, 20, 36, + 55, 80, 96, 91, 70, 54, 39, 17, -14, -51, -75, -79, -75, -77, -80, -68, + -40, -11, 15, 33, 48, 71, 92, 91, 73, 57, 45, 24, -3, -38, -68, -79, + -77, -76, -80, -74, -51, -19, 12, 32, 46, 65, 88, 96, 83, 59, 40, 24, + 4, -31, -67, -83, -80, -73, -73, -72, -55, -24, 9, 31, 44, 58, 78, 90, + 84, 63, 42, 28, 10, -18, -53, -77, -82, -76, -73, -74, -65, -37, -2, 27, + 42, 55, 73, 88, 90, 72, 47, 28, 13, -12, -45, -74, -84, -78, -70, -68, + -63, -43, -9, 23, 42, 52, 64, 78, 84, 75, 52, 32, 17, -3, -32, -62, + -79, -78, -71, -67, -65, -52, -19, 15, 38, 50, 61, 73, 80, 79, 59, 34, + 18, 3, -21, -51, -75, -81, -72, -64, -61, -54, -31, 4, 31, 48, 55, 63, + 73, 78, 67, 40, 21, 8, -12, -39, -65, -80, -76, -65, -58, -52, -38, -8, + 25, 45, 56, 61, 67, 74, 69, 47, 22, 7, -10, -31, -56, -75, -77, -66, + -57, -49, -37, -14, 16, 40, 53, 57, 61, 67, 69, 55, 30, 11, -6, -25, + -47, -69, -78, -70, -59, -51, -40, -20, 10, 34, 51, 58, 59, 63, 66, 59, + 36, 14, -2, -19, -40, -61, -75, -71, -59, -51, -41, -27, -2, 26, 47, 58, + 58, 59, 64, 63, 46, 19, -2, -17, -35, -56, -71, -75, -64, -50, -40, -26, + -6, 21, 43, 55, 57, 56, 58, 59, 47, 23, 1, -13, -29, -48, -63, -69, + -61, -48, -40, -29, -11, 13, 35, 48, 53, 51, 53, 57, 50, 33, 9, -10, + -25, -42, -56, -65, -64, -51, -40, -29, -13, 9, 30, 44, 50, 48, 47, 50, + 46, 35, 13, -8, -20, -33, -47, -57, -56, -48, -38, -30, -16, 1, 21, 35, + 44, 46, 42, 44, 44, 39, 21, -3, -18, -30, -40, -51, -57, -51, -37, -26, + -14, 0, 16, 33, 42, 43, 37, 34, 37, 35, 22, 1, -17, -27, -34, -41, + -48, -45, -36, -25, -11, 0, 11, 24, 34, 38, 35, 30, 29, 30, 24, 8, + -11, -24, -31, -36, -42, -42, -35, -25, -12, -2, 9, 21, 29, 33, 32, 27, + 25, 26, 23, 9, -8, -21, -31, -34, -36, -37, -33, -26, -13, -2, 8, 18, + 24, 28, 29, 27, 22, 20, 21, 14, -2, -17, -27, -30, -31, -33, -32, -26, + -14, -3, 6, 15, 22, 27, 26, 25, 22, 17, 17, 13, 3, -12, -25, -30, + -31, -30, -27, -24, -14, 0, 8, 16, 20, 22, 22, 21, 16, 11, 13, 13, + 3, -8, -21, -27, -26, -25, -25, -23, -12, 0, 6, 12, 18, 20, 22, 20, + 15, 9, 9, 10, 3, -9, -21, -29, -28, -23, -20, -19, -10, 3, 13, 17, + 19, 19, 21, 17, 11, 4, 1, 4, 0, -8, -17, -25, -24, -21, -19, -16, + -9, 4, 13, 17, 19, 20, 22, 19, 11, 3, -4, -3, -4, -12, -18, -26, + -28, -23, -16, -10, -5, 5, 18, 25, 25, 22, 21, 19, 9, 0, -9, -11, + -10, -13, -16, -24, -27, -22, -14, -8, -2, 7, 17, 25, 25, 22, 20, 17, + 10, -2, -10, -12, -13, -15, -18, -20, -24, -22, -16, -8, 3, 11, 17, 25, + 27, 23, 21, 17, 9, 0, -10, -12, -13, -18, -19, -20, -24, -23, -17, -10, + 0, 11, 19, 26, 30, 26, 24, 20, 12, 3, -8, -15, -18, -22, -25, -25, + -25, -24, -20, -12, 2, 15, 20, 25, 31, 33, 29, 23, 12, 3, -5, -15, + -23, -28, -28, -25, -22, -22, -18, -10, 2, 15, 19, 23, 30, 32, 28, 24, + 15, 7, 1, -13, -23, -27, -29, -28, -26, -24, -20, -14, -2, 13, 20, 24, + 32, 34, 32, 29, 22, 9, -2, -10, -21, -30, -34, -34, -29, -22, -20, -18, + -5, 14, 23, 25, 31, 36, 35, 30, 22, 10, 0, -8, -21, -34, -39, -36, + -32, -27, -20, -15, -5, 14, 27, 28, 32, 36, 35, 33, 25, 14, 0, -11, + -21, -34, -40, -41, -39, -30, -20, -13, -6, 10, 27, 30, 32, 35, 34, 36, + 29, 17, 5, -7, -16, -33, -45, -45, -43, -33, -24, -18, -9, 8, 26, 32, + 33, 39, 38, 36, 31, 20, 10, -6, -19, -32, -45, -47, -46, -39, -25, -12, + -3, 8, 22, 32, 32, 35, 35, 32, 31, 23, 14, 0, -15, -26, -43, -51, + -50, -43, -29, -17, -6, 5, 19, 34, 36, 33, 37, 37, 34, 25, 16, 5, + -11, -26, -41, -51, -55, -51, -36, -21, -7, 7, 16, 28, 37, 35, 35, 36, + 34, 30, 20, 9, -7, -22, -37, -49, -56, -54, -42, -25, -11, 2, 13, 24, + 35, 38, 37, 38, 37, 32, 25, 16, 1, -21, -38, -47, -56, -58, -50, -34, + -14, 4, 13, 20, 31, 40, 39, 35, 36, 34, 28, 20, 5, -15, -33, -44, + -55, -63, -54, -38, -19, -2, 10, 17, 30, 40, 41, 36, 38, 41, 33, 22, + 9, -13, -36, -50, -55, -63, -61, -44, -22, 2, 18, 22, 28, 38, 42, 39, + 34, 35, 34, 27, 14, -7, -29, -43, -51, -60, -63, -50, -30, -10, 8, 16, + 21, 32, 40, 40, 38, 39, 41, 35, 24, 6, -20, -41, -54, -62, -65, -58, + -39, -16, 7, 18, 22, 29, 39, 43, 40, 35, 38, 37, 27, 12, -14, -37, + -51, -58, -64, -64, -47, -22, -2, 14, 18, 24, 36, 44, 45, 41, 43, 43, + 32, 17, -8, -35, -54, -63, -67, -68, -56, -29, -4, 16, 24, 26, 35, 44, + 47, 43, 38, 38, 36, 24, 0, -30, -50, -57, -59, -63, -61, -40, -11, 11, + 20, 20, 26, 39, 48, 46, 40, 39, 42, 33, 12, -20, -47, -58, -60, -62, + -61, -49, -23, 2, 17, 21, 22, 33, 48, 51, 45, 43, 43, 38, 20, -10, + -41, -58, -61, -64, -62, -55, -35, -9, 10, 21, 23, 32, 50, 57, 49, 45, + 45, 43, 26, -6, -38, -58, -62, -65, -67, -61, -44, -15, 10, 23, 26, 28, + 44, 59, 55, 46, 42, 41, 33, 6, -30, -57, -64, -62, -64, -62, -50, -26, + 2, 18, 26, 28, 39, 59, 60, 48, 43, 43, 37, 14, -22, -53, -67, -63, + -65, -66, -55, -33, -2, 19, 28, 31, 37, 55, 64, 53, 41, 39, 37, 20, + -16, -48, -66, -65, -62, -66, -60, -43, -12, 15, 26, 31, 37, 53, 69, 63, + 46, 39, 38, 27, -5, -44, -72, -73, -65, -65, -63, -52, -24, 11, 31, 36, + 38, 48, 65, 70, 53, 38, 34, 28, 5, -35, -69, -78, -70, -65, -63, -53, + -30, 2, 26, 38, 43, 49, 62, 69, 58, 40, 33, 28, 9, -25, -61, -78, + -75, -69, -64, -55, -37, -7, 22, 36, 43, 49, 57, 66, 62, 44, 31, 29, + 15, -16, -52, -76, -77, -69, -63, -57, -44, -16, 14, 33, 42, 48, 54, 65, + 68, 52, 33, 27, 19, -6, -41, -72, -82, -74, -65, -59, -48, -24, 7, 29, + 43, 50, 53, 60, 67, 58, 39, 28, 22, 2, -31, -64, -82, -79, -71, -61, + -49, -31, -2, 22, 40, 51, 55, 58, 65, 63, 46, 29, 21, 9, -21, -56, + -79, -83, -77, -65, -54, -37, -10, 16, 36, 50, 57, 60, 65, 64, 50, 33, + 22, 11, -13, -47, -73, -82, -80, -70, -57, -42, -19, 8, 30, 49, 58, 61, + 62, 64, 56, 41, 24, 11, -6, -35, -66, -80, -82, -75, -61, -45, -25, -2, + 22, 43, 57, 63, 64, 63, 58, 49, 31, 15, -2, -26, -58, -79, -85, -81, + -66, -49, -31, -9, 17, 39, 55, 64, 69, 67, 61, 53, 35, 16, 1, -20, + -49, -75, -86, -85, -74, -54, -34, -11, 11, 33, 53, 64, 70, 68, 59, 51, + 40, 22, 5, -15, -40, -66, -79, -81, -78, -63, -41, -19, 4, 25, 44, 58, + 67, 72, 65, 57, 47, 29, 11, -8, -31, -61, -81, -85, -82, -68, -47, -25, + -3, 21, 44, 59, 68, 73, 68, 56, 47, 33, 15, -7, -27, -52, -76, -82, + -82, -72, -52, -30, -7, 13, 36, 57, 67, 74, 72, 61, 48, 36, 20, -4, + -25, -47, -71, -81, -81, -75, -56, -33, -10, 11, 30, 49, 63, 73, 74, 63, + 48, 37, 25, 6, -20, -41, -63, -79, -81, -77, -65, -43, -19, 4, 25, 45, + 63, 73, 76, 70, 55, 41, 28, 10, -15, -38, -59, -77, -83, -79, -70, -49, + -25, -4, 20, 40, 59, 74, 76, 73, 62, 46, 33, 16, -10, -34, -51, -68, + -83, -85, -75, -58, -34, -11, 14, 35, 55, 73, 79, 76, 69, 51, 33, 20, + -2, -30, -53, -67, -81, -84, -76, -61, -39, -14, 11, 32, 49, 67, 77, 74, + 68, 55, 37, 23, 5, -22, -45, -59, -73, -84, -82, -68, -46, -24, 3, 26, + 43, 62, 75, 74, 72, 61, 42, 25, 10, -15, -40, -57, -70, -83, -84, -71, + -49, -28, -6, 20, 41, 59, 72, 72, 69, 63, 48, 29, 13, -8, -31, -51, + -66, -79, -84, -75, -56, -37, -16, 12, 36, 55, 71, 74, 72, 69, 54, 34, + 16, -5, -28, -47, -61, -75, -85, -80, -60, -38, -20, 4, 30, 53, 68, 71, + 69, 67, 57, 39, 20, 0, -21, -41, -58, -71, -79, -79, -66, -45, -25, -3, + 23, 45, 61, 68, 69, 70, 63, 47, 29, 8, -16, -37, -56, -71, -80, -81, + -71, -52, -30, -7, 17, 41, 60, 67, 67, 68, 65, 50, 30, 10, -14, -31, + -47, -65, -77, -79, -70, -53, -33, -14, 8, 34, 56, 62, 62, 66, 64, 54, + 36, 15, -8, -27, -42, -61, -73, -75, -70, -56, -36, -14, 5, 26, 49, 60, + 59, 61, 60, 54, 42, 23, -2, -22, -35, -53, -69, -75, -70, -58, -41, -20, + -3, 18, 43, 59, 57, 57, 60, 56, 44, 28, 7, -17, -32, -47, -63, -73, + -72, -62, -46, -23, -6, 12, 35, 55, 60, 57, 59, 56, 49, 35, 14, -13, + -28, -40, -58, -72, -73, -62, -50, -31, -13, 5, 30, 51, 59, 56, 58, 61, + 56, 38, 17, -9, -26, -37, -52, -68, -74, -63, -50, -32, -14, 1, 22, 45, + 57, 56, 51, 54, 54, 41, 21, -4, -22, -31, -44, -59, -69, -63, -48, -36, + -21, -7, 11, 35, 52, 56, 53, 54, 58, 48, 30, 8, -17, -32, -43, -57, + -68, -69, -56, -39, -22, -8, 6, 28, 49, 57, 54, 51, 55, 52, 35, 13, + -13, -29, -36, -49, -64, -70, -58, -39, -23, -11, 0, 19, 43, 57, 55, 47, + 49, 55, 43, 18, -9, -28, -35, -42, -57, -69, -65, -45, -25, -11, 1, 14, + 37, 55, 60, 50, 45, 48, 42, 21, -4, -25, -35, -40, -50, -60, -61, -46, + -27, -15, -6, 6, 25, 46, 56, 50, 43, 45, 47, 33, 9, -15, -30, -37, + -45, -58, -64, -56, -36, -18, -8, 4, 18, 40, 58, 59, 47, 39, 41, 35, + 12, -15, -32, -38, -39, -46, -57, -55, -37, -17, -7, 1, 11, 27, 48, 56, + 47, 37, 38, 38, 21, -6, -24, -32, -37, -43, -54, -57, -44, -25, -9, 2, + 11, 24, 44, 57, 51, 38, 32, 31, 21, -5, -28, -35, -36, -36, -45, -51, + -41, -25, -8, 3, 8, 17, 33, 48, 49, 37, 31, 30, 25, 7, -18, -30, + -34, -37, -40, -48, -47, -33, -16, 1, 11, 16, 28, 42, 50, 43, 30, 25, + 22, 10, -12, -28, -33, -34, -35, -41, -44, -33, -18, -2, 9, 12, 20, 32, + 43, 41, 29, 24, 22, 14, -3, -21, -29, -30, -31, -35, -41, -35, -21, -6, + 9, 13, 18, 27, 38, 42, 29, 18, 16, 13, 4, -15, -27, -28, -27, -28, + -34, -34, -23, -10, 5, 11, 14, 22, 32, 37, 31, 20, 16, 12, 6, -9, + -22, -25, -27, -26, -32, -34, -27, -15, 0, 10, 12, 18, 28, 36, 35, 23, + 14, 11, 8, -3, -19, -28, -28, -25, -27, -32, -28, -16, -2, 11, 14, 14, + 22, 30, 31, 24, 15, 11, 8, 2, -11, -22, -25, -25, -26, -30, -28, -18, + -7, 5, 12, 14, 19, 27, 30, 26, 19, 13, 9, 4, -6, -20, -26, -23, + -24, -27, -27, -19, -6, 4, 12, 12, 13, 22, 26, 22, 15, 11, 10, 6, + -2, -12, -19, -19, -21, -25, -25, -20, -11, -3, 5, 9, 13, 19, 24, 24, + 21, 15, 12, 7, 2, -9, -20, -22, -22, -23, -24, -22, -11, -2, 7, 11, + 13, 17, 21, 21, 18, 13, 11, 7, 1, -7, -15, -19, -19, -21, -20, -18, + -12, -4, 2, 8, 11, 15, 17, 16, 15, 13, 11, 8, 4, -3, -11, -16, + -15, -19, -20, -16, -12, -5, 2, 5, 8, 14, 17, 15, 11, 10, 9, 8, + 4, -2, -6, -11, -12, -14, -18, -13, -7, -6, -3, 2, 6, 10, 13, 13, + 9, 8, 9, 6, 1, 0, -5, -9, -12, -12, -13, -12, -4, 1, 3, 4, + 4, 7, 11, 10, 7, 3, 3, 4, 2, -2, -3, -6, -7, -6, -6, -8, + -5, 2, 1, 1, 0, 1, 5, 5, 3, 0, 0, 5, 5, 2, 3, 0, + -3, -5, -6, -8, -7, -2, -3, -4, -2, -2, 3, 6, 4, 1, -3, 1, + 5, 3, 2, 0, -2, -3, -4, -5, -5, 1, 2, -3, -3, -4, -3, 4, + 4, 0, -5, -3, 3, 3, 2, 1, 1, 0, 0, 0, -3, -2, 1, -2, + -4, -3, -4, 1, 5, 2, -5, -7, -2, 2, -2, -2, 0, 2, 3, 2, + 2, 3, 6, 4, -2, -5, -6, -2, 3, -2, -9, -11, -5, 0, -3, -4, + -2, 3, 7, 8, 4, 2, 4, 3, 0, -6, -8, -6, 2, 4, -3, -10, + -10, -5, -2, -4, -5, -3, 5, 11, 11, 8, 5, 5, 4, -2, -9, -9, + -2, 0, -5, -13, -14, -10, -5, -4, -2, 2, 6, 14, 15, 11, 8, 6, + 1, -5, -10, -12, -6, 1, -2, -10, -15, -11, -4, -3, -6, -5, 2, 14, + 19, 14, 10, 10, 8, 3, -6, -15, -12, -4, -4, -12, -18, -17, -10, -2, + 0, 1, 6, 16, 25, 21, 12, 8, 4, -2, -8, -18, -20, -11, -6, -9, + -14, -14, -10, -3, 0, 1, 6, 13, 23, 25, 17, 13, 9, 1, -6, -13, + -18, -14, -11, -13, -17, -19, -14, -8, -3, 1, 7, 14, 24, 30, 24, 16, + 12, 4, -5, -11, -18, -19, -15, -12, -14, -19, -18, -14, -9, 0, 8, 13, + 19, 27, 28, 22, 18, 9, -4, -11, -14, -16, -15, -16, -16, -17, -16, -14, + -13, -6, 4, 12, 19, 26, 31, 27, 19, 13, 3, -8, -12, -16, -18, -19, + -17, -16, -20, -18, -15, -10, 1, 10, 18, 24, 31, 30, 22, 18, 9, -4, + -10, -14, -17, -20, -22, -19, -19, -22, -18, -13, -2, 9, 16, 21, 29, 36, + 29, 19, 12, 1, -7, -10, -15, -22, -24, -20, -18, -21, -21, -17, -8, 7, + 16, 23, 27, 33, 35, 26, 17, 7, -5, -11, -14, -22, -27, -24, -19, -22, + -25, -19, -11, 5, 16, 21, 25, 33, 38, 31, 18, 9, -2, -10, -13, -22, + -29, -28, -21, -18, -24, -22, -15, -3, 14, 21, 24, 30, 38, 36, 24, 13, + 4, -5, -9, -16, -28, -32, -25, -21, -25, -27, -18, -7, 8, 18, 24, 31, + 40, 40, 29, 16, 6, -3, -8, -16, -27, -31, -27, -22, -24, -27, -21, -10, + 4, 16, 22, 28, 37, 40, 33, 19, 7, 1, -5, -12, -23, -32, -28, -23, + -23, -27, -26, -15, -2, 13, 21, 25, 34, 41, 38, 28, 14, 4, -3, -11, + -22, -34, -35, -30, -26, -28, -29, -20, -3, 14, 24, 27, 32, 41, 42, 34, + 17, 4, -4, -11, -20, -32, -38, -33, -28, -27, -27, -22, -9, 7, 20, 29, + 34, 39, 40, 37, 24, 10, 2, -7, -16, -28, -40, -40, -33, -29, -28, -27, + -16, 5, 21, 28, 32, 36, 41, 40, 30, 12, 1, -6, -11, -22, -37, -42, + -34, -30, -29, -27, -20, -3, 16, 27, 32, 34, 39, 41, 35, 20, 6, -4, + -11, -16, -32, -45, -41, -33, -31, -27, -23, -10, 13, 28, 33, 35, 38, 39, + 36, 25, 8, -6, -11, -14, -26, -42, -45, -34, -29, -25, -23, -15, 6, 26, + 36, 36, 36, 37, 36, 29, 14, -2, -12, -14, -23, -42, -50, -42, -32, -23, + -18, -15, 3, 25, 38, 39, 35, 35, 37, 33, 18, -3, -15, -18, -20, -34, + -48, -47, -34, -22, -14, -12, -4, 17, 35, 41, 37, 34, 33, 33, 24, 6, + -13, -22, -22, -30, -45, -51, -39, -23, -10, -6, -3, 13, 32, 41, 37, 30, + 29, 31, 27, 10, -10, -22, -23, -26, -38, -48, -44, -28, -12, -5, -3, 9, + 27, 38, 38, 32, 28, 29, 27, 17, -4, -21, -26, -27, -35, -47, -49, -33, + -12, 2, 5, 9, 23, 35, 40, 34, 21, 23, 25, 22, 5, -20, -28, -28, + -29, -39, -50, -43, -19, 3, 10, 7, 15, 29, 41, 43, 28, 22, 23, 22, + 12, -16, -33, -32, -32, -38, -46, -43, -21, 3, 15, 13, 16, 29, 35, 35, + 27, 19, 19, 19, 15, -8, -30, -31, -30, -32, -40, -44, -29, -2, 18, 17, + 11, 22, 34, 37, 32, 21, 18, 20, 17, -2, -28, -37, -34, -34, -38, -42, + -30, -7, 16, 22, 16, 20, 31, 31, 29, 23, 17, 18, 19, 6, -21, -37, + -35, -34, -35, -38, -35, -15, 14, 27, 21, 13, 23, 31, 31, 26, 16, 12, + 16, 12, -10, -35, -39, -35, -36, -36, -34, -21, 6, 24, 24, 16, 20, 29, + 28, 27, 22, 16, 17, 15, -4, -29, -41, -39, -40, -39, -36, -29, -6, 20, + 27, 21, 19, 28, 33, 31, 27, 18, 14, 13, 2, -22, -41, -43, -40, -39, + -34, -28, -12, 16, 28, 24, 19, 25, 29, 27, 24, 19, 15, 12, 4, -15, + -34, -41, -40, -37, -32, -26, -18, 5, 24, 24, 20, 21, 26, 27, 26, 24, + 18, 12, 6, -9, -30, -44, -45, -41, -33, -26, -19, -2, 23, 29, 24, 22, + 24, 28, 25, 22, 18, 13, 7, -7, -24, -40, -46, -42, -36, -28, -21, -6, + 15, 28, 25, 22, 25, 29, 28, 23, 20, 14, 6, -6, -22, -40, -47, -42, + -36, -28, -23, -10, 13, 30, 28, 21, 23, 27, 28, 21, 18, 16, 9, -2, + -17, -33, -44, -44, -38, -31, -23, -14, 5, 25, 32, 25, 23, 26, 29, 24, + 16, 13, 8, -2, -15, -31, -43, -44, -37, -30, -23, -14, 1, 21, 31, 27, + 22, 24, 28, 25, 17, 13, 10, 3, -10, -27, -40, -44, -38, -32, -26, -17, + -3, 16, 31, 31, 25, 25, 30, 29, 17, 8, 7, 3, -8, -25, -39, -43, + -37, -31, -27, -18, -4, 13, 29, 32, 26, 24, 27, 27, 17, 9, 8, 6, + -5, -20, -34, -39, -37, -34, -30, -21, -8, 6, 23, 34, 31, 29, 28, 27, + 22, 13, 6, 5, -4, -18, -34, -40, -37, -34, -29, -23, -10, 5, 21, 32, + 29, 27, 29, 26, 20, 12, 4, 3, 0, -12, -28, -37, -35, -31, -29, -23, + -13, 1, 16, 30, 33, 29, 27, 25, 21, 15, 5, -2, -3, -9, -22, -35, + -36, -31, -29, -24, -14, 0, 12, 27, 35, 31, 29, 26, 21, 16, 8, -2, + -3, -7, -19, -34, -36, -32, -31, -28, -18, -3, 11, 22, 32, 32, 30, 29, + 23, 16, 11, 2, -3, -6, -17, -32, -37, -32, -30, -31, -23, -6, 9, 18, + 30, 36, 32, 31, 25, 17, 13, 4, -6, -8, -14, -26, -36, -34, -31, -31, + -25, -11, 6, 16, 24, 34, 35, 33, 28, 17, 16, 10, -3, -9, -13, -23, + -34, -36, -32, -31, -27, -16, 2, 16, 22, 30, 35, 33, 30, 21, 15, 11, + 0, -7, -11, -20, -31, -35, -31, -31, -29, -21, -6, 13, 21, 25, 32, 34, + 33, 26, 18, 13, 4, -6, -10, -19, -29, -34, -34, -29, -27, -24, -12, 7, + 20, 25, 30, 33, 32, 29, 21, 13, 7, -5, -11, -18, -28, -35, -36, -29, + -25, -24, -16, 3, 21, 26, 28, 34, 37, 34, 26, 12, 4, -5, -13, -20, + -30, -35, -39, -35, -24, -19, -13, -2, 15, 27, 30, 32, 34, 31, 28, 18, + 5, -6, -15, -20, -24, -31, -37, -35, -24, -19, -16, -9, 8, 24, 30, 30, + 33, 35, 35, 24, 5, -5, -11, -20, -27, -34, -40, -39, -30, -21, -16, -9, + 4, 20, 32, 36, 36, 36, 35, 31, 13, -3, -13, -23, -27, -29, -41, -44, + -33, -19, -11, -10, -4, 14, 32, 38, 34, 33, 36, 33, 18, -4, -13, -20, + -25, -28, -37, -43, -34, -22, -14, -8, -4, 9, 26, 39, 38, 35, 35, 34, + 23, 3, -12, -21, -28, -28, -31, -41, -40, -27, -15, -7, -6, 2, 20, 37, + 42, 36, 34, 35, 28, 9, -10, -18, -24, -26, -29, -38, -42, -32, -21, -11, + -6, -3, 12, 33, 45, 41, 37, 37, 29, 13, -4, -17, -26, -28, -28, -33, + -39, -37, -26, -15, -8, -7, 6, 29, 47, 46, 39, 34, 30, 20, 1, -18, + -26, -26, -25, -29, -37, -40, -31, -17, -8, -7, 0, 20, 42, 51, 45, 38, + 30, 18, 7, -10, -24, -27, -26, -24, -29, -38, -37, -27, -14, -9, -6, 11, + 36, 51, 47, 42, 34, 24, 14, -3, -20, -25, -23, -22, -26, -37, -42, -33, + -17, -8, -7, 4, 28, 50, 54, 45, 35, 24, 15, 3, -16, -24, -25, -22, + -23, -32, -41, -37, -22, -11, -8, 0, 21, 44, 54, 46, 34, 26, 18, 7, + -11, -22, -21, -20, -21, -28, -40, -43, -30, -15, -10, -3, 16, 40, 56, 52, + 37, 24, 16, 9, -6, -21, -22, -18, -17, -22, -35, -43, -34, -21, -14, -9, + 7, 34, 53, 54, 40, 29, 21, 14, 4, -14, -21, -17, -17, -22, -33, -46, + -45, -31, -16, -8, 4, 25, 50, 60, 49, 31, 20, 15, 9, -5, -17, -18, + -15, -17, -26, -42, -50, -40, -24, -11, -2, 18, 43, 56, 52, 35, 21, 17, + 11, 0, -12, -18, -14, -15, -22, -36, -50, -46, -30, -15, -3, 12, 35, 53, + 55, 41, 24, 18, 12, 5, -4, -15, -18, -15, -20, -33, -46, -49, -37, -21, + -7, 7, 25, 46, 54, 45, 27, 18, 14, 10, 3, -8, -15, -16, -18, -28, + -41, -49, -44, -29, -12, 4, 17, 35, 49, 49, 34, 19, 16, 15, 9, 1, + -10, -14, -16, -24, -38, -50, -49, -36, -18, -3, 10, 26, 43, 49, 38, 22, + 18, 20, 16, 9, -5, -13, -16, -23, -36, -50, -53, -43, -25, -8, 6, 21, + 38, 48, 44, 27, 19, 21, 19, 13, -2, -13, -17, -21, -30, -45, -52, -46, + -29, -10, 3, 14, 29, 42, 44, 30, 17, 19, 21, 17, 6, -8, -14, -19, + -26, -39, -49, -48, -36, -18, -2, 11, 27, 37, 42, 37, 22, 18, 21, 19, + 9, -5, -13, -18, -24, -33, -45, -46, -39, -24, -8, 6, 20, 33, 40, 38, + 27, 19, 22, 23, 17, 4, -8, -14, -22, -29, -43, -48, -43, -32, -16, -2, + 13, 25, 34, 39, 33, 23, 21, 23, 20, 9, -4, -11, -19, -25, -33, -43, + -42, -34, -20, -7, 3, 14, 24, 32, 31, 22, 20, 26, 28, 20, 6, -5, + -11, -18, -28, -42, -44, -38, -28, -15, -5, 8, 19, 28, 31, 24, 21, 25, + 27, 22, 10, 0, -6, -12, -22, -34, -38, -34, -30, -20, -11, 0, 11, 20, + 26, 23, 19, 22, 27, 25, 17, 7, -2, -7, -17, -29, -35, -35, -34, -26, + -16, -5, 7, 15, 23, 28, 24, 21, 22, 24, 20, 11, -2, -8, -14, -24, + -29, -31, -31, -27, -18, -9, 0, 8, 15, 22, 23, 20, 21, 24, 24, 19, + 7, -4, -10, -19, -26, -32, -34, -33, -24, -12, -2, 6, 14, 22, 26, 23, + 22, 22, 22, 21, 10, 0, -6, -15, -21, -24, -28, -31, -28, -17, -7, 2, + 7, 13, 19, 23, 23, 21, 19, 21, 18, 8, -2, -11, -17, -21, -24, -30, + -33, -25, -11, 0, 4, 9, 16, 20, 21, 20, 18, 18, 20, 14, 4, -6, + -12, -15, -17, -25, -32, -32, -20, -6, -3, -3, 7, 18, 23, 19, 16, 19, + 26, 24, 11, 0, -6, -9, -15, -25, -33, -35, -26, -15, -9, -6, 5, 17, + 22, 21, 17, 18, 25, 26, 16, 4, -5, -7, -9, -18, -29, -38, -35, -21, + -11, -9, -4, 9, 22, 25, 20, 16, 22, 30, 24, 8, -4, -5, -5, -13, + -25, -36, -38, -26, -16, -11, -10, 2, 19, 25, 18, 12, 19, 30, 28, 14, + 1, -2, 3, -3, -17, -31, -36, -29, -21, -18, -19, -11, 7, 20, 16, 10, + 16, 30, 36, 24, 8, 4, 8, 6, -12, -32, -40, -35, -26, -21, -20, -14, + 2, 19, 20, 10, 12, 24, 35, 29, 13, 5, 7, 9, -3, -23, -37, -37, + -31, -23, -21, -19, -8, 12, 19, 10, 6, 19, 36, 37, 23, 11, 12, 16, + 7, -15, -35, -43, -38, -30, -27, -23, -16, 2, 18, 16, 7, 13, 30, 38, + 29, 17, 12, 16, 15, -4, -27, -40, -39, -32, -28, -28, -24, -8, 12, 14, + 5, 7, 26, 40, 36, 24, 18, 21, 21, 4, -20, -38, -41, -37, -34, -30, + -26, -15, 4, 14, 7, 3, 18, 37, 41, 33, 24, 22, 25, 14, -10, -33, + -44, -42, -36, -32, -29, -22, -6, 10, 9, 2, 9, 29, 40, 37, 32, 28, + 29, 21, 0, -24, -39, -44, -44, -38, -31, -24, -16, 0, 7, 3, 8, 24, + 38, 43, 41, 32, 28, 25, 9, -15, -34, -44, -44, -39, -31, -26, -20, -10, + 3, 2, 1, 14, 32, 44, 46, 39, 33, 31, 20, -7, -31, -45, -47, -44, + -38, -30, -26, -16, 0, 5, 4, 12, 30, 45, 52, 47, 36, 30, 22, 0, + -24, -40, -50, -49, -42, -31, -24, -19, -10, -3, 3, 11, 24, 39, 51, 55, + 49, 37, 27, 8, -18, -36, -50, -54, -47, -36, -29, -25, -16, -6, 4, 10, + 18, 34, 52, 59, 53, 39, 28, 15, -8, -29, -45, -53, -51, -43, -34, -29, + -23, -14, -4, 7, 17, 33, 52, 62, 61, 50, 37, 23, -4, -28, -44, -55, + -55, -48, -38, -30, -25, -18, -8, 5, 13, 25, 46, 61, 65, 57, 43, 30, + 8, -17, -36, -50, -55, -53, -47, -39, -32, -24, -15, -3, 11, 25, 45, 62, + 68, 63, 51, 37, 14, -14, -34, -46, -56, -57, -51, -44, -33, -25, -18, -6, + 8, 19, 36, 55, 67, 65, 53, 42, 23, -4, -26, -40, -50, -56, -54, -49, + -41, -31, -23, -12, 1, 15, 34, 53, 65, 68, 59, 49, 33, 6, -21, -37, + -47, -57, -60, -56, -48, -38, -28, -16, -2, 14, 33, 51, 64, 70, 63, 53, + 38, 13, -14, -34, -44, -53, -59, -59, -53, -42, -30, -19, -8, 5, 26, 47, + 61, 68, 64, 57, 48, 26, -3, -26, -39, -49, -58, -63, -59, -49, -37, -24, + -13, 1, 20, 42, 55, 65, 69, 64, 54, 34, 7, -18, -34, -44, -55, -65, + -64, -54, -42, -31, -19, -8, 12, 37, 54, 61, 67, 67, 60, 46, 22, -8, + -29, -40, -50, -64, -70, -63, -50, -34, -21, -13, 2, 28, 51, 62, 68, 68, + 61, 51, 32, 3, -23, -36, -47, -60, -70, -67, -58, -44, -27, -14, -2, 22, + 45, 58, 65, 70, 68, 56, 38, 16, -11, -32, -45, -58, -69, -70, -62, -52, + -34, -17, -6, 13, 38, 54, 64, 70, 67, 59, 47, 29, -2, -28, -40, -51, + -65, -74, -67, -54, -37, -20, -11, 5, 33, 53, 59, 63, 67, 62, 51, 34, + 7, -20, -35, -46, -59, -72, -70, -60, -46, -27, -12, 1, 24, 47, 60, 64, + 69, 66, 54, 39, 15, -13, -32, -44, -54, -68, -71, -60, -48, -32, -18, -7, + 14, 38, 54, 61, 68, 70, 60, 46, 26, -2, -23, -38, -50, -63, -72, -68, + -55, -39, -24, -13, 5, 31, 52, 61, 67, 71, 64, 53, 34, 7, -21, -36, + -46, -57, -69, -72, -60, -42, -27, -17, -2, 21, 45, 58, 65, 69, 66, 57, + 42, 15, -13, -30, -43, -54, -66, -72, -65, -47, -30, -18, -5, 15, 40, 57, + 64, 67, 62, 56, 46, 23, -6, -27, -39, -50, -58, -67, -67, -51, -32, -20, + -9, 9, 31, 51, 60, 64, 64, 58, 48, 27, 1, -20, -34, -46, -56, -65, + -70, -57, -37, -22, -14, 2, 26, 48, 62, 66, 64, 59, 51, 34, 8, -18, + -31, -42, -52, -61, -70, -63, -42, -24, -15, -3, 19, 43, 60, 63, 60, 57, + 52, 39, 14, -14, -28, -36, -46, -54, -65, -66, -49, -29, -17, -9, 10, 33, + 54, 64, 62, 58, 53, 42, 23, -5, -25, -35, -46, -54, -63, -67, -54, -33, + -17, -7, 7, 30, 51, 61, 58, 55, 51, 43, 28, 3, -21, -30, -37, -46, + -56, -63, -56, -39, -22, -12, -5, 16, 40, 57, 58, 55, 53, 48, 38, 19, + -10, -27, -35, -45, -56, -66, -65, -49, -28, -14, -6, 8, 34, 57, 60, 55, + 54, 50, 42, 26, -4, -28, -35, -42, -52, -62, -63, -51, -32, -14, -5, 3, + 24, 47, 57, 53, 50, 47, 41, 33, 11, -20, -35, -40, -46, -56, -65, -58, + -38, -17, -4, 1, 15, 41, 57, 55, 47, 45, 42, 35, 17, -13, -33, -38, + -41, -49, -58, -55, -41, -21, -4, 0, 7, 29, 50, 52, 45, 42, 40, 37, + 25, 0, -28, -38, -38, -44, -53, -58, -46, -26, -6, 3, 4, 18, 42, 53, + 47, 41, 39, 37, 30, 10, -21, -41, -43, -41, -47, -54, -46, -29, -8, 7, + 9, 13, 31, 46, 45, 37, 33, 33, 28, 15, -10, -35, -42, -38, -39, -45, + -46, -32, -10, 6, 9, 8, 19, 38, 44, 38, 30, 29, 30, 19, -3, -29, + -42, -38, -34, -40, -43, -32, -14, 3, 11, 11, 15, 30, 41, 39, 30, 25, + 25, 19, 4, -21, -40, -42, -32, -30, -33, -29, -15, 2, 11, 10, 8, 17, + 30, 35, 30, 23, 24, 23, 11, -11, -32, -43, -34, -26, -29, -29, -18, -3, + 9, 12, 9, 12, 26, 35, 32, 21, 18, 18, 12, -6, -29, -43, -36, -22, + -22, -25, -15, 1, 10, 11, 10, 8, 17, 29, 29, 21, 16, 17, 15, 2, + -21, -39, -39, -24, -17, -20, -16, -5, 9, 13, 10, 7, 12, 24, 28, 23, + 14, 12, 11, 4, -14, -33, -39, -28, -15, -14, -12, -6, 5, 11, 9, 7, + 7, 16, 26, 25, 16, 10, 11, 6, -8, -24, -37, -32, -17, -12, -11, -5, + 5, 11, 11, 10, 7, 12, 21, 21, 16, 7, 4, 3, -6, -20, -32, -32, + -20, -8, -5, 0, 5, 11, 11, 9, 8, 8, 13, 17, 16, 9, 3, 2, + -3, -13, -25, -31, -23, -9, -4, -2, 5, 11, 14, 11, 7, 6, 12, 15, + 12, 5, -2, -2, -3, -11, -22, -29, -24, -9, 0, 3, 8, 13, 13, 12, + 8, 4, 5, 7, 9, 6, -3, -5, -4, -5, -14, -24, -23, -13, 0, 4, + 6, 10, 14, 14, 9, 3, 3, 5, 6, 4, -4, -6, -5, -5, -9, -18, + -20, -15, -4, 6, 9, 11, 13, 13, 10, 5, 1, 0, -3, 0, -4, -6, + -6, -5, -4, -11, -16, -16, -9, 3, 8, 11, 11, 10, 11, 8, 3, -2, + -5, -4, -3, -5, -6, -6, -2, -5, -12, -15, -13, -2, 8, 9, 11, 11, + 11, 7, 4, 0, -6, -6, -4, -4, -6, -6, -2, 0, -7, -13, -15, -5, + 8, 13, 12, 9, 11, 9, 4, -5, -11, -11, -8, -5, -5, -5, 0, 4, + 3, -4, -11, -8, 3, 11, 12, 8, 7, 4, 2, -2, -10, -14, -13, -7, + -3, -4, -2, 3, 4, 1, -8, -8, 3, 13, 17, 12, 11, 7, 1, -6, + -16, -21, -19, -13, -7, -2, 3, 7, 10, 10, 1, -6, -2, 8, 14, 12, + 10, 4, -2, -6, -15, -21, -20, -15, -8, -2, 3, 5, 9, 14, 5, -6, + 1, 12, 18, 14, 9, 7, 2, -4, -18, -28, -27, -22, -12, -5, 3, 9, + 13, 18, 16, 5, 1, 7, 14, 13, 8, 5, -5, -9, -17, -26, -26, -23, + -15, -4, 5, 8, 11, 17, 17, 7, 2, 7, 16, 18, 10, 4, -2, -6, + -16, -31, -33, -27, -18, -9, 0, 7, 12, 18, 22, 16, 9, 9, 16, 20, + 13, 5, -2, -9, -18, -33, -37, -29, -22, -13, -4, 7, 15, 21, 25, 21, + 15, 13, 17, 20, 14, 5, -3, -8, -18, -35, -42, -36, -24, -16, -6, 5, + 13, 23, 27, 25, 20, 17, 19, 20, 15, 5, -3, -8, -21, -35, -45, -39, + -25, -18, -11, 3, 16, 25, 29, 27, 26, 24, 23, 21, 17, 8, -4, -12, + -23, -35, -46, -46, -34, -22, -15, -3, 13, 25, 31, 33, 34, 31, 28, 25, + 20, 11, -4, -12, -22, -38, -49, -51, -39, -26, -21, -11, 8, 24, 34, 35, + 36, 37, 35, 29, 21, 13, 0, -11, -20, -36, -48, -52, -46, -31, -22, -14, + 1, 19, 34, 38, 39, 40, 38, 34, 24, 15, 0, -14, -21, -34, -47, -53, + -50, -35, -22, -17, -5, 13, 31, 37, 38, 42, 41, 37, 28, 21, 9, -8, + -19, -30, -44, -50, -53, -46, -32, -23, -11, 7, 26, 39, 43, 49, 48, 42, + 32, 20, 9, -9, -21, -31, -46, -52, -54, -50, -35, -24, -13, 4, 23, 40, + 46, 48, 49, 46, 37, 26, 13, -4, -20, -29, -42, -50, -53, -54, -43, -31, + -21, -2, 17, 36, 47, 53, 56, 51, 42, 29, 17, 3, -16, -30, -41, -51, + -55, -57, -51, -35, -24, -9, 11, 30, 47, 53, 57, 55, 46, 34, 20, 6, + -12, -29, -43, -52, -55, -55, -55, -42, -29, -12, 8, 25, 41, 55, 62, 59, + 51, 37, 23, 10, -6, -24, -40, -51, -56, -58, -58, -48, -33, -19, 2, 22, + 41, 55, 61, 61, 56, 45, 28, 11, -3, -19, -37, -51, -57, -58, -58, -54, + -39, -23, -2, 20, 36, 52, 64, 65, 58, 48, 33, 19, 4, -13, -35, -51, + -58, -61, -62, -60, -47, -29, -7, 17, 34, 50, 67, 70, 62, 50, 35, 20, + 6, -8, -29, -47, -57, -62, -61, -60, -54, -37, -15, 10, 29, 44, 60, 68, + 66, 56, 42, 24, 12, 1, -19, -41, -55, -60, -62, -61, -57, -43, -21, 7, + 24, 36, 53, 66, 67, 59, 46, 30, 15, 5, -11, -32, -48, -58, -63, -62, + -59, -50, -32, -3, 22, 35, 49, 60, 66, 63, 53, 38, 19, 8, -5, -25, + -43, -57, -64, -64, -62, -54, -39, -13, 16, 32, 46, 59, 65, 66, 56, 45, + 26, 11, 3, -17, -39, -56, -65, -67, -62, -56, -44, -21, 10, 29, 40, 54, + 63, 68, 61, 49, 33, 13, 2, -14, -34, -50, -64, -67, -63, -56, -44, -26, + 2, 27, 38, 49, 57, 64, 61, 50, 36, 17, 6, -7, -27, -44, -60, -67, + -63, -57, -48, -32, -7, 22, 36, 44, 53, 60, 62, 55, 41, 21, 7, -3, + -20, -40, -58, -68, -65, -57, -47, -34, -14, 16, 37, 42, 47, 55, 59, 53, + 42, 27, 10, -2, -14, -30, -47, -60, -63, -57, -49, -38, -20, 5, 30, 40, + 44, 52, 57, 57, 46, 31, 13, -2, -12, -27, -44, -57, -64, -61, -50, -38, + -20, 2, 25, 39, 41, 49, 55, 54, 45, 32, 17, 0, -12, -23, -37, -50, + -59, -61, -52, -38, -22, -6, 17, 35, 39, 42, 48, 53, 48, 36, 22, 4, + -9, -18, -30, -45, -56, -59, -54, -42, -27, -10, 12, 29, 37, 38, 44, 50, + 47, 37, 25, 9, -5, -13, -23, -38, -50, -55, -54, -45, -32, -17, 5, 25, + 34, 35, 39, 46, 48, 40, 29, 13, -3, -11, -21, -33, -44, -51, -54, -47, + -34, -17, 2, 21, 32, 34, 34, 38, 42, 39, 27, 15, 1, -7, -13, -25, + -36, -45, -49, -46, -36, -23, -6, 15, 27, 31, 31, 34, 39, 38, 30, 18, + 3, -6, -10, -19, -32, -40, -46, -45, -36, -24, -11, 8, 24, 29, 27, 29, + 34, 36, 30, 18, 4, -5, -5, -12, -25, -34, -39, -41, -37, -24, -11, 4, + 18, 24, 25, 25, 29, 29, 26, 19, 5, -6, -6, -6, -18, -28, -33, -37, + -34, -24, -11, 2, 15, 24, 23, 20, 24, 27, 22, 14, 4, -4, -4, -5, + -15, -24, -26, -29, -32, -27, -13, 2, 14, 21, 21, 18, 21, 23, 20, 13, + 5, -3, -5, -4, -9, -16, -21, -25, -28, -25, -14, 1, 10, 16, 19, 16, + 16, 18, 16, 11, 5, -2, -5, -4, -6, -12, -17, -20, -22, -22, -17, -4, + 8, 13, 16, 15, 13, 15, 14, 10, 4, -4, -6, -6, -5, -7, -11, -15, + -17, -17, -15, -3, 10, 13, 14, 11, 7, 8, 9, 5, -3, -8, -7, -4, + -2, -2, -6, -10, -9, -10, -12, -5, 11, 15, 13, 11, 5, 6, 7, 3, + -6, -10, -8, -6, -6, -2, 1, -2, -6, -6, -7, -5, 8, 14, 10, 7, + 4, 0, 1, -2, -6, -12, -11, -6, -2, 4, 8, 4, -2, -2, -4, -5, + 3, 12, 8, 5, 4, 0, 0, -2, -8, -13, -15, -12, -7, -3, 6, 10, + 7, 5, 6, 4, 6, 14, 10, 3, 0, -6, -10, -7, -10, -16, -19, -15, + -8, 0, 11, 17, 13, 10, 11, 7, 5, 8, 9, 2, -4, -7, -12, -10, + -10, -16, -21, -19, -13, -4, 10, 21, 22, 17, 17, 14, 9, 9, 9, 3, + -7, -12, -17, -16, -14, -20, -25, -21, -15, -5, 10, 23, 27, 25, 22, 18, + 11, 8, 4, -2, -9, -14, -18, -19, -14, -15, -23, -25, -20, -10, 9, 22, + 29, 29, 26, 23, 16, 12, 6, 1, -6, -14, -18, -22, -20, -19, -27, -28, + -25, -18, 0, 19, 32, 36, 33, 31, 23, 14, 7, 1, -4, -15, -23, -25, + -24, -19, -25, -32, -29, -20, -3, 16, 31, 40, 38, 36, 29, 16, 9, 1, + -4, -12, -23, -26, -28, -24, -26, -34, -33, -24, -8, 12, 29, 41, 44, 44, + 37, 22, 11, 4, -4, -11, -24, -31, -32, -31, -30, -36, -39, -30, -11, 11, + 29, 43, 51, 50, 44, 32, 15, 4, -4, -11, -24, -32, -33, -33, -34, -38, + -42, -35, -17, 4, 24, 42, 56, 60, 52, 38, 19, 7, 1, -13, -28, -37, + -37, -35, -37, -39, -43, -37, -19, 3, 22, 41, 57, 64, 57, 44, 26, 7, + -2, -11, -24, -35, -41, -40, -38, -39, -43, -40, -24, 0, 20, 37, 55, 65, + 63, 50, 32, 9, -4, -10, -24, -36, -42, -42, -41, -41, -41, -39, -26, -2, + 19, 34, 51, 64, 66, 55, 38, 15, -3, -8, -20, -34, -42, -44, -43, -44, + -45, -45, -35, -12, 14, 31, 50, 66, 73, 65, 49, 28, 7, -6, -18, -35, + -45, -49, -51, -53, -51, -47, -37, -16, 10, 30, 49, 69, 78, 72, 56, 35, + 14, -4, -17, -33, -46, -51, -55, -56, -54, -51, -40, -20, 5, 26, 44, 64, + 76, 77, 64, 41, 19, 1, -14, -30, -43, -50, -57, -60, -58, -54, -43, -24, + -2, 21, 39, 61, 76, 79, 72, 52, 28, 9, -10, -26, -41, -49, -54, -61, + -62, -59, -51, -33, -10, 14, 34, 55, 75, 81, 79, 63, 39, 19, -2, -23, + -40, -51, -56, -64, -67, -64, -56, -39, -16, 9, 29, 51, 73, 83, 82, 73, + 50, 27, 9, -18, -40, -52, -56, -63, -69, -69, -61, -43, -20, 2, 21, 42, + 66, 81, 82, 76, 59, 36, 19, -6, -33, -50, -57, -61, -71, -76, -68, -52, + -28, -2, 17, 36, 62, 83, 86, 82, 69, 43, 22, 2, -28, -51, -60, -63, + -67, -76, -74, -57, -34, -7, 14, 29, 53, 76, 87, 84, 75, 54, 33, 14, + -18, -46, -58, -62, -69, -80, -84, -68, -44, -18, 7, 26, 49, 75, 91, 92, + 82, 64, 42, 21, -8, -43, -63, -68, -68, -75, -86, -76, -48, -22, 4, 23, + 41, 66, 87, 92, 83, 69, 51, 31, 6, -31, -59, -67, -69, -74, -88, -87, + -62, -34, -7, 17, 36, 62, 87, 96, 90, 76, 60, 39, 14, -23, -58, -70, + -71, -73, -83, -89, -68, -37, -13, 9, 26, 51, 79, 94, 91, 80, 68, 52, + 28, -8, -48, -67, -70, -73, -84, -96, -83, -49, -22, 0, 20, 44, 75, 96, + 98, 88, 75, 61, 40, 6, -39, -67, -72, -75, -83, -95, -91, -60, -29, -7, + 13, 36, 66, 89, 97, 92, 78, 65, 50, 22, -21, -58, -71, -73, -78, -91, + -98, -79, -45, -15, 4, 25, 56, 84, 101, 99, 86, 73, 60, 35, -9, -53, + -72, -77, -80, -90, -98, -85, -51, -20, -2, 18, 48, 77, 96, 99, 87, 75, + 62, 46, 9, -39, -68, -75, -75, -83, -95, -94, -67, -30, -7, 8, 34, 68, + 92, 102, 93, 82, 72, 58, 26, -24, -61, -75, -78, -85, -97, -99, -78, -42, + -12, 6, 28, 59, 87, 102, 99, 86, 74, 62, 38, -7, -52, -76, -81, -83, + -93, -100, -90, -57, -23, -2, 18, 48, 80, 102, 103, 92, 81, 71, 51, 9, + -41, -72, -83, -85, -93, -100, -92, -65, -32, -7, 13, 39, 72, 97, 103, 95, + 85, 73, 55, 25, -21, -61, -79, -83, -90, -99, -97, -77, -45, -17, 1, 24, + 59, 93, 107, 103, 92, 85, 72, 42, -6, -54, -80, -86, -91, -104, -105, -87, + -56, -23, 0, 18, 48, 85, 106, 106, 96, 87, 77, 52, 13, -35, -71, -84, + -88, -98, -106, -96, -70, -40, -14, 6, 31, 70, 103, 111, 103, 95, 88, 68, + 29, -19, -61, -84, -91, -99, -106, -101, -80, -51, -22, 2, 23, 56, 91, 109, + 108, 98, 89, 76, 45, 1, -44, -76, -87, -92, -102, -104, -90, -64, -34, -11, + 8, 37, 78, 108, 113, 106, 96, 85, 61, 19, -29, -68, -88, -94, -102, -104, + -93, -73, -46, -21, 2, 28, 63, 98, 113, 109, 100, 89, 70, 33, -14, -55, + -81, -91, -98, -104, -98, -79, -54, -30, -9, 18, 52, 89, 108, 110, 104, 96, + 79, 46, 2, -40, -71, -90, -100, -104, -100, -86, -67, -44, -19, 7, 40, 77, + 105, 115, 109, 99, 86, 58, 17, -29, -63, -86, -97, -101, -101, -92, -74, -50, + -26, -4, 28, 66, 98, 114, 113, 102, 90, 68, 33, -15, -53, -76, -93, -101, + -104, -96, -79, -57, -34, -15, 15, 56, 90, 110, 115, 105, 93, 75, 44, 0, + -43, -68, -86, -98, -101, -98, -83, -65, -42, -22, 4, 41, 79, 104, 113, 107, + 96, 81, 57, 16, -31, -59, -79, -95, -101, -100, -90, -71, -49, -30, -9, 28, + 67, 97, 110, 107, 97, 86, 65, 30, -14, -47, -67, -84, -98, -102, -96, -79, + -59, -41, -22, 14, 53, 90, 110, 111, 101, 90, 75, 45, 2, -39, -64, -79, + -93, -102, -101, -87, -64, -44, -28, 0, 39, 81, 108, 110, 102, 93, 82, 58, + 18, -25, -54, -70, -85, -101, -103, -94, -72, -53, -39, -14, 25, 70, 104, 112, + 103, 96, 88, 70, 34, -13, -48, -65, -78, -97, -108, -101, -79, -55, -42, -24, + 11, 56, 96, 111, 103, 94, 90, 77, 46, 5, -34, -56, -71, -92, -109, -109, + -91, -64, -46, -30, 0, 44, 89, 112, 108, 95, 88, 80, 57, 16, -27, -54, + -66, -82, -104, -112, -100, -71, -46, -34, -13, 29, 80, 111, 112, 97, 86, 84, + 69, 32, -15, -48, -61, -72, -94, -109, -106, -82, -54, -37, -23, 11, 61, 101, + 113, 101, 85, 80, 75, 48, 4, -37, -56, -64, -84, -107, -112, -90, -60, -37, + -29, -7, 43, 91, 111, 103, 86, 80, 77, 58, 20, -24, -52, -61, -75, -100, + -111, -99, -72, -44, -27, -12, 29, 77, 105, 106, 91, 80, 75, 64, 33, -9, + -43, -58, -69, -94, -111, -104, -78, -49, -28, -18, 11, 62, 97, 107, 94, 80, + 75, 69, 47, 6, -36, -55, -62, -81, -105, -108, -87, -59, -33, -18, 1, 46, + 86, 103, 97, 83, 75, 69, 52, 19, -23, -50, -59, -74, -97, -106, -91, -64, + -38, -21, -9, 26, 70, 95, 95, 80, 71, 69, 60, 35, -6, -40, -53, -64, + -87, -102, -96, -72, -45, -25, -14, 13, 56, 87, 95, 86, 75, 69, 60, 41, + 6, -32, -54, -62, -77, -95, -99, -79, -51, -23, -8, 6, 39, 75, 92, 87, + 72, 64, 62, 49, 21, -17, -47, -57, -67, -86, -97, -87, -59, -32, -16, -4, + 25, 63, 89, 92, 78, 67, 63, 53, 27, -10, -40, -55, -63, -78, -93, -89, + -65, -36, -17, -7, 11, 44, 77, 89, 79, 65, 61, 58, 41, 8, -26, -50, + -59, -67, -83, -90, -76, -47, -25, -13, 3, 30, 63, 85, 82, 70, 63, 58, + 45, 14, -18, -43, -56, -63, -74, -84, -78, -52, -26, -13, -2, 19, 46, 73, + 81, 68, 57, 55, 49, 27, -5, -32, -48, -54, -63, -77, -80, -60, -34, -17, + -5, 10, 34, 62, 79, 71, 57, 52, 48, 31, 2, -26, -45, -50, -53, -65, + -75, -63, -37, -16, -6, 4, 19, 45, 68, 70, 57, 49, 49, 39, 16, -11, + -33, -45, -49, -56, -70, -71, -51, -26, -8, 2, 13, 35, 63, 76, 63, 48, + 43, 38, 23, -7, -32, -45, -47, -47, -58, -67, -55, -30, -8, 0, 4, 20, + 46, 68, 65, 47, 38, 38, 31, 8, -19, -37, -44, -42, -48, -63, -62, -41, + -16, -2, 5, 16, 37, 61, 68, 53, 38, 34, 31, 14, -14, -33, -40, -38, + -41, -54, -60, -46, -20, -5, -3, 6, 25, 49, 63, 55, 38, 32, 33, 24, + 1, -23, -34, -35, -36, -45, -59, -55, -30, -9, -3, 2, 16, 39, 59, 59, + 44, 32, 30, 26, 7, -20, -33, -33, -32, -40, -53, -54, -35, -12, -3, -2, + 10, 29, 48, 55, 45, 32, 28, 27, 14, -10, -27, -30, -28, -34, -46, -53, + -41, -17, -5, -5, 5, 24, 44, 54, 46, 32, 25, 25, 18, -4, -25, -31, + -24, -27, -39, -47, -42, -21, -4, -2, 1, 15, 35, 46, 44, 31, 22, 23, + 20, 6, -15, -26, -23, -20, -29, -41, -42, -29, -11, -4, -4, 7, 26, 42, + 47, 37, 25, 21, 19, 9, -10, -25, -25, -18, -24, -38, -40, -29, -11, 1, + 0, 3, 19, 34, 42, 33, 19, 14, 15, 10, -5, -21, -24, -15, -13, -26, + -35, -31, -17, -2, 0, -2, 11, 26, 37, 34, 20, 14, 13, 12, 2, -17, + -25, -17, -12, -21, -31, -30, -19, -4, 4, 1, 9, 22, 32, 32, 19, 9, + 9, 10, 4, -11, -21, -16, -9, -14, -23, -26, -20, -8, 0, -2, 3, 15, + 26, 31, 24, 12, 9, 10, 6, -5, -17, -19, -12, -11, -18, -25, -22, -10, + 1, 2, 2, 11, 22, 29, 24, 10, 3, 5, 4, -4, -13, -15, -8, -5, + -10, -16, -18, -14, -5, -2, 0, 6, 13, 20, 23, 16, 6, 5, 5, 0, + -7, -12, -12, -8, -7, -12, -19, -18, -7, 0, 2, 7, 13, 18, 20, 13, + 3, -2, 1, -2, -6, -8, -6, -3, -2, -2, -10, -14, -10, -6, -4, 0, + 4, 9, 14, 15, 6, -2, -2, -2, -4, -4, -5, -3, 2, 3, -3, -10, + -9, -5, 0, 0, 0, 3, 8, 10, 3, -5, -7, -6, -4, 0, -2, -2, + 3, 7, 7, 2, -5, -6, -3, 2, 2, 0, 0, 2, 2, -4, -9, -9, + -7, -3, 2, 4, 8, 9, 6, 2, -3, -4, -3, -2, -2, -2, 0, 1, + -3, -8, -11, -8, -6, -4, 2, 6, 9, 10, 9, 8, 5, -4, -7, -3, + 1, 1, -6, -7, -6, -6, -11, -14, -10, -5, 3, 9, 12, 14, 13, 10, + 9, 1, -6, -5, -4, -3, -4, -6, -8, -12, -12, -13, -13, -11, -3, 9, + 16, 18, 15, 13, 14, 11, -2, -6, -4, -3, -5, -11, -13, -12, -14, -15, + -14, -10, -4, 6, 15, 22, 21, 16, 13, 12, 3, -7, -8, -7, -7, -10, + -14, -17, -16, -13, -12, -10, -7, 3, 15, 24, 26, 19, 16, 18, 12, -3, + -9, -10, -9, -11, -18, -22, -21, -17, -14, -14, -10, 0, 14, 26, 32, 28, + 23, 22, 21, 5, -9, -12, -16, -18, -22, -27, -27, -23, -17, -13, -8, 2, + 12, 25, 35, 36, 29, 21, 20, 11, -6, -14, -17, -19, -22, -27, -28, -24, + -20, -15, -11, -4, 7, 19, 32, 39, 35, 28, 25, 19, 4, -10, -17, -24, + -28, -31, -33, -30, -26, -19, -11, -3, 8, 19, 31, 42, 42, 34, 27, 21, + 9, -9, -19, -26, -31, -35, -34, -30, -26, -23, -13, -4, 4, 14, 25, 42, + 49, 41, 31, 27, 20, 3, -15, -28, -37, -38, -39, -38, -35, -29, -16, 0, + 9, 17, 26, 41, 52, 48, 36, 26, 19, 6, -16, -30, -39, -43, -41, -39, + -33, -29, -22, -5, 7, 13, 21, 36, 55, 56, 46, 34, 24, 15, -8, -29, + -44, -54, -50, -44, -39, -35, -27, -7, 11, 20, 25, 34, 54, 63, 53, 38, + 22, 14, 0, -27, -45, -56, -56, -46, -39, -36, -31, -14, 8, 19, 23, 29, + 46, 63, 61, 47, 30, 20, 8, -15, -39, -56, -62, -54, -44, -41, -38, -23, + -2, 16, 23, 28, 42, 63, 69, 58, 41, 25, 13, -7, -34, -56, -68, -64, + -50, -45, -43, -29, -7, 15, 26, 29, 40, 58, 72, 67, 48, 30, 16, 0, + -26, -53, -68, -69, -57, -47, -46, -36, -16, 9, 25, 30, 38, 53, 71, 74, + 58, 37, 17, 2, -21, -49, -70, -76, -64, -49, -43, -38, -21, 3, 25, 33, + 37, 49, 65, 74, 65, 45, 24, 8, -11, -40, -68, -79, -72, -57, -48, -42, + -29, -6, 20, 34, 39, 48, 63, 77, 74, 56, 31, 11, -8, -33, -61, -79, + -80, -68, -53, -45, -34, -16, 11, 31, 41, 51, 61, 75, 78, 64, 42, 19, + -3, -27, -55, -78, -84, -73, -59, -48, -37, -20, 5, 27, 40, 49, 58, 71, + 80, 71, 49, 23, 2, -20, -47, -72, -86, -82, -66, -52, -39, -26, -5, 20, + 39, 51, 59, 69, 79, 77, 61, 34, 7, -16, -42, -68, -88, -90, -75, -58, + -41, -26, -8, 17, 39, 52, 59, 65, 74, 77, 65, 41, 12, -12, -35, -60, + -81, -89, -79, -60, -45, -33, -17, 6, 31, 49, 59, 64, 73, 80, 74, 51, + 22, -5, -29, -54, -78, -92, -90, -70, -49, -35, -18, 3, 26, 48, 60, 64, + 68, 75, 75, 58, 31, 1, -25, -48, -73, -88, -90, -77, -56, -41, -23, -3, + 21, 43, 58, 64, 70, 75, 77, 64, 40, 12, -18, -44, -70, -87, -94, -87, + -64, -42, -22, -4, 16, 39, 58, 65, 66, 67, 74, 68, 46, 18, -12, -38, + -62, -82, -92, -89, -67, -45, -28, -9, 13, 31, 52, 64, 67, 66, 72, 71, + 53, 29, -3, -34, -59, -79, -94, -96, -77, -50, -29, -8, 12, 30, 49, 63, + 68, 67, 68, 70, 56, 34, 6, -29, -57, -77, -92, -99, -84, -56, -32, -10, + 11, 29, 45, 61, 69, 69, 68, 70, 60, 37, 12, -20, -50, -73, -90, -100, + -91, -64, -37, -14, 7, 25, 42, 57, 66, 67, 65, 67, 64, 45, 21, -9, + -41, -66, -84, -98, -95, -74, -47, -21, 3, 23, 39, 54, 64, 69, 69, 67, + 63, 50, 27, 0, -33, -63, -83, -94, -95, -79, -54, -26, -2, 18, 35, 49, + 61, 67, 67, 65, 64, 55, 33, 6, -25, -55, -82, -95, -98, -84, -60, -32, + -6, 17, 36, 48, 56, 64, 66, 65, 62, 55, 39, 14, -16, -46, -76, -92, + -96, -88, -69, -41, -9, 15, 33, 46, 54, 62, 68, 66, 59, 54, 44, 20, + -12, -41, -72, -92, -97, -90, -71, -46, -14, 15, 34, 48, 55, 59, 62, 63, + 60, 51, 42, 24, -6, -34, -63, -87, -95, -89, -75, -52, -23, 10, 31, 45, + 54, 58, 62, 66, 63, 51, 42, 30, 1, -32, -59, -84, -96, -93, -80, -58, + -28, 7, 32, 45, 53, 60, 64, 67, 62, 52, 41, 31, 9, -25, -55, -78, + -92, -91, -82, -65, -39, -2, 30, 43, 49, 56, 61, 65, 63, 54, 44, 33, + 16, -15, -47, -72, -88, -91, -84, -70, -45, -12, 22, 42, 48, 54, 58, 61, + 63, 56, 43, 32, 20, -4, -36, -65, -82, -87, -82, -72, -53, -23, 15, 40, + 46, 48, 55, 61, 62, 55, 43, 32, 21, 4, -26, -57, -75, -82, -80, -73, + -58, -30, 5, 35, 46, 47, 51, 57, 61, 57, 46, 34, 22, 9, -15, -47, + -71, -81, -80, -75, -62, -36, -4, 28, 46, 47, 49, 56, 60, 57, 48, 35, + 23, 12, -9, -39, -67, -78, -76, -71, -65, -45, -13, 21, 45, 50, 46, 50, + 58, 59, 49, 35, 23, 12, -4, -31, -62, -78, -74, -70, -65, -49, -18, 18, + 43, 51, 45, 48, 56, 56, 45, 30, 20, 12, 0, -24, -53, -71, -69, -63, + -60, -51, -25, 9, 36, 50, 47, 44, 50, 52, 45, 32, 21, 12, 1, -18, + -44, -66, -70, -64, -59, -51, -31, 2, 32, 50, 51, 46, 47, 52, 47, 32, + 17, 9, 0, -14, -34, -57, -67, -62, -56, -50, -33, -6, 24, 44, 51, 48, + 47, 48, 46, 34, 21, 12, 2, -13, -32, -51, -62, -62, -56, -51, -38, -13, + 18, 40, 51, 50, 45, 47, 46, 36, 20, 9, -2, -14, -28, -45, -59, -61, + -54, -48, -37, -15, 14, 36, 49, 52, 48, 44, 42, 33, 19, 10, 0, -13, + -26, -39, -52, -58, -54, -47, -37, -19, 9, 30, 44, 52, 48, 40, 38, 31, + 19, 7, -3, -12, -22, -31, -42, -51, -49, -43, -36, -22, 1, 22, 35, 45, + 47, 41, 37, 31, 23, 13, 3, -11, -22, -28, -36, -48, -53, -46, -35, -23, + -4, 17, 31, 45, 49, 41, 33, 29, 23, 13, 2, -11, -22, -26, -29, -38, + -46, -45, -34, -21, -6, 14, 25, 38, 46, 43, 35, 27, 19, 10, 3, -7, + -20, -28, -28, -32, -38, -41, -35, -23, -8, 10, 23, 33, 44, 44, 36, 27, + 18, 10, 0, -9, -22, -28, -28, -28, -33, -37, -32, -21, -7, 8, 20, 28, + 38, 41, 36, 27, 17, 8, -2, -6, -17, -28, -31, -28, -27, -30, -30, -22, + -7, 9, 19, 26, 35, 41, 37, 26, 16, 6, -5, -11, -18, -28, -31, -28, + -22, -23, -23, -18, -4, 11, 19, 24, 27, 33, 33, 24, 14, 3, -8, -11, + -15, -23, -29, -29, -21, -18, -19, -15, -5, 9, 16, 21, 26, 30, 32, 25, + 13, 2, -9, -13, -16, -21, -27, -27, -20, -12, -13, -14, -7, 9, 17, 20, + 24, 25, 26, 27, 15, 2, -9, -17, -17, -20, -25, -28, -23, -11, -6, -8, + -5, 7, 19, 23, 24, 24, 24, 25, 16, 0, -13, -22, -22, -22, -26, -28, + -22, -8, 2, 1, 0, 8, 18, 24, 24, 20, 18, 20, 15, 1, -12, -22, + -24, -22, -23, -25, -22, -13, 2, 7, 3, 8, 16, 25, 28, 21, 15, 15, + 15, 4, -13, -25, -29, -24, -20, -24, -21, -12, 1, 12, 10, 9, 16, 23, + 27, 21, 14, 12, 10, 3, -10, -21, -28, -27, -22, -22, -20, -14, -4, 10, + 14, 11, 17, 23, 29, 26, 15, 11, 10, 4, -12, -25, -33, -33, -26, -23, + -22, -12, 0, 13, 22, 19, 20, 25, 29, 25, 12, 5, 3, 0, -12, -25, + -32, -34, -27, -21, -20, -11, -2, 7, 18, 21, 22, 26, 30, 29, 21, 11, + 4, -5, -14, -29, -38, -38, -33, -27, -23, -10, 4, 12, 22, 29, 30, 30, + 31, 30, 21, 10, 0, -11, -19, -30, -39, -40, -36, -28, -20, -9, 4, 12, + 20, 29, 32, 30, 32, 32, 23, 12, 3, -8, -18, -27, -39, -44, -40, -32, + -25, -15, 1, 13, 22, 30, 37, 38, 36, 34, 26, 14, 2, -11, -22, -31, + -40, -45, -42, -35, -26, -14, 0, 12, 19, 26, 35, 39, 36, 33, 28, 18, + 6, -7, -18, -28, -37, -43, -43, -37, -30, -19, -6, 8, 20, 25, 34, 42, + 41, 37, 32, 22, 8, -7, -19, -32, -40, -44, -44, -38, -30, -20, -6, 8, + 19, 24, 30, 40, 41, 36, 29, 23, 13, -3, -16, -28, -39, -43, -44, -41, + -34, -23, -11, 2, 16, 25, 32, 41, 46, 42, 34, 26, 15, 0, -16, -29, + -40, -45, -45, -40, -32, -24, -12, -2, 12, 22, 26, 37, 45, 44, 34, 24, + 18, 6, -12, -24, -37, -41, -40, -40, -36, -30, -17, -4, 9, 18, 25, 37, + 45, 45, 40, 29, 19, 8, -8, -22, -38, -43, -42, -42, -35, -28, -17, -4, + 7, 17, 23, 33, 43, 43, 38, 28, 19, 12, -3, -19, -34, -40, -38, -40, + -38, -31, -22, -8, 5, 14, 21, 31, 44, 47, 41, 31, 20, 13, 3, -15, + -33, -45, -45, -41, -38, -31, -24, -10, 4, 15, 21, 29, 42, 47, 41, 33, + 22, 13, 4, -13, -29, -40, -41, -41, -41, -36, -26, -14, -2, 8, 17, 29, + 42, 50, 46, 37, 27, 17, 7, -9, -27, -41, -48, -45, -42, -38, -29, -15, + -2, 10, 18, 26, 38, 50, 51, 40, 28, 17, 6, -7, -24, -36, -43, -45, + -41, -38, -31, -18, -8, 2, 13, 26, 38, 44, 49, 42, 33, 22, 8, -4, + -20, -32, -41, -46, -44, -37, -32, -21, -8, 2, 14, 25, 35, 42, 47, 44, + 31, 19, 7, -4, -15, -28, -36, -42, -40, -34, -31, -24, -9, 0, 7, 18, + 30, 40, 44, 42, 32, 22, 12, 2, -10, -23, -31, -38, -42, -38, -31, -26, + -13, -3, 2, 14, 29, 40, 41, 40, 36, 26, 13, 1, -10, -19, -26, -35, + -43, -41, -33, -27, -17, -6, 1, 12, 27, 43, 47, 42, 37, 29, 14, 0, + -10, -21, -29, -34, -40, -42, -33, -26, -18, -5, 3, 10, 23, 39, 45, 39, + 33, 30, 18, 3, -8, -15, -22, -29, -37, -43, -36, -27, -22, -13, -4, 6, + 19, 36, 47, 47, 37, 33, 25, 6, -8, -15, -25, -31, -36, -43, -42, -32, + -21, -11, 0, 5, 15, 32, 46, 45, 35, 31, 28, 12, -6, -13, -20, -24, + -31, -41, -46, -38, -26, -18, -9, 1, 14, 31, 43, 48, 42, 33, 28, 15, + -5, -15, -18, -24, -31, -38, -41, -34, -26, -19, -8, 1, 10, 23, 37, 43, + 41, 32, 26, 19, 3, -12, -15, -18, -24, -34, -42, -38, -28, -20, -13, -4, + 6, 21, 37, 44, 43, 36, 28, 21, 8, -9, -16, -19, -25, -34, -42, -39, + -29, -21, -13, -3, 8, 19, 34, 42, 41, 36, 28, 20, 8, -7, -15, -16, + -19, -30, -41, -42, -31, -23, -15, -8, 3, 19, 36, 43, 39, 36, 30, 23, + 13, -6, -19, -21, -20, -26, -38, -43, -35, -25, -15, -7, 3, 14, 30, 42, + 40, 35, 28, 23, 16, 0, -14, -20, -19, -22, -34, -42, -37, -26, -15, -8, + 0, 12, 27, 40, 41, 35, 29, 22, 16, 4, -9, -19, -20, -20, -29, -39, + -39, -30, -19, -10, -3, 10, 24, 37, 42, 37, 31, 25, 18, 7, -7, -17, + -21, -20, -28, -38, -40, -33, -22, -11, -5, 9, 25, 37, 44, 40, 32, 24, + 17, 10, -5, -18, -24, -23, -28, -35, -38, -35, -26, -14, -5, 5, 19, 34, + 44, 42, 33, 23, 18, 13, 0, -15, -20, -22, -26, -33, -39, -35, -28, -18, + -10, 1, 18, 33, 43, 45, 38, 28, 20, 11, 2, -12, -22, -24, -28, -31, + -36, -35, -29, -21, -11, 0, 15, 30, 40, 44, 39, 31, 21, 13, 8, -5, + -17, -20, -25, -28, -32, -36, -34, -27, -18, -7, 9, 26, 39, 46, 45, 36, + 25, 14, 10, -2, -16, -24, -29, -31, -31, -36, -36, -27, -16, -7, 6, 23, + 37, 45, 44, 36, 26, 14, 8, 1, -14, -22, -23, -29, -32, -35, -36, -29, + -21, -14, 0, 16, 35, 46, 45, 39, 33, 20, 8, 3, -9, -21, -28, -32, + -34, -35, -36, -32, -25, -15, 1, 17, 32, 45, 49, 44, 35, 23, 7, 0, + -7, -17, -25, -30, -31, -32, -34, -31, -25, -18, -7, 10, 27, 43, 50, 45, + 35, 24, 13, 3, -7, -17, -24, -28, -30, -30, -33, -34, -26, -19, -11, 5, + 22, 39, 50, 48, 37, 26, 16, 5, -7, -18, -23, -27, -28, -28, -33, -34, + -24, -16, -11, 2, 17, 33, 48, 48, 37, 27, 18, 7, -5, -14, -20, -25, + -30, -31, -32, -37, -31, -20, -15, -3, 15, 30, 46, 53, 43, 31, 20, 11, + 0, -12, -21, -27, -31, -30, -30, -36, -33, -20, -10, -5, 9, 25, 41, 52, + 46, 34, 23, 15, 6, -9, -21, -27, -30, -31, -31, -37, -39, -25, -12, -7, + 1, 18, 36, 52, 53, 40, 28, 22, 13, -2, -18, -29, -32, -35, -34, -39, + -40, -28, -13, -7, -2, 12, 33, 50, 56, 44, 30, 24, 18, 4, -15, -29, + -32, -33, -33, -35, -40, -35, -20, -7, -2, 8, 25, 43, 54, 49, 35, 25, + 18, 8, -7, -23, -32, -32, -34, -34, -37, -36, -24, -11, -5, 2, 18, 36, + 51, 51, 39, 30, 24, 14, 0, -19, -32, -35, -35, -37, -38, -39, -29, -12, + -2, 3, 14, 29, 47, 54, 45, 33, 26, 17, 5, -12, -31, -37, -36, -38, + -38, -38, -32, -17, -3, 3, 9, 25, 42, 53, 49, 39, 31, 23, 10, -9, + -27, -38, -40, -41, -41, -41, -36, -23, -5, 5, 8, 18, 36, 51, 51, 43, + 34, 26, 16, 1, -20, -36, -40, -41, -42, -40, -38, -28, -10, 4, 7, 14, + 30, 48, 51, 45, 39, 31, 21, 4, -16, -33, -41, -43, -43, -39, -38, -32, + -15, 1, 7, 13, 25, 42, 52, 48, 39, 31, 22, 9, -10, -29, -40, -40, + -40, -38, -35, -34, -20, -2, 5, 9, 17, 33, 49, 50, 43, 34, 25, 13, + -4, -21, -36, -44, -44, -40, -35, -34, -26, -8, 5, 11, 17, 26, 43, 51, + 46, 36, 27, 16, 1, -16, -31, -42, -46, -43, -37, -35, -29, -12, 3, 11, + 17, 23, 37, 50, 52, 41, 29, 20, 4, -15, -30, -43, -49, -46, -39, -37, + -33, -15, 3, 13, 19, 23, 35, 52, 55, 44, 29, 20, 8, -12, -28, -40, + -48, -45, -39, -35, -32, -20, -2, 12, 16, 19, 28, 45, 55, 49, 35, 24, + 14, -3, -20, -36, -49, -53, -45, -38, -35, -27, -9, 8, 19, 23, 26, 40, + 55, 55, 41, 25, 15, -2, -19, -33, -46, -53, -47, -39, -35, -29, -14, 6, + 19, 24, 25, 35, 53, 59, 47, 29, 17, 7, -12, -30, -47, -58, -56, -47, + -39, -35, -22, -2, 17, 28, 30, 34, 50, 63, 56, 35, 19, 8, -9, -26, + -43, -56, -58, -49, -42, -38, -27, -9, 12, 26, 33, 34, 44, 60, 62, 44, + 23, 9, -4, -20, -40, -56, -63, -56, -44, -39, -30, -14, 8, 26, 35, 35, + 43, 60, 64, 50, 28, 13, 2, -16, -37, -53, -62, -61, -50, -42, -32, -17, + 2, 18, 32, 40, 44, 54, 63, 55, 37, 17, 4, -10, -31, -48, -61, -67, + -59, -45, -36, -24, -5, 17, 33, 43, 47, 54, 64, 59, 42, 20, 3, -10, + -28, -49, -63, -68, -63, -50, -37, -25, -7, 13, 31, 44, 48, 54, 61, 59, + 48, 27, 6, -10, -24, -43, -59, -67, -67, -56, -39, -28, -13, 8, 24, 42, + 51, 54, 58, 58, 52, 37, 14, -6, -20, -38, -54, -65, -70, -63, -45, -29, + -17, 2, 18, 37, 52, 56, 58, 56, 51, 42, 23, -2, -19, -34, -50, -62, + -70, -69, -52, -30, -17, -3, 15, 33, 50, 58, 58, 56, 52, 46, 29, 3, + -15, -31, -45, -58, -68, -71, -60, -38, -20, -5, 11, 25, 42, 58, 62, 58, + 51, 44, 36, 15, -10, -29, -43, -53, -64, -72, -67, -45, -21, -8, 4, 20, + 40, 60, 65, 57, 53, 48, 42, 21, -8, -27, -40, -50, -62, -71, -71, -54, + -29, -9, 3, 18, 34, 54, 68, 65, 57, 48, 40, 28, 2, -23, -41, -52, + -60, -71, -75, -60, -34, -12, 0, 13, 31, 52, 69, 66, 56, 50, 44, 33, + 7, -21, -38, -47, -55, -65, -75, -67, -41, -15, 2, 11, 23, 41, 61, 68, + 59, 49, 40, 34, 17, -11, -35, -47, -48, -55, -69, -72, -50, -21, 0, 8, + 15, 33, 56, 69, 62, 52, 44, 40, 26, -4, -30, -44, -48, -56, -69, -77, + -59, -28, -7, 7, 15, 30, 52, 68, 66, 55, 45, 38, 30, 6, -24, -43, + -49, -52, -64, -75, -65, -35, -10, 4, 11, 25, 45, 65, 67, 55, 48, 43, + 34, 13, -18, -39, -45, -49, -61, -75, -72, -45, -17, -2, 9, 20, 39, 61, + 70, 62, 52, 45, 36, 18, -9, -34, -47, -52, -58, -69, -72, -52, -23, -5, + 7, 17, 35, 54, 65, 63, 55, 45, 37, 23, 0, -27, -45, -49, -53, -63, + -71, -59, -31, -8, 7, 15, 28, 47, 61, 65, 58, 47, 38, 27, 6, -21, + -41, -49, -53, -62, -69, -62, -39, -14, 3, 14, 28, 46, 59, 64, 62, 51, + 39, 29, 11, -16, -40, -52, -55, -58, -65, -65, -47, -20, 1, 14, 24, 39, + 52, 59, 64, 56, 43, 33, 16, -8, -32, -49, -55, -58, -63, -65, -54, -29, + -3, 12, 21, 36, 51, 60, 65, 59, 46, 35, 21, -4, -28, -48, -56, -57, + -59, -60, -55, -37, -12, 9, 19, 32, 46, 54, 58, 58, 48, 36, 26, 7, + -18, -41, -53, -53, -52, -57, -58, -45, -19, 6, 15, 26, 42, 54, 59, 59, + 52, 39, 28, 10, -16, -40, -56, -56, -52, -51, -53, -45, -22, 4, 17, 24, + 35, 46, 56, 57, 52, 40, 30, 18, -7, -33, -54, -58, -52, -49, -53, -51, + -33, -5, 17, 26, 34, 43, 54, 58, 53, 42, 31, 19, 0, -24, -47, -60, + -55, -46, -46, -50, -39, -13, 13, 25, 32, 38, 48, 56, 52, 41, 30, 20, + 7, -15, -41, -58, -55, -44, -41, -44, -40, -19, 10, 25, 28, 32, 41, 53, + 52, 42, 31, 21, 13, -5, -32, -55, -60, -47, -36, -38, -40, -26, 2, 24, + 29, 28, 32, 46, 48, 40, 29, 21, 14, 1, -23, -48, -56, -46, -34, -33, + -36, -29, -7, 20, 28, 25, 26, 37, 46, 42, 30, 19, 15, 7, -13, -39, + -58, -54, -37, -27, -27, -29, -17, 13, 29, 28, 24, 31, 42, 42, 34, 21, + 11, 5, -10, -32, -51, -52, -40, -28, -24, -24, -18, 6, 27, 30, 26, 28, + 36, 38, 33, 22, 11, 6, -7, -26, -44, -49, -42, -30, -21, -17, -16, -5, + 18, 29, 26, 25, 29, 33, 33, 25, 13, 7, 0, -18, -36, -46, -45, -31, + -20, -16, -16, -9, 12, 28, 29, 24, 25, 29, 31, 26, 13, 2, -5, -15, + -26, -39, -46, -37, -19, -9, -9, -11, 1, 21, 31, 26, 21, 23, 26, 25, + 15, 4, -4, -10, -20, -32, -41, -38, -22, -10, -7, -9, -6, 11, 26, 29, + 22, 20, 21, 24, 19, 7, -6, -12, -17, -23, -30, -36, -27, -12, -3, 0, + -5, 3, 18, 28, 25, 18, 15, 16, 15, 7, -4, -10, -14, -19, -24, -30, + -26, -13, -3, 2, -3, -2, 12, 23, 26, 18, 13, 13, 14, 9, 0, -11, + -14, -15, -18, -24, -26, -16, -4, 4, 0, -5, 6, 17, 25, 21, 11, 7, + 8, 8, 1, -11, -14, -11, -10, -13, -20, -18, -7, 5, 7, -3, -2, 8, + 21, 23, 12, 4, 4, 8, 7, -5, -15, -14, -11, -9, -15, -20, -13, 1, + 8, 3, 0, 6, 17, 24, 16, 3, -2, 1, 0, -10, -17, -14, -8, -4, + -5, -11, -12, 0, 9, 6, -3, 1, 10, 18, 16, 5, -3, 0, 3, -4, + -13, -15, -10, -6, -4, -8, -13, -8, 5, 8, 5, 3, 9, 17, 18, 13, + 0, -7, -5, -5, -11, -14, -11, -6, 2, 2, -6, -9, 1, 8, 5, -2, + 1, 8, 14, 12, 2, -6, -5, -2, -6, -12, -10, -2, 3, 4, -5, -11, + -6, 5, 6, 0, 0, 7, 12, 14, 6, -7, -8, -6, -6, -9, -10, -5, + 4, 8, 4, -7, -11, -2, 6, 3, -2, 2, 9, 15, 12, -2, -8, -6, + -3, -5, -11, -9, 2, 10, 7, -5, -15, -10, 4, 6, -2, -2, 8, 14, + 14, 3, -9, -8, -5, -4, -8, -10, 0, 8, 9, 3, -9, -12, -3, 6, + 3, -3, 1, 8, 13, 5, -9, -13, -7, -2, -2, -6, -2, 9, 13, 6, + -6, -13, -10, 2, 4, -3, -2, 7, 13, 9, -6, -12, -11, -6, 0, -5, + -5, 7, 15, 13, 1, -10, -13, -4, 5, -2, -7, -2, 9, 9, -3, -11, + -11, -8, 2, 1, -3, 7, 15, 12, 4, -7, -13, -11, -2, 1, -4, -3, + 7, 11, 3, -8, -11, -10, 0, 1, -5, 2, 12, 17, 11, -2, -11, -11, + -3, 4, -4, -9, 1, 10, 3, -9, -11, -8, 0, 5, 1, 2, 11, 14, + 9, 1, -11, -15, -11, -3, 1, -3, 3, 12, 11, 1, -7, -9, -6, -3, + -5, -5, 5, 12, 9, 4, -3, -8, -8, -5, 0, -4, -3, 5, 6, -3, + -10, -7, -3, 0, 2, 3, 10, 14, 11, 4, -3, -11, -15, -15, -9, -5, + -5, 5, 13, 5, -2, 0, 2, 4, 1, -3, 4, 12, 11, 2, -5, -10, + -13, -13, -11, -6, -4, 3, 13, 9, 1, -2, 4, 5, 1, -5, 3, 12, + 13, 4, -9, -12, -14, -16, -17, -12, -5, 5, 16, 17, 6, 3, 9, 9, + 2, -8, -7, 2, 7, 4, -8, -12, -10, -13, -14, -13, -6, 4, 13, 19, + 10, 0, 6, 14, 8, -6, -9, 0, 7, 5, -8, -17, -13, -9, -14, -18, + -13, 2, 15, 23, 16, 4, 5, 16, 15, 0, -10, -6, 3, 6, -4, -15, + -15, -10, -11, -16, -16, -5, 10, 21, 18, 7, 2, 12, 18, 6, -7, -9, + 1, 7, 1, -14, -19, -15, -13, -16, -18, -8, 7, 19, 24, 16, 5, 8, + 16, 9, -4, -9, -5, 3, 4, -9, -19, -18, -13, -12, -17, -12, 2, 16, + 22, 17, 6, 4, 14, 13, 1, -8, -6, 2, 6, -5, -18, -20, -16, -14, + -18, -17, -5, 12, 23, 24, 14, 9, 15, 19, 9, -5, -8, -3, 2, -6, + -17, -23, -19, -14, -16, -17, -8, 7, 19, 24, 19, 10, 11, 17, 13, 3, + -5, -3, -2, -4, -14, -24, -25, -20, -18, -16, -10, 3, 16, 26, 28, 18, + 11, 15, 17, 9, -4, -7, -6, -6, -12, -24, -29, -22, -16, -15, -10, 0, + 13, 24, 27, 22, 14, 13, 16, 13, 2, -6, -7, -9, -12, -21, -29, -27, + -21, -15, -10, -3, 8, 21, 29, 26, 17, 13, 17, 19, 9, -5, -10, -9, + -12, -21, -30, -29, -22, -14, -10, -4, 7, 17, 26, 23, 17, 13, 12, 18, + 16, 5, -6, -10, -11, -19, -29, -32, -27, -18, -10, -4, 4, 13, 25, 26, + 21, 16, 11, 16, 17, 8, -5, -12, -12, -16, -25, -30, -27, -19, -10, -6, + 0, 10, 21, 24, 18, 15, 13, 16, 20, 14, 1, -10, -12, -15, -26, -31, + -29, -22, -12, -5, 0, 8, 19, 25, 22, 17, 14, 14, 19, 17, 4, -10, + -15, -15, -22, -30, -30, -26, -16, -6, 1, 7, 15, 23, 23, 18, 17, 17, + 17, 17, 8, -6, -15, -18, -24, -31, -29, -26, -19, -8, 2, 7, 15, 23, + 24, 21, 17, 15, 15, 17, 13, -4, -16, -20, -23, -30, -32, -27, -19, -8, + 3, 7, 14, 23, 24, 20, 16, 16, 15, 14, 10, 0, -12, -20, -24, -31, + -32, -25, -19, -10, 0, 9, 14, 22, 27, 23, 17, 17, 18, 12, 8, 1, + -12, -18, -23, -31, -34, -26, -17, -9, -2, 6, 14, 22, 27, 22, 16, 15, + 18, 17, 10, 3, -9, -17, -21, -31, -38, -32, -23, -13, -5, 4, 14, 21, + 30, 30, 21, 17, 18, 17, 10, 3, -8, -20, -23, -29, -38, -34, -25, -12, + 0, 3, 11, 17, 26, 31, 23, 15, 13, 16, 14, 5, -4, -15, -19, -23, + -35, -38, -32, -19, -7, -5, 6, 16, 25, 36, 32, 22, 19, 19, 15, 3, + -7, -16, -23, -26, -35, -42, -34, -19, -3, 1, 6, 18, 26, 37, 34, 20, + 15, 14, 14, 5, -7, -15, -21, -23, -28, -39, -37, -22, -5, 1, 3, 15, + 25, 35, 40, 27, 14, 14, 14, 6, -7, -14, -20, -25, -27, -36, -41, -28, + -8, 2, 4, 14, 24, 33, 40, 32, 17, 13, 12, 5, -7, -14, -17, -24, + -28, -34, -40, -32, -14, 1, 4, 13, 26, 33, 41, 40, 26, 15, 12, 4, + -9, -17, -20, -25, -31, -34, -41, -38, -20, 0, 7, 12, 24, 32, 40, 41, + 30, 17, 11, 4, -10, -18, -19, -21, -27, -31, -35, -36, -24, -5, 5, 9, + 21, 31, 37, 41, 36, 21, 11, 4, -8, -15, -18, -21, -26, -31, -34, -37, + -30, -12, 3, 9, 18, 30, 38, 44, 42, 29, 15, 7, -6, -18, -23, -24, + -25, -31, -34, -36, -33, -15, 3, 9, 17, 28, 38, 44, 42, 34, 20, 8, + -5, -18, -23, -22, -24, -30, -35, -35, -35, -24, -6, 6, 14, 25, 36, 42, + 45, 42, 28, 13, 1, -15, -26, -27, -26, -29, -35, -39, -38, -28, -10, 5, + 13, 21, 36, 47, 48, 45, 36, 21, 6, -11, -25, -31, -30, -29, -35, -41, + -41, -34, -18, 1, 15, 24, 35, 47, 52, 51, 42, 26, 8, -9, -25, -32, + -34, -32, -34, -40, -41, -35, -22, -5, 11, 21, 30, 44, 52, 51, 45, 32, + 15, -3, -19, -28, -33, -34, -36, -42, -44, -41, -30, -13, 6, 20, 29, 43, + 54, 56, 50, 37, 22, 4, -17, -31, -39, -39, -38, -40, -44, -41, -31, -14, + 4, 18, 26, 37, 52, 57, 54, 44, 29, 11, -9, -26, -38, -42, -40, -41, + -45, -46, -39, -24, -2, 17, 25, 35, 49, 59, 59, 52, 36, 19, -2, -22, + -38, -46, -45, -43, -44, -47, -41, -28, -7, 12, 22, 32, 45, 58, 60, 52, + 40, 26, 9, -14, -36, -46, -47, -44, -44, -50, -47, -34, -14, 8, 21, 30, + 42, 58, 65, 58, 46, 32, 14, -7, -30, -47, -51, -50, -45, -50, -51, -38, + -20, 4, 19, 28, 38, 53, 67, 63, 50, 40, 23, 2, -22, -43, -54, -55, + -50, -53, -57, -48, -31, -6, 17, 28, 39, 53, 69, 72, 60, 47, 29, 7, + -18, -39, -54, -59, -56, -53, -55, -52, -37, -16, 10, 25, 36, 48, 65, 75, + 68, 54, 40, 20, -6, -31, -52, -61, -61, -59, -63, -62, -46, -24, 2, 20, + 33, 50, 67, 79, 75, 62, 49, 30, 2, -29, -50, -63, -66, -65, -64, -64, + -50, -28, -6, 18, 34, 48, 62, 74, 79, 70, 54, 38, 14, -19, -45, -62, + -70, -71, -67, -68, -61, -39, -15, 10, 28, 45, 63, 77, 82, 77, 62, 47, + 25, -9, -40, -61, -70, -73, -69, -70, -66, -47, -23, 2, 23, 41, 57, 71, + 79, 83, 72, 55, 37, 6, -27, -51, -67, -76, -78, -77, -75, -60, -35, -12, + 13, 37, 59, 75, 82, 86, 81, 66, 48, 17, -23, -50, -66, -77, -83, -83, + -78, -66, -43, -18, 7, 31, 54, 73, 83, 87, 87, 74, 55, 29, -10, -41, + -61, -76, -85, -88, -84, -72, -53, -28, -3, 22, 51, 75, 84, 88, 92, 87, + 67, 40, 0, -38, -60, -77, -89, -94, -89, -77, -59, -34, -7, 17, 44, 73, + 88, 90, 91, 88, 74, 49, 12, -29, -57, -73, -84, -93, -94, -84, -68, -44, + -17, 8, 33, 64, 85, 90, 92, 91, 83, 63, 30, -15, -50, -71, -82, -92, + -96, -90, -74, -52, -26, 0, 24, 56, 82, 92, 93, 92, 89, 74, 42, 0, + -41, -67, -80, -93, -100, -97, -83, -62, -35, -8, 16, 43, 74, 91, 96, 96, + 93, 83, 56, 16, -28, -61, -79, -92, -99, -99, -90, -71, -45, -16, 9, 36, + 66, 88, 98, 97, 93, 87, 68, 31, -16, -52, -75, -89, -98, -103, -98, -81, + -54, -23, 1, 25, 56, 83, 97, 98, 92, 88, 76, 46, 1, -42, -68, -81, + -91, -99, -97, -82, -58, -30, -6, 15, 44, 73, 91, 94, 89, 85, 78, 55, + 16, -28, -59, -77, -87, -93, -95, -85, -65, -40, -16, 6, 33, 62, 85, 94, + 90, 86, 81, 66, 32, -15, -52, -73, -84, -90, -93, -87, -69, -45, -22, 0, + 22, 48, 75, 88, 88, 85, 80, 67, 42, 4, -36, -62, -77, -87, -90, -85, + -72, -52, -30, -11, 11, 36, 63, 83, 86, 86, 82, 74, 54, 17, -25, -55, + -72, -81, -88, -87, -77, -57, -34, -16, 4, 26, 54, 77, 84, 84, 82, 75, + 58, 27, -12, -45, -65, -76, -84, -84, -76, -61, -41, -24, -7, 15, 41, 67, + 78, 81, 80, 76, 67, 42, 5, -30, -54, -67, -79, -85, -79, -67, -50, -32, + -16, 6, 32, 58, 73, 77, 81, 78, 68, 49, 16, -19, -45, -63, -74, -80, + -77, -67, -53, -35, -20, -3, 20, 45, 65, 72, 76, 75, 68, 56, 29, -6, + -33, -52, -65, -75, -77, -70, -57, -42, -28, -13, 9, 34, 57, 70, 73, 75, + 72, 63, 41, 7, -24, -46, -60, -70, -75, -72, -59, -45, -31, -18, 0, 25, + 48, 63, 68, 70, 71, 65, 47, 17, -13, -33, -49, -62, -73, -73, -61, -48, + -37, -25, -10, 14, 39, 57, 64, 67, 70, 69, 54, 28, -3, -27, -44, -57, + -68, -74, -66, -50, -39, -26, -13, 5, 30, 50, 60, 62, 64, 65, 58, 38, + 9, -17, -35, -46, -59, -69, -67, -52, -40, -31, -20, -6, 18, 42, 55, 58, + 60, 65, 62, 47, 20, -10, -28, -39, -51, -66, -70, -58, -44, -34, -23, -10, + 11, 34, 51, 57, 58, 62, 63, 51, 29, 2, -21, -34, -46, -60, -69, -63, + -49, -37, -27, -15, 3, 26, 45, 55, 56, 58, 62, 55, 37, 11, -14, -29, + -39, -52, -65, -66, -52, -40, -30, -18, -5, 17, 39, 52, 54, 55, 58, 57, + 44, 21, -8, -24, -33, -45, -59, -66, -57, -43, -31, -20, -11, 7, 30, 47, + 53, 51, 52, 55, 51, 33, 4, -20, -29, -36, -49, -64, -63, -50, -36, -24, + -14, 0, 22, 43, 55, 53, 49, 52, 51, 39, 12, -16, -27, -33, -45, -60, + -66, -53, -37, -25, -16, -6, 16, 40, 53, 53, 47, 49, 51, 43, 22, 0, + 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, -2, -2, -2, -2, 0, -2, + 0, 0, 1, 2, 3, 4, 4, 4, 5, 6, 7, 6, 3, 1, 0, -3, + -5, -11, -17, -20, -20, -18, -16, -17, -17, -14, -10, -9, -13, -18, -19, -15, + -13, -12, -13, -8, 1, 12, 25, 32, 40, 45, 50, 49, 41, 32, 24, 16, + 9, 1, -12, -20, -23, -24, -20, -20, -18, -12, -11, -12, -7, 0, 10, 17, + 23, 25, 24, 21, 22, 23, 21, 10, 1, -5, -8, -11, -19, -29, -33, -32, + -26, -19, -16, -14, -12, -8, -7, -11, -19, -27, -29, -27, -25, -25, -24, -17, + -4, 13, 26, 34, 43, 54, 59, 56, 46, 33, 23, 15, 5, -11, -23, -32, + -35, -32, -30, -27, -23, -16, -11, -5, 3, 11, 23, 31, 36, 33, 28, 27, + 26, 21, 11, 1, -9, -14, -18, -23, -28, -35, -33, -26, -18, -12, -11, -7, + -4, -2, 0, -8, -19, -29, -33, -32, -30, -30, -25, -17, -4, 13, 26, 36, + 47, 55, 59, 53, 43, 32, 23, 12, 0, -14, -23, -30, -35, -35, -35, -33, + -28, -19, -11, -6, 3, 11, 22, 33, 39, 38, 34, 30, 27, 20, 11, 0, + -9, -17, -21, -26, -31, -34, -29, -19, -8, -3, 0, -3, 1, 4, 1, -11, + -25, -35, -37, -39, -35, -32, -27, -17, 0, 15, 29, 42, 55, 63, 62, 55, + 47, 38, 27, 14, -4, -20, -31, -40, -44, -46, -45, -41, -34, -25, -14, -3, + 8, 22, 32, 43, 44, 40, 36, 34, 26, 18, 8, -2, -11, -20, -25, -29, + -33, -31, -21, -10, -2, -2, -2, 4, 6, 9, 0, -14, -28, -35, -39, -38, + -38, -36, -30, -16, 0, 16, 29, 41, 55, 65, 67, 59, 49, 39, 28, 13, + -3, -19, -32, -42, -48, -51, -53, -47, -36, -22, -12, 0, 10, 24, 38, 46, + 48, 43, 39, 32, 26, 17, 6, -7, -16, -21, -26, -31, -34, -28, -16, -2, + 3, 1, 2, 8, 16, 12, 2, -15, -27, -34, -37, -41, -47, -44, -33, -16, + 1, 16, 31, 47, 65, 75, 73, 63, 52, 41, 27, 9, -14, -34, -47, -54, + -55, -58, -57, -50, -35, -17, 0, 8, 20, 34, 47, 54, 49, 42, 36, 29, + 21, 9, -4, -14, -21, -26, -30, -33, -28, -18, -5, 4, 6, 6, 8, 13, + 17, 12, -4, -21, -33, -39, -44, -49, -50, -46, -35, -15, 4, 22, 36, 55, + 72, 81, 78, 69, 54, 42, 27, 6, -19, -38, -52, -57, -62, -65, -64, -52, + -35, -17, -3, 8, 19, 33, 45, 50, 48, 42, 35, 29, 18, 7, -5, -11, + -20, -26, -29, -27, -20, -13, -4, 3, 8, 9, 11, 12, 12, 5, -8, -22, + -33, -42, -50, -53, -51, -42, -27, -11, 9, 27, 45, 62, 75, 78, 73, 60, + 48, 32, 14, -8, -30, -46, -54, -60, -64, -62, -53, -39, -23, -8, 5, 17, + 30, 41, 46, 44, 38, 30, 22, 11, 4, -5, -12, -20, -25, -26, -24, -17, + -7, 3, 8, 11, 12, 14, 15, 14, 9, -4, -17, -32, -44, -54, -57, -56, + -48, -36, -22, -5, 18, 41, 61, 74, 79, 75, 67, 55, 39, 20, -2, -20, + -37, -47, -56, -62, -63, -57, -44, -31, -18, -5, 7, 16, 28, 35, 38, 37, + 32, 25, 16, 8, 3, -2, -5, -11, -19, -21, -16, -7, 3, 6, 8, 7, + 8, 10, 9, 5, -4, -13, -23, -37, -49, -54, -54, -47, -38, -25, -9, 9, + 30, 50, 67, 77, 75, 69, 58, 42, 26, 7, -12, -31, -46, -52, -56, -59, + -58, -49, -36, -19, -5, 8, 14, 22, 28, 33, 35, 30, 23, 13, 4, 3, + 3, 0, -8, -12, -13, -10, -6, 2, 8, 11, 12, 11, 9, 4, -2, -5, + -12, -23, -35, -46, -52, -54, -48, -36, -22, -8, 9, 28, 46, 61, 70, 72, + 68, 58, 45, 27, 9, -8, -22, -35, -43, -48, -48, -46, -39, -33, -23, -12, + 1, 8, 11, 14, 16, 19, 19, 17, 11, 7, 8, 11, 13, 7, 5, 2, + 2, 2, 4, 6, 6, 5, 2, -3, -5, -9, -11, -17, -23, -29, -34, -40, + -45, -41, -32, -18, -5, 7, 19, 36, 54, 64, 67, 61, 55, 48, 36, 18, + 3, -11, -23, -36, -45, -46, -42, -39, -34, -27, -20, -11, 0, 10, 13, 14, + 12, 13, 13, 10, 7, 6, 9, 11, 11, 11, 10, 10, 8, 9, 9, 9, + 6, 1, -4, -12, -16, -22, -25, -28, -29, -30, -39, -43, -39, -26, -11, 0, + 8, 19, 33, 48, 58, 63, 61, 56, 50, 40, 25, 8, -5, -15, -24, -35, + -41, -42, -39, -32, -29, -25, -21, -13, -6, 0, 4, 2, 2, 3, 6, 6, + 7, 11, 17, 20, 22, 23, 24, 23, 21, 17, 12, 4, -5, -13, -22, -29, + -37, -41, -40, -36, -31, -32, -34, -34, -22, -6, 8, 14, 20, 29, 41, 50, + 56, 56, 49, 45, 39, 30, 17, 5, -8, -19, -28, -34, -35, -32, -27, -25, + -25, -23, -19, -12, -7, -4, -6, -10, -11, -7, 0, 4, 10, 14, 19, 26, + 32, 35, 34, 31, 25, 16, 6, -5, -17, -29, -39, -47, -51, -50, -44, -35, + -28, -27, -25, -18, -6, 10, 18, 21, 25, 31, 40, 46, 49, 48, 44, 42, + 37, 29, 19, 8, -5, -14, -21, -29, -30, -30, -27, -28, -32, -33, -31, -22, + -17, -15, -17, -19, -19, -9, 5, 16, 22, 25, 31, 38, 44, 47, 43, 34, + 20, 6, -9, -21, -35, -49, -59, -62, -60, -53, -42, -30, -22, -15, -6, 4, + 14, 23, 27, 28, 27, 30, 35, 38, 39, 42, 38, 35, 30, 25, 20, 12, + 4, -6, -18, -23, -22, -20, -22, -30, -37, -39, -34, -29, -27, -27, -26, -23, + -16, -3, 10, 21, 29, 35, 43, 46, 50, 49, 41, 28, 15, -2, -19, -35, + -50, -62, -67, -67, -60, -50, -36, -23, -14, -6, 3, 11, 21, 27, 27, 24, + 25, 27, 29, 31, 36, 41, 42, 39, 33, 27, 22, 17, 8, -3, -11, -15, + -15, -18, -25, -35, -42, -45, -42, -41, -41, -40, -38, -28, -12, 7, 22, 34, + 43, 51, 59, 62, 59, 49, 37, 20, 1, -19, -38, -54, -65, -73, -74, -69, + -55, -35, -19, -10, -2, 8, 18, 23, 25, 25, 22, 20, 19, 20, 22, 30, + 39, 44, 42, 39, 35, 32, 29, 18, 4, -8, -13, -15, -17, -24, -33, -43, + -47, -44, -42, -40, -40, -39, -32, -17, 3, 16, 28, 39, 47, 53, 56, 56, + 52, 40, 24, 5, -12, -29, -43, -54, -65, -72, -71, -56, -36, -20, -13, -4, + 5, 12, 18, 21, 23, 20, 18, 14, 16, 19, 27, 38, 45, 45, 42, 41, + 42, 37, 27, 15, 1, -8, -12, -13, -17, -30, -40, -47, -48, -47, -46, -46, + -45, -41, -28, -9, 11, 26, 38, 45, 51, 55, 58, 55, 47, 31, 10, -12, + -27, -39, -49, -58, -67, -69, -62, -46, -26, -13, -4, 2, 7, 14, 18, 21, + 20, 15, 11, 12, 14, 21, 32, 40, 44, 42, 42, 40, 37, 33, 22, 11, + 1, -7, -11, -11, -19, -30, -39, -43, -43, -42, -43, -44, -44, -36, -20, 0, + 14, 25, 35, 42, 46, 50, 50, 48, 36, 17, -3, -18, -30, -36, -43, -52, + -59, -60, -49, -35, -20, -12, -7, -4, 2, 8, 12, 12, 9, 9, 12, 16, + 23, 29, 39, 45, 46, 46, 43, 41, 37, 30, 20, 7, -5, -10, -11, -15, + -25, -39, -46, -45, -43, -42, -45, -46, -39, -26, -8, 8, 20, 31, 41, 45, + 48, 46, 44, 36, 21, 1, -20, -31, -33, -36, -44, -53, -59, -54, -41, -26, + -17, -12, -6, -3, 5, 7, 9, 11, 11, 12, 15, 20, 29, 36, 42, 46, + 45, 42, 40, 38, 33, 25, 13, 4, -7, -10, -11, -17, -29, -38, -38, -34, + -35, -39, -41, -39, -31, -16, -6, 4, 14, 24, 30, 34, 34, 35, 32, 22, + 8, -9, -16, -16, -17, -22, -33, -43, -46, -41, -34, -30, -25, -19, -14, -9, + -6, -2, 5, 9, 13, 15, 21, 29, 36, 43, 47, 46, 46, 42, 39, 37, + 31, 20, 10, 0, -6, -9, -14, -22, -29, -33, -31, -30, -34, -37, -37, -30, + -21, -12, -5, 1, 10, 20, 28, 31, 31, 28, 20, 12, 0, -8, -10, -10, + -16, -24, -33, -39, -44, -42, -35, -28, -23, -18, -14, -10, -4, 6, 12, 16, + 17, 22, 29, 33, 35, 38, 41, 43, 41, 38, 34, 30, 24, 16, 9, 3, + -4, -10, -15, -21, -23, -23, -23, -24, -28, -32, -31, -28, -22, -15, -10, -6, + 2, 11, 20, 23, 25, 19, 14, 9, 5, 3, 2, -2, -8, -19, -28, -36, + -42, -44, -39, -33, -28, -26, -20, -11, 0, 8, 15, 22, 28, 33, 35, 36, + 37, 38, 41, 40, 38, 32, 27, 21, 17, 11, 4, -3, -8, -12, -17, -18, + -16, -16, -15, -18, -22, -25, -26, -25, -23, -19, -15, -9, -2, 8, 13, 17, + 18, 17, 16, 15, 13, 10, 6, 0, -9, -21, -32, -42, -47, -46, -43, -36, + -30, -22, -15, -6, 4, 14, 22, 28, 33, 36, 37, 36, 35, 37, 36, 36, + 32, 27, 23, 16, 10, 5, 0, -7, -10, -12, -11, -11, -11, -10, -9, -11, + -16, -22, -27, -30, -30, -30, -25, -19, -9, 0, 7, 13, 18, 23, 27, 27, + 26, 20, 12, 1, -13, -27, -40, -50, -54, -54, -49, -42, -33, -21, -10, 1, + 14, 24, 30, 39, 44, 43, 38, 36, 38, 37, 34, 31, 28, 22, 13, 7, + 5, -2, -7, -11, -14, -13, -13, -8, -6, -6, -10, -12, -14, -19, -26, -34, + -38, -33, -26, -15, -7, 2, 7, 17, 26, 35, 40, 37, 29, 19, 7, -12, + -31, -44, -53, -56, -61, -62, -59, -46, -27, -9, 5, 14, 25, 36, 47, 53, + 51, 45, 37, 34, 32, 29, 26, 23, 18, 13, 5, 0, -3, -4, -6, -10, + -12, -12, -6, 2, 6, 2, -6, -12, -17, -21, -31, -41, -47, -43, -32, -20, + -11, -4, 9, 21, 40, 50, 48, 42, 34, 22, 5, -16, -36, -53, -58, -63, + -69, -73, -63, -43, -19, -2, 9, 19, 34, 50, 60, 61, 53, 42, 37, 32, + 30, 24, 21, 16, 11, 4, -4, -7, -6, -5, -5, -10, -14, -11, -4, 3, + 2, -2, -8, -13, -19, -26, -36, -42, -40, -33, -21, -9, 1, 10, 22, 36, + 49, 53, 47, 36, 19, 1, -18, -36, -51, -60, -65, -67, -67, -63, -47, -24, + -4, 11, 20, 33, 48, 57, 57, 52, 42, 33, 30, 28, 25, 19, 16, 12, + 8, 3, -2, -2, -2, -2, -5, -8, -10, -5, -2, 0, 0, -5, -8, -15, + -23, -32, -39, -38, -33, -24, -15, -7, 5, 16, 30, 45, 52, 49, 40, 23, + 4, -14, -29, -42, -55, -63, -67, -67, -61, -50, -35, -19, 0, 16, 31, 46, + 56, 59, 56, 47, 38, 34, 31, 28, 23, 16, 10, 4, 0, -2, -2, 0, + -5, -9, -12, -11, -7, -3, -3, -4, -5, -4, -7, -14, -26, -33, -32, -27, + -20, -15, -7, 2, 13, 21, 34, 42, 46, 40, 25, 7, -13, -27, -35, -44, + -54, -62, -64, -60, -51, -39, -26, -10, 8, 24, 40, 51, 58, 60, 54, 44, + 36, 29, 24, 19, 13, 8, 0, -6, -5, 0, 1, 0, -4, -3, -2, 0, + 1, -2, -5, -5, -4, -7, -17, -27, -31, -29, -24, -19, -15, -9, -3, 7, + 18, 27, 34, 39, 37, 26, 9, -9, -24, -32, -39, -47, -55, -60, -57, -51, + -42, -32, -20, -6, 14, 31, 48, 57, 60, 58, 52, 45, 35, 25, 21, 17, + 9, 0, -8, -10, -8, -7, -6, -9, -9, -6, -2, 0, -3, -6, -6, -2, + 1, -6, -15, -25, -25, -20, -17, -13, -11, -7, 1, 8, 16, 24, 31, 34, + 29, 16, -3, -17, -28, -35, -41, -47, -54, -56, -54, -46, -37, -27, -15, 4, + 23, 40, 50, 58, 60, 58, 50, 42, 34, 26, 19, 14, 4, -6, -13, -13, + -13, -14, -16, -15, -12, -9, -7, -7, -4, -4, 2, 7, 5, 0, -8, -11, + -13, -13, -11, -10, -11, -11, -9, 0, 8, 14, 22, 24, 19, 9, -3, -14, + -23, -29, -32, -38, -47, -54, -52, -44, -32, -23, -9, 8, 23, 39, 52, 59, + 58, 51, 46, 43, 33, 25, 16, 9, 4, -4, -11, -15, -16, -16, -15, -14, + -15, -16, -13, -7, -5, 2, 5, 5, 5, 6, 3, -4, -6, -4, -5, -10, + -16, -16, -13, -6, 4, 12, 15, 17, 14, 10, 4, -8, -17, -23, -30, -38, + -46, -52, -51, -41, -30, -20, -8, 9, 29, 47, 56, 57, 55, 52, 50, 45, + 34, 20, 10, 2, -2, -9, -16, -22, -24, -22, -21, -22, -19, -14, -7, -4, + 1, 5, 11, 15, 20, 17, 9, 3, 3, 0, -6, -15, -21, -23, -16, -9, + -3, 4, 10, 13, 15, 13, 4, -9, -15, -20, -27, -39, -48, -51, -47, -38, + -29, -21, -7, 16, 36, 48, 51, 52, 55, 60, 59, 49, 33, 20, 12, 7, + -2, -13, -24, -28, -27, -26, -30, -32, -29, -20, -9, 0, 3, 8, 16, 25, + 28, 23, 17, 12, 6, -2, -14, -26, -31, -27, -18, -10, -3, 7, 15, 22, + 24, 18, 9, 0, -9, -19, -34, -46, -57, -57, -51, -44, -38, -26, -5, 21, + 42, 48, 53, 58, 67, 75, 71, 57, 37, 23, 12, 3, -12, -27, -39, -43, + -43, -45, -47, -42, -28, -12, 2, 7, 12, 20, 32, 38, 37, 30, 21, 13, + 1, -13, -26, -34, -33, -26, -17, -10, -3, 9, 20, 25, 22, 13, 5, -3, + -13, -28, -43, -53, -56, -51, -46, -40, -31, -14, 10, 31, 41, 47, 56, 67, + 76, 73, 63, 46, 30, 19, 9, -7, -25, -39, -47, -50, -54, -52, -50, -38, + -22, -9, 4, 12, 22, 30, 39, 41, 39, 31, 22, 12, -3, -19, -30, -32, + -29, -23, -17, -9, 1, 12, 20, 24, 18, 10, 2, -7, -19, -35, -50, -59, + -59, -54, -49, -43, -31, -9, 15, 32, 41, 53, 70, 85, 87, 80, 64, 49, + 37, 23, 2, -23, -42, -52, -59, -66, -69, -68, -56, -38, -18, -2, 9, 19, + 31, 41, 49, 51, 44, 35, 21, 5, -9, -22, -29, -30, -26, -20, -14, -7, + 5, 15, 17, 14, 9, 2, -4, -16, -29, -45, -55, -56, -50, -46, -44, -36, + -19, 1, 19, 33, 46, 63, 79, 86, 84, 73, 60, 47, 32, 12, -10, -30, + -48, -59, -68, -72, -73, -64, -49, -30, -12, 2, 12, 26, 35, 45, 51, 51, + 44, 30, 15, 3, -9, -17, -20, -21, -19, -18, -14, 0, 10, 16, 15, 7, + -4, -10, -14, -24, -38, -51, -58, -55, -50, -44, -36, -23, -7, 10, 26, 41, + 57, 76, 89, 89, 81, 70, 59, 45, 25, 0, -24, -41, -56, -67, -75, -80, + -76, -63, -45, -26, -9, 6, 20, 32, 44, 52, 54, 53, 47, 35, 18, 3, + -6, -11, -14, -16, -19, -19, -12, -4, 5, 5, 0, -8, -12, -15, -21, -34, + -47, -51, -45, -39, -34, -30, -23, -12, 4, 17, 31, 45, 60, 72, 78, 75, + 69, 62, 53, 40, 18, -5, -24, -38, -50, -62, -73, -78, -74, -59, -41, -28, + -17, -4, 14, 33, 47, 55, 58, 55, 48, 39, 29, 16, 4, -5, -11, -18, + -21, -20, -15, -8, -7, -9, -13, -15, -16, -17, -23, -33, -43, -44, -41, -34, + -28, -23, -16, -8, 5, 21, 36, 50, 62, 73, 76, 73, 68, 59, 48, 30, + 9, -16, -35, -48, -59, -70, -77, -79, -72, -54, -38, -24, -8, 8, 29, 45, + 56, 61, 62, 56, 51, 39, 27, 16, 4, -8, -16, -22, -23, -25, -19, -16, + -17, -19, -20, -21, -18, -19, -25, -32, -38, -34, -24, -19, -15, -12, -7, 3, + 15, 28, 39, 48, 56, 63, 63, 63, 57, 47, 32, 14, -5, -22, -36, -46, + -58, -68, -73, -71, -61, -47, -35, -23, -9, 10, 29, 43, 52, 56, 56, 56, + 52, 45, 33, 19, 6, -5, -15, -22, -25, -26, -26, -29, -29, -26, -24, -20, + -19, -23, -27, -30, -27, -21, -18, -14, -10, -7, 0, 8, 18, 30, 40, 47, + 52, 54, 54, 55, 49, 39, 22, 7, -9, -24, -37, -50, -58, -65, -71, -67, + -59, -50, -39, -23, -6, 15, 32, 43, 51, 57, 61, 64, 61, 52, 37, 21, + 4, -11, -20, -26, -30, -35, -37, -39, -35, -29, -22, -17, -20, -22, -20, -18, + -17, -16, -13, -8, -3, 2, 7, 10, 17, 27, 35, 42, 43, 44, 45, 44, + 38, 28, 16, 3, -10, -22, -33, -46, -57, -64, -64, -59, -53, -46, -34, -17, + 3, 21, 32, 41, 48, 55, 60, 60, 54, 44, 31, 18, 3, -10, -19, -27, + -30, -32, -34, -35, -30, -23, -17, -17, -20, -20, -20, -17, -15, -13, -11, -8, + 1, 8, 12, 17, 23, 30, 39, 39, 37, 36, 35, 34, 27, 14, 0, -10, + -15, -23, -34, -46, -56, -60, -56, -49, -39, -32, -23, -8, 8, 23, 32, 38, + 44, 54, 58, 57, 48, 37, 29, 17, 4, -11, -21, -28, -29, -31, -34, -35, + -27, -20, -15, -16, -16, -17, -13, -10, -10, -11, -10, -4, 5, 11, 13, 15, + 21, 29, 33, 32, 28, 25, 25, 23, 16, 5, -6, -10, -16, -21, -30, -42, + -48, -48, -43, -34, -29, -21, -13, -3, 11, 22, 27, 34, 39, 48, 53, 48, + 42, 32, 23, 16, 4, -7, -18, -24, -24, -26, -28, -24, -19, -14, -13, -16, + -18, -18, -16, -14, -15, -16, -15, -7, 3, 11, 14, 21, 27, 33, 36, 33, + 30, 25, 22, 17, 9, -4, -15, -21, -24, -31, -39, -44, -44, -39, -30, -23, + -16, -8, 4, 14, 21, 23, 25, 29, 37, 43, 42, 36, 31, 25, 18, 11, + 4, -7, -11, -13, -16, -21, -22, -18, -14, -13, -16, -19, -21, -21, -19, -19, + -20, -18, -11, -2, 8, 14, 18, 23, 30, 34, 35, 31, 27, 21, 13, 2, + -11, -17, -23, -28, -36, -39, -40, -37, -31, -23, -14, -9, 0, 7, 13, 15, + 15, 16, 22, 27, 30, 28, 29, 32, 29, 23, 16, 9, 4, 1, -2, -7, + -14, -19, -14, -10, -10, -14, -18, -22, -24, -23, -26, -28, -27, -18, -8, -3, + 2, 9, 22, 33, 40, 40, 36, 30, 25, 20, 8, -8, -22, -29, -32, -39, + -48, -50, -42, -30, -19, -13, -8, 2, 11, 22, 25, 21, 17, 15, 20, 23, + 21, 20, 20, 19, 19, 16, 11, 9, 7, 7, 3, 0, -3, -5, -5, -5, + -7, -12, -22, -28, -32, -35, -35, -36, -30, -21, -12, -4, 3, 16, 29, 39, + 46, 45, 40, 34, 26, 13, -2, -17, -28, -37, -48, -57, -60, -52, -36, -19, + -12, -8, 2, 16, 28, 33, 28, 23, 21, 22, 21, 19, 18, 16, 14, 12, + 8, 6, 5, 5, 7, 5, 4, 5, 7, 9, 7, 3, -5, -13, -22, -28, + -35, -44, -49, -48, -38, -26, -14, -7, 4, 20, 38, 49, 54, 53, 49, 40, + 26, 8, -11, -24, -33, -46, -61, -70, -67, -52, -31, -14, -5, 4, 14, 27, + 36, 36, 33, 29, 26, 25, 21, 14, 10, 7, 8, 6, 5, 5, 6, 8, + 9, 10, 14, 18, 17, 13, 5, -4, -12, -20, -28, -37, -49, -56, -56, -48, + -36, -25, -15, -2, 16, 36, 51, 55, 57, 55, 48, 37, 20, 1, -17, -30, + -43, -60, -73, -76, -63, -43, -24, -14, -6, 7, 23, 39, 44, 38, 34, 31, + 32, 30, 24, 16, 8, 5, 6, 6, 5, 5, 6, 10, 10, 13, 16, 19, + 19, 14, 5, -7, -18, -25, -34, -45, -55, -61, -59, -51, -39, -25, -12, 5, + 27, 48, 58, 60, 61, 58, 49, 32, 14, -4, -20, -36, -54, -69, -79, -75, + -57, -35, -21, -15, -4, 12, 28, 39, 42, 41, 38, 38, 38, 33, 23, 13, + 8, 9, 11, 9, 5, 3, 6, 10, 13, 14, 15, 17, 16, 9, -6, -16, + -21, -27, -40, -56, -65, -67, -57, -45, -33, -23, -5, 21, 44, 60, 66, 67, + 65, 61, 47, 25, 2, -16, -34, -53, -72, -83, -82, -70, -51, -33, -20, -8, + 8, 25, 39, 46, 43, 43, 43, 43, 38, 27, 17, 9, 8, 10, 11, 9, + 5, 5, 8, 13, 14, 18, 20, 18, 12, -2, -13, -19, -25, -34, -48, -62, + -69, -67, -58, -46, -32, -14, 9, 30, 48, 60, 69, 72, 69, 57, 36, 13, + -6, -27, -47, -66, -79, -83, -77, -64, -46, -29, -13, 4, 17, 30, 39, 41, + 46, 48, 45, 40, 31, 20, 12, 10, 13, 14, 12, 11, 10, 10, 15, 17, + 20, 20, 17, 12, 0, -14, -24, -30, -37, -47, -60, -69, -68, -62, -51, -36, + -18, 5, 25, 45, 58, 65, 68, 67, 59, 42, 20, -2, -22, -42, -61, -75, + -81, -77, -66, -51, -35, -20, -4, 14, 28, 37, 38, 38, 42, 47, 43, 35, + 24, 17, 14, 14, 17, 20, 20, 17, 13, 14, 17, 18, 18, 17, 11, -2, + -15, -24, -31, -38, -46, -52, -58, -62, -61, -52, -38, -22, -4, 16, 35, 48, + 55, 60, 62, 57, 46, 26, 6, -17, -35, -53, -68, -76, -75, -66, -51, -38, + -23, -7, 10, 25, 35, 38, 37, 39, 40, 39, 30, 21, 16, 15, 15, 16, + 20, 24, 26, 27, 27, 26, 24, 21, 19, 11, -3, -16, -29, -40, -44, -50, + -54, -57, -58, -55, -48, -36, -21, -5, 13, 29, 41, 48, 52, 53, 50, 41, + 26, 7, -14, -33, -49, -62, -70, -69, -61, -48, -36, -21, -5, 16, 30, 35, + 35, 35, 32, 31, 29, 24, 17, 13, 13, 14, 15, 18, 26, 34, 39, 37, + 32, 29, 26, 22, 13, 1, -15, -29, -40, -46, -51, -54, -55, -52, -46, -40, + -32, -22, -10, 5, 19, 28, 33, 35, 37, 38, 33, 21, 8, -7, -20, -35, + -50, -57, -57, -49, -37, -28, -21, -8, 10, 25, 32, 32, 31, 27, 24, 22, + 20, 15, 13, 13, 15, 15, 19, 26, 36, 42, 43, 40, 33, 27, 22, 16, + 3, -13, -26, -37, -44, -50, -55, -54, -48, -42, -32, -24, -18, -10, -3, 8, + 20, 30, 31, 26, 22, 20, 15, 7, -7, -20, -32, -43, -52, -52, -46, -36, + -25, -16, -5, 9, 24, 38, 42, 39, 30, 23, 19, 15, 11, 8, 6, 6, + 6, 9, 18, 30, 42, 47, 45, 43, 38, 31, 22, 8, -9, -21, -33, -45, + -55, -59, -56, -47, -37, -29, -21, -13, -5, 2, 8, 13, 19, 22, 20, 15, + 9, 5, -3, -9, -20, -30, -39, -46, -45, -40, -31, -24, -16, -6, 7, 21, + 35, 39, 36, 31, 24, 22, 15, 10, 8, 5, 6, 3, 4, 12, 25, 40, + 48, 50, 48, 43, 37, 30, 17, -2, -18, -33, -45, -57, -64, -62, -53, -40, + -31, -23, -13, -3, 4, 11, 16, 19, 18, 17, 13, 7, -3, -10, -16, -22, + -31, -40, -45, -45, -41, -32, -24, -15, -5, 8, 24, 39, 47, 44, 38, 32, + 26, 20, 12, 3, -4, -4, -5, -4, 1, 11, 29, 41, 49, 51, 49, 45, + 38, 27, 9, -11, -27, -38, -52, -60, -64, -58, -45, -32, -21, -14, -5, 3, + 10, 13, 13, 14, 14, 12, 4, -6, -12, -17, -21, -25, -31, -35, -40, -39, + -33, -27, -19, -12, 1, 16, 29, 38, 42, 40, 36, 33, 30, 22, 11, 1, + -2, -2, -3, -2, 2, 16, 32, 44, 48, 46, 44, 39, 31, 19, 1, -21, + -36, -48, -58, -62, -59, -49, -38, -28, -20, -12, -2, 9, 16, 16, 15, 16, + 14, 9, 2, -7, -14, -19, -25, -31, -36, -38, -38, -36, -34, -28, -20, -7, + 8, 22, 33, 41, 46, 46, 42, 39, 33, 25, 14, 4, -4, -8, -8, -4, + 4, 16, 30, 38, 42, 46, 45, 38, 25, 10, -7, -24, -39, -51, -58, -59, + -53, -43, -34, -28, -21, -9, 5, 15, 17, 16, 15, 16, 15, 10, 2, -10, + -17, -21, -26, -33, -38, -40, -37, -34, -33, -28, -17, 0, 15, 29, 40, 48, + 50, 48, 44, 40, 34, 26, 15, 3, -6, -11, -11, -4, 7, 18, 24, 30, + 36, 38, 35, 31, 24, 13, -7, -25, -40, -50, -53, -51, -47, -41, -38, -33, + -25, -10, 4, 14, 19, 21, 22, 19, 19, 17, 7, -5, -15, -23, -31, -39, + -46, -49, -49, -46, -41, -33, -19, 0, 21, 39, 53, 61, 64, 63, 56, 50, + 42, 31, 15, -2, -13, -19, -19, -11, 0, 10, 15, 19, 27, 33, 37, 35, + 25, 9, -13, -28, -38, -44, -46, -50, -53, -51, -46, -38, -23, -7, 10, 20, + 21, 24, 25, 28, 28, 19, 8, -7, -18, -28, -36, -43, -52, -56, -57, -51, + -44, -31, -13, 7, 29, 46, 60, 66, 71, 68, 61, 54, 45, 32, 13, -5, + -17, -22, -20, -15, -8, -2, 8, 14, 24, 31, 35, 32, 21, 4, -13, -24, + -34, -42, -49, -55, -58, -54, -48, -38, -23, -4, 14, 26, 32, 31, 32, 36, + 34, 23, 7, -12, -25, -35, -47, -61, -68, -68, -61, -53, -42, -26, -7, 22, + 45, 61, 71, 75, 78, 74, 66, 56, 42, 24, 7, -13, -24, -29, -25, -18, + -11, -7, 2, 14, 27, 36, 38, 32, 19, 1, -14, -22, -33, -44, -56, -64, + -65, -60, -47, -32, -16, 3, 18, 31, 37, 37, 38, 41, 35, 20, 0, -18, + -31, -43, -56, -64, -69, -68, -60, -50, -36, -15, 6, 31, 50, 62, 71, 77, + 78, 74, 66, 54, 38, 20, 2, -15, -23, -26, -24, -22, -17, -7, 8, 20, + 29, 35, 33, 25, 13, -2, -14, -29, -42, -57, -67, -72, -67, -57, -42, -24, + -5, 13, 31, 43, 46, 47, 48, 43, 32, 14, -5, -22, -40, -55, -63, -68, + -69, -66, -57, -44, -25, -5, 18, 37, 55, 66, 75, 78, 75, 70, 62, 47, + 28, 9, -7, -19, -27, -30, -27, -21, -11, 5, 18, 28, 34, 36, 32, 24, + 12, -4, -20, -38, -55, -68, -75, -71, -65, -53, -35, -14, 6, 24, 39, 47, + 50, 48, 44, 36, 22, 5, -16, -34, -47, -56, -60, -60, -59, -54, -45, -28, + -9, 9, 25, 41, 53, 63, 67, 66, 65, 62, 54, 40, 22, 6, -8, -16, + -22, -23, -20, -11, 1, 13, 22, 27, 29, 26, 24, 15, 2, -15, -33, -49, + -64, -74, -74, -67, -55, -39, -20, -2, 16, 32, 45, 50, 49, 43, 35, 26, + 11, -9, -25, -35, -44, -49, -52, -54, -50, -39, -26, -12, 1, 14, 27, 39, + 48, 53, 55, 57, 56, 48, 36, 25, 15, 6, -5, -12, -17, -14, -8, 3, + 14, 21, 26, 23, 21, 21, 14, 3, -11, -26, -44, -61, -72, -72, -68, -56, + -42, -25, -11, 7, 24, 37, 44, 44, 40, 33, 25, 13, 0, -12, -24, -32, + -39, -41, -39, -36, -30, -24, -18, -10, 1, 11, 21, 29, 36, 41, 47, 51, + 51, 42, 35, 27, 19, 10, 1, -6, -10, -9, -2, 6, 11, 13, 13, 15, + 14, 10, 4, -9, -19, -31, -45, -58, -67, -68, -56, -43, -31, -20, -9, 7, + 21, 31, 35, 35, 33, 27, 18, 7, -3, -9, -13, -20, -27, -32, -33, -29, + -23, -19, -16, -12, -4, 6, 15, 23, 30, 39, 47, 49, 42, 35, 31, 27, + 22, 14, 2, -8, -9, -4, 5, 8, 8, 9, 7, 6, 3, 0, -5, -12, + -22, -35, -50, -58, -58, -50, -39, -32, -26, -19, -8, 7, 21, 26, 27, 25, + 22, 18, 11, 5, 2, 1, -3, -10, -19, -24, -23, -16, -15, -17, -20, -17, + -10, -2, 6, 12, 21, 32, 44, 45, 38, 30, 27, 31, 31, 21, 8, 1, + 0, 2, 8, 10, 7, 1, -3, -2, -4, -9, -12, -17, -25, -37, -47, -53, + -50, -42, -32, -27, -26, -22, -11, 5, 15, 18, 20, 22, 23, 22, 18, 15, + 14, 11, 7, -3, -14, -18, -17, -18, -22, -27, -27, -21, -14, -6, 3, 12, + 24, 34, 40, 39, 35, 32, 31, 34, 30, 19, 10, 4, 2, 5, 7, 7, + 1, -6, -10, -9, -8, -8, -11, -16, -25, -34, -41, -41, -36, -32, -33, -33, + -29, -22, -11, -2, 6, 13, 17, 22, 23, 22, 22, 24, 23, 20, 12, 0, + -7, -11, -14, -20, -26, -28, -26, -22, -15, -9, 2, 13, 25, 32, 33, 35, + 36, 37, 38, 35, 29, 19, 9, 5, 7, 6, 4, -3, -9, -12, -11, -6, + -4, -5, -10, -17, -26, -33, -37, -38, -38, -38, -41, -39, -31, -20, -9, -2, + 6, 15, 23, 31, 31, 31, 30, 29, 28, 21, 13, 2, -9, -17, -20, -23, + -26, -27, -26, -20, -14, -6, 6, 14, 22, 26, 32, 34, 35, 37, 37, 36, + 27, 15, 6, 6, 7, 5, -3, -13, -17, -17, -11, -5, -5, -6, -11, -18, + -24, -27, -30, -35, -40, -44, -44, -39, -28, -16, -6, 1, 9, 20, 31, 34, + 36, 37, 36, 33, 23, 14, 5, -3, -10, -17, -23, -30, -34, -31, -22, -14, + -8, 0, 7, 15, 20, 26, 30, 35, 40, 40, 34, 27, 18, 14, 9, 8, + 5, -2, -11, -15, -13, -8, -4, 0, 1, -6, -12, -18, -23, -29, -38, -45, + -52, -53, -47, -37, -28, -16, -5, 6, 17, 28, 37, 42, 43, 40, 37, 31, + 19, 8, 1, -7, -14, -22, -27, -33, -34, -28, -18, -8, 0, 5, 10, 14, + 19, 25, 33, 38, 39, 35, 27, 18, 13, 9, 8, 4, -3, -8, -12, -13, + -10, -4, 4, 4, -2, -7, -14, -21, -28, -36, -45, -53, -54, -50, -44, -34, + -20, -5, 7, 18, 28, 37, 39, 42, 40, 35, 28, 17, 7, 0, -7, -12, + -18, -23, -28, -28, -23, -17, -8, 2, 8, 9, 10, 12, 17, 25, 32, 33, + 28, 20, 13, 10, 10, 8, 6, 5, 1, -5, -6, -3, 3, 10, 10, 5, + -6, -15, -21, -28, -38, -49, -59, -62, -59, -51, -39, -25, -8, 7, 17, 28, + 37, 42, 44, 43, 38, 30, 17, 7, 0, -4, -10, -16, -24, -26, -27, -21, + -14, -9, -2, 5, 11, 14, 12, 13, 19, 26, 29, 26, 19, 13, 8, 8, + 9, 5, 2, 2, 4, 3, 1, 1, 5, 8, 7, 0, -10, -18, -25, -32, + -42, -52, -56, -53, -48, -38, -29, -14, 1, 14, 23, 30, 33, 33, 35, 33, + 26, 17, 9, 2, 1, 0, -5, -12, -19, -22, -21, -13, -8, -4, 5, 10, + 12, 10, 10, 14, 21, 25, 24, 15, 5, 3, 5, 7, 5, 2, 5, 10, + 12, 10, 9, 11, 13, 10, 2, -8, -18, -25, -32, -40, -50, -55, -53, -45, + -35, -27, -17, -4, 11, 20, 28, 30, 28, 29, 30, 28, 19, 10, 6, 6, + 5, 0, -10, -18, -20, -18, -14, -11, -10, -4, 6, 13, 13, 11, 13, 20, + 25, 24, 15, 7, 3, 4, 5, 4, 0, 3, 9, 14, 15, 11, 9, 8, + 8, 6, -5, -16, -24, -29, -35, -43, -48, -47, -42, -31, -23, -17, -7, 5, + 17, 24, 26, 22, 19, 19, 20, 17, 11, 5, 2, 2, 0, -4, -10, -14, + -14, -10, -8, -6, 1, 10, 19, 23, 22, 17, 16, 19, 18, 11, 1, -8, + -11, -10, -7, -4, 1, 7, 15, 22, 22, 18, 17, 16, 12, 4, -8, -21, + -29, -34, -39, -46, -49, -46, -37, -28, -19, -9, -2, 8, 19, 22, 20, 18, + 18, 19, 19, 12, 6, 3, 2, 0, -5, -10, -16, -18, -14, -9, -8, -3, + 6, 17, 25, 27, 26, 24, 25, 22, 15, 3, -8, -13, -13, -12, -11, -6, + 0, 9, 16, 19, 19, 16, 13, 10, 6, -5, -14, -22, -26, -32, -37, -41, + -39, -32, -23, -17, -14, -10, -3, 9, 17, 18, 10, 7, 10, 16, 18, 12, + 5, 1, 1, -4, -13, -18, -18, -15, -12, -11, -10, 1, 15, 29, 37, 35, + 31, 30, 30, 24, 11, -8, -18, -18, -15, -17, -20, -17, -6, 8, 15, 18, + 16, 15, 11, 12, 8, 0, -10, -16, -20, -28, -35, -38, -33, -27, -23, -21, + -19, -13, 0, 11, 14, 12, 9, 11, 18, 21, 19, 10, 2, -3, -5, -12, + -21, -28, -26, -20, -15, -12, -6, 9, 25, 38, 43, 42, 40, 38, 34, 23, + 6, -12, -18, -18, -18, -23, -25, -22, -13, 0, 7, 9, 8, 8, 11, 12, + 9, 6, 2, -5, -14, -21, -24, -24, -22, -22, -21, -22, -20, -12, -3, 4, + 5, 5, 6, 11, 15, 16, 10, 4, -2, -7, -11, -20, -25, -27, -21, -13, + -11, -5, 6, 22, 37, 46, 50, 49, 44, 39, 31, 16, -3, -15, -21, -24, + -27, -32, -33, -28, -17, -5, 5, 7, 7, 10, 15, 16, 15, 10, 4, -4, + -11, -18, -22, -22, -20, -22, -21, -21, -17, -10, 1, 6, 9, 10, 15, 19, + 18, 12, 5, 0, -9, -15, -23, -31, -36, -32, -24, -17, -11, -4, 12, 31, + 47, 53, 58, 60, 56, 49, 35, 15, -4, -16, -21, -25, -32, -42, -45, -35, + -23, -14, -8, 0, 6, 13, 20, 21, 19, 15, 9, 1, -6, -11, -13, -16, + -18, -20, -23, -20, -14, -8, 0, 2, 5, 11, 18, 18, 14, 6, -2, -10, + -18, -27, -34, -41, -40, -31, -20, -12, -7, 4, 23, 47, 64, 71, 71, 63, + 56, 46, 30, 12, -7, -22, -35, -42, -49, -52, -48, -34, -22, -14, -7, 3, + 15, 24, 27, 27, 24, 15, 6, -4, -8, -11, -13, -13, -15, -16, -14, -12, + -7, -2, 3, 10, 12, 14, 15, 7, 0, -7, -16, -25, -32, -40, -44, -44, + -36, -24, -11, 0, 6, 16, 36, 58, 72, 76, 71, 62, 51, 38, 24, 5, + -13, -30, -42, -50, -52, -53, -46, -33, -21, -15, -6, 7, 20, 25, 25, 21, + 18, 14, 7, 2, -5, -9, -9, -7, -8, -9, -10, -7, -3, 1, 6, 7, + 8, 9, 6, -2, -13, -23, -30, -35, -41, -45, -44, -38, -26, -15, -3, 11, + 19, 33, 52, 69, 75, 72, 65, 54, 42, 29, 13, -6, -25, -41, -49, -54, + -55, -48, -38, -26, -18, -8, 1, 13, 24, 29, 26, 19, 11, 5, 2, -2, + -6, -6, -6, -5, -7, -5, 1, 5, 9, 11, 8, 8, 7, 4, -6, -17, + -28, -35, -42, -47, -48, -45, -39, -29, -16, -5, 7, 18, 32, 45, 57, 64, + 67, 62, 54, 45, 35, 22, 5, -13, -28, -40, -47, -49, -46, -42, -32, -21, + -11, -4, 6, 15, 21, 21, 16, 12, 6, 1, -3, -5, -3, 3, 8, 9, + 8, 7, 7, 11, 12, 11, 6, -2, -9, -13, -20, -29, -40, -47, -47, -45, + -42, -37, -29, -16, -5, 7, 17, 27, 38, 48, 56, 59, 53, 44, 40, 37, + 30, 17, -2, -16, -25, -32, -35, -36, -35, -31, -23, -16, -10, -3, 4, 10, + 11, 8, 1, 0, 0, 0, 0, 1, 6, 14, 20, 21, 19, 15, 14, 13, + 11, 7, 0, -13, -21, -28, -37, -46, -51, -48, -43, -37, -32, -28, -21, -9, + 4, 17, 27, 32, 40, 45, 50, 51, 46, 40, 38, 35, 27, 12, -3, -13, + -23, -27, -29, -30, -29, -28, -23, -15, -10, -5, 2, 5, 5, 1, -2, -2, + 1, 4, 4, 8, 14, 19, 25, 26, 21, 15, 13, 12, 12, 5, -9, -21, + -30, -37, -43, -50, -51, -47, -42, -38, -34, -27, -17, -5, 10, 22, 30, 38, + 44, 49, 50, 46, 40, 37, 38, 33, 19, 4, -8, -14, -18, -22, -24, -24, + -22, -18, -16, -14, -10, -6, 1, 1, -6, -8, -9, -6, 0, 2, 8, 14, + 21, 28, 31, 27, 24, 21, 20, 16, 9, -3, -16, -26, -33, -42, -50, -55, + -56, -50, -43, -39, -38, -29, -13, 6, 18, 27, 33, 42, 51, 54, 53, 48, + 41, 39, 38, 29, 12, -5, -15, -19, -20, -23, -24, -22, -18, -17, -13, -12, + -10, -4, -3, -4, -7, -8, -9, -9, -7, 2, 9, 14, 21, 26, 27, 27, + 22, 20, 19, 17, 12, 1, -14, -25, -35, -41, -45, -50, -53, -54, -51, -47, + -41, -31, -18, -3, 12, 24, 35, 47, 55, 58, 57, 55, 49, 46, 40, 26, + 11, -5, -17, -22, -23, -23, -22, -21, -21, -18, -15, -9, -5, -3, -4, -6, + -7, -9, -12, -12, -8, 1, 7, 13, 14, 19, 23, 27, 26, 25, 25, 20, + 13, 4, -9, -22, -36, -42, -48, -55, -61, -62, -59, -54, -43, -32, -18, 0, + 18, 35, 49, 57, 60, 62, 63, 61, 57, 48, 33, 15, -2, -15, -24, -28, + -27, -22, -23, -24, -21, -13, -4, 3, 3, 1, -2, -4, -4, -9, -15, -16, + -13, -9, -5, 2, 7, 11, 19, 24, 28, 31, 29, 28, 24, 12, -4, -21, + -33, -38, -48, -61, -72, -76, -71, -61, -47, -34, -20, 2, 26, 45, 58, 65, + 69, 74, 75, 68, 55, 41, 28, 13, -7, -22, -32, -32, -29, -24, -23, -22, + -19, -7, 6, 7, 2, -2, -3, 0, -3, -10, -20, -24, -19, -12, -5, 1, + 5, 14, 23, 30, 33, 37, 39, 36, 24, 8, -10, -25, -33, -43, -55, -71, + -82, -82, -71, -57, -44, -29, -11, 13, 34, 52, 64, 70, 73, 77, 76, 65, + 50, 35, 20, 4, -13, -26, -31, -32, -27, -26, -25, -21, -10, 2, 8, 5, + 3, 0, 1, 2, -3, -12, -22, -24, -21, -16, -9, -3, 6, 14, 22, 28, + 34, 41, 42, 35, 23, 6, -10, -21, -32, -45, -61, -76, -85, -82, -70, -54, + -43, -29, -7, 18, 40, 55, 64, 71, 77, 81, 76, 62, 48, 32, 19, 6, + -10, -23, -30, -29, -28, -30, -27, -20, -10, -2, 3, 1, 0, 3, 6, 4, + -9, -18, -24, -22, -18, -14, -8, 0, 8, 16, 24, 32, 38, 42, 42, 31, + 15, -2, -14, -25, -38, -52, -67, -81, -85, -76, -63, -49, -37, -19, 3, 26, + 43, 57, 67, 75, 82, 79, 70, 56, 41, 28, 15, 1, -12, -22, -27, -27, + -28, -26, -21, -12, -3, 3, -2, -2, 1, 3, 1, -12, -22, -28, -29, -27, + -23, -18, -11, 3, 16, 25, 34, 44, 51, 52, 43, 27, 12, -2, -17, -34, + -51, -71, -82, -86, -83, -75, -61, -45, -27, -7, 16, 37, 53, 63, 72, 78, + 77, 68, 60, 45, 33, 20, 10, -2, -9, -15, -18, -22, -23, -19, -15, -8, + -5, -7, -8, -7, -4, -3, -10, -22, -29, -29, -24, -21, -18, -14, -3, 12, + 23, 27, 35, 44, 49, 47, 34, 18, 1, -11, -23, -40, -57, -73, -81, -80, + -74, -64, -50, -36, -19, 2, 22, 38, 49, 61, 69, 74, 69, 60, 50, 40, + 29, 20, 10, 2, -5, -9, -12, -16, -18, -14, -9, -6, -10, -13, -12, -10, + -11, -15, -23, -30, -31, -27, -25, -23, -19, -8, 8, 20, 28, 36, 45, 49, + 49, 41, 29, 15, -2, -15, -31, -49, -65, -76, -79, -77, -67, -55, -43, -30, + -13, 7, 25, 40, 51, 60, 66, 66, 62, 54, 45, 37, 29, 22, 14, 7, + 3, -3, -7, -10, -12, -10, -8, -12, -18, -19, -16, -13, -15, -23, -31, -33, + -29, -26, -25, -23, -15, 1, 14, 23, 31, 40, 50, 52, 46, 36, 21, 7, + -8, -24, -41, -58, -70, -75, -74, -67, -57, -43, -30, -18, -3, 13, 26, 39, + 48, 56, 60, 58, 51, 45, 42, 36, 29, 25, 20, 14, 9, 6, 3, 0, + -5, -6, -12, -17, -22, -21, -20, -24, -33, -37, -38, -35, -30, -28, -24, -17, + -3, 12, 24, 33, 43, 50, 52, 49, 40, 28, 13, -3, -18, -34, -51, -63, + -71, -72, -67, -59, -49, -37, -24, -10, 3, 16, 27, 37, 46, 50, 53, 51, + 49, 46, 43, 37, 32, 29, 25, 21, 17, 10, 4, -3, -8, -10, -11, -18, + -25, -29, -31, -34, -37, -40, -40, -37, -31, -25, -20, -13, 0, 17, 31, 41, + 48, 50, 49, 46, 36, 22, 8, -5, -20, -36, -49, -61, -67, -67, -61, -51, + -44, -36, -23, -9, 4, 13, 20, 30, 38, 46, 48, 47, 44, 44, 44, 46, + 42, 35, 31, 28, 24, 15, 5, -3, -6, -10, -18, -28, -35, -39, -41, -41, + -43, -45, -42, -36, -29, -23, -15, 1, 15, 28, 40, 47, 51, 51, 46, 37, + 27, 14, 2, -14, -29, -42, -49, -54, -62, -63, -57, -49, -41, -31, -21, -12, + -3, 6, 17, 25, 32, 40, 45, 49, 50, 48, 49, 49, 48, 44, 39, 34, + 26, 13, 4, -4, -11, -17, -23, -32, -41, -48, -48, -49, -48, -44, -39, -36, + -31, -21, -5, 13, 24, 35, 44, 51, 52, 47, 39, 30, 21, 8, -6, -18, + -34, -44, -50, -54, -59, -58, -53, -46, -38, -28, -18, -10, -4, 6, 16, 24, + 30, 37, 42, 48, 49, 47, 48, 51, 51, 49, 45, 35, 27, 17, 9, 0, + -12, -23, -32, -41, -48, -53, -55, -54, -53, -49, -43, -38, -27, -13, 5, 20, + 33, 44, 52, 58, 57, 50, 40, 29, 16, 5, -11, -29, -43, -53, -56, -62, + -65, -63, -54, -42, -33, -24, -16, -8, 3, 16, 23, 29, 33, 38, 44, 46, + 45, 43, 45, 49, 52, 48, 42, 37, 28, 19, 10, 0, -13, -25, -36, -42, + -47, -56, -58, -56, -53, -49, -48, -40, -26, -6, 13, 27, 39, 49, 59, 64, + 62, 53, 42, 29, 16, 2, -18, -37, -52, -60, -65, -71, -75, -68, -55, -41, + -30, -19, -10, 0, 14, 24, 33, 37, 38, 39, 42, 45, 45, 43, 45, 48, + 47, 46, 41, 35, 28, 19, 8, -6, -20, -30, -38, -44, -50, -55, -57, -59, + -57, -53, -46, -35, -19, 0, 17, 32, 45, 59, 66, 66, 59, 54, 46, 32, + 15, -5, -24, -43, -57, -65, -71, -76, -78, -71, -58, -41, -27, -16, -5, 5, + 15, 27, 37, 43, 43, 42, 42, 42, 43, 46, 46, 46, 45, 42, 41, 35, + 28, 18, 7, -6, -18, -29, -37, -44, -51, -56, -59, -61, -60, -55, -45, -33, + -18, -2, 18, 37, 50, 61, 67, 68, 65, 59, 47, 31, 10, -11, -32, -47, + -58, -71, -81, -86, -83, -70, -52, -36, -21, -9, 2, 13, 25, 35, 41, 44, + 43, 40, 39, 39, 40, 43, 43, 40, 39, 40, 40, 36, 28, 18, 9, -5, + -18, -28, -36, -44, -52, -57, -61, -64, -63, -56, -43, -27, -13, 6, 26, 44, + 56, 66, 71, 71, 64, 55, 42, 23, 3, -19, -38, -52, -66, -76, -82, -86, + -81, -67, -49, -32, -19, -8, 3, 15, 28, 36, 42, 43, 43, 41, 41, 40, + 40, 41, 40, 40, 41, 41, 36, 30, 24, 17, 10, -5, -19, -29, -37, -43, + -50, -57, -64, -66, -60, -50, -40, -28, -10, 12, 32, 45, 54, 59, 64, 67, + 63, 54, 35, 14, -6, -22, -35, -50, -64, -75, -82, -81, -73, -59, -46, -33, + -21, -8, 5, 19, 27, 33, 40, 44, 44, 42, 40, 42, 41, 40, 38, 39, + 38, 38, 35, 30, 21, 13, 4, -8, -16, -25, -35, -45, -53, -62, -65, -63, + -56, -47, -39, -25, -6, 15, 32, 45, 53, 58, 64, 65, 60, 48, 30, 9, + -7, -19, -31, -47, -60, -72, -79, -79, -73, -61, -50, -37, -24, -10, 3, 12, + 22, 33, 43, 47, 46, 44, 43, 45, 46, 45, 45, 43, 41, 38, 34, 26, + 16, 7, -2, -10, -19, -29, -39, -50, -59, -64, -62, -58, -51, -44, -34, -22, + -2, 16, 30, 41, 52, 56, 57, 58, 54, 42, 29, 13, 2, -12, -27, -42, + -56, -67, -71, -73, -70, -63, -55, -42, -26, -10, 2, 11, 20, 33, 41, 46, + 45, 43, 49, 53, 52, 48, 44, 43, 42, 38, 33, 22, 12, 4, -5, -13, + -23, -34, -43, -50, -57, -61, -60, -55, -49, -40, -29, -14, -2, 12, 25, 35, + 44, 51, 56, 56, 49, 39, 30, 20, 10, -2, -17, -32, -48, -60, -67, -74, + -77, -74, -66, -50, -36, -21, -9, 0, 14, 30, 43, 51, 53, 57, 62, 64, + 62, 58, 53, 48, 42, 36, 25, 12, 4, -4, -12, -21, -31, -38, -43, -45, + -47, -49, -47, -44, -40, -34, -28, -22, -11, 1, 11, 21, 28, 39, 49, 53, + 52, 49, 44, 38, 29, 16, -4, -24, -41, -57, -74, -86, -90, -86, -73, -59, + -44, -30, -16, 1, 21, 40, 54, 61, 66, 67, 71, 72, 65, 57, 49, 41, + 33, 24, 12, 1, -8, -12, -15, -22, -31, -37, -35, -31, -33, -36, -39, -40, + -38, -34, -32, -29, -24, -14, -2, 11, 24, 36, 48, 56, 61, 63, 59, 54, + 44, 27, 6, -19, -46, -68, -84, -94, -99, -98, -90, -72, -51, -30, -15, 1, + 22, 46, 64, 76, 78, 80, 81, 78, 72, 60, 45, 34, 24, 13, 0, -13, + -18, -18, -18, -22, -28, -29, -24, -19, -19, -26, -33, -38, -40, -40, -41, -42, + -41, -32, -15, 6, 22, 37, 50, 62, 74, 79, 76, 65, 50, 30, 6, -24, + -54, -78, -94, -106, -110, -103, -89, -69, -49, -29, -10, 11, 36, 57, 73, 78, + 80, 82, 83, 77, 66, 51, 37, 24, 14, 5, -5, -12, -17, -17, -17, -18, + -19, -17, -13, -13, -19, -28, -37, -44, -44, -48, -53, -59, -54, -35, -12, 11, + 29, 46, 61, 78, 88, 90, 84, 68, 49, 24, -6, -39, -71, -92, -104, -115, + -116, -108, -89, -66, -43, -21, 1, 24, 49, 68, 78, 82, 81, 81, 79, 71, + 56, 37, 24, 15, 6, -4, -9, -11, -9, -6, -6, -10, -11, -6, -4, -8, + -20, -33, -44, -55, -61, -65, -70, -68, -55, -31, -6, 15, 38, 61, 82, 97, + 101, 94, 80, 61, 37, 9, -25, -60, -88, -107, -119, -123, -116, -99, -77, -53, + -30, -5, 20, 47, 68, 80, 82, 82, 80, 77, 70, 57, 40, 23, 10, 3, + -2, -3, -4, -3, 2, 5, 7, 5, 5, 4, -4, -17, -32, -45, -60, -69, + -74, -79, -80, -70, -47, -20, 9, 32, 55, 76, 94, 104, 103, 91, 71, 46, + 16, -16, -48, -75, -97, -115, -121, -117, -101, -80, -57, -32, -8, 15, 39, 58, + 68, 73, 73, 73, 69, 61, 50, 39, 26, 15, 7, 4, 7, 12, 18, 19, + 20, 18, 17, 15, 10, -4, -20, -41, -57, -68, -77, -85, -91, -90, -76, -53, + -25, 2, 28, 55, 79, 97, 106, 104, 94, 77, 52, 22, -9, -39, -67, -92, + -111, -119, -115, -99, -79, -55, -33, -11, 15, 37, 55, 67, 71, 68, 61, 51, + 44, 40, 35, 24, 10, 3, 4, 13, 25, 36, 42, 41, 34, 29, 20, 12, + -2, -21, -43, -66, -84, -94, -96, -96, -93, -81, -55, -26, 4, 30, 56, 80, + 98, 107, 106, 95, 77, 53, 24, -8, -38, -64, -85, -101, -109, -109, -100, -80, + -55, -31, -8, 13, 31, 46, 56, 61, 59, 52, 43, 36, 30, 25, 16, 8, + 7, 11, 23, 37, 48, 56, 59, 56, 48, 33, 17, -5, -29, -54, -79, -96, + -106, -109, -105, -96, -82, -57, -25, 8, 38, 61, 79, 94, 103, 102, 92, 73, + 46, 19, -10, -36, -62, -81, -95, -101, -100, -90, -71, -47, -25, -3, 18, 31, + 41, 49, 53, 50, 42, 32, 21, 13, 9, 7, 8, 8, 12, 30, 49, 63, + 71, 76, 75, 67, 48, 25, -3, -30, -59, -87, -107, -120, -124, -117, -105, -89, + -63, -31, 5, 40, 63, 81, 92, 100, 100, 88, 69, 46, 20, -6, -31, -55, + -73, -87, -91, -88, -80, -64, -45, -22, 1, 16, 27, 34, 39, 45, 41, 31, + 20, 9, 4, 3, 1, 3, 6, 15, 32, 53, 71, 81, 85, 86, 78, 61, + 35, 3, -29, -63, -93, -113, -124, -128, -124, -110, -89, -64, -32, 5, 38, 62, + 80, 91, 98, 93, 80, 63, 42, 19, -5, -29, -51, -68, -78, -81, -79, -72, + -58, -40, -19, 0, 13, 21, 29, 35, 35, 29, 21, 14, 8, 2, -2, -3, + 1, 10, 20, 36, 56, 73, 84, 89, 89, 81, 65, 41, 6, -32, -63, -90, + -110, -124, -127, -123, -110, -89, -61, -30, 2, 33, 56, 71, 81, 86, 85, 74, + 58, 38, 17, -5, -21, -38, -52, -62, -69, -69, -64, -50, -34, -18, -5, 5, + 13, 23, 28, 27, 22, 15, 10, 6, 1, 0, -2, 2, 9, 23, 41, 56, + 72, 84, 88, 89, 81, 66, 45, 15, -20, -55, -84, -106, -119, -121, -116, -105, + -89, -67, -38, -7, 21, 44, 58, 69, 75, 74, 64, 50, 36, 22, 8, -10, + -26, -39, -47, -54, -56, -53, -47, -36, -25, -11, -2, 5, 14, 23, 24, 20, + 12, 7, 6, 6, 6, 4, 5, 10, 22, 39, 57, 72, 80, 82, 80, 73, + 62, 45, 18, -13, -48, -78, -96, -105, -105, -104, -97, -81, -64, -40, -15, 10, + 28, 40, 49, 54, 53, 49, 42, 31, 22, 13, 2, -9, -17, -22, -30, -38, + -40, -37, -33, -28, -22, -16, -10, -5, 5, 11, 11, 6, 3, 5, 11, 16, + 16, 18, 22, 29, 40, 54, 68, 75, 74, 72, 63, 49, 35, 15, -10, -37, + -63, -83, -94, -95, -89, -82, -73, -63, -46, -24, -2, 16, 25, 31, 35, 39, + 41, 37, 30, 22, 15, 11, 4, -3, -11, -18, -25, -31, -35, -33, -28, -22, + -18, -16, -13, -4, 5, 10, 11, 10, 5, 6, 14, 21, 23, 24, 27, 33, + 45, 59, 68, 72, 67, 57, 46, 34, 19, 0, -24, -49, -70, -81, -82, -77, + -70, -65, -60, -49, -34, -15, 2, 9, 13, 14, 18, 20, 21, 19, 18, 17, + 16, 15, 13, 10, 5, -3, -12, -20, -26, -28, -27, -24, -26, -25, -18, -9, + 3, 9, 10, 10, 11, 18, 27, 32, 33, 33, 35, 42, 51, 58, 59, 55, + 46, 36, 25, 16, 3, -15, -33, -50, -61, -65, -64, -59, -57, -56, -52, -42, + -29, -14, -5, -2, -3, 1, 8, 12, 13, 13, 16, 16, 18, 19, 19, 14, + 4, -3, -10, -19, -24, -24, -22, -20, -24, -23, -16, -2, 10, 16, 14, 13, + 16, 28, 35, 36, 35, 32, 33, 40, 45, 49, 47, 41, 31, 20, 12, 4, + -8, -16, -29, -41, -50, -53, -50, -49, -51, -51, -48, -40, -30, -20, -13, -13, + -12, -6, 2, 8, 12, 13, 16, 21, 26, 27, 23, 15, 8, 0, -10, -19, + -23, -24, -24, -26, -25, -21, -9, 5, 15, 19, 20, 22, 28, 36, 39, 38, + 36, 33, 33, 35, 37, 38, 36, 30, 20, 9, 4, -3, -10, -17, -26, -35, + -40, -45, -47, -51, -52, -49, -46, -39, -30, -23, -19, -17, -12, -5, 1, 4, + 7, 11, 18, 22, 22, 22, 20, 17, 12, 3, -8, -16, -18, -16, -17, -19, + -18, -12, 3, 13, 19, 20, 24, 29, 34, 35, 33, 32, 31, 31, 30, 26, + 24, 24, 25, 21, 14, 6, 0, -4, -5, -10, -19, -31, -37, -40, -47, -51, + -50, -49, -45, -39, -31, -25, -19, -12, -6, -3, 0, 2, 6, 13, 17, 18, + 16, 15, 16, 14, 7, -3, -10, -12, -13, -13, -14, -13, -6, 6, 18, 24, + 25, 26, 29, 33, 32, 26, 24, 23, 23, 22, 18, 14, 15, 21, 24, 22, + 14, 6, 4, 4, 1, -9, -21, -32, -41, -47, -50, -54, -54, -51, -47, -37, + -30, -21, -10, -3, 1, 4, 6, 7, 8, 7, 7, 7, 7, 6, 6, 5, + 2, -3, -8, -8, -6, -3, 1, 3, 9, 17, 25, 29, 32, 33, 29, 26, + 24, 23, 20, 17, 14, 11, 8, 8, 14, 21, 22, 17, 13, 9, 9, 7, + 1, -11, -25, -37, -44, -52, -53, -55, -55, -51, -43, -35, -24, -14, -4, 3, + 4, 4, 6, 7, 6, 3, -2, -2, 2, 6, 5, 1, -4, -8, -7, -5, + 3, 9, 9, 12, 17, 25, 32, 37, 37, 32, 25, 21, 19, 17, 15, 9, + 6, 6, 6, 8, 14, 23, 24, 20, 15, 14, 11, 3, -6, -18, -31, -44, + -53, -54, -57, -58, -55, -47, -37, -26, -16, -4, 7, 10, 10, 9, 7, 3, + -2, -6, -8, -6, -5, -4, -7, -10, -8, -6, 0, 6, 12, 16, 20, 27, + 33, 35, 35, 36, 34, 28, 21, 16, 10, 7, 7, 5, 3, 1, 5, 12, + 21, 25, 23, 17, 14, 13, 9, -3, -17, -30, -41, -50, -54, -59, -61, -55, + -46, -37, -26, -15, -4, 7, 14, 15, 12, 6, 1, -3, -7, -12, -14, -15, + -13, -12, -12, -12, -8, 0, 8, 15, 20, 25, 31, 36, 40, 41, 41, 38, + 33, 27, 21, 12, 4, 1, 0, -4, -5, -2, 5, 12, 17, 19, 19, 18, + 14, 11, 2, -9, -21, -32, -42, -49, -55, -57, -56, -49, -39, -30, -20, -8, + 3, 12, 17, 18, 12, 5, -2, -8, -14, -18, -21, -22, -21, -21, -19, -13, + -7, 4, 14, 24, 32, 39, 44, 48, 47, 44, 41, 38, 33, 27, 17, 7, + -3, -5, -5, -5, -5, -5, 3, 12, 17, 19, 16, 11, 7, 3, -6, -15, + -26, -36, -42, -48, -53, -54, -50, -40, -31, -22, -12, -2, 11, 19, 20, 13, + 6, 2, -5, -12, -21, -26, -29, -31, -30, -27, -21, -13, -2, 12, 25, 36, + 48, 57, 62, 60, 51, 46, 43, 37, 28, 15, 3, -8, -12, -14, -12, -10, + -7, -4, 8, 16, 20, 17, 14, 10, 6, -2, -12, -24, -32, -39, -45, -51, + -54, -52, -43, -32, -21, -12, -2, 11, 22, 28, 24, 13, 4, -6, -14, -23, + -32, -38, -41, -42, -39, -31, -20, -8, 6, 21, 37, 50, 63, 69, 68, 61, + 55, 48, 39, 29, 20, 9, -6, -15, -17, -13, -11, -7, -4, 3, 11, 13, + 16, 15, 10, 5, 0, -8, -15, -25, -31, -37, -42, -49, -52, -46, -37, -30, + -21, -12, 0, 14, 25, 28, 25, 15, 2, -11, -22, -29, -36, -44, -49, -49, + -43, -32, -18, -5, 13, 30, 50, 66, 74, 75, 71, 68, 61, 50, 37, 26, + 15, 3, -13, -22, -22, -20, -16, -14, -9, 1, 9, 11, 11, 9, 9, 9, + 6, -3, -15, -25, -32, -37, -41, -50, -53, -50, -41, -30, -20, -8, 6, 21, + 31, 33, 26, 15, 0, -12, -23, -34, -46, -56, -60, -54, -44, -31, -19, -2, + 21, 44, 66, 77, 81, 79, 75, 72, 63, 51, 35, 23, 10, -4, -16, -25, + -28, -26, -22, -16, -12, -7, -2, 4, 8, 10, 14, 14, 7, -3, -12, -20, + -28, -36, -42, -48, -53, -53, -43, -31, -19, -6, 12, 25, 31, 30, 26, 15, + -2, -17, -28, -40, -52, -60, -61, -53, -40, -25, -9, 11, 32, 56, 74, 84, + 85, 81, 76, 72, 61, 46, 29, 13, -2, -16, -23, -29, -33, -31, -25, -19, + -14, -8, 2, 10, 14, 18, 19, 17, 8, 1, -12, -24, -35, -42, -49, -54, + -57, -53, -43, -30, -13, 7, 22, 32, 34, 32, 26, 11, -8, -24, -40, -50, + -60, -66, -63, -53, -36, -17, 2, 23, 45, 67, 84, 90, 91, 85, 78, 72, + 62, 44, 24, 4, -9, -21, -32, -39, -41, -36, -30, -23, -17, -9, 2, 13, + 23, 27, 26, 19, 12, 2, -12, -26, -38, -47, -54, -59, -59, -53, -41, -23, + -5, 14, 28, 36, 36, 31, 21, 6, -13, -31, -46, -58, -66, -70, -65, -50, + -28, -7, 14, 35, 58, 76, 89, 96, 94, 90, 82, 72, 54, 35, 16, -5, + -21, -31, -40, -48, -47, -38, -28, -20, -13, 1, 15, 28, 33, 33, 27, 18, + 8, -6, -21, -37, -52, -64, -66, -65, -58, -47, -30, -9, 13, 28, 38, 43, + 40, 31, 15, -5, -24, -40, -57, -69, -75, -74, -65, -48, -26, -2, 24, 47, + 66, 83, 97, 102, 102, 101, 91, 73, 51, 28, 7, -15, -33, -45, -56, -60, + -54, -42, -28, -17, -4, 13, 26, 36, 38, 36, 29, 16, 2, -14, -34, -52, + -62, -66, -65, -63, -53, -36, -15, 9, 27, 36, 41, 40, 35, 25, 8, -16, + -37, -55, -68, -77, -81, -75, -60, -37, -12, 12, 35, 57, 75, 94, 105, 107, + 103, 97, 84, 64, 41, 18, -6, -25, -40, -51, -57, -56, -46, -32, -19, -6, + 7, 20, 30, 34, 32, 24, 12, 0, -17, -33, -47, -60, -65, -64, -58, -46, + -31, -12, 8, 26, 37, 43, 44, 41, 28, 11, -12, -31, -49, -67, -81, -87, + -85, -72, -52, -30, -6, 21, 45, 69, 87, 101, 110, 113, 110, 100, 77, 51, + 27, 8, -11, -32, -49, -59, -59, -53, -41, -27, -11, 3, 14, 24, 28, 28, + 24, 17, 5, -15, -32, -45, -54, -61, -58, -54, -44, -32, -13, 8, 26, 37, + 41, 40, 36, 29, 16, -3, -24, -47, -66, -81, -89, -88, -76, -58, -37, -16, + 10, 34, 58, 78, 94, 106, 111, 107, 97, 81, 58, 37, 17, 0, -17, -33, + -45, -51, -48, -38, -26, -14, -3, 9, 16, 19, 17, 14, 10, 0, -15, -30, + -42, -49, -52, -49, -44, -37, -25, -8, 9, 21, 29, 32, 35, 33, 29, 19, + 1, -18, -38, -58, -75, -85, -85, -79, -70, -52, -29, -6, 20, 44, 67, 89, + 101, 110, 114, 107, 93, 72, 49, 28, 10, -9, -25, -38, -48, -49, -42, -31, + -20, -11, 0, 9, 13, 12, 7, 5, 0, -11, -24, -36, -42, -44, -43, -38, + -28, -16, -4, 8, 16, 22, 29, 30, 29, 24, 13, 2, -14, -32, -51, -68, + -79, -83, -77, -69, -56, -41, -19, 6, 31, 53, 74, 90, 101, 108, 109, 101, + 83, 60, 38, 24, 9, -10, -25, -36, -40, -37, -29, -21, -13, -8, 0, 3, + 0, -5, -6, -8, -16, -27, -35, -39, -40, -33, -27, -21, -11, 3, 14, 21, + 24, 27, 26, 22, 19, 13, 3, -14, -32, -53, -66, -74, -80, -80, -75, -63, + -47, -28, -4, 19, 41, 66, 85, 99, 105, 106, 104, 95, 76, 51, 29, 13, + 2, -12, -27, -36, -38, -32, -22, -15, -12, -8, -3, -4, -9, -12, -14, -18, + -26, -31, -35, -36, -29, -20, -10, -2, 7, 16, 25, 25, 24, 19, 15, 10, + 4, -4, -16, -30, -44, -57, -67, -73, -75, -70, -60, -48, -34, -16, 5, 27, + 51, 71, 85, 92, 99, 101, 95, 82, 64, 44, 28, 14, 1, -12, -22, -28, + -27, -22, -18, -17, -15, -15, -15, -21, -23, -25, -24, -27, -31, -34, -30, -21, + -6, 7, 13, 17, 22, 27, 28, 24, 16, 7, -3, -10, -17, -27, -35, -43, + -50, -58, -68, -70, -65, -53, -42, -32, -22, -4, 15, 36, 54, 70, 83, 89, + 92, 91, 82, 68, 54, 42, 29, 14, 2, -9, -17, -21, -22, -20, -21, -20, + -23, -26, -30, -32, -32, -29, -27, -28, -30, -26, -15, 0, 15, 25, 25, 25, + 26, 27, 21, 11, 0, -9, -17, -24, -30, -38, -45, -47, -49, -55, -59, -56, + -48, -39, -28, -20, -9, 7, 26, 44, 55, 65, 72, 79, 80, 77, 66, 57, + 49, 41, 30, 19, 7, -2, -7, -12, -17, -22, -25, -29, -33, -36, -39, -41, + -36, -29, -26, -26, -22, -11, 2, 17, 28, 32, 31, 29, 28, 23, 11, -2, + -9, -17, -24, -36, -44, -48, -49, -50, -53, -54, -54, -47, -36, -25, -17, -7, + 7, 21, 36, 47, 55, 63, 70, 72, 69, 60, 52, 46, 42, 34, 23, 15, + 8, 3, 0, -7, -14, -21, -24, -27, -32, -39, -44, -43, -37, -29, -25, -23, + -16, -2, 14, 26, 32, 33, 32, 30, 25, 16, 4, -6, -16, -25, -36, -45, + -50, -54, -51, -51, -54, -54, -48, -36, -23, -15, -6, 5, 17, 31, 42, 51, + 59, 62, 63, 61, 56, 51, 43, 40, 38, 28, 20, 13, 9, 7, 2, -8, + -16, -23, -27, -31, -36, -40, -43, -39, -31, -23, -20, -15, -4, 11, 24, 31, + 32, 31, 30, 25, 17, 7, -3, -13, -23, -36, -48, -56, -58, -57, -53, -50, + -52, -51, -40, -25, -12, 0, 7, 16, 25, 36, 49, 58, 60, 59, 57, 54, + 49, 43, 36, 31, 26, 18, 13, 10, 6, 4, 0, -6, -12, -19, -22, -26, + -31, -35, -35, -32, -27, -22, -16, -7, 4, 13, 21, 26, 30, 29, 27, 22, + 15, 4, -7, -19, -31, -44, -55, -59, -59, -58, -54, -52, -49, -41, -28, -14, + 0, 10, 18, 26, 33, 44, 50, 53, 51, 50, 48, 46, 41, 37, 30, 24, + 21, 18, 15, 13, 8, 4, 0, -6, -9, -14, -19, -23, -27, -33, -33, -31, + -25, -19, -11, -3, 3, 11, 20, 28, 31, 28, 22, 14, 8, -3, -15, -29, + -40, -49, -57, -62, -60, -56, -50, -47, -42, -32, -18, -3, 11, 20, 25, 29, + 35, 43, 49, 51, 47, 43, 41, 37, 33, 29, 24, 18, 15, 14, 13, 11, + 8, 5, 1, 0, -5, -11, -19, -23, -24, -25, -25, -26, -22, -15, -9, -3, + 4, 12, 19, 25, 26, 24, 17, 11, 2, -11, -26, -37, -45, -53, -58, -59, + -57, -53, -47, -42, -35, -25, -10, 5, 15, 19, 22, 29, 37, 45, 48, 47, + 44, 44, 43, 40, 33, 24, 19, 14, 13, 12, 8, 2, -2, 1, 1, 1, + -4, -12, -15, -14, -13, -14, -18, -18, -15, -12, -8, -5, 2, 10, 18, 21, + 20, 15, 10, 3, -7, -18, -31, -42, -47, -50, -53, -57, -57, -51, -42, -34, + -25, -15, -5, 7, 16, 22, 30, 35, 40, 43, 42, 39, 39, 38, 38, 31, + 22, 16, 14, 15, 17, 16, 12, 6, 4, 5, 7, 6, 0, -8, -12, -13, + -15, -19, -21, -20, -17, -14, -11, -6, 2, 10, 18, 21, 21, 19, 11, -2, + -17, -29, -37, -42, -46, -52, -55, -58, -52, -42, -34, -24, -15, -5, 5, 12, + 17, 24, 32, 37, 37, 36, 33, 33, 35, 35, 32, 26, 22, 16, 17, 19, + 19, 14, 7, 5, 5, 6, 5, 0, -7, -10, -9, -6, -7, -13, -17, -15, + -11, -8, -7, -6, 1, 7, 12, 13, 11, 7, 0, -12, -25, -35, -40, -42, + -43, -44, -47, -49, -43, -34, -22, -12, -7, 0, 4, 9, 17, 25, 31, 33, + 33, 31, 30, 27, 28, 30, 29, 25, 20, 17, 20, 24, 22, 17, 11, 10, + 9, 9, 5, -6, -11, -13, -9, -5, -9, -16, -19, -16, -9, -6, -6, -2, + 4, 8, 11, 11, 6, -4, -11, -21, -34, -39, -41, -40, -38, -40, -44, -38, + -28, -17, -10, -6, -5, -3, 3, 10, 15, 17, 20, 23, 26, 25, 24, 26, + 28, 30, 30, 28, 25, 24, 23, 25, 22, 18, 14, 9, 5, 0, -7, -12, + -13, -12, -7, -6, -9, -12, -10, -4, 2, 2, 3, 3, 3, 6, 7, 3, + -9, -21, -28, -35, -40, -40, -37, -37, -36, -36, -29, -22, -11, -3, 2, 3, + 0, 1, 3, 6, 9, 10, 10, 10, 13, 16, 21, 24, 29, 31, 33, 33, + 33, 32, 30, 27, 23, 16, 12, 7, -2, -7, -14, -19, -16, -10, -5, -7, + -9, -9, -6, 2, 6, 8, 7, 4, 3, 1, -3, -9, -16, -25, -34, -39, + -41, -37, -33, -31, -31, -29, -22, -12, -4, 2, 7, 5, 1, -2, 0, 4, + 4, 2, 2, 5, 10, 14, 19, 24, 28, 32, 36, 38, 36, 34, 31, 27, + 23, 18, 11, 3, -5, -12, -15, -15, -11, -6, -5, -6, -8, -7, -3, 1, + 4, 6, 3, -2, -7, -9, -12, -19, -24, -30, -34, -36, -35, -32, -29, -26, + -22, -16, -10, -3, 4, 8, 9, 4, 0, -3, 0, 1, -5, -7, -5, 1, + 7, 13, 14, 17, 27, 35, 38, 37, 35, 33, 31, 29, 25, 19, 11, 3, + 0, -6, -10, -10, -7, -5, -5, -7, -7, -6, -3, 1, 4, 3, 0, -8, + -15, -18, -20, -23, -27, -30, -32, -33, -29, -28, -25, -20, -16, -13, -6, 1, + 6, 7, 4, 0, -5, -5, -5, -6, -7, -6, -2, 5, 10, 15, 20, 25, + 32, 34, 34, 34, 32, 29, 24, 22, 19, 14, 9, 6, 4, 2, 0, 0, + 2, 2, -2, -4, -6, -5, -5, -4, -4, -7, -12, -19, -25, -26, -26, -26, + -26, -29, -28, -28, -25, -22, -18, -14, -10, -5, 0, 3, 4, 5, 4, 3, + -2, -7, -10, -12, -9, -6, 0, 6, 11, 14, 16, 22, 30, 33, 34, 29, + 25, 23, 21, 22, 22, 20, 18, 16, 14, 13, 11, 11, 11, 6, -4, -12, + -16, -17, -16, -13, -16, -22, -26, -30, -30, -25, -21, -18, -17, -19, -18, -20, + -19, -15, -13, -9, -7, -6, -5, -2, 3, 5, 4, 0, -5, -8, -6, -6, + -6, -2, 4, 9, 11, 13, 15, 19, 23, 25, 22, 19, 16, 17, 20, 21, + 22, 23, 24, 25, 24, 23, 22, 21, 16, 7, -4, -14, -21, -23, -24, -24, + -28, -34, -38, -36, -31, -21, -13, -9, -8, -10, -11, -12, -14, -13, -12, -9, + -10, -12, -11, -9, -4, 3, 4, 1, -3, -4, 1, 4, 7, 10, 10, 11, + 12, 11, 8, 9, 11, 13, 11, 5, 4, 11, 20, 26, 29, 32, 35, 39, + 39, 34, 30, 23, 15, 5, -10, -23, -31, -34, -32, -33, -37, -42, -41, -32, + -21, -11, -6, -3, -3, -6, -8, -11, -14, -15, -14, -14, -14, -19, -20, -15, + -7, 0, -2, -3, 0, 4, 10, 17, 19, 18, 18, 20, 18, 11, 5, 1, + -2, -4, -7, -8, -4, 4, 14, 24, 32, 38, 46, 51, 52, 46, 37, 28, + 19, 5, -12, -29, -39, -44, -46, -46, -50, -48, -39, -29, -14, -4, 6, 9, + 8, 6, 0, -8, -13, -15, -18, -22, -28, -30, -26, -18, -9, -7, -4, 2, + 10, 18, 24, 26, 26, 23, 22, 21, 14, 3, -5, -9, -14, -16, -16, -11, + -4, 6, 14, 24, 37, 50, 58, 58, 53, 45, 36, 28, 17, 1, -18, -36, + -47, -53, -54, -53, -51, -43, -33, -20, -8, 5, 15, 17, 13, 5, -4, -12, + -14, -18, -23, -30, -34, -32, -24, -15, -10, -6, -3, 7, 18, 27, 32, 33, + 30, 28, 24, 19, 12, 2, -10, -18, -24, -26, -23, -16, -6, 4, 12, 25, + 39, 53, 60, 60, 58, 51, 42, 30, 16, 0, -20, -37, -49, -57, -61, -57, + -50, -40, -29, -17, -4, 9, 17, 17, 11, 5, -3, -8, -13, -21, -30, -35, + -34, -29, -22, -16, -11, -6, 1, 12, 24, 34, 39, 39, 35, 28, 21, 16, + 8, -3, -16, -29, -35, -34, -26, -16, -9, 1, 14, 30, 46, 56, 60, 62, + 59, 57, 46, 32, 15, -2, -17, -35, -51, -61, -61, -55, -46, -39, -30, -19, + -4, 10, 14, 13, 7, 3, -2, -6, -15, -24, -31, -33, -31, -26, -23, -19, + -11, -2, 6, 17, 30, 38, 41, 39, 34, 25, 18, 14, 6, -9, -24, -34, + -38, -34, -28, -18, -9, 0, 14, 32, 44, 52, 58, 63, 66, 59, 45, 31, + 18, 4, -17, -36, -53, -60, -59, -54, -46, -39, -30, -18, -3, 6, 8, 6, + 3, 1, -3, -11, -22, -29, -28, -23, -20, -20, -18, -10, -2, 7, 17, 27, + 34, 37, 38, 33, 26, 19, 15, 11, 0, -17, -31, -39, -40, -34, -27, -20, + -11, 1, 16, 31, 43, 52, 59, 67, 70, 62, 47, 32, 19, 4, -18, -39, + -53, -60, -57, -51, -44, -37, -30, -17, -6, 1, 2, 1, 0, -2, -7, -15, + -23, -27, -25, -19, -16, -15, -12, -4, 5, 15, 25, 33, 37, 34, 31, 27, + 22, 17, 11, 2, -11, -25, -35, -41, -41, -34, -23, -13, -4, 6, 18, 31, + 43, 54, 61, 65, 62, 53, 44, 34, 22, 2, -20, -38, -47, -50, -47, -43, + -42, -41, -32, -19, -13, -11, -10, -7, -5, -5, -9, -14, -18, -17, -12, -9, + -8, -6, 1, 6, 12, 16, 21, 25, 25, 23, 19, 18, 14, 11, 8, 0, + -10, -23, -34, -36, -32, -24, -16, -12, -6, 4, 15, 30, 42, 52, 59, 60, + 58, 53, 46, 39, 27, 5, -19, -35, -43, -44, -43, -45, -49, -48, -39, -31, + -27, -24, -19, -11, -6, -3, -4, -6, -8, -5, 3, 5, 7, 6, 7, 9, + 12, 13, 15, 14, 12, 11, 11, 9, 8, 5, 4, 0, -12, -22, -28, -26, + -21, -17, -13, -10, -5, 4, 14, 22, 32, 44, 56, 61, 59, 56, 48, 38, + 25, 7, -10, -24, -33, -38, -44, -50, -51, -47, -41, -41, -41, -37, -26, -14, + -6, 0, -2, -3, 5, 13, 19, 21, 16, 12, 9, 9, 10, 7, 3, 2, + 2, 1, -2, 0, 3, 4, 1, -4, -12, -16, -16, -9, -9, -10, -9, -5, + 2, 7, 11, 17, 27, 39, 51, 54, 52, 52, 49, 42, 28, 10, -4, -15, + -25, -36, -48, -56, -58, -56, -52, -53, -54, -45, -28, -11, -2, 3, 8, 15, + 24, 30, 34, 30, 22, 16, 12, 6, -4, -9, -9, -8, -12, -14, -12, -5, + 3, 4, 2, -3, -4, 0, 3, 2, -4, -6, -6, -5, -4, -5, -3, 8, + 21, 36, 44, 50, 55, 58, 55, 45, 33, 20, 5, -11, -27, -43, -55, -60, + -61, -62, -64, -66, -58, -40, -20, -6, 3, 8, 16, 26, 34, 39, 38, 30, + 21, 11, 2, -9, -14, -13, -13, -15, -16, -14, -6, 1, 4, 4, 3, 4, + 7, 10, 10, 5, -3, -7, -8, -9, -12, -14, -11, 0, 13, 28, 40, 51, + 58, 61, 60, 56, 47, 33, 15, -8, -28, -44, -55, -62, -72, -81, -83, -74, + -58, -39, -21, -6, 8, 18, 30, 40, 47, 49, 44, 33, 19, 6, -6, -14, + -19, -23, -26, -24, -19, -13, -5, -2, 2, 5, 8, 11, 14, 13, 9, 2, + -4, -8, -12, -15, -19, -18, -13, -3, 14, 30, 44, 53, 62, 66, 66, 59, + 48, 33, 12, -10, -31, -46, -58, -71, -79, -84, -81, -71, -54, -34, -14, 1, + 14, 26, 37, 44, 48, 49, 41, 29, 12, -3, -13, -17, -19, -24, -26, -22, + -16, -8, -3, -2, 3, 6, 10, 13, 12, 10, 6, 2, -4, -11, -18, -22, + -22, -19, -14, -3, 13, 30, 46, 61, 68, 71, 70, 64, 52, 32, 10, -12, + -31, -51, -67, -81, -88, -91, -84, -69, -51, -32, -12, 8, 25, 37, 43, 47, + 52, 50, 40, 23, 5, -8, -13, -18, -23, -28, -26, -19, -12, -6, -4, -2, + 2, 6, 11, 11, 5, 3, 4, 1, -9, -17, -21, -23, -22, -19, -14, 0, + 17, 37, 54, 65, 70, 75, 76, 67, 50, 30, 6, -15, -35, -56, -75, -88, + -93, -88, -78, -64, -47, -26, -3, 17, 31, 37, 42, 46, 48, 42, 27, 10, + 0, -3, -7, -14, -21, -21, -13, -4, 1, -2, -3, 1, 5, 7, 4, -3, + -8, -7, -7, -14, -19, -22, -23, -21, -20, -16, -6, 12, 32, 51, 63, 70, + 76, 78, 75, 63, 44, 20, -5, -26, -46, -67, -83, -94, -93, -83, -69, -55, + -40, -17, 8, 25, 34, 38, 43, 48, 45, 35, 20, 8, 2, 3, -2, -12, + -18, -15, -8, 0, 0, -5, -6, -4, -3, -5, -11, -15, -14, -12, -13, -16, + -19, -20, -20, -16, -10, -2, 11, 24, 42, 57, 64, 70, 73, 72, 64, 48, + 26, 4, -15, -35, -50, -68, -81, -88, -81, -68, -55, -44, -29, -10, 9, 22, + 25, 30, 37, 38, 35, 24, 14, 11, 13, 14, 9, 0, -5, -3, 3, 4, + -2, -10, -15, -15, -15, -19, -25, -24, -20, -18, -19, -20, -18, -16, -13, -9, + 1, 12, 25, 37, 53, 63, 69, 74, 73, 69, 56, 37, 15, -6, -25, -42, + -59, -75, -82, -81, -72, -61, -50, -35, -17, -2, 13, 20, 27, 31, 34, 34, + 28, 19, 14, 13, 15, 14, 8, 4, 3, 5, 5, 1, -6, -15, -18, -22, + -27, -33, -34, -31, -25, -24, -20, -19, -17, -10, -2, 9, 18, 28, 39, 51, + 60, 67, 71, 72, 67, 53, 35, 16, -4, -21, -40, -57, -70, -76, -74, -65, + -55, -44, -34, -21, -7, 6, 15, 18, 20, 24, 24, 21, 16, 15, 16, 17, + 17, 16, 13, 12, 13, 13, 9, 0, -12, -17, -22, -31, -40, -43, -40, -35, + -30, -26, -24, -20, -11, -2, 9, 19, 29, 39, 46, 54, 60, 66, 67, 66, + 58, 41, 21, 5, -11, -29, -47, -62, -68, -68, -65, -57, -49, -39, -27, -13, + -2, 6, 11, 18, 23, 24, 21, 19, 19, 21, 21, 18, 15, 11, 13, 15, + 15, 10, -2, -8, -14, -21, -30, -39, -44, -44, -40, -33, -29, -27, -21, -12, + -3, 6, 16, 28, 40, 48, 54, 56, 59, 61, 62, 57, 44, 28, 12, -3, + -22, -40, -55, -64, -63, -61, -56, -51, -41, -29, -15, -6, 1, 8, 15, 20, + 20, 18, 17, 18, 23, 23, 20, 17, 15, 18, 20, 20, 15, 4, -5, -11, + -20, -32, -43, -49, -48, -43, -36, -32, -29, -21, -13, 0, 11, 20, 30, 38, + 46, 50, 51, 53, 56, 53, 48, 41, 30, 19, 5, -10, -26, -42, -50, -56, + -57, -56, -53, -46, -38, -27, -18, -10, -2, 8, 16, 19, 24, 24, 22, 23, + 25, 23, 17, 16, 15, 16, 14, 10, 3, -5, -11, -20, -28, -35, -42, -44, + -42, -35, -29, -25, -19, -11, 0, 10, 20, 26, 31, 38, 45, 48, 46, 46, + 44, 41, 37, 30, 22, 13, 1, -15, -27, -36, -44, -49, -51, -52, -49, -44, + -37, -27, -20, -12, 1, 10, 19, 23, 28, 29, 28, 28, 24, 19, 17, 16, + 15, 14, 10, 4, -3, -10, -15, -23, -31, -36, -41, -41, -39, -32, -24, -19, + -11, -3, 5, 15, 24, 31, 36, 42, 45, 44, 41, 37, 33, 31, 29, 23, + 14, 2, -8, -16, -22, -31, -40, -44, -46, -46, -46, -44, -37, -28, -20, -10, + 2, 11, 20, 28, 32, 32, 29, 26, 22, 19, 17, 14, 12, 11, 8, 2, + -5, -14, -20, -24, -30, -34, -37, -38, -36, -30, -21, -14, -6, 2, 11, 19, + 26, 30, 34, 41, 44, 42, 38, 32, 27, 25, 24, 21, 11, 1, -9, -16, + -25, -34, -40, -43, -45, -48, -50, -49, -40, -27, -15, -6, 4, 15, 27, 36, + 40, 37, 32, 27, 22, 15, 11, 10, 8, 6, 0, -8, -14, -16, -17, -18, + -24, -31, -33, -33, -27, -22, -17, -10, -4, 6, 13, 17, 22, 27, 33, 38, + 39, 37, 35, 33, 31, 27, 23, 19, 11, 3, -7, -20, -30, -38, -42, -42, + -46, -53, -58, -53, -41, -27, -13, -2, 10, 19, 30, 39, 43, 38, 29, 23, + 18, 12, 8, 6, 6, 4, -3, -8, -12, -13, -10, -12, -17, -24, -25, -23, + -23, -23, -19, -12, -4, 2, 5, 9, 14, 22, 32, 37, 39, 39, 37, 37, + 33, 28, 27, 21, 12, 0, -14, -25, -33, -38, -43, -48, -54, -60, -59, -48, + -36, -20, -8, 2, 12, 26, 39, 44, 40, 32, 27, 23, 16, 8, 3, 3, + 2, 1, -4, -9, -9, -6, -6, -8, -13, -16, -18, -21, -22, -21, -16, -7, + -2, 0, -2, 2, 13, 25, 30, 34, 34, 34, 34, 33, 33, 31, 26, 21, + 11, -3, -15, -25, -31, -37, -48, -57, -62, -63, -56, -46, -35, -25, -12, 5, + 18, 32, 40, 40, 36, 32, 29, 22, 15, 7, 3, 0, 0, 0, 1, -2, + -2, 0, 0, -3, -4, -7, -13, -22, -28, -25, -17, -10, -10, -11, -10, -4, + 12, 26, 36, 39, 40, 41, 40, 37, 35, 33, 28, 19, 3, -11, -22, -30, + -37, -46, -56, -63, -65, -59, -52, -43, -29, -17, -4, 10, 23, 32, 36, 36, + 34, 29, 24, 19, 12, 5, -2, 0, 4, 7, 10, 9, 6, 5, 5, 5, + 0, -10, -20, -26, -29, -26, -20, -18, -19, -17, -9, 3, 16, 28, 36, 40, + 42, 43, 41, 40, 36, 33, 26, 16, 3, -10, -21, -31, -42, -53, -61, -65, + -63, -58, -52, -41, -31, -18, -4, 9, 21, 26, 29, 30, 31, 31, 28, 21, + 12, 6, 5, 10, 13, 13, 14, 9, 8, 7, 5, 0, -8, -17, -24, -28, + -27, -23, -17, -14, -12, -8, 2, 15, 26, 32, 36, 39, 38, 37, 36, 33, + 28, 21, 16, 10, 1, -13, -25, -34, -41, -50, -59, -62, -62, -53, -44, -37, + -28, -19, -6, 7, 14, 18, 22, 26, 28, 28, 21, 13, 6, 6, 15, 19, + 21, 20, 20, 18, 16, 13, 7, -3, -12, -21, -27, -31, -30, -24, -15, -11, + -8, 0, 10, 23, 29, 32, 34, 34, 34, 33, 32, 27, 23, 20, 17, 10, + -2, -15, -25, -34, -43, -52, -61, -63, -58, -49, -43, -41, -33, -22, -9, 3, + 11, 17, 21, 26, 30, 28, 23, 17, 15, 18, 22, 22, 20, 21, 21, 18, + 12, 4, -5, -11, -16, -22, -28, -32, -24, -14, -7, -5, 1, 11, 20, 27, + 30, 26, 25, 29, 30, 29, 22, 17, 18, 22, 20, 9, -8, -18, -25, -31, + -40, -53, -60, -58, -54, -46, -45, -42, -32, -20, -10, -2, 5, 12, 19, 25, + 27, 22, 18, 18, 21, 24, 25, 22, 24, 26, 27, 22, 10, 0, -7, -9, + -12, -21, -28, -28, -20, -9, -4, -2, 5, 14, 22, 24, 21, 15, 18, 24, + 28, 24, 19, 21, 26, 30, 22, 7, -6, -15, -23, -34, -50, -61, -66, -61, + -52, -50, -49, -45, -36, -22, -10, 1, 11, 15, 20, 26, 26, 24, 21, 21, + 27, 28, 24, 21, 22, 26, 24, 16, 5, -5, -7, -5, -11, -17, -22, -17, + -7, 0, 1, 4, 9, 16, 19, 18, 13, 12, 16, 22, 24, 23, 23, 28, + 33, 27, 16, 2, -12, -23, -33, -45, -57, -64, -64, -55, -51, -52, -49, -39, + -25, -13, -6, 1, 6, 12, 16, 18, 20, 18, 20, 25, 28, 28, 29, 31, + 36, 37, 28, 15, 7, 3, 0, -4, -14, -21, -23, -16, -7, -4, -3, 1, + 10, 16, 17, 10, 7, 9, 18, 24, 24, 24, 28, 34, 34, 26, 12, -3, + -15, -26, -40, -53, -61, -65, -62, -59, -57, -55, -49, -39, -27, -18, -6, 3, + 8, 14, 17, 21, 25, 26, 27, 28, 30, 32, 32, 31, 32, 28, 22, 14, + 6, 3, 0, -3, -8, -12, -12, -5, 0, 2, 1, 3, 6, 11, 11, 7, + 4, 6, 13, 20, 24, 28, 31, 32, 28, 19, 7, -7, -20, -32, -44, -53, + -58, -58, -55, -54, -53, -50, -46, -40, -27, -14, -6, -6, -5, 0, 8, 16, + 20, 23, 25, 30, 37, 42, 43, 41, 39, 34, 28, 18, 9, 4, 3, 0, + -10, -13, -12, -10, -5, 1, 1, 0, 4, 8, 7, 5, 6, 11, 19, 23, + 27, 32, 33, 27, 20, 10, 0, -15, -30, -41, -49, -52, -54, -55, -55, -53, + -50, -45, -40, -32, -24, -16, -11, -10, -8, -3, 6, 13, 17, 21, 29, 37, + 43, 48, 47, 43, 38, 35, 30, 19, 11, 7, 2, -5, -9, -9, -5, 1, + 1, 0, -2, 1, 3, 6, 5, 4, 5, 10, 16, 20, 24, 27, 25, 18, + 10, 3, -9, -21, -31, -39, -44, -47, -47, -44, -46, -48, -48, -45, -39, -36, + -30, -26, -25, -23, -19, -9, 4, 14, 24, 32, 41, 48, 54, 56, 57, 52, + 47, 40, 28, 17, 10, 4, -3, -8, -10, -8, -6, -5, -5, -5, -3, 0, + 3, 4, 4, 5, 7, 12, 19, 26, 27, 24, 18, 12, 5, -3, -12, -24, + -34, -43, -46, -48, -48, -46, -46, -45, -44, -42, -38, -33, -29, -26, -26, -22, + -14, -5, 5, 13, 23, 32, 40, 47, 52, 56, 57, 55, 52, 47, 36, 27, + 19, 11, 3, -5, -6, -8, -10, -13, -15, -14, -13, -11, -6, 1, 4, 7, + 11, 17, 21, 26, 28, 26, 19, 10, 2, -7, -17, -26, -36, -41, -45, -47, + -45, -44, -44, -41, -39, -40, -40, -37, -33, -34, -32, -26, -18, -9, 2, 12, + 26, 40, 47, 56, 63, 66, 66, 63, 60, 53, 40, 27, 14, 3, -8, -11, + -12, -15, -19, -19, -18, -15, -12, -8, 0, 6, 11, 13, 14, 17, 23, 29, + 27, 18, 9, 1, -7, -16, -25, -35, -43, -49, -47, -44, -43, -42, -40, -36, + -34, -33, -33, -33, -35, -34, -30, -23, -16, -9, 2, 14, 27, 39, 49, 58, + 66, 69, 68, 66, 61, 53, 45, 32, 18, 1, -11, -14, -17, -17, -20, -23, + -21, -17, -13, -3, 4, 10, 13, 14, 17, 18, 21, 24, 22, 15, 6, -4, + -12, -22, -28, -38, -49, -51, -48, -45, -43, -40, -38, -36, -35, -34, -33, -33, + -34, -35, -33, -29, -18, -6, 6, 19, 33, 46, 59, 71, 78, 78, 78, 74, + 67, 54, 39, 22, 6, -8, -16, -22, -25, -25, -26, -22, -17, -12, -3, 6, + 15, 17, 16, 14, 14, 16, 17, 16, 13, 6, -2, -11, -20, -27, -34, -43, + -49, -48, -44, -41, -39, -36, -33, -34, -33, -34, -32, -33, -35, -35, -30, -21, + -11, 0, 9, 23, 38, 52, 65, 74, 76, 76, 74, 70, 62, 47, 28, 13, + 2, -6, -14, -21, -23, -20, -18, -16, -13, -7, 1, 8, 10, 11, 9, 11, + 11, 13, 15, 16, 13, 8, -2, -11, -19, -27, -37, -47, -52, -51, -48, -46, + -43, -40, -38, -36, -35, -35, -38, -38, -33, -27, -21, -16, -7, 6, 21, 36, + 49, 61, 70, 75, 79, 78, 73, 62, 49, 35, 22, 8, -3, -12, -17, -20, + -18, -14, -13, -15, -12, -5, 4, 7, 8, 8, 9, 8, 9, 11, 14, 14, + 10, 4, -6, -15, -25, -35, -41, -48, -54, -53, -47, -42, -38, -37, -35, -31, + -31, -30, -30, -29, -26, -24, -19, -12, -2, 10, 22, 35, 48, 60, 70, 76, + 76, 73, 67, 57, 44, 28, 14, 5, -3, -8, -13, -14, -13, -10, -11, -11, + -8, -2, 4, 6, 5, 5, 5, 6, 10, 11, 10, 8, 4, -2, -9, -15, + -24, -35, -44, -50, -52, -49, -45, -42, -42, -40, -37, -37, -37, -33, -29, -26, + -24, -21, -16, -7, 6, 18, 30, 41, 54, 66, 75, 77, 79, 76, 67, 53, + 37, 21, 8, 2, -5, -10, -14, -14, -12, -12, -11, -10, -5, 4, 7, 4, + 1, 2, 6, 9, 9, 7, 5, 4, 0, -7, -14, -23, -32, -37, -43, -48, + -50, -51, -47, -42, -34, -32, -32, -34, -32, -26, -21, -18, -17, -14, -11, -4, + 5, 13, 24, 40, 55, 67, 72, 74, 76, 75, 67, 51, 37, 23, 11, 4, + -4, -11, -15, -17, -17, -16, -14, -13, -8, -2, 1, 1, 1, 3, 5, 9, + 7, 5, 4, 4, 3, -5, -14, -24, -32, -38, -41, -47, -52, -53, -49, -41, + -35, -34, -35, -33, -29, -24, -19, -13, -10, -9, -7, -2, 8, 17, 29, 43, + 56, 67, 74, 75, 75, 72, 64, 53, 38, 23, 13, 4, -5, -12, -16, -20, + -21, -18, -16, -14, -11, -8, -5, -3, 0, 2, 6, 6, 6, 5, 5, 6, + 3, -6, -19, -31, -37, -41, -45, -50, -52, -53, -48, -39, -32, -30, -26, -25, + -22, -16, -10, -7, -11, -10, -8, -2, 6, 17, 31, 45, 58, 68, 78, 80, + 76, 70, 65, 55, 37, 18, 5, -4, -10, -19, -25, -26, -24, -18, -13, -11, + -9, -6, -2, 4, 6, 5, 4, 3, 4, 2, 1, -3, -4, -11, -20, -29, + -38, -43, -45, -48, -51, -48, -44, -39, -35, -34, -31, -30, -25, -15, -8, -8, + -10, -8, 1, 11, 22, 33, 42, 54, 66, 76, 80, 75, 70, 66, 59, 42, + 23, 6, -4, -9, -17, -22, -27, -25, -19, -9, -7, -8, -5, 0, 4, 5, + 2, -2, -5, -5, -4, -6, -7, -6, -10, -16, -21, -29, -34, -37, -38, -41, + -44, -42, -36, -32, -33, -37, -39, -35, -27, -17, -12, -13, -12, -6, 6, 22, + 36, 44, 54, 66, 77, 82, 80, 75, 68, 59, 47, 29, 10, -3, -13, -18, + -23, -26, -27, -24, -16, -9, -5, -4, -2, 3, 6, 4, -2, -6, -8, -7, + -8, -8, -9, -10, -13, -16, -22, -29, -31, -30, -34, -36, -36, -32, -28, -30, + -36, -39, -38, -33, -28, -24, -24, -22, -15, -2, 13, 26, 38, 53, 67, 78, + 84, 88, 85, 81, 71, 59, 39, 13, -5, -14, -19, -26, -32, -34, -30, -22, + -13, -5, 0, 6, 7, 10, 8, 2, -4, -10, -12, -15, -18, -20, -20, -20, + -22, -24, -26, -26, -23, -23, -23, -24, -21, -17, -18, -25, -31, -35, -37, -37, + -36, -33, -29, -22, -10, 5, 19, 31, 45, 62, 75, 84, 86, 88, 87, 80, + 66, 45, 22, 4, -9, -18, -26, -34, -37, -33, -24, -15, -9, -3, 6, 13, + 15, 11, 2, -5, -10, -13, -20, -25, -27, -26, -25, -26, -29, -29, -23, -18, + -16, -19, -18, -15, -9, -6, -12, -21, -32, -36, -36, -40, -39, -36, -30, -21, + -10, 6, 20, 36, 55, 69, 79, 85, 90, 92, 88, 75, 56, 33, 12, -3, + -15, -24, -33, -37, -35, -28, -20, -12, -4, 6, 14, 18, 16, 9, 0, -8, + -15, -19, -27, -33, -35, -34, -34, -36, -36, -29, -19, -10, -10, -10, -8, -4, + -2, -2, -8, -18, -28, -36, -43, -48, -46, -36, -25, -14, -4, 10, 27, 46, + 65, 78, 86, 89, 87, 85, 78, 64, 42, 19, 0, -12, -20, -29, -34, -36, + -30, -22, -12, -6, 1, 8, 16, 18, 13, 2, -7, -12, -17, -24, -33, -38, + -39, -36, -36, -36, -34, -26, -18, -11, -7, -6, -5, -5, 1, 1, -5, -14, + -24, -33, -41, -42, -37, -28, -19, -10, 3, 16, 30, 47, 64, 76, 83, 85, + 83, 78, 69, 54, 37, 17, -2, -14, -21, -28, -32, -32, -27, -18, -11, -6, + 2, 12, 18, 16, 5, -5, -11, -14, -19, -30, -40, -47, -45, -38, -36, -34, + -33, -26, -15, -6, -2, 1, 1, 3, 5, 4, -3, -13, -26, -35, -41, -39, + -33, -23, -13, -5, 7, 21, 36, 53, 68, 79, 82, 78, 72, 66, 59, 47, + 30, 10, -6, -16, -21, -22, -25, -27, -25, -18, -10, -4, 4, 10, 11, 6, + -4, -11, -13, -18, -25, -34, -43, -45, -41, -36, -34, -32, -27, -19, -10, -5, + 0, 2, 5, 5, 5, 1, -7, -16, -25, -33, -38, -35, -25, -13, -6, 0, + 11, 27, 46, 60, 69, 70, 68, 69, 68, 62, 52, 39, 22, 8, -2, -11, + -18, -21, -22, -23, -24, -17, -10, -5, 1, 5, 5, 2, -3, -5, -9, -17, + -28, -41, -46, -48, -43, -42, -42, -39, -30, -19, -9, -3, 6, 11, 15, 16, + 12, 5, -2, -12, -23, -33, -37, -34, -25, -18, -8, 1, 15, 32, 48, 62, + 69, 68, 67, 63, 62, 58, 50, 34, 15, -2, -8, -10, -11, -16, -24, -24, + -19, -12, -6, -2, 2, 3, 1, 0, -6, -10, -17, -26, -37, -46, -48, -45, + -44, -42, -38, -32, -22, -12, -6, 4, 10, 14, 16, 15, 11, 5, -2, -11, + -23, -31, -29, -22, -18, -16, -11, 3, 17, 34, 50, 56, 59, 61, 63, 62, + 59, 53, 44, 32, 16, 3, -8, -9, -13, -20, -26, -27, -21, -16, -11, -9, + -6, 1, 7, 7, 0, -10, -15, -20, -30, -39, -45, -48, -48, -46, -41, -36, + -29, -20, -11, 3, 11, 14, 19, 21, 19, 15, 6, -3, -13, -18, -18, -17, + -20, -19, -12, 2, 15, 26, 36, 43, 51, 59, 61, 61, 57, 54, 49, 37, + 21, 9, 1, -8, -17, -25, -29, -28, -27, -23, -19, -13, -5, 2, 8, 5, + -4, -11, -13, -17, -27, -40, -49, -53, -53, -50, -44, -37, -28, -19, -7, 8, + 18, 22, 26, 26, 23, 17, 10, 0, -8, -15, -20, -25, -23, -19, -11, 0, + 13, 25, 34, 44, 54, 60, 62, 60, 58, 56, 52, 38, 21, 6, -6, -16, + -26, -32, -33, -30, -26, -24, -17, -8, 3, 13, 16, 10, 1, -7, -12, -18, + -34, -50, -61, -63, -58, -54, -50, -45, -33, -13, 6, 21, 27, 34, 37, 36, + 30, 20, 11, -2, -13, -24, -32, -37, -34, -24, -10, 2, 12, 25, 41, 55, + 61, 64, 65, 67, 64, 59, 48, 32, 16, 0, -12, -20, -27, -33, -33, -31, + -28, -23, -12, 0, 10, 13, 9, 2, -2, -7, -13, -25, -41, -56, -65, -66, + -62, -56, -53, -42, -25, -5, 13, 24, 34, 39, 42, 39, 32, 22, 11, -2, + -15, -27, -36, -37, -31, -22, -13, 0, 12, 27, 43, 55, 61, 64, 65, 63, + 60, 53, 42, 28, 10, -6, -20, -27, -28, -28, -25, -23, -20, -13, -2, 11, + 16, 14, 8, 2, -6, -14, -25, -38, -53, -67, -73, -73, -67, -58, -46, -32, + -14, 6, 24, 36, 43, 45, 44, 39, 30, 18, 5, -11, -25, -35, -39, -37, + -28, -17, -7, 4, 16, 32, 48, 58, 64, 66, 63, 61, 56, 46, 31, 18, + 3, -13, -21, -25, -23, -19, -15, -11, -7, -2, 6, 13, 14, 8, -3, -12, + -21, -32, -40, -55, -70, -78, -75, -67, -56, -47, -29, -12, 10, 29, 40, 47, + 49, 48, 43, 31, 15, 0, -16, -29, -39, -45, -41, -32, -18, -6, 3, 13, + 27, 43, 57, 64, 65, 61, 58, 52, 43, 32, 18, 6, -9, -18, -20, -17, + -12, -4, 1, 3, 7, 12, 17, 16, 9, -3, -15, -27, -39, -48, -60, -72, + -82, -82, -73, -58, -45, -33, -14, 7, 28, 42, 49, 51, 51, 48, 38, 22, + 2, -16, -30, -37, -42, -45, -40, -26, -11, 3, 11, 20, 34, 52, 65, 69, + 64, 54, 46, 38, 28, 16, 4, -11, -18, -16, -10, -4, 3, 13, 21, 23, + 22, 20, 18, 11, -2, -16, -34, -47, -59, -70, -76, -83, -83, -76, -64, -48, + -31, -12, 10, 30, 42, 50, 53, 51, 46, 37, 25, 8, -13, -30, -41, -45, + -43, -35, -23, -15, -5, 8, 17, 28, 40, 56, 64, 63, 55, 45, 34, 24, + 14, 7, -4, -12, -13, -9, -2, 11, 23, 31, 33, 33, 31, 26, 17, 4, + -14, -31, -48, -62, -75, -86, -90, -87, -79, -68, -54, -39, -18, 4, 23, 39, + 47, 52, 52, 47, 39, 29, 15, -5, -23, -35, -41, -40, -34, -26, -16, -8, + 2, 12, 22, 30, 43, 52, 58, 54, 45, 36, 25, 16, 7, -2, -7, -8, + -3, 4, 13, 24, 32, 39, 42, 39, 30, 19, 6, -10, -25, -44, -62, -79, + -88, -90, -85, -78, -70, -59, -45, -24, 0, 20, 35, 43, 48, 48, 46, 42, + 33, 20, 2, -19, -32, -38, -41, -37, -29, -19, -8, 1, 11, 19, 26, 35, + 43, 48, 48, 41, 35, 26, 16, 7, 0, 0, 3, 6, 10, 16, 24, 32, + 40, 44, 43, 33, 21, 8, -5, -19, -37, -54, -72, -84, -87, -81, -75, -68, + -61, -50, -33, -12, 8, 22, 29, 34, 40, 42, 41, 35, 24, 13, -2, -16, + -27, -33, -33, -27, -22, -17, -13, -4, 9, 18, 25, 31, 36, 42, 44, 40, + 32, 21, 12, 9, 7, 8, 9, 13, 17, 23, 29, 35, 40, 40, 35, 26, + 13, 0, -11, -24, -41, -60, -74, -80, -79, -73, -68, -63, -56, -43, -27, -10, + 6, 18, 24, 29, 34, 38, 37, 30, 20, 9, -3, -14, -24, -27, -27, -25, + -23, -18, -9, 2, 10, 19, 25, 30, 37, 40, 41, 33, 22, 16, 10, 6, + 6, 10, 16, 21, 28, 31, 35, 38, 44, 45, 34, 19, 5, -5, -17, -33, + -52, -68, -76, -78, -75, -71, -67, -62, -51, -37, -20, -7, 4, 13, 21, 29, + 34, 36, 33, 26, 17, 10, 0, -8, -13, -19, -21, -21, -17, -11, -6, 4, + 10, 13, 19, 25, 30, 31, 28, 20, 14, 10, 7, 7, 11, 20, 26, 32, + 36, 39, 41, 44, 46, 41, 30, 13, 0, -13, -27, -44, -62, -72, -74, -74, + -74, -71, -66, -57, -47, -32, -19, -9, 2, 14, 24, 28, 32, 34, 33, 25, + 17, 9, 2, -5, -10, -17, -22, -18, -13, -7, 0, 4, 10, 17, 23, 26, + 25, 21, 15, 9, 9, 7, 4, 7, 16, 27, 34, 39, 43, 48, 49, 52, + 49, 39, 24, 9, -3, -17, -32, -52, -67, -75, -75, -71, -70, -70, -66, -56, + -43, -31, -21, -12, -2, 11, 21, 27, 30, 33, 31, 29, 22, 15, 8, 0, + -6, -13, -14, -14, -11, -5, 0, 4, 8, 13, 16, 18, 15, 12, 10, 7, + 7, 6, 7, 14, 24, 36, 44, 46, 46, 49, 52, 53, 47, 35, 21, 9, + -6, -23, -43, -59, -68, -71, -74, -74, -76, -73, -64, -52, -39, -31, -25, -15, + 0, 12, 20, 24, 29, 32, 30, 26, 21, 16, 10, 4, -2, -7, -7, -5, + -3, 0, 3, 5, 6, 9, 8, 8, 6, 3, 2, 4, 5, 7, 14, 22, + 34, 43, 49, 57, 57, 55, 52, 48, 43, 31, 17, 2, -13, -33, -49, -59, + -63, -66, -72, -75, -76, -70, -61, -52, -44, -37, -30, -18, -4, 11, 20, 25, + 28, 32, 32, 30, 26, 19, 13, 5, 0, -4, -5, -3, 1, 2, 1, -3, + -2, 2, 6, 4, 2, -3, -2, 3, 10, 13, 18, 27, 40, 49, 56, 59, + 60, 56, 52, 47, 41, 30, 17, 1, -19, -39, -55, -64, -67, -70, -76, -81, + -78, -69, -56, -46, -40, -33, -24, -12, 3, 15, 22, 25, 26, 29, 27, 23, + 19, 14, 9, 4, 0, -2, 1, 5, 9, 7, 2, -3, -3, 3, 3, -2, + -10, -13, -10, -2, 7, 14, 22, 31, 45, 59, 65, 68, 65, 62, 58, 50, + 41, 28, 12, -9, -31, -49, -59, -65, -70, -76, -84, -84, -77, -63, -50, -45, + -40, -32, -21, -7, 7, 16, 24, 28, 29, 28, 23, 18, 15, 11, 6, 0, + -4, -3, 4, 11, 14, 11, 6, 5, 7, 7, 2, -7, -12, -16, -13, -6, + 1, 8, 17, 32, 50, 63, 68, 68, 69, 70, 65, 56, 43, 27, 7, -17, + -38, -52, -62, -71, -78, -86, -88, -84, -73, -59, -50, -43, -34, -25, -11, 2, + 11, 19, 23, 26, 26, 21, 17, 12, 9, 7, 5, 2, 2, 4, 11, 16, + 14, 10, 9, 10, 9, 1, -8, -16, -19, -16, -11, -6, 0, 8, 24, 43, + 57, 66, 70, 72, 72, 67, 63, 52, 37, 18, -5, -23, -41, -54, -62, -70, + -78, -81, -82, -76, -67, -56, -45, -36, -31, -22, -12, 0, 10, 16, 20, 21, + 17, 13, 7, 3, 3, 6, 6, 6, 9, 14, 20, 21, 20, 17, 17, 15, + 9, -3, -15, -23, -27, -20, -14, -9, -4, 9, 31, 49, 64, 70, 75, 78, + 76, 70, 60, 45, 31, 12, -11, -31, -46, -58, -66, -70, -73, -77, -74, -67, + -59, -52, -44, -36, -29, -22, -14, -6, 1, 11, 14, 14, 11, 6, 6, 7, + 10, 11, 12, 15, 18, 24, 23, 21, 19, 20, 18, 12, 0, -13, -20, -27, + -27, -22, -16, -11, 1, 19, 36, 52, 64, 73, 79, 81, 77, 69, 56, 43, + 26, 5, -16, -37, -54, -62, -66, -69, -72, -71, -65, -62, -56, -47, -39, -33, + -26, -19, -14, -12, -3, 9, 9, 3, -6, -4, 5, 11, 12, 11, 12, 20, + 29, 31, 29, 25, 25, 27, 24, 11, -6, -17, -25, -31, -32, -30, -26, -16, + 0, 17, 35, 51, 66, 78, 87, 88, 84, 73, 57, 40, 23, 3, -20, -42, + -57, -65, -69, -71, -70, -68, -63, -58, -52, -45, -38, -30, -26, -24, -23, -16, + -8, -2, -5, -9, -6, 1, 9, 12, 13, 17, 24, 32, 37, 37, 34, 32, + 33, 31, 19, 2, -15, -25, -31, -36, -38, -35, -27, -13, 4, 23, 40, 59, + 76, 91, 96, 91, 80, 69, 55, 35, 13, -12, -35, -52, -61, -66, -71, -70, + -63, -54, -48, -44, -42, -36, -31, -30, -34, -36, -33, -26, -20, -20, -21, -18, + -9, 5, 13, 18, 21, 29, 40, 47, 50, 49, 44, 40, 34, 23, 6, -14, + -27, -39, -45, -48, -45, -35, -23, -7, 11, 30, 51, 73, 89, 97, 96, 89, + 80, 63, 44, 25, 4, -18, -39, -53, -59, -63, -61, -58, -55, -52, -49, -45, + -39, -35, -37, -41, -46, -43, -38, -33, -29, -25, -18, -11, 3, 13, 20, 25, + 30, 38, 46, 51, 50, 47, 43, 37, 26, 9, -7, -19, -32, -45, -52, -51, + -40, -28, -12, 4, 19, 38, 61, 83, 94, 95, 89, 82, 67, 50, 30, 12, + -8, -26, -40, -52, -57, -56, -52, -48, -46, -44, -40, -34, -32, -32, -37, -44, + -47, -45, -41, -39, -35, -28, -17, -6, 7, 15, 23, 32, 40, 47, 52, 52, + 51, 46, 39, 32, 17, 1, -14, -26, -37, -46, -50, -45, -35, -25, -11, 5, + 24, 44, 62, 79, 88, 86, 79, 70, 59, 45, 25, 7, -13, -25, -36, -46, + -50, -51, -50, -46, -43, -41, -37, -34, -33, -36, -40, -43, -46, -46, -41, -36, + -31, -22, -10, 4, 13, 21, 30, 40, 47, 50, 53, 52, 47, 39, 30, 18, + 3, -12, -22, -33, -42, -47, -45, -36, -25, -14, -2, 14, 34, 52, 67, 76, + 77, 72, 65, 55, 43, 27, 12, -7, -21, -29, -36, -41, -44, -43, -39, -36, + -32, -27, -26, -26, -29, -33, -36, -43, -49, -48, -44, -38, -32, -22, -11, 4, + 15, 25, 34, 44, 50, 53, 54, 52, 44, 35, 23, 9, -4, -15, -27, -37, + -43, -45, -42, -34, -21, -9, 5, 19, 34, 50, 63, 70, 69, 63, 54, 46, + 35, 20, 4, -11, -23, -29, -33, -37, -41, -40, -33, -25, -20, -19, -21, -22, + -23, -26, -34, -42, -47, -46, -43, -36, -30, -22, -11, 5, 17, 28, 37, 45, + 52, 55, 53, 49, 41, 30, 19, 4, -12, -23, -33, -41, -45, -45, -40, -31, + -18, -3, 11, 23, 38, 51, 63, 64, 58, 51, 45, 36, 25, 10, -4, -15, + -24, -28, -32, -36, -35, -29, -19, -13, -13, -14, -13, -13, -13, -21, -33, -43, + -45, -45, -41, -38, -34, -25, -11, 4, 17, 29, 39, 49, 57, 60, 55, 48, + 39, 29, 16, 1, -14, -27, -35, -42, -47, -48, -42, -29, -15, -3, 10, 20, + 34, 48, 56, 57, 51, 45, 38, 30, 20, 7, -7, -17, -22, -26, -32, -36, + -31, -21, -9, -6, -8, -8, -4, 1, -4, -13, -26, -35, -39, -40, -42, -44, + -40, -29, -13, 3, 16, 29, 43, 58, 67, 67, 59, 49, 39, 27, 11, -9, + -28, -39, -47, -50, -53, -52, -44, -29, -12, 5, 13, 25, 38, 51, 57, 52, + 45, 38, 30, 21, 9, -4, -14, -21, -26, -29, -33, -28, -18, -7, 2, 2, + 2, 4, 8, 10, 5, -10, -25, -36, -42, -45, -49, -49, -45, -33, -14, 5, + 22, 35, 54, 69, 78, 76, 67, 53, 41, 27, 6, -17, -36, -50, -55, -60, + -63, -62, -51, -34, -16, -2, 9, 20, 34, 45, 50, 48, 42, 35, 29, 18, + 7, 0, 0, 0, 0, 0, 0, 7, 0, -1, -7, -18, -16, 3, 6, -18, + -29, -21, 6, 6, -12, -10, -10, -2, 4, 15, 21, 14, 4, 9, 29, 27, + 15, 9, 13, 20, 0, -21, -11, 3, -11, -37, -36, -7, 11, -4, -26, -23, + -4, 15, -4, -15, -11, -10, -1, 9, 23, 15, 8, 6, 24, 35, 19, 14, + 6, 17, 10, -15, -26, -7, -1, -23, -40, -24, 4, 10, -16, -25, -13, 11, + 10, -14, -15, -12, -6, 1, 19, 22, 6, 7, 15, 40, 31, 22, 7, 7, + 15, 5, -22, -21, -5, -9, -33, -32, -15, 5, -4, -19, -20, 1, 17, -4, + -15, -11, -12, -4, 9, 27, 13, 7, 11, 32, 44, 30, 14, 2, 7, 9, + -8, -25, -18, -9, -19, -30, -21, -4, 2, -10, -21, -13, 15, 8, -11, -13, + -16, -12, 0, 20, 24, 9, 9, 19, 44, 47, 25, 6, 2, 11, -1, -21, + -27, -19, -17, -20, -23, -17, -5, -5, -14, -20, 0, 15, -4, -7, -17, -17, + -8, 7, 25, 18, 7, 11, 31, 54, 41, 14, -1, 10, 3, -14, -27, -29, + -21, -16, -16, -18, -17, -11, -10, -16, -16, 10, 6, -3, -9, -19, -16, -2, + 18, 27, 16, 8, 19, 45, 54, 29, 5, 6, 4, -9, -18, -29, -30, -18, + -10, -9, -14, -20, -12, -13, -17, -5, 12, 7, 2, -16, -22, -13, 8, 25, + 23, 12, 11, 32, 53, 48, 17, 9, 9, -7, -16, -24, -37, -28, -12, -4, + -2, -18, -21, -18, -23, -17, 7, 11, 10, -4, -16, -22, -7, 21, 28, 18, + 9, 20, 43, 55, 37, 11, 11, 1, -14, -17, -31, -34, -21, -10, 4, -2, + -20, -23, -26, -29, -3, 6, 13, 8, -5, -23, -27, 7, 28, 27, 15, 12, + 32, 48, 50, 24, 9, 8, -12, -19, -26, -37, -35, -19, 3, 6, -12, -21, + -31, -38, -17, 6, 4, 14, 6, -8, -35, -15, 19, 26, 21, 7, 23, 43, + 52, 42, 14, 9, -2, -16, -21, -25, -33, -33, -4, 13, 3, -13, -30, -47, + -37, 1, 6, 7, 12, 6, -15, -31, -1, 22, 30, 14, 9, 37, 48, 50, + 26, 8, 6, -11, -22, -22, -25, -45, -22, 13, 15, 1, -22, -43, -56, -21, + 7, 6, 10, 15, -7, -25, -21, 7, 28, 21, 2, 25, 47, 53, 39, 11, + 10, 1, -20, -22, -18, -37, -42, 2, 15, 15, -8, -32, -57, -48, -9, 9, + 5, 14, 8, -14, -20, -13, 17, 33, 8, 9, 37, 52, 55, 25, 7, 8, + -11, -23, -15, -23, -47, -20, 12, 21, 10, -23, -50, -57, -31, 2, 10, 9, + 11, -8, -10, -18, -3, 30, 22, 1, 22, 45, 57, 45, 11, 11, 0, -23, + -22, -16, -36, -36, -6, 15, 18, -3, -43, -56, -49, -21, 5, 11, 12, -2, + -8, -9, -15, 12, 31, 9, 10, 34, 48, 60, 29, 16, 10, -17, -24, -21, + -27, -31, -17, 5, 14, 12, -22, -50, -48, -41, -9, 7, 13, -1, -8, -2, + -11, -5, 26, 19, 6, 21, 37, 55, 49, 25, 22, -5, -20, -24, -26, -29, + -23, -9, 8, 13, -1, -41, -48, -47, -30, -3, 12, 7, -12, -2, 1, -8, + 10, 20, 11, 16, 26, 40, 54, 42, 36, 7, -13, -18, -26, -29, -26, -14, + -2, 7, 8, -18, -45, -48, -45, -19, 6, 11, -10, -8, 5, -7, 2, 12, + 17, 15, 16, 23, 45, 55, 48, 27, -7, -12, -18, -30, -31, -17, -5, -3, + 4, 5, -24, -40, -50, -38, -8, 8, 1, -13, 1, -1, 3, 8, 15, 18, + 15, 15, 28, 52, 59, 47, 9, -9, -10, -25, -40, -29, -3, -5, -13, 1, + 3, -26, -47, -53, -23, -2, 5, -11, -6, 4, 6, 10, 10, 19, 11, 13, + 15, 42, 61, 61, 32, 3, -5, -12, -35, -43, -14, 1, -16, -13, 9, -1, + -33, -57, -46, -19, -3, -1, -16, -2, 5, 15, 6, 17, 9, 5, 9, 26, + 54, 65, 52, 21, 3, -6, -21, -48, -33, -4, -7, -22, -2, 18, -4, -47, + -58, -33, -11, 2, -13, -15, 3, 16, 15, 9, 15, -1, 5, 14, 48, 66, + 65, 37, 23, 2, -11, -42, -48, -20, -4, -23, -18, 18, 19, -17, -61, -52, + -27, -2, -5, -24, -7, 9, 20, 14, 18, 2, -3, 7, 34, 63, 68, 50, + 37, 19, -9, -25, -49, -38, -14, -14, -28, 6, 25, 9, -40, -62, -45, -17, + 3, -21, -16, -3, 12, 18, 18, 10, -6, 0, 16, 56, 69, 63, 43, 38, + 2, -20, -42, -44, -33, -14, -25, -10, 22, 18, -11, -55, -57, -37, -3, -10, + -26, -10, 2, 17, 21, 20, -3, -2, 5, 39, 67, 73, 56, 47, 22, -17, + -35, -43, -36, -28, -18, -20, 9, 22, 8, -33, -56, -53, -26, -2, -23, -24, + -11, 4, 23, 30, 4, -3, 0, 27, 60, 71, 69, 58, 43, -6, -35, -43, + -35, -36, -27, -18, -2, 19, 17, -9, -41, -51, -45, -10, -12, -31, -21, -9, + 8, 33, 17, 0, 2, 8, 50, 69, 75, 70, 64, 16, -31, -47, -35, -32, + -34, -25, -14, 10, 16, 5, -26, -42, -50, -32, -8, -22, -31, -22, -8, 22, + 32, 7, 6, 4, 28, 63, 69, 71, 78, 43, -20, -51, -41, -23, -34, -30, + -22, 2, 13, 9, -10, -31, -45, -44, -21, -19, -27, -36, -26, 2, 29, 24, + 12, 11, 13, 45, 69, 68, 81, 70, 6, -47, -52, -28, -23, -27, -26, -14, + 11, 10, -2, -18, -33, -43, -34, -25, -22, -36, -44, -14, 14, 29, 27, 22, + 18, 29, 60, 65, 71, 86, 41, -32, -57, -41, -23, -22, -22, -24, -4, 10, + 0, -11, -21, -31, -37, -37, -29, -29, -53, -33, -3, 16, 33, 31, 27, 23, + 46, 64, 65, 85, 71, -4, -48, -47, -31, -20, -15, -15, -19, 1, 0, -5, + -14, -21, -26, -40, -39, -28, -51, -50, -18, 4, 26, 38, 36, 30, 32, 61, + 64, 70, 80, 31, -35, -43, -40, -25, -19, -6, -17, -11, 0, -6, -11, -17, + -15, -31, -47, -39, -45, -62, -34, -8, 12, 36, 38, 41, 37, 51, 65, 60, + 71, 56, -7, -36, -38, -35, -27, -11, -5, -17, -8, -8, -9, -17, -13, -20, + -37, -47, -50, -62, -49, -16, 1, 25, 34, 43, 53, 49, 62, 58, 62, 65, + 22, -23, -31, -34, -35, -19, -3, -8, -18, -7, -4, -14, -17, -9, -27, -40, + -56, -68, -64, -27, -4, 9, 28, 37, 54, 60, 61, 59, 54, 63, 43, -1, + -25, -23, -37, -28, -8, 4, -10, -15, -3, -7, -26, -15, -11, -29, -51, -71, + -71, -49, -8, 5, 14, 30, 48, 66, 68, 63, 51, 56, 51, 18, -18, -20, + -25, -39, -23, -5, 3, -13, -6, -5, -21, -28, -10, -18, -43, -67, -78, -64, + -25, 1, 8, 15, 38, 60, 75, 74, 58, 54, 57, 28, -7, -18, -8, -31, + -34, -15, 4, -2, -4, 0, -15, -32, -21, -8, -28, -57, -77, -75, -44, -12, + 6, 8, 20, 49, 68, 77, 71, 53, 61, 41, 3, -18, -4, -14, -36, -28, + -7, 1, 7, 6, -8, -34, -35, -16, -15, -41, -66, -75, -59, -31, -4, 10, + 11, 31, 56, 72, 85, 63, 58, 55, 14, -17, -10, -1, -24, -30, -22, -6, + 11, 16, 9, -27, -43, -27, -15, -26, -53, -63, -66, -46, -21, 3, 13, 15, + 40, 63, 83, 78, 60, 67, 38, -9, -20, 4, -7, -23, -25, -22, 6, 24, + 20, -8, -48, -43, -24, -16, -39, -55, -57, -57, -36, -10, 9, 11, 22, 50, + 73, 88, 71, 65, 59, 14, -24, -9, -3, -15, -18, -31, -14, 25, 28, 10, + -36, -56, -41, -21, -29, -48, -47, -51, -50, -26, -2, 11, 6, 30, 57, 82, + 83, 69, 65, 35, -12, -16, -3, -10, -12, -21, -26, 11, 33, 26, -7, -56, + -54, -32, -26, -41, -39, -37, -52, -41, -16, 5, 7, 11, 37, 72, 91, 78, + 66, 55, 11, -19, -14, -15, -9, -7, -19, -8, 22, 30, 13, -32, -62, -44, + -31, -34, -40, -29, -40, -46, -29, -8, 2, 1, 18, 49, 84, 86, 72, 67, + 39, -6, -21, -25, -16, 2, -6, -12, 6, 23, 18, -7, -51, -56, -39, -33, + -41, -30, -24, -41, -36, -17, -8, -5, 7, 32, 66, 84, 78, 75, 58, 20, + -15, -29, -33, 2, 4, -1, 1, 11, 17, 4, -27, -56, -46, -36, -37, -39, + -22, -24, -38, -23, -16, -16, -7, 18, 46, 72, 82, 81, 72, 44, -1, -25, + -41, -18, 14, 8, 10, 0, 5, 2, -11, -40, -50, -42, -38, -37, -33, -11, + -27, -26, -20, -22, -13, 0, 31, 52, 73, 82, 80, 61, 26, -16, -37, -40, + 0, 18, 17, 12, -5, -8, -10, -21, -41, -43, -44, -36, -35, -20, -12, -23, + -14, -32, -21, -12, 15, 38, 58, 76, 82, 72, 46, 4, -26, -41, -23, 14, + 25, 18, 2, -23, -18, -14, -29, -35, -45, -42, -35, -29, -15, -19, -3, -23, + -32, -19, -1, 27, 40, 67, 81, 76, 61, 26, -11, -33, -36, -6, 28, 28, + 13, -15, -38, -19, -20, -26, -36, -46, -35, -32, -20, -21, -4, -4, -28, -25, + -16, 13, 31, 49, 74, 79, 69, 48, 8, -16, -33, -21, 7, 33, 24, 5, + -32, -38, -22, -21, -22, -41, -43, -32, -25, -23, -16, 6, -9, -29, -28, -5, + 20, 39, 58, 75, 71, 60, 22, 0, -18, -27, -10, 16, 30, 15, -14, -49, + -34, -19, -16, -27, -43, -31, -25, -27, -24, -1, 7, -15, -32, -22, 3, 28, + 50, 61, 67, 59, 38, 13, 5, -17, -16, -3, 21, 23, 3, -34, -49, -28, + -17, -19, -34, -34, -18, -26, -32, -16, 14, 6, -23, -34, -11, 14, 44, 54, + 56, 60, 44, 25, 18, 2, -18, -9, 3, 21, 9, -14, -45, -39, -24, -22, + -28, -32, -18, -17, -36, -30, 5, 21, -5, -31, -27, 1, 30, 56, 46, 50, + 47, 32, 29, 20, -4, -9, -9, 4, 10, -2, -28, -38, -31, -33, -26, -26, + -19, -9, -24, -38, -11, 24, 10, -17, -36, -14, 14, 48, 49, 37, 43, 39, + 33, 32, 11, 1, -5, -11, -6, -3, -16, -29, -28, -40, -38, -27, -20, -6, + -11, -31, -29, 15, 22, 0, -25, -25, 2, 31, 51, 38, 35, 41, 41, 34, + 27, 8, 6, -7, -20, -14, -7, -20, -19, -34, -52, -35, -23, -11, -5, -18, + -33, -5, 26, 5, -11, -27, -11, 17, 43, 43, 30, 29, 46, 45, 38, 17, + 6, 2, -22, -27, -16, -16, -18, -18, -53, -48, -23, -19, -3, -10, -21, -19, + 18, 12, -6, -20, -21, 6, 29, 42, 31, 23, 37, 54, 48, 31, 13, 13, + -13, -31, -25, -16, -16, -11, -38, -62, -33, -28, -7, -3, -12, -17, 6, 16, + 2, -11, -17, -5, 15, 35, 34, 25, 23, 44, 55, 41, 22, 14, 2, -29, + -32, -23, -11, -13, -18, -60, -50, -32, -16, -6, -11, -4, 3, 11, 3, -1, + -14, -8, 5, 20, 39, 31, 24, 26, 54, 57, 37, 16, 8, -19, -32, -27, + -17, -17, -17, -36, -58, -40, -32, -11, -11, -2, 6, 10, 2, 0, -4, -12, + 1, 8, 33, 42, 26, 17, 35, 63, 53, 26, 6, -9, -27, -30, -25, -17, + -23, -24, -47, -51, -38, -17, -11, -6, 12, 17, 8, -8, -1, -10, -7, 4, + 18, 40, 33, 18, 22, 49, 70, 46, 12, -11, -16, -23, -27, -19, -28, -26, + -36, -50, -48, -31, -13, -13, 10, 20, 21, 0, -6, -1, -7, 3, 15, 32, + 40, 24, 17, 31, 58, 67, 28, -2, -21, -14, -31, -18, -24, -33, -33, -49, + -49, -41, -18, -20, -2, 20, 23, 19, -12, -7, -2, -3, 10, 22, 33, 37, + 21, 23, 39, 72, 51, 10, -17, -18, -20, -29, -17, -33, -36, -49, -48, -47, + -24, -16, -15, 11, 24, 30, 6, -12, -2, -2, -1, 18, 29, 35, 27, 25, + 25, 56, 63, 23, -5, -19, -14, -23, -21, -21, -38, -52, -54, -40, -32, -15, + -23, -7, 18, 31, 22, -2, -7, 3, 0, 12, 21, 34, 31, 28, 22, 35, + 66, 40, 2, -19, -19, -15, -21, -16, -30, -60, -62, -42, -33, -18, -18, -22, + 4, 29, 29, 14, -2, -4, 5, 6, 16, 28, 36, 24, 29, 26, 52, 49, + 14, -13, -24, -19, -14, -15, -17, -53, -75, -54, -32, -18, -11, -26, -18, 18, + 28, 25, 13, -6, 4, 13, 9, 17, 37, 24, 28, 33, 37, 49, 26, 1, + -19, -26, -16, -11, -7, -33, -77, -71, -45, -15, -8, -18, -30, 1, 25, 21, + 26, 3, 5, 17, 14, 11, 33, 27, 17, 34, 38, 42, 33, 6, -11, -28, + -22, -12, -3, -16, -60, -81, -62, -25, -2, -14, -27, -17, 20, 18, 24, 18, + 6, 16, 21, 12, 24, 28, 12, 26, 44, 42, 35, 13, -5, -21, -31, -18, + -2, -2, -42, -77, -76, -47, -10, -6, -22, -24, 4, 16, 18, 25, 18, 18, + 24, 20, 20, 32, 14, 11, 40, 49, 41, 21, -6, -13, -27, -28, -5, 5, + -18, -59, -79, -63, -30, -6, -11, -28, -11, 8, 10, 23, 27, 17, 24, 25, + 25, 28, 19, 8, 25, 47, 46, 27, -5, -15, -18, -33, -20, -5, -3, -35, + -70, -66, -51, -22, -7, -21, -19, -3, 6, 17, 29, 26, 23, 28, 25, 32, + 23, 14, 11, 39, 50, 38, 3, -19, -10, -21, -29, -12, -3, -12, -55, -65, + -56, -42, -14, -10, -23, -11, -3, 10, 23, 32, 26, 28, 28, 35, 29, 22, + 13, 18, 41, 43, 18, -16, -18, -14, -29, -21, -11, -8, -32, -61, -52, -52, + -30, -11, -18, -16, -10, 2, 22, 35, 30, 25, 32, 34, 40, 27, 19, 11, + 23, 39, 32, -1, -22, -14, -22, -23, -14, -11, -17, -45, -52, -51, -51, -22, + -17, -19, -17, -10, 11, 35, 39, 29, 26, 34, 43, 43, 27, 16, 12, 25, + 31, 18, -13, -20, -19, -22, -12, -14, -15, -28, -44, -47, -53, -33, -15, -22, + -24, -20, 5, 27, 38, 31, 21, 27, 46, 51, 40, 18, 8, 13, 23, 24, + 3, -21, -22, -22, -8, -9, -22, -26, -31, -40, -51, -44, -17, -15, -26, -31, + -10, 24, 35, 37, 25, 21, 42, 57, 53, 30, 11, 7, 11, 21, 12, -11, + -23, -25, -12, 0, -18, -32, -31, -30, -45, -46, -26, -13, -25, -39, -25, 15, + 36, 29, 25, 20, 37, 58, 63, 46, 15, 3, -2, 19, 16, -2, -19, -25, + -23, 4, -4, -31, -36, -29, -32, -43, -37, -17, -16, -39, -43, -2, 34, 31, + 21, 17, 30, 62, 67, 62, 27, 9, -9, 3, 26, 8, -18, -26, -26, -5, + 9, -23, -44, -33, -26, -33, -40, -28, -12, -30, -52, -24, 23, 33, 15, 14, + 22, 54, 75, 68, 47, 14, -9, -12, 19, 23, -12, -20, -20, -13, 11, -6, + -40, -41, -19, -23, -34, -34, -14, -13, -48, -48, 4, 35, 23, 7, 13, 40, + 77, 78, 57, 31, -3, -18, 3, 27, 7, -24, -19, -16, 1, 5, -29, -49, + -28, -13, -26, -34, -26, -4, -30, -57, -24, 22, 30, 6, 7, 31, 63, 86, + 68, 42, 10, -19, -13, 15, 25, -10, -22, -14, -7, 6, -11, -45, -40, -14, + -24, -35, -31, -12, -8, -51, -44, -2, 29, 11, -1, 22, 47, 74, 78, 49, + 25, -8, -26, -4, 26, 12, -16, -19, -11, -1, -1, -28, -45, -22, -13, -29, + -29, -23, -1, -26, -55, -26, 14, 20, -3, 13, 39, 63, 80, 61, 33, 8, + -22, -25, 10, 22, -1, -14, -15, -7, -1, -14, -37, -26, -13, -25, -28, -26, + -2, -5, -48, -44, -7, 18, 3, 9, 30, 49, 71, 70, 45, 23, -13, -33, + -5, 22, 11, -7, -17, -14, -6, -8, -29, -29, -15, -19, -26, -31, -15, 6, + -25, -52, -30, 7, 7, 2, 21, 40, 60, 67, 52, 33, 7, -29, -19, 16, + 22, 4, -8, -15, -11, -6, -23, -24, -10, -11, -23, -27, -22, 1, 0, -34, + -45, -14, 2, 1, 15, 35, 52, 62, 49, 36, 21, -16, -26, 1, 20, 12, + -7, -10, -20, -10, -19, -28, -9, -8, -15, -26, -27, -11, 2, -15, -41, -34, + -10, -7, 6, 32, 48, 56, 51, 35, 26, 1, -24, -10, 15, 18, 2, -9, + -17, -18, -11, -32, -6, 2, -9, -18, -22, -17, -3, -2, -21, -34, -26, -13, + -8, 20, 47, 53, 52, 38, 24, 5, -14, -15, 9, 14, 4, -6, -14, -21, + -14, -28, -22, 12, 0, -10, -23, -24, -13, 2, -10, -23, -34, -26, -13, 4, + 39, 58, 51, 45, 28, 6, -9, -11, 3, 17, 7, -3, -10, -18, -15, -22, + -35, 2, 18, 2, -11, -23, -20, -1, 0, -15, -24, -39, -25, -6, 17, 52, + 56, 47, 35, 6, -10, -8, 0, 13, 13, -2, -9, -13, -13, -25, -43, -16, + 21, 19, -3, -21, -25, -10, 2, -5, -14, -30, -40, -13, -1, 34, 58, 51, + 44, 18, -10, -9, -2, 6, 12, 7, -7, -12, -12, -18, -40, -33, 9, 32, + 19, -9, -23, -15, 1, 3, -9, -18, -40, -28, -4, 7, 47, 59, 49, 24, + 1, -13, -5, 1, 10, 11, 5, -12, -12, -15, -35, -42, -9, 23, 33, 9, + -22, -24, -5, 1, -5, -12, -30, -40, -7, -3, 22, 56, 58, 35, 11, -12, + -9, -5, -1, 7, 13, -4, -13, -13, -25, -43, -29, 10, 34, 32, -6, -27, + -8, 3, -5, -13, -22, -40, -18, -3, -1, 37, 61, 46, 23, -5, -13, -4, + -4, -7, 12, 14, -10, -18, -22, -34, -35, -10, 22, 39, 23, -15, -14, 5, + 3, -8, -15, -36, -23, -1, -7, 14, 51, 57, 37, 8, -13, -7, -2, -14, + -6, 20, 3, -21, -26, -27, -30, -27, 1, 28, 36, 7, -10, 0, 5, -8, + -14, -30, -29, -3, -10, -5, 31, 56, 46, 19, -7, -10, 3, -11, -21, 9, + 19, -10, -30, -29, -19, -24, -20, 10, 35, 29, 8, -1, 5, -2, -13, -28, + -33, -3, -1, -13, 12, 49, 55, 31, -1, -12, 2, -3, -26, -2, 21, 2, + -28, -34, -21, -17, -29, -12, 23, 34, 19, 6, 7, 4, -4, -23, -40, -10, + 7, -12, -2, 34, 55, 36, 8, -10, 1, 3, -19, -18, 15, 15, -10, -33, + -30, -9, -19, -25, 4, 32, 30, 16, 11, 10, 3, -15, -35, -27, 9, -4, + -10, 16, 52, 42, 12, -7, -6, 4, -6, -21, -2, 17, 0, -20, -41, -13, + -9, -31, -16, 18, 34, 23, 14, 9, 10, -7, -26, -34, -3, 10, -10, 2, + 42, 51, 16, -8, -11, -2, -2, -11, -9, 9, 2, -8, -36, -31, 3, -23, + -30, -1, 27, 27, 23, 15, 18, 3, -17, -31, -19, 8, 1, -4, 24, 51, + 30, -11, -16, -6, -3, -5, -10, 3, 1, -10, -22, -41, -4, -6, -29, -18, + 12, 25, 26, 23, 20, 11, -10, -21, -27, -4, 7, 0, 13, 41, 40, 3, + -24, -11, -1, -2, -3, 5, 5, -14, -15, -35, -20, 0, -19, -24, -4, 11, + 23, 31, 24, 16, -3, -13, -23, -14, 2, 3, 18, 32, 38, 21, -20, -29, + -5, -2, 0, 5, 11, -14, -22, -25, -26, -3, -11, -26, -11, -2, 8, 32, + 34, 24, 2, -8, -16, -13, 1, 1, 10, 31, 31, 33, 1, -36, -22, 0, + 0, 8, 18, -3, -27, -22, -22, -10, -9, -24, -16, -5, -16, 16, 40, 34, + 8, -3, -13, -12, 1, 1, 3, 30, 30, 24, 18, -28, -35, -13, -2, 6, + 19, 10, -25, -28, -15, -9, -10, -19, -20, -3, -15, -8, 27, 42, 25, 1, + -14, -18, 7, 9, -1, 19, 37, 19, 23, -10, -41, -26, -9, 2, 20, 19, + -17, -35, -21, 0, -9, -18, -20, -7, -8, -24, 6, 37, 43, 14, -10, -22, + 3, 18, 4, 6, 36, 23, 16, 4, -32, -37, -19, -3, 17, 27, 0, -37, + -34, -3, 7, -17, -27, -19, -1, -20, -13, 17, 44, 35, 2, -22, -9, 19, + 20, 2, 26, 32, 15, 5, -17, -40, -29, -9, 10, 28, 17, -23, -41, -21, + 9, -2, -27, -30, -5, -7, -21, -4, 27, 47, 27, -14, -21, 11, 29, 14, + 15, 32, 20, 4, -11, -31, -38, -15, 2, 22, 22, -3, -32, -34, -6, 8, + -13, -38, -19, 0, -16, -14, 6, 37, 39, 11, -18, -4, 25, 25, 16, 24, + 27, 7, -10, -24, -38, -25, 0, 12, 23, 8, -16, -31, -23, 0, 0, -27, + -33, -2, -9, -16, -11, 17, 41, 32, 5, -15, 12, 25, 24, 21, 27, 14, + -4, -21, -31, -29, -4, 9, 19, 9, -9, -19, -25, -10, -5, -15, -38, -13, + -6, -13, -17, -1, 30, 36, 27, -2, 2, 20, 24, 25, 24, 19, 2, -16, + -32, -29, -13, 8, 18, 16, -6, -13, -21, -15, -14, -13, -26, -22, -6, -11, + -14, -14, 11, 30, 37, 17, 1, 13, 20, 23, 24, 21, 5, -10, -32, -31, + -15, 0, 17, 22, -3, -15, -17, -11, -15, -19, -23, -22, -8, -8, -13, -18, + -8, 18, 40, 38, 12, 12, 15, 21, 23, 24, 7, -9, -22, -34, -19, -6, + 11, 30, 9, -17, -20, -16, -11, -22, -30, -27, -8, -7, -10, -19, -16, -2, + 32, 52, 31, 17, 16, 13, 21, 19, 19, -9, -17, -30, -25, -7, 3, 29, + 25, -9, -21, -20, -11, -14, -29, -37, -14, 2, -5, -14, -22, -12, 13, 50, + 49, 27, 23, 15, 13, 9, 18, 7, -22, -22, -28, -11, -5, 19, 35, 13, + -20, -24, -18, -8, -22, -38, -31, 2, 3, -6, -26, -22, -3, 38, 56, 42, + 34, 21, 12, 6, 11, 17, -15, -24, -20, -15, -6, 9, 29, 29, -4, -28, + -23, -14, -13, -30, -39, -16, 9, 6, -12, -33, -16, 19, 57, 49, 41, 30, + 13, 4, -1, 6, -4, -27, -21, -13, -6, 2, 12, 34, 12, -24, -24, -20, + -16, -24, -38, -33, 2, 12, -2, -30, -31, 2, 45, 59, 46, 41, 24, 8, + -3, -6, 1, -15, -25, -16, -3, 5, 2, 21, 28, -11, -26, -23, -18, -20, + -32, -40, -14, 14, 11, -10, -40, -20, 30, 60, 55, 42, 34, 15, 6, -12, + -12, -4, -19, -21, -9, 8, 4, 10, 28, 6, -25, -22, -20, -22, -29, -38, + -27, 5, 16, 4, -24, -39, 12, 51, 61, 51, 41, 27, 10, -7, -25, -9, + -10, -17, -15, 0, 9, 5, 21, 15, -13, -27, -17, -21, -23, -38, -33, -11, + 10, 6, -4, -38, -17, 36, 55, 55, 45, 35, 21, 4, -27, -25, -2, -10, + -14, -13, 3, 5, 14, 16, 0, -24, -21, -18, -22, -36, -39, -17, -3, 5, + 3, -15, -28, 16, 50, 53, 52, 43, 29, 13, -14, -36, -10, -1, -15, -15, + -6, 6, 5, 13, 4, -11, -24, -17, -18, -27, -43, -18, -12, -7, 4, 3, + -17, -4, 38, 53, 52, 48, 41, 23, 0, -31, -30, 2, -7, -14, -13, -5, + 3, 11, 7, -4, -21, -25, -21, -19, -39, -23, -9, -19, -8, 5, -1, -10, + 24, 46, 48, 46, 44, 32, 10, -18, -37, -7, 0, -12, -14, -13, -4, 8, + 9, 1, -16, -29, -28, -17, -33, -31, -6, -21, -21, -4, 12, 3, 13, 41, + 46, 44, 46, 44, 20, -7, -36, -27, 6, -3, -18, -21, -12, 2, 12, 6, + -5, -27, -36, -21, -20, -34, -12, -8, -29, -16, 11, 15, 10, 28, 47, 46, + 41, 45, 35, 5, -24, -30, -5, 3, -14, -26, -16, -7, 7, 8, -3, -18, + -39, -32, -16, -28, -26, -8, -23, -26, 0, 19, 16, 20, 42, 55, 45, 38, + 39, 20, -11, -24, -13, -2, -6, -25, -22, -7, -5, 13, 0, -11, -36, -41, + -20, -16, -29, -16, -14, -28, -12, 13, 17, 15, 32, 50, 57, 41, 38, 30, + 2, -14, -9, -3, -3, -19, -33, -10, -7, 7, 7, -13, -30, -42, -28, -13, + -17, -26, -14, -22, -15, 7, 19, 15, 26, 46, 59, 51, 34, 33, 12, -7, + -11, -4, -5, -13, -38, -23, -3, 3, 15, -7, -32, -45, -34, -21, -11, -27, + -25, -21, -19, -1, 13, 15, 22, 37, 53, 62, 46, 34, 15, -2, 0, -4, + -8, -9, -34, -38, -8, 4, 17, 3, -25, -50, -44, -26, -12, -13, -32, -24, + -20, -7, 11, 18, 17, 33, 50, 65, 57, 41, 24, 0, 5, 5, -9, -11, + -25, -44, -25, -1, 17, 13, -18, -42, -51, -33, -20, -7, -27, -29, -23, -16, + 0, 14, 14, 28, 48, 60, 66, 51, 34, 4, 0, 15, -3, -14, -20, -35, + -37, -12, 12, 27, -7, -37, -50, -40, -29, -15, -15, -30, -24, -15, -7, 6, + 17, 25, 46, 59, 68, 63, 43, 20, -6, 14, 10, -8, -20, -30, -34, -22, + -2, 24, 15, -30, -49, -49, -37, -28, -15, -26, -28, -18, -11, -7, 7, 27, + 42, 58, 70, 70, 53, 35, 4, 0, 18, -1, -15, -32, -31, -26, -12, 12, + 28, -4, -44, -53, -44, -39, -25, -23, -28, -19, -11, -12, -16, 13, 42, 56, + 71, 71, 57, 45, 23, -3, 10, 11, -6, -27, -35, -25, -22, -1, 23, 17, + -29, -54, -46, -44, -39, -29, -28, -21, -15, -15, -26, -12, 39, 57, 70, 73, + 60, 49, 41, 13, 1, 11, 0, -16, -32, -25, -15, -14, 10, 23, -5, -48, + -46, -42, -49, -43, -31, -24, -15, -13, -24, -32, 18, 59, 71, 77, 67, 57, + 47, 33, 3, 5, 5, -9, -23, -33, -16, -14, -5, 17, 12, -29, -44, -35, + -50, -57, -43, -30, -18, -11, -22, -39, -9, 44, 68, 82, 69, 61, 49, 42, + 18, 5, 5, -8, -12, -26, -14, -7, -9, 5, 16, -6, -36, -32, -42, -62, + -55, -39, -29, -15, -14, -34, -30, 20, 59, 82, 79, 66, 58, 45, 38, 9, + 1, -7, -11, -16, -19, -3, -6, -6, 9, 5, -22, -32, -32, -58, -70, -56, + -42, -24, -16, -25, -39, -9, 41, 72, 86, 73, 65, 46, 40, 30, -4, -7, + -14, -12, -20, -3, 4, -5, 1, 8, -9, -27, -25, -40, -67, -67, -55, -38, + -24, -17, -25, -28, 16, 61, 81, 82, 71, 60, 37, 42, 17, -14, -17, -11, + -13, -8, 10, 2, -2, 1, -1, -17, -20, -26, -54, -69, -70, -58, -34, -25, + -16, -23, -9, 37, 70, 87, 80, 68, 44, 38, 39, -5, -27, -19, -12, -6, + 13, 10, 4, 1, 1, -5, -19, -20, -37, -59, -71, -71, -54, -35, -17, -9, + -20, 11, 49, 80, 86, 72, 54, 36, 45, 23, -25, -34, -16, -9, 11, 17, + 8, 5, -4, -2, -15, -19, -26, -50, -69, -77, -71, -51, -29, -7, -11, -6, + 26, 64, 87, 78, 60, 40, 42, 45, 2, -38, -34, -12, 10, 24, 10, 11, + 3, -1, -6, -20, -16, -31, -61, -81, -80, -69, -41, -16, -5, -8, 10, 47, + 81, 86, 70, 44, 36, 48, 32, -21, -48, -31, -3, 24, 24, 10, 15, 0, + 2, -17, -21, -18, -45, -81, -87, -80, -57, -33, -11, -6, 2, 30, 74, 86, + 77, 55, 34, 42, 48, 13, -39, -50, -20, 15, 34, 14, 16, 12, 4, -5, + -26, -16, -19, -64, -92, -91, -65, -43, -26, -12, -1, 16, 47, 83, 76, 66, + 40, 33, 45, 33, -8, -52, -41, -5, 32, 30, 15, 25, 13, 8, -22, -28, + -11, -34, -85, -101, -86, -52, -36, -25, -13, 15, 32, 69, 80, 69, 52, 32, + 37, 39, 19, -30, -54, -24, 10, 38, 25, 25, 22, 18, -6, -35, -20, -14, + -59, -98, -99, -68, -41, -30, -23, 5, 28, 52, 74, 67, 59, 43, 32, 35, + 32, -2, -47, -38, -13, 23, 33, 31, 26, 27, 16, -29, -37, -15, -33, -80, + -104, -89, -54, -35, -31, -11, 17, 42, 63, 68, 60, 59, 37, 27, 33, 22, + -28, -37, -26, 3, 32, 38, 30, 25, 30, -3, -41, -29, -23, -55, -90, -98, + -76, -39, -32, -21, 4, 36, 52, 61, 61, 63, 48, 24, 28, 34, -10, -31, + -29, -14, 15, 37, 37, 28, 31, 19, -27, -40, -24, -38, -69, -95, -96, -60, + -32, -26, -10, 19, 45, 53, 58, 59, 58, 29, 23, 39, 14, -21, -25, -23, + 1, 27, 43, 34, 34, 21, 0, -36, -32, -31, -49, -84, -102, -83, -41, -22, + -19, -1, 35, 49, 52, 53, 56, 39, 23, 34, 33, -3, -23, -22, -10, 17, + 36, 36, 39, 26, 8, -16, -34, -29, -36, -61, -93, -95, -58, -26, -18, -11, + 22, 48, 53, 53, 51, 41, 31, 33, 37, 16, -15, -24, -14, 4, 29, 34, + 41, 32, 8, -7, -19, -28, -30, -54, -83, -101, -76, -40, -20, -21, 1, 36, + 54, 55, 44, 33, 32, 35, 36, 30, 7, -26, -19, -5, 22, 36, 37, 37, + 15, -3, -5, -15, -24, -43, -75, -94, -87, -47, -29, -25, -14, 26, 48, 62, + 49, 29, 23, 35, 45, 38, 19, -16, -28, -7, 10, 29, 32, 38, 23, -2, + -10, -6, -12, -28, -67, -90, -98, -59, -32, -28, -25, 3, 43, 56, 59, 25, + 16, 24, 46, 43, 31, 0, -31, -14, 5, 25, 29, 32, 29, 6, -13, -6, + -3, -8, -49, -85, -97, -75, -31, -30, -30, -12, 31, 50, 61, 40, 12, 14, + 34, 53, 43, 20, -23, -20, -3, 21, 29, 23, 24, 15, -10, -8, -1, 2, + -25, -75, -98, -92, -42, -31, -35, -24, 14, 41, 50, 49, 22, 11, 20, 45, + 52, 39, 0, -26, -12, 9, 35, 25, 18, 14, 1, -13, -6, 4, 3, -49, + -89, -102, -61, -27, -30, -27, -4, 34, 46, 46, 32, 17, 13, 26, 47, 50, + 29, -19, -22, -4, 30, 37, 15, 7, 7, -5, -10, -4, 9, -20, -72, -100, + -86, -41, -33, -31, -16, 18, 43, 34, 32, 27, 23, 15, 31, 47, 48, 9, + -24, -16, 12, 43, 25, -2, 0, 9, -9, -15, 2, 8, -40, -87, -99, -69, + -37, -31, -19, 6, 38, 35, 25, 31, 35, 26, 18, 36, 49, 40, -10, -22, + -9, 29, 40, 6, -12, 6, 6, -16, -11, 9, -6, -61, -95, -90, -58, -35, + -26, -5, 23, 36, 18, 21, 36, 41, 28, 22, 38, 52, 23, -17, -17, 7, + 39, 21, -12, -13, 16, -8, -22, -5, 6, -25, -77, -93, -79, -46, -30, -11, + 15, 36, 22, 5, 29, 47, 47, 24, 22, 41, 48, 7, -15, -4, 22, 33, + 6, -23, 4, 8, -21, -15, -1, -5, -49, -79, -92, -71, -43, -20, 11, 31, + 29, 4, 16, 40, 55, 41, 22, 31, 50, 25, -9, -2, 8, 23, 16, -17, + -6, 8, -10, -15, -6, -4, -29, -56, -80, -86, -61, -42, 0, 30, 33, 12, + 2, 24, 47, 55, 37, 28, 39, 40, 4, -1, 6, 6, 16, -4, -13, 1, + -2, -9, -11, -11, -21, -35, -55, -82, -80, -64, -24, 27, 36, 23, 3, 10, + 35, 61, 55, 40, 35, 35, 19, 6, 12, 4, 1, 3, -12, -3, -2, -4, + -4, -14, -23, -30, -37, -58, -83, -84, -58, 8, 37, 33, 11, 3, 20, 46, + 62, 55, 50, 28, 16, 12, 15, 9, -4, -9, -9, -4, -5, -7, 2, -7, + -28, -35, -31, -36, -67, -90, -86, -23, 28, 38, 25, 5, 13, 34, 58, 58, + 69, 50, 15, 10, 20, 16, -3, -14, -14, -2, 1, -12, -3, 3, -20, -36, + -39, -26, -46, -81, -98, -61, 6, 27, 30, 16, 12, 25, 50, 57, 66, 74, + 31, 4, 16, 21, 8, -13, -21, -10, 8, -5, -11, 6, -8, -31, -40, -29, + -30, -66, -93, -84, -22, 17, 22, 26, 16, 20, 43, 56, 56, 70, 60, 17, + 8, 18, 15, -10, -26, -21, 6, 7, -12, -1, 1, -20, -33, -34, -31, -51, + -79, -92, -52, -6, 9, 19, 23, 21, 40, 57, 59, 60, 72, 43, 17, 13, + 18, 3, -23, -32, -5, 14, -7, -11, 7, -12, -26, -31, -37, -46, -66, -85, + -67, -21, -5, 3, 16, 22, 37, 54, 59, 55, 60, 58, 30, 16, 13, 11, + -15, -34, -23, 9, 7, -12, -2, -4, -19, -16, -31, -49, -64, -76, -72, -35, + -12, -14, 0, 15, 34, 53, 60, 58, 53, 57, 43, 30, 18, 12, -4, -27, + -28, -8, 14, -3, -9, -2, -13, -9, -17, -49, -66, -70, -69, -44, -15, -19, + -11, 2, 21, 53, 64, 68, 55, 48, 44, 36, 28, 15, -1, -18, -23, -19, + -4, 5, -3, 1, -9, -7, -1, -35, -70, -74, -70, -50, -21, -14, -22, -7, + -1, 39, 66, 77, 69, 46, 38, 36, 38, 22, 5, -12, -16, -12, -17, -8, + -5, 2, 1, -6, 5, -13, -64, -78, -73, -60, -31, -14, -17, -16, -10, 7, + 61, 79, 81, 57, 38, 28, 32, 24, 9, -4, -10, -4, -11, -20, -13, -2, + 11, 4, 4, -2, -41, -76, -76, -69, -43, -22, -12, -17, -14, -14, 25, 74, + 92, 79, 47, 31, 26, 26, 11, 3, -5, 0, 0, -20, -26, -11, 9, 14, + 9, 4, -24, -61, -76, -74, -53, -30, -13, -8, -12, -25, -8, 51, 90, 93, + 63, 42, 21, 18, 13, 6, 2, 1, 8, -12, -30, -27, -2, 14, 18, 11, + -13, -48, -68, -79, -70, -44, -19, -2, -5, -21, -31, 18, 77, 100, 81, 55, + 29, 7, 8, 6, 7, 4, 14, 0, -26, -34, -13, 9, 16, 17, 1, -35, + -58, -70, -82, -62, -29, -2, 1, -14, -36, -15, 50, 89, 95, 71, 46, 5, + -6, 4, 11, 3, 11, 14, -12, -31, -22, -2, 8, 16, 16, -15, -53, -56, + -80, -81, -41, -5, 9, -3, -30, -34, 17, 73, 97, 86, 63, 25, -12, -6, + 11, 13, 1, 15, 4, -19, -25, -5, 2, 9, 19, 10, -39, -48, -61, -95, + -67, -17, 12, 8, -23, -43, -9, 49, 85, 91, 76, 50, 1, -23, 2, 22, + 5, 2, 14, -5, -23, -12, 0, -2, 13, 17, -15, -48, -43, -83, -88, -38, + 5, 17, -11, -41, -28, 27, 67, 83, 82, 65, 29, -21, -18, 21, 19, -7, + 3, 6, -8, -14, 1, 0, 0, 13, 2, -34, -42, -59, -99, -63, -12, 17, + 0, -35, -42, 1, 53, 69, 79, 72, 53, -1, -34, 2, 32, 3, -8, 1, + 2, -2, -3, 8, -2, 3, 7, -18, -40, -39, -76, -81, -35, 9, 17, -22, + -46, -24, 34, 59, 68, 74, 66, 27, -26, -22, 31, 24, -10, -11, 0, 14, + 1, 5, 8, -5, -2, -10, -34, -35, -48, -77, -59, -13, 20, -4, -37, -35, + 8, 47, 55, 68, 74, 49, -4, -34, 10, 39, 1, -13, -11, 14, 14, 3, + 20, 6, -9, -14, -29, -37, -28, -56, -66, -42, 9, 9, -25, -38, -14, 27, + 45, 54, 72, 61, 21, -25, -14, 31, 19, -10, -15, -2, 22, 6, 22, 24, + -4, -20, -28, -38, -24, -28, -54, -57, -20, 14, -10, -29, -26, 2, 29, 39, + 61, 66, 39, -6, -25, 16, 30, 0, -16, -8, 12, 13, 18, 38, 10, -20, + -36, -34, -31, -16, -33, -56, -42, 0, 0, -21, -22, -12, 11, 25, 49, 68, + 53, 14, -20, -3, 29, 15, -11, -12, 3, 13, 13, 42, 34, -12, -39, -37, + -27, -22, -18, -44, -50, -21, 3, -12, -15, -18, -5, 9, 27, 60, 60, 32, + -6, -12, 21, 25, -4, -12, -2, 7, 8, 33, 53, 8, -37, -41, -25, -22, + -16, -27, -47, -34, -10, -10, -15, -15, -15, -5, 5, 41, 63, 44, 12, -11, + 10, 32, 10, -14, -8, 8, 5, 19, 53, 34, -24, -43, -25, -14, -15, -19, + -35, -35, -20, -12, -8, -14, -17, -19, -13, 19, 55, 53, 22, -8, 4, 31, + 26, -8, -13, 6, 10, 7, 39, 50, -2, -41, -31, -10, -13, -23, -31, -33, + -24, -15, -7, -13, -16, -22, -23, -6, 38, 55, 34, 1, -1, 23, 34, 9, + -18, -3, 14, 9, 20, 51, 24, -28, -37, -6, 2, -20, -30, -27, -21, -22, + -6, -12, -17, -21, -32, -27, 9, 49, 43, 12, -4, 14, 34, 24, -9, -12, + 12, 19, 13, 30, 37, -3, -35, -15, 12, -10, -31, -30, -15, -18, -13, -3, + -19, -20, -31, -35, -17, 28, 44, 22, 0, 7, 28, 27, 5, -15, 1, 20, + 20, 17, 28, 19, -21, -23, 12, 8, -22, -32, -20, -8, -15, 0, -13, -23, + -25, -43, -36, 4, 37, 30, 11, 4, 22, 28, 15, 0, -10, 9, 23, 14, + 11, 24, 5, -21, 2, 17, -8, -27, -27, -7, -10, -6, -1, -20, -26, -39, + -53, -20, 23, 36, 17, 7, 14, 28, 16, 12, -3, 2, 19, 16, 2, 14, + 19, -8, -5, 17, 4, -15, -26, -10, -4, -12, 1, -8, -23, -38, -58, -41, + 0, 29, 23, 11, 16, 21, 15, 9, 11, -6, 11, 20, 4, 3, 24, 5, + -5, 10, 17, -6, -15, -15, 6, -15, -8, 0, -11, -37, -54, -56, -24, 13, + 29, 12, 15, 20, 19, 6, 16, 5, -2, 10, 11, -3, 22, 18, 0, 6, + 20, 10, -6, -12, 1, -6, -23, 0, 1, -23, -56, -60, -43, -10, 19, 22, + 15, 22, 18, 6, 11, 17, -2, -5, 10, 4, 7, 23, 1, 3, 16, 22, + 5, -1, 0, 5, -21, -14, 6, -6, -46, -64, -54, -29, 1, 17, 18, 24, + 25, 10, 1, 17, 9, -8, -1, 15, 6, 20, 11, 2, 14, 25, 16, 9, + 5, 7, -11, -26, -5, 4, -27, -62, -62, -40, -17, 8, 11, 21, 29, 17, + -2, 10, 17, -8, -16, 6, 13, 11, 15, 3, 8, 24, 26, 14, 12, 12, + 4, -26, -15, 1, -12, -50, -64, -48, -27, -10, 5, 8, 32, 31, 1, -1, + 18, 0, -23, -6, 18, 14, 11, 5, 3, 17, 35, 25, 16, 18, 14, -11, + -27, -8, -6, -30, -55, -53, -36, -20, -5, 5, 14, 43, 13, -6, 11, 11, + -22, -22, 7, 19, 13, 10, 1, 7, 30, 36, 22, 23, 23, 6, -28, -20, + -6, -23, -43, -49, -43, -29, -19, 3, 1, 34, 29, -4, 3, 13, -13, -32, + -3, 20, 14, 11, 5, 2, 23, 42, 34, 22, 23, 21, -13, -26, -14, -19, + -32, -38, -43, -32, -29, -6, 4, 16, 35, 9, -4, 11, 0, -33, -22, 9, + 13, 12, 9, 3, 14, 35, 47, 34, 23, 27, 8, -22, -19, -16, -30, -29, + -42, -33, -32, -23, 4, 9, 24, 20, -1, 3, 10, -20, -36, -5, 13, 9, + 11, 8, 8, 21, 43, 48, 27, 22, 23, -7, -25, -20, -28, -25, -31, -36, + -28, -33, -8, 11, 14, 14, 6, -8, 7, -5, -39, -25, 7, 14, 9, 10, + 12, 15, 29, 55, 41, 23, 22, 9, -12, -23, -28, -24, -23, -34, -26, -31, + -21, 9, 19, 9, 1, -3, -1, 7, -32, -38, -9, 13, 11, 9, 11, 14, + 21, 46, 53, 32, 24, 12, -2, -16, -26, -24, -17, -34, -33, -25, -24, -4, + 17, 14, -3, -4, -7, 3, -13, -46, -25, 2, 17, 5, 8, 12, 18, 32, + 56, 38, 29, 15, 8, -4, -22, -30, -14, -22, -42, -25, -15, -10, 6, 17, + 1, -5, -7, -10, -2, -38, -37, -7, 15, 9, 2, 8, 21, 26, 43, 44, + 29, 18, 7, 12, -9, -25, -24, -11, -35, -43, -17, -5, 3, 10, 9, -3, + -3, -23, -9, -23, -45, -22, 7, 15, 2, 4, 17, 33, 31, 45, 35, 23, + 8, 17, 6, -16, -26, -14, -20, -48, -27, -2, 6, 11, 9, -1, 6, -15, + -28, -18, -39, -32, -7, 11, 7, 6, 7, 33, 30, 31, 41, 27, 7, 13, + 24, -3, -18, -22, -9, -40, -41, -10, 4, 9, 17, 3, 5, -4, -37, -29, + -29, -35, -19, 1, 10, 3, 7, 25, 41, 19, 31, 32, 13, 5, 27, 14, + -6, -19, -12, -23, -48, -22, 7, 8, 16, 11, 1, 6, -29, -46, -32, -32, + -20, -5, 7, 4, 3, 21, 43, 32, 15, 29, 16, 8, 19, 26, 3, -9, + -22, -13, -42, -37, -8, 11, 14, 25, 9, 4, -17, -50, -44, -30, -25, -14, + -1, 11, 1, 18, 36, 41, 12, 14, 18, 14, 15, 20, 17, 6, -14, -18, + -27, -39, -19, 5, 12, 24, 27, 8, -13, -49, -53, -32, -27, -19, -12, 7, + 7, 12, 31, 43, 26, 2, 8, 14, 22, 13, 17, 18, 6, -17, -26, -36, + -28, -6, 14, 25, 35, 20, -6, -42, -57, -37, -23, -23, -20, 0, 9, 8, + 25, 41, 40, 7, -4, 1, 23, 21, 14, 22, 20, -2, -24, -34, -31, -13, + 8, 24, 37, 33, 8, -32, -62, -44, -20, -22, -27, -9, 9, 7, 16, 31, + 42, 20, -10, -13, 10, 26, 7, 13, 25, 18, -11, -35, -39, -20, 0, 17, + 37, 37, 19, -17, -58, -55, -26, -18, -25, -21, 0, 14, 12, 20, 38, 35, + 0, -19, -9, 24, 19, 3, 21, 31, 17, -24, -42, -30, -3, 13, 34, 42, + 28, -2, -45, -62, -38, -22, -19, -20, -12, 12, 17, 11, 29, 42, 18, -16, + -20, 3, 24, 2, 4, 26, 36, 0, -38, -45, -13, 12, 27, 41, 34, 14, + -27, -62, -55, -30, -19, -15, -16, -2, 18, 11, 14, 37, 31, -6, -22, -12, + 15, 10, -10, 12, 36, 30, -19, -46, -33, 11, 24, 28, 35, 28, -5, -44, + -65, -44, -23, -11, -9, -8, 5, 14, 10, 25, 37, 14, -17, -18, -2, 14, + -7, -6, 23, 43, 10, -33, -38, -9, 24, 24, 28, 30, 11, -21, -57, -61, + -39, -12, -5, -5, -3, 7, 10, 17, 31, 30, -3, -20, -14, 6, 1, -16, + 2, 38, 38, -5, -30, -24, 13, 25, 21, 28, 15, 1, -34, -64, -62, -23, + 0, 2, -1, -1, 5, 14, 24, 33, 14, -12, -23, -4, 7, -18, -18, 18, + 43, 25, -9, -22, -2, 21, 19, 24, 20, 11, -13, -47, -69, -46, -7, 5, + 6, -1, -4, 9, 21, 31, 25, 5, -15, -20, 3, -8, -33, -7, 29, 37, + 20, -10, -10, 9, 15, 17, 14, 12, 1, -23, -55, -70, -30, 5, 13, 2, + -8, -1, 15, 25, 30, 15, -1, -20, -8, -3, -31, -28, 8, 31, 41, 15, + -6, 0, 9, 14, 12, 9, 8, -10, -28, -63, -55, -12, 17, 11, -7, -13, + 8, 22, 26, 19, 9, -7, -13, -5, -23, -39, -10, 17, 41, 38, 8, 0, + 5, 7, 12, 5, 7, -6, -8, -39, -60, -35, 7, 19, 6, -10, -6, 15, + 26, 22, 15, 9, -8, -13, -24, -45, -29, -1, 29, 48, 30, 2, 6, 5, + 9, 5, -1, -5, -4, -13, -51, -51, -16, 20, 13, 0, -11, 7, 25, 22, + 18, 17, 10, -8, -22, -50, -43, -13, 15, 46, 42, 16, 7, 8, 7, 7, + -1, -6, -10, -4, -27, -45, -36, 5, 16, 7, -5, -5, 20, 22, 19, 19, + 22, 7, -15, -43, -62, -29, 3, 35, 43, 27, 11, 9, 8, 4, 2, -9, + -13, -7, -15, -30, -43, -16, 12, 13, 4, -8, 12, 24, 17, 16, 24, 25, + -3, -38, -72, -52, -9, 25, 42, 30, 21, 8, 14, 4, 6, -3, -13, -12, + -13, -18, -36, -34, 3, 14, 9, -9, 5, 26, 18, 13, 26, 34, 13, -31, + -69, -68, -16, 19, 35, 29, 22, 6, 16, 3, 2, 6, -5, -15, -20, -19, + -21, -34, -17, 8, 16, -2, -3, 24, 27, 16, 23, 34, 32, -10, -56, -80, + -45, 6, 29, 29, 22, 10, 14, 13, -4, 6, 7, -8, -27, -27, -18, -20, + -28, -8, 14, 8, -7, 11, 29, 21, 17, 25, 35, 16, -36, -77, -67, -14, + 25, 30, 22, 11, 10, 19, 5, 2, 6, 5, -18, -34, -25, -13, -23, -19, + 4, 13, 0, 7, 24, 32, 24, 22, 31, 30, -12, -62, -76, -41, 9, 28, + 24, 15, 6, 18, 16, 6, 6, 7, -7, -32, -37, -16, -18, -24, -8, 11, + 7, 7, 20, 31, 35, 25, 24, 33, 9, -40, -72, -58, -16, 17, 27, 16, + 6, 10, 22, 12, 8, 8, 2, -23, -43, -26, -16, -24, -18, 2, 6, 7, + 21, 29, 36, 32, 21, 27, 22, -21, -57, -67, -38, -4, 26, 21, 9, 3, + 18, 25, 18, 10, 2, -11, -42, -36, -24, -27, -23, -9, 5, 2, 17, 32, + 42, 36, 27, 18, 25, -2, -39, -58, -51, -27, 11, 27, 11, 1, 9, 24, + 25, 21, 5, -8, -31, -37, -30, -33, -24, -15, 0, -2, 13, 31, 48, 47, + 33, 15, 18, 10, -27, -50, -52, -44, -12, 21, 21, 5, -1, 13, 33, 30, + 16, -6, -26, -39, -33, -35, -28, -20, -10, -8, 4, 27, 51, 61, 45, 21, + 13, 14, -11, -39, -40, -44, -36, 1, 25, 16, 1, 2, 27, 40, 28, 3, + -22, -38, -38, -32, -33, -21, -18, -14, -8, 18, 50, 66, 60, 27, 7, 12, + -3, -31, -36, -37, -46, -27, 18, 26, 5, -3, 8, 35, 43, 16, -14, -36, + -43, -32, -32, -25, -16, -23, -14, 6, 46, 64, 74, 49, 9, 4, 7, -23, + -37, -34, -41, -44, -8, 31, 19, -5, 0, 21, 47, 33, -2, -33, -43, -43, + -32, -29, -14, -22, -23, -6, 34, 62, 75, 71, 30, 0, 8, -13, -37, -34, + -35, -45, -34, 18, 31, 5, -5, 7, 35, 44, 12, -23, -45, -49, -40, -29, + -18, -18, -27, -15, 22, 57, 74, 80, 57, 15, 4, -1, -39, -34, -34, -40, + -46, -4, 25, 13, -3, 2, 22, 44, 25, -10, -38, -44, -50, -34, -20, -14, + -31, -21, 5, 47, 63, 81, 76, 38, 8, 9, -30, -45, -35, -36, -43, -20, + 9, 14, 5, 3, 7, 36, 32, 3, -32, -43, -50, -40, -28, -13, -24, -28, + -2, 35, 56, 73, 86, 58, 23, 21, -10, -49, -45, -33, -39, -25, -3, 5, + 5, 8, 5, 18, 32, 17, -19, -45, -49, -41, -35, -22, -19, -31, -12, 28, + 52, 59, 76, 74, 41, 31, 10, -39, -58, -41, -32, -27, -5, -3, 3, 8, + 8, 10, 24, 22, -4, -39, -52, -42, -35, -30, -18, -28, -22, 20, 53, 52, + 60, 73, 62, 43, 31, -18, -56, -61, -35, -28, -9, -6, -3, 3, 9, 10, + 12, 18, 8, -23, -53, -50, -31, -35, -24, -28, -26, 3, 48, 55, 52, 59, + 66, 57, 46, 7, -37, -67, -53, -24, -11, -4, -6, 0, 3, 13, 10, 7, + 10, -6, -38, -58, -36, -30, -30, -26, -26, -11, 33, 60, 56, 49, 59, 67, + 58, 32, -15, -58, -69, -34, -14, -8, -6, 1, -4, 7, 8, 2, 4, 4, + -21, -54, -49, -30, -30, -28, -29, -18, 13, 53, 60, 50, 44, 63, 61, 49, + 11, -33, -71, -49, -19, -9, -10, 5, 2, -1, 4, -1, 4, 5, -5, -38, + -55, -40, -28, -21, -25, -26, -2, 40, 61, 56, 39, 53, 66, 54, 33, -4, + -55, -63, -29, -18, -12, 3, 11, -4, -4, -9, -3, 4, 4, -18, -49, -49, + -35, -18, -18, -25, -16, 24, 51, 60, 42, 43, 66, 57, 42, 21, -23, -63, + -44, -26, -18, -10, 13, 9, -8, -18, -17, 5, 5, -4, -35, -47, -42, -24, + -11, -20, -21, 5, 36, 56, 53, 37, 60, 59, 40, 34, 11, -34, -52, -33, + -21, -15, 1, 21, 2, -19, -33, -10, 8, 3, -20, -42, -41, -33, -14, -16, + -18, -7, 21, 43, 54, 39, 47, 61, 44, 31, 27, -4, -41, -47, -28, -23, + -9, 11, 15, -9, -34, -34, 1, 10, -2, -30, -38, -34, -18, -15, -17, -10, + 10, 27, 43, 42, 42, 53, 54, 36, 24, 14, -15, -42, -36, -32, -22, 1, + 13, 7, -26, -48, -24, 11, 10, -14, -35, -32, -19, -16, -15, -11, 5, 18, + 31, 34, 41, 48, 51, 46, 28, 26, 8, -26, -36, -33, -35, -12, 7, 12, + -8, -45, -47, -9, 13, 5, -24, -32, -17, -14, -16, -11, 6, 14, 20, 26, + 27, 47, 49, 49, 34, 25, 22, -6, -31, -27, -39, -30, -10, 13, 6, -28, + -57, -31, -3, 12, -7, -28, -19, -8, -21, -18, -2, 18, 17, 17, 19, 34, + 47, 53, 42, 34, 30, 13, -22, -20, -30, -44, -32, -4, 15, -7, -45, -49, + -18, 4, 10, -14, -18, 0, -11, -26, -7, 15, 23, 10, 10, 20, 34, 51, + 49, 38, 41, 30, -8, -28, -15, -39, -47, -28, 5, 10, -26, -55, -34, -9, + 10, 3, -13, -4, 1, -21, -19, 3, 25, 13, 5, 9, 18, 36, 54, 39, + 40, 46, 16, -27, -17, -23, -47, -47, -18, 9, -2, -47, -51, -23, 0, 4, + 0, 1, 9, -11, -20, -9, 20, 23, 4, 2, 8, 20, 45, 46, 38, 53, + 41, -13, -30, -19, -36, -52, -40, -9, 5, -23, -53, -35, -6, 4, 3, 6, + 10, 5, -16, -17, 6, 30, 12, 0, -4, 9, 32, 47, 43, 55, 57, 16, + -27, -30, -28, -44, -52, -31, -6, -8, -43, -43, -15, -1, -1, 8, 10, 13, + 2, -18, -11, 21, 23, 6, -5, 0, 19, 33, 41, 56, 67, 44, -5, -34, + -35, -32, -46, -47, -27, -7, -30, -44, -23, -2, -2, 3, 7, 14, 18, -1, + -19, 4, 20, 16, -5, -9, 10, 27, 30, 46, 65, 63, 26, -22, -42, -34, + -41, -46, -40, -18, -25, -39, -28, -4, 1, -1, 5, 10, 24, 19, -8, -6, + 11, 20, 4, -13, 2, 22, 24, 36, 59, 70, 51, 5, -39, -39, -43, -47, + -45, -31, -30, -39, -33, -7, 1, -2, 1, 4, 19, 25, 5, -5, 1, 12, + 13, -12, -12, 18, 25, 21, 46, 68, 69, 36, -17, -39, -44, -51, -43, -33, + -35, -41, -38, -15, 8, 0, 0, 0, 13, 26, 19, 5, 0, -1, 10, -2, + -14, 5, 25, 19, 29, 54, 71, 59, 9, -31, -43, -56, -50, -32, -38, -47, + -42, -26, 8, 10, -3, -3, 7, 20, 23, 16, 8, -5, 3, 2, -17, -6, + 22, 20, 18, 40, 66, 71, 37, -13, -36, -52, -61, -38, -32, -47, -51, -38, + -7, 19, 6, -6, 4, 14, 19, 21, 19, 2, -5, 0, -13, -12, 14, 21, + 13, 27, 53, 71, 57, 12, -25, -42, -61, -54, -33, -38, -52, -50, -22, 13, + 17, -4, 1, 16, 17, 19, 25, 11, -2, -2, -11, -18, 6, 21, 15, 18, + 43, 66, 67, 34, -7, -30, -49, -58, -42, -36, -42, -54, -36, -2, 20, 4, + -4, 11, 16, 17, 26, 17, 4, 1, -8, -22, -8, 17, 16, 17, 27, 55, + 66, 48, 10, -25, -36, -49, -52, -42, -39, -47, -46, -18, 13, 14, -1, 3, + 13, 19, 27, 18, 2, 5, 1, -14, -17, 6, 13, 16, 26, 44, 64, 54, + 27, -15, -30, -33, -49, -50, -43, -44, -45, -30, -1, 13, 3, 6, 10, 22, + 30, 21, 3, 2, 2, -3, -18, -9, 8, 11, 23, 35, 55, 58, 37, 1, + -25, -18, -33, -51, -48, -46, -41, -30, -17, 6, 3, 7, 9, 16, 30, 27, + 9, 3, 3, 1, -10, -18, 0, 3, 12, 37, 46, 52, 40, 15, -23, -16, + -14, -39, -48, -48, -45, -31, -20, -7, 1, 4, 14, 13, 21, 26, 16, 2, + 1, 1, 1, -16, -12, 1, 5, 29, 50, 47, 39, 21, -11, -21, -3, -23, + -41, -45, -47, -37, -21, -13, -6, 1, 16, 20, 22, 22, 18, 10, 2, 1, + 6, -7, -16, -10, 0, 16, 51, 53, 38, 22, -1, -21, -1, -4, -30, -41, + -45, -45, -28, -13, -13, -8, 13, 24, 26, 15, 13, 15, 8, -4, 1, -2, + -11, -15, -11, 2, 40, 56, 44, 21, 1, -16, -10, 5, -16, -32, -38, -41, + -36, -22, -14, -15, 4, 24, 32, 18, 7, 14, 14, 4, -2, -1, -8, -12, + -15, -6, 24, 50, 51, 28, 1, -13, -14, 4, 1, -18, -31, -35, -36, -33, + -21, -21, -5, 19, 38, 23, 3, 5, 17, 15, 2, -3, -7, -8, -18, -14, + 12, 39, 50, 35, 2, -14, -14, -3, 6, -6, -24, -27, -32, -40, -25, -22, + -12, 8, 35, 34, 10, 2, 5, 19, 9, -6, -4, -3, -15, -18, 4, 30, + 42, 40, 13, -17, -16, -7, 3, 5, -14, -21, -24, -41, -37, -23, -18, -1, + 22, 37, 17, 4, -1, 11, 17, 1, -7, -4, -12, -22, -6, 24, 35, 33, + 25, -7, -26, -15, 2, 14, 3, -16, -19, -33, -42, -27, -23, -10, 15, 28, + 27, 8, 2, 5, 20, 11, -4, -6, -7, -19, -11, 17, 31, 26, 25, 6, + -24, -25, -6, 11, 14, -3, -13, -25, -39, -33, -23, -17, 7, 19, 26, 19, + 4, 1, 15, 14, -1, -5, -10, -14, -22, 8, 33, 28, 20, 16, -13, -26, + -17, 9, 22, 5, -8, -18, -37, -35, -28, -23, -4, 12, 16, 28, 12, 1, + 12, 18, 3, -2, -9, -10, -27, -10, 29, 34, 18, 16, 2, -26, -29, -3, + 27, 19, -4, -10, -29, -36, -30, -29, -12, 9, 3, 18, 21, 7, 12, 17, + 3, -2, -7, -7, -19, -26, 15, 36, 21, 12, 9, -15, -30, -18, 19, 30, + 6, -5, -21, -32, -25, -29, -22, 6, 0, 3, 20, 14, 12, 18, 12, 0, + -9, -12, -9, -26, -4, 31, 28, 11, 10, -6, -24, -29, 3, 35, 19, -3, + -15, -26, -19, -23, -31, -6, 4, -7, 13, 19, 17, 20, 18, 9, -9, -19, + -5, -17, -20, 16, 34, 18, 9, 0, -16, -25, -10, 30, 29, 3, -10, -19, + -19, -16, -29, -19, 3, -9, -5, 13, 21, 24, 16, 13, 1, -23, -14, -12, + -19, -2, 28, 21, 8, 1, -11, -23, -19, 16, 41, 14, -8, -13, -9, -13, + -18, -27, -4, -5, -12, -1, 19, 31, 18, 10, 16, -20, -22, -13, -14, -12, + 18, 26, 12, 4, -4, -17, -18, -1, 38, 31, -5, -14, -7, -7, -14, -24, + -13, -3, -13, -12, 7, 30, 34, 14, 18, -5, -33, -18, -10, -14, 1, 19, + 14, 6, -8, -13, -15, -2, 19, 40, 8, -13, -9, -4, -8, -18, -20, -9, + -14, -16, -7, 22, 37, 23, 16, 10, -26, -28, -13, -9, -5, 14, 14, 9, + -9, -17, -13, -1, 8, 31, 26, -6, -10, -4, -2, -12, -19, -11, -11, -17, + -12, 6, 34, 29, 15, 16, -7, -35, -25, -9, -6, 8, 14, 12, 1, -15, + -14, 3, 10, 19, 29, 8, -10, -9, 1, -7, -20, -10, -9, -17, -17, -1, + 30, 35, 18, 15, 5, -28, -33, -17, -6, -4, 8, 13, 5, -14, -19, 1, + 14, 14, 20, 17, 0, -8, -2, -3, -14, -18, -9, -12, -18, -6, 21, 37, + 26, 7, 10, -13, -33, -24, -6, -2, 0, 9, 11, -5, -19, -7, 16, 18, + 13, 18, 11, -2, -6, -3, -6, -22, -10, -11, -16, -11, 17, 34, 32, 9, + 9, 2, -26, -30, -14, -2, -5, 3, 8, 3, -16, -12, 8, 21, 13, 13, + 15, 2, -3, -5, -5, -20, -16, -8, -16, -20, 6, 32, 34, 14, -4, 6, + -12, -26, -20, -7, -6, -4, 4, 7, -2, -15, 1, 17, 15, 9, 15, 10, + 0, -3, -7, -15, -22, -4, -7, -19, -7, 29, 36, 20, -6, -1, 0, -17, + -19, -12, -9, -7, -1, 2, 6, -3, -8, 10, 18, 9, 8, 21, 4, -2, + -8, -13, -20, -12, -2, -16, -14, 14, 39, 26, -3, -17, 1, -6, -16, -12, + -7, -9, -9, 0, 3, 11, -3, 0, 15, 13, 3, 19, 12, -8, -6, -14, + -19, -16, 0, -6, -17, 3, 33, 35, 5, -18, -9, 1, -15, -11, -8, -8, + -16, -8, 1, 15, 15, 3, 11, 19, 2, 12, 26, 0, -10, -13, -21, -11, + 1, -1, -18, -2, 23, 35, 17, -12, -21, -2, -8, -9, -8, -9, -12, -17, + -5, 10, 22, 8, 7, 18, 7, -1, 23, 13, -13, -19, -23, -14, 5, 2, + -15, -13, 17, 30, 22, -3, -24, -7, -2, -9, -6, -10, -8, -21, -19, 5, + 22, 22, 13, 15, 13, -3, 11, 18, -4, -20, -28, -20, 4, 11, -10, -18, + 6, 26, 17, 3, -20, -12, -2, -11, -7, -8, -8, -16, -27, -7, 19, 30, + 21, 19, 15, 4, 3, 18, 2, -17, -33, -24, 0, 17, 1, -16, -6, 24, + 19, 5, -17, -18, 1, -8, -12, -7, -11, -10, -22, -14, 10, 29, 29, 32, + 23, 13, 0, 9, 6, -12, -28, -36, -7, 13, 12, -8, -17, 12, 24, 6, + -10, -20, 1, 1, -13, -9, -12, -16, -20, -17, 0, 21, 27, 31, 35, 20, + 7, 0, 2, -13, -19, -37, -19, 8, 18, 9, -16, -9, 20, 11, -2, -25, + -13, 8, -4, -16, -13, -18, -23, -17, 0, 14, 29, 27, 43, 35, 17, -1, + -4, -13, -22, -29, -31, -2, 17, 20, -5, -21, 6, 16, 5, -16, -25, 4, + 11, -12, -17, -20, -27, -19, -2, 13, 26, 27, 36, 46, 32, 7, -8, -18, + -26, -25, -32, -16, 12, 26, 11, -18, -11, 4, 13, -1, -27, -12, 14, 2, + -21, -23, -31, -26, -11, 10, 24, 30, 29, 43, 50, 24, -4, -16, -34, -28, + -28, -27, -1, 27, 24, -5, -21, -12, 6, 16, -13, -28, 1, 13, -9, -23, + -33, -32, -18, 2, 24, 34, 33, 34, 50, 49, 12, -11, -34, -37, -28, -25, + -14, 14, 28, 10, -10, -25, -9, 21, 15, -27, -15, 12, 2, -18, -33, -36, + -24, -7, 13, 30, 39, 42, 35, 54, 36, 1, -29, -45, -35, -26, -17, -1, + 20, 19, 2, -23, -30, 1, 30, -5, -32, 1, 7, -8, -27, -37, -25, -12, + -1, 23, 37, 51, 38, 41, 49, 16, -15, -41, -40, -31, -21, -11, 4, 19, + 15, -8, -33, -19, 22, 20, -21, -13, 2, -6, -17, -36, -32, -11, -8, 9, + 28, 48, 54, 36, 48, 30, 3, -30, -41, -34, -24, -15, -6, 2, 17, 8, + -19, -37, 0, 31, 3, -20, -6, -4, -7, -31, -35, -9, -3, -4, 16, 37, + 62, 44, 41, 33, 13, -11, -36, -39, -29, -21, -11, -11, 6, 14, -2, -28, + -24, 15, 22, -5, -10, -11, -10, -20, -35, -13, 2, -5, 2, 21, 55, 64, + 46, 37, 19, 2, -23, -36, -28, -23, -17, -18, -17, 10, 11, -12, -32, -7, + 23, 16, -7, -14, -17, -8, -27, -23, 1, 1, 0, 6, 31, 63, 60, 46, + 21, 7, -12, -29, -24, -18, -24, -23, -27, -11, 11, 5, -16, -19, 11, 21, + 4, -9, -21, -15, -17, -30, -5, 7, 2, -1, 9, 48, 65, 59, 30, 13, + -4, -25, -19, -6, -22, -33, -32, -31, -3, 7, -3, -20, -4, 14, 11, -1, + -11, -19, -13, -20, -16, 9, 7, 2, -3, 27, 60, 69, 44, 12, 7, -18, + -20, 1, -4, -35, -38, -34, -22, -9, 4, -2, -11, 8, 8, 2, -6, -19, + -23, -14, -16, 3, 13, 2, 2, 12, 47, 65, 62, 22, 10, -3, -21, -9, + 9, -17, -46, -40, -34, -23, -6, 4, -1, 3, 7, 2, -4, -13, -25, -18, + -11, -4, 18, 3, -2, 5, 30, 58, 66, 39, 12, 9, -10, -18, 8, 5, + -41, -49, -38, -33, -18, -4, 2, 7, 8, 2, -7, -12, -18, -23, -12, -6, + 18, 15, -8, 0, 21, 44, 62, 48, 22, 14, 7, -16, -7, 18, -18, -52, + -44, -42, -32, -18, -1, 12, 10, 6, -8, -20, -11, -18, -19, -10, 14, 24, + 2, -5, 14, 34, 57, 51, 27, 19, 20, -1, -13, 15, -1, -42, -45, -49, + -38, -28, -15, 13, 19, 10, -1, -23, -16, -11, -24, -10, 6, 21, 14, -5, + 3, 24, 48, 58, 29, 17, 24, 18, -6, 4, 8, -28, -38, -46, -50, -36, + -29, 3, 22, 15, 4, -18, -31, -7, -20, -17, 5, 11, 18, 4, -2, 15, + 37, 58, 35, 11, 26, 31, 11, -2, 6, -13, -32, -39, -55, -45, -38, -17, + 21, 23, 11, -10, -31, -18, -11, -25, 1, 9, 14, 15, 0, 7, 26, 49, + 49, 13, 10, 33, 26, 8, 4, -5, -25, -35, -46, -53, -41, -35, 5, 24, + 17, 0, -25, -26, -14, -24, -9, 6, 5, 17, 6, 6, 20, 38, 55, 30, + 3, 25, 38, 18, 10, -4, -16, -30, -42, -51, -46, -41, -16, 21, 23, 14, + -16, -30, -16, -17, -17, 0, 2, 12, 16, 3, 17, 28, 46, 49, 14, 13, + 39, 30, 17, 4, -9, -20, -38, -49, -50, -50, -34, 4, 21, 20, 4, -29, + -23, -15, -15, -8, -3, 7, 19, 8, 9, 26, 35, 47, 29, 6, 29, 35, + 26, 13, -5, -18, -29, -42, -49, -51, -50, -16, 11, 23, 18, -17, -34, -14, + -15, -9, -10, -2, 17, 14, 5, 21, 33, 44, 38, 14, 23, 37, 30, 20, + 6, -8, -26, -34, -47, -52, -54, -34, 0, 16, 19, 5, -29, -20, -13, -10, + -9, -10, 4, 19, 11, 13, 29, 37, 36, 22, 22, 39, 32, 23, 10, 2, + -18, -32, -40, -54, -56, -49, -23, 8, 17, 11, -15, -26, -11, -13, -9, -15, + -11, 14, 17, 10, 23, 34, 36, 24, 21, 35, 42, 26, 12, 2, -4, -23, + -31, -47, -57, -50, -33, -7, 17, 11, -2, -18, -12, -12, -11, -10, -21, -6, + 18, 19, 21, 33, 35, 28, 23, 34, 51, 40, 12, -2, 1, -9, -27, -43, + -59, -53, -39, -23, 4, 15, 1, -10, -14, -9, -8, -10, -22, -18, 5, 19, + 16, 27, 34, 28, 23, 27, 47, 53, 27, -3, -4, -1, -13, -33, -53, -57, + -45, -31, -13, 14, 4, -4, -11, -9, -9, -11, -19, -28, -16, 10, 24, 23, + 35, 24, 26, 26, 38, 60, 44, 2, -13, -3, -5, -19, -44, -58, -49, -33, + -26, 1, 14, 1, -4, -5, 0, -7, -14, -29, -26, -11, 20, 27, 30, 32, + 21, 27, 34, 59, 58, 22, -11, -10, -6, -10, -29, -55, -53, -38, -34, -16, + 12, 9, -5, -8, 5, 1, -16, -31, -32, -28, 0, 26, 26, 33, 23, 24, + 33, 49, 61, 37, 3, -15, -8, -11, -19, -43, -56, -44, -34, -25, -2, 17, + 5, -11, 2, 12, -2, -23, -32, -35, -23, 14, 26, 27, 35, 23, 32, 45, + 58, 47, 19, -5, -9, -10, -16, -27, -46, -48, -41, -34, -18, 11, 20, -6, + -10, 12, 9, -18, -34, -38, -29, -7, 17, 27, 32, 30, 30, 46, 52, 51, + 28, 6, -8, -9, -15, -24, -32, -41, -45, -40, -30, -1, 23, 10, -12, 2, + 17, -2, -31, -39, -32, -18, -6, 18, 29, 38, 32, 45, 54, 54, 33, 11, + 2, -9, -11, -19, -32, -33, -41, -45, -40, -18, 16, 19, 2, -6, 13, 12, + -20, -43, -35, -21, -18, -5, 21, 35, 36, 46, 58, 52, 38, 17, 9, -5, + -9, -13, -29, -32, -28, -41, -43, -36, 0, 22, 18, -4, -3, 17, 2, -33, + -43, -25, -18, -16, 4, 27, 38, 47, 64, 57, 40, 18, 10, 5, -7, -10, + -22, -39, -24, -30, -42, -39, -22, 13, 28, 14, -9, 3, 17, -16, -51, -36, + -17, -23, -18, 8, 35, 50, 66, 68, 43, 23, 12, 13, -1, -11, -17, -32, + -27, -22, -40, -38, -37, -10, 22, 34, 1, -10, 8, 6, -39, -48, -27, -19, + -25, -10, 18, 49, 66, 78, 54, 26, 17, 16, 3, -7, -15, -25, -29, -12, + -32, -37, -35, -28, 3, 38, 26, -7, -4, 11, -15, -46, -42, -26, -23, -24, + -2, 34, 66, 81, 70, 30, 19, 21, 10, -5, -11, -25, -29, -12, -20, -37, + -33, -39, -17, 25, 46, 6, -11, 2, 0, -29, -44, -41, -30, -27, -17, 12, + 58, 79, 84, 46, 19, 22, 19, 2, -7, -26, -35, -12, -1, -29, -33, -39, + -36, 3, 46, 31, -11, -6, -1, -14, -38, -46, -39, -32, -22, -5, 40, 76, + 88, 64, 23, 22, 30, 12, -8, -20, -39, -22, 0, -13, -29, -33, -43, -20, + 24, 49, 13, -12, 2, -6, -26, -45, -45, -39, -32, -15, 19, 68, 85, 77, + 32, 22, 35, 27, 0, -18, -36, -38, -6, 3, -17, -29, -44, -37, -2, 40, + 34, -8, -6, 3, -18, -44, -47, -44, -43, -21, 3, 49, 76, 80, 53, 21, + 35, 39, 15, -18, -35, -42, -23, 2, -3, -19, -33, -42, -23, 16, 46, 16, + -8, 2, -6, -37, -45, -47, -51, -33, -8, 31, 68, 74, 66, 33, 35, 45, + 36, -3, -33, -40, -34, -7, 5, -8, -18, -35, -39, -13, 32, 32, 3, -1, + 5, -26, -46, -50, -52, -44, -20, 15, 59, 68, 69, 50, 32, 42, 48, 21, + -26, -42, -42, -24, 2, 2, -8, -20, -38, -35, 6, 33, 17, -2, 5, -6, + -41, -55, -57, -46, -33, -6, 40, 64, 62, 63, 45, 38, 54, 40, -4, -42, + -50, -40, -11, 6, -2, -8, -24, -41, -19, 17, 28, 10, 0, 1, -26, -52, + -64, -51, -40, -23, 19, 54, 56, 61, 60, 38, 52, 55, 24, -30, -50, -47, + -27, 4, 8, -6, -11, -30, -36, -6, 19, 25, 4, 1, -9, -38, -64, -61, + -42, -36, 0, 44, 55, 51, 66, 50, 49, 62, 46, -5, -48, -51, -40, -11, + 11, 4, -14, -15, -36, -25, 1, 19, 15, -1, -2, -18, -53, -69, -48, -42, + -20, 21, 51, 45, 56, 62, 51, 60, 59, 23, -32, -53, -49, -28, 5, 17, + -12, -18, -22, -32, -12, 9, 20, 1, -6, -5, -29, -70, -62, -48, -32, 2, + 36, 45, 44, 62, 62, 60, 64, 47, -10, -45, -54, -42, -11, 21, 5, -19, + -18, -23, -20, -1, 15, 4, -6, -2, -6, -51, -72, -57, -44, -13, 19, 40, + 41, 51, 65, 66, 69, 63, 14, -32, -47, -50, -30, 10, 14, -12, -16, -18, + -16, -14, 7, 8, -6, -8, -1, -21, -65, -67, -54, -29, 1, 26, 38, 44, + 53, 69, 77, 73, 37, -17, -41, -46, -37, -10, 13, -1, -11, -14, -14, -10, + -6, 9, -5, -6, -11, -3, -43, -67, -68, -42, -15, 12, 27, 40, 47, 65, + 80, 83, 55, 7, -34, -43, -34, -22, -5, 2, -3, -2, -13, -10, -11, 3, + -2, -4, -13, -5, -15, -51, -72, -63, -31, -3, 16, 29, 42, 55, 78, 91, + 68, 25, -11, -40, -32, -22, -21, -9, -1, 8, -1, -19, -11, -3, 1, -5, + -11, -12, -3, -29, -58, -70, -48, -18, 6, 15, 35, 50, 68, 89, 84, 37, + 11, -27, -38, -19, -20, -23, -8, 10, 18, -10, -19, -8, 4, 0, -11, -14, + -7, -20, -42, -63, -60, -37, -4, 7, 23, 41, 67, 82, 90, 53, 19, -4, + -34, -23, -20, -31, -22, 5, 25, 8, -17, -20, 0, 10, -5, -20, -9, -12, + -31, -47, -60, -53, -26, -3, 12, 32, 58, 81, 85, 70, 27, 9, -19, -26, + -19, -28, -31, -8, 24, 21, -2, -26, -11, 14, 10, -20, -18, -8, -24, -33, + -53, -56, -44, -23, 3, 22, 44, 77, 85, 74, 40, 17, -3, -21, -21, -24, + -36, -25, 11, 22, 15, -13, -28, 5, 23, 0, -28, -12, -19, -26, -42, -56, + -48, -39, -17, 12, 34, 62, 84, 73, 52, 26, 9, -12, -21, -22, -31, -30, + -1, 15, 16, 6, -25, -14, 23, 19, -17, -21, -13, -24, -34, -54, -44, -39, + -36, -9, 27, 46, 79, 79, 59, 38, 16, -2, -17, -25, -25, -27, -10, 5, + 10, 15, -4, -24, 5, 29, 5, -24, -18, -19, -28, -48, -50, -35, -38, -28, + 10, 33, 62, 82, 62, 46, 27, 4, -8, -23, -24, -25, -15, -3, 0, 8, + 6, -12, -9, 22, 25, -6, -21, -22, -28, -45, -53, -39, -30, -37, -11, 20, + 43, 75, 66, 53, 41, 10, -8, -16, -25, -23, -15, -2, -4, -5, 4, 1, + -7, 8, 29, 19, -9, -21, -24, -42, -55, -48, -30, -31, -19, 5, 23, 61, + 74, 58, 53, 26, -7, -11, -18, -25, -14, 0, 1, -16, -8, 4, 0, 3, + 20, 28, 11, -16, -19, -38, -58, -55, -35, -27, -16, -1, 5, 32, 63, 61, + 56, 44, 3, -17, -13, -22, -19, -4, 5, -8, -21, -6, 7, 8, 12, 25, + 25, 2, -17, -26, -54, -64, -47, -32, -11, 5, 3, 16, 40, 60, 58, 56, + 26, -16, -19, -16, -20, -8, 0, -4, -20, -22, 1, 12, 9, 17, 30, 20, + -2, -15, -42, -68, -57, -44, -19, 11, 6, 10, 19, 42, 58, 58, 45, 6, + -23, -18, -13, -13, -3, -3, -10, -26, -14, 9, 15, 12, 26, 27, 10, -7, + -25, -61, -68, -54, -36, 10, 15, 13, 16, 19, 42, 55, 52, 31, -9, -25, + -18, -15, -7, -3, -9, -23, -26, -2, 15, 19, 19, 26, 18, 7, -10, -41, + -72, -60, -51, -8, 25, 22, 20, 13, 19, 45, 51, 44, 19, -15, -28, -15, + -7, -4, -9, -19, -28, -14, 6, 18, 18, 24, 22, 12, 1, -17, -55, -67, + -56, -35, 19, 33, 30, 20, 9, 23, 44, 48, 39, 6, -22, -25, -9, -8, + -9, -15, -29, -21, -3, 10, 16, 20, 23, 13, 7, -4, -31, -63, -61, -50, + -11, 33, 37, 30, 12, 7, 24, 44, 48, 28, -4, -28, -14, -4, -14, -14, + -27, -27, -8, 5, 13, 15, 19, 19, 11, 3, -12, -44, -64, -58, -31, 17, + 40, 39, 24, 8, 3, 30, 46, 42, 16, -18, -21, -6, -16, -18, -26, -32, + -15, 1, 6, 10, 10, 15, 12, 10, -3, -23, -51, -63, -50, -4, 34, 41, + 33, 17, -4, 10, 35, 42, 32, 5, -15, -8, -10, -18, -21, -30, -22, 0, + 3, -2, -2, 6, 5, 4, 3, -7, -25, -45, -45, -18, 25, 33, 32, 21, + 7, 8, 20, 30, 31, 20, 3, -7, -10, -14, -17, -23, -29, -12, 6, -2, + -11, -11, -4, 2, 3, -7, -10, -27, -33, -21, 13, 27, 23, 19, 8, 15, + 17, 18, 21, 23, 19, 2, -12, -10, -9, -15, -27, -28, -2, 9, -8, -18, + -17, -4, 9, -6, -7, -10, -17, -13, 2, 21, 20, 14, 4, 15, 25, 15, + 11, 14, 19, 13, -13, -17, -6, -5, -20, -36, -23, 4, 6, -18, -28, -20, + 6, 6, 0, 3, 5, 5, 28, 31, 31, 49, 55, 35, 11, 27, 26, 4, + 7, 11, 31, 54, 38, 26, 34, 35, 20, -10, -32, -43, -47, -43, -20, -7, + -37, -55, -62, -61, -63, -34, -21, -35, -28, -10, 15, 24, 23, 5, -31, -38, + -6, 23, 19, 15, 24, 20, 31, 57, 54, 28, 13, 33, 20, 1, 4, 17, + 38, 44, 33, 31, 43, 36, 10, -14, -34, -53, -53, -46, -22, -22, -38, -46, + -54, -60, -58, -29, -25, -39, -29, -12, 11, 25, 27, 6, -31, -33, -3, 27, + 32, 21, 13, 16, 38, 60, 53, 26, 18, 28, 11, -2, 8, 26, 37, 34, + 36, 42, 47, 31, 6, -14, -41, -61, -54, -49, -26, -30, -41, -40, -44, -54, + -48, -23, -28, -41, -33, -7, 14, 26, 29, 3, -32, -27, 6, 33, 35, 18, + 5, 21, 45, 61, 49, 25, 30, 22, 0, -5, 9, 37, 39, 27, 33, 47, + 50, 31, 1, -22, -51, -65, -59, -45, -31, -40, -36, -29, -35, -49, -41, -28, + -39, -44, -26, -8, 6, 27, 31, -5, -31, -18, 14, 33, 31, 17, 4, 25, + 48, 57, 45, 32, 27, 9, -6, -5, 14, 43, 36, 29, 39, 51, 50, 31, + 0, -32, -65, -73, -62, -37, -36, -46, -36, -23, -26, -37, -32, -35, -46, -42, + -22, -11, 2, 30, 28, -8, -29, -12, 22, 33, 32, 15, 4, 25, 49, 58, + 50, 36, 20, 2, -9, -3, 21, 43, 37, 32, 44, 55, 53, 33, -7, -42, + -67, -72, -64, -43, -43, -46, -35, -17, -17, -24, -31, -40, -47, -39, -18, -15, + 0, 33, 22, -14, -22, 5, 29, 29, 28, 11, 7, 23, 49, 54, 50, 37, + 13, -6, -11, -6, 25, 44, 38, 26, 40, 57, 54, 28, -12, -48, -70, -73, + -66, -43, -43, -43, -29, -12, -15, -16, -32, -48, -51, -38, -24, -19, 4, 31, + 12, -16, -14, 21, 34, 24, 24, 13, 10, 27, 49, 53, 53, 33, 6, -9, + -16, -4, 33, 48, 37, 24, 45, 61, 54, 23, -15, -60, -76, -76, -60, -48, + -45, -38, -26, -11, -3, -5, -33, -49, -52, -35, -25, -21, 7, 24, 1, -15, + -1, 34, 30, 23, 29, 17, 5, 26, 49, 55, 53, 26, -3, -16, -16, 4, + 38, 43, 33, 33, 49, 59, 45, 19, -18, -63, -78, -79, -58, -50, -39, -31, + -21, -11, -2, -3, -30, -49, -51, -35, -29, -20, 8, 12, -10, -11, 17, 37, + 27, 29, 29, 13, 2, 33, 56, 55, 38, 18, -7, -19, -17, 13, 40, 42, + 33, 35, 52, 58, 40, 10, -28, -68, -84, -78, -56, -47, -36, -30, -17, -7, + 5, -4, -30, -49, -51, -34, -30, -18, 10, 1, -18, -9, 30, 39, 26, 32, + 28, 9, 7, 38, 51, 45, 35, 16, -13, -28, -11, 27, 41, 41, 34, 45, + 58, 54, 29, 7, -33, -69, -80, -78, -59, -43, -31, -24, -15, -3, 9, -4, + -29, -51, -51, -33, -27, -8, 8, -13, -24, -1, 40, 41, 29, 31, 22, 7, + 15, 46, 48, 38, 33, 11, -19, -28, -7, 26, 42, 36, 39, 54, 54, 48, + 20, 3, -39, -68, -79, -78, -54, -37, -32, -27, -16, 5, 11, -6, -31, -50, + -49, -33, -24, -3, -3, -29, -26, 13, 44, 36, 30, 32, 17, 7, 28, 43, + 37, 31, 28, 4, -17, -27, -5, 24, 46, 43, 48, 56, 50, 41, 20, -1, + -47, -64, -82, -78, -48, -35, -34, -26, -14, 6, 9, -10, -31, -46, -43, -33, + -21, 1, -16, -38, -15, 24, 38, 35, 44, 33, 10, 15, 37, 43, 30, 22, + 18, 4, -20, -29, 0, 30, 43, 48, 54, 52, 46, 35, 19, -9, -41, -60, + -83, -73, -44, -29, -37, -27, -12, 6, 8, -10, -28, -45, -43, -25, -9, -3, + -33, -43, -4, 32, 35, 37, 49, 24, 7, 26, 47, 35, 17, 11, 14, 3, + -21, -30, 6, 30, 44, 60, 56, 44, 37, 33, 15, -11, -40, -63, -82, -61, + -36, -33, -39, -26, -13, 0, 4, -9, -29, -42, -37, -18, -7, -13, -39, -34, + 2, 30, 34, 45, 49, 16, 11, 37, 45, 26, 11, 8, 9, -1, -26, -25, + 17, 31, 46, 62, 52, 42, 29, 26, 15, -12, -45, -64, -71, -48, -34, -35, + -33, -27, -16, 1, 2, -10, -23, -41, -32, -12, -6, -29, -46, -28, 12, 26, + 36, 54, 43, 10, 23, 52, 43, 18, -2, 5, 5, -7, -25, -11, 19, 22, + 49, 61, 50, 40, 24, 20, 15, -10, -47, -62, -62, -45, -34, -30, -30, -23, + -16, -6, -1, -8, -25, -38, -29, -9, -10, -39, -42, -19, 5, 23, 48, 57, + 33, 7, 32, 57, 39, 8, -7, 3, -2, -16, -16, 1, 20, 22, 48, 55, + 46, 39, 17, 16, 17, -9, -48, -58, -54, -40, -37, -28, -26, -22, -23, -5, + 2, -11, -28, -37, -27, -10, -18, -44, -35, -18, 3, 31, 54, 52, 25, 13, + 45, 61, 29, -4, -10, 0, -5, -16, -8, 4, 21, 21, 50, 54, 45, 31, + 4, 20, 18, -15, -43, -48, -48, -39, -33, -28, -25, -22, -21, 0, -1, -19, + -29, -29, -22, -11, -29, -42, -30, -17, 3, 38, 61, 46, 24, 25, 53, 58, + 20, -10, -9, -5, -16, -12, 4, 11, 22, 17, 48, 51, 43, 16, 2, 18, + 13, -15, -35, -46, -43, -38, -31, -23, -27, -24, -13, 3, -8, -25, -29, -27, + -22, -18, -36, -38, -31, -19, 6, 46, 60, 36, 24, 33, 56, 44, 10, -8, + -9, -12, -24, -7, 14, 23, 18, 11, 45, 47, 39, 13, 5, 16, 1, -19, + -22, -39, -45, -45, -31, -20, -24, -16, -6, -3, -19, -24, -25, -26, -22, -24, + -39, -35, -25, -13, 8, 54, 64, 36, 29, 41, 56, 36, 5, -12, -11, -14, + -26, -6, 24, 33, 7, 12, 45, 44, 30, 13, 10, 17, -4, -17, -16, -34, + -46, -50, -30, -20, -23, -12, 1, -11, -26, -27, -24, -21, -19, -34, -48, -32, + -23, -10, 13, 66, 65, 33, 32, 48, 55, 25, 0, -8, -1, -18, -36, -4, + 40, 33, -1, 17, 37, 35, 25, 10, 14, 10, -13, -15, -9, -26, -46, -51, + -32, -18, -15, -4, 3, -17, -31, -28, -25, -20, -26, -48, -48, -27, -20, -13, + 19, 71, 61, 28, 33, 56, 50, 12, -8, -2, 5, -24, -41, 2, 52, 29, + -1, 24, 36, 26, 16, 14, 19, 6, -19, -12, 1, -21, -49, -50, -28, -12, + -3, 2, -2, -25, -32, -29, -24, -14, -31, -61, -44, -17, -15, -9, 28, 72, + 61, 25, 38, 61, 41, 7, -7, 4, 3, -32, -36, 9, 45, 21, 4, 30, + 33, 15, 11, 18, 17, -1, -18, -7, -4, -22, -47, -45, -24, -6, 2, 5, + -7, -27, -34, -28, -21, -14, -42, -69, -40, -11, -16, -3, 41, 68, 53, 29, + 48, 61, 32, 0, -5, 8, 2, -33, -28, 9, 31, 16, 16, 34, 22, 0, + 10, 24, 10, -9, -19, -6, -8, -26, -38, -34, -20, -10, 1, 11, -9, -33, + -31, -32, -25, -18, -50, -65, -40, -15, -8, 13, 47, 65, 50, 33, 54, 62, + 24, -2, 2, 12, -6, -31, -20, 12, 21, 10, 28, 34, 9, -5, 20, 20, + -2, -13, -10, -4, -18, -33, -26, -16, -19, -14, 6, 8, -14, -31, -32, -29, + -29, -31, -51, -69, -47, -12, 2, 21, 49, 56, 43, 45, 62, 54, 16, -2, + 7, 9, -13, -22, -4, 12, 7, 13, 37, 33, 7, -4, 23, 9, -8, -8, + -2, -8, -33, -38, -7, -1, -22, -19, 11, 7, -21, -29, -29, -29, -31, -32, + -55, -80, -49, -7, 16, 31, 43, 45, 44, 56, 66, 45, 12, 2, 10, 3, + -18, -13, 7, 9, -2, 17, 38, 22, 1, 5, 17, 4, -14, -12, -1, -11, + -43, -38, 6, 5, -22, -15, 12, 0, -23, -26, -28, -31, -32, -36, -60, -82, + -46, 3, 24, 35, 38, 41, 46, 59, 62, 41, 13, -1, 3, -6, -18, 3, + 22, 2, -9, 20, 36, 18, 10, 7, 4, -5, -17, -9, -2, -18, -55, -30, + 17, 6, -20, -10, 6, -5, -16, -26, -32, -27, -30, -42, -69, -84, -41, 13, + 31, 42, 37, 38, 45, 63, 65, 41, 12, 3, 1, -18, -10, 23, 27, -2, + -12, 17, 36, 26, 13, 4, -2, -5, -14, -14, -11, -26, -54, -19, 21, 8, + -16, -8, 6, -7, -20, -30, -33, -24, -33, -50, -74, -82, -32, 18, 34, 42, + 38, 34, 50, 69, 58, 34, 16, 7, -9, -29, -2, 41, 32, -7, -15, 11, + 34, 30, 9, 2, -3, -7, -23, -21, -15, -30, -52, -10, 18, 10, -8, -4, + 5, -4, -25, -33, -26, -22, -42, -59, -79, -72, -20, 23, 36, 41, 37, 34, + 54, 74, 53, 22, 17, 15, -17, -34, 10, 52, 37, -8, -11, 12, 33, 23, + 8, 4, -1, -16, -31, -25, -18, -38, -49, -3, 19, 11, -4, 0, 7, -8, + -34, -31, -19, -26, -52, -62, -79, -55, -7, 23, 41, 47, 41, 33, 61, 75, + 43, 22, 21, 13, -26, -33, 17, 58, 39, -6, -8, 13, 27, 10, 5, 13, + -2, -32, -43, -32, -19, -38, -36, -3, 12, 4, 4, 13, 6, -22, -41, -31, + -13, -33, -59, -71, -76, -35, 2, 20, 39, 53, 47, 39, 60, 62, 37, 26, + 22, 5, -33, -29, 26, 64, 40, 0, -5, 12, 21, 8, 16, 10, -13, -39, + -49, -37, -25, -41, -30, -6, 9, 9, 13, 23, 0, -30, -44, -26, -13, -45, + -67, -76, -68, -20, 10, 19, 39, 55, 50, 46, 57, 50, 37, 30, 16, -3, + -34, -22, 34, 65, 40, 13, -2, 6, 19, 12, 21, 5, -23, -49, -52, -38, + -33, -36, -24, -9, 10, 12, 25, 23, -11, -29, -43, -27, -21, -55, -73, -77, + -50, -2, 19, 19, 35, 59, 59, 49, 45, 40, 36, 27, 4, -10, -24, -12, + 31, 59, 44, 22, -5, 4, 19, 20, 12, -4, -27, -52, -50, -45, -39, -24, + -23, -13, 16, 20, 30, 15, -16, -28, -37, -30, -36, -64, -79, -73, -28, 17, + 24, 14, 36, 65, 68, 45, 33, 39, 40, 22, -2, -5, -11, -11, 28, 58, + 57, 20, -13, 0, 27, 23, 1, -15, -35, -58, -55, -52, -39, -20, -22, -9, + 20, 29, 30, 10, -15, -31, -39, -32, -48, -72, -86, -59, -4, 27, 19, 17, + 44, 77, 69, 31, 26, 40, 38, 14, -6, 0, 1, -11, 26, 67, 62, 10, + -18, 6, 31, 20, -5, -22, -44, -66, -61, -50, -31, -17, -24, -7, 24, 34, + 31, 3, -17, -31, -36, -40, -61, -73, -76, -46, 11, 34, 20, 22, 56, 83, + 60, 22, 24, 46, 32, 5, -4, 9, 0, -8, 31, 73, 53, 0, -13, 16, + 28, 14, -15, -31, -51, -74, -64, -43, -25, -22, -25, -1, 30, 37, 20, -2, + -20, -36, -39, -55, -69, -75, -69, -32, 21, 36, 22, 31, 63, 76, 50, 22, + 25, 49, 29, 3, 4, 9, 2, 0, 43, 74, 37, -8, -1, 28, 24, 8, + -22, -42, -65, -80, -60, -31, -25, -31, -24, 8, 41, 37, 10, -3, -22, -40, + -45, -60, -69, -69, -55, -15, 32, 37, 25, 42, 72, 70, 37, 21, 32, 41, + 20, 5, 15, 8, 0, 9, 46, 62, 26, -7, 8, 28, 21, 4, -29, -53, + -79, -82, -57, -25, -27, -32, -21, 14, 48, 35, -1, -7, -24, -44, -52, -70, + -69, -60, -38, 1, 34, 33, 32, 57, 70, 58, 34, 26, 31, 31, 16, 14, + 14, 3, 8, 25, 47, 47, 18, -2, 13, 25, 19, -2, -33, -64, -87, -83, + -53, -24, -29, -32, -17, 21, 46, 27, -4, -12, -30, -51, -61, -73, -60, -46, + -17, 9, 25, 32, 47, 69, 61, 48, 41, 30, 26, 24, 18, 24, 15, 2, + 14, 37, 42, 34, 17, 9, 19, 20, 11, -7, -35, -79, -97, -79, -45, -21, + -29, -33, -12, 26, 43, 27, -3, -15, -43, -58, -66, -69, -52, -37, -2, 16, + 24, 38, 61, 72, 56, 43, 41, 32, 28, 22, 22, 26, 12, 1, 23, 45, + 34, 21, 8, 17, 22, 19, 4, -18, -47, -93, -97, -70, -40, -29, -33, -22, + -5, 24, 44, 19, -6, -23, -53, -60, -74, -63, -41, -20, 10, 18, 19, 40, + 70, 70, 47, 41, 43, 37, 27, 14, 24, 32, 10, 1, 29, 44, 27, 12, + 7, 28, 32, 9, -11, -27, -56, -100, -94, -64, -43, -38, -31, -7, 0, 27, + 41, 11, -7, -35, -60, -62, -75, -54, -29, -5, 17, 22, 14, 46, 80, 72, + 46, 42, 44, 42, 24, 16, 31, 32, 9, 4, 33, 45, 22, 5, 8, 41, + 34, 0, -22, -36, -69, -100, -92, -65, -40, -44, -25, 0, 5, 28, 36, 4, + -12, -50, -64, -64, -68, -46, -19, 2, 25, 28, 19, 44, 72, 67, 46, 45, + 44, 39, 21, 21, 38, 29, 1, 9, 39, 39, 13, -4, 9, 54, 41, -11, + -38, -51, -76, -91, -92, -65, -44, -47, -17, 12, 11, 21, 27, 6, -24, -59, + -65, -67, -61, -40, -17, 8, 31, 26, 20, 49, 74, 65, 45, 48, 47, 36, + 25, 28, 36, 25, 5, 19, 42, 28, 6, -2, 21, 56, 27, -22, -45, -62, + -83, -92, -84, -65, -49, -37, -8, 15, 16, 22, 23, -1, -38, -65, -66, -65, + -51, -35, -15, 20, 42, 26, 25, 51, 70, 60, 45, 52, 47, 25, 25, 39, + 33, 24, 16, 31, 37, 14, 3, 2, 33, 55, 14, -35, -55, -67, -84, -88, + -84, -68, -47, -28, -1, 17, 22, 24, 17, -14, -54, -66, -64, -61, -46, -32, + -10, 26, 45, 24, 29, 52, 66, 57, 49, 56, 41, 16, 29, 46, 31, 22, + 24, 37, 30, 12, -1, 5, 40, 39, 1, -41, -63, -72, -89, -89, -77, -62, + -48, -17, 5, 13, 26, 31, 10, -29, -62, -64, -65, -54, -41, -25, -4, 32, + 52, 29, 32, 55, 61, 55, 56, 57, 35, 17, 33, 40, 28, 27, 37, 36, + 26, 14, -3, 13, 41, 22, -13, -45, -65, -78, -90, -87, -70, -56, -47, -12, + 9, 18, 35, 27, -5, -41, -63, -61, -65, -52, -37, -17, 5, 35, 52, 34, + 38, 55, 58, 53, 60, 54, 31, 21, 33, 34, 30, 35, 40, 32, 29, 15, + -4, 18, 30, 11, -25, -53, -69, -85, -91, -82, -66, -54, -36, -7, 6, 20, + 40, 19, -17, -52, -63, -60, -65, -50, -32, -11, 9, 34, 50, 40, 46, 51, + 56, 60, 60, 50, 28, 23, 33, 33, 31, 40, 43, 38, 38, 13, -6, 13, + 19, -2, -34, -57, -78, -91, -85, -73, -63, -55, -28, -1, 6, 26, 39, 13, + -28, -56, -61, -55, -61, -43, -27, -13, 12, 38, 48, 49, 54, 46, 52, 64, + 64, 48, 27, 22, 28, 33, 36, 44, 42, 39, 44, 15, -3, 10, 6, -19, + -46, -60, -81, -92, -83, -73, -52, -44, -22, -5, 5, 38, 37, -6, -41, -55, + -54, -49, -53, -45, -28, -9, 19, 41, 47, 56, 57, 41, 56, 69, 64, 42, + 26, 23, 27, 36, 39, 44, 39, 48, 53, 12, -4, 2, -8, -33, -61, -72, + -84, -87, -80, -73, -49, -36, -12, -5, 9, 42, 24, -15, -44, -50, -51, -51, + -51, -45, -26, -4, 20, 40, 47, 64, 58, 38, 61, 71, 55, 37, 32, 23, + 30, 34, 39, 50, 43, 58, 53, 9, 4, -3, -27, -49, -71, -79, -79, -79, + -82, -70, -44, -26, -7, -5, 16, 36, 9, -18, -40, -47, -49, -45, -42, -43, + -20, 1, 21, 40, 53, 72, 54, 36, 64, 66, 41, 30, 36, 26, 28, 31, + 44, 57, 48, 62, 45, 13, 3, -14, -47, -65, -77, -87, -78, -71, -75, -68, + -43, -16, -2, -1, 18, 20, -4, -18, -37, -46, -50, -36, -39, -46, -15, 7, + 23, 41, 62, 72, 49, 41, 69, 59, 33, 29, 38, 24, 28, 31, 52, 59, + 49, 61, 45, 21, 2, -31, -64, -73, -78, -89, -79, -71, -77, -62, -36, -8, + 3, 5, 15, 5, -10, -17, -34, -49, -50, -27, -37, -43, -12, 14, 25, 45, + 67, 68, 48, 48, 64, 48, 27, 33, 41, 25, 24, 32, 64, 66, 51, 62, + 41, 21, -7, -43, -77, -81, -83, -87, -74, -71, -77, -54, -29, -1, 7, 13, + 12, -6, -9, -18, -38, -54, -44, -21, -37, -41, -8, 16, 28, 53, 73, 61, + 46, 52, 60, 35, 25, 34, 38, 20, 25, 42, 73, 62, 60, 58, 39, 22, + -19, -54, -85, -88, -95, -88, -65, -69, -73, -47, -22, 3, 14, 15, -5, -14, + -6, -23, -42, -52, -34, -19, -42, -38, 0, 18, 30, 62, 76, 61, 49, 52, + 49, 26, 23, 34, 33, 22, 21, 50, 78, 68, 66, 47, 40, 22, -23, -66, + -95, -102, -97, -74, -61, -77, -68, -36, -12, 9, 15, 13, -18, -14, -5, -31, + -50, -44, -21, -25, -49, -25, 8, 16, 30, 70, 82, 56, 45, 55, 39, 21, + 25, 31, 24, 21, 28, 64, 81, 68, 64, 47, 44, 15, -30, -77, -101, -104, + -96, -71, -66, -76, -53, -22, -9, 6, 22, 10, -22, -15, -13, -38, -48, -32, + -9, -33, -49, -14, 10, 11, 37, 77, 85, 51, 44, 48, 30, 18, 21, 26, + 16, 21, 36, 71, 76, 73, 68, 48, 35, 4, -38, -81, -103, -109, -91, -67, + -71, -69, -40, -15, -12, 3, 23, 7, -23, -17, -24, -41, -45, -24, -11, -46, + -46, -1, 10, 8, 49, 84, 83, 48, 50, 48, 27, 16, 18, 20, 14, 26, + 44, 72, 75, 82, 71, 47, 26, -6, -45, -80, -107, -110, -88, -70, -69, -58, + -28, -9, -12, 2, 23, 2, -21, -19, -35, -38, -33, -13, -17, -50, -35, 8, + 9, 10, 57, 89, 74, 45, 52, 41, 24, 15, 11, 14, 13, 22, 54, 72, + 74, 86, 72, 41, 13, -14, -47, -86, -113, -111, -88, -72, -67, -42, -18, -11, + -11, 2, 18, -2, -17, -27, -44, -37, -28, -12, -26, -49, -22, 9, 3, 21, + 69, 87, 63, 46, 49, 36, 24, 13, 11, 11, 8, 26, 64, 68, 76, 89, + 74, 38, 3, -17, -44, -86, -117, -114, -86, -65, -58, -38, -19, -7, 0, 8, + 9, -5, -20, -37, -45, -29, -19, -15, -36, -39, -10, 6, 4, 33, 79, 81, + 55, 48, 42, 30, 23, 10, 13, 10, 3, 27, 62, 60, 76, 88, 68, 30, + -5, -21, -49, -89, -120, -115, -81, -54, -46, -34, -14, -1, 7, 9, 1, -6, + -18, -45, -52, -29, -16, -17, -35, -36, -12, 5, 11, 47, 81, 72, 53, 51, + 39, 28, 24, 9, 13, 7, 5, 36, 57, 55, 82, 90, 62, 31, -10, -29, + -55, -91, -121, -115, -76, -47, -38, -34, -13, 1, 13, 9, -4, -9, -17, -49, + -56, -26, -9, -12, -33, -40, -17, 12, 25, 57, 71, 62, 52, 50, 35, 22, + 21, 14, 11, -2, 10, 41, 50, 48, 85, 87, 66, 29, -15, -34, -64, -97, + -121, -108, -73, -43, -37, -28, -7, 7, 16, 6, -7, -5, -15, -59, -56, -19, + -4, -14, -37, -42, -10, 21, 38, 66, 63, 57, 52, 49, 28, 22, 28, 16, + 5, -3, 22, 47, 38, 45, 79, 85, 68, 23, -16, -34, -70, -100, -122, -107, + -62, -39, -38, -25, -4, 15, 18, 2, -3, 0, -27, -70, -51, -17, -3, -16, + -44, -40, -1, 27, 45, 67, 57, 54, 48, 39, 17, 18, 28, 17, 3, -3, + 27, 49, 37, 42, 69, 86, 66, 16, -17, -37, -72, -99, -117, -101, -55, -39, + -36, -24, 1, 20, 13, 4, 4, -5, -46, -74, -43, -9, -4, -28, -49, -33, + 6, 33, 63, 68, 54, 53, 49, 33, 18, 21, 24, 15, 7, 9, 33, 42, + 35, 39, 70, 85, 55, 10, -16, -40, -75, -98, -113, -92, -47, -38, -35, -21, + 1, 21, 15, 8, 7, -14, -62, -70, -30, -11, -15, -34, -49, -23, 9, 39, + 64, 58, 51, 56, 42, 20, 16, 19, 16, 16, 4, 13, 40, 46, 33, 31, + 65, 83, 49, 3, -24, -41, -73, -98, -105, -77, -45, -41, -30, -13, 7, 19, + 12, 13, 8, -26, -68, -61, -22, -14, -25, -38, -40, -18, 12, 47, 68, 59, + 49, 51, 42, 19, 17, 17, 12, 13, 5, 18, 41, 47, 26, 26, 67, 78, + 44, -2, -31, -47, -71, -97, -96, -67, -44, -42, -29, -11, 13, 21, 13, 17, + 8, -34, -68, -54, -17, -18, -36, -43, -35, -12, 14, 50, 69, 56, 49, 44, + 35, 16, 13, 17, 13, 13, 6, 27, 46, 50, 24, 28, 66, 64, 28, 0, + -25, -49, -75, -99, -87, -54, -42, -38, -28, -8, 20, 19, 11, 17, 1, -41, + -62, -49, -18, -27, -41, -39, -29, -8, 15, 55, 73, 55, 42, 42, 33, 16, + 12, 12, 9, 6, 14, 40, 52, 48, 21, 31, 60, 50, 23, 0, -32, -60, + -76, -90, -73, -44, -39, -36, -32, 1, 29, 20, 6, 13, -3, -41, -53, -43, + -21, -34, -47, -38, -22, -2, 22, 54, 65, 49, 38, 42, 32, 17, 12, 7, + 6, 3, 21, 48, 53, 42, 24, 39, 53, 38, 15, -3, -38, -65, -76, -85, + -59, -36, -35, -40, -26, 15, 26, 12, 6, 10, -12, -40, -49, -33, -26, -41, + -53, -36, -12, 5, 28, 50, 61, 46, 34, 37, 31, 20, 12, 1, 0, 5, + 32, 53, 56, 41, 23, 39, 48, 35, 13, -10, -44, -72, -81, -79, -50, -27, + -34, -41, -18, 20, 27, 12, 5, 1, -19, -36, -40, -22, -34, -50, -55, -33, + -3, 14, 33, 52, 54, 35, 27, 36, 37, 25, 7, -13, 1, 19, 41, 50, + 50, 38, 32, 43, 41, 32, 6, -17, -46, -69, -79, -75, -43, -20, -34, -38, + -8, 23, 26, 12, 6, -8, -23, -30, -30, -23, -46, -56, -52, -29, 6, 23, + 35, 44, 47, 31, 25, 33, 40, 26, -4, -22, 3, 28, 39, 40, 50, 40, + 28, 34, 37, 28, 0, -22, -50, -70, -81, -72, -34, -22, -36, -33, 2, 24, + 25, 12, 4, -15, -24, -26, -25, -23, -46, -56, -50, -24, 10, 33, 36, 40, + 35, 21, 25, 43, 47, 25, -13, -25, 11, 40, 36, 40, 56, 38, 27, 31, + 33, 24, -4, -24, -53, -71, -80, -59, -34, -27, -31, -27, 8, 24, 25, 17, + 2, -22, -25, -26, -19, -24, -51, -58, -40, -9, 14, 37, 36, 35, 27, 14, + 28, 48, 46, 19, -19, -24, 18, 40, 29, 41, 50, 29, 29, 27, 33, 18, + -12, -29, -53, -71, -75, -48, -33, -32, -25, -14, 13, 24, 19, 17, 2, -25, + -28, -28, -18, -28, -55, -59, -30, -3, 20, 41, 34, 24, 15, 15, 36, 49, + 39, 17, -17, -17, 22, 41, 33, 45, 38, 26, 30, 24, 27, 10, -11, -34, + -58, -70, -66, -38, -32, -36, -21, -2, 14, 28, 19, 14, 0, -25, -29, -28, + -17, -30, -57, -51, -22, 3, 23, 39, 34, 15, 11, 17, 38, 46, 39, 15, + -18, -14, 27, 40, 37, 45, 32, 28, 30, 29, 28, 1, -16, -38, -55, -65, + -62, -37, -31, -34, -17, 9, 18, 27, 18, 9, -1, -22, -35, -29, -17, -32, + -57, -45, -17, 15, 30, 30, 25, 8, 10, 19, 35, 46, 37, 4, -19, -8, + 31, 33, 33, 42, 28, 22, 24, 29, 23, -6, -21, -43, -54, -59, -55, -32, + -34, -39, -10, 19, 30, 25, 9, 2, -2, -20, -38, -30, -23, -41, -51, -35, + -12, 24, 32, 22, 12, 8, 16, 23, 32, 48, 33, 1, -16, 0, 29, 30, + 33, 36, 24, 23, 22, 33, 14, -14, -20, -42, -55, -50, -44, -27, -38, -41, + -3, 31, 35, 23, 5, -2, -4, -15, -34, -33, -38, -47, -40, -26, -3, 31, + 31, 9, 2, 13, 14, 20, 38, 53, 27, -6, -14, 11, 30, 23, 32, 28, + 25, 22, 24, 32, 5, -20, -26, -45, -49, -40, -36, -37, -48, -40, 8, 40, + 37, 16, -3, -6, -2, -9, -27, -42, -52, -48, -32, -21, 8, 39, 28, -2, + -5, 13, 17, 23, 40, 45, 19, -4, -3, 18, 15, 19, 33, 30, 29, 22, + 21, 22, 0, -17, -27, -46, -48, -33, -31, -38, -53, -33, 23, 43, 31, 11, + -7, -5, -3, -8, -26, -49, -59, -48, -25, -14, 15, 41, 23, -8, -6, 11, + 10, 26, 49, 41, 12, 0, 10, 19, 4, 22, 31, 25, 25, 24, 20, 12, + -4, -10, -37, -50, -37, -23, -26, -43, -55, -18, 34, 41, 28, 10, -9, -6, + -3, -8, -27, -57, -62, -37, -15, -8, 24, 44, 23, -10, -6, 3, 8, 39, + 55, 30, 12, 11, 20, 8, 3, 27, 26, 20, 21, 24, 19, -1, -10, -14, + -42, -47, -25, -14, -28, -49, -50, -5, 38, 38, 23, 9, -11, -9, -1, -5, + -33, -64, -59, -34, -14, -2, 32, 49, 17, -11, -6, -2, 11, 46, 46, 19, + 16, 23, 24, -3, 3, 29, 29, 16, 17, 22, 11, -12, -12, -18, -50, -43, + -15, -11, -30, -53, -38, 10, 31, 31, 25, 3, -16, -3, 3, -8, -41, -67, + -53, -24, -14, 3, 35, 46, 17, -2, -7, -9, 16, 49, 41, 20, 22, 34, + 21, -5, 5, 31, 29, 12, 14, 18, 8, -22, -17, -20, -52, -38, -13, -19, + -32, -48, -25, 11, 23, 29, 26, 1, -14, 1, 1, -18, -47, -60, -47, -31, + -11, 13, 45, 39, 8, -2, -2, -11, 16, 43, 35, 25, 34, 40, 18, -7, + 6, 34, 28, 14, 7, 11, 2, -23, -25, -29, -51, -30, -11, -24, -38, -40, + -15, 9, 18, 29, 32, -1, -10, 0, -9, -27, -48, -52, -46, -30, -2, 27, + 47, 30, 10, 7, -6, -15, 12, 35, 28, 30, 45, 42, 19, -4, 11, 29, + 21, 6, 1, 3, -3, -27, -31, -34, -40, -22, -18, -31, -35, -30, -18, 5, + 19, 32, 28, -9, -7, 1, -14, -30, -42, -45, -47, -28, 7, 38, 45, 23, + 14, 20, -2, -24, 7, 32, 30, 37, 43, 41, 22, 7, 18, 22, 14, 4, + -7, 4, -7, -36, -37, -37, -27, -15, -26, -34, -34, -29, -18, 4, 19, 31, + 20, -4, 0, -3, -21, -32, -37, -41, -40, -25, 14, 49, 44, 18, 19, 25, + -1, -19, 5, 26, 35, 38, 46, 41, 18, 18, 16, 13, 12, 2, -5, -3, + -23, -44, -37, -32, -20, -20, -33, -28, -32, -32, -16, 1, 17, 31, 17, -2, + 2, -3, -22, -33, -39, -40, -34, -23, 15, 56, 44, 15, 27, 23, -4, -14, + 2, 22, 38, 37, 48, 40, 25, 24, 15, 11, 2, -2, -3, -15, -31, -40, + -37, -33, -17, -17, -28, -29, -41, -34, -7, 1, 13, 31, 17, -2, 4, 1, + -20, -35, -47, -37, -24, -10, 22, 52, 38, 26, 35, 26, -2, -9, 4, 23, + 40, 38, 46, 39, 32, 31, 16, 2, -7, -8, -2, -21, -38, -44, -38, -31, + -18, -15, -29, -35, -45, -32, -1, -3, 4, 30, 16, 3, 8, 4, -20, -42, + -48, -30, -17, -8, 21, 49, 41, 30, 38, 23, -2, -5, 1, 21, 35, 37, + 44, 40, 40, 33, 17, 1, -13, -10, -9, -35, -41, -41, -39, -33, -19, -12, + -27, -40, -48, -28, -4, -10, 10, 28, 15, 9, 12, 5, -24, -43, -43, -23, + -18, 0, 26, 47, 43, 35, 40, 20, -1, 1, 4, 20, 28, 37, 42, 42, + 46, 31, 22, 8, -17, -15, -15, -42, -41, -37, -44, -37, -16, -13, -33, -41, + -41, -20, -11, -17, 10, 18, 13, 16, 17, 1, -24, -38, -38, -27, -21, 9, + 29, 46, 44, 43, 38, 18, 3, 6, 6, 12, 19, 38, 41, 47, 44, 28, + 29, 11, -26, -25, -27, -45, -39, -39, -48, -41, -18, -13, -33, -38, -36, -21, + -19, -14, 13, 11, 11, 26, 17, -6, -25, -32, -32, -35, -14, 21, 31, 38, + 49, 49, 34, 19, 13, 10, 4, 9, 20, 37, 41, 45, 39, 29, 35, 6, + -28, -28, -35, -43, -37, -42, -50, -44, -20, -20, -37, -37, -27, -16, -23, -11, + 10, 5, 17, 36, 16, -16, -23, -21, -33, -38, -5, 23, 28, 35, 55, 55, + 31, 17, 18, 12, 3, 4, 21, 33, 41, 45, 31, 32, 39, 3, -29, -35, + -41, -40, -38, -45, -55, -45, -26, -31, -36, -26, -22, -22, -29, 1, 9, -1, + 24, 39, 8, -19, -17, -14, -32, -34, 5, 29, 29, 35, 58, 51, 32, 29, + 23, 11, 1, 6, 29, 37, 38, 36, 24, 43, 39, -2, -32, -44, -45, -36, + -36, -45, -55, -51, -37, -35, -30, -22, -20, -32, -24, 6, 2, 3, 30, 36, + 3, -17, -16, -18, -29, -24, 10, 31, 25, 34, 58, 44, 33, 37, 26, 8, + 5, 10, 37, 36, 35, 29, 22, 47, 36, -6, -36, -51, -49, -34, -38, -48, + -58, -53, -46, -42, -24, -23, -22, -32, -13, 4, -7, 8, 35, 30, 6, -14, + -20, -19, -21, -20, 14, 34, 29, 43, 52, 37, 39, 43, 24, 8, 7, 15, + 45, 33, 36, 24, 25, 43, 25, -10, -39, -53, -47, -34, -39, -53, -56, -54, + -56, -42, -21, -23, -29, -25, -5, 1, -10, 12, 35, 27, 7, -14, -25, -19, + -11, -10, 13, 31, 37, 44, 42, 37, 45, 44, 24, 14, 13, 24, 40, 28, + 35, 23, 31, 35, 15, -16, -38, -53, -45, -37, -48, -56, -54, -63, -63, -40, + -23, -24, -27, -19, 3, 1, -11, 14, 33, 24, 5, -16, -28, -17, -6, -1, + 15, 38, 39, 38, 29, 36, 54, 42, 20, 20, 19, 32, 38, 30, 31, 23, + 33, 23, -1, -17, -35, -44, -43, -47, -51, -51, -56, -71, -67, -45, -28, -23, + -23, -13, 12, -1, -15, 15, 33, 20, -2, -22, -25, -17, -3, 10, 24, 46, + 44, 31, 26, 41, 53, 42, 23, 23, 26, 39, 37, 32, 24, 28, 36, 11, + -7, -19, -38, -39, -37, -49, -54, -51, -62, -76, -68, -51, -28, -19, -21, 1, + 22, -3, -11, 14, 25, 16, -5, -25, -25, -15, -2, 20, 36, 51, 42, 19, + 19, 43, 58, 43, 25, 21, 35, 46, 41, 34, 17, 26, 33, 5, -15, -25, + -39, -34, -37, -55, -50, -49, -69, -80, -67, -50, -31, -18, -12, 12, 17, -5, + -5, 14, 17, 6, -15, -27, -22, -14, 3, 37, 49, 48, 40, 22, 22, 36, + 51, 44, 29, 22, 42, 49, 41, 29, 16, 29, 31, -9, -30, -33, -35, -29, + -38, -55, -45, -54, -79, -80, -65, -51, -34, -16, -2, 18, 18, 5, 7, 8, + 6, 3, -19, -21, -22, -19, 12, 51, 53, 48, 39, 22, 18, 36, 46, 42, + 35, 31, 44, 46, 42, 31, 24, 35, 21, -25, -39, -33, -30, -24, -41, -53, + -47, -60, -81, -81, -63, -53, -40, -14, 6, 24, 20, 8, 7, 0, -1, -4, + -21, -23, -29, -16, 30, 60, 55, 50, 37, 19, 19, 35, 43, 46, 37, 29, + 43, 49, 43, 32, 27, 31, 13, -35, -46, -36, -26, -28, -44, -52, -47, -65, + -84, -84, -68, -49, -27, 0, 10, 15, 19, 15, 9, -3, -10, -16, -20, -26, + -28, -2, 41, 59, 62, 56, 37, 16, 15, 31, 43, 50, 42, 30, 41, 49, + 49, 38, 28, 23, 5, -42, -55, -42, -21, -22, -40, -49, -54, -71, -86, -81, + -62, -44, -21, 5, 17, 16, 25, 23, 0, -13, -17, -17, -24, -32, -21, 15, + 45, 58, 66, 52, 33, 15, 9, 35, 42, 44, 44, 36, 38, 50, 52, 40, + 28, 16, -11, -48, -60, -43, -22, -21, -40, -53, -58, -78, -90, -79, -61, -42, + -9, 14, 15, 16, 22, 21, -4, -20, -21, -19, -30, -31, -10, 26, 54, 63, + 69, 51, 33, 12, 13, 40, 42, 45, 42, 33, 36, 53, 57, 44, 24, 3, + -24, -53, -63, -45, -21, -15, -39, -57, -63, -78, -89, -76, -55, -34, 3, 18, + 9, 16, 21, 15, -8, -26, -28, -25, -32, -24, 4, 34, 56, 67, 75, 48, + 22, 7, 23, 44, 39, 40, 40, 35, 40, 59, 59, 44, 18, -6, -31, -54, + -58, -44, -20, -13, -43, -63, -69, -80, -88, -71, -48, -21, 12, 16, 12, 18, + 13, 6, -12, -27, -32, -30, -34, -20, 13, 46, 63, 74, 73, 40, 15, 13, + 39, 46, 33, 32, 35, 36, 48, 58, 61, 43, 16, -13, -36, -57, -62, -41, + -22, -16, -42, -66, -73, -79, -85, -65, -38, -7, 13, 9, 7, 16, 11, -2, + -18, -36, -39, -26, -25, -16, 21, 53, 64, 74, 68, 36, 19, 22, 38, 44, + 32, 28, 32, 38, 52, 60, 56, 43, 13, -25, -39, -54, -52, -35, -30, -27, + -46, -70, -79, -80, -79, -58, -26, 3, 15, 6, 0, 12, 6, -8, -27, -45, + -39, -17, -16, -13, 28, 57, 67, 71, 57, 37, 22, 25, 41, 46, 29, 24, + 34, 44, 56, 55, 52, 44, 7, -27, -38, -48, -44, -35, -31, -29, -46, -77, + -83, -73, -70, -48, -15, 6, 9, 1, 1, 9, -3, -20, -41, -48, -30, -5, + -14, -9, 39, 63, 70, 66, 47, 36, 25, 32, 40, 43, 26, 21, 36, 47, + 59, 50, 49, 35, 0, -26, -36, -44, -41, -36, -35, -33, -50, -79, -79, -66, + -63, -36, -8, 6, -3, -9, 2, 3, -13, -30, -49, -46, -18, -2, -15, 4, + 42, 58, 65, 61, 50, 38, 28, 37, 40, 38, 28, 30, 38, 48, 50, 42, + 46, 28, -3, -28, -37, -36, -36, -39, -36, -37, -59, -79, -69, -62, -52, -24, + -2, 3, -12, -11, 4, -5, -29, -42, -53, -39, -12, -4, -4, 14, 37, 52, + 63, 58, 50, 37, 34, 37, 36, 37, 38, 36, 35, 47, 46, 44, 42, 18, + -7, -30, -34, -32, -34, -41, -37, -45, -66, -74, -64, -57, -36, -12, 1, -8, + -23, -7, 6, -18, -39, -49, -53, -29, -5, -1, 10, 19, 30, 46, 59, 58, + 50, 36, 37, 37, 32, 40, 46, 38, 34, 44, 42, 41, 36, 9, -9, -27, + -29, -26, -34, -40, -40, -56, -69, -66, -56, -46, -22, -7, -7, -19, -21, 3, + 1, -35, -48, -53, -49, -22, -3, 12, 23, 18, 22, 46, 66, 59, 47, 38, + 43, 35, 30, 46, 51, 39, 33, 41, 37, 42, 24, 2, -8, -22, -23, -24, + -33, -39, -50, -66, -69, -59, -49, -31, -13, -10, -17, -25, -16, 1, -17, -50, + -55, -58, -42, -17, -1, 20, 31, 14, 15, 48, 70, 59, 42, 38, 45, 33, + 33, 51, 53, 36, 35, 37, 36, 37, 12, 0, -9, -16, -18, -22, -33, -42, + -59, -67, -62, -52, -40, -20, -11, -15, -23, -23, -11, -3, -28, -51, -59, -61, + -38, -14, 4, 26, 30, 10, 18, 53, 71, 56, 40, 42, 45, 32, 34, 53, + 52, 37, 36, 32, 37, 32, 10, -3, -10, -10, -11, -17, -31, -46, -62, -63, + -54, -44, -30, -14, -14, -23, -27, -22, -11, -11, -35, -51, -65, -59, -32, -11, + 11, 29, 25, 8, 24, 63, 73, 51, 38, 46, 44, 29, 34, 51, 51, 39, + 34, 27, 34, 23, 3, -5, -9, -6, -10, -18, -33, -51, -66, -60, -50, -35, + -20, -10, -21, -33, -29, -17, -9, -20, -39, -55, -71, -57, -26, -7, 11, 23, + 22, 11, 35, 70, 71, 46, 39, 48, 42, 29, 33, 51, 47, 38, 31, 28, + 35, 17, 0, -12, -7, 0, -4, -15, -36, -56, -67, -56, -42, -26, -15, -12, + -29, -36, -28, -15, -13, -25, -40, -58, -70, -49, -23, -6, 8, 19, 17, 18, + 49, 76, 66, 40, 42, 49, 39, 25, 35, 51, 43, 40, 30, 31, 32, 15, + -1, -14, -7, 1, -2, -17, -40, -59, -61, -51, -38, -21, -10, -17, -34, -35, + -28, -18, -17, -24, -40, -64, -65, -40, -18, -8, 5, 13, 17, 31, 61, 75, + 60, 41, 43, 47, 34, 20, 36, 47, 43, 41, 31, 32, 26, 7, -7, -16, + -6, 0, -3, -22, -44, -60, -56, -47, -34, -19, -8, -20, -39, -40, -27, -18, + -20, -29, -44, -63, -56, -38, -23, -11, 4, 14, 21, 42, 65, 71, 59, 45, + 42, 34, 21, 20, 42, 48, 44, 41, 31, 34, 24, 6, -10, -20, -11, 4, + 0, -20, -48, -57, -47, -39, -30, -17, -4, -24, -43, -40, -26, -19, -24, -29, + -45, -59, -51, -37, -25, -14, 3, 15, 27, 51, 72, 76, 61, 44, 38, 23, + 12, 21, 43, 46, 45, 40, 31, 35, 21, 5, -17, -22, -13, 3, 1, -24, + -51, -52, -43, -37, -28, -8, -7, -38, -46, -36, -21, -21, -31, -33, -45, -51, + -47, -40, -30, -13, 4, 14, 33, 60, 76, 76, 61, 47, 30, 16, 8, 20, + 40, 45, 48, 37, 37, 37, 22, 3, -19, -20, -10, 4, -6, -30, -49, -44, + -41, -38, -23, -1, -14, -41, -44, -36, -22, -26, -35, -33, -45, -52, -48, -40, + -32, -9, 6, 18, 35, 65, 85, 80, 62, 46, 24, 6, -1, 23, 41, 48, + 45, 31, 42, 40, 23, -6, -21, -15, -6, 0, -13, -31, -44, -41, -38, -32, + -15, 0, -22, -40, -41, -36, -24, -31, -28, -32, -46, -49, -47, -43, -30, -6, + 9, 19, 46, 77, 87, 77, 61, 42, 18, -2, -7, 22, 39, 51, 41, 32, + 43, 35, 13, -18, -18, -10, -5, -8, -21, -29, -39, -42, -41, -23, -3, -3, + -32, -39, -38, -34, -31, -35, -23, -32, -46, -50, -51, -46, -26, 0, 12, 20, + 54, 87, 91, 72, 60, 38, 13, -10, -11, 24, 44, 52, 43, 39, 45, 34, + 2, -19, -8, -1, -8, -19, -19, -25, -35, -42, -39, -17, 7, -7, -38, -36, + -36, -37, -37, -31, -20, -34, -49, -53, -50, -43, -19, 6, 10, 25, 66, 91, + 84, 67, 60, 36, 1, -18, -10, 27, 48, 52, 42, 42, 38, 25, -3, -18, + -5, -2, -13, -22, -24, -28, -35, -45, -35, -4, 14, -17, -41, -36, -33, -35, + -41, -29, -20, -38, -51, -54, -46, -33, -14, 6, 14, 37, 74, 87, 76, 65, + 64, 29, -9, -22, -7, 23, 52, 55, 46, 42, 25, 17, -5, -12, -4, -3, + -17, -25, -33, -36, -33, -39, -30, 5, 12, -25, -37, -33, -34, -42, -41, -25, + -22, -41, -52, -53, -40, -25, -10, 11, 21, 43, 72, 78, 74, 69, 58, 15, + -13, -15, -4, 22, 54, 58, 53, 41, 15, 6, -2, -1, -3, -6, -18, -24, + -42, -40, -29, -32, -20, 13, 8, -25, -35, -34, -29, -42, -43, -27, -27, -42, + -51, -50, -30, -14, -5, 17, 26, 46, 70, 72, 72, 69, 48, 2, -13, -9, + -3, 19, 55, 59, 53, 30, 1, -1, 5, 8, -7, -15, -19, -25, -48, -45, + -31, -28, -10, 15, 1, -24, -35, -35, -22, -37, -43, -36, -35, -41, -47, -45, + -18, -6, -1, 24, 32, 51, 65, 65, 67, 63, 37, -3, -13, -9, 1, 29, + 54, 60, 50, 18, -4, -4, 13, 9, -10, -15, -17, -30, -54, -47, -29, -20, + -8, 4, -8, -15, -29, -35, -21, -37, -43, -46, -37, -33, -48, -39, -10, 3, + 13, 31, 34, 54, 56, 57, 63, 56, 32, -3, -16, -6, 14, 38, 48, 53, + 40, 11, -3, 1, 6, -2, -11, -9, -11, -28, -54, -54, -29, -8, 2, -8, + -16, -13, -27, -31, -21, -32, -45, -54, -36, -27, -44, -33, 1, 16, 25, 29, + 39, 56, 48, 51, 57, 48, 22, 3, -14, 0, 22, 39, 42, 46, 36, 7, + -7, 0, 0, -3, -8, -8, -15, -34, -50, -49, -27, -3, 0, -15, -14, -16, + -28, -26, -21, -34, -56, -55, -32, -30, -41, -23, 8, 20, 31, 33, 45, 53, + 38, 42, 54, 40, 18, -3, -9, 14, 33, 37, 34, 34, 27, 8, -5, -1, + -9, -3, -1, -8, -19, -35, -43, -42, -28, -7, 1, -18, -13, -17, -29, -24, + -21, -34, -55, -52, -34, -30, -26, -9, 15, 28, 28, 32, 55, 50, 29, 38, + 45, 35, 17, -3, -1, 18, 36, 40, 27, 24, 19, 0, -5, -1, -14, -7, + -2, -12, -20, -30, -40, -42, -25, -5, -5, -24, -14, -16, -25, -20, -26, -38, + -52, -49, -35, -31, -13, 8, 16, 28, 29, 42, 57, 40, 23, 32, 35, 30, + 12, -5, 9, 22, 40, 38, 19, 17, 16, -1, -9, -7, -12, -6, -5, -13, + -18, -29, -39, -39, -18, -3, -19, -26, -11, -18, -24, -19, -30, -40, -51, -45, + -30, -24, 0, 19, 22, 28, 36, 49, 54, 41, 22, 30, 31, 26, 10, 2, + 10, 26, 43, 28, 14, 16, 7, -6, -12, -9, -9, -5, -12, -19, -16, -29, + -35, -34, -8, -8, -35, -20, -7, -26, -23, -23, -30, -39, -53, -38, -25, -12, + 11, 24, 24, 29, 47, 50, 48, 36, 20, 29, 24, 15, 5, 8, 12, 32, + 40, 21, 17, 11, 0, -3, -15, -14, -7, -4, -13, -17, -16, -28, -31, -23, + -6, -20, -37, -15, -12, -29, -22, -28, -30, -38, -54, -34, -20, -4, 21, 33, + 24, 33, 50, 45, 40, 33, 27, 28, 14, 8, 8, 11, 11, 30, 33, 26, + 20, -1, -8, -4, -17, -16, -2, -7, -22, -20, -20, -26, -26, -15, -10, -27, + -35, -12, -19, -31, -21, -23, -23, -42, -57, -31, -11, 9, 35, 33, 23, 39, + 53, 47, 40, 31, 31, 21, 10, 9, 11, 10, 13, 26, 35, 33, 13, -11, + -10, -4, -19, -22, 3, -2, -28, -26, -16, -21, -24, -12, -12, -31, -34, -17, + -27, -34, -25, -17, -19, -48, -59, -29, -2, 27, 46, 26, 22, 43, 54, 44, + 38, 30, 29, 16, 6, 15, 15, 6, 9, 22, 36, 37, 9, -20, -10, -5, + -21, -21, 2, -5, -29, -31, -18, -11, -17, -11, -15, -32, -34, -23, -30, -30, + -25, -15, -22, -52, -50, -17, 9, 36, 42, 26, 29, 50, 53, 40, 33, 32, + 27, 14, 7, 9, 7, 4, 12, 22, 36, 36, 3, -27, -16, -9, -20, -21, + -1, -12, -31, -27, -13, -12, -18, -12, -17, -33, -39, -29, -34, -35, -23, -7, + -25, -55, -42, -10, 20, 43, 40, 27, 33, 51, 51, 37, 34, 31, 21, 9, + 8, 5, 2, 11, 16, 18, 34, 35, 3, -22, -17, -16, -20, -17, -7, -20, + -32, -28, -14, -12, -10, -8, -17, -34, -41, -35, -34, -31, -19, -8, -27, -48, + -29, -4, 26, 50, 44, 32, 37, 50, 49, 40, 36, 22, 11, 11, 12, 5, + 3, 14, 12, 13, 34, 37, 9, -23, -24, -16, -21, -16, -17, -30, -27, -27, + -20, -10, -10, -9, -18, -39, -46, -42, -35, -31, -14, -9, -33, -42, -19, 1, + 36, 55, 41, 32, 46, 55, 47, 35, 32, 18, 6, 7, 9, -2, 7, 17, + 8, 13, 34, 32, 10, -22, -27, -14, -20, -21, -26, -31, -23, -27, -22, -6, + -5, -11, -21, -39, -46, -46, -37, -30, -14, -12, -33, -31, -8, 6, 41, 55, + 40, 38, 54, 57, 39, 30, 33, 17, 2, 1, 4, 7, 14, 14, -2, 11, + 37, 31, 11, -26, -30, -16, -20, -18, -21, -27, -32, -28, -12, 0, -4, -11, + -23, -40, -46, -43, -33, -26, -16, -15, -29, -19, -1, 13, 44, 58, 41, 49, + 68, 59, 36, 28, 36, 18, -9, -9, 4, 17, 20, 7, -6, 18, 36, 22, + -1, -30, -26, -19, -25, -26, -31, -35, -33, -21, -3, -8, -10, -14, -24, -40, + -45, -43, -35, -20, -18, -20, -22, -12, 0, 15, 48, 58, 41, 58, 77, 57, + 30, 27, 33, 7, -23, -16, 11, 23, 21, 2, -5, 24, 33, 10, -10, -24, + -19, -25, -37, -30, -30, -34, -29, -14, -5, -16, -8, -8, -26, -50, -47, -41, + -30, -16, -25, -24, -14, -6, 3, 23, 50, 51, 49, 69, 81, 56, 29, 33, + 30, -2, -29, -14, 15, 26, 18, 2, -1, 31, 28, 0, -20, -21, -21, -32, + -43, -34, -33, -36, -23, -4, -8, -20, -8, -11, -25, -44, -41, -39, -32, -17, + -30, -22, -4, 1, 6, 31, 48, 47, 63, 80, 82, 52, 31, 38, 23, -13, + -33, -11, 20, 29, 14, -1, 9, 34, 19, -12, -26, -13, -23, -46, -46, -38, + -39, -35, -24, -3, -7, -17, -15, -16, -25, -45, -37, -37, -33, -26, -36, -20, + 5, 3, 4, 32, 42, 50, 76, 83, 75, 49, 34, 36, 17, -24, -33, -12, + 23, 32, 10, 1, 23, 30, 7, -17, -22, -8, -27, -49, -50, -42, -38, -28, + -18, -3, -8, -13, -14, -15, -24, -43, -35, -33, -29, -27, -34, -15, 16, 8, + 5, 32, 43, 62, 84, 84, 73, 53, 40, 30, 6, -26, -34, -15, 25, 28, + 8, 9, 38, 27, -4, -26, -21, -12, -33, -54, -47, -48, -38, -21, -14, -2, + -3, -11, -25, -18, -26, -32, -34, -34, -29, -31, -35, -10, 18, 11, 7, 33, + 47, 68, 83, 81, 71, 58, 42, 20, -5, -25, -36, -15, 23, 23, 7, 20, + 40, 21, -14, -35, -21, -16, -40, -58, -52, -52, -31, -11, -9, -6, -1, -15, + -26, -15, -29, -31, -36, -31, -29, -36, -32, -4, 17, 8, 15, 36, 48, 66, + 77, 83, 77, 59, 38, 9, -11, -20, -34, -12, 22, 20, 14, 33, 39, 16, + -22, -36, -23, -21, -40, -56, -52, -47, -24, -10, -4, 3, 1, -17, -22, -18, + -28, -26, -32, -30, -32, -30, -22, 1, 15, 15, 27, 42, 52, 62, 75, 85, + 80, 59, 35, 1, -16, -20, -35, -12, 18, 17, 18, 40, 34, 5, -34, -38, + -27, -28, -42, -60, -58, -48, -18, -4, 0, 3, -4, -18, -20, -22, -35, -29, + -27, -34, -42, -28, -12, 3, 8, 19, 31, 40, 45, 60, 75, 79, 76, 62, + 37, -2, -20, -22, -31, -11, 13, 15, 31, 43, 27, 0, -28, -33, -36, -37, + -43, -58, -61, -47, -13, 1, 1, 3, -5, -12, -17, -25, -36, -27, -25, -39, + -45, -24, 1, 0, 8, 25, 43, 45, 42, 57, 76, 76, 73, 60, 37, -8, + -25, -22, -25, -6, 9, 21, 41, 41, 15, -6, -18, -33, -48, -40, -38, -57, + -64, -46, -6, 9, -4, 1, -1, -9, -18, -28, -33, -24, -27, -42, -45, -18, + 2, 3, 13, 31, 49, 43, 37, 60, 74, 68, 68, 60, 30, -12, -28, -23, + -19, -8, 5, 26, 48, 37, 11, -12, -17, -37, -54, -40, -41, -58, -65, -42, + 5, 12, -8, 0, 2, -6, -22, -29, -30, -28, -37, -44, -42, -9, 6, 7, + 17, 33, 44, 42, 40, 61, 72, 57, 63, 61, 24, -16, -34, -21, -15, -12, + 3, 31, 47, 28, 7, -10, -15, -43, -51, -38, -45, -61, -61, -31, 10, 8, + -3, 6, 5, -8, -24, -27, -28, -31, -44, -42, -29, -3, 6, 10, 24, 40, + 44, 45, 46, 57, 62, 56, 65, 56, 16, -13, -32, -18, -12, -10, 11, 32, + 39, 25, 6, -10, -19, -48, -44, -38, -49, -63, -61, -19, 12, 3, 4, 6, + 3, -9, -25, -26, -27, -38, -46, -39, -18, 1, 12, 20, 29, 33, 36, 49, + 47, 54, 59, 49, 63, 51, 8, -12, -25, -18, -18, -6, 20, 33, 28, 19, + 4, -9, -27, -43, -41, -45, -55, -64, -51, -13, 7, -3, 0, 7, 3, -12, + -28, -27, -33, -46, -51, -33, -10, -5, 15, 31, 34, 26, 32, 47, 51, 53, + 47, 50, 61, 41, 1, -8, -12, -21, -20, 5, 27, 29, 16, 13, 8, -9, + -28, -40, -40, -44, -55, -62, -40, -8, 5, -2, 4, 11, 4, -15, -26, -26, + -37, -49, -47, -27, -8, -3, 22, 45, 38, 22, 34, 47, 55, 52, 39, 44, + 58, 32, 2, 0, -7, -25, -21, 10, 29, 30, 9, 0, 0, -7, -26, -38, + -40, -53, -61, -53, -30, -5, 1, -2, 5, 10, 3, -18, -25, -33, -43, -51, + -46, -20, -10, -8, 26, 52, 35, 19, 32, 47, 56, 46, 33, 44, 48, 20, + 10, 11, -7, -29, -20, 15, 35, 28, 2, -9, -8, -6, -26, -32, -36, -54, + -64, -52, -22, 1, 3, 2, 3, 15, 2, -22, -24, -34, -41, -45, -39, -19, + -9, 1, 35, 57, 37, 18, 27, 46, 52, 41, 37, 44, 40, 18, 16, 13, + -7, -29, -14, 23, 36, 17, -6, -17, -2, 1, -24, -38, -43, -59, -62, -44, + -22, -4, 7, 2, 5, 16, -2, -24, -27, -36, -43, -48, -37, -20, -5, 14, + 40, 52, 36, 20, 26, 43, 46, 40, 41, 42, 28, 19, 19, 9, -4, -21, + -10, 27, 32, 10, -6, -16, -4, -5, -14, -37, -48, -59, -58, -36, -24, -1, + 13, -3, 7, 16, -5, -19, -32, -38, -46, -43, -32, -22, -7, 22, 49, 57, + 37, 22, 20, 37, 41, 36, 46, 41, 21, 19, 16, 9, -2, -25, -9, 27, + 24, 8, -12, -11, -2, -9, -10, -39, -51, -59, -59, -35, -21, 2, 15, -5, + 10, 11, -12, -19, -35, -39, -46, -35, -29, -26, -5, 37, 60, 53, 36, 26, + 19, 33, 37, 33, 48, 41, 18, 17, 19, 11, -8, -23, -3, 30, 21, -5, + -14, -2, -6, -9, -9, -42, -59, -64, -54, -33, -16, 6, 14, 0, 15, 4, + -14, -17, -35, -45, -46, -33, -27, -22, 2, 42, 56, 49, 37, 26, 19, 26, + 23, 36, 58, 44, 11, 8, 23, 10, -7, -15, 3, 26, 12, -10, -8, 3, + -10, -7, -13, -46, -58, -60, -57, -40, -11, 9, 9, 3, 13, -6, -12, -17, + -42, -53, -45, -28, -23, -14, 11, 49, 60, 49, 40, 27, 14, 16, 13, 43, + 62, 46, 6, 8, 22, 7, -9, -10, 11, 23, 4, -17, 2, 6, -6, -7, + -21, -51, -58, -58, -55, -38, -12, 12, 10, 13, 1, -15, -7, -14, -47, -62, + -45, -29, -19, -2, 21, 51, 63, 46, 37, 31, 16, 0, 4, 43, 64, 43, + 6, 9, 24, 4, -15, -2, 14, 9, -9, -15, 14, 7, -11, -10, -29, -53, + -54, -57, -48, -35, -9, 13, 9, 11, -5, -6, -2, -22, -57, -60, -39, -24, + -11, 5, 30, 52, 62, 49, 42, 38, 11, -9, 7, 45, 61, 44, 10, 15, + 21, -4, -15, 3, 13, 1, -13, -9, 13, 7, -9, -13, -32, -51, -53, -56, + -44, -35, -9, 15, 11, 7, -8, 0, -2, -34, -65, -56, -31, -24, -7, 20, + 37, 49, 56, 47, 47, 39, -3, -16, 12, 40, 53, 45, 16, 23, 17, -7, + -8, 7, 8, -5, -12, -7, 7, 7, -4, -17, -38, -56, -60, -50, -37, -33, + -8, 7, 9, 0, -6, 7, -8, -47, -71, -50, -25, -23, 0, 33, 41, 46, + 52, 53, 54, 35, -6, -9, 13, 32, 50, 48, 23, 25, 13, -4, -3, 0, + -1, -7, -7, -8, 3, 6, -3, -22, -41, -55, -62, -46, -30, -24, -5, 0, + 5, 2, 3, 10, -20, -57, -69, -41, -19, -16, 5, 37, 47, 46, 49, 54, + 58, 29, -4, -6, 7, 21, 49, 49, 24, 24, 12, -2, -5, -9, 0, 0, + -10, -15, 2, 8, -4, -23, -42, -57, -66, -43, -22, -16, -11, -8, 3, 5, + 7, 4, -28, -61, -61, -36, -19, -11, 10, 45, 51, 43, 46, 52, 54, 26, + 3, -8, -3, 15, 52, 48, 27, 30, 15, -1, -9, -14, 0, -2, -15, -17, + -2, -1, -5, -23, -37, -62, -64, -34, -17, -15, -19, -8, 4, 7, 8, -8, + -37, -55, -50, -33, -19, -5, 16, 49, 54, 44, 45, 52, 53, 32, 3, -12, + -5, 14, 46, 46, 38, 34, 21, 6, -13, -21, -2, -3, -18, -19, -14, -9, + -2, -14, -44, -74, -56, -26, -15, -16, -18, -6, -1, 7, 6, -20, -43, -48, + -35, -32, -24, 1, 23, 51, 54, 41, 42, 52, 49, 32, 3, -14, -5, 19, + 42, 47, 43, 38, 27, 10, -18, -19, -5, -7, -18, -27, -23, -9, 2, -8, + -51, -75, -41, -19, -15, -13, -15, -11, -5, 10, 1, -30, -37, -40, -30, -33, + -24, 6, 30, 49, 49, 45, 43, 52, 39, 24, 7, -10, -7, 12, 33, 44, + 48, 43, 36, 7, -29, -18, -6, -14, -23, -36, -32, -12, 2, -16, -60, -65, + -27, -22, -22, -9, -6, -14, -6, 11, -10, -38, -35, -27, -26, -35, -15, 18, + 39, 47, 48, 51, 55, 51, 28, 22, 13, -5, -6, 5, 27, 46, 57, 49, + 39, 1, -29, -12, -7, -15, -28, -48, -39, -11, -1, -28, -61, -51, -22, -30, + -22, -3, -4, -21, -6, 8, -23, -45, -29, -18, -27, -32, -11, 24, 44, 40, + 46, 56, 61, 44, 17, 18, 19, 1, -11, -2, 24, 48, 57, 54, 45, 2, + -27, -12, -11, -18, -32, -49, -41, -16, -10, -32, -47, -33, -25, -34, -13, 6, + -5, -24, -13, -4, -29, -43, -29, -18, -25, -21, -1, 25, 44, 40, 49, 67, + 60, 31, 12, 18, 24, -2, -18, -5, 22, 45, 62, 65, 46, -5, -21, -12, + -12, -17, -36, -57, -48, -23, -15, -29, -35, -28, -33, -31, -3, 12, -16, -32, + -12, -19, -36, -33, -25, -22, -29, -10, 14, 30, 41, 35, 51, 73, 57, 27, + 16, 21, 14, -4, -12, -2, 21, 41, 62, 71, 43, -7, -12, -19, -22, -23, + -46, -57, -51, -35, -20, -17, -22, -26, -37, -27, 7, 12, -24, -31, -14, -29, + -34, -30, -22, -20, -21, 2, 15, 26, 40, 45, 55, 66, 52, 28, 20, 17, + 10, -1, -12, -4, 21, 43, 65, 74, 39, 1, -9, -25, -27, -24, -45, -61, + -55, -43, -22, -9, -12, -24, -32, -26, 9, 7, -25, -31, -30, -40, -31, -26, + -19, -20, -11, 14, 18, 27, 45, 54, 52, 61, 49, 33, 24, 15, 5, 0, + -14, -2, 24, 44, 62, 67, 37, 12, -9, -30, -29, -33, -49, -66, -58, -51, + -25, -2, -6, -19, -31, -24, 6, 3, -21, -37, -43, -42, -31, -25, -17, -19, + -5, 15, 19, 30, 52, 56, 45, 54, 52, 38, 22, 11, 8, 0, -16, 2, + 27, 44, 63, 60, 34, 16, -10, -25, -31, -38, -55, -68, -62, -53, -18, 5, + -2, -17, -31, -16, 5, -4, -22, -43, -50, -38, -32, -21, -16, -11, 8, 10, + 19, 32, 60, 60, 43, 46, 51, 37, 24, 13, 8, -6, -17, 4, 32, 52, + 56, 52, 39, 23, -5, -23, -41, -48, -64, -65, -63, -57, -14, 9, 3, -18, + -28, -9, 0, -11, -25, -47, -53, -38, -30, -19, -11, 0, 10, 11, 23, 42, + 66, 60, 42, 49, 53, 36, 24, 20, 9, -17, -18, 3, 39, 59, 49, 41, + 39, 26, 1, -24, -53, -59, -70, -61, -66, -58, -12, 17, 7, -20, -26, -7, + -7, -16, -30, -51, -60, -45, -26, -11, -5, 5, 8, 10, 23, 48, 66, 55, + 40, 48, 48, 33, 30, 25, 2, -21, -15, 10, 41, 51, 44, 37, 41, 27, + 6, -28, -60, -65, -70, -63, -70, -55, -6, 21, 1, -20, -15, -2, -15, -24, + -32, -54, -66, -45, -22, -8, 6, 13, 5, 15, 31, 51, 64, 58, 41, 42, + 44, 35, 36, 29, 0, -20, -9, 14, 43, 53, 46, 39, 39, 24, 7, -33, + -69, -75, -73, -70, -75, -46, 4, 17, -2, -18, -6, 3, -18, -32, -38, -61, + -65, -39, -17, -2, 10, 10, 5, 19, 33, 55, 61, 54, 39, 40, 41, 41, + 40, 30, -6, -25, -6, 22, 44, 48, 42, 42, 37, 23, 11, -42, -73, -77, + -75, -74, -75, -39, 4, 8, -5, -15, 1, -1, -30, -33, -38, -69, -66, -40, + -14, 3, 16, 8, 5, 21, 39, 60, 59, 48, 40, 38, 39, 42, 42, 30, + -8, -20, 0, 26, 48, 51, 48, 43, 29, 21, 1, -47, -70, -80, -83, -80, + -70, -25, 0, -2, -9, -6, 9, -7, -29, -33, -49, -72, -59, -29, -3, 3, + 11, 6, 14, 27, 47, 61, 54, 47, 43, 34, 42, 45, 39, 21, -10, -17, + 4, 29, 53, 54, 47, 39, 29, 22, -11, -53, -70, -83, -86, -77, -61, -19, + -6, -7, -12, -2, 9, -14, -29, -35, -61, -70, -54, -25, -8, 2, 11, 8, + 17, 27, 54, 60, 50, 45, 42, 40, 43, 39, 35, 18, -9, -7, 8, 28, + 55, 56, 49, 32, 30, 15, -21, -53, -71, -88, -87, -74, -45, -12, -11, -15, + -14, 6, 12, -12, -30, -48, -66, -60, -44, -18, -8, 5, 13, 15, 21, 31, + 51, 57, 48, 43, 42, 40, 43, 37, 29, 16, -3, -1, 7, 35, 60, 54, + 38, 26, 29, 5, -30, -54, -72, -93, -87, -69, -34, -14, -19, -25, -12, 13, + 6, -17, -37, -56, -66, -49, -38, -18, -11, 1, 17, 24, 26, 32, 47, 52, + 50, 49, 45, 39, 40, 33, 32, 13, 4, 3, 3, 47, 65, 52, 29, 27, + 20, -5, -35, -56, -76, -90, -79, -63, -27, -17, -26, -24, 0, 12, -2, -16, + -33, -61, -61, -42, -33, -17, -16, -6, 22, 30, 25, 29, 45, 50, 46, 53, + 41, 37, 37, 33, 28, 17, 15, 2, 15, 54, 64, 46, 21, 25, 9, -12, + -39, -58, -77, -87, -75, -46, -21, -23, -34, -24, 9, 9, -7, -17, -40, -67, + -53, -33, -27, -22, -26, -4, 34, 34, 25, 27, 46, 44, 52, 59, 37, 30, + 35, 32, 26, 25, 16, 2, 30, 62, 57, 33, 19, 17, -7, -25, -43, -58, + -80, -82, -64, -36, -26, -26, -33, -17, 11, 4, -9, -18, -45, -62, -44, -30, + -24, -28, -29, 5, 38, 32, 25, 30, 48, 41, 53, 57, 35, 28, 26, 27, + 31, 29, 14, 12, 47, 63, 48, 35, 24, 4, -19, -32, -46, -55, -76, -77, + -58, -31, -30, -33, -36, -8, 12, -4, -9, -22, -51, -57, -30, -23, -27, -40, + -31, 18, 36, 31, 30, 33, 39, 36, 56, 51, 32, 27, 20, 24, 39, 30, + 16, 29, 55, 53, 43, 36, 21, -5, -28, -39, -45, -55, -71, -70, -47, -27, + -35, -36, -25, -2, 1, -4, -6, -23, -48, -48, -25, -16, -25, -46, -23, 24, + 30, 35, 34, 29, 33, 37, 51, 41, 30, 21, 12, 27, 47, 33, 19, 38, + 51, 43, 39, 36, 15, -17, -35, -35, -42, -55, -68, -62, -45, -33, -40, -36, + -19, -5, -4, -3, -6, -24, -47, -38, -17, -13, -37, -48, -13, 26, 30, 36, + 32, 27, 29, 36, 48, 38, 27, 9, 5, 34, 47, 31, 30, 49, 47, 36, + 38, 28, 11, -21, -32, -32, -47, -56, -60, -54, -40, -39, -42, -31, -12, -5, + -7, -1, -4, -21, -39, -28, -11, -13, -45, -42, -2, 23, 25, 42, 33, 26, + 26, 33, 44, 34, 20, 1, 5, 36, 47, 38, 40, 47, 37, 35, 38, 20, + 1, -23, -26, -35, -49, -56, -55, -48, -40, -46, -42, -28, -12, -12, -10, 2, + -6, -25, -32, -25, -13, -22, -43, -30, 5, 18, 24, 45, 35, 29, 21, 27, + 39, 28, 16, 2, 9, 39, 40, 44, 55, 45, 25, 31, 34, 15, -1, -18, + -25, -41, -49, -50, -52, -46, -42, -48, -40, -23, -9, -18, -13, 9, -1, -24, + -27, -22, -14, -30, -41, -26, 8, 15, 25, 40, 36, 26, 15, 26, 35, 21, + 11, 2, 17, 44, 37, 54, 63, 37, 16, 31, 27, 12, -3, -12, -24, -45, + -47, -46, -45, -40, -44, -55, -40, -17, -12, -22, -7, 19, -2, -22, -24, -15, + -17, -36, -36, -11, 16, 10, 17, 38, 43, 25, 15, 25, 26, 14, 7, 2, + 25, 39, 38, 63, 67, 30, 16, 25, 18, 14, -5, -9, -26, -43, -45, -47, + -42, -38, -52, -57, -35, -14, -22, -27, 0, 23, -5, -24, -22, -12, -21, -40, + -31, 1, 19, 6, 11, 35, 44, 22, 18, 28, 14, 4, 4, 11, 32, 34, + 38, 70, 68, 22, 18, 17, 15, 17, 0, -10, -31, -45, -43, -42, -34, -36, + -62, -61, -25, -11, -28, -29, 3, 25, -3, -26, -15, -12, -28, -34, -21, 9, + 17, 2, 10, 31, 40, 24, 23, 28, 5, -3, 6, 19, 35, 33, 42, 72, + 59, 22, 22, 12, 17, 17, 2, -11, -31, -40, -40, -36, -28, -40, -66, -57, + -18, -15, -32, -22, 9, 22, -3, -23, -8, -12, -31, -32, -12, 18, 15, -1, + 9, 25, 36, 26, 27, 20, -7, -5, 12, 23, 29, 33, 45, 70, 48, 25, + 20, 8, 16, 9, 4, -11, -33, -39, -37, -34, -30, -46, -65, -50, -23, -22, + -30, -19, 13, 22, -4, -21, -6, -15, -32, -28, -3, 18, 9, 0, 9, 21, + 30, 28, 30, 12, -14, -1, 17, 19, 27, 41, 51, 63, 35, 28, 22, 12, + 10, 6, 9, -14, -31, -36, -31, -27, -38, -49, -62, -48, -29, -25, -27, -13, + 13, 13, -3, -9, -9, -21, -30, -20, 4, 12, 4, 5, 12, 19, 27, 33, + 29, 6, -12, 2, 21, 17, 31, 45, 54, 55, 31, 31, 25, 14, 3, 5, + 11, -14, -27, -33, -24, -27, -41, -49, -63, -53, -37, -26, -22, -7, 11, 8, + 0, -3, -14, -19, -27, -14, 8, 5, 2, 9, 12, 20, 25, 31, 18, 0, + -6, 8, 20, 14, 27, 43, 59, 48, 24, 28, 25, 14, 2, 8, 6, -15, + -26, -30, -16, -28, -44, -53, -61, -58, -37, -27, -21, -4, 8, 3, 1, -2, + -18, -21, -24, -11, 3, -4, 3, 15, 17, 20, 22, 29, 15, 3, -2, 8, + 17, 18, 30, 46, 56, 40, 21, 29, 26, 14, -1, 5, 4, -6, -22, -29, + -13, -27, -46, -51, -62, -61, -37, -28, -14, 2, 7, 0, 5, -2, -16, -17, + -19, -10, -7, -9, 11, 20, 22, 18, 17, 25, 19, 4, -1, 10, 19, 25, + 32, 44, 53, 36, 19, 29, 24, 10, -4, 5, 4, -2, -22, -24, -13, -31, + -48, -56, -63, -60, -40, -31, -11, 8, 8, 2, 8, -6, -20, -17, -12, -10, + -20, -12, 14, 30, 26, 10, 14, 24, 24, -1, -7, 12, 25, 27, 30, 40, + 52, 34, 17, 28, 24, 7, -9, 1, 8, 3, -20, -20, -16, -33, -53, -59, + -62, -61, -47, -29, -5, 15, 5, 1, 9, -8, -20, -14, -5, -12, -30, -11, + 20, 37, 25, 10, 19, 25, 19, -5, -2, 18, 28, 26, 29, 41, 49, 31, + 20, 30, 24, 1, -8, 4, 10, 3, -17, -12, -18, -40, -57, -61, -62, -59, + -48, -23, 0, 18, 5, 5, 12, -9, -19, -9, -2, -20, -37, -7, 25, 39, + 23, 11, 25, 26, 10, -10, 5, 23, 24, 26, 30, 40, 42, 27, 23, 31, + 18, -7, -5, 2, 7, -1, -10, -10, -22, -45, -59, -63, -62, -58, -45, -21, + -1, 17, 10, 13, 7, -18, -21, -5, -3, -27, -38, -7, 26, 38, 21, 20, + 31, 23, 0, -9, 15, 25, 21, 28, 33, 35, 35, 29, 28, 31, 12, -5, + 0, 0, 4, 0, -3, -14, -27, -48, -57, -69, -66, -61, -40, -19, 1, 16, + 13, 16, -3, -18, -17, -4, -9, -30, -33, -1, 24, 35, 28, 34, 31, 16, + -4, -2, 22, 29, 20, 27, 38, 33, 30, 30, 31, 33, 9, 1, -3, -7, + 2, 6, -1, -22, -31, -50, -61, -74, -67, -52, -34, -25, 1, 19, 21, 14, + -8, -18, -14, -10, -14, -27, -26, -5, 21, 35, 38, 40, 31, 12, -1, 5, + 22, 29, 19, 31, 41, 28, 30, 28, 31, 28, 12, 7, -13, -11, -2, 13, + -5, -26, -32, -52, -67, -80, -65, -46, -34, -26, 2, 15, 25, 9, -8, -14, + -16, -10, -18, -25, -25, -9, 20, 37, 46, 35, 26, 10, 7, 8, 18, 27, + 18, 31, 39, 25, 29, 29, 34, 26, 20, 2, -18, -10, -5, 12, -9, -22, + -31, -48, -74, -79, -66, -42, -34, -22, -1, 14, 25, 13, -6, -19, -16, -8, + -19, -22, -21, -5, 21, 41, 51, 32, 25, 14, 19, 13, 14, 21, 21, 32, + 34, 26, 26, 30, 32, 25, 25, -3, -19, -13, -2, 8, -12, -24, -32, -46, + -75, -79, -67, -43, -33, -18, -7, 12, 25, 18, 0, -23, -13, -7, -23, -18, + -15, -4, 21, 48, 51, 27, 27, 23, 22, 12, 12, 19, 22, 28, 28, 28, + 28, 31, 28, 23, 28, -3, -20, -22, -5, 0, -14, -23, -28, -50, -78, -81, + -63, -44, -34, -19, -14, 10, 25, 18, -6, -19, -5, -11, -30, -17, -8, 2, + 21, 54, 45, 25, 28, 33, 25, 9, 12, 21, 26, 23, 24, 33, 37, 35, + 20, 23, 32, -1, -21, -25, -12, -11, -12, -19, -27, -53, -78, -79, -55, -42, + -31, -26, -18, 12, 24, 13, -9, -12, 0, -20, -33, -13, 1, 6, 26, 55, + 38, 25, 33, 45, 26, 7, 13, 21, 26, 16, 18, 38, 44, 33, 14, 25, + 30, 4, -24, -32, -21, -18, -19, -19, -25, -54, -79, -78, -53, -43, -29, -28, + -20, 6, 20, 12, -3, 0, -3, -35, -28, 1, 9, 8, 25, 46, 34, 30, + 37, 44, 19, 13, 20, 17, 20, 12, 18, 49, 49, 23, 13, 28, 33, 3, + -34, -37, -28, -30, -21, -10, -26, -57, -77, -74, -52, -40, -25, -32, -22, 3, + 17, 12, 3, 8, -15, -40, -18, 10, 10, 4, 32, 39, 27, 38, 48, 39, + 11, 18, 28, 17, 15, 5, 23, 61, 46, 21, 23, 35, 26, -3, -31, -37, + -39, -38, -23, -3, -29, -60, -74, -68, -58, -37, -27, -35, -22, -7, 15, 23, + 14, 8, -27, -41, -6, 19, 14, 9, 35, 31, 31, 48, 54, 35, 11, 27, + 26, 4, 7, 11, 31, 54, 38, 25, 34, 35, 20, -10, 19, 3, -8, -45, + 64, -15, -41, 23, 40, -58, 22, 29, -27, -28, 42, -36, 21, -12, -19, 39, + -14, 3, -18, 32, -27, 18, -8, -43, 43, 25, -52, 6, 19, 13, -7, -50, + 55, 5, -46, -22, 94, -53, -33, 35, 27, -45, -2, 20, 19, -30, -23, 47, + 8, -58, 5, 76, -67, -22, 42, 30, -54, 8, 23, 11, -51, 3, 47, -33, + -7, 5, 27, -33, 34, -35, 17, 4, -26, 5, 17, -30, 33, 5, -29, -5, + 44, -18, -50, 60, -33, 10, -5, 10, -7, 1, -5, 19, -36, 3, 37, -17, + -51, 52, 37, -64, 9, 4, 37, -44, -13, 25, 45, -75, -9, 79, -34, -57, + 53, 24, -59, 18, 22, -3, -24, 10, -2, 18, -53, 29, 35, -20, -43, 37, + 18, -17, -31, 8, 45, -49, 8, 11, 9, -23, 30, -24, -22, 29, 14, -43, + 27, 13, -22, -1, 2, 22, -37, 5, -5, 38, -43, 6, 36, -21, -20, 20, + 0, -5, -27, 27, 21, -53, 4, 52, -2, -84, 70, 5, -29, -19, 36, -6, + -8, -12, 3, 35, -32, -25, 48, 6, -60, 49, 4, -27, -13, 31, -15, -9, + -4, 31, -13, -25, 29, 12, -34, -6, 30, -41, 36, -23, 6, 31, -30, 0, + 17, -45, 47, -5, -47, 19, 28, -8, -30, 27, -6, 15, -54, 34, 21, -27, + -9, 25, 3, -45, 26, 27, -52, 22, 20, -29, 34, -46, 22, 40, -69, -27, + 108, -49, -54, 69, -11, -3, -18, 3, 15, -12, -23, 29, -8, 4, -23, 50, + -38, -8, 33, -32, -2, 26, -27, 12, 13, -39, 56, -31, -22, 28, 2, -39, + 54, -20, -36, 51, -6, -34, 15, 2, 1, 2, -36, 42, 2, -10, -39, 64, + -36, -16, 24, 1, -1, -18, -10, 54, -27, -54, 80, -18, -61, 51, 27, -76, + 64, -30, -1, 9, -19, 24, 13, -29, -13, 49, -18, -46, 43, 6, -47, 42, + -28, 14, 18, -18, 2, 14, -39, 25, 16, -58, 33, 29, -49, 16, 41, -62, + 43, -17, -17, 25, -10, -28, 41, -5, -30, 27, 14, -53, 27, 35, -63, 16, + 30, 0, -30, -10, 22, 31, -57, 0, 68, -59, 2, 37, -30, 6, -3, -19, + 35, -29, 1, 20, 22, -68, 33, 39, -71, 21, 27, -22, -1, 3, 0, 18, + -16, -13, 17, 4, -37, 44, -15, -26, 48, -29, -11, 34, -25, -4, 25, -48, + 43, 4, -49, 28, 42, -72, 7, 59, -36, -28, 45, -9, -28, 25, -19, 23, + -9, -40, 47, 18, -85, 78, -2, -53, 39, -17, 2, 14, -36, 10, 63, -78, + 17, 59, -66, -8, 54, -49, 14, 1, 5, 2, -18, 16, -12, 30, -58, 22, + 53, -83, 17, 79, -84, 19, 17, -34, 44, -33, -27, 82, -62, -19, 91, -93, + 22, 49, -51, -25, 48, -12, -6, 1, -2, -1, 22, -32, -1, 59, -78, 12, + 58, -49, -26, 70, -40, -8, 16, -8, 12, 10, -65, 74, -1, -97, 90, 0, + -56, 23, 25, -17, 11, -23, 14, 9, -24, -31, 77, -41, -48, 95, -38, -46, + 59, -1, -57, 49, -33, 19, 18, -46, 34, 31, -79, 47, 11, -38, 10, 19, + -14, -10, 26, -29, 28, -17, -27, 48, -15, -51, 78, -14, -73, 64, 12, -55, + 29, 3, -24, 52, -65, 26, 50, -75, -5, 81, -76, 0, 42, -6, -26, 10, + 18, -14, 4, -24, 33, 2, -69, 61, 43, -101, 40, 54, -73, 22, 18, -41, + 44, -19, -43, 94, -69, -13, 65, -26, -46, 35, 24, -34, -2, 23, -13, 6, + -19, 4, 38, -56, 14, 40, -37, -19, 66, -57, -9, 50, -47, 21, 6, -31, + 55, -34, -50, 98, -44, -47, 44, 28, -51, 6, 31, -3, -34, 8, 11, 6, + -18, -27, 78, -48, -28, 55, -2, -60, 57, -37, 14, 15, -48, 49, 22, -96, + 74, 23, -83, 36, 18, -17, -25, 41, -12, -4, -2, 1, 9, -14, -18, 36, + 12, -77, 54, 32, -67, 20, 38, -67, 61, -53, 32, 21, -60, 27, 41, -74, + 27, 33, -30, -6, 22, -1, -30, 20, 1, -4, -22, 9, 8, 37, -65, 18, + 61, -69, -3, 37, -19, -15, 15, -16, 57, -78, 20, 66, -67, -27, 76, -37, + -16, 11, 11, -5, -18, 10, 16, -5, -38, 36, 9, -20, -32, 73, -41, -36, + 62, -33, -9, 34, -41, 35, -7, -40, 65, -35, -26, 33, 2, -43, 42, -4, + -9, 5, -11, 19, -10, -16, 11, 16, -28, -9, 41, 2, -70, 67, -3, -55, + 23, 33, -26, 6, -29, 43, 16, -85, 51, 28, -54, 7, 27, -9, 2, -18, + 27, -4, -42, 31, 10, -19, -9, 18, 8, -24, -3, 45, -57, 25, 0, -7, + 15, -28, 10, 33, -46, -6, 52, -36, -15, 46, -29, -4, 12, -14, 34, -57, + 16, 40, -41, 3, 16, 8, -32, 16, 15, -17, -27, 47, -30, -1, 14, -5, + 16, -17, -33, 70, -44, -42, 84, -34, -27, 18, 15, 3, -20, -22, 55, -35, + -22, 31, 10, -11, -27, 27, 13, -28, -10, 41, -21, -3, -22, 41, -21, -13, + 6, 34, -68, 46, 25, -65, 50, -21, -1, 10, -33, 34, 1, -43, 58, -34, + -2, 13, 8, -25, 0, -2, 34, -29, -26, 45, -12, 4, -34, 32, 15, -54, + 17, 53, -76, 41, 4, -17, 13, -26, 13, 31, -47, 1, 52, -53, 11, 8, + 14, -31, -7, 19, 30, -60, 26, 27, -22, -10, 0, 18, -13, -24, 52, -38, + -17, 68, -60, 26, -9, -25, 41, -29, -8, 40, -25, -9, 26, -28, 15, -9, + -3, 11, -21, -1, 44, -47, 19, 0, 3, -14, -12, 38, -22, -23, 37, -10, + -13, 9, -6, 21, -14, -39, 61, -4, -68, 60, 6, -43, 28, -14, 21, -22, + -13, 36, -7, -40, 46, -14, -5, -18, 20, 22, -49, 22, 10, -18, 21, -30, + 9, 34, -54, 19, 22, -34, 27, 7, -45, 30, 0, -20, 23, -23, 29, -10, + -21, 25, 3, -23, -1, 5, 16, -33, 14, 25, -21, -11, 16, 3, -22, 5, + 6, 32, -73, 27, 62, -72, 5, 26, -21, 30, -37, 4, 40, -45, 5, 18, + -18, -1, 12, -3, 0, -18, 28, -8, -14, 11, -11, 13, -15, -3, 27, -17, + -30, 65, -45, -5, 28, -25, 1, 20, -36, 38, -11, -20, 35, -23, -20, 27, + 11, -42, 13, 17, 1, -25, 20, 10, -33, 10, 6, -7, 9, -26, 40, -3, + -63, 74, -30, -11, 10, -10, 5, 17, -47, 53, -10, -47, 29, 31, -45, 4, + 16, 14, -15, -33, 40, -11, -3, -10, 2, 18, -20, 9, 22, -44, 19, 20, + -42, 25, -5, -11, 25, -25, -3, 47, -63, 28, 20, -42, 7, 39, -41, 2, + 13, 10, -24, -8, 41, -26, -1, -13, 9, 42, -60, 0, 61, -54, -4, 19, + -6, 11, -19, -13, 52, -37, -26, 66, -38, -30, 49, -18, -11, 5, 7, 10, + -30, 4, 17, 2, -12, -15, 38, -19, -20, 30, -16, -23, 38, -13, -16, 29, + -22, 26, -17, -35, 62, -30, -35, 51, -16, -27, 40, -16, 3, -8, -4, 9, + 4, -26, 11, 20, -11, -38, 56, -19, -29, 31, 7, -39, 17, 10, 6, -8, + -41, 45, 26, -79, 36, 42, -58, 21, 6, -10, 7, -19, 17, -1, -15, -12, + 53, -22, -32, 24, 25, -59, 24, 22, -36, 10, 18, -27, 44, -45, 0, 42, + -45, -2, 30, -27, 12, 23, -38, 13, 5, 4, -4, -20, 1, 43, -27, -36, + 43, 14, -51, 12, 40, -41, 5, 18, -11, -1, -5, -11, 53, -56, -29, 91, + -41, -45, 57, -7, -18, -3, -4, 29, -20, -19, 20, 26, -57, 31, 17, -22, + -13, 28, -31, 3, 36, -33, 9, 17, -39, 42, -9, -54, 58, 6, -69, 44, + 30, -50, 24, 3, -17, 9, -20, 17, 8, -23, 1, 46, -50, 1, 27, 1, + -49, 37, 5, -17, 4, -5, 7, 18, -55, 39, 36, -85, 37, 48, -63, 5, + 27, -13, -6, -4, 5, 24, -26, -12, 42, -25, -34, 33, 20, -33, -13, 29, + -2, 7, -34, 12, 37, -50, 1, 47, -46, -1, 56, -54, -18, 59, -35, -6, + 12, -16, 20, -2, -27, 43, -12, -34, 22, 25, -41, -7, 43, -20, -18, 19, + -1, 1, -6, -20, 54, -55, -12, 67, -24, -56, 56, -8, -12, -7, -3, 16, + 20, -48, 20, 32, -46, 8, 23, -17, -38, 54, 1, -34, 2, 30, -1, -21, + -18, 38, -14, -35, 41, 3, -36, 19, 22, -45, 40, -32, 12, 12, -26, 2, + 35, -54, 34, 14, -25, -30, 47, 10, -53, 24, 13, -4, -18, 3, 5, 27, + -61, 38, 15, -39, 6, 40, -36, 0, 2, -6, 28, -40, 7, 46, -37, -30, + 59, -21, -29, 6, 48, -55, 12, 30, -21, -6, 5, -2, 1, -14, -7, 46, + -41, -4, 35, -8, -33, 29, -20, 26, -31, -10, 63, -46, -4, 12, 7, -11, + -15, 26, -14, -22, 54, -47, 12, 9, -1, -8, -7, -8, 41, -12, -60, 77, + -21, -26, 11, 13, 1, -26, -9, 59, -45, -16, 38, -3, -27, -1, 28, -8, + -19, 11, 20, -41, 34, -23, 22, -20, -9, 6, 51, -79, 40, 18, -40, 23, + -5, -19, 13, 2, 3, -4, -35, 71, -39, 5, -30, 33, 6, -29, -3, 38, + -29, -5, 18, -9, -4, -11, 16, 15, -32, -14, 77, -83, 30, 10, -10, -19, + 20, 15, -17, -19, 29, 7, -32, 6, -1, 14, -14, -6, 5, 36, -58, 47, + -18, -14, 4, 8, 8, -24, -15, 60, -36, -20, 43, -32, 3, -2, 1, 9, + -5, -8, 30, -33, 6, 6, 2, -12, -11, 24, 1, -22, 9, 34, -61, 25, + 11, -5, -18, -1, 38, -19, -33, 49, -19, -21, 18, -7, 1, 5, -4, -3, + 13, -30, 25, -5, -12, 2, 8, 17, -37, 0, 50, -38, -26, 40, -15, 7, + -24, 31, -11, -8, 6, -6, -3, 1, 9, -8, 6, -20, 25, 0, -21, 7, + 22, -48, 29, -4, 10, -22, 7, 22, -9, -34, 45, -15, -31, 30, -2, 0, + -30, 46, -18, -6, -17, 31, -6, -7, -21, 8, 45, -47, -7, 31, -17, -11, + 25, -20, 17, -30, 47, -38, -2, 5, 16, -36, 24, -2, 3, -7, 6, 10, + -23, 5, -11, 35, -42, 17, 0, 21, -35, 11, 16, -18, -15, 36, -24, -3, + 9, 5, 13, -49, 36, -11, -2, -14, 37, -32, 13, -1, 0, -2, -2, -8, + 17, -11, -21, 30, -1, -1, -41, 72, -65, 14, 14, 12, -41, 21, 4, 15, + -32, -1, 25, -9, -18, 3, 29, -38, 35, -22, 14, -20, 16, -6, -6, -13, + 29, -4, -17, 7, 14, -6, -38, 54, -32, 3, -16, 36, -39, 42, -40, 36, + -22, -13, 17, 14, -36, 12, 23, -25, 6, -25, 53, -33, -12, 5, 37, -46, + 6, 20, 9, -53, 52, -16, -22, 24, -9, 10, -17, 12, -20, 48, -73, 40, + 18, -30, -20, 52, -34, 11, -6, 0, 1, -15, 24, -16, 16, -30, 44, -27, + -10, 0, 34, -52, 24, 3, 2, -6, 12, -25, 35, -38, -14, 72, -73, 7, + 31, 15, -50, 20, 12, -5, -25, 23, 3, -10, -9, 15, 9, -41, 28, 6, + -5, -36, 44, -13, 10, -19, 2, 14, -10, -29, 56, -27, -35, 58, -19, -27, + 17, 16, -30, 10, -7, 15, -12, -3, 11, 18, -30, -13, 38, -17, -16, 3, + 32, -37, 23, -24, 30, -12, -26, 40, -14, -52, 59, 12, -55, 16, 35, -20, + -30, 39, -24, 21, -26, 12, 13, -10, -19, 23, 2, -35, 17, 33, -30, -17, + 39, -15, 12, -53, 50, -13, -25, 2, 50, -42, -1, 25, -22, 6, -5, 3, + -4, 2, -18, 39, -25, -3, 1, 29, -57, 22, 26, -22, -18, 34, -10, -10, + -11, 13, 31, -77, 46, 23, -22, -35, 61, -24, -13, 7, -3, 0, 4, -24, + 27, 12, -50, 35, 13, -19, -37, 69, -46, -4, 13, 5, -8, 6, -25, 40, + -26, -13, 38, -12, -28, 21, 22, -57, 40, -15, 11, -19, 4, 19, 9, -36, + 3, 42, -35, -30, 46, 0, -50, 59, -26, 9, -16, 12, -10, 10, -33, 44, + -8, -29, 8, 42, -43, -6, 26, -19, 14, -30, 34, 4, -21, -17, 49, -31, + -24, 34, 14, -53, 32, 13, -26, 12, -22, 26, -3, -22, -11, 66, -59, 0, + 43, -27, -23, 42, -32, 7, -7, 11, 9, -19, -1, 15, 16, -58, 43, 1, + -32, 11, 36, -44, 18, 0, 4, -4, -7, -22, 50, -22, -44, 67, -14, -43, + 37, 2, -32, 15, 7, 8, -22, -1, 14, 19, -43, 0, 40, -30, -14, 28, + 10, -32, 11, 1, 21, -33, -9, 31, 15, -72, 61, 4, -40, 21, 14, -37, + 22, 4, -4, -9, 5, -8, 23, -16, -22, 35, -24, 0, 12, 3, -17, 15, + 2, -10, -6, -8, 21, 7, -58, 40, 43, -75, 25, 28, -25, -18, 28, -15, + 6, -5, -4, 22, -5, -39, 37, 1, -30, 12, 23, -27, -8, 34, -22, 0, + -12, 15, 10, -28, 2, 45, -45, -9, 36, -22, -7, 13, -7, 6, 2, -18, + 17, 10, -34, 9, 18, -22, -1, 22, -9, -17, 23, -1, -22, 21, -20, 20, + -17, -6, 38, -33, -18, 55, -32, -21, 26, -5, -9, 5, -8, 16, 9, -47, + 36, 11, -36, -3, 38, -7, -48, 44, -2, -11, 2, -16, 15, 11, -36, 33, + -3, -18, 9, 19, -46, 26, -1, -11, 20, -24, 12, 16, -16, -17, 37, -32, + -6, 13, 13, -33, 25, 14, -27, 8, 1, -18, 22, -5, -15, 32, -46, 37, + -2, -19, -13, 38, -32, 8, 2, -4, 15, -12, -4, 19, -25, -10, 37, -19, + -11, -10, 57, -54, 19, -17, 18, 3, -18, -9, 27, -6, -36, 57, -23, -21, + 14, 11, -23, 32, -53, 56, -24, -5, -3, 11, -16, 16, -7, -20, 17, 11, + -3, -31, 42, -33, 14, -6, -2, -8, 39, -56, 48, -21, -20, 30, -8, -20, + 12, 15, -32, 41, -36, 29, -25, 14, -22, 22, -19, 9, 4, 10, -31, 17, + 11, -14, -1, -7, 17, -16, 6, -18, 64, -88, 47, 6, -20, -5, 22, -13, + 18, -28, 2, 25, -19, -10, -3, 29, -23, 11, -22, 39, -25, 13, -27, 20, + -2, -18, 15, -3, 3, 9, -17, -8, 38, -57, 35, 1, -9, -24, 43, -32, + 30, -30, -3, 19, -3, -21, 12, 14, -12, 2, -5, 11, -37, 37, -3, -13, + -4, 10, 11, -4, -38, 41, -9, -27, 37, -37, 16, 17, -7, -15, 22, -40, + 33, -2, -16, 4, 3, 8, -4, -20, 21, -3, -10, 8, -26, 37, -21, 8, + 0, -3, -3, 0, -8, 20, -15, -32, 54, -10, -26, 17, -12, 10, 24, -71, + 51, 3, -21, 9, -3, 17, -22, 2, 15, -21, -11, 39, -25, 11, -27, 28, + 3, -11, -26, 45, -43, 24, 7, -39, 47, -24, -15, 27, -13, -15, 35, -27, + 15, -17, 9, 0, -7, 0, 4, -9, 13, -3, -16, 28, -29, 21, -23, 11, + -4, 10, -30, 64, -63, 13, 28, -30, 16, -13, 0, 25, -39, -2, 53, -40, + 5, -19, 41, -25, -6, -3, 37, -40, 6, 8, 0, 6, -34, 32, 4, -27, + 13, 15, -34, 52, -63, 40, -5, -22, 5, 24, -32, 22, 11, -26, 14, -22, + 26, -21, 10, -8, 5, -10, 46, -66, 44, -20, 14, -7, -27, 23, 30, -53, + 24, 10, -37, 44, -40, 21, -11, 3, 6, 20, -47, 27, 5, -2, -18, -4, + 29, -13, -20, 27, 9, -47, 43, -37, 55, -62, 14, 33, -13, -28, 24, -9, + 23, -35, -4, 32, -14, -13, 28, -10, -30, 46, -43, 43, -46, 13, 13, -10, + 7, -3, -20, 39, -19, -19, 14, -15, 39, -31, -10, 25, 2, -34, 41, -35, + 15, -4, -3, 22, -18, -27, 46, -1, -36, 10, -4, 42, -56, 13, 31, -19, + -18, 28, -29, 27, -32, 24, 10, -44, 20, 32, -32, -17, 32, -13, 13, -35, + 20, 32, -53, 20, 9, -16, 16, -36, 39, -3, -33, 43, -26, 2, 2, 2, + -17, 24, -22, 14, -3, -12, 31, -28, -8, 26, -29, 19, -4, -15, 33, -39, + 22, 16, -37, 6, 17, -4, -13, -12, 37, 9, -65, 34, 25, -27, -9, 7, + 5, 10, -36, 45, -11, -41, 42, -6, -21, 7, -5, 31, -5, -57, 62, -12, + -15, -16, 23, 4, -24, 12, 26, -35, -11, 44, -25, -8, -1, -4, 28, -11, + -37, 61, -48, 23, -1, -30, 29, -8, -2, 6, -19, 18, 15, -41, 30, -4, + -11, -11, 28, -10, -4, -37, 81, -45, -43, 61, -19, 1, -11, 0, 31, -30, + -25, 68, -43, -11, 0, 27, -1, -33, -7, 77, -54, -30, 44, -6, -5, -14, + 17, -6, -10, 6, 30, -68, 50, -16, 5, 5, -30, 30, 26, -69, 36, 8, + -34, 37, -28, 11, 0, -1, 9, 1, -41, 53, -22, -24, 23, 5, -9, -11, + 12, 28, -61, 28, 36, -68, 51, -33, 25, -6, -26, 7, 53, -65, 2, 47, + -25, -23, 17, 20, -4, -51, 38, 29, -67, 31, 1, 22, -35, -8, 40, -9, + -46, 47, -13, -8, 5, -15, 37, -27, -20, 45, -16, -45, 59, -37, 19, -6, + 2, 1, -11, -3, 34, -42, 0, 33, -30, 16, -13, 13, 2, -23, 18, -5, + -26, 43, -24, 15, -26, 4, 35, -15, -62, 64, 19, -75, 50, -8, 8, -14, + -12, 31, -19, -30, 45, -10, -12, -10, 36, 3, -53, 14, 45, -37, -22, 42, + -25, 21, -36, 21, 37, -61, 5, 47, -49, 19, -4, 5, 1, -12, 7, 3, + -11, 2, 18, -28, 13, -4, 18, -13, -20, 33, -22, -8, 21, -12, -10, 24, + -9, 2, -27, 15, 33, -41, -18, 56, -40, 9, -5, 6, 20, -44, 11, 39, + -35, -22, 50, -7, -36, -6, 41, -10, -30, 15, 20, -22, 7, -11, 16, 6, + -51, 59, -21, -26, 24, 12, -24, 8, -7, 12, 3, -36, 27, 18, -42, 22, + 9, -22, 11, -2, 15, -40, 38, -13, -16, 8, 24, -33, 15, -13, 4, 23, + -42, 17, 30, -34, -5, 28, -22, 11, -23, 30, -14, -28, 37, 12, -46, 11, + 31, -23, -12, -7, 36, -17, -6, -4, 25, -18, 4, -29, 53, -48, 4, 24, + -9, -21, 30, -1, -20, 2, -13, 51, -51, -1, 39, -23, -18, 33, -23, 3, + 3, 2, -13, 11, 4, -13, 15, -14, -3, 1, 24, -53, 55, -24, -17, 36, + -1, -49, 45, -7, -12, -2, -4, 24, -23, 1, 6, 23, -51, 30, -8, 14, + -29, 17, 12, -9, -21, 21, 1, 3, -32, 21, 30, -59, 27, 25, -21, -26, + 36, -24, 16, -23, 15, 10, -15, 11, -11, -3, 14, 1, -30, 32, -24, 27, + -25, 10, -12, 29, -33, 7, -5, 25, -29, 14, 15, -42, 20, 18, -27, 1, + 21, -19, 17, -18, 2, 19, -12, -34, 47, -21, -6, 9, -2, 14, -32, 32, + -23, 14, -21, 21, 0, -13, -8, 42, -35, -19, 33, 4, -34, 23, -5, -6, + 22, -31, 21, -8, -5, -3, 15, -22, 10, 2, 7, -17, 11, 3, -10, 2, + -1, -2, -9, 25, -20, 11, -18, 17, -3, -12, 2, 9, -1, -10, 5, 0, + 15, -40, 36, -5, -28, 16, 24, -34, 16, -1, 13, -32, 11, 9, 5, -26, + 5, 32, -32, 4, -1, 29, -38, 8, 7, -6, 5, -2, -5, 18, -26, -2, + 39, -42, 0, 26, 2, -43, 45, -30, 20, -11, -6, -3, 16, -7, -6, 3, + 12, -13, 5, -7, -21, 47, -29, -11, 9, 36, -45, 8, 0, 22, -28, -7, + 32, -22, -9, 20, 12, -40, 24, -8, 14, -28, 10, 9, 12, -29, 15, -7, + 15, -23, 5, 14, -24, 12, 8, 4, -38, 36, -4, -7, -30, 47, -13, -24, + 16, 23, -46, 29, -3, -10, 20, -43, 35, 0, -4, -30, 47, -18, -21, 16, + 19, -35, 11, 19, -21, -11, 27, -12, -9, 16, -21, 23, -32, 30, 3, -22, + -15, 51, -38, -1, -2, 11, 15, -28, -1, 16, 13, -42, 23, 4, -6, -32, + 61, -24, -35, 34, 29, -55, 4, 13, 9, -6, -26, 35, -6, -11, -11, 19, + -6, -3, -15, 43, -41, 4, 22, -1, -34, 18, 15, -35, 18, -1, 23, -35, + 18, -2, -9, 1, 10, -18, 17, -18, 21, -8, -17, 24, -1, -20, -7, 26, + -11, 6, -33, 42, 0, -40, 9, 46, -48, -6, 24, 13, -39, 8, 41, -43, + 3, 6, 6, -7, -6, -8, 42, -37, -11, 39, -16, -26, 25, 3, -24, 9, + 11, 6, -34, 17, 14, -12, -22, 20, 0, 14, -38, 27, 10, -37, 22, -1, + -5, -7, 11, 4, -3, -29, 38, -5, -26, 4, 20, -17, 6, 2, 11, -17, + -10, 40, -49, 10, 26, -8, -24, 11, 12, 5, -36, 21, 20, -22, -29, 28, + 30, -30, -24, 31, 25, -70, 39, 4, -16, 3, 9, -13, 16, -26, 23, 19, + -46, 1, 29, 6, -37, 8, 27, -8, -33, 36, -24, 5, 14, -8, -8, 1, + 4, 15, -27, -11, 44, -38, 6, 12, -3, -12, 20, -17, 16, -35, 28, -4, + 0, -13, 8, 23, -24, -16, 28, 11, -58, 48, 6, -39, 11, 24, -9, -8, + -25, 42, -16, -14, 12, 2, 13, -31, 6, 26, -10, -48, 64, -22, -21, 6, + 28, -15, -11, -2, 22, -30, 11, 15, -25, 13, 2, -1, -7, -4, 6, 17, + -37, 17, 0, 1, 14, -23, 4, 16, -23, 6, 12, -31, 30, 6, -18, -25, + 45, -7, -20, -15, 44, -38, 9, 22, -37, 24, 6, -20, 14, -17, -8, 44, + -27, -22, 16, 30, -33, -18, 20, 31, -50, 11, 27, -21, -4, -3, 26, -15, + -24, 15, 20, -27, 16, -12, 9, 5, -24, 3, 26, -27, 5, 15, -19, 9, + -9, 26, -25, -5, 10, -4, -6, 31, -45, 18, 24, -23, -23, 27, -3, 2, + -18, 9, 13, -18, 19, -17, 7, -1, -24, 31, 5, -49, 31, 32, -40, -7, + 10, 14, -12, -12, 5, 21, -30, 25, -12, 4, -18, 9, 11, -13, -20, 37, + -8, -3, -13, -3, 33, -21, -32, 44, -7, -22, 28, -24, 5, 12, -19, 2, + 6, 2, -16, 11, 10, -6, -23, 31, -25, 7, 6, -16, 18, 1, -35, 40, + -9, -18, 12, 4, -2, -25, 20, 19, -16, -35, 46, -14, -8, -3, -1, 24, + -12, -25, 26, -4, -6, 3, -12, 20, -24, 18, 9, -20, -2, 18, -13, -1, + -16, 8, 26, -35, 12, 10, -11, 6, 2, -30, 46, -43, 16, 6, 1, -20, + 26, -18, 8, -13, 9, -3, 3, 1, -25, 29, 13, -50, 12, 41, -47, 15, + 14, -12, 2, -3, -1, 14, -25, -3, 26, -23, 19, -35, 41, -5, -23, -1, + 31, -30, 8, -15, 32, -29, -7, 22, 10, -35, 12, 6, -2, 20, -50, 36, + 7, -17, -4, -1, 7, 2, -21, 19, -12, 1, 28, -25, -5, 9, -3, -12, + 32, -45, 16, 21, 0, -43, 21, 28, -19, -38, 45, -15, -8, 28, -43, 39, + -12, -23, 13, 19, -39, 23, -3, 17, -32, 6, 20, -5, -32, 23, 8, -15, + -1, 11, 9, -28, 5, 20, -18, -6, 9, -18, 50, -50, -8, 49, -30, -5, + -4, 14, -19, 28, -21, 2, 4, 11, -20, 6, 3, -5, -24, 54, -34, -14, + 26, -4, -2, -16, 5, 20, -23, 1, 6, -9, 32, -37, 1, 25, -22, -8, + 31, -6, -37, 31, 0, 3, -37, 24, 25, -27, -20, 27, 1, 4, -26, 13, + 3, -14, 12, -6, 6, -3, -6, 18, -14, -27, 38, 5, -36, 14, 13, -22, + 26, -13, -22, 36, -23, -5, 3, 18, -12, -23, 31, -5, -24, 23, -15, 17, + -7, -23, 20, 6, -4, -19, 20, -8, 15, -32, 13, 17, -30, 17, 13, -19, + -8, 4, 24, -18, -29, 36, 7, -21, -20, 28, 13, -17, -31, 36, -9, -7, + 7, 6, -9, -4, 7, -6, 10, -32, 41, -26, 12, -10, -12, 35, -10, -39, + 36, -9, -7, 7, 6, -9, -4, 11, -14, 5, -7, 9, -13, 24, -27, 4, + 14, 7, -31, 19, -14, 17, -5, -34, 57, -31, -7, -6, 28, -15, -11, 2, + 25, -21, -14, 15, 18, -35, 12, 1, 9, -20, -2, 32, -37, 26, -17, 7, + 1, -10, -18, 54, -37, -16, 23, 11, -13, -23, 34, -5, -16, -10, 25, -28, + 30, -10, -7, -5, 18, -24, 25, -24, 18, -11, 0, 3, -19, 34, -12, -12, + 2, 3, -13, 32, -37, 20, 4, -6, -25, 29, -3, -2, -11, -2, 28, -38, + 18, 7, -5, -7, 0, -4, 21, -36, 30, -19, 25, -29, -15, 48, -11, -43, + 33, 33, -64, 17, 26, -12, -18, 9, -1, 18, -33, 23, -13, 21, -18, -13, + 18, -2, -20, 20, 6, -15, 4, -12, 28, -27, 1, 10, -5, 3, 0, -17, + 15, 17, -30, 2, 5, -8, 17, -11, -2, 9, -20, 23, -27, 23, -10, -3, + 7, -3, -25, 31, 9, -28, -9, 30, -5, -28, 15, 29, -36, -9, 29, -11, + -20, 33, -27, 21, -14, -12, 21, -3, -9, -2, 12, -5, -27, 27, 7, -20, + -11, 32, -9, -15, -1, 9, 20, -42, 12, 9, -4, 3, -6, -3, 6, 0, + -12, 15, -25, 27, -6, -6, -6, 6, -2, -4, 5, 9, -20, 12, 8, -17, + -10, 30, -12, -24, 25, -15, 18, -21, 21, -8, -6, -9, 12, -6, 15, -33, + 26, 8, -32, 13, 21, -12, -28, 20, 11, -6, -28, 27, 11, -21, -10, 22, + -1, -11, -7, 24, -12, -27, 35, -8, 0, -20, 23, -10, 9, -30, 32, -15, + 3, -7, 6, -2, 10, -17, 1, 8, -4, -5, -3, 14, -9, 1, -11, 18, + -13, 15, -33, 22, 14, -32, 11, 9, -1, -17, 14, 0, -3, -16, 29, -21, + -4, -1, 28, -24, -2, -11, 41, -25, -23, 24, 6, -18, -13, 37, -21, -2, + -4, 29, -40, 11, 12, 4, -25, 12, -9, 23, -17, -14, 27, -2, -26, 9, + 18, -14, -1, -15, 29, -18, -4, 5, 12, -26, 18, -3, -7, 3, 13, -10, + -25, 44, -38, 11, 8, -2, -25, 28, -9, 12, -13, -13, 10, 27, -53, 19, + 16, -4, -20, 12, 12, -21, 5, 12, 3, -35, 22, 8, 0, -28, 18, 16, + -25, -3, 9, 8, -3, -19, 8, 24, -34, -4, 38, -16, -30, 29, -1, -2, + -25, 28, -1, -21, 11, 10, -18, -1, 10, 1, -7, 0, 1, -7, 15, -15, + -5, 16, 2, -22, 8, 0, -1, 26, -34, -22, 56, -26, -11, 12, 9, -9, + -9, 4, 7, -8, -1, 8, 0, -21, 10, 19, -8, -25, 17, 10, -18, 3, + -4, 26, -15, -29, 30, 9, -46, 36, 12, -33, 1, 18, -2, -16, 4, 16, + -10, -16, 11, 2, 8, -19, 5, 1, 10, -21, 20, -8, -1, -3, 1, 7, + -19, 7, 11, -12, 5, 5, -26, 29, -11, -5, -2, 12, -13, 9, -22, 23, + 3, -20, 4, 17, -16, -13, 17, 15, -16, -34, 37, -5, 8, -32, 23, 17, + -36, -2, 36, -25, -4, 28, -18, -20, 15, 4, 7, -12, -24, 43, -19, 0, + -11, 25, -9, -12, -7, 10, -1, 11, -2, -12, 13, -27, 30, -9, -15, 8, + 17, -28, 18, -9, 3, 7, -8, -10, 16, -26, 35, -22, -10, 37, -35, 1, + 11, 11, -19, -2, 9, 17, -37, 11, 10, 9, -16, -12, 27, -11, -22, 16, + 24, -48, 25, -1, -3, 4, -20, 13, 39, -72, 34, 1, 2, -6, 4, -1, + -8, 2, -8, 18, -10, -1, -5, 19, -30, 5, 30, -16, -26, 36, -26, 3, + 21, -27, 10, 4, -10, 0, -4, 15, 9, -41, 32, -11, 2, -11, 15, -3, + -7, -8, 16, -3, -21, 23, -2, -9, -4, -2, 20, -5, -37, 49, -20, -6, + -9, 17, 17, -36, -8, 40, -24, -5, 3, 8, 5, -12, -6, 15, 2, -27, + 28, -4, -23, 16, 5, -1, -26, 29, 11, -38, 22, -12, -8, 38, -34, -3, + 10, 4, -2, -5, -8, 24, -16, -20, 21, 1, -7, 11, -7, -4, -15, 15, + 15, -21, -6, 10, -1, 17, -45, 23, 29, -42, 2, 18, -5, -6, -1, 22, + -20, -19, 16, 21, -20, -18, 23, 2, 5, -41, 36, 10, -34, 12, 12, -25, + 11, 1, 6, -6, -11, 20, -11, 10, -11, -12, 13, 8, -21, 5, -1, 14, + 3, -26, 5, 27, -39, 18, 7, -27, 34, -20, 13, -20, 7, -4, 25, -23, + -16, 7, 47, -35, -29, 37, 10, -35, 4, 12, -1, 0, -15, 25, -23, -12, + 35, 7, -51, 28, -1, 16, -33, 5, 27, -21, 2, -5, 13, -3, 0, -20, + 27, -30, 8, 16, -4, -13, 14, -15, 19, -12, -6, 8, -9, 19, -27, 4, + 20, -9, -12, 21, -37, 41, -22, 1, 1, 13, -33, 20, 14, -30, -2, 22, + 21, -51, 3, 38, -7, -35, 17, 6, 11, -43, 33, 9, -36, 10, 31, -24, + -13, 16, -6, 24, -36, -1, 16, 19, -45, 20, 11, 2, -30, 31, -21, -14, + 29, -4, -12, 3, -6, 9, 15, -37, 20, -4, 8, -18, 12, -7, 17, -8, + -12, -9, 23, 8, -28, 1, 29, -19, -18, 27, -2, -8, -28, 44, -4, -36, + 15, 33, -30, -13, 13, 14, -20, -7, 25, -11, -5, -8, 21, -1, -8, -37, + 50, 1, -53, 27, 28, -21, -10, 4, 16, -24, 10, 6, -12, 0, 2, 6, + 1, -13, 2, 21, -26, 3, 13, -19, 10, 9, -18, -3, 22, -18, -1, -2, + 14, -1, -23, 21, -6, -2, -9, 20, 5, -35, 1, 34, -21, -16, 22, 1, + -8, -5, 1, 18, -12, -23, 18, 5, -17, -7, 37, -6, -35, 6, 47, -44, + -7, 20, 5, -10, -23, 35, -6, -12, -12, 39, -27, -10, 9, 21, -21, -6, + 2, 5, 1, 6, -28, 17, 20, -31, -3, 15, 7, -26, 31, -40, 43, -32, + 23, -19, 11, -22, 26, -6, -1, -25, 33, 2, -25, -7, 9, 26, -16, -30, + 29, 20, -47, 13, 16, -9, -19, 18, 23, -32, -17, 32, 21, -38, -13, 14, + 43, -66, 19, 23, 5, -50, 47, -20, 2, -11, 22, -5, -6, -21, 4, 38, + -15, -32, 12, 35, -35, -4, 7, 18, -17, -1, -7, 6, 5, 0, 0, -7, + 0, -8, 21, -10, 5, -28, 30, 3, -17, -29, 57, -16, -17, -10, 28, -9, + -20, 26, -12, 3, -20, 27, -3, -7, -42, 65, -9, -45, -3, 63, -33, -11, + -6, 28, -17, -1, -6, 6, 7, -12, 0, 25, -21, -30, 54, -9, -37, 1, + 28, 7, -42, 18, 11, 17, -46, 24, -9, 27, -38, 22, -20, 23, -21, 11, + -6, 42, -71, 20, 32, -11, -43, 44, -3, -4, -27, 12, 24, -8, -18, -8, + 30, -19, -23, 44, -8, -30, 0, 45, -39, 0, -1, 28, -16, -17, -15, 44, + -13, -11, -13, 36, -24, -11, 12, 17, -30, 8, 17, -10, -18, 9, 22, -18, + -15, 3, 25, -25, 11, -6, 5, 7, -18, -3, 15, -1, -17, 8, 28, -32, + -17, 36, 8, -41, 12, 7, 13, -22, -14, 18, 41, -57, -1, 25, 10, -40, + 18, 11, -8, -23, 25, -16, 37, -45, 17, 10, 2, -60, 64, -15, -3, -16, + 22, -9, 9, -27, 30, -7, -21, 3, 20, -10, 6, -12, 15, -19, 14, -19, + 3, 22, -8, -29, 37, -28, 29, -26, 11, -15, 15, -17, 21, -26, 18, 5, + -5, -11, 2, 16, -10, -10, -5, 29, -30, 4, 3, 18, -21, 4, 1, 8, + -13, -10, 1, 40, -35, -26, 44, 5, -38, 8, 30, -24, 0, -1, 0, 12, + -18, -1, 18, -8, -28, 39, -18, 24, -35, 24, -36, 46, -41, 12, -3, 24, + -37, 31, -28, 32, -16, 2, -27, 39, -34, 7, 24, -19, -6, 14, -10, -1, + 14, -16, -4, 25, -26, -4, 8, 22, -40, 33, -30, 22, -15, 36, -63, 39, + 1, 10, -54, 36, 9, 5, -51, 49, -13, 5, -7, -7, 15, -9, -10, 2, + 12, -18, 6, 3, 18, -29, 9, 10, -10, 1, -20, 20, -3, -1, -13, 21, + -26, 41, -36, 2, 23, -23, -10, 39, -41, 17, -10, 8, 7, -13, 23, -54, + 66, -26, -50, 54, 17, -66, 59, -46, 30, -10, 6, -8, -18, 19, 16, -32, + 12, 6, -2, 3, -36, 33, -6, -7, 12, -16, 6, 14, -21, 14, 16, -58, + 37, 3, 0, -35, 44, -16, 17, -38, 28, -14, 25, -45, 28, -21, 32, -31, + 11, 17, -24, 11, 5, -24, 18, -6, -3, 0, -3, 21, -33, 24, 20, -78, + 66, -8, -24, 3, 17, -14, 24, -41, 34, -25, 27, -32, 17, -5, 13, -26, + 28, -29, 22, -8, -16, 33, -30, 2, 25, -27, 1, 31, -36, -7, 31, -8, + -12, -5, 17, -7, 5, -26, 32, 1, -18, -16, 27, -7, -10, 2, 21, -42, + 30, -3, -19, 33, -40, 19, 6, -13, -5, 17, -10, 28, -63, 40, 6, -10, + -9, 7, -3, 12, -20, -1, 17, -1, -6, -14, 18, 1, -19, 12, 5, -9, + -2, -14, 33, -3, -44, 51, -17, -6, -16, 36, -35, 29, -31, 31, -24, 15, + -23, 33, -35, 20, -4, -1, -19, 27, -1, -29, 25, 1, -20, 25, -23, -13, + 62, -50, -18, 43, -20, 1, -4, 16, -18, 4, -16, 36, -42, 42, -42, 38, + -28, 9, -10, 31, -40, 30, -39, 30, 8, -28, 11, 9, -7, -6, -8, 10, + 22, -36, -5, 26, 4, -41, 30, 12, -11, -10, -14, 37, -29, 3, -6, 9, + -5, 15, -30, 40, -26, 12, -25, 25, -21, -12, 46, -17, -39, 47, 7, -57, + 45, -14, 1, -13, 21, -21, 14, -7, 7, -11, 18, -34, 25, 7, -28, 22, + 1, -12, 11, -24, 4, 38, -44, 17, 2, -12, 19, -17, 0, 9, 17, -55, + 29, 3, 3, -27, 48, -38, 16, -17, 24, -19, 26, -49, 29, 9, -18, -25, + 50, 2, -31, -20, 43, -3, -35, 23, 13, -34, 9, 20, -15, -8, 29, -37, + 29, -21, 4, -8, 36, -52, 29, -8, 6, -18, 35, -34, 22, -21, 10, 5, + -11, -13, 35, -26, -3, 12, -17, 13, 1, -12, -4, 24, -18, -6, 18, -7, + -13, 17, -4, -30, 48, -41, 10, 34, -39, -22, 73, -48, -12, 12, 22, -14, + -31, 18, 29, -17, -21, 22, -3, -8, -12, 25, -11, 13, -41, 36, -3, -2, + -27, 37, -6, -36, 17, 18, -7, -10, 4, -5, 10, -21, 13, 15, -21, 2, + -1, -5, 8, -1, -16, 29, -24, 14, -18, 26, -24, 17, -26, 21, -18, 24, + -49, 82, -52, -11, 36, -22, -17, 30, -21, 1, 1, -1, 8, -2, -7, 2, + 17, -9, -36, 37, -5, -15, -4, 27, -20, 11, -31, 46, -18, -13, -11, 58, + -67, 19, -4, 40, -43, 9, -14, 41, -32, -16, 46, -19, -13, 5, -5, 6, + 2, -16, 10, -9, 18, -13, 3, 24, -37, 11, 1, 0, -8, -9, 28, -1, + -41, 40, -10, 6, -13, 1, -11, 30, -28, -10, 30, 1, -36, 17, 28, -54, + 51, -24, 1, -6, 6, -12, 33, -48, 23, 18, -17, -23, 27, 11, -23, -13, + 27, -7, -1, -24, 35, 3, -48, 35, 8, -20, -3, 3, 16, -11, 8, -35, + 32, 7, -27, -22, 81, -85, 36, -7, 16, -16, 2, 0, 13, -28, 12, -16, + 24, 6, -25, -14, 47, -15, -25, 3, 37, -41, -5, 32, -25, 11, 6, -16, + 25, -34, 14, 8, 13, -52, 30, 6, 13, -56, 56, -27, 13, -11, -6, 16, + -12, -1, 18, -40, 18, 19, -13, -11, 7, -2, 9, 10, -39, 9, 46, -48, + -18, 59, -32, -3, 14, -10, 10, -13, 10, -13, 14, -11, -10, 5, 31, -43, + 10, 23, -16, 3, -29, 50, -23, -19, 16, 15, -19, 3, -20, 39, -19, -14, + -6, 54, -44, -12, 18, 30, -56, 28, -15, 22, -16, -15, 31, -8, -9, -1, + 1, 1, 2, -8, 9, 10, -43, 41, -9, 8, -48, 62, -30, -9, 13, 6, + -24, 32, -31, 8, -4, 16, -27, 27, -19, -1, -6, 37, -40, 14, -3, 0, + 25, -59, 34, 18, -18, -21, 17, 13, -11, -8, -11, 43, -40, 1, 6, 24, + -37, 10, 14, -4, -12, -2, 17, 11, -40, 10, 16, 17, -51, 24, 14, -4, + -31, 22, 18, -32, 15, -24, 46, -38, 9, 2, -2, 14, -15, -12, 15, 3, + -28, 29, -7, -6, 13, -7, -6, 2, 3, -17, 28, -28, -9, 37, -17, 0, + 3, 10, -19, -5, 19, -17, 12, -25, 30, -19, 8, -27, 49, -15, -27, 9, + 10, 7, -31, 6, 30, -12, -45, 41, 24, -42, -1, 28, -2, -38, 29, -18, + 23, -4, -43, 35, 26, -54, 23, 7, 6, -30, 17, -14, 32, -40, 24, -13, + 17, -15, -11, 16, 16, -20, -26, 47, -10, -26, -6, 41, -19, -22, 36, -41, + 33, 5, -32, 12, 28, -51, 19, 27, -40, 7, 35, -34, 9, -22, 42, -20, + -15, -3, 43, -55, 15, 23, -10, -11, 3, 14, -32, 31, -26, 21, 7, -44, + 15, 40, -22, -41, 54, -17, -17, 8, -6, 10, 11, -17, -6, 15, -2, -20, + 31, -19, 4, -17, 22, 0, 2, -36, 39, 0, -31, 23, -38, 59, -15, -29, + -13, 69, -50, -22, 43, -11, -16, 0, 16, -9, -10, 13, 5, -8, -18, 27, + -8, -2, -12, 13, -1, -16, 16, -18, 27, -11, -19, 39, -28, -26, 28, 36, + -85, 72, -40, 24, -10, 0, -9, 30, -29, -11, 22, -13, -7, 23, -10, -14, + 6, 13, -15, 22, -31, 12, 0, 0, -3, -15, 19, 14, -21, -22, 27, 35, + -72, 36, -3, 18, -54, 50, -29, 38, -47, 14, 19, -11, -25, 27, 9, -23, + -2, 2, 16, -6, -24, 22, 10, -27, 7, 16, -30, 11, 24, -40, 31, -28, + 29, 1, -28, 7, 17, 3, -45, 40, -11, -7, 4, 19, -45, 24, 24, -50, + 48, -35, 11, 9, -12, -14, 30, -23, 8, 7, -15, -7, 53, -59, 13, 5, + 15, -46, 49, -48, 57, -36, -20, 34, 1, -10, -15, 15, 20, -36, -9, 35, + 6, -39, 7, 14, 27, -81, 70, -21, 5, -22, 21, -6, 1, -13, 19, -19, + 4, -10, 35, -43, 31, -3, -7, -15, 40, -56, 33, -1, -33, 51, -35, -2, + 24, -18, 5, 0, 4, -16, 10, -6, 9, -28, 37, -38, 45, -35, 0, 37, + -38, 7, 19, -32, 3, 17, -2, -23, 19, 15, -23, 5, -2, 13, 1, -37, + 8, 59, -80, 26, 13, 15, -31, -8, 30, -7, -7, -19, 22, -2, -9, -2, + 12, -7, 3, 1, -25, 47, -53, 35, -5, -27, 21, 15, -25, 13, -24, 42, + -41, 19, 2, -13, 1, 23, -40, 37, -45, 46, -8, -41, 44, -11, -17, 23, + -9, -20, 22, -3, -15, 22, -23, 19, -7, 2, -34, 65, -56, 7, 28, -8, + -37, 37, 3, -8, -34, 39, -11, 9, -29, 6, 35, -14, -49, 48, 5, -25, + 5, -25, 66, -47, -9, 28, -7, -12, 0, 17, -20, -2, 21, -12, -23, 54, + -50, 20, 7, -20, 7, -2, 3, 4, -26, 26, -6, -14, 15, -3, -10, 12, + -10, -4, 23, -33, 14, -12, 38, -55, 36, 0, -6, -5, 0, -4, 7, 0, + -14, 2, 8, -11, 13, 5, -33, 41, 4, -62, 40, 8, -6, -8, -31, 52, + -4, -44, 25, 20, -18, -24, 32, -11, -9, -4, 30, -37, 34, -31, 7, 30, + -29, -14, 28, -10, -9, 6, 0, -5, 14, -9, -3, -2, 10, -22, 29, -22, + -2, 6, -5, 16, -25, 6, 27, -19, -9, -11, 29, -13, -5, -6, 16, 5, + -20, -1, 30, -20, -8, 7, -8, -2, 3, 14, -9, -24, 35, -7, -14, -12, + 32, -5, -18, -15, 35, -7, -13, -1, -4, 27, -20, -30, 58, -15, -29, 9, + 15, -16, -3, 1, 4, 5, -4, -11, 17, 3, -29, 28, -10, -18, 20, -7, + -2, 4, 2, -17, 22, -3, -31, 23, 23, -32, -14, 34, -3, -14, -13, 11, + 21, -26, -16, 36, -7, -13, 15, -8, -3, -1, -11, 15, -8, -4, -4, 24, + -21, 1, 11, 3, -22, 5, 15, -24, 0, 37, -31, 7, -18, 15, 16, -15, + -19, 26, 0, -10, -26, 31, 6, -19, -6, 21, -19, 20, -13, -3, 13, -2, + -32, 24, 2, -8, -10, 36, -29, -10, 19, 10, -25, 5, -9, 31, -23, -21, + 21, 26, -25, -9, -5, 35, -17, -34, 17, 42, -44, -11, 30, 11, -40, 18, + 8, -6, -11, 11, -26, 39, -18, -23, 37, -12, -32, 45, -8, -22, 5, 16, + -15, -10, 6, 17, -15, -3, 9, -22, 41, -22, -25, 29, 5, -30, 6, 12, + 17, -32, 7, 20, -26, 9, 9, -10, 7, -17, 10, 11, -16, -7, 12, 5, + -4, -26, 25, 24, -46, -4, 50, -39, -11, 8, 35, -36, 2, -9, 33, -7, + -22, -26, 76, -37, -41, 33, 28, -43, 14, 6, 2, -8, 2, -20, 34, -19, + -2, -4, 15, -6, -23, 28, -3, -32, 33, -16, 7, -11, 14, 9, -10, -30, + 35, -25, 17, -14, 1, 14, 12, -38, 16, 15, -7, -30, 15, 18, -24, -6, + 47, -38, 6, 7, -9, -2, -3, 1, 12, -8, -23, 20, 35, -47, -14, 51, + -9, -48, 19, 20, 0, -25, -2, 20, 16, -29, -25, 60, -17, -23, -8, 31, + -4, -30, 12, 20, -14, -4, -1, 17, -11, -9, 7, 7, -17, 1, -12, 25, + -5, -20, 15, 19, -29, 2, 5, 11, -19, -18, 31, 1, -27, 18, -17, 51, + -53, -2, 29, 4, -37, 17, 11, -11, -23, 41, -17, -10, 13, -4, -8, 18, + -27, 17, 1, -19, -7, 51, -37, -28, 53, 4, -47, 5, 18, 17, -32, -8, + 14, 36, -46, 3, 11, 11, -24, 4, 0, 16, -7, -26, 25, 20, -44, 7, + 20, -12, 2, -14, 4, 33, -38, 1, 8, 20, -34, -12, 61, -46, -19, 44, + -10, -4, -18, 12, 12, -8, -26, 16, 22, 2, -51, 18, 53, -56, -5, 30, + -9, -22, 32, -11, -18, 18, 13, -25, -7, 8, 9, 3, -20, 1, 32, -27, + -9, 5, 19, -20, -13, 18, 8, 3, -35, 22, 31, -47, -2, 16, -8, 15, + -10, -22, 54, -20, -23, -6, 51, -52, -13, 48, -23, -11, 28, -30, 38, -6, + -50, 28, 33, -58, 2, 34, 16, -53, -1, 55, -13, -42, 15, 23, -7, -33, + 13, 21, -14, -6, 2, -2, 27, -43, 27, 11, -19, -16, 26, -16, -4, 16, + -17, 1, 20, -17, 8, -17, 6, 26, -25, -24, 40, -13, 6, -14, -14, 29, + 3, -32, -5, 46, -21, -28, 38, -30, 6, 28, -47, 3, 65, -67, -5, 61, + -34, -27, 31, 12, -30, -7, 11, 19, 0, -43, 18, 47, -52, -20, 52, -14, + -9, -10, -5, 55, -45, -29, 55, 16, -83, 28, 36, -23, 6, -8, -13, 37, + -17, -30, 32, -9, -6, 10, -19, 16, 4, 9, -35, 22, -1, -17, 3, 8, + 10, -10, -21, 40, -27, -5, 16, -6, -27, 47, -23, -26, 48, -18, -19, 14, + -1, -9, 5, 1, -20, 58, -57, -14, 55, -16, -40, 37, -6, 11, -19, -22, + 43, 2, -55, 27, 37, -38, -29, 58, -6, -11, -22, 4, 26, -7, -67, 67, + 21, -56, 19, 15, -5, 0, 2, -41, 37, 10, -65, 49, 8, 1, -19, 1, + 9, 8, -20, -9, 22, -14, -3, 4, -1, 13, -6, -11, 15, -8, -15, 13, + 16, -38, 14, 24, -39, 20, 9, -17, 14, -15, 7, 3, -12, -3, 30, -25, + -24, 43, -1, -40, 18, 17, 0, -22, -14, 31, 20, -68, 35, 32, -43, -9, + 35, -16, 4, 2, -35, 35, 27, -81, 40, 31, -21, -30, 29, -12, 13, 10, + -42, 26, 17, -33, -1, 16, 12, -29, 6, 4, 21, -27, -9, 39, -6, -54, + 40, -14, 15, -4, -17, 20, 4, -18, -4, 23, -24, -3, 30, -41, 15, 17, + -4, -29, 19, 4, -9, -10, 12, 17, -21, -7, 26, -19, -17, 17, 3, 1, + -3, -30, 47, 16, -62, -4, 68, -29, -54, 43, -1, -4, 20, -42, 22, 34, + -32, -43, 63, -12, -26, 8, -6, 10, 22, -66, 55, 25, -65, 15, 9, 21, + -22, -28, 36, 5, -16, -51, 102, -49, -12, 6, 21, -12, -23, 24, -15, 11, + -14, -8, 31, 4, -53, 64, -35, 13, -28, 23, -23, 22, -16, 13, -22, 23, + 27, -51, -8, 41, 6, -66, 36, 13, 4, -26, 7, 11, 9, -34, 0, 35, + -21, -15, 10, 34, -57, 60, -69, 60, -22, 1, -27, 27, 14, -27, 1, -13, + 35, -2, -51, 36, 35, -49, 5, -1, 31, -42, 25, -26, 34, -7, -60, 98, + -46, -22, -1, 49, -45, -2, 10, 26, -33, 25, -36, 37, -19, 4, -3, -7, + 9, 7, -8, -29, 48, -23, 0, -33, 45, 0, -23, -16, 47, -7, -31, -9, + 38, -2, -36, 18, -8, 43, -55, 16, -1, 41, -72, 54, -35, 24, 4, -46, + 47, -11, 6, -40, 24, 10, 8, -38, 16, 16, 24, -98, 80, 2, -28, -28, + 44, 11, -47, 31, -7, 35, -42, -25, 41, 12, -64, 34, 14, -2, -21, 24, + -14, 11, -3, -24, 22, -28, 46, -51, 38, -22, 35, -40, 2, 11, 22, -48, + 23, -9, 34, -35, -24, 52, -7, -37, 9, 36, -21, 0, -32, 61, -44, 6, + -1, -16, 41, -28, 19, -37, 49, -11, -38, -8, 65, -53, 9, -21, 59, -37, + 8, -33, 59, -13, -80, 67, 19, -39, -28, 70, -21, -25, -3, 23, 17, -29, + -44, 83, -41, 0, -23, 53, -27, -12, 21, -19, 21, -21, 13, -4, -12, -5, + 38, -58, 34, 10, -22, -16, 47, -8, -39, 19, 12, 4, -46, 39, -24, 48, + -69, 45, -18, 10, -5, -2, -4, 10, -5, 7, -17, -3, 20, 0, -40, 26, + 40, -64, 11, 34, 1, -49, 11, 35, -22, -14, -32, 98, -47, -37, 9, 76, + -70, -8, 7, 63, -92, 56, -49, 77, -64, 2, 41, -28, -25, 37, 0, -26, + 35, -40, 16, 3, 14, -46, 22, 18, -6, -9, -11, 22, 26, -44, -46, 94, + -60, 18, -37, 69, -33, 5, -20, 42, -32, -20, 24, -1, -10, -12, 39, -31, + 13, 1, 9, -47, 42, -26, 39, -73, 48, 48, -73, -13, 56, 14, -78, 38, + 11, 12, -50, 8, 39, 3, -79, 73, 2, -25, -17, 23, 27, -58, 26, -37, + 67, -49, 11, -12, 62, -82, 64, -41, 3, 26, -17, -45, 55, -4, -22, 10, + -2, 38, -54, 8, 5, 47, -79, 7, 54, -7, -64, 41, 49, -73, 29, -24, + 54, -51, -4, 14, 33, -84, 82, -46, 17, -25, 57, -44, -2, 11, 8, 15, + -66, 46, 19, -25, -44, 58, 10, -38, -23, 77, -48, -3, -12, 24, 24, -70, + 37, 21, -15, -48, 81, -66, 44, -29, 6, 4, 9, -30, 31, -24, 5, 19, + -51, 34, 21, 11, -92, 78, 19, -44, -54, 104, -47, -8, -19, 29, 45, -78, + 6, 55, -11, -75, 66, -10, 8, -38, 24, 10, 4, -57, 66, -20, -25, 20, + 6, 9, -71, 100, -60, -6, 8, 28, -37, 29, -42, 78, -58, -22, 42, 10, + -69, 34, 33, -36, 29, -54, 81, -54, 0, 7, 1, -19, 22, -14, 4, -3, + 32, -13, -59, 86, -54, 4, 0, 21, -35, 43, -68, 91, -31, -53, 38, 48, + -72, -15, 50, 3, -11, -72, 96, -1, -49, -23, 81, -21, -57, 15, 63, -67, + 5, 25, -27, 34, -48, 49, -26, 12, -33, 66, -73, 14, 35, -20, -27, 45, + -24, 12, -12, 0, 24, -50, 33, -26, 45, -65, 47, -7, -4, -9, 19, -19, + -2, 15, -17, 30, -39, 25, 2, -3, -57, 109, -86, 10, 14, 31, -53, 7, + 32, 5, -44, -20, 84, -35, -34, -6, 99, -97, 1, 23, 40, -65, 15, 9, + 36, -45, -22, 55, 4, -55, -3, 73, -80, 63, -49, 28, 2, -10, -19, 24, + -13, 8, 1, -15, 5, 22, -4, -57, 72, -41, 16, -45, 76, -57, 30, -26, + 38, -16, -34, 32, 12, -53, 22, 47, -46, -4, 6, 45, -65, 32, -21, 45, + -44, -22, 69, -44, -16, 29, 19, -59, 40, -7, 42, -77, 39, -4, 29, -74, + 27, 38, -12, -60, 69, 7, -32, 1, -9, 50, -56, -15, 19, 47, -75, 44, + 5, -22, 27, -7, -22, 0, 23, -30, 1, 4, 33, -44, 29, -24, 57, -67, + 17, 18, 4, -59, 32, 48, -72, 28, -2, 13, -10, -21, 16, 58, -117, 85, + -14, -5, -34, 21, 29, -27, -20, 31, 23, -49, 16, -14, 51, -74, 24, 38, + -38, -16, 56, -33, -7, 3, 0, 36, -80, 49, 23, -19, -48, 76, -61, 43, + -41, 27, -11, 23, -30, 8, 3, 15, -14, -22, 16, 3, 15, -39, 11, 38, + -13, -70, 88, -41, 2, 4, -30, 80, -84, 15, 37, -6, -61, 58, -19, 27, + -72, 64, -6, -16, -30, 59, -21, -21, -12, 44, 22, -101, 78, -10, -16, -11, + 20, -21, 31, -36, 37, -18, -20, 46, -24, -23, 10, 21, -36, 32, -38, 68, + -50, 12, -6, 19, -33, 14, -16, 20, -11, -14, 47, -59, 56, -14, -27, 5, + 29, -43, 49, -96, 106, -35, -41, 28, 35, -30, -29, 37, 12, -11, -58, 79, + -31, -16, -11, 43, -13, -25, 3, 71, -76, -13, 64, -39, 3, -45, 66, -13, + -1, -45, 80, -40, 6, -29, 26, -12, 6, -19, 21, -4, 9, 0, -37, 44, + -28, 11, -22, 19, 7, 1, -45, 60, -13, -42, 32, -16, 31, -50, 35, 10, + -22, -23, 60, -62, 21, -2, 39, -49, -4, 24, 30, -53, -23, 66, -33, 2, + -34, 69, -33, -10, 7, 24, -51, 28, 0, 9, -24, -3, 38, -24, -16, -9, + 68, -81, 38, -16, 35, -34, -4, 16, 20, -43, 10, 7, -3, 14, -30, 38, + -39, 38, -20, -12, -20, 78, -79, 22, -4, 44, -48, -6, 37, -2, -25, -24, + 60, -41, 15, -30, 50, -43, 7, 9, 27, -64, 45, 5, -15, -17, 1, 49, + -56, 3, -11, 69, -78, 37, -5, 38, -60, 26, -2, 9, -51, 53, -20, -3, + 9, -1, 38, -74, 40, 6, -13, -54, 69, -24, 6, -22, 31, 0, -17, 12, + -13, 8, -9, 20, -53, 56, -27, 29, -63, 41, 8, 11, -73, 59, 15, -25, + -21, -1, 61, -69, 10, 17, 28, -59, 34, -14, 32, -54, 17, 22, -11, -47, + 63, 7, -56, 46, -28, 50, -96, 60, 2, 0, -37, 36, -11, 15, -38, 41, + -19, -31, 46, -12, -25, 9, 49, -67, 47, -48, 51, -30, -15, 23, 19, -43, + 8, 17, 4, -11, -29, 54, -48, 38, -28, 10, -9, 38, -48, 27, -47, 55, + 3, -59, 22, 41, -5, -59, 38, 5, 31, -101, 72, 11, -36, -18, 54, -25, + -1, -30, 54, -28, -34, 61, -27, 13, -46, 55, -21, -10, -21, 52, -34, -8, + 30, -21, 20, -11, -21, 22, -2, -46, 79, -84, 60, -9, 13, -57, 51, 2, + -16, -38, 34, 15, -23, -7, -6, 53, -38, -22, 29, 23, -63, 65, -34, -21, + 34, -7, -19, -8, 24, 13, -8, -63, 110, -56, -8, -37, 79, -56, -3, -3, + 62, -57, 19, 9, 8, -20, -29, 27, 13, -28, -19, 79, -80, 58, -31, 24, + -16, -35, 46, 0, -52, 36, 21, -29, 16, -23, 26, -29, 38, -42, 26, -41, + 60, -29, -16, -4, 42, 7, -85, 53, 47, -54, -29, 67, -53, 39, -58, 45, + -5, 5, -37, 61, -56, 27, 17, -40, 1, 15, 17, -43, 19, 4, 30, -49, + 12, -1, 49, -64, -27, 96, -41, -47, 45, 8, -38, 35, -50, 74, -81, 54, + -14, 24, -64, 57, -5, -25, -19, 27, 16, -27, 4, 16, 2, -25, 26, -31, + 22, -35, 56, -54, 0, 55, -23, -29, 9, 38, -38, 12, -41, 74, -28, -29, + -3, 61, -71, 36, -32, 43, -19, -14, 21, 0, -10, -19, 32, -42, 20, 11, + 23, -94, 107, -13, -53, 5, 35, -17, -11, -25, 32, 40, -76, 29, 32, -9, + -65, 80, -42, 6, -22, 42, -27, -2, 10, -2, 13, -41, 32, 10, -17, -26, + 53, -50, 40, -42, 30, -19, 41, -50, 33, -20, -1, 40, -67, 8, 29, 15, + -58, 25, 32, 15, -81, 46, 14, -8, -51, 24, 40, -44, 17, 10, 2, -26, + 47, -68, 49, -49, 50, -27, -3, -20, 84, -62, -32, 52, 12, -52, 0, 42, + -30, 24, -47, 45, -16, 11, -51, 74, -47, -9, 45, -19, -18, -5, 41, -39, + 11, -33, 56, -20, -14, -8, 64, -85, 60, -23, -13, -3, 33, -20, -25, 57, + -34, 2, -23, 42, -21, 3, -49, 85, -35, -27, 1, 54, -34, -31, 24, 15, + 6, -45, 54, -30, 12, -27, 40, -61, 39, 1, -5, -18, 17, 14, 7, -33, + -27, 83, -44, -40, 21, 66, -82, 32, -7, 33, -54, 27, 3, 2, -13, -15, + 52, -57, 14, 14, -6, -27, 54, -45, 23, -11, 16, -27, 27, -33, -3, 36, + -46, 47, -15, -8, -7, 67, -93, 12, 34, 17, -73, 32, 15, 29, -44, -17, + 47, 2, -40, -31, 81, -43, 3, -24, 52, -32, 4, 1, 20, -48, 20, 40, + -68, 23, 14, 19, -64, 46, -8, 17, -48, 55, -29, 23, -59, 48, -2, -27, + 11, 1, 21, -30, 25, -24, 29, -41, 21, 0, -15, -17, 64, -47, 1, 31, + -22, 2, -11, 22, -56, 69, -53, 32, -30, 31, -16, 32, -68, 29, 42, -39, + -49, 80, 17, -74, 17, 0, 55, -88, 25, 29, 14, -72, 56, 0, 0, -33, + 20, 5, -34, 35, -33, 45, -37, 23, -9, 10, -54, 67, -22, -13, -15, 41, + -14, -16, 8, 0, 19, -51, 56, -51, 39, -20, 19, -34, 26, -18, 19, -31, + 23, 0, 12, -31, 7, 45, -65, 22, 4, 24, -73, 74, -13, -34, 18, 23, + -16, -25, -2, 40, 5, -84, 76, -4, 6, -74, 75, -7, -10, -51, 60, -13, + 0, -45, 50, 18, -57, 20, 21, -7, -26, 47, -51, 28, -19, 12, -13, 3, + -1, 20, -23, 1, 28, -18, 3, -41, 67, -72, 34, -11, 33, -47, 47, -9, + -20, -2, 28, -21, -27, 11, 26, -15, -25, 57, -44, 46, -67, 49, -5, -30, + 1, 42, -36, -9, 22, 7, -13, -34, 67, -29, -16, -26, 84, -49, -21, -11, + 77, -53, -43, 62, 0, -3, -32, 23, 13, -5, -69, 88, -42, 7, -17, 37, + -35, 27, -6, -13, -11, 31, -17, -28, 45, -17, 8, -32, 41, -48, 39, -35, + 41, -16, -28, 41, -3, -13, -26, 23, 12, -22, -50, 104, -57, 9, -28, 67, + -53, -7, 0, 45, -41, -22, 50, -8, -21, -9, 38, -19, -18, -2, 55, -76, + 38, -12, 39, -49, -14, 64, -24, -45, 25, 50, -66, 23, -15, 32, -36, 32, + -46, 44, -14, 2, -16, 22, -7, -11, 14, -28, 21, 4, -10, -18, 63, -66, + 30, -20, 36, -35, -16, 26, 12, -37, 6, 50, -35, -15, 6, 48, -64, 4, + 12, 46, -85, 33, 12, 25, -49, -11, 77, -53, -18, 19, 29, -41, -1, 3, + 39, -70, 55, -6, -1, -23, 38, -22, -12, 1, -11, 36, -39, 5, 15, 33, + -55, 32, -8, 6, -37, 39, -32, 4, 27, -23, 11, -1, 10, -28, 19, -24, + 52, -69, 27, 21, 11, -72, 52, 17, -35, -13, 16, 33, -44, 4, 19, 18, + -60, 13, 35, 12, -93, 82, 9, -35, -20, 26, 40, -74, 14, 18, 28, -66, + 37, 4, 9, -43, 34, -15, 17, -35, 38, -11, -14, 14, -5, 2, -36, 54, + -35, 2, 1, 29, -35, 9, -4, 24, -32, -5, 31, -19, -17, 28, 34, -86, + 49, 13, -16, -52, 71, -29, 3, -30, 51, -1, -36, 6, 25, 4, -75, 56, + 10, -21, -18, 37, -16, 17, -53, 60, -7, -38, -9, 63, -18, -70, 67, 1, + -19, -32, 50, -20, 11, -23, 24, -10, -3, -21, 32, -26, 7, 12, -19, 35, + -29, 26, -41, 32, -22, 14, -43, 41, 7, -16, -24, 57, -20, -35, 25, 7, + -11, -20, 31, -18, 10, -34, 44, -7, -22, -9, 49, -33, -18, 26, -4, 12, + -63, 51, 11, -16, -40, 80, -28, -37, 5, 61, -78, 22, 16, -3, -10, -5, + 26, -8, -2, -43, 68, -42, -24, 39, 11, -31, 15, -9, 18, -20, -1, 7, + -17, 26, -30, 31, -31, 42, -28, -1, -15, 49, -51, -2, 26, 3, -12, -11, + 7, 22, -9, -51, 70, -27, -14, -13, 53, -37, -12, 9, 44, -57, -14, 51, + -6, -27, -10, 60, -55, 2, 14, 18, -45, 32, -19, 29, -27, -12, 31, 14, + -54, 17, 41, -62, 51, -40, 40, -40, 12, -8, 28, -39, 16, 10, 10, -46, + 37, 12, -42, 17, -4, 2, -17, 35, -34, 38, -30, 21, -6, -36, 36, 13, + -56, 14, 53, -36, -13, -1, 61, -64, 7, -3, 54, -63, 5, 14, 34, -67, + 10, 46, -27, -18, 26, 20, -41, 14, -13, 40, -66, 20, 38, -34, -11, 39, + -16, 11, -26, 7, 28, -58, 26, 0, 30, -61, 44, 11, -30, -17, 66, -40, + -33, 35, 6, -21, -2, 9, 16, -13, -39, 79, -71, 27, 9, -9, -29, 28, + 4, -17, 1, 14, 2, -20, -2, 16, 24, -67, 20, 37, -4, -80, 75, 18, + -46, 2, 10, 25, -31, -28, 43, 19, -75, 59, -13, 14, -40, 29, 7, -22, + -20, 44, -20, -16, 10, 32, -21, -42, 61, -19, -29, 12, 39, -55, 32, -4, + 0, -2, -24, 40, -19, -38, 34, 22, -33, 11, -3, 31, -49, 21, -16, 40, + -54, 12, 29, -19, -8, 17, 17, -52, 28, 22, -39, -2, 45, -42, 23, -46, + 51, 11, -68, 26, 55, -34, -44, 45, 9, -19, -43, 57, -16, -5, -9, 40, + -24, -12, 8, 29, -54, -4, 50, -37, 0, 11, 7, -4, 0, -25, 57, -62, + 19, 18, -7, -22, 12, 19, -27, 9, -5, 15, -19, 2, 15, 4, -45, 36, + -5, 8, -48, 60, -13, -35, 36, -19, 21, -24, -7, 23, -24, -22, 73, -58, + -5, 34, 25, -71, 19, 30, 0, -43, -4, 50, -9, -21, -21, 69, -28, -46, + 24, 29, -45, 12, 3, 21, -13, -28, 47, -9, -37, 21, 22, -46, 21, 8, + -1, -32, 42, -22, 14, -27, 19, 16, -29, 3, 17, -1, -39, 28, 21, -42, + 8, 47, -45, 2, -16, 50, -20, -54, 50, 9, -25, -12, 41, -29, 8, -3, + -5, -13, 25, -16, 19, -30, 15, 15, -2, -52, 38, 38, -69, 12, 37, 9, + -54, 10, 36, 5, -79, 27, 57, -35, -40, 48, 21, -41, 13, -3, 10, -29, + 4, 18, 4, -50, 52, 1, -28, -6, 41, -25, -22, 34, -22, 10, -5, 3, + -6, -1, 2, 26, -48, 24, 12, 5, -54, 36, 18, -32, -6, -3, 48, -28, + -21, 22, 35, -63, 6, 43, -28, -27, 42, -7, -22, 6, 21, 8, -56, 31, + 23, -10, -73, 76, 18, -49, -26, 70, -21, -23, -8, 35, 0, -42, 7, 42, + -26, -28, 47, -31, 0, 13, 11, -25, 14, -6, 10, -13, -26, 40, -14, -5, + -8, 42, -36, 1, 15, -10, -34, 47, -24, 5, -22, 38, 14, -39, -10, 53, + -26, -67, 72, 0, -15, -25, 29, 19, -29, -25, 50, -14, -31, 10, 42, -44, + -24, 81, -40, -32, 12, 45, -41, -5, -1, 47, -27, -54, 54, 32, -64, 4, + 26, 1, -1, -41, 44, 4, -22, -22, 47, -30, 7, 5, 3, -37, 45, 1, + -53, 44, -1, -20, 7, 12, -13, 9, -23, 26, -2, -47, 32, 37, -61, 6, + 42, 0, -25, -43, 76, -23, -38, -10, 73, -24, -57, 47, 45, -70, 3, 19, + 7, -19, -8, 10, 24, -12, -36, 66, -60, -1, 50, -32, -19, 8, 26, 2, + -44, 11, 53, -42, -26, 20, 42, -52, 14, 16, -26, -11, 42, -41, 16, 16, + -23, 13, 1, -6, 17, -18, -41, 71, -39, -23, 40, 13, -30, 2, 19, 0, + -39, 10, 24, -15, -25, 12, 66, -81, 6, 47, 9, -69, 12, 47, -9, -36, + -27, 76, 9, -107, 58, 53, -68, 19, -10, 39, -49, 8, 14, -11, -17, 21, + 18, -25, -17, 47, -4, -48, 32, -9, -4, -3, 8, -5, 29, -40, 13, 14, + -31, 24, 7, -48, 27, 37, -61, 22, 15, 7, -46, 17, 10, 22, -45, -9, + 56, 1, -73, 43, 34, -51, -15, 40, 2, -47, 35, 8, 27, -87, 31, 86, + -94, -27, 67, 10, -44, -15, 43, 11, -46, 6, 9, 33, -71, 35, 26, -30, + -18, 37, -18, -9, 20, -15, 1, 5, 9, -2, -23, -11, 50, -42, -3, 24, + 6, -21, 17, -5, -8, 11, -26, 24, -19, -9, 33, 22, -78, 38, 44, -48, + -53, 80, 6, -66, 14, 36, 8, -37, -15, 66, -24, -75, 87, -14, -27, -10, + 45, -12, -38, 13, 33, 7, -67, 20, 75, -55, -67, 85, 8, -52, -11, 45, + -10, 13, -34, 12, 26, -36, 7, -1, -1, -7, 23, -27, 18, 15, -12, -28, + 27, -6, 9, -52, 40, 26, -50, 3, 51, -10, -71, 67, 10, -59, 4, 56, + -27, -20, -19, 58, 6, -81, 38, 49, -39, -39, 47, 14, -25, -40, 54, -2, + -20, -38, 82, -25, -51, 44, 24, -60, 8, 51, -47, -2, 6, 22, 9, -34, + -20, 78, -56, -25, 36, 19, -49, 17, 32, -50, 44, -29, 4, -11, 14, 3, + -13, -11, 19, 13, -24, 28, -32, 33, -37, 39, -61, 119, -76, 120, -70, 99, + -122, 89, -113, 91, -123, 122, -123, 77, 86, -116, 6, -118, 123, -23, 64, -93, + 17, 24, -125, 124, -125, 124, -24, -12, 56, 87, -54, 38, -91, 64, -2, -41, + 126, -127, 20, 8, -48, -62, 127, -128, 88, -43, -18, 86, -100, 44, -32, -26, + 71, -13, 6, 51, -33, -50, 106, -59, 33, 5, -20, 69, -56, 54, -48, -6, + 38, -5, -38, 35, -1, 12, -1, 4, 23, -56, 19, -7, 5, -4, 31, -38, + 3, -12, -9, -25, -7, 24, -32, 17, -21, -22, 24, -20, 6, -18, 0, -15, + 5, -16, 15, 3, 2, -10, 3, 27, -31, 37, -12, 32, -5, 2, -21, 27, + -14, 20, -8, 5, 15, -7, -11, 20, -37, 7, -23, 17, -22, 11, -14, 8, + -44, 39, -52, 26, 3, 14, -10, 51, -45, 29, -19, 19, -3, 41, -21, 46, + -23, 10, 16, -25, 3, 7, -30, 19, -9, -5, -1, 1, -19, 1, -24, -23, + 51, -48, -10, 17, -34, -38, 60, -71, 26, -43, 65, -59, 70, -26, 61, -51, + 63, -51, 42, -25, 58, -36, 31, 10, -14, -9, 8, -18, 8, 4, 8, 7, + 31, -52, 39, -53, 53, -56, 24, 11, 1, -20, -8, -32, -18, -10, -25, 4, + 1, 37, -37, 42, -42, 53, -57, 52, -18, 30, 11, 20, -52, 55, -61, 56, + -50, 24, -26, 38, -42, 36, -1, -43, 58, -46, 6, 18, -35, 31, -36, 28, + -55, 55, -98, 52, -41, 26, -24, 48, -31, 48, -26, 30, 19, -17, 23, -8, + 13, 15, 19, -7, -23, 41, -36, 20, -39, 65, -64, 66, -38, -9, 7, -14, + -10, -3, 6, 15, -19, -40, 53, -67, -11, -12, -25, 23, -11, -12, 46, -48, + 39, -20, 20, -14, 31, -54, 71, -25, 2, -8, -5, -9, 1, 7, 27, 17, + -14, 43, -31, 27, 11, -33, 20, -2, -33, 45, -38, 17, -9, -11, -17, -22, + -19, 20, -25, 4, 29, -35, 14, -17, 1, -7, 19, 2, 16, 32, -3, -17, + 4, 0, -9, 17, 5, -8, 52, -32, 40, -39, -5, -18, 14, -21, 31, 10, + -17, 8, -34, -7, 1, -44, 7, 10, -8, -6, -18, -25, -1, -19, 16, -29, + 62, 6, 9, 21, 0, -14, 4, 5, 20, 13, 27, -1, 18, -5, 21, -31, + 11, 2, -9, -4, 21, -27, 8, -21, -28, -19, 14, -12, 5, -20, 20, -36, + 4, -18, -27, -4, -4, 15, 4, 48, -7, -11, 20, -6, 7, 20, 1, 20, + 0, 35, -35, 28, -37, 7, -43, 21, -22, 23, -18, 12, -22, -13, -20, -11, + 7, 23, -10, 19, -18, 17, -41, 4, -16, -8, 21, 11, -4, 10, 30, -24, + 32, -15, 15, -13, 28, -5, 38, -10, 0, -22, -13, -12, 24, -18, 30, -7, + 4, -16, 27, -28, -3, -1, 18, -14, 31, -24, -3, -13, -19, -36, -2, -31, + 9, -2, -12, 17, 12, -50, 46, -49, 43, -15, 13, 22, 15, -25, 10, -8, + -6, 14, -2, 24, 15, 9, 17, -13, 5, 14, -15, 7, 20, 4, 4, 18, + -16, 3, -47, 31, -46, 19, -24, 5, -19, -1, -42, 14, -44, 18, -7, -1, + 15, 9, -35, 32, -44, 39, -46, 23, -16, 36, -25, 45, -34, 32, -8, 10, + 5, 28, 0, 12, 11, 3, 20, -23, 6, -8, 16, 7, 17, -19, 32, -44, + 3, -8, -21, -8, -5, 2, -29, 2, -3, -19, -14, 3, 7, -23, 10, 1, + 3, 8, 13, -44, 20, 21, -16, 23, 3, 5, 10, -11, 32, -11, 13, -7, + 30, 4, 16, -7, -6, -7, 14, -40, 4, -16, -26, 3, -1, 0, -6, 5, + -50, 37, -27, 18, -16, -14, 6, -1, -4, -15, 8, -12, 14, 9, -22, 42, + -10, 23, -11, 36, -15, 13, 30, 1, 47, -20, 33, -14, -12, 1, -20, -9, + -9, -11, -13, 7, -37, 25, -47, 14, -13, 4, -12, 9, -32, 18, -48, -1, + -35, -1, -7, 35, -20, 53, -4, 34, -7, 13, 19, 9, 30, 6, 45, -22, + 23, -18, -6, -1, 3, -30, 14, -15, 9, -39, 10, -33, -13, -24, 10, 14, + 14, -10, 2, -34, -4, -20, -21, -14, 40, -10, 17, -14, 28, -17, 37, -26, + 69, -15, 38, 2, 21, -25, 37, -61, 13, -9, 5, -17, 18, -41, 22, -57, + -1, -9, -13, 24, -10, 38, -5, 8, -16, -2, 1, 12, -25, -2, -13, 2, + 2, -16, -19, 32, -30, 22, 20, -4, 12, 11, -17, 19, -17, -3, 20, -33, + 65, -27, 32, -14, 8, -8, 13, -19, 9, -2, 7, 33, -40, 18, -18, -18, + 6, -23, -11, -11, -28, 4, -11, -15, -14, -8, -5, 34, -6, 19, 1, -3, + 9, -1, 5, 5, 14, -11, 40, -3, 18, -20, 16, -7, 2, -5, 9, -16, + 9, -17, 0, -17, 4, -17, -3, 3, 8, -14, -19, 12, -21, -7, 1, -2, + -8, 16, 3, -6, 35, -23, 33, -13, 11, 12, 3, -7, 26, -11, 19, -18, + 23, -22, 39, -49, 39, -50, 11, -38, 26, -29, 10, -6, -22, 15, -8, 15, + -37, 36, -43, 39, -43, 18, -26, 1, 11, 4, -2, 9, 7, 2, 7, 19, + 1, 1, -4, 16, -5, 16, -9, -3, 4, -4, -1, -17, 0, 11, 16, -27, + 12, -15, 15, -3, 0, 10, -3, -5, 12, -13, -7, -13, -31, -1, -3, -17, + 15, -31, 25, -10, 15, -1, 2, 4, 10, 7, 32, -13, 7, -22, 2, -10, + 16, 1, -15, 19, -24, 16, -18, -12, 18, -9, 9, 24, -8, 8, 11, 0, + -31, 17, -55, 21, -43, 40, -40, 29, -54, 44, -34, 22, 11, 16, 7, 19, + 21, -6, 2, -7, -16, 22, 0, -1, -4, 5, -8, 26, -42, 4, -6, -21, + 35, -16, 8, 0, -22, -13, 11, -31, 7, -28, 4, 17, -12, -18, -2, -23, + 23, -1, 19, 34, 7, 7, 35, -19, 11, -8, -17, 8, 4, 16, -16, -13, + 9, -15, -5, -1, -6, 7, 3, 11, 1, -7, -24, 21, -31, 36, -3, -10, + 8, 2, -17, 12, -24, 6, -3, 9, 15, 3, 13, -8, -13, -3, 6, -19, + 14, -33, 16, -17, -5, -31, 3, -29, 24, -7, -6, 35, -20, -5, 34, -20, + 25, -3, 10, 25, 8, 14, -13, 0, 1, 17, -33, 51, -38, 45, -32, 39, + -3, -2, -24, 3, -18, 14, -4, -44, 2, -25, -15, -2, -23, 3, -2, -2, + 20, -14, 8, -10, -4, 21, 11, -13, 32, -4, 8, 19, -16, -2, -2, -2, + 14, -2, -1, 27, -26, 20, 11, -13, 10, -3, -7, 12, -13, -3, -30, -16, + 10, -26, -3, -10, -2, -9, 15, -17, 1, -2, -7, 14, -8, 12, -3, -1, + 2, 47, -26, 22, -19, 16, 2, 13, -3, 21, -10, 22, -32, 43, -24, 16, + 0, 5, -2, 12, -44, -12, 1, -26, 1, -36, 5, 2, 9, -17, 20, -37, + 14, -9, -5, 6, -3, -13, 23, -19, 25, -33, 6, 17, 10, 19, 15, -4, + 12, 5, -9, 33, -20, 26, -9, 11, -2, 11, -21, -7, -13, -4, -8, -12, + 0, -10, -9, 8, -33, 9, -26, 8, 6, -8, 12, 7, -8, 0, 7, -16, + 25, -8, 27, 12, 0, 9, -9, 4, -17, 14, -16, 11, -8, 18, -2, 4, + 2, -20, -18, 22, -16, -5, 3, -24, 13, -10, -12, -10, 2, -16, 33, -15, + 21, -15, -4, -19, 29, -22, 18, 2, 20, 12, 18, -22, -7, -16, 7, -19, + 14, 1, -17, 33, -22, 38, -8, 3, -3, 21, -17, 51, -43, 15, -22, -23, + -6, -12, -14, 14, 9, 6, 4, -31, 3, -16, -14, 22, -22, 5, 13, -25, + 17, -2, -18, 7, 1, 5, 36, -16, 23, 4, -15, 29, -20, 10, 1, 24, + 17, 16, -4, -16, -37, -11, 1, -33, 27, -36, 17, -22, 2, -33, 16, -29, + 32, -7, 24, -12, 14, -12, 22, -16, 15, -20, 19, 9, 14, 12, -1, -24, + 13, -6, -1, 32, -19, 24, 12, -26, 4, -31, -38, 18, -16, -13, 3, -14, + -1, 11, -15, 15, 0, -2, 30, -6, 35, -23, 10, -35, 5, -14, 17, -21, + 20, 4, 7, 8, -5, -15, 20, -25, 26, 6, -3, 3, 5, -24, 26, -35, + 4, 0, -6, 13, -23, 8, -25, 1, -2, 9, 3, 17, 4, 0, 13, -15, + 3, -21, -16, 4, -5, -10, 11, -2, 7, 23, -22, 25, -19, 18, 25, -9, + 14, -21, -7, 11, -24, 22, -12, -7, 6, 9, -33, 11, -20, 2, -9, 2, + 3, -13, 12, -15, 23, -21, 16, -16, -2, 8, 13, -12, 18, -10, 16, -12, + 20, -18, 18, -1, 21, -21, 20, -30, -6, 10, -2, 13, -6, -15, 6, 2, + -1, 1, -19, 9, -15, -3, -11, 0, -5, 1, 5, 1, -4, -8, 1, -16, + 23, 0, -23, 2, 8, -6, 38, -4, 2, 13, -17, 31, -4, -8, 22, -14, + 0, 12, -22, 7, -7, 11, 4, -4, -12, -9, -22, 2, -17, -17, -11, 7, + -17, 19, -24, 9, -8, -6, 29, -4, 10, 4, 4, 23, -1, 9, -6, -12, + 23, 16, -6, 33, -29, 12, -7, -10, 17, -4, -18, 21, 0, -14, -2, -20, + -21, 10, -28, 5, -18, -4, 0, -11, 1, 5, -17, 3, 9, 20, 6, 1, + -7, 2, -7, 3, 9, -22, 29, 6, -1, 25, -10, 6, -1, 4, 12, 18, + -13, 28, -11, 6, -15, -14, -22, -7, 5, -14, 1, -16, -12, -5, 5, -9, + 4, -1, -14, 21, -10, -5, 0, -17, -7, 2, -10, 6, 11, 1, 37, -17, + 6, 21, -24, 41, 2, 23, 0, 10, -18, 16, -26, 14, -21, -19, 18, -9, + -14, -1, -9, -14, -3, -7, -10, 7, -7, 19, -11, 15, -25, -3, -6, 2, + 8, -10, 4, 12, -3, 11, -2, -2, 5, 31, -9, 39, -21, 14, -23, 18, + -16, -1, -3, -6, 0, 22, -9, -5, -17, -4, -12, 2, -3, -7, 10, -10, + 7, -20, -19, -10, 0, -14, 32, -15, -18, 13, -9, 2, 17, -14, 6, 36, + -9, 28, 1, 0, 17, -10, 5, 17, -8, 12, -2, 3, 2, -22, -6, -14, + 6, 8, -11, -14, 2, -23, 25, -35, 3, -18, 1, -14, 22, -1, -12, -7, + -9, 13, -4, 12, 4, -3, 18, 0, 1, 8, -14, 14, -2, 1, 17, -3, + -14, 35, -17, 19, -14, -6, 1, -9, 18, -17, -4, -13, -2, -14, 10, -10, + -6, 0, 3, 5, -12, -13, -3, -6, -6, 11, -13, -7, 13, -2, 6, 13, + -7, 11, -5, 23, 1, 29, -17, 23, -10, 18, -16, 12, -20, 10, 7, -9, + -5, -21, -9, 5, -13, -2, 0, -15, -11, 3, 0, -18, 5, -25, -2, 3, + -2, -3, 4, 8, 14, -7, 15, 4, 8, 19, 9, 11, 7, -3, 14, -11, + 1, 15, -35, 3, 3, -10, -16, 0, -15, 2, 3, -12, 27, -23, 32, -15, + 10, -14, 3, -27, 10, -15, 12, -24, 7, 2, 9, -2, -2, -1, 3, 1, + 1, 8, -4, 0, 6, -6, 1, 1, -1, 8, -11, 31, -27, 13, 4, -3, + 5, -1, 0, 2, 9, 0, 12, -31, 4, -27, 1, -25, 20, -21, -14, 12, + -14, 0, -5, -23, 18, -1, 15, 19, -5, 20, -8, 14, -7, 16, 3, 0, + 8, 10, 0, -8, -10, 3, -8, 9, -12, 4, 15, -6, 2, -12, -29, -3, + -16, -11, 35, -18, -1, -28, 7, -12, 0, 7, -5, 22, 10, 10, -4, 6, + -13, 21, -23, 20, 8, -13, 11, 15, -6, -6, -22, -1, 3, 14, 7, 11, + -27, 12, -17, -12, 8, -15, 3, -8, 12, -12, 5, -30, 12, -18, 9, -2, + 3, 4, 15, 1, 5, -9, 0, -8, 24, -2, 21, 5, -4, -4, 14, -15, + 0, -1, 3, 17, -5, 13, -19, -10, -4, -6, -4, -7, 18, -27, 8, 1, + -12, -21, -13, 1, -9, 11, 1, -3, -1, 22, -21, 9, 6, -3, 20, -2, + 17, 7, -12, 1, 4, 4, -9, 9, -20, 24, 7, -9, -3, -7, -6, 10, + 7, 3, 9, -2, -3, -4, 1, -19, -8, -16, 0, -12, 0, -25, 4, -22, + 10, -9, 0, -3, 15, -1, 8, 11, -15, 10, 13, 1, 22, -5, 15, 1, + 24, 6, 0, -6, 5, 5, 10, 8, -1, -11, -14, 3, -31, 2, -22, -4, + -8, -15, -2, -31, -12, 6, -7, 5, 2, 3, -4, 19, 3, 4, 7, 7, + -8, 31, -6, 26, 1, -2, 2, -3, -10, -4, -4, 9, 3, 12, -16, 16, + -9, -1, 5, 4, -7, 13, -17, 0, -11, -13, -22, 1, -9, 4, -7, 7, + -10, 5, -1, -6, -3, -21, 7, -10, 18, -3, 1, -7, -11, 11, -8, 12, + 20, 3, 13, 16, -1, 3, 13, -3, 23, 16, -3, 15, -14, 12, -6, -8, + -28, 0, -33, 4, -11, -12, -13, -21, -17, -16, -5, -12, 16, -7, 15, -6, + -5, 3, -9, 21, 17, 13, 14, 11, 21, -12, 31, -18, 7, 12, 8, 9, + 7, 1, -3, -7, -14, 17, -35, -10, -2, -18, -8, -10, -20, -22, 2, -10, + -3, 1, -1, 4, -5, 11, -20, 11, -6, 27, 7, 18, 8, -1, 2, 3, + 11, -9, 5, 5, -7, 29, -6, 20, -21, 23, -15, 19, -19, 2, -22, 11, + -26, -7, -10, -30, -1, -3, -6, 15, -22, 16, -7, -9, -2, -7, -5, 11, + 17, -13, 2, 8, -5, 6, 27, -6, 12, -6, 4, 15, 3, 14, -3, -12, + 11, -2, 6, 5, 4, -6, -12, 0, -32, 2, -22, 22, -12, -5, -7, -11, + -7, 6, -1, -3, -3, -16, 2, -1, 0, 0, -7, -2, 1, 12, -4, 5, + 20, 1, 16, -2, 14, -1, 19, 8, 29, -8, 7, -14, -2, 3, -13, 8, + -40, 22, -18, 2, -14, -8, -11, -8, 12, -21, -1, -10, -12, -6, -4, -14, + 6, -19, 7, 14, 1, 11, 11, -11, 25, 1, 14, -5, 31, 0, 22, 4, + 1, 3, 6, -3, 4, -2, -20, -7, -26, 1, -12, -7, -10, 2, -1, -5, + -7, -8, -10, 6, -7, -6, 10, -17, 6, 3, 15, -8, 15, -7, 12, 1, + 9, -4, -2, 10, 9, -1, 10, -4, 9, -8, 17, 0, -13, -7, -2, -11, + 3, -2, -15, -4, -11, -5, -9, 1, 8, -10, 8, -8, -6, -18, 21, -19, + 26, -19, -1, -11, 10, 4, 12, -10, 16, -10, 17, 8, 13, -1, 17, 1, + 5, -1, 11, -8, 9, 16, -17, 3, -26, -17, -14, 6, -17, 4, -20, 0, + -1, -6, -4, 2, -15, 13, -3, -1, 0, -2, -8, 11, 7, -3, -8, 5, + 14, -1, 28, -19, 13, -4, 8, 1, 11, 7, 6, -8, -2, -13, -10, -22, + 6, 11, -1, -1, -5, -13, 18, 3, -10, 9, -17, -8, 9, -9, 1, -17, + -4, -16, 18, -6, 15, -10, 17, 5, 0, -5, 0, -11, 12, 15, 4, 8, + 5, -4, 0, -2, 3, -17, -2, -1, 11, -6, -7, 2, -33, 23, -6, -1, + -2, -2, -1, -8, 3, -29, -2, -34, 16, -3, 16, 1, 10, -12, 23, 0, + -3, 16, 12, 19, 23, -1, 8, -26, 16, -32, 26, -13, 2, -11, 5, -1, + -15, -9, -16, 7, -6, 14, -15, 5, -10, -7, -9, -9, 6, -17, 13, 18, + -5, -3, -4, -4, -18, 28, -6, 13, 17, 24, -2, 9, -14, 1, -11, 7, + 17, 1, -15, 10, -23, -4, -12, 5, -20, 17, -10, 6, 0, -9, 4, -8, + -15, 6, -16, 7, 9, 3, 6, -12, -17, 0, 4, 13, 22, -4, 10, -8, + 7, -12, 5, 5, 1, 11, 2, 10, -3, -2, 3, -10, -5, -7, -4, -18, + 17, -2, -14, -16, -7, -10, -3, 6, -1, 14, -11, 15, -18, 2, -6, 0, + -1, 0, 20, -17, 1, 6, 2, 6, 12, -3, 7, 25, -5, 17, -14, 0, + -6, 0, -2, -5, -1, -10, 8, 2, -9, -19, -7, -17, 5, 3, -7, 4, + -15, -5, 9, -12, -1, -5, 3, -5, 26, -2, 3, -4, 5, 3, 7, 10, + 5, 6, 6, 26, -17, 0, -1, 3, -3, 10, -7, -7, -9, 11, -18, 0, + -16, -6, -5, 3, 7, -14, -14, 0, -21, 14, -8, -1, -12, 2, 1, 2, + -3, -1, -3, 18, 5, 5, 9, 12, 7, 18, 8, 5, -25, 16, -15, 16, + -7, 9, -22, 1, 14, -13, -5, 2, -6, -8, 13, -17, 6, -16, 1, -5, + -14, -6, -6, -15, -2, 9, -9, -18, 15, -19, 12, 7, 4, 8, 14, 15, + 6, 10, -3, 9, -7, 23, -17, 21, -20, 7, 0, -9, 8, -10, 1, 4, + 2, 3, -9, -9, -15, -6, -21, -16, -6, 0, -11, 19, -8, -9, 5, -6, + 0, 5, 14, 7, 1, 12, 8, 7, -5, 12, 8, -4, 19, 4, -7, 2, + 3, -12, -8, -1, 0, 5, 7, -5, -8, -22, -8, -21, -2, -9, 10, -20, + 13, -6, 8, -17, -9, -6, 2, 5, 8, 6, -3, 10, -9, -2, 15, -6, + 20, 7, 11, 10, -3, -4, -8, 25, -25, 18, -12, 17, -6, 20, -22, -1, + -17, -10, 5, -10, 9, -13, -9, -6, 10, -25, -5, -2, -5, 13, 2, -5, + -8, -10, 11, -27, 10, -4, 11, 0, 33, -4, 10, -14, 1, 12, -2, 27, + -8, 6, 11, 9, -12, -4, -10, -13, 12, 5, 1, -10, -14, -15, -8, -7, + -9, 3, -5, 10, 3, -11, -12, -13, -3, -3, 3, 2, 9, 17, -6, 25, + -3, -3, -8, 19, 3, 30, -10, 12, -22, 7, -5, -10, -3, 21, -8, 12, + 6, -5, -13, -13, -9, -9, -1, -23, 13, -17, 15, -22, -11, -18, 8, -14, + 20, 1, 4, -5, 3, 3, 5, 11, 1, 2, 27, 1, 10, -7, -8, -2, + -2, 7, -1, 17, -5, 24, -7, 5, -10, -20, -6, 5, -4, -5, -1, -18, + -5, -14, -1, -20, 1, 7, -7, 12, -4, -2, -4, 2, 8, 0, 7, 1, + 6, -2, 18, -5, -7, 4, 3, -2, 13, 4, 0, 2, -3, 2, -10, -6, + 1, -6, 6, -7, -3, -21, -2, -12, 5, -1, -9, 7, -3, 13, 5, 5, + -8, 0, -8, 19, -5, 13, 13, -7, 3, 0, -10, 0, -8, 20, -8, 13, + -20, -5, -7, 3, 5, -7, 2, -5, -4, -14, 11, -23, -13, 2, -1, 12, + 13, 5, -6, 23, -9, 9, -6, -9, 18, -13, 16, -3, -7, -17, 3, -13, + 12, -9, 4, 0, 0, 13, -18, -1, 3, -13, 20, -5, 1, -20, 15, -23, + 18, -4, -8, 5, -7, 16, 4, 6, -3, 7, -21, 19, -17, -7, 9, 5, + 3, -5, -3, -16, -9, 25, -9, 12, -5, 10, -5, 9, -4, -6, -3, 4, + 10, -2, 11, -12, -2, -14, 8, -23, -5, 0, -8, 9, -2, -11, -3, -9, + 9, 2, 2, 4, -5, 7, 11, -16, 0, -6, 7, 6, 25, 5, 6, -4, + 3, 4, 3, 2, -8, -3, 5, -1, -11, -4, -9, -3, -15, 10, -12, -5, + 11, -4, -7, 6, -29, -5, 6, 11, 3, 9, -18, 13, -14, 19, -1, -2, + 4, 5, 12, 1, 5, -8, 3, 1, 20, -6, 2, 3, -16, 10, -10, -18, + -11, -7, -7, 9, -4, -8, 9, -15, 13, -13, -3, -7, 3, 8, 11, -6, + -16, 1, -8, 20, 4, 15, -5, -3, 11, -5, 6, 0, -5, 10, 13, 0, + -6, -11, 0, 11, -11, 10, -7, -8, 1, 16, -9, 2, -22, -9, 0, 4, + 5, -12, -22, 2, -8, -8, 14, -16, 0, 13, 0, 9, -7, 2, -1, 7, + 8, -3, -3, 2, 15, 5, 10, -7, 12, -4, 22, -4, -3, -12, -2, -15, + 8, -2, -22, 7, -10, 5, 12, -20, -9, -11, -2, -12, 2, -9, 5, -3, + 11, 7, -9, 4, -4, 24, -7, 21, -15, -3, 2, 14, -1, 5, 18, -12, + 13, 3, 5, -10, -11, 0, -8, -2, -4, 2, -15, 9, -10, -16, -9, -7, + 0, -1, 3, -8, -10, 5, -8, 4, -3, 8, -2, 20, 1, 6, -4, -9, + 4, 14, 7, -1, 3, -5, 18, -7, 20, -6, -10, 8, 1, -2, 3, -4, + -5, -3, -6, 0, -16, -7, 12, 0, -17, 4, -31, -7, 1, 1, -4, 8, + -11, 6, -1, 11, -5, -7, -4, 2, 4, 15, -3, 21, -5, 20, 3, -12, + 21, -1, 10, 5, 6, -20, -1, -18, 2, 3, -4, -5, -1, 6, -2, -11, + -17, -15, -13, 0, 6, -18, 7, -18, 7, -7, 6, 7, -10, 18, 16, 2, + -1, 3, -11, 6, 14, 1, 15, -2, 29, -8, 17, -14, 2, -19, 12, 8, + -6, -1, -23, 6, -11, 7, -19, -18, 0, 1, -8, -8, -4, -20, 8, -8, + 4, 10, -12, 13, 0, 18, -10, -3, -4, 6, 4, 17, 7, -2, 18, -9, + 14, -10, -4, -11, 4, 3, 23, -17, -6, -2, -7, -7, 9, -10, 1, 2, + -4, -14, -7, -6, -8, -4, 7, 2, -3, 3, 0, 13, -10, -4, -9, -6, + 18, 11, -4, 16, -8, -4, 1, -1, 7, 3, 3, 3, 10, -15, -2, -9, + 9, 0, 2, 2, -9, 12, -7, 0, -23, -7, -19, 2, -1, 0, 4, -15, + 7, 3, -3, 0, 9, -12, 19, 4, 8, -13, -6, 5, -1, 14, 10, 9, + 13, -3, 16, -18, 13, -18, 7, -10, 13, -6, -11, -3, 7, -23, -6, -11, + -21, 9, -1, 4, -3, -16, 0, -12, 7, 14, -5, 15, 0, 6, -5, -3, + -9, 9, 4, 10, 4, -2, -7, 10, -1, 10, -6, -14, 15, -4, 13, -4, + -4, -14, 5, -2, 4, -9, 3, -14, 2, 3, -10, -1, -9, 0, 3, -6, + 12, -16, 0, 4, 10, -25, 6, -5, 2, 8, 3, -2, -4, 15, 4, 7, + 2, -1, -6, 10, 11, 2, -2, -14, 6, -3, 0, -3, -9, -10, 1, -1, + -15, 9, -29, 9, -10, 7, -3, -3, -10, -2, 14, 4, -6, 0, 1, 12, + 4, 18, -15, 19, 1, 15, 1, 1, 3, -10, 8, -1, 7, -30, 8, -19, + -2, -5, -9, -10, 0, -1, 6, -4, -12, 1, -18, 10, -1, -12, 2, 7, + 12, 11, 0, -4, -1, 6, 10, 17, -8, 1, -12, 5, -2, 1, -7, -1, + 4, 3, -3, -1, -18, 8, -9, 0, -2, 8, -12, 12, 7, -5, -2, -16, + -7, 9, -5, 11, -9, -4, 3, 1, -9, -1, -2, -6, 7, 12, 0, -8, + 9, -10, 3, 0, 2, -3, 11, 14, 4, 3, -12, 3, -3, 2, 12, -4, + -2, -2, 9, -21, -5, -28, -6, -10, 6, 7, -6, -3, -24, 7, -11, 10, + 0, 8, 13, 10, 6, -7, -2, -5, 7, -1, 9, 18, -2, 12, -4, 7, + -26, 13, -6, 19, 6, 6, -5, -16, -6, -8, -18, -2, 1, -11, 3, 4, + -16, -8, -10, -3, 2, -3, 5, 5, 0, 11, 0, -14, 0, 1, 14, 11, + 13, 0, -2, 5, -1, -4, -2, -4, 5, 21, 3, 14, -5, -22, 5, -11, + -3, -6, -3, -11, 0, -5, -13, -10, -18, 3, 9, -10, 2, 3, -11, 11, + -11, 5, -19, 23, -1, 20, 18, 4, -3, -6, 9, 4, -3, 8, 4, 6, + 2, 5, -14, -6, -3, 2, -6, -4, -3, -11, 0, -5, 0, -21, -2, -10, + 11, 5, -4, -5, -5, -8, 10, -10, 4, -1, 6, 12, 9, 2, 8, -20, + 8, -2, 11, -11, 1, -4, 5, 6, -6, 6, -14, 14, 4, -2, 12, -3, + -10, 8, -5, -15, -9, -1, 5, 8, -3, 0, -23, -9, -11, 4, -12, 3, + -4, 4, 1, 15, -12, 3, 13, 2, 5, 8, -8, 7, 11, -3, 17, -11, + 5, 3, 19, 13, 3, -11, -11, -2, -9, -7, -4, -24, -1, -17, -3, -17, + 0, -15, 2, -1, -5, -4, 3, 2, 2, 11, -4, 3, -6, 11, 8, 3, + 6, 3, 7, 7, 6, -6, 2, 0, 14, 14, 3, 8, -6, 4, -3, 6, + -13, -2, -9, -4, 5, -13, -5, -21, -1, -6, -1, -5, -14, 8, -7, 5, + -7, -17, -11, 7, 3, 20, 7, 1, -3, 4, 5, 14, -3, 5, 3, 10, + 8, 6, -6, -2, 6, 3, 7, -6, -3, -3, -6, -1, -27, -11, -17, 0, + 11, 7, 1, -7, -9, -13, 5, -11, 0, -10, 15, 2, 5, -2, -5, 1, + 6, 6, -6, -5, 6, 2, 5, 3, 10, -16, 11, 8, 18, 3, 13, -11, + 7, 5, -7, -6, -20, 15, -1, 10, -1, -13, -17, -11, -3, -13, -4, -14, + -3, -2, -6, 6, -28, 9, -8, 10, 0, 12, -2, 10, 9, 1, 3, -6, + 5, 17, 24, 18, 3, 4, -9, -4, 2, -8, -4, -2, -11, 1, -8, -12, + -9, -10, 5, 0, -7, -9, 7, -18, 6, -10, -12, -1, -1, 13, 1, 18, + 2, -3, 4, 3, 3, -3, 3, 10, 9, 7, 5, -8, -7, 0, 3, -7, + 7, -2, -2, 5, -10, 2, -5, -3, -1, 4, 1, -2, -10, 4, -9, -5, + -12, -18, 3, 6, -3, 3, -15, -1, -13, 6, -2, 8, 0, 8, 16, -2, + 17, -4, 8, 3, 23, -1, 11, -8, 10, -4, -5, -3, -13, -2, -1, -2, + 2, -9, -13, -13, -2, -11, -2, -20, -5, 0, 3, 2, -1, -10, 1, 8, + 3, 9, 6, 4, -3, 13, 3, 4, 11, 2, 11, 8, -2, -1, -2, -2, + -2, -1, -21, -1, -14, 8, 6, -8, -10, 2, -16, 4, -3, -1, -10, 7, + -1, 4, -4, -12, 3, -2, 13, 2, -3, -9, -2, 6, -7, 8, -8, -5, + 12, 7, 8, -3, 6, -1, 16, 0, 7, -8, 3, -7, -1, 0, -6, -4, + -8, 6, -1, 4, -19, 2, -3, -8, -3, -12, 4, -6, 2, -7, 1, -13, + 2, 9, -1, 17, -19, 3, -3, 23, 9, 6, 3, 6, 6, -5, 11, -11, + 1, 0, -5, 6, -6, -4, -5, -7, 3, -4, -14, -9, -7, -1, 5, -11, + 4, -19, 14, -4, 3, 4, 2, 0, 9, -2, -3, 2, -2, 10, 15, -3, + 14, -6, -4, 6, 1, -8, 11, -9, 4, 3, -9, 2, 2, -2, 2, -2, + -9, -2, -2, 1, -6, -6, -22, -16, -10, 12, 0, 5, -8, -2, -4, -2, + 5, -1, 7, 7, 9, 1, 7, 6, -1, 10, 11, 5, -3, 8, 1, -1, + 8, -15, -6, -10, 12, 0, 2, -5, -9, -12, -7, -4, -14, -4, 0, -1, + 5, -7, -8, -12, 0, 2, 16, -3, 11, -4, 16, 11, 2, -3, 2, 8, + -1, 7, -13, 4, -3, -1, 3, -10, -2, -11, 3, 2, 3, -7, -10, -5, + -10, 12, -8, 5, -7, 15, 1, -10, 7, -16, 1, 3, 4, -5, 7, -7, + 4, -2, -1, -8, 0, -2, 17, 10, -2, 6, -5, 3, 10, -7, 2, -3, + 4, 5, 5, -3, -8, -8, -1, 1, 7, -5, -11, -2, -10, -4, -15, -7, + -10, -2, 2, -4, -10, -8, 0, 2, 6, 3, 2, 3, 10, 14, 8, 7, + 3, 5, -5, 20, -6, -1, -2, 0, 1, -2, -2, -8, 3, -3, 10, -14, + 3, -3, -2, 0, -5, 0, -15, 4, -2, 0, 4, -7, 3, -8, 7, -14, + -2, -6, 4, 2, 3, -10, -2, 5, -3, 12, -2, -5, -9, 1, 4, 1, + 11, -12, 15, 5, 20, 10, -5, 1, 5, 3, -13, 6, -16, 5, 1, -5, + -8, -3, -14, -6, -2, -5, -8, -17, -9, 3, -6, -2, -3, -3, 1, 14, + 2, 4, 5, 3, 8, 7, 12, 0, 11, 4, 16, 2, -3, -9, -1, 1, + -1, -3, -6, -14, 4, -6, 2, -14, -9, -11, -1, 0, 0, -5, -6, -10, + 5, -5, 2, -3, 2, 2, 17, -2, -1, -3, 3, 11, 1, 10, 2, 7, + 6, 5, -5, -3, -3, -2, 7, 2, 1, -18, -5, -2, -3, -5, 0, -2, + 0, 8, -9, -10, -15, -7, -2, -1, 6, -8, 16, -10, 13, -4, 2, -4, + 4, 7, 9, 6, -5, -2, 8, -1, 11, -6, -1, 5, 8, 0, 9, -20, + 0, -9, 4, -3, 1, -4, -11, 2, -6, 0, -12, 0, 1, 5, -2, 1, + -7, -4, 3, -1, -10, 3, -3, 7, 4, 8, -9, -6, -10, 0, 0, 2, + -4, 6, 9, 10, 2, 0, -1, 2, 14, 3, 7, -7, 2, -2, -2, -6, + -9, 2, -3, 6, -3, -7, -9, -10, -2, 2, -1, -11, 2, 1, 7, -4, + -7, -19, 3, -1, 6, 6, 6, 6, 0, 6, 7, 3, -1, 3, 8, 3, + 4, -10, -5, -7, 5, -4, -14, 2, -8, 5, -2, 2, -16, -4, -11, 2, + 4, -1, 2, -1, 0, 5, 4, -12, 3, 9, 7, 13, -3, -7, 2, 6, + -1, 7, -1, -1, 5, -5, 7, -11, -9, -13, 2, 5, 2, -2, -7, 5, + 4, -4, -2, -15, -4, 3, 0, 0, -5, 2, -7, -1, 9, -2, -1, 5, + 1, 1, -4, -5, -4, 6, 8, 7, -5, 4, -7, 4, 0, 1, -6, -5, + -2, 5, -1, 0, 1, 1, 3, 9, -4, -2, -4, -9, -1, 4, -17, 1, + -13, 11, -1, 6, -9, -1, 5, 1, 8, -3, 4, -5, 1, 7, -5, 1, + -3, 5, 3, 4, -7, -11, -7, 1, 5, -13, 11, -11, 1, 3, 6, -9, + 6, -5, -7, 4, -13, 5, -7, 10, 5, 6, -15, -1, 6, 4, 18, -7, + -7, -3, -4, 2, -5, 3, -4, 9, -4, 3, 3, -3, -10, 0, -1, 2, + 5, -3, 7, 3, 2, -6, -11, -2, -1, 4, -5, 4, -5, 0, -5, 5, + -5, -4, 2, 4, 2, 5, -8, -13, -3, 0, -1, -2, 4, 6, 9, 1, + 3, -7, -1, 1, 12, 1, 1, -1, -5, -1, 2, -8, -9, -7, -2, 3, + 10, -6, -7, -12, -7, -4, -5, 6, 0, 10, 5, 7, -4, -2, -8, 10, + 5, 9, 4, -1, -1, -1, -1, -1, -2, -3, 3, 9, -2, 9, -14, -13, + -8, -10, 1, 1, 3, 3, 1, -3, -12, -5, -7, 1, 6, 6, -2, -7, + -3, -3, 2, 2, 4, -9, 14, 8, 11, -3, 5, -11, 1, -1, 5, 3, + 8, 2, 8, -2, -6, -13, -10, 0, 4, 3, 4, -3, -9, 1, -5, -5, + -6, 1, -2, 2, -10, -6, -15, 1, -5, 4, -1, 2, 2, 4, 10, 4, + 2, -13, 0, 4, 8, 17, 2, 5, 4, 2, -6, 5, -5, 0, 8, -2, + -1, -5, -4, -5, -1, -5, -4, -5, 0, 0, 1, -9, -15, -3, -12, 1, + -1, -7, 10, 2, 5, -1, 2, -6, 2, 2, 10, 10, -1, 2, -2, 4, + 5, 0, -6, 12, 5, 3, -1, -8, -8, -4, -4, 3, -11, 0, -1, -1, + 0, -2, -14, -6, -9, 2, 1, 7, -4, 3, -1, 0, -3, 1, 2, 7, + 5, 4, 3, -2, -3, 1, 6, -1, 6, -11, 7, 2, -6, 2, -4, 0, + 2, 3, -7, -9, 3, 0, 4, -6, 0, -21, 0, -5, -1, 0, -1, 1, + -6, -1, -1, 0, -7, 5, 7, -2, 8, -4, -1, 3, 9, -6, 10, -6, + 7, 9, 10, 9, -6, 5, -14, 6, -5, 1, 2, -3, 0, -9, -10, -14, + -2, -3, 6, -8, -15, 3, -9, 0, -3, 0, -6, -1, 3, 9, 10, 3, + 3, -10, 6, 1, 3, -1, 9, 12, 4, 4, -9, -7, -5, 8, 6, 1, + 1, -4, -5, -5, -1, -11, -3, -4, 1, -1, 1, -10, -7, -2, -3, -4, + -3, -6, 11, 5, 3, 2, -8, -5, -2, 3, 9, 13, 5, 4, 4, 0, + -5, -1, -5, 9, 2, 3, -9, -4, 3, -6, 2, 1, -9, 5, -2, 3, + -2, -9, -8, -15, -5, -3, 3, -13, 11, 6, -3, 1, -6, -6, -1, 6, + 4, 6, 7, 1, 5, 0, 8, -6, 7, 2, 6, 2, -5, 0, -3, -1, + 3, -7, -1, -3, 5, 7, 6, -18, -10, -11, -7, -3, 10, -4, 3, -4, + -8, -5, -12, -3, -4, 12, 10, 2, -4, 6, 3, 1, 2, 0, -3, 3, + 7, 7, -5, 2, -4, 1, 3, 11, 2, 3, 4, -2, -7, -5, -17, -11, + 4, -3, 5, -7, -7, -6, -1, -8, -5, -5, 1, 7, 1, 2, -1, -9, + 7, 1, 7, 3, 3, 6, 9, 6, 1, -6, -4, 2, 5, 7, 4, -2, + 1, 3, -11, -1, -16, -2, -6, 1, 3, -8, -15, -11, 4, -1, 9, -2, + -5, 0, 6, 0, -7, 0, -8, 4, 2, 6, 2, 0, 2, 6, 2, -2, + 4, -2, 4, 14, 2, 2, -6, -6, -3, 4, -4, -1, -4, 1, -3, -6, + -1, -13, -1, -2, 7, -8, -7, -10, 0, 4, 3, -8, -3, 1, 4, 6, + 4, 6, -3, 5, 3, 4, 0, 6, 1, 4, 7, -3, -10, 8, -1, 9, + -1, 1, -11, -7, -3, -3, -6, -8, -9, -6, 1, -3, -6, -6, -5, 0, + 0, 2, -3, 0, 6, 4, 3, 2, 7, 4, 11, 14, 5, -1, -5, 1, + -2, 7, 3, 0, 1, 2, -5, -7, -10, -12, -10, -5, -5, -6, -6, -9, + 1, -8, -2, -1, -9, 1, 8, 2, -5, -2, -5, 0, 5, 6, 6, 7, + 8, 10, 2, 0, -3, -1, 2, 13, 3, 0, -6, 0, 1, -3, 0, -12, + -2, 4, -4, 4, -8, -11, -1, -2, 1, -1, 2, -12, 3, -6, 1, -12, + -7, -7, 3, 0, 9, 0, 1, 6, 1, -1, 2, 1, 2, 8, 9, -3, + -1, 0, 7, 3, 8, -1, -4, -1, 1, 3, -9, -1, -17, -3, -2, -4, + -4, -3, -4, -6, -11, -15, -2, -5, 6, 10, 1, 3, -1, -3, 13, 7, + 1, 6, 4, 4, 9, 5, -3, -5, 9, 3, 5, -3, 1, -3, 3, 0, + -7, -5, -7, 0, -5, 0, -1, -15, -11, -4, -5, -10, 2, -7, 5, -4, + 1, -9, 2, 1, 8, 7, 10, 2, 2, 0, 4, 3, -2, 0, 4, 2, + 6, 8, -2, 4, 4, -2, 5, -3, -6, 3, -3, -5, -9, -8, -11, -5, + -1, -1, -5, -7, -5, -8, 0, -3, 5, -7, 11, 1, 0, 2, -3, -1, + 3, 9, 6, -3, 8, 1, 11, 2, 8, -3, -3, 6, 2, 1, 2, -7, + -3, -2, -4, -8, -3, -3, 5, -10, -10, -4, -12, -2, 3, -5, 3, -6, + -8, -2, 5, -3, 0, 1, 4, 8, 4, 5, 0, 4, 8, 1, 7, -3, + 0, 3, 4, 4, -5, -2, -7, -3, 0, 5, -5, -9, 3, -2, -1, -2, + -5, -1, -4, -3, -11, -4, -5, -6, 0, 5, 0, -5, 5, 3, 8, -1, + 3, 3, 2, 5, 7, -4, 3, 1, 3, 10, 2, -7, 1, 0, 6, -4, + -3, -5, -7, -2, -4, -3, -6, 0, -10, 4, -6, -4, -7, -2, 1, -4, + -1, -3, -1, 2, 6, 2, 4, -2, 2, 4, 2, 5, -3, 4, 2, 1, + 0, 8, -3, 2, 5, -5, 3, -5, -2, 5, -5, 3, -1, -4, -3, 4, + -10, -5, -7, -4, -4, 0, 0, -7, -1, -1, 2, 1, -2, -12, -4, -1, + 0, 4, -5, 2, 0, 3, 12, 11, 3, 11, -1, -3, 6, -6, 1, 1, + 7, 6, -7, -1, -7, -4, -4, -7, -8, -1, -6, -6, -2, -3, -5, 0, + -4, 8, -7, 1, 4, -3, 6, 1, -7, 3, 5, 6, 5, 13, 2, 2, + -4, 4, -3, 1, 4, -4, 2, -3, -10, -10, -7, -2, -2, -2, 0, -6, + -2, 1, -3, -4, -2, -5, -2, 7, 1, 6, -5, 6, -1, -1, 2, -3, + 4, 11, 2, -1, 2, -7, -5, 8, 0, 3, -3, -5, -1, -2, 3, 1, + -4, 4, 7, 0, 2, 3, -3, 0, 1, -5, -15, -5, -3, 1, 3, -3, + -11, -4, -7, 1, -2, -1, -1, 0, 1, 1, -5, -1, 3, -2, 7, 1, + -4, -1, 0, 4, 5, 3, 3, -1, 8, 11, 1, 4, 1, -5, 7, -6, + -4, -2, -4, -2, 3, -8, -3, -13, -6, 3, -3, -7, -4, -7, 3, 3, + -3, 2, -1, 1, -4, -2, -2, -5, 1, 11, 9, -2, 6, -3, 7, 7, + 1, 1, -7, 2, -3, 1, 4, -4, -4, 5, 1, 0, -3, -6, 2, -3, + 0, -8, -12, -6, -2, -3, 6, -1, -9, 0, -1, 1, 3, -2, -1, 0, + 1, 6, 0, -3, 5, 1, 6, 1, -1, 4, 1, 7, -3, -1, -1, -4, + 4, 14, -1, -1, 2, -4, -1, -6, -8, -8, -3, -2, 2, -9, -5, -7, + -12, 5, 0, -3, -4, -3, 5, 4, 3, -2, -6, 4, 7, 3, 5, 7, + -3, 8, 0, -5, -1, -1, 11, 10, 3, 4, -8, -3, -3, 1, -3, 0, + -4, -3, 1, -7, -8, -16, -7, -6, -2, 3, -7, -2, 1, -4, 0, -5, + -5, 1, 5, 10, 5, 0, 3, 0, 1, 13, 0, 5, 9, 6, 8, -1, + -4, 0, -3, 6, 4, -4, 0, -3, -15, -2, -12, -15, -3, -6, 2, 1, + -3, -4, -9, -9, -3, -3, -2, 3, 4, 9, 0, 2, 1, 2, 14, 5, + 3, 8, 2, 7, 4, -4, -4, -1, -9, 9, -5, -1, -7, -10, -2, -7, + -4, 0, -5, 2, 5, 1, 0, -5, -5, -1, -1, -3, 4, -8, 5, 3, + -4, 4, -5, -3, 9, 4, 8, 0, 0, 2, 0, -2, 0, -2, -7, 12, + -1, 5, -4, 2, -3, 0, 2, -2, -4, -2, 2, -5, 3, -7, -9, -4, + -3, -2, -6, -6, -2, -6, -1, -7, -8, 1, 3, 6, 10, 4, 5, 0, + 5, 8, 1, 3, 8, 5, 11, 12, -7, 4, 0, -3, 2, -1, -8, -7, + -4, -2, -6, -9, -6, -13, -4, -1, 0, -9, -5, -3, -4, -2, 3, 1, + 1, 9, 4, 2, 6, -1, 3, 6, 2, 0, -3, 3, 2, 6, 3, -1, + -4, 4, 1, 2, 2, -5, -8, -1, -3, -1, -9, -4, 1, -5, 5, -7, + -4, 0, 3, -10, 3, -3, -5, 1, 5, 4, 1, -5, 1, -5, 4, 1, + -6, 0, 5, 8, 8, 1, 6, 0, 3, 4, 2, -3, 1, -3, -3, 3, + -10, -6, -8, -2, -1, -3, -6, -6, -5, -6, -6, -5, 5, -3, 5, 6, + -2, -1, -1, -4, 6, -2, 6, 6, 2, 12, 8, -2, 3, -6, -2, 5, + 4, -3, -2, -5, -4, -7, -6, 1, -5, 2, 2, 0, 1, -7, 0, -4, + -2, -1, -2, -5, 7, -5, -2, -3, -2, -3, 4, 4, 9, 0, 1, 1, + -5, -3, -4, -4, 4, 3, 6, 1, -2, -2, -7, 4, 1, 1, -3, 3, + -1, 2, 0, -7, 0, 0, -1, -3, -2, -1, -5, -2, -3, -8, -5, -5, + -1, 5, 5, 2, 2, -3, 4, 3, 4, 6, 3, -1, 10, -4, -3, -2, + -3, 0, -4, 0, -2, -2, 0, 2, -5, -2, -5, -9, 8, -2, -1, -1, + -3, -3, -2, -6, 2, 1, 2, 9, 0, 1, 4, -5, 2, 4, -6, -1, + 2, -1, 6, 3, 0, -5, -3, -1, 0, 3, -3, 0, -6, -2, -3, -4, + -2, 0, 3, 2, 2, 0, -10, 1, -6, -5, -1, -2, 5, 3, 6, -2, + -6, -1, -3, 2, 4, 1, -1, 0, 1, 1, 3, -1, 5, -1, 7, 6, + 1, -2, 0, -6, -2, -2, -8, -2, -2, -3, -5, -5, -8, -3, -1, 5, + -3, 1, 2, 1, 2, -3, -2, -3, 2, 6, 2, 6, 0, 0, -2, 9, + -1, 3, -2, 3, 0, 0, 0, -6, -6, -1, -5, -7, 1, -3, -6, 2, + -2, -1, -5, -2, 1, 4, 2, 2, -3, -1, 6, -2, 2, 4, -3, 2, + 2, 2, -3, 1, 0, -4, 2, -1, -2, 3, 1, 1, -1, -5, -8, -2, + -5, 0, 1, -6, 3, -4, 2, 3, -6, 3, 0, 2, -2, -1, -4, -2, + -4, 4, 0, -3, 0, -6, -3, 10, -3, 3, 0, 4, 7, 3, 0, 5, + 1, 5, 1, -3, -2, 0, -6, 3, -1, -7, -5, -7, -1, -2, -2, -2, + -3, -2, 2, -2, -1, -3, -3, 2, -2, -6, -3, -3, 4, 3, 2, 0, + -1, 5, 5, 8, 2, 2, -2, 4, 0, 5, -5, -3, -1, -3, -3, -6, + -4, -2, 3, 0, -2, -2, -5, 5, -1, 3, -1, -1, -3, 0, 0, -5, + -4, -3, -2, 5, 0, -4, -4, 1, 2, 6, 0, -3, -1, 2, 3, 7, + -3, 0, -4, -2, 4, 3, 0, 1, 3, -3, 1, -7, -4, 0, 1, 1, + -4, -4, -4, -9, -1, -2, -3, -2, -3, -3, 4, 3, -1, -4, 2, 4, + 4, 3, 2, -1, 0, 9, -1, 4, 2, 7, -1, 6, -2, -2, -5, -1, + -9, -2, -2, -6, -1, -1, 1, -8, -6, -5, -1, -1, 1, -4, -5, 3, + 1, 5, 3, -3, 0, -2, 7, 0, 1, -2, 3, -1, 5, -1, -5, 7, + -1, 3, 2, -5, -6, -2, 4, 2, -1, -3, -1, -1, -1, -1, -2, -4, + 1, -5, 3, -1, -3, -5, 2, 6, -6, -1, -5, -4, 4, -1, -1, -2, + -1, 2, 0, 3, 1, 4, 2, 7, -1, 2, 0, -2, 1, 4, -5, -3, + -7, -2, 0, -1, -1, -3, 0, 0, -2, -6, 2, -4, 2, -4, 1, -7, + -2, -1, 5, 3, -2, -7, -4, 1, 6, 4, 5, 1, 4, 0, 5, 1, + -1, 2, 0, -3, -3, -5, -6, 3, -1, 5, -1, -2, 1, 1, 4, 2, + -6, -3, -4, -3, 2, -2, -8, -3, -6, -4, -2, -11, 0, 0, 1, 6, + -3, -2, 1, 2, 10, 8, 4, -2, -1, 2, 2, 1, -2, 3, 1, 5, + 3, -1, 0, -4, 4, -7, -2, -7, -8, -4, -3, -2, -7, -7, -3, -1, + 5, -2, 0, -7, 2, -1, 3, 1, 4, 6, 5, 8, 3, 2, -1, 3, + -3, 0, 0, -5, -1, 1, 1, -5, -3, -2, 6, 4, 5, -4, -8, -4, + -3, -2, -5, -4, -4, -4, 2, -3, -2, -4, -4, -4, 6, 1, 0, 1, + 3, 3, 5, 2, 1, 0, 6, 2, -1, 1, -3, -3, 2, -1, 0, 1, + 3, 1, 4, -4, -5, -10, -8, 1, -6, -3, -4, -6, -3, 0, 2, -3, + -1, 2, 0, 8, 1, 4, 4, 3, 6, 3, 1, 3, 5, 1, 2, -4, + -7, -3, -3, 3, 0, -7, -5, 0, -3, -1, -2, -4, 0, -5, 1, -6, + -1, -5, -3, 1, 4, -1, -3, 3, 3, 5, -1, -2, 2, -1, 2, 1, + -1, -5, 5, 1, 2, 2, -4, 0, -1, 3, 0, -2, -1, 2, 1, 5, + 4, -3, -5, 0, -2, -2, -6, -3, -3, -4, -1, -5, -4, -1, -2, 0, + 2, -2, -6, -3, 1, 1, 1, -1, 3, 4, 7, 2, 3, 4, -1, 7, + 2, 3, 1, -1, 1, -2, 0, -4, -5, -6, 0, -2, -7, -2, -5, -5, + 1, -4, -5, -5, 3, -1, 1, 2, -2, 0, 1, 4, 1, -4, 2, 2, + 0, 9, 2, 0, 4, 3, 1, 2, -4, -2, -4, 3, -4, -2, -6, 0, + -1, 5, 2, -4, 0, -4, -4, -1, -5, -4, -7, -3, 1, 0, -2, -1, + -5, 1, 0, -1, 0, 2, 4, 0, 3, -2, 1, 2, 6, 0, 1, 5, + 0, 3, 3, 2, -5, -2, 1, 5, 2, -2, -5, -9, 0, -6, -1, -6, + -7, -5, -4, 0, -2, -5, -3, 2, -2, 3, 2, 0, 9, 2, 0, 4, + -3, 4, 5, 8, 6, -2, -4, -1, 0, -2, -2, 1, -5, 2, -5, -1, + -4, -3, -4, 0, -2, -7, -3, -1, 0, -1, 0, -6, 3, -2, 5, 2, + -1, -2, 1, 0, 1, -1, -3, 2, 3, 1, 2, -4, -3, -1, 5, 5, + 3, -4, 0, 1, 2, 5, -5, 1, -5, 2, -2, 2, -4, -3, 0, -4, + -3, -9, -7, -4, 2, -2, 1, -6, -3, 0, 1, 5, 1, -5, 0, 0, + 2, 1, 2, 0, 6, 4, 6, 3, 2, 3, 1, -2, -2, -9, -4, -1, + 4, 0, -1, -5, -8, -5, -4, 0, -4, -1, -3, 0, 0, -4, -3, -1, + 1, 2, 0, -2, -3, 1, 3, 2, 3, 3, 0, 8, 2, 7, -1, 3, + -2, 4, 0, 0, 1, -4, 5, -1, -3, -3, -6, -4, 2, 1, -5, -4, + -7, -4, -4, -7, -2, -10, 1, 0, 1, -3, 4, -2, 5, 2, 1, -3, + -1, 2, 8, 4, 5, 0, 1, 4, 5, 2, 2, -2, 1, -4, 0, -3, + -3, -1, 0, 2, -4, -4, -5, -1, -7, 0, -4, -5, -1, -3, 2, -2, + 0, 3, 0, 2, 0, 1, -2, 2, 4, -1, 0, -3, -1, 1, 3, 2, + -3, 2, 0, 2, 2, -1, 2, -2, -3, 0, 0, -2, 2, -2, 4, -3, + -6, -7, -6, 2, -1, -4, -1, -7, -1, -3, 3, -1, 0, -2, 2, 2, + -3, 3, -4, 5, 7, 6, 3, 1, -1, 6, 2, 1, 0, -1, -1, 1, + -3, 1, -3, -5, -5, -3, -8, -3, -11, -1, -1, 0, -8, -2, -5, 3, + 4, 0, 1, -2, 2, 0, 6, 4, 1, 4, 1, 5, 0, 0, 1, 2, + 5, 0, 1, -10, 0, -5, 2, 0, -6, -6, -2, -2, 2, -3, 0, -4, + 2, -4, 1, -3, -4, 1, -2, 2, 1, -2, 0, 3, 2, -3, -1, -5, + -3, 4, 2, 3, -1, 4, 1, 5, -1, 2, -3, 2, -3, 0, -3, -2, + 1, 1, 5, 1, -2, -5, 1, -1, -4, -3, -7, 0, -5, -4, -4, 0, + -4, 4, 0, -1, 1, -8, 1, 0, 9, 1, 2, -2, 5, 5, 1, 6, + -1, 6, 3, 1, 1, -2, -2, -4, -3, -2, -3, -7, -4, -4, -1, -3, + -8, -1, -8, 4, -5, 0, -3, 1, 0, 4, -1, 0, 1, 3, 3, 4, + -4, 6, -2, 2, 5, 4, -3, 4, -3, 5, 0, -4, 0, 0, -1, 0, + -4, -4, 3, -1, -2, -4, -8, -9, -5, -4, 4, -4, 1, -4, 1, 1, + -1, -1, -1, 3, 2, 3, 0, 1, 2, 1, 5, 3, 1, 0, 5, 3, + 3, 0, -5, -4, -2, 5, 0, -2, -5, -2, -6, -2, -5, -8, -2, 1, + -1, -3, -7, -8, -6, 0, 4, 7, -2, 7, -1, 7, 3, 2, -5, 0, + 2, 0, 1, -3, 2, 2, 3, 3, -3, 0, -2, 3, -1, -1, -4, -6, + -2, -3, 4, -4, 0, -4, 6, -2, -6, -2, -7, 1, 2, -1, -3, -2, + -2, 3, -1, 0, -3, -1, 4, 7, 4, 0, 2, -1, 0, 6, -2, 1, + 1, 5, 4, 1, -3, -3, -2, 2, 2, 1, -6, -6, -3, -4, -2, -6, + -5, -4, -5, -2, -8, -8, -3, 0, 4, 0, 1, -1, 2, 5, 4, 2, + 2, 3, 3, 4, 10, 0, 2, 0, 3, 1, 1, 0, -3, 1, -3, 1, + -7, 0, 1, -2, 1, -6, -4, -10, -1, -4, -2, -2, -3, 2, -4, 1, + -5, -4, -4, 2, 1, 1, -4, -1, 3, 1, 6, 2, -2, -2, 3, 3, + 2, 7, -5, 5, 0, 8, 1, -1, 2, 3, -1, -6, 0, -10, 3, -1, + -1, -5, -6, -8, -2, 0, -3, -5, -8, -4, 2, -3, -1, -2, 0, -1, + 7, -1, 3, 2, 4, 7, 3, 4, -1, 5, 1, 9, 1, -2, -1, -1, + 1, -3, -2, -6, -7, 1, -3, -1, -9, -4, -6, 0, 2, -3, -2, -4, + -3, 0, -4, -1, -4, 0, 1, 6, -1, 1, -1, 3, 5, -1, 3, 4, + 5, 7, 4, -2, 0, -2, 0, 3, 1, -1, -8, -2, -1, -2, -5, -1, + -2, -2, 2, -5, -7, -9, -2, -3, -2, 1, -5, 4, -4, 5, -1, -1, + -3, 2, 3, 7, 3, -1, 3, 4, -1, 5, -4, 0, 4, 4, 3, 4, + -9, 1, -5, 2, -2, -2, -3, -7, -1, -2, -2, -5, -3, -1, 1, -2, + -1, -4, -4, 1, -1, -7, 0, -1, 2, 5, 4, -4, -5, -4, 0, 2, + 1, -1, 3, 5, 4, 0, 0, -1, 3, 8, 3, 3, -4, 0, 1, 0, + -2, -6, -2, -4, 3, -2, -3, -5, -6, -3, -1, -1, -7, 0, 0, 3, + -5, -4, -11, 0, 0, 3, 3, 1, 1, 1, 4, 6, 1, 1, 2, 9, + 3, 3, -4, -4, -3, 2, -1, -6, 1, -5, 2, 0, -1, -8, -5, -6, + 1, 0, -2, -1, -2, -1, 2, 0, -9, 0, 5, 4, 7, -3, -3, 3, + 4, 2, 4, 0, -1, 3, 1, 5, -5, -6, -7, 0, 3, 0, -2, -4, + 3, 3, -3, -4, -7, -2, 4, 1, -1, -4, -1, -6, -2, 3, -2, -3, + 1, 4, 1, -1, -4, -3, 3, 4, 5, -2, 2, -3, 4, 0, 3, -3, + -3, 0, 3, 1, -2, -1, -3, 2, 4, -2, -2, -3, -1, -1, 3, -11, + -2, -8, 5, -1, 3, -5, -2, 2, -1, 3, -3, 0, -1, -1, 5, -2, + 0, -2, 3, 2, 3, -2, -6, -3, 2, 4, -6, 5, -6, 1, 2, 3, + -6, 2, -3, -4, 3, -9, 2, -6, 3, 4, 2, -9, -1, 1, 2, 8, + -3, -4, -1, -2, 2, -2, 2, -3, 3, -1, 1, 2, -1, -6, 1, 2, + 2, 1, -2, 2, 3, 1, -3, -6, -3, 0, 1, -3, 0, -3, -1, -4, + 2, -4, -3, -1, 4, 0, 5, -6, -7, -1, 0, 0, -3, -1, 2, 4, + 0, 3, -4, -1, 1, 7, 4, 2, -1, -4, 0, 2, -4, -5, -5, -1, + 1, 4, -5, -4, -6, -3, -2, -3, 2, -2, 5, 2, 3, -4, -2, -5, + 6, 3, 4, 2, -3, 1, 0, 0, 1, -3, -1, 1, 7, 0, 6, -6, + -7, -2, -7, 0, -1, 0, 2, 1, -2, -7, -2, -5, 0, 2, 0, -3, + -5, -1, -3, 0, -1, 0, -6, 8, 4, 5, -1, 1, -4, 1, 1, 4, + 2, 5, 3, 6, 0, -2, -9, -4, -1, 0, 0, 1, -1, -4, -1, -5, + -5, -5, 0, 0, 1, -6, -5, -9, 0, -3, 0, -2, 0, 0, 3, 4, + 2, 1, -7, 1, 3, 4, 9, 1, 4, 4, 2, -4, 2, -2, 1, 5, + -2, 0, -3, -4, -3, -2, -4, -4, -4, 1, -1, 2, -6, -8, -3, -8, + -1, -2, -4, 5, 2, 3, -1, 0, -4, 2, -1, 5, 5, -1, 3, 0, + 3, 3, 0, -4, 9, 4, 2, -1, -6, -4, -2, -2, 2, -7, 0, 0, + -2, -2, -2, -10, -4, -7, 0, -2, 2, -2, 2, 1, 0, -3, 0, 1, + 6, 3, 2, 0, 0, -1, 2, 3, -1, 4, -5, 6, 2, -3, 0, -3, + 0, 1, 0, -5, -6, 1, 0, 1, -5, -2, -14, 0, -4, -1, -1, -1, + 1, -3, 0, -2, -1, -4, 4, 5, -1, 5, -1, 3, 3, 5, -3, 5, + -3, 5, 5, 6, 4, -6, 2, -9, 4, -4, 0, 1, -2, -1, -8, -6, + -11, -2, -3, 3, -6, -8, 3, -5, 1, -3, 1, -3, 1, 3, 5, 6, + 2, 1, -6, 4, -1, 1, 0, 7, 7, 2, 3, -6, -4, -4, 3, 3, + 0, 1, -1, -2, -4, 0, -8, -2, -3, 1, -2, 1, -5, -2, -1, -3, + -3, -4, -3, 7, 4, 1, -1, -6, -5, -3, 2, 5, 8, 3, 3, 2, + 1, -4, -1, -2, 6, 3, 2, -4, -1, 1, -5, -1, -1, -5, 2, -2, + 1, -2, -7, -5, -11, -4, -3, 3, -8, 8, 4, -2, -2, -4, -4, -1, + 4, 3, 5, 5, 2, 4, -1, 6, -3, 6, 2, 3, 0, -4, 0, -2, + -2, 0, -5, -2, -1, 4, 3, 1, -13, -8, -8, -5, -3, 7, -2, 3, + -2, -5, -3, -8, -2, -3, 8, 6, 1, -2, 5, 3, 1, 2, 0, -1, + 2, 4, 3, -5, 1, -3, 0, 1, 7, 1, 2, 3, -1, -4, -4, -10, + -7, 3, 0, 2, -5, -5, -4, -1, -7, -3, -3, 1, 3, 0, 0, -1, + -6, 6, 1, 4, 1, 2, 5, 6, 4, -1, -4, -3, 1, 2, 5, 2, + -1, 1, 3, -8, -1, -10, -2, -5, 0, -1, -6, -10, -7, 2, -2, 6, + -1, -2, 1, 4, -1, -5, -1, -5, 4, 1, 4, 2, 1, 3, 4, 0, + -2, 1, -1, 3, 8, 2, 1, -4, -3, -3, 3, -3, -1, -4, 0, -4, + -6, -2, -8, 1, -2, 5, -6, -5, -6, 0, 3, 1, -6, -3, 1, 2, + 4, 2, 4, -2, 3, 3, 3, 1, 5, 1, 2, 3, -2, -6, 6, -1, + 6, -2, 1, -7, -5, -2, -3, -6, -6, -6, -4, 0, -2, -4, -4, -3, + 0, -1, 1, -3, -1, 3, 1, 1, 0, 6, 4, 8, 10, 5, 0, -3, + 1, -2, 5, 2, 1, 1, 1, -4, -6, -8, -8, -8, -5, -4, -5, -4, + -5, 0, -5, -3, 0, -7, 0, 4, 1, -4, -1, -4, -2, 4, 4, 5, + 6, 6, 7, 0, 0, -1, 0, 2, 9, 2, 1, -3, 0, 1, -3, 1, + -9, -1, 3, -4, 3, -6, -7, -2, -1, -1, -1, 1, -9, 2, -5, 1, + -8, -6, -6, 1, -1, 6, 0, 2, 5, 2, 0, 2, 1, 2, 6, 5, + -2, -1, 0, 4, 1, 6, 0, -2, 1, 0, 3, -7, -1, -13, -4, -3, + -3, -3, -2, -3, -5, -9, -11, -2, -3, 4, 7, -1, 2, 0, -2, 8, + 5, 1, 4, 3, 2, 7, 3, -2, -4, 7, 2, 3, -2, 1, -1, 2, + 0, -5, -4, -4, 0, -4, 0, -1, -10, -9, -3, -5, -8, 1, -5, 3, + -3, 0, -7, 1, 0, 5, 4, 7, 1, 1, 0, 2, 2, -2, -1, 2, + 1, 4, 6, -1, 4, 3, -1, 4, -2, -3, 3, -1, -2, -6, -6, -7, + -3, -1, 0, -4, -6, -5, -6, 0, -3, 3, -5, 7, 0, -1, 1, -3, + -1, 1, 6, 3, -3, 7, 1, 10, 1, 6, -1, -2, 5, 2, 1, 1, + -4, -2, 0, -3, -7, -2, -4, 4, -8, -8, -4, -10, -2, 2, -4, 1, + -5, -7, -1, 3, -1, 1, 1, 4, 6, 2, 2, 0, 4, 7, 0, 5, + -2, 0, 3, 3, 3, -3, -1, -5, -2, 0, 3, -4, -6, 2, -1, 0, + -2, -4, 0, -4, -3, -9, -3, -4, -4, 0, 3, -1, -4, 3, 1, 5, + -2, 1, 2, 2, 4, 5, -3, 2, 1, 3, 7, 1, -5, 1, 0, 5, + -3, -2, -3, -4, 0, -3, -2, -5, 0, -8, 3, -6, -4, -6, -2, 2, + -4, -2, -3, -2, 1, 4, 2, 3, -2, 2, 4, 1, 4, -2, 3, 2, + 1, 1, 7, -1, 2, 4, -4, 2, -4, -2, 5, -4, 3, -1, -3, -2, + 3, -8, -4, -6, -3, -3, -1, 0, -6, -1, 0, 1, 1, -2, -10, -3, + -1, 0, 2, -5, 1, 1, 2, 10, 8, 2, 8, -1, -2, 4, -5, 2, + 2, 7, 6, -6, -1, -5, -4, -3, -6, -7, 0, -5, -5, -1, -2, -5, + 0, -4, 6, -6, 0, 3, -3, 4, 0, -6, 2, 5, 5, 4, 10, 0, + 2, -3, 3, -2, 0, 3, -3, 2, -3, -8, -8, -5, -1, -1, -1, 0, + -5, -2, 0, -3, -4, -1, -5, -2, 5, 0, 5, -4, 4, -1, -1, 1, + -3, 3, 9, 2, -1, 1, -6, -3, 7, 1, 3, -2, -4, 0, -1, 3, + 1, -3, 4, 6, 0, 1, 2, -3, 0, 0, -5, -13, -4, -2, 1, 2, + -3, -10, -4, -7, 1, -2, -2, -1, 0, 1, 1, -4, -1, 2, -2, 7, + 1, -3, 0, 0, 4, 5, 2, 2, -1, 6, 9, 1, 3, 1, -5, 5, + -6, -5, -2, -4, -2, 2, -7, -4, -11, -5, 3, -3, -6, -4, -6, 3, + 3, -3, 2, 0, 1, -3, -1, -2, -4, 1, 10, 8, -2, 4, -3, 6, + 6, 1, 0, -7, 2, -2, 1, 3, -4, -4, 4, 1, 0, -2, -5, 2, + -2, 0, -7, -11, -5, -2, -2, 5, -1, -8, -1, -1, 1, 2, -2, -1, + 1, 1, 5, 0, -3, 5, 1, 6, 1, -1, 3, 1, 6, -3, -1, -1, + -3, 4, 12, -1, -1, 2, -4, -1, -6, -8, -7, -3, -2, 1, -9, -5, + -6, -10, 5, 1, -2, -3, -2, 5, 4, 3, -1, -5, 4, 6, 3, 4, + 6, -2, 7, 0, -4, -1, -1, 9, 8, 2, 2, -8, -3, -3, 0, -2, + 0, -4, -2, 0, -6, -7, -14, -6, -5, -1, 3, -6, -2, 1, -3, 0, + -4, -5, 1, 5, 9, 4, 0, 3, 0, 1, 12, 0, 4, 8, 5, 7, + -1, -4, 0, -3, 5, 4, -4, 0, -3, -13, -2, -10, -14, -3, -5, 2, + 1, -3, -4, -8, -8, -3, -2, -2, 3, 4, 8, 0, 2, 1, 2, 12, + 5, 3, 8, 2, 6, 3, -4, -4, -2, -8, 8, -5, -2, -6, -10, -2, + -6, -4, 0, -4, 2, 5, 1, 0, -4, -4, -1, -1, -3, 4, -7, 4, + 3, -3, 4, -4, -3, 8, 4, 7, 0, 0, 2, -1, -2, -1, -2, -7, + 11, -1, 5, -4, 2, -2, 0, 2, -2, -4, -2, 1, -5, 3, -6, -9, + -3, -3, -2, -5, -5, -2, -6, -2, -7, -8, 1, 3, 5, 9, 4, 4, + 0, 5, 8, 1, 3, 7, 5, 10, 11, -7, 3, 0, -3, 1, -1, -7, + -7, -3, -2, -6, -9, -6, -12, -4, -1, 0, -8, -5, -3, -3, -2, 3, + 1, 1, 9, 4, 2, 5, -1, 2, 6, 2, 0, -3, 2, 2, 5, 2, + -1, -4, 4, 1, 1, 2, -5, -8, -1, -3, -1, -9, -4, 1, -4, 5, + -6, -4, 0, 3, -9, 3, -3, -5, 1, 4, 4, 1, -4, 1, -4, 4, + 1, -6, 0, 5, 7, 8, 1, 6, 0, 3, 4, 2, -3, 1, -3, -3, + 3, -9, -6, -7, -2, -1, -3, -5, -6, -5, -5, -6, -5, 4, -3, 5, + 5, -2, -1, -1, -3, 6, -2, 5, 6, 2, 11, 8, -1, 3, -6, -2, + 5, 4, -3, -3, -5, -3, -7, -5, 0, -5, 2, 1, 0, 1, -7, 0, + -3, -2, -1, -2, -5, 7, -4, -2, -3, -2, -3, 4, 4, 9, 0, 1, + 1, -5, -3, -4, -4, 4, 3, 6, 0, -2, -2, -6, 4, 1, 1, -3, + 3, -1, 2, 0, -7, 0, 0, -1, -3, -2, -1, -5, -2, -3, -8, -5, + -5, -1, 5, 5, 2, 2, -3, 4, 3, 3, 6, 3, -1, 10, -4, -3, + -2, -3, 0, -4, 0, -2, -2, 0, 1, -4, -2, -5, -9, 8, -2, -1, + -1, -3, -3, -2, -6, 2, 1, 2, 9, 0, 1, 3, -4, 2, 4, -6, + -1, 2, -1, 6, 3, 0, -5, -3, -1, 0, 3, -3, 0, -6, -2, -3, + -4, -2, 0, 3, 2, 2, 0, -10, 1, -6, -5, -1, -2, 5, 3, 6, + -2, -6, -1, -3, 2, -1, 0, 0, -1, 0, 0, 0, 1, -2, 2, -2, + -5, -1, -2, 16, 12, -18, -10, 3, -14, -10, 16, -1, -3, -16, 28, 3, + -1, -1, 12, -5, -6, 6, 7, -7, -18, -28, 11, 0, 6, -2, 26, -21, + -10, -1, 24, -3, 20, -19, 15, -14, -3, -3, 15, -35, -2, 6, -14, 30, + 6, -36, -8, 17, 0, -27, 26, 16, -38, 8, -14, 57, 3, -31, -14, 34, + -20, 33, 2, -6, -7, -28, 20, -24, 8, 13, 8, -39, 17, 40, -42, -11, + 13, -46, 1, 28, -22, 11, -3, -14, 5, 20, -12, -4, 49, -22, -24, 39, + -11, -1, -9, 37, -30, 13, 34, 4, -11, -25, 18, -22, 1, 29, -17, -3, + -26, -16, -21, 12, -18, 7, -17, -6, 51, 0, -21, 10, 24, -45, 8, 14, + 31, -10, -37, 6, 0, 24, 3, -18, -13, 14, 11, 0, 7, -1, -38, -29, + -21, 32, -30, 22, -26, 14, -40, 55, -36, 30, -12, 8, 31, -16, 19, -15, + 23, -48, 36, 1, 63, 3, 24, 0, -3, 14, 26, -21, 15, 47, -21, -80, + 14, -4, -25, -33, 11, 25, -35, -44, 13, -2, -48, -11, -23, -7, 27, -4, + -15, -22, 5, 26, -36, 50, 23, 11, -23, -14, 19, 32, 14, 38, -66, 56, + -11, 26, 18, -12, 17, -30, -6, -54, 22, 77, -62, -12, -16, 34, -25, 2, + 14, -62, 12, 20, -22, -50, 58, -29, -58, 4, 28, 30, 13, 25, -78, 38, + 45, -19, -7, 52, -61, 27, 17, -21, -4, 6, 37, -24, -38, 73, 8, -16, + 21, -2, -15, -19, -19, 18, 3, 7, -48, -10, -10, 10, 4, 13, -13, -4, + 0, 46, -12, 6, -18, -25, 4, 14, 27, -22, -37, 14, -6, -17, 55, 40, + -111, 63, 9, -38, -16, 46, -35, 4, 0, -10, -8, -12, 58, -69, 1, 66, + -38, 21, -33, -6, 10, 0, 10, -11, 18, -16, 32, -7, -10, -25, 65, -42, + 42, -62, 18, -3, -2, -8, 21, 4, -71, 13, 40, -3, 18, -19, -29, 15, + -66, 60, -50, -6, 67, -80, 17, 66, -21, -20, -15, 68, -16, 72, -4, -23, + 4, 53, -8, 8, -4, 0, 27, -26, -22, 25, -31, 7, -39, -18, 27, -43, + -25, -33, -6, 17, -16, 0, -55, 6, 26, -3, -67, 7, 60, -83, 25, 15, + 45, -8, 51, -55, 28, 42, 42, -17, 37, -6, 17, 8, 11, -1, 59, -7, + -45, 14, -41, 107, -49, -50, -25, 63, -58, -27, -57, 19, 13, -13, -27, 19, + -42, 63, -113, -1, 44, 8, 1, -10, -33, 0, 55, -41, 15, 0, 76, -17, + -39, 60, -20, 28, 54, -93, 15, 83, -30, 4, -56, 49, -58, 30, -28, 2, + 54, -64, 83, -128, 86, 24, -40, -27, -66, 51, 11, -51, 59, 6, 20, -58, + -24, 78, -7, -23, -27, 1, -3, -24, 10, -6, -16, 34, 39, -37, -17, 26, + 52, -69, -7, 11, 24, -62, 38, -13, 41, 5, -2, -5, -12, 15, 77, -49, + -10, 74, -12, -11, -38, 32, -24, 25, -6, 19, -24, -2, -38, 63, -91, 64, + -27, -11, -56, -43, 27, -41, -55, -15, 1, -4, 27, 8, 37, -57, 3, 28, + -11, -4, 46, -39, 3, 12, 100, -33, 39, 17, 6, 49, 5, 38, -12, 10, + 21, -35, 23, -6, -36, 10, -9, 3, -1, 13, -65, -40, 36, -25, -28, 5, + -37, -20, -14, 31, -16, -32, -16, 4, 15, -11, 26, -16, 29, -42, 46, 7, + 39, -1, -5, -9, 33, -31, 35, -33, -7, 17, 56, -24, 22, 14, -22, -34, + 44, 16, 11, -46, 43, -48, -27, 43, 36, -45, 21, 11, 0, -98, -22, 87, + -126, 52, -45, 34, -28, -17, -31, 23, -38, 23, 25, -11, 25, -63, 21, 13, + 19, 47, 28, -23, 20, 21, -5, -14, 112, -30, -67, 37, 43, -12, -57, 34, + -9, -29, 52, -19, 14, -51, 0, 26, -69, 3, -18, -24, -34, 31, -15, -33, + -36, 10, -20, -38, 63, 0, 44, -50, 72, 25, -16, -6, 6, 15, 23, 31, + 3, -20, -9, 19, 63, 17, -18, -5, -12, -87, 31, 26, -37, -29, 49, -42, + -15, 14, 11, -16, -31, 46, -19, -13, -37, 59, -91, 47, 4, -11, -26, 39, + -29, -24, 48, 10, 39, -11, 45, -51, -1, -24, 47, -19, 39, -34, -29, -17, + 1, 56, -25, -16, -13, 0, 48, -71, 49, 2, -2, -45, -10, 59, -17, -25, + 9, 9, 44, 42, -32, -23, -49, 46, -11, -50, 76, -43, -45, -1, 41, -8, + 2, 71, -36, -61, 35, 21, -13, -36, 44, -45, 26, -45, -21, 28, -37, 39, + -29, 15, 4, -5, 24, -7, 7, 3, 68, -80, 26, 24, -22, 8, 26, 28, + 10, -26, -3, 16, -51, 85, -8, -14, -54, 39, -28, -9, -25, 46, -39, -20, + 34, 11, -25, -7, -12, -41, 12, -17, -5, -43, -8, 0, 18, 13, 9, 28, + -40, 34, 0, 13, 40, -20, 5, 22, -25, -13, 51, 9, -34, 43, -16, -18, + 2, 35, -4, -28, 14, -37, 6, -8, 31, -49, 9, -31, 61, -55, 35, -46, + -37, -12, 32, 74, -59, -30, -21, 5, 38, 3, 48, -35, -42, 2, 29, 81, + -8, -37, 24, 42, -31, 18, -11, -21, -67, 98, -18, 11, -26, -14, -76, 11, + 71, -70, 30, -52, 37, -45, 61, 6, -33, -44, 58, 24, -16, -51, 49, -28, + 51, -6, -15, 46, 10, -24, 36, -4, 6, -30, 46, -66, 54, 27, -16, -34, + -23, 90, -61, -49, 22, -3, -22, 17, -35, -11, -59, 23, 2, -25, 69, -24, + -26, -28, 37, 12, 11, -63, 27, 18, 3, 34, -25, 9, -14, 29, 4, 24, + 21, -77, 12, 14, 37, 1, 45, -63, 1, 49, -14, -23, -7, -4, -42, 48, + -57, 18, -36, 17, 15, -37, 47, 1, -41, -14, 11, 49, -32, 32, -36, -19, + 21, -11, 39, -31, 43, 0, -24, 15, 6, 9, -46, 5, 21, -23, 2, -28, + -15, 59, -13, -29, 50, -7, -45, -12, 23, -1, 27, 6, -17, 7, -4, -3, + -3, 53, -10, 17, -52, 19, 24, -8, -7, 19, -51, -30, 55, -22, -22, 29, + -38, -25, 39, 3, 34, -84, 26, -37, 42, 15, 4, -4, -16, -33, 29, 17, + 43, -93, 24, -6, -20, -14, 107, -29, -36, 69, -21, 10, -7, 74, -67, 38, + -23, -8, 27, -35, -49, 29, -8, -4, 7, -8, 5, -38, -28, -33, 22, 70, + -37, -10, -56, 26, 5, 7, 59, -21, -58, 10, -2, 6, 49, -16, -9, -38, + 60, 13, 43, -43, 23, -14, -9, 38, 17, -38, -15, 29, 6, -5, -11, -3, + -4, -65, 45, -13, 26, -13, -4, -5, -38, 48, 0, 4, -40, 40, -48, 23, + 21, 23, -42, 5, -17, 13, -9, 12, -3, 5, -25, 34, -24, -3, -18, 16, + -44, 13, 27, -30, 44, -54, 6, -18, -3, 4, 21, -25, -13, 22, -20, -12, + 37, -10, -10, 5, 24, -17, 23, 9, 0, 4, 3, 12, 26, -27, 17, 9, + -41, 69, -1, 15, -37, 15, -6, 0, -1, 3, -13, -23, -18, 27, -5, 21, + -16, -41, -2, 20, 13, -27, 6, -21, 8, 6, 0, 6, -5, -21, -22, 73, + -40, 4, 6, 21, -8, -5, 29, -47, -1, 1, 19, 3, -10, -1, 2, -48, + -11, 45, -27, 11, -33, -21, 21, 7, 12, -22, 21, -40, 13, 27, -20, 37, + 5, -18, -18, 35, 40, -11, 20, -25, 10, -4, 33, 12, -29, 9, -20, -30, + 34, 24, -9, -10, -24, -16, 8, 22, 6, -58, -5, -13, 18, 5, -43, 10, + -16, -25, 13, 70, -25, -7, -25, -19, 16, 58, -46, -5, 6, -5, 40, -24, + 22, 50, -73, -7, 7, 32, 39, -27, -23, -23, 56, -35, 21, 17, -40, 40, + -52, 4, 0, 49, -29, -42, 24, 9, 31, 2, -46, 0, -9, -5, 9, -31, + 64, -5, -45, -26, 42, -4, -34, -8, -3, 32, -15, -8, 22, -24, 13, -31, + -2, 31, 10, -10, -18, 8, 24, 20, -29, 2, 14, 23, 25, -4, -19, 20, + -25, -5, -3, 23, -8, 52, -42, -17, -7, 29, -26, 2, -19, 55, -50, -28, + 1, -10, -7, 7, -41, 16, 21, 1, -20, 0, 16, -19, 14, -39, 86, -17, + -34, -64, 73, 0, 20, -28, 30, -22, 9, 58, -4, -8, -18, -20, 31, -21, + 1, 26, -49, 5, 41, -25, -13, -6, -7, 6, 10, 42, -30, -26, -43, 11, + 44, -54, 31, -10, -11, -17, 25, 32, -43, 64, -23, 3, -37, 33, -30, -4, + -35, 47, -29, 9, 23, -34, -5, 64, -37, 32, -11, -44, 21, 25, -19, 8, + 6, -25, 34, 2, -18, -23, 38, 20, 7, 21, 1, -32, -37, 50, -9, -25, + 34, -61, 55, -32, 7, -48, 20, 13, 0, -35, 17, 9, -42, -28, 14, 42, + -33, -25, -5, 21, 41, -60, 32, -7, 38, -9, -3, 20, -4, 29, -69, 62, + -16, 35, -64, 45, 10, 5, -1, -18, -18, -1, 5, 32, 0, -21, -12, -23, + 29, -15, 13, -39, -3, -3, 6, 35, -24, -23, -7, -2, 44, -10, -37, 25, + 25, -25, -23, 7, 40, 4, -40, -18, 21, -2, -3, 1, -16, 45, -26, -2, + -16, 18, 41, -64, 8, -26, 40, 5, -32, 8, 18, -1, 15, -1, 9, 2, + 2, -13, -12, 35, -9, 13, -62, -29, 72, 18, 7, -30, 26, -7, -29, 39, + -38, 31, -56, -25, -3, 17, 2, -3, -46, 35, 6, 27, -39, -3, 3, 31, + -25, -19, -2, 38, 26, -77, 22, 18, 40, 3, -22, 65, -48, 33, -16, -37, + 78, -34, 1, -52, 23, 16, 1, -37, 17, 12, 1, -4, 8, -27, -1, -11, + -18, 27, -23, -10, -11, -19, -6, -7, 51, -74, 16, 20, 17, -14, 7, 7, + -13, -8, -5, -11, 39, 21, -5, -44, 31, 64, -38, -18, 20, 40, -4, -10, + 10, -23, 23, -6, -20, 11, 9, 10, 6, -23, -11, 1, 17, -56, 56, -40, + 0, -17, -60, 84, -80, 16, -13, 4, -25, 12, 17, -42, -26, 54, -29, 12, + -5, 37, 16, -62, 94, -5, -2, -2, -2, -9, 5, 51, -25, -5, -11, 5, + 16, -14, -9, 43, -44, -8, 27, 2, -1, 9, -18, -6, 5, 23, -46, -9, + 13, 16, -10, -10, -23, 59, -47, -14, 23, 29, -15, -14, -30, 21, -21, 0, + 14, -3, 25, -16, -35, -2, -8, 32, -19, 22, -23, -37, 30, -33, -19, 11, + 12, -32, 47, -4, 27, 11, 9, -35, 39, 29, -18, -2, -11, 27, -2, 13, + 0, 18, -26, 15, -25, 26, -4, 21, -29, -33, 18, -8, -31, -5, 21, -1, + -38, -28, 41, -18, -4, -22, 47, -12, -44, 55, -79, -5, 19, -10, 25, 4, + 21, 15, -28, 13, -6, 45, -24, 25, 10, -26, 4, 2, 31, 3, -7, 3, + 5, -23, 51, -9, -32, -5, 35, -32, -21, -20, 35, -40, -10, 20, -8, 7, + -5, -38, -1, -24, 39, -26, 20, -16, -9, -27, 25, 34, -32, 1, 12, -13, + 3, 37, 13, 3, -31, 27, 30, 5, -15, -21, 2, 10, -13, 16, 36, -9, + -59, 41, -10, 61, -60, -35, -11, 7, 5, -28, 30, 5, -23, -66, 34, 50, + -26, -19, -10, 11, 8, 8, -35, -5, -11, 56, -24, 10, 35, 16, -10, -19, + 30, 4, -11, 23, 0, -6, 6, 36, -15, 0, 15, -14, -26, -8, -5, 15, + -31, -45, 42, -30, 0, -9, 6, -22, 9, -22, 7, -8, 15, -19, -3, -13, + 29, -14, 9, -16, 3, -5, -10, 63, 0, 4, 4, 20, 16, -21, 18, 31, + -24, -19, 31, 54, -39, -7, -16, 5, -3, 0, -29, 16, 6, -29, -25, -52, + 49, -9, -66, -3, 50, -3, -2, -14, 4, -8, 33, -40, 2, 15, -6, -17, + -4, 10, 48, -16, 14, -9, 27, 10, 2, 2, 40, -35, 5, -10, 7, 28, + 1, 4, -30, -4, 0, 1, -14, -13, -11, 26, -17, 13, -44, -9, -6, -23, + 17, 11, 11, -21, -11, 0, 9, 8, 8, -30, 29, 10, -26, -12, 15, 17, + 4, -26, 14, 19, 20, -9, -24, 39, 23, -10, -35, 8, -6, 18, -25, 15, + -17, 41, -48, -31, -5, 47, -14, -20, -4, -7, 5, -19, 3, 21, 12, -23, + 15, -24, 8, 3, -25, 2, 28, 14, 21, 25, -72, 15, 26, -6, 45, -27, + 29, -30, -17, 23, 6, -2, 27, -46, 13, 9, 15, -57, 27, 1, -18, 1, + -11, -2, -20, -16, -23, 24, 18, -21, -5, -15, -14, 26, -12, 30, -48, 37, + -24, -3, 23, 9, -5, 9, 8, -43, 23, 26, 6, 28, -29, 30, -8, -12, + 25, -18, 33, -48, -4, 29, 1, -8, -4, -20, 41, -22, 1, 12, -33, 0, + -17, -16, 29, -3, -2, -36, 6, -1, -11, 4, -24, 40, -24, -5, 26, -2, + -28, 13, -11, 35, -9, -2, -3, -6, 13, 10, 1, 11, -22, 22, -27, -5, + 20, 11, -1, 8, -23, 8, 7, -7, 17, -6, 16, -9, -10, 3, 13, -3, + -17, 19, -21, 6, -13, -15, -7, 22, -15, -7, 11, -20, -19, -6, 0, 28, + -10, -7, -13, 9, 7, 1, -11, -6, 21, -33, -4, 52, -11, -1, -2, -2, + -4, 32, 17, -31, 7, 12, 2, -5, 11, -1, -6, 1, 3, -11, 5, 4, + -15, -8, 10, 5, -18, 5, -26, -11, 22, -15, -23, 22, 19, -30, 3, 1, + -5, 10, -17, 10, -2, 10, 7, -17, -5, 36, -12, -24, 27, 22, -3, -11, + -6, -7, 20, 5, -21, 0, 23, -31, -27, 14, 2, 8, 7, -15, 0, 13, + -7, -3, -21, 33, -4, -26, 7, 5, -7, -7, 1, 3, 4, 11, -24, 6, + 11, -7, 14, -9, -11, -1, 34, -22, 11, 1, -18, 17, 4, -19, 28, -15, + -7, -11, 12, 1, -7, -9, -12, 17, -20, 6, 5, 2, -10, 12, -23, -3, + 26, -1, 4, 6, -25, 12, -3, -26, 2, 15, 14, -18, -6, -17, 14, 4, + -10, 21, -13, 5, -15, -20, 27, 6, 8, -11, 18, 15, -34, 17, -2, -13, + 41, -9, -10, -6, -2, 7, -11, -4, 28, -26, -6, 25, 17, -36, -2, 33, + -39, -15, 11, -2, 26, -32, -31, 21, 26, -11, -24, 12, -17, 4, -33, 24, + 14, -10, 12, -19, -3, 28, 11, -8, 0, 26, -17, -7, 8, -6, 20, 26, + -29, -27, 25, -14, -2, 10, -16, 39, -24, -17, -4, -13, 24, -10, -3, -20, + 25, -1, -24, 24, -20, -5, 21, -26, 7, 21, -26, 15, 17, 6, -34, 5, + 11, -27, 20, 17, -13, -8, -16, 9, 33, -36, 19, 5, 4, -2, -33, -12, + 38, -17, -10, -4, 19, 14, -4, -32, -41, 64, 5, -38, 28, 6, -2, -11, + -22, 11, 17, 17, -24, 23, -7, 9, 10, -38, 0, 25, -9, -6, -27, 20, + 2, -27, 34, -23, 17, -22, 4, 12, -43, 29, -8, 25, -19, 13, -17, -11, + 27, -8, 14, -19, 12, 9, -22, -6, 11, -10, 17, -4, 2, -3, 15, -47, + 32, -18, 11, 14, 0, 8, -33, -14, -12, 23, 17, -12, -4, 13, -27, 10, + -17, 20, -2, -11, -11, 27, 18, -21, -6, 26, -18, 9, -7, 27, -12, 3, + -9, -9, 22, 7, -38, -2, 14, -16, 12, -21, -10, 22, 1, -28, 20, 31, + -11, -49, 9, 16, -4, -7, -4, -5, 46, -39, 9, -18, 16, 22, -24, -13, + 14, 29, -10, 3, -23, 4, 11, -33, 30, 18, -9, 5, -11, 4, -20, 30, + -9, -14, -7, -9, 4, 0, 4, -15, -11, 23, 5, -24, 26, -6, -8, -17, + 21, 0, 3, 13, -10, -13, 19, -16, -10, -5, 10, 8, 22, -19, 4, -8, + 0, -24, 38, 12, -33, 10, -9, 5, -13, 11, 3, 7, -18, -12, 11, -4, + 8, -17, -7, 16, -9, -2, -9, 0, 10, -2, -1, -1, 12, -6, 13, -18, + 18, -6, 10, 1, -3, 9, -2, -30, 23, -9, 29, -11, -31, 10, 6, -21, + -19, 54, -30, 18, -12, -26, 23, -10, -31, 23, -5, 49, -34, 4, -18, 3, + 11, -24, 27, 12, -24, 3, -13, 3, 16, -6, -7, 1, 19, -8, -3, -11, + 13, -14, 19, 10, 17, -21, 14, -40, 12, 13, -5, -3, 21, -14, -29, 16, + -24, 1, 10, -1, -3, 6, -15, -16, 16, -4, 2, 23, -32, -1, 7, -5, + 13, 4, -15, 33, 1, -7, -7, -12, 13, 6, -8, 2, 21, 2, -21, 17, + -14, -19, 36, -2, -16, -4, 3, 9, 15, -39, 3, 9, -10, -3, -12, -7, + 28, -19, 8, -18, 22, -18, -11, -2, 17, 23, -15, -24, 11, 13, -14, -10, + 9, 4, 14, -10, -13, 13, -3, -12, 25, 6, -12, 12, -19, -3, 19, -10, + -13, 19, 10, 18, -31, -15, 19, -9, -14, -6, 25, -18, 2, 17, -41, 11, + 16, -20, 3, -10, 16, 9, 14, -27, -1, -3, 9, -19, 36, -6, -4, -4, + -16, 5, -7, 24, -1, -30, 13, -8, -4, -9, 47, -37, 3, 21, -24, 1, + 3, 11, 5, -10, -8, 20, -31, 16, 10, -1, 0, -9, -1, -6, 14, -6, + 6, -17, 20, 3, -23, 10, -14, 17, -16, -2, 26, 7, -20, -10, 9, -18, + 31, -35, 3, 14, -8, 13, -27, -4, -4, 26, -20, -9, 14, 22, -27, -4, + 18, 9, 9, 3, -13, -20, 15, -13, 6, 12, -5, -6, -12, 0, 4, -10, + 18, -7, -8, -15, 1, -11, 17, 5, -11, 14, -6, -11, 4, 10, -5, 13, + 0, -7, 15, -2, -16, 2, -3, 9, -6, 2, 34, -11, -17, -8, 21, 13, + -21, -4, 14, -7, -7, -19, 13, -7, 4, -25, 7, 16, -14, -40, -11, 36, + 3, -10, 4, -10, 7, -1, -1, 4, 14, 6, -14, -14, 17, 23, -13, -2, + -1, -12, 9, 8, 1, -7, 22, -29, 7, 7, 0, -24, 13, -10, 18, -1, + -3, 13, -24, 30, -32, -5, 18, -2, -6, -8, 11, -18, -12, 17, -11, 0, + 5, -4, -14, 31, -15, -16, 13, 12, -4, 4, -4, -1, -11, -15, 26, -18, + 29, -15, -3, -8, 6, 6, -34, 22, 0, 11, -18, 16, 20, -19, -21, -5, + 11, 21, 10, 10, -27, -5, 3, 2, -5, 9, -9, -1, 1, -11, -3, 8, + 4, 1, -1, -11, 19, -1, -21, -5, -2, 11, -2, -8, 10, -7, -1, 2, + -18, 3, 0, 7, 2, 7, 1, 1, -28, -14, 10, 19, 12, -21, 7, -19, + 20, -2, -3, -1, 17, -11, -13, -16, 32, 4, -5, -3, 4, -4, 18, -2, + -17, -6, 16, -3, 4, -12, 4, -2, 2, 6, -18, 20, -24, 17, -10, 19, + -16, -17, 8, -7, -5, 16, -12, -18, 11, 9, 2, -8, 17, -9, -3, -13, + 7, -6, 30, -15, -11, 5, 14, -2, -15, -5, 14, 13, -12, -24, -10, 22, + -2, -8, -1, 21, -5, -19, -16, 8, 42, -6, -27, -12, 23, 10, -17, -14, + 16, 14, -16, -2, 9, -2, 16, -9, -31, 22, 0, -2, 3, 4, -5, 20, + -24, -5, 13, -1, -5, -10, -6, 8, -11, 2, 8, -8, -5, -9, 1, -6, + 16, -1, -18, 4, 9, -3, 6, -4, 6, 9, -7, -9, -1, 10, -7, 4, + 3, -3, 4, -8, -5, 3, -4, 10, 6, -15, 2, 3, -5, -2, -3, -12, + 18, 2, -16, 7, 13, 0, -19, -8, 11, -6, -1, -9, 5, 13, -8, -6, + 6, 7, 11, -11, -6, 13, -2, -5, -1, 9, -2, -7, -15, 10, 5, -1, + -13, 8, 0, -6, -2, -2, 18, -16, -7, 2, 3, -4, 6, -11, 4, 6, + 1, -5, 22, -11, -5, -6, -3, 11, -1, -1, 4, 1, -4, -13, -4, 11, + -9, 1, 9, -1, -8, 1, -5, -7, 5, -14, 18, -1, -12, 11, -12, 16, + -5, -11, 11, -2, 15, -7, -18, -10, 0, 18, -12, 8, 3, 6, -16, -3, + 3, 6, 0, -1, -3, 4, 9, 3, -17, -7, 11, 11, -19, 5, 15, -12, + -3, -12, 4, 11, -19, 0, 0, -14, 21, -15, 2, 8, 3, 8, -8, 5, + -18, 9, -2, -8, 23, -5, -16, 5, 3, -20, 13, 11, -6, -15, 5, 4, + -12, 2, 10, -5, -12, 5, -14, -2, 18, 11, -14, 0, 28, -10, -20, 4, + 7, 9, -13, -6, 15, 11, -9, -6, 14, -8, 10, 4, -12, 11, -18, 13, + -17, -9, 16, -4, -14, -7, 17, -24, -5, 4, 6, -6, 14, 2, -24, -22, + 11, 13, 8, -16, 6, 13, -28, 10, -2, 11, 8, -1, -8, -14, 22, 3, + -5, -13, 18, 7, -26, 15, 20, -6, -10, 4, 11, 5, -8, -3, -5, 0, + -1, -6, 0, 4, 4, -14, -1, 1, 8, -14, -10, -4, 6, 4, -8, 3, + -9, 0, 11, -4, -7, 5, 4, 6, -29, 18, 22, -19, -16, -11, 17, 7, + -4, 3, -23, 20, 8, -19, 3, 13, 13, -16, -18, 15, -6, 0, 3, 17, + -7, -4, 2, -22, 21, -1, -2, -1, -15, 13, 3, -7, 4, 0, -7, 8, + -7, 11, 3, -2, -8, 10, -15, 0, 9, -14, -8, 8, -2, -9, 10, -13, + 9, 7, -6, 2, -12, -4, 6, -12, 8, 12, 3, -10, 6, 7, 1, -2, + -11, -1, 7, -7, 8, -13, -10, 11, -9, -10, -8, 20, 9, -11, 8, -5, + -4, 6, -3, 5, 13, -13, -7, -7, 6, 19, 0, -9, 9, -1, -3, 4, + -7, 0, -2, -4, -5, 5, 0, -5, 14, -19, -14, 18, -1, -5, 3, -12, + 18, -19, 4, -15, -10, 10, 10, -17, -4, 19, -6, -2, 5, 11, -4, -3, + 9, -22, 28, -6, -5, 0, -1, 11, -11, -13, 22, 3, -8, -9, 1, 3, + 0, 1, 2, 7, -5, -25, 10, 6, 6, 2, -11, 8, -16, 15, -20, 5, + 9, -6, -13, -5, 14, 6, -21, 22, -7, -14, 4, 26, -8, -13, 8, 1, + -10, -13, 11, 10, -10, 2, -13, -9, 15, 0, 10, -30, 14, 7, -13, -5, + -12, 8, 10, -4, 10, 12, -15, -7, 5, 2, 2, 10, -13, -3, 0, 21, + -2, -16, 9, 3, -1, 6, 15, -3, -21, 10, -8, 5, 1, 1, 2, -19, + 10, -7, -3, -1, 8, 6, -26, -10, 18, -28, -3, -3, 4, 0, -7, 6, + -10, -2, 25, -19, 5, -11, -2, 14, 4, -5, -3, 4, -5, 6, -2, -3, + 11, -1, 13, -12, 5, 20, -15, -3, 17, 4, -14, -5, 11, 3, 1, 6, + 11, -20, 10, -4, -4, -4, -4, -18, -7, 5, 10, -25, 7, -9, -15, 1, + -4, 4, 4, -4, -1, -18, 9, -6, 4, 7, -19, 10, 0, 3, -6, 12, + 18, -5, 2, 4, -4, 11, 2, 5, 2, 1, 3, -4, 3, 4, -3, -2, + -8, 11, 5, -10, -12, 12, -6, 6, -9, -6, 4, 9, 0, -9, 4, 3, + -7, -5, -12, 19, 2, -28, 1, 0, 9, -10, -6, 3, 3, -11, -4, 6, + 7, -7, -3, 5, -12, 9, 10, -12, 7, 5, 5, -6, -9, 16, 6, -16, + 3, 8, -17, 12, -5, 2, 1, 21, -25, -10, 5, -2, 15, -6, 1, 3, + 5, -16, -2, -16, 32, -17, 7, -13, 6, -1, -4, 0, -4, 10, -2, -17, + -7, 29, 0, -13, -1, -1, 2, 12, -4, 3, -2, 4, -19, -1, 18, 2, + -3, -15, -2, 10, -4, 1, -2, -5, 20, -5, -6, -7, 9, 0, -2, -24, + 5, 15, -2, -11, 1, 0, -2, -14, -2, -4, 7, 4, -4, -9, 2, 4, + -8, 8, -1, 2, 10, -13, 4, 10, -4, 27, -22, 17, -18, -2, 5, 8, + -1, 4, -6, 2, -1, 9, 1, -3, 16, -21, -18, 2, 10, -14, 9, 3, + -14, -9, 0, -16, 9, -10, 11, -12, -3, 1, -10, 3, -2, 2, -13, 13, + 10, -1, 4, 4, 1, -3, 9, 0, 4, 8, -14, 10, -4, 0, 8, 11, + -2, 2, -11, 3, -13, -8, 11, 4, 1, -7, 4, -21, 0, 1, -4, -22, + 17, -8, -16, 10, 4, -2, 0, -4, 2, -2, 2, -6, 10, 3, 3, 5, + -1, 6, 5, 2, -6, -3, -2, 7, -4, -4, 12, 1, -30, 12, -7, 3, + 4, -6, -7, -9, 9, -1, 7, -10, 12, -16, 2, -8, 23, -5, -5, -1, + -8, 10, 3, -14, -12, 25, 7, -13, -6, 4, 15, -3, -23, 9, 12, -9, + -13, 18, -9, 5, 1, -17, -4, 13, -10, 11, -10, -1, 6, 0, -7, -2, + 9, -4, 9, -24, 7, 6, -5, 4, 15, -15, 11, -5, -24, 9, 11, -16, + 2, 0, -9, -2, 10, 7, -12, 8, -12, -6, 10, 6, 10, -14, -5, 20, + -16, 7, 8, -1, -19, 24, 2, -10, 15, 6, -6, -21, 3, -3, 15, -9, + -3, 3, -2, -4, -3, -9, 5, 0, -5, -3, -15, -4, -1, 1, -14, 33, + -12, -18, 9, -2, -10, 9, 9, -1, -1, -5, 10, -3, 2, 4, 2, -9, + -1, 25, -2, -3, 15, -17, -7, 8, -7, 0, 10, -13, 9, -11, 0, -3, + 18, -15, -11, 5, 0, -12, -2, 7, -6, -4, -9, 11, -6, 8, 1, -14, + 3, 16, -10, -3, 2, 6, 4, 9, -9, -2, 0, 2, -3, 15, 3, -10, + -4, -8, -1, 10, -13, -9, 16, -9, -3, -2, 5, -6, -6, -9, 10, 8, + -4, 14, -7, -19, 12, 1, 2, 1, 4, -1, -6, -3, -3, 5, 7, -2, + 0, 0, -5, 0, -6, 1, 6, -5, -4, 5, -6, 5, -4, -8, 15, -5, + -7, 0, 3, -8, 0, 3, -8, -4, 6, -4, -4, 15, -5, -8, -7, 4, + 7, -10, -6, 15, -4, -13, 7, 2, 2, 1, -4, 5, 0, 0, 1, 4, + -7, 4, 4, -2, 4, 5, 1, -18, 12, 4, -3, -6, 11, 0, -13, -1, + 1, -12, 3, 13, -9, -15, 7, 0, -4, -8, 0, 5, 0, -9, 1, 1, + -3, 0, 3, 5, -10, 6, -1, -4, 4, 15, -15, -5, -9, 18, -2, 0, + 15, -11, -9, 0, 6, -2, 8, 1, -8, -9, 7, 3, -7, -3, 6, 1, + -5, 0, -5, -5, 0, -3, 11, 1, -3, -8, -4, -4, 5, 9, -6, -7, + 4, 15, -13, 5, -4, 2, -6, -2, 0, 5, 4, -4, 0, -6, 8, 3, + -2, -4, -4, -11, 4, 10, -1, -4, -2, -1, -3, 1, -4, -2, 3, 1, + -4, -11, 12, -4, 5, -2, 7, -12, -2, 4, -4, 5, 8, 1, -8, 14, + -11, -1, 1, 4, 0, 5, -5, 2, -7, -7, 10, 3, 1, -13, 0, -4, + 5, -9, -1, 1, -11, -5, 5, 2, -6, 5, -5, -8, 12, -2, 7, -1, + -10, -5, -7, 14, 9, 3, -5, -2, 5, 4, -2, 0, -5, 2, 3, 3, + -12, 6, 3, 2, -9, -1, 24, -13, -9, -1, -2, 0, 7, -6, -17, 14, + -12, -5, 10, 1, -4, -1, -1, 1, -3, 2, -2, -11, 1, -1, -1, 1, + 10, -3, 2, 1, 5, -7, 1, -1, -5, 7, 1, 7, -4, 5, -11, -8, + -8, 7, 8, 6, 0, -15, -1, 7, 0, -6, -3, 7, -4, -3, -2, 1, + 5, 8, -6, -4, 11, 3, -14, -6, -3, -6, 9, -5, 4, -5, 2, 3, + -13, -3, 1, -4, -3, 11, -1, 0, 7, -16, -6, 11, 5, 0, 4, 5, + -2, -3, -2, 8, 7, -16, 1, 2, 6, 3, -17, 11, -2, -2, -9, 6, + 0, -7, 6, -22, -2, 14, 3, -11, 0, -6, -2, -7, -7, 1, 4, 14, + -1, -6, 0, 7, 3, -14, 4, 15, -4, -9, -2, 12, 14, -10, 5, 9, + -11, -2, -9, 2, -9, 11, 2, -21, 7, 6, -11, -1, 0, 0, 1, -9, + 4, 0, -10, 1, 3, -3, -7, 12, -9, -2, 4, 6, 3, -8, 0, 1, + -2, -14, 12, 11, -5, 10, -3, -1, 3, -6, 1, 0, -3, 8, -1, -18, + 12, 5, -13, -4, 17, -1, -6, 1, -11, 0, -6, 2, -2, -2, 5, 3, + -17, 2, -5, 11, -4, 8, 8, -19, -6, 14, -6, -6, 0, 5, 0, -8, + 7, 13, -6, -5, 6, -2, -9, -1, 8, 3, -4, -4, 10, -10, -9, 7, + 2, -6, 14, 0, -15, 3, 5, -4, -10, 8, 0, -6, -11, 3, 10, -9, + 1, 8, -7, 2, -1, -6, -8, 6, 2, -8, -2, 16, -3, -3, -1, 5, + -3, -8, 6, 9, -6, 1, -1, -1, 2, -6, 6, -1, -9, 3, 9, -10, + 1, 5, -4, -14, 2, 1, 7, -5, 3, -2, -13, 5, 10, -9, -8, 14, + -6, -19, -3, 19, -3, -3, 6, -4, -10, 3, -1, -4, 5, 5, 1, 0, + -1, 11, 4, -10, 3, -5, 4, -7, 1, 8, -3, 1, 2, 0, -10, 2, + 5, -15, -3, 8, -8, -6, 5, -2, -5, -5, 11, 0, -12, -7, 5, 2, + -5, 2, -1, -4, 2, 7, -12, 5, 6, -3, 5, -1, 12, 7, -13, -3, + 0, 3, 0, 13, -1, -4, 0, -9, 5, -6, 5, -2, -10, -6, -2, 9, + -8, 5, -6, -10, 5, 4, -6, -2, 1, 1, 6, -14, 10, -3, -4, -5, + 1, 8, -16, 7, 7, -1, 0, 3, -5, 2, -1, -3, 11, -11, 9, 8, + -18, 3, 8, 13, -4, -5, -9, 4, -2, -4, 9, 5, -6, -5, -15, -3, + 17, -6, 2, -8, 4, 4, -4, -12, -3, -2, -2, -4, 5, -4, 1, 7, + -12, -6, 8, 6, -2, 1, -3, 3, 10, -3, 7, -11, 12, 4, -1, -1, + 1, 0, -11, 11, 4, 0, -2, -9, -2, -2, -8, -1, 5, -4, -5, -5, + 1, 10, -8, -11, -5, -4, 5, -1, 1, 6, -2, -5, -5, 3, 6, -2, + 6, -3, 0, 4, 5, 2, 4, -2, 1, 5, -2, -6, 11, -1, -5, 8, + -14, 6, -2, -6, -11, 4, 2, -14, 6, -9, 5, -4, -3, 4, -12, -2, + 2, -5, 4, 7, -5, 3, 6, -1, -3, -6, 0, 7, 0, 1, 6, 9, + 4, -2, -7, -4, 7, 4, 4, -5, -5, 0, 3, -6, -1, 7, -2, -18, + -1, 3, -15, 5, -2, -2, 0, 4, -10, -4, 3, 4, -10, 4, -1, 5, + 4, -7, 8, -7, 0, 3, 2, -7, 13, 0, -2, -6, -6, 5, 10, -10, + 4, -1, 2, -1, -5, 7, 5, -3, -7, 1, -5, 10, 1, -11, 7, 6, + -10, -15, 12, 2, -4, 1, 0, -5, 3, 0, -2, 6, -5, -4, -13, -2, + 3, 1, 4, 3, 3, -10, -7, -7, 11, -2, 2, 2, -7, 4, -1, 6, + 2, 0, 8, 3, 0, -7, 8, 3, 5, -8, -3, -2, 2, 3, -12, -4, + -3, 12, -12, -4, 7, -3, -10, -10, -4, 6, -2, -8, 9, 1, 1, 1, + -3, -6, 12, -5, -6, -1, 11, -7, 5, 6, 2, 9, -11, 6, -2, 8, + 1, -6, 4, 3, -6, -3, 5, -4, 4, 1, -19, -1, 3, 4, 0, 0, + -10, -1, -3, -5, -3, 0, 11, -1, -12, -2, 6, 0, -3, 3, 4, -1, + -7, 1, -2, -1, 2, -1, 0, 2, -2, 4, -5, -4, 11, -4, -5, -3, + 7, 5, -8, 3, 6, -9, 0, 9, -5, -2, 5, -4, -6, 0, 7, -1, + -2, 0, -1, -6, -9, -6, -1, 8, 4, -1, -9, -5, 13, 2, -11, -5, + 9, 0, -8, -1, 5, -2, -5, -3, -2, 7, 5, -4, -13, 3, 11, -8, + 3, 0, 2, 5, -12, -6, 6, 3, -4, -1, 8, 1, -5, -7, -6, 2, + 8, 5, -2, -9, 7, -6, -2, 13, -7, 2, 1, -1, -5, 3, 7, -1, + -11, 9, -6, -4, -2, -5, -1, 2, -1, 3, 8, -7, -1, -9, 0, 0, + -1, 2, 5, -2, 1, -2, -3, 6, 6, -3, -6, -5, 4, -1, 1, 5, + 1, -1, -2, -3, -4, 4, 3, 1, -7, 5, -1, 0, -8, -6, 1, 7, + -3, -6, -2, 3, -1, -3, 2, 2, 0, -9, 1, -2, 4, 4, -5, 1, + -1, 1, 6, -2, 2, -5, -4, -1, 14, -3, 2, -9, 1, -2, -4, 1, + -1, 7, -9, 5, 2, -3, 2, -2, -9, -2, 4, -1, 2, -2, -2, 0, + -1, -1, -2, 3, 1, -1, -3, -6, 3, 7, -5, -3, 9, -5, -4, -5, + 8, -4, 2, 2, 8, -10, -1, 8, -14, 0, 6, -7, -1, 2, -3, 2, + -4, 5, 2, -5, -4, 5, 1, -6, 3, 6, -4, -1, -3, 3, -7, 0, + 1, 0, -4, 7, 6, -13, -3, 3, 2, -15, 8, 3, -3, -6, 9, -4, + -1, 9, 1, -6, -6, 7, 1, 1, -2, 6, -1, -4, -1, -1, -7, 5, + 3, 0, -5, -2, 8, -2, -8, 6, 7, -16, -5, 6, -6, -1, 1, 7, + -4, -3, -6, 3, -10, -3, 8, -9, -1, 5, -1, -7, 5, 2, -1, 1, + 5, 1, 2, -4, -5, 1, 1, 3, 1, -5, -2, 3, 2, -7, -1, 7, + 5, -5, -7, 5, 0, 3, -1, -4, -4, 4, 0, -4, 1, 6, -3, -7, + 0, -3, -3, -1, 0, -2, -4, 2, 1, -2, 3, -1, 0, -1, -6, 9, + -5, 4, -1, -1, 4, -2, 5, -8, 2, -3, -2, 2, -3, 10, 2, -3, + -5, 2, -4, -1, -3, -7, 9, 1, 0, 0, -5, 1, -2, -12, 6, 8, + -18, 4, -1, 4, -1, 5, -5, -3, 3, -1, 4, -5, 9, -5, -4, -5, + 2, 5, -1, -4, 0, -3, -2, 8, -5, 2, 1, -13, 3, 1, 4, 5, + -8, 2, 8, 1, -1, 1, -9, 1, -2, -4, 1, 4, -3, 4, -4, -5, + 6, 5, -6, -3, -3, 1, 1, -7, 1, 2, 1, -5, -4, -2, 2, -6, + 6, 3, 7, -10, -9, 4, 1, -5, 6, 9, 3, 1, -2, -4, 3, 4, + -1, -6, 3, 1, -2, -9, 4, 4, -5, 4, -10, 2, -4, -5, -1, 1, + 2, 0, 2, -8, 1, 3, -4, -13, 0, 10, -1, -4, 5, 0, -4, 5, + -3, 2, -5, 2, 1, 2, 4, 2, 2, -10, 5, 3, -11, -2, 3, 3, + 0, -6, -2, 1, 1, 2, -1, -8, -1, -5, -4, -3, 5, 8, -4, -4, + 2, 0, -2, -2, 1, -5, 0, 13, -8, -6, 4, 8, -6, -1, 6, -2, + 4, -5, 3, 5, -7, -8, -2, -3, 7, 8, -8, -3, 1, 5, -5, -5, + 9, -4, -7, -5, 4, 3, -6, 5, 1, -1, 3, 0, -6, -9, 0, -6, + 1, 4, 10, 5, -13, 0, 6, -2, -4, 2, -2, 6, -1, -4, 0, -11, + 6, 3, -1, -3, 14, -1, -15, 1, 2, 3, -1, 4, -3, -6, 0, 3, + 0, -6, 10, -3, -14, -2, 10, -3, -9, -4, 0, 6, -1, 7, -3, -5, + -6, 1, 0, -5, 11, -2, 1, -2, 5, -1, -4, -1, -3, -4, 2, 11, + 2, -4, 1, 2, -12, 7, 3, -1, -11, 3, 15, -8, -11, 0, 0, 2, + -7, 1, -3, -4, -3, -5, -4, 6, 11, -7, -8, -1, 6, -5, -3, 6, + 8, 3, -6, 1, -1, -1, -1, -5, -3, 8, 7, 4, -9, 1, -2, -4, + -6, 9, -4, 3, -8, 0, 6, -2, -4, -2, -2, -6, 8, -7, 3, 1, + 3, -1, -3, 2, 1, -6, -9, 3, -5, 8, 5, -10, 7, 5, -3, -2, + -1, -3, -1, -4, -7, 6, 6, 3, -7, 0, 0, 1, 0, -7, 3, -1, + 0, 1, 2, 2, 2, -11, -8, 9, 6, 2, -6, -1, 1, -3, 3, 1, + -6, 2, -3, -2, -1, 2, -4, 0, -4, -2, 0, -3, -2, -6, 5, 2, + 0, -1, -3, -1, 3, 1, -2, 0, 2, 2, 0, 1, 7, 1, -4, -2, + -6, 4, 3, -1, -4, -1, 3, 3, -9, -2, 0, -2, -1, -5, 6, 1, + -5, 1, -5, 9, -10, -4, 0, -4, 6, 1, -3, -5, 9, -2, -5, 2, + 0, 6, -6, 2, 5, 10, -8, -3, -2, -1, 4, -3, -1, -4, 0, -1, + 1, -4, 0, 5, -8, -1, -5, -1, -1, 3, 3, 3, 2, -14, -5, 1, + 2, 3, 1, -1, 2, 5, -2, 2, -5, 2, 3, -2, -2, -3, 4, 4, + 4, -6, 3, 1, -10, 1, -6, 6, -2, -3, 0, -3, 1, -3, 1, -1, + -4, -5, -4, 7, -2, -2, -3, 6, -5, -5, 2, -6, 1, 4, 3, -8, + 11, 4, -4, -1, 2, 3, -5, -2, 1, 7, -4, 2, 4, -10, 7, -7, + -1, 0, -3, 5, -4, -1, -4, 5, -7, 3, 3, -11, -2, -1, 5, 1, + -1, 0, 6, -11, 0, 1, -2, 1, 0, -1, -4, 2, 9, -2, -9, -4, + 2, 0, 2, -1, 1, 1, -7, 5, -3, 4, -1, -3, -8, 5, 7, -1, + -1, -3, 3, -7, 0, 4, -3, -3, 1, 6, 0, -1, 0, -5, -1, 0, + -4, 0, 0, -3, 1, -4, 1, 7, -3, -13, -2, -2, -1, 3, 5, 2, + -6, 1, 6, -2, -6, 8, -1, -6, 0, 4, 6, -2, 0, -2, -4, 3, + 5, -4, -7, 2, 5, -3, -3, 3, 1, -10, -7, 3, 1, -3, 2, 4, + -7, -3, 0, 2, -5, -3, 3, -2, 0, 3, 5, -6, -1, 4, -2, 0, + 5, 1, -2, -2, 3, 2, -1, -3, -3, -7, 7, 3, -1, -2, 0, 0, + 1, -2, 1, 0, -15, -1, 3, 2, -3, 4, 0, -7, 0, -1, -1, -4, + -3, 2, -1, -1, 11, -3, -1, -5, -1, 2, 2, 0, 1, 2, 3, 4, + -6, -3, -2, 1, 0, -4, 2, 1, -1, -5, 1, -1, -7, 2, -2, -5, + 0, 2, -2, 3, 5, 0, -2, -6, 6, -7, 3, -4, -6, 1, 6, 3, + 1, -2, -3, -4, -6, -1, 7, -2, 0, -3, 0, 9, -3, -5, -1, 3, + 0, -1, -3, 6, 1, -6, -3, 3, 6, 0, -6, -4, 2, 1, -1, 2, + -5, 4, 1, -2, -5, 0, 7, -9, 3, -1, 1, -6, 0, -5, -1, 1, + -1, 0, -4, 2, -2, -2, 1, 6, -1, -5, 0, 0, 0, 1, 3, 2, + 2, -1, -3, 0, 1, 5, 1, -5, -7, 2, 6, -3, -3, -3, 2, -7, + -5, 5, 0, 0, -3, -4, -1, 3, -4, -5, 1, 5, -1, -2, -4, 0, + 5, 2, 0, 2, 2, -1, -1, -5, 5, 3, -1, -4, 1, 0, -1, -2, + -1, 2, 2, -4, -4, 2, -2, -3, -4, -3, 0, 3, -3, -2, -2, 4, + 1, -2, -2, 1, 2, -6, -1, 2, 6, 1, -2, 0, 4, -3, -1, -2, + -1, 5, 1, -11, 4, 3, -1, -6, 2, -2, 3, -4, -8, -2, -1, 4, + 0, 3, -2, -1, -2, -2, 1, 3, 3, -7, 0, 2, 10, 0, -4, 3, + -3, 0, 0, 3, -4, 6, -4, -8, 2, 1, 3, -14, 1, -1, -2, 0, + 0, -5, -1, 2, -6, -1, 3, 0, -5, -3, 3, 1, 6, -2, 0, 6, + 2, -7, 1, 3, -5, 5, 8, 0, -1, 1, -4, -6, -2, 6, 4, -4, + -1, 1, -10, 0, -4, 0, -3, 2, 0, -8, 3, -3, 0, 2, -1, 1, + -8, -1, -1, -3, -1, 4, 1, 6, 1, 0, 0, -2, 0, -2, 7, -4, + 3, -1, 2, 0, -2, -2, -8, 3, 2, -1, -4, 3, 0, -3, -5, 2, + -3, -3, -2, 5, 2, 1, 1, -4, 1, -1, 4, 6, -4, 0, -6, -4, + 1, 3, 3, -1, -2, -7, -1, -3, 6, -6, 2, 1, 5, -8, -5, -1, + 2, -1, -3, -1, -1, 5, -7, 3, 3, 1, 4, -4, -3, -3, 8, 1, + -2, 4, 4, -2, -8, 2, 1, 0, 2, 0, -6, 3, -2, -8, -2, 5, + -1, -6, 0, 2, -1, -5, -2, -2, 6, 0, -5, -2, 3, 0, -5, -1, + 6, 7, 2, -8, -4, 6, 2, -6, -4, 12, 2, -5, -2, -6, 1, 1, + -3, -7, -3, 11, -3, -6, -1, 3, -2, -4, -4, 4, -3, 4, -2, -3, + 1, 7, 0, -8, 7, 1, -2, -4, -6, 13, 0, -3, 1, 2, -1, -4, + -3, 1, 3, -2, -3, -1, 0, 3, -1, -10, -1, 2, -8, -3, 3, 2, + 1, 4, -6, -2, 1, -3, -1, -4, 6, 5, -1, -5, -1, 9, -2, 0, + -4, 0, 1, -3, 4, -5, 1, 3, -4, -6, 0, 4, -2, -6, 9, -1, + -3, 2, -4, 0, 4, -7, -4, -1, 1, 4, 0, -1, 6, -2, -2, 4, + -3, -1, -6, -2, 2, 3, 1, -3, 8, -10, -10, 7, 0, -2, -1, -4, + 3, -6, 0, -5, -5, 5, 3, -6, 1, 5, 0, -1, 1, -1, 0, 0, + 0, -5, 7, -2, -1, 2, -1, 3, 0, -6, 4, -3, -2, -3, -2, 1, + 3, 3, 0, -2, -1, -9, 2, 2, -1, 4, -4, 4, -10, 7, -8, 2, + 1, -1, 0, -1, 4, 2, -7, 7, -6, -4, 3, 11, -5, -6, 1, 3, + -4, -6, 2, 2, -2, -3, -7, -4, 6, 0, 7, -13, 6, 2, -9, -2, + -5, 3, 8, 0, 0, 5, -5, -4, 3, 0, 2, 4, -7, 0, -1, 10, + -3, -6, 7, 2, -1, 0, 6, -2, -7, 4, -2, -1, -2, 1, -3, -9, + 6, 0, -4, 0, 3, 3, -11, -4, 7, -16, -2, 0, 2, 1, -2, 2, + -5, -1, 12, -6, 2, -7, 2, 6, 0, -4, -1, 1, -3, 2, -1, 0, + 7, -2, 2, -6, 2, 7, -9, -4, 8, 2, -9, -3, 8, 1, -1, 4, + 5, -11, 2, 1, -1, 0, 0, -6, -2, 2, 6, -13, 2, -3, -8, 1, + 1, 3, -2, -3, -2, -7, 4, -6, -2, 3, -10, 5, -2, 1, -3, 5, + 8, -4, -1, 2, -1, 6, 2, 3, 2, -2, 0, -1, 0, 4, 1, -1, + -2, 7, 1, -7, -5, 7, -5, 2, -5, -4, 0, 3, 3, -2, 0, -1, + -9, -4, -9, 10, 1, -14, 0, -1, 6, -8, -3, 3, -1, -6, -1, 5, + 3, -5, -1, 3, -6, 5, 7, -10, 5, 5, 2, -4, -3, 9, 4, -11, + 0, 5, -11, 7, -6, 2, 2, 12, -15, -8, 2, -3, 7, -5, 3, 3, + 1, -10, 0, -9, 17, -11, 7, -6, 2, 1, -3, 0, -1, 5, -2, -10, + -4, 16, -1, -7, -1, -3, 1, 11, -3, 1, -3, 2, -12, -2, 12, 3, + -1, -10, -2, 6, -3, 1, -1, -4, 12, -1, -2, -7, 6, -1, -1, -16, + 5, 11, -3, -7, 1, -1, -2, -6, -4, -5, 3, 4, -3, -8, -1, 3, + -5, 3, 1, 2, 6, -10, 1, 7, 0, 21, -15, 11, -12, 0, 1, 4, + 1, 4, -4, -1, 3, 7, 0, -5, 10, -15, -14, 2, 6, -11, 5, 3, + -10, -6, -1, -11, 4, -9, 6, -9, -2, 2, -8, 3, 0, 2, -9, 7, + 7, 2, 2, 0, 3, 1, 6, 0, 3, 6, -10, 6, -4, 1, 7, 9, + -1, 0, -7, 1, -11, -8, 9, 4, 0, -6, 2, -16, 0, 1, -2, -16, + 10, -7, -12, 7, 4, -1, -1, -4, 2, -1, 2, -5, 8, 3, 3, 4, + -2, 4, 3, 2, -4, -2, -1, 5, -5, -3, 9, 2, -22, 8, -6, 1, + 3, -5, -4, -6, 7, 0, 5, -8, 9, -13, 0, -6, 18, -3, -3, -1, + -6, 7, 3, -11, -9, 19, 6, -10, -6, 3, 12, -2, -18, 7, 8, -7, + -10, 14, -8, 5, 1, -15, -4, 11, -6, 9, -8, -1, 5, 1, -6, -2, + 7, -3, 7, -20, 6, 5, -4, 3, 12, -12, 11, -4, -22, 7, 9, -13, + 1, 0, -8, -1, 9, 6, -10, 5, -9, -5, 8, 5, 8, -12, -4, 16, + -14, 7, 6, -1, -16, 21, 2, -9, 13, 5, -4, -19, 2, -3, 12, -7, + -2, 3, -2, -4, -3, -8, 4, 1, -4, -4, -14, -3, -1, 1, -11, 30, + -11, -16, 8, -2, -9, 8, 8, -1, -1, -5, 10, -4, 1, 4, 3, -8, + -1, 23, -2, -2, 14, -15, -7, 7, -7, 0, 9, -12, 8, -10, 0, -3, + 16, -13, -11, 5, -1, -10, -2, 6, -5, -4, -9, 10, -6, 7, 1, -13, + 2, 14, -9, -3, 2, 6, 4, 8, -8, -2, 0, 2, -3, 14, 3, -10, + -4, -8, -1, 10, -13, -8, 15, -9, -3, -2, 5, -5, -6, -9, 9, 7, + -4, 14, -7, -18, 12, 1, 2, 1, 4, -2, -6, -3, -2, 5, 7, -2, + 0, 0, -4, 0, -6, 1, 5, -5, -4, 5, -6, 5, -4, -8, 15, -5, + -6, 0, 3, -8, 0, 3, 0, -1, 0, -4, 6, -16, 22, -7, 3, -5, + 2, 2, 1, -3, 4, -8, 4, 4, 0, -5, -9, 4, -5, -4, 3, 2, + 1, 3, -4, 6, -15, -1, 4, 1, -9, 3, 1, -8, 3, -6, 11, -5, + 6, -11, 17, -15, -2, -19, -11, 1, -4, 8, 0, 5, 18, -11, 0, 13, + -4, 6, -13, 4, -11, -1, -7, -7, 11, 10, -9, 17, -11, 20, -6, 7, + -14, 23, -7, -2, -2, 7, -10, 2, 0, 2, 5, 6, -8, 5, -4, -10, + 9, -4, 6, 0, -7, 8, -7, 1, -20, -4, -1, -3, 6, -10, -6, -15, + -11, 10, -5, 19, 3, 1, -19, -11, -1, -9, 9, 22, 24, 10, -5, -18, + -8, -23, 14, 11, 0, 31, 43, -9, 0, -7, -15, -28, -35, -30, 3, 5, + -5, 11, 52, 55, 7, -5, -10, -12, -25, -43, -12, 4, -37, -47, -21, -5, + 4, -11, 1, 31, 27, 34, 46, 48, 61, 10, 16, 8, 7, -14, -40, -47, + -36, -51, -42, -15, 4, 12, -32, -42, -10, -4, 10, 1, 15, 50, 31, 5, + 15, 38, 37, 29, 15, 22, 11, -4, -35, 10, 3, -18, 1, -14, -33, -5, + -47, -25, -13, -2, 15, -6, 5, -29, -17, -19, -1, 3, 7, 2, 17, 28, + -8, -23, 7, 7, 36, 15, 2, 1, -2, -9, 1, 6, 20, 6, 14, -3, + 21, -11, -12, -35, 11, -20, -18, -36, -23, -27, -19, 1, 10, 14, 27, 6, + 44, 14, -9, 3, 20, 27, 45, -8, -13, 16, -16, 24, -10, -9, -3, -38, + -19, -14, -38, -38, -41, 13, 40, -37, 5, -7, -7, -4, 4, -31, 32, 22, + 15, 9, 13, 10, 10, -17, 22, 30, 9, -6, 27, 66, 47, -17, -21, -20, + -9, -36, -73, -3, 22, -35, -12, 6, 7, 4, -17, -45, 22, 17, -17, 3, + -9, -4, 11, -10, 13, -4, 8, 38, 3, 20, 42, -22, 9, 23, -28, -21, + 3, 10, 1, 26, -28, -18, -9, 7, -30, -41, -24, -9, 10, -6, 31, -5, + 2, 29, -9, 1, -27, -24, 7, -19, -5, 10, -13, 21, 21, 3, 30, -11, + -17, 34, -11, 8, 7, -8, 1, 11, -1, 7, -13, 1, -3, 23, -12, 8, + -19, -3, 20, -78, 42, -23, 4, -29, -16, -5, 38, -49, 30, -26, 26, 16, + 8, -33, 53, 19, -20, 12, 5, 23, -11, 4, -6, 42, -111, 67, -40, 29, + -32, -20, -77, 113, -46, -12, 8, -5, -14, 35, -52, 94, -5, -61, 58, -36, + 41, -83, 21, -19, 61, -68, 37, -37, 12, 66, -69, -16, 100, -88, 48, 21, + -39, 73, -24, -2, 45, 65, -59, 53, -103, 95, -97, 1, -14, -4, -41, 9, + -13, -18, 16, -26, 9, 26, -15, 25, -16, 6, 8, 26, -52, 35, -21, 4, + -2, -11, -4, 22, 0, 21, -40, 65, -6, -13, -11, -7, 32, -46, -48, 16, + -26, -3, 0, -42, 87, -68, 34, 17, -14, 43, 23, -15, 30, 20, 47, -19, + -33, -12, 15, 1, -37, 15, -12, -11, -7, 15, -75, 36, -41, 27, -8, -7, + -12, 10, -4, 49, -6, 42, -32, 4, 20, 33, -65, 24, -52, 10, 13, -17, + -15, 60, -14, -55, 35, -16, 50, -83, -3, 29, 58, -75, 71, -46, 47, -32, + 44, -57, 10, -43, 33, 22, -48, 51, -41, 6, 7, 39, -3, -41, 7, -9, + 37, -66, 22, 26, -13, 74, -87, 127, -39, -16, -29, -11, -8, -57, -15, -45, + 52, -74, -5, -2, 103, -126, 85, 20, 28, -7, 53, -38, 58, -10, -11, 33, + -70, 20, 1, 40, -36, 26, -58, 58, -23, 61, -71, -7, -39, 43, 22, -18, + -1, -61, 90, -37, 35, -58, 30, -62, 27, -45, 47, -59, -6, -35, 70, -49, + 9, -30, 92, -15, 21, 1, 26, 6, -19, 90, -43, 49, -46, 10, 6, 15, + -90, 67, -51, -11, 4, 28, -36, 24, 41, -68, 24, -34, 63, -40, 17, -30, + 18, -39, 14, -38, 15, 9, -54, 54, -20, 36, -21, -14, -13, 11, 23, 11, + -54, 56, -25, 37, -46, 49, -74, 81, -40, 51, -44, 57, -69, 51, -50, 61, + 27, -112, 111, -114, 106, -85, 49, -61, 75, -18, 26, -68, 32, -15, -25, 21, + -15, 38, -46, 80, -119, 126, -85, 41, -40, 77, -65, 28, -6, -39, 45, -87, + 39, -63, 81, -32, 4, -32, 44, -25, 42, -12, -15, 21, -1, -56, 21, 23, + -30, 33, -28, -3, 32, 4, -36, 60, -20, 13, -3, 22, -43, 101, -88, 59, + -53, 18, 8, 22, -33, -52, 34, -32, 35, -90, 112, -107, 56, -59, 43, -60, + -18, -4, -21, 45, 11, -48, 11, 38, -27, 58, -49, 65, 19, 54, -38, 35, + -37, 24, -11, 44, -62, 41, -16, -48, -8, 31, -68, 17, -3, -5, 52, -51, + -10, 16, -26, 18, -29, 56, -41, 3, 5, -10, -37, 61, -14, -10, -9, 20, + -8, 8, -2, -16, 44, -17, 14, -33, 30, -2, -27, 16, 3, 0, 51, -42, + 32, -20, 8, -11, -24, 10, 12, -15, 6, -32, 10, 21, -38, -11, -12, 23, + 13, -64, 19, 34, -23, -23, 16, 10, 39, 2, -36, 55, -31, 0, -29, 18, + 8, 12, -61, 73, -28, 54, -34, 21, 9, 7, 53, -34, -29, 19, -7, -44, + 7, 15, -16, -18, -31, 10, -29, 36, -69, 7, 4, 33, -72, 45, 14, 0, + -8, 35, -13, 26, 16, -28, -3, -32, 45, -4, 8, -20, 65, -24, 2, -24, + 40, -16, -16, 20, 8, 2, -3, -2, 23, -15, -11, -30, 19, -51, -19, -5, + -36, 18, 24, -4, -1, 46, -90, 60, 4, 23, -17, 16, 60, -24, 0, 18, + 0, 5, -6, -24, 27, -34, -28, -7, -4, 22, -30, -11, -3, -1, -44, 36, + -38, -6, -9, 55, -34, 16, 27, 28, -65, 62, 22, -32, 36, 7, 2, 27, + -19, 50, -71, 44, -19, -67, 13, -3, -14, -30, 33, 5, -12, -48, 60, -47, + -28, 9, -6, 24, -11, -1, 13, 62, -53, 26, 7, -9, 6, 58, -38, -10, + 0, 5, -23, 23, 8, -14, -19, 21, -9, 35, -17, -28, 14, 27, -17, -14, + -29, 24, 6, -85, 74, -16, -18, -2, -19, 47, -29, -18, -15, 52, 0, 7, + -10, -23, 45, 13, -11, 12, -28, 27, -26, 19, -69, 74, -55, 35, -21, 41, + -24, -11, 39, -19, 7, 0, 7, -31, 10, 7, -45, -17, 25, -12, 9, -19, + 3, 28, -53, 76, -19, -25, 49, -2, 6, -11, 24, -12, -23, 17, -1, -15, + -10, -36, 26, -25, 0, -44, 59, -67, 45, -31, 5, 15, 56, -12, -14, 12, + 10, 24, -52, 37, 5, -35, 52, 23, -55, -6, 24, -49, 26, 31, -24, 10, + -33, 33, -11, 1, -49, 8, 7, 6, -78, 12, -22, 10, -11, 13, 13, -18, + 38, 50, -18, -5, 64, -52, 59, 33, 3, -9, -6, -6, 26, -64, 18, -38, + -47, 18, -33, 4, -39, 40, -31, -1, -23, 48, -30, 18, 17, 32, -20, 32, + 19, 24, -58, 49, -38, -9, 15, -28, 16, -3, -2, -28, 33, -22, 23, -1, + -34, 33, -48, 67, -55, 21, 51, -66, -2, 21, -5, -17, 24, -63, 53, 8, + -19, 9, -11, 36, -37, -35, 43, -35, -3, -44, 68, -43, 53, -24, -5, 45, + -16, -7, 14, 49, 3, -16, 22, -10, 2, -28, -9, -6, -5, 32, -76, -22, + 35, -26, -35, -12, 0, 3, 13, 6, 36, 7, -32, 69, -15, 45, -20, -21, + 35, 35, 1, -25, 11, 34, -24, -33, -9, 5, -25, -49, 31, -41, 15, -42, + 25, -30, 42, -80, 32, 2, -18, 33, -12, -9, 43, -1, 4, -12, 54, -51, + 22, -1, 18, 28, -29, 18, 7, 10, -19, 8, -1, 12, -21, -6, -11, 4, + 4, -28, -8, 22, -27, -5, 9, -25, 20, -19, -36, 41, -8, 20, -32, 16, + -29, 29, -13, 13, 4, 1, 17, 8, 0, 9, 22, -1, -3, 28, -11, -39, + 36, -31, 5, -11, -27, 22, -39, 7, 15, -24, 19, 8, -37, 75, -52, 54, + -65, 22, -13, 23, -26, 32, -19, 10, -8, -3, 12, 16, -44, 25, -23, 14, + 9, -46, 20, 2, -4, -8, -6, 18, 4, -2, -3, -15, 4, 16, -9, -5, + 34, -29, 27, -54, 98, -65, 11, -18, 16, -13, 0, -2, 0, 22, -43, 31, + -46, 58, 2, -25, -2, 16, -2, -29, 17, 18, -26, 21, -17, 5, -4, -9, + 0, -34, 50, -27, -3, 4, 31, -3, -47, 32, -25, 36, 6, -47, 33, -28, + 39, -36, 42, -28, 5, -3, -2, 25, 27, -47, 20, 22, -5, -15, 1, -9, + 16, -25, -10, -43, 40, -12, -19, 22, -24, -5, 14, -44, 42, -32, 32, -45, + 40, 41, -17, 27, -44, 38, -16, 15, -36, 39, -13, -19, -4, 34, 1, -9, + 9, -16, -2, -29, 31, -31, -4, 35, -21, -52, 63, -41, 2, -7, 30, -35, + 13, 9, 15, -4, 14, -36, 18, -14, 55, -50, -6, 22, -23, -11, -5, 12, + 17, -13, -43, 44, -33, 41, -42, 45, 3, -12, 26, 11, -11, 35, -76, 39, + 2, 0, 3, -4, 15, -19, -6, -33, 11, 5, 16, -25, -2, 19, -7, -43, + 30, 20, -27, -18, 12, 14, 33, -50, 14, -15, 23, 8, 2, -10, -4, 53, + -86, 24, -9, 41, -34, -21, 22, 24, -54, 27, 13, 2, -9, 14, -29, 21, + 40, -43, -9, -3, 27, -3, -22, 18, 10, -23, -15, 1, 14, -12, 3, -30, + 30, -22, -28, 36, -15, 39, -57, 21, 3, -3, 33, -13, -2, 6, 20, -6, + 4, -13, -5, -18, 13, -7, 7, 26, -26, 16, 7, -64, 37, -7, 10, -20, + 12, -11, 7, -34, 37, -12, -24, 34, -18, -18, 39, 9, -42, -24, 43, 2, + -16, 25, 12, -16, 8, 12, -44, 32, -9, 23, 1, -37, 40, -23, -17, 18, + -42, 23, -12, -7, 10, -6, 6, -13, -13, 30, -23, 36, -4, 7, 17, -18, + 18, -3, 8, 5, -1, -13, -15, 2, -5, -16, 7, -52, 23, -38, 30, -30, + 16, -26, 21, -22, 24, 3, 20, -28, 22, 22, -31, 42, -16, -11, 32, -26, + 0, 31, -14, 11, -15, 14, -17, -9, 10, 11, 27, -38, -4, 14, -18, 36, + -44, 0, -11, 16, -14, -2, 16, -34, -23, 22, 4, -24, 14, -13, 16, 31, + -28, -10, -6, 51, -27, 13, -49, 3, 68, -38, 1, 8, -27, 26, -16, 0, + 15, -36, 7, -6, 38, -11, 0, -14, 10, -4, 22, -48, 31, -1, 23, -38, + 1, 15, -7, 10, -1, -3, 4, -1, 10, -2, -12, 3, -22, 5, 9, 8, + 4, -14, 12, -3, -7, 22, -20, 3, -6, 13, -15, -8, -7, 16, -14, -1, + -3, 6, -17, 12, 22, -44, 68, -67, 50, 13, -20, -11, -4, -20, -3, 22, + -13, -20, 28, -7, 2, 11, -9, -23, 5, 5, -26, 24, -31, 2, 20, 15, + 2, -7, 4, 19, -6, 41, -51, -3, 24, 27, -30, 25, -37, 1, -7, -2, + -4, -26, -1, 12, 5, -12, 9, -30, 5, 11, 26, -18, -32, 42, 7, 0, + -23, 10, 10, -20, 53, -49, 6, -39, 18, 3, -27, 41, -21, 16, 28, 14, + -24, -15, 19, 5, 16, -31, -1, 45, -25, -6, -16, -4, -19, 37, -47, 21, + 2, -14, -7, 30, -35, 13, -30, 14, 21, 11, -18, -28, 37, 12, -18, 9, + 5, -1, 33, -41, 3, -7, -19, 8, -14, 12, 15, -18, -4, 44, -25, 22, + -46, 19, 40, -25, -12, -5, 17, 7, -53, 25, 4, -10, 14, 16, -31, 40, + -27, -11, -4, 28, -40, -5, -9, -3, 34, -47, 33, -5, 11, -33, 33, 0, + -14, 35, -18, -27, 11, 14, -37, 35, -20, 7, 15, 2, 27, -17, 15, -31, + -1, 11, -27, 24, -26, 14, 13, -35, 20, -13, -2, 16, 16, -6, 2, 15, + -7, -22, 51, -36, -2, 20, -19, 23, -20, -19, -9, -14, 8, -4, -13, 35, + -66, 36, -37, 3, 19, -1, 15, 32, -45, 71, -15, -5, 12, 34, -33, 24, + -5, 20, -43, 42, -59, 13, -12, -69, 66, -29, -34, 17, 7, -28, 24, 5, + -27, 51, -40, -9, 46, 3, -17, 36, -56, 63, -7, -31, -19, 53, -12, -10, + 4, 19, -47, 35, 0, -40, 17, -14, 13, -11, 11, 3, -39, 22, 5, 21, + -19, -11, 25, -4, -5, 20, -13, 25, -6, -16, -16, 29, -61, 25, -33, 12, + -17, 7, -19, 34, -27, 15, -19, 32, -26, 54, -46, 6, 9, 14, -6, -6, + 23, -32, 58, -19, -5, 15, 46, -42, 39, -7, -23, -7, -14, -22, 42, -66, + 0, 4, -8, -11, -4, -3, -7, 7, -23, 30, -14, 19, 8, -9, 20, 36, + 5, -24, 25, 12, -20, 16, -53, 60, -49, -26, 24, -87, 67, -49, 13, -7, + 5, -14, 5, 11, 38, -3, -15, 27, 26, -36, 20, 30, -47, 29, -5, 9, + -10, 38, -65, 47, -49, -4, -10, -6, 1, -1, -28, 16, -14, 3, -14, 27, + -8, 1, 2, 23, 21, -53, 40, 24, -16, -12, -2, 11, 17, -8, -18, 8, + -25, 28, -10, -12, 13, -51, 10, 35, -10, -8, -9, 8, 10, 14, -20, 4, + -9, 37, -5, -2, 2, 4, -9, -5, 16, -16, -23, 13, 7, -9, 14, -49, + 13, 8, -3, -13, -9, 22, -8, 12, -13, 36, -36, 35, -17, 23, -12, 0, + -37, 50, -31, -8, -31, 43, -4, -11, 0, 3, -7, -19, 16, -16, -28, 46, + -28, 27, -13, 33, -21, -1, 39, -13, 3, -4, 4, -39, 74, -30, -17, 33, + -3, -20, -12, 24, -94, 75, -63, 54, -62, 23, 4, 12, -33, 22, -35, 16, + 12, -28, 34, 2, -12, -3, 22, 23, -31, -6, 26, 4, -41, 8, 37, -15, + 21, -7, 18, -51, 42, -27, 35, -45, 35, -30, 18, 9, -20, 1, 18, -12, + -51, 61, -61, 24, -20, 1, 11, -5, -2, -12, 11, 20, -35, -2, 37, -21, + 23, -15, -2, 19, -51, 82, -50, 20, 29, -26, -34, 49, -2, -16, 11, -17, + -4, 6, 15, -35, 13, -15, -10, -17, 15, 4, -42, 43, -31, 34, -30, 53, + -43, 40, -22, 9, 9, -24, 64, -41, 29, -17, 8, -15, 8, 2, -27, 7, + 10, -28, 0, 30, -50, 6, -13, -14, -21, 11, 9, 13, -47, 35, -11, 32, + 28, -28, 1, 32, 2, -19, 28, -24, 9, 0, 19, -6, 16, -33, 6, -23, + 33, -31, -1, -4, 26, -22, -22, -10, -11, 18, -26, 19, -8, -4, 21, -14, + 36, -2, 12, -48, 49, -1, -13, -5, 8, -3, 9, -4, -18, 15, 28, -50, + 10, 4, -7, 4, -39, 37, -39, 11, 2, -20, 13, 4, -6, 0, 35, -17, + -9, 6, 38, -21, -1, -1, 12, -2, -16, 15, 7, -22, 18, -23, 11, 3, + -9, -39, 29, -31, 44, -41, 0, 5, 21, -9, -25, 25, -6, 38, -55, 38, + -14, 6, -26, 38, -24, 39, -39, -15, 17, 16, -20, -27, 17, 24, -20, -20, + 33, 8, -31, 2, 2, 27, 11, -4, -7, 31, -20, -9, 4, -4, 17, -32, + 2, -18, 31, -35, 38, -52, 42, -1, -28, -26, 25, 3, -51, 42, -35, 35, + -39, 44, -38, 20, 20, -51, 34, 45, -10, -7, 27, -19, 33, -49, 22, 2, + -7, -5, -27, 59, -24, -20, 21, -8, -15, 24, -51, 3, 9, -23, 24, -30, + 2, 29, -26, -2, 4, 10, 0, -18, 50, 3, 9, -14, 17, -18, 24, -13, + -33, 7, 25, -50, 2, -2, 30, -58, 31, -8, 23, -11, -1, -24, 21, 1, + -41, 47, -30, 28, -39, 56, -16, -20, 51, -45, 33, 6, 23, -12, -19, -2, + 7, 1, -14, -5, -11, -20, 25, -17, 7, -22, 21, -19, 34, -47, -2, 1, + 33, -30, 14, 20, 6, -9, 17, 13, -22, 19, -58, 23, 26, -15, -52, 2, + 18, 10, -13, 46, -5, -8, -6, 4, -14, 5, 11, -13, -7, 42, -25, 8, + -37, 35, -10, 6, -25, 16, 15, -15, -9, -20, 18, -23, 26, -34, 35, -22, + -10, 9, 14, -6, -21, 27, -8, 4, 1, 3, -19, 28, 2, -7, 30, -8, + -13, 11, -9, -9, -19, 12, 0, -23, -1, -23, -6, 27, -31, 41, -28, 13, + 5, 9, -21, 6, 2, -2, 18, -16, 31, -25, 40, -38, 39, -13, 8, 14, + -3, 9, -30, 6, -12, -7, -15, 30, -64, 6, -22, 13, -8, 14, -40, 9, + 32, -35, 14, -1, 12, -25, 63, -25, 35, -2, 19, -5, -3, 20, -29, -1, + 35, -37, 53, -46, 4, -14, 22, -27, 23, -64, 8, 5, -25, 41, -18, 14, + -42, 53, -56, 35, -42, 71, -63, 45, -38, 29, -12, 33, -22, 0, 24, -13, + 3, 13, 1, -10, -19, 11, 19, -38, 5, -2, -18, -21, 33, -54, 41, 9, + 4, -1, -21, 3, 3, 37, -31, 34, -40, 34, -19, 30, -26, 23, -53, 55, + -8, -13, -16, 7, -13, 46, -38, 2, -3, 17, -1, -26, 18, -57, 68, -27, + 23, -19, 32, -39, 2, 2, -18, 12, -16, 4, -23, 38, -65, 40, -5, 13, + 19, -26, -13, 60, -25, 7, 1, 10, 22, -24, 23, -20, -16, -17, 14, -32, + 26, -4, 17, -15, 9, -29, 4, -29, 11, 36, -18, -19, -2, 5, 28, -23, + 31, 6, 4, 18, -14, 4, -7, 0, -45, 61, -31, 5, -15, -23, -21, 52, + -62, 4, 22, 1, -9, 15, -24, -27, 60, -49, 38, 0, -6, 1, 13, 7, + 4, 19, 6, 0, 27, -28, -14, -21, 17, -1, -30, 23, 10, -36, 18, -19, + 2, -18, 0, 6, -1, 7, -1, -37, 26, 15, -35, 41, -24, 10, 10, -9, + -12, 12, 7, 3, 10, -11, 11, -14, 27, -49, 71, -55, 25, 8, -11, 11, + -5, -22, 7, 15, -17, -11, 18, 4, -54, 43, -38, 27, -1, 7, -13, 19, + 10, -41, 50, -41, 13, 9, 10, -41, 38, -13, 13, -2, -2, -4, 9, -36, + -5, 22, -31, -18, 8, 21, -22, 21, -24, 12, 3, 16, -24, 25, -16, 22, + -35, 14, 3, 11, 12, -22, 40, -11, -25, 14, 0, 14, -2, 2, -10, -12, + 14, -51, 11, -21, 55, -27, 9, 3, 38, 7, -25, 5, -19, 6, -14, 0, + -10, 21, -57, 35, 18, -21, 21, -40, -13, 24, -24, -12, 10, -1, 11, 10, + -12, -5, 38, -45, 23, 26, -13, -9, 32, 6, -3, 30, -28, -28, 27, 3, + -10, -11, -10, 16, -28, 21, -12, -3, -1, -33, 14, -30, 12, -20, 40, -15, + 7, 19, -18, -1, -1, 9, 4, -23, 32, 17, -19, 12, 16, -45, 4, -6, + 18, -28, 36, -44, 44, -29, 10, 4, 14, -8, -13, 9, -30, 39, -17, -5, + 10, -10, 5, -1, -16, 17, -7, -9, -10, 15, -21, 9, 10, 8, -10, -6, + 3, -21, 34, -3, 6, -4, 15, 3, -2, 4, 26, -44, 30, -43, 2, 9, + -5, -7, -18, 16, -28, 0, 5, -7, 0, 7, 0, -7, 21, -14, 17, 15, + 2, -40, 7, 44, -30, 55, -33, -19, 40, -30, 17, -1, -20, -20, -20, 5, + 14, 1, -7, -32, 26, -11, -11, 24, -23, 17, 17, 8, -19, 18, 11, -6, + 17, -4, -13, 14, -9, 21, 9, -16, -8, 2, -16, 3, -9, -32, 6, -36, + -4, 0, 10, -36, 26, -11, 3, 31, -20, 1, 7, 4, 45, -35, 39, 0, + 4, 28, -21, 29, -39, 27, 15, -6, -14, 17, -25, -33, 16, -15, 18, -43, + 28, -61, 33, 1, -27, 13, -19, -20, 26, 11, -27, 16, -21, 33, -13, 43, + -44, 13, 24, -10, 35, -39, 36, 20, -39, 68, -68, 23, -16, -7, 0, 36, + -30, -13, -27, 42, -21, -4, -23, -2, 23, 0, -3, -3, 2, 4, -15, -5, + 28, -10, -20, 24, -7, 27, -58, 31, -7, -29, 39, -40, 41, -35, 8, -25, + 30, 31, -17, -9, 3, 36, -8, -18, -11, 29, -2, 6, -25, 21, -5, -8, + -17, -24, 20, -26, 20, -23, 46, -26, -13, 8, 13, 2, -15, 4, -9, 28, + -25, -19, 49, 18, -50, 45, -11, -17, 5, -61, 15, 4, -22, -1, 22, 23, + 33, -55, 46, -25, 37, 18, 2, -9, 11, -47, 23, -8, -25, 37, -32, 2, + 5, 12, -18, -5, 19, -27, -7, 20, -40, 32, -44, -21, -29, 58, 8, -9, + 57, -28, 29, -32, 14, -14, 4, 23, -33, 16, -4, -16, 21, 38, -37, 23, + 10, -32, 17, 17, -12, -59, 9, -3, -12, 22, -13, -8, -26, 16, 1, 33, + -9, -17, 16, -7, 21, -44, 26, 5, 35, -36, -1, 13, 36, -36, 39, -36, + 17, -13, 2, -33, 20, -13, -51, -2, 9, -2, 35, -21, 19, -20, 18, -19, + -5, 30, -39, 30, 22, -35, 74, -52, 33, -15, 17, -21, -13, 11, 6, -25, + 25, -31, 29, -18, 18, -52, 40, -11, -17, -26, 56, -56, 69, -53, -14, 32, + -10, -8, -2, 18, -14, 20, -18, 20, 22, -27, 0, -25, 56, -46, 16, -28, + 52, -5, -33, 76, -75, 36, -1, -42, 42, -46, 13, -13, 25, -7, 35, -55, + 5, 63, -56, 11, -24, 13, -8, -10, -27, 15, -15, 44, -66, 52, -3, -6, + 0, 23, -33, 79, -55, 30, -27, 37, -18, -6, -2, -19, 52, -22, -50, 60, + -32, 28, -56, 44, -28, 15, -37, -9, -28, 63, -75, 9, 39, 28, -21, 5, + -17, 15, 2, -13, 30, 13, -14, 10, -12, 30, -22, -10, 4, -8, -9, 14, + 6, -39, 34, -6, 4, 1, -5, 0, 33, -73, 34, -12, 23, -9, 53, -47, + 17, 3, -18, -6, 2, -19, -12, -7, -45, 72, -9, -71, 55, -58, 50, -18, + -36, 37, 19, -11, 13, -35, 32, 6, 5, 18, -6, 19, -26, 32, 16, 20, + -43, 20, -10, -7, 16, -7, -68, 21, -36, 7, 19, -22, 19, -3, -35, -37, + 25, 21, -57, 67, -9, 9, 32, -11, 28, -18, 35, -41, 60, -19, 29, 0, + -38, 29, -6, -35, 0, 25, -37, -1, -31, -42, 30, -19, -21, 36, -66, 53, + -33, 15, 16, -13, 20, -35, 73, -4, 18, 39, 4, 1, 3, 21, -2, -12, + -18, -51, 44, -17, -50, 48, -30, -16, -13, -35, -7, 25, -33, -14, 14, 0, + 8, -30, 45, -13, 50, -53, 28, 60, -33, 23, -7, -2, 15, 36, -11, 9, + 19, -44, 4, -21, 19, -5, -27, -45, 48, 9, -47, -23, 12, 3, -25, -8, + -21, 63, 1, -29, 31, -18, 19, 16, -24, -17, 50, -65, 65, -56, 93, -45, + -17, -25, 45, -18, 23, -53, 50, -15, -12, -39, 51, -11, 11, 13, -31, 54, + -14, -29, 22, -11, 10, -41, -19, 52, 10, -51, -60, 72, -13, 12, -38, 19, + -2, 31, -56, 37, -4, -10, 22, -14, -33, 48, -40, 38, -14, 27, -24, 19, + 29, 17, -31, -2, -41, 34, -17, 2, 5, 5, -13, -30, 14, 9, -9, 7, + -11, 15, 5, -28, -2, 0, 45, -30, -25, 1, 10, 29, -55, -24, 52, -5, + 5, 20, -25, 20, -15, 14, -64, 95, -53, 32, 13, -26, 31, -8, -27, 18, + 48, -57, -3, -10, 25, -24, -32, -9, 18, 18, -33, -15, 27, -22, 14, -5, + 10, 51, -21, -25, 19, 5, -15, -29, 16, 1, 33, -39, -12, 56, 14, -63, + 36, -2, -17, 52, -11, -37, 5, 19, -52, 38, -23, -60, 93, -75, 52, -30, + -2, -11, 49, -11, -25, 1, 42, -35, 26, -35, -9, 24, -1, 10, -6, -12, + 7, 4, 22, -10, 41, -25, -8, -4, -2, 28, -43, 19, -32, 4, -27, 9, + -47, 51, -16, 12, -52, 49, 8, 7, -37, 27, -33, 80, -44, 6, 5, 28, + -15, 16, 15, 2, -12, 50, -77, 38, -38, -45, 30, 8, -37, -13, -8, -18, + 50, 3, -54, 29, 29, -20, 4, 52, -57, 62, -52, -2, -9, 62, -64, -5, + 24, 23, 0, -7, -23, 48, 25, -78, -9, 38, 18, -46, 30, -51, 39, 4, + -48, 22, 15, 13, -39, 8, 10, 31, -20, -22, 21, -17, 17, -23, 22, 22, + -24, -36, 11, 31, -16, -28, 34, -4, 0, -20, 6, -2, 35, -13, -60, 36, + 24, -45, 21, -2, 36, 0, -73, 66, -37, 39, -66, -18, 22, 17, -17, -25, + 24, 36, -47, 3, 25, 7, 8, 0, 1, 14, 20, -21, 4, 21, 12, -77, + 17, -4, -12, 31, -57, 38, -11, -4, -31, -6, 29, -34, 11, 13, -20, 82, + -36, -36, 40, -28, 77, -68, 12, 2, 34, -23, 5, -31, 11, -5, 44, -105, + 79, -31, -29, -16, 37, 8, 18, -14, -9, 32, -10, -11, -7, 0, 41, 34, + -56, 7, 13, -2, -31, 33, -67, 42, -31, -2, 22, -49, 18, -34, -11, 38, + -40, 56, -16, 14, -2, 24, 0, 0, 41, -21, -8, 6, -11, 11, 11, -45, + 26, 4, -17, -7, -26, -30, 7, -21, -29, 56, -29, 37, -3, 2, -8, -3, + 22, 11, 40, -13, 58, -6, -38, 48, -23, 15, -52, -14, -6, 49, -66, -20, + -11, 34, -32, -44, 41, 4, 20, -59, -24, 77, 23, -24, -17, 42, 19, -3, + -19, -34, 54, 17, -22, -17, 46, -24, -9, 3, -22, 40, -47, -49, 72, 4, + -18, -48, -33, 55, -4, -41, -51, 105, -26, -3, -22, 64, 28, -51, 31, 2, + 15, 27, -62, 18, 21, 6, -15, -54, 52, -14, -46, 7, -30, 32, -1, 6, + -37, 39, -3, -23, -20, 24, 23, 17, -25, -6, 67, -36, -11, -37, 56, -79, + 3, 30, 45, -39, -17, -2, 21, 2, -4, -3, 3, 1, 16, -16, 9, 30, + -37, 8, -6, 46, -65, 3, 14, -59, 104, -60, 2, 46, -29, -30, -2, -10, + 24, -52, 63, -31, 81, -85, 18, 35, 16, -32, -18, -24, 45, -16, -15, -13, + 37, -15, -20, -42, 91, -45, -15, -9, -16, 64, -11, -23, 31, -18, 38, -42, + 3, 12, 1, 5, -5, 22, -44, 69, -31, -18, 15, 21, -64, -13, 34, -37, + 30, -26, -15, 6, -3, 44, -28, 11, -3, -1, 16, -18, 25, -14, -26, 69, + -56, -5, 31, -51, 24, 3, -36, 9, 52, -34, 31, 21, -11, -68, 31, -24, + 53, -25, -29, 31, 23, -20, 9, -15, -11, 19, 12, -47, 84, -60, -16, -11, + 17, -4, -15, 30, -45, 32, 34, -63, -7, 68, 0, -35, 17, 7, 33, -31, + -8, 7, -32, 43, -13, -18, 15, 31, -32, -34, 5, 8, -16, 20, -26, -29, + 32, -9, -20, 17, 33, -31, -13, -5, 86, -52, 23, -19, 2, 13, 14, -7, + -20, 36, -16, -3, 8, 0, 14, -69, 76, -77, 25, -14, -17, 3, 39, -14, + -46, 31, -2, -7, 37, -45, -6, 24, 28, -37, 22, 13, -35, 4, 8, 23, + 7, -43, 53, -59, 23, 16, 4, -25, -15, 23, -9, -20, 26, -18, -1, 25, + -3, -48, 53, 2, -43, 7, 14, -34, 15, 28, -33, 53, -2, -59, 31, -34, + 40, 19, -27, 20, -2, 8, 2, 3, -8, -8, 4, -57, 62, 24, -72, -4, + 17, -17, -3, -10, -26, 42, -30, 12, -29, 31, -10, 3, 24, 2, 21, -1, + -36, 52, -7, 21, 14, -32, -18, 73, -45, -6, 8, -12, -66, 21, 25, -17, + -6, -35, -14, 27, 26, -47, 40, -51, 56, -19, -24, 31, 6, 4, 11, -3, + 37, -47, 41, -32, 50, 0, -72, 25, 16, -19, -1, -2, -4, -41, 20, 6, + 9, -3, -44, 32, -54, 83, -30, -26, -8, 46, -47, 29, 5, -19, 37, -9, + -20, 65, -14, -21, -4, 10, 28, -28, 18, -29, 35, -25, 3, -17, -31, 4, + -4, 0, -9, 41, -42, -34, 40, -15, 8, -24, -8, 36, 22, -18, -27, 70, + -39, 39, 1, -5, 57, -54, 12, 36, 3, -13, -1, -32, 69, 6, -64, -50, + 13, -13, -34, 22, -13, 0, -10, -38, 41, -11, -22, -3, 11, 4, 38, 22, + -10, 24, 32, -23, 23, -6, 8, -4, 21, -61, 66, -35, -41, 7, 5, -29, + -19, -45, 23, -2, 46, -84, 78, -59, 40, -10, -18, 79, -35, -5, -1, 36, + 16, 13, -21, -31, 52, 2, -50, 34, -5, -36, -37, 65, -42, 1, 16, -42, + 35, -8, -50, -6, 41, -16, 27, -41, 22, 64, -50, -11, 31, -18, -17, 5, + -3, 34, 34, -40, -41, 66, -37, 20, -11, -20, 29, -5, -14, -15, 45, -33, + -37, -11, 36, -25, 18, -8, 20, 1, -23, 60, -32, 0, 34, -24, -32, 64, + -39, -35, 48, -7, -13, 4, -39, 32, 0, 1, -31, 2, -12, 43, -38, -8, + 26, 0, -57, 53, 19, -22, -10, 17, -30, 57, 6, -31, 33, 10, 0, -48, + 29, -4, -23, 6, -7, 31, -39, 15, -41, 38, -19, 5, -37, 23, 11, -28, + -14, 59, -48, 8, 22, -20, 50, 15, -34, -26, 67, -8, -15, -21, 53, -27, + -9, 13, -24, -35, -10, 9, -15, -13, 18, -38, 28, 22, -14, 2, -22, 42, + -20, 22, 12, -20, 45, -16, 17, -16, 22, 34, -27, -13, -7, 1, -21, -1, + 13, -44, 36, -51, -8, 16, -7, -30, -46, 90, -54, 35, 1, 11, 9, 5, + 1, -19, 20, 11, 21, -1, -49, 41, -6, 0, 37, -74, 9, 20, -12, -47, + 65, -68, 28, -5, -26, 15, 14, -3, -23, 8, 18, -22, 13, 3, 31, -21, + -5, 8, 24, -21, 48, -20, -21, 41, -43, 4, 18, 21, -60, 9, -27, 1, + 13, -15, -33, 15, 23, -48, -8, 53, -50, 1, 6, -40, 90, -10, -15, 51, + -52, 53, 29, -68, 50, 52, -30, -21, 7, -1, -8, -29, 11, -47, 6, 18, + -12, -25, 53, -34, -23, -6, 19, -7, -13, 7, 5, -2, 14, 11, -15, 51, + -29, 6, 12, 20, -27, 29, -12, 4, -18, -5, 2, -17, 10, -19, 2, -8, + -5, 56, -82, 49, 0, -42, 48, -25, 19, 6, -41, 17, 35, -18, -17, -29, + 26, 10, 4, -24, 26, -35, 47, -36, 2, 2, -23, 27, -42, 55, 0, -21, + 19, 21, -8, 1, -3, -15, 7, 12, -23, -29, 47, -12, 4, -28, 17, 16, + -7, -31, -8, 25, -6, 0, 13, -20, 6, 3, -7, 19, -21, -37, 27, 41, + 7, -14, 12, -59, 57, 6, -49, -2, -8, 0, 19, 13, -20, -5, 16, 23, + 4, -15, -33, 14, 2, 15, -26, -28, 10, 45, -17, -24, 14, 17, -39, 22, + -8, 48, -51, -1, -16, 52, -34, -21, 11, 13, 18, -57, 26, 15, 27, -36, + -12, 40, -7, -14, 15, -86, 91, -20, -13, -7, 53, -43, 33, -25, 13, 3, + -38, -19, 28, 28, -18, -74, 58, -3, 40, -27, -34, 30, 28, -1, -22, 2, + 9, -8, -12, 12, 21, -35, -2, -17, 17, 2, -27, 22, -36, 38, -11, 2, + -20, 7, 20, -29, 39, 11, -3, 9, -24, 47, -36, 28, -14, -16, 38, -37, + 12, -15, 18, -69, 56, -31, 17, -16, -18, -13, 21, -6, -9, -25, 37, 6, + -1, -2, 5, -1, -26, 39, 6, -3, -10, 0, 12, 30, -12, -31, 24, 13, + -14, 9, -23, 31, -43, -17, -2, 13, -23, -14, -21, 21, 19, -22, -12, 24, + 41, -26, 10, 12, 19, -3, 9, -12, 26, 12, -52, -4, 16, -3, 0, -43, + 7, 5, -14, -9, 12, -28, 15, -23, -2, 35, -12, -8, -10, 24, 57, -55, + 26, -18, 19, 44, -30, 0, -5, 50, -56, -1, 8, -5, -39, 9, 19, -39, + 38, -73, 30, -1, 2, 16, -24, 6, 29, -71, 70, -18, -6, 8, 31, 4, + -13, 23, -11, 31, -56, 57, -25, 10, 15, -44, -10, 16, -17, -44, 18, -28, + 10, 8, -21, -4, -9, 28, 20, -16, 17, -17, -6, 30, 0, 11, -21, 25, + 25, -1, 31, -56, 31, 14, -32, 2, -19, 4, -17, -26, -13, 42, -59, 15, + -29, 53, -4, 1, -23, 13, 31, 5, -22, 3, 30, -28, 2, -24, 37, 1, + -3, -18, 18, 41, -40, 3, -40, 48, -31, -5, -20, 5, 9, 0, -30, -1, + 26, -15, -5, -6, 51, -25, -27, 7, 44, -11, 10, -32, 14, 46, -31, 6, + -11, 37, -33, -14, 19, -4, 22, -50, 26, -45, 21, 1, -23, 10, -15, 17, + -63, 53, -14, -18, 56, -49, 21, 25, -7, 4, -21, 52, -33, 19, 3, 11, + -9, -7, 0, -49, 22, -17, 25, -10, -11, 5, -19, 35, -26, 20, -7, -21, + 37, -25, 29, -23, 3, 6, 17, -26, 27, 5, -16, 10, -9, -24, 11, -4, + -17, 9, -5, -13, 1, -2, 10, 5, -13, 21, 0, 8, 9, -22, 12, 13, + -24, -3, -22, 42, -18, 3, -4, -15, 1, -2, 8, -17, -13, -2, 1, 23, + 10, -2, -31, 23, 17, -15, -9, -24, 31, 2, 19, -24, 4, -22, 28, -5, + -20, 34, -57, 26, 71, -51, 28, -24, -12, 28, 10, -35, -4, -6, 7, -7, + 8, -52, 61, -52, 7, -9, -21, 9, 18, -19, 3, 34, -53, 56, -29, 20, + -11, 22, 4, -1, 23, 2, 1, 24, -15, 3, -32, 13, 21, -37, 6, -11, + -25, 22, 7, -2, -41, 4, 10, -30, 39, -24, -7, 8, 12, 9, -1, -35, + 13, 3, 9, -18, 21, 26, -14, 41, -8, -35, 31, -29, 17, -20, -12, 20, + -30, 27, -26, 21, -9, -6, 5, -14, 3, -11, 15, 2, 8, -14, -5, 20, + 4, 0, -31, 9, 4, 25, -24, 5, -5, -13, 27, -7, -32, 1, -5, -10, + 28, 7, -4, 11, 10, 22, -3, -22, -15, 6, -3, -3, -27, -25, 5, 8, + -10, -17, 18, -18, 12, 32, -18, 1, 25, -25, 50, 7, 2, 0, -3, -3, + 16, -20, 9, -14, -15, 21, -27, -3, -17, 23, -31, -4, -18, 31, -21, 6, + 0, 18, -16, 27, 3, -7, -17, 17, -15, -11, 19, -16, 6, 1, 12, -18, + 5, -6, 24, 0, -19, 22, -23, 43, -35, 18, 22, -40, 1, 12, -4, -18, + 26, -53, 34, 1, -10, 1, -18, 27, -25, -24, 33, -31, 9, -43, 53, -29, + 33, -17, 5, 23, -7, 2, 23, 29, 1, -8, 20, -10, -1, -22, -3, -17, + 4, 22, -61, -23, 31, -26, -29, -12, 2, -3, 12, 10, 26, 5, -29, 61, + -9, 32, -18, -14, 29, 31, 2, -19, 9, 31, -20, -31, -7, 5, -22, -47, + 31, -40, 15, -39, 22, -27, 40, -78, 31, 4, -19, 33, -13, -8, 41, -1, + 5, -12, 53, -51, 22, -1, 18, 28, -29, -1, 0, 0, 11, 13, -2, -7, + -5, -3, -3, 1, 2, -6, 0, 3, 8, 9, 5, 0, 14, -5, -28, -39, + -39, -36, -37, -27, -43, -49, -13, 4, 6, -7, 0, -1, 3, 23, 39, 29, + 35, 41, 21, 35, 0, 0, 21, 59, 67, 31, 21, 13, -3, 18, 34, 28, + 5, 3, 13, 3, 0, 12, -7, -33, -27, -39, -14, -34, -50, -30, -37, -35, + -53, -74, -70, -61, -62, -62, -50, -44, -61, -36, -3, -23, -15, -12, -17, -20, + -6, 11, -6, -12, -6, -17, 7, 46, 71, 87, 79, 70, 77, 104, 109, 66, + 37, 34, 27, 31, 40, 43, 31, 23, 17, 2, 10, 24, 32, 66, 56, 17, + -13, -55, -54, -21, 19, -19, -56, -77, -37, -27, -10, -6, -38, -36, -37, -3, + 23, 25, 25, 19, 35, 34, -7, -5, 28, 60, 66, 65, 51, 34, 22, 53, + 51, 15, 20, 11, 21, 21, 16, 24, -2, -23, -36, -35, -21, -29, -51, -51, + -47, -57, -85, -80, -70, -100, -97, -82, -78, -76, -64, -51, -56, -54, -49, -70, + -62, -53, -54, -60, -57, -65, -78, -76, -62, -39, 0, 31, 13, 6, 31, 54, + 55, 43, 30, 13, 9, 31, 23, 43, 28, 24, 36, 36, 24, 30, 54, 70, + 113, 103, 75, 4, -3, 40, 55, 50, 23, 9, 25, 29, 48, 41, 29, 14, + 6, 40, 63, 49, 39, 71, 80, 64, 21, 12, 17, 29, 68, 71, 52, 36, + 24, 37, 24, 1, 5, 3, -6, -4, 1, 13, -3, -22, -35, -31, -27, -58, + -59, -43, -55, -71, -76, -71, -88, -103, -95, -98, -85, -77, -68, -71, -58, -50, + -47, -52, -46, -40, -47, -44, -48, -56, -60, -91, -96, -68, -15, -6, -16, 9, + 3, 29, 31, 29, 8, 10, -6, 5, 10, -6, -4, -6, 15, 7, -2, 2, + -5, 30, 91, 107, 74, 8, -3, 14, 27, 32, 26, 17, 21, 18, 34, 49, + 20, -3, 2, 30, 42, 20, 36, 68, 79, 81, 52, 27, 22, 37, 80, 95, + 77, 77, 72, 74, 57, 55, 56, 41, 35, 22, 40, 58, 32, 23, 24, 26, + 0, -7, 6, -2, -16, -26, -31, -45, -46, -64, -77, -79, -73, -72, -75, -59, + -49, -56, -35, -48, -44, -50, -43, -59, -58, -40, -78, -119, -123, -95, -73, -40, + -52, -45, -29, -18, -3, -1, -11, -21, -28, -12, -24, -29, -21, -29, -16, -3, + -5, -30, -40, 1, 69, 96, 78, 31, 14, 23, 17, 19, 33, 20, 9, 9, + 45, 50, 14, 3, 12, 13, 16, 7, 14, 35, 54, 75, 56, 24, 1, 18, + 47, 47, 60, 62, 66, 69, 46, 54, 53, 38, 11, 18, 44, 41, 28, 33, + 37, 22, 14, 15, 13, 13, 1, -1, -13, -6, -11, -38, -33, -47, -40, -46, + -31, -29, -22, -9, -5, -9, 9, 4, -23, -14, -4, -3, -26, -69, -87, -74, + -60, -42, -49, -33, -28, -16, 9, 2, -16, -22, -25, -25, -33, -32, -44, -58, + -41, -11, -19, -51, -77, -43, 24, 47, 49, 34, 21, 5, -9, 5, 18, -10, + -14, 2, 23, 26, -3, -7, -4, 2, -3, -10, -4, -6, 38, 64, 50, 25, + 1, 11, 17, 21, 36, 58, 62, 46, 46, 61, 56, 27, 11, 20, 18, 27, + 15, 31, 26, 23, 17, 7, 16, 0, -9, -10, -3, -8, -14, -25, -36, -56, + -41, -39, -50, -30, -12, -23, -8, 10, 23, 17, -2, 3, 14, 26, 7, -33, + -48, -53, -52, -35, -30, -30, -23, 3, 21, 17, 8, 7, -8, -1, 0, -6, + -29, -50, -26, 10, 5, -38, -64, -41, 5, 22, 49, 63, 38, 20, 13, 26, + 15, -7, -9, -1, 28, 9, 1, -4, -12, -1, -5, -20, -38, -32, 6, 38, + 36, 16, 10, 0, -8, -13, 15, 41, 25, 30, 30, 52, 35, 17, 8, 3, + -5, -5, -6, 4, 7, 4, 4, 3, 3, -20, -25, -23, -28, -22, -18, -47, + -50, -54, -62, -67, -62, -48, -43, -44, -31, -10, 17, 10, -8, 1, 22, 24, + 17, -1, -21, -40, -39, -26, -38, -32, -21, 2, 17, 26, 29, 18, 5, 15, + 35, 19, -11, -37, -9, 33, 17, -6, -30, -23, -10, 22, 65, 73, 71, 47, + 57, 66, 38, 15, 16, 23, 34, 35, 27, 10, 11, 21, 32, -4, -26, -29, + 4, 29, 28, 38, 32, 17, -6, -6, 17, 32, 21, 31, 39, 49, 36, 27, + 25, 13, -1, -11, -8, -1, -15, -11, 4, -7, -9, -14, -38, -46, -35, -31, + -43, -53, -54, -72, -84, -88, -86, -79, -73, -86, -69, -40, -16, -23, -28, -13, + -9, 5, 5, -10, -34, -45, -48, -52, -61, -59, -42, -38, -9, 13, 19, 8, + -14, 18, 42, 28, -18, -31, -3, 11, 21, 13, -9, -17, -22, 9, 57, 71, + 62, 68, 83, 82, 65, 38, 38, 31, 52, 57, 45, 23, 25, 51, 56, 21, + -2, -8, 7, 21, 28, 55, 55, 37, 15, 17, 30, 30, 30, 48, 55, 65, + 55, 54, 61, 42, 24, 22, 13, 6, 6, 4, 4, 17, 19, 1, -20, -23, + -25, -27, -26, -44, -44, -62, -79, -91, -83, -76, -99, -104, -87, -63, -51, -40, + -42, -40, -29, -16, -6, -31, -40, -47, -63, -68, -81, -76, -81, -75, -49, -15, + -5, -34, -38, 2, 15, 8, -29, -43, -33, -18, -11, 8, -9, -42, -45, -14, + 25, 33, 41, 54, 67, 75, 71, 46, 30, 23, 52, 55, 38, 20, 25, 53, + 59, 35, 17, 6, 3, 5, 27, 64, 61, 49, 40, 40, 45, 36, 38, 63, + 69, 69, 77, 85, 78, 76, 63, 48, 38, 42, 28, 15, 30, 35, 41, 27, + 14, 0, -4, -2, -14, -16, -15, -35, -65, -63, -56, -64, -80, -94, -77, -71, + -46, -34, -42, -37, -21, -6, -5, -16, -20, -35, -44, -62, -66, -66, -96, -94, + -58, -26, -32, -44, -50, -14, 2, -9, -26, -41, -53, -49, -27, -5, -28, -59, + -65, -47, -20, -11, 7, 15, 28, 51, 57, 32, 7, 2, 30, 32, 15, 0, + 7, 30, 30, 24, 21, -2, -19, -20, 6, 37, 40, 31, 40, 45, 30, 29, + 35, 49, 52, 69, 74, 78, 89, 79, 72, 62, 60, 51, 37, 29, 29, 42, + 51, 46, 30, 32, 18, 2, 8, 13, 15, -13, -35, -35, -38, -40, -53, -71, + -70, -58, -34, -38, -32, -28, -9, 10, 10, 7, 11, -7, -28, -21, -26, -47, + -80, -84, -49, -18, -28, -38, -32, -8, -4, 4, 3, -23, -46, -44, -19, -5, + -22, -42, -55, -56, -35, -25, -12, -8, 11, 43, 51, 33, 1, 0, 24, 18, + 1, -5, 0, 1, 9, 15, 21, -2, -38, -36, -19, 2, 2, 19, 26, 19, + 20, 10, 11, 20, 31, 37, 49, 62, 64, 61, 60, 61, 50, 51, 32, 10, + 16, 27, 31, 33, 33, 36, 7, -6, 3, 14, 12, -10, -21, -40, -34, -33, + -47, -65, -67, -60, -40, -40, -44, -25, -10, -4, 14, 26, 22, 4, -7, 8, + 8, -22, -67, -65, -33, -19, -24, -20, -18, -8, 1, 26, 30, -2, -22, -25, + -6, 5, -1, -13, -38, -43, -31, -21, -16, -16, 9, 47, 61, 35, 22, 22, + 31, 24, 10, 13, 5, -2, 0, 28, 34, 1, -21, -30, -28, -18, -5, 5, + 18, 20, 14, 6, 6, 12, 9, 20, 33, 39, 51, 51, 42, 51, 51, 48, + 20, 9, 7, 5, 7, 15, 28, 19, -1, -16, -15, -4, 4, -16, -30, -41, + -45, -41, -50, -79, -77, -69, -65, -64, -56, -45, -40, -28, -4, 21, 17, -8, + -9, 21, 16, -18, -56, -58, -44, -39, -24, -22, -28, -22, -4, 29, 31, 13, + -9, -16, -3, 11, 13, 1, -18, -33, -15, -11, -23, -22, 11, 52, 58, 50, + 46, 50, 49, 36, 40, 40, 17, 6, 20, 37, 45, 29, 9, -7, -12, -11, + -6, 9, 30, 25, 26, 26, 17, 19, 15, 21, 24, 46, 55, 47, 43, 56, + 64, 52, 33, 25, 13, -3, 2, 10, 21, 26, 4, -15, -16, -13, -2, -11, + -32, -43, -37, -44, -61, -77, -78, -82, -82, -80, -71, -61, -72, -59, -21, 5, + -2, -27, -10, 15, 7, -14, -44, -59, -67, -55, -37, -38, -50, -45, -23, 5, + 23, 9, -6, -19, -15, 5, 14, 2, -22, -22, -10, -17, -35, -38, -3, 35, + 38, 43, 57, 51, 44, 49, 57, 46, 25, 14, 24, 35, 54, 41, 31, 22, + 1, -7, -4, 12, 23, 34, 37, 35, 35, 36, 26, 24, 33, 55, 62, 53, + 58, 70, 70, 73, 62, 51, 38, 14, 6, 20, 31, 32, 27, 4, -9, -1, + 9, -8, -21, -22, -27, -33, -53, -64, -67, -82, -86, -83, -67, -75, -97, -77, + -36, -15, -27, -32, -18, -1, -1, -6, -31, -62, -73, -68, -52, -52, -68, -69, + -50, -21, -2, 4, -10, -33, -29, -4, 2, -10, -29, -22, -8, -27, -55, -49, + -27, -6, 12, 31, 43, 31, 38, 44, 54, 48, 25, 11, 19, 30, 36, 41, + 41, 29, 11, -1, -9, 0, 15, 27, 34, 36, 46, 46, 26, 27, 39, 51, + 59, 62, 62, 73, 76, 77, 85, 78, 58, 35, 23, 21, 37, 53, 37, 22, + 15, 16, 20, 3, 0, -2, -2, -14, -33, -35, -45, -69, -77, -59, -53, -76, + -96, -74, -41, -30, -25, -26, -19, -4, 7, 11, -8, -40, -62, -62, -51, -55, + -69, -74, -71, -44, -15, -2, -14, -36, -38, -8, -7, -27, -33, -17, -12, -38, + -51, -57, -58, -41, -14, 8, 19, 15, 15, 31, 46, 40, 21, 9, 7, 10, + 20, 25, 33, 28, 16, 1, -18, -13, 0, 6, 12, 30, 39, 39, 26, 20, + 32, 41, 45, 53, 64, 63, 62, 80, 84, 87, 81, 51, 29, 21, 44, 52, + 41, 33, 29, 31, 27, 12, 8, 16, 10, -4, -7, -7, -29, -62, -57, -37, + -44, -68, -81, -70, -48, -33, -23, -22, -17, -5, 16, 31, 14, -15, -33, -42, + -41, -37, -53, -65, -74, -54, -16, 2, -12, -33, -19, -1, -10, -22, -17, -8, + -8, -18, -33, -48, -62, -57, -31, -1, 7, 0, 9, 22, 40, 40, 27, 14, + 4, 3, 10, 14, 21, 31, 20, 0, -13, -19, -17, -15, -7, 12, 29, 28, + 13, 20, 18, 18, 31, 38, 47, 49, 51, 56, 67, 87, 84, 56, 30, 20, + 31, 41, 31, 24, 32, 33, 20, 7, 14, 15, -2, -1, 13, 4, -28, -53, + -45, -34, -38, -59, -75, -72, -58, -44, -26, -26, -29, -8, 14, 34, 28, 10, + -9, -22, -26, -24, -30, -54, -78, -56, -13, -4, -17, -16, -5, 1, -6, -9, + -8, -1, 3, -2, -4, -28, -53, -58, -37, -10, 1, -1, 6, 20, 34, 46, + 40, 25, 19, 11, 7, 10, 23, 33, 28, 16, -3, -3, -17, -31, -14, 4, + 15, 20, 20, 16, 10, 14, 19, 23, 37, 45, 35, 37, 53, 76, 83, 62, + 34, 20, 27, 28, 13, 17, 29, 21, 7, 9, 13, -4, -17, -4, 13, 2, + -27, -53, -47, -39, -46, -56, -77, -87, -77, -58, -45, -46, -47, -33, -6, 17, + 22, 16, 1, -20, -25, -10, -21, -57, -79, -57, -32, -24, -23, -18, -3, -1, + -6, -4, -4, -5, 3, 13, 14, -6, -38, -51, -39, -22, -4, -1, 3, 14, + 32, 45, 46, 46, 33, 25, 15, 9, 28, 38, 32, 28, 26, 14, -9, -21, + -15, -5, 10, 24, 22, 22, 21, 15, 15, 23, 36, 42, 35, 31, 41, 72, + 87, 68, 46, 42, 34, 19, 14, 25, 25, 11, 14, 18, 14, -7, -24, -7, + 12, 4, -19, -41, -47, -44, -41, -52, -74, -92, -88, -72, -59, -63, -68, -53, + -34, -11, 12, 19, -7, -27, -15, -5, -22, -54, -76, -66, -52, -47, -41, -29, + -17, -12, -12, -10, -11, -19, -7, 12, 19, 3, -23, -42, -48, -31, -19, -14, + -6, 1, 20, 35, 39, 50, 51, 33, 16, 17, 30, 31, 32, 41, 39, 28, + 14, -7, -14, -5, 8, 18, 27, 34, 29, 22, 21, 26, 38, 51, 39, 27, + 43, 75, 84, 73, 75, 68, 46, 32, 31, 35, 27, 15, 23, 36, 26, 0, + -13, -4, 12, 14, 1, -23, -36, -36, -32, -36, -60, -83, -84, -70, -67, -70, + -66, -67, -62, -27, 8, 13, -11, -22, -7, 4, -16, -44, -63, -67, -63, -63, + -53, -42, -33, -25, -15, -10, -22, -27, -18, -1, 16, 9, -13, -32, -46, -42, + -31, -30, -24, -8, 5, 11, 25, 49, 50, 33, 25, 20, 21, 24, 29, 34, + 41, 41, 26, 5, -5, -7, -4, 12, 23, 33, 37, 29, 19, 24, 49, 53, + 33, 33, 49, 65, 73, 80, 89, 85, 63, 48, 50, 46, 30, 20, 35, 46, + 39, 17, 0, 2, 15, 23, 18, -2, -20, -24, -12, -19, -45, -60, -66, -70, + -66, -56, -61, -74, -74, -38, 0, 6, -8, -15, 3, 13, -1, -24, -42, -52, + -65, -64, -54, -54, -47, -31, -19, -12, -21, -32, -27, -12, 7, 13, -2, -24, + -36, -37, -44, -47, -32, -20, -18, -9, 12, 30, 38, 35, 26, 18, 17, 16, + 13, 25, 36, 37, 32, 18, 2, -11, -10, -5, 3, 28, 38, 20, 8, 25, + 42, 40, 28, 30, 40, 46, 54, 70, 87, 82, 66, 61, 59, 48, 28, 20, + 32, 43, 43, 24, 8, 1, 7, 23, 25, 3, -13, -9, -8, -15, -28, -40, + -58, -71, -60, -49, -58, -80, -82, -50, -17, -5, -13, -12, 6, 13, 8, -3, + -24, -42, -54, -59, -57, -60, -59, -43, -24, -15, -20, -30, -35, -25, 1, 11, + -2, -12, -18, -33, -48, -49, -41, -37, -32, -21, -8, 13, 27, 27, 27, 23, + 16, 8, 7, 15, 22, 32, 35, 22, 9, 0, -18, -26, -8, 20, 25, 11, + 4, 18, 32, 29, 22, 29, 30, 27, 38, 60, 75, 70, 68, 69, 67, 52, + 30, 19, 27, 36, 40, 34, 10, -2, 6, 21, 20, 4, -2, -4, -7, -9, + -12, -25, -52, -66, -53, -42, -53, -79, -86, -58, -33, -23, -16, -12, 0, 12, + 17, 13, -5, -24, -38, -44, -50, -59, -61, -51, -33, -15, -11, -28, -36, -23, + -4, 5, 5, 7, -3, -17, -31, -40, -38, -37, -36, -29, -14, 4, 15, 25, + 34, 30, 24, 19, 9, 8, 22, 33, 31, 30, 31, 16, -14, -26, -13, 14, + 17, 7, 8, 18, 24, 23, 28, 31, 23, 18, 30, 50, 62, 61, 63, 75, + 73, 59, 40, 23, 20, 30, 43, 35, 11, 0, 8, 15, 12, 6, 3, -6, + -10, -3, -1, -15, -46, -62, -47, -38, -54, -77, -84, -70, -53, -40, -30, -21, + -12, 1, 16, 20, 5, -12, -21, -33, -44, -52, -64, -64, -44, -17, -15, -27, + -30, -26, -15, -3, 6, 12, 9, -2, -17, -26, -29, -36, -41, -32, -21, -10, + 6, 18, 27, 34, 37, 25, 11, 14, 21, 26, 27, 37, 48, 33, -1, -19, + -8, 7, 8, 8, 16, 16, 17, 25, 34, 36, 23, 16, 28, 44, 53, 54, + 61, 74, 79, 75, 56, 30, 19, 31, 45, 35, 15, 9, 9, 9, 11, 9, + 5, -8, -14, 0, 9, -10, -40, -53, -44, -38, -51, -72, -84, -80, -69, -58, + -45, -38, -30, -13, 5, 13, 8, 0, -14, -25, -30, -46, -67, -72, -55, -34, + -26, -28, -31, -31, -26, -17, -4, 9, 11, 2, -4, -12, -22, -33, -38, -40, + -34, -18, -7, 2, 17, 33, 38, 29, 19, 20, 22, 17, 19, 38, 57, 43, + 15, 2, -1, 1, 3, 10, 18, 15, 14, 25, 38, 40, 27, 21, 28, 38, + 46, 50, 55, 66, 81, 90, 71, 40, 30, 37, 44, 39, 26, 18, 12, 8, + 14, 19, 8, -11, -13, 5, 15, -2, -28, -42, -36, -34, -45, -60, -76, -83, + -77, -65, -59, -55, -43, -28, -13, 5, 11, 2, -9, -11, -17, -37, -61, -71, + -65, -49, -38, -36, -34, -35, -36, -32, -16, -2, 1, 3, 0, -7, -13, -25, + -39, -46, -42, -30, -22, -15, 2, 21, 30, 24, 22, 28, 19, 5, 11, 33, + 50, 45, 31, 17, 6, -1, 0, 8, 16, 12, 11, 23, 37, 40, 33, 29, + 29, 33, 45, 48, 46, 58, 83, 97, 84, 59, 45, 46, 47, 46, 42, 31, + 16, 12, 23, 29, 16, -5, -9, 10, 21, 10, -12, -24, -25, -25, -29, -42, + -64, -73, -70, -66, -63, -58, -52, -42, -22, 0, 8, 4, 1, 3, -1, -19, + -44, -61, -63, -57, -50, -39, -33, -37, -39, -36, -27, -14, -4, 0, 0, 0, + -1, -13, -30, -42, -43, -37, -36, -30, -10, 8, 12, 15, 26, 31, 16, 1, + 4, 21, 37, 41, 38, 29, 13, 0, -1, 6, 8, 3, 7, 17, 26, 34, + 35, 27, 24, 32, 40, 37, 32, 45, 72, 89, 86, 70, 57, 48, 45, 49, + 50, 37, 16, 11, 25, 34, 20, -3, -7, 7, 18, 15, 2, -14, -20, -15, + -17, -32, -49, -61, -67, -65, -60, -61, -63, -54, -33, -12, -1, 1, 2, 10, + 12, -3, -26, -43, -57, -60, -54, -45, -38, -38, -39, -39, -35, -23, -13, -6, + -3, 2, 7, -2, -20, -30, -34, -42, -47, -38, -19, -9, -5, 7, 24, 31, + 19, 3, 0, 10, 23, 33, 40, 36, 18, 5, 4, 4, 0, 0, 0, 5, + 16, 29, 30, 22, 22, 31, 36, 27, 21, 32, 54, 74, 81, 77, 65, 49, + 44, 50, 55, 40, 16, 10, 24, 31, 20, 3, -6, -1, 11, 16, 5, -9, + -13, -12, -14, -22, -36, -53, -63, -62, -59, -63, -69, -67, -48, -25, -14, -10, + -1, 10, 16, 10, -6, -26, -45, -54, -55, -50, -42, -39, -39, -40, -39, -29, + -19, -15, -8, 4, 11, 3, -6, -11, -21, -38, -48, -40, -26, -21, -16, -3, + 18, 30, 24, 12, 6, 4, 11, 29, 41, 39, 28, 18, 11, 8, 5, 1, + -4, -2, 11, 25, 25, 19, 23, 33, 35, 25, 17, 23, 39, 57, 74, 81, + 72, 53, 47, 56, 60, 44, 23, 16, 22, 29, 25, 10, -4, -3, 7, 11, + 6, -3, -9, -11, -9, -12, -26, -42, -56, -59, -55, -61, -73, -75, -60, -42, + -32, -23, -12, 0, 12, 15, 7, -10, -30, -46, -53, -53, -46, -41, -43, -45, + -41, -32, -30, -26, -14, -1, 5, 2, 3, 3, -9, -30, -43, -40, -31, -31, + -28, -12, 8, 20, 25, 22, 9, 0, 6, 21, 34, 39, 35, 26, 18, 16, + 14, 4, -7, -5, 9, 21, 19, 16, 23, 35, 37, 28, 20, 20, 26, 43, + 67, 82, 74, 57, 54, 62, 63, 52, 33, 21, 23, 30, 28, 14, 1, -1, + 3, 8, 7, -1, -7, -9, -6, -5, -15, -34, -49, -51, -51, -60, -72, -76, + -70, -57, -46, -37, -25, -13, 3, 14, 14, 3, -15, -33, -48, -52, -47, -45, + -49, -49, -41, -37, -39, -35, -21, -10, -5, -2, 6, 12, 1, -19, -32, -34, + -36, -39, -34, -23, -9, 9, 23, 25, 14, 3, 2, 12, 25, 36, 37, 30, + 24, 25, 24, 10, -5, -4, 9, 18, 15, 14, 23, 34, 38, 36, 30, 19, + 15, 32, 61, 78, 75, 63, 60, 67, 71, 62, 42, 29, 30, 33, 32, 20, + 8, 4, 6, 8, 8, 3, -5, -9, -2, 3, -7, -25, -37, -42, -45, -54, + -66, -74, -74, -67, -58, -49, -40, -27, -9, 5, 13, 13, 0, -21, -39, -45, + -44, -49, -54, -50, -44, -44, -47, -42, -29, -21, -19, -11, 5, 12, 4, -8, + -18, -28, -36, -40, -40, -36, -24, -4, 14, 21, 17, 7, 0, 3, 17, 32, + 34, 29, 28, 34, 33, 17, 0, 0, 9, 13, 12, 14, 20, 27, 38, 46, + 39, 21, 11, 24, 51, 71, 74, 66, 64, 73, 78, 71, 54, 40, 38, 41, + 38, 28, 17, 11, 9, 12, 14, 7, -3, -5, 3, 9, 2, -12, -23, -28, + -35, -45, -55, -65, -71, -68, -62, -57, -50, -37, -22, -7, 10, 20, 12, -8, + -24, -32, -39, -48, -52, -49, -45, -49, -52, -44, -34, -33, -30, -18, -3, 5, + 5, 1, -8, -19, -29, -37, -43, -45, -37, -18, 0, 13, 18, 10, -1, -3, + 10, 24, 26, 23, 29, 38, 37, 21, 8, 5, 6, 8, 10, 12, 11, 16, + 34, 49, 46, 27, 10, 15, 38, 59, 67, 63, 63, 72, 81, 77, 61, 48, + 45, 45, 42, 35, 23, 13, 11, 17, 18, 9, -3, -5, 3, 10, 6, -3, + -12, -19, -24, -34, -46, -57, -64, -65, -66, -63, -56, -48, -39, -22, 1, 17, + 16, 3, -8, -17, -30, -44, -47, -44, -47, -53, -52, -44, -41, -41, -38, -28, + -14, -3, 3, 3, -2, -9, -17, -28, -42, -49, -46, -34, -17, 3, 14, 9, + -3, -6, 5, 15, 13, 15, 26, 36, 35, 25, 16, 8, 2, 4, 9, 6, + 1, 4, 22, 43, 48, 31, 11, 7, 24, 45, 55, 54, 55, 68, 79, 77, + 66, 54, 48, 47, 47, 41, 27, 14, 11, 18, 20, 10, -2, -6, 0, 7, + 8, 2, -6, -12, -14, -23, -38, -49, -55, -62, -66, -63, -60, -59, -53, -37, + -12, 8, 13, 10, 7, -4, -21, -35, -37, -39, -47, -53, -51, -45, -44, -44, + -42, -36, -24, -10, 0, 2, 1, 1, -3, -15, -30, -42, -49, -45, -30, -6, + 10, 7, -2, -3, 5, 9, 6, 11, 23, 32, 35, 33, 25, 14, 6, 9, + 12, 8, -2, -4, 13, 36, 48, 39, 18, 7, 17, 34, 43, 45, 50, 62, + 74, 78, 71, 59, 51, 49, 52, 48, 32, 16, 12, 19, 21, 13, 1, -6, + -5, 2, 6, 2, -4, -6, -9, -18, -29, -40, -51, -60, -65, -63, -63, -68, + -68, -53, -30, -12, 0, 10, 13, 3, -14, -25, -29, -35, -45, -52, -52, -49, + -47, -47, -47, -46, -35, -20, -10, -5, -1, 4, 4, -4, -15, -30, -47, -54, + -41, -15, 1, 0, -2, 2, 6, 4, 3, 7, 16, 26, 35, 38, 32, 20, + 12, 14, 18, 12, -1, -8, 3, 27, 46, 44, 26, 14, 17, 28, 35, 38, + 44, 55, 69, 78, 77, 66, 55, 54, 60, 58, 41, 24, 17, 19, 23, 20, + 7, -4, -4, 0, 2, 1, 0, -2, -4, -10, -17, -28, -42, -55, -59, -56, + -61, -72, -74, -63, -47, -32, -14, 5, 13, 7, -4, -12, -19, -28, -38, -46, + -51, -50, -46, -47, -51, -52, -43, -30, -20, -13, -5, 0, 4, 4, 2, -13, + -40, -55, -47, -25, -12, -8, -3, 3, 5, 4, 2, 3, 7, 18, 32, 41, + 36, 25, 18, 21, 25, 21, 5, -9, -3, 19, 41, 45, 34, 24, 23, 27, + 30, 33, 38, 47, 62, 78, 82, 72, 61, 61, 67, 66, 54, 37, 24, 23, + 28, 25, 15, 5, 0, 0, 0, 1, 2, 2, -1, -4, -5, -15, -34, -47, + -49, -49, -58, -69, -73, -70, -63, -51, -30, -8, 5, 7, 3, -4, -11, -20, + -29, -41, -49, -50, -46, -49, -54, -56, -50, -42, -33, -22, -13, -10, -6, 5, + 12, -1, -30, -50, -50, -38, -27, -18, -10, -3, 1, 2, 2, -2, -4, 6, + 24, 36, 36, 27, 19, 22, 30, 28, 10, -8, -10, 9, 30, 39, 35, 30, + 26, 26, 28, 29, 29, 35, 53, 73, 80, 74, 65, 63, 69, 72, 64, 47, + 33, 28, 29, 28, 21, 12, 6, 2, -2, 1, 4, 1, -2, 2, 6, -4, + -23, -35, -38, -42, -51, -60, -66, -70, -71, -63, -45, -23, -5, 4, 6, 3, + -2, -7, -18, -32, -42, -43, -43, -47, -52, -54, -53, -51, -42, -27, -20, -21, + -14, 4, 17, 10, -13, -35, -45, -44, -37, -26, -17, -11, -3, 3, 3, -3, + -9, -4, 13, 31, 35, 27, 19, 23, 34, 36, 19, -3, -10, 2, 19, 31, + 35, 33, 29, 30, 32, 28, 22, 26, 43, 63, 76, 75, 67, 65, 71, 75, + 70, 57, 43, 36, 34, 30, 26, 21, 14, 5, 1, 4, 3, -2, -2, 6, + 11, 3, -11, -22, -29, -36, -43, -50, -57, -67, -74, -72, -60, -40, -19, -5, + 2, 4, 6, 3, -8, -23, -32, -35, -40, -45, -47, -51, -57, -58, -47, -33, + -30, -32, -24, -5, 13, 14, 1, -18, -36, -45, -42, -35, -27, -20, -11, 0, + 3, -3, -12, -12, 1, 21, 31, 25, 16, 20, 34, 40, 26, 5, -7, -6, + 7, 21, 27, 26, 27, 31, 33, 27, 17, 15, 28, 50, 65, 68, 64, 62, + 68, 74, 72, 61, 51, 44, 35, 29, 28, 25, 15, 7, 5, 5, -1, -8, + -5, 3, 8, 4, -4, -12, -22, -32, -38, -42, -50, -61, -72, -77, -73, -57, + -36, -20, -11, -2, 7, 8, -3, -14, -22, -30, -38, -41, -42, -49, -60, -62, + -52, -41, -40, -41, -34, -18, 0, 11, 10, -3, -23, -38, -42, -40, -36, -31, + -20, -6, 2, -1, -13, -19, -9, 12, 25, 20, 12, 17, 30, 39, 34, 17, + -2, -8, 1, 13, 19, 21, 23, 31, 37, 32, 18, 10, 18, 36, 55, 62, + 60, 60, 67, 73, 72, 68, 61, 51, 41, 35, 34, 28, 18, 12, 11, 8, + -2, -9, -7, 0, 4, 5, 3, -3, -14, -24, -31, -36, -41, -50, -64, -77, + -80, -68, -51, -37, -26, -11, 3, 6, 2, -3, -13, -24, -32, -33, -34, -46, + -60, -62, -54, -47, -46, -47, -43, -31, -13, 4, 12, 6, -9, -23, -34, -39, + -40, -38, -29, -14, 0, 2, -11, -22, -15, 4, 17, 16, 11, 13, 25, 39, + 41, 28, 9, -3, 0, 9, 15, 15, 19, 30, 40, 39, 26, 12, 11, 28, + 45, 54, 56, 60, 66, 70, 73, 74, 69, 58, 49, 45, 42, 32, 22, 18, + 19, 14, 3, -6, -7, -4, 0, 5, 6, 3, -5, -14, -24, -30, -32, -38, + -53, -71, -78, -72, -63, -54, -39, -22, -8, 1, 6, 6, -4, -18, -25, -23, + -25, -39, -54, -58, -54, -49, -49, -50, -49, -42, -26, -7, 7, 9, 2, -9, + -20, -30, -38, -43, -39, -22, -2, 3, -9, -20, -16, -2, 11, 14, 10, 10, + 20, 36, 46, 40, 22, 8, 6, 11, 13, 12, 15, 26, 41, 46, 36, 20, + 14, 24, 38, 47, 54, 60, 64, 69, 76, 81, 76, 66, 60, 58, 53, 40, + 30, 27, 27, 22, 12, 3, -3, -4, -1, 4, 8, 8, 5, -4, -15, -21, + -21, -25, -41, -58, -69, -71, -70, -64, -51, -35, -23, -9, 5, 10, 1, -13, + -17, -15, -19, -32, -46, -54, -54, -51, -50, -52, -55, -53, -40, -22, -6, 3, + 4, -2, -10, -19, -32, -47, -49, -32, -11, -3, -10, -20, -20, -10, 2, 7, + 5, 2, 10, 28, 42, 41, 29, 16, 10, 11, 11, 7, 6, 17, 35, 45, + 39, 26, 18, 19, 26, 37, 47, 53, 56, 61, 73, 81, 76, 68, 65, 65, + 59, 46, 36, 31, 28, 25, 19, 9, -1, -6, -4, -1, 2, 8, 9, 0, + -10, -15, -14, -18, -32, -46, -57, -68, -74, -71, -61, -51, -41, -23, -2, 8, + 2, -8, -11, -10, -13, -23, -37, -48, -53, -51, -49, -53, -59, -60, -53, -37, + -19, -7, -3, -2, -1, -6, -22, -43, -52, -42, -21, -9, -12, -20, -23, -16, + -4, 3, -1, -6, 0, 18, 34, 40, 33, 22, 16, 16, 13, 5, 0, 9, + 27, 39, 40, 32, 24, 18, 19, 29, 40, 44, 46, 55, 69, 77, 75, 71, + 70, 70, 65, 55, 45, 37, 32, 30, 26, 17, 7, 0, -5, -6, -1, 8, + 11, 4, -5, -7, -7, -13, -21, -30, -44, -59, -69, -69, -65, -63, -56, -36, + -13, 1, 1, -4, -6, -5, -6, -12, -25, -40, -47, -47, -46, -50, -56, -62, + -61, -48, -30, -18, -12, -6, 4, 6, -7, -32, -49, -46, -30, -16, -12, -19, + -25, -20, -7, 0, -3, -9, -7, 8, 26, 36, 34, 27, 24, 24, 19, 7, + -2, 4, 18, 31, 38, 38, 30, 20, 18, 26, 34, 35, 38, 48, 62, 71, + 73, 72, 73, 72, 70, 64, 53, 43, 38, 35, 30, 23, 16, 7, -4, -10, + -4, 6, 8, 3, -1, -2, -4, -9, -12, -19, -33, -51, -61, -65, -69, -73, + -70, -52, -30, -13, -6, -5, -7, -5, -2, -5, -17, -31, -41, -45, -44, -45, + -53, -64, -67, -58, -43, -31, -26, -17, -1, 10, 3, -19, -41, -48, -39, -23, + -16, -21, -27, -24, -12, -3, -5, -13, -15, -3, 16, 28, 29, 26, 28, 31, + 24, 10, 0, 0, 8, 20, 33, 38, 32, 22, 19, 24, 28, 28, 30, 40, + 52, 61, 68, 71, 72, 73, 73, 69, 59, 51, 45, 39, 32, 28, 26, 15, + 0, -9, -5, 2, 4, 2, 1, -1, -4, -6, -5, -10, -24, -41, -50, -56, + -66, -76, -77, -66, -47, -27, -15, -11, -10, -5, 0, -1, -8, -20, -33, -40, + -40, -40, -48, -62, -70, -64, -51, -43, -39, -29, -11, 7, 10, -5, -28, -43, + -41, -28, -20, -22, -29, -28, -17, -6, -5, -14, -20, -12, 6, 19, 22, 23, + 30, 35, 31, 20, 8, 0, 1, 13, 29, 37, 33, 26, 25, 27, 27, 25, + 26, 33, 43, 54, 63, 67, 70, 74, 76, 72, 66, 61, 54, 44, 37, 36, + 34, 24, 8, -3, -4, -2, 0, 2, 3, -1, -5, -3, 2, -2, -16, -29, + -36, -44, -57, -70, -79, -76, -60, -41, -27, -19, -14, -8, -1, 3, 0, -10, + -24, -33, -33, -32, -40, -55, -65, -63, -56, -51, -48, -40, -23, -1, 12, 7, + -13, -32, -37, -29, -21, -21, -28, -29, -19, -6, -2, -12, -20, -14, 0, 11, + 16, 22, 30, 37, 38, 33, 21, 7, 0, 9, 26, 36, 35, 32, 32, 32, + 31, 28, 27, 30, 38, 50, 58, 63, 70, 78, 79, 76, 74, 72, 64, 53, + 46, 45, 44, 34, 20, 9, 3, -1, 1, 7, 7, 0, -4, 2, 8, 5, + -5, -15, -23, -30, -41, -58, -73, -77, -68, -53, -38, -28, -21, -14, -5, 4, + 7, -1, -15, -25, -25, -24, -32, -48, -59, -61, -59, -57, -57, -54, -39, -16, + 4, 8, -5, -24, -33, -30, -24, -24, -32, -35, -26, -11, -6, -14, -20, -19, + -10, -2, 5, 13, 21, 29, 37, 40, 30, 11, 0, 4, 17, 27, 30, 31, + 31, 32, 32, 29, 23, 23, 31, 40, 45, 52, 63, 72, 74, 73, 75, 75, + 67, 56, 51, 50, 46, 38, 29, 18, 6, -3, -1, 5, 3, -4, -7, -2, + 4, 5, -2, -11, -17, -21, -30, -47, -66, -78, -77, -66, -53, -42, -34, -27, + -16, -3, 6, 1, -12, -21, -21, -21, -28, -42, -54, -60, -60, -61, -65, -67, + -57, -35, -11, 1, -3, -18, -30, -30, -25, -27, -36, -41, -32, -19, -13, -17, + -22, -22, -19, -14, -6, 2, 7, 17, 31, 41, 34, 17, 3, 1, 8, 17, + 23, 25, 26, 30, 32, 28, 22, 21, 25, 30, 34, 42, 54, 63, 66, 70, + 77, 77, 69, 61, 57, 55, 49, 44, 39, 28, 11, 2, 2, 5, 3, -3, + -8, -4, 3, 6, 2, -4, -9, -11, -16, -31, -52, -68, -75, -71, -61, -50, + -43, -38, -26, -8, 5, 4, -6, -13, -14, -13, -19, -31, -44, -51, -52, -55, + -64, -71, -67, -49, -24, -4, -1, -12, -22, -21, -18, -22, -33, -39, -33, -22, + -16, -16, -17, -19, -20, -16, -9, -4, -2, 5, 18, 31, 37, 32, 21, 11, + 9, 12, 17, 20, 24, 28, 32, 31, 28, 26, 26, 26, 28, 34, 43, 51, + 57, 65, 74, 77, 75, 72, 68, 63, 59, 56, 53, 44, 31, 19, 12, 11, + 8, 3, -2, -3, 0, 4, 5, 2, 0, -1, -3, -11, -25, -42, -58, -66, + -65, -59, -54, -51, -42, -27, -11, -2, -3, -6, -7, -7, -9, -16, -27, -36, + -40, -44, -52, -63, -70, -66, -49, -28, -15, -13, -16, -16, -13, -16, -24, -31, + -33, -29, -24, -19, -17, -19, -20, -18, -14, -13, -12, -6, 7, 22, 33, 35, + 28, 18, 12, 12, 14, 17, 21, 27, 31, 31, 30, 30, 28, 25, 25, 30, + 36, 42, 49, 58, 67, 74, 76, 75, 71, 66, 62, 60, 59, 53, 41, 29, + 19, 14, 11, 7, 1, -3, -2, 1, 3, 3, 1, 0, 0, -3, -11, -26, + -44, -59, -65, -63, -60, -57, -52, -41, -25, -11, -4, -4, -6, -6, -6, -9, + -17, -27, -35, -39, -44, -53, -65, -71, -65, -47, -28, -16, -15, -16, -15, -14, + -17, -25, -32, -33, -29, -24, -19, -17, -19, -20, -18, -14, -13, -12, -6, -2, + 1, 6, 5, 21, 46, 42, 15, 0, 5, 34, 48, 29, -4, -31, -33, -17, + 26, 49, 32, 0, -21, -15, 14, 24, 24, 16, 0, 3, 11, 11, 11, 5, + 9, 9, 8, 11, 30, 27, 22, 7, -3, -3, 10, 2, -2, -4, -13, -4, + -4, -2, -2, -3, -7, -6, -14, -15, -14, -14, -13, -3, -14, -16, -18, -13, + -15, -16, -22, -20, -14, -3, -6, -4, -14, -11, -6, -10, -15, -15, -16, -9, + -10, -19, -3, -5, -17, -15, -18, -16, -14, -14, -12, -15, -7, -22, -19, -17, + -20, -11, -17, -14, -11, -8, -10, -13, -12, -11, -6, -6, -9, 1, 1, -3, + 0, 6, -2, -9, 7, -8, 8, 4, 3, 1, -6, -2, -2, 2, -5, -7, + -4, -7, -8, -9, -6, -6, 0, -8, -12, -12, -13, -8, -4, -7, -3, -11, + -6, -15, -7, -9, -9, -3, -10, -8, -9, -15, -10, -2, 2, -7, -16, -17, + -15, -13, -9, -6, -5, -7, -9, -15, -17, -12, -19, -12, -8, -8, -4, -6, + -3, 0, -4, -11, -13, -7, -6, -2, 4, 4, 8, 10, 4, 3, 3, 4, + 7, 12, 11, 14, 15, 20, 20, 18, 16, 17, 15, 14, 15, 22, 23, 28, + 34, 29, 28, 17, 22, 24, 23, 25, 28, 28, 30, 24, 19, 16, 13, 18, + 20, 15, 8, 2, 3, 0, 2, 0, -3, -2, -9, -20, -23, -25, -24, -23, + -27, -33, -38, -39, -44, -36, -42, -44, -48, -53, -54, -56, -52, -50, -40, -35, + -44, -43, -44, -39, -28, -24, -23, -22, -15, -9, 2, 11, 19, 28, 31, 31, + 32, 35, 43, 61, 70, 78, 81, 73, 78, 78, 78, 85, 82, 85, 88, 87, + 84, 83, 83, 79, 74, 62, 49, 45, 42, 43, 44, 38, 30, 18, 6, -5, + -15, -17, -15, -22, -28, -38, -46, -48, -50, -58, -59, -72, -80, -83, -89, -88, + -89, -87, -81, -84, -93, -105, -110, -109, -110, -102, -96, -82, -65, -62, -60, -60, + -60, -51, -43, -37, -28, -16, 1, 15, 28, 35, 41, 46, 53, 56, 60, 66, + 77, 91, 101, 102, 101, 99, 104, 103, 97, 91, 86, 90, 91, 86, 85, 79, + 75, 71, 59, 48, 39, 35, 33, 32, 28, 22, 15, 13, 7, 3, -7, -15, + -16, -18, -19, -23, -28, -29, -33, -37, -47, -52, -56, -63, -61, -70, -67, -70, + -72, -72, -80, -93, -91, -99, -103, -96, -108, -105, -109, -112, -94, -81, -73, -67, + -71, -77, -69, -63, -57, -38, -27, -15, 0, 4, 6, 19, 26, 41, 53, 49, + 56, 58, 69, 84, 91, 95, 101, 103, 98, 93, 85, 87, 102, 102, 103, 95, + 81, 78, 78, 71, 66, 60, 51, 50, 44, 39, 34, 34, 32, 27, 15, 0, + -6, -8, -3, -3, -11, -10, -18, -21, -26, -35, -39, -38, -44, -48, -53, -63, + -61, -61, -71, -63, -86, -89, -86, -107, -99, -109, -108, -109, -108, -121, -128, -105, + -102, -83, -67, -88, -82, -76, -78, -62, -47, -41, -19, -6, 1, 7, 13, 33, + 44, 64, 61, 59, 68, 73, 93, 98, 107, 114, 109, 123, 107, 100, 105, 100, + 111, 117, 100, 93, 92, 86, 85, 80, 70, 59, 58, 47, 38, 41, 33, 40, + 38, 25, 16, 1, -2, -3, -3, -4, -10, -16, -12, -21, -28, -28, -36, -38, + -39, -52, -61, -61, -67, -63, -65, -76, -77, -86, -95, -95, -107, -109, -112, -112, + -121, -121, -122, -105, -79, -80, -71, -80, -84, -73, -70, -56, -43, -28, -10, 6, + 11, 17, 31, 43, 63, 69, 69, 65, 77, 88, 101, 113, 112, 127, 122, 122, + 115, 104, 112, 116, 122, 117, 106, 99, 97, 96, 94, 86, 75, 70, 61, 53, + 44, 41, 46, 47, 45, 28, 19, 9, 5, 9, 1, -8, -14, -20, -24, -26, + -28, -29, -36, -39, -42, -45, -41, -42, -45, -46, -49, -47, -50, -55, -53, -61, + -63, -67, -83, -78, -89, -91, -88, -100, -93, -108, -110, -110, -115, -90, -100, -91, + -80, -91, -73, -62, -60, -41, -33, -36, -25, -16, -9, 8, 18, 35, 40, 57, + 61, 66, 95, 94, 106, 114, 105, 117, 111, 117, 118, 115, 120, 111, 109, 111, + 104, 102, 106, 93, 88, 76, 66, 63, 52, 53, 31, 27, 25, 5, 12, 1, + -5, 0, -15, -17, -23, -27, -27, -31, -31, -37, -44, -41, -43, -43, -35, -45, + -43, -41, -50, -49, -51, -57, -58, -62, -72, -76, -79, -81, -82, -86, -92, -94, + -100, -109, -110, -102, -99, -96, -83, -96, -83, -67, -73, -45, -41, -42, -27, -27, + -19, -5, 7, 14, 30, 44, 46, 57, 75, 84, 98, 108, 102, 112, 114, 110, + 120, 115, 116, 117, 108, 112, 107, 104, 108, 99, 96, 90, 73, 69, 66, 57, + 48, 36, 26, 18, 13, 6, -3, 3, -8, -14, -15, -26, -25, -26, -33, -33, + -40, -45, -45, -45, -42, -43, -44, -45, -48, -46, -55, -57, -58, -62, -67, -73, + -78, -80, -81, -82, -89, -93, -99, -106, -108, -115, -100, -95, -103, -77, -91, -85, + -59, -63, -48, -32, -36, -33, -18, -14, -6, 11, 21, 27, 47, 55, 56, 81, + 92, 96, 114, 106, 111, 116, 110, 121, 113, 115, 115, 105, 111, 106, 101, 103, + 100, 92, 84, 74, 66, 60, 58, 43, 29, 29, 13, 9, 10, -6, -2, -6, + -16, -18, -22, -27, -30, -30, -35, -44, -43, -46, -46, -42, -44, -48, -45, -46, + -50, -54, -51, -61, -63, -61, -85, -76, -80, -94, -75, -98, -97, -93, -111, -103, + -106, -97, -97, -90, -79, -93, -73, -64, -67, -39, -38, -41, -20, -20, -12, 11, + 10, 30, 40, 48, 62, 62, 85, 91, 99, 111, 101, 112, 111, 113, 120, 112, + 119, 111, 108, 114, 101, 102, 104, 89, 91, 79, 63, 67, 56, 52, 41, 29, + 26, 12, 14, 3, -5, 1, -14, -15, -19, -27, -24, -30, -31, -34, -43, -43, + -45, -48, -40, -48, -48, -45, -51, -49, -53, -56, -57, -63, -69, -76, -86, -80, + -86, -90, -87, -98, -101, -101, -108, -103, -88, -96, -88, -77, -89, -70, -60, -56, + -39, -34, -30, -26, -11, -4, 6, 26, 27, 42, 54, 57, 72, 86, 95, 105, + 107, 108, 112, 109, 116, 118, 112, 117, 108, 109, 107, 104, 103, 99, 97, 83, + 77, 71, 57, 60, 49, 35, 30, 21, 11, 11, 4, -2, -3, -13, -17, -22, + -24, -28, -29, -29, -39, -39, -44, -44, -41, -45, -44, -50, -49, -49, -56, -50, + -60, -62, -55, -82, -70, -82, -90, -80, -95, -95, -100, -105, -112, -112, -93, -102, + -91, -81, -91, -77, -60, -65, -45, -33, -40, -25, -21, -14, 5, 10, 30, 35, + 49, 61, 61, 87, 94, 102, 109, 109, 112, 112, 116, 117, 116, 118, 116, 106, + 113, 108, 101, 110, 96, 91, 84, 69, 66, 58, 54, 38, 29, 26, 12, 11, + 6, -2, -2, -8, -16, -20, -23, -27, -28, -33, -34, -44, -43, -43, -47, -39, + -44, -47, -43, -47, -49, -50, -52, -57, -58, -68, -75, -76, -83, -86, -86, -91, + -97, -98, -103, -109, -102, -91, -99, -84, -81, -93, -65, -66, -60, -37, -42, -33, + -25, -18, -9, 6, 16, 28, 41, 49, 57, 68, 84, 93, 102, 106, 106, 110, + 107, 116, 114, 111, 119, 106, 111, 108, 101, 104, 99, 94, 85, 76, 68, 61, + 56, 49, 34, 28, 21, 10, 10, 2, -3, -3, -13, -15, -24, -26, -28, -34, + -31, -42, -45, -43, -48, -44, -43, -47, -47, -47, -48, -51, -57, -57, -63, -70, + -72, -80, -86, -81, -92, -88, -96, -103, -100, -113, -110, -96, -101, -96, -79, -91, + -82, -59, -68, -47, -34, -39, -29, -18, -13, -5, 18, 22, 32, 54, 52, 64, + 83, 90, 100, 108, 109, 110, 113, 113, 116, 113, 117, 113, 106, 111, 103, 100, + 101, 98, 86, 82, 73, 59, 61, 53, 36, 34, 24, 12, 10, 5, -5, -3, + -8, -17, -18, -24, -27, -29, -30, -35, -40, -41, -45, -43, -43, -42, -45, -46, + -44, -50, -49, -55, -58, -55, -71, -70, -79, -87, -77, -92, -88, -95, -104, -100, + -115, -107, -91, -105, -85, -83, -97, -67, -68, -65, -37, -43, -33, -29, -21, -9, + 0, 18, 23, 35, 55, 48, 69, 87, 86, 108, 107, 103, 117, 106, 117, 118, + 113, 122, 109, 111, 111, 102, 110, 101, 98, 92, 77, 73, 62, 59, 54, 34, + 34, 21, 11, 15, 2, 2, 2, -14, -12, -23, -26, -26, -33, -30, -40, -44, + -42, -49, -41, -41, -44, -43, -46, -49, -51, -59, -54, -63, -67, -64, -84, -79, + -76, -91, -82, -87, -100, -100, -101, -118, -101, -89, -107, -81, -82, -93, -65, -57, + -57, -36, -26, -39, -17, -9, -13, 14, 21, 26, 45, 53, 54, 76, 88, 95, + 111, 106, 111, 114, 109, 120, 115, 115, 116, 110, 105, 109, 104, 98, 105, 94, + 83, 81, 68, 60, 62, 49, 32, 33, 18, 9, 12, 0, -3, -3, -13, -18, + -20, -24, -27, -26, -31, -37, -40, -42, -42, -43, -42, -44, -48, -48, -47, -51, + -54, -52, -56, -64, -68, -75, -84, -79, -89, -91, -93, -104, -105, -110, -114, -97, + -97, -96, -78, -89, -81, -58, -66, -47, -34, -40, -31, -23, -14, -6, 14, 22, + 31, 54, 55, 63, 87, 91, 103, 113, 105, 111, 113, 109, 119, 112, 117, 114, + 106, 113, 106, 105, 105, 99, 93, 81, 74, 61, 58, 55, 36, 30, 25, 10, + 11, 6, -5, 1, -8, -16, -19, -25, -27, -32, -32, -37, -44, -41, -47, -43, + -39, -43, -44, -45, -46, -46, -56, -53, -55, -72, -64, -74, -91, -72, -88, -97, + -80, -100, -105, -100, -111, -111, -88, -100, -99, -74, -97, -79, -54, -68, -43, -32, + -41, -26, -10, -16, 6, 22, 19, 41, 51, 49, 69, 86, 88, 103, 107, 100, + 119, 110, 111, 125, 110, 115, 115, 104, 108, 106, 99, 98, 98, 82, 76, 71, + 60, 60, 52, 34, 30, 25, 9, 11, 3, -6, 0, -15, -18, -21, -27, -27, + -30, -31, -38, -39, -43, -43, -39, -43, -44, -46, -47, -47, -54, -53, -59, -58, + -65, -71, -75, -81, -75, -90, -83, -90, -100, -95, -111, -109, -101, -97, -100, -84, + -86, -89, -62, -64, -50, -34, -37, -30, -21, -11, -8, 10, 19, 26, 47, 49, + 59, 76, 89, 99, 107, 109, 110, 115, 113, 119, 115, 114, 115, 106, 111, 103, + 103, 101, 98, 94, 81, 78, 65, 63, 59, 43, 34, 25, 17, 10, 7, -4, + -3, -6, -14, -16, -23, -24, -28, -29, -33, -41, -41, -46, -43, -40, -44, -44, + -46, -46, -47, -50, -54, -56, -58, -69, -70, -76, -83, -75, -87, -87, -91, -100, + -100, -109, -108, -97, -98, -93, -83, -88, -76, -61, -59, -43, -36, -33, -28, -18, + -11, -4, 14, 21, 31, 52, 51, 63, 84, 90, 101, 111, 104, 113, 113, 111, + 118, 112, 114, 109, 108, 109, 102, 106, 101, 98, 94, 79, 74, 66, 58, 55, + 39, 29, 24, 13, 11, 5, -4, 0, -10, -15, -17, -24, -25, -28, -29, -34, + -41, -41, -47, -42, -44, -46, -45, -50, -45, -50, -55, -48, -60, -60, -65, -76, + -77, -83, -84, -91, -92, -94, -106, -103, -109, -106, -89, -101, -82, -81, -88, -63, + -66, -54, -36, -40, -31, -25, -16, -7, 6, 17, 30, 41, 55, 56, 73, 89, + 92, 109, 104, 106, 114, 104, 117, 113, 110, 116, 105, 108, 106, 100, 102, 98, + 94, 85, 74, 67, 59, 55, 48, 31, 28, 19, 10, 12, 0, 2, -2, -11, + -11, -21, -21, -26, -30, -30, -40, -43, -43, -44, -40, -39, -41, -43, -42, -46, + -52, -52, -58, -63, -65, -75, -79, -83, -80, -89, -85, -88, -101, -94, -104, -114, + -93, -97, -104, -78, -92, -89, -60, -68, -48, -36, -36, -26, -21, -8, -5, 12, + 23, 26, 47, 50, 54, 77, 85, 96, 109, 102, 114, 112, 109, 125, 112, 114, + 118, 102, 110, 103, 99, 101, 96, 92, 79, 76, 66, 59, 61, 43, 32, 31, + 14, 10, 9, -5, -2, -9, -17, -18, -28, -25, -31, -31, -31, -42, -38, -43, + -41, -39, -43, -44, -47, -45, -48, -51, -53, -54, -61, -64, -67, -77, -76, -82, + -81, -89, -93, -97, -106, -108, -105, -96, -99, -88, -82, -92, -67, -64, -60, -38, + -38, -36, -24, -20, -16, 4, 11, 21, 36, 46, 53, 66, 85, 88, 103, 108, + 102, 115, 107, 112, 115, 109, 114, 104, 106, 106, 99, 102, 101, 92, 89, 81, + 67, 66, 58, 47, 39, 28, 21, 11, 12, 2, -2, 2, -12, -12, -17, -25, + -24, -29, -30, -36, -39, -41, -41, -41, -39, -41, -44, -44, -47, -51, -52, -54, + -59, -63, -65, -75, -79, -75, -90, -81, -89, -99, -92, -109, -109, -105, -99, -97, + -92, -80, -90, -71, -58, -60, -37, -32, -37, -19, -15, -14, 9, 14, 23, 42, + 46, 56, 67, 83, 96, 100, 111, 106, 111, 114, 111, 117, 111, 112, 109, 103, + 107, 100, 99, 103, 92, 88, 82, 65, 66, 59, 48, 39, 27, 22, 12, 9, + 5, -5, 0, -12, -16, -17, -26, -25, -26, -31, -34, -40, -41, -41, -41, -40, + -42, -47, -43, -46, -46, -52, -50, -52, -61, -59, -74, -75, -77, -83, -84, -91, + -92, -105, -100, -106, -109, -81, -103, -86, -73, -96, -64, -62, -59, -38, -39, -36, + -28, -15, -11, 3, 18, 25, 37, 53, 53, 67, 89, 85, 106, 103, 98, 115, + 99, 114, 115, 103, 116, 103, 104, 109, 98, 101, 98, 91, 84, 75, 67, 60, + 55, 50, 31, 28, 20, 7, 15, 0, -3, 2, -15, -12, -19, -25, -24, -32, + -32, -38, -44, -44, -45, -42, -41, -44, -43, -46, -44, -44, -58, -48, -63, -67, + -63, -87, -75, -83, -90, -81, -94, -95, -95, -107, -109, -99, -95, -99, -85, -85, + -90, -68, -62, -60, -36, -34, -39, -15, -13, -9, 14, 15, 29, 42, 50, 55, + 68, 87, 91, 101, 107, 106, 110, 113, 114, 115, 114, 112, 108, 105, 106, 98, + 98, 100, 88, 84, 75, 63, 63, 57, 46, 34, 28, 18, 10, 8, 0, -5, + -5, -15, -19, -20, -26, -26, -26, -31, -36, -40, -42, -43, -42, -39, -44, -44, + -42, -44, -47, -51, -52, -54, -65, -63, -76, -81, -68, -93, -84, -85, -104, -92, + -105, -109, -95, -95, -96, -84, -82, -84, -64, -64, -52, -39, -37, -33, -23, -11, + -9, 10, 20, 25, 49, 46, 60, 76, 82, 98, 101, 104, 110, 108, 108, 116, + 111, 111, 113, 104, 108, 106, 101, 98, 99, 92, 80, 79, 63, 61, 59, 41, + 35, 27, 18, 13, 9, 2, 0, -5, -12, -15, -20, -22, -26, -27, -30, -38, + -39, -42, -40, -39, -40, -40, -45, -43, -47, -49, -54, -53, -57, -70, -59, -80, + -77, -72, -93, -75, -91, -99, -93, -105, -108, -97, -92, -99, -80, -84, -84, -61, + -59, -49, -35, -28, -34, -14, -9, -10, 19, 17, 27, 47, 47, 61, 72, 87, + 95, 105, 104, 110, 111, 109, 117, 109, 111, 109, 103, 103, 102, 97, 95, 100, + 85, 81, 77, 61, 64, 55, 42, 34, 26, 17, 10, 9, -3, -2, -5, -13, + -15, -20, -23, -27, -27, -32, -37, -38, -41, -40, -41, -39, -43, -43, -40, -48, + -47, -49, -55, -61, -59, -70, -80, -69, -87, -83, -79, -97, -89, -98, -101, -107, + -96, -93, -101, -77, -90, -84, -62, -63, -49, -36, -34, -30, -15, -12, -2, 11, + 20, 32, 39, 53, 56, 71, 87, 89, 103, 101, 109, 109, 109, 118, 106, 114, + 111, 101, 107, 102, 93, 99, 94, 84, 85, 71, 65, 62, 54, 45, 32, 30, + 16, 12, 8, -5, -2, -9, -14, -16, -24, -22, -27, -29, -31, -38, -41, -38, + -44, -42, -41, -47, -45, -44, -48, -50, -50, -52, -62, -57, -69, -79, -69, -83, + -88, -78, -99, -97, -92, -109, -106, -91, -100, -93, -76, -91, -80, -60, -66, -48, + -37, -38, -32, -18, -15, -4, 11, 14, 31, 42, 48, 60, 69, 85, 94, 96, + 102, 107, 103, 109, 115, 104, 112, 109, 100, 106, 103, 95, 97, 96, 84, 82, + 73, 60, 62, 54, 41, 33, 27, 17, 14, 7, 0, 0, -8, -11, -16, -23, + -23, -29, -29, -32, -39, -40, -40, -40, -41, -40, -46, -48, -45, -50, -51, -54, + -56, -64, -63, -71, -78, -73, -84, -82, -87, -95, -93, -102, -102, -108, -95, -96, + -95, -76, -90, -77, -57, -61, -42, -33, -35, -26, -13, -14, 3, 15, 17, 36, + 45, 54, 60, 80, 89, 96, 108, 101, 111, 110, 109, 118, 107, 110, 109, 102, + 103, 103, 95, 97, 96, 83, 82, 70, 60, 61, 51, 38, 28, 23, 11, 8, + 4, -7, -3, -10, -16, -17, -22, -25, -27, -29, -35, -38, -43, -42, -41, -40, + -39, -43, -42, -44, -45, -46, -53, -51, -55, -68, -65, -75, -79, -77, -88, -83, + -94, -93, -101, -105, -96, -96, -92, -85, -85, -83, -71, -64, -57, -41, -41, -31, + -27, -17, -7, 2, 18, 23, 38, 48, 51, 68, 78, 91, 98, 102, 106, 108, + 110, 112, 115, 110, 115, 107, 107, 108, 99, 102, 97, 94, 87, 76, 70, 63, + 60, 49, 39, 30, 22, 16, 8, 4, 0, -4, -10, -14, -20, -24, -25, -31, + -30, -37, -41, -40, -41, -38, -39, -40, -42, -41, -43, -48, -44, -55, -58, -57, + -71, -71, -73, -78, -79, -80, -88, -89, -95, -99, -103, -101, -88, -98, -85, -79, + -90, -62, -60, -54, -35, -35, -27, -21, -9, -3, 7, 22, 26, 38, 52, 54, + 67, 87, 89, 101, 105, 103, 114, 107, 117, 112, 107, 116, 100, 105, 103, 94, + 98, 93, 87, 80, 73, 65, 59, 56, 45, 31, 28, 19, 6, 10, -3, -5, + -4, -17, -16, -22, -24, -25, -30, -28, -39, -37, -40, -44, -40, -44, -46, -46, + -47, -51, -50, -55, -55, -60, -67, -65, -81, -75, -78, -93, -78, -97, -101, -94, + -113, -104, -92, -96, -91, -79, -86, -79, -58, -58, -49, -34, -34, -33, -14, -12, + -5, 20, 19, 34, 49, 49, 66, 76, 91, 98, 98, 105, 104, 107, 111, 110, + 109, 108, 108, 103, 101, 102, 97, 95, 96, 80, 75, 71, 56, 58, 49, 33, + 28, 20, 13, 7, 4, -4, -7, -9, -18, -22, -22, -28, -30, -30, -38, -41, + -41, -43, -40, -41, -40, -44, -43, -45, -48, -49, -55, -55, -59, -67, -66, -82, + -70, -81, -86, -78, -101, -92, -98, -111, -98, -95, -95, -89, -76, -91, -70, -56, + -61, -38, -34, -33, -25, -12, -10, 1, 21, 15, 39, 47, 48, 68, 75, 90, + 97, 101, 103, 106, 106, 110, 111, 104, 111, 101, 99, 103, 96, 94, 95, 92, + 75, 79, 64, 55, 64, 43, 36, 30, 17, 13, 9, 3, -4, -3, -12, -16, + -18, -23, -25, -26, -29, -35, -38, -42, -40, -39, -41, -38, -48, -42, -45, -50, + -49, -52, -57, -63, -57, -78, -76, -67, -94, -75, -88, -100, -92, -103, -106, -97, + -88, -96, -81, -77, -85, -60, -55, -51, -35, -30, -33, -19, -9, -10, 17, 16, + 30, 46, 48, 64, 72, 86, 96, 101, 104, 105, 111, 104, 116, 109, 107, 110, + 104, 101, 104, 100, 93, 100, 86, 77, 78, 59, 60, 54, 40, 32, 23, 18, + 9, 9, 0, -5, -6, -14, -17, -20, -23, -25, -26, -31, -35, -39, -40, -36, + -40, -37, -40, -45, -42, -45, -48, -51, -50, -57, -64, -62, -76, -78, -71, -90, + -84, -88, -101, -97, -105, -108, -94, -97, -92, -81, -87, -76, -63, -58, -42, -36, + -33, -27, -15, -10, -2, 18, 19, 34, 49, 47, 66, 78, 86, 102, 104, 104, + 111, 109, 112, 115, 112, 110, 108, 106, 101, 102, 98, 96, 97, 86, 79, 72, + 62, 61, 51, 39, 32, 20, 15, 10, 2, 1, -4, -9, -13, -18, -22, -24, + -25, -29, -33, -37, -41, -39, -37, -39, -39, -43, -46, -46, -49, -49, -56, -54, + -57, -68, -66, -73, -77, -79, -83, -90, -96, -95, -107, -110, -98, -97, -98, -76, + -87, -83, -56, -68, -49, -34, -43, -28, -26, -18, -8, 3, 14, 22, 39, 47, + 54, 70, 83, 90, 101, 100, 104, 107, 102, 113, 103, 106, 109, 95, 106, 99, + 95, 101, 92, 93, 83, 74, 66, 60, 56, 44, 33, 26, 17, 12, 8, 1, + 2, -4, -11, -10, -21, -19, -25, -29, -28, -39, -38, -41, -41, -37, -40, -42, + -43, -42, -45, -47, -48, -56, -52, -59, -69, -67, -78, -78, -79, -88, -86, -95, + -100, -99, -112, -95, -92, -101, -77, -86, -86, -62, -65, -51, -39, -35, -31, -26, + -8, -11, 7, 26, 21, 45, 53, 50, 76, 86, 90, 105, 102, 105, 109, 108, + 115, 107, 112, 110, 100, 108, 100, 96, 100, 93, 89, 79, 72, 64, 58, 56, + 42, 31, 28, 14, 10, 9, -5, -2, -6, -14, -15, -22, -22, -27, -28, -31, + -41, -37, -41, -42, -37, -41, -45, -43, -45, -47, -48, -49, -58, -53, -64, -71, + -68, -82, -75, -83, -91, -87, -103, -97, -104, -111, -90, -98, -95, -77, -91, -76, + -61, -63, -43, -41, -35, -29, -23, -7, -7, 13, 22, 24, 50, 50, 59, 82, + 82, 99, 102, 100, 110, 105, 111, 113, 104, 114, 103, 104, 107, 96, 102, 97, + 92, 90, 77, 73, 64, 58, 53, 38, 31, 23, 13, 12, 3, 0, -2, -11, + -10, -17, -21, -20, -29, -27, -33, -40, -38, -44, -39, -39, -43, -41, -42, -42, + -46, -42, -53, -53, -52, -71, -67, -73, -83, -80, -81, -89, -93, -91, -100, -106, + -97, -96, -93, -88, -81, -85, -79, -59, -58, -48, -30, -36, -28, -11, -9, -2, + 21, 22, 32, 50, 52, 58, 79, 89, 90, 104, 104, 100, 113, 111, 109, 114, + 109, 107, 103, 104, 99, 94, 97, 91, 78, 79, 65, 58, 61, 47, 37, 30, + 23, 14, 10, 7, -7, -4, -8, -21, -17, -23, -30, -26, -30, -36, -37, -39, + -38, -38, -36, -38, -45, -41, -45, -49, -51, -56, -57, -63, -64, -69, -78, -70, + -80, -84, -84, -91, -100, -98, -106, -108, -90, -103, -90, -80, -93, -65, -64, -52, + -38, -37, -27, -26, -12, -6, 3, 18, 22, 36, 48, 54, 69, 84, 89, 105, + 103, 106, 117, 105, 117, 113, 106, 113, 101, 105, 101, 99, 98, 93, 94, 83, + 75, 70, 60, 55, 49, 33, 27, 19, 10, 8, -2, -2, -7, -13, -12, -22, + -20, -23, -28, -28, -35, -39, -40, -41, -40, -42, -40, -43, -42, -42, -44, -46, + -49, -52, -59, -60, -70, -74, -71, -84, -82, -88, -96, -98, -100, -105, -102, -88, + -95, -83, -79, -87, -62, -62, -52, -40, -39, -31, -27, -14, -10, 7, 17, 25, + 42, 49, 59, 72, 85, 92, 103, 103, 102, 111, 104, 113, 110, 104, 112, 102, + 107, 103, 101, 99, 97, 92, 81, 76, 64, 61, 54, 42, 33, 24, 17, 11, + 8, -2, -2, -5, -13, -12, -22, -23, -26, -31, -32, -38, -40, -43, -39, -40, + -41, -40, -44, -41, -44, -47, -51, -49, -62, -55, -68, -78, -68, -89, -79, -81, + -96, -85, -101, -100, -103, -98, -91, -97, -79, -83, -87, -61, -64, -55, -31, -41, + -29, -15, -19, 3, 9, 18, 33, 36, 56, 54, 71, 87, 87, 103, 103, 103, + 110, 107, 113, 112, 108, 111, 101, 104, 103, 92, 101, 92, 84, 84, 66, 65, + 59, 51, 45, 31, 27, 16, 10, 6, -3, -3, -9, -15, -16, -22, -24, -25, + -30, -28, -36, -40, -36, -42, -38, -41, -45, -44, -47, -47, -49, -51, -52, -54, + -62, -68, -73, -78, -81, -84, -83, -97, -94, -101, -113, -100, -99, -96, -87, -83, + -85, -75, -60, -60, -43, -36, -38, -27, -20, -15, 0, 14, 19, 33, 47, 49, + 67, 78, 90, 100, 103, 105, 107, 108, 110, 112, 109, 109, 107, 102, 105, 100, + 99, 98, 95, 84, 80, 69, 59, 60, 48, 36, 31, 18, 14, 9, 3, -2, + -5, -10, -15, -19, -24, -25, -28, -31, -34, -39, -41, -40, -38, -40, -38, -43, + -43, -42, -48, -47, -53, -54, -58, -67, -63, -79, -73, -78, -90, -80, -98, -97, + -101, -109, -105, -93, -98, -90, -76, -93, -66, -60, -59, -33, -42, -32, -26, -18, + -9, 0, 17, 21, 38, 48, 53, 69, 82, 93, 101, 107, 102, 112, 108, 111, + 115, 105, 112, 103, 105, 104, 96, 103, 95, 95, 85, 76, 68, 63, 59, 47, + 38, 26, 19, 13, 7, 1, -3, -4, -14, -12, -19, -23, -21, -29, -29, -35, + -40, -41, -42, -39, -43, -42, -46, -43, -47, -45, -48, -54, -47, -66, -61, -68, + -85, -66, -90, -84, -84, -103, -91, -106, -105, -96, -90, -92, -81, -79, -86, -59, + -59, -53, -34, -36, -33, -19, -10, -10, 17, 20, 26, 52, 48, 60, 75, 85, + 95, 102, 104, 102, 111, 107, 113, 110, 109, 111, 103, 107, 102, 97, 96, 95, + 85, 77, 73, 56, 60, 52, 37, 33, 22, 16, 11, 7, -3, -4, -6, -16, + -14, -21, -24, -24, -28, -32, -37, -38, -42, -36, -37, -39, -39, -43, -40, -42, + -48, -50, -50, -64, -57, -70, -84, -63, -90, -81, -77, -101, -85, -99, -105, -102, + -100, -92, -99, -79, -89, -86, -58, -65, -49, -29, -41, -26, -11, -19, 6, 12, + 14, 39, 37, 52, 60, 68, 90, 90, 104, 102, 106, 111, 108, 118, 109, 109, + 111, 98, 106, 101, 90, 101, 90, 82, 86, 63, 65, 63, 48, 47, 29, 25, + 16, 10, 6, -6, -3, -13, -18, -16, -26, -25, -25, -32, -30, -39, -43, -37, + -43, -39, -39, -48, -44, -46, -53, -50, -56, -59, -59, -67, -72, -77, -76, -84, + -83, -84, -100, -95, -103, -115, -98, -93, -103, -82, -82, -91, -60, -62, -54, -34, + -35, -31, -23, -13, -11, 7, 19, 21, 43, 48, 55, 73, 85, 94, 104, 102, + 109, 110, 105, 118, 107, 109, 113, 98, 106, 103, 96, 99, 98, 90, 82, 79, + 62, 62, 58, 41, 34, 26, 14, 10, 8, -3, -2, -5, -14, -13, -20, -20, + -24, -26, -28, -38, -39, -42, -42, -41, -41, -42, -48, -41, -43, -50, -41, -49, + -59, -50, -68, -74, -67, -82, -80, -89, -87, -101, -101, -93, -121, -85, -90, -105, + -65, -93, -82, -55, -69, -49, -38, -46, -32, -27, -19, -5, 3, 19, 26, 41, + 53, 52, 81, 81, 95, 104, 90, 113, 101, 105, 118, 99, 113, 109, 100, 109, + 104, 98, 104, 96, 89, 83, 71, 66, 57, 56, 38, 28, 29, 8, 17, 6, + -2, 3, -24, -13, -79, -103, -120, -116, -104, -87, -76, -63, 63, 82, 97, 108, + 119, 99, 70, 69, 80, 91, 92, 98, 115, 124, 127, 113, 82, 42, 4, -44, + -70, -82, -100, -87, -62, -58, -71, -65, -79, -60, -102, -113, -62, -44, -31, -31, + -22, -18, -3, 4, 11, 20, 28, 11, 15, 18, 27, 18, 7, 13, 26, 11, + -19, -69, -108, -84, -51, -21, -3, -6, -18, -17, -31, -33, -18, 2, 4, 26, + 47, 48, 77, 117, 127, 127, 127, 121, 110, 86, 72, 62, 46, 11, 17, -2, + -7, -13, -44, -60, -61, -61, -63, -72, -79, -99, -116, -127, -128, -128, -124, -81, + -51, -4, 5, -6, 7, 8, 9, 31, 31, 16, 34, 28, 34, 34, 46, 78, + 84, 93, 69, 47, 40, 64, 44, 27, 22, 0, -29, -8, 15, -6, -36, -66, + -68, -42, 0, 6, 1, 13, 24, 41, 64, 58, 50, 40, 4, 0, 3, -24, + -3, 21, 28, 26, 9, -30, -42, -61, -85, -92, -91, -96, -87, -74, -31, -20, + -38, -14, -44, -17, 18, -25, -9, 7, 1, 11, -2, -19, 12, 47, 76, 72, + 58, 68, 69, 82, 86, 76, 58, 9, -23, -12, -7, -22, -2, 0, -9, -2, + -15, -10, -3, -22, -17, -38, -44, -33, -24, -27, -16, 0, -15, 20, 19, 18, + 1, 10, 41, -1, -25, -25, -11, 30, 37, 9, 45, 37, -30, -30, 21, 5, + -26, -43, -56, -42, -48, -48, -29, -62, -76, -42, -23, -12, -14, 8, 45, 36, + 40, 25, 14, 11, 40, 46, 55, 65, 30, 17, 30, 36, 33, 18, 13, 16, + 15, 46, 37, 2, -1, -26, -36, -19, -21, -36, -62, -51, -48, -20, -2, 3, + -12, -12, -10, -35, -37, -49, -22, 14, 61, 40, 60, 75, 33, 41, 48, 38, + 29, -32, -45, -56, -64, -61, -30, -20, 30, 10, -46, -37, -35, -30, -24, -12, + -23, -34, -29, -22, -20, -14, 4, 44, 77, 49, 10, 8, 24, 20, 28, 31, + 27, 40, 35, 69, 39, 54, 38, 26, 22, 43, 36, 7, 14, 2, -25, -50, + -51, -56, -42, -55, -46, -36, -44, -36, -35, 1, 23, 11, -3, -34, -66, -33, + -12, -31, -27, -13, -1, 21, 31, 23, 0, -11, -3, -2, 9, 27, 5, -8, + -2, -17, -13, 10, 9, 3, 35, 32, 43, 24, 15, 2, -15, -9, -5, 2, + 5, 27, 25, 42, 76, 61, 17, 25, 14, -5, -17, -24, -6, 11, 23, 7, + -8, 5, -11, -23, -27, -48, -30, -12, -26, -36, -37, -39, -46, -61, -55, -23, + -20, -22, -14, -10, -16, -16, -22, -11, -3, -14, -34, -16, 9, 28, 25, 50, + 63, 52, 56, 46, 50, 54, 56, 45, 54, 29, 20, 21, 0, 0, 6, 16, + 28, 14, -1, -9, -10, -4, -9, -13, -7, -21, -27, -29, -40, -41, -35, -42, + -64, -11, 9, 2, -12, -24, -37, -40, -34, -29, -34, -12, -26, -20, -6, -4, + 5, 5, 27, 1, -17, 2, 21, 12, 8, 9, 15, 23, 24, 1, 5, 22, + 25, 28, 57, 55, 41, 33, 36, 27, 5, 1, 15, 34, 23, 4, 20, 18, + -1, -21, -22, -15, -17, -8, -6, -6, -12, -15, -26, 1, 29, -8, -40, -52, + -55, -19, -21, -36, -48, -56, -29, -15, -29, -39, -46, -35, -14, -11, -16, 1, + 27, 22, -10, -14, -7, -12, -12, 23, 55, 48, 65, 42, 20, 46, 45, 49, + 42, 38, 34, 25, 33, 21, 10, 38, 40, 26, 22, 37, 33, 12, 4, 7, + -14, -49, -41, -36, -53, -40, -35, -44, -31, -22, -19, -50, -78, -80, -78, -48, + -31, -18, -27, -28, -7, -17, -11, 5, 32, 39, 19, 14, 22, 34, 37, 23, + 20, 40, 40, 27, 14, 11, 7, 29, 34, 19, 32, 7, -15, -12, -24, -12, + 8, 6, 21, 34, 29, -6, -22, -15, 1, -1, 24, 27, 20, 36, 42, 45, + 27, -14, -50, -34, -14, -26, -25, -10, 10, -4, -28, -30, -34, -69, -91, -85, + -74, -51, -38, -24, -19, -9, -7, -30, -35, -30, -36, -12, 25, 32, 44, 50, + 45, 51, 68, 94, 90, 74, 60, 52, 64, 48, 30, 11, 11, 11, 2, 14, + 24, 16, 13, -7, -17, -9, -12, -20, -32, -45, -54, -58, -35, -23, -46, -51, + -33, -28, -29, -24, -36, -30, -24, -22, -20, -13, -9, -14, -7, 10, 26, 22, + 9, 9, 10, -2, -9, -15, -11, -1, 19, 27, 33, 28, 5, 3, 5, 6, + 10, 14, 24, 32, 36, 40, 41, 37, 19, 11, 3, -7, -10, -7, 6, 27, + 38, 28, 23, 16, 18, 15, -7, -33, -20, -13, -24, -25, -19, -15, -26, -52, + -56, -48, -41, -36, -30, -32, -30, -15, -38, -49, -47, -32, -17, -17, -11, -3, + 3, 8, 24, 28, 16, 6, 1, 7, 28, 41, 42, 69, 87, 78, 73, 62, + 30, 14, 9, 7, 15, 32, 20, 10, -8, -20, 2, 9, -2, 5, 12, -4, + -12, -19, -32, -37, -29, -24, -28, -39, -43, -40, -44, -28, -25, -33, -39, -37, + -34, -29, -28, -25, -19, -1, -5, -22, -12, 2, 6, 38, 46, 25, 30, 41, + 47, 37, 21, 7, -7, -8, 11, 39, 48, 43, 35, 27, 25, 22, -1, -22, + -11, 13, -4, -13, -3, -8, -7, -11, -17, -5, 5, 9, 8, 15, 25, 16, + 22, 20, 5, -16, -27, -29, -30, -9, 9, 9, 3, -14, -50, -56, -56, -79, + -92, -80, -57, -24, 12, 10, 11, 4, -22, -21, -13, -2, 4, 10, 15, 8, + 35, 72, 53, 44, 25, 25, 48, 56, 69, 53, 50, 75, 85, 71, 33, 12, + -16, -32, -25, -14, -5, -16, -23, -19, -22, -39, -41, -47, -45, -33, -35, -39, + -38, -35, -34, -29, -28, -28, -23, -10, -7, -9, -11, -18, -5, 13, 1, -13, + -8, -5, 6, 27, 46, 43, 25, 8, 11, 16, 18, 23, 30, 12, 5, 10, + 7, 5, -6, -4, -5, 1, 10, 9, 15, 21, 17, 10, -8, -16, 10, 33, + 34, 23, 13, 17, 17, 9, 11, 7, -4, -8, -8, -22, -27, -26, -19, -7, + -18, -16, -16, -47, -62, -55, -36, -16, -25, -33, -30, -34, -42, -49, -41, -43, + -31, -20, -3, 28, 48, 66, 64, 36, 20, 26, 21, 22, 39, 51, 45, 39, + 40, 53, 56, 39, 24, 16, 12, 16, 24, 27, 16, 13, 7, -18, -33, -50, + -47, -33, -24, -20, -26, -32, -31, -46, -53, -58, -56, -29, -13, -11, -2, 8, + -11, -24, -11, -9, -6, -2, -6, 1, 4, 5, 11, 6, 7, 16, 30, 28, + 19, 15, 7, 4, 11, 27, 22, 6, 9, 11, 3, 4, 17, 27, 18, 11, + 12, 5, 2, -2, -6, -7, -2, 10, 12, 9, 1, -2, 3, 4, 11, 21, + 30, 28, 6, -9, -18, -22, -22, -38, -41, -27, -18, -18, -27, -27, -23, -32, + -35, -32, -34, -30, -25, -24, -18, -9, -5, 5, -5, -26, -19, -11, -4, 11, + 37, 48, 46, 50, 53, 50, 45, 45, 37, 18, 24, 44, 38, 43, 47, 29, + 15, 11, 10, 12, 4, -8, -6, -4, -17, -27, -28, -36, -34, -37, -53, -53, + -46, -38, -38, -37, -28, -24, -23, -37, -42, -30, 0, 20, 18, 12, 14, 9, + 2, 6, 15, 13, 10, 14, 12, 2, 12, 29, 21, 1, 7, 21, 19, 14, + 15, 15, 4, -1, 5, -1, -4, 0, -2, 3, 6, 6, 13, 21, 15, 7, + 3, 5, 2, -3, 3, 3, 5, 8, 10, 16, 14, -1, -7, 2, 11, 12, + -10, -35, -42, -26, -21, -37, -44, -44, -47, -42, -27, -27, -23, -15, -16, -20, + -21, -14, -12, -9, -7, -6, 0, 13, 30, 32, 37, 38, 31, 24, 25, 43, + 54, 49, 46, 44, 40, 41, 30, 9, -1, 6, 22, 31, 22, 9, 0, -14, + -23, -29, -29, -28, -35, -39, -39, -39, -33, -25, -30, -44, -49, -45, -45, -35, + -19, 2, 16, 16, 9, 0, 0, 6, 2, -1, 11, 27, 40, 32, 16, -2, + -2, 1, 3, 1, 7, 12, 6, 8, 11, 5, -1, -2, -1, 1, 8, 10, + 5, 4, 14, 17, 6, -1, 0, 4, 4, 17, 23, 19, 25, 20, 5, -8, + -9, -2, -1, -6, -3, 13, 16, 1, -13, -19, -21, -26, -34, -37, -23, -13, + -13, -24, -40, -42, -40, -39, -29, -22, -21, -18, -12, -2, 18, 24, 10, 0, + -6, -4, 15, 33, 34, 34, 44, 41, 31, 33, 44, 43, 31, 22, 20, 17, + 16, 23, 22, 19, 21, 10, -5, -6, -9, -8, -2, -5, -16, -28, -36, -47, + -53, -39, -23, -21, -24, -32, -43, -39, -34, -24, -18, -14, -11, -12, -6, 10, + 29, 41, 40, 27, 14, 10, 4, 1, 3, 2, 9, 19, 21, 9, -10, -16, + -10, 8, 18, 20, 13, -3, -8, -4, -1, 2, 5, 5, -1, 3, 9, 12, + 16, 16, 14, 9, 3, 5, 10, 4, -6, 1, 6, 5, 13, 20, 11, 1, + -7, -21, -30, -25, -12, -9, -13, -19, -24, -29, -34, -30, -32, -39, -33, -24, + -20, -22, -24, -13, 3, 6, 2, 1, 3, 5, 16, 30, 35, 35, 24, 16, + 15, 19, 31, 37, 33, 28, 29, 29, 30, 26, 20, 15, 13, 10, 10, 12, + 9, 7, -3, -21, -39, -44, -43, -42, -34, -26, -23, -18, -12, -18, -32, -36, + -31, -27, -20, -10, -7, -9, -11, -5, 2, 12, 19, 19, 25, 24, 11, 3, + 15, 29, 30, 20, 9, 1, -1, 1, 5, 2, -3, -2, 0, -6, -18, -27, + -20, -3, 8, 13, 15, 11, 7, 10, 18, 16, 10, 6, 3, -1, 1, 11, + 19, 19, 15, 14, 5, -2, -2, -7, -12, -15, -20, -16, -10, -5, 2, 1, + -13, -29, -33, -24, -10, -6, -13, -18, -23, -31, -32, -26, -22, -18, -13, -3, + 2, 3, 7, 8, 10, 19, 27, 32, 33, 33, 35, 38, 43, 41, 29, 9, + -4, -9, 2, 16, 17, 13, 15, 17, 13, 10, 5, -1, -8, -18, -29, -32, + -27, -21, -22, -30, -31, -31, -33, -31, -27, -18, -7, -6, -15, -16, -8, -1, + 4, 12, 18, 22, 20, 16, 11, 10, 14, 18, 16, 15, 14, 9, 6, 4, + 3, 3, 0, -5, -13, -18, -15, -13, -9, -7, -8, -5, -2, -5, -1, 5, + 8, 10, 11, 12, 17, 19, 16, 10, 4, 4, 8, 8, 8, 13, 14, 9, + 3, 0, -1, 0, 0, -7, -19, -24, -20, -15, -12, -15, -21, -23, -24, -26, + -28, -29, -28, -21, -10, -1, 5, 6, -3, -12, -14, -11, -1, 12, 16, 17, + 28, 36, 28, 20, 25, 27, 24, 25, 28, 21, 15, 11, 3, 4, 12, 11, + 0, -7, -5, -1, -1, -5, -8, -11, -17, -23, -22, -19, -21, -20, -20, -22, + -24, -22, -17, -20, -24, -20, -10, 2, 10, 13, 14, 14, 11, 8, 8, 12, + 17, 18, 20, 20, 14, 4, -1, -2, -1, 3, 11, 12, 6, 0, -9, -20, + -25, -18, -9, -8, -13, -18, -19, -14, -6, 0, 4, 11, 19, 22, 20, 19, + 15, 13, 14, 18, 17, 12, 7, 9, 14, 9, -1, -4, -1, -5, -10, -12, + -16, -23, -19, -7, -5, -10, -10, -11, -19, -27, -24, -14, -6, -3, -10, -21, + -24, -15, -6, 0, 9, 15, 12, 8, 6, 9, 9, 11, 20, 26, 31, 35, + 30, 21, 16, 16, 13, 6, 2, 4, 5, 3, -2, -10, -13, -11, -8, -9, + -13, -16, -18, -18, -19, -22, -18, -8, -3, -1, 0, -5, -11, -10, -9, -11, + -9, -2, 2, 4, 10, 15, 18, 19, 21, 21, 22, 22, 15, 4, -4, -8, + -7, -6, -10, -14, -18, -23, -20, -15, -8, -1, 0, -4, -7, -9, -9, -6, + -2, 2, 6, 7, 4, 1, 0, 7, 13, 11, 14, 22, 22, 15, 8, 2, + 4, 10, 16, 17, 13, 10, 9, 6, -3, -13, -23, -26, -21, -17, -14, -12, + -13, -16, -14, -9, -8, -8, -11, -18, -18, -12, -4, 0, 2, 6, 6, -1, + -6, 0, 8, 11, 13, 11, 6, 6, 9, 13, 16, 16, 15, 10, 7, 10, + 10, 4, 0, -2, -3, -1, 2, 2, -1, -5, -13, -21, -27, -30, -26, -16, + -4, 5, 8, 6, 2, -3, -5, -1, 4, 8, 9, 11, 11, 6, 0, 0, + 7, 12, 13, 11, 7, 1, -4, -3, 0, 5, 6, 5, -2, -10, -13, -13, + -10, -5, -4, -9, -18, -28, -31, -24, -14, -10, -4, 2, 5, 4, 2, 4, + 13, 20, 21, 19, 14, 11, 11, 12, 13, 14, 15, 17, 18, 18, 14, 5, + -3, -5, -8, -11, -11, -12, -15, -15, -13, -13, -15, -13, -12, -15, -16, -11, + -7, -6, -4, -1, 4, 6, -1, -10, -11, -7, -4, -1, 4, 9, 11, 12, + 9, 7, 8, 8, 7, 9, 13, 15, 12, 4, 1, 1, -2, -9, -10, -7, + -1, 3, 3, -1, -9, -12, -9, -5, 1, 3, -2, -10, -10, -7, -4, 2, + 8, 6, 4, 6, 5, -1, -1, 7, 17, 20, 17, 16, 19, 16, 7, -3, + -8, -9, -9, -11, -15, -24, -27, -20, -15, -12, -11, -7, -3, -4, -6, -7, + -6, -8, -14, -18, -18, -15, -10, -5, 3, 12, 18, 20, 17, 11, 10, 16, + 21, 22, 23, 23, 22, 17, 9, 0, -3, 2, 10, 15, 16, 11, 2, -9, + -19, -23, -22, -15, -10, -8, -11, -13, -15, -17, -19, -18, -15, -10, -3, 1, + -2, -6, -3, 0, -3, -3, 0, 6, 10, 9, 7, 4, -1, -4, 0, 10, + 17, 16, 11, 5, 0, -1, 2, 5, 1, -6, -10, -10, -8, -6, -4, -2, + -4, -7, -9, -9, -6, 2, 12, 17, 16, 11, 8, 7, 6, 5, 7, 9, + 12, 14, 14, 9, 3, -1, -3, -5, -4, 0, 4, -1, -10, -18, -24, -29, + -28, -20, -14, -13, -12, -8, -5, -5, -9, -13, -14, -11, -10, -9, -4, 1, + 3, 2, 3, 8, 16, 20, 18, 13, 10, 14, 24, 29, 29, 27, 23, 17, + 14, 16, 17, 15, 9, -1, -7, -10, -14, -18, -16, -11, -8, -7, -8, -12, + -18, -26, -29, -26, -19, -11, -5, -3, -3, -2, 0, 2, 0, -3, -3, -2, + -3, -4, -2, -1, 3, 7, 9, 8, 7, 3, 1, 4, 5, 2, 3, 5, + 5, 0, -7, -9, -6, -1, 5, 9, 8, 3, -2, -6, -5, 3, 9, 12, + 11, 8, 4, 3, 4, 6, 11, 13, 8, 1, 0, 4, 9, 13, 12, 5, + 2, 3, 3, 0, -6, -16, -26, -30, -28, -26, -22, -18, -17, -19, -22, -24, + -19, -12, -7, -2, 1, 0, -2, -4, -5, -2, 4, 10, 14, 15, 15, 16, + 16, 17, 19, 22, 26, 25, 19, 13, 10, 7, 9, 11, 10, 7, 4, 1, + -5, -8, -8, -4, 0, 1, -4, -11, -16, -17, -16, -14, -12, -10, -11, -14, + -15, -16, -13, -9, -3, 1, 2, 1, 0, 0, -3, -9, -13, -10, -8, -7, + -4, 0, 3, 6, 9, 9, 5, 3, 3, 5, 8, 12, 12, 6, -1, -2, + 2, 8, 8, 4, -2, -5, -1, 4, 10, 13, 14, 13, 13, 14, 14, 12, + 10, 8, 8, 8, 6, 6, 9, 6, -1, -9, -15, -19, -22, -24, -23, -25, + -25, -23, -20, -19, -19, -21, -20, -20, -21, -19, -11, -2, 2, 1, 0, 3, + 9, 13, 15, 16, 14, 10, 5, 3, 8, 14, 16, 18, 20, 22, 24, 21, + 15, 9, 6, 8, 14, 18, 15, 9, 4, 1, 0, -2, -4, -4, -3, -3, + -4, -7, -11, -13, -12, -11, -15, -19, -22, -25, -25, -21, -14, -11, -15, -19, + -18, -14, -7, -1, 4, 2, -3, -6, -4, 0, 5, 10, 16, 17, 12, 7, + 2, -1, -3, 0, 3, 6, 10, 14, 12, 6, 2, 5, 10, 15, 18, 18, + 16, 14, 11, 6, 4, 3, 1, 1, 2, 6, 9, 9, 3, -2, -3, -4, + -6, -8, -10, -15, -19, -20, -19, -18, -17, -15, -16, -17, -18, -20, -22, -21, + -16, -11, -4, 1, 0, -4, -4, -1, 1, 2, 4, 4, 3, 3, 4, 7, + 11, 16, 21, 20, 15, 11, 9, 12, 16, 21, 24, 23, 21, 17, 13, 11, + 9, 4, 0, 0, 1, 3, 4, 0, -4, -7, -7, -9, -13, -17, -20, -22, + -23, -21, -16, -12, -12, -15, -17, -17, -15, -12, -10, -10, -11, -12, -15, -15, + -10, -4, 0, -1, -1, 1, 4, 7, 13, 19, 22, 23, 21, 19, 18, 17, + 11, 5, 2, 5, 10, 13, 15, 15, 14, 13, 10, 5, 1, 0, 2, 5, + 8, 10, 9, 6, 4, 2, -1, -5, -7, -8, -7, -8, -11, -13, -14, -16, + -19, -21, -22, -22, -24, -23, -20, -17, -16, -16, -15, -16, -16, -15, -13, -11, + -9, -5, 0, 6, 12, 15, 18, 18, 17, 17, 19, 20, 19, 19, 20, 23, + 25, 25, 23, 20, 17, 13, 11, 9, 9, 8, 6, 3, 1, -2, -5, -5, + -2, -1, -3, -7, -6, -3, 0, -2, -9, -21, -29, -32, -32, -30, -27, -27, + -29, -30, -28, -24, -23, -21, -16, -7, 0, 1, 2, 2, 4, 7, 10, 14, + 16, 14, 12, 13, 15, 18, 20, 22, 23, 20, 15, 8, 3, 2, 7, 13, + 15, 13, 7, 2, 0, 0, -1, -2, -1, 1, 2, 1, 0, 2, 3, 4, + 4, 6, 7, 5, 0, -10, -21, -30, -36, -36, -33, -28, -23, -18, -15, -14, + -17, -19, -19, -17, -12, -5, -2, -2, -3, -1, 2, 6, 10, 12, 14, 13, + 12, 13, 18, 25, 29, 28, 24, 19, 14, 10, 6, 6, 9, 12, 13, 15, + 17, 18, 18, 14, 7, 0, -1, 1, 1, -2, -6, -8, -10, -11, -13, -17, + -19, -18, -17, -16, -14, -14, -15, -17, -19, -22, -26, -26, -24, -20, -17, -14, + -13, -12, -10, -7, -4, 1, 5, 7, 9, 10, 13, 15, 17, 18, 21, 24, + 22, 21, 19, 17, 15, 13, 14, 14, 16, 17, 18, 16, 12, 10, 8, 6, + 5, 3, 0, -3, -6, -7, -5, -4, -4, -5, -5, -4, -4, -4, -8, -13, + -19, -24, -27, -28, -27, -25, -25, -27, -27, -25, -19, -14, -8, -3, 1, 6, + 9, 8, 3, -3, -6, -4, -1, 4, 9, 14, 18, 20, 22, 22, 23, 23, + 22, 21, 20, 20, 21, 21, 19, 15, 9, 3, -2, -4, -3, 0, 2, 2, + 2, 3, 3, 1, -4, -10, -15, -19, -19, -16, -11, -7, -7, -9, -13, -17, + -23, -28, -30, -29, -24, -20, -18, -19, -20, -19, -18, -19, -18, -13, -5, 1, + 6, 9, 11, 13, 16, 21, 26, 29, 30, 29, 29, 28, 26, 23, 20, 20, + 21, 21, 20, 18, 15, 9, 2, -4, -6, -5, -3, -3, -4, -6, -7, -9, + -10, -10, -10, -10, -11, -13, -12, -11, -8, -6, -6, -10, -17, -26, -32, -35, + -35, -34, -32, -27, -19, -9, -3, -1, -2, -5, -7, -6, -1, 7, 14, 18, + 21, 23, 25, 26, 26, 23, 20, 20, 23, 24, 24, 21, 19, 14, 8, 2, + -1, 0, 1, 2, 3, 6, 8, 8, 5, 2, -2, -5, -5, -4, -1, 1, + 1, -1, -6, -9, -11, -13, -17, -20, -24, -26, -27, -26, -23, -21, -20, -23, + -26, -27, -26, -24, -20, -15, -9, -2, 4, 8, 10, 13, 16, 19, 21, 23, + 25, 28, 33, 36, 38, 38, 35, 32, 29, 24, 16, 11, 6, 2, -2, -6, + -6, -5, -4, -4, -7, -11, -14, -13, -10, -8, -8, -8, -9, -11, -12, -12, + -11, -11, -12, -14, -17, -19, -19, -18, -18, -20, -22, -23, -21, -18, -14, -11, + -8, -4, -1, 5, 11, 13, 11, 8, 6, 7, 9, 11, 13, 15, 19, 22, + 23, 25, 27, 27, 22, 17, 11, 6, 4, 5, 9, 13, 15, 15, 11, 6, + 0, -4, -7, -8, -6, -3, -2, -3, -6, -9, -13, -18, -22, -23, -20, -15, + -11, -10, -11, -14, -19, -24, -27, -28, -28, -27, -26, -23, -19, -15, -10, -6, + -1, 4, 8, 10, 11, 11, 13, 15, 17, 20, 23, 24, 24, 26, 28, 28, + 28, 27, 26, 24, 22, 20, 16, 13, 10, 8, 6, 3, -3, -9, -15, -17, + -16, -15, -13, -13, -14, -17, -19, -20, -20, -17, -14, -12, -13, -14, -13, -13, + -14, -15, -14, -13, -12, -12, -12, -10, -8, -7, -8, -9, -9, -7, -4, 0, + 3, 6, 8, 10, 12, 14, 18, 22, 25, 26, 27, 28, 28, 27, 24, 20, + 16, 13, 11, 9, 6, 3, 0, -3, -3, -2, 1, 3, 5, 3, 0, -4, + -8, -12, -17, -21, -22, -20, -17, -15, -14, -14, -13, -15, -19, -22, -21, -18, + -14, -13, -15, -16, -17, -17, -19, -19, -16, -11, -4, 1, 6, 10, 13, 17, + 20, 23, 24, 24, 24, 25, 28, 33, 37, 38, 35, 30, 24, 20, 16, 13, + 9, 2, -4, -8, -8, -8, -7, -7, -9, -12, -16, -18, -18, -16, -15, -16, + -16, -16, -13, -10, -10, -11, -13, -15, -15, -15, -15, -16, -17, -16, -14, -13, + -13, -13, -13, -12, -9, -5, -2, 1, 3, 6, 12, 18, 22, 22, 21, 18, + 16, 16, 19, 23, 29, 32, 30, 24, 18, 13, 9, 6, 3, 0, -2, -4, + -6, -8, -10, -11, -10, -6, -3, -2, -3, -5, -5, -6, -6, -7, -6, -5, + -4, -5, -8, -10, -11, -12, -14, -16, -18, -20, -21, -21, -22, -23, -24, -24, + -22, -18, -11, -4, 1, 4, 5, 6, 8, 11, 15, 20, 24, 26, 27, 28, + 31, 32, 31, 30, 28, 27, 24, 20, 17, 14, 12, 9, 3, -3, -9, -12, + -15, -16, -17, -15, -13, -10, -10, -11, -13, -14, -15, -17, -19, -21, -23, -24, + -22, -18, -13, -9, -8, -8, -8, -9, -9, -9, -7, -4, 0, 2, 3, 5, + 5, 3, 3, 4, 5, 6, 7, 10, 14, 17, 20, 20, 20, 21, 22, 20, + 18, 16, 15, 14, 12, 9, 7, 6, 4, 2, -2, -5, -7, -9, -9, -8, + -5, -2, 0, 0, -1, -3, -7, -12, -16, -16, -15, -13, -12, -13, -13, -12, + -11, -11, -12, -15, -19, -23, -24, -22, -19, -16, -13, -10, -5, -1, 3, 6, + 7, 8, 8, 10, 13, 17, 21, 25, 27, 28, 28, 26, 24, 24, 25, 27, + 28, 29, 28, 25, 19, 12, 4, -3, -10, -15, -19, -22, -24, -25, -26, -25, + -23, -21, -20, -18, -17, -16, -14, -12, -11, -12, -14, -14, -13, -13, -15, -16, + -16, -16, -15, -11, -4, 0, -2, 0, 0, 3, 14, 34, 24, -3, -14, -12, + 6, 6, -11, -23, -5, 15, 20, 15, -19, -12, 3, 19, 11, -5, 1, 4, + 7, -13, -3, 5, -13, 0, -2, 8, 0, -6, 16, 23, 13, 6, 2, 14, + 25, 2, 11, 3, -7, -8, -24, -6, -4, -18, 6, 30, 14, 9, 0, 0, + 13, -7, 0, -3, 9, 8, -6, -14, -15, -23, -19, -7, 0, -3, 1, -8, + -10, -10, -17, -12, -7, -10, 1, -12, -13, 0, -15, -20, -25, -16, -6, -7, + -6, -6, -2, -4, -13, -12, -6, -6, -5, 2, 8, -5, -13, -3, -4, -11, + -16, -3, 12, -2, -8, -4, -4, 4, -15, -17, -6, -2, 5, -4, 3, -2, + -10, -4, -5, -7, -8, 4, 17, 1, -3, -14, -4, -2, -7, -4, -6, 10, + 5, -6, -7, -8, 10, -5, -3, 3, -8, 11, 7, -5, -3, -13, -7, 0, + -6, 4, 0, -7, 12, -9, -17, -7, 5, 2, -3, -4, -7, 7, -2, -13, + -5, -2, 5, 4, 0, 7, -3, 4, 1, -2, -4, 6, 8, 8, 0, -2, + 2, 3, 2, 1, -2, 5, 12, 6, 3, 2, -3, 2, 3, 1, 8, 6, + 7, 2, -5, -3, 1, 5, 2, 0, -3, 2, 7, 2, 0, -9, 0, 5, + 1, 3, 1, 4, 6, -5, -3, -2, 2, 6, 4, 6, 1, 2, 4, 4, + -2, 2, 5, 5, 7, 7, 2, 6, 0, 3, 0, -3, 8, 4, 4, 9, + -3, 2, 1, 1, 2, 1, 5, 5, 4, 6, 1, -6, -2, 3, 5, 6, + 4, 3, 4, 1, 2, -4, 0, 6, 2, 2, 4, 3, 5, -3, -2, -5, + -3, 5, 2, 1, 3, 1, -2, -3, -4, -6, 3, 5, 1, -2, 1, 2, + -2, -2, -2, -3, 3, 5, 3, 4, 2, 2, 1, 0, 1, 4, 9, 9, + 5, 2, 1, 6, 4, 4, 5, 5, 7, 8, 4, 5, 1, 2, 3, 1, + 1, 4, 2, 3, 0, -4, -7, -5, 0, -3, -3, -3, -5, 0, -8, -7, + -8, -5, -3, -6, -3, -4, -5, 0, -7, -4, -5, -3, 1, 1, -2, 1, + -2, 2, 0, 0, -2, 3, 5, 4, 5, 4, 2, 4, 2, 4, 5, 6, + 5, 6, 4, 4, 4, 4, 3, 4, 2, 4, 4, 2, -2, -2, 0, -3, + -3, -3, -4, -2, -7, -6, -7, -9, -7, -10, -9, -10, -10, -8, -11, -9, + -9, -12, -10, -13, -12, -7, -8, -6, -6, -9, -6, -5, -3, 0, 0, 1, + 1, 4, 3, 4, 8, 6, 8, 7, 6, 10, 9, 12, 12, 11, 12, 8, + 13, 10, 11, 10, 8, 9, 8, 6, 9, 4, 5, 0, -3, -5, -5, -6, + -7, -9, -12, -15, -17, -21, -18, -22, -21, -23, -25, -24, -27, -27, -26, -30, + -27, -27, -28, -20, -22, -19, -14, -15, -12, -10, -10, -2, 3, 4, 12, 12, + 14, 20, 17, 25, 27, 29, 33, 35, 35, 40, 38, 41, 39, 36, 38, 36, + 36, 38, 31, 33, 25, 21, 14, 8, 1, 2, 0, -3, -5, -15, -23, -28, + -40, -39, -43, -46, -43, -52, -53, -59, -66, -62, -69, -63, -64, -64, -50, -56, + -44, -45, -43, -38, -36, -31, -20, -8, 4, 12, 19, 18, 28, 31, 40, 52, + 57, 68, 73, 73, 77, 73, 81, 79, 82, 82, 77, 82, 77, 75, 69, 59, + 53, 42, 33, 24, 22, 17, 11, 1, -17, -25, -36, -42, -46, -55, -60, -64, + -73, -77, -88, -90, -92, -97, -98, -100, -100, -92, -85, -79, -80, -76, -79, -69, + -56, -50, -32, -24, -15, 0, -2, 11, 15, 29, 45, 55, 67, 72, 82, 88, + 95, 101, 102, 109, 109, 112, 109, 110, 110, 106, 104, 91, 81, 77, 68, 66, + 54, 42, 32, 14, 6, -6, -12, -20, -29, -43, -55, -65, -76, -76, -85, -89, + -97, -105, -107, -114, -115, -117, -117, -113, -112, -104, -101, -91, -85, -84, -70, -72, + -55, -42, -34, -14, -8, 5, 16, 22, 35, 44, 57, 69, 78, 89, 94, 101, + 104, 109, 109, 119, 118, 117, 120, 110, 114, 114, 99, 102, 84, 74, 72, 57, + 52, 43, 32, 22, 10, -7, -20, -28, -34, -47, -54, -60, -67, -71, -80, -87, + -90, -105, -105, -110, -120, -115, -120, -123, -113, -111, -109, -97, -98, -92, -83, -82, + -76, -63, -61, -48, -39, -30, -16, -3, 10, 22, 32, 42, 49, 61, 67, 76, + 84, 91, 101, 105, 115, 116, 117, 125, 115, 119, 116, 106, 111, 102, 97, 92, + 84, 79, 70, 64, 50, 45, 31, 19, 14, -2, -9, -19, -30, -35, -47, -54, + -62, -67, -73, -82, -86, -96, -100, -105, -109, -116, -118, -120, -120, -117, -111, -110, + -97, -96, -90, -84, -78, -73, -64, -55, -50, -39, -25, -20, 1, 11, 19, 37, + 40, 51, 61, 68, 76, 85, 94, 97, 105, 114, 112, 120, 122, 119, 121, 117, + 110, 106, 105, 92, 90, 84, 69, 71, 57, 48, 45, 29, 22, 14, -2, -9, + -22, -31, -40, -47, -59, -62, -68, -76, -80, -87, -97, -96, -111, -111, -116, -124, + -119, -123, -120, -109, -109, -98, -95, -93, -84, -81, -75, -66, -55, -51, -37, -28, + -16, 1, 12, 23, 39, 40, 55, 59, 68, 77, 86, 94, 103, 104, 116, 117, + 118, 125, 122, 117, 120, 107, 108, 104, 95, 92, 85, 72, 70, 60, 48, 43, + 29, 18, 10, -7, -12, -22, -30, -38, -49, -58, -63, -72, -75, -84, -90, -93, + -100, -110, -103, -121, -115, -115, -124, -110, -112, -111, -92, -98, -86, -81, -77, -69, + -61, -53, -48, -34, -27, -13, 1, 9, 28, 37, 45, 58, 59, 76, 78, 85, + 97, 98, 109, 114, 111, 123, 120, 119, 121, 116, 111, 110, 101, 93, 92, 79, + 73, 68, 55, 52, 40, 30, 21, 10, 0, -13, -23, -29, -41, -47, -58, -64, + -69, -75, -84, -89, -93, -103, -105, -110, -120, -115, -117, -128, -105, -114, -109, -88, + -102, -86, -76, -84, -64, -63, -56, -43, -37, -25, -10, 4, 11, 31, 36, 46, + 56, 58, 74, 78, 84, 100, 95, 110, 114, 110, 124, 120, 116, 121, 110, 105, + 108, 97, 96, 91, 79, 75, 66, 57, 51, 38, 29, 17, 5, -3, -13, -20, + -28, -40, -46, -55, -66, -68, -76, -85, -88, -97, -102, -106, -110, -117, -115, -120, + -122, -108, -117, -103, -98, -96, -86, -79, -77, -66, -59, -54, -46, -33, -31, -10, + -2, 11, 27, 36, 47, 58, 62, 74, 78, 86, 94, 96, 106, 109, 115, 120, + 118, 121, 119, 112, 114, 104, 98, 94, 85, 77, 72, 63, 56, 49, 37, 31, + 20, 6, -2, -15, -24, -33, -44, -50, -58, -63, -68, -76, -82, -89, -95, -105, + -105, -116, -118, -117, -126, -114, -111, -118, -92, -105, -92, -83, -88, -72, -71, -65, + -51, -50, -31, -25, -9, 2, 16, 29, 35, 50, 53, 67, 73, 75, 92, 88, + 104, 112, 108, 122, 117, 119, 123, 114, 116, 110, 104, 98, 94, 86, 80, 75, + 63, 59, 47, 36, 29, 13, 9, -5, -16, -21, -36, -40, -50, -61, -61, -73, + -77, -85, -93, -95, -103, -108, -117, -120, -118, -125, -117, -108, -116, -96, -98, -97, + -83, -82, -78, -66, -61, -54, -43, -32, -25, -2, 3, 16, 33, 36, 52, 56, + 66, 75, 78, 94, 91, 103, 113, 108, 122, 119, 119, 121, 116, 112, 110, 106, + 93, 96, 83, 76, 74, 59, 58, 47, 34, 28, 14, 6, -6, -17, -27, -36, + -44, -54, -61, -63, -70, -76, -86, -90, -99, -102, -108, -117, -115, -121, -123, -111, + -120, -102, -100, -101, -84, -91, -76, -74, -70, -54, -56, -41, -30, -20, -3, 8, + 23, 31, 46, 47, 59, 70, 71, 83, 89, 90, 108, 108, 115, 120, 121, 122, + 118, 118, 109, 110, 102, 93, 93, 82, 78, 72, 62, 57, 45, 37, 22, 15, + 4, -10, -18, -30, -36, -42, -54, -57, -63, -68, -77, -86, -91, -102, -103, -108, + -117, -114, -119, -117, -115, -110, -106, -100, -91, -99, -79, -81, -77, -59, -61, -50, + -36, -33, -16, -4, 10, 16, 35, 39, 48, 62, 64, 76, 85, 89, 98, 105, + 110, 113, 120, 119, 118, 123, 112, 111, 110, 100, 98, 93, 82, 78, 70, 58, + 54, 45, 30, 24, 12, 0, -7, -20, -28, -36, -45, -55, -61, -66, -73, -79, + -88, -93, -103, -105, -112, -119, -115, -124, -123, -109, -119, -103, -98, -102, -92, -84, + -83, -75, -62, -59, -50, -34, -34, -12, 1, 7, 26, 33, 42, 50, 62, 67, + 76, 88, 90, 101, 110, 108, 118, 121, 119, 122, 121, 111, 113, 110, 98, 98, + 91, 80, 78, 66, 58, 53, 40, 29, 20, 8, -4, -11, -22, -33, -37, -49, + -57, -61, -68, -77, -81, -90, -96, -101, -110, -112, -116, -120, -116, -121, -119, -104, + -111, -96, -91, -96, -79, -79, -76, -59, -57, -46, -33, -25, -14, 5, 11, 26, + 39, 42, 55, 61, 70, 81, 86, 94, 101, 105, 114, 116, 120, 121, 119, 119, + 115, 111, 107, 102, 94, 90, 82, 73, 68, 59, 50, 41, 28, 20, 7, -4, + -12, -22, -30, -41, -48, -56, -62, -69, -75, -83, -90, -98, -100, -107, -111, -119, + -112, -124, -120, -107, -119, -101, -93, -104, -80, -85, -83, -61, -65, -55, -40, -38, + -25, -7, -3, 13, 29, 34, 45, 57, 59, 74, 79, 87, 98, 98, 108, 111, + 112, 122, 117, 119, 119, 111, 110, 107, 96, 96, 89, 76, 74, 63, 54, 51, + 35, 27, 19, 5, -3, -12, -25, -29, -43, -52, -58, -64, -71, -78, -82, -92, + -98, -101, -108, -110, -114, -120, -119, -118, -115, -110, -106, -95, -97, -82, -84, -76, + -62, -63, -51, -42, -39, -20, -12, 2, 15, 29, 36, 47, 58, 62, 74, 80, + 85, 95, 101, 106, 111, 116, 118, 117, 122, 113, 115, 111, 99, 103, 90, 85, + 80, 68, 63, 56, 46, 36, 28, 17, 5, -5, -19, -25, -35, -43, -52, -58, + -62, -72, -75, -83, -94, -94, -105, -105, -115, -115, -116, -122, -114, -112, -108, -98, + -99, -89, -86, -82, -72, -69, -58, -52, -44, -31, -21, -6, 4, 17, 28, 39, + 48, 53, 66, 72, 80, 88, 92, 104, 108, 113, 116, 119, 121, 116, 119, 112, + 108, 107, 94, 94, 85, 79, 72, 62, 57, 48, 37, 25, 17, 8, -8, -15, + -26, -35, -42, -55, -59, -65, -73, -75, -87, -89, -97, -104, -109, -116, -116, -121, + -120, -120, -109, -108, -103, -90, -97, -78, -78, -77, -60, -64, -50, -41, -34, -16, + -7, 9, 19, 33, 42, 52, 60, 65, 77, 79, 87, 96, 99, 109, 113, 118, + 124, 117, 121, 117, 109, 110, 99, 94, 93, 83, 77, 73, 63, 55, 50, 32, + 26, 18, 0, -6, -20, -29, -34, -49, -53, -57, -63, -71, -76, -83, -91, -97, + -108, -112, -114, -122, -115, -124, -112, -105, -112, -89, -99, -90, -78, -89, -72, -66, + -61, -49, -41, -28, -16, 2, 6, 25, 35, 36, 53, 54, 67, 77, 79, 93, + 97, 105, 112, 111, 122, 118, 119, 117, 112, 109, 108, 99, 95, 92, 82, 76, + 71, 59, 56, 43, 30, 24, 10, 0, -9, -18, -26, -36, -45, -55, -59, -68, + -75, -81, -88, -94, -99, -106, -109, -110, -119, -117, -119, -116, -111, -105, -101, -91, + -92, -83, -75, -75, -61, -52, -52, -35, -29, -18, 0, 9, 22, 36, 41, 51, + 64, 68, 78, 88, 90, 101, 103, 109, 113, 115, 121, 117, 118, 116, 109, 109, + 102, 94, 90, 80, 71, 67, 57, 47, 42, 30, 19, 14, -4, -9, -19, -31, + -36, -50, -55, -61, -68, -74, -79, -87, -93, -101, -107, -107, -115, -118, -118, -123, + -112, -110, -109, -92, -93, -94, -74, -83, -71, -57, -61, -45, -34, -31, -10, 0, + 12, 27, 37, 42, 55, 61, 70, 77, 87, 95, 96, 106, 112, 113, 123, 122, + 117, 122, 112, 109, 110, 96, 96, 92, 76, 74, 68, 55, 50, 40, 28, 20, + 7, -6, -10, -23, -31, -42, -51, -59, -65, -70, -76, -82, -88, -92, -104, -104, + -105, -122, -113, -122, -126, -106, -119, -103, -91, -99, -82, -80, -76, -66, -59, -54, + -46, -34, -30, -9, 1, 13, 33, 34, 51, 57, 63, 76, 77, 91, 95, 95, + 110, 108, 115, 122, 120, 120, 123, 112, 110, 110, 94, 95, 87, 70, 74, 62, + 55, 50, 39, 29, 20, 7, -5, -13, -26, -35, -44, -56, -61, -65, -69, -75, + -83, -86, -98, -104, -104, -121, -115, -119, -128, -110, -117, -116, -92, -100, -90, -78, + -83, -75, -63, -64, -55, -41, -39, -20, -7, 1, 21, 31, 40, 51, 55, 67, + 72, 77, 91, 93, 99, 110, 109, 118, 125, 118, 124, 119, 108, 114, 101, 93, + 96, 81, 75, 73, 59, 57, 48, 35, 27, 15, 1, -7, -20, -29, -37, -49, + -56, -61, -65, -69, -74, -83, -91, -98, -107, -113, -117, -120, -122, -118, -115, -111, + -103, -101, -92, -89, -85, -80, -77, -65, -61, -51, -41, -33, -16, -4, 8, 21, + 34, 40, 49, 57, 63, 73, 82, 89, 98, 104, 109, 117, 118, 123, 122, 119, + 116, 110, 108, 100, 97, 93, 83, 80, 70, 64, 55, 45, 34, 22, 12, -2, + -10, -20, -30, -35, -48, -55, -62, -67, -71, -78, -86, -91, -101, -104, -110, -117, + -117, -120, -123, -111, -111, -110, -90, -99, -90, -76, -85, -71, -58, -63, -45, -37, + -33, -14, 1, 4, 27, 34, 41, 53, 59, 66, 79, 84, 92, 100, 103, 110, + 115, 116, 123, 118, 118, 117, 107, 110, 101, 95, 93, 79, 76, 68, 57, 52, + 43, 30, 23, 11, -3, -8, -20, -30, -34, -48, -55, -60, -69, -74, -81, -89, + -92, -101, -105, -108, -114, -117, -118, -122, -112, -113, -108, -95, -101, -87, -82, -83, + -68, -60, -56, -45, -38, -28, -17, -2, 6, 23, 33, 40, 54, 60, 68, 80, + 85, 94, 96, 103, 109, 110, 119, 118, 118, 121, 113, 112, 110, 100, 98, 90, + 77, 73, 66, 55, 51, 41, 29, 25, 8, 1, -9, -23, -28, -42, -51, -59, + -64, -67, -75, -79, -86, -94, -98, -105, -111, -115, -117, -121, -123, -111, -120, -102, + -95, -100, -79, -84, -81, -61, -69, -55, -46, -42, -27, -14, -3, 11, 30, 35, + 49, 57, 60, 76, 76, 86, 95, 95, 109, 108, 116, 122, 121, 123, 120, 116, + 114, 106, 100, 94, 88, 78, 73, 65, 59, 52, 38, 33, 20, 10, -2, -15, + -22, -32, -42, -51, -58, -62, -67, -77, -80, -86, -94, -100, -106, -113, -115, -119, + -122, -118, -117, -107, -106, -98, -89, -89, -78, -76, -71, -57, -56, -46, -36, -25, + -12, 0, 16, 26, 39, 49, 54, 67, 72, 80, 88, 94, 101, 104, 115, 113, + 121, 125, 116, 123, 116, 110, 109, 98, 93, 88, 78, 69, 65, 56, 47, 42, + 27, 20, 8, -6, -15, -27, -33, -43, -53, -58, -64, -68, -74, -86, -87, -96, + -106, -103, -117, -116, -117, -123, -117, -106, -114, -97, -96, -96, -81, -81, -80, -62, + -64, -49, -45, -34, -19, -8, 4, 17, 28, 40, 47, 54, 66, 73, 79, 93, + 95, 102, 113, 110, 117, 123, 119, 121, 117, 113, 111, 106, 96, 95, 88, 78, + 72, 63, 55, 47, 35, 26, 14, 4, -9, -19, -24, -35, -43, -51, -61, -65, + -72, -79, -88, -88, -99, -107, -107, -120, -114, -120, -122, -113, -116, -102, -106, -95, + -89, -95, -72, -80, -70, -50, -58, -37, -30, -20, -5, 6, 18, 29, 44, 45, + 57, 72, 68, 89, 89, 97, 109, 104, 120, 113, 118, 124, 112, 120, 112, 107, + 106, 96, 91, 87, 78, 66, 65, 52, 40, 39, 17, 17, 4, -13, -13, -30, + -35, -44, -58, -59, -66, -72, -78, -85, -93, -97, -106, -114, -110, -120, -120, -118, + -120, -109, -110, -98, -100, -89, -81, -87, -68, -68, -59, -44, -46, -29, -18, -5, + 5, 22, 32, 39, 54, 56, 68, 79, 79, 94, 98, 102, 110, 112, 117, 119, + 124, 117, 116, 116, 104, 106, 97, 89, 86, 74, 67, 60, 53, 41, 34, 24, + 12, 4, -9, -19, -28, -38, -47, -58, -60, -68, -73, -77, -88, -93, -96, -111, + -109, -115, -124, -118, -122, -120, -107, -109, -102, -91, -95, -82, -78, -78, -60, -59, + -51, -36, -35, -14, -3, 6, 24, 34, 41, 56, 59, 67, 81, 82, 92, 103, + 102, 112, 119, 114, 123, 123, 116, 121, 112, 106, 107, 93, 91, 84, 74, 69, + 61, 52, 43, 32, 21, 13, -2, -10, -22, -31, -38, -51, -56, -59, -69, -71, + -76, -87, -90, -100, -107, -110, -119, -118, -120, -123, -108, -118, -101, -92, -102, -77, + -85, -83, -63, -71, -58, -45, -44, -27, -15, -2, 10, 30, 32, 46, 57, 56, + 74, 73, 84, 93, 95, 109, 108, 117, 117, 124, 119, 119, 119, 112, 109, 100, + 96, 90, 81, 75, 65, 59, 51, 41, 33, 22, 12, 0, -12, -23, -30, -40, + -51, -57, -64, -71, -73, -83, -84, -95, -102, -102, -116, -117, -118, -128, -116, -114, + -116, -102, -99, -95, -86, -80, -80, -71, -58, -61, -46, -38, -30, -10, -4, 12, + 26, 37, 47, 54, 67, 68, 79, 89, 86, 104, 104, 111, 118, 118, 123, 121, + 119, 116, 112, 109, 99, 96, 88, 80, 75, 66, 58, 49, 41, 29, 19, 10, + -5, -10, -25, -35, -39, -53, -58, -64, -69, -75, -81, -87, -100, -99, -112, -116, + -118, -126, -123, -115, -120, -111, -102, -100, -93, -86, -85, -76, -69, -64, -56, -47, + -38, -25, -10, 4, 16, 31, 40, 46, 61, 65, 70, 83, 86, 93, 103, 105, + 114, 125, 118, 124, 125, 112, 120, 111, 98, 103, 91, 86, 83, 71, 66, 61, + 49, 38, 32, 16, 7, -4, -17, -26, -36, -44, -54, -60, -59, -71, -75, -79, + -94, -95, -103, -117, -112, -120, -127, -120, -118, -117, -104, -102, -99, -88, -84, -86, + -73, -70, -64, -51, -47, -37, -17, -10, 7, 19, 32, 40, 52, 56, 67, 73, + 80, 87, 92, 103, 109, 110, 123, 119, 121, 126, 111, 113, 112, 98, 98, 91, + 80, 80, 71, 60, 61, 47, 36, 30, 13, 5, -5, -19, -27, -35, -43, -52, + -58, -62, -71, -76, -84, -96, -100, -105, -118, -115, -121, -123, -121, -114, -117, -110, + -98, -105, -91, -83, -90, -71, -68, -64, -48, -43, -33, -17, -5, 3, 23, 32, + 38, 54, 59, 66, 79, 82, 92, 100, 105, 108, 116, 119, 117, 126, 116, 115, + 118, 106, 105, 99, 91, 85, 78, 67, 60, 54, 41, 33, 24, 11, 0, 3, + 10, 14, -8, 46, 7, -20, -23, -28, 17, 9, 47, -7, -15, -35, -1, -26, + 44, 34, -31, 31, -47, -32, 30, -2, 32, 15, -15, -17, -39, 16, -2, 26, + 23, 3, -43, 11, -37, 14, 37, 7, 4, -21, -30, -9, 14, 18, 38, -13, + -16, -21, -24, 8, 38, 3, 16, -29, -11, -26, 20, 15, 24, -9, 0, -34, + -21, 32, -16, 41, -1, -20, -7, -7, -7, 27, 0, -2, -2, -11, -11, 19, + -16, 32, -19, -4, 11, -40, 49, -13, -12, 12, -32, 12, 17, 1, 23, -34, + -20, 14, -20, 33, 44, -51, 7, -21, -38, 46, 19, 37, -28, -29, -17, -40, + 63, 36, -33, 42, -45, -57, 16, 37, -3, 54, 0, -64, -25, -7, 15, 37, + 34, -2, -65, -12, -3, -7, 76, -2, -6, -28, -22, -30, 40, 11, 12, 21, + -43, -6, -1, -31, 73, -35, 33, -1, -67, 29, -24, 16, 42, 4, -26, 17, + -71, 32, 0, 0, 72, -56, 4, -2, -75, 76, -25, 39, 24, -42, -6, -20, + -31, 56, 1, 3, 49, -63, -12, -16, -10, 49, 12, 29, -32, -59, 35, -39, + 35, 45, -33, -21, 46, -68, 13, 16, 12, 0, 2, 32, -70, 12, 30, -62, + 64, 5, -31, 22, -30, 11, -30, 43, 2, -8, 16, -3, -60, 39, -11, -13, + 63, -32, 8, -6, -45, 39, -38, 30, 49, -89, 96, -84, 0, 43, -51, 52, + -4, -6, 7, -31, -10, 12, -22, 62, 8, -57, 65, -101, 1, 69, -46, 76, + -18, -34, -24, -33, 50, -6, 55, 16, -70, -19, 2, -33, 59, 61, -40, 7, + -44, -33, -7, 61, 31, -15, 5, -32, -70, 47, 34, 8, 22, -16, -44, -47, + 56, -6, 12, 56, -46, -32, -3, 7, -4, 42, 19, -41, -35, 41, -59, 43, + 45, -44, 9, -9, -7, -19, 36, 2, -50, 49, -6, -34, 33, -1, -38, 17, + 44, -33, 5, 28, -68, -13, 62, -25, 15, 45, -57, -32, 23, -14, 37, 11, + 29, -56, -48, 46, -55, 48, 94, -74, 22, -40, -59, 36, 9, 75, -19, -31, + 6, -104, 39, 80, -23, 59, -12, -104, 10, -12, 24, 59, 5, 9, -78, -12, + 24, -47, 116, -6, -51, 34, -71, -26, 55, 3, 11, 38, -31, -9, -45, 21, + -11, 4, 92, -79, 16, -16, -41, 29, 27, 19, -5, -19, -13, -35, 29, 22, + -7, 20, -35, 6, -21, 30, -2, 6, -8, -20, -12, 30, -13, 8, 23, -52, + 21, 8, -16, 40, -20, -7, -15, -38, 62, -33, 48, 5, -66, 28, -25, 15, + 39, 5, -46, 8, -46, 32, 12, 37, -9, -49, 43, -78, 43, 46, -43, 39, + -41, -36, 13, 19, 48, -21, 9, -37, -54, 45, 32, -14, 41, -32, -66, 42, + -8, 37, 12, -10, -12, -74, 71, -30, 16, 65, -64, -1, -13, -12, 17, 24, + 10, -16, -31, -1, -3, 1, 68, -47, -7, -8, -41, 74, -16, 32, -27, -42, + 22, -49, 80, -11, 0, 23, -84, 34, -24, 31, 48, -37, 23, -55, -25, 22, + 14, 22, 59, -78, -11, -1, -45, 90, -35, 32, 0, -75, 63, -65, 34, 52, + -71, 70, -56, -14, 30, -22, 10, 55, -74, 41, -19, -47, 88, -62, 50, -11, + -57, 44, -54, 59, 17, -23, 12, -40, -41, 60, 3, 15, 28, -71, -1, -17, + 11, 61, -28, 47, -59, -48, 35, -18, 51, 27, -20, -35, -36, 14, 6, 44, + 23, -30, -33, -17, -1, 14, 49, -2, -32, -12, -20, 5, 29, 34, -33, 9, + -34, -26, 36, -2, 40, -28, 5, -26, -39, 65, -27, 19, 31, -54, 0, -8, + 12, 2, 30, -5, -25, -22, 24, -29, 26, 52, -57, 7, 5, -56, 46, 1, + 8, 4, -5, 1, -51, 28, 14, -21, 48, -17, -46, 4, 11, -6, 35, 7, + -16, -31, -10, 25, -49, 95, -28, -29, 19, -46, -5, 32, 21, 8, -1, -24, + -36, -17, 59, -7, 33, 10, -76, -14, 19, -1, 56, 16, -23, -64, -8, 7, + 8, 85, 0, -57, -21, -35, -7, 72, 23, 28, -66, -16, -47, 2, 68, 24, + 5, 0, -69, -26, 22, -7, 72, 0, -12, -20, -51, 15, -11, 44, 44, -46, + 36, -59, -38, 32, 19, -3, 71, -45, -28, -29, -17, 36, 8, 79, -47, -53, + 18, -65, 38, 75, -24, 20, -36, -34, -26, 38, 39, -7, -3, 7, -85, 44, + 26, -17, 42, -20, -29, -26, 26, 18, -8, 36, -17, -73, 40, 4, -1, 52, + -16, -47, -15, 14, 4, 29, 30, -41, -44, 15, -2, 16, 60, -26, -54, 17, + -33, 22, 48, -5, -15, -20, -13, -15, 31, 37, -28, 6, -17, -22, -10, 64, + -43, 16, 22, -71, 41, 3, -1, 6, -12, 12, -38, 11, 38, -49, 37, 24, + -64, 27, 18, -73, 81, -33, 14, -3, -32, 43, -60, 53, 24, -76, 70, -29, + -33, 50, -18, -34, 48, -38, 37, -15, -5, 25, -80, 70, -4, -45, 89, -72, + -3, 13, -23, 28, 21, -9, -9, -25, -11, 24, -26, 62, -14, -49, 67, -97, + 57, 12, -23, 46, -46, 9, -20, -4, 25, -1, 5, 18, -31, -25, 38, -43, + 44, 17, -42, 37, -66, 37, -16, 26, 18, -16, -17, -4, -17, 7, 38, -11, + 4, -3, -51, 32, -17, 38, 18, -34, 23, -58, 4, 25, 0, 26, 3, -35, + -11, -10, 16, 24, 8, 4, -33, -30, 22, -2, 14, 52, -61, 10, -23, -4, + 20, 10, 32, -44, -2, 1, -36, 37, 32, -25, 2, 0, -40, 14, 24, -5, + 13, -28, 20, -51, 41, 15, -23, 25, -12, -41, 30, -2, -11, 40, -34, 14, + -24, 3, 22, -31, 44, -22, -31, 57, -55, 28, 0, -9, 1, 11, -10, 8, + -13, 3, -2, -23, 60, -49, 23, 10, -59, 36, -3, -3, 35, -23, 5, -42, + 15, 7, -2, 35, 0, -45, 8, -4, -27, 63, -4, -14, 9, -39, 1, 1, + 27, 19, -27, 24, -49, -6, 34, -5, 10, 19, -32, -20, 14, -12, 16, 26, + -9, -19, -9, -8, 8, 7, 40, -29, -14, -4, -25, 7, 56, -15, 6, -20, + -36, 3, 10, 33, 20, -23, -5, -42, -18, 54, -17, 63, -5, -59, 2, -44, + 12, 57, 17, 15, -33, -44, -16, -17, 65, 40, -9, 10, -72, -51, 39, 10, + 65, 19, -25, -47, -51, 17, 20, 53, 30, -35, -35, -34, -16, 36, 48, 12, + -3, -35, -42, -9, 28, 34, 12, 15, -42, -39, 7, 8, 24, 28, 1, -31, + -36, 9, -1, 28, 29, -14, -34, 14, -43, 23, 34, -7, 24, -44, 10, -28, + -5, 53, -29, 29, -7, -33, 2, -1, 5, 19, 10, -17, 2, -33, 14, 1, + 8, 32, -36, 17, -28, -18, 36, -22, 29, 2, -25, 5, -17, 13, 1, 16, + -1, -10, -12, 3, -9, 10, 19, -22, 16, -3, -20, 24, -22, 15, -3, -14, + 22, -30, 31, -14, -11, 12, -11, 8, 17, -9, -4, -13, -13, 7, 10, 19, + -6, -7, -2, -32, 24, 8, 0, 17, -20, -10, -15, 13, 10, 11, 4, -1, + -40, 19, -4, -6, 42, -31, -1, -5, -12, 19, 6, 7, -5, -26, 10, -12, + 15, 20, -8, -19, 12, -40, 31, 15, -3, 16, -23, -27, 7, -5, 31, 6, + 3, -6, -41, 14, -2, 7, 38, -10, -29, 11, -44, 17, 29, 6, 20, -26, + 1, -45, 9, 31, -18, 40, -1, -47, 8, -10, -4, 29, 33, -25, 1, -31, + -12, -9, 35, 30, -25, 31, -48, -28, 20, 17, 9, 30, -19, -39, -13, 6, + 8, 38, 15, -10, -42, 0, -24, 15, 49, -9, -12, 5, -44, -5, 42, 4, + 6, 8, -27, -29, 5, 24, -2, 10, 28, -56, 1, 23, -29, 29, 15, -19, + -11, 1, -4, -8, 24, 6, -15, 2, 7, -27, 12, 21, -40, 36, -15, -12, + 22, -16, 17, -17, 15, -6, -18, 23, -3, -26, 39, -27, -5, 26, -20, 8, + 5, -11, 7, -21, 19, -11, -8, 35, -25, 2, 18, -35, 9, 16, -21, 29, + -16, 1, -13, -13, 28, -18, 23, 13, -36, 6, -1, -23, 26, 12, -15, 17, + -20, -2, -7, 3, 22, -22, 27, -11, -34, 36, -30, 11, 17, 2, -12, 13, + -22, -11, 11, -5, 26, -17, 26, -25, -32, 44, -47, 39, 25, -31, 16, -35, + -1, -4, 26, 16, 3, -16, -10, -23, -8, 55, -27, 26, 0, -63, 41, -26, + 28, 22, -23, 14, -42, 5, 20, -13, 28, 3, -42, 20, -6, -17, 52, -32, + 6, -2, -37, 42, -27, 29, 15, -51, 40, -38, 2, 33, -19, 6, 11, -43, + 25, 0, -19, 57, -54, 31, -9, -43, 58, -52, 36, 11, -44, 50, -44, 8, + 23, -24, 12, 6, -34, 25, -9, -15, 50, -55, 35, -7, -25, 49, -48, 32, + -23, -18, 37, -30, 28, 8, -27, 7, -2, -19, 22, 10, -11, 10, -27, 4, + -16, 18, 29, -19, 20, -22, -36, 16, -2, 18, 14, 3, -24, -15, -5, 12, + 13, 20, 4, -40, 2, -23, 8, 29, 7, 9, -23, -10, -13, 5, 19, 9, + -3, -14, -7, -19, 21, 6, 5, 10, -20, 0, -14, 12, 0, 2, 5, -13, + 1, -3, 12, -12, 20, -13, -7, 6, -11, 5, 0, 5, -5, -4, 10, -10, + 2, 6, -5, -12, 18, -13, -9, 19, -17, 11, -1, 8, -5, -22, 26, -26, + 1, 29, -17, -7, 16, -22, -8, 23, -3, 4, -3, -2, -15, -20, 42, -21, + 4, 40, -55, 8, 8, -22, 21, 20, -17, 2, -14, -7, -2, 10, 31, -25, + 10, -3, -54, 40, 5, -12, 42, -17, -37, 13, -12, 7, 24, 10, -6, -36, + 12, -9, -25, 74, -24, -19, 38, -64, 5, 25, 0, 16, 1, -9, -25, -23, + 36, -8, 6, 50, -58, -12, 22, -53, 52, 18, -12, 16, -51, 15, -30, 25, + 46, -37, 31, -26, -49, 30, 9, -1, 42, -19, -28, -13, -5, 16, 4, 42, + -18, -40, 20, -30, 1, 49, -4, -15, 0, -21, -19, 21, 26, 0, -9, 9, + -43, -1, 26, -5, 21, -7, -6, -32, 9, 12, -3, 34, -17, -12, -17, -4, + 9, 7, 28, -19, -3, -13, -11, 7, 15, 15, -19, 15, -38, -5, 17, -1, + 29, -20, 15, -39, -11, 41, -33, 45, -8, -21, -11, -3, 7, 0, 28, -7, + -19, -8, 7, -20, 23, 24, -40, 24, -17, -16, 26, -9, 21, -27, 13, -11, + -22, 29, -7, 0, 22, -22, -16, 14, -12, 12, 11, -5, -6, -17, 14, -15, + 9, 30, -28, 5, 1, -26, 8, 18, -7, 1, 6, -12, -15, 9, 13, -13, + 13, 13, -42, 14, 3, -16, 20, 7, -3, -22, 25, -26, 4, 16, -7, 3, + -8, 17, -33, 14, 9, -21, 25, -3, -11, -1, 1, -13, 1, 23, -20, 26, + -18, 0, -18, 3, 24, -25, 36, -15, -29, 22, -22, 3, 24, -5, -1, 0, + -18, 2, -11, 20, 10, -17, 30, -37, -15, 29, -33, 39, 11, -23, 7, -34, + 8, 0, 11, 36, -27, -12, 9, -47, 29, 31, -29, 40, -37, -14, 3, -17, + 45, -11, 8, 12, -60, 20, -2, -2, 41, -12, -18, 3, -37, 27, 12, -4, + 37, -56, 17, -21, -5, 44, -20, 14, -2, -40, 20, 0, 3, 22, -13, -10, + -6, -16, 29, -12, 14, 15, -49, 24, -11, -7, 39, -18, 3, -20, -12, 19, + -10, 32, 2, -34, 10, -13, -13, 37, 1, -7, 3, -33, 4, 2, 18, 25, + -25, 8, -33, -13, 34, -7, 24, 4, -33, -10, -2, 2, 25, 12, -1, -25, + -12, 3, -18, 34, 12, -15, 4, -9, -25, 10, 17, -3, 9, 2, -13, -23, + 9, 8, -13, 37, -10, -15, 1, -13, -1, 0, 31, -15, 0, 5, -29, 6, + 5, 15, -9, 16, -9, -29, 15, -10, 3, 15, 9, -11, -12, 11, -29, 17, + 14, -7, 6, -6, -7, -24, 30, -11, 9, 18, -20, -8, -6, 6, -10, 22, + 10, -29, 14, -13, -8, 13, 17, -13, 2, 1, -24, 5, 5, 12, -10, 15, + -7, -28, 21, -2, -8, 22, -9, -14, -2, 6, -5, 5, 12, -7, -15, 14, + -4, -16, 27, -10, -14, 13, -5, -9, 10, 5, -8, -5, 16, -20, 2, 13, + -14, -3, 17, -18, 2, 10, -12, 9, -6, -2, -16, 13, 10, -15, 33, -24, + -17, 10, -4, 15, 1, 9, -23, -9, 6, -5, 5, 21, -10, -13, 11, -21, + -2, 19, -10, 23, -20, 10, -16, -21, 33, -17, 17, 18, -30, 1, -14, -1, + 20, -2, 18, -15, -24, 6, -5, 6, 36, -26, 6, -18, -23, 34, -12, 25, + 1, -30, -1, -11, 10, 22, -1, 4, -19, -28, 21, -11, 22, 25, -33, 4, + -21, -7, 22, 7, 19, -23, -13, -3, -13, 21, 17, -11, 7, -19, -12, 12, + -10, 30, -13, -5, 4, -30, 27, -9, 17, -3, -25, 13, -23, 13, 27, -15, + -5, 3, -35, 17, 19, -8, 29, -37, 1, -15, -10, 48, -20, 26, -7, -49, + 22, -23, 21, 33, -10, -8, -17, -34, 11, 19, 12, 40, -39, -14, -13, -36, + 64, -4, 20, 9, -55, 3, -24, 21, 31, 10, -1, -22, -30, -7, 12, 18, + 29, -10, -7, -28, -22, 22, 3, 26, 4, -13, -18, -16, 21, -9, 28, -1, + -21, 0, -12, 5, 6, 5, 10, -20, 1, 3, -20, 21, 7, -23, 24, -25, + -6, 21, -13, 25, -19, -8, 2, -14, 20, 13, -23, 25, -31, -7, 24, -16, + 20, 6, -25, 8, -24, 12, 15, -10, 24, -25, -2, 0, -12, 14, 10, -13, + 4, 1, -17, 9, 6, -9, 9, 0, -3, -8, 11, -10, -2, 7, -1, -6, + 6, 1, -12, 1, 18, -31, 23, -2, -21, 21, -6, -8, 15, -14, 4, -6, + -1, 17, -22, 20, -6, -35, 37, -17, -6, 47, -41, 6, -6, -16, 12, 16, + 6, 1, -36, 18, -26, 4, 59, -36, -1, 16, -64, 30, 14, 1, 16, -13, + 0, -35, 17, 13, -8, 12, 14, -45, 11, 12, -24, 27, 12, -27, 10, -6, + -9, 1, 14, -7, -6, 8, -4, -8, 8, 8, -24, 13, 7, -27, 28, -1, + -28, 27, -19, -2, 17, -5, 6, -10, -5, 4, -25, 32, 2, -22, 32, -28, + -20, 35, -20, 16, 7, -18, 1, -22, 20, 0, 2, 20, -15, -25, 24, -25, + 12, 25, -23, 10, -19, -5, 8, 2, 20, -6, -13, 0, -22, 12, 15, -3, + 13, -13, -25, 12, -6, 18, 13, -3, -14, -22, 3, -2, 14, 25, -10, -16, + -5, -13, 2, 22, 9, -2, -11, -12, -20, 15, 20, 1, 14, -19, -17, -9, + 1, 19, 5, 0, 4, -35, 17, -7, 5, 20, -16, 2, -8, -11, 11, -2, + 2, 7, -19, 15, -10, 2, 12, -14, -3, 2, -9, 17, -3, 2, -7, -16, + 10, 2, 9, 10, -14, -9, -6, -11, 21, 5, 4, 6, -24, -5, -4, 6, + 18, 0, 8, -21, -18, 8, -8, 21, 16, -11, -9, -12, -15, 15, 3, 27, + -9, -16, 5, -30, 13, 23, -11, 21, -19, -15, -3, -9, 30, -9, 14, -6, + -22, -5, 15, -11, 23, -1, -14, -4, -9, 8, 4, 1, 20, -34, 9, 1, + -17, 24, -6, 1, -9, 1, -4, 3, 6, 8, -16, 0, 2, -13, 11, 21, + -31, 24, -21, -4, 13, -2, 7, -9, -3, 0, -18, 29, -4, -9, 16, -19, + -13, 25, -5, -1, 15, -24, 4, -15, 22, 4, -11, 20, -21, -25, 39, -23, + 14, 14, -23, 1, -8, 3, 12, -9, 23, -19, -18, 24, -22, 5, 30, -32, + 11, 2, -21, 18, -6, 5, 1, -9, 13, -22, 4, 19, -28, 26, 3, -28, + 21, -4, -25, 32, -15, 5, 0, -2, -4, -9, 15, 0, -13, 21, -14, -20, + 31, -19, 2, 17, -14, -9, 12, -6, 4, -1, 4, -17, -1, 12, -2, 0, + 20, -31, -8, 12, -8, 17, 14, -13, -16, -9, -7, 20, 11, 18, -13, -28, + -3, -12, 13, 40, -12, 4, -20, -32, 8, 17, 14, 21, -10, -28, -18, -2, + 11, 22, 17, 0, -34, -6, -3, -17, 50, 1, -13, 4, -22, -21, 17, 16, + 4, 7, 0, -27, -11, 4, 10, 2, 24, -6, -28, 7, -12, -2, 33, -3, + -6, 2, -37, 3, 9, 7, 24, -4, -14, -6, -24, 25, -1, 11, 16, -36, + -9, 12, -25, 45, 5, -20, 11, -36, 11, 7, 0, 30, -32, -1, 7, -33, + 37, 0, -9, 15, -21, -10, 12, -15, 24, -8, 3, 4, -20, 7, 3, -15, + 28, -14, -7, 13, -23, 2, 11, 0, 4, 7, -9, -16, 1, 7, -7, 19, + -3, -12, -14, 15, -10, 7, 30, -26, -13, 15, -30, 15, 26, -12, -1, -8, + -9, -5, 13, 22, -12, -12, 7, -36, 17, 31, -24, 27, -21, -24, 15, -10, + 26, 4, -12, 4, -36, 13, 14, -5, 27, -14, -22, 7, -12, 6, 23, -13, + 7, -19, -2, 7, -8, 25, -5, -17, 18, -25, 3, 14, -8, 4, 0, -1, + -11, 4, 12, -18, 15, 2, -23, 12, -2, -7, 12, 1, -1, -15, 11, -3, + -17, 41, -24, -7, 13, -25, 3, 22, -9, 15, -12, -9, 0, -17, 32, -5, + -5, 19, -49, 19, 3, -11, 45, -30, 2, -4, -28, 29, 0, 7, 12, -34, + 6, -10, 1, 33, -9, -6, 4, -41, 25, 2, 4, 29, -40, 8, -17, -9, + 42, -16, 16, -10, -33, 11, -7, 22, 12, -6, -6, -25, -4, 18, -3, 25, + -4, -29, 5, -17, 8, 22, 1, 4, -22, 1, -13, 2, 31, -19, 9, 2, + -36, 17, 5, -7, 20, -11, -2, -13, 4, 9, -18, 24, -3, -30, 33, -19, + -11, 31, -21, 6, 0, -5, 3, -10, 17, -7, -19, 30, -24, 0, 26, -23, + 3, 7, -17, 9, -3, 9, -1, -17, 23, -25, -3, 34, -27, 10, 15, -34, + 9, 1, 1, 7, -1, 12, -31, 4, 16, -27, 32, 10, -33, 10, -1, -27, + 29, 9, -9, 0, -1, -16, -6, 24, 2, -17, 23, -20, -24, 33, -11, -2, + 17, -7, -21, 13, 1, -7, 10, 1, -12, -9, 13, -1, -5, 20, -16, -15, + 15, -8, 5, 13, -10, -7, -9, 5, 2, 10, 7, -7, -22, 12, -13, 6, + 26, -14, -6, 0, -17, 3, 16, 6, 0, -11, 3, -26, 13, 15, -6, 7, + 4, -29, 6, 7, -3, 13, 1, -11, -9, 2, -1, 3, 9, -3, -8, 1, + -4, 0, 5, 0, 0, -2, 0, -1, 0, 0, -2, 11, 23, 22, 24, 25, + 20, 21, 15, 40, -1, -24, -42, -5, -19, -11, -8, 4, -46, -31, -14, -33, + -40, -44, -48, -89, -63, -47, -33, -27, -10, -6, 22, 25, 26, 28, 37, 11, + 15, 51, 44, 54, 66, 66, 71, 111, 84, 70, 63, 47, 39, 22, 47, -28, + -79, -111, -90, -91, -112, -81, -87, -49, -46, -5, -24, 26, 24, 47, 29, 23, + 30, 30, 13, -1, 4, -14, 17, 35, 62, 31, 53, 59, 72, 64, 27, 26, + 9, 9, -61, -44, -88, -74, -81, -83, -124, -96, -37, -78, -48, -56, -68, -60, + 7, 44, 39, 54, 77, 102, 110, 108, 89, 101, 100, 105, 64, 22, -1, 44, + 40, -19, -29, -35, -16, -27, -40, -77, -82, -113, -104, -93, -57, -72, -56, -3, + 1, 7, -1, 49, 39, 30, 31, 23, 10, 31, 11, 7, -19, -2, -2, 28, + 62, 92, 75, 33, 34, -20, -47, -61, -85, -105, -93, -119, -112, -54, -70, -67, + -32, -1, 4, 4, 20, 29, 62, 70, 54, 62, 78, 115, 92, 85, 78, 52, + 21, 19, 27, 2, -8, 13, 0, 5, 3, 9, 18, 0, -59, -61, -45, -57, + -65, -76, -89, -102, -48, -24, 17, 6, 26, 33, 35, 26, 41, 63, 20, 12, + 29, 34, 8, 7, 31, 21, 31, 39, 33, -5, -8, -55, -57, -98, -94, -88, + -64, -82, -74, -39, -14, 3, 16, 22, 8, 2, 17, 5, 36, 76, 74, 71, + 57, 73, 62, 47, 30, 32, 19, 4, 7, -14, -18, -2, 17, -5, 13, 22, + 31, 10, 8, -13, -47, -80, -85, -86, -71, -73, -60, -35, -10, 9, 19, 49, + 53, 47, 60, 73, 43, 33, 20, 13, -1, -7, -7, 7, 9, -2, 5, -14, + -40, -69, -61, -66, -67, -84, -58, -58, -33, 2, -7, -5, 12, 32, 18, 25, + 19, 24, 65, 59, 62, 64, 63, 55, 60, 52, 31, 19, -12, -26, -4, -7, + -10, -3, 6, -22, -14, 12, 19, 4, -26, -38, -40, -56, -61, -66, -59, -65, + -51, -20, 29, 40, 51, 52, 62, 61, 53, 26, 20, 6, 8, 6, 9, -14, + -14, -15, -2, -11, -23, -36, -38, -60, -77, -69, -60, -51, -56, -44, -27, 10, + -2, 14, 10, 22, 16, 41, 60, 39, 35, 60, 62, 43, 45, 63, 52, 17, + 12, 15, -1, -2, 0, -38, -48, -32, -22, -7, 3, 13, 10, -2, -1, -8, + -12, -25, -48, -46, -52, -49, -36, -17, 9, 17, 26, 48, 57, 55, 69, 60, + 32, 6, 4, -6, -20, -24, -9, -21, -25, -14, -18, -38, -38, -32, -51, -52, + -60, -34, -6, -6, -16, -11, -2, -1, 17, 19, 3, 11, 25, 31, 41, 39, + 33, 33, 41, 34, 34, 23, 21, 15, 6, -13, -24, -28, -20, -8, -12, -19, + -12, -5, 9, 14, 2, -12, -25, -28, -21, -28, -23, -22, -18, -26, -5, 24, + 45, 46, 47, 39, 33, 36, 42, 29, 7, -5, -10, -21, -29, -39, -39, -31, + -24, -29, -39, -51, -43, -27, -22, -18, -25, -26, -20, 9, 19, 18, 4, -2, + 19, 30, 38, 25, 24, 28, 33, 41, 38, 34, 32, 38, 24, 8, 4, -8, + -11, -15, -25, -31, -25, -20, -22, -15, -11, -9, -12, -17, -20, -20, -15, -6, + -11, -8, 0, 11, 29, 19, 17, 17, 18, 28, 31, 25, 18, 23, 18, 10, + 1, -7, -18, -26, -24, -30, -41, -38, -44, -32, -31, -31, -35, -25, -12, -2, + -8, -11, -13, -13, -2, 8, 15, 19, 29, 35, 37, 39, 43, 42, 40, 35, + 27, 25, 18, 15, 9, 4, -4, -15, -28, -28, -26, -28, -18, -15, -25, -23, + -12, -11, -14, -10, -2, -4, -1, 8, 15, 19, 22, 25, 16, 16, 17, 5, + 7, 13, 18, 13, 9, 6, 6, 4, -4, -21, -31, -28, -37, -39, -34, -38, + -38, -32, -17, -6, -4, -14, -19, -9, 3, -2, 3, 4, 7, 8, 13, 23, + 35, 38, 43, 42, 31, 25, 23, 17, 8, 3, 4, -7, -7, -10, -13, -20, + -19, -28, -33, -30, -23, -18, -13, -17, -12, 3, 14, 23, 31, 27, 23, 21, + 22, 19, 12, 4, 2, 2, -2, 0, 4, 11, 11, 6, 4, -2, -5, -14, + -17, -30, -38, -44, -42, -28, -21, -23, -21, -15, -15, -4, 8, 11, 4, -7, + -15, -7, 5, 10, 21, 26, 28, 27, 34, 37, 36, 28, 19, 10, 11, 8, + -2, -18, -17, -19, -19, -22, -24, -21, -24, -18, -17, -13, -19, -13, -1, 12, + 19, 22, 21, 19, 19, 30, 34, 24, 13, 7, 2, 1, 1, 2, -1, -2, + -6, 0, 0, -2, -15, -21, -17, -21, -28, -32, -31, -31, -32, -27, -24, -17, + -4, 1, -3, -1, 1, 4, 7, 8, 15, 16, 15, 15, 20, 32, 36, 38, + 32, 19, 12, 3, 2, -2, -4, -11, -19, -17, -15, -11, -16, -20, -27, -30, + -28, -22, -13, -6, -2, 2, 12, 23, 29, 45, 44, 36, 32, 21, 16, 14, + 10, 1, -9, -8, -2, -1, -7, -13, -13, -12, -9, -11, -18, -24, -26, -28, + -30, -24, -21, -21, -21, -11, -11, -10, 0, -2, 0, 4, 12, 13, 14, 12, + 17, 22, 28, 30, 28, 20, 16, 13, 8, 2, -2, -6, -15, -14, -18, -15, + -15, -16, -18, -18, -16, -19, -18, -17, -10, 0, -1, 4, 13, 22, 37, 39, + 36, 27, 27, 32, 26, 15, 6, -1, -4, -5, -7, -11, -11, -9, -15, -15, + -14, -18, -21, -19, -17, -21, -19, -15, -15, -10, -15, -14, -12, -11, -6, -2, + 1, -2, 1, 5, 14, 22, 33, 35, 23, 18, 16, 13, 11, 6, 1, -9, + -18, -11, -6, -7, -8, -9, -11, -11, -12, -13, -17, -21, -24, -24, -15, -4, + 7, 12, 17, 25, 30, 28, 31, 32, 31, 27, 22, 15, 12, 3, -2, -8, + -6, -3, -9, -13, -22, -24, -20, -18, -22, -24, -18, -14, -13, -10, -11, -9, + -3, -2, -3, -5, -10, -10, -5, -1, 4, 11, 15, 19, 22, 27, 23, 20, + 16, 14, 5, -3, -11, -15, -16, -12, -12, -11, -5, 1, -3, -10, -13, -15, + -11, -10, -10, -11, -8, -3, 2, 7, 9, 15, 25, 30, 33, 31, 25, 21, + 20, 16, 13, 7, -2, -8, -5, -4, -11, -20, -21, -22, -21, -17, -20, -21, + -22, -19, -19, -11, -4, -2, -2, -2, 2, 5, 2, 0, 0, -3, 1, 8, + 16, 13, 14, 17, 15, 13, 8, 5, -1, -6, -10, -13, -14, -14, -13, -10, + -7, -8, -8, -6, -6, -3, -1, -1, -9, -12, -7, 3, 13, 17, 14, 13, + 17, 22, 23, 24, 18, 15, 18, 18, 18, 15, 8, 0, -5, -8, -11, -15, + -17, -21, -26, -26, -24, -26, -24, -13, -9, -6, -3, -2, 3, 4, 6, 7, + 5, 2, 4, 2, -2, -4, -3, 5, 13, 17, 10, 3, -1, -2, -4, -5, + -11, -14, -13, -11, -8, -8, -8, -6, -3, 0, -1, -5, -5, 0, 4, 3, + 1, 2, 0, 0, 6, 13, 20, 17, 17, 18, 21, 18, 14, 13, 11, 11, + 7, 9, 3, -5, -12, -14, -18, -21, -23, -26, -26, -13, -3, -6, -13, -14, + -5, 5, 8, 3, 0, 1, 3, 6, 4, -1, -1, 1, 3, 7, 5, 3, + 0, 1, -1, 3, 0, -3, -11, -11, -9, -10, -9, -8, -5, -7, -7, -10, + -9, -6, -1, 4, 6, 4, 2, 5, 10, 13, 9, 12, 13, 14, 15, 16, + 13, 12, 10, 13, 14, 13, 8, 2, -1, -4, -6, -9, -15, -20, -21, -19, + -14, -16, -22, -21, -13, -5, -3, -3, -1, 3, 5, 10, 9, 9, 6, 8, + 7, 7, 7, 3, -4, -6, -4, -1, -4, -8, -10, -11, -8, -4, -6, -10, + -7, -8, -11, -11, -8, -5, -4, 0, 3, 3, 8, 10, 10, 12, 12, 11, + 10, 13, 12, 10, 6, 8, 9, 9, 11, 13, 11, 9, 10, 7, 2, -3, + -8, -9, -14, -16, -16, -19, -18, -14, -13, -11, -11, -10, -5, -1, 3, 5, + 2, 2, 9, 14, 11, 9, 10, 7, 2, 0, 2, -2, -9, -13, -15, -18, + -17, -15, -13, -10, -5, -5, -7, -7, -4, -1, 0, -2, -4, -2, 1, 4, + 9, 10, 10, 11, 11, 13, 14, 10, 11, 9, 9, 4, 6, 5, 4, 5, + 7, 8, 10, 9, 4, -4, -8, -9, -10, -11, -12, -14, -15, -17, -15, -9, + -4, -1, -6, -5, 2, 8, 8, 6, 5, 3, 4, 5, 9, 10, 10, 5, + -1, -5, -10, -12, -14, -16, -18, -17, -11, -10, -11, -8, -5, -2, -2, 0, + 3, 4, 5, 3, 2, 3, 5, 9, 12, 12, 11, 10, 12, 14, 12, 8, + 5, 0, -1, 1, 3, 0, 1, 3, 5, 6, 5, 0, -5, -11, -10, -13, + -12, -13, -15, -14, -8, -4, -3, -3, -4, 0, 4, 5, 3, 6, 4, 4, + 7, 10, 9, 9, 8, 5, 5, 2, -4, -10, -15, -17, -20, -22, -22, -19, + -14, -11, -10, -8, -6, 0, 3, 5, 3, 4, 8, 11, 11, 12, 13, 12, + 12, 15, 15, 16, 16, 13, 11, 6, 3, -2, -5, -5, -3, -2, -1, 2, + 0, -3, -4, -5, -7, -10, -12, -11, -12, -11, -8, -4, -2, 0, 1, 2, + 2, 2, 4, 3, 3, 4, 5, 9, 10, 6, 2, 1, 2, 0, -3, -7, + -13, -18, -19, -18, -16, -18, -20, -19, -14, -8, -4, -1, 3, 3, 5, 7, + 9, 9, 10, 12, 13, 13, 13, 13, 16, 15, 13, 9, 6, 3, 2, 1, + 0, -3, -5, -6, -4, -2, -2, -4, -4, -5, -5, -3, -3, -4, -6, -6, + -7, -4, 0, 2, 3, 2, 2, 1, 2, 2, 1, 4, 5, 4, 1, 0, + 2, 2, 0, -2, -6, -8, -6, -7, -9, -11, -15, -18, -19, -18, -18, -17, + -13, -9, -2, 2, 3, 5, 10, 12, 13, 14, 14, 15, 17, 17, 16, 16, + 15, 13, 11, 7, 2, -6, -10, -8, -6, -8, -8, -7, -6, -6, -3, -4, + -6, -5, -3, -2, -2, 0, 1, 0, 2, 2, 3, 2, 3, 2, 3, 3, + 5, 2, 0, 4, 6, 5, -1, -4, -2, -1, -2, -6, -8, -9, -10, -12, + -10, -14, -17, -22, -22, -21, -19, -15, -8, -3, 1, 7, 12, 12, 15, 19, + 22, 21, 18, 16, 16, 16, 13, 12, 6, 3, 3, 2, -3, -6, -7, -12, + -12, -11, -8, -9, -8, -7, -3, 0, 0, 0, 0, -2, -2, 0, 1, 2, + 2, 4, 6, 6, 7, 5, 4, 3, 4, 5, 3, 0, -2, -2, -4, -6, + -10, -8, -8, -10, -11, -12, -12, -12, -13, -16, -16, -16, -14, -11, -8, -4, + -2, 1, 6, 12, 17, 19, 20, 20, 21, 21, 19, 13, 10, 9, 5, 0, + -3, -4, -4, -5, -6, -6, -4, -7, -10, -12, -12, -12, -10, -7, -4, -2, + 4, 6, 8, 7, 7, 7, 7, 8, 8, 7, 5, 6, 6, 4, 1, -1, + -1, 0, -3, -7, -10, -10, -8, -11, -14, -14, -12, -11, -9, -6, -8, -8, + -8, -11, -13, -12, -9, -8, -5, 0, 4, 8, 11, 14, 18, 18, 20, 23, + 23, 20, 14, 9, 4, 0, -3, -6, -8, -8, -8, -8, -9, -10, -11, -10, + -9, -8, -8, -7, -6, -3, 0, 3, 6, 12, 16, 16, 14, 10, 8, 9, + 7, 4, 1, 0, 0, -2, -1, 0, 0, -3, -7, -10, -13, -13, -12, -13, + -15, -14, -13, -9, -6, -5, -5, -7, -8, -9, -7, -6, -5, -7, -5, 1, + 8, 13, 17, 19, 20, 21, 22, 22, 18, 12, 9, 5, -1, -5, -9, -11, + -13, -12, -12, -11, -10, -8, -7, -7, -6, -7, -6, -3, 0, 1, 3, 7, + 10, 11, 12, 15, 15, 14, 9, 6, 3, 1, 0, -2, -2, -2, -3, -6, + -8, -10, -11, -13, -15, -15, -15, -13, -12, -12, -7, -5, -5, -5, -4, -3, + -3, -4, -4, -1, -1, 1, 4, 7, 10, 12, 14, 17, 20, 22, 19, 14, + 8, 5, 2, -2, -5, -10, -14, -13, -11, -10, -10, -10, -10, -8, -6, -3, + -3, -3, -1, -1, 2, 6, 10, 13, 14, 15, 15, 15, 13, 11, 8, 5, + 1, -1, -3, -3, -6, -10, -12, -12, -12, -12, -13, -15, -18, -19, -15, -11, + -6, -4, -3, -4, -4, -2, 1, 4, 2, -1, -2, 1, 4, 6, 8, 7, + 7, 11, 14, 15, 15, 15, 13, 10, 6, 1, -3, -6, -9, -13, -15, -15, + -13, -11, -9, -9, -9, -7, -3, 0, 2, 2, 4, 7, 11, 15, 16, 14, + 11, 12, 13, 15, 13, 9, 4, 1, -1, -4, -6, -8, -11, -15, -17, -17, + -17, -17, -15, -13, -13, -12, -10, -7, -6, -4, 1, 2, 2, 3, 4, 5, + 4, 4, 3, 5, 6, 6, 8, 7, 7, 9, 11, 10, 9, 8, 5, 2, + 0, -2, -6, -10, -13, -13, -14, -14, -13, -11, -9, -4, -1, -1, -1, 2, + 6, 8, 10, 11, 12, 14, 14, 14, 13, 11, 10, 7, 4, 2, 3, 1, + -3, -6, -10, -14, -17, -18, -18, -19, -19, -17, -15, -13, -9, -5, -1, 1, + 0, 1, 3, 5, 6, 6, 6, 7, 8, 9, 8, 4, 1, 0, 2, 4, + 5, 6, 5, 4, 4, 4, 3, 1, -3, -7, -9, -11, -12, -12, -12, -11, + -10, -7, -4, -2, 1, 4, 5, 8, 11, 13, 14, 14, 11, 11, 11, 10, + 10, 9, 6, 5, 3, 1, -2, -5, -10, -14, -16, -17, -18, -19, -20, -19, + -17, -14, -10, -5, -1, 1, 3, 5, 6, 6, 6, 6, 6, 6, 6, 6, + 8, 7, 6, 4, 2, 0, -1, 0, 0, 1, 2, 1, 1, 2, 1, -2, + -5, -8, -9, -10, -11, -12, -12, -10, -7, -4, -1, 2, 8, 11, 13, 15, + 15, 13, 12, 11, 10, 9, 8, 6, 5, 4, 4, 3, 0, -3, -6, -10, + -14, -18, -21, -22, -21, -18, -16, -13, -10, -6, -3, 0, 3, 5, 5, 5, + 6, 7, 8, 8, 8, 7, 8, 7, 6, 5, 4, 1, 0, -2, -4, -4, + -5, -4, -4, -3, -2, -1, -2, -3, -4, -7, -8, -9, -9, -9, -8, -5, + -2, 2, 4, 8, 11, 14, 15, 15, 14, 12, 10, 7, 5, 4, 4, 2, + 1, 1, 2, -1, -3, -7, -10, -15, -18, -18, -18, -18, -17, -15, -11, -7, + -3, 1, 3, 4, 5, 6, 7, 7, 8, 8, 9, 10, 10, 9, 6, 4, + 2, 0, -3, -4, -6, -7, -7, -6, -5, -3, -2, -2, -2, -2, -3, -4, + -5, -6, -6, -6, -6, -5, -4, -1, 4, 7, 9, 11, 12, 12, 11, 10, + 9, 8, 7, 5, 3, 3, 2, 1, 0, -1, -4, -7, -8, -10, -13, -14, + -15, -15, -15, -14, -11, -9, -6, -3, 0, 2, 4, 5, 6, 7, 8, 9, + 10, 10, 9, 8, 6, 5, 3, 1, -3, -6, -8, -8, -7, -7, -7, -6, + -4, -2, 0, -1, -2, -3, -3, -3, -3, -4, -3, -3, -1, 1, 3, 4, + 6, 7, 8, 9, 10, 10, 9, 7, 6, 6, 4, 3, 2, 1, -1, -2, + -4, -6, -9, -11, -12, -12, -12, -11, -11, -10, -9, -8, -7, -5, -4, -1, + 1, 3, 5, 7, 9, 10, 11, 10, 9, 8, 7, 6, 2, -1, -3, -4, + -6, -7, -7, -7, -7, -6, -5, -5, -4, -3, -3, -4, -4, -4, -3, -2, + 0, 0, 1, 1, 2, 4, 6, 6, 7, 7, 8, 7, 7, 7, 7, 7, + 6, 5, 2, 0, -2, -4, -5, -7, -8, -8, -8, -9, -10, -10, -9, -8, + -7, -7, -7, -5, -3, -2, 0, 1, 2, 4, 6, 9, 10, 11, 12, 10, + 8, 6, 3, 1, -2, -4, -6, -7, -7, -7, -7, -8, -7, -7, -6, -6, + -5, -4, -3, -3, -2, -1, 1, 2, 2, 3, 4, 5, 5, 5, 6, 6, + 6, 5, 5, 6, 6, 6, 4, 3, 2, 1, -1, -3, -4, -6, -8, -9, + -9, -8, -8, -6, -5, -5, -5, -6, -6, -6, -5, -4, -2, 0, 2, 4, + 6, 7, 8, 9, 9, 9, 9, 6, 4, 1, -1, -3, -5, -6, -7, -7, + -7, -6, -6, -6, -6, -6, -5, -4, -3, -3, -2, -1, 1, 3, 4, 5, + 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 1, + -1, -3, -4, -5, -6, -7, -7, -7, -7, -7, -6, -5, -4, -4, -3, -3, + -3, -3, -2, -1, 0, 1, 3, 5, 7, 8, 8, 8, 7, 6, 4, 2, + 0, -2, -3, -4, -5, -6, -7, -7, -7, -7, -6, -6, -5, -5, -5, -3, + -2, 0, 1, 2, 3, 4, 5, 6, 6, 6, 5, 5, 4, 3, 3, 3, + 3, 3, 3, 2, 1, 1, -1, -2, -3, -4, -5, -6, -6, -7, -6, -5, + -4, -3, -3, -3, -3, -3, -2, -1, -1, 0, 1, 1, 1, 2, 3, 5, + 6, 6, 6, 5, 4, 2, 1, 0, -2, -4, -5, -5, -6, -6, -6, -7, + -7, -7, -6, -5, -4, -3, -2, -1, 0, 2, 3, 3, 4, 4, 5, 5, + 5, 4, 4, 4, 4, 3, 3, 2, 1, 1, 0, 0, -1, -1, -2, -3, + -4, -5, -5, -5, -5, -5, -4, -4, -3, -3, -2, -1, -1, -1, -1, 0, + 0, 0, 1, 2, 3, 3, 4, 4, 4, 4, 4, 3, 1, 0, 0, -2, + -3, -4, -5, -5, -6, -6, -6, -5, -4, -4, -4, -3, -2, -2, -1, 0, + 2, 3, 3, 4, 4, 4, 4, 3, 3, 3, 3, 2, 2, 1, 1, 1, + 0, -1, -1, -2, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -2, -2, + -2, -1, -1, -1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, + 2, 1, 1, 0, 0, -1, -1, -2, -3, -3, -3, -4, -4, -4, -4, -3, + -3, -2, -1, -1, -1, 0, 1, 1, 1, 2, 2, 2, 3, 3, 2, 2, + 1, 1, 1, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -5, -41, -25, -37, -9, 28, 14, 6, 1, + 19, 16, -83, -53, -35, -44, -29, 8, -23, -29, -6, -20, -22, -19, -40, -2, + 14, 34, 78, 59, 73, 93, 73, 83, 124, 94, 87, 61, 98, 80, 29, 27, + 6, 8, -9, -8, -26, -33, -35, -32, -25, -32, -28, -59, -46, -31, -19, -12, + -12, 14, 14, -41, -59, -46, -33, -32, -52, -31, -29, -49, -51, -53, -85, -53, + -60, -100, -85, -84, -66, -37, -26, -11, -8, 22, 41, 33, 39, 27, 29, 75, + 59, 45, 52, 69, 66, 73, 90, 91, 103, 81, 46, 16, -21, -32, -13, -34, + -22, -42, -51, -35, -53, -62, -45, -35, -34, -29, 25, 62, 61, 39, -8, -20, + -5, -7, 2, 28, 1, -24, 8, 29, 11, -9, -54, -34, -35, -57, -41, -63, + -50, -16, -18, 26, 23, -2, 38, 9, 17, 41, 39, 82, 64, 64, 103, 64, + 43, 43, 51, 26, -3, 30, 1, 9, 14, -26, 20, -27, -50, -39, -47, -31, + -23, -33, 25, 56, 51, 20, -19, -60, -41, -27, -10, 3, -36, -30, -22, -46, + -5, -12, -7, -4, -54, 3, -25, -10, -1, -42, -75, -27, -84, -60, -88, -107, + -73, -29, -67, -53, 9, -10, 17, -29, -33, 55, 12, 7, 121, 70, 42, 123, + 96, 127, 74, 28, 51, 21, 60, 23, -10, 25, 103, 113, 65, 45, 15, -1, + 10, 2, -26, 1, -16, 19, 27, -8, -8, -24, -20, -17, -35, -86, -87, -32, + -51, -26, -60, -60, -50, -15, -31, -30, -50, -55, -19, 22, 14, 30, 49, 42, + 15, -11, -57, -15, -29, -65, -37, -56, -29, 15, 70, 69, 36, 24, 19, 21, + 19, 4, 60, 55, 18, -17, 0, -2, -21, 51, 49, -6, 22, 14, -24, -63, + -5, 4, -53, -33, -1, -37, -34, 40, 30, 12, -6, -1, 12, 12, 23, 20, + 43, 34, 11, -26, -40, 25, 56, -1, -41, -50, -37, -10, 20, -58, -65, -43, + -26, 42, 57, 77, 57, 26, -4, -10, -57, -45, -23, -49, -1, -59, -41, -26, + -27, 24, 52, -3, -12, 19, -44, -31, 33, 11, -14, 43, 31, 7, 58, 84, + 45, 35, 18, -5, 6, -21, -6, -20, -7, 41, 53, 29, 25, 55, 68, 37, + -29, -17, -41, -67, -76, -90, -112, -104, -60, -21, 25, 16, -23, -9, 30, 47, + 17, 3, 19, 4, -2, 30, 24, 1, 26, 33, 34, 10, 14, 1, -5, 16, + -2, -60, -32, -51, -48, -38, -34, -42, -20, 16, 17, -16, -32, -6, 4, -39, + -18, 1, -20, -22, 55, 70, 34, 5, -1, 13, 2, 1, 28, 20, -31, -2, + 51, 26, 24, 19, 11, -1, 2, 30, 13, 2, 70, 36, 15, 24, 5, 9, + 14, 48, 43, 8, 2, -10, 18, 33, 22, -27, -19, -17, -22, 11, 19, -5, + 0, -55, -60, -49, -63, -72, -45, -80, -55, -18, -8, 32, 52, 22, 0, -40, + -42, -30, -68, -51, -9, -67, -52, -10, 7, 35, 12, 36, 64, 23, 13, 64, + 39, 32, 73, 3, 6, -10, -6, 16, 18, 53, 51, 21, -20, -15, 13, -3, + 2, -39, -30, -7, -3, 6, 10, -4, -25, -7, -10, -10, -18, -31, -23, -38, + -48, -3, -26, -43, -7, 11, 31, 62, 41, -7, -34, -42, -24, 17, 12, 44, + 25, 24, 18, 11, 32, 51, 46, 46, 51, 33, 24, 32, 30, 40, 8, -30, + -39, -30, -44, -19, -33, -55, -41, -36, -70, -67, -64, -34, -37, -46, 1, 19, + 27, 81, 23, 13, 10, -5, -18, -19, -51, -14, -48, -75, 11, 51, 43, 63, + 37, 20, 19, 4, -23, 27, 47, 71, 29, 16, 15, -17, -11, 32, 40, 22, + 6, 16, -7, 5, 34, 61, 12, -21, -24, -13, -38, -41, -36, -33, 2, 9, + -45, -54, -36, 12, -18, -41, -25, -18, 19, 31, -11, -16, -22, -62, -65, -68, + -42, -4, -48, -49, 4, 38, 65, 47, 12, -20, -20, -8, 3, 32, 69, 84, + 44, 28, 31, 18, 36, 57, 74, 35, 19, 6, 24, 29, 36, 35, 6, -13, + -25, -43, -45, -35, -33, -44, -23, -41, -57, -52, -41, -35, -21, -16, -22, -11, + 33, 42, 14, 19, 16, 0, -6, -34, -17, -37, -25, -7, 6, 48, 47, 3, + -14, -17, -19, -11, -9, -11, 42, 42, 16, 1, 6, 15, 51, 42, 33, 29, + 20, -5, -3, 4, 54, 42, 8, -30, -19, -15, -15, -20, -6, -7, -24, -32, + -24, -17, -1, -16, -18, -36, -55, -38, -2, 8, 16, 7, -21, -35, -56, -67, + -17, -58, -67, -36, 21, 67, 48, 15, 8, 13, -9, -8, -1, 21, 107, 56, + 40, 56, 32, 33, 71, 60, 36, 30, 3, 31, 15, 4, 21, 2, -2, -25, + -30, -26, -13, -9, -26, -20, -34, -34, -51, -28, 6, -9, -24, -49, -67, -54, + -54, -52, -41, -42, -58, -37, 16, 39, 31, 16, 19, 11, -4, -23, -5, 24, + 1, 10, 24, 26, 15, 34, 70, 77, 56, 33, 43, 28, 17, 25, 12, 2, + 0, -12, -15, -2, 10, -19, -28, -45, -41, -28, -17, -3, -2, -9, -3, -25, + -45, -14, 23, 10, -5, -19, -32, -22, -10, -1, -15, -16, -6, 13, 48, 70, + 55, 23, 23, 10, -8, -14, 6, 8, -12, -5, 13, 10, -14, 0, 33, 23, + 18, 43, 21, 26, 33, 13, -14, -7, -3, -31, -29, -5, -5, -25, -27, -35, + -56, -45, -21, -17, -40, -14, 2, -23, -38, -9, 8, -16, -16, -7, -13, -25, + -4, -12, -21, -14, 3, 13, 44, 65, 60, 40, 15, 5, -20, -22, -3, 3, + 20, 39, 39, 9, 6, 21, 48, 24, 25, 25, 11, 0, 4, -5, -31, -34, + -22, -45, -40, -24, -24, -41, -38, -47, -54, -45, -16, -22, -32, -7, 16, -1, + -11, 23, 31, -1, -10, -20, -19, -9, 15, -10, -28, -21, 4, 24, 45, 60, + 56, 46, 30, 26, 23, 36, 48, 33, 46, 40, 34, 19, 12, 23, 43, 37, + 41, 43, 22, 24, 11, -11, -2, -5, 8, -28, -33, -11, -5, -26, -30, -25, + -45, -21, -8, -26, -35, -37, -39, -54, -56, -20, -23, -42, -52, -49, -63, -47, + -31, -29, -16, -21, -7, 14, 26, 48, 32, 12, -10, -22, -24, -6, 0, 33, + 44, 31, 25, 15, 10, 34, 48, 38, 14, 9, 16, 12, -23, -15, -15, -8, + -9, -19, -22, -2, -8, -10, -32, -27, 4, 12, -5, 1, -1, 4, -5, -3, + -5, 10, 37, 18, -8, -19, -3, 0, -10, -5, -31, -32, -29, -2, 18, 32, + 33, 14, -12, -15, 6, 8, 36, 66, 48, 38, 37, 42, 29, 49, 50, 42, + 28, 25, 33, 15, 2, 4, 2, 4, 2, -11, -1, 6, 3, 9, -14, -12, + -5, -12, -33, -36, -29, -26, -38, -44, -42, -38, -38, -52, -67, -70, -50, -32, + -27, -29, -38, -26, -27, 1, 21, 23, 16, -17, -34, -26, -18, -20, 2, 11, + 13, 5, 10, 13, 12, 28, 33, 35, 14, 14, 14, -8, -24, -25, -8, -16, + -23, -14, 12, 8, 21, 25, 13, 25, 29, 25, 6, 3, 36, 26, 34, 11, + 30, 29, 34, 23, 0, 1, 7, 8, 1, -10, -9, -13, 5, 17, 30, 26, + 25, 3, -11, -4, -4, 9, 13, 17, 6, 4, 17, -1, -4, 9, 16, 22, + 3, -2, -4, -16, -28, -22, -13, -34, -37, -31, -9, -7, -12, -16, -26, -12, + -14, -11, -23, -16, -24, -33, -24, -30, -17, -28, -34, -44, -51, -34, -24, -22, + -25, -2, 14, 23, 38, 46, 43, 28, 10, -6, -11, 1, 0, 5, 18, 16, + -3, 12, 27, 23, 32, 48, 42, 34, 21, 21, 10, -3, -10, -10, -20, -38, + -34, -29, -22, -16, -15, -17, -9, 7, 6, 6, -6, 1, 7, 6, 3, 11, + 30, 30, 15, 11, 11, 10, 17, 22, 23, 24, 9, 15, 5, -2, 4, 3, + -17, -21, -4, -21, -6, 8, -9, -1, 0, 8, -7, -18, -16, -3, -14, -13, + -8, -17, -10, -8, -26, -37, -28, -17, -35, -17, -10, 1, -6, 1, 25, 32, + 26, 9, -18, -19, 1, -12, -20, 2, 12, 5, -4, 15, 14, 15, 15, 17, + 14, 2, 6, 3, -18, -21, -9, -1, -15, -11, -15, -22, -1, 3, -7, 0, + 14, 14, -4, -13, 4, 18, 12, 15, 19, 25, 28, 27, 12, 9, 9, -10, + -17, -4, -5, -4, -20, -19, 11, 20, 13, 0, -19, -8, 6, -9, 6, 26, + 18, 14, 17, 22, 24, 18, 21, 37, 20, 7, 11, -8, -11, -4, -3, -8, + -22, -16, -18, -15, -4, -9, -21, -10, 5, -8, -7, -17, -7, -9, -20, -28, + -35, -31, -23, -23, -29, -28, -28, -33, -28, -24, -6, 0, -4, 7, 29, 25, + 15, -6, -19, 1, -2, -22, 4, 10, 1, 9, 10, 13, 4, 6, 21, 15, + 5, 21, 11, -18, -21, -15, -3, -4, -15, -15, -19, 4, 19, 11, 2, 17, + 16, 2, 14, 14, 17, 20, 22, 20, 10, 16, 27, 12, 8, 11, 5, -9, + -10, -6, -1, -7, -12, -3, 3, 8, 9, -5, -3, 6, -5, -6, 23, 14, + 11, 12, 21, 21, 4, 18, 30, 7, 12, 25, 3, -11, -16, -15, -10, -13, + -8, -6, -21, 2, -2, -25, -18, -8, -22, -22, -17, -12, -7, -12, -15, -20, + -41, -28, -24, -23, -12, -12, -15, -10, -7, 2, 1, 6, 18, 29, 23, 21, + 20, 9, -3, -9, -9, -10, -15, -8, -11, -2, 6, 14, 7, 7, 11, 9, + 14, 2, 3, 7, 6, 6, -21, -20, -10, -12, -15, -16, -18, -14, -11, -14, + 0, 0, -5, 3, 14, 12, 9, 0, -11, 5, 5, 12, 11, -1, 5, 3, + 1, 4, -1, -1, 13, 16, 8, 14, 9, -2, -7, -11, -17, -12, -5, -9, + -10, -13, -4, 1, 0, 4, 5, 0, 2, 3, 5, 14, 18, 9, -3, 2, + 15, 14, 6, 2, 1, -1, -5, -6, 0, 0, 0, 7, 20, 22, 23, 13, + 13, 17, 20, 35, 25, 20, 20, 14, 17, 16, 3, 7, 18, 15, 13, 17, + 6, -5, -6, -13, -23, -19, -19, -22, -22, -24, -17, -18, -22, -27, -31, -30, + -29, -30, -33, -36, -34, -37, -47, -38, -24, -28, -27, -31, -30, -28, -26, -20, + -14, -14, -9, 4, 17, 21, 15, 12, 25, 29, 33, 33, 30, 30, 31, 19, + 20, 14, 4, 10, 17, 18, 21, 28, 19, 20, 20, 5, -2, -3, -7, -10, + -2, 1, 4, 6, 4, 5, 3, 2, -1, -4, -7, -10, -3, -6, -16, -5, + -1, -8, -7, -6, -9, -10, -11, -7, -6, -10, -11, 2, 11, 7, 1, 6, + 12, 16, 18, 15, 11, 14, 16, 9, 11, 6, 5, 13, 14, 13, 11, 0, + -11, -4, -4, -8, -7, -5, -6, -3, -1, 2, -1, -6, -7, -9, -9, -9, + -15, -11, -14, -17, -16, -18, -17, -12, -7, -8, -7, -6, -2, -3, -12, -15, + -15, -18, -13, -19, -23, -24, -21, -21, -13, -12, -7, -3, -7, -6, -4, 2, + 1, 1, 3, 9, 23, 28, 23, 17, 24, 27, 22, 19, 16, 19, 10, 9, + 10, 10, 19, 8, 11, 16, 15, 11, 13, 14, 7, 5, -3, -7, -12, -15, + -16, -17, -10, -5, 4, -2, -2, -9, -13, -9, -8, -10, -10, -12, -5, 3, + 7, 3, 9, 3, 4, -1, -2, 2, -4, -9, -4, 0, 4, 4, -6, -3, + 12, 10, 15, 12, 7, 7, 1, -1, 8, 11, 9, 9, 13, 17, 17, 9, + 11, 4, 0, -3, -6, -8, -9, -10, -17, -20, -24, -17, -19, -22, -20, -21, + -15, -16, -19, -23, -21, -28, -26, -15, -14, -4, -1, -6, -3, -1, 4, 9, + 2, 4, 7, 7, 11, 15, 6, 17, 24, 16, 15, 9, 6, 6, 3, 1, + 3, 2, -2, 6, 6, 6, 3, -6, -3, -8, -7, -10, -13, -17, -18, -16, + -19, -13, -9, -3, 4, 10, 7, 7, 12, 11, 13, 10, 6, 1, 2, 4, + 4, 10, 10, 7, 4, 1, 4, -5, -12, -3, 1, 10, 7, 6, 4, 19, + 22, 20, 23, 16, 15, 19, 17, 14, 9, 7, 4, 4, 2, 5, 3, 0, + 0, -7, -7, -8, -7, -14, -15, -18, -25, -21, -21, -16, -13, -14, -17, -18, + -23, -21, -23, -29, -32, -33, -30, -23, -13, -11, -10, -8, -7, -2, 1, -3, + -1, 5, 13, 17, 13, 11, 13, 16, 14, 10, 11, 8, 16, 13, 4, 0, + 7, 13, 14, 15, 15, 17, 17, 9, 8, 9, 9, 2, 5, 11, 14, 7, + 4, 11, 10, 5, 7, 2, -1, -4, -9, -16, -15, -12, -9, -15, -23, -21, + -22, -22, -20, -22, -22, -21, -22, -22, -13, -6, 4, 2, -2, 2, 7, 6, + 10, 8, 9, 12, 21, 16, 11, 7, 11, 13, 11, 10, 11, 13, 9, 6, + 6, 5, 4, -5, 1, 4, 5, -1, -2, 6, 3, 3, -3, -10, -14, -14, + -14, -16, -8, -6, -1, -6, -7, -5, -7, -6, -9, -8, -8, -4, -5, -8, + -6, 3, 12, 4, -2, 3, 1, 1, -1, -4, -4, 5, 6, 1, -4, -3, + 5, 9, 8, 18, 20, 22, 15, 11, 11, 15, 12, 9, 11, 11, 11, 5, + 10, 12, 5, 3, -2, -4, -9, -9, -16, -17, -14, -12, -14, -20, -15, -16, + -17, -17, -19, -20, -19, -15, -17, -15, -13, -2, -3, -13, -8, 0, 4, 7, + 6, 4, 11, 13, 14, 11, 5, 6, 3, -1, -2, 2, 3, -1, -2, -6, + -4, -1, -3, 0, 3, 1, -2, -5, -5, -3, -6, -9, -7, -15, -13, -10, + -8, -4, 1, 9, 7, 2, 8, 8, 9, 12, 14, 7, 12, 12, 12, 8, + 14, 19, 11, 7, 10, 13, 10, 2, -2, -6, -1, 2, 6, 3, 1, 4, + 2, 2, 5, 8, 8, 7, 7, 2, 0, -3, -6, -3, -1, -6, -12, -9, + -6, -7, -9, -10, -14, -16, -12, -12, -11, -13, -16, -16, -20, -18, -14, -10, + -8, -9, -13, -9, -8, -9, -7, -9, -8, -3, -4, -3, -6, 0, 2, 3, + -3, 2, 5, 1, 6, 5, 5, 10, 11, 17, 15, 20, 25, 20, 15, 17, + 13, 12, 11, 7, 4, -1, -2, 6, 7, 7, 9, 10, 7, 9, 7, 5, + 5, 1, -6, -2, -5, -6, -3, -3, -1, -3, -5, -3, -6, -8, -7, -8, + -11, -12, -16, -19, -19, -14, -14, -17, -17, -11, -12, -15, -6, -8, -12, -12, + -9, -7, -6, 2, 9, 6, 8, 11, 13, 15, 14, 11, 7, 3, 3, 4, + 7, 9, 10, 6, 6, 5, 7, 11, 11, 4, 1, 1, -3, -5, -1, -1, + -1, -5, -2, -1, -1, 1, 1, -3, -7, -7, -9, -12, -11, -3, -3, -7, + -6, -6, -5, -5, 0, -3, -4, -2, 2, -1, 0, 6, 7, 7, 4, 3, + 5, -1, 0, -1, -7, -9, -8, -11, -5, 0, -1, 0, 2, 2, 5, 10, + 10, 7, 7, 7, 8, 8, 9, 11, 9, 8, 9, 6, 4, 2, 0, -3, + -5, -8, -8, -12, -8, -1, -4, -4, -5, -7, -9, -6, -5, -6, -8, -6, + -3, -7, 0, 5, 6, 3, 1, 6, 6, 4, 3, 1, -2, -4, -6, -4, + 3, 7, 3, 0, -1, -3, -2, -1, -2, -5, -8, -9, -7, -9, -8, -6, + -9, -7, -9, -7, -6, -7, -6, -7, -7, -7, -7, -8, -2, 1, 2, 4, + 3, 5, 6, 10, 11, 9, 10, 12, 9, 9, 11, 9, 10, 8, 7, 7, + 6, 7, 5, 4, 5, 4, -1, -4, -3, -5, -1, -2, -4, -4, -4, -4, + -2, -2, -3, -4, -2, -1, 0, 1, 8, 8, 4, 4, 4, 2, -2, -3, + -5, -6, -9, -10, -8, -5, 2, 1, -2, -2, -2, -2, -2, -5, -5, -7, + -7, -3, -4, -6, -4, -3, -5, -7, -5, -4, -7, -9, -6, -6, -9, -7, + -6, -2, 3, 3, 4, 5, 3, 4, 5, 2, 0, 2, 3, 2, 5, 7, + 10, 9, 7, 7, 6, 4, 1, -2, -5, -6, -10, -10, -8, 2, 8, 7, + 6, 7, 5, 5, 7, 6, 3, 4, 3, 4, 1, 3, 2, 4, 2, 1, + 1, -1, -3, -3, -4, -6, -9, -9, -9, -7, -6, -5, -5, -4, -5, -2, + -1, -2, -3, -1, -1, -3, -2, 2, 2, 3, 4, 4, 2, 0, -1, -3, + -4, -4, -5, -7, -2, 2, 2, -1, -3, -1, -4, -3, -2, -4, -4, -2, + -1, -2, -4, -2, -2, -1, -2, -2, -2, -3, -2, 0, 2, 0, -2, -2, + 0, 2, 3, 5, 4, 4, 4, 6, 3, 1, 0, 0, 0, 0, 5, 5, + 4, 6, 4, 2, 0, -2, -3, -6, -9, -8, -10, -10, -2, 3, 4, 4, + 4, 5, 4, 4, 5, 4, 4, 4, 4, 2, 3, 2, 2, 2, 1, 1, + 0, -2, -3, -3, -4, -6, -8, -7, -4, -6, -3, -3, -3, -2, 1, 0, + -1, -2, -2, -1, -1, 0, 1, 0, 0, 1, 0, 0, 0, -1, -2, -3, + -3, -4, -5, -4, -3, -3, -3, -3, -3, -3, -2, -1, 0, -1, 0, 0, + 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 2, 3, + 3, 2, 2, 0, -1, -1, -2, -3, -3, -4, -5, -4, 0, 3, 3, 3, + 3, 2, 3, 4, 6, 4, 4, 3, 2, 1, 2, 1, 0, 0, -1, -2, + -3, -3, -2, -2, -3, -3, -3, -3, -3, -2, -2, -2, -2, -2, -2, -2, + -2, -3, -2, -3, -2, -2, 0, 0, 0, 0, 0, -1, -1, -2, -2, -3, + -2, -4, -4, -3, 0, -1, 0, 0, 0, 0, 0, 1, 2, 1, 1, 1, + 0, 0, 0, -1, 0, -1, -1, -1, -1, -1, 0, 0, -1, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, + 0, 0, -1, -1, -2, -2, -2, -2, -2, -3, -3, -1, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 1, 0, 0, 0, -8, -33, -24, -25, -25, -26, -27, + -32, -28, -36, -31, -36, -22, -34, 11, -74, -14, 94, 41, 28, 33, 30, 40, + 34, 23, 41, 40, 60, 56, 59, 60, 44, 39, 54, 45, 52, 17, 44, 62, + 34, 33, 19, 18, 43, 35, 22, 36, -15, -10, 32, -7, -12, -6, -8, -50, + -47, -44, -4, -25, -48, -76, -58, -75, -96, -85, -118, -114, -63, -106, -103, -83, + -110, -99, -84, -76, -58, -63, -61, -51, -53, -36, -32, -41, -27, -11, 11, 8, + 27, 19, 30, 35, 28, 57, 53, 38, 71, 51, 68, 110, 78, 89, 109, 97, + 82, 94, 115, 114, 79, 70, 79, 94, 85, 76, 84, 95, 83, 82, 55, 54, + 54, 41, 41, 27, 20, 6, -11, -21, -16, -14, -33, -33, -52, -54, -59, -62, + -71, -79, -88, -88, -78, -78, -72, -71, -94, -99, -93, -90, -78, -87, -105, -103, + -79, -62, -71, -78, -63, -61, -66, -49, -23, -10, -11, -24, -20, -4, -22, 9, + 8, 27, 43, 34, 38, 51, 83, 65, 58, 74, 75, 70, 73, 71, 65, 100, + 89, 94, 65, 84, 49, 49, 61, 54, 43, 51, 58, 53, 35, 40, 36, 38, + 34, 23, 14, -12, -10, -1, -1, -11, -12, -19, -33, -66, -52, -42, -37, -55, + -42, -28, -32, -29, -35, -41, -28, -25, -46, -85, -64, -62, -55, -49, -68, -55, + -53, -52, -47, -43, -26, -32, -41, -34, -35, -40, -26, -8, -1, -6, -11, 5, + -2, 8, 3, 8, 6, 4, 20, 29, 43, 24, 33, 20, 30, 24, 39, 38, + 40, 29, 37, 36, 39, 61, 58, 41, 51, 59, 51, 55, 58, 48, 32, 45, + 40, 27, 30, 41, 44, 26, 19, 23, -3, 7, 0, -3, 2, 3, -6, -5, + -14, -6, -10, -27, -45, -47, -41, -38, -50, -51, -46, -43, -45, -65, -65, -80, + -95, -82, -74, -66, -69, -67, -33, -31, -53, -48, -51, -43, -18, -24, -24, -33, + -26, -10, 0, -17, -6, 17, 31, 2, 23, 45, 46, 12, 75, 38, 63, 69, + 31, 38, 80, 57, 48, 59, 81, 74, 32, 52, 72, 24, 60, 44, 55, 40, + 28, 48, 33, 24, 10, -2, 21, 34, 13, 18, 7, -1, -12, -20, -18, -30, + -9, -7, -30, -27, -26, -38, -20, -54, -55, -64, -53, -36, -62, -37, -71, -47, + -42, -71, -45, -55, -50, -54, -56, -36, -37, -54, -36, -12, -38, -33, -26, -7, + -22, -44, -10, 2, 3, 15, 8, 18, 6, 12, 8, 15, 28, 22, 50, 35, + 55, 42, 36, 49, 52, 64, 48, 60, 49, 60, 62, 40, 47, 68, 52, 59, + 61, 44, 53, 44, 35, 31, 31, 47, 22, 6, 4, -7, 5, -4, -21, -13, + -9, -10, -27, -46, -32, -44, -46, -62, -44, -51, -67, -53, -59, -63, -74, -67, + -61, -61, -65, -47, -58, -57, -45, -41, -46, -41, -38, -22, -25, -34, -16, -10, + -18, 0, 1, -6, 5, 17, 15, 10, 23, 38, 28, 28, 54, 40, 19, 55, + 55, 41, 46, 53, 40, 49, 51, 52, 41, 56, 39, 53, 38, 33, 35, 18, + 15, 38, 30, 23, 27, 13, 11, 7, 16, -1, 0, 0, 13, -6, -10, -15, + -10, -10, -24, -20, -16, -38, -36, -21, -40, -32, -42, -38, -52, -53, -41, -48, + -58, -50, -47, -37, -41, -45, -29, -41, -6, -48, -24, -25, -15, -9, -10, -10, + -10, -1, -17, 4, 3, 10, -4, 9, 15, 25, 24, 19, 23, 34, 28, 33, + 37, 38, 26, 36, 47, 35, 46, 45, 28, 35, 32, 32, 24, 21, 26, 23, + 19, 37, 20, 9, 29, -2, 26, 24, 8, 4, 14, 21, 11, -9, -8, 4, + -9, -31, -11, -15, -21, -24, -29, -22, -33, -26, -29, -48, -32, -44, -28, -22, + -35, -30, -38, -31, -46, -44, -36, -27, -23, -29, -24, -11, -20, -28, -13, -34, + -19, -1, 7, -3, -1, 6, -3, 5, 4, 8, 17, 26, 19, 33, 27, 16, + 35, 14, 36, 39, 22, 32, 31, 19, 32, 23, 29, 21, 30, 29, 23, 31, + 13, 24, 17, 11, 26, 18, 12, 5, 23, 16, 9, 15, -10, 3, 18, -15, + -4, -4, 6, -14, -15, -5, -34, -11, -20, -18, -8, -17, -29, -30, -29, -19, + -34, -35, -20, -36, -20, -16, -21, -38, -16, -30, -24, -25, -19, -18, -15, -7, + -5, -5, -10, -23, -3, -14, 0, -1, -12, -9, 7, 7, 2, 12, 5, 7, + 19, 10, 21, 21, 27, 30, 22, 18, 34, 22, 11, 26, 24, 20, 21, 25, + 29, 22, 27, 27, 20, 10, 20, 16, 22, 15, 16, 16, 5, 19, 10, 3, + 22, -5, -5, -7, -16, -4, -11, -22, -7, -16, -11, -23, -16, -30, -24, -28, + -20, -29, -24, -32, -22, -22, -30, -17, -23, -28, -22, -20, -21, -21, -17, -30, + -15, -14, -20, -9, 3, 6, 5, -20, 10, 13, -2, 11, 8, -1, 7, 16, + 5, 22, 23, 13, 22, 13, 22, 25, 15, 16, 11, 15, 13, 7, 12, 19, + 18, 20, 12, 23, 11, 6, 10, 1, 11, 19, 5, 20, 0, 11, 11, 1, + 14, 15, -3, -1, -7, 6, -6, -9, -9, 4, -3, -10, -20, -14, -9, -14, + -7, -10, -5, -4, -29, -14, -12, -26, -21, -27, -18, -10, -19, -27, -18, -8, + -25, -8, -13, -15, -14, -15, 5, -13, -7, -11, -4, -12, 0, 15, 5, 4, + 1, 11, 6, 4, 3, 6, 21, 19, 8, 15, 13, 6, 14, 16, 18, 17, + 20, 15, 11, 15, 24, 13, 11, 19, 7, 17, 14, 6, 17, 7, 7, 6, + 6, 5, 11, 0, 6, 0, -6, 5, 1, -11, -6, -1, -8, -9, -15, -7, + -4, -16, -17, -13, -13, -17, -14, -12, -12, -28, -13, -19, -25, -31, -24, -17, + -17, -16, -7, -15, -12, -8, -15, -8, -16, -10, -4, -1, -2, 3, 5, 2, + -2, 5, 3, 6, 10, 8, 11, 14, 14, 13, 15, 22, 16, 14, 18, 13, + 17, 19, 16, 10, 17, 8, 17, 14, 3, 14, 7, 10, 10, 7, 6, 6, + -1, 6, 1, 0, 12, -6, 6, 12, -4, -5, -4, -2, -2, -1, -2, -8, + -11, -9, -11, -11, -18, -6, -5, -16, -9, -14, -10, -13, -10, -11, -15, -14, + -14, -12, -17, -17, -17, -7, -11, -14, -15, -12, -6, -15, -5, -13, -9, 0, + 12, -2, -2, 6, 2, -7, 4, 10, 2, 9, 8, 7, 4, 5, 11, 15, + 11, 10, 18, 9, 13, 13, 13, 21, 11, 18, 19, 13, 14, 16, 6, 8, + 1, 19, 11, 10, 11, 1, 3, -1, -1, 5, -11, 5, -1, -5, -3, -13, + -10, -6, -7, -5, -15, -10, -11, -18, -8, -16, -20, -18, -9, -12, -17, -21, + -21, -13, -21, -8, -10, -10, -5, -16, -7, 2, -6, -6, -9, -7, -2, -9, + -5, 6, -7, 1, 3, -1, 2, 1, 2, 9, 8, 5, 15, 12, 1, 11, + 9, 8, 10, 15, 14, 5, 13, 17, 14, 15, 10, 7, 16, 5, 5, 5, + 8, 9, 10, 10, 7, 0, 4, 6, 9, -10, -4, 5, 2, -1, 0, -3, + -4, -5, -10, -5, -8, -9, -10, -3, -13, -6, -9, -20, -15, -11, -18, -14, + -10, -12, -20, -14, -14, -7, -12, -21, -14, -9, -8, -11, -5, -2, -7, -4, + 4, -2, -3, -1, 0, -1, 8, 6, 9, 7, 10, 6, 3, 4, 7, 10, + 11, 6, 9, 17, 11, 9, 7, -2, 16, 13, 12, 18, 5, 16, 9, 4, + 9, 6, 8, 9, 4, 4, 3, -2, -3, 2, -6, -3, 1, -7, -6, -3, + -6, -14, -8, -9, -4, -13, -9, -8, -16, -10, -12, -13, -11, -7, -8, -12, + -9, -8, -7, -11, -4, -8, -7, -8, -3, -13, -10, -3, 6, -5, -5, 0, + -5, -3, 6, -2, -2, 4, -2, 6, 2, -2, 5, 5, -2, 5, 15, 13, + 4, 6, 6, 14, 9, 4, 8, 7, 3, 11, 12, 2, 10, 7, 10, 8, + 4, 6, 2, 0, 3, 2, 4, 2, -6, -2, 2, -4, 3, -5, -6, -5, + -5, -5, -4, -8, -7, -4, -4, -7, -8, -7, -13, -10, -10, -11, -9, -8, + -8, -7, -11, -7, -3, -9, -6, -7, -3, -4, -5, 3, -3, -1, -2, -4, + 1, 4, 0, 3, 0, 5, 2, 0, 5, 4, 1, 3, 1, 0, 1, 7, + 3, 0, 4, 3, 6, 5, 0, 9, 5, 7, 6, 3, 6, 2, 3, 5, + -4, 9, 0, 4, 10, 0, 5, 1, -2, 4, -3, -3, -2, 0, 2, -7, + 3, -10, -1, -6, -9, -2, -4, -10, -3, -7, -6, -4, -10, -6, -6, -11, + -6, 0, -6, -8, -4, -1, -9, -10, 0, -6, -7, -2, -7, 1, -5, -5, + -1, 1, -6, 2, 0, -3, -1, 7, -4, 0, 7, 0, 8, 2, 3, 4, + 4, 2, 5, -1, 6, 7, 5, 6, 4, 2, 4, 6, 8, 6, 3, 1, + 8, 9, 2, -1, 4, 3, 4, 3, -3, 7, 4, 3, -2, 2, -4, -6, + -2, -5, -2, -3, 0, -5, -6, -13, -5, -6, -11, -9, -10, -5, -4, -9, + -9, -7, -7, -8, -8, -6, -5, -7, -5, -1, -3, -4, -2, -2, 2, -3, + 1, 2, -3, 1, 2, 1, 0, 1, 5, 0, 2, 5, 2, 0, 4, 1, + 7, 3, 2, 6, 0, 5, 7, 5, 5, 1, 3, 3, 5, 10, 3, 4, + 8, 2, 7, 3, -2, 3, 0, -1, -1, 1, 0, 1, -3, -2, -5, -4, + -3, -1, -7, -8, -4, -4, -10, -2, -8, -8, -8, -8, -9, -6, -8, -9, + -4, -2, -7, -5, -2, -7, -6, -9, -2, 0, -4, 4, -6, -3, -4, -1, + 2, 1, 2, 9, 0, 3, 0, 6, 4, 0, 5, 6, 2, 7, 7, 5, + 7, 6, 8, 6, 6, 5, 5, 1, 6, 5, -1, 3, 4, -1, 4, 1, + 4, 3, -5, 0, 4, 1, 4, -2, -3, -4, 0, -4, -8, -2, -5, -4, + -8, -6, -5, -3, -3, -7, -9, -6, -10, -10, -6, -6, -5, -4, -7, -6, + -4, -10, -3, -10, 0, -2, -2, -6, -1, 3, -3, -3, 1, 2, 1, 4, + 3, 4, 3, 4, 1, 2, 6, 5, 5, 5, 7, 9, 1, 5, 4, 4, + 7, 2, 9, 2, 4, 8, 2, 5, 6, 3, -2, -2, -1, -2, -1, 1, + -2, -4, 1, -6, -2, -5, -3, -5, -5, -6, -4, -3, -4, -10, -4, -3, + -8, -4, 0, -3, -5, -6, -6, -3, -1, -7, -3, 1, -1, -4, -2, 1, + -2, 0, -1, -2, 0, 0, 5, -2, 0, 3, 3, 1, 5, 2, 4, 1, + 4, 1, 2, 3, 3, 3, 4, 3, 3, 5, 1, 4, 2, 3, 1, 2, + 0, 2, 1, -2, -2, -1, 0, -2, -1, -1, -3, -5, -2, 0, -5, -1, + 0, -5, -2, -2, -2, -3, -3, -1, -4, -1, -2, -4, -2, -1, -2, -1, + 0, -3, -1, -1, 0, 1, -1, -1, 3, -4, -2, -2, 4, -2, -1, -1, + -1, 0, 0, -1, -1, -1, -1, 2, 0, -1, 2, -1, 0, -1, 2, 0, + 3, 5, -2, 1, 2, 0, 5, 0, -3, 4, -3, 1, 2, 0, 4, -1, + -2, 1, 0, 0, 0, -1, 1, -2, 0, 1, 1, 0, -5, 1, -2, -1, + 0, -2, -3, -1, -3, 0, -2, -3, -4, 1, -2, -3, -2, -2, -1, -1, + -2, -1, -4, -5, 2, -4, 0, 1, -1, 2, -2, -1, 0, 0, 1, -3, + 3, 2, 0, -2, 2, 1, 2, -2, 5, 3, -2, -2, -1, 1, 0, 0, + 1, 3, 2, 0, 0, -1, -2, 1, 1, 2, 1, 1, -1, 0, -1, -1, + -1, -3, 1, 1, 2, -2, -1, 0, 0, -2, 0, -1, -1, 2, -2, 1, + -1, 0, 0, -1, -1, -2, 0, -1, 1, -1, -1, 2, -2, 0, -1, -1, + 2, -1, 0, -3, -1, 0, 0, 0, -3, -3, -2, 0, 0, -1, -1, 0, + -4, 2, 0, -2, 0, 1, -3, -1, 2, 1, 0, -1, 0, 0, -1, 0, + 2, -1, -1, 0, 0, -2, 1, 1, 0, 1, 0, 2, -3, -2, 2, -1, + -1, 2, -2, 1, 1, 0, 0, 1, 1, 0, -4, 3, -1, 2, 0, 2, + -1, -2, 0, 1, 1, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -1, + -1, 1, 0, -5, 0, -1, -1, -1, 1, -1, 1, -1, 1, 0, -2, 0, + -2, 1, -1, 1, 0, -1, -2, 0, -1, 0, 0, 2, 0, 0, 0, 1, + 0, 0, 2, 0, -1, 0, 0, 0, 2, -1, 1, 1, -1, -1, 0, 0, + 1, 1, 0, 0, 0, 0, -1, 0, 0, -2, 0, 0, -1, 1, -2, -1, + -1, -1, -2, -1, -2, 1, -1, 0, -2, -2, 1, -2, -1, 1, 0, 1, + 1, -1, -1, 0, -1, 0, 0, 0, -2, 0, -1, 0, 0, -1, -2, -2, + -2, 1, -1, 0, 0, -1, 1, 1, -2, -1, -2, -1, 1, -1, -1, -2, + -2, 0, 0, 1, -1, -1, -1, -1, -2, 2, 0, 0, 1, 1, 1, -2, + 0, -1, 0, -1, -1, 2, 0, -1, -1, -1, 1, -1, 2, 0, -1, 1, + 1, 0, 1, 0, -1, -1, -1, -1, -3, 0, 0, -1, 1, 0, 0, -2, + -2, -2, 0, -1, 0, 0, -1, 0, -1, -2, -1, -2, 0, -2, 0, 0, + -1, -2, 1, -2, 0, -1, -2, 2, 0, -1, 2, -1, 1, -1, 0, 0, + -1, 0, 0, 0, -1, 0, 1, 0, 0, 1, 0, -1, -1, 0, -2, -1, + 0, 0, 1, 0, 0, 0, 0, -1, -1, 1, -1, -2, -1, 0, 0, -2, + 0, -1, 0, 0, 0, 1, 0, 0, -1, 1, 0, -1, 0, 1, -1, 0, + -1, -2, 0, -1, 0, -1, -1, -1, 0, -1, 0, 0, 0, -1, -1, 0, + -2, 0, 0, 0, -2, -2, 0, -2, -1, -1, -1, -2, 0, -1, -1, -1, + 0, 0, -1, -1, 0, 1, -1, -1, 0, -1, 0, 0, 1, 1, 0, 0, + -1, 0, 0, 0, 0, 0, 1, -1, 0, 0, 0, 1, 0, 0, -1, 0, + 0, -1, -1, 0, -1, -1, 0, -1, 0, -1, -1, 0, -2, -1, 0, -1, + -1, -1, -1, 0, -1, 0, 0, 0, 0, -1, 1, 0, 0, 0, -1, -1, + 0, -1, -1, 0, 0, 0, 0, 0, -1, -1, 0, -1, -1, 0, 0, -1, + 0, -2, 0, -1, -1, -1, 0, -1, -1, 0, -1, 0, 0, 0, -2, -1, + 0, -1, -1, 0, 1, -1, -1, 0, 0, 0, 0, -1, -1, -1, -1, 0, + 1, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, -1, 0, 0, + -1, 0, 0, -1, -1, -1, 0, 0, -1, -1, 0, -1, 0, 0, 0, -1, + 0, -1, -1, 0, -2, -1, -1, -1, 0, -1, 0, -1, -1, 0, 0, -1, + 0, -1, 0, -1, -1, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, + 0, -1, -1, 0, 0, 0, -1, 0, -1, 0, 1, -1, 0, 0, 0, 0, + 0, -1, 0, 0, 0, -1, 0, 0, -1, -1, 0, 0, 0, -1, 0, 1, + -1, -1, -1, 0, 0, -1, -1, -1, -1, 0, -1, 0, 0, 0, 0, 0, + 0, -1, -1, 0, -1, -1, 0, -1, 0, -1, -1, -1, -1, 0, -1, -1, + -1, -1, -1, -1, -1, 0, -1, 0, -1, 0, 0, -1, -1, 0, -1, 0, + -1, 0, 0, -1, 0, -1, -1, -1, 0, -1, 0, 0, 0, 0, 0, -1, + -1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, -1, 0, 0, 0, + 0, -1, 0, -1, 0, 0, 0, -1, -1, 0, 0, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 0, 0, -1, -1, -1, 0, 0, 0, -1, 0, -1, -1, + 0, -1, 0, 0, -1, -1, -1, -1, -1, 0, 0, -1, 0, 0, -1, 0, + 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, + -1, 0, 0, 0, 0, -1, 0, 0, -1, 0, -1, 0, 0, -1, -1, -1, + 0, -1, -1, 0, -1, -1, 0, 0, -1, -1, -1, -1, 0, -1, -1, 0, + 0, -1, 0, 0, 0, -1, -1, 0, -1, -1, -1, 0, 0, -1, -1, -1, + -1, -1, 0, -1, 0, 0, -1, -1, 0, 0, -1, 0, 0, -1, -1, -1, + 0, -1, 0, 0, -1, -1, 0, 0, -1, -1, 0, 0, 0, -1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, + 0, 0, 0, -1, 0, -1, 0, -1, -1, -1, -1, -1, -1, 0, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 0, -4, 11, 6, 16, 10, -16, -48, + -44, 2, 67, 42, -17, -51, 15, 71, 12, -22, -14, -44, -35, 11, 17, -18, + 2, -15, 19, 12, -1, -44, -15, 50, 45, -25, -61, 17, 10, -10, 31, 18, + -72, -27, 57, 26, -13, -17, -2, 6, -1, -23, -54, 17, 39, 8, 30, 28, + -6, -71, -5, 33, 27, -5, 17, 10, -23, -6, 12, -26, -6, -7, -9, -14, + 11, 37, 41, 8, -33, -14, 8, -31, -38, 13, 9, 15, 35, 33, 11, 17, + -41, -48, -33, 29, 25, 16, -9, -9, -17, -19, -29, 43, 64, -2, -55, -42, + -1, -21, -4, 29, 34, -25, -67, -29, 1, 51, 49, 25, -6, -15, -48, -76, + -3, 60, 78, 33, 19, 13, -38, -35, -35, -2, 62, 19, -4, -12, -4, -4, + -32, -30, 8, 68, -43, -66, -28, 55, 51, 20, -28, -29, -19, 20, -2, 8, + 21, -15, -43, 24, 22, -7, -2, 35, 15, -2, -24, -12, 3, 31, 13, -15, + -20, -17, -17, 26, -26, 24, -3, 7, 21, 26, -3, -17, -26, -50, -26, 33, + 58, 49, -22, -67, -17, 24, 7, -57, 5, 42, -11, -3, 32, -3, 7, 13, + -11, -9, 27, 17, 1, -5, -9, -18, -19, -3, -23, -5, 7, -8, 9, 13, + 12, -5, 7, -37, 22, 26, 21, 24, -20, -35, 23, 24, -35, -15, 46, -38, + -48, -14, -4, 0, -22, 3, 43, 38, -1, -14, -8, -5, -14, 1, 21, 23, + 29, -19, -47, -42, -49, -10, 66, 77, 48, -29, -32, 1, -11, 8, 17, -17, + 3, 43, 33, -22, -19, -41, 29, 22, -42, 9, 63, 28, -23, -59, -65, 7, + 53, -22, -10, -27, -30, 36, 48, -4, -6, -22, -16, 10, 14, -7, 22, 50, + -4, -25, -41, -55, -62, 23, 68, -16, -31, 49, 57, 21, -38, 14, 12, -43, + -49, -16, 28, 7, -12, -50, -17, 49, 65, 18, 1, -8, 28, 2, -27, -13, + 12, -11, -52, 4, 31, -32, -39, 15, 8, -19, 6, 25, -1, -23, 13, 34, + 59, 36, -16, -5, -7, -28, -30, 1, -14, -42, 10, 43, 26, -25, -37, -61, + 1, 63, 62, 1, -36, -24, 38, -7, -26, 27, 10, 4, 2, -19, -22, -27, + -24, 0, 33, -8, -57, -12, 62, 77, 51, -10, -42, -27, -28, -31, -3, 5, + 21, 10, 15, -27, -18, -18, -10, 3, 17, 19, 18, -16, -20, 25, -3, -19, + -5, 32, 17, -3, -32, -8, 2, -11, -24, -17, -11, 3, 42, 15, -12, -2, + 26, 9, -4, -30, -3, 16, 7, 13, 34, 40, 114, 11, -104, -71, 7, -14, + -34, -26, 35, 45, 47, 7, -7, -16, 11, -6, -29, -32, 1, 24, 32, 10, + 29, -10, -74, -80, -20, 18, 9, 18, 61, 38, -27, -44, 13, 16, -26, 20, + 69, 14, -14, -46, -7, -6, -35, 0, 9, 5, 58, 71, -36, -78, -15, 43, + 34, -61, -101, -27, 45, 26, -10, 23, 69, 69, 5, -72, -62, 19, 16, -37, + -60, 37, 60, 10, -49, -10, -2, -1, 43, 44, 10, -50, -5, 19, 8, -43, + -58, -17, 32, 28, 4, -1, -18, -10, 13, 8, 1, 1, 22, -3, -4, 9, + -8, -9, 17, 3, -15, -8, 14, 11, -14, -11, -5, 13, -24, -34, -1, -16, + -4, 32, 35, -32, 9, 22, 12, -27, -16, 14, 15, 0, -2, -12, -31, -24, + 14, 48, 10, -14, -7, -22, 4, -8, -14, 19, 21, -21, -25, -12, 19, 24, + 19, 27, -3, -15, -16, 10, 21, -14, 3, 8, 3, -11, -33, -16, 7, 5, + -8, 2, -3, 12, 5, -34, -19, -6, 26, 19, 0, -4, -12, 5, 12, 20, + 16, 19, 18, -13, -42, -26, -1, 0, -18, -16, 10, 27, 23, -5, -7, 9, + -8, 7, 22, 10, -28, -51, -26, 13, 44, 17, 16, 25, 14, -32, -45, -36, + -40, -3, 22, 41, 34, -12, -35, -31, 18, 3, 31, 28, 4, -21, 2, -14, + -24, -23, 19, -6, -7, -10, -1, -13, -13, 21, 52, 28, 7, 1, -25, -36, + 2, 34, 10, -37, -31, -13, 19, 11, -4, -20, 15, -5, -18, 40, -13, 15, + -36, 14, 18, 17, -21, 6, -39, 21, 7, -26, 8, -33, 24, 30, 32, -11, + -26, -47, -39, 62, 10, 11, 5, -17, -21, 10, 0, 18, 15, -22, 7, 13, + 14, -8, -9, 30, 33, -34, -41, -32, 37, 24, -19, -15, 1, 2, 10, 10, + -27, -46, -14, -9, 9, 47, 1, -22, -18, 5, 37, 29, -3, -19, -19, -18, + 8, 17, 1, -11, -6, -20, 27, 37, -2, -28, -34, -3, 22, 54, 34, -31, + -43, -28, -30, -33, 26, 49, 45, 43, -15, -58, -13, -2, -27, -7, 41, 11, + 19, -50, -74, -28, 31, 75, 39, -45, -7, 99, 44, -83, -47, 45, -1, -30, + 23, 29, -55, -30, 31, 28, -19, 2, -44, -46, -49, 30, 22, 58, 31, -50, + -20, 9, -38, -53, 49, 37, -9, 13, -25, -18, 18, -27, -7, 17, 3, 24, + 57, 26, -51, -52, -54, -43, 53, 85, 31, -36, -44, 7, 13, 19, -23, -33, + 36, 47, -38, -11, 37, -19, -6, 18, 17, 2, 31, 54, -29, -72, -80, -1, + 27, 52, 10, -29, -40, -48, -72, 24, 108, 66, -44, -76, -32, -24, 21, 69, + 54, 24, -2, -8, -28, -44, -50, 34, 95, 45, -40, -72, -32, 6, 28, -1, + 18, -7, 27, 1, -14, 21, -8, -51, -62, -24, 64, 56, 12, 19, -36, -22, + 10, 20, -10, -1, -5, -51, 36, 72, -42, -51, 70, 45, -48, -27, 54, 19, + -46, 8, 0, -46, 10, 37, 35, -21, -32, -22, -44, -82, -33, 59, 105, 48, + -32, -36, -31, 18, 60, -12, -49, 10, 89, 28, 12, 8, -45, -21, -6, -16, + -32, -17, -18, 3, 29, -3, 0, -20, -51, -31, 24, 52, 1, -17, -20, 1, + 35, 15, 5, 35, 27, 18, -19, 8, -71, -74, -8, 88, 57, -45, -37, 17, + 51, -1, -13, -4, 3, -13, -24, -7, 30, -7, -25, -1, 16, -8, -43, -70, + 11, 85, 77, 12, -62, -57, 35, 53, -33, -96, 8, 82, 21, -38, 25, 39, + -1, -27, -14, 18, -16, -45, -24, 42, 7, -9, 22, 32, -39, -5, -8, -49, + -17, 60, 88, 21, -93, -20, 82, 31, -26, -63, -17, 52, -28, -25, 13, -2, + -32, -46, 55, 56, -37, 6, -57, -33, 65, 63, 5, -25, -31, 69, 86, -32, + -34, -56, -23, -47, 14, 44, -23, 19, 6, 60, -27, -69, -37, 20, -14, -5, + 50, 44, 15, 13, -23, -60, -46, 23, 40, -5, -25, 6, 46, -4, -10, -27, + -12, 28, 45, 10, -13, -33, -19, -39, 42, 32, -23, -25, 24, -17, 13, 25, + 13, -32, 13, 48, 4, -93, -5, 40, -7, 37, -39, -37, 41, 1, -13, -33, + 43, -53, 106, 8, -57, -93, 55, 40, 56, -24, -4, -19, 7, -23, -65, -18, + 34, -30, 7, 66, 92, 3, -43, -37, -23, 12, -7, -17, 14, -15, -9, -18, + 18, 51, -1, -57, -17, 23, 19, 15, -40, -1, 0, -8, 39, -13, -43, 72, + 57, -1, -54, -17, 32, -19, 11, 0, 36, 25, -23, -86, 21, -3, 14, -17, + 76, 37, 23, 2, -23, -54, -42, -80, 61, 60, 63, -12, -57, -44, 15, 35, + 26, 11, -44, -22, 8, 33, -24, -17, 21, 38, -25, -39, 16, 43, -36, -28, + 54, 10, -52, -18, -34, -14, 76, 60, 24, -32, -19, 16, -13, -68, -5, 30, + -13, -23, -14, 61, 24, 35, 39, 4, -50, -58, -39, 0, 43, 43, 21, 24, + -20, -46, -36, 38, 8, -67, -8, 61, 38, 10, -12, 5, -4, -16, -47, -5, + -18, -20, 37, 41, 24, 4, 7, -19, 11, -52, 0, 17, 20, -30, -33, -16, + 60, 34, -15, -46, -77, 14, 29, 26, 21, 25, 8, 7, 36, 23, -39, -16, + 21, 11, -23, 11, -4, -6, -35, 13, -8, -49, -17, 44, 19, -25, -17, 9, + -5, -5, -1, -31, 11, 15, 17, -8, -31, -51, 12, 54, 85, 32, 4, -58, + -35, -31, 0, 10, 21, -20, -20, -29, 15, 26, -7, 8, 4, 0, 30, 2, + -26, 2, 19, 15, -18, -13, -20, -19, 47, 33, -6, -51, -30, -12, 12, 30, + 34, 31, 4, -45, -81, -7, -22, 1, 73, 98, 24, -67, -13, 19, -32, -86, + 6, 94, 4, -47, 21, -11, -50, 22, -3, -2, 50, 20, -37, -59, 35, 28, + -16, -36, -30, -11, 4, 69, 98, -65, -84, 73, 27, -90, -17, 84, 10, -51, + -14, 40, -24, -11, 16, -34, -26, 38, -43, -34, 58, 85, -33, -51, 17, 7, + 4, 52, 25, -35, 0, 44, -21, -47, 40, 44, -69, -65, 37, 35, -21, 4, + 32, -60, -75, 21, 64, 60, -6, -11, 6, 2, -41, -34, 19, 31, 9, 7, + -1, 11, 6, -11, -26, -23, 16, 35, -39, -68, 6, 56, -3, -42, 29, 28, + 3, 28, 14, -37, -16, 11, -8, -18, 15, -1, -8, 43, -20, -67, -12, 34, + 7, -12, -9, 5, -4, 7, -12, 27, -3, -68, 26, 96, 30, -33, -28, -25, + 19, 27, -33, -48, -3, 37, -1, -35, -11, 5, 42, 36, 6, -48, -38, 26, + 54, -23, -41, 52, 44, -32, -22, 28, -23, -32, 12, 41, -16, -6, -6, -17, + -18, -14, -12, -5, 18, 52, 45, -10, -16, 29, 11, -36, -26, 7, 36, 12, + -57, -48, 48, 70, 16, 21, -13, -46, -33, -62, -63, -21, 94, 94, 20, -110, + -47, 41, 67, -16, -57, -40, 85, 71, 7, -39, 15, -29, -50, -41, 18, -40, + -42, 38, 69, 21, -8, -58, -19, 23, 24, -20, -10, 11, 41, 7, -6, -30, + -23, 2, 16, 57, 38, -11, -50, 36, -16, -51, -51, 81, 24, -68, -84, 39, + 112, 62, -79, -104, 24, 102, 15, -38, 20, 22, -49, -91, 15, 51, 30, -1, + -15, -30, -12, 17, 42, -17, -48, 0, 49, 35, 2, -19, -16, -30, 9, 17, + -12, -4, -15, 5, 34, -1, -56, -64, 7, 48, 54, -16, -51, 20, 62, -17, + -27, -9, -10, -29, -1, 35, 44, -20, -23, -2, -12, -4, 31, 24, -24, -14, + 2, -28, -27, 49, 61, -54, -61, 6, 23, -20, 2, 41, 26, 2, 15, -5, + 6, -16, -36, -16, 2, -54, -53, -18, 62, 64, 10, -3, 91, 39, -54, -103, + -5, 16, -31, -28, 75, 105, -32, -114, -52, 68, 32, -52, -19, 25, 54, 61, + 14, -40, 12, 1, -56, -31, 74, 40, -73, -66, 0, 49, 36, 24, -20, 0, + 13, -40, -99, -11, 55, 31, -33, 39, 24, 3, -18, 7, 10, 4, -29, 17, + 19, 27, -30, -41, 9, 33, -24, -25, 30, 28, -34, -57, 8, -7, -46, 5, + 48, -22, -6, 57, 58, -31, -72, -2, 72, 44, -53, -42, 41, 1, -54, 30, + 54, -6, -79, -14, 33, -6, -22, 14, 10, -5, -8, 13, 23, 21, -47, -74, + 22, 24, -10, -7, 39, 2, 12, -7, -2, 4, 33, -20, -33, 18, 22, -88, + -71, 26, 81, 14, -37, 3, -24, 6, -8, 11, 40, 18, -7, -17, 20, -8, + -15, -41, -11, 27, 52, -27, -46, 33, 21, 46, -30, -13, 26, -91, -106, -47, + 54, 109, 67, -87, -90, 38, 92, 31, -10, -69, -73, -27, -6, 24, -6, 20, + 30, 45, 33, -13, -25, 10, 57, -16, -32, 0, -14, -55, -20, 4, 7, -4, + 3, 18, -11, 34, 11, -45, -45, -125, -38, -2, 19, 72, 82, 99, 98, 35, + -51, -81, -53, 3, -39, 23, -4, -58, -63, -24, 40, 84, 48, -7, -18, -2, + -8, -20, -10, 3, 21, 17, -39, -66, -20, -2, 37, 30, 39, 34, -5, -41, + -26, 33, 40, 18, -2, 11, 13, -20, -60, -21, 33, -25, -35, 30, 65, 22, + 13, -15, 2, 16, 11, -68, -18, 74, 10, -74, -34, -39, -17, 8, 59, 39, + -22, -38, -8, 9, 30, 23, 11, -3, -12, 10, -1, 59, 9, -28, -72, -27, + 32, 68, -11, -3, 27, 4, -33, -39, 7, -1, -5, -7, 26, -14, -26, -40, + -12, 5, 5, 1, -12, 64, 63, -41, -56, 10, 26, 40, -26, -44, -42, 25, + -6, 3, -1, 10, 9, -1, 9, 1, -28, 10, 24, 26, -33, -36, 46, 20, + -43, -52, -35, 22, 53, 30, -6, 18, -16, -49, -36, 45, 10, 21, 7, 9, + -33, -50, 21, 73, 33, -42, -46, 42, -12, -18, 5, -50, -25, 68, 55, -31, + -79, -7, 77, 25, -6, 29, 78, 24, -87, -41, -30, -41, -23, 75, 35, -32, + -65, -7, -13, 3, 41, 34, -24, -33, 25, 14, -52, -28, 19, 76, 45, -45, + -47, -5, 24, 9, -14, -41, -5, 49, 22, 10, -31, -35, -1, -6, 3, 10, + -1, -12, -20, -51, 9, 79, 53, -36, -38, -13, -14, -15, 50, 50, -36, -33, + 0, 5, 22, 23, 24, -51, -81, -27, 56, 42, -10, -16, 0, 0, -5, 16, + 12, -19, 11, 10, -15, -1, -32, -17, 1, 11, 62, -16, -21, 9, 21, -29, + -50, 16, 82, 17, -35, -4, 11, 3, 8, 8, -9, -13, 10, -39, -63, -19, + 54, 58, -16, -25, 18, 38, -8, -50, -54, -17, 18, 47, 17, -33, -45, 0, + 52, 57, -5, -34, -17, 32, 10, -28, -10, -21, -3, -9, -20, 20, 47, 22, + 5, -4, -15, -37, -22, -28, 9, 37, -18, -13, 3, 15, -33, -47, 20, 73, + 0, -36, 33, 60, -11, -77, -13, 42, 13, -20, 9, 47, 22, -27, 29, 6, + -71, -78, -20, 21, 4, 27, 23, 19, 31, 45, -29, -54, -10, 37, -78, -46, + -14, 67, 108, 57, 12, -62, -108, -15, 116, 56, -58, -110, -33, 33, 30, -39, + -26, 11, 29, 22, 8, 52, 76, 31, 0, -31, -50, -10, 59, 54, -13, -84, + -65, -60, 0, 35, 105, 61, -30, -117, -62, 35, 88, 57, 48, -38, -85, 41, + 12, -21, -6, 7, 15, 73, -30, -72, -37, 25, 0, -5, 65, 76, -90, -78, + 24, 47, 2, -14, 40, 83, 0, -32, -46, -62, -26, 50, 37, -4, -44, -40, + 55, 31, -38, -13, -17, -30, -4, 7, 68, 39, 1, -23, -38, -30, 6, -35, + 14, 52, -9, -62, -47, 45, 44, 11, -17, -9, 6, 16, 34, -3, -32, -21, + -33, -3, 21, 26, -39, 11, 65, 33, 19, -1, -49, -85, -97, 66, 58, -93, + -15, 15, 5, 81, 76, 29, -2, -52, -51, -30, 65, 38, -45, -14, 1, 28, + 22, 43, 19, -59, -109, -29, 29, -14, -22, -41, 0, 54, 76, 16, 8, 23, + 15, -47, -39, -8, 5, 36, -6, -3, -4, 13, 13, 21, -47, -53, -6, -9, + -27, -44, 8, 86, 64, 12, -5, -32, -10, -20, -27, -23, 8, 30, 1, 16, + 42, -35, -8, 4, -39, -11, -62, -29, 108, 87, -20, -104, -18, -55, 8, 47, + -16, 29, 38, 4, -44, -39, -20, 38, -13, 23, 82, 30, -67, -93, 26, 79, + 20, -79, -74, -23, 33, 59, 80, 39, -42, -100, 0, 19, 38, 9, -55, 9, + -15, 22, 68, -17, -55, -23, 1, 87, 19, -56, -60, 32, 37, 38, -67, -33, + -1, 31, 24, 15, -30, -5, -36, -29, -27, 8, 27, -9, 12, 29, 38, 33, + 0, -39, -18, 6, 19, 18, 8, 1, -33, 9, -1, 2, -29, -66, 0, 41, + 6, -50, -13, 9, 73, -28, -47, -21, 30, 68, 31, 32, 29, -46, -14, 13, + -44, -75, -3, 62, 55, 9, -49, -1, 54, 19, -6, 7, 16, 38, 13, -26, + -55, -76, -23, 16, 21, -33, -22, 16, 61, 25, -14, -35, 12, 23, -7, -17, + -32, -10, -16, -1, 7, 18, -1, 19, -2, -1, 21, -14, 1, -44, -44, -23, + -29, -1, 28, -28, 47, 64, 12, -4, -15, -37, -7, 24, 50, 6, -15, -26, + -5, 20, 12, -25, -21, -2, -18, -23, 9, 16, 24, 36, -30, -35, -12, 32, + 19, -13, 19, -6, 2, -2, -22, -11, 14, 50, 10, -21, -55, -14, 23, 6, + 6, -6, -26, -25, -8, 25, 14, 24, 14, -13, 18, 11, 23, -34, -49, -45, + 6, 39, 37, 3, 0, -29, 8, 26, -6, -7, -21, 2, -11, 6, 16, -1, + -17, 6, 32, -4, -54, -9, 22, -14, 6, 27, -1, -2, 34, 33, 8, 1, + -8, -14, -32, 23, -22, -23, -29, -12, 5, 25, 22, -4, 14, 5, 24, -39, + -29, 17, -21, -80, -60, -9, 78, 99, 81, -41, -53, 22, 11, -69, -22, -2, + 70, 80, 18, -56, -54, -79, -27, 56, 46, 28, -1, 12, -37, -76, 23, 64, + -4, -5, 4, 0, -2, -5, 10, -4, -9, 5, 3, 3, -2, 6, -2, -1, + 0, 2, 0, 1, -2, 2, -3, -2, 0, 1, -1, 0, 0, -1, -1, -1, + 0, -1, -1, -1, -1, 0, 0, -1, 0, -1, -1, -1, -1, -1, -1, 0, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -2, -3, -5, -6, -5, -5, + -3, 0, -1, -3, -1, 7, 16, 20, 8, -8, -24, -35, -39, -36, -35, -42, + -47, -35, -14, 0, 8, 17, 28, 45, 60, 65, 64, 66, 67, 60, 50, 39, + 26, 14, 5, -14, -40, -54, -56, -56, -55, -47, -36, -20, 1, 13, 15, 16, + 12, 2, -10, -20, -33, -43, -42, -38, -43, -40, -28, -17, -7, 6, 21, 34, + 48, 60, 63, 64, 66, 61, 54, 51, 41, 23, 10, 1, -18, -37, -46, -54, + -63, -60, -46, -30, -13, 5, 15, 16, 17, 11, -2, -11, -21, -34, -44, -45, + -43, -42, -33, -21, -17, -10, 5, 23, 39, 54, 62, 61, 62, 63, 59, 53, + 47, 38, 23, 10, -5, -23, -36, -42, -51, -61, -61, -48, -26, -2, 14, 16, + 13, 13, 9, -1, -14, -27, -36, -42, -44, -48, -44, -31, -17, -10, -8, 1, + 21, 47, 65, 67, 58, 54, 58, 61, 54, 41, 31, 23, 11, -9, -30, -41, + -44, -45, -54, -61, -52, -21, 11, 25, 19, 8, 4, 7, 2, -15, -33, -39, + -39, -44, -51, -48, -34, -12, -2, -4, -2, 19, 54, 74, 72, 58, 47, 51, + 59, 54, 40, 26, 20, 7, -16, -37, -46, -44, -42, -51, -58, -47, -15, 19, + 31, 25, 9, -1, -1, -4, -15, -30, -37, -41, -51, -55, -48, -28, -11, -4, + -2, 6, 28, 58, 73, 74, 63, 50, 45, 46, 49, 42, 31, 19, -6, -30, + -43, -44, -42, -51, -54, -49, -33, -3, 18, 30, 31, 17, 2, -13, -15, -15, + -25, -31, -45, -62, -60, -45, -24, -16, -10, 6, 20, 40, 58, 68, 74, 69, + 55, 41, 37, 44, 43, 34, 15, -17, -41, -48, -46, -51, -59, -51, -34, -16, + 3, 17, 29, 33, 23, 2, -15, -18, -18, -22, -31, -50, -64, -61, -42, -30, + -24, -8, 13, 35, 50, 57, 65, 70, 70, 58, 42, 40, 41, 40, 32, 6, + -23, -45, -53, -55, -64, -60, -45, -24, -1, 10, 19, 27, 28, 23, 4, -9, + -17, -22, -23, -36, -53, -61, -60, -47, -36, -22, -3, 19, 44, 56, 60, 65, + 65, 65, 60, 52, 45, 39, 37, 23, -2, -26, -49, -63, -66, -63, -55, -42, + -16, 3, 14, 25, 25, 22, 19, 11, -2, -17, -20, -29, -44, -50, -58, -64, + -53, -32, -13, 0, 25, 45, 53, 65, 68, 61, 60, 63, 60, 47, 42, 33, + 7, -10, -26, -56, -73, -68, -57, -53, -37, -12, -1, 14, 32, 26, 16, 17, + 16, 1, -12, -19, -38, -52, -47, -55, -65, -50, -23, -9, 4, 27, 40, 48, + 68, 72, 59, 58, 67, 64, 52, 42, 21, -5, -16, -31, -60, -73, -62, -54, + -49, -34, -17, -4, 17, 32, 24, 13, 18, 20, 6, -11, -29, -46, -48, -46, + -54, -59, -41, -17, -5, 6, 20, 35, 54, 71, 68, 55, 60, 74, 71, 53, + 27, 5, -6, -16, -35, -62, -70, -57, -49, -45, -40, -25, 4, 25, 29, 15, + 7, 23, 27, 10, -20, -46, -47, -41, -39, -47, -55, -34, -11, -1, 4, 11, + 38, 67, 72, 62, 48, 61, 83, 76, 49, 9, -9, -7, -15, -31, -59, -70, + -55, -48, -46, -43, -21, 16, 29, 22, 6, 1, 25, 32, 10, -28, -57, -47, + -34, -30, -38, -49, -33, -12, -4, 3, 17, 50, 72, 68, 55, 44, 61, 86, + 77, 41, -2, -16, -10, -13, -28, -56, -69, -58, -52, -47, -35, -7, 22, 25, + 13, -4, -2, 25, 33, 7, -35, -58, -46, -29, -22, -32, -44, -34, -16, -5, + 8, 30, 59, 72, 65, 46, 39, 62, 87, 76, 33, -8, -20, -13, -10, -28, + -57, -70, -62, -51, -42, -24, 3, 23, 23, 4, -15, -4, 25, 34, 3, -38, + -55, -45, -23, -17, -32, -43, -34, -15, -1, 14, 41, 64, 73, 59, 35, 35, + 64, 89, 73, 26, -11, -23, -14, -11, -33, -60, -69, -59, -48, -39, -14, 11, + 25, 17, -11, -24, -3, 30, 35, -3, -40, -54, -41, -18, -19, -36, -41, -28, + -10, 0, 21, 51, 70, 71, 47, 24, 36, 72, 93, 65, 17, -14, -22, -13, + -17, -43, -62, -63, -52, -48, -36, -5, 19, 26, 5, -26, -27, 5, 40, 31, + -12, -42, -50, -34, -20, -28, -37, -33, -17, -8, -1, 29, 61, 75, 64, 31, + 19, 44, 85, 93, 51, 9, -15, -18, -16, -30, -50, -57, -52, -48, -52, -32, + 3, 25, 20, -10, -34, -21, 19, 42, 20, -17, -40, -43, -35, -30, -32, -32, + -21, -12, -12, 3, 37, 67, 72, 50, 25, 24, 57, 92, 81, 42, 6, -12, + -18, -25, -39, -53, -52, -44, -49, -51, -28, 6, 25, 13, -17, -32, -11, 29, + 39, 8, -24, -38, -37, -33, -36, -39, -30, -10, -3, -9, 3, 38, 68, 71, + 46, 23, 32, 68, 92, 71, 31, 5, -7, -16, -31, -50, -55, -45, -37, -49, + -53, -27, 8, 23, 8, -20, -24, 3, 34, 28, -6, -28, -32, -30, -35, -46, + -43, -23, 0, 0, -10, 5, 41, 67, 65, 42, 30, 47, 77, 83, 52, 23, + 10, 2, -16, -43, -60, -55, -38, -36, -53, -53, -25, 8, 19, 3, -14, -8, + 17, 29, 9, -17, -24, -22, -26, -43, -53, -42, -14, 4, -3, -9, 10, 44, + 63, 58, 43, 43, 63, 77, 64, 38, 24, 20, 7, -23, -52, -62, -49, -38, + -45, -57, -49, -19, 6, 11, 2, -1, 12, 22, 13, -7, -18, -15, -17, -32, + -50, -52, -32, -11, -4, -8, -3, 21, 44, 55, 53, 52, 63, 70, 64, 49, + 35, 34, 24, 0, -29, -53, -54, -50, -51, -56, -57, -37, -17, -2, 7, 9, + 20, 21, 12, 1, -13, -11, -13, -24, -36, -49, -40, -30, -22, -12, -9, 10, + 25, 38, 51, 57, 70, 71, 62, 57, 44, 42, 34, 15, -4, -30, -42, -53, + -65, -61, -61, -49, -35, -22, -2, 10, 25, 27, 15, 11, -1, -8, -14, -22, + -27, -37, -37, -37, -40, -26, -14, -2, 10, 24, 42, 54, 68, 73, 65, 65, + 60, 49, 36, 27, 15, -7, -25, -43, -63, -69, -65, -61, -54, -36, -13, 3, + 18, 26, 23, 20, 16, 1, -16, -21, -20, -31, -37, -38, -40, -38, -25, -15, + -7, 11, 34, 48, 56, 66, 71, 72, 73, 61, 43, 34, 29, 11, -14, -31, + -46, -63, -69, -72, -69, -53, -28, -7, 3, 16, 27, 30, 28, 15, -3, -14, + -19, -25, -39, -42, -37, -38, -35, -30, -19, -2, 18, 39, 47, 56, 69, 75, + 78, 71, 60, 49, 35, 22, -1, -20, -32, -50, -65, -76, -75, -63, -49, -27, + -9, 6, 22, 28, 31, 27, 16, 6, -13, -26, -36, -43, -41, -42, -42, -36, + -27, -10, 2, 18, 38, 52, 64, 70, 73, 79, 76, 70, 50, 27, 11, -5, + -21, -41, -62, -69, -72, -68, -61, -50, -26, -4, 13, 21, 23, 32, 35, 27, + 6, -21, -33, -37, -42, -48, -53, -45, -31, -19, -8, 3, 23, 45, 59, 65, + 65, 73, 88, 88, 69, 40, 19, 10, -6, -30, -54, -69, -69, -68, -67, -59, + -43, -18, 2, 10, 15, 22, 39, 46, 27, -3, -28, -34, -37, -48, -56, -60, + -48, -29, -16, -1, 14, 35, 52, 58, 60, 64, 80, 96, 88, 64, 34, 16, + 6, -11, -36, -62, -77, -75, -68, -58, -47, -33, -14, -1, 7, 15, 28, 43, + 44, 24, -6, -30, -38, -40, -49, -63, -68, -56, -30, -5, 15, 27, 40, 51, + 59, 63, 72, 84, 91, 83, 60, 32, 12, 1, -14, -45, -73, -84, -78, -62, + -46, -36, -28, -17, 0, 11, 20, 31, 38, 35, 20, -6, -28, -40, -46, -58, + -72, -71, -52, -26, 4, 26, 37, 45, 54, 64, 69, 74, 81, 80, 73, 59, + 35, 13, -5, -28, -54, -75, -79, -74, -63, -43, -30, -21, -11, 0, 14, 23, + 29, 33, 23, 14, -2, -25, -41, -58, -69, -71, -64, -43, -24, 3, 33, 47, + 56, 60, 64, 73, 74, 75, 73, 62, 56, 38, 13, -12, -42, -57, -69, -77, + -71, -63, -44, -25, -15, -3, 2, 13, 26, 23, 24, 19, 8, -2, -24, -44, + -64, -74, -64, -60, -45, -16, 9, 34, 53, 63, 68, 66, 75, 73, 63, 66, + 62, 49, 34, 11, -17, -43, -54, -66, -82, -72, -52, -43, -28, -10, 0, 4, + 18, 27, 16, 13, 20, 8, -11, -26, -47, -66, -63, -59, -63, -47, -7, 20, + 34, 56, 69, 65, 73, 81, 67, 54, 61, 63, 44, 25, 6, -23, -37, -44, + -69, -85, -69, -48, -39, -26, -7, -4, 5, 27, 25, 9, 10, 15, 5, -17, + -34, -52, -62, -54, -54, -60, -40, -5, 21, 41, 59, 67, 66, 78, 81, 64, + 53, 58, 56, 39, 18, -3, -24, -34, -45, -64, -76, -67, -51, -37, -21, -8, + -3, 11, 22, 20, 11, 9, 11, -4, -23, -38, -56, -57, -53, -50, -42, -31, + -5, 21, 41, 63, 67, 72, 77, 69, 67, 58, 56, 49, 28, 16, -8, -28, + -35, -50, -53, -62, -65, -53, -44, -20, -2, 2, 14, 10, 14, 17, 7, 5, + -13, -27, -37, -60, -58, -55, -42, -22, -18, -2, 13, 36, 69, 73, 76, 71, + 62, 70, 60, 53, 42, 23, 16, -13, -35, -45, -51, -40, -46, -58, -60, -52, + -17, 4, 8, 11, 5, 14, 15, 4, -4, -20, -23, -37, -62, -67, -59, -27, + -2, -3, -3, 3, 36, 70, 77, 75, 66, 67, 70, 57, 46, 32, 29, 19, + -17, -49, -62, -46, -25, -33, -54, -68, -51, -15, 4, 8, 6, 11, 18, 8, + -7, -19, -16, -12, -35, -68, -83, -56, -9, 13, 7, -7, 4, 40, 66, 73, + 69, 73, 80, 69, 46, 27, 31, 42, 24, -23, -68, -69, -36, -14, -25, -57, + -66, -43, -16, -3, -2, 11, 28, 23, -2, -31, -29, -4, -1, -34, -83, -89, + -45, 3, 22, 6, -3, 16, 41, 56, 55, 68, 93, 93, 65, 23, 12, 38, + 53, 27, -38, -80, -64, -29, -12, -31, -54, -49, -34, -22, -24, -11, 28, 47, + 25, -24, -51, -27, 5, 5, -43, -90, -79, -34, 6, 11, 4, 17, 31, 39, + 34, 38, 79, 114, 105, 50, 3, 12, 44, 56, 16, -49, -72, -54, -28, -29, + -44, -37, -27, -28, -41, -45, -5, 46, 61, 17, -44, -53, -20, 7, -6, -53, + -78, -62, -27, -7, -6, 14, 41, 45, 26, 11, 38, 93, 127, 101, 34, 1, + 20, 48, 42, -1, -41, -53, -45, -40, -51, -44, -18, -9, -34, -61, -47, 7, + 57, 58, 2, -46, -43, -14, -5, -27, -52, -58, -46, -31, -26, -12, 28, 59, + 45, 10, 6, 50, 104, 124, 87, 30, 11, 30, 40, 19, -9, -26, -35, -44, + -58, -62, -38, -4, -6, -46, -67, -37, 21, 56, 43, -4, -37, -30, -15, -25, + -40, -44, -38, -38, -43, -38, -9, 40, 64, 37, 5, 14, 65, 106, 107, 75, + 36, 26, 34, 24, 4, -8, -10, -24, -53, -70, -64, -30, 0, -16, -53, -61, + -22, 28, 43, 29, -2, -21, -20, -26, -39, -43, -34, -26, -43, -54, -40, 0, + 46, 56, 30, 12, 30, 75, 97, 90, 69, 47, 38, 29, 13, 2, 0, -1, + -27, -61, -71, -55, -25, -14, -32, -50, -41, -6, 22, 25, 17, 4, -8, -19, + -31, -38, -35, -28, -35, -53, -54, -29, 7, 31, 32, 23, 28, 51, 72, 78, + 72, 65, 55, 42, 30, 19, 15, 11, -8, -36, -58, -58, -42, -35, -35, -43, + -40, -18, 0, 12, 14, 11, 9, -4, -15, -25, -31, -28, -36, -49, -53, -45, + -18, 1, 12, 19, 23, 43, 58, 64, 68, 64, 64, 57, 46, 40, 28, 22, + 9, -17, -35, -48, -47, -44, -47, -45, -44, -31, -12, -2, 7, 10, 9, 7, + -2, -8, -19, -28, -32, -44, -51, -48, -37, -21, -9, 5, 16, 26, 43, 55, + 60, 64, 63, 61, 58, 55, 48, 34, 21, 6, -13, -27, -39, -49, -53, -50, + -46, -41, -32, -16, -3, 5, 11, 9, 6, 5, -4, -17, -32, -40, -42, -44, + -42, -40, -32, -12, 5, 17, 24, 35, 50, 58, 64, 64, 60, 65, 61, 50, + 34, 18, 10, -2, -18, -38, -58, -56, -49, -45, -41, -38, -22, -4, 8, 14, + 8, 11, 10, -5, -20, -38, -41, -36, -37, -40, -48, -37, -12, 4, 14, 19, + 27, 46, 59, 66, 63, 62, 70, 64, 50, 34, 22, 17, 8, -11, -38, -59, + -57, -50, -49, -47, -43, -28, -6, 10, 16, 10, 14, 8, 1, -5, -5, -4, + -5, 5, 2, 2, 1, -1, 0, 1, 0, 2, 0, 0, -2, -1, -1, 2, + 1, 1, 0, 0, -1, 0, -1, 0, 0, 0, 0, 0, 0, -1, -1, -1, + 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, -1, + -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, + -1, 0, 1, 0, 0, 0, 1, 0, 1, 0, -3, -10, -11, -8, -13, -25, + -21, -10, 0, 2, 18, 41, 44, 42, 66, 62, 28, 10, 17, 17, -16, -10, + 25, 28, 29, 34, 47, 34, -7, 7, 25, -12, -43, -44, -40, -61, -85, -78, + -55, -42, -33, -10, 17, 31, 43, 59, 51, 25, 25, 40, 27, -1, 2, 25, + 30, 15, 12, 27, 26, 13, 16, 9, -24, -43, -37, -49, -83, -92, -62, -40, + -42, -36, 1, 33, 34, 45, 61, 46, 27, 32, 33, 10, -6, 15, 38, 26, + 4, 15, 35, 19, 7, 17, 3, -26, -41, -50, -67, -91, -82, -48, -40, -46, + -24, 18, 33, 32, 54, 62, 46, 30, 22, 20, 7, 4, 28, 33, 15, 10, + 22, 25, 9, 13, 18, -2, -29, -54, -65, -74, -86, -68, -49, -46, -32, -8, + 17, 29, 45, 65, 60, 43, 23, 13, 17, 12, 18, 28, 22, 19, 16, 13, + 14, 16, 24, 13, -13, -40, -66, -72, -75, -74, -64, -55, -36, -20, -9, 15, + 43, 63, 65, 51, 37, 17, 9, 19, 23, 21, 19, 24, 21, 3, 4, 24, + 31, 18, -2, -20, -49, -77, -74, -65, -71, -69, -47, -27, -27, -10, 38, 66, + 59, 52, 51, 34, 4, 11, 36, 26, 12, 22, 26, 2, -11, 25, 45, 18, + 0, -1, -23, -72, -83, -55, -65, -83, -61, -34, -37, -36, 23, 71, 55, 43, + 60, 55, 11, 1, 40, 37, 8, 16, 31, 6, -22, 14, 55, 27, -3, 8, + 2, -52, -83, -57, -56, -89, -79, -43, -43, -55, -4, 66, 61, 35, 56, 68, + 31, 4, 32, 46, 13, 7, 31, 16, -24, -4, 50, 42, 2, 7, 16, -25, + -67, -60, -54, -86, -95, -55, -44, -63, -32, 40, 62, 40, 47, 67, 48, 22, + 32, 42, 18, 4, 25, 25, -15, -16, 29, 44, 21, 11, 15, -5, -39, -49, + -59, -85, -96, -72, -52, -62, -50, 7, 45, 49, 50, 56, 56, 43, 42, 39, + 19, 9, 16, 21, 1, -16, 9, 32, 31, 24, 14, 5, -14, -34, -52, -81, + -94, -85, -71, -62, -55, -21, 21, 41, 53, 55, 55, 57, 51, 44, 26, 13, + 15, 11, 3, -3, 0, 19, 27, 29, 26, 11, 0, -16, -41, -70, -90, -88, + -85, -80, -57, -34, -3, 26, 42, 57, 57, 60, 64, 50, 33, 20, 17, 9, + -6, -1, 6, 10, 23, 26, 28, 22, 10, 1, -27, -60, -78, -87, -90, -94, + -74, -42, -20, 10, 34, 44, 57, 65, 71, 58, 35, 30, 23, 8, -5, -7, + 4, 7, 19, 33, 23, 19, 24, 17, -13, -53, -65, -75, -96, -98, -83, -61, + -40, -7, 32, 38, 38, 66, 83, 65, 36, 36, 37, 8, -7, 1, 0, -5, + 11, 39, 34, 10, 21, 36, 4, -45, -59, -59, -89, -106, -84, -67, -62, -32, + 21, 41, 30, 47, 85, 80, 41, 34, 45, 20, -8, 0, 9, -7, -6, 31, + 45, 21, 12, 32, 25, -27, -55, -52, -76, -104, -95, -70, -64, -57, -7, 33, + 34, 38, 67, 84, 57, 35, 46, 29, -1, -4, 7, 7, -8, 12, 41, 31, + 21, 24, 25, -5, -43, -45, -65, -98, -98, -82, -62, -58, -35, 13, 27, 38, + 59, 70, 67, 45, 49, 39, 2, -3, 2, 9, 9, 6, 30, 30, 24, 31, + 20, 3, -26, -37, -48, -91, -100, -88, -75, -53, -41, -9, 12, 23, 55, 65, + 61, 54, 51, 51, 14, -6, 1, 1, 15, 18, 26, 29, 16, 30, 28, 4, + -14, -29, -36, -71, -100, -93, -87, -64, -38, -16, 2, 6, 33, 61, 59, 56, + 54, 55, 32, 1, -3, -4, 5, 25, 36, 36, 17, 14, 25, 14, -4, -19, + -30, -53, -84, -94, -95, -82, -49, -16, 4, 2, 10, 37, 56, 61, 58, 54, + 42, 19, 3, -9, -8, 14, 41, 53, 32, 10, 7, 10, 10, -7, -25, -43, + -65, -81, -97, -99, -72, -29, 9, 11, 3, 10, 33, 61, 65, 55, 46, 30, + 19, 0, -17, -5, 29, 62, 57, 24, -1, -6, 10, 8, -16, -35, -54, -64, + -80, -105, -99, -57, -2, 26, 13, -2, 6, 42, 67, 60, 49, 36, 31, 22, + -10, -24, 1, 49, 77, 53, 9, -14, -4, 10, -4, -26, -47, -56, -58, -89, + -115, -93, -34, 23, 33, 6, -6, 16, 50, 62, 53, 39, 34, 40, 16, -24, + -26, 15, 71, 82, 38, -5, -13, -1, 3, -13, -39, -53, -48, -61, -103, -119, + -80, -6, 42, 27, -1, 2, 26, 51, 56, 43, 33, 43, 42, 4, -34, -23, + 37, 87, 70, 20, -6, -10, -3, -5, -27, -49, -48, -44, -72, -115, -118, -56, + 22, 43, 17, 3, 12, 33, 51, 45, 34, 38, 51, 38, -11, -42, -9, 59, + 86, 53, 13, -5, -5, -3, -19, -42, -50, -43, -45, -85, -127, -105, -28, 34, + 37, 15, 8, 23, 41, 42, 34, 33, 45, 55, 26, -27, -38, 12, 69, 77, + 40, 9, 1, 0, -13, -33, -48, -49, -39, -55, -102, -124, -83, -8, 37, 31, + 14, 19, 35, 39, 34, 30, 35, 51, 50, 9, -31, -25, 27, 72, 65, 30, + 12, 9, -2, -23, -42, -52, -46, -43, -71, -109, -112, -63, 7, 36, 25, 20, + 33, 42, 35, 29, 29, 40, 52, 35, -2, -28, -12, 40, 69, 51, 26, 18, + 13, -8, -33, -48, -50, -46, -57, -84, -107, -98, -43, 14, 29, 24, 30, 44, + 43, 30, 26, 34, 44, 40, 19, -8, -20, 4, 46, 59, 42, 29, 25, 10, + -18, -40, -46, -47, -57, -73, -91, -100, -78, -30, 13, 25, 30, 44, 48, 39, + 29, 31, 41, 35, 23, 9, -9, -5, 16, 43, 52, 40, 37, 25, 0, -23, + -41, -43, -54, -74, -82, -93, -86, -60, -26, 12, 26, 41, 53, 44, 40, 33, + 36, 38, 19, 12, 2, -3, 9, 18, 40, 48, 42, 41, 16, -6, -23, -41, + -45, -68, -84, -86, -90, -71, -52, -22, 15, 32, 52, 54, 45, 45, 36, 36, + 25, 6, 6, 0, 5, 15, 21, 41, 46, 46, 37, 10, -7, -24, -42, -57, + -81, -88, -88, -83, -62, -43, -14, 16, 41, 59, 55, 48, 48, 40, 27, 10, + 2, 2, 0, 8, 22, 30, 36, 45, 50, 32, 5, -9, -23, -48, -75, -86, + -86, -88, -81, -54, -26, -11, 16, 52, 65, 55, 50, 53, 39, 9, -2, 4, + 2, -4, 11, 36, 34, 27, 47, 51, 26, 0, -9, -23, -63, -91, -85, -81, + -89, -79, -38, -13, -11, 23, 62, 67, 55, 52, 56, 29, -8, -7, 7, 0, + -5, 19, 44, 30, 28, 49, 46, 21, -2, -10, -32, -79, -96, -83, -81, -87, + -67, -27, -11, 0, 36, 65, 67, 58, 54, 48, 14, -15, -7, 3, 1, 6, + 26, 35, 30, 38, 46, 37, 18, -2, -18, -48, -85, -96, -89, -81, -70, -52, + -30, -8, 20, 48, 63, 66, 59, 50, 33, 6, -14, -15, -2, 13, 20, 21, + 25, 36, 45, 42, 31, 12, -10, -31, -56, -84, -103, -96, -70, -50, -43, -31, + 0, 35, 58, 68, 65, 51, 37, 26, 8, -19, -25, 2, 27, 27, 17, 20, + 36, 45, 45, 29, 0, -27, -41, -55, -87, -111, -93, -57, -37, -33, -23, 5, + 41, 70, 77, 59, 36, 26, 24, 4, -24, -22, 7, 31, 33, 19, 14, 29, + 49, 50, 22, -16, -39, -48, -63, -92, -104, -86, -51, -25, -19, -16, 10, 53, + 82, 74, 47, 26, 19, 16, -1, -18, -16, 7, 35, 37, 18, 10, 31, 55, + 41, 4, -25, -45, -57, -73, -90, -95, -82, -42, -9, -8, -11, 20, 71, 84, + 57, 39, 27, 13, 2, -6, -9, -12, 8, 45, 41, 8, 5, 42, 56, 20, + -10, -24, -50, -73, -83, -83, -87, -76, -25, 10, -5, -9, 39, 84, 71, 44, + 38, 26, 2, -9, -2, -4, -11, 17, 52, 36, 0, 11, 50, 43, 3, -19, + -31, -57, -84, -84, -77, -82, -59, -9, 14, 1, 7, 55, 81, 61, 38, 29, + 20, -2, -10, -1, -4, 0, 26, 42, 30, 8, 20, 41, 28, -4, -31, -46, + -64, -84, -82, -79, -66, -37, -7, 15, 18, 30, 58, 68, 57, 33, 17, 9, + 0, -3, -7, 0, 15, 23, 31, 29, 23, 24, 22, 14, -12, -43, -63, -72, + -73, -83, -75, -47, -26, -2, 20, 37, 48, 50, 57, 52, 30, 6, -1, 11, + 0, -9, 7, 16, 24, 28, 32, 33, 15, 7, 2, -21, -55, -79, -66, -67, + -81, -63, -38, -12, 9, 29, 53, 48, 42, 51, 47, 22, -6, 5, 18, -4, + -7, 6, 22, 28, 26, 39, 28, 2, -2, -8, -35, -73, -76, -56, -67, -77, + -55, -20, 4, 16, 40, 54, 42, 41, 51, 37, 7, 0, 17, 13, -12, -9, + 20, 31, 25, 29, 33, 15, -5, -8, -22, -57, -74, -62, -57, -74, -71, -33, + 0, 11, 26, 44, 45, 41, 47, 45, 22, 3, 12, 19, 0, -15, 4, 30, + 32, 27, 26, 17, 3, -4, -14, -44, -69, -66, -56, -63, -74, -52, -11, 12, + 21, 29, 35, 41, 49, 51, 31, 9, 11, 19, 11, -8, -7, 20, 36, 34, + 22, 10, 6, 5, -4, -33, -64, -66, -58, -58, -67, -63, -29, 4, 20, 21, + 21, 35, 52, 57, 39, 12, 10, 18, 16, 3, -7, 8, 31, 39, 25, 5, + 3, 10, 5, -22, -58, -67, -58, -56, -60, -64, -45, -11, 15, 19, 12, 24, + 50, 62, 46, 17, 9, 18, 20, 12, 0, 2, 21, 37, 31, 7, 0, 11, + 14, -12, -51, -66, -58, -53, -54, -59, -54, -29, 3, 16, 9, 17, 44, 62, + 51, 22, 8, 17, 24, 21, 9, 1, 11, 30, 31, 14, 3, 11, 16, -4, + -43, -65, -58, -49, -50, -53, -55, -43, -16, 5, 10, 16, 38, 59, 54, 26, + 7, 18, 29, 24, 18, 8, 5, 16, 27, 23, 11, 14, 18, -1, -36, -63, + -56, -43, -48, -47, -49, -52, -36, -12, 8, 17, 35, 55, 50, 28, 9, 17, + 33, 25, 24, 20, 5, 4, 15, 27, 23, 20, 22, 0, -32, -58, -55, -40, + -47, -44, -39, -52, -54, -34, -2, 19, 35, 53, 46, 27, 12, 18, 34, 26, + 26, 33, 13, -6, 0, 22, 34, 32, 28, 3, -31, -53, -51, -39, -47, -45, + -30, -45, -66, -56, -19, 15, 38, 52, 43, 22, 13, 22, 35, 26, 26, 41, + 25, -7, -13, 10, 35, 46, 39, 10, -29, -50, -46, -37, -47, -46, -27, -35, + -65, -72, -42, 2, 38, 55, 43, 19, 11, 24, 36, 27, 26, 43, 37, 2, + -19, -6, 25, 53, 56, 20, -24, -46, -43, -36, -46, -48, -29, -28, -56, -77, + -64, -22, 31, 61, 45, 16, 10, 23, 35, 30, 26, 41, 42, 16, -14, -21, + 7, 51, 70, 36, -15, -38, -40, -35, -42, -49, -35, -29, -44, -71, -81, -49, + 14, 60, 50, 18, 10, 21, 34, 34, 26, 37, 43, 30, 0, -27, -13, 37, + 74, 54, 2, -29, -35, -32, -37, -49, -42, -32, -36, -57, -85, -73, -12, 46, + 57, 27, 9, 17, 32, 38, 28, 30, 41, 39, 18, -20, -27, 15, 62, 68, + 26, -17, -30, -28, -29, -45, -51, -40, -34, -45, -77, -86, -42, 18, 54, 43, + 14, 12, 29, 42, 34, 25, 33, 41, 30, -2, -24, -5, 36, 65, 50, 3, + -24, -24, -19, -33, -54, -52, -42, -45, -61, -75, -58, -15, 32, 48, 25, 10, + 24, 45, 45, 27, 26, 32, 28, 13, -4, -6, 14, 44, 55, 24, -11, -18, + -12, -20, -46, -57, -53, -54, -57, -63, -57, -33, 4, 35, 32, 16, 22, 40, + 49, 36, 26, 28, 23, 17, 8, 1, 10, 27, 43, 33, 5, -6, -8, -14, + -33, -53, -57, -61, -62, -61, -59, -38, -10, 15, 26, 20, 26, 40, 44, 41, + 30, 27, 25, 18, 12, 3, 9, 26, 33, 28, 13, 5, 5, -8, -25, -45, + -57, -60, -64, -66, -65, -49, -17, 6, 13, 16, 26, 43, 47, 39, 32, 27, + 27, 25, 13, 3, 6, 22, 35, 26, 13, 10, 12, 5, -17, -40, -54, -58, + -58, -68, -74, -61, -31, -1, 9, 10, 23, 40, 50, 45, 31, 24, 27, 31, + 20, 3, 2, 17, 32, 31, 16, 12, 15, 12, -4, -31, -51, -55, -54, -62, + -76, -73, -47, -17, 2, 8, 19, 37, 51, 50, 34, 24, 26, 31, 25, 9, + 4, 13, 26, 34, 25, 9, 13, 20, -2, -33, -44, -43, -58, -78, -77, -59, + -44, -33, -10, 17, 6, 12, -9, 32, 13, 4, -4, 6, -9, 27, 8, 2, + -1, -3, -2, 3, -4, -3, 2, 0, -2, 1, -2, 1, -4, 2, 1, 0, + -2, -1, -3, 2, 0, -1, -2, -2, -2, -1, -2, -2, -1, -2, -2, -2, + -2, -1, -2, -1, 0, -1, -2, -2, -2, -1, 0, -2, -2, -2, -2, -1, + -1, -2, -1, -2, -2, -2, -3, -1, -1, 0, 0, -1, -3, -2, 1, 3, + 0, 0, -2, -8, -21, -17, -2, 12, 20, 19, 6, -13, -28, -73, -67, -64, + -58, -39, -11, 19, 38, 60, 96, 80, 38, 12, 6, -20, -65, -83, -65, -61, + -56, -17, 22, 35, 49, 74, 94, 55, 16, 20, -5, -52, -89, -81, -53, -65, + -36, 21, 37, 48, 51, 85, 82, 25, 23, 9, -36, -80, -105, -58, -57, -54, + 7, 36, 54, 44, 58, 97, 48, 26, 16, -21, -61, -115, -83, -45, -57, -12, + 23, 57, 54, 36, 86, 77, 37, 21, -16, -40, -103, -110, -54, -46, -24, 6, + 43, 68, 36, 62, 86, 60, 30, -12, -34, -80, -119, -76, -44, -24, -5, 24, + 64, 51, 50, 76, 72, 48, 0, -34, -68, -106, -94, -56, -26, -7, 11, 45, + 59, 58, 66, 71, 60, 23, -27, -68, -93, -93, -72, -37, -8, 10, 25, 50, + 70, 68, 62, 62, 45, -10, -70, -88, -83, -79, -57, -15, 15, 13, 31, 73, + 80, 59, 53, 61, 15, -67, -89, -73, -75, -75, -33, 21, 11, 10, 66, 92, + 65, 42, 63, 42, -56, -92, -66, -66, -84, -57, 16, 19, -5, 50, 98, 76, + 39, 56, 60, -35, -95, -64, -53, -84, -79, 0, 28, -8, 29, 96, 89, 42, + 46, 69, -10, -90, -69, -41, -74, -95, -25, 28, -1, 13, 81, 101, 53, 37, + 69, 11, -77, -75, -38, -53, -103, -55, 22, 8, 6, 61, 104, 75, 29, 59, + 31, -61, -76, -43, -36, -91, -88, 6, 17, 1, 46, 96, 94, 34, 40, 48, + -40, -80, -47, -27, -69, -107, -27, 26, 4, 29, 87, 105, 51, 24, 46, -10, + -76, -58, -21, -49, -107, -62, 17, 16, 17, 70, 110, 67, 22, 38, 10, -60, + -71, -24, -28, -97, -85, -6, 25, 18, 50, 106, 84, 28, 31, 16, -38, -71, + -38, -17, -78, -94, -30, 15, 30, 41, 86, 92, 44, 31, 15, -25, -54, -53, + -26, -57, -88, -51, -2, 33, 45, 68, 88, 59, 35, 17, -15, -42, -55, -41, + -48, -73, -60, -19, 24, 50, 61, 74, 67, 46, 21, -8, -32, -48, -54, -53, + -57, -57, -34, 9, 50, 63, 59, 65, 58, 29, -1, -24, -38, -62, -67, -48, + -47, -40, -8, 43, 68, 48, 58, 66, 38, 6, -19, -26, -62, -85, -45, -35, + -39, -21, 28, 72, 41, 47, 74, 45, 15, -14, -17, -53, -102, -50, -24, -36, + -26, 10, 69, 42, 32, 81, 52, 21, -4, -15, -39, -109, -64, -12, -35, -26, + -1, 54, 47, 21, 79, 65, 20, 7, -12, -33, -100, -82, -8, -27, -32, -2, + 36, 47, 21, 66, 77, 25, 12, -2, -36, -88, -87, -18, -16, -36, -8, 27, + 36, 30, 56, 77, 39, 12, 6, -33, -84, -79, -30, -11, -29, -20, 19, 27, + 31, 58, 66, 50, 21, 5, -25, -81, -75, -32, -17, -17, -27, 2, 24, 28, + 61, 61, 48, 35, 4, -22, -71, -77, -31, -19, -12, -23, -18, 16, 29, 59, + 65, 45, 41, 10, -23, -59, -76, -37, -14, -11, -18, -29, -2, 29, 57, 68, + 51, 37, 16, -21, -55, -67, -44, -12, -5, -21, -29, -19, 19, 59, 68, 61, + 36, 14, -12, -55, -61, -44, -16, 3, -21, -29, -25, 0, 55, 72, 69, 43, + 8, -6, -49, -63, -39, -18, 5, -15, -31, -26, -18, 39, 78, 75, 53, 8, + -8, -40, -67, -37, -15, 2, -8, -30, -26, -29, 16, 79, 84, 59, 14, -11, + -33, -66, -42, -9, -2, -6, -23, -26, -33, -7, 66, 94, 67, 22, -9, -32, + -62, -48, -8, 0, -9, -16, -20, -35, -24, 46, 96, 78, 31, -2, -29, -59, + -51, -13, 1, -10, -13, -9, -31, -35, 23, 86, 88, 42, 5, -22, -57, -53, + -18, -3, -10, -13, 0, -19, -44, 2, 69, 90, 57, 12, -13, -50, -57, -21, + -9, -13, -13, 1, -3, -41, -17, 51, 82, 69, 23, -9, -37, -57, -25, -12, + -22, -15, 0, 10, -25, -32, 32, 69, 71, 37, -4, -25, -48, -30, -12, -32, + -23, -3, 14, -2, -33, 11, 56, 63, 49, 3, -18, -32, -31, -13, -37, -38, + -9, 11, 17, -16, -6, 41, 53, 51, 11, -17, -15, -23, -14, -35, -54, -22, + 4, 26, 10, -10, 26, 43, 46, 19, -19, -6, -5, -10, -30, -65, -42, -9, + 24, 35, 3, 12, 32, 37, 24, -20, -8, 14, 2, -23, -68, -62, -26, 10, + 50, 28, 11, 22, 27, 24, -19, -19, 24, 21, -8, -63, -78, -45, -11, 47, + 53, 23, 21, 19, 22, -17, -34, 21, 40, 15, -48, -89, -65, -34, 30, 68, + 44, 27, 16, 16, -11, -47, 3, 49, 39, -22, -89, -82, -55, 3, 68, 61, + 44, 21, 11, -6, -53, -21, 45, 56, 11, -74, -96, -72, -26, 52, 73, 60, + 39, 10, -3, -48, -44, 27, 61, 42, -43, -101, -88, -52, 27, 73, 70, 59, + 21, -1, -40, -60, 2, 52, 60, -4, -90, -100, -74, -2, 62, 72, 76, 42, + 5, -30, -66, -22, 34, 63, 33, -62, -104, -92, -31, 44, 68, 84, 66, 21, + -21, -64, -41, 13, 54, 55, -26, -94, -104, -57, 20, 56, 82, 84, 43, -6, + -57, -54, -10, 36, 60, 7, -70, -107, -78, -6, 40, 73, 92, 66, 12, -45, + -57, -27, 16, 52, 29, -41, -96, -90, -32, 20, 60, 91, 83, 34, -27, -52, + -37, -3, 34, 36, -15, -77, -91, -52, -1, 43, 83, 93, 53, -5, -42, -40, + -17, 14, 32, 1, -54, -81, -65, -21, 23, 71, 96, 67, 16, -25, -37, -24, + -5, 21, 6, -36, -64, -69, -37, 3, 54, 93, 73, 35, -6, -28, -25, -19, + 8, 4, -27, -46, -65, -46, -14, 34, 86, 73, 49, 15, -17, -19, -28, -4, + -3, -28, -32, -56, -48, -24, 15, 74, 67, 55, 36, -2, -10, -28, -14, -9, + -36, -25, -42, -50, -29, 1, 60, 59, 50, 55, 16, -3, -22, -20, -14, -46, + -29, -28, -48, -33, -5, 47, 50, 40, 64, 40, 4, -14, -17, -19, -53, -40, + -18, -40, -41, -6, 39, 39, 28, 61, 62, 17, -10, -7, -21, -59, -53, -20, + -28, -47, -11, 38, 29, 15, 52, 77, 36, -6, 1, -12, -63, -66, -25, -20, + -46, -19, 37, 28, 0, 38, 83, 54, 5, 5, -2, -57, -81, -34, -15, -44, + -22, 29, 31, -4, 16, 85, 68, 17, 15, 1, -44, -87, -54, -8, -42, -27, + 25, 24, 2, 0, 69, 88, 24, 25, 11, -42, -76, -75, -14, -25, -40, 23, + 18, -3, 3, 42, 96, 45, 22, 29, -39, -70, -75, -40, -8, -39, 7, 24, + -17, 8, 33, 79, 76, 22, 35, -21, -75, -64, -60, -15, -17, -14, 21, -21, + -4, 40, 59, 88, 45, 24, -3, -71, -61, -59, -38, 1, -14, 0, -17, -18, + 41, 54, 82, 74, 22, -3, -53, -61, -53, -54, -2, 3, -19, -25, -22, 30, + 57, 73, 92, 38, -15, -40, -51, -50, -58, -17, 17, -23, -44, -22, 19, 55, + 72, 97, 60, -22, -40, -35, -45, -55, -32, 14, -17, -60, -26, 11, 46, 75, + 97, 78, -17, -46, -23, -38, -45, -37, -1, -14, -66, -31, 3, 34, 80, 98, + 85, -4, -47, -19, -33, -33, -30, -20, -25, -63, -34, -4, 18, 79, 104, 84, + 9, -38, -18, -29, -27, -14, -30, -46, -63, -32, -5, 3, 68, 111, 84, 18, + -23, -12, -25, -28, -2, -25, -67, -75, -29, 1, -6, 46, 112, 91, 22, -11, + 0, -18, -33, -1, -9, -76, -96, -34, 9, -8, 22, 101, 102, 27, -2, 14, + -7, -36, -9, 4, -68, -114, -48, 13, -3, 5, 80, 109, 40, 4, 26, 6, + -33, -18, 6, -52, -120, -67, 7, 4, -1, 55, 103, 58, 14, 31, 17, -21, + -24, -4, -39, -110, -84, -10, 6, 2, 34, 87, 71, 29, 36, 25, -7, -23, + -16, -33, -96, -90, -29, -1, 6, 22, 68, 75, 45, 45, 31, 4, -15, -24, + -37, -84, -87, -43, -15, 3, 18, 53, 68, 57, 58, 38, 11, -7, -22, -45, + -81, -79, -48, -29, -10, 17, 45, 57, 61, 71, 50, 17, 0, -15, -49, -85, + -74, -45, -40, -25, 10, 42, 49, 55, 82, 65, 22, 7, -9, -43, -89, -80, + -34, -47, -40, -1, 35, 52, 43, 85, 84, 25, 17, -4, -38, -85, -92, -28, + -44, -55, -9, 21, 53, 42, 75, 100, 35, 22, 6, -38, -74, -99, -38, -34, + -65, -18, 12, 42, 51, 63, 102, 52, 25, 21, -36, -70, -90, -56, -30, -64, + -30, 7, 27, 55, 63, 90, 69, 33, 26, -26, -69, -79, -66, -43, -54, -37, + -1, 17, 49, 69, 79, 72, 50, 30, -15, -61, -75, -68, -58, -52, -33, -12, + 9, 42, 69, 78, 64, 60, 42, -9, -49, -71, -69, -68, -61, -25, -17, -1, + 38, 64, 77, 59, 62, 58, -3, -37, -62, -72, -72, -73, -24, -12, -11, 35, + 55, 73, 59, 58, 69, 8, -29, -48, -75, -76, -82, -31, -4, -14, 28, 49, + 63, 61, 54, 73, 22, -21, -36, -71, -82, -88, -42, 0, -9, 21, 43, 53, + 57, 56, 73, 33, -12, -25, -62, -89, -95, -49, -2, -2, 18, 37, 43, 49, + 60, 75, 38, -2, -16, -49, -89, -105, -54, -7, 1, 19, 31, 37, 38, 59, + 81, 39, 4, -7, -35, -83, -115, -62, -10, 0, 20, 27, 32, 30, 53, 87, + 43, 4, 0, -24, -70, -118, -75, -12, -2, 19, 24, 27, 27, 45, 89, 52, + 4, 1, -14, -55, -113, -87, -18, -3, 13, 20, 24, 28, 41, 85, 60, 7, + -3, -9, -40, -100, -91, -28, -4, 7, 10, 21, 30, 43, 82, 62, 13, -8, + -11, -26, -85, -87, -36, -10, 2, -4, 14, 35, 47, 81, 62, 18, -9, -21, + -20, -65, -78, -38, -19, -4, -16, 0, 39, 54, 85, 65, 20, -7, -31, -24, + -47, -62, -33, -26, -15, -25, -19, 35, 63, 90, 73, 22, -3, -39, -39, -35, + -43, -20, -26, -30, -34, -36, 24, 71, 94, 85, 29, -3, -40, -58, -34, -24, + -4, -16, -46, -47, -47, 6, 73, 100, 97, 42, -4, -39, -73, -45, -8, 12, + 0, -51, -64, -56, -13, 66, 104, 106, 64, 2, -40, -82, -63, -3, 27, 18, + -43, -82, -68, -28, 51, 104, 112, 86, 19, -42, -86, -81, -10, 40, 34, -26, + -90, -86, -41, 31, 98, 116, 104, 46, -38, -92, -95, -25, 46, 48, -6, -84, + -105, -55, 13, 84, 117, 114, 76, -20, -95, -105, -45, 41, 54, 8, -65, -112, + -70, -1, 65, 109, 115, 100, 14, -85, -106, -62, 21, 50, 13, -44, -104, -84, + -14, 45, 98, 112, 111, 53, -62, -105, -75, -3, 44, 12, -31, -85, -93, -27, + 27, 82, 110, 110, 81, -27, -95, -81, -27, 31, 11, -31, -66, -90, -39, 12, + 61, 106, 107, 94, 12, -73, -79, -48, 11, 13, -32, -57, -78, -46, -1, 38, + 97, 109, 96, 43, -41, -69, -62, -13, 13, -30, -58, -68, -46, -11, 17, 81, + 112, 97, 59, -7, -51, -67, -37, 6, -23, -62, -67, -42, -14, 2, 60, 110, + 99, 65, 20, -24, -63, -56, -7, -15, -63, -75, -40, -12, -8, 39, 102, 103, + 67, 35, 6, -48, -68, -25, -11, -56, -85, -46, -7, -10, 22, 86, 107, 72, + 41, 29, -25, -70, -42, -14, -42, -91, -62, -5, -6, 9, 67, 105, 84, 40, + 40, 3, -64, -56, -23, -30, -83, -85, -12, 3, 1, 50, 97, 96, 44, 36, + 28, -45, -69, -33, -22, -67, -101, -34, 13, 2, 31, 88, 104, 56, 28, 37, + -16, -71, -51, -18, -49, -103, -62, 9, 14, 18, 70, 109, 68, 26, 36, 6, + -58, -68, -23, -28, -97, -84, -7, 23, 19, 50, 106, 84, 28, 31, -21, -26, + -18, -30, -24, -77, -76, -48, -46, 31, 0, -1, 0, 0, 2, 0, 1, -2, + 1, 0, -6, -7, -5, -3, 0, -3, -4, -2, 2, 0, -8, -11, -14, -10, + -8, -4, 6, 13, 14, 9, 2, -6, -10, -9, -6, 9, 17, 15, 8, 0, + 1, -4, -12, -19, -14, -8, -4, 3, 6, -2, -4, -6, -7, -10, -8, -12, + -11, 3, 23, 27, 11, 4, -3, -5, 0, -9, -3, 6, 11, 19, 4, -8, + -17, -20, -21, -3, 5, 8, 2, 3, 5, 2, -3, -3, -12, 4, 1, 3, + -7, 0, 5, 6, 0, -7, -8, -5, -7, -5, -3, 4, 9, 5, -5, -5, + -5, -17, -7, 3, 17, 15, 7, -2, -5, -3, 3, -8, -5, -3, 3, 8, + 12, 5, -10, -27, -20, 1, 5, -4, -9, -17, 4, 10, 9, -2, -12, -16, + -12, -2, 8, 16, 13, 11, 16, 19, 10, -2, -16, -21, -11, 14, 15, 21, + 11, 6, -10, -8, -11, -24, -35, -31, -13, 9, 24, 17, -2, -11, -20, -11, + -19, -7, 3, 8, 22, 21, 21, 2, -7, -10, 12, 24, 18, -3, -19, -6, + 0, -5, -18, -17, 6, 12, 7, -16, -20, -22, -27, -19, -14, 12, 14, 3, + 0, 2, 8, -3, -5, -3, 21, 29, 17, 6, -8, 3, 3, 10, 10, 3, + 12, 4, -9, -18, -20, -20, -9, 6, 3, -9, -7, -14, -9, -8, -9, -23, + -19, 7, 17, 20, 9, 8, 5, 9, 18, 9, 8, -10, -10, -4, 9, 25, + -6, -19, -19, -5, -4, -7, -7, -17, -15, -7, -4, 0, 2, -2, -17, -4, + 14, 23, 15, 2, -7, -5, 9, 11, 1, 0, -3, 0, 0, 15, 14, -4, + -15, -20, -26, -22, -13, 0, 6, 12, 5, -10, 2, 8, -2, -18, -8, 6, + 20, 28, 23, 0, -16, -7, 9, 7, 10, -12, -21, -19, 7, 12, 4, -17, + -28, -24, -3, 14, 4, -19, -18, -9, 11, 22, 16, -13, -23, -15, 18, 32, + 32, 17, -4, 1, 14, 11, 1, -20, -19, -3, 9, 13, -4, -13, -16, -18, + -23, -12, -17, -16, -20, -15, -14, -4, 8, 12, 0, 8, 5, 12, 17, 26, + 25, 14, 10, 11, 11, 18, 15, 4, -9, -13, -8, -9, -14, -20, -28, -32, + -12, -9, -16, -17, -24, -18, -12, 5, 10, 4, 6, 8, 18, 35, 31, 17, + 1, 12, 21, 33, 18, 6, -10, -11, -4, -9, -13, -19, -24, -24, -24, -18, + -20, -18, -20, -13, -15, -10, -9, -5, 8, 10, 13, 23, 26, 29, 14, 13, + 13, 13, 16, 25, 19, 17, 4, -15, -18, -15, -14, -17, -34, -23, -16, -12, + -16, -26, -33, -23, -15, -4, 4, 10, 16, 19, 22, 29, 28, 7, 1, 2, + 18, 26, 30, 21, 9, 3, -4, -10, -16, -29, -31, -27, -4, -9, -11, -28, + -23, -17, -15, -13, -11, 4, 11, 9, 13, 16, 25, 18, 8, 10, 18, 17, + 8, 18, 17, 11, -5, -19, -17, -12, -19, -38, -27, -8, 0, -3, -14, -19, + -20, -14, -10, -13, -3, 6, 12, 26, 38, 34, 14, 2, -2, 11, 19, 14, + 8, 5, 16, 9, -7, -19, -24, -29, -36, -26, -13, -12, -22, -28, -20, 5, + -3, -10, -19, 7, 20, 18, 17, 24, 25, 14, 18, 19, 29, 21, 11, 10, + 9, 13, -13, -29, -27, -20, -24, -30, -22, -12, -7, -15, -22, -21, -13, -14, + -20, -8, 12, 26, 25, 21, 33, 27, 25, 16, 13, 16, 16, -2, 2, 11, + 9, -2, -17, -18, -16, -25, -25, -26, -27, -30, -35, -30, -12, -6, -6, -6, + -5, 19, 19, 11, 15, 17, 24, 23, 34, 28, 23, 13, 2, 9, 18, 16, + -14, -18, -12, -7, -9, -31, -37, -33, -24, -14, -24, -20, -16, -21, -15, -7, + 5, 9, 15, 20, 28, 38, 29, 21, 15, 22, 17, 4, 12, 6, 12, -4, + -9, -15, -16, -19, -40, -38, -34, -23, -18, -17, -8, -10, -3, -7, 1, 3, + 4, 11, 13, 36, 41, 36, 24, 9, 17, 20, 21, 14, -5, -9, -11, -8, + -19, -14, -24, -30, -23, -18, -25, -30, -24, -17, -20, -9, -3, 6, 8, 22, + 23, 20, 27, 18, 10, 10, 14, 18, 14, 23, 17, 6, 5, -4, -8, -26, + -19, -24, -25, -24, -21, -27, -28, -15, -19, -16, -9, 0, 7, 9, 17, 14, + 15, 24, 30, 29, 29, 32, 16, 10, 8, 0, -3, -10, -7, -17, -22, -25, + -30, -36, -32, -25, -26, -22, -12, -16, -11, -3, 5, 7, 13, 21, 21, 26, + 32, 28, 26, 28, 31, 17, 15, 15, 5, -4, -14, -18, -28, -25, -24, -28, + -32, -33, -32, -29, -18, -17, -20, -10, -4, 6, 6, 18, 22, 22, 37, 38, + 31, 27, 26, 23, 22, 23, 12, 4, -5, -2, -11, -19, -25, -35, -35, -36, + -36, -43, -32, -24, -20, -12, -7, -3, -7, 3, 13, 23, 29, 35, 37, 35, + 42, 33, 26, 22, 17, 12, 6, 4, -9, -23, -28, -34, -34, -33, -31, -40, + -36, -27, -25, -22, -30, -20, -11, 2, 12, 22, 22, 26, 28, 35, 47, 44, + 27, 29, 29, 29, 19, 2, 1, -9, -15, -21, -34, -35, -34, -40, -44, -42, + -34, -31, -26, -21, -9, -12, -3, 10, 17, 29, 26, 27, 34, 48, 50, 34, + 33, 25, 21, 16, 8, 3, -8, -11, -25, -30, -37, -37, -42, -51, -34, -28, + -21, -26, -25, -19, -13, 4, 9, 17, 29, 41, 33, 33, 44, 45, 32, 31, + 28, 22, 16, 5, -10, -13, -16, -23, -38, -39, -39, -45, -54, -40, -32, -24, + -22, -17, -14, 0, 6, 9, 18, 41, 43, 34, 32, 40, 40, 31, 30, 27, + 22, 19, 14, -2, -16, -21, -34, -48, -45, -41, -41, -41, -45, -38, -25, -21, + -17, -20, -7, 11, 17, 19, 36, 40, 42, 44, 47, 46, 39, 33, 26, 15, + 11, 8, -5, -19, -24, -29, -40, -44, -48, -44, -37, -37, -43, -43, -26, -19, + -14, -2, 13, 23, 31, 36, 36, 43, 41, 47, 46, 44, 40, 24, 15, 14, + 3, -12, -21, -23, -30, -36, -47, -51, -50, -47, -44, -46, -31, -19, -16, -11, + 2, 16, 20, 25, 29, 40, 53, 51, 49, 45, 41, 35, 25, 18, 7, 5, + -12, -18, -23, -34, -39, -56, -58, -54, -49, -50, -45, -35, -26, -12, -5, 6, + 17, 29, 41, 42, 47, 50, 46, 49, 50, 50, 39, 30, 16, 2, -8, -15, + -21, -30, -41, -49, -50, -46, -57, -63, -57, -41, -29, -24, -12, -3, 5, 12, + 22, 33, 41, 50, 51, 53, 57, 55, 46, 36, 29, 16, 2, -4, -11, -21, + -33, -40, -49, -47, -53, -60, -58, -51, -42, -34, -23, -13, -2, 5, 17, 27, + 39, 49, 48, 51, 56, 54, 58, 44, 37, 28, 18, 4, -3, -15, -29, -39, + -49, -49, -51, -62, -65, -64, -47, -42, -36, -26, -14, -5, 10, 24, 32, 45, + 50, 49, 62, 65, 63, 47, 42, 41, 36, 23, 7, -7, -22, -31, -41, -53, + -58, -62, -59, -62, -56, -54, -50, -44, -32, -16, 0, 11, 25, 35, 50, 54, + 55, 56, 66, 65, 62, 54, 45, 36, 23, 14, -4, -22, -44, -55, -52, -62, + -61, -66, -70, -68, -60, -54, -45, -29, -15, 4, 21, 34, 36, 44, 54, 62, + 70, 73, 68, 67, 59, 50, 37, 21, -5, -12, -25, -39, -48, -53, -63, -76, + -73, -71, -71, -67, -57, -45, -29, -12, 2, 13, 30, 42, 51, 61, 76, 71, + 63, 66, 71, 60, 50, 40, 23, -2, -9, -20, -41, -54, -59, -72, -79, -71, + -64, -73, -68, -60, -51, -36, -13, 2, 13, 27, 47, 54, 71, 78, 71, 60, + 72, 74, 65, 54, 39, 28, 7, -6, -23, -50, -59, -64, -69, -75, -70, -78, + -74, -73, -64, -52, -37, -13, 6, 18, 40, 51, 58, 64, 78, 79, 75, 68, + 64, 68, 57, 45, 21, 4, -16, -34, -50, -65, -75, -83, -80, -71, -69, -68, + -73, -63, -57, -36, -16, 6, 26, 45, 60, 70, 71, 79, 79, 81, 78, 80, + 64, 55, 36, 16, -4, -23, -38, -54, -63, -69, -81, -85, -87, -76, -72, -66, + -61, -52, -30, -12, 12, 24, 44, 55, 69, 78, 85, 84, 74, 70, 71, 71, + 62, 41, 17, -11, -25, -42, -55, -66, -75, -87, -87, -81, -74, -76, -76, -63, + -48, -32, -13, 7, 30, 51, 64, 76, 80, 82, 83, 81, 80, 82, 70, 61, + 42, 19, 0, -28, -49, -61, -72, -78, -87, -90, -89, -88, -87, -82, -69, -54, + -33, -13, 15, 36, 58, 68, 79, 90, 96, 90, 84, 86, 89, 79, 62, 38, + 22, -3, -29, -55, -69, -81, -89, -94, -94, -94, -94, -89, -74, -62, -52, -35, + -18, 14, 39, 54, 65, 76, 87, 98, 95, 94, 90, 82, 75, 69, 47, 26, + -6, -33, -57, -72, -82, -88, -97, -90, -91, -88, -83, -80, -75, -59, -33, -9, + 20, 42, 58, 68, 82, 90, 94, 93, 94, 88, 85, 77, 65, 43, 16, -10, + -37, -60, -71, -84, -89, -95, -97, -102, -95, -84, -80, -72, -57, -26, -4, 19, + 42, 62, 80, 89, 94, 97, 100, 99, 90, 83, 71, 65, 39, 14, -9, -43, + -65, -83, -90, -95, -98, -96, -100, -96, -88, -76, -66, -51, -24, -12, 21, 45, + 70, 85, 93, 95, 97, 101, 105, 92, 84, 69, 58, 35, 16, -14, -44, -68, + -86, -88, -96, -101, -101, -102, -97, -90, -74, -69, -50, -19, 9, 35, 56, 76, + 84, 92, 98, 96, 99, 97, 93, 84, 77, 59, 24, 2, -30, -52, -76, -87, + -93, -98, -100, -102, -100, -96, -89, -81, -73, -46, -18, 12, 36, 62, 82, 88, + 96, 104, 107, 105, 102, 92, 84, 77, 53, 26, -6, -35, -57, -75, -81, -92, + -103, -114, -111, -108, -98, -88, -83, -67, -35, -7, 20, 39, 60, 70, 89, 106, + 116, 107, 103, 99, 86, 90, 82, 53, 18, -13, -31, -52, -73, -92, -102, -106, + -104, -97, -106, -99, -101, -92, -72, -42, -5, 16, 38, 66, 86, 101, 99, 101, + 95, 112, 107, 99, 95, 81, 53, 16, -3, -29, -60, -81, -102, -98, -102, -102, + -112, -114, -101, -104, -88, -69, -34, -8, 14, 41, 67, 92, 94, 99, 103, 104, + 115, 109, 103, 90, 78, 52, 22, 0, -39, -65, -92, -95, -91, -103, -104, -118, + -110, -102, -93, -84, -71, -36, -15, 19, 52, 81, 94, 89, 98, 103, 115, 117, + 102, 92, 83, 80, 49, 23, -11, -43, -67, -90, -93, -102, -105, -110, -118, -104, + -100, -89, -83, -64, -36, -7, 28, 50, 74, 88, 95, 104, 103, 115, 107, 106, + 97, 87, 74, 50, 20, -17, -47, -75, -89, -93, -101, -102, -115, -117, -106, -97, + -88, -90, -73, -38, 2, 36, 60, 75, 84, 96, 104, 115, 115, 102, 98, 96, + 96, 84, 52, 10, -12, -32, -53, -71, -87, -101, -109, -112, -109, -106, -105, -102, + -92, -74, -48, -19, 7, 33, 56, 76, 91, 101, 108, 111, 111, 108, 103, 96, + 85, 63, 33, 1, -27, -51, -73, -90, -102, -109, -112, -110, -107, -103, -100, -93, + -76, -50, -19, 10, 36, 58, 76, 91, 101, 108, 111, 111, 108, 103, 96, 85, + 63, 33, 1, -27, -51, -73, -90, -102, -109, -112, -110, -107, -103, -100, -93, -76, + -50, -19, 10, 36, 58, 76, -1, -2, -15, 21, -17, 23, -30, 1, 34, -34, + 6, 5, -15, 19, 1, -25, 6, 20, -2, -28, 15, 10, -15, 0, -7, 10, + 7, -5, -9, -6, 19, -3, -21, 3, 20, -4, -20, 1, 16, -3, -8, -2, + 5, 1, -8, -6, 3, 9, 2, -13, -4, 15, -7, -9, 0, 3, 6, -7, + -7, 5, 8, -8, -4, 0, 1, 1, -6, -4, 7, 2, -2, -7, 0, 4, + -3, -4, 0, 2, 0, -2, -4, 1, 4, -2, -4, -3, 1, 3, -5, -4, + 4, 3, -6, -5, 4, -1, -2, -3, 0, 3, -3, -1, -4, 3, 3, -5, + -3, 1, 1, -2, -3, 1, 2, -2, -4, 0, 0, 0, -1, -3, 1, 1, + -3, -2, 1, 0, -2, -2, 0, 0, -2, -1, 0, -1, 1, -2, -2, 1, + 0, -2, 0, -1, 0, -1, -1, -1, 0, 0, -1, -3, 1, 1, -2, -2, + 0, 1, -1, -2, -1, 0, 0, 0, -2, -1, 1, 0, -3, 0, 2, -1, + -2, 0, 0, 0, -2, 0, -1, 0, -1, -1, 1, 0, -1, 0, -1, 1, + 0, -13, 5, 7, -11, 24, -50, 41, 4, -29, 14, -11, 8, 11, -15, -12, + 15, 18, -21, -14, 22, -2, -11, -3, -3, 18, -3, -5, -14, 9, 22, -24, + -16, 23, 12, -23, -8, 9, 10, -4, -8, -3, 11, -4, -14, 0, 8, 8, + -5, -14, 8, 10, -12, -4, -2, 10, 0, -11, -3, 11, 0, -7, -2, -1, + 7, -6, -8, 3, 6, 0, -3, -8, 7, 2, -7, -2, 2, 1, -2, -4, + -1, 3, 3, -4, -5, 1, 3, -3, -6, 2, 5, -1, -7, -1, 3, -1, + -4, -3, 5, 0, -3, -2, -1, 4, -1, -5, -1, 3, -1, -4, -1, 3, + 1, -4, -2, 1, 0, -2, -3, 0, 2, -1, -4, 1, 1, -1, -2, -2, + 1, -1, -3, 0, 0, 0, -1, -2, 0, 0, -2, -1, 0, -1, 0, -2, + -1, 0, -1, 0, -1, -2, 2, -1, -2, -1, 0, 1, -2, 0, -1, -1, + 0, -1, -2, 0, 1, -1, -3, 0, 1, -1, -3, 0, 1, -2, -1, 0, + 0, -1, -1, 0, -1, -1, -1, -1, 0, 0, -1, -1, 0, 0, -2, 0, + 0, 0, 0, -2, 1, -1, 0, -1, 0, 0, 0, -1, 0, 0, 0, 0, + -1, 0, 0, -1, 0, -1, 1, 0, 0, 0, 1, -1, -1, 0, 0, 0, + 1, -2, 4, -3, 3, -40, 71, -73, 67, -27, -68, 127, -80, 3, 5, 1, + 17, -14, 1, -30, 53, -3, -42, 15, 19, -9, -17, -1, 13, 16, -17, 4, + -32, 43, 15, -68, 18, 54, -38, -7, -1, 11, 7, -3, -18, 5, 25, -27, + -9, 9, 19, -6, -12, -8, 20, -1, -15, -1, 1, 17, -10, -16, 12, 12, + -13, 0, -6, 10, 2, -16, -1, 14, -4, 4, -11, -2, 12, -6, -8, 4, + 4, -2, -4, 1, -2, 4, 3, -7, -5, 8, 0, -10, 1, 4, 2, -4, + -6, 4, 1, -1, -7, 1, 8, -9, 2, -5, 3, 3, -4, -3, 0, 3, + -3, -5, 4, 3, -3, -4, 0, 2, 0, -3, -4, 5, 0, -5, -1, 2, + 0, -3, 0, -1, 2, -2, -4, 3, 0, -1, -2, -1, 2, -2, -2, 1, + -1, 0, -1, -3, 1, 1, -2, 1, -3, 1, 1, -3, -1, 1, 0, -1, + -2, 1, -1, -1, 1, -2, 1, -1, -1, -1, -1, 0, 1, -3, 0, 0, + 1, -4, 0, 1, -2, 0, -2, 0, 0, 0, -2, 1, -1, 0, -2, 0, + 2, -2, -1, 0, -1, 2, -2, -1, 1, -2, 0, -1, 1, -1, -1, -1, + 1, -2, 1, -1, -1, 2, -3, 0, 0, -1, 1, -1, 0, 1, 0, -2, + 0, -1, 1, -2, 0, 0, -1, 1, 0, -2, 0, 1, -2, 1, 0, 0, + -1, 0, 1, -1, -1, -1, 1, 1, -1, 0, 0, 0, -1, 1, 0, -1, + 1, 0, 0, 1, 0, -1, 1, 0, 3, -40, 58, -39, 12, 42, -117, 108, + 1, -66, 22, 17, 0, -9, 10, -39, 42, 4, -23, -12, 28, 3, -34, 9, + 17, 3, -9, 10, -29, 13, 53, -79, 3, 64, -26, -24, 16, -9, 14, 2, + -8, -15, 31, -9, -30, 11, 29, -15, -7, 0, 3, 6, -4, -9, -6, 22, + 1, -24, 9, 11, -8, 0, -2, 2, 8, -12, -6, 10, 2, 2, -9, -4, + 11, -2, -10, 3, 2, 3, -5, -1, 1, -1, 6, -4, -8, 9, 2, -8, + -3, 6, 3, -4, -3, -1, 6, -2, -8, 0, 9, -4, -3, -2, 2, 4, + -4, -1, -1, 4, -2, -6, 4, 2, -1, -4, 0, 1, 2, -3, -5, 3, + 3, -3, -4, 3, 0, -1, 0, -2, 2, 0, -3, 0, 3, 0, -3, -1, + 2, 0, -3, 1, 0, -1, 2, -2, -2, 2, -1, 0, -1, -1, 1, -1, + -2, 0, 0, 1, -3, 1, 0, -1, 1, -2, -1, 2, -2, -1, 0, -1, + 2, -3, -1, 1, 1, -2, -2, 2, 1, -2, -1, 0, 0, 1, -3, 1, + 0, 0, 0, -2, 3, 0, -2, 0, 0, 1, 0, -1, 1, -2, 0, 0, + 0, -1, 1, 0, 0, 0, -1, 1, -1, 1, 0, -1, 1, -2, 0, 1, + 1, 0, 1, -2, 1, 0, 1, 0, 0, 3, -1, 0, 1, 0, 0, 3, + -29, 35, -12, -16, 56, -88, 39, 62, -79, 5, 29, 1, -13, 12, -29, 26, + 17, -28, -3, 12, 5, -11, -19, 28, 1, -5, 9, -21, -7, 60, -56, -20, + 57, -10, -27, 21, -21, 16, 12, -12, -21, 24, 6, -29, 4, 19, 2, -7, + -5, -3, 7, 6, -11, -9, 11, 13, -18, -4, 13, 1, -3, -6, -1, 10, + -8, -6, 5, 3, 5, -3, -11, 4, 9, -11, 0, 4, 3, -4, -1, 0, + 0, 7, 0, -14, 7, 5, -7, -4, 4, 5, -1, -4, -4, 4, 1, -4, + -4, 7, -1, -1, -3, 0, 5, -1, -4, -1, 2, 0, -3, 1, 1, 2, + -2, -4, 1, 2, 0, -5, 2, 3, -2, -2, 1, 1, -2, 2, -3, 0, + 0, -1, -1, 0, 1, 0, -3, 0, 0, -1, 1, -1, -2, 1, -1, 0, + -2, 2, 1, -2, -1, 1, 0, -1, -1, 0, 1, -1, 0, -2, 1, 1, + -1, 0, -1, -1, 0, 0, -1, -1, 0, -1, -1, 2, -2, -1, 1, 0, + 0, -1, -1, 1, 0, -1, 1, -1, 0, 1, -3, 1, 1, -1, -1, 0, + 1, 0, 0, 0, -1, 0, 0, -1, 0, 1, 0, 0, 2, -2, 0, 1, + 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, -1, -1, -7, -9, 35, -52, + 59, -33, -32, 64, -15, -41, 19, 22, -20, 9, -11, -3, 33, -27, 2, 7, + -9, 19, -37, 24, 7, -11, 11, -1, -30, 37, 8, -57, 36, 19, -33, 14, + 0, -17, 26, 1, -20, -5, 26, -18, -13, 14, 7, -6, 4, -9, -4, 11, + 3, -14, -7, 20, 0, -18, 10, 1, 4, -5, -7, 6, 0, -3, -2, -2, + 8, 5, -11, -6, 10, -1, -10, 6, -2, -1, 1, -3, 0, 3, 5, -9, + -5, 9, -3, -4, 1, 1, 3, -1, -4, -1, 2, -2, -5, 5, -3, 0, + 1, -5, 4, 2, -3, -3, 0, 0, -2, 1, 0, -2, 3, -2, -5, 2, + 2, -2, -4, 3, 0, -2, 1, -2, -2, 5, -2, -6, 1, 2, -1, -1, + 0, 1, -1, -2, -1, -1, 2, 0, -4, 0, 1, 0, -3, 0, 2, 0, + -3, 0, 0, 1, -1, -1, 1, 0, -1, -2, 1, 0, 0, -1, 0, -2, + 1, 0, -1, 1, -1, 0, -2, 1, 1, -2, -1, 2, -2, 1, -3, 1, + 1, -1, 0, 0, -1, 1, 0, -2, 2, -1, -1, 0, 0, 1, 0, 1, + 0, -2, 1, 0, 0, -1, 1, 0, 0, 0, 0, -3, -20, 45, -56, 40, + -5, -34, 27, 24, -42, -1, 29, -14, -4, 2, -7, 24, -20, -1, 18, -25, + 25, -29, 9, 21, -26, 14, 4, -20, 7, 27, -42, 5, 31, -24, -2, 19, + -30, 21, 8, -11, -17, 20, 1, -22, 11, 7, -7, 6, -5, -7, 3, 11, + -6, -18, 11, 16, -20, 1, 5, 2, -3, -3, 0, -3, 4, -1, -7, 2, + 10, -9, -8, 7, 2, -9, 5, -1, -5, 2, 1, -3, -2, 9, -5, -8, + 4, 1, -5, 0, 1, 2, -1, 0, -5, 4, -1, -5, 4, -3, 1, 1, + -5, 3, 0, 0, -3, 0, -1, -2, 1, 2, -5, 2, 1, -5, -2, 3, + -1, -5, 2, 1, -4, 2, -1, -4, 2, 3, -7, -1, 2, 0, -2, 1, + 0, -2, -1, 0, -3, 1, 2, -3, -2, 3, 0, -3, -1, 1, 0, -1, + -2, -1, 1, 0, 0, -1, 0, 0, -2, 0, 0, 1, -2, 2, -3, 1, + 0, 0, -2, 1, 0, -1, 0, 0, -1, -1, 2, -3, 0, 0, -1, 0, + 0, -1, 1, 0, -4, -13, 32, -41, 31, -10, -10, 4, 22, -25, -8, 21, + -3, -14, 5, 1, 12, -23, 8, 18, -31, 25, -26, 10, 17, -23, 8, 5, + -9, 0, 16, -25, 2, 23, -22, -2, 22, -30, 15, 7, -6, -13, 12, 1, + -17, 9, 5, -6, 4, -3, -7, 5, 7, -6, -13, 7, 10, -11, 0, 0, + 4, -3, -3, 2, -7, 4, 2, -5, 0, 6, -3, -8, 4, 2, -8, 7, + 0, -8, -1, 6, 0, -8, 6, 0, -5, 1, 0, -5, 3, 2, -3, -2, + 4, -5, -1, -1, -2, 3, -4, 1, -1, -3, 3, -1, -2, -2, 1, -2, + -2, 1, 1, -4, 1, 2, -5, -3, 5, -3, -4, 4, -1, -4, 2, -1, + -4, 3, 1, -5, -2, 2, 0, -2, 2, -1, -4, 3, -1, -3, 0, 1, + -2, -2, 1, -1, -1, -1, 0, 0, -1, -1, -1, 0, -1, 1, -1, -1, + 0, -2, 1, 0, -1, -1, 0, -1, -1, -1, 2, -2, -1, 1, -1, -2, + 1, -1, -1, 1, -2, 1, -7, -3, 15, -23, 20, -16, 9, -12, 16, -12, + -8, 11, 5, -18, 6, 8, 0, -18, 16, 4, -19, 16, -17, 10, 5, -8, + -2, 9, -5, -4, 10, -17, 5, 13, -18, 2, 12, -17, 10, 0, -2, -8, + 7, -4, -7, 6, 1, -3, 1, 3, -9, -2, 10, -7, -8, 4, 6, -6, + 1, 0, 0, -2, 1, -1, -8, 6, 1, -5, 2, 4, -2, -4, 1, 1, + -7, 5, -1, -4, -2, 4, 0, -4, 4, -3, -4, 1, 0, -3, 0, 2, + -1, -2, 2, -2, -1, -3, 0, 3, -4, 3, -3, 0, 2, 0, -3, -1, + 1, -3, -1, 2, 0, -1, 0, 0, -3, 0, 1, -4, -1, 2, 0, -2, + 0, 1, -3, 1, 1, -3, -2, 2, -1, -1, 2, -1, -2, 1, 0, -1, + -1, -1, -3, -8, -16, -20, -7, 14, 20, 19, 18, 16, 11, 3, -9, -21, + -36, -43, -39, -24, 6, 38, 57, 55, 26, 0, -7, -10, -13, -12, -11, -29, + -56, -59, -37, 0, 43, 74, 87, 75, 37, -2, -31, -51, -59, -45, -15, -16, + -34, -20, -10, -5, 29, 61, 72, 51, 18, -2, -21, -39, -35, -24, 1, 0, + -31, -29, -23, -44, -13, 48, 82, 79, 46, 16, -4, -44, -58, -26, 3, 6, + -38, -52, -24, -42, -35, 47, 95, 88, 55, 19, 12, -22, -72, -38, 4, 3, + -31, -67, -29, -24, -60, 23, 112, 111, 72, 22, 7, -20, -90, -73, -1, 19, + -4, -57, -36, 3, -54, -32, 98, 125, 71, 14, 14, 0, -82, -106, 0, 42, + 10, -48, -32, -2, -54, -63, 72, 125, 82, 24, 14, -8, -57, -104, -22, 52, + 34, -34, -46, -16, -35, -83, 32, 127, 99, 26, 19, 4, -55, -110, -48, 45, + 36, -12, -26, -22, -41, -64, -7, 107, 113, 56, 6, 4, -41, -92, -74, 35, + 57, 12, -41, -21, -39, -67, -40, 86, 114, 71, 10, 22, -31, -83, -83, 16, + 46, 34, -28, -18, -42, -58, -60, 55, 108, 97, 3, 21, -8, -77, -102, 10, + 45, 42, -26, -2, -27, -68, -73, 45, 83, 92, 29, 25, -8, -56, -104, -13, + 35, 52, -6, -7, -22, -46, -91, 10, 80, 95, 35, 26, 8, -38, -106, -34, + 34, 42, 5, 1, -23, -39, -73, -28, 61, 89, 60, 20, 2, -7, -73, -86, + 24, 52, 26, -12, -11, -19, -58, -86, 46, 91, 62, 17, 22, -15, -39, -106, + 8, 55, 45, -13, -6, -30, -21, -102, 4, 82, 87, 7, 28, -3, -9, -115, + -32, 50, 63, -23, 8, -19, -18, -94, -28, 61, 96, 14, 39, -4, 1, -85, + -60, 23, 79, -3, 2, -20, -10, -82, -65, 25, 108, 28, 31, 19, 9, -65, + -74, -5, 78, 16, -3, -9, -14, -65, -76, -3, 93, 60, 29, 22, 13, -43, + -90, -30, 61, 49, -9, -1, 4, -52, -98, -16, 68, 72, 21, 38, 15, -31, + -94, -34, 32, 67, 5, 9, 0, -28, -111, -33, 40, 85, 24, 37, 23, -6, + -104, -44, 13, 69, 9, 14, 8, -11, -110, -53, 20, 80, 32, 48, 30, 5, + -87, -66, -7, 63, 33, 12, 2, 5, -86, -94, -2, 79, 46, 26, 44, 22, + -59, -88, -19, 54, 48, 13, 14, 4, -51, -112, -37, 67, 71, 21, 38, 29, + -29, -104, -50, 44, 63, 11, 10, 14, -24, -103, -67, 49, 88, 20, 27, 43, + -10, -90, -79, 24, 69, 21, 7, 18, -8, -82, -103, 17, 94, 38, 10, 54, + 12, -70, -97, 1, 68, 37, -4, 27, -6, -56, -104, -21, 82, 67, -3, 46, + 23, -37, -108, -31, 57, 58, -13, 29, 11, -32, -106, -50, 53, 92, -6, 38, + 38, -15, -105, -54, 34, 79, -12, 20, 22, -11, -98, -70, 22, 99, 4, 16, + 48, 14, -99, -75, 15, 82, 2, 0, 44, 8, -93, -80, 0, 84, 29, -3, + 57, 32, -79, -94, 1, 66, 27, -19, 49, 29, -73, -109, -7, 54, 52, -17, + 62, 53, -46, -113, -4, 43, 51, -30, 46, 37, -42, -128, -23, 26, 69, -18, + 51, 59, -2, -122, -30, 24, 66, -27, 31, 51, 1, -128, -48, 13, 71, -11, + 33, 66, 22, -110, -57, 8, 68, -9, 12, 53, 28, -104, -87, -4, 67, 8, + 8, 72, 53, -80, -91, -4, 59, 10, -13, 63, 44, -81, -109, -19, 46, 33, + -6, 76, 57, -43, -104, -24, 36, 42, -26, 55, 51, -34, -126, -39, 19, 58, + -21, 68, 71, -8, -114, -32, 2, 62, -24, 52, 54, -4, -120, -53, -22, 71, + -8, 49, 62, 31, -102, -52, -25, 70, -5, 24, 55, 35, -109, -69, -40, 59, + 16, 25, 65, 55, -80, -70, -37, 47, 23, 7, 48, 51, -73, -97, -48, 30, + 46, 6, 57, 74, -37, -98, -34, 21, 48, -10, 44, 58, -34, -123, -46, -2, + 61, 2, 50, 69, 10, -110, -40, -5, 59, -9, 31, 53, 19, -126, -59, -20, + 62, 8, 32, 64, 49, -105, -59, -16, 58, 2, 17, 50, 45, -102, -83, -31, + 46, 24, 15, 53, 69, -65, -86, -24, 42, 25, -4, 45, 64, -58, -112, -37, + 30, 41, -6, 51, 75, -24, -105, -32, 26, 41, -19, 39, 62, -14, -117, -51, + 7, 54, -13, 35, 78, 19, -105, -47, 9, 58, -19, 21, 69, 18, -113, -66, + -10, 52, -10, 14, 75, 42, -83, -60, -5, 52, 0, -3, 69, 43, -83, -83, + -21, 35, 17, -13, 72, 57, -54, -82, -10, 29, 28, -29, 65, 52, -45, -98, + -21, 1, 40, -30, 64, 63, -7, -94, -9, 1, 51, -36, 51, 54, -8, -115, + -23, -22, 47, -30, 48, 65, 24, -90, -13, -15, 46, -26, 30, 55, 21, -100, + -37, -26, 31, -10, 24, 65, 41, -71, -35, -10, 25, -2, 4, 58, 32, -69, + -61, -16, 2, 8, 1, 67, 42, -33, -56, -1, -1, 20, -13, 59, 33, -28, + -82, -10, -20, 22, -15, 64, 40, -1, -70, 0, -17, 29, -22, 53, 33, 1, + -84, -15, -29, 22, -19, 53, 43, 22, -64, -7, -19, 25, -18, 37, 38, 16, + -73, -30, -33, 11, -14, 32, 50, 31, -45, -17, -15, 16, -4, 16, 43, 23, + -49, -43, -30, -2, -1, 8, 52, 36, -25, -32, -13, -1, 11, -1, 42, 30, + -25, -49, -25, -18, 10, -7, 44, 40, -2, -34, -11, -15, 21, -6, 29, 33, + -5, -54, -29, -30, 13, -6, 29, 46, 15, -32, -10, -18, 16, -1, 13, 36, + 9, -45, -30, -32, 0, 1, 12, 43, 28, -23, -16, -16, 6, 9, 2, 33, + 22, -33, -34, -27, -11, 2, 1, 35, 36, -14, -16, -11, -5, 8, 3, 24, + 32, -19, -30, -29, -17, -4, 1, 20, 43, -5, -14, -13, -4, 0, 7, 11, + 39, -9, -23, -28, -17, -16, 1, 9, 44, 3, -7, -15, -4, -4, 7, 5, + 38, 3, -20, -30, -19, -19, -8, 0, 40, 17, -6, -7, -3, -2, -1, 4, + 32, 16, -20, -21, -26, -17, -18, -3, 28, 32, -7, -1, -9, 4, -9, 3, + 22, 34, -19, -14, -27, -13, -27, -10, 16, 44, -8, 5, -6, 3, -12, 1, + 13, 40, -12, -11, -25, -17, -27, -15, 5, 45, 4, 2, 0, 0, -9, -5, + 6, 38, 2, -17, -14, -20, -24, -23, 0, 38, 19, -4, 11, -4, -7, -10, + 4, 27, 20, -20, -9, -23, -22, -30, -6, 26, 35, -8, 12, 2, -4, -15, + 2, 20, 32, -16, -7, -15, -22, -37, -14, 18, 39, -3, 5, 8, -5, -18, + -2, 18, 34, -4, -14, -4, -21, -35, -25, 15, 36, 8, -4, 21, -5, -17, + -14, 23, 26, 9, -22, 4, -25, -32, -40, 14, 27, 24, -12, 30, 1, -8, + -26, 24, 21, 19, -28, 9, -20, -28, -51, 7, 23, 30, -15, 27, 9, -7, + -32, 16, 25, 23, -21, 4, -8, -27, -50, -10, 25, 29, -9, 13, 24, -7, + -28, -3, 34, 20, -12, -9, 10, -31, -43, -29, 30, 23, 2, -3, 38, -9, + -19, -19, 39, 18, -1, -20, 25, -29, -36, -42, 26, 17, 12, -14, 43, -3, + -15, -29, 35, 19, 6, -28, 27, -18, -36, -48, 16, 17, 15, -15, 39, 12, + -13, -29, 24, 24, 9, -25, 19, -1, -39, -50, 1, 18, 11, -11, 25, 26, + -14, -26, 12, 32, 10, -17, 6, 17, -33, -48, -14, 20, 6, -7, 11, 36, + -9, -26, -1, 34, 11, -9, -4, 25, -25, -49, -26, 19, 4, -4, 5, 41, + 3, -21, -8, 31, 12, -7, -11, 23, -13, -47, -37, 13, 6, -3, 1, 40, + 14, -17, -14, 26, 16, -2, -12, 20, -3, -40, -44, 2, 6, -2, -4, 35, + 24, -9, -19, 19, 17, 2, -13, 16, 5, -29, -48, -7, 4, 3, -7, 28, + 28, 2, -21, 13, 14, 9, -14, 11, 9, -15, -49, -17, -3, 6, -11, 20, + 30, 14, -23, 7, 12, 14, -11, 6, 10, -4, -46, -24, -10, 6, -8, 11, + 29, 24, -15, 0, 11, 14, -4, -2, 11, 3, -37, -36, -13, -3, -2, 2, + 28, 27, -2, -10, 14, 9, 7, -8, 13, 3, -21, -42, -14, -14, 4, -6, + 24, 24, 13, -16, 12, 3, 14, -8, 12, 4, -7, -44, -18, -20, 5, -6, + 18, 22, 23, -13, 6, 2, 13, -4, 5, 5, 1, -36, -26, -20, -1, -1, + 10, 23, 25, -3, -4, 5, 9, 5, -2, 8, 1, -24, -36, -18, -10, 4, + 1, 24, 23, 11, -9, 8, 4, 12, -7, 9, 1, -12, -40, -19, -16, 4, + -4, 21, 21, 16, -9, 6, 2, 13, -4, 6, 6, -4, -33, -24, -18, -2, + -2, 10, 21, 18, 0, -3, 3, 8, 6, -1, 8, 0, -18, -31, -19, -10, + 1, 0, 19, 20, 13, -5, 4, 5, 12, -4, 5, 2, -7, -34, -24, -17, + 1, -4, 13, 20, 21, -3, 2, 5, 14, 0, 2, 4, 0, -26, -28, -20, + -6, -4, 4, 18, 23, 6, -3, 5, 9, 7, -1, 6, 3, -14, -33, -22, + -14, -1, -1, 16, 22, 17, -4, 4, 4, 10, -2, 4, 3, -4, -30, -25, + -19, -2, -2, 11, 20, 23, 0, 0, 2, 10, 3, 1, 4, 1, -23, -30, + -22, -8, -1, 4, 19, 23, 10, -3, 4, 6, 8, -2, 5, 2, -13, -33, + -23, -15, 0, -1, 16, 21, 16, -3, 3, 4, 11, 0, 5, 6, -3, -27, + -25, -19, -4, -2, 9, 19, 19, 2, -3, 2, 8, 6, -1, 8, 0, 0, + 2, 33, 42, 58, 71, 79, 85, 88, 91, 94, 79, 95, 82, 106, 86, 105, + 47, 16, -6, 13, 44, 31, -15, -38, -36, 20, 70, 41, 48, 58, 24, -57, + -127, -119, -102, -126, -128, -111, -78, -82, -88, -87, -60, -66, -98, -104, -99, -97, + -99, -104, -101, -88, -87, -91, -61, -27, -34, -54, -55, -45, -24, -10, -5, -4, + 5, 34, 63, 101, 94, 78, 52, 51, 52, 74, 81, 77, 59, 46, 17, 7, + 39, 53, 47, 42, 66, 83, 73, 52, 28, 22, 11, 8, 11, 0, -15, -23, + -15, -14, -6, 16, 46, 62, 71, 76, 90, 102, 103, 103, 101, 100, 90, 75, + 63, 67, 49, 37, 28, 12, 5, 6, 15, 15, 8, -7, -12, -4, -10, -28, + -24, -17, -25, -50, -64, -81, -103, -116, -116, -113, -95, -72, -54, -41, -47, -65, + -65, -50, -33, -24, -7, 11, 8, -4, -13, -28, -51, -75, -90, -91, -90, -90, + -87, -88, -83, -84, -82, -81, -81, -76, -65, -71, -85, -84, -79, -83, -81, -77, + -72, -70, -65, -66, -66, -65, -66, -68, -61, -56, -51, -36, -13, -3, -5, -8, + -12, -12, 3, 16, 21, 31, 50, 69, 77, 82, 90, 102, 110, 114, 116, 117, + 118, 119, 116, 112, 109, 105, 98, 99, 103, 102, 91, 73, 64, 63, 61, 57, + 51, 40, 24, 35, 57, 75, 84, 79, 65, 37, 4, -26, -45, -57, -54, -46, + -45, -54, -67, -67, -48, -16, 15, 35, 44, 45, 44, 45, 46, 38, 23, 2, + -15, -34, -52, -60, -70, -77, -80, -79, -74, -77, -84, -86, -80, -72, -68, -72, + -80, -87, -92, -96, -101, -104, -104, -101, -93, -90, -89, -86, -85, -84, -83, -82, + -81, -79, -77, -76, -73, -71, -66, -62, -55, -39, -31, -27, -25, -31, -37, -46, + -51, -53, -54, -48, -45, -38, -20, 3, 24, 35, 39, 32, 16, 5, 3, 0, + -6, -13, -13, -11, -2, 14, 28, 40, 50, 53, 50, 55, 64, 74, 90, 105, + 108, 112, 106, 104, 109, 112, 123, 127, 127, 127, 127, 127, 127, 118, 113, 107, + 110, 114, 111, 104, 101, 101, 102, 103, 99, 99, 89, 73, 53, 35, 20, 0, + -22, -43, -63, -77, -82, -76, -65, -48, -36, -29, -24, -25, -29, -37, -40, -49, + -59, -67, -73, -76, -78, -79, -75, -73, -74, -75, -68, -52, -44, -30, -19, -9, + -6, -9, -13, -24, -33, -35, -31, -30, -35, -40, -44, -45, -51, -53, -54, -50, + -50, -47, -42, -50, -55, -54, -56, -56, -54, -54, -49, -48, -41, -32, -28, -18, + -13, -5, 6, 18, 33, 49, 60, 71, 78, 88, 95, 97, 93, 88, 91, 93, + 97, 98, 97, 94, 91, 85, 81, 72, 70, 66, 61, 60, 64, 66, 74, 83, + 92, 102, 108, 109, 107, 102, 97, 95, 91, 87, 80, 74, 67, 62, 61, 58, + 61, 61, 57, 53, 43, 35, 27, 25, 24, 20, 20, 22, 27, 34, 36, 32, + 21, 8, -3, -10, -16, -18, -16, -16, -19, -15, -11, -11, -12, -20, -34, -45, + -59, -72, -80, -89, -94, -95, -102, -111, -114, -111, -111, -108, -106, -104, -101, -98, + -93, -90, -86, -86, -83, -82, -81, -79, -76, -73, -70, -72, -78, -81, -79, -79, + -72, -60, -43, -31, -25, -27, -34, -37, -40, -42, -41, -39, -36, -34, -25, -12, + -4, 5, 12, 16, 17, 15, 13, 6, -4, -7, -8, -6, -1, 4, 7, 9, + 12, 16, 19, 19, 22, 28, 29, 28, 29, 30, 34, 40, 49, 57, 71, 78, + 85, 92, 96, 95, 89, 85, 86, 93, 99, 104, 102, 100, 94, 85, 77, 73, + 69, 66, 63, 60, 60, 59, 57, 52, 47, 41, 31, 18, 6, -3, -7, -11, + -12, -14, -18, -22, -23, -22, -24, -30, -37, -41, -44, -50, -56, -64, -67, -65, + -62, -58, -58, -58, -59, -61, -62, -66, -72, -78, -79, -77, -73, -68, -64, -61, + -56, -53, -54, -52, -52, -57, -63, -69, -70, -68, -65, -62, -59, -57, -56, -58, + -60, -61, -63, -64, -62, -61, -60, -58, -54, -49, -45, -42, -39, -36, -32, -28, + -22, -13, -7, -3, 2, 13, 28, 41, 52, 64, 71, 73, 73, 70, 64, 61, + 60, 64, 66, 65, 66, 64, 61, 60, 62, 65, 64, 66, 67, 67, 68, 66, + 64, 66, 68, 73, 76, 74, 72, 66, 58, 52, 46, 42, 38, 38, 41, 47, + 52, 52, 48, 45, 42, 40, 38, 34, 29, 27, 26, 28, 29, 28, 29, 30, + 31, 28, 24, 21, 19, 17, 14, 10, 6, 3, -4, -9, -15, -19, -26, -33, + -40, -49, -55, -60, -65, -70, -73, -72, -72, -71, -70, -71, -75, -78, -81, -83, + -86, -86, -85, -84, -82, -80, -77, -72, -69, -66, -63, -61, -61, -61, -61, -61, + -60, -58, -53, -48, -42, -36, -30, -28, -30, -32, -33, -32, -31, -28, -22, -18, + -10, -5, 0, 3, 6, 11, 16, 19, 22, 24, 26, 27, 29, 34, 40, 46, + 48, 48, 48, 45, 40, 36, 33, 31, 33, 35, 40, 48, 55, 62, 68, 73, + 76, 78, 78, 77, 79, 82, 85, 87, 87, 87, 86, 86, 86, 83, 78, 71, + 63, 55, 48, 44, 39, 36, 36, 36, 35, 32, 28, 24, 18, 13, 9, 6, + 4, 1, -2, -5, -11, -17, -20, -21, -20, -21, -24, -28, -32, -34, -33, -33, + -35, -37, -40, -43, -47, -52, -58, -63, -69, -74, -77, -80, -81, -82, -81, -80, + -77, -74, -69, -62, -54, -48, -48, -51, -54, -57, -57, -57, -56, -55, -55, -56, + -57, -56, -55, -54, -54, -54, -54, -52, -49, -45, -41, -38, -34, -31, -29, -27, + -24, -20, -17, -11, -7, -3, 0, 5, 10, 16, 22, 27, 31, 34, 38, 42, + 44, 45, 48, 50, 52, 57, 61, 64, 64, 65, 65, 63, 60, 57, 55, 55, + 58, 61, 63, 65, 67, 69, 71, 74, 77, 79, 79, 77, 74, 71, 68, 66, + 63, 60, 57, 55, 51, 46, 40, 36, 30, 25, 20, 17, 16, 17, 16, 14, + 12, 10, 7, 3, -1, -5, -11, -15, -17, -18, -18, -19, -21, -25, -29, -32, + -33, -33, -36, -39, -43, -46, -50, -53, -56, -58, -59, -60, -61, -62, -63, -65, + -66, -67, -68, -70, -72, -72, -70, -67, -63, -61, -60, -60, -58, -56, -54, -53, + -52, -52, -52, -51, -50, -49, -47, -45, -43, -40, -37, -35, -34, -32, -29, -25, + -21, -18, -14, -9, -4, 0, 4, 7, 11, 15, 18, 21, 25, 28, 33, 37, + 41, 44, 46, 47, 47, 46, 46, 45, 43, 42, 42, 43, 46, 48, 49, 50, + 52, 55, 59, 62, 65, 66, 67, 68, 69, 69, 70, 72, 74, 74, 73, 72, + 71, 69, 65, 61, 57, 53, 50, 46, 43, 38, 35, 32, 28, 23, 19, 17, + 17, 15, 13, 11, 9, 5, 1, -3, -6, -9, -12, -14, -17, -19, -23, -27, + -31, -35, -38, -40, -43, -46, -48, -52, -55, -57, -61, -64, -66, -67, -68, -69, + -70, -70, -70, -69, -69, -70, -71, -70, -66, -62, -59, -55, -52, -50, -46, -43, + -41, -38, -36, -35, -35, -34, -33, -33, -33, -33, -31, -30, -28, -26, -25, -24, + -21, -20, -20, -19, -19, -18, -17, -16, -15, -13, -11, -8, -3, 2, 9, 15, + 21, 27, 33, 38, 41, 45, 48, 51, 53, 55, 56, 56, 56, 56, 56, 56, + 56, 55, 57, 58, 60, 61, 62, 62, 64, 66, 68, 69, 71, 72, 73, 74, + 72, 70, 67, 63, 60, 57, 54, 50, 46, 41, 36, 31, 27, 23, 19, 16, + 14, 12, 11, 9, 8, 5, 2, -1, -4, -8, -10, -15, -18, -19, -20, -22, + -22, -23, -23, -24, -26, -29, -31, -33, -35, -36, -37, -38, -41, -44, -46, -48, + -50, -52, -54, -56, -59, -61, -63, -63, -64, -65, -64, -63, -62, -61, -60, -59, + -58, -57, -58, -57, -57, -55, -53, -50, -49, -47, -46, -43, -40, -37, -33, -31, + -28, -26, -23, -20, -16, -14, -12, -9, -5, -2, 1, 5, 9, 13, 17, 21, + 24, 26, 29, 32, 35, 37, 37, 38, 39, 41, 43, 44, 45, 46, 48, 50, + 51, 53, 52, 52, 50, 48, 47, 46, 46, 46, 46, 47, 48, 49, 51, 54, + 56, 58, 60, 61, 62, 62, 62, 61, 59, 57, 55, 54, 53, 52, 51, 49, + 46, 41, 36, 31, 27, 22, 18, 14, 11, 9, 6, 3, 0, -2, -5, -8, + -11, -16, -20, -25, -28, -31, -34, -37, -39, -41, -41, -42, -42, -42, -43, -45, + -46, -47, -49, -50, -52, -54, -56, -57, -58, -60, -61, -63, -64, -64, -64, -63, + -63, -61, -59, -58, -57, -55, -54, -53, -52, -52, -51, -50, -49, -47, -46, -45, + -44, -42, -40, -38, -35, -32, -30, -28, -25, -22, -19, -17, -15, -12, -9, -5, + -1, 3, 7, 11, 15, 19, 23, 25, 27, 30, 34, 36, 37, 38, 39, 40, + 42, 44, 45, 46, 47, 49, 50, 52, 53, 52, 51, 49, 47, 47, 46, 46, + 46, 47, 47, 48, 50, 52, 55, 57, 59, 61, 62, 62, 62, 61, 60, 58, + 56, 54, 54, 53, 51, 50, 47, 44, 39, 34, 29, 25, 20, 16, 13, 10, + 7, 4, 2, -1, -3, -6, -9, -14, -18, -22, -26, -30, -33, -35, -38, -40, + -41, -41, -42, -42, -43, -44, -46, -47, -48, -49, -51, -53, -55, -56, -57, -59, + -60, -62, -63, -64, -64, -63, -63, -62, -60, -59, -57, -56, -55, -53, -52, -52, + -51, -51, -50, -48, -46, -45, -44, -43, -41, -39, -36, -34, -31, -29, -26, -24, + -21, -16, -1, -2, -1, -3, 1, -2, -2, -4, 2, 6, 2, -2, -2, 0, + 7, 8, 4, -2, -2, 6, 5, 6, 0, -2, 5, 12, 10, 0, -5, -3, + 5, 10, 9, -7, -8, -7, 5, 8, 3, -9, -13, -5, 3, 5, -5, -9, + -4, 0, 6, 0, -4, -11, -7, 3, 4, 0, -5, 0, -1, 5, 1, 4, + -6, -5, -3, 12, 9, -2, -10, 4, 11, 8, -4, -5, -9, -6, 1, 19, + 13, -2, -22, 4, 9, 6, -26, -4, 3, 12, -9, 0, 2, 0, -15, 4, + 8, -8, -20, 0, 15, 8, -13, -2, -4, -4, -2, 12, 3, -14, -18, 1, + 21, 13, -9, -25, -8, 17, 15, 5, -14, -17, 5, 19, 13, -15, -17, -3, + 10, 20, 10, -27, -19, 5, 11, 12, 3, -13, -17, -1, 6, -3, -2, 1, + -1, -11, -17, 7, 7, -7, -7, -13, 9, 0, -5, 9, -5, -9, 6, 5, + -2, -16, -5, 15, 17, -10, -20, 1, 11, 14, -1, 1, 10, -11, -8, -1, + 18, 13, -2, -12, 1, -16, -2, 34, 27, -28, -42, -3, 42, 26, -14, -39, + -19, 7, 26, 25, -16, -55, -26, 32, 57, 4, -69, -48, 6, 75, 29, -51, + -67, -32, 51, 56, 7, -57, -75, 14, 63, 43, -29, -82, -27, 31, 56, 28, + -43, -81, -31, 59, 85, 1, -100, -59, 8, 102, 41, -42, -92, -52, 72, 79, + 29, -103, -85, -1, 117, 49, -54, -113, 7, 24, 94, -28, -39, -84, 39, 28, + 61, -44, -28, -67, 61, 23, 35, -40, -23, -37, 6, 38, 69, -42, -61, -53, + 58, 86, 2, -93, -24, 19, 72, 17, -19, -87, 45, 10, 64, -13, -45, -57, + 38, 48, 36, -51, -35, -37, 46, 26, 37, -73, -28, -12, 44, 22, 27, -84, + -22, 6, 70, 17, -24, -82, -7, 26, 79, 9, -63, -78, 6, 90, 68, -55, + -118, -3, 92, 62, -10, -73, -50, 14, 110, 15, -5, -118, 5, 69, 53, 22, + -81, -45, 29, 47, 80, -69, -28, -52, 58, 66, -1, -25, -59, -22, 107, 2, + 43, -108, -13, 20, 59, 56, -58, -66, -7, 34, 114, -42, -63, -50, 42, 69, + 44, -63, -37, -50, 114, 27, 18, -49, -81, 20, 74, 51, -14, -102, -4, 40, + 70, 38, -64, -73, 11, 60, 76, -41, -30, -78, 42, 46, 68, -63, -48, -56, + 89, 43, 28, -100, -53, 41, 60, 11, -6, -76, -16, 44, 52, 9, -67, -48, + 10, 69, 30, -1, -84, -4, 36, 72, -23, -22, -27, -33, 55, 74, -11, -86, + -1, 27, 36, 31, -7, -101, 49, 5, 66, -7, -46, -39, 9, 64, 44, -63, + -33, -22, 55, 23, 43, -79, -24, 5, 29, 54, -14, -59, -53, 63, 32, 20, + -34, -32, -36, 93, -2, 20, -35, -38, 18, 51, 61, -94, 15, -14, 17, 69, + 5, -87, 16, 28, 34, 1, 34, -57, -53, 118, -22, 34, -10, -71, 23, 70, + 25, -29, -7, -19, -3, 117, -33, -12, -21, -19, 43, 84, -38, -57, 33, 0, + 32, 41, -7, -103, 85, 2, 2, 58, -14, -103, 103, 7, -17, 34, -32, -59, + 71, 51, -78, 76, -65, -30, 63, 48, -66, 9, -11, -28, 52, 50, -72, -37, + 73, -61, 75, 7, -51, -44, 73, -3, -11, 40, -78, 7, 63, -15, -16, 30, + -53, 12, 38, 12, -42, 39, -63, 47, 23, 0, -23, -11, 8, -25, 60, -37, + -15, -3, -9, 12, 27, -14, -40, 22, 12, 14, 15, -31, -14, 15, 23, -12, + 14, -31, 19, 13, 32, -39, 27, -51, 43, 8, 0, 5, -26, 16, 4, 19, + -24, 17, -18, 6, -2, 49, -67, 39, -1, -30, 46, -13, -16, -9, 21, -17, + 27, 2, -34, 19, -3, 24, 8, -38, 13, -10, 22, 15, -34, 2, 4, -10, + 18, 14, -15, -15, 26, -12, 28, -21, 0, -6, 0, 7, 0, -15, 6, -2, + -18, 9, 8, -18, -15, 59, -94, 81, -40, -24, 14, -18, 25, -15, 4, -21, + -9, 24, -20, 3, 3, -52, 56, -29, 4, 5, -51, 45, -50, 73, -75, 13, + 17, -48, 38, -10, -16, 5, 4, -22, 3, 17, -27, -23, 42, -30, -5, 41, + -53, 10, 23, -28, 1, 29, -47, 9, 13, -3, -18, 9, -13, -11, 18, 12, + -53, 28, 1, -41, 41, 7, -61, 32, 0, -34, 16, 9, -74, 45, -23, -33, + 22, 39, -104, 49, 23, -96, 83, 5, -46, 36, -4, -45, 54, -25, -26, 21, + 2, -39, 51, -25, -25, 43, -22, -25, 30, -2, -32, 39, 14, -69, 42, 22, + -78, 60, 23, -83, 33, 44, -74, 19, 69, -113, 43, 53, -88, 51, 17, -74, + 42, 1, -38, 4, 39, -67, 12, 35, -39, -23, 73, -82, -5, 67, -71, -5, + 42, -36, -48, 78, -64, -4, 40, -48, -7, 50, -80, 17, 31, -56, 9, 6, + -18, -36, 43, -37, -29, 47, -47, -18, 33, -29, -27, 40, -30, -37, 51, -46, + -25, 61, -66, 7, 28, -48, 30, -15, -8, -6, 17, -14, -9, 26, -23, 4, + 9, -15, 12, -9, 16, -22, 7, 22, -51, 59, -29, -23, 54, -49, 6, 20, + -19, -11, 17, -3, -30, 32, -27, -5, 16, -28, 4, 4, -27, 32, -46, 27, + -18, -8, 11, -25, 18, -6, -17, 10, 1, -18, 24, -33, 10, 8, -12, -10, + 21, -19, 0, 8, -18, 14, 11, -44, 39, -22, -4, -6, 11, -15, -13, 17, + -17, -6, 13, -22, -1, 7, -5, -8, 0, 4, -24, 29, -23, 0, 20, -25, + -8, 30, -34, 31, -29, 11, -9, 21, -15, -1, 10, -9, -11, 32, -23, -2, + -14, 27, -19, 10, -4, -23, 14, 13, -45, 48, -44, 11, -4, -7, -3, 4, + -2, -34, -8, 37, -41, 20, -24, -4, -10, 2, 4, 12, -28, -30, 9, 32, + -16, 6, -46, -23, 60, 0, -22, -3, -23, -15, 48, 12, -34, -17, -18, 10, + 46, -1, -56, -8, 12, 9, 18, 13, -72, -3, 26, 9, 28, -14, -89, 15, + 67, -18, 1, -19, -52, 45, 26, -8, -5, -25, -25, 36, 38, -13, -36, -18, + -6, 55, 23, -51, -14, 4, 6, 25, 24, -41, -44, 38, 19, 10, 10, -59, + -14, 42, 1, 6, -8, -43, -1, 43, 10, -30, -10, -36, 18, 35, -20, -14, + -11, -19, 9, 20, -5, -22, -9, -6, 13, 26, -30, -23, 4, 1, 20, 9, + -20, -22, 3, -1, 17, 28, -26, -25, 16, -2, -4, 12, -10, -16, 24, -2, + -18, 17, -27, -1, 36, -6, -7, -4, -26, 6, 29, -3, -17, -6, -4, 18, + 18, -26, -10, -4, 6, 30, -1, -6, -24, 0, 24, 12, 2, -16, -25, 13, + 32, -3, -4, -3, -24, 15, 16, -7, 8, -20, -13, 36, 9, -24, -11, -10, + 10, 20, -1, -13, -10, -9, 20, 17, -12, -9, -15, 9, 20, -11, -14, -6, + 5, 10, 6, 5, -7, -11, 7, 19, 1, 3, -11, -10, 24, 14, -16, 2, + -9, 11, 14, 7, -1, -11, -4, 15, 24, 3, -24, -4, 4, 15, 13, -3, + -15, 0, 15, 8, 2, 0, -19, 16, 12, -1, 7, -13, -2, 18, 3, -3, + 5, -9, -10, 12, 9, -2, 8, -9, 4, 9, 6, 1, -8, 10, 4, -2, + 11, -14, 3, 5, 1, 9, 4, -15, 0, 10, 1, 5, -4, -10, 3, 7, + -1, 8, -13, 1, 4, 10, 6, -9, -3, 1, 6, 14, -3, -4, 4, -10, + 10, 13, -1, -4, 5, -3, 10, 13, -13, 4, 7, 1, 8, -1, 1, 4, + 5, 4, 11, -5, -2, 1, 8, 6, 1, 3, -1, -5, 11, 3, -3, 4, + -5, -1, 17, -4, -2, 6, -10, 10, 10, -4, 2, 3, -10, 10, 5, -2, + -2, -1, 4, 3, -1, -2, -4, 1, 6, -4, 6, -4, -10, 8, 2, -4, + 6, -4, -4, 12, -2, 2, 6, -9, 3, 2, 0, 7, -5, -3, 3, 2, + 4, -4, -2, 7, 3, 5, 9, -3, 1, 12, -3, 7, 6, -9, 4, 9, + -4, 12, 1, -7, 9, 2, 1, 10, -3, 1, 0, 0, 8, 0, -1, 5, + -2, 8, 1, -3, 10, 2, 0, 11, -4, -1, 6, -3, 2, 3, -5, 4, + 0, -5, 5, -3, 1, 3, 0, 4, -3, -3, 4, -2, -2, 5, -2, -1, + 6, -5, 2, 3, -4, 4, -2, -3, 11, -8, 0, 5, -1, 1, 0, -3, + 4, 2, 2, 6, -2, 4, 5, -3, 4, 7, -4, 11, -1, 0, 3, 0, + 3, 7, -2, 5, 1, 0, 6, 3, 2, 4, -1, 2, 6, 0, 3, 5, + -4, 6, 0, 2, 7, -4, -1, 2, -2, 7, 1, -1, 1, -2, 2, 4, + -5, 0, 4, -1, 2, -1, -2, 1, -2, 3, 2, -3, 3, -1, -4, 5, + -2, -2, 3, 0, -1, 2, -5, 2, 1, -4, 0, 1, -3, 5, -2, 2, + 2, -3, 1, 3, -2, 3, 1, -2, 4, 1, 2, 5, -2, 3, 1, 2, + 5, 0, -1, 4, 0, 1, 4, 2, 4, 4, -2, 0, 2, 3, 5, 0, + 0, 0, 1, 5, -2, -3, 4, 0, 1, 2, -2, -4, -4, -5, -6, -7, + -8, -9, -10, -11, -12, -13, -13, -14, -16, -18, -21, -25, -29, -34, -36, -38, + -39, -40, -42, -44, -47, -50, -53, -56, -58, -59, -58, -55, -50, -44, -38, -31, + -24, -18, -13, -9, -6, -3, 0, 3, 6, 9, 13, 17, 21, 27, 33, 42, + 53, 63, 74, 83, 91, 98, 104, 108, 111, 113, 115, 118, 119, 121, 123, 125, + 126, 127, 127, 127, 127, 126, 126, 126, 126, 127, 127, 127, 127, 127, 127, 127, + 126, 125, 123, 121, 118, 114, 111, 107, 104, 101, 100, 99, 98, 98, 98, 98, + 98, 99, 98, 98, 97, 95, 92, 88, 81, 73, 63, 54, 46, 39, 33, 29, + 27, 25, 24, 22, 20, 18, 14, 10, 5, 0, -5, -8, -8, -7, -3, 2, + 8, 14, 19, 23, 26, 28, 29, 30, 31, 32, 32, 31, 30, 28, 24, 20, + 14, 9, 4, -1, -4, -7, -9, -10, -12, -13, -15, -17, -19, -22, -24, -25, + -25, -23, -21, -19, -17, -15, -15, -14, -15, -15, -16, -17, -17, -17, -16, -16, + -16, -17, -19, -22, -25, -30, -35, -39, -44, -47, -50, -53, -56, -58, -61, -63, + -64, -65, -65, -63, -60, -55, -49, -43, -38, -34, -32, -31, -31, -32, -33, -35, + -36, -37, -37, -36, -35, -34, -34, -34, -36, -39, -43, -49, -55, -61, -67, -72, + -77, -81, -85, -88, -90, -92, -94, -94, -95, -94, -94, -94, -94, -95, -96, -98, + -100, -102, -104, -105, -107, -108, -108, -109, -110, -110, -110, -109, -109, -109, -108, -108, + -109, -109, -109, -109, -108, -108, -107, -106, -106, -105, -105, -105, -105, -105, -105, -104, + -103, -101, -98, -93, -88, -82, -76, -70, -64, -58, -52, -47, -42, -38, -34, -31, + -29, -27, -25, -22, -18, -13, -7, -1, 6, 13, 20, 26, 32, 37, 41, 45, + 48, 51, 55, 58, 63, 68, 73, 77, 82, 85, 89, 91, 94, 96, 97, 98, + 99, 99, 99, 100, 100, 100, 101, 101, 101, 101, 101, 101, 99, 97, 95, 93, + 90, 87, 84, 81, 77, 73, 67, 60, 51, 40, 29, 17, 6, -5, -14, -23, + -31, -38, -45, -52, -58, -65, -70, -75, -80, -84, -87, -90, -92, -94, -95, -96, + -97, -98, -100, -101, -102, -102, -103, -103, -104, -104, -103, -102, -100, -97, -93, -89, + -86, -82, -79, -77, -75, -72, -70, -67, -63, -59, -53, -47, -40, -33, -26, -20, + -14, -9, -6, -3, 0, 3, 6, 9, 13, 17, 21, 26, 31, 37, 44, 51, + 58, 64, 70, 75, 79, 83, 86, 88, 90, 92, 93, 95, 96, 97, 98, 100, + 100, 101, 102, 102, 102, 102, 102, 102, 102, 102, 102, 103, 103, 103, 102, 102, + 102, 101, 100, 98, 96, 94, 92, 90, 89, 88, 88, 87, 87, 87, 87, 87, + 86, 85, 84, 82, 79, 76, 72, 67, 61, 55, 49, 43, 39, 35, 32, 30, + 29, 27, 25, 24, 21, 18, 15, 12, 8, 5, 3, 3, 4, 6, 9, 12, + 15, 18, 21, 23, 25, 27, 28, 30, 31, 31, 31, 30, 28, 25, 22, 18, + 14, 10, 7, 5, 3, 1, 0, -2, -4, -6, -9, -11, -14, -16, -17, -17, + -16, -14, -12, -11, -9, -9, -9, -10, -11, -12, -13, -14, -15, -15, -16, -16, + -17, -19, -22, -26, -30, -34, -38, -42, -45, -48, -50, -52, -53, -54, -55, -56, + -56, -55, -53, -50, -46, -42, -38, -35, -32, -31, -30, -31, -31, -33, -34, -35, + -36, -36, -36, -35, -35, -35, -36, -38, -41, -45, -49, -54, -59, -64, -68, -73, + -76, -80, -83, -86, -88, -89, -90, -91, -91, -91, -92, -92, -93, -95, -96, -98, + -100, -101, -102, -103, -104, -105, -105, -105, -105, -105, -105, -105, -105, -105, -105, -105, + -105, -105, -104, -104, -103, -102, -102, -101, -100, -100, -100, -99, -99, -99, -98, -96, + -94, -91, -86, -82, -76, -71, -65, -59, -53, -48, -42, -37, -32, -28, -25, -22, + -19, -16, -13, -8, -3, 3, 9, 16, 22, 28, 35, 40, 45, 49, 53, 56, + 60, 63, 67, 71, 76, 80, 85, 88, 92, 94, 97, 99, 100, 102, 103, 103, + 104, 104, 104, 104, 105, 105, 105, 105, 105, 104, 103, 101, 99, 97, 94, 91, + 87, 84, 80, 76, 71, 65, 57, 48, 39, 28, 18, 8, -2, -11, -19, -27, + -34, -41, -47, -54, -60, -65, -70, -75, -79, -82, -85, -87, -89, -91, -92, -94, + -95, -96, -97, -98, -99, -100, -100, -100, -100, -100, -98, -96, -94, -90, -87, -84, + -81, -78, -76, -73, -71, -68, -65, -61, -57, -52, -46, -40, -33, -27, -21, -15, + -11, -7, -4, 0, 3, 7, 11, 15, 20, 24, 29, 35, 41, 48, 54, 61, + 67, 72, 77, 81, 85, 88, 90, 92, 94, 95, 97, 98, 99, 101, 102, 103, + 104, 104, 104, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 104, + 104, 103, 101, 99, 98, 96, 95, 93, 93, 92, 92, 91, 91, 90, 90, 88, + 87, 86, 84, 81, 78, 74, 69, 64, 59, 54, 49, 45, 42, 39, 37, 35, + 33, 31, 29, 27, 24, 21, 18, 15, 13, 11, 11, 12, 13, 15, 17, 20, + 22, 24, 25, 27, 28, 29, 30, 31, 31, 31, 30, 28, 26, 23, 20, 17, + 14, 11, 9, 8, 6, 5, 3, 1, -1, -4, -6, -8, -10, -11, -11, -11, + -10, -9, -8, -8, -8, -9, -10, -11, -13, -14, -15, -16, -17, -17, -18, -20, + -22, -25, -28, -31, -35, -38, -41, -44, -46, -47, -49, -50, -51, -52, -52, -52, + -51, -49, -47, -44, -40, -38, -35, -33, -33, -32, -33, -33, -34, -35, -36, -37, + -38, -38, -38, -38, -39, -40, -42, -45, -49, -53, -57, -61, -65, -69, -73, -76, + -79, -82, -85, -87, -88, -89, -90, -91, -91, -92, -93, -94, -95, -97, -98, -99, + -100, -101, -102, -103, -103, -104, -104, -104, -104, -104, -104, -104, -104, -104, -103, -103, + -103, -102, -102, -101, -100, -99, -99, -98, -97, -97, -96, -96, -95, -94, -92, -89, + -86, -82, -77, -72, -67, -61, -56, -50, -45, -39, -34, -29, -25, -21, -18, -14, + -11, -5, 4, 8, 14, 19, 25, 31, 37, 42, 47, 52, 57, 61, 65, 69, + 72, 76, 79, 83, 86, 89, 92, 95, 97, 99, 101, 102, 104, 104, 105, 106, + 106, 106, 106, 106, 106, 105, 104, 104, 103, 101, 99, 97, 95, 92, 89, 85, + 81, 77, 73, 68, 62, 57, 50, 43, 35, 28, 19, 12, 4, -4, -11, -18, + -25, -32, -38, -44, -50, -55, -61, -65, -69, -73, -77, -80, -82, -85, -87, -89, + -91, -92, -93, -95, -95, -96, -97, -97, -97, -96, -96, -95, -93, -92, -90, -88, + -86, -84, -82, -79, -77, -74, -71, -68, -64, -60, -55, -51, -46, -41, -36, -31, + -26, -21, -16, -11, -7, -2, 3, 8, 14, 19, 25, 30, 36, 42, 47, 53, + 58, 63, 68, 72, 76, 79, 82, 85, 87, 89, 91, 93, 95, 96, 98, 99, + 101, 102, 103, 103, 104, 105, 105, 105, 106, 106, 106, 106, 106, 106, 106, 105, + 105, 105, 104, 103, 103, 102, 101, 100, 99, 99, 98, 97, 96, 95, 93, 92, + 91, 89, 87, 85, 82, 79, 76, 73, 70, 67, 63, 60, 58, 55, 53, 50, + 48, 46, 44, 41, 39, 37, 34, 32, 31, 29, 28, 28, 27, 28, 28, 28, + 28, 29, 29, 29, 29, 30, 30, 30, 29, 29, 28, 27, 26, 25, 23, 22, + 20, 19, 17, 16, 15, 13, 12, 10, 8, 6, 4, 2, 1, -1, -2, -4, + -5, -6, -7, -9, -10, -12, -13, -15, -17, -19, -21, -22, -24, -26, -27, -29, + -31, -32, -34, -36, -38, -40, -42, -43, -45, -46, -47, -47, -48, -48, -49, -49, + -48, -48, -47, -46, -45, -44, -44, -43, -43, -43, -44, -44, -45, -46, -47, -48, + -49, -50, -51, -52, -53, -55, -57, -59, -61, -64, -67, -70, -72, -75, -78, -80, + -82, -84, -86, -88, -90, -91, -92, -94, -95, -96, -97, -98, -98, -99, -100, -101, + -101, -101, -102, -102, -102, -102, -102, -102, -102, -102, -102, -102, -101, -101, -100, -100, + -99, -98, -97, -96, -95, -94, -93, -92, -91, -89, -88, -87, -85, -83, -81, -78, + -75, -71, -67, -63, -58, -54, -49, -44, -39, -33, -28, -23, -18, -13, -8, -3, + 2, 7, 13, 18, 23, 29, 35, 40, 45, 51, 55, 60, 64, 68, 71, 75, + 78, 82, 85, 88, 91, 93, 96, 98, 100, 101, 103, 104, 105, 105, 106, 106, + 106, 106, 105, 105, 104, 104, 103, 101, 100, 98, 95, 93, 90, 86, 83, 79, + 75, 70, 65, 60, 54, 47, 40, 33, 25, 18, 10, 2, -5, -12, -19, -26, + -32, -38, -44, -50, -55, -60, -65, -69, -73, -76, -79, -82, -84, -87, -89, -90, + -92, -93, -94, -95, -96, -96, -96, -96, -96, -95, -94, -93, -91, -90, -88, -86, + -84, -81, -79, -76, -74, -70, -67, -63, -59, -54, -49, -44, -39, -34, -29, -24, + -19, -14, -10, -5, -2, -1, 3, -2, 1, -3, 4, -2, 0, 0, 8, 0, + 10, -9, -7, -128, -72, 13, -44, -13, -18, 4, -4, 12, 3, 31, 4, 66, + 74, 38, 38, 36, 30, 25, 22, 18, 13, 7, 5, 2, 1, -5, -7, -9, + -9, -11, -14, -12, -14, -12, -16, -13, -16, -13, -14, -16, -11, -14, -10, -13, + -11, -13, -8, -8, -6, -6, -5, 0, -6, -3, -3, 3, -4, 6, -13, 17, + -5, -5, 15, -1, -23, 6, 23, 28, 35, 13, 41, -3, 24, 25, -4, 6, + 30, 4, 18, 10, -32, -64, -120, -64, -91, -76, -33, -45, -58, 2, 1, -19, + -14, 18, 48, 50, 59, 51, 53, 47, 46, 41, 37, 35, 26, 28, 19, 21, + 10, 13, 9, 3, 5, -4, 2, -5, -3, -8, -5, -8, -8, -10, -9, -10, + -10, -12, -7, -17, -8, -11, -14, -5, -15, -5, -4, -10, -13, 11, -22, 3, + -3, -4, -5, -11, 13, 2, -16, -9, -5, -12, 27, 15, 17, 21, 20, 20, + 8, 14, 13, 0, 10, 35, 10, -1, -12, -52, -89, -78, -58, -85, -74, -51, + -25, -25, -28, -30, -14, 12, 29, 44, 44, 51, 46, 50, 49, 43, 38, 36, + 32, 29, 23, 19, 17, 14, 10, 6, 6, 2, 4, -8, 3, -7, -3, -6, + -7, -11, -4, -12, -7, -6, -20, 1, -15, -14, -8, -7, -10, -10, -10, 2, + -14, -12, 7, -10, -8, -5, -6, 1, 6, -2, -12, -19, -3, 3, 2, 19, + 19, 14, 19, 24, 13, 5, 12, 12, 13, 21, 29, 5, -18, -43, -48, -64, + -82, -82, -71, -44, -37, -37, -40, -33, -23, 5, 20, 33, 38, 45, 48, 51, + 46, 44, 41, 38, 36, 27, 26, 24, 19, 13, 16, 5, 11, 4, -1, 3, + -4, -3, 1, -9, -7, -2, -9, -6, -13, -4, -6, -17, -8, -6, -15, -10, + -5, -10, -8, -10, -5, -7, -5, -2, -14, -10, 3, 5, -4, -3, -10, -17, + -10, 3, 4, 5, 18, 18, 18, 16, 16, 10, 5, 11, 23, 26, 22, 7, + -9, -16, -37, -62, -80, -76, -65, -46, -43, -43, -51, -41, -24, -4, 11, 24, + 32, 41, 47, 43, 49, 45, 41, 40, 33, 31, 31, 20, 23, 18, 11, 16, + 9, 5, 3, 2, 5, -2, -7, 2, -4, -10, -3, -5, -8, -10, -7, -8, + -14, -10, -8, -11, -9, -6, -14, -10, -2, -3, -12, -10, -7, -9, 0, 6, + -1, -11, -12, -11, -10, -7, 4, 7, 12, 17, 20, 18, 13, 6, 8, 19, + 22, 24, 17, 14, 5, -8, -29, -54, -77, -71, -55, -50, -44, -54, -57, -39, + -32, -15, 3, 15, 31, 34, 39, 47, 45, 44, 44, 37, 37, 33, 28, 27, + 18, 20, 21, 10, 7, 10, 7, 1, 2, 2, 0, -5, 0, -2, -7, -3, + -5, -8, -8, -5, -13, -13, -5, -6, -14, -11, -8, -8, -5, -5, -9, -17, + -10, -2, 0, -2, -1, -9, -12, -14, -12, -6, -1, 3, 11, 19, 19, 14, + 7, 9, 13, 17, 23, 22, 19, 21, 12, 2, -21, -55, -65, -59, -52, -47, + -56, -56, -50, -53, -38, -22, -7, 10, 18, 29, 36, 40, 45, 43, 38, 41, + 40, 32, 27, 26, 26, 19, 17, 17, 12, 9, 9, 6, 2, 4, 4, -1, + -2, 2, -3, -3, 0, -2, -8, -9, -7, -7, -7, -6, -8, -12, -6, -4, + -7, -12, -13, -10, -5, -2, -2, -3, -8, -12, -15, -16, -14, -13, -7, 2, + 8, 11, 8, 4, 5, 8, 13, 20, 22, 23, 24, 23, 19, 6, -13, -23, + -29, -32, -37, -42, -46, -53, -57, -53, -49, -39, -25, -12, -1, 10, 21, 28, + 32, 35, 36, 34, 34, 32, 28, 25, 24, 21, 18, 19, 16, 10, 7, 8, + 9, 8, 6, 5, 2, 3, 6, 7, 5, 2, -2, -4, -3, -1, -3, -4, + -3, -1, -3, -8, -13, -14, -11, -4, -1, -2, -4, -6, -11, -16, -19, -21, + -21, -17, -9, -3, 0, 0, -3, -5, -2, 4, 11, 18, 23, 25, 26, 24, + 17, 10, 5, -1, -7, -12, -20, -29, -37, -44, -51, -55, -54, -47, -39, -28, + -16, -4, 9, 18, 23, 27, 31, 31, 30, 30, 28, 23, 20, 22, 23, 20, + 14, 10, 9, 9, 10, 9, 6, 4, 4, 6, 9, 10, 7, 2, 0, 1, + -1, -2, -2, -1, 1, 2, -2, -10, -14, -11, -8, -5, -2, -1, -3, -6, + -9, -14, -20, -23, -23, -18, -11, -5, -3, -4, -6, -8, -4, 2, 7, 14, + 21, 25, 25, 23, 19, 13, 8, 4, -1, -9, -15, -23, -31, -39, -48, -53, + -51, -48, -44, -34, -20, -8, 3, 12, 20, 24, 27, 30, 31, 29, 24, 22, + 22, 23, 22, 18, 13, 10, 10, 11, 11, 9, 5, 3, 5, 10, 11, 9, + 7, 5, 4, 2, 0, -3, -1, 3, 5, 2, -3, -8, -11, -10, -7, -5, + -3, -2, -2, -4, -7, -14, -20, -24, -24, -19, -12, -6, -6, -8, -8, -8, + -7, -2, 5, 12, 19, 23, 24, 22, 20, 16, 12, 7, 1, -5, -10, -17, + -27, -36, -42, -47, -52, -51, -45, -36, -26, -12, 0, 9, 15, 21, 27, 30, + 29, 26, 23, 22, 23, 23, 21, 17, 12, 9, 10, 12, 10, 6, 3, 4, + 7, 10, 11, 9, 8, 9, 7, 2, -1, 0, 2, 6, 6, 3, -2, -7, + -9, -8, -6, -4, -3, -1, -1, -2, -6, -13, -21, -26, -24, -18, -13, -10, + -9, -10, -11, -11, -10, -5, 3, 10, 17, 21, 22, 22, 21, 19, 14, 8, + 5, 1, -7, -14, -21, -29, -38, -45, -49, -50, -48, -40, -28, -16, -6, 3, + 11, 19, 26, 27, 26, 24, 22, 22, 24, 24, 20, 14, 11, 11, 12, 11, + 8, 4, 3, 6, 8, 9, 9, 10, 11, 10, 6, 2, 0, 2, 5, 8, + 7, 3, -2, -5, -6, -7, -6, -4, -3, -1, 1, 1, -5, -13, -21, -24, + -23, -18, -14, -12, -11, -12, -13, -14, -13, -8, 0, 8, 14, 17, 21, 22, + 21, 18, 15, 12, 8, 2, -3, -9, -16, -24, -32, -40, -47, -51, -49, -41, + -30, -21, -12, -1, 9, 17, 23, 25, 24, 21, 21, 24, 24, 22, 17, 12, + 11, 13, 12, 8, 4, 3, 4, 6, 7, 7, 9, 11, 12, 10, 6, 3, + 3, 6, 9, 10, 8, 5, 1, -2, -3, -3, -2, -1, 1, 3, 3, 1, + -5, -12, -18, -20, -20, -18, -16, -16, -16, -17, -19, -20, -17, -11, -5, 1, + 8, 13, 17, 18, 18, 17, 16, 14, 11, 7, 2, -3, -8, -14, -22, -34, + -43, -46, -42, -35, -28, -20, -11, -2, 7, 15, 19, 19, 19, 19, 20, 20, + 17, 14, 11, 10, 9, 7, 1, -4, -6, -4, 0, 2, 4, 6, 7, 8, + 9, 8, 7, 7, 10, 13, 15, 15, 13, 9, 6, 3, 2, 4, 7, 9, + 11, 11, 7, 1, -5, -10, -13, -14, -14, -14, -16, -19, -23, -26, -28, -27, + -23, -18, -13, -7, -1, 6, 11, 14, 15, 14, 14, 15, 15, 12, 7, 2, + -1, -4, -11, -22, -34, -41, -40, -34, -26, -19, -12, -4, 4, 10, 14, 17, + 17, 18, 19, 18, 15, 12, 10, 9, 8, 6, 0, -6, -11, -10, -6, -1, + 3, 5, 6, 6, 6, 7, 7, 8, 10, 13, 16, 18, 17, 13, 9, 5, + 3, 4, 7, 11, 13, 14, 11, 5, -2, -7, -11, -12, -12, -13, -14, -17, + -22, -26, -28, -29, -27, -22, -17, -11, -5, 1, 7, 12, 14, 14, 13, 14, + 15, 14, 11, 5, 0, -2, -6, -15, -27, -37, -42, -38, -31, -24, -17, -9, + -1, 6, 12, 15, 17, 18, 19, 19, 17, 13, 11, 9, 9, 8, 4, -2, + -8, -11, -9, -4, 1, 4, 5, 6, 6, 6, 7, 7, 9, 11, 14, 17, + 18, 16, 12, 8, 4, 3, 5, 9, 12, 14, 13, 9, 2, -4, -9, -12, + -13, -12, -13, -15, -19, -23, -27, -29, -28, -25, -20, -15, -9, -3, 3, 9, + 13, 15, 14, 13, 15, 15, 13, 9, 3, -1, -3, -9, -19, -31, -40, -41, + -36, -28, -21, -14, -6, 2, 9, 13, 16, 17, 18, 19, 18, 16, 12, 10, + 9, 9, 7, 2, -4, -10, -11, -8, -2, 2, 5, 5, 6, 6, 7, 7, + 8, 9, 12, 16, 18, 17, 14, 10, 6, 4, 4, 6, 10, 13, 14, 12, + 7, 0, -6, -10, -12, -13, -13, -14, -16, -21, -25, -28, -29, -28, -24, -18, + -13, -7, -1, 6, 11, 14, 15, 13, 14, 15, 15, 12, 7, 2, -1, -5, + -12, -23, -35, -41, -40, -34, -26, -19, -12, -3, 4, 10, 14, 17, 18, 18, + 19, 18, 14, 11, 9, 9, 8, 6, 0, -7, -11, -10, -6, 0, 2, -1, + -2, -9, -24, 4, -3, 3, -3, 10, 7, 4, 13, -4, 1, 3, 3, 0, + 2, 8, -9, -9, 2, 1, -1, 7, 17, 21, 37, 25, 13, 14, -2, 15, + 20, 5, 0, -3, -7, -27, -14, -18, -19, -29, -20, -4, -18, -32, -30, -30, + -29, -32, -22, -26, -19, -19, -1, -6, 4, 7, 5, 2, 0, -8, -16, -12, + -13, -17, -17, 19, 20, 24, 16, 8, -4, 8, 0, 13, 28, 33, 16, 11, + 5, -3, -1, 4, 12, 12, 40, 20, 11, 4, 5, 8, -1, 2, 5, 5, + 22, 13, 21, 8, 9, 18, 20, 13, 20, 26, 11, 24, 17, 10, 27, 30, + 22, 28, 30, 41, 47, 57, 36, 36, 20, -16, 4, 6, -19, -21, -41, -39, + -33, -38, -41, -46, -42, -36, -18, -37, -65, -75, -77, -78, -62, -63, -62, -68, + -63, -63, -44, -50, -30, -41, -43, -26, -34, -35, -36, -45, -49, -27, 1, -6, + -4, -7, -20, -16, -20, -21, -13, 2, -6, -1, -12, 0, -1, 15, 19, 20, + 26, 37, 40, 46, 37, 50, 35, 34, 41, 43, 51, 54, 55, 50, 56, 47, + 59, 51, 51, 75, 67, 66, 71, 59, 60, 72, 75, 72, 80, 79, 82, 98, + 99, 87, 93, 62, 49, 58, 41, 42, 28, 5, -6, -6, -18, -24, -23, -30, + -25, -20, -38, -60, -75, -77, -80, -75, -71, -75, -70, -73, -69, -76, -60, -66, + -71, -66, -57, -62, -61, -61, -87, -90, -69, -63, -46, -31, -35, -47, -42, -53, + -63, -53, -45, -33, -36, -39, -37, -43, -39, -34, -30, -19, -9, 2, -9, -1, + -3, 1, -3, 5, 7, 15, 24, 22, 23, 20, 32, 43, 33, 48, 63, 67, + 70, 68, 52, 59, 73, 73, 77, 85, 73, 81, 103, 98, 116, 115, 87, 80, + 76, 72, 69, 60, 37, 27, 29, 12, 19, 4, -12, 1, 3, -3, -31, -42, + -57, -67, -67, -61, -61, -61, -48, -58, -51, -41, -46, -48, -40, -35, -33, -26, + -36, -67, -68, -65, -59, -47, -28, -34, -37, -36, -52, -61, -61, -47, -34, -39, + -39, -42, -42, -48, -36, -38, -37, -20, -19, -16, -16, -18, -20, -22, -26, -22, + -16, -15, 1, -4, -6, 10, 12, 13, 22, 32, 41, 54, 52, 44, 54, 66, + 61, 78, 81, 71, 87, 89, 99, 119, 107, 91, 77, 76, 69, 76, 68, 47, + 49, 35, 33, 37, 22, 14, 24, 37, 26, 13, -10, -26, -41, -43, -34, -40, + -34, -33, -43, -39, -25, -27, -27, -18, -25, -15, -1, -10, -29, -42, -39, -39, + -19, -7, -10, -10, -11, -20, -35, -44, -33, -30, -28, -36, -34, -47, -41, -36, + -46, -42, -34, -27, -29, -25, -34, -30, -32, -40, -36, -36, -31, -16, -25, -25, + -15, -21, -14, -9, -11, 1, 17, 15, 9, 25, 20, 25, 46, 39, 46, 50, + 51, 68, 85, 87, 72, 65, 52, 50, 59, 44, 42, 29, 23, 22, 23, 11, + -5, 8, 14, 19, 8, -6, -23, -38, -43, -42, -48, -41, -34, -42, -38, -19, + -23, -16, -15, -19, -10, 8, 8, -9, -18, -27, -30, -10, -4, 7, 6, 15, + 8, -8, -17, -15, -8, -11, -3, -15, -17, -14, -16, -27, -30, -26, -22, -19, + -21, -22, -19, -30, -27, -26, -36, -22, -9, -13, -10, -10, -8, -9, -6, -12, + -1, 16, 6, 11, 16, 6, 19, 24, 27, 38, 38, 38, 48, 71, 72, 78, + 66, 51, 54, 52, 49, 42, 32, 21, 25, 26, 13, 1, -1, 10, 15, 8, + 1, -22, -38, -47, -56, -58, -46, -43, -46, -33, -25, -17, -11, -9, -19, -9, + 16, 18, 12, 1, -17, -18, -9, 3, 9, 17, 24, 26, 9, -4, -1, -6, + 2, 9, 0, -2, 2, -3, -13, -16, -15, -8, -8, -8, -1, -6, -17, -11, + -22, -24, -16, -12, -9, -9, -9, -9, -6, -8, -16, 2, 6, 2, 13, 9, + 7, 10, 17, 19, 30, 31, 22, 37, 49, 61, 70, 56, 43, 37, 36, 31, + 32, 15, 4, 11, 9, 4, -14, -16, -7, -5, -1, -8, -28, -46, -56, -75, + -74, -67, -70, -67, -62, -55, -47, -36, -32, -42, -28, -9, 1, 4, -4, -17, + -30, -18, -12, -2, 4, 15, 21, 7, 1, -7, -6, -1, 7, 0, 0, 3, + -3, -8, -15, -18, -6, -9, -6, 5, -2, -2, 0, -7, -12, -7, -3, 2, + 7, 3, 4, 14, 2, 1, 12, 11, 17, 20, 19, 16, 19, 20, 24, 39, + 36, 37, 42, 55, 71, 84, 76, 63, 56, 47, 49, 46, 29, 18, 14, 18, + 11, -5, -11, -8, -3, 4, 4, -16, -27, -44, -60, -64, -59, -62, -62, -55, + -55, -47, -28, -32, -35, -29, -15, -3, 4, 3, -15, -25, -24, -13, -11, -3, + 10, 14, 12, 4, -5, -9, -1, 2, -1, 1, 1, -1, -7, -17, -16, -12, + -17, -8, 0, -1, -1, -2, -8, -13, -9, -9, 0, 9, 1, 14, 16, 6, + 7, 10, 12, 18, 26, 20, 22, 22, 16, 25, 32, 36, 34, 36, 43, 60, + 75, 72, 67, 52, 44, 50, 45, 38, 17, 14, 17, 11, -2, -9, -14, -10, + 0, -4, -12, -24, -41, -59, -67, -63, -70, -69, -62, -70, -55, -40, -38, -42, + -38, -29, -16, -3, -3, -9, -29, -31, -25, -26, -20, -7, 0, 2, -1, -14, + -18, -14, -14, -12, -10, -10, -4, -13, -21, -19, -22, -24, -16, -10, -6, -2, + -2, -10, -12, -15, -17, -4, -4, -5, 7, 9, 3, 4, 7, 5, 18, 23, + 22, 28, 25, 22, 27, 34, 39, 43, 38, 41, 62, 71, 79, 78, 62, 55, + 55, 57, 49, 31, 23, 30, 21, 15, 7, -5, 1, 8, 9, 8, -3, -16, + -39, -46, -50, -60, -55, -58, -62, -53, -36, -33, -34, -34, -29, -18, -6, 5, + -2, -17, -23, -22, -24, -17, -8, 1, 9, 10, -4, -7, -8, -9, -6, -9, + -6, 0, -11, -14, -14, -21, -24, -21, -16, -10, 1, -3, -3, -5, -14, -11, + -7, -7, -5, 6, 9, 4, 8, 1, 3, 11, 16, 20, 26, 24, 20, 25, + 29, 36, 41, 32, 40, 51, 64, 77, 78, 67, 55, 54, 57, 53, 33, 27, + 25, 22, 20, 9, -3, -3, 3, 7, 6, 4, -16, -32, -42, -55, -60, -61, + -64, -70, -62, -49, -39, -41, -40, -37, -33, -18, -5, -8, -16, -24, -29, -31, + -28, -24, -15, -1, 1, -7, -11, -14, -13, -14, -18, -11, -8, -14, -16, -16, + -25, -31, -29, -31, -20, -12, -13, -6, -11, -19, -19, -14, -17, -12, -1, 2, + 6, 7, 2, 4, 8, 11, 18, 24, 21, 22, 19, 21, 33, 33, 32, 32, + 40, 55, 71, 76, 72, 58, 55, 62, 56, 42, 34, 28, 29, 26, 17, 4, + 2, 6, 4, 13, 12, -4, -18, -30, -45, -50, -51, -59, -63, -61, -47, -37, + -33, -32, -34, -32, -19, -4, -3, -5, -13, -21, -23, -22, -24, -13, 1, 5, + 5, -3, -6, -1, -7, -9, -2, 1, -2, -2, -4, -13, -16, -22, -22, -15, + -10, -4, 2, -1, -11, -8, -7, -12, -6, 1, 6, 12, 11, 8, 9, 9, + 9, 20, 23, 26, 25, 20, 24, 32, 34, 35, 33, 35, 49, 63, 74, 74, + 58, 55, 60, 54, 45, 33, 27, 25, 26, 19, 6, 4, 1, 1, 9, 12, + -1, -10, -26, -43, -50, -54, -61, -70, -69, -61, -50, -43, -40, -44, -44, -34, + -18, -12, -9, -15, -24, -25, -28, -31, -22, -12, -2, 1, -8, -8, -5, -12, + -14, -8, -8, -8, -5, -9, -11, -18, -27, -26, -22, -19, -12, -1, -4, -9, + -8, -11, -14, -12, -8, 0, 7, 5, 5, 6, 0, 3, 8, 13, 20, 18, + 13, 15, 22, 27, 29, 25, 26, 36, 51, 70, 71, 59, 56, 57, 55, 47, + 37, 25, 24, 27, 17, 9, 3, -2, -2, 8, 9, 6, -2, -16, -34, -44, + -47, -54, -63, -66, -63, -55, -44, -39, -42, -44, -35, -23, -11, -4, -10, -16, + -17, -23, -25, -22, -13, 1, 6, 1, 1, 4, -2, -4, 1, -1, 4, 3, + 2, 2, -3, -12, -15, -14, -15, -7, 3, 5, 3, 2, 1, -2, -4, -4, + 3, 9, 10, 13, 11, 9, 8, 9, 15, 22, 22, 20, 19, 21, 27, 30, + 28, 28, 28, 42, 61, 69, 65, 60, 60, 58, 55, 47, 35, 30, 30, 24, + 18, 10, 0, -1, 2, 6, 7, 3, -8, -24, -36, -43, -50, -59, -65, -66, + -62, -52, -43, -43, -44, -41, -35, -21, -12, -12, -13, -17, -23, -26, -30, -24, + -12, -4, -5, -3, -2, -5, -6, -6, -5, -3, -2, -1, 2, 2, -5, -3, + 2, 8, 17, 26, 32, 42, 50, 56, 68, 73, 64, 63, 65, 48, 56, 71, + 48, 49, 50, 26, 30, 30, 16, 25, 21, -2, 0, -13, -15, -2, -19, -17, + -16, -50, -49, -49, -81, -85, -88, -108, -112, -116, -127, -126, -113, -113, -106, -79, + -65, -48, -17, 5, 20, 41, 58, 63, 69, 59, 28, 17, 0, -32, -41, -52, + -69, -63, -61, -59, -41, -26, -19, 6, 28, 33, 52, 67, 70, 81, 87, 84, + 90, 93, 84, 72, 69, 60, 45, 56, 57, 40, 46, 39, 25, 29, 25, 16, + 21, 12, -1, -3, -11, -8, -5, -16, -12, -21, -41, -38, -48, -68, -70, -77, + -91, -93, -98, -106, -103, -93, -92, -82, -60, -47, -30, -4, 13, 27, 44, 56, + 60, 62, 47, 23, 13, -8, -32, -40, -54, -64, -59, -59, -53, -36, -26, -14, + 12, 27, 36, 56, 66, 72, 84, 86, 86, 93, 92, 82, 73, 70, 57, 49, + 59, 52, 43, 47, 37, 29, 30, 24, 18, 18, 7, -2, -6, -11, -7, -10, + -16, -14, -29, -42, -42, -57, -71, -73, -83, -93, -96, -102, -107, -101, -93, -90, + -75, -55, -41, -22, 3, 19, 33, 50, 59, 61, 60, 41, 21, 10, -14, -33, + -43, -57, -63, -60, -61, -51, -36, -27, -9, 15, 26, 40, 59, 66, 74, 85, + 85, 88, 94, 90, 80, 75, 69, 56, 54, 60, 50, 47, 46, 36, 31, 30, + 23, 19, 15, 4, -3, -7, -10, -9, -14, -17, -19, -35, -44, -47, -63, -73, + -77, -88, -96, -98, -104, -107, -99, -92, -86, -69, -50, -35, -14, 9, 24, 38, + 54, 60, 61, 56, 36, 19, 4, -20, -35, -46, -60, -62, -61, -60, -48, -35, + -25, -3, 17, 27, 45, 60, 66, 77, 85, 86, 91, 94, 88, 80, 75, 67, + 56, 58, 59, 50, 49, 45, 36, 33, 30, 23, 19, 13, 2, -5, -8, -10, + -11, -16, -18, -25, -40, -45, -53, -68, -76, -81, -91, -97, -100, -106, -106, -97, + -90, -81, -63, -44, -28, -6, 15, 28, 44, 57, 61, 61, 52, 31, 16, -1, + -24, -37, -50, -61, -62, -62, -59, -46, -35, -22, 1, 18, 30, 48, 61, 68, + 79, 85, 87, 92, 93, 86, 80, 75, 66, 58, 60, 58, 51, 50, 44, 37, + 33, 29, 23, 17, 10, 0, -6, -9, -10, -14, -18, -21, -31, -43, -48, -59, + -72, -78, -85, -94, -99, -102, -107, -104, -95, -88, -76, -56, -39, -22, 2, 20, + 33, 49, 59, 61, 60, 47, 27, 12, -7, -27, -40, -53, -62, -62, -63, -57, + -44, -34, -18, 5, 19, 33, 51, 61, 70, 81, 85, 88, 94, 92, 85, 80, + 74, 65, 60, 62, 57, 52, 50, 43, 37, 33, 28, 22, 15, 8, -2, -7, + -10, -12, -16, -20, -24, -36, -46, -52, -64, -75, -81, -89, -97, -100, -104, -107, + -102, -93, -85, -70, -50, -33, -14, 8, 25, 38, 53, 61, 61, 58, 42, 24, + 8, -12, -30, -43, -56, -62, -63, -63, -54, -43, -32, -13, 7, 20, 37, 53, + 62, 72, 82, 85, 89, 94, 90, 84, 80, 73, 64, 62, 62, 56, 53, 49, + 43, 37, 33, 27, 20, 14, 5, -3, -8, -11, -13, -18, -22, -28, -40, -49, + -57, -69, -78, -84, -92, -99, -102, -105, -106, -99, -90, -81, -64, -44, -27, -7, + 14, 29, 43, 56, 61, 61, 54, 37, 20, 4, -17, -33, -46, -58, -62, -64, + -62, -52, -42, -29, -9, 9, 23, 40, 55, 64, 74, 83, 86, 91, 93, 89, + 84, 80, 72, 65, 64, 62, 56, 53, 49, 42, 37, 33, 26, 19, 12, 3, + -5, -8, -12, -16, -20, -24, -33, -44, -52, -61, -73, -80, -87, -95, -100, -103, + -106, -104, -96, -88, -76, -57, -38, -21, 0, 20, 33, 47, 59, 62, 60, 51, + 33, 17, -1, -21, -36, -49, -59, -63, -64, -61, -51, -40, -25, -5, 11, 26, + 43, 56, 65, 76, 83, 87, 92, 93, 88, 84, 79, 71, 65, 65, 61, 56, + 53, 48, 42, 37, 32, 25, 17, 10, 1, -6, -10, -13, -18, -22, -27, -37, + -48, -55, -65, -76, -83, -90, -97, -101, -104, -106, -102, -94, -84, -71, -51, -33, + -15, 7, 24, 38, 51, 60, 62, 59, 46, 29, 13, -6, -25, -39, -52, -60, + -63, -64, -59, -49, -38, -21, -1, 14, 29, 46, 57, 67, 78, 84, 88, 92, + 92, 87, 83, 78, 70, 66, 65, 61, 57, 53, 48, 42, 37, 31, 23, 15, + 7, -1, -7, -11, -15, -20, -24, -31, -41, -51, -59, -69, -79, -85, -93, -99, + -102, -105, -106, -100, -91, -80, -65, -45, -27, -8, 13, 29, 42, 55, 61, 61, + 56, 42, 25, 8, -11, -28, -42, -54, -61, -64, -64, -57, -47, -35, -17, 1, + 16, 33, 48, 59, 69, 79, 84, 89, 93, 91, 87, 83, 77, 70, 67, 65, + 60, 57, 53, 47, 41, 36, 29, 21, 14, 5, -3, -8, -12, -17, -22, -27, + -35, -45, -54, -63, -73, -81, -88, -95, -100, -103, -105, -104, -97, -88, -76, -58, + -39, -21, -1, 18, 33, 46, 58, 62, 61, 53, 38, 21, 4, -15, -31, -45, + -56, -62, -65, -64, -56, -46, -32, -13, 4, 19, 36, 50, 61, 71, 80, 85, + 90, 92, 90, 86, 82, 76, 70, 68, 65, 60, 57, 52, 46, 41, 35, 27, + 19, 12, 3, -5, -9, -14, -19, -24, -29, -38, -48, -57, -66, -76, -84, -91, + -97, -101, -104, -105, -102, -94, -84, -71, -52, -33, -15, 5, 23, 37, 50, 60, + 62, 60, 50, 34, 17, -1, -19, -35, -48, -58, -63, -65, -62, -54, -43, -28, + -10, 7, 22, 39, 52, 62, 73, 81, 86, 91, 92, 89, 86, 82, 75, 70, + 68, 64, 60, 57, 52, 46, 40, 34, 26, 17, 9, 1, -6, -11, -15, -21, + -26, -32, -42, -52, -60, -70, -79, -86, -93, -99, -102, -104, -105, -100, -91, -80, + -65, -46, -27, -9, 11, 28, 42, 54, 61, 62, 58, 46, 30, 13, -6, -23, + -38, -51, -60, -64, -65, -61, -52, -41, -25, -6, 9, 26, 42, 54, 64, 75, + 82, 87, 91, 91, 89, 85, 81, 74, 71, 68, 64, 60, 56, 51, 45, 39, + 32, 24, 16, 7, -1, -7, -12, -17, -23, -28, -36, -45, -55, -64, -73, -82, + -88, -95, -100, -103, -105, -104, -97, -88, -76, -59, -40, -22, -2, 17, 32, 45, + 57, 62, 62, 56, 42, 26, 9, -10, -27, -41, -53, -61, -65, -65, -60, -50, + -38, -21, -3, 12, 29, 44, 55, 66, 76, 82, 88, 91, 91, 88, 85, 80, + 74, 71, 68, 63, 60, 56, 50, 44, 38, 30, 22, 14, 5, -3, -9, -14, + -19, -25, -31, -39, -49, -58, -67, -77, -84, -91, -97, -101, -103, -105, -102, -95, + -84, -71, -53, -34, -16, 4, 22, 37, 49, 59, 63, 61, 53, 38, 22, 4, + -14, -30, -44, -56, -62, -66, -65, -58, -48, -35, -17, -1, 15, 32, 46, 57, + 68, 77, 83, 88, 91, 90, 88, 84, 79, 74, 71, 67, 63, 60, 55, 49, + 43, 37, 28, 20, 12, 3, -5, -10, -15, -21, -27, -33, -43, -52, -61, -70, + -79, -86, -93, -98, -102, -104, -104, -100, -92, -81, -66, -47, -28, -10, 10, 27, + 40, 53, 61, 63, 59, 49, 34, 18, -1, -18, -34, -47, -58, -63, -66, -64, + -56, -46, -31, -14, 2, 18, 35, 48, 59, 70, 78, 84, 89, 91, 90, 87, + 83, 78, 74, 71, 67, 63, 59, 54, 49, 42, 35, 27, 18, 9, 1, -6, + -12, -17, -23, -29, -36, -46, -55, -64, -73, -82, -89, -95, -100, -102, -104, -103, + -97, -88, -76, -60, -41, -23, -4, 15, 31, 44, 55, 62, 62, 57, 46, 30, + 13, -5, -22, -37, -50, -59, -64, -66, -62, -55, -43, -28, -11, 5, 22, 37, + 50, 61, 71, 79, 85, 89, 91, 89, 87, 82, 77, 73, 70, 66, 63, 59, + 53, 47, 41, 33, 24, 16, 7, -1, -8, -14, -19, -25, -32, -40, -49, -58, + -67, -76, -84, -91, -96, -101, -103, -104, -102, -95, -85, -72, -55, -37, -18, 1, + 19, 34, 47, 57, 62, 62, 56, 43, 28, 10, -8, -25, -39, -52, -60, -65, + -66, -62, -53, -42, -25, -9, 8, 24, 39, 51, 62, 72, 80, 86, 90, 90, + 89, 86, 82, 77, 73, 70, 66, 62, 58, 53, 47, 40, 33, 24, 15, 6, + -2, -8, -14, -19, -25, -32, -40, -49, -58, -67, -72, -103, -18, -76, 0, 0, + 0, 0, 1, 2, 3, 5, 6, 0, -7, -8, -15, -9, 10, 8, 17, 33, + 14, 5, 38, 44, 31, 63, 70, 51, 73, 82, 68, 85, 100, 96, 97, 103, + 115, 114, 112, 127, 122, 110, 116, 113, 109, 120, 120, 118, 113, 91, 93, 109, + 97, 98, 115, 110, 109, 120, 112, 94, 75, 63, 69, 72, 64, 64, 59, 45, + 39, 36, 35, 42, 42, 24, 5, 2, 3, 4, 7, 9, 11, 14, 17, 19, + 14, -3, -20, -26, -30, -26, -24, -31, -32, -34, -40, -39, -33, -34, -45, -56, + -60, -66, -64, -55, -60, -62, -56, -59, -58, -50, -56, -70, -73, -76, -86, -77, + -70, -80, -76, -71, -77, -71, -66, -76, -85, -82, -90, -95, -80, -82, -92, -85, + -86, -94, -85, -79, -86, -92, -90, -94, -101, -92, -85, -90, -84, -77, -78, -74, + -73, -85, -86, -85, -95, -85, -77, -90, -88, -83, -94, -93, -83, -81, -81, -86, + -89, -89, -94, -88, -77, -77, -71, -59, -58, -59, -63, -72, -74, -77, -73, -61, + -67, -72, -67, -73, -80, -74, -68, -60, -56, -65, -70, -67, -72, -66, -52, -49, + -40, -27, -27, -32, -39, -47, -50, -42, -30, -31, -34, -32, -38, -46, -46, -43, + -35, -20, -16, -24, -30, -30, -31, -24, -13, -6, 4, 13, 11, 3, -5, -9, + -2, 12, 15, 15, 16, 9, 3, -2, -5, -1, 12, 24, 30, 29, 20, 17, + 22, 25, 30, 41, 47, 49, 46, 37, 32, 41, 52, 54, 60, 61, 52, 48, + 45, 36, 35, 43, 51, 60, 67, 69, 60, 57, 63, 63, 64, 73, 75, 72, + 69, 63, 67, 78, 78, 82, 89, 80, 73, 76, 67, 60, 64, 67, 73, 79, + 83, 88, 82, 75, 80, 81, 77, 83, 83, 76, 74, 77, 83, 85, 86, 94, + 89, 80, 82, 78, 69, 68, 68, 69, 78, 80, 81, 90, 83, 73, 79, 77, + 70, 73, 70, 62, 65, 73, 75, 76, 84, 82, 70, 71, 69, 59, 57, 54, + 48, 53, 63, 64, 68, 76, 66, 57, 58, 51, 42, 40, 33, 28, 37, 46, + 49, 55, 56, 42, 37, 37, 27, 22, 20, 10, 4, 8, 15, 24, 30, 31, + 24, 14, 8, -3, -14, -21, -26, -26, -15, -4, -1, -4, -13, -21, -26, -34, + -39, -42, -50, -57, -63, -66, -60, -47, -43, -48, -51, -57, -66, -75, -82, -88, + -91, -88, -78, -74, -81, -86, -85, -92, -101, -100, -102, -109, -109, -110, -112, -113, + -115, -109, -106, -113, -113, -107, -110, -110, -106, -108, -112, -109, -110, -114, -111, -98, + -95, -98, -93, -93, -98, -94, -89, -81, -69, -65, -71, -73, -73, -77, -73, -62, + -56, -48, -40, -41, -45, -47, -47, -37, -20, -11, -4, 5, 4, 3, 6, 9, + 16, 30, 39, 47, 51, 44, 40, 45, 47, 50, 59, 64, 66, 68, 65, 65, + 75, 80, 78, 87, 95, 91, 93, 98, 96, 98, 104, 100, 96, 99, 104, 101, + 100, 106, 107, 105, 108, 109, 109, 110, 111, 110, 101, 87, 82, 84, 81, 82, + 88, 89, 90, 91, 85, 71, 57, 49, 48, 51, 52, 55, 59, 58, 58, 60, + 61, 61, 57, 42, 24, 14, 7, 5, 9, 11, 15, 20, 21, 19, 11, -3, + -18, -27, -33, -31, -25, -24, -21, -16, -16, -14, -11, -17, -29, -40, -49, -59, + -61, -55, -54, -52, -45, -42, -41, -41, -48, -59, -65, -72, -81, -79, -72, -73, + -69, -62, -61, -59, -60, -69, -76, -79, -87, -92, -84, -81, -82, -76, -72, -71, + -67, -66, -72, -79, -81, -87, -94, -92, -87, -86, -82, -76, -75, -75, -78, -85, + -87, -91, -96, -91, -82, -83, -80, -74, -74, -71, -64, -64, -68, -73, -77, -81, + -87, -88, -82, -79, -76, -70, -69, -72, -76, -80, -84, -87, -82, -71, -67, -64, + -58, -57, -55, -49, -43, -39, -40, -47, -54, -58, -64, -66, -61, -58, -54, -49, + -50, -55, -59, -63, -65, -58, -45, -38, -32, -25, -24, -23, -18, -13, -5, 3, + 4, -2, -11, -17, -23, -26, -23, -20, -18, -15, -18, -24, -28, -28, -21, -7, + 3, 11, 18, 20, 19, 22, 24, 30, 40, 47, 51, 49, 40, 32, 28, 24, + 23, 25, 25, 23, 20, 15, 15, 23, 34, 43, 51, 59, 59, 58, 59, 58, + 60, 67, 73, 78, 84, 85, 78, 71, 68, 63, 60, 60, 57, 53, 50, 50, + 56, 65, 70, 76, 84, 84, 81, 81, 79, 76, 79, 84, 87, 91, 96, 98, + 94, 88, 85, 81, 76, 73, 70, 66, 66, 70, 76, 80, 84, 91, 92, 87, + 86, 83, 78, 76, 78, 81, 85, 88, 91, 96, 93, 86, 83, 78, 71, 68, + 64, 61, 64, 71, 74, 78, 84, 86, 80, 76, 72, 64, 59, 56, 55, 59, + 66, 69, 74, 79, 76, 69, 64, 57, 48, 43, 39, 39, 45, 52, 56, 62, + 63, 55, 47, 41, 31, 21, 15, 8, 5, 9, 16, 24, 31, 35, 33, 26, + 19, 10, 0, -6, -9, -7, -7, -13, -17, -22, -26, -31, -34, -37, -40, -42, + -44, -46, -48, -50, -51, -54, -56, -58, -61, -64, -67, -70, -74, -78, -82, -86, + -90, -93, -97, -99, -102, -104, -106, -108, -109, -110, -111, -112, -113, -113, -114, -114, + -115, -115, -115, -115, -115, -114, -113, -111, -109, -107, -104, -100, -97, -93, -90, -87, + -84, -82, -80, -78, -76, -74, -73, -71, -69, -67, -65, -61, -58, -53, -48, -42, + -35, -28, -21, -13, -6, 1, 8, 15, 21, 26, 31, 35, 38, 41, 44, 46, + 48, 50, 52, 55, 58, 61, 64, 68, 72, 76, 80, 83, 87, 90, 92, 94, + 96, 98, 99, 100, 101, 102, 102, 103, 103, 103, 103, 104, 103, 103, 103, 102, + 101, 99, 97, 94, 92, 88, 85, 81, 78, 74, 71, 67, 64, 61, 58, 55, + 53, 51, 49, 47, 46, 44, 42, 40, 37, 34, 30, 26, 22, 17, 12, 8, + 3, -1, -5, -9, -13, -16, -20, -23, -26, -29, -31, -33, -35, -37, -38, -40, + -42, -44, -46, -48, -51, -54, -56, -59, -61, -64, -65, -67, -69, -70, -72, -74, + -75, -77, -78, -80, -81, -82, -83, -84, -85, -86, -86, -87, -88, -89, -90, -90, + -91, -92, -92, -92, -92, -92, -92, -91, -91, -92, -92, -92, -93, -93, -94, -94, + -94, -95, -95, -95, -95, -95, -95, -95, -95, -95, -94, -93, -92, -91, -90, -89, + -87, -86, -85, -85, -85, -84, -84, -85, -85, -85, -85, -85, -85, -85, -85, -85, + -84, -83, -82, -81, -79, -77, -75, -73, -70, -68, -65, -63, -62, -60, -59, -59, + -59, -59, -59, -59, -59, -60, -59, -59, -59, -58, -57, -55, -53, -50, -47, -44, + -40, -36, -32, -29, -25, -22, -20, -18, -17, -16, -15, -15, -16, -16, -16, -16, + -16, -16, -15, -13, -11, -9, -6, -2, 2, 6, 10, 15, 19, 22, 26, 29, + 31, 33, 35, 36, 36, 36, 36, 35, 35, 35, 35, 35, 36, 38, 40, 42, + 45, 48, 52, 55, 58, 61, 64, 67, 70, 72, 73, 74, 75, 76, 76, 76, + 75, 75, 74, 74, 74, 74, 74, 75, 77, 78, 80, 82, 83, 85, 87, 89, + 90, 91, 92, 93, 94, 94, 94, 94, 94, 93, 93, 92, 91, 91, 90, 90, + 90, 90, 91, 91, 92, 92, 93, 93, 94, 94, 94, 94, 94, 94, 94, 94, + 93, 93, 92, 92, 91, 90, 89, 88, 87, 87, 86, 86, 85, 85, 85, 84, + 84, 83, 83, 82, 81, 80, 79, 78, 77, 77, 76, 75, 74, 72, 71, 70, + 68, 67, 65, 64, 63, 61, 60, 58, 57, 55, 53, 50, 48, 45, 43, 40, + 38, 36, 34, 32, 30, 29, 27, 25, 23, 21, 19, 17, 14, 12, 9, 6, + 3, 0, -4, -8, -12, -17, -21, -25, -29, -33, -36, -39, -42, -45, -47, -49, + -51, -53, -55, -58, -60, -63, -65, -68, -71, -74, -77, -81, -84, -87, -91, -94, + -97, -99, -102, -104, -105, -107, -108, -109, -110, -111, -111, -112, -112, -113, -113, -113, + -113, -113, -113, -112, -111, -109, -107, -105, -102, -99, -96, -93, -90, -87, -84, -82, + -79, -77, -75, -73, -70, -69, -66, -64, -60, -58, -53, -49, -44, -39, -32, -27, + -19, -14, -8, -3, 3, 11, 22, 10, 8, 1, 1, 1, 1, 1, 2, 2, + 2, 2, 3, 3, 3, 3, 4, 4, 5, 5, 6, 5, 6, 6, 6, 6, + 6, 6, 7, 5, 7, 5, 6, 4, 6, 4, 4, 4, 4, 3, 3, 2, + 3, 1, 3, -2, 2, 0, 0, 0, 0, -2, -1, -2, -3, -3, 0, -5, + -1, -2, -2, -2, -1, 0, -3, -1, -1, 0, 1, -1, 0, -1, 0, 0, + 1, 0, 0, 1, -1, 1, -1, 1, -2, -1, -3, 0, -2, -1, -2, -2, + -2, -3, -2, -3, -4, -5, -6, -5, -9, -8, -9, -9, -9, -11, -10, -13, + -14, -14, -15, -16, -15, -17, -19, -19, -21, -18, -21, -20, -22, -20, -24, -21, + -22, -19, -20, -21, -17, -19, -16, -17, -15, -17, -13, -11, -10, -7, -5, -3, + 2, 6, 4, 8, 9, 18, 14, 31, 25, 24, 25, 24, 21, 13, 15, 15, + 11, 9, 1, 4, -20, -18, -38, -44, -57, -57, -55, -55, -52, -55, -46, -47, + -40, -32, -26, -19, -16, -2, 3, 13, 19, 28, 30, 37, 40, 44, 39, 38, + 35, 34, 37, 41, 48, 51, 53, 58, 61, 70, 74, 76, 76, 80, 81, 86, + 83, 83, 78, 78, 73, 69, 65, 55, 47, 40, 36, 29, 23, 16, 14, 8, + -2, -4, -11, -11, -19, -22, -26, -25, -34, -39, -40, -41, -45, -49, -51, -57, + -56, -58, -59, -66, -70, -70, -72, -65, -64, -59, -53, -49, -45, -34, -29, -21, + -15, -10, -6, -6, -3, -4, 2, 3, 3, 3, -1, -3, -11, -11, -13, -16, + -22, -24, -27, -32, -34, -37, -35, -31, -30, -26, -25, -22, -21, -15, -13, -15, + -10, -12, -12, -7, 2, 15, 22, 27, 24, 28, 22, 22, 21, 22, 17, 13, + 14, 9, 5, 2, -8, -12, -16, -14, -17, -17, -17, -17, -14, -8, -3, -3, + 0, 5, 3, 5, 6, 3, -2, -6, -9, -11, -13, -18, -19, -29, -42, -61, + -72, -79, -81, -83, -82, -79, -76, -65, -54, -42, -33, -24, -14, 0, 18, 33, + 48, 62, 75, 87, 93, 99, 100, 102, 102, 104, 102, 100, 100, 96, 93, 95, + 96, 105, 109, 112, 111, 110, 106, 106, 104, 102, 97, 93, 85, 80, 71, 60, + 48, 36, 26, 12, 0, -5, -13, -21, -28, -31, -36, -42, -49, -53, -56, -59, + -61, -63, -64, -64, -63, -67, -70, -77, -75, -77, -78, -79, -80, -81, -80, -75, + -69, -64, -57, -50, -43, -35, -26, -16, -6, 6, 13, 17, 22, 26, 25, 27, + 27, 26, 23, 19, 11, 5, -5, -12, -19, -24, -31, -37, -42, -45, -50, -49, + -48, -47, -43, -41, -38, -38, -37, -35, -35, -37, -42, -40, -33, -27, -20, -12, + -11, -13, -10, -9, -10, -10, -10, -13, -11, -9, -8, -11, -13, -16, -18, -17, + -15, -15, -14, -12, -8, -3, 3, 8, 16, 22, 25, 31, 34, 36, 36, 34, + 31, 25, 23, 24, 26, 23, 13, -1, -16, -29, -38, -45, -51, -56, -57, -54, + -48, -39, -34, -29, -20, -10, 0, 13, 27, 39, 54, 68, 79, 87, 92, 94, + 96, 94, 92, 89, 87, 82, 76, 72, 71, 74, 76, 81, 83, 83, 84, 84, + 85, 85, 82, 81, 82, 80, 75, 71, 66, 57, 46, 34, 24, 15, 5, -2, + -8, -13, -19, -26, -31, -37, -41, -44, -48, -53, -54, -53, -54, -54, -57, -61, + -64, -67, -70, -72, -75, -77, -79, -79, -76, -73, -70, -63, -58, -53, -47, -38, + -29, -21, -13, -6, 0, 4, 7, 7, 8, 8, 6, 5, -1, -8, -15, -22, + -30, -36, -41, -47, -51, -54, -56, -58, -59, -56, -50, -45, -42, -37, -31, -26, + -23, -23, -23, -24, -21, -14, -6, 2, 8, 12, 15, 18, 21, 20, 20, 20, + 20, 21, 23, 22, 18, 13, 10, 8, 6, 5, 4, 3, 2, 2, 4, 7, + 10, 13, 18, 22, 24, 26, 28, 27, 21, 14, 8, 5, 4, 2, -3, -12, + -24, -37, -50, -59, -67, -76, -80, -79, -75, -69, -61, -55, -47, -38, -27, -15, + -2, 11, 27, 43, 58, 71, 82, 90, 94, 96, 98, 98, 98, 95, 89, 84, + 81, 79, 81, 85, 88, 89, 91, 92, 92, 90, 89, 89, 88, 85, 82, 79, + 75, 67, 58, 48, 37, 25, 14, 4, -4, -10, -17, -24, -31, -37, -42, -47, + -51, -56, -59, -59, -59, -59, -61, -63, -65, -67, -70, -72, -74, -76, -78, -78, + -78, -75, -70, -66, -61, -56, -50, -41, -33, -23, -14, -6, 2, 10, 16, 19, + 21, 23, 24, 24, 22, 19, 13, 7, 0, -6, -14, -20, -25, -27, -32, -37, + -39, -39, -38, -36, -33, -30, -27, -22, -19, -19, -20, -23, -24, -22, -18, -13, + -8, -4, 0, 2, 5, 6, 5, 3, 2, 4, 6, 6, 5, 1, -2, -6, + -8, -9, -10, -11, -13, -12, -12, -11, -9, -4, 0, 4, 8, 13, 18, 20, + 19, 14, 10, 6, 4, 4, 4, 0, -8, -17, -28, -38, -49, -60, -68, -72, + -72, -70, -65, -59, -54, -46, -37, -27, -17, -5, 8, 22, 37, 51, 66, 77, + 84, 88, 91, 93, 94, 94, 91, 85, 79, 75, 74, 76, 77, 80, 83, 85, + 85, 85, 86, 86, 85, 85, 85, 83, 81, 77, 70, 64, 55, 44, 32, 22, + 13, 6, -1, -9, -16, -22, -27, -32, -38, -43, -46, -47, -47, -47, -48, -49, + -49, -50, -52, -54, -56, -59, -62, -64, -66, -65, -64, -61, -59, -56, -53, -48, + -41, -33, -25, -17, -10, -2, 4, 9, 13, 15, 16, 17, 17, 15, 11, 7, + 1, -7, -15, -22, -27, -33, -38, -43, -47, -49, -50, -50, -49, -46, -42, -37, + -31, -28, -28, -29, -30, -29, -26, -22, -17, -13, -8, -3, 2, 6, 7, 6, + 5, 6, 8, 10, 12, 11, 8, 5, 3, 1, -1, -2, -3, -4, -6, -7, + -6, -3, 0, 1, 5, 10, 16, 20, 21, 19, 15, 10, 8, 6, 6, 4, + 0, -5, -12, -22, -33, -45, -57, -65, -70, -72, -70, -68, -64, -58, -51, -44, + -36, -24, -13, -2, 11, 27, 43, 58, 70, 78, 83, 88, 92, 96, 97, 93, + 89, 85, 81, 80, 81, 83, 86, 88, 90, 91, 91, 91, 91, 91, 91, 91, + 89, 86, 83, 79, 72, 63, 52, 41, 30, 21, 13, 4, -5, -11, -17, -23, + -31, -38, -44, -47, -49, -50, -52, -54, -55, -57, -57, -58, -60, -63, -66, -69, + -72, -74, -73, -72, -70, -69, -67, -64, -59, -53, -45, -37, -30, -22, -14, -7, + -2, 3, 8, 10, 12, 12, 13, 12, 8, 3, -4, -10, -16, -21, -27, -33, + -37, -41, -44, -46, -48, -48, -45, -48, -43, -37, -33, -31, -32, -33, -32, -29, + -26, -22, -18, -12, -5, 1, 6, 9, 9, 9, 9, 11, 14, 16, 16, 14, + 12, 8, 5, 3, 2, 1, -1, -3, -4, -4, -2, -1, 2, 5, 11, 18, + 24, 27, 27, 24, 20, 17, 15, 13, 11, 9, 5, -1, -10, -22, -35, -49, + -61, -70, -75, -77, -76, -73, -69, -63, -56, -47, -36, -25, -13, 0, 16, 34, + 52, 67, 79, 88, 95, 101, 106, 109, 108, 105, 100, 95, 92, 90, 91, 93, + 96, 99, 100, 101, 101, 101, 101, 101, 101, 100, 97, 95, 91, 85, 78, 67, + 55, 43, 31, 21, 11, 1, -7, -14, -21, -29, -37, -45, -51, -54, -56, -58, + -60, -62, -64, -65, -66, -67, -69, -72, -76, -80, -82, -84, -83, -82, -80, -79, + -77, -73, -67, -60, -51, -42, -34, -25, -16, -8, -2, 4, 9, 12, 13, 14, + 14, 13, 9, 3, -5, -12, -18, -25, -31, -37, -42, -47, -50, -53, -54, -53, + -48, -41, -36, -32, -31, -31, -32, -31, -28, -25, -22, -17, -12, -5, 1, 1, + -2, -1, -9, -9, -6, 5, 6, -1, -10, 8, 24, 11, -2, -14, -9, -15, + -13, 5, 14, 12, -6, -1, -12, 1, -9, 12, 12, 10, 5, -19, -11, -13, + -2, 8, 5, 1, -2, -3, 9, -6, 6, 5, 6, -3, -17, -7, 3, 2, + -1, 0, 7, -7, 5, 4, 6, -18, -24, 6, 20, -1, -4, -1, 10, 3, + -10, 8, 7, -11, -17, -15, 5, 18, 4, 1, 8, -16, -4, 0, 11, 9, + -10, -15, 0, -22, -12, 19, 34, 16, -9, -16, -7, -12, -10, 13, 23, -1, + -10, -2, -3, -11, 13, 7, -6, -9, 3, 11, -10, -18, 12, 22, 7, -27, + -29, -4, 20, 20, 10, 8, -16, -26, -6, 22, 21, 7, 15, 8, -50, -50, + -7, 35, 22, -13, 32, 41, -33, -46, -10, 23, -7, -25, 23, 21, -38, -36, + 14, 44, 2, 2, 34, -14, -51, -29, 11, 19, 7, 22, 13, -23, -21, -8, + -9, 1, 14, 26, 26, -8, -34, -33, 4, 1, -6, -2, 16, -7, -23, 12, + 27, 5, 6, 6, 0, -8, 0, -1, -17, -13, -12, 3, 9, 4, 11, 23, + 36, 0, -43, -16, 4, -21, -26, 27, 16, -25, 3, 65, 4, -34, 24, -10, + -38, -14, 13, 4, -15, 36, 44, -42, -51, 20, -5, -6, 68, 20, -18, -39, + -11, 9, 17, 6, -33, -20, -13, 48, 30, 22, -4, -9, -53, -20, 32, 32, + -16, 17, -11, -36, -8, -5, 39, 28, 33, 21, -64, -48, 3, -22, 15, 62, + -26, 0, 3, 5, 73, -14, -48, -20, -59, 4, 70, 60, -7, -2, -88, -22, + -17, 39, 17, 33, -3, 15, 28, -47, -80, -37, 5, 7, 104, 16, -99, -92, + -36, 109, 78, 26, -15, -92, -21, 62, 48, -51, -81, -25, 55, 63, 35, 21, + -115, -54, 101, 73, -41, -110, -66, 50, 107, 45, -8, -109, -38, 12, 102, 3, + 17, -45, -2, -36, 39, 46, -12, -28, -27, -17, 17, -18, 82, -5, -3, -25, + -5, -14, 15, 9, -3, -17, -6, 2, 7, -36, -13, 6, 21, -23, -20, 16, + -18, 3, -2, 26, 0, 13, -23, -2, -19, -28, -18, 15, 12, 22, -4, 23, + -17, -22, -9, -18, -4, 11, 13, 0, 34, -16, -20, 26, 23, 15, -4, -25, + 7, 8, -9, 8, 44, 1, -40, 17, -32, 9, -30, -52, 52, 3, 2, -21, + 83, 58, -14, -46, -61, -12, -67, -20, 64, 72, 57, -10, 5, 1, -77, 31, + -47, -39, 12, 22, 57, 28, 0, 9, -76, 15, -74, 33, -12, 39, 114, -35, + -36, -38, -23, 27, -21, 14, 56, 47, 6, -72, -61, -4, 18, -4, 19, 13, + 45, 71, 48, -1, -125, -52, -56, -20, -18, -12, 51, 78, 68, -46, 32, -40, + -29, -28, -81, -25, 75, 42, 58, -38, 1, -29, -34, 31, -36, -14, 10, 64, + 37, 2, -31, -72, -17, -33, 30, -52, -54, 25, 43, 70, 81, -9, -73, 4, + -65, 15, -28, 25, 0, 28, 19, 51, -26, 6, 0, -37, -15, -22, -20, -16, + -5, 50, 56, 67, 25, 16, -35, -29, -14, -39, 19, -24, -52, -13, -32, -10, + 39, 33, 59, 6, 37, 55, 11, -9, -35, -15, -57, -56, -36, -34, 19, 19, + 6, 20, 17, -11, 5, 26, 19, 16, 7, -20, -26, -55, -62, -36, -18, 19, + 37, 47, 25, -6, -14, 1, -4, -13, 12, 23, 34, 38, 41, 33, 31, -10, + -56, -52, -49, -31, -40, -21, -12, 0, 5, 12, 22, 22, 21, 31, 12, 2, + -8, -4, -18, -7, 3, 1, -1, 11, 12, 18, 17, 9, -2, -12, -13, -11, + -1, 8, 3, 3, 2, 5, -5, -16, -15, -13, -8, -12, -9, -2, -1, 2, + 7, 10, 7, 11, 14, 7, -1, -4, 5, -3, -2, 0, -6, -10, -1, -5, + 3, 9, 0, -8, -9, -6, -6, 0, 6, 3, 6, 7, 10, 0, -8, -3, + -5, -1, -8, -7, -4, -3, -3, 0, -1, -6, 2, 7, 7, 5, 4, 10, + 5, 8, -1, -11, -15, -11, -15, -10, -1, -8, -12, -5, 1, 3, 6, 8, + 11, 18, 22, 26, 10, -10, -1, -15, -3, -21, -16, -14, -12, -7, -8, -18, + -20, -11, 9, 20, 27, 26, 11, 1, 21, 6, 3, -9, -15, -9, -20, 3, + 5, 21, 14, 6, 11, -21, -22, -6, -21, -23, -18, 11, 6, 5, 21, 9, + 23, 16, -3, -30, -7, -27, -4, 5, 18, 22, 16, 2, 7, -1, -2, -10, + -14, -10, -17, -10, -15, -16, 3, 12, 30, 18, -1, -6, -15, -3, 5, 11, + -18, -2, 8, 21, 11, -13, -4, -30, -7, 0, 12, 25, -3, 17, 14, -20, + -6, -27, -41, -11, -12, 23, -8, 13, 24, 18, 27, -11, -8, -12, -2, 17, + 23, 13, -20, -21, -2, -21, -34, -46, -23, 28, 48, 9, -10, 8, 29, 27, + 5, -29, -12, 13, -5, -2, -35, 1, 3, 24, 13, 17, -18, -30, -21, 14, + -1, 6, -8, 48, 45, -7, -34, -49, -32, -6, -26, 20, 29, 76, 30, -21, + -66, -36, -15, 40, -5, 29, 3, 10, -39, -25, -2, 24, 19, 19, -4, -8, + 3, -22, -23, -18, 13, 17, -3, -25, 23, 66, 26, -18, -27, -34, -30, -30, + 36, 25, 28, -22, -17, -7, -22, 21, 18, 42, 8, -25, -28, -31, -10, 15, + 18, 0, -1, -5, 16, -12, 13, 13, 12, -8, -37, -9, 13, -5, 8, -3, + 13, -8, 4, 24, -16, -43, -18, 26, 26, -11, -9, 19, 9, -15, 9, 15, + -12, -31, -27, 8, 29, 5, 7, 17, -33, -14, 14, 23, -1, -18, -18, -4, + -35, -17, 47, 71, -16, -20, -11, -16, -25, 6, 37, 14, -18, 1, -8, -14, + 10, 14, 2, -20, 0, 20, -10, -25, 14, 32, 7, -39, -38, -3, 34, 25, + 13, 3, -24, -34, 5, 38, 18, 7, 29, -30, -74, -41, 36, 40, -12, 26, + 55, -17, -59, -26, 28, -2, -31, 24, 25, -44, -39, 21, 44, -1, 10, 33, + -34, -50, -12, 18, 13, 20, 17, -6, -31, -10, -6, -1, 7, 12, 14, 6, + -16, -24, 6, 9, -16, -16, 6, 2, -10, 13, 12, -10, 0, 11, 11, 10, + -3, -22, -22, -12, -7, 19, 17, -2, -12, 6, 16, 7, -11, -1, -20, -22, + -8, 26, 16, -3, 12, 1, -33, 2, 30, -23, -5, 28, -17, -19, 21, 9, + -28, -14, 25, -1, 4, 24, 0, -26, -9, 7, 2, -2, 20, -10, -11, 5, + -3, -4, 8, -9, 14, 18, 25, -22, -15, -22, -3, -12, 27, 30, 15, -11, + -26, -4, 15, -7, -14, 23, -23, -4, 34, -2, -38, 14, -11, -24, 16, 34, + 11, -13, 3, -3, -19, -34, 0, -3, 24, 43, 1, -12, -38, -25, -11, 23, + 35, 12, -28, -25, -16, 7, 22, 1, -10, 8, 8, -3, 6, -24, -20, -13, + 9, 31, 12, -16, 7, -29, 5, 8, -28, 3, 4, 12, 26, -9, -15, -5, + -20, 9, 21, 0, 1, -9, 0, 8, -3, -7, -9, -3, 22, 8, 3, -11, + -9, -11, 3, 15, 9, -10, 1, -3, -3, -2, -5, 9, 0, 12, 7, -15, + -7, 0, -8, 5, 9, -5, 7, -7, 10, 4, -11, -2, -8, -4, 9, 9, + 0, -2, -11, -3, -4, 3, 4, 3, -2, 3, 3, -8, -9, -2, 0, 3, + 5, -1, -10, -7, 2, 8, 3, 0, -5, -5, 2, 4, -2, -5, -3, 2, + 3, 0, 2, -5, -3, 3, 2, -2, -4, -2, 1, 2, 1, 0, 0, 0, + 0, -1, -7, -9, -5, 0, 2, 2, 5, 6, 0, -11, -13, -5, 3, 1, + 0, 0, 1, -3, -9, -6, -1, 5, 3, -3, -5, -3, -1, -4, -3, -1, + 2, -2, -9, -7, -2, -5, -18, -31, -36, -36, -41, -38, -29, -21, -27, -31, + -26, -4, 37, 65, 67, 44, 22, 10, 2, -4, 8, 32, 44, 38, 24, 17, + 9, 4, 3, 12, 26, 32, 32, 23, 16, 7, 1, -7, -13, -8, 1, -5, + -39, -72, -79, -64, -49, -40, -24, -1, 12, 0, -25, -44, -43, -30, -14, 1, + 13, 13, 4, 4, 16, 34, 46, 55, 65, 73, 67, 53, 54, 58, 62, 60, + 51, 38, 33, 20, -7, -27, -40, -46, -55, -58, -41, -9, 7, 8, 2, -26, + -49, -71, -92, -101, -93, -80, -70, -71, -73, -65, -67, -69, -61, -42, -15, 15, + 18, -5, -33, -54, -54, -40, -18, 2, 21, 21, 3, -28, -52, -33, 9, 35, + 33, 30, 34, 45, 46, 43, 54, 63, 65, 61, 56, 43, 45, 59, 77, 96, + 104, 112, 115, 100, 78, 53, 22, -3, -6, 5, 24, 37, 38, 35, 25, 3, + -19, -38, -51, -46, -33, -34, -42, -47, -48, -38, -27, -30, -40, -48, -45, -30, + -24, -38, -44, -43, -47, -34, -13, 7, 27, 30, 9, -18, -38, -22, 19, 47, + 70, 83, 68, 28, -13, -41, -41, -19, -1, 10, 8, 4, 4, -7, -12, 6, + 32, 42, 31, 0, -39, -71, -99, -115, -111, -85, -56, -46, -61, -74, -66, -45, + -22, 4, 21, 27, 25, 1, -30, -51, -37, 4, 37, 40, 26, 17, 12, 12, + 5, 1, 2, 12, 29, 43, 44, 45, 54, 45, 28, 10, 13, 26, 32, 43, + 59, 67, 62, 60, 66, 72, 61, 34, 11, 0, 1, -6, -18, -12, 19, 47, + 51, 32, 9, -8, -22, -26, -27, -30, -29, -12, 7, 18, 13, -1, -11, -11, + 5, 16, 14, 11, 5, -19, -47, -54, -29, 13, 37, 42, 33, 9, -17, -31, + -21, 14, 61, 81, 68, 39, 4, -26, -46, -38, -17, -1, 1, -4, -14, -25, + -23, -4, 24, 43, 49, 37, 4, -48, -97, -123, -116, -89, -66, -65, -73, -67, + -64, -66, -69, -46, 3, 36, 27, -3, -25, -39, -38, -39, -36, -24, -9, 5, + 13, 13, 4, -1, -13, -15, 0, 22, 47, 65, 76, 67, 35, 3, -4, 6, + 27, 47, 58, 68, 72, 73, 72, 66, 59, 62, 61, 49, 28, -5, -30, -27, + 9, 40, 51, 46, 40, 28, 1, -30, -56, -57, -41, -13, 5, 12, 7, -11, + -38, -54, -40, -16, 12, 23, 13, -16, -49, -62, -55, -29, 4, 38, 45, 28, + -5, -36, -36, -5, 39, 68, 77, 73, 55, 8, -35, -46, -29, -15, -15, -16, + -12, -9, -23, -30, -18, 16, 48, 51, 24, -18, -45, -72, -96, -111, -101, -80, + -67, -71, -79, -77, -70, -46, -22, -7, -4, -5, -4, -2, -15, -37, -43, -42, + -27, -5, 9, 27, 38, 27, 4, -14, -15, 6, 30, 61, 93, 90, 52, 16, + 2, 1, 5, 11, 34, 64, 79, 71, 48, 35, 43, 61, 59, 46, 27, 1, + -22, -33, -25, -9, 15, 37, 56, 54, 28, -10, -44, -58, -49, -27, -8, 20, + 29, 0, -42, -66, -60, -34, -7, 16, 30, 15, -20, -50, -64, -49, -11, 21, + 34, 34, 17, -7, -31, -29, 3, 43, 69, 78, 73, 45, 10, -20, -32, -33, + -26, -12, -6, -18, -41, -44, -27, -6, 10, 17, 19, 18, -4, -49, -87, -108, + -100, -84, -87, -93, -83, -67, -54, -45, -45, -35, -23, -13, 6, 17, 14, 1, + -22, -40, -35, -18, 2, 28, 57, 63, 33, -7, -21, -4, 23, 57, 89, 102, + 94, 68, 37, 8, -4, 4, 37, 71, 88, 79, 54, 46, 55, 62, 55, 53, + 54, 46, 20, -14, -40, -41, -16, 15, 44, 60, 59, 30, -21, -61, -70, -54, + -26, 10, 29, 19, -16, -49, -63, -58, -33, 4, 29, 26, -1, -33, -49, -50, + -34, -9, 16, 34, 34, 9, -20, -25, -9, 13, 29, 54, 87, 91, 56, 11, + -12, -11, -12, -20, -22, -17, -11, -12, -22, -25, -15, 3, 19, 19, 9, -11, + -38, -62, -76, -92, -107, -109, -95, -68, -53, -49, -49, -58, -63, -48, -25, -5, + 12, 12, -7, -36, -56, -56, -32, 8, 50, 64, 36, 6, -10, -15, -11, 9, + 47, 94, 118, 100, 58, 14, -3, 3, 19, 44, 72, 83, 78, 75, 66, 53, + 45, 52, 66, 70, 52, 22, -8, -36, -36, -14, 21, 63, 84, 63, 14, -29, + -55, -54, -42, -12, 28, 40, 14, -24, -52, -58, -42, -22, 6, 19, 16, -5, + -34, -49, -43, -24, -12, 2, 14, 22, 10, -10, -20, -16, 3, 28, 60, 72, + 61, 42, 25, 1, -26, -44, -46, -31, -25, -26, -32, -30, -24, -12, -12, -15, + 0, 6, -3, -23, -47, -79, -112, -128, -115, -84, -61, -45, -42, -51, -64, -68, + -61, -33, 9, 29, 12, -28, -54, -64, -56, -30, 9, 36, 41, 34, 10, -18, + -38, -29, 13, 70, 105, 106, 79, 48, 31, 12, -1, 12, 51, 78, 89, 87, + 75, 66, 49, 44, 56, 73, 79, 66, 23, -23, -42, -39, -9, 31, 65, 75, + 52, 7, -32, -54, -57, -30, 3, 24, 19, 2, -18, -39, -50, -39, -10, 8, + 10, -2, -12, -18, -21, -29, -33, -16, 11, 28, 17, 1, -4, 3, -3, -6, + 13, 42, 64, 67, 56, 29, 2, -21, -36, -42, -40, -25, -15, -10, -7, -10, + -27, -38, -24, 2, 19, 14, -6, -44, -86, -115, -121, -109, -81, -45, -27, -36, + -58, -76, -81, -53, -13, 11, 8, -11, -24, -40, -58, -62, -30, 11, 42, 44, + 17, -15, -36, -38, -22, 15, 53, 84, 88, 73, 52, 19, -6, -9, 13, 44, + 71, 88, 93, 79, 54, 42, 46, 67, 82, 79, 54, 20, -10, -28, -27, 0, + 46, 70, 61, 29, 2, -18, -38, -45, -23, 7, 16, 10, -8, -22, -26, -30, + -32, -23, -13, -2, 6, -6, -15, -16, -18, -20, -9, 0, 2, 11, 19, 17, + -2, -21, -12, 14, 33, 50, 65, 61, 43, 19, -17, -44, -50, -42, -21, 1, + 11, 1, -31, -56, -45, -22, -1, 17, 18, -4, -44, -95, -126, -123, -95, -56, + -36, -41, -51, -59, -68, -60, -38, -15, 5, 14, 7, -17, -47, -61, -37, 1, + 27, 33, 24, 7, -13, -30, -43, -26, 13, 47, 70, 74, 68, 48, 12, -19, + -14, 14, 46, 74, 81, 75, 64, 52, 48, 56, 67, 82, 78, 44, 9, -12, + -20, -8, 18, 41, 57, 46, 23, 0, -23, -33, -21, -10, -10, -2, 3, 5, + -2, -19, -33, -32, -24, -16, -11, -14, -6, 7, -2, -20, -25, -16, -6, 6, + 17, 27, 22, 2, -10, -11, 0, 24, 51, 68, 79, 65, 25, -19, -49, -48, + -30, -9, 8, 10, -12, -40, -57, -57, -34, -1, 25, 24, -7, -56, -95, -111, + -102, -84, -69, -57, -44, -42, -59, -74, -71, -47, -17, 0, 3, -6, -21, -37, + -38, -27, -6, 15, 23, 22, 12, -4, -23, -32, -26, 1, 36, 63, 82, 78, + 46, 12, -1, 2, 20, 41, 64, 81, 79, 66, 59, 61, 67, 75, 76, 66, + 49, 27, 5, -7, 2, 24, 41, 44, 38, 28, 13, -5, -19, -21, -17, -11, + -2, 4, 4, -2, -14, -28, -32, -27, -21, -16, -13, -1, 6, -4, -21, -25, + -17, -7, 6, 0, 0, -4, -4, -5, -8, -4, 3, 8, 6, 1, 1, 2, + 3, 3, -2, -7, -11, -10, -5, -2, 4, 6, 0, -2, -5, -4, -4, -9, + -9, -7, -11, -11, -10, -7, 4, 0, -4, -4, -1, 4, 0, -4, -3, -5, + -6, -5, -4, 4, -1, 2, 11, 5, -13, -20, -30, -49, -50, -34, -22, -33, + -27, -20, -17, 0, 34, 70, 73, 42, 3, -26, -37, -25, -1, 25, 48, 71, + 75, 44, 22, 45, 69, 57, 44, 52, 58, 24, -23, -41, -50, -58, -67, -82, + -66, -29, -29, -41, -34, -19, -4, -4, -1, 20, 50, 56, 35, 12, 4, -8, + -15, 4, 28, 44, 46, 34, 17, 2, 0, 11, 28, 42, 22, -28, -51, -45, + -34, -39, -37, -19, -17, -30, -32, -18, -4, 9, 19, 38, 35, 3, -24, -35, + -40, -23, -11, -25, -47, -52, -51, -58, -61, -52, -47, -37, -17, -5, -5, -16, + -31, -24, -11, -1, -3, -23, -40, -48, -40, -12, 15, 25, 17, -5, -2, 14, + 21, 15, -12, -26, -18, -2, 28, 48, 55, 52, 42, 35, 35, 42, 38, 36, + 40, 53, 55, 52, 44, 36, 49, 57, 56, 57, 55, 50, 39, 27, 31, 30, + 15, 11, 12, 6, 4, 14, 28, 23, 1, -6, -17, -35, -44, -41, -33, -22, + -9, -6, -12, -15, -13, -27, -29, -7, 14, -5, -55, -71, -49, -33, -37, -46, + -33, -18, -43, -89, -96, -65, -23, 2, 8, 20, 24, -11, -50, -51, -12, 15, + 4, 1, 20, 47, 53, 43, 52, 77, 98, 114, 110, 100, 88, 53, 10, -29, + -55, -71, -83, -77, -58, -55, -57, -52, -48, -47, -46, -12, 34, 59, 52, 25, + -10, -33, -21, 18, 49, 54, 46, 18, 13, 30, 41, 48, 54, 53, 44, 24, + 1, -13, -25, -43, -38, -28, -35, -55, -71, -64, -40, -13, 10, 24, 38, 41, + 21, -1, -11, 1, 15, 7, -6, -13, -39, -57, -64, -51, -20, -12, -24, -37, + -30, -4, 17, 21, 12, -7, -16, -15, -7, 6, 1, -20, -34, -30, -1, 32, + 44, 36, 22, 25, 21, 6, 1, -2, -13, -5, 19, 28, 24, 12, 11, 16, + 19, 38, 54, 49, 38, 28, 28, 39, 52, 49, 32, 25, 33, 45, 49, 39, + 40, 46, 20, -9, -6, 6, 1, -22, -29, 10, 48, 33, -17, -51, -55, -44, + -49, -50, -36, -33, -57, -84, -71, -21, 11, 13, 4, -1, -8, -32, -45, -32, + -10, 2, -13, -37, -39, -42, -57, -65, -63, -36, -11, 10, 33, 22, -12, -34, + -28, -12, 2, 8, 6, -2, -4, 0, 10, 22, 36, 57, 82, 104, 122, 127, + 109, 70, 17, -28, -45, -36, -20, -33, -68, -102, -114, -103, -76, -45, -20, -7, + -11, -10, -2, 6, 0, -14, -5, 30, 48, 29, 3, -8, 10, 39, 67, 86, + 83, 59, 32, 17, 32, 46, 40, 11, -29, -48, -57, -68, -69, -57, -43, -26, + -13, -2, 1, 1, 3, 4, 8, 21, 20, 11, 3, -2, -6, -26, -39, -33, + -34, -36, -28, -23, -27, -28, -17, -1, 0, -6, -10, -9, -7, -12, -26, -44, + -54, -38, -16, 0, 18, 27, 17, -3, -18, -3, 19, 11, -9, -7, 10, 14, + 5, 5, 18, 29, 29, 12, 16, 38, 43, 14, 2, 24, 55, 59, 33, 17, + 24, 44, 65, 75, 77, 55, 15, -16, -20, 6, 31, 27, 17, 18, 19, 17, + 7, 0, -5, -20, -22, -25, -49, -69, -73, -58, -45, -29, -4, 9, -1, -23, + -51, -52, -24, -2, 11, 12, -16, -51, -75, -77, -67, -59, -59, -54, -35, -15, + -9, -9, -9, -7, -8, -12, -1, 15, 22, 10, -14, -34, -28, -14, 11, 64, + 113, 127, 117, 97, 87, 84, 68, 50, 37, 36, 24, -15, -58, -78, -84, -71, + -40, -14, -12, -34, -48, -41, -14, 20, 37, 35, 16, -6, 1, 14, 15, 20, + 23, 24, 38, 58, 69, 57, 40, 54, 73, 75, 65, 40, -3, -49, -68, -56, + -42, -42, -53, -59, -44, -23, -9, -3, -11, -18, -13, -11, -5, 3, 13, 4, + -25, -39, -22, -14, -16, -27, -38, -37, -42, -55, -51, -21, 8, 10, -8, -12, + -4, -10, -39, -55, -38, -13, -4, -11, -15, -3, 15, 12, 2, 11, 28, 34, + 15, -5, 3, 11, 6, 12, 25, 25, 13, 10, 15, 27, 48, 55, 38, 23, + 17, 23, 32, 23, 32, 57, 75, 75, 52, 22, 10, 5, 12, 28, 33, 23, + 2, -14, -4, 19, 30, 25, 15, 1, -27, -64, -78, -67, -49, -45, -48, -42, + -31, -25, -40, -50, -39, -18, -4, 13, 19, 12, -10, -43, -59, -53, -47, -54, + -61, -51, -20, -2, -12, -23, -25, -18, 5, 33, 51, 45, 16, -16, -46, -53, + -38, -6, 33, 57, 74, 81, 75, 77, 89, 105, 114, 110, 83, 39, -6, -25, + -28, -39, -48, -52, -55, -59, -67, -67, -57, -42, -23, -3, 10, 3, -19, -33, + -30, -8, 20, 23, 2, -18, -17, 12, 40, 58, 65, 65, 66, 71, 64, 54, + 38, 1, -41, -62, -47, -26, -31, -49, -55, -42, -21, -17, -19, -10, -2, -3, + -10, -13, 2, 13, -10, -38, -27, 3, 8, -18, -46, -61, -65, -53, -36, -18, + -5, -6, -14, -22, -18, -12, -19, -29, -28, -21, -10, -15, -24, -18, -4, 16, + 23, 17, 14, 10, 9, 13, 15, 28, 35, 19, 4, 2, -2, 9, 34, 62, + 66, 43, 13, -2, 15, 42, 50, 48, 51, 56, 56, 45, 44, 45, 48, 40, + 33, 31, 27, 10, -10, -4, 16, 41, 52, 48, 31, -1, -36, -56, -50, -27, + -14, -25, -43, -60, -67, -47, -31, -38, -47, -40, -17, 13, 32, 28, -10, -50, + -68, -62, -40, -21, -20, -33, -58, -72, -63, -45, -28, -11, 18, 48, 42, 15, + -14, -43, -54, -40, -15, 4, 2, -5, 0, 20, 55, 91, 113, 120, 109, 89, + 77, 63, 43, 26, 20, 12, -13, -47, -69, -68, -53, -49, -49, -36, -28, -27, + -27, -28, -12, 5, 1, -9, -2, 14, 10, -25, -39, -6, 21, 35, 41, 53, + 73, 82, 74, 64, 54, 39, 9, -23, -37, -30, -22, -30, -52, -62, -54, -32, + -9, 2, 5, -3, -17, -25, -17, -1, 13, 8, -7, -12, -7, -7, -21, -40, + -51, -51, -38, -21, -16, -22, -29, -33, -23, -10, -2, -9, -24, -33, -33, -29, + -21, -8, 3, 2, -10, -18, -11, 8, 26, 32, 27, 21, 14, 7, 1, 3, + 12, 22, 35, 45, 43, 29, 13, 10, 20, 37, 54, 59, 45, 28, 28, 37, + 48, 55, 60, 60, 43, 17, 0, -3, 9, 24, 31, 31, 28, 28, 26, 14, + -5, -22, -31, -30, -21, -7, -8, -34, -63, -82, -80, -63, -45, -28, -14, -5, + 3, 2, -11, -27, -39, -33, -11, 2, -8, -39, -73, -95, -91, -54, -8, 19, + 16, 4, 5, 14, 14, 2, -8, -14, -19, -33, -45, -38, -19, 2, 21, 54, + 93, 106, 90, 74, 80, 97, 98, 76, 52, 34, 10, -18, -37, -36, -27, -35, + -52, -62, -56, -44, -39, -37, -29, -17, -8, -2, 3, 4, -4, -16, -27, -32, + -19, 1, 19, 41, 60, 70, 71, 67, 64, 61, 53, 38, 14, -8, -21, -29, + -34, -38, -39, -29, -15, 0, 5, -5, -19, -25, -16, 5, 19, 17, 6, -3, + -7, 0, -1, 1, -2, -5, 0, 0, 2, 0, -3, -2, 0, 1, 0, -2, + -2, -2, 0, 3, 3, -2, -5, -1, -1, -1, -4, 3, 9, 1, -1, -2, + -11, -7, 1, 9, 11, 8, -4, -11, -12, -9, -4, 18, 15, 14, 1, -22, + -29, -14, 3, 30, 29, 14, -2, -35, -43, -11, 13, 36, 42, 15, -16, -49, + -44, -10, 28, 47, 38, 11, -25, -66, -39, 4, 36, 58, 33, -3, -44, -65, + -29, 19, 52, 54, 23, -13, -59, -65, -15, 32, 69, 49, 8, -30, -74, -51, + 3, 43, 71, 40, -5, -48, -77, -31, 16, 57, 67, 24, -15, -67, -72, -12, + 36, 66, 59, 5, -31, -80, -51, 3, 49, 75, 37, -2, -59, -81, -28, 20, + 67, 66, 22, -23, -76, -65, -10, 41, 78, 48, 4, -36, -85, -47, 6, 59, + 80, 31, -8, -69, -82, -22, 29, 73, 63, 17, -31, -81, -63, -1, 47, 79, + 47, 3, -56, -90, -40, 19, 75, 73, 28, -25, -86, -74, -10, 48, 85, 56, + 6, -51, -93, -48, 11, 67, 86, 33, -11, -78, -87, -29, 36, 89, 66, 13, + -38, -91, -60, 2, 50, 83, 48, 0, -56, -90, -41, 16, 71, 78, 30, -17, + -80, -75, -20, 31, 82, 62, 15, -32, -85, -66, -7, 48, 84, 50, 4, -53, + -87, -44, 8, 62, 78, 35, -8, -65, -83, -30, 23, 70, 71, 24, -20, -76, + -75, -12, 32, 73, 62, 15, -30, -85, -62, -2, 41, 76, 51, 9, -39, -86, + -52, 1, 45, 79, 46, 8, -49, -89, -46, 3, 54, 80, 43, 7, -55, -83, + -50, 0, 53, 76, 54, 11, -52, -83, -55, 0, 40, 67, 58, 22, -32, -79, + -67, -11, 28, 63, 52, 37, -9, -70, -63, -28, 10, 42, 49, 53, 8, -46, + -64, -41, 1, 22, 38, 51, 39, -16, -63, -46, -23, 5, 33, 38, 48, 14, + -42, -57, -29, -5, 22, 37, 40, 28, -23, -53, -39, -10, 14, 30, 40, 31, + -1, -48, -40, -18, 11, 19, 31, 26, 14, -20, -50, -25, -5, 11, 31, 30, + 14, 0, -35, -39, -4, -1, 19, 27, 17, 9, -10, -39, -21, -8, 9, 24, + 26, 13, -5, -19, -30, -12, -1, 17, 25, 16, 3, -19, -26, -13, -6, 17, + 22, 20, 5, -16, -32, -19, -1, 23, 27, 23, 4, -30, -33, -23, -1, 35, + 35, 24, -2, -41, -45, -21, 9, 45, 41, 22, -12, -50, -46, -18, 28, 55, + 45, 10, -27, -78, -42, 0, 53, 66, 32, -1, -61, -74, -28, 27, 64, 64, + 24, -28, -80, -66, -15, 53, 84, 48, 5, -59, -94, -41, 17, 75, 80, 26, + -21, -91, -79, -12, 48, 87, 55, 10, -58, -96, -46, 9, 80, 81, 30, -23, + -84, -80, -15, 49, 90, 49, 9, -57, -95, -45, 17, 76, 79, 26, -20, -91, + -75, -18, 52, 90, 52, 6, -59, -92, -41, 15, 68, 80, 31, -21, -87, -76, + -13, 45, 87, 49, 11, -60, -94, -35, 14, 80, 68, 22, -23, -89, -66, -7, + 47, 93, 44, -8, -61, -95, -31, 24, 86, 75, 10, -35, -96, -66, -1, 61, + 100, 44, -12, -77, -105, -33, 32, 97, 92, 16, -44, -111, -90, -5, 65, 121, + 65, -3, -80, -123, -59, 17, 98, 111, 46, -25, -112, -109, -33, 42, 112, 90, + 30, -55, -115, -84, -17, 66, 105, 71, 13, -73, -113, -61, 0, 77, 96, 56, + 4, -80, -108, -50, 8, 78, 93, 47, 3, -88, -98, -40, 7, 65, 76, 53, + 18, -71, -90, -44, 0, 39, 57, 43, 34, -19, -69, -54, -19, 18, 32, 31, + 34, 7, -40, -36, -21, -1, 12, 12, 25, 27, -9, -32, -14, -14, 2, 0, + 1, 20, 19, -2, -13, -11, -18, -12, -2, 18, 24, 12, -2, -14, -19, -19, + -12, 18, 24, 22, -2, -15, -32, -20, 3, 22, 26, 17, -13, -31, -27, -13, + 17, 33, 32, 5, -29, -47, -29, 2, 33, 42, 32, -6, -53, -52, -24, 22, + 51, 41, 27, -32, -74, -45, 0, 45, 59, 33, -1, -62, -66, -31, 26, 73, + 49, 17, -42, -80, -42, -8, 63, 72, 28, -10, -75, -72, -23, 32, 88, 47, + 13, -56, -93, -38, 10, 76, 69, 26, -20, -96, -66, -10, 48, 90, 47, 0, + -69, -103, -29, 25, 87, 73, 18, -35, -104, -68, -2, 61, 93, 47, -5, -83, + -98, -31, 30, 92, 68, 17, -39, -97, -63, -5, 64, 88, 35, -9, -74, -86, + -22, 31, 85, 54, 13, -44, -93, -46, 9, 65, 75, 23, -17, -75, -78, -15, + 39, 84, 54, 3, -52, -96, -46, 12, 71, 90, 29, -18, -89, -87, -26, 36, + 86, 72, 26, -37, -106, -77, -12, 45, 99, 68, 22, -46, -108, -73, -10, 43, + 87, 69, 19, -27, -92, -79, -12, 27, 63, 57, 26, 4, -53, -75, -35, 12, + 33, 37, 31, 26, -9, -53, -39, -16, 6, 20, 23, 22, 13, -8, -22, -23, + -18, -3, 9, 25, 19, 4, -8, -20, -17, -10, 6, 16, 17, 13, -8, -34, + -21, -6, 17, 33, 23, 6, -32, -51, -23, 11, 36, 46, 31, -11, -46, -65, + -31, 15, 59, 55, 28, -20, -73, -64, -26, 42, 78, 51, 14, -53, -85, -48, + -4, 70, 80, 38, -16, -80, -76, -32, 39, 90, 58, 19, -59, -99, -50, 14, + 71, 75, 36, -21, -94, -70, -23, 51, 88, 53, 9, -68, -97, -40, 16, 83, + 73, 29, -33, -100, -61, -13, 58, 87, 41, 0, -74, -81, -35, 24, 87, 55, + 20, -41, -88, -58, 0, 69, 73, 34, -5, -86, -75, -20, 38, 79, 49, 13, + -48, -90, -39, 2, 71, 68, 31, -16, -84, -67, -15, 38, 79, 42, 12, -50, + -85, -37, 2, 62, 71, 34, -5, -83, -75, -24, 27, 82, 51, 27, -30, -88, + -54, -15, 44, 73, 50, 16, -49, -81, -47, -6, 38, 58, 50, 27, -31, -69, + -52, -13, 15, 36, 45, 33, -5, -41, -44, -23, 2, 14, 27, 33, 10, -25, + -20, -18, -6, 1, -1, 17, 22, 3, -13, -10, -17, -13, -6, 13, 24, 15, + 1, -11, -19, -19, -16, 12, 24, 24, 3, -12, -29, -26, -1, 18, 27, 19, + -4, -31, -28, -19, 11, 30, 35, 12, -21, -46, -35, -6, 28, 42, 36, 5, + -46, -57, -31, 10, 50, 43, 33, -16, -71, -55, -9, 35, 62, 38, 10, -51, + -71, -40, 11, 69, 58, 24, -26, -81, -50, -18, 48, 79, 37, 1, -62, -81, + -32, 16, 84, 59, 20, -37, -96, -50, -2, 63, 78, 33, -4, -85, -80, -20, + 33, 88, 59, 10, -50, -107, -47, 14, 75, 85, 27, -19, -95, -83, -15, 47, + 94, 60, 8, -66, -105, -46, 15, 83, 81, 26, -23, -91, -76, -18, 48, 92, + 47, 1, -59, -94, -36, 18, 78, 66, 19, -27, -91, -60, -3, 53, 80, 35, + -8, -62, -86, -28, 27, 79, 66, 13, -38, -94, -62, 1, 56, 95, 42, -6, + -75, -96, -39, 22, 80, 80, 36, -20, -97, -92, -24, 30, 93, 79, 32, -27, + -102, -87, -22, 31, 81, 79, 29, -14, -81, -91, -25, 19, 56, 63, 31, 11, + -39, -77, -47, 3, 31, 37, 33, 27, 3, -48, -46, -20, 0, 18, 22, 23, + 16, -3, -20, -19, -15, -4, 2, 8, 5, 0, 0, 0, 0, 2, 2, 5, + 9, 12, 14, 12, 7, 6, 4, 0, -1, -1, 1, -2, -2, -11, -17, -32, + -41, -49, -55, -58, -61, -61, -65, -61, -57, -47, -37, -27, -22, -15, -5, 6, + 12, 16, 21, 27, 28, 32, 33, 35, 41, 44, 45, 47, 50, 54, 57, 56, + 53, 53, 54, 50, 50, 52, 54, 56, 52, 53, 54, 50, 49, 46, 43, 38, + 33, 27, 19, 8, 2, -11, -20, -27, -29, -30, -32, -35, -42, -52, -57, -57, + -59, -48, -40, -27, -13, 4, 13, 20, 18, 14, 11, 7, 3, -1, -3, -10, + -11, -20, -28, -46, -60, -72, -82, -92, -97, -97, -97, -94, -90, -81, -71, -61, + -55, -55, -53, -47, -38, -29, -23, -11, -6, -3, 1, 2, 5, 6, 3, 3, + 5, 15, 24, 28, 30, 30, 35, 37, 36, 39, 39, 44, 47, 48, 56, 62, + 73, 84, 91, 96, 95, 91, 85, 76, 72, 63, 55, 47, 44, 43, 41, 38, + 31, 19, 7, 0, -9, -7, -4, 8, 22, 40, 54, 67, 71, 70, 64, 56, + 45, 32, 24, 15, 12, 3, -3, -21, -42, -66, -84, -102, -117, -124, -128, -127, + -124, -118, -107, -96, -86, -86, -88, -86, -80, -70, -63, -50, -40, -33, -25, -23, + -20, -18, -18, -21, -25, -22, -14, -8, -3, -3, -1, 1, 0, 1, -3, -1, + 2, 4, 13, 24, 35, 49, 59, 67, 70, 69, 68, 59, 54, 46, 40, 31, + 29, 27, 25, 23, 20, 12, -1, -9, -19, -22, -21, -11, 3, 23, 41, 60, + 71, 76, 73, 71, 65, 56, 50, 44, 42, 35, 33, 24, 9, -13, -31, -48, + -65, -76, -83, -83, -82, -77, -69, -59, -46, -40, -40, -41, -38, -30, -24, -13, + -2, 8, 17, 22, 24, 25, 23, 20, 13, 9, 11, 15, 19, 16, 12, 9, + 4, 1, -6, -10, -11, -14, -12, -5, 3, 15, 26, 35, 40, 41, 41, 35, + 28, 19, 12, 3, -2, -6, -7, -10, -13, -19, -31, -39, -50, -56, -58, -52, + -41, -22, -3, 18, 34, 46, 48, 47, 45, 38, 32, 26, 24, 20, 19, 15, + 5, -14, -32, -49, -65, -79, -88, -91, -91, -88, -82, -75, -63, -52, -47, -46, + -46, -38, -31, -21, -8, 4, 17, 26, 31, 36, 39, 42, 40, 35, 36, 39, + 47, 48, 45, 43, 38, 36, 30, 24, 22, 19, 18, 23, 29, 40, 50, 61, + 68, 72, 74, 71, 66, 57, 50, 40, 32, 24, 21, 16, 12, 7, -3, -14, + -26, -38, -45, -46, -43, -31, -16, 3, 18, 33, 39, 39, 36, 31, 22, 13, + 8, 3, -1, -4, -9, -24, -42, -60, -77, -94, -107, -115, -119, -120, -116, -112, + -103, -91, -81, -78, -80, -75, -69, -61, -51, -39, -25, -13, -5, 2, 8, 14, + 17, 16, 15, 16, 24, 31, 32, 32, 29, 29, 27, 22, 21, 20, 19, 22, + 26, 35, 46, 59, 70, 77, 83, 85, 84, 79, 74, 66, 59, 50, 46, 41, + 38, 35, 29, 21, 11, 0, -9, -14, -16, -11, 0, 16, 30, 48, 58, 62, + 61, 58, 51, 40, 31, 25, 19, 15, 13, 4, -11, -28, -44, -61, -76, -87, + -95, -100, -100, -99, -95, -86, -75, -68, -69, -68, -67, -62, -56, -49, -38, -27, + -19, -13, -9, -3, 2, 1, -1, -3, 0, 7, 10, 10, 6, 5, 4, 0, + -4, -5, -7, -7, -7, -2, 5, 16, 27, 36, 44, 49, 52, 50, 46, 40, + 35, 26, 22, 18, 15, 15, 13, 9, 4, -5, -14, -19, -23, -21, -14, 0, + 15, 33, 49, 60, 63, 63, 61, 53, 44, 38, 32, 27, 27, 23, 14, 0, + -14, -29, -44, -58, -67, -74, -76, -76, -73, -67, -55, -45, -41, -41, -41, -39, + -35, -30, -23, -12, -3, 4, 9, 14, 20, 21, 20, 17, 15, 19, 24, 26, + 24, 21, 20, 18, 12, 9, 6, 3, 0, 1, 4, 11, 21, 30, 38, 43, + 47, 48, 45, 38, 32, 23, 15, 9, 5, 3, 1, -2, -5, -13, -22, -30, + -37, -41, -40, -30, -18, -3, 15, 30, 38, 41, 41, 37, 27, 19, 12, 6, + 3, 2, -2, -13, -25, -39, -53, -67, -78, -88, -92, -92, -91, -86, -77, -63, + -54, -50, -48, -47, -43, -38, -32, -23, -11, -1, 6, 11, 19, 25, 27, 26, + 24, 26, 31, 36, 38, 36, 37, 37, 34, 32, 29, 27, 24, 22, 23, 27, + 35, 45, 53, 61, 67, 70, 71, 66, 60, 51, 42, 34, 28, 24, 21, 18, + 16, 11, 2, -8, -16, -24, -28, -25, -17, -5, 10, 26, 39, 45, 47, 45, + 37, 27, 18, 9, 3, 0, -2, -10, -22, -36, -51, -67, -81, -93, -102, -107, + -108, -107, -102, -90, -78, -71, -67, -66, -63, -59, -56, -49, -39, -28, -19, -13, + -6, 1, 7, 8, 6, 5, 8, 14, 19, 19, 19, 20, 20, 19, 16, 15, + 13, 12, 11, 13, 20, 30, 39, 49, 57, 63, 68, 68, 65, 58, 51, 43, + 37, 32, 29, 27, 26, 24, 19, 11, 2, -5, -12, -14, -9, 0, 13, 30, + 46, 56, 62, 65, 61, 53, 44, 35, 26, 22, 20, 15, 6, -6, -20, -36, + -51, -66, -78, -87, -91, -92, -92, -85, -74, -65, -58, -56, -55, -52, -50, -46, + -40, -30, -20, -14, -8, -2, 5, 7, 6, 3, 2, 5, 10, 11, 10, 9, + 9, 8, 5, 2, 0, -2, -5, -5, -3, 5, 14, 23, 32, 39, 46, 50, + 49, 45, 38, 31, 24, 17, 14, 11, 10, 9, 7, 2, -5, -12, -20, -25, + -25, -19, -8, 7, 24, 40, 50, 58, 60, 56, 49, 41, 31, 24, 22, 20, + 15, 6, -5, -19, -34, -48, -61, -72, -79, -83, -85, -81, -72, -62, -52, -47, + -44, -41, -39, -35, -31, -24, -13, -5, 1, 7, 14, 20, 22, 21, 19, 18, + 22, 25, 25, 24, 23, 23, 20, 17, 15, 12, 10, 7, 5, 9, 16, 24, + 33, 40, 47, 53, 56, 54, 48, 41, 33, 25, 20, 15, 11, 9, 8, 5, + -2, -10, -19, -27, -32, -31, -25, -15, 0, 17, 30, 40, 46, 46, 42, 35, + 25, 15, 10, 9, 5, -2, -11, -23, -37, -52, -65, -79, -89, -95, -99, -100, + -95, -85, -74, -65, -60, -55, -52, -48, -44, -40, -29, -18, -10, -4, 4, 12, + 18, 20, 19, 17, 20, 24, 27, 27, 26, 26, 25, 23, 21, 19, 17, 15, + 12, 13, 17, 25, 34, 41, 49, 57, 62, 65, 63, 57, 51, 42, 35, 30, + 25, 22, 21, 19, 15, 8, 0, -9, -17, -21, -20, -14, -3, 13, 26, 38, + 48, 53, 52, 47, 39, 28, 19, 15, 13, 8, 0, -10, -22, -37, -51, -65, + -79, -88, -95, -100, -99, -94, -84, -74, -67, -61, -58, -55, -51, -49, -43, -33, + -23, -17, -10, -2, 6, 10, 11, 9, 9, 12, 15, 17, 16, 16, 16, 14, + 12, 11, 9, 8, 5, 3, 4, 10, 18, 26, 34, 42, 50, 57, 59, 57, + 52, 45, 38, 32, 27, 23, 21, 20, 19, 14, 8, 1, -9, 2, 5, 7, + 8, -1, 6, 15, 1, 20, 28, 1, 37, 41, 31, 29, 27, 61, 40, -12, + 38, 52, -16, -20, -1, -23, -48, -56, -63, -61, -77, -100, -88, -76, -103, -113, + -98, -103, -118, -120, -108, -107, -104, -110, -118, -104, -109, -128, -107, -83, -106, -86, + -94, -100, -77, -113, -88, -43, -77, -46, -44, -69, -34, -54, -39, 4, -30, 11, + 18, -25, 20, 16, 10, 52, 35, 52, 74, 33, 55, 74, 59, 70, 81, 85, + 91, 81, 72, 89, 94, 82, 80, 99, 100, 85, 86, 91, 100, 91, 81, 91, + 102, 83, 74, 92, 95, 63, 62, 75, 71, 63, 39, 54, 74, 15, 1, 31, + 6, -5, -13, -20, -8, -44, -59, -38, -69, -73, -67, -86, -90, -68, -73, -77, + -49, -82, -70, -43, -76, -27, 0, -29, 22, 25, -5, 44, 45, 29, 66, 71, + 49, 84, 92, 73, 92, 74, 72, 91, 37, 48, 99, 47, 31, 44, 36, 33, + -5, -11, 26, 6, -33, -22, -6, -32, -55, -44, -45, -52, -63, -73, -55, -51, + -77, -79, -61, -73, -91, -83, -70, -77, -74, -82, -85, -68, -88, -98, -57, -67, + -77, -58, -75, -66, -64, -78, -33, -37, -50, -19, -47, -38, -23, -41, 3, 6, + -7, 30, 0, -4, 24, 15, 31, 45, 44, 66, 44, 34, 58, 54, 59, 67, + 71, 87, 78, 60, 73, 84, 78, 76, 86, 95, 89, 76, 85, 94, 89, 73, + 82, 99, 85, 66, 75, 93, 75, 50, 56, 69, 59, 31, 31, 61, 29, -15, + 15, 5, -15, -14, -36, -25, -29, -69, -55, -53, -82, -78, -76, -95, -88, -69, + -80, -65, -63, -86, -58, -67, -59, -12, -28, -9, 29, -8, 13, 44, 22, 44, + 68, 53, 62, 91, 74, 81, 89, 64, 84, 78, 35, 78, 86, 44, 43, 47, + 45, 22, -5, 17, 21, -16, -24, -14, -14, -34, -50, -40, -36, -63, -71, -58, + -60, -69, -78, -78, -67, -81, -98, -78, -71, -89, -85, -84, -86, -82, -99, -82, + -60, -76, -75, -74, -76, -71, -86, -68, -37, -51, -34, -41, -57, -37, -51, -31, + -7, -17, -3, 1, 7, 22, 31, 46, 57, 41, 43, 56, 63, 62, 68, 85, + 86, 80, 84, 92, 96, 93, 93, 104, 105, 96, 99, 108, 106, 102, 98, 102, + 111, 99, 87, 106, 110, 85, 80, 88, 89, 79, 68, 70, 81, 48, 25, 39, + 32, 18, 9, 12, 0, -29, -31, -38, -60, -52, -63, -79, -71, -66, -62, -59, + -62, -74, -72, -73, -81, -43, -21, -28, 8, 10, -10, 16, 28, 27, 42, 50, + 47, 66, 76, 68, 81, 73, 67, 72, 39, 40, 67, 41, 23, 25, 22, 12, + -16, -22, -5, -27, -51, -44, -45, -57, -68, -73, -71, -74, -91, -89, -84, -90, + -97, -98, -98, -102, -105, -108, -103, -97, -105, -109, -101, -107, -113, -106, -92, -87, + -90, -92, -92, -92, -100, -92, -57, -56, -54, -40, -59, -58, -54, -61, -23, -9, + -12, 16, 0, -14, 4, 5, 17, 32, 41, 57, 55, 43, 54, 66, 67, 68, + 84, 89, 87, 87, 91, 98, 100, 96, 104, 109, 105, 103, 108, 111, 109, 105, + 105, 113, 111, 99, 102, 115, 104, 88, 90, 97, 93, 80, 75, 86, 75, 37, + 40, 43, 33, 20, 20, -14, -26, -36, -53, -52, -65, -75, -75, -69, -69, -69, + -74, -77, -76, -74, -59, -34, -26, -9, 9, 5, 13, 32, 39, 42, 53, 58, + 61, 73, 77, 77, 73, 61, 57, 46, 29, 37, 37, 17, 6, 2, -10, -27, + -38, -41, -46, -58, -68, -69, -75, -85, -89, -92, -97, -101, -103, -106, -107, -108, + -112, -111, -112, -115, -115, -115, -113, -111, -116, -115, -112, -116, -117, -110, -101, -98, + -101, -101, -98, -101, -101, -86, -69, -65, -59, -57, -62, -58, -54, -39, -19, -12, + 1, 7, -1, 5, 16, 24, 36, 46, 58, 64, 61, 64, 74, 79, 81, 90, + 96, 97, 100, 100, 104, 108, 107, 111, 114, 113, 115, 115, 115, 118, 117, 116, + 118, 119, 116, 115, 116, 117, 111, 104, 105, 107, 99, 93, 95, 91, 71, 57, + 53, 47, 38, 29, 23, 14, -11, -28, -38, -49, -58, -67, -73, -80, -84, -84, + -83, -82, -80, -78, -74, -67, -56, -42, -29, -16, -4, 7, 18, 29, 40, 49, + 57, 64, 70, 74, 78, 79, 77, 72, 67, 60, 53, 48, 42, 33, 23, 14, + 4, -6, -16, -24, -32, -40, -48, -55, -61, -68, -74, -78, -83, -87, -91, -94, + -96, -99, -101, -103, -104, -106, -107, -107, -107, -107, -107, -108, -107, -107, -107, -105, + -101, -98, -96, -94, -93, -91, -87, -82, -74, -67, -62, -57, -54, -49, -43, -35, + -25, -16, -7, -1, 4, 10, 17, 25, 33, 41, 49, 55, 59, 63, 69, 74, + 78, 83, 88, 91, 93, 96, 98, 100, 102, 104, 106, 107, 107, 108, 108, 109, + 109, 108, 108, 108, 107, 105, 104, 102, 99, 94, 91, 87, 83, 78, 73, 66, + 56, 46, 37, 28, 19, 9, 0, -11, -23, -35, -45, -55, -64, -71, -78, -83, + -85, -84, -83, -81, -79, -75, -70, -61, -49, -36, -23, -10, 2, 12, 24, 35, + 45, 53, 61, 67, 72, 76, 79, 78, 75, 70, 65, 58, 52, 46, 39, 29, + 20, 11, 1, -9, -18, -26, -34, -42, -50, -56, -63, -69, -74, -79, -83, -88, + -91, -94, -96, -98, -101, -102, -104, -105, -106, -106, -106, -106, -106, -106, -106, -106, + -105, -102, -98, -96, -94, -92, -90, -88, -84, -77, -70, -64, -59, -55, -51, -45, + -38, -29, -20, -11, -4, 2, 7, 13, 21, 29, 37, 44, 51, 56, 60, 65, + 70, 75, 80, 84, 88, 91, 93, 96, 98, 100, 102, 104, 105, 106, 107, 107, + 108, 108, 107, 107, 107, 106, 104, 103, 101, 99, 95, 91, 87, 83, 78, 73, + 67, 59, 49, 39, 30, 21, 12, 3, -8, -19, -31, -41, -51, -60, -68, -75, + -81, -84, -85, -84, -82, -80, -77, -73, -65, -55, -42, -29, -16, -4, 7, 18, + 29, 40, 49, 57, 64, 70, 74, 78, 79, 77, 73, 68, 62, 56, 50, 44, + 36, 26, 17, 7, -3, -12, -20, -28, -36, -44, -51, -58, -64, -70, -75, -79, + -84, -88, -91, -93, -96, -98, -100, -102, -103, -105, -105, -105, -105, -105, -105, -105, + -105, -104, -102, -99, -96, -94, -92, -90, -88, -85, -79, -72, -66, -61, -56, -52, + -47, -41, -33, -24, -15, -8, -1, 4, 10, 17, 24, 32, 40, 47, 53, 57, + 62, 67, 72, 77, 81, 85, 89, 91, 94, 96, 98, 100, 102, 104, 105, 105, + 106, 106, 107, 106, 106, 106, 105, 104, 102, 101, 99, 95, 91, 87, 83, 79, + 74, 68, 61, 52, 42, 33, 24, 15, 5, -5, -15, -27, -38, -48, -57, -66, + -72, -79, -83, -85, -85, -83, -81, -79, -75, -69, -60, -48, -35, -23, -10, 2, + 13, 24, 35, 45, 54, 61, 67, 72, 77, 78, 79, 76, 72, 66, 60, 54, + 49, 41, 32, 23, 12, 3, -4, -17, -15, 1, -1, 0, 0, 1, 3, 5, + 9, 13, 18, 24, 32, 38, 32, 18, -9, -48, -73, -41, 2, -3, -24, -34, + -44, -72, -111, -124, -62, 40, 40, -51, -35, 45, 46, -22, -79, 35, 78, -47, + -98, -88, -69, -57, -44, -31, -17, -9, -3, 6, 41, 85, 43, -91, -128, -65, + -25, -21, -19, -12, 2, 16, 29, 39, 49, 48, 10, -69, -47, 50, 8, -52, + -44, 5, 21, -40, -42, 33, 79, 66, 38, 24, 25, 26, 18, 21, 70, 117, + 98, 28, -1, 20, 22, 0, 1, 9, -10, -49, -33, 39, 68, 39, -5, -17, + -58, -76, 78, 104, 17, 6, -23, -43, -13, 58, 85, 43, 21, 35, 46, 31, + 22, 35, 14, -48, -74, -38, 6, 10, -8, -17, -24, -37, -60, -69, -41, 15, + 27, -21, -26, 18, 28, -1, -41, 5, 51, -9, -51, -48, -38, -31, -24, -16, + -8, -2, 1, 6, 23, 52, 41, -39, -83, -50, -19, -13, -12, -8, 1, 10, + 20, 27, 34, 35, 15, -40, -46, 27, 16, -35, -38, -6, 19, -18, -35, 17, + 61, 55, 33, 21, 22, 25, 21, 18, 52, 98, 92, 31, -5, 9, 17, -1, + -2, 7, -7, -47, -43, 24, 62, 39, -3, -20, -48, -88, 46, 113, 25, 4, + -20, -45, -25, 42, 82, 47, 19, 28, 42, 32, 18, 30, 19, -39, -77, -51, + -4, 10, -6, -18, -25, -37, -57, -70, -50, 4, 26, -15, -33, 9, 27, 6, + -38, -12, 50, 6, -47, -50, -40, -32, -25, -17, -10, -3, 0, 4, 17, 45, + 47, -23, -82, -60, -24, -14, -13, -10, -2, 7, 16, 24, 30, 33, 18, -32, + -56, 13, 23, -31, -41, -15, 19, -6, -35, 4, 52, 55, 35, 21, 22, 25, + 22, 15, 41, 89, 94, 38, -5, 4, 16, 2, -2, 7, -4, -41, -48, 12, + 58, 43, 2, -20, -38, -89, 14, 118, 38, 3, -15, -43, -32, 28, 78, 53, + 19, 24, 40, 34, 18, 26, 23, -28, -75, -61, -14, 10, -2, -16, -24, -34, + -53, -68, -55, -7, 25, -8, -36, 1, 27, 12, -31, -26, 45, 22, -39, -50, + -41, -32, -25, -17, -10, -4, 0, 3, 13, 38, 51, -5, -77, -69, -31, -15, + -14, -11, -4, 5, 13, 21, 27, 31, 20, -24, -61, -3, 28, -23, -43, -23, + 15, 5, -32, -6, 43, 53, 36, 22, 21, 26, 24, 14, 32, 79, 95, 46, + -3, 0, 15, 5, -1, 7, -1, -36, -52, 2, 53, 46, 7, -18, -30, -84, + -15, 114, 55, 4, -10, -40, -37, 15, 72, 59, 22, 20, 36, 36, 19, 23, + 26, -18, -70, -68, -25, 7, 2, -13, -22, -32, -49, -65, -59, -16, 22, -1, + -36, -8, 25, 17, -22, -35, 34, 36, -29, -48, -42, -32, -25, -18, -10, -4, + 0, 3, 10, 32, 52, 11, -67, -76, -38, -16, -13, -11, -6, 3, 11, 19, + 25, 30, 22, -15, -62, -19, 30, -14, -43, -30, 9, 13, -25, -15, 33, 51, + 37, 23, 21, 26, 26, 15, 24, 68, 94, 54, 0, -3, 13, 8, 1, 8, + 2, -30, -53, -8, 47, 49, 13, -16, -25, -75, -41, 102, 73, 6, -5, -36, + -40, 2, 65, 64, 25, 18, 33, 37, 21, 21, 27, -8, -63, -73, -36, 2, + 5, -10, -21, -30, -45, -62, -61, -25, 17, 5, -35, -17, 21, 21, -13, -39, + 20, 46, -16, -46, -42, -32, -25, -17, -10, -4, 0, 3, 8, 27, 50, 25, + -54, -81, -46, -19, -13, -12, -7, 1, 9, 17, 23, 28, 23, -8, -59, -35, + 27, -5, -42, -35, 2, 20, -16, -20, 24, 47, 38, 24, 21, 27, 28, 17, + 18, 58, 91, 62, 5, -6, 10, 10, 3, 9, 5, -24, -52, -17, 40, 50, + 18, -13, -22, -64, -60, 83, 90, 12, -3, -31, -41, -8, 55, 67, 30, 17, + 30, 37, 24, 19, 27, 1, -54, -75, -46, -4, 7, -7, -18, -28, -41, -58, + -61, -32, 11, 10, -31, -24, 17, 23, -4, -39, 5, 52, -2, -42, -42, -32, + -25, -17, -10, -4, 0, 3, 6, 22, 47, 35, -38, -82, -55, -23, -13, -12, + -8, -1, 7, 15, 21, 26, 23, -1, -53, -48, 20, 5, -39, -39, -6, 22, + -5, -22, 14, 43, 38, 25, 21, 27, 29, 19, 15, 47, 86, 68, 12, -7, + 7, 11, 4, 10, 7, -18, -50, -25, 33, 51, 24, -10, -20, -52, -72, 58, + 103, 21, -1, -26, -41, -17, 44, 67, 35, 16, 27, 36, 26, 18, 25, 8, + -45, -76, -55, -13, 7, -3, -16, -26, -38, -55, -61, -38, 4, 13, -26, -30, + 11, 25, 4, -36, -10, 51, 14, -37, -42, -33, -24, -17, -10, -4, 1, 3, + 6, 18, 42, 42, -22, -80, -63, -28, -14, -12, -9, -3, 5, 12, 19, 24, + 23, 3, -46, -58, 9, 14, -34, -41, -14, 21, 6, -21, 4, 36, 38, 26, + 21, 26, 30, 22, 13, 37, 78, 73, 20, -7, 4, 11, 6, 10, 10, -11, + -45, -33, 22, 49, 29, -4, -18, -40, -75, 23, 108, 40, 1, -18, -39, -26, + 28, 65, 42, 17, 22, 34, 29, 18, 23, 15, -30, -71, -65, -27, 3, 2, + -11, -22, -34, -49, -58, -45, -7, 13, -16, -35, -1, 24, 13, -23, -26, 37, + 36, -20, -39, -34, -24, -17, -10, -4, 1, 3, 5, 12, 33, 46, 6, -64, + -75, -40, -17, -12, -10, -5, 2, 9, 15, 20, 22, 10, -30, -65, -18, 20, + -19, -42, -27, 11, 21, -8, -8, 22, 34, 27, 22, 26, 31, 27, 14, 22, + 60, 75, 34, -4, -2, 8, 8, 11, 14, -2, -36, -42, 6, 44, 36, 4, + -15, -26, -66, -24, 95, 71, 8, -10, -33, -32, 7, 56, 51, 21, 17, 29, + 32, 20, 19, 20, -12, -59, -72, -45, -8, 5, -5, -17, -28, -42, -54, -50, + -21, 9, -5, -36, -16, 19, 21, -7, -34, 12, 51, 4, -33, -34, -25, -17, + -10, -4, 1, 4, 5, 9, 23, 44, 29, -39, -79, -55, -24, -13, -10, -7, + -1, 6, 12, 16, 20, 14, -15, -62, -46, 16, -2, -39, -36, -2, 29, 9, + -12, 8, 28, 27, 23, 25, 31, 31, 17, 13, 43, 72, 46, 2, -5, 5, + 8, 11, 16, 5, -26, -44, -8, 36, 40, 12, -12, -19, -52, -53, 67, 94, + 20, -5, -27, -35, -7, 45, 55, 27, 15, 25, 32, 23, 17, 21, 0, -47, + -73, -57, -19, 4, 0, -13, -24, -37, -50, -51, -29, 3, 1, -32, -26, 12, + 23, 3, -32, -6, 52, 22, -26, -34, -25, -17, -10, -4, 1, 5, 6, 8, + 18, 39, 38, -21, -76, -64, -30, -14, -10, -8, -2, 4, 10, 15, 18, 14, + -9, -56, -57, 7, 7, -35, -39, -10, 27, 18, -10, 2, 23, 26, 23, 24, + 31, 32, 20, 11, 35, 67, 51, 7, -6, 3, 8, 11, 17, 8, -20, -44, + -15, 31, 41, 16, -9, -17, -43, -61, 44, 102, 31, -2, -23, -35, -15, 36, + 56, 32, 0, -27, 1, -1, -1, 3, -4, -2, 1, -1, -2, 2, 3, -6, + 1, 2, -6, 2, 2, -4, -1, 2, -5, 1, 4, -4, 0, -1, 0, -1, + -2, 2, 2, -6, 0, 4, -3, -3, 4, -2, -3, -2, 0, 1, 1, -2, + -2, 3, -8, 27, -42, 11, 21, -35, 34, -25, 12, 9, -24, 14, 13, -38, + 53, -42, -3, 46, -73, 55, -16, -9, 28, -49, 38, -12, -21, 49, -51, 20, + 32, -73, 64, -28, -7, 32, -50, 42, -11, -30, 49, -21, -31, 46, -25, -7, + 20, -22, 18, -16, -10, 21, -23, 5, 28, -35, 8, 0, 8, -26, 19, 6, + -11, -20, 64, -46, -18, 51, -73, 119, -117, 46, 36, -80, 67, -46, 22, 0, + -24, 56, -59, 14, 26, -40, 24, -9, 20, -20, -15, 43, -26, -11, 9, 14, + -3, -31, 6, 54, -62, 3, 67, -78, 20, 21, -25, 31, -41, 18, 27, -53, + 32, 15, -48, 37, -11, 4, -12, -3, 31, -24, -21, 42, -10, -45, 55, -32, + 34, -43, -14, 86, -78, 8, 39, -35, -2, 13, 2, 5, -11, -4, 7, 5, + -31, 37, -4, -28, 28, -9, -11, 10, -1, 4, -18, 17, -9, -13, 24, -18, + 20, -18, -30, 59, -25, -29, 48, -15, -29, 23, 4, -3, -18, 14, 6, -8, + -19, 19, 8, -13, 0, 13, -18, 4, 1, 0, 0, 10, -14, -12, 39, -46, + 23, 9, -22, 23, -20, -22, 63, -42, -28, 77, -66, 12, 38, -56, 31, 27, + -77, 66, -11, -39, 59, -33, -41, 92, -54, -50, 96, -36, -46, 46, -17, 31, + -43, -28, 98, -57, -50, 84, -22, -44, 39, -8, 17, -28, -13, 63, -67, 16, + 10, 3, -15, -4, 36, -34, -1, 26, -27, -2, 13, 7, -22, 0, 27, -11, + -19, 6, 26, -42, 14, 18, -7, -14, -10, 37, -14, -24, 25, -4, -5, -10, + 3, 35, -39, -7, 31, -8, -23, 15, 4, -1, -25, 28, 7, -35, 34, -16, + -1, 9, -35, 45, -22, -17, 48, -52, 24, 22, -65, 48, 7, -45, 47, -19, + -33, 71, -70, 46, -7, -52, 68, -25, -35, 48, -13, -17, 14, 2, -12, 8, + -10, 1, 22, -32, 4, 34, -26, -18, 29, -7, -19, 15, -7, 15, -8, -29, + 50, -22, -35, 53, -19, -37, 47, -9, -40, 41, 1, -27, 7, 3, 0, 0, + -7, 13, -7, -21, 26, 14, -44, 11, 40, -51, 10, 26, -28, 16, -13, -3, + 31, -42, 11, 34, -52, 11, 34, -43, 10, 29, -19, -21, 27, -10, -5, 10, + -14, 11, 3, -35, 43, 3, -52, 37, 22, -66, 49, -12, -19, 50, -58, 16, + 42, -70, 50, -2, -42, 60, -69, 43, 11, -57, 54, -8, -31, 23, -8, -7, + 24, -32, 11, 21, -51, 60, -44, -6, 68, -87, 33, 45, -79, 50, -7, -13, + 21, -40, 31, 12, -41, 18, 24, -39, 15, 7, -17, 25, -20, -12, 43, -47, + 17, 6, -16, 10, 4, -11, -1, 14, -10, -7, 6, 9, -23, 9, 3, 13, + -30, 16, 16, -33, 17, 4, -17, 23, -29, 3, 54, -86, 50, 11, -41, 30, + -23, 15, 18, -60, 56, 7, -65, 49, -4, -12, 1, -6, 19, -4, -33, 35, + -10, -12, 13, -2, -2, -2, 2, -10, 16, -8, -11, 19, -6, -19, 24, -14, + 9, 3, -24, 24, -6, -13, 19, -11, -6, 6, -9, 16, -8, -10, 14, -10, + -1, -5, 16, -8, -25, 37, -11, -27, 37, -14, -13, 19, -17, 14, -5, -15, + 26, -27, 10, 11, -23, 22, -5, -19, 25, -7, -28, 44, -35, 0, 25, -31, + 31, -10, -26, 46, -41, 2, 33, -40, 24, 8, -43, 44, -12, -25, 37, -25, + -6, 29, -27, 5, 24, -40, 24, -1, -25, 23, -1, -6, -2, -1, 14, -24, + 8, 13, -11, 0, -13, 16, 15, -56, 43, 12, -35, 14, -9, 18, -10, -19, + 28, -3, -27, 23, -2, -14, 27, -35, 10, 35, -68, 44, 7, -43, 46, -21, + -25, 56, -35, -21, 51, -33, -8, 28, -27, 19, -2, -26, 36, -26, 3, 13, + -12, 6, -10, 8, -14, 15, -12, 0, 13, -9, -16, 32, -27, 3, 23, -49, + 49, -17, -31, 63, -64, 25, 36, -76, 61, -11, -47, 75, -54, -9, 69, -81, + 32, 29, -63, 46, -7, -26, 39, -31, 6, 18, -26, 13, -5, 5, -5, -2, + 5, -12, 17, -17, -2, 22, -25, 1, 20, -19, 3, 6, -6, 3, -9, 10, + -6, -3, 7, -7, -3, 12, -5, -5, -11, 24, -7, -23, 24, 0, -14, 0, + 12, -10, -2, 5, 0, 1, -10, 10, -2, -17, 26, -11, -16, 28, -22, 6, + 4, -17, 30, -27, -7, 46, -54, 15, 29, -42, 25, -4, -15, 26, -29, 11, + 15, -28, 19, -7, 1, 8, -20, 14, 1, -15, 11, -2, -2, 0, -10, 15, + -5, -12, 15, -1, -15, 12, 4, -15, 9, -1, -9, 9, -5, -6, 13, -12, + 1, 6, -6, -3, 6, -4, 0, -6, 11, -9, -2, 13, -12, -2, -1, 8, + -11, 4, 2, -6, 4, -4, 4, 0, -13, 15, 0, -21, 23, -5, -15, 15, + -2, -9, 6, -2, -4, 2, 3, -1, -7, 7, -2, -9, 6, 2, -9, 4, + 5, -12, 10, -9, 4, 5, -16, 12, -2, -13, 20, -13, -4, 17, -23, 14, + 2, -20, 22, -13, -3, 15, -22, 12, 4, -18, 17, -7, -7, 13, -14, 6, + 4, -10, 9, -5, -6, 7, 0, -7, 8, -4, -1, 0, -6, 4, 7, -14, + 2, 13, -16, 3, 10, -15, 7, -1, -10, 14, -10, -2, 11, -9, -4, 7, + -6, 3, -3, -5, 9, -6, -3, 5, 1, -7, 3, -2, 0, -2, 0, 4, + -3, -2, 4, -6, 4, -2, -2, 0, 1, 0, -7, 7, -2, -7, 9, -7, + -4, 11, -15, 11, -2, -9, 9, -4, -3, 2, 3, -7, 5, 0, -5, 6, + -7, 1, 7, -10, -2, 13, -9, -4, 8, -4, -2, -1, 1, 1, -7, 4, + 5, -8, 0, 6, -6, 0, 3, -4, 0, 1, -2, 2, -4, -4, 8, -7, + -1, 6, -9, 8, -3, -6, 12, -12, 1, 10, -11, 1, 5, -6, 3, -2, + -3, 7, -10, 2, 7, -12, 5, 2, -5, 3, -5, 0, 6, -10, 3, 4, + -8, 2, 2, -3, 3, -8, 8, 2, -14, 10, 3, -12, 8, 2, -11, 8, + -2, -6, 9, -7, -4, 10, -9, -1, 7, -7, 1, 3, -8, 8, -2, -8, + 10, -3, -5, 5, -6, 3, 1, -8, 10, -5, -5, 7, -4, -2, 2, -3, + 1, -1, -3, 4, -3, 0, 0, 0, 0, -4, 3, -2, -3, 3, -5, 3, + 0, -7, 5, 1, -8, 5, 1, -6, 6, -5, 0, 3, -7, 3, 2, -6, + 3, 2, -6, 3, 1, -3, -2, 5, -4, -1, 3, -4, 0, 0, -3, 5, + -5, -3, 7, -5, -3, 6, -4, 0, -1, -3, 3, -2, -1, 2, -1, -2, + 1, -2, 1, -1, -7, 8, -1, 5, -7, 13, -22, 8, -7, 8, -110, -28, + 24, 54, 36, 2, 60, -45, 57, 42, -43, 20, 41, -66, 24, -11, 18, -18, + -38, -63, -36, 30, -11, 33, 25, 30, 18, 11, -18, -5, 5, -46, 40, 1, + -13, -18, -20, -31, 20, 10, 29, -7, -18, 40, -29, -17, 42, -19, 6, -4, + 6, -8, 10, -26, -5, 3, 1, -17, 6, 0, 19, -1, 8, 0, -6, -10, + -1, -12, -1, 1, -3, 8, -7, 4, 11, 4, 14, -13, 16, -19, -4, -13, + -13, -14, 6, 4, -1, 4, 11, -1, 11, -1, 1, -4, -1, -15, 6, -9, + 1, -1, 0, 3, 1, -8, 3, -1, -1, 2, -2, 2, -2, 1, -5, -7, + 3, -3, 6, -3, 4, -1, 0, -4, 2, -7, 3, -6, -1, -1, 4, 0, + 3, -2, 2, -5, 5, -8, -3, -3, 2, -5, 7, -1, 4, -2, 4, -10, + 6, -6, -1, -4, 5, -13, 7, -6, 5, -8, 17, -20, 14, -6, 9, -40, + 71, -127, 9, -73, 127, 76, -28, 74, -32, 8, -62, -49, -38, 40, -68, 22, + -12, 68, 10, 39, -10, 0, 35, -23, 0, -59, -15, -7, -3, -23, 1, -20, + 37, 27, 2, 30, -2, 17, 2, -5, -7, -27, -29, 16, -3, -11, 1, -16, + -5, -8, -10, 7, 32, 9, 5, -4, 16, 5, -8, -17, -16, 5, -13, 8, + 11, 15, -10, -9, 0, -1, 2, 7, -3, -23, 9, 2, 3, 1, -13, -1, + -6, 11, -6, 8, 1, 12, -12, 9, -14, 8, -1, 0, -3, -13, 4, -7, + -4, 8, 5, -5, -7, 4, -2, -3, 2, 3, -6, 8, -3, 1, -3, -2, + 2, -6, 2, -4, -3, -4, 3, 1, 0, 0, 1, -1, -1, 2, -2, 0, + -4, -2, 1, 2, 0, -3, 1, -3, 0, -1, -3, -6, 2, -2, 3, -4, + 10, -8, 9, -5, 12, -19, 46, 37, -128, 60, -90, 102, -65, 40, -57, 39, + -6, 23, -8, 19, 24, 15, -17, -47, -27, -36, -16, 21, 3, 23, 14, 50, + -8, 19, 25, 7, -9, -28, -63, -37, 0, -42, 54, -17, 68, -3, 30, -12, + -4, 11, -15, 9, -25, -15, -2, -27, -25, 38, -8, -13, 33, 24, 12, -38, + 39, -12, -3, -17, -44, 38, 2, 27, 3, -5, -4, -13, -30, -56, -4, 11, + 1, 9, 17, 46, 25, -14, 6, -3, -7, -21, 2, 16, -5, -22, 2, -2, + 6, -12, -25, -15, 10, 9, 8, 11, 43, 8, -5, -22, -16, 14, -31, 16, + 7, -7, -26, -20, -2, 9, 11, 26, 7, 6, -20, -13, 0, 4, 17, -17, + -18, 10, 2, -10, 27, -8, 24, -23, -14, 1, 0, 13, -19, 14, 10, -16, + 16, -4, -20, 20, -33, 2, 2, 24, 21, -3, -26, -24, -18, -18, 10, 10, + 24, 18, 2, 9, -24, 16, -14, -8, 9, -5, -14, 8, -5, 30, -11, 11, + -13, -15, -12, 7, 4, -13, -13, 13, -13, 12, 23, 9, 0, 14, -10, -9, + -35, -2, -21, 12, -1, 17, 19, 11, -4, 0, -18, -24, 11, -10, 1, 11, + 12, -13, -16, 10, -23, 21, 9, -9, 3, 12, -6, 3, -5, 12, 0, -2, + 0, -19, -9, 5, -11, -7, 10, 1, -3, 9, 18, -6, 0, -1, 1, -13, + 2, 1, -3, -8, 17, -4, -9, 18, -15, 8, -1, -11, -5, -14, 11, -5, + -7, 12, 16, -7, 7, -3, -11, -5, -6, 1, 4, -3, -3, 15, 5, 0, + 3, 6, -16, 4, -14, -6, -9, -4, 2, 11, 11, 7, -2, 4, -12, -7, + -14, -6, -7, 9, 4, 7, -2, 6, 5, 6, -4, -3, -4, 7, -7, -11, + -9, 0, -3, 7, -2, -2, 3, 13, -4, -6, -15, 9, -7, -1, 4, 6, + 5, 8, -6, -8, 0, -11, -4, 6, -8, 4, 3, 5, 13, -4, -9, -3, + 4, -3, -3, 4, -1, -12, 6, -14, 2, 3, 15, 2, 6, -7, -8, 3, + 1, -2, 3, -3, -12, -6, -14, 7, -2, 13, 6, 10, 6, 0, -2, -10, + -12, -8, -6, -7, -6, 6, 4, -2, 5, 2, 0, -1, 3, -11, 4, 0, + 20, -8, -2, 0, -1, -3, 7, -3, -4, -2, -6, -10, -10, -8, 1, 2, + 5, 8, 2, 5, 8, 3, 4, 3, -2, -15, 0, -1, -7, -2, -5, -10, + 10, -1, 5, 3, 5, -1, -2, -8, -5, -9, 1, -8, 6, 5, 4, 1, + 1, 2, 3, -2, 4, -7, 1, -7, -9, -2, 0, 2, 3, 6, -8, 8, + 3, 0, -2, -9, -3, -2, 0, 3, -1, -2, -3, 7, -3, 10, -8, 1, + -12, 3, -7, 2, -3, 7, 4, 4, 0, 0, -6, -1, -5, -3, -4, -7, + 0, 5, 7, 0, 2, -3, 10, -1, 3, -7, -5, -4, -9, -3, -7, 5, + -4, 9, 2, 1, 4, 5, 0, -5, 1, -8, 4, -9, 5, -5, 0, 3, + -2, -1, 1, 1, -7, 7, 0, 3, -5, 0, -3, -1, -1, -5, -1, 1, + -1, 1, -1, 0, 2, 0, 2, -7, -7, 4, -1, 0, 3, 4, -1, -3, + -4, -6, 3, -2, 4, -1, 5, -2, -1, -5, -2, -4, 1, 3, 2, 2, + 0, -3, 1, 1, -3, -3, -1, 1, -3, -2, -1, -2, -3, -1, 0, 4, + 3, 5, 2, 1, -4, -9, -3, -7, 1, -2, 7, -2, 3, 3, 3, 1, + 0, -1, -6, -7, -6, -4, -1, 1, 0, 5, 2, -2, 2, -3, -1, 3, + -1, 1, -4, -4, -5, 0, -7, 2, -4, 3, 4, 1, 2, -1, -1, -2, + -2, 0, -1, 1, -1, -1, -3, 1, 1, 3, -3, -1, 1, 1, -2, -3, + -8, -5, 0, -1, 5, 2, 3, 1, -2, -1, -1, -3, 1, 1, -2, -3, + -3, -1, 0, -1, 1, 2, 2, 5, 0, -1, -2, -1, -2, 0, -4, 0, + -5, -1, -1, 0, 1, 5, 4, -2, -1, -2, 0, -6, -1, 0, 1, -1, + -2, 1, 0, 0, 3, 1, -2, 1, -2, -4, -1, 0, -1, -1, -4, -2, + -4, 2, -1, 1, 0, 3, 2, 0, 4, -1, 4, -6, 2, -4, -3, -5, + -4, -3, 0, 2, 0, 1, 4, 2, 2, -2, -2, -5, -6, -5, -3, -2, + 1, -1, 0, 0, 2, 2, 2, 0, 4, -2, 3, 2, -1, -2, -3, -3, + -3, -5, -5, -5, -1, -1, 0, 2, 2, 4, 1, 2, 1, 2, -1, -1, + -3, -4, -5, -3, -2, -2, -1, 1, 4, 2, 2, 2, 1, -1, -2, -6, + -2, -3, 2, -1, 1, -2, 0, 2, 1, 2, -2, 1, 0, -2, -2, -3, + 0, -2, -1, -1, 0, -2, -2, 1, 0, 2, -1, 1, -1, 0, -1, -1, + 0, -1, 0, -2, 2, 0, 2, 2, 5, 3, 6, 8, 12, 13, -6, -110, + -7, 51, -99, -128, 10, -28, -39, 25, -33, -27, 41, 34, -5, 17, 23, 25, + 24, 23, 20, 24, 25, 24, 21, 20, 23, 23, 16, 20, 9, 20, 18, 10, + 14, 5, 14, 11, 7, 5, 3, 10, 2, 7, -4, 0, 3, 0, -3, -5, + -6, -1, -12, -4, -17, -10, 9, -42, -40, 65, 40, -58, 29, 72, 39, 50, + 31, -1, 30, 25, -7, -4, -33, -47, -29, -49, -74, -69, -71, -79, -61, -51, + -57, -53, -34, -20, -22, -16, -10, -6, -2, 1, 3, 4, 8, 8, 12, 10, + 9, 14, 13, 12, 12, 13, 12, 12, 14, 12, 12, 12, 12, 13, 12, 9, + 11, 11, 11, 7, 8, 7, 8, 9, 2, 5, 8, -6, 2, 17, -17, -20, + 18, 5, -15, 15, 27, 21, 37, 44, 41, 46, 38, 26, 32, 26, -4, -15, + -6, -20, -44, -50, -54, -60, -59, -58, -58, -54, -46, -38, -32, -26, -19, -14, + -9, -5, -1, 2, 5, 7, 8, 10, 11, 12, 13, 13, 14, 14, 14, 13, + 13, 14, 15, 14, 11, 13, 14, 13, 12, 10, 12, 12, 10, 10, 8, 6, + 11, 9, -1, 5, 11, -1, -6, 1, -1, -4, 0, -1, 0, 14, 25, 24, + 28, 37, 38, 38, 38, 31, 22, 14, 4, -5, -15, -26, -38, -47, -52, -54, + -56, -57, -55, -51, -45, -39, -34, -28, -22, -17, -13, -8, -3, -1, 2, 5, + 7, 8, 10, 11, 12, 13, 13, 13, 13, 14, 14, 13, 13, 14, 13, 12, + 13, 13, 12, 11, 12, 11, 9, 11, 9, 6, 7, 8, 5, 3, 2, 0, + 0, 0, -2, -3, 0, 3, 6, 11, 18, 23, 27, 31, 34, 35, 32, 27, + 21, 14, 5, -5, -15, -26, -35, -43, -48, -52, -53, -53, -52, -49, -44, -40, + -35, -29, -24, -19, -14, -10, -6, -3, 1, 3, 5, 7, 9, 10, 11, 12, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 12, 13, 12, 11, 13, 11, 10, + 10, 9, 9, 8, 7, 7, 5, 4, 3, 2, 0, -1, -1, 0, 2, 4, + 8, 12, 17, 22, 25, 28, 30, 30, 28, 24, 19, 12, 3, -5, -14, -23, + -31, -37, -43, -46, -46, -48, -47, -43, -41, -38, -33, -29, -25, -21, -16, -12, + -8, -5, -2, 0, 3, 5, 7, 9, 10, 11, 12, 12, 13, 14, 13, 13, + 13, 13, 13, 12, 12, 12, 11, 11, 11, 10, 9, 9, 8, 7, 7, 6, + 5, 4, 4, 3, 3, 3, 3, 5, 6, 8, 10, 12, 14, 17, 18, 19, + 20, 19, 17, 14, 10, 5, 0, -6, -11, -17, -22, -26, -29, -32, -34, -34, + -35, -34, -32, -31, -28, -26, -23, -20, -17, -14, -11, -8, -5, -3, 0, 2, + 4, 6, 7, 8, 9, 10, 11, 11, 12, 12, 12, 12, 11, 11, 11, 10, + 10, 9, 9, 8, 8, 7, 7, 6, 5, 5, 5, 4, 4, 5, 5, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 13, 13, 13, 12, 10, 8, 5, 2, + -2, -6, -10, -14, -18, -21, -24, -26, -28, -29, -29, -30, -29, -28, -27, -25, + -23, -20, -18, -15, -12, -10, -7, -4, -2, 0, 2, 4, 6, 7, 9, 10, + 10, 11, 11, 12, 12, 12, 12, 11, 11, 11, 10, 10, 9, 9, 8, 8, + 7, 7, 6, 6, 5, 5, 5, 5, 6, 6, 7, 7, 8, 9, 10, 11, + 12, 13, 13, 13, 12, 11, 10, 8, 5, 2, -1, -5, -9, -13, -16, -19, + -22, -24, -26, -27, -28, -28, -28, -27, -26, -24, -22, -20, -18, -15, -13, -10, + -7, -5, -2, 0, 2, 4, 5, 7, 8, 9, 10, 11, 11, 11, 11, 11, + 11, 11, 11, 10, 10, 9, 9, 8, 8, 7, 7, 6, 6, 6, 5, 5, + 5, 5, 6, 6, 6, 7, 8, 9, 10, 11, 11, 12, 12, 12, 11, 10, + 9, 7, 5, 2, -1, -5, -8, -12, -15, -18, -21, -23, -25, -26, -27, -27, + -27, -26, -25, -24, -22, -20, -18, -16, -13, -11, -8, -6, -3, -1, 1, 3, + 4, 6, 7, 8, 9, 10, 10, 10, 11, 11, 11, 10, 10, 10, 10, 9, + 9, 8, 8, 7, 7, 6, 6, 6, 5, 5, 5, 5, 6, 6, 6, 7, + 8, 9, 9, 10, 11, 11, 11, 11, 11, 10, 9, 7, 4, 2, -1, -4, + -7, -11, -14, -17, -19, -21, -23, -24, -25, -26, -26, -25, -24, -23, -22, -20, + -18, -16, -13, -11, -9, -6, -4, -2, 0, 2, 4, 5, 7, 8, 9, 9, + 10, 10, 11, 11, 11, 11, 10, 10, 10, 9, 9, 8, 8, 7, 7, 7, + 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 8, 9, 9, 10, 11, 11, + 11, 11, 10, 10, 8, 7, 5, 2, -1, -3, -7, -10, -13, -15, -18, -20, + -22, -23, -24, -25, -25, -24, -24, -23, -21, -20, -18, -16, -14, -11, -9, -7, + -5, -2, 0, 1, 3, 5, 6, 7, 8, 9, 9, 10, 10, 10, 10, 10, + 10, 10, 9, 9, 8, 8, 8, 7, 7, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 7, 7, 8, 8, 9, 9, 9, 10, 9, 9, 8, 7, 6, 4, + 2, 0, -2, -5, -7, -10, -12, -15, -17, -18, -20, -21, -21, -22, -22, -21, + -21, -20, -18, -17, -15, -13, -12, -10, -8, -6, -4, -2, 0, 1, 3, 4, + 5, 6, 7, 8, 8, 8, 9, 9, 9, 9, 9, 8, 8, 8, 8, 7, + 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, + 8, 8, 8, 8, 7, 6, 5, 4, 3, 1, -1, -3, -5, -7, -9, -10, + -12, -14, -15, -16, -17, -18, -18, -18, -18, -17, -17, -16, -15, -13, -12, -11, + -9, -7, -6, -4, -3, -1, 0, 1, 3, 4, 5, 5, 6, 7, 7, 7, + 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 5, + 4, 3, 2, 0, -1, -3, -5, -7, -9, -10, -12, -13, -15, -16, -17, -17, + -18, -18, -18, -17, -17, -16, -15, -14, -12, -11, -9, -8, -6, -5, -3, -2, + -1, 1, 2, 3, 4, 5, 5, 6, 6, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 6, 6, 5, 4, 3, 2, 0, -1, -3, + 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 3, 4, 5, + 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 6, 7, 8, 9, 10, 10, + 11, 12, 12, 13, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23, 24, 26, + 27, 29, 29, 29, 28, 28, 28, 29, 30, 31, 31, 31, 31, 28, 19, -8, + -41, -53, -57, -59, -60, -62, -62, -63, -64, -65, -65, -66, -67, -69, -69, -69, + -72, -74, -73, -74, -76, -78, -79, -81, -82, -82, -83, -81, -83, -85, -81, -81, + -88, -90, -80, -64, -47, -32, -23, -18, -15, -13, -12, -12, -12, -13, -13, -13, + -13, -13, -12, -12, -11, -9, -7, -6, -4, -2, -1, 0, 1, 2, 4, 5, + 7, 10, 12, 14, 16, 18, 19, 18, 19, 21, 19, 20, 22, 22, 22, 25, + 27, 28, 29, 29, 29, 29, 29, 30, 31, 31, 31, 33, 34, 34, 35, 34, + 33, 31, 30, 29, 26, 25, 26, 25, 22, 22, 21, 20, 20, 19, 19, 19, + 18, 18, 18, 17, 17, 17, 17, 16, 16, 16, 15, 13, 13, 14, 14, 15, + 13, 12, 13, 13, 11, 12, 14, 14, 16, 17, 15, 16, 19, 19, 19, 19, + 21, 19, 17, 18, 19, 18, 15, 15, 17, 18, 18, 13, 11, 14, 15, 14, + 11, 6, 5, 10, 13, 17, 18, 11, 2, -2, -2, -3, 2, 14, 24, 30, + 37, 47, 52, 52, 56, 63, 65, 65, 63, 65, 72, 75, 73, 71, 73, 77, + 82, 82, 77, 77, 82, 90, 99, 104, 99, 89, 84, 86, 94, 106, 119, 127, + 126, 117, 104, 87, 64, 42, 24, 10, -2, -15, -22, -25, -27, -30, -35, -37, + -36, -34, -33, -36, -40, -42, -44, -43, -44, -48, -53, -57, -59, -57, -53, -52, + -53, -57, -62, -68, -73, -75, -75, -71, -63, -56, -48, -40, -34, -29, -26, -23, + -22, -21, -19, -19, -20, -21, -22, -22, -22, -22, -22, -21, -21, -21, -20, -19, + -19, -18, -18, -17, -17, -16, -14, -14, -13, -11, -9, -9, -9, -9, -9, -8, + -8, -8, -8, -8, -7, -6, -7, -6, -4, -3, -2, -2, -3, -4, -3, -3, + -2, -1, 0, 0, -1, -1, 0, -1, -1, -1, -3, -5, -5, -8, -10, -10, + -9, -9, -10, -11, -11, -11, -11, -11, -10, -9, -10, -10, -10, -11, -12, -12, + -13, -12, -11, -12, -14, -14, -11, -10, -12, -11, -11, -12, -12, -11, -11, -13, + -12, -9, -6, -6, -7, -7, -6, -5, -4, -4, -5, -8, -12, -11, -8, -4, + -3, -5, -6, -7, -9, -12, -13, -8, -3, -2, -4, -8, -11, -14, -15, -17, + -19, -19, -15, -8, -1, 2, 4, 8, 12, 17, 23, 26, 25, 24, 25, 30, + 36, 40, 39, 36, 33, 32, 33, 37, 43, 49, 53, 53, 49, 45, 43, 43, + 46, 52, 60, 67, 76, 82, 82, 78, 69, 58, 47, 37, 26, 14, 2, -9, + -16, -21, -24, -28, -32, -35, -37, -38, -37, -36, -36, -36, -39, -43, -46, -49, + -51, -49, -47, -46, -45, -45, -48, -52, -58, -62, -65, -66, -65, -62, -58, -54, + -50, -45, -39, -34, -30, -28, -25, -23, -21, -20, -20, -20, -20, -19, -18, -19, + -20, -18, -17, -18, -17, -17, -18, -17, -16, -15, -15, -13, -12, -10, -10, -10, + -9, -8, -7, -6, -4, -4, -5, -6, -5, -4, -4, -3, -2, -2, -1, -1, + -1, 0, 2, 3, 2, 2, 3, 2, 1, 2, 4, 5, 5, 4, 4, 4, + 3, 2, 2, 1, 0, 0, -1, -4, -5, -4, -2, -2, -3, -3, -3, -2, + -1, -2, -3, -2, -3, -4, -4, -3, -4, -6, -7, -4, 0, 0, -2, -4, + -4, -3, -2, -2, -3, -4, -4, -3, -2, -1, 3, 6, 8, 6, 3, 0, + 0, 2, 4, 5, 4, 3, 2, 2, 2, 1, 0, -1, 2, 7, 11, 9, + 6, 2, -1, -3, -3, -5, -7, -8, -6, -3, 2, 8, 13, 17, 18, 18, + 19, 23, 28, 34, 40, 42, 42, 40, 39, 39, 40, 42, 46, 50, 55, 59, + 59, 55, 51, 48, 48, 51, 57, 63, 70, 76, 82, 86, 88, 89, 86, 80, + 71, 61, 51, 43, 34, 25, 18, 10, 2, -5, -9, -12, -13, -12, -12, -13, + -14, -17, -22, -26, -29, -28, -27, -25, -24, -24, -25, -27, -31, -35, -40, -43, + -46, -47, -49, -49, -46, -43, -40, -36, -32, -28, -24, -21, -18, -16, -14, -13, + -13, -12, -11, -11, -12, -11, -10, -9, -11, -11, -11, -12, -12, -12, -10, -10, + -10, -10, -9, -8, -7, -6, -5, -4, -4, -4, -4, -4, -3, -2, -2, -1, + -2, -3, -2, -1, 0, 0, 1, 2, 3, 2, 1, 1, 2, 3, 3, 4, + 5, 4, 4, 5, 6, 7, 6, 4, 3, 3, 3, 2, -1, -3, -3, -1, + -1, -2, -3, -3, -2, -1, 1, 0, -1, -1, -2, -5, -6, -5, -4, -4, + -4, -4, -6, -6, -4, -1, 0, -2, -6, -9, -10, -8, -5, -4, -3, -3, + -1, 1, 1, -1, -3, -4, -2, 0, 2, 2, 0, -3, -6, -7, -6, -4, + -3, -2, -1, -1, -1, 0, 1, 0, -3, -9, -14, -18, -18, -15, -12, -9, + -8, -7, -5, -3, -2, 0, 5, 11, 17, 22, 25, 24, 23, 21, 20, 22, + 27, 32, 37, 40, 41, 40, 39, 37, 35, 34, 34, 35, 39, 45, 52, 59, + 66, 71, 73, 75, 74, 71, 65, 60, 55, 48, 39, 28, 17, 7, -1, -7, + -11, -13, -13, -14, -17, -21, -24, -28, -31, -32, -32, -32, -32, -31, -29, -29, + -30, -33, -36, -40, -44, -47, -50, -52, -54, -55, -54, -52, -49, -47, -43, -39, + -35, -31, -28, -26, -24, -22, -21, -19, -18, -17, -17, -16, -15, -16, -18, -17, + -16, -16, -17, -18, -18, -17, -16, -16, -14, -13, -13, -12, -12, -12, -11, -10, + -10, -9, -7, -8, -9, -10, -10, -8, -6, -5, -6, -6, -5, -3, -3, -4, + -4, -4, -3, -2, -2, -1, -1, -1, 0, 2, 3, 3, 3, 2, 1, 0, + -1, -1, -1, -2, -3, -5, -5, -4, -2, -3, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 3, 2, 0, + -1, 1, 2, 1, -1, -1, 2, 2, 0, 1, 2, 2, -1, -4, -10, -21, + -30, -36, -41, -44, -40, -30, -18, -10, -8, -11, -13, -8, 3, 18, 32, 41, + 44, 45, 48, 49, 43, 32, 23, 14, 7, 8, 16, 27, 35, 37, 30, 18, + 9, 5, 3, 2, 1, 1, -1, -6, -11, -12, -6, -2, -5, -11, -18, -28, + -39, -47, -55, -69, -86, -99, -102, -92, -70, -46, -28, -15, -3, 7, 17, 26, + 28, 24, 23, 30, 42, 53, 57, 50, 36, 21, 5, -5, -4, 6, 20, 31, + 35, 34, 29, 26, 27, 37, 56, 76, 85, 80, 71, 63, 55, 47, 34, 13, + -13, -32, -39, -40, -46, -65, -93, -117, -128, -128, -126, -120, -110, -96, -78, -58, + -36, -14, 3, 10, 20, 41, 60, 68, 63, 54, 45, 39, 36, 32, 28, 29, + 35, 41, 47, 46, 41, 39, 43, 53, 68, 80, 78, 64, 46, 28, 13, 3, + -9, -35, -64, -80, -82, -74, -66, -71, -91, -111, -121, -118, -105, -86, -68, -57, + -49, -37, -22, -7, 5, 14, 26, 42, 55, 56, 46, 35, 25, 14, 6, 2, + 1, 3, 11, 22, 32, 40, 43, 42, 46, 60, 77, 88, 90, 78, 54, 30, + 14, 2, -15, -37, -62, -82, -90, -89, -86, -90, -99, -107, -109, -101, -81, -54, + -29, -14, -5, 7, 24, 40, 49, 56, 68, 83, 92, 92, 87, 74, 54, 32, + 12, -5, -19, -25, -24, -18, -7, 1, -1, -6, -4, 13, 41, 69, 84, 80, + 63, 44, 32, 29, 25, 11, -10, -25, -31, -35, -40, -48, -65, -87, -104, -109, + -102, -87, -69, -58, -54, -42, -21, 0, 13, 29, 51, 71, 84, 89, 86, 75, + 54, 33, 14, -3, -19, -29, -27, -22, -18, -11, -8, -16, -26, -19, 2, 24, + 40, 48, 42, 27, 21, 29, 34, 24, 7, -5, -14, -23, -28, -32, -45, -67, + -82, -85, -78, -63, -46, -34, -29, -24, -13, 0, 12, 25, 44, 65, 79, 85, + 86, 78, 60, 41, 27, 12, -5, -15, -15, -14, -13, -8, -7, -17, -27, -23, + -3, 23, 44, 51, 43, 25, 12, 11, 14, 8, -3, -10, -15, -22, -28, -30, + -36, -55, -73, -78, -74, -71, -63, -51, -43, -39, -34, -25, -18, -9, 8, 28, + 46, 56, 61, 62, 58, 47, 36, 28, 20, 12, 11, 16, 19, 20, 21, 15, + 0, -6, 10, 37, 57, 63, 55, 36, 15, 2, -3, -9, -19, -27, -34, -43, + -49, -49, -52, -66, -82, -86, -81, -77, -71, -61, -51, -47, -43, -35, -22, -12, + 2, 24, 47, 58, 63, 67, 66, 58, 51, 45, 34, 18, 9, 7, 7, 7, + 8, 1, -14, -24, -12, 18, 47, 64, 68, 63, 53, 42, 37, 38, 36, 29, + 21, 16, 11, 5, -2, -17, -36, -49, -52, -56, -62, -63, -61, -61, -63, -60, + -56, -49, -37, -19, 2, 17, 25, 30, 34, 37, 37, 37, 34, 25, 15, 11, + 13, 14, 14, 8, -7, -21, -16, 9, 37, 53, 60, 61, 53, 40, 33, 34, + 32, 22, 14, 12, 10, 6, -2, -15, -32, -48, -57, -60, -63, -67, -66, -63, + -63, -65, -64, -58, -49, -34, -13, 6, 16, 21, 28, 34, 38, 41, 43, 36, + 25, 19, 21, 26, 27, 20, 4, -11, -11, 7, 31, 53, 66, 70, 66, 57, + 49, 47, 44, 33, 21, 17, 16, 10, 1, -9, -26, -46, -60, -67, -76, -84, + -84, -80, -78, -79, -78, -73, -65, -52, -32, -11, 4, 10, 17, 25, 32, 36, + 40, 37, 24, 13, 15, 23, 23, 11, -5, -19, -25, -16, 9, 38, 59, 70, + 72, 67, 63, 63, 60, 50, 39, 32, 28, 22, 14, 3, -14, -34, -53, -65, + -76, -87, -94, -93, -91, -94, -96, -93, -86, -76, -56, -30, -9, 4, 16, 29, + 40, 51, 63, 65, 52, 39, 39, 45, 42, 29, 11, -7, -22, -24, -8, 19, + 42, 54, 60, 63, 61, 58, 57, 53, 43, 36, 36, 34, 28, 21, 11, -5, + -24, -39, -52, -65, -75, -77, -75, -75, -78, -80, -78, -73, -61, -43, -23, -9, + 1, 10, 23, 39, 52, 56, 47, 36, 35, 41, 42, 33, 17, -2, -24, -35, + -26, -3, 18, 32, 42, 50, 52, 53, 52, 47, 38, 31, 30, 31, 29, 26, + 22, 14, -1, -18, -33, -46, -58, -65, -65, -65, -71, -79, -81, -79, -75, -62, + -42, -27, -21, -14, 1, 19, 34, 40, 36, 29, 27, 31, 38, 39, 29, 9, + -12, -27, -28, -14, 8, 25, 37, 50, 62, 67, 66, 62, 53, 42, 36, 37, + 36, 32, 30, 25, 12, -7, -24, -39, -54, -65, -67, -67, -72, -78, -81, -82, + -81, -70, -51, -35, -29, -23, -7, 15, 30, 37, 40, 35, 25, 25, 36, 41, + 33, 15, -6, -26, -36, -27, -9, 7, 20, 35, 50, 58, 59, 58, 52, 43, + 37, 37, 37, 36, 34, 31, 24, 8, -11, -29, -44, -57, -67, -70, -73, -79, + -86, -92, -93, -87, -72, -59, -53, -46, -29, -9, 7, 20, 28, 26, 19, 17, + 27, 38, 38, 26, 7, -12, -25, -26, -15, 1, 14, 28, 47, 61, 67, 68, + 68, 63, 54, 51, 53, 51, 49, 49, 47, 34, 14, -5, -22, -39, -56, -65, + -67, -73, -86, -96, -97, -92, -86, -77, -69, -61, -49, -28, -6, 10, 22, 27, + 25, 24, 33, 49, 56, 48, 32, 13, -5, -15, -12, -2, 7, 18, 35, 50, + 59, 63, 65, 61, 53, 48, 46, 44, 43, 46, 49, 43, 27, 10, -6, -25, + -45, -53, -53, -60, -75, -87, -90, -90, -88, -81, -75, -72, -65, -48, -25, -6, + 5, 10, 13, 18, 31, 49, 60, 58, 44, 28, 12, -1, -7, -7, -1, 8, + 23, 41, 54, 61, 65, 66, 63, 56, 48, 43, 41, 42, 44, 43, 37, 25, + 8, -12, -32, -44, -49, -53, -64, -80, -91, -95, -93, -89, -85, -82, -78, -68, + -50, -27, -6, 0, -1, 0, 0, 0, 1, 2, 3, 6, 9, 13, 17, 19, + 13, -4, -15, -10, 4, 19, 26, 15, -9, -16, 6, -2, -18, 38, 64, 21, + -48, 30, 82, -23, -63, -50, -26, -7, 12, 26, 47, 83, 100, 3, -108, -87, + -30, -6, 5, 18, 33, 46, 47, 21, -52, -46, 48, 3, -54, -32, 22, 25, + -7, 12, 9, -18, -33, -24, 2, 44, 88, 92, 10, -28, -1, 1, 20, 42, + 1, -17, 53, 72, 12, -16, -74, -31, 127, 52, 1, -35, -46, 13, 39, -13, + -13, 13, 12, 11, 8, -57, -80, -44, -5, 14, 18, 6, -13, -26, -11, -8, + -24, 3, 30, 14, -28, -12, 41, -2, -37, -35, -23, -12, -1, 6, 17, 34, + 53, 19, -55, -67, -32, -13, -5, 2, 12, 19, 24, 14, -24, -47, 12, 11, + -36, -35, -1, 18, -3, 0, 5, -13, -25, -22, -5, 19, 53, 69, 21, -28, + -10, -5, 6, 28, 8, -25, 23, 57, 17, -17, -49, -63, 84, 70, 3, -23, + -50, -6, 36, -2, -20, 8, 14, 9, 13, -37, -82, -58, -19, 8, 17, 10, + -9, -26, -19, -7, -24, -9, 25, 22, -17, -28, 33, 16, -32, -37, -27, -15, + -4, 4, 13, 27, 48, 35, -35, -72, -43, -17, -7, -1, 9, 16, 23, 17, + -12, -51, -7, 21, -27, -40, -12, 19, 6, -3, 5, -9, -22, -23, -8, 11, + 42, 68, 38, -23, -16, -6, 3, 25, 19, -24, 8, 54, 31, -13, -33, -76, + 46, 95, 13, -13, -48, -20, 32, 13, -22, 2, 15, 10, 15, -17, -77, -67, + -31, 3, 17, 15, -3, -21, -23, -7, -20, -18, 18, 27, -4, -34, 17, 33, + -21, -36, -29, -16, -6, 4, 11, 23, 42, 47, -12, -69, -54, -22, -8, -2, + 7, 15, 22, 20, -2, -46, -27, 23, -13, -41, -22, 15, 16, -2, 4, -5, + -18, -21, -10, 5, 32, 64, 53, -12, -21, -6, 0, 21, 27, -16, -6, 48, + 42, -6, -22, -71, 2, 106, 31, -6, -41, -32, 22, 25, -18, -4, 15, 12, + 14, -1, -64, -74, -42, -5, 16, 19, 4, -16, -25, -10, -14, -23, 9, 29, + 9, -31, -2, 42, -5, -33, -30, -18, -8, 3, 9, 19, 36, 51, 10, -58, + -63, -29, -11, -2, 4, 13, 20, 21, 6, -35, -44, 16, 1, -38, -30, 7, + 23, 3, 2, -2, -16, -20, -12, 2, 23, 56, 62, 3, -24, -7, -2, 17, + 30, -5, -17, 37, 49, 4, -17, -57, -37, 99, 55, 0, -31, -41, 9, 33, + -10, -11, 13, 14, 12, 9, -47, -78, -53, -15, 12, 20, 9, -10, -24, -14, + -11, -25, -2, 27, 18, -21, -20, 39, 13, -29, -31, -20, -9, 1, 8, 17, + 30, 49, 29, -41, -70, -39, -15, -4, 2, 11, 17, 21, 11, -22, -52, 0, + 14, -31, -36, -4, 25, 11, 1, -1, -13, -19, -13, 0, 15, 45, 65, 20, + -24, -10, -4, 12, 30, 8, -22, 24, 52, 17, -14, -39, -61, 71, 81, 8, + -21, -44, -5, 34, 2, -16, 9, 16, 11, 14, -29, -76, -62, -27, 6, 20, + 15, -4, -21, -19, -9, -23, -12, 22, 25, -8, -30, 26, 30, -20, -31, -23, + -11, -1, 8, 14, 25, 44, 42, -19, -69, -50, -20, -6, 1, 9, 15, 20, + 15, -11, -51, -19, 20, -20, -39, -15, 23, 20, 2, 0, -11, -17, -14, -2, + 9, 35, 63, 37, -19, -14, -5, 8, 28, 18, -22, 9, 50, 28, -11, -26, + -68, 32, 100, 22, -13, -43, -18, 30, 15, -17, 4, 16, 12, 15, -12, -69, + -69, -39, -2, 18, 19, 2, -17, -22, -10, -19, -20, 15, 27, 4, -31, 7, + 41, -7, -30, -25, -13, -3, 6, 12, 22, 38, 48, 3, -61, -60, -27, -9, + 0, 7, 13, 19, 17, -2, -44, -37, 18, -7, -39, -24, 15, 28, 7, 0, + -9, -16, -14, -3, 6, 25, 57, 49, -9, -18, -7, 3, 25, 26, -15, -4, + 45, 38, -5, -18, -61, -8, 103, 42, -6, -37, -30, 21, 25, -13, -3, 16, + 13, 14, 2, -56, -73, -49, -12, 15, 21, 8, -11, -23, -13, -15, -24, 4, + 28, 14, -25, -12, 42, 9, -26, -26, -15, -5, 5, 11, 19, 32, 48, 22, + -46, -67, -36, -12, -2, 4, 12, 17, 18, 4, -33, -50, 6, 6, -35, -31, + 4, 31, 14, 0, -8, -15, -14, -4, 4, 17, 48, 57, 4, -21, -8, -1, + 21, 30, -5, -15, 36, 44, 5, -14, -46, -40, 88, 67, 2, -29, -37, 9, + 31, -6, -9, 14, 15, 13, 11, -40, -74, -58, -24, 9, 22, 13, -6, -21, + -17, -13, -25, -6, 25, 21, -13, -25, 33, 26, -19, -27, -18, -6, 3, 10, + 16, 27, 45, 36, -26, -69, -46, -17, -4, 2, 10, 15, 18, 9, -22, -55, + -11, 15, -26, -36, -8, 30, 23, 2, -6, -14, -14, -6, 4, 11, 37, 59, + 19, -20, -10, -4, 16, 31, 7, -20, 23, 47, 15, -13, -32, -58, 58, 88, + 13, -21, -40, -5, 32, 4, -13, 10, 17, 12, 14, -23, -70, -65, -35, 1, + 20, 17, 0, -18, -20, -12, -23, -16, 19, 25, -1, -30, 16, 39, -8, -26, + -20, -8, 1, 9, 14, 23, 39, 44, -5, -63, -57, -24, -7, 1, 8, 13, + 17, 12, -12, -52, -30, 17, -15, -38, -18, 23, 32, 7, -6, -13, -14, -7, + 3, 8, 27, 55, 33, -16, -13, -6, 10, 30, 17, -20, 10, 46, 25, -9, + -21, -60, 19, 100, 31, -13, -39, -17, 27, 15, -13, 4, 17, 13, 15, -8, + -61, -69, -46, -10, 17, 21, 6, -13, -22, -13, -20, -22, 10, 27, 9, -27, + -4, 44, 6, -24, -22, -11, -1, 8, 13, 20, 33, 46, 14, -50, -65, -33, + -11, 0, 5, 12, 15, 14, -4, -43, -46, 10, -2, -36, -27, 13, 36, 15, + -4, -13, -14, -8, 3, 7, 18, 49, 43, -7, -16, -7, 5, 27, 24, -14, + -3, 42, 33, -3, -16, -51, -17, 97, 51, -3, -38, -5, -13, 1, -7, 5, + -22, -32, -35, -32, -43, -35, -55, -42, -66, -48, -80, -57, -17, -128, -59, -76, + 0, -26, 1, -33, 21, 3, 16, 15, 26, 43, 28, 66, 6, 97, 40, 103, + 67, 101, 102, 98, 94, 21, 98, 90, 57, 78, 89, 81, 61, -6, 54, 4, + 62, 19, 27, 34, 12, 16, 14, -17, 19, -5, -2, -13, -38, -24, -3, -33, + -14, -11, -16, 0, -13, 7, -26, -13, -16, 6, -57, -23, -28, -13, -9, -34, + -32, -20, -87, -62, -28, -38, -75, -37, -27, -41, -71, -48, -30, -44, -83, -67, + -52, -48, -45, -46, -45, -63, -47, -40, -32, -45, -24, -32, -43, -21, -17, 0, + 21, 26, 43, 51, 62, 47, 41, 55, 57, 68, 34, 53, 63, 62, 71, 60, + 61, 56, 53, 56, 54, 38, 50, 58, 50, 40, 28, 54, 39, 41, 38, 22, + 32, 20, -3, 19, -1, -7, -6, -16, -16, -14, -27, -29, -46, -66, -61, -51, + -54, -61, -41, -50, -47, -52, -55, -45, -44, -28, -58, -56, -31, -37, -36, -32, + -18, -16, -34, -29, -9, -21, -20, -30, -22, -17, -19, -8, -12, -14, -6, -14, + -6, -11, -2, 4, -6, 9, 8, 17, 23, 13, 31, 13, 24, 30, 28, 29, + 30, 43, 34, 37, 52, 42, 44, 50, 67, 59, 49, 54, 48, 43, 51, 45, + 42, 62, 47, 39, 37, 36, 24, 28, 13, 3, 9, -11, -3, -9, -14, -18, + -34, -27, -29, -39, -42, -38, -46, -37, -46, -43, -41, -35, -38, -31, -38, -34, + -39, -39, -34, -48, -44, -47, -49, -54, -52, -44, -53, -37, -47, -38, -31, -38, + -27, -19, -19, -15, -16, 0, 0, 2, 7, 13, 29, 22, 32, 32, 39, 47, + 41, 40, 55, 48, 41, 44, 57, 43, 36, 47, 43, 42, 37, 32, 32, 27, + 33, 36, 30, 23, 25, 25, 22, 18, 22, 20, 16, 8, 6, 12, 7, 0, + 1, 3, -5, -14, -9, -7, -8, -19, -15, -16, -23, -21, -21, -32, -31, -29, + -26, -27, -29, -33, -26, -29, -30, -39, -28, -41, -43, -35, -34, -32, -29, -28, + -28, -25, -27, -24, -27, -27, -27, -22, -23, -17, -9, -10, -14, -10, -8, -4, + -2, -1, -3, 5, 4, 10, 11, 7, 13, 11, 14, 27, 22, 22, 22, 27, + 36, 34, 36, 37, 45, 44, 47, 48, 51, 49, 52, 51, 52, 48, 50, 47, + 48, 42, 40, 29, 33, 24, 22, 12, 5, 0, -3, -5, -9, -21, -21, -25, + -19, -28, -28, -30, -33, -39, -42, -42, -46, -46, -45, -42, -43, -47, -47, -36, + -32, -30, -34, -31, -22, -29, -29, -30, -26, -28, -30, -21, -26, -27, -21, -19, + -16, -11, -12, -8, -2, 1, -4, 1, 0, 1, 9, 8, 7, 12, 10, 13, + 20, 17, 18, 21, 26, 29, 30, 30, 29, 34, 33, 34, 33, 30, 32, 33, + 28, 33, 29, 35, 32, 31, 30, 31, 30, 25, 27, 24, 21, 21, 20, 16, + 17, 12, 6, 4, -3, 1, -6, -7, -11, -13, -11, -10, -8, -13, -12, -9, + -17, -14, -19, -24, -22, -24, -30, -32, -30, -33, -37, -39, -40, -42, -39, -41, + -39, -40, -41, -35, -35, -35, -37, -36, -33, -30, -25, -25, -19, -16, -16, -10, + -6, -7, -4, -2, 1, 3, 6, 10, 9, 15, 17, 18, 17, 13, 19, 18, + 17, 19, 20, 24, 24, 27, 27, 29, 30, 26, 28, 28, 27, 28, 26, 25, + 24, 25, 20, 19, 17, 18, 15, 12, 13, 10, 6, 8, 6, 3, 4, 3, + 0, -3, 0, -1, -2, -5, -4, -5, -4, -5, -6, -8, -9, -9, -12, -11, + -16, -16, -15, -15, -13, -17, -16, -17, -17, -21, -20, -25, -24, -24, -24, -26, + -30, -30, -27, -30, -26, -26, -27, -27, -25, -24, -19, -20, -17, -13, -12, -8, + -8, -8, -6, -5, -2, -1, 0, 3, 8, 10, 12, 16, 18, 24, 25, 25, + 28, 30, 28, 32, 33, 31, 32, 31, 35, 33, 31, 31, 27, 28, 26, 23, + 23, 20, 22, 18, 16, 13, 11, 9, 5, 4, -2, -2, -3, -8, -9, -11, + -12, -13, -15, -15, -15, -15, -15, -14, -12, -12, -13, -13, -8, -11, -10, -12, + -10, -12, -12, -8, -8, -9, -9, -9, -8, -9, -10, -11, -11, -10, -13, -14, + -13, -16, -16, -17, -17, -18, -19, -18, -17, -16, -16, -15, -15, -13, -12, -10, + -12, -10, -9, -8, -6, -6, -3, 0, 0, 1, 2, 2, 3, 4, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 12, 13, 14, 14, 15, 15, 15, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 14, 13, 13, 12, 11, 10, + 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -1, -2, -3, -4, -5, + -5, -6, -7, -7, -8, -9, -9, -10, -11, -11, -12, -12, -13, -13, -13, -13, + -14, -14, -14, -15, -15, -15, -15, -15, -15, -16, -16, -16, -15, -15, -15, -14, + -13, -13, -12, -11, -10, -9, -8, -7, -6, -5, -4, -2, -1, 0, 1, 2, + 4, 5, 6, 7, 8, 9, 10, 11, 12, 12, 13, 13, 14, 14, 15, 15, + 15, 15, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 16, 16, 15, 15, + 14, 14, 13, 12, 11, 10, 9, 7, 6, 5, 3, 1, 0, -2, -4, -5, + -7, -9, -10, -11, -13, -14, -15, -15, -16, -17, -17, -18, -18, -18, -18, -18, + -18, -18, -18, -18, -18, -18, -18, -17, -17, -16, -16, -15, -14, -14, -13, -12, + -11, -10, -9, -8, -7, -6, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 9, 10, 11, 11, 12, 13, 13, 13, 14, 14, 14, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, 13, 12, 12, + 11, 10, 9, 8, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, -1, 0, + 0, -1, 2, 1, 0, 1, 4, 2, 2, 2, 5, 2, 5, 5, 8, 4, + 13, 15, 19, -62, -65, 56, -18, -128, -39, 15, -57, -10, 19, -22, -11, 36, + 30, 5, 19, 25, 17, 21, 21, 16, 21, 18, 17, 17, 15, 14, 13, 12, + 10, 6, 8, 6, 6, -1, 1, -4, 7, -10, -36, 35, 64, -25, -18, 83, + 50, 22, 39, 21, 19, -4, -20, 28, 0, -88, -55, -5, -55, -83, -64, -58, + -77, -61, -22, -39, -57, -15, 2, -14, -9, -1, 1, 1, 2, 9, 5, 6, + 11, 9, 9, 10, 11, 12, 12, 10, 9, 9, 13, 7, 3, 14, 4, -3, + 2, 2, 17, 40, 12, 14, 55, 58, 44, 39, 38, 37, 6, 4, 31, -6, + -50, -25, -15, -49, -52, -41, -60, -68, -32, -25, -47, -36, -9, -5, -7, -3, + 3, 4, 6, 8, 11, 9, 10, 14, 14, 11, 13, 15, 14, 13, 14, 12, + 11, 12, 12, 8, 8, 3, 4, 5, -1, 8, 32, 21, 14, 43, 50, 39, + 47, 39, 20, 23, 16, 5, -9, -23, -26, -34, -48, -37, -48, -71, -56, -34, + -43, -49, -36, -20, -14, -13, -9, -4, -1, 1, 3, 6, 6, 6, 9, 10, + 8, 10, 11, 11, 11, 11, 10, 10, 10, 10, 6, 6, 4, 3, 6, -3, + 2, 25, 23, 16, 34, 38, 43, 51, 31, 19, 38, 22, -10, -7, 0, -25, + -45, -34, -32, -54, -62, -47, -39, -45, -47, -36, -24, -19, -16, -11, -6, -3, + 0, 2, 4, 6, 7, 8, 10, 11, 9, 11, 12, 11, 11, 12, 11, 10, + 10, 8, 7, 6, 3, 5, 4, 0, 13, 28, 23, 19, 36, 50, 42, 30, + 31, 39, 24, -6, -2, 7, -21, -40, -27, -34, -51, -51, -44, -42, -45, -45, + -37, -27, -22, -18, -13, -9, -6, -2, 1, 2, 5, 7, 7, 9, 11, 10, + 10, 12, 12, 11, 12, 11, 10, 10, 9, 7, 7, 4, 5, 7, 1, 7, + 27, 24, 15, 34, 47, 37, 32, 36, 36, 26, 4, -1, 4, -13, -30, -27, + -34, -47, -46, -42, -43, -45, -44, -38, -31, -25, -21, -17, -12, -8, -5, -1, + 1, 3, 5, 6, 8, 9, 10, 10, 10, 11, 11, 11, 11, 11, 10, 9, + 7, 7, 6, 3, 6, 5, 6, 17, 23, 19, 29, 40, 35, 33, 36, 34, + 26, 14, 3, 0, -6, -18, -26, -32, -39, -40, -38, -39, -41, -40, -36, -31, + -27, -23, -19, -15, -12, -8, -4, -2, 0, 3, 4, 5, 7, 8, 9, 9, + 9, 10, 10, 10, 10, 10, 9, 8, 8, 8, 7, 8, 10, 11, 14, 19, + 22, 25, 28, 29, 29, 29, 27, 21, 14, 7, -1, -5, -11, -19, -26, -29, + -31, -32, -33, -34, -33, -32, -29, -26, -24, -21, -18, -15, -12, -9, -6, -4, + -2, 0, 2, 3, 5, 6, 7, 7, 8, 8, 9, 9, 9, 9, 9, 9, + 10, 10, 11, 12, 14, 16, 18, 20, 22, 23, 24, 24, 23, 20, 17, 12, + 7, 2, -3, -8, -13, -17, -21, -23, -25, -26, -27, -27, -27, -26, -25, -23, + -21, -19, -17, -14, -12, -9, -7, -5, -3, -1, 1, 2, 4, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 12, 13, 15, 16, 18, 19, 21, + 22, 22, 22, 21, 19, 17, 13, 9, 4, 0, -5, -10, -14, -18, -21, -23, + -25, -26, -26, -26, -26, -25, -23, -22, -20, -18, -15, -13, -11, -9, -6, -4, + -2, 0, 1, 3, 4, 5, 6, 7, 7, 8, 8, 8, 9, 9, 10, 11, + 12, 13, 14, 15, 17, 18, 20, 21, 21, 21, 21, 19, 17, 14, 11, 7, + 2, -3, -7, -11, -15, -19, -21, -23, -25, -25, -26, -25, -25, -24, -22, -21, + -19, -17, -15, -12, -10, -8, -6, -4, -2, 0, 1, 3, 4, 5, 6, 6, + 7, 8, 8, 9, 9, 10, 11, 11, 12, 13, 15, 16, 17, 19, 20, 20, + 21, 20, 19, 18, 15, 12, 8, 4, 0, -4, -9, -13, -16, -19, -21, -23, + -24, -25, -25, -25, -24, -23, -21, -20, -18, -16, -14, -12, -9, -7, -5, -3, + -2, 0, 1, 3, 4, 5, 6, 6, 7, 8, 8, 9, 10, 10, 11, 12, + 13, 14, 15, 17, 18, 19, 20, 20, 20, 19, 18, 16, 13, 10, 6, 2, + -2, -6, -10, -13, -16, -19, -21, -23, -24, -24, -24, -24, -23, -22, -20, -19, + -17, -15, -13, -11, -8, -6, -5, -3, -1, 0, 2, 3, 4, 5, 6, 7, + 7, 8, 9, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, + 19, 18, 16, 14, 11, 8, 4, 0, -3, -7, -11, -14, -17, -19, -21, -22, + -23, -23, -23, -23, -22, -21, -19, -18, -16, -14, -12, -10, -8, -6, -4, -2, + -1, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 10, 11, 12, 12, 13, + 14, 15, 16, 17, 18, 19, 19, 19, 18, 17, 15, 12, 9, 6, 3, -1, + -5, -9, -12, -15, -17, -19, -21, -22, -23, -23, -23, -22, -21, -20, -18, -17, + -15, -13, -11, -9, -7, -6, -4, -2, -1, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 9, 10, 11, 12, 13, 14, 15, 16, 17, 17, 18, 18, 18, 17, + 16, 14, 12, 10, 7, 4, 0, -3, -6, -9, -12, -15, -17, -18, -20, -20, + -21, -21, -21, -20, -19, -18, -17, -15, -14, -12, -10, -9, -7, -5, -4, -2, + -1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 14, + 15, 15, 16, 16, 16, 16, 16, 15, 14, 12, 11, 8, 6, 3, 0, -3, + -6, -9, -12, 1, -1, 2, -1, 4, 2, 8, 5, 10, -5, 0, 5, 17, + -11, 0, 19, -17, 26, 65, 15, 29, 3, 35, 67, 50, 88, 59, 117, 28, + -6, -16, 29, 63, 62, -40, 59, 22, -95, -49, -55, 19, 36, -15, 26, -117, + 60, 8, -101, -115, 23, 60, -32, -106, -84, -88, -127, -99, -117, -110, -56, -42, + -53, -79, -44, 43, 10, -11, 72, 22, 61, 10, -92, -106, -111, -35, -68, -128, + -67, -36, -118, -97, -96, -4, 75, 70, 113, 36, 73, 115, 37, 6, 79, 97, + 89, -8, -38, -8, -72, -8, -29, -35, 73, 98, 66, 12, 40, 113, 106, 87, + 126, 112, 127, 87, -3, -21, -23, 40, 14, -68, -20, 21, -57, -67, -67, -4, + 69, 53, 90, 17, 36, 78, -7, -54, -2, 32, 21, -71, -109, -89, -124, -103, + -114, -113, -37, -4, -30, -88, -83, 15, 13, -35, 42, 28, 33, 14, -90, -92, + -104, -37, -34, -115, -73, -9, -75, -89, -85, -29, 67, 51, 97, 55, 47, 115, + 46, -9, 42, 90, 96, 26, -36, 11, -43, -25, -6, -37, 59, 104, 88, 31, + 22, 96, 116, 69, 110, 119, 119, 109, 11, -15, -26, 18, 37, -45, -32, 34, + -13, -62, -62, -30, 61, 47, 75, 46, 14, 72, 14, -58, -35, 16, 30, -38, + -109, -78, -109, -116, -102, -123, -57, -2, -11, -58, -95, -18, 22, -41, -3, 36, + 20, 31, -69, -94, -100, -72, -21, -91, -92, -9, -33, -82, -81, -57, 48, 52, + 70, 81, 35, 97, 69, -10, 8, 66, 94, 55, -27, 4, -5, -40, -1, -33, + 30, 102, 101, 61, 19, 70, 121, 72, 77, 123, 112, 121, 36, -13, -21, -10, + 38, -18, -43, 27, 25, -40, -59, -45, 40, 54, 52, 68, 15, 56, 35, -48, + -58, -12, 25, -10, -98, -84, -83, -122, -101, -123, -81, -8, -3, -28, -85, -47, + 20, -28, -39, 23, 18, 31, -38, -99, -92, -97, -35, -66, -102, -26, -3, -60, + -77, -69, 18, 59, 47, 87, 46, 73, 86, 3, -13, 34, 80, 70, -8, -12, + 19, -32, -12, -21, 3, 91, 105, 87, 34, 51, 114, 89, 53, 106, 115, 119, + 65, -10, -13, -25, 20, 4, -45, 9, 44, -8, -49, -51, 14, 61, 39, 68, + 34, 39, 51, -30, -67, -41, 7, 5, -76, -96, -65, -111, -110, -115, -103, -20, + -1, -9, -58, -65, 8, -9, -55, -6, 17, 24, -11, -94, -89, -102, -64, -50, + -101, -51, 6, -30, -66, -71, -12, 59, 40, 72, 67, 58, 91, 24, -21, 6, + 56, 74, 14, -22, 23, -8, -24, -14, -13, 71, 106, 101, 62, 42, 101, 105, + 49, 76, 114, 114, 87, 3, -12, -23, -6, 13, -37, -11, 45, 24, -29, -49, + -8, 57, 40, 53, 54, 32, 56, -6, -65, -61, -21, 6, -52, -101, -65, -85, + -115, -109, -116, -42, 0, -1, -27, -65, -12, 7, -51, -37, 7, 17, 6, -76, + -95, -94, -91, -52, -90, -76, -2, -4, -46, -66, -35, 46, 46, 49, 78, 57, + 85, 50, -17, -13, 26, 64, 34, -22, 9, 18, -22, -14, -18, 42, 103, 105, + 88, 50, 83, 114, 63, 49, 96, 110, 99, 26, -14, -15, -23, 6, -24, -29, + 33, 45, 0, -38, -23, 44, 50, 37, 60, 38, 52, 21, -54, -70, -48, -7, + -31, -95, -78, -63, -104, -108, -117, -69, -4, -1, -5, -47, -30, 13, -33, -58, + -14, 8, 11, -50, -99, -87, -101, -70, -77, -92, -22, 10, -22, -52, -46, 23, + 55, 36, 70, 66, 74, 69, -2, -23, 1, 43, 43, -11, -8, 29, -4, -17, + -16, 18, 91, 105, 102, 71, 72, 112, 83, 40, 70, 101, 102, 50, -10, -10, + -24, -10, -13, -36, 14, 52, 27, -18, -28, 26, 58, 33, 51, 49, 46, 40, + -34, -70, -66, -31, -22, -81, -92, -56, -83, -105, -112, -91, -17, 0, 2, -22, + -37, 7, -12, -61, -39, -5, 7, -27, -93, -90, -96, -90, -72, -95, -48, 9, + -1, -33, -46, 0, 55, 37, 50, 72, 68, 77, 20, -25, -15, 17, 40, 3, + -20, 22, 19, -12, -14, 2, 70, 105, 106, 92, 72, 104, 100, 48, 46, 83, + 98, 70, 3, -12, -16, -23, -11, -34, -8, 46, 47, 11, -21, 8, 57, 41, + 36, 53, 45, 48, -6, -64, -72, -57, -28, -61, -98, -65, -60, -94, -105, -103, + -41, 1, 0, -1, -29, -6, 5, -48, -60, -26, -3, -12, -74, -97, -86, -100, + -80, -89, -74, -6, 13, -10, -35, -18, 41, 48, 33, 64, 68, 75, 46, -15, + -25, -7, 24, 16, -20, 4, 33, 5, -11, -5, 43, 98, 105, 105, 85, 93, + 110, 67, 35, 59, 87, 81, 25, -13, -9, -23, -18, -27, -25, 30, 55, 37, + -1, -3, 46, 53, 29, 44, 47, 48, 20, -48, -72, -72, -47, -48, -93, -82, + -51, -73, -96, -102, -66, -6, 0, 5, -10, -16, 10, -26, -66, -49, -20, -10, + -51, -98, -86, -93, -93, -85, -88, -32, 14, 8, -16, -23, 22, 54, 32, 45, + 67, 70, 61, 4, -27, -21, 2, 17, -13, -13, 29, 26, -1, -5, 23, 83, + 104, 106, 100, 90, 110, 87, 40, 38, 68, 80, 45, -6, -9, -14, -24, -23, + -32, 8, 52, 53, 25, 1, 31, 60, 35, 30, 45, 45, 36, -24, -68, -76, + -67, -49, -80, -94, -57, -54, -81, -95, -82, -23, 2, 1, 4, -12, 4, -5, + -57, -65, -40, -20, -36, -87, -94, -83, -97, -87, -90, -57, 2, 18, 2, -12, + 8, 10, -20, 30, 25, 21, 14, 4, 15, -48, -33, 11, -70, 54, -5, -21, + -8, -3, 73, -52, 65, -55, 80, -28, -67, -3, -13, 21, -49, -2, 11, 36, + 59, -60, 34, -28, 21, -25, -45, 54, 5, 0, -19, -12, 20, 54, -51, -23, + 22, 36, -59, -20, 8, 28, -9, -54, 127, -44, 69, -128, 5, 69, -8, -98, + 45, 69, 20, -97, 23, -7, 121, -81, -2, -21, 51, -67, -14, -24, 127, -60, + 45, -116, 127, -29, -93, -23, 107, -5, -21, -62, 37, 41, 29, -74, -63, 103, + 24, -59, -44, 62, 43, -28, -46, 7, 72, 19, -70, -47, 42, 53, -68, -13, + 37, 59, -38, -60, 39, 66, 27, -128, 36, 77, 15, -74, -15, 75, 38, -49, + -11, -39, 16, -8, -30, 35, 41, -1, -2, 17, -68, 99, -97, 60, -49, 32, + -44, -29, 82, -26, 39, -35, 10, 38, -20, -21, -92, 83, -24, 13, 31, -33, + 22, 45, -31, -24, 9, -24, -32, 42, -17, 34, 7, -27, 6, 61, -9, -34, + -5, -8, -17, -6, -34, 17, 43, -9, 35, -34, 16, 27, -24, -17, -17, 5, + -17, 42, -31, 22, 17, -26, -22, 32, 41, -27, -25, -10, -5, 16, -2, 13, + -1, 48, -33, -27, 6, 16, 13, -37, -11, 18, 25, -42, -11, 46, -7, -15, + 9, 15, 4, -3, -36, -24, 31, -8, 14, 12, 27, -19, -17, -14, -7, 42, + -5, -15, 5, 1, -15, 14, 43, -19, 1, -25, -35, 16, 16, 29, -12, 8, + -14, 1, 21, -8, -12, -22, -4, 24, 26, -16, -22, 37, 3, -41, 7, 4, + 3, 30, 4, -27, 11, -6, -26, 33, 23, -23, -14, -20, -7, -4, 36, 0, + 18, 10, -27, 1, 1, 16, -1, -4, -44, -5, 17, 9, 13, -4, -3, 31, + 24, -14, -26, 9, -27, -28, 19, 22, 32, -11, -15, 5, 15, -23, -21, 16, + 14, 18, -11, -26, 13, 10, -12, -12, 11, 14, -6, -13, -3, 6, -6, 3, + 12, 32, 14, -22, -45, -10, 37, 11, -50, -11, 50, 22, -13, -4, -4, 15, + -16, -33, 7, 34, -9, -14, -1, 21, 15, -14, -12, -6, 7, 8, 2, 0, + -5, 6, 15, 4, -9, 13, 3, -51, -18, 27, 10, 5, -11, 6, -1, 5, + 22, 2, -14, -39, -12, 19, 17, 4, 11, 5, -25, 2, 23, 8, 2, -3, + -39, -22, 4, 18, 6, 14, 25, 20, -17, -20, 17, 7, -43, -38, -18, 17, + 24, -6, 30, 44, 6, -36, -20, 7, 24, 1, -69, -25, 47, 15, -4, 35, + 19, -18, -22, -12, 20, 39, -36, -49, 9, 28, -16, 9, 34, 36, -22, -69, + -16, 39, 7, -28, -3, 33, -18, -7, 18, 53, 24, -37, -61, -10, 38, 2, + -24, -11, 12, 17, 0, 28, 50, -5, -59, -57, 22, 14, -15, -5, 22, 9, + -20, 19, 33, 31, -33, -62, -13, -2, 45, -9, -4, -3, 19, 8, -8, 40, + 8, -16, -44, -19, 16, 3, 23, -32, 22, 5, -9, 5, 26, 21, -27, -18, + -45, 3, 15, 0, 7, 7, 7, 13, 18, -10, 3, -5, -30, -30, -3, 9, + 31, 17, -10, 19, 28, -33, -20, 31, 14, -67, -27, 13, 20, 29, 1, -2, + 24, -3, -26, -12, 32, -7, -31, -17, 5, 22, 11, -6, 6, 7, 2, 7, + 5, -12, -22, -17, -24, 22, 47, 1, 2, 10, 5, -29, -5, 13, 1, -30, + -28, -5, 23, 25, 6, 5, 1, 7, 0, 5, 3, -33, -37, -6, 19, 20, + 26, -1, -15, 21, 9, -14, -13, 0, -11, -24, -9, 9, 23, 1, 1, 32, + 11, -25, -18, 5, -5, -6, -9, -10, 2, 18, 4, 12, 6, -2, -8, 2, + 2, -7, 2, -22, -5, 17, 25, 15, -5, -1, -24, -8, -10, -5, 12, 7, + -4, -10, 4, 8, 22, 11, -1, -12, -31, -17, 6, 12, 11, 5, -3, -1, + 22, 0, -4, 3, -18, -17, -3, 16, 9, 2, -5, 0, 4, -9, 18, 17, + -22, -19, -8, -6, 21, 11, -6, -16, 33, 13, -15, -3, -15, 1, -3, -10, + -7, 8, 17, -11, 9, 19, 0, 5, 0, -18, -13, 2, -20, 10, 29, -11, + -13, 5, 11, 16, 4, -25, -21, 13, -5, 1, 3, -1, 6, 13, -7, -1, + 17, -6, -6, -9, -6, -3, -1, 1, 18, 11, -22, 2, 18, -2, -15, 1, + 5, -12, -10, -7, 9, 26, 10, -11, 5, 0, -7, -3, -11, -9, -3, 2, + -10, 19, 28, -3, -3, -4, 9, -14, -5, -7, 8, -3, -27, 5, 37, 11, + -2, 3, -27, -15, 12, -2, 14, 2, -8, -16, 22, 11, -1, 10, -17, -8, + -5, -23, 2, 29, 8, -21, 8, 12, 6, 8, -17, 3, -2, -12, -27, 16, + 25, -5, -7, 2, 19, 1, -15, 7, 2, -5, -34, 2, 18, 17, -10, 2, + 18, -1, -12, -10, 5, 1, -16, -9, 12, 21, 4, -10, 2, 12, 1, -19, + -11, 20, 5, -14, -21, 5, 17, -5, 3, 17, 4, -25, -5, 5, 4, 0, + -5, 2, 2, -1, 1, 13, 0, -11, -8, 3, 2, -1, -3, -3, 11, 8, + -6, 2, 7, 4, -5, -23, -2, 14, -1, -15, -2, 15, 10, 1, -4, 16, + 1, -24, -12, 8, 8, -20, -2, 14, 13, 10, 2, 2, -9, -6, -9, -3, + 5, 7, -3, -9, 0, 2, 8, 3, -1, 2, -4, 0, -1, -1, -1, -2, + -8, -14, -19, -28, -51, -53, -49, -48, -49, -44, -37, -30, -23, -14, -8, -11, + -5, 3, 11, 2, 0, 8, 19, 10, 1, 6, 18, 15, 4, 4, 17, 19, + 13, 9, 20, 27, 26, 26, 33, 42, 45, 53, 59, 68, 69, 83, 89, 92, + 85, 88, 91, 80, 56, 37, 29, 9, -25, -54, -65, -74, -94, -113, -112, -103, + -101, -103, -93, -79, -66, -62, -50, -41, -33, -27, -17, -11, -12, -8, 0, 7, + -1, -2, 5, 15, 8, -1, 3, 15, 13, 2, 2, 12, 17, 12, 8, 15, + 23, 24, 25, 29, 38, 42, 50, 56, 65, 68, 78, 87, 91, 87, 87, 91, + 84, 64, 43, 33, 16, -14, -44, -60, -70, -87, -107, -111, -105, -101, -103, -96, + -84, -70, -64, -55, -45, -36, -30, -22, -14, -14, -11, -4, 4, 0, -3, 1, + 11, 8, -1, 0, 10, 12, 3, 0, 9, 15, 11, 7, 14, 22, 23, 24, + 28, 37, 42, 49, 55, 64, 67, 78, 87, 91, 88, 88, 93, 86, 67, 47, + 36, 20, -10, -40, -56, -67, -84, -104, -109, -105, -101, -103, -96, -85, -71, -65, + -56, -46, -38, -31, -23, -16, -15, -12, -6, 2, -1, -5, 0, 9, 6, -1, + -1, 8, 11, 3, 0, 8, 14, 11, 7, 13, 21, 23, 23, 27, 37, 41, + 48, 54, 63, 67, 77, 86, 91, 89, 89, 93, 87, 70, 51, 39, 23, -6, + -36, -53, -64, -81, -101, -107, -103, -100, -102, -96, -85, -72, -66, -57, -47, -39, + -32, -25, -17, -16, -13, -7, 0, -3, -5, -1, 7, 6, -2, -2, 7, 9, + 2, -1, 7, 13, 10, 7, 12, 20, 22, 23, 27, 36, 41, 48, 54, 63, + 68, 77, 87, 91, 91, 91, 95, 89, 73, 54, 43, 27, -1, -31, -49, -61, + -78, -98, -105, -102, -99, -101, -96, -85, -73, -66, -58, -48, -40, -33, -26, -19, + -17, -14, -9, -2, -4, -6, -3, 5, 4, -3, -3, 5, 8, 1, -1, 6, + 12, 10, 7, 11, 20, 22, 23, 27, 35, 41, 47, 54, 62, 68, 76, 86, + 91, 91, 92, 96, 91, 76, 58, 46, 30, 3, -27, -45, -57, -75, -94, -103, + -100, -98, -100, -96, -85, -74, -67, -59, -49, -41, -34, -28, -20, -19, -15, -10, + -3, -5, -7, -4, 3, 3, -4, -4, 4, 7, 1, -2, 5, 11, 9, 6, + 11, 19, 21, 22, 26, 35, 40, 46, 53, 61, 67, 76, 86, 91, 92, 93, + 97, 93, 78, 61, 49, 33, 7, -22, -41, -54, -72, -91, -100, -99, -97, -100, + -96, -86, -74, -67, -60, -51, -42, -35, -29, -22, -20, -17, -11, -5, -6, -8, + -5, 2, 1, -5, -5, 2, 5, 0, -3, 3, 10, 8, 5, 10, 18, 21, + 21, 25, 34, 39, 45, 52, 61, 67, 75, 85, 91, 92, 94, 97, 94, 81, + 64, 52, 37, 11, -18, -37, -51, -69, -88, -98, -98, -96, -99, -95, -86, -75, + -68, -61, -52, -44, -36, -30, -23, -21, -17, -13, -6, -7, -9, -6, 0, 0, + -5, -5, 1, 4, -1, -3, 2, 8, 8, 5, 10, 17, 20, 21, 25, 33, + 39, 45, 51, 60, 66, 75, 85, 91, 93, 94, 98, 95, 83, 67, 55, 40, + 15, -14, -33, -48, -66, -85, -96, -96, -95, -98, -95, -86, -75, -69, -62, -53, + -45, -38, -32, -25, -22, -19, -14, -8, -9, -10, -8, -2, -1, -6, -7, -1, + 2, -2, -4, 1, 7, 6, 5, 8, 16, 19, 20, 24, 32, 38, 44, 50, + 59, 66, 74, 84, 91, 93, 95, 99, 97, 85, 70, 58, 43, 18, -10, -30, + -45, -63, -82, -93, -95, -94, -97, -95, -87, -76, -70, -63, -54, -46, -39, -33, + -26, -23, -20, -16, -10, -10, -12, -9, -3, -3, -7, -8, -2, 1, -2, -5, + 0, 6, 6, 4, 8, 15, 18, 20, 23, 31, 37, 43, 50, 58, 65, 74, + 83, 91, 93, 96, 100, 98, 87, 72, 61, 46, 22, -6, -27, -42, -60, -79, + -91, -94, -93, -97, -95, -87, -77, -70, -64, -55, -47, -40, -34, -28, -25, -22, + -17, -12, -11, -13, -11, -5, -4, -8, -9, -3, 0, -4, -6, -1, 5, 5, + 3, 7, 14, 18, 19, 23, 30, 36, 42, 49, 57, 65, 73, 83, 90, 94, + 96, 100, 99, 89, 75, 63, 49, 25, -2, -23, -38, -56, -76, -88, -92, -92, + -95, -94, -87, -77, -71, -65, -57, -48, -41, -36, -29, -26, -23, -19, -13, -12, + -14, -12, -7, -6, -9, -10, -5, -1, -4, -7, -2, 2, 5, 4, 6, 12, + 18, 20, 24, 30, 38, 45, 52, 61, 70, 79, 89, 99, 106, 109, 113, 115, + 109, 96, 81, 66, 44, 16, -12, -32, -52, -74, -92, -101, -104, -107, -108, -103, + -94, -85, -78, -70, -60, -52, -45, -38, -33, -29, -25, -19, -16, -17, -16, -12, + -9, -10, -12, -9, -5, -5, -7, -5, 0, 3, 3, 5, 11, 17, 20, 23, + 29, 37, 44, 51, 59, 69, 78, 88, 98, 105, 110, 114, 116, 110, 98, 84, + 69, 48, 20, -7, -29, -49, -71, -89, -99, -102, -105, -107, -103, -94, -86, -79, + -71, -62, -54, -47, -40, -34, -30, -26, -21, -18, -18, -17, -14, -10, -12, -14, + -11, -5, -10, 43, -94, 44, -13, 27, -98, 1, 9, 77, 63, 4, 8, -128, + 63, -73, 78, -116, 127, -14, 111, -87, -67, -43, -45, 38, 53, 99, -37, 14, + -51, -58, -23, -32, 34, 27, 75, 9, 51, -104, -71, -33, 27, 67, 0, -1, + 25, 0, -35, 1, -70, 28, -4, 109, 3, 5, -42, -7, 42, -15, 37, -62, + 67, -14, 48, -85, -46, -94, 37, 35, 23, 15, -79, 35, -50, 91, -64, 40, + -69, 46, 20, 43, -21, -51, 8, -1, 95, -47, 69, -104, 98, -44, 74, -61, + -14, -19, 7, 52, -40, 8, -89, 58, -53, 106, -106, 42, -82, 61, -1, -8, + -10, -59, 53, -18, 85, -83, 63, -73, 89, -32, 50, -62, 10, 13, 20, 62, + -81, 41, -84, 88, -32, 41, -78, 27, -30, 51, -6, -42, 6, -49, 74, -41, + 41, -89, 27, -33, 57, 0, -16, -8, -4, 45, 8, 20, -63, 36, -29, 75, + -23, -17, -23, -14, 45, -7, 17, -56, 20, -12, 45, -16, -13, -31, 6, 31, + -7, 17, -81, 40, -35, 73, -34, 0, -31, 10, 35, -4, 19, -60, 44, -30, + 83, -66, 41, -87, 59, -6, 23, -4, -59, 34, -33, 77, -70, 49, -89, 88, + -45, 63, -62, 4, -20, 18, 46, -49, 45, -101, 91, -56, 78, -79, 35, -51, + 67, -12, -2, -14, -49, 66, -35, 72, -87, 51, -74, 83, -38, 29, -36, -10, + 23, 3, 30, -59, 27, -59, 91, -44, 41, -63, 12, 2, 23, 8, -36, 14, + -35, 66, -38, 32, -59, 25, -11, 40, -6, -25, -2, -24, 55, -25, 29, -58, + 30, -17, 41, -18, -17, -3, -13, 50, -25, 26, -63, 35, -23, 50, -22, -5, + -18, 0, 33, -19, 22, -67, 57, -39, 63, -45, 6, -27, 13, 23, -6, 15, + -55, 44, -42, 70, -59, 36, -60, 56, -13, 15, -9, -50, 49, -38, 72, -63, + 37, -65, 67, -48, 55, -51, 10, 2, -5, 45, -61, 46, -83, 91, -58, 72, + -69, 23, -27, 35, -8, -3, -2, -33, 66, -61, 79, -100, 67, -60, 66, -26, + 13, -21, -13, 23, -11, 29, -49, 40, -53, 80, -67, 52, -63, 28, 6, -1, + 23, -45, 25, -30, 42, -25, 22, -42, 33, -26, 39, -26, -9, 10, -28, 61, + -50, 33, -43, 18, 2, 6, 4, -18, 4, -8, 24, -21, 22, -49, 50, -40, + 52, -35, -10, 17, -34, 64, -53, 38, -47, 37, -28, 40, -47, 33, -32, 28, + 3, -20, 30, -69, 79, -75, 88, -72, 39, -34, 22, -7, 9, -18, 1, 19, + -27, 58, -89, 81, -90, 89, -58, 42, -27, -5, 16, -21, 29, -34, 28, -37, + 59, -65, 72, -90, 69, -45, 31, 6, -36, 40, -53, 56, -47, 39, -42, 40, + -38, 50, -52, 34, -31, 7, 32, -47, 62, -79, 66, -51, 41, -27, 12, -10, + 12, -5, 3, -5, -18, 33, -44, 70, -75, 60, -52, 27, 4, -19, 22, -29, + 27, -15, 18, -31, 26, -36, 50, -41, 35, -31, 3, 19, -37, 55, -62, 51, + -38, 25, -11, 1, -13, 12, -7, 13, 4, -33, 38, -56, 72, -64, 52, -43, + 20, 6, -20, 25, -40, 34, -25, 38, -41, 43, -68, 68, -59, 53, -28, -7, + 27, -45, 63, -70, 56, -60, 59, -41, 48, -56, 39, -43, 35, -3, -19, 40, + -70, 85, -81, 76, -75, 48, -36, 41, -20, 12, -23, 0, 16, -23, 51, -76, + 78, -82, 80, -57, 29, -23, 3, 14, -2, 9, -29, 17, -31, 55, -51, 53, + -66, 49, -27, 17, 3, -35, 36, -33, 44, -27, 11, -30, 24, -18, 37, -29, + 4, -3, -15, 45, -47, 42, -57, 46, -19, 18, -11, -20, 10, -3, 24, -18, + 14, -46, 52, -50, 64, -57, 25, -14, 1, 33, -42, 30, -52, 50, -28, 47, + -54, 32, -49, 53, -25, 14, -4, -34, 57, -54, 69, -78, 46, -45, 52, -21, + 21, -37, 7, 1, 3, 29, -57, 56, -74, 90, -66, 47, -51, 16, 6, 10, + 10, -29, 9, -32, 58, -47, 59, -84, 65, -49, 52, -24, -18, 14, -30, 61, + -39, 31, -57, 39, -38, 67, -56, 37, -46, 26, 10, -15, 18, -49, 45, -27, + 42, -37, 11, -24, 30, -15, 21, -34, 15, -5, 11, 5, -24, 11, -16, 30, + -16, 6, -20, 7, 3, 11, -9, -5, -6, 4, 16, -15, 9, -29, 22, -6, + 14, -6, -16, 9, -12, 28, -22, 15, -27, 22, -11, 21, -23, 5, -10, 8, + 17, -22, 19, -42, 41, -31, 39, -37, 20, -20, 19, -3, -7, 2, -17, 27, + -20, 30, -43, 30, -34, 38, -24, 13, -13, -1, 16, -16, 19, -36, 28, -21, + 30, -22, 7, -17, 11, 2, 1, 1, -19, 22, -21, 32, -34, 18, -21, 17, + 6, -8, 5, -25, 21, -13, 24, -24, 12, -22, 24, -11, 10, -14, -7, 15, + -11, 28, -36, 21, -30, 30, -10, 10, -13, -5, 6, -2, 14, -22, 15, -25, + 33, -22, 23, -31, 11, -6, 8, 11, -21, 14, -28, 32, -23, 25, -31, 19, + -15, 19, -7, -7, 1, -13, 26, -19, 24, -37, 25, -24, 30, -18, 6, -9, + -2, 17, -16, 17, -34, 27, -19, 28, -21, 6, -15, 10, 4, 0, 2, -20, + 22, -19, -21, 0, -3, -3, 2, 1, -1, 2, -2, -1, 4, 3, -3, -15, + -21, -20, -23, -42, -45, -31, -27, -17, -8, 9, 29, 41, 44, 33, 20, 13, + 6, 12, 16, 25, 43, 44, 33, 33, 35, 15, -5, -3, 8, 16, 8, -10, + -6, 8, 4, -4, 1, -18, -38, -43, -51, -54, -55, -71, -85, -68, -58, -61, + -50, -33, -27, -15, -5, 22, 67, 100, 109, 114, 110, 91, 69, 50, 37, 35, + 46, 48, 37, 36, 14, -24, -38, -42, -38, -38, -59, -91, -86, -57, -44, -32, + -15, -26, -44, -30, -30, -30, -16, -31, -50, -34, -43, -59, -49, -44, -52, -62, + -69, -50, -4, 47, 83, 105, 120, 111, 88, 72, 55, 57, 76, 69, 59, 55, + 41, 10, -18, -32, -28, -19, -36, -68, -76, -72, -71, -46, -35, -47, -43, -43, + -61, -48, -28, -25, -22, -19, -23, -15, -7, 3, 4, -8, -28, -37, -5, 42, + 72, 107, 127, 122, 117, 90, 48, 37, 48, 51, 54, 56, 43, 24, -8, -37, + -33, -11, -28, -55, -61, -75, -75, -51, -58, -55, -33, -33, -41, -35, -30, -21, + -16, -17, -24, -26, -20, -18, -17, -12, -36, -72, -65, -45, -6, 53, 88, 106, + 119, 107, 71, 52, 50, 59, 75, 87, 85, 76, 43, -1, -7, 9, -1, -13, + -34, -69, -80, -74, -80, -73, -65, -67, -65, -56, -44, -33, -23, -18, -24, -25, + -16, -20, -9, -1, -21, -38, -55, -64, -40, 3, 39, 82, 113, 114, 95, 71, + 54, 56, 68, 76, 87, 94, 57, 10, -9, -17, -17, -15, -35, -60, -75, -89, + -92, -85, -76, -71, -74, -70, -53, -41, -20, -9, -9, 4, 4, 10, 33, 38, + 25, 15, -17, -43, -33, -15, 3, 40, 77, 94, 91, 69, 37, 31, 33, 37, + 68, 96, 82, 53, 25, 8, 22, 28, 9, -9, -27, -46, -56, -65, -62, -61, + -60, -51, -51, -39, -25, -23, -11, -3, -15, -10, 5, 12, 20, 18, -11, -41, + -52, -47, -34, -2, 33, 65, 82, 70, 51, 45, 28, 21, 49, 74, 86, 74, + 33, 5, 10, 14, 7, -10, -28, -45, -67, -68, -73, -76, -66, -66, -65, -46, + -39, -31, -9, -3, -6, 1, 8, 22, 41, 49, 33, 8, -16, -34, -30, -17, + 7, 49, 73, 64, 63, 50, 19, 5, 13, 32, 62, 65, 37, 8, -5, 4, + -1, -8, -15, -36, -50, -57, -71, -65, -53, -58, -49, -37, -40, -28, -10, -3, + 0, 2, -2, 5, 30, 41, 36, 22, -7, -33, -39, -46, -30, 15, 44, 56, + 72, 65, 44, 21, 2, 15, 42, 59, 49, 18, 2, -3, -4, 0, -10, -25, + -34, -52, -65, -59, -56, -50, -37, -33, -33, -25, -12, -2, 10, 12, 3, 6, + 27, 42, 52, 43, 16, -3, -24, -48, -41, -11, 16, 48, 67, 78, 75, 49, + 21, 13, 36, 64, 63, 47, 25, -1, -2, 2, -12, -18, -28, -53, -65, -71, + -76, -70, -55, -53, -49, -41, -35, -24, -1, 5, 1, 4, 8, 28, 51, 43, + 26, 18, -14, -42, -51, -49, -23, 5, 31, 55, 67, 58, 26, -2, 11, 35, + 49, 55, 35, 8, 3, -2, -5, -6, -13, -30, -38, -49, -61, -56, -45, -43, + -36, -31, -37, -25, -7, 1, 6, 1, -10, 11, 33, 29, 27, 17, -6, -34, + -58, -67, -57, -34, -4, 21, 50, 63, 37, 11, 8, 17, 45, 63, 55, 39, + 26, 12, 11, 10, -1, -11, -19, -35, -51, -52, -52, -45, -35, -36, -41, -31, + -24, -9, 9, -3, -12, 2, 19, 33, 40, 37, 25, -3, -30, -51, -59, -42, + -24, -3, 38, 58, 51, 32, 8, 2, 25, 45, 50, 49, 35, 18, 16, 19, + 10, 9, 4, -13, -27, -36, -45, -36, -24, -32, -29, -31, -33, -10, 6, 1, + -4, -6, 4, 19, 30, 37, 30, 12, -13, -48, -59, -57, -56, -35, 2, 31, + 48, 41, 12, -2, 7, 25, 41, 52, 44, 29, 25, 22, 18, 20, 15, 1, + -6, -26, -38, -28, -26, -21, -17, -31, -33, -19, -4, 0, -8, -16, -15, -11, + 9, 19, 22, 24, -2, -34, -49, -61, -70, -57, -32, 4, 38, 46, 26, 5, + -1, 7, 29, 45, 44, 38, 32, 23, 27, 30, 23, 24, 14, -8, -16, -24, + -24, -12, -10, -19, -27, -26, -9, -2, -4, -6, -16, -14, -2, 8, 23, 34, + 17, -6, -26, -47, -61, -62, -50, -18, 26, 50, 48, 31, 12, 6, 24, 40, + 44, 51, 40, 29, 34, 28, 27, 32, 20, 7, -5, -23, -26, -19, -9, -12, + -25, -25, -17, -8, 1, -4, -13, -12, -16, -9, 13, 26, 23, 8, -13, -37, + -55, -71, -78, -59, -18, 16, 35, 34, 8, -3, 4, 13, 31, 40, 34, 34, + 29, 23, 30, 31, 27, 21, 7, -6, -21, -21, -10, -10, -19, -24, -28, -17, + -6, -8, -9, -9, -19, -21, -5, 12, 23, 22, 5, -16, -34, -55, -80, -78, + -56, -22, 18, 33, 24, 14, 3, 7, 25, 31, 37, 41, 33, 29, 29, 32, + 33, 30, 24, 7, -16, -22, -18, -15, -14, -24, -31, -22, -13, -12, -8, -6, + -18, -27, -22, -6, -5, -1, -1, -1, 1, 2, 7, 13, 19, 10, -12, -31, + -13, 17, 29, -4, -29, 24, 53, 18, 92, 15, -15, 23, 13, -35, -52, 127, + 9, 3, -9, 31, -63, -64, -5, -50, 14, 33, -29, -42, 0, 43, 39, -15, + -59, -45, 3, 33, 12, -35, -10, 51, 18, 49, 55, -28, 16, 4, 3, -64, + 54, 53, -12, 0, 5, -4, -72, -7, -31, -14, 26, -2, -37, -14, 17, 35, + 4, -33, -45, -12, 15, 21, -16, -23, 22, 28, 12, 55, -7, -2, 7, 7, + -34, -10, 65, -4, 1, -5, 14, -46, -28, -9, -29, 13, 13, -23, -23, 4, + 27, 18, -17, -39, -25, 5, 20, 0, -26, 1, 34, 7, 41, 24, -20, 11, + 1, -6, -45, 53, 22, -6, -4, 9, -17, -52, -4, -30, -6, 20, -9, -29, + -8, 18, 27, -2, -33, -36, -6, 16, 13, -20, -16, 27, 19, 18, 49, -17, + 3, 2, 6, -42, 9, 55, -9, 1, -3, 9, -54, -19, -16, -24, 16, 7, + -27, -19, 8, 28, 12, -22, -40, -20, 8, 19, -7, -25, 9, 31, 7, 48, + 9, -14, 9, 2, -17, -35, 62, 9, -2, -6, 13, -30, -44, -4, -31, 2, + 18, -15, -27, -3, 22, 24, -8, -36, -32, -2, 17, 8, -23, -9, 31, 13, + 28, 40, -21, 8, 1, 3, -47, 29, 43, -9, 0, 1, 1, -57, -11, -22, + -17, 19, 2, -28, -14, 12, 29, 7, -27, -39, -14, 11, 17, -13, -22, 17, + 27, 10, 51, -4, -7, 7, 5, -27, -19, 64, -1, 1, -6, 14, -41, -34, + -8, -30, 8, 15, -20, -24, 2, 25, 20, -14, -38, -27, 2, 18, 2, -25, + -1, 33, 9, 37, 29, -21, 11, 0, -3, -46, 46, 29, -7, -2, 7, -9, + -54, -6, -27, -10, 20, -4, -28, -9, 16, 28, 1, -30, -37, -8, 14, 14, + -18, -17, 25, 22, 16, 50, -13, 1, 4, 5, -37, 0, 59, -7, 2, -4, + 12, -49, -24, -13, -26, 13, 11, -23, -19, 6, 27, 15, -19, -39, -21, 6, + 18, -4, -24, 7, 32, 8, 45, 15, -16, 10, 2, -12, -39, 58, 16, -3, + -5, 11, -22, -48, -4, -30, -2, 19, -10, -26, -4, 20, 25, -5, -34, -33, + -4, 16, 10, -21, -11, 30, 16, 25, 43, -19, 7, 1, 4, -44, 20, 49, + -8, 1, -1, 6, -54, -15, -19, -20, 17, 6, -26, -15, 10, 29, 9, -23, + -39, -16, 9, 17, -10, -22, 15, 29, 10, 50, 2, -10, 8, 3, -22, -26, + 63, 5, 0, -6, 14, -34, -39, -6, -30, 4, 17, -15, -24, 0, 24, 22, + -11, -36, -28, 1, 17, 5, -23, -3, 32, 12, 34, 33, -21, 10, 0, 0, + -46, 39, 36, -7, -1, 4, -3, -54, -9, -24, -14, 19, 0, -26, -10, 14, + 28, 4, -27, -37, -11, 12, 15, -15, -18, 22, 24, 14, 50, -9, -2, 5, + 5, -32, -8, 61, -3, 2, -5, 14, -44, -29, -10, -27, 10, 13, -20, -20, + 4, 26, 17, -16, -37, -23, 4, 18, -1, -23, 5, 32, 9, 42, 20, -18, + 11, 1, -7, -41, 53, 22, -4, -3, 9, -14, -50, -6, -27, -7, 19, -6, + -26, -5, 18, 26, -2, -31, -34, -6, 14, 11, -19, -12, 28, 19, 22, 45, + -17, 4, 2, 5, -40, 11, 54, -6, 2, -3, 10, -51, -20, -16, -23, 14, + 9, -23, -15, 8, 28, 12, -20, -38, -18, 7, 17, -7, -22, 13, 30, 10, + 47, 7, -12, 9, 2, -17, -31, 61, 10, 0, -5, 13, -26, -43, -6, -29, + 0, 18, -11, -23, -1, 22, 23, -8, -34, -30, -1, 15, 7, -22, -5, 31, + 14, 30, 37, -20, 9, 0, 2, -44, 30, 42, -7, 1, 2, 2, -53, -12, + -21, -17, 17, 4, -25, -11, 12, 28, 6, -25, -37, -13, 10, 15, -13, -18, + 20, 26, 13, 49, -5, -5, 6, 4, -27, -16, 62, 1, 2, -5, 14, -38, + -34, -9, -28, 6, 15, -16, -20, 3, 25, 19, -13, -36, -25, 2, 16, 1, + -23, 3, 32, 11, 38, 25, -19, 11, 0, -4, -43, 46, 29, -4, -2, 7, + -8, -51, -8, -25, -10, 18, -2, -25, -7, 16, 27, 0, -28, -35, -8, 12, + 12, -17, -13, 26, 21, 19, 46, -14, 2, 3, 4, -36, 2, 57, -4, 3, + -4, 12, -46, -25, -13, -25, 11, 12, -20, -16, 7, 27, 14, -18, -37, -20, + 5, 16, -5, -21, 10, 31, 10, 45, 12, -14, 10, 1, -12, -36, 57, 16, + -1, -4, 11, -20, -46, -6, -28, -4, 18, -8, -23, -3, 20, 24, -5, -32, + -31, -4, 13, 8, -20, -6, 29, 17, 27, 39, -19, 7, 0, 3, -42, 21, + 47, -6, 2, 0, 7, -51, -17, -18, -20, 15, 7, -23, -12, 10, 28, 8, + -22, -37, -15, 8, 15, -10, -19, 18, 27, 13, 47, 0, -8, 8, 3, -24, + -20, 52, -36, -2, 0, -2, 3, 5, -4, -28, 22, -43, 36, -13, -127, -43, + 2, -18, 126, 78, -127, -48, 68, -74, -67, 33, 62, 83, 42, -32, -46, -70, + -26, 115, 21, -66, 72, 52, -27, 44, 50, 50, 61, 28, -12, 3, -59, 49, + 3, -19, 39, 94, 16, 31, 6, 29, 3, -100, -1, -4, -60, 19, 7, -29, + -28, -38, -3, -47, -20, -21, -1, 5, -55, -12, -55, -39, 26, 47, -22, -9, + -41, -21, -19, -37, 0, 45, -56, 24, 75, -50, -9, 31, 28, 26, 13, -3, + -15, -27, 1, 1, -31, -10, 38, -1, 7, 43, 19, 21, 41, 33, 9, -17, + -3, -42, -76, -30, -8, -9, -1, 21, 22, 38, 32, 22, 0, -18, -32, -58, + -12, 5, -48, -13, 64, 29, -2, 2, 19, 43, 25, -19, -39, -69, -92, -15, + 23, 30, 30, 51, 37, 35, 37, 30, -27, -63, 5, -30, -56, -16, 26, 52, + 20, 14, 59, 27, -9, 22, -4, -20, -37, -17, -34, -34, -1, 35, 26, 31, + 5, -16, 4, 33, 22, 8, 5, -28, -41, -20, -10, -6, -2, -16, 12, 31, + -23, 7, -2, -39, -28, -13, 8, 5, 16, -4, -6, -18, -24, -27, -50, -6, + 5, 12, 0, -2, -14, -23, 5, -28, -10, 2, 28, 15, 2, 22, 27, 41, + 31, 2, 12, 31, 5, 12, -6, 15, 40, 34, 18, 26, 26, 12, 34, 23, + 34, 30, 22, 10, -26, -22, 1, 0, -1, 12, -4, -21, -5, -5, -20, -31, + -25, -24, -42, -44, -41, -41, -37, -29, -28, -29, -40, -17, -21, -38, -42, -38, + -40, -36, -13, -14, -8, -15, -7, -6, 5, 12, -1, -17, -1, 9, 2, 16, + 30, 27, 37, 36, 38, 36, 36, 19, 45, 45, 33, 26, 33, 28, 36, 31, + 17, 12, 22, 11, 11, 17, 5, -13, 6, 10, 2, -6, 2, 9, 15, -6, + -8, -23, -44, -3, -11, -35, -25, -35, -23, -21, 0, -11, -21, -17, 11, -6, + -11, -17, -33, -16, -16, -4, -7, -7, -9, -4, 1, 1, -3, 6, 7, 4, + -17, -11, -6, -4, 1, 3, 6, 4, 5, -4, 17, 7, 3, 9, -20, 0, + -7, -3, -5, 4, 9, 16, 2, 3, 8, 15, 15, 1, -3, 8, -1, 5, + 14, 7, 4, 8, -8, 2, -3, 5, 11, 5, 3, -4, 10, 17, 13, -11, + -5, 1, -3, 0, -6, -12, 2, -3, 13, -5, -25, -15, -7, 4, 1, -8, + -4, -12, -16, 3, 9, -6, 3, -21, -4, 4, -14, 1, -1, -2, 3, -8, + -5, 0, 7, -2, -3, -1, 3, -9, 5, -4, -17, -1, 9, 3, 7, 1, + -4, -3, 5, 2, -7, -9, 12, -6, -14, -16, 2, -1, 16, 2, 2, 7, + -6, -26, 3, -2, -4, -2, 10, 3, -7, 3, 8, 9, 5, 4, 1, -5, + -5, 11, 8, 7, 11, 12, -1, -5, -16, 13, 7, 2, 11, 4, -4, 9, + -8, -8, 14, 11, -8, 0, -1, -5, -2, -1, -10, -5, -9, -9, -16, -12, + -8, -16, 5, -10, -4, -11, -3, 1, 0, -3, -5, -13, -9, -2, -8, 5, + -9, -7, -2, 2, -11, -7, 13, 8, -3, 2, 7, -2, -1, 5, 0, 11, + 6, 13, 15, 1, -4, 9, 5, 3, 8, -3, -4, 16, 4, 11, 9, 0, + 8, 1, -6, -5, -18, 3, 7, -18, -4, 0, -3, -3, -6, -4, -5, -5, + -10, -2, -9, -5, -2, -4, -11, -2, 1, -5, -2, 11, -6, -9, 1, 4, + -6, -1, -5, 1, 2, 9, 5, 0, 4, 4, -2, 7, 0, -10, 5, 2, + -3, 0, -6, 7, -4, -3, 6, -1, -6, -1, -1, 2, -2, -6, -3, 0, + 8, -6, 4, -1, -5, -3, 3, 1, -5, -6, -2, -3, 5, 6, 0, 7, + -3, 3, -1, 0, -2, 9, 1, 1, -3, 4, 5, -5, 2, -2, 2, -11, + -2, -4, 11, 4, 5, 0, -5, -12, -6, -5, -5, 3, -2, -2, 2, 2, + 1, 0, -1, -8, -5, -5, -3, 2, -1, 3, -1, 3, 0, -1, 0, -1, + 1, 1, -4, -4, 2, -2, 1, -6, 1, 2, 4, 2, 2, -5, -1, 6, + -3, -1, -4, 11, 3, -9, -2, -6, -3, 2, 4, 2, 1, 2, 4, 3, + -6, -4, -3, -2, 0, 2, -2, 5, 2, -1, 3, -9, -3, -3, -4, -4, + -1, 0, -2, 7, 3, 1, 1, -2, -4, -2, -3, -2, -4, 2, 4, -1, + 2, 3, 0, 3, -1, 0, -2, -2, -3, 1, -1, -4, 5, -1, 5, 0, + -3, -2, -1, -4, 3, -1, -3, -2, -2, -1, 0, 0, 1, -1, 0, -2, + -2, 0, -3, -1, 0, 0, 1, 1, -2, -1, 1, -3, 1, 2, 0, -1, + 0, -1, 1, 5, -2, 1, -3, -3, -1, -3, 0, 1, 3, 2, -1, -1, + -2, -2, -1, 1, 0, -1, -2, -2, -2, -3, -3, -3, -2, -2, -2, -2, + -2, -2, -2, -1, 0, 1, 1, -2, -2, 0, 0, 2, -3, -16, -22, -20, + -28, -35, -31, -17, 19, 33, 36, 33, 34, 40, 36, 25, 18, 20, 18, 14, + 17, 12, 14, 10, -24, -36, -27, -38, -55, -69, -66, -47, -33, -13, 3, 5, + 10, 22, 25, 15, 28, 43, 41, 51, 56, 58, 58, 31, -18, -52, -64, -71, + -92, -105, -98, -77, -50, -17, 23, 59, 85, 99, 94, 76, 55, 14, -9, -5, + -7, -18, -17, -35, -53, -53, -33, -23, -33, -36, -15, 17, 32, 24, 12, 19, + 37, 54, 49, 38, 21, -14, -44, -30, -22, -15, 5, 8, -1, -26, -42, -46, + -49, -51, -37, -17, 1, -4, -19, -4, 45, 84, 91, 79, 57, 3, -30, -29, + -35, -25, -8, -6, -26, -61, -75, -73, -77, -72, -54, -19, 9, 6, -10, 3, + 47, 85, 92, 103, 92, 45, 21, 6, 4, 16, 27, 27, -1, -48, -69, -78, + -80, -84, -72, -33, -10, -24, -41, -20, 40, 82, 99, 123, 102, 69, 49, 30, + 27, 34, 42, 41, -2, -58, -96, -108, -103, -106, -83, -37, -10, -18, -38, -18, + 40, 65, 92, 110, 84, 44, 1, -26, -23, -7, 21, 32, 7, -39, -78, -84, + -79, -82, -61, -19, 5, -14, -52, -25, 25, 59, 102, 127, 116, 86, 40, 13, + 4, 9, 27, 29, 4, -47, -88, -94, -87, -83, -56, -18, 15, -13, -49, -30, + -2, 29, 69, 87, 80, 50, 9, -15, -27, -10, 18, 44, 36, -9, -45, -53, + -53, -46, -33, 6, 31, -8, -36, -28, -11, 21, 54, 76, 76, 44, 4, -33, + -53, -45, -18, 13, 10, -35, -62, -70, -61, -44, -19, 38, 63, 30, 9, 4, + 9, 35, 60, 81, 75, 51, 14, -25, -44, -37, -9, 29, 24, -11, -41, -59, + -51, -54, -33, 23, 35, 6, -13, -28, -18, 8, 43, 73, 76, 63, 33, -1, + -21, -22, 10, 43, 35, 5, -32, -47, -51, -68, -44, 6, 14, 0, -21, -34, + -25, 0, 37, 65, 73, 64, 35, 5, -22, -25, 11, 40, 39, 13, -20, -28, + -42, -64, -32, 6, 15, -1, -25, -39, -39, -16, 19, 44, 58, 53, 27, -2, + -39, -38, -2, 30, 40, 13, -16, -19, -45, -60, -29, 6, 17, 1, -21, -40, + -44, -24, 9, 38, 58, 51, 38, 8, -31, -29, 0, 34, 44, 9, -11, -23, + -58, -69, -42, -6, 9, 0, -16, -33, -36, -12, 19, 55, 72, 68, 58, 18, + -22, -25, -6, 29, 31, 2, -5, -23, -57, -69, -45, -8, 12, 10, 0, -22, + -24, -7, 20, 52, 61, 65, 59, 21, -15, -28, -11, 26, 20, 2, -2, -22, + -56, -71, -49, -14, 3, 8, -5, -26, -28, -19, 14, 42, 54, 71, 67, 38, + 8, -11, 16, 47, 37, 26, 18, -10, -51, -74, -59, -35, -19, -12, -24, -37, + -44, -34, 0, 24, 44, 67, 64, 43, 3, -18, 11, 35, 28, 22, 18, -4, + -47, -68, -55, -34, -11, -7, -15, -27, -43, -32, -1, 18, 42, 58, 60, 43, + -8, -29, -6, 11, 7, 4, 4, -17, -59, -75, -66, -41, -13, -3, 1, -11, + -29, -19, 1, 19, 42, 53, 64, 45, -8, -28, -9, 7, 4, 4, 9, -13, + -51, -71, -69, -43, -19, -7, 3, -11, -25, -17, -2, 23, 43, 60, 78, 55, + 1, -19, -5, 8, 3, 7, 13, -8, -41, -66, -67, -40, -19, 3, 16, 1, + -7, -5, 10, 34, 46, 67, 87, 62, 11, -13, -1, 8, 4, 15, 20, 1, + -33, -64, -65, -48, -30, -2, 6, -5, -14, -18, 1, 21, 32, 62, 86, 66, + 20, -3, 6, 7, 5, 16, 20, 7, -29, -62, -65, -59, -39, -13, -5, -8, + -22, -27, -6, 7, 17, 49, 74, 58, 14, -5, -2, -4, -3, 7, 14, 6, + -32, -59, -66, -63, -40, -16, -2, -2, -19, -20, -1, 6, 18, 49, 77, 62, + 21, 3, -1, -5, -2, 5, 18, 10, -26, -50, -65, -64, -43, -24, -5, -6, + -24, -23, -8, -2, 10, 45, 75, 60, 25, 6, -4, -4, -5, 3, 20, 8, + -20, -43, -60, -58, -45, -24, 1, -1, -15, -12, -1, 3, 16, 53, 83, 70, + 42, 19, 9, 7, 3, 16, 29, 17, -7, -35, -55, -56, -49, -24, 2, -1, + -11, -7, 3, 4, 16, 55, 83, 75, 50, 25, 15, 6, 0, 13, 21, 13, + -9, -40, -58, -66, -62, -35, -11, -11, -18, -13, -3, -7, 9, 49, 75, 74, + 51, 28, 19, 5, 1, 13, 20, 16, -3, -28, -48, -62, -61, -37, -16, -13, + -20, -15, -12, -19, -5, 21, 50, 61, 47, 28, 15, -1, -6, 0, 9, 14, + 1, -19, -37, -55, -56, -38, -16, -11, -13, -9, -9, -16, -8, 18, 48, 59, + 44, 28, 9, 15, -3, 2, -5, 3, 3, 4, 1, 7, -2, 7, -4, 2, + -124, -37, 33, -48, 7, -27, 8, -14, 77, 26, -9, 26, 7, 20, 10, 13, + 8, 9, 7, 4, 5, 2, 3, 2, 1, -1, 0, -3, -2, -5, 1, -10, + 11, 70, -6, 21, 5, 27, -2, 41, -15, -61, -66, -128, 0, -48, -21, -46, + -6, -55, 23, 53, -6, 11, 2, 14, 11, 10, 11, 8, 9, 9, 8, 5, + 8, 5, 6, 5, 6, 2, 7, -4, 6, 5, -23, 62, 29, 24, 8, 33, + 4, 32, 36, -30, -16, -124, -58, -39, -18, -51, -3, -43, -40, 53, 19, 12, + 4, 9, 12, 13, 10, 11, 9, 8, 11, 6, 5, 8, 6, 3, 9, 1, + 7, 2, -5, 22, -33, 20, 37, 35, 7, 29, 14, 8, 52, -5, 17, -64, + -84, -70, -15, -55, -23, -12, -72, 1, 28, 16, 8, 6, 7, 12, 10, 8, + 11, 6, 8, 10, 5, 4, 10, 1, 8, 4, 2, 10, -15, 26, -16, -9, + 14, 42, 17, 19, 29, -3, 42, 14, 28, -8, -45, -92, -37, -41, -54, 0, + -53, -48, 2, 18, 10, 8, 4, 8, 12, 8, 10, 10, 6, 9, 10, 2, + 10, 5, 3, 9, -2, 18, -16, 17, 3, -9, -12, 26, 28, 13, 35, 3, + 27, 19, 31, 17, 4, -60, -67, -33, -66, -22, -22, -58, -38, 2, 11, 9, + 7, 4, 9, 10, 8, 10, 9, 5, 12, 5, 5, 9, 2, 11, -5, 21, + -8, 4, 10, 5, -17, -1, 28, 11, 34, 13, 20, 17, 28, 24, 27, -6, + -61, -41, -57, -51, -17, -36, -56, -32, -1, 7, 8, 5, 6, 8, 10, 8, + 12, 6, 9, 9, 5, 9, 1, 15, -7, 15, 5, -2, 4, 14, -3, -18, + 15, 8, 28, 21, 20, 16, 23, 23, 29, 30, -20, -38, -45, -63, -38, -23, + -43, -53, -29, -5, 5, 5, 5, 5, 9, 7, 11, 8, 8, 10, 5, 12, + -2, 16, -1, 4, 11, 4, -3, 8, 15, -16, 0, 1, 16, 23, 23, 17, + 20, 21, 21, 39, 19, -14, -28, -52, -58, -33, -28, -47, -50, -30, -6, 2, + 5, 4, 6, 6, 9, 10, 7, 12, 3, 15, 0, 10, 8, 1, 6, 11, + 2, -4, 20, -1, -6, -5, 4, 15, 24, 20, 18, 23, 15, 30, 38, 13, + -6, -27, -56, -52, -30, -34, -48, -50, -28, -8, 2, 3, 5, 5, 6, 11, + 5, 13, 3, 12, 6, 5, 10, 5, 2, 7, 13, -8, 10, 11, 0, -6, + -4, 3, 17, 23, 16, 24, 18, 17, 36, 32, 13, -1, -30, -57, -45, -31, + -36, -51, -49, -28, -7, -1, 3, 6, 2, 11, 5, 12, 6, 9, 10, 5, + 8, 8, 5, -1, 16, 1, -1, 11, 9, -1, -5, -5, 4, 20, 17, 20, + 24, 14, 23, 37, 29, 16, 2, -33, -53, -42, -30, -39, -52, -49, -27, -9, + -3, 5, 0, 8, 5, 10, 8, 6, 10, 6, 7, 6, 11, -3, 8, 11, + 0, 2, 11, 8, -1, -5, -7, 9, 18, 16, 24, 20, 14, 27, 35, 27, + 21, 1, -33, -50, -38, -32, -42, -53, -48, -25, -14, -1, -2, 4, 3, 6, + 9, 5, 9, 7, 7, 4, 12, 4, 1, 10, 6, 2, 6, 10, 4, 0, + -6, -2, 11, 14, 18, 22, 17, 20, 32, 34, 28, 20, 0, -26, -36, -34, + -37, -45, -54, -44, -30, -13, -8, -3, 1, 2, 6, 4, 7, 8, 8, 2, + 8, 10, 1, 4, 6, 5, 5, 9, 6, 1, -3, -5, 3, 10, 14, 18, + 18, 17, 26, 35, 35, 29, 17, -1, -17, -24, -32, -41, -50, -51, -44, -28, + -18, -12, -5, -2, 2, 3, 3, 6, 9, 4, 3, 9, 6, 2, 2, 4, + 5, 9, 10, 4, -2, -5, -1, 5, 10, 14, 16, 15, 19, 30, 38, 37, + 29, 15, 1, -5, -14, -31, -43, -50, -52, -42, -29, -22, -16, -9, -3, 0, + 0, 2, 6, 6, 2, 4, 7, 6, 2, 1, 2, 6, 11, 10, 2, -5, + -4, 0, 5, 10, 14, 15, 14, 21, 32, 39, 38, 29, 14, 4, 0, -3, + -19, -32, -40, -43, -41, -36, -31, -25, -19, -12, -9, -8, -6, -1, 2, 2, + 0, -3, -4, -1, 3, 6, 6, 2, -3, -6, -2, 2, 2, 1, 2, 7, + 16, 25, 32, 35, 35, 36, 36, 33, 24, 11, -3, -18, -32, -40, -42, -40, + -36, -30, -25, -18, -12, -9, -8, -5, -1, 2, 2, 0, -3, -4, -1, 3, + 7, 6, 2, -4, -5, -2, 2, 2, 1, 2, 8, 17, 25, 32, 35, 36, + 36, 36, 32, 23, 10, -4, -20, -33, -41, -42, -40, -35, -30, -24, -18, -12, + -9, -8, -5, -1, 3, 2, -1, -4, -4, -1, 4, 7, 6, 1, -4, -5, + -2, -1, 3, 1, 3, 5, 3, -3, -1, -1, 1, -15, 1, 1, -5, -7, + 7, -2, -4, 3, -2, -5, -1, -3, -3, -1, 6, 3, 2, 3, -26, -117, + 35, -8, -19, 24, 58, -7, -6, 25, -9, 7, 4, 10, 2, 7, 6, 6, + 0, 6, -2, -1, -3, -3, 8, 71, 0, 17, 27, 20, -102, -115, 39, -32, + -18, -5, 58, -15, -12, 13, -10, -4, 1, 2, 1, 0, 6, 2, 1, 2, + 0, -4, 0, -5, 2, 67, 9, 14, 28, 29, -72, -126, 27, -25, -19, -14, + 58, -6, -11, 13, -5, -3, 3, 3, 4, 1, 8, 3, 3, 3, 3, -2, + 2, -3, -3, 62, 17, 14, 27, 35, -45, -128, 11, -19, -20, -22, 53, 1, + -12, 11, -3, -4, 2, 3, 4, 1, 7, 3, 3, 3, 3, -2, 2, -2, + -9, 57, 22, 14, 25, 37, -23, -125, -8, -15, -20, -30, 46, 9, -12, 10, + -2, -3, 0, 3, 3, 1, 6, 4, 2, 3, 2, -2, 1, 0, -16, 50, + 26, 13, 22, 37, -2, -117, -27, -13, -18, -36, 36, 16, -13, 9, -2, -2, + -2, 3, 2, 2, 4, 5, 1, 4, 2, -1, 0, 4, -20, 43, 29, 15, + 20, 36, 14, -102, -43, -15, -16, -40, 26, 22, -12, 8, -2, -2, -3, 3, + 1, 3, 2, 6, 1, 5, 1, 0, -1, 7, -23, 35, 31, 18, 18, 33, + 27, -83, -57, -20, -14, -42, 14, 26, -9, 7, -2, 0, -5, 3, 1, 4, + 1, 7, 0, 5, 1, 1, -2, 10, -24, 26, 31, 20, 17, 30, 36, -62, + -65, -27, -12, -43, 2, 28, -7, 6, -2, 0, -5, 3, 0, 4, 0, 7, + 0, 5, 1, 2, -4, 11, -23, 17, 32, 22, 16, 27, 42, -44, -67, -36, + -9, -42, -8, 28, -3, 5, -1, 1, -5, 2, 0, 4, 1, 7, 1, 5, + 1, 3, -5, 13, -22, 10, 31, 23, 17, 22, 45, -25, -66, -45, -8, -40, + -18, 27, 0, 5, -1, 1, -5, 1, 0, 4, 0, 6, 2, 4, 2, 3, + -6, 14, -19, 2, 29, 25, 19, 19, 47, -10, -60, -54, -10, -37, -27, 24, + 4, 4, 0, 1, -5, 0, 0, 3, 1, 5, 2, 4, 2, 4, -7, 15, + -16, -4, 27, 25, 21, 15, 48, 4, -51, -61, -12, -33, -34, 19, 7, 4, + 1, 0, -4, -1, 0, 3, 2, 5, 3, 3, 3, 5, -8, 15, -11, -10, + 24, 25, 23, 12, 45, 15, -39, -66, -18, -28, -40, 12, 10, 4, 2, 1, + -3, -2, 0, 2, 2, 4, 3, 3, 3, 5, -8, 13, -6, -14, 19, 25, + 25, 10, 43, 24, -25, -67, -25, -24, -45, 4, 11, 5, 3, 0, -2, -3, + -1, 1, 2, 3, 3, 3, 2, 6, -9, 11, -2, -17, 15, 24, 27, 9, + 39, 31, -13, -66, -33, -19, -48, -3, 11, 5, 3, 1, -2, -3, -1, 1, + 2, 4, 3, 3, 2, 8, -9, 9, 3, -18, 10, 22, 29, 9, 35, 35, + 0, -61, -41, -17, -49, -11, 10, 6, 3, 2, -2, -3, -2, 1, 1, 4, + 3, 5, 1, 9, -9, 7, 6, -18, 5, 20, 29, 10, 32, 38, 11, -47, + -45, -18, -47, -20, 5, 6, 4, 2, -1, -3, -2, 0, 1, 5, 1, 6, + 1, 7, -7, 6, 6, -16, 1, 16, 27, 11, 29, 40, 20, -30, -43, -23, + -46, -28, -2, 4, 4, 2, -1, -3, -2, -1, 0, 6, -1, 7, 2, 5, + -6, 5, 6, -15, -3, 13, 25, 12, 26, 41, 26, -14, -36, -26, -44, -35, + -11, 1, 4, 2, 0, -4, -3, -3, -1, 7, -2, 7, 4, 4, -6, 4, + 7, -13, -6, 10, 23, 12, 24, 42, 31, 0, -24, -28, -42, -40, -19, -4, + 4, 2, 1, -4, -3, -4, -3, 8, -3, 6, 6, 3, -6, 4, 7, -11, + -8, 7, 20, 12, 21, 41, 34, -2, -31, -34, -29, -21, -12, -3, -4, -10, + -7, -5, -6, -4, 5, 8, -3, -1, 7, -1, -11, -7, 0, 1, 6, 16, + 28, 33, 33, 30, 13, -1, -26, -35, -30, -24, -14, -5, -4, -11, -7, -5, + -6, -6, 3, 8, -2, -2, 7, 1, -11, -9, -1, 0, 4, 14, 26, 32, + 33, 32, 17, 3, -22, -34, -31, -25, -16, -6, -3, -10, -8, -5, -6, -7, + 2, 9, 0, -3, 6, 3, -9, -10, -2, 0, 3, 12, 24, 32, -1, 0, + -3, -1, -8, -5, -16, -5, -14, -4, -13, -5, -1, -7, 16, -17, 28, -16, + 47, 1, 70, 35, 97, 71, 98, 66, 32, -5, -71, -69, -122, -69, -105, -33, + -67, -6, -35, 2, -12, -2, 4, -12, 16, -19, 29, -16, 44, 2, 66, 37, + 92, 76, 95, 74, 33, 5, -69, -63, -122, -69, -106, -36, -66, -11, -33, -3, + -9, -7, 7, -16, 18, -22, 29, -17, 42, 3, 61, 40, 86, 81, 91, 82, + 34, 15, -67, -57, -122, -69, -105, -40, -64, -17, -29, -9, -6, -12, 10, -20, + 20, -23, 28, -17, 39, 4, 56, 42, 80, 85, 88, 89, 35, 24, -63, -53, + -119, -70, -104, -45, -62, -22, -26, -14, -2, -16, 12, -23, 20, -25, 27, -16, + 35, 7, 51, 45, 74, 89, 85, 96, 38, 32, -58, -49, -116, -72, -102, -50, + -60, -27, -24, -19, 0, -20, 14, -24, 20, -24, 24, -14, 31, 10, 45, 48, + 69, 92, 82, 102, 40, 39, -53, -45, -112, -74, -100, -55, -57, -33, -21, -24, + 3, -24, 15, -26, 19, -24, 22, -12, 27, 12, 40, 50, 63, 95, 80, 106, + 43, 45, -47, -42, -107, -76, -97, -60, -55, -38, -18, -28, 4, -26, 15, -27, + 18, -23, 19, -10, 23, 15, 35, 53, 59, 97, 78, 110, 47, 50, -39, -39, + -102, -79, -94, -65, -52, -43, -16, -32, 5, -28, 14, -27, 16, -21, 15, -7, + 18, 18, 30, 55, 54, 98, 76, 113, 51, 55, -32, -37, -96, -81, -91, -70, + -50, -48, -15, -35, 6, -30, 13, -26, 13, -19, 11, -5, 13, 20, 25, 56, + 50, 99, 75, 115, 56, 59, -24, -35, -90, -83, -88, -75, -48, -52, -14, -38, + 5, -30, 11, -25, 10, -17, 7, -2, 9, 22, 21, 57, 47, 99, 75, 116, + 61, 62, -15, -33, -82, -86, -84, -80, -47, -56, -14, -39, 4, -30, 9, -24, + 6, -15, 3, 1, 5, 24, 17, 57, 44, 98, 75, 116, 66, 65, -6, -31, + -75, -88, -81, -83, -46, -59, -14, -41, 3, -30, 6, -22, 3, -12, -1, 3, + 1, 26, 13, 57, 41, 96, 75, 115, 72, 68, 2, -29, -69, -89, -78, -87, + -45, -62, -15, -42, 0, -29, 3, -20, -1, -10, -5, 5, -2, 26, 11, 56, + 40, 94, 76, 114, 77, 69, 12, -28, -61, -91, -75, -89, -45, -64, -16, -42, + -2, -28, 0, -18, -5, -8, -9, 7, -6, 27, 8, 55, 38, 91, 77, 112, + 82, 71, 20, -25, -55, -91, -73, -91, -46, -65, -18, -42, -5, -26, -4, -15, + -10, -5, -13, 9, -9, 27, 7, 53, 37, 88, 78, 110, 87, 72, 29, -23, + -48, -90, -71, -93, -47, -66, -21, -41, -9, -24, -8, -13, -13, -3, -16, 9, + -11, 27, 5, 51, 37, 84, 79, 108, 93, 74, 37, -20, -42, -90, -70, -94, + -49, -66, -24, -40, -12, -23, -12, -12, -16, -2, -18, 10, -12, 25, 5, 48, + 37, 80, 81, 105, 98, 75, 45, -16, -36, -88, -68, -94, -51, -66, -28, -39, + -16, -21, -15, -10, -19, -1, -21, 10, -13, 24, 4, 45, 37, 76, 82, 102, + 102, 76, 52, -13, -30, -85, -67, -94, -54, -66, -31, -38, -20, -19, -19, -9, + -22, 0, -22, 9, -14, 22, 4, 41, 37, 71, 83, 99, 105, 77, 59, -8, + -25, -82, -67, -93, -56, -65, -35, -37, -23, -18, -22, -7, -25, 0, -24, 8, + -14, 20, 5, 37, 38, 67, 84, 96, 108, 79, 65, -3, -20, -79, -66, -92, + -59, -65, -39, -36, -27, -17, -25, -7, -27, -1, -24, 6, -14, 17, 6, 34, + 39, 63, 84, 93, 111, 80, 71, 1, -15, -75, -66, -90, -62, -64, -43, -35, + -31, -16, -28, -6, -28, -1, -25, 5, -14, 14, 6, 30, 39, 58, 85, 90, + 113, 82, 76, 7, -11, -70, -66, -88, -66, -62, -46, -34, -34, -15, -30, -7, + -30, -2, -25, 2, -13, 11, 7, 26, 40, 53, 84, 87, 115, 84, 81, 13, + -7, -65, -66, -85, -68, -61, -50, -33, -37, -15, -32, -7, -30, -4, -25, 0, + -12, 7, 9, 19, 37, 52, 80, 97, 118, 113, 98, 54, 7, -41, -72, -87, + -87, -75, -65, -47, -42, -29, -30, -22, -24, -19, -19, -14, -9, -2, 8, 17, + 36, 50, 77, 95, 117, 115, 101, 60, 13, -35, -69, -85, -88, -75, -66, -49, + -44, -31, -31, -23, -25, -20, -20, -15, -9, -2, -1, 0, 0, 0, 0, -1, + -1, -1, 3, 9, 14, 14, 10, -3, -17, -13, 1, 1, 23, 33, -14, -55, + -59, -80, -75, -35, -7, 51, 40, -29, -35, -53, -128, -31, 111, 72, 46, 55, + -19, -73, -23, 14, 64, 104, 87, 105, 68, -54, -76, -1, -18, 12, 92, 23, + -79, -93, -105, -119, -64, -20, 39, 70, 2, -45, -52, -107, -82, 73, 106, 56, + 53, 12, -57, -37, 14, 52, 105, 101, 94, 85, -5, -75, -25, -1, -8, 59, + 52, -45, -89, -94, -117, -90, -42, 1, 53, 29, -29, -45, -79, -104, 3, 99, + 78, 63, 42, -25, -49, -7, 30, 83, 112, 103, 99, 40, -54, -58, -11, -7, + 36, 68, -4, -80, -98, -114, -106, -57, -15, 33, 42, -10, -46, -66, -97, -45, + 68, 90, 67, 53, 4, -40, -20, 18, 60, 103, 107, 100, 69, -15, -62, -31, + -9, 15, 60, 31, -50, -90, -108, -115, -79, -33, 11, 42, 15, -33, -58, -87, + -75, 21, 87, 79, 63, 27, -26, -33, 1, 40, 88, 111, 105, 85, 20, -50, + -49, -17, 5, 46, 49, -17, -77, -102, -115, -95, -49, -7, 31, 28, -15, -50, + -76, -84, -21, 64, 84, 71, 45, -4, -32, -13, 22, 66, 103, 108, 95, 50, + -23, -56, -32, -5, 30, 55, 14, -53, -92, -111, -107, -68, -24, 16, 34, 4, + -37, -66, -85, -53, 32, 81, 77, 58, 17, -25, -24, 6, 46, 89, 108, 101, + 71, 6, -49, -45, -16, 15, 49, 36, -26, -77, -103, -110, -85, -41, 0, 30, + 20, -21, -55, -79, -72, -5, 65, 81, 67, 36, -10, -28, -8, 27, 71, 102, + 104, 85, 34, -31, -51, -29, 1, 37, 48, 2, -57, -93, -109, -97, -58, -16, + 20, 28, -4, -42, -70, -79, -36, 39, 78, 74, 51, 9, -24, -18, 11, 51, + 91, 105, 94, 57, -6, -48, -41, -12, 22, 48, 26, -33, -79, -103, -104, -74, + -32, 6, 28, 12, -27, -60, -78, -59, 8, 66, 78, 62, 27, -13, -24, -3, + 33, 74, 100, 99, 74, 20, -35, -48, -25, 8, 40, 40, -7, -61, -94, -106, + -88, -49, -9, 21, 21, -11, -47, -72, -71, -22, 45, 76, 71, 43, 2, -22, + -13, 16, 56, 91, 101, 85, 43, -15, -47, -36, -6, 28, 45, 16, -38, -80, + -102, -97, -65, -24, 11, 25, 4, -33, -63, -75, -46, 18, 66, 75, 56, 19, + -15, -20, 2, 38, 77, 98, 93, 62, 8, -38, -44, -20, 14, 41, 32, -15, + -64, -94, -101, -79, -40, -2, 22, 15, -17, -52, -72, -61, -9, 49, 74, 66, + 36, -2, -21, -9, 22, 61, 91, 96, 76, 31, -22, -45, -32, 0, 32, 40, + 7, -43, -82, -99, -89, -56, -17, 14, 21, -2, -38, -65, -69, -33, 26, 66, + 71, 50, 13, -16, -16, 7, 43, 79, 95, 85, 50, -2, -40, -40, -14, 20, + 40, 24, -22, -66, -93, -95, -70, -32, 3, 21, 9, -23, -55, -70, -51, 1, + 52, 71, 60, 28, -6, -19, -4, 27, 64, 90, 91, 66, 19, -27, -43, -26, + 6, 34, 35, -1, -48, -83, -96, -81, -47, -10, 16, 17, -9, -43, -66, -62, + -22, 33, 66, 67, 43, 7, -16, -13, 12, 48, 80, 91, 77, 39, -10, -40, + -36, -8, 24, 38, 17, -28, -69, -92, -89, -62, -25, 7, 19, 4, -29, -58, + -67, -42, 10, 55, 70, 55, 22, -9, -17, 0, 33, 68, 90, 86, 57, 10, + -31, -41, -21, 12, 36, 30, -8, -53, -85, -94, -75, -41, -5, 17, 13, -15, + -48, -67, -57, -13, 39, 68, 64, 37, 3, -16, -9, 18, 54, 84, 91, 72, + 30, -17, -41, -33, -2, 28, 37, 10, -35, -74, -94, -86, -56, -19, 10, 17, + -2, -36, -63, -66, -34, 19, 60, 70, 51, 17, -11, -15, 5, 39, 74, 92, + 83, 49, 1, -36, -40, -16, 18, 37, 24, -17, -61, -90, -93, -70, -34, 1, + 18, 8, -22, -55, -69, -50, -2, 47, 70, 61, 31, -3, -17, -5, 26, 62, + 88, 90, 65, 19, -25, -42, -27, 5, 33, 33, 1, -45, -81, -95, -81, -48, + -11, 14, 15, -10, -43, -66, -61, -22, 31, 65, 68, 43, 9, -14, -11, 12, + 49, 80, 92, 76, 38, -10, -39, -36, -8, 24, 38, 16, -27, -70, -92, -89, + -61, -25, 7, 17, 3, -31, -59, -68, -39, 8, 55, 55, 19, 0, -9, -10, + -14, -13, -21, -30, -32, -44, -49, -57, -65, -72, -83, -98, -104, -117, -123, -128, + -127, -128, -128, -128, -128, -127, -128, -120, -117, -109, -100, -90, -83, -72, -66, -55, + -50, -33, -42, -18, -29, -18, 15, -6, 11, 7, 19, 3, 38, 5, 48, 44, + 64, 57, 97, 82, 111, 104, 110, 107, 120, 116, 125, 126, 126, 126, 126, 127, + 117, 125, 123, 100, 127, 101, 124, 102, 121, 109, 126, 96, 125, 116, 127, 90, + 119, 87, 127, 90, 118, 95, 123, 93, 106, 90, 100, 104, 74, 84, 73, 97, + 72, 71, 57, 66, 80, 36, 59, 38, 55, 35, 57, -6, 64, 10, 25, 19, + 19, -22, 65, -26, 14, 2, -17, -12, 22, -40, -3, -31, -24, -38, -1, -56, + -6, -48, -36, -54, -19, -56, -33, -49, -69, -49, -52, -53, -60, -61, -84, -76, + -85, -96, -95, -95, -114, -93, -117, -104, -93, -101, -98, -100, -101, -96, -78, -95, + -71, -70, -72, -52, -63, -70, -43, -77, -41, -48, -65, -53, -53, -59, -42, -56, + -37, -64, -54, -52, -50, -54, -56, -54, -55, -62, -51, -47, -44, -67, -60, -63, + -56, -64, -53, -48, -61, -53, -58, -38, -48, -32, -38, -34, -28, -26, -23, -25, + -22, -6, -7, -12, -1, 5, 6, 6, -7, 22, -4, 27, 15, 18, 24, 37, + 30, 47, 24, 53, 29, 63, 29, 46, 46, 51, 52, 53, 36, 54, 65, 55, + 33, 64, 36, 69, 54, 26, 62, 66, 36, 68, 30, 47, 54, 58, 20, 55, + 31, 40, 50, 35, 19, 56, 33, 25, 46, 18, 22, 42, 21, 25, 32, 19, + 19, 26, 18, 23, 29, 24, 7, 27, 6, 33, 8, 17, -2, 14, 3, 23, + 14, 7, 5, -9, -13, -10, -23, -12, -16, -27, -8, -18, -15, -3, -18, -24, + -5, -23, -9, 0, -11, 4, -1, 4, 2, 5, -2, 3, -1, -7, 4, -11, + 1, -12, -4, -7, -10, -11, -11, -16, -23, -15, -20, -22, -23, -20, -30, -23, + -31, -25, -32, -35, -41, -34, -44, -39, -34, -49, -33, -30, -36, -29, -33, -14, + -24, -32, -18, -15, -7, -9, -11, 5, -14, 27, -11, 16, -10, 13, -9, 23, + -10, 19, 10, 18, 11, 29, 1, 47, 27, -4, 45, 3, 43, 40, 14, 13, + 57, 16, 34, 27, 22, 30, 32, 14, 24, 27, 20, 20, 17, 4, 20, 20, + 8, 8, 0, 10, -3, 17, -8, -1, -4, 1, 0, 6, -7, -3, -3, -13, + -5, -6, -18, -5, -28, -12, -13, -5, -11, -5, -28, -7, -15, -10, -6, -28, + -16, -12, -17, -8, -10, -19, -10, -24, -30, -32, -26, -31, -36, -32, -33, -27, + -25, -26, -26, -25, -25, -23, -16, -22, -10, -11, -7, -7, 4, -10, 10, -9, + 11, -8, 4, -6, 4, -8, 3, -4, 2, -3, -5, -3, -11, -8, -6, -12, + -11, -7, -24, -4, -17, -9, -18, -28, -16, -29, -23, -38, -24, -34, -22, -38, + -18, -27, -10, -22, -19, -21, -2, -23, 10, -19, 0, 4, 16, 7, 0, 3, + 17, 14, 26, 8, 25, 27, 30, 25, 38, 31, 49, 37, 42, 45, 48, 55, + 63, 46, 54, 54, 56, 59, 56, 47, 50, 53, 47, 50, 44, 42, 35, 40, + 31, 37, 35, 27, 20, 23, 19, 26, 24, 18, 11, 14, 18, 24, 18, 12, + 10, 3, 12, 2, 9, 4, 0, 0, 3, -4, 11, 1, 1, -1, -5, -7, + 1, -6, -1, 2, -4, 1, -1, -7, -9, -11, -21, -19, -20, -28, -27, -22, + -29, -24, -26, -32, -22, -25, -31, -24, -19, -22, -11, -19, -15, -4, -5, -4, + 0, -6, -6, 2, -9, -5, -5, -9, -10, -7, -18, -8, -14, -14, -19, -29, + -25, -16, -25, -30, -30, -30, -21, -29, -38, -37, -36, -41, -44, -53, -48, -43, + -44, -55, -46, -40, -33, -36, -40, -40, -28, -25, -24, -23, -17, -15, 1, -3, + -1, 5, 2, 9, 1, 4, 12, 13, 14, 15, 9, 21, 26, 32, 31, 28, + 28, 41, 38, 49, 45, 46, 53, 56, 57, 57, 57, 58, 55, 48, 56, 56, + 56, 45, 39, 41, 41, 44, 42, 25, 28, 27, 24, 28, 21, 14, 17, 8, + 15, 22, 13, 15, 16, 3, 11, 10, 4, 6, 4, -8, 0, -2, -2, -3, + -2, 1, 3, -3, -3, -6, -8, -5, 4, 3, 2, -4, -2, -1, 5, 3, + -2, -2, -2, 3, 7, -2, -26, -37, -34, -30, -13, -14, -21, -24, -27, -24, + -13, -7, -15, 6, 3, -30, -50, -48, -47, -41, -26, -8, 28, 43, 38, 57, + 63, 56, 75, 118, 127, 117, 99, 86, 85, 66, 46, 59, 80, 69, 43, 27, + -6, -47, -74, -80, -71, -57, -40, -44, -56, -78, -88, -78, -59, -52, -51, -56, + -57, -47, -36, -36, -39, -39, -32, -17, 6, 24, 33, 10, -14, -14, -2, -11, + -20, -15, -24, -28, -28, -25, -28, -54, -73, -65, -43, -18, 6, 27, 21, 23, + 17, 22, 18, 16, 31, 50, 45, 25, 22, 8, -20, -17, 8, 29, 10, -22, + -41, -45, -51, -53, -31, -18, -23, -7, 37, 54, 38, 36, 60, 100, 119, 120, + 122, 125, 110, 88, 94, 99, 90, 85, 82, 54, 26, -5, -49, -83, -85, -67, + -36, -14, -30, -55, -76, -86, -65, -41, -45, -60, -53, -43, -35, -34, -41, -43, + -45, -35, 10, 40, 32, 3, -3, -14, -30, -38, -33, -23, -29, -26, -18, -10, + -17, -37, -46, -58, -61, -45, -17, -4, -2, 19, 31, 27, 13, 22, 38, 49, + 59, 69, 60, 23, -13, -11, 13, 24, 19, 24, 8, -30, -58, -58, -66, -85, + -90, -61, -19, -1, -11, -5, 25, 42, 61, 92, 109, 106, 110, 104, 93, 93, + 89, 82, 86, 81, 71, 51, 13, -40, -74, -87, -73, -35, -24, -50, -71, -73, + -53, -50, -58, -68, -60, -61, -54, -30, -25, -40, -52, -25, 13, 32, 45, 49, + 44, 28, 22, 29, 32, 20, 3, 7, 6, 0, -1, -4, -30, -63, -69, -62, + -57, -49, -25, 2, 17, 24, 27, 30, 10, 4, 38, 77, 66, 32, 13, 7, + 0, 9, 31, 43, 23, -11, -25, -23, -46, -83, -87, -63, -42, -19, -6, -3, + 6, 27, 49, 81, 108, 121, 123, 124, 115, 110, 98, 80, 78, 77, 77, 69, + 54, 8, -56, -99, -92, -53, -46, -64, -75, -73, -70, -75, -62, -67, -86, -88, + -54, -28, -33, -46, -50, -40, -24, -3, 29, 51, 48, 34, 44, 44, 30, 18, + 13, -3, -15, -7, -1, -10, -36, -56, -65, -79, -100, -91, -64, -52, -40, -5, + 20, 9, -14, -9, 21, 49, 59, 58, 49, 25, -1, 11, 39, 39, 22, 19, + 20, 8, -19, -49, -72, -69, -58, -43, -27, -24, -13, -5, 12, 38, 74, 97, + 110, 124, 126, 126, 114, 105, 100, 87, 91, 108, 115, 73, 5, -41, -49, -49, + -53, -45, -49, -69, -77, -60, -51, -71, -94, -96, -68, -49, -46, -44, -45, -60, + -60, -27, 0, 11, 26, 37, 37, 37, 40, 42, 34, 8, -1, 14, 15, -5, + -12, -18, -44, -75, -85, -88, -98, -99, -76, -36, -12, -19, -24, -11, -9, 1, + 36, 71, 58, 29, 13, 17, 33, 33, 30, 35, 44, 44, 27, -3, -39, -51, + -61, -55, -41, -31, -25, -29, -21, -1, 23, 46, 76, 102, 109, 110, 116, 118, + 92, 61, 76, 112, 120, 93, 57, 14, -28, -54, -50, -46, -60, -83, -82, -64, + -62, -82, -89, -93, -101, -88, -59, -52, -64, -75, -76, -63, -50, -30, -1, 9, + 8, 11, 32, 44, 36, 29, 32, 27, 20, 22, 28, 24, 0, -21, -30, -45, + -78, -97, -83, -66, -50, -32, -17, -16, -23, -20, 4, 38, 51, 47, 37, 28, + 29, 27, 27, 31, 42, 54, 55, 43, 20, -5, -29, -40, -37, -30, -27, -23, + -15, -12, -11, 8, 43, 67, 78, 100, 122, 126, 107, 84, 81, 92, 106, 115, + 110, 79, 31, -3, -13, -26, -47, -56, -56, -58, -58, -56, -59, -72, -86, -84, + -66, -57, -56, -56, -60, -74, -74, -51, -32, -24, -14, 3, 14, 15, 19, 28, + 33, 19, 11, 22, 29, 18, 8, 9, 0, 0, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, + -1, -1, -1, -1, -1, -1, -1, 0, -1, -3, -2, -1, 0, 2, -4, -13, + -21, -23, -19, -8, 7, 17, 23, 26, 33, 38, 32, 17, -5, -17, -24, -20, + -6, -3, -16, -29, -26, -17, -5, -1, 2, 7, 11, 17, 15, 9, 9, 3, + 10, 15, 9, -14, -33, -27, -18, -6, -7, -10, -6, 0, 12, 15, 29, 38, + 36, 32, 11, 0, -30, -45, -50, -39, -23, -27, -24, -15, 6, 25, 37, 51, + 46, 40, 0, -19, -22, -34, -30, -40, -45, -51, -34, -1, 25, 48, 40, 43, + 51, 64, 58, 5, -22, -49, -63, -69, -68, -58, -54, -16, 13, 44, 66, 61, + 68, 72, 86, 47, -17, -56, -82, -88, -93, -72, -58, -40, 4, 45, 94, 98, + 84, 65, 68, 71, 15, -46, -88, -90, -88, -85, -62, -56, -34, -4, 41, 80, + 82, 74, 54, 70, 66, 25, -29, -70, -74, -90, -87, -79, -73, -46, -10, 54, + 90, 103, 88, 76, 90, 69, 25, -38, -76, -96, -119, -111, -103, -81, -57, -12, + 50, 90, 113, 98, 100, 112, 103, 60, -11, -54, -95, -121, -124, -119, -95, -71, + -10, 53, 103, 116, 93, 91, 89, 80, 31, -28, -67, -108, -122, -128, -110, -87, + -53, 8, 60, 107, 107, 89, 83, 83, 76, 27, -14, -52, -84, -99, -103, -82, + -72, -40, 4, 53, 92, 92, 88, 85, 97, 87, 42, 3, -45, -74, -106, -111, + -105, -101, -70, -30, 27, 65, 77, 83, 87, 106, 90, 58, 16, -30, -67, -101, + -100, -101, -93, -68, -27, 29, 60, 77, 79, 93, 111, 96, 71, 24, -21, -73, + -109, -118, -127, -118, -98, -50, 6, 43, 65, 70, 99, 115, 108, 82, 40, -1, + -53, -80, -94, -105, -101, -82, -31, 18, 56, 66, 72, 95, 103, 97, 64, 29, + -15, -63, -85, -102, -105, -104, -81, -35, 13, 53, 58, 69, 86, 97, 94, 67, + 39, -12, -54, -80, -97, -102, -103, -77, -38, 9, 40, 45, 60, 77, 95, 88, + 70, 41, -8, -46, -74, -87, -99, -100, -78, -42, 10, 37, 50, 66, 89, 110, + 103, 91, 57, 9, -33, -68, -86, -105, -105, -89, -51, -2, 23, 40, 53, 80, + 99, 98, 89, 53, 8, -37, -68, -90, -107, -106, -94, -51, -5, 25, 43, 58, + 86, 95, 98, 86, 52, 9, -36, -64, -92, -105, -108, -95, -53, -11, 22, 37, + 57, 81, 90, 96, 82, 52, 6, -34, -64, -92, -104, -113, -97, -59, -18, 15, + 31, 58, 79, 92, 98, 87, 57, 9, -29, -63, -87, -100, -109, -91, -58, -13, + 16, 36, 62, 78, 93, 96, 88, 56, 12, -25, -62, -83, -101, -106, -89, -57, + -15, 6, 30, 52, 71, 87, 94, 89, 55, 18, -21, -55, -76, -96, -100, -88, + -53, -16, 6, 31, 53, 76, 93, 105, 98, 64, 26, -18, -52, -78, -99, -105, + -95, -59, -26, 0, 24, 45, 66, 81, 97, 88, 62, 28, -12, -40, -67, -84, + -95, -83, -50, -21, 4, 24, 47, 64, 81, 96, 85, 63, 26, -11, -41, -69, + -88, -102, -91, -64, -36, -12, 10, 34, 51, 74, 87, 81, 62, 26, -7, -40, + -63, -83, -95, -83, -58, -31, -10, 14, 34, 51, 75, 85, 82, 61, 30, -3, + -34, -57, -81, -92, -83, -60, -36, -15, 11, 27, 47, 69, 80, 79, 59, 30, + -5, -33, -57, -82, -93, -84, -61, -38, -15, 10, 25, 48, 68, 80, 77, 58, + 29, -4, -30, -56, -80, -89, -78, -54, -34, -8, 10, 0, 0, 1, 0, -2, + -2, -5, -8, -3, 3, -4, -10, 2, 8, 3, 4, 5, -3, -9, 10, 26, + 26, 12, -4, -40, -64, -50, 1, 55, 69, 28, -23, -65, -83, -52, 13, 67, + 67, 39, 16, -15, -48, -38, 10, 53, 44, 5, -5, -14, -43, -35, 16, 54, + 37, -1, -26, -53, -82, -37, 35, 67, 44, 2, -10, -20, -39, -19, 27, 55, + 42, 3, -26, -67, -107, -62, 43, 110, 102, 43, -18, -63, -91, -35, 73, 120, + 77, -6, -72, -113, -109, -36, 53, 78, 50, 0, -46, -72, -71, -20, 67, 112, + 100, 44, -24, -88, -123, -84, 5, 71, 97, 66, 7, -53, -100, -80, -1, 83, + 127, 108, 38, -57, -121, -119, -57, 24, 84, 97, 62, -4, -77, -97, -46, 32, + 101, 108, 56, -20, -103, -119, -69, 18, 105, 126, 90, 6, -92, -126, -90, -3, + 85, 108, 75, 0, -86, -117, -85, -6, 76, 115, 101, 30, -68, -118, -105, -33, + 57, 105, 102, 41, -46, -104, -112, -59, 25, 95, 121, 81, -5, -88, -126, -94, + -12, 63, 101, 76, 7, -67, -107, -73, 11, 94, 127, 102, 21, -74, -124, -95, + -21, 57, 101, 82, 21, -48, -89, -59, 6, 67, 95, 60, -11, -82, -115, -81, + -13, 52, 84, 52, -9, -68, -96, -56, 9, 66, 93, 63, 10, -52, -86, -54, + 1, 60, 96, 70, 19, -44, -80, -51, 0, 55, 94, 69, 20, -42, -88, -76, + -40, 24, 79, 72, 34, -28, -75, -63, -23, 35, 71, 48, 4, -57, -95, -67, + -10, 62, 103, 75, 18, -61, -110, -86, -22, 61, 110, 90, 37, -45, -100, -87, + -39, 34, 81, 70, 33, -39, -88, -76, -24, 54, 94, 76, 32, -46, -100, -92, + -42, 35, 73, 62, 26, -46, -97, -93, -44, 36, 81, 75, 35, -38, -87, -81, + -26, 58, 99, 85, 37, -44, -101, -103, -46, 47, 98, 97, 56, -27, -90, -99, + -49, 37, 88, 95, 62, -12, -74, -93, -51, 27, 69, 71, 35, -30, -78, -87, + -38, 41, 84, 90, 57, -11, -71, -96, -56, 21, 69, 86, 60, -4, -67, -97, + -61, 12, 65, 88, 65, 3, -61, -94, -60, 14, 71, 96, 68, 3, -66, -104, + -70, 3, 59, 84, 59, -1, -67, -107, -76, -3, 59, 89, 64, 3, -67, -111, + -82, -9, 57, 92, 76, 26, -43, -93, -71, -9, 50, 80, 64, 16, -51, -100, + -79, -17, 49, 88, 77, 30, -41, -95, -79, -17, 49, 87, 77, 34, -36, -92, + -78, -19, 44, 82, 73, 33, -37, -95, -84, -23, 47, 89, 83, 43, -30, -92, + -83, -28, 39, 79, 74, 40, -28, -87, -82, -31, 34, 71, 67, 35, -31, -88, + -85, -36, 28, 68, 69, 44, -20, -79, -83, -43, 19, 59, 64, 41, -25, -89, + -100, -61, 9, 60, 76, 57, -10, -75, -90, -51, 22, 74, 88, 66, 1, -61, + -78, -42, 25, 71, 84, 63, -1, -67, -90, -59, 8, 59, 81, 68, 8, -56, + -85, -62, 1, 50, 74, 63, 7, -53, -84, -60, 5, 55, 80, 70, 17, -43, + -76, -55, 4, 49, 73, 65, 17, -41, -77, -62, -9, 38, 68, 64, 17, -43, + -84, -73, -22, 23, 56, 57, 18, -36, -77, -68, -23, 20, 51, 52, 16, -36, + -77, -70, -26, 18, 54, 59, 28, -22, -64, -59, -20, 21, 56, 63, 36, -12, + -55, -52, -16, 25, 58, 63, 35, -14, -59, -57, -22, 18, 51, 57, 31, -16, + -58, -58, -27, 10, 43, 51, 30, -16, -59, -60, -28, 12, 48, 57, 35, -13, + -59, -64, -35, 7, 47, 63, 47, 1, -46, -55, -32, 7, 47, 0, 0, -1, + -1, -4, 1, -1, -3, -13, -8, -14, -3, -2, -2, 1, 8, 5, 7, -21, + -13, -2, -6, -8, -22, -6, 5, 11, 34, 41, 33, 13, 28, 33, 48, 35, + 21, -3, -26, -18, -10, 3, 7, 22, 21, 63, 40, 41, 43, 4, -8, -43, + -63, -77, -77, -59, -18, 3, 2, -21, -46, -74, -90, -108, -101, -94, -89, -84, + -85, -77, -59, -50, -33, -7, 18, 37, 47, 64, 101, 127, 125, 127, 126, 126, + 126, 122, 100, 87, 62, 37, 28, 27, 25, 27, 34, 25, -4, -45, -85, -123, + -128, -126, -128, -127, -123, -92, -73, -55, -45, -37, -33, -32, -33, -43, -53, -55, + -43, -20, 3, 20, 34, 42, 49, 55, 63, 74, 84, 93, 101, 107, 112, 117, + 109, 92, 63, 33, 8, -13, -25, -29, -30, -27, -27, -32, -46, -63, -82, -98, + -109, -116, -121, -118, -104, -80, -49, -12, 21, 45, 58, 64, 66, 66, 61, 51, + 44, 37, 32, 32, 33, 33, 28, 23, 15, 8, 3, 2, 9, 16, 20, 24, + 23, 14, -1, -20, -37, -48, -53, -52, -47, -38, -26, -13, -5, -1, -4, -10, + -22, -34, -43, -48, -46, -34, -16, 5, 25, 45, 65, 78, 84, 83, 71, 55, + 39, 24, 9, -3, -12, -23, -34, -45, -57, -65, -71, -71, -63, -49, -34, -21, + -11, -2, 2, 8, 11, 12, 14, 14, 20, 28, 38, 50, 58, 63, 61, 56, + 46, 33, 17, -1, -19, -34, -45, -48, -44, -32, -19, -5, 5, 7, 4, -2, + -7, -11, -15, -18, -21, -23, -26, -28, -30, -31, -29, -26, -20, -12, -1, 11, + 21, 32, 42, 51, 55, 55, 52, 46, 41, 37, 32, 30, 28, 27, 24, 19, + 12, -1, -21, -45, -67, -89, -103, -107, -101, -90, -70, -51, -33, -18, -2, 11, + 23, 33, 39, 44, 49, 52, 57, 59, 59, 56, 52, 48, 41, 35, 28, 20, + 15, 11, 4, 0, -5, -11, -18, -25, -34, -42, -47, -48, -46, -40, -33, -27, + -24, -21, -24, -32, -42, -51, -56, -58, -56, -47, -35, -18, 2, 24, 48, 70, + 88, 99, 104, 102, 97, 89, 79, 69, 59, 49, 37, 27, 14, 0, -14, -29, + -44, -58, -71, -81, -87, -88, -88, -85, -81, -77, -72, -63, -51, -37, -21, -5, + 12, 29, 43, 53, 59, 61, 57, 48, 36, 24, 13, 8, 8, 15, 25, 38, + 48, 54, 54, 50, 43, 33, 22, 11, 3, -6, -15, -25, -35, -46, -54, -61, + -65, -68, -69, -69, -68, -64, -59, -52, -43, -32, -20, -7, 6, 19, 31, 42, + 51, 58, 62, 64, 62, 58, 52, 44, 35, 26, 17, 9, 1, -5, -10, -15, + -18, -19, -20, -19, -18, -16, -15, -14, -14, -15, -16, -17, -18, -19, -19, -19, + -19, -18, -16, -14, -11, -9, -6, -3, 0, 3, 6, 10, 14, 18, 22, 27, + 32, 35, 37, 37, 35, 30, 23, 14, 4, -6, -15, -24, -31, -36, -39, -40, + -39, -37, -32, -26, -19, -10, -1, 8, 17, 24, 29, 32, 33, 32, 29, 25, + 20, 15, 11, 7, 3, -1, -5, -9, -14, -19, -24, -28, -31, -32, -31, -27, + -23, -16, -10, -3, 2, 7, 10, 12, 13, 13, 13, 12, 10, 8, 7, 5, + 5, 5, 5, 6, 8, 10, 13, 17, 20, 23, 25, 26, 25, 21, 16, 9, + 1, -7, -16, -24, -31, -37, -42, -47, -49, -51, -52, -51, -48, -43, -37, -30, + -20, -7, 6, 19, -1, -4, -4, 0, -1, -4, -3, 4, 4, -2, -3, 2, + 1, -4, 0, 5, 0, -4, 2, -10, -26, -29, -34, -49, -61, -44, -21, -8, + -3, -3, 1, 20, 32, 38, 32, 12, -4, 1, 14, 28, 51, 68, 78, 80, + 72, 38, 1, -6, 16, 23, 2, -14, -15, -20, -33, -62, -65, -37, -18, -27, + -29, -26, -45, -38, 8, 52, 55, 31, 26, 16, 17, 45, 80, 87, 77, 62, + 54, 24, -23, -50, -43, -28, -47, -72, -86, -86, -87, -61, -35, -38, -57, -69, + -55, -27, 1, 4, 22, 45, 54, 31, 0, -7, -5, -3, 0, -9, -21, -20, + -15, -27, -31, -10, 5, 9, 3, -21, -67, -83, -46, -3, 8, 18, 22, 4, + -3, 5, 35, 52, 67, 72, 83, 89, 71, 37, 19, 25, 8, -11, -37, -58, + -80, -85, -68, -33, -24, -57, -60, -34, -16, -14, 17, 73, 96, 77, 48, 17, + -7, -9, 4, -1, -3, 6, 3, -12, -10, 19, 33, 33, 41, 35, -29, -70, + -64, -38, -18, 3, 17, -5, -26, -35, -5, 31, 63, 73, 86, 94, 80, 64, + 50, 46, 37, 28, -2, -32, -65, -91, -84, -63, -59, -82, -97, -80, -66, -65, + -43, 8, 49, 60, 61, 42, 27, 23, 23, 14, 15, 18, 10, -12, -17, -9, + -13, 8, 35, 42, 2, -41, -76, -87, -67, -46, -31, -32, -45, -72, -53, -5, + 32, 46, 72, 92, 96, 92, 77, 75, 73, 61, 44, 12, -32, -68, -72, -54, + -58, -75, -85, -67, -57, -61, -60, -46, -11, 24, 35, 22, 15, 6, -1, -13, + 8, 23, 8, -1, -1, -6, -8, 35, 71, 86, 79, 50, -11, -46, -38, -31, + -29, -21, -30, -64, -68, -43, -12, 10, 28, 62, 89, 88, 84, 85, 90, 89, + 95, 83, 28, -32, -53, -36, -44, -62, -64, -55, -59, -54, -52, -48, -23, 19, + 48, 37, 39, 42, 31, 12, 19, 20, 5, 4, 1, -23, -40, -14, 14, 42, + 68, 64, 14, -33, -53, -52, -32, -18, -24, -43, -67, -62, -36, -18, -1, 25, + 54, 57, 58, 56, 54, 50, 66, 80, 44, -21, -50, -40, -52, -69, -77, -60, + -56, -54, -53, -62, -49, -9, 28, 41, 58, 58, 47, 43, 49, 41, 34, 37, + 18, -19, -44, -47, -36, 1, 35, 38, 19, -20, -62, -71, -59, -36, -34, -47, + -63, -63, -50, -38, -17, 7, 37, 56, 74, 80, 73, 61, 87, 116, 99, 47, + -7, -26, -22, -20, -32, -57, -72, -76, -76, -71, -47, -9, 13, 24, 29, 29, + 25, 27, 52, 68, 62, 9, -38, -67, -66, -39, -11, -4, -24, -37, -47, -51, + -49, -44, -55, -39, -6, -17, -52, -54, -19, 1, 15, 24, 31, 41, 55, 71, + 79, 89, 111, 115, 88, 54, 22, -2, -8, -5, -7, -27, -49, -57, -69, -72, + -64, -30, -3, 17, 31, 37, 29, 14, 39, 67, 73, 47, 10, -40, -72, -58, + -23, -12, -19, -19, -39, -49, -42, -46, -62, -44, -8, -11, -36, -51, -39, -15, + 0, 13, 21, 25, 40, 55, 63, 73, 95, 115, 115, 85, 53, 20, 2, -1, + -2, -10, -32, -48, -64, -73, -77, -62, -33, -9, 16, 33, 31, 18, 17, 44, + 67, 70, 49, 6, -45, -69, -53, -24, -13, -19, -24, -40, -47, -45, -50, -62, + -43, -10, -13, -37, -51, -39, -15, 0, -3, -1, 1, -1, -6, -6, -4, -1, + -2, -6, -8, -7, -4, -5, -10, -14, -16, -16, -16, -17, -18, -18, -17, -15, + -15, -16, -15, -13, -10, -9, -9, -11, -13, -14, -11, -9, -8, -9, -7, -3, + -2, -5, -8, -6, 1, 5, 4, 1, 0, 1, 4, 4, 4, 5, 7, 9, + 9, 8, 8, 9, 10, 9, 5, 2, 3, 5, 7, 7, 9, 11, 11, 12, + 14, 14, 12, 8, 7, 8, 5, 1, 3, 8, 9, 9, 10, 14, 16, 15, + 14, 12, 11, 9, 7, 3, -2, -3, 3, 5, 0, -5, -1, -1, -6, -10, + -16, -23, -28, -29, -32, -39, -36, -23, -16, -19, -19, -10, -7, -12, -11, -5, + -6, -11, -13, -11, -9, -8, -2, 6, 8, 8, 9, 6, 2, 4, 8, 9, + 4, 4, 12, 18, 17, 14, 17, 20, 20, 16, 9, 7, 7, 5, 3, 4, + 1, -2, 0, 3, 2, -1, 1, 3, 3, 1, 2, 2, 0, 3, 6, 9, + 8, 0, -5, -3, 7, 12, 8, -2, -2, 9, 10, 2, -3, 2, 5, 1, + -3, -5, -6, -2, -3, -11, -20, -26, -28, -30, -32, -37, -43, -45, -43, -40, + -42, -41, -31, -22, -20, -18, -16, -16, -19, -15, -8, -3, -3, 3, 17, 26, + 22, 16, 18, 23, 27, 26, 23, 17, 15, 21, 25, 24, 25, 31, 36, 32, + 29, 23, 17, 15, 11, 5, 1, 4, 6, 8, 6, 7, 8, 10, 14, 18, + 22, 20, 17, 14, 15, 13, 10, 15, 15, 12, 9, 10, 15, 14, 9, 3, + 6, 10, 5, -3, -9, -16, -16, -10, -11, -20, -24, -18, -20, -32, -42, -48, + -55, -70, -84, -95, -100, -92, -75, -65, -68, -67, -56, -55, -51, -41, -33, -37, + -42, -38, -33, -31, -26, -6, 19, 30, 25, 25, 28, 30, 27, 19, 16, 18, + 31, 44, 46, 48, 56, 71, 77, 74, 66, 54, 47, 37, 19, 3, 2, 3, + 3, 4, 13, 20, 21, 25, 24, 25, 19, 18, 19, 19, 14, 6, 17, 14, + 1, 3, 12, 27, 29, 25, 13, 14, 24, 22, 6, -7, -7, 0, 11, 12, + 1, 0, 10, 8, -13, -32, -46, -52, -57, -70, -88, -106, -101, -81, -74, -82, + -75, -49, -37, -42, -44, -42, -46, -51, -47, -40, -32, -27, -6, 3, 16, 32, + 29, 25, 24, 30, 54, 69, 74, 78, 90, 108, 118, 124, 117, 107, 102, 93, + 76, 61, 50, 41, 35, 31, 26, 13, 4, 0, -1, 0, -6, -12, -10, -8, + -4, 0, -3, -20, -31, -27, -18, -16, -22, -29, -28, -9, 0, -3, -1, 2, + 11, 20, 24, 18, 22, 34, 32, 16, -1, -18, -34, -46, -55, -67, -91, -102, + -91, -72, -73, -81, -68, -55, -55, -65, -74, -79, -87, -87, -83, -81, -77, -60, + -25, 4, 4, -3, 0, 13, 29, 29, 24, 23, 29, 51, 67, 72, 77, 88, + 105, 114, 122, 116, 106, 100, 93, 77, 63, 51, 42, 36, 31, 27, 15, 5, + 0, -1, 0, -4, -10, -9, -7, -3, 2, -1, -16, -28, -26, -16, -13, -18, + -25, -25, -8, 2, 1, 2, 5, 13, 21, 26, 20, 23, 35, 35, 20, 3, + -14, -32, -45, -54, -67, -91, -102, -90, -72, -75, -82, -68, -56, -56, -66, -75, + -81, -88, -88, -83, -82, -77, -59, -22, 4, 1, -1, -2, -3, -3, -1, -1, + -6, -8, -9, -12, -5, 6, 15, 21, 22, 21, 9, -8, -16, -23, -32, -22, + 4, 27, 32, 17, -2, -21, -34, -37, -30, -24, -3, 24, 47, 58, 50, 23, + -12, -41, -52, -47, -33, -2, 28, 48, 45, 28, 0, -36, -58, -53, -34, -4, + 26, 52, 75, 73, 45, -5, -66, -101, -90, -61, -14, 23, 59, 87, 89, 63, + 10, -46, -79, -80, -55, -23, -3, 27, 58, 62, 41, -6, -66, -92, -77, -29, + 19, 41, 65, 74, 69, 42, -9, -73, -109, -107, -67, -17, 23, 70, 104, 111, + 83, 21, -56, -104, -109, -62, -21, 4, 34, 68, 89, 75, 19, -46, -89, -85, + -38, -1, 23, 45, 64, 74, 62, 8, -53, -98, -93, -47, -9, 16, 36, 62, + 86, 78, 13, -67, -121, -109, -56, -9, 25, 58, 89, 109, 81, 8, -70, -119, + -106, -56, -7, 32, 63, 90, 108, 74, -3, -89, -128, -118, -70, -22, 23, 62, + 101, 126, 98, 26, -64, -117, -110, -72, -32, 6, 44, 93, 124, 100, 28, -63, + -116, -110, -71, -26, 16, 54, 101, 121, 92, 13, -86, -128, -120, -79, -28, 15, + 60, 111, 127, 95, 11, -83, -127, -116, -80, -29, 15, 67, 117, 127, 100, 17, + -75, -118, -108, -75, -31, 7, 60, 109, 123, 87, 3, -83, -118, -106, -67, -23, + 13, 62, 106, 119, 85, 3, -77, -106, -95, -61, -27, 2, 52, 103, 124, 97, + 19, -61, -95, -92, -63, -34, -4, 45, 94, 116, 87, 8, -63, -91, -85, -58, + -36, -9, 36, 81, 104, 76, 2, -60, -87, -77, -52, -32, -2, 48, 97, 119, + 86, 7, -59, -90, -85, -65, -50, -22, 26, 78, 107, 79, 11, -49, -78, -73, + -58, -46, -18, 31, 85, 112, 75, 1, -59, -84, -73, -55, -40, -12, 30, 80, + 106, 74, 10, -46, -70, -62, -49, -39, -13, 31, 86, 110, 74, 8, -49, -70, + -59, -46, -33, -6, 38, 92, 111, 76, 13, -42, -62, -56, -51, -44, -23, 19, + 75, 97, 67, 8, -44, -63, -58, -56, -48, -26, 19, 75, 94, 64, 8, -40, + -55, -50, -49, -42, -25, 18, 69, 85, 57, 4, -41, -54, -51, -50, -45, -28, + 18, 71, 88, 60, 8, -35, -46, -47, -48, -46, -30, 16, 66, 84, 59, 9, + -30, -41, -43, -42, -40, -22, 25, 73, 88, 60, 8, -30, -42, -46, -45, -42, + -21, 28, 74, 83, 52, -1, -36, -46, -45, -40, -37, -17, 26, 66, 73, 41, + -10, -42, -54, -53, -48, -43, -19, 27, 68, 76, 44, -4, -34, -44, -41, -37, + -33, -10, 34, 71, 75, 40, -7, -36, -47, -43, -39, -35, -9, 35, 72, 75, + 39, -7, -38, -49, -45, -43, -38, -11, 33, 68, 70, 36, -4, -31, -39, -36, + -35, -31, -5, 36, 69, 69, 35, -4, -31, -38, -35, -37, -33, -8, 31, 64, + 63, 31, -7, -34, -42, -40, -43, -38, -12, 28, 61, 59, 27, -10, -34, -40, + -38, -41, -35, -9, 31, 63, 60, 29, -6, -31, -37, -38, -42, -35, -10, 29, + 60, 56, 27, -8, -30, -33, -34, -38, -32, -10, 28, 56, 51, 23, -9, -29, + -32, -34, -38, -33, -10, 29, 55, 50, 23, -9, -28, -30, -33, -37, -32, -8, + 32, 56, 52, 23, 23, 0, -2, 0, -2, -6, -6, -6, -5, -2, -1, 5, + 15, 20, 11, 12, 12, 6, 0, -8, -19, -12, -4, -19, -19, -4, 4, -7, + -3, 5, 8, 11, 14, 9, 9, 8, -4, -11, -6, -8, -16, -14, -7, -1, + -3, 1, 10, 13, 24, 28, 12, 10, 14, 11, -14, -29, -19, -12, -21, -25, + -16, 2, 0, -11, -7, 7, 10, 0, 0, 5, 11, 6, 10, 21, 13, 7, + 14, 4, -4, -9, -5, -11, -16, -7, -3, 3, 15, -2, 2, 17, 6, -19, + -16, 3, 3, -14, -10, 7, 7, 4, 8, 11, 4, -5, -12, -9, -6, -14, + -13, -17, -13, -8, 5, 9, 3, 10, 12, 24, 28, 26, 35, 20, -3, 24, + 23, -19, -31, -23, -23, -38, -34, -18, -10, -8, -6, -4, -1, 5, -4, -8, + 2, 15, 12, 26, 56, 37, 10, 25, 25, -4, -21, -24, -23, -26, -30, -27, + -8, 10, -5, 3, 30, 6, -26, -7, 13, -2, -19, -2, 11, 3, 14, 21, + 8, 12, 5, -19, -26, -12, 9, 1, -8, -8, 20, 27, 17, 16, 15, 0, + 23, 39, 11, -4, -13, -21, -21, -32, -36, -27, -20, -24, -10, -4, 5, 14, + 4, -11, -10, 7, -8, -7, 7, 7, 2, 15, 29, 55, 26, 4, 22, 37, + 32, 14, 10, 18, 7, -1, -28, -49, -24, -14, -41, -53, -37, -28, -27, -15, + 1, 2, 14, 14, 13, 3, 0, 1, 18, 9, 7, 11, 23, 23, 25, 16, + -7, 1, 13, 26, 26, 9, 13, 28, 28, 1, -29, -29, -26, -27, -43, -43, + -31, -12, -26, -15, 6, 16, 6, 22, 11, -4, 0, 3, 0, -4, -20, -9, + 15, 23, 19, 7, 25, 19, 42, 63, 40, 13, 22, 24, 1, -41, -60, -55, + -63, -69, -61, -31, -7, 10, 8, 0, 7, 4, 4, 20, 5, -4, 9, 27, + 31, 27, 23, 13, 19, 12, 2, 4, 15, 20, 35, 19, 16, 26, 3, -30, + -48, -31, -40, -60, -59, -47, -13, -3, 12, 22, 11, 7, 9, 8, 3, -10, + -34, -5, 6, 24, 38, 19, 13, 21, 40, 15, 2, 27, 26, 16, 44, 47, + -7, -43, -41, -29, -44, -80, -81, -58, -26, -17, 3, 16, 30, 19, 10, 25, + 16, 6, -12, -3, 13, 30, 38, 20, 17, 22, 25, 18, 13, 16, -3, 1, + 32, 44, -11, -48, -51, -34, -38, -49, -64, -70, -23, -10, -14, -1, 20, 18, + 20, 21, 11, 3, -8, -3, 13, 14, 22, 18, 32, 37, 30, 25, 16, 27, + 27, 18, 37, 52, 12, -26, -56, -57, -46, -71, -92, -86, -50, -21, -10, 8, + 15, 15, 18, 28, 17, 1, 1, 2, 13, 13, 23, 23, 21, 29, 31, 29, + 15, 20, 33, 32, 29, 46, 21, -31, -49, -53, -51, -66, -82, -76, -54, -32, + -10, 12, 19, 29, 18, 3, 0, 16, 20, 29, 31, 20, 25, 31, 43, 41, + 34, 44, 27, 29, 65, 54, -15, -70, -79, -63, -86, -114, -114, -79, -26, -2, + 6, 18, 19, 10, 19, 26, 15, 5, 0, 16, 23, 29, 30, 21, 25, 28, + 37, 37, 38, 44, 32, 29, 66, 65, -7, -67, -74, -59, -82, -114, -117, -85, + -31, -2, 11, 20, 18, 9, 20, 30, 15, 5, 0, 0, 1, 1, 2, 3, + 3, 3, 4, 4, 5, 6, 6, 7, 8, 8, 7, 7, 7, 7, 7, 6, + 4, 3, 2, 0, -1, -2, -3, -5, -6, -8, -9, -9, -11, -12, -14, -15, + -17, -17, -17, -18, -19, -19, -19, -18, -17, -16, -15, -13, -11, -8, -7, -6, + -5, -3, -1, 0, 0, 1, 3, 5, 8, 10, 12, 14, 17, 19, 21, 23, + 26, 27, 28, 28, 28, 26, 25, 24, 23, 23, 21, 19, 18, 16, 15, 14, + 13, 12, 11, 11, 11, 10, 8, 6, 5, 5, 4, 2, 0, -2, -4, -5, + -7, -10, -11, -12, -13, -14, -15, -15, -15, -15, -15, -16, -17, -18, -18, -19, + -21, -23, -25, -27, -28, -29, -29, -30, -30, -29, -27, -25, -23, -22, -20, -18, + -16, -14, -13, -12, -11, -11, -10, -9, -8, -6, -5, -4, -3, -1, 1, 3, + 4, 6, 7, 8, 8, 9, 10, 11, 12, 13, 13, 13, 13, 15, 18, 21, + 23, 24, 25, 25, 28, 31, 33, 34, 34, 32, 31, 31, 31, 30, 27, 22, + 16, 12, 10, 9, 7, 3, -5, -13, -19, -22, -22, -23, -25, -28, -31, -33, + -33, -32, -32, -31, -32, -33, -32, -29, -25, -21, -19, -19, -19, -19, -18, -15, + -9, -3, 2, 6, 9, 12, 16, 21, 27, 32, 37, 39, 40, 40, 39, 39, + 40, 41, 40, 38, 35, 34, 34, 33, 29, 22, 16, 11, 10, 11, 12, 12, + 10, 8, 7, 5, 3, 2, 0, -6, -12, -19, -23, -23, -22, -23, -26, -30, + -33, -33, -33, -34, -35, -37, -40, -45, -50, -53, -52, -48, -42, -37, -32, -27, + -22, -20, -18, -16, -16, -18, -21, -26, -30, -33, -34, -35, -36, -38, -40, -41, + -41, -38, -36, -36, -38, -41, -40, -38, -34, -30, -27, -25, -22, -20, -16, -15, + -16, -17, -18, -16, -13, -10, -7, -4, -2, 1, 6, 11, 16, 21, 24, 25, + 26, 24, 22, 19, 18, 19, 22, 24, 26, 30, 33, 38, 44, 50, 56, 61, + 63, 68, 72, 74, 73, 68, 64, 57, 50, 47, 46, 44, 37, 21, 3, -11, + -20, -23, -25, -30, -33, -36, -36, -34, -31, -27, -22, -21, -22, -21, -18, -21, + -24, -27, -31, -33, -32, -27, -21, -14, -13, -17, -17, -10, 0, 10, 15, 16, + 14, 8, 6, 10, 16, 25, 34, 39, 43, 47, 53, 62, 72, 82, 89, 92, + 90, 84, 79, 77, 77, 76, 67, 54, 42, 33, 26, 18, 5, -11, -27, -41, + -53, -65, -73, -77, -79, -81, -86, -93, -102, -110, -116, -118, -120, -124, -127, -128, + -128, -126, -122, -116, -107, -96, -85, -78, -72, -64, -54, -45, -39, -40, -46, -49, + -49, -47, -45, -44, -45, -45, -44, -42, -38, -33, -29, -26, -23, -20, -18, -14, + -11, -8, -5, -2, 2, 7, 11, 10, 8, 7, 9, 16, 22, 26, 28, 31, + 34, 39, 44, 49, 53, 57, 60, 62, 63, 63, 65, 66, 63, 57, 51, 46, + 46, 50, 53, 54, 55, 54, 55, 57, 63, 69, 73, 75, 73, 69, 66, 64, + 65, 63, 55, 43, 30, 18, 11, 3, -6, -15, -23, -29, -32, -32, -28, -22, + -16, -13, -16, -16, -11, -2, 9, 15, 1, 0, 0, 0, -1, 0, -3, 0, + -1, 0, -18, 21, -22, 23, -41, 20, 84, -39, 50, -61, 26, -126, -19, -37, + 15, 2, 70, -33, 127, -55, 117, -73, 15, -45, -50, 8, -11, 23, 33, 1, + 26, -67, 26, -25, 14, -45, 57, -124, 12, -4, -23, 107, -54, 127, -49, 43, + 27, -59, -30, 15, -128, 5, -128, 86, -39, 82, 12, 62, 9, 51, -59, 53, + -95, 67, -92, 68, -28, 94, 21, 47, -11, -1, -41, 0, -25, -9, 18, -68, + 15, -27, 49, -27, 103, -4, 3, -36, 58, -98, 56, -116, -31, -123, 25, -58, + 89, -21, 110, -25, 73, -28, 39, -21, 35, -40, 37, -20, 50, 55, 51, 6, + 1, -47, -11, -32, -23, 38, -67, 3, -54, 34, -55, 79, 1, 32, -61, 89, + -86, 53, -67, -10, -128, -6, -68, 51, -4, 82, 15, 83, -16, 63, -24, 55, + -29, 8, 0, 6, 11, 54, 14, 16, -39, -9, -12, -47, 37, -40, -22, -60, + 21, -76, 51, -17, 74, -63, 98, -36, 44, -33, 24, -113, -37, -89, 20, -30, + 67, 18, 87, 0, 67, -6, 38, 1, -2, -18, -5, -20, 32, 17, 21, -8, + -30, 15, -47, 11, -17, 11, -97, 43, -87, 27, -36, 91, -41, 66, 3, 44, + -28, 55, -74, -37, -92, -21, -37, 33, -1, 75, 22, 36, 14, 26, 8, 8, + -12, -7, -21, -1, 27, 11, 21, -30, 21, -37, -3, -13, 23, -27, -32, -10, + -23, -44, 56, -1, 43, -12, 76, -29, 48, -9, -25, -71, -70, -48, -20, 2, + 9, 56, 8, 56, -10, 52, -12, 31, -29, 27, -60, 62, -42, 83, -45, 30, + -24, 4, -26, 33, -23, 5, -18, -25, -53, -7, -6, -6, 19, 16, 31, 3, + 58, -14, 0, -64, -33, -58, -8, -43, 42, -18, 57, -9, 54, 1, 47, -3, + 36, -18, 3, 4, 6, 2, -17, 8, -14, -27, 35, 2, -3, 1, -8, -43, + -34, -1, -22, 12, 2, 37, -6, 53, 14, 16, -43, -22, -75, -2, -67, 23, + -24, 39, -3, 39, 6, 44, 9, 37, 5, 1, 3, 5, 12, -18, 0, 0, + -31, 5, 23, 1, -3, 10, -20, -48, -6, -30, 7, -18, 35, -4, 32, 21, + 39, -26, -1, -75, -9, -65, -3, -28, 20, -5, 32, 5, 36, 20, 30, 30, + 3, 10, -1, 16, -10, -7, -1, -17, -23, 18, 14, -3, 8, 9, -45, -14, + -35, -1, -27, 18, -2, 29, 1, 61, -14, 20, -56, -19, -51, -22, -38, 9, + -14, 22, 5, 24, 27, 23, 41, 13, 20, -7, 23, -2, -8, -2, -9, -26, + -6, 14, 11, -11, 37, -33, -12, -38, -6, -33, 7, -14, 30, -12, 55, 4, + 33, -32, -14, -45, -22, -43, -7, -15, 18, 18, 33, 17, 41, 22, 15, 14, + 8, -24, -16, -18, -16, -7, 6, 16, -2, 8, -14, -6, -23, 0, -22, 1, + -23, 21, 4, 24, -1, 9, -9, -11, -14, -13, -16, -14, -15, -12, -16, -5, + 8, 28, 25, 28, 34, 27, 15, 16, 2, -20, -22, -20, -15, -8, 10, 11, + 7, -3, -5, -16, -10, -13, -5, -16, -5, 4, 17, 13, 6, 1, -9, -1, + -2, -3, -4, -4, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -6, + -6, -6, -6, -6, -5, -3, -3, -5, -5, -5, -7, -8, -5, 4, 5, 13, + 12, -12, -5, 10, 5, 4, 0, 3, 26, 33, 10, -15, -69, -89, -25, 25, + 58, 70, 22, -41, -62, -31, 18, 17, -17, -12, -9, 20, 99, 96, 0, -88, + -123, -69, 61, 116, 54, -11, -45, -28, 40, 38, -42, -59, -53, -31, 63, 78, + -9, -65, -83, -59, 48, 110, 50, -11, -51, -54, 41, 96, 9, -87, -119, -77, + 42, 118, 67, -18, -57, -46, 24, 89, 81, 22, -43, -77, -65, -41, -23, -3, + 4, 8, -13, -54, -52, -21, 30, 89, 86, 8, -49, -76, -56, 30, 55, 52, + 47, -7, -45, -49, -48, -10, 68, 74, 43, 22, -27, -25, 12, 20, -5, -43, + -69, -46, 21, 53, 51, 38, -8, -32, 6, 20, -1, -19, -56, -67, -26, 27, + 76, 95, 23, -64, -60, -15, 33, 39, -8, -37, -24, -7, 7, 4, -25, -23, + -10, -14, -7, -5, -12, 2, 28, 31, 37, 21, -18, -16, -4, -22, -37, -46, + -56, -8, 58, 64, 53, 31, -9, -9, -2, -57, -85, -52, -13, 59, 92, 21, + -42, -47, -33, 27, 75, 27, -22, -38, -44, 18, 77, 32, -21, -46, -50, 34, + 89, 22, -37, -60, -56, 31, 95, 36, -27, -57, -82, -15, 53, 15, -13, -25, + -44, 14, 66, 14, -32, -53, -62, 25, 96, 50, 3, -32, -56, 25, 98, 51, + -9, -56, -78, 7, 92, 71, 28, -31, -92, -42, 28, 20, 24, 8, -34, 22, + 70, 18, -17, -53, -88, -20, 39, 7, -2, -8, -28, 35, 80, 19, -23, -55, + -93, -22, 63, 54, 47, 19, -52, -35, 2, -36, -32, -18, -49, -9, 41, 15, + 26, 34, -22, -6, 31, 1, 8, 9, -43, -15, 30, -3, -1, -7, -73, -48, + 6, -14, 5, 13, -47, -30, 12, -13, 6, 18, -37, -13, 39, 27, 45, 38, + -37, -32, 12, 3, 32, 46, -10, 6, 48, 16, 15, 15, -32, -2, 47, 24, + 26, 18, -51, -51, -15, -29, -1, 19, -28, -15, 21, 2, 18, 22, -34, -24, + 13, -3, 15, 14, -45, -34, 7, 10, 38, 31, -34, -30, 4, 5, 43, 61, + 13, 4, 6, -22, 4, 24, -13, -13, -10, -34, 0, 23, -16, -16, -13, -42, + -18, -4, -36, -17, 5, -10, 14, 22, -21, -22, -16, -37, -6, 20, -2, 17, + 36, 19, 43, 43, -9, -15, -12, -29, 6, 31, 6, 10, 7, -23, -2, 9, + -23, -15, -10, -26, 3, 20, -5, 1, 0, -22, 5, 22, -6, -8, -16, -37, + -5, 20, 2, 11, 6, -19, 11, 33, 12, 20, 16, -7, 20, 35, 11, 11, + -3, -28, 2, 19, -1, 3, -6, -29, -5, 2, -25, -17, -12, -16, 22, 34, + 3, -4, -21, -36, 4, 26, 8, -1, -30, -54, -23, -3, -11, 0, -12, -27, + 7, 24, 13, 19, -1, -21, 10, 27, 14, 17, 0, -14, 18, 33, 19, 14, + -17, -41, -10, 9, 2, 7, -14, -30, 4, 20, 9, 9, -15, -35, -3, 16, + 9, 0, -1, -2, -3, 4, 7, 4, -2, -3, 0, 3, -1, -1, 4, 5, + -2, -13, -9, 1, 4, 2, 1, 2, 2, -2, -8, -4, 0, 4, 4, -3, + -4, -3, 1, 2, -1, 3, 14, 1, -7, -12, -4, -2, 1, 1, 9, 5, + -6, -5, -2, -1, -1, 1, 14, 6, -6, -7, 3, 8, -2, -4, 13, 12, + -10, -17, -10, -5, -4, 2, 3, 7, -6, -6, -1, -1, -4, 1, 11, 6, + -6, -9, 10, 11, 3, 1, 14, 15, -12, -20, -12, -9, -15, -1, 7, 2, + -16, -7, 6, 0, -2, 10, 26, 17, -6, -11, 24, 21, 1, 0, 18, 15, + -17, -31, -28, -23, -14, 0, -4, 0, -16, -8, 8, -4, -3, 7, 15, 5, + -3, -3, 26, 25, 12, 8, 28, 17, -15, -28, -18, -17, -18, -7, -3, -7, + -20, 0, 7, 1, -9, 6, 9, -4, -9, 2, 15, 24, 34, 31, 10, -4, + -15, -29, -17, -21, -41, -40, -5, 19, -20, 3, 11, 33, 28, 21, 18, 15, + 16, 3, -1, 18, 17, 15, 1, -15, -10, -5, -14, -42, -48, -43, -26, 4, + -29, -14, -9, 32, 20, 12, 15, 21, 39, 24, 8, 26, 33, 6, -3, 0, + 1, -7, -16, -41, -44, -51, -34, -3, -6, -6, -19, 26, 10, 15, 35, 46, + 32, 20, 16, 23, 38, 15, -4, -10, 17, -6, -41, -48, -53, -70, -52, -9, + -9, -22, -15, 19, 24, 22, 30, 49, 34, 10, 1, 15, 33, 15, 1, 17, + 46, 12, -38, -59, -50, -57, -46, -13, -16, -30, -24, 26, 37, 33, 30, 45, + 40, 2, -11, 17, 41, 24, -4, 16, 48, 15, -38, -67, -64, -65, -46, -18, + -18, -35, -32, 35, 39, 37, 21, 45, 42, -2, -19, 14, 37, 22, 7, 24, + 40, 13, -42, -68, -63, -63, -38, -6, -12, -34, -25, 39, 43, 39, 17, 47, + 45, 3, -19, 21, 45, 25, 2, 21, 31, 0, -45, -71, -78, -83, -48, 2, + 7, -27, -32, 34, 45, 49, 23, 44, 36, 5, -5, 38, 60, 27, -13, 21, + 42, -13, -69, -81, -86, -79, -38, -9, -11, -41, -36, 38, 56, 45, 10, 43, + 43, 10, -6, 36, 57, 41, 10, 36, 46, -16, -67, -66, -71, -80, -44, -8, + -5, -29, -27, 30, 43, 46, 20, 52, 39, -9, -21, 40, 68, 42, -1, 20, + 32, -14, -70, -86, -94, -90, -45, -2, 0, -31, -17, 36, 47, 46, 18, 44, + 29, -2, -11, 46, 74, 51, 14, 36, 46, -15, -78, -87, -91, -89, -46, -12, + -11, -28, -5, 41, 46, 40, 17, 51, 33, -6, -13, 49, 75, 52, 15, 30, + 34, -21, -79, -88, -93, -88, -42, -9, -4, -25, -3, 36, 40, 34, 16, 44, + 23, -8, -10, 52, 83, 55, 17, 38, 31, -31, -82, -91, -93, -82, -39, -16, + -10, -25, 5, 33, 42, 32, 20, 54, 25, -9, -3, 59, 85, 63, 24, 37, + 24, -39, -86, -92, -97, -80, -34, -17, -15, -24, 10, 35, 45, 32, 16, 45, + 12, -23, -2, 62, 78, 53, 21, 37, 26, -39, -91, -95, -96, -77, -29, -16, + -16, -25, 10, -1, 0, 3, 21, -26, 18, -30, 32, -19, -15, -27, 2, 0, + 103, -84, -53, -52, 79, 51, 36, -69, -31, 48, 71, 33, -74, -64, 10, 51, + 49, -68, -91, -16, 30, 33, -31, -58, -42, 14, 24, -25, 23, -71, 79, -22, + 123, -74, 28, 28, 115, 99, -7, 9, -15, 72, 1, 16, -47, -5, -71, -18, + -75, -26, -71, -28, -56, -24, -57, -19, -33, -5, 7, -3, 14, -8, 82, 100, + 23, -32, -15, 80, 98, 68, -30, -21, 24, 71, 28, -41, -96, -22, 32, 37, + -57, -110, -67, 28, 35, -22, -112, -79, 13, 70, 27, -55, -63, 31, 95, 86, + -4, -40, 29, 110, 110, 28, -50, -12, 66, 80, 14, -87, -81, -7, 36, -5, + -95, -118, -42, 26, 8, -69, -121, -48, 37, 60, -6, -68, -29, 67, 104, 61, + -24, -17, 70, 123, 92, -5, -43, 23, 82, 67, -28, -96, -54, 18, 30, -39, + -115, -96, -7, 25, -13, -99, -101, -13, 52, 42, -35, -62, 9, 88, 93, 28, + -32, 15, 97, 118, 58, -29, -24, 51, 82, 39, -61, -88, -26, 28, 9, -70, + -117, -63, 7, 14, -46, -109, -71, 15, 55, 16, -51, -42, 43, 94, 75, 2, + -21, 48, 107, 101, 23, -36, 4, 65, 70, 1, -81, -69, -3, 26, -19, -94, + -106, -32, 14, -3, -74, -103, -37, 34, 46, -10, -56, -12, 66, 91, 49, -15, + 1, 74, 111, 76, -4, -28, 31, 72, 50, -33, -85, -43, 11, 15, -46, -106, + -80, -11, 13, -26, -92, -84, -8, 44, 29, -30, -48, 19, 80, 81, 26, -18, + 27, 91, 103, 49, -22, -10, 48, 68, 22, -60, -75, -22, 17, -5, -71, -105, + -54, 3, 3, -49, -98, -58, 14, 44, 11, -44, -27, 45, 85, 65, 5, -8, + 53, 100, 87, 21, -26, 11, 60, 56, -6, -74, -58, -4, 13, -25, -90, -91, + -29, 7, -12, -72, -90, -29, 32, 37, -10, -46, -2, 66, 83, 47, -8, 10, + 74, 101, 68, -3, -19, 31, 62, 38, -36, -77, -40, 6, 4, -49, -100, -72, + -12, 3, -31, -86, -73, -4, 37, 25, -28, -36, 25, 75, 74, 25, -9, 34, + 88, 94, 43, -16, -4, 47, 58, 15, -57, -69, -22, 6, -12, -73, -96, -50, + -4, -7, -53, -89, -49, 13, 36, 5, -37, -17, 47, 77, 59, 9, 2, 58, + 92, 79, 19, -17, 16, 54, 45, -13, -69, -52, -8, 3, -33, -85, -82, -29, + -2, -20, -68, -79, -23, 24, 29, -11, -34, 7, 61, 73, 41, 0, 22, 73, + 90, 58, 1, -9, 32, 52, 26, -36, -69, -35, -3, -7, -53, -90, -63, -16, + -7, -36, -78, -60, -4, 29, 16, -22, -23, 29, 68, 64, 26, 2, 42, 80, + 81, 38, -8, 5, 42, 44, 4, -53, -57, -21, -2, -22, -69, -83, -43, -10, + -15, -51, -77, -38, 11, 27, 3, -27, -5, 46, 68, 52, 13, 15, 58, 83, + 68, 19, -8, 21, 46, 32, -16, -60, -44, -12, -6, -36, -76, -74, -34, -10, + -20, -57, -73, -33, 12, 27, 3, -1, -6, -11, -3, 4, 0, -7, -8, 1, + 21, 14, 28, 33, 25, -1, 7, 4, -13, -21, -44, -29, -17, -31, -32, 2, + 0, -20, 4, 3, 4, 0, -2, -5, -4, -14, 3, 14, 9, 28, 34, 54, + 43, 54, 39, 19, 17, -1, 5, -23, -31, -25, -35, -46, -60, -29, -29, -13, + -37, -22, -16, -20, -27, -21, -6, -16, 8, -5, 15, 26, 69, 65, 74, 85, + 81, 76, 51, 22, -10, -10, -19, -3, -39, -73, -55, -36, -18, -45, -49, -45, + -52, -47, -74, -73, -56, -31, -15, -16, -5, 18, 65, 86, 108, 94, 97, 90, + 79, 54, 30, 19, 10, 25, -16, -34, -37, -9, -16, -35, -44, -60, -60, -50, + -62, -70, -66, -44, -34, -34, -29, -10, 23, 61, 85, 79, 75, 70, 61, 41, + 31, 7, 8, 3, -22, -42, -28, 0, -13, -29, -39, -52, -56, -55, -58, -60, + -57, -41, -35, -37, -19, 5, 35, 71, 87, 85, 97, 112, 97, 71, 56, 52, + 53, 43, 18, -7, -3, 10, 0, -17, -39, -55, -58, -64, -80, -106, -121, -112, + -110, -113, -105, -82, -51, -8, 16, 20, 45, 66, 66, 49, 46, 59, 75, 78, + 63, 62, 74, 80, 80, 69, 51, 27, 11, 0, -14, -40, -53, -48, -55, -68, + -71, -56, -34, -1, 14, 24, 49, 62, 59, 42, 34, 43, 47, 43, 26, 30, + 33, 38, 26, 4, -17, -41, -66, -81, -92, -112, -120, -115, -116, -128, -125, -103, + -71, -36, -11, 9, 33, 56, 59, 54, 61, 67, 77, 77, 77, 79, 74, 75, + 73, 55, 30, 10, -21, -38, -46, -61, -70, -67, -70, -81, -77, -64, -45, -23, + -4, 10, 30, 44, 44, 39, 42, 48, 51, 50, 51, 58, 58, 65, 65, 47, + 29, 12, -14, -31, -41, -53, -63, -60, -62, -64, -58, -44, -26, -11, 1, 10, + 20, 22, 17, 9, 5, 6, 6, 2, 4, 10, 10, 17, 19, 9, 7, -1, + -14, -18, -13, -14, -9, 1, 7, 12, 17, 23, 31, 35, 36, 35, 38, 31, + 21, 16, 3, 0, -8, -11, -11, -13, -19, -20, -23, -34, -39, -51, -69, -78, + -81, -83, -83, -78, -70, -60, -47, -34, -19, 2, 20, 39, 57, 60, 66, 67, + 63, 61, 53, 50, 51, 47, 37, 32, 23, 13, 6, -3, -17, -23, -28, -34, + -37, -35, -27, -15, -2, 4, 12, 23, 30, 44, 47, 43, 41, 35, 29, 22, + 15, 13, 14, 7, -1, -5, -11, -19, -20, -25, -37, -43, -41, -43, -47, -47, + -40, -29, -17, -7, 5, 13, 23, 38, 44, 37, 34, 31, 23, 17, 6, 1, + -2, -10, -20, -25, -35, -45, -50, -54, -64, -68, -65, -66, -65, -59, -47, -30, + -19, -7, 5, 14, 28, 48, 62, 66, 72, 75, 78, 76, 67, 60, 56, 46, + 32, 20, 9, -2, -10, -21, -35, -43, -44, -49, -56, -57, -51, -38, -25, -13, + -2, 9, 25, 42, 56, 59, 64, 65, 67, 65, 57, 52, 49, 41, 28, 18, + 8, -2, -10, 0, 8, 13, 21, 20, 20, 17, 10, 8, -2, -6, -17, -21, + -29, -23, -25, -14, -7, -2, 7, 10, 20, 21, 22, 23, 19, 14, 9, -2, + -6, -18, -20, -28, -25, -23, -18, -10, -3, 5, 9, 22, 17, 28, 22, 21, + 17, 11, 2, -8, -18, -23, -27, -26, -24, -19, -13, -6, 3, 9, 17, 20, + 28, 24, 25, 21, 13, 6, -5, -14, -21, -29, -29, -30, -23, -19, -7, -1, + 10, 18, 25, 29, 27, 28, 20, 17, 5, -7, -13, -26, -29, -30, -30, -27, + -20, -12, 0, 11, 19, 25, 27, 30, 26, 28, 19, 11, -2, -12, -24, -30, + -35, -34, -30, -24, -14, -2, 9, 18, 23, 28, 26, 33, 31, 29, 24, 12, + 5, -12, -23, -30, -37, -36, -36, -26, -19, -5, 5, 19, 22, 32, 32, 36, + 35, 26, 21, 3, -6, -22, -34, -41, -44, -38, -31, -18, -6, 6, 15, 23, + 32, 33, 39, 34, 31, 23, 10, -2, -21, -32, -44, -47, -45, -37, -23, -12, + 6, 13, 28, 30, 38, 40, 40, 38, 23, 17, -6, -15, -35, -42, -50, -49, + -41, -31, -14, 0, 14, 26, 35, 42, 45, 45, 40, 27, 18, -4, -14, -33, + -42, -54, -52, -47, -36, -21, -5, 13, 24, 39, 43, 52, 47, 42, 36, 20, + 7, -15, -32, -45, -55, -56, -54, -43, -27, -8, 12, 26, 38, 45, 50, 51, + 48, 40, 27, 9, -11, -30, -46, -58, -62, -58, -49, -31, -11, 9, 24, 41, + 45, 54, 53, 54, 45, 30, 14, -10, -27, -48, -58, -67, -64, -56, -35, -15, + 6, 24, 37, 45, 54, 56, 56, 49, 39, 18, 0, -26, -45, -60, -74, -70, + -63, -41, -23, 4, 21, 39, 48, 53, 61, 58, 59, 43, 29, 3, -20, -46, + -64, -77, -77, -69, -50, -27, 0, 20, 36, 49, 56, 64, 64, 63, 51, 34, + 6, -17, -46, -65, -79, -83, -76, -58, -33, -6, 17, 38, 49, 60, 67, 68, + 66, 53, 37, 13, -13, -38, -65, -79, -90, -82, -68, -41, -15, 14, 36, 52, + 63, 70, 73, 69, 62, 44, 19, -8, -38, -63, -83, -93, -90, -77, -49, -20, + 12, 34, 54, 65, 72, 75, 76, 65, 51, 26, -1, -33, -62, -86, -98, -96, + -86, -58, -29, 6, 32, 54, 66, 73, 79, 76, 73, 58, 36, 4, -27, -60, + -85, -101, -104, -92, -70, -36, -1, 31, 53, 70, 75, 81, 80, 78, 65, 41, + 15, -24, -56, -84, -105, -109, -101, -79, -46, -7, 25, 56, 65, 77, 82, 85, + 83, 69, 51, 19, -14, -50, -83, -103, -115, -107, -88, -55, -17, 21, 50, 67, + 81, 86, 89, 85, 79, 55, 28, -8, -46, -77, -103, -116, -117, -97, -67, -25, + 1, 39, 66, 81, 92, 96, 97, 90, 73, 45, 11, -27, -64, -97, -120, -128, + -117, -89, -49, -5, 35, 65, 81, 93, 98, 99, 91, 75, 46, 12, -27, 28, + -9, -42, -57, -50, -18, 33, 77, 77, 17, -64, -96, -55, 22, 73, 68, 17, + -43, -77, -67, -15, 59, 102, 79, 12, -48, -71, -57, -28, -3, 11, 10, -3, + -17, -4, 44, 88, 79, 10, -69, -103, -74, -6, 54, 75, 53, -4, -63, -80, + -38, 32, 73, 59, 7, -43, -67, -57, -18, 33, 71, 71, 24, -31, -47, -17, + 20, 23, -14, -58, -73, -47, 10, 73, 110, 93, 20, -62, -97, -68, -6, 43, + 54, 28, -13, -51, -65, -35, 26, 74, 69, 12, -50, -68, -37, 9, 37, 37, + 16, -12, -26, -7, 36, 65, 45, -19, -87, -112, -75, -7, 58, 97, 92, 41, + -30, -75, -62, -3, 49, 52, 7, -44, -63, -45, -6, 37, 60, 42, -5, -42, + -41, -3, 38, 41, 8, -33, -51, -38, 3, 54, 90, 79, 12, -76, -127, -106, + -29, 47, 78, 63, 23, -19, -36, -16, 24, 50, 35, -15, -59, -64, -27, 17, + 40, 35, 11, -20, -39, -26, 19, 63, 67, 14, -61, -97, -72, -5, 64, 101, + 87, 26, -49, -96, -86, -32, 24, 40, 17, -11, -17, -3, 24, 51, 55, 29, + -20, -66, -69, -23, 35, 55, 25, -26, -59, -55, -14, 44, 86, 80, 23, -56, + -105, -87, -19, 48, 79, 67, 27, -18, -46, -43, -14, 17, 16, -20, -54, -47, + 3, 59, 83, 66, 18, -35, -64, -54, -8, 44, 59, 18, -48, -87, -72, -16, + 49, 88, 84, 37, -31, -81, -79, -26, 33, 52, 29, -5, -19, -6, 20, 34, + 27, -5, -51, -84, -71, -9, 62, 95, 71, 12, -40, -58, -37, 8, 52, 63, + 22, -53, -103, -88, -23, 47, 80, 64, 24, -14, -33, -28, -3, 21, 18, -15, + -45, -39, 5, 57, 78, 54, -1, -60, -97, -89, -29, 50, 92, 67, 0, -53, + -57, -13, 38, 64, 52, 10, -44, -82, -76, -26, 28, 49, 32, 1, -14, -1, + 24, 40, 38, 9, -43, -87, -79, -13, 69, 110, 80, 4, -65, -90, -69, -21, + 32, 58, 39, -9, -48, -45, 0, 52, 69, 46, 5, -34, -57, -50, -14, 23, + 28, -8, -48, -48, 4, 71, 99, 69, 3, -63, -99, -88, -30, 46, 92, 78, + 16, -45, -66, -44, -6, 25, 34, 16, -24, -55, -43, 10, 67, 80, 37, -22, + -48, -29, 7, 30, 27, -5, -51, -84, -73, -11, 71, 116, 95, 27, -43, -84, + -84, -43, 18, 63, 60, 10, -44, -53, -9, 41, 49, 14, -31, -57, -50, -15, + 29, 61, 57, 14, -37, -51, -14, 38, 63, 47, -1, -61, -106, -105, -47, 44, + 115, 113, 42, -36, -64, -42, -2, 23, 20, -3, -28, -39, -21, 24, 64, 59, + 7, -48, -67, -47, -7, 36, 59, 47, 2, -55, -77, -31, 55, 111, 89, 7, + -75, -113, -96, -42, 21, 62, 64, 28, -13, -18, 17, 45, 28, -2, -7, -6, + -7, -7, -8, -8, -8, -8, -7, -6, -5, -4, -3, -3, -2, -2, -1, 0, + 1, 2, 4, 5, 6, 8, 9, 10, 11, 12, 13, 13, 14, 15, 16, 17, + 17, 17, 17, 17, 16, 16, 15, 15, 14, 14, 13, 12, 10, 10, 9, 8, + 7, 6, 5, 5, 4, 3, 2, 1, 0, -2, -3, -4, -5, -6, -7, -8, + -9, -10, -11, -12, -13, -13, -14, -14, -14, -14, -14, -15, -15, -15, -15, -16, + -16, -14, -14, -12, -10, -13, -10, -13, -7, -3, -5, -1, -1, -5, -5, 8, + 13, 10, 10, 15, 16, 17, 30, 34, 19, 17, 22, 29, 27, 22, 16, 1, + -3, 8, 18, 11, 6, 8, 8, 1, 6, 18, 5, -8, -4, 4, 5, 3, + 5, -3, -6, 12, 30, 23, 9, 5, 6, 9, 15, 27, 20, 2, 0, 10, + 17, 8, -1, -4, -8, -8, -3, -7, -19, -28, -24, -22, -31, -42, -47, -50, + -50, -42, -35, -35, -43, -41, -31, -27, -23, -17, -9, -7, 3, 26, 37, 38, + 37, 41, 39, 39, 49, 55, 50, 46, 53, 58, 51, 44, 36, 24, 9, 5, + 2, -12, -25, -28, -26, -33, -42, -44, -55, -66, -69, -62, -60, -65, -57, -42, + -33, -26, -15, -5, -6, 0, 15, 29, 34, 41, 55, 61, 62, 68, 71, 62, + 49, 49, 49, 39, 29, 24, 14, -2, -10, -16, -34, -56, -67, -70, -77, -83, + -85, -88, -93, -92, -79, -74, -78, -74, -61, -49, -41, -23, -9, -2, 11, 35, + 54, 56, 58, 64, 69, 73, 81, 91, 86, 77, 78, 77, 67, 50, 39, 24, + 6, -4, -10, -22, -41, -49, -52, -62, -73, -81, -87, -98, -97, -83, -74, -70, + -63, -46, -33, -23, -6, 9, 18, 26, 48, 69, 77, 85, 97, 106, 107, 111, + 114, 104, 89, 83, 84, 75, 60, 50, 34, 13, -5, -16, -34, -59, -74, -80, + -86, -95, -97, -96, -104, -104, -95, -86, -86, -82, -66, -49, -32, -11, 12, 26, + 36, 55, 73, 81, 84, 94, 104, 107, 114, 120, 116, 102, 92, 88, 73, 54, + 37, 21, 0, -16, -23, -37, -58, -76, -85, -94, -108, -114, -116, -120, -119, -106, + -89, -84, -78, -64, -49, -37, -21, 1, 13, 25, 46, 71, 88, 95, 105, 113, + 112, 113, 116, 112, 97, 91, 91, 83, 68, 51, 35, 11, -10, -23, -38, -60, + -80, -86, -93, -102, -107, -110, -116, -121, -114, -102, -98, -93, -77, -55, -38, -18, + 1, 13, 25, 46, 71, 88, 95, 105, 113, 112, 113, 116, 112, 97, 91, 91, + 83, 68, 51, 35, 11, -10, -23, -38, -60, -80, -86, -93, -102, -107, -110, -116, + -121, -114, -102, -98, -93, -77, -55, -38, -18, 1, -3, -7, -8, -3, 1, 0, + 3, -5, -9, -14, -15, -4, 0, 7, 12, 12, 11, 18, 16, 14, 14, 11, + 20, 14, 19, 7, 12, 8, 13, 8, 7, 9, 0, 9, -7, -4, -5, -8, + -7, -9, -7, -2, -7, -4, 1, 1, 0, -2, 3, 2, 1, 2, 1, -2, + -3, -7, -2, -2, -2, -5, -4, -4, -4, 3, 6, 8, 3, 0, -3, -2, + 3, 4, 3, 2, 2, -2, 1, 0, 2, 3, 9, 8, 2, -3, -4, -2, + 1, 4, 0, -2, 3, 1, 7, 1, -4, 0, 2, 3, 1, 1, 2, -5, + 3, -3, -4, -3, -8, 2, -7, 1, -3, -2, -5, -8, -7, -8, -7, -5, + -7, -4, -8, -10, -7, -8, -7, -5, 0, -2, 0, -2, -3, -3, -2, 0, + 1, 0, 1, 0, -3, -3, -5, -5, -9, -9, -13, -16, -21, -26, -25, -25, + -16, -16, -12, -13, -15, -9, 3, 25, 44, 66, 68, 66, 49, 17, 13, 18, + 41, 51, 40, 35, 25, 23, -2, -16, -28, -8, -4, -12, -18, -34, -29, -31, + -28, -18, -4, 2, 16, 13, 20, 9, 4, 2, -3, -4, -9, -9, -9, -8, + -9, -10, -13, -14, -15, -13, -4, 7, 13, 19, 18, 16, 9, 7, 4, 6, + 8, 7, 7, 3, -3, -15, -19, -24, -21, -16, -9, 0, 3, 7, 4, 4, + -3, -2, 6, 13, 20, 14, 16, 14, 11, 7, 0, -4, -3, -3, -7, -12, + -12, -9, -5, -5, -7, -9, -4, -2, -2, -2, -4, -9, -10, -13, -13, -14, + -15, -13, -9, -8, -9, -9, -7, -4, 2, 2, 6, 9, 8, 11, 9, 11, + 9, 8, 6, 0, -7, -13, -21, -29, -36, -45, -53, -63, -72, -73, -61, -41, + 0, 52, 98, 109, 81, 64, 54, 78, 77, 45, 39, 44, 25, 19, 6, -8, + 25, 30, 44, 62, 46, -20, -85, -89, -88, -47, -29, -30, 2, 11, 8, 12, + 24, 33, 29, 25, 22, 1, -15, -34, -37, -36, -41, -36, -28, -15, 2, 9, + 11, 14, 12, 8, 12, 17, 18, 19, 23, 20, 20, 20, 8, -5, -14, -15, + -15, -13, -13, -18, -19, -24, -29, -32, -31, -23, -12, -2, 12, 20, 23, 24, + 25, 20, 22, 18, 16, 14, 9, 7, 2, 1, -9, -10, -19, -15, -12, -13, + -8, -5, -4, -4, -7, -10, -12, -12, -16, -14, -8, -9, -13, -14, -18, -15, + -10, -5, -3, 3, 4, 6, 11, 13, 13, 16, 16, 16, 12, 6, -3, -10, + -16, -21, -28, -37, -48, -61, -77, -88, -87, -68, -34, 28, 92, 127, 99, 64, + 50, 72, 92, 55, 43, 51, 41, 32, 4, -8, -7, -17, -23, -31, -33, -35, + -32, -28, -23, -18, -12, -8, -4, -2, 0, 1, 2, 2, 3, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 3, 4, 6, 7, 7, 7, 8, 9, 9, 8, + 8, 9, 11, 14, 18, 22, 27, 32, 33, 30, 21, 6, -12, -30, -45, -54, + -56, -51, -41, -29, -17, -9, -3, 0, 1, 1, 1, 1, 1, 1, 1, 2, + 2, 3, 3, 3, 3, 3, 2, 3, 4, 5, 8, 9, 10, 9, 8, 7, + 7, 8, 10, 15, 20, 25, 30, 35, 39, 39, 32, 19, 0, -22, -42, -56, + -62, -61, -53, -40, -27, -15, -7, -3, -1, 0, 0, 0, 0, 2, 3, 4, + 5, 5, 5, 4, 2, 0, -1, 0, 2, 5, 8, 9, 10, 10, 9, 9, + 8, 9, 10, 14, 19, 24, 28, 32, 34, 38, 36, 29, 17, -5, -28, -49, + -61, -65, -61, -52, -39, -25, -14, -7, -3, -2, -1, -2, -1, 0, 2, 4, + 6, 7, 7, 5, 3, 0, -1, -1, 0, 3, 7, 11, 13, 14, 13, 12, + 10, 8, 8, 9, 12, 17, 22, 26, 29, 31, 33, 31, 26, 18, 3, -16, + -35, -50, -59, -61, -56, -46, -35, -23, -14, -6, -2, 0, 1, 2, 3, 4, + 4, 5, 5, 5, 4, 2, 1, -1, -1, 0, 2, 5, 9, 12, 13, 13, + 12, 11, 9, 7, 7, 8, 11, 15, 20, 24, 29, 33, 35, 34, 30, 21, + 4, -16, -37, -55, -66, -68, -63, -50, -35, -21, -9, -1, 4, 5, 5, 4, + 4, 3, 3, 3, 3, 2, 2, 1, 0, -1, -1, 1, 6, 10, 13, 15, + 15, 13, 11, 8, 5, 4, 4, 7, 11, 17, 22, 27, 32, 36, 39, 39, + 36, 24, 6, -20, -48, -70, -81, -79, -67, -48, -29, -12, -1, 5, 7, 7, + 4, 2, 1, 1, 2, 2, 3, 2, 2, -1, -2, -3, -3, -1, 3, 8, + 13, 16, 17, 16, 12, 8, 3, -1, -3, -2, 2, 11, 21, 29, 36, 38, + 39, 42, 48, 57, 52, 23, -27, -76, -107, -113, -98, -71, -42, -18, -1, 8, + 12, 13, 10, 7, 3, 1, 1, 2, 3, 2, 1, 0, -2, -3, -3, -1, + 2, 8, 13, 17, 18, 17, 12, 7, 1, -3, -4, -3, 20, 30, 38, 41, + 39, 38, 46, 65, 75, 45, -23, -89, -126, -127, -101, -64, -31, -7, 5, 11, + 13, 14, 13, 9, 4, 1, 0, 1, 2, 1, -1, -3, -4, -4, -2, 2, + 6, 10, 14, 18, 18, 15, 9, 1, -6, -10, -13, -10, -4, 7, 20, 0, + 14, 19, 23, 26, 28, 28, 26, 23, 18, 11, 3, -4, -10, -16, -21, -23, + -24, -22, -20, -16, -12, -8, -3, 3, 8, 13, 19, 23, 26, 27, 26, 23, + 17, 10, 4, -3, -9, -15, -20, -24, -25, -25, -22, -17, -11, -3, 3, 9, + 14, 18, 20, 22, 23, 23, 21, 17, 13, 6, 1, -6, -11, -15, -18, -20, + -19, -19, -17, -16, -13, -11, -8, -5, -1, 2, 5, 7, 9, 9, 8, 6, + 3, 0, -3, -7, -10, -14, -17, -19, -19, -18, -16, -12, -7, -2, 3, 8, + 13, 16, 18, 19, 17, 14, 8, -1, -11, -21, -31, -38, -41, -40, -34, -25, + -12, 2, 17, 32, 45, 56, 62, 65, 63, 58, 49, 38, 25, 10, -6, -18, + -28, -37, -44, -51, -59, -64, -64, -56, -40, -17, 7, 29, 46, 56, 58, 59, + 56, 51, 45, 33, 19, 4, -13, -26, -39, -49, -56, -59, -55, -46, -34, -19, + -4, 10, 21, 30, 40, 46, 51, 52, 49, 43, 31, 18, 5, -8, -16, -21, + -23, -26, -29, -35, -39, -42, -40, -34, -22, -11, 2, 11, 18, 21, 24, 23, + 22, 19, 14, 7, -3, -13, -21, -30, -39, -46, -50, -52, -49, -42, -31, -17, + -3, 12, 26, 39, 49, 57, 60, 58, 51, 39, 22, 1, -23, -47, -68, -82, + -89, -88, -77, -60, -37, -11, 16, 43, 65, 83, 94, 100, 101, 96, 87, 71, + 51, 29, 4, -18, -38, -58, -75, -91, -104, -109, -105, -87, -61, -27, 8, 39, + 67, 87, 97, 97, 88, 71, 54, 36, 16, -2, -23, -42, -57, -70, -75, -75, + -71, -60, -43, -23, -1, 18, 31, 47, 57, 66, 71, 68, 61, 49, 32, 17, + 1, -11, -22, -33, -41, -47, -54, -59, -63, -62, -57, -46, -30, -12, 1, 17, + 30, 41, 49, 50, 47, 40, 29, 17, 3, -14, -30, -46, -60, -70, -76, -77, + -73, -63, -48, -28, -4, 20, 44, 65, 81, 91, 93, 88, 77, 60, 37, 11, + -19, -49, -76, -97, -109, -110, -100, -81, -56, -25, 7, 38, 67, 91, 109, 121, + 127, 126, 116, 96, 68, 38, 8, -18, -43, -68, -90, -110, -124, -127, -116, -91, + -59, -22, 14, 47, 77, 98, 107, 105, 93, 74, 54, 33, 13, -6, -26, -45, + -60, -71, -78, -79, -74, -61, -42, -21, 1, 18, 33, 49, 60, 68, 73, 70, + 62, 48, 32, 15, 0, -13, -24, -34, -42, -48, -55, -61, -65, -65, -60, -48, + -32, -15, 2, 19, 32, 43, 50, 51, 47, 40, 28, 16, 1, -14, 2, -2, + 2, -5, -3, -1, 0, -4, -4, -6, -4, -6, -4, -4, -7, -6, -7, -6, + -1, 0, 3, 13, 14, 16, 12, 13, 2, 1, 0, -1, -1, -1, -2, -2, + -2, -3, -3, -4, -8, -4, -4, -5, -5, -5, -7, -9, -12, -8, -14, -11, + -14, -18, -8, 1, 31, 71, 68, 24, -5, -11, -7, -5, -5, -5, -3, -2, + -5, -5, -9, -8, -7, -7, -9, -12, -11, -17, -14, -16, -15, -20, -26, -30, + -27, -15, 16, 51, 87, 101, 70, 8, -18, -11, -14, -7, -7, -1, -2, -5, + -7, -12, -14, -10, -10, -13, -14, -13, -16, -16, -17, -18, -35, -31, -30, -34, + -9, 16, 56, 84, 89, 60, 30, 5, -7, -5, -8, -3, -4, -4, -6, -12, + -14, -13, -10, -12, -12, -9, -10, -8, -12, -13, -15, -19, -23, -26, -33, -29, + -28, -9, 12, 43, 71, 88, 72, 48, 29, -2, -16, -19, -12, -12, -12, -7, + -11, -10, -10, -10, -11, -13, -15, -18, -19, -17, -16, -15, -13, -12, -13, -9, + -13, -17, -21, -18, 2, 34, 59, 87, 92, 98, 38, -30, -24, -27, -18, -16, + -11, -11, -13, -15, -12, -14, -15, -18, -17, -20, -18, -15, -10, -7, -3, -1, + 2, -8, -11, -22, -22, -20, 7, 31, 61, 97, 106, 43, -23, -28, -25, -20, + -12, -7, -5, -7, -10, -13, -13, -13, -11, -14, -15, -15, -12, -8, -7, -4, + -2, -4, -10, -15, -19, -26, -10, 12, 42, 72, 101, 90, 20, -25, -27, -22, + -18, -10, -6, -9, -11, -16, -17, -16, -14, -10, -8, -9, -9, -9, -9, -9, + -8, -5, -3, -6, -10, -17, -24, -21, 4, 30, 61, 84, 96, 79, -16, -38, + -27, -26, -17, -12, -8, -12, -13, -14, -14, -11, -8, -4, -4, -7, -9, -8, + -10, -12, -8, -5, -4, -7, -10, -18, -24, -11, 14, 42, 70, 79, 93, 36, + -32, -26, -28, -19, -15, -9, -9, -13, -16, -14, -12, -8, -5, -3, -7, -9, + -9, -9, -11, -8, -5, -1, -6, -9, -15, -24, -23, 6, 28, 63, 86, 127, + 37, -45, -27, -28, -26, -19, -4, -5, -8, -11, -12, -14, -12, -8, -4, -8, + -8, -10, -8, -13, -8, -8, -3, -8, -8, -16, -23, -17, 7, 34, 69, 83, + 113, 37, -50, -28, -25, -22, -16, 0, -3, -8, -12, -12, -14, -14, -10, -5, + -7, -6, -9, -9, -13, -9, -10, -7, -9, -9, -15, -20, -14, 8, 33, 64, + 81, 90, 57, -29, -28, 0, -4, 10, 10, 11, -15, 4, -1, 3, -11, 11, + 2, -12, 3, 18, -10, -62, 89, -16, -95, 118, -128, 122, -128, 112, -100, 109, + -121, 120, -104, 58, 10, -88, 127, -102, 6, 98, -126, 35, 89, -111, -7, 112, + -53, -94, 92, 64, -106, -53, 109, 52, -100, -75, 86, 95, -45, -119, -12, 111, + 74, -58, -118, -27, 97, 100, -4, -107, -95, 17, 109, 92, -4, -99, -109, -26, + 78, 115, 66, -27, -104, -109, -41, 55, 112, 98, 32, -53, -109, -105, -44, 41, + 102, 109, 67, -4, -74, -112, -102, -47, 27, 88, 112, 93, 45, -19, -78, -110, + -105, -65, -4, 59, 101, 110, 87, 43, -13, -67, -103, -111, -89, -44, 13, 65, + 100, 109, 93, 59, 14, -36, -78, -104, -108, -90, -53, -6, 43, 83, 104, 106, + 88, 57, 17, -27, -66, -95, -108, -102, -80, -44, -2, 41, 77, 99, 106, 98, + 77, 46, 10, -29, -64, -91, -105, -105, -91, -64, -29, 10, 48, 78, 98, 105, + 100, 84, 59, 30, -3, -36, -65, -88, -101, -105, -99, -83, -60, -32, -1, 30, + 58, 80, 96, 103, 102, 94, 80, 62, 40, 16, -10, -35, -58, -78, -92, -101, + -104, -100, -91, -77, -58, -36, -13, 12, 36, 57, 75, 89, 98, 102, 102, 97, + 88, 76, 61, 44, 25, 5, -15, -35, -54, -70, -84, -94, -101, -104, -103, -98, + -89, -77, -63, -46, -27, -8, 12, 31, 49, 65, 79, 90, 97, 102, 104, 102, + 97, 90, 81, 70, 57, 42, 27, 10, -7, -24, -40, -56, -70, -81, -91, -99, + -103, -105, -105, -101, -95, -87, -76, -63, -49, -34, -18, -1, 16, 32, 48, 62, + 74, 85, 93, 100, 104, 105, 105, 102, 97, 90, 82, 72, 61, 48, 35, 21, + 6, -9, -24, -38, -52, -65, -76, -86, -94, -101, -105, -108, -108, -106, -102, -96, + -87, -78, -66, -54, -40, -26, -11, 4, 19, 34, 48, 61, 73, 83, 92, 99, + 104, 107, 108, 108, 105, 101, 96, 89, 80, 70, 60, 48, 36, 22, 9, -5, + -19, -33, -46, -58, -69, -80, -89, -96, -102, -107, -109, -110, -110, -107, -102, -97, + -89, -80, -70, -59, -47, -33, -20, -6, 7, 19, 30, 41, 50, 58, 65, 71, + 75, 78, 79, 80, 79, 77, 74, 70, 65, 60, 54, 48, 42, 36, 29, 22, + 16, 10, 4, -2, -7, -12, -16, -19, -22, -24, -26, -27, -27, -27, -26, -25, + -23, -22, -19, -17, -14, -12, -10, -1, -1, -4, -9, -9, -7, -6, -7, -3, + 4, 8, 10, 11, 13, 10, 4, -3, -10, -15, -13, -9, -10, -11, -5, 4, + 12, 14, 12, 13, 14, 9, 1, -8, -15, -21, -23, -22, -13, -3, 7, 17, + 24, 27, 19, 11, 16, 15, -5, -24, -29, -23, -27, -32, -21, 5, 18, 20, + 21, 24, 24, 15, 11, 8, -6, -30, -31, -19, -17, -24, -14, 2, 17, 15, + 12, 17, 16, 19, 8, -5, -2, -1, -17, -17, -3, 6, 5, -4, 0, 1, + -12, -9, 9, 11, -4, -14, -8, 9, -2, -21, -14, 4, 9, 9, 11, 18, + 21, 10, 8, 16, 10, 26, 35, 6, -14, -28, -25, -24, -55, -65, -33, -17, + 1, -6, -6, 8, 23, 33, 49, 37, 19, 16, 11, 24, 42, 17, -37, -36, + 3, 7, -23, -36, -9, 9, -12, -20, -8, -2, -4, -23, -17, -6, 0, 10, + 24, 24, 40, 46, 33, 39, 26, 5, 6, 9, -12, -26, -33, -42, -61, -52, + -43, -37, -21, -4, 7, 13, 28, 36, 31, 24, 1, -1, 20, 24, 23, 21, + 26, 27, 8, -32, -44, -3, 28, -1, -36, -30, -6, 13, -12, -34, -18, -6, + 9, 21, 25, 16, 10, 38, 62, 46, 17, -11, -7, 10, -8, -44, -53, -33, + -35, -38, -29, -27, -16, 0, 1, 9, 37, 50, 36, 2, -20, -12, 15, 21, + 24, 32, 29, 20, 23, 12, -8, -3, 4, -10, -5, 2, -19, -63, -70, -21, + 20, 41, 23, 33, 57, 61, 42, 21, 15, 10, -45, -82, -60, -29, -44, -77, + -50, -7, 4, -4, 10, 32, 56, 42, 1, -10, -18, 2, 22, 28, 33, 42, + 47, 43, 47, 11, -23, 0, 10, -40, -81, -70, -28, -29, -68, -29, 19, 6, + 7, 21, 40, 41, 32, 22, 28, 47, 69, 66, 35, 21, 15, -3, -20, -34, + -24, -6, -19, -59, -47, -42, -35, -28, 15, 45, 51, 66, 78, 83, 37, 1, + 13, 7, -51, -81, -92, -83, -87, -74, -58, -73, -51, 12, 35, 26, 35, 47, + 69, 70, 63, 65, 49, 47, 68, 73, 52, 33, 15, -12, -30, -50, -51, -46, + -45, -60, -50, -50, -50, -54, -24, 38, 78, 90, 106, 99, 40, -6, -11, -46, + -110, -127, -107, -76, -67, -53, -41, -41, -23, 14, 33, 27, 34, 49, 70, 71, + 66, 65, 51, 51, 69, 72, 52, 32, 10, -12, 0, -5, -2, -5, 2, -29, + 22, 0, -27, 67, -59, 45, -13, -37, 28, 65, -4, 6, 60, 5, 58, 44, + 60, 27, 43, 96, 71, 81, 48, 96, 70, 23, 90, 66, 80, 88, 40, 20, + 61, 64, 12, 36, 24, 4, 7, 5, -27, -38, -26, -33, -49, -50, -70, -69, + -93, -92, -94, -104, -104, -101, -110, -107, -111, -111, -126, -87, -119, -100, -94, -112, + -93, -93, -80, -81, -76, -58, -56, -70, -30, -21, -42, -13, -3, 2, 8, 20, + 28, 41, 45, 59, 62, 69, 84, 85, 90, 103, 109, 111, 118, 121, 121, 123, + 121, 122, 121, 122, 121, 122, 121, 121, 120, 121, 120, 121, 120, 121, 120, 120, + 119, 120, 119, 120, 118, 105, 106, 110, 83, 89, 92, 75, 67, 61, 57, 47, + 40, 33, 24, 17, 10, 3, -2, -10, -20, -31, -31, -37, -49, -50, -63, -66, + -69, -74, -79, -91, -89, -92, -95, -102, -106, -104, -107, -113, -113, -110, -113, -116, + -114, -115, -114, -115, -114, -113, -114, -113, -114, -113, -112, -113, -109, -105, -111, -106, + -107, -103, -100, -103, -99, -97, -98, -99, -92, -92, -93, -92, -92, -90, -88, -90, + -88, -86, -89, -85, -85, -87, -85, -85, -82, -83, -82, -80, -78, -79, -76, -74, + -73, -73, -69, -68, -66, -64, -65, -62, -58, -56, -56, -52, -50, -47, -43, -42, + -39, -35, -33, -31, -27, -23, -21, -16, -16, -8, -7, -3, 1, 0, 10, 15, + 15, 19, 26, 29, 30, 38, 41, 42, 47, 54, 54, 57, 63, 68, 69, 72, + 77, 78, 80, 85, 84, 86, 87, 86, 87, 86, 85, 86, 85, 84, 85, 84, + 83, 84, 83, 82, 82, 83, 82, 81, 82, 81, 80, 81, 80, 79, 80, 79, + 79, 78, 79, 78, 78, 77, 74, 70, 66, 64, 61, 55, 52, 49, 45, 40, + 35, 32, 29, 24, 19, 15, 12, 8, 4, 0, -4, -8, -11, -15, -17, -20, + -25, -26, -29, -32, -34, -37, -39, -41, -43, -45, -46, -48, -49, -50, -50, -52, + -52, -53, -52, -53, -54, -53, -53, -52, -52, -51, -50, -50, -49, -48, -48, -46, + -45, -44, -42, -41, -40, -39, -37, -35, -34, -32, -30, -28, -27, -24, -23, -22, + -20, -19, -17, -15, -14, -13, -12, -10, -9, -8, -8, -6, -6, -5, -4, -4, + -3, -3, -2, -2, -1, -2, -1, -2, -1, -1, 0, -1, -1, 1, 0, 0, + -3, -1, 1, -4, -4, -3, -2, -5, -3, 0, -1, -1, -3, -1, 0, 2, + 0, -2, -5, 5, 4, 1, 7, 2, 2, 1, 8, 1, 6, 2, -4, 2, + 1, -4, 6, -8, -3, -7, -2, -6, -1, -9, 1, -2, -4, 1, 2, 1, + -2, 8, 2, 0, 14, 9, 10, 5, 3, 5, 6, 4, 3, -8, -2, -4, + -10, -1, -5, -3, -4, -6, -13, -5, -4, -4, -3, 2, -13, -6, 3, 6, + 6, 7, 1, 1, 6, 6, 16, 13, 9, 10, 9, 2, 7, 10, 4, -4, + -3, -17, -7, -6, -6, -10, -17, -17, -10, -11, -9, -5, -6, -8, 2, 1, + 8, 19, 15, 18, 24, 19, 16, 17, 19, 11, 7, 1, -5, -8, -9, -15, + -8, -9, -14, -20, -19, -9, -18, -10, -13, -23, -13, -12, -7, 0, -1, 5, + 16, 12, 28, 30, 32, 34, 34, 19, 24, 23, 16, 11, 5, -7, -19, -17, + -16, -21, -26, -23, -32, -31, -30, -25, -26, -24, -19, -13, -9, -1, 0, 4, + 6, 13, 15, 19, 17, 13, 8, 8, 8, 7, 0, -4, -8, -10, -7, -5, + -6, -6, -9, -12, -8, -10, -9, -9, -11, -13, -12, -9, -4, -1, 4, 9, + 19, 27, 31, 26, 16, 14, 16, 16, 12, 1, -8, -14, -11, -9, -6, -11, + -11, -12, -14, -10, -11, -13, -15, -19, -23, -19, -14, -8, -5, -1, 8, 34, + 62, 59, 12, 14, 32, 22, 6, 20, 6, -9, -54, -16, -1, -19, 7, -15, + -13, -12, -14, -15, -14, -22, -24, -30, -30, -20, -12, -6, 3, 26, 66, 88, + 39, 0, 47, 36, -2, 26, -23, 21, 13, -6, -60, -42, 6, -22, 4, -18, + -16, -4, -16, -19, -24, -39, -31, -25, -32, -26, -11, 12, 55, 104, 75, 10, + 35, 62, 9, 26, -16, -8, 19, 3, -9, -61, -46, 2, -26, -7, -16, -10, + 2, -7, -22, -23, -38, -40, -37, -44, -33, -8, 37, 101, 124, 36, -5, 89, + 20, 38, 5, -26, 3, 1, 5, -28, -65, -21, 1, -22, -12, -26, 1, -7, + -10, -24, -26, -33, -37, -48, -50, -36, 5, 63, 122, 109, 7, 35, 84, 5, + 59, -36, -4, -11, -1, -5, -40, -55, -4, -15, -21, -16, -22, 5, -10, -17, + -20, -27, -23, -44, -54, -62, -23, 29, 114, 127, 51, 7, -2, -4, -2, 4, + 11, 14, 10, 2, -7, -9, -9, -15, -16, -7, 3, 2, -10, -21, -17, 6, + 10, -8, -28, -11, 45, 66, 64, 47, 36, 49, 49, 27, 9, -12, -18, -25, + -30, -11, 0, -5, 0, -1, -18, -36, -33, -18, -10, -13, -31, -26, -25, -17, + 4, 28, 70, 89, 48, 9, -32, -58, -56, -70, -57, -17, -38, -48, -35, -32, + -7, 35, 38, 53, 62, 44, 33, 27, -6, -35, -52, -65, -54, -40, -43, -30, + -25, 2, 63, 54, 34, 17, 34, 70, 60, 8, -15, -3, 0, 39, 55, 35, + 39, 60, 75, 36, 20, -7, -25, -66, -110, -89, -89, -71, -36, -12, 9, 31, + 41, 54, 46, 45, 59, 41, 22, 3, -69, -110, -126, -116, -64, -15, 9, 29, + 33, 30, 56, 42, 12, 23, 6, -27, -36, -21, -22, -32, -21, -30, -29, -5, + 9, 16, 22, -9, -12, 31, 24, -17, -41, -23, 32, 32, 26, 34, 64, 66, + 109, 104, 51, 5, 12, 16, -36, -58, -59, -66, -63, -82, -64, -23, -9, 11, + 16, 20, 19, 13, 12, 33, 37, 41, 46, 28, 7, -58, -93, -79, -64, -33, + -1, 22, -4, 2, 19, 4, -7, -3, -3, 5, 1, -10, -3, 12, -6, -38, + -29, -17, -5, 11, 2, -33, -20, 44, 42, 20, -30, -24, 9, 44, 38, 20, + 36, 71, 61, 86, 72, 25, -8, 10, 17, -35, -54, -63, -67, -70, -78, -58, + -16, -7, 19, 22, 20, 21, 29, 21, 16, 35, 36, 16, -8, -27, -61, -58, + -67, -43, 3, 35, 38, -2, -2, 10, -9, -29, -14, -5, -1, -5, 2, 12, + -6, -32, -23, -22, -16, -5, 3, -9, -29, 27, 56, 39, 11, -27, -28, 23, + 34, 28, 18, 20, 62, 82, 71, 74, 24, -4, 16, 18, -39, -54, -65, -61, + -52, -64, -49, -11, -4, 12, 17, 16, 25, 24, 6, 23, 36, 18, 18, -1, + -42, -50, -90, -43, 3, 35, 38, -2, -2, 10, -9, -29, -14, -5, -1, -5, + 2, 12, -6, -32, -23, -22, -16, -5, 3, -9, -29, 27, 56, 39, 11, -27, + -28, 23, 34, 28, 18, 20, 62, 82, 71, 74, 24, -4, 16, 18, -39, -54, + -65, -61, -52, -64, -49, -11, -4, 12, 17, 16, 25, 24, 6, 23, 36, 18, + 18, -1, -42, -50, -90, -43, 0, 1, 6, -11, 19, -25, 24, -15, 11, -6, + 1, 9, -6, -3, 11, -18, 28, -23, 8, 6, -2, -1, 0, -5, 18, -23, + 24, -28, 27, -12, -1, -2, 6, 4, -14, 19, -29, 42, -40, 22, -6, -3, + 14, -16, 4, 8, -9, 13, -22, 17, 5, -24, 37, -34, 20, -4, -11, 19, + -20, 21, -16, 1, 17, -17, 5, -9, 25, -31, 31, -40, 32, -11, -7, 4, + -4, 13, -23, 29, -40, 51, -49, 20, 3, -20, 38, -47, 34, -21, 14, -9, + 4, -13, 20, -29, 37, -57, 59, -48, 23, -5, -7, 5, -6, -5, 13, -17, + 9, -4, -12, 22, -19, -8, 10, -5, -7, 8, -18, 19, -13, 5, -12, 6, + -10, 18, -40, 66, -91, 82, -56, 17, 19, -51, 56, -45, 30, -19, 5, -6, + 7, -9, -4, -2, -5, 13, -19, 1, 20, -28, 13, -6, 0, -17, 33, -48, + 38, -16, -20, 53, -75, 75, -61, 30, -12, -9, 2, 5, -9, -7, 15, -17, + 9, 4, -46, 70, -85, 86, -67, 29, 18, -60, 76, -70, 29, -8, -1, 1, + 14, -58, 93, -118, 127, -125, 85, -36, -2, 17, -39, 46, -61, 70, -99, 122, + -120, 56, 15, -85, 116, -101, 30, 43, -108, 127, -122, 72, -38, -3, 20, -31, + 29, -37, 42, -50, 63, -72, 40, -7, -46, 66, -82, 53, -25, 1, 1, -1, + -3, 3, -24, 24, -34, 27, -24, 36, -49, 37, -38, 35, -42, 13, -4, -14, + 14, -29, 42, -58, 58, -60, 41, -39, 27, -35, 27, -32, 25, -37, 43, -50, + 32, -20, -4, 4, -14, 16, -43, 66, -93, 79, -58, 27, -11, -21, 34, -40, + 24, -7, -25, 31, -29, 19, -18, -2, 1, -6, 4, -31, 47, -63, 62, -64, + 32, 2, -29, 23, -21, 19, -41, 59, -76, 62, -52, 26, -11, -1, -10, 6, + -10, -7, 17, -42, 34, -12, -34, 73, -106, 92, -61, 26, -24, 8, -7, -2, + 3, -24, 31, -44, 27, -9, -22, 38, -43, 15, -4, -3, -2, -12, 5, 1, + -7, 7, -25, 17, -17, 4, -15, 27, -40, 34, -18, 6, -13, 12, -3, -9, + -6, 8, -18, 18, -36, 54, -55, 30, -25, 26, -41, 38, -49, 48, -38, 8, + 16, -40, 47, -52, 34, -12, -4, 2, -13, 0, 1, 6, -11, 19, -25, 24, + -15, 11, -6, 1, 9, -6, -3, 11, -18, 28, -23, 8, 6, -2, -1, 0, + -5, 18, -23, 24, -28, 27, -12, -1, -2, 6, 4, -14, 19, -29, 42, -40, + 22, -6, -3, 14, -16, 4, 8, -9, 13, -22, 17, 5, -24, 37, -34, 20, + -4, -11, 19, -20, 21, -16, 1, 17, -17, 5, -9, 25, -31, 31, -40, 32, + -11, -7, 4, -4, 13, -23, 29, -40, 51, -49, 20, 3, -20, 38, -47, 34, + -21, 14, -9, 4, -13, 20, -29, 37, -57, 59, -48, 23, -5, -7, 5, -6, + -5, 13, -17, 9, -4, -12, 22, -19, -8, 10, -5, -7, 8, -18, 19, -13, + 5, -12, 6, -10, 18, -40, 66, -91, 82, -56, 17, 19, -51, 56, -45, 30, + -19, 5, -6, 7, -9, -4, -2, -5, 13, -19, 1, 20, -28, 13, -6, 0, + -17, 33, -48, 38, -16, -20, 53, -75, 75, -61, 30, -12, -9, 2, 5, -9, + -7, 15, -17, 9, 4, -46, 70, -85, 86, -67, 29, 18, -60, 76, -70, 29, + -8, -1, 1, 14, -58, 93, -118, 127, -125, 85, -36, -2, 17, -39, 46, -61, + 70, -99, 122, -120, 56, 15, -85, 116, -101, 30, 43, -108, 127, -122, 72, -38, + -3, 20, -31, 29, -37, 42, -50, 63, -72, 40, -7, -46, 66, -82, 53, -25, + 1, 1, -1, -3, 3, -24, 24, -34, 27, -24, 36, -49, 37, -38, 35, -42, + 13, -4, -14, 14, -29, 42, -58, 58, -60, 41, -39, 27, -35, 27, -32, 25, + -37, 43, -50, 32, -20, -4, 4, -14, 16, -43, 66, -93, 79, -58, 27, -11, + -21, 34, -40, 24, -7, -25, 31, -29, 19, -18, -2, 1, -6, 4, -31, 47, + -63, 62, -64, 32, 2, -29, 23, -21, 19, -41, 59, -76, 62, -52, 26, -11, + -1, -10, 6, -10, -7, 17, -42, 34, -12, -34, 73, -106, 92, -61, 26, -24, + 8, -7, -2, 3, -24, 31, -44, 27, -9, -22, 38, -43, 15, -4, -3, -2, + -12, 5, 1, -7, 7, -25, 17, -17, 4, -15, 27, -40, 34, -18, 6, -13, + 12, -3, -9, -6, 8, -18, 18, -36, 54, -55, 30, -25, 26, -41, 38, -49, + 48, -38, 8, 16, -40, 47, -52, 34, -12, -4, 2, -13, -1, -2, -1, -4, + -3, -25, -41, 8, 16, 27, 2, 16, 1, 13, 21, -8, -6, -29, 17, 8, + 8, 20, -13, 5, 4, 25, 17, 30, 22, 14, 15, 19, 7, 51, -16, -15, + -32, -13, 12, -8, -17, -49, -27, -29, -29, -52, -66, -55, -32, -20, -41, -21, + -36, -11, -16, 22, 3, 19, 0, -6, -10, 0, -38, -17, -35, -19, -27, 0, + -35, -27, -9, -17, -14, -2, 20, 50, 63, 57, 49, 70, 70, 97, 81, 68, + 52, 78, 93, 98, 102, 56, 34, 20, 53, 60, 45, 24, -18, 21, -10, 0, + -38, -79, -38, -37, -13, -27, -41, -50, -51, 14, 10, 16, -21, -13, -22, -20, + -48, -53, -55, -66, -76, -65, -91, -105, -92, -87, -101, -79, -56, -34, -7, -4, + 7, 20, 15, 26, 29, 32, -8, 36, 47, 50, 66, 29, 18, -33, -11, -4, + -10, -24, -42, -31, -22, 2, -23, -75, -34, -36, 5, 1, 1, -17, -47, 20, + 43, 68, 28, 30, 9, 29, 7, -9, -5, -32, -46, -36, -15, -40, -35, -15, + -26, -21, 2, 21, 49, 62, 83, 87, 106, 77, 97, 94, 67, 60, 85, 79, + 110, 80, 61, 1, 8, 16, 50, 36, 2, -22, 4, -2, 21, -35, -33, -19, + 4, 24, 19, 10, -58, -23, 18, 45, 34, 8, -12, -6, -5, -48, -51, -75, + -72, -77, -37, -65, -80, -57, -66, -68, -38, -38, 2, 10, 38, 31, 58, 22, + 39, 37, 27, -9, 23, 9, 35, 18, 15, -31, -50, -44, -5, 6, -10, -63, + -41, -56, -15, -41, -71, -45, -37, 7, -6, 5, -56, -71, -6, 21, 41, 8, + -13, -14, -40, -30, -41, -40, -56, -31, -31, -9, -15, -5, 10, 42, 27, 73, + 82, 73, 73, 79, 70, 38, 28, 31, 23, 45, 42, 44, 30, -40, 8, 28, + 52, 30, -18, -29, -40, -14, -45, -50, -55, -68, -39, -6, -29, -45, -59, -32, + 4, 31, 23, 16, 20, 11, -1, 1, -28, -45, -53, -56, -67, -60, -55, -40, + -31, -25, -16, 11, 20, 36, 67, 70, 75, 77, 81, 65, 46, 38, 34, 39, + 51, 44, 57, 7, -4, 13, 37, 46, 19, -8, -29, -1, -9, -21, -32, -43, + -55, -58, -40, -8, 15, 29, 38, 44, 59, 63, 51, 20, -20, -47, -61, -58, + -48, -42, -43, -35, -15, 15, 41, 55, 61, 62, 70, 67, 45, 11, -31, -62, + -80, -78, -71, -62, -54, -39, -15, 18, 50, 68, 79, 83, 92, 88, 57, 16, + -31, -71, -94, -95, -90, -83, -71, -55, -28, 7, 49, 77, 93, 100, 109, 107, + 78, 36, -20, -71, -99, -104, -100, -92, -83, -69, -43, -5, 42, 79, 100, 108, + 114, 112, 90, 51, -9, -65, -100, -110, -105, -95, -87, -76, -52, -11, 35, 75, + 100, 107, 111, 106, 90, 52, -4, -60, -97, -109, -99, -87, -80, -65, -35, 5, + 43, 75, 91, 95, 93, 87, 71, 31, -19, -64, -93, -99, -88, -76, -66, -44, + -9, 28, 59, 79, 84, 80, 71, 59, 35, -5, -45, -76, -96, -95, -77, -59, + -39, -9, 28, 61, 86, 98, 93, 74, 52, 28, -6, -43, -72, -94, -108, -99, + -77, -52, -20, 19, 56, 84, 106, 115, 106, 79, 45, 3, -40, -74, -93, -108, + -112, -100, -79, -46, -1, 45, 78, 100, 113, 118, 108, 81, 39, -19, -67, -93, + -103, -108, -104, -94, -74, -32, 19, 61, 88, 102, 108, 109, 100, 73, 21, -44, + -87, -102, -104, -97, -90, -78, -49, 0, 46, 78, 90, 92, 89, 87, 77, 43, + -15, -72, -101, -104, -93, -79, -69, -47, -3, 47, 84, 96, 89, 74, 65, 58, + 37, -7, -61, -99, -110, -101, -82, -62, -38, 2, 49, 92, 112, 106, 82, 59, + 41, 18, -19, -61, -95, -111, -110, -98, -74, -39, 6, 54, 99, 122, 123, 104, + 79, 50, 12, -32, -72, -100, -111, -110, -106, -90, -54, -4, 49, 99, 123, 126, + 113, 95, 69, 24, -27, -72, -102, -114, -109, -104, -94, -64, -16, 36, 87, 116, + 121, 111, 97, 76, 36, -15, -61, -94, -110, -108, -98, -86, -60, -19, 29, 77, + 104, 109, 99, 86, 67, 35, -7, -47, -82, -98, -101, -92, -77, -48, -14, 25, + 67, 92, 95, 83, 66, 45, 18, -9, -37, -62, -77, -81, -78, -54, -16, 0, + 0, 0, 12, -10, 16, -14, -18, 17, -31, -2, 3, -19, -8, 17, 28, 37, + 31, -1, -25, -16, -47, -13, -43, -22, 6, 34, 41, 49, 41, 27, 6, -33, + -62, -54, -59, -32, -13, 29, 53, 73, 60, 54, 16, -19, -58, -77, -89, -42, + -46, 17, 55, 78, 86, 81, 33, -3, -35, -84, -110, -75, -70, 0, 39, 78, + 92, 105, 70, 13, -15, -82, -107, -103, -84, -41, 20, 81, 85, 127, 86, 39, + -4, -63, -103, -99, -107, -69, 2, 68, 82, 127, 84, 58, 28, -44, -88, -104, + -108, -83, -13, 29, 69, 116, 87, 77, 40, -16, -65, -89, -104, -89, -40, -1, + 47, 96, 90, 85, 52, 9, -38, -62, -96, -95, -62, -22, 21, 73, 78, 86, + 65, 35, -15, -41, -80, -92, -69, -48, 1, 43, 65, 80, 73, 49, 8, -23, + -59, -75, -74, -60, -22, 17, 49, 69, 65, 60, 25, -1, -36, -59, -70, -61, + -40, -9, 30, 52, 57, 63, 37, 17, -12, -41, -61, -57, -50, -30, 9, 30, + 49, 60, 47, 28, 6, -20, -49, -51, -53, -42, -11, 13, 34, 53, 50, 34, + 18, -3, -35, -39, -52, -49, -23, 0, 18, 41, 47, 36, 31, 10, -21, -28, + -43, -49, -31, -13, 2, 28, 39, 35, 38, 19, -7, -18, -33, -42, -36, -26, + -12, 19, 30, 34, 36, 22, 6, -5, -25, -38, -36, -29, -17, 8, 19, 26, + 35, 28, 12, 3, -17, -30, -29, -29, -22, -3, 9, 19, 33, 26, 14, 8, + -9, -18, -22, -28, -25, -9, 3, 15, 22, 20, 18, 12, 1, -11, -22, -24, + -21, -13, -3, 8, 11, 20, 21, 12, 5, -6, -19, -16, -17, -17, -7, 3, + 8, 20, 17, 7, 7, -2, -11, -13, -16, -17, -5, 2, 5, 12, 13, 8, + 6, 3, -9, -11, -9, -14, -5, 1, -3, 6, 11, 6, 7, 2, -6, -4, + -4, -10, -6, -3, -4, 5, 8, 2, 5, 4, -2, 0, -3, -9, -4, -3, + -3, 2, 3, 0, 6, 4, 0, -1, -2, -2, 0, 0, 0, 12, -10, 16, + -14, -18, 17, -31, -2, 3, -19, -8, 17, 28, 37, 31, -1, -25, -16, -47, + -13, -43, -22, 6, 34, 41, 49, 41, 27, 6, -33, -62, -54, -59, -32, -13, + 29, 53, 73, 60, 54, 16, -19, -58, -77, -89, -42, -46, 17, 55, 78, 86, + 81, 33, -3, -35, -84, -110, -75, -70, 0, 39, 78, 92, 105, 70, 13, -15, + -82, -107, -103, -84, -41, 20, 81, 85, 127, 86, 39, -4, -63, -103, -99, -107, + -69, 2, 68, 82, 127, 84, 58, 28, -44, -88, -104, -108, -83, -13, 29, 69, + 116, 87, 77, 40, -16, -65, -89, -104, -89, -40, -1, 47, 96, 90, 85, 52, + 9, -38, -62, -96, -95, -62, -22, 21, 73, 78, 86, 65, 35, -15, -41, -80, + -92, -69, -48, 1, 43, 65, 80, 73, 49, 8, -23, -59, -75, -74, -60, -22, + 17, 49, 69, 65, 60, 25, -1, -36, -59, -70, -61, -40, -9, 30, 52, 57, + 63, 37, 17, -12, -41, -61, -57, -50, -30, 9, 30, 49, 60, 47, 28, 6, + -20, -49, -51, -53, -42, -11, 13, 34, 53, 50, 34, 18, -3, -35, -39, -52, + -49, -23, 0, 18, 41, 47, 36, 31, 10, -21, -28, -43, -49, -31, -13, 2, + 28, 39, 35, 38, 19, -7, -18, -33, -42, -36, -26, -12, 19, 30, 34, 36, + 22, 6, -5, -25, -38, -36, -29, -17, 8, 19, 26, 35, 28, 12, 3, -17, + -30, -29, -29, -22, -3, 9, 19, 33, 26, 14, 8, -9, -18, -22, -28, -25, + -9, 3, 15, 22, 20, 18, 12, 1, -11, -22, -24, -21, -13, -3, 8, 11, + 20, 21, 12, 5, -6, -19, -16, -17, -17, -7, 3, 8, 20, 17, 7, 7, + -2, -11, -13, -16, -17, -5, 2, 5, 12, 13, 8, 6, 3, -9, -11, -9, + -14, -5, 1, -3, 6, 11, 6, 7, 2, -6, -4, -4, -10, -6, -3, -4, + 5, 8, 2, 5, 4, -2, 0, -3, -9, -4, -3, -3, 2, 3, 0, 6, + 4, 0, -1, -2, -2, 0, -1, -1, -3, -7, -14, -23, -32, -45, -55, -66, + -74, -83, -88, -80, -77, -71, -64, -54, -46, -37, -31, -25, -19, -12, -6, -1, + 4, 8, 12, 17, 21, 23, 25, 25, 27, 29, 32, 35, 36, 34, 32, 31, + 32, 35, 37, 37, 35, 31, 29, 29, 31, 33, 34, 32, 29, 26, 25, 27, + 30, 32, 31, 29, 27, 27, 29, 31, 34, 35, 35, 35, 36, 38, 41, 43, + 45, 47, 49, 52, 55, 57, 59, 61, 63, 66, 69, 70, 70, 68, 66, 63, + 61, 58, 54, 47, 36, 24, 11, 1, -9, -20, -33, -48, -64, -78, -89, -97, + -103, -110, -116, -123, -128, -128, -126, -121, -116, -112, -107, -102, -95, -88, -78, -69, + -61, -54, -47, -41, -34, -27, -21, -16, -12, -7, -2, 2, 5, 6, 8, 10, + 13, 16, 19, 19, 19, 17, 18, 19, 22, 24, 24, 22, 19, 18, 19, 21, + 23, 24, 22, 19, 17, 18, 20, 22, 24, 24, 22, 21, 22, 24, 27, 29, + 30, 30, 31, 32, 35, 37, 40, 42, 45, 47, 50, 53, 56, 58, 60, 62, + 66, 68, 70, 69, 68, 65, 63, 61, 59, 54, 46, 36, 24, 13, -1, -14, + -28, -43, -57, -68, -78, -86, -94, -102, -109, -114, -117, -117, -115, -112, -109, -106, + -101, -96, -89, -81, -73, -67, -59, -53, -46, -40, -34, -28, -23, -18, -13, -9, + -5, -2, 0, 2, 5, 7, 10, 12, 14, 15, 15, 15, 16, 18, 19, 20, + 20, 19, 18, 18, 19, 21, 22, 22, 21, 20, 19, 21, 23, 24, 25, 25, + 25, 25, 26, 29, 31, 33, 34, 35, 36, 38, 40, 43, 46, 48, 51, 53, + 56, 59, 62, 65, 68, 71, 74, 77, 78, 79, 78, 77, 76, 74, 71, 66, + 58, 49, 39, 28, 17, 6, -6, -20, -35, -50, -64, -75, -85, -94, -102, -110, + -117, -122, -124, -123, -121, -118, -114, -110, -106, -99, -92, -84, -76, -69, -61, -55, + -48, -41, -34, -29, -23, -18, -13, -9, -5, -2, 0, -1, -1, 0, 2, 0, + 3, 2, 2, 4, 5, 4, 4, 4, 4, 5, 3, 4, 3, 1, 2, 0, + 0, -1, -3, -4, -2, -3, -5, -3, -4, -5, -5, -4, -3, -3, -6, -5, + -4, -2, -5, -5, -2, -3, -3, -3, 1, 4, 4, 8, 8, 8, 13, 12, + 13, 14, 12, 9, 8, 6, 6, 3, -2, -2, -5, -5, -4, -5, -11, -16, + -12, -7, -3, -5, -10, -11, -6, -2, -2, -1, -4, -6, -6, -7, -8, -5, + -2, 2, 5, 6, 8, 8, 9, 13, 16, 16, 14, 11, 7, 5, 4, 2, + 0, -2, -3, -3, 0, -3, -13, -28, -11, 7, -1, -15, -1, -5, -18, -10, + 6, 11, -11, -1, -10, -14, -13, -13, -4, 4, 6, 14, 13, 10, 10, 15, + 17, 24, 24, 13, 12, 10, 1, 0, 2, -4, 0, -6, 2, 7, -22, -68, + 2, 35, -40, 14, -24, -3, -10, -9, -20, -3, 28, 2, -9, -12, -28, -19, + -4, -1, 15, 17, 17, 16, 12, 16, 22, 25, 28, 6, 17, 9, -1, -2, + -3, 2, 12, -6, 6, -5, -35, -89, 32, 28, -39, 20, -36, 9, -20, -9, + -34, 3, 34, 8, -16, -11, -37, -15, -3, 0, 26, 18, 13, 15, 13, 25, + 27, 29, 20, 3, 21, 2, -2, 0, -8, 11, 16, -1, 8, -21, -76, -81, + 87, -25, 4, -4, -23, 6, -26, -20, -35, 23, 28, 0, -18, -16, -43, 2, + -9, 17, 25, 15, 9, 18, 17, 37, 28, 35, 3, 14, 12, -5, -1, -1, + -5, 27, 0, 16, -11, -49, -128, 36, 40, -36, 35, -41, 21, -27, -14, -45, + 4, 24, 20, -23, -6, -41, -9, -1, 6, 23, 19, 5, 15, 14, 33, 35, + 40, 16, 5, 16, -3, -5, 4, -12, 24, 10, 18, 1, -38, -128, -21, 72, + -50, 42, -38, 19, -16, -16, -43, -10, 21, 24, -22, -11, -30, -15, 6, 4, + 22, 18, 6, 11, 13, 27, 39, 42, 22, 4, -3, -2, -2, -5, -3, -5, + -3, -2, -6, -5, -5, -6, -5, -3, -5, -3, -5, -4, -6, -3, -1, -2, + -1, 0, -2, 1, 2, 1, 4, 4, 5, 5, 5, 8, 10, 11, 9, 10, + 11, 8, 5, 10, 7, 5, 5, 0, -3, 1, 0, -5, -2, -8, -9, -7, + -7, -5, -9, -11, -9, -8, -8, -7, -9, -7, -6, -7, -5, -6, -5, -3, + -3, -3, -4, -4, -2, 0, 1, 2, 5, 9, 12, 16, 19, 22, 22, 24, + 22, 22, 19, 13, 11, 7, 7, 4, -2, -7, -9, -9, -8, -10, -14, -14, + -15, -15, -13, -14, -17, -18, -14, -12, -12, -8, -9, -7, -6, -6, -6, -8, + -9, -9, -11, -13, -11, -6, -1, 3, 9, 20, 27, 33, 37, 46, 46, 42, + 37, 28, 21, 14, 11, 10, 14, 20, -2, -40, -47, -22, -5, -4, -1, 4, + -15, -53, -56, -7, -33, -14, -2, -19, -7, -8, -15, -6, -9, -8, -3, -9, + -15, -18, -26, -19, -6, -5, -6, 0, 12, 22, 29, 30, 28, 32, 29, 21, + 15, 13, 5, 5, 3, 19, 30, 3, -68, -26, 2, -17, 17, -12, 15, -1, + -12, -48, -43, -19, -1, 3, 6, -8, -4, -10, -10, -4, 0, -6, -1, -7, + -9, -17, -12, -6, -9, -14, -5, 14, 33, 33, 41, 32, 41, 35, 20, 10, + 8, 4, 10, -2, 36, 40, 3, -110, -8, -7, -6, 16, -18, 27, -2, -4, + -56, -57, -33, 16, -2, 12, -11, -5, -17, -9, -5, 10, -6, 0, -12, -11, + -20, -10, -8, -12, -17, -3, 17, 38, 34, 45, 36, 51, 37, 18, 4, -3, + 3, 8, 8, 54, 48, -34, -128, 28, -33, 28, -13, 1, 21, 3, -20, -59, + -65, -10, 17, -1, 7, -17, -10, -19, -8, 5, 11, -4, -2, -16, -17, -20, + -9, -11, -18, -11, 3, 31, 36, 41, 41, 44, 53, 30, 10, 1, -13, 12, + -5, 42, 63, 43, -127, -55, 19, -27, 28, -1, 0, 3, 5, 8, 12, 14, + 15, 15, 14, 12, 8, 5, 1, -3, -9, -14, -17, -19, -18, -16, -12, -8, + -5, -4, -2, -1, -1, -2, -3, -4, -3, -2, -1, -1, 0, 0, 0, 2, + 8, 12, 16, 19, 23, 26, 34, 40, 39, 28, 11, -8, -26, -36, -40, -39, + -35, -27, -19, -10, -5, -6, -10, -12, -15, -14, -12, -9, -5, -3, -1, 1, + 6, 8, 7, 7, 7, 8, 13, 20, 28, 35, 43, 48, 55, 57, 51, 32, + 3, -29, -56, -68, -67, -60, -46, -31, -17, -7, -4, -7, -11, -15, -16, -15, + -10, -5, -1, 1, 3, 5, 7, 9, 11, 12, 12, 10, 13, 19, 26, 36, + 43, 51, 58, 65, 61, 40, 6, -30, -60, -75, -73, -64, -49, -32, -16, -5, + -1, -4, -11, -18, -23, -23, -19, -12, -5, 2, 8, 12, 13, 11, 9, 8, + 8, 10, 15, 21, 27, 32, 37, 42, 49, 55, 63, 55, 32, -3, -39, -66, + -79, -73, -56, -39, -24, -12, -7, -7, -12, -19, -24, -24, -21, -14, -6, 3, + 8, 11, 12, 11, 10, 10, 10, 11, 14, 17, 21, 27, 33, 41, 49, 56, + 63, 66, 49, 15, -27, -61, -82, -85, -73, -52, -33, -18, -9, -5, -7, -12, + -18, -21, -20, -15, -9, -1, 4, 8, 12, 15, 15, 14, 11, 8, 7, 10, + 15, 22, 32, 45, 59, 72, 86, 95, 75, 22, -40, -93, -119, -120, -97, -64, + -32, -9, 5, 9, 5, -3, -14, -21, -23, -20, -13, -5, 4, 12, 17, 18, + 15, 10, 7, 4, 3, 6, 9, 15, 21, 30, 40, 56, 77, 99, 99, 54, + -19, -86, -123, -127, -103, -66, -27, 1, 16, 18, 11, -1, -12, -21, -23, -21, + -16, -8, 1, 9, 16, 19, 16, 11, 8, 5, 5, 7, 9, 14, 19, 27, + 35, 49, 68, 90, 101, 73, 6, -66, -114, -128, -113, -78, -39, -6, 13, 19, + 11, -1, 0, 10, 30, 35, 40, 39, 37, 28, 18, 6, -9, -20, -30, -35, + -33, -30, -28, -23, -24, -23, -19, -20, -15, -11, -8, -3, 0, 1, 0, -2, + -4, -1, 0, 10, 15, 21, 27, 25, 25, 22, 13, 10, -5, -9, -15, -19, + -17, -17, -12, -7, 0, 4, 10, 8, 5, -5, -13, -23, -31, -30, -24, -13, + 11, 36, 62, 81, 83, 78, 54, 35, 19, -11, -29, -49, -57, -47, -35, -20, + -19, -26, -27, -33, -30, -26, -22, -11, -8, 3, 11, 6, 0, -16, -23, -23, + -11, 9, 23, 35, 45, 51, 46, 49, 26, 12, -13, -26, -37, -45, -31, -35, + -17, -4, 8, 23, 24, 23, 9, -10, -22, -37, -40, -38, -33, -12, 22, 67, + 100, 119, 111, 79, 50, 10, -12, -32, -52, -69, -62, -38, -14, -9, -21, -42, + -60, -50, -39, -19, -4, -1, 3, 15, 19, 2, -16, -43, -57, -48, -21, 19, + 38, 63, 66, 69, 74, 59, 39, 4, -33, -52, -67, -58, -39, -25, 2, 10, + 32, 35, 36, 18, -7, -25, -37, -31, -28, -23, -10, 11, 53, 101, 121, 123, + 92, 48, 11, -24, -42, -60, -66, -67, -48, -20, 2, -16, -41, -67, -87, -62, + -44, -10, 8, 19, 30, 34, 35, 4, -36, -66, -78, -75, -27, 22, 49, 83, + 91, 97, 90, 69, 39, -18, -61, -104, -98, -75, -32, 19, 47, 68, 70, 56, + 16, -33, -77, -89, -76, -47, 7, 35, 64, 100, 123, 125, 107, 60, 5, -39, + -76, -94, -101, -93, -69, -36, -3, 17, 10, -15, -56, -80, -86, -69, -40, -7, + 25, 49, 66, 72, 54, 19, -19, -55, -77, -67, -40, 4, 45, 76, 96, 100, + 92, 67, 32, -11, -56, -88, -91, -73, -33, 9, 41, 61, 65, 52, 17, -28, + -67, -80, -68, -36, 6, 47, 82, 114, 126, 114, 74, 18, -32, -73, -93, -101, + -93, -70, -36, -3, 17, 10, -15, 0, -1, -2, -2, 0, 2, 3, 6, 7, + 6, 6, 3, 2, -1, -4, -8, -12, -14, -13, -13, -11, -5, -1, 5, 10, + 14, 17, 19, 18, 15, 12, 7, 3, 1, -2, -4, -4, -7, -11, -13, -16, + -16, -12, -9, -6, -3, -1, -1, -1, -4, -8, -11, -15, -16, -15, -10, -2, + 7, 18, 25, 28, 28, 24, 16, 10, 4, -2, -5, -5, -4, -4, -1, 0, + 0, 1, 1, 0, -1, -3, -6, -11, -11, -14, -16, -17, -19, -19, -16, -10, + -2, 8, 19, 27, 33, 35, 32, 26, 21, 14, 7, 0, -6, -11, -18, -25, + -31, -32, -27, -19, -9, 1, 10, 15, 14, 10, 0, -13, -28, -38, -42, -40, + -26, -4, 17, 40, 58, 66, 62, 51, 35, 17, 3, -8, -16, -18, -18, -15, + -13, -15, -17, -17, -15, -13, -11, -12, -3, -2, 1, -3, -15, -28, -36, -42, + -40, -28, -11, 14, 45, 63, 70, 69, 56, 44, 36, 21, 3, -12, -18, -26, + -37, -47, -58, -55, -41, -20, 4, 22, 34, 43, 37, 22, -7, -43, -71, -88, + -86, -64, -31, 7, 56, 99, 115, 106, 85, 48, 17, 1, -14, -28, -33, -20, + -11, -12, -18, -37, -44, -41, -29, -23, -7, 15, 31, 40, 33, 8, -27, -56, + -73, -74, -63, -33, 4, 50, 93, 101, 91, 79, 56, 43, 24, 5, -17, -32, + -31, -43, -56, -63, -72, -57, -32, 3, 26, 46, 62, 63, 45, 9, -39, -85, + -112, -106, -84, -49, 6, 60, 104, 127, 115, 83, 46, 16, -1, -16, -21, -26, + -16, -2, -8, -25, -47, -67, -62, -49, -26, 2, 34, 60, 74, 65, 33, -21, + -71, -98, -92, -77, -36, 21, 69, 106, 112, 88, 58, 29, 9, -8, -18, -24, + -17, -4, -10, -26, -47, -67, -62, -49, -26, 2, 34, 60, 74, 65, 33, 17, + 16, -38, 9, 40, -58, 27, 43, -80, 52, -2, -54, 64, -27, -17, 32, 4, + -49, 53, -22, -47, 90, -73, 17, 42, -45, 8, 23, -41, -1, 58, -74, 40, + 25, -66, 56, -19, -45, 58, -9, -39, 45, 3, -48, 55, -41, -27, 78, -66, + 13, 40, -38, 0, 29, -51, 12, 57, -79, 38, 31, -64, 40, -4, -47, 63, + -16, -40, 55, -16, -32, 45, -31, -29, 76, -64, 0, 58, -49, 4, 31, -52, + 31, 5, -35, 45, -21, 4, -5, 3, -17, -7, 55, -72, 43, 35, -88, 80, + -57, 3, 45, -62, 53, -14, -2, -17, 46, -77, 42, 23, -61, 75, -54, 39, + -40, 31, -42, 25, 11, -48, 93, -97, 62, -27, -13, 7, 0, 30, -59, 82, + -74, 28, 10, -53, 65, -47, 46, -41, 40, -48, 7, 45, -95, 127, -99, 43, + -9, -25, 40, -58, 84, -84, 78, -66, 11, 50, -96, 111, -85, 51, -26, -14, + 36, -60, 91, -84, 58, -26, -22, 56, -87, 98, -71, 47, -25, -11, 44, -84, + 103, -92, 69, -32, -3, 25, -59, 87, -90, 70, -45, 17, 16, -57, 81, -73, + 50, -33, 14, 0, -35, 75, -84, 69, -42, 8, 11, -46, 74, -69, 57, -47, + 36, -26, -20, 69, -89, 83, -58, 37, -24, -7, 41, -58, 54, -53, 53, -42, + 14, 28, -54, 52, -55, 46, -41, 22, 30, -57, 58, -64, 56, -54, 26, 31, + -55, 63, -73, 66, -68, 49, -3, -38, 61, -71, 75, -87, 69, -15, -27, 37, + -55, 74, -84, 73, -34, -5, 26, -59, 74, -85, 84, -33, -12, 30, -57, 65, + -85, 86, -40, 9, 15, -50, 69, -94, 93, -53, 15, 11, -38, 58, -86, 96, + -64, 11, 21, -30, 17, -3, -3, 0, 0, -3, -4, -4, -3, -4, -4, -5, + -6, -6, -8, -5, -6, -3, 0, 2, 4, 7, 8, 12, 12, 14, 13, 13, + 12, 8, 7, 2, 2, -4, -6, -10, -11, -12, -12, -14, -10, -9, -3, -3, + 2, 3, 3, 2, 1, 1, -3, -3, -4, -3, -3, -3, -4, 0, -3, -3, + -3, 0, -3, 0, -3, 0, 1, 0, 0, 0, 0, 0, -3, 1, -3, 1, + -3, 2, 1, 0, 0, -3, -4, -5, -9, -10, -15, -16, -17, -17, -14, -10, + -3, 4, 9, 14, 19, 24, 25, 26, 28, 30, 34, 42, 31, 9, -31, -39, + -23, -15, -17, -23, -30, -23, -12, -10, 4, 9, 19, 13, 14, 6, 0, -9, + -11, -12, -9, -8, 0, 0, 2, 1, 1, -3, -3, -5, -3, -5, -3, -4, + 0, -3, -4, -4, -3, -5, -3, -5, -3, 0, 3, 2, 7, 7, 7, 3, + 0, -14, -17, -26, -26, -28, -21, -17, -11, -10, 2, 6, 19, 18, 32, 32, + 60, 69, 98, 60, 7, -58, -8, -8, -14, -39, -30, -14, -47, -21, -45, -3, + 7, 20, 14, 31, 12, 10, -15, -5, -23, -14, -15, -4, -8, 2, 1, 7, + -3, 2, -8, -4, -6, -6, -3, 0, -6, -6, -8, -10, -11, -12, -9, -9, + -4, -3, 0, 8, 10, 12, 15, 13, 4, -10, -15, -30, -32, -30, -23, -22, + -19, -14, -4, 3, 10, 14, 26, 40, 70, 102, 127, 62, -17, -39, 9, -25, + -9, -87, -12, -16, 0, -30, -27, -19, -9, 6, 18, 21, 19, 6, 0, -9, + -17, -14, -16, -8, -6, 0, 4, 4, -5, -4, -11, -3, -6, 2, 2, 0, + -6, 0, -2, -4, -8, -14, -21, -25, -28, -32, -36, -40, -44, -48, -51, -55, + -59, -63, -67, -71, -74, -78, -82, -86, -90, -94, -98, -101, -84, -60, -38, -15, + 8, 28, 27, 23, 19, 16, 11, 21, 46, 68, 93, 109, 106, 102, 98, 95, + 91, 87, 83, 79, 75, 71, 67, 64, 60, 56, 52, 49, 45, 41, 37, 33, + 30, 26, 22, 18, 15, 11, 7, 3, -1, -5, -9, -13, -17, -20, -24, -28, + -32, -35, -39, -43, -47, -51, -54, -58, -62, -66, -69, -73, -77, -81, -85, -89, + -93, -97, -100, -105, -95, -70, -48, -23, -7, -10, -14, -17, -22, -18, 4, 26, + 50, 72, 96, 107, 103, 100, 96, 92, 88, 84, 80, 76, 72, 68, 64, 61, + 57, 53, 49, 46, 42, 38, 34, 30, 26, 23, 19, 15, 11, 8, 4, 0, + -4, -8, -11, -15, -19, -23, -27, -30, -35, -38, -43, -46, -51, -54, -58, -61, + -66, -56, -31, -9, 16, 33, 30, 26, 22, 18, 15, 11, 7, 3, -1, -5, + -9, -13, -16, -20, -24, -28, -32, -36, -40, -43, -48, -51, -55, -59, -63, -50, + -26, -4, 20, 42, 64, 67, 62, 59, 55, 51, 47, 43, 39, 35, 31, 27, + 23, 20, 16, 12, 8, 4, 0, -4, -7, -11, -15, -19, -22, -27, -17, 8, + 30, 55, 72, 69, 65, 61, 57, 54, 50, 46, 42, 38, 34, 30, 26, 22, + 18, 15, 11, 7, 3, 0, -4, -8, -12, -15, -19, -23, -27, -31, -35, -38, + -42, -46, -50, -54, -57, -61, -65, -69, -73, -77, -81, -85, -89, -92, -96, -100, + -100, -79, -64, -47, -31, -15, 0, 0, -4, -3, -6, -8, 6, 10, -8, -13, + 22, 55, 15, -58, -102, -88, -25, 51, 77, 79, 82, 19, -45, -107, -128, -88, + 19, 81, 86, 71, 35, -16, -50, -73, -55, -27, -14, 7, 77, 89, 31, -22, + -27, -61, -86, -34, 40, 55, 67, 80, 57, -1, -48, -60, -41, -46, -31, 28, + 62, 47, 43, 33, -5, -34, -45, -52, -33, 26, 66, 70, 41, 17, -34, -79, + -93, -41, -6, 22, 53, 93, 62, 17, -20, -66, -118, -88, -4, 45, 60, 69, + 67, 2, -72, -109, -95, -78, -7, 67, 101, 78, 69, 19, -56, -110, -89, -64, + -19, 45, 100, 86, 36, -11, -65, -107, -108, -41, 24, 69, 93, 111, 56, -15, + -70, -81, -88, -38, 30, 88, 90, 83, 43, -24, -81, -82, -57, -24, 38, 100, + 115, 70, 26, -25, -75, -108, -66, -20, 29, 71, 105, 67, 7, -46, -67, -83, + -60, 0, 58, 82, 81, 57, -9, -72, -99, -78, -60, -8, 54, 95, 69, 44, + 0, -51, -92, -69, -26, 18, 53, 81, 63, 6, -44, -74, -88, -79, -19, 40, + 75, 75, 72, 18, -42, -80, -74, -69, -25, 32, 76, 66, 39, 5, -41, -82, + -76, -34, 3, 42, 79, 88, 38, -12, -49, -74, -92, -48, 8, 51, 70, 83, + 50, -7, -58, -68, -65, -43, 13, 70, 82, 62, 34, -17, -72, -94, -65, -28, + 17, 69, 101, 71, 25, -21, -60, -88, -66, -13, 37, 62, 82, 68, 11, -47, + -73, -79, -66, -15, 49, 82, 76, 57, 11, -51, -88, -78, -48, -9, 49, 0, + 0, 0, 0, 0, 0, -3, -5, -5, -7, -6, -2, 5, 16, 24, 21, 17, + 12, 3, -10, -31, -44, -47, -42, -28, -2, 26, 29, 36, 35, 1, -26, -39, + -52, -53, -38, -10, -32, -41, -7, 2, 22, 65, 89, 74, 15, -16, -24, 12, + 62, 39, 6, -12, -3, 47, 48, 21, 109, 127, 119, 53, -9, 19, 9, -50, + -55, -43, -71, -46, -5, -2, -20, -12, -9, 12, -27, -66, -50, -8, -19, -58, + -22, -8, -19, -34, -42, 10, 32, -4, 4, 46, 96, 34, -51, -10, -8, -93, + -70, -58, -46, -16, -32, -30, 6, 7, -41, -29, 3, 25, 73, 67, 45, 37, + 30, 83, 0, -31, -4, -50, -28, -41, -75, -110, -53, -13, -3, 22, 14, 14, + 13, 7, 9, 38, 47, 39, 17, -8, 90, 75, -5, -29, -46, -54, -102, -66, + -35, -27, -29, -21, 32, 5, 1, 1, -2, 16, 16, 19, 30, 50, 89, 41, + 6, 40, -10, -15, -41, -46, -43, -77, -100, -100, -48, -37, -26, -4, -9, 0, + 13, 36, 70, 75, 59, 34, 12, -13, -27, 37, 71, 48, 53, 37, 7, 8, + 34, 48, 40, 31, 25, 2, -20, -15, -5, 12, -11, -49, -20, 15, -13, -42, + -29, 16, -6, -58, -28, 17, 12, -20, -11, 16, -3, -37, -14, 3, -32, -10, + 40, 54, 53, 27, -3, -5, -34, -47, -49, -90, -68, -36, -32, -31, -16, 26, + 3, 0, -2, -2, 15, 16, 19, 30, 51, 88, 40, 6, 39, -10, 3, -2, + 11, -7, 23, 19, 74, 39, 32, -13, -21, -7, -39, -44, -128, -58, -21, 52, + -86, -74, -94, 75, 61, 72, -38, 13, 59, 116, 71, -9, -33, -12, 68, -2, + -35, -128, -42, -43, 39, -78, -57, -81, 56, 59, 63, -13, 7, 69, 98, 87, + -13, -9, -24, 70, -11, -23, -128, -42, -48, 28, -68, -61, -69, 34, 64, 46, + 8, -5, 79, 82, 100, -17, 5, -29, 69, -13, -21, -122, -49, -43, 11, -55, + -72, -54, 13, 73, 30, 23, -16, 87, 72, 107, -17, 10, -26, 64, -6, -26, + -109, -61, -31, -6, -40, -86, -41, -4, 80, 17, 31, -22, 88, 70, 106, -10, + 6, -16, 53, 7, -37, -93, -76, -17, -21, -28, -99, -33, -15, 83, 12, 31, + -21, 83, 76, 98, 2, -4, -1, 41, 24, -49, -77, -89, -6, -31, -20, -106, + -32, -19, 79, 14, 23, -15, 71, 87, 87, 17, -16, 13, 30, 39, -57, -67, + -97, -1, -34, -19, -106, -38, -16, 69, 23, 11, -5, 56, 100, 75, 32, -28, + 25, 22, 50, -59, -62, -98, -2, -30, -24, -100, -52, -9, 55, 36, -4, 5, + 41, 112, 67, 43, -34, 30, 21, 55, -53, -65, -93, -11, -18, -34, -88, -69, + 0, 41, 48, -17, 12, 29, 118, 65, 49, -34, 28, 27, 53, -42, -72, -83, + -23, -6, -44, -77, -85, 5, -69, 1, -12, -29, -28, -13, 1, 9, -4, -27, + -18, -5, 11, 65, 87, 54, 59, 66, 30, 12, 8, -6, -7, 4, -7, -39, + -59, -63, -48, -23, -13, -6, 22, 61, 68, 15, -59, -87, -41, 3, 5, -10, + -17, -17, -20, -23, -20, -28, -17, -3, -10, -29, 23, 11, 25, 52, 56, 62, + 80, 54, 22, -15, -31, -38, -5, 11, -9, -7, -36, -44, -6, 52, 127, 26, + -68, -125, -105, 22, 15, -27, -27, 13, 25, 69, 28, -42, -77, -57, -70, 15, + 44, 14, 26, 57, 69, 43, 33, 41, 33, 32, 25, -50, -98, -100, -38, 24, + 7, -35, -38, -2, 76, 64, 15, -79, -93, -50, -12, 27, 45, 32, -4, 23, + 6, -36, -47, -33, -52, -15, 37, 78, 49, 40, 17, 14, 14, 70, 81, 60, + -3, -4, -12, -42, -50, -28, -20, 5, 9, 27, 46, -13, -69, -99, -88, -47, + 5, -4, -10, 17, 39, -12, -8, -21, -16, 22, 9, -9, 1, 15, 15, 33, + 29, 17, 11, 38, 72, 29, -8, -36, -27, -42, 17, -40, 25, 25, 8, -3, + 14, 15, 2, 43, 33, -2, -19, -24, -8, 2, -69, -114, -94, -77, -87, 22, + 27, 19, 24, 57, 121, 94, 40, -27, -29, 4, 28, -12, 5, -21, -28, -18, + 0, -9, 1, 36, 22, 7, 6, 12, 7, 8, 55, 6, -2, -7, -13, -12, + -12, -8, -5, -5, -1, -4, -4, -3, -1, 5, 11, 15, 18, 16, 11, 5, + -5, -12, -16, -17, -14, -10, -7, -3, -2, -3, -3, -5, -3, 2, 9, 18, + 22, 23, 18, 11, -2, -14, -20, -22, -18, -12, -8, -5, -3, -5, -6, -6, + -5, 1, 11, 22, 30, 31, 24, 15, -1, -12, -20, -23, -19, -13, -8, -3, + -3, -2, -6, -8, -9, -5, 6, 21, 32, 35, 29, 19, 1, -15, -27, -29, + -25, -15, -9, -4, -1, -2, -7, -14, -15, -10, 4, 24, 42, 48, 43, 26, + 4, -20, -36, -38, -30, -17, -7, -3, 0, -1, -4, -16, -24, -19, -3, 26, + 49, 61, 60, 40, 9, -23, -45, -52, -39, -22, -5, -2, 1, 3, -2, -18, + -32, -30, -10, 22, 55, 77, 78, 52, 15, -22, -51, -66, -52, -29, -5, 0, + 2, 9, 6, -15, -37, -42, -22, 10, 55, 89, 99, 71, 22, -20, -58, -79, + -68, -35, -8, 6, 1, 12, 13, -9, -37, -50, -35, 0, 46, 93, 116, 90, + 33, -15, -60, -89, -84, -44, -9, 10, 3, 13, 19, -3, -35, -53, -43, -12, + 34, 91, 127, 109, 46, -9, -57, -95, -96, -57, -13, 11, 7, 10, 25, 2, + -2, -35, 0, 2, 7, 12, -7, -79, -68, 2, -6, -5, 19, 40, 33, 55, + 56, 17, 32, 32, 2, -20, 5, 51, 27, -21, -13, -11, -17, -20, -6, -63, + -125, -116, -86, -59, -34, 11, 23, 20, 39, 66, 50, 47, 54, 46, 11, -4, + 44, 67, 30, 11, 16, 6, -2, 7, -4, -77, -114, -107, -70, -50, -20, 29, + 26, 12, 48, 69, 44, 47, 49, 28, -8, 9, 53, 49, 15, 9, 8, -3, + -11, 7, -33, -107, -123, -101, -62, -49, -5, 25, 6, 13, 55, 49, 32, 40, + 39, 7, -17, 18, 49, 32, 7, 8, 1, -12, -3, 7, -62, -113, -109, -74, + -50, -31, 23, 32, 13, 40, 69, 48, 46, 54, 42, 2, 1, 42, 52, 25, + 10, 11, 0, -11, 10, -10, -90, -115, -101, -64, -52, -15, 29, 16, 10, 51, + 59, 41, 46, 49, 25, -9, 15, 48, 42, 15, 10, 7, -9, -7, 16, -43, + -107, -113, -89, -60, -47, 4, 27, 4, 19, 58, 47, 38, 46, 43, 6, -9, + 28, 47, 29, 10, 11, 2, -14, 5, 5, -73, -111, -106, -73, -56, -29, 24, + 22, 6, 40, 61, 43, 43, 52, 37, -3, 6, 41, 47, 23, 12, 11, 0, + -14, 1, 3, 5, 5, 6, 8, 6, 4, 0, -4, -5, -6, -9, -9, -11, + -11, -12, -13, -13, -13, -12, -11, -9, -5, -2, -1, 1, 4, 6, 9, 11, + 12, 12, 11, 8, 5, 2, -2, -2, -2, -2, 0, -1, -1, -2, -5, -5, + -5, -1, 4, 10, 17, 20, 22, 19, 15, 7, -1, -9, -15, -19, -21, -21, + -18, -16, -13, -11, -12, -15, -19, -23, -24, -20, -13, -3, 9, 20, 34, 44, + 50, 46, 35, 21, 7, -4, -14, -20, -19, -13, -8, 2, 0, -5, -15, -28, + -32, -29, -14, 0, 11, 27, 42, 58, 59, 45, 22, 4, -15, -26, -37, -43, + -42, -37, -17, 1, 18, 23, 8, -5, -29, -47, -47, -43, -25, -5, 20, 52, + 80, 92, 76, 43, 9, -20, -35, -38, -46, -41, -29, -12, 19, 35, 22, 4, + -34, -53, -58, -40, -26, -16, 14, 47, 88, 108, 90, 50, 16, -9, -36, -51, + -64, -64, -52, -33, -1, 32, 40, 24, 3, -29, -62, -58, -65, -52, -18, 23, + 68, 114, 127, 95, 41, 1, -36, -54, -56, -68, -55, -35, -17, 19, 42, 29, + 13, -16, -46, -60, -54, -56, -47, -11, 29, 72, 116, 127, 94, 41, -3, 0, + 16, 39, 54, 46, 18, 7, -15, -36, -9, -6, -16, -5, -15, -30, -23, -35, + -20, 22, 3, -19, -20, -13, -9, 19, 23, 10, 12, 35, 66, 54, 4, -43, + -58, -15, -10, 16, 55, 18, -39, -38, -30, 2, 9, 27, 51, -32, -60, -72, + -4, 32, 71, 19, -8, 56, -2, -42, 10, 21, -6, 31, -9, -70, 8, -6, + -19, -93, -20, -5, -31, 10, 5, 56, 24, -45, 11, 66, 48, 61, 89, 49, + -57, -6, -20, -69, -104, -83, -50, 32, 10, -16, -87, -78, 30, 127, 63, -17, + -91, -2, -12, 45, 83, 30, 56, 54, 42, 7, 79, -26, -52, -64, -97, 12, + -3, -107, -99, -39, 34, 86, 19, -25, 25, 90, -8, -38, 65, 36, 10, 30, + 36, 19, -6, 38, -47, -101, -52, -45, 30, -9, -106, 18, -10, -37, 16, 100, + -94, -111, -25, -35, -12, -8, -9, 51, 24, -5, -70, -52, -52, -19, -11, 48, + 93, 61, 17, 113, 125, 73, -16, -30, -57, -78, -116, -55, -38, -10, -5, -4, + 38, 31, -3, -46, -46, -50, -20, -10, 52, 84, 48, 14, 115, 119, 64, -16, + -1, 4, 0, -9, -11, -1, 6, 2, -2, 4, -6, -10, -2, 11, 14, 3, + -10, -15, -1, 17, 4, 6, 4, -12, -18, 6, 10, 4, 6, -8, -36, 2, + 3, 3, 5, 15, -20, -17, 9, 8, 11, 17, -8, -26, 18, 2, 5, 5, + 13, -24, -8, -2, 2, 5, 7, -21, -18, 13, 5, -5, 17, 7, -14, -13, + -12, 0, 14, 3, -12, -26, 13, 3, 10, 18, 12, -15, -14, -1, 3, 19, + 0, -10, -29, 11, 4, 17, 15, 12, -24, -20, 6, 9, 22, -3, -13, -15, + 9, 1, 7, 6, 18, -19, -26, -18, 2, 22, 0, -25, -20, 15, 8, -4, + 8, 31, -12, -20, -15, 9, 33, 9, -29, -2, 27, 7, -11, 8, 20, -20, + -41, -10, 15, 35, 15, -21, 11, 49, 6, -6, 4, 3, -48, -76, -35, 14, + 37, 22, -24, 29, 68, 20, 3, 7, -5, -68, -90, -59, 19, 36, 28, -13, + 59, 93, 30, 2, 18, -25, -88, -105, -81, 13, 26, 30, -4, 88, 109, 33, + 0, 22, -30, -88, -112, -76, 17, 31, 18, 5, 94, 114, 30, -4, 0, 4, + -30, -1, 0, -2, -2, -2, -1, 4, 11, 18, 30, 7, -64, -60, -30, -7, + 0, 2, 22, 67, 117, 23, -128, -74, -30, -5, -2, 1, 19, 62, 116, 38, + -123, -82, -31, -8, -1, -1, 16, 57, 114, 52, -117, -88, -33, -10, -2, -3, + 14, 52, 112, 64, -108, -96, -35, -13, -2, -4, 12, 49, 108, 77, -99, -102, + -37, -15, -2, -5, 10, 43, 104, 86, -87, -109, -40, -18, -2, -6, 8, 40, + 100, 95, -73, -115, -42, -21, -2, -8, 7, 35, 95, 102, -59, -120, -45, -24, + -2, -8, 5, 32, 90, 109, -44, -124, -49, -26, -3, -9, 3, 28, 85, 114, + -29, -126, -53, -28, -4, -9, 2, 25, 81, 116, -13, -127, -58, -29, -6, -9, + 0, 22, 75, 119, 3, -126, -63, -31, -7, -9, -2, 19, 70, 120, 18, -124, + -69, -32, -9, -9, -3, 16, 65, 119, 34, -63, -107, -58, -23, -11, -7, 7, + 46, 107, 89, -52, -109, -62, -25, -12, -8, 5, 42, 104, 97, -41, -87, -70, + -36, -18, -11, 0, 30, 85, 100, -2, -87, -5, 11, -23, -10, -3, -20, -3, + -17, -24, -33, -26, -1, -13, -12, -6, -9, 6, 25, 19, -7, -1, 22, -6, + -20, 13, 6, -12, 26, 48, 0, -7, 34, 23, 4, 32, 23, -41, -11, 49, + -3, -30, 35, 45, -14, -2, 62, 18, -44, -2, 26, -4, -28, -6, 16, 2, + -9, -9, 2, 18, 24, 9, -25, -57, -36, 30, 38, -21, -63, -37, 9, 37, + 40, 0, -56, -56, 3, 39, 20, -23, -52, -58, -46, 8, 67, 56, -18, -61, + -18, 36, 70, 95, 73, -35, -128, -127, -73, -17, 32, 48, 29, 28, 60, 106, + 113, 91, 36, -26, -67, -90, -91, -71, -44, -25, -13, 9, 36, 51, 69, 70, + 32, -40, -92, -99, -70, -25, 12, 29, 21, 3, -9, 10, 21, 12, -11, -22, + -27, -44, -23, 10, 30, 25, 24, 39, 18, 3, 8, 19, -1, -19, -8, 6, + 5, 13, 50, 43, 37, 36, 40, 37, 4, 12, -10, -33, -31, -25, -1, 1, + 7, 14, 10, -4, -11, -10, -6, -19, -42, -28, -54, -51, -18, -5, 3, 2, + -10, -10, 10, 28, 27, 16, 5, -5, -24, -26, -7, -14, -25, -16, 53, 33, + -49, -30, 53, 50, -24, -34, 40, 82, -118, -23, 120, -56, -70, -72, 106, -10, + -48, 3, 87, 28, -126, -16, 81, 4, -84, -51, 38, 62, -32, 36, 84, -12, + -41, 72, -42, -60, -64, 4, 77, -24, -79, -9, 122, 6, -94, 52, 43, 35, + 13, -62, -7, -89, 24, -30, 16, 29, 56, -59, 83, 42, 31, 36, -76, -2, + -128, -2, 45, 27, -104, -31, 66, 21, 19, 36, 121, 11, -76, -26, -93, 34, + 24, -34, -65, -53, 53, 17, 73, 46, 75, -9, -64, -21, -103, 41, 51, -41, + -83, -43, 108, 6, -11, 28, 127, 2, -84, -38, -72, 39, 17, -23, -15, -67, + 37, 6, 29, 64, 79, 17, -39, -39, -120, 55, 23, -17, -62, -51, 81, 23, + 20, 24, 99, -38, -99, 4, 17, -66, -41, -33, 63, 62, 16, 53, 91, 56, + -65, -36, -99, -38, 14, -47, -29, -38, 35, 83, 9, 48, 83, 62, -45, -31, + -103, -49, 14, 2, 6, -33, 33, -4, -1, 34, -93, 60, -49, 68, -21, 41, + -38, -38, 27, -87, 127, -34, 38, -3, -34, -2, -85, 79, -24, 4, 75, -23, + 11, -70, 1, -6, -6, 63, -48, 76, -71, 2, -7, -15, 46, -32, 48, -25, + -5, 10, -31, 18, -23, 5, 6, 17, 11, 3, 24, -46, -21, -1, -5, 31, + 1, 36, -23, -11, -4, -29, 14, -5, 29, 9, -2, -2, -20, -2, -15, 13, + 7, 4, 15, -11, 4, -13, -1, 1, -13, 15, -6, 9, 9, -2, -4, -11, + -2, -11, 7, 12, 9, 5, -6, -6, -16, -2, 3, 6, 13, 1, 7, -14, + -3, -11, -1, 8, 0, 18, -3, -3, -6, -13, 0, 4, 2, 9, 2, 2, + -6, -4, -1, -8, 2, 4, 2, 7, -4, 2, 1, -7, -3, -2, 0, 2, + 8, -2, 2, -1, -7, -3, -1, 3, 4, 3, 3, -3, -4, -4, 0, 2, + 1, 5, -1, -2, 1, -4, -1, 1, 0, 2, -5, -8, -3, -3, -9, -2, + -2, 5, 10, 16, 11, 5, -3, -5, -1, -4, -6, -7, -15, -18, -27, -31, + -21, -11, 22, 56, 90, 66, -17, -25, -25, 0, -12, -15, -25, -32, -39, -37, + -26, 6, 33, 65, 69, 44, -1, -13, -12, 1, 0, -9, -14, -22, -40, -44, + -42, -23, 8, 39, 60, 84, 57, -16, -25, -19, 2, -8, -11, -18, -32, -51, + -45, -32, -6, 28, 54, 85, 96, -5, -29, -23, -7, -10, -17, -16, -28, -53, + -44, -40, -7, 22, 52, 82, 112, 17, -37, -25, -20, -11, -18, -10, -23, -33, + -51, -40, -23, 10, 45, 65, 96, 64, -21, -35, -34, -19, -20, -13, -5, -14, + -35, -41, -39, -17, 9, 45, 58, 82, 98, -2, -57, -47, -23, -12, -11, -2, + -18, -28, -39, -36, -24, -1, 26, 57, 84, 121, 23, -65, -50, -40, -12, -11, + -4, -14, -20, -34, -32, -27, -5, 19, 56, 80, 127, 15, -66, -50, -2, -5, + -5, 2, 10, 8, -7, -16, -9, 6, 17, 8, -19, -20, 14, 38, 34, 20, + -5, 1, 50, 37, -50, -54, -66, -32, 32, -3, -13, -18, -17, 46, 89, -17, + -62, 45, 127, 57, -57, -67, -109, -11, 88, -31, -90, -88, -27, 63, 97, -27, + -105, -44, 65, 110, 60, -12, -30, -27, 17, 49, -2, -39, -6, 30, -16, -36, + -43, 32, 67, -54, -58, -38, -21, 47, 95, 76, -33, -78, -62, 10, 107, 24, + -106, -107, 12, 52, 27, 78, 8, -75, 25, 6, -26, 59, 32, -17, -7, -19, + 11, 32, -51, -52, 41, -9, -13, 94, 2, -65, 5, -46, -86, 34, 62, 85, + 29, -93, -89, -29, 44, 35, -31, -33, -19, 56, 127, 7, -9, -62, -52, 23, + 46, 44, -56, -16, -55, -46, 22, 83, -13, -42, -7, 13, 81, 49, 3, -9, + -30, -47, -30, 3, 23, 6, -7, -20, -44, 10, 96, -13, 0, 16, 31, 47, + 61, 75, 87, 98, 107, 115, 121, 125, 127, 127, 125, 121, 116, 108, 99, 88, + 75, 62, 47, 32, 16, 0, -16, -31, -47, -61, -75, -87, -98, -108, -116, -122, + -126, -128, -128, -126, -123, -117, -109, -100, -89, -77, -64, -49, -34, -18, -2, 14, + 29, 45, 59, 73, 86, 97, 106, 114, 121, 125, 127, 127, 126, 122, 116, 109, + 100, 89, 77, 63, 49, 34, 18, 2, -14, -30, -45, -60, -73, -86, -97, -107, + -115, -121, -126, -128, -128, -127, -123, -118, -110, -101, -91, -79, -65, -51, -36, -20, + -4, 12, 28, 43, 58, 72, 84, 96, 106, 114, 120, 124, 127, 127, 126, 122, + 117, 109, 100, 90, 78, 64, 50, 35, 19, 3, -13, -29, -44, -59, -73, -85, + -97, -107, -115, -121, -125, -128, -128, -127, -123, -118, -110, -101, -91, -79, -65, -51, + -36, -20, -4, 12, 2, 5, 5, 0, -16, -9, -2, -19, 4, 18, 6, 10, + -16, -21, 22, -2, 3, -7, 21, 43, -57, -37, 46, -39, -31, 78, 23, -23, + -10, -10, -7, -52, 44, 50, -44, 9, -9, -46, 47, 12, -75, 40, 45, 32, + -10, -25, -15, -45, 24, 44, -40, -10, 18, -48, -29, 63, 44, -30, -1, 83, + -45, -94, 96, 0, -103, 21, 29, -42, 21, 80, -25, -15, 26, 39, -79, -18, + 73, -111, -45, 61, 29, 55, -22, -77, 40, 9, -72, 78, 35, -1, -1, -69, + 12, -50, -42, 123, 45, -7, -39, -86, 3, 51, 30, 28, -4, -33, -41, -66, + 54, -8, -30, 127, -7, -30, -32, -39, 48, -65, 20, 121, -33, -14, -53, -32, + 46, -24, 36, 98, -49, -39, -61, 1, 49, -54, 65, 59, -83, -11, -49, 32, + 39, -72, 113, 59, -83, -11, -49, 32, 39, -72, 113, 59, -2, -4, -4, -7, + -8, -8, -7, -4, -3, -2, 1, 4, 6, 6, 6, 4, 2, 0, -2, -3, + -4, -7, -7, -5, -3, 0, 4, 9, 11, 11, 9, 7, 4, 1, -3, -7, + -9, -12, -13, -16, -19, -19, -13, -2, 9, 17, 19, 20, 18, 13, 8, 3, + 0, -2, -3, -8, -14, -21, -25, -21, -9, 4, 15, 23, 28, 25, 20, 9, + -7, -21, -14, 3, 3, -18, -38, -49, -32, -7, 8, 14, 26, 37, 42, 37, + 26, 7, -18, -27, -5, 8, -7, -24, -34, -40, -32, -19, 1, 17, 42, 56, + 58, 40, -19, -81, 1, 67, 0, -60, -49, -27, -24, 0, -18, -24, -8, 37, + 67, 70, 59, 34, -42, -81, 7, 51, -12, -54, -37, -14, -25, -14, -16, -24, + 4, 55, 75, 102, 52, -102, -104, 90, 30, -48, -76, 1, -14, 0, -2, -2, + -3, -5, -7, -8, -8, -7, -6, -4, -2, 0, 1, 3, 4, 6, 6, 6, + 6, 5, 4, 3, 1, 0, 0, -3, -4, -7, -10, -11, -11, -8, -6, 1, + 5, 6, 8, 11, 11, 8, 5, 5, 2, 1, 0, 0, -2, 1, -4, -16, + -36, -27, -5, 6, -3, -6, 0, -6, 2, 27, 24, 19, 16, 9, 3, 0, + -4, 2, 1, 9, 19, -14, -79, -32, 22, -4, -22, -14, 25, 8, -11, 13, + 28, 16, 19, 16, 1, -2, -4, -3, -6, 28, 38, -59, -111, 25, 16, -16, + -40, 16, 24, -20, 4, 24, 29, 17, 27, 13, 1, -10, -6, -10, -8, 43, + 61, -68, -128, 28, 12, -15, -39, 12, 21, -28, 12, 37, 25, 12, 27, 11, + 0, -16, -2, -12, -11, 52, 67, -68, 35, 54, 47, 4, -60, -92, -68, -27, + 0, -2, -18, -20, -6, 2, -8, -15, -11, -3, 3, -7, -11, -6, -2, 7, + 15, 18, 19, 22, 27, 40, 40, 29, 20, 24, 28, 34, 30, 25, 32, 20, + 14, 9, 16, 19, 17, 6, -1, 3, -6, -14, -23, -18, -7, 1, -18, -18, + -24, -25, -24, -35, -35, -35, -21, -12, -14, -21, -17, -29, -24, -31, -34, -9, + -11, -9, -3, -7, -7, 6, -17, -22, 7, 16, 14, -4, -11, 10, 33, 24, + 21, 27, 3, -19, -25, -18, 17, 50, 48, 49, 61, 31, -48, -103, -73, 9, + 56, 70, 82, 109, 127, 71, -46, -127, -96, -30, -4, 9, 47, 103, 117, 60, + -39, -110, -119, -94, -64, -40, -4, 35, -8, -14, -9, -5, -4, -3, 6, 18, + 19, 6, -14, -20, -12, -3, -3, -6, 2, 21, 28, 13, -16, -26, -14, -6, + -6, -7, 1, 27, 36, 18, -15, -27, -15, -3, -2, -10, -6, 25, 41, 22, + -17, -34, -18, -4, -3, -16, -12, 29, 56, 31, -24, -44, -20, -4, -1, -19, + -22, 31, 73, 47, -27, -62, -25, -2, 4, -21, -36, 26, 91, 61, -27, -79, + -33, 0, 10, -18, -49, 14, 106, 82, -24, -94, -40, 8, 14, -12, -59, 1, + 112, 105, -19, -106, -51, 12, 16, -4, -63, -13, 110, 127, -12, -114, -51, 0, + -1, -4, -8, -11, -8, -2, 0, 7, 14, 21, 46, 92, 120, 76, -36, -121, + -119, -73, -31, -7, 3, 2, -4, -6, 2, 22, 60, 106, 116, 43, -72, -128, + -105, -57, -21, -3, 3, -1, -6, -5, 7, 33, 76, 117, 102, 5, -100, -127, + -89, -43, -13, 0, 2, -3, -7, -2, 14, 46, 92, 122, 79, -34, -118, -118, + -72, -31, -8, 1, 0, -5, -7, 2, 23, 61, 107, 118, 46, -69, -126, -104, + -56, -21, -4, 1, 0, -4, -5, 0, 16, 48, 87, 103, 60, -25, -87, -94, + -58, -20, -4, -11, 12, 24, 31, -36, 29, -9, 2, -38, -5, -5, -10, -33, + -10, -24, -20, -39, -36, -18, -38, -58, -5, -22, -15, -15, 90, -42, -3, -8, + 25, 6, 28, 25, 17, 25, -16, 28, 80, 22, 12, -6, 35, 22, 8, -7, + 28, 29, -19, 7, 8, -1, -29, -23, 10, -23, -13, -26, -17, -20, -33, -41, + -19, -28, -64, -13, -21, -13, -29, 54, 25, -20, -36, 42, -4, 13, 52, -8, + 47, -14, 9, 42, 88, -12, 20, -5, 43, 22, -11, 127, 127, -128, -128, -128, + -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, + -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, + -128, -128, -128, -128, -128, -128, -128, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, -128, 1, 4, 7, 10, 12, 16, 19, 22, 25, 28, 31, 35, 38, 42, + 45, 49, 51, 56, 58, 63, 65, 70, 73, 78, 80, 85, 87, 93, 95, 100, + 102, 108, 109, 117, 114, 127, 85, -63, -60, -64, -60, -62, -59, -61, -59, -61, + -58, -60, -58, -59, -58, -58, -57, -57, -55, -55, -54, -54, -52, -51, -50, -49, + -47, -46, -44, -43, -41, -40, -37, -36, -34, -32, -30, -28, -25, -24, -21, -19, + -16, -14, -11, -9, -6, 1, 1, 4, 7, 10, 12, 16, 19, 22, 25, 28, + 31, 35, 38, 42, 45, 49, 51, 56, 58, 63, 65, 70, 73, 78, 80, 85, + 87, 93, 95, 100, 102, 108, 109, 117, 114, 127, 85, -63, -60, -64, -60, -62, + -59, -61, -59, -61, -58, -60, -58, -59, -58, -58, -57, -57, -55, -55, -54, -54, + -52, -51, -50, -49, -47, -46, -44, -43, -41, -40, -37, -36, -34, -32, -30, -28, + -25, -24, -21, -19, -16, -14, -11, -9, -6, 1, -3, -19, -24, -14, -8, -19, + -12, -10, -5, -12, -50, -19, 23, 35, 4, -20, -7, -26, 9, 40, 69, 16, + -88, -69, -38, -32, -27, 41, 65, 55, 18, -40, -38, -20, 66, 127, 121, 57, + -23, -55, -48, 13, 53, 31, -20, -38, -13, 10, 8, 0, 12, 17, 13, 2, + -1, -3, -3, 6, 13, 7, -17, -24, -12, 4, 3, -10, -20, -32, -22, -18, + -12, -3, 6, 16, 22, 29, 30, 27, 20, 11, 0, -7, -12, -11, -5, 0, + -3, -14, -20, -16, -9, -9, -17, -25, -29, -31, -33, -35, -33, -29, -25, -22, + -20, -17, -14, -13, -12, -11, -9, -10, -13, -15, -11, -5, 3, 9, 10, 9, + 9, 12, 18, 30, 50, 80, 119, 127, 102, 82, 77, 60, 37, 5, -34, -70, + -84, -83, -74, -60, -46, -29, -12, -2, 6, -23, 28, -20, 50, 50, -14, 14, + -28, -2, 28, 52, -25, -13, -52, 43, -41, -9, -26, 36, -25, -20, -17, 3, + -11, 38, 30, -61, 12, -6, 5, 45, 41, -4, 4, -20, -12, 45, 33, -11, + -29, -44, 27, -17, -36, -1, 17, -11, -31, -12, 4, -10, 37, 20, -39, -23, + 0, -104, -55, -11, 24, 33, 30, 7, -15, -31, -30, -25, -23, -20, -9, 10, + 31, 59, 91, 111, 115, 92, 51, 7, -33, -64, -81, -81, -71, -51, -22, 16, + 52, 74, 82, 81, 68, 38, 0, -40, -81, -112, -124, -102, -57, -11, 0, 7, + -23, -58, -85, -100, -104, -100, -92, -81, -69, -57, -45, -33, -22, -11, -1, 8, + 18, 27, 37, 49, 62, 79, 99, 118, 124, 111, 84, 53, 26, 5, -8, -14, + -15, -12, -6, 2, 12, 21, 28, 26, 9, -22, -58, -20, 7, 10, 21, -14, + 9, 22, 57, 62, 127, 56, 28, 26, -28, 10, -81, -31, -81, -35, -19, -55, + -27, -4, -4, 23, 49, 88, 85, 22, 1, 0, -3, 18, -22, -12, -39, -14, + -47, -67, -53, -53, -33, -20, 8, -22, 25, 30, 6, -19, -62, -19, 10, 83, + 57, -67, -88, -52, 63, 127, 42, -63, -121, -70, 82, 111, 46, -43, -114, -35, + 45, 73, 39, -19, -54, -41, 9, 49, 24, -16, -14, -9, -6, 10, 8, -22, + 25, 30, 6, -19, -62, -19, 10, 83, 57, -67, -88, -52, 63, 127, 42, -63, + -121, -70, 82, 111, 46, -43, -114, -35, 45, 73, 39, -19, -54, -41, 9, 49, + 24, -16, -14, -9, -6, 10, 8, -22, 25, 30, 6, -19, -62, -19, 10, 83, + 57, -67, -88, -52, 63, 127, 42, -63, -121, -70, 82, 111, 46, -43, -114, -35, + 45, 73, 39, -19, -54, -41, 9, 49, 24, -16, -14, -9, -6, 10, -18, -15, + 80, 127, 20, 18, 72, 60, -36, 22, 33, -73, -105, -27, 29, 25, 8, 43, + 23, -22, -35, -14, -8, -34, -25, -5, -18, -46, -13, -28, -3, -19, -10, -28, + -10, 17, -18, 96, 127, 123, 127, 126, 126, 95, 61, 22, -17, -56, -95, -118, + -123, -128, -128, -128, -128, -128, -128, -128, -128, -124, -93, -55, -17, 25, 62, 100, + 107, 119, 119, 127, 41, -4, -4, -10, -27, -62, -102, -128, -117, -85, -76, -49, + -25, -7, 15, 24, 14, 0, -9, -12, -3, 33, 81, 105, 111, 101, 80, 62, + 45, 30, 16, 8, 1, -4, 126, 86, -44, -68, -88, -63, 4, 84, 127, 14, + -29, -51, -127, -47, 58, 87, 82, 24, -17, -112, -113, 18, 46, 72, 102, 19, + -72, -118, -51, 9, 27, 126, 19, -53, -114, -108, 15, 122, 111, 21, -71, -70, + 5, 59, 83, 23, -72, -84, -49, 12, 37, 38, -28, -65, -26, 7, -2, 11, + 5, 23, 68, 19, 27, -54, 15, -24, -31, 46, 71, 81, -24, -33, -87, -41, + -71, -61, -70, -36, -44, -3, 12, -25, -20, 20, 68, 85, 127, 15, 50, -5, + 27, 51, 82, 106, 127, 118, 101, 92, 74, 52, 39, 37, 14, -41, -105, -108, + -94, -119, -124, -93, -57, -40, -37, -45, -51, -41, -5, 51, 127, 127, -128, -128, + -128, -128, -128, -128, -128, -128, -128, -128, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127 +}; + +const EAS_U32 eas_sampleLengths[] = +{ + 16820, 16708, 16592, 11754, 10954, 10295, 9922, 7489, + 5779, 5462, 4452, 3779, 3115, 3093, 3057, 3024, + 2818, 2776, 2171, 2168, 2052, 1902, 1835, 1614, + 1603, 1528, 1517, 1480, 1455, 1424, 1387, 1302, + 1262, 1254, 1230, 1227, 1185, 1181, 1178, 1168, + 1132, 1120, 1034, 1033, 1018, 994, 964, 926, + 907, 886, 881, 866, 830, 817, 816, 813, + 749, 748, 739, 720, 652, 610, 610, 583, + 564, 561, 556, 549, 542, 535, 530, 530, + 516, 508, 492, 478, 461, 448, 437, 431, + 423, 418, 403, 402, 400, 394, 387, 387, + 367, 357, 347, 347, 341, 336, 334, 329, + 325, 312, 294, 284, 277, 265, 255, 233, + 230, 213, 207, 205, 194, 193, 184, 181, + 181, 167, 164, 158, 152, 152, 145, 139, + 128, 103, 100, 88, 87, 84, 84, 72, + 71, 55, 46, 45, 43, 40, 40, 40, + 37, 35, 32, 32, 30, 29, 27, 23, + 22, 21, 21, 21, 21, 20 +}; + +const EAS_U32 eas_sampleOffsets[] = +{ + 0x00000000, 0x000041b4, 0x000082f8, 0x0000c3c8, 0x0000f1b2, 0x00011c7c, 0x000144b3, 0x00016b75, + 0x000188b6, 0x00019f49, 0x0001b49f, 0x0001c603, 0x0001d4c6, 0x0001e0f1, 0x0001ed06, 0x0001f8f7, + 0x000204c7, 0x00020fc9, 0x00021aa1, 0x0002231c, 0x00022b94, 0x00023398, 0x00023b06, 0x00024231, + 0x0002487f, 0x00024ec2, 0x000254ba, 0x00025aa7, 0x0002606f, 0x0002661e, 0x00026bae, 0x00027119, + 0x0002762f, 0x00027b1d, 0x00028003, 0x000284d1, 0x0002899c, 0x00028e3d, 0x000292da, 0x00029774, + 0x00029c04, 0x0002a070, 0x0002a4d0, 0x0002a8da, 0x0002ace3, 0x0002b0dd, 0x0002b4bf, 0x0002b883, + 0x0002bc21, 0x0002bfac, 0x0002c322, 0x0002c693, 0x0002c9f5, 0x0002cd33, 0x0002d064, 0x0002d394, + 0x0002d6c1, 0x0002d9ae, 0x0002dc9a, 0x0002df7d, 0x0002e24d, 0x0002e4d9, 0x0002e73b, 0x0002e99d, + 0x0002ebe4, 0x0002ee18, 0x0002f049, 0x0002f275, 0x0002f49a, 0x0002f6b8, 0x0002f8cf, 0x0002fae1, + 0x0002fcf3, 0x0002fef7, 0x000300f3, 0x000302df, 0x000304bd, 0x0003068a, 0x0003084a, 0x000309ff, + 0x00030bae, 0x00030d55, 0x00030ef7, 0x0003108a, 0x0003121c, 0x000313ac, 0x00031536, 0x000316b9, + 0x0003183c, 0x000319ab, 0x00031b10, 0x00031c6b, 0x00031dc6, 0x00031f1b, 0x0003206b, 0x000321b9, + 0x00032302, 0x00032447, 0x0003257f, 0x000326a5, 0x000327c1, 0x000328d6, 0x000329df, 0x00032ade, + 0x00032bc7, 0x00032cad, 0x00032d82, 0x00032e51, 0x00032f1e, 0x00032fe0, 0x000330a1, 0x00033159, + 0x0003320e, 0x000332c3, 0x0003336a, 0x0003340e, 0x000334ac, 0x00033544, 0x000335dc, 0x0003366d, + 0x000336f8, 0x00033778, 0x000337df, 0x00033843, 0x0003389b, 0x000338f2, 0x00033946, 0x0003399a, + 0x000339e2, 0x00033a29, 0x00033a60, 0x00033a8e, 0x00033abb, 0x00033ae6, 0x00033b0e, 0x00033b36, + 0x00033b5e, 0x00033b83, 0x00033ba6, 0x00033bc6, 0x00033be6, 0x00033c04, 0x00033c21, 0x00033c3c, + 0x00033c53, 0x00033c69, 0x00033c7e, 0x00033c93, 0x00033ca8, 0x00033cbd +}; + +/*---------------------------------------------------------------------------- + * S_EAS + *---------------------------------------------------------------------------- +*/ +const S_EAS easSoundLib = +{ + 0x01534145, + 0x0010ac44, + eas_banks, + eas_programs, + eas_regions, + eas_articulations, + eas_sampleLengths, + eas_sampleOffsets, + eas_samples, + 0, + 1, + 1, + 377, + 185, + 150, + 0 +}; /* end S_EAS */ + +/*---------------------------------------------------------------------------- + * Statistics + * + * Number of banks: 1 + * Number of programs: 1 + * Number of regions: 377 + * Number of articulations: 185 + * Number of samples: 150 + * Size of sample pool: 212050 + *---------------------------------------------------------------------------- +*/ +/* end wt_200k_G_MAC.c */ diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib/libarm-wt-22k.a b/common/embeddedaudiosynthesis/arm-wt-22k/lib/libarm-wt-22k.a new file mode 100755 index 0000000..b130714 Binary files /dev/null and b/common/embeddedaudiosynthesis/arm-wt-22k/lib/libarm-wt-22k.a differ diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/ARM-E_filter_gnu.s b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/ARM-E_filter_gnu.s new file mode 100755 index 0000000..871cd7d --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/ARM-E_filter_gnu.s @@ -0,0 +1,134 @@ +@*********************************************************** +@ Function: WT_VoiceFilter +@ Processor: ARM +@ Description: +@ Implements a 2-pole low-pass filter with resonanance +@ +@ Usage: +@ void WT_VoiceFilter( +@ S_FILTER CONTROL *pFilter, +@ S_WT_FRAME *pWTFrame); +@ +@ Copyright 2005 Sonic Network, Inc. +@**************************************************************** +@ Revision Control: +@ $Revision: 496 $ +@ $Date: 2006-12-11 14:33:26 -0800 (Mon, 11 Dec 2006) $ +@**************************************************************** +@ +@ where: +@ S_FILTER_CONTROL *pFilter +@ PASSED IN: r0 +@ +@ S_WT_FRAME *pWTFrame +@ PASSED IN: r1 +@**************************************************************** + + .include "ARM_synth_constants_gnu.inc" + + .arm + .text + + + .global WT_VoiceFilter + + +@ Register usage +@ -------------- +pFilter .req r0 +pWTFrame .req r1 +pBuffer .req r2 +numSamples .req r3 + +z1 .req r4 +z2 .req r5 +b1 .req r6 +b2 .req r7 +K .req r8 + +tmp0 .req r1 @ reuse register +tmp1 .req r9 +tmp2 .req r10 + + +@SaveRegs RLIST {r4-r10, lr} +@RestoreRegs RLIST {r4-r10, pc} + + + .func WT_VoiceFilter +WT_VoiceFilter: + + STMFD sp!, {r4-r10, lr} + +@ +@ Setup passed parameters in their destination registers +@---------------------------------------------------------------- + + LDR pBuffer, [pWTFrame, #m_pAudioBuffer] + LDR numSamples, [pWTFrame, #m_numSamples] + + @load state variables from pFilter structure + LDRSH z1, [pFilter, #m_z1] + LDRSH z2, [pFilter, #m_z2] + + @load coefficients from pWTFrame structure + LDR K, [pWTFrame, #m_k] + LDR b1, [pWTFrame, #m_b1] + LDR b2, [pWTFrame, #m_b2] + + RSB b1, b1, #0 @ b1 = -b1 + RSB b2, b2, #0 @ b2 = -b2 + MOV b2, b2, ASR #1 @ b2 = b2 >> 1 + MOV K, K, ASR #1 @ K = K >> 1 + +@ +@ Start processing +@---------------------------------------------------------------- + + LDRSH tmp0, [pBuffer] @ fetch sample + +FilterLoop: + SMULBB tmp2, z1, b1 @ tmp2 = z1 * -b1 + SMLABB tmp2, z2, b2, tmp2 @ tmp2 = (-b1 * z1) + (-b2 * z2) + + MOV z2, z1 @ delay line + + SMLABB tmp0, tmp0, K, tmp2 @ tmp1 = (K * x[n]) + (-b1 * z1) + (-b2 * z2) + + LDRSH tmp1, [pBuffer, #NEXT_OUTPUT_PCM] @ fetch next sample + + MOV z1, tmp0, ASR #14 @ shift result to low word + STRH z1, [pBuffer], #NEXT_OUTPUT_PCM @ write back to buffer + + SMULBB tmp2, z1, b1 @ tmp2 = z1 * -b1 + + SUBS numSamples, numSamples, #2 @ unroll loop once + + SMLABB tmp2, z2, b2, tmp2 @ tmp2 = (-b1 * z1) + (-b2 * z2) + + SMLABB tmp1, tmp1, K, tmp2 @ tmp1 = (K * x[n]) + (-b1 * z1) + (-b2 * z2) + + MOV z2, z1 @ delay line + + MOV z1, tmp1, ASR #14 @ shift result to low word + + LDRGTSH tmp0, [pBuffer, #NEXT_OUTPUT_PCM] @ fetch next sample + + STRH z1, [pBuffer], #NEXT_OUTPUT_PCM @ write back to buffer + + BGT FilterLoop +@ save z terms +@---------------------------------------------------------------- + + STRH z1, [pFilter, #m_z1] + STRH z2, [pFilter, #m_z2] + +@ Return to calling function +@---------------------------------------------------------------- + + LDMFD sp!,{r4-r10, lr} + BX lr + + .endfunc + .end + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/ARM-E_interpolate_loop_gnu.s b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/ARM-E_interpolate_loop_gnu.s new file mode 100755 index 0000000..847a7f0 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/ARM-E_interpolate_loop_gnu.s @@ -0,0 +1,131 @@ +@*********************************************************** +@ Function: WT_Interpolate +@ Processor: ARM-E +@ Description: the main synthesis function when fetching +@ wavetable samples. +@ C-callable. +@ +@ Usage: +@ void WT_Interpolate( +@ S_WT_VOICE *pWTVoice, +@ S_WT_FRAME *pWTFrame); +@ +@ Copyright Sonic Network Inc. 2004 +@**************************************************************** +@ Revision Control: +@ $Revision: 496 $ +@ $Date: 2006-12-11 14:33:26 -0800 (Mon, 11 Dec 2006) $ +@**************************************************************** +@ +@ where: +@ S_WT_VOICE *pWTVoice +@ PASSED IN: r0 +@ +@ S_WT_FRAME *pWTFrame; +@ PASSED IN: r1 +@**************************************************************** + + .include "ARM_synth_constants_gnu.inc" + + .arm + .text + + .global WT_Interpolate + + +@ Register usage +@ -------------- +pWTVoice .req r0 +pWTFrame .req r1 + +numSamples .req r2 +phaseIncrement .req r3 +pOutputBuffer .req r4 + +tmp0 .req r1 @reuse register +tmp1 .req r5 +tmp2 .req r6 + +pLoopEnd .req r7 +pLoopStart .req r8 + +pPhaseAccum .req r9 +phaseFrac .req r10 +phaseFracMask .req r11 + +@SaveRegs RLIST {r4-r11,lr} +@RestoreRegs RLIST {r4-r11,pc} + + .func WT_Interpolate +WT_Interpolate: + + STMFD sp!,{r4-r11,lr} + +@ +@ Fetch parameters from structures +@---------------------------------------------------------------- + + LDR pOutputBuffer, [pWTFrame, #m_pAudioBuffer] + LDR numSamples, [pWTFrame, #m_numSamples] + + LDR phaseIncrement, [pWTFrame, #m_phaseIncrement] + LDR pPhaseAccum, [pWTVoice, #m_pPhaseAccum] + LDR phaseFrac, [pWTVoice, #m_phaseFrac] + LDR phaseFracMask,=PHASE_FRAC_MASK + + LDR pLoopStart, [pWTVoice, #m_pLoopStart] + LDR pLoopEnd, [pWTVoice, #m_pLoopEnd] + ADD pLoopEnd, pLoopEnd, #1 @ need loop end to equal last sample + 1 + +InterpolationLoop: + SUBS tmp0, pPhaseAccum, pLoopEnd @ check for loop end + ADDGE pPhaseAccum, pLoopStart, tmp0 @ loop back to start + + .ifdef SAMPLES_8_BIT + LDRSB tmp0, [pPhaseAccum] @ tmp0 = x0 + LDRSB tmp1, [pPhaseAccum, #1] @ tmp1 = x1 + .else + LDRSH tmp0, [pPhaseAccum] @ tmp0 = x0 + LDRSH tmp1, [pPhaseAccum, #2] @ tmp1 = x1 + .endif + + ADD tmp2, phaseIncrement, phaseFrac @ increment pointer here to avoid pipeline stall + + SUB tmp1, tmp1, tmp0 @ tmp1 = x1 - x0 + SMULBB tmp1, phaseFrac, tmp1 @ tmp1 = phaseFrac * tmp2 + +@ This section performs a gain adjustment of -12dB for 16-bit samples +@ or +36dB for 8-bit samples. For a high quality synthesizer, the output +@ can be set to full scale, however if the filter is used, it can overflow +@ with certain coefficients and signal sources. In this case, either a +@ saturation operation should take in the filter before scaling back to +@ 16 bits or the signal path should be increased to 18 bits or more. + + .ifdef SAMPLES_8_BIT + MOV tmp0, tmp0, LSL #6 @ boost 8-bit signal by 36dB + .else + MOV tmp0, tmp0, ASR #2 @ reduce 16-bit signal by 12dB + .endif + + ADD tmp1, tmp0, tmp1, ASR #(NUM_EG1_FRAC_BITS-6) @ tmp1 = tmp0 + (tmp1 >> (15-6)) + @ = x0 + f * (x1 - x0) == interpolated result + + STRH tmp1, [pOutputBuffer], #NEXT_OUTPUT_PCM @ *pOutputBuffer++ = interpolated result + +@ carry overflow from fraction to integer portion + ADD pPhaseAccum, pPhaseAccum, tmp2, LSR #(NUM_PHASE_FRAC_BITS - NEXT_INPUT_PCM_SHIFT) + AND phaseFrac, tmp2, phaseFracMask @ nphaseFrac = frac part + + SUBS numSamples, numSamples, #1 + BGT InterpolationLoop + +@ update and store phase + STR pPhaseAccum, [pWTVoice, #m_pPhaseAccum] + STR phaseFrac, [pWTVoice, #m_phaseFrac] + + LDMFD sp!,{r4-r11,lr} + BX lr + + .endfunc + .end + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/ARM-E_interpolate_noloop_gnu.s b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/ARM-E_interpolate_noloop_gnu.s new file mode 100755 index 0000000..6343762 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/ARM-E_interpolate_noloop_gnu.s @@ -0,0 +1,130 @@ +@*********************************************************** +@ Function: WT_InterpolateNoLoop +@ Processor: ARM-E +@ Description: the main synthesis function when fetching +@ wavetable samples. +@ C-callable. +@ +@ Usage: +@ void WT_InterpolateNoLoop( +@ S_WT_VOICE *pWTVoice, +@ S_WT_FRAME *pWTFrame); +@ +@ Copyright Sonic Network Inc. 2004 +@**************************************************************** +@ Revision Control: +@ $Revision: 496 $ +@ $Date: 2006-12-11 14:33:26 -0800 (Mon, 11 Dec 2006) $ +@**************************************************************** +@ +@ where: +@ S_WT_VOICE *pWTVoice +@ PASSED IN: r0 +@ +@ S_WT_FRAME *pWTFrame; +@ PASSED IN: r1 +@**************************************************************** + + .include "ARM_synth_constants_gnu.inc" + + .arm + .text + + + .global WT_InterpolateNoLoop + + +@ Register usage +@ -------------- +pWTVoice .req r0 +pWTFrame .req r1 +pOutputBuffer .req r2 +numSamples .req r3 + +phaseIncrement .req r4 +pPhaseAccum .req r5 +phaseFrac .req r6 +phaseFracMask .req r7 + +tmp0 .req r1 @ reuse register +tmp1 .req r8 +tmp2 .req r9 + + +@SaveRegs RLIST {r4-r9,lr} +@RestoreRegs RLIST {r4-r9,pc} + + .func WT_InterpolateNoLoop +WT_InterpolateNoLoop: + + STMFD sp!, {r4-r9,lr} + +@ +@ Fetch parameters from structures +@---------------------------------------------------------------- + + LDR pOutputBuffer, [pWTFrame, #m_pAudioBuffer] + LDR numSamples, [pWTFrame, #m_numSamples] + + LDR phaseIncrement, [pWTFrame, #m_phaseIncrement] + LDR pPhaseAccum, [pWTVoice, #m_pPhaseAccum] + LDR phaseFrac, [pWTVoice, #m_phaseFrac] + LDR phaseFracMask,=PHASE_FRAC_MASK + +InterpolationLoop: + + .ifdef SAMPLES_8_BIT + LDRSB tmp0, [pPhaseAccum] @ tmp0 = x0 + LDRSB tmp1, [pPhaseAccum, #1] @ tmp1 = x1 + .else + LDRSH tmp0, [pPhaseAccum] @ tmp0 = x0 + LDRSH tmp1, [pPhaseAccum, #2] @ tmp1 = x1 + .endif + + ADD tmp2, phaseIncrement, phaseFrac @ increment pointer here to avoid pipeline stall + + SUB tmp1, tmp1, tmp0 @ tmp1 = x1 - x0 + SMULBB tmp1, phaseFrac, tmp1 @ tmp1 = phaseFrac * tmp2 + +@ This section performs a gain adjustment of -12dB for 16-bit samples +@ or +36dB for 8-bit samples. For a high quality synthesizer, the output +@ can be set to full scale, however if the filter is used, it can overflow +@ with certain coefficients and signal sources. In this case, either a +@ saturation operation should take in the filter before scaling back to +@ 16 bits or the signal path should be increased to 18 bits or more. + + .ifdef SAMPLES_8_BIT + MOV tmp0, tmp0, LSL #6 @ boost 8-bit signal by 36dB + .else + MOV tmp0, tmp0, ASR #2 @ reduce 16-bit signal by 12dB + .endif + + ADD tmp1, tmp0, tmp1, ASR #(NUM_EG1_FRAC_BITS-6) @ tmp1 = tmp0 + (tmp1 >> (15-6)) + @ = x0 + f * (x1 - x0) == interpolated result + + STRH tmp1, [pOutputBuffer], #NEXT_OUTPUT_PCM @ *pOutputBuffer++ = interpolated result + +@ carry overflow from fraction to integer portion + ADD pPhaseAccum, pPhaseAccum, tmp2, LSR #(NUM_PHASE_FRAC_BITS - NEXT_INPUT_PCM_SHIFT) + AND phaseFrac, tmp2, phaseFracMask @ nphaseFrac = frac part + + SUBS numSamples, numSamples, #1 + BGT InterpolationLoop + +@ Clean up and store any changes that were caused during the loop +@---------------------------------------------------------------- + + @ update and store phase + STR pPhaseAccum, [pWTVoice, #m_pPhaseAccum] + STR phaseFrac, [pWTVoice, #m_phaseFrac] + +@ +@ Return to calling function +@---------------------------------------------------------------- + + LDMFD sp!,{r4-r9,lr} + BX lr + + .endfunc + .end + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/ARM-E_mastergain_gnu.s b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/ARM-E_mastergain_gnu.s new file mode 100755 index 0000000..b4e905b --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/ARM-E_mastergain_gnu.s @@ -0,0 +1,109 @@ +@*********************************************************** +@ Function: SynthMasterGain +@ Processor: ARM-E +@ Description: Copies 32-bit synth output to 16-bit buffer +@ with saturated gain control +@ C-callable. +@ +@ Usage: +@ SynthMasterGain( +@ pInputBuffer +@ pOutputBuffer, +@ nGain, +@ nNumLoopSamples +@ ); +@ +@ Copyright Sonic Network Inc. 2004 +@**************************************************************** +@ Revision Control: +@ $Revision: 496 $ +@ $Date: 2006-12-11 14:33:26 -0800 (Mon, 11 Dec 2006) $ +@**************************************************************** +@ +@ where: +@ long *pInputBuffer +@ PASSED IN: r0 +@ +@ EAS_PCM *pOutputBuffer +@ PASSED IN: r1 +@ +@ short nGain +@ PASSED IN: r2 +@ +@ EAS_U16 nNumLoopSamples +@ PASSED IN: r3 +@ +@**************************************************************** + + .include "ARM_synth_constants_gnu.inc" + + .arm + .text + + .func SynthMasterGain +SynthMasterGain: + + .global SynthMasterGain @ allow other files to use this function + + + + + +@ Stack frame +@ ----------- + .equ RET_ADDR_SZ, 0 @return address + .equ REG_SAVE_SZ, 0 @save-on-entry registers saved + .equ FRAME_SZ, (8) @local variables + .equ ARG_BLK_SZ, 0 @argument block + + .equ PARAM_OFFSET, (ARG_BLK_SZ + FRAME_SZ + REG_SAVE_SZ + RET_ADDR_SZ) + +@ Register usage +@ -------------- +pnInputBuffer .req r0 +pnOutputBuffer .req r1 +nGain .req r2 +nNumLoopSamples .req r3 + + STMFD sp!,{r4-r6,r14} @Save any save-on-entry registers that are used + + LDR r6, =0x7fff @constant for saturation tests + +loop: + LDR r4, [pnInputBuffer], #4 @fetch 1st output sample + + LDR r5, [pnInputBuffer], #4 @fetch 2nd output sample + + SMULWB r4, r4, nGain @output = gain * input + + CMP r4, r6 @check for positive saturation + MOVGT r4, r6 @saturate + CMN r4, r6 @check for negative saturation + MVNLT r4, r6 @saturate + + SMULWB r5, r5, nGain @output = gain * input + + STRH r4, [pnOutputBuffer], #NEXT_OUTPUT_PCM @save 1st output sample + + CMP r5, r6 @check for positive saturation + MOVGT r5, r6 @saturate + CMN r5, r6 @check for negative saturation + MVNLT r5, r6 @saturate + STRH r5, [pnOutputBuffer], #NEXT_OUTPUT_PCM @save 2nd output sample + + SUBS nNumLoopSamples, nNumLoopSamples, #2 + BGT loop + +@ +@ Return to calling function +@---------------------------------------------------------------- + + LDMFD sp!,{r4-r6, lr} @ return to calling function + BX lr + +@***************************************************************************** + + .endfunc @ end of function/procedure + + .end @ end of assembly code + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/ARM-E_voice_gain_gnu.s b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/ARM-E_voice_gain_gnu.s new file mode 100755 index 0000000..4517a3d --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/ARM-E_voice_gain_gnu.s @@ -0,0 +1,166 @@ +@*********************************************************** +@ Function: WT_VoiceGain +@ Processor: ARM-E +@ Description: the main synthesis function when fetching +@ wavetable samples. +@ C-callable. +@ +@ Usage: +@ Usage: +@ WT_VoiceGain( +@ S_WT_VOICE *pWTVoice, +@ S_WT_FRAME *pWTFrame); +@ +@ Copyright 2004, 2005 Sonic Network, Inc. +@**************************************************************** +@ Revision Control: +@ $Revision: 814 $ +@ $Date: 2007-08-02 10:34:53 -0700 (Thu, 02 Aug 2007) $ +@**************************************************************** +@ +@ where: +@ S_WT_VOICE *psVoice +@ PASSED IN: r0 +@ +@ S_WT_FRAME *pWTFrame +@ PASSED IN: r1 +@**************************************************************** + + + + .include "ARM_synth_constants_gnu.inc" + + .arm + .text + + .global WT_VoiceGain + +@ Register usage +@ -------------- +pWTVoice .req r0 +pWTFrame .req r1 +pInputBuffer .req r2 +pMixBuffer .req r3 + +tmp0 .req r4 +tmp1 .req r5 +tmp2 .req r1 @ reuse register +tmp3 .req r6 + +numSamples .req r9 + + .if STEREO_OUTPUT +gainIncLeft .req r7 +gainIncRight .req r8 +gainLeft .req r10 +gainRight .req r11 + .else +gainIncrement .req r7 +gain .req r8 + .endif + + +@ register context for local variables +@SaveRegs RLIST {r4-r11,lr} +@RestoreRegs RLIST {r4-r11,pc} + + .func WT_VoiceGain +WT_VoiceGain: + + STMFD sp!, {r4-r11,lr} + + LDR pInputBuffer, [pWTFrame, #m_pAudioBuffer] + LDR pMixBuffer, [pWTFrame, #m_pMixBuffer] + LDR numSamples, [pWTFrame, #m_numSamples] + +@---------------------------------------------------------------- +@ Stereo version +@---------------------------------------------------------------- +@ NOTE: instructions are reordered to reduce the effect of latency +@ due to storage and computational dependencies. +@---------------------------------------------------------------- + + .if STEREO_OUTPUT + + LDR tmp0, [pWTFrame, #m_prevGain] + LDR tmp1, [pWTFrame, #m_gainTarget] + + LDRSH gainLeft, [pWTVoice, #m_gainLeft] + LDRSH gainRight, [pWTVoice, #m_gainRight] + + MOV gainIncLeft, gainLeft + SMULBB gainLeft, tmp0, gainLeft + + SMULBB gainIncLeft, tmp1, gainIncLeft + SUB gainIncLeft, gainIncLeft, gainLeft + MOV gainLeft, gainLeft, ASR #(NUM_MIXER_GUARD_BITS - 2) + MOV gainIncLeft, gainIncLeft, ASR #(SYNTH_UPDATE_PERIOD_IN_BITS + NUM_MIXER_GUARD_BITS - 2) + + MOV gainIncRight, gainRight + SMULBB gainRight, tmp0, gainRight + + SMULBB gainIncRight, tmp1, gainIncRight + SUB gainIncRight, gainIncRight, gainRight + MOV gainRight, gainRight, ASR #(NUM_MIXER_GUARD_BITS - 2) + MOV gainIncRight, gainIncRight, ASR #(SYNTH_UPDATE_PERIOD_IN_BITS + NUM_MIXER_GUARD_BITS - 2) + + LDRSH tmp0, [pInputBuffer], #2 + +StereoGainLoop: + LDR tmp1, [pMixBuffer] + + ADD gainLeft, gainLeft, gainIncLeft + + SMLAWB tmp1, gainLeft, tmp0, tmp1 + + LDR tmp2, [pMixBuffer, #4] + + ADD gainRight, gainRight, gainIncRight + + STR tmp1, [pMixBuffer], #4 + + SMLAWB tmp2, gainRight, tmp0, tmp2 + + SUBS numSamples, numSamples, #1 + + LDRGTSH tmp0, [pInputBuffer], #2 + + STR tmp2, [pMixBuffer], #4 + + BGT StereoGainLoop + +@---------------------------------------------------------------- +@ Mono version +@---------------------------------------------------------------- + .else + + LDR gain, [pWTFrame, #m_prevGain] + MOV gain, gain, LSL #(NUM_MIXER_GUARD_BITS + 4) + LDR gainIncrement, [pWTFrame, #m_gainTarget] + MOV gainIncrement, gainIncrement, LSL #(NUM_MIXER_GUARD_BITS + 4) + SUB gainIncrement, gainIncrement, gain + MOV gainIncrement, gainIncrement, ASR #SYNTH_UPDATE_PERIOD_IN_BITS + +MonoGainLoop: + + LDRSH tmp0, [pInputBuffer], #NEXT_OUTPUT_PCM @ fetch voice output + + LDR tmp1, [pMixBuffer] @ get left channel output sample + ADD gain, gain, gainIncrement @ gain step to eliminate zipper noise + SMULWB tmp0, gain, tmp0 @ sample * local gain + + MOV tmp0, tmp0, ASR #1 @ add 6dB headroom + ADD tmp1, tmp0, tmp1 + STR tmp1, [pMixBuffer], #4 @ save and bump pointer + + SUBS numSamples, numSamples, #1 + BGT MonoGainLoop + + .endif @end Mono version + + LDMFD sp!,{r4-r11,lr} + BX lr + + .endfunc + .end + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/ARM_synth_constants_gnu.inc b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/ARM_synth_constants_gnu.inc new file mode 100755 index 0000000..c0f8df3 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/ARM_synth_constants_gnu.inc @@ -0,0 +1,153 @@ +@*********************************************************** +@ File: ARM_synth_constants.inc +@ Processor: ARM +@ Description: Contains constants and defines, most of which +@ are mirrored in synth.h +@ +@ Copyright Sonic Network Inc. 2004 +@**************************************************************** +@ Revision Control: +@ $Revision: 741 $ +@ $Date: 2007-06-22 16:39:21 -0700 (Fri, 22 Jun 2007) $ +@**************************************************************** + + + .ifdef SAMPLE_RATE_8000 + .equ SYNTH_UPDATE_PERIOD_IN_BITS, 5 + .equ BUFFER_SIZE_IN_MONO_SAMPLES, 32 + .endif + + .ifdef SAMPLE_RATE_16000 + .equ SYNTH_UPDATE_PERIOD_IN_BITS, 6 + .equ BUFFER_SIZE_IN_MONO_SAMPLES, 64 + .endif + + .ifdef SAMPLE_RATE_20000 + .equ SYNTH_UPDATE_PERIOD_IN_BITS, 7 + .equ BUFFER_SIZE_IN_MONO_SAMPLES, 128 + .endif + + .ifdef SAMPLE_RATE_22050 + .equ SYNTH_UPDATE_PERIOD_IN_BITS, 7 + .equ BUFFER_SIZE_IN_MONO_SAMPLES, 128 + .endif + + .ifdef SAMPLE_RATE_24000 + .equ SYNTH_UPDATE_PERIOD_IN_BITS, 7 + .equ BUFFER_SIZE_IN_MONO_SAMPLES, 128 + .endif + + .ifdef SAMPLE_RATE_32000 + .equ SYNTH_UPDATE_PERIOD_IN_BITS, 7 + .equ BUFFER_SIZE_IN_MONO_SAMPLES, 128 + .endif + + .ifdef SAMPLE_RATE_44100 + .equ SYNTH_UPDATE_PERIOD_IN_BITS, 8 + .equ BUFFER_SIZE_IN_MONO_SAMPLES, 256 + .endif + + .ifdef SAMPLE_RATE_48000 + .equ SYNTH_UPDATE_PERIOD_IN_BITS, 8 + .equ BUFFER_SIZE_IN_MONO_SAMPLES, 256 + .endif + + +@ if the OUTPUT PCM sample is 16-bits, then when using indexed addressing, +@ the next sample is this many bytes away + .equ NEXT_OUTPUT_PCM, 2 + +@**************************************************************************** +@/* macros for fractional phase accumulator */ + .equ NUM_PHASE_FRAC_BITS, 15 + + .equ PHASE_FRAC_MASK, 0x7FFF + +@ shift for phase accumulator when fraction carries over + .ifdef SAMPLES_8_BIT + .equ NEXT_INPUT_PCM_SHIFT, 0 + .endif + + .ifdef SAMPLES_16_BIT + .equ NEXT_INPUT_PCM_SHIFT, 1 + .endif + +@**************************************************************************** + .equ NUM_MIXER_GUARD_BITS, 4 + +@**************************************************************************** +@/* Envelope 1 (EG1) calculation macros */ + .equ NUM_EG1_FRAC_BITS, 15 + +@**************************************************************************** + + .equ NUM_ENHANCER_FILTER_COEF_FRAC_BITS, 5 + +@**************************************************************************** + +@ +@ I've temporarily given up on the idea of getting ADS/RV and gcc to +@ handle a struct in a compatible fashion. Switching to old fashion EQU +@ + + .if FILTER_ENABLED +@************************************** +@ typedef struct s_filter_tag + .equ m_z1, 0 + .equ m_z2, 2 + .endif + +@************************************** +@ typedef struct s_wt_frame_tag + .equ m_gainTarget, 0 + .equ m_phaseIncrement, 4 + + .if FILTER_ENABLED + .equ m_k, 8 + .equ m_b1, 12 + .equ m_b2, 16 + .equ m_pAudioBuffer, 20 + .equ m_pMixBuffer, 24 + .equ m_numSamples, 28 + .equ m_prevGain, 32 + .else + .equ m_pAudioBuffer, 8 + .equ m_pMixBuffer, 12 + .equ m_numSamples, 16 + .equ m_prevGain, 20 + .endif + + +@************************************** +@ typedef struct s_wt_voice_tag + .equ m_pLoopEnd, 0 @ /* points to last PCM sample (not 1 beyond last) */ + .equ m_pLoopStart, 4 @ /* points to first sample at start of loop */ + .equ m_pPhaseAccum, 8 @ /* points to first sample at start of loop */ + .equ m_phaseFrac, 12 @ /* points to first sample at start of loop */ + + .if STEREO_OUTPUT + .equ m_gainLeft, 16 @ /* current gain, left ch */ + .equ m_gainRight, 18 @ /* current gain, right ch */ + .endif + + +@**************************************************************************** +@ enhancer + .equ m_nEnhancerFeedForward1, 0 + .equ m_nEnhancerFeedback1, 1 + .equ m_nDriveCoef, 2 + .equ m_nEnhancerFeedback2, 3 + .equ m_nWet, 4 + .equ m_nDry, 5 + + .equ m_zF0L, 6 @ filter 1 zero state var, left + .equ m_zF1L, 8 @ filter 1 pole state var, left + .equ m_zF2L, 10 @ filter 2 zero state var, left + .equ m_zF0R, 12 @ filter 1 zero state var, right + .equ m_zF1R, 14 @ filter 1 pole state var, right + .equ m_zF2R, 16 @ filter 2 zero state var, right + +@**************************************************************************** + + + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/arm-wt-22k_lib.mak b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/arm-wt-22k_lib.mak new file mode 100755 index 0000000..8e9824f --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/arm-wt-22k_lib.mak @@ -0,0 +1,25 @@ +# +# Auto-generated sample makefile +# +# This makefile is intended for use with GNU make. +# Set the paths to the tools (CC, AR, LD, etc.) +# + +vpath %.c lib_src + +CC = C:\Program Files\GNUARM\bin\arm-elf-gcc.exe +AS = C:\Program Files\GNUARM\bin\arm-elf-as.exe +LD = C:\Program Files\GNUARM\bin\arm-elf-gcc.exe +AR = C:\Program Files\GNUARM\bin\arm-elf-ar.exe + +%.o: %.c + $(CC) -c -O2 -o $@ -I lib_src -I host_src -D NUM_OUTPUT_CHANNELS=2 -D _SAMPLE_RATE_22050 -D MAX_SYNTH_VOICES=64 -D EAS_WT_SYNTH -D _8_BIT_SAMPLES -D _FILTER_ENABLED -D _IMELODY_PARSER -D _RTTTL_PARSER -D _OTA_PARSER -D _XMF_PARSER -D _WAVE_PARSER -D _REVERB_ENABLED -D _CHORUS_ENABLED -D DLS_SYNTHESIZER -D _IMA_DECODER -D MMAPI_SUPPORT -D NATIVE_EAS_KERNEL -D JET_INTERFACE $< + +%.o: %.s + $(AS) -o $@ -EL -mcpu=arm946e-s -mfpu=softfpa -I lib_src --defsym CHECK_STACK=0 --defsym REVERB=0 --defsym CHORUS=0 --defsym STEREO_OUTPUT=1 --defsym SAMPLE_RATE_22050=1 --defsym SAMPLES_8_BIT=1 --defsym FILTER_ENABLED=1 $< + +OBJS = eas_mididata.o eas_pan.o eas_wavefiledata.o eas_imelody.o eas_xmfdata.o ARM-E_interpolate_noloop_gnu.o eas_chorusdata.o ARM-E_voice_gain_gnu.o eas_ota.o eas_reverbdata.o eas_rtttl.o eas_reverb.o jet.o eas_mdls.o eas_mixbuf.o eas_smf.o eas_tcdata.o eas_chorus.o eas_pcmdata.o eas_xmf.o eas_smfdata.o eas_math.o eas_tonecontrol.o eas_rtttldata.o eas_voicemgt.o eas_public.o eas_dlssynth.o ARM-E_interpolate_loop_gnu.o ARM-E_filter_gnu.o eas_midi.o eas_otadata.o eas_flog.o eas_wtengine.o eas_imaadpcm.o eas_wtsynth.o wt_22khz.o eas_pcm.o eas_mixer.o eas_wavefile.o eas_ima_tables.o eas_data.o ARM-E_mastergain_gnu.o eas_imelodydata.o + +arm-wt-22k.a: $(OBJS) + $(AR) rc lib$@ $(OBJS) + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/dls.h b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/dls.h new file mode 100755 index 0000000..0a9e302 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/dls.h @@ -0,0 +1,268 @@ + /* + + dls.h + + Description: + + Interface defines and structures for the Instrument Collection Form + RIFF DLS. + + Written by Sonic Foundry 1996. Released for public use. + + */ + + #ifndef _INC_DLS + #define _INC_DLS + + /* + + Layout of an instrument collection: + + + RIFF [] 'DLS ' [colh,INSTLIST,WAVEPOOL,INFOLIST] + + INSTLIST + LIST [] 'lins' + LIST [] 'ins ' [insh,RGNLIST,ARTLIST,INFOLIST] + LIST [] 'ins ' [insh,RGNLIST,ARTLIST,INFOLIST] + LIST [] 'ins ' [insh,RGNLIST,ARTLIST,INFOLIST] + + RGNLIST + LIST [] 'lrgn' + LIST [] 'rgn ' [rgnh,wsmp,wlnk,ARTLIST] + LIST [] 'rgn ' [rgnh,wsmp,wlnk,ARTLIST] + LIST [] 'rgn ' [rgnh,wsmp,wlnk,ARTLIST] + + ARTLIST + LIST [] 'lart' + 'art1' level 1 Articulation connection graph + 'art2' level 2 Articulation connection graph + '3rd1' Possible 3rd party articulation structure 1 + '3rd2' Possible 3rd party articulation structure 2 .... and so on + + WAVEPOOL + ptbl [] [pool table] + LIST [] 'wvpl' + [path], + [path], + LIST [] 'wave',RIFFWAVE + LIST [] 'wave',RIFFWAVE + LIST [] 'wave',RIFFWAVE + LIST [] 'wave',RIFFWAVE + LIST [] 'wave',RIFFWAVE + + INFOLIST + LIST [] 'INFO' + 'icmt' 'One of those crazy comments.' + 'icop' 'Copyright (C) 1996 Sonic Foundry' + + */ + + + /* + FOURCC's used in the DLS file + */ +/* shree */ +//#define FAR + +/* shree + + #define FOURCC_DLS mmioFOURCC('D','L','S',' ') + #define FOURCC_COLH mmioFOURCC('c','o','l','h') + #define FOURCC_WVPL mmioFOURCC('w','v','p','l') + #define FOURCC_PTBL mmioFOURCC('p','t','b','l') + #define FOURCC_PATH mmioFOURCC('p','a','t','h') + #define FOURCC_wave mmioFOURCC('w','a','v','e') + #define FOURCC_LINS mmioFOURCC('l','i','n','s') + #define FOURCC_INS mmioFOURCC('i','n','s',' ') + #define FOURCC_INSH mmioFOURCC('i','n','s','h') + #define FOURCC_LRGN mmioFOURCC('l','r','g','n') + #define FOURCC_RGN mmioFOURCC('r','g','n',' ') + #define FOURCC_RGNH mmioFOURCC('r','g','n','h') + #define FOURCC_LART mmioFOURCC('l','a','r','t') + #define FOURCC_ART1 mmioFOURCC('a','r','t','1') + #define FOURCC_WLNK mmioFOURCC('w','l','n','k') + #define FOURCC_WSMP mmioFOURCC('w','s','m','p') + #define FOURCC_VERS mmioFOURCC('v','e','r','s') +*/ + /* + Articulation connection graph definitions + */ + + /* Generic Sources */ + #define CONN_SRC_NONE 0x0000 + #define CONN_SRC_LFO 0x0001 + #define CONN_SRC_KEYONVELOCITY 0x0002 + #define CONN_SRC_KEYNUMBER 0x0003 + #define CONN_SRC_EG1 0x0004 + #define CONN_SRC_EG2 0x0005 + #define CONN_SRC_PITCHWHEEL 0x0006 + + /* Midi Controllers 0-127 */ + #define CONN_SRC_CC1 0x0081 + #define CONN_SRC_CC7 0x0087 + #define CONN_SRC_CC10 0x008a + #define CONN_SRC_CC11 0x008b + + /* Registered Parameter Numbers */ + #define CONN_SRC_RPN0 0x0100 + #define CONN_SRC_RPN1 0x0101 + #define CONN_SRC_RPN2 0x0102 + + /* Generic Destinations */ + #define CONN_DST_NONE 0x0000 + #define CONN_DST_ATTENUATION 0x0001 + #define CONN_DST_RESERVED 0x0002 + #define CONN_DST_PITCH 0x0003 + #define CONN_DST_PAN 0x0004 + + /* LFO Destinations */ + #define CONN_DST_LFO_FREQUENCY 0x0104 + #define CONN_DST_LFO_STARTDELAY 0x0105 + + /* EG1 Destinations */ + #define CONN_DST_EG1_ATTACKTIME 0x0206 + #define CONN_DST_EG1_DECAYTIME 0x0207 + #define CONN_DST_EG1_RESERVED 0x0208 + #define CONN_DST_EG1_RELEASETIME 0x0209 + #define CONN_DST_EG1_SUSTAINLEVEL 0x020a + + /* EG2 Destinations */ + #define CONN_DST_EG2_ATTACKTIME 0x030a + #define CONN_DST_EG2_DECAYTIME 0x030b + #define CONN_DST_EG2_RESERVED 0x030c + #define CONN_DST_EG2_RELEASETIME 0x030d + #define CONN_DST_EG2_SUSTAINLEVEL 0x030e + + #define CONN_TRN_NONE 0x0000 + #define CONN_TRN_CONCAVE 0x0001 + + typedef struct _DLSVERSION { + DWORD dwVersionMS; + DWORD dwVersionLS; + }DLSVERSION, FAR *LPDLSVERSION; + + + typedef struct _CONNECTION { + USHORT usSource; + USHORT usControl; + USHORT usDestination; + USHORT usTransform; + LONG lScale; + }CONNECTION, FAR *LPCONNECTION; + + + /* Level 1 Articulation Data */ + + typedef struct _CONNECTIONLIST { + ULONG cbSize; /* size of the connection list structure */ + ULONG cConnections; /* count of connections in the list */ + } CONNECTIONLIST, FAR *LPCONNECTIONLIST; + + + + /* + Generic type defines for regions and instruments + */ + + typedef struct _RGNRANGE { + USHORT usLow; + USHORT usHigh; + }RGNRANGE, FAR * LPRGNRANGE; + + #define F_INSTRUMENT_DRUMS 0x80000000 + + typedef struct _MIDILOCALE { + ULONG ulBank; + ULONG ulInstrument; + }MIDILOCALE, FAR *LPMIDILOCALE; + + /* + Header structures found in an DLS file for collection, instruments, and + regions. + */ + + #define F_RGN_OPTION_SELFNONEXCLUSIVE 0x0001 + + typedef struct _RGNHEADER { + RGNRANGE RangeKey; /* Key range */ + RGNRANGE RangeVelocity; /* Velocity Range */ + USHORT fusOptions; /* Synthesis options for this range */ + USHORT usKeyGroup; /* Key grouping for non simultaneous play + 0 = no group, 1 up is group + for Level 1 only groups 1-15 are allowed */ + }RGNHEADER, FAR *LPRGNHEADER; + + typedef struct _INSTHEADER { + ULONG cRegions; /* Count of regions in this instrument */ + MIDILOCALE Locale; /* Intended MIDI locale of this instrument */ + }INSTHEADER, FAR *LPINSTHEADER; + + typedef struct _DLSHEADER { + ULONG cInstruments; /* Count of instruments in the collection */ + }DLSHEADER, FAR *LPDLSHEADER; + + /* + definitions for the Wave link structure + */ + + /***** For level 1 only WAVELINK_CHANNEL_MONO is valid **** + ulChannel allows for up to 32 channels of audio with each bit position + specifiying a channel of playback */ + + #define WAVELINK_CHANNEL_LEFT 0x0001 + #define WAVELINK_CHANNEL_RIGHT 0x0002 + + #define F_WAVELINK_PHASE_MASTER 0x0001 + + typedef struct _WAVELINK { /* any paths or links are stored right after struct */ + USHORT fusOptions; /* options flags for this wave */ + USHORT usPhaseGroup; /* Phase grouping for locking channels */ + ULONG ulChannel; /* channel placement */ + ULONG ulTableIndex; /* index into the wave pool table, 0 based */ + }WAVELINK, FAR *LPWAVELINK; + + #define POOL_CUE_NULL 0xffffffff + + typedef struct _POOLCUE { + // ULONG ulEntryIndex; /* Index entry in the list */ + ULONG ulOffset; /* Offset to the entry in the list */ + }POOLCUE, FAR *LPPOOLCUE; + + typedef struct _POOLTABLE { + ULONG cbSize; /* size of the pool table structure */ + ULONG cCues; /* count of cues in the list */ + } POOLTABLE, FAR *LPPOOLTABLE; + + /* + Structures for the "wsmp" chunk + */ + + #define F_WSMP_NO_TRUNCATION 0x0001 + #define F_WSMP_NO_COMPRESSION 0x0002 + + + typedef struct _rwsmp { + ULONG cbSize; + USHORT usUnityNote; /* MIDI Unity Playback Note */ + SHORT sFineTune; /* Fine Tune in log tuning */ + LONG lAttenuation; /* Overall Attenuation to be applied to data */ + ULONG fulOptions; /* Flag options */ + ULONG cSampleLoops; /* Count of Sample loops, 0 loops is one shot */ + } WSMPL, FAR *LPWSMPL; + + + /* This loop type is a normal forward playing loop which is continually + played until the envelope reaches an off threshold in the release + portion of the volume envelope */ + + #define WLOOP_TYPE_FORWARD 0 + + typedef struct _rloop { + ULONG cbSize; + ULONG ulType; /* Loop Type */ + ULONG ulStart; /* Start of loop in samples */ + ULONG ulLength; /* Length of loop in samples */ + } WLOOP, FAR *LPWLOOP; + + #endif /* _INC_DLS */ diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/dls2.h b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/dls2.h new file mode 100755 index 0000000..081557d --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/dls2.h @@ -0,0 +1,122 @@ +/* + + dls2.h + + Description: + + Interface defines and structures for the DLS2 extensions of DLS. + + + Written by Microsoft 1998. Released for public use. + +*/ + +#ifndef _INC_DLS2 +#define _INC_DLS2 + +/* + FOURCC's used in the DLS2 file, in addition to DLS1 chunks +*/ + +#define FOURCC_RGN2 mmioFOURCC('r','g','n','2') +#define FOURCC_LAR2 mmioFOURCC('l','a','r','2') +#define FOURCC_ART2 mmioFOURCC('a','r','t','2') +#define FOURCC_CDL mmioFOURCC('c','d','l',' ') +#define FOURCC_DLID mmioFOURCC('d','l','i','d') + +/* + Articulation connection graph definitions. These are in addition to + the definitions in the DLS1 header. +*/ + +/* Generic Sources (in addition to DLS1 sources. */ +#define CONN_SRC_POLYPRESSURE 0x0007 /* Polyphonic Pressure */ +#define CONN_SRC_CHANNELPRESSURE 0x0008 /* Channel Pressure */ +#define CONN_SRC_VIBRATO 0x0009 /* Vibrato LFO */ +#define CONN_SRC_MONOPRESSURE 0x000a /* MIDI Mono pressure */ + + +/* Midi Controllers */ +#define CONN_SRC_CC91 0x00db /* Reverb Send */ +#define CONN_SRC_CC93 0x00dd /* Chorus Send */ + + +/* Generic Destinations */ +#define CONN_DST_GAIN 0x0001 /* Same as CONN_DST_ ATTENUATION, but more appropriate terminology. */ +#define CONN_DST_KEYNUMBER 0x0005 /* Key Number Generator */ + +/* Audio Channel Output Destinations */ +#define CONN_DST_LEFT 0x0010 /* Left Channel Send */ +#define CONN_DST_RIGHT 0x0011 /* Right Channel Send */ +#define CONN_DST_CENTER 0x0012 /* Center Channel Send */ +#define CONN_DST_LEFTREAR 0x0013 /* Left Rear Channel Send */ +#define CONN_DST_RIGHTREAR 0x0014 /* Right Rear Channel Send */ +#define CONN_DST_LFE_CHANNEL 0x0015 /* LFE Channel Send */ +#define CONN_DST_CHORUS 0x0080 /* Chorus Send */ +#define CONN_DST_REVERB 0x0081 /* Reverb Send */ + +/* Vibrato LFO Destinations */ +#define CONN_DST_VIB_FREQUENCY 0x0114 /* Vibrato Frequency */ +#define CONN_DST_VIB_STARTDELAY 0x0115 /* Vibrato Start Delay */ + +/* EG1 Destinations */ +#define CONN_DST_EG1_DELAYTIME 0x020B /* EG1 Delay Time */ +#define CONN_DST_EG1_HOLDTIME 0x020C /* EG1 Hold Time */ +#define CONN_DST_EG1_SHUTDOWNTIME 0x020D /* EG1 Shutdown Time */ + + +/* EG2 Destinations */ +#define CONN_DST_EG2_DELAYTIME 0x030F /* EG2 Delay Time */ +#define CONN_DST_EG2_HOLDTIME 0x0310 /* EG2 Hold Time */ + + +/* Filter Destinations */ +#define CONN_DST_FILTER_CUTOFF 0x0500 /* Filter Cutoff Frequency */ +#define CONN_DST_FILTER_Q 0x0501 /* Filter Resonance */ + + +/* Transforms */ +#define CONN_TRN_CONVEX 0x0002 /* Convex Transform */ +#define CONN_TRN_SWITCH 0x0003 /* Switch Transform */ + + +/* Conditional chunk operators */ + #define DLS_CDL_AND 0x0001 /* X = X & Y */ + #define DLS_CDL_OR 0x0002 /* X = X | Y */ + #define DLS_CDL_XOR 0x0003 /* X = X ^ Y */ + #define DLS_CDL_ADD 0x0004 /* X = X + Y */ + #define DLS_CDL_SUBTRACT 0x0005 /* X = X - Y */ + #define DLS_CDL_MULTIPLY 0x0006 /* X = X * Y */ + #define DLS_CDL_DIVIDE 0x0007 /* X = X / Y */ + #define DLS_CDL_LOGICAL_AND 0x0008 /* X = X && Y */ + #define DLS_CDL_LOGICAL_OR 0x0009 /* X = X || Y */ + #define DLS_CDL_LT 0x000A /* X = (X < Y) */ + #define DLS_CDL_LE 0x000B /* X = (X <= Y) */ + #define DLS_CDL_GT 0x000C /* X = (X > Y) */ + #define DLS_CDL_GE 0x000D /* X = (X >= Y) */ + #define DLS_CDL_EQ 0x000E /* X = (X == Y) */ + #define DLS_CDL_NOT 0x000F /* X = !X */ + #define DLS_CDL_CONST 0x0010 /* 32-bit constant */ + #define DLS_CDL_QUERY 0x0011 /* 32-bit value returned from query */ + #define DLS_CDL_QUERYSUPPORTED 0x0012 /* 32-bit value returned from query */ + +/* + Loop and release +*/ + +#define WLOOP_TYPE_RELEASE 1 + +/* + DLSID queries for +*/ +DEFINE_DLSID(DLSID_GMInHardware, 0x178f2f24, 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12); +DEFINE_DLSID(DLSID_GSInHardware, 0x178f2f25, 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12); +DEFINE_DLSID(DLSID_XGInHardware, 0x178f2f26, 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12); +DEFINE_DLSID(DLSID_SupportsDLS1, 0x178f2f27, 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12); +DEFINE_DLSID(DLSID_SupportsDLS2, 0xf14599e5, 0x4689, 0x11d2, 0xaf, 0xa6, 0x0, 0xaa, 0x0, 0x24, 0xd8, 0xb6); +DEFINE_DLSID(DLSID_SampleMemorySize, 0x178f2f28, 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12); +DEFINE_DLSID(DLSID_ManufacturersID, 0xb03e1181, 0x8095, 0x11d2, 0xa1, 0xef, 0x0, 0x60, 0x8, 0x33, 0xdb, 0xd8); +DEFINE_DLSID(DLSID_ProductID, 0xb03e1182, 0x8095, 0x11d2, 0xa1, 0xef, 0x0, 0x60, 0x8, 0x33, 0xdb, 0xd8); +DEFINE_DLSID(DLSID_SamplePlaybackRate, 0x2a91f713, 0xa4bf, 0x11d2, 0xbb, 0xdf, 0x0, 0x60, 0x8, 0x33, 0xdb, 0xd8); +#endif /* _INC_DLS2 */ + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_audioconst.h b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_audioconst.h new file mode 100755 index 0000000..066148e --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_audioconst.h @@ -0,0 +1,97 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_audioconst.h + * + * Contents and purpose: + * Defines audio constants related to the sample rate, bit size, etc. + * + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_AUDIOCONST_H +#define _EAS_AUDIOCONST_H + +/*---------------------------------------------------------------------------- + * These macros define the various characteristics of the defined sample rates + *---------------------------------------------------------------------------- + * BUFFER_SIZE_IN_MONO_SAMPLES size of buffer in samples + * _OUTPUT_SAMPLE_RATE compiled output sample rate + * AUDIO_FRAME_LENGTH length of an audio frame in 256ths of a millisecond + * SYNTH_UPDATE_PERIOD_IN_BITS length of an audio frame (2^x samples) + *---------------------------------------------------------------------------- +*/ + +#if defined (_SAMPLE_RATE_8000) +#define BUFFER_SIZE_IN_MONO_SAMPLES 32 +#define _OUTPUT_SAMPLE_RATE 8000 +#define AUDIO_FRAME_LENGTH 1024 +#define SYNTH_UPDATE_PERIOD_IN_BITS 5 + +#elif defined (_SAMPLE_RATE_16000) +#define BUFFER_SIZE_IN_MONO_SAMPLES 64 +#define _OUTPUT_SAMPLE_RATE 16000 +#define AUDIO_FRAME_LENGTH 1024 +#define SYNTH_UPDATE_PERIOD_IN_BITS 6 + +#elif defined (_SAMPLE_RATE_20000) +#define BUFFER_SIZE_IN_MONO_SAMPLES 128 +#define _OUTPUT_SAMPLE_RATE 20000 +#define AUDIO_FRAME_LENGTH 1638 +#define SYNTH_UPDATE_PERIOD_IN_BITS 7 + +#elif defined (_SAMPLE_RATE_22050) +#define BUFFER_SIZE_IN_MONO_SAMPLES 128 +#define _OUTPUT_SAMPLE_RATE 22050 +#define AUDIO_FRAME_LENGTH 1486 +#define SYNTH_UPDATE_PERIOD_IN_BITS 7 + +#elif defined (_SAMPLE_RATE_24000) +#define BUFFER_SIZE_IN_MONO_SAMPLES 128 +#define _OUTPUT_SAMPLE_RATE 24000 +#define AUDIO_FRAME_LENGTH 1365 +#define SYNTH_UPDATE_PERIOD_IN_BITS 7 + +#elif defined (_SAMPLE_RATE_32000) +#define BUFFER_SIZE_IN_MONO_SAMPLES 128 +#define _OUTPUT_SAMPLE_RATE 32000 +#define AUDIO_FRAME_LENGTH 1024 +#define SYNTH_UPDATE_PERIOD_IN_BITS 7 + +#elif defined (_SAMPLE_RATE_44100) +#define BUFFER_SIZE_IN_MONO_SAMPLES 256 +#define _OUTPUT_SAMPLE_RATE 44100 +#define AUDIO_FRAME_LENGTH 1486 +#define SYNTH_UPDATE_PERIOD_IN_BITS 8 + +#elif defined (_SAMPLE_RATE_48000) +#define BUFFER_SIZE_IN_MONO_SAMPLES 256 +#define _OUTPUT_SAMPLE_RATE 48000 +#define AUDIO_FRAME_LENGTH 1365 +#define SYNTH_UPDATE_PERIOD_IN_BITS 8 + +#else +#error "_SAMPLE_RATE_XXXXX must be defined to valid rate" +#endif + +#endif /* #ifndef _EAS_AUDIOCONST_H */ + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_chorus.c b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_chorus.c new file mode 100755 index 0000000..422eb38 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_chorus.c @@ -0,0 +1,604 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_chorus.c + * + * Contents and purpose: + * Contains the implementation of the Chorus effect. + * + * + * Copyright Sonic Network Inc. 2006 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 499 $ + * $Date: 2006-12-11 16:07:20 -0800 (Mon, 11 Dec 2006) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_data.h" +#include "eas_effects.h" +#include "eas_math.h" +#include "eas_chorusdata.h" +#include "eas_chorus.h" +#include "eas_config.h" +#include "eas_host.h" +#include "eas_report.h" + +/* prototypes for effects interface */ +static EAS_RESULT ChorusInit (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR *pInstData); +static void ChorusProcess (EAS_VOID_PTR pInstData, EAS_PCM *pSrc, EAS_PCM *pDst, EAS_I32 numSamples); +static EAS_RESULT ChorusShutdown (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT ChorusGetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue); +static EAS_RESULT ChorusSetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value); + +/* common effects interface for configuration module */ +const S_EFFECTS_INTERFACE EAS_Chorus = +{ + ChorusInit, + ChorusProcess, + ChorusShutdown, + ChorusGetParam, + ChorusSetParam +}; + + + +//LFO shape table used by the chorus, larger table would sound better +//this is a sine wave, where 32767 = 1.0 +static const EAS_I16 EAS_chorusShape[CHORUS_SHAPE_SIZE] = { + 0, 1608, 3212, 4808, 6393, 7962, 9512, 11309, 12539, 14010, 15446, 16846, 18204, 19519, 20787, 22005, 23170, + 24279, 25329, 26319, 27245, 28105, 28898, 29621, 30273, 30852, 31356, 31785, 32137, 32412, 32609, 32728, + 32767, 32728, 32609, 32412, 32137, 31785, 31356, 30852, 30273, 29621, 28898, 28105, 27245, 26319, 25329, + 24279, 23170, 22005, 20787, 19519, 18204, 16846, 15446, 14010, 12539, 11039, 9512, 7962, 6393, 4808, 3212, + 1608, 0, -1608, -3212, -4808, -6393, -7962, -9512, -11309, -12539, -14010, -15446, -16846, -18204, -19519, + -20787, -22005, -23170, -24279, -25329, -26319, -27245, -28105, -28898, -29621, -30273, -30852, -31356, -31785, + -32137, -32412, -32609, -32728, -32767, -32728, -32609, -32412, -32137, -31785, -31356, -30852, -30273, -29621, + -28898, -28105, -27245, -26319, -25329, -24279, -23170, -22005, -20787, -19519, -18204, -16846, -15446, -14010, + -12539, -11039, -9512, -7962, -6393, -4808, -3212, -1608 +}; + +/*---------------------------------------------------------------------------- + * InitializeChorus() + *---------------------------------------------------------------------------- + * Purpose: Initializes chorus parameters + * + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ChorusInit (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR *pInstData) +{ + S_CHORUS_OBJECT *pChorusData; + S_CHORUS_PRESET *pPreset; + EAS_I32 index; + + /* check Configuration Module for data allocation */ + if (pEASData->staticMemoryModel) + pChorusData = EAS_CMEnumFXData(EAS_MODULE_CHORUS); + + /* allocate dynamic memory */ + else + pChorusData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_CHORUS_OBJECT)); + + if (pChorusData == NULL) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Failed to allocate Chorus memory\n"); */ } + return EAS_ERROR_MALLOC_FAILED; + } + + /* clear the structure */ + EAS_HWMemSet(pChorusData, 0, sizeof(S_CHORUS_OBJECT)); + + ChorusReadInPresets(pChorusData); + + /* set some default values */ + pChorusData->bypass = EAS_CHORUS_BYPASS_DEFAULT; + pChorusData->preset = EAS_CHORUS_PRESET_DEFAULT; + pChorusData->m_nLevel = EAS_CHORUS_LEVEL_DEFAULT; + pChorusData->m_nRate = EAS_CHORUS_RATE_DEFAULT; + pChorusData->m_nDepth = EAS_CHORUS_DEPTH_DEFAULT; + + //chorus rate and depth need some massaging from preset value (which is sample rate independent) + + //convert rate from steps of .05 Hz to value which can be used as phase increment, + //with current CHORUS_SHAPE_SIZE and rate limits, this fits into 16 bits + //want to compute ((shapeSize * 65536) * (storedRate/20))/sampleRate; + //computing it as below allows rate steps to be evenly spaced + //uses 32 bit divide, but only once when new value is selected + pChorusData->m_nRate = (EAS_I16) + ((((EAS_I32)CHORUS_SHAPE_SIZE<<16)/(20*(EAS_I32)_OUTPUT_SAMPLE_RATE)) * pChorusData->m_nRate); + + //convert depth from steps of .05 ms, to samples, with 16 bit whole part, discard fraction + //want to compute ((depth * sampleRate)/20000) + //use the following approximation since 105/32 is roughly 65536/20000 + /*lint -e{704} use shift for performance */ + pChorusData->m_nDepth = (EAS_I16) + (((((EAS_I32)pChorusData->m_nDepth * _OUTPUT_SAMPLE_RATE)>>5) * 105) >> 16); + + pChorusData->m_nLevel = pChorusData->m_nLevel; + + //zero delay memory for chorus + for (index = CHORUS_L_SIZE - 1; index >= 0; index--) + { + pChorusData->chorusDelayL[index] = 0; + } + for (index = CHORUS_R_SIZE - 1; index >= 0; index--) + { + pChorusData->chorusDelayR[index] = 0; + } + + //init delay line index, these are used to implement circular delay buffer + pChorusData->chorusIndexL = 0; + pChorusData->chorusIndexR = 0; + + //init LFO phase + //16 bit whole part, 16 bit fraction + pChorusData->lfoLPhase = 0; + pChorusData->lfoRPhase = (CHORUS_SHAPE_SIZE << 16) >> 2; // 1/4 of total, i.e. 90 degrees out of phase; + + //init chorus delay position + //right now chorus delay is a compile-time value, as is sample rate + pChorusData->chorusTapPosition = (EAS_I16)((CHORUS_DELAY_MS * _OUTPUT_SAMPLE_RATE)/1000); + + //now copy from the new preset into Chorus + pPreset = &pChorusData->m_sPreset.m_sPreset[pChorusData->m_nNextChorus]; + + pChorusData->m_nLevel = pPreset->m_nLevel; + pChorusData->m_nRate = pPreset->m_nRate; + pChorusData->m_nDepth = pPreset->m_nDepth; + + pChorusData->m_nRate = (EAS_I16) + ((((EAS_I32)CHORUS_SHAPE_SIZE<<16)/(20*(EAS_I32)_OUTPUT_SAMPLE_RATE)) * pChorusData->m_nRate); + + /*lint -e{704} use shift for performance */ + pChorusData->m_nDepth = (EAS_I16) + (((((EAS_I32)pChorusData->m_nDepth * _OUTPUT_SAMPLE_RATE)>>5) * 105) >> 16); + + *pInstData = pChorusData; + + return EAS_SUCCESS; +} /* end ChorusInit */ + +/*---------------------------------------------------------------------------- + * WeightedTap() + *---------------------------------------------------------------------------- + * Purpose: Does fractional array look-up using linear interpolation + * + * first convert indexDesired to actual desired index by taking into account indexReference + * then do linear interpolation between two actual samples using fractional part + * + * Inputs: + * array: pointer to array of signed 16 bit values, typically either PCM data or control data + * indexReference: the circular buffer relative offset + * indexDesired: the fractional index we are looking up (16 bits index + 16 bits fraction) + * indexLimit: the total size of the array, used to compute buffer wrap + * + * Outputs: + * Value from the input array, linearly interpolated between two actual data values + * + *---------------------------------------------------------------------------- +*/ +EAS_I16 WeightedTap(const EAS_I16 *array, EAS_I16 indexReference, EAS_I32 indexDesired, EAS_I16 indexLimit) +{ + EAS_I16 index; + EAS_I16 fraction; + EAS_I16 val1; + EAS_I16 val2; + + //separate indexDesired into whole and fractional parts + /*lint -e{704} use shift for performance */ + index = (EAS_I16)(indexDesired >> 16); + /*lint -e{704} use shift for performance */ + fraction = (EAS_I16)((indexDesired>>1) & 0x07FFF); //just use 15 bits of fractional part + + //adjust whole part by indexReference + index = indexReference - index; + //make sure we stay within array bounds, this implements circular buffer + while (index < 0) + { + index += indexLimit; + } + + //get two adjacent values from the array + val1 = array[index]; + + //handle special case when index == 0, else typical case + if (index == 0) + { + val2 = array[indexLimit-1]; //get last value from array + } + else + { + val2 = array[index-1]; //get previous value from array + } + + //compute linear interpolation as (val1 + ((val2-val1)*fraction)) + return(val1 + (EAS_I16)MULT_EG1_EG1(val2-val1,fraction)); +} + +/*---------------------------------------------------------------------------- + * ChorusProcess() + *---------------------------------------------------------------------------- + * Purpose: compute the chorus on the input buffer, and mix into output buffer + * + * + * Inputs: + * src: pointer to input buffer of PCM values to be processed + * dst: pointer to output buffer of PCM values we are to sume the result with + * bufSize: the number of sample frames (i.e. stereo samples) in the buffer + * + * Outputs: + * None + * + *---------------------------------------------------------------------------- +*/ +//compute the chorus, and mix into output buffer +static void ChorusProcess (EAS_VOID_PTR pInstData, EAS_PCM *pSrc, EAS_PCM *pDst, EAS_I32 numSamples) +{ + EAS_I32 ix; + EAS_I32 nChannelNumber; + EAS_I16 lfoValueLeft; + EAS_I16 lfoValueRight; + EAS_I32 positionOffsetL; + EAS_I32 positionOffsetR; + EAS_PCM tapL; + EAS_PCM tapR; + EAS_I32 tempValue; + EAS_PCM nInputSample; + EAS_I32 nOutputSample; + EAS_PCM *pIn; + EAS_PCM *pOut; + + S_CHORUS_OBJECT *pChorusData; + + pChorusData = (S_CHORUS_OBJECT*) pInstData; + + //if the chorus is disabled or turned all the way down + if (pChorusData->bypass == EAS_TRUE || pChorusData->m_nLevel == 0) + { + if (pSrc != pDst) + EAS_HWMemCpy(pSrc, pDst, numSamples * NUM_OUTPUT_CHANNELS * (EAS_I32) sizeof(EAS_PCM)); + return; + } + + if (pChorusData->m_nNextChorus != pChorusData->m_nCurrentChorus) + { + ChorusUpdate(pChorusData); + } + + for (nChannelNumber = 0; nChannelNumber < NUM_OUTPUT_CHANNELS; nChannelNumber++) + { + + pIn = pSrc + nChannelNumber; + pOut = pDst + nChannelNumber; + + if(nChannelNumber==0) + { + for (ix = 0; ix < numSamples; ix++) + { + nInputSample = *pIn; + pIn += NUM_OUTPUT_CHANNELS; + + //feed input into chorus delay line + pChorusData->chorusDelayL[pChorusData->chorusIndexL] = nInputSample; + + //compute chorus lfo value using phase as fractional index into chorus shape table + //resulting value is between -1.0 and 1.0, expressed as signed 16 bit number + lfoValueLeft = WeightedTap(EAS_chorusShape, 0, pChorusData->lfoLPhase, CHORUS_SHAPE_SIZE); + + //scale chorus depth by lfo value to get relative fractional sample index + //index is expressed as 32 bit number with 16 bit fractional part + /*lint -e{703} use shift for performance */ + positionOffsetL = pChorusData->m_nDepth * (((EAS_I32)lfoValueLeft) << 1); + + //add fixed chorus delay to get actual fractional sample index + positionOffsetL += ((EAS_I32)pChorusData->chorusTapPosition) << 16; + + //get tap value from chorus delay using fractional sample index + tapL = WeightedTap(pChorusData->chorusDelayL, pChorusData->chorusIndexL, positionOffsetL, CHORUS_L_SIZE); + + //scale by chorus level, then sum with input buffer contents and saturate + tempValue = MULT_EG1_EG1(tapL, pChorusData->m_nLevel); + nOutputSample = SATURATE(tempValue + nInputSample); + + *pOut = (EAS_I16)SATURATE(nOutputSample); + pOut += NUM_OUTPUT_CHANNELS; + + + //increment chorus delay index and make it wrap as needed + //this implements circular buffer + if ((pChorusData->chorusIndexL+=1) >= CHORUS_L_SIZE) + pChorusData->chorusIndexL = 0; + + //increment fractional lfo phase, and make it wrap as needed + pChorusData->lfoLPhase += pChorusData->m_nRate; + while (pChorusData->lfoLPhase >= (CHORUS_SHAPE_SIZE<<16)) + { + pChorusData->lfoLPhase -= (CHORUS_SHAPE_SIZE<<16); + } + } + } + else + { + for (ix = 0; ix < numSamples; ix++) + { + nInputSample = *pIn; + pIn += NUM_OUTPUT_CHANNELS; + + //feed input into chorus delay line + pChorusData->chorusDelayR[pChorusData->chorusIndexR] = nInputSample; + + //compute chorus lfo value using phase as fractional index into chorus shape table + //resulting value is between -1.0 and 1.0, expressed as signed 16 bit number + lfoValueRight = WeightedTap(EAS_chorusShape, 0, pChorusData->lfoRPhase, CHORUS_SHAPE_SIZE); + + //scale chorus depth by lfo value to get relative fractional sample index + //index is expressed as 32 bit number with 16 bit fractional part + /*lint -e{703} use shift for performance */ + positionOffsetR = pChorusData->m_nDepth * (((EAS_I32)lfoValueRight) << 1); + + //add fixed chorus delay to get actual fractional sample index + positionOffsetR += ((EAS_I32)pChorusData->chorusTapPosition) << 16; + + //get tap value from chorus delay using fractional sample index + tapR = WeightedTap(pChorusData->chorusDelayR, pChorusData->chorusIndexR, positionOffsetR, CHORUS_R_SIZE); + + //scale by chorus level, then sum with output buffer contents and saturate + tempValue = MULT_EG1_EG1(tapR, pChorusData->m_nLevel); + nOutputSample = SATURATE(tempValue + nInputSample); + + *pOut = (EAS_I16)SATURATE(nOutputSample); + pOut += NUM_OUTPUT_CHANNELS; + + //increment chorus delay index and make it wrap as needed + //this implements circular buffer + if ((pChorusData->chorusIndexR+=1) >= CHORUS_R_SIZE) + pChorusData->chorusIndexR = 0; + + //increment fractional lfo phase, and make it wrap as needed + pChorusData->lfoRPhase += pChorusData->m_nRate; + while (pChorusData->lfoRPhase >= (CHORUS_SHAPE_SIZE<<16)) + { + pChorusData->lfoRPhase -= (CHORUS_SHAPE_SIZE<<16); + } + } + } + + } +} /* end ChorusProcess */ + + + +/*---------------------------------------------------------------------------- + * ChorusShutdown() + *---------------------------------------------------------------------------- + * Purpose: + * Initializes the Chorus effect. + * + * Inputs: + * pInstData - handle to instance data + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ChorusShutdown (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR pInstData) +{ + /* check Configuration Module for static memory allocation */ + if (!pEASData->staticMemoryModel) + EAS_HWFree(pEASData->hwInstData, pInstData); + return EAS_SUCCESS; +} /* end ChorusShutdown */ + +/*---------------------------------------------------------------------------- + * ChorusGetParam() + *---------------------------------------------------------------------------- + * Purpose: + * Get a Chorus parameter + * + * Inputs: + * pInstData - handle to instance data + * param - parameter index + * *pValue - pointer to variable to hold retrieved value + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ChorusGetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue) +{ + S_CHORUS_OBJECT *p; + + p = (S_CHORUS_OBJECT*) pInstData; + + switch (param) + { + case EAS_PARAM_CHORUS_BYPASS: + *pValue = (EAS_I32) p->bypass; + break; + case EAS_PARAM_CHORUS_PRESET: + *pValue = (EAS_I8) p->m_nCurrentChorus; + break; + case EAS_PARAM_CHORUS_RATE: + *pValue = (EAS_I32) p->m_nRate; + break; + case EAS_PARAM_CHORUS_DEPTH: + *pValue = (EAS_I32) p->m_nDepth; + break; + case EAS_PARAM_CHORUS_LEVEL: + *pValue = (EAS_I32) p->m_nLevel; + break; + default: + return EAS_ERROR_INVALID_PARAMETER; + } + return EAS_SUCCESS; +} /* end ChorusGetParam */ + + +/*---------------------------------------------------------------------------- + * ChorusSetParam() + *---------------------------------------------------------------------------- + * Purpose: + * Set a Chorus parameter + * + * Inputs: + * pInstData - handle to instance data + * param - parameter index + * *pValue - new paramter value + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ChorusSetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value) +{ + S_CHORUS_OBJECT *p; + + p = (S_CHORUS_OBJECT*) pInstData; + + switch (param) + { + case EAS_PARAM_CHORUS_BYPASS: + p->bypass = (EAS_BOOL) value; + break; + case EAS_PARAM_CHORUS_PRESET: + if(value!=EAS_PARAM_CHORUS_PRESET1 && value!=EAS_PARAM_CHORUS_PRESET2 && + value!=EAS_PARAM_CHORUS_PRESET3 && value!=EAS_PARAM_CHORUS_PRESET4) + return EAS_ERROR_INVALID_PARAMETER; + p->m_nNextChorus = (EAS_I8)value; + break; + case EAS_PARAM_CHORUS_RATE: + if(valueEAS_CHORUS_RATE_MAX) + return EAS_ERROR_INVALID_PARAMETER; + p->m_nRate = (EAS_I16) value; + break; + case EAS_PARAM_CHORUS_DEPTH: + if(valueEAS_CHORUS_DEPTH_MAX) + return EAS_ERROR_INVALID_PARAMETER; + p->m_nDepth = (EAS_I16) value; + break; + case EAS_PARAM_CHORUS_LEVEL: + if(valueEAS_CHORUS_LEVEL_MAX) + return EAS_ERROR_INVALID_PARAMETER; + p->m_nLevel = (EAS_I16) value; + break; + + default: + return EAS_ERROR_INVALID_PARAMETER; + } + return EAS_SUCCESS; +} /* end ChorusSetParam */ + + +/*---------------------------------------------------------------------------- + * ChorusReadInPresets() + *---------------------------------------------------------------------------- + * Purpose: sets global Chorus preset bank to defaults + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT ChorusReadInPresets(S_CHORUS_OBJECT *pChorusData) +{ + + int preset = 0; + int defaultPreset = 0; + + //now init any remaining presets to defaults + for (defaultPreset = preset; defaultPreset < CHORUS_MAX_TYPE; defaultPreset++) + { + S_CHORUS_PRESET *pPreset = &pChorusData->m_sPreset.m_sPreset[defaultPreset]; + if (defaultPreset == 0 || defaultPreset > CHORUS_MAX_TYPE-1) + { + pPreset->m_nDepth = 39; + pPreset->m_nRate = 30; + pPreset->m_nLevel = 32767; + } + else if (defaultPreset == 1) + { + pPreset->m_nDepth = 21; + pPreset->m_nRate = 45; + pPreset->m_nLevel = 25000; + } + else if (defaultPreset == 2) + { + pPreset->m_nDepth = 53; + pPreset->m_nRate = 25; + pPreset->m_nLevel = 32000; + } + else if (defaultPreset == 3) + { + pPreset->m_nDepth = 32; + pPreset->m_nRate = 37; + pPreset->m_nLevel = 29000; + } + } + + return EAS_SUCCESS; +} + + +/*---------------------------------------------------------------------------- + * ChorusUpdate + *---------------------------------------------------------------------------- + * Purpose: + * Update the Chorus preset parameters as required + * + * Inputs: + * + * Outputs: + * + * + * Side Effects: + * - chorus paramters will be changed + * - m_nCurrentRoom := m_nNextRoom + *---------------------------------------------------------------------------- +*/ +EAS_RESULT ChorusUpdate(S_CHORUS_OBJECT *pChorusData) +{ + S_CHORUS_PRESET *pPreset = &pChorusData->m_sPreset.m_sPreset[pChorusData->m_nNextChorus]; + + pChorusData->m_nLevel = pPreset->m_nLevel; + pChorusData->m_nRate = pPreset->m_nRate; + pChorusData->m_nDepth = pPreset->m_nDepth; + + pChorusData->m_nRate = (EAS_I16) + ((((EAS_I32)CHORUS_SHAPE_SIZE<<16)/(20*(EAS_I32)_OUTPUT_SAMPLE_RATE)) * pChorusData->m_nRate); + + /*lint -e{704} use shift for performance */ + pChorusData->m_nDepth = (EAS_I16) + (((((EAS_I32)pChorusData->m_nDepth * _OUTPUT_SAMPLE_RATE)>>5) * 105) >> 16); + + pChorusData->m_nCurrentChorus = pChorusData->m_nNextChorus; + + return EAS_SUCCESS; + +} /* end ChorusUpdate */ diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_chorusdata.c b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_chorusdata.c new file mode 100755 index 0000000..ec71ff8 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_chorusdata.c @@ -0,0 +1,34 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_chorusdata.c + * + * Contents and purpose: + * Contains the static data allocation for the Chorus effect + * + * + * Copyright Sonic Network Inc. 2006 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 550 $ + * $Date: 2007-02-02 09:37:03 -0800 (Fri, 02 Feb 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_chorusdata.h" + +S_CHORUS_OBJECT eas_ChorusData; + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_chorusdata.h b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_chorusdata.h new file mode 100755 index 0000000..094dc79 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_chorusdata.h @@ -0,0 +1,160 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_chorusdata.h + * + * Contents and purpose: + * Contains the prototypes for the Chorus effect. + * + * + * Copyright Sonic Network Inc. 2006 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 309 $ + * $Date: 2006-09-12 18:52:45 -0700 (Tue, 12 Sep 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_CHORUS_H +#define _EAS_CHORUS_H + +#include "eas_types.h" +#include "eas_audioconst.h" + +//defines for chorus + +#define EAS_CHORUS_BYPASS_DEFAULT 1 +#define EAS_CHORUS_PRESET_DEFAULT 0 +#define EAS_CHORUS_RATE_DEFAULT 30 +#define EAS_CHORUS_DEPTH_DEFAULT 39 +#define EAS_CHORUS_LEVEL_DEFAULT 32767 + +#define EAS_CHORUS_LEVEL_MIN 0 +#define EAS_CHORUS_LEVEL_MAX 32767 + +#define EAS_CHORUS_RATE_MIN 10 +#define EAS_CHORUS_RATE_MAX 50 + +#define EAS_CHORUS_DEPTH_MIN 15 +#define EAS_CHORUS_DEPTH_MAX 60 + +#define CHORUS_SIZE_MS 20 +#define CHORUS_L_SIZE ((CHORUS_SIZE_MS*_OUTPUT_SAMPLE_RATE)/1000) +#define CHORUS_R_SIZE CHORUS_L_SIZE +#define CHORUS_SHAPE_SIZE 128 +#define CHORUS_DELAY_MS 10 + +#define CHORUS_MAX_TYPE 4 // any Chorus numbers larger than this are invalid + +typedef struct +{ + EAS_I16 m_nRate; + EAS_I16 m_nDepth; + EAS_I16 m_nLevel; + +} S_CHORUS_PRESET; + +typedef struct +{ + S_CHORUS_PRESET m_sPreset[CHORUS_MAX_TYPE]; //array of presets + +} S_CHORUS_PRESET_BANK; + +/* parameters for each Chorus */ +typedef struct +{ + EAS_I32 lfoLPhase; + EAS_I32 lfoRPhase; + EAS_I16 chorusIndexL; + EAS_I16 chorusIndexR; + EAS_U16 chorusTapPosition; + + EAS_I16 m_nRate; + EAS_I16 m_nDepth; + EAS_I16 m_nLevel; + + //delay lines used by the chorus, longer would sound better + EAS_PCM chorusDelayL[CHORUS_L_SIZE]; + EAS_PCM chorusDelayR[CHORUS_R_SIZE]; + + EAS_BOOL bypass; + EAS_I8 preset; + + EAS_I16 m_nCurrentChorus; // preset number for current Chorus + EAS_I16 m_nNextChorus; // preset number for next Chorus + + S_CHORUS_PRESET pPreset; + + S_CHORUS_PRESET_BANK m_sPreset; + +} S_CHORUS_OBJECT; + + +/*---------------------------------------------------------------------------- + * WeightedTap() + *---------------------------------------------------------------------------- + * Purpose: Does fractional array look-up using linear interpolation + * + * first convert indexDesired to actual desired index by taking into account indexReference + * then do linear interpolation between two actual samples using fractional part + * + * Inputs: + * array: pointer to array of signed 16 bit values, typically either PCM data or control data + * indexReference: the circular buffer relative offset + * indexDesired: the fractional index we are looking up (16 bits index + 16 bits fraction) + * indexLimit: the total size of the array, used to compute buffer wrap + * + * Outputs: + * Value from the input array, linearly interpolated between two actual data values + * + *---------------------------------------------------------------------------- +*/ +EAS_I16 WeightedTap(const EAS_I16 *array, EAS_I16 indexReference, EAS_I32 indexDesired, EAS_I16 indexLimit); + +/*---------------------------------------------------------------------------- + * ChorusReadInPresets() + *---------------------------------------------------------------------------- + * Purpose: sets global Chorus preset bank to defaults + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT ChorusReadInPresets(S_CHORUS_OBJECT *pChorusData); + +/*---------------------------------------------------------------------------- + * ChorusUpdate + *---------------------------------------------------------------------------- + * Purpose: + * Update the Chorus preset parameters as required + * + * Inputs: + * + * Outputs: + * + * + * Side Effects: + * - chorus paramters will be changed + * - m_nCurrentChorus := m_nNextChorus + *---------------------------------------------------------------------------- +*/ +EAS_RESULT ChorusUpdate(S_CHORUS_OBJECT* pChorusData); + +#endif /* #ifndef _EAS_CHORUSDATA_H */ + + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_ctype.h b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_ctype.h new file mode 100755 index 0000000..14fa96f --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_ctype.h @@ -0,0 +1,41 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_ctype.h + * + * Contents and purpose: + * This is a replacement for the CRT ctype.h functions. These + * functions are currently ASCII only, but eventually, we will want + * to support wide-characters for localization. + * + * Copyright (c) 2005 Sonic Network Inc. + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 429 $ + * $Date: 2006-10-19 23:50:15 -0700 (Thu, 19 Oct 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_CTYPE_H +#define _EAS_CTYPE_H + +EAS_INLINE EAS_I8 IsDigit (EAS_I8 c) { return ((c >= '0') && (c <= '9')); } +EAS_INLINE EAS_I8 IsSpace (EAS_I8 c) { return (((c >= 9) && (c <= 13)) || (c == ' ')); } +EAS_INLINE EAS_I8 ToUpper (EAS_I8 c) { if ((c >= 'a') && (c <= 'z')) return c & ~0x20; else return c; } +EAS_INLINE EAS_I8 ToLower (EAS_I8 c) { if ((c >= 'A') && (c <= 'Z')) return c |= 0x20; else return c; } + +#endif + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_data.c b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_data.c new file mode 100755 index 0000000..31a4e6a --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_data.c @@ -0,0 +1,37 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_data.c + * + * Contents and purpose: + * Contains a data allocation for synthesizer + * + * Copyright Sonic Network Inc. 2004 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 547 $ + * $Date: 2007-01-31 16:30:17 -0800 (Wed, 31 Jan 2007) $ + *---------------------------------------------------------------------------- +*/ + +// includes +#include "eas_data.h" + +// globals +S_EAS_DATA eas_Data; +S_VOICE_MGR eas_Synth; +S_SYNTH eas_MIDI; + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_data.h b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_data.h new file mode 100755 index 0000000..ab724e6 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_data.h @@ -0,0 +1,133 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_data.h + * + * Contents and purpose: + * This header defines all types, to support dynamic allocation of the + * memory resources needed for persistent EAS data. + * + * Copyright 2004 Sonic Network Inc. + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 842 $ + * $Date: 2007-08-23 14:32:31 -0700 (Thu, 23 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_DATA_H +#define _EAS_DATA_H + +//#define JET_INTERFACE + +#include "eas_types.h" +#include "eas_synthcfg.h" +#include "eas.h" +#include "eas_audioconst.h" +#include "eas_sndlib.h" +#include "eas_pcm.h" +#include "eas_pcmdata.h" +#include "eas_synth.h" +#include "eas_miditypes.h" +#include "eas_effects.h" + +#ifdef AUX_MIXER +#include "eas_auxmixdata.h" +#endif + +#ifdef JET_INTERFACE +#include "jet.h" +#endif + +#ifdef _METRICS_ENABLED +#include "eas_perf.h" +#endif + +#ifndef MAX_NUMBER_STREAMS +#define MAX_NUMBER_STREAMS 4 +#endif + +/* flags for S_EAS_STREAM */ +#define STREAM_FLAGS_PARSED 1 +#define STREAM_FLAGS_PAUSE 2 +#define STREAM_FLAGS_LOCATE 4 +#define STREAM_FLAGS_RESUME 8 + +/* structure for parsing a stream */ +typedef struct s_eas_stream_tag +{ + void *pParserModule; + EAS_U32 time; + EAS_U32 frameLength; + EAS_I32 repeatCount; + EAS_VOID_PTR handle; + EAS_U8 volume; + EAS_BOOL8 streamFlags; +} S_EAS_STREAM; + +/* default master volume is -10dB */ +#define DEFAULT_VOLUME 90 +#define DEFAULT_STREAM_VOLUME 100 +#define DEFAULT_STREAM_GAIN 14622 + +/* 10 dB of boost available for individual parsers */ +#define STREAM_VOLUME_HEADROOM 10 + +/* amalgamated persistent data type */ +typedef struct s_eas_data_tag +{ +#ifdef _CHECKED_BUILD + EAS_U32 handleCheck; +#endif + EAS_HW_DATA_HANDLE hwInstData; + + S_EFFECTS_MODULE effectsModules[NUM_EFFECTS_MODULES]; + +#ifdef _METRICS_ENABLED + S_METRICS_INTERFACE *pMetricsModule; + EAS_VOID_PTR pMetricsData; +#endif + + EAS_I32 *pMixBuffer; + EAS_PCM *pOutputAudioBuffer; + +#ifdef AUX_MIXER + S_EAS_AUX_MIXER auxMixer; +#endif + +#ifdef _MAXIMIZER_ENABLED + EAS_VOID_PTR pMaximizerData; +#endif + + S_EAS_STREAM streams[MAX_NUMBER_STREAMS]; + + S_PCM_STATE *pPCMStreams; + + S_VOICE_MGR *pVoiceMgr; + +#ifdef JET_INTERFACE + JET_DATA_HANDLE jetHandle; +#endif + + EAS_U32 renderTime; + EAS_I16 masterGain; + EAS_U8 masterVolume; + EAS_BOOL8 staticMemoryModel; + EAS_BOOL8 searchHeaderFlag; +} S_EAS_DATA; + +#endif + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_dlssynth.c b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_dlssynth.c new file mode 100755 index 0000000..8606a29 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_dlssynth.c @@ -0,0 +1,578 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_dlssynth.c + * + * Contents and purpose: + * Implements the Mobile DLS synthesizer. + * + * Copyright Sonic Network Inc. 2006 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 795 $ + * $Date: 2007-08-01 00:14:45 -0700 (Wed, 01 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +// includes +#include "eas_data.h" +#include "eas_report.h" +#include "eas_host.h" +#include "eas_math.h" +#include "eas_synth_protos.h" +#include "eas_wtsynth.h" +#include "eas_pan.h" +#include "eas_mdls.h" +#include "eas_dlssynth.h" + +#ifdef _METRICS_ENABLED +#include "eas_perf.h" +#endif + +static void DLS_UpdateEnvelope (S_SYNTH_VOICE *pVoice, S_SYNTH_CHANNEL *pChannel, const S_DLS_ENVELOPE *pEnvParams, EAS_I16 *pValue, EAS_I16 *pIncrement, EAS_U8 *pState); + +/*---------------------------------------------------------------------------- + * DLS_MuteVoice() + *---------------------------------------------------------------------------- + * Mute the voice using shutdown time from the DLS articulation data + *---------------------------------------------------------------------------- +*/ +void DLS_MuteVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum) +{ + S_WT_VOICE *pWTVoice; + const S_DLS_ARTICULATION *pDLSArt; + + pWTVoice = &pVoiceMgr->wtVoices[voiceNum]; + pDLSArt = &pSynth->pDLS->pDLSArticulations[pWTVoice->artIndex]; + + /* clear deferred action flags */ + pVoice->voiceFlags &= + ~(VOICE_FLAG_DEFER_MIDI_NOTE_OFF | + VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF | + VOICE_FLAG_DEFER_MUTE); + + /* set the envelope state */ + pVoiceMgr->wtVoices[voiceNum].eg1State = eEnvelopeStateRelease; + pWTVoice->eg1Increment = pDLSArt->eg1ShutdownTime; + pVoiceMgr->wtVoices[voiceNum].eg2State = eEnvelopeStateRelease; + pWTVoice->eg2Increment = pDLSArt->eg2.releaseTime; +} + +/*---------------------------------------------------------------------------- + * DLS_ReleaseVoice() + *---------------------------------------------------------------------------- + * Release the selected voice. + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pVoice) standard API, pVoice may be used by other synthesizers */ +void DLS_ReleaseVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum) +{ + S_WT_VOICE *pWTVoice; + const S_DLS_ARTICULATION *pDLSArt; + + pWTVoice = &pVoiceMgr->wtVoices[voiceNum]; + pDLSArt = &pSynth->pDLS->pDLSArticulations[pWTVoice->artIndex]; + + /* if still in attack phase, convert units to log */ + /*lint -e{732} eg1Value is never negative */ + /*lint -e{703} use shift for performance */ + if (pWTVoice->eg1State == eEnvelopeStateAttack) + pWTVoice->eg1Value = (EAS_I16) ((EAS_flog2(pWTVoice->eg1Value) << 1) + 2048); + + /* release EG1 */ + pWTVoice->eg1State = eEnvelopeStateRelease; + pWTVoice->eg1Increment = pDLSArt->eg1.releaseTime; + + /* release EG2 */ + pWTVoice->eg2State = eEnvelopeStateRelease; + pWTVoice->eg2Increment = pDLSArt->eg2.releaseTime; +} + +/*---------------------------------------------------------------------------- + * DLS_SustainPedal() + *---------------------------------------------------------------------------- + * The sustain pedal was just depressed. If the voice is still + * above the sustain level, catch the voice and continue holding. + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pChannel) pChannel reserved for future use */ +void DLS_SustainPedal (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, S_SYNTH_CHANNEL *pChannel, EAS_I32 voiceNum) +{ + S_WT_VOICE *pWTVoice; + const S_DLS_ARTICULATION *pDLSArt; + + pWTVoice = &pVoiceMgr->wtVoices[voiceNum]; + pDLSArt = &pSynth->pDLS->pDLSArticulations[pWTVoice->artIndex]; + + /* don't catch the voice if below the sustain level */ + if (pWTVoice->eg1Value < pDLSArt->eg1.sustainLevel) + return; + + /* defer releasing this note until the damper pedal is off */ + pWTVoice->eg1State = eEnvelopeStateDecay; + pVoice->voiceState = eVoiceStatePlay; + pVoice->voiceFlags |= VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF; + +#ifdef _DEBUG_SYNTH + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "DLS_SustainPedal: defer note off because sustain pedal is on\n"); */ } +#endif +} + +/*---------------------------------------------------------------------------- + * DLS_UpdatePhaseInc() + *---------------------------------------------------------------------------- + * Calculate the oscillator phase increment for the next frame + *---------------------------------------------------------------------------- +*/ +static EAS_I32 DLS_UpdatePhaseInc (S_WT_VOICE *pWTVoice, const S_DLS_ARTICULATION *pDLSArt, S_SYNTH_CHANNEL *pChannel, EAS_I32 pitchCents) +{ + EAS_I32 temp; + + /* start with base mod LFO modulation */ + temp = pDLSArt->modLFOToPitch; + + /* add mod wheel effect */ + /*lint -e{702} use shift for performance */ + temp += ((pDLSArt->modLFOCC1ToPitch * pChannel->modWheel) >> 7); + + /* add channel pressure effect */ + /*lint -e{702} use shift for performance */ + temp += ((pDLSArt->modLFOChanPressToPitch * pChannel->channelPressure) >> 7); + + /* add total mod LFO effect */ + pitchCents += FMUL_15x15(temp, pWTVoice->modLFO.lfoValue); + + /* start with base vib LFO modulation */ + temp = pDLSArt->vibLFOToPitch; + + /* add mod wheel effect */ + /*lint -e{702} use shift for performance */ + temp += ((pDLSArt->vibLFOCC1ToPitch * pChannel->modWheel) >> 7); + + /* add channel pressure effect */ + /*lint -e{702} use shift for performance */ + temp += ((pDLSArt->vibLFOChanPressToPitch * pChannel->channelPressure) >> 7); + + /* add total vibrato LFO effect */ + pitchCents += FMUL_15x15(temp, pWTVoice->vibLFO.lfoValue); + + /* add EG2 effect */ + pitchCents += FMUL_15x15(pDLSArt->eg2ToPitch, pWTVoice->eg2Value); + + /* convert from cents to linear phase increment */ + return EAS_Calculate2toX(pitchCents); +} + +/*---------------------------------------------------------------------------- + * DLS_UpdateGain() + *---------------------------------------------------------------------------- + * Calculate the gain for the next frame + *---------------------------------------------------------------------------- +*/ +static EAS_I32 DLS_UpdateGain (S_WT_VOICE *pWTVoice, const S_DLS_ARTICULATION *pDLSArt, S_SYNTH_CHANNEL *pChannel, EAS_I32 gain, EAS_U8 velocity) +{ + EAS_I32 temp; + + /* start with base mod LFO modulation */ + temp = pDLSArt->modLFOToGain; + + /* add mod wheel effect */ + /*lint -e{702} use shift for performance */ + temp += ((pDLSArt->modLFOCC1ToGain * pChannel->modWheel) >> 7); + + /* add channel pressure effect */ + /*lint -e{702} use shift for performance */ + temp += ((pDLSArt->modLFOChanPressToGain * pChannel->channelPressure) >> 7); + + /* add total mod LFO effect */ + gain += FMUL_15x15(temp, pWTVoice->modLFO.lfoValue); + if (gain > 0) + gain = 0; + + /* convert to linear gain including EG1 */ + if (pWTVoice->eg1State != eEnvelopeStateAttack) + { + gain = (DLS_GAIN_FACTOR * gain) >> DLS_GAIN_SHIFT; + /*lint -e{702} use shift for performance */ +#if 1 + gain += (pWTVoice->eg1Value - 32767) >> 1; + gain = EAS_LogToLinear16(gain); +#else + gain = EAS_LogToLinear16(gain); + temp = EAS_LogToLinear16((pWTVoice->eg1Value - 32767) >> 1); + gain = FMUL_15x15(gain, temp); +#endif + } + else + { + gain = (DLS_GAIN_FACTOR * gain) >> DLS_GAIN_SHIFT; + gain = EAS_LogToLinear16(gain); + gain = FMUL_15x15(gain, pWTVoice->eg1Value); + } + + /* include MIDI channel gain */ + gain = FMUL_15x15(gain, pChannel->staticGain); + + /* include velocity */ + if (pDLSArt->filterQandFlags & FLAG_DLS_VELOCITY_SENSITIVE) + { + temp = velocity << 8; + temp = FMUL_15x15(temp, temp); + gain = FMUL_15x15(gain, temp); + } + + /* return gain */ + return gain; +} + +/*---------------------------------------------------------------------------- + * DLS_UpdateFilter() + *---------------------------------------------------------------------------- + * Update the Filter parameters + *---------------------------------------------------------------------------- +*/ +static void DLS_UpdateFilter (S_SYNTH_VOICE *pVoice, S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pIntFrame, S_SYNTH_CHANNEL *pChannel, const S_DLS_ARTICULATION *pDLSArt) +{ + EAS_I32 cutoff; + EAS_I32 temp; + + /* no need to calculate filter coefficients if it is bypassed */ + if (pDLSArt->filterCutoff == DEFAULT_DLS_FILTER_CUTOFF_FREQUENCY) + { + pIntFrame->frame.k = 0; + return; + } + + /* start with base cutoff frequency */ + cutoff = pDLSArt->filterCutoff; + + /* get base mod LFO modulation */ + temp = pDLSArt->modLFOToFc; + + /* add mod wheel effect */ + /*lint -e{702} use shift for performance */ + temp += ((pDLSArt->modLFOCC1ToFc * pChannel->modWheel) >> 7); + + /* add channel pressure effect */ + /*lint -e{702} use shift for performance */ + temp += ((pDLSArt->modLFOChanPressToFc* pChannel->channelPressure) >> 7); + + /* add total mod LFO effect */ + cutoff += FMUL_15x15(temp, pWTVoice->modLFO.lfoValue); + + /* add EG2 effect */ + cutoff += FMUL_15x15(pWTVoice->eg2Value, pDLSArt->eg2ToFc); + + /* add velocity effect */ + /*lint -e{702} use shift for performance */ + cutoff += (pVoice->velocity * pDLSArt->velToFc) >> 7; + + /* add velocity effect */ + /*lint -e{702} use shift for performance */ + cutoff += (pVoice->note * pDLSArt->keyNumToFc) >> 7; + + /* subtract the A5 offset and the sampling frequency */ + cutoff -= FILTER_CUTOFF_FREQ_ADJUST + A5_PITCH_OFFSET_IN_CENTS; + + /* limit the cutoff frequency */ + if (cutoff > FILTER_CUTOFF_MAX_PITCH_CENTS) + cutoff = FILTER_CUTOFF_MAX_PITCH_CENTS; + else if (cutoff < FILTER_CUTOFF_MIN_PITCH_CENTS) + cutoff = FILTER_CUTOFF_MIN_PITCH_CENTS; + + WT_SetFilterCoeffs(pIntFrame, cutoff, pDLSArt->filterQandFlags & FILTER_Q_MASK); +} + +/*---------------------------------------------------------------------------- + * DLS_StartVoice() + *---------------------------------------------------------------------------- + * Start up a DLS voice + *---------------------------------------------------------------------------- +*/ +EAS_RESULT DLS_StartVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_U16 regionIndex) +{ + S_WT_VOICE *pWTVoice; + const S_DLS_REGION *pDLSRegion; + const S_DLS_ARTICULATION *pDLSArt; + S_SYNTH_CHANNEL *pChannel; + +#ifdef _DEBUG_SYNTH + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "DLS_StartVoice: Voice %ld; Region %d\n", (EAS_I32) (pVoice - pVoiceMgr->voices), regionIndex); */ } +#endif + + pWTVoice = &pVoiceMgr->wtVoices[voiceNum]; + pChannel = &pSynth->channels[pVoice->channel & 15]; + pDLSRegion = &pSynth->pDLS->pDLSRegions[regionIndex & REGION_INDEX_MASK]; + pWTVoice->artIndex = pDLSRegion->wtRegion.artIndex; + pDLSArt = &pSynth->pDLS->pDLSArticulations[pWTVoice->artIndex]; + + /* initialize the envelopes */ + pWTVoice->eg1State = eEnvelopeStateInit; + DLS_UpdateEnvelope(pVoice, pChannel, &pDLSArt->eg1, &pWTVoice->eg1Value, &pWTVoice->eg1Increment, &pWTVoice->eg1State); + pWTVoice->eg2State = eEnvelopeStateInit; + DLS_UpdateEnvelope(pVoice, pChannel, &pDLSArt->eg2, &pWTVoice->eg2Value, &pWTVoice->eg2Increment, &pWTVoice->eg2State); + + /* initialize the LFOs */ + pWTVoice->modLFO.lfoValue = 0; + pWTVoice->modLFO.lfoPhase = pDLSArt->modLFO.lfoDelay; + pWTVoice->vibLFO.lfoValue = 0; + pWTVoice->vibLFO.lfoPhase = pDLSArt->vibLFO.lfoDelay; + + /* initalize the envelopes and calculate initial gain */ + DLS_UpdateEnvelope(pVoice, pChannel, &pDLSArt->eg1, &pWTVoice->eg1Value, &pWTVoice->eg1Increment, &pWTVoice->eg1State); + DLS_UpdateEnvelope(pVoice, pChannel, &pDLSArt->eg2, &pWTVoice->eg2Value, &pWTVoice->eg2Increment, &pWTVoice->eg2State); + pVoice->gain = (EAS_I16) DLS_UpdateGain(pWTVoice, pDLSArt, pChannel, pDLSRegion->wtRegion.gain, pVoice->velocity); + +#if (NUM_OUTPUT_CHANNELS == 2) + EAS_CalcPanControl((EAS_INT) pChannel->pan - 64 + (EAS_INT) pDLSArt->pan, &pWTVoice->gainLeft, &pWTVoice->gainRight); +#endif + + /* initialize the filter states */ + pWTVoice->filter.z1 = 0; + pWTVoice->filter.z2 = 0; + + /* initialize the oscillator */ + pWTVoice->phaseAccum = (EAS_U32) pSynth->pDLS->pDLSSamples + pSynth->pDLS->pDLSSampleOffsets[pDLSRegion->wtRegion.waveIndex]; + if (pDLSRegion->wtRegion.region.keyGroupAndFlags & REGION_FLAG_IS_LOOPED) + { + pWTVoice->loopStart = pWTVoice->phaseAccum + pDLSRegion->wtRegion.loopStart; + pWTVoice->loopEnd = pWTVoice->phaseAccum + pDLSRegion->wtRegion.loopEnd - 1; + } + else + pWTVoice->loopStart = pWTVoice->loopEnd = pWTVoice->phaseAccum + pSynth->pDLS->pDLSSampleLen[pDLSRegion->wtRegion.waveIndex] - 1; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * DLS_UpdateVoice() + *---------------------------------------------------------------------------- + * Purpose: + * Synthesize a block of samples for the given voice. + * Use linear interpolation. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * + * Outputs: + * number of samples actually written to buffer + * + * Side Effects: + * - samples are added to the presently free buffer + * + *---------------------------------------------------------------------------- +*/ +EAS_BOOL DLS_UpdateVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_I32 *pMixBuffer, EAS_I32 numSamples) +{ + S_WT_VOICE *pWTVoice; + S_SYNTH_CHANNEL *pChannel; + const S_DLS_REGION *pDLSRegion; + const S_DLS_ARTICULATION *pDLSArt; + S_WT_INT_FRAME intFrame; + EAS_I32 temp; + EAS_BOOL done = EAS_FALSE; + + /* establish pointers to critical data */ + pWTVoice = &pVoiceMgr->wtVoices[voiceNum]; + pDLSRegion = &pSynth->pDLS->pDLSRegions[pVoice->regionIndex & REGION_INDEX_MASK]; + pChannel = &pSynth->channels[pVoice->channel & 15]; + pDLSArt = &pSynth->pDLS->pDLSArticulations[pWTVoice->artIndex]; + + /* update the envelopes */ + DLS_UpdateEnvelope(pVoice, pChannel, &pDLSArt->eg1, &pWTVoice->eg1Value, &pWTVoice->eg1Increment, &pWTVoice->eg1State); + DLS_UpdateEnvelope(pVoice, pChannel, &pDLSArt->eg2, &pWTVoice->eg2Value, &pWTVoice->eg2Increment, &pWTVoice->eg2State); + + /* update the LFOs using the EAS synth function */ + WT_UpdateLFO(&pWTVoice->modLFO, pDLSArt->modLFO.lfoFreq); + WT_UpdateLFO(&pWTVoice->vibLFO, pDLSArt->vibLFO.lfoFreq); + + /* calculate base frequency */ + temp = pDLSArt->tuning + pChannel->staticPitch + pDLSRegion->wtRegion.tuning + + (((EAS_I32) pVoice->note * (EAS_I32) pDLSArt->keyNumToPitch) >> 7); + + /* don't transpose rhythm channel */ + if ((pChannel ->channelFlags & CHANNEL_FLAG_RHYTHM_CHANNEL) == 0) + temp += pSynth->globalTranspose * 100; + + /* calculate phase increment including modulation effects */ + intFrame.frame.phaseIncrement = DLS_UpdatePhaseInc(pWTVoice, pDLSArt, pChannel, temp); + + /* calculate gain including modulation effects */ + intFrame.frame.gainTarget = DLS_UpdateGain(pWTVoice, pDLSArt, pChannel, pDLSRegion->wtRegion.gain, pVoice->velocity); + intFrame.prevGain = pVoice->gain; + + DLS_UpdateFilter(pVoice, pWTVoice, &intFrame, pChannel, pDLSArt); + + /* call into engine to generate samples */ + intFrame.pAudioBuffer = pVoiceMgr->voiceBuffer; + intFrame.pMixBuffer = pMixBuffer; + intFrame.numSamples = numSamples; + if (numSamples < 0) + return EAS_FALSE; + + /* check for end of sample */ + if ((pWTVoice->loopStart != WT_NOISE_GENERATOR) && (pWTVoice->loopStart == pWTVoice->loopEnd)) + done = WT_CheckSampleEnd(pWTVoice, &intFrame, EAS_FALSE); + + WT_ProcessVoice(pWTVoice, &intFrame); + + /* clear flag */ + pVoice->voiceFlags &= ~VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET; + + /* if the update interval has elapsed, then force the current gain to the next + * gain since we never actually reach the next gain when ramping -- we just get + * very close to the target gain. + */ + pVoice->gain = (EAS_I16) intFrame.frame.gainTarget; + + /* if voice has finished, set flag for voice manager */ + if ((pVoice->voiceState != eVoiceStateStolen) && (pWTVoice->eg1State == eEnvelopeStateMuted)) + done = EAS_TRUE; + + return done; +} + +/*---------------------------------------------------------------------------- + * DLS_UpdateEnvelope() + *---------------------------------------------------------------------------- + * Purpose: + * Synthesize a block of samples for the given voice. + * Use linear interpolation. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * + * Outputs: + * number of samples actually written to buffer + * + * Side Effects: + * - samples are added to the presently free buffer + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pChannel) pChannel not used in this instance */ +static void DLS_UpdateEnvelope (S_SYNTH_VOICE *pVoice, S_SYNTH_CHANNEL *pChannel, const S_DLS_ENVELOPE *pEnvParams, EAS_I16 *pValue, EAS_I16 *pIncrement, EAS_U8 *pState) +{ + EAS_I32 temp; + + switch (*pState) + { + /* initial state */ + case eEnvelopeStateInit: + *pState = eEnvelopeStateDelay; + *pValue = 0; + *pIncrement = pEnvParams->delayTime; + if (*pIncrement != 0) + return; + /*lint -e{825} falls through to next case */ + + case eEnvelopeStateDelay: + if (*pIncrement) + { + *pIncrement = *pIncrement - 1; + return; + } + + /* calculate attack rate */ + *pState = eEnvelopeStateAttack; + if (pEnvParams->attackTime != ZERO_TIME_IN_CENTS) + { + /*lint -e{702} use shift for performance */ + temp = pEnvParams->attackTime + ((pEnvParams->velToAttack * pVoice->velocity) >> 7); + *pIncrement = ConvertRate(temp); + return; + } + + *pValue = SYNTH_FULL_SCALE_EG1_GAIN; + /*lint -e{825} falls through to next case */ + + case eEnvelopeStateAttack: + if (*pValue < SYNTH_FULL_SCALE_EG1_GAIN) + { + temp = *pValue + *pIncrement; + *pValue = (EAS_I16) (temp < SYNTH_FULL_SCALE_EG1_GAIN ? temp : SYNTH_FULL_SCALE_EG1_GAIN); + return; + } + + /* calculate hold time */ + *pState = eEnvelopeStateHold; + if (pEnvParams->holdTime != ZERO_TIME_IN_CENTS) + { + /*lint -e{702} use shift for performance */ + temp = pEnvParams->holdTime + ((pEnvParams->keyNumToHold * pVoice->note) >> 7); + *pIncrement = ConvertDelay(temp); + return; + } + else + *pIncrement = 0; + /*lint -e{825} falls through to next case */ + + case eEnvelopeStateHold: + if (*pIncrement) + { + *pIncrement = *pIncrement - 1; + return; + } + + /* calculate decay rate */ + *pState = eEnvelopeStateDecay; + if (pEnvParams->decayTime != ZERO_TIME_IN_CENTS) + { + /*lint -e{702} use shift for performance */ + temp = pEnvParams->decayTime + ((pEnvParams->keyNumToDecay * pVoice->note) >> 7); + *pIncrement = ConvertRate(temp); + return; + } + +// *pValue = pEnvParams->sustainLevel; + /*lint -e{825} falls through to next case */ + + case eEnvelopeStateDecay: + if (*pValue > pEnvParams->sustainLevel) + { + temp = *pValue - *pIncrement; + *pValue = (EAS_I16) (temp > pEnvParams->sustainLevel ? temp : pEnvParams->sustainLevel); + return; + } + + *pState = eEnvelopeStateSustain; + *pValue = pEnvParams->sustainLevel; + /*lint -e{825} falls through to next case */ + + case eEnvelopeStateSustain: + return; + + case eEnvelopeStateRelease: + temp = *pValue - *pIncrement; + if (temp <= 0) + { + *pState = eEnvelopeStateMuted; + *pValue = 0; + } + else + *pValue = (EAS_I16) temp; + break; + + case eEnvelopeStateMuted: + *pValue = 0; + return; + + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Envelope in invalid state %d\n", *pState); */ } + break; + } +} + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_dlssynth.h b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_dlssynth.h new file mode 100755 index 0000000..17a635a --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_dlssynth.h @@ -0,0 +1,41 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_dlssynth.h + * + * Contents and purpose: + * Implements the Mobile DLS synthesizer. + * + * Copyright Sonic Network Inc. 2006 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 143 $ + * $Date: 2006-07-17 14:09:35 -0700 (Mon, 17 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_DLSSYNTH_H +#define _EAS_DLSSYNTH_H + +/* prototypes */ +void DLS_MuteVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum); +void DLS_ReleaseVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum); +void DLS_SustainPedal (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, S_SYNTH_CHANNEL *pChannel, EAS_I32 voiceNum); +EAS_RESULT DLS_StartVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_U16 regionIndex); +EAS_BOOL DLS_UpdateVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_I32 *pMixBuffer, EAS_I32 numSamples); + +#endif + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_effects.h b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_effects.h new file mode 100755 index 0000000..86dedac --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_effects.h @@ -0,0 +1,61 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_effects.h + * + * Contents and purpose: + * Defines a generic effects interface. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_EFFECTS_H +#define _EAS_EFFECTS_H + +#include "eas_types.h" + +typedef struct +{ + EAS_RESULT (*pfInit)(EAS_DATA_HANDLE pEASData, EAS_VOID_PTR *pInstData); + void (*pfProcess)(EAS_VOID_PTR pInstData, EAS_PCM *in, EAS_PCM *out, EAS_I32 numSamples); + EAS_RESULT (*pfShutdown)(EAS_DATA_HANDLE pEASData, EAS_VOID_PTR pInstData); + EAS_RESULT (*pFGetParam)(EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue); + EAS_RESULT (*pFSetParam)(EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value); +} S_EFFECTS_INTERFACE; + +typedef struct +{ + EAS_RESULT (*pfInit)(EAS_DATA_HANDLE pEASData, EAS_VOID_PTR *pInstData); + void (*pfProcess)(EAS_VOID_PTR pInstData, EAS_I32 *in, EAS_I32 *out, EAS_I32 numSamples); + EAS_RESULT (*pfShutdown)(EAS_DATA_HANDLE pEASData, EAS_VOID_PTR pInstData); + EAS_RESULT (*pFGetParam)(EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue); + EAS_RESULT (*pFSetParam)(EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value); +} S_EFFECTS32_INTERFACE; + +/* mixer instance data */ +typedef struct +{ + S_EFFECTS_INTERFACE *effect; + EAS_VOID_PTR effectData; +} S_EFFECTS_MODULE; + +#endif /* end _EAS_EFFECTS_H */ + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_flog.c b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_flog.c new file mode 100755 index 0000000..16539f5 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_flog.c @@ -0,0 +1,96 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_flog2.c + * + * Contents and purpose: + * Fixed point square root + * + * + * Copyright (c) 2006 Sonic Network Inc. + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision$ + * $Date$ + *---------------------------------------------------------------------------- +*/ + +#include "eas_types.h" +#include "eas_math.h" + +#define MANTISSA_SHIFT 27 +#define MANTISSA_MASK 0x0000000f +#define MANTISSA_LSB_SHIFT 7 +#define MANTISSA_LSB_MASK 0x000fffff +#define LOG_EXPONENT_SHIFT 10 +#define INTERPOLATION_SHIFT 20 +#define MAX_NEGATIVE (-2147483647-1) + +/* log lookup table */ +static const EAS_U16 eas_log2_table[] = +{ + 0, 90, 174, 254, 330, 402, 470, 536, + 599, 659, 717, 773, 827, 879, 929, 977, + 1024 +}; + +/*---------------------------------------------------------------------------- + * EAS_flog2() + *---------------------------------------------------------------------------- + * Purpose: + * Calculates the log2 of a 32-bit fixed point value + * + * Inputs: + * n = value of interest + * + * Outputs: + * returns the log2 of n + * + *---------------------------------------------------------------------------- +*/ +EAS_I32 EAS_flog2 (EAS_U32 n) +{ + EAS_U32 exp; + EAS_U32 interp; + + /* check for error condition */ + if (n == 0) + return MAX_NEGATIVE; + + /* find exponent */ + for (exp = 31; exp > 0; exp--) + { + /* shift until we get a 1 bit in bit 31 */ + if ((n & (EAS_U32) MAX_NEGATIVE) != 0) + break; + n <<= 1; + } + /*lint -e{701} use shift for performance */ + exp <<= LOG_EXPONENT_SHIFT; + + /* get the least significant bits for interpolation */ + interp = (n >> MANTISSA_LSB_SHIFT) & MANTISSA_LSB_MASK; + + /* get the most significant bits for mantissa lookup */ + n = (n >> MANTISSA_SHIFT) & MANTISSA_MASK; + + /* interpolate mantissa */ + interp = ((eas_log2_table[n+1] - eas_log2_table[n]) * interp) >> INTERPOLATION_SHIFT; + exp += eas_log2_table[n] + interp; + + return (EAS_I32) exp; +} + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_ima_tables.c b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_ima_tables.c new file mode 100755 index 0000000..b03b4d4 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_ima_tables.c @@ -0,0 +1,54 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_ima_tables.c + * + * Contents and purpose: + * Contains the constant tables for IMA encode/decode + * + * Copyright (c) 2005 Sonic Network Inc. + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 760 $ + * $Date: 2007-07-17 23:09:36 -0700 (Tue, 17 Jul 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_types.h" + +/*---------------------------------------------------------------------------- + * ADPCM decode tables + *---------------------------------------------------------------------------- +*/ +const EAS_I16 imaIndexTable[16] = +{ + -1, -1, -1, -1, 2, 4, 6, 8, + -1, -1, -1, -1, 2, 4, 6, 8 +}; + +const EAS_I16 imaStepSizeTable[89] = +{ + 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, + 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, + 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, + 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, + 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, + 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, + 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, + 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, + 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 +}; + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_imaadpcm.c b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_imaadpcm.c new file mode 100755 index 0000000..41280b5 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_imaadpcm.c @@ -0,0 +1,368 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_imaadpcm.c + * + * Contents and purpose: + * Implements the IMA ADPCM decoder + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 847 $ + * $Date: 2007-08-27 21:30:08 -0700 (Mon, 27 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_data.h" +#include "eas_host.h" +#include "eas_pcm.h" +#include "eas_math.h" +#include "eas_report.h" + +// #define _DEBUG_IMA_ADPCM_LOCATE + +/*---------------------------------------------------------------------------- + * externs + *---------------------------------------------------------------------------- +*/ +extern const EAS_I16 imaIndexTable[]; +extern const EAS_I16 imaStepSizeTable[]; + +/*---------------------------------------------------------------------------- + * prototypes + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT IMADecoderInit (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState); +static EAS_RESULT IMADecoderSample (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState); +static void IMADecoderADPCM (S_DECODER_STATE *pState, EAS_U8 nibble); +static EAS_RESULT IMADecoderLocate (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState, EAS_I32 time); + +/*---------------------------------------------------------------------------- + * IMA ADPCM Decoder interface + *---------------------------------------------------------------------------- +*/ +const S_DECODER_INTERFACE IMADecoder = +{ + IMADecoderInit, + IMADecoderSample, + IMADecoderLocate +}; + +/*---------------------------------------------------------------------------- + * IMADecoderInit() + *---------------------------------------------------------------------------- + * Purpose: + * Initializes the IMA ADPCM decoder + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ +static EAS_RESULT IMADecoderInit (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState) +{ + pState->decoderL.step = 0; + pState->decoderR.step = 0; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMADecoderSample() + *---------------------------------------------------------------------------- + * Purpose: + * Decodes an IMA ADPCM sample + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT IMADecoderSample (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState) +{ + EAS_RESULT result; + EAS_I16 sTemp; + + /* if high nibble, decode */ + if (pState->hiNibble) + { + IMADecoderADPCM(&pState->decoderL, (EAS_U8)(pState->srcByte >> 4)); + pState->hiNibble = EAS_FALSE; + } + + /* low nibble, need to fetch another byte */ + else + { + /* check for loop */ + if ((pState->bytesLeft == 0) && (pState->loopSamples != 0)) + { + /* seek to start of loop */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pState->fileHandle, (EAS_I32) (pState->startPos + pState->loopLocation))) != EAS_SUCCESS) + return result; + pState->bytesLeft = pState->byteCount = (EAS_I32) pState->bytesLeftLoop; + pState->blockCount = 0; + pState->flags &= ~PCM_FLAGS_EMPTY; + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMADecoderSample: Rewind file to %d, bytesLeft = %d\n", pState->startPos, pState->bytesLeft); */ } + } + + /* if start of block, fetch new predictor and step index */ + if ((pState->blockSize != 0) && (pState->blockCount == 0) && (pState->bytesLeft != 0)) + { + + /* get predicted sample for left channel */ + if ((result = EAS_HWGetWord(pEASData->hwInstData, pState->fileHandle, &sTemp, EAS_FALSE)) != EAS_SUCCESS) + return result; +#ifdef _DEBUG_IMA_ADPCM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Predictor: Was %d, now %d\n", pState->decoderL.acc, sTemp); */ } +#endif + pState->decoderL.acc = pState->decoderL.x1 = sTemp; + + /* get step index for left channel - upper 8 bits are reserved */ + if ((result = EAS_HWGetWord(pEASData->hwInstData, pState->fileHandle, &sTemp, EAS_FALSE)) != EAS_SUCCESS) + return result; +#ifdef _DEBUG_IMA_ADPCM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Step: Was %d, now %d\n", pState->decoderL.step, sTemp); */ } +#endif + pState->decoderL.step = sTemp & 0xff; + + if (pState->flags & PCM_FLAGS_STEREO) + { + /* get predicted sample for right channel */ + if ((result = EAS_HWGetWord(pEASData->hwInstData, pState->fileHandle, &sTemp, EAS_FALSE)) != EAS_SUCCESS) + return result; + pState->decoderR.acc = pState->decoderR.x1 = sTemp; + + /* get step index for right channel - upper 8 bits are reserved */ + if ((result = EAS_HWGetWord(pEASData->hwInstData, pState->fileHandle, &sTemp, EAS_FALSE)) != EAS_SUCCESS) + return result; +#ifdef _DEBUG_IMA_ADPCM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Step: Was %d, now %d\n", pState->decoderR.step, sTemp); */ } +#endif + pState->decoderR.step = sTemp & 0xff; + + pState->blockCount = pState->blockSize - 8; + pState->bytesLeft -= 8; + } + else + { + pState->blockCount = pState->blockSize - 4; + pState->bytesLeft -= 4; + } + } + else + { + + /* get another ADPCM data pair */ + if (pState->bytesLeft) + { + + if ((result = EAS_HWGetByte(pEASData->hwInstData, pState->fileHandle, &pState->srcByte)) != EAS_SUCCESS) + return result; + + /* decode the low nibble */ + pState->bytesLeft--; + pState->blockCount--; + IMADecoderADPCM(&pState->decoderL, (EAS_U8)(pState->srcByte & 0x0f)); + + if (pState->flags & PCM_FLAGS_STEREO) + IMADecoderADPCM(&pState->decoderR, (EAS_U8)(pState->srcByte >> 4)); + else + pState->hiNibble = EAS_TRUE; + } + + /* out of ADPCM data, generate enough samples to fill buffer */ + else + { + pState->decoderL.x1 = pState->decoderL.x0; + pState->decoderR.x1 = pState->decoderR.x0; + } + } + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMADecoderADPCM() + *---------------------------------------------------------------------------- + * Purpose: + * Decodes an IMA ADPCM sample + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static void IMADecoderADPCM (S_DECODER_STATE *pState, EAS_U8 nibble) +{ + EAS_INT delta; + EAS_INT stepSize; + + /* get stepsize from table */ + stepSize = imaStepSizeTable[pState->step]; + + /* delta = (abs(delta) + 0.5) * step / 4 */ + delta = 0; + if (nibble & 4) + delta += stepSize; + + if (nibble & 2) + /*lint -e{702} use shift for performance */ + delta += stepSize >> 1; + + if (nibble & 1) + /*lint -e{702} use shift for performance */ + delta += stepSize >> 2; + + /*lint -e{702} use shift for performance */ + delta += stepSize >> 3; + + /* integrate the delta */ + if (nibble & 8) + pState->acc -= delta; + else + pState->acc += delta; + + /* saturate */ + if (pState->acc > 32767) + pState->acc = 32767; + if (pState->acc < -32768) + pState->acc = -32768; + pState->x1 = (EAS_PCM) pState->acc; + + /* compute new step size */ + pState->step += imaIndexTable[nibble]; + if (pState->step < 0) + pState->step = 0; + if (pState->step > 88) + pState->step = 88; + +#ifdef _DEBUG_IMA_ADPCM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "In=%u, Pred=%d, Step=%d\n", nibble, pState->acc, imaStepSizeTable[pState->step]); */ } +#endif +} + +/*---------------------------------------------------------------------------- + * IMADecoderLocate() + *---------------------------------------------------------------------------- + * Locate in an IMA ADPCM stream + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT IMADecoderLocate (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState, EAS_I32 time) +{ + EAS_RESULT result; + EAS_I32 temp; + EAS_I32 samplesPerBlock; + EAS_I32 secs, msecs; + + /* no need to calculate if time is zero */ + if (time == 0) + temp = 0; + + /* not zero */ + else + { + + /* can't seek if not a blocked file */ + if (pState->blockSize == 0) + return EAS_ERROR_FEATURE_NOT_AVAILABLE; + + /* calculate number of samples per block */ + if (pState->flags & PCM_FLAGS_STEREO) + samplesPerBlock = pState->blockSize - 7; + else + samplesPerBlock = (pState->blockSize << 1) - 7; + + /* break down into secs and msecs */ + secs = time / 1000; + msecs = time - (secs * 1000); + + /* calculate sample number fraction from msecs */ + temp = (msecs * pState->sampleRate); + temp = (temp >> 10) + ((temp * 49) >> 21); + + /* add integer sample count */ + temp += secs * pState->sampleRate; + +#ifdef _DEBUG_IMA_ADPCM_LOCATE + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x2380b977, 0x00000006 , time, temp); +#endif + + /* for looped samples, calculate position in the loop */ + if ((temp > pState->byteCount) && (pState->loopSamples != 0)) + { + EAS_I32 numBlocks; + EAS_I32 samplesPerLoop; + EAS_I32 samplesInLastBlock; + + numBlocks = (EAS_I32) (pState->loopStart / pState->blockSize); + samplesInLastBlock = (EAS_I32) pState->loopStart - (numBlocks * pState->blockSize); + if (samplesInLastBlock) + { + if (pState->flags & PCM_FLAGS_STEREO) + samplesInLastBlock = samplesInLastBlock - 7; + else + /*lint -e{703} use shift for performance */ + samplesInLastBlock = (samplesInLastBlock << 1) - 7; + } + samplesPerLoop = numBlocks * samplesPerBlock + samplesInLastBlock; + temp = temp % samplesPerLoop; +#ifdef _DEBUG_IMA_ADPCM_LOCATE + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x2380b977, 0x00000007 , numBlocks, samplesPerLoop, samplesInLastBlock, temp); +#endif + } + + /* find start of block for requested sample */ + temp = (temp / samplesPerBlock) * pState->blockSize; +#ifdef _DEBUG_IMA_ADPCM_LOCATE + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x2380b977, 0x00000008 , temp); +#endif + + } + + /* seek to new location */ + if ((result = EAS_PESeek(pEASData, pState, &temp)) != EAS_SUCCESS) + return result; + +#ifdef _DEBUG_IMA_ADPCM_LOCATE + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x2380b977, 0x00000009 , pState->bytesLeft); +#endif + + /* reset state */ + pState->blockCount = 0; + pState->hiNibble = EAS_FALSE; + if ((pState->state != EAS_STATE_PAUSING) && (pState->state != EAS_STATE_PAUSED)) + pState->state = EAS_STATE_READY; + + return EAS_SUCCESS; +} + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_imelody.c b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_imelody.c new file mode 100755 index 0000000..05380e5 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_imelody.c @@ -0,0 +1,1747 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_imelody.c + * + * Contents and purpose: + * iMelody parser + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 797 $ + * $Date: 2007-08-01 00:15:56 -0700 (Wed, 01 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +/* lint doesn't like the way some string.h files look */ +#ifdef _lint +#include "lint_stdlib.h" +#else +#include +#endif + +#include "eas_data.h" +#include "eas_miditypes.h" +#include "eas_parser.h" +#include "eas_report.h" +#include "eas_host.h" +#include "eas_midi.h" +#include "eas_config.h" +#include "eas_vm_protos.h" +#include "eas_imelodydata.h" +#include "eas_ctype.h" + +// #define _DEBUG_IMELODY + +/* increase gain for mono ringtones */ +#define IMELODY_GAIN_OFFSET 8 + +/* length of 32nd note in 1/256ths of a msec for 120 BPM tempo */ +#define DEFAULT_TICK_CONV 16000 +#define TICK_CONVERT 1920000 + +/* default channel and program for iMelody playback */ +#define IMELODY_CHANNEL 0 +#define IMELODY_PROGRAM 80 +#define IMELODY_VEL_MUL 4 +#define IMELODY_VEL_OFS 67 + +/* multiplier for fixed point triplet conversion */ +#define TRIPLET_MULTIPLIER 683 +#define TRIPLET_SHIFT 10 + +static const char* const tokens[] = +{ + "BEGIN:IMELODY", + "VERSION:", + "FORMAT:CLASS", + "NAME:", + "COMPOSER:", + "BEAT:", + "STYLE:", + "VOLUME:", + "MELODY:", + "END:IMELODY" +}; + +/* ledon or ledoff */ +static const char ledStr[] = "edo"; + +/* vibeon or vibeoff */ +static const char vibeStr[] = "ibeo"; + +/* backon or backoff */ +static const char backStr[] = "cko"; + +typedef enum +{ + TOKEN_BEGIN, + TOKEN_VERSION, + TOKEN_FORMAT, + TOKEN_NAME, + TOKEN_COMPOSER, + TOKEN_BEAT, + TOKEN_STYLE, + TOKEN_VOLUME, + TOKEN_MELODY, + TOKEN_END, + TOKEN_INVALID +} ENUM_IMELODY_TOKENS; + +/* lookup table for note values */ +static const EAS_I8 noteTable[] = { 9, 11, 0, 2, 4, 5, 7 }; + +/* inline functions */ +#ifdef _DEBUG_IMELODY +static void PutBackChar (S_IMELODY_DATA *pData) +{ + if (pData->index) + pData->index--; + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "PutBackChar '%c'\n", pData->buffer[pData->index]); */ } +} +#else +EAS_INLINE void PutBackChar (S_IMELODY_DATA *pData) { if (pData->index) pData->index--; } +#endif + + +/* local prototypes */ +static EAS_RESULT IMY_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset); +static EAS_RESULT IMY_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT IMY_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime); +static EAS_RESULT IMY_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode); +static EAS_RESULT IMY_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_STATE *pState); +static EAS_RESULT IMY_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT IMY_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT IMY_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT IMY_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT IMY_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value); +static EAS_RESULT IMY_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue); +static EAS_BOOL IMY_PlayNote (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData, EAS_I8 note, EAS_INT parserMode); +static EAS_BOOL IMY_PlayRest (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData); +static EAS_BOOL IMY_GetDuration (EAS_HW_DATA_HANDLE hwInstData, S_IMELODY_DATA *pData, EAS_I32 *pDuration); +static EAS_BOOL IMY_GetLEDState (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData); +static EAS_BOOL IMY_GetVibeState (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData); +static EAS_BOOL IMY_GetBackState (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData); +static EAS_BOOL IMY_GetVolume (EAS_HW_DATA_HANDLE hwInstData, S_IMELODY_DATA *pData, EAS_BOOL inHeader); +static EAS_BOOL IMY_GetNumber (EAS_HW_DATA_HANDLE hwInstData, S_IMELODY_DATA *pData, EAS_INT *temp, EAS_BOOL inHeader); +static EAS_RESULT IMY_ParseHeader (S_EAS_DATA *pEASData, S_IMELODY_DATA* pData); +static EAS_I8 IMY_GetNextChar (EAS_HW_DATA_HANDLE hwInstData, S_IMELODY_DATA *pData, EAS_BOOL inHeader); +static EAS_RESULT IMY_ReadLine (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle, EAS_I8 *buffer, EAS_I32 *pStartLine); +static EAS_INT IMY_ParseLine (EAS_I8 *buffer, EAS_U8 *pIndex); + + +/*---------------------------------------------------------------------------- + * + * EAS_iMelody_Parser + * + * This structure contains the functional interface for the iMelody parser + *---------------------------------------------------------------------------- +*/ +const S_FILE_PARSER_INTERFACE EAS_iMelody_Parser = +{ + IMY_CheckFileType, + IMY_Prepare, + IMY_Time, + IMY_Event, + IMY_State, + IMY_Close, + IMY_Reset, + IMY_Pause, + IMY_Resume, + NULL, + IMY_SetData, + IMY_GetData, + NULL +}; + +/*---------------------------------------------------------------------------- + * IMY_CheckFileType() + *---------------------------------------------------------------------------- + * Purpose: + * Check the file type to see if we can parse it + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT IMY_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset) +{ + S_IMELODY_DATA* pData; + EAS_I8 buffer[MAX_LINE_SIZE+1]; + EAS_U8 index; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_CheckFileType\n"); */ } +#endif + + /* read the first line of the file */ + *ppHandle = NULL; + if (IMY_ReadLine(pEASData->hwInstData, fileHandle, buffer, NULL) != EAS_SUCCESS) + return EAS_SUCCESS; + + /* check for header string */ + if (IMY_ParseLine(buffer, &index) == TOKEN_BEGIN) + { + + /* check for static memory allocation */ + if (pEASData->staticMemoryModel) + pData = EAS_CMEnumData(EAS_CM_IMELODY_DATA); + else + pData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_IMELODY_DATA)); + if (!pData) + return EAS_ERROR_MALLOC_FAILED; + EAS_HWMemSet(pData, 0, sizeof(S_IMELODY_DATA)); + + /* initialize */ + pData->fileHandle = fileHandle; + pData->fileOffset = offset; + pData->state = EAS_STATE_ERROR; + pData->state = EAS_STATE_OPEN; + + /* return a pointer to the instance data */ + *ppHandle = pData; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMY_Prepare() + *---------------------------------------------------------------------------- + * Purpose: + * Prepare to parse the file. Allocates instance data (or uses static allocation for + * static memory model). + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT IMY_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_IMELODY_DATA* pData; + EAS_RESULT result; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_Prepare\n"); */ } +#endif + + /* check for valid state */ + pData = (S_IMELODY_DATA*) pInstData; + if (pData->state != EAS_STATE_OPEN) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + /* instantiate a synthesizer */ + if ((result = VMInitMIDI(pEASData, &pData->pSynth)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitMIDI returned %d\n", result); */ } + return result; + } + + /* parse the header */ + if ((result = IMY_ParseHeader(pEASData, pData)) != EAS_SUCCESS) + return result; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Prepare: state set to EAS_STATE_READY\n"); */ } +#endif + + pData ->state = EAS_STATE_READY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMY_Time() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the time of the next event in msecs + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * pTime - pointer to variable to hold time of next event (in msecs) + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ +static EAS_RESULT IMY_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime) +{ + S_IMELODY_DATA *pData; + + pData = (S_IMELODY_DATA*) pInstData; + + /* return time in milliseconds */ + /*lint -e{704} use shift instead of division */ + *pTime = pData->time >> 8; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMY_Event() + *---------------------------------------------------------------------------- + * Purpose: + * Parse the next event in the file + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT IMY_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode) +{ + S_IMELODY_DATA* pData; + EAS_RESULT result; + EAS_I8 c; + EAS_BOOL eof; + EAS_INT temp; + + pData = (S_IMELODY_DATA*) pInstData; + if (pData->state >= EAS_STATE_OPEN) + return EAS_SUCCESS; + + if (pData->state == EAS_STATE_READY) { + pData->state = EAS_STATE_PLAY; + } + + /* initialize MIDI channel when the track starts playing */ + if (pData->time == 0) + { + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Event: Reset\n"); */ } +#endif + /* set program to square lead */ + VMProgramChange(pEASData->pVoiceMgr, pData->pSynth, IMELODY_CHANNEL, IMELODY_PROGRAM); + + /* set channel volume to max */ + VMControlChange(pEASData->pVoiceMgr, pData->pSynth, IMELODY_CHANNEL, 7, 127); + } + + /* check for end of note */ + if (pData->note) + { + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Stopping note %d\n", pData->note); */ } +#endif + /* stop the note */ + VMStopNote(pEASData->pVoiceMgr, pData->pSynth, IMELODY_CHANNEL, pData->note, 0); + pData->note = 0; + + /* check for rest between notes */ + if (pData->restTicks) + { + pData->time += pData->restTicks; + pData->restTicks = 0; + return EAS_SUCCESS; + } + } + + /* parse the next event */ + eof = EAS_FALSE; + while (!eof) + { + + /* get next character */ + c = IMY_GetNextChar(pEASData->hwInstData, pData, EAS_FALSE); + + switch (c) + { + /* start repeat */ + case '(': + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter repeat section\n", c); */ } +#endif + + if (pData->repeatOffset < 0) + { + pData->repeatOffset = pData->startLine + (EAS_I32) pData->index; + + /* save current time and check it later to make sure the loop isn't zero length */ + pData->repeatTime = pData->time; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Repeat offset = %d\n", pData->repeatOffset); */ } +#endif + } + else + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Ignoring nested repeat section\n"); */ } + break; + + /* end repeat */ + case ')': + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "End repeat section, repeat offset = %d\n", pData->repeatOffset); */ } +#endif + /* ignore zero-length loops */ + if (pData->repeatTime == pData->time) { + pData->repeatCount = -1; + pData->repeatOffset = -1; + } else if (pData->repeatCount >= 0) { + + /* decrement repeat count (repeatCount == 0 means infinite loop) */ + if (pData->repeatCount > 0) + { + if (--pData->repeatCount == 0) + { + pData->repeatCount = -1; +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Repeat loop complete\n"); */ } +#endif + } + } + +//2 TEMPORARY FIX: If locating, don't do infinite loops. +//3 We need a different mode for metadata parsing where we don't loop at all + if ((parserMode == eParserModePlay) || (pData->repeatCount != 0)) + { + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Rewinding file for repeat\n"); */ } +#endif + /* rewind to start of loop */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pData->fileHandle, pData->repeatOffset)) != EAS_SUCCESS) + return result; + IMY_ReadLine(pEASData->hwInstData, pData->fileHandle, pData->buffer, &pData->startLine); + pData->index = 0; + + /* if last loop, prevent future loops */ + if (pData->repeatCount == -1) + pData->repeatOffset = -1; + } + } + break; + + /* repeat count */ + case '@': + if (!IMY_GetNumber(pEASData->hwInstData, pData, &temp, EAS_FALSE)) + eof = EAS_TRUE; + else if (pData->repeatOffset > 0) + { + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Repeat count = %dt", pData->repeatCount); */ } +#endif + if (pData->repeatCount < 0) + pData->repeatCount = (EAS_I16) temp; + } + break; + + /* volume */ + case 'V': + if (!IMY_GetVolume(pEASData->hwInstData, pData, EAS_FALSE)) + eof = EAS_TRUE; + break; + + /* flat */ + case '&': + pData->noteModifier = -1; + break; + + /* sharp */ + case '#': + pData->noteModifier = +1; + break; + + /* octave */ + case '*': + c = IMY_GetNextChar(pEASData->hwInstData, pData, EAS_FALSE); + if (IsDigit(c)) + pData->octave = (EAS_U8) ((c - '0' + 1) * 12); + else if (!c) + eof = EAS_TRUE; + break; + + /* ledon or ledoff */ + case 'l': + if (!IMY_GetLEDState(pEASData, pData)) + eof = EAS_TRUE; + break; + + /* vibeon or vibeoff */ + case 'v': + if (!IMY_GetVibeState(pEASData, pData)) + eof = EAS_TRUE; + break; + + /* either a B note or backon or backoff */ + case 'b': + if (IMY_GetNextChar(pEASData->hwInstData, pData, EAS_FALSE) == 'a') + { + if (!IMY_GetBackState(pEASData, pData)) + eof = EAS_TRUE; + } + else + { + PutBackChar(pData); + if (IMY_PlayNote(pEASData, pData, c, parserMode)) + return EAS_SUCCESS; + eof = EAS_TRUE; + } + break; + + /* rest */ + case 'r': + case 'R': + if (IMY_PlayRest(pEASData, pData)) + return EAS_SUCCESS; + eof = EAS_TRUE; + break; + + /* EOF */ + case 0: +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Event: end of iMelody file detected\n"); */ } +#endif + eof = EAS_TRUE; + break; + + /* must be a note */ + default: + c = ToLower(c); + if ((c >= 'a') && (c <= 'g')) + { + if (IMY_PlayNote(pEASData, pData, c, parserMode)) + return EAS_SUCCESS; + eof = EAS_TRUE; + } + else + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Ignoring unexpected character '%c' [0x%02x]\n", c, c); */ } + break; + } + } + + /* handle EOF */ +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Event: state set to EAS_STATE_STOPPING\n"); */ } +#endif + pData->state = EAS_STATE_STOPPING; + VMReleaseAllVoices(pEASData->pVoiceMgr, pData->pSynth); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMY_State() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current state of the stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * pState - pointer to variable to store state + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ +static EAS_RESULT IMY_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pState) +{ + S_IMELODY_DATA* pData; + + /* establish pointer to instance data */ + pData = (S_IMELODY_DATA*) pInstData; + + /* if stopping, check to see if synth voices are active */ + if (pData->state == EAS_STATE_STOPPING) + { + if (VMActiveVoices(pData->pSynth) == 0) + { + pData->state = EAS_STATE_STOPPED; +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_State: state set to EAS_STATE_STOPPED\n"); */ } +#endif + } + } + + if (pData->state == EAS_STATE_PAUSING) + { + if (VMActiveVoices(pData->pSynth) == 0) + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_State: state set to EAS_STATE_PAUSED\n"); */ } +#endif + pData->state = EAS_STATE_PAUSED; + } + } + + /* return current state */ + *pState = pData->state; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMY_Close() + *---------------------------------------------------------------------------- + * Purpose: + * Close the file and clean up + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT IMY_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_IMELODY_DATA* pData; + EAS_RESULT result; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Close: close file\n"); */ } +#endif + + pData = (S_IMELODY_DATA*) pInstData; + + /* close the file */ + if ((result = EAS_HWCloseFile(pEASData->hwInstData, pData->fileHandle)) != EAS_SUCCESS) + return result; + + /* free the synth */ + if (pData->pSynth != NULL) + VMMIDIShutdown(pEASData, pData->pSynth); + + /* if using dynamic memory, free it */ + if (!pEASData->staticMemoryModel) + EAS_HWFree(pEASData->hwInstData, pData); + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMY_Reset() + *---------------------------------------------------------------------------- + * Purpose: + * Reset the sequencer. Used for locating backwards in the file. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT IMY_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_IMELODY_DATA* pData; + EAS_RESULT result; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Reset: reset file\n"); */ } +#endif + pData = (S_IMELODY_DATA*) pInstData; + + /* reset the synth */ + VMReset(pEASData->pVoiceMgr, pData->pSynth, EAS_TRUE); + + /* reset time to zero */ + pData->time = 0; + pData->note = 0; + + /* reset file position and re-parse header */ + pData->state = EAS_STATE_ERROR; + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pData->fileHandle, pData->fileOffset)) != EAS_SUCCESS) + return result; + if ((result = IMY_ParseHeader (pEASData, pData)) != EAS_SUCCESS) + return result; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Reset: state set to EAS_STATE_ERROR\n"); */ } +#endif + + pData->state = EAS_STATE_READY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMY_Pause() + *---------------------------------------------------------------------------- + * Purpose: + * Pauses the sequencer. Mutes all voices and sets state to pause. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT IMY_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_IMELODY_DATA *pData; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Pause: pause file\n"); */ } +#endif + + /* can't pause a stopped stream */ + pData = (S_IMELODY_DATA*) pInstData; + if (pData->state == EAS_STATE_STOPPED) + return EAS_ERROR_ALREADY_STOPPED; + + /* mute the synthesizer */ + VMMuteAllVoices(pEASData->pVoiceMgr, pData->pSynth); + pData->state = EAS_STATE_PAUSING; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMY_Resume() + *---------------------------------------------------------------------------- + * Purpose: + * Resume playing after a pause, sets state back to playing. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ +static EAS_RESULT IMY_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_IMELODY_DATA *pData; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Resume: resume file\n"); */ } +#endif + + /* can't resume a stopped stream */ + pData = (S_IMELODY_DATA*) pInstData; + if (pData->state == EAS_STATE_STOPPED) + return EAS_ERROR_ALREADY_STOPPED; + + /* nothing to do but resume playback */ + pData->state = EAS_STATE_PLAY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMY_SetData() + *---------------------------------------------------------------------------- + * Purpose: + * Adjust tempo relative to song tempo + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * pInstData - pointer to iMelody instance data + * rate - rate (28-bit fractional amount) + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ +static EAS_RESULT IMY_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value) +{ + S_IMELODY_DATA *pData; + + pData = (S_IMELODY_DATA*) pInstData; + switch (param) + { + + /* set metadata callback */ + case PARSER_DATA_METADATA_CB: + EAS_HWMemCpy(&pData->metadata, (void*) value, sizeof(S_METADATA_CB)); + break; + + default: + return EAS_ERROR_INVALID_PARAMETER; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMY_GetData() + *---------------------------------------------------------------------------- + * Purpose: + * Return the file type + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * pInstData - pointer to iMelody instance data + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ +static EAS_RESULT IMY_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue) +{ + S_IMELODY_DATA *pData; + + pData = (S_IMELODY_DATA*) pInstData; + + switch (param) + { + /* return file type as iMelody */ + case PARSER_DATA_FILE_TYPE: + *pValue = EAS_FILE_IMELODY; + break; + + case PARSER_DATA_SYNTH_HANDLE: + *pValue = (EAS_I32) pData->pSynth; + break; + + case PARSER_DATA_GAIN_OFFSET: + *pValue = IMELODY_GAIN_OFFSET; + break; + + default: + return EAS_ERROR_INVALID_PARAMETER; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMY_PlayNote() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL IMY_PlayNote (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData, EAS_I8 note, EAS_INT parserMode) +{ + EAS_I32 duration; + EAS_U8 velocity; + + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_PlayNote: start note %d\n", note); */ } +#endif + + /* get the duration */ + if (!IMY_GetDuration(pEASData->hwInstData, pData, &duration)) + return EAS_FALSE; + + /* save note value */ + pData->note = (EAS_U8) (pData->octave + noteTable[note - 'a'] + pData->noteModifier); + velocity = (EAS_U8) (pData->volume ? pData->volume * IMELODY_VEL_MUL + IMELODY_VEL_OFS : 0); + + /* start note only if in play mode */ + if (parserMode == eParserModePlay) + VMStartNote(pEASData->pVoiceMgr, pData->pSynth, IMELODY_CHANNEL, pData->note, velocity); + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_PlayNote: Start note %d, duration %d\n", pData->note, duration); */ } +#endif + + /* determine note length */ + switch (pData->style) + { + case 0: + /*lint -e{704} shift for performance */ + pData->restTicks = duration >> 4; + break; + case 1: + pData->restTicks = 0; + break; + case 2: + /*lint -e{704} shift for performance */ + pData->restTicks = duration >> 1; + break; + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "IMY_PlayNote: Note style out of range: %d\n", pData->style); */ } + /*lint -e{704} shift for performance */ + pData->restTicks = duration >> 4; + break; + } + + /* next event is at end of this note */ + pData->time += duration - pData->restTicks; + + /* reset the flat/sharp modifier */ + pData->noteModifier = 0; + + return EAS_TRUE; +} + +/*---------------------------------------------------------------------------- + * IMY_PlayRest() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL IMY_PlayRest (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData) +{ + EAS_I32 duration; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_PlayRest]n"); */ } +#endif + + /* get the duration */ + if (!IMY_GetDuration(pEASData->hwInstData, pData, &duration)) + return EAS_FALSE; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_PlayRest: note duration %d\n", duration); */ } +#endif + + /* next event is at end of this note */ + pData->time += duration; + return EAS_TRUE; +} + +/*---------------------------------------------------------------------------- + * IMY_GetDuration() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ + +static EAS_BOOL IMY_GetDuration (EAS_HW_DATA_HANDLE hwInstData, S_IMELODY_DATA *pData, EAS_I32 *pDuration) +{ + EAS_I32 duration; + EAS_I8 c; + + /* get the duration */ + *pDuration = 0; + c = IMY_GetNextChar(hwInstData, pData, EAS_FALSE); + if (!c) + return EAS_FALSE; + if ((c < '0') || (c > '5')) + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetDuration: error in duration '%c'\n", c); */ } +#endif + return EAS_FALSE; + } + + /* calculate total length of note */ + duration = pData->tick * (1 << ('5' - c)); + + /* check for duration modifier */ + c = IMY_GetNextChar(hwInstData, pData, EAS_FALSE); + if (c) + { + if (c == '.') + /*lint -e{704} shift for performance */ + duration += duration >> 1; + else if (c == ':') + /*lint -e{704} shift for performance */ + duration += (duration >> 1) + (duration >> 2); + else if (c == ';') + /*lint -e{704} shift for performance */ + duration = (duration * TRIPLET_MULTIPLIER) >> TRIPLET_SHIFT; + else + PutBackChar(pData); + } + + *pDuration = duration; + return EAS_TRUE; +} + +/*---------------------------------------------------------------------------- + * IMY_GetLEDState() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL IMY_GetLEDState (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData) +{ + EAS_I8 c; + EAS_INT i; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_GetLEDState\n"); */ } +#endif + + for (i = 0; i < 5; i++) + { + c = IMY_GetNextChar(pEASData->hwInstData, pData, EAS_FALSE); + if (!c) + return EAS_FALSE; + switch (i) + { + case 3: + if (c == 'n') + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetLEDState: LED on\n"); */ } +#endif + EAS_HWLED(pEASData->hwInstData, EAS_TRUE); + return EAS_TRUE; + } + else if (c != 'f') + return EAS_FALSE; + break; + + case 4: + if (c == 'f') + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetLEDState: LED off\n"); */ } +#endif + EAS_HWLED(pEASData->hwInstData, EAS_FALSE); + return EAS_TRUE; + } + return EAS_FALSE; + + default: + if (c != ledStr[i]) + return EAS_FALSE; + break; + } + } + return EAS_FALSE; +} + +/*---------------------------------------------------------------------------- + * IMY_GetVibeState() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL IMY_GetVibeState (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData) +{ + EAS_I8 c; + EAS_INT i; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_GetVibeState\n"); */ } +#endif + + for (i = 0; i < 6; i++) + { + c = IMY_GetNextChar(pEASData->hwInstData, pData, EAS_FALSE); + if (!c) + return EAS_FALSE; + switch (i) + { + case 4: + if (c == 'n') + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetVibeState: vibrate on\n"); */ } +#endif + EAS_HWVibrate(pEASData->hwInstData, EAS_TRUE); + return EAS_TRUE; + } + else if (c != 'f') + return EAS_FALSE; + break; + + case 5: + if (c == 'f') + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetVibeState: vibrate off\n"); */ } +#endif + EAS_HWVibrate(pEASData->hwInstData, EAS_FALSE); + return EAS_TRUE; + } + return EAS_FALSE; + + default: + if (c != vibeStr[i]) + return EAS_FALSE; + break; + } + } + return EAS_FALSE; +} + +/*---------------------------------------------------------------------------- + * IMY_GetBackState() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL IMY_GetBackState (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData) +{ + EAS_I8 c; + EAS_INT i; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_GetBackState\n"); */ } +#endif + + for (i = 0; i < 5; i++) + { + c = IMY_GetNextChar(pEASData->hwInstData, pData, EAS_FALSE); + if (!c) + return EAS_FALSE; + switch (i) + { + case 3: + if (c == 'n') + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetBackState: backlight on\n"); */ } +#endif + EAS_HWBackLight(pEASData->hwInstData, EAS_TRUE); + return EAS_TRUE; + } + else if (c != 'f') + return EAS_FALSE; + break; + + case 4: + if (c == 'f') + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetBackState: backlight off\n"); */ } +#endif + EAS_HWBackLight(pEASData->hwInstData, EAS_FALSE); + return EAS_TRUE; + } + return EAS_FALSE; + + default: + if (c != backStr[i]) + return EAS_FALSE; + break; + } + } + return EAS_FALSE; +} + +/*---------------------------------------------------------------------------- + * IMY_GetVolume() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL IMY_GetVolume (EAS_HW_DATA_HANDLE hwInstData, S_IMELODY_DATA *pData, EAS_BOOL inHeader) +{ + EAS_INT temp; + EAS_I8 c; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_GetVolume\n"); */ } +#endif + + c = IMY_GetNextChar(hwInstData, pData, inHeader); + if (c == '+') + { + if (pData->volume < 15) + pData->volume++; + return EAS_TRUE; + } + else if (c == '-') + { + if (pData->volume > 0) + pData->volume--; + return EAS_TRUE; + } + else if (IsDigit(c)) + temp = c - '0'; + else + return EAS_FALSE; + + c = IMY_GetNextChar(hwInstData, pData, inHeader); + if (IsDigit(c)) + temp = temp * 10 + c - '0'; + else if (c) + PutBackChar(pData); + if ((temp >= 0) && (temp <= 15)) + { + if (inHeader && (temp == 0)) + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Ignoring V0 encountered in header\n"); */ } + else + pData->volume = (EAS_U8) temp; + } + return EAS_TRUE; +} + +/*---------------------------------------------------------------------------- + * IMY_GetNumber() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL IMY_GetNumber (EAS_HW_DATA_HANDLE hwInstData, S_IMELODY_DATA *pData, EAS_INT *temp, EAS_BOOL inHeader) +{ + EAS_BOOL ok; + EAS_I8 c; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_GetNumber\n"); */ } +#endif + + *temp = 0; + ok = EAS_FALSE; + for (;;) + { + c = IMY_GetNextChar(hwInstData, pData, inHeader); + if (IsDigit(c)) + { + *temp = *temp * 10 + c - '0'; + ok = EAS_TRUE; + } + else + { + if (c) + PutBackChar(pData); + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetNumber: value %d\n", *temp); */ } +#endif + + return ok; + } + } +} + +/*---------------------------------------------------------------------------- + * IMY_GetVersion() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL IMY_GetVersion (S_IMELODY_DATA *pData, EAS_INT *pVersion) +{ + EAS_I8 c; + EAS_INT temp; + EAS_INT version; + + version = temp = 0; + for (;;) + { + c = pData->buffer[pData->index++]; + if ((c == 0) || (c == '.')) + { + /*lint -e{701} use shift for performance */ + version = (version << 8) + temp; + if (c == 0) + { + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetVersion: version 0x%04x\n", version); */ } +#endif + + *pVersion = version; + return EAS_TRUE; + } + temp = 0; + } + else if (IsDigit(c)) + temp = (temp * 10) + c - '0'; + } +} + +/*---------------------------------------------------------------------------- + * IMY_MetaData() + *---------------------------------------------------------------------------- + * Purpose: + * Prepare to parse the file. Allocates instance data (or uses static allocation for + * static memory model). + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static void IMY_MetaData (S_IMELODY_DATA *pData, E_EAS_METADATA_TYPE metaType, EAS_I8 *buffer) +{ + EAS_I32 len; + + /* check for callback */ + if (!pData->metadata.callback) + return; + + /* copy data to host buffer */ + len = (EAS_I32) strlen((char*) buffer); + if (len >pData->metadata.bufferSize) + len = pData->metadata.bufferSize; + strncpy((char*) pData->metadata.buffer, (char*) buffer, (size_t) len); + pData->metadata.buffer[len] = 0; + + /* callback to host */ + pData->metadata.callback(metaType, pData->metadata.buffer, pData->metadata.pUserData); +} + +/*---------------------------------------------------------------------------- + * IMY_ParseHeader() + *---------------------------------------------------------------------------- + * Purpose: + * Prepare to parse the file. Allocates instance data (or uses static allocation for + * static memory model). + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT IMY_ParseHeader (S_EAS_DATA *pEASData, S_IMELODY_DATA* pData) +{ + EAS_RESULT result; + EAS_INT token; + EAS_INT temp; + EAS_I8 c; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_ParseHeader\n"); */ } +#endif + + /* initialize some defaults */ + pData->time = 0; + pData->tick = DEFAULT_TICK_CONV; + pData->note = 0; + pData->noteModifier = 0; + pData ->restTicks = 0; + pData->volume = 7; + pData->octave = 60; + pData->repeatOffset = -1; + pData->repeatCount = -1; + pData->style = 0; + + /* force the read of the first line */ + pData->index = 1; + + /* read data until we get to melody */ + for (;;) + { + /* read a line from the file and parse the token */ + if (pData->index != 0) + { + if ((result = IMY_ReadLine(pEASData->hwInstData, pData->fileHandle, pData->buffer, &pData->startLine)) != EAS_SUCCESS) + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_ParseHeader: IMY_ReadLine returned %d\n", result); */ } +#endif + return result; + } + } + token = IMY_ParseLine(pData->buffer, &pData->index); + + switch (token) + { + /* ignore these valid tokens */ + case TOKEN_BEGIN: + break; + + case TOKEN_FORMAT: + if (!IMY_GetVersion(pData, &temp)) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Invalid FORMAT field '%s'\n", pData->buffer); */ } + return EAS_ERROR_FILE_FORMAT; + } + if ((temp != 0x0100) && (temp != 0x0200)) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Unsupported FORMAT %02x\n", temp); */ } + return EAS_ERROR_UNRECOGNIZED_FORMAT; + } + break; + + case TOKEN_VERSION: + if (!IMY_GetVersion(pData, &temp)) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Invalid VERSION field '%s'\n", pData->buffer); */ } + return EAS_ERROR_FILE_FORMAT; + } + if ((temp != 0x0100) && (temp != 0x0102)) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Unsupported VERSION %02x\n", temp); */ } + return EAS_ERROR_UNRECOGNIZED_FORMAT; + } + break; + + case TOKEN_NAME: + IMY_MetaData(pData, EAS_METADATA_TITLE, pData->buffer + pData->index); + break; + + case TOKEN_COMPOSER: + IMY_MetaData(pData, EAS_METADATA_AUTHOR, pData->buffer + pData->index); + break; + + /* handle beat */ + case TOKEN_BEAT: + IMY_GetNumber(pEASData->hwInstData, pData, &temp, EAS_TRUE); + if ((temp >= 25) && (temp <= 900)) + pData->tick = TICK_CONVERT / temp; + break; + + /* handle style */ + case TOKEN_STYLE: + c = IMY_GetNextChar(pEASData->hwInstData, pData, EAS_TRUE); + if (c == 'S') + c = IMY_GetNextChar(pEASData->hwInstData, pData, EAS_TRUE); + if ((c >= '0') && (c <= '2')) + pData->style = (EAS_U8) (c - '0'); + else + { + PutBackChar(pData); + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Error in style command: %s\n", pData->buffer); */ } + } + break; + + /* handle volume */ + case TOKEN_VOLUME: + c = IMY_GetNextChar(pEASData->hwInstData, pData, EAS_TRUE); + if (c != 'V') + { + PutBackChar(pData); + if (!IsDigit(c)) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Error in volume command: %s\n", pData->buffer); */ } + break; + } + } + IMY_GetVolume(pEASData->hwInstData, pData, EAS_TRUE); + break; + + case TOKEN_MELODY: +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Header successfully parsed\n"); */ } +#endif + return EAS_SUCCESS; + + case TOKEN_END: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Unexpected END:IMELODY encountered\n"); */ } + return EAS_ERROR_FILE_FORMAT; + + default: + /* force a read of the next line */ + pData->index = 1; + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Ignoring unrecognized token in iMelody file: %s\n", pData->buffer); */ } + break; + } + } +} + +/*---------------------------------------------------------------------------- + * IMY_GetNextChar() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_I8 IMY_GetNextChar (EAS_HW_DATA_HANDLE hwInstData, S_IMELODY_DATA *pData, EAS_BOOL inHeader) +{ + EAS_I8 c; + EAS_U8 index; + + for (;;) + { + /* get next character */ + c = pData->buffer[pData->index++]; + + /* buffer empty, read more */ + if (!c) + { + /* don't read the next line in the header */ + if (inHeader) + return 0; + + pData->index = 0; + pData->buffer[0] = 0; + if (IMY_ReadLine(hwInstData, pData->fileHandle, pData->buffer, &pData->startLine) != EAS_SUCCESS) + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetNextChar: EOF\n"); */ } +#endif + return 0; + } + + /* check for END:IMELODY token */ + if (IMY_ParseLine(pData->buffer, &index) == TOKEN_END) + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetNextChar: found END:IMELODY\n"); */ } +#endif + pData->buffer[0] = 0; + return 0; + } + continue; + } + + /* ignore white space */ + if (!IsSpace(c)) + { + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetNextChar returned '%c'\n", c); */ } +#endif + return c; + } + } +} + +/*---------------------------------------------------------------------------- + * IMY_ReadLine() + *---------------------------------------------------------------------------- + * Purpose: + * Reads a line of input from the file, discarding the CR/LF + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT IMY_ReadLine (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle, EAS_I8 *buffer, EAS_I32 *pStartLine) +{ + EAS_RESULT result; + EAS_INT i; + EAS_I8 c; + + /* fetch current file position and save it */ + if (pStartLine != NULL) + { + if ((result = EAS_HWFilePos(hwInstData, fileHandle, pStartLine)) != EAS_SUCCESS) + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_ParseHeader: EAS_HWFilePos returned %d\n", result); */ } +#endif + return result; + } + } + + buffer[0] = 0; + for (i = 0; i < MAX_LINE_SIZE; ) + { + if ((result = EAS_HWGetByte(hwInstData, fileHandle, &c)) != EAS_SUCCESS) + { + if ((result == EAS_EOF) && (i > 0)) + break; + return result; + } + + /* return on LF or end of data */ + if (c == '\n') + break; + + /* store characters in buffer */ + if (c != '\r') + buffer[i++] = c; + } + buffer[i] = 0; + +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_ReadLine read %s\n", buffer); */ } +#endif + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * IMY_ParseLine() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_INT IMY_ParseLine (EAS_I8 *buffer, EAS_U8 *pIndex) +{ + EAS_INT i; + EAS_INT j; + + /* there's no strnicmp() in stdlib, so we have to roll our own */ + for (i = 0; i < TOKEN_INVALID; i++) + { + for (j = 0; ; j++) + { + /* end of token, must be a match */ + if (tokens[i][j] == 0) + { +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_ParseLine found token %d\n", i); */ } +#endif + *pIndex = (EAS_U8) j; + return i; + } + if (tokens[i][j] != ToUpper(buffer[j])) + break; + } + } +#ifdef _DEBUG_IMELODY + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_ParseLine: no token found\n"); */ } +#endif + return TOKEN_INVALID; +} + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_imelodydata.c b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_imelodydata.c new file mode 100755 index 0000000..9437e08 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_imelodydata.c @@ -0,0 +1,43 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_imelodydata.c + * + * Contents and purpose: + * SMF File Parser + * + * This file contains data definitions for the SMF parser. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 547 $ + * $Date: 2007-01-31 16:30:17 -0800 (Wed, 31 Jan 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_types.h" +#include "eas_imelodydata.h" + +/*---------------------------------------------------------------------------- + * + * eas_iMelodyData + * + * Static memory allocation for iMelody parser + *---------------------------------------------------------------------------- +*/ +S_IMELODY_DATA eas_iMelodyData; + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_imelodydata.h b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_imelodydata.h new file mode 100755 index 0000000..17d03dc --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_imelodydata.h @@ -0,0 +1,74 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_imelodydata.h + * + * Contents and purpose: + * SMF File Parser + * + * This file contains data declarations for the iMelody parser. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 778 $ + * $Date: 2007-07-23 16:45:17 -0700 (Mon, 23 Jul 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef EAS_IMELODYDATA_H +#define EAS_IMELODYDATA_H + +#include "eas_data.h" + +/* maximum line size as specified in iMelody V1.2 spec */ +#define MAX_LINE_SIZE 75 + +/*---------------------------------------------------------------------------- + * + * S_IMELODY_DATA + * + * This structure contains the state data for the iMelody parser + *---------------------------------------------------------------------------- +*/ + +typedef struct +{ + EAS_FILE_HANDLE fileHandle; /* file handle */ + S_SYNTH *pSynth; /* pointer to synth */ + EAS_I32 fileOffset; /* offset to start of data */ + EAS_I32 time; /* current time in 256ths of a msec */ + EAS_I32 tickBase; /* basline length of 32nd note in 256th of a msec */ + EAS_I32 tick; /* actual length of 32nd note in 256th of a msec */ + EAS_I32 restTicks; /* ticks to rest after current note */ + EAS_I32 startLine; /* file offset at start of line (for repeats) */ + EAS_I32 repeatOffset; /* file offset to start of repeat section */ + EAS_I32 repeatTime; /* time at start of repeat section */ + S_METADATA_CB metadata; /* metadata callback */ + EAS_I16 repeatCount; /* repeat counter */ + EAS_U8 state; /* current state EAS_STATE_XXXX */ + EAS_U8 style; /* from STYLE */ + EAS_U8 index; /* index into buffer */ + EAS_U8 octave; /* octave prefix */ + EAS_U8 volume; /* current volume */ + EAS_U8 note; /* MIDI note number */ + EAS_I8 noteModifier; /* sharp or flat */ + EAS_I8 buffer[MAX_LINE_SIZE+1]; /* buffer for ASCII data */ +} S_IMELODY_DATA; + +#endif + + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_math.c b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_math.c new file mode 100755 index 0000000..dc85051 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_math.c @@ -0,0 +1,168 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_math.c + * + * Contents and purpose: + * Contains common math routines for the various audio engines. + * + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 586 $ + * $Date: 2007-03-08 20:33:04 -0800 (Thu, 08 Mar 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas.h" +#include "eas_math.h" + +/* anything less than this converts to a fraction too small to represent in 32-bits */ +#define MIN_CENTS -18000 + +/*---------------------------------------------------------------------------- + * EAS_Calculate2toX() + *---------------------------------------------------------------------------- + * Purpose: + * Calculate 2^x + * + * Inputs: + * nCents - measured in cents + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * nResult - int.frac result (where frac has NUM_DENTS_FRAC_BITS) + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_I32 EAS_Calculate2toX (EAS_I32 nCents) +{ + EAS_I32 nDents; + EAS_I32 nExponentInt, nExponentFrac; + EAS_I32 nTemp1, nTemp2; + EAS_I32 nResult; + + /* check for minimum value */ + if (nCents < MIN_CENTS) + return 0; + + /* for the time being, convert cents to dents */ + nDents = FMUL_15x15(nCents, CENTS_TO_DENTS); + + nExponentInt = GET_DENTS_INT_PART(nDents); + nExponentFrac = GET_DENTS_FRAC_PART(nDents); + + /* + implement 2^(fracPart) as a power series + */ + nTemp1 = GN2_TO_X2 + MULT_DENTS_COEF(nExponentFrac, GN2_TO_X3); + nTemp2 = GN2_TO_X1 + MULT_DENTS_COEF(nExponentFrac, nTemp1); + nTemp1 = GN2_TO_X0 + MULT_DENTS_COEF(nExponentFrac, nTemp2); + + /* + implement 2^(intPart) as + a left shift for intPart >= 0 or + a left shift for intPart < 0 + */ + if (nExponentInt >= 0) + { + /* left shift for positive exponents */ + /*lint -e{703} */ + nResult = nTemp1 << nExponentInt; + } + else + { + /* right shift for negative exponents */ + nExponentInt = -nExponentInt; + nResult = nTemp1 >> nExponentInt; + } + + return nResult; +} + +/*---------------------------------------------------------------------------- + * EAS_LogToLinear16() + *---------------------------------------------------------------------------- + * Purpose: + * Transform log value to linear gain multiplier using piece-wise linear + * approximation + * + * Inputs: + * nGain - log scale value in 20.10 format. Even though gain is normally + * stored in 6.10 (16-bit) format we use 32-bit numbers here to eliminate + * the need for saturation checking when combining gain values. + * + * Outputs: + * Returns a 16-bit linear value approximately equal to 2^(nGain/1024) + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_U16 EAS_LogToLinear16 (EAS_I32 nGain) +{ + EAS_INT nExp; + EAS_U16 nTemp; + + /* bias to positive */ + nGain += 32767; + + /* check for infinite attenuation */ + if (nGain < 0) + return 0; + + /* extract the exponent */ + nExp = 31 - (nGain >> 10); + + /* check for maximum output */ + if (nExp < 0) + return 0x7fff; + + /* extract mantissa and restore implied 1 bit */ + nTemp = (EAS_U16)((((nGain & 0x3ff) << 4) | 0x4000) >> nExp); + + /* use shift to approximate power-of-2 operation */ + return nTemp; +} + +/*---------------------------------------------------------------------------- + * EAS_VolumeToGain() + *---------------------------------------------------------------------------- + * Purpose: + * Transform volume control in 1dB increments to gain multiplier + * + * Inputs: + * volume - 100 = 0dB, 99 = -1dB, 0 = -inf + * + * Outputs: + * Returns a 16-bit linear value + *---------------------------------------------------------------------------- +*/ +EAS_I16 EAS_VolumeToGain (EAS_INT volume) +{ + /* check for limits */ + if (volume <= 0) + return 0; + if (volume >= 100) + return 0x7fff; + + /*lint -e{702} use shift instead of division */ + return (EAS_I16) EAS_Calculate2toX((((volume - EAS_MAX_VOLUME) * 204099) >> 10) - 1); +} + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_math.h b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_math.h new file mode 100755 index 0000000..f240b51 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_math.h @@ -0,0 +1,412 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_math.h + * + * Contents and purpose: + * Contains common math routines for the various audio engines. + * + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 584 $ + * $Date: 2007-03-08 09:49:24 -0800 (Thu, 08 Mar 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_MATH_H +#define _EAS_MATH_H + + +/** coefs for pan, generates sin, cos */ +#define COEFF_PAN_G2 -27146 /* -0.82842712474619 = 2 - 4/sqrt(2) */ +#define COEFF_PAN_G0 23170 /* 0.707106781186547 = 1/sqrt(2) */ + +/* +coefficients for approximating +2^x = gn2toX0 + gn2toX1*x + gn2toX2*x^2 + gn2toX3*x^3 +where x is a int.frac number representing number of octaves. +Actually, we approximate only the 2^(frac) using the power series +and implement the 2^(int) as a shift, so that +2^x == 2^(int.frac) == 2^(int) * 2^(fract) + == (gn2toX0 + gn2toX1*x + gn2toX2*x^2 + gn2toX3*x^3) << (int) + +The gn2toX.. were generated using a best fit for a 3rd +order polynomial, instead of taking the coefficients from +a truncated Taylor (or Maclaurin?) series. +*/ + +#define GN2_TO_X0 32768 /* 1 */ +#define GN2_TO_X1 22833 /* 0.696807861328125 */ +#define GN2_TO_X2 7344 /* 0.22412109375 */ +#define GN2_TO_X3 2588 /* 0.0789794921875 */ + +/*---------------------------------------------------------------------------- + * Fixed Point Math + *---------------------------------------------------------------------------- + * These macros are used for fixed point multiplies. If the processor + * supports fixed point multiplies, replace these macros with inline + * assembly code to improve performance. + *---------------------------------------------------------------------------- +*/ + +/* Fixed point multiply 0.15 x 0.15 = 0.15 returned as 32-bits */ +#define FMUL_15x15(a,b) \ + /*lint -e(704) */ \ + (((EAS_I32)(a) * (EAS_I32)(b)) >> 15) + +/* Fixed point multiply 0.7 x 0.7 = 0.15 returned as 32-bits */ +#define FMUL_7x7(a,b) \ + /*lint -e(704) */ \ + (((EAS_I32)(a) * (EAS_I32)(b) ) << 1) + +/* Fixed point multiply 0.8 x 0.8 = 0.15 returned as 32-bits */ +#define FMUL_8x8(a,b) \ + /*lint -e(704) */ \ + (((EAS_I32)(a) * (EAS_I32)(b) ) >> 1) + +/* Fixed point multiply 0.8 x 1.15 = 0.15 returned as 32-bits */ +#define FMUL_8x15(a,b) \ + /*lint -e(704) */ \ + (((EAS_I32)((a) << 7) * (EAS_I32)(b)) >> 15) + +/* macros for fractional phase accumulator */ +/* +Note: changed the _U32 to _I32 on 03/14/02. This should not +affect the phase calculations, and should allow us to reuse these +macros for other audio sample related math. +*/ +#define HARDWARE_BIT_WIDTH 32 + +#define NUM_PHASE_INT_BITS 1 +#define NUM_PHASE_FRAC_BITS 15 + +#define PHASE_FRAC_MASK (EAS_U32) ((0x1L << NUM_PHASE_FRAC_BITS) -1) + +#define GET_PHASE_INT_PART(x) (EAS_U32)((EAS_U32)(x) >> NUM_PHASE_FRAC_BITS) +#define GET_PHASE_FRAC_PART(x) (EAS_U32)((EAS_U32)(x) & PHASE_FRAC_MASK) + +#define DEFAULT_PHASE_FRAC 0 +#define DEFAULT_PHASE_INT 0 + +/* +Linear interpolation calculates: +output = (1-frac) * sample[n] + (frac) * sample[n+1] + +where conceptually 0 <= frac < 1 + +For a fixed point implementation, frac is actually an integer value +with an implied binary point one position to the left. The value of +one (unity) is given by PHASE_ONE +one half and one quarter are useful for 4-point linear interp. +*/ +#define PHASE_ONE (EAS_I32) (0x1L << NUM_PHASE_FRAC_BITS) + +/* + Multiply the signed audio sample by the unsigned fraction. +- a is the signed audio sample +- b is the unsigned fraction (cast to signed int as long as coef + uses (n-1) or less bits, where n == hardware bit width) +*/ +#define MULT_AUDIO_COEF(audio,coef) /*lint -e704 */ \ + (EAS_I32)( \ + ( \ + ((EAS_I32)(audio)) * ((EAS_I32)(coef)) \ + ) \ + >> NUM_PHASE_FRAC_BITS \ + ) \ + /* lint +704 */ + +/* wet / dry calculation macros */ +#define NUM_WET_DRY_FRAC_BITS 7 // 15 +#define NUM_WET_DRY_INT_BITS 9 // 1 + +/* define a 1.0 */ +#define WET_DRY_ONE (EAS_I32) ((0x1L << NUM_WET_DRY_FRAC_BITS)) +#define WET_DRY_MINUS_ONE (EAS_I32) (~WET_DRY_ONE) +#define WET_DRY_FULL_SCALE (EAS_I32) (WET_DRY_ONE - 1) + +#define MULT_AUDIO_WET_DRY_COEF(audio,coef) /*lint -e(702) */ \ + (EAS_I32)( \ + ( \ + ((EAS_I32)(audio)) * ((EAS_I32)(coef)) \ + ) \ + >> NUM_WET_DRY_FRAC_BITS \ + ) + +/* Envelope 1 (EG1) calculation macros */ +#define NUM_EG1_INT_BITS 1 +#define NUM_EG1_FRAC_BITS 15 + +/* the max positive gain used in the synth for EG1 */ +/* SYNTH_FULL_SCALE_EG1_GAIN must match the value in the dls2eas +converter, otherwise, the values we read from the .eas file are bogus. */ +#define SYNTH_FULL_SCALE_EG1_GAIN (EAS_I32) ((0x1L << NUM_EG1_FRAC_BITS) -1) + +/* define a 1.0 */ +#define EG1_ONE (EAS_I32) ((0x1L << NUM_EG1_FRAC_BITS)) +#define EG1_MINUS_ONE (EAS_I32) (~SYNTH_FULL_SCALE_EG1_GAIN) + +#define EG1_HALF (EAS_I32) (EG1_ONE/2) +#define EG1_MINUS_HALF (EAS_I32) (EG1_MINUS_ONE/2) + +/* +We implement the EG1 using a linear gain value, which means that the +attack segment is handled by incrementing (adding) the linear gain. +However, EG1 treats the Decay, Sustain, and Release differently than +the Attack portion. For Decay, Sustain, and Release, the gain is +linear on dB scale, which is equivalent to exponential damping on +a linear scale. Because we use a linear gain for EG1, we implement +the Decay and Release as multiplication (instead of incrementing +as we did for the attack segment). +Therefore, we need the following macro to implement the multiplication +(i.e., exponential damping) during the Decay and Release segments of +the EG1 +*/ +#define MULT_EG1_EG1(gain,damping) /*lint -e(704) */ \ + (EAS_I32)( \ + ( \ + ((EAS_I32)(gain)) * ((EAS_I32)(damping)) \ + ) \ + >> NUM_EG1_FRAC_BITS \ + ) + +// Use the following macro specifically for the filter, when multiplying +// the b1 coefficient. The 0 <= |b1| < 2, which therefore might overflow +// in certain conditions because we store b1 as a 1.15 value. +// Instead, we could store b1 as b1p (b1' == b1 "prime") where +// b1p == b1/2, thus ensuring no potential overflow for b1p because +// 0 <= |b1p| < 1 +// However, during the filter calculation, we must account for the fact +// that we are using b1p instead of b1, and thereby multiply by +// an extra factor of 2. Rather than multiply by an extra factor of 2, +// we can instead shift the result right by one less, hence the +// modified shift right value of (NUM_EG1_FRAC_BITS -1) +#define MULT_EG1_EG1_X2(gain,damping) /*lint -e(702) */ \ + (EAS_I32)( \ + ( \ + ((EAS_I32)(gain)) * ((EAS_I32)(damping)) \ + ) \ + >> (NUM_EG1_FRAC_BITS -1) \ + ) + +#define SATURATE_EG1(x) /*lint -e{734} saturation operation */ \ + ((EAS_I32)(x) > SYNTH_FULL_SCALE_EG1_GAIN) ? (SYNTH_FULL_SCALE_EG1_GAIN) : \ + ((EAS_I32)(x) < EG1_MINUS_ONE) ? (EG1_MINUS_ONE) : (x); + + +/* use "digital cents" == "dents" instead of cents */ +/* we coudl re-use the phase frac macros, but if we do, +we must change the phase macros to cast to _I32 instead of _U32, +because using a _U32 cast causes problems when shifting the exponent +for the 2^x calculation, because right shift a negative values MUST +be sign extended, or else the 2^x calculation is wrong */ + +/* use "digital cents" == "dents" instead of cents */ +#define NUM_DENTS_FRAC_BITS 12 +#define NUM_DENTS_INT_BITS (HARDWARE_BIT_WIDTH - NUM_DENTS_FRAC_BITS) + +#define DENTS_FRAC_MASK (EAS_I32) ((0x1L << NUM_DENTS_FRAC_BITS) -1) + +#define GET_DENTS_INT_PART(x) /*lint -e(704) */ \ + (EAS_I32)((EAS_I32)(x) >> NUM_DENTS_FRAC_BITS) + +#define GET_DENTS_FRAC_PART(x) (EAS_I32)((EAS_I32)(x) & DENTS_FRAC_MASK) + +#define DENTS_ONE (EAS_I32) (0x1L << NUM_DENTS_FRAC_BITS) + +/* use CENTS_TO_DENTS to convert a value in cents to dents */ +#define CENTS_TO_DENTS (EAS_I32) (DENTS_ONE * (0x1L << NUM_EG1_FRAC_BITS) / 1200L) \ + + +/* +For gain, the LFO generates a value that modulates in terms +of dB. However, we use a linear gain value, so we must convert +the LFO value in dB to a linear gain. Normally, we would use +linear gain = 10^x, where x = LFO value in dB / 20. +Instead, we implement 10^x using our 2^x approximation. +because + + 10^x = 2^(log2(10^x)) = 2^(x * log2(10)) + +so we need to multiply by log2(10) which is just a constant. +Ah, but just wait -- our 2^x actually doesn't exactly implement +2^x, but it actually assumes that the input is in cents, and within +the 2^x approximation converts its input from cents to octaves +by dividing its input by 1200. + +So, in order to convert the LFO gain value in dB to something +that our existing 2^x approximation can use, multiply the LFO gain +by log2(10) * 1200 / 20 + +The divide by 20 helps convert dB to linear gain, and we might +as well incorporate that operation into this conversion. +Of course, we need to keep some fractional bits, so multiply +the constant by NUM_EG1_FRAC_BITS +*/ + +/* use LFO_GAIN_TO_CENTS to convert the LFO gain value to cents */ +#if 0 +#define DOUBLE_LOG2_10 (double) (3.32192809488736) /* log2(10) */ + +#define DOUBLE_LFO_GAIN_TO_CENTS (double) \ + ( \ + (DOUBLE_LOG2_10) * \ + 1200.0 / \ + 20.0 \ + ) + +#define LFO_GAIN_TO_CENTS (EAS_I32) \ + ( \ + DOUBLE_LFO_GAIN_TO_CENTS * \ + (0x1L << NUM_EG1_FRAC_BITS) \ + ) +#endif + +#define LFO_GAIN_TO_CENTS (EAS_I32) (1671981156L >> (23 - NUM_EG1_FRAC_BITS)) + + +#define MULT_DENTS_COEF(dents,coef) /*lint -e704 */ \ + (EAS_I32)( \ + ( \ + ((EAS_I32)(dents)) * ((EAS_I32)(coef)) \ + ) \ + >> NUM_DENTS_FRAC_BITS \ + ) \ + /* lint +e704 */ + +/* we use 16-bits in the PC per audio sample */ +#define BITS_PER_AUDIO_SAMPLE 16 + +/* we define 1 as 1.0 - 1 LSbit */ +#define DISTORTION_ONE (EAS_I32)((0x1L << (BITS_PER_AUDIO_SAMPLE-1)) -1) +#define DISTORTION_MINUS_ONE (EAS_I32)(~DISTORTION_ONE) + +/* drive coef is given as int.frac */ +#define NUM_DRIVE_COEF_INT_BITS 1 +#define NUM_DRIVE_COEF_FRAC_BITS 4 + +#define MULT_AUDIO_DRIVE(audio,drive) /*lint -e(702) */ \ + (EAS_I32) ( \ + ( \ + ((EAS_I32)(audio)) * ((EAS_I32)(drive)) \ + ) \ + >> NUM_DRIVE_COEF_FRAC_BITS \ + ) + +#define MULT_AUDIO_AUDIO(audio1,audio2) /*lint -e(702) */ \ + (EAS_I32) ( \ + ( \ + ((EAS_I32)(audio1)) * ((EAS_I32)(audio2)) \ + ) \ + >> (BITS_PER_AUDIO_SAMPLE-1) \ + ) + +#define SATURATE(x) \ + ((((EAS_I32)(x)) > DISTORTION_ONE) ? (DISTORTION_ONE) : \ + (((EAS_I32)(x)) < DISTORTION_MINUS_ONE) ? (DISTORTION_MINUS_ONE) : ((EAS_I32)(x))); + + + +/*---------------------------------------------------------------------------- + * EAS_Calculate2toX() + *---------------------------------------------------------------------------- + * Purpose: + * Calculate 2^x + * + * Inputs: + * nCents - measured in cents + * + * Outputs: + * nResult - int.frac result (where frac has NUM_DENTS_FRAC_BITS) + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_I32 EAS_Calculate2toX (EAS_I32 nCents); + +/*---------------------------------------------------------------------------- + * EAS_LogToLinear16() + *---------------------------------------------------------------------------- + * Purpose: + * Transform log value to linear gain multiplier using piece-wise linear + * approximation + * + * Inputs: + * nGain - log scale value in 20.10 format. Even though gain is normally + * stored in 6.10 (16-bit) format we use 32-bit numbers here to eliminate + * the need for saturation checking when combining gain values. + * + * Outputs: + * Returns a 16-bit linear value approximately equal to 2^(nGain/1024) + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_U16 EAS_LogToLinear16 (EAS_I32 nGain); + +/*---------------------------------------------------------------------------- + * EAS_VolumeToGain() + *---------------------------------------------------------------------------- + * Purpose: + * Transform volume control in 1dB increments to gain multiplier + * + * Inputs: + * volume - 100 = 0dB, 99 = -1dB, 0 = -inf + * + * Outputs: + * Returns a 16-bit linear value + *---------------------------------------------------------------------------- +*/ +EAS_I16 EAS_VolumeToGain (EAS_INT volume); + +/*---------------------------------------------------------------------------- + * EAS_fsqrt() + *---------------------------------------------------------------------------- + * Purpose: + * Calculates the square root of a 32-bit fixed point value + * + * Inputs: + * n = value of interest + * + * Outputs: + * returns the square root of n + * + *---------------------------------------------------------------------------- +*/ +EAS_U16 EAS_fsqrt (EAS_U32 n); + +/*---------------------------------------------------------------------------- + * EAS_flog2() + *---------------------------------------------------------------------------- + * Purpose: + * Calculates the log2 of a 32-bit fixed point value + * + * Inputs: + * n = value of interest + * + * Outputs: + * returns the log2 of n + * + *---------------------------------------------------------------------------- +*/ +EAS_I32 EAS_flog2 (EAS_U32 n); + +#endif + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_mdls.c b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_mdls.c new file mode 100755 index 0000000..3948a85 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_mdls.c @@ -0,0 +1,2668 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_mdls.c + * + * Contents and purpose: + * This file contains DLS to EAS converter. + * + * Copyright (c) 2005 Sonic Network Inc. + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 818 $ + * $Date: 2007-08-02 15:19:41 -0700 (Thu, 02 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +/* + * NOTES: + * + * Processor Endian-ness: + * + * We use the EAS_HWGetDWord() and EAS_HWGetWord () functions + * extensively in this module. It would probably be faster to read + * an entire data structure, but this introduces the problem of + * sensitivity to processor endian-ness to the parser. By utlilizing + * the host wrapper functions, we avoid having to flip bytes around + * for big-endian processors. The default host wrapper versions of + * these functions are insensitive to processor endian-ness due to + * the fact that they read the file as a byte stream. + * + * Dynamic Memory: + * + * Dynamic memory allocation is a risky proposition in a mobile + * device. The memory can become fragmented, resulting in an + * inability to allocate a memory block, or garbage collection + * routines can use many CPU cycles. Either can contribute to + * failures of critical systems. Therefore, we try to minimize the + * number of memory allocations we make. + * + * We allocate a single large block of memory for the entire + * converted DLS collection, including the articulation data and + * samples. This block is then sub-allocated for the various + * data structures. + * + * Parser Overview: + * + * We make two passes through the file, the first pass to count the + * number of instruments, regions, etc. and allocate memory for + * them. The second pass parses the data into the allocated data + * structures. + * + * Conditional chunks are challenging in that they can occur + * anywhere in the list chunk that contains them. To simplify, we + * parse the blocks in a list in specific order, no matter which + * order they appear in the file. This way we don't allocate memory + * and parse a block that we end up throwing away later due to + * a conditional chunk. + * + * Assumptions that may bite us in the future: + * + * We make some assumptions to simplify things. The most fundamental + * assumption is that there will be no more than one of any type of + * chunk in a list. While this is consistent with the block diagram + * of the file layout in the mDLS spec, there is nothing in the + * spec that precludes having mulitple lar2 or rgn2 chunks, with + * conditional blocks that dictate their usage. + * + * DLS -> EAS Conversion Process: + * + * Another challenge is that the DLS structure does not map well to + * the current EAS sound library structure. Not all DLS constructs + * are supported, and data from DLS structures must sometimes be + * mapped to multiple EAS data structures. To simplify the process, + * the EAS region, articulation, and envelopes are treated as a + * single combined unit. Thus for each region, there must be one + * articulation element and two envelope elements. + * + * The sample processing is also a multi-step process. First the + * ptbl chunk is pre-parsed to determine the number of samples + * in the collection. The next step is to parse the instrument data + * to determine which samples are actually used by instruments. + * Some samples may not be used because they are used only in + * conditional blocks that the synthesizer cannot parse, or the + * author neglected to remove unused samples from the collection. + * In the next step, the active samples are read into memory and + * converted to the appropriate playback format. Finally, as the + * instruments are processed, the links are made to the samples and + * wsmp data is extracted for the region and articulation data + * structures. +*/ + +#ifndef _FILTER_ENABLED +#error "Filter must be enabled if DLS_SYNTHESIZER is enabled" +#endif + +/*------------------------------------ + * includes + *------------------------------------ +*/ + +/* this define allows us to use the sndlib.h structures as RW memory */ +#define SCNST + +#include "eas_data.h" +#include "eas_host.h" +#include "eas_mdls.h" +#include "eas_math.h" +#include "dls.h" +#include "dls2.h" +#include "eas_report.h" + +//2 we should replace log10() function with fixed point routine in ConvertSampleRate() +/* lint is choking on the ARM math.h file, so we declare the log10 function here */ +extern double log10(double x); + +/*------------------------------------ + * defines + *------------------------------------ +*/ + +// #define _DEBUG_DLS + +#define DLS_MAX_WAVE_COUNT 1024 +#define DLS_MAX_ART_COUNT 2048 +#define DLS_MAX_REGION_COUNT 2048 +#define DLS_MAX_INST_COUNT 256 +#define MAX_DLS_WAVE_SIZE (1024*1024) + +/*------------------------------------ + * typedefs + *------------------------------------ +*/ + +/* offsets to articulation data */ +typedef enum +{ + PARAM_MODIFIED = 0, + PARAM_MOD_LFO_FREQ, + PARAM_MOD_LFO_DELAY, + + PARAM_VIB_LFO_FREQ, + PARAM_VIB_LFO_DELAY, + + PARAM_VOL_EG_DELAY, + PARAM_VOL_EG_ATTACK, + PARAM_VOL_EG_HOLD, + PARAM_VOL_EG_DECAY, + PARAM_VOL_EG_SUSTAIN, + PARAM_VOL_EG_RELEASE, + PARAM_VOL_EG_SHUTDOWN, + PARAM_VOL_EG_VEL_TO_ATTACK, + PARAM_VOL_EG_KEY_TO_DECAY, + PARAM_VOL_EG_KEY_TO_HOLD, + + PARAM_MOD_EG_DELAY, + PARAM_MOD_EG_ATTACK, + PARAM_MOD_EG_HOLD, + PARAM_MOD_EG_DECAY, + PARAM_MOD_EG_SUSTAIN, + PARAM_MOD_EG_RELEASE, + PARAM_MOD_EG_VEL_TO_ATTACK, + PARAM_MOD_EG_KEY_TO_DECAY, + PARAM_MOD_EG_KEY_TO_HOLD, + + PARAM_INITIAL_FC, + PARAM_INITIAL_Q, + PARAM_MOD_LFO_TO_FC, + PARAM_MOD_LFO_CC1_TO_FC, + PARAM_MOD_LFO_CHAN_PRESS_TO_FC, + PARAM_MOD_EG_TO_FC, + PARAM_VEL_TO_FC, + PARAM_KEYNUM_TO_FC, + + PARAM_MOD_LFO_TO_GAIN, + PARAM_MOD_LFO_CC1_TO_GAIN, + PARAM_MOD_LFO_CHAN_PRESS_TO_GAIN, + PARAM_VEL_TO_GAIN, + + PARAM_TUNING, + PARAM_KEYNUM_TO_PITCH, + PARAM_VIB_LFO_TO_PITCH, + PARAM_VIB_LFO_CC1_TO_PITCH, + PARAM_VIB_LFO_CHAN_PRESS_TO_PITCH, + PARAM_MOD_LFO_TO_PITCH, + PARAM_MOD_LFO_CC1_TO_PITCH, + PARAM_MOD_LFO_CHAN_PRESS_TO_PITCH, + PARAM_MOD_EG_TO_PITCH, + + PARAM_DEFAULT_PAN, + PARAM_MIDI_CC91_TO_REVERB_SEND, + PARAM_DEFAULT_REVERB_SEND, + PARAM_MIDI_CC93_TO_CHORUS_SEND, + PARAM_DEFAULT_CHORUS_SEND, + PARAM_TABLE_SIZE +} E_ART_INDEX; + +/* temporary data structure combining region, articulation, and envelope data */ +typedef struct s_art_dls_tag +{ + EAS_I16 values[PARAM_TABLE_SIZE]; +} S_DLS_ART_VALUES; + +/* temporary data structure for wlnk chunk data */ +typedef struct +{ + EAS_I32 gain; + EAS_U32 loopStart; + EAS_U32 loopLength; + EAS_U32 sampleRate; + EAS_U16 bitsPerSample; + EAS_I16 fineTune; + EAS_U8 unityNote; +} S_WSMP_DATA; + +/* temporary data structure used while parsing a DLS file */ +typedef struct +{ + S_DLS *pDLS; + EAS_HW_DATA_HANDLE hwInstData; + EAS_FILE_HANDLE fileHandle; + S_WSMP_DATA *wsmpData; + EAS_U32 instCount; + EAS_U32 regionCount; + EAS_U32 artCount; + EAS_U32 waveCount; + EAS_U32 wavePoolSize; + EAS_U32 wavePoolOffset; + EAS_BOOL bigEndian; + EAS_BOOL filterUsed; +} SDLS_SYNTHESIZER_DATA; + +/* connection lookup table */ +typedef struct s_connection_tag +{ + EAS_U16 source; + EAS_U16 control; + EAS_U16 destination; + EAS_U16 connection; +} S_CONNECTION; + +static const S_CONNECTION connTable[] = +{ + { CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_LFO_FREQUENCY, PARAM_MOD_LFO_FREQ }, + { CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_LFO_STARTDELAY, PARAM_MOD_LFO_DELAY}, + + { CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_VIB_FREQUENCY, PARAM_VIB_LFO_FREQ }, + { CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_VIB_STARTDELAY, PARAM_VIB_LFO_DELAY }, + + { CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_EG1_DELAYTIME, PARAM_VOL_EG_DELAY }, + { CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_EG1_ATTACKTIME, PARAM_VOL_EG_ATTACK }, + { CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_EG1_HOLDTIME, PARAM_VOL_EG_HOLD }, + { CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_EG1_DECAYTIME, PARAM_VOL_EG_DECAY }, + { CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_EG1_SUSTAINLEVEL, PARAM_VOL_EG_SUSTAIN }, + { CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_EG1_RELEASETIME, PARAM_VOL_EG_RELEASE }, + { CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_EG1_SHUTDOWNTIME, PARAM_VOL_EG_SHUTDOWN }, + { CONN_SRC_KEYONVELOCITY, CONN_SRC_NONE, CONN_DST_EG1_ATTACKTIME, PARAM_VOL_EG_VEL_TO_ATTACK }, + { CONN_SRC_KEYNUMBER, CONN_SRC_NONE, CONN_DST_EG1_DECAYTIME, PARAM_VOL_EG_KEY_TO_DECAY }, + { CONN_SRC_KEYNUMBER, CONN_SRC_NONE, CONN_DST_EG1_HOLDTIME, PARAM_VOL_EG_KEY_TO_HOLD }, + + { CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_EG2_DELAYTIME, PARAM_MOD_EG_DELAY }, + { CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_EG2_ATTACKTIME, PARAM_MOD_EG_ATTACK }, + { CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_EG2_HOLDTIME, PARAM_MOD_EG_HOLD }, + { CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_EG2_DECAYTIME, PARAM_MOD_EG_DECAY }, + { CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_EG2_SUSTAINLEVEL, PARAM_MOD_EG_SUSTAIN }, + { CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_EG2_RELEASETIME, PARAM_MOD_EG_RELEASE }, + { CONN_SRC_KEYONVELOCITY, CONN_SRC_NONE, CONN_DST_EG2_ATTACKTIME, PARAM_MOD_EG_VEL_TO_ATTACK }, + { CONN_SRC_KEYNUMBER, CONN_SRC_NONE, CONN_DST_EG2_DECAYTIME, PARAM_MOD_EG_KEY_TO_DECAY }, + { CONN_SRC_KEYNUMBER, CONN_SRC_NONE, CONN_DST_EG2_HOLDTIME, PARAM_MOD_EG_KEY_TO_HOLD }, + + { CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_FILTER_CUTOFF, PARAM_INITIAL_FC }, + { CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_FILTER_Q, PARAM_INITIAL_Q }, + { CONN_SRC_LFO, CONN_SRC_NONE, CONN_DST_FILTER_CUTOFF, PARAM_MOD_LFO_TO_FC }, + { CONN_SRC_LFO, CONN_SRC_CC1, CONN_DST_FILTER_CUTOFF, PARAM_MOD_LFO_CC1_TO_FC }, + { CONN_SRC_LFO, CONN_SRC_CHANNELPRESSURE, CONN_DST_FILTER_CUTOFF, PARAM_MOD_LFO_CHAN_PRESS_TO_FC }, + { CONN_SRC_EG2, CONN_SRC_NONE, CONN_DST_FILTER_CUTOFF, PARAM_MOD_EG_TO_FC }, + { CONN_SRC_KEYONVELOCITY, CONN_SRC_NONE, CONN_DST_FILTER_CUTOFF, PARAM_VEL_TO_FC }, + { CONN_SRC_KEYNUMBER, CONN_SRC_NONE, CONN_DST_FILTER_CUTOFF, PARAM_KEYNUM_TO_FC }, + + { CONN_SRC_LFO, CONN_SRC_NONE, CONN_DST_GAIN, PARAM_MOD_LFO_TO_GAIN }, + { CONN_SRC_LFO, CONN_SRC_CC1, CONN_DST_GAIN, PARAM_MOD_LFO_CC1_TO_GAIN }, + { CONN_SRC_LFO, CONN_SRC_CHANNELPRESSURE, CONN_DST_GAIN, PARAM_MOD_LFO_CHAN_PRESS_TO_GAIN }, + { CONN_SRC_KEYONVELOCITY, CONN_SRC_NONE, CONN_DST_GAIN, PARAM_VEL_TO_GAIN }, + + { CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_PITCH, PARAM_TUNING }, + { CONN_SRC_KEYNUMBER, CONN_SRC_NONE, CONN_DST_PITCH, PARAM_KEYNUM_TO_PITCH }, + { CONN_SRC_VIBRATO, CONN_SRC_NONE, CONN_DST_PITCH, PARAM_VIB_LFO_TO_PITCH }, + { CONN_SRC_VIBRATO, CONN_SRC_CC1, CONN_DST_PITCH, PARAM_VIB_LFO_CC1_TO_PITCH }, + { CONN_SRC_VIBRATO, CONN_SRC_CHANNELPRESSURE, CONN_DST_PITCH, PARAM_VIB_LFO_CHAN_PRESS_TO_PITCH }, + { CONN_SRC_LFO, CONN_SRC_NONE, CONN_DST_PITCH, PARAM_MOD_LFO_TO_PITCH }, + { CONN_SRC_LFO, CONN_SRC_CC1, CONN_DST_PITCH, PARAM_MOD_LFO_CC1_TO_PITCH }, + { CONN_SRC_LFO, CONN_SRC_CHANNELPRESSURE, CONN_DST_PITCH, PARAM_MOD_LFO_CHAN_PRESS_TO_PITCH }, + { CONN_SRC_EG2, CONN_SRC_NONE, CONN_DST_PITCH, PARAM_MOD_EG_TO_PITCH }, + + { CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_PAN, PARAM_DEFAULT_PAN }, + { CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_REVERB, PARAM_DEFAULT_REVERB_SEND }, + { CONN_SRC_CC91, CONN_SRC_NONE, CONN_DST_REVERB, PARAM_MIDI_CC91_TO_REVERB_SEND }, + { CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_CHORUS, PARAM_DEFAULT_CHORUS_SEND }, + { CONN_SRC_CC93, CONN_SRC_NONE, CONN_DST_REVERB, PARAM_MIDI_CC93_TO_CHORUS_SEND } +}; +#define ENTRIES_IN_CONN_TABLE (sizeof(connTable)/sizeof(S_CONNECTION)) + +static const S_DLS_ART_VALUES defaultArt = +{{ + 0, /* not modified */ + -851, /* Mod LFO frequency: 5 Hz */ + -7973, /* Mod LFO delay: 10 milliseconds */ + + -851, /* Vib LFO frequency: 5 Hz */ + -7973, /* Vib LFO delay: 10 milliseconds */ + + -32768, /* EG1 delay time: 0 secs */ + -32768, /* EG1 attack time: 0 secs */ + -32768, /* EG1 hold time: 0 secs */ + -32768, /* EG1 decay time: 0 secs */ + 1000, /* EG1 sustain level: 100.0% */ + -32768, /* EG1 release time: 0 secs */ + -7271, /* EG1 shutdown time: 15 msecs */ + 0, /* EG1 velocity to attack: 0 time cents */ + 0, /* EG1 key number to decay: 0 time cents */ + 0, /* EG1 key number to hold: 0 time cents */ + + -32768, /* EG2 delay time: 0 secs */ + -32768, /* EG2 attack time: 0 secs */ + -32768, /* EG2 hold time: 0 secs */ + -32768, /* EG2 decay time: 0 secs */ + 1000, /* EG2 sustain level: 100.0% */ + -32768, /* EG2 release time: 0 secs */ + 0, /* EG2 velocity to attack: 0 time cents */ + 0, /* EG2 key number to decay: 0 time cents */ + 0, /* EG2 key number to hold: 0 time cents */ + + 0x7fff, /* Initial Fc: Disabled */ + 0, /* Initial Q: 0 dB */ + 0, /* Mod LFO to Fc: 0 cents */ + 0, /* Mod LFO CC1 to Fc: 0 cents */ + 0, /* Mod LFO channel pressure to Fc: 0 cents */ + 0, /* EG2 to Fc: 0 cents */ + 0, /* Velocity to Fc: 0 cents */ + 0, /* Key number to Fc: 0 cents */ + + 0, /* Mod LFO to gain: 0 dB */ + 0, /* Mod LFO CC1 to gain: 0 dB */ + 0, /* Mod LFO channel pressure to gain: 0 dB */ + 960, /* Velocity to gain: 96 dB */ + + 0, /* Tuning: 0 cents */ + 12800, /* Key number to pitch: 12,800 cents */ + 0, /* Vibrato to pitch: 0 cents */ + 0, /* Vibrato CC1 to pitch: 0 cents */ + 0, /* Vibrato channel pressure to pitch: 0 cents */ + 0, /* Mod LFO to pitch: 0 cents */ + 0, /* Mod LFO CC1 to pitch: 0 cents */ + 0, /* Mod LFO channel pressure to pitch: 0 cents */ + 0, /* Mod EG to pitch: 0 cents */ + + 0, /* Default pan: 0.0% */ + 0, /* Default reverb send: 0.0% */ + 1000, /* Default CC91 to reverb send: 100.0% */ + 0, /* Default chorus send: 0.0% */ + 1000 /* Default CC93 to chorus send: 100.0% */ +}}; + +/*------------------------------------ + * local variables + *------------------------------------ +*/ + +#if defined(_8_BIT_SAMPLES) +static const EAS_INT bitDepth = 8; +#elif defined(_16_BIT_SAMPLES) +static const EAS_INT bitDepth = 16; +#else +#error "Must define _8_BIT_SAMPLES or _16_BIT_SAMPLES" +#endif + +static const EAS_U32 outputSampleRate = _OUTPUT_SAMPLE_RATE; +static const EAS_I32 dlsRateConvert = DLS_RATE_CONVERT; +static const EAS_I32 dlsLFOFrequencyConvert = DLS_LFO_FREQUENCY_CONVERT; + +/*------------------------------------ + * inline functions + *------------------------------------ +*/ +EAS_INLINE void *PtrOfs (void *p, EAS_I32 offset) +{ + return (void*) (((EAS_U8*) p) + offset); +} + +/*------------------------------------ + * prototypes + *------------------------------------ +*/ +static EAS_RESULT NextChunk (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 *pPos, EAS_U32 *pChunkType, EAS_I32 *pSize); +static EAS_RESULT Parse_ptbl (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, EAS_I32 wsmpPos, EAS_I32 wsmpSize); +static EAS_RESULT Parse_wave (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, EAS_U16 waveIndex); +static EAS_RESULT Parse_wsmp (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, S_WSMP_DATA *p); +static EAS_RESULT Parse_fmt (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, S_WSMP_DATA *p); +static EAS_RESULT Parse_data (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, EAS_I32 size, S_WSMP_DATA *p, EAS_SAMPLE *pSample); +static EAS_RESULT Parse_lins(SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, EAS_I32 size); +static EAS_RESULT Parse_ins (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, EAS_I32 size); +static EAS_RESULT Parse_insh (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, EAS_U32 *pRgnCount, EAS_U32 *pLocale); +static EAS_RESULT Parse_lrgn (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, EAS_I32 size, EAS_U16 artIndex, EAS_U32 numRegions); +static EAS_RESULT Parse_rgn (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, EAS_I32 size, EAS_U16 artIndex); +static EAS_RESULT Parse_rgnh (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, S_DLS_REGION *pRgn); +static EAS_RESULT Parse_lart (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, EAS_I32 size, S_DLS_ART_VALUES *pArt); +static EAS_RESULT Parse_art (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, S_DLS_ART_VALUES *pArt); +static EAS_RESULT Parse_wlnk (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, EAS_U32 *pWaveIndex); +static EAS_RESULT Parse_cdl (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 size, EAS_U32 *pValue); +static void Convert_rgn (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_U16 regionIndex, EAS_U16 artIndex, EAS_U16 waveIndex, S_WSMP_DATA *pWsmp); +static void Convert_art (SDLS_SYNTHESIZER_DATA *pDLSData, const S_DLS_ART_VALUES *pDLSArt, EAS_U16 artIndex); +static EAS_I16 ConvertSampleRate (EAS_U32 sampleRate); +static EAS_I16 ConvertSustain (EAS_I32 sustain); +static EAS_I16 ConvertLFOPhaseIncrement (EAS_I32 pitchCents); +static EAS_I8 ConvertPan (EAS_I32 pan); +static EAS_U8 ConvertQ (EAS_I32 q); + +#ifdef _DEBUG_DLS +static void DumpDLS (S_EAS *pEAS); +#endif + + +/*---------------------------------------------------------------------------- + * DLSParser () + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * pEASData - pointer to over EAS data instance + * fileHandle - file handle for input file + * offset - offset into file where DLS data starts + * + * Outputs: + * EAS_RESULT + * ppEAS - address of pointer to alternate EAS wavetable + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT DLSParser (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle, EAS_I32 offset, EAS_DLSLIB_HANDLE *ppDLS) +{ + EAS_RESULT result; + SDLS_SYNTHESIZER_DATA dls; + EAS_U32 temp; + EAS_I32 pos; + EAS_I32 chunkPos; + EAS_I32 size; + EAS_I32 instSize; + EAS_I32 rgnPoolSize; + EAS_I32 artPoolSize; + EAS_I32 waveLenSize; + EAS_I32 endDLS; + EAS_I32 wvplPos; + EAS_I32 wvplSize; + EAS_I32 linsPos; + EAS_I32 linsSize; + EAS_I32 ptblPos; + EAS_I32 ptblSize; + void *p; + + /* zero counts and pointers */ + EAS_HWMemSet(&dls, 0, sizeof(dls)); + + /* save file handle and hwInstData to save copying pointers around */ + dls.hwInstData = hwInstData; + dls.fileHandle = fileHandle; + + /* NULL return value in case of error */ + *ppDLS = NULL; + + /* seek to start of DLS and read in RIFF tag and set processor endian flag */ + if ((result = EAS_HWFileSeek(dls.hwInstData, dls.fileHandle, offset)) != EAS_SUCCESS) + return result; + if ((result = EAS_HWReadFile(dls.hwInstData, dls.fileHandle, &temp, sizeof(temp), &size)) != EAS_SUCCESS) + return result; + + /* check for processor endian-ness */ + dls.bigEndian = (temp == CHUNK_RIFF); + + /* first chunk should be DLS */ + pos = offset; + if ((result = NextChunk(&dls, &pos, &temp, &size)) != EAS_SUCCESS) + return result; + if (temp != CHUNK_DLS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Expected DLS chunk, got %08lx\n", temp); */ } + return EAS_ERROR_FILE_FORMAT; + } + + /* no instrument or wavepool chunks */ + linsSize = wvplSize = ptblSize = linsPos = wvplPos = ptblPos = 0; + + /* scan the chunks in the DLS list */ + endDLS = offset + size; + pos = offset + 12; + while (pos < endDLS) + { + chunkPos = pos; + + /* get the next chunk type */ + if ((result = NextChunk(&dls, &pos, &temp, &size)) != EAS_SUCCESS) + return result; + + /* parse useful chunks */ + switch (temp) + { + case CHUNK_CDL: + if ((result = Parse_cdl(&dls, size, &temp)) != EAS_SUCCESS) + return result; + if (!temp) + return EAS_ERROR_UNRECOGNIZED_FORMAT; + break; + + case CHUNK_LINS: + linsPos = chunkPos + 12; + linsSize = size - 4; + break; + + case CHUNK_WVPL: + wvplPos = chunkPos + 12; + wvplSize = size - 4; + break; + + case CHUNK_PTBL: + ptblPos = chunkPos + 8; + ptblSize = size - 4; + break; + + default: + break; + } + } + + /* must have a lins chunk */ + if (linsSize == 0) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "No lins chunk found"); */ } + return EAS_ERROR_UNRECOGNIZED_FORMAT; + } + + /* must have a wvpl chunk */ + if (wvplSize == 0) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "No wvpl chunk found"); */ } + return EAS_ERROR_UNRECOGNIZED_FORMAT; + } + + /* must have a ptbl chunk */ + if ((ptblSize == 0) || (ptblSize > DLS_MAX_WAVE_COUNT * sizeof(POOLCUE) + sizeof(POOLTABLE))) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "No ptbl chunk found"); */ } + return EAS_ERROR_UNRECOGNIZED_FORMAT; + } + + /* pre-parse the wave pool chunk */ + if ((result = Parse_ptbl(&dls, ptblPos, wvplPos, wvplSize)) != EAS_SUCCESS) + return result; + + /* limit check */ + if ((dls.waveCount == 0) || (dls.waveCount > DLS_MAX_WAVE_COUNT)) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "DLS file contains invalid #waves [%u]\n", dls.waveCount); */ } + return EAS_ERROR_FILE_FORMAT; + } + + /* allocate memory for wsmp data */ + dls.wsmpData = EAS_HWMalloc(dls.hwInstData, (EAS_I32) (sizeof(S_WSMP_DATA) * dls.waveCount)); + if (dls.wsmpData == NULL) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_HWMalloc for wsmp data failed\n"); */ } + return EAS_ERROR_MALLOC_FAILED; + } + EAS_HWMemSet(dls.wsmpData, 0, (EAS_I32) (sizeof(S_WSMP_DATA) * dls.waveCount)); + + /* pre-parse the lins chunk */ + result = Parse_lins(&dls, linsPos, linsSize); + if (result == EAS_SUCCESS) + { + + /* limit check */ + if ((dls.regionCount == 0) || (dls.regionCount > DLS_MAX_REGION_COUNT)) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "DLS file contains invalid #regions [%u]\n", dls.regionCount); */ } + return EAS_ERROR_FILE_FORMAT; + } + + /* limit check */ + if ((dls.artCount == 0) || (dls.artCount > DLS_MAX_ART_COUNT)) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "DLS file contains invalid #articulations [%u]\n", dls.regionCount); */ } + return EAS_ERROR_FILE_FORMAT; + } + + /* limit check */ + if ((dls.instCount == 0) || (dls.instCount > DLS_MAX_INST_COUNT)) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "DLS file contains invalid #instruments [%u]\n", dls.instCount); */ } + return EAS_ERROR_FILE_FORMAT; + } + + /* Allocate memory for the converted DLS data */ + /* calculate size of instrument data */ + instSize = (EAS_I32) (sizeof(S_PROGRAM) * dls.instCount); + + /* calculate size of region pool */ + rgnPoolSize = (EAS_I32) (sizeof(S_DLS_REGION) * dls.regionCount); + + /* calculate size of articulation pool, add one for default articulation */ + dls.artCount++; + artPoolSize = (EAS_I32) (sizeof(S_DLS_ARTICULATION) * dls.artCount); + + /* calculate size of wave length and offset arrays */ + waveLenSize = (EAS_I32) (dls.waveCount * sizeof(EAS_U32)); + + /* calculate final memory size */ + size = (EAS_I32) sizeof(S_EAS) + instSize + rgnPoolSize + artPoolSize + (2 * waveLenSize) + (EAS_I32) dls.wavePoolSize; + if (size <= 0) { + return EAS_ERROR_FILE_FORMAT; + } + + /* allocate the main EAS chunk */ + dls.pDLS = EAS_HWMalloc(dls.hwInstData, size); + if (dls.pDLS == NULL) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_HWMalloc failed for DLS memory allocation size %ld\n", size); */ } + return EAS_ERROR_MALLOC_FAILED; + } + EAS_HWMemSet(dls.pDLS, 0, size); + dls.pDLS->refCount = 1; + p = PtrOfs(dls.pDLS, sizeof(S_EAS)); + + /* setup pointer to programs */ + dls.pDLS->numDLSPrograms = (EAS_U16) dls.instCount; + dls.pDLS->pDLSPrograms = p; + p = PtrOfs(p, instSize); + + /* setup pointer to regions */ + dls.pDLS->pDLSRegions = p; + dls.pDLS->numDLSRegions = (EAS_U16) dls.regionCount; + p = PtrOfs(p, rgnPoolSize); + + /* setup pointer to articulations */ + dls.pDLS->numDLSArticulations = (EAS_U16) dls.artCount; + dls.pDLS->pDLSArticulations = p; + p = PtrOfs(p, artPoolSize); + + /* setup pointer to wave length table */ + dls.pDLS->numDLSSamples = (EAS_U16) dls.waveCount; + dls.pDLS->pDLSSampleLen = p; + p = PtrOfs(p, waveLenSize); + + /* setup pointer to wave offsets table */ + dls.pDLS->pDLSSampleOffsets = p; + p = PtrOfs(p, waveLenSize); + + /* setup pointer to wave pool */ + dls.pDLS->pDLSSamples = p; + + /* clear filter flag */ + dls.filterUsed = EAS_FALSE; + + /* parse the wave pool and load samples */ + result = Parse_ptbl(&dls, ptblPos, wvplPos, wvplSize); + } + + /* create the default articulation */ + Convert_art(&dls, &defaultArt, 0); + dls.artCount = 1; + + /* parse the lins chunk and load instruments */ + dls.regionCount = dls.instCount = 0; + if (result == EAS_SUCCESS) + result = Parse_lins(&dls, linsPos, linsSize); + + /* clean up any temporary objects that were allocated */ + if (dls.wsmpData) + EAS_HWFree(dls.hwInstData, dls.wsmpData); + + /* if successful, return a pointer to the EAS collection */ + if (result == EAS_SUCCESS) + { + *ppDLS = dls.pDLS; +#ifdef _DEBUG_DLS + DumpDLS(dls.pDLS); +#endif + } + + /* something went wrong, deallocate the EAS collection */ + else + DLSCleanup(dls.hwInstData, dls.pDLS); + + return result; +} + +/*---------------------------------------------------------------------------- + * DLSCleanup () + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * pEASData - pointer to over EAS data instance + * pEAS - pointer to alternate EAS wavetable + * + * Outputs: + * EAS_RESULT + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT DLSCleanup (EAS_HW_DATA_HANDLE hwInstData, S_DLS *pDLS) +{ + + /* free the allocated memory */ + if (pDLS) + { + if (pDLS->refCount) + { + if (--pDLS->refCount == 0) + EAS_HWFree(hwInstData, pDLS); + } + } + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * DLSAddRef () + *---------------------------------------------------------------------------- + * Increment reference count + *---------------------------------------------------------------------------- +*/ +void DLSAddRef (S_DLS *pDLS) +{ + if (pDLS) + pDLS->refCount++; +} + +/*---------------------------------------------------------------------------- + * NextChunk () + *---------------------------------------------------------------------------- + * Purpose: + * Returns the type and size of the next chunk in the file + * + * Inputs: + * + * Outputs: + * + * Side Effects: + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT NextChunk (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 *pPos, EAS_U32 *pChunkType, EAS_I32 *pSize) +{ + EAS_RESULT result; + + /* seek to start of chunk */ + if ((result = EAS_HWFileSeek(pDLSData->hwInstData, pDLSData->fileHandle, *pPos)) != EAS_SUCCESS) + return result; + + /* read the chunk type */ + if ((result = EAS_HWGetDWord(pDLSData->hwInstData, pDLSData->fileHandle, pChunkType, EAS_TRUE)) != EAS_SUCCESS) + return result; + + /* read the chunk size */ + if ((result = EAS_HWGetDWord(pDLSData->hwInstData, pDLSData->fileHandle, pSize, EAS_FALSE)) != EAS_SUCCESS) + return result; + + /* get form type for RIFF and LIST types */ + if ((*pChunkType == CHUNK_RIFF) || (*pChunkType == CHUNK_LIST)) + { + + /* read the form type */ + if ((result = EAS_HWGetDWord(pDLSData->hwInstData, pDLSData->fileHandle, pChunkType, EAS_TRUE)) != EAS_SUCCESS) + return result; + + } + + /* calculate start of next chunk */ + *pPos += *pSize + 8; + + /* adjust to word boundary */ + if (*pPos & 1) + (*pPos)++; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * Parse_ptbl () + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT Parse_ptbl (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, EAS_I32 wtblPos, EAS_I32 wtblSize) +{ + EAS_RESULT result; + EAS_U32 temp; + EAS_FILE_HANDLE tempFile; + EAS_U16 waveIndex; + + /* seek to start of chunk */ + if ((result = EAS_HWFileSeek(pDLSData->hwInstData, pDLSData->fileHandle, pos)) != EAS_SUCCESS) + return result; + + /* get the structure size */ + if ((result = EAS_HWGetDWord(pDLSData->hwInstData, pDLSData->fileHandle, &temp, EAS_FALSE)) != EAS_SUCCESS) + return result; + + /* get the number of waves */ + if ((result = EAS_HWGetDWord(pDLSData->hwInstData, pDLSData->fileHandle, &pDLSData->waveCount, EAS_FALSE)) != EAS_SUCCESS) + return result; + +#if 0 + /* just need the wave count on the first pass */ + if (!pDLSData->pDLS) + return EAS_SUCCESS; +#endif + + /* open duplicate file handle */ + if ((result = EAS_HWDupHandle(pDLSData->hwInstData, pDLSData->fileHandle, &tempFile)) != EAS_SUCCESS) + return result; + + /* read to end of chunk */ + for (waveIndex = 0; waveIndex < pDLSData->waveCount; waveIndex++) + { + + /* get the offset to the wave and make sure it is within the wtbl chunk */ + if ((result = EAS_HWGetDWord(pDLSData->hwInstData, tempFile, &temp, EAS_FALSE)) != EAS_SUCCESS) + return result; + if (temp > (EAS_U32) wtblSize) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Ptbl offset exceeds size of wtbl\n"); */ } + EAS_HWCloseFile(pDLSData->hwInstData, tempFile); + return EAS_ERROR_FILE_FORMAT; + } + + /* parse the wave */ + if ((result = Parse_wave(pDLSData, wtblPos +(EAS_I32) temp, waveIndex)) != EAS_SUCCESS) + return result; + } + + /* close the temporary handle and return */ + EAS_HWCloseFile(pDLSData->hwInstData, tempFile); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * Parse_wave () + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT Parse_wave (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, EAS_U16 waveIndex) +{ + EAS_RESULT result; + EAS_U32 temp; + EAS_I32 size; + EAS_I32 endChunk; + EAS_I32 chunkPos; + EAS_I32 wsmpPos = 0; + EAS_I32 fmtPos = 0; + EAS_I32 dataPos = 0; + EAS_I32 dataSize = 0; + S_WSMP_DATA *p; + void *pSample; + S_WSMP_DATA wsmp; + + /* seek to start of chunk */ + chunkPos = pos + 12; + if ((result = EAS_HWFileSeek(pDLSData->hwInstData, pDLSData->fileHandle, pos)) != EAS_SUCCESS) + return result; + + /* get the chunk type */ + if ((result = NextChunk(pDLSData, &pos, &temp, &size)) != EAS_SUCCESS) + return result; + + /* make sure it is a wave chunk */ + if (temp != CHUNK_WAVE) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Offset in ptbl does not point to wave chunk\n"); */ } + return EAS_ERROR_FILE_FORMAT; + } + + /* read to end of chunk */ + pos = chunkPos; + endChunk = pos + size; + while (pos < endChunk) + { + chunkPos = pos; + + /* get the chunk type */ + if ((result = NextChunk(pDLSData, &pos, &temp, &size)) != EAS_SUCCESS) + return result; + + /* parse useful chunks */ + switch (temp) + { + case CHUNK_WSMP: + wsmpPos = chunkPos + 8; + break; + + case CHUNK_FMT: + fmtPos = chunkPos + 8; + break; + + case CHUNK_DATA: + dataPos = chunkPos + 8; + dataSize = size; + break; + + default: + break; + } + } + + // limit to reasonable size + if (dataSize > MAX_DLS_WAVE_SIZE) + { + return EAS_ERROR_SOUND_LIBRARY; + } + + /* for first pass, use temporary variable */ + if (pDLSData->pDLS == NULL) + p = &wsmp; + else + p = &pDLSData->wsmpData[waveIndex]; + + /* set the defaults */ + p->fineTune = 0; + p->unityNote = 60; + p->gain = 0; + p->loopStart = 0; + p->loopLength = 0; + + /* must have a fmt chunk */ + if (!fmtPos) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "DLS wave chunk has no fmt chunk\n"); */ } + return EAS_ERROR_UNRECOGNIZED_FORMAT; + } + + /* must have a data chunk */ + if (!dataPos) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "DLS wave chunk has no data chunk\n"); */ } + return EAS_ERROR_UNRECOGNIZED_FORMAT; + } + + /* parse the wsmp chunk */ + if (wsmpPos) + { + if ((result = Parse_wsmp(pDLSData, wsmpPos, p)) != EAS_SUCCESS) + return result; + } + + /* parse the fmt chunk */ + if ((result = Parse_fmt(pDLSData, fmtPos, p)) != EAS_SUCCESS) + return result; + + /* calculate the size of the wavetable needed. We need only half + * the memory for 16-bit samples when in 8-bit mode, and we need + * double the memory for 8-bit samples in 16-bit mode. For + * unlooped samples, we may use ADPCM. If so, we need only 1/4 + * the memory. + * + * We also need to add one for looped samples to allow for + * the first sample to be copied to the end of the loop. + */ + + /* use ADPCM encode for unlooped 16-bit samples if ADPCM is enabled */ + /*lint -e{506} -e{774} groundwork for future version to support 8 & 16 bit */ + if (bitDepth == 8) + { + if (p->bitsPerSample == 8) + size = dataSize; + else + /*lint -e{704} use shift for performance */ + size = dataSize >> 1; + if (p->loopLength) + size++; + } + + else + { + if (p->bitsPerSample == 16) + size = dataSize; + else + /*lint -e{703} use shift for performance */ + size = dataSize << 1; + if (p->loopLength) + size += 2; + } + + /* for first pass, add size to wave pool size and return */ + if (pDLSData->pDLS == NULL) + { + pDLSData->wavePoolSize += (EAS_U32) size; + return EAS_SUCCESS; + } + + /* allocate memory and read in the sample data */ + pSample = pDLSData->pDLS->pDLSSamples + pDLSData->wavePoolOffset; + pDLSData->pDLS->pDLSSampleOffsets[waveIndex] = pDLSData->wavePoolOffset; + pDLSData->pDLS->pDLSSampleLen[waveIndex] = (EAS_U32) size; + pDLSData->wavePoolOffset += (EAS_U32) size; + if (pDLSData->wavePoolOffset > pDLSData->wavePoolSize) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Wave pool exceeded allocation\n"); */ } + return EAS_ERROR_SOUND_LIBRARY; + } + + if ((result = Parse_data(pDLSData, dataPos, dataSize, p, pSample)) != EAS_SUCCESS) + return result; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * Parse_wsmp () + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT Parse_wsmp (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, S_WSMP_DATA *p) +{ + EAS_RESULT result; + EAS_U16 wtemp; + EAS_U32 ltemp; + EAS_U32 cbSize; + + /* seek to start of chunk */ + if ((result = EAS_HWFileSeek(pDLSData->hwInstData, pDLSData->fileHandle, pos)) != EAS_SUCCESS) + return result; + + /* get structure size */ + if ((result = EAS_HWGetDWord(pDLSData->hwInstData, pDLSData->fileHandle, &cbSize, EAS_FALSE)) != EAS_SUCCESS) + return result; + + /* get unity note */ + if ((result = EAS_HWGetWord(pDLSData->hwInstData, pDLSData->fileHandle, &wtemp, EAS_FALSE)) != EAS_SUCCESS) + return result; + if (wtemp <= 127) + p->unityNote = (EAS_U8) wtemp; + else + { + p->unityNote = 60; + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Invalid unity note [%u] in DLS wsmp ignored, set to 60\n", wtemp); */ } + } + + /* get fine tune */ + if ((result = EAS_HWGetWord(pDLSData->hwInstData, pDLSData->fileHandle, &p->fineTune, EAS_FALSE)) != EAS_SUCCESS) + return result; + + /* get gain */ + if ((result = EAS_HWGetDWord(pDLSData->hwInstData, pDLSData->fileHandle, &p->gain, EAS_FALSE)) != EAS_SUCCESS) + return result; + if (p->gain > 0) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Positive gain [%ld] in DLS wsmp ignored, set to 0dB\n", p->gain); */ } + p->gain = 0; + } + + /* option flags */ + if ((result = EAS_HWGetDWord(pDLSData->hwInstData, pDLSData->fileHandle, <emp, EAS_FALSE)) != EAS_SUCCESS) + return result; + + /* sample loops */ + if ((result = EAS_HWGetDWord(pDLSData->hwInstData, pDLSData->fileHandle, <emp, EAS_FALSE)) != EAS_SUCCESS) + return result; + + /* if looped sample, get loop data */ + if (ltemp) + { + + if (ltemp > 1) + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "DLS sample with %lu loops, ignoring extra loops\n", ltemp); */ } + + /* skip ahead to loop data */ + if ((result = EAS_HWFileSeek(pDLSData->hwInstData, pDLSData->fileHandle, pos + (EAS_I32) cbSize)) != EAS_SUCCESS) + return result; + + /* get structure size */ + if ((result = EAS_HWGetDWord(pDLSData->hwInstData, pDLSData->fileHandle, <emp, EAS_FALSE)) != EAS_SUCCESS) + return result; + + /* get loop type */ + if ((result = EAS_HWGetDWord(pDLSData->hwInstData, pDLSData->fileHandle, <emp, EAS_FALSE)) != EAS_SUCCESS) + return result; + + /* get loop start */ + if ((result = EAS_HWGetDWord(pDLSData->hwInstData, pDLSData->fileHandle, &p->loopStart, EAS_FALSE)) != EAS_SUCCESS) + return result; + + /* get loop length */ + if ((result = EAS_HWGetDWord(pDLSData->hwInstData, pDLSData->fileHandle, &p->loopLength, EAS_FALSE)) != EAS_SUCCESS) + return result; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * Parse_fmt () + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT Parse_fmt (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, S_WSMP_DATA *p) +{ + EAS_RESULT result; + EAS_U16 wtemp; + EAS_U32 ltemp; + + /* seek to start of chunk */ + if ((result = EAS_HWFileSeek(pDLSData->hwInstData, pDLSData->fileHandle, pos)) != EAS_SUCCESS) + return result; + + /* get format tag */ + if ((result = EAS_HWGetWord(pDLSData->hwInstData, pDLSData->fileHandle, &wtemp, EAS_FALSE)) != EAS_SUCCESS) + return result; + if (wtemp != WAVE_FORMAT_PCM) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Unsupported DLS sample format %04x\n", wtemp); */ } + return EAS_ERROR_UNRECOGNIZED_FORMAT; + } + + /* get number of channels */ + if ((result = EAS_HWGetWord(pDLSData->hwInstData, pDLSData->fileHandle, &wtemp, EAS_FALSE)) != EAS_SUCCESS) + return result; + if (wtemp != 1) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "No support for DLS multi-channel samples\n"); */ } + return EAS_ERROR_UNRECOGNIZED_FORMAT; + } + + /* get sample rate */ + if ((result = EAS_HWGetDWord(pDLSData->hwInstData, pDLSData->fileHandle, &p->sampleRate, EAS_FALSE)) != EAS_SUCCESS) + return result; + + /* bytes/sec */ + if ((result = EAS_HWGetDWord(pDLSData->hwInstData, pDLSData->fileHandle, <emp, EAS_FALSE)) != EAS_SUCCESS) + return result; + + /* block align */ + if ((result = EAS_HWGetWord(pDLSData->hwInstData, pDLSData->fileHandle, &wtemp, EAS_FALSE)) != EAS_SUCCESS) + return result; + + /* bits/sample */ + if ((result = EAS_HWGetWord(pDLSData->hwInstData, pDLSData->fileHandle, &p->bitsPerSample, EAS_FALSE)) != EAS_SUCCESS) + return result; + + if ((p->bitsPerSample != 8) && (p->bitsPerSample != 16)) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Unsupported DLS bits-per-sample %d\n", p->bitsPerSample); */ } + return EAS_ERROR_UNRECOGNIZED_FORMAT; + } + + return EAS_SUCCESS; +} + +#if defined( _8_BIT_SAMPLES) +/*---------------------------------------------------------------------------- + * Parse_data () + *---------------------------------------------------------------------------- + * Purpose: + * + * NOTE: The optimized assembly versions of the interpolator require + * an extra sample at the end of the loop - a copy of the first + * sample. This routine must allocate an extra sample of data and + * copy the first sample of the loop to the end. + * + * Inputs: + * + * + * Outputs: + * + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT Parse_data (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, EAS_I32 size, S_WSMP_DATA *pWsmp, EAS_SAMPLE *pSample) +{ + EAS_RESULT result; + EAS_U8 convBuf[SAMPLE_CONVERT_CHUNK_SIZE]; + EAS_I32 count; + EAS_I32 i; + EAS_I8 *p; + + /* seek to start of chunk */ + if ((result = EAS_HWFileSeek(pDLSData->hwInstData, pDLSData->fileHandle, pos)) != EAS_SUCCESS) + return result; + + /* 8-bit samples in an 8-bit synth, just copy the data, and flip bit 7 */ + p = pSample; + if (pWsmp->bitsPerSample == 8) + { + if ((result = EAS_HWReadFile(pDLSData->hwInstData, pDLSData->fileHandle, pSample, size, &count)) != EAS_SUCCESS) + return result; + for (i = 0; i < size; i++) + /*lint -e{734} convert from unsigned to signed audio */ + *p++ ^= 0x80; + } + + /* 16-bit samples, need to convert to 8-bit or ADPCM */ + else + { + + while (size) + { + EAS_I8 *pInput; + + /* for undithered conversion, we're just copying the 8-bit data */ + if (pDLSData->bigEndian) + pInput = (EAS_I8*) convBuf; + else + pInput = (EAS_I8*) convBuf + 1; + + /* read a small chunk of data and convert it */ + count = (size < SAMPLE_CONVERT_CHUNK_SIZE ? size : SAMPLE_CONVERT_CHUNK_SIZE); + if ((result = EAS_HWReadFile(pDLSData->hwInstData, pDLSData->fileHandle, convBuf, count, &count)) != EAS_SUCCESS) + return result; + size -= count; + /*lint -e{704} use shift for performance */ + count = count >> 1; + + while (count--) + { + *p++ = *pInput; + pInput += 2; + } + } + } + + /* for looped samples, copy the last sample to the end */ + if (pWsmp->loopLength) + pSample[pWsmp->loopStart + pWsmp->loopLength] = pSample[pWsmp->loopStart]; + + return EAS_SUCCESS; +} +#elif defined(_16_BIT_SAMPLES) +#error "16-bit DLS conversion not implemented yet" +#else +#error "Must specifiy _8_BIT_SAMPLES or _16_BIT_SAMPLES" +#endif + +/*---------------------------------------------------------------------------- + * Parse_lins () + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT Parse_lins (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, EAS_I32 size) +{ + EAS_RESULT result; + EAS_U32 temp; + EAS_I32 endChunk; + EAS_I32 chunkPos; + + /* seek to start of chunk */ + if ((result = EAS_HWFileSeek(pDLSData->hwInstData, pDLSData->fileHandle, pos)) != EAS_SUCCESS) + return result; + + /* read to end of chunk */ + endChunk = pos + size; + while (pos < endChunk) + { + chunkPos = pos; + + /* get the next chunk type */ + if ((result = NextChunk(pDLSData, &pos, &temp, &size)) != EAS_SUCCESS) + return result; + + /* only instrument chunks are useful */ + if (temp != CHUNK_INS) + continue; + + if ((result = Parse_ins(pDLSData, chunkPos + 12, size)) != EAS_SUCCESS) + return result; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * Parse_ins () + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT Parse_ins (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, EAS_I32 size) +{ + EAS_RESULT result; + EAS_U32 temp; + EAS_I32 chunkPos; + EAS_I32 endChunk; + EAS_I32 lrgnPos; + EAS_I32 lrgnSize; + EAS_I32 lartPos; + EAS_I32 lartSize; + EAS_I32 lar2Pos; + EAS_I32 lar2Size; + EAS_I32 inshPos; + EAS_U32 regionCount; + EAS_U32 locale; + S_DLS_ART_VALUES art; + S_PROGRAM *pProgram; + EAS_U16 artIndex; + + /* seek to start of chunk */ + if ((result = EAS_HWFileSeek(pDLSData->hwInstData, pDLSData->fileHandle, pos)) != EAS_SUCCESS) + return result; + + /* no chunks yet */ + lrgnPos = lrgnSize = lartPos = lartSize = lar2Pos = lar2Size = inshPos = artIndex = 0; + + /* read to end of chunk */ + endChunk = pos + size; + while (pos < endChunk) + { + chunkPos = pos; + + /* get the next chunk type */ + if ((result = NextChunk(pDLSData, &pos, &temp, &size)) != EAS_SUCCESS) + return result; + + /* parse useful chunks */ + switch (temp) + { + case CHUNK_INSH: + inshPos = chunkPos + 8; + break; + + case CHUNK_LART: + lartPos = chunkPos + 12; + lartSize = size; + break; + + case CHUNK_LAR2: + lar2Pos = chunkPos + 12; + lar2Size = size; + break; + + case CHUNK_LRGN: + lrgnPos = chunkPos + 12; + lrgnSize = size; + break; + + default: + break; + } + } + + /* must have an lrgn to be useful */ + if (!lrgnPos) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "DLS ins chunk has no lrgn chunk\n"); */ } + return EAS_ERROR_UNRECOGNIZED_FORMAT; + } + + /* must have an insh to be useful */ + if (!inshPos) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "DLS ins chunk has no insh chunk\n"); */ } + return EAS_ERROR_UNRECOGNIZED_FORMAT; + } + + /* parse the instrument header */ + if ((result = Parse_insh(pDLSData, inshPos, ®ionCount, &locale)) != EAS_SUCCESS) + return result; + + /* initialize and parse the global data first */ + EAS_HWMemCpy(&art, &defaultArt, sizeof(S_DLS_ART_VALUES)); + if (lartPos) + if ((result = Parse_lart(pDLSData, lartPos, lartSize, &art)) != EAS_SUCCESS) + return result; + if (lar2Pos) + if ((result = Parse_lart(pDLSData, lar2Pos, lar2Size, &art)) != EAS_SUCCESS) + return result; + + if (art.values[PARAM_MODIFIED]) + { + artIndex = (EAS_U16) pDLSData->artCount; + pDLSData->artCount++; + } + + /* convert data on second pass */ + if (pDLSData->pDLS) + { + + if (art.values[PARAM_MODIFIED]) + Convert_art(pDLSData, &art, artIndex); + + /* setup pointers */ + pProgram = &pDLSData->pDLS->pDLSPrograms[pDLSData->instCount]; + + /* initialize instrument */ + pProgram->locale = locale; + pProgram->regionIndex = (EAS_U16) pDLSData->regionCount | FLAG_RGN_IDX_DLS_SYNTH; + + } + + /* parse the region data */ + if ((result = Parse_lrgn(pDLSData, lrgnPos, lrgnSize, artIndex, regionCount)) != EAS_SUCCESS) + return result; + + /* bump instrument count */ + pDLSData->instCount++; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * Parse_insh () + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT Parse_insh (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, EAS_U32 *pRgnCount, EAS_U32 *pLocale) +{ + EAS_RESULT result; + EAS_U32 bank; + EAS_U32 program; + + /* seek to start of chunk */ + if ((result = EAS_HWFileSeek(pDLSData->hwInstData, pDLSData->fileHandle, pos)) != EAS_SUCCESS) + return result; + + /* get the region count and locale */ + if ((result = EAS_HWGetDWord(pDLSData->hwInstData, pDLSData->fileHandle, pRgnCount, EAS_FALSE)) != EAS_SUCCESS) + return result; + if ((result = EAS_HWGetDWord(pDLSData->hwInstData, pDLSData->fileHandle, &bank, EAS_FALSE)) != EAS_SUCCESS) + return result; + if ((result = EAS_HWGetDWord(pDLSData->hwInstData, pDLSData->fileHandle, &program, EAS_FALSE)) != EAS_SUCCESS) + return result; + + /* verify the parameters are valid */ + if (bank & 0x7fff8080) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "DLS bank number is out of range: %08lx\n", bank); */ } + bank &= 0xff7f; + } + if (program > 127) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "DLS program number is out of range: %08lx\n", program); */ } + program &= 0x7f; + } + + /* save the program number */ + *pLocale = (bank << 8) | program; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * Parse_lrgn () + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT Parse_lrgn (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, EAS_I32 size, EAS_U16 artIndex, EAS_U32 numRegions) +{ + EAS_RESULT result; + EAS_U32 temp; + EAS_I32 chunkPos; + EAS_I32 endChunk; + EAS_U16 regionCount; + + /* seek to start of chunk */ + if ((result = EAS_HWFileSeek(pDLSData->hwInstData, pDLSData->fileHandle, pos)) != EAS_SUCCESS) + return result; + + /* read to end of chunk */ + regionCount = 0; + endChunk = pos + size; + while (pos < endChunk) + { + chunkPos = pos; + + /* get the next chunk type */ + if ((result = NextChunk(pDLSData, &pos, &temp, &size)) != EAS_SUCCESS) + return result; + + if ((temp == CHUNK_RGN) || (temp == CHUNK_RGN2)) + { + if (regionCount == numRegions) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "DLS region count exceeded cRegions value in insh, extra region ignored\n"); */ } + return EAS_SUCCESS; + } + if ((result = Parse_rgn(pDLSData, chunkPos + 12, size, artIndex)) != EAS_SUCCESS) + return result; + regionCount++; + } + } + + /* set a flag in the last region */ + if ((pDLSData->pDLS != NULL) && (regionCount > 0)) + pDLSData->pDLS->pDLSRegions[pDLSData->regionCount - 1].wtRegion.region.keyGroupAndFlags |= REGION_FLAG_LAST_REGION; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * Parse_rgn () + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT Parse_rgn (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, EAS_I32 size, EAS_U16 artIndex) +{ + EAS_RESULT result; + EAS_U32 temp; + EAS_I32 chunkPos; + EAS_I32 endChunk; + EAS_I32 rgnhPos; + EAS_I32 lartPos; + EAS_I32 lartSize; + EAS_I32 lar2Pos; + EAS_I32 lar2Size; + EAS_I32 wlnkPos; + EAS_I32 wsmpPos; + EAS_U32 waveIndex; + S_DLS_ART_VALUES art; + S_WSMP_DATA wsmp; + S_WSMP_DATA *pWsmp; + EAS_U16 regionIndex; + + /* seek to start of chunk */ + if ((result = EAS_HWFileSeek(pDLSData->hwInstData, pDLSData->fileHandle, pos)) != EAS_SUCCESS) + return result; + + /* no chunks found yet */ + rgnhPos = lartPos = lartSize = lar2Pos = lar2Size = wsmpPos = wlnkPos = 0; + regionIndex = (EAS_U16) pDLSData->regionCount; + + /* read to end of chunk */ + endChunk = pos + size; + while (pos < endChunk) + { + chunkPos = pos; + + /* get the next chunk type */ + if ((result = NextChunk(pDLSData, &pos, &temp, &size)) != EAS_SUCCESS) + return result; + + /* parse useful chunks */ + switch (temp) + { + case CHUNK_CDL: + if ((result = Parse_cdl(pDLSData, size, &temp)) != EAS_SUCCESS) + return result; + + /* if conditional chunk evaluates false, skip this list */ + if (!temp) + return EAS_SUCCESS; + break; + + case CHUNK_RGNH: + rgnhPos = chunkPos + 8; + break; + + case CHUNK_WLNK: + wlnkPos = chunkPos + 8; + break; + + case CHUNK_WSMP: + wsmpPos = chunkPos + 8; + break; + + case CHUNK_LART: + lartPos = chunkPos + 12; + lartSize = size; + break; + + case CHUNK_LAR2: + lar2Pos = chunkPos + 12; + lar2Size = size; + break; + + default: + break; + } + } + + /* must have a rgnh chunk to be useful */ + if (!rgnhPos) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "DLS rgn chunk has no rgnh chunk\n"); */ } + return EAS_ERROR_UNRECOGNIZED_FORMAT; + } + + /* must have a wlnk chunk to be useful */ + if (!wlnkPos) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "DLS rgn chunk has no wlnk chunk\n"); */ } + return EAS_ERROR_UNRECOGNIZED_FORMAT; + } + + /* parse wlnk chunk */ + if ((result = Parse_wlnk(pDLSData, wlnkPos, &waveIndex)) != EAS_SUCCESS) + return result; + pWsmp = &pDLSData->wsmpData[waveIndex]; + + /* if there is any articulation data, parse it */ + EAS_HWMemCpy(&art, &defaultArt, sizeof(S_DLS_ART_VALUES)); + if (lartPos) + { + if ((result = Parse_lart(pDLSData, lartPos, lartSize, &art)) != EAS_SUCCESS) + return result; + } + + if (lar2Pos) + { + if ((result = Parse_lart(pDLSData, lar2Pos, lar2Size, &art)) != EAS_SUCCESS) + return result; + } + + /* if second pass, process region header */ + if (pDLSData->pDLS) + { + + /* if local data was found convert it */ + if (art.values[PARAM_MODIFIED] == EAS_TRUE) + { + Convert_art(pDLSData, &art, (EAS_U16) pDLSData->artCount); + artIndex = (EAS_U16) pDLSData->artCount; + } + + /* parse region header */ + if ((result = Parse_rgnh(pDLSData, rgnhPos, &pDLSData->pDLS->pDLSRegions[regionIndex & REGION_INDEX_MASK])) != EAS_SUCCESS) + return result; + + /* parse wsmp chunk, copying parameters from original first */ + if (wsmpPos) + { + EAS_HWMemCpy(&wsmp, pWsmp, sizeof(wsmp)); + if ((result = Parse_wsmp(pDLSData, wsmpPos, &wsmp)) != EAS_SUCCESS) + return result; + + pWsmp = &wsmp; + } + + Convert_rgn(pDLSData, regionIndex, artIndex, (EAS_U16) waveIndex, pWsmp); + } + + /* if local articulation, bump count */ + if (art.values[PARAM_MODIFIED]) + pDLSData->artCount++; + + /* increment region count */ + pDLSData->regionCount++; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * Parse_rgnh () + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT Parse_rgnh (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, S_DLS_REGION *pRgn) +{ + EAS_RESULT result; + EAS_U16 lowKey; + EAS_U16 highKey; + EAS_U16 lowVel; + EAS_U16 highVel; + EAS_U16 optionFlags; + EAS_U16 keyGroup; + + /* seek to start of chunk */ + if ((result = EAS_HWFileSeek(pDLSData->hwInstData, pDLSData->fileHandle, pos)) != EAS_SUCCESS) + return result; + + /* get the key range */ + if ((result = EAS_HWGetWord(pDLSData->hwInstData, pDLSData->fileHandle, &lowKey, EAS_FALSE)) != EAS_SUCCESS) + return result; + if ((result = EAS_HWGetWord(pDLSData->hwInstData, pDLSData->fileHandle, &highKey, EAS_FALSE)) != EAS_SUCCESS) + return result; + + /* check the range */ + if (lowKey > 127) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "DLS rgnh: Low key out of range [%u]\n", lowKey); */ } + lowKey = 127; + } + if (highKey > 127) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "DLS rgnh: High key out of range [%u]\n", lowKey); */ } + highKey = 127; + } + + /* get the velocity range */ + if ((result = EAS_HWGetWord(pDLSData->hwInstData, pDLSData->fileHandle, &lowVel, EAS_FALSE)) != EAS_SUCCESS) + return result; + if ((result = EAS_HWGetWord(pDLSData->hwInstData, pDLSData->fileHandle, &highVel, EAS_FALSE)) != EAS_SUCCESS) + return result; + + /* check the range */ + if (lowVel > 127) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "DLS rgnh: Low velocity out of range [%u]\n", lowVel); */ } + lowVel = 127; + } + if (highVel > 127) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "DLS rgnh: High velocity out of range [%u]\n", highVel); */ } + highVel = 127; + } + + /* get the option flags */ + if ((result = EAS_HWGetWord(pDLSData->hwInstData, pDLSData->fileHandle, &optionFlags, EAS_FALSE)) != EAS_SUCCESS) + return result; + + /* get the key group */ + if ((result = EAS_HWGetWord(pDLSData->hwInstData, pDLSData->fileHandle, &keyGroup, EAS_FALSE)) != EAS_SUCCESS) + return result; + + /* save the key range and key group */ + pRgn->wtRegion.region.rangeLow = (EAS_U8) lowKey; + pRgn->wtRegion.region.rangeHigh = (EAS_U8) highKey; + + /*lint -e{734} keyGroup will always be from 0-15 */ + pRgn->wtRegion.region.keyGroupAndFlags = keyGroup << 8; + pRgn->velLow = (EAS_U8) lowVel; + pRgn->velHigh = (EAS_U8) highVel; + if (optionFlags & F_RGN_OPTION_SELFNONEXCLUSIVE) + pRgn->wtRegion.region.keyGroupAndFlags |= REGION_FLAG_NON_SELF_EXCLUSIVE; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * Parse_lart () + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT Parse_lart (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, EAS_I32 size, S_DLS_ART_VALUES *pArt) +{ + EAS_RESULT result; + EAS_U32 temp; + EAS_I32 endChunk; + EAS_I32 chunkPos; + EAS_I32 art1Pos; + EAS_I32 art2Pos; + + /* seek to start of chunk */ + if ((result = EAS_HWFileSeek(pDLSData->hwInstData, pDLSData->fileHandle, pos)) != EAS_SUCCESS) + return result; + + /* no articulation chunks yet */ + art1Pos = art2Pos = 0; + + /* read to end of chunk */ + endChunk = pos + size; + while (pos < endChunk) + { + chunkPos = pos; + + /* get the next chunk type */ + if ((result = NextChunk(pDLSData, &pos, &temp, &size)) != EAS_SUCCESS) + return result; + + /* parse useful chunks */ + switch (temp) + { + case CHUNK_CDL: + if ((result = Parse_cdl(pDLSData, size, &temp)) != EAS_SUCCESS) + return result; + + /* if conditional chunk evaluates false, skip this list */ + if (!temp) + return EAS_SUCCESS; + break; + + case CHUNK_ART1: + art1Pos = chunkPos + 8; + break; + + case CHUNK_ART2: + art2Pos = chunkPos + 8; + break; + + default: + break; + + } + } + + if (art1Pos) + { + if ((result = Parse_art(pDLSData, art1Pos, pArt)) != EAS_SUCCESS) + return result; + } + + if (art2Pos) + { + if ((result = Parse_art(pDLSData, art2Pos, pArt)) != EAS_SUCCESS) + return result; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * Parse_art() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT Parse_art (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, S_DLS_ART_VALUES *pArt) +{ + EAS_RESULT result; + EAS_U32 structSize; + EAS_U32 numConnections; + EAS_U16 source; + EAS_U16 control; + EAS_U16 destination; + EAS_U16 transform; + EAS_I32 scale; + EAS_INT i; + + /* seek to start of data */ + if ((result = EAS_HWFileSeek(pDLSData->hwInstData, pDLSData->fileHandle, pos)) != EAS_SUCCESS) + return result; + + /* get the structure size */ + if ((result = EAS_HWGetDWord(pDLSData->hwInstData, pDLSData->fileHandle, &structSize, EAS_FALSE)) != EAS_SUCCESS) + return result; + pos += (EAS_I32) structSize; + + /* get the number of connections */ + if ((result = EAS_HWGetDWord(pDLSData->hwInstData, pDLSData->fileHandle, &numConnections, EAS_FALSE)) != EAS_SUCCESS) + return result; + + /* skip to start of connections */ + if ((result = EAS_HWFileSeek(pDLSData->hwInstData, pDLSData->fileHandle, pos)) != EAS_SUCCESS) + return result; + + while (numConnections--) + { + + /* read the connection data */ + if ((result = EAS_HWGetWord(pDLSData->hwInstData, pDLSData->fileHandle, &source, EAS_FALSE)) != EAS_SUCCESS) + return result; + if ((result = EAS_HWGetWord(pDLSData->hwInstData, pDLSData->fileHandle, &control, EAS_FALSE)) != EAS_SUCCESS) + return result; + if ((result = EAS_HWGetWord(pDLSData->hwInstData, pDLSData->fileHandle, &destination, EAS_FALSE)) != EAS_SUCCESS) + return result; + if ((result = EAS_HWGetWord(pDLSData->hwInstData, pDLSData->fileHandle, &transform, EAS_FALSE)) != EAS_SUCCESS) + return result; + if ((result = EAS_HWGetDWord(pDLSData->hwInstData, pDLSData->fileHandle, &scale, EAS_FALSE)) != EAS_SUCCESS) + return result; + + /* look up the connection */ + for (i = 0; i < (EAS_INT) ENTRIES_IN_CONN_TABLE; i++) + { + if ((connTable[i].source == source) && + (connTable[i].destination == destination) && + (connTable[i].control == control)) + { + /*lint -e{704} use shift for performance */ + pArt->values[connTable[i].connection] = (EAS_I16) (scale >> 16); + pArt->values[PARAM_MODIFIED] = EAS_TRUE; + break; + } + } + if (i == PARAM_TABLE_SIZE) + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "WARN: Unsupported parameter in DLS file\n"); */ } + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * Parse_wlnk () + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT Parse_wlnk (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 pos, EAS_U32 *pWaveIndex) +{ + EAS_RESULT result; + + /* we only care about the the index */ + if ((result = EAS_HWFileSeek(pDLSData->hwInstData, pDLSData->fileHandle, pos + 8)) != EAS_SUCCESS) + return result; + + /* read the index */ + return EAS_HWGetDWord(pDLSData->hwInstData, pDLSData->fileHandle,pWaveIndex, EAS_FALSE); +} + +/*---------------------------------------------------------------------------- + * PopcdlStack () + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT PopcdlStack (EAS_U32 *pStack, EAS_INT *pStackPtr, EAS_U32 *pValue) +{ + + /* stack underflow, cdl block has an errorr */ + if (*pStackPtr < 0) + return EAS_ERROR_FILE_FORMAT; + + /* pop the value off the stack */ + *pValue = pStack[*pStackPtr]; + *pStackPtr = *pStackPtr - 1; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * PushcdlStack () + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT PushcdlStack (EAS_U32 *pStack, EAS_INT *pStackPtr, EAS_U32 value) +{ + + /* stack overflow, return an error */ + if (*pStackPtr >= CDL_STACK_SIZE) + return EAS_ERROR_FILE_FORMAT; + + /* push the value onto the stack */ + *pStackPtr = *pStackPtr + 1; + pStack[*pStackPtr] = value; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * QueryGUID () + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL QueryGUID (const DLSID *pGUID, EAS_U32 *pValue) +{ + + /* assume false */ + *pValue = 0; + if (EAS_HWMemCmp(&DLSID_GMInHardware, pGUID, sizeof(DLSID)) == 0) + { + *pValue = 0xffffffff; + return EAS_TRUE; + } + + if (EAS_HWMemCmp(&DLSID_GSInHardware, pGUID, sizeof(DLSID)) == 0) + return EAS_TRUE; + + if (EAS_HWMemCmp(&DLSID_XGInHardware, pGUID, sizeof(DLSID)) == 0) + return EAS_TRUE; + + if (EAS_HWMemCmp(&DLSID_SupportsDLS1, pGUID, sizeof(DLSID)) == 0) + { + *pValue = 0xffffffff; + return EAS_TRUE; + } + + if (EAS_HWMemCmp(&DLSID_SupportsDLS2, pGUID, sizeof(DLSID)) == 0) + return EAS_TRUE; + + if (EAS_HWMemCmp(&DLSID_SampleMemorySize, pGUID, sizeof(DLSID)) == 0) + { + *pValue = MAX_DLS_MEMORY; + return EAS_TRUE; + } + + if (EAS_HWMemCmp(&DLSID_ManufacturersID, pGUID, sizeof(DLSID)) == 0) + { + *pValue = 0x0000013A; + return EAS_TRUE; + } + + if (EAS_HWMemCmp(&DLSID_ProductID, pGUID, sizeof(DLSID)) == 0) + { + *pValue = LIB_VERSION; + return EAS_TRUE; + } + + if (EAS_HWMemCmp(&DLSID_SamplePlaybackRate, pGUID, sizeof(DLSID)) == 0) + { + *pValue = (EAS_U32) outputSampleRate; + return EAS_TRUE; + } + + /* unrecognized DLSID */ + return EAS_FALSE; +} + +/*---------------------------------------------------------------------------- + * ReadDLSID () + *---------------------------------------------------------------------------- + * Purpose: + * Reads a DLSID in a manner that is not sensitive to processor endian-ness + * + * Inputs: + * + * + * Outputs: + * + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ReadDLSID (SDLS_SYNTHESIZER_DATA *pDLSData, DLSID *pDLSID) +{ + EAS_RESULT result; + EAS_I32 n; + + if ((result = EAS_HWGetDWord(pDLSData->hwInstData, pDLSData->fileHandle, &pDLSID->Data1, EAS_FALSE)) != EAS_SUCCESS) + return result; + if ((result = EAS_HWGetWord(pDLSData->hwInstData, pDLSData->fileHandle, &pDLSID->Data2, EAS_FALSE)) != EAS_SUCCESS) + return result; + if ((result = EAS_HWGetWord(pDLSData->hwInstData, pDLSData->fileHandle, &pDLSID->Data3, EAS_FALSE)) != EAS_SUCCESS) + return result; + return EAS_HWReadFile(pDLSData->hwInstData, pDLSData->fileHandle, pDLSID->Data4, sizeof(pDLSID->Data4), &n); +} + +/*---------------------------------------------------------------------------- + * Parse_cdl () + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT Parse_cdl (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_I32 size, EAS_U32 *pValue) +{ + EAS_RESULT result; + EAS_U32 stack[CDL_STACK_SIZE]; + EAS_U16 opcode; + EAS_INT stackPtr; + EAS_U32 x, y; + DLSID dlsid; + + stackPtr = -1; + *pValue = 0; + x = 0; + while (size) + { + /* read the opcode */ + if ((result = EAS_HWGetWord(pDLSData->hwInstData, pDLSData->fileHandle, &opcode, EAS_FALSE)) != EAS_SUCCESS) + return result; + + /* handle binary opcodes */ + if (opcode <= DLS_CDL_EQ) + { + /* pop X and Y */ + if ((result = PopcdlStack(stack, &stackPtr, &x)) != EAS_SUCCESS) + return result; + if ((result = PopcdlStack(stack, &stackPtr, &y)) != EAS_SUCCESS) + return result; + switch (opcode) + { + case DLS_CDL_AND: + x = x & y; + break; + case DLS_CDL_OR: + x = x | y; + break; + case DLS_CDL_XOR: + x = x ^ y; + break; + case DLS_CDL_ADD: + x = x + y; + break; + case DLS_CDL_SUBTRACT: + x = x - y; + break; + case DLS_CDL_MULTIPLY: + x = x * y; + break; + case DLS_CDL_DIVIDE: + if (!y) + return EAS_ERROR_FILE_FORMAT; + x = x / y; + break; + case DLS_CDL_LOGICAL_AND: + x = (x && y); + break; + case DLS_CDL_LOGICAL_OR: + x = (x || y); + break; + case DLS_CDL_LT: + x = (x < y); + break; + case DLS_CDL_LE: + x = (x <= y); + break; + case DLS_CDL_GT: + x = (x > y); + break; + case DLS_CDL_GE: + x = (x >= y); + break; + case DLS_CDL_EQ: + x = (x == y); + break; + default: + break; + } + } + + else if (opcode == DLS_CDL_NOT) + { + if ((result = PopcdlStack(stack, &stackPtr, &x)) != EAS_SUCCESS) + return result; + x = !x; + } + + else if (opcode == DLS_CDL_CONST) + { + if ((result = EAS_HWGetDWord(pDLSData->hwInstData, pDLSData->fileHandle, &x, EAS_FALSE)) != EAS_SUCCESS) + return result; + } + + else if (opcode == DLS_CDL_QUERY) + { + if ((result = ReadDLSID(pDLSData, &dlsid)) != EAS_SUCCESS) + return result; + QueryGUID(&dlsid, &x); + } + + else if (opcode == DLS_CDL_QUERYSUPPORTED) + { + if ((result = ReadDLSID(pDLSData, &dlsid)) != EAS_SUCCESS) + return result; + x = QueryGUID(&dlsid, &y); + } + else + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Unsupported opcode %d in DLS file\n", opcode); */ } + + /* push the result on the stack */ + if ((result = PushcdlStack(stack, &stackPtr, x)) != EAS_SUCCESS) + return result; + } + + /* pop the last result off the stack */ + return PopcdlStack(stack, &stackPtr, pValue); +} + +/*---------------------------------------------------------------------------- + * Convert_rgn() + *---------------------------------------------------------------------------- + * Purpose: + * Convert region data from DLS to EAS + * + * Inputs: + * + * + * Outputs: + * + * + *---------------------------------------------------------------------------- +*/ +static void Convert_rgn (SDLS_SYNTHESIZER_DATA *pDLSData, EAS_U16 regionIndex, EAS_U16 artIndex, EAS_U16 waveIndex, S_WSMP_DATA *pWsmp) +{ + S_DLS_REGION *pRgn; + + /* setup pointers to data structures */ + pRgn = &pDLSData->pDLS->pDLSRegions[regionIndex]; + + /* intiailize indices */ + pRgn->wtRegion.artIndex = artIndex; + pRgn->wtRegion.waveIndex = waveIndex; + + /* convert region data */ + /*lint -e{704} use shift for performance */ + pRgn->wtRegion.gain = (EAS_I16) (pWsmp->gain >> 16); + pRgn->wtRegion.loopStart = pWsmp->loopStart; + pRgn->wtRegion.loopEnd = (pWsmp->loopStart + pWsmp->loopLength); + pRgn->wtRegion.tuning = pWsmp->fineTune -(pWsmp->unityNote * 100) + ConvertSampleRate(pWsmp->sampleRate); + if (pWsmp->loopLength != 0) + pRgn->wtRegion.region.keyGroupAndFlags |= REGION_FLAG_IS_LOOPED; +} + +/*---------------------------------------------------------------------------- + * Convert_art() + *---------------------------------------------------------------------------- + * Purpose: + * Convert articulation data from DLS to EAS + * + * Inputs: + * + * + * Outputs: + * + * + *---------------------------------------------------------------------------- +*/ +static void Convert_art (SDLS_SYNTHESIZER_DATA *pDLSData, const S_DLS_ART_VALUES *pDLSArt, EAS_U16 artIndex) +{ + S_DLS_ARTICULATION *pArt; + + /* setup pointers to data structures */ + pArt = &pDLSData->pDLS->pDLSArticulations[artIndex]; + + /* LFO parameters */ + pArt->modLFO.lfoFreq = ConvertLFOPhaseIncrement(pDLSArt->values[PARAM_MOD_LFO_FREQ]); + pArt->modLFO.lfoDelay = -ConvertDelay(pDLSArt->values[PARAM_MOD_LFO_DELAY]); + pArt->vibLFO.lfoFreq = ConvertLFOPhaseIncrement(pDLSArt->values[PARAM_VIB_LFO_FREQ]); + pArt->vibLFO.lfoDelay = -ConvertDelay(pDLSArt->values[PARAM_VIB_LFO_DELAY]); + + /* EG1 parameters */ + pArt->eg1.delayTime = ConvertDelay(pDLSArt->values[PARAM_VOL_EG_DELAY]); + pArt->eg1.attackTime = pDLSArt->values[PARAM_VOL_EG_ATTACK]; + pArt->eg1.holdTime = pDLSArt->values[PARAM_VOL_EG_HOLD]; + pArt->eg1.decayTime = pDLSArt->values[PARAM_VOL_EG_DECAY]; + pArt->eg1.sustainLevel = ConvertSustain(pDLSArt->values[PARAM_VOL_EG_SUSTAIN]); + pArt->eg1.releaseTime = ConvertRate(pDLSArt->values[PARAM_VOL_EG_RELEASE]); + pArt->eg1.velToAttack = pDLSArt->values[PARAM_VOL_EG_VEL_TO_ATTACK]; + pArt->eg1.keyNumToDecay = pDLSArt->values[PARAM_VOL_EG_KEY_TO_DECAY]; + pArt->eg1.keyNumToHold = pDLSArt->values[PARAM_VOL_EG_KEY_TO_HOLD]; + pArt->eg1ShutdownTime = ConvertRate(pDLSArt->values[PARAM_VOL_EG_SHUTDOWN]); + + /* EG2 parameters */ + pArt->eg2.delayTime = ConvertDelay(pDLSArt->values[PARAM_MOD_EG_DELAY]); + pArt->eg2.attackTime = pDLSArt->values[PARAM_MOD_EG_ATTACK]; + pArt->eg2.holdTime = pDLSArt->values[PARAM_MOD_EG_HOLD]; + pArt->eg2.decayTime = pDLSArt->values[PARAM_MOD_EG_DECAY]; + pArt->eg2.sustainLevel = ConvertSustain(pDLSArt->values[PARAM_MOD_EG_SUSTAIN]); + pArt->eg2.releaseTime = ConvertRate(pDLSArt->values[PARAM_MOD_EG_RELEASE]); + pArt->eg2.velToAttack = pDLSArt->values[PARAM_MOD_EG_VEL_TO_ATTACK]; + pArt->eg2.keyNumToDecay = pDLSArt->values[PARAM_MOD_EG_KEY_TO_DECAY]; + pArt->eg2.keyNumToHold = pDLSArt->values[PARAM_MOD_EG_KEY_TO_HOLD]; + + /* filter parameters */ + pArt->filterCutoff = pDLSArt->values[PARAM_INITIAL_FC]; + pArt->filterQandFlags = ConvertQ(pDLSArt->values[PARAM_INITIAL_Q]); + pArt->modLFOToFc = pDLSArt->values[PARAM_MOD_LFO_TO_FC]; + pArt->modLFOCC1ToFc = pDLSArt->values[PARAM_MOD_LFO_CC1_TO_FC]; + pArt->modLFOChanPressToFc = pDLSArt->values[PARAM_MOD_LFO_CHAN_PRESS_TO_FC]; + pArt->eg2ToFc = pDLSArt->values[PARAM_MOD_EG_TO_FC]; + pArt->velToFc = pDLSArt->values[PARAM_VEL_TO_FC]; + pArt->keyNumToFc = pDLSArt->values[PARAM_KEYNUM_TO_FC]; + + /* gain parameters */ + pArt->modLFOToGain = pDLSArt->values[PARAM_MOD_LFO_TO_GAIN]; + pArt->modLFOCC1ToGain = pDLSArt->values[PARAM_MOD_LFO_CC1_TO_GAIN]; + pArt->modLFOChanPressToGain = pDLSArt->values[PARAM_MOD_LFO_CHAN_PRESS_TO_GAIN]; + + /* pitch parameters */ + pArt->tuning = pDLSArt->values[PARAM_TUNING]; + pArt->keyNumToPitch = pDLSArt->values[PARAM_KEYNUM_TO_PITCH]; + pArt->vibLFOToPitch = pDLSArt->values[PARAM_VIB_LFO_TO_PITCH]; + pArt->vibLFOCC1ToPitch = pDLSArt->values[PARAM_VIB_LFO_CC1_TO_PITCH]; + pArt->vibLFOChanPressToPitch = pDLSArt->values[PARAM_VIB_LFO_CHAN_PRESS_TO_PITCH]; + pArt->modLFOToPitch = pDLSArt->values[PARAM_MOD_LFO_TO_PITCH]; + pArt->modLFOCC1ToPitch = pDLSArt->values[PARAM_MOD_LFO_CC1_TO_PITCH]; + pArt->modLFOChanPressToPitch = pDLSArt->values[PARAM_MOD_LFO_CHAN_PRESS_TO_PITCH]; + pArt->eg2ToPitch = pDLSArt->values[PARAM_MOD_EG_TO_PITCH]; + + /* output parameters */ + pArt->pan = ConvertPan(pDLSArt->values[PARAM_DEFAULT_PAN]); + + if (pDLSArt->values[PARAM_VEL_TO_GAIN] != 0) + pArt->filterQandFlags |= FLAG_DLS_VELOCITY_SENSITIVE; + +#ifdef _REVERB + pArt->reverbSend = pDLSArt->values[PARAM_DEFAULT_REVERB_SEND]; + pArt->cc91ToReverbSend = pDLSArt->values[PARAM_MIDI_CC91_TO_REVERB_SEND]; +#endif + +#ifdef _CHORUS + pArt->chorusSend = pDLSArt->values[PARAM_DEFAULT_CHORUS_SEND]; + pArt->cc93ToChorusSend = pDLSArt->values[PARAM_MIDI_CC93_TO_CHORUS_SEND]; +#endif +} + +/*---------------------------------------------------------------------------- + * ConvertSampleRate() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * + * Outputs: + * + * Side Effects: + *---------------------------------------------------------------------------- +*/ +static EAS_I16 ConvertSampleRate (EAS_U32 sampleRate) +{ + return (EAS_I16) (1200.0 * log10((double) sampleRate / (double) outputSampleRate) / log10(2.0)); +} + +/*---------------------------------------------------------------------------- + * ConvertSustainEG2() + *---------------------------------------------------------------------------- + * Convert sustain level to pitch/Fc multipler for EG2 + *---------------------------------------------------------------------------- +*/ +static EAS_I16 ConvertSustain (EAS_I32 sustain) +{ + /* check for sustain level of zero */ + if (sustain == 0) + return 0; + + /* convert to log2 factor */ + /*lint -e{704} use shift for performance */ + sustain = (sustain * SUSTAIN_LINEAR_CONVERSION_FACTOR) >> 15; + + if (sustain > SYNTH_FULL_SCALE_EG1_GAIN) + return SYNTH_FULL_SCALE_EG1_GAIN; + return (EAS_I16) sustain; +} + +/*---------------------------------------------------------------------------- + * ConvertDelay () + *---------------------------------------------------------------------------- + * Converts timecents to frame count. Used for LFO and envelope + * delay times. + *---------------------------------------------------------------------------- +*/ +EAS_I16 ConvertDelay (EAS_I32 timeCents) +{ + EAS_I32 temp; + + if (timeCents == ZERO_TIME_IN_CENTS) + return 0; + + /* divide time by secs per frame to get number of frames */ + temp = timeCents - dlsRateConvert; + + /* convert from time cents to 10-bit fraction */ + temp = FMUL_15x15(temp, TIME_CENTS_TO_LOG2); + + /* convert to frame count */ + temp = EAS_LogToLinear16(temp - (15 << 10)); + + if (temp < SYNTH_FULL_SCALE_EG1_GAIN) + return (EAS_I16) temp; + return SYNTH_FULL_SCALE_EG1_GAIN; +} + +/*---------------------------------------------------------------------------- + * ConvertRate () + *---------------------------------------------------------------------------- + * Convert timecents to rate + *---------------------------------------------------------------------------- +*/ +EAS_I16 ConvertRate (EAS_I32 timeCents) +{ + EAS_I32 temp; + + if (timeCents == ZERO_TIME_IN_CENTS) + return SYNTH_FULL_SCALE_EG1_GAIN; + + /* divide frame rate by time in log domain to get rate */ + temp = dlsRateConvert - timeCents; + +#if 1 + temp = EAS_Calculate2toX(temp); +#else + /* convert from time cents to 10-bit fraction */ + temp = FMUL_15x15(temp, TIME_CENTS_TO_LOG2); + + /* convert to rate */ + temp = EAS_LogToLinear16(temp); +#endif + + if (temp < SYNTH_FULL_SCALE_EG1_GAIN) + return (EAS_I16) temp; + return SYNTH_FULL_SCALE_EG1_GAIN; +} + + +/*---------------------------------------------------------------------------- + * ConvertLFOPhaseIncrement() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * + * Outputs: + * + * Side Effects: + *---------------------------------------------------------------------------- +*/ +static EAS_I16 ConvertLFOPhaseIncrement (EAS_I32 pitchCents) +{ + + /* check range */ + if (pitchCents > MAX_LFO_FREQUENCY_IN_PITCHCENTS) + pitchCents = MAX_LFO_FREQUENCY_IN_PITCHCENTS; + if (pitchCents < MIN_LFO_FREQUENCY_IN_PITCHCENTS) + pitchCents = MIN_LFO_FREQUENCY_IN_PITCHCENTS; + + /* double the rate and divide by frame rate by subtracting in log domain */ + pitchCents = pitchCents - dlsLFOFrequencyConvert; + + /* convert to phase increment */ + return (EAS_I16) EAS_Calculate2toX(pitchCents); +} + +/*---------------------------------------------------------------------------- + * ConvertPan() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * + * Outputs: + * + * Side Effects: + *---------------------------------------------------------------------------- +*/ +static EAS_I8 ConvertPan (EAS_I32 pan) +{ + + /* multiply by conversion factor */ + pan = FMUL_15x15 (PAN_CONVERSION_FACTOR, pan); + if (pan < MIN_PAN_VALUE) + return MIN_PAN_VALUE; + if (pan > MAX_PAN_VALUE) + return MAX_PAN_VALUE; + return (EAS_I8) pan; +} + +/*---------------------------------------------------------------------------- + * ConvertQ() + *---------------------------------------------------------------------------- + * Convert the DLS filter resonance to an index value used by the synth + * that accesses tables of coefficients based on the Q. + *---------------------------------------------------------------------------- +*/ +static EAS_U8 ConvertQ (EAS_I32 q) +{ + + /* apply limits */ + if (q <= 0) + return 0; + + /* convert to table index */ + /*lint -e{704} use shift for performance */ + q = (FILTER_Q_CONVERSION_FACTOR * q + 0x4000) >> 15; + + /* apply upper limit */ + if (q >= FILTER_RESONANCE_NUM_ENTRIES) + q = FILTER_RESONANCE_NUM_ENTRIES - 1; + return (EAS_U8) q; +} + +#ifdef _DEBUG_DLS +/*---------------------------------------------------------------------------- + * DumpDLS() + *---------------------------------------------------------------------------- +*/ +static void DumpDLS (S_EAS *pEAS) +{ + S_DLS_ARTICULATION *pArt; + S_DLS_REGION *pRegion; + EAS_INT i; + EAS_INT j; + + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x00000022 , pEAS->numPrograms); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x00000023 , pEAS->numWTRegions); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x00000024 , pEAS->numDLSArticulations); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x00000025 , pEAS->numSamples); + + /* dump the instruments */ + for (i = 0; i < pEAS->numPrograms; i++) + { + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x00000026 , + pEAS->pPrograms[i].locale >> 16, + (pEAS->pPrograms[i].locale >> 8) & 0x7f, + pEAS->pPrograms[i].locale & 0x7f); + + for (j = pEAS->pPrograms[i].regionIndex; ; j++) + { + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x00000027 , j); + pRegion = &pEAS->pWTRegions[j]; + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x00000028 , pRegion->gain); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x00000029 , pRegion->region.rangeLow, pRegion->region.rangeHigh); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x0000002a , pRegion->region.keyGroupAndFlags); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x0000002b , pRegion->loopStart); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x0000002c , pRegion->loopEnd); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x0000002d , pRegion->tuning); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x0000002e , pRegion->artIndex); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x0000002f , pRegion->waveIndex); + + if (pRegion->region.keyGroupAndFlags & REGION_FLAG_LAST_REGION) + break; + } + + } + + /* dump the articulation data */ + for (i = 0; i < pEAS->numDLSArticulations; i++) + { + /* articulation data */ + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x00000030 , i); + pArt = &pEAS->pDLSArticulations[i]; + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x00000031 , pArt->m_nEG2toFilterDepth); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x00000032 , pArt->m_nEG2toPitchDepth); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x00000033 , pArt->m_nFilterCutoffFrequency); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x00000034 , pArt->m_nFilterResonance); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x00000035 , pArt->m_nLFOAmplitudeDepth); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x00000036 , pArt->m_nLFODelayTime); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x00000037 , pArt->m_nLFOFrequency); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x00000038 , pArt->m_nLFOPitchDepth); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x00000039 , pArt->m_nPan); + + /* EG1 data */ + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x0000003a , pArt->m_sEG1.m_nAttack); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x0000003b , pArt->m_sEG1.m_nDecay); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x0000003c , pArt->m_sEG1.m_nSustain); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x0000003d , pArt->m_sEG1.m_nRelease); + + /* EG2 data */ + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x0000003e , pArt->m_sEG2.m_nAttack); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x0000003f , pArt->m_sEG2.m_nDecay); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x00000040 , pArt->m_sEG2.m_nSustain); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x00000041 , pArt->m_sEG2.m_nRelease); + + } + + /* dump the waves */ + for (i = 0; i < pEAS->numSamples; i++) + { + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x00000042 , i); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x00000043 , pEAS->pSampleLen[i]); + EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x19299ed4, 0x00000044 , pEAS->ppSamples[i]); + } + +} +#endif + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_mdls.h b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_mdls.h new file mode 100755 index 0000000..16e6479 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_mdls.h @@ -0,0 +1,295 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_mdls.h + * + * Contents and purpose: + * Declarations, interfaces, and prototypes for eas_mdls.c + * + * Copyright Sonic Network Inc. 2004 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_MDLS_H +#define _EAS_MDLS_H + +/*------------------------------------ + * includes + *------------------------------------ +*/ +#include "eas_data.h" + + +/*------------------------------------ + * Some defines for dls.h + *------------------------------------ +*/ +#ifndef DWORD +#define DWORD EAS_I32 +#define FAR +#define SHORT EAS_I16 +#define USHORT EAS_U16 +#define LONG EAS_I32 +#define ULONG EAS_U32 +#endif + + +/* GUID struct (call it DLSID in case GUID is defined elsewhere) */ +typedef struct +{ + EAS_U32 Data1; + EAS_U16 Data2; + EAS_U16 Data3; + EAS_U8 Data4[8]; +} DLSID; + +#define DEFINE_DLSID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) const DLSID name = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } + +/*------------------------------------ + * defines + *------------------------------------ +*/ + +/* maximum sample memory for DLS query support */ +#ifndef MAX_DLS_MEMORY +#define MAX_DLS_MEMORY 65536 +#endif + +/* size of conditional chunk stack */ +#ifndef CDL_STACK_SIZE +#define CDL_STACK_SIZE 8 +#endif + +/* size of read buffer for sample conversion */ +#ifndef SAMPLE_CONVERT_CHUNK_SIZE +#define SAMPLE_CONVERT_CHUNK_SIZE 32 +#endif + + +#define ZERO_TIME_IN_CENTS -32768 + +/* Pan calculation macros */ +#define PAN_CONVERSION_FACTOR 4129 +#define MAX_PAN_VALUE 63 +#define MIN_PAN_VALUE -63 + +/* multiplier to convert time cents to 10-bit fraction log for EAS_LogToLinear16 */ +#define TIME_CENTS_TO_LOG2 27962 + +/* conversion factor sustain level from percent to exponent for LogToLinear16 */ +#define SUSTAIN_LOG_CONVERSION_FACTOR 536871 +#define SUSTAIN_LOG_CONVERSION_SHIFT 15 + +/* conversion factor sustain level from percent to EG full scale */ +#define SUSTAIN_LINEAR_CONVERSION_FACTOR 1073709 + +/* conversion factor to convert frame period to decay rate */ +#define DECAY_CONVERSION_FACTOR -16 + +/*---------------------------------------------------------------------------- + * These macros define the various characteristics of the defined sample rates + *---------------------------------------------------------------------------- + * DLS_ATTACK_TIME_CONVERT log offset for conversion from time cents to attack rate + * DLS_LFO_FREQUENCY_CONVERT pitch-cents offset for LFO frequency conversion + *---------------------------------------------------------------------------- +*/ + +#if defined (_SAMPLE_RATE_8000) +#define DLS_RATE_CONVERT -9559 +#define DLS_LFO_FREQUENCY_CONVERT 5921 + +#elif defined (_SAMPLE_RATE_16000) +#define DLS_RATE_CONVERT -9559 +#define DLS_LFO_FREQUENCY_CONVERT 5921 + +#elif defined (_SAMPLE_RATE_20000) +#define DLS_RATE_CONVERT -8745 +#define DLS_LFO_FREQUENCY_CONVERT 5108 + +#elif defined (_SAMPLE_RATE_22050) +#define DLS_RATE_CONVERT -8914 +#define DLS_LFO_FREQUENCY_CONVERT 5277 + +#elif defined (_SAMPLE_RATE_24000) +#define DLS_RATE_CONVERT -9061 +#define DLS_LFO_FREQUENCY_CONVERT 5423 + +#elif defined (_SAMPLE_RATE_32000) +#define DLS_RATE_CONVERT -9559 +#define DLS_LFO_FREQUENCY_CONVERT 5921 + +#elif defined (_SAMPLE_RATE_44100) +#define DLS_RATE_CONVERT -8914 +#define DLS_LFO_FREQUENCY_CONVERT 5277 + +#elif defined (_SAMPLE_RATE_48000) +#define DLS_RATE_CONVERT -9061 +#define DLS_LFO_FREQUENCY_CONVERT 5423 + +#else +#error "_SAMPLE_RATE_XXXXX must be defined to valid rate" +#endif + +/* + * FILTER_Q_CONVERSION_FACTOR convers the 0.1dB steps in the DLS + * file to our internal 0.75 dB steps. The value is calculated + * as follows: + * + * 32768 / (10 * ) + * + * FILTER_RESONANCE_NUM_ENTRIES is the number of entries in the table +*/ +#define FILTER_Q_CONVERSION_FACTOR 4369 +#define FILTER_RESONANCE_NUM_ENTRIES 31 + +/* + * Multiplier to convert DLS gain units (10ths of a dB) to a + * power-of-two exponent for conversion to linear gain using our + * piece-wise linear approximator. Note that we ignore the lower + * 16-bits of the DLS gain value. The result is a 10-bit fraction + * that works with the EAS_LogToLinear16 function. + * + * DLS_GAIN_FACTOR = (2^18) / (200 * log10(2)) + */ +#define DLS_GAIN_FACTOR 4354 +#define DLS_GAIN_SHIFT 8 + +/* + * Reciprocal of 10 for quick divide by 10's + * + * DLS_GAIN_FACTOR = (2^18) / (200 * log10(2)) + */ +#define DLS_DIV_10_FACTOR 3277 +#define DLS_DIV_10_SHIFT 16 + +/* + * Multiplier to convert DLS time cents units to a power-of-two + * exponent for conversion to absolute time units using our + * piece-wise linear approximator. + * + * DLS_TIME_FACTOR = (2^22) / 1200 + */ +#define DLS_TIME_FACTOR 3495 +#define DLS_TIME_SHIFT 22 + + +/* LFO limits */ +#define MAX_LFO_FREQUENCY_IN_HERTZ 20 +#define MIN_LFO_FREQUENCY_IN_HERTZ 0.1 +#define MAX_LFO_FREQUENCY_IN_PITCHCENTS 1549 +#define MIN_LFO_FREQUENCY_IN_PITCHCENTS -7624 +#define MAX_LFO_AMPLITUDE_DEPTH 12 /* in dB, DLS2.1 p 31*/ +#define MIN_LFO_AMPLITUDE_DEPTH -12 /* in dB, DLS2.1 p 31*/ + +/* add to pitch cents before pow(2.0, n) to convert to frequency */ +#define ABSOLUTE_PITCH_BIAS 238395828 + +#define A5_PITCH_OFFSET 6900 + +/* +CHUNK_TYPE is a macro that converts the 4 input args into a 32-bit int +where +argument a is placed at the MSB location and +argument d is placed at the LSB location. +This is useful for determining the DLS chunk types +*/ +#define CHUNK_TYPE(a,b,c,d) ( \ + ( ((EAS_U32)(a) & 0xFF) << 24 ) \ + + ( ((EAS_U32)(b) & 0xFF) << 16 ) \ + + ( ((EAS_U32)(c) & 0xFF) << 8 ) \ + + ( ((EAS_U32)(d) & 0xFF) ) ) + +#define CHUNK_RIFF CHUNK_TYPE('R','I','F','F') +#define CHUNK_DLS CHUNK_TYPE('D','L','S',' ') +#define CHUNK_CDL CHUNK_TYPE('c','d','l',' ') +#define CHUNK_VERS CHUNK_TYPE('v','e','r','s') +#define CHUNK_DLID CHUNK_TYPE('d','l','i','d') +#define CHUNK_LIST CHUNK_TYPE('L','I','S','T') +#define CHUNK_COLH CHUNK_TYPE('c','o','l','h') +#define CHUNK_LINS CHUNK_TYPE('l','i','n','s') +#define CHUNK_PTBL CHUNK_TYPE('p','t','b','l') +#define CHUNK_WVPL CHUNK_TYPE('w','v','p','l') +#define CHUNK_INFO CHUNK_TYPE('I','N','F','O') +#define CHUNK_INAM CHUNK_TYPE('I','N','A','M') +#define CHUNK_INS CHUNK_TYPE('i','n','s',' ') +#define CHUNK_INSH CHUNK_TYPE('i','n','s','h') +#define CHUNK_LRGN CHUNK_TYPE('l','r','g','n') +#define CHUNK_RGN CHUNK_TYPE('r','g','n',' ') +#define CHUNK_RGN2 CHUNK_TYPE('r','g','n','2') +#define CHUNK_RGNH CHUNK_TYPE('r','g','n','h') +#define CHUNK_WSMP CHUNK_TYPE('w','s','m','p') +#define CHUNK_WLNK CHUNK_TYPE('w','l','n','k') +#define CHUNK_LART CHUNK_TYPE('l','a','r','t') +#define CHUNK_LAR2 CHUNK_TYPE('l','a','r','2') +#define CHUNK_ART1 CHUNK_TYPE('a','r','t','1') +#define CHUNK_ART2 CHUNK_TYPE('a','r','t','2') +#define CHUNK_WAVE CHUNK_TYPE('w','a','v','e') +#define CHUNK_FMT CHUNK_TYPE('f','m','t',' ') +#define CHUNK_DATA CHUNK_TYPE('d','a','t','a') +#define CHUNK_DMPR CHUNK_TYPE('d','m','p','r') + + +#define WAVE_FORMAT_PCM 0x0001 /* Microsoft PCM format, see DLS2.1 p60 */ +#define WAVE_FORMAT_EXTENSIBLE 0xffff + +/* defines for wave table structures */ + +/* initialize each articulation structure to a harmless state */ +/* change art values after we've determined EAS internals */ +#define DEFAULT_DLS_FILTER_CUTOFF_FREQUENCY 0x7FFF /* DLS2.1, p 31 means leave filter off */ + +/**********/ + +/* define the waves that we expect to generate instead of store */ +/* NOTE: our comparison routine converts the input string +to lowercase, so the following comparison values should all +be in lowercase. +*/ +#define STRING_NOISE "noise" + + +/*------------------------------------ + * type definitions + *------------------------------------ +*/ +#ifdef _STANDALONE_CONVERTER +typedef struct s_dls_params +{ + EAS_INT sampleRate; + EAS_INT samplesPerFrame; + EAS_INT bitDepth; + double ditherLevel; + double ditherFilterCoeff; + EAS_BOOL compatibility; + EAS_BOOL encodeADPCM; +} S_DLS_PARAMS; +#endif + + +/* function prototypes */ +EAS_RESULT DLSParser (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle, EAS_I32 offset, S_DLS **pDLS); +EAS_RESULT DLSCleanup (EAS_HW_DATA_HANDLE hwInstData, S_DLS *pDLS); +void DLSAddRef (S_DLS *pDLS); +EAS_I16 ConvertDelay (EAS_I32 timeCents); +EAS_I16 ConvertRate (EAS_I32 timeCents); + + +#ifdef _STANDALONE_CONVERTER +void DLSConvParams (S_DLS_PARAMS *pParams, EAS_BOOL set); +#endif + +#endif + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_midi.c b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_midi.c new file mode 100755 index 0000000..8cb043a --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_midi.c @@ -0,0 +1,569 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_midi.c + * + * Contents and purpose: + * This file implements the MIDI stream parser. It is called by eas_smf.c to parse MIDI messages + * that are streamed out of the file. It can also parse live MIDI streams. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 794 $ + * $Date: 2007-08-01 00:08:48 -0700 (Wed, 01 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_data.h" +#include "eas_report.h" +#include "eas_miditypes.h" +#include "eas_midi.h" +#include "eas_vm_protos.h" +#include "eas_parser.h" + +#ifdef JET_INTERFACE +#include "jet_data.h" +#endif + + +/* state enumerations for ProcessSysExMessage */ +typedef enum +{ + eSysEx, + eSysExUnivNonRealTime, + eSysExUnivNrtTargetID, + eSysExGMControl, + eSysExUnivRealTime, + eSysExUnivRtTargetID, + eSysExDeviceControl, + eSysExMasterVolume, + eSysExMasterVolLSB, + eSysExSPMIDI, + eSysExSPMIDIchan, + eSysExSPMIDIMIP, + eSysExMfgID1, + eSysExMfgID2, + eSysExMfgID3, + eSysExEnhancer, + eSysExEnhancerSubID, + eSysExEnhancerFeedback1, + eSysExEnhancerFeedback2, + eSysExEnhancerDrive, + eSysExEnhancerWet, + eSysExEOX, + eSysExIgnore +} E_SYSEX_STATES; + +/* local prototypes */ +static EAS_RESULT ProcessMIDIMessage (S_EAS_DATA *pEASData, S_SYNTH *pSynth, S_MIDI_STREAM *pMIDIStream, EAS_INT parserMode); +static EAS_RESULT ProcessSysExMessage (S_EAS_DATA *pEASData, S_SYNTH *pSynth, S_MIDI_STREAM *pMIDIStream, EAS_U8 c, EAS_INT parserMode); + +/*---------------------------------------------------------------------------- + * EAS_InitMIDIStream() + *---------------------------------------------------------------------------- + * Purpose: + * Initializes the MIDI stream state for parsing. + * + * Inputs: + * + * Outputs: + * returns EAS_RESULT (EAS_SUCCESS is OK) + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void EAS_InitMIDIStream (S_MIDI_STREAM *pMIDIStream) +{ + pMIDIStream->byte3 = EAS_FALSE; + pMIDIStream->pending = EAS_FALSE; + pMIDIStream->runningStatus = 0; + pMIDIStream->status = 0; +} + +/*---------------------------------------------------------------------------- + * EAS_ParseMIDIStream() + *---------------------------------------------------------------------------- + * Purpose: + * Parses a MIDI input stream character by character. Characters are pushed (rather than pulled) + * so the interface works equally well for both file and stream I/O. + * + * Inputs: + * c - character from MIDI stream + * + * Outputs: + * returns EAS_RESULT (EAS_SUCCESS is OK) + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_ParseMIDIStream (S_EAS_DATA *pEASData, S_SYNTH *pSynth, S_MIDI_STREAM *pMIDIStream, EAS_U8 c, EAS_INT parserMode) +{ + + /* check for new status byte */ + if (c & 0x80) + { + /* save new running status */ + if (c < 0xf8) + { + pMIDIStream->runningStatus = c; + pMIDIStream->byte3 = EAS_FALSE; + + /* deal with SysEx */ + if ((c == 0xf7) || (c == 0xf0)) + { + if (parserMode == eParserModeMetaData) + return EAS_SUCCESS; + return ProcessSysExMessage(pEASData, pSynth, pMIDIStream, c, parserMode); + } + + /* inform the file parser that we're in the middle of a message */ + if ((c < 0xf4) || (c > 0xf6)) + pMIDIStream->pending = EAS_TRUE; + } + + /* real-time message - ignore it */ + return EAS_SUCCESS; + } + + /* 3rd byte of a 3-byte message? */ + if (pMIDIStream->byte3) + { + pMIDIStream->d2 = c; + pMIDIStream->byte3 = EAS_FALSE; + pMIDIStream->pending = EAS_FALSE; + if (parserMode == eParserModeMetaData) + return EAS_SUCCESS; + return ProcessMIDIMessage(pEASData, pSynth, pMIDIStream, parserMode); + } + + /* check for status received */ + if (pMIDIStream->runningStatus) + { + + /* save new status and data byte */ + pMIDIStream->status = pMIDIStream->runningStatus; + + /* check for 3-byte messages */ + if (pMIDIStream->status < 0xc0) + { + pMIDIStream->d1 = c; + pMIDIStream->pending = EAS_TRUE; + pMIDIStream->byte3 = EAS_TRUE; + return EAS_SUCCESS; + } + + /* check for 2-byte messages */ + if (pMIDIStream->status < 0xe0) + { + pMIDIStream->d1 = c; + pMIDIStream->pending = EAS_FALSE; + if (parserMode == eParserModeMetaData) + return EAS_SUCCESS; + return ProcessMIDIMessage(pEASData, pSynth, pMIDIStream, parserMode); + } + + /* check for more 3-bytes message */ + if (pMIDIStream->status < 0xf0) + { + pMIDIStream->d1 = c; + pMIDIStream->pending = EAS_TRUE; + pMIDIStream->byte3 = EAS_TRUE; + return EAS_SUCCESS; + } + + /* SysEx message? */ + if (pMIDIStream->status == 0xF0) + { + if (parserMode == eParserModeMetaData) + return EAS_SUCCESS; + return ProcessSysExMessage(pEASData, pSynth, pMIDIStream, c, parserMode); + } + + /* remaining messages all clear running status */ + pMIDIStream->runningStatus = 0; + + /* F2 is 3-byte message */ + if (pMIDIStream->status == 0xf2) + { + pMIDIStream->byte3 = EAS_TRUE; + return EAS_SUCCESS; + } + } + + /* no status byte received, provide a warning, but we should be able to recover */ + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Received MIDI data without a valid status byte: %d\n",c); */ } + pMIDIStream->pending = EAS_FALSE; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * ProcessMIDIMessage() + *---------------------------------------------------------------------------- + * Purpose: + * This function processes a typical MIDI message. All of the data has been received, just need + * to take appropriate action. + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ProcessMIDIMessage (S_EAS_DATA *pEASData, S_SYNTH *pSynth, S_MIDI_STREAM *pMIDIStream, EAS_INT parserMode) +{ + EAS_U8 channel; + + channel = pMIDIStream->status & 0x0f; + switch (pMIDIStream->status & 0xf0) + { + case 0x80: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"NoteOff: %02x %02x %02x\n", + pMIDIStream->status, pMIDIStream->d1, pMIDIStream->d2); */ } + if (parserMode <= eParserModeMute) + VMStopNote(pEASData->pVoiceMgr, pSynth, channel, pMIDIStream->d1, pMIDIStream->d2); + break; + + case 0x90: + if (pMIDIStream->d2) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"NoteOn: %02x %02x %02x\n", + pMIDIStream->status, pMIDIStream->d1, pMIDIStream->d2); */ } + pMIDIStream->flags |= MIDI_FLAG_FIRST_NOTE; + if (parserMode == eParserModePlay) + VMStartNote(pEASData->pVoiceMgr, pSynth, channel, pMIDIStream->d1, pMIDIStream->d2); + } + else + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"NoteOff: %02x %02x %02x\n", + pMIDIStream->status, pMIDIStream->d1, pMIDIStream->d2); */ } + if (parserMode <= eParserModeMute) + VMStopNote(pEASData->pVoiceMgr, pSynth, channel, pMIDIStream->d1, pMIDIStream->d2); + } + break; + + case 0xa0: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"PolyPres: %02x %02x %02x\n", + pMIDIStream->status, pMIDIStream->d1, pMIDIStream->d2); */ } + break; + + case 0xb0: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"Control: %02x %02x %02x\n", + pMIDIStream->status, pMIDIStream->d1, pMIDIStream->d2); */ } + if (parserMode <= eParserModeMute) + VMControlChange(pEASData->pVoiceMgr, pSynth, channel, pMIDIStream->d1, pMIDIStream->d2); +#ifdef JET_INTERFACE + if (pMIDIStream->jetData & MIDI_FLAGS_JET_CB) + { + JET_Event(pEASData, pMIDIStream->jetData & (JET_EVENT_SEG_MASK | JET_EVENT_TRACK_MASK), + channel, pMIDIStream->d1, pMIDIStream->d2); + } +#endif + break; + + case 0xc0: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"Program: %02x %02x\n", + pMIDIStream->status, pMIDIStream->d1); */ } + if (parserMode <= eParserModeMute) + VMProgramChange(pEASData->pVoiceMgr, pSynth, channel, pMIDIStream->d1); + break; + + case 0xd0: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"ChanPres: %02x %02x\n", + pMIDIStream->status, pMIDIStream->d1); */ } + if (parserMode <= eParserModeMute) + VMChannelPressure(pSynth, channel, pMIDIStream->d1); + break; + + case 0xe0: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"PBend: %02x %02x %02x\n", + pMIDIStream->status, pMIDIStream->d1, pMIDIStream->d2); */ } + if (parserMode <= eParserModeMute) + VMPitchBend(pSynth, channel, pMIDIStream->d1, pMIDIStream->d2); + break; + + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"Unknown: %02x %02x %02x\n", + pMIDIStream->status, pMIDIStream->d1, pMIDIStream->d2); */ } + } + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * ProcessSysExMessage() + *---------------------------------------------------------------------------- + * Purpose: + * Process a SysEx character byte from the MIDI stream. Since we cannot + * simply wait for the next character to arrive, we are forced to save + * state after each character. It would be easier to parse at the file + * level, but then we lose the nice feature of being able to support + * these messages in a real-time MIDI stream. + * + * Inputs: + * pEASData - pointer to synthesizer instance data + * c - character to be processed + * locating - if true, the sequencer is relocating to a new position + * + * Outputs: + * + * + * Side Effects: + * + * Notes: + * These are the SysEx messages we can receive: + * + * SysEx messages + * { f0 7e 7f 09 01 f7 } GM 1 On + * { f0 7e 7f 09 02 f7 } GM 1/2 Off + * { f0 7e 7f 09 03 f7 } GM 2 On + * { f0 7f 7f 04 01 lsb msb } Master Volume + * { f0 7f 7f 0b 01 ch mip [ch mip ...] f7 } SP-MIDI + * { f0 00 01 3a 04 01 fdbk1 fdbk2 drive wet dry f7 } Enhancer + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ProcessSysExMessage (S_EAS_DATA *pEASData, S_SYNTH *pSynth, S_MIDI_STREAM *pMIDIStream, EAS_U8 c, EAS_INT parserMode) +{ + + /* check for start byte */ + if (c == 0xf0) + { + pMIDIStream->sysExState = eSysEx; + } + /* check for end byte */ + else if (c == 0xf7) + { + /* if this was a MIP message, update the MIP table */ + if ((pMIDIStream->sysExState == eSysExSPMIDIchan) && (parserMode != eParserModeMetaData)) + VMUpdateMIPTable(pEASData->pVoiceMgr, pSynth); + pMIDIStream->sysExState = eSysExIgnore; + } + + /* process SysEx message */ + else + { + switch (pMIDIStream->sysExState) + { + case eSysEx: + + /* first byte, determine message class */ + switch (c) + { + case 0x7e: + pMIDIStream->sysExState = eSysExUnivNonRealTime; + break; + case 0x7f: + pMIDIStream->sysExState = eSysExUnivRealTime; + break; + case 0x00: + pMIDIStream->sysExState = eSysExMfgID1; + break; + default: + pMIDIStream->sysExState = eSysExIgnore; + break; + } + break; + + /* process GM message */ + case eSysExUnivNonRealTime: + if (c == 0x7f) + pMIDIStream->sysExState = eSysExUnivNrtTargetID; + else + pMIDIStream->sysExState = eSysExIgnore; + break; + + case eSysExUnivNrtTargetID: + if (c == 0x09) + pMIDIStream->sysExState = eSysExGMControl; + else + pMIDIStream->sysExState = eSysExIgnore; + break; + + case eSysExGMControl: + if ((c == 1) || (c == 3)) + { + /* GM 1 or GM2 On, reset synth */ + if (parserMode != eParserModeMetaData) + { + pMIDIStream->flags |= MIDI_FLAG_GM_ON; + VMReset(pEASData->pVoiceMgr, pSynth, EAS_FALSE); + VMInitMIPTable(pSynth); + } + pMIDIStream->sysExState = eSysExEOX; + } + else + pMIDIStream->sysExState = eSysExIgnore; + break; + + /* Process Master Volume and SP-MIDI */ + case eSysExUnivRealTime: + if (c == 0x7f) + pMIDIStream->sysExState = eSysExUnivRtTargetID; + else + pMIDIStream->sysExState = eSysExIgnore; + break; + + case eSysExUnivRtTargetID: + if (c == 0x04) + pMIDIStream->sysExState = eSysExDeviceControl; + else if (c == 0x0b) + pMIDIStream->sysExState = eSysExSPMIDI; + else + pMIDIStream->sysExState = eSysExIgnore; + break; + + /* process master volume */ + case eSysExDeviceControl: + if (c == 0x01) + pMIDIStream->sysExState = eSysExMasterVolume; + else + pMIDIStream->sysExState = eSysExIgnore; + break; + + case eSysExMasterVolume: + /* save LSB */ + pMIDIStream->d1 = c; + pMIDIStream->sysExState = eSysExMasterVolLSB; + break; + + case eSysExMasterVolLSB: + if (parserMode != eParserModeMetaData) + { + EAS_I32 gain = ((EAS_I32) c << 8) | ((EAS_I32) pMIDIStream->d1 << 1); + gain = (gain * gain) >> 15; + VMSetVolume(pSynth, (EAS_U16) gain); + } + pMIDIStream->sysExState = eSysExEOX; + break; + + /* process SP-MIDI MIP message */ + case eSysExSPMIDI: + if (c == 0x01) + { + /* assume all channels are muted */ + if (parserMode != eParserModeMetaData) + VMInitMIPTable(pSynth); + pMIDIStream->d1 = 0; + pMIDIStream->sysExState = eSysExSPMIDIchan; + } + else + pMIDIStream->sysExState = eSysExIgnore; + break; + + case eSysExSPMIDIchan: + if (c < NUM_SYNTH_CHANNELS) + { + pMIDIStream->d2 = c; + pMIDIStream->sysExState = eSysExSPMIDIMIP; + } + else + { + /* bad MIP message - unmute channels */ + if (parserMode != eParserModeMetaData) + VMInitMIPTable(pSynth); + pMIDIStream->sysExState = eSysExIgnore; + } + break; + + case eSysExSPMIDIMIP: + /* process MIP entry here */ + if (parserMode != eParserModeMetaData) + VMSetMIPEntry(pEASData->pVoiceMgr, pSynth, pMIDIStream->d2, pMIDIStream->d1, c); + pMIDIStream->sysExState = eSysExSPMIDIchan; + + /* if 16 channels received, update MIP table */ + if (++pMIDIStream->d1 == NUM_SYNTH_CHANNELS) + { + if (parserMode != eParserModeMetaData) + VMUpdateMIPTable(pEASData->pVoiceMgr, pSynth); + pMIDIStream->sysExState = eSysExEOX; + } + break; + + /* process Enhancer */ + case eSysExMfgID1: + if (c == 0x01) + pMIDIStream->sysExState = eSysExMfgID1; + else + pMIDIStream->sysExState = eSysExIgnore; + break; + + case eSysExMfgID2: + if (c == 0x3a) + pMIDIStream->sysExState = eSysExMfgID1; + else + pMIDIStream->sysExState = eSysExIgnore; + break; + + case eSysExMfgID3: + if (c == 0x04) + pMIDIStream->sysExState = eSysExEnhancer; + else + pMIDIStream->sysExState = eSysExIgnore; + break; + + case eSysExEnhancer: + if (c == 0x01) + pMIDIStream->sysExState = eSysExEnhancerSubID; + else + pMIDIStream->sysExState = eSysExIgnore; + break; + + case eSysExEnhancerSubID: + pMIDIStream->sysExState = eSysExEnhancerFeedback1; + break; + + case eSysExEnhancerFeedback1: + pMIDIStream->sysExState = eSysExEnhancerFeedback2; + break; + + case eSysExEnhancerFeedback2: + pMIDIStream->sysExState = eSysExEnhancerDrive; + break; + + case eSysExEnhancerDrive: + pMIDIStream->sysExState = eSysExEnhancerWet; + break; + + case eSysExEnhancerWet: + pMIDIStream->sysExState = eSysExEOX; + break; + + case eSysExEOX: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Expected F7, received %02x\n", c); */ } + pMIDIStream->sysExState = eSysExIgnore; + break; + + case eSysExIgnore: + break; + + default: + pMIDIStream->sysExState = eSysExIgnore; + break; + } + } + + if (pMIDIStream->sysExState == eSysExIgnore) + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Ignoring SysEx byte %02x\n", c); */ } + return EAS_SUCCESS; +} /* end ProcessSysExMessage */ + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_midi.h b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_midi.h new file mode 100755 index 0000000..10649a0 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_midi.h @@ -0,0 +1,71 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_midi.h + * + * Contents and purpose: + * Prototypes for MIDI stream parsing functions + * + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_MIDI_H +#define _EAS_MIDI_H + +/*---------------------------------------------------------------------------- + * EAS_InitMIDIStream() + *---------------------------------------------------------------------------- + * Purpose: + * Initializes the MIDI stream state for parsing. + * + * Inputs: + * + * Outputs: + * returns EAS_RESULT (EAS_SUCCESS is OK) + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void EAS_InitMIDIStream (S_MIDI_STREAM *pMIDIStream); + +/*---------------------------------------------------------------------------- + * EAS_ParseMIDIStream() + *---------------------------------------------------------------------------- + * Purpose: + * Parses a MIDI input stream character by character. Characters are pushed (rather than pulled) + * so the interface works equally well for both file and stream I/O. + * + * Inputs: + * c - character from MIDI stream + * + * Outputs: + * returns EAS_RESULT (EAS_SUCCESS is OK) + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_ParseMIDIStream (S_EAS_DATA *pEASData, S_SYNTH *pSynth, S_MIDI_STREAM *pMIDIStream, EAS_U8 c, EAS_INT parserMode); + +#endif /* #define _EAS_MIDI_H */ + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_midictrl.h b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_midictrl.h new file mode 100755 index 0000000..46fdc4f --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_midictrl.h @@ -0,0 +1,64 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_midictrl.h + * + * Contents and purpose: + * MIDI controller definitions + * + * This header only contains declarations that are specific + * to this implementation. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_MIDICTRL_H +#define _EAS_MIDICTRL_H + +/* define controller types */ +/* + Note that these controller types are specified in base 10 (decimal) + and not in hexadecimal. The above midi messages are specified + in hexadecimal. +*/ +#define MIDI_CONTROLLER_BANK_SELECT 0 +#define MIDI_CONTROLLER_BANK_SELECT_MSB 0 +#define MIDI_CONTROLLER_MOD_WHEEL 1 +#define MIDI_CONTROLLER_ENTER_DATA_MSB 6 +#define MIDI_CONTROLLER_VOLUME 7 +#define MIDI_CONTROLLER_PAN 10 +#define MIDI_CONTROLLER_EXPRESSION 11 +#define MIDI_CONTROLLER_BANK_SELECT_LSB 32 +#define MIDI_CONTROLLER_ENTER_DATA_LSB 38 /* 0x26 */ +#define MIDI_CONTROLLER_SUSTAIN_PEDAL 64 +#define MIDI_CONTROLLER_SELECT_NRPN_LSB 98 +#define MIDI_CONTROLLER_SELECT_NRPN_MSB 99 +#define MIDI_CONTROLLER_SELECT_RPN_LSB 100 /* 0x64 */ +#define MIDI_CONTROLLER_SELECT_RPN_MSB 101 /* 0x65 */ +#define MIDI_CONTROLLER_ALL_SOUND_OFF 120 +#define MIDI_CONTROLLER_RESET_CONTROLLERS 121 +#define MIDI_CONTROLLER_ALL_NOTES_OFF 123 +#define MIDI_CONTROLLER_OMNI_OFF 124 +#define MIDI_CONTROLLER_OMNI_ON 125 +#define MIDI_CONTROLLER_MONO_ON_POLY_OFF 126 +#define MIDI_CONTROLLER_POLY_ON_MONO_OFF 127 + +#endif /* #ifndef _EAS_MIDICTRL_H */ diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_mididata.c b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_mididata.c new file mode 100755 index 0000000..4463b7e --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_mididata.c @@ -0,0 +1,34 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_mididata.c + * + * Contents and purpose: + * Data module for MIDI stream interface + * + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 547 $ + * $Date: 2007-01-31 16:30:17 -0800 (Wed, 31 Jan 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_miditypes.h" + +S_INTERACTIVE_MIDI eas_MIDIData; + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_miditypes.h b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_miditypes.h new file mode 100755 index 0000000..015f08b --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_miditypes.h @@ -0,0 +1,138 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_miditypes.h + * + * Contents and purpose: + * Contains declarations for the MIDI stream parser. + * + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 778 $ + * $Date: 2007-07-23 16:45:17 -0700 (Mon, 23 Jul 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_MIDITYPES_H +#define _EAS_MIDITYPES_H + +#include "eas_data.h" +#include "eas_parser.h" + +/*---------------------------------------------------------------------------- + * S_MIDI_STREAM + * + * Maintains parser state for the MIDI stream parser + * + *---------------------------------------------------------------------------- +*/ + +typedef struct s_midi_stream_tag +{ + EAS_BOOL8 byte3; /* flag indicates 3rd byte expected */ + EAS_BOOL8 pending; /* flag indicates more data expected */ + EAS_U8 sysExState; /* maintains the SysEx state */ + EAS_U8 runningStatus; /* last running status received */ + EAS_U8 status; /* status byte */ + EAS_U8 d1; /* first data byte */ + EAS_U8 d2; /* second data byte */ + EAS_U8 flags; /* flags - see below for definition */ +#ifdef JET_INTERFACE + EAS_U32 jetData; /* JET data */ +#endif +} S_MIDI_STREAM; + +/* flags for S_MIDI_STREAM.flags */ +#define MIDI_FLAG_GM_ON 0x01 /* GM System On message received */ +#define MIDI_FLAG_FIRST_NOTE 0x02 /* first note received */ + +/* flags for S_MIDI_STREAM.jetFlags */ +#define MIDI_FLAGS_JET_MUTE 0x00000001 /* track is muted */ +#define MIDI_FLAGS_JET_CB 0x00000002 /* JET callback enabled */ + +/*---------------------------------------------------------------------------- + * + * S_SMF_STREAM + * + * This structure contains data required to parse an SMF stream. For SMF0 files, there + * will be a single instance of this per file. For SMF1 files, there will be multiple instance, + * one for each separate stream in the file. + * + *---------------------------------------------------------------------------- +*/ + +typedef struct s_smf_stream_tag +{ + EAS_FILE_HANDLE fileHandle; /* host wrapper file handle */ + EAS_U32 ticks; /* time of next event in stream */ + EAS_I32 startFilePos; /* start location of track within file */ + S_MIDI_STREAM midiStream; /* MIDI stream state */ +} S_SMF_STREAM; + +/*---------------------------------------------------------------------------- + * + * S_SMF_DATA + * + * This structure contains the instance data required to parse an SMF stream. + * + *---------------------------------------------------------------------------- +*/ + +typedef struct s_smf_data_tag +{ +#ifdef _CHECKED_BUILD + EAS_U32 handleCheck; /* signature check for checked build */ +#endif + S_SMF_STREAM *streams; /* pointer to individual streams in file */ + S_SMF_STREAM *nextStream; /* pointer to next stream with event */ + S_SYNTH *pSynth; /* pointer to synth */ + EAS_FILE_HANDLE fileHandle; /* file handle */ + S_METADATA_CB metadata; /* metadata callback */ + EAS_I32 fileOffset; /* for embedded files */ + EAS_I32 time; /* current time in milliseconds/256 */ + EAS_U16 numStreams; /* actual number of streams */ + EAS_U16 tickConv; /* current MIDI tick to msec conversion */ + EAS_U16 ppqn; /* ticks per quarter note */ + EAS_U8 state; /* current state EAS_STATE_XXXX */ + EAS_U8 flags; /* flags - see definitions below */ +} S_SMF_DATA; + +#define SMF_FLAGS_CHASE_MODE 0x01 /* chase mode - skip to first note */ +#define SMF_FLAGS_HAS_TIME_SIG 0x02 /* time signature encountered at time 0 */ +#define SMF_FLAGS_HAS_TEMPO 0x04 /* tempo encountered at time 0 */ +#define SMF_FLAGS_HAS_GM_ON 0x08 /* GM System On encountered at time 0 */ +#define SMF_FLAGS_JET_STREAM 0x80 /* JET in use - keep strict timing */ + +/* combo flags indicate setup bar */ +#define SMF_FLAGS_SETUP_BAR (SMF_FLAGS_HAS_TIME_SIG | SMF_FLAGS_HAS_TEMPO | SMF_FLAGS_HAS_GM_ON) + +/*---------------------------------------------------------------------------- + * Interactive MIDI structure + *---------------------------------------------------------------------------- +*/ +typedef struct s_interactive_midi_tag +{ +#ifdef _CHECKED_BUILD + EAS_U32 handleCheck; /* signature check for checked build */ +#endif + S_SYNTH *pSynth; /* pointer to synth */ + S_MIDI_STREAM stream; /* stream data */ +} S_INTERACTIVE_MIDI; + +#endif /* #ifndef _EAS_MIDITYPES_H */ + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_mixbuf.c b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_mixbuf.c new file mode 100755 index 0000000..db5bd02 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_mixbuf.c @@ -0,0 +1,36 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_mixbuf.c + * + * Contents and purpose: + * Contains a data allocation for synthesizer + * + * Copyright Sonic Network Inc. 2004 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +// includes +#include "eas_data.h" +#include "eas_mixer.h" + +// globals +EAS_I32 eas_MixBuffer[BUFFER_SIZE_IN_MONO_SAMPLES * NUM_OUTPUT_CHANNELS]; + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_mixer.c b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_mixer.c new file mode 100755 index 0000000..0a839a8 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_mixer.c @@ -0,0 +1,464 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_mixer.c + * + * Contents and purpose: + * This file contains the critical components of the mix engine that + * must be optimized for best performance. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 706 $ + * $Date: 2007-05-31 17:22:51 -0700 (Thu, 31 May 2007) $ + *---------------------------------------------------------------------------- +*/ + +//3 dls: This module is in the midst of being converted from a synth +//3 specific module to a general purpose mix engine + +/*------------------------------------ + * includes + *------------------------------------ +*/ +#include "eas_data.h" +#include "eas_host.h" +#include "eas_math.h" +#include "eas_mixer.h" +#include "eas_config.h" +#include "eas_report.h" + +#ifdef _MAXIMIZER_ENABLED +EAS_I32 MaximizerProcess (EAS_VOID_PTR pInstData, EAS_I32 *pSrc, EAS_I32 *pDst, EAS_I32 numSamples); +#endif + +/*------------------------------------ + * defines + *------------------------------------ +*/ + +/* need to boost stereo by ~3dB to compensate for the panner */ +#define STEREO_3DB_GAIN_BOOST 512 + +/*---------------------------------------------------------------------------- + * EAS_MixEngineInit() + *---------------------------------------------------------------------------- + * Purpose: + * Prepares the mix engine for work, allocates buffers, locates effects modules, etc. + * + * Inputs: + * pEASData - instance data + * pInstData - pointer to variable to receive instance data handle + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_MixEngineInit (S_EAS_DATA *pEASData) +{ + + /* check Configuration Module for mix buffer allocation */ + if (pEASData->staticMemoryModel) + pEASData->pMixBuffer = EAS_CMEnumData(EAS_CM_MIX_BUFFER); + else + pEASData->pMixBuffer = EAS_HWMalloc(pEASData->hwInstData, BUFFER_SIZE_IN_MONO_SAMPLES * NUM_OUTPUT_CHANNELS * sizeof(EAS_I32)); + if (pEASData->pMixBuffer == NULL) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Failed to allocate mix buffer memory\n"); */ } + return EAS_ERROR_MALLOC_FAILED; + } + EAS_HWMemSet((void *)(pEASData->pMixBuffer), 0, BUFFER_SIZE_IN_MONO_SAMPLES * NUM_OUTPUT_CHANNELS * sizeof(EAS_I32)); + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_MixEnginePrep() + *---------------------------------------------------------------------------- + * Purpose: + * Performs prep before synthesize a buffer of audio, such as clearing + * audio buffers, etc. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void EAS_MixEnginePrep (S_EAS_DATA *pEASData, EAS_I32 numSamples) +{ + + /* clear the mix buffer */ +#if (NUM_OUTPUT_CHANNELS == 2) + EAS_HWMemSet(pEASData->pMixBuffer, 0, numSamples * (EAS_I32) sizeof(long) * 2); +#else + EAS_HWMemSet(pEASData->pMixBuffer, 0, (EAS_I32) numSamples * (EAS_I32) sizeof(long)); +#endif + + /* need to clear other side-chain effect buffers (chorus & reverb) */ +} + +/*---------------------------------------------------------------------------- + * EAS_MixEnginePost + *---------------------------------------------------------------------------- + * Purpose: + * This routine does the post-processing after all voices have been + * synthesized. It calls any sweeteners and does the final mixdown to + * the output buffer. + * + * Inputs: + * + * Outputs: + * + * Notes: + *---------------------------------------------------------------------------- +*/ +void EAS_MixEnginePost (S_EAS_DATA *pEASData, EAS_I32 numSamples) +{ + EAS_U16 gain; + +//3 dls: Need to restore the mix engine metrics + + /* calculate the gain multiplier */ +#ifdef _MAXIMIZER_ENABLED + if (pEASData->effectsModules[EAS_MODULE_MAXIMIZER].effect) + { + EAS_I32 temp; + temp = MaximizerProcess(pEASData->effectsModules[EAS_MODULE_MAXIMIZER].effectData, pEASData->pMixBuffer, pEASData->pMixBuffer, numSamples); + temp = (temp * pEASData->masterGain) >> 15; + if (temp > 32767) + gain = 32767; + else + gain = (EAS_U16) temp; + } + else + gain = (EAS_U16) pEASData->masterGain; +#else + gain = (EAS_U16) pEASData->masterGain; +#endif + + /* Not using all the gain bits for now + * Reduce the input to the compressor by 6dB to prevent saturation + */ +#ifdef _COMPRESSOR_ENABLED + if (pEASData->effectsModules[EAS_MODULE_COMPRESSOR].effectData) + gain = gain >> 5; + else + gain = gain >> 4; +#else + gain = gain >> 4; +#endif + + /* convert 32-bit mix buffer to 16-bit output format */ +#if (NUM_OUTPUT_CHANNELS == 2) + SynthMasterGain(pEASData->pMixBuffer, pEASData->pOutputAudioBuffer, gain, (EAS_U16) ((EAS_U16) numSamples * 2)); +#else + SynthMasterGain(pEASData->pMixBuffer, pEASData->pOutputAudioBuffer, gain, (EAS_U16) numSamples); +#endif + +#ifdef _ENHANCER_ENABLED + /* enhancer effect */ + if (pEASData->effectsModules[EAS_MODULE_ENHANCER].effectData) + (*pEASData->effectsModules[EAS_MODULE_ENHANCER].effect->pfProcess) + (pEASData->effectsModules[EAS_MODULE_ENHANCER].effectData, + pEASData->pOutputAudioBuffer, + pEASData->pOutputAudioBuffer, + numSamples); +#endif + +#ifdef _GRAPHIC_EQ_ENABLED + /* graphic EQ effect */ + if (pEASData->effectsModules[EAS_MODULE_GRAPHIC_EQ].effectData) + (*pEASData->effectsModules[EAS_MODULE_GRAPHIC_EQ].effect->pfProcess) + (pEASData->effectsModules[EAS_MODULE_GRAPHIC_EQ].effectData, + pEASData->pOutputAudioBuffer, + pEASData->pOutputAudioBuffer, + numSamples); +#endif + +#ifdef _COMPRESSOR_ENABLED + /* compressor effect */ + if (pEASData->effectsModules[EAS_MODULE_COMPRESSOR].effectData) + (*pEASData->effectsModules[EAS_MODULE_COMPRESSOR].effect->pfProcess) + (pEASData->effectsModules[EAS_MODULE_COMPRESSOR].effectData, + pEASData->pOutputAudioBuffer, + pEASData->pOutputAudioBuffer, + numSamples); +#endif + +#ifdef _WOW_ENABLED + /* WOW requires a 32-bit buffer, borrow the mix buffer and + * pass it as the destination buffer + */ + /*lint -e{740} temporarily passing a parameter through an existing I/F */ + if (pEASData->effectsModules[EAS_MODULE_WOW].effectData) + (*pEASData->effectsModules[EAS_MODULE_WOW].effect->pfProcess) + (pEASData->effectsModules[EAS_MODULE_WOW].effectData, + pEASData->pOutputAudioBuffer, + (EAS_PCM*) pEASData->pMixBuffer, + numSamples); +#endif + +#ifdef _TONECONTROLEQ_ENABLED + /* ToneControlEQ effect */ + if (pEASData->effectsModules[EAS_MODULE_TONECONTROLEQ].effectData) + (*pEASData->effectsModules[EAS_MODULE_TONECONTROLEQ].effect->pfProcess) + (pEASData->effectsModules[EAS_MODULE_TONECONTROLEQ].effectData, + pEASData->pOutputAudioBuffer, + pEASData->pOutputAudioBuffer, + numSamples); +#endif + +#ifdef _REVERB_ENABLED + /* Reverb effect */ + if (pEASData->effectsModules[EAS_MODULE_REVERB].effectData) + (*pEASData->effectsModules[EAS_MODULE_REVERB].effect->pfProcess) + (pEASData->effectsModules[EAS_MODULE_REVERB].effectData, + pEASData->pOutputAudioBuffer, + pEASData->pOutputAudioBuffer, + numSamples); +#endif + +#ifdef _CHORUS_ENABLED + /* Chorus effect */ + if (pEASData->effectsModules[EAS_MODULE_CHORUS].effectData) + (*pEASData->effectsModules[EAS_MODULE_CHORUS].effect->pfProcess) + (pEASData->effectsModules[EAS_MODULE_CHORUS].effectData, + pEASData->pOutputAudioBuffer, + pEASData->pOutputAudioBuffer, + numSamples); +#endif + +} + +#ifndef NATIVE_EAS_KERNEL +/*---------------------------------------------------------------------------- + * SynthMasterGain + *---------------------------------------------------------------------------- + * Purpose: + * Mixes down audio from 32-bit to 16-bit target buffer + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +void SynthMasterGain (long *pInputBuffer, EAS_PCM *pOutputBuffer, EAS_U16 nGain, EAS_U16 numSamples) { + + /* loop through the buffer */ + while (numSamples--) { + long s; + + /* read a sample from the input buffer and add some guard bits */ + s = *pInputBuffer++; + + /* add some guard bits */ + /*lint -e{704} */ + s = s >> 7; + + /* apply master gain */ + s *= (long) nGain; + + /* shift to lower 16-bits */ + /*lint -e{704} */ + s = s >> 9; + + /* saturate */ + s = SATURATE(s); + + *pOutputBuffer++ = (EAS_PCM)s; + } +} +#endif + +/*---------------------------------------------------------------------------- + * EAS_MixEngineShutdown() + *---------------------------------------------------------------------------- + * Purpose: + * Shuts down effects modules and deallocates memory + * + * Inputs: + * pEASData - instance data + * pInstData - instance data handle + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_MixEngineShutdown (S_EAS_DATA *pEASData) +{ + + /* check Configuration Module for static memory allocation */ + if (!pEASData->staticMemoryModel && (pEASData->pMixBuffer != NULL)) + EAS_HWFree(pEASData->hwInstData, pEASData->pMixBuffer); + + return EAS_SUCCESS; +} + +#ifdef UNIFIED_MIXER +#ifndef NATIVE_MIX_STREAM +/*---------------------------------------------------------------------------- + * EAS_MixStream + *---------------------------------------------------------------------------- + * Mix a 16-bit stream into a 32-bit buffer + * + * pInputBuffer 16-bit input buffer + * pMixBuffer 32-bit mix buffer + * numSamples number of samples to mix + * gainLeft initial gain left or mono + * gainRight initial gain right + * gainLeft left gain increment per sample + * gainRight right gain increment per sample + * flags bit 0 = stereo source + * bit 1 = stereo output + *---------------------------------------------------------------------------- +*/ +void EAS_MixStream (EAS_PCM *pInputBuffer, EAS_I32 *pMixBuffer, EAS_I32 numSamples, EAS_I32 gainLeft, EAS_I32 gainRight, EAS_I32 gainIncLeft, EAS_I32 gainIncRight, EAS_I32 flags) +{ + EAS_I32 temp; + EAS_INT src, dest; + + /* NOTE: There are a lot of optimizations that can be done + * in the native implementations based on register + * availability, etc. For example, it may make sense to + * break this down into 8 separate routines: + * + * 1. Mono source to mono output + * 2. Mono source to stereo output + * 3. Stereo source to mono output + * 4. Stereo source to stereo output + * 5. Mono source to mono output - no gain change + * 6. Mono source to stereo output - no gain change + * 7. Stereo source to mono output - no gain change + * 8. Stereo source to stereo output - no gain change + * + * Other possibilities include loop unrolling, skipping + * a gain calculation every 2 or 4 samples, etc. + */ + + /* no gain change, use fast loops */ + if ((gainIncLeft == 0) && (gainIncRight == 0)) + { + switch (flags & (MIX_FLAGS_STEREO_SOURCE | MIX_FLAGS_STEREO_OUTPUT)) + { + /* mono to mono */ + case 0: + gainLeft >>= 15; + for (src = dest = 0; src < numSamples; src++, dest++) + { + + pMixBuffer[dest] += (pInputBuffer[src] * gainLeft) >> NUM_MIXER_GUARD_BITS; + } + break; + + /* mono to stereo */ + case MIX_FLAGS_STEREO_OUTPUT: + gainLeft >>= 15; + gainRight >>= 15; + for (src = dest = 0; src < numSamples; src++, dest+=2) + { + pMixBuffer[dest] += (pInputBuffer[src] * gainLeft) >> NUM_MIXER_GUARD_BITS; + pMixBuffer[dest+1] += (pInputBuffer[src] * gainRight) >> NUM_MIXER_GUARD_BITS; + } + break; + + /* stereo to mono */ + case MIX_FLAGS_STEREO_SOURCE: + gainLeft >>= 15; + gainRight >>= 15; + for (src = dest = 0; src < numSamples; src+=2, dest++) + { + temp = (pInputBuffer[src] * gainLeft) >> NUM_MIXER_GUARD_BITS; + temp += ((pInputBuffer[src+1] * gainRight) >> NUM_MIXER_GUARD_BITS); + pMixBuffer[dest] += temp; + } + break; + + /* stereo to stereo */ + case MIX_FLAGS_STEREO_SOURCE | MIX_FLAGS_STEREO_OUTPUT: + gainLeft >>= 15; + gainRight >>= 15; + for (src = dest = 0; src < numSamples; src+=2, dest+=2) + { + pMixBuffer[dest] += (pInputBuffer[src] * gainLeft) >> NUM_MIXER_GUARD_BITS; + pMixBuffer[dest+1] += (pInputBuffer[src+1] * gainRight) >> NUM_MIXER_GUARD_BITS; + } + break; + } + } + + /* gain change - do gain increment */ + else + { + switch (flags & (MIX_FLAGS_STEREO_SOURCE | MIX_FLAGS_STEREO_OUTPUT)) + { + /* mono to mono */ + case 0: + for (src = dest = 0; src < numSamples; src++, dest++) + { + gainLeft += gainIncLeft; + pMixBuffer[dest] += (pInputBuffer[src] * (gainLeft >> 15)) >> NUM_MIXER_GUARD_BITS; + } + break; + + /* mono to stereo */ + case MIX_FLAGS_STEREO_OUTPUT: + for (src = dest = 0; src < numSamples; src++, dest+=2) + { + gainLeft += gainIncLeft; + gainRight += gainIncRight; + pMixBuffer[dest] += (pInputBuffer[src] * (gainLeft >> 15)) >> NUM_MIXER_GUARD_BITS; + pMixBuffer[dest+1] += (pInputBuffer[src] * (gainRight >> 15)) >> NUM_MIXER_GUARD_BITS; + } + break; + + /* stereo to mono */ + case MIX_FLAGS_STEREO_SOURCE: + for (src = dest = 0; src < numSamples; src+=2, dest++) + { + gainLeft += gainIncLeft; + gainRight += gainIncRight; + temp = (pInputBuffer[src] * (gainLeft >> 15)) >> NUM_MIXER_GUARD_BITS; + temp += ((pInputBuffer[src+1] * (gainRight >> 15)) >> NUM_MIXER_GUARD_BITS); + pMixBuffer[dest] += temp; + } + break; + + /* stereo to stereo */ + case MIX_FLAGS_STEREO_SOURCE | MIX_FLAGS_STEREO_OUTPUT: + for (src = dest = 0; src < numSamples; src+=2, dest+=2) + { + gainLeft += gainIncLeft; + gainRight += gainIncRight; + pMixBuffer[dest] += (pInputBuffer[src] * (gainLeft >> 15)) >> NUM_MIXER_GUARD_BITS; + pMixBuffer[dest+1] += (pInputBuffer[src+1] * (gainRight >> 15)) >> NUM_MIXER_GUARD_BITS; + } + break; + } + } +} +#endif +#endif + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_mixer.h b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_mixer.h new file mode 100755 index 0000000..b2eb33b --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_mixer.h @@ -0,0 +1,137 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_mixer.h + * + * Contents and purpose: + * This file contains the critical components of the mix engine that + * must be optimized for best performance. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 706 $ + * $Date: 2007-05-31 17:22:51 -0700 (Thu, 31 May 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_MIXER_H +#define _EAS_MIXER_H + +//3 dls: This module is in the midst of being converted from a synth +//3 specific module to a general purpose mix engine + +#define MIX_FLAGS_STEREO_SOURCE 1 +#define MIX_FLAGS_STEREO_OUTPUT 2 +#define NUM_MIXER_GUARD_BITS 4 + +#include "eas_effects.h" + +extern void SynthMasterGain( long *pInputBuffer, EAS_PCM *pOutputBuffer, EAS_U16 nGain, EAS_U16 nNumLoopSamples); + +/*---------------------------------------------------------------------------- + * EAS_MixEngineInit() + *---------------------------------------------------------------------------- + * Purpose: + * Prepares the mix engine for work, allocates buffers, locates effects modules, etc. + * + * Inputs: + * pEASData - instance data + * pInstData - pointer to variable to receive instance data handle + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_MixEngineInit (EAS_DATA_HANDLE pEASData); + +/*---------------------------------------------------------------------------- + * EAS_MixEnginePrep() + *---------------------------------------------------------------------------- + * Purpose: + * Performs prep before synthesize a buffer of audio, such as clearing + * audio buffers, etc. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void EAS_MixEnginePrep (EAS_DATA_HANDLE pEASData, EAS_I32 nNumSamplesToAdd); + +/*---------------------------------------------------------------------------- + * EAS_MixEnginePost + *---------------------------------------------------------------------------- + * Purpose: + * This routine does the post-processing after all voices have been + * synthesized. It calls any sweeteners and does the final mixdown to + * the output buffer. + * + * Inputs: + * + * Outputs: + * + * Notes: + *---------------------------------------------------------------------------- +*/ +void EAS_MixEnginePost (EAS_DATA_HANDLE pEASData, EAS_I32 nNumSamplesToAdd); + +/*---------------------------------------------------------------------------- + * EAS_MixEngineShutdown() + *---------------------------------------------------------------------------- + * Purpose: + * Shuts down effects modules and deallocates memory + * + * Inputs: + * pEASData - instance data + * pInstData - instance data handle + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_MixEngineShutdown (EAS_DATA_HANDLE pEASData); + +#ifdef UNIFIED_MIXER +/*---------------------------------------------------------------------------- + * EAS_MixStream + *---------------------------------------------------------------------------- + * Mix a 16-bit stream into a 32-bit buffer + * + * pInputBuffer 16-bit input buffer + * pMixBuffer 32-bit mix buffer + * numSamples number of samples to mix + * gainLeft initial gain left or mono + * gainRight initial gain right + * gainLeft left gain increment per sample + * gainRight right gain increment per sample + * flags bit 0 = stereo source + * bit 1 = stereo output + *---------------------------------------------------------------------------- +*/ +void EAS_MixStream (EAS_PCM *pInputBuffer, EAS_I32 *pMixBuffer, EAS_I32 numSamples, EAS_I32 gainLeft, EAS_I32 gainRight, EAS_I32 gainIncLeft, EAS_I32 gainIncRight, EAS_I32 flags); +#endif + +#endif /* #ifndef _EAS_MIXER_H */ + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_ota.c b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_ota.c new file mode 100755 index 0000000..5bc9062 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_ota.c @@ -0,0 +1,1077 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_ota.c + * + * Contents and purpose: + * OTA parser + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 795 $ + * $Date: 2007-08-01 00:14:45 -0700 (Wed, 01 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_data.h" +#include "eas_miditypes.h" +#include "eas_parser.h" +#include "eas_report.h" +#include "eas_host.h" +#include "eas_midi.h" +#include "eas_config.h" +#include "eas_vm_protos.h" +#include "eas_otadata.h" + +/* increase gain for mono ringtones */ +#define OTA_GAIN_OFFSET 8 + +/* file definitions */ +#define OTA_RINGTONE 0x25 +#define OTA_SOUND 0x1d +#define OTA_UNICODE 0x22 + +/* song type definitions */ +#define OTA_BASIC_SONG_TYPE 0x01 +#define OTA_TEMPORARY_SONG_TYPE 0x02 + +/* instruction ID coding */ +#define OTA_PATTERN_HEADER_ID 0x00 +#define OTA_NOTE_INST_ID 0x01 +#define OTA_SCALE_INST_ID 0x02 +#define OTA_STYLE_INST_ID 0x03 +#define OTA_TEMPO_INST_ID 0x04 +#define OTA_VOLUME_INST_ID 0x05 + +/* note durations */ +#define OTA_NORMAL_DURATION 0x00 +#define OTA_DOTTED_NOTE 0x01 +#define OTA_DOUBLE_DOTTED_NOTE 0x02 +#define OTA_TRIPLET_NOTE 0x03 + +/* loop count value for infinite loop */ +#define OTA_INFINITE_LOOP 0x0f + +/* length of 32nd note in 1/256ths of a msec for 63 BPM tempo */ +#define DEFAULT_TICK_CONV 30476 + +/* default channel and program for OTA playback */ +#define OTA_CHANNEL 0 +#define OTA_PROGRAM 80 +#define OTA_VEL_MUL 4 +#define OTA_VEL_OFS 67 +#define OTA_VEL_DEFAULT 95 + +/* multiplier for fixed point triplet conversion */ +#define TRIPLET_MULTIPLIER 683 +#define TRIPLET_SHIFT 10 + +/* local prototypes */ +static EAS_RESULT OTA_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset); +static EAS_RESULT OTA_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT OTA_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime); +static EAS_RESULT OTA_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode); +static EAS_RESULT OTA_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_STATE *pState); +static EAS_RESULT OTA_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT OTA_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT OTA_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT OTA_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT OTA_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value); +static EAS_RESULT OTA_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue); +static EAS_RESULT OTA_ParseHeader (S_EAS_DATA *pEASData, S_OTA_DATA* pData); +static EAS_RESULT OTA_FetchBitField (EAS_HW_DATA_HANDLE hwInstData, S_OTA_DATA *pData, EAS_I32 numBits, EAS_U8 *pValue); +static EAS_RESULT OTA_SavePosition (EAS_HW_DATA_HANDLE hwInstData, S_OTA_DATA *pData, S_OTA_LOC *pLoc); +static EAS_RESULT OTA_RestorePosition (EAS_HW_DATA_HANDLE hwInstData, S_OTA_DATA *pData, S_OTA_LOC *pLoc); + + +/*---------------------------------------------------------------------------- + * + * EAS_OTA_Parser + * + * This structure contains the functional interface for the OTA parser + *---------------------------------------------------------------------------- +*/ +const S_FILE_PARSER_INTERFACE EAS_OTA_Parser = +{ + OTA_CheckFileType, + OTA_Prepare, + OTA_Time, + OTA_Event, + OTA_State, + OTA_Close, + OTA_Reset, + OTA_Pause, + OTA_Resume, + NULL, + OTA_SetData, + OTA_GetData, + NULL +}; + +/*---------------------------------------------------------------------------- + * + * bpmTable + * + * BPM conversion table. Converts bpm values to 256ths of a millisecond for a 32nd note + *---------------------------------------------------------------------------- +*/ +static const EAS_U32 bpmTable[32] = +{ + 76800, 68571, 61935, 54857, + 48000, 42667, 38400, 34286, + 30476, 27429, 24000, 21333, + 19200, 17143, 15360, 13714, + 12000, 10667, 9600, 8533, + 7680, 6737, 6000, 5408, + 4800, 4267, 3840, 3398, + 3024, 2685, 2400, 2133 +}; + +/*---------------------------------------------------------------------------- + * OTA_CheckFileType() + *---------------------------------------------------------------------------- + * Purpose: + * Check the file type to see if we can parse it + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT OTA_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset) +{ + S_OTA_DATA* pData; + EAS_RESULT result; + EAS_INT cmdLen; + EAS_INT state; + EAS_U8 temp; + + /* read the first byte, should be command length */ + *ppHandle = NULL; + if ((result = EAS_HWGetByte(pEASData->hwInstData, fileHandle, &temp)) != EAS_SUCCESS) + return result; + + /* read all the commands */ + cmdLen = temp; + state = 0; + while (cmdLen--) + { + + /* read the command, upper 7 bits */ + if ((result = EAS_HWGetByte(pEASData->hwInstData, fileHandle, &temp)) != EAS_SUCCESS) + return result; + temp = temp >> 1; + + if (state == 0) + { + if (temp != OTA_RINGTONE) + break; + state++; + } + else + { + + if (temp == OTA_SOUND) + { + + /* check for static memory allocation */ + if (pEASData->staticMemoryModel) + pData = EAS_CMEnumData(EAS_CM_OTA_DATA); + else + pData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_OTA_DATA)); + if (!pData) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Malloc failed in OTA_Prepare\n"); */ } + return EAS_ERROR_MALLOC_FAILED; + } + EAS_HWMemSet(pData, 0, sizeof(S_OTA_DATA)); + + /* return a pointer to the instance data */ + pData->fileHandle = fileHandle; + pData->fileOffset = offset; + pData->state = EAS_STATE_OPEN; + *ppHandle = pData; + break; + } + + if (temp != OTA_UNICODE) + break; + } + } + + /* not recognized */ + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_Prepare() + *---------------------------------------------------------------------------- + * Purpose: + * Prepare to parse the file. Allocates instance data (or uses static allocation for + * static memory model). + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT OTA_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_OTA_DATA* pData; + EAS_RESULT result; + + /* check for valid state */ + pData = (S_OTA_DATA*) pInstData; + if (pData->state != EAS_STATE_OPEN) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + /* instantiate a synthesizer */ + if ((result = VMInitMIDI(pEASData, &pData->pSynth)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitMIDI returned %d\n", result); */ } + return result; + } + + pData->state = EAS_STATE_ERROR; + if ((result = OTA_ParseHeader(pEASData, pData)) != EAS_SUCCESS) + return result; + + pData->state = EAS_STATE_READY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_Time() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the time of the next event in msecs + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * pTime - pointer to variable to hold time of next event (in msecs) + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ +static EAS_RESULT OTA_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime) +{ + S_OTA_DATA *pData; + + pData = (S_OTA_DATA*) pInstData; + + /* return time in milliseconds */ + /*lint -e{704} use shift instead of division */ + *pTime = pData->time >> 8; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_Event() + *---------------------------------------------------------------------------- + * Purpose: + * Parse the next event in the file + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT OTA_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode) +{ + S_OTA_DATA* pData; + EAS_RESULT result; + EAS_U32 duration; + EAS_U8 temp; + + pData = (S_OTA_DATA*) pInstData; + if (pData->state >= EAS_STATE_OPEN) + return EAS_SUCCESS; + + /* initialize MIDI channel when the track starts playing */ + if (pData->time == 0) + { + /* set program to square lead */ + if (parserMode != eParserModeMetaData) + VMProgramChange(pEASData->pVoiceMgr, pData->pSynth, OTA_CHANNEL, OTA_PROGRAM); + + /* set channel volume to max */ + if (parserMode != eParserModeMetaData) + VMControlChange(pEASData->pVoiceMgr, pData->pSynth, OTA_CHANNEL, 7, 127); + } + + /* check for end of note */ + if (pData->note) + { + /* stop the note */ + VMStopNote(pEASData->pVoiceMgr, pData->pSynth, OTA_CHANNEL, pData->note, 0); + pData->note = 0; + + /* check for rest between notes */ + if (pData->restTicks) + { + pData->time += (EAS_I32) pData->restTicks; + pData->restTicks = 0; + return EAS_SUCCESS; + } + } + + /* if not in a pattern, read the pattern header */ + while (pData->current.patternLen == 0) + { + + /* check for loop - don't do infinite loops when locating */ + if (pData->loopCount && ((parserMode == eParserModePlay) || (pData->loopCount != OTA_INFINITE_LOOP))) + { + /* if not infinite loop, decrement loop count */ + if (pData->loopCount != OTA_INFINITE_LOOP) + pData->loopCount--; + + /* back to start of pattern*/ + if ((result = OTA_RestorePosition(pEASData->hwInstData, pData, &pData->patterns[pData->currentPattern])) != EAS_SUCCESS) + return result; + } + + /* if no previous position to restore, continue forward */ + else if (pData->restore.fileOffset < 0) + { + + /* check for end of song */ + if (pData->numPatterns == 0) + { + pData->state = EAS_STATE_STOPPING; + VMReleaseAllVoices(pEASData->pVoiceMgr, pData->pSynth); + return EAS_SUCCESS; + } + + /* read the next pattern header */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 3, &temp)) != EAS_SUCCESS) + return result; + if (temp != OTA_PATTERN_HEADER_ID) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Expected OTA pattern header\n"); */ } + return EAS_ERROR_FILE_FORMAT; + } + + /* get the pattern ID */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 2, &pData->currentPattern)) != EAS_SUCCESS) + return result; + + /* get the loop count */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 4, &pData->loopCount)) != EAS_SUCCESS) + return result; + + /* get the pattern length */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 8, &pData->current.patternLen)) != EAS_SUCCESS) + return result; + + /* if pattern definition, save the current position */ + if (pData->current.patternLen) + { + if ((result = OTA_SavePosition(pEASData->hwInstData, pData, &pData->patterns[pData->currentPattern])) != EAS_SUCCESS) + return result; + } + + /* if pattern length is zero, repeat a previous pattern */ + else + { + /* make sure it's a valid pattern */ + if (pData->patterns[pData->currentPattern].fileOffset < 0) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "OTA pattern error, invalid pattern specified\n"); */ } + return EAS_ERROR_FILE_FORMAT; + } + + /* save current position and data */ + if ((result = OTA_SavePosition(pEASData->hwInstData, pData, &pData->restore)) != EAS_SUCCESS) + return result; + + /* seek to the pattern in the file */ + if ((result = OTA_RestorePosition(pEASData->hwInstData, pData, &pData->patterns[pData->currentPattern])) != EAS_SUCCESS) + return result; + } + + /* decrement pattern count */ + pData->numPatterns--; + } + + /* restore previous position */ + else + { + if ((result = OTA_RestorePosition(pEASData->hwInstData, pData, &pData->restore)) != EAS_SUCCESS) + return result; + } + } + + /* get the next event */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 3, &temp)) != EAS_SUCCESS) + return result; + + switch (temp) + { + case OTA_NOTE_INST_ID: + /* fetch note value */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 4, &pData->note)) != EAS_SUCCESS) + return result; + + /* fetch note duration */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 3, &temp)) != EAS_SUCCESS) + return result; + duration = pData->tick * (0x20 >> temp); + + /* fetch note duration modifier */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 2, &temp)) != EAS_SUCCESS) + return result; + switch (temp) + { + case OTA_NORMAL_DURATION: + break; + + case OTA_DOTTED_NOTE: + duration += duration >> 1; + break; + + case OTA_DOUBLE_DOTTED_NOTE: + duration += (duration >> 1) + (duration >> 2); + break; + + case OTA_TRIPLET_NOTE: + duration = (duration * TRIPLET_MULTIPLIER) >> TRIPLET_SHIFT; + break; + + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Unrecognized note duration ignored\n"); */ } + break; + } + + /* check for note */ + if (pData->note) + { + + /* determine note length based on style */ + switch (pData->style) + { + case 0: + pData->restTicks = duration >> 4; + break; + case 1: + pData->restTicks = 0; + break; + case 2: + pData->restTicks = duration >> 1; + break; + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Unrecognized note style ignored\n"); */ } + } + + /* add octave */ + pData->note += pData->octave; + if (parserMode == eParserModePlay) + VMStartNote(pEASData->pVoiceMgr, pData->pSynth, OTA_CHANNEL, pData->note, pData->velocity); + pData->time += (EAS_I32) duration - (EAS_I32) pData->restTicks; + } + + /* this is a rest */ + else + pData->time += (EAS_I32) duration; + break; + + case OTA_SCALE_INST_ID: + /* fetch octave */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 2, &temp)) != EAS_SUCCESS) + return result; + pData->octave = (EAS_U8) (temp * 12 + 59); + break; + + case OTA_STYLE_INST_ID: + /* fetch note style */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 2, &pData->style)) != EAS_SUCCESS) + return result; + break; + + case OTA_TEMPO_INST_ID: + /* fetch tempo */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 5, &temp)) != EAS_SUCCESS) + return result; + pData->tick = bpmTable[temp]; + break; + + case OTA_VOLUME_INST_ID: + /* fetch volume */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 4, &temp)) != EAS_SUCCESS) + return result; + pData->velocity = temp ? (EAS_U8) (temp * OTA_VEL_MUL + OTA_VEL_OFS) : 0; + break; + + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Unexpected instruction ID in OTA stream\n"); */ } + return EAS_ERROR_FILE_FORMAT; + } + + /* decrement pattern length */ + pData->current.patternLen--; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_State() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current state of the stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * pState - pointer to variable to store state + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ +static EAS_RESULT OTA_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pState) +{ + S_OTA_DATA* pData; + + /* establish pointer to instance data */ + pData = (S_OTA_DATA*) pInstData; + + /* if stopping, check to see if synth voices are active */ + if (pData->state == EAS_STATE_STOPPING) + { + if (VMActiveVoices(pData->pSynth) == 0) + pData->state = EAS_STATE_STOPPED; + } + + if (pData->state == EAS_STATE_PAUSING) + { + if (VMActiveVoices(pData->pSynth) == 0) + pData->state = EAS_STATE_PAUSED; + } + + /* return current state */ + *pState = pData->state; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_Close() + *---------------------------------------------------------------------------- + * Purpose: + * Close the file and clean up + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT OTA_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_OTA_DATA* pData; + EAS_RESULT result; + + pData = (S_OTA_DATA*) pInstData; + + /* close the file */ + if ((result = EAS_HWCloseFile(pEASData->hwInstData, pData->fileHandle)) != EAS_SUCCESS) + return result; + + /* free the synth */ + if (pData->pSynth != NULL) + VMMIDIShutdown(pEASData, pData->pSynth); + + /* if using dynamic memory, free it */ + if (!pEASData->staticMemoryModel) + EAS_HWFree(pEASData->hwInstData, pData); + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_Reset() + *---------------------------------------------------------------------------- + * Purpose: + * Reset the sequencer. Used for locating backwards in the file. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT OTA_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_OTA_DATA* pData; + EAS_RESULT result; + + pData = (S_OTA_DATA*) pInstData; + + /* reset the synth */ + VMReset(pEASData->pVoiceMgr, pData->pSynth, EAS_TRUE); + pData->note = 0; + + /* reset file position and re-parse header */ + pData->state = EAS_STATE_ERROR; + if ((result = OTA_ParseHeader (pEASData, pData)) != EAS_SUCCESS) + return result; + + pData->state = EAS_STATE_READY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_Pause() + *---------------------------------------------------------------------------- + * Purpose: + * Pauses the sequencer. Mutes all voices and sets state to pause. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT OTA_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_OTA_DATA *pData; + + /* can't pause a stopped stream */ + pData = (S_OTA_DATA*) pInstData; + if (pData->state == EAS_STATE_STOPPED) + return EAS_ERROR_ALREADY_STOPPED; + + /* mute the synthesizer */ + VMMuteAllVoices(pEASData->pVoiceMgr, pData->pSynth); + pData->state = EAS_STATE_PAUSING; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_Resume() + *---------------------------------------------------------------------------- + * Purpose: + * Resume playing after a pause, sets state back to playing. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ +static EAS_RESULT OTA_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_OTA_DATA *pData; + + /* can't resume a stopped stream */ + pData = (S_OTA_DATA*) pInstData; + if (pData->state == EAS_STATE_STOPPED) + return EAS_ERROR_ALREADY_STOPPED; + + /* nothing to do but resume playback */ + pData->state = EAS_STATE_PLAY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_SetData() + *---------------------------------------------------------------------------- + * Purpose: + * Return file type + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ +static EAS_RESULT OTA_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value) +{ + S_OTA_DATA *pData; + + pData = (S_OTA_DATA *) pInstData; + switch (param) + { + + /* set metadata callback */ + case PARSER_DATA_METADATA_CB: + EAS_HWMemCpy(&pData->metadata, (void*) value, sizeof(S_METADATA_CB)); + break; + + default: + return EAS_ERROR_INVALID_PARAMETER; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_GetData() + *---------------------------------------------------------------------------- + * Purpose: + * Return file type + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ +static EAS_RESULT OTA_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue) +{ + S_OTA_DATA *pData; + + pData = (S_OTA_DATA*) pInstData; + switch (param) + { + /* return file type as OTA */ + case PARSER_DATA_FILE_TYPE: + *pValue = EAS_FILE_OTA; + break; + +#if 0 + /* set transposition */ + case PARSER_DATA_TRANSPOSITION: + *pValue = pData->transposition; + break; +#endif + + case PARSER_DATA_SYNTH_HANDLE: + *pValue = (EAS_I32) pData->pSynth; + break; + + case PARSER_DATA_GAIN_OFFSET: + *pValue = OTA_GAIN_OFFSET; + break; + + default: + return EAS_ERROR_INVALID_PARAMETER; + } + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_ParseHeader() + *---------------------------------------------------------------------------- + * Purpose: + * Prepare to parse the file. Allocates instance data (or uses static allocation for + * static memory model). + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT OTA_ParseHeader (S_EAS_DATA *pEASData, S_OTA_DATA* pData) +{ + EAS_RESULT result; + EAS_INT i; + EAS_INT state; + EAS_U8 temp; + EAS_U8 titleLen; + + /* initialize some data */ + pData->flags = 0; + pData->time = 0; + pData->tick = DEFAULT_TICK_CONV; + pData->patterns[0].fileOffset = pData->patterns[1].fileOffset = + pData->patterns[2].fileOffset = pData->patterns[3].fileOffset = -1; + pData->current.bitCount = 0; + pData->current.patternLen = 0; + pData->loopCount = 0; + pData->restore.fileOffset = -1; + pData->note = 0; + pData->restTicks = 0; + pData->velocity = OTA_VEL_DEFAULT; + pData->style = 0; + pData->octave = 59; + + /* seek to start of data */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pData->fileHandle, pData->fileOffset)) != EAS_SUCCESS) + return result; + + /* read the first byte, should be command length */ + if ((result = EAS_HWGetByte(pEASData->hwInstData, pData->fileHandle, &temp)) != EAS_SUCCESS) + return result; + + /* read all the commands */ + i = temp; + state = 0; + while (i--) + { + + /* fetch command, always starts on byte boundary */ + pData->current.bitCount = 0; + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 7, &temp)) != EAS_SUCCESS) + return result; + + if (state == 0) + { + if (temp != OTA_RINGTONE) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Expected OTA Ring Tone Programming type\n"); */ } + return EAS_ERROR_FILE_FORMAT; + } + state++; + } + else + { + + if (temp == OTA_SOUND) + break; + + if (temp == OTA_UNICODE) + pData->flags |= OTA_FLAGS_UNICODE; + else + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Expected OTA Sound or Unicode type\n"); */ } + return EAS_ERROR_FILE_FORMAT; + } + } + } + + /* get song type */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 3, &temp)) != EAS_SUCCESS) + return result; + + /* check for basic song type */ + if (temp == OTA_BASIC_SONG_TYPE) + { + /* fetch title length */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 4, &titleLen)) != EAS_SUCCESS) + return result; + + /* if unicode, double the length */ + if (pData->flags & OTA_FLAGS_UNICODE) + titleLen = (EAS_U8) (titleLen << 1); + + /* zero the metadata buffer */ + if (pData->metadata.buffer) + EAS_HWMemSet(pData->metadata.buffer, 0, pData->metadata.bufferSize); + + /* read the song title */ + for (i = 0; i < titleLen; i++) + { + /* fetch character */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 8, &temp)) != EAS_SUCCESS) + return result; + + /* check for metadata callback */ + if (pData->metadata.callback) + { + if (i < (pData->metadata.bufferSize - 1)) + pData->metadata.buffer[i] = (char) temp; + } + } + + /* if host has registered callback, call it now */ + if (pData->metadata.callback) + (*pData->metadata.callback)(EAS_METADATA_TITLE, pData->metadata.buffer, pData->metadata.pUserData); + } + + /* must be temporary song */ + else if (temp != OTA_TEMPORARY_SONG_TYPE) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Expected OTA basic or temporary song type\n"); */ } + return EAS_ERROR_FILE_FORMAT; + } + + /* get the song length */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 8, &pData->numPatterns)) != EAS_SUCCESS) + return result; + + /* sanity check */ + if (pData->numPatterns == 0) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "OTA number of patterns is zero\n"); */ } + return EAS_ERROR_FILE_FORMAT; + } + + /* at start of first pattern */ + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_FetchBitField() + *---------------------------------------------------------------------------- + * Purpose: + * Fetch a specified number of bits from the input stream + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT OTA_FetchBitField (EAS_HW_DATA_HANDLE hwInstData, S_OTA_DATA *pData, EAS_I32 numBits, EAS_U8 *pValue) +{ + EAS_RESULT result; + EAS_I32 bitsLeft; + EAS_U8 value; + + value = 0; + + /* do we have enough bits? */ + bitsLeft = pData->current.bitCount - numBits; + + /* not enough bits, assemble them from 2 characters */ + if (bitsLeft < 0) + { + /* grab the remaining bits from the previous byte */ + if (pData->current.bitCount) + /*lint -e{504,734} this is a legitimate shift operation */ + value = pData->current.dataByte << -bitsLeft; + + /* read the next byte */ + if ((result = EAS_HWGetByte(hwInstData, pData->fileHandle, &pData->current.dataByte)) != EAS_SUCCESS) + return result; + bitsLeft += 8; + } + + /* more bits than needed? */ + if (bitsLeft > 0) + { + value |= pData->current.dataByte >> bitsLeft; + pData->current.bitCount = (EAS_U8) bitsLeft; + pData->current.dataByte = pData->current.dataByte & (0xff >> (8 - bitsLeft)); + } + + /* exactly the right number of bits */ + else + { + value |= pData->current.dataByte; + pData->current.bitCount = 0; + } + + *pValue = value; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_SavePosition() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT OTA_SavePosition (EAS_HW_DATA_HANDLE hwInstData, S_OTA_DATA *pData, S_OTA_LOC *pLoc) +{ + EAS_HWMemCpy(pLoc, &pData->current, sizeof(S_OTA_LOC)); + return EAS_HWFilePos(hwInstData, pData->fileHandle, &pLoc->fileOffset); +} + +/*---------------------------------------------------------------------------- + * OTA_RestorePosition() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT OTA_RestorePosition (EAS_HW_DATA_HANDLE hwInstData, S_OTA_DATA *pData, S_OTA_LOC *pLoc) +{ + EAS_HWMemCpy(&pData->current, pLoc, sizeof(S_OTA_LOC)); + pData->restore.fileOffset = -1; + return EAS_HWFileSeek(hwInstData, pData->fileHandle, pLoc->fileOffset); +} + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_otadata.c b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_otadata.c new file mode 100755 index 0000000..7463a0c --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_otadata.c @@ -0,0 +1,41 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_otadata..c + * + * Contents and purpose: + * OTA Stream Parser data module for static memory model + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 547 $ + * $Date: 2007-01-31 16:30:17 -0800 (Wed, 31 Jan 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_types.h" +#include "eas_otadata.h" + +/*---------------------------------------------------------------------------- + * + * eas_OTAData + * + * Static memory allocation for OTA parser + *---------------------------------------------------------------------------- +*/ +S_OTA_DATA eas_OTAData; + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_otadata.h b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_otadata.h new file mode 100755 index 0000000..c06e3d3 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_otadata.h @@ -0,0 +1,81 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_otadata.h + * + * Contents and purpose: + * OTA File Parser + * + * This file contains data declarations for the OTA parser. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef EAS_OTADATA_H +#define EAS_OTADATA_H + +#include "eas_data.h" + +/* definition for state flags */ +#define OTA_FLAGS_UNICODE 0x01 /* unicode text */ + +/*---------------------------------------------------------------------------- + * + * S_OTA_DATA + * + * This structure contains the state data for the OTA parser + *---------------------------------------------------------------------------- +*/ + +typedef struct +{ + EAS_I32 fileOffset; /* offset to location in file */ + EAS_U8 patternLen; /* length of current pattern */ + EAS_U8 dataByte; /* previous char from file */ + EAS_U8 bitCount; /* bit count in char */ +} S_OTA_LOC; + +typedef struct +{ + EAS_FILE_HANDLE fileHandle; /* file handle */ + S_SYNTH *pSynth; /* synth handle */ + EAS_I32 fileOffset; /* offset to start of data */ + EAS_I32 time; /* current time in 256ths of a msec */ + EAS_U32 tick; /* length of 32nd note in 256th of a msec */ + EAS_U32 restTicks; /* ticks to rest after current note */ + S_OTA_LOC patterns[4]; /* pattern locations */ + S_OTA_LOC current; /* current location */ + S_OTA_LOC restore; /* previous location */ + S_METADATA_CB metadata; /* metadata callback */ + EAS_U8 flags; /* bit flags */ + EAS_U8 numPatterns; /* number of patterns left in song */ + EAS_U8 currentPattern; /* current pattern for loop */ + EAS_U8 note; /* MIDI note number */ + EAS_U8 octave; /* octave modifier */ + EAS_U8 style; /* from STYLE */ + EAS_U8 velocity; /* current volume */ + EAS_U8 state; /* current state EAS_STATE_XXXX */ + EAS_U8 loopCount; /* loop count for pattern */ +} S_OTA_DATA; + +#endif + + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_pan.c b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_pan.c new file mode 100755 index 0000000..ae4c69d --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_pan.c @@ -0,0 +1,98 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_pan.c + * + * Contents and purpose: + * Calculates left and right gain multipliers based on a pan value from -63 to +63 + * + * NOTES: + * The _CMX_PARSER and _MFI_PARSER preprocessor symbols determine + * whether the parser works for those particular file formats. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_pan.h" +#include "eas_math.h" + +/*---------------------------------------------------------------------------- + * EAS_CalcPanControl() + *---------------------------------------------------------------------------- + * Purpose: + * Assign the left and right gain values corresponding to the given pan value. + * + * This routine uses sin/cos approximations for an equal power curve: + * + * sin(x) = (2-4*c)*x^2 + c + x + * cos(x) = (2-4*c)*x^2 + c - x + * + * where c = 1/sqrt(2) + * using the a0 + x*(a1 + x*a2) approach + * + * Inputs: + * pan - pan value (-63 to + 63) + * + * Outputs: + * pGainLeft linear gain multiplier for left channel (15-bit fraction) + * pGainRight linear gain multiplier for left channel (15-bit fraction) + * + * Side Effects: + *---------------------------------------------------------------------------- +*/ +void EAS_CalcPanControl (EAS_INT pan, EAS_I16 *pGainLeft, EAS_I16 *pGainRight) +{ + EAS_INT temp; + EAS_INT netAngle; + + /* impose hard limit */ + if (pan < -63) + netAngle = -63; + else if (pan > 63) + netAngle = 63; + else + netAngle = pan; + + /*lint -e{701} */ + netAngle = netAngle << 8; + + /* calculate sin */ + temp = EG1_ONE + FMUL_15x15(COEFF_PAN_G2, netAngle); + temp = COEFF_PAN_G0 + FMUL_15x15(temp, netAngle); + + if (temp > SYNTH_FULL_SCALE_EG1_GAIN) + temp = SYNTH_FULL_SCALE_EG1_GAIN; + else if (temp < 0) + temp = 0; + + *pGainRight = (EAS_I16) temp; + + /* calculate cos */ + temp = -EG1_ONE + FMUL_15x15(COEFF_PAN_G2, netAngle); + temp = COEFF_PAN_G0 + FMUL_15x15(temp, netAngle); + if (temp > SYNTH_FULL_SCALE_EG1_GAIN) + temp = SYNTH_FULL_SCALE_EG1_GAIN; + else if (temp < 0) + temp = 0; + + *pGainLeft = (EAS_I16) temp; +} + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_pan.h b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_pan.h new file mode 100755 index 0000000..cb0a90d --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_pan.h @@ -0,0 +1,66 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_pan.h + * + * Contents and purpose: + * Calculates left and right gain multipliers based on a pan value from -63 to +63 + * + * NOTES: + * The _CMX_PARSER and _MFI_PARSER preprocessor symbols determine + * whether the parser works for those particular file formats. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef EAS_PAN_H +#define _EAS_PAN_H + +#include "eas_types.h" + +/*---------------------------------------------------------------------------- + * EAS_CalcPanControl() + *---------------------------------------------------------------------------- + * Purpose: + * Assign the left and right gain values corresponding to the given pan value. + * + * This routine uses sin/cos approximations for an equal power curve: + * + * sin(x) = (2-4*c)*x^2 + c + x + * cos(x) = (2-4*c)*x^2 + c - x + * + * where c = 1/sqrt(2) + * using the a0 + x*(a1 + x*a2) approach + * + * Inputs: + * pan - pan value (-63 to + 63) + * + * Outputs: + * pGainLeft linear gain multiplier for left channel (15-bit fraction) + * pGainRight linear gain multiplier for left channel (15-bit fraction) + * + * Side Effects: + *---------------------------------------------------------------------------- +*/ +void EAS_CalcPanControl (EAS_INT pan, EAS_I16 *pGainLeft, EAS_I16 *pGainRight); + +#endif + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_parser.h b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_parser.h new file mode 100755 index 0000000..96ec35b --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_parser.h @@ -0,0 +1,98 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_parser.h + * + * Contents and purpose: + * Interface declarations for the generic parser interface + * + * This header only contains declarations that are specific + * to this implementation. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 767 $ + * $Date: 2007-07-19 13:47:31 -0700 (Thu, 19 Jul 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_PARSER_H +#define _EAS_PARSER_H + +#include "eas_types.h" + + +/* metadata callback */ +typedef struct s_metadata_cb_tag +{ + EAS_METADATA_CBFUNC callback; + char *buffer; + EAS_VOID_PTR pUserData; + EAS_I32 bufferSize; +} S_METADATA_CB; + +/* generic parser interface */ +typedef struct +{ + EAS_RESULT (* EAS_CONST pfCheckFileType)(struct s_eas_data_tag *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset); + EAS_RESULT (* EAS_CONST pfPrepare)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData); + EAS_RESULT (* EAS_CONST pfTime)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime); + EAS_RESULT (* EAS_CONST pfEvent)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData, EAS_INT parseMode); + EAS_RESULT (* EAS_CONST pfState)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData, EAS_STATE *pState); + EAS_RESULT (* EAS_CONST pfClose)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData); + EAS_RESULT (* EAS_CONST pfReset)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData); + EAS_RESULT (* EAS_CONST pfPause)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData); + EAS_RESULT (* EAS_CONST pfResume)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData); + EAS_RESULT (* EAS_CONST pfLocate)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData, EAS_I32 time, EAS_BOOL *pParserLocate); + EAS_RESULT (* EAS_CONST pfSetData)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value); + EAS_RESULT (* EAS_CONST pfGetData)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue); + EAS_RESULT (* EAS_CONST pfGetMetaData)(struct s_eas_data_tag *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pMediaLength); +} S_FILE_PARSER_INTERFACE; + +typedef enum +{ + eParserModePlay, + eParserModeLocate, + eParserModeMute, + eParserModeMetaData +} E_PARSE_MODE; + +typedef enum +{ + PARSER_DATA_FILE_TYPE, + PARSER_DATA_PLAYBACK_RATE, + PARSER_DATA_TRANSPOSITION, + PARSER_DATA_VOLUME, + PARSER_DATA_SYNTH_HANDLE, + PARSER_DATA_METADATA_CB, + PARSER_DATA_DLS_COLLECTION, + PARSER_DATA_EAS_LIBRARY, + PARSER_DATA_POLYPHONY, + PARSER_DATA_PRIORITY, + PARSER_DATA_FORMAT, + PARSER_DATA_MEDIA_LENGTH, + PARSER_DATA_JET_CB, + PARSER_DATA_MUTE_FLAGS, + PARSER_DATA_SET_MUTE, + PARSER_DATA_CLEAR_MUTE, + PARSER_DATA_NOTE_COUNT, + PARSER_DATA_MAX_PCM_STREAMS, + PARSER_DATA_GAIN_OFFSET, + PARSER_DATA_PLAY_MODE +} E_PARSER_DATA; + +#endif /* #ifndef _EAS_PARSER_H */ diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_pcm.c b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_pcm.c new file mode 100755 index 0000000..ff3f6f9 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_pcm.c @@ -0,0 +1,1482 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_pcm.c + * + * Contents and purpose: + * Implements the PCM engine including ADPCM decode for SMAF and CMX audio playback. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 849 $ + * $Date: 2007-08-28 08:59:11 -0700 (Tue, 28 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_data.h" +#include "eas_report.h" +#include "eas_host.h" +#include "eas_config.h" +#include "eas_parser.h" +#include "eas_pcm.h" +#include "eas_math.h" +#include "eas_mixer.h" + +#define PCM_MIXER_GUARD_BITS (NUM_MIXER_GUARD_BITS + 1) + +/*---------------------------------------------------------------------------- + * Decoder interfaces + *---------------------------------------------------------------------------- +*/ + +static EAS_RESULT LinearPCMDecode (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState); +static EAS_RESULT LinearPCMLocate (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState, EAS_I32 time); + +static const S_DECODER_INTERFACE PCMDecoder = +{ + NULL, + LinearPCMDecode, + LinearPCMLocate, +}; + +/* SMAF ADPCM decoder */ +#ifdef _SMAF_PARSER +extern S_DECODER_INTERFACE SmafDecoder; +#define SMAF_DECODER &SmafDecoder +extern S_DECODER_INTERFACE Smaf7BitDecoder; +#define SMAF_7BIT_DECODER &Smaf7BitDecoder +#else +#define SMAF_DECODER NULL +#define SMAF_7BIT_DECODER NULL +#endif + +/* IMA ADPCM decoder */ +#ifdef _IMA_DECODER +extern S_DECODER_INTERFACE IMADecoder; +#define IMA_DECODER &IMADecoder +#else +#define IMA_DECODER NULL +#endif + +static const S_DECODER_INTERFACE * const decoders[] = +{ + &PCMDecoder, + SMAF_DECODER, + IMA_DECODER, + SMAF_7BIT_DECODER +}; + +/*---------------------------------------------------------------------------- + * Sample rate conversion + *---------------------------------------------------------------------------- +*/ + +#define SRC_RATE_MULTIPLER (0x40000000 / _OUTPUT_SAMPLE_RATE) + +#ifdef _LOOKUP_SAMPLE_RATE +static const EAS_U32 srcConvRate[][2] = +{ + 4000L, (4000L << 15) / _OUTPUT_SAMPLE_RATE, + 8000L, (8000L << 15) / _OUTPUT_SAMPLE_RATE, + 11025L, (11025L << 15) / _OUTPUT_SAMPLE_RATE, + 12000L, (12000L << 15) / _OUTPUT_SAMPLE_RATE, + 16000L, (16000L << 15) / _OUTPUT_SAMPLE_RATE, + 22050L, (22050L << 15) / _OUTPUT_SAMPLE_RATE, + 24000L, (24000L << 15) / _OUTPUT_SAMPLE_RATE, + 32000L, (32000L << 15) / _OUTPUT_SAMPLE_RATE +}; +static EAS_U32 CalcBaseFreq (EAS_U32 sampleRate); +#define SRC_CONV_RATE_ENTRIES (sizeof(srcConvRate)/sizeof(EAS_U32)/2) +#endif + + +/* interface prototypes */ +static EAS_RESULT RenderPCMStream (S_EAS_DATA *pEASData, S_PCM_STATE *pState, EAS_I32 numSamples); + + +/* local prototypes */ +static S_PCM_STATE *FindSlot (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_PCM_CALLBACK pCallbackFunc, EAS_VOID_PTR cbInstData); +static EAS_RESULT InitPCMStream (S_EAS_DATA *pEASData, S_PCM_STATE *pState); + +/*---------------------------------------------------------------------------- + * EAS_PEInit() + *---------------------------------------------------------------------------- + * Purpose: + * Initializes the PCM engine + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEInit (S_EAS_DATA *pEASData) +{ + S_PCM_STATE *pState; + EAS_INT i; + + /* check for static memory allocation */ + if (pEASData->staticMemoryModel) + pEASData->pPCMStreams = EAS_CMEnumData(EAS_CM_PCM_DATA); + /* allocate dynamic memory */ + else + pEASData->pPCMStreams = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_PCM_STATE) * MAX_PCM_STREAMS); + + if (!pEASData->pPCMStreams) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Failed to allocate memory for PCM streams\n"); */ } + return EAS_ERROR_MALLOC_FAILED; + } + + //zero the memory to insure complete initialization + EAS_HWMemSet((void *)(pEASData->pPCMStreams),0, sizeof(S_PCM_STATE) * MAX_PCM_STREAMS); + + /* initialize the state data */ + for (i = 0, pState = pEASData->pPCMStreams; i < MAX_PCM_STREAMS; i++, pState++) + pState->fileHandle = NULL; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_PEShutdown() + *---------------------------------------------------------------------------- + * Purpose: + * Shuts down the PCM engine + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEShutdown (S_EAS_DATA *pEASData) +{ + + /* free any dynamic memory */ + if (!pEASData->staticMemoryModel) + { + if (pEASData->pPCMStreams) + { + EAS_HWFree(pEASData->hwInstData, pEASData->pPCMStreams); + pEASData->pPCMStreams = NULL; + } + } + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_PERender() + *---------------------------------------------------------------------------- + * Purpose: + * Render a buffer of PCM audio + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PERender (S_EAS_DATA* pEASData, EAS_I32 numSamples) +{ + S_PCM_STATE *pState; + EAS_RESULT result; + EAS_INT i; + + /* render all the active streams */ + for (i = 0, pState = pEASData->pPCMStreams; i < MAX_PCM_STREAMS; i++, pState++) + { + if ((pState->fileHandle) && (pState->state != EAS_STATE_STOPPED) && (pState->state != EAS_STATE_PAUSED)) + if ((result = RenderPCMStream(pEASData, pState, numSamples)) != EAS_SUCCESS) + return result; + } + return EAS_SUCCESS; +} + + +/*---------------------------------------------------------------------------- + * EAS_PEState() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current state of the stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * pState - pointer to variable to store state + * + * Outputs: + * + * + * Side Effects: + * + * Notes: + * This interface is also exposed in the internal library for use by the other modules. + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT EAS_PEState (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pInstData, EAS_STATE *pState) +{ + /* return current state */ + *pState = pInstData->state; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_PEClose() + *---------------------------------------------------------------------------- + * Purpose: + * Close the file and clean up + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEClose (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pState) +{ + EAS_RESULT result; + + if ((result = EAS_HWCloseFile(pEASData->hwInstData, pState->fileHandle)) != EAS_SUCCESS) + return result; + + pState->fileHandle = NULL; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * PCM_Reset() + *---------------------------------------------------------------------------- + * Purpose: + * Reset the sequencer. Used for locating backwards in the file. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEReset (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pState) +{ + EAS_RESULT result; + + /* reset file position to first byte of data in the stream */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pState->fileHandle, pState->startPos)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %d seeking to start of PCM file\n", result); */ } + return result; + } + + /* re-initialize stream */ + return InitPCMStream(pEASData, pState); +} + +/*---------------------------------------------------------------------------- + * EAS_PEOpenStream() + *---------------------------------------------------------------------------- + * Purpose: + * Starts up a PCM playback + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEOpenStream (S_EAS_DATA *pEASData, S_PCM_OPEN_PARAMS *pParams, EAS_PCM_HANDLE *pHandle) +{ + EAS_RESULT result; + S_PCM_STATE *pState; + EAS_I32 filePos; + + /* make sure we support this decoder */ + if (pParams->decoder >= NUM_DECODER_MODULES) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Decoder selector out of range\n"); */ } + return EAS_ERROR_PARAMETER_RANGE; + } + if (decoders[pParams->decoder] == NULL) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Decoder module not available\n"); */ } + return EAS_ERROR_FEATURE_NOT_AVAILABLE; + } + + /* find a slot for the new stream */ + if ((pState = FindSlot(pEASData, pParams->fileHandle, pParams->pCallbackFunc, pParams->cbInstData)) == NULL) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Unable to open ADPCM stream, too many streams open\n"); */ } + return EAS_ERROR_MAX_PCM_STREAMS; + } + + /* get the current file position */ + if ((result = EAS_HWFilePos(pEASData->hwInstData, pState->fileHandle, &filePos)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_HWFilePos returned %ld\n",result); */ } + pState->fileHandle = NULL; + return result; + } + + pState->pDecoder = decoders[pParams->decoder]; + pState->startPos = filePos; + pState->bytesLeftLoop = pState->byteCount = pParams->size; + pState->loopStart = pParams->loopStart; + pState->samplesTilLoop = (EAS_I32) pState->loopStart; + pState->loopSamples = pParams->loopSamples; + pState->samplesInLoop = 0; + pState->blockSize = (EAS_U16) pParams->blockSize; + pState->flags = pParams->flags; + pState->envData = pParams->envData; + pState->volume = pParams->volume; + pState->sampleRate = (EAS_U16) pParams->sampleRate; + + /* set the base frequency */ + pState->basefreq = (SRC_RATE_MULTIPLER * (EAS_U32) pParams->sampleRate) >> 15; + + /* calculate shift for frequencies > 1.0 */ + pState->rateShift = 0; + while (pState->basefreq > 32767) + { + pState->basefreq = pState->basefreq >> 1; + pState->rateShift++; + } + + /* initialize */ + if ((result = InitPCMStream(pEASData, pState)) != EAS_SUCCESS) + return result; + + *pHandle = pState; + + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "EAS_PEOpenStream: StartPos=%d, byteCount = %d, loopSamples=%d\n", + pState->startPos, pState->byteCount, pState->loopSamples); */ } + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_PEContinueStream() + *---------------------------------------------------------------------------- + * Purpose: + * Continues a PCM stream + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -e{715} reserved for future use */ +EAS_RESULT EAS_PEContinueStream (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pState, EAS_I32 size) +{ + + /* add new samples to count */ + pState->bytesLeft += size; + if (pState->bytesLeft > 0) + pState->flags &= ~PCM_FLAGS_EMPTY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_PEGetFileHandle() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the file handle of a stream + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT EAS_PEGetFileHandle (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pState, EAS_FILE_HANDLE *pFileHandle) +{ + *pFileHandle = pState->fileHandle; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_PEUpdateParams() + *---------------------------------------------------------------------------- + * Purpose: + * Update the pitch and volume parameters for a PCM stream + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_PCM_STATE for this stream + * gainLeft - linear gain multipler in 1.15 fraction format + * gainRight - linear gain multipler in 1.15 fraction format + * pitch - pitch shift in cents + * initial - initial settings, set current gain + * + * Outputs: + * + * + * Side Effects: + * + * Notes + * In mono mode, leftGain controls the output gain and rightGain is ignored + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +/*lint -esym(715, gainRight) used only in 2-channel version */ +EAS_RESULT EAS_PEUpdateParams (S_EAS_DATA* pEASData, EAS_PCM_HANDLE pState, EAS_I16 pitch, EAS_I16 gainLeft, EAS_I16 gainRight) +{ + + pState->gainLeft = gainLeft; + +#if (NUM_OUTPUT_CHANNELS == 2) + pState->gainRight = gainRight; +#endif + + pState->pitch = pitch; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_PELocate() + *---------------------------------------------------------------------------- + * Purpose: + * This function seeks to the requested place in the file. Accuracy + * is dependent on the sample rate and block size. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * pState - stream handle + * time - media time in milliseconds + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PELocate (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pState, EAS_I32 time) +{ + if (pState->pDecoder->pfLocate == NULL) + return EAS_ERROR_FEATURE_NOT_AVAILABLE; + + return pState->pDecoder->pfLocate(pEASData, pState, time); +} + +/*---------------------------------------------------------------------------- + * EAS_PEUpdateVolume() + *---------------------------------------------------------------------------- + * Purpose: + * Update the volume parameters for a PCM stream + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_PCM_STATE for this stream + * gainLeft - linear gain multipler in 1.15 fraction format + * gainRight - linear gain multipler in 1.15 fraction format + * initial - initial settings, set current gain + * + * Outputs: + * + * + * Side Effects: + * + * Notes + * In mono mode, leftGain controls the output gain and rightGain is ignored + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT EAS_PEUpdateVolume (S_EAS_DATA* pEASData, EAS_PCM_HANDLE pState, EAS_I16 volume) +{ + pState->volume = volume; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_PEUpdatePitch() + *---------------------------------------------------------------------------- + * Purpose: + * Update the pitch parameter for a PCM stream + * + * Inputs: + * pEASData - pointer to EAS library instance data + * pState - pointer to S_PCM_STATE for this stream + * pitch - new pitch value in pitch cents + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT EAS_PEUpdatePitch (S_EAS_DATA* pEASData, EAS_PCM_HANDLE pState, EAS_I16 pitch) +{ + pState->pitch = pitch; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_PEPause() + *---------------------------------------------------------------------------- + * Purpose: + * Mute and stop rendering a PCM stream. Sets the gain target to zero and stops the playback + * at the end of the next audio frame. + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_PCM_STATE for this stream + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT EAS_PEPause (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pState) +{ + /* set state to stopping */ + pState->state = EAS_STATE_PAUSING; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_PEResume() + *---------------------------------------------------------------------------- + * Purpose: + * Resume rendering a PCM stream. Sets the gain target back to its + * previous setting and restarts playback at the end of the next audio + * frame. + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_PCM_STATE for this stream + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT EAS_PEResume (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pState) +{ + /* set state to stopping */ + pState->state = EAS_STATE_PLAY; + return EAS_SUCCESS; +} + +EAS_U32 getDecayScale(EAS_U32 index) +{ + EAS_U32 utemp; + + //envelope decay segment + switch (index) + { + case 0: //no decay + utemp = 512;//32768; + break; + case 1: //.0156 dB per update + utemp = 511;//32709; + break; + case 2: //.03125 + utemp = 510;//32649; + break; + case 3: //.0625 + utemp = 508;//32532; + break; + case 4: //.125 + utemp = 505;//32298; + break; + case 5: //.25 + utemp = 497;//31835; + break; + case 6: //.5 + utemp = 483;//30929; + break; + case 7: //1.0 + utemp = 456;//29193; + break; + case 8: //2.0 + utemp = 406;//26008; + break; + case 9: //4.0 + utemp = 323;//20642; + break; + case 10: //8.0 + utemp = 203;//13004; + break; + case 11: //16.0 + utemp = 81;//5160; + break; + case 12: //32.0 + utemp = 13;//813; + break; + case 13: //64.0 + utemp = 0;//20; + break; + case 14: //128.0 + utemp = 0; + break; + case 15: //256.0 + default: + utemp = 0; + break; + } + //printf("getdecayscale returned %d\n",utemp); + return utemp; +} + +EAS_U32 getAttackIncrement(EAS_U32 index) +{ + EAS_U32 utemp; + + //envelope decay segment + switch (index) + { + case 0: + utemp = 32; + break; + case 1: + utemp = 64; + break; + case 2: + utemp = 128; + break; + case 3: + utemp = 256; + break; + case 4: + utemp = 512; + break; + case 5: + utemp = 1024; + break; + case 6: + utemp = 2048; + break; + case 7: + utemp = 4096; + break; + case 8: + utemp = 8192; + break; + case 9: + utemp = 16384; + break; + case 10: + utemp = 32768; + break; + case 11: + utemp = 65536; + break; + case 12: + utemp = 65536; + break; + case 13: + utemp = 65536; + break; + case 14: + utemp = 65535; + break; + case 15: + default: + utemp = 0; + break; + } + //printf("getattackincrement returned %d\n",utemp); + return utemp; +} + +/*---------------------------------------------------------------------------- + * EAS_PERelease() + *---------------------------------------------------------------------------- + * Purpose: + * Put the PCM stream envelope into release. + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_PCM_STATE for this stream + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT EAS_PERelease (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pState) +{ + EAS_U32 utemp; + + //printf("handling note-off part of envelope\n"); + /*if the note is not ignore release or sustained*/ + if (((pState->envData >> 24) & 0x0F)==0) + { + /* set envelope state to release */ + pState->envState = PCM_ENV_RELEASE; + utemp = ((pState->envData >> 20) & 0x0F); + pState->envScale = getDecayScale(utemp); //getReleaseScale(utemp); + } + else + { + /*else change envelope state to sustain */ + pState->envState = PCM_ENV_SUSTAIN; + utemp = ((pState->envData >> 28) & 0x0F); + pState->envScale = getDecayScale(utemp); //getSustainScale(utemp); + } + //since we are in release, don't let anything hang around too long + //printf("checking env scale, val = %d\n",((S_PCM_STATE*) handle)->envScale); + if (pState->envScale > 505) + pState->envScale = 505; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * FindSlot() + *---------------------------------------------------------------------------- + * Purpose: + * Locates an empty stream slot and assigns the file handle + * + * Inputs: + * pEASData - pointer to EAS library instance data + * fileHandle - file handle + * pCallbackFunc - function to be called back upon EAS_STATE_STOPPED + * + * Outputs: + * returns handle to slot or NULL if all slots are used + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static S_PCM_STATE *FindSlot (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_PCM_CALLBACK pCallbackFunc, EAS_VOID_PTR cbInstData) +{ + EAS_INT i; + S_PCM_STATE *pState; + +#ifndef NO_PCM_STEAL + S_PCM_STATE *foundState = NULL; + EAS_INT count = 0; + EAS_U32 startOrder = 0xFFFFFFFF; + S_PCM_STATE *stealState = NULL; + EAS_U32 youngest = 0; + + /* find an empty slot, count total in use, and find oldest in use (lowest start order) */ + for (i = 0, pState = pEASData->pPCMStreams; i < MAX_PCM_STREAMS; i++, pState++) + { + /* if this one is available */ + if (pState->fileHandle == NULL) + { + foundState = pState; + } + /* else this one is in use, so see if it is the oldest, and count total in use */ + /* also find youngest */ + else + { + /*one more voice in use*/ + count++; + /* is this the oldest? (lowest start order) */ + if ((pState->state != EAS_STATE_STOPPING) && (pState->startOrder < startOrder)) + { + /* remember this one */ + stealState = pState; + /* remember the oldest so far */ + startOrder = pState->startOrder; + } + /* is this the youngest? (highest start order) */ + if (pState->startOrder >= youngest) + { + youngest = pState->startOrder; + } + } + } + + /* if there are too many voices active, stop the oldest one */ + if (count > PCM_STREAM_THRESHOLD) + { + //printf("stealing!!!\n"); + /* make sure we got one, although we should always have one at this point */ + if (stealState != NULL) + { + //flag this as stopping, so it will get shut off + stealState->state = EAS_STATE_STOPPING; + } + } + + /* if there are no available open streams (we won't likely see this, due to stealing) */ + if (foundState == NULL) + return NULL; + + /* save info */ + foundState->startOrder = youngest + 1; + foundState->fileHandle = fileHandle; + foundState->pCallback = pCallbackFunc; + foundState->cbInstData = cbInstData; + return foundState; +#else + /* find an empty slot*/ + for (i = 0; i < MAX_PCM_STREAMS; i++) + { + pState = &pEASData->pPCMStreams[i]; + if (pState->fileHandle != NULL) + continue; + + pState->fileHandle = fileHandle; + pState->pCallback = pCallbackFunc; + pState->cbInstData = cbInstData; + return pState; + } + return NULL; +#endif +} + +#ifdef _LOOKUP_SAMPLE_RATE +/*---------------------------------------------------------------------------- + * CalcBaseFreq() + *---------------------------------------------------------------------------- + * Purpose: + * Calculates the fractional phase increment for the sample rate converter + * + * Inputs: + * sampleRate - sample rate in samples/sec + * + * Outputs: + * Returns fractional sample rate with a 15-bit fraction + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_U32 CalcBaseFreq (EAS_U32 sampleRate) +{ + EAS_INT i; + + /* look up the conversion rate */ + for (i = 0; i < (EAS_INT)(SRC_CONV_RATE_ENTRIES); i ++) + { + if (srcConvRate[i][0] == sampleRate) + return srcConvRate[i][1]; + } + + /* if not found in table, do it the long way */ + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Sample rate %u not in table, calculating by division\n", sampleRate); */ } + + return (SRC_RATE_MULTIPLER * (EAS_U32) sampleRate) >> 15; +} +#endif + +/*---------------------------------------------------------------------------- + * InitPCMStream() + *---------------------------------------------------------------------------- + * Purpose: + * Start an ADPCM stream playback. Decodes the header, preps the engine. + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT InitPCMStream (S_EAS_DATA *pEASData, S_PCM_STATE *pState) +{ + + /* initialize the data structure */ + pState->bytesLeft = pState->byteCount; + pState->phase = 0; + pState->srcByte = 0; + pState->decoderL.acc = 0; + pState->decoderL.output = 0; + pState->decoderL.x0 = pState->decoderL.x1 = 0; + pState->decoderL.step = 0; + pState->decoderR.acc = 0; + pState->decoderR.output = 0; + pState->decoderR.x0 = pState->decoderR.x1 = 0; + pState->decoderR.step = 0; + pState->hiNibble = EAS_FALSE; + pState->pitch = 0; + pState->blockCount = 0; + pState->gainLeft = PCM_DEFAULT_GAIN_SETTING; +// pState->currentGainLeft = PCM_DEFAULT_GAIN_SETTING; + pState->envValue = 0; + pState->envState = PCM_ENV_START; + +#if (NUM_OUTPUT_CHANNELS == 2) + pState->gainRight = PCM_DEFAULT_GAIN_SETTING; +// pState->currentGainRight = PCM_DEFAULT_GAIN_SETTING; +#endif + pState->state = EAS_STATE_READY; + + /* initialize the decoder */ + if (pState->pDecoder->pfInit) + return (*pState->pDecoder->pfInit)(pEASData, pState); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RenderPCMStream() + *---------------------------------------------------------------------------- + * Purpose: + * Decodes a buffer of ADPCM data. + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RenderPCMStream (S_EAS_DATA *pEASData, S_PCM_STATE *pState, EAS_I32 numSamples) +{ + EAS_RESULT result; + EAS_U32 phaseInc; + EAS_I32 gainLeft, gainIncLeft; + EAS_I32 *pOut; + EAS_I32 temp; + EAS_U32 utemp; + +#if (NUM_OUTPUT_CHANNELS == 2) + EAS_I32 gainRight, gainIncRight; +#endif + +#if 0 + printf("env data: AR = %d, DR = %d, SL = %d, SR = %d, RR = %d\n", + ((pState->envData >> 12) & 0x0F), + ((pState->envData >> 16) & 0x0F), + ((pState->envData >> 8) & 0x0F), + ((pState->envData >> 28) & 0x0F), + ((pState->envData >> 20) & 0x0F)); +#endif + + if (pState->envState == PCM_ENV_START) + { + //printf("env start\n"); + utemp = ((pState->envData >> 12) & 0x0F); + //if fastest rate, attack is already completed + //do the same for slowest rate, since that allows zero to be passed for default envelope + if (utemp == 0x0F || utemp == 0x00) + { + //start envelope at full + pState->envValue = (32768<<7); + //jump right into decay + utemp = ((pState->envData >> 16) & 0x0F); + pState->envScale = getDecayScale(utemp); + pState->envState = PCM_ENV_DECAY; + pState->currentGainLeft = (EAS_I16) FMUL_15x15(pState->gainLeft, pState->volume); + pState->currentGainRight = (EAS_I16) FMUL_15x15(pState->gainRight, pState->volume); + } + //else attack has a ramp + else + { + //start the envelope very low + pState->envValue = (2<<7); + pState->currentGainLeft = 0; + pState->currentGainRight = 0; + //get envelope attack scaling value + pState->envScale = getAttackIncrement(utemp); + //go to attack state + pState->envState = PCM_ENV_ATTACK; + } + } + if (pState->envState == PCM_ENV_ATTACK) + { + //printf("env attack, env value = %d, env scale = %d\n",pState->envValue>>7,pState->envScale); + //update envelope value + pState->envValue = pState->envValue + (pState->envScale << 7); + //check envelope level and update state if needed + if (pState->envValue >= (32768<<7)) + { + pState->envValue = (32768<<7); + utemp = ((pState->envData >> 16) & 0x0F); + pState->envScale = getDecayScale(utemp); + pState->envState = PCM_ENV_DECAY; + } + } + else if (pState->envState == PCM_ENV_DECAY) + { + //printf("env decay, env value = %d, env scale = %d\n",pState->envValue>>7,pState->envScale); + //update envelope value + pState->envValue = (pState->envValue * pState->envScale)>>9; + //check envelope level against sustain level and update state if needed + utemp = ((pState->envData >> 8) & 0x0F); + if (utemp == (EAS_U32)0x0F) + utemp = (2<<7); + else + { + utemp = ((32769<<7) >> (utemp>>1)); + } + if (pState->envValue <= utemp) + { + utemp = ((pState->envData >> 28) & 0x0F); + pState->envScale = getDecayScale(utemp); //getSustainScale(utemp); + pState->envState = PCM_ENV_SUSTAIN; + } + } + else if (pState->envState == PCM_ENV_SUSTAIN) + { + //printf("env sustain, env value = %d, env scale = %d\n",pState->envValue>>7,pState->envScale); + //update envelope value + pState->envValue = (pState->envValue * pState->envScale)>>9; + //check envelope level against bottom level and update state if needed + if (pState->envValue <= (2<<7)) + { + //no more decay + pState->envScale = 512; + pState->envState = PCM_ENV_END; + } + } + else if (pState->envState == PCM_ENV_RELEASE) + { + //printf("env release, env value = %d, env scale = %d\n",pState->envValue>>7,pState->envScale); + //update envelope value + pState->envValue = (pState->envValue * pState->envScale)>>9; + //check envelope level against bottom level and update state if needed + if (pState->envValue <= (2<<7)) + { + //no more decay + pState->envScale = 512; + pState->envState = PCM_ENV_END; + } + } + else if (pState->envState == PCM_ENV_END) + { + //printf("env end\n"); + /* set state to stopping, already ramped down */ + pState->state = EAS_STATE_STOPPING; + } + + //pState->gainLeft = (EAS_U16)((pState->gainLeft * (pState->envValue>>7))>>15); + //pState->gainRight = (EAS_U16)((pState->gainRight * (pState->envValue>>7))>>15); + + /* gain to 32-bits to increase resolution on anti-zipper filter */ + /*lint -e{703} use shift for performance */ + gainLeft = (EAS_I32) pState->currentGainLeft << SYNTH_UPDATE_PERIOD_IN_BITS; +#if (NUM_OUTPUT_CHANNELS == 2) + /*lint -e{703} use shift for performance */ + gainRight = (EAS_I32) pState->currentGainRight << SYNTH_UPDATE_PERIOD_IN_BITS; +#endif + + /* calculate a new gain increment, gain target is zero if pausing */ + if ((pState->state == EAS_STATE_PAUSING) || (pState->state == EAS_STATE_PAUSED)) + { + gainIncLeft = -pState->currentGainLeft; +#if (NUM_OUTPUT_CHANNELS == 2) + gainIncRight= -pState->currentGainRight; +#endif + } + else + { + EAS_I32 gain = FMUL_15x15(pState->envValue >> 7, pState->volume); + gainIncLeft = FMUL_15x15(pState->gainLeft, gain) - pState->currentGainLeft; +#if (NUM_OUTPUT_CHANNELS == 2) + gainIncRight = FMUL_15x15(pState->gainRight, gain) - pState->currentGainRight; +#endif + } + + /* calculate phase increment */ + phaseInc = pState->basefreq; + + /* convert pitch cents to linear multiplier */ + if (pState->pitch) + { + temp = EAS_Calculate2toX(pState->pitch); + phaseInc = FMUL_15x15(phaseInc, temp); + } + phaseInc = phaseInc << pState->rateShift; + + /* pointer to mix buffer */ + pOut = pEASData->pMixBuffer; + + /* render a buffer of samples */ + while (numSamples--) + { + + /* interpolate an output sample */ + pState->decoderL.output = pState->decoderL.x0 + FMUL_15x15((pState->decoderL.x1 - pState->decoderL.x0), pState->phase & PHASE_FRAC_MASK); + + /* stereo output */ +#if (NUM_OUTPUT_CHANNELS == 2) + + /* stereo stream? */ + if (pState->flags & PCM_FLAGS_STEREO) + pState->decoderR.output = pState->decoderR.x0 + FMUL_15x15((pState->decoderR.x1 - pState->decoderR.x0), pState->phase & PHASE_FRAC_MASK); + + /* gain scale and mix */ + /*lint -e{704} use shift instead of division */ + *pOut++ += (pState->decoderL.output * (gainLeft >> SYNTH_UPDATE_PERIOD_IN_BITS)) >> PCM_MIXER_GUARD_BITS; + gainLeft += gainIncLeft; + + /*lint -e{704} use shift instead of division */ + if (pState->flags & PCM_FLAGS_STEREO) + *pOut++ += (pState->decoderR.output * (gainRight >> SYNTH_UPDATE_PERIOD_IN_BITS)) >> PCM_MIXER_GUARD_BITS; + else + *pOut++ += (pState->decoderL.output * (gainRight >> SYNTH_UPDATE_PERIOD_IN_BITS)) >> PCM_MIXER_GUARD_BITS; + + gainRight += gainIncRight; + + /* mono output */ +#else + /* if stereo stream, decode right channel and mix to mono */ + if (pState->flags & PCM_FLAGS_STEREO) + { + pState->decoderR.output= pState->decoderR.x0 + FMUL_15x15((pState->decoderR.x1 - pState->decoderR.x0), pState->phase & PHASE_FRAC_MASK); + + /* for mono, sum stereo ADPCM to mono */ + /*lint -e{704} use shift instead of division */ + *pOut++ += ((pState->decoderL.output + pState->decoderR.output) * (gainLeft >> SYNTH_UPDATE_PERIOD_IN_BITS)) >> PCM_MIXER_GUARD_BITS; + } + else + /*lint -e{704} use shift instead of division */ + *pOut++ += (pState->decoderL.output * (gainLeft >> SYNTH_UPDATE_PERIOD_IN_BITS)) >> PCM_MIXER_GUARD_BITS; + + gainLeft += gainIncLeft; +#endif + + /* advance phase accumulator */ + pState->phase += phaseInc; + + /* if integer part of phase accumulator is non-zero, advance to next sample */ + while (pState->phase & ~PHASE_FRAC_MASK) + { + pState->decoderL.x0 = pState->decoderL.x1; + pState->decoderR.x0 = pState->decoderR.x1; + + /* give the source a chance to continue the stream */ + if (!pState->bytesLeft && pState->pCallback && ((pState->flags & PCM_FLAGS_EMPTY) == 0)) + { + pState->flags |= PCM_FLAGS_EMPTY; + (*pState->pCallback)(pEASData, pState->cbInstData, pState, EAS_STATE_EMPTY); + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "RenderPCMStream: After empty callback, bytesLeft = %d\n", pState->bytesLeft); */ } + } + + /* decode the next sample */ + if ((result = (*pState->pDecoder->pfDecodeSample)(pEASData, pState)) != EAS_SUCCESS) + return result; + + /* adjust phase by one sample */ + pState->phase -= (1L << NUM_PHASE_FRAC_BITS); + } + + } + + /* save new gain */ + /*lint -e{704} use shift instead of division */ + pState->currentGainLeft = (EAS_I16) (gainLeft >> SYNTH_UPDATE_PERIOD_IN_BITS); + +#if (NUM_OUTPUT_CHANNELS == 2) + /*lint -e{704} use shift instead of division */ + pState->currentGainRight = (EAS_I16) (gainRight >> SYNTH_UPDATE_PERIOD_IN_BITS); +#endif + + /* if pausing, set new state and notify */ + if (pState->state == EAS_STATE_PAUSING) + { + pState->state = EAS_STATE_PAUSED; + if (pState->pCallback) + (*pState->pCallback)(pEASData, pState->cbInstData, pState, pState->state); + } + + /* if out of data, set stopped state and notify */ + if (pState->bytesLeft == 0 || pState->state == EAS_STATE_STOPPING) + { + pState->state = EAS_STATE_STOPPED; + + /* do callback unless the file has already been closed */ + if (pState->pCallback && pState->fileHandle) + (*pState->pCallback)(pEASData, pState->cbInstData, pState, pState->state); + } + + if (pState->state == EAS_STATE_READY) + pState->state = EAS_STATE_PLAY; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * LinearPCMDecode() + *---------------------------------------------------------------------------- + * Purpose: + * Decodes a PCM sample + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT LinearPCMDecode (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState) +{ + EAS_RESULT result; + EAS_HW_DATA_HANDLE hwInstData; + + hwInstData = ((S_EAS_DATA*) pEASData)->hwInstData; + + /* if out of data, check for loop */ + if ((pState->bytesLeft == 0) && (pState->loopSamples != 0)) + { + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pState->fileHandle, (EAS_I32) (pState->startPos + pState->loopLocation))) != EAS_SUCCESS) + return result; + pState->bytesLeft = pState->byteCount = (EAS_I32) pState->bytesLeftLoop; + pState->flags &= ~PCM_FLAGS_EMPTY; + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "LinearPCMDecode: Rewind file to %d, bytesLeft = %d\n", pState->startPos, pState->bytesLeft); */ } + } + + if (pState->bytesLeft) + { + + /* check format byte for 8-bit samples */ + if (pState->flags & PCM_FLAGS_8_BIT) + { + /* fetch left or mono sample */ + if ((result = EAS_HWGetByte(hwInstData, pState->fileHandle, &pState->srcByte)) != EAS_SUCCESS) + return result; + + /* if unsigned */ + if (pState->flags & PCM_FLAGS_UNSIGNED) + { + /*lint -e{734} converting unsigned 8-bit to signed 16-bit */ + pState->decoderL.x1 = (EAS_PCM)(((EAS_PCM) pState->srcByte << 8) ^ 0x8000); + } + else + { + /*lint -e{734} converting signed 8-bit to signed 16-bit */ + pState->decoderL.x1 = (EAS_PCM)((EAS_PCM) pState->srcByte << 8); + } + pState->bytesLeft--; + + /* fetch right sample */ + if(pState->flags & PCM_FLAGS_STEREO) + { + if ((result = EAS_HWGetByte(hwInstData, pState->fileHandle, &pState->srcByte)) != EAS_SUCCESS) + return result; + + /* if unsigned */ + if (pState->flags & PCM_FLAGS_UNSIGNED) + { + /*lint -e{734} converting unsigned 8-bit to signed 16-bit */ + pState->decoderR.x1 = (EAS_PCM)(((EAS_PCM) pState->srcByte << 8) ^ 0x8000); + } + else + { + /*lint -e{734} converting signed 8-bit to signed 16-bit */ + pState->decoderR.x1 = (EAS_PCM)((EAS_PCM) pState->srcByte << 8); + } + pState->bytesLeft--; + } + } + + /* must be 16-bit samples */ + else + { + //unsigned 16 bit currently not supported + if (pState->flags & PCM_FLAGS_UNSIGNED) + { + return EAS_ERROR_INVALID_PCM_TYPE; + } + + /* fetch left or mono sample */ + if ((result = EAS_HWGetWord(hwInstData, pState->fileHandle, &pState->decoderL.x1, EAS_FALSE)) != EAS_SUCCESS) + return result; + pState->bytesLeft -= 2; + + /* fetch right sample */ + if(pState->flags & PCM_FLAGS_STEREO) + { + if ((result = EAS_HWGetWord(hwInstData, pState->fileHandle, &pState->decoderR.x1, EAS_FALSE)) != EAS_SUCCESS) + return result; + pState->bytesLeft -= 2; + } + } + } + + /* no more data, force zero samples */ + else + pState->decoderL.x1 = pState->decoderR.x1 = 0; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * LinearPCMLocate() + *---------------------------------------------------------------------------- + * Purpose: + * Locate in a linear PCM stream + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT LinearPCMLocate (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState, EAS_I32 time) +{ + EAS_RESULT result; + EAS_I32 temp; + EAS_I32 secs, msecs; + EAS_INT shift; + + /* calculate size of sample frame */ + if (pState->flags & PCM_FLAGS_8_BIT) + shift = 0; + else + shift = 1; + if (pState->flags & PCM_FLAGS_STEREO) + shift++; + + /* break down into secs and msecs */ + secs = time / 1000; + msecs = time - (secs * 1000); + + /* calculate sample number fraction from msecs */ + temp = (msecs * pState->sampleRate); + temp = (temp >> 10) + ((temp * 49) >> 21); + + /* add integer sample count */ + temp += secs * pState->sampleRate; + + /* calculate the position based on sample frame size */ + /*lint -e{703} use shift for performance */ + temp <<= shift; + + /* past end of sample? */ + if (temp > (EAS_I32) pState->loopStart) + { + /* if not looped, flag error */ + if (pState->loopSamples == 0) + { + pState->bytesLeft = 0; + pState->flags |= PCM_FLAGS_EMPTY; + return EAS_ERROR_LOCATE_BEYOND_END; + } + + /* looped sample - calculate position in loop */ + while (temp > (EAS_I32) pState->loopStart) + temp -= (EAS_I32) pState->loopStart; + } + + /* seek to new position */ + if ((result = EAS_PESeek(pEASData, pState, &temp)) != EAS_SUCCESS) + return result; + + /* reset state */ + if ((pState->state != EAS_STATE_PAUSING) && (pState->state != EAS_STATE_PAUSED)) + pState->state = EAS_STATE_READY; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_PESeek + *---------------------------------------------------------------------------- + * Purpose: + * Locate to a particular byte in a PCM stream + *---------------------------------------------------------------------------- + * This bit is tricky because the chunks may not be contiguous, + * so we have to rely on the parser to position in the file. We + * do this by seeking to the end of each chunk and simulating an + * empty buffer condition until we get to where we want to go. + * + * A better solution would be a parser API for re-positioning, + * but there isn't time at the moment to re-factor all the + * parsers to support a new API. + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PESeek (S_EAS_DATA *pEASData, S_PCM_STATE *pState, EAS_I32 *pLocation) +{ + EAS_RESULT result; + + /* seek to start of audio */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pState->fileHandle, pState->startPos)) != EAS_SUCCESS) + { + pState->state = EAS_STATE_ERROR; + return result; + } + pState->bytesLeft = pState->bytesLeftLoop; + + /* skip through chunks until we find the right chunk */ + while (*pLocation > (EAS_I32) pState->bytesLeft) + { + /* seek to end of audio chunk */ + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "EAS_PESeek: Seek to offset = %d\n", pState->bytesLeft); */ } + if ((result = EAS_HWFileSeekOfs(pEASData->hwInstData, pState->fileHandle, pState->bytesLeft)) != EAS_SUCCESS) + { + pState->state = EAS_STATE_ERROR; + return result; + } + *pLocation -= pState->bytesLeft; + pState->bytesLeft = 0; + pState->flags |= PCM_FLAGS_EMPTY; + + /* retrieve more data */ + if (pState->pCallback) + (*pState->pCallback)(pEASData, pState->cbInstData, pState, EAS_STATE_EMPTY); + + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "EAS_PESeek: bytesLeft=%d, byte location = %d\n", pState->bytesLeft, *pLocation); */ } + + /* no more samples */ + if (pState->bytesLeft == 0) + return EAS_ERROR_LOCATE_BEYOND_END; + } + + /* seek to new offset in current chunk */ + if (*pLocation > 0) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "EAS_PESeek: Seek to offset = %d\n", *pLocation); */ } + if ((result = EAS_HWFileSeekOfs(pEASData->hwInstData, pState->fileHandle, *pLocation)) != EAS_SUCCESS) + { + pState->state = EAS_STATE_ERROR; + return result; + } + + /* if not streamed, calculate number of bytes left */ + if (pState->flags & PCM_FLAGS_STREAMING) + pState->bytesLeft = 0x7fffffff; + else + pState->bytesLeft -= *pLocation; + } + return EAS_SUCCESS; +} + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_pcm.h b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_pcm.h new file mode 100755 index 0000000..4fc77e9 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_pcm.h @@ -0,0 +1,359 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_pcm.h + * + * Contents and purpose: + * External function prototypes for eas_pcm.c module + * + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 847 $ + * $Date: 2007-08-27 21:30:08 -0700 (Mon, 27 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_PCM_H +#define _EAS_PCM_H + +/* default gain setting - roughly unity gain */ +#define PCM_DEFAULT_GAIN_SETTING 0x6000 + +typedef struct s_pcm_state_tag *EAS_PCM_HANDLE; +typedef void (*EAS_PCM_CALLBACK) (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR cbInstData, EAS_PCM_HANDLE pcmHandle, EAS_STATE state); + +/* parameters for EAS_PEOpenStream */ +typedef struct s_pcm_open_params_tag +{ + EAS_FILE_HANDLE fileHandle; + EAS_I32 decoder; + EAS_U32 sampleRate; + EAS_I32 size; + EAS_U32 loopStart; + EAS_U32 loopSamples; + EAS_I32 blockSize; + EAS_U32 flags; + EAS_U32 envData; + EAS_I16 volume; + EAS_PCM_CALLBACK pCallbackFunc; + EAS_VOID_PTR cbInstData; + } S_PCM_OPEN_PARAMS; + +/*---------------------------------------------------------------------------- + * EAS_PEInit() + *---------------------------------------------------------------------------- + * Purpose: + * Initializes the PCM engine + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEInit (EAS_DATA_HANDLE pEASData); + +/*---------------------------------------------------------------------------- + * EAS_PEShutdown() + *---------------------------------------------------------------------------- + * Purpose: + * Shuts down the PCM engine + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEShutdown (EAS_DATA_HANDLE pEASData); + +/*---------------------------------------------------------------------------- + * EAS_PEOpenStream() + *---------------------------------------------------------------------------- + * Purpose: + * Starts up a PCM playback + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEOpenStream (EAS_DATA_HANDLE pEASData, S_PCM_OPEN_PARAMS *pParams, EAS_PCM_HANDLE *pHandle); + +/*---------------------------------------------------------------------------- + * EAS_PEContinueStream() + *---------------------------------------------------------------------------- + * Purpose: + * Continues a PCM stream + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEContinueStream (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE handle, EAS_I32 size); + +/*---------------------------------------------------------------------------- + * EAS_PEGetFileHandle() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the file handle of a stream + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEGetFileHandle (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE handle, EAS_FILE_HANDLE *pFileHandle); + +/*---------------------------------------------------------------------------- + * EAS_PERender() + *---------------------------------------------------------------------------- + * Purpose: + * Render a buffer of PCM audio + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PERender (EAS_DATA_HANDLE pEASData, EAS_I32 numSamples); + +/*---------------------------------------------------------------------------- + * EAS_PEUpdateParams() + *---------------------------------------------------------------------------- + * Purpose: + * Update the pitch and volume parameters using MIDI controls + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEUpdateParams (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE pState, EAS_I16 pitch, EAS_I16 gainLeft, EAS_I16 gainRight); + +/*---------------------------------------------------------------------------- + * EAS_PELocate() + *---------------------------------------------------------------------------- + * Purpose: + * This function seeks to the requested place in the file. Accuracy + * is dependent on the sample rate and block size. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * pState - stream handle + * time - media time in milliseconds + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PELocate (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE pState, EAS_I32 time); + +/*---------------------------------------------------------------------------- + * EAS_PEUpdateVolume() + *---------------------------------------------------------------------------- + * Purpose: + * Update the volume parameters for a PCM stream + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_PCM_STATE for this stream + * gainLeft - linear gain multipler in 1.15 fraction format + * gainRight - linear gain multipler in 1.15 fraction format + * initial - initial settings, set current gain + * + * Outputs: + * + * + * Side Effects: + * + * Notes + * In mono mode, leftGain controls the output gain and rightGain is ignored + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT EAS_PEUpdateVolume (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE pState, EAS_I16 volume); + +/*---------------------------------------------------------------------------- + * EAS_PEUpdatePitch() + *---------------------------------------------------------------------------- + * Purpose: + * Update the pitch parameter for a PCM stream + * + * Inputs: + * pEASData - pointer to EAS library instance data + * pState - pointer to S_PCM_STATE for this stream + * pitch - new pitch value in pitch cents + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT EAS_PEUpdatePitch (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE pState, EAS_I16 pitch); + +/*---------------------------------------------------------------------------- + * EAS_PEState() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current state of the stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * pState - pointer to variable to store state + * + * Outputs: + * + * + * Side Effects: + * + * Notes: + * This interface is also exposed in the internal library for use by the other modules. + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEState (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE handle, EAS_STATE *pState); + +/*---------------------------------------------------------------------------- + * EAS_PEClose() + *---------------------------------------------------------------------------- + * Purpose: + * Close the file and clean up + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEClose (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE handle); + +/*---------------------------------------------------------------------------- + * EAS_PEReset() + *---------------------------------------------------------------------------- + * Purpose: + * Reset the sequencer. Used for locating backwards in the file. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEReset (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE handle); + +/*---------------------------------------------------------------------------- + * EAS_PEPause() + *---------------------------------------------------------------------------- + * Purpose: + * Mute and pause rendering a PCM stream. Sets the gain target to zero and stops the playback + * at the end of the next audio frame. + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_PCM_STATE for this stream + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEPause (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE handle); + +/*---------------------------------------------------------------------------- + * EAS_PEResume() + *---------------------------------------------------------------------------- + * Purpose: + * Resume rendering a PCM stream. Sets the gain target back to its + * previous setting and restarts playback at the end of the next audio + * frame. + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_PCM_STATE for this stream + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PEResume (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE handle); + +/*---------------------------------------------------------------------------- + * EAS_PERelease() + *---------------------------------------------------------------------------- + * Purpose: + * Put the PCM stream envelope into release. + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_PCM_STATE for this stream + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PERelease (EAS_DATA_HANDLE pEASData, EAS_PCM_HANDLE handle); + +#endif /* end _EAS_PCM_H */ + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_pcmdata.c b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_pcmdata.c new file mode 100755 index 0000000..2d85ac2 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_pcmdata.c @@ -0,0 +1,35 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_pcmdata.c + * + * Contents and purpose: + * Contains the static data for the PCM engine. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 547 $ + * $Date: 2007-01-31 16:30:17 -0800 (Wed, 31 Jan 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_data.h" + +/* static data allocation */ +S_PCM_STATE eas_PCMData[MAX_PCM_STREAMS]; + + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_pcmdata.h b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_pcmdata.h new file mode 100755 index 0000000..ae18d6d --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_pcmdata.h @@ -0,0 +1,157 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_pcmdata.h + * + * Contents and purpose: + * Data declarations for the PCM engine + * + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 847 $ + * $Date: 2007-08-27 21:30:08 -0700 (Mon, 27 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_PCMDATA_H +#define _EAS_PCMDATA_H + +/* sets the maximum number of simultaneous PCM streams */ +#ifndef MAX_PCM_STREAMS +#define MAX_PCM_STREAMS 16 +#define PCM_STREAM_THRESHOLD (MAX_PCM_STREAMS - 4) +#endif + +/* coefficents for high-pass filter in ADPCM */ +#define INTEGRATOR_COEFFICIENT 100 /* coefficient for leaky integrator */ + +/* additional flags in S_PCM_STATE.flags used internal to module */ +#define PCM_FLAGS_EMPTY 0x01000000 /* unsigned format */ + +/*---------------------------------------------------------------------------- + * S_PCM_STATE + * + * Retains state information for PCM streams. + *---------------------------------------------------------------------------- +*/ +typedef struct s_decoder_state_tag +{ + EAS_I32 output; /* last output for DC offset filter */ + EAS_I32 acc; /* accumulator for DC offset filter */ + EAS_I32 step; /* current ADPCM step size */ + EAS_PCM x1; /* current generated sample */ + EAS_PCM x0; /* previous generated sample */ +} S_DECODER_STATE; + +typedef enum +{ + PCM_ENV_START = 0, + PCM_ENV_ATTACK, + PCM_ENV_DECAY, + PCM_ENV_SUSTAIN, + PCM_ENV_RELEASE, + PCM_ENV_END +} E_PCM_ENV_STATE; + +typedef struct s_pcm_state_tag +{ +#ifdef _CHECKED_BUILD + EAS_U32 handleCheck; /* signature check for checked build */ +#endif + EAS_FILE_HANDLE fileHandle; /* pointer to input file */ + EAS_PCM_CALLBACK pCallback; /* pointer to callback function */ + EAS_VOID_PTR cbInstData; /* instance data for callback function */ + struct s_decoder_interface_tag EAS_CONST * pDecoder; /* pointer to decoder interface */ + EAS_STATE state; /* stream state */ + EAS_I32 time; /* media time */ + EAS_I32 startPos; /* start of PCM stream */ + EAS_I32 loopLocation; /* file location where loop starts */ + EAS_I32 byteCount; /* size of file */ + EAS_U32 loopStart; /* loop start, offset in samples from startPos */ + /* NOTE: For CMF, we use this to store total sample size */ + EAS_U32 loopSamples; /* total loop length, in samples, 0 means no loop */ + /* NOTE: For CMF, non-zero means looped */ + EAS_U32 samplesInLoop; /* samples left in the loop to play back */ + EAS_I32 samplesTilLoop; /* samples left to play until top of loop */ + EAS_I32 bytesLeft; /* count of bytes left in stream */ + EAS_I32 bytesLeftLoop; /* count of bytes left in stream, value at start of loop */ + EAS_U32 phase; /* current phase for interpolator */ + EAS_U32 basefreq; /* frequency multiplier */ + EAS_U32 flags; /* stream flags */ + EAS_U32 envData; /* envelope data (and LFO data) */ + EAS_U32 envValue; /* current envelope value */ + EAS_U32 envScale; /* current envelope scale */ + EAS_U32 startOrder; /* start order index, first is 0, next is 1, etc. */ + S_DECODER_STATE decoderL; /* left (mono) ADPCM state */ + S_DECODER_STATE decoderR; /* right ADPCM state */ + S_DECODER_STATE decoderLLoop; /* left (mono) ADPCM state, value at start of loop */ + S_DECODER_STATE decoderRLoop; /* right ADPCM state, value at start of loop */ + E_PCM_ENV_STATE envState; /* current envelope state */ + EAS_I16 volume; /* volume for stream */ + EAS_I16 pitch; /* relative pitch in cents - zero is unity playback */ + EAS_I16 gainLeft; /* requested gain */ + EAS_I16 gainRight; /* requested gain */ + EAS_I16 currentGainLeft; /* current gain for anti-zipper filter */ + EAS_I16 currentGainRight; /* current gain for anti-zipper filter */ + EAS_U16 blockSize; /* block size for ADPCM decoder */ + EAS_U16 blockCount; /* block counter for ADPCM decoder */ + EAS_U16 sampleRate; /* input sample rate */ + EAS_U8 srcByte; /* source byte */ + EAS_U8 msBitCount; /* count keeps track of MS bits */ + EAS_U8 msBitMask; /* mask keeps track of MS bits */ + EAS_U8 msBitValue; /* value keeps track of MS bits */ + EAS_U8 msBitCountLoop; /* count keeps track of MS bits, value at loop start */ + EAS_U8 msBitMaskLoop; /* mask keeps track of MS bits, value at loop start */ + EAS_U8 msBitValueLoop; /* value keeps track of MS bits, value at loop start */ + EAS_BOOL8 hiNibble; /* indicates high/low nibble is next */ + EAS_BOOL8 hiNibbleLoop; /* indicates high/low nibble is next, value loop start */ + EAS_U8 rateShift; /* for playback rate greater than 1.0 */ +} S_PCM_STATE; + +/*---------------------------------------------------------------------------- + * S_DECODER_INTERFACE + * + * Generic interface for audio decoders + *---------------------------------------------------------------------------- +*/ +typedef struct s_decoder_interface_tag +{ + EAS_RESULT (* EAS_CONST pfInit)(EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState); + EAS_RESULT (* EAS_CONST pfDecodeSample)(EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState); + EAS_RESULT (* EAS_CONST pfLocate)(EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState, EAS_I32 time); +} S_DECODER_INTERFACE; + + +/* header chunk for SMAF ADPCM */ +#define TAG_YAMAHA_ADPCM 0x4d776100 +#define TAG_MASK 0xffffff00 +#define TAG_RIFF_FILE 0x52494646 +#define TAG_WAVE_CHUNK 0x57415645 +#define TAG_FMT_CHUNK 0x666d7420 + +/*---------------------------------------------------------------------------- + * EAS_PESeek + *---------------------------------------------------------------------------- + * Purpose: + * Locate to a particular byte in a PCM stream + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_PESeek (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState, EAS_I32 *pLocation); + +#endif /* _EAS_PCMDATA_H */ + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_public.c b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_public.c new file mode 100755 index 0000000..9ee6cf4 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_public.c @@ -0,0 +1,2601 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_public.c + * + * Contents and purpose: + * Contains EAS library public interface + * + * Copyright Sonic Network Inc. 2004 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 842 $ + * $Date: 2007-08-23 14:32:31 -0700 (Thu, 23 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_synthcfg.h" +#include "eas.h" +#include "eas_config.h" +#include "eas_host.h" +#include "eas_report.h" +#include "eas_data.h" +#include "eas_parser.h" +#include "eas_pcm.h" +#include "eas_midi.h" +#include "eas_mixer.h" +#include "eas_build.h" +#include "eas_vm_protos.h" +#include "eas_math.h" + +#ifdef JET_INTERFACE +#include "jet_data.h" +#endif + +#ifdef DLS_SYNTHESIZER +#include "eas_mdls.h" +#endif + +/* number of events to parse before calling EAS_HWYield function */ +#define YIELD_EVENT_COUNT 10 + +/*---------------------------------------------------------------------------- + * easLibConfig + * + * This structure is available through the EAS public interface to allow + * the user to check the configuration of the library. + *---------------------------------------------------------------------------- +*/ +static const S_EAS_LIB_CONFIG easLibConfig = +{ + LIB_VERSION, +#ifdef _CHECKED_BUILD + EAS_TRUE, +#else + EAS_FALSE, +#endif + MAX_SYNTH_VOICES, + NUM_OUTPUT_CHANNELS, + _OUTPUT_SAMPLE_RATE, + BUFFER_SIZE_IN_MONO_SAMPLES, +#ifdef _FILTER_ENABLED + EAS_TRUE, +#else + EAS_FALSE, +#endif + _BUILD_TIME_, + _BUILD_VERSION_ +}; + +/* local prototypes */ +static EAS_RESULT EAS_ParseEvents (S_EAS_DATA *pEASData, S_EAS_STREAM *pStream, EAS_U32 endTime, EAS_INT parseMode); + +/*---------------------------------------------------------------------------- + * EAS_SetStreamParameter + *---------------------------------------------------------------------------- + * Sets the specified parameter in the stream. Allows access to + * customizable settings within the individual file parsers. + *---------------------------------------------------------------------------- + * pEASData - pointer to EAS persistent data object + * pStream - stream handle + * param - enumerated parameter (see eas_parser.h) + * value - new value + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_SetStreamParameter (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_I32 param, EAS_I32 value) +{ + S_FILE_PARSER_INTERFACE *pParserModule; + + pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; + if (pParserModule->pfSetData) + return (*pParserModule->pfSetData)(pEASData, pStream->handle, param, value); + return EAS_ERROR_FEATURE_NOT_AVAILABLE; +} + +/*---------------------------------------------------------------------------- + * EAS_GetStreamParameter + *---------------------------------------------------------------------------- + * Sets the specified parameter in the stream. Allows access to + * customizable settings within the individual file parsers. + *---------------------------------------------------------------------------- + * pEASData - pointer to EAS persistent data object + * pStream - stream handle + * param - enumerated parameter (see eas_parser.h) + * pValue - pointer to variable to receive current setting + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_GetStreamParameter (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_I32 param, EAS_I32 *pValue) +{ + S_FILE_PARSER_INTERFACE *pParserModule; + + pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; + if (pParserModule->pfGetData) + return (*pParserModule->pfGetData)(pEASData, pStream->handle, param, pValue); + return EAS_ERROR_FEATURE_NOT_AVAILABLE; +} + +/*---------------------------------------------------------------------------- + * EAS_StreamReady() + *---------------------------------------------------------------------------- + * This routine sets common parameters like transpose, volume, etc. + * First, it attempts to use the parser EAS_SetStreamParameter interface. If that + * fails, it attempts to get the synth handle from the parser and + * set the parameter directly on the synth. This eliminates duplicate + * code in the parser. + *---------------------------------------------------------------------------- +*/ +EAS_BOOL EAS_StreamReady (S_EAS_DATA *pEASData, EAS_HANDLE pStream) +{ + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_STATE state; + + pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; + if (pParserModule->pfState(pEASData, pStream->handle, &state) != EAS_SUCCESS) + return EAS_FALSE; + return (state < EAS_STATE_OPEN); +} + +/*---------------------------------------------------------------------------- + * EAS_IntSetStrmParam() + *---------------------------------------------------------------------------- + * This routine sets common parameters like transpose, volume, etc. + * First, it attempts to use the parser EAS_SetStreamParameter interface. If that + * fails, it attempts to get the synth handle from the parser and + * set the parameter directly on the synth. This eliminates duplicate + * code in the parser. + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_IntSetStrmParam (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_INT param, EAS_I32 value) +{ + S_SYNTH *pSynth; + + /* try to set the parameter using stream interface */ + if (EAS_SetStreamParameter(pEASData, pStream, param, value) == EAS_SUCCESS) + return EAS_SUCCESS; + + /* get a pointer to the synth object and set it directly */ + /*lint -e{740} we are cheating by passing a pointer through this interface */ + if (EAS_GetStreamParameter(pEASData, pStream, PARSER_DATA_SYNTH_HANDLE, (EAS_I32*) &pSynth) != EAS_SUCCESS) + return EAS_ERROR_INVALID_PARAMETER; + + if (pSynth == NULL) + return EAS_ERROR_INVALID_PARAMETER; + + switch (param) + { + +#ifdef DLS_SYNTHESIZER + case PARSER_DATA_DLS_COLLECTION: + { + EAS_RESULT result = VMSetDLSLib(pSynth, (EAS_DLSLIB_HANDLE) value); + if (result == EAS_SUCCESS) + { + DLSAddRef((S_DLS*) value); + VMInitializeAllChannels(pEASData->pVoiceMgr, pSynth); + } + return result; + } +#endif + + case PARSER_DATA_EAS_LIBRARY: + return VMSetEASLib(pSynth, (EAS_SNDLIB_HANDLE) value); + + case PARSER_DATA_POLYPHONY: + return VMSetPolyphony(pEASData->pVoiceMgr, pSynth, value); + + case PARSER_DATA_PRIORITY: + return VMSetPriority(pEASData->pVoiceMgr, pSynth, value); + + case PARSER_DATA_TRANSPOSITION: + VMSetTranposition(pSynth, value); + break; + + case PARSER_DATA_VOLUME: + VMSetVolume(pSynth, (EAS_U16) value); + break; + + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Invalid paramter %d in call to EAS_IntSetStrmParam", param); */ } + return EAS_ERROR_INVALID_PARAMETER; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_IntGetStrmParam() + *---------------------------------------------------------------------------- + * This routine gets common parameters like transpose, volume, etc. + * First, it attempts to use the parser EAS_GetStreamParameter interface. If that + * fails, it attempts to get the synth handle from the parser and + * get the parameter directly on the synth. + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_IntGetStrmParam (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_INT param, EAS_I32 *pValue) +{ + S_SYNTH *pSynth; + + /* try to set the parameter */ + if (EAS_GetStreamParameter(pEASData, pStream, param, pValue) == EAS_SUCCESS) + return EAS_SUCCESS; + + /* get a pointer to the synth object and retrieve data directly */ + /*lint -e{740} we are cheating by passing a pointer through this interface */ + if (EAS_GetStreamParameter(pEASData, pStream, PARSER_DATA_SYNTH_HANDLE, (EAS_I32*) &pSynth) != EAS_SUCCESS) + return EAS_ERROR_INVALID_PARAMETER; + + if (pSynth == NULL) + return EAS_ERROR_INVALID_PARAMETER; + + switch (param) + { + case PARSER_DATA_POLYPHONY: + return VMGetPolyphony(pEASData->pVoiceMgr, pSynth, pValue); + + case PARSER_DATA_PRIORITY: + return VMGetPriority(pEASData->pVoiceMgr, pSynth, pValue); + + case PARSER_DATA_TRANSPOSITION: + VMGetTranposition(pSynth, pValue); + break; + + case PARSER_DATA_NOTE_COUNT: + *pValue = VMGetNoteCount(pSynth); + break; + + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Invalid paramter %d in call to EAS_IntSetStrmParam", param); */ } + return EAS_ERROR_INVALID_PARAMETER; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_AllocateStream() + *---------------------------------------------------------------------------- + * Purpose: + * Allocates a stream handle + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static EAS_INT EAS_AllocateStream (EAS_DATA_HANDLE pEASData) +{ + EAS_INT streamNum; + + /* check for static allocation, only one stream allowed */ + if (pEASData->staticMemoryModel) + { + if (pEASData->streams[0].handle != NULL) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Attempt to open multiple streams in static model\n"); */ } + return -1; + } + return 0; + } + + /* dynamic model */ + for (streamNum = 0; streamNum < MAX_NUMBER_STREAMS; streamNum++) + if (pEASData->streams[streamNum].handle == NULL) + break; + if (streamNum == MAX_NUMBER_STREAMS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Exceeded maximum number of open streams\n"); */ } + return -1; + } + return streamNum; +} + +/*---------------------------------------------------------------------------- + * EAS_InitStream() + *---------------------------------------------------------------------------- + * Purpose: + * Initialize a stream + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static void EAS_InitStream (S_EAS_STREAM *pStream, EAS_VOID_PTR pParserModule, EAS_VOID_PTR streamHandle) +{ + pStream->pParserModule = pParserModule; + pStream->handle = streamHandle; + pStream->time = 0; + pStream->frameLength = AUDIO_FRAME_LENGTH; + pStream->repeatCount = 0; + pStream->volume = DEFAULT_STREAM_VOLUME; + pStream->streamFlags = 0; +} + +/*---------------------------------------------------------------------------- + * EAS_Config() + *---------------------------------------------------------------------------- + * Purpose: + * Returns a pointer to a structure containing the configuration options + * in this library build. + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC const S_EAS_LIB_CONFIG *EAS_Config (void) +{ + return &easLibConfig; +} + +/*---------------------------------------------------------------------------- + * EAS_Init() + *---------------------------------------------------------------------------- + * Purpose: + * Initialize the synthesizer library + * + * Inputs: + * ppEASData - pointer to data handle variable for this instance + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Init (EAS_DATA_HANDLE *ppEASData) +{ + EAS_HW_DATA_HANDLE pHWInstData; + EAS_RESULT result; + S_EAS_DATA *pEASData; + EAS_INT module; + EAS_BOOL staticMemoryModel; + + /* get the memory model */ + staticMemoryModel = EAS_CMStaticMemoryModel(); + + /* initialize the host wrapper interface */ + *ppEASData = NULL; + if ((result = EAS_HWInit(&pHWInstData)) != EAS_SUCCESS) + return result; + + /* check Configuration Module for S_EAS_DATA allocation */ + if (staticMemoryModel) + pEASData = EAS_CMEnumData(EAS_CM_EAS_DATA); + else + pEASData = EAS_HWMalloc(pHWInstData, sizeof(S_EAS_DATA)); + if (!pEASData) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Failed to allocate EAS library memory\n"); */ } + return EAS_ERROR_MALLOC_FAILED; + } + + /* initialize some data */ + EAS_HWMemSet(pEASData, 0, sizeof(S_EAS_DATA)); + pEASData->staticMemoryModel = (EAS_BOOL8) staticMemoryModel; + pEASData->hwInstData = pHWInstData; + pEASData->renderTime = 0; + + /* set header search flag */ +#ifdef FILE_HEADER_SEARCH + pEASData->searchHeaderFlag = EAS_TRUE; +#endif + + /* initalize parameters */ + EAS_SetVolume(pEASData, NULL, DEFAULT_VOLUME); + +#ifdef _METRICS_ENABLED + /* initalize the metrics module */ + pEASData->pMetricsModule = EAS_CMEnumOptModules(EAS_MODULE_METRICS); + if (pEASData->pMetricsModule != NULL) + { + if ((result = (*pEASData->pMetricsModule->pfInit)(pEASData, &pEASData->pMetricsData)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld initializing metrics module\n", result); */ } + return result; + } + } +#endif + + /* initailize the voice manager & synthesizer */ + if ((result = VMInitialize(pEASData)) != EAS_SUCCESS) + return result; + + /* initialize mix engine */ + if ((result = EAS_MixEngineInit(pEASData)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld starting up mix engine\n", result); */ } + return result; + } + + /* initialize effects modules */ + for (module = 0; module < NUM_EFFECTS_MODULES; module++) + { + pEASData->effectsModules[module].effect = EAS_CMEnumFXModules(module); + if (pEASData->effectsModules[module].effect != NULL) + { + if ((result = (*pEASData->effectsModules[module].effect->pfInit)(pEASData, &pEASData->effectsModules[module].effectData)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Initialization of effects module %d returned %d\n", module, result); */ } + return result; + } + } + } + + /* initialize PCM engine */ + if ((result = EAS_PEInit(pEASData)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "EAS_PEInit failed with error code %ld\n", result); */ } + return result; + } + + /* return instance data pointer to host */ + *ppEASData = pEASData; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_Shutdown() + *---------------------------------------------------------------------------- + * Purpose: + * Shuts down the library. Deallocates any memory associated with the + * synthesizer (dynamic memory model only) + * + * Inputs: + * pEASData - handle to data for this instance + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Shutdown (EAS_DATA_HANDLE pEASData) +{ + EAS_HW_DATA_HANDLE hwInstData; + EAS_RESULT result, reportResult; + EAS_INT i; + + /* establish pointers */ + hwInstData = pEASData->hwInstData; + + /* check for NULL handle */ + if (!pEASData) + return EAS_ERROR_HANDLE_INTEGRITY; + + /* if there are streams open, close them */ + reportResult = EAS_SUCCESS; + for (i = 0; i < MAX_NUMBER_STREAMS; i++) + { + if (pEASData->streams[i].pParserModule && pEASData->streams[i].handle) + { + if ((result = (*((S_FILE_PARSER_INTERFACE*)(pEASData->streams[i].pParserModule))->pfClose)(pEASData, pEASData->streams[i].handle)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld shutting down parser module\n", result); */ } + reportResult = result; + } + } + } + + /* shutdown PCM engine */ + if ((result = EAS_PEShutdown(pEASData)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld shutting down PCM engine\n", result); */ } + if (reportResult == EAS_SUCCESS) + reportResult = result; + } + + /* shutdown mix engine */ + if ((result = EAS_MixEngineShutdown(pEASData)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld shutting down mix engine\n", result); */ } + if (reportResult == EAS_SUCCESS) + reportResult = result; + } + + /* shutdown effects modules */ + for (i = 0; i < NUM_EFFECTS_MODULES; i++) + { + if (pEASData->effectsModules[i].effect) + { + if ((result = (*pEASData->effectsModules[i].effect->pfShutdown)(pEASData, pEASData->effectsModules[i].effectData)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Shutdown of effects module %d returned %d\n", i, result); */ } + if (reportResult == EAS_SUCCESS) + reportResult = result; + } + } + } + + /* shutdown the voice manager & synthesizer */ + VMShutdown(pEASData); + +#ifdef _METRICS_ENABLED + /* shutdown the metrics module */ + if (pEASData->pMetricsModule != NULL) + { + if ((result = (*pEASData->pMetricsModule->pfShutdown)(pEASData, pEASData->pMetricsData)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld shutting down metrics module\n", result); */ } + if (reportResult == EAS_SUCCESS) + reportResult = result; + } + } +#endif + + /* release allocated memory */ + if (!pEASData->staticMemoryModel) + EAS_HWFree(hwInstData, pEASData); + + /* shutdown host wrappers */ + if (hwInstData) + { + if ((result = EAS_HWShutdown(hwInstData)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld shutting down host wrappers\n", result); */ } + if (reportResult == EAS_SUCCESS) + reportResult = result; + } + } + + return reportResult; +} + +#ifdef JET_INTERFACE +/*---------------------------------------------------------------------------- + * EAS_OpenJETStream() + *---------------------------------------------------------------------------- + * Private interface for JET to open an SMF stream with an offset + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_OpenJETStream (EAS_DATA_HANDLE pEASData, EAS_FILE_HANDLE fileHandle, EAS_I32 offset, EAS_HANDLE *ppStream) +{ + EAS_RESULT result; + EAS_VOID_PTR streamHandle; + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_INT streamNum; + + /* allocate a stream */ + if ((streamNum = EAS_AllocateStream(pEASData)) < 0) + return EAS_ERROR_MAX_STREAMS_OPEN; + + /* check Configuration Module for SMF parser */ + *ppStream = NULL; + streamHandle = NULL; + pParserModule = (S_FILE_PARSER_INTERFACE *) EAS_CMEnumModules(0); + if (pParserModule == NULL) + return EAS_ERROR_UNRECOGNIZED_FORMAT; + + /* see if SMF parser recognizes the file */ + if ((result = (*pParserModule->pfCheckFileType)(pEASData, fileHandle, &streamHandle, offset)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "CheckFileType returned error %ld\n", result); */ } + return result; + } + + /* parser recognized the file, return the handle */ + if (streamHandle) + { + EAS_InitStream(&pEASData->streams[streamNum], pParserModule, streamHandle); + *ppStream = &pEASData->streams[streamNum]; + return EAS_SUCCESS; + } + + return EAS_ERROR_UNRECOGNIZED_FORMAT; +} +#endif + +/*---------------------------------------------------------------------------- + * EAS_OpenFile() + *---------------------------------------------------------------------------- + * Purpose: + * Opens a file for audio playback. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * pHandle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_OpenFile (EAS_DATA_HANDLE pEASData, EAS_FILE_LOCATOR locator, EAS_HANDLE *ppStream) +{ + EAS_RESULT result; + EAS_FILE_HANDLE fileHandle; + EAS_VOID_PTR streamHandle; + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_INT streamNum; + EAS_INT moduleNum; + + /* open the file */ + if ((result = EAS_HWOpenFile(pEASData->hwInstData, locator, &fileHandle, EAS_FILE_READ)) != EAS_SUCCESS) + return result; + + /* allocate a stream */ + if ((streamNum = EAS_AllocateStream(pEASData)) < 0) + return EAS_ERROR_MAX_STREAMS_OPEN; + + /* check Configuration Module for file parsers */ + pParserModule = NULL; + *ppStream = NULL; + streamHandle = NULL; + for (moduleNum = 0; ; moduleNum++) + { + pParserModule = (S_FILE_PARSER_INTERFACE *) EAS_CMEnumModules(moduleNum); + if (pParserModule == NULL) + break; + + /* see if this parser recognizes it */ + if ((result = (*pParserModule->pfCheckFileType)(pEASData, fileHandle, &streamHandle, 0L)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "CheckFileType returned error %ld\n", result); */ } + return result; + } + + /* parser recognized the file, return the handle */ + if (streamHandle) + { + + /* save the parser pointer and file handle */ + EAS_InitStream(&pEASData->streams[streamNum], pParserModule, streamHandle); + *ppStream = &pEASData->streams[streamNum]; + return EAS_SUCCESS; + } + + /* rewind the file for the next parser */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, 0L)) != EAS_SUCCESS) + return result; + } + + /* no parser was able to recognize the file, close it and return an error */ + EAS_HWCloseFile(pEASData->hwInstData, fileHandle); + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "No parser recognized the requested file\n"); */ } + return EAS_ERROR_UNRECOGNIZED_FORMAT; +} + +#ifdef MMAPI_SUPPORT +/*---------------------------------------------------------------------------- + * EAS_MMAPIToneControl() + *---------------------------------------------------------------------------- + * Purpose: + * Opens a ToneControl file for audio playback. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * pHandle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_MMAPIToneControl (EAS_DATA_HANDLE pEASData, EAS_FILE_LOCATOR locator, EAS_HANDLE *ppStream) +{ + EAS_RESULT result; + EAS_FILE_HANDLE fileHandle; + EAS_VOID_PTR streamHandle; + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_INT streamNum; + + /* check if the tone control parser is available */ + *ppStream = NULL; + streamHandle = NULL; + pParserModule = EAS_CMEnumOptModules(EAS_MODULE_MMAPI_TONE_CONTROL); + if (pParserModule == NULL) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_MMAPIToneControl: ToneControl parser not available\n"); */ } + return EAS_ERROR_FEATURE_NOT_AVAILABLE; + } + + /* open the file */ + if ((result = EAS_HWOpenFile(pEASData->hwInstData, locator, &fileHandle, EAS_FILE_READ)) != EAS_SUCCESS) + return result; + + /* allocate a stream */ + if ((streamNum = EAS_AllocateStream(pEASData)) < 0) + return EAS_ERROR_MAX_STREAMS_OPEN; + + /* see if ToneControl parser recognizes it */ + if ((result = (*pParserModule->pfCheckFileType)(pEASData, fileHandle, &streamHandle, 0L)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "CheckFileType returned error %ld\n", result); */ } + return result; + } + + /* parser accepted the file, return the handle */ + if (streamHandle) + { + + /* save the parser pointer and file handle */ + EAS_InitStream(&pEASData->streams[streamNum], pParserModule, streamHandle); + *ppStream = &pEASData->streams[streamNum]; + return EAS_SUCCESS; + } + + /* parser did not recognize the file, close it and return an error */ + EAS_HWCloseFile(pEASData->hwInstData, fileHandle); + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "No parser recognized the requested file\n"); */ } + return EAS_ERROR_UNRECOGNIZED_FORMAT; +} + +/*---------------------------------------------------------------------------- + * EAS_GetWaveFmtChunk + *---------------------------------------------------------------------------- + * Helper function to retrieve WAVE file fmt chunk for MMAPI + *---------------------------------------------------------------------------- + * pEASData - pointer to EAS persistent data object + * pStream - stream handle + * pFmtChunk - pointer to variable to receive current setting + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetWaveFmtChunk (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_VOID_PTR *ppFmtChunk) +{ + EAS_RESULT result; + EAS_I32 value; + + if ((result = EAS_GetStreamParameter(pEASData, pStream, PARSER_DATA_FORMAT, &value)) != EAS_SUCCESS) + return result; + *ppFmtChunk = (EAS_VOID_PTR) value; + return EAS_SUCCESS; +} +#endif + +/*---------------------------------------------------------------------------- + * EAS_GetFileType + *---------------------------------------------------------------------------- + * Returns the file type (see eas_types.h for enumerations) + *---------------------------------------------------------------------------- + * pEASData - pointer to EAS persistent data object + * pStream - stream handle + * pFileType - pointer to variable to receive file type + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetFileType (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_I32 *pFileType) +{ + if (!EAS_StreamReady (pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + return EAS_GetStreamParameter(pEASData, pStream, PARSER_DATA_FILE_TYPE, pFileType); +} + +/*---------------------------------------------------------------------------- + * EAS_Prepare() + *---------------------------------------------------------------------------- + * Purpose: + * Prepares the synthesizer to play the file or stream. Parses the first + * frame of data from the file and arms the synthesizer. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - file or stream handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Prepare (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream) +{ + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_STATE state; + EAS_RESULT result; + + pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; + if (pParserModule == NULL) + return EAS_ERROR_FEATURE_NOT_AVAILABLE; + + /* check for valid state */ + result = pParserModule->pfState(pEASData, pStream->handle, &state); + if (result == EAS_SUCCESS) + { + /* prepare the stream */ + if (state == EAS_STATE_OPEN) + { + pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; + result = (*pParserModule->pfPrepare)(pEASData, pStream->handle); + + /* set volume */ + if (result == EAS_SUCCESS) + result = EAS_SetVolume(pEASData, pStream, pStream->volume); + } + else + result = EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + } + + return result; +} + +/*---------------------------------------------------------------------------- + * EAS_Render() + *---------------------------------------------------------------------------- + * Purpose: + * Parse the Midi data and render PCM audio data. + * + * Inputs: + * pEASData - buffer for internal EAS data + * pOut - output buffer pointer + * nNumRequested - requested num samples to generate + * pnNumGenerated - actual number of samples generated + * + * Outputs: + * EAS_SUCCESS if PCM data was successfully rendered + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Render (EAS_DATA_HANDLE pEASData, EAS_PCM *pOut, EAS_I32 numRequested, EAS_I32 *pNumGenerated) +{ + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_RESULT result; + EAS_I32 voicesRendered; + EAS_STATE parserState; + EAS_INT streamNum; + + /* assume no samples generated and reset workload */ + *pNumGenerated = 0; + VMInitWorkload(pEASData->pVoiceMgr); + + /* no support for other buffer sizes yet */ + if (numRequested != BUFFER_SIZE_IN_MONO_SAMPLES) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "This library supports only %ld samples in buffer, host requested %ld samples\n", + (EAS_I32) BUFFER_SIZE_IN_MONO_SAMPLES, numRequested); */ } + return EAS_BUFFER_SIZE_MISMATCH; + } + +#ifdef _METRICS_ENABLED + /* start performance counter */ + if (pEASData->pMetricsData) + (*pEASData->pMetricsModule->pfStartTimer)(pEASData->pMetricsData, EAS_PM_TOTAL_TIME); +#endif + + /* prep the frame buffer, do mix engine prep only if TRUE */ +#ifdef _SPLIT_ARCHITECTURE + if (VMStartFrame(pEASData)) + EAS_MixEnginePrep(pEASData, numRequested); +#else + /* prep the mix engine */ + EAS_MixEnginePrep(pEASData, numRequested); +#endif + + /* save the output buffer pointer */ + pEASData->pOutputAudioBuffer = pOut; + + +#ifdef _METRICS_ENABLED + /* start performance counter */ + if (pEASData->pMetricsData) + (*pEASData->pMetricsModule->pfStartTimer)(pEASData->pMetricsData, EAS_PM_PARSE_TIME); +#endif + + /* if we haven't finished parsing from last time, do it now */ + /* need to parse another frame of events before we render again */ + for (streamNum = 0; streamNum < MAX_NUMBER_STREAMS; streamNum++) + { + /* clear the locate flag */ + pEASData->streams[streamNum].streamFlags &= ~STREAM_FLAGS_LOCATE; + + if (pEASData->streams[streamNum].pParserModule) + { + + /* establish pointer to parser module */ + pParserModule = pEASData->streams[streamNum].pParserModule; + + /* handle pause */ + if (pEASData->streams[streamNum].streamFlags & STREAM_FLAGS_PAUSE) + { + if (pParserModule->pfPause) + result = pParserModule->pfPause(pEASData, pEASData->streams[streamNum].handle); + pEASData->streams[streamNum].streamFlags &= ~STREAM_FLAGS_PAUSE; + } + + /* get current state */ + if ((result = (*pParserModule->pfState)(pEASData, pEASData->streams[streamNum].handle, &parserState)) != EAS_SUCCESS) + return result; + + /* handle resume */ + if (parserState == EAS_STATE_PAUSED) + { + if (pEASData->streams[streamNum].streamFlags & STREAM_FLAGS_RESUME) + { + if (pParserModule->pfResume) + result = pParserModule->pfResume(pEASData, pEASData->streams[streamNum].handle); + pEASData->streams[streamNum].streamFlags &= ~STREAM_FLAGS_RESUME; + } + } + + /* if necessary, parse stream */ + if ((pEASData->streams[streamNum].streamFlags & STREAM_FLAGS_PARSED) == 0) + if ((result = EAS_ParseEvents(pEASData, &pEASData->streams[streamNum], pEASData->streams[streamNum].time + pEASData->streams[streamNum].frameLength, eParserModePlay)) != EAS_SUCCESS) + return result; + + /* check for an early abort */ + if ((pEASData->streams[streamNum].streamFlags) == 0) + { + +#ifdef _METRICS_ENABLED + /* stop performance counter */ + if (pEASData->pMetricsData) + (*pEASData->pMetricsModule->pfStartTimer)(pEASData->pMetricsData, EAS_PM_TOTAL_TIME); +#endif + + return EAS_SUCCESS; + } + + /* check for repeat */ + if (pEASData->streams[streamNum].repeatCount) + { + + /* check for stopped state */ + if ((result = (*pParserModule->pfState)(pEASData, pEASData->streams[streamNum].handle, &parserState)) != EAS_SUCCESS) + return result; + if (parserState == EAS_STATE_STOPPED) + { + + /* decrement repeat count, unless it is negative */ + if (pEASData->streams[streamNum].repeatCount > 0) + pEASData->streams[streamNum].repeatCount--; + + /* reset the parser */ + if ((result = (*pParserModule->pfReset)(pEASData, pEASData->streams[streamNum].handle)) != EAS_SUCCESS) + return result; + pEASData->streams[streamNum].time = 0; + } + } + } + } + +#ifdef _METRICS_ENABLED + /* stop performance counter */ + if (pEASData->pMetricsData) + (void)(*pEASData->pMetricsModule->pfStopTimer)(pEASData->pMetricsData, EAS_PM_PARSE_TIME); +#endif + +#ifdef _METRICS_ENABLED + /* start the render timer */ + if (pEASData->pMetricsData) + (*pEASData->pMetricsModule->pfStartTimer)(pEASData->pMetricsData, EAS_PM_RENDER_TIME); +#endif + + /* render audio */ + if ((result = VMRender(pEASData->pVoiceMgr, BUFFER_SIZE_IN_MONO_SAMPLES, pEASData->pMixBuffer, &voicesRendered)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "pfRender function returned error %ld\n", result); */ } + return result; + } + +#ifdef _METRICS_ENABLED + /* stop the render timer */ + if (pEASData->pMetricsData) { + (*pEASData->pMetricsModule->pfIncrementCounter)(pEASData->pMetricsData, EAS_PM_FRAME_COUNT, 1); + (void)(*pEASData->pMetricsModule->pfStopTimer)(pEASData->pMetricsData, EAS_PM_RENDER_TIME); + (*pEASData->pMetricsModule->pfIncrementCounter)(pEASData->pMetricsData, EAS_PM_TOTAL_VOICE_COUNT, (EAS_U32) voicesRendered); + (void)(*pEASData->pMetricsModule->pfRecordMaxValue)(pEASData->pMetricsData, EAS_PM_MAX_VOICES, (EAS_U32) voicesRendered); + } +#endif + + //2 Do we really need frameParsed? + /* need to parse another frame of events before we render again */ + for (streamNum = 0; streamNum < MAX_NUMBER_STREAMS; streamNum++) + if (pEASData->streams[streamNum].pParserModule != NULL) + pEASData->streams[streamNum].streamFlags &= ~STREAM_FLAGS_PARSED; + +#ifdef _METRICS_ENABLED + /* start performance counter */ + if (pEASData->pMetricsData) + (*pEASData->pMetricsModule->pfStartTimer)(pEASData->pMetricsData, EAS_PM_STREAM_TIME); +#endif + + /* render PCM audio */ + if ((result = EAS_PERender(pEASData, numRequested)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_PERender returned error %ld\n", result); */ } + return result; + } + +#ifdef _METRICS_ENABLED + /* stop the stream timer */ + if (pEASData->pMetricsData) + (void)(*pEASData->pMetricsModule->pfStopTimer)(pEASData->pMetricsData, EAS_PM_STREAM_TIME); +#endif + +#ifdef _METRICS_ENABLED + /* start the post timer */ + if (pEASData->pMetricsData) + (*pEASData->pMetricsModule->pfStartTimer)(pEASData->pMetricsData, EAS_PM_POST_TIME); +#endif + + /* for split architecture, send DSP vectors. Do post only if return is TRUE */ +#ifdef _SPLIT_ARCHITECTURE + if (VMEndFrame(pEASData)) + { + /* now do post-processing */ + EAS_MixEnginePost(pEASData, numRequested); + *pNumGenerated = numRequested; + } +#else + /* now do post-processing */ + EAS_MixEnginePost(pEASData, numRequested); + *pNumGenerated = numRequested; +#endif + +#ifdef _METRICS_ENABLED + /* stop the post timer */ + if (pEASData->pMetricsData) + (void)(*pEASData->pMetricsModule->pfStopTimer)(pEASData->pMetricsData, EAS_PM_POST_TIME); +#endif + + /* advance render time */ + pEASData->renderTime += AUDIO_FRAME_LENGTH; + +#if 0 + /* dump workload for debug */ + if (pEASData->pVoiceMgr->workload) + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Workload = %d\n", pEASData->pVoiceMgr->workload); */ } +#endif + +#ifdef _METRICS_ENABLED + /* stop performance counter */ + if (pEASData->pMetricsData) + { + PERF_TIMER temp; + temp = (*pEASData->pMetricsModule->pfStopTimer)(pEASData->pMetricsData, EAS_PM_TOTAL_TIME); + + /* if max render time, record the number of voices and time */ + if ((*pEASData->pMetricsModule->pfRecordMaxValue) + (pEASData->pMetricsData, EAS_PM_MAX_CYCLES, (EAS_U32) temp)) + { + (*pEASData->pMetricsModule->pfRecordValue)(pEASData->pMetricsData, EAS_PM_MAX_CYCLES_VOICES, (EAS_U32) voicesRendered); + (*pEASData->pMetricsModule->pfRecordValue)(pEASData->pMetricsData, EAS_PM_MAX_CYCLES_TIME, (EAS_I32) (pEASData->renderTime >> 8)); + } + } +#endif + +#ifdef JET_INTERFACE + /* let JET to do its thing */ + if (pEASData->jetHandle != NULL) + { + result = JET_Process(pEASData); + if (result != EAS_SUCCESS) + return result; + } +#endif + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_SetRepeat() + *---------------------------------------------------------------------------- + * Purpose: + * Set the selected stream to repeat. + * + * Inputs: + * pEASData - handle to data for this instance + * handle - handle to stream + * repeatCount - repeat count + * + * Outputs: + * + * Side Effects: + * + * Notes: + * 0 = no repeat + * 1 = repeat once, i.e. play through twice + * -1 = repeat forever + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_PUBLIC EAS_RESULT EAS_SetRepeat (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 repeatCount) +{ + pStream->repeatCount = repeatCount; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_GetRepeat() + *---------------------------------------------------------------------------- + * Purpose: + * Gets the current repeat count for the selected stream. + * + * Inputs: + * pEASData - handle to data for this instance + * handle - handle to stream + * pRrepeatCount - pointer to variable to hold repeat count + * + * Outputs: + * + * Side Effects: + * + * Notes: + * 0 = no repeat + * 1 = repeat once, i.e. play through twice + * -1 = repeat forever + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_PUBLIC EAS_RESULT EAS_GetRepeat (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 *pRepeatCount) +{ + *pRepeatCount = pStream->repeatCount; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_SetPlaybackRate() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the playback rate. + * + * Inputs: + * pEASData - handle to data for this instance + * handle - handle to stream + * rate - rate (28-bit fractional amount) + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_PUBLIC EAS_RESULT EAS_SetPlaybackRate (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_U32 rate) +{ + + /* check range */ + if ((rate < (1 << 27)) || (rate > (1 << 29))) + return EAS_ERROR_INVALID_PARAMETER; + + /* calculate new frame length + * + * NOTE: The maximum frame length we can accomodate based on a + * maximum rate of 2.0 (2^28) is 2047 (2^13-1). To accomodate a + * longer frame length or a higher maximum rate, the fixed point + * divide below will need to be adjusted + */ + pStream->frameLength = (AUDIO_FRAME_LENGTH * (rate >> 8)) >> 20; + + /* notify stream of new playback rate */ + EAS_SetStreamParameter(pEASData, pStream, PARSER_DATA_PLAYBACK_RATE, (EAS_I32) rate); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_SetTransposition) + *---------------------------------------------------------------------------- + * Purpose: + * Sets the key tranposition for the synthesizer. Transposes all + * melodic instruments by the specified amount. Range is limited + * to +/-12 semitones. + * + * Inputs: + * pEASData - handle to data for this instance + * handle - handle to stream + * transposition - +/-12 semitones + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetTransposition (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 transposition) +{ + + /* check range */ + if ((transposition < -12) || (transposition > 12)) + return EAS_ERROR_INVALID_PARAMETER; + + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + return EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_TRANSPOSITION, transposition); +} + +/*---------------------------------------------------------------------------- + * EAS_ParseEvents() + *---------------------------------------------------------------------------- + * Purpose: + * Parse events in the current streams until the desired time is reached. + * + * Inputs: + * pEASData - buffer for internal EAS data + * endTime - stop parsing if this time is reached + * parseMode - play, locate, or metadata + * + * Outputs: + * EAS_SUCCESS if PCM data was successfully rendered + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT EAS_ParseEvents (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_U32 endTime, EAS_INT parseMode) +{ + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_RESULT result; + EAS_I32 parserState; + EAS_BOOL done; + EAS_INT yieldCount = YIELD_EVENT_COUNT; + EAS_U32 time = 0; + + /* does this parser have a time function? */ + pParserModule = pStream->pParserModule; + if (pParserModule->pfTime == NULL) + { + /* check state */ + if ((result = (*pParserModule->pfState)(pEASData, pStream->handle, &parserState)) != EAS_SUCCESS) + return result; + /* if play state, advance time */ + if ((parserState >= EAS_STATE_READY) && (parserState <= EAS_STATE_PAUSING)) + pStream->time += pStream->frameLength; + done = EAS_TRUE; + } + + /* assume we're not done, in case we abort out */ + else + { + pStream->streamFlags &= ~STREAM_FLAGS_PARSED; + done = EAS_FALSE; + } + + while (!done) + { + + /* check for stopped state */ + if ((result = (*pParserModule->pfState)(pEASData, pStream->handle, &parserState)) != EAS_SUCCESS) + return result; + if (parserState > EAS_STATE_PLAY) + { + /* save current time if we're not in play mode */ + if (parseMode != eParserModePlay) + pStream->time = time << 8; + done = EAS_TRUE; + break; + } + + /* get the next event time */ + if (pParserModule->pfTime) + { + if ((result = (*pParserModule->pfTime)(pEASData, pStream->handle, &time)) != EAS_SUCCESS) + return result; + + /* if next event is within this frame, parse it */ + if (time < (endTime >> 8)) + { + + /* parse the next event */ + if (pParserModule->pfEvent) + if ((result = (*pParserModule->pfEvent)(pEASData, pStream->handle, parseMode)) != EAS_SUCCESS) + return result; + } + + /* no more events in this frame, advance time */ + else + { + pStream->time = endTime; + done = EAS_TRUE; + } + } + + /* check for max workload exceeded */ + if (VMCheckWorkload(pEASData->pVoiceMgr)) + { + /* stop even though we may not have parsed + * all the events in this frame. The parser will try to + * catch up on the next frame. + */ + break; + } + + /* give host a chance for an early abort */ + if (--yieldCount == 0) + { + if (EAS_HWYield(pEASData->hwInstData)) + break; + yieldCount = YIELD_EVENT_COUNT; + } + } + + /* if no early abort, parsing is complete for this frame */ + if (done) + pStream->streamFlags |= STREAM_FLAGS_PARSED; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_ParseMetaData() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - file or stream handle + * playLength - pointer to variable to store the play length (in msecs) + * + * Outputs: + * + * + * Side Effects: + * - resets the parser to the start of the file + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_ParseMetaData (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 *playLength) +{ + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_RESULT result; + EAS_STATE state; + + pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; + if (pParserModule == NULL) + return EAS_ERROR_FEATURE_NOT_AVAILABLE; + + /* check parser state */ + if ((result = (*pParserModule->pfState)(pEASData, pStream->handle, &state)) != EAS_SUCCESS) + return result; + if (state >= EAS_STATE_OPEN) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + /* if parser has metadata function, use that */ + if (pParserModule->pfGetMetaData != NULL) + return pParserModule->pfGetMetaData(pEASData, pStream->handle, playLength); + + /* reset the parser to the beginning */ + if ((result = (*pParserModule->pfReset)(pEASData, pStream->handle)) != EAS_SUCCESS) + return result; + + /* parse the file to end */ + pStream->time = 0; + VMInitWorkload(pEASData->pVoiceMgr); + if ((result = EAS_ParseEvents(pEASData, pStream, 0x7fffffff, eParserModeMetaData)) != EAS_SUCCESS) + return result; + + /* get the parser time */ + if ((result = EAS_GetLocation(pEASData, pStream, playLength)) != EAS_SUCCESS) + return result; + + /* reset the parser to the beginning */ + pStream->time = 0; + return (*pParserModule->pfReset)(pEASData, pStream->handle); +} + +/*---------------------------------------------------------------------------- + * EAS_RegisterMetaDataCallback() + *---------------------------------------------------------------------------- + * Purpose: + * Registers a metadata callback function for parsed metadata. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - file or stream handle + * cbFunc - pointer to host callback function + * metaDataBuffer - pointer to metadata buffer + * metaDataBufSize - maximum size of the metadata buffer + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_RegisterMetaDataCallback ( + EAS_DATA_HANDLE pEASData, + EAS_HANDLE pStream, + EAS_METADATA_CBFUNC cbFunc, + char *metaDataBuffer, + EAS_I32 metaDataBufSize, + EAS_VOID_PTR pUserData) +{ + S_METADATA_CB metadata; + + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + /* register callback function */ + metadata.callback = cbFunc; + metadata.buffer = metaDataBuffer; + metadata.bufferSize = metaDataBufSize; + metadata.pUserData = pUserData; + return EAS_SetStreamParameter(pEASData, pStream, PARSER_DATA_METADATA_CB, (EAS_I32) &metadata); +} + +/*---------------------------------------------------------------------------- + * EAS_GetNoteCount () + *---------------------------------------------------------------------------- + * Returns the total number of notes played in this stream + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetNoteCount (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 *pNoteCount) +{ + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + return EAS_IntGetStrmParam(pEASData, pStream, PARSER_DATA_NOTE_COUNT, pNoteCount); +} + +/*---------------------------------------------------------------------------- + * EAS_CloseFile() + *---------------------------------------------------------------------------- + * Purpose: + * Closes an audio file or stream. Playback should have either paused or + * completed (EAS_State returns EAS_PAUSED or EAS_STOPPED). + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - file or stream handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_CloseFile (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream) +{ + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_RESULT result; + + /* call the close function */ + pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; + if (pParserModule == NULL) + return EAS_ERROR_FEATURE_NOT_AVAILABLE; + + result = (*pParserModule->pfClose)(pEASData, pStream->handle); + + /* clear the handle and parser interface pointer */ + pStream->handle = NULL; + pStream->pParserModule = NULL; + return result; +} + +/*---------------------------------------------------------------------------- + * EAS_OpenMIDIStream() + *---------------------------------------------------------------------------- + * Purpose: + * Opens a raw MIDI stream allowing the host to route MIDI cable data directly to the synthesizer + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * pHandle - pointer to variable to hold file or stream handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_OpenMIDIStream (EAS_DATA_HANDLE pEASData, EAS_HANDLE *ppStream, EAS_HANDLE streamHandle) +{ + EAS_RESULT result; + S_INTERACTIVE_MIDI *pMIDIStream; + EAS_INT streamNum; + + /* initialize some pointers */ + *ppStream = NULL; + + /* allocate a stream */ + if ((streamNum = EAS_AllocateStream(pEASData)) < 0) + return EAS_ERROR_MAX_STREAMS_OPEN; + + /* check Configuration Module for S_EAS_DATA allocation */ + if (pEASData->staticMemoryModel) + pMIDIStream = EAS_CMEnumData(EAS_CM_MIDI_STREAM_DATA); + else + pMIDIStream = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_INTERACTIVE_MIDI)); + + /* allocate dynamic memory */ + if (!pMIDIStream) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Failed to allocate MIDI stream data\n"); */ } + return EAS_ERROR_MALLOC_FAILED; + } + + /* zero the memory to insure complete initialization */ + EAS_HWMemSet(pMIDIStream, 0, sizeof(S_INTERACTIVE_MIDI)); + EAS_InitStream(&pEASData->streams[streamNum], NULL, pMIDIStream); + + /* instantiate a new synthesizer */ + if (streamHandle == NULL) + { + result = VMInitMIDI(pEASData, &pMIDIStream->pSynth); + } + + /* use an existing synthesizer */ + else + { + EAS_I32 value; + result = EAS_GetStreamParameter(pEASData, streamHandle, PARSER_DATA_SYNTH_HANDLE, &value); + pMIDIStream->pSynth = (S_SYNTH*) value; + VMIncRefCount(pMIDIStream->pSynth); + } + if (result != EAS_SUCCESS) + { + EAS_CloseMIDIStream(pEASData, &pEASData->streams[streamNum]); + return result; + } + + /* initialize the MIDI stream data */ + EAS_InitMIDIStream(&pMIDIStream->stream); + + *ppStream = (EAS_HANDLE) &pEASData->streams[streamNum]; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_WriteMIDIStream() + *---------------------------------------------------------------------------- + * Purpose: + * Send data to the MIDI stream device + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - stream handle + * pBuffer - pointer to buffer + * count - number of bytes to write + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_WriteMIDIStream (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_U8 *pBuffer, EAS_I32 count) +{ + S_INTERACTIVE_MIDI *pMIDIStream; + EAS_RESULT result; + + pMIDIStream = (S_INTERACTIVE_MIDI*) pStream->handle; + + if (count <= 0) + return EAS_ERROR_PARAMETER_RANGE; + + /* send the entire buffer */ + while (count--) + { + if ((result = EAS_ParseMIDIStream(pEASData, pMIDIStream->pSynth, &pMIDIStream->stream, *pBuffer++, eParserModePlay)) != EAS_SUCCESS) + return result; + } + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_CloseMIDIStream() + *---------------------------------------------------------------------------- + * Purpose: + * Closes a raw MIDI stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - stream handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_CloseMIDIStream (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream) +{ + S_INTERACTIVE_MIDI *pMIDIStream; + + pMIDIStream = (S_INTERACTIVE_MIDI*) pStream->handle; + + /* close synth */ + if (pMIDIStream->pSynth != NULL) + { + VMMIDIShutdown(pEASData, pMIDIStream->pSynth); + pMIDIStream->pSynth = NULL; + } + + /* release allocated memory */ + if (!pEASData->staticMemoryModel) + EAS_HWFree(((S_EAS_DATA*) pEASData)->hwInstData, pMIDIStream); + + pStream->handle = NULL; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_State() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the state of an audio file or stream. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - file or stream handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_State (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_STATE *pState) +{ + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_RESULT result; + + /* call the parser to return state */ + pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; + if (pParserModule == NULL) + return EAS_ERROR_FEATURE_NOT_AVAILABLE; + + if ((result = (*pParserModule->pfState)(pEASData, pStream->handle, pState)) != EAS_SUCCESS) + return result; + + /* if repeat count is set for this parser, mask the stopped state from the application */ + if (pStream->repeatCount && (*pState == EAS_STATE_STOPPED)) + *pState = EAS_STATE_PLAY; + + /* if we're not ready or playing, we don't need to hide state from host */ + if (*pState > EAS_STATE_PLAY) + return EAS_SUCCESS; + + /* if stream is about to be paused, report it as paused */ + if (pStream->streamFlags & STREAM_FLAGS_PAUSE) + { + if (pStream->streamFlags & STREAM_FLAGS_LOCATE) + *pState = EAS_STATE_PAUSED; + else + *pState = EAS_STATE_PAUSING; + } + + /* if stream is about to resume, report it as playing */ + if (pStream->streamFlags & STREAM_FLAGS_RESUME) + *pState = EAS_STATE_PLAY; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_SetPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Set the polyphony of the stream. A value of 0 allows the stream + * to use all voices (set by EAS_SetSynthPolyphony). + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - handle returned by EAS_OpenFile + * polyphonyCount - the desired polyphony count + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetPolyphony (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 polyphonyCount) +{ + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + return EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_POLYPHONY, polyphonyCount); +} + +/*---------------------------------------------------------------------------- + * EAS_GetPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current polyphony setting of the stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - handle returned by EAS_OpenFile + * pPolyphonyCount - pointer to variable to receive polyphony count + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetPolyphony (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 *pPolyphonyCount) +{ + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + return EAS_IntGetStrmParam(pEASData, pStream, PARSER_DATA_POLYPHONY, pPolyphonyCount); +} + +/*---------------------------------------------------------------------------- + * EAS_SetSynthPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Set the polyphony of the synth . Value must be >= 1 and <= the + * maximum number of voices. This function will pin the polyphony + * at those limits + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * synthNum - synthesizer number (0 = onboard, 1 = DSP) + * polyphonyCount - the desired polyphony count + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetSynthPolyphony (EAS_DATA_HANDLE pEASData, EAS_I32 synthNum, EAS_I32 polyphonyCount) +{ + return VMSetSynthPolyphony(pEASData->pVoiceMgr, synthNum, polyphonyCount); +} + +/*---------------------------------------------------------------------------- + * EAS_GetSynthPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current polyphony setting of the synth + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * synthNum - synthesizer number (0 = onboard, 1 = DSP) + * pPolyphonyCount - pointer to variable to receive polyphony count + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetSynthPolyphony (EAS_DATA_HANDLE pEASData, EAS_I32 synthNum, EAS_I32 *pPolyphonyCount) +{ + return VMGetSynthPolyphony(pEASData->pVoiceMgr, synthNum, pPolyphonyCount); +} + +/*---------------------------------------------------------------------------- + * EAS_SetPriority() + *---------------------------------------------------------------------------- + * Purpose: + * Set the priority of the stream. Determines which stream's voices + * are stolen when there are insufficient voices for all notes. + * Value must be in the range of 1-15, lower values are higher + * priority. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - handle returned by EAS_OpenFile + * polyphonyCount - the desired polyphony count + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetPriority (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 priority) +{ + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + return EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_PRIORITY, priority); +} + +/*---------------------------------------------------------------------------- + * EAS_GetPriority() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current priority setting of the stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - handle returned by EAS_OpenFile + * pPriority - pointer to variable to receive priority + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetPriority (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 *pPriority) +{ + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + return EAS_IntGetStrmParam(pEASData, pStream, PARSER_DATA_PRIORITY, pPriority); +} + +/*---------------------------------------------------------------------------- + * EAS_SetVolume() + *---------------------------------------------------------------------------- + * Purpose: + * Set the master gain for the mix engine in 1dB increments + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * volume - the desired master gain (100 is max) + * handle - file or stream handle + * + * Outputs: + * + * + * Side Effects: + * overrides any previously set master volume from sysex + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetVolume (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 volume) +{ + EAS_I16 gain; + + /* check range */ + if ((volume < 0) || (volume > EAS_MAX_VOLUME)) + return EAS_ERROR_PARAMETER_RANGE; + + /* stream volume */ + if (pStream != NULL) + { + EAS_I32 gainOffset; + EAS_RESULT result; + + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + /* get gain offset */ + pStream->volume = (EAS_U8) volume; + result = EAS_GetStreamParameter(pEASData, pStream, PARSER_DATA_GAIN_OFFSET, &gainOffset); + if (result == EAS_SUCCESS) + volume += gainOffset; + + /* set stream volume */ + gain = EAS_VolumeToGain(volume - STREAM_VOLUME_HEADROOM); + + /* convert to linear scalar */ + return EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_VOLUME, gain); + } + + /* master volume */ + pEASData->masterVolume = (EAS_U8) volume; +#if (NUM_OUTPUT_CHANNELS == 1) + /* leave 3dB headroom for mono output */ + volume -= 3; +#endif + + gain = EAS_VolumeToGain(volume - STREAM_VOLUME_HEADROOM); + pEASData->masterGain = gain; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_GetVolume() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the master volume for the synthesizer. The default volume setting is + * 50. The volume range is 0 to 100; + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * volume - the desired master volume + * handle - file or stream handle + * + * Outputs: + * + * + * Side Effects: + * overrides any previously set master volume from sysex + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_I32 EAS_GetVolume (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream) +{ + if (pStream == NULL) + return pEASData->masterVolume; + + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + return pStream->volume; +} + +/*---------------------------------------------------------------------------- + * EAS_SetMaxLoad() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the maximum workload the parsers will do in a single call to + * EAS_Render. The units are currently arbitrary, but should correlate + * well to the actual CPU cycles consumed. The primary effect is to + * reduce the occasional peaks in CPU cycles consumed when parsing + * dense parts of a MIDI score. + * + * Inputs: + * pEASData - handle to data for this instance + * maxLoad - the desired maximum workload + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetMaxLoad (EAS_DATA_HANDLE pEASData, EAS_I32 maxLoad) +{ + VMSetWorkload(pEASData->pVoiceMgr, maxLoad); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_SetMaxPCMStreams() + *---------------------------------------------------------------------------- + * Sets the maximum number of PCM streams allowed in parsers that + * use PCM streaming. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * streamHandle - handle returned by EAS_OpenFile + * maxNumStreams - maximum number of PCM streams + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetMaxPCMStreams (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 maxNumStreams) +{ + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + return EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_MAX_PCM_STREAMS, maxNumStreams); +} + +/*---------------------------------------------------------------------------- + * EAS_Locate() + *---------------------------------------------------------------------------- + * Purpose: + * Locate into the file associated with the handle. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - file handle + * milliseconds - playback offset from start of file in milliseconds + * + * Outputs: + * + * + * Side Effects: + * the actual offset will be quantized to the closest update period, typically + * a resolution of 5.9ms. Notes that are started prior to this time will not + * sound. Any notes currently playing will be shut off. + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Locate (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 milliseconds, EAS_BOOL offset) +{ + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_RESULT result; + EAS_U32 requestedTime; + EAS_STATE state; + + /* get pointer to parser function table */ + pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; + if (pParserModule == NULL) + return EAS_ERROR_FEATURE_NOT_AVAILABLE; + + if ((result = (*pParserModule->pfState)(pEASData, pStream->handle, &state)) != EAS_SUCCESS) + return result; + if (state >= EAS_STATE_OPEN) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + /* handle offset and limit to start of file */ + /*lint -e{704} use shift for performance*/ + if (offset) + milliseconds += (EAS_I32) pStream->time >> 8; + if (milliseconds < 0) + milliseconds = 0; + + /* check to see if the request is different from the current time */ + requestedTime = (EAS_U32) milliseconds; + if (requestedTime == (pStream->time >> 8)) + return EAS_SUCCESS; + + /* set the locate flag */ + pStream->streamFlags |= STREAM_FLAGS_LOCATE; + + /* use the parser locate function, if available */ + if (pParserModule->pfLocate != NULL) + { + EAS_BOOL parserLocate = EAS_FALSE; + result = pParserModule->pfLocate(pEASData, pStream->handle, (EAS_I32) requestedTime, &parserLocate); + if (!parserLocate) + { + if (result == EAS_SUCCESS) + pStream->time = requestedTime << 8; + return result; + } + } + + /* if we were paused and not going to resume, set pause request flag */ + if (((state == EAS_STATE_PAUSING) || (state == EAS_STATE_PAUSED)) && ((pStream->streamFlags & STREAM_FLAGS_RESUME) == 0)) + pStream->streamFlags |= STREAM_FLAGS_PAUSE; + + /* reset the synth and parser */ + if ((result = (*pParserModule->pfReset)(pEASData, pStream->handle)) != EAS_SUCCESS) + return result; + pStream->time = 0; + + /* locating forward, clear parsed flag and parse data until we get to the requested location */ + if ((result = EAS_ParseEvents(pEASData, pStream, requestedTime << 8, eParserModeLocate)) != EAS_SUCCESS) + return result; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_GetLocation() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current playback offset + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - file handle + * + * Outputs: + * The offset in milliseconds from the start of the current sequence, quantized + * to the nearest update period. Actual resolution is typically 5.9 ms. + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_PUBLIC EAS_RESULT EAS_GetLocation (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 *pTime) +{ + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + *pTime = pStream->time >> 8; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_GetRenderTime() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current playback offset + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * + * Outputs: + * Gets the render time clock in msecs. + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetRenderTime (EAS_DATA_HANDLE pEASData, EAS_I32 *pTime) +{ + *pTime = pEASData->renderTime >> 8; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_Pause() + *---------------------------------------------------------------------------- + * Purpose: + * Pauses the playback of the data associated with this handle. The audio + * is gracefully ramped down to prevent clicks and pops. It may take several + * buffers of audio before the audio is muted. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * handle - file or stream handle + * + * Outputs: + * + * + * Side Effects: + * + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Pause (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream) +{ + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_STATE state; + EAS_RESULT result; + + pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; + if (pParserModule == NULL) + return EAS_ERROR_FEATURE_NOT_AVAILABLE; + + /* check for valid state */ + result = pParserModule->pfState(pEASData, pStream->handle, &state); + if (result == EAS_SUCCESS) + { + if ((state != EAS_STATE_PLAY) && (state != EAS_STATE_READY) && ((pStream->streamFlags & STREAM_FLAGS_RESUME) == 0)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + /* make sure parser implements pause */ + if (pParserModule->pfPause == NULL) + result = EAS_ERROR_NOT_IMPLEMENTED; + + /* clear resume flag */ + pStream->streamFlags &= ~STREAM_FLAGS_RESUME; + + /* set pause flag */ + pStream->streamFlags |= STREAM_FLAGS_PAUSE; + +#if 0 + /* pause the stream */ + if (pParserModule->pfPause) + result = pParserModule->pfPause(pEASData, pStream->handle); + else + result = EAS_ERROR_NOT_IMPLEMENTED; +#endif + } + + return result; +} + +/*---------------------------------------------------------------------------- + * EAS_Resume() + *---------------------------------------------------------------------------- + * Purpose: + * Resumes the playback of the data associated with this handle. The audio + * is gracefully ramped up to prevent clicks and pops. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * handle - file or stream handle + * + * Outputs: + * + * + * Side Effects: + * + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_Resume (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream) +{ + S_FILE_PARSER_INTERFACE *pParserModule; + EAS_STATE state; + EAS_RESULT result; + + pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; + if (pParserModule == NULL) + return EAS_ERROR_FEATURE_NOT_AVAILABLE; + + /* check for valid state */ + result = pParserModule->pfState(pEASData, pStream->handle, &state); + if (result == EAS_SUCCESS) + { + if ((state != EAS_STATE_PAUSED) && (state != EAS_STATE_PAUSING) && ((pStream->streamFlags & STREAM_FLAGS_PAUSE) == 0)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + /* make sure parser implements this function */ + if (pParserModule->pfResume == NULL) + result = EAS_ERROR_NOT_IMPLEMENTED; + + /* clear pause flag */ + pStream->streamFlags &= ~STREAM_FLAGS_PAUSE; + + /* set resume flag */ + pStream->streamFlags |= STREAM_FLAGS_RESUME; + +#if 0 + /* resume the stream */ + if (pParserModule->pfResume) + result = pParserModule->pfResume(pEASData, pStream->handle); + else + result = EAS_ERROR_NOT_IMPLEMENTED; +#endif + } + + return result; +} + +/*---------------------------------------------------------------------------- + * EAS_GetParameter() + *---------------------------------------------------------------------------- + * Purpose: + * Set the parameter of a module. See E_MODULES for a list of modules + * and the header files of the modules for a list of parameters. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * handle - file or stream handle + * module - enumerated module number + * param - enumerated parameter number + * pValue - pointer to variable to receive parameter value + * + * Outputs: + * + * + * Side Effects: + * + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetParameter (EAS_DATA_HANDLE pEASData, EAS_I32 module, EAS_I32 param, EAS_I32 *pValue) +{ + + if (module >= NUM_EFFECTS_MODULES) + return EAS_ERROR_INVALID_MODULE; + + if (pEASData->effectsModules[module].effectData == NULL) + return EAS_ERROR_INVALID_MODULE; + + return (*pEASData->effectsModules[module].effect->pFGetParam) + (pEASData->effectsModules[module].effectData, param, pValue); +} + +/*---------------------------------------------------------------------------- + * EAS_SetParameter() + *---------------------------------------------------------------------------- + * Purpose: + * Set the parameter of a module. See E_MODULES for a list of modules + * and the header files of the modules for a list of parameters. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * handle - file or stream handle + * module - enumerated module number + * param - enumerated parameter number + * value - new parameter value + * + * Outputs: + * + * + * Side Effects: + * + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetParameter (EAS_DATA_HANDLE pEASData, EAS_I32 module, EAS_I32 param, EAS_I32 value) +{ + + if (module >= NUM_EFFECTS_MODULES) + return EAS_ERROR_INVALID_MODULE; + + if (pEASData->effectsModules[module].effectData == NULL) + return EAS_ERROR_INVALID_MODULE; + + return (*pEASData->effectsModules[module].effect->pFSetParam) + (pEASData->effectsModules[module].effectData, param, value); +} + +#ifdef _METRICS_ENABLED +/*---------------------------------------------------------------------------- + * EAS_MetricsReport() + *---------------------------------------------------------------------------- + * Purpose: + * Displays the current metrics through the metrics interface. + * + * Inputs: + * p - instance data handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_MetricsReport (EAS_DATA_HANDLE pEASData) +{ + if (!pEASData->pMetricsModule) + return EAS_ERROR_INVALID_MODULE; + + return (*pEASData->pMetricsModule->pfReport)(pEASData->pMetricsData); +} + +/*---------------------------------------------------------------------------- + * EAS_MetricsReset() + *---------------------------------------------------------------------------- + * Purpose: + * Resets the metrics. + * + * Inputs: + * p - instance data handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_MetricsReset (EAS_DATA_HANDLE pEASData) +{ + + if (!pEASData->pMetricsModule) + return EAS_ERROR_INVALID_MODULE; + + return (*pEASData->pMetricsModule->pfReset)(pEASData->pMetricsData); +} +#endif + +/*---------------------------------------------------------------------------- + * EAS_SetSoundLibrary() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the location of the sound library. + * + * Inputs: + * pEASData - instance data handle + * pSoundLib - pointer to sound library + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetSoundLibrary (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_SNDLIB_HANDLE pSndLib) +{ + if (pStream) + { + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + return EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_EAS_LIBRARY, (EAS_I32) pSndLib); + } + + return VMSetGlobalEASLib(pEASData->pVoiceMgr, pSndLib); +} + +/*---------------------------------------------------------------------------- + * EAS_SetHeaderSearchFlag() + *---------------------------------------------------------------------------- + * By default, when EAS_OpenFile is called, the parsers check the + * first few bytes of the file looking for a specific header. Some + * mobile devices may add a header to the start of a file, which + * will prevent the parser from recognizing the file. If the + * searchFlag is set to EAS_TRUE, the parser will search the entire + * file looking for the header. This may enable EAS to recognize + * some files that it would ordinarily reject. The negative is that + * it make take slightly longer to process the EAS_OpenFile request. + * + * Inputs: + * pEASData - instance data handle + * searchFlag - search flag (EAS_TRUE or EAS_FALSE) + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetHeaderSearchFlag (EAS_DATA_HANDLE pEASData, EAS_BOOL searchFlag) +{ + pEASData->searchHeaderFlag = (EAS_BOOL8) searchFlag; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_SetPlayMode() + *---------------------------------------------------------------------------- + * Some file formats support special play modes, such as iMode partial + * play mode. This call can be used to change the play mode. The + * default play mode (usually straight playback) is always zero. + * + * Inputs: + * pEASData - instance data handle + * handle - file or stream handle + * playMode - play mode (see file parser for specifics) + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetPlayMode (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 playMode) +{ + return EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_PLAY_MODE, playMode); +} + +#ifdef DLS_SYNTHESIZER +/*---------------------------------------------------------------------------- + * EAS_LoadDLSCollection() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the location of the sound library. + * + * Inputs: + * pEASData - instance data handle + * pSoundLib - pointer to sound library + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_LoadDLSCollection (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_FILE_LOCATOR locator) +{ + EAS_FILE_HANDLE fileHandle; + EAS_RESULT result; + EAS_DLSLIB_HANDLE pDLS; + + if (pStream != NULL) + { + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + } + + /* open the file */ + if ((result = EAS_HWOpenFile(pEASData->hwInstData, locator, &fileHandle, EAS_FILE_READ)) != EAS_SUCCESS) + return result; + + /* parse the file */ + result = DLSParser(pEASData->hwInstData, fileHandle, 0, &pDLS); + EAS_HWCloseFile(pEASData->hwInstData, fileHandle); + + if (result == EAS_SUCCESS) + { + + /* if a stream pStream is specified, point it to the DLS collection */ + if (pStream) + result = EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_DLS_COLLECTION, (EAS_I32) pDLS); + + /* global DLS load */ + else + result = VMSetGlobalDLSLib(pEASData, pDLS); + } + + return result; +} +#endif + +#ifdef EXTERNAL_AUDIO +/*---------------------------------------------------------------------------- + * EAS_RegExtAudioCallback() + *---------------------------------------------------------------------------- + * Purpose: + * Registers callback functions for audio events. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - file or stream handle + * cbProgChgFunc - pointer to host callback function for program change + * cbEventFunc - pointer to host callback functio for note events + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_RegExtAudioCallback (EAS_DATA_HANDLE pEASData, + EAS_HANDLE pStream, + EAS_VOID_PTR pInstData, + EAS_EXT_PRG_CHG_FUNC cbProgChgFunc, + EAS_EXT_EVENT_FUNC cbEventFunc) +{ + S_SYNTH *pSynth; + + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + if (EAS_GetStreamParameter(pEASData, pStream, PARSER_DATA_SYNTH_HANDLE, (EAS_I32*) &pSynth) != EAS_SUCCESS) + return EAS_ERROR_INVALID_PARAMETER; + + if (pSynth == NULL) + return EAS_ERROR_INVALID_PARAMETER; + + VMRegExtAudioCallback(pSynth, pInstData, cbProgChgFunc, cbEventFunc); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_GetMIDIControllers() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current state of MIDI controllers on the requested channel. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - file or stream handle + * pControl - pointer to structure to receive data + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_GetMIDIControllers (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_U8 channel, S_MIDI_CONTROLLERS *pControl) +{ + S_SYNTH *pSynth; + + if (!EAS_StreamReady(pEASData, pStream)) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + if (EAS_GetStreamParameter(pEASData, pStream, PARSER_DATA_SYNTH_HANDLE, (EAS_I32*) &pSynth) != EAS_SUCCESS) + return EAS_ERROR_INVALID_PARAMETER; + + if (pSynth == NULL) + return EAS_ERROR_INVALID_PARAMETER; + + VMGetMIDIControllers(pSynth, channel, pControl); + return EAS_SUCCESS; +} +#endif + +#ifdef _SPLIT_ARCHITECTURE +/*---------------------------------------------------------------------------- + * EAS_SetFrameBuffer() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the frame buffer pointer passed to the IPC communications functions + * + * Inputs: + * pEASData - instance data handle + * locator - file locator + * + * Outputs: + * + * + * Side Effects: + * May overlay instruments in the GM sound set + * + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT EAS_SetFrameBuffer (EAS_DATA_HANDLE pEASData, EAS_FRAME_BUFFER_HANDLE pFrameBuffer) +{ + if (pEASData->pVoiceMgr) + pEASData->pVoiceMgr->pFrameBuffer = pFrameBuffer; + return EAS_SUCCESS; +} +#endif + +/*---------------------------------------------------------------------------- + * EAS_SearchFile + *---------------------------------------------------------------------------- + * Search file for specific sequence starting at current file + * position. Returns offset to start of sequence. + * + * Inputs: + * pEASData - pointer to EAS persistent data object + * fileHandle - file handle + * searchString - pointer to search sequence + * len - length of search sequence + * pOffset - pointer to variable to store offset to sequence + * + * Returns EAS_EOF if end-of-file is reached + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_SearchFile (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, const EAS_U8 *searchString, EAS_I32 len, EAS_I32 *pOffset) +{ + EAS_RESULT result; + EAS_INT index; + EAS_U8 c; + + *pOffset = -1; + index = 0; + for (;;) + { + result = EAS_HWGetByte(pEASData->hwInstData, fileHandle, &c); + if (result != EAS_SUCCESS) + return result; + if (c == searchString[index]) + { + index++; + if (index == 4) + { + result = EAS_HWFilePos(pEASData->hwInstData, fileHandle, pOffset); + if (result != EAS_SUCCESS) + return result; + *pOffset -= len; + break; + } + } + else + index = 0; + } + return EAS_SUCCESS; +} + + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_reverb.c b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_reverb.c new file mode 100755 index 0000000..a5cca71 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_reverb.c @@ -0,0 +1,1154 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_reverb.c + * + * Contents and purpose: + * Contains the implementation of the Reverb effect. + * + * + * Copyright Sonic Network Inc. 2006 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 510 $ + * $Date: 2006-12-19 01:47:33 -0800 (Tue, 19 Dec 2006) $ + *---------------------------------------------------------------------------- +*/ + +/*------------------------------------ + * includes + *------------------------------------ +*/ + +#include "eas_data.h" +#include "eas_effects.h" +#include "eas_math.h" +#include "eas_reverbdata.h" +#include "eas_reverb.h" +#include "eas_config.h" +#include "eas_host.h" +#include "eas_report.h" + +/* prototypes for effects interface */ +static EAS_RESULT ReverbInit (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR *pInstData); +static void ReverbProcess (EAS_VOID_PTR pInstData, EAS_PCM *pSrc, EAS_PCM *pDst, EAS_I32 numSamples); +static EAS_RESULT ReverbShutdown (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT ReverbGetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue); +static EAS_RESULT ReverbSetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value); + +/* common effects interface for configuration module */ +const S_EFFECTS_INTERFACE EAS_Reverb = +{ + ReverbInit, + ReverbProcess, + ReverbShutdown, + ReverbGetParam, + ReverbSetParam +}; + + + +/*---------------------------------------------------------------------------- + * InitializeReverb() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ReverbInit(EAS_DATA_HANDLE pEASData, EAS_VOID_PTR *pInstData) +{ + EAS_I32 i; + EAS_U16 nOffset; + EAS_INT temp; + + S_REVERB_OBJECT *pReverbData; + S_REVERB_PRESET *pPreset; + + /* check Configuration Module for data allocation */ + if (pEASData->staticMemoryModel) + pReverbData = EAS_CMEnumFXData(EAS_MODULE_REVERB); + + /* allocate dynamic memory */ + else + pReverbData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_REVERB_OBJECT)); + + if (pReverbData == NULL) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Failed to allocate Reverb memory\n"); */ } + return EAS_ERROR_MALLOC_FAILED; + } + + /* clear the structure */ + EAS_HWMemSet(pReverbData, 0, sizeof(S_REVERB_OBJECT)); + + ReverbReadInPresets(pReverbData); + + pReverbData->m_nMinSamplesToAdd = REVERB_UPDATE_PERIOD_IN_SAMPLES; + + pReverbData->m_nRevOutFbkR = 0; + pReverbData->m_nRevOutFbkL = 0; + + pReverbData->m_sAp0.m_zApIn = AP0_IN; + pReverbData->m_sAp0.m_zApOut = AP0_IN + DEFAULT_AP0_LENGTH; + pReverbData->m_sAp0.m_nApGain = DEFAULT_AP0_GAIN; + + pReverbData->m_zD0In = DELAY0_IN; + + pReverbData->m_sAp1.m_zApIn = AP1_IN; + pReverbData->m_sAp1.m_zApOut = AP1_IN + DEFAULT_AP1_LENGTH; + pReverbData->m_sAp1.m_nApGain = DEFAULT_AP1_GAIN; + + pReverbData->m_zD1In = DELAY1_IN; + + pReverbData->m_zLpf0 = 0; + pReverbData->m_zLpf1 = 0; + pReverbData->m_nLpfFwd = 8837; + pReverbData->m_nLpfFbk = 6494; + + pReverbData->m_nSin = 0; + pReverbData->m_nCos = 0; + pReverbData->m_nSinIncrement = 0; + pReverbData->m_nCosIncrement = 0; + + // set xfade parameters + pReverbData->m_nXfadeInterval = (EAS_U16)REVERB_XFADE_PERIOD_IN_SAMPLES; + pReverbData->m_nXfadeCounter = pReverbData->m_nXfadeInterval + 1; // force update on first iteration + pReverbData->m_nPhase = -32768; + pReverbData->m_nPhaseIncrement = REVERB_XFADE_PHASE_INCREMENT; + + pReverbData->m_nNoise = (EAS_I16)0xABCD; + + pReverbData->m_nMaxExcursion = 0x007F; + + // set delay tap lengths + nOffset = ReverbCalculateNoise( pReverbData->m_nMaxExcursion, + &pReverbData->m_nNoise ); + + pReverbData->m_zD1Cross = + DELAY1_OUT - pReverbData->m_nMaxExcursion + nOffset; + + nOffset = ReverbCalculateNoise( pReverbData->m_nMaxExcursion, + &pReverbData->m_nNoise ); + + pReverbData->m_zD0Cross = + DELAY1_OUT - pReverbData->m_nMaxExcursion - nOffset; + + nOffset = ReverbCalculateNoise( pReverbData->m_nMaxExcursion, + &pReverbData->m_nNoise ); + + pReverbData->m_zD0Self = + DELAY0_OUT - pReverbData->m_nMaxExcursion - nOffset; + + nOffset = ReverbCalculateNoise( pReverbData->m_nMaxExcursion, + &pReverbData->m_nNoise ); + + pReverbData->m_zD1Self = + DELAY1_OUT - pReverbData->m_nMaxExcursion + nOffset; + + // for debugging purposes, allow noise generator + pReverbData->m_bUseNoise = EAS_FALSE; + + // for debugging purposes, allow bypass + pReverbData->m_bBypass = EAS_TRUE; //EAS_FALSE; + + pReverbData->m_nNextRoom = 1; + + pReverbData->m_nCurrentRoom = pReverbData->m_nNextRoom + 1; // force update on first iteration + + pReverbData->m_nWet = REVERB_DEFAULT_WET; + + pReverbData->m_nDry = REVERB_DEFAULT_DRY; + + // set base index into circular buffer + pReverbData->m_nBaseIndex = 0; + + // set the early reflections, L + pReverbData->m_sEarlyL.m_nLpfFbk = 4915; + pReverbData->m_sEarlyL.m_nLpfFwd = 27852; + pReverbData->m_sEarlyL.m_zLpf = 0; + + for (i=0; i < REVERB_MAX_NUM_REFLECTIONS; i++) + { + pReverbData->m_sEarlyL.m_nGain[i] = 0; + pReverbData->m_sEarlyL.m_zDelay[i] = 0; + } + + // set the early reflections, R + pReverbData->m_sEarlyR.m_nLpfFbk = 4915; + pReverbData->m_sEarlyR.m_nLpfFwd = 27852; + pReverbData->m_sEarlyR.m_zLpf = 0; + + for (i=0; i < REVERB_MAX_NUM_REFLECTIONS; i++) + { + pReverbData->m_sEarlyR.m_nGain[i] = 0; + pReverbData->m_sEarlyR.m_zDelay[i] = 0; + } + + // clear the reverb delay line + for (i=0; i < REVERB_BUFFER_SIZE_IN_SAMPLES; i++) + { + pReverbData->m_nDelayLine[i] = 0; + } + + //////////////////////////////// + ///code from the EAS DEMO Reverb + //now copy from the new preset into the reverb + pPreset = &pReverbData->m_sPreset.m_sPreset[pReverbData->m_nNextRoom]; + + pReverbData->m_nLpfFbk = pPreset->m_nLpfFbk; + pReverbData->m_nLpfFwd = pPreset->m_nLpfFwd; + + pReverbData->m_nEarly = pPreset->m_nEarly; + pReverbData->m_nWet = pPreset->m_nWet; + pReverbData->m_nDry = pPreset->m_nDry; + + pReverbData->m_nMaxExcursion = pPreset->m_nMaxExcursion; + //stored as time based, convert to sample based + temp = pPreset->m_nXfadeInterval; + /*lint -e{702} shift for performance */ + temp = (temp * _OUTPUT_SAMPLE_RATE) >> 16; + pReverbData->m_nXfadeInterval = (EAS_U16) temp; + //gsReverbObject.m_nXfadeInterval = pPreset->m_nXfadeInterval; + + pReverbData->m_sAp0.m_nApGain = pPreset->m_nAp0_ApGain; + //stored as time based, convert to absolute sample value + temp = pPreset->m_nAp0_ApOut; + /*lint -e{702} shift for performance */ + temp = (temp * _OUTPUT_SAMPLE_RATE) >> 16; + pReverbData->m_sAp0.m_zApOut = (EAS_U16) (pReverbData->m_sAp0.m_zApIn + temp); + //gsReverbObject.m_sAp0.m_zApOut = pPreset->m_nAp0_ApOut; + + pReverbData->m_sAp1.m_nApGain = pPreset->m_nAp1_ApGain; + //stored as time based, convert to absolute sample value + temp = pPreset->m_nAp1_ApOut; + /*lint -e{702} shift for performance */ + temp = (temp * _OUTPUT_SAMPLE_RATE) >> 16; + pReverbData->m_sAp1.m_zApOut = (EAS_U16) (pReverbData->m_sAp1.m_zApIn + temp); + //gsReverbObject.m_sAp1.m_zApOut = pPreset->m_nAp1_ApOut; + ///code from the EAS DEMO Reverb + //////////////////////////////// + + *pInstData = pReverbData; + + return EAS_SUCCESS; + +} /* end InitializeReverb */ + + + +/*---------------------------------------------------------------------------- + * ReverbProcess() + *---------------------------------------------------------------------------- + * Purpose: + * Reverberate the requested number of samples (block based processing) + * + * Inputs: + * pInputBuffer - src buffer + * pOutputBuffer - dst buffer + * nNumSamplesToAdd - number of samples to write to buffer + * + * Outputs: + * number of samples actually written to buffer + * + * Side Effects: + * - samples are added to the presently free buffer + * + *---------------------------------------------------------------------------- +*/ +static void ReverbProcess(EAS_VOID_PTR pInstData, EAS_PCM *pSrc, EAS_PCM *pDst, EAS_I32 numSamples) +{ + S_REVERB_OBJECT *pReverbData; + + pReverbData = (S_REVERB_OBJECT*) pInstData; + + //if bypassed or the preset forces the signal to be completely dry + if (pReverbData->m_bBypass || + (pReverbData->m_nWet == 0 && pReverbData->m_nDry == 32767)) + { + if (pSrc != pDst) + EAS_HWMemCpy(pSrc, pDst, numSamples * NUM_OUTPUT_CHANNELS * (EAS_I32) sizeof(EAS_PCM)); + return; + } + + if (pReverbData->m_nNextRoom != pReverbData->m_nCurrentRoom) + { + ReverbUpdateRoom(pReverbData); + } + + ReverbUpdateXfade(pReverbData, numSamples); + + Reverb(pReverbData, numSamples, pDst, pSrc); + + /* check if update counter needs to be reset */ + if (pReverbData->m_nUpdateCounter >= REVERB_MODULO_UPDATE_PERIOD_IN_SAMPLES) + { + /* update interval has elapsed, so reset counter */ + pReverbData->m_nUpdateCounter = 0; + } /* end if m_nUpdateCounter >= update interval */ + + /* increment update counter */ + pReverbData->m_nUpdateCounter += (EAS_I16)numSamples; + +} /* end ComputeReverb */ + +/*---------------------------------------------------------------------------- + * ReverbUpdateXfade + *---------------------------------------------------------------------------- + * Purpose: + * Update the xfade parameters as required + * + * Inputs: + * nNumSamplesToAdd - number of samples to write to buffer + * + * Outputs: + * + * + * Side Effects: + * - xfade parameters will be changed + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT ReverbUpdateXfade(S_REVERB_OBJECT *pReverbData, EAS_INT nNumSamplesToAdd) +{ + EAS_U16 nOffset; + EAS_I16 tempCos; + EAS_I16 tempSin; + + if (pReverbData->m_nXfadeCounter >= pReverbData->m_nXfadeInterval) + { + /* update interval has elapsed, so reset counter */ + pReverbData->m_nXfadeCounter = 0; + + // Pin the sin,cos values to min / max values to ensure that the + // modulated taps' coefs are zero (thus no clicks) + if (pReverbData->m_nPhaseIncrement > 0) + { + // if phase increment > 0, then sin -> 1, cos -> 0 + pReverbData->m_nSin = 32767; + pReverbData->m_nCos = 0; + + // reset the phase to match the sin, cos values + pReverbData->m_nPhase = 32767; + + // modulate the cross taps because their tap coefs are zero + nOffset = ReverbCalculateNoise( pReverbData->m_nMaxExcursion, &pReverbData->m_nNoise ); + + pReverbData->m_zD1Cross = + DELAY1_OUT - pReverbData->m_nMaxExcursion + nOffset; + + nOffset = ReverbCalculateNoise( pReverbData->m_nMaxExcursion, &pReverbData->m_nNoise ); + + pReverbData->m_zD0Cross = + DELAY0_OUT - pReverbData->m_nMaxExcursion - nOffset; + } + else + { + // if phase increment < 0, then sin -> 0, cos -> 1 + pReverbData->m_nSin = 0; + pReverbData->m_nCos = 32767; + + // reset the phase to match the sin, cos values + pReverbData->m_nPhase = -32768; + + // modulate the self taps because their tap coefs are zero + nOffset = ReverbCalculateNoise( pReverbData->m_nMaxExcursion, &pReverbData->m_nNoise ); + + pReverbData->m_zD0Self = + DELAY0_OUT - pReverbData->m_nMaxExcursion - nOffset; + + nOffset = ReverbCalculateNoise( pReverbData->m_nMaxExcursion, &pReverbData->m_nNoise ); + + pReverbData->m_zD1Self = + DELAY1_OUT - pReverbData->m_nMaxExcursion + nOffset; + + } // end if-else (pReverbData->m_nPhaseIncrement > 0) + + // Reverse the direction of the sin,cos so that the + // tap whose coef was previously increasing now decreases + // and vice versa + pReverbData->m_nPhaseIncrement = -pReverbData->m_nPhaseIncrement; + + } // end if counter >= update interval + + //compute what phase will be next time + pReverbData->m_nPhase += pReverbData->m_nPhaseIncrement; + + //calculate what the new sin and cos need to reach by the next update + ReverbCalculateSinCos(pReverbData->m_nPhase, &tempSin, &tempCos); + + //calculate the per-sample increment required to get there by the next update + /*lint -e{702} shift for performance */ + pReverbData->m_nSinIncrement = + (tempSin - pReverbData->m_nSin) >> REVERB_UPDATE_PERIOD_IN_BITS; + + /*lint -e{702} shift for performance */ + pReverbData->m_nCosIncrement = + (tempCos - pReverbData->m_nCos) >> REVERB_UPDATE_PERIOD_IN_BITS; + + + /* increment update counter */ + pReverbData->m_nXfadeCounter += (EAS_U16) nNumSamplesToAdd; + + return EAS_SUCCESS; + +} /* end ReverbUpdateXfade */ + + +/*---------------------------------------------------------------------------- + * ReverbCalculateNoise + *---------------------------------------------------------------------------- + * Purpose: + * Calculate a noise sample and limit its value + * + * Inputs: + * nMaxExcursion - noise value is limited to this value + * pnNoise - return new noise sample in this (not limited) + * + * Outputs: + * new limited noise value + * + * Side Effects: + * - *pnNoise noise value is updated + * + *---------------------------------------------------------------------------- +*/ +EAS_U16 ReverbCalculateNoise(EAS_U16 nMaxExcursion, EAS_I16 *pnNoise) +{ + // calculate new noise value + *pnNoise = (EAS_I16) (*pnNoise * 5 + 1); + +#if 0 // 1xxx, test + *pnNoise = 0; +#endif // 1xxx, test + + // return the limited noise value + return (nMaxExcursion & (*pnNoise)); + +} /* end ReverbCalculateNoise */ + +/*---------------------------------------------------------------------------- + * ReverbCalculateSinCos + *---------------------------------------------------------------------------- + * Purpose: + * Calculate a new sin and cosine value based on the given phase + * + * Inputs: + * nPhase - phase angle + * pnSin - input old value, output new value + * pnCos - input old value, output new value + * + * Outputs: + * + * Side Effects: + * - *pnSin, *pnCos are updated + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT ReverbCalculateSinCos(EAS_I16 nPhase, EAS_I16 *pnSin, EAS_I16 *pnCos) +{ + EAS_I32 nTemp; + EAS_I32 nNetAngle; + + // -1 <= nPhase < 1 + // However, for the calculation, we need a value + // that ranges from -1/2 to +1/2, so divide the phase by 2 + /*lint -e{702} shift for performance */ + nNetAngle = nPhase >> 1; + + /* + Implement the following + sin(x) = (2-4*c)*x^2 + c + x + cos(x) = (2-4*c)*x^2 + c - x + + where c = 1/sqrt(2) + using the a0 + x*(a1 + x*a2) approach + */ + + /* limit the input "angle" to be between -0.5 and +0.5 */ + if (nNetAngle > EG1_HALF) + { + nNetAngle = EG1_HALF; + } + else if (nNetAngle < EG1_MINUS_HALF) + { + nNetAngle = EG1_MINUS_HALF; + } + + /* calculate sin */ + nTemp = EG1_ONE + MULT_EG1_EG1(REVERB_PAN_G2, nNetAngle); + nTemp = REVERB_PAN_G0 + MULT_EG1_EG1(nTemp, nNetAngle); + *pnSin = (EAS_I16) SATURATE_EG1(nTemp); + + /* calculate cos */ + nTemp = -EG1_ONE + MULT_EG1_EG1(REVERB_PAN_G2, nNetAngle); + nTemp = REVERB_PAN_G0 + MULT_EG1_EG1(nTemp, nNetAngle); + *pnCos = (EAS_I16) SATURATE_EG1(nTemp); + + return EAS_SUCCESS; +} /* end ReverbCalculateSinCos */ + +/*---------------------------------------------------------------------------- + * Reverb + *---------------------------------------------------------------------------- + * Purpose: + * apply reverb to the given signal + * + * Inputs: + * nNu + * pnSin - input old value, output new value + * pnCos - input old value, output new value + * + * Outputs: + * number of samples actually reverberated + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT Reverb(S_REVERB_OBJECT *pReverbData, EAS_INT nNumSamplesToAdd, EAS_PCM *pOutputBuffer, EAS_PCM *pInputBuffer) +{ + EAS_I32 i; + EAS_I32 nDelayOut; + EAS_U16 nBase; + + EAS_U32 nAddr; + EAS_I32 nTemp1; + EAS_I32 nTemp2; + EAS_I32 nApIn; + EAS_I32 nApOut; + + EAS_I32 j; + EAS_I32 nEarlyOut; + + EAS_I32 tempValue; + + + // get the base address + nBase = pReverbData->m_nBaseIndex; + + for (i=0; i < nNumSamplesToAdd; i++) + { + // ********** Left Allpass - start + // left input = (left dry/4) + right feedback from previous period + /*lint -e{702} use shift for performance */ + nApIn = ((*pInputBuffer++)>>2) + pReverbData->m_nRevOutFbkR; +// nApIn = *pInputBuffer++; // 1xxx test and debug ap + + // fetch allpass delay line out + //nAddr = CIRCULAR(nBase, psAp0->m_zApOut, REVERB_BUFFER_MASK); + nAddr = CIRCULAR(nBase, pReverbData->m_sAp0.m_zApOut, REVERB_BUFFER_MASK); + nDelayOut = pReverbData->m_nDelayLine[nAddr]; + + // calculate allpass feedforward; subtract the feedforward result + nTemp1 = MULT_EG1_EG1(nApIn, pReverbData->m_sAp0.m_nApGain); + nApOut = SATURATE(nDelayOut - nTemp1); // allpass output + + // calculate allpass feedback; add the feedback result + nTemp1 = MULT_EG1_EG1(nApOut, pReverbData->m_sAp0.m_nApGain); + nTemp1 = SATURATE(nApIn + nTemp1); + + // inject into allpass delay + nAddr = CIRCULAR(nBase, pReverbData->m_sAp0.m_zApIn, REVERB_BUFFER_MASK); + pReverbData->m_nDelayLine[nAddr] = (EAS_PCM) nTemp1; + + // inject allpass output into delay line + nAddr = CIRCULAR(nBase, pReverbData->m_zD0In, REVERB_BUFFER_MASK); + pReverbData->m_nDelayLine[nAddr] = (EAS_PCM) nApOut; + + // ********** Left Allpass - end + + // ********** Right Allpass - start + // right input = (right dry/4) + left feedback from previous period + /*lint -e{702} use shift for performance */ + nApIn = ((*pInputBuffer++)>>2) + pReverbData->m_nRevOutFbkL; +// nApIn = *pInputBuffer++; // 1xxx test and debug ap + + // fetch allpass delay line out + nAddr = CIRCULAR(nBase, pReverbData->m_sAp1.m_zApOut, REVERB_BUFFER_MASK); + nDelayOut = pReverbData->m_nDelayLine[nAddr]; + + // calculate allpass feedforward; subtract the feedforward result + nTemp1 = MULT_EG1_EG1(nApIn, pReverbData->m_sAp1.m_nApGain); + nApOut = SATURATE(nDelayOut - nTemp1); // allpass output + + // calculate allpass feedback; add the feedback result + nTemp1 = MULT_EG1_EG1(nApOut, pReverbData->m_sAp1.m_nApGain); + nTemp1 = SATURATE(nApIn + nTemp1); + + // inject into allpass delay + nAddr = CIRCULAR(nBase, pReverbData->m_sAp1.m_zApIn, REVERB_BUFFER_MASK); + pReverbData->m_nDelayLine[nAddr] = (EAS_PCM) nTemp1; + + // inject allpass output into delay line + nAddr = CIRCULAR(nBase, pReverbData->m_zD1In, REVERB_BUFFER_MASK); + pReverbData->m_nDelayLine[nAddr] = (EAS_PCM) nApOut; + + // ********** Right Allpass - end + + // ********** D0 output - start + // fetch delay line self out + nAddr = CIRCULAR(nBase, pReverbData->m_zD0Self, REVERB_BUFFER_MASK); + nDelayOut = pReverbData->m_nDelayLine[nAddr]; + + // calculate delay line self out + nTemp1 = MULT_EG1_EG1(nDelayOut, pReverbData->m_nSin); + + // fetch delay line cross out + nAddr = CIRCULAR(nBase, pReverbData->m_zD1Cross, REVERB_BUFFER_MASK); + nDelayOut = pReverbData->m_nDelayLine[nAddr]; + + // calculate delay line self out + nTemp2 = MULT_EG1_EG1(nDelayOut, pReverbData->m_nCos); + + // calculate unfiltered delay out + nDelayOut = SATURATE(nTemp1 + nTemp2); + + // calculate lowpass filter (mixer scale factor included in LPF feedforward) + nTemp1 = MULT_EG1_EG1(nDelayOut, pReverbData->m_nLpfFwd); + + nTemp2 = MULT_EG1_EG1(pReverbData->m_zLpf0, pReverbData->m_nLpfFbk); + + // calculate filtered delay out and simultaneously update LPF state variable + // filtered delay output is stored in m_zLpf0 + pReverbData->m_zLpf0 = (EAS_PCM) SATURATE(nTemp1 + nTemp2); + + // ********** D0 output - end + + // ********** D1 output - start + // fetch delay line self out + nAddr = CIRCULAR(nBase, pReverbData->m_zD1Self, REVERB_BUFFER_MASK); + nDelayOut = pReverbData->m_nDelayLine[nAddr]; + + // calculate delay line self out + nTemp1 = MULT_EG1_EG1(nDelayOut, pReverbData->m_nSin); + + // fetch delay line cross out + nAddr = CIRCULAR(nBase, pReverbData->m_zD0Cross, REVERB_BUFFER_MASK); + nDelayOut = pReverbData->m_nDelayLine[nAddr]; + + // calculate delay line self out + nTemp2 = MULT_EG1_EG1(nDelayOut, pReverbData->m_nCos); + + // calculate unfiltered delay out + nDelayOut = SATURATE(nTemp1 + nTemp2); + + // calculate lowpass filter (mixer scale factor included in LPF feedforward) + nTemp1 = MULT_EG1_EG1(nDelayOut, pReverbData->m_nLpfFwd); + + nTemp2 = MULT_EG1_EG1(pReverbData->m_zLpf1, pReverbData->m_nLpfFbk); + + // calculate filtered delay out and simultaneously update LPF state variable + // filtered delay output is stored in m_zLpf1 + pReverbData->m_zLpf1 = (EAS_PCM)SATURATE(nTemp1 + nTemp2); + + // ********** D1 output - end + + // ********** mixer and feedback - start + // sum is fedback to right input (R + L) + pReverbData->m_nRevOutFbkL = + (EAS_PCM)SATURATE((EAS_I32)pReverbData->m_zLpf1 + (EAS_I32)pReverbData->m_zLpf0); + + // difference is feedback to left input (R - L) + /*lint -e{685} lint complains that it can't saturate negative */ + pReverbData->m_nRevOutFbkR = + (EAS_PCM)SATURATE((EAS_I32)pReverbData->m_zLpf1 - (EAS_I32)pReverbData->m_zLpf0); + + // ********** mixer and feedback - end + + // ********** start early reflection generator, left + //psEarly = &(pReverbData->m_sEarlyL); + + nEarlyOut = 0; + + for (j=0; j < REVERB_MAX_NUM_REFLECTIONS; j++) + { + // fetch delay line out + //nAddr = CIRCULAR(nBase, psEarly->m_zDelay[j], REVERB_BUFFER_MASK); + nAddr = CIRCULAR(nBase, pReverbData->m_sEarlyL.m_zDelay[j], REVERB_BUFFER_MASK); + + nDelayOut = pReverbData->m_nDelayLine[nAddr]; + + // calculate reflection + //nTemp1 = MULT_EG1_EG1(nDelayOut, psEarly->m_nGain[j]); + nTemp1 = MULT_EG1_EG1(nDelayOut, pReverbData->m_sEarlyL.m_nGain[j]); + + nEarlyOut = SATURATE(nEarlyOut + nTemp1); + + } // end for (j=0; j < REVERB_MAX_NUM_REFLECTIONS; j++) + + // apply lowpass to early reflections + //nTemp1 = MULT_EG1_EG1(nEarlyOut, psEarly->m_nLpfFwd); + nTemp1 = MULT_EG1_EG1(nEarlyOut, pReverbData->m_sEarlyL.m_nLpfFwd); + + //nTemp2 = MULT_EG1_EG1(psEarly->m_zLpf, psEarly->m_nLpfFbk); + nTemp2 = MULT_EG1_EG1(pReverbData->m_sEarlyL.m_zLpf, pReverbData->m_sEarlyL.m_nLpfFbk); + + + // calculate filtered out and simultaneously update LPF state variable + // filtered output is stored in m_zLpf1 + //psEarly->m_zLpf = SATURATE(nTemp1 + nTemp2); + pReverbData->m_sEarlyL.m_zLpf = (EAS_PCM) SATURATE(nTemp1 + nTemp2); + + // combine filtered early and late reflections for output + //*pOutputBuffer++ = inL; + //tempValue = SATURATE(psEarly->m_zLpf + pReverbData->m_nRevOutFbkL); + tempValue = SATURATE((EAS_I32)pReverbData->m_sEarlyL.m_zLpf + (EAS_I32)pReverbData->m_nRevOutFbkL); + //scale reverb output by wet level + /*lint -e{701} use shift for performance */ + tempValue = MULT_EG1_EG1(tempValue, (pReverbData->m_nWet<<1)); + //sum with output buffer + tempValue += *pOutputBuffer; + *pOutputBuffer++ = (EAS_PCM)SATURATE(tempValue); + + // ********** end early reflection generator, left + + // ********** start early reflection generator, right + //psEarly = &(pReverbData->m_sEarlyR); + + nEarlyOut = 0; + + for (j=0; j < REVERB_MAX_NUM_REFLECTIONS; j++) + { + // fetch delay line out + nAddr = CIRCULAR(nBase, pReverbData->m_sEarlyR.m_zDelay[j], REVERB_BUFFER_MASK); + nDelayOut = pReverbData->m_nDelayLine[nAddr]; + + // calculate reflection + nTemp1 = MULT_EG1_EG1(nDelayOut, pReverbData->m_sEarlyR.m_nGain[j]); + + nEarlyOut = SATURATE(nEarlyOut + nTemp1); + + } // end for (j=0; j < REVERB_MAX_NUM_REFLECTIONS; j++) + + // apply lowpass to early reflections + nTemp1 = MULT_EG1_EG1(nEarlyOut, pReverbData->m_sEarlyR.m_nLpfFwd); + + nTemp2 = MULT_EG1_EG1(pReverbData->m_sEarlyR.m_zLpf, pReverbData->m_sEarlyR.m_nLpfFbk); + + // calculate filtered out and simultaneously update LPF state variable + // filtered output is stored in m_zLpf1 + pReverbData->m_sEarlyR.m_zLpf = (EAS_PCM)SATURATE(nTemp1 + nTemp2); + + // combine filtered early and late reflections for output + //*pOutputBuffer++ = inR; + tempValue = SATURATE((EAS_I32)pReverbData->m_sEarlyR.m_zLpf + (EAS_I32)pReverbData->m_nRevOutFbkR); + //scale reverb output by wet level + /*lint -e{701} use shift for performance */ + tempValue = MULT_EG1_EG1(tempValue, (pReverbData->m_nWet << 1)); + //sum with output buffer + tempValue = tempValue + *pOutputBuffer; + *pOutputBuffer++ = (EAS_PCM)SATURATE(tempValue); + + // ********** end early reflection generator, right + + // decrement base addr for next sample period + nBase--; + + pReverbData->m_nSin += pReverbData->m_nSinIncrement; + pReverbData->m_nCos += pReverbData->m_nCosIncrement; + + } // end for (i=0; i < nNumSamplesToAdd; i++) + + // store the most up to date version + pReverbData->m_nBaseIndex = nBase; + + return EAS_SUCCESS; +} /* end Reverb */ + + + +/*---------------------------------------------------------------------------- + * ReverbShutdown() + *---------------------------------------------------------------------------- + * Purpose: + * Initializes the Reverb effect. + * + * Inputs: + * pInstData - handle to instance data + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ReverbShutdown (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR pInstData) +{ + /* check Configuration Module for static memory allocation */ + if (!pEASData->staticMemoryModel) + EAS_HWFree(pEASData->hwInstData, pInstData); + return EAS_SUCCESS; +} /* end ReverbShutdown */ + +/*---------------------------------------------------------------------------- + * ReverbGetParam() + *---------------------------------------------------------------------------- + * Purpose: + * Get a Reverb parameter + * + * Inputs: + * pInstData - handle to instance data + * param - parameter index + * *pValue - pointer to variable to hold retrieved value + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ReverbGetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue) +{ + S_REVERB_OBJECT *p; + + p = (S_REVERB_OBJECT*) pInstData; + + switch (param) + { + case EAS_PARAM_REVERB_BYPASS: + *pValue = (EAS_I32) p->m_bBypass; + break; + case EAS_PARAM_REVERB_PRESET: + *pValue = (EAS_I8) p->m_nCurrentRoom; + break; + case EAS_PARAM_REVERB_WET: + *pValue = p->m_nWet; + break; + case EAS_PARAM_REVERB_DRY: + *pValue = p->m_nDry; + break; + default: + return EAS_ERROR_INVALID_PARAMETER; + } + return EAS_SUCCESS; +} /* end ReverbGetParam */ + + +/*---------------------------------------------------------------------------- + * ReverbSetParam() + *---------------------------------------------------------------------------- + * Purpose: + * Set a Reverb parameter + * + * Inputs: + * pInstData - handle to instance data + * param - parameter index + * *pValue - new paramter value + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ReverbSetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value) +{ + S_REVERB_OBJECT *p; + + p = (S_REVERB_OBJECT*) pInstData; + + switch (param) + { + case EAS_PARAM_REVERB_BYPASS: + p->m_bBypass = (EAS_BOOL) value; + break; + case EAS_PARAM_REVERB_PRESET: + if(value!=EAS_PARAM_REVERB_LARGE_HALL && value!=EAS_PARAM_REVERB_HALL && + value!=EAS_PARAM_REVERB_CHAMBER && value!=EAS_PARAM_REVERB_ROOM) + return EAS_ERROR_INVALID_PARAMETER; + p->m_nNextRoom = (EAS_I16)value; + break; + case EAS_PARAM_REVERB_WET: + if(value>EAS_REVERB_WET_MAX || valuem_nWet = (EAS_I16)value; + break; + case EAS_PARAM_REVERB_DRY: + if(value>EAS_REVERB_DRY_MAX || valuem_nDry = (EAS_I16)value; + break; + default: + return EAS_ERROR_INVALID_PARAMETER; + } + return EAS_SUCCESS; +} /* end ReverbSetParam */ + + +/*---------------------------------------------------------------------------- + * ReverbUpdateRoom + *---------------------------------------------------------------------------- + * Purpose: + * Update the room's preset parameters as required + * + * Inputs: + * + * Outputs: + * + * + * Side Effects: + * - reverb paramters (fbk, fwd, etc) will be changed + * - m_nCurrentRoom := m_nNextRoom + *---------------------------------------------------------------------------- +*/ +EAS_RESULT ReverbUpdateRoom(S_REVERB_OBJECT *pReverbData) +{ + EAS_INT temp; + + S_REVERB_PRESET *pPreset = &pReverbData->m_sPreset.m_sPreset[pReverbData->m_nNextRoom]; + + pReverbData->m_nLpfFwd = pPreset->m_nLpfFwd; + pReverbData->m_nLpfFbk = pPreset->m_nLpfFbk; + + pReverbData->m_nEarly = pPreset->m_nEarly; + pReverbData->m_nWet = pPreset->m_nWet; + pReverbData->m_nDry = pPreset->m_nDry; + + + pReverbData->m_nMaxExcursion = pPreset->m_nMaxExcursion; + //stored as time based, convert to sample based + temp = pPreset->m_nXfadeInterval; + /*lint -e{702} shift for performance */ + temp = (temp * _OUTPUT_SAMPLE_RATE) >> 16; + pReverbData->m_nXfadeInterval = (EAS_U16) temp; + //gpsReverbObject->m_nXfadeInterval = pPreset->m_nXfadeInterval; + pReverbData->m_sAp0.m_nApGain = pPreset->m_nAp0_ApGain; + //stored as time based, convert to absolute sample value + temp = pPreset->m_nAp0_ApOut; + /*lint -e{702} shift for performance */ + temp = (temp * _OUTPUT_SAMPLE_RATE) >> 16; + pReverbData->m_sAp0.m_zApOut = (EAS_U16) (pReverbData->m_sAp0.m_zApIn + temp); + //gpsReverbObject->m_sAp0.m_zApOut = pPreset->m_nAp0_ApOut; + pReverbData->m_sAp1.m_nApGain = pPreset->m_nAp1_ApGain; + //stored as time based, convert to absolute sample value + temp = pPreset->m_nAp1_ApOut; + /*lint -e{702} shift for performance */ + temp = (temp * _OUTPUT_SAMPLE_RATE) >> 16; + pReverbData->m_sAp1.m_zApOut = (EAS_U16) (pReverbData->m_sAp1.m_zApIn + temp); + //gpsReverbObject->m_sAp1.m_zApOut = pPreset->m_nAp1_ApOut; + + pReverbData->m_nCurrentRoom = pReverbData->m_nNextRoom; + + return EAS_SUCCESS; + +} /* end ReverbUpdateRoom */ + + +/*---------------------------------------------------------------------------- + * ReverbReadInPresets() + *---------------------------------------------------------------------------- + * Purpose: sets global reverb preset bank to defaults + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT ReverbReadInPresets(S_REVERB_OBJECT *pReverbData) +{ + + int preset = 0; + int defaultPreset = 0; + + //now init any remaining presets to defaults + for (defaultPreset = preset; defaultPreset < REVERB_MAX_ROOM_TYPE; defaultPreset++) + { + S_REVERB_PRESET *pPreset = &pReverbData->m_sPreset.m_sPreset[defaultPreset]; + if (defaultPreset == 0 || defaultPreset > REVERB_MAX_ROOM_TYPE-1) + { + pPreset->m_nLpfFbk = 8307; + pPreset->m_nLpfFwd = 14768; + pPreset->m_nEarly = 0; + pPreset->m_nWet = 27690; + pPreset->m_nDry = 32767; + pPreset->m_nEarlyL_LpfFbk = 3692; + pPreset->m_nEarlyL_LpfFwd = 29075; + pPreset->m_nEarlyL_Delay0 = 922; + pPreset->m_nEarlyL_Gain0 = 22152; + pPreset->m_nEarlyL_Delay1 = 1462; + pPreset->m_nEarlyL_Gain1 = 17537; + pPreset->m_nEarlyL_Delay2 = 0; + pPreset->m_nEarlyL_Gain2 = 14768; + pPreset->m_nEarlyL_Delay3 = 1221; + pPreset->m_nEarlyL_Gain3 = 14307; + pPreset->m_nEarlyL_Delay4 = 0; + pPreset->m_nEarlyL_Gain4 = 13384; + pPreset->m_nEarlyR_Delay0 = 502; + pPreset->m_nEarlyR_Gain0 = 20306; + pPreset->m_nEarlyR_Delay1 = 1762; + pPreset->m_nEarlyR_Gain1 = 17537; + pPreset->m_nEarlyR_Delay2 = 0; + pPreset->m_nEarlyR_Gain2 = 14768; + pPreset->m_nEarlyR_Delay3 = 0; + pPreset->m_nEarlyR_Gain3 = 16153; + pPreset->m_nEarlyR_Delay4 = 0; + pPreset->m_nEarlyR_Gain4 = 13384; + pPreset->m_nMaxExcursion = 127; + pPreset->m_nXfadeInterval = 6388; + pPreset->m_nAp0_ApGain = 15691; + pPreset->m_nAp0_ApOut = 711; + pPreset->m_nAp1_ApGain = 17999; + pPreset->m_nAp1_ApOut = 1113; + pPreset->m_rfu4 = 0; + pPreset->m_rfu5 = 0; + pPreset->m_rfu6 = 0; + pPreset->m_rfu7 = 0; + pPreset->m_rfu8 = 0; + pPreset->m_rfu9 = 0; + pPreset->m_rfu10 = 0; + } + else if (defaultPreset == 1) + { + pPreset->m_nLpfFbk = 6461; + pPreset->m_nLpfFwd = 14307; + pPreset->m_nEarly = 0; + pPreset->m_nWet = 27690; + pPreset->m_nDry = 32767; + pPreset->m_nEarlyL_LpfFbk = 3692; + pPreset->m_nEarlyL_LpfFwd = 29075; + pPreset->m_nEarlyL_Delay0 = 922; + pPreset->m_nEarlyL_Gain0 = 22152; + pPreset->m_nEarlyL_Delay1 = 1462; + pPreset->m_nEarlyL_Gain1 = 17537; + pPreset->m_nEarlyL_Delay2 = 0; + pPreset->m_nEarlyL_Gain2 = 14768; + pPreset->m_nEarlyL_Delay3 = 1221; + pPreset->m_nEarlyL_Gain3 = 14307; + pPreset->m_nEarlyL_Delay4 = 0; + pPreset->m_nEarlyL_Gain4 = 13384; + pPreset->m_nEarlyR_Delay0 = 502; + pPreset->m_nEarlyR_Gain0 = 20306; + pPreset->m_nEarlyR_Delay1 = 1762; + pPreset->m_nEarlyR_Gain1 = 17537; + pPreset->m_nEarlyR_Delay2 = 0; + pPreset->m_nEarlyR_Gain2 = 14768; + pPreset->m_nEarlyR_Delay3 = 0; + pPreset->m_nEarlyR_Gain3 = 16153; + pPreset->m_nEarlyR_Delay4 = 0; + pPreset->m_nEarlyR_Gain4 = 13384; + pPreset->m_nMaxExcursion = 127; + pPreset->m_nXfadeInterval = 6391; + pPreset->m_nAp0_ApGain = 15230; + pPreset->m_nAp0_ApOut = 708; + pPreset->m_nAp1_ApGain = 9692; + pPreset->m_nAp1_ApOut = 1113; + pPreset->m_rfu4 = 0; + pPreset->m_rfu5 = 0; + pPreset->m_rfu6 = 0; + pPreset->m_rfu7 = 0; + pPreset->m_rfu8 = 0; + pPreset->m_rfu9 = 0; + pPreset->m_rfu10 = 0; + } + else if (defaultPreset == 2) + { + pPreset->m_nLpfFbk = 5077; + pPreset->m_nLpfFwd = 12922; + pPreset->m_nEarly = 0; + pPreset->m_nWet = 24460; + pPreset->m_nDry = 32767; + pPreset->m_nEarlyL_LpfFbk = 3692; + pPreset->m_nEarlyL_LpfFwd = 29075; + pPreset->m_nEarlyL_Delay0 = 922; + pPreset->m_nEarlyL_Gain0 = 22152; + pPreset->m_nEarlyL_Delay1 = 1462; + pPreset->m_nEarlyL_Gain1 = 17537; + pPreset->m_nEarlyL_Delay2 = 0; + pPreset->m_nEarlyL_Gain2 = 14768; + pPreset->m_nEarlyL_Delay3 = 1221; + pPreset->m_nEarlyL_Gain3 = 14307; + pPreset->m_nEarlyL_Delay4 = 0; + pPreset->m_nEarlyL_Gain4 = 13384; + pPreset->m_nEarlyR_Delay0 = 502; + pPreset->m_nEarlyR_Gain0 = 20306; + pPreset->m_nEarlyR_Delay1 = 1762; + pPreset->m_nEarlyR_Gain1 = 17537; + pPreset->m_nEarlyR_Delay2 = 0; + pPreset->m_nEarlyR_Gain2 = 14768; + pPreset->m_nEarlyR_Delay3 = 0; + pPreset->m_nEarlyR_Gain3 = 16153; + pPreset->m_nEarlyR_Delay4 = 0; + pPreset->m_nEarlyR_Gain4 = 13384; + pPreset->m_nMaxExcursion = 127; + pPreset->m_nXfadeInterval = 6449; + pPreset->m_nAp0_ApGain = 15691; + pPreset->m_nAp0_ApOut = 774; + pPreset->m_nAp1_ApGain = 15691; + pPreset->m_nAp1_ApOut = 1113; + pPreset->m_rfu4 = 0; + pPreset->m_rfu5 = 0; + pPreset->m_rfu6 = 0; + pPreset->m_rfu7 = 0; + pPreset->m_rfu8 = 0; + pPreset->m_rfu9 = 0; + pPreset->m_rfu10 = 0; + } + else if (defaultPreset == 3) + { + pPreset->m_nLpfFbk = 5077; + pPreset->m_nLpfFwd = 11076; + pPreset->m_nEarly = 0; + pPreset->m_nWet = 23075; + pPreset->m_nDry = 32767; + pPreset->m_nEarlyL_LpfFbk = 3692; + pPreset->m_nEarlyL_LpfFwd = 29075; + pPreset->m_nEarlyL_Delay0 = 922; + pPreset->m_nEarlyL_Gain0 = 22152; + pPreset->m_nEarlyL_Delay1 = 1462; + pPreset->m_nEarlyL_Gain1 = 17537; + pPreset->m_nEarlyL_Delay2 = 0; + pPreset->m_nEarlyL_Gain2 = 14768; + pPreset->m_nEarlyL_Delay3 = 1221; + pPreset->m_nEarlyL_Gain3 = 14307; + pPreset->m_nEarlyL_Delay4 = 0; + pPreset->m_nEarlyL_Gain4 = 13384; + pPreset->m_nEarlyR_Delay0 = 502; + pPreset->m_nEarlyR_Gain0 = 20306; + pPreset->m_nEarlyR_Delay1 = 1762; + pPreset->m_nEarlyR_Gain1 = 17537; + pPreset->m_nEarlyR_Delay2 = 0; + pPreset->m_nEarlyR_Gain2 = 14768; + pPreset->m_nEarlyR_Delay3 = 0; + pPreset->m_nEarlyR_Gain3 = 16153; + pPreset->m_nEarlyR_Delay4 = 0; + pPreset->m_nEarlyR_Gain4 = 13384; + pPreset->m_nMaxExcursion = 127; + pPreset->m_nXfadeInterval = 6470; //6483; + pPreset->m_nAp0_ApGain = 14768; + pPreset->m_nAp0_ApOut = 792; + pPreset->m_nAp1_ApGain = 15783; + pPreset->m_nAp1_ApOut = 1113; + pPreset->m_rfu4 = 0; + pPreset->m_rfu5 = 0; + pPreset->m_rfu6 = 0; + pPreset->m_rfu7 = 0; + pPreset->m_rfu8 = 0; + pPreset->m_rfu9 = 0; + pPreset->m_rfu10 = 0; + + } + } + + return EAS_SUCCESS; +} diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_reverbdata.c b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_reverbdata.c new file mode 100755 index 0000000..db34b48 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_reverbdata.c @@ -0,0 +1,34 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_reverbdata.c + * + * Contents and purpose: + * Contains the static data allocation for the Reverb effect + * + * + * Copyright Sonic Network Inc. 2006 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 550 $ + * $Date: 2007-02-02 09:37:03 -0800 (Fri, 02 Feb 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_reverbdata.h" + +S_REVERB_OBJECT eas_ReverbData; + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_reverbdata.h b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_reverbdata.h new file mode 100755 index 0000000..6171a01 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_reverbdata.h @@ -0,0 +1,486 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_reverbdata.h + * + * Contents and purpose: + * Contains the prototypes for the Reverb effect. + * + * + * Copyright Sonic Network Inc. 2006 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 499 $ + * $Date: 2006-12-11 16:07:20 -0800 (Mon, 11 Dec 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_REVERBDATA_H +#define _EAS_REVERBDATA_H + +#include "eas_types.h" +#include "eas_audioconst.h" + +/*------------------------------------ + * defines + *------------------------------------ +*/ + +/* +CIRCULAR() calculates the array index using modulo arithmetic. +The "trick" is that modulo arithmetic is simplified by masking +the effective address where the mask is (2^n)-1. This only works +if the buffer size is a power of two. +*/ +#define CIRCULAR(base,offset,size) (EAS_U32)( \ + ( \ + ((EAS_I32)(base)) + ((EAS_I32)(offset)) \ + ) \ + & size \ + ) + +/* reverb parameters are updated every 2^(REVERB_UPDATE_PERIOD_IN_BITS) samples */ +#if defined (_SAMPLE_RATE_8000) + +#define REVERB_UPDATE_PERIOD_IN_BITS 5 +#define REVERB_BUFFER_SIZE_IN_SAMPLES 2048 + +#elif defined (_SAMPLE_RATE_16000) + +#define REVERB_UPDATE_PERIOD_IN_BITS 6 +#define REVERB_BUFFER_SIZE_IN_SAMPLES 4096 + +#elif defined (_SAMPLE_RATE_22050) + +#define REVERB_UPDATE_PERIOD_IN_BITS 7 +#define REVERB_BUFFER_SIZE_IN_SAMPLES 4096 + +#elif defined (_SAMPLE_RATE_32000) + +#define REVERB_UPDATE_PERIOD_IN_BITS 7 +#define REVERB_BUFFER_SIZE_IN_SAMPLES 8192 + +#elif defined (_SAMPLE_RATE_44100) + +#define REVERB_UPDATE_PERIOD_IN_BITS 8 +#define REVERB_BUFFER_SIZE_IN_SAMPLES 8192 + +#elif defined (_SAMPLE_RATE_48000) + +#define REVERB_UPDATE_PERIOD_IN_BITS 8 +#define REVERB_BUFFER_SIZE_IN_SAMPLES 8192 + +#endif + +// Define a mask for circular addressing, so that array index +// can wraparound and stay in array boundary of 0, 1, ..., (buffer size -1) +// The buffer size MUST be a power of two +#define REVERB_BUFFER_MASK (REVERB_BUFFER_SIZE_IN_SAMPLES -1) + +#define REVERB_MAX_ROOM_TYPE 4 // any room numbers larger than this are invalid +#define REVERB_MAX_NUM_REFLECTIONS 5 // max num reflections per channel + +/* synth parameters are updated every SYNTH_UPDATE_PERIOD_IN_SAMPLES */ +#define REVERB_UPDATE_PERIOD_IN_SAMPLES (EAS_I32)(0x1L << REVERB_UPDATE_PERIOD_IN_BITS) + +/* +calculate the update counter by bitwise ANDING with this value to +generate a 2^n modulo value +*/ +#define REVERB_MODULO_UPDATE_PERIOD_IN_SAMPLES (EAS_I32)(REVERB_UPDATE_PERIOD_IN_SAMPLES -1) + +/* synth parameters are updated every SYNTH_UPDATE_PERIOD_IN_SECONDS seconds */ +#define REVERB_UPDATE_PERIOD_IN_SECONDS (REVERB_UPDATE_PERIOD_IN_SAMPLES / _OUTPUT_SAMPLE_RATE) + +// xfade parameters +#define REVERB_XFADE_PERIOD_IN_SECONDS (100.0 / 1000.0) // xfade once every this many seconds + +#define REVERB_XFADE_PERIOD_IN_SAMPLES (REVERB_XFADE_PERIOD_IN_SECONDS * _OUTPUT_SAMPLE_RATE) + +#define REVERB_XFADE_PHASE_INCREMENT (EAS_I16)(65536 / ((EAS_I16)REVERB_XFADE_PERIOD_IN_SAMPLES/(EAS_I16)REVERB_UPDATE_PERIOD_IN_SAMPLES)) + +/**********/ +/* the entire synth uses various flags in a bit field */ + +/* if flag is set, synth reset has been requested */ +#define REVERB_FLAG_RESET_IS_REQUESTED 0x01 /* bit 0 */ +#define MASK_REVERB_RESET_IS_REQUESTED 0x01 +#define MASK_REVERB_RESET_IS_NOT_REQUESTED (EAS_U32)(~MASK_REVERB_RESET_IS_REQUESTED) + +/* +by default, we always want to update ALL channel parameters +when we reset the synth (e.g., during GM ON) +*/ +#define DEFAULT_REVERB_FLAGS 0x0 + +/* coefficients for generating sin, cos */ +#define REVERB_PAN_G2 4294940151 /* -0.82842712474619 = 2 - 4/sqrt(2) */ +/* +EAS_I32 nPanG1 = +1.0 for sin +EAS_I32 nPanG1 = -1.0 for cos +*/ +#define REVERB_PAN_G0 23170 /* 0.707106781186547 = 1/sqrt(2) */ + +/*************************************************************/ +// define the input injection points +#define GUARD 5 // safety guard of this many samples + +#define MAX_AP_TIME (double) (20.0/1000.0) // delay time in milliseconds +#define MAX_DELAY_TIME (double) (65.0/1000.0) // delay time in milliseconds + +#define MAX_AP_SAMPLES (int)(((double) MAX_AP_TIME) * ((double) _OUTPUT_SAMPLE_RATE)) +#define MAX_DELAY_SAMPLES (int)(((double) MAX_DELAY_TIME) * ((double) _OUTPUT_SAMPLE_RATE)) + +#define AP0_IN 0 +#define AP1_IN (AP0_IN + MAX_AP_SAMPLES + GUARD) +#define DELAY0_IN (AP1_IN + MAX_AP_SAMPLES + GUARD) +#define DELAY1_IN (DELAY0_IN + MAX_DELAY_SAMPLES + GUARD) + +// Define the max offsets for the end points of each section +// i.e., we don't expect a given section's taps to go beyond +// the following limits +#define AP0_OUT (AP0_IN + MAX_AP_SAMPLES -1) +#define AP1_OUT (AP1_IN + MAX_AP_SAMPLES -1) +#define DELAY0_OUT (DELAY0_IN + MAX_DELAY_SAMPLES -1) +#define DELAY1_OUT (DELAY1_IN + MAX_DELAY_SAMPLES -1) + +#define REVERB_DEFAULT_ROOM_NUMBER 1 // default preset number +#define DEFAULT_AP0_LENGTH (int)(((double) (17.0/1000.0)) * ((double) _OUTPUT_SAMPLE_RATE)) +#define DEFAULT_AP0_GAIN 19400 +#define DEFAULT_AP1_LENGTH (int)(((double) (16.5/1000.0)) * ((double) _OUTPUT_SAMPLE_RATE)) +#define DEFAULT_AP1_GAIN -19400 + +#define REVERB_DEFAULT_WET 32767 +#define REVERB_DEFAULT_DRY 0 + +#define EAS_REVERB_WET_MAX 32767 +#define EAS_REVERB_WET_MIN 0 +#define EAS_REVERB_DRY_MAX 32767 +#define EAS_REVERB_DRY_MIN 0 + +/* parameters for each allpass */ +typedef struct +{ + EAS_U16 m_zApOut; // delay offset for ap out + + EAS_I16 m_nApGain; // gain for ap + + EAS_U16 m_zApIn; // delay offset for ap in + +} S_ALLPASS_OBJECT; + + +/* parameters for each allpass */ +typedef struct +{ + EAS_PCM m_zLpf; // actual state variable, not a length + + EAS_I16 m_nLpfFwd; // lpf forward gain + + EAS_I16 m_nLpfFbk; // lpf feedback gain + + EAS_U16 m_zDelay[REVERB_MAX_NUM_REFLECTIONS]; // delay offset for ap out + + EAS_I16 m_nGain[REVERB_MAX_NUM_REFLECTIONS]; // gain for ap + +} S_EARLY_REFLECTION_OBJECT; + +//demo +typedef struct +{ + EAS_I16 m_nLpfFbk; + EAS_I16 m_nLpfFwd; + + EAS_I16 m_nEarly; + EAS_I16 m_nWet; + EAS_I16 m_nDry; + + EAS_I16 m_nEarlyL_LpfFbk; + EAS_I16 m_nEarlyL_LpfFwd; + + EAS_I16 m_nEarlyL_Delay0; //8 + EAS_I16 m_nEarlyL_Gain0; + EAS_I16 m_nEarlyL_Delay1; + EAS_I16 m_nEarlyL_Gain1; + EAS_I16 m_nEarlyL_Delay2; + EAS_I16 m_nEarlyL_Gain2; + EAS_I16 m_nEarlyL_Delay3; + EAS_I16 m_nEarlyL_Gain3; + EAS_I16 m_nEarlyL_Delay4; + EAS_I16 m_nEarlyL_Gain4; + + EAS_I16 m_nEarlyR_Delay0; //18 + EAS_I16 m_nEarlyR_Gain0; + EAS_I16 m_nEarlyR_Delay1; + EAS_I16 m_nEarlyR_Gain1; + EAS_I16 m_nEarlyR_Delay2; + EAS_I16 m_nEarlyR_Gain2; + EAS_I16 m_nEarlyR_Delay3; + EAS_I16 m_nEarlyR_Gain3; + EAS_I16 m_nEarlyR_Delay4; + EAS_I16 m_nEarlyR_Gain4; + + EAS_U16 m_nMaxExcursion; //28 + EAS_I16 m_nXfadeInterval; + + EAS_I16 m_nAp0_ApGain; //30 + EAS_I16 m_nAp0_ApOut; + EAS_I16 m_nAp1_ApGain; + EAS_I16 m_nAp1_ApOut; + + EAS_I16 m_rfu4; + EAS_I16 m_rfu5; + EAS_I16 m_rfu6; + EAS_I16 m_rfu7; + EAS_I16 m_rfu8; + EAS_I16 m_rfu9; + EAS_I16 m_rfu10; //43 + +} S_REVERB_PRESET; + +typedef struct +{ + S_REVERB_PRESET m_sPreset[REVERB_MAX_ROOM_TYPE]; //array of presets + +} S_REVERB_PRESET_BANK; + +/* parameters for each reverb */ +typedef struct +{ + /* controls entire reverb playback volume */ + /* to conserve memory, use the MSB and ignore the LSB */ + EAS_U8 m_nMasterVolume; + + /* update counter keeps track of when synth params need updating */ + /* only needs to be as large as REVERB_UPDATE_PERIOD_IN_SAMPLES */ + EAS_I16 m_nUpdateCounter; + + EAS_U16 m_nMinSamplesToAdd; /* ComputeReverb() generates this many samples */ + + EAS_U8 m_nFlags; /* misc flags/bit fields */ + + EAS_PCM *m_pOutputBuffer; + EAS_PCM *m_pInputBuffer; + + EAS_U16 m_nNumSamplesInOutputBuffer; + EAS_U16 m_nNumSamplesInInputBuffer; + + EAS_U16 m_nNumInputSamplesRead; // if m_nNumInputSamplesRead >= NumSamplesInInputBuffer + // then get a new input buffer + EAS_PCM *m_pNextInputSample; + + EAS_U16 m_nBaseIndex; // base index for circular buffer + + // reverb delay line offsets, allpass parameters, etc: + + EAS_PCM m_nRevOutFbkR; // combine feedback reverb right out with dry left in + + S_ALLPASS_OBJECT m_sAp0; // allpass 0 (left channel) + + EAS_U16 m_zD0In; // delay offset for delay line D0 in + + EAS_PCM m_nRevOutFbkL; // combine feedback reverb left out with dry right in + + S_ALLPASS_OBJECT m_sAp1; // allpass 1 (right channel) + + EAS_U16 m_zD1In; // delay offset for delay line D1 in + + // delay output taps, notice criss cross order + EAS_U16 m_zD0Self; // self feeds forward d0 --> d0 + + EAS_U16 m_zD1Cross; // cross feeds across d1 --> d0 + + EAS_PCM m_zLpf0; // actual state variable, not a length + + EAS_U16 m_zD1Self; // self feeds forward d1 --> d1 + + EAS_U16 m_zD0Cross; // cross feeds across d0 --> d1 + + EAS_PCM m_zLpf1; // actual state variable, not a length + + EAS_I16 m_nSin; // gain for self taps + + EAS_I16 m_nCos; // gain for cross taps + + EAS_I16 m_nSinIncrement; // increment for gain + + EAS_I16 m_nCosIncrement; // increment for gain + + EAS_I16 m_nLpfFwd; // lpf forward gain (includes scaling for mixer) + + EAS_I16 m_nLpfFbk; // lpf feedback gain + + EAS_U16 m_nXfadeInterval; // update/xfade after this many samples + + EAS_U16 m_nXfadeCounter; // keep track of when to xfade + + EAS_I16 m_nPhase; // -1 <= m_nPhase < 1 + // but during sin,cos calculations + // use m_nPhase/2 + + EAS_I16 m_nPhaseIncrement; // add this to m_nPhase each frame + + EAS_I16 m_nNoise; // random noise sample + + EAS_U16 m_nMaxExcursion; // the taps can excurse +/- this amount + + EAS_BOOL m_bUseNoise; // if EAS_TRUE, use noise as input signal + + EAS_BOOL m_bBypass; // if EAS_TRUE, then bypass reverb and copy input to output + + EAS_I16 m_nCurrentRoom; // preset number for current room + + EAS_I16 m_nNextRoom; // preset number for next room + + EAS_I16 m_nWet; // gain for wet (processed) signal + + EAS_I16 m_nDry; // gain for dry (unprocessed) signal + + EAS_I16 m_nEarly; // gain for early (widen) signal + + S_EARLY_REFLECTION_OBJECT m_sEarlyL; // left channel early reflections + S_EARLY_REFLECTION_OBJECT m_sEarlyR; // right channel early reflections + + EAS_PCM m_nDelayLine[REVERB_BUFFER_SIZE_IN_SAMPLES]; // one large delay line for all reverb elements + + S_REVERB_PRESET pPreset; + + S_REVERB_PRESET_BANK m_sPreset; + + //EAS_I8 preset; + +} S_REVERB_OBJECT; + + +/*------------------------------------ + * prototypes + *------------------------------------ +*/ + +/*---------------------------------------------------------------------------- + * ReverbUpdateXfade + *---------------------------------------------------------------------------- + * Purpose: + * Update the xfade parameters as required + * + * Inputs: + * nNumSamplesToAdd - number of samples to write to buffer + * + * Outputs: + * + * + * Side Effects: + * - xfade parameters will be changed + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT ReverbUpdateXfade(S_REVERB_OBJECT* pReverbData, EAS_INT nNumSamplesToAdd); + +/*---------------------------------------------------------------------------- + * ReverbCalculateNoise + *---------------------------------------------------------------------------- + * Purpose: + * Calculate a noise sample and limit its value + * + * Inputs: + * nMaxExcursion - noise value is limited to this value + * pnNoise - return new noise sample in this (not limited) + * + * Outputs: + * new limited noise value + * + * Side Effects: + * - *pnNoise noise value is updated + * + *---------------------------------------------------------------------------- +*/ +EAS_U16 ReverbCalculateNoise(EAS_U16 nMaxExcursion, EAS_I16 *pnNoise); + +/*---------------------------------------------------------------------------- + * ReverbCalculateSinCos + *---------------------------------------------------------------------------- + * Purpose: + * Calculate a new sin and cosine value based on the given phase + * + * Inputs: + * nPhase - phase angle + * pnSin - input old value, output new value + * pnCos - input old value, output new value + * + * Outputs: + * + * Side Effects: + * - *pnSin, *pnCos are updated + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT ReverbCalculateSinCos(EAS_I16 nPhase, EAS_I16 *pnSin, EAS_I16 *pnCos); + +/*---------------------------------------------------------------------------- + * Reverb + *---------------------------------------------------------------------------- + * Purpose: + * apply reverb to the given signal + * + * Inputs: + * nNu + * pnSin - input old value, output new value + * pnCos - input old value, output new value + * + * Outputs: + * number of samples actually reverberated + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT Reverb(S_REVERB_OBJECT* pReverbData, EAS_INT nNumSamplesToAdd, EAS_PCM *pOutputBuffer, EAS_PCM *pInputBuffer); + +/*---------------------------------------------------------------------------- + * ReverbReadInPresets() + *---------------------------------------------------------------------------- + * Purpose: sets global reverb preset bank to defaults + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT ReverbReadInPresets(S_REVERB_OBJECT* pReverbData); + + +/*---------------------------------------------------------------------------- + * ReverbUpdateRoom + *---------------------------------------------------------------------------- + * Purpose: + * Update the room's preset parameters as required + * + * Inputs: + * + * Outputs: + * + * + * Side Effects: + * - reverb paramters (fbk, fwd, etc) will be changed + * - m_nCurrentRoom := m_nNextRoom + *---------------------------------------------------------------------------- +*/ +EAS_RESULT ReverbUpdateRoom(S_REVERB_OBJECT* pReverbData); + +#endif /* #ifndef _EAS_REVERBDATA_H */ + + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_rtttl.c b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_rtttl.c new file mode 100755 index 0000000..d8253fb --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_rtttl.c @@ -0,0 +1,1197 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_rtttl.c + * + * Contents and purpose: + * RTTTL parser + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 795 $ + * $Date: 2007-08-01 00:14:45 -0700 (Wed, 01 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_data.h" +#include "eas_miditypes.h" +#include "eas_parser.h" +#include "eas_report.h" +#include "eas_host.h" +#include "eas_midi.h" +#include "eas_config.h" +#include "eas_vm_protos.h" +#include "eas_rtttldata.h" +#include "eas_ctype.h" + +/* increase gain for mono ringtones */ +#define RTTTL_GAIN_OFFSET 8 + +/* maximum title length including colon separator */ +#define RTTTL_MAX_TITLE_LEN 32 +#define RTTTL_INFINITE_LOOP 15 + +/* length of 32nd note in 1/256ths of a msec for 63 BPM tempo */ +#define DEFAULT_TICK_CONV 30476 +#define TICK_CONVERT 1920000 + +/* default channel and program for RTTTL playback */ +#define RTTTL_CHANNEL 0 +#define RTTTL_PROGRAM 80 +#define RTTTL_VELOCITY 127 + +/* note used for rest */ +#define RTTTL_REST 1 + +/* multiplier for fixed point triplet conversion */ +#define TRIPLET_MULTIPLIER 683 +#define TRIPLET_SHIFT 10 + +/* local prototypes */ +static EAS_RESULT RTTTL_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset); +static EAS_RESULT RTTTL_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT RTTTL_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime); +static EAS_RESULT RTTTL_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode); +static EAS_RESULT RTTTL_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_STATE *pState); +static EAS_RESULT RTTTL_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT RTTTL_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT RTTTL_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT RTTTL_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT RTTTL_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value); +static EAS_RESULT RTTTL_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue); +static EAS_RESULT RTTTL_GetStyle (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData); +static EAS_RESULT RTTTL_GetDuration (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData, EAS_I8 *pDuration); +static EAS_RESULT RTTTL_GetOctave (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData, EAS_U8 *pOctave); +static EAS_RESULT RTTTL_GetTempo (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData); +static EAS_RESULT RTTTL_GetNumber (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData, EAS_I32 *pValue); +static EAS_RESULT RTTTL_ParseHeader (S_EAS_DATA *pEASData, S_RTTTL_DATA* pData, EAS_BOOL metaData); +static EAS_RESULT RTTTL_GetNextChar (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData, EAS_I8 *pValue); +static EAS_RESULT RTTTL_PeekNextChar (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData, EAS_I8 *pValue); + +/* inline functions */ +EAS_INLINE void RTTTL_PutBackChar (S_RTTTL_DATA *pData, EAS_I8 value) { pData->dataByte = value; } + + +/* lookup table for note values */ +static const EAS_U8 noteTable[] = { 21, 23, 12, 14, 16, 17, 19, 23 }; + +/*---------------------------------------------------------------------------- + * + * EAS_RTTTL_Parser + * + * This structure contains the functional interface for the iMelody parser + *---------------------------------------------------------------------------- +*/ +const S_FILE_PARSER_INTERFACE EAS_RTTTL_Parser = +{ + RTTTL_CheckFileType, + RTTTL_Prepare, + RTTTL_Time, + RTTTL_Event, + RTTTL_State, + RTTTL_Close, + RTTTL_Reset, + RTTTL_Pause, + RTTTL_Resume, + NULL, + RTTTL_SetData, + RTTTL_GetData, + NULL +}; + +/*---------------------------------------------------------------------------- + * RTTTL_CheckFileType() + *---------------------------------------------------------------------------- + * Purpose: + * Check the file type to see if we can parse it + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset) +{ + S_RTTTL_DATA data; + S_RTTTL_DATA *pData; + + /* see if we can parse the header */ + data.fileHandle = fileHandle; + data.fileOffset = offset; + *ppHandle= NULL; + if (RTTTL_ParseHeader (pEASData, &data, EAS_FALSE) == EAS_SUCCESS) + { + + /* check for static memory allocation */ + if (pEASData->staticMemoryModel) + pData = EAS_CMEnumData(EAS_CM_RTTTL_DATA); + else + pData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_RTTTL_DATA)); + if (!pData) + return EAS_ERROR_MALLOC_FAILED; + EAS_HWMemSet(pData, 0, sizeof(S_RTTTL_DATA)); + + /* return a pointer to the instance data */ + pData->fileHandle = fileHandle; + pData->fileOffset = offset; + pData->state = EAS_STATE_OPEN; + *ppHandle = pData; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_Prepare() + *---------------------------------------------------------------------------- + * Purpose: + * Prepare to parse the file. Allocates instance data (or uses static allocation for + * static memory model). + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_RTTTL_DATA* pData; + EAS_RESULT result; + + /* check for valid state */ + pData = (S_RTTTL_DATA*) pInstData; + if (pData->state != EAS_STATE_OPEN) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + /* instantiate a synthesizer */ + if ((result = VMInitMIDI(pEASData, &pData->pSynth)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitMIDI returned %d\n", result); */ } + return result; + } + + pData->state = EAS_STATE_ERROR; + if ((result = RTTTL_ParseHeader (pEASData, pData, (EAS_BOOL) (pData->metadata.callback != NULL))) != EAS_SUCCESS) + { + /* if using dynamic memory, free it */ + if (!pEASData->staticMemoryModel) + EAS_HWFree(pEASData->hwInstData, pData); + return result; + } + + pData->state = EAS_STATE_READY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_Time() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the time of the next event in msecs + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * pTime - pointer to variable to hold time of next event (in msecs) + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +static EAS_RESULT RTTTL_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime) +{ + S_RTTTL_DATA *pData; + + pData = (S_RTTTL_DATA*) pInstData; + + /* return time in milliseconds */ + /*lint -e{704} use shift instead of division */ + *pTime = pData->time >> 8; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_Event() + *---------------------------------------------------------------------------- + * Purpose: + * Parse the next event in the file + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode) +{ + S_RTTTL_DATA* pData; + EAS_RESULT result; + EAS_I32 ticks; + EAS_I32 temp; + EAS_I8 c; + EAS_U8 note; + EAS_U8 octave; + + pData = (S_RTTTL_DATA*) pInstData; + if (pData->state >= EAS_STATE_OPEN) + return EAS_SUCCESS; + + /* initialize MIDI channel when the track starts playing */ + if (pData->time == 0) + { + /* set program to square lead */ + VMProgramChange(pEASData->pVoiceMgr, pData->pSynth, RTTTL_CHANNEL, RTTTL_PROGRAM); + + /* set channel volume to max */ + VMControlChange(pEASData->pVoiceMgr, pData->pSynth, RTTTL_CHANNEL, 7, 127); + } + + /* check for end of note */ + if (pData->note) + { + /* stop the note */ + VMStopNote(pEASData->pVoiceMgr, pData->pSynth, RTTTL_CHANNEL, pData->note, 0); + pData->note = 0; + + /* check for rest between notes */ + if (pData->restTicks) + { + pData->time += pData->restTicks; + pData->restTicks = 0; + return EAS_SUCCESS; + } + } + + /* parse the next event */ + octave = pData->octave; + note = 0; + ticks = pData->duration * pData->tick; + for (;;) + { + + /* get next character */ + if ((result = RTTTL_GetNextChar(pEASData->hwInstData, pData, &c)) != EAS_SUCCESS) + { + if (result != EAS_EOF) + return result; + + /* end of file, if no notes to process, check for looping */ + if (!note) + { + /* if no loop set state to stopping */ + if (pData->repeatCount == 0) + { + pData->state = EAS_STATE_STOPPING; + VMReleaseAllVoices(pEASData->pVoiceMgr, pData->pSynth); + return EAS_SUCCESS; + } + + /* decrement loop count */ + if (pData->repeatCount != RTTTL_INFINITE_LOOP) + pData->repeatCount--; + + /* if locating, ignore infinite loops */ + else if (parserMode != eParserModePlay) + { + pData->state = EAS_STATE_STOPPING; + VMReleaseAllVoices(pEASData->pVoiceMgr, pData->pSynth); + return EAS_SUCCESS; + } + + /* loop back to start of notes */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pData->fileHandle, pData->repeatOffset)) != EAS_SUCCESS) + return result; + continue; + } + + /* still have a note to process */ + else + c = ','; + } + + /* bpm */ + if (c == 'b') + { + /* peek at next character */ + if ((result = RTTTL_PeekNextChar(pEASData->hwInstData, pData, &c)) != EAS_SUCCESS) + return result; + + /* if a number, must be octave or tempo */ + if (IsDigit(c)) + { + if ((result = RTTTL_GetNumber(pEASData->hwInstData, pData, &temp)) != EAS_SUCCESS) + return result; + + /* check for octave first */ + if ((temp >= 4) && (temp <= 7)) + { + octave = (EAS_U8) temp; + } + + /* check for tempo */ + else if ((temp >= 25) && (temp <= 900)) + { + pData->tick = TICK_CONVERT / (EAS_U32) temp; + } + + /* don't know what it was */ + else + return EAS_ERROR_FILE_FORMAT; + } + + /* must be a note */ + else + { + note = noteTable[1]; + } + } + + /* octave */ + else if (c == 'o') + { + if ((result = RTTTL_GetOctave(pEASData->hwInstData, pData, &pData->octave)) != EAS_SUCCESS) + return result; + } + + /* style */ + else if (c == 's') + { + if ((result = RTTTL_GetStyle(pEASData->hwInstData, pData)) != EAS_SUCCESS) + return result; + } + + /* duration or octave */ + else if (IsDigit(c)) + { + RTTTL_PutBackChar(pData, c); + + /* duration comes before note */ + if (!note) + { + if ((result = RTTTL_GetDuration(pEASData->hwInstData, pData, &c)) != EAS_SUCCESS) + return result; + ticks = c * pData->tick; + } + + /* octave comes after note */ + else + { + if ((result = RTTTL_GetOctave(pEASData->hwInstData, pData, &octave)) != EAS_SUCCESS) + return result; + } + } + + /* note or rest */ + else if ((c >= 'a') && (c <= 'h')) + { + note = noteTable[c - 'a']; + } + + else if (c == 'p') + { + note = RTTTL_REST; + } + + /* dotted note */ + else if (c == '.') + { + /*lint -e{704} shift for performance */ + ticks += ticks >> 1; + } + + /* accidental */ + else if (c == '#') + { + if (note) + note++; + } + + /* end of event */ + else if ((c == ',') && note) + { + + /* handle note events */ + if (note != RTTTL_REST) + { + + /* save note and start it */ + pData->note = note + octave; + if (parserMode == eParserModePlay) + VMStartNote(pEASData->pVoiceMgr, pData->pSynth, RTTTL_CHANNEL, pData->note, RTTTL_VELOCITY); + + /* determine note length */ + switch (pData->style) + { + /* natural */ + case 'n': + /*lint -e{704} shift for performance */ + pData->restTicks = ticks >> 4; + break; + /* continuous */ + + case 'c': + pData->restTicks = 0; + break; + + /* staccato */ + case 's': + /*lint -e{704} shift for performance */ + pData->restTicks = ticks >> 1; + break; + + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "RTTTL_Event: Unexpected style type %c\n", pData->style); */ } + break; + } + + /* next event is at end of this note */ + pData->time += ticks - pData->restTicks; + } + + /* rest */ + else + pData->time += ticks; + + /* event found, return to caller */ + break; + } + } + + pData->state = EAS_STATE_PLAY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_State() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current state of the stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * pState - pointer to variable to store state + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +static EAS_RESULT RTTTL_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pState) +{ + S_RTTTL_DATA* pData; + + /* establish pointer to instance data */ + pData = (S_RTTTL_DATA*) pInstData; + + /* if stopping, check to see if synth voices are active */ + if (pData->state == EAS_STATE_STOPPING) + { + if (VMActiveVoices(pData->pSynth) == 0) + pData->state = EAS_STATE_STOPPED; + } + + if (pData->state == EAS_STATE_PAUSING) + { + if (VMActiveVoices(pData->pSynth) == 0) + pData->state = EAS_STATE_PAUSED; + } + + /* return current state */ + *pState = pData->state; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_Close() + *---------------------------------------------------------------------------- + * Purpose: + * Close the file and clean up + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_RTTTL_DATA* pData; + EAS_RESULT result; + + pData = (S_RTTTL_DATA*) pInstData; + + /* close the file */ + if ((result = EAS_HWCloseFile(pEASData->hwInstData, pData->fileHandle)) != EAS_SUCCESS) + return result; + + /* free the synth */ + if (pData->pSynth != NULL) + VMMIDIShutdown(pEASData, pData->pSynth); + + /* if using dynamic memory, free it */ + if (!pEASData->staticMemoryModel) + EAS_HWFree(pEASData->hwInstData, pData); + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_Reset() + *---------------------------------------------------------------------------- + * Purpose: + * Reset the sequencer. Used for locating backwards in the file. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_RTTTL_DATA* pData; + EAS_RESULT result; + + pData = (S_RTTTL_DATA*) pInstData; + + /* reset the synth */ + VMReset(pEASData->pVoiceMgr, pData->pSynth, EAS_TRUE); + + /* reset time to zero */ + pData->time = 0; + pData->note = 0; + + /* reset file position and re-parse header */ + pData->state = EAS_STATE_ERROR; + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pData->fileHandle, pData->fileOffset)) != EAS_SUCCESS) + return result; + if ((result = RTTTL_ParseHeader (pEASData, pData, EAS_TRUE)) != EAS_SUCCESS) + return result; + + pData->state = EAS_STATE_READY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_Pause() + *---------------------------------------------------------------------------- + * Purpose: + * Pauses the sequencer. Mutes all voices and sets state to pause. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_RTTTL_DATA *pData; + + /* can't pause a stopped stream */ + pData = (S_RTTTL_DATA*) pInstData; + if (pData->state == EAS_STATE_STOPPED) + return EAS_ERROR_ALREADY_STOPPED; + + /* mute the synthesizer */ + VMMuteAllVoices(pEASData->pVoiceMgr, pData->pSynth); + pData->state = EAS_STATE_PAUSING; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_Resume() + *---------------------------------------------------------------------------- + * Purpose: + * Resume playing after a pause, sets state back to playing. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +static EAS_RESULT RTTTL_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_RTTTL_DATA *pData; + + /* can't resume a stopped stream */ + pData = (S_RTTTL_DATA*) pInstData; + if (pData->state == EAS_STATE_STOPPED) + return EAS_ERROR_ALREADY_STOPPED; + + /* nothing to do but resume playback */ + pData->state = EAS_STATE_PLAY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_SetData() + *---------------------------------------------------------------------------- + * Purpose: + * Return file type + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +static EAS_RESULT RTTTL_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value) +{ + S_RTTTL_DATA *pData; + + pData = (S_RTTTL_DATA *) pInstData; + switch (param) + { + + /* set metadata callback */ + case PARSER_DATA_METADATA_CB: + EAS_HWMemCpy(&pData->metadata, (void*) value, sizeof(S_METADATA_CB)); + break; + + default: + return EAS_ERROR_INVALID_PARAMETER; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_GetData() + *---------------------------------------------------------------------------- + * Purpose: + * Return file type + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +static EAS_RESULT RTTTL_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue) +{ + S_RTTTL_DATA *pData; + + pData = (S_RTTTL_DATA *) pInstData; + switch (param) + { + /* return file type as RTTTL */ + case PARSER_DATA_FILE_TYPE: + *pValue = EAS_FILE_RTTTL; + break; + +#if 0 + /* set transposition */ + case PARSER_DATA_TRANSPOSITION: + *pValue = pData->transposition; + break; +#endif + + case PARSER_DATA_SYNTH_HANDLE: + *pValue = (EAS_I32) pData->pSynth; + break; + + case PARSER_DATA_GAIN_OFFSET: + *pValue = RTTTL_GAIN_OFFSET; + break; + + default: + return EAS_ERROR_INVALID_PARAMETER; + } + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_GetStyle() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_GetStyle (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData) +{ + EAS_RESULT result; + EAS_I8 style; + + /* get style */ + if ((result = RTTTL_GetNextChar(hwInstData, pData, &style)) != EAS_SUCCESS) + return result; + + if ((style != 's') && (style != 'n') && (style != 'c')) + return EAS_ERROR_FILE_FORMAT; + + pData->style = style; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_GetDuration() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_GetDuration (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData, EAS_I8 *pDuration) +{ + EAS_RESULT result; + EAS_I32 duration; + EAS_I8 temp; + + /* get the duration */ + if ((result = RTTTL_GetNumber(hwInstData, pData, &duration)) != EAS_SUCCESS) + return result; + + if ((duration != 1) && (duration != 2) && (duration != 4) && (duration != 8) && (duration != 16) && (duration != 32)) + return EAS_ERROR_FILE_FORMAT; + + temp = 64; + while (duration) + { + /*lint -e{704} shift for performance */ + duration = duration >> 1; + /*lint -e{702} use shift for performance */ + temp = temp >> 1; + } + + *pDuration = temp; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_GetOctave() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_GetOctave (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData, EAS_U8 *pOctave) +{ + EAS_RESULT result; + EAS_I32 octave; + + /* get the tempo */ + if ((result = RTTTL_GetNumber(hwInstData, pData, &octave)) != EAS_SUCCESS) + return result; + + if ((octave < 4) || (octave > 7)) + return EAS_ERROR_FILE_FORMAT; + + *pOctave = (EAS_U8) (octave * 12); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_GetTempo() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_GetTempo (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData) +{ + EAS_RESULT result; + EAS_I32 tempo; + + /* get the tempo */ + if ((result = RTTTL_GetNumber(hwInstData, pData, &tempo)) != EAS_SUCCESS) + return result; + + if ((tempo < 25) || (tempo > 900)) + return EAS_ERROR_FILE_FORMAT; + + pData->tick = TICK_CONVERT / (EAS_U32) tempo; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_GetNumber() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_GetNumber (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData, EAS_I32 *pValue) +{ + EAS_RESULT result; + EAS_INT temp; + EAS_I8 c; + + *pValue = -1; + temp = 0; + for (;;) + { + if ((result = RTTTL_PeekNextChar(hwInstData, pData, &c)) != EAS_SUCCESS) + { + if ((result == EAS_EOF) && (*pValue != -1)) + return EAS_SUCCESS; + return result; + } + + if (IsDigit(c)) + { + pData->dataByte = 0; + temp = temp * 10 + c - '0'; + *pValue = temp; + } + else + return EAS_SUCCESS; + } +} + +/*---------------------------------------------------------------------------- + * RTTTL_ParseHeader() + *---------------------------------------------------------------------------- + * Purpose: + * Prepare to parse the file. Allocates instance data (or uses static allocation for + * static memory model). + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_ParseHeader (S_EAS_DATA *pEASData, S_RTTTL_DATA* pData, EAS_BOOL metaData) +{ + EAS_RESULT result; + EAS_I32 i; + EAS_I8 temp; + EAS_I8 control; + + /* initialize some defaults */ + pData->time = 0; + pData->tick = DEFAULT_TICK_CONV; + pData->note = 0; + pData->duration = 4; + pData ->restTicks = 0; + pData->octave = 60; + pData->repeatOffset = -1; + pData->repeatCount = 0; + pData->style = 'n'; + pData->dataByte = 0; + + metaData = metaData && (pData->metadata.buffer != NULL) && (pData->metadata.callback != NULL); + + /* seek to start of data */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pData->fileHandle, pData->fileOffset)) != EAS_SUCCESS) + return result; + + /* zero the metadata buffer */ + if (metaData) + EAS_HWMemSet(pData->metadata.buffer, 0, pData->metadata.bufferSize); + + /* read the title */ + for (i = 0; i < RTTTL_MAX_TITLE_LEN; i++) + { + if ((result = EAS_HWGetByte(pEASData->hwInstData, pData->fileHandle, &temp)) != EAS_SUCCESS) + return result; + + if (temp == ':') + break; + + /* pass along metadata */ + if (metaData) + { + if (i < (pData->metadata.bufferSize- 1)) + pData->metadata.buffer[i] = (char) temp; + } + } + + /* check for error in title */ + if (i == RTTTL_MAX_TITLE_LEN) + return EAS_ERROR_FILE_FORMAT; + + /* pass along metadata */ + if (metaData) + (*pData->metadata.callback)(EAS_METADATA_TITLE, pData->metadata.buffer, pData->metadata.pUserData); + + /* control fields */ + for (;;) + { + + /* get control type */ + if ((result = RTTTL_GetNextChar(pEASData->hwInstData, pData, &control)) != EAS_SUCCESS) + return result; + + /* next char should be equal sign */ + if ((result = RTTTL_GetNextChar(pEASData->hwInstData, pData, &temp)) != EAS_SUCCESS) + return result; + if (temp != '=') + return EAS_ERROR_FILE_FORMAT; + + /* get the control value */ + switch (control) + { + + /* bpm */ + case 'b': + if ((result = RTTTL_GetTempo(pEASData->hwInstData, pData)) != EAS_SUCCESS) + return result; + break; + + /* duration */ + case 'd': + if ((result = RTTTL_GetDuration(pEASData->hwInstData, pData, &temp)) != EAS_SUCCESS) + return result; + pData->duration = temp; + break; + + /* loop */ + case 'l': + if ((result = RTTTL_GetNumber(pEASData->hwInstData, pData, &i)) != EAS_SUCCESS) + return result; + if ((i < 0) || (i > 15)) + return EAS_ERROR_FILE_FORMAT; + pData->repeatCount = (EAS_U8) i; + break; + + /* octave */ + case 'o': + if ((result = RTTTL_GetOctave(pEASData->hwInstData, pData, &pData->octave)) != EAS_SUCCESS) + return result; + break; + + /* get style */ + case 's': + if ((result = RTTTL_GetStyle(pEASData->hwInstData, pData)) != EAS_SUCCESS) + return result; + break; + + /* unrecognized control */ + default: + return EAS_ERROR_FILE_FORMAT; + } + + /* next character should be comma or colon */ + if ((result = RTTTL_GetNextChar(pEASData->hwInstData, pData, &temp)) != EAS_SUCCESS) + return result; + + /* check for end of control field */ + if (temp == ':') + break; + + /* must be a comma */ + if (temp != ',') + return EAS_ERROR_FILE_FORMAT; + } + + /* should be at the start of the music block */ + if ((result = EAS_HWFilePos(pEASData->hwInstData, pData->fileHandle, &pData->repeatOffset)) != EAS_SUCCESS) + return result; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * RTTTL_GetNextChar() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_GetNextChar (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData, EAS_I8 *pValue) +{ + EAS_RESULT result; + EAS_I8 temp; + + *pValue = 0; + for(;;) + { + + /* check for character that has been put back */ + if (pData->dataByte) + { + temp = pData->dataByte; + pData->dataByte = 0; + } + else + { + if ((result = EAS_HWGetByte(hwInstData, pData->fileHandle, &temp)) != EAS_SUCCESS) + return result; + } + + /* ignore white space */ + if (!IsSpace(temp)) + { + *pValue = ToLower(temp); + return EAS_SUCCESS; + } + } +} + +/*---------------------------------------------------------------------------- + * RTTTL_PeekNextChar() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT RTTTL_PeekNextChar (EAS_HW_DATA_HANDLE hwInstData, S_RTTTL_DATA *pData, EAS_I8 *pValue) +{ + EAS_RESULT result; + EAS_I8 temp; + + *pValue = 0; + for(;;) + { + + /* read a character from the file, if necessary */ + if (!pData->dataByte) + { + if ((result = EAS_HWGetByte(hwInstData, pData->fileHandle, &pData->dataByte)) != EAS_SUCCESS) + return result; + + } + temp = pData->dataByte; + + /* ignore white space */ + if (!IsSpace(temp)) + { + *pValue = ToLower(temp); + return EAS_SUCCESS; + } + pData->dataByte = 0; + } +} + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_rtttldata.c b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_rtttldata.c new file mode 100755 index 0000000..708a1d9 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_rtttldata.c @@ -0,0 +1,41 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_rtttldata.c + * + * Contents and purpose: + * RTTTL File Parser data module for static memory models + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 547 $ + * $Date: 2007-01-31 16:30:17 -0800 (Wed, 31 Jan 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_types.h" +#include "eas_rtttldata.h" + +/*---------------------------------------------------------------------------- + * + * eas_RTTTLData + * + * Static memory allocation for RTTTL parser + *---------------------------------------------------------------------------- +*/ +S_RTTTL_DATA eas_RTTTLData; + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_rtttldata.h b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_rtttldata.h new file mode 100755 index 0000000..31dd522 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_rtttldata.h @@ -0,0 +1,70 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_rtttldata.h + * + * Contents and purpose: + * SMF File Parser + * + * This file contains data declarations for the RTTTL parser. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef EAS_RTTTLDATA_H +#define EAS_RTTTLDATA_H + +#include "eas_data.h" + + +/* maximum line size as specified in iMelody V1.2 spec */ +#define MAX_LINE_SIZE 75 + +/*---------------------------------------------------------------------------- + * + * S_RTTTL_DATA + * + * This structure contains the state data for the iMelody parser + *---------------------------------------------------------------------------- +*/ + +typedef struct +{ + EAS_FILE_HANDLE fileHandle; /* file handle */ + S_SYNTH *pSynth; /* synthesizer handle */ + S_METADATA_CB metadata; /* metadata callback */ + EAS_I32 fileOffset; /* offset to start of data */ + EAS_I32 time; /* current time in 256ths of a msec */ + EAS_I32 tick; /* length of 32nd note in 256th of a msec */ + EAS_I32 restTicks; /* ticks to rest after current note */ + EAS_I32 repeatOffset; /* file offset to start of repeat section */ + EAS_U8 repeatCount; /* repeat counter */ + EAS_I8 dataByte; /* storage for characters that are "put back" */ + EAS_U8 state; /* current state EAS_STATE_XXXX */ + EAS_I8 style; /* from STYLE */ + EAS_U8 note; /* MIDI note number */ + EAS_U8 octave; /* decault octave prefix */ + EAS_I8 duration; /* default note duration */ +} S_RTTTL_DATA; + +#endif + + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_smf.c b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_smf.c new file mode 100755 index 0000000..9e096b6 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_smf.c @@ -0,0 +1,1207 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_smf.c + * + * Contents and purpose: + * SMF Type 0 and 1 File Parser + * + * For SMF timebase analysis, see "MIDI Sequencer Analysis.xls". + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 803 $ + * $Date: 2007-08-01 09:57:00 -0700 (Wed, 01 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_data.h" +#include "eas_miditypes.h" +#include "eas_parser.h" +#include "eas_report.h" +#include "eas_host.h" +#include "eas_midi.h" +#include "eas_config.h" +#include "eas_vm_protos.h" +#include "eas_smfdata.h" +#include "eas_smf.h" + +#ifdef JET_INTERFACE +#include "jet_data.h" +#endif + +//3 dls: The timebase for this module is adequate to keep MIDI and +//3 digital audio synchronized for only a few minutes. It should be +//3 sufficient for most mobile applications. If better accuracy is +//3 required, more fractional bits should be added to the timebase. + +static const EAS_U8 smfHeader[] = { 'M', 'T', 'h', 'd' }; + +/* local prototypes */ +static EAS_RESULT SMF_GetVarLenData (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle, EAS_U32 *pData); +static EAS_RESULT SMF_ParseMetaEvent (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream); +static EAS_RESULT SMF_ParseSysEx (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream, EAS_U8 f0, EAS_INT parserMode); +static EAS_RESULT SMF_ParseEvent (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream, EAS_INT parserMode); +static EAS_RESULT SMF_GetDeltaTime (EAS_HW_DATA_HANDLE hwInstData, S_SMF_STREAM *pSMFStream); +static void SMF_UpdateTime (S_SMF_DATA *pSMFData, EAS_U32 ticks); + + +/*---------------------------------------------------------------------------- + * + * SMF_Parser + * + * This structure contains the functional interface for the SMF parser + *---------------------------------------------------------------------------- +*/ +const S_FILE_PARSER_INTERFACE EAS_SMF_Parser = +{ + SMF_CheckFileType, + SMF_Prepare, + SMF_Time, + SMF_Event, + SMF_State, + SMF_Close, + SMF_Reset, + SMF_Pause, + SMF_Resume, + NULL, + SMF_SetData, + SMF_GetData, + NULL +}; + +/*---------------------------------------------------------------------------- + * SMF_CheckFileType() + *---------------------------------------------------------------------------- + * Purpose: + * Check the file type to see if we can parse it + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT SMF_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset) +{ + S_SMF_DATA* pSMFData; + EAS_RESULT result; + + /* seek to starting offset - usually 0 */ + *ppHandle = NULL; + if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, offset)) != EAS_SUCCESS) + return result; + + /* search through file for header - slow method */ + if (pEASData->searchHeaderFlag) + { + result = EAS_SearchFile(pEASData, fileHandle, smfHeader, sizeof(smfHeader), &offset); + if (result != EAS_SUCCESS) + return (result == EAS_EOF) ? EAS_SUCCESS : result; + } + + /* read the first 4 bytes of the file - quick method */ + else { + EAS_U8 header[4]; + EAS_I32 count; + if ((result = EAS_HWReadFile(pEASData->hwInstData, fileHandle, header, sizeof(header), &count)) != EAS_SUCCESS) + return result; + + /* check for 'MTrk' - return if no match */ + if ((header[0] != 'M') || (header[1] != 'T') || (header[2] != 'h') || (header[3] != 'd')) + return EAS_SUCCESS; + } + + /* check for static memory allocation */ + if (pEASData->staticMemoryModel) + pSMFData = EAS_CMEnumData(EAS_CM_SMF_DATA); + else + { + pSMFData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_SMF_DATA)); + EAS_HWMemSet((void *)pSMFData,0, sizeof(S_SMF_DATA)); + } + if (!pSMFData) + return EAS_ERROR_MALLOC_FAILED; + + /* initialize some critical data */ + pSMFData->fileHandle = fileHandle; + pSMFData->fileOffset = offset; + pSMFData->pSynth = NULL; + pSMFData->time = 0; + pSMFData->state = EAS_STATE_OPEN; + *ppHandle = pSMFData; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_Prepare() + *---------------------------------------------------------------------------- + * Purpose: + * Prepare to parse the file. Allocates instance data (or uses static allocation for + * static memory model). + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT SMF_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_SMF_DATA* pSMFData; + EAS_RESULT result; + + /* check for valid state */ + pSMFData = (S_SMF_DATA *) pInstData; + if (pSMFData->state != EAS_STATE_OPEN) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + /* instantiate a synthesizer */ + if ((result = VMInitMIDI(pEASData, &pSMFData->pSynth)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitMIDI returned %d\n", result); */ } + return result; + } + + /* parse the file header and setup the individual stream parsers */ + if ((result = SMF_ParseHeader(pEASData->hwInstData, pSMFData)) != EAS_SUCCESS) + return result; + + /* ready to play */ + pSMFData->state = EAS_STATE_READY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_Time() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the time of the next event in msecs + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * pTime - pointer to variable to hold time of next event (in msecs) + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT SMF_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime) +{ + S_SMF_DATA *pSMFData; + + pSMFData = (S_SMF_DATA*) pInstData; + + /* sanity check */ +#ifdef _CHECKED_BUILD + if (pSMFData->state == EAS_STATE_STOPPED) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Can't ask for time on a stopped stream\n"); */ } + } + + if (pSMFData->nextStream == NULL) + { + { /* dpp: EAS_ReportEx( _EAS_SEVERITY_ERROR, "no is NULL\n"); */ } + } +#endif + +#if 0 + /* return time in milliseconds */ + /* if chase mode, lie about time */ + if (pSMFData->flags & SMF_FLAGS_CHASE_MODE) + *pTime = 0; + + else +#endif + + /*lint -e{704} use shift instead of division */ + *pTime = pSMFData->time >> 8; + + *pTime = pSMFData->time >> 8; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_Event() + *---------------------------------------------------------------------------- + * Purpose: + * Parse the next event in the file + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT SMF_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode) +{ + S_SMF_DATA* pSMFData; + EAS_RESULT result; + EAS_I32 i; + EAS_U32 ticks; + EAS_U32 temp; + + /* establish pointer to instance data */ + pSMFData = (S_SMF_DATA*) pInstData; + if (pSMFData->state >= EAS_STATE_OPEN) + return EAS_SUCCESS; + + /* get current ticks */ + ticks = pSMFData->nextStream->ticks; + + /* assume that an error occurred */ + pSMFData->state = EAS_STATE_ERROR; + +#ifdef JET_INTERFACE + /* if JET has track muted, set parser mode to mute */ + if (pSMFData->nextStream->midiStream.jetData & MIDI_FLAGS_JET_MUTE) + parserMode = eParserModeMute; +#endif + + /* parse the next event from all the streams */ + if ((result = SMF_ParseEvent(pEASData, pSMFData, pSMFData->nextStream, parserMode)) != EAS_SUCCESS) + { + /* check for unexpected end-of-file */ + if (result != EAS_EOF) + return result; + + /* indicate end of track for this stream */ + pSMFData->nextStream->ticks = SMF_END_OF_TRACK; + } + + /* get next delta time, unless already at end of track */ + else if (pSMFData->nextStream->ticks != SMF_END_OF_TRACK) + { + if ((result = SMF_GetDeltaTime(pEASData->hwInstData, pSMFData->nextStream)) != EAS_SUCCESS) + { + /* check for unexpected end-of-file */ + if (result != EAS_EOF) + return result; + + /* indicate end of track for this stream */ + pSMFData->nextStream->ticks = SMF_END_OF_TRACK; + } + + /* if zero delta to next event, stay with this stream */ + else if (pSMFData->nextStream->ticks == ticks) + { + pSMFData->state = EAS_STATE_PLAY; + return EAS_SUCCESS; + } + } + + /* find next event in all streams */ + temp = 0x7ffffff; + pSMFData->nextStream = NULL; + for (i = 0; i < pSMFData->numStreams; i++) + { + if (pSMFData->streams[i].ticks < temp) + { + temp = pSMFData->streams[i].ticks; + pSMFData->nextStream = &pSMFData->streams[i]; + } + } + + /* are there any more events to parse? */ + if (pSMFData->nextStream) + { + pSMFData->state = EAS_STATE_PLAY; + + /* update the time of the next event */ + SMF_UpdateTime(pSMFData, pSMFData->nextStream->ticks - ticks); + } + else + { + pSMFData->state = EAS_STATE_STOPPING; + VMReleaseAllVoices(pEASData->pVoiceMgr, pSMFData->pSynth); + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_State() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current state of the stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * pState - pointer to variable to store state + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT SMF_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pState) +{ + S_SMF_DATA* pSMFData; + + /* establish pointer to instance data */ + pSMFData = (S_SMF_DATA*) pInstData; + + /* if stopping, check to see if synth voices are active */ + if (pSMFData->state == EAS_STATE_STOPPING) + { + if (VMActiveVoices(pSMFData->pSynth) == 0) + pSMFData->state = EAS_STATE_STOPPED; + } + + if (pSMFData->state == EAS_STATE_PAUSING) + { + if (VMActiveVoices(pSMFData->pSynth) == 0) + pSMFData->state = EAS_STATE_PAUSED; + } + + /* return current state */ + *pState = pSMFData->state; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_Close() + *---------------------------------------------------------------------------- + * Purpose: + * Close the file and clean up + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT SMF_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_SMF_DATA* pSMFData; + EAS_I32 i; + EAS_RESULT result; + + pSMFData = (S_SMF_DATA*) pInstData; + + /* close all the streams */ + for (i = 0; i < pSMFData->numStreams; i++) + { + if (pSMFData->streams[i].fileHandle != NULL) + { + if ((result = EAS_HWCloseFile(pEASData->hwInstData, pSMFData->streams[i].fileHandle)) != EAS_SUCCESS) + return result; + } + } + if (pSMFData->fileHandle != NULL) + if ((result = EAS_HWCloseFile(pEASData->hwInstData, pSMFData->fileHandle)) != EAS_SUCCESS) + return result; + + /* free the synth */ + if (pSMFData->pSynth != NULL) + VMMIDIShutdown(pEASData, pSMFData->pSynth); + + /* if using dynamic memory, free it */ + if (!pEASData->staticMemoryModel) + { + if (pSMFData->streams) + EAS_HWFree(pEASData->hwInstData, pSMFData->streams); + + /* free the instance data */ + EAS_HWFree(pEASData->hwInstData, pSMFData); + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_Reset() + *---------------------------------------------------------------------------- + * Purpose: + * Reset the sequencer. Used for locating backwards in the file. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT SMF_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_SMF_DATA* pSMFData; + EAS_I32 i; + EAS_RESULT result; + EAS_U32 ticks; + + pSMFData = (S_SMF_DATA*) pInstData; + + /* reset time to zero */ + pSMFData->time = 0; + + /* reset the synth */ + VMReset(pEASData->pVoiceMgr, pSMFData->pSynth, EAS_TRUE); + + /* find the start of each track */ + ticks = 0x7fffffffL; + pSMFData->nextStream = NULL; + for (i = 0; i < pSMFData->numStreams; i++) + { + + /* reset file position to first byte of data in track */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pSMFData->streams[i].fileHandle, pSMFData->streams[i].startFilePos)) != EAS_SUCCESS) + return result; + + /* initalize some data */ + pSMFData->streams[i].ticks = 0; + + /* initalize the MIDI parser data */ + EAS_InitMIDIStream(&pSMFData->streams[i].midiStream); + + /* parse the first delta time in each stream */ + if ((result = SMF_GetDeltaTime(pEASData->hwInstData,&pSMFData->streams[i])) != EAS_SUCCESS) + return result; + if (pSMFData->streams[i].ticks < ticks) + { + ticks = pSMFData->streams[i].ticks; + pSMFData->nextStream = &pSMFData->streams[i]; + } + } + + + pSMFData->state = EAS_STATE_READY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_Pause() + *---------------------------------------------------------------------------- + * Purpose: + * Pauses the sequencer. Mutes all voices and sets state to pause. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT SMF_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_SMF_DATA *pSMFData; + + /* can't pause a stopped stream */ + pSMFData = (S_SMF_DATA*) pInstData; + if (pSMFData->state == EAS_STATE_STOPPED) + return EAS_ERROR_ALREADY_STOPPED; + + /* mute the synthesizer */ + VMMuteAllVoices(pEASData->pVoiceMgr, pSMFData->pSynth); + pSMFData->state = EAS_STATE_PAUSING; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_Resume() + *---------------------------------------------------------------------------- + * Purpose: + * Resume playing after a pause, sets state back to playing. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT SMF_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_SMF_DATA *pSMFData; + + /* can't resume a stopped stream */ + pSMFData = (S_SMF_DATA*) pInstData; + if (pSMFData->state == EAS_STATE_STOPPED) + return EAS_ERROR_ALREADY_STOPPED; + + /* nothing to do but resume playback */ + pSMFData->state = EAS_STATE_PLAY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_SetData() + *---------------------------------------------------------------------------- + * Purpose: + * Sets parser parameters + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT SMF_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value) +{ + S_SMF_DATA *pSMFData; + + pSMFData = (S_SMF_DATA*) pInstData; + switch (param) + { + + /* set metadata callback */ + case PARSER_DATA_METADATA_CB: + EAS_HWMemCpy(&pSMFData->metadata, (void*) value, sizeof(S_METADATA_CB)); + break; + +#ifdef JET_INTERFACE + /* set jet segment and track ID of all tracks for callback function */ + case PARSER_DATA_JET_CB: + { + EAS_U32 i; + EAS_U32 bit = (EAS_U32) value; + bit = (bit << JET_EVENT_SEG_SHIFT) & JET_EVENT_SEG_MASK; + for (i = 0; i < pSMFData->numStreams; i++) + pSMFData->streams[i].midiStream.jetData = + (pSMFData->streams[i].midiStream.jetData & + ~(JET_EVENT_TRACK_MASK | JET_EVENT_SEG_MASK)) | + i << JET_EVENT_TRACK_SHIFT | bit | MIDI_FLAGS_JET_CB; + pSMFData->flags |= SMF_FLAGS_JET_STREAM; + } + break; + + /* set state of all mute flags at once */ + case PARSER_DATA_MUTE_FLAGS: + { + EAS_INT i; + EAS_U32 bit = (EAS_U32) value; + for (i = 0; i < pSMFData->numStreams; i++) + { + if (bit & 1) + pSMFData->streams[i].midiStream.jetData |= MIDI_FLAGS_JET_MUTE; + else + pSMFData->streams[i].midiStream.jetData &= ~MIDI_FLAGS_JET_MUTE; + bit >>= 1; + } + } + break; + + /* set track mute */ + case PARSER_DATA_SET_MUTE: + if (value < pSMFData->numStreams) + pSMFData->streams[value].midiStream.jetData |= MIDI_FLAGS_JET_MUTE; + else + return EAS_ERROR_PARAMETER_RANGE; + break; + + /* clear track mute */ + case PARSER_DATA_CLEAR_MUTE: + if (value < pSMFData->numStreams) + pSMFData->streams[value].midiStream.jetData &= ~MIDI_FLAGS_JET_MUTE; + else + return EAS_ERROR_PARAMETER_RANGE; + break; +#endif + + default: + return EAS_ERROR_INVALID_PARAMETER; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_GetData() + *---------------------------------------------------------------------------- + * Purpose: + * Retrieves parser parameters + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +EAS_RESULT SMF_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue) +{ + S_SMF_DATA *pSMFData; + + pSMFData = (S_SMF_DATA*) pInstData; + switch (param) + { + /* return file type */ + case PARSER_DATA_FILE_TYPE: + if (pSMFData->numStreams == 1) + *pValue = EAS_FILE_SMF0; + else + *pValue = EAS_FILE_SMF1; + break; + +/* now handled in eas_public.c */ +#if 0 + case PARSER_DATA_POLYPHONY: + if (pSMFData->pSynth) + VMGetPolyphony(pEASData->pVoiceMgr, pSMFData->pSynth, pValue); + else + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + break; + + case PARSER_DATA_PRIORITY: + if (pSMFData->pSynth) + VMGetPriority(pEASData->pVoiceMgr, pSMFData->pSynth, pValue); + break; + + /* set transposition */ + case PARSER_DATA_TRANSPOSITION: + *pValue = pSMFData->transposition; + break; +#endif + + case PARSER_DATA_SYNTH_HANDLE: + *pValue = (EAS_I32) pSMFData->pSynth; + break; + + default: + return EAS_ERROR_INVALID_PARAMETER; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_GetVarLenData() + *---------------------------------------------------------------------------- + * Purpose: + * Reads a varible length quantity from an SMF file + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT SMF_GetVarLenData (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle, EAS_U32 *pData) +{ + EAS_RESULT result; + EAS_U32 data; + EAS_U8 c; + + /* read until bit 7 is zero */ + data = 0; + do + { + if ((result = EAS_HWGetByte(hwInstData, fileHandle,&c)) != EAS_SUCCESS) + return result; + data = (data << 7) | (c & 0x7f); + } while (c & 0x80); + *pData = data; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_GetDeltaTime() + *---------------------------------------------------------------------------- + * Purpose: + * Reads a varible length quantity from an SMF file + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT SMF_GetDeltaTime (EAS_HW_DATA_HANDLE hwInstData, S_SMF_STREAM *pSMFStream) +{ + EAS_RESULT result; + EAS_U32 ticks; + + if ((result = SMF_GetVarLenData(hwInstData, pSMFStream->fileHandle, &ticks)) != EAS_SUCCESS) + return result; + + pSMFStream->ticks += ticks; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_ParseMetaEvent() + *---------------------------------------------------------------------------- + * Purpose: + * Reads a varible length quantity from an SMF file + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT SMF_ParseMetaEvent (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream) +{ + EAS_RESULT result; + EAS_U32 len; + EAS_I32 pos; + EAS_U32 temp; + EAS_U8 c; + + /* get the meta-event type */ + if ((result = EAS_HWGetByte(pEASData->hwInstData, pSMFStream->fileHandle, &c)) != EAS_SUCCESS) + return result; + + /* get the length */ + if ((result = SMF_GetVarLenData(pEASData->hwInstData, pSMFStream->fileHandle, &len)) != EAS_SUCCESS) + return result; + + /* get the current file position so we can skip the event */ + if ((result = EAS_HWFilePos(pEASData->hwInstData, pSMFStream->fileHandle, &pos)) != EAS_SUCCESS) + return result; + pos += (EAS_I32) len; + + /* end of track? */ + if (c == SMF_META_END_OF_TRACK) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Meta-event: end of track\n", c, len); */ } + pSMFStream->ticks = SMF_END_OF_TRACK; + } + + /* tempo event? */ + else if (c == SMF_META_TEMPO) + { + /* read the 3-byte timebase value */ + temp = 0; + while (len--) + { + if ((result = EAS_HWGetByte(pEASData->hwInstData, pSMFStream->fileHandle, &c)) != EAS_SUCCESS) + return result; + temp = (temp << 8) | c; + } + + pSMFData->tickConv = (EAS_U16) (((temp * 1024) / pSMFData->ppqn + 500) / 1000); + pSMFData->flags |= SMF_FLAGS_HAS_TEMPO; + } + + /* check for time signature - see iMelody spec V1.4 section 4.1.2.2.3.6 */ + else if (c == SMF_META_TIME_SIGNATURE) + { + pSMFData->flags |= SMF_FLAGS_HAS_TIME_SIG; + } + + /* if the host has registered a metadata callback return the metadata */ + else if (pSMFData->metadata.callback) + { + EAS_I32 readLen; + E_EAS_METADATA_TYPE metaType; + + metaType = EAS_METADATA_UNKNOWN; + + /* only process title on the first track */ + if (c == SMF_META_SEQTRK_NAME) + metaType = EAS_METADATA_TITLE; + else if (c == SMF_META_TEXT) + metaType = EAS_METADATA_TEXT; + else if (c == SMF_META_COPYRIGHT) + metaType = EAS_METADATA_COPYRIGHT; + else if (c == SMF_META_LYRIC) + metaType = EAS_METADATA_LYRIC; + + if (metaType != EAS_METADATA_UNKNOWN) + { + readLen = pSMFData->metadata.bufferSize - 1; + if ((EAS_I32) len < readLen) + readLen = (EAS_I32) len; + if ((result = EAS_HWReadFile(pEASData->hwInstData, pSMFStream->fileHandle, pSMFData->metadata.buffer, readLen, &readLen)) != EAS_SUCCESS) + return result; + pSMFData->metadata.buffer[readLen] = 0; + pSMFData->metadata.callback(metaType, pSMFData->metadata.buffer, pSMFData->metadata.pUserData); + } + } + + /* position file to next event - in case we ignored all or part of the meta-event */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pSMFStream->fileHandle, pos)) != EAS_SUCCESS) + return result; + + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Meta-event: type=%02x, len=%d\n", c, len); */ } + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_ParseSysEx() + *---------------------------------------------------------------------------- + * Purpose: + * Reads a varible length quantity from an SMF file + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT SMF_ParseSysEx (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream, EAS_U8 f0, EAS_INT parserMode) +{ + EAS_RESULT result; + EAS_U32 len; + EAS_U8 c; + + /* get the length */ + if ((result = SMF_GetVarLenData(pEASData->hwInstData, pSMFStream->fileHandle, &len)) != EAS_SUCCESS) + return result; + + /* start of SysEx message? */ + if (f0 == 0xf0) + { + if ((result = EAS_ParseMIDIStream(pEASData, pSMFData->pSynth, &pSMFStream->midiStream, f0, parserMode)) != EAS_SUCCESS) + return result; + } + + /* feed the SysEx to the stream parser */ + while (len--) + { + if ((result = EAS_HWGetByte(pEASData->hwInstData, pSMFStream->fileHandle, &c)) != EAS_SUCCESS) + return result; + if ((result = EAS_ParseMIDIStream(pEASData, pSMFData->pSynth, &pSMFStream->midiStream, c, parserMode)) != EAS_SUCCESS) + return result; + + /* check for GM system ON */ + if (pSMFStream->midiStream.flags & MIDI_FLAG_GM_ON) + pSMFData->flags |= SMF_FLAGS_HAS_GM_ON; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_ParseEvent() + *---------------------------------------------------------------------------- + * Purpose: + * Reads a varible length quantity from an SMF file + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT SMF_ParseEvent (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream, EAS_INT parserMode) +{ + EAS_RESULT result; + EAS_U8 c; + + /* get the event type */ + if ((result = EAS_HWGetByte(pEASData->hwInstData, pSMFStream->fileHandle, &c)) != EAS_SUCCESS) + return result; + + /* parse meta-event */ + if (c == 0xff) + { + if ((result = SMF_ParseMetaEvent(pEASData, pSMFData, pSMFStream)) != EAS_SUCCESS) + return result; + } + + /* parse SysEx */ + else if ((c == 0xf0) || (c == 0xf7)) + { + if ((result = SMF_ParseSysEx(pEASData, pSMFData, pSMFStream, c, parserMode)) != EAS_SUCCESS) + return result; + } + + /* parse MIDI message */ + else + { + if ((result = EAS_ParseMIDIStream(pEASData, pSMFData->pSynth, &pSMFStream->midiStream, c, parserMode)) != EAS_SUCCESS) + return result; + + /* keep streaming data to the MIDI parser until the message is complete */ + while (pSMFStream->midiStream.pending) + { + if ((result = EAS_HWGetByte(pEASData->hwInstData, pSMFStream->fileHandle, &c)) != EAS_SUCCESS) + return result; + if ((result = EAS_ParseMIDIStream(pEASData, pSMFData->pSynth, &pSMFStream->midiStream, c, parserMode)) != EAS_SUCCESS) + return result; + } + + } + + /* chase mode logic */ + if (pSMFData->time == 0) + { + if (pSMFData->flags & SMF_FLAGS_CHASE_MODE) + { + if (pSMFStream->midiStream.flags & MIDI_FLAG_FIRST_NOTE) + pSMFData->flags &= ~SMF_FLAGS_CHASE_MODE; + } + else if ((pSMFData->flags & SMF_FLAGS_SETUP_BAR) == SMF_FLAGS_SETUP_BAR) + pSMFData->flags = (pSMFData->flags & ~SMF_FLAGS_SETUP_BAR) | SMF_FLAGS_CHASE_MODE; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * SMF_ParseHeader() + *---------------------------------------------------------------------------- + * Purpose: + * Parses the header of an SMF file, allocates memory the stream parsers and initializes the + * stream parsers. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * pSMFData - pointer to parser instance data + * fileHandle - file handle + * fileOffset - offset in the file where the header data starts, usually 0 + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -e{801} we know that 'goto' is deprecated - but it's cleaner in this case */ +EAS_RESULT SMF_ParseHeader (EAS_HW_DATA_HANDLE hwInstData, S_SMF_DATA *pSMFData) +{ + EAS_RESULT result; + EAS_I32 i; + EAS_U16 division; + EAS_U32 chunkSize; + EAS_U32 chunkStart; + EAS_U32 temp; + EAS_U32 ticks; + + /* rewind the file and find the end of the header chunk */ + if ((result = EAS_HWFileSeek(hwInstData, pSMFData->fileHandle, pSMFData->fileOffset + SMF_OFS_HEADER_SIZE)) != EAS_SUCCESS) + goto ReadError; + if ((result = EAS_HWGetDWord(hwInstData, pSMFData->fileHandle, &chunkSize, EAS_TRUE)) != EAS_SUCCESS) + goto ReadError; + + /* determine the number of tracks */ + if ((result = EAS_HWFileSeek(hwInstData, pSMFData->fileHandle, pSMFData->fileOffset + SMF_OFS_NUM_TRACKS)) != EAS_SUCCESS) + goto ReadError; + if ((result = EAS_HWGetWord(hwInstData, pSMFData->fileHandle, &pSMFData->numStreams, EAS_TRUE)) != EAS_SUCCESS) + goto ReadError; + + /* limit the number of tracks */ + if (pSMFData->numStreams > MAX_SMF_STREAMS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "SMF file contains %u tracks, playing %d tracks\n", pSMFData->numStreams, MAX_SMF_STREAMS); */ } + pSMFData->numStreams = MAX_SMF_STREAMS; + } else if (pSMFData->numStreams == 0) + { + /* avoid 0 sized allocation */ + return EAS_ERROR_PARAMETER_RANGE; + } + + /* get the time division */ + if ((result = EAS_HWGetWord(hwInstData, pSMFData->fileHandle, &division, EAS_TRUE)) != EAS_SUCCESS) + goto ReadError; + + /* setup default timebase for 120 bpm */ + pSMFData->ppqn = 192; + if (!division || division & 0x8000) + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING,"No support for SMPTE code timebase\n"); */ } + else + pSMFData->ppqn = (division & 0x7fff); + pSMFData->tickConv = (EAS_U16) (((SMF_DEFAULT_TIMEBASE * 1024) / pSMFData->ppqn + 500) / 1000); + + /* dynamic memory allocation, allocate memory for streams */ + if (pSMFData->streams == NULL) + { + pSMFData->streams = EAS_HWMalloc(hwInstData,sizeof(S_SMF_STREAM) * pSMFData->numStreams); + if (pSMFData->streams == NULL) + return EAS_ERROR_MALLOC_FAILED; + + /* zero the memory to insure complete initialization */ + EAS_HWMemSet((void *)(pSMFData->streams), 0, sizeof(S_SMF_STREAM) * pSMFData->numStreams); + } + + /* find the start of each track */ + chunkStart = (EAS_U32) pSMFData->fileOffset; + ticks = 0x7fffffffL; + pSMFData->nextStream = NULL; + for (i = 0; i < pSMFData->numStreams; i++) + { + + for (;;) + { + + /* calculate start of next chunk - checking for errors */ + temp = chunkStart + SMF_CHUNK_INFO_SIZE + chunkSize; + if (temp <= chunkStart) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING,"Error in chunk size at offset %d\n", chunkStart); */ } + return EAS_ERROR_FILE_FORMAT; + } + chunkStart = temp; + + /* seek to the start of the next chunk */ + if ((result = EAS_HWFileSeek(hwInstData, pSMFData->fileHandle, (EAS_I32) chunkStart)) != EAS_SUCCESS) + goto ReadError; + + /* read the chunk identifier */ + if ((result = EAS_HWGetDWord(hwInstData, pSMFData->fileHandle, &temp, EAS_TRUE)) != EAS_SUCCESS) + goto ReadError; + + /* read the chunk size */ + if ((result = EAS_HWGetDWord(hwInstData, pSMFData->fileHandle, &chunkSize, EAS_TRUE)) != EAS_SUCCESS) + goto ReadError; + + /* make sure this is an 'MTrk' chunk */ + if (temp == SMF_CHUNK_TYPE_TRACK) + break; + + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING,"Unexpected chunk type: 0x%08x\n", temp); */ } + } + + /* initalize some data */ + pSMFData->streams[i].ticks = 0; + pSMFData->streams[i].fileHandle = pSMFData->fileHandle; + + /* NULL the file handle so we don't try to close it twice */ + pSMFData->fileHandle = NULL; + + /* save this file position as the start of the track */ + pSMFData->streams[i].startFilePos = (EAS_I32) chunkStart + SMF_CHUNK_INFO_SIZE; + + /* initalize the MIDI parser data */ + EAS_InitMIDIStream(&pSMFData->streams[i].midiStream); + + /* parse the first delta time in each stream */ + if ((result = SMF_GetDeltaTime(hwInstData, &pSMFData->streams[i])) != EAS_SUCCESS) + goto ReadError; + + if (pSMFData->streams[i].ticks < ticks) + { + ticks = pSMFData->streams[i].ticks; + pSMFData->nextStream = &pSMFData->streams[i]; + } + + /* more tracks to do, create a duplicate file handle */ + if (i < (pSMFData->numStreams - 1)) + { + if ((result = EAS_HWDupHandle(hwInstData, pSMFData->streams[i].fileHandle, &pSMFData->fileHandle)) != EAS_SUCCESS) + goto ReadError; + } + } + + /* update the time of the next event */ + if (pSMFData->nextStream) + SMF_UpdateTime(pSMFData, pSMFData->nextStream->ticks); + + return EAS_SUCCESS; + + /* ugly goto: but simpler than structured */ + ReadError: + if (result == EAS_EOF) + return EAS_ERROR_FILE_FORMAT; + return result; +} + +/*---------------------------------------------------------------------------- + * SMF_UpdateTime() + *---------------------------------------------------------------------------- + * Purpose: + * Update the millisecond time base by converting the ticks into millieconds + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static void SMF_UpdateTime (S_SMF_DATA *pSMFData, EAS_U32 ticks) +{ + EAS_U32 temp1, temp2; + + if (pSMFData->flags & SMF_FLAGS_CHASE_MODE) + return; + + temp1 = (ticks >> 10) * pSMFData->tickConv; + temp2 = (ticks & 0x3ff) * pSMFData->tickConv; + pSMFData->time += (EAS_I32)((temp1 << 8) + (temp2 >> 2)); +} + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_smf.h b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_smf.h new file mode 100755 index 0000000..37c0790 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_smf.h @@ -0,0 +1,49 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_smf.h + * + * Contents and purpose: + * SMF Type 0 and 1 File Parser + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_SMF_H +#define _EAS_SMF_H + +/* prototypes for private interface to SMF parser */ +EAS_RESULT SMF_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset); +EAS_RESULT SMF_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +EAS_RESULT SMF_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime); +EAS_RESULT SMF_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode); +EAS_RESULT SMF_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_STATE *pState); +EAS_RESULT SMF_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +EAS_RESULT SMF_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +EAS_RESULT SMF_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +EAS_RESULT SMF_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +EAS_RESULT SMF_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value); +EAS_RESULT SMF_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue); +EAS_RESULT SMF_ParseHeader (EAS_HW_DATA_HANDLE hwInstData, S_SMF_DATA *pSMFData); + +#endif /* end _EAS_SMF_H */ + + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_smfdata.c b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_smfdata.c new file mode 100755 index 0000000..383d7f3 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_smfdata.c @@ -0,0 +1,66 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_smfdata.c + * + * Contents and purpose: + * SMF File Parser + * + * This file contains data definitions for the SMF parser. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 778 $ + * $Date: 2007-07-23 16:45:17 -0700 (Mon, 23 Jul 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_miditypes.h" +#include "eas_smfdata.h" + +/*---------------------------------------------------------------------------- + * + * S_SMF_STREAM + * + * Static memory allocation for SMF parser + *---------------------------------------------------------------------------- +*/ +static S_SMF_STREAM eas_SMFStreams[MAX_SMF_STREAMS]; + +/*---------------------------------------------------------------------------- + * + * eas_SMFData + * + * Static memory allocation for SMF parser + *---------------------------------------------------------------------------- +*/ +S_SMF_DATA eas_SMFData = +{ + eas_SMFStreams, /* pointer to individual streams in file */ + 0, /* pointer to next stream with event */ + 0, /* pointer to synth */ + 0, /* file handle */ + { 0, 0, 0, 0}, /* metadata callback */ + 0, /* file offset */ + 0, /* current time in milliseconds/256 */ + 0, /* actual number of streams */ + 0, /* current MIDI tick to msec conversion */ + 0, /* ticks per quarter note */ + 0, /* current state EAS_STATE_XXXX */ + 0 /* flags */ +}; + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_smfdata.h b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_smfdata.h new file mode 100755 index 0000000..8f08839 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_smfdata.h @@ -0,0 +1,66 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_smfdata.h + * + * Contents and purpose: + * SMF File Parser + * + * This file contains data definitions for the SMF parser. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 686 $ + * $Date: 2007-05-03 14:10:54 -0700 (Thu, 03 May 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_SMF_DATA_H +#define _EAS_SMF_DATA_H + +#ifndef MAX_SMF_STREAMS +#define MAX_SMF_STREAMS 128 +#endif + +/* offsets in to the SMF file */ +#define SMF_OFS_HEADER_SIZE 4 +#define SMF_OFS_FILE_TYPE 8 +#define SMF_OFS_NUM_TRACKS 10 + +/* size of chunk info (chunk ID + chunk size) */ +#define SMF_CHUNK_INFO_SIZE 8 + +/* 'MTrk' track chunk ID */ +#define SMF_CHUNK_TYPE_TRACK 0x4d54726bL + +/* some useful meta-events */ +#define SMF_META_TEXT 0x01 +#define SMF_META_COPYRIGHT 0x02 +#define SMF_META_SEQTRK_NAME 0x03 +#define SMF_META_LYRIC 0x05 +#define SMF_META_END_OF_TRACK 0x2f +#define SMF_META_TEMPO 0x51 +#define SMF_META_TIME_SIGNATURE 0x58 + +/* default timebase (120BPM) */ +#define SMF_DEFAULT_TIMEBASE 500000L + +/* value for pSMFStream->ticks to signify end of track */ +#define SMF_END_OF_TRACK 0xffffffff + +#endif + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_sndlib.h b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_sndlib.h new file mode 100755 index 0000000..416be6e --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_sndlib.h @@ -0,0 +1,406 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_sndlib.h + * + * Contents and purpose: + * Declarations for the sound library + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 550 $ + * $Date: 2007-02-02 09:37:03 -0800 (Fri, 02 Feb 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_SNDLIB_H +#define _EAS_SNDLIB_H + +#include "eas_types.h" +#include "eas_synthcfg.h" + +#ifdef _WT_SYNTH +#include "eas_wtengine.h" +#endif + +/*---------------------------------------------------------------------------- + * This is bit of a hack to allow us to keep the same structure + * declarations for the DLS parser. Normally, the data is located + * in read-only memory, but for DLS, we store the data in RW + * memory. + *---------------------------------------------------------------------------- +*/ +#ifndef SCNST +#define SCNST const +#endif + +/*---------------------------------------------------------------------------- + * sample size + *---------------------------------------------------------------------------- +*/ +#ifdef _16_BIT_SAMPLES +typedef EAS_I16 EAS_SAMPLE; +#else +typedef EAS_I8 EAS_SAMPLE; +#endif + +/*---------------------------------------------------------------------------- + * EAS Library ID - quick check for valid library and version + *---------------------------------------------------------------------------- +*/ +#define _EAS_LIBRARY_VERSION 0x01534145 + +#define NUM_PROGRAMS_IN_BANK 128 +#define INVALID_REGION_INDEX 0xffff + +/* this bit in region index indicates that region is for secondary synth */ +#define FLAG_RGN_IDX_FM_SYNTH 0x8000 +#define FLAG_RGN_IDX_DLS_SYNTH 0x4000 +#define REGION_INDEX_MASK 0x3fff + +/*---------------------------------------------------------------------------- + * Generic region data structure + * + * This must be the first element in each region structure + *---------------------------------------------------------------------------- +*/ +typedef struct s_region_tag +{ + EAS_U16 keyGroupAndFlags; + EAS_U8 rangeLow; + EAS_U8 rangeHigh; +} S_REGION; + +/* + * Bit fields for m_nKeyGroupAndFlags + * Bits 0-2 are mode bits in FM synth + * Bits 8-11 are the key group + */ +#define REGION_FLAG_IS_LOOPED 0x01 +#define REGION_FLAG_USE_WAVE_GENERATOR 0x02 +#define REGION_FLAG_USE_ADPCM 0x04 +#define REGION_FLAG_ONE_SHOT 0x08 +#define REGION_FLAG_SQUARE_WAVE 0x10 +#define REGION_FLAG_OFF_CHIP 0x20 +#define REGION_FLAG_NON_SELF_EXCLUSIVE 0x40 +#define REGION_FLAG_LAST_REGION 0x8000 + +/*---------------------------------------------------------------------------- + * Envelope data structure + *---------------------------------------------------------------------------- +*/ +typedef struct s_envelope_tag +{ + EAS_I16 attackTime; + EAS_I16 decayTime; + EAS_I16 sustainLevel; + EAS_I16 releaseTime; +} S_ENVELOPE; + +/*---------------------------------------------------------------------------- + * DLS envelope data structure + *---------------------------------------------------------------------------- +*/ +typedef struct s_dls_envelope_tag +{ + EAS_I16 delayTime; + EAS_I16 attackTime; + EAS_I16 holdTime; + EAS_I16 decayTime; + EAS_I16 sustainLevel; + EAS_I16 releaseTime; + EAS_I16 velToAttack; + EAS_I16 keyNumToDecay; + EAS_I16 keyNumToHold; +} S_DLS_ENVELOPE; + +/*---------------------------------------------------------------------------- + * LFO data structure + *---------------------------------------------------------------------------- +*/ +typedef struct s_lfo_params_tag +{ + EAS_I16 lfoFreq; + EAS_I16 lfoDelay; +} S_LFO_PARAMS; + +/*---------------------------------------------------------------------------- + * Articulation data structure + *---------------------------------------------------------------------------- +*/ +typedef struct s_articulation_tag +{ + S_ENVELOPE eg1; + S_ENVELOPE eg2; + EAS_I16 lfoToPitch; + EAS_I16 lfoDelay; + EAS_I16 lfoFreq; + EAS_I16 eg2ToPitch; + EAS_I16 eg2ToFc; + EAS_I16 filterCutoff; + EAS_I8 lfoToGain; + EAS_U8 filterQ; + EAS_I8 pan; +} S_ARTICULATION; + +/*---------------------------------------------------------------------------- + * DLS articulation data structure + *---------------------------------------------------------------------------- +*/ + +typedef struct s_dls_articulation_tag +{ + S_LFO_PARAMS modLFO; + S_LFO_PARAMS vibLFO; + + S_DLS_ENVELOPE eg1; + S_DLS_ENVELOPE eg2; + + EAS_I16 eg1ShutdownTime; + + EAS_I16 filterCutoff; + EAS_I16 modLFOToFc; + EAS_I16 modLFOCC1ToFc; + EAS_I16 modLFOChanPressToFc; + EAS_I16 eg2ToFc; + EAS_I16 velToFc; + EAS_I16 keyNumToFc; + + EAS_I16 modLFOToGain; + EAS_I16 modLFOCC1ToGain; + EAS_I16 modLFOChanPressToGain; + + EAS_I16 tuning; + EAS_I16 keyNumToPitch; + EAS_I16 vibLFOToPitch; + EAS_I16 vibLFOCC1ToPitch; + EAS_I16 vibLFOChanPressToPitch; + EAS_I16 modLFOToPitch; + EAS_I16 modLFOCC1ToPitch; + EAS_I16 modLFOChanPressToPitch; + EAS_I16 eg2ToPitch; + + /* pad to 4-byte boundary */ + EAS_U16 pad; + + EAS_I8 pan; + EAS_U8 filterQandFlags; + +#ifdef _REVERB + EAS_I16 reverbSend; + EAS_I16 cc91ToReverbSend; +#endif + +#ifdef _CHORUS + EAS_I16 chorusSend; + EAS_I16 cc93ToChorusSend; +#endif +} S_DLS_ARTICULATION; + +/* flags in filterQandFlags + * NOTE: Q is stored in bottom 5 bits + */ +#define FLAG_DLS_VELOCITY_SENSITIVE 0x80 +#define FILTER_Q_MASK 0x1f + +/*---------------------------------------------------------------------------- + * Wavetable region data structure + *---------------------------------------------------------------------------- +*/ +typedef struct s_wt_region_tag +{ + S_REGION region; + EAS_I16 tuning; + EAS_I16 gain; + EAS_U32 loopStart; + EAS_U32 loopEnd; + EAS_U16 waveIndex; + EAS_U16 artIndex; +} S_WT_REGION; + +/*---------------------------------------------------------------------------- + * DLS region data structure + *---------------------------------------------------------------------------- +*/ +typedef struct s_dls_region_tag +{ + S_WT_REGION wtRegion; + EAS_U8 velLow; + EAS_U8 velHigh; +} S_DLS_REGION; + +/*---------------------------------------------------------------------------- + * FM synthesizer data structures + *---------------------------------------------------------------------------- +*/ +typedef struct s_fm_oper_tag +{ + EAS_I16 tuning; + EAS_U8 attackDecay; + EAS_U8 velocityRelease; + EAS_U8 egKeyScale; + EAS_U8 sustain; + EAS_U8 gain; + EAS_U8 flags; +} S_FM_OPER; + +/* defines for S_FM_OPER.m_nFlags */ +#define FM_OPER_FLAG_MONOTONE 0x01 +#define FM_OPER_FLAG_NO_VIBRATO 0x02 +#define FM_OPER_FLAG_NOISE 0x04 +#define FM_OPER_FLAG_LINEAR_VELOCITY 0x08 + +/* NOTE: The first two structure elements are common with S_WT_REGION + * and we will rely on that in the voice management code and must + * remain there unless the voice management code is revisited. + */ +typedef struct s_fm_region_tag +{ + S_REGION region; + EAS_U8 vibTrem; + EAS_U8 lfoFreqDelay; + EAS_U8 feedback; + EAS_I8 pan; + S_FM_OPER oper[4]; +} S_FM_REGION; + +/*---------------------------------------------------------------------------- + * Common data structures + *---------------------------------------------------------------------------- +*/ + +/*---------------------------------------------------------------------------- + * Program data structure + * Used for individual programs not stored as a complete bank. + *---------------------------------------------------------------------------- +*/ +typedef struct s_program_tag +{ + EAS_U32 locale; + EAS_U16 regionIndex; +} S_PROGRAM; + +/*---------------------------------------------------------------------------- + * Bank data structure + * + * A bank always consists of 128 programs. If a bank is less than 128 + * programs, it should be stored as a spare matrix in the pPrograms + * array. + * + * bankNum: MSB/LSB of MIDI bank select controller + * regionIndex: Index of first region in program + *---------------------------------------------------------------------------- +*/ +typedef struct s_bank_tag +{ + EAS_U16 locale; + EAS_U16 regionIndex[NUM_PROGRAMS_IN_BANK]; +} S_BANK; + + +/* defines for libFormat field + * bits 0-17 are the sample rate + * bit 18 is true if wavetable is present + * bit 19 is true if FM is present + * bit 20 is true if filter is enabled + * bit 21 is sample depth (0 = 8-bits, 1 = 16-bits) + * bits 22-31 are reserved + */ +#define LIBFORMAT_SAMPLE_RATE_MASK 0x0003ffff +#define LIB_FORMAT_TYPE_MASK 0x000c0000 +#define LIB_FORMAT_WAVETABLE 0x00000000 +#define LIB_FORMAT_FM 0x00040000 +#define LIB_FORMAT_HYBRID 0x00080000 +#define LIB_FORMAT_FILTER_ENABLED 0x00100000 +#define LIB_FORMAT_16_BIT_SAMPLES 0x00200000 + +#ifdef DLS_SYNTHESIZER +/*---------------------------------------------------------------------------- + * DLS data structure + * + * pDLSPrograms pointer to array of DLS programs + * pDLSRegions pointer to array of DLS regions + * pDLSArticulations pointer to array of DLS articulations + * pSampleLen pointer to array of sample lengths + * ppSamples pointer to array of sample pointers + * numDLSPrograms number of DLS programs + * numDLSRegions number of DLS regions + * numDLSArticulations number of DLS articulations + * numDLSSamples number of DLS samples + *---------------------------------------------------------------------------- +*/ +typedef struct s_eas_dls_tag +{ + S_PROGRAM *pDLSPrograms; + S_DLS_REGION *pDLSRegions; + S_DLS_ARTICULATION *pDLSArticulations; + EAS_U32 *pDLSSampleLen; + EAS_U32 *pDLSSampleOffsets; + EAS_SAMPLE *pDLSSamples; + EAS_U16 numDLSPrograms; + EAS_U16 numDLSRegions; + EAS_U16 numDLSArticulations; + EAS_U16 numDLSSamples; + EAS_U8 refCount; +} S_DLS; +#endif + +/*---------------------------------------------------------------------------- + * Sound library data structure + * + * pBanks pointer to array of banks + * pPrograms pointer to array of programs + * pWTRegions pointer to array of wavetable regions + * pFMRegions pointer to array of FM regions + * pArticulations pointer to array of articulations + * pSampleLen pointer to array of sample lengths + * ppSamples pointer to array of sample pointers + * numBanks number of banks + * numPrograms number of individual program + * numRegions number of regions + * numArticulations number of articulations + * numSamples number of samples + *---------------------------------------------------------------------------- +*/ +typedef struct s_eas_sndlib_tag +{ + SCNST EAS_U32 identifier; + SCNST EAS_U32 libAttr; + + SCNST S_BANK *pBanks; + SCNST S_PROGRAM *pPrograms; + + SCNST S_WT_REGION *pWTRegions; + SCNST S_ARTICULATION *pArticulations; + SCNST EAS_U32 *pSampleLen; + SCNST EAS_U32 *pSampleOffsets; + SCNST EAS_SAMPLE *pSamples; + + SCNST S_FM_REGION *pFMRegions; + + SCNST EAS_U16 numBanks; + SCNST EAS_U16 numPrograms; + + SCNST EAS_U16 numWTRegions; + SCNST EAS_U16 numArticulations; + SCNST EAS_U16 numSamples; + + SCNST EAS_U16 numFMRegions; +} S_EAS; + +#endif + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_synth.h b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_synth.h new file mode 100755 index 0000000..6274b7d --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_synth.h @@ -0,0 +1,395 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_synth.h + * + * Contents and purpose: + * Declarations, interfaces, and prototypes for synth. + * + * Copyright Sonic Network Inc. 2004, 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 718 $ + * $Date: 2007-06-08 16:43:16 -0700 (Fri, 08 Jun 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_SYNTH_H +#define _EAS_SYNTH_H + +#include "eas_types.h" +#include "eas_sndlib.h" + +#ifdef _WT_SYNTH +#include "eas_wtsynth.h" +#endif + +#ifdef _FM_SYNTH +#include "eas_fmsynth.h" +#endif + +#ifndef NUM_OUTPUT_CHANNELS +#define NUM_OUTPUT_CHANNELS 2 +#endif + +#ifndef MAX_SYNTH_VOICES +#define MAX_SYNTH_VOICES 64 +#endif + +#ifndef MAX_VIRTUAL_SYNTHESIZERS +#define MAX_VIRTUAL_SYNTHESIZERS 4 +#endif + +/* defines */ +#ifndef NUM_PRIMARY_VOICES +#define NUM_PRIMARY_VOICES MAX_SYNTH_VOICES +#elif !defined(NUM_SECONDARY_VOICES) +#define NUM_SECONDARY_VOICES (MAX_SYNTH_VOICES - NUM_PRIMARY_VOICES) +#endif + +#if defined(EAS_WT_SYNTH) +#define NUM_WT_VOICES MAX_SYNTH_VOICES + +/* FM on MCU */ +#elif defined(EAS_FM_SYNTH) +#define NUM_FM_VOICES MAX_SYNTH_VOICES + +/* wavetable drums on MCU, wavetable melodic on DSP */ +#elif defined(EAS_SPLIT_WT_SYNTH) +#define NUM_WT_VOICES MAX_SYNTH_VOICES + +/* wavetable drums and FM melodic on MCU */ +#elif defined(EAS_HYBRID_SYNTH) +#define NUM_WT_VOICES NUM_PRIMARY_VOICES +#define NUM_FM_VOICES NUM_SECONDARY_VOICES + +/* wavetable drums on MCU, FM melodic on DSP */ +#elif defined(EAS_SPLIT_HYBRID_SYNTH) +#define NUM_WT_VOICES NUM_PRIMARY_VOICES +#define NUM_FM_VOICES NUM_SECONDARY_VOICES + +/* FM synth on DSP */ +#elif defined(EAS_SPLIT_FM_SYNTH) +#define NUM_FM_VOICES MAX_SYNTH_VOICES + +#else +#error "Unrecognized architecture option" +#endif + +#define NUM_SYNTH_CHANNELS 16 + +#define DEFAULT_SYNTH_VOICES MAX_SYNTH_VOICES + +/* use the following values to specify unassigned channels or voices */ +#define UNASSIGNED_SYNTH_CHANNEL NUM_SYNTH_CHANNELS +#define UNASSIGNED_SYNTH_VOICE MAX_SYNTH_VOICES + + +/* synth parameters are updated every SYNTH_UPDATE_PERIOD_IN_SAMPLES */ +#define SYNTH_UPDATE_PERIOD_IN_SAMPLES (EAS_I32)(0x1L << SYNTH_UPDATE_PERIOD_IN_BITS) + +/* stealing weighting factors */ +#define NOTE_AGE_STEAL_WEIGHT 1 +#define NOTE_GAIN_STEAL_WEIGHT 4 +#define CHANNEL_POLY_STEAL_WEIGHT 12 +#define CHANNEL_PRIORITY_STEAL_WEIGHT 2 +#define NOTE_MATCH_PENALTY 128 +#define SYNTH_PRIORITY_WEIGHT 8 + +/* default synth master volume */ +#define DEFAULT_SYNTH_MASTER_VOLUME 0x7fff + +#define DEFAULT_SYNTH_PRIORITY 5 + +/* default tuning values */ +#define DEFAULT_PITCH_BEND_SENSITIVITY 200 /* 2 semitones */ +#define DEFAULT_FINE_PITCH 0 /* 0 cents */ +#define DEFAULT_COARSE_PITCH 0 /* 0 semitones */ + +/* default drum channel is 10, but is internally 9 due to unit offset */ +#define DEFAULT_DRUM_CHANNEL 9 + +/* drum channel can simultaneously play this many voices at most */ +#define DEFAULT_CHANNEL_POLYPHONY_LIMIT 2 + +/* default instrument is acoustic piano */ +#define DEFAULT_MELODY_BANK_MSB 0x79 +#define DEFAULT_RHYTHM_BANK_MSB 0x78 +#define DEFAULT_MELODY_BANK_NUMBER (DEFAULT_MELODY_BANK_MSB << 8) +#define DEFAULT_RHYTHM_BANK_NUMBER (DEFAULT_RHYTHM_BANK_MSB << 8) +#define DEFAULT_SYNTH_PROGRAM_NUMBER 0 + +#define DEFAULT_PITCH_BEND 0x2000 /* 0x2000 == (0x40 << 7) | 0x00 */ +#define DEFAULT_MOD_WHEEL 0 +#define DEFAULT_CHANNEL_VOLUME 0x64 +#define DEFAULT_PAN 0x40 /* decimal 64, center */ + +#ifdef _REVERB +#define DEFAULT_REVERB_SEND 40 /* some reverb */ +#endif + +#ifdef _CHORUS +#define DEFAULT_CHORUS_SEND 0 /* no chorus */ +#endif + +#define DEFAULT_EAS_FILTER_CUTOFF_FREQUENCY 0 /* EAS synth uses a different default */ +#define DEFAULT_FILTER_RESONANCE 0 +#define DEFAULT_EXPRESSION 0x7F + +#define DEFAULT_CHANNEL_PRESSURE 0 + +#define DEFAULT_REGISTERED_PARAM 0x3FFF + +#define DEFAULT_CHANNEL_STATIC_GAIN 0 +#define DEFAULT_CHANNEL_STATIC_PITCH 0 + +#define DEFAULT_LFO_MOD_WHEEL_TO_PITCH_CENTS 50 +#define DEFAULT_LFO_CHANNEL_PRESSURE_TO_PITCH_CENTS 50 + +#define DEFAULT_KEY_NUMBER 0x69 +#define DEFAULT_VELOCITY 0x64 +#define DEFAULT_REGION_INDEX 0 +#define DEFAULT_ARTICULATION_INDEX 0 +#define DEFAULT_VOICE_GAIN 0 +#define DEFAULT_AGE 0 +#define DEFAULT_SP_MIDI_PRIORITY 16 + + +/* filter defines */ +#define DEFAULT_FILTER_ZERO 0 +#define FILTER_CUTOFF_MAX_PITCH_CENTS 1919 +#define FILTER_CUTOFF_MIN_PITCH_CENTS -4467 +#define A5_PITCH_OFFSET_IN_CENTS 6900 + +/*------------------------------------ + * S_SYNTH_CHANNEL data structure + *------------------------------------ +*/ + +/* S_SYNTH_CHANNEL.m_nFlags */ +#define CHANNEL_FLAG_SUSTAIN_PEDAL 0x01 +#define CHANNEL_FLAG_MUTE 0x02 +#define CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS 0x04 +#define CHANNEL_FLAG_RHYTHM_CHANNEL 0x08 +#define CHANNEL_FLAG_EXTERNAL_AUDIO 0x10 +#define DEFAULT_CHANNEL_FLAGS 0 + +/* macros for extracting virtual synth and channel numbers */ +#define GET_VSYNTH(a) ((a) >> 4) +#define GET_CHANNEL(a) ((a) & 15) + +typedef struct s_synth_channel_tag +{ + /* use static channel parameters to reduce MIPs */ + /* parameters shared by multiple voices assigned to same channel */ + EAS_I32 staticPitch; /* (pitch bend * pitch sens) + fine pitch */ + EAS_I16 staticGain; /* (CC7 * CC11 * master vol)^2 */ + + EAS_U16 regionIndex; /* index of first region in program */ + + EAS_U16 bankNum; /* play programs from this bank */ + EAS_I16 pitchBend; /* pitch wheel value */ + EAS_I16 pitchBendSensitivity; + EAS_I16 registeredParam; /* currently selected registered param */ + + +#if defined(_FM_SYNTH) + EAS_I16 lfoAmt; /* amount of LFO to apply to voice */ +#endif + + EAS_U8 programNum; /* play this instrument number */ + EAS_U8 modWheel; /* CC1 */ + EAS_U8 volume; /* CC7 */ + EAS_U8 pan; /* CC10 */ + + EAS_U8 expression; /* CC11 */ + + /* the following parameters are controlled by RPNs */ + EAS_I8 finePitch; + EAS_I8 coarsePitch; + + EAS_U8 channelPressure; /* applied to all voices on a given channel */ + + EAS_U8 channelFlags; /* bit field channelFlags for */ + /* CC64, SP-MIDI channel masking */ + + EAS_U8 pool; /* SPMIDI channel voice pool */ + EAS_U8 mip; /* SPMIDI MIP setting */ + +#ifdef _REVERB + EAS_U8 reverbSend; /* CC91 */ +#endif + +#ifdef _CHORUS + EAS_U8 chorusSend; /* CC93 */ +#endif +} S_SYNTH_CHANNEL; + +/*------------------------------------ + * S_SYNTH_VOICE data structure + *------------------------------------ +*/ + +/* S_SYNTH_VOICE.m_nFlags */ +#define VOICE_FLAG_UPDATE_VOICE_PARAMETERS 0x01 +#define VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF 0x02 +#define VOICE_FLAG_DEFER_MIDI_NOTE_OFF 0x04 +#define VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET 0x08 +#define VOICE_FLAG_DEFER_MUTE 0x40 +#define DEFAULT_VOICE_FLAGS 0 + +/* S_SYNTH_VOICE.m_eState */ +typedef enum { + + eVoiceStateFree = 0, + eVoiceStateStart, + eVoiceStatePlay, + eVoiceStateRelease, + eVoiceStateMuting, + eVoiceStateStolen, + eVoiceStateInvalid /* should never be in this state! */ + +} E_VOICE_STATE; +#define DEFAULT_VOICE_STATE eVoiceStateFree + +typedef struct s_synth_voice_tag +{ + +/* These parameters are common to both wavetable and FM + * synthesizers. The voice manager should only access this data. + * Any other data should be manipulated by the code that is + * specific to that synthesizer and reflected back through the + * common state data available here. + */ + EAS_U16 regionIndex; /* index to wave and playback params */ + EAS_I16 gain; /* current gain */ + EAS_U16 age; /* large value means old note */ + EAS_U16 nextRegionIndex; /* index to wave and playback params */ + EAS_U8 voiceState; /* current voice state */ + EAS_U8 voiceFlags; /* misc flags/bit fields */ + EAS_U8 channel; /* this voice plays on this synth channel */ + EAS_U8 note; /* 12 <= key number <= 108 */ + EAS_U8 velocity; /* 0 <= velocity <= 127 */ + EAS_U8 nextChannel; /* play stolen voice on this channel */ + EAS_U8 nextNote; /* 12 <= key number <= 108 */ + EAS_U8 nextVelocity; /* 0 <= velocity <= 127 */ +} S_SYNTH_VOICE; + +/*------------------------------------ + * S_SYNTH data structure + * + * One instance for each MIDI stream + *------------------------------------ +*/ + +/* S_SYNTH.m_nFlags */ +#define SYNTH_FLAG_RESET_IS_REQUESTED 0x01 +#define SYNTH_FLAG_SP_MIDI_ON 0x02 +#define SYNTH_FLAG_UPDATE_ALL_CHANNEL_PARAMETERS 0x04 +#define SYNTH_FLAG_DEFERRED_MIDI_NOTE_OFF_PENDING 0x08 +#define DEFAULT_SYNTH_FLAGS SYNTH_FLAG_UPDATE_ALL_CHANNEL_PARAMETERS + +typedef struct s_synth_tag +{ + struct s_eas_data_tag *pEASData; + const S_EAS *pEAS; + +#ifdef DLS_SYNTHESIZER + S_DLS *pDLS; +#endif + +#ifdef EXTERNAL_AUDIO + EAS_EXT_PRG_CHG_FUNC cbProgChgFunc; + EAS_EXT_EVENT_FUNC cbEventFunc; + EAS_VOID_PTR *pExtAudioInstData; +#endif + + S_SYNTH_CHANNEL channels[NUM_SYNTH_CHANNELS]; + EAS_I32 totalNoteCount; + EAS_U16 maxPolyphony; + EAS_U16 numActiveVoices; + EAS_U16 masterVolume; + EAS_U8 channelsByPriority[NUM_SYNTH_CHANNELS]; + EAS_U8 poolCount[NUM_SYNTH_CHANNELS]; + EAS_U8 poolAlloc[NUM_SYNTH_CHANNELS]; + EAS_U8 synthFlags; + EAS_I8 globalTranspose; + EAS_U8 vSynthNum; + EAS_U8 refCount; + EAS_U8 priority; +} S_SYNTH; + +/*------------------------------------ + * S_VOICE_MGR data structure + * + * One instance for each EAS library instance + *------------------------------------ +*/ +typedef struct s_voice_mgr_tag +{ + S_SYNTH *pSynth[MAX_VIRTUAL_SYNTHESIZERS]; + EAS_PCM voiceBuffer[SYNTH_UPDATE_PERIOD_IN_SAMPLES]; + +#ifdef _FM_SYNTH + EAS_PCM operMixBuffer[SYNTH_UPDATE_PERIOD_IN_SAMPLES]; + S_FM_VOICE fmVoices[NUM_FM_VOICES]; +#endif + +#ifdef _WT_SYNTH + S_WT_VOICE wtVoices[NUM_WT_VOICES]; +#endif + +#ifdef _REVERB + EAS_PCM reverbSendBuffer[NUM_OUTPUT_CHANNELS * SYNTH_UPDATE_PERIOD_IN_SAMPLES]; +#endif + +#ifdef _CHORUS + EAS_PCM chorusSendBuffer[NUM_OUTPUT_CHANNELS * SYNTH_UPDATE_PERIOD_IN_SAMPLES]; +#endif + S_SYNTH_VOICE voices[MAX_SYNTH_VOICES]; + + EAS_SNDLIB_HANDLE pGlobalEAS; + +#ifdef DLS_SYNTHESIZER + S_DLS *pGlobalDLS; +#endif + +#ifdef _SPLIT_ARCHITECTURE + EAS_FRAME_BUFFER_HANDLE pFrameBuffer; +#endif + +#if defined(_SECONDARY_SYNTH) || defined(EAS_SPLIT_WT_SYNTH) + EAS_U16 maxPolyphonyPrimary; + EAS_U16 maxPolyphonySecondary; +#endif + + EAS_I32 workload; + EAS_I32 maxWorkLoad; + + EAS_U16 activeVoices; + EAS_U16 maxPolyphony; + + EAS_U16 age; + +/* limits the number of voice starts in a frame for split architecture */ +#ifdef MAX_VOICE_STARTS + EAS_U16 numVoiceStarts; +#endif +} S_VOICE_MGR; + +#endif /* #ifdef _EAS_SYNTH_H */ + + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_synth_protos.h b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_synth_protos.h new file mode 100755 index 0000000..b03af0f --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_synth_protos.h @@ -0,0 +1,60 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_synth_protos.h + * + * Contents and purpose: + * Declarations, interfaces, and prototypes for synth. + * + * Copyright Sonic Network Inc. 2004 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_SYNTH_PROTOS_H +#define _EAS_SYNTH_PROTOS_H + +/* includes */ +#include "eas_data.h" +#include "eas_sndlib.h" + +#ifdef _SPLIT_ARCHITECTURE +typedef struct s_frame_interface_tag +{ + EAS_BOOL (* EAS_CONST pfStartFrame)(EAS_FRAME_BUFFER_HANDLE pFrameBuffer); + EAS_BOOL (* EAS_CONST pfEndFrame)(EAS_FRAME_BUFFER_HANDLE pFrameBuffer, EAS_I32 *pMixBuffer, EAS_I16 masterGain); +} S_FRAME_INTERFACE; +#endif + +/* generic synthesizer interface */ +typedef struct +{ + EAS_RESULT (* EAS_CONST pfInitialize)(S_VOICE_MGR *pVoiceMgr); + EAS_RESULT (* EAS_CONST pfStartVoice)(S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_U16 regionIndex); + EAS_BOOL (* EAS_CONST pfUpdateVoice)(S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_I32 *pMixBuffer, EAS_I32 numSamples); + void (* EAS_CONST pfReleaseVoice)(S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum); + void (* EAS_CONST pfMuteVoice)(S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum); + void (* EAS_CONST pfSustainPedal)(S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, S_SYNTH_CHANNEL *pChannel, EAS_I32 voiceNum); + void (* EAS_CONST pfUpdateChannel)(S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel); +} S_SYNTH_INTERFACE; + +#endif + + + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_synthcfg.h b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_synthcfg.h new file mode 100755 index 0000000..78a4178 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_synthcfg.h @@ -0,0 +1,70 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_synthcfg.h + * + * Contents and purpose: + * Defines for various synth configurations + * + * Copyright Sonic Network Inc. 2004, 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 664 $ + * $Date: 2007-04-25 13:11:22 -0700 (Wed, 25 Apr 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_SYNTHCFG_H +#define _EAS_SYNTHCFG_H + +#if defined(EAS_WT_SYNTH) +#define _WT_SYNTH + +/* FM on MCU */ +#elif defined(EAS_FM_SYNTH) +#define _FM_SYNTH + +/* wavetable drums and FM melodic on MCU */ +#elif defined(EAS_HYBRID_SYNTH) +#define _WT_SYNTH +#define _FM_SYNTH +#define _SECONDARY_SYNTH +#define _HYBRID_SYNTH + +/* wavetable drums on MCU, wavetable melodic on DSP */ +#elif defined(EAS_SPLIT_WT_SYNTH) +#define _WT_SYNTH +#define _SPLIT_ARCHITECTURE + +/* wavetable drums on MCU, FM melodic on DSP */ +#elif defined(EAS_SPLIT_HYBRID_SYNTH) +#define _WT_SYNTH +#define _FM_SYNTH +#define _SECONDARY_SYNTH +#define _SPLIT_ARCHITECTURE +#define _HYBRID_SYNTH + +/* FM synth on DSP */ +#elif defined(EAS_SPLIT_FM_SYNTH) +#define _FM_SYNTH +#define _SPLIT_ARCHITECTURE + +#else +#error "Unrecognized architecture option" +#endif + +#endif + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_tcdata.c b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_tcdata.c new file mode 100755 index 0000000..65ba49e --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_tcdata.c @@ -0,0 +1,43 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_tcdata.c + * + * Contents and purpose: + * ToneControl Parser data + * + * This file contains static data for the ToneControl parser. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 547 $ + * $Date: 2007-01-31 16:30:17 -0800 (Wed, 31 Jan 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_types.h" +#include "eas_tcdata.h" + +/*---------------------------------------------------------------------------- + * + * eas_iMelodyData + * + * Static memory allocation for iMelody parser + *---------------------------------------------------------------------------- +*/ +S_TC_DATA eas_TCData; + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_tcdata.h b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_tcdata.h new file mode 100755 index 0000000..8b9dec5 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_tcdata.h @@ -0,0 +1,65 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_tcdata.h + * + * Contents and purpose: + * SMF File Parser + * + * This file contains data declarations for the ToneControl parser. + * + * Copyright Sonic Network Inc. 2006 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef EAS_TFDATA_H +#define EAS_TCDATA_H + +#include "eas_data.h" + +/*---------------------------------------------------------------------------- + * + * S_TC_DATA + * + * This structure contains the state data for the ToneControl parser + *---------------------------------------------------------------------------- +*/ +typedef struct +{ + EAS_FILE_HANDLE fileHandle; /* file handle */ + S_SYNTH *pSynth; /* synthesizer handle */ + EAS_I32 fileOffset; /* offset to start of data */ + EAS_I32 time; /* current time in 256ths of a msec */ + EAS_I32 tick; /* tick based on current tempo and resolution */ + EAS_I32 length; /* length of current note */ + EAS_I32 restorePos; /* return to here after block */ + EAS_U8 state; /* current state EAS_STATE_XXXX */ + EAS_U8 volume; /* volume */ + EAS_I8 note; /* current note */ + EAS_I8 repeatCount; /* note repeat counter */ + EAS_I8 tempo; /* tempo from file (bpm = tempo * 4) */ + EAS_I8 resolution; /* resolution from file */ + EAS_I8 dataByte; /* storage for characters that are "put back" */ + EAS_BOOL8 byteAvail; /* char in "put back" buffer */ +} S_TC_DATA; + +#endif + + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_tonecontrol.c b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_tonecontrol.c new file mode 100755 index 0000000..cceb7f9 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_tonecontrol.c @@ -0,0 +1,941 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_tonecontrol.c + * + * Contents and purpose: + * MMAPI ToneControl parser + * + * Copyright Sonic Network Inc. 2006 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 795 $ + * $Date: 2007-08-01 00:14:45 -0700 (Wed, 01 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_data.h" +#include "eas_miditypes.h" +#include "eas_parser.h" +#include "eas_report.h" +#include "eas_host.h" +#include "eas_midi.h" +#include "eas_config.h" +#include "eas_vm_protos.h" +#include "eas_tcdata.h" + + +/* default channel and program for TC playback */ +#define TC_CHANNEL 0 +#define TC_PROGRAM 80 +#define TC_VELOCITY 127 + +#define TC_FIELD_SILENCE -1 +#define TC_FIELD_VERSION -2 +#define TC_FIELD_TEMPO -3 +#define TC_FIELD_RESOLUTION -4 +#define TC_FIELD_BLOCK_START -5 +#define TC_FIELD_BLOCK_END -6 +#define TC_FIELD_PLAY_BLOCK -7 +#define TC_FIELD_SET_VOLUME -8 +#define TC_FIELD_REPEAT -9 +#define TC_FIELD_INVALID -10 + +/* convert 0-100 volume to 0-127 velocity using fixed point */ +#define TC_VOLUME_CONV 21307064 +#define TC_VOLUME_SHIFT 24 + + +/* local prototypes */ +static EAS_RESULT TC_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset); +static EAS_RESULT TC_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT TC_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime); +static EAS_RESULT TC_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode); +static EAS_RESULT TC_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_STATE *pState); +static EAS_RESULT TC_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT TC_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT TC_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT TC_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT TC_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value); +static EAS_RESULT TC_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue); +static EAS_RESULT TC_ParseHeader (S_EAS_DATA *pEASData, S_TC_DATA* pData); +static EAS_RESULT TC_StartNote (S_EAS_DATA *pEASData, S_TC_DATA* pData, EAS_INT parserMode, EAS_I8 note); +static EAS_RESULT TC_GetRepeat (S_EAS_DATA *pEASData, S_TC_DATA* pData, EAS_INT parserMode); +static EAS_RESULT TC_PlayBlock (S_EAS_DATA *pEASData, S_TC_DATA* pData); +static EAS_RESULT TC_BlockEnd (S_EAS_DATA *pEASData, S_TC_DATA* pData); +static EAS_RESULT TC_GetVolume (S_EAS_DATA *pEASData, S_TC_DATA* pData); +static EAS_RESULT TC_GetTempo (S_EAS_DATA *pEASData, S_TC_DATA* pData); +static EAS_RESULT TC_GetResolution (S_EAS_DATA *pEASData, S_TC_DATA* pData); +static EAS_RESULT TC_GetNextChar (EAS_HW_DATA_HANDLE hwInstData, S_TC_DATA *pData, EAS_I8 *pValue); +static void TC_PutBackChar (S_TC_DATA *pData, EAS_I8 value); + +/* calculate a new tick time based on resolution & tempo */ +EAS_INLINE void TC_CalcTimeBase (S_TC_DATA *pData) +{ + + /* ticks in 256ths of a millisecond */ + pData->tick = ((60 * 1000) << 8) / (pData->tempo * pData->resolution); +} + +/*---------------------------------------------------------------------------- + * + * EAS_TC_Parser + * + * This structure contains the functional interface for the iMelody parser + *---------------------------------------------------------------------------- +*/ +const S_FILE_PARSER_INTERFACE EAS_TC_Parser = +{ + TC_CheckFileType, + TC_Prepare, + TC_Time, + TC_Event, + TC_State, + TC_Close, + TC_Reset, + TC_Pause, + TC_Resume, + NULL, + TC_SetData, + TC_GetData, + NULL +}; + +/*---------------------------------------------------------------------------- + * TC_CheckFileType() + *---------------------------------------------------------------------------- + * Purpose: + * Check the file type to see if we can parse it + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT TC_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset) +{ + S_TC_DATA data; + S_TC_DATA *pData; + + /* init data */ + EAS_HWMemSet(&data, 0, sizeof(S_TC_DATA)); + data.fileHandle = fileHandle; + data.fileOffset = offset; + *ppHandle= NULL; + + /* see if we can parse the header */ + if (TC_ParseHeader(pEASData, &data) == EAS_SUCCESS) + { + + /* check for static memory allocation */ + if (pEASData->staticMemoryModel) + pData = EAS_CMEnumOptData(EAS_MODULE_MMAPI_TONE_CONTROL); + else + pData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_TC_DATA)); + if (!pData) + return EAS_ERROR_MALLOC_FAILED; + + /* copy data to persistent storage */ + EAS_HWMemCpy(pData, &data, sizeof(S_TC_DATA)); + + /* return a pointer to the instance data */ + pData->state = EAS_STATE_OPEN; + *ppHandle = pData; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * TC_Prepare() + *---------------------------------------------------------------------------- + * Purpose: + * Prepare to parse the file. Allocates instance data (or uses static allocation for + * static memory model). + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT TC_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_TC_DATA* pData; + EAS_RESULT result; + + /* check for valid state */ + pData = (S_TC_DATA*) pInstData; + if (pData->state != EAS_STATE_OPEN) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + /* instantiate a synthesizer */ + if ((result = VMInitMIDI(pEASData, &pData->pSynth)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitMIDI returned %d\n", result); */ } + return result; + } + + /* set to ready state */ + pData->state = EAS_STATE_READY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * TC_Time() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the time of the next event in msecs + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * pTime - pointer to variable to hold time of next event (in msecs) + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +static EAS_RESULT TC_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime) +{ + S_TC_DATA *pData; + + pData = (S_TC_DATA*) pInstData; + + /* return time in milliseconds */ + /*lint -e{704} use shift instead of division */ + *pTime = pData->time >> 8; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * TC_Event() + *---------------------------------------------------------------------------- + * Purpose: + * Parse the next event in the file + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT TC_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode) +{ + S_TC_DATA* pData; + EAS_RESULT result; + EAS_I8 temp; + + pData = (S_TC_DATA*) pInstData; + if (pData->state >= EAS_STATE_OPEN) + return EAS_SUCCESS; + + /* initialize MIDI channel when the track starts playing */ + if (pData->time == 0) + { + /* set program to square lead */ + VMProgramChange(pEASData->pVoiceMgr, pData->pSynth, TC_CHANNEL, TC_PROGRAM); + + /* set channel volume to max */ + VMControlChange(pEASData->pVoiceMgr, pData->pSynth, TC_CHANNEL, 7, 127); + } + + /* check for end of note */ + if (pData->note >= 0) + { + /* stop the note */ + VMStopNote(pEASData->pVoiceMgr, pData->pSynth, TC_CHANNEL, (EAS_U8) pData->note, 0); + + /* check for repeat note */ + if (pData->repeatCount) + { + pData->repeatCount--; + pData->time += pData->length; + if ((pData->note >= 0) && (parserMode == eParserModePlay)) + VMStartNote(pEASData->pVoiceMgr, pData->pSynth, TC_CHANNEL, (EAS_U8) pData->note, pData->volume); + return EAS_SUCCESS; + } + + pData->note = TC_FIELD_SILENCE; + } + + /* parse stream until we get a note or rest */ + for (;;) + { + + /* get next byte from stream */ + if ((result = TC_GetNextChar(pEASData->hwInstData, pData, &temp)) != EAS_SUCCESS) + { + if (result == EAS_EOF) + { + pData->state = EAS_STATE_STOPPING; + return EAS_SUCCESS; + } + break; + } + + /* check for musical events */ + if (temp >= TC_FIELD_SILENCE) + { + result = TC_StartNote(pEASData, pData, parserMode, temp); + break; + } + + /* must be a control field */ + switch (temp) + { + case TC_FIELD_TEMPO: + result = TC_GetTempo(pEASData, pData); + break; + + case TC_FIELD_RESOLUTION: + result = TC_GetResolution(pEASData, pData); + break; + + case TC_FIELD_SET_VOLUME: + result = TC_GetVolume(pEASData, pData); + break; + + case TC_FIELD_REPEAT: + result = TC_GetRepeat(pEASData, pData, parserMode); + break; + + case TC_FIELD_PLAY_BLOCK: + result = TC_PlayBlock(pEASData, pData); + break; + + case TC_FIELD_BLOCK_START: + result = TC_GetNextChar(pEASData->hwInstData, pData, &temp); + break; + + case TC_FIELD_BLOCK_END: + result = TC_BlockEnd(pEASData, pData); + break; + + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Unexpected byte 0x%02x in ToneControl stream\n", temp); */ } + result = EAS_ERROR_FILE_FORMAT; + } + + /* check for error */ + if (result != EAS_SUCCESS) + break; + } + + /* check for error */ + if (result != EAS_SUCCESS) + { + if (result == EAS_EOF) + result = EAS_ERROR_FILE_FORMAT; + pData->state = EAS_STATE_ERROR; + } + else + pData->state = EAS_STATE_PLAY; + return result; +} + +/*---------------------------------------------------------------------------- + * TC_State() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current state of the stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * pState - pointer to variable to store state + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +static EAS_RESULT TC_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pState) +{ + S_TC_DATA* pData; + + /* establish pointer to instance data */ + pData = (S_TC_DATA*) pInstData; + + /* if stopping, check to see if synth voices are active */ + if (pData->state == EAS_STATE_STOPPING) + { + if (VMActiveVoices(pData->pSynth) == 0) + pData->state = EAS_STATE_STOPPED; + } + + if (pData->state == EAS_STATE_PAUSING) + { + if (VMActiveVoices(pData->pSynth) == 0) + pData->state = EAS_STATE_PAUSED; + } + + /* return current state */ + *pState = pData->state; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * TC_Close() + *---------------------------------------------------------------------------- + * Purpose: + * Close the file and clean up + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT TC_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_TC_DATA* pData; + EAS_RESULT result; + + pData = (S_TC_DATA*) pInstData; + + /* close the file */ + if ((result = EAS_HWCloseFile(pEASData->hwInstData, pData->fileHandle)) != EAS_SUCCESS) + return result; + + /* free the synth */ + if (pData->pSynth != NULL) + VMMIDIShutdown(pEASData, pData->pSynth); + + /* if using dynamic memory, free it */ + if (!pEASData->staticMemoryModel) + EAS_HWFree(pEASData->hwInstData, pData); + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * TC_Reset() + *---------------------------------------------------------------------------- + * Purpose: + * Reset the sequencer. Used for locating backwards in the file. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT TC_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_TC_DATA* pData; + EAS_RESULT result; + + pData = (S_TC_DATA*) pInstData; + + /* reset the synth */ + VMReset(pEASData->pVoiceMgr, pData->pSynth, EAS_TRUE); + + /* reset time to zero */ + pData->time = 0; + + /* reset file position and re-parse header */ + pData->state = EAS_STATE_ERROR; + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pData->fileHandle, pData->fileOffset)) != EAS_SUCCESS) + return result; + if ((result = TC_ParseHeader (pEASData, pData)) != EAS_SUCCESS) + return result; + + pData->state = EAS_STATE_READY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * TC_Pause() + *---------------------------------------------------------------------------- + * Purpose: + * Pauses the sequencer. Mutes all voices and sets state to pause. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT TC_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_TC_DATA *pData; + + /* can't pause a stopped stream */ + pData = (S_TC_DATA*) pInstData; + if (pData->state == EAS_STATE_STOPPED) + return EAS_ERROR_ALREADY_STOPPED; + + /* mute the synthesizer */ + VMMuteAllVoices(pEASData->pVoiceMgr, pData->pSynth); + pData->state = EAS_STATE_PAUSING; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * TC_Resume() + *---------------------------------------------------------------------------- + * Purpose: + * Resume playing after a pause, sets state back to playing. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +static EAS_RESULT TC_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_TC_DATA *pData; + + /* can't resume a stopped stream */ + pData = (S_TC_DATA*) pInstData; + if (pData->state == EAS_STATE_STOPPED) + return EAS_ERROR_ALREADY_STOPPED; + + /* nothing to do but resume playback */ + pData->state = EAS_STATE_PLAY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * TC_SetData() + *---------------------------------------------------------------------------- + * Purpose: + * Return file type + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData, pInstData, value) reserved for future use */ +static EAS_RESULT TC_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value) +{ + /* we don't parse any metadata, but we need to return success here */ + if (param == PARSER_DATA_METADATA_CB) + return EAS_SUCCESS; + + return EAS_ERROR_INVALID_PARAMETER; +} + +/*---------------------------------------------------------------------------- + * TC_GetData() + *---------------------------------------------------------------------------- + * Purpose: + * Return file type + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -e{715} common with other parsers */ +static EAS_RESULT TC_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue) +{ + S_TC_DATA *pData; + + pData = (S_TC_DATA *) pInstData; + switch (param) + { + /* return file type as TC */ + case PARSER_DATA_FILE_TYPE: + *pValue = EAS_FILE_MMAPI_TONE_CONTROL; + break; + + case PARSER_DATA_SYNTH_HANDLE: + *pValue = (EAS_I32) pData->pSynth; + break; + + default: + return EAS_ERROR_INVALID_PARAMETER; + } + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * TC_ParseHeader() + *---------------------------------------------------------------------------- + * Purpose: + * Prepare to parse the file. Allocates instance data (or uses static allocation for + * static memory model). + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT TC_ParseHeader (S_EAS_DATA *pEASData, S_TC_DATA* pData) +{ + EAS_RESULT result; + EAS_I8 temp; + + /* initialize some defaults */ + pData->time = 0; + pData->tempo = 120; + pData->resolution = 64; + pData->volume = 127; + pData->repeatCount = 0; + pData->note = TC_FIELD_SILENCE; + pData->byteAvail = EAS_FALSE; + + /* set default timebase */ + TC_CalcTimeBase(pData); + + /* seek to start of data */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pData->fileHandle, pData->fileOffset)) != EAS_SUCCESS) + return result; + + /* get version */ + if ((result = TC_GetNextChar(pEASData->hwInstData, pData, &temp)) != EAS_SUCCESS) + return result; + + /* check for version number */ + if (temp == TC_FIELD_VERSION) + { + TC_GetNextChar(pEASData->hwInstData, pData, &temp); +// { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "ToneControl sequence version %d\n", temp); */ } + } + else + return EAS_ERROR_FILE_FORMAT; + + /* parse the header data until we find the first note or block */ + for (;;) + { + + /* get next byte from stream */ + if ((result = TC_GetNextChar(pEASData->hwInstData, pData, &temp)) != EAS_SUCCESS) + return result; + + /* check for tempo */ + if (temp == TC_FIELD_TEMPO) + { + if ((result = TC_GetTempo(pEASData, pData)) != EAS_SUCCESS) + return result; + } + + /* or resolution */ + else if (temp == TC_FIELD_TEMPO) + { + if ((result = TC_GetResolution(pEASData, pData)) != EAS_SUCCESS) + return result; + } + + /* must be music data */ + else if (temp > TC_FIELD_INVALID) + { + TC_PutBackChar(pData, temp); + return EAS_SUCCESS; + } + + /* unknown codes */ + else + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Unexpected byte 0x%02x in ToneControl stream\n", temp); */ } + return EAS_ERROR_FILE_FORMAT; + } + } +} + +/*---------------------------------------------------------------------------- + * TC_StartNote() + *---------------------------------------------------------------------------- + * Process a note or silence event + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT TC_StartNote (S_EAS_DATA *pEASData, S_TC_DATA* pData, EAS_INT parserMode, EAS_I8 note) +{ + EAS_I8 duration; + + /* get the duration */ + if (TC_GetNextChar(pEASData->hwInstData, pData, &duration) != EAS_SUCCESS) + return EAS_ERROR_FILE_FORMAT; + + /* calculate time of next event */ + pData->length = (EAS_I32) duration * pData->tick; + pData->time += pData->length; + + /* start the note */ + if ((note >= 0) && (parserMode == eParserModePlay)) + { + VMStartNote(pEASData->pVoiceMgr, pData->pSynth, TC_CHANNEL, (EAS_U8) note, pData->volume); + pData->note = note; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * TC_GetRepeat() + *---------------------------------------------------------------------------- + * Process a repeat code + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT TC_GetRepeat (S_EAS_DATA *pEASData, S_TC_DATA* pData, EAS_INT parserMode) +{ + EAS_I8 count; + + /* get the repeat count */ + if (TC_GetNextChar(pEASData->hwInstData, pData, &count) != EAS_SUCCESS) + return EAS_ERROR_FILE_FORMAT; + + /* validiate it */ + if (count < 2) + return EAS_ERROR_FILE_FORMAT; + + /* calculate time of next event */ + pData->time += pData->length; + pData->repeatCount = count - 2; + + /* start the note */ + if ((pData->note >= 0) && (parserMode == eParserModePlay)) + VMStartNote(pEASData->pVoiceMgr, pData->pSynth, TC_CHANNEL, (EAS_U8) pData->note, pData->volume); + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * TC_PlayBlock() + *---------------------------------------------------------------------------- + * Play a block of notes + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT TC_PlayBlock (S_EAS_DATA *pEASData, S_TC_DATA* pData) +{ + EAS_RESULT result; + EAS_I8 blockNum; + EAS_I8 temp; + EAS_I8 temp2; + + /* get the block number */ + if (TC_GetNextChar(pEASData->hwInstData, pData, &blockNum) != EAS_SUCCESS) + return EAS_ERROR_FILE_FORMAT; + + /* validiate it */ + if (blockNum < 0) + return EAS_ERROR_FILE_FORMAT; + + /* save the current position */ + if ((result = EAS_HWFilePos(pEASData->hwInstData, pData->fileHandle, &pData->restorePos)) != EAS_SUCCESS) + return result; + + /* return to start of file */ + pData->byteAvail = EAS_FALSE; + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pData->fileHandle, pData->fileOffset)) != EAS_SUCCESS) + return result; + + /* find the block */ + for (;;) + { + if (TC_GetNextChar(pEASData->hwInstData, pData, &temp) != EAS_SUCCESS) + return EAS_ERROR_FILE_FORMAT; + + if (TC_GetNextChar(pEASData->hwInstData, pData, &temp2) != EAS_SUCCESS) + return EAS_ERROR_FILE_FORMAT; + + if ((temp == TC_FIELD_BLOCK_START) && (temp2 == blockNum)) + return EAS_SUCCESS; + } +} + +/*---------------------------------------------------------------------------- + * TC_BlockEnd() + *---------------------------------------------------------------------------- + * Handle end of block + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT TC_BlockEnd (S_EAS_DATA *pEASData, S_TC_DATA* pData) +{ + EAS_I8 blockNum; + + /* get the block number */ + if (TC_GetNextChar(pEASData->hwInstData, pData, &blockNum) != EAS_SUCCESS) + return EAS_ERROR_FILE_FORMAT; + + /* validiate it */ + if (blockNum < 0) + return EAS_ERROR_FILE_FORMAT; + + /* if we were playing this block, restore to previous position */ + pData->byteAvail = EAS_FALSE; + return EAS_HWFileSeek(pEASData->hwInstData, pData->fileHandle, pData->restorePos); +} + +/*---------------------------------------------------------------------------- + * TC_GetVolume() + *---------------------------------------------------------------------------- + * Get the volume field and process it + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT TC_GetVolume (S_EAS_DATA *pEASData, S_TC_DATA* pData) +{ + EAS_I8 volume; + + /* get volume */ + if (TC_GetNextChar(pEASData->hwInstData, pData, &volume) != EAS_SUCCESS) + return EAS_ERROR_FILE_FORMAT; + if ((volume < 0) || (volume > 100)) + return EAS_ERROR_FILE_FORMAT; + + /* save volume */ + pData->volume = (EAS_U8) ((EAS_I32) (volume * TC_VOLUME_CONV + 1) >> TC_VOLUME_SHIFT); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * TC_GetTempo() + *---------------------------------------------------------------------------- + * Get the tempo field and process it + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT TC_GetTempo (S_EAS_DATA *pEASData, S_TC_DATA* pData) +{ + EAS_I8 tempo; + + /* get tempo */ + if (TC_GetNextChar(pEASData->hwInstData, pData, &tempo) != EAS_SUCCESS) + return EAS_ERROR_FILE_FORMAT; + if (tempo < 5) + return EAS_ERROR_FILE_FORMAT; + + /* save tempo */ + pData->tempo = tempo; + + /* calculate new timebase */ + TC_CalcTimeBase(pData); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * TC_GetResolution() + *---------------------------------------------------------------------------- + * Get the resolution field and process it + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT TC_GetResolution (S_EAS_DATA *pEASData, S_TC_DATA* pData) +{ + EAS_I8 resolution; + + /* get resolution */ + if (TC_GetNextChar(pEASData->hwInstData, pData, &resolution) != EAS_SUCCESS) + return EAS_ERROR_FILE_FORMAT; + if (resolution < 0) + return EAS_ERROR_FILE_FORMAT; + + /* save tempo */ + pData->resolution = resolution; + + /* calculate new timebase */ + TC_CalcTimeBase(pData); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * TC_GetNextChar() + *---------------------------------------------------------------------------- + * Fetch the next character from the stream + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT TC_GetNextChar (EAS_HW_DATA_HANDLE hwInstData, S_TC_DATA *pData, EAS_I8 *pValue) +{ + + /* get character from "put back" buffer */ + if (pData->byteAvail) + { + pData->byteAvail = EAS_FALSE; + *pValue = pData->dataByte; + return EAS_SUCCESS; + } + + /* get character from file */ + return EAS_HWGetByte(hwInstData, pData->fileHandle, pValue); +} + +/*---------------------------------------------------------------------------- + * TC_PutBackChar() + *---------------------------------------------------------------------------- + * Put back the character + *---------------------------------------------------------------------------- +*/ +static void TC_PutBackChar (S_TC_DATA *pData, EAS_I8 value) +{ + + pData->dataByte = value; + pData->byteAvail = EAS_TRUE; +} + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_vm_protos.h b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_vm_protos.h new file mode 100755 index 0000000..20f7c09 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_vm_protos.h @@ -0,0 +1,1086 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_vm_protos.h + * + * Contents and purpose: + * Declarations, interfaces, and prototypes for voice manager. + * + * Copyright Sonic Network Inc. 2004 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 736 $ + * $Date: 2007-06-22 13:51:24 -0700 (Fri, 22 Jun 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_VM_PROTOS_H +#define _EAS_VM_PROTOS_H + +// includes +#include "eas_data.h" +#include "eas_sndlib.h" + +/*---------------------------------------------------------------------------- + * VMInitialize() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMInitialize (S_EAS_DATA *pEASData); + +/*---------------------------------------------------------------------------- + * VMInitMIDI() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMInitMIDI (S_EAS_DATA *pEASData, S_SYNTH **ppSynth); + +/*---------------------------------------------------------------------------- + * VMInitializeAllChannels() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +void VMInitializeAllChannels (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth); + +/*---------------------------------------------------------------------------- + * VMResetControllers() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +void VMResetControllers (S_SYNTH *pSynth); + +/*---------------------------------------------------------------------------- + * VMInitMIPTable() + *---------------------------------------------------------------------------- + * Purpose: + * Initialize the SP-MIDI MIP table + * + * Inputs: + * pEASData - pointer to synthesizer instance data + * mute - EAS_FALSE to unmute channels, EAS_TRUE to mute + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMInitMIPTable (S_SYNTH *pSynth); + +/*---------------------------------------------------------------------------- + * VMSetMIPEntry() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the priority and MIP level for a MIDI channel + * + * Inputs: + * pEASData - pointer to synthesizer instance data + * channel - MIDI channel number + * priority - priority (0-15 with 0 = highest priority) + * mip - maximum instantaneous polyphony + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMSetMIPEntry (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 priority, EAS_U8 mip); + +/*---------------------------------------------------------------------------- + * VMUpdateMIPTable() + *---------------------------------------------------------------------------- + * Purpose: + * This routine is called when the polyphony count in the synthesizer changes + * + * Inputs: + * pEASData - pointer to synthesizer instance data + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMUpdateMIPTable (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth); + +/*---------------------------------------------------------------------------- + * VMInitializeAllVoices() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +void VMInitializeAllVoices (S_VOICE_MGR *pVoiceMgr, EAS_INT vSynthNum); + +/*---------------------------------------------------------------------------- + * VMStartNote() + *---------------------------------------------------------------------------- + * Purpose: + * Update the synth's state to play the requested note on the requested + * channel if possible. + * + * Inputs: + * nChannel - the MIDI channel + * nKeyNumber - the MIDI key number for this note + * nNoteVelocity - the key velocity for this note + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +void VMStartNote (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 note, EAS_U8 velocity); + +/*---------------------------------------------------------------------------- + * VMCheckKeyGroup() + *---------------------------------------------------------------------------- + * Purpose: + * If the note that we've been asked to start is in the same key group as + * any currently playing notes, then we must shut down the currently playing + * note in the same key group and then start the newly requested note. + * + * Inputs: + * nChannel - synth channel that wants to start a new note + * nKeyNumber - new note's midi note number + * nRegionIndex - calling routine finds this index and gives to us + * nNoteVelocity - new note's velocity + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * pbVoiceStealingRequired - flag: this routine sets true if we needed to + * steal a voice + * + * Side Effects: + * gsSynthObject.m_sVoice[free voice num].m_nKeyNumber may be assigned + * gsSynthObject.m_sVoice[free voice num].m_nVelocity may be assigned + *---------------------------------------------------------------------------- +*/ +void VMCheckKeyGroup (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U16 keyGroup, EAS_U8 channel); + +/*---------------------------------------------------------------------------- + * VMCheckPolyphonyLimiting() + *---------------------------------------------------------------------------- + * Purpose: + * We only play at most 2 of the same note on a MIDI channel. + * E.g., if we are asked to start note 36, and there are already two voices + * that are playing note 36, then we must steal the voice playing + * the oldest note 36 and use that stolen voice to play the new note 36. + * + * Inputs: + * nChannel - synth channel that wants to start a new note + * nKeyNumber - new note's midi note number + * nNoteVelocity - new note's velocity + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * pbVoiceStealingRequired - flag: this routine sets true if we needed to + * steal a voice + * * + * Side Effects: + * psSynthObject->m_sVoice[free voice num].m_nKeyNumber may be assigned + * psSynthObject->m_sVoice[free voice num].m_nVelocity may be assigned + *---------------------------------------------------------------------------- +*/ +EAS_BOOL VMCheckPolyphonyLimiting (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 note, EAS_U8 velocity, EAS_U16 regionIndex, EAS_I32 lowVoice, EAS_I32 highVoice); + +/*---------------------------------------------------------------------------- + * VMStopNote() + *---------------------------------------------------------------------------- + * Purpose: + * Update the synth's state to end the requested note on the requested + * channel. + * + * Inputs: + * nChannel - the MIDI channel + * nKeyNumber - the key number of the note to stop + * nNoteVelocity - the note-off velocity + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * Side Effects: + * gsSynthObject.m_sVoice[free voice num].m_nSynthChannel may be assigned + * gsSynthObject.m_sVoice[free voice num].m_nKeyNumber is assigned + * gsSynthObject.m_sVoice[free voice num].m_nVelocity is assigned + *---------------------------------------------------------------------------- +*/ +void VMStopNote (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 key, EAS_U8 velocity); + +/*---------------------------------------------------------------------------- + * VMFindAvailableVoice() + *---------------------------------------------------------------------------- + * Purpose: + * Find an available voice and return the voice number if available. + * + * Inputs: + * pnVoiceNumber - really an output, see below + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * pnVoiceNumber - returns the voice number of available voice if found + * success - if there is an available voice + * failure - otherwise + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMFindAvailableVoice (S_VOICE_MGR *pVoiceMgr, EAS_INT *pVoiceNumber, EAS_I32 lowVoice, EAS_I32 highVoice); + +/*---------------------------------------------------------------------------- + * VMStealVoice() + *---------------------------------------------------------------------------- + * Purpose: + * Steal a voice and return the voice number + * + * Stealing algorithm: steal the best choice with minimal work, taking into + * account SP-Midi channel priorities and polyphony allocation. + * + * In one pass through all the voices, figure out which voice to steal + * taking into account a number of different factors: + * Priority of the voice's MIDI channel + * Number of voices over the polyphony allocation for voice's MIDI channel + * Amplitude of the voice + * Note age + * Key velocity (for voices that haven't been started yet) + * If any matching notes are found + * + * Inputs: + * nChannel - the channel that this voice wants to be started on + * nKeyNumber - the key number for this new voice + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * pnVoiceNumber - voice stolen + * EAS_RESULT EAS_SUCCESS - always successful + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMStealVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_INT *pVoiceNumber, EAS_U8 channel, EAS_U8 note, EAS_I32 lowVoice, EAS_I32 highVoice); + +/*---------------------------------------------------------------------------- + * VMAddSamples() + *---------------------------------------------------------------------------- + * Purpose: + * Synthesize the requested number of samples. + * + * Inputs: + * nNumSamplesToAdd - number of samples to write to buffer + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * number of samples actually written to buffer + * + * Side Effects: + * - samples are added to the presently free buffer + * + *---------------------------------------------------------------------------- +*/ +EAS_I32 VMAddSamples (S_VOICE_MGR *pVoiceMgr, EAS_I32 *pMixBuffer, EAS_I32 numSamplesToAdd); + +/*---------------------------------------------------------------------------- + * VMProgramChange() + *---------------------------------------------------------------------------- + * Purpose: + * Change the instrument (program) for the given channel. + * + * Depending on the program number, and the bank selected for this channel, the + * program may be in ROM, RAM (from SMAF or CMX related RAM wavetable), or + * Alternate wavetable (from mobile DLS or other DLS file) + * + * This function figures out what wavetable should be used, and sets it up as the + * wavetable to use for this channel. Also the channel may switch from a melodic + * channel to a rhythm channel, or vice versa. + * + * Inputs: + * + * Outputs: + * Side Effects: + * gsSynthObject.m_sChannel[nChannel].m_nProgramNumber is likely changed + * gsSynthObject.m_sChannel[nChannel].m_psEAS may be changed + * gsSynthObject.m_sChannel[nChannel].m_bRhythmChannel may be changed + * + *---------------------------------------------------------------------------- +*/ +void VMProgramChange (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 program); + +/*---------------------------------------------------------------------------- + * VMChannelPressure() + *---------------------------------------------------------------------------- + * Purpose: + * Change the channel pressure for the given channel + * + * Inputs: + * nChannel - the MIDI channel + * nVelocity - the channel pressure value + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * Side Effects: + * gsSynthObject.m_sChannel[nChannel].m_nChannelPressure is updated + *---------------------------------------------------------------------------- +*/ +void VMChannelPressure (S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 value); + +/*---------------------------------------------------------------------------- + * VMPitchBend() + *---------------------------------------------------------------------------- + * Purpose: + * Change the pitch wheel value for the given channel. + * This routine constructs the proper 14-bit argument when the calling routine + * passes the pitch LSB and MSB. + * + * Note: some midi disassemblers display a bipolar pitch bend value. + * We can display the bipolar value using + * if m_nPitchBend >= 0x2000 + * bipolar pitch bend = postive (m_nPitchBend - 0x2000) + * else + * bipolar pitch bend = negative (0x2000 - m_nPitchBend) + * + * Inputs: + * nChannel - the MIDI channel + * nPitchLSB - the LSB byte from the pitch bend message + * nPitchMSB - the MSB byte from the message + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * gsSynthObject.m_sChannel[nChannel].m_nPitchBend is changed + * + *---------------------------------------------------------------------------- +*/ +void VMPitchBend (S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 pitchLSB, EAS_U8 pitchMSB); + +/*---------------------------------------------------------------------------- + * VMControlChange() + *---------------------------------------------------------------------------- + * Purpose: + * Change the controller (or mode) for the given channel. + * + * Inputs: + * nChannel - the MIDI channel + * nControllerNumber - the controller number + * nControlValue - the controller number for this control change + * nControlValue - the value for this control change + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * Side Effects: + * gsSynthObject.m_sChannel[nChannel] controller is changed + * + *---------------------------------------------------------------------------- +*/ +void VMControlChange (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 controller, EAS_U8 value); + +/*---------------------------------------------------------------------------- + * VMUpdateRPNStateMachine() + *---------------------------------------------------------------------------- + * Purpose: + * Call this function when we want to parse a stream of RPN messages. + * NOTE: The synth has only one set of global RPN data instead of RPN data + * per channel. + * So actually, we don't really need to look at the nChannel parameter, + * but we pass it to facilitate future upgrades. Furthermore, we only + * support RPN0 (pitch bend sensitivity), RPN1 (fine tuning) and + * RPN2 (coarse tuning). Any other RPNs are rejected. + * + * Inputs: + * nChannel - the MIDI channel + * nControllerNumber - the RPN controller number + * nControlValue - the value for this control change + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * gsSynthObject.m_RPN0 (or m_RPN1 or m_RPN2) may be updated if the + * proper RPN message sequence is parsed. + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMUpdateRPNStateMachine (S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 controller, EAS_U8 value); + +/*---------------------------------------------------------------------------- + * VMUpdateStaticChannelParameters() + *---------------------------------------------------------------------------- + * Purpose: + * Update all of the static channel parameters for channels that have had + * a controller change values + * Or if the synth has signalled that all channels must forcibly + * be updated + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * none + * + * Side Effects: + * - psSynthObject->m_sChannel[].m_nStaticGain and m_nStaticPitch + * are updated for channels whose controller values have changed + * or if the synth has signalled that all channels must forcibly + * be updated + *---------------------------------------------------------------------------- +*/ +void VMUpdateStaticChannelParameters (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth); + +/*---------------------------------------------------------------------------- + * VMReleaseAllDeferredNoteOffs() + *---------------------------------------------------------------------------- + * Purpose: + * Call this functin when the sustain flag is presently set but + * we are now transitioning from damper pedal on to + * damper pedal off. This means all notes in this channel + * that received a note off while the damper pedal was on, and + * had their note-off requests deferred, should now proceed to + * the release state. + * + * Inputs: + * nChannel - this channel has its sustain pedal transitioning from on to off + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * Side Effects: + * any voice with deferred note offs on this channel are updated such that + * + * + *---------------------------------------------------------------------------- +*/ +void VMReleaseAllDeferredNoteOffs (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel); + +/*---------------------------------------------------------------------------- + * VMCatchNotesForSustainPedal() + *---------------------------------------------------------------------------- + * Purpose: + * Call this function when the sustain flag is presently clear and + * the damper pedal is off and we are transitioning from damper pedal OFF to + * damper pedal ON. Currently sounding notes should be left + * unchanged. However, we should try to "catch" notes if possible. + * If any notes have levels >= sustain level, catch them, + * otherwise, let them continue to release. + * + * Inputs: + * nChannel - this channel has its sustain pedal transitioning from on to off + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * Side Effects: + * any voice with deferred note offs on this channel are updated such that + * psVoice->m_sEG1.m_eState = eEnvelopeStateSustainPedal + *---------------------------------------------------------------------------- +*/ +void VMCatchNotesForSustainPedal (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel); + +/*---------------------------------------------------------------------------- + * VMUpdateAllNotesAge() + *---------------------------------------------------------------------------- + * Purpose: + * Increment the note age for all voices older than the age of the voice + * that is stopping, effectively making the voices "younger". + * + * Inputs: + * nAge - age of voice that is going away + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * m_nAge for some voices is incremented + *---------------------------------------------------------------------------- +*/ +void VMUpdateAllNotesAge (S_VOICE_MGR *pVoiceMgr, EAS_U16 nAge); + +/*---------------------------------------------------------------------------- + * VMFindRegionIndex() + *---------------------------------------------------------------------------- + * Purpose: + * Find the region index for the given instrument using the midi key number + * and the RPN2 (coarse tuning) value. By using RPN2 as part of the + * region selection process, we reduce the amount a given sample has + * to be transposed by selecting the closest recorded root instead. + * + * Inputs: + * nChannel - current channel for this note + * nKeyNumber - current midi note number + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * pnRegionIndex - valid only if we returned success + * success if we found the region index number, otherwise + * failure + * + * Side Effects: + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMFindRegionIndex (S_VOICE_MGR *pVoiceMgr, EAS_U8 channel, EAS_U8 note, EAS_U16 *pRegionIndex); + +/*---------------------------------------------------------------------------- + * VMIncRefCount() + *---------------------------------------------------------------------------- + * Increment reference count for virtual synth + *---------------------------------------------------------------------------- +*/ +void VMIncRefCount (S_SYNTH *pSynth); + +/*---------------------------------------------------------------------------- + * VMReset() + *---------------------------------------------------------------------------- + * Purpose: + * We call this routine to start the process of reseting the synth. + * This routine sets a flag for the entire synth indicating that we want + * to reset. + * We also force all voices to mute quickly. + * However, we do not actually perform any synthesis in this routine. That + * is, we do not ramp the voices down from this routine, but instead, we + * let the "regular" synth processing steps take care of adding the ramp + * down samples to the output buffer. After we are sure that all voices + * have completed ramping down, we continue the process of resetting the + * synth (from another routine). + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * - set a flag (in gsSynthObject.m_nFlags) indicating synth reset requested. + * - force all voices to update their envelope states to mute + * + *---------------------------------------------------------------------------- +*/ +void VMReset (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_BOOL force); + +/*---------------------------------------------------------------------------- + * VMMuteAllVoices() + *---------------------------------------------------------------------------- + * Purpose: + * We call this in an emergency reset situation. + * This forces all voices to mute quickly. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * - forces all voices to update their envelope states to mute + * + *---------------------------------------------------------------------------- +*/ +void VMMuteVoice (S_VOICE_MGR *pVoiceMgr, EAS_I32 voiceNum); +void VMMuteAllVoices (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth); + +/*---------------------------------------------------------------------------- + * VMReleaseAllVoices() + *---------------------------------------------------------------------------- + * Purpose: + * We call this after we've encountered the end of the Midi file. + * This ensures all voice are either in release (because we received their + * note off already) or forces them to mute quickly. + * We use this as a safety to prevent bad midi files from playing forever. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * - forces all voices to update their envelope states to release or mute + * + *---------------------------------------------------------------------------- +*/ +void VMReleaseAllVoices (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth); + +/*---------------------------------------------------------------------------- + * VMAllNotesOff() + *---------------------------------------------------------------------------- + * Purpose: + * Quickly mute all notes on the given channel. + * + * Inputs: + * nChannel - quickly turn off all notes on this channel + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * - forces all voices on this channel to update their envelope states to mute + * + *---------------------------------------------------------------------------- +*/ +void VMAllNotesOff (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel); + +/*---------------------------------------------------------------------------- + * VMDeferredStopNote() + *---------------------------------------------------------------------------- + * Purpose: + * Stop the notes that had deferred note-off requests. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * None. + * + * Side Effects: + * voices that have had deferred note-off requests are now put into release + * gsSynthObject.m_sVoice[i].m_nFlags has the VOICE_FLAG_DEFER_MIDI_NOTE_OFF + * cleared + *---------------------------------------------------------------------------- +*/ +void VMDeferredStopNote (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth); + +/*---------------------------------------------------------------------------- + * VMSetSynthPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Set the synth to a new polyphony value. Value must be >= 1 and + * <= MAX_SYNTH_VOICES. This function will pin the polyphony at those limits + * + * Inputs: + * pVoiceMgr pointer to synthesizer data + * synth synthesizer number (0 = onboard, 1 = DSP) + * polyphonyCount desired polyphony count + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMSetSynthPolyphony (S_VOICE_MGR *pVoiceMgr, EAS_I32 synth, EAS_I32 polyphonyCount); + +/*---------------------------------------------------------------------------- + * VMGetSynthPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Set the synth to a new polyphony value. Value must be >= 1 and + * <= MAX_SYNTH_VOICES. This function will pin the polyphony at those limits + * + * Inputs: + * pVoiceMgr pointer to synthesizer data + * synth synthesizer number (0 = onboard, 1 = DSP) + * polyphonyCount desired polyphony count + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMGetSynthPolyphony (S_VOICE_MGR *pVoiceMgr, EAS_I32 synth, EAS_I32 *pPolyphonyCount); + +/*---------------------------------------------------------------------------- + * VMSetPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Set the virtual synth polyphony. 0 = no limit (i.e. can use + * all available voices). + * + * Inputs: + * pVoiceMgr pointer to synthesizer data + * polyphonyCount desired polyphony count + * pSynth pointer to virtual synth + * + * Outputs: + * Returns error code + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMSetPolyphony (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 polyphonyCount); + +/*---------------------------------------------------------------------------- + * VMGetPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current polyphony setting + * + * Inputs: + * pVoiceMgr pointer to synthesizer data + * pSynth pointer to virtual synth + * pPolyphonyCount pointer to variable to receive data + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMGetPolyphony (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 *pPolyphonyCount); + +/*---------------------------------------------------------------------------- + * VMSetPriority() + *---------------------------------------------------------------------------- + * Purpose: + * Set the virtual synth priority + * + * Inputs: + * pVoiceMgr pointer to synthesizer data + * priority new priority + * pSynth pointer to virtual synth + * + * Outputs: + * Returns error code + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMSetPriority (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 priority); + +/*---------------------------------------------------------------------------- + * VMGetPriority() + *---------------------------------------------------------------------------- + * Purpose: + * Get the virtual synth priority + * + * Inputs: + * pVoiceMgr pointer to synthesizer data + * pPriority pointer to variable to hold priority + * pSynth pointer to virtual synth + * + * Outputs: + * Returns error code + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMGetPriority (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 *pPriority); + +/*---------------------------------------------------------------------------- + * VMSetVolume() + *---------------------------------------------------------------------------- + * Purpose: + * Set the master volume for this sequence + * + * Inputs: + * nSynthVolume - the desired master volume + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * + * Side Effects: + * overrides any previously set master volume from sysex + * + *---------------------------------------------------------------------------- +*/ +void VMSetVolume (S_SYNTH *pSynth, EAS_U16 masterVolume); + +/*---------------------------------------------------------------------------- + * VMSetPitchBendRange() + *---------------------------------------------------------------------------- + * Set the pitch bend range for the given channel. + *---------------------------------------------------------------------------- +*/ +void VMSetPitchBendRange (S_SYNTH *pSynth, EAS_INT channel, EAS_I16 pitchBendRange); + +/*---------------------------------------------------------------------------- + * VMSetEASLib() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the pointer to the sound library + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMSetGlobalEASLib (S_VOICE_MGR *pVoiceMgr, EAS_SNDLIB_HANDLE pEAS); +EAS_RESULT VMSetEASLib (S_SYNTH *pSynth, EAS_SNDLIB_HANDLE pEAS); + +#ifdef DLS_SYNTHESIZER +/*---------------------------------------------------------------------------- + * VMSetDLSLib() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the pointer to the sound library + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMSetGlobalDLSLib (EAS_DATA_HANDLE pEASData, EAS_DLSLIB_HANDLE pDLS); +EAS_RESULT VMSetDLSLib (S_SYNTH *pSynth, EAS_DLSLIB_HANDLE pDLS); +#endif + +/*---------------------------------------------------------------------------- + * VMSetTranposition() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the global key transposition used by the synthesizer. + * Transposes all melodic instruments up or down by the specified + * amount. Range is limited to +/-12 semitones. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * transposition - transpose amount (+/-12) + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMSetTranposition (S_SYNTH *pSynth, EAS_I32 transposition); + +/*---------------------------------------------------------------------------- + * VMGetTranposition() + *---------------------------------------------------------------------------- + * Purpose: + * Gets the global key transposition used by the synthesizer. + * Transposes all melodic instruments up or down by the specified + * amount. Range is limited to +/-12 semitones. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMGetTranposition (S_SYNTH *pSynth, EAS_I32 *pTransposition); + +/*---------------------------------------------------------------------------- + * VMGetNoteCount() + *---------------------------------------------------------------------------- +* Returns the total note count +*---------------------------------------------------------------------------- +*/ +EAS_I32 VMGetNoteCount (S_SYNTH *pSynth); + +/*---------------------------------------------------------------------------- + * VMRender() + *---------------------------------------------------------------------------- + * Purpose: + * This routine renders a frame of audio + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * pVoicesRendered - number of voices rendered this frame + * + * Side Effects: + * sets psMidiObject->m_nMaxWorkloadPerFrame + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMRender (S_VOICE_MGR *pVoiceMgr, EAS_I32 numSamples, EAS_I32 *pMixBuffer, EAS_I32 *pVoicesRendered); + +/*---------------------------------------------------------------------------- + * VMInitWorkload() + *---------------------------------------------------------------------------- + * Purpose: + * Clears the workload counter + * + * Inputs: + * pVoiceMgr - pointer to instance data + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMInitWorkload (S_VOICE_MGR *pVoiceMgr); + +/*---------------------------------------------------------------------------- + * VMSetWorkload() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the max workload for a single frame. + * + * Inputs: + * pVoiceMgr - pointer to instance data + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMSetWorkload (S_VOICE_MGR *pVoiceMgr, EAS_I32 maxWorkLoad); + +/*---------------------------------------------------------------------------- + * VMCheckWorkload() + *---------------------------------------------------------------------------- + * Purpose: + * Checks to see if work load has been exceeded on this frame. + * + * Inputs: + * pVoiceMgr - pointer to instance data + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_BOOL VMCheckWorkload (S_VOICE_MGR *pVoiceMgr); + +/*---------------------------------------------------------------------------- + * VMActiveVoices() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the number of active voices in the synthesizer. + * + * Inputs: + * pEASData - pointer to instance data + * + * Outputs: + * Returns the number of active voices + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_I32 VMActiveVoices (S_SYNTH *pSynth); + +/*---------------------------------------------------------------------------- + * VMMIDIShutdown() + *---------------------------------------------------------------------------- + * Purpose: + * Clean up any Synth related system issues. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * None + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMMIDIShutdown (S_EAS_DATA *pEASData, S_SYNTH *pSynth); + +/*---------------------------------------------------------------------------- + * VMShutdown() + *---------------------------------------------------------------------------- + * Purpose: + * Clean up any Synth related system issues. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * None + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMShutdown (S_EAS_DATA *pEASData); + +#ifdef EXTERNAL_AUDIO +/*---------------------------------------------------------------------------- + * EAS_RegExtAudioCallback() + *---------------------------------------------------------------------------- + * Register a callback for external audio processing + *---------------------------------------------------------------------------- +*/ +void VMRegExtAudioCallback (S_SYNTH *pSynth, EAS_VOID_PTR pInstData, EAS_EXT_PRG_CHG_FUNC cbProgChgFunc, EAS_EXT_EVENT_FUNC cbEventFunc); + +/*---------------------------------------------------------------------------- + * VMGetMIDIControllers() + *---------------------------------------------------------------------------- + * Returns the MIDI controller values on the specified channel + *---------------------------------------------------------------------------- +*/ +void VMGetMIDIControllers (S_SYNTH *pSynth, EAS_U8 channel, S_MIDI_CONTROLLERS *pControl); +#endif + +#ifdef _SPLIT_ARCHITECTURE +/*---------------------------------------------------------------------------- + * VMStartFrame() + *---------------------------------------------------------------------------- + * Purpose: + * Starts an audio frame + * + * Inputs: + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_BOOL VMStartFrame (S_EAS_DATA *pEASData); + +/*---------------------------------------------------------------------------- + * VMEndFrame() + *---------------------------------------------------------------------------- + * Purpose: + * Stops an audio frame + * + * Inputs: + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_BOOL VMEndFrame (S_EAS_DATA *pEASData); +#endif + +#endif /* #ifdef _EAS_VM_PROTOS_H */ + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_voicemgt.c b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_voicemgt.c new file mode 100755 index 0000000..ab0b776 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_voicemgt.c @@ -0,0 +1,3971 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_voicemgt.c + * + * Contents and purpose: + * Implements the synthesizer functions. + * + * Copyright Sonic Network Inc. 2004 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 794 $ + * $Date: 2007-08-01 00:08:48 -0700 (Wed, 01 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +/* includes */ +#include "eas.h" +#include "eas_data.h" +#include "eas_config.h" +#include "eas_report.h" +#include "eas_midictrl.h" +#include "eas_host.h" +#include "eas_synth_protos.h" +#include "eas_vm_protos.h" + +#ifdef DLS_SYNTHESIZER +#include "eas_mdls.h" +#endif + +// #define _DEBUG_VM + +/* some defines for workload */ +#define WORKLOAD_AMOUNT_SMALL_INCREMENT 5 +#define WORKLOAD_AMOUNT_START_NOTE 10 +#define WORKLOAD_AMOUNT_STOP_NOTE 10 +#define WORKLOAD_AMOUNT_KEY_GROUP 10 +#define WORKLOAD_AMOUNT_POLY_LIMIT 10 + +/* pointer to base sound library */ +extern S_EAS easSoundLib; + +#ifdef TEST_HARNESS +extern S_EAS easTestLib; +EAS_SNDLIB_HANDLE VMGetLibHandle(EAS_INT libNum) +{ + switch (libNum) + { + case 0: + return &easSoundLib; +#ifdef _WT_SYNTH + case 1: + return &easTestLib; +#endif + default: + return NULL; + } +} +#endif + +/* pointer to synthesizer interface(s) */ +#ifdef _WT_SYNTH +extern const S_SYNTH_INTERFACE wtSynth; +#endif + +#ifdef _FM_SYNTH +extern const S_SYNTH_INTERFACE fmSynth; +#endif + +typedef S_SYNTH_INTERFACE *S_SYNTH_INTERFACE_HANDLE; + +/* wavetable on MCU */ +#if defined(EAS_WT_SYNTH) +const S_SYNTH_INTERFACE *const pPrimarySynth = &wtSynth; + +/* FM on MCU */ +#elif defined(EAS_FM_SYNTH) +const S_SYNTH_INTERFACE *const pPrimarySynth = &fmSynth; + +/* wavetable drums on MCU, FM melodic on DSP */ +#elif defined(EAS_HYBRID_SYNTH) +const S_SYNTH_INTERFACE *const pPrimarySynth = &wtSynth; +const S_SYNTH_INTERFACE *const pSecondarySynth = &fmSynth; + +/* wavetable drums on MCU, wavetable melodic on DSP */ +#elif defined(EAS_SPLIT_WT_SYNTH) +const S_SYNTH_INTERFACE *const pPrimarySynth = &wtSynth; +extern const S_FRAME_INTERFACE wtFrameInterface; +const S_FRAME_INTERFACE *const pFrameInterface = &wtFrameInterface; + +/* wavetable drums on MCU, FM melodic on DSP */ +#elif defined(EAS_SPLIT_HYBRID_SYNTH) +const S_SYNTH_INTERFACE *const pPrimarySynth = &wtSynth; +const S_SYNTH_INTERFACE *const pSecondarySynth = &fmSynth; +extern const S_FRAME_INTERFACE fmFrameInterface; +const S_FRAME_INTERFACE *const pFrameInterface = &fmFrameInterface; + +/* FM on DSP */ +#elif defined(EAS_SPLIT_FM_SYNTH) +const S_SYNTH_INTERFACE *const pPrimarySynth = &fmSynth; +extern const S_FRAME_INTERFACE fmFrameInterface; +const S_FRAME_INTERFACE *const pFrameInterface = &fmFrameInterface; + +#else +#error "Undefined architecture option" +#endif + +/*---------------------------------------------------------------------------- + * inline functions + *---------------------------------------------------------------------------- +*/ +EAS_INLINE const S_REGION* GetRegionPtr (S_SYNTH *pSynth, EAS_U16 regionIndex) +{ +#if defined(DLS_SYNTHESIZER) + if (regionIndex & FLAG_RGN_IDX_DLS_SYNTH) + return &pSynth->pDLS->pDLSRegions[regionIndex & REGION_INDEX_MASK].wtRegion.region; +#endif +#if defined(_HYBRID_SYNTH) + if (regionIndex & FLAG_RGN_IDX_FM_SYNTH) + return &pSynth->pEAS->pFMRegions[regionIndex & REGION_INDEX_MASK].region; + else + return &pSynth->pEAS->pWTRegions[regionIndex].region; +#elif defined(_WT_SYNTH) + return &pSynth->pEAS->pWTRegions[regionIndex].region; +#elif defined(_FM_SYNTH) + return &pSynth->pEAS->pFMRegions[regionIndex].region; +#endif +} + +/*lint -esym(715, voiceNum) used in some implementation */ +EAS_INLINE const S_SYNTH_INTERFACE* GetSynthPtr (EAS_INT voiceNum) +{ +#if defined(_HYBRID_SYNTH) + if (voiceNum < NUM_PRIMARY_VOICES) + return pPrimarySynth; + else + return pSecondarySynth; +#else + return pPrimarySynth; +#endif +} + +EAS_INLINE EAS_INT GetAdjustedVoiceNum (EAS_INT voiceNum) +{ +#if defined(_HYBRID_SYNTH) + if (voiceNum >= NUM_PRIMARY_VOICES) + return voiceNum - NUM_PRIMARY_VOICES; +#endif + return voiceNum; +} + +EAS_INLINE EAS_U8 VSynthToChannel (S_SYNTH *pSynth, EAS_U8 channel) +{ + /*lint -e{734} synthNum is always 0-15 */ + return channel | (pSynth->vSynthNum << 4); +} + +/*---------------------------------------------------------------------------- + * InitVoice() + *---------------------------------------------------------------------------- + * Initialize a synthesizer voice + *---------------------------------------------------------------------------- +*/ +void InitVoice (S_SYNTH_VOICE *pVoice) +{ + pVoice->channel = UNASSIGNED_SYNTH_CHANNEL; + pVoice->nextChannel = UNASSIGNED_SYNTH_CHANNEL; + pVoice->note = pVoice->nextNote = DEFAULT_KEY_NUMBER; + pVoice->velocity = pVoice->nextVelocity = DEFAULT_VELOCITY; + pVoice->regionIndex = DEFAULT_REGION_INDEX; + pVoice->age = DEFAULT_AGE; + pVoice->voiceFlags = DEFAULT_VOICE_FLAGS; + pVoice->voiceState = DEFAULT_VOICE_STATE; +} + +/*---------------------------------------------------------------------------- + * IncVoicePoolCount() + *---------------------------------------------------------------------------- + * Updates the voice pool count when a voice changes state + *---------------------------------------------------------------------------- +*/ +static void IncVoicePoolCount (S_VOICE_MGR *pVoiceMgr, S_SYNTH_VOICE *pVoice) +{ + S_SYNTH *pSynth; + EAS_INT pool; + + /* ignore muting voices */ + if (pVoice->voiceState == eVoiceStateMuting) + return; + + if (pVoice->voiceState == eVoiceStateStolen) + { + pSynth = pVoiceMgr->pSynth[GET_VSYNTH(pVoice->nextChannel)]; + pool = pSynth->channels[GET_CHANNEL(pVoice->nextChannel)].pool; + } + else + { + pSynth = pVoiceMgr->pSynth[GET_VSYNTH(pVoice->channel)]; + pool = pSynth->channels[GET_CHANNEL(pVoice->channel)].pool; + } + + pSynth->poolCount[pool]++; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IncVoicePoolCount: Synth=%d pool=%d\n", pSynth->vSynthNum, pool); */ } +#endif +} + +/*---------------------------------------------------------------------------- + * DecVoicePoolCount() + *---------------------------------------------------------------------------- + * Updates the voice pool count when a voice changes state + *---------------------------------------------------------------------------- +*/ +static void DecVoicePoolCount (S_VOICE_MGR *pVoiceMgr, S_SYNTH_VOICE *pVoice) +{ + S_SYNTH *pSynth; + EAS_INT pool; + + /* ignore muting voices */ + if (pVoice->voiceState == eVoiceStateMuting) + return; + + if (pVoice->voiceState == eVoiceStateStolen) + { + pSynth = pVoiceMgr->pSynth[GET_VSYNTH(pVoice->nextChannel)]; + pool = pSynth->channels[GET_CHANNEL(pVoice->nextChannel)].pool; + } + else + { + pSynth = pVoiceMgr->pSynth[GET_VSYNTH(pVoice->channel)]; + pool = pSynth->channels[GET_CHANNEL(pVoice->channel)].pool; + } + + pSynth->poolCount[pool]--; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "DecVoicePoolCount: Synth=%d pool=%d\n", pSynth->vSynthNum, pool); */ } +#endif +} + +/*---------------------------------------------------------------------------- + * VMInitialize() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMInitialize (S_EAS_DATA *pEASData) +{ + S_VOICE_MGR *pVoiceMgr; + EAS_INT i; + + /* check Configuration Module for data allocation */ + if (pEASData->staticMemoryModel) + pVoiceMgr = EAS_CMEnumData(EAS_CM_SYNTH_DATA); + else + pVoiceMgr = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_VOICE_MGR)); + if (!pVoiceMgr) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitialize: Failed to allocate synthesizer memory\n"); */ } + return EAS_ERROR_MALLOC_FAILED; + } + EAS_HWMemSet(pVoiceMgr, 0, sizeof(S_VOICE_MGR)); + + /* initialize non-zero variables */ + pVoiceMgr->pGlobalEAS = (S_EAS*) &easSoundLib; + pVoiceMgr->maxPolyphony = (EAS_U16) MAX_SYNTH_VOICES; + +#if defined(_SECONDARY_SYNTH) || defined(EAS_SPLIT_WT_SYNTH) + pVoiceMgr->maxPolyphonyPrimary = NUM_PRIMARY_VOICES; + pVoiceMgr->maxPolyphonySecondary = NUM_SECONDARY_VOICES; +#endif + + /* set max workload to zero */ + pVoiceMgr->maxWorkLoad = 0; + + /* initialize the voice manager parameters */ + for (i = 0; i < MAX_SYNTH_VOICES; i++) + InitVoice(&pVoiceMgr->voices[i]); + + /* initialize the synth */ + /*lint -e{522} return unused at this time */ + pPrimarySynth->pfInitialize(pVoiceMgr); + + /* initialize the off-chip synth */ +#ifdef _HYBRID_SYNTH + /*lint -e{522} return unused at this time */ + pSecondarySynth->pfInitialize(pVoiceMgr); +#endif + + pEASData->pVoiceMgr = pVoiceMgr; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMInitMIDI() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMInitMIDI (S_EAS_DATA *pEASData, S_SYNTH **ppSynth) +{ + EAS_RESULT result; + S_SYNTH *pSynth; + EAS_INT virtualSynthNum; + + *ppSynth = NULL; + + /* static memory model only allows one synth */ + if (pEASData->staticMemoryModel) + { + if (pEASData->pVoiceMgr->pSynth[0] != NULL) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitMIDI: No virtual synthesizer support for static memory model\n"); */ } + return EAS_ERROR_NO_VIRTUAL_SYNTHESIZER; + } + + /* check Configuration Module for data allocation */ + pSynth = EAS_CMEnumData(EAS_CM_MIDI_DATA); + virtualSynthNum = 0; + } + + /* dynamic memory model */ + else + { + for (virtualSynthNum = 0; virtualSynthNum < MAX_VIRTUAL_SYNTHESIZERS; virtualSynthNum++) + if (pEASData->pVoiceMgr->pSynth[virtualSynthNum] == NULL) + break; + if (virtualSynthNum == MAX_VIRTUAL_SYNTHESIZERS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitMIDI: Exceeded number of active virtual synthesizers"); */ } + return EAS_ERROR_NO_VIRTUAL_SYNTHESIZER; + } + pSynth = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_SYNTH)); + } + + /* make sure we have a valid memory pointer */ + if (pSynth == NULL) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitMIDI: Failed to allocate synthesizer memory\n"); */ } + return EAS_ERROR_MALLOC_FAILED; + } + EAS_HWMemSet(pSynth, 0, sizeof(S_SYNTH)); + + /* set the sound library pointer */ + if ((result = VMSetEASLib(pSynth, pEASData->pVoiceMgr->pGlobalEAS)) != EAS_SUCCESS) + { + VMMIDIShutdown(pEASData, pSynth); + return result; + } + + /* link in DLS bank if downloaded */ +#ifdef DLS_SYNTHESIZER + if (pEASData->pVoiceMgr->pGlobalDLS) + { + pSynth->pDLS = pEASData->pVoiceMgr->pGlobalDLS; + DLSAddRef(pSynth->pDLS); + } +#endif + + /* initialize MIDI state variables */ + pSynth->synthFlags = DEFAULT_SYNTH_FLAGS; + pSynth->masterVolume = DEFAULT_SYNTH_MASTER_VOLUME; + pSynth->refCount = 1; + pSynth->priority = DEFAULT_SYNTH_PRIORITY; + pSynth->poolAlloc[0] = (EAS_U8) pEASData->pVoiceMgr->maxPolyphony; + + VMInitializeAllChannels(pEASData->pVoiceMgr, pSynth); + + pSynth->vSynthNum = (EAS_U8) virtualSynthNum; + pEASData->pVoiceMgr->pSynth[virtualSynthNum] = pSynth; + + *ppSynth = pSynth; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMIncRefCount() + *---------------------------------------------------------------------------- + * Increment reference count for virtual synth + *---------------------------------------------------------------------------- +*/ +void VMIncRefCount (S_SYNTH *pSynth) +{ + pSynth->refCount++; +} + +/*---------------------------------------------------------------------------- + * VMReset() + *---------------------------------------------------------------------------- + * Purpose: + * We call this routine to start the process of reseting the synth. + * This routine sets a flag for the entire synth indicating that we want + * to reset. + * We also force all voices to mute quickly. + * However, we do not actually perform any synthesis in this routine. That + * is, we do not ramp the voices down from this routine, but instead, we + * let the "regular" synth processing steps take care of adding the ramp + * down samples to the output buffer. After we are sure that all voices + * have completed ramping down, we continue the process of resetting the + * synth (from another routine). + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * force - force reset even if voices are active + * + * Outputs: + * + * Side Effects: + * - set a flag (in psSynthObject->m_nFlags) indicating synth reset requested. + * - force all voices to update their envelope states to mute + * + *---------------------------------------------------------------------------- +*/ +void VMReset (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_BOOL force) +{ + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMReset: request to reset synth. Force = %d\n", force); */ } +#endif + + /* force voices to off state - may cause audio artifacts */ + if (force) + { + pVoiceMgr->activeVoices -= pSynth->numActiveVoices; + pSynth->numActiveVoices = 0; + VMInitializeAllVoices(pVoiceMgr, pSynth->vSynthNum); + } + else + VMMuteAllVoices(pVoiceMgr, pSynth); + + /* don't reset if voices are still playing */ + if (pSynth->numActiveVoices == 0) + { + EAS_INT i; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMReset: complete the reset process\n"); */ } +#endif + + VMInitializeAllChannels(pVoiceMgr, pSynth); + for (i = 0; i < NUM_SYNTH_CHANNELS; i++) + pSynth->poolCount[i] = 0; + + /* set polyphony */ + if (pSynth->maxPolyphony < pVoiceMgr->maxPolyphony) + pSynth->poolAlloc[0] = (EAS_U8) pVoiceMgr->maxPolyphony; + else + pSynth->poolAlloc[0] = (EAS_U8) pSynth->maxPolyphony; + + /* clear reset flag */ + pSynth->synthFlags &= ~SYNTH_FLAG_RESET_IS_REQUESTED; + } + + /* handle reset after voices are muted */ + else + pSynth->synthFlags |= SYNTH_FLAG_RESET_IS_REQUESTED; +} + +/*---------------------------------------------------------------------------- + * VMInitializeAllChannels() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +void VMInitializeAllChannels (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth) +{ + S_SYNTH_CHANNEL *pChannel; + EAS_INT i; + + VMResetControllers(pSynth); + + /* init each channel */ + pChannel = pSynth->channels; + + for (i = 0; i < NUM_SYNTH_CHANNELS; i++, pChannel++) + { + pChannel->channelFlags = DEFAULT_CHANNEL_FLAGS; + pChannel->staticGain = DEFAULT_CHANNEL_STATIC_GAIN; + pChannel->staticPitch = DEFAULT_CHANNEL_STATIC_PITCH; + pChannel->pool = 0; + + /* the drum channel needs a different init */ + if (i == DEFAULT_DRUM_CHANNEL) + { + pChannel->bankNum = DEFAULT_RHYTHM_BANK_NUMBER; + pChannel->channelFlags |= CHANNEL_FLAG_RHYTHM_CHANNEL; + } + else + pChannel->bankNum = DEFAULT_MELODY_BANK_NUMBER; + + VMProgramChange(pVoiceMgr, pSynth, (EAS_U8) i, DEFAULT_SYNTH_PROGRAM_NUMBER); + } + +} + +/*---------------------------------------------------------------------------- + * VMResetControllers() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +void VMResetControllers (S_SYNTH *pSynth) +{ + S_SYNTH_CHANNEL *pChannel; + EAS_INT i; + + pChannel = pSynth->channels; + + for (i = 0; i < NUM_SYNTH_CHANNELS; i++, pChannel++) + { + pChannel->pitchBend = DEFAULT_PITCH_BEND; + pChannel->modWheel = DEFAULT_MOD_WHEEL; + pChannel->volume = DEFAULT_CHANNEL_VOLUME; + pChannel->pan = DEFAULT_PAN; + pChannel->expression = DEFAULT_EXPRESSION; + +#ifdef _REVERB + pSynth->channels[i].reverbSend = DEFAULT_REVERB_SEND; +#endif + +#ifdef _CHORUS + pSynth->channels[i].chorusSend = DEFAULT_CHORUS_SEND; +#endif + + pChannel->channelPressure = DEFAULT_CHANNEL_PRESSURE; + pChannel->registeredParam = DEFAULT_REGISTERED_PARAM; + pChannel->pitchBendSensitivity = DEFAULT_PITCH_BEND_SENSITIVITY; + pChannel->finePitch = DEFAULT_FINE_PITCH; + pChannel->coarsePitch = DEFAULT_COARSE_PITCH; + + /* update all voices on this channel */ + pChannel->channelFlags |= CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS; + } +} + +/*---------------------------------------------------------------------------- + * VMInitializeAllVoices() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +void VMInitializeAllVoices (S_VOICE_MGR *pVoiceMgr, EAS_INT vSynthNum) +{ + EAS_INT i; + + /* initialize the voice manager parameters */ + for (i = 0; i < MAX_SYNTH_VOICES; i++) + { + if (pVoiceMgr->voices[i].voiceState != eVoiceStateStolen) + { + if (GET_VSYNTH(pVoiceMgr->voices[i].channel) == vSynthNum) + InitVoice(&pVoiceMgr->voices[i]); + } + else + { + if (GET_VSYNTH(pVoiceMgr->voices[i].nextChannel) == vSynthNum) + InitVoice(&pVoiceMgr->voices[i]); + } + } +} + +/*---------------------------------------------------------------------------- + * VMMuteVoice() + *---------------------------------------------------------------------------- + * Mute the selected voice + *---------------------------------------------------------------------------- +*/ +void VMMuteVoice (S_VOICE_MGR *pVoiceMgr, EAS_I32 voiceNum) +{ + S_SYNTH *pSynth; + S_SYNTH_VOICE *pVoice; + + /* take no action if voice is already muted */ + pVoice = &pVoiceMgr->voices[voiceNum]; + if ((pVoice->voiceState == eVoiceStateMuting) || (pVoice->voiceState == eVoiceStateFree)) + return; + + /* one less voice in pool */ + DecVoicePoolCount(pVoiceMgr, pVoice); + + pSynth = pVoiceMgr->pSynth[GET_VSYNTH(pVoice->channel)]; + GetSynthPtr(voiceNum)->pfMuteVoice(pVoiceMgr, pSynth, pVoice, GetAdjustedVoiceNum(voiceNum)); + pVoice->voiceState = eVoiceStateMuting; + +} + +/*---------------------------------------------------------------------------- + * VMReleaseVoice() + *---------------------------------------------------------------------------- + * Release the selected voice + *---------------------------------------------------------------------------- +*/ +void VMReleaseVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 voiceNum) +{ + S_SYNTH_VOICE *pVoice = &pVoiceMgr->voices[voiceNum]; + + /* take no action if voice is already free, muting, or releasing */ + if (( pVoice->voiceState == eVoiceStateMuting) || + (pVoice->voiceState == eVoiceStateFree) || + (pVoice->voiceState == eVoiceStateRelease)) + return; + + /* stolen voices should just be muted */ + if (pVoice->voiceState == eVoiceStateStolen) + VMMuteVoice(pVoiceMgr, voiceNum); + + /* release this voice */ + GetSynthPtr(voiceNum)->pfReleaseVoice(pVoiceMgr, pSynth, &pVoiceMgr->voices[voiceNum], GetAdjustedVoiceNum(voiceNum)); + pVoice->voiceState = eVoiceStateRelease; +} + +/*---------------------------------------------------------------------------- + * VMInitMIPTable() + *---------------------------------------------------------------------------- + * Initialize the SP-MIDI MIP table in preparation for receiving MIP message + *---------------------------------------------------------------------------- +*/ +void VMInitMIPTable (S_SYNTH *pSynth) +{ + EAS_INT i; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMInitMIPTable\n"); */ } +#endif + + /* clear SP-MIDI flag */ + pSynth->synthFlags &= ~SYNTH_FLAG_SP_MIDI_ON; + for (i = 0; i < NUM_SYNTH_CHANNELS; i++) + { + pSynth->channels[i].pool = 0; + pSynth->channels[i].mip = 0; + } +} + +/*---------------------------------------------------------------------------- + * VMSetMIPEntry() + *---------------------------------------------------------------------------- + * Sets the priority and MIP level for a MIDI channel + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pVoiceMgr) reserved for future use */ +void VMSetMIPEntry (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 priority, EAS_U8 mip) +{ + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMSetMIPEntry: channel=%d, priority=%d, MIP=%d\n", channel, priority, mip); */ } +#endif + + /* save data for use by MIP message processing */ + if (priority < NUM_SYNTH_CHANNELS) + { + pSynth->channels[channel].pool = priority; + pSynth->channels[channel].mip = mip; + } +} + +/*---------------------------------------------------------------------------- + * VMMIPUpdateChannelMuting() + *---------------------------------------------------------------------------- + * This routine is called after an SP-MIDI message is received and + * any time the allocated polyphony changes. It mutes or unmutes + * channels based on polyphony. + *---------------------------------------------------------------------------- +*/ +void VMMIPUpdateChannelMuting (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth) +{ + EAS_INT i; + EAS_INT maxPolyphony; + EAS_INT channel; + EAS_INT vSynthNum; + EAS_INT pool; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMUpdateMIPTable\n"); */ } +#endif + + /* determine max polyphony */ + if (pSynth->maxPolyphony) + maxPolyphony = pSynth->maxPolyphony; + else + maxPolyphony = pVoiceMgr->maxPolyphony; + + /* process channels */ + for (i = 0; i < NUM_SYNTH_CHANNELS; i++) + { + + /* channel must be in MIP message and must meet allocation target */ + if ((pSynth->channels[i].mip != 0) && (pSynth->channels[i].mip <= maxPolyphony)) + pSynth->channels[i].channelFlags &= ~CHANNEL_FLAG_MUTE; + else + pSynth->channels[i].channelFlags |= CHANNEL_FLAG_MUTE; + + /* reset voice pool count */ + pSynth->poolCount[i] = 0; + } + + /* mute any voices on muted channels, and count unmuted voices */ + for (i = 0; i < MAX_SYNTH_VOICES; i++) + { + + /* ignore free voices */ + if (pVoiceMgr->voices[i].voiceState == eVoiceStateFree) + continue; + + /* get channel and virtual synth */ + if (pVoiceMgr->voices[i].voiceState != eVoiceStateStolen) + { + vSynthNum = GET_VSYNTH(pVoiceMgr->voices[i].channel); + channel = GET_CHANNEL(pVoiceMgr->voices[i].channel); + } + else + { + vSynthNum = GET_VSYNTH(pVoiceMgr->voices[i].nextChannel); + channel = GET_CHANNEL(pVoiceMgr->voices[i].nextChannel); + } + + /* ignore voices on other synths */ + if (vSynthNum != pSynth->vSynthNum) + continue; + + /* count voices */ + pool = pSynth->channels[channel].pool; + + /* deal with muted channels */ + if (pSynth->channels[channel].channelFlags & CHANNEL_FLAG_MUTE) + { + /* mute stolen voices scheduled to play on this channel */ + if (pVoiceMgr->voices[i].voiceState == eVoiceStateStolen) + pVoiceMgr->voices[i].voiceState = eVoiceStateMuting; + + /* release voices that aren't already muting */ + else if (pVoiceMgr->voices[i].voiceState != eVoiceStateMuting) + { + VMReleaseVoice(pVoiceMgr, pSynth, i); + pSynth->poolCount[pool]++; + } + } + + /* not muted, count this voice */ + else + pSynth->poolCount[pool]++; + } +} + +/*---------------------------------------------------------------------------- + * VMUpdateMIPTable() + *---------------------------------------------------------------------------- + * This routine is called at the end of the SysEx message to allow + * the Voice Manager to complete the initialization of the MIP + * table. It assigns channels to the appropriate voice pool based + * on the MIP setting and calculates the voices allocated for each + * pool. + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pVoiceMgr) reserved for future use */ +void VMUpdateMIPTable (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth) +{ + S_SYNTH_CHANNEL *pChannel; + EAS_INT i; + EAS_INT currentMIP; + EAS_INT currentPool; + EAS_INT priority[NUM_SYNTH_CHANNELS]; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMUpdateMIPTable\n"); */ } +#endif + + /* set SP-MIDI flag */ + pSynth->synthFlags |= SYNTH_FLAG_SP_MIDI_ON; + + /* sort channels into priority order */ + for (i = 0; i < NUM_SYNTH_CHANNELS; i++) + priority[i] = -1; + for (i = 0; i < NUM_SYNTH_CHANNELS; i++) + { + if (pSynth->channels[i].pool != DEFAULT_SP_MIDI_PRIORITY) + priority[pSynth->channels[i].pool] = i; + } + + /* process channels in priority order */ + currentMIP = 0; + currentPool = -1; + for (i = 0; i < NUM_SYNTH_CHANNELS; i++) + { + /* stop when we run out of channels */ + if (priority[i] == -1) + break; + + pChannel = &pSynth->channels[priority[i]]; + + /* when 2 or more channels have the same MIP setting, they + * share a common voice pool + */ + if (pChannel->mip == currentMIP) + pChannel->pool = (EAS_U8) currentPool; + + /* new voice pool */ + else + { + currentPool++; + pSynth->poolAlloc[currentPool] = (EAS_U8) (pChannel->mip - currentMIP); + currentMIP = pChannel->mip; + } + } + + /* set SP-MIDI flag */ + pSynth->synthFlags |= SYNTH_FLAG_SP_MIDI_ON; + + /* update channel muting */ + VMMIPUpdateChannelMuting (pVoiceMgr, pSynth); +} + +/*---------------------------------------------------------------------------- + * VMMuteAllVoices() + *---------------------------------------------------------------------------- + * Purpose: + * We call this in an emergency reset situation. + * This forces all voices to mute quickly. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * - forces all voices to update their envelope states to mute + * + *---------------------------------------------------------------------------- +*/ +void VMMuteAllVoices (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth) +{ + EAS_INT i; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMMuteAllVoices: about to mute all voices!!\n"); */ } +#endif + + for (i = 0; i < MAX_SYNTH_VOICES; i++) + { + /* for stolen voices, check new channel */ + if (pVoiceMgr->voices[i].voiceState == eVoiceStateStolen) + { + if (GET_VSYNTH(pVoiceMgr->voices[i].nextChannel) == pSynth->vSynthNum) + VMMuteVoice(pVoiceMgr, i); + } + + else if (pSynth->vSynthNum == GET_VSYNTH(pVoiceMgr->voices[i].channel)) + VMMuteVoice(pVoiceMgr, i); + } +} + +/*---------------------------------------------------------------------------- + * VMReleaseAllVoices() + *---------------------------------------------------------------------------- + * Purpose: + * We call this after we've encountered the end of the Midi file. + * This ensures all voices are either in release (because we received their + * note off already) or forces them to mute quickly. + * We use this as a safety to prevent bad midi files from playing forever. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * - forces all voices to update their envelope states to release or mute + * + *---------------------------------------------------------------------------- +*/ +void VMReleaseAllVoices (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth) +{ + EAS_INT i; + + /* release sustain pedal on all channels */ + for (i = 0; i < NUM_SYNTH_CHANNELS; i++) + { + if (pSynth->channels[ i ].channelFlags & CHANNEL_FLAG_SUSTAIN_PEDAL) + { + VMReleaseAllDeferredNoteOffs(pVoiceMgr, pSynth, (EAS_U8) i); + pSynth->channels[i].channelFlags &= ~CHANNEL_FLAG_SUSTAIN_PEDAL; + } + } + + /* release all voices */ + for (i = 0; i < MAX_SYNTH_VOICES; i++) + { + + switch (pVoiceMgr->voices[i].voiceState) + { + case eVoiceStateStart: + case eVoiceStatePlay: + /* only release voices on this synth */ + if (GET_VSYNTH(pVoiceMgr->voices[i].channel) == pSynth->vSynthNum) + VMReleaseVoice(pVoiceMgr, pSynth, i); + break; + + case eVoiceStateStolen: + if (GET_VSYNTH(pVoiceMgr->voices[i].nextChannel) == pSynth->vSynthNum) + VMMuteVoice(pVoiceMgr, i); + break; + + case eVoiceStateFree: + case eVoiceStateRelease: + case eVoiceStateMuting: + break; + + case eVoiceStateInvalid: + default: +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMReleaseAllVoices: error, %d is an unrecognized state\n", + pVoiceMgr->voices[i].voiceState); */ } +#endif + break; + } + } +} + +/*---------------------------------------------------------------------------- + * VMAllNotesOff() + *---------------------------------------------------------------------------- + * Purpose: + * Quickly mute all notes on the given channel. + * + * Inputs: + * nChannel - quickly turn off all notes on this channel + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * - forces all voices on this channel to update their envelope states to mute + * + *---------------------------------------------------------------------------- +*/ +void VMAllNotesOff (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel) +{ + EAS_INT voiceNum; + S_SYNTH_VOICE *pVoice; + +#ifdef _DEBUG_VM + if (channel >= NUM_SYNTH_CHANNELS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMAllNotesOff: error, %d invalid channel number\n", + channel); */ } + return; + } +#endif + + /* increment workload */ + pVoiceMgr->workload += WORKLOAD_AMOUNT_SMALL_INCREMENT; + + /* check each voice */ + channel = VSynthToChannel(pSynth, channel); + for (voiceNum = 0; voiceNum < MAX_SYNTH_VOICES; voiceNum++) + { + pVoice = &pVoiceMgr->voices[voiceNum]; + if (pVoice->voiceState != eVoiceStateFree) + { + if (((pVoice->voiceState != eVoiceStateStolen) && (channel == pVoice->channel)) || + ((pVoice->voiceState == eVoiceStateStolen) && (channel == pVoice->nextChannel))) + { + /* this voice is assigned to the requested channel */ + GetSynthPtr(voiceNum)->pfMuteVoice(pVoiceMgr, pSynth, pVoice, GetAdjustedVoiceNum(voiceNum)); + pVoice->voiceState = eVoiceStateMuting; + } + } + } +} + +/*---------------------------------------------------------------------------- + * VMDeferredStopNote() + *---------------------------------------------------------------------------- + * Purpose: + * Stop the notes that had deferred note-off requests. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * None. + * + * Side Effects: + * voices that have had deferred note-off requests are now put into release + * psSynthObject->m_sVoice[i].m_nFlags has the VOICE_FLAG_DEFER_MIDI_NOTE_OFF + * cleared + *---------------------------------------------------------------------------- +*/ +void VMDeferredStopNote (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth) +{ + EAS_INT voiceNum; + EAS_INT channel; + EAS_BOOL deferredNoteOff; + + deferredNoteOff = EAS_FALSE; + + /* check each voice to see if it requires a deferred note off */ + for (voiceNum=0; voiceNum < MAX_SYNTH_VOICES; voiceNum++) + { + if (pVoiceMgr->voices[voiceNum].voiceFlags & VOICE_FLAG_DEFER_MIDI_NOTE_OFF) + { + /* check if this voice was stolen */ + if (pVoiceMgr->voices[voiceNum].voiceState == eVoiceStateStolen) + { + /* + This voice was stolen, AND it also has a deferred note-off. + The stolen note must be completely ramped down at this point. + The note that caused the stealing to occur, however, must + have received a note-off request before the note that caused + stealing ever had a chance to even start. We want to give + the note that caused the stealing a chance to play, so we + start it on the next update interval, and we defer sending + the note-off request until the subsequent update interval. + So do not send the note-off request for this voice because + this voice was stolen and should have completed ramping down, + Also, do not clear the global flag nor this voice's flag + because we must indicate that the subsequent update interval, + after the note that caused stealing has started, should + then send the deferred note-off request. + */ + deferredNoteOff = EAS_TRUE; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMDeferredStopNote: defer request to stop voice %d (channel=%d note=%d) - voice not started\n", + voiceNum, + pVoiceMgr->voices[voiceNum].nextChannel, + pVoiceMgr->voices[voiceNum].note); */ } + + /* sanity check: this stolen voice better be ramped to zero */ + if (0 != pVoiceMgr->voices[voiceNum].gain) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMDeferredStopNote: warning, this voice did not complete its ramp to zero\n"); */ } + } +#endif // #ifdef _DEBUG_VM + + } + else + { + /* clear the flag using exor */ + pVoiceMgr->voices[voiceNum].voiceFlags ^= + VOICE_FLAG_DEFER_MIDI_NOTE_OFF; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMDeferredStopNote: Stop voice %d (channel=%d note=%d)\n", + voiceNum, + pVoiceMgr->voices[voiceNum].nextChannel, + pVoiceMgr->voices[voiceNum].note); */ } +#endif + + channel = pVoiceMgr->voices[voiceNum].channel & 15; + + /* check if sustain pedal is on */ + if (pSynth->channels[channel].channelFlags & CHANNEL_FLAG_SUSTAIN_PEDAL) + { + GetSynthPtr(voiceNum)->pfSustainPedal(pVoiceMgr, pSynth, &pVoiceMgr->voices[voiceNum], &pSynth->channels[channel], GetAdjustedVoiceNum(voiceNum)); + } + + /* release this voice */ + else + VMReleaseVoice(pVoiceMgr, pSynth, voiceNum); + + } + + } + + } + + /* clear the deferred note-off flag, unless there's another one pending */ + if (deferredNoteOff == EAS_FALSE) + pSynth->synthFlags ^= SYNTH_FLAG_DEFERRED_MIDI_NOTE_OFF_PENDING; +} + +/*---------------------------------------------------------------------------- + * VMReleaseAllDeferredNoteOffs() + *---------------------------------------------------------------------------- + * Purpose: + * Call this functin when the sustain flag is presently set but + * we are now transitioning from damper pedal on to + * damper pedal off. This means all notes in this channel + * that received a note off while the damper pedal was on, and + * had their note-off requests deferred, should now proceed to + * the release state. + * + * Inputs: + * nChannel - this channel has its sustain pedal transitioning from on to off + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * Side Effects: + * any voice with deferred note offs on this channel are updated such that + * pVoice->m_sEG1.m_eState = eEnvelopeStateRelease + * pVoice->m_sEG1.m_nIncrement = release increment + * pVoice->m_nFlags = clear the deferred note off flag + *---------------------------------------------------------------------------- +*/ +void VMReleaseAllDeferredNoteOffs (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel) +{ + S_SYNTH_VOICE *pVoice; + EAS_INT voiceNum; + +#ifdef _DEBUG_VM + if (channel >= NUM_SYNTH_CHANNELS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMReleaseAllDeferredNoteOffs: error, %d invalid channel number\n", + channel); */ } + return; + } +#endif /* #ifdef _DEBUG_VM */ + + /* increment workload */ + pVoiceMgr->workload += WORKLOAD_AMOUNT_SMALL_INCREMENT; + + /* find all the voices assigned to this channel */ + channel = VSynthToChannel(pSynth, channel); + for (voiceNum = 0; voiceNum < MAX_SYNTH_VOICES; voiceNum++) + { + + pVoice = &pVoiceMgr->voices[voiceNum]; + if (channel == pVoice->channel) + { + + /* does this voice have a deferred note off? */ + if (pVoice->voiceFlags & VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF) + { + /* release voice */ + VMReleaseVoice(pVoiceMgr, pSynth, voiceNum); + + /* use exor to flip bit, clear the flag */ + pVoice->voiceFlags &= ~VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF; + + } + + } + } + + return; +} + +/*---------------------------------------------------------------------------- + * VMCatchNotesForSustainPedal() + *---------------------------------------------------------------------------- + * Purpose: + * Call this function when the sustain flag is presently clear and + * the damper pedal is off and we are transitioning from damper pedal OFF to + * damper pedal ON. Currently sounding notes should be left + * unchanged. However, we should try to "catch" notes if possible. + * If any notes are in release and have levels >= sustain level, catch them, + * otherwise, let them continue to release. + * + * Inputs: + * nChannel - this channel has its sustain pedal transitioning from on to off + * psEASData - pointer to overall EAS data structure + * + * Outputs: + *---------------------------------------------------------------------------- +*/ +void VMCatchNotesForSustainPedal (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel) +{ + EAS_INT voiceNum; + +#ifdef _DEBUG_VM + if (channel >= NUM_SYNTH_CHANNELS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMCatchNotesForSustainPedal: error, %d invalid channel number\n", + channel); */ } + return; + } +#endif + + pVoiceMgr->workload += WORKLOAD_AMOUNT_SMALL_INCREMENT; + channel = VSynthToChannel(pSynth, channel); + + /* find all the voices assigned to this channel */ + for (voiceNum = 0; voiceNum < MAX_SYNTH_VOICES; voiceNum++) + { + if (channel == pVoiceMgr->voices[voiceNum].channel) + { + if (eVoiceStateRelease == pVoiceMgr->voices[voiceNum].voiceState) + GetSynthPtr(voiceNum)->pfSustainPedal(pVoiceMgr, pSynth, &pVoiceMgr->voices[voiceNum], &pSynth->channels[channel], GetAdjustedVoiceNum(voiceNum)); + } + } +} + +/*---------------------------------------------------------------------------- + * VMUpdateAllNotesAge() + *---------------------------------------------------------------------------- + * Purpose: + * Increment the note age for all of the active voices. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * m_nAge for all voices is incremented + *---------------------------------------------------------------------------- +*/ +void VMUpdateAllNotesAge (S_VOICE_MGR *pVoiceMgr, EAS_U16 age) +{ + EAS_INT i; + + for (i = 0; i < MAX_SYNTH_VOICES; i++) + { + if (age - pVoiceMgr->voices[i].age > 0) + pVoiceMgr->voices[i].age++; + } +} + +/*---------------------------------------------------------------------------- + * VMStolenVoice() + *---------------------------------------------------------------------------- + * Purpose: + * The selected voice is being stolen. Sets the parameters so that the + * voice will begin playing the new sound on the next buffer. + * + * Inputs: + * pVoice - pointer to voice to steal + * nChannel - the channel to start a note on + * nKeyNumber - the key number to start a note for + * nNoteVelocity - the key velocity from this note + * + * Outputs: + * None + *---------------------------------------------------------------------------- +*/ +static void VMStolenVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 voiceNum, EAS_U8 channel, EAS_U8 note, EAS_U8 velocity, EAS_U16 regionIndex) +{ + S_SYNTH_VOICE *pVoice = &pVoiceMgr->voices[voiceNum]; + + /* one less voice in old pool */ + DecVoicePoolCount(pVoiceMgr, pVoice); + + /* mute the sound that is currently playing */ + GetSynthPtr(voiceNum)->pfMuteVoice(pVoiceMgr, pVoiceMgr->pSynth[GET_VSYNTH(pVoice->channel)], &pVoiceMgr->voices[voiceNum], GetAdjustedVoiceNum(voiceNum)); + pVoice->voiceState = eVoiceStateStolen; + + /* set new note data */ + pVoice->nextChannel = VSynthToChannel(pSynth, channel); + pVoice->nextNote = note; + pVoice->nextVelocity = velocity; + pVoice->nextRegionIndex = regionIndex; + + /* one more voice in new pool */ + IncVoicePoolCount(pVoiceMgr, pVoice); + + /* clear the deferred flags */ + pVoice->voiceFlags &= + ~(VOICE_FLAG_DEFER_MIDI_NOTE_OFF | + VOICE_FLAG_DEFER_MUTE | + VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF); + + /* all notes older than this one get "younger" */ + VMUpdateAllNotesAge(pVoiceMgr, pVoice->age); + + /* assign current age to this note and increment for the next note */ + pVoice->age = pVoiceMgr->age++; +} + +/*---------------------------------------------------------------------------- + * VMFreeVoice() + *---------------------------------------------------------------------------- + * Purpose: + * The selected voice is done playing and being returned to the + * pool of free voices + * + * Inputs: + * pVoice - pointer to voice to free + * + * Outputs: + * None + *---------------------------------------------------------------------------- +*/ +static void VMFreeVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice) +{ + + /* do nothing if voice is already free */ + if (pVoice->voiceState == eVoiceStateFree) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "VMFreeVoice: Attempt to free voice that is already free\n"); */ } + return; + } + + /* if we jump directly to free without passing muting stage, + * we need to adjust the voice count */ + DecVoicePoolCount(pVoiceMgr, pVoice); + + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "VMFreeVoice: Synth=%d\n", pSynth->vSynthNum); */ } +#endif + + /* return to free voice pool */ + pVoiceMgr->activeVoices--; + pSynth->numActiveVoices--; + InitVoice(pVoice); + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMFreeVoice: free voice %d\n", pVoice - pVoiceMgr->voices); */ } +#endif + + /* all notes older than this one get "younger" */ + VMUpdateAllNotesAge(pVoiceMgr, pVoice->age); + } + +/*---------------------------------------------------------------------------- + * VMRetargetStolenVoice() + *---------------------------------------------------------------------------- + * Purpose: + * The selected voice has been stolen and needs to be initalized with + * the paramters of its new note. + * + * Inputs: + * pVoice - pointer to voice to retarget + * + * Outputs: + * None + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL VMRetargetStolenVoice (S_VOICE_MGR *pVoiceMgr, EAS_I32 voiceNum) +{ + EAS_U8 flags; + S_SYNTH_CHANNEL *pMIDIChannel; + S_SYNTH_VOICE *pVoice; + S_SYNTH *pSynth; + S_SYNTH *pNextSynth; + + /* establish some pointers */ + pVoice = &pVoiceMgr->voices[voiceNum]; + pSynth = pVoiceMgr->pSynth[GET_VSYNTH(pVoice->channel)]; + pMIDIChannel = &pSynth->channels[pVoice->channel & 15]; + pNextSynth = pVoiceMgr->pSynth[GET_VSYNTH(pVoice->nextChannel)]; + +#ifdef _DEBUG_VM +{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMRetargetStolenVoice: retargeting stolen voice %d on channel %d\n", + voiceNum, pVoice->channel); */ } + + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\to channel %d note: %d velocity: %d\n", + pVoice->nextChannel, pVoice->nextNote, pVoice->nextVelocity); */ } +#endif + + /* make sure new channel hasn't been muted by SP-MIDI since the voice was stolen */ + if ((pSynth->synthFlags & SYNTH_FLAG_SP_MIDI_ON) && + (pMIDIChannel->channelFlags & CHANNEL_FLAG_MUTE)) + { + VMFreeVoice(pVoiceMgr, pSynth, &pVoiceMgr->voices[voiceNum]); + return EAS_FALSE; + } + + /* if assigned to a new synth, correct the active voice count */ + if (pVoice->channel != pVoice->nextChannel) + { +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMRetargetStolenVoice: Note assigned to different virtual synth, adjusting numActiveVoices\n"); */ } +#endif + pSynth->numActiveVoices--; + pNextSynth->numActiveVoices++; + } + + /* assign new channel number, and increase channel voice count */ + pVoice->channel = pVoice->nextChannel; + pMIDIChannel = &pNextSynth->channels[pVoice->channel & 15]; + + /* assign other data */ + pVoice->note = pVoice->nextNote; + pVoice->velocity = pVoice->nextVelocity; + pVoice->nextChannel = UNASSIGNED_SYNTH_CHANNEL; + pVoice->regionIndex = pVoice->nextRegionIndex; + + /* save the flags, pfStartVoice() will clear them */ + flags = pVoice->voiceFlags; + + /* keep track of the note-start related workload */ + pVoiceMgr->workload += WORKLOAD_AMOUNT_START_NOTE; + + /* setup the voice parameters */ + pVoice->voiceState = eVoiceStateStart; + + /*lint -e{522} return not used at this time */ + GetSynthPtr(voiceNum)->pfStartVoice(pVoiceMgr, pNextSynth, &pVoiceMgr->voices[voiceNum], GetAdjustedVoiceNum(voiceNum), pVoice->regionIndex); + + /* did the new note already receive a MIDI note-off request? */ + if (flags & VOICE_FLAG_DEFER_MIDI_NOTE_OFF) + { +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMRetargetVoice: stolen note note-off request deferred\n"); */ } +#endif + pVoice->voiceFlags |= VOICE_FLAG_DEFER_MIDI_NOTE_OFF; + pNextSynth->synthFlags |= SYNTH_FLAG_DEFERRED_MIDI_NOTE_OFF_PENDING; + } + + return EAS_TRUE; +} + +/*---------------------------------------------------------------------------- + * VMCheckKeyGroup() + *---------------------------------------------------------------------------- + * If the note that we've been asked to start is in the same key group as + * any currently playing notes, then we must shut down the currently playing + * note in the same key group + *---------------------------------------------------------------------------- +*/ +void VMCheckKeyGroup (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U16 keyGroup, EAS_U8 channel) +{ + const S_REGION *pRegion; + EAS_INT voiceNum; + + /* increment frame workload */ + pVoiceMgr->workload += WORKLOAD_AMOUNT_KEY_GROUP; + + /* need to check all voices in case this is a layered sound */ + channel = VSynthToChannel(pSynth, channel); + for (voiceNum = 0; voiceNum < MAX_SYNTH_VOICES; voiceNum++) + { + if (pVoiceMgr->voices[voiceNum].voiceState != eVoiceStateStolen) + { + /* voice must be on the same channel */ + if (channel == pVoiceMgr->voices[voiceNum].channel) + { + /* check key group */ + pRegion = GetRegionPtr(pSynth, pVoiceMgr->voices[voiceNum].regionIndex); + if (keyGroup == (pRegion->keyGroupAndFlags & 0x0f00)) + { +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMCheckKeyGroup: voice %d matches key group %d\n", voiceNum, keyGroup >> 8); */ } +#endif + + /* if this voice was just started, set it to mute on the next buffer */ + if (pVoiceMgr->voices[voiceNum].voiceFlags & VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET) + pVoiceMgr->voices[voiceNum].voiceFlags |= VOICE_FLAG_DEFER_MUTE; + + /* mute immediately */ + else + VMMuteVoice(pVoiceMgr, voiceNum); + } + } + } + + /* for stolen voice, check new values */ + else + { + /* voice must be on the same channel */ + if (channel == pVoiceMgr->voices[voiceNum].nextChannel) + { + /* check key group */ + pRegion = GetRegionPtr(pSynth, pVoiceMgr->voices[voiceNum].nextRegionIndex); + if (keyGroup == (pRegion->keyGroupAndFlags & 0x0f00)) + { +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMCheckKeyGroup: voice %d matches key group %d\n", voiceNum, keyGroup >> 8); */ } +#endif + + /* if this voice was just started, set it to mute on the next buffer */ + if (pVoiceMgr->voices[voiceNum].voiceFlags & VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET) + pVoiceMgr->voices[voiceNum].voiceFlags |= VOICE_FLAG_DEFER_MUTE; + + /* mute immediately */ + else + VMMuteVoice(pVoiceMgr, voiceNum); + } + } + + } + } +} + +/*---------------------------------------------------------------------------- + * VMCheckPolyphonyLimiting() + *---------------------------------------------------------------------------- + * Purpose: + * We only play at most 2 of the same note on a MIDI channel. + * E.g., if we are asked to start note 36, and there are already two voices + * that are playing note 36, then we must steal the voice playing + * the oldest note 36 and use that stolen voice to play the new note 36. + * + * Inputs: + * nChannel - synth channel that wants to start a new note + * nKeyNumber - new note's midi note number + * nNoteVelocity - new note's velocity + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * pbVoiceStealingRequired - flag: this routine sets true if we needed to + * steal a voice + * * + * Side Effects: + * psSynthObject->m_sVoice[free voice num].m_nKeyNumber may be assigned + * psSynthObject->m_sVoice[free voice num].m_nVelocity may be assigned + *---------------------------------------------------------------------------- +*/ +EAS_BOOL VMCheckPolyphonyLimiting (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 note, EAS_U8 velocity, EAS_U16 regionIndex, EAS_I32 lowVoice, EAS_I32 highVoice) +{ + EAS_INT voiceNum; + EAS_INT oldestVoiceNum; + EAS_INT numVoicesPlayingNote; + EAS_U16 age; + EAS_U16 oldestNoteAge; + + pVoiceMgr->workload += WORKLOAD_AMOUNT_POLY_LIMIT; + + numVoicesPlayingNote = 0; + oldestVoiceNum = MAX_SYNTH_VOICES; + oldestNoteAge = 0; + channel = VSynthToChannel(pSynth, channel); + + /* examine each voice on this channel playing this note */ + for (voiceNum = lowVoice; voiceNum <= highVoice; voiceNum++) + { + /* check stolen notes separately */ + if (pVoiceMgr->voices[voiceNum].voiceState != eVoiceStateStolen) + { + + /* same channel and note ? */ + if ((channel == pVoiceMgr->voices[voiceNum].channel) && (note == pVoiceMgr->voices[voiceNum].note)) + { + numVoicesPlayingNote++; + age = pVoiceMgr->age - pVoiceMgr->voices[voiceNum].age; + + /* is this the oldest voice for this note? */ + if (age >= oldestNoteAge) + { + oldestNoteAge = age; + oldestVoiceNum = voiceNum; + } + } + } + + /* handle stolen voices */ + else + { + /* same channel and note ? */ + if ((channel == pVoiceMgr->voices[voiceNum].nextChannel) && (note == pVoiceMgr->voices[voiceNum].nextNote)) + { + numVoicesPlayingNote++; + } + } + } + + /* check to see if we exceeded poly limit */ + if (numVoicesPlayingNote < DEFAULT_CHANNEL_POLYPHONY_LIMIT) + return EAS_FALSE; + + /* make sure we have a voice to steal */ + if (oldestVoiceNum != MAX_SYNTH_VOICES) + { +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMCheckPolyphonyLimiting: voice %d has the oldest note\n", oldestVoiceNum); */ } + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "VMCheckPolyphonyLimiting: polyphony limiting requires shutting down note %d \n", pVoiceMgr->voices[oldestVoiceNum].note); */ } +#endif + VMStolenVoice(pVoiceMgr, pSynth, oldestVoiceNum, channel, note, velocity, regionIndex); + return EAS_TRUE; + } + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "VMCheckPolyphonyLimiting: No oldest voice to steal\n"); */ } +#endif + return EAS_FALSE; +} + +/*---------------------------------------------------------------------------- + * VMStartVoice() + *---------------------------------------------------------------------------- + * Starts a voice given a region index + *---------------------------------------------------------------------------- +*/ +void VMStartVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 note, EAS_U8 velocity, EAS_U16 regionIndex) +{ + const S_REGION *pRegion; + S_SYNTH_CHANNEL *pChannel; + EAS_INT voiceNum; + EAS_INT maxSynthPoly; + EAS_I32 lowVoice, highVoice; + EAS_U16 keyGroup; + + pChannel = &pSynth->channels[channel]; + pRegion = GetRegionPtr(pSynth, regionIndex); + + /* select correct synth */ +#if defined(_SECONDARY_SYNTH) || defined(EAS_SPLIT_WT_SYNTH) + { +#ifdef EAS_SPLIT_WT_SYNTH + if ((pRegion->keyGroupAndFlags & REGION_FLAG_OFF_CHIP) == 0) +#else + if ((regionIndex & FLAG_RGN_IDX_FM_SYNTH) == 0) +#endif + { + lowVoice = 0; + highVoice = NUM_PRIMARY_VOICES - 1; + } + else + { + lowVoice = NUM_PRIMARY_VOICES; + highVoice = MAX_SYNTH_VOICES - 1; + } + } +#else + lowVoice = 0; + highVoice = MAX_SYNTH_VOICES - 1; +#endif + + /* keep track of the note-start related workload */ + pVoiceMgr->workload+= WORKLOAD_AMOUNT_START_NOTE; + + /* other voices in pool, check for key group and poly limiting */ + if (pSynth->poolCount[pChannel->pool] != 0) + { + + /* check for key group exclusivity */ + keyGroup = pRegion->keyGroupAndFlags & 0x0f00; + if (keyGroup!= 0) + VMCheckKeyGroup(pVoiceMgr, pSynth, keyGroup, channel); + + /* check polyphony limit and steal a voice if necessary */ + if ((pRegion->keyGroupAndFlags & REGION_FLAG_NON_SELF_EXCLUSIVE) == 0) + { + if (VMCheckPolyphonyLimiting(pVoiceMgr, pSynth, channel, note, velocity, regionIndex, lowVoice, highVoice) == EAS_TRUE) + return; + } + } + + /* check max poly allocation */ + if ((pSynth->maxPolyphony == 0) || (pVoiceMgr->maxPolyphony < pSynth->maxPolyphony)) + maxSynthPoly = pVoiceMgr->maxPolyphony; + else + maxSynthPoly = pSynth->maxPolyphony; + + /* any free voices? */ + if ((pVoiceMgr->activeVoices < pVoiceMgr->maxPolyphony) && + (pSynth->numActiveVoices < maxSynthPoly) && + (EAS_SUCCESS == VMFindAvailableVoice(pVoiceMgr, &voiceNum, lowVoice, highVoice))) + { + S_SYNTH_VOICE *pVoice = &pVoiceMgr->voices[voiceNum]; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "VMStartVoice: Synth=%d\n", pSynth->vSynthNum); */ } +#endif + + /* bump voice counts */ + pVoiceMgr->activeVoices++; + pSynth->numActiveVoices++; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMStartVoice: voice %d assigned to channel %d note %d velocity %d\n", + voiceNum, channel, note, velocity); */ } +#endif + + /* save parameters */ + pVoiceMgr->voices[voiceNum].channel = VSynthToChannel(pSynth, channel); + pVoiceMgr->voices[voiceNum].note = note; + pVoiceMgr->voices[voiceNum].velocity = velocity; + + /* establish note age for voice stealing */ + pVoiceMgr->voices[voiceNum].age = pVoiceMgr->age++; + + /* setup the synthesis parameters */ + pVoiceMgr->voices[voiceNum].voiceState = eVoiceStateStart; + + /* increment voice pool count */ + IncVoicePoolCount(pVoiceMgr, pVoice); + + /* start voice on correct synth */ + /*lint -e{522} return not used at this time */ + GetSynthPtr(voiceNum)->pfStartVoice(pVoiceMgr, pSynth, &pVoiceMgr->voices[voiceNum], GetAdjustedVoiceNum(voiceNum), regionIndex); + return; + } + + /* no free voices, we have to steal one using appropriate algorithm */ + if (VMStealVoice(pVoiceMgr, pSynth, &voiceNum, channel, note, lowVoice, highVoice) == EAS_SUCCESS) + VMStolenVoice(pVoiceMgr, pSynth, voiceNum, channel, note, velocity, regionIndex); + +#ifdef _DEBUG_VM + else + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMStartVoice: Could not steal a voice for channel %d note %d velocity %d\n", + channel, note, velocity); */ } + } +#endif + + return; +} + +/*---------------------------------------------------------------------------- + * VMStartNote() + *---------------------------------------------------------------------------- + * Purpose: + * Update the synth's state to play the requested note on the requested + * channel if possible. + * + * Inputs: + * nChannel - the channel to start a note on + * nKeyNumber - the key number to start a note for + * nNoteVelocity - the key velocity from this note + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * Side Effects: + * psSynthObject->m_nNumActiveVoices may be incremented + * psSynthObject->m_sVoice[free voice num].m_nSynthChannel may be assigned + * psSynthObject->m_sVoice[free voice num].m_nKeyNumber is assigned + * psSynthObject->m_sVoice[free voice num].m_nVelocity is assigned + *---------------------------------------------------------------------------- +*/ +void VMStartNote (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 note, EAS_U8 velocity) +{ + S_SYNTH_CHANNEL *pChannel; + EAS_U16 regionIndex; + EAS_I16 adjustedNote; + + /* bump note count */ + pSynth->totalNoteCount++; + + pChannel = &pSynth->channels[channel]; + + /* check channel mute */ + if (pChannel->channelFlags & CHANNEL_FLAG_MUTE) + return; + +#ifdef EXTERNAL_AUDIO + /* pass event to external audio when requested */ + if ((pChannel->channelFlags & CHANNEL_FLAG_EXTERNAL_AUDIO) && (pSynth->cbEventFunc != NULL)) + { + S_EXT_AUDIO_EVENT event; + event.channel = channel; + event.note = note; + event.velocity = velocity; + event.noteOn = EAS_TRUE; + if (pSynth->cbEventFunc(pSynth->pExtAudioInstData, &event)) + return; + } +#endif + + /* start search at first region */ + regionIndex = pChannel->regionIndex; + + /* handle transposition */ + adjustedNote = note; + if (pChannel->channelFlags & CHANNEL_FLAG_RHYTHM_CHANNEL) + adjustedNote += pChannel->coarsePitch; + else + adjustedNote += pChannel->coarsePitch + pSynth->globalTranspose; + + /* limit adjusted key number so it does not wraparound, over/underflow */ + if (adjustedNote < 0) + { + adjustedNote = 0; + } + else if (adjustedNote > 127) + { + adjustedNote = 127; + } + +#if defined(DLS_SYNTHESIZER) + if (regionIndex & FLAG_RGN_IDX_DLS_SYNTH) + { + /* DLS voice */ + for (;;) + { + /*lint -e{740,826} cast OK, we know this is actually a DLS region */ + const S_DLS_REGION *pDLSRegion = (S_DLS_REGION*) GetRegionPtr(pSynth, regionIndex); + + /* check key against this region's key and velocity range */ + if (((adjustedNote >= pDLSRegion->wtRegion.region.rangeLow) && (adjustedNote <= pDLSRegion->wtRegion.region.rangeHigh)) && + ((velocity >= pDLSRegion->velLow) && (velocity <= pDLSRegion->velHigh))) + { + VMStartVoice(pVoiceMgr, pSynth, channel, note, velocity, regionIndex); + } + + /* last region in program? */ + if (pDLSRegion->wtRegion.region.keyGroupAndFlags & REGION_FLAG_LAST_REGION) + break; + + /* advance to next region */ + regionIndex++; + } + } + else +#endif + + /* braces here for #if clause */ + { + /* EAS voice */ + for (;;) + { + const S_REGION *pRegion = GetRegionPtr(pSynth, regionIndex); + + /* check key against this region's keyrange */ + if ((adjustedNote >= pRegion->rangeLow) && (adjustedNote <= pRegion->rangeHigh)) + { + VMStartVoice(pVoiceMgr, pSynth, channel, note, velocity, regionIndex); + break; + } + + /* last region in program? */ + if (pRegion->keyGroupAndFlags & REGION_FLAG_LAST_REGION) + break; + + /* advance to next region */ + regionIndex++; + } + } +} + +/*---------------------------------------------------------------------------- + * VMStopNote() + *---------------------------------------------------------------------------- + * Purpose: + * Update the synth's state to end the requested note on the requested + * channel. + * + * Inputs: + * nChannel - the channel to stop a note on + * nKeyNumber - the key number for this note off + * nNoteVelocity - the note-off velocity + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * Side Effects: + * psSynthObject->m_sVoice[free voice num].m_nSynthChannel may be assigned + * psSynthObject->m_sVoice[free voice num].m_nKeyNumber is assigned + * psSynthObject->m_sVoice[free voice num].m_nVelocity is assigned + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, velocity) reserved for future use */ +void VMStopNote (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 note, EAS_U8 velocity) +{ + S_SYNTH_CHANNEL *pChannel; + EAS_INT voiceNum; + + pChannel = &(pSynth->channels[channel]); + +#ifdef EXTERNAL_AUDIO + if ((pChannel->channelFlags & CHANNEL_FLAG_EXTERNAL_AUDIO) && (pSynth->cbEventFunc != NULL)) + { + S_EXT_AUDIO_EVENT event; + event.channel = channel; + event.note = note; + event.velocity = velocity; + event.noteOn = EAS_FALSE; + if (pSynth->cbEventFunc(pSynth->pExtAudioInstData, &event)) + return; + } +#endif + + /* keep track of the note-start workload */ + pVoiceMgr->workload += WORKLOAD_AMOUNT_STOP_NOTE; + + channel = VSynthToChannel(pSynth, channel); + + for (voiceNum=0; voiceNum < MAX_SYNTH_VOICES; voiceNum++) + { + + /* stolen notes are handled separately */ + if (eVoiceStateStolen != pVoiceMgr->voices[voiceNum].voiceState) + { + + /* channel and key number must match */ + if ((channel == pVoiceMgr->voices[voiceNum].channel) && (note == pVoiceMgr->voices[voiceNum].note)) + { +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMStopNote: voice %d channel %d note %d\n", + voiceNum, channel, note); */ } +#endif + + /* if sustain pedal is down, set deferred note-off flag */ + if (pChannel->channelFlags & CHANNEL_FLAG_SUSTAIN_PEDAL) + { + pVoiceMgr->voices[voiceNum].voiceFlags |= VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF; + continue; + } + + /* if this note just started, wait before we stop it */ + if (pVoiceMgr->voices[voiceNum].voiceFlags & VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET) + { +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tDeferred: Not started yet\n"); */ } +#endif + pVoiceMgr->voices[voiceNum].voiceFlags |= VOICE_FLAG_DEFER_MIDI_NOTE_OFF; + pSynth->synthFlags |= SYNTH_FLAG_DEFERRED_MIDI_NOTE_OFF_PENDING; + } + + /* release voice */ + else + VMReleaseVoice(pVoiceMgr, pSynth, voiceNum); + + } + } + + /* process stolen notes, new channel and key number must match */ + else if ((channel == pVoiceMgr->voices[voiceNum].nextChannel) && (note == pVoiceMgr->voices[voiceNum].nextNote)) + { + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMStopNote: voice %d channel %d note %d\n\tDeferred: Stolen voice\n", + voiceNum, channel, note); */ } +#endif + pVoiceMgr->voices[voiceNum].voiceFlags |= VOICE_FLAG_DEFER_MIDI_NOTE_OFF; + } + } +} + +/*---------------------------------------------------------------------------- + * VMFindAvailableVoice() + *---------------------------------------------------------------------------- + * Purpose: + * Find an available voice and return the voice number if available. + * + * Inputs: + * pnVoiceNumber - really an output, returns the voice number found + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * success - if there is an available voice + * failure - otherwise + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMFindAvailableVoice (S_VOICE_MGR *pVoiceMgr, EAS_INT *pVoiceNumber, EAS_I32 lowVoice, EAS_I32 highVoice) +{ + EAS_INT voiceNum; + + /* Check each voice to see if it has been assigned to a synth channel */ + for (voiceNum = lowVoice; voiceNum <= highVoice; voiceNum++) + { + /* check if this voice has been assigned to a synth channel */ + if ( pVoiceMgr->voices[voiceNum].voiceState == eVoiceStateFree) + { + *pVoiceNumber = voiceNum; /* this voice is available */ + return EAS_SUCCESS; + } + } + + /* if we reach here, we have not found a free voice */ + *pVoiceNumber = UNASSIGNED_SYNTH_VOICE; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMFindAvailableVoice: error, could not find an available voice\n"); */ } +#endif + return EAS_FAILURE; +} + +/*---------------------------------------------------------------------------- + * VMStealVoice() + *---------------------------------------------------------------------------- + * Purpose: + * Steal a voice and return the voice number + * + * Stealing algorithm: steal the best choice with minimal work, taking into + * account SP-Midi channel priorities and polyphony allocation. + * + * In one pass through all the voices, figure out which voice to steal + * taking into account a number of different factors: + * Priority of the voice's MIDI channel + * Number of voices over the polyphony allocation for voice's MIDI channel + * Amplitude of the voice + * Note age + * Key velocity (for voices that haven't been started yet) + * If any matching notes are found + * + * Inputs: + * pnVoiceNumber - really an output, see below + * nChannel - the channel that this voice wants to be started on + * nKeyNumber - the key number for this new voice + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * pnVoiceNumber - voice number of the voice that was stolen + * EAS_RESULT EAS_SUCCESS - always successful + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMStealVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_INT *pVoiceNumber, EAS_U8 channel, EAS_U8 note, EAS_I32 lowVoice, EAS_I32 highVoice) +{ + S_SYNTH_VOICE *pCurrVoice; + S_SYNTH *pCurrSynth; + EAS_INT voiceNum; + EAS_INT bestCandidate; + EAS_U8 currChannel; + EAS_U8 currNote; + EAS_I32 bestPriority; + EAS_I32 currentPriority; + + /* determine which voice to steal */ + bestPriority = 0; + bestCandidate = MAX_SYNTH_VOICES; + + for (voiceNum = lowVoice; voiceNum <= highVoice; voiceNum++) + { + pCurrVoice = &pVoiceMgr->voices[voiceNum]; + + /* ignore free voices */ + if (pCurrVoice->voiceState == eVoiceStateFree) + continue; + + /* for stolen voices, use the new parameters, not the old */ + if (pCurrVoice->voiceState == eVoiceStateStolen) + { + pCurrSynth = pVoiceMgr->pSynth[GET_VSYNTH(pCurrVoice->nextChannel)]; + currChannel = pCurrVoice->nextChannel; + currNote = pCurrVoice->nextNote; + } + else + { + pCurrSynth = pVoiceMgr->pSynth[GET_VSYNTH(pCurrVoice->channel)]; + currChannel = pCurrVoice->channel; + currNote = pCurrVoice->note; + } + + /* ignore voices that are higher priority */ + if (pSynth->priority > pCurrSynth->priority) + continue; +#ifdef _DEBUG_VM +// { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMStealVoice: New priority = %d exceeds old priority = %d\n", pSynth->priority, pCurrSynth->priority); */ } +#endif + + /* if voice is stolen or just started, reduce the likelihood it will be stolen */ + if (( pCurrVoice->voiceState == eVoiceStateStolen) || (pCurrVoice->voiceFlags & VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET)) + { + currentPriority = 128 - pCurrVoice->nextVelocity; + } + else + { + /* compute the priority of this voice, higher means better for stealing */ + /* use not age */ + currentPriority = (EAS_I32) pCurrVoice->age << NOTE_AGE_STEAL_WEIGHT; + + /* include note gain -higher gain is lower steal value */ + /*lint -e{704} use shift for performance */ + currentPriority += ((32768 >> (12 - NOTE_GAIN_STEAL_WEIGHT)) + 256) - + ((EAS_I32) pCurrVoice->gain >> (12 - NOTE_GAIN_STEAL_WEIGHT)); + } + + /* in SP-MIDI mode, include over poly allocation and channel priority */ + if (pSynth->synthFlags & SYNTH_FLAG_SP_MIDI_ON) + { + S_SYNTH_CHANNEL *pChannel = &pCurrSynth->channels[GET_CHANNEL(currChannel)]; + /*lint -e{701} use shift for performance */ + if (pSynth->poolCount[pChannel->pool] >= pSynth->poolAlloc[pChannel->pool]) + currentPriority += (pSynth->poolCount[pChannel->pool] -pSynth->poolAlloc[pChannel->pool] + 1) << CHANNEL_POLY_STEAL_WEIGHT; + + /* include channel priority */ + currentPriority += (EAS_I32)(pChannel->pool << CHANNEL_PRIORITY_STEAL_WEIGHT); + } + + /* if a note is already playing that matches this note, consider stealing it more readily */ + if ((note == currNote) && (channel == currChannel)) + currentPriority += NOTE_MATCH_PENALTY; + + /* is this the best choice so far? */ + if (currentPriority >= bestPriority) + { + bestPriority = currentPriority; + bestCandidate = voiceNum; + } + } + + /* may happen if all voices are allocated to a higher priority virtual synth */ + if (bestCandidate == MAX_SYNTH_VOICES) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMStealVoice: Unable to allocate a voice\n"); */ } + return EAS_ERROR_NO_VOICE_ALLOCATED; + } + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMStealVoice: Voice %d stolen\n", bestCandidate); */ } + + /* are we stealing a stolen voice? */ + if (pVoiceMgr->voices[bestCandidate].voiceState == eVoiceStateStolen) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "VMStealVoice: Voice %d is already marked as stolen and was scheduled to play ch: %d note: %d vel: %d\n", + bestCandidate, + pVoiceMgr->voices[bestCandidate].nextChannel, + pVoiceMgr->voices[bestCandidate].nextNote, + pVoiceMgr->voices[bestCandidate].nextVelocity); */ } + } +#endif + + *pVoiceNumber = (EAS_U16) bestCandidate; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMChannelPressure() + *---------------------------------------------------------------------------- + * Purpose: + * Change the channel pressure for the given channel + * + * Inputs: + * nChannel - the MIDI channel + * nVelocity - the channel pressure value + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * Side Effects: + * psSynthObject->m_sChannel[nChannel].m_nChannelPressure is updated + *---------------------------------------------------------------------------- +*/ +void VMChannelPressure (S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 value) +{ + S_SYNTH_CHANNEL *pChannel; + + pChannel = &(pSynth->channels[channel]); + pChannel->channelPressure = value; + + /* + set a channel flag to request parameter updates + for all the voices associated with this channel + */ + pChannel->channelFlags |= CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS; +} + +/*---------------------------------------------------------------------------- + * VMPitchBend() + *---------------------------------------------------------------------------- + * Purpose: + * Change the pitch wheel value for the given channel. + * This routine constructs the proper 14-bit argument when the calling routine + * passes the pitch LSB and MSB. + * + * Note: some midi disassemblers display a bipolar pitch bend value. + * We can display the bipolar value using + * if m_nPitchBend >= 0x2000 + * bipolar pitch bend = postive (m_nPitchBend - 0x2000) + * else + * bipolar pitch bend = negative (0x2000 - m_nPitchBend) + * + * Inputs: + * nChannel - the MIDI channel + * nPitchLSB - the LSB byte of the pitch bend message + * nPitchMSB - the MSB byte of the pitch bend message + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * psSynthObject->m_sChannel[nChannel].m_nPitchBend is changed + * + *---------------------------------------------------------------------------- +*/ +void VMPitchBend (S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 nPitchLSB, EAS_U8 nPitchMSB) +{ + S_SYNTH_CHANNEL *pChannel; + + pChannel = &(pSynth->channels[channel]); + pChannel->pitchBend = (EAS_I16) ((nPitchMSB << 7) | nPitchLSB); + + /* + set a channel flag to request parameter updates + for all the voices associated with this channel + */ + pChannel->channelFlags |= CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS; +} + +/*---------------------------------------------------------------------------- + * VMControlChange() + *---------------------------------------------------------------------------- + * Purpose: + * Change the controller (or mode) for the given channel. + * + * Inputs: + * nChannel - the MIDI channel + * nControllerNumber - the MIDI controller number + * nControlValue - the value for this controller message + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * Side Effects: + * psSynthObject->m_sChannel[nChannel] controller is changed + * + *---------------------------------------------------------------------------- +*/ +void VMControlChange (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 controller, EAS_U8 value) +{ + S_SYNTH_CHANNEL *pChannel; + + pChannel = &(pSynth->channels[channel]); + + /* + set a channel flag to request parameter updates + for all the voices associated with this channel + */ + pChannel->channelFlags |= CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS; + + switch ( controller ) + { + case MIDI_CONTROLLER_BANK_SELECT_MSB: +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMControlChange: Bank Select MSB: msb 0x%X\n", value); */ } +#endif + /* use this MSB with a zero LSB, until we get an LSB message */ + pChannel->bankNum = value << 8; + break; + + case MIDI_CONTROLLER_MOD_WHEEL: + /* we treat mod wheel as a 7-bit controller and only use the MSB */ + pChannel->modWheel = value; + break; + + case MIDI_CONTROLLER_VOLUME: + /* we treat volume as a 7-bit controller and only use the MSB */ + pChannel->volume = value; + break; + + case MIDI_CONTROLLER_PAN: + /* we treat pan as a 7-bit controller and only use the MSB */ + pChannel->pan = value; + break; + + case MIDI_CONTROLLER_EXPRESSION: + /* we treat expression as a 7-bit controller and only use the MSB */ + pChannel->expression = value; + break; + + case MIDI_CONTROLLER_BANK_SELECT_LSB: +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMControlChange: Bank Select LSB: lsb 0x%X\n", value); */ } +#endif + /* + construct bank number as 7-bits (stored as 8) of existing MSB + and 7-bits of new LSB (also stored as 8( + */ + pChannel->bankNum = + (pChannel->bankNum & 0xFF00) | value; + + break; + + case MIDI_CONTROLLER_SUSTAIN_PEDAL: + /* we treat sustain pedal as a boolean on/off bit flag */ + if (value < 64) + { + /* + we are requested to turn the pedal off, but first check + if the pedal is already on + */ + if (0 != + (pChannel->channelFlags & CHANNEL_FLAG_SUSTAIN_PEDAL) + ) + { + /* + The sustain flag is presently set and the damper pedal is on. + We are therefore transitioning from damper pedal ON to + damper pedal OFF. This means all notes in this channel + that received a note off while the damper pedal was on, and + had their note-off requests deferred, should now proceed to + the release state. + */ + VMReleaseAllDeferredNoteOffs(pVoiceMgr, pSynth, channel); + } /* end if sustain pedal is already on */ + + /* turn the sustain pedal off */ + pChannel->channelFlags &= ~CHANNEL_FLAG_SUSTAIN_PEDAL; + } + else + { + /* + we are requested to turn the pedal on, but first check + if the pedal is already off + */ + if (0 == + (pChannel->channelFlags & CHANNEL_FLAG_SUSTAIN_PEDAL) + ) + { + /* + The sustain flag is presently clear and the damper pedal is off. + We are therefore transitioning from damper pedal OFF to + damper pedal ON. Currently sounding notes should be left + unchanged. However, we should try to "catch" notes if possible. + If any notes have levels >= sustain level, catch them, + otherwise, let them continue to release. + */ + VMCatchNotesForSustainPedal(pVoiceMgr, pSynth, channel); + } + + /* turn the sustain pedal on */ + pChannel->channelFlags |= CHANNEL_FLAG_SUSTAIN_PEDAL; + } + + break; +#ifdef _REVERB + case MIDI_CONTROLLER_REVERB_SEND: + /* we treat send as a 7-bit controller and only use the MSB */ + pSynth->channels[channel].reverbSend = value; + break; +#endif +#ifdef _CHORUS + case MIDI_CONTROLLER_CHORUS_SEND: + /* we treat send as a 7-bit controller and only use the MSB */ + pSynth->channels[channel].chorusSend = value; + break; +#endif + case MIDI_CONTROLLER_RESET_CONTROLLERS: + /* despite the Midi message name, not ALL controllers are reset */ + pChannel->modWheel = DEFAULT_MOD_WHEEL; + pChannel->expression = DEFAULT_EXPRESSION; + + /* turn the sustain pedal off as default/reset */ + pChannel->channelFlags &= ~CHANNEL_FLAG_SUSTAIN_PEDAL; + pChannel->pitchBend = DEFAULT_PITCH_BEND; + + /* reset channel pressure */ + pChannel->channelPressure = DEFAULT_CHANNEL_PRESSURE; + + /* reset RPN values */ + pChannel->registeredParam = DEFAULT_REGISTERED_PARAM; + pChannel->pitchBendSensitivity = DEFAULT_PITCH_BEND_SENSITIVITY; + pChannel->finePitch = DEFAULT_FINE_PITCH; + pChannel->coarsePitch = DEFAULT_COARSE_PITCH; + + /* + program change, bank select, channel volume CC7, pan CC10 + are NOT reset + */ + break; + + /* + For logical reasons, the RPN data entry are grouped together. + However, keep in mind that these cases are not necessarily in + ascending order. + e.g., MIDI_CONTROLLER_DATA_ENTRY_MSB == 6, + whereas MIDI_CONTROLLER_SUSTAIN_PEDAL == 64. + So arrange these case statements in whatever manner is more efficient for + the processor / compiler. + */ + case MIDI_CONTROLLER_ENTER_DATA_MSB: + case MIDI_CONTROLLER_ENTER_DATA_LSB: + case MIDI_CONTROLLER_SELECT_RPN_LSB: + case MIDI_CONTROLLER_SELECT_RPN_MSB: + case MIDI_CONTROLLER_SELECT_NRPN_MSB: + case MIDI_CONTROLLER_SELECT_NRPN_LSB: + VMUpdateRPNStateMachine(pSynth, channel, controller, value); + break; + + case MIDI_CONTROLLER_ALL_SOUND_OFF: + case MIDI_CONTROLLER_ALL_NOTES_OFF: + case MIDI_CONTROLLER_OMNI_OFF: + case MIDI_CONTROLLER_OMNI_ON: + case MIDI_CONTROLLER_MONO_ON_POLY_OFF: + case MIDI_CONTROLLER_POLY_ON_MONO_OFF: + /* NOTE: we treat all sounds off the same as all notes off */ + VMAllNotesOff(pVoiceMgr, pSynth, channel); + break; + + default: +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMControlChange: controller %d not yet implemented\n", controller); */ } +#endif + break; + + } + + return; +} + +/*---------------------------------------------------------------------------- + * VMUpdateRPNStateMachine() + *---------------------------------------------------------------------------- + * Purpose: + * Call this function when we want to parse RPN related controller messages. + * We only support RPN0 (pitch bend sensitivity), RPN1 (fine tuning) and + * RPN2 (coarse tuning). Any other RPNs or NRPNs are ignored for now. + *. + * Supports any order, so not a state machine anymore. This function was + * rewritten to work correctly regardless of order. + * + * Inputs: + * nChannel - the channel this controller message is coming from + * nControllerNumber - which RPN related controller + * nControlValue - the value of the RPN related controller + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * returns EAS_RESULT, which is typically EAS_SUCCESS, since there are + * few possible errors + * + * Side Effects: + * gsSynthObject.m_sChannel[nChannel].m_nPitchBendSensitivity + * (or m_nFinePitch or m_nCoarsePitch) + * will be updated if the proper RPN message is received. + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMUpdateRPNStateMachine (S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 controller, EAS_U8 value) +{ + S_SYNTH_CHANNEL *pChannel; + +#ifdef _DEBUG_VM + if (channel >= NUM_SYNTH_CHANNELS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMUpdateRPNStateMachines: error, %d invalid channel number\n", + channel); */ } + return EAS_FAILURE; + } +#endif + + pChannel = &(pSynth->channels[channel]); + + switch (controller) + { + case MIDI_CONTROLLER_SELECT_NRPN_MSB: + case MIDI_CONTROLLER_SELECT_NRPN_LSB: + pChannel->registeredParam = DEFAULT_REGISTERED_PARAM; + break; + case MIDI_CONTROLLER_SELECT_RPN_MSB: + pChannel->registeredParam = + (pChannel->registeredParam & 0x7F) | (value<<7); + break; + case MIDI_CONTROLLER_SELECT_RPN_LSB: + pChannel->registeredParam = + (pChannel->registeredParam & 0x7F00) | value; + break; + case MIDI_CONTROLLER_ENTER_DATA_MSB: + switch (pChannel->registeredParam) + { + case 0: + pChannel->pitchBendSensitivity = value * 100; + break; + case 1: + /*lint -e{702} */ + pChannel->finePitch = (EAS_I8)((((value << 7) - 8192) * 100) >> 13); + break; + case 2: + pChannel->coarsePitch = (EAS_I8)(value - 64); + break; + default: + break; + } + break; + case MIDI_CONTROLLER_ENTER_DATA_LSB: + switch (pChannel->registeredParam) + { + case 0: + //ignore lsb + break; + case 1: + //ignore lsb + break; + case 2: + //ignore lsb + break; + default: + break; + } + break; + default: + return EAS_FAILURE; //not a RPN related controller + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMUpdateStaticChannelParameters() + *---------------------------------------------------------------------------- + * Purpose: + * Update all of the static channel parameters for channels that have had + * a controller change values + * Or if the synth has signalled that all channels must forcibly + * be updated + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * none + * + * Side Effects: + * - psSynthObject->m_sChannel[].m_nStaticGain and m_nStaticPitch + * are updated for channels whose controller values have changed + * or if the synth has signalled that all channels must forcibly + * be updated + *---------------------------------------------------------------------------- +*/ +void VMUpdateStaticChannelParameters (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth) +{ + EAS_INT channel; + + if (pSynth->synthFlags & SYNTH_FLAG_UPDATE_ALL_CHANNEL_PARAMETERS) + { + /* + the synth wants us to forcibly update all channel + parameters. This event occurs when we are about to + finish resetting the synth + */ + for (channel = 0; channel < NUM_SYNTH_CHANNELS; channel++) + { +#ifdef _HYBRID_SYNTH + if (pSynth->channels[channel].regionIndex & FLAG_RGN_IDX_FM_SYNTH) + pSecondarySynth->pfUpdateChannel(pVoiceMgr, pSynth, (EAS_U8) channel); + else + pPrimarySynth->pfUpdateChannel(pVoiceMgr, pSynth, (EAS_U8) channel); +#else + pPrimarySynth->pfUpdateChannel(pVoiceMgr, pSynth, (EAS_U8) channel); +#endif + } + + /* + clear the flag to indicates we have now forcibly + updated all channel parameters + */ + pSynth->synthFlags &= ~SYNTH_FLAG_UPDATE_ALL_CHANNEL_PARAMETERS; + } + else + { + + /* only update channel params if signalled by a channel flag */ + for (channel = 0; channel < NUM_SYNTH_CHANNELS; channel++) + { + if ( 0 != (pSynth->channels[channel].channelFlags & CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS)) + { +#ifdef _HYBRID_SYNTH + if (pSynth->channels[channel].regionIndex & FLAG_RGN_IDX_FM_SYNTH) + pSecondarySynth->pfUpdateChannel(pVoiceMgr, pSynth, (EAS_U8) channel); + else + pPrimarySynth->pfUpdateChannel(pVoiceMgr, pSynth, (EAS_U8) channel); +#else + pPrimarySynth->pfUpdateChannel(pVoiceMgr, pSynth, (EAS_U8) channel); +#endif + } + } + + } + + return; +} + +/*---------------------------------------------------------------------------- + * VMFindProgram() + *---------------------------------------------------------------------------- + * Purpose: + * Look up an individual program in sound library. This function + * searches the bank list for a program, then the individual program + * list. + * + * Inputs: + * + * Outputs: + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT VMFindProgram (const S_EAS *pEAS, EAS_U32 bank, EAS_U8 programNum, EAS_U16 *pRegionIndex) +{ + EAS_U32 locale; + const S_PROGRAM *p; + EAS_U16 i; + EAS_U16 regionIndex; + + /* make sure we have a valid sound library */ + if (pEAS == NULL) + return EAS_FAILURE; + + /* search the banks */ + for (i = 0; i < pEAS->numBanks; i++) + { + if (bank == (EAS_U32) pEAS->pBanks[i].locale) + { + regionIndex = pEAS->pBanks[i].regionIndex[programNum]; + if (regionIndex != INVALID_REGION_INDEX) + { + *pRegionIndex = regionIndex; + return EAS_SUCCESS; + } + break; + } + } + + /* establish locale */ + locale = ( bank << 8) | programNum; + + /* search for program */ + for (i = 0, p = pEAS->pPrograms; i < pEAS->numPrograms; i++, p++) + { + if (p->locale == locale) + { + *pRegionIndex = p->regionIndex; + return EAS_SUCCESS; + } + } + + return EAS_FAILURE; +} + +#ifdef DLS_SYNTHESIZER +/*---------------------------------------------------------------------------- + * VMFindDLSProgram() + *---------------------------------------------------------------------------- + * Purpose: + * Look up an individual program in sound library. This function + * searches the bank list for a program, then the individual program + * list. + * + * Inputs: + * + * Outputs: + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT VMFindDLSProgram (const S_DLS *pDLS, EAS_U32 bank, EAS_U8 programNum, EAS_U16 *pRegionIndex) +{ + EAS_U32 locale; + const S_PROGRAM *p; + EAS_U16 i; + + /* make sure we have a valid sound library */ + if (pDLS == NULL) + return EAS_FAILURE; + + /* establish locale */ + locale = (bank << 8) | programNum; + + /* search for program */ + for (i = 0, p = pDLS->pDLSPrograms; i < pDLS->numDLSPrograms; i++, p++) + { + if (p->locale == locale) + { + *pRegionIndex = p->regionIndex; + return EAS_SUCCESS; + } + } + + return EAS_FAILURE; +} +#endif + +/*---------------------------------------------------------------------------- + * VMProgramChange() + *---------------------------------------------------------------------------- + * Purpose: + * Change the instrument (program) for the given channel. + * + * Depending on the program number, and the bank selected for this channel, the + * program may be in ROM, RAM (from SMAF or CMX related RAM wavetable), or + * Alternate wavetable (from mobile DLS or other DLS file) + * + * This function figures out what wavetable should be used, and sets it up as the + * wavetable to use for this channel. Also the channel may switch from a melodic + * channel to a rhythm channel, or vice versa. + * + * Inputs: + * + * Outputs: + * Side Effects: + * gsSynthObject.m_sChannel[nChannel].m_nProgramNumber is likely changed + * gsSynthObject.m_sChannel[nChannel].m_psEAS may be changed + * gsSynthObject.m_sChannel[nChannel].m_bRhythmChannel may be changed + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pVoiceMgr) reserved for future use */ +void VMProgramChange (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 program) +{ + S_SYNTH_CHANNEL *pChannel; + EAS_U32 bank; + EAS_U16 regionIndex; + +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "VMProgramChange: vSynthNum=%d, channel=%d, program=%d\n", pSynth->vSynthNum, channel, program); */ } +#endif + + /* setup pointer to MIDI channel data */ + pChannel = &pSynth->channels[channel]; + bank = pChannel->bankNum; + + /* allow channels to switch between being melodic or rhythm channels, using GM2 CC values */ + if ((bank & 0xFF00) == DEFAULT_RHYTHM_BANK_NUMBER) + { + /* make it a rhythm channel */ + pChannel->channelFlags |= CHANNEL_FLAG_RHYTHM_CHANNEL; + } + else if ((bank & 0xFF00) == DEFAULT_MELODY_BANK_NUMBER) + { + /* make it a melody channel */ + pChannel->channelFlags &= ~CHANNEL_FLAG_RHYTHM_CHANNEL; + } + + regionIndex = DEFAULT_REGION_INDEX; + +#ifdef EXTERNAL_AUDIO + /* give the external audio interface a chance to handle it */ + if (pSynth->cbProgChgFunc != NULL) + { + S_EXT_AUDIO_PRG_CHG prgChg; + prgChg.channel = channel; + prgChg.bank = (EAS_U16) bank; + prgChg.program = program; + if (pSynth->cbProgChgFunc(pSynth->pExtAudioInstData, &prgChg)) + pChannel->channelFlags |= CHANNEL_FLAG_EXTERNAL_AUDIO; + } + +#endif + + +#ifdef DLS_SYNTHESIZER + /* first check for DLS program that may overlay the internal instrument */ + if (VMFindDLSProgram(pSynth->pDLS, bank, program, ®ionIndex) != EAS_SUCCESS) +#endif + + /* braces to support 'if' clause above */ + { + + /* look in the internal banks */ + if (VMFindProgram(pSynth->pEAS, bank, program, ®ionIndex) != EAS_SUCCESS) + + /* fall back to default bank */ + { + if (pSynth->channels[channel].channelFlags & CHANNEL_FLAG_RHYTHM_CHANNEL) + bank = DEFAULT_RHYTHM_BANK_NUMBER; + else + bank = DEFAULT_MELODY_BANK_NUMBER; + + if (VMFindProgram(pSynth->pEAS, bank, program, ®ionIndex) != EAS_SUCCESS) + + /* switch to program 0 in the default bank */ + { + if (VMFindProgram(pSynth->pEAS, bank, 0, ®ionIndex) != EAS_SUCCESS) + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "VMProgramChange: No program @ %03d:%03d:%03d\n", + (bank >> 8) & 0x7f, bank & 0x7f, program); */ } + } + } + } + + /* we have our new program change for this channel */ + pChannel->programNum = program; + pChannel->regionIndex = regionIndex; + + /* + set a channel flag to request parameter updates + for all the voices associated with this channel + */ + pChannel->channelFlags |= CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS; + + return; +} + +/*---------------------------------------------------------------------------- + * VMAddSamples() + *---------------------------------------------------------------------------- + * Purpose: + * Synthesize the requested number of samples (block based processing) + * + * Inputs: + * nNumSamplesToAdd - number of samples to write to buffer + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * number of voices rendered + * + * Side Effects: + * - samples are added to the presently free buffer + * + *---------------------------------------------------------------------------- +*/ +EAS_I32 VMAddSamples (S_VOICE_MGR *pVoiceMgr, EAS_I32 *pMixBuffer, EAS_I32 numSamples) +{ + S_SYNTH *pSynth; + EAS_INT voicesRendered; + EAS_INT voiceNum; + EAS_BOOL done; + +#ifdef _REVERB + EAS_PCM *pReverbSendBuffer; +#endif // ifdef _REVERB + +#ifdef _CHORUS + EAS_PCM *pChorusSendBuffer; +#endif // ifdef _CHORUS + + voicesRendered = 0; + for (voiceNum = 0; voiceNum < MAX_SYNTH_VOICES; voiceNum++) + { + + /* retarget stolen voices */ + if ((pVoiceMgr->voices[voiceNum].voiceState == eVoiceStateStolen) && (pVoiceMgr->voices[voiceNum].gain <= 0)) + VMRetargetStolenVoice(pVoiceMgr, voiceNum); + + /* get pointer to virtual synth */ + pSynth = pVoiceMgr->pSynth[pVoiceMgr->voices[voiceNum].channel >> 4]; + + /* synthesize active voices */ + if (pVoiceMgr->voices[voiceNum].voiceState != eVoiceStateFree) + { + done = GetSynthPtr(voiceNum)->pfUpdateVoice(pVoiceMgr, pSynth, &pVoiceMgr->voices[voiceNum], GetAdjustedVoiceNum(voiceNum), pMixBuffer, numSamples); + voicesRendered++; + + /* voice is finished */ + if (done == EAS_TRUE) + { + /* set gain of stolen voice to zero so it will be restarted */ + if (pVoiceMgr->voices[voiceNum].voiceState == eVoiceStateStolen) + pVoiceMgr->voices[voiceNum].gain = 0; + + /* or return it to the free voice pool */ + else + VMFreeVoice(pVoiceMgr, pSynth, &pVoiceMgr->voices[voiceNum]); + } + + /* if this voice is scheduled to be muted, set the mute flag */ + if (pVoiceMgr->voices[voiceNum].voiceFlags & VOICE_FLAG_DEFER_MUTE) + { + pVoiceMgr->voices[voiceNum].voiceFlags &= ~(VOICE_FLAG_DEFER_MUTE | VOICE_FLAG_DEFER_MIDI_NOTE_OFF); + VMMuteVoice(pVoiceMgr, voiceNum); + } + + /* if voice just started, advance state to play */ + if (pVoiceMgr->voices[voiceNum].voiceState == eVoiceStateStart) + pVoiceMgr->voices[voiceNum].voiceState = eVoiceStatePlay; + } + } + + return voicesRendered; +} + +/*---------------------------------------------------------------------------- + * VMRender() + *---------------------------------------------------------------------------- + * Purpose: + * This routine renders a frame of audio + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * pVoicesRendered - number of voices rendered this frame + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMRender (S_VOICE_MGR *pVoiceMgr, EAS_I32 numSamples, EAS_I32 *pMixBuffer, EAS_I32 *pVoicesRendered) +{ + S_SYNTH *pSynth; + EAS_INT i; + EAS_INT channel; + +#ifdef _CHECKED_BUILD + SanityCheck(pVoiceMgr); +#endif + + /* update MIDI channel parameters */ + *pVoicesRendered = 0; + for (i = 0; i < MAX_VIRTUAL_SYNTHESIZERS; i++) + { + if (pVoiceMgr->pSynth[i] != NULL) + VMUpdateStaticChannelParameters(pVoiceMgr, pVoiceMgr->pSynth[i]); + } + + /* synthesize a buffer of audio */ + *pVoicesRendered = VMAddSamples(pVoiceMgr, pMixBuffer, numSamples); + + /* + * check for deferred note-off messages + * If flag is set, that means one or more voices are expecting deferred + * midi note-off messages because the midi note-on and corresponding midi + * note-off requests occurred during the same update interval. The goal + * is the defer the note-off request so that the note can at least start. + */ + for (i = 0; i < MAX_VIRTUAL_SYNTHESIZERS; i++) + { + pSynth = pVoiceMgr->pSynth[i]; + + if (pSynth== NULL) + continue; + + if (pSynth->synthFlags & SYNTH_FLAG_DEFERRED_MIDI_NOTE_OFF_PENDING) + VMDeferredStopNote(pVoiceMgr, pSynth); + + /* check if we need to reset the synth */ + if ((pSynth->synthFlags & SYNTH_FLAG_RESET_IS_REQUESTED) && + (pSynth->numActiveVoices == 0)) + { + /* + complete the process of resetting the synth now that + all voices have muted + */ +#ifdef _DEBUG_VM + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMAddSamples: complete the reset process\n"); */ } +#endif + + VMInitializeAllChannels(pVoiceMgr, pSynth); + VMInitializeAllVoices(pVoiceMgr, pSynth->vSynthNum); + + /* clear the reset flag */ + pSynth->synthFlags &= ~SYNTH_FLAG_RESET_IS_REQUESTED; + } + + /* clear channel update flags */ + for (channel = 0; channel < NUM_SYNTH_CHANNELS; channel++) + pSynth->channels[channel].channelFlags &= ~CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS; + + } + +#ifdef _CHECKED_BUILD + SanityCheck(pVoiceMgr); +#endif + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMInitWorkload() + *---------------------------------------------------------------------------- + * Purpose: + * Clears the workload counter + * + * Inputs: + * pVoiceMgr - pointer to instance data + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMInitWorkload (S_VOICE_MGR *pVoiceMgr) +{ + pVoiceMgr->workload = 0; +} + +/*---------------------------------------------------------------------------- + * VMSetWorkload() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the max workload for a single frame. + * + * Inputs: + * pVoiceMgr - pointer to instance data + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMSetWorkload (S_VOICE_MGR *pVoiceMgr, EAS_I32 maxWorkLoad) +{ + pVoiceMgr->maxWorkLoad = maxWorkLoad; +} + +/*---------------------------------------------------------------------------- + * VMCheckWorkload() + *---------------------------------------------------------------------------- + * Purpose: + * Checks to see if work load has been exceeded on this frame. + * + * Inputs: + * pVoiceMgr - pointer to instance data + * + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_BOOL VMCheckWorkload (S_VOICE_MGR *pVoiceMgr) +{ + if (pVoiceMgr->maxWorkLoad > 0) + return (EAS_BOOL) (pVoiceMgr->workload >= pVoiceMgr->maxWorkLoad); + return EAS_FALSE; +} + +/*---------------------------------------------------------------------------- + * VMActiveVoices() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the number of active voices in the synthesizer. + * + * Inputs: + * pEASData - pointer to instance data + * + * Outputs: + * Returns the number of active voices + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_I32 VMActiveVoices (S_SYNTH *pSynth) +{ + return pSynth->numActiveVoices; +} + +/*---------------------------------------------------------------------------- + * VMSetSynthPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Set the synth to a new polyphony value. Value must be >= 1 and + * <= MAX_SYNTH_VOICES. This function will pin the polyphony at those limits + * + * Inputs: + * pVoiceMgr pointer to synthesizer data + * polyphonyCount desired polyphony count + * synth synthesizer number (0 = onboard, 1 = DSP) + * + * Outputs: + * Returns error code + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMSetSynthPolyphony (S_VOICE_MGR *pVoiceMgr, EAS_I32 synth, EAS_I32 polyphonyCount) +{ + EAS_INT i; + EAS_INT activeVoices; + + /* lower limit */ + if (polyphonyCount < 1) + polyphonyCount = 1; + + /* split architecture */ +#if defined(_SECONDARY_SYNTH) || defined(EAS_SPLIT_WT_SYNTH) + if (synth == EAS_MCU_SYNTH) + { + if (polyphonyCount > NUM_PRIMARY_VOICES) + polyphonyCount = NUM_PRIMARY_VOICES; + if (pVoiceMgr->maxPolyphonyPrimary == polyphonyCount) + return EAS_SUCCESS; + pVoiceMgr->maxPolyphonyPrimary = (EAS_U16) polyphonyCount; + } + else if (synth == EAS_DSP_SYNTH) + { + if (polyphonyCount > NUM_SECONDARY_VOICES) + polyphonyCount = NUM_SECONDARY_VOICES; + if (pVoiceMgr->maxPolyphonySecondary == polyphonyCount) + return EAS_SUCCESS; + pVoiceMgr->maxPolyphonySecondary = (EAS_U16) polyphonyCount; + } + else + return EAS_ERROR_PARAMETER_RANGE; + + /* setting for SP-MIDI */ + pVoiceMgr->maxPolyphony = pVoiceMgr->maxPolyphonyPrimary + pVoiceMgr->maxPolyphonySecondary; + + /* standard architecture */ +#else + if (synth != EAS_MCU_SYNTH) + return EAS_ERROR_PARAMETER_RANGE; + + /* pin desired value to possible limits */ + if (polyphonyCount > MAX_SYNTH_VOICES) + polyphonyCount = MAX_SYNTH_VOICES; + + /* set polyphony, if value is different than current value */ + if (pVoiceMgr->maxPolyphony == polyphonyCount) + return EAS_SUCCESS; + + pVoiceMgr->maxPolyphony = (EAS_U16) polyphonyCount; +#endif + + /* if SPMIDI enabled, update channel masking based on new polyphony */ + for (i = 0; i < MAX_VIRTUAL_SYNTHESIZERS; i++) + { + if (pVoiceMgr->pSynth[i]) + { + if (pVoiceMgr->pSynth[i]->synthFlags & SYNTH_FLAG_SP_MIDI_ON) + VMMIPUpdateChannelMuting(pVoiceMgr, pVoiceMgr->pSynth[i]); + else + pVoiceMgr->pSynth[i]->poolAlloc[0] = (EAS_U8) polyphonyCount; + } + } + + /* are we under polyphony limit? */ + if (pVoiceMgr->activeVoices <= polyphonyCount) + return EAS_SUCCESS; + + /* count the number of active voices */ + activeVoices = 0; + for (i = 0; i < MAX_SYNTH_VOICES; i++) + { + + /* is voice active? */ + if ((pVoiceMgr->voices[i].voiceState != eVoiceStateFree) && (pVoiceMgr->voices[i].voiceState != eVoiceStateMuting)) + activeVoices++; + } + + /* we may have to mute voices to reach new target */ + while (activeVoices > polyphonyCount) + { + S_SYNTH *pSynth; + S_SYNTH_VOICE *pVoice; + EAS_I32 currentPriority, bestPriority; + EAS_INT bestCandidate; + + /* find the lowest priority voice */ + bestPriority = bestCandidate = -1; + for (i = 0; i < MAX_SYNTH_VOICES; i++) + { + + pVoice = &pVoiceMgr->voices[i]; + + /* ignore free and muting voices */ + if ((pVoice->voiceState == eVoiceStateFree) || (pVoice->voiceState == eVoiceStateMuting)) + continue; + + pSynth = pVoiceMgr->pSynth[GET_VSYNTH(pVoice->channel)]; + + /* if voice is stolen or just started, reduce the likelihood it will be stolen */ + if (( pVoice->voiceState == eVoiceStateStolen) || (pVoice->voiceFlags & VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET)) + { + /* include velocity */ + currentPriority = 128 - pVoice->nextVelocity; + + /* include channel priority */ + currentPriority += pSynth->channels[GET_CHANNEL(pVoice->nextChannel)].pool << CHANNEL_PRIORITY_STEAL_WEIGHT; + } + else + { + /* include age */ + currentPriority = (EAS_I32) pVoice->age << NOTE_AGE_STEAL_WEIGHT; + + /* include note gain -higher gain is lower steal value */ + /*lint -e{704} use shift for performance */ + currentPriority += ((32768 >> (12 - NOTE_GAIN_STEAL_WEIGHT)) + 256) - + ((EAS_I32) pVoice->gain >> (12 - NOTE_GAIN_STEAL_WEIGHT)); + + /* include channel priority */ + currentPriority += pSynth->channels[GET_CHANNEL(pVoice->channel)].pool << CHANNEL_PRIORITY_STEAL_WEIGHT; + } + + /* include synth priority */ + currentPriority += pSynth->priority << SYNTH_PRIORITY_WEIGHT; + + /* is this the best choice so far? */ + if (currentPriority > bestPriority) + { + bestPriority = currentPriority; + bestCandidate = i; + } + } + + /* shutdown best candidate */ + if (bestCandidate < 0) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "VMSetPolyphony: Unable to reduce polyphony\n"); */ } + break; + } + + /* shut down this voice */ + /*lint -e{771} pSynth is initialized if bestCandidate >= 0 */ + VMMuteVoice(pVoiceMgr, bestCandidate); + activeVoices--; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMGetSynthPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current polyphony setting + * + * Inputs: + * pVoiceMgr pointer to synthesizer data + * synth synthesizer number (0 = onboard, 1 = DSP) + * + * Outputs: + * Returns actual polyphony value set, as pinned by limits + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMGetSynthPolyphony (S_VOICE_MGR *pVoiceMgr, EAS_I32 synth, EAS_I32 *pPolyphonyCount) +{ + +#if defined(_SECONDARY_SYNTH) || defined(EAS_SPLIT_WT_SYNTH) + if (synth == EAS_MCU_SYNTH) + *pPolyphonyCount = pVoiceMgr->maxPolyphonyPrimary; + else if (synth == EAS_DSP_SYNTH) + *pPolyphonyCount = pVoiceMgr->maxPolyphonySecondary; + else + return EAS_ERROR_PARAMETER_RANGE; +#else + if (synth != EAS_MCU_SYNTH) + return EAS_ERROR_PARAMETER_RANGE; + *pPolyphonyCount = pVoiceMgr->maxPolyphony; +#endif + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMSetPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Set the virtual synth polyphony. 0 = no limit (i.e. can use + * all available voices). + * + * Inputs: + * pVoiceMgr pointer to synthesizer data + * polyphonyCount desired polyphony count + * pSynth pointer to virtual synth + * + * Outputs: + * Returns error code + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMSetPolyphony (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 polyphonyCount) +{ + EAS_INT i; + EAS_INT activeVoices; + + /* check limits */ + if (polyphonyCount < 0) + return EAS_ERROR_PARAMETER_RANGE; + + /* zero is max polyphony */ + if ((polyphonyCount == 0) || (polyphonyCount > MAX_SYNTH_VOICES)) + { + pSynth->maxPolyphony = 0; + return EAS_SUCCESS; + } + + /* set new polyphony */ + pSynth->maxPolyphony = (EAS_U16) polyphonyCount; + + /* max polyphony is minimum of virtual synth and actual synth */ + if (polyphonyCount > pVoiceMgr->maxPolyphony) + polyphonyCount = pVoiceMgr->maxPolyphony; + + /* if SP-MIDI mode, update the channel muting */ + if (pSynth->synthFlags & SYNTH_FLAG_SP_MIDI_ON) + VMMIPUpdateChannelMuting(pVoiceMgr, pSynth); + else + pSynth->poolAlloc[0] = (EAS_U8) polyphonyCount; + + /* are we under polyphony limit? */ + if (pSynth->numActiveVoices <= polyphonyCount) + return EAS_SUCCESS; + + /* count the number of active voices */ + activeVoices = 0; + for (i = 0; i < MAX_SYNTH_VOICES; i++) + { + /* this synth? */ + if (GET_VSYNTH(pVoiceMgr->voices[i].nextChannel) != pSynth->vSynthNum) + continue; + + /* is voice active? */ + if ((pVoiceMgr->voices[i].voiceState != eVoiceStateFree) && (pVoiceMgr->voices[i].voiceState != eVoiceStateMuting)) + activeVoices++; + } + + /* we may have to mute voices to reach new target */ + while (activeVoices > polyphonyCount) + { + S_SYNTH_VOICE *pVoice; + EAS_I32 currentPriority, bestPriority; + EAS_INT bestCandidate; + + /* find the lowest priority voice */ + bestPriority = bestCandidate = -1; + for (i = 0; i < MAX_SYNTH_VOICES; i++) + { + pVoice = &pVoiceMgr->voices[i]; + + /* this synth? */ + if (GET_VSYNTH(pVoice->nextChannel) != pSynth->vSynthNum) + continue; + + /* if voice is stolen or just started, reduce the likelihood it will be stolen */ + if (( pVoice->voiceState == eVoiceStateStolen) || (pVoice->voiceFlags & VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET)) + { + /* include velocity */ + currentPriority = 128 - pVoice->nextVelocity; + + /* include channel priority */ + currentPriority += pSynth->channels[GET_CHANNEL(pVoice->nextChannel)].pool << CHANNEL_PRIORITY_STEAL_WEIGHT; + } + else + { + /* include age */ + currentPriority = (EAS_I32) pVoice->age << NOTE_AGE_STEAL_WEIGHT; + + /* include note gain -higher gain is lower steal value */ + /*lint -e{704} use shift for performance */ + currentPriority += ((32768 >> (12 - NOTE_GAIN_STEAL_WEIGHT)) + 256) - + ((EAS_I32) pVoice->gain >> (12 - NOTE_GAIN_STEAL_WEIGHT)); + + /* include channel priority */ + currentPriority += pSynth->channels[GET_CHANNEL(pVoice->nextChannel)].pool << CHANNEL_PRIORITY_STEAL_WEIGHT; + } + + /* is this the best choice so far? */ + if (currentPriority > bestPriority) + { + bestPriority = currentPriority; + bestCandidate = i; + } + } + + /* shutdown best candidate */ + if (bestCandidate < 0) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "VMSetPolyphony: Unable to reduce polyphony\n"); */ } + break; + } + + /* shut down this voice */ + VMMuteVoice(pVoiceMgr, bestCandidate); + activeVoices--; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMGetPolyphony() + *---------------------------------------------------------------------------- + * Purpose: + * Get the virtual synth polyphony + * + * Inputs: + * pVoiceMgr pointer to synthesizer data + * pPolyphonyCount pointer to variable to hold polyphony count + * pSynth pointer to virtual synth + * + * Outputs: + * Returns error code + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pVoiceMgr) reserved for future use */ +EAS_RESULT VMGetPolyphony (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 *pPolyphonyCount) +{ + *pPolyphonyCount = (EAS_U16) pSynth->maxPolyphony; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMSetPriority() + *---------------------------------------------------------------------------- + * Purpose: + * Set the virtual synth priority + * + * Inputs: + * pVoiceMgr pointer to synthesizer data + * priority new priority + * pSynth pointer to virtual synth + * + * Outputs: + * Returns error code + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pVoiceMgr) reserved for future use */ +EAS_RESULT VMSetPriority (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 priority) +{ + pSynth->priority = (EAS_U8) priority ; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMGetPriority() + *---------------------------------------------------------------------------- + * Purpose: + * Get the virtual synth priority + * + * Inputs: + * pVoiceMgr pointer to synthesizer data + * pPriority pointer to variable to hold priority + * pSynth pointer to virtual synth + * + * Outputs: + * Returns error code + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pVoiceMgr) reserved for future use */ +EAS_RESULT VMGetPriority (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 *pPriority) +{ + *pPriority = pSynth->priority; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMSetVolume() + *---------------------------------------------------------------------------- + * Purpose: + * Set the master volume for this synthesizer for this sequence. + * + * Inputs: + * nSynthVolume - the desired master volume + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * + * Side Effects: + * overrides any previously set master volume from sysex + * + *---------------------------------------------------------------------------- +*/ +void VMSetVolume (S_SYNTH *pSynth, EAS_U16 masterVolume) +{ + pSynth->masterVolume = masterVolume; + pSynth->synthFlags |= SYNTH_FLAG_UPDATE_ALL_CHANNEL_PARAMETERS; +} + +/*---------------------------------------------------------------------------- + * VMSetPitchBendRange() + *---------------------------------------------------------------------------- + * Set the pitch bend range for the given channel. + *---------------------------------------------------------------------------- +*/ +void VMSetPitchBendRange (S_SYNTH *pSynth, EAS_INT channel, EAS_I16 pitchBendRange) +{ + pSynth->channels[channel].pitchBendSensitivity = pitchBendRange; +} + +/*---------------------------------------------------------------------------- + * VMValidateEASLib() + *---------------------------------------------------------------------------- + * Validates an EAS library + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMValidateEASLib (EAS_SNDLIB_HANDLE pEAS) +{ + /* validate the sound library */ + if (pEAS) + { + if (pEAS->identifier != _EAS_LIBRARY_VERSION) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMValidateEASLib: Sound library mismatch in sound library: Read 0x%08x, expected 0x%08x\n", + pEAS->identifier, _EAS_LIBRARY_VERSION); */ } + return EAS_ERROR_SOUND_LIBRARY; + } + + /* check sample rate */ + if ((pEAS->libAttr & LIBFORMAT_SAMPLE_RATE_MASK) != _OUTPUT_SAMPLE_RATE) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMValidateEASLib: Sample rate mismatch in sound library: Read %lu, expected %lu\n", + pEAS->libAttr & LIBFORMAT_SAMPLE_RATE_MASK, _OUTPUT_SAMPLE_RATE); */ } + return EAS_ERROR_SOUND_LIBRARY; + } + +#ifdef _WT_SYNTH + /* check sample bit depth */ +#ifdef _8_BIT_SAMPLES + if (pEAS->libAttr & LIB_FORMAT_16_BIT_SAMPLES) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMValidateEASLib: Expected 8-bit samples and found 16-bit\n", + pEAS->libAttr & LIBFORMAT_SAMPLE_RATE_MASK, _OUTPUT_SAMPLE_RATE); */ } + return EAS_ERROR_SOUND_LIBRARY; + } +#endif +#ifdef _16_BIT_SAMPLES + if ((pEAS->libAttr & LIB_FORMAT_16_BIT_SAMPLES) == 0) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMValidateEASLib: Expected 16-bit samples and found 8-bit\n", + pEAS->libAttr & LIBFORMAT_SAMPLE_RATE_MASK, _OUTPUT_SAMPLE_RATE); */ } + return EAS_ERROR_SOUND_LIBRARY; + } +#endif +#endif + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMSetGlobalEASLib() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the EAS library to be used by the synthesizer + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMSetGlobalEASLib (S_VOICE_MGR *pVoiceMgr, EAS_SNDLIB_HANDLE pEAS) +{ + EAS_RESULT result; + + result = VMValidateEASLib(pEAS); + if (result != EAS_SUCCESS) + return result; + + pVoiceMgr->pGlobalEAS = pEAS; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMSetEASLib() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the EAS library to be used by the synthesizer + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMSetEASLib (S_SYNTH *pSynth, EAS_SNDLIB_HANDLE pEAS) +{ + EAS_RESULT result; + + result = VMValidateEASLib(pEAS); + if (result != EAS_SUCCESS) + return result; + + pSynth->pEAS = pEAS; + return EAS_SUCCESS; +} + +#ifdef DLS_SYNTHESIZER +/*---------------------------------------------------------------------------- + * VMSetGlobalDLSLib() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the DLS library to be used by the synthesizer + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMSetGlobalDLSLib (EAS_DATA_HANDLE pEASData, EAS_DLSLIB_HANDLE pDLS) +{ + + if (pEASData->pVoiceMgr->pGlobalDLS) + DLSCleanup(pEASData->hwInstData, pEASData->pVoiceMgr->pGlobalDLS); + + pEASData->pVoiceMgr->pGlobalDLS = pDLS; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * VMSetDLSLib() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the DLS library to be used by the synthesizer + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMSetDLSLib (S_SYNTH *pSynth, EAS_DLSLIB_HANDLE pDLS) +{ + pSynth->pDLS = pDLS; + return EAS_SUCCESS; +} +#endif + +/*---------------------------------------------------------------------------- + * VMSetTranposition() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the global key transposition used by the synthesizer. + * Transposes all melodic instruments up or down by the specified + * amount. Range is limited to +/-12 semitones. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMSetTranposition (S_SYNTH *pSynth, EAS_I32 transposition) +{ + pSynth->globalTranspose = (EAS_I8) transposition; +} + +/*---------------------------------------------------------------------------- + * VMGetTranposition() + *---------------------------------------------------------------------------- + * Purpose: + * Gets the global key transposition used by the synthesizer. + * Transposes all melodic instruments up or down by the specified + * amount. Range is limited to +/-12 semitones. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMGetTranposition (S_SYNTH *pSynth, EAS_I32 *pTransposition) +{ + *pTransposition = pSynth->globalTranspose; +} + +/*---------------------------------------------------------------------------- + * VMGetNoteCount() + *---------------------------------------------------------------------------- +* Returns the total note count +*---------------------------------------------------------------------------- +*/ +EAS_I32 VMGetNoteCount (S_SYNTH *pSynth) +{ + return pSynth->totalNoteCount; +} + +/*---------------------------------------------------------------------------- + * VMMIDIShutdown() + *---------------------------------------------------------------------------- + * Purpose: + * Clean up any Synth related system issues. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * None + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMMIDIShutdown (S_EAS_DATA *pEASData, S_SYNTH *pSynth) +{ + EAS_INT vSynthNum; + + /* decrement reference count, free if all references are gone */ + if (--pSynth->refCount > 0) + return; + + vSynthNum = pSynth->vSynthNum; + + /* cleanup DLS load */ +#ifdef DLS_SYNTHESIZER + /*lint -e{550} result used only in debugging code */ + if (pSynth->pDLS != NULL) + { + EAS_RESULT result; + if ((result = DLSCleanup(pEASData->hwInstData, pSynth->pDLS)) != EAS_SUCCESS) + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMMIDIShutdown: Error %ld cleaning up DLS collection\n", result); */ } + pSynth->pDLS = NULL; + } +#endif + + VMReset(pEASData->pVoiceMgr, pSynth, EAS_TRUE); + + /* check Configuration Module for static memory allocation */ + if (!pEASData->staticMemoryModel) + EAS_HWFree(pEASData->hwInstData, pSynth); + + /* clear pointer to MIDI state */ + pEASData->pVoiceMgr->pSynth[vSynthNum] = NULL; +} + +/*---------------------------------------------------------------------------- + * VMShutdown() + *---------------------------------------------------------------------------- + * Purpose: + * Clean up any Synth related system issues. + * + * Inputs: + * psEASData - pointer to overall EAS data structure + * + * Outputs: + * None + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +void VMShutdown (S_EAS_DATA *pEASData) +{ + + /* don't free a NULL pointer */ + if (pEASData->pVoiceMgr == NULL) + return; + +#ifdef DLS_SYNTHESIZER + /* if we have a global DLS collection, clean it up */ + if (pEASData->pVoiceMgr->pGlobalDLS) + { + DLSCleanup(pEASData->hwInstData, pEASData->pVoiceMgr->pGlobalDLS); + pEASData->pVoiceMgr->pGlobalDLS = NULL; + } +#endif + + /* check Configuration Module for static memory allocation */ + if (!pEASData->staticMemoryModel) + EAS_HWFree(pEASData->hwInstData, pEASData->pVoiceMgr); + pEASData->pVoiceMgr = NULL; +} + +#ifdef EXTERNAL_AUDIO +/*---------------------------------------------------------------------------- + * EAS_RegExtAudioCallback() + *---------------------------------------------------------------------------- + * Register a callback for external audio processing + *---------------------------------------------------------------------------- +*/ +void VMRegExtAudioCallback (S_SYNTH *pSynth, EAS_VOID_PTR pInstData, EAS_EXT_PRG_CHG_FUNC cbProgChgFunc, EAS_EXT_EVENT_FUNC cbEventFunc) +{ + pSynth->pExtAudioInstData = pInstData; + pSynth->cbProgChgFunc = cbProgChgFunc; + pSynth->cbEventFunc = cbEventFunc; +} + +/*---------------------------------------------------------------------------- + * VMGetMIDIControllers() + *---------------------------------------------------------------------------- + * Returns the MIDI controller values on the specified channel + *---------------------------------------------------------------------------- +*/ +void VMGetMIDIControllers (S_SYNTH *pSynth, EAS_U8 channel, S_MIDI_CONTROLLERS *pControl) +{ + pControl->modWheel = pSynth->channels[channel].modWheel; + pControl->volume = pSynth->channels[channel].volume; + pControl->pan = pSynth->channels[channel].pan; + pControl->expression = pSynth->channels[channel].expression; + pControl->channelPressure = pSynth->channels[channel].channelPressure; + +#ifdef _REVERB + pControl->reverbSend = pSynth->channels[channel].reverbSend; +#endif + +#ifdef _CHORUSE + pControl->chorusSend = pSynth->channels[channel].chorusSend; +#endif +} +#endif + +#ifdef _SPLIT_ARCHITECTURE +/*---------------------------------------------------------------------------- + * VMStartFrame() + *---------------------------------------------------------------------------- + * Purpose: + * Starts an audio frame + * + * Inputs: + * + * Outputs: + * Returns true if EAS_MixEnginePrep should be called (onboard mixing) + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_BOOL VMStartFrame (S_EAS_DATA *pEASData) +{ + + /* init counter for voices starts in split architecture */ +#ifdef MAX_VOICE_STARTS + pVoiceMgr->numVoiceStarts = 0; +#endif + + return pFrameInterface->pfStartFrame(pEASData->pVoiceMgr->pFrameBuffer); +} + +/*---------------------------------------------------------------------------- + * VMEndFrame() + *---------------------------------------------------------------------------- + * Purpose: + * Stops an audio frame + * + * Inputs: + * + * Outputs: + * Returns true if EAS_MixEnginePost should be called (onboard mixing) + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +EAS_BOOL VMEndFrame (S_EAS_DATA *pEASData) +{ + + return pFrameInterface->pfEndFrame(pEASData->pVoiceMgr->pFrameBuffer, pEASData->pMixBuffer, pEASData->masterGain); +} +#endif + +#ifdef TEST_HARNESS +/*---------------------------------------------------------------------------- + * SanityCheck() + *---------------------------------------------------------------------------- +*/ +EAS_RESULT VMSanityCheck (EAS_DATA_HANDLE pEASData) +{ + S_SYNTH_VOICE *pVoice; + S_SYNTH *pSynth; + EAS_INT i; + EAS_INT j; + EAS_INT freeVoices; + EAS_INT activeVoices; + EAS_INT playingVoices; + EAS_INT stolenVoices; + EAS_INT releasingVoices; + EAS_INT mutingVoices; + EAS_INT poolCount[MAX_VIRTUAL_SYNTHESIZERS][NUM_SYNTH_CHANNELS]; + EAS_INT vSynthNum; + EAS_RESULT result = EAS_SUCCESS; + + /* initialize counts */ + EAS_HWMemSet(poolCount, 0, sizeof(poolCount)); + freeVoices = activeVoices = playingVoices = stolenVoices = releasingVoices = mutingVoices = 0; + + /* iterate through all voices */ + for (i = 0; i < MAX_SYNTH_VOICES; i++) + { + pVoice = &pEASData->pVoiceMgr->voices[i]; + if (pVoice->voiceState != eVoiceStateFree) + { + vSynthNum = GET_VSYNTH(pVoice->channel); + if (vSynthNum >= MAX_VIRTUAL_SYNTHESIZERS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMSanityCheck: Voice %d has invalid virtual synth number %d\n", i, vSynthNum); */ } + result = EAS_FAILURE; + continue; + } + pSynth = pEASData->pVoiceMgr->pSynth[vSynthNum]; + + switch (pVoice->voiceState) + { + case eVoiceStateMuting: + activeVoices++; + mutingVoices++; + break; + + case eVoiceStateStolen: + vSynthNum = GET_VSYNTH(pVoice->nextChannel); + if (vSynthNum >= MAX_VIRTUAL_SYNTHESIZERS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMSanityCheck: Voice %d has invalid virtual synth number %d\n", i, vSynthNum); */ } + result = EAS_FAILURE; + continue; + } + pSynth = pEASData->pVoiceMgr->pSynth[vSynthNum]; + activeVoices++; + stolenVoices++; + poolCount[vSynthNum][pSynth->channels[GET_CHANNEL(pVoice->nextChannel)].pool]++; + break; + + case eVoiceStateStart: + case eVoiceStatePlay: + activeVoices++; + playingVoices++; + poolCount[vSynthNum][pSynth->channels[GET_CHANNEL(pVoice->channel)].pool]++; + break; + + case eVoiceStateRelease: + activeVoices++; + releasingVoices++; + poolCount[vSynthNum][pSynth->channels[GET_CHANNEL(pVoice->channel)].pool]++; + break; + + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMSanityCheck : voice %d in invalid state\n", i); */ } + result = EAS_FAILURE; + break; + } + } + + /* count free voices */ + else + freeVoices++; + } + + /* dump state info */ + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "%d free\n", freeVoices); */ } + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "%d active\n", activeVoices); */ } + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "%d playing\n", playingVoices); */ } + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "%d releasing\n", releasingVoices); */ } + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "%d muting\n", mutingVoices); */ } + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "%d stolen\n", stolenVoices); */ } + + if (pEASData->pVoiceMgr->activeVoices != activeVoices) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Active voice mismatch was %d should be %d\n", + pEASData->pVoiceMgr->activeVoices, activeVoices); */ } + result = EAS_FAILURE; + } + + /* check virtual synth status */ + for (i = 0; i < MAX_VIRTUAL_SYNTHESIZERS; i++) + { + if (pEASData->pVoiceMgr->pSynth[i] == NULL) + continue; + + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Synth %d numActiveVoices: %d\n", i, pEASData->pVoiceMgr->pSynth[i]->numActiveVoices); */ } + if (pEASData->pVoiceMgr->pSynth[i]->numActiveVoices > MAX_SYNTH_VOICES) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMSanityCheck: Synth %d illegal count for numActiveVoices: %d\n", i, pEASData->pVoiceMgr->pSynth[i]->numActiveVoices); */ } + result = EAS_FAILURE; + } + for (j = 0; j < NUM_SYNTH_CHANNELS; j++) + { + if (poolCount[i][j] != pEASData->pVoiceMgr->pSynth[i]->poolCount[j]) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Pool count mismatch synth %d pool %d, was %d, should be %d\n", + i, j, pEASData->pVoiceMgr->pSynth[i]->poolCount[j], poolCount[i][j]); */ } + result = EAS_FAILURE; + } + } + } + + return result; +} +#endif + + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_wavefile.c b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_wavefile.c new file mode 100755 index 0000000..f24bde2 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_wavefile.c @@ -0,0 +1,867 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_wavefile.c + * + * Contents and purpose: + * This file implements the wave file parser. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 852 $ + * $Date: 2007-09-04 11:43:49 -0700 (Tue, 04 Sep 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_data.h" +#include "eas_report.h" +#include "eas_host.h" +#include "eas_config.h" +#include "eas_parser.h" +#include "eas_pcm.h" +#include "eas_wavefile.h" + +/* lint is choking on the ARM math.h file, so we declare the log10 function here */ +extern double log10(double x); + +/* increase gain to compensate for loss in mixer */ +#define WAVE_GAIN_OFFSET 6 + +/* constant for 1200 / log10(2.0) */ +#define PITCH_CENTS_CONVERSION 3986.313714 + +/*---------------------------------------------------------------------------- + * WAVE file defines + *---------------------------------------------------------------------------- +*/ +/* RIFF chunks */ +#define CHUNK_TYPE(a,b,c,d) ( \ + ( ((EAS_U32)(a) & 0xFF) << 24 ) \ + + ( ((EAS_U32)(b) & 0xFF) << 16 ) \ + + ( ((EAS_U32)(c) & 0xFF) << 8 ) \ + + ( ((EAS_U32)(d) & 0xFF) ) ) + +#define CHUNK_RIFF CHUNK_TYPE('R','I','F','F') +#define CHUNK_WAVE CHUNK_TYPE('W','A','V','E') +#define CHUNK_FMT CHUNK_TYPE('f','m','t',' ') +#define CHUNK_DATA CHUNK_TYPE('d','a','t','a') +#define CHUNK_LIST CHUNK_TYPE('L','I','S','T') +#define CHUNK_INFO CHUNK_TYPE('I','N','F','O') +#define CHUNK_INAM CHUNK_TYPE('I','N','A','M') +#define CHUNK_ICOP CHUNK_TYPE('I','C','O','P') +#define CHUNK_IART CHUNK_TYPE('I','A','R','T') + +/* wave file format identifiers */ +#define WAVE_FORMAT_PCM 0x0001 +#define WAVE_FORMAT_IMA_ADPCM 0x0011 + +/* file size for streamed file */ +#define FILE_SIZE_STREAMING 0x80000000 + +/*---------------------------------------------------------------------------- + * prototypes + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT WaveCheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *pHandle, EAS_I32 offset); +static EAS_RESULT WavePrepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT WaveState (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_STATE *pState); +static EAS_RESULT WaveClose (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT WaveReset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT WaveLocate (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 time, EAS_BOOL *pParserLocate); +static EAS_RESULT WavePause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT WaveResume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT WaveSetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value); +static EAS_RESULT WaveGetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue); +static EAS_RESULT WaveParseHeader (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, S_WAVE_STATE *pWaveData); +static EAS_RESULT WaveGetMetaData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pMediaLength); + +#ifdef MMAPI_SUPPORT +static EAS_RESULT SaveFmtChunk (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, S_WAVE_STATE *pWaveData, EAS_I32 size); +#endif + +/*---------------------------------------------------------------------------- + * + * EAS_Wave_Parser + * + * This structure contains the functional interface for the Wave file parser + *---------------------------------------------------------------------------- +*/ +const S_FILE_PARSER_INTERFACE EAS_Wave_Parser = +{ + WaveCheckFileType, + WavePrepare, + NULL, + NULL, + WaveState, + WaveClose, + WaveReset, + WavePause, + WaveResume, + WaveLocate, + WaveSetData, + WaveGetData, + WaveGetMetaData +}; + +/*---------------------------------------------------------------------------- + * WaveCheckFileType() + *---------------------------------------------------------------------------- + * Purpose: + * Check the file type to see if we can parse it + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT WaveCheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *pHandle, EAS_I32 offset) +{ + S_WAVE_STATE *pWaveData; + + /* zero the memory to insure complete initialization */ + *pHandle = NULL; + + /* read the file header */ + if (WaveParseHeader(pEASData, fileHandle, NULL) == EAS_SUCCESS) + { + + /* check for static memory allocation */ + if (pEASData->staticMemoryModel) + pWaveData = EAS_CMEnumData(EAS_CM_WAVE_DATA); + else + pWaveData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_WAVE_STATE)); + if (!pWaveData) + return EAS_ERROR_MALLOC_FAILED; + EAS_HWMemSet(pWaveData, 0, sizeof(S_WAVE_STATE)); + + /* return a pointer to the instance data */ + pWaveData->fileHandle = fileHandle; + pWaveData->fileOffset = offset; + *pHandle = pWaveData; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * WavePrepare() + *---------------------------------------------------------------------------- + * Purpose: + * Prepare to parse the file. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT WavePrepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_WAVE_STATE *pWaveData; + EAS_RESULT result; + + /* validate parser state */ + pWaveData = (S_WAVE_STATE*) pInstData; + if (pWaveData->streamHandle != NULL) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + /* back to start of file */ + pWaveData->time = 0; + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pWaveData->fileHandle, pWaveData->fileOffset)) != EAS_SUCCESS) + return result; + + /* parse the file header */ + if ((result = WaveParseHeader(pEASData, pWaveData->fileHandle, pWaveData)) != EAS_SUCCESS) + return result; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * WaveState() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current state of the stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * pState - pointer to variable to store state + * + * Outputs: + * + * + * Side Effects: + * + * Notes: + * This interface is also exposed in the internal library for use by the other modules. + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT WaveState (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_STATE *pState) +{ + S_WAVE_STATE *pWaveData; + + /* return current state */ + pWaveData = (S_WAVE_STATE*) pInstData; + if (pWaveData->streamHandle) + return EAS_PEState(pEASData, pWaveData->streamHandle, pState); + + /* if no stream handle, and time is not zero, we are done */ + if (pWaveData->time > 0) + *pState = EAS_STATE_STOPPED; + else + *pState = EAS_STATE_OPEN; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * WaveClose() + *---------------------------------------------------------------------------- + * Purpose: + * Close the file and clean up + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT WaveClose (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_WAVE_STATE *pWaveData; + EAS_RESULT result; + + pWaveData = (S_WAVE_STATE*) pInstData; + + /* close the stream */ + if (pWaveData->streamHandle) + { + if ((result = EAS_PEClose(pEASData, pWaveData->streamHandle)) != EAS_SUCCESS) + return result; + pWaveData->streamHandle = NULL; + } + + /* if using dynamic memory, free it */ + if (!pEASData->staticMemoryModel) + { + +#ifdef MMAPI_SUPPORT + /* need to free the fmt chunk */ + if (pWaveData->fmtChunk != NULL) + EAS_HWFree(pEASData->hwInstData, pWaveData->fmtChunk); +#endif + + /* free the instance data */ + EAS_HWFree(pEASData->hwInstData, pWaveData); + + } + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * WaveReset() + *---------------------------------------------------------------------------- + * Purpose: + * Reset the sequencer. Used for locating backwards in the file. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT WaveReset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + EAS_PCM_HANDLE streamHandle; + + /* reset to first byte of data in the stream */ + streamHandle = ((S_WAVE_STATE*)pInstData)->streamHandle; + if (streamHandle) + return EAS_PEReset(pEASData, streamHandle); + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; +} + +/*---------------------------------------------------------------------------- + * WaveLocate() + *---------------------------------------------------------------------------- + * Purpose: + * Rewind/fast-forward in file. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * time - time (in msecs) + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pParserLocate) reserved for future use */ +static EAS_RESULT WaveLocate (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 time, EAS_BOOL *pParserLocate) +{ + EAS_PCM_HANDLE streamHandle; + + /* reset to first byte of data in the stream */ + streamHandle = ((S_WAVE_STATE*)pInstData)->streamHandle; + if (streamHandle) + return EAS_PELocate(pEASData, streamHandle, time); + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; +} + +/*---------------------------------------------------------------------------- + * WavePause() + *---------------------------------------------------------------------------- + * Purpose: + * Mute and stop rendering a PCM stream. Sets the gain target to zero and stops the playback + * at the end of the next audio frame. + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_WAVE_STATE for this stream + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +static EAS_RESULT WavePause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + EAS_PCM_HANDLE streamHandle; + + /* pause the stream */ + streamHandle = ((S_WAVE_STATE*)pInstData)->streamHandle; + if (streamHandle) + return EAS_PEPause(pEASData, streamHandle); + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; +} + +/*---------------------------------------------------------------------------- + * WaveResume() + *---------------------------------------------------------------------------- + * Purpose: + * Resume rendering a PCM stream. Sets the gain target back to its + * previous setting and restarts playback at the end of the next audio + * frame. + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_WAVE_STATE for this stream + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +static EAS_RESULT WaveResume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + EAS_PCM_HANDLE streamHandle; + + /* resume the stream */ + streamHandle = ((S_WAVE_STATE*)pInstData)->streamHandle; + if (streamHandle) + return EAS_PEResume(pEASData, streamHandle); + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; +} + +/*---------------------------------------------------------------------------- + * WaveSetData() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_WAVE_STATE for this stream + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT WaveSetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value) +{ + S_WAVE_STATE *pWaveData = (S_WAVE_STATE*) pInstData; + + switch (param) + { + /* set metadata callback */ + case PARSER_DATA_METADATA_CB: + EAS_HWMemCpy(&pWaveData->metadata, (void*) value, sizeof(S_METADATA_CB)); + return EAS_SUCCESS; + + case PARSER_DATA_PLAYBACK_RATE: + value = (EAS_I32) (PITCH_CENTS_CONVERSION * log10((double) value / (double) (1 << 28))); + return EAS_PEUpdatePitch(pEASData, pWaveData->streamHandle, (EAS_I16) value); + + case PARSER_DATA_VOLUME: + return EAS_PEUpdateVolume(pEASData, pWaveData->streamHandle, (EAS_I16) value); + + default: + return EAS_ERROR_INVALID_PARAMETER; + } +} + +/*---------------------------------------------------------------------------- + * WaveGetData() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_WAVE_STATE for this stream + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) reserved for future use */ +static EAS_RESULT WaveGetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue) +{ + S_WAVE_STATE *pWaveData; + + pWaveData = (S_WAVE_STATE*) pInstData; + switch (param) + { + /* return file type as WAVE */ + case PARSER_DATA_FILE_TYPE: + *pValue = pWaveData->fileType; + break; + +#ifdef MMAPI_SUPPORT + /* return pointer to 'fmt' chunk */ + case PARSER_DATA_FORMAT: + *pValue = (EAS_I32) pWaveData->fmtChunk; + break; +#endif + + case PARSER_DATA_GAIN_OFFSET: + *pValue = WAVE_GAIN_OFFSET; + break; + + default: + return EAS_ERROR_INVALID_PARAMETER; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * WaveParseHeader() + *---------------------------------------------------------------------------- + * Purpose: + * Parse the WAVE file header. + * + * Inputs: + * pEASData - pointer to EAS library instance data + * handle - pointer to S_WAVE_STATE for this stream + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT WaveParseHeader (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, S_WAVE_STATE *pWaveData) +{ + S_PCM_OPEN_PARAMS params; + EAS_RESULT result; + EAS_U32 tag; + EAS_U32 fileSize; + EAS_U32 size; + EAS_I32 pos; + EAS_I32 audioOffset; + EAS_U16 usTemp; + EAS_BOOL parseDone; + EAS_U32 avgBytesPerSec; + + /* init some data (and keep lint happy) */ + params.sampleRate = 0; + params.size = 0; + audioOffset = 0; + params.decoder = 0; + params.blockSize = 0; + params.pCallbackFunc = NULL; + params.cbInstData = NULL; + params.loopSamples = 0; + params.fileHandle = fileHandle; + params.volume = 0x7fff; + params.envData = 0; + avgBytesPerSec = 8000; + + /* check for 'RIFF' tag */ + if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &tag, EAS_TRUE)) != EAS_FALSE) + return result; + if (tag != CHUNK_RIFF) + return EAS_ERROR_UNRECOGNIZED_FORMAT; + + /* get size */ + if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &fileSize, EAS_FALSE)) != EAS_FALSE) + return result; + + /* check for 'WAVE' tag */ + if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &tag, EAS_TRUE)) != EAS_FALSE) + return result; + if (tag != CHUNK_WAVE) + return EAS_ERROR_UNRECOGNIZED_FORMAT; + + /* this is enough to say we recognize the file */ + if (pWaveData == NULL) + return EAS_SUCCESS; + + /* check for streaming mode */ + pWaveData->flags = 0; + pWaveData->mediaLength = -1; + pWaveData->infoChunkPos = -1; + pWaveData->infoChunkSize = -1; + if (fileSize== FILE_SIZE_STREAMING) + { + pWaveData->flags |= PCM_FLAGS_STREAMING; + fileSize = 0x7fffffff; + } + + /* find out where we're at */ + if ((result = EAS_HWFilePos(pEASData->hwInstData, fileHandle, &pos)) != EAS_SUCCESS) + return result; + fileSize -= 4; + + parseDone = EAS_FALSE; + for (;;) + { + /* get tag and size for next chunk */ + if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &tag, EAS_TRUE)) != EAS_FALSE) + return result; + if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &size, EAS_FALSE)) != EAS_FALSE) + return result; + + /* process chunk */ + pos += 8; + switch (tag) + { + case CHUNK_FMT: + +#ifdef MMAPI_SUPPORT + if ((result = SaveFmtChunk(pEASData, fileHandle, pWaveData, (EAS_I32) size)) != EAS_SUCCESS) + return result; +#endif + + /* get audio format */ + if ((result = EAS_HWGetWord(pEASData->hwInstData, fileHandle, &usTemp, EAS_FALSE)) != EAS_FALSE) + return result; + if (usTemp == WAVE_FORMAT_PCM) + { + params.decoder = EAS_DECODER_PCM; + pWaveData->fileType = EAS_FILE_WAVE_PCM; + } + else if (usTemp == WAVE_FORMAT_IMA_ADPCM) + { + params.decoder = EAS_DECODER_IMA_ADPCM; + pWaveData->fileType = EAS_FILE_WAVE_IMA_ADPCM; + } + else + return EAS_ERROR_UNRECOGNIZED_FORMAT; + + /* get number of channels */ + if ((result = EAS_HWGetWord(pEASData->hwInstData, fileHandle, &usTemp, EAS_FALSE)) != EAS_FALSE) + return result; + if (usTemp == 2) + pWaveData->flags |= PCM_FLAGS_STEREO; + else if (usTemp != 1) + return EAS_ERROR_UNRECOGNIZED_FORMAT; + + /* get sample rate */ + if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, ¶ms.sampleRate, EAS_FALSE)) != EAS_FALSE) + return result; + + /* get stream rate */ + if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &avgBytesPerSec, EAS_FALSE)) != EAS_FALSE) + return result; + + /* get block alignment */ + if ((result = EAS_HWGetWord(pEASData->hwInstData, fileHandle, &usTemp, EAS_FALSE)) != EAS_FALSE) + return result; + params.blockSize = usTemp; + + /* get bits per sample */ + if ((result = EAS_HWGetWord(pEASData->hwInstData, fileHandle, &usTemp, EAS_FALSE)) != EAS_FALSE) + return result; + + /* PCM, must be 8 or 16 bit samples */ + if (params.decoder == EAS_DECODER_PCM) + { + if (usTemp == 8) + pWaveData->flags |= PCM_FLAGS_8_BIT | PCM_FLAGS_UNSIGNED; + else if (usTemp != 16) + return EAS_ERROR_UNRECOGNIZED_FORMAT; + } + + /* for IMA ADPCM, we only support mono 4-bit ADPCM */ + else + { + if ((usTemp != 4) || (pWaveData->flags & PCM_FLAGS_STEREO)) + return EAS_ERROR_UNRECOGNIZED_FORMAT; + } + + break; + + case CHUNK_DATA: + audioOffset = pos; + if (pWaveData->flags & PCM_FLAGS_STREAMING) + { + params.size = 0x7fffffff; + parseDone = EAS_TRUE; + } + else + { + params.size = (EAS_I32) size; + params.loopStart = size; + /* use more accurate method if possible */ + if (size <= (0x7fffffff / 1000)) + pWaveData->mediaLength = (EAS_I32) ((size * 1000) / avgBytesPerSec); + else + pWaveData->mediaLength = (EAS_I32) (size / (avgBytesPerSec / 1000)); + } + break; + + case CHUNK_LIST: + /* get the list type */ + if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &tag, EAS_TRUE)) != EAS_FALSE) + return result; + if (tag == CHUNK_INFO) + { + pWaveData->infoChunkPos = pos + 4; + pWaveData->infoChunkSize = (EAS_I32) size - 4; + } + break; + + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WaveParseHeader: %c%c%c%c chunk - %d byte(s) ignored\n", + (char) (tag >> 24), (char) (tag >> 16), (char) (tag >> 8), (char) tag, size); */ } + break; + } + + if (parseDone) + break; + + /* subtract header size */ + fileSize -= 8; + + /* account for zero-padding on odd length chunks */ + if (size & 1) + size++; + + /* this check works for files with odd length last chunk and no zero-pad */ + if (size >= fileSize) + { + if (size > fileSize) + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WaveParseHeader: '%c%c%c%c' chunk size exceeds length of file or is not zero-padded\n", + (char) (tag >> 24), (char) (tag >> 16), (char) (tag >> 8), (char) tag, size); */ } + break; + } + + /* subtract size of data chunk (including any zero-pad) */ + fileSize -= size; + + /* seek to next chunk */ + pos += (EAS_I32) size; + if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, pos)) != EAS_SUCCESS) + return result; + } + + /* check for valid header */ + if ((params.sampleRate == 0) || (params.size == 0)) + return EAS_ERROR_UNRECOGNIZED_FORMAT; + + /* save the pertinent information */ + pWaveData->audioOffset = audioOffset; + params.flags = pWaveData->flags; + + /* seek to data */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, audioOffset)) != EAS_SUCCESS) + return result; + + /* open a stream in the PCM engine */ + return EAS_PEOpenStream(pEASData, ¶ms, &pWaveData->streamHandle); +} + +/*---------------------------------------------------------------------------- + * WaveGetMetaData() + *---------------------------------------------------------------------------- + * Purpose: + * Process the INFO chunk and return metadata to host + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT WaveGetMetaData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pMediaLength) +{ + S_WAVE_STATE *pWaveData; + EAS_RESULT result; + EAS_I32 pos; + EAS_U32 size; + EAS_I32 infoSize; + EAS_U32 tag; + EAS_I32 restorePos; + E_EAS_METADATA_TYPE metaType; + EAS_I32 metaLen; + + /* get current position so we can restore it */ + pWaveData = (S_WAVE_STATE*) pInstData; + + /* return media length */ + *pMediaLength = pWaveData->mediaLength; + + /* did we encounter an INFO chunk? */ + if (pWaveData->infoChunkPos < 0) + return EAS_SUCCESS; + + if ((result = EAS_HWFilePos(pEASData->hwInstData, pWaveData->fileHandle, &restorePos)) != EAS_SUCCESS) + return result; + + /* offset to start of first chunk in INFO chunk */ + pos = pWaveData->infoChunkPos; + infoSize = pWaveData->infoChunkSize; + + /* read all the chunks in the INFO chunk */ + for (;;) + { + + /* seek to next chunk */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pWaveData->fileHandle, pos)) != EAS_SUCCESS) + return result; + + /* get tag and size for next chunk */ + if ((result = EAS_HWGetDWord(pEASData->hwInstData, pWaveData->fileHandle, &tag, EAS_TRUE)) != EAS_FALSE) + return result; + if ((result = EAS_HWGetDWord(pEASData->hwInstData, pWaveData->fileHandle, &size, EAS_FALSE)) != EAS_FALSE) + return result; + + /* process chunk */ + pos += 8; + metaType = EAS_METADATA_UNKNOWN; + switch (tag) + { + case CHUNK_INAM: + metaType = EAS_METADATA_TITLE; + break; + + case CHUNK_IART: + metaType = EAS_METADATA_AUTHOR; + break; + + case CHUNK_ICOP: + metaType = EAS_METADATA_COPYRIGHT; + break; + + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WaveParseHeader: %c%c%c%c chunk - %d byte(s) ignored\n", + (char) (tag >> 24), (char) (tag >> 16), (char) (tag >> 8), (char) tag, size); */ } + break; + } + + /* process known metadata */ + if (metaType != EAS_METADATA_UNKNOWN) + { + metaLen = pWaveData->metadata.bufferSize - 1; + if (metaLen > (EAS_I32) size) + metaLen = (EAS_I32) size; + if ((result = EAS_HWReadFile(pEASData->hwInstData, pWaveData->fileHandle, pWaveData->metadata.buffer, metaLen, &metaLen)) != EAS_SUCCESS) + return result; + pWaveData->metadata.buffer[metaLen] = 0; + pWaveData->metadata.callback(metaType, pWaveData->metadata.buffer, pWaveData->metadata.pUserData); + } + + /* subtract this block */ + if (size & 1) + size++; + infoSize -= (EAS_I32) size + 8; + if (infoSize == 0) + break; + pos += (EAS_I32) size; + } + + + /* restore original position */ + return EAS_HWFileSeek(pEASData->hwInstData, pWaveData->fileHandle, restorePos); +} + +#ifdef MMAPI_SUPPORT +/*---------------------------------------------------------------------------- + * SaveFmtChunk() + *---------------------------------------------------------------------------- + * Purpose: + * Save the fmt chunk for the MMAPI library + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT SaveFmtChunk (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, S_WAVE_STATE *pWaveData, EAS_I32 fmtSize) +{ + EAS_RESULT result; + EAS_I32 pos; + EAS_I32 count; + + /* save current file position */ + if ((result = EAS_HWFilePos(pEASData->hwInstData, fileHandle, &pos)) != EAS_SUCCESS) + return result; + + /* allocate a chunk of memory */ + pWaveData->fmtChunk = EAS_HWMalloc(pEASData->hwInstData, fmtSize); + if (!pWaveData->fmtChunk) + return EAS_ERROR_MALLOC_FAILED; + + /* read the fmt chunk into memory */ + if ((result = EAS_HWReadFile(pEASData->hwInstData, fileHandle, pWaveData->fmtChunk, fmtSize, &count)) != EAS_SUCCESS) + return result; + if (count != fmtSize) + return EAS_ERROR_FILE_READ_FAILED; + + /* restore file position */ + return EAS_HWFileSeek(pEASData->hwInstData, fileHandle, pos); +} +#endif + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_wavefile.h b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_wavefile.h new file mode 100755 index 0000000..f8814a8 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_wavefile.h @@ -0,0 +1,63 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_wavefile.h + * + * Contents and purpose: + * Static data block for wave file parser. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 439 $ + * $Date: 2006-10-26 11:53:18 -0700 (Thu, 26 Oct 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_WAVEFILE_H +#define _EAS_WAVEFILE_H + +#include "eas_data.h" +#include "eas_pcm.h" + +/*---------------------------------------------------------------------------- + * + * S_WAVE_STATE + * + * This structure contains the WAVE file parser state information + *---------------------------------------------------------------------------- +*/ +typedef struct s_wave_state_tag +{ + EAS_FILE_HANDLE fileHandle; + EAS_PCM_HANDLE streamHandle; + S_METADATA_CB metadata; + EAS_U32 time; + EAS_I32 fileOffset; + EAS_I32 audioOffset; + EAS_I32 mediaLength; + EAS_U32 audioSize; + EAS_U32 flags; + EAS_I16 fileType; +#ifdef MMAPI_SUPPORT + EAS_VOID_PTR fmtChunk; +#endif + EAS_I32 infoChunkPos; + EAS_I32 infoChunkSize; +} S_WAVE_STATE; + +#endif + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_wavefiledata.c b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_wavefiledata.c new file mode 100755 index 0000000..c224a6c --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_wavefiledata.c @@ -0,0 +1,33 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_wavefiledata.c + * + * Contents and purpose: + * Static data block for wave file parser. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 547 $ + * $Date: 2007-01-31 16:30:17 -0800 (Wed, 31 Jan 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_wavefile.h" + +S_WAVE_STATE eas_WaveData; + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_wt_IPC_frame.h b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_wt_IPC_frame.h new file mode 100755 index 0000000..29d77aa --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_wt_IPC_frame.h @@ -0,0 +1,82 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_wt_IPC_frame.h + * + * Contents and purpose: + * This module contains data definitions for the interprocessor + * communications framework for a split-architecture synthesizer. + * + * This sample version writes IPC data to a file that can be used + * as a test vector for the DSP simulator. For a real-time system + * the file I/O is replaced with an IPC protocol in the hardware. + * + * Synchronization with the DSP is accomplished at the API level, + * i.e. the host code should call EAS_Render when it is ready to + * buffer another block of data for transmission to the DSP. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 818 $ + * $Date: 2007-08-02 15:19:41 -0700 (Thu, 02 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_WT_IPC_FRAME_H +#define _EAS_WT_IPC_FRAME_H + +/*---------------------------------------------------------------------------- + * S_WT_FRAME + * + * This structure contains the common parameters that are updated + *for each frame of audio. + *---------------------------------------------------------------------------- +*/ +typedef struct s_wt_frame_tag +{ + EAS_I32 gainTarget; + EAS_I32 phaseIncrement; + +#if defined(_FILTER_ENABLED) + EAS_I32 k; + EAS_I32 b1; + EAS_I32 b2; +#endif +} S_WT_FRAME; + +/*---------------------------------------------------------------------------- + * S_WT_CONFIG + * + * This structure contains state data for the wavetable engine + *---------------------------------------------------------------------------- +*/ +typedef struct s_wt_config_tag +{ + EAS_U32 loopEnd; /* points to last PCM sample (not 1 beyond last) */ + EAS_U32 loopStart; /* points to first sample at start of loop */ + EAS_U32 phaseAccum; /* current sample, integer portion of phase */ + +#if (NUM_OUTPUT_CHANNELS == 2) + EAS_I16 gainLeft; /* left channel gain */ + EAS_I16 gainRight; /* right channel gain */ +#endif + + EAS_I16 gain; /* current voice gain */ +} S_WT_CONFIG; + +#endif + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_wtengine.c b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_wtengine.c new file mode 100755 index 0000000..224f60d --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_wtengine.c @@ -0,0 +1,661 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_wtengine.c + * + * Contents and purpose: + * This file contains the critical synthesizer components that need to + * be optimized for best performance. + * + * Copyright Sonic Network Inc. 2004-2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 844 $ + * $Date: 2007-08-23 14:33:32 -0700 (Thu, 23 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +/*------------------------------------ + * includes + *------------------------------------ +*/ +#include "eas_types.h" +#include "eas_math.h" +#include "eas_audioconst.h" +#include "eas_sndlib.h" +#include "eas_wtengine.h" +#include "eas_mixer.h" + +/*---------------------------------------------------------------------------- + * prototypes + *---------------------------------------------------------------------------- +*/ +extern void WT_NoiseGenerator (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame); +extern void WT_VoiceGain (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame); + +#if defined(_OPTIMIZED_MONO) +extern void WT_InterpolateMono (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame); +#else +extern void WT_InterpolateNoLoop (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame); +extern void WT_Interpolate (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame); +#endif + +#if defined(_FILTER_ENABLED) +extern void WT_VoiceFilter (S_FILTER_CONTROL*pFilter, S_WT_INT_FRAME *pWTIntFrame); +#endif + +#if defined(_OPTIMIZED_MONO) || !defined(NATIVE_EAS_KERNEL) +/*---------------------------------------------------------------------------- + * WT_VoiceGain + *---------------------------------------------------------------------------- + * Purpose: + * Output gain for individual voice + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pWTVoice) reserved for future use */ +void WT_VoiceGain (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame) +{ + EAS_I32 *pMixBuffer; + EAS_PCM *pInputBuffer; + EAS_I32 gain; + EAS_I32 gainIncrement; + EAS_I32 tmp0; + EAS_I32 tmp1; + EAS_I32 tmp2; + EAS_I32 numSamples; + +#if (NUM_OUTPUT_CHANNELS == 2) + EAS_I32 gainLeft, gainRight; +#endif + + /* initialize some local variables */ + numSamples = pWTIntFrame->numSamples; + pMixBuffer = pWTIntFrame->pMixBuffer; + pInputBuffer = pWTIntFrame->pAudioBuffer; + + /*lint -e{703} */ + gainIncrement = (pWTIntFrame->frame.gainTarget - pWTIntFrame->prevGain) << (16 - SYNTH_UPDATE_PERIOD_IN_BITS); + if (gainIncrement < 0) + gainIncrement++; + /*lint -e{703} */ + gain = pWTIntFrame->prevGain << 16; + +#if (NUM_OUTPUT_CHANNELS == 2) + gainLeft = pWTVoice->gainLeft; + gainRight = pWTVoice->gainRight; +#endif + + while (numSamples--) { + + /* incremental gain step to prevent zipper noise */ + tmp0 = *pInputBuffer++; + gain += gainIncrement; + /*lint -e{704} */ + tmp2 = gain >> 16; + + /* scale sample by gain */ + tmp2 *= tmp0; + + + /* stereo output */ +#if (NUM_OUTPUT_CHANNELS == 2) + /*lint -e{704} */ + tmp2 = tmp2 >> 14; + + /* get the current sample in the final mix buffer */ + tmp1 = *pMixBuffer; + + /* left channel */ + tmp0 = tmp2 * gainLeft; + /*lint -e{704} */ + tmp0 = tmp0 >> NUM_MIXER_GUARD_BITS; + tmp1 += tmp0; + *pMixBuffer++ = tmp1; + + /* get the current sample in the final mix buffer */ + tmp1 = *pMixBuffer; + + /* right channel */ + tmp0 = tmp2 * gainRight; + /*lint -e{704} */ + tmp0 = tmp0 >> NUM_MIXER_GUARD_BITS; + tmp1 += tmp0; + *pMixBuffer++ = tmp1; + + /* mono output */ +#else + + /* get the current sample in the final mix buffer */ + tmp1 = *pMixBuffer; + /*lint -e{704} */ + tmp2 = tmp2 >> (NUM_MIXER_GUARD_BITS - 1); + tmp1 += tmp2; + *pMixBuffer++ = tmp1; +#endif + + } +} +#endif + +#ifndef NATIVE_EAS_KERNEL +/*---------------------------------------------------------------------------- + * WT_Interpolate + *---------------------------------------------------------------------------- + * Purpose: + * Interpolation engine for wavetable synth + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +void WT_Interpolate (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame) +{ + EAS_PCM *pOutputBuffer; + EAS_I32 phaseInc; + EAS_I32 phaseFrac; + EAS_I32 acc0; + const EAS_SAMPLE *pSamples; + const EAS_SAMPLE *loopEnd; + EAS_I32 samp1; + EAS_I32 samp2; + EAS_I32 numSamples; + + /* initialize some local variables */ + numSamples = pWTIntFrame->numSamples; + pOutputBuffer = pWTIntFrame->pAudioBuffer; + + loopEnd = (const EAS_SAMPLE*) pWTVoice->loopEnd + 1; + pSamples = (const EAS_SAMPLE*) pWTVoice->phaseAccum; + /*lint -e{713} truncation is OK */ + phaseFrac = pWTVoice->phaseFrac; + phaseInc = pWTIntFrame->frame.phaseIncrement; + + /* fetch adjacent samples */ +#if defined(_8_BIT_SAMPLES) + /*lint -e{701} */ + samp1 = pSamples[0] << 8; + /*lint -e{701} */ + samp2 = pSamples[1] << 8; +#else + samp1 = pSamples[0]; + samp2 = pSamples[1]; +#endif + + while (numSamples--) { + + /* linear interpolation */ + acc0 = samp2 - samp1; + acc0 = acc0 * phaseFrac; + /*lint -e{704} */ + acc0 = samp1 + (acc0 >> NUM_PHASE_FRAC_BITS); + + /* save new output sample in buffer */ + /*lint -e{704} */ + *pOutputBuffer++ = (EAS_I16)(acc0 >> 2); + + /* increment phase */ + phaseFrac += phaseInc; + /*lint -e{704} */ + acc0 = phaseFrac >> NUM_PHASE_FRAC_BITS; + + /* next sample */ + if (acc0 > 0) { + + /* advance sample pointer */ + pSamples += acc0; + phaseFrac = (EAS_I32)((EAS_U32)phaseFrac & PHASE_FRAC_MASK); + + /* check for loop end */ + acc0 = (EAS_I32) (pSamples - loopEnd); + if (acc0 >= 0) + pSamples = (const EAS_SAMPLE*) pWTVoice->loopStart + acc0; + + /* fetch new samples */ +#if defined(_8_BIT_SAMPLES) + /*lint -e{701} */ + samp1 = pSamples[0] << 8; + /*lint -e{701} */ + samp2 = pSamples[1] << 8; +#else + samp1 = pSamples[0]; + samp2 = pSamples[1]; +#endif + } + } + + /* save pointer and phase */ + pWTVoice->phaseAccum = (EAS_U32) pSamples; + pWTVoice->phaseFrac = (EAS_U32) phaseFrac; +} +#endif + +#ifndef NATIVE_EAS_KERNEL +/*---------------------------------------------------------------------------- + * WT_InterpolateNoLoop + *---------------------------------------------------------------------------- + * Purpose: + * Interpolation engine for wavetable synth + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +void WT_InterpolateNoLoop (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame) +{ + EAS_PCM *pOutputBuffer; + EAS_I32 phaseInc; + EAS_I32 phaseFrac; + EAS_I32 acc0; + const EAS_SAMPLE *pSamples; + EAS_I32 samp1; + EAS_I32 samp2; + EAS_I32 numSamples; + + /* initialize some local variables */ + numSamples = pWTIntFrame->numSamples; + pOutputBuffer = pWTIntFrame->pAudioBuffer; + + phaseInc = pWTIntFrame->frame.phaseIncrement; + pSamples = (const EAS_SAMPLE*) pWTVoice->phaseAccum; + phaseFrac = (EAS_I32)pWTVoice->phaseFrac; + + /* fetch adjacent samples */ +#if defined(_8_BIT_SAMPLES) + /*lint -e{701} */ + samp1 = pSamples[0] << 8; + /*lint -e{701} */ + samp2 = pSamples[1] << 8; +#else + samp1 = pSamples[0]; + samp2 = pSamples[1]; +#endif + + while (numSamples--) { + + + /* linear interpolation */ + acc0 = samp2 - samp1; + acc0 = acc0 * phaseFrac; + /*lint -e{704} */ + acc0 = samp1 + (acc0 >> NUM_PHASE_FRAC_BITS); + + /* save new output sample in buffer */ + /*lint -e{704} */ + *pOutputBuffer++ = (EAS_I16)(acc0 >> 2); + + /* increment phase */ + phaseFrac += phaseInc; + /*lint -e{704} */ + acc0 = phaseFrac >> NUM_PHASE_FRAC_BITS; + + /* next sample */ + if (acc0 > 0) { + + /* advance sample pointer */ + pSamples += acc0; + phaseFrac = (EAS_I32)((EAS_U32)phaseFrac & PHASE_FRAC_MASK); + + /* fetch new samples */ +#if defined(_8_BIT_SAMPLES) + /*lint -e{701} */ + samp1 = pSamples[0] << 8; + /*lint -e{701} */ + samp2 = pSamples[1] << 8; +#else + samp1 = pSamples[0]; + samp2 = pSamples[1]; +#endif + } + } + + /* save pointer and phase */ + pWTVoice->phaseAccum = (EAS_U32) pSamples; + pWTVoice->phaseFrac = (EAS_U32) phaseFrac; +} +#endif + +#if defined(_FILTER_ENABLED) && !defined(NATIVE_EAS_KERNEL) +/*---------------------------------------------------------------------------- + * WT_VoiceFilter + *---------------------------------------------------------------------------- + * Purpose: + * Implements a 2-pole filter + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +void WT_VoiceFilter (S_FILTER_CONTROL *pFilter, S_WT_INT_FRAME *pWTIntFrame) +{ + EAS_PCM *pAudioBuffer; + EAS_I32 k; + EAS_I32 b1; + EAS_I32 b2; + EAS_I32 z1; + EAS_I32 z2; + EAS_I32 acc0; + EAS_I32 acc1; + EAS_I32 numSamples; + + /* initialize some local variables */ + numSamples = pWTIntFrame->numSamples; + pAudioBuffer = pWTIntFrame->pAudioBuffer; + + z1 = pFilter->z1; + z2 = pFilter->z2; + b1 = -pWTIntFrame->frame.b1; + + /*lint -e{702} */ + b2 = -pWTIntFrame->frame.b2 >> 1; + + /*lint -e{702} */ + k = pWTIntFrame->frame.k >> 1; + + while (numSamples--) + { + + /* do filter calculations */ + acc0 = *pAudioBuffer; + acc1 = z1 * b1; + acc1 += z2 * b2; + acc0 = acc1 + k * acc0; + z2 = z1; + + /*lint -e{702} */ + z1 = acc0 >> 14; + *pAudioBuffer++ = (EAS_I16) z1; + } + + /* save delay values */ + pFilter->z1 = (EAS_I16) z1; + pFilter->z2 = (EAS_I16) z2; +} +#endif + +/*---------------------------------------------------------------------------- + * WT_NoiseGenerator + *---------------------------------------------------------------------------- + * Purpose: + * Generate pseudo-white noise using PRNG and interpolation engine + * + * Inputs: + * + * Outputs: + * + * Notes: + * This output is scaled -12dB to prevent saturation in the filter. For a + * high quality synthesizer, the output can be set to full scale, however + * if the filter is used, it can overflow with certain coefficients. In this + * case, either a saturation operation should take in the filter before + * scaling back to 16 bits or the signal path should be increased to 18 bits + * or more. + *---------------------------------------------------------------------------- +*/ + void WT_NoiseGenerator (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame) + { + EAS_PCM *pOutputBuffer; + EAS_I32 phaseInc; + EAS_I32 tmp0; + EAS_I32 tmp1; + EAS_I32 nInterpolatedSample; + EAS_I32 numSamples; + + /* initialize some local variables */ + numSamples = pWTIntFrame->numSamples; + pOutputBuffer = pWTIntFrame->pAudioBuffer; + phaseInc = pWTIntFrame->frame.phaseIncrement; + + /* get last two samples generated */ + /*lint -e{704} */ + tmp0 = (EAS_I32) (pWTVoice->phaseAccum) >> 18; + /*lint -e{704} */ + tmp1 = (EAS_I32) (pWTVoice->loopEnd) >> 18; + + /* generate a buffer of noise */ + while (numSamples--) { + nInterpolatedSample = MULT_AUDIO_COEF( tmp0, (PHASE_ONE - pWTVoice->phaseFrac)); + nInterpolatedSample += MULT_AUDIO_COEF( tmp1, pWTVoice->phaseFrac); + *pOutputBuffer++ = (EAS_PCM) nInterpolatedSample; + + /* update PRNG */ + pWTVoice->phaseFrac += (EAS_U32) phaseInc; + if (GET_PHASE_INT_PART(pWTVoice->phaseFrac)) { + tmp0 = tmp1; + pWTVoice->phaseAccum = pWTVoice->loopEnd; + pWTVoice->loopEnd = (5 * pWTVoice->loopEnd + 1); + tmp1 = (EAS_I32) (pWTVoice->loopEnd) >> 18; + pWTVoice->phaseFrac = GET_PHASE_FRAC_PART(pWTVoice->phaseFrac); + } + + } +} + +#ifndef _OPTIMIZED_MONO +/*---------------------------------------------------------------------------- + * WT_ProcessVoice + *---------------------------------------------------------------------------- + * Purpose: + * This routine does the block processing for one voice. It is isolated + * from the main synth code to allow for various implementation-specific + * optimizations. It calls the interpolator, filter, and gain routines + * appropriate for a particular configuration. + * + * Inputs: + * + * Outputs: + * + * Notes: + *---------------------------------------------------------------------------- +*/ +void WT_ProcessVoice (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame) +{ + + /* use noise generator */ + if (pWTVoice->loopStart == WT_NOISE_GENERATOR) + WT_NoiseGenerator(pWTVoice, pWTIntFrame); + + /* generate interpolated samples for looped waves */ + else if (pWTVoice->loopStart != pWTVoice->loopEnd) + WT_Interpolate(pWTVoice, pWTIntFrame); + + /* generate interpolated samples for unlooped waves */ + else + { + WT_InterpolateNoLoop(pWTVoice, pWTIntFrame); + } + +#ifdef _FILTER_ENABLED + if (pWTIntFrame->frame.k != 0) + WT_VoiceFilter(&pWTVoice->filter, pWTIntFrame); +#endif + +//2 TEST NEW MIXER FUNCTION +#ifdef UNIFIED_MIXER + { + EAS_I32 gainLeft, gainIncLeft; + +#if (NUM_OUTPUT_CHANNELS == 2) + EAS_I32 gainRight, gainIncRight; +#endif + + gainLeft = (pWTIntFrame->prevGain * pWTVoice->gainLeft) << 1; + gainIncLeft = (((pWTIntFrame->frame.gainTarget * pWTVoice->gainLeft) << 1) - gainLeft) >> SYNTH_UPDATE_PERIOD_IN_BITS; + +#if (NUM_OUTPUT_CHANNELS == 2) + gainRight = (pWTIntFrame->prevGain * pWTVoice->gainRight) << 1; + gainIncRight = (((pWTIntFrame->frame.gainTarget * pWTVoice->gainRight) << 1) - gainRight) >> SYNTH_UPDATE_PERIOD_IN_BITS; + EAS_MixStream( + pWTIntFrame->pAudioBuffer, + pWTIntFrame->pMixBuffer, + pWTIntFrame->numSamples, + gainLeft, + gainRight, + gainIncLeft, + gainIncRight, + MIX_FLAGS_STEREO_OUTPUT); + +#else + EAS_MixStream( + pWTIntFrame->pAudioBuffer, + pWTIntFrame->pMixBuffer, + pWTIntFrame->numSamples, + gainLeft, + 0, + gainIncLeft, + 0, + 0); +#endif + } + +#else + /* apply gain, and left and right gain */ + WT_VoiceGain(pWTVoice, pWTIntFrame); +#endif +} +#endif + +#if defined(_OPTIMIZED_MONO) && !defined(NATIVE_EAS_KERNEL) +/*---------------------------------------------------------------------------- + * WT_InterpolateMono + *---------------------------------------------------------------------------- + * Purpose: + * A C version of the sample interpolation + gain routine, optimized for mono. + * It's not pretty, but it matches the assembly code exactly. + * + * Inputs: + * + * Outputs: + * + * Notes: + *---------------------------------------------------------------------------- +*/ +void WT_InterpolateMono (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame) +{ + EAS_I32 *pMixBuffer; + const EAS_I8 *pLoopEnd; + const EAS_I8 *pCurrentPhaseInt; + EAS_I32 numSamples; + EAS_I32 gain; + EAS_I32 gainIncrement; + EAS_I32 currentPhaseFrac; + EAS_I32 phaseInc; + EAS_I32 tmp0; + EAS_I32 tmp1; + EAS_I32 tmp2; + EAS_I8 *pLoopStart; + + numSamples = pWTIntFrame->numSamples; + pMixBuffer = pWTIntFrame->pMixBuffer; + + /* calculate gain increment */ + gainIncrement = (pWTIntFrame->gainTarget - pWTIntFrame->prevGain) << (16 - SYNTH_UPDATE_PERIOD_IN_BITS); + if (gainIncrement < 0) + gainIncrement++; + gain = pWTIntFrame->prevGain << 16; + + pCurrentPhaseInt = pWTVoice->pPhaseAccum; + currentPhaseFrac = pWTVoice->phaseFrac; + phaseInc = pWTIntFrame->phaseIncrement; + + pLoopStart = pWTVoice->pLoopStart; + pLoopEnd = pWTVoice->pLoopEnd + 1; + +InterpolationLoop: + tmp0 = (EAS_I32)(pCurrentPhaseInt - pLoopEnd); + if (tmp0 >= 0) + pCurrentPhaseInt = pLoopStart + tmp0; + + tmp0 = *pCurrentPhaseInt; + tmp1 = *(pCurrentPhaseInt + 1); + + tmp2 = phaseInc + currentPhaseFrac; + + tmp1 = tmp1 - tmp0; + tmp1 = tmp1 * currentPhaseFrac; + + tmp1 = tmp0 + (tmp1 >> NUM_EG1_FRAC_BITS); + + pCurrentPhaseInt += (tmp2 >> NUM_PHASE_FRAC_BITS); + currentPhaseFrac = tmp2 & PHASE_FRAC_MASK; + + gain += gainIncrement; + tmp2 = (gain >> SYNTH_UPDATE_PERIOD_IN_BITS); + + tmp0 = *pMixBuffer; + tmp2 = tmp1 * tmp2; + tmp2 = (tmp2 >> 9); + tmp0 = tmp2 + tmp0; + *pMixBuffer++ = tmp0; + + numSamples--; + if (numSamples > 0) + goto InterpolationLoop; + + pWTVoice->pPhaseAccum = pCurrentPhaseInt; + pWTVoice->phaseFrac = currentPhaseFrac; + /*lint -e{702} */ + pWTVoice->gain = (EAS_I16)(gain >> SYNTH_UPDATE_PERIOD_IN_BITS); +} +#endif + +#ifdef _OPTIMIZED_MONO +/*---------------------------------------------------------------------------- + * WT_ProcessVoice + *---------------------------------------------------------------------------- + * Purpose: + * This routine does the block processing for one voice. It is isolated + * from the main synth code to allow for various implementation-specific + * optimizations. It calls the interpolator, filter, and gain routines + * appropriate for a particular configuration. + * + * Inputs: + * + * Outputs: + * + * Notes: + * This special version works handles an optimized mono-only signal + * without filters + *---------------------------------------------------------------------------- +*/ +void WT_ProcessVoice (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame) +{ + + /* use noise generator */ + if (pWTVoice->loopStart== WT_NOISE_GENERATOR) + { + WT_NoiseGenerator(pWTVoice, pWTIntFrame); + WT_VoiceGain(pWTVoice, pWTIntFrame); + } + + /* or generate interpolated samples */ + else + { + WT_InterpolateMono(pWTVoice, pWTIntFrame); + } +} +#endif + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_wtengine.h b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_wtengine.h new file mode 100755 index 0000000..bba7a5e --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_wtengine.h @@ -0,0 +1,171 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_wtengine.h + * + * Contents and purpose: + * This file defines the interface for wavetable synthesis engine + * + * Copyright Sonic Network Inc. 2004 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 818 $ + * $Date: 2007-08-02 15:19:41 -0700 (Thu, 02 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_WTENGINE_H +#define _EAS_WTENGINE_H + +/* option sanity check */ +#if defined(_OPTIMIZED_MONO) && defined(_FILTER_ENABLED) +#error "Incompatible build settings: _OPTIMIZED_MONO cannot be used with _FILTER_ENABLED" +#endif + +#if defined(_OPTIMIZED_MONO) && (NUM_OUTPUT_CHANNELS != 1) +#error "Incompatible build settings: _OPTIMIZED_MONO can only be used with NUM_OUTPUT_CHANNELS = 1" +#endif + +#include "eas_wt_IPC_frame.h" + +/*---------------------------------------------------------------------------- + * defines + *---------------------------------------------------------------------------- +*/ +#define WT_NOISE_GENERATOR 0xffffffff + +/*---------------------------------------------------------------------------- + * typedefs + *---------------------------------------------------------------------------- +*/ + +/*---------------------------------------------------------------------------- + * S_WT_INT_FRAME + * + * This structure includes S_WT_FRAME plus the bus mixing + * parameters for the internal voices. + *---------------------------------------------------------------------------- +*/ +typedef struct s_wt_int_frame_tag +{ + S_WT_FRAME frame; + EAS_PCM *pAudioBuffer; + EAS_I32 *pMixBuffer; + EAS_I32 numSamples; + EAS_I32 prevGain; +} S_WT_INT_FRAME; + +#if defined(_FILTER_ENABLED) +/*---------------------------------------------------------------------------- + * S_FILTER_CONTROL data structure + *---------------------------------------------------------------------------- +*/ +typedef struct s_filter_control_tag +{ + EAS_I16 z1; /* 1 sample delay state variable */ + EAS_I16 z2; /* 2 sample delay state variable */ +} S_FILTER_CONTROL; +#endif + +/*------------------------------------ + * S_LFO_CONTROL data structure + *------------------------------------ +*/ +typedef struct s_lfo_control_tag +{ + EAS_I16 lfoValue; /* LFO current output value */ + EAS_I16 lfoPhase; /* LFO current phase */ +} S_LFO_CONTROL; + +/* bit definitions for S_WT_VOICE:flags */ +#define WT_FLAGS_ADPCM_NIBBLE 1 /* high/low nibble flag */ +#define WT_FLAGS_ADPCM_READY 2 /* first 2 samples are decoded */ +#define WT_FLAGS_USE_ADPCM 4 /* sample is ADPCM encoded */ + +/* eg1State and eg2State */ +typedef enum { + eEnvelopeStateInit = 0, + eEnvelopeStateDelay, + eEnvelopeStateAttack, + eEnvelopeStateHold, + eEnvelopeStateDecay, + eEnvelopeStateSustain, + eEnvelopeStateRelease, + eEnvelopeStateMuting, + eEnvelopeStateMuted, + eEnvelopeStateInvalid /* should never be in this state! */ +} E_ENVELOPE_STATE; + +#define DEFAULT_EG1_STATE eEnvelopeStateAttack +#define DEFAULT_EG1_VALUE 0 +#define DEFAULT_EG1_INCREMENT 0 +#define DEFAULT_EG2_STATE eEnvelopeStateAttack +#define DEFAULT_EG2_VALUE 0 +#define DEFAULT_EG2_INCREMENT 0 + +/*---------------------------------------------------------------------------- + * S_WT_VOICE + * + * This structure contains state data for the wavetable engine + *---------------------------------------------------------------------------- +*/ +typedef struct s_wt_voice_tag +{ + EAS_U32 loopEnd; /* points to last PCM sample (not 1 beyond last) */ + EAS_U32 loopStart; /* points to first sample at start of loop */ + EAS_U32 phaseAccum; /* current sample, integer portion of phase */ + EAS_U32 phaseFrac; /* fractional portion of phase */ + +#if (NUM_OUTPUT_CHANNELS == 2) + EAS_I16 gainLeft; /* current gain, left ch */ + EAS_I16 gainRight; /* current gain, right ch */ +#endif + +#if defined(_FILTER_ENABLED) + S_FILTER_CONTROL filter; /* low pass filter */ +#endif + + S_LFO_CONTROL modLFO; /* modulator LFO */ + +#ifdef DLS_SYNTHESIZER + S_LFO_CONTROL vibLFO; /* vibrato LFO */ +#endif + + /* envelope control */ + EAS_I16 eg1Value; + EAS_I16 eg2Value; + EAS_I16 eg1Increment; + EAS_I16 eg2Increment; + EAS_U8 eg1State; + EAS_U8 eg2State; + + EAS_U16 artIndex; /* index to articulation params */ + +} S_WT_VOICE; + +/*---------------------------------------------------------------------------- + * prototypes + *---------------------------------------------------------------------------- +*/ +EAS_BOOL WT_CheckSampleEnd (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame, EAS_BOOL update); +void WT_ProcessVoice (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame); + +#ifdef EAS_SPLIT_WT_SYNTH +void WTE_ConfigVoice (EAS_I32 voiceNum, S_WT_CONFIG *pWTConfig, EAS_FRAME_BUFFER_HANDLE pFrameBuffer); +void WTE_ProcessVoice (EAS_I32 voiceNum, S_WT_FRAME *pWTParams, EAS_FRAME_BUFFER_HANDLE pFrameBuffer); +#endif + +#endif diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_wtsynth.c b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_wtsynth.c new file mode 100755 index 0000000..45cf4b1 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_wtsynth.c @@ -0,0 +1,1257 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_wtsynth.c + * + * Contents and purpose: + * Implements the synthesizer functions. + * + * Copyright Sonic Network Inc. 2004 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 795 $ + * $Date: 2007-08-01 00:14:45 -0700 (Wed, 01 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +// includes +#include "eas_data.h" +#include "eas_report.h" +#include "eas_host.h" +#include "eas_math.h" +#include "eas_synth_protos.h" +#include "eas_wtsynth.h" +#include "eas_pan.h" + +#ifdef DLS_SYNTHESIZER +#include "eas_dlssynth.h" +#endif + +#ifdef _METRICS_ENABLED +#include "eas_perf.h" +#endif + +/* local prototypes */ +static EAS_RESULT WT_Initialize(S_VOICE_MGR *pVoiceMgr); +static void WT_ReleaseVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum); +static void WT_MuteVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum); +static void WT_SustainPedal (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, S_SYNTH_CHANNEL *pChannel, EAS_I32 voiceNum); +static EAS_RESULT WT_StartVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_U16 regionIndex); +static EAS_BOOL WT_UpdateVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_I32 *pMixBuffer, EAS_I32 numSamples); +static void WT_UpdateChannel (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel); +static EAS_I32 WT_UpdatePhaseInc (S_WT_VOICE *pWTVoice, const S_ARTICULATION *pArt, S_SYNTH_CHANNEL *pChannel, EAS_I32 pitchCents); +static EAS_I32 WT_UpdateGain (S_SYNTH_VOICE *pVoice, S_WT_VOICE *pWTVoice, const S_ARTICULATION *pArt, S_SYNTH_CHANNEL *pChannel, EAS_I32 gain); +static void WT_UpdateEG1 (S_WT_VOICE *pWTVoice, const S_ENVELOPE *pEnv); +static void WT_UpdateEG2 (S_WT_VOICE *pWTVoice, const S_ENVELOPE *pEnv); + +#ifdef EAS_SPLIT_WT_SYNTH +extern EAS_BOOL WTE_StartFrame (EAS_FRAME_BUFFER_HANDLE pFrameBuffer); +extern EAS_BOOL WTE_EndFrame (EAS_FRAME_BUFFER_HANDLE pFrameBuffer, EAS_I32 *pMixBuffer, EAS_I16 masterGain); +#endif + +#ifdef _FILTER_ENABLED +static void WT_UpdateFilter (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pIntFrame, const S_ARTICULATION *pArt); +#endif + +#ifdef _STATS +extern double statsPhaseIncrement; +extern double statsMaxPhaseIncrement; +extern long statsPhaseSampleCount; +extern double statsSampleSize; +extern long statsSampleCount; +#endif + +/*---------------------------------------------------------------------------- + * Synthesizer interface + *---------------------------------------------------------------------------- +*/ + +const S_SYNTH_INTERFACE wtSynth = +{ + WT_Initialize, + WT_StartVoice, + WT_UpdateVoice, + WT_ReleaseVoice, + WT_MuteVoice, + WT_SustainPedal, + WT_UpdateChannel +}; + +#ifdef EAS_SPLIT_WT_SYNTH +const S_FRAME_INTERFACE wtFrameInterface = +{ + WTE_StartFrame, + WTE_EndFrame +}; +#endif + +/*---------------------------------------------------------------------------- + * WT_Initialize() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * pVoice - pointer to voice to initialize + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT WT_Initialize (S_VOICE_MGR *pVoiceMgr) +{ + EAS_INT i; + + for (i = 0; i < NUM_WT_VOICES; i++) + { + + pVoiceMgr->wtVoices[i].artIndex = DEFAULT_ARTICULATION_INDEX; + + pVoiceMgr->wtVoices[i].eg1State = DEFAULT_EG1_STATE; + pVoiceMgr->wtVoices[i].eg1Value = DEFAULT_EG1_VALUE; + pVoiceMgr->wtVoices[i].eg1Increment = DEFAULT_EG1_INCREMENT; + + pVoiceMgr->wtVoices[i].eg2State = DEFAULT_EG2_STATE; + pVoiceMgr->wtVoices[i].eg2Value = DEFAULT_EG2_VALUE; + pVoiceMgr->wtVoices[i].eg2Increment = DEFAULT_EG2_INCREMENT; + + /* left and right gain values are needed only if stereo output */ +#if (NUM_OUTPUT_CHANNELS == 2) + pVoiceMgr->wtVoices[i].gainLeft = DEFAULT_VOICE_GAIN; + pVoiceMgr->wtVoices[i].gainRight = DEFAULT_VOICE_GAIN; +#endif + + pVoiceMgr->wtVoices[i].phaseFrac = DEFAULT_PHASE_FRAC; + pVoiceMgr->wtVoices[i].phaseAccum = DEFAULT_PHASE_INT; + +#ifdef _FILTER_ENABLED + pVoiceMgr->wtVoices[i].filter.z1 = DEFAULT_FILTER_ZERO; + pVoiceMgr->wtVoices[i].filter.z2 = DEFAULT_FILTER_ZERO; +#endif + } + + return EAS_TRUE; +} + +/*---------------------------------------------------------------------------- + * WT_ReleaseVoice() + *---------------------------------------------------------------------------- + * Purpose: + * The selected voice is being released. + * + * Inputs: + * pEASData - pointer to S_EAS_DATA + * pVoice - pointer to voice to release + * + * Outputs: + * None + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pVoice) used in some implementations */ +static void WT_ReleaseVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum) +{ + S_WT_VOICE *pWTVoice; + const S_ARTICULATION *pArticulation; + +#ifdef DLS_SYNTHESIZER + if (pVoice->regionIndex & FLAG_RGN_IDX_DLS_SYNTH) + { + DLS_ReleaseVoice(pVoiceMgr, pSynth, pVoice, voiceNum); + return; + } +#endif + + pWTVoice = &pVoiceMgr->wtVoices[voiceNum]; + pArticulation = &pSynth->pEAS->pArticulations[pWTVoice->artIndex]; + + /* release EG1 */ + pWTVoice->eg1State = eEnvelopeStateRelease; + pWTVoice->eg1Increment = pArticulation->eg1.releaseTime; + + /* + The spec says we should release EG2, but doing so with the current + voicing is causing clicks. This fix will need to be coordinated with + a new sound library release + */ + + /* release EG2 */ + pWTVoice->eg2State = eEnvelopeStateRelease; + pWTVoice->eg2Increment = pArticulation->eg2.releaseTime; +} + +/*---------------------------------------------------------------------------- + * WT_MuteVoice() + *---------------------------------------------------------------------------- + * Purpose: + * The selected voice is being muted. + * + * Inputs: + * pVoice - pointer to voice to release + * + * Outputs: + * None + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pSynth) used in some implementations */ +static void WT_MuteVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum) +{ + +#ifdef DLS_SYNTHESIZER + if (pVoice->regionIndex & FLAG_RGN_IDX_DLS_SYNTH) + { + DLS_MuteVoice(pVoiceMgr, pSynth, pVoice, voiceNum); + return; + } +#endif + + /* clear deferred action flags */ + pVoice->voiceFlags &= + ~(VOICE_FLAG_DEFER_MIDI_NOTE_OFF | + VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF | + VOICE_FLAG_DEFER_MUTE); + + /* set the envelope state */ + pVoiceMgr->wtVoices[voiceNum].eg1State = eEnvelopeStateMuted; + pVoiceMgr->wtVoices[voiceNum].eg2State = eEnvelopeStateMuted; +} + +/*---------------------------------------------------------------------------- + * WT_SustainPedal() + *---------------------------------------------------------------------------- + * Purpose: + * The selected voice is held due to sustain pedal + * + * Inputs: + * pVoice - pointer to voice to sustain + * + * Outputs: + * None + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pChannel) used in some implementations */ +static void WT_SustainPedal (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, S_SYNTH_CHANNEL *pChannel, EAS_I32 voiceNum) +{ + S_WT_VOICE *pWTVoice; + +#ifdef DLS_SYNTHESIZER + if (pVoice->regionIndex & FLAG_RGN_IDX_DLS_SYNTH) + { + DLS_SustainPedal(pVoiceMgr, pSynth, pVoice, pChannel, voiceNum); + return; + } +#endif + + /* don't catch the voice if below the sustain level */ + pWTVoice = &pVoiceMgr->wtVoices[voiceNum]; + if (pWTVoice->eg1Value < pSynth->pEAS->pArticulations[pWTVoice->artIndex].eg1.sustainLevel) + return; + + /* sustain flag is set, damper pedal is on */ + /* defer releasing this note until the damper pedal is off */ + pWTVoice->eg1State = eEnvelopeStateDecay; + pVoice->voiceState = eVoiceStatePlay; + + /* + because sustain pedal is on, this voice + should defer releasing its note + */ + pVoice->voiceFlags |= VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF; + +#ifdef _DEBUG_SYNTH + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WT_SustainPedal: defer note off because sustain pedal is on\n"); */ } +#endif +} + +/*---------------------------------------------------------------------------- + * WT_StartVoice() + *---------------------------------------------------------------------------- + * Purpose: + * Assign the region for the given instrument using the midi key number + * and the RPN2 (coarse tuning) value. By using RPN2 as part of the + * region selection process, we reduce the amount a given sample has + * to be transposed by selecting the closest recorded root instead. + * + * This routine is the second half of SynthAssignRegion(). + * If the region was successfully found by SynthFindRegionIndex(), + * then assign the region's parameters to the voice. + * + * Setup and initialize the following voice parameters: + * m_nRegionIndex + * + * Inputs: + * pVoice - ptr to the voice we have assigned for this channel + * nRegionIndex - index of the region + * pEASData - pointer to overall EAS data structure + * + * Outputs: + * success - could find and assign the region for this voice's note otherwise + * failure - could not find nor assign the region for this voice's note + * + * Side Effects: + * psSynthObject->m_sVoice[].m_nRegionIndex is assigned + * psSynthObject->m_sVoice[] parameters are assigned + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT WT_StartVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_U16 regionIndex) +{ + S_WT_VOICE *pWTVoice; + const S_WT_REGION *pRegion; + const S_ARTICULATION *pArt; + S_SYNTH_CHANNEL *pChannel; + +#if (NUM_OUTPUT_CHANNELS == 2) + EAS_INT pan; +#endif + +#ifdef EAS_SPLIT_WT_SYNTH + S_WT_CONFIG wtConfig; +#endif + + /* no samples have been synthesized for this note yet */ + pVoice->regionIndex = regionIndex; + pVoice->voiceFlags = VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET; + + /* get the articulation index for this region */ + pWTVoice = &pVoiceMgr->wtVoices[voiceNum]; + pChannel = &pSynth->channels[pVoice->channel & 15]; + + /* update static channel parameters */ + if (pChannel->channelFlags & CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS) + WT_UpdateChannel(pVoiceMgr, pSynth, pVoice->channel & 15); + +#ifdef DLS_SYNTHESIZER + if (pVoice->regionIndex & FLAG_RGN_IDX_DLS_SYNTH) + return DLS_StartVoice(pVoiceMgr, pSynth, pVoice, voiceNum, regionIndex); +#endif + + pRegion = &(pSynth->pEAS->pWTRegions[regionIndex]); + pWTVoice->artIndex = pRegion->artIndex; + +#ifdef _DEBUG_SYNTH + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WT_StartVoice: Voice %ld; Region %d\n", (EAS_I32) (pVoice - pVoiceMgr->voices), regionIndex); */ } +#endif + + pArt = &pSynth->pEAS->pArticulations[pWTVoice->artIndex]; + + /* MIDI note on puts this voice into attack state */ + pWTVoice->eg1State = eEnvelopeStateAttack; + pWTVoice->eg1Value = 0; + pWTVoice->eg1Increment = pArt->eg1.attackTime; + pWTVoice->eg2State = eEnvelopeStateAttack; + pWTVoice->eg2Value = 0; + pWTVoice->eg2Increment = pArt->eg2.attackTime; + + /* init the LFO */ + pWTVoice->modLFO.lfoValue = 0; + pWTVoice->modLFO.lfoPhase = -pArt->lfoDelay; + + pVoice->gain = 0; + +#if (NUM_OUTPUT_CHANNELS == 2) + /* + Get the Midi CC10 pan value for this voice's channel + convert the pan value to an "angle" representation suitable for + our sin, cos calculator. This representation is NOT necessarily the same + as the transform in the GM manuals because of our sin, cos calculator. + "angle" = (CC10 - 64)/128 + */ + pan = (EAS_INT) pSynth->channels[pVoice->channel & 15].pan - 64; + pan += pArt->pan; + EAS_CalcPanControl(pan, &pWTVoice->gainLeft, &pWTVoice->gainRight); +#endif + +#ifdef _FILTER_ENABLED + /* clear out the filter states */ + pWTVoice->filter.z1 = 0; + pWTVoice->filter.z2 = 0; +#endif + + /* if this wave is to be generated using noise generator */ + if (pRegion->region.keyGroupAndFlags & REGION_FLAG_USE_WAVE_GENERATOR) + { + pWTVoice->phaseAccum = 4574296; + pWTVoice->loopStart = WT_NOISE_GENERATOR; + pWTVoice->loopEnd = 4574295; + } + + /* normal sample */ + else + { + +#ifdef EAS_SPLIT_WT_SYNTH + if (voiceNum < NUM_PRIMARY_VOICES) + pWTVoice->phaseAccum = (EAS_U32) pSynth->pEAS->pSamples + pSynth->pEAS->pSampleOffsets[pRegion->waveIndex]; + else + pWTVoice->phaseAccum = pSynth->pEAS->pSampleOffsets[pRegion->waveIndex]; +#else + pWTVoice->phaseAccum = (EAS_U32) pSynth->pEAS->pSamples + pSynth->pEAS->pSampleOffsets[pRegion->waveIndex]; +#endif + + if (pRegion->region.keyGroupAndFlags & REGION_FLAG_IS_LOOPED) + { + pWTVoice->loopStart = pWTVoice->phaseAccum + pRegion->loopStart; + pWTVoice->loopEnd = pWTVoice->phaseAccum + pRegion->loopEnd - 1; + } + else + pWTVoice->loopStart = pWTVoice->loopEnd = pWTVoice->phaseAccum + pSynth->pEAS->pSampleLen[pRegion->waveIndex] - 1; + } + +#ifdef EAS_SPLIT_WT_SYNTH + /* configure off-chip voices */ + if (voiceNum >= NUM_PRIMARY_VOICES) + { + wtConfig.phaseAccum = pWTVoice->phaseAccum; + wtConfig.loopStart = pWTVoice->loopStart; + wtConfig.loopEnd = pWTVoice->loopEnd; + wtConfig.gain = pVoice->gain; + +#if (NUM_OUTPUT_CHANNELS == 2) + wtConfig.gainLeft = pWTVoice->gainLeft; + wtConfig.gainRight = pWTVoice->gainRight; +#endif + + WTE_ConfigVoice(voiceNum - NUM_PRIMARY_VOICES, &wtConfig, pVoiceMgr->pFrameBuffer); + } +#endif + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * WT_CheckSampleEnd + *---------------------------------------------------------------------------- + * Purpose: + * Check for end of sample and calculate number of samples to synthesize + * + * Inputs: + * + * Outputs: + * + * Notes: + * + *---------------------------------------------------------------------------- +*/ +EAS_BOOL WT_CheckSampleEnd (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame, EAS_BOOL update) +{ + EAS_U32 endPhaseAccum; + EAS_U32 endPhaseFrac; + EAS_I32 numSamples; + EAS_BOOL done = EAS_FALSE; + + /* check to see if we hit the end of the waveform this time */ + /*lint -e{703} use shift for performance */ + endPhaseFrac = pWTVoice->phaseFrac + (pWTIntFrame->frame.phaseIncrement << SYNTH_UPDATE_PERIOD_IN_BITS); + endPhaseAccum = pWTVoice->phaseAccum + GET_PHASE_INT_PART(endPhaseFrac); + if (endPhaseAccum >= pWTVoice->loopEnd) + { + /* calculate how far current ptr is from end */ + numSamples = (EAS_I32) (pWTVoice->loopEnd - pWTVoice->phaseAccum); + + /* now account for the fractional portion */ + /*lint -e{703} use shift for performance */ + numSamples = (EAS_I32) ((numSamples << NUM_PHASE_FRAC_BITS) - pWTVoice->phaseFrac); + if (pWTIntFrame->frame.phaseIncrement) { + pWTIntFrame->numSamples = 1 + (numSamples / pWTIntFrame->frame.phaseIncrement); + } else { + pWTIntFrame->numSamples = numSamples; + } + + /* sound will be done this frame */ + done = EAS_TRUE; + } + + /* update data for off-chip synth */ + if (update) + { + pWTVoice->phaseFrac = endPhaseFrac; + pWTVoice->phaseAccum = endPhaseAccum; + } + + return done; +} + +/*---------------------------------------------------------------------------- + * WT_UpdateVoice() + *---------------------------------------------------------------------------- + * Purpose: + * Synthesize a block of samples for the given voice. + * Use linear interpolation. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * + * Outputs: + * number of samples actually written to buffer + * + * Side Effects: + * - samples are added to the presently free buffer + * + *---------------------------------------------------------------------------- +*/ +static EAS_BOOL WT_UpdateVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_I32 *pMixBuffer, EAS_I32 numSamples) +{ + S_WT_VOICE *pWTVoice; + S_WT_INT_FRAME intFrame; + S_SYNTH_CHANNEL *pChannel; + const S_WT_REGION *pWTRegion; + const S_ARTICULATION *pArt; + EAS_I32 temp; + EAS_BOOL done; + +#ifdef DLS_SYNTHESIZER + if (pVoice->regionIndex & FLAG_RGN_IDX_DLS_SYNTH) + return DLS_UpdateVoice(pVoiceMgr, pSynth, pVoice, voiceNum, pMixBuffer, numSamples); +#endif + + /* establish pointers to critical data */ + pWTVoice = &pVoiceMgr->wtVoices[voiceNum]; + pWTRegion = &pSynth->pEAS->pWTRegions[pVoice->regionIndex & REGION_INDEX_MASK]; + pArt = &pSynth->pEAS->pArticulations[pWTVoice->artIndex]; + pChannel = &pSynth->channels[pVoice->channel & 15]; + intFrame.prevGain = pVoice->gain; + + /* update the envelopes */ + WT_UpdateEG1(pWTVoice, &pArt->eg1); + WT_UpdateEG2(pWTVoice, &pArt->eg2); + + /* update the LFO */ + WT_UpdateLFO(&pWTVoice->modLFO, pArt->lfoFreq); + +#ifdef _FILTER_ENABLED + /* calculate filter if library uses filter */ + if (pSynth->pEAS->libAttr & LIB_FORMAT_FILTER_ENABLED) + WT_UpdateFilter(pWTVoice, &intFrame, pArt); + else + intFrame.frame.k = 0; +#endif + + /* update the gain */ + intFrame.frame.gainTarget = WT_UpdateGain(pVoice, pWTVoice, pArt, pChannel, pWTRegion->gain); + + /* calculate base pitch*/ + temp = pChannel->staticPitch + pWTRegion->tuning; + + /* include global transpose */ + if (pChannel->channelFlags & CHANNEL_FLAG_RHYTHM_CHANNEL) + temp += pVoice->note * 100; + else + temp += (pVoice->note + pSynth->globalTranspose) * 100; + intFrame.frame.phaseIncrement = WT_UpdatePhaseInc(pWTVoice, pArt, pChannel, temp); + + /* call into engine to generate samples */ + intFrame.pAudioBuffer = pVoiceMgr->voiceBuffer; + intFrame.pMixBuffer = pMixBuffer; + intFrame.numSamples = numSamples; + + /* check for end of sample */ + if ((pWTVoice->loopStart != WT_NOISE_GENERATOR) && (pWTVoice->loopStart == pWTVoice->loopEnd)) + done = WT_CheckSampleEnd(pWTVoice, &intFrame, (EAS_BOOL) (voiceNum >= NUM_PRIMARY_VOICES)); + else + done = EAS_FALSE; + + if (intFrame.numSamples < 0) intFrame.numSamples = 0; + +#ifdef EAS_SPLIT_WT_SYNTH + if (voiceNum < NUM_PRIMARY_VOICES) + { +#ifndef _SPLIT_WT_TEST_HARNESS + WT_ProcessVoice(pWTVoice, &intFrame); +#endif + } + else + WTE_ProcessVoice(voiceNum - NUM_PRIMARY_VOICES, &intFrame.frame, pVoiceMgr->pFrameBuffer); +#else + WT_ProcessVoice(pWTVoice, &intFrame); +#endif + + /* clear flag */ + pVoice->voiceFlags &= ~VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET; + + /* if voice has finished, set flag for voice manager */ + if ((pVoice->voiceState != eVoiceStateStolen) && (pWTVoice->eg1State == eEnvelopeStateMuted)) + done = EAS_TRUE; + + /* if the update interval has elapsed, then force the current gain to the next + * gain since we never actually reach the next gain when ramping -- we just get + * very close to the target gain. + */ + pVoice->gain = (EAS_I16) intFrame.frame.gainTarget; + + return done; +} + +/*---------------------------------------------------------------------------- + * WT_UpdatePhaseInc() + *---------------------------------------------------------------------------- + * Purpose: + * Calculate the phase increment + * + * Inputs: + * pVoice - pointer to the voice being updated + * psRegion - pointer to the region + * psArticulation - pointer to the articulation + * nChannelPitchForThisVoice - the portion of the pitch that is fixed for this + * voice during the duration of this synthesis + * pEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * set the phase increment for this voice + *---------------------------------------------------------------------------- +*/ +static EAS_I32 WT_UpdatePhaseInc (S_WT_VOICE *pWTVoice, const S_ARTICULATION *pArt, S_SYNTH_CHANNEL *pChannel, EAS_I32 pitchCents) +{ + EAS_I32 temp; + + /*pitchCents due to CC1 = LFO * (CC1 / 128) * DEFAULT_LFO_MOD_WHEEL_TO_PITCH_CENTS */ + temp = MULT_EG1_EG1(DEFAULT_LFO_MOD_WHEEL_TO_PITCH_CENTS, + ((pChannel->modWheel) << (NUM_EG1_FRAC_BITS -7))); + + /* pitchCents due to channel pressure = LFO * (channel pressure / 128) * DEFAULT_LFO_CHANNEL_PRESSURE_TO_PITCH_CENTS */ + temp += MULT_EG1_EG1(DEFAULT_LFO_CHANNEL_PRESSURE_TO_PITCH_CENTS, + ((pChannel->channelPressure) << (NUM_EG1_FRAC_BITS -7))); + + /* now multiply the (channel pressure + CC1) pitch values by the LFO value */ + temp = MULT_EG1_EG1(pWTVoice->modLFO.lfoValue, temp); + + /* + add in the LFO pitch due to + channel pressure and CC1 along with + the LFO pitch, the EG2 pitch, and the + "static" pitch for this voice on this channel + */ + temp += pitchCents + + (MULT_EG1_EG1(pWTVoice->eg2Value, pArt->eg2ToPitch)) + + (MULT_EG1_EG1(pWTVoice->modLFO.lfoValue, pArt->lfoToPitch)); + + /* convert from cents to linear phase increment */ + return EAS_Calculate2toX(temp); +} + +/*---------------------------------------------------------------------------- + * WT_UpdateChannel() + *---------------------------------------------------------------------------- + * Purpose: + * Calculate and assign static channel parameters + * These values only need to be updated if one of the controller values + * for this channel changes + * + * Inputs: + * nChannel - channel to update + * pEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * - the given channel's static gain and static pitch are updated + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pVoiceMgr) reserved for future use */ +static void WT_UpdateChannel (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel) +{ + EAS_I32 staticGain; + EAS_I32 pitchBend; + S_SYNTH_CHANNEL *pChannel; + + pChannel = &pSynth->channels[channel]; + + /* + nChannelGain = (CC7 * CC11)^2 * master volume + where CC7 == 100 by default, CC11 == 127, master volume == 32767 + */ + staticGain = MULT_EG1_EG1((pChannel->volume) << (NUM_EG1_FRAC_BITS - 7), + (pChannel->expression) << (NUM_EG1_FRAC_BITS - 7)); + + /* staticGain has to be squared */ + staticGain = MULT_EG1_EG1(staticGain, staticGain); + + pChannel->staticGain = (EAS_I16) MULT_EG1_EG1(staticGain, pSynth->masterVolume); + + /* + calculate pitch bend: RPN0 * ((2*pitch wheel)/16384 -1) + However, if we use the EG1 macros, remember that EG1 has a full + scale value of 32768 (instead of 16384). So instead of multiplying + by 2, multiply by 4 (left shift by 2), and subtract by 32768 instead + of 16384. This utilizes the fact that the EG1 macro places a binary + point 15 places to the left instead of 14 places. + */ + /*lint -e{703} */ + pitchBend = + (((EAS_I32)(pChannel->pitchBend) << 2) + - 32768); + + pChannel->staticPitch = + MULT_EG1_EG1(pitchBend, pChannel->pitchBendSensitivity); + + /* if this is not a drum channel, then add in the per-channel tuning */ + if (!(pChannel->channelFlags & CHANNEL_FLAG_RHYTHM_CHANNEL)) + pChannel->staticPitch += pChannel->finePitch + (pChannel->coarsePitch * 100); + + /* clear update flag */ + pChannel->channelFlags &= ~CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS; + return; +} + +/*---------------------------------------------------------------------------- + * WT_UpdateGain() + *---------------------------------------------------------------------------- + * Purpose: + * Calculate and assign static voice parameters as part of WT_UpdateVoice() + * + * Inputs: + * pVoice - ptr to the synth voice that we want to synthesize + * pEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * - various voice parameters are calculated and assigned + * + *---------------------------------------------------------------------------- +*/ +static EAS_I32 WT_UpdateGain (S_SYNTH_VOICE *pVoice, S_WT_VOICE *pWTVoice, const S_ARTICULATION *pArt, S_SYNTH_CHANNEL *pChannel, EAS_I32 gain) +{ + EAS_I32 lfoGain; + EAS_I32 temp; + + /* + If this voice was stolen, then the velocity is actually + for the new note, not the note that we are currently ramping down. + So we really shouldn't use this velocity. However, that would require + more memory to store the velocity value, and the improvement may + not be sufficient to warrant the added memory. + */ + /* velocity is fixed at note start for a given voice and must be squared */ + temp = (pVoice->velocity) << (NUM_EG1_FRAC_BITS - 7); + temp = MULT_EG1_EG1(temp, temp); + + /* region gain is fixed as part of the articulation */ + temp = MULT_EG1_EG1(temp, gain); + + /* include the channel gain */ + temp = MULT_EG1_EG1(temp, pChannel->staticGain); + + /* calculate LFO gain using an approximation for 10^x */ + lfoGain = MULT_EG1_EG1(pWTVoice->modLFO.lfoValue, pArt->lfoToGain); + lfoGain = MULT_EG1_EG1(lfoGain, LFO_GAIN_TO_CENTS); + + /* convert from a dB-like value to linear gain */ + lfoGain = EAS_Calculate2toX(lfoGain); + temp = MULT_EG1_EG1(temp, lfoGain); + + /* calculate the voice's gain */ + temp = (EAS_I16)MULT_EG1_EG1(temp, pWTVoice->eg1Value); + + return temp; +} + +/*---------------------------------------------------------------------------- + * WT_UpdateEG1() + *---------------------------------------------------------------------------- + * Purpose: + * Calculate the EG1 envelope for the given voice (but do not update any + * state) + * + * Inputs: + * pVoice - ptr to the voice whose envelope we want to update + * nVoice - this voice's number - used only for debug + * pEASData - pointer to overall EAS data structure + * + * Outputs: + * nValue - the envelope value + * + * Side Effects: + * - updates EG1 state value for the given voice + *---------------------------------------------------------------------------- +*/ +static void WT_UpdateEG1 (S_WT_VOICE *pWTVoice, const S_ENVELOPE *pEnv) +{ + EAS_I32 temp; + + switch (pWTVoice->eg1State) + { + case eEnvelopeStateAttack: + temp = pWTVoice->eg1Value + pWTVoice->eg1Increment; + + /* check if we have reached peak amplitude */ + if (temp >= SYNTH_FULL_SCALE_EG1_GAIN) + { + /* limit the volume */ + temp = SYNTH_FULL_SCALE_EG1_GAIN; + + /* prepare to move to decay state */ + pWTVoice->eg1State = eEnvelopeStateDecay; + pWTVoice->eg1Increment = pEnv->decayTime; + } + + break; + + /* exponential decay */ + case eEnvelopeStateDecay: + temp = MULT_EG1_EG1(pWTVoice->eg1Value, pWTVoice->eg1Increment); + + /* check if we have reached sustain level */ + if (temp <= pEnv->sustainLevel) + { + /* enforce the sustain level */ + temp = pEnv->sustainLevel; + + /* if sustain level is zero, skip sustain & release the voice */ + if (temp > 0) + pWTVoice->eg1State = eEnvelopeStateSustain; + + /* move to sustain state */ + else + pWTVoice->eg1State = eEnvelopeStateMuted; + } + + break; + + case eEnvelopeStateSustain: + return; + + case eEnvelopeStateRelease: + temp = MULT_EG1_EG1(pWTVoice->eg1Value, pWTVoice->eg1Increment); + + /* if we hit zero, this voice isn't contributing any audio */ + if (temp <= 0) + { + temp = 0; + pWTVoice->eg1State = eEnvelopeStateMuted; + } + break; + + /* voice is muted, set target to zero */ + case eEnvelopeStateMuted: + temp = 0; + break; + + case eEnvelopeStateInvalid: + default: + temp = 0; +#ifdef _DEBUG_SYNTH + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WT_UpdateEG1: error, %d is an unrecognized state\n", + pWTVoice->eg1State); */ } +#endif + break; + + } + + pWTVoice->eg1Value = (EAS_I16) temp; +} + +/*---------------------------------------------------------------------------- + * WT_UpdateEG2() + *---------------------------------------------------------------------------- + * Purpose: + * Update the EG2 envelope for the given voice + * + * Inputs: + * pVoice - ptr to the voice whose envelope we want to update + * pEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * - updates EG2 values for the given voice + *---------------------------------------------------------------------------- +*/ + +static void WT_UpdateEG2 (S_WT_VOICE *pWTVoice, const S_ENVELOPE *pEnv) +{ + EAS_I32 temp; + + switch (pWTVoice->eg2State) + { + case eEnvelopeStateAttack: + temp = pWTVoice->eg2Value + pWTVoice->eg2Increment; + + /* check if we have reached peak amplitude */ + if (temp >= SYNTH_FULL_SCALE_EG1_GAIN) + { + /* limit the volume */ + temp = SYNTH_FULL_SCALE_EG1_GAIN; + + /* prepare to move to decay state */ + pWTVoice->eg2State = eEnvelopeStateDecay; + + pWTVoice->eg2Increment = pEnv->decayTime; + } + + break; + + /* implement linear pitch decay in cents */ + case eEnvelopeStateDecay: + temp = pWTVoice->eg2Value -pWTVoice->eg2Increment; + + /* check if we have reached sustain level */ + if (temp <= pEnv->sustainLevel) + { + /* enforce the sustain level */ + temp = pEnv->sustainLevel; + + /* prepare to move to sustain state */ + pWTVoice->eg2State = eEnvelopeStateSustain; + } + break; + + case eEnvelopeStateSustain: + return; + + case eEnvelopeStateRelease: + temp = pWTVoice->eg2Value - pWTVoice->eg2Increment; + + if (temp <= 0) + { + temp = 0; + pWTVoice->eg2State = eEnvelopeStateMuted; + } + + break; + + /* voice is muted, set target to zero */ + case eEnvelopeStateMuted: + temp = 0; + break; + + case eEnvelopeStateInvalid: + default: + temp = 0; +#ifdef _DEBUG_SYNTH + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WT_UpdateEG2: error, %d is an unrecognized state\n", + pWTVoice->eg2State); */ } +#endif + break; + } + + pWTVoice->eg2Value = (EAS_I16) temp; +} + +/*---------------------------------------------------------------------------- + * WT_UpdateLFO () + *---------------------------------------------------------------------------- + * Purpose: + * Calculate the LFO for the given voice + * + * Inputs: + * pLFO - ptr to the LFO data + * phaseInc - phase increment + * + * Outputs: + * + * Side Effects: + * - updates LFO values for the given voice + *---------------------------------------------------------------------------- +*/ +void WT_UpdateLFO (S_LFO_CONTROL *pLFO, EAS_I16 phaseInc) +{ + + /* To save memory, if m_nPhaseValue is negative, we are in the + * delay phase, and m_nPhaseValue represents the time left + * in the delay. + */ + if (pLFO->lfoPhase < 0) + { + pLFO->lfoPhase++; + return; + } + + /* calculate LFO output from phase value */ + /*lint -e{701} Use shift for performance */ + pLFO->lfoValue = (EAS_I16) (pLFO->lfoPhase << 2); + /*lint -e{502} */ + if ((pLFO->lfoPhase > 0x1fff) && (pLFO->lfoPhase < 0x6000)) + pLFO->lfoValue = ~pLFO->lfoValue; + + /* update LFO phase */ + pLFO->lfoPhase = (pLFO->lfoPhase + phaseInc) & 0x7fff; +} + +#ifdef _FILTER_ENABLED +/*---------------------------------------------------------------------------- + * WT_UpdateFilter() + *---------------------------------------------------------------------------- + * Purpose: + * Update the Filter parameters + * + * Inputs: + * pVoice - ptr to the voice whose filter we want to update + * pEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * - updates Filter values for the given voice + *---------------------------------------------------------------------------- +*/ +static void WT_UpdateFilter (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pIntFrame, const S_ARTICULATION *pArt) +{ + EAS_I32 cutoff; + + /* no need to calculate filter coefficients if it is bypassed */ + if (pArt->filterCutoff == DEFAULT_EAS_FILTER_CUTOFF_FREQUENCY) + { + pIntFrame->frame.k = 0; + return; + } + + /* determine the dynamic cutoff frequency */ + cutoff = MULT_EG1_EG1(pWTVoice->eg2Value, pArt->eg2ToFc); + cutoff += pArt->filterCutoff; + + /* subtract the A5 offset and the sampling frequency */ + cutoff -= FILTER_CUTOFF_FREQ_ADJUST + A5_PITCH_OFFSET_IN_CENTS; + + /* limit the cutoff frequency */ + if (cutoff > FILTER_CUTOFF_MAX_PITCH_CENTS) + cutoff = FILTER_CUTOFF_MAX_PITCH_CENTS; + else if (cutoff < FILTER_CUTOFF_MIN_PITCH_CENTS) + cutoff = FILTER_CUTOFF_MIN_PITCH_CENTS; + + WT_SetFilterCoeffs(pIntFrame, cutoff, pArt->filterQ); +} +#endif + +#if defined(_FILTER_ENABLED) || defined(DLS_SYNTHESIZER) +/*---------------------------------------------------------------------------- + * coef + *---------------------------------------------------------------------------- + * Table of filter coefficients for low-pass filter + *---------------------------------------------------------------------------- + * + * polynomial coefficients are based on 8kHz sampling frequency + * filter coef b2 = k2 = k2g0*k^0 + k2g1*k^1*(2^x) + k2g2*k^2*(2^x) + * + *where k2g0, k2g1, k2g2 are from the truncated power series expansion on theta + *(k*2^x = theta, but we incorporate the k along with the k2g0, k2g1, k2g2) + *note: this is a power series in 2^x, not k*2^x + *where k = (2*pi*440)/8kHz == convert octaves to radians + * + * so actually, the following coefs listed as k2g0, k2g1, k2g2 are really + * k2g0*k^0 = k2g0 + * k2g1*k^1 + * k2g2*k^2 + * + * + * filter coef n1 = numerator = n1g0*k^0 + n1g1*k^1*(2^x) + n1g2*k^2*(2^x) + n1g3*k^3*(2^x) + * + *where n1g0, n1g1, n1g2, n1g3 are from the truncated power series expansion on theta + *(k*2^x = theta, but we incorporate the k along with the n1g0, n1g1, n1g2, n2g3) + *note: this is a power series in 2^x, not k*2^x + *where k = (2*pi*440)/8kHz == convert octaves to radians + *we also include the optimization factor of 0.81 + * + * so actually, the following coefs listed as n1g0, n1g1, n1g2, n2g3 are really + * n1g0*k^0 = n1g0 + * n1g1*k^1 + * n1g2*k^2 + * n1g3*k^3 + * + * NOTE that n1g0 == n1g1 == 0, always, so we only need to store n1g2 and n1g3 + *---------------------------------------------------------------------------- +*/ + +static const EAS_I16 nk1g0 = -32768; +static const EAS_I16 nk1g2 = 1580; +static const EAS_I16 k2g0 = 32767; + +static const EAS_I16 k2g1[] = +{ + -11324, /* k2g1[0] = -0.3455751918948761 */ + -10387, /* k2g1[1] = -0.3169878073928751 */ + -9528, /* k2g1[2] = -0.29076528753345476 */ + -8740, /* k2g1[3] = -0.2667120011011279 */ + -8017, /* k2g1[4] = -0.24464850028971705 */ + -7353, /* k2g1[5] = -0.22441018194495696 */ + -6745, /* k2g1[6] = -0.20584605955455101 */ + -6187, /* k2g1[7] = -0.18881763682420102 */ + -5675, /* k2g1[8] = -0.1731978744360067 */ + -5206, /* k2g1[9] = -0.15887024228080968 */ + -4775, /* k2g1[10] = -0.14572785009373057 */ + -4380, /* k2g1[11] = -0.13367265000706827 */ + -4018, /* k2g1[12] = -0.1226147050712642 */ + -3685, /* k2g1[13] = -0.11247151828678581 */ + -3381, /* k2g1[14] = -0.10316741714122014 */ + -3101, /* k2g1[15] = -0.0946329890599603 */ + -2844, /* k2g1[16] = -0.08680456355870586 */ + -2609, /* k2g1[17] = -0.07962373723441349 */ + -2393, /* k2g1[18] = -0.07303693805092666 */ + -2195, /* k2g1[19] = -0.06699502566866912 */ + -2014, /* k2g1[20] = -0.06145292483669077 */ + -1847, /* k2g1[21] = -0.056369289112013346 */ + -1694, /* k2g1[22] = -0.05170619239747895 */ + -1554, /* k2g1[23] = -0.04742884599684141 */ + -1426, /* k2g1[24] = -0.043505339076210514 */ + -1308, /* k2g1[25] = -0.03990640059558053 */ + -1199, /* k2g1[26] = -0.03660518093435039 */ + -1100, /* k2g1[27] = -0.03357705158166837 */ + -1009, /* k2g1[28] = -0.030799421397205727 */ + -926, /* k2g1[29] = -0.028251568071585884 */ + -849 /* k2g1[30] = -0.025914483529091967 */ +}; + +static const EAS_I16 k2g2[] = +{ + 1957, /* k2g2[0] = 0.059711106626580836 */ + 1646, /* k2g2[1] = 0.05024063501786333 */ + 1385, /* k2g2[2] = 0.042272226217199664 */ + 1165, /* k2g2[3] = 0.03556764576567844 */ + 981, /* k2g2[4] = 0.029926444346999134 */ + 825, /* k2g2[5] = 0.025179964880280382 */ + 694, /* k2g2[6] = 0.02118630011706455 */ + 584, /* k2g2[7] = 0.01782604998793514 */ + 491, /* k2g2[8] = 0.014998751854573014 */ + 414, /* k2g2[9] = 0.012619876941179595 */ + 348, /* k2g2[10] = 0.010618303146468736 */ + 293, /* k2g2[11] = 0.008934188679954682 */ + 246, /* k2g2[12] = 0.007517182949855368 */ + 207, /* k2g2[13] = 0.006324921212866403 */ + 174, /* k2g2[14] = 0.005321757979794424 */ + 147, /* k2g2[15] = 0.004477701309210577 */ + 123, /* k2g2[16] = 0.00376751612730811 */ + 104, /* k2g2[17] = 0.0031699697655869644 */ + 87, /* k2g2[18] = 0.00266719715992703 */ + 74, /* k2g2[19] = 0.0022441667321724647 */ + 62, /* k2g2[20] = 0.0018882309854916855 */ + 52, /* k2g2[21] = 0.0015887483774966232 */ + 44, /* k2g2[22] = 0.0013367651661223448 */ + 37, /* k2g2[23] = 0.0011247477162958733 */ + 31, /* k2g2[24] = 0.0009463572640678758 */ + 26, /* k2g2[25] = 0.0007962604042473498 */ + 22, /* k2g2[26] = 0.0006699696356181593 */ + 18, /* k2g2[27] = 0.0005637091964589207 */ + 16, /* k2g2[28] = 0.00047430217920125243 */ + 13, /* k2g2[29] = 0.00039907554925166274 */ + 11 /* k2g2[30] = 0.00033578022828973666 */ +}; + +static const EAS_I16 n1g2[] = +{ + 3170, /* n1g2[0] = 0.0967319927350769 */ + 3036, /* n1g2[1] = 0.0926446051254155 */ + 2908, /* n1g2[2] = 0.08872992911818503 */ + 2785, /* n1g2[3] = 0.08498066682523227 */ + 2667, /* n1g2[4] = 0.08138982872895201 */ + 2554, /* n1g2[5] = 0.07795072065216213 */ + 2446, /* n1g2[6] = 0.0746569312785634 */ + 2343, /* n1g2[7] = 0.07150232020051943 */ + 2244, /* n1g2[8] = 0.06848100647187474 */ + 2149, /* n1g2[9] = 0.06558735764447099 */ + 2058, /* n1g2[10] = 0.06281597926792246 */ + 1971, /* n1g2[11] = 0.06016170483307614 */ + 1888, /* n1g2[12] = 0.05761958614040857 */ + 1808, /* n1g2[13] = 0.05518488407540374 */ + 1732, /* n1g2[14] = 0.052853059773715245 */ + 1659, /* n1g2[15] = 0.05061976615964251 */ + 1589, /* n1g2[16] = 0.04848083984214659 */ + 1521, /* n1g2[17] = 0.046432293353298 */ + 1457, /* n1g2[18] = 0.04447030771468711 */ + 1396, /* n1g2[19] = 0.04259122531793907 */ + 1337, /* n1g2[20] = 0.040791543106060944 */ + 1280, /* n1g2[21] = 0.03906790604290942 */ + 1226, /* n1g2[22] = 0.037417100858604564 */ + 1174, /* n1g2[23] = 0.035836050059229754 */ + 1125, /* n1g2[24] = 0.03432180618965023 */ + 1077, /* n1g2[25] = 0.03287154633875494 */ + 1032, /* n1g2[26] = 0.03148256687687814 */ + 988, /* n1g2[27] = 0.030152278415589925 */ + 946, /* n1g2[28] = 0.028878200980459685 */ + 906, /* n1g2[29] = 0.02765795938779331 */ + 868 /* n1g2[30] = 0.02648927881672521 */ +}; + +static const EAS_I16 n1g3[] = +{ + -548, /* n1g3[0] = -0.016714088475899017 */ + -481, /* n1g3[1] = -0.014683605122742116 */ + -423, /* n1g3[2] = -0.012899791676436092 */ + -371, /* n1g3[3] = -0.01133268185193299 */ + -326, /* n1g3[4] = -0.00995594976868754 */ + -287, /* n1g3[5] = -0.008746467702146129 */ + -252, /* n1g3[6] = -0.00768391756106361 */ + -221, /* n1g3[7] = -0.006750449563854721 */ + -194, /* n1g3[8] = -0.005930382380083576 */ + -171, /* n1g3[9] = -0.005209939699767622 */ + -150, /* n1g3[10] = -0.004577018805123356 */ + -132, /* n1g3[11] = -0.004020987256990177 */ + -116, /* n1g3[12] = -0.003532504280467257 */ + -102, /* n1g3[13] = -0.00310336384922047 */ + -89, /* n1g3[14] = -0.002726356832432369 */ + -78, /* n1g3[15] = -0.002395149888601605 */ + -69, /* n1g3[16] = -0.0021041790717285314 */ + -61, /* n1g3[17] = -0.0018485563625771063 */ + -53, /* n1g3[18] = -0.001623987554831628 */ + -47, /* n1g3[19] = -0.0014267001167177025 */ + -41, /* n1g3[20] = -0.0012533798162347005 */ + -36, /* n1g3[21] = -0.0011011150453668693 */ + -32, /* n1g3[22] = -0.0009673479079754438 */ + -28, /* n1g3[23] = -0.0008498312496971563 */ + -24, /* n1g3[24] = -0.0007465909079943587 */ + -21, /* n1g3[25] = -0.0006558925481952733 */ + -19, /* n1g3[26] = -0.0005762125284029567 */ + -17, /* n1g3[27] = -0.0005062123038325457 */ + -15, /* n1g3[28] = -0.0004447159405951901 */ + -13, /* n1g3[29] = -0.00039069036118270117 */ + -11 /* n1g3[30] = -0.00034322798979677605 */ +}; + +/*---------------------------------------------------------------------------- + * WT_SetFilterCoeffs() + *---------------------------------------------------------------------------- + * Purpose: + * Update the Filter parameters + * + * Inputs: + * pVoice - ptr to the voice whose filter we want to update + * pEASData - pointer to overall EAS data structure + * + * Outputs: + * + * Side Effects: + * - updates Filter values for the given voice + *---------------------------------------------------------------------------- +*/ +void WT_SetFilterCoeffs (S_WT_INT_FRAME *pIntFrame, EAS_I32 cutoff, EAS_I32 resonance) +{ + EAS_I32 temp; + + /* + Convert the cutoff, which has had A5 subtracted, using the 2^x approx + Note, this cutoff is related to theta cutoff by + theta = k * 2^x + We use 2^x and incorporate k in the power series coefs instead + */ + cutoff = EAS_Calculate2toX(cutoff); + + /* calculate b2 coef */ + temp = k2g1[resonance] + MULT_AUDIO_COEF(cutoff, k2g2[resonance]); + temp = k2g0 + MULT_AUDIO_COEF(cutoff, temp); + pIntFrame->frame.b2 = temp; + + /* calculate b1 coef */ + temp = MULT_AUDIO_COEF(cutoff, nk1g2); + temp = nk1g0 + MULT_AUDIO_COEF(cutoff, temp); + temp += MULT_AUDIO_COEF(temp, pIntFrame->frame.b2); + pIntFrame->frame.b1 = temp >> 1; + + /* calculate K coef */ + temp = n1g2[resonance] + MULT_AUDIO_COEF(cutoff, n1g3[resonance]); + temp = MULT_AUDIO_COEF(cutoff, temp); + temp = MULT_AUDIO_COEF(cutoff, temp); + pIntFrame->frame.k = temp; +} +#endif + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_wtsynth.h b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_wtsynth.h new file mode 100755 index 0000000..90a7ad8 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_wtsynth.h @@ -0,0 +1,66 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_wtsynth.h + * + * Contents and purpose: + * This file defines the interface for synthesizer engine + * + * Copyright Sonic Network Inc. 2004 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_WTSYNTH_H +#define _EAS_WTSYNTH_H + +#include "eas_sndlib.h" +#include "eas_wtengine.h" + +/* adjust the filter cutoff frequency to the sample rate */ +#if defined (_SAMPLE_RATE_8000) +#define FILTER_CUTOFF_FREQ_ADJUST 0 +#elif defined (_SAMPLE_RATE_16000) +#define FILTER_CUTOFF_FREQ_ADJUST 1200 +#elif defined (_SAMPLE_RATE_20000) +#define FILTER_CUTOFF_FREQ_ADJUST 1586 +#elif defined (_SAMPLE_RATE_22050) +#define FILTER_CUTOFF_FREQ_ADJUST 1756 +#elif defined (_SAMPLE_RATE_24000) +#define FILTER_CUTOFF_FREQ_ADJUST 1902 +#elif defined (_SAMPLE_RATE_32000) +#define FILTER_CUTOFF_FREQ_ADJUST 2400 +#elif defined (_SAMPLE_RATE_44100) +#define FILTER_CUTOFF_FREQ_ADJUST 2956 +#elif defined (_SAMPLE_RATE_48000) +#define FILTER_CUTOFF_FREQ_ADJUST 3102 +#else +#error "_SAMPLE_RATE_XXXXX must be defined to valid rate" +#endif + +/* function prototypes */ +void WT_UpdateLFO (S_LFO_CONTROL *pLFO, EAS_I16 phaseInc); + +#if defined(_FILTER_ENABLED) || defined(DLS_SYNTHESIZER) +void WT_SetFilterCoeffs (S_WT_INT_FRAME *pIntFrame, EAS_I32 cutoff, EAS_I32 resonance); +#endif + +#endif + + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_xmf.c b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_xmf.c new file mode 100755 index 0000000..0a92425 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_xmf.c @@ -0,0 +1,850 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_xmf.c + * 5 + * Contents and purpose: + * XMF File Parser + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 501 $ + * $Date: 2006-12-11 17:53:36 -0800 (Mon, 11 Dec 2006) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_data.h" +#include "eas_miditypes.h" +#include "eas_parser.h" +#include "eas_report.h" +#include "eas_host.h" +#include "eas_midi.h" +#include "eas_xmf.h" +#include "eas_xmfdata.h" +#include "eas_config.h" +#include "eas_vm_protos.h" +#include "eas_mdls.h" +#include "eas_smf.h" + + +/* XMF header file type */ +#define XMF_IDENTIFIER 0x584d465f +#define XMF_VERSION_2_00 0x322e3030 +#define XMF_FILE_TYPE 0x00000002 +#define XMF_SPEC_LEVEL 0x00000001 +#define XMF_RIFF_CHUNK 0x52494646 +#define XMF_RIFF_DLS 0x444c5320 +#define XMF_SMF_CHUNK 0x4d546864 + +/* local prototypes */ +static EAS_RESULT XMF_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset); +static EAS_RESULT XMF_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT XMF_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime); +static EAS_RESULT XMF_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode); +static EAS_RESULT XMF_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_STATE *pState); +static EAS_RESULT XMF_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT XMF_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT XMF_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT XMF_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT XMF_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value); +static EAS_RESULT XMF_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue); +static EAS_RESULT XMF_FindFileContents (EAS_HW_DATA_HANDLE hwInstData, S_XMF_DATA *pXMFData); +static EAS_RESULT XMF_ReadNode (EAS_HW_DATA_HANDLE hwInstData, S_XMF_DATA *pXMFData, EAS_I32 nodeOffset, EAS_I32 *pLength); +static EAS_RESULT XMF_ReadVLQ (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle, EAS_I32 *value); + + +/*---------------------------------------------------------------------------- + * + * XMF_Parser + * + * This structure contains the functional interface for the XMF parser + *---------------------------------------------------------------------------- +*/ +const S_FILE_PARSER_INTERFACE EAS_XMF_Parser = +{ + XMF_CheckFileType, + XMF_Prepare, + XMF_Time, + XMF_Event, + XMF_State, + XMF_Close, + XMF_Reset, + XMF_Pause, + XMF_Resume, + NULL, + XMF_SetData, + XMF_GetData, + NULL +}; + +/*---------------------------------------------------------------------------- + * XMF_CheckFileType() + *---------------------------------------------------------------------------- + * Purpose: + * Check the file type to see if we can parse it + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT XMF_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset) +{ + S_XMF_DATA *pXMFData; + EAS_RESULT result; + EAS_U32 temp; + + /* assume we don't recognize it initially */ + *ppHandle = NULL; + + /* read the file identifier */ + if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &temp, EAS_TRUE)) != EAS_SUCCESS) + return result; + if (temp != XMF_IDENTIFIER) + return EAS_SUCCESS; + + /* read the version */ + if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &temp, EAS_TRUE)) != EAS_SUCCESS) + return result; + if (temp != XMF_VERSION_2_00) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "XMF file version was 0x%08x, expected 0x%08x\n", temp, XMF_VERSION_2_00); */ } + return EAS_SUCCESS; + } + + /* read the file type */ + if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &temp, EAS_TRUE)) != EAS_SUCCESS) + return result; + if (temp != XMF_FILE_TYPE) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "XMF file type was 0x%08x, expected 0x%08x\n", temp, XMF_FILE_TYPE); */ } + return EAS_SUCCESS; + } + + /* read the spec level */ + if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &temp, EAS_TRUE)) != EAS_SUCCESS) + return result; + if (temp != XMF_SPEC_LEVEL) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "XMF file spec was 0x%08x, expected 0x%08x\n", temp, XMF_SPEC_LEVEL); */ } + return EAS_SUCCESS; + } + + /* check for static memory allocation */ + if (pEASData->staticMemoryModel) + pXMFData = EAS_CMEnumData(EAS_CM_XMF_DATA); + else + pXMFData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_XMF_DATA)); + if (!pXMFData) + return EAS_ERROR_MALLOC_FAILED; + + /* zero the memory to insure complete initialization */ + EAS_HWMemSet((void *)pXMFData,0, sizeof(S_XMF_DATA)); + + pXMFData->fileHandle = fileHandle; + pXMFData->fileOffset = offset; + *ppHandle = pXMFData; + + /* locate the SMF and DLS contents */ + if ((result = XMF_FindFileContents(pEASData->hwInstData, pXMFData)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "No SMF data found in XMF file\n"); */ } + return result; + } + + /* let the SMF parser take over */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, pXMFData->midiOffset)) != EAS_SUCCESS) + return result; + return SMF_CheckFileType(pEASData, fileHandle, &pXMFData->pSMFData, pXMFData->midiOffset); +} + +/*---------------------------------------------------------------------------- + * XMF_Prepare() + *---------------------------------------------------------------------------- + * Purpose: + * Prepare to parse the file. Allocates instance data (or uses static allocation for + * static memory model). + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT XMF_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_XMF_DATA* pXMFData; + EAS_RESULT result; + + /* parse DLS collection */ + pXMFData = (S_XMF_DATA*) pInstData; + if (pXMFData->dlsOffset != 0) + { + if ((result = DLSParser(pEASData->hwInstData, pXMFData->fileHandle, pXMFData->dlsOffset, &pXMFData->pDLS)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Error converting XMF DLS data\n"); */ } + return result; + } + } + + /* Prepare the SMF parser */ + if ((result = SMF_Prepare(pEASData, pXMFData->pSMFData)) != EAS_SUCCESS) + return result; + + /* if no DLS file, skip this step */ + if (pXMFData->pDLS == NULL) + return EAS_SUCCESS; + + /* tell the synth to use the DLS collection */ + result = VMSetDLSLib(((S_SMF_DATA*) pXMFData->pSMFData)->pSynth, pXMFData->pDLS); + if (result == EAS_SUCCESS) + { + DLSAddRef(pXMFData->pDLS); + VMInitializeAllChannels(pEASData->pVoiceMgr, ((S_SMF_DATA*) pXMFData->pSMFData)->pSynth); + } + return result; +} + +/*---------------------------------------------------------------------------- + * XMF_Time() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the time of the next event in msecs + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * pTime - pointer to variable to hold time of next event (in msecs) + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT XMF_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime) +{ + return SMF_Time(pEASData, ((S_XMF_DATA*) pInstData)->pSMFData, pTime); +} + +/*---------------------------------------------------------------------------- + * XMF_Event() + *---------------------------------------------------------------------------- + * Purpose: + * Parse the next event in the file + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT XMF_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode) +{ + return SMF_Event(pEASData, ((S_XMF_DATA*) pInstData)->pSMFData, parserMode); +} + +/*---------------------------------------------------------------------------- + * XMF_State() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current state of the stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * pState - pointer to variable to store state + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT XMF_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pState) +{ + return SMF_State(pEASData, ((S_XMF_DATA*) pInstData)->pSMFData, pState); +} + +/*---------------------------------------------------------------------------- + * XMF_Close() + *---------------------------------------------------------------------------- + * Purpose: + * Close the file and clean up + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT XMF_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_XMF_DATA* pXMFData; + EAS_RESULT result; + + pXMFData = (S_XMF_DATA *)pInstData; + + /* close the SMF stream, it will close the file handle */ + if ((result = SMF_Close(pEASData, pXMFData->pSMFData)) != EAS_SUCCESS) + return result; + + if (pXMFData->pDLS) + DLSCleanup(pEASData->hwInstData, pXMFData->pDLS); + + /* if using dynamic memory, free it */ + if (!pEASData->staticMemoryModel) + { + /* free the instance data */ + EAS_HWFree(pEASData->hwInstData, pXMFData); + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * XMF_Reset() + *---------------------------------------------------------------------------- + * Purpose: + * Reset the sequencer. Used for locating backwards in the file. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT XMF_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + return SMF_Reset(pEASData, ((S_XMF_DATA*) pInstData)->pSMFData); +} + +/*---------------------------------------------------------------------------- + * XMF_Pause() + *---------------------------------------------------------------------------- + * Purpose: + * Pauses the sequencer. Mutes all voices and sets state to pause. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT XMF_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + return SMF_Pause(pEASData, ((S_XMF_DATA*) pInstData)->pSMFData); +} + +/*---------------------------------------------------------------------------- + * XMF_Resume() + *---------------------------------------------------------------------------- + * Purpose: + * Resume playing after a pause, sets state back to playing. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT XMF_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + return SMF_Resume(pEASData, ((S_XMF_DATA*) pInstData)->pSMFData); +} + +/*---------------------------------------------------------------------------- + * XMF_SetData() + *---------------------------------------------------------------------------- + * Purpose: + * Sets the playback rate of the underlying SMF file + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * rate - rate (28-bit fraction) + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT XMF_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value) +{ + return SMF_SetData(pEASData, ((S_XMF_DATA*) pInstData)->pSMFData, param, value); +} + +/*---------------------------------------------------------------------------- + * XMF_GetData() + *---------------------------------------------------------------------------- + * Purpose: + * Gets the file type + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * rate - rate (28-bit fraction) + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT XMF_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue) +{ + EAS_RESULT result; + + /* call SMF parser to get value */ + if ((result = SMF_GetData(pEASData, ((S_XMF_DATA*) pInstData)->pSMFData, param, pValue)) != EAS_SUCCESS) + return result; + + /* special case for file type */ + if (param == PARSER_DATA_FILE_TYPE) + { + if (*pValue == EAS_FILE_SMF0) + *pValue = EAS_FILE_XMF0; + else if (*pValue == EAS_FILE_SMF1) + *pValue = EAS_FILE_XMF1; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * XMF_FindFileContents() + *---------------------------------------------------------------------------- + * Purpose: + * Finds SMF data and DLS data in XMF file, and remembers offset for each. + * If more than one is found, uses the first one found of each. + * Makes assumptions about the format of a mobile XMF file + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * pXMFData - pointer to XMF parser instance data + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT XMF_FindFileContents (EAS_HW_DATA_HANDLE hwInstData, S_XMF_DATA *pXMFData) +{ + EAS_RESULT result; + EAS_I32 value; + EAS_I32 length; + + /* initialize offsets */ + pXMFData->dlsOffset = pXMFData->midiOffset = 0; + + /* read file length, ignore it for now */ + if ((result = XMF_ReadVLQ(hwInstData, pXMFData->fileHandle, &value)) != EAS_SUCCESS) + return result; + + /* read MetaDataTypesTable length and skip over it */ + if ((result = XMF_ReadVLQ(hwInstData, pXMFData->fileHandle, &value)) != EAS_SUCCESS) + return result; + if ((result = EAS_HWFileSeekOfs(hwInstData, pXMFData->fileHandle, value)) != EAS_SUCCESS) + return result; + + /* get TreeStart offset and jump to it */ + if ((result = XMF_ReadVLQ(hwInstData, pXMFData->fileHandle, &value)) != EAS_SUCCESS) + return result; + if ((result = XMF_ReadNode(hwInstData, pXMFData, value, &length)) != EAS_SUCCESS) + return result; + + /* check for SMF data */ + if (pXMFData->midiOffset == 0) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "No SMF data found in XMF file\n"); */ } + return EAS_ERROR_FILE_FORMAT; + } + + /* check for SFM in wrong order */ + if ((pXMFData->dlsOffset > 0) && (pXMFData->midiOffset < pXMFData->dlsOffset)) + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "DLS data must precede SMF data in Mobile XMF file\n"); */ } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * XMF_ReadNode() + *---------------------------------------------------------------------------- + * Purpose: + * + * Inputs: + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT XMF_ReadNode (EAS_HW_DATA_HANDLE hwInstData, S_XMF_DATA *pXMFData, EAS_I32 nodeOffset, EAS_I32 *pLength) +{ + EAS_RESULT result; + EAS_I32 refType; + EAS_I32 numItems; + EAS_I32 offset; + EAS_I32 length; + EAS_I32 headerLength; + EAS_U32 chunkType; + + /* seek to start of node */ + if ((result = EAS_HWFileSeek(hwInstData, pXMFData->fileHandle, nodeOffset)) != EAS_SUCCESS) + return result; + + /* get node length */ + if ((result = XMF_ReadVLQ(hwInstData, pXMFData->fileHandle, pLength)) != EAS_SUCCESS) + return result; + + /* get number of contained items */ + if ((result = XMF_ReadVLQ(hwInstData, pXMFData->fileHandle, &numItems)) != EAS_SUCCESS) + return result; + + /* get node header length */ + if ((result = XMF_ReadVLQ(hwInstData, pXMFData->fileHandle, &headerLength)) != EAS_SUCCESS) + return result; + + /* get metadata length */ + if ((result = XMF_ReadVLQ(hwInstData, pXMFData->fileHandle, &length)) != EAS_SUCCESS) + return result; + + /* get the current location */ + if ((result = EAS_HWFilePos(hwInstData, pXMFData->fileHandle, &offset)) != EAS_SUCCESS) + return result; + + /* skip to node contents */ + if ((result = EAS_HWFileSeek(hwInstData, pXMFData->fileHandle, nodeOffset + headerLength)) != EAS_SUCCESS) + return result; + + /* get reference type */ + if ((result = XMF_ReadVLQ(hwInstData, pXMFData->fileHandle, &refType)) != EAS_SUCCESS) + return result; + + /* get the current location */ + if ((result = EAS_HWFilePos(hwInstData, pXMFData->fileHandle, &offset)) != EAS_SUCCESS) + return result; + + /* process file node */ + if (numItems == 0) + + { + /* if in-file resource, find out where it is and jump to it */ + if (refType == 2) + { + if ((result = XMF_ReadVLQ(hwInstData, pXMFData->fileHandle, &offset)) != EAS_SUCCESS) + return result; + offset += pXMFData->fileOffset; + if ((result = EAS_HWFileSeek(hwInstData, pXMFData->fileHandle, offset)) != EAS_SUCCESS) + return result; + } + + /* or else it must be an inline resource */ + else if (refType != 1) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Unexpected reference type %d\n", refType); */ } + return EAS_ERROR_FILE_FORMAT; + } + + /* get the chunk type */ + if ((result = EAS_HWGetDWord(hwInstData, pXMFData->fileHandle, &chunkType, EAS_TRUE)) != EAS_SUCCESS) + return result; + + /* found a RIFF chunk, check for DLS type */ + if (chunkType == XMF_RIFF_CHUNK) + { + /* skip length */ + if ((result = EAS_HWFileSeekOfs(hwInstData, pXMFData->fileHandle, sizeof(EAS_I32))) != EAS_SUCCESS) + return result; + + /* get RIFF file type */ + if ((result = EAS_HWGetDWord(hwInstData, pXMFData->fileHandle, &chunkType, EAS_TRUE)) != EAS_SUCCESS) + return result; + if (chunkType == XMF_RIFF_DLS) + pXMFData->dlsOffset = offset; + } + + /* found an SMF chunk */ + else if (chunkType == XMF_SMF_CHUNK) + pXMFData->midiOffset = offset; + } + + /* folder node, process the items in the list */ + else + { + for ( ; numItems > 0; numItems--) + { + /* process this item */ + if ((result = XMF_ReadNode(hwInstData, pXMFData, offset, &length)) != EAS_SUCCESS) + return result; + + /* seek to start of next item */ + offset += length; + if ((result = EAS_HWFileSeek(hwInstData, pXMFData->fileHandle, offset)) != EAS_SUCCESS) + return result; + } + } + + return EAS_SUCCESS; +} + +#if 0 +/*---------------------------------------------------------------------------- + * XMF_FindFileContents() + *---------------------------------------------------------------------------- + * Purpose: + * Finds SMF data and DLS data in XMF file, and remembers offset for each. + * If more than one is found, uses the first one found of each. + * Makes assumptions about the format of a mobile XMF file + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * pXMFData - pointer to XMF parser instance data + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT XMF_FindFileContents(S_EAS_DATA *pEASData, S_XMF_DATA *pXMFData, EAS_FILE_HANDLE fileHandle) +{ + EAS_RESULT result; + EAS_I32 offset; + EAS_I32 value; + EAS_I32 numItems; + EAS_I32 length; + EAS_CHAR id[4]; + EAS_I32 location; + + /* init dls offset, so that we know we haven't found a dls chunk yet */ + pXMFData->dlsOffset = 0; + + /* read file length, ignore it for now */ + if ((result = XMF_ReadVLQ(pEASData, fileHandle, &value)) != EAS_SUCCESS) + return result; + + /* read MetaDataTypesTable length and skip over it */ + if ((result = XMF_ReadVLQ(pEASData, fileHandle, &value)) != EAS_SUCCESS) + return result; + if ((result = EAS_HWFileSeekOfs(pEASData, fileHandle, value)) != EAS_SUCCESS) + return result; + + /* get TreeStart offset and jump to it */ + if ((result = XMF_ReadVLQ(pEASData, fileHandle, &offset)) != EAS_SUCCESS) + return result; + if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, offset)) != EAS_SUCCESS) + return result; + + /* read node length, ignore it for now */ + if ((result = XMF_ReadVLQ(pEASData, fileHandle, &value)) != EAS_SUCCESS) + return result; + + /* read number of contained items */ + if ((result = XMF_ReadVLQ(pEASData, fileHandle, &numItems)) != EAS_SUCCESS) + return result; + + /*read node header length */ + if ((result = XMF_ReadVLQ(pEASData, fileHandle, &value)) != EAS_SUCCESS) + return result; + + /*go to the node offset */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, offset + value)) != EAS_SUCCESS) + return result; + + /* read Reference Type */ + if ((result = XMF_ReadVLQ(pEASData, fileHandle, &value)) != EAS_SUCCESS) + return result; + + /* make sure it is an in-line resource, for now */ + if (value != 1) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Problem parsing XMF file tree\n"); */ } + return EAS_FAILURE; + } + + /* parse through the list of items */ + while (numItems > 0) + { + /*get current offset */ + if ((result = EAS_HWFilePos(pEASData->hwInstData, fileHandle, &offset)) != EAS_SUCCESS) + return result; + + /*read node length */ + if ((result = XMF_ReadVLQ(pEASData, fileHandle, &length)) != EAS_SUCCESS) + return result; + + /* read number of items */ + if ((result = XMF_ReadVLQ(pEASData, fileHandle, &value)) != EAS_SUCCESS) + return result; + + /* make sure not a folder */ + if (value != 0) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Problem parsing XMF file node\n"); */ } + return EAS_FAILURE; + } + + /* read offset to resource and jump to it */ + if ((result = XMF_ReadVLQ(pEASData, fileHandle, &value)) != EAS_SUCCESS) + return result; + if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, offset + value)) != EAS_SUCCESS) + return result; + + /* read Reference Type */ + if ((result = XMF_ReadVLQ(pEASData, fileHandle, &value)) != EAS_SUCCESS) + return result; + + /* make sure it is an in-line resource */ + if (value != 1) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Problem parsing XMF file node\n"); */ } + return EAS_FAILURE; + } + + /* get current offset as a possible location for SMF file or DLS file */ + if ((result = EAS_HWFilePos(pEASData->hwInstData, fileHandle, &location)) != EAS_SUCCESS) + return result; + + /* read four bytes */ + if ((result = EAS_HWReadFile(pEASData->hwInstData, fileHandle, id, sizeof(id), &value)) != EAS_SUCCESS) + return result; + + /* check if DLS */ + if (pXMFData->dlsOffset == 0 && id[0] == 'R' && id[1] == 'I' && id[2] == 'F' && id[3] == 'F') + { + //remember offset + pXMFData->dlsOffset = location; + } + + /* else check if SMF */ + else if (id[0] == 'M' && id[1] == 'T' && id[2] == 'h' && id[3] == 'd') + { + //remember offset + pXMFData->midiOffset = location; + + //we are done + return EAS_SUCCESS; + } + + //one less item + numItems--; + + //if more data, go to the next item + if (numItems >0) + { + if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, offset + length)) != EAS_SUCCESS) + return result; + } + } + + return EAS_FAILURE; + +} +#endif + +/*---------------------------------------------------------------------------- + * XMF_ReadVLQ() + *---------------------------------------------------------------------------- + * Purpose: + * Reads a VLQ encoded value from the file referenced by fileHandle + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * fileHandle - pointer to file handle + * + * Outputs: + * value - pointer to the value decoded from the VLQ data + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT XMF_ReadVLQ (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle, EAS_I32 *value) +{ + EAS_RESULT result; + EAS_U8 c; + + *value = 0; + + if ((result = EAS_HWGetByte(hwInstData, fileHandle, &c)) != EAS_SUCCESS) + return result; + + while (c > 0x7F) + { + /*lint -e{703} shift for performance */ + *value = (*value << 7) | (c & 0x7F); + + if ((result = EAS_HWGetByte(hwInstData, fileHandle, &c)) != EAS_SUCCESS) + return result; + } + + /*lint -e{703} shift for performance */ + *value = (*value << 7) | c; + + return EAS_SUCCESS; +} + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_xmf.h b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_xmf.h new file mode 100755 index 0000000..b8f7a24 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_xmf.h @@ -0,0 +1,60 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_xmf.h + * + * Contents and purpose: + * XMF Type 0 and 1 File Parser + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_XMF_H +#define _EAS_XMF_H + +#ifndef MAX_XMF_STREAMS +#define MAX_XMF_STREAMS 16 +#endif + +/* offsets in to the XMF file */ +#define XMF_OFS_HEADER_SIZE 4 +#define XMF_OFS_FILE_TYPE 8 +#define XMF_OFS_NUM_TRACKS 10 + +/* size of chunk info (chunk ID + chunk size) */ +#define XMF_CHUNK_INFO_SIZE 8 + +/* 'MTrk' track chunk ID */ +#define XMF_CHUNK_TYPE_TRACK 0x4d54726bL + +/* some useful meta-events */ +#define XMF_META_END_OF_TRACK 0x2f +#define XMF_META_TEMPO 0x51 + +/* default timebase (120BPM) */ +#define XMF_DEFAULT_TIMEBASE 500000L + +/* value for pXMFStream->ticks to signify end of track */ +#define XMF_END_OF_TRACK 0xffffffff + +#endif /* end _EAS_XMF_H */ + + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_xmfdata.c b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_xmfdata.c new file mode 100755 index 0000000..f305c12 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_xmfdata.c @@ -0,0 +1,44 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_xmfdata.c + * + * Contents and purpose: + * XMF File Parser + * + * This file contains data definitions for the XMF parser. + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 547 $ + * $Date: 2007-01-31 16:30:17 -0800 (Wed, 31 Jan 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_miditypes.h" +#include "eas_xmf.h" +#include "eas_xmfdata.h" + +/*---------------------------------------------------------------------------- + * + * eas_XMFData + * + * Static memory allocation for XMF parser + *---------------------------------------------------------------------------- +*/ +S_XMF_DATA eas_XMFData; + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_xmfdata.h b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_xmfdata.h new file mode 100755 index 0000000..fce02a1 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/eas_xmfdata.h @@ -0,0 +1,55 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_xmfdata.h + * + * Contents and purpose: + * Contains declarations for the XMF file parser. + * + * + * Copyright Sonic Network Inc. 2005 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 82 $ + * $Date: 2006-07-10 11:45:19 -0700 (Mon, 10 Jul 2006) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _EAS_XMFDATA_H +#define _EAS_XMFDATA_H + +#include "eas_data.h" + +/*---------------------------------------------------------------------------- + * + * S_XMF_DATA + * + * This structure contains the instance data required to parse an XMF file. + * + *---------------------------------------------------------------------------- +*/ + +typedef struct +{ + EAS_FILE_HANDLE fileHandle; + EAS_I32 fileOffset; + EAS_VOID_PTR pSMFData; + EAS_I32 midiOffset; + EAS_I32 dlsOffset; + S_DLS *pDLS; +} S_XMF_DATA; + +#endif diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/jet.c b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/jet.c new file mode 100755 index 0000000..97672cf --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/jet.c @@ -0,0 +1,1129 @@ +/*---------------------------------------------------------------------------- + * + * File: + * jet.c + * + * Contents and purpose: + * Implementation for JET sound engine + * + * Copyright (c) 2006 Sonic Network Inc. + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 563 $ + * $Date: 2007-02-13 20:26:23 -0800 (Tue, 13 Feb 2007) $ + *---------------------------------------------------------------------------- +*/ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "JET_C" + +//#define DEBUG_JET + +#include "eas_data.h" +#include "eas_smf.h" +#include "jet_data.h" +#include "eas_host.h" +#include "eas_report.h" + + +/* default configuration */ +static const S_JET_CONFIG jetDefaultConfig = +{ + JET_EVENT_APP_LOW, + JET_EVENT_APP_HIGH +}; + +/* function prototypes */ +extern EAS_RESULT EAS_IntSetStrmParam (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_INT param, EAS_I32 value); +extern EAS_RESULT EAS_OpenJETStream (EAS_DATA_HANDLE pEASData, EAS_FILE_HANDLE fileHandle, EAS_I32 offset, EAS_HANDLE *ppStream); +extern EAS_RESULT DLSParser (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle, EAS_I32 offset, EAS_DLSLIB_HANDLE *ppDLS); + +/*---------------------------------------------------------------------------- + * JET_ParseEvent() + *---------------------------------------------------------------------------- + * Returns current status + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC void JET_ParseEvent (EAS_U32 event, S_JET_EVENT *pEvent) +{ + pEvent->segment = (EAS_U8) ((event & JET_EVENT_SEG_MASK) >> JET_EVENT_SEG_SHIFT); + pEvent->track = (EAS_U8) ((event & JET_EVENT_TRACK_MASK) >> JET_EVENT_TRACK_SHIFT); + pEvent->channel = (EAS_U8) ((event & JET_EVENT_CHAN_MASK) >> JET_EVENT_CHAN_SHIFT); + pEvent->controller = (EAS_U8) ((event & JET_EVENT_CTRL_MASK) >> JET_EVENT_CTRL_SHIFT); + pEvent->value = (EAS_U8) (event & JET_EVENT_VAL_MASK); +} + +#ifdef DEBUG_JET +/*---------------------------------------------------------------------------- + * JET_DumpEvent + *---------------------------------------------------------------------------- + * Advances queue read/write index + *---------------------------------------------------------------------------- +*/ +static void JET_DumpEvent (const char *procName, EAS_U32 event) +{ + S_JET_EVENT sEvent; + JET_ParseEvent(event, &sEvent); + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "%s: SegID=%d, TrkID=%d, channel=%d, ctrl=%d, val=%d\n", + procName, sEvent.segment, sEvent.track, sEvent.channel, sEvent.controller, sEvent.value); */ } +} +#endif + +/*---------------------------------------------------------------------------- + * JET_IncQueueIndex + *---------------------------------------------------------------------------- + * Advances queue read/write index + *---------------------------------------------------------------------------- +*/ +EAS_INLINE EAS_U8 JET_IncQueueIndex (EAS_U8 index, EAS_U8 queueSize) +{ + if (++index == queueSize) + index = 0; + return index; +} + +/*---------------------------------------------------------------------------- + * JET_WriteQueue + *---------------------------------------------------------------------------- + * Save event to queue + *---------------------------------------------------------------------------- +*/ +EAS_INLINE void JET_WriteQueue (EAS_U32 *pEventQueue, EAS_U8 *pWriteIndex, EAS_U8 readIndex, EAS_U8 queueSize, EAS_U32 event) +{ + EAS_U8 temp; + + /* check for queue overflow */ + temp = JET_IncQueueIndex(*pWriteIndex, queueSize); + if (temp == readIndex) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "JET_Event: Event queue overflow --- event ignored!\n"); */ } + return; + } + + /* save in queue and advance write index */ + pEventQueue[*pWriteIndex] = event; + *pWriteIndex = temp; +} + +/*---------------------------------------------------------------------------- + * JET_ReadQueue + *---------------------------------------------------------------------------- + * Read event to queue + *---------------------------------------------------------------------------- +*/ +EAS_INLINE EAS_BOOL JET_ReadQueue (EAS_U32 *pEventQueue, EAS_U8 *pReadIndex, EAS_U8 writeIndex, EAS_U8 queueSize, EAS_U32 *pEvent) +{ + + /* check for empty queue */ + if (*pReadIndex == writeIndex) + return EAS_FALSE; + + /* save in queue and advance write index */ + *pEvent = pEventQueue[*pReadIndex]; + *pReadIndex = JET_IncQueueIndex(*pReadIndex, queueSize); + return EAS_TRUE; +} + +/*---------------------------------------------------------------------------- + * JET_NextSegment + *---------------------------------------------------------------------------- + * Advances segment number + *---------------------------------------------------------------------------- +*/ +EAS_INLINE EAS_INT JET_NextSegment (EAS_INT seg_num) +{ + if (++seg_num == SEG_QUEUE_DEPTH) + seg_num = 0; + return seg_num; +} + +/*---------------------------------------------------------------------------- + * JET_PrepareSegment() + *---------------------------------------------------------------------------- + * Prepare a segment for playback + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT JET_PrepareSegment (EAS_DATA_HANDLE easHandle, EAS_I32 queueNum) +{ + EAS_RESULT result; + S_JET_SEGMENT *p; + + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "JET_PrepareSegment: %d\n", queueNum); */ } + + p = &easHandle->jetHandle->segQueue[queueNum]; + result = EAS_Prepare(easHandle, p->streamHandle); + if (result != EAS_SUCCESS) + return result; + + /* pause segment - must be triggered by play or end of previous segment */ + result = EAS_Pause(easHandle, p->streamHandle); + if (result != EAS_SUCCESS) + return result; + p->state = JET_STATE_READY; + + /* set calback data */ + result = EAS_IntSetStrmParam(easHandle, p->streamHandle, PARSER_DATA_JET_CB, queueNum); + if (result != EAS_SUCCESS) + return result; + + /* set DLS collection */ + if (p->libNum >= 0) + { + result = EAS_IntSetStrmParam(easHandle, p->streamHandle, + PARSER_DATA_DLS_COLLECTION, (EAS_I32) easHandle->jetHandle->libHandles[p->libNum]); + if (result != EAS_SUCCESS) + return result; + } + + /* set transposition */ + if (p->transpose) + { + result = EAS_SetTransposition(easHandle, p->streamHandle, p->transpose); + if (result != EAS_SUCCESS) + return result; + } + + return result; +} + +/*---------------------------------------------------------------------------- + * JET_StartPlayback() + *---------------------------------------------------------------------------- + * Start segment playback + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT JET_StartPlayback (EAS_DATA_HANDLE easHandle, EAS_I32 queueNum) +{ + EAS_RESULT result = EAS_SUCCESS; + S_JET_SEGMENT *pSeg; + + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "JET_StartPlayback %d\n", queueNum); */ } + + /* if next segment is queued, start playback */ + pSeg = &easHandle->jetHandle->segQueue[queueNum]; + if (pSeg->streamHandle != NULL) + { + result = EAS_Resume(easHandle, pSeg->streamHandle); + easHandle->jetHandle->segQueue[queueNum].state = JET_STATE_PLAYING; + + /* set mute flags */ + if ((result == EAS_SUCCESS) && (pSeg->muteFlags != 0)) + result = EAS_IntSetStrmParam(easHandle, pSeg->streamHandle, PARSER_DATA_MUTE_FLAGS, (EAS_I32) pSeg->muteFlags); + } + return result; +} + +/*---------------------------------------------------------------------------- + * JET_CloseSegment + *---------------------------------------------------------------------------- + * Closes stream associated with a segment + *---------------------------------------------------------------------------- +*/ +EAS_INLINE EAS_INT JET_CloseSegment (EAS_DATA_HANDLE easHandle, EAS_INT queueNum) +{ + EAS_RESULT result; + + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "JET_CloseSegment %d\n", queueNum); */ } + + /* close the segment */ + result = EAS_CloseFile(easHandle, easHandle->jetHandle->segQueue[queueNum].streamHandle); + if (result != EAS_SUCCESS) + return result; + + easHandle->jetHandle->segQueue[queueNum].streamHandle = NULL; + easHandle->jetHandle->segQueue[queueNum].state = JET_STATE_CLOSED; + easHandle->jetHandle->numQueuedSegments--; + return result; +} + +/*---------------------------------------------------------------------------- + * JetParseInfoChunk() + *---------------------------------------------------------------------------- + * Parses the JET info chunk + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT JetParseInfoChunk (EAS_DATA_HANDLE easHandle, EAS_I32 pos, EAS_I32 chunkSize) +{ + EAS_RESULT result; + EAS_U32 infoType; + EAS_U32 temp; + + /* offset to data */ + result = EAS_HWFileSeek(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle, pos); + if (result != EAS_SUCCESS) + return result; + + /* read the entire chunk */ + result = EAS_SUCCESS; + while ((result == EAS_SUCCESS) && (chunkSize > 0)) + { + + /* get info infoType */ + result = EAS_HWGetDWord(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle, &infoType, EAS_TRUE); + if (result != EAS_SUCCESS) + break; + + /* get info field */ + result = EAS_HWGetDWord(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle, &temp, EAS_FALSE); + if (result == EAS_SUCCESS) + + switch (infoType) + { + case INFO_NUM_SMF_CHUNKS: + easHandle->jetHandle->numSegments = (EAS_U8) temp; + break; + + case INFO_NUM_DLS_CHUNKS: + easHandle->jetHandle->numLibraries = (EAS_U8) temp; + break; + + case INFO_JET_VERSION: + /* check major version number */ + if ((temp & 0xff000000) != (JET_VERSION & 0xff000000)) + return EAS_ERROR_INCOMPATIBLE_VERSION; + break; + + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Ignoring unrecognized JET info type 0x%08x", infoType); */ } + break; + } + + chunkSize -= 8; + } + + /* allocate pointers for chunks to follow */ + + return result; +} + +/*---------------------------------------------------------------------------- + * JET_OpenFile() + *---------------------------------------------------------------------------- + * Opens a JET content file for playback + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT JET_OpenFile (EAS_DATA_HANDLE easHandle, EAS_FILE_LOCATOR locator) +{ + EAS_RESULT result; + EAS_U32 chunkType; + EAS_I32 pos; + EAS_I32 chunkSize; + EAS_INT smfChunkNum; + EAS_INT dlsChunkNum; + EAS_I32 dataSize = 0; /* make lint happy */ + + /* make sure that we don't have an open file */ + if (easHandle->jetHandle->jetFileHandle != NULL) + return EAS_ERROR_FILE_ALREADY_OPEN; + + /* open the media file */ + result = EAS_HWOpenFile(easHandle->hwInstData, locator, &easHandle->jetHandle->jetFileHandle, EAS_FILE_READ); + if (result != EAS_SUCCESS) + return result; + + /* check header */ + result = EAS_HWGetDWord(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle, &chunkType, EAS_TRUE); + if (result == EAS_SUCCESS) + { + if (chunkType != JET_HEADER_TAG) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "File is not JET format\n"); */ } + result = EAS_ERROR_UNRECOGNIZED_FORMAT; + } + } + /* get the file data size */ + if (result == EAS_SUCCESS) + result = EAS_HWGetDWord(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle, &dataSize, EAS_FALSE); + + /* parse through the file to find contents */ + smfChunkNum = dlsChunkNum = 0; + pos = chunkSize = 8; + while ((result == EAS_SUCCESS) && (pos < dataSize)) + { + + /* offset to chunk data */ + result = EAS_HWFileSeek(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle, pos); + if (result != EAS_SUCCESS) + break; + + /* get chunk size and type */ + result = EAS_HWGetDWord(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle, &chunkType, EAS_TRUE); + if (result != EAS_SUCCESS) + break; + + result = EAS_HWGetDWord(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle, &chunkSize, EAS_FALSE); + if (result != EAS_SUCCESS) + break; + pos += 8; + + switch (chunkType) + { + case JET_INFO_CHUNK: + result = JetParseInfoChunk(easHandle, pos, chunkSize); + break; + + case JET_SMF_CHUNK: + if (smfChunkNum < easHandle->jetHandle->numSegments) + easHandle->jetHandle->segmentOffsets[smfChunkNum++] = pos; + else + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Ignoring extraneous SMF chunk"); */ } + break; + + case JET_DLS_CHUNK: + if (dlsChunkNum < easHandle->jetHandle->numLibraries) + result = DLSParser(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle, pos, &easHandle->jetHandle->libHandles[dlsChunkNum++]); + else + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Ignoring extraneous DLS chunk"); */ } + break; + + case JET_APP_DATA_CHUNK: + easHandle->jetHandle->appDataOffset = pos; + easHandle->jetHandle->appDataSize = chunkSize; + break; + + case INFO_JET_COPYRIGHT: + break; + + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Ignoring unrecognized JET chunk type 0x%08x", chunkType); */ } + break; + } + + /* offset to next chunk */ + pos += chunkSize; + } + + /* close file if something went wrong */ + if (result != EAS_SUCCESS) + EAS_HWCloseFile(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle); + + return result; +} + +/*---------------------------------------------------------------------------- + * JET_GetAppData() + *---------------------------------------------------------------------------- + * Returns location and size of application data in the JET file + *---------------------------------------------------------------------------- +*/ +EAS_RESULT JET_GetAppData (EAS_DATA_HANDLE easHandle, EAS_I32 *pAppDataOffset, EAS_I32 *pAppDataSize) +{ + + /* check for app chunk */ + if (easHandle->jetHandle->appDataSize == 0) + { + *pAppDataOffset = *pAppDataSize = 0; + return EAS_FAILURE; + } + + /* return app data */ + *pAppDataOffset = easHandle->jetHandle->appDataOffset; + *pAppDataSize = easHandle->jetHandle->appDataSize; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * JET_CloseFile() + *---------------------------------------------------------------------------- + * Closes a JET content file and releases associated resources + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT JET_CloseFile (EAS_DATA_HANDLE easHandle) +{ + EAS_INT index; + EAS_RESULT result = EAS_SUCCESS; + + /* close open streams */ + for (index = 0; index < SEG_QUEUE_DEPTH; index++) + { + if (easHandle->jetHandle->segQueue[index].streamHandle != NULL) + { + result = JET_CloseSegment(easHandle, index); + if (result != EAS_SUCCESS) + break; + } + } + + /* close the main file handle */ + if ((result == EAS_SUCCESS) && (easHandle->jetHandle->jetFileHandle != NULL)) + { + result = EAS_HWCloseFile(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle); + if (result == EAS_SUCCESS) + easHandle->jetHandle->jetFileHandle = NULL; + } + return result; +} + +/*---------------------------------------------------------------------------- + * JET_Init() + *---------------------------------------------------------------------------- + * Initializes the JET library, allocates memory, etc. Call + * JET_Shutdown to de-allocate memory. + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT JET_Init (EAS_DATA_HANDLE easHandle, const S_JET_CONFIG *pConfig, EAS_INT configSize) +{ + S_JET_DATA *pJet; + EAS_U8 flags = 0; + + /* sanity check */ + if (easHandle == NULL) + return EAS_ERROR_HANDLE_INTEGRITY; + if (easHandle->jetHandle != NULL) + return EAS_ERROR_FEATURE_ALREADY_ACTIVE; + if (pConfig == NULL) + pConfig = &jetDefaultConfig; + + /* allocate the JET data object */ + pJet = EAS_HWMalloc(easHandle->hwInstData, sizeof(S_JET_DATA)); + if (pJet == NULL) + return EAS_ERROR_MALLOC_FAILED; + + /* initialize JET data structure */ + EAS_HWMemSet(pJet, 0, sizeof(S_JET_DATA)); + easHandle->jetHandle = pJet; + pJet->flags = flags; + + /* copy config data */ + if (configSize > (EAS_INT) sizeof(S_JET_CONFIG)) + configSize = sizeof(S_JET_CONFIG); + EAS_HWMemCpy(&pJet->config, pConfig, configSize); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * JET_Shutdown() + *---------------------------------------------------------------------------- + * Frees any memory used by the JET library + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT JET_Shutdown (EAS_DATA_HANDLE easHandle) +{ + EAS_RESULT result; + + /* close any open files */ + result = JET_CloseFile(easHandle); + + /* free allocated data */ + EAS_HWFree(easHandle->hwInstData, easHandle->jetHandle); + easHandle->jetHandle = NULL; + return result; +} + +/*---------------------------------------------------------------------------- + * JET_Status() + *---------------------------------------------------------------------------- + * Returns current status + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT JET_Status (EAS_DATA_HANDLE easHandle, S_JET_STATUS *pStatus) +{ + S_JET_SEGMENT *pSeg; + + pSeg = &easHandle->jetHandle->segQueue[easHandle->jetHandle->playSegment]; + if (pSeg->streamHandle != NULL) + { + pStatus->currentUserID = pSeg->userID; + pStatus->segmentRepeatCount = pSeg->repeatCount; + } + else + { + pStatus->currentUserID = -1; + pStatus->segmentRepeatCount = 0; + } + + pStatus->paused = !(easHandle->jetHandle->flags & JET_FLAGS_PLAYING); + pStatus->numQueuedSegments = easHandle->jetHandle->numQueuedSegments; + pStatus->currentPlayingSegment = easHandle->jetHandle->playSegment; + pStatus->currentQueuedSegment = easHandle->jetHandle->queueSegment; + if (pSeg->streamHandle != NULL) + { + EAS_RESULT result; + EAS_I32 location ; + if ((result = EAS_GetLocation(easHandle, pSeg->streamHandle, &location)) == EAS_SUCCESS) + if(location != 0) + { + pStatus->location = location; + } + } + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * JET_GetEvent() + *---------------------------------------------------------------------------- + * Checks for application events + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_BOOL JET_GetEvent (EAS_DATA_HANDLE easHandle, EAS_U32 *pEventRaw, S_JET_EVENT *pEvent) +{ + EAS_U32 jetEvent; + EAS_BOOL gotEvent; + + /* process event queue */ + gotEvent = JET_ReadQueue(easHandle->jetHandle->appEventQueue, + &easHandle->jetHandle->appEventQueueRead, + easHandle->jetHandle->appEventQueueWrite, + APP_EVENT_QUEUE_SIZE, &jetEvent); + + if (gotEvent) + { + if (pEventRaw != NULL) + *pEventRaw = jetEvent; + + if (pEvent != NULL) + JET_ParseEvent(jetEvent, pEvent); + } + + return gotEvent; +} + +/*---------------------------------------------------------------------------- + * JET_QueueSegment() + *---------------------------------------------------------------------------- + * Queue a segment for playback + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT JET_QueueSegment (EAS_DATA_HANDLE easHandle, EAS_INT segmentNum, EAS_INT libNum, EAS_INT repeatCount, EAS_INT transpose, EAS_U32 muteFlags, EAS_U8 userID) +{ + EAS_FILE_HANDLE fileHandle; + EAS_RESULT result; + S_JET_SEGMENT *p; + + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "JET_QueueSegment segNum=%d, queue=%d\n", segmentNum, easHandle->jetHandle->queueSegment); */ } + + /* make sure it's a valid segment */ + if (segmentNum >= easHandle->jetHandle->numSegments) + return EAS_ERROR_PARAMETER_RANGE; + + /* make sure it's a valid DLS */ + if (libNum >= easHandle->jetHandle->numLibraries) + return EAS_ERROR_PARAMETER_RANGE; + + /* check to see if queue is full */ + p = &easHandle->jetHandle->segQueue[easHandle->jetHandle->queueSegment]; + if (p->streamHandle != NULL) + return EAS_ERROR_QUEUE_IS_FULL; + + /* initialize data */ + p->userID = userID; + p->repeatCount = (EAS_I16) repeatCount; + p->transpose = (EAS_I8) transpose; + p->libNum = (EAS_I8) libNum; + p->muteFlags = muteFlags; + p->state = JET_STATE_CLOSED; + + /* open the file */ + result = EAS_OpenJETStream(easHandle, easHandle->jetHandle->jetFileHandle, easHandle->jetHandle->segmentOffsets[segmentNum], &p->streamHandle); + if (result != EAS_SUCCESS) + return result; + p->state = JET_STATE_OPEN; + + /* if less than SEG_QUEUE_DEPTH segments queued up, prepare file for playback */ + if (++easHandle->jetHandle->numQueuedSegments < SEG_QUEUE_DEPTH) + { + result = JET_PrepareSegment(easHandle, easHandle->jetHandle->queueSegment); + if (result != EAS_SUCCESS) + return result; + } + + /* create duplicate file handle */ + result = EAS_HWDupHandle(easHandle->hwInstData, easHandle->jetHandle->jetFileHandle, &fileHandle); + if (result != EAS_SUCCESS) + return result; + + easHandle->jetHandle->jetFileHandle = fileHandle; + easHandle->jetHandle->queueSegment = (EAS_U8) JET_NextSegment(easHandle->jetHandle->queueSegment); + return result; +} + +/*---------------------------------------------------------------------------- + * JET_Play() + *---------------------------------------------------------------------------- + * Starts playback of the file + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT JET_Play (EAS_DATA_HANDLE easHandle) +{ + EAS_RESULT result; + EAS_INT index; + EAS_INT count = 0; + + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "JET_Play\n"); */ } + + /* sanity check */ + if (easHandle->jetHandle->flags & JET_FLAGS_PLAYING) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + /* resume all paused streams */ + for (index = 0; index < SEG_QUEUE_DEPTH; index++) + { + if (((index == easHandle->jetHandle->playSegment) && (easHandle->jetHandle->segQueue[index].state == JET_STATE_READY)) || + (easHandle->jetHandle->segQueue[index].state == JET_STATE_PAUSED)) + { + result = JET_StartPlayback(easHandle, index); + if (result != EAS_SUCCESS) + return result; + count++; + } + } + + /* if no streams are playing, return error */ + if (!count) + return EAS_ERROR_QUEUE_IS_EMPTY; + + easHandle->jetHandle->flags |= JET_FLAGS_PLAYING; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * JET_Pause() + *---------------------------------------------------------------------------- + * Pauses playback of the file + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT JET_Pause (EAS_DATA_HANDLE easHandle) +{ + EAS_RESULT result; + EAS_INT index; + EAS_INT count = 0; + + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "JET_Pause\n"); */ } + + /* sanity check */ + if ((easHandle->jetHandle->flags & JET_FLAGS_PLAYING) == 0) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + /* pause all playing streams */ + for (index = 0; index < SEG_QUEUE_DEPTH; index++) + { + if (easHandle->jetHandle->segQueue[index].state == JET_STATE_PLAYING) + { + result = EAS_Pause(easHandle, easHandle->jetHandle->segQueue[easHandle->jetHandle->playSegment].streamHandle); + if (result != EAS_SUCCESS) + return result; + easHandle->jetHandle->segQueue[easHandle->jetHandle->playSegment].state = JET_STATE_PAUSED; + count++; + } + } + + /* if no streams are paused, return error */ + if (!count) + return EAS_ERROR_QUEUE_IS_EMPTY; + + easHandle->jetHandle->flags &= ~JET_FLAGS_PLAYING; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * JET_SetMuteFlags() + *---------------------------------------------------------------------------- + * Change the state of the mute flags + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT JET_SetMuteFlags (EAS_DATA_HANDLE easHandle, EAS_U32 muteFlags, EAS_BOOL sync) +{ + S_JET_SEGMENT *pSeg; + + /* get pointer to current segment */ + pSeg = &easHandle->jetHandle->segQueue[easHandle->jetHandle->playSegment]; + + /* unsynchronized mute, set flags and return */ + if (!sync) + { + if (pSeg->streamHandle == NULL) + return EAS_ERROR_QUEUE_IS_EMPTY; + pSeg->muteFlags = muteFlags; + return EAS_IntSetStrmParam(easHandle, pSeg->streamHandle, PARSER_DATA_MUTE_FLAGS, (EAS_I32) muteFlags); + } + + + /* check for valid stream state */ + if (pSeg->state == JET_STATE_CLOSED) + return EAS_ERROR_QUEUE_IS_EMPTY; + + /* save mute flags */ + pSeg->muteFlags = muteFlags; + + /* if repeating segment, set mute update flag */ + if (sync) + pSeg->flags |= JET_SEG_FLAG_MUTE_UPDATE; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * JET_SetMuteFlag() + *---------------------------------------------------------------------------- + * Change the state of a single mute flag + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT JET_SetMuteFlag (EAS_DATA_HANDLE easHandle, EAS_INT trackNum, EAS_BOOL muteFlag, EAS_BOOL sync) +{ + S_JET_SEGMENT *pSeg; + EAS_U32 trackMuteFlag; + + + /* setup flag */ + if ((trackNum < 0) || (trackNum > 31)) + return EAS_ERROR_PARAMETER_RANGE; + trackMuteFlag = (1 << trackNum); + + /* get pointer to current segment */ + pSeg = &easHandle->jetHandle->segQueue[easHandle->jetHandle->playSegment]; + + /* unsynchronized mute, set flags and return */ + if (!sync) + { + if (pSeg->streamHandle == NULL) + return EAS_ERROR_QUEUE_IS_EMPTY; + if (muteFlag) + pSeg->muteFlags |= trackMuteFlag; + else + pSeg->muteFlags &= ~trackMuteFlag; + return EAS_IntSetStrmParam(easHandle, pSeg->streamHandle, PARSER_DATA_MUTE_FLAGS, (EAS_I32) pSeg->muteFlags); + } + + + /* check for valid stream state */ + if (pSeg->state == JET_STATE_CLOSED) + return EAS_ERROR_QUEUE_IS_EMPTY; + + /* save mute flags and set mute update flag */ + if (muteFlag) + pSeg->muteFlags |= trackMuteFlag; + else + pSeg->muteFlags &= ~trackMuteFlag; + pSeg->flags |= JET_SEG_FLAG_MUTE_UPDATE; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * JET_TriggerClip() + *---------------------------------------------------------------------------- + * Unmute a track and then mute it when it is complete. If a clip + * is already playing, change mute event to a trigger event. The + * JET_Event function will not mute the clip, but will allow it + * to continue playing through the next clip. + * + * NOTE: We use bit 7 to indicate an entry in the queue. For a + * small queue, it is cheaper in both memory and CPU cycles to + * scan the entire queue for non-zero events than keep enqueue + * and dequeue indices. + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT JET_TriggerClip (EAS_DATA_HANDLE easHandle, EAS_INT clipID) +{ + EAS_INT i; + EAS_INT index = -1; + + /* check for valid clipID */ + if ((clipID < 0) || (clipID > 63)) + return EAS_ERROR_PARAMETER_RANGE; + + /* set active flag */ + clipID |= JET_CLIP_ACTIVE_FLAG; + + /* Reverse the search so that we get the first empty element */ + for (i = JET_MUTE_QUEUE_SIZE-1; i >= 0 ; i--) + { + if (easHandle->jetHandle->muteQueue[i] == clipID) + { + index = i; + break; + } + if (easHandle->jetHandle->muteQueue[i] == 0) + index = i; + } + if (index < 0) + return EAS_ERROR_QUEUE_IS_FULL; + + easHandle->jetHandle->muteQueue[index] = (EAS_U8) clipID | JET_CLIP_TRIGGER_FLAG; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * JET_Process() + *---------------------------------------------------------------------------- + * Called during EAS_Render to process stream states + *---------------------------------------------------------------------------- +*/ +EAS_PUBLIC EAS_RESULT JET_Process (EAS_DATA_HANDLE easHandle) +{ + S_JET_SEGMENT *pSeg; + EAS_STATE state; + EAS_INT index; + EAS_INT playIndex; + EAS_RESULT result = EAS_SUCCESS; + EAS_BOOL endOfLoop = EAS_FALSE; + EAS_BOOL startNextSegment = EAS_FALSE; + EAS_BOOL prepareNextSegment = EAS_FALSE; + EAS_U32 jetEvent; + + /* process event queue */ + while (JET_ReadQueue(easHandle->jetHandle->jetEventQueue, + &easHandle->jetHandle->jetEventQueueRead, + easHandle->jetHandle->jetEventQueueWrite, + JET_EVENT_QUEUE_SIZE, &jetEvent)) + { + S_JET_EVENT event; +#ifdef DEBUG_JET + JET_DumpEvent("JET_Process", jetEvent); +#endif + JET_ParseEvent(jetEvent, &event); + + /* check for end of loop */ + if ((event.controller == JET_EVENT_MARKER) && + (event.value == JET_MARKER_LOOP_END) && + (easHandle->jetHandle->segQueue[easHandle->jetHandle->playSegment].streamHandle != NULL)) + endOfLoop = EAS_TRUE; + } + + /* check state of all streams */ + index = playIndex = easHandle->jetHandle->playSegment; + for (;;) + { + pSeg = &easHandle->jetHandle->segQueue[index]; + if (pSeg->state != JET_STATE_CLOSED) + { + + /* get playback state */ + result = EAS_State(easHandle, pSeg->streamHandle, &state); + if (result != EAS_SUCCESS) + return result; + + /* process state */ + switch (pSeg->state) + { + /* take action if this segment is stopping */ + case JET_STATE_PLAYING: + if (endOfLoop || (state == EAS_STATE_STOPPING) || (state == EAS_STATE_STOPPED)) + { + /* handle repeats */ + if (pSeg->repeatCount != 0) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "JET_Render repeating segment %d\n", index); */ } + result = EAS_Locate(easHandle, pSeg->streamHandle, 0, EAS_FALSE); + if (result != EAS_SUCCESS) + return result; + if (pSeg->repeatCount > 0) + pSeg->repeatCount--; + + /* update mute flags if necessary */ + if (pSeg->flags & JET_SEG_FLAG_MUTE_UPDATE) + { + result = EAS_IntSetStrmParam(easHandle, pSeg->streamHandle, PARSER_DATA_MUTE_FLAGS, (EAS_I32) pSeg->muteFlags); + if (result != EAS_SUCCESS) + return result; + pSeg->flags &= ~JET_SEG_FLAG_MUTE_UPDATE; + } + + } + /* no repeat, start next segment */ + else + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "JET_Render stopping queue %d\n", index); */ } + startNextSegment = EAS_TRUE; + pSeg->state = JET_STATE_STOPPING; + easHandle->jetHandle->playSegment = (EAS_U8) JET_NextSegment(index); + } + } + break; + + /* if playback has stopped, close the segment */ + case JET_STATE_STOPPING: + if (state == EAS_STATE_STOPPED) + { + result = JET_CloseSegment(easHandle, index); + if (result != EAS_SUCCESS) + return result; + } + break; + + case JET_STATE_READY: + if (startNextSegment) + { + result = JET_StartPlayback(easHandle, index); + if (result != EAS_SUCCESS) + return result; + startNextSegment = EAS_FALSE; + prepareNextSegment = EAS_TRUE; + } + break; + + case JET_STATE_OPEN: + if (prepareNextSegment) + { + result = JET_PrepareSegment(easHandle, index); + if (result != EAS_SUCCESS) + return result; + prepareNextSegment = EAS_FALSE; + } + break; + + case JET_STATE_PAUSED: + break; + + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "JET_Render: Unexpected segment state %d\n", pSeg->state); */ } + break; + } + } + + /* increment index */ + index = JET_NextSegment(index); + if (index == playIndex) + break; + } + + /* if out of segments, clear playing flag */ + if (easHandle->jetHandle->numQueuedSegments == 0) + easHandle->jetHandle->flags &= ~JET_FLAGS_PLAYING; + + return result; +} + +/*---------------------------------------------------------------------------- + * JET_Event() + *---------------------------------------------------------------------------- + * Called from MIDI parser when data of interest is received + *---------------------------------------------------------------------------- +*/ +void JET_Event (EAS_DATA_HANDLE easHandle, EAS_U32 segTrack, EAS_U8 channel, EAS_U8 controller, EAS_U8 value) +{ + EAS_U32 event; + + if (easHandle->jetHandle == NULL) + return; + + /* handle triggers */ + if (controller == JET_EVENT_TRIGGER_CLIP) + { + S_JET_SEGMENT *pSeg; + EAS_INT i; + EAS_U32 muteFlag; + + for (i = 0; i < JET_MUTE_QUEUE_SIZE; i++) + { + /* search for event in queue */ + if ((easHandle->jetHandle->muteQueue[i] & JET_CLIP_ID_MASK) == (value & JET_CLIP_ID_MASK)) + { + /* get segment pointer and mute flag */ + pSeg = &easHandle->jetHandle->segQueue[segTrack >> JET_EVENT_SEG_SHIFT]; + muteFlag = 1 << ((segTrack & JET_EVENT_TRACK_MASK) >> JET_EVENT_TRACK_SHIFT); + + /* un-mute the track */ + if ((easHandle->jetHandle->muteQueue[i] & JET_CLIP_TRIGGER_FLAG) && ((value & 0x40) > 0)) + { + pSeg->muteFlags &= ~muteFlag; + easHandle->jetHandle->muteQueue[i] &= ~JET_CLIP_TRIGGER_FLAG; + } + + /* mute the track */ + else + { + EAS_U32 beforeMute ; + beforeMute = pSeg->muteFlags ; + pSeg->muteFlags |= muteFlag; + if (beforeMute != pSeg->muteFlags) + easHandle->jetHandle->muteQueue[i] = 0; + } + EAS_IntSetStrmParam(easHandle, pSeg->streamHandle, PARSER_DATA_MUTE_FLAGS, (EAS_I32) pSeg->muteFlags); + return; + } + } + return; + } + + /* generic event stuff */ + event = (channel << JET_EVENT_CHAN_SHIFT) | (controller << JET_EVENT_CTRL_SHIFT) | value; + + /* write to app queue, translate queue index to segment number */ + if ((controller >= easHandle->jetHandle->config.appEventRangeLow) && (controller <= easHandle->jetHandle->config.appEventRangeHigh)) + { + + event |= easHandle->jetHandle->segQueue[(segTrack & JET_EVENT_SEG_MASK) >> JET_EVENT_SEG_SHIFT].userID << JET_EVENT_SEG_SHIFT; +#ifdef DEBUG_JET + JET_DumpEvent("JET_Event[app]", event); +#endif + JET_WriteQueue(easHandle->jetHandle->appEventQueue, + &easHandle->jetHandle->appEventQueueWrite, + easHandle->jetHandle->appEventQueueRead, + APP_EVENT_QUEUE_SIZE, + event); + } + + /* write to JET queue */ + else if ((controller >= JET_EVENT_LOW) && (controller <= JET_EVENT_HIGH)) + { + event |= segTrack; +#ifdef DEBUG_JET + JET_DumpEvent("JET_Event[jet]", event); +#endif + JET_WriteQueue(easHandle->jetHandle->jetEventQueue, + &easHandle->jetHandle->jetEventQueueWrite, + easHandle->jetHandle->jetEventQueueRead, + JET_EVENT_QUEUE_SIZE, + event); + } +} + +/*---------------------------------------------------------------------------- + * JET_Clear_Queue() + *---------------------------------------------------------------------------- + * Clears the queue and stops play without a complete shutdown + *---------------------------------------------------------------------------- +*/ +EAS_RESULT JET_Clear_Queue(EAS_DATA_HANDLE easHandle) +{ + EAS_INT index; + EAS_RESULT result = EAS_SUCCESS; + + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "JET_Clear_Queue\n"); */ } + + /* pause all playing streams */ + for (index = 0; index < SEG_QUEUE_DEPTH; index++) + { + if (easHandle->jetHandle->segQueue[index].state == JET_STATE_PLAYING) + { + result = EAS_Pause(easHandle, easHandle->jetHandle->segQueue[index].streamHandle); + if (result != EAS_SUCCESS) + return result; + + easHandle->jetHandle->segQueue[index].state = JET_STATE_PAUSED; + } + } + + /* close all streams */ + for (index = 0; index < SEG_QUEUE_DEPTH; index++) + { + if (easHandle->jetHandle->segQueue[index].streamHandle != NULL) + { + result = JET_CloseSegment(easHandle, index); + if (result != EAS_SUCCESS) + return result; + } + } + + /* clear all clips */ + for (index = 0; index < JET_MUTE_QUEUE_SIZE ; index++) + { + easHandle->jetHandle->muteQueue[index] = 0; + } + + easHandle->jetHandle->flags &= ~JET_FLAGS_PLAYING; + easHandle->jetHandle->playSegment = easHandle->jetHandle->queueSegment = 0; + return result; +} + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/jet_data.h b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/jet_data.h new file mode 100755 index 0000000..6bd72e0 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/jet_data.h @@ -0,0 +1,183 @@ +/*---------------------------------------------------------------------------- + * + * File: + * jet_data.h + * + * Contents and purpose: + * Internal data structures and interfaces for JET + * + * Copyright (c) 2006 Sonic Network Inc. + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 554 $ + * $Date: 2007-02-02 11:06:10 -0800 (Fri, 02 Feb 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifndef _JET_DATA_H +#define _JET_DATA_H + +#include "eas.h" +#include "jet.h" + +/* maximum number of segments allowed in a JET file */ +#ifndef JET_MAX_SEGMENTS +#define JET_MAX_SEGMENTS 32 +#endif + +/* maximum number of DLS collections allowed in a JET file */ +#ifndef JET_MAX_DLS_COLLECTIONS +#define JET_MAX_DLS_COLLECTIONS 4 +#endif + +/* maximum number of JET events in internal queue */ +#ifndef JET_EVENT_QUEUE_SIZE +#define JET_EVENT_QUEUE_SIZE 32 +#endif + +/* maximum number of JET events in application queue */ +#ifndef APP_EVENT_QUEUE_SIZE +#define APP_EVENT_QUEUE_SIZE 32 +#endif + +/* maximum number of active mute events */ +#ifndef JET_MUTE_QUEUE_SIZE +#define JET_MUTE_QUEUE_SIZE 8 +#endif + +/*---------------------------------------------------------------------------- + * JET event definitions + *---------------------------------------------------------------------------- +*/ +#define JET_EVENT_APP_LOW 80 +#define JET_EVENT_APP_HIGH 83 +#define JET_EVENT_LOW 102 +#define JET_EVENT_HIGH 119 +#define JET_EVENT_MARKER 102 +#define JET_EVENT_TRIGGER_CLIP 103 + +#define JET_MARKER_LOOP_END 0 + +#define JET_CLIP_ACTIVE_FLAG 0x80 +#define JET_CLIP_TRIGGER_FLAG 0x40 +#define JET_CLIP_ID_MASK 0x3f + +/*---------------------------------------------------------------------------- + * JET file definitions + *---------------------------------------------------------------------------- +*/ +#define JET_TAG(a,b,c,d) (\ + ( ((EAS_U32)(a) & 0xFF) << 24 ) \ + + ( ((EAS_U32)(b) & 0xFF) << 16 ) \ + + ( ((EAS_U32)(c) & 0xFF) << 8 ) \ + + ( ((EAS_U32)(d) & 0xFF))) + +#define JET_VERSION 0x01000000 +#define JET_HEADER_TAG JET_TAG('J','E','T',' ') +#define JET_INFO_CHUNK JET_TAG('J','I','N','F') +#define JET_SMF_CHUNK JET_TAG('J','S','M','F') +#define JET_DLS_CHUNK JET_TAG('J','D','L','S') +#define INFO_JET_COPYRIGHT JET_TAG('J','C','O','P') +#define JET_APP_DATA_CHUNK JET_TAG('J','A','P','P') + +#define INFO_NUM_SMF_CHUNKS JET_TAG('S','M','F','#') +#define INFO_NUM_DLS_CHUNKS JET_TAG('D','L','S','#') +#define INFO_JET_VERSION JET_TAG('J','V','E','R') + +/*---------------------------------------------------------------------------- + * S_JET_SEGMENT + * + * JET segment data + *---------------------------------------------------------------------------- +*/ +typedef struct s_jet_segment_tag +{ + EAS_HANDLE streamHandle; + EAS_U32 muteFlags; + EAS_I16 repeatCount; + EAS_U8 userID; + EAS_I8 transpose; + EAS_I8 libNum; + EAS_U8 state; + EAS_U8 flags; +} S_JET_SEGMENT; + +/* S_JET_SEGMENT.state */ +typedef enum +{ + JET_STATE_CLOSED, + JET_STATE_OPEN, + JET_STATE_READY, + JET_STATE_PLAYING, + JET_STATE_PAUSED, + JET_STATE_STOPPING +} E_JET_SEGMENT_STATE; + +/* S_JEG_SEGMENT.flags */ +#define JET_SEG_FLAG_MUTE_UPDATE 0x01 + +/*---------------------------------------------------------------------------- + * S_JET_DATA + * + * Main JET data structure + *---------------------------------------------------------------------------- +*/ +#define SEG_QUEUE_DEPTH 3 +typedef struct s_jet_data_tag +{ + EAS_FILE_HANDLE jetFileHandle; + S_JET_SEGMENT segQueue[SEG_QUEUE_DEPTH]; + EAS_I32 segmentOffsets[JET_MAX_SEGMENTS]; + EAS_I32 appDataOffset; + EAS_I32 appDataSize; + EAS_DLSLIB_HANDLE libHandles[JET_MAX_DLS_COLLECTIONS]; + EAS_U32 jetEventQueue[JET_EVENT_QUEUE_SIZE]; + EAS_U32 appEventQueue[APP_EVENT_QUEUE_SIZE]; + S_JET_CONFIG config; + EAS_U32 segmentTime; + EAS_U8 muteQueue[JET_MUTE_QUEUE_SIZE]; + EAS_U8 numSegments; + EAS_U8 numLibraries; + EAS_U8 flags; + EAS_U8 playSegment; + EAS_U8 queueSegment; + EAS_U8 numQueuedSegments; + EAS_U8 jetEventQueueRead; + EAS_U8 jetEventQueueWrite; + EAS_U8 appEventQueueRead; + EAS_U8 appEventQueueWrite; +} S_JET_DATA; + +/* flags for S_JET_DATA.flags */ +#define JET_FLAGS_PLAYING 1 + +#define JET_EVENT_VAL_MASK 0x0000007f /* mask for value */ +#define JET_EVENT_CTRL_MASK 0x00003f80 /* mask for controller */ +#define JET_EVENT_CHAN_MASK 0x0003c000 /* mask for channel */ +#define JET_EVENT_TRACK_MASK 0x00fc0000 /* mask for track number */ +#define JET_EVENT_SEG_MASK 0xff000000 /* mask for segment ID */ +#define JET_EVENT_CTRL_SHIFT 7 /* shift for controller number */ +#define JET_EVENT_CHAN_SHIFT 14 /* shift to for MIDI channel */ +#define JET_EVENT_TRACK_SHIFT 18 /* shift to get track ID to bit 0 */ +#define JET_EVENT_SEG_SHIFT 24 /* shift to get segment ID to bit 0 */ + +/* prototype for callback function */ +extern void JET_Event (EAS_DATA_HANDLE easHandle, EAS_U32 segTrack, EAS_U8 channel, EAS_U8 controller, EAS_U8 value); + +/* prototype for JET render function */ +extern EAS_PUBLIC EAS_RESULT JET_Process (EAS_DATA_HANDLE easHandle); + +#endif + diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/wt_22khz.c b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/wt_22khz.c new file mode 100755 index 0000000..6d2c24c --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/lib_src/wt_22khz.c @@ -0,0 +1,14731 @@ +/*---------------------------------------------------------------------------- + * + * Filename: wt_200k_G.c + * Source: wt_200k_G.dls + * CmdLine: -w wt_200k_G.c -l wt_200k_G.log -ce -cf wt_200k_G.dls -w -l -ce -cf wt_200k_G.dls + * Purpose: Wavetable sound libary + * + * Copyright (c) 2009 Sonic Network Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 960 $ + * $Date: 2009-03-18 15:08:29 -0500 (Wed, 18 Mar 2009) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_sndlib.h" + +/*---------------------------------------------------------------------------- + * Articulations + *---------------------------------------------------------------------------- +*/ +const S_ARTICULATION eas_articulations[] = +{ + { /* articulation 0 */ + { 32767, 30725, 0, 30725 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 1 */ + { 32767, 26863, 0, 26863 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 2 */ + { 32767, 30484, 0, 30668 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 3 */ + { 32767, 26439, 0, 26439 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 4 */ + { 32767, 0, 32767, 32715 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 5 */ + { 32767, 21333, 0, 21333 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 6 */ + { 32767, 31882, 0, 31938 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 7 */ + { 32767, 32663, 32767, 32663 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 8 */ + { 32767, 0, 32767, 0 }, + { 32767, 1902, 0, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 9 */ + { 32767, 32349, 0, 32349 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 10 */ + { 32767, 0, 32767, 17213 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -1 + }, + { /* articulation 11 */ + { 32767, 31730, 0, 31730 }, + { 32767, 761, 0, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -44 + }, + { /* articulation 12 */ + { 32767, 23749, 0, 23749 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 56 + }, + { /* articulation 13 */ + { 32767, 31730, 0, 31730 }, + { 32767, 761, 0, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -31 + }, + { /* articulation 14 */ + { 9511, 21333, 0, 21333 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 56 + }, + { /* articulation 15 */ + { 32767, 31617, 0, 31617 }, + { 32767, 761, 0, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -6 + }, + { /* articulation 16 */ + { 32767, 32123, 0, 32194 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 56 + }, + { /* articulation 17 */ + { 32767, 31550, 0, 31550 }, + { 32767, 761, 0, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 6 + }, + { /* articulation 18 */ + { 32767, 31391, 0, 31391 }, + { 32767, 951, 0, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 31 + }, + { /* articulation 19 */ + { 32767, 31964, 0, 31964 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 25 + }, + { /* articulation 20 */ + { 32767, 31056, 0, 31056 }, + { 32767, 951, 0, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 63 + }, + { /* articulation 21 */ + { 32767, 32289, 0, 32271 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -37 + }, + { /* articulation 22 */ + { 19021, 31882, 0, 31911 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -37 + }, + { /* articulation 23 */ + { 32767, 31988, 0, 32032 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -37 + }, + { /* articulation 24 */ + { 32767, 0, 32767, 32663 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 12 + }, + { /* articulation 25 */ + { 32767, 31352, 0, 31352 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -25 + }, + { /* articulation 26 */ + { 32767, 0, 32767, 32663 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 25 + }, + { /* articulation 27 */ + { 32767, 31817, 0, 31781 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -25 + }, + { /* articulation 28 */ + { 32767, 30725, 0, 30725 }, + { 32767, 95, 0, 0 }, + 0, 0, 951, 240, 0, 0, 0, 0, -56 + }, + { /* articulation 29 */ + { 32767, 32230, 0, 32218 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -37 + }, + { /* articulation 30 */ + { 32767, 26439, 0, 26439 }, + { 32767, 3804, 0, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 50 + }, + { /* articulation 31 */ + { 32767, 23749, 0, 23749 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -50 + }, + { /* articulation 32 */ + { 32767, 29434, 0, 29434 }, + { 32767, 3804, 0, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -50 + }, + { /* articulation 33 */ + { 32767, 30240, 0, 30234 }, + { 32767, 3804, 0, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -44 + }, + { /* articulation 34 */ + { 32767, 32558, 0, 32558 }, + { 32767, 254, 0, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 25 + }, + { /* articulation 35 */ + { 32767, 0, 32767, 32663 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -63 + }, + { /* articulation 36 */ + { 3804, 23749, 0, 23749 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -63 + }, + { /* articulation 37 */ + { 32767, 23749, 0, 23749 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -59 + }, + { /* articulation 38 */ + { 32767, 30725, 0, 30725 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 50 + }, + { /* articulation 39 */ + { 32767, 28809, 0, 28809 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 44 + }, + { /* articulation 40 */ + { 1902, 30725, 0, 30725 }, + { 32767, 380, 0, 0 }, + 0, 0, 951, -100, 0, 0, 0, 0, 44 + }, + { /* articulation 41 */ + { 32767, 9042, 0, 9042 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 25 + }, + { /* articulation 42 */ + { 32767, 29889, 0, 29889 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 63 + }, + { /* articulation 43 */ + { 32767, 30240, 0, 30234 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 63 + }, + { /* articulation 44 */ + { 19021, 19970, 0, 19970 }, + { 951, 32767, 32767, 0 }, + 0, 0, 951, 100, 0, 0, 0, 0, -25 + }, + { /* articulation 45 */ + { 3804, 17213, 0, 17213 }, + { 951, 32767, 32767, 0 }, + 0, 0, 951, 500, 0, 0, 0, 0, -25 + }, + { /* articulation 46 */ + { 32767, 17213, 0, 17213 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -56 + }, + { /* articulation 47 */ + { 32767, 30725, 0, 30725 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, -56 + }, + { /* articulation 48 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 49 */ + { 32767, 31180, 0, 31180 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 50 */ + { 19021, 31964, 0, 32071 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 51 */ + { 32767, 29669, 0, 29669 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 52 */ + { 32767, 31742, 0, 31352 }, + { 32767, 294, 0, 0 }, + 0, 0, 951, 0, 10000, 7121, 0, 0, 0 + }, + { /* articulation 53 */ + { 32767, 0, 32767, 31391 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 1555, 0, -2300, 11920, 0, 0, 0 + }, + { /* articulation 54 */ + { 1174, 0, 32767, 31988 }, + { 32767, 127, 0, 0 }, + 0, 0, 1555, 0, 2000, 10721, 0, 8, 15 + }, + { /* articulation 55 */ + { 1174, 0, 32767, 31988 }, + { 951, 127, 0, 0 }, + 0, 0, 1555, 0, 2000, 9023, 0, 5, 15 + }, + { /* articulation 56 */ + { 7608, 0, 32767, 30237 }, + { 32767, 69, 5898, 0 }, + 0, 0, 1555, 0, 6000, 9080, 0, 0, -2 + }, + { /* articulation 57 */ + { 32767, 0, 32767, 29337 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 1555, 0, 0, 0, 0, 0, 1 + }, + { /* articulation 58 */ + { 5141, 0, 32767, 30194 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 1555, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 59 */ + { 32767, 32558, 0, 26439 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 60 */ + { 32767, 32349, 0, 26439 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 61 */ + { 32767, 32072, 0, 32072 }, + { 32767, 95, 0, 0 }, + 0, 34, 989, 0, 2400, 9521, 0, 0, 0 + }, + { /* articulation 62 */ + { 32767, 30234, 0, 30234 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 11738, 0, 16, 0 + }, + { /* articulation 63 */ + { 32767, 32349, 0, 30073 }, + { 32767, 634, 0, 0 }, + 0, 34, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 64 */ + { 32767, 31730, 0, 31476 }, + { 32767, 634, 0, 0 }, + 0, 34, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 65 */ + { 32767, 32418, 0, 25329 }, + { 32767, 95, 0, 0 }, + 0, 34, 989, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 66 */ + { 32767, 32052, 0, 31964 }, + { 32767, 634, 0, 0 }, + 0, 34, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 67 */ + { 32767, 31938, 0, 31938 }, + { 32767, 634, 0, 0 }, + 0, 34, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 68 */ + { 9511, 32663, 18820, 23749 }, + { 1902, 57, 13107, 0 }, + 0, 0, 989, 0, 6000, 5535, 0, 4, 0 + }, + { /* articulation 69 */ + { 32767, 31754, 0, 31730 }, + { 32767, 1902, 0, 0 }, + 0, 52, 989, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 70 */ + { 127, 32686, 3811, 32349 }, + { 95, 38, 32767, 0 }, + 0, 0, 989, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 71 */ + { 4755, 32663, 3566, 28809 }, + { 3804, 32767, 32767, 0 }, + 0, 0, 989, 100, 0, 11919, 0, 0, 0 + }, + { /* articulation 72 */ + { 32767, 31935, 0, 31935 }, + { 32767, 335, 0, 0 }, + 0, 17, 989, 0, 7000, 9023, 0, 0, 0 + }, + { /* articulation 73 */ + { 32767, 31391, 0, 31391 }, + { 32767, 335, 0, 0 }, + 0, 2, 951, 0, 7000, 9023, 0, 0, 0 + }, + { /* articulation 74 */ + { 32767, 32628, 6208, 31935 }, + { 380, 95, 0, 0 }, + 0, 0, 989, 0, 3840, 8302, 0, 8, 0 + }, + { /* articulation 75 */ + { 32767, 32072, 0, 32171 }, + { 32767, 380, 0, 0 }, + 0, 0, 989, 0, 5000, 8321, 0, 0, 0 + }, + { /* articulation 76 */ + { 32767, 31935, 0, 31935 }, + { 32767, 380, 0, 0 }, + 0, 0, 951, 0, 5000, 7934, 0, 0, 0 + }, + { /* articulation 77 */ + { 32767, 32117, 0, 30685 }, + { 32767, 63, 0, 0 }, + 0, 17, 989, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 78 */ + { 32767, 32245, 0, 23749 }, + { 32767, 1902, 0, 0 }, + 0, 172, 989, 0, 1000, 11107, 0, 0, 0 + }, + { /* articulation 79 */ + { 32767, 32663, 6208, 31935 }, + { 95, 95, 0, 0 }, + 0, 34, 1622, 0, 3560, 8834, 1, 8, 0 + }, + { /* articulation 80 */ + { 32767, 32362, 0, 26439 }, + { 32767, 190, 0, 0 }, + 0, 17, 989, 0, 6000, 9907, 0, 0, 0 + }, + { /* articulation 81 */ + { 32767, 32245, 0, 23749 }, + { 32767, 63, 0, 0 }, + 0, 17, 989, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 82 */ + { 32767, 31730, 18820, 9042 }, + { 32767, 32767, 32767, 0 }, + 0, 17, 989, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 83 */ + { 32767, 32715, 128, 32168 }, + { 32767, 127, 0, 0 }, + 0, 0, 989, 0, 0, 11920, 0, 8, 0 + }, + { /* articulation 84 */ + { 32767, 32072, 0, 32072 }, + { 32767, 67, 0, 0 }, + 3, 0, 572, 0, 5000, 5535, 0, 0, 0 + }, + { /* articulation 85 */ + { 3804, 32663, 18820, 23749 }, + { 32767, 2024, 0, 0 }, + 10, 34, 1008, -30, 0, 0, 0, 0, 0 + }, + { /* articulation 86 */ + { 19021, 32663, 18820, 23749 }, + { 761, 95, 0, 0 }, + 0, 34, 989, 0, 4473, 7131, 0, 8, 0 + }, + { /* articulation 87 */ + { 1902, 32628, 6208, 32171 }, + { 634, 38, 16384, 0 }, + 0, 0, 989, 0, 2987, 7877, 0, 12, 0 + }, + { /* articulation 88 */ + { 32767, 32593, 0, 31935 }, + { 32767, 95, 0, 0 }, + 0, 0, 1162, 0, 4053, 7930, 2, 12, 0 + }, + { /* articulation 89 */ + { 380, 32684, 6208, 31935 }, + { 32767, 112, 0, 0 }, + 0, 0, 989, 0, 0, 8887, 0, 0, 0 + }, + { /* articulation 90 */ + { 19021, 32663, 18820, 23749 }, + { 1268, 95, 0, 0 }, + 0, 34, 989, 0, 5113, 7981, 0, 4, 0 + }, + { /* articulation 91 */ + { 1902, 32663, 6208, 30725 }, + { 1902, 127, 0, 0 }, + 0, 34, 989, 0, 3500, 7877, 0, 5, 0 + }, + { /* articulation 92 */ + { 1902, 32663, 6208, 30725 }, + { 1268, 95, 0, 0 }, + 0, 34, 951, 0, 4773, 8355, 0, 5, 0 + }, + { /* articulation 93 */ + { 476, 32663, 10809, 31935 }, + { 32767, 32767, 32767, 0 }, + 0, 34, 989, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 94 */ + { 3804, 32663, 18820, 30234 }, + { 32767, 32767, 32767, 0 }, + 0, 34, 989, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 95 */ + { 7608, 32663, 18820, 17213 }, + { 2536, 261, 0, 0 }, + 0, 34, 989, 0, 1200, 11690, 0, 4, 0 + }, + { /* articulation 96 */ + { 32767, 32468, 15076, 30234 }, + { 32767, 32767, 32767, 0 }, + 0, 36, 2183, 0, 0, 11919, 1, 0, 0 + }, + { /* articulation 97 */ + { 32767, 0, 32767, 32663 }, + { 380, 32767, 32767, 0 }, + 0, 0, 989, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 98 */ + { 32767, 31391, 0, 31391 }, + { 32767, 634, 0, 0 }, + 0, 0, 989, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 99 */ + { 32767, 32558, 0, 23749 }, + { 1268, 190, 13107, 0 }, + 0, 34, 989, 0, 3200, 8321, 0, 0, 0 + }, + { /* articulation 100 */ + { 32767, 0, 32767, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 989, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 101 */ + { 32767, 32072, 0, 23749 }, + { 32767, 1087, 0, 0 }, + 0, 34, 989, 0, 8187, 5535, 0, 5, 0 + }, + { /* articulation 102 */ + { 32767, 32558, 0, 29434 }, + { 32767, 190, 7667, 0 }, + 5, 0, 989, 0, 6053, 5535, 0, 5, 0 + }, + { /* articulation 103 */ + { 32767, 32663, 18820, 23749 }, + { 1902, 95, 0, 0 }, + 0, 0, 989, 0, 2700, 9852, 0, 0, 0 + }, + { /* articulation 104 */ + { 32767, 32663, 18820, 27897 }, + { 1902, 95, 0, 0 }, + 0, 0, 989, 0, 2700, 9852, 0, 0, 0 + }, + { /* articulation 105 */ + { 32767, 32663, 18820, 23749 }, + { 32767, 1268, 0, 0 }, + 0, 52, 951, 0, 2500, 10490, 1, 8, 0 + }, + { /* articulation 106 */ + { 32767, 32663, 23493, 23749 }, + { 32767, 380, 0, 0 }, + 0, 34, 988, 0, 4000, 10223, 1, 4, 0 + }, + { /* articulation 107 */ + { 32767, 32663, 18820, 27897 }, + { 32767, 126, 7667, 0 }, + 0, 0, 989, 0, 1813, 9154, 0, 0, 0 + }, + { /* articulation 108 */ + { 32767, 31730, 0, 31730 }, + { 32767, 380, 0, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 109 */ + { 32767, 31180, 0, 30484 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 11690, 0, 0, 0 + }, + { /* articulation 110 */ + { 32767, 30725, 0, 30725 }, + { 32767, 380, 0, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 111 */ + { 32767, 32349, 18820, 27897 }, + { 32767, 95, 0, 0 }, + 12, 34, 951, 0, 3000, 10223, 0, 0, 0 + }, + { /* articulation 112 */ + { 32767, 32349, 18820, 27897 }, + { 32767, 63, 0, 0 }, + 12, 34, 951, 0, 1900, 10031, 0, 0, 0 + }, + { /* articulation 113 */ + { 32767, 32663, 18820, 26439 }, + { 32767, 63, 0, 0 }, + 12, 34, 988, 0, 1000, 11107, 0, 0, 0 + }, + { /* articulation 114 */ + { 32767, 32663, 18820, 26439 }, + { 32767, 63, 0, 0 }, + 12, 34, 988, 0, 2000, 11107, 0, 0, 0 + }, + { /* articulation 115 */ + { 32767, 32505, 0, 26439 }, + { 32767, 190, 0, 0 }, + 0, 17, 989, 0, 4000, 8321, 0, 0, 0 + }, + { /* articulation 116 */ + { 32767, 31832, 19893, 9042 }, + { 32767, 476, 0, 0 }, + 0, 34, 1452, 0, 0, 11919, 0, 0, 0 + }, + { /* articulation 117 */ + { 19021, 32072, 23493, 9042 }, + { 32767, 32767, 32767, 0 }, + 0, 34, 1355, 0, 0, 11877, 1, 0, 0 + }, + { /* articulation 118 */ + { 32767, 32468, 0, 23749 }, + { 32767, 190, 0, 0 }, + 0, 34, 989, 0, 3500, 9023, 0, 0, 0 + }, + { /* articulation 119 */ + { 32767, 17213, 23493, 0 }, + { 32767, 32767, 32767, 0 }, + 0, 17, 1521, 0, 0, 10925, 1, 0, 0 + }, + { /* articulation 120 */ + { 32767, 32505, 0, 26439 }, + { 32767, 190, 0, 0 }, + 0, 52, 989, 0, 3200, 8721, 0, 4, 0 + }, + { /* articulation 121 */ + { 3804, 32663, 18820, 23749 }, + { 32767, 32767, 32767, 0 }, + 0, 34, 989, 0, 0, 0, 1, 0, 0 + }, + { /* articulation 122 */ + { 9511, 32663, 18820, 25329 }, + { 32767, 32767, 32767, 0 }, + 0, 34, 989, 0, 0, 11877, 0, 8, 0 + }, + { /* articulation 123 */ + { 32767, 32663, 18820, 23749 }, + { 32767, 32, 0, 0 }, + 0, 17, 989, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 124 */ + { 32767, 32558, 0, 23749 }, + { 32767, 380, 0, 0 }, + 0, 34, 989, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 125 */ + { 32767, 32663, 18820, 23749 }, + { 32767, 24, 0, 0 }, + 0, 17, 989, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 126 */ + { 32767, 30725, 0, 30725 }, + { 32767, 761, 0, 0 }, + 0, 0, 989, 0, 3000, 10223, 0, 8, 0 + }, + { /* articulation 127 */ + { 127, 0, 32767, 32349 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 1522, 0, 0, 11423, 4, 0, 0 + }, + { /* articulation 128 */ + { 951, 32422, 0, 32387 }, + { 32767, 19, 0, 0 }, + 0, 0, 989, 0, 0, 11423, 0, 0, 0 + }, + { /* articulation 129 */ + { 391, 0, 0, 31180 }, + { 190, 32767, 32767, 0 }, + 0, 0, 989, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 130 */ + { 32767, 30725, 0, 30725 }, + { 32767, 761, 0, 0 }, + 0, 0, 989, 1200, 0, 0, 0, 0, 0 + }, + { /* articulation 131 */ + { 32767, 31730, 0, 31935 }, + { 32767, 380, 0, 0 }, + 0, 0, 989, 50, 0, 0, 0, 0, 0 + }, + { /* articulation 132 */ + { 32767, 32072, 0, 32072 }, + { 32767, 19021, 0, 0 }, + 0, 0, 989, 0, 4700, 7769, 0, 0, 0 + }, + { /* articulation 133 */ + { 32767, 30073, 0, 30073 }, + { 32767, 32767, 0, 0 }, + 0, 0, 989, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 134 */ + { 32767, 32558, 32767, 32558 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 135 */ + { 32767, 32663, 18820, 17213 }, + { 32767, 190, 0, 0 }, + 10, 34, 951, 0, 2000, 10696, 0, 0, 0 + }, + { /* articulation 136 */ + { 32767, 32663, 10809, 17213 }, + { 32767, 190, 0, 0 }, + 12, 34, 982, 0, 0, 10910, 0, 0, 0 + }, + { /* articulation 137 */ + { 32767, 32663, 18820, 17213 }, + { 32767, 190, 0, 0 }, + 10, 34, 951, 0, 1200, 10218, 0, 0, 0 + }, + { /* articulation 138 */ + { 32767, 32663, 18820, 17213 }, + { 32767, 190, 0, 0 }, + 10, 34, 951, 0, 1100, 9525, 0, 0, 0 + }, + { /* articulation 139 */ + { 19021, 32558, 18820, 23749 }, + { 32767, 19, 0, 0 }, + 10, 34, 988, 0, 2000, 10962, 0, 0, 0 + }, + { /* articulation 140 */ + { 32767, 32349, 18820, 23749 }, + { 19021, 634, 0, 0 }, + 10, 32, 1008, 0, 1200, 10090, 0, 0, 0 + }, + { /* articulation 141 */ + { 2536, 0, 32767, 27897 }, + { 1902, 380, 0, 0 }, + 7, 34, 988, 0, 1620, 8933, 0, 0, 0 + }, + { /* articulation 142 */ + { 32767, 32349, 10809, 23749 }, + { 32767, 380, 0, 0 }, + 7, 34, 988, 0, 2200, 8994, 0, 0, 0 + }, + { /* articulation 143 */ + { 32767, 32663, 15076, 23749 }, + { 32767, 1902, 0, 0 }, + 10, 34, 982, 0, 2500, 9525, 0, 0, 0 + }, + { /* articulation 144 */ + { 32767, 32663, 15076, 23749 }, + { 32767, 190, 0, 0 }, + 10, 34, 951, 0, 1500, 11423, 0, 0, 0 + }, + { /* articulation 145 */ + { 32767, 32663, 18820, 23749 }, + { 32767, 1902, 0, 0 }, + 9, 34, 982, 0, 1500, 9521, 0, 0, 0 + }, + { /* articulation 146 */ + { 3804, 0, 32767, 28809 }, + { 32767, 32767, 32767, 0 }, + 0, 0, 1521, 0, 0, 9521, 0, 0, 0 + }, + { /* articulation 147 */ + { 32767, 32558, 0, 23749 }, + { 32767, 19021, 0, 0 }, + 0, 17, 989, 0, 5000, 10223, 0, 0, 0 + }, + { /* articulation 148 */ + { 32767, 32663, 18820, 23749 }, + { 32767, 63, 0, 0 }, + 10, 34, 951, 0, 1500, 9907, 0, 0, 0 + }, + { /* articulation 149 */ + { 32767, 32698, 11682, 23749 }, + { 32767, 1902, 0, 0 }, + 0, 34, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 150 */ + { 32767, 32072, 0, 32072 }, + { 32767, 380, 0, 0 }, + 0, 17, 989, 0, 3440, 9260, 0, 0, 0 + }, + { /* articulation 151 */ + { 32767, 30234, 0, 30725 }, + { 32767, 1902, 0, 0 }, + 0, 17, 989, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 152 */ + { 32767, 31730, 0, 30725 }, + { 32767, 380, 0, 0 }, + 0, 17, 989, 0, 4000, 7823, 0, 0, 0 + }, + { /* articulation 153 */ + { 32767, 32558, 3566, 23749 }, + { 783, 32767, 32767, 0 }, + 100, 0, 1522, 500, 0, 11877, 0, 0, 0 + }, + { /* articulation 154 */ + { 32767, 32663, 18820, 17213 }, + { 32767, 1902, 0, 0 }, + 8, 34, 989, -22, 0, 0, 0, 0, 0 + }, + { /* articulation 155 */ + { 19021, 29007, 6784, 23749 }, + { 32767, 1902, 0, 0 }, + 0, 34, 951, 0, 5000, 9521, 1, 0, 0 + }, + { /* articulation 156 */ + { 32767, 32558, 0, 31935 }, + { 1902, 254, 16384, 0 }, + 0, 52, 989, 0, 3627, 10547, 0, 5, 0 + }, + { /* articulation 157 */ + { 3804, 0, 32767, 23749 }, + { 1902, 1902, 0, 0 }, + 0, 34, 989, 27, 0, 11919, 0, 0, 0 + }, + { /* articulation 158 */ + { 32767, 0, 32767, 31730 }, + { 76, 66, 10092, 0 }, + 5, 0, 989, 0, 8007, 5535, 0, 8, 0 + }, + { /* articulation 159 */ + { 32767, 32468, 0, 29434 }, + { 32767, 127, 0, 0 }, + 0, 52, 989, 0, 2500, 9032, 0, 0, 0 + }, + { /* articulation 160 */ + { 9511, 32663, 10809, 25329 }, + { 32767, 32767, 32767, 0 }, + 0, 34, 989, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 161 */ + { 19021, 32558, 18820, 23749 }, + { 32767, 190, 0, 0 }, + 10, 34, 988, 0, 2600, 9513, 0, 0, 0 + }, + { /* articulation 162 */ + { 32767, 32106, 9568, 23749 }, + { 2348, 391, 0, 0 }, + 10, 52, 980, 0, 6500, 9023, 0, 0, 0 + }, + { /* articulation 163 */ + { 32767, 32558, 0, 26439 }, + { 32767, 63, 0, 0 }, + 0, 34, 989, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 164 */ + { 32767, 32072, 15076, 17213 }, + { 32767, 1268, 0, 0 }, + 0, 0, 951, 0, 2000, 10223, 0, 0, 0 + }, + { /* articulation 165 */ + { 32767, 32558, 0, 23749 }, + { 32767, 380, 0, 0 }, + 0, 34, 989, 0, 3000, 9366, 0, 0, 0 + }, + { /* articulation 166 */ + { 32767, 32663, 18820, 23749 }, + { 1902, 127, 10879, 0 }, + 0, 0, 989, 0, 6000, 7121, 0, 4, 0 + }, + { /* articulation 167 */ + { 32767, 32505, 0, 26439 }, + { 32767, 21, 0, 0 }, + 0, 52, 989, 0, 3500, 6236, 0, 5, 0 + }, + { /* articulation 168 */ + { 32767, 32505, 0, 26439 }, + { 32767, 190, 0, 0 }, + 0, 52, 989, 0, 2800, 7121, 0, 0, 0 + }, + { /* articulation 169 */ + { 32767, 32418, 0, 29434 }, + { 32767, 127, 0, 0 }, + 0, 52, 989, 0, 2100, 9626, 0, 0, 0 + }, + { /* articulation 170 */ + { 32767, 32349, 0, 30234 }, + { 32767, 127, 0, 0 }, + 0, 52, 989, 0, 3000, 9626, 0, 0, 0 + }, + { /* articulation 171 */ + { 32767, 32288, 0, 28400 }, + { 32767, 127, 0, 0 }, + 0, 52, 989, 0, 1000, 9032, 0, 0, 0 + }, + { /* articulation 172 */ + { 32767, 32072, 0, 28809 }, + { 32767, 127, 0, 0 }, + 0, 52, 989, 0, 1000, 9032, 0, 0, 0 + }, + { /* articulation 173 */ + { 3804, 32072, 15076, 17213 }, + { 32767, 1268, 0, 0 }, + 0, 52, 991, 0, 0, 11107, 0, 8, 0 + }, + { /* articulation 174 */ + { 32767, 32349, 15076, 23749 }, + { 7608, 147, 0, 0 }, + 0, 0, 989, 0, 4500, 9521, 0, 8, 0 + }, + { /* articulation 175 */ + { 32767, 32663, 18820, 23749 }, + { 32767, 95, 0, 0 }, + 0, 0, 989, 0, 2000, 8321, 0, 8, 0 + }, + { /* articulation 176 */ + { 32767, 32715, 128, 29669 }, + { 32767, 1729, 0, 0 }, + 0, 0, 989, 0, 6000, 7823, 0, 8, 0 + }, + { /* articulation 177 */ + { 19021, 32448, 0, 31882 }, + { 32767, 95, 0, 0 }, + 0, 0, 989, 0, 4500, 7121, 0, 8, 0 + }, + { /* articulation 178 */ + { 32767, 32560, 3646, 32107 }, + { 32767, 190, 0, 0 }, + 0, 0, 989, 0, 4000, 8321, 0, 8, 0 + }, + { /* articulation 179 */ + { 32767, 32602, 13644, 26439 }, + { 32767, 63, 0, 0 }, + 12, 34, 988, 0, 2000, 11107, 0, 0, 0 + }, + { /* articulation 180 */ + { 19021, 30484, 0, 23749 }, + { 32767, 1902, 0, 0 }, + 0, 0, 989, 0, 5000, 8321, 1, 0, 0 + }, + { /* articulation 181 */ + { 261, 32466, 0, 31938 }, + { 32767, 634, 0, 0 }, + 0, 34, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 182 */ + { 32767, 32418, 0, 31742 }, + { 2348, 39, 0, 0 }, + 0, 34, 989, 0, 3600, 7121, 0, 4, 0 + }, + { /* articulation 183 */ + { 32767, 32090, 0, 32090 }, + { 32767, 634, 0, 0 }, + 0, 34, 951, 0, 0, 0, 0, 0, 0 + }, + { /* articulation 184 */ + { 1669, 32715, 19242, 30194 }, + { 32767, 296, 0, 0 }, + 0, 0, 1555, 0, 3000, 9907, 0, 4, 0 + } +}; /*end Articulations */ + +/*---------------------------------------------------------------------------- + * Regions + *---------------------------------------------------------------------------- +*/ +const S_WT_REGION eas_regions[] = +{ + { { 0, 27, 27 }, -2868, 16422, 0, 0, 81, 0 }, /* region 0 */ + { { 0, 28, 28 }, -3568, 32767, 0, 0, 40, 0 }, /* region 1 */ + { { 0, 29, 29 }, -4553, 32767, 0, 0, 32, 1 }, /* region 2 */ + { { 0, 30, 30 }, -4853, 32767, 0, 0, 32, 2 }, /* region 3 */ + { { 0, 31, 31 }, -3868, 23197, 0, 0, 48, 3 }, /* region 4 */ + { { 1536, 32, 32 }, -3200, 20675, 0, 0, 137, 4 }, /* region 5 */ + { { 1537, 33, 33 }, -3703, 20675, 792, 879, 50, 5 }, /* region 6 */ + { { 1537, 34, 34 }, -3803, 16422, 792, 879, 50, 6 }, /* region 7 */ + { { 0, 35, 35 }, -4968, 32767, 0, 0, 83, 7 }, /* region 8 */ + { { 0, 36, 36 }, -4968, 32767, 0, 0, 83, 7 }, /* region 9 */ + { { 0, 37, 37 }, -4051, 18426, 0, 0, 53, 8 }, /* region 10 */ + { { 0, 38, 38 }, -4151, 23197, 0, 0, 16, 9 }, /* region 11 */ + { { 0, 39, 39 }, -3568, 32767, 0, 0, 40, 10 }, /* region 12 */ + { { 0, 40, 40 }, -4151, 23197, 0, 0, 16, 4 }, /* region 13 */ + { { 1, 41, 41 }, -5855, 26028, 798, 993, 45, 11 }, /* region 14 */ + { { 257, 42, 42 }, -4200, 26028, 4288, 7488, 7, 12 }, /* region 15 */ + { { 1, 43, 43 }, -5755, 26028, 798, 993, 45, 13 }, /* region 16 */ + { { 257, 44, 44 }, -4400, 26028, 4288, 7488, 7, 14 }, /* region 17 */ + { { 1, 45, 45 }, -5755, 26028, 798, 993, 45, 15 }, /* region 18 */ + { { 257, 46, 46 }, -4600, 26028, 4288, 7488, 7, 16 }, /* region 19 */ + { { 1, 47, 47 }, -5455, 26028, 798, 993, 45, 17 }, /* region 20 */ + { { 1, 48, 48 }, -5355, 26028, 798, 993, 45, 18 }, /* region 21 */ + { { 1, 49, 49 }, -5200, 16422, 1294, 5778, 8, 19 }, /* region 22 */ + { { 1, 50, 50 }, -5255, 26028, 798, 993, 45, 20 }, /* region 23 */ + { { 1, 51, 51 }, -5268, 16422, 6592, 9921, 6, 21 }, /* region 24 */ + { { 1, 52, 52 }, -5600, 32767, 1294, 5778, 8, 22 }, /* region 25 */ + { { 1, 53, 53 }, -5418, 14636, 6592, 9921, 6, 23 }, /* region 26 */ + { { 0, 54, 54 }, -5751, 26028, 0, 0, 39, 24 }, /* region 27 */ + { { 1, 55, 55 }, -5300, 32767, 1294, 5778, 8, 25 }, /* region 28 */ + { { 0, 56, 56 }, -7255, 32767, 0, 0, 90, 26 }, /* region 29 */ + { { 1, 57, 57 }, -5700, 32767, 1294, 5778, 8, 27 }, /* region 30 */ + { { 1, 58, 58 }, -7053, 23197, 0, 166, 113, 28 }, /* region 31 */ + { { 1, 59, 59 }, -5968, 16422, 6592, 9921, 6, 29 }, /* region 32 */ + { { 1, 60, 60 }, -6453, 23197, 432, 582, 63, 30 }, /* region 33 */ + { { 1, 61, 61 }, -6853, 16422, 432, 582, 63, 30 }, /* region 34 */ + { { 1, 62, 62 }, -7253, 20675, 432, 582, 63, 31 }, /* region 35 */ + { { 1, 63, 63 }, -7353, 23197, 432, 582, 63, 32 }, /* region 36 */ + { { 1, 64, 64 }, -7953, 23197, 432, 582, 63, 33 }, /* region 37 */ + { { 0, 65, 65 }, -7555, 32767, 0, 0, 14, 34 }, /* region 38 */ + { { 0, 66, 66 }, -7955, 20675, 0, 0, 14, 34 }, /* region 39 */ + { { 512, 67, 67 }, -7155, 18426, 0, 0, 90, 35 }, /* region 40 */ + { { 512, 68, 68 }, -7755, 18426, 0, 0, 90, 35 }, /* region 41 */ + { { 0, 69, 69 }, -7755, 32767, 0, 0, 86, 36 }, /* region 42 */ + { { 0, 70, 70 }, -6855, 21900, 0, 0, 86, 37 }, /* region 43 */ + { { 769, 71, 71 }, -6355, 23197, 0, 1226, 35, 38 }, /* region 44 */ + { { 769, 72, 72 }, -6955, 26028, 0, 1226, 35, 38 }, /* region 45 */ + { { 1024, 73, 73 }, -7955, 32767, 0, 0, 22, 39 }, /* region 46 */ + { { 1024, 74, 74 }, -8455, 32767, 0, 0, 22, 40 }, /* region 47 */ + { { 1, 75, 75 }, -7900, 23197, 0, 31, 139, 41 }, /* region 48 */ + { { 0, 76, 76 }, -10455, 23197, 0, 0, 134, 42 }, /* region 49 */ + { { 0, 77, 77 }, -10055, 23197, 0, 0, 134, 43 }, /* region 50 */ + { { 0, 78, 78 }, -8853, 16422, 0, 0, 89, 44 }, /* region 51 */ + { { 0, 79, 79 }, -10253, 16422, 0, 0, 89, 45 }, /* region 52 */ + { { 1281, 80, 80 }, -6300, 13045, 209, 230, 103, 46 }, /* region 53 */ + { { 1281, 81, 81 }, -6400, 16422, 209, 230, 103, 47 }, /* region 54 */ + { { 0, 82, 82 }, -8455, 20675, 0, 0, 87, 48 }, /* region 55 */ + { { 0, 83, 83 }, -8900, 32767, 0, 0, 13, 49 }, /* region 56 */ + { { 1, 84, 84 }, -8400, 23197, 0, 10294, 5, 50 }, /* region 57 */ + { { 0, 85, 85 }, -9655, 32767, 0, 0, 135, 4 }, /* region 58 */ + { { 0, 86, 86 }, -9068, 16422, 0, 0, 24, 51 }, /* region 59 */ + { { 32769, 87, 87 }, -9168, 32767, 1335, 1603, 24, 52 }, /* region 60 */ + { { 1, 12, 67 }, -6605, 23197, 437, 16584, 2, 48 }, /* region 61 */ + { { 1, 68, 73 }, -7196, 23197, 452, 16803, 0, 48 }, /* region 62 */ + { { 32769, 74, 108 }, -8467, 23197, 404, 16698, 1, 48 }, /* region 63 */ + { { 1, 12, 78 }, -6605, 16422, 437, 16584, 2, 48 }, /* region 64 */ + { { 1, 79, 91 }, -7196, 16422, 452, 16803, 0, 48 }, /* region 65 */ + { { 32769, 92, 108 }, -8467, 16422, 404, 16698, 1, 48 }, /* region 66 */ + { { 1, 12, 78 }, -6605, 16422, 437, 16584, 2, 48 }, /* region 67 */ + { { 1, 79, 91 }, -7196, 16422, 452, 16803, 0, 48 }, /* region 68 */ + { { 32769, 92, 108 }, -8467, 16422, 404, 16698, 1, 48 }, /* region 69 */ + { { 1, 12, 70 }, -6600, 23197, 437, 16584, 2, 48 }, /* region 70 */ + { { 1, 71, 88 }, -7191, 23197, 452, 16803, 0, 48 }, /* region 71 */ + { { 32769, 89, 108 }, -8462, 23197, 404, 16698, 1, 48 }, /* region 72 */ + { { 1, 12, 54 }, -5956, 13045, 639, 4368, 10, 48 }, /* region 73 */ + { { 32769, 55, 108 }, -6351, 18426, 702, 3112, 12, 48 }, /* region 74 */ + { { 1, 12, 66 }, -6611, 23197, 437, 16584, 2, 48 }, /* region 75 */ + { { 1, 67, 87 }, -7202, 23197, 452, 16803, 0, 48 }, /* region 76 */ + { { 32769, 88, 108 }, -8473, 16422, 404, 16698, 1, 48 }, /* region 77 */ + { { 1, 12, 43 }, -3055, 23197, 920, 1383, 30, 59 }, /* region 78 */ + { { 32769, 44, 96 }, -5060, 18426, 885, 1176, 37, 59 }, /* region 79 */ + { { 1, 12, 48 }, -3461, 18426, 1148, 1514, 26, 60 }, /* region 80 */ + { { 32769, 49, 96 }, -6253, 16422, 1347, 1420, 29, 60 }, /* region 81 */ + { { 1, 33, 56 }, -5600, 26028, 1064, 1170, 38, 61 }, /* region 82 */ + { { 1, 57, 72 }, -6000, 26028, 930, 1014, 44, 61 }, /* region 83 */ + { { 32769, 73, 108 }, -7600, 26028, 726, 826, 52, 61 }, /* region 84 */ + { { 1, 36, 96 }, -7600, 20675, 635, 735, 58, 62 }, /* region 85 */ + { { 32769, 97, 108 }, -10108, 13045, 0, 31, 139, 62 }, /* region 86 */ + { { 1, 36, 96 }, -7600, 14636, 635, 735, 58, 0 }, /* region 87 */ + { { 32769, 97, 108 }, -10108, 13045, 0, 31, 139, 0 }, /* region 88 */ + { { 1, 36, 83 }, -6006, 13045, 838, 922, 47, 63 }, /* region 89 */ + { { 1, 84, 93 }, -8406, 14636, 209, 230, 103, 63 }, /* region 90 */ + { { 32769, 94, 108 }, -10108, 13045, 0, 31, 139, 63 }, /* region 91 */ + { { 1, 36, 83 }, -6006, 13045, 838, 922, 47, 64 }, /* region 92 */ + { { 1, 84, 93 }, -8406, 13045, 209, 230, 103, 64 }, /* region 93 */ + { { 32769, 94, 108 }, -10108, 13045, 0, 31, 139, 64 }, /* region 94 */ + { { 1, 21, 56 }, -5595, 23197, 1064, 1170, 38, 65 }, /* region 95 */ + { { 1, 57, 72 }, -5995, 23197, 930, 1014, 44, 65 }, /* region 96 */ + { { 32769, 73, 108 }, -7598, 23197, 726, 826, 52, 65 }, /* region 97 */ + { { 1, 12, 83 }, -6006, 16422, 838, 922, 47, 66 }, /* region 98 */ + { { 1, 84, 93 }, -8406, 16422, 209, 230, 103, 66 }, /* region 99 */ + { { 32769, 94, 108 }, -10108, 16422, 0, 31, 139, 66 }, /* region 100 */ + { { 1, 24, 83 }, -6006, 16422, 838, 922, 47, 67 }, /* region 101 */ + { { 1, 84, 93 }, -8406, 16422, 209, 230, 103, 67 }, /* region 102 */ + { { 32769, 94, 108 }, -10108, 16422, 0, 31, 139, 67 }, /* region 103 */ + { { 1, 12, 83 }, -6020, 16422, 0, 83, 126, 68 }, /* region 104 */ + { { 1, 84, 90 }, -8482, 16422, 0, 20, 145, 68 }, /* region 105 */ + { { 32769, 91, 108 }, -9101, 16422, 6, 20, 147, 68 }, /* region 106 */ + { { 1, 21, 75 }, -7241, 16422, 419, 460, 76, 69 }, /* region 107 */ + { { 32769, 76, 108 }, -9690, 14636, 254, 264, 101, 69 }, /* region 108 */ + { { 32769, 36, 84 }, -7755, 16422, 0, 2775, 17, 70 }, /* region 109 */ + { { 32769, 12, 108 }, -6655, 23197, 30, 276, 100, 71 }, /* region 110 */ + { { 0, 12, 60 }, -7914, 26028, 0, 0, 15, 72 }, /* region 111 */ + { { 32768, 61, 96 }, -7914, 26028, 0, 0, 15, 73 }, /* region 112 */ + { { 1, 12, 65 }, -7053, 16422, 23, 10953, 4, 74 }, /* region 113 */ + { { 32769, 66, 108 }, -7755, 20675, 11, 11753, 3, 74 }, /* region 114 */ + { { 1, 12, 35 }, -5355, 16422, 2869, 3778, 11, 75 }, /* region 115 */ + { { 1, 36, 48 }, -6555, 20675, 2869, 3778, 11, 75 }, /* region 116 */ + { { 32769, 49, 72 }, -6555, 20675, 2869, 3778, 11, 76 }, /* region 117 */ + { { 1, 16, 55 }, -6224, 20675, 1045, 1119, 41, 77 }, /* region 118 */ + { { 32769, 56, 96 }, -6718, 20675, 907, 963, 46, 77 }, /* region 119 */ + { { 1, 16, 53 }, -5994, 29204, 1140, 1479, 27, 78 }, /* region 120 */ + { { 1, 54, 70 }, -7171, 29204, 726, 812, 55, 78 }, /* region 121 */ + { { 32769, 71, 108 }, -7788, 29204, 718, 748, 56, 78 }, /* region 122 */ + { { 1, 12, 65 }, -7053, 16422, 23, 10953, 4, 79 }, /* region 123 */ + { { 32769, 66, 108 }, -7755, 20675, 11, 11753, 3, 79 }, /* region 124 */ + { { 1, 16, 54 }, -5727, 20675, 5362, 5461, 9, 80 }, /* region 125 */ + { { 1, 55, 63 }, -5851, 26028, 1362, 1454, 28, 80 }, /* region 126 */ + { { 32769, 64, 108 }, -6744, 16422, 311, 366, 88, 80 }, /* region 127 */ + { { 1, 16, 48 }, -4798, 20675, 1132, 1301, 31, 81 }, /* region 128 */ + { { 32769, 49, 108 }, -5988, 20675, 1099, 1184, 36, 81 }, /* region 129 */ + { { 1, 21, 68 }, -8458, 20675, 87, 2170, 18, 82 }, /* region 130 */ + { { 1, 69, 82 }, -8960, 20675, 120, 2167, 19, 82 }, /* region 131 */ + { { 32769, 83, 108 }, -10160, 20675, 376, 2041, 20, 82 }, /* region 132 */ + { { 1, 12, 65 }, -7053, 16422, 23, 10953, 4, 83 }, /* region 133 */ + { { 32769, 66, 108 }, -7755, 20675, 11, 11753, 3, 83 }, /* region 134 */ + { { 32769, 55, 108 }, -7368, 20675, 0, 477, 75, 84 }, /* region 135 */ + { { 32769, 36, 96 }, -6900, 14636, 101, 151, 116, 85 }, /* region 136 */ + { { 1, 24, 83 }, -6020, 13045, 0, 83, 126, 86 }, /* region 137 */ + { { 1, 84, 90 }, -8482, 13045, 0, 20, 145, 86 }, /* region 138 */ + { { 32769, 91, 108 }, -9101, 13045, 6, 20, 147, 86 }, /* region 139 */ + { { 1, 12, 65 }, -7053, 16422, 23, 10953, 4, 87 }, /* region 140 */ + { { 32769, 66, 108 }, -7755, 20675, 11, 11753, 3, 87 }, /* region 141 */ + { { 1, 12, 65 }, -7053, 16422, 23, 10953, 4, 88 }, /* region 142 */ + { { 32769, 66, 108 }, -7755, 20675, 11, 11753, 3, 88 }, /* region 143 */ + { { 1, 12, 65 }, -7053, 16422, 23, 10953, 4, 89 }, /* region 144 */ + { { 32769, 66, 108 }, -7755, 20675, 11, 11753, 3, 89 }, /* region 145 */ + { { 1, 24, 83 }, -6020, 13045, 0, 83, 126, 90 }, /* region 146 */ + { { 1, 84, 90 }, -8482, 13045, 0, 20, 145, 90 }, /* region 147 */ + { { 32769, 91, 108 }, -9101, 13045, 6, 20, 147, 90 }, /* region 148 */ + { { 1, 12, 65 }, -7053, 16422, 23, 10953, 4, 91 }, /* region 149 */ + { { 32769, 66, 108 }, -7755, 20675, 11, 11753, 3, 91 }, /* region 150 */ + { { 1, 12, 65 }, -7053, 16422, 23, 10953, 4, 92 }, /* region 151 */ + { { 32769, 66, 108 }, -7755, 20675, 11, 11753, 3, 92 }, /* region 152 */ + { { 1, 12, 62 }, -7053, 16422, 23, 10953, 4, 93 }, /* region 153 */ + { { 32769, 63, 108 }, -7755, 20675, 11, 11753, 3, 93 }, /* region 154 */ + { { 1, 12, 62 }, -7053, 16422, 23, 10953, 4, 94 }, /* region 155 */ + { { 32769, 63, 108 }, -7755, 16422, 11, 11753, 3, 94 }, /* region 156 */ + { { 1, 24, 79 }, -6020, 13045, 0, 83, 126, 95 }, /* region 157 */ + { { 1, 80, 90 }, -8482, 13045, 0, 20, 145, 95 }, /* region 158 */ + { { 32769, 91, 108 }, -9101, 13045, 6, 20, 147, 95 }, /* region 159 */ + { { 1, 12, 65 }, -7053, 13045, 23, 10953, 4, 96 }, /* region 160 */ + { { 32769, 66, 108 }, -7755, 16422, 11, 11753, 3, 96 }, /* region 161 */ + { { 32768, 36, 84 }, -7500, 20675, 0, 0, 25, 97 }, /* region 162 */ + { { 32769, 36, 96 }, -8855, 20675, 1482, 1613, 23, 98 }, /* region 163 */ + { { 32769, 12, 96 }, -4366, 32767, 818, 1033, 42, 99 }, /* region 164 */ + { { 32769, 36, 84 }, -8568, 18426, 0, 293, 98, 100 }, /* region 165 */ + { { 32769, 12, 96 }, -6020, 26028, 0, 83, 125, 101 }, /* region 166 */ + { { 32769, 12, 96 }, -6020, 20675, 0, 83, 125, 102 }, /* region 167 */ + { { 1, 12, 83 }, -6020, 13045, 0, 83, 125, 104 }, /* region 168 */ + { { 1, 84, 90 }, -8482, 13045, 0, 20, 146, 104 }, /* region 169 */ + { { 32769, 91, 108 }, -9101, 13045, 6, 20, 148, 104 }, /* region 170 */ + { { 32769, 36, 108 }, -8570, 32767, 472, 491, 74, 105 }, /* region 171 */ + { { 32769, 36, 108 }, -8570, 20675, 472, 491, 74, 106 }, /* region 172 */ + { { 1, 12, 72 }, -6012, 7336, 2, 86, 124, 107 }, /* region 173 */ + { { 1, 73, 101 }, -8500, 8231, 2, 22, 143, 107 }, /* region 174 */ + { { 32769, 102, 108 }, -9683, 20675, 173, 183, 110, 107 }, /* region 175 */ + { { 1, 21, 96 }, -7768, 13045, 477, 507, 73, 108 }, /* region 176 */ + { { 32769, 97, 108 }, -9683, 13045, 173, 183, 110, 109 }, /* region 177 */ + { { 32769, 12, 108 }, -7771, 16422, 477, 507, 73, 110 }, /* region 178 */ + { { 1, 12, 53 }, -4971, 16422, 388, 541, 68, 111 }, /* region 179 */ + { { 32769, 54, 60 }, -5949, 11626, 473, 560, 65, 111 }, /* region 180 */ + { { 32769, 36, 72 }, -5949, 16422, 473, 560, 65, 112 }, /* region 181 */ + { { 1, 48, 58 }, -7053, 16422, 356, 402, 82, 113 }, /* region 182 */ + { { 1, 59, 65 }, -7574, 16422, 514, 548, 67, 113 }, /* region 183 */ + { { 1, 66, 78 }, -8174, 16422, 505, 529, 71, 113 }, /* region 184 */ + { { 32769, 79, 96 }, -9233, 16422, 178, 191, 109, 113 }, /* region 185 */ + { { 1, 55, 60 }, -7053, 16422, 356, 402, 82, 114 }, /* region 186 */ + { { 1, 61, 69 }, -7574, 16422, 514, 548, 67, 114 }, /* region 187 */ + { { 1, 70, 79 }, -8174, 16422, 505, 529, 71, 114 }, /* region 188 */ + { { 32769, 80, 108 }, -9233, 16422, 178, 191, 109, 114 }, /* region 189 */ + { { 1, 16, 82 }, -8029, 23197, 180, 206, 106, 115 }, /* region 190 */ + { { 32769, 83, 108 }, -7240, 18426, 3, 44, 131, 115 }, /* region 191 */ + { { 32769, 21, 108 }, -8869, 20675, 483, 515, 72, 116 }, /* region 192 */ + { { 1, 21, 89 }, -7205, 18426, 3, 45, 130, 117 }, /* region 193 */ + { { 32769, 90, 108 }, -9101, 10362, 6, 20, 148, 117 }, /* region 194 */ + { { 1, 21, 42 }, -4686, 20675, 0, 180, 111, 118 }, /* region 195 */ + { { 1, 43, 51 }, -5286, 23197, 0, 127, 120, 118 }, /* region 196 */ + { { 1, 52, 58 }, -6292, 26028, 0, 71, 127, 118 }, /* region 197 */ + { { 1, 59, 68 }, -7468, 23197, 0, 36, 136, 118 }, /* region 198 */ + { { 32769, 69, 108 }, -8574, 20675, 0, 19, 149, 118 }, /* region 199 */ + { { 1, 21, 89 }, -7199, 20675, 3, 45, 130, 119 }, /* region 200 */ + { { 32769, 90, 108 }, -9101, 14636, 6, 20, 148, 119 }, /* region 201 */ + { { 1, 21, 46 }, -5651, 26028, 236, 340, 92, 120 }, /* region 202 */ + { { 1, 47, 71 }, -6563, 20675, 824, 885, 49, 120 }, /* region 203 */ + { { 1, 72, 88 }, -7907, 18426, 719, 747, 57, 120 }, /* region 204 */ + { { 1, 89, 93 }, -8876, 16422, 83, 99, 122, 120 }, /* region 205 */ + { { 32769, 94, 108 }, -9689, 16422, 173, 183, 110, 120 }, /* region 206 */ + { { 1, 60, 71 }, -7205, 16422, 0, 42, 132, 121 }, /* region 207 */ + { { 1, 72, 78 }, -7903, 16422, 0, 28, 141, 121 }, /* region 208 */ + { { 32769, 79, 96 }, -8405, 16422, 0, 21, 144, 121 }, /* region 209 */ + { { 1, 48, 65 }, -6316, 11626, 0, 70, 128, 122 }, /* region 210 */ + { { 1, 66, 79 }, -7724, 14636, 0, 31, 138, 122 }, /* region 211 */ + { { 32769, 80, 96 }, -8030, 11626, 0, 26, 142, 122 }, /* region 212 */ + { { 1, 16, 44 }, -5868, 14636, 163, 254, 102, 123 }, /* region 213 */ + { { 1, 45, 51 }, -6418, 16422, 261, 393, 85, 123 }, /* region 214 */ + { { 1, 52, 58 }, -7333, 18426, 190, 229, 104, 123 }, /* region 215 */ + { { 1, 59, 66 }, -8100, 18426, 168, 193, 108, 123 }, /* region 216 */ + { { 1, 67, 70 }, -8576, 18426, 138, 157, 115, 123 }, /* region 217 */ + { { 1, 71, 80 }, -9103, 18426, 166, 180, 112, 123 }, /* region 218 */ + { { 32769, 81, 108 }, -10074, 18426, 135, 151, 117, 123 }, /* region 219 */ + { { 32769, 12, 96 }, -5004, 23197, 570, 719, 59, 124 }, /* region 220 */ + { { 1, 12, 48 }, -5868, 14636, 163, 254, 102, 125 }, /* region 221 */ + { { 1, 49, 54 }, -6418, 16422, 261, 393, 85, 125 }, /* region 222 */ + { { 1, 55, 63 }, -7333, 18426, 190, 229, 104, 125 }, /* region 223 */ + { { 1, 64, 70 }, -8100, 18426, 168, 193, 108, 125 }, /* region 224 */ + { { 1, 71, 75 }, -8576, 18426, 138, 157, 115, 125 }, /* region 225 */ + { { 1, 76, 82 }, -9103, 18426, 166, 180, 112, 125 }, /* region 226 */ + { { 32769, 83, 108 }, -10074, 18426, 135, 151, 117, 125 }, /* region 227 */ + { { 32770, 36, 84 }, -7200, 29204, 0, 0, 0, 126 }, /* region 228 */ + { { 32770, 36, 84 }, -7600, 8231, 0, 0, 0, 127 }, /* region 229 */ + { { 32770, 36, 84 }, -7200, 20675, 0, 0, 0, 128 }, /* region 230 */ + { { 32769, 36, 84 }, -6000, -24285, 1294, 5778, 8, 129 }, /* region 231 */ + { { 32769, 36, 84 }, -6555, 29204, 798, 993, 45, 130 }, /* region 232 */ + { { 32769, 36, 84 }, -6855, 20675, 798, 993, 45, 131 }, /* region 233 */ + { { 32769, 36, 84 }, -7755, 29204, 798, 993, 45, 132 }, /* region 234 */ + { { 32768, 36, 84 }, -8155, 32767, 0, 0, 133, 133 }, /* region 235 */ + { { 32768, 36, 84 }, -6555, 20675, 0, 0, 91, 134 }, /* region 236 */ + { { 1, 24, 62 }, -7000, 23197, 286, 333, 94, 135 }, /* region 237 */ + { { 1, 63, 66 }, -7364, 26028, 297, 335, 93, 135 }, /* region 238 */ + { { 1, 67, 72 }, -7722, 23197, 368, 399, 84, 135 }, /* region 239 */ + { { 32769, 73, 96 }, -8310, 23197, 116, 138, 119, 135 }, /* region 240 */ + { { 1, 24, 48 }, -5141, 23197, 309, 447, 77, 136 }, /* region 241 */ + { { 1, 49, 56 }, -6266, 26028, 211, 283, 99, 136 }, /* region 242 */ + { { 1, 57, 63 }, -7000, 26028, 286, 333, 94, 136 }, /* region 243 */ + { { 32769, 64, 84 }, -7722, 23197, 368, 399, 84, 136 }, /* region 244 */ + { { 1, 24, 56 }, -6266, 29204, 211, 283, 99, 137 }, /* region 245 */ + { { 1, 57, 63 }, -7000, 29204, 286, 333, 94, 137 }, /* region 246 */ + { { 1, 64, 69 }, -7722, 29204, 368, 399, 84, 137 }, /* region 247 */ + { { 32769, 70, 96 }, -8310, 29204, 116, 138, 119, 137 }, /* region 248 */ + { { 1, 24, 68 }, -7722, 18426, 368, 399, 84, 138 }, /* region 249 */ + { { 1, 69, 76 }, -8310, 26028, 116, 138, 119, 138 }, /* region 250 */ + { { 32769, 77, 108 }, -8758, 23197, 127, 144, 118, 138 }, /* region 251 */ + { { 1, 24, 82 }, -7613, 23197, 389, 422, 80, 139 }, /* region 252 */ + { { 32769, 83, 108 }, -8764, 26028, 146, 163, 114, 139 }, /* region 253 */ + { { 1, 12, 58 }, -6898, 29204, 386, 436, 78, 140 }, /* region 254 */ + { { 32769, 59, 96 }, -7371, 26028, 290, 328, 95, 140 }, /* region 255 */ + { { 1, 12, 58 }, -6898, 16422, 386, 436, 78, 141 }, /* region 256 */ + { { 32769, 59, 96 }, -7371, 18426, 290, 328, 95, 141 }, /* region 257 */ + { { 1, 12, 48 }, -6898, -28771, 386, 436, 78, 142 }, /* region 258 */ + { { 32769, 49, 84 }, -7371, 29204, 290, 328, 95, 142 }, /* region 259 */ + { { 1, 12, 60 }, -5453, 20675, 314, 430, 79, 143 }, /* region 260 */ + { { 32769, 61, 84 }, -6553, 18426, 263, 324, 96, 143 }, /* region 261 */ + { { 1, 24, 60 }, -6553, 16422, 263, 324, 96, 144 }, /* region 262 */ + { { 1, 61, 70 }, -7669, 20675, 279, 311, 97, 144 }, /* region 263 */ + { { 32769, 71, 96 }, -8098, 23197, 179, 204, 107, 144 }, /* region 264 */ + { { 1, 24, 84 }, -8483, 20675, 191, 211, 105, 145 }, /* region 265 */ + { { 32769, 85, 108 }, -9683, 20675, 92, 102, 121, 145 }, /* region 266 */ + { { 1, 21, 69 }, -6553, 13045, 263, 324, 96, 146 }, /* region 267 */ + { { 1, 70, 94 }, -7669, 20675, 279, 311, 97, 146 }, /* region 268 */ + { { 1, 95, 96 }, -8098, -24285, 179, 204, 107, 146 }, /* region 269 */ + { { 32769, 97, 108 }, -9683, -24285, 173, 183, 110, 146 }, /* region 270 */ + { { 1, 16, 55 }, -8100, 20675, 168, 193, 108, 147 }, /* region 271 */ + { { 1, 56, 74 }, -8576, 26028, 138, 157, 115, 147 }, /* region 272 */ + { { 32769, 75, 96 }, -10074, 26028, 135, 151, 117, 147 }, /* region 273 */ + { { 1, 24, 72 }, -8098, 26028, 179, 204, 107, 148 }, /* region 274 */ + { { 1, 73, 85 }, -8483, 20675, 191, 211, 105, 148 }, /* region 275 */ + { { 32769, 86, 108 }, -9683, 18426, 92, 102, 121, 148 }, /* region 276 */ + { { 32769, 36, 108 }, -7730, 18426, 1839, 1901, 21, 149 }, /* region 277 */ + { { 32769, 24, 108 }, -7273, 20675, 494, 534, 69, 150 }, /* region 278 */ + { { 32769, 12, 108 }, -7273, 20675, 494, 534, 69, 151 }, /* region 279 */ + { { 32769, 24, 108 }, -7273, 20675, 494, 534, 69, 152 }, /* region 280 */ + { { 1, 36, 60 }, -4900, 5193, 2, 22, 143, 153 }, /* region 281 */ + { { 32769, 61, 84 }, -6083, 20675, 173, 183, 110, 153 }, /* region 282 */ + { { 32769, 24, 96 }, -6553, 14636, 263, 324, 96, 154 }, /* region 283 */ + { { 32769, 36, 96 }, -7730, 26028, 1839, 1901, 21, 155 }, /* region 284 */ + { { 32769, 24, 108 }, -7273, 20675, 494, 534, 69, 156 }, /* region 285 */ + { { 1, 24, 58 }, -7851, 14636, 0, 29, 140, 157 }, /* region 286 */ + { { 32769, 59, 96 }, -7851, 14636, 0, 29, 140, 157 }, /* region 287 */ + { { 1, 12, 83 }, -6020, 13045, 0, 83, 125, 158 }, /* region 288 */ + { { 1, 84, 90 }, -8482, 13045, 0, 20, 146, 158 }, /* region 289 */ + { { 32769, 91, 108 }, -9101, 13045, 6, 20, 148, 158 }, /* region 290 */ + { { 1, 21, 42 }, -4663, 26028, 1047, 1229, 34, 159 }, /* region 291 */ + { { 1, 43, 48 }, -5456, 29204, 1138, 1253, 33, 159 }, /* region 292 */ + { { 1, 49, 53 }, -5845, 26028, 559, 651, 60, 159 }, /* region 293 */ + { { 1, 54, 60 }, -6732, 26028, 508, 563, 64, 159 }, /* region 294 */ + { { 1, 61, 65 }, -7080, 32767, 819, 864, 51, 159 }, /* region 295 */ + { { 1, 66, 70 }, -6866, 26942, 981, 1032, 43, 159 }, /* region 296 */ + { { 1, 71, 76 }, -8166, 26028, 790, 814, 54, 159 }, /* region 297 */ + { { 1, 77, 82 }, -8766, 26028, 592, 609, 61, 159 }, /* region 298 */ + { { 1, 83, 87 }, -9517, 23197, 543, 554, 66, 159 }, /* region 299 */ + { { 1, 88, 96 }, -10071, 18426, 601, 609, 62, 159 }, /* region 300 */ + { { 32769, 97, 108 }, -10566, 18426, 523, 529, 70, 159 }, /* region 301 */ + { { 1, 48, 69 }, -6313, 14636, 0, 70, 128, 160 }, /* region 302 */ + { { 1, 70, 79 }, -7724, 18426, 0, 31, 138, 160 }, /* region 303 */ + { { 32769, 80, 96 }, -8030, 14636, 0, 26, 142, 160 }, /* region 304 */ + { { 1, 36, 72 }, -7134, 29204, 0, 87, 123, 161 }, /* region 305 */ + { { 32769, 73, 96 }, -7960, 29204, 0, 54, 129, 161 }, /* region 306 */ + { { 32769, 36, 96 }, -7730, 26028, 1839, 1901, 21, 162 }, /* region 307 */ + { { 32769, 12, 96 }, -4372, 32767, 818, 1033, 42, 163 }, /* region 308 */ + { { 32769, 36, 108 }, -8570, 26028, 472, 491, 74, 164 }, /* region 309 */ + { { 32769, 12, 96 }, -5004, 29204, 570, 719, 59, 165 }, /* region 310 */ + { { 1, 12, 83 }, -6020, 13045, 0, 83, 125, 166 }, /* region 311 */ + { { 1, 84, 90 }, -8482, 13045, 0, 20, 146, 166 }, /* region 312 */ + { { 32769, 91, 108 }, -9101, 13045, 6, 20, 148, 166 }, /* region 313 */ + { { 1, 21, 46 }, -5651, 32767, 236, 340, 92, 167 }, /* region 314 */ + { { 1, 47, 75 }, -6563, 26028, 824, 885, 49, 167 }, /* region 315 */ + { { 1, 76, 84 }, -7907, 23197, 719, 747, 57, 167 }, /* region 316 */ + { { 1, 85, 93 }, -8876, 20675, 83, 99, 122, 167 }, /* region 317 */ + { { 32769, 94, 108 }, -9689, 20675, 173, 183, 110, 167 }, /* region 318 */ + { { 1, 21, 46 }, -5651, 26028, 236, 340, 92, 168 }, /* region 319 */ + { { 1, 47, 71 }, -6563, 20675, 824, 885, 49, 168 }, /* region 320 */ + { { 1, 72, 88 }, -7907, 18426, 719, 747, 57, 168 }, /* region 321 */ + { { 1, 89, 93 }, -8876, 16422, 83, 99, 122, 168 }, /* region 322 */ + { { 32769, 94, 108 }, -9689, 16422, 173, 183, 110, 168 }, /* region 323 */ + { { 1, 21, 45 }, -4663, 26028, 1047, 1229, 34, 169 }, /* region 324 */ + { { 1, 46, 51 }, -5456, 29204, 1138, 1253, 33, 169 }, /* region 325 */ + { { 1, 52, 54 }, -5845, 26028, 559, 651, 60, 169 }, /* region 326 */ + { { 1, 55, 63 }, -6732, 26028, 508, 563, 64, 169 }, /* region 327 */ + { { 1, 64, 68 }, -7080, 32767, 819, 864, 51, 169 }, /* region 328 */ + { { 1, 69, 73 }, -6866, 26942, 981, 1032, 43, 169 }, /* region 329 */ + { { 1, 74, 79 }, -8166, 26028, 790, 814, 54, 169 }, /* region 330 */ + { { 1, 80, 88 }, -8766, 23197, 592, 609, 61, 169 }, /* region 331 */ + { { 1, 89, 99 }, -10071, 18426, 601, 609, 62, 169 }, /* region 332 */ + { { 32769, 100, 108 }, -10566, 18426, 523, 529, 70, 169 }, /* region 333 */ + { { 1, 21, 45 }, -4663, 26028, 1047, 1229, 34, 170 }, /* region 334 */ + { { 1, 46, 51 }, -5456, 29204, 1138, 1253, 33, 170 }, /* region 335 */ + { { 1, 52, 54 }, -5845, 26028, 559, 651, 60, 170 }, /* region 336 */ + { { 1, 55, 63 }, -6732, 26028, 508, 563, 64, 170 }, /* region 337 */ + { { 1, 64, 68 }, -7080, 32767, 819, 864, 51, 170 }, /* region 338 */ + { { 1, 69, 73 }, -6866, 26942, 981, 1032, 43, 170 }, /* region 339 */ + { { 1, 74, 79 }, -8166, 26028, 790, 814, 54, 170 }, /* region 340 */ + { { 1, 80, 88 }, -8766, 23197, 592, 609, 61, 170 }, /* region 341 */ + { { 1, 89, 99 }, -10071, 18426, 601, 609, 62, 171 }, /* region 342 */ + { { 32769, 100, 108 }, -10566, 18426, 523, 529, 70, 172 }, /* region 343 */ + { { 32769, 36, 108 }, -8570, 20675, 472, 491, 74, 173 }, /* region 344 */ + { { 32769, 12, 108 }, -7730, 20675, 1839, 1901, 21, 174 }, /* region 345 */ + { { 1, 12, 44 }, -5868, 18426, 163, 254, 102, 175 }, /* region 346 */ + { { 1, 45, 51 }, -6418, 20675, 261, 393, 85, 175 }, /* region 347 */ + { { 1, 52, 58 }, -7333, 23197, 190, 229, 104, 175 }, /* region 348 */ + { { 1, 59, 66 }, -8100, 23197, 168, 193, 108, 175 }, /* region 349 */ + { { 1, 67, 70 }, -8576, 23197, 138, 157, 115, 175 }, /* region 350 */ + { { 1, 71, 80 }, -9103, 23197, 166, 180, 112, 175 }, /* region 351 */ + { { 32769, 81, 108 }, -10074, 23197, 135, 151, 117, 175 }, /* region 352 */ + { { 1, 12, 65 }, -7053, 16422, 23, 10953, 4, 176 }, /* region 353 */ + { { 32769, 66, 108 }, -7755, 20675, 11, 11753, 3, 176 }, /* region 354 */ + { { 1, 12, 48 }, -4798, 29204, 1132, 1301, 31, 177 }, /* region 355 */ + { { 32769, 49, 108 }, -5988, 29204, 1099, 1184, 36, 177 }, /* region 356 */ + { { 1, 12, 83 }, -7241, 20675, 419, 460, 76, 178 }, /* region 357 */ + { { 32769, 84, 108 }, -10123, 20675, 0, 31, 139, 178 }, /* region 358 */ + { { 1, 55, 60 }, -7053, 18426, 356, 402, 82, 179 }, /* region 359 */ + { { 1, 61, 69 }, -7574, 18426, 514, 548, 67, 179 }, /* region 360 */ + { { 1, 70, 79 }, -8174, 18426, 505, 529, 71, 179 }, /* region 361 */ + { { 32769, 80, 108 }, -9233, 23197, 178, 191, 109, 179 }, /* region 362 */ + { { 32769, 36, 96 }, -7730, -24285, 1839, 1901, 21, 180 }, /* region 363 */ + { { 1, 12, 83 }, -6006, 16422, 838, 922, 47, 181 }, /* region 364 */ + { { 1, 84, 93 }, -8406, 18426, 209, 230, 103, 181 }, /* region 365 */ + { { 32769, 94, 108 }, -10108, 16422, 0, 31, 139, 181 }, /* region 366 */ + { { 1, 12, 56 }, -5595, 23197, 1064, 1170, 38, 182 }, /* region 367 */ + { { 1, 57, 72 }, -5995, 23197, 930, 1014, 44, 182 }, /* region 368 */ + { { 32769, 73, 108 }, -7598, 23197, 726, 826, 52, 182 }, /* region 369 */ + { { 32769, 24, 108 }, -7600, 23197, 635, 735, 58, 62 }, /* region 370 */ + { { 1, 36, 83 }, -6006, 13045, 838, 922, 47, 183 }, /* region 371 */ + { { 1, 84, 93 }, -8406, 13045, 209, 230, 103, 183 }, /* region 372 */ + { { 32769, 94, 108 }, -10108, 13045, 0, 31, 139, 183 }, /* region 373 */ + { { 1, 12, 66 }, -6611, 23197, 437, 16584, 2, 184 }, /* region 374 */ + { { 1, 67, 87 }, -7202, 23197, 452, 16803, 0, 184 }, /* region 375 */ + { { 32769, 88, 108 }, -8473, 16422, 404, 16698, 1, 184 } /* region 376 */ +}; /* end Regions */ + +/*---------------------------------------------------------------------------- + * Programs + *---------------------------------------------------------------------------- +*/ +const S_PROGRAM eas_programs[] = +{ + { 7864320, 0 } /* program 0 */ +}; /* end Programs */ + +/*---------------------------------------------------------------------------- + * Banks + *---------------------------------------------------------------------------- +*/ +const S_BANK eas_banks[] = +{ + { /* bank 0 */ + 30976, + { + 291, 324, 314, 334, 202, 319, 95, 195, + 107, 92, 371, 89, 87, 85, 135, 82, + 200, 192, 130, 267, 193, 302, 207, 210, + 128, 125, 190, 120, 118, 213, 221, 271, + 80, 78, 308, 164, 220, 310, 166, 167, + 186, 182, 181, 179, 160, 178, 176, 115, + 155, 153, 151, 149, 75, 73, 374, 111, + 252, 254, 258, 305, 256, 157, 146, 137, + 249, 237, 245, 241, 274, 262, 260, 265, + 172, 171, 309, 277, 284, 307, 136, 344, + 173, 168, 345, 353, 346, 70, 110, 311, + 357, 144, 104, 67, 364, 367, 64, 288, + 142, 140, 98, 355, 133, 123, 61, 113, + 285, 280, 279, 278, 370, 286, 359, 283, + 101, 236, 163, 235, 234, 233, 232, 231, + 162, 363, 230, 281, 165, 229, 109, 228 + } + } +}; /* end Banks */ + +/*---------------------------------------------------------------------------- + * Samples + *---------------------------------------------------------------------------- +*/ + +const EAS_SAMPLE eas_samples[] = +{ + 0, 0, -3, -4, -6, -8, -10, -12, -12, -11, -8, -3, 3, 7, 10, 14, + 16, 16, 15, 12, 9, 4, -4, -12, -18, -21, -21, -19, -18, -15, -10, -3, + 10, 20, 34, 44, 51, 52, 48, 43, 38, 26, 8, -15, -37, -52, -61, -64, + -66, -64, -59, -47, -31, -13, 4, 18, 30, 37, 40, 36, 30, 24, 19, 11, + -2, -17, -24, -28, -28, -21, -18, -16, -10, -3, 12, 27, 39, 49, 53, 53, + 50, 43, 37, 25, 11, -11, -31, -46, -57, -63, -66, -63, -57, -46, -34, -19, + -3, 13, 27, 35, 39, 37, 32, 26, 20, 11, 0, -13, -20, -24, -25, -21, + -19, -14, -8, -2, 9, 23, 37, 47, 53, 52, 49, 42, 35, 25, 13, -6, + -28, -48, -60, -67, -67, -64, -60, -51, -39, -23, -7, 10, 23, 35, 39, 38, + 32, 26, 21, 15, 4, -9, -20, -22, -21, -19, -14, -11, -5, 1, 9, 19, + 31, 45, 51, 52, 47, 39, 35, 25, 15, -3, -23, -42, -58, -70, -71, -66, + -60, -51, -43, -30, -13, 6, 22, 32, 40, 40, 38, 33, 27, 19, 9, -5, + -17, -25, -26, -22, -16, -11, -8, -4, 7, 21, 35, 48, 53, 56, 50, 43, + 34, 22, 13, -2, -22, -44, -63, -75, -76, -69, -61, -51, -43, -29, -13, 6, + 23, 32, 41, 43, 41, 37, 26, 18, 7, -8, -19, -25, -25, -22, -15, -9, + -5, 0, 10, 24, 37, 44, 48, 52, 52, 46, 33, 20, 8, -5, -20, -38, + -59, -74, -79, -73, -67, -55, -43, -26, -11, 4, 18, 29, 41, 45, 45, 38, + 29, 21, 11, -3, -15, -25, -27, -22, -16, -11, -8, 0, 10, 25, 38, 44, + 47, 50, 53, 49, 37, 20, 7, -5, -17, -34, -58, -74, -82, -76, -67, -59, + -47, -29, -12, 3, 14, 25, 38, 50, 52, 46, 33, 23, 14, 3, -11, -25, + -28, -27, -21, -16, -13, -7, 8, 27, 41, 44, 45, 47, 54, 55, 44, 25, + 7, -7, -18, -32, -53, -71, -81, -81, -72, -67, -55, -37, -16, 3, 15, 23, + 34, 48, 57, 56, 44, 30, 19, 5, -12, -26, -33, -31, -25, -19, -16, -11, + 7, 25, 45, 49, 49, 52, 57, 59, 48, 32, 11, -5, -22, -39, -56, -73, + -82, -88, -84, -75, -60, -38, -16, 5, 21, 30, 39, 52, 59, 61, 53, 37, + 22, 7, -12, -28, -35, -36, -30, -22, -19, -16, -2, 21, 41, 52, 51, 52, + 57, 62, 54, 40, 18, -2, -18, -36, -54, -70, -80, -86, -87, -81, -69, -48, + -23, 0, 18, 28, 35, 45, 57, 64, 59, 46, 27, 9, -11, -24, -30, -32, + -29, -25, -20, -16, -5, 15, 36, 47, 50, 49, 53, 57, 54, 43, 24, 5, + -14, -32, -50, -65, -75, -82, -86, -86, -77, -58, -32, -8, 14, 25, 30, 41, + 56, 69, 69, 57, 36, 17, -4, -20, -29, -32, -27, -28, -27, -23, -13, 10, + 33, 46, 50, 48, 50, 54, 55, 48, 34, 16, -6, -29, -50, -68, -75, -78, + -82, -86, -84, -72, -47, -16, 11, 28, 34, 41, 51, 64, 70, 64, 49, 27, + 5, -17, -30, -33, -29, -29, -30, -30, -22, -2, 23, 41, 49, 51, 51, 54, + 56, 50, 42, 25, 4, -20, -44, -62, -70, -76, -83, -87, -89, -78, -56, -29, + 0, 19, 31, 38, 48, 63, 72, 71, 60, 40, 14, -12, -25, -29, -26, -27, + -33, -37, -30, -12, 11, 31, 41, 48, 51, 53, 55, 55, 51, 39, 17, -12, + -38, -58, -67, -74, -82, -92, -98, -89, -69, -41, -13, 10, 29, 41, 50, 64, + 72, 78, 74, 57, 29, 0, -18, -26, -28, -32, -38, -42, -38, -23, -3, 18, + 30, 42, 52, 58, 60, 61, 57, 48, 28, 2, -30, -51, -62, -70, -81, -94, + -101, -93, -75, -49, -23, -2, 18, 36, 50, 61, 69, 77, 78, 66, 42, 11, + -11, -22, -27, -32, -39, -46, -46, -36, -14, 8, 25, 41, 52, 59, 62, 63, + 62, 57, 38, 11, -20, -47, -61, -69, -78, -89, -98, -94, -80, -60, -37, -12, + 13, 33, 48, 62, 70, 78, 81, 72, 52, 23, 0, -14, -24, -33, -43, -49, + -49, -39, -23, -2, 15, 33, 47, 57, 63, 62, 62, 57, 40, 20, -7, -34, + -52, -65, -74, -83, -94, -92, -81, -63, -42, -22, 0, 21, 39, 54, 63, 73, + 79, 76, 61, 37, 12, -5, -19, -28, -37, -46, -51, -47, -32, -13, 7, 25, + 43, 54, 58, 60, 60, 61, 48, 27, 3, -25, -45, -60, -72, -81, -90, -92, + -84, -71, -52, -32, -9, 14, 33, 50, 61, 74, 80, 78, 67, 47, 24, 6, + -12, -26, -37, -50, -56, -52, -37, -19, -2, 16, 35, 52, 61, 63, 61, 59, + 51, 35, 12, -15, -38, -55, -66, -77, -83, -83, -80, -68, -55, -39, -19, 4, + 25, 41, 54, 66, 73, 75, 68, 52, 31, 11, -7, -22, -33, -46, -54, -51, + -39, -24, -5, 12, 32, 48, 56, 60, 61, 58, 50, 36, 17, -8, -30, -46, + -63, -74, -80, -80, -74, -69, -58, -43, -27, -5, 15, 31, 48, 60, 68, 72, + 68, 57, 39, 20, 2, -16, -30, -44, -51, -50, -41, -27, -10, 9, 28, 43, + 53, 57, 57, 54, 48, 37, 19, -3, -25, -41, -56, -69, -75, -73, -69, -63, + -59, -49, -32, -13, 9, 25, 37, 48, 58, 66, 65, 58, 42, 25, 8, -9, + -22, -36, -41, -43, -37, -26, -14, 4, 21, 37, 48, 52, 53, 47, 42, 34, + 21, 3, -18, -39, -51, -64, -67, -62, -60, -60, -58, -50, -36, -16, 3, 17, + 29, 41, 49, 58, 61, 60, 49, 29, 11, -7, -19, -28, -32, -33, -30, -25, + -14, 2, 19, 33, 41, 45, 42, 38, 36, 29, 20, 6, -14, -28, -43, -54, + -58, -55, -50, -51, -54, -51, -41, -22, -4, 11, 19, 30, 37, 47, 55, 56, + 51, 34, 16, 0, -15, -19, -23, -22, -22, -21, -14, 0, 15, 29, 39, 43, + 37, 31, 25, 21, 18, 6, -11, -28, -42, -50, -51, -48, -44, -41, -44, -43, + -41, -25, -8, 9, 16, 22, 26, 35, 43, 50, 48, 33, 16, -3, -13, -16, + -16, -15, -13, -11, -6, 5, 16, 28, 38, 41, 35, 24, 15, 12, 10, 4, + -11, -27, -39, -46, -46, -45, -40, -36, -36, -37, -38, -29, -13, 6, 16, 19, + 22, 27, 37, 43, 42, 32, 19, 2, -10, -13, -12, -7, -4, -2, 2, 10, + 18, 27, 36, 38, 32, 20, 9, 4, -2, -4, -11, -23, -34, -42, -42, -38, + -31, -28, -29, -32, -33, -30, -18, 0, 10, 12, 12, 17, 26, 35, 36, 31, + 19, 5, -6, -11, -9, -2, 7, 14, 13, 13, 16, 23, 31, 34, 29, 15, + -3, -8, -10, -10, -14, -20, -26, -30, -32, -30, -25, -18, -17, -24, -31, -32, + -26, -11, 2, 7, 8, 9, 17, 25, 29, 28, 21, 9, -2, -7, -5, 4, + 12, 21, 24, 23, 25, 26, 29, 31, 27, 15, -2, -15, -21, -23, -23, -23, + -28, -30, -31, -27, -19, -10, -9, -13, -21, -22, -20, -11, -4, -3, -5, -2, + 5, 13, 17, 17, 16, 10, 6, 0, 3, 11, 23, 32, 33, 30, 28, 27, + 24, 24, 19, 9, -6, -19, -29, -29, -26, -20, -19, -22, -24, -23, -16, -10, + -9, -14, -20, -24, -21, -16, -10, -6, -5, 1, 5, 11, 12, 13, 11, 8, + 6, 1, 4, 9, 23, 33, 39, 36, 32, 32, 28, 22, 17, 7, -7, -22, + -31, -33, -31, -24, -19, -18, -18, -16, -13, -7, -6, -8, -14, -21, -24, -20, + -15, -12, -9, -6, 0, 4, 6, 8, 8, 5, 5, 2, 7, 15, 27, 37, + 42, 45, 41, 39, 32, 22, 13, 3, -11, -26, -37, -41, -37, -29, -21, -18, + -15, -11, -6, -2, -2, -4, -7, -13, -16, -20, -21, -16, -14, -10, -6, -3, + -3, 0, 3, 2, 3, 3, 9, 18, 32, 41, 46, 49, 44, 43, 35, 24, + 12, 1, -14, -27, -39, -40, -36, -31, -22, -16, -13, -6, -3, -3, -4, -9, + -9, -13, -16, -20, -21, -16, -15, -11, -6, -4, -4, -5, -5, -3, -3, 0, + 10, 19, 33, 44, 51, 56, 52, 50, 40, 23, 11, -6, -19, -30, -40, -43, + -40, -35, -24, -16, -7, 2, 6, 5, 1, -6, -9, -9, -9, -12, -19, -21, + -21, -17, -9, -7, -9, -11, -15, -14, -9, -7, 7, 19, 36, 51, 57, 61, + 59, 56, 48, 33, 13, -8, -24, -35, -45, -51, -46, -38, -26, -14, -7, 3, + 11, 15, 12, 3, -5, -7, -6, -9, -15, -22, -25, -23, -17, -13, -12, -16, + -19, -21, -18, -12, 3, 21, 38, 50, 58, 67, 65, 64, 55, 41, 21, -4, + -25, -38, -46, -50, -49, -43, -33, -23, -11, 3, 14, 19, 16, 8, 0, -2, + -2, 0, -8, -19, -27, -30, -25, -22, -20, -20, -22, -25, -24, -16, 1, 22, + 43, 56, 62, 67, 68, 65, 60, 46, 24, -3, -25, -40, -45, -49, -50, -46, + -37, -23, -10, 1, 12, 20, 20, 14, 7, 2, 3, 3, -4, -15, -26, -31, + -30, -27, -26, -26, -29, -33, -33, -25, -8, 17, 41, 57, 65, 71, 73, 73, + 66, 53, 33, 5, -23, -41, -48, -50, -48, -48, -40, -30, -14, 1, 12, 21, + 24, 18, 13, 6, 5, 5, 0, -11, -25, -37, -39, -35, -31, -31, -33, -38, + -37, -29, -12, 15, 40, 59, 67, 71, 72, 73, 69, 59, 39, 14, -16, -38, + -50, -51, -50, -48, -45, -36, -21, -4, 12, 25, 30, 25, 18, 11, 11, 10, + 6, -8, -25, -39, -46, -42, -38, -37, -37, -40, -42, -34, -15, 13, 40, 57, + 66, 71, 72, 72, 69, 61, 45, 19, -10, -34, -46, -48, -47, -45, -45, -41, + -28, -12, 7, 23, 27, 25, 18, 15, 17, 17, 12, 1, -20, -37, -47, -50, + -46, -45, -44, -45, -46, -41, -21, 7, 37, 60, 69, 73, 72, 72, 72, 67, + 52, 25, -6, -33, -47, -50, -47, -47, -47, -45, -35, -16, 6, 23, 31, 30, + 24, 23, 24, 25, 18, 4, -15, -33, -50, -56, -57, -53, -48, -49, -49, -45, + -29, 2, 35, 58, 68, 71, 72, 74, 73, 68, 56, 34, 5, -26, -43, -48, + -45, -42, -46, -46, -41, -24, 0, 21, 33, 34, 31, 25, 27, 27, 19, 6, + -14, -36, -55, -64, -64, -60, -50, -47, -45, -44, -31, -4, 32, 58, 71, 72, + 68, 70, 70, 66, 57, 36, 11, -20, -43, -50, -48, -41, -37, -42, -40, -28, + -5, 21, 36, 38, 34, 26, 29, 28, 20, 8, -13, -33, -52, -68, -69, -65, + -55, -49, -47, -44, -31, -3, 30, 55, 67, 70, 68, 70, 70, 65, 57, 39, + 15, -13, -38, -49, -47, -40, -35, -39, -41, -30, -9, 17, 37, 44, 45, 38, + 32, 29, 22, 9, -10, -34, -54, -70, -75, -73, -64, -52, -45, -43, -31, -7, + 25, 53, 67, 72, 70, 72, 70, 62, 53, 38, 16, -10, -32, -49, -50, -43, + -35, -33, -36, -29, -10, 16, 35, 46, 46, 41, 35, 30, 23, 10, -10, -34, + -53, -69, -75, -74, -66, -53, -45, -42, -34, -13, 17, 46, 63, 68, 66, 63, + 65, 63, 54, 43, 24, 0, -20, -40, -43, -42, -36, -32, -32, -28, -16, 7, + 29, 47, 52, 47, 39, 31, 21, 10, -9, -30, -50, -66, -78, -77, -71, -59, + -49, -42, -34, -17, 9, 37, 56, 66, 66, 62, 62, 61, 56, 45, 30, 7, + -13, -31, -39, -40, -36, -33, -32, -28, -18, 1, 21, 41, 54, 52, 44, 36, + 26, 13, -8, -29, -48, -66, -76, -80, -74, -64, -55, -45, -34, -18, 5, 29, + 50, 65, 68, 66, 64, 60, 59, 47, 33, 15, -5, -23, -37, -43, -41, -37, + -35, -31, -21, -4, 16, 36, 52, 59, 54, 45, 33, 17, -5, -25, -45, -60, + -74, -83, -82, -71, -59, -49, -37, -23, -2, 22, 43, 59, 66, 65, 64, 60, + 58, 50, 39, 23, 2, -17, -32, -39, -40, -38, -35, -32, -23, -6, 14, 33, + 49, 59, 58, 49, 34, 16, -5, -25, -43, -60, -74, -83, -83, -76, -63, -53, + -40, -24, -5, 16, 36, 54, 65, 67, 65, 61, 57, 52, 43, 27, 9, -12, + -26, -37, -40, -39, -36, -32, -28, -13, 6, 27, 46, 58, 60, 52, 39, 23, + 5, -16, -36, -53, -66, -77, -84, -81, -72, -60, -45, -32, -15, 5, 25, 48, + 62, 69, 71, 69, 65, 58, 50, 34, 16, -6, -24, -36, -42, -45, -44, -39, + -33, -21, -2, 22, 43, 59, 64, 60, 47, 34, 17, -6, -28, -50, -66, -76, + -84, -86, -82, -72, -57, -40, -21, -2, 21, 42, 58, 66, 73, 76, 71, 64, + 53, 40, 26, 4, -17, -34, -45, -49, -48, -43, -38, -28, -10, 15, 40, 58, + 66, 64, 56, 42, 25, 4, -21, -44, -62, -73, -81, -87, -86, -78, -65, -47, + -31, -9, 15, 34, 52, 62, 72, 79, 80, 72, 61, 49, 34, 12, -12, -32, + -43, -49, -54, -55, -48, -36, -16, 10, 35, 56, 67, 71, 67, 54, 38, 15, + -10, -34, -57, -72, -85, -93, -97, -89, -76, -59, -40, -20, 8, 32, 50, 67, + 77, 87, 89, 81, 66, 52, 35, 16, -6, -30, -47, -58, -61, -57, -50, -37, + -19, 6, 29, 51, 65, 73, 73, 62, 44, 18, -6, -28, -49, -67, -81, -93, + -97, -94, -83, -65, -47, -28, -5, 19, 42, 61, 76, 87, 90, 88, 80, 66, + 48, 27, 3, -17, -40, -56, -65, -66, -58, -49, -30, -6, 17, 41, 59, 71, + 77, 70, 56, 36, 11, -13, -34, -53, -71, -89, -98, -100, -94, -79, -62, -44, + -21, 3, 27, 52, 74, 90, 98, 95, 86, 75, 59, 37, 12, -14, -35, -54, + -64, -67, -64, -51, -34, -10, 11, 32, 50, 65, 73, 71, 58, 37, 14, -10, + -29, -48, -64, -81, -93, -98, -94, -82, -63, -45, -26, -5, 16, 40, 65, 83, + 94, 94, 84, 75, 63, 46, 23, -3, -27, -47, -58, -64, -64, -56, -39, -17, + 3, 20, 38, 57, 71, 72, 61, 45, 24, 1, -19, -37, -56, -73, -91, -99, + -100, -92, -74, -53, -34, -16, 7, 31, 59, 82, 97, 101, 92, 78, 65, 48, + 29, 6, -21, -43, -55, -64, -66, -58, -40, -18, 3, 17, 32, 51, 69, 71, + 62, 45, 27, 6, -15, -34, -50, -64, -81, -93, -99, -96, -80, -59, -40, -23, + -4, 21, 50, 77, 94, 100, 93, 81, 67, 53, 36, 14, -12, -36, -53, -58, + -63, -56, -42, -22, -5, 10, 23, 42, 63, 70, 62, 47, 29, 13, -6, -27, + -43, -57, -72, -84, -98, -99, -87, -66, -44, -27, -11, 10, 38, 67, 91, 99, + 92, 82, 70, 57, 41, 21, -3, -27, -47, -58, -63, -58, -44, -23, -5, 7, + 17, 35, 55, 66, 61, 46, 29, 13, -4, -22, -39, -51, -65, -78, -90, -95, + -85, -69, -47, -30, -12, 9, 30, 57, 83, 96, 91, 81, 67, 57, 42, 26, + 6, -18, -39, -55, -62, -58, -43, -24, -8, 2, 14, 30, 47, 60, 60, 49, + 34, 17, 0, -16, -31, -43, -58, -71, -86, -93, -86, -72, -52, -32, -15, 3, + 22, 48, 76, 90, 89, 78, 69, 59, 46, 32, 14, -6, -27, -47, -57, -56, + -45, -29, -12, -5, 4, 18, 37, 54, 58, 51, 36, 21, 6, -8, -20, -33, + -52, -68, -84, -90, -85, -74, -58, -42, -22, 0, 20, 42, 67, 83, 87, 80, + 68, 58, 47, 34, 19, 0, -20, -40, -52, -53, -45, -27, -13, -4, 6, 17, + 33, 47, 53, 52, 38, 21, 3, -11, -24, -35, -50, -65, -80, -89, -85, -71, + -55, -39, -21, -2, 20, 39, 59, 74, 81, 75, 67, 57, 47, 38, 23, 4, + -17, -32, -43, -45, -39, -26, -14, -4, 4, 12, 26, 38, 47, 48, 35, 19, + 4, -10, -20, -29, -41, -56, -71, -78, -81, -71, -56, -43, -23, -6, 15, 35, + 49, 62, 72, 69, 63, 54, 45, 41, 28, 11, -11, -27, -37, -40, -35, -24, + -17, -7, 2, 9, 22, 35, 46, 49, 37, 21, 4, -9, -18, -27, -41, -55, + -71, -79, -79, -70, -53, -38, -23, -8, 9, 31, 46, 58, 63, 63, 59, 52, + 45, 40, 32, 14, -6, -24, -32, -31, -30, -23, -18, -12, 1, 9, 21, 31, + 41, 44, 33, 21, 5, -6, -20, -29, -43, -57, -69, -77, -73, -65, -52, -41, + -27, -8, 11, 32, 49, 57, 64, 61, 55, 47, 39, 36, 29, 13, -8, -25, + -36, -35, -26, -16, -9, -5, 1, 9, 22, 36, 45, 43, 33, 17, 1, -11, + -21, -32, -45, -57, -71, -78, -73, -61, -45, -33, -23, -8, 11, 31, 46, 53, + 57, 54, 48, 40, 34, 31, 27, 14, -4, -20, -29, -28, -22, -12, -4, 1, + 4, 8, 21, 34, 43, 43, 31, 17, 1, -11, -22, -31, -44, -59, -72, -78, + -70, -54, -40, -28, -19, -8, 10, 28, 45, 53, 57, 53, 43, 34, 28, 27, + 26, 18, 0, -18, -31, -29, -20, -11, -3, 2, 5, 10, 19, 31, 43, 44, + 34, 19, 2, -13, -23, -32, -43, -55, -68, -77, -73, -57, -41, -26, -15, -6, + 11, 28, 43, 52, 52, 49, 41, 33, 24, 22, 21, 14, 1, -14, -25, -24, + -18, -7, -2, 2, 7, 10, 20, 31, 40, 43, 33, 18, 3, -13, -24, -35, + -44, -55, -70, -78, -74, -59, -40, -26, -11, 1, 13, 29, 44, 53, 57, 54, + 45, 32, 24, 18, 13, 9, -4, -16, -26, -29, -22, -10, 1, 8, 13, 18, + 23, 35, 42, 45, 37, 21, 5, -14, -30, -41, -49, -57, -69, -77, -76, -61, + -39, -20, -5, 9, 20, 34, 47, 53, 55, 48, 39, 27, 14, 8, 3, 2, + -4, -15, -23, -24, -16, -3, 6, 11, 19, 24, 30, 34, 41, 43, 35, 18, + 1, -17, -31, -44, -52, -59, -68, -75, -73, -61, -38, -19, 1, 13, 23, 30, + 42, 52, 52, 47, 36, 23, 14, 7, 4, 0, -6, -11, -20, -24, -18, -5, + 7, 15, 18, 22, 28, 36, 43, 43, 38, 24, 4, -13, -30, -44, -55, -64, + -69, -77, -76, -65, -44, -19, 1, 15, 27, 35, 46, 53, 53, 46, 36, 23, + 11, 3, -5, -7, -9, -14, -20, -23, -19, -7, 11, 18, 21, 25, 30, 40, + 43, 43, 38, 24, 7, -14, -30, -41, -55, -65, -73, -77, -74, -66, -49, -24, + -2, 17, 29, 35, 44, 51, 54, 49, 35, 23, 11, 1, -6, -12, -15, -16, + -20, -24, -21, -10, 8, 21, 27, 33, 35, 42, 48, 47, 37, 23, 7, -12, + -28, -44, -60, -69, -75, -78, -74, -65, -49, -25, -2, 17, 30, 40, 48, 54, + 55, 48, 36, 20, 6, -4, -9, -14, -20, -22, -24, -21, -15, -6, 7, 21, + 32, 39, 43, 44, 49, 50, 38, 21, 4, -13, -28, -47, -62, -74, -77, -78, + -77, -65, -48, -26, -4, 15, 28, 40, 50, 56, 54, 46, 33, 20, 9, -2, + -10, -16, -21, -21, -23, -21, -15, -5, 9, 19, 30, 38, 42, 44, 46, 47, + 36, 22, 6, -10, -23, -39, -57, -74, -78, -79, -75, -65, -51, -33, -11, 9, + 25, 37, 46, 55, 56, 48, 34, 21, 10, 4, -4, -14, -20, -25, -24, -21, + -12, -3, 8, 17, 26, 36, 47, 50, 50, 47, 36, 25, 10, -5, -21, -40, + -57, -75, -82, -79, -75, -64, -51, -37, -16, 5, 25, 40, 48, 55, 55, 49, + 37, 25, 15, 6, -6, -18, -26, -29, -25, -20, -16, -7, 5, 17, 29, 39, + 49, 56, 56, 51, 39, 28, 15, 0, -17, -38, -58, -75, -86, -86, -80, -70, + -54, -37, -16, 7, 25, 42, 50, 55, 58, 52, 40, 25, 11, 2, -5, -14, + -21, -26, -26, -18, -12, -5, 4, 13, 25, 34, 45, 53, 55, 48, 39, 25, + 16, 3, -13, -31, -54, -70, -83, -85, -78, -68, -55, -38, -20, 1, 20, 36, + 46, 51, 55, 48, 39, 27, 17, 7, -5, -13, -20, -23, -23, -18, -10, -4, + 3, 10, 21, 29, 40, 48, 52, 50, 40, 28, 20, 10, -5, -24, -48, -67, + -82, -87, -81, -73, -56, -44, -25, -5, 15, 34, 46, 52, 55, 51, 39, 27, + 18, 7, -2, -13, -22, -25, -24, -16, -9, 1, 8, 13, 22, 30, 42, 48, + 50, 47, 38, 26, 15, 6, -8, -22, -41, -61, -77, -86, -81, -70, -54, -40, + -27, -8, 12, 31, 42, 49, 50, 48, 38, 26, 16, 7, -4, -11, -18, -22, + -21, -16, -9, 0, 9, 15, 21, 26, 35, 47, 50, 46, 36, 28, 18, 7, + -7, -22, -37, -53, -70, -81, -83, -72, -58, -43, -30, -14, 5, 22, 37, 44, + 46, 44, 37, 26, 17, 8, 2, -7, -12, -17, -16, -12, -6, 3, 8, 13, + 17, 22, 31, 42, 43, 43, 35, 29, 25, 14, 2, -17, -35, -51, -65, -77, + -80, -75, -63, -47, -34, -18, 4, 21, 32, 38, 41, 41, 36, 28, 17, 8, + 1, -9, -12, -16, -15, -9, -2, 8, 13, 15, 17, 23, 28, 39, 43, 38, + 30, 21, 17, 11, 4, -12, -28, -45, -60, -68, -71, -66, -58, -49, -38, -23, + -5, 15, 27, 34, 34, 32, 28, 23, 18, 13, 4, -2, -7, -9, -7, -4, + 5, 14, 16, 16, 14, 15, 24, 35, 39, 35, 23, 17, 15, 11, 8, -4, + -19, -37, -53, -62, -65, -62, -57, -53, -43, -31, -14, 5, 19, 27, 31, 28, + 26, 23, 20, 18, 11, 5, -2, -5, 0, 3, 8, 14, 16, 15, 11, 7, + 12, 23, 32, 32, 21, 12, 10, 13, 12, 6, -9, -27, -43, -50, -55, -53, + -51, -52, -44, -38, -23, -6, 7, 18, 22, 19, 16, 15, 16, 19, 17, 12, + 6, 3, 7, 10, 16, 20, 23, 20, 14, 8, 9, 17, 27, 26, 17, 6, + 3, 7, 10, 7, -5, -18, -32, -41, -46, -45, -45, -45, -44, -40, -30, -16, + -3, 8, 15, 12, 10, 11, 16, 19, 19, 16, 12, 10, 11, 15, 20, 25, + 26, 24, 18, 11, 6, 11, 17, 21, 15, 3, -6, -2, 4, 7, 2, -14, + -25, -32, -36, -38, -37, -37, -35, -33, -33, -25, -15, -4, 3, 4, 0, -3, + 2, 13, 21, 21, 20, 17, 19, 23, 27, 31, 33, 31, 24, 16, 4, 2, + 7, 13, 13, 3, -10, -9, 0, 8, 7, -3, -15, -22, -24, -30, -32, -37, + -39, -38, -37, -34, -28, -17, -8, -2, -4, -4, 4, 16, 26, 30, 26, 22, + 22, 25, 29, 31, 30, 29, 24, 17, 6, -2, 7, 10, 13, 4, -11, -15, + -10, 3, 8, 2, -10, -17, -17, -17, -23, -29, -35, -37, -34, -36, -35, -28, + -19, -10, -11, -14, -8, 8, 21, 26, 26, 21, 24, 31, 38, 40, 38, 37, + 33, 26, 15, 4, 1, 2, 1, -6, -19, -24, -18, -7, 2, 5, -4, -10, + -9, -6, -7, -16, -27, -33, -35, -38, -41, -38, -32, -22, -20, -18, -10, 4, + 20, 29, 31, 30, 28, 32, 38, 43, 42, 39, 34, 28, 14, 4, 1, 3, + 4, -5, -21, -30, -26, -14, 1, 3, -4, -8, -8, 0, 0, -8, -15, -26, + -29, -35, -40, -40, -36, -30, -28, -29, -22, -10, 9, 22, 28, 28, 27, 30, + 39, 46, 50, 50, 43, 33, 21, 9, 3, 3, 1, -10, -22, -35, -34, -22, + -8, 2, 0, -6, -7, 0, 5, -2, -9, -18, -28, -34, -41, -43, -39, -35, + -33, -33, -25, -12, 5, 19, 26, 29, 31, 31, 39, 46, 51, 52, 47, 38, + 27, 18, 10, 5, -3, -13, -22, -33, -36, -28, -16, -4, -2, -4, -6, 0, + 8, 7, 0, -12, -22, -33, -40, -42, -39, -37, -38, -39, -32, -17, 2, 15, + 24, 25, 28, 33, 39, 47, 51, 53, 51, 44, 35, 23, 15, 8, 1, -12, + -25, -37, -41, -33, -22, -11, -4, -5, -3, 3, 10, 13, 6, -5, -17, -28, + -38, -43, -44, -44, -44, -43, -36, -23, -7, 7, 20, 26, 29, 35, 43, 51, + 54, 58, 56, 52, 44, 29, 18, 9, -2, -12, -28, -39, -45, -38, -26, -16, + -7, -3, 1, 6, 12, 15, 12, 3, -11, -25, -37, -41, -43, -46, -47, -46, + -39, -28, -15, 0, 11, 21, 25, 31, 38, 46, 53, 60, 62, 59, 53, 42, + 32, 19, 6, -10, -27, -41, -47, -47, -39, -31, -21, -9, -2, 5, 11, 16, + 19, 13, 2, -15, -30, -35, -37, -43, -47, -49, -42, -32, -21, -11, 0, 8, + 19, 27, 38, 47, 51, 58, 63, 63, 59, 50, 41, 28, 10, -9, -26, -37, + -43, -44, -40, -33, -23, -11, 0, 6, 9, 14, 15, 13, 1, -15, -25, -32, + -34, -43, -49, -50, -43, -30, -20, -13, -9, 0, 10, 23, 36, 46, 52, 55, + 62, 65, 66, 61, 51, 36, 15, -7, -24, -34, -42, -45, -46, -42, -34, -20, + -5, 5, 11, 14, 16, 13, 2, -10, -18, -24, -31, -39, -49, -48, -42, -34, + -24, -18, -15, -8, 2, 13, 29, 42, 51, 57, 62, 65, 70, 69, 60, 45, + 20, -3, -24, -37, -43, -46, -49, -48, -39, -24, -6, 5, 12, 17, 20, 16, + 6, -9, -15, -21, -26, -38, -50, -56, -50, -37, -26, -23, -19, -14, -4, 11, + 27, 42, 54, 58, 63, 65, 68, 70, 63, 50, 26, 1, -21, -37, -43, -44, + -44, -44, -40, -28, -11, 5, 10, 16, 18, 14, 5, -12, -19, -22, -24, -33, + -47, -52, -52, -38, -25, -17, -17, -16, -10, 4, 22, 39, 53, 59, 62, 63, + 66, 68, 66, 55, 32, 9, -17, -34, -43, -42, -39, -38, -38, -31, -19, -3, + 10, 17, 19, 12, 3, -12, -21, -24, -24, -31, -40, -49, -52, -41, -30, -18, + -15, -17, -10, 0, 16, 33, 47, 59, 65, 64, 65, 67, 63, 56, 38, 13, + -12, -32, -41, -39, -35, -33, -32, -27, -17, -4, 8, 15, 16, 13, 4, -11, + -20, -25, -27, -32, -40, -48, -52, -46, -37, -25, -18, -16, -10, 1, 16, 33, + 49, 59, 66, 67, 65, 66, 62, 51, 38, 15, -9, -30, -38, -41, -33, -29, + -26, -23, -17, -5, 7, 16, 15, 14, 5, -9, -19, -27, -31, -34, -40, -47, + -52, -49, -40, -30, -22, -16, -8, 4, 19, 32, 46, 59, 67, 71, 69, 64, + 57, 49, 36, 17, -7, -27, -38, -40, -35, -28, -23, -19, -12, -5, 6, 12, + 16, 15, 10, -5, -19, -28, -32, -36, -39, -46, -53, -52, -45, -34, -25, -18, + -7, 6, 20, 33, 46, 60, 67, 74, 71, 65, 56, 46, 37, 18, -2, -20, + -33, -38, -38, -30, -22, -16, -12, -6, 2, 6, 15, 15, 11, 1, -11, -19, + -31, -37, -42, -46, -51, -54, -53, -46, -35, -26, -14, 3, 17, 33, 45, 57, + 67, 75, 77, 71, 62, 50, 36, 18, 0, -19, -31, -36, -37, -31, -23, -17, + -11, -6, 1, 6, 11, 15, 14, 8, -3, -16, -27, -37, -41, -47, -52, -58, + -60, -55, -46, -32, -16, 0, 17, 32, 46, 59, 70, 79, 80, 75, 65, 51, + 35, 20, 2, -15, -27, -38, -42, -36, -27, -17, -10, -4, 3, 7, 12, 18, + 19, 14, 5, -7, -22, -37, -46, -53, -57, -62, -67, -65, -58, -43, -22, 1, + 20, 35, 48, 60, 69, 79, 82, 79, 68, 53, 36, 21, 4, -11, -24, -36, + -40, -38, -31, -21, -14, -5, 1, 5, 11, 17, 22, 19, 14, -2, -17, -35, + -48, -55, -63, -67, -73, -72, -64, -49, -27, -4, 19, 36, 52, 64, 73, 81, + 85, 82, 72, 56, 36, 20, 3, -14, -24, -33, -36, -35, -32, -22, -13, -6, + 2, 7, 10, 15, 19, 19, 17, 6, -10, -29, -48, -58, -67, -71, -75, -78, + -72, -58, -35, -10, 16, 35, 52, 65, 74, 80, 86, 87, 79, 62, 39, 21, + 5, -11, -22, -33, -39, -39, -34, -25, -15, -7, 3, 8, 16, 17, 21, 22, + 19, 9, -6, -27, -47, -60, -71, -77, -80, -81, -73, -61, -39, -12, 16, 36, + 52, 63, 73, 80, 85, 87, 76, 59, 41, 23, 8, -7, -18, -29, -36, -38, + -33, -23, -13, -8, 1, 6, 14, 18, 19, 23, 23, 17, 1, -20, -43, -57, + -67, -78, -83, -89, -81, -67, -45, -19, 9, 35, 55, 67, 74, 80, 87, 91, + 83, 68, 44, 24, 6, -9, -21, -29, -36, -39, -39, -31, -20, -10, 1, 13, + 20, 26, 26, 27, 28, 22, 8, -16, -40, -60, -75, -86, -93, -95, -89, -75, + -52, -24, 7, 37, 57, 69, 77, 83, 90, 93, 85, 70, 48, 27, 8, -8, + -19, -26, -32, -35, -39, -37, -28, -17, -2, 9, 19, 21, 27, 31, 32, 29, + 12, -9, -32, -54, -71, -86, -94, -96, -90, -82, -62, -33, 2, 34, 56, 69, + 78, 87, 94, 94, 85, 69, 49, 29, 9, -10, -21, -27, -30, -33, -37, -36, + -29, -17, -5, 9, 19, 25, 27, 31, 33, 33, 21, -2, -25, -51, -71, -86, + -95, -95, -92, -85, -69, -42, -8, 27, 52, 67, 74, 83, 92, 95, 89, 75, + 56, 35, 16, -6, -17, -26, -28, -34, -41, -39, -37, -25, -9, 6, 20, 28, + 31, 37, 37, 34, 24, 3, -20, -46, -69, -85, -96, -99, -97, -89, -73, -47, + -11, 21, 45, 61, 73, 84, 92, 95, 89, 77, 61, 41, 20, -2, -13, -20, + -28, -36, -43, -46, -40, -30, -16, 0, 12, 24, 30, 38, 43, 41, 33, 13, + -14, -39, -63, -80, -93, -98, -100, -94, -76, -52, -19, 14, 38, 56, 70, 80, + 90, 94, 88, 75, 58, 40, 22, 6, -8, -19, -25, -33, -39, -41, -38, -31, + -19, -5, 7, 21, 31, 39, 45, 42, 32, 15, -8, -32, -55, -77, -93, -102, + -101, -94, -80, -57, -29, 5, 34, 54, 70, 78, 88, 96, 92, 80, 62, 41, + 24, 8, -9, -21, -32, -35, -38, -41, -39, -35, -22, -6, 6, 21, 31, 39, + 46, 44, 35, 18, -5, -27, -49, -70, -86, -97, -102, -96, -84, -58, -30, -2, + 26, 45, 62, 74, 82, 89, 89, 80, 66, 46, 28, 12, -3, -14, -26, -36, + -39, -42, -40, -36, -28, -15, 0, 17, 30, 37, 45, 48, 40, 23, 3, -20, + -43, -64, -81, -93, -98, -96, -85, -65, -38, -8, 20, 40, 55, 68, 80, 88, + 88, 82, 68, 54, 35, 18, 2, -12, -24, -35, -40, -45, -45, -41, -33, -20, + -4, 15, 31, 41, 49, 52, 48, 32, 13, -14, -38, -59, -77, -92, -101, -102, + -91, -70, -45, -15, 15, 38, 53, 65, 77, 89, 91, 85, 71, 52, 38, 21, + 5, -12, -26, -36, -42, -45, -45, -43, -34, -22, -7, 9, 26, 39, 50, 56, + 50, 34, 14, -7, -29, -50, -69, -84, -96, -98, -90, -72, -50, -24, 7, 32, + 48, 57, 68, 84, 91, 88, 74, 58, 44, 30, 11, -9, -26, -38, -41, -46, + -45, -44, -38, -23, -7, 9, 24, 36, 49, 55, 51, 35, 18, -3, -24, -45, + -64, -78, -89, -93, -90, -75, -54, -29, 0, 23, 42, 54, 67, 80, 90, 91, + 81, 65, 48, 31, 13, -5, -24, -41, -50, -53, -51, -46, -42, -28, -10, 8, + 23, 36, 50, 59, 56, 44, 26, 8, -13, -35, -56, -77, -89, -94, -92, -80, + -61, -39, -11, 14, 33, 50, 63, 77, 88, 89, 81, 67, 54, 38, 21, 1, + -23, -39, -50, -54, -53, -46, -42, -31, -17, 1, 17, 33, 46, 56, 56, 46, + 33, 16, -4, -24, -46, -67, -82, -92, -94, -87, -67, -45, -19, 4, 22, 43, + 62, 76, 87, 90, 87, 76, 59, 40, 20, 1, -22, -40, -55, -62, -58, -50, + -40, -29, -17, -3, 14, 33, 49, 59, 58, 49, 35, 21, 2, -17, -39, -59, + -76, -90, -93, -86, -70, -49, -29, -8, 12, 33, 57, 75, 84, 87, 84, 78, + 65, 47, 28, 6, -18, -39, -58, -65, -64, -57, -44, -33, -22, -10, 6, 26, + 44, 56, 56, 48, 40, 27, 11, -8, -30, -49, -65, -80, -86, -87, -72, -51, + -31, -13, 5, 24, 48, 70, 81, 86, 83, 79, 69, 51, 30, 8, -16, -37, + -55, -65, -67, -61, -48, -36, -21, -10, 5, 22, 40, 55, 58, 53, 43, 31, + 16, -2, -23, -45, -60, -74, -82, -86, -75, -56, -36, -16, 1, 21, 44, 65, + 81, 88, 85, 81, 72, 54, 33, 8, -18, -41, -58, -71, -74, -70, -56, -41, + -23, -6, 8, 23, 38, 53, 60, 59, 50, 37, 22, 1, -20, -41, -56, -69, + -79, -83, -78, -62, -42, -20, 2, 22, 41, 59, 77, 86, 87, 79, 67, 50, + 31, 10, -15, -36, -52, -63, -69, -69, -59, -41, -23, -9, 4, 15, 29, 44, + 55, 56, 53, 43, 27, 12, -8, -27, -44, -57, -68, -78, -77, -67, -48, -29, + -12, 12, 32, 52, 70, 79, 84, 82, 73, 59, 38, 15, -9, -33, -52, -63, + -71, -72, -66, -50, -30, -13, 2, 12, 27, 42, 50, 54, 54, 46, 34, 19, + -2, -19, -35, -47, -61, -71, -72, -66, -51, -36, -19, 5, 27, 46, 63, 74, + 79, 79, 70, 58, 41, 21, 3, -24, -44, -58, -66, -66, -65, -52, -36, -22, + -10, 4, 18, 34, 43, 49, 52, 48, 43, 31, 14, -4, -21, -35, -51, -61, + -66, -64, -56, -43, -29, -8, 16, 37, 54, 67, 72, 74, 70, 61, 46, 27, + 7, -19, -40, -56, -62, -62, -63, -55, -43, -26, -10, 3, 13, 26, 38, 44, + 47, 43, 39, 30, 19, 5, -12, -24, -40, -47, -51, -53, -51, -44, -32, -14, + 6, 24, 41, 54, 61, 63, 61, 56, 47, 32, 13, -9, -31, -46, -56, -53, + -54, -54, -48, -37, -18, -3, 8, 17, 27, 33, 38, 39, 39, 37, 30, 18, + 1, -16, -29, -35, -39, -42, -47, -47, -39, -22, -3, 14, 29, 42, 51, 57, + 56, 54, 45, 36, 20, -2, -23, -41, -50, -51, -52, -53, -51, -42, -27, -8, + 5, 12, 19, 28, 35, 40, 39, 40, 37, 28, 12, -7, -23, -28, -30, -37, + -43, -49, -45, -32, -15, 3, 19, 34, 45, 49, 49, 51, 47, 41, 26, 6, + -18, -34, -43, -45, -45, -48, -51, -49, -33, -15, -2, 8, 12, 19, 26, 33, + 38, 38, 38, 34, 25, 8, -11, -19, -20, -23, -32, -43, -48, -41, -24, -8, + 10, 21, 31, 38, 43, 47, 48, 45, 34, 16, -9, -31, -41, -42, -42, -46, + -52, -52, -40, -23, -6, 6, 11, 17, 24, 30, 35, 38, 39, 40, 29, 14, + -3, -14, -14, -15, -24, -36, -47, -45, -33, -15, 3, 14, 23, 29, 35, 39, + 44, 45, 38, 22, -3, -26, -38, -37, -37, -41, -50, -56, -45, -26, -8, 5, + 12, 16, 22, 27, 32, 39, 41, 41, 33, 17, 1, -9, -8, -8, -16, -30, + -41, -45, -35, -21, -5, 10, 18, 24, 28, 31, 38, 42, 39, 25, 2, -23, + -36, -36, -37, -39, -47, -53, -47, -31, -11, 3, 12, 16, 23, 27, 32, 37, + 40, 41, 33, 18, 2, -7, -8, -6, -10, -23, -36, -41, -35, -20, -6, 7, + 14, 17, 24, 29, 36, 42, 40, 28, 5, -20, -35, -38, -38, -39, -45, -51, + -46, -33, -15, 2, 13, 22, 27, 28, 27, 30, 37, 41, 35, 20, 5, -4, + -4, -2, -3, -13, -28, -35, -32, -23, -10, 3, 11, 14, 14, 20, 28, 37, + 40, 27, 7, -16, -31, -36, -37, -36, -41, -44, -45, -35, -18, 1, 12, 19, + 25, 26, 27, 31, 34, 39, 34, 20, 8, 0, 0, 1, 0, -9, -23, -33, + -34, -24, -10, 2, 8, 8, 10, 16, 27, 34, 35, 27, 10, -10, -27, -35, + -35, -34, -39, -46, -47, -38, -22, -3, 10, 19, 26, 31, 32, 32, 35, 41, + 39, 25, 9, -2, -3, -2, -2, -7, -19, -30, -33, -26, -14, -3, 6, 6, + 7, 12, 26, 37, 37, 26, 10, -8, -25, -35, -39, -39, -42, -47, -49, -42, + -27, -4, 12, 20, 29, 33, 36, 35, 35, 38, 37, 27, 10, -3, -6, -3, + -2, -7, -16, -24, -28, -24, -13, -4, 4, 5, 7, 9, 19, 30, 33, 28, + 12, -6, -24, -35, -40, -39, -42, -47, -47, -41, -26, -8, 10, 22, 31, 36, + 41, 39, 34, 33, 33, 29, 15, 2, -7, -8, -6, -6, -10, -18, -24, -24, + -15, -5, 6, 7, 7, 10, 17, 23, 23, 18, 9, -7, -23, -36, -42, -41, + -41, -45, -45, -39, -28, -11, 7, 21, 31, 36, 39, 39, 34, 31, 33, 29, + 19, 7, -5, -6, -6, -4, -6, -13, -17, -20, -16, -8, 1, 6, 7, 7, + 11, 16, 20, 18, 9, -7, -24, -37, -43, -42, -42, -42, -45, -41, -28, -11, + 7, 19, 28, 35, 40, 42, 38, 33, 29, 27, 21, 10, -2, -8, -8, -6, + -8, -11, -13, -16, -14, -8, 1, 5, 8, 9, 15, 19, 20, 18, 9, -4, + -18, -34, -42, -46, -47, -45, -47, -45, -36, -20, 0, 13, 26, 36, 45, 48, + 42, 35, 29, 28, 26, 20, 6, -6, -10, -10, -6, -7, -8, -10, -14, -10, + -7, 0, 6, 8, 13, 14, 16, 13, 7, -3, -13, -27, -37, -44, -49, -44, + -42, -40, -37, -25, -9, 9, 23, 31, 41, 44, 44, 37, 30, 27, 28, 27, + 15, 2, -7, -9, -6, -7, -9, -8, -13, -12, -8, -3, 4, 9, 13, 14, + 14, 11, 6, 0, -9, -23, -34, -43, -49, -46, -42, -40, -35, -29, -13, 3, + 19, 31, 41, 45, 43, 37, 31, 29, 30, 28, 19, 4, -5, -7, -7, -5, + -8, -7, -9, -11, -9, -4, 0, 6, 12, 14, 13, 9, 5, -3, -9, -19, + -28, -37, -48, -48, -45, -39, -34, -30, -18, -5, 12, 23, 34, 42, 44, 39, + 34, 32, 31, 33, 30, 18, 8, 1, -5, -6, -5, -5, -8, -13, -16, -14, + -7, 2, 7, 11, 10, 7, 4, -2, -7, -12, -22, -32, -45, -50, -45, -38, + -33, -30, -24, -13, 2, 20, 31, 39, 43, 42, 38, 36, 33, 33, 33, 24, + 14, 1, -8, -9, -7, -4, -5, -11, -16, -16, -11, -4, 2, 9, 8, 7, + 3, -3, -6, -9, -15, -24, -38, -47, -48, -42, -35, -32, -29, -21, -9, 11, + 27, 35, 42, 42, 42, 40, 40, 38, 36, 30, 19, 8, -4, -9, -8, -5, + -5, -12, -18, -20, -15, -5, -2, 3, 4, 5, 6, 1, -3, -8, -12, -19, + -31, -43, -47, -43, -36, -35, -36, -32, -19, 2, 19, 30, 38, 42, 46, 49, + 50, 47, 43, 39, 28, 16, 1, -10, -13, -11, -9, -14, -21, -25, -20, -10, + -4, 1, 3, 4, 7, 4, -3, -7, -7, -10, -23, -38, -47, -46, -41, -37, + -38, -37, -27, -11, 11, 24, 33, 38, 45, 50, 53, 52, 48, 43, 37, 25, + 10, -3, -11, -11, -11, -13, -20, -27, -29, -22, -14, -7, -2, 2, 6, 3, + -2, -3, 0, 0, -11, -28, -41, -45, -39, -35, -36, -39, -37, -24, -7, 11, + 22, 32, 41, 51, 55, 56, 54, 53, 50, 40, 23, 6, -5, -10, -11, -14, + -20, -28, -34, -33, -25, -16, -10, -5, 0, 0, 1, 2, 4, 5, -4, -16, + -29, -35, -37, -37, -35, -39, -39, -32, -19, 0, 13, 23, 36, 46, 54, 58, + 57, 59, 56, 47, 33, 16, 3, -5, -9, -11, -19, -29, -36, -39, -33, -26, + -18, -12, -7, -5, -2, 4, 11, 15, 10, -3, -18, -29, -32, -35, -36, -41, + -44, -40, -30, -18, 0, 13, 28, 41, 50, 59, 63, 66, 66, 60, 44, 26, + 11, 2, -6, -12, -19, -29, -38, -44, -41, -33, -25, -16, -9, -8, -6, 1, + 11, 18, 16, 8, -6, -17, -27, -32, -36, -39, -43, -44, -37, -30, -12, 8, + 26, 39, 46, 56, 64, 70, 72, 66, 51, 36, 18, 7, -4, -11, -18, -29, + -42, -50, -51, -45, -35, -23, -14, -10, -9, 0, 14, 27, 29, 20, 7, -5, + -15, -23, -30, -38, -45, -50, -49, -43, -30, -9, 13, 31, 41, 52, 65, 75, + 79, 77, 66, 50, 30, 13, 3, -6, -14, -26, -41, -53, -57, -54, -44, -32, + -23, -17, -13, -5, 10, 24, 31, 28, 20, 9, -5, -17, -26, -35, -40, -48, + -54, -53, -44, -23, 0, 21, 35, 46, 60, 73, 81, 83, 77, 60, 42, 25, + 11, 1, -11, -25, -42, -57, -64, -62, -54, -43, -33, -24, -17, -6, 9, 23, + 37, 37, 33, 19, 6, -9, -20, -30, -41, -49, -57, -59, -54, -38, -16, 10, + 31, 46, 58, 70, 78, 85, 84, 73, 54, 32, 16, 5, -5, -22, -41, -60, + -72, -71, -66, -54, -43, -30, -19, -6, 10, 25, 41, 47, 43, 32, 20, 7, + -10, -25, -40, -52, -61, -68, -65, -54, -34, -11, 16, 39, 57, 72, 80, 88, + 91, 83, 67, 46, 28, 13, 1, -18, -40, -62, -77, -77, -70, -63, -54, -43, + -30, -12, 7, 25, 40, 51, 51, 42, 31, 19, 3, -13, -32, -48, -60, -68, + -71, -63, -49, -28, -2, 23, 46, 66, 77, 86, 92, 89, 82, 62, 43, 22, + 7, -12, -39, -59, -74, -80, -78, -72, -63, -50, -35, -17, 5, 22, 35, 45, + 49, 49, 42, 31, 13, -7, -25, -38, -49, -59, -66, -65, -57, -42, -20, 8, + 34, 55, 69, 79, 84, 84, 84, 77, 64, 42, 18, -6, -29, -49, -69, -82, + -87, -87, -78, -66, -48, -27, -4, 17, 33, 47, 56, 60, 58, 49, 31, 8, + -18, -36, -47, -57, -67, -75, -74, -60, -36, -3, 25, 48, 65, 76, 83, 87, + 90, 88, 77, 52, 24, -4, -26, -42, -61, -77, -91, -94, -85, -70, -54, -34, + -11, 12, 30, 44, 56, 63, 66, 61, 43, 19, -8, -27, -39, -49, -62, -74, + -80, -71, -49, -20, 9, 34, 56, 70, 79, 86, 93, 96, 91, 70, 41, 11, + -18, -39, -58, -77, -91, -99, -95, -83, -65, -42, -17, 7, 27, 43, 57, 66, + 69, 67, 55, 32, 5, -21, -32, -42, -56, -73, -84, -79, -60, -33, -5, 21, + 44, 61, 72, 80, 92, 100, 99, 82, 54, 23, -10, -31, -51, -71, -87, -101, + -101, -92, -76, -49, -24, 1, 21, 37, 52, 66, 72, 72, 64, 44, 18, -7, + -23, -31, -45, -64, -79, -83, -71, -46, -18, 7, 27, 46, 62, 72, 85, 97, + 100, 92, 65, 35, 2, -22, -40, -60, -78, -92, -100, -96, -82, -59, -29, -6, + 15, 28, 44, 57, 65, 67, 65, 49, 27, 2, -17, -23, -35, -53, -70, -79, + -73, -52, -27, -4, 16, 35, 54, 65, 77, 88, 95, 93, 73, 44, 12, -17, + -38, -54, -74, -86, -97, -98, -89, -69, -37, -11, 9, 27, 42, 56, 65, 68, + 71, 59, 39, 13, -9, -20, -30, -45, -62, -74, -75, -60, -41, -18, 3, 23, + 43, 60, 74, 83, 91, 91, 78, 52, 22, -8, -30, -46, -66, -82, -90, -92, + -85, -70, -44, -17, 5, 22, 33, 45, 56, 60, 63, 56, 39, 21, 5, -9, + -20, -33, -49, -62, -70, -62, -47, -28, -9, 11, 29, 47, 60, 73, 83, 87, + 81, 62, 32, 4, -21, -39, -60, -78, -88, -90, -86, -73, -55, -28, -2, 18, + 30, 42, 50, 57, 58, 53, 44, 27, 15, 4, -10, -24, -40, -53, -59, -57, + -49, -38, -21, -3, 17, 34, 49, 62, 75, 81, 76, 63, 39, 15, -11, -31, + -50, -69, -79, -84, -82, -73, -57, -34, -7, 12, 26, 35, 42, 50, 56, 53, + 42, 31, 20, 13, 1, -16, -30, -43, -50, -51, -49, -42, -28, -11, 7, 23, + 38, 52, 65, 75, 73, 62, 43, 20, -2, -24, -43, -60, -69, -74, -74, -69, + -59, -42, -19, 2, 19, 27, 34, 41, 48, 50, 45, 39, 33, 25, 13, -3, + -18, -32, -42, -47, -49, -47, -40, -27, -8, 11, 28, 43, 57, 69, 73, 65, + 50, 31, 8, -16, -36, -53, -63, -70, -72, -70, -62, -46, -25, -6, 11, 23, + 30, 38, 45, 49, 50, 46, 42, 33, 22, 6, -13, -25, -37, -43, -48, -50, + -45, -35, -18, 2, 21, 39, 51, 61, 64, 63, 53, 38, 19, -6, -30, -49, + -59, -63, -65, -66, -64, -52, -31, -14, 2, 13, 25, 35, 42, 46, 46, 47, + 48, 44, 33, 15, -6, -21, -32, -37, -42, -48, -46, -39, -26, -8, 12, 31, + 45, 55, 58, 57, 51, 39, 22, 2, -21, -39, -49, -56, -59, -62, -59, -52, + -38, -22, -9, 5, 16, 25, 32, 40, 46, 51, 54, 52, 40, 24, 5, -11, + -20, -28, -35, -44, -48, -43, -33, -17, 0, 18, 32, 44, 48, 49, 48, 40, + 28, 11, -10, -26, -37, -45, -52, -58, -57, -51, -41, -29, -19, -10, 3, 15, + 27, 36, 40, 50, 59, 60, 51, 33, 15, 2, -11, -21, -34, -45, -49, -45, + -36, -25, -11, 8, 26, 38, 43, 42, 41, 39, 31, 16, -5, -24, -31, -37, + -43, -51, -54, -49, -40, -31, -24, -13, -3, 12, 22, 29, 33, 43, 55, 60, + 53, 37, 18, 5, -4, -12, -23, -35, -44, -42, -35, -26, -15, -2, 15, 26, + 33, 31, 31, 29, 28, 21, 6, -13, -27, -30, -37, -44, -48, -45, -39, -34, + -28, -18, -8, 4, 17, 23, 31, 40, 51, 58, 56, 42, 25, 12, 2, -7, + -16, -27, -36, -39, -37, -31, -21, -12, 3, 14, 21, 25, 23, 23, 25, 23, + 11, -4, -16, -21, -26, -34, -39, -40, -34, -31, -30, -23, -17, -3, 9, 16, + 23, 31, 42, 54, 57, 49, 29, 14, 7, 4, -3, -15, -26, -32, -32, -31, + -24, -16, -5, 5, 8, 10, 9, 10, 16, 19, 14, 4, -8, -14, -16, -21, + -29, -34, -33, -30, -29, -26, -20, -10, 2, 11, 20, 28, 40, 51, 55, 51, + 33, 17, 9, 6, 4, -9, -20, -28, -32, -29, -25, -20, -11, -2, 3, 4, + 1, 6, 12, 18, 16, 8, -5, -10, -14, -17, -20, -23, -25, -26, -28, -26, + -21, -12, -2, 6, 13, 20, 29, 40, 48, 48, 37, 23, 13, 8, 7, 3, + -6, -15, -22, -24, -24, -21, -16, -10, -6, -11, -15, -10, 1, 12, 15, 9, + 4, 3, 1, -5, -11, -18, -18, -22, -25, -29, -27, -19, -7, 4, 10, 14, + 21, 35, 46, 48, 40, 27, 16, 13, 11, 11, 5, -5, -14, -19, -21, -24, + -19, -14, -13, -17, -21, -21, -11, 1, 11, 12, 5, 3, 2, 5, 6, 0, + -6, -16, -20, -25, -26, -20, -12, -4, 1, 5, 11, 25, 38, 46, 41, 33, + 21, 17, 15, 15, 14, 8, -3, -14, -23, -27, -26, -21, -20, -22, -26, -25, + -20, -7, 5, 10, 10, 8, 5, 6, 6, 5, 1, -7, -14, -20, -23, -21, + -17, -11, -4, 2, 7, 17, 29, 38, 40, 37, 30, 23, 21, 20, 17, 14, + 5, -6, -19, -26, -29, -25, -24, -27, -28, -28, -26, -18, -4, 6, 9, 8, + 4, 5, 10, 12, 11, 3, -8, -15, -18, -18, -15, -11, -10, -5, 1, 8, + 16, 26, 35, 35, 31, 24, 22, 21, 22, 21, 16, 5, -12, -24, -30, -31, + -29, -31, -32, -31, -32, -22, -12, 0, 7, 11, 12, 10, 11, 15, 13, 10, + 2, -10, -13, -16, -17, -14, -14, -12, -6, 0, 10, 20, 26, 32, 30, 29, + 27, 26, 28, 26, 22, 13, -2, -16, -25, -30, -32, -33, -35, -35, -34, -28, + -19, -12, -5, 1, 5, 9, 11, 16, 17, 18, 11, 3, -4, -10, -12, -13, + -12, -13, -14, -10, -4, 8, 20, 27, 31, 31, 28, 29, 31, 30, 26, 17, + 5, -9, -23, -32, -37, -36, -34, -35, -34, -32, -24, -16, -7, 2, 4, 6, + 10, 16, 17, 15, 12, 8, 3, -5, -11, -11, -10, -11, -12, -11, -5, 3, + 13, 22, 30, 32, 27, 25, 25, 28, 27, 19, 7, -8, -22, -31, -34, -32, + -30, -28, -31, -31, -29, -21, -12, -4, 1, 1, 3, 10, 16, 18, 18, 14, + 12, 3, -5, -8, -7, -8, -10, -12, -12, -5, 6, 16, 26, 30, 29, 24, + 25, 26, 29, 23, 13, -2, -16, -26, -32, -33, -30, -30, -30, -30, -29, -25, + -18, -12, -5, -2, 2, 8, 14, 18, 16, 18, 14, 10, 4, 0, -5, -4, + -7, -9, -14, -10, -3, 9, 19, 26, 26, 23, 23, 26, 29, 28, 21, 7, + -10, -19, -25, -26, -27, -27, -29, -30, -32, -31, -27, -19, -13, -9, -7, 0, + 9, 18, 24, 26, 21, 13, 9, 8, 4, -2, -6, -9, -11, -11, -7, 4, + 16, 24, 26, 21, 19, 22, 26, 29, 23, 7, -10, -17, -19, -19, -23, -25, + -25, -25, -26, -26, -29, -26, -17, -14, -9, -7, 1, 12, 21, 26, 23, 18, + 13, 11, 11, 6, -4, -6, -10, -10, -9, -2, 9, 20, 25, 23, 18, 18, + 23, 26, 24, 10, -5, -13, -17, -14, -15, -17, -20, -24, -25, -29, -31, -32, + -28, -22, -16, -13, -8, 2, 14, 25, 27, 27, 22, 17, 15, 13, 10, 5, + -3, -6, -8, -6, 1, 11, 18, 20, 13, 11, 15, 19, 20, 14, 4, -4, + -12, -12, -12, -12, -14, -17, -23, -30, -35, -37, -31, -26, -20, -16, -12, -4, + 9, 22, 28, 26, 22, 17, 14, 15, 11, 8, 6, 2, 0, -2, 4, 11, + 16, 16, 12, 7, 8, 13, 13, 10, 1, -5, -8, -8, -8, -7, -7, -10, + -20, -26, -34, -36, -33, -31, -29, -25, -19, -12, 4, 18, 27, 28, 23, 22, + 18, 19, 17, 14, 9, 7, 4, 0, 2, 8, 14, 16, 12, 2, 0, 2, + 5, 6, 2, -4, -7, -6, -2, -2, -3, -5, -11, -19, -28, -37, -37, -37, + -34, -29, -24, -18, -8, 7, 20, 25, 25, 25, 22, 21, 21, 21, 19, 15, + 11, 6, 6, 6, 10, 11, 6, -2, -5, -5, -2, 0, 0, 0, -4, 0, + 2, 4, 2, -2, -8, -16, -25, -34, -39, -42, -39, -33, -26, -21, -16, -4, + 11, 22, 25, 27, 25, 23, 23, 24, 25, 22, 17, 13, 10, 9, 12, 10, + 4, -5, -12, -12, -11, -9, -8, -6, -5, 1, 4, 8, 10, 7, 4, -7, + -18, -26, -34, -39, -43, -42, -34, -28, -22, -13, 2, 14, 18, 21, 23, 27, + 30, 32, 31, 28, 23, 20, 20, 15, 14, 10, 2, -5, -13, -15, -16, -16, + -12, -12, -5, 1, 5, 8, 8, 10, 8, 0, -13, -23, -27, -33, -40, -44, + -41, -32, -24, -17, -6, 3, 9, 17, 22, 25, 29, 34, 39, 36, 32, 26, + 25, 23, 19, 11, 1, -9, -16, -18, -17, -19, -21, -17, -8, 0, 4, 7, + 8, 10, 11, 6, -4, -13, -21, -25, -35, -40, -41, -37, -26, -21, -13, -8, + -3, 6, 15, 23, 27, 35, 40, 41, 38, 33, 31, 29, 24, 16, 5, -5, + -16, -23, -23, -23, -18, -14, -6, 2, 3, 4, 7, 11, 13, 7, -5, -13, + -21, -25, -32, -40, -42, -37, -28, -21, -14, -13, -9, 1, 11, 22, 27, 33, + 39, 43, 42, 41, 33, 29, 25, 18, 7, -6, -17, -25, -24, -23, -21, -16, + -9, 2, 6, 5, 5, 10, 15, 12, 3, -8, -16, -22, -29, -39, -44, -42, + -34, -27, -22, -21, -17, -8, 4, 19, 29, 40, 48, 53, 51, 49, 43, 38, + 28, 19, 6, -9, -19, -27, -30, -30, -24, -16, -10, -3, 3, 6, 5, 6, + 9, 11, 7, 2, -7, -16, -25, -34, -37, -37, -33, -31, -28, -27, -24, -20, + -10, 8, 22, 35, 46, 52, 53, 54, 49, 46, 37, 23, 9, -7, -18, -24, + -30, -32, -28, -22, -12, -5, 1, 6, 4, 8, 9, 11, 9, 3, -3, -13, + -21, -32, -37, -38, -35, -34, -32, -32, -32, -27, -14, 5, 24, 38, 48, 55, + 56, 56, 54, 50, 40, 23, 4, -10, -18, -24, -26, -29, -29, -24, -17, -5, + 2, 9, 9, 6, 6, 7, 12, 11, 6, -7, -18, -30, -36, -36, -37, -35, + -38, -40, -41, -36, -24, -2, 20, 35, 47, 55, 60, 62, 62, 61, 47, 26, + 7, -12, -18, -22, -24, -28, -33, -31, -24, -12, -2, 7, 9, 5, 4, 5, + 11, 14, 13, 7, -8, -24, -37, -41, -38, -34, -37, -44, -50, -46, -33, -10, + 16, 36, 49, 57, 61, 64, 66, 65, 55, 34, 11, -14, -24, -26, -26, -24, + -30, -34, -33, -24, -7, 5, 12, 10, 5, 6, 9, 16, 22, 21, 10, -10, + -32, -45, -44, -38, -38, -47, -61, -60, -48, -21, 11, 34, 51, 60, 63, 66, + 70, 69, 63, 45, 18, -10, -27, -27, -23, -20, -28, -36, -37, -32, -17, -2, + 8, 9, 5, 6, 8, 15, 24, 30, 25, 5, -22, -41, -44, -40, -38, -50, + -64, -72, -62, -37, -3, 29, 52, 62, 66, 69, 73, 78, 72, 54, 26, -5, + -25, -32, -29, -24, -27, -34, -37, -36, -26, -11, 5, 15, 15, 11, 9, 15, + 26, 35, 33, 14, -14, -37, -49, -47, -45, -51, -63, -72, -66, -42, -10, 22, + 49, 64, 69, 69, 70, 75, 73, 59, 34, 4, -20, -30, -30, -25, -24, -29, + -36, -40, -35, -22, -2, 16, 20, 17, 14, 15, 27, 39, 41, 27, -4, -32, + -48, -54, -53, -59, -65, -73, -71, -55, -23, 16, 49, 67, 70, 68, 71, 77, + 78, 65, 40, 10, -17, -31, -34, -28, -24, -26, -31, -40, -40, -30, -10, 10, + 21, 18, 15, 16, 26, 40, 48, 40, 13, -20, -44, -55, -61, -63, -69, -76, + -76, -63, -35, 6, 41, 66, 75, 71, 71, 75, 77, 67, 44, 17, -10, -25, + -34, -35, -29, -27, -28, -35, -40, -35, -18, 1, 16, 21, 20, 19, 25, 38, + 47, 43, 23, -9, -34, -50, -59, -65, -72, -76, -74, -66, -43, -9, 27, 58, + 71, 69, 70, 71, 73, 67, 48, 25, 2, -18, -28, -33, -29, -25, -25, -31, + -39, -41, -28, -10, 8, 19, 20, 23, 27, 36, 45, 45, 31, 4, -22, -45, + -58, -67, -74, -75, -73, -66, -50, -21, 16, 49, 67, 73, 72, 72, 74, 69, + 53, 33, 9, -11, -25, -34, -35, -31, -27, -30, -38, -43, -33, -16, 6, 18, + 24, 27, 30, 38, 45, 46, 34, 10, -16, -40, -61, -70, -77, -76, -72, -66, + -52, -31, 2, 36, 60, 71, 72, 69, 71, 68, 57, 44, 20, 2, -17, -32, + -36, -33, -31, -31, -40, -46, -41, -29, -5, 16, 27, 34, 35, 41, 49, 51, + 41, 17, -11, -34, -56, -71, -79, -80, -76, -68, -57, -36, -10, 21, 48, 64, + 71, 71, 73, 69, 61, 48, 32, 11, -5, -21, -31, -34, -34, -37, -43, -48, + -45, -34, -14, 8, 25, 34, 41, 43, 49, 51, 43, 26, -2, -27, -49, -65, + -74, -77, -74, -70, -58, -42, -20, 9, 38, 56, 64, 67, 69, 71, 66, 53, + 37, 16, 1, -15, -30, -33, -39, -38, -41, -45, -42, -35, -15, 7, 25, 36, + 41, 45, 49, 49, 40, 23, 1, -20, -41, -59, -71, -75, -73, -65, -57, -45, + -28, -6, 22, 42, 56, 63, 67, 71, 70, 59, 44, 28, 12, -3, -19, -32, + -40, -41, -46, -47, -46, -37, -20, -2, 20, 34, 45, 48, 52, 53, 42, 26, + 4, -15, -35, -51, -65, -70, -70, -68, -61, -50, -34, -15, 9, 28, 45, 54, + 64, 71, 72, 67, 53, 40, 24, 8, -10, -27, -37, -41, -49, -53, -53, -42, + -25, -8, 14, 31, 43, 52, 56, 56, 46, 30, 11, -8, -26, -43, -59, -70, + -69, -68, -62, -55, -44, -25, -4, 17, 36, 48, 62, 69, 69, 67, 57, 47, + 33, 17, -2, -21, -33, -41, -47, -52, -53, -43, -25, -10, 9, 23, 36, 46, + 52, 54, 47, 31, 14, -4, -19, -32, -49, -57, -62, -60, -57, -58, -51, -39, + -19, 6, 23, 38, 51, 60, 68, 71, 67, 58, 44, 27, 7, -17, -32, -41, + -47, -52, -54, -46, -31, -12, 7, 22, 35, 45, 51, 53, 46, 33, 18, 2, + -12, -26, -42, -55, -61, -60, -56, -57, -55, -46, -29, -8, 10, 27, 42, 55, + 65, 70, 69, 61, 49, 34, 16, -5, -23, -36, -45, -51, -54, -50, -35, -17, + 3, 17, 29, 37, 44, 51, 47, 39, 21, 6, -8, -20, -31, -44, -52, -58, + -60, -58, -58, -51, -39, -22, -4, 14, 31, 48, 62, 70, 69, 65, 57, 45, + 28, 7, -15, -31, -44, -50, -53, -50, -39, -24, -6, 11, 24, 33, 43, 46, + 45, 35, 25, 14, 1, -13, -23, -35, -44, -53, -57, -59, -59, -57, -47, -33, + -15, 3, 21, 39, 56, 69, 72, 69, 60, 49, 36, 17, -5, -25, -42, -52, + -52, -48, -40, -26, -9, 9, 20, 29, 34, 39, 40, 34, 25, 16, 6, -6, + -16, -27, -34, -44, -50, -55, -58, -57, -52, -41, -27, -11, 11, 31, 51, 67, + 70, 68, 61, 53, 43, 30, 7, -14, -35, -49, -54, -50, -40, -26, -13, -2, + 9, 22, 30, 38, 41, 36, 28, 20, 12, 4, -5, -15, -26, -41, -52, -58, + -60, -60, -59, -55, -41, -25, -5, 19, 42, 62, 74, 75, 70, 63, 55, 43, + 22, -3, -24, -42, -51, -50, -45, -32, -22, -14, -2, 14, 28, 35, 34, 33, + 30, 25, 21, 11, 4, -6, -18, -32, -46, -56, -61, -61, -62, -60, -51, -39, + -16, 11, 37, 58, 70, 75, 72, 67, 58, 46, 31, 10, -17, -35, -48, -49, + -41, -28, -17, -14, -7, 4, 18, 28, 32, 29, 27, 21, 19, 16, 7, 2, + -11, -22, -35, -48, -57, -61, -60, -60, -56, -47, -30, -5, 23, 48, 63, 72, + 75, 71, 64, 53, 39, 20, -2, -22, -40, -48, -45, -34, -21, -17, -10, -4, + 10, 22, 27, 28, 29, 26, 26, 22, 14, 7, -3, -14, -30, -46, -59, -65, + -65, -65, -64, -56, -41, -17, 15, 42, 62, 73, 77, 75, 69, 57, 43, 25, + 6, -12, -31, -44, -46, -37, -24, -16, -11, -3, 6, 20, 24, 23, 24, 23, + 25, 23, 16, 9, 1, -10, -23, -41, -56, -63, -67, -67, -66, -59, -47, -25, + 3, 32, 54, 70, 75, 76, 70, 62, 47, 32, 15, -3, -21, -38, -44, -41, + -31, -21, -15, -11, -2, 8, 18, 24, 27, 28, 29, 29, 24, 17, 8, -2, + -17, -35, -54, -66, -73, -74, -71, -66, -55, -35, -6, 24, 50, 69, 77, 79, + 74, 63, 51, 38, 22, 2, -17, -35, -42, -39, -32, -24, -17, -11, -5, 6, + 13, 20, 28, 31, 33, 29, 23, 15, 10, 3, -12, -30, -51, -65, -73, -75, + -71, -67, -58, -41, -18, 11, 38, 60, 75, 77, 74, 64, 53, 42, 31, 15, + -7, -25, -38, -40, -37, -29, -24, -15, -11, -2, 9, 17, 28, 33, 36, 33, + 27, 18, 13, 4, -8, -26, -48, -65, -75, -76, -72, -68, -58, -43, -18, 11, + 37, 58, 72, 76, 73, 63, 51, 40, 28, 13, -6, -23, -35, -41, -40, -33, + -24, -16, -9, -2, 7, 18, 29, 38, 42, 38, 31, 21, 11, 3, -10, -26, + -47, -65, -75, -79, -75, -69, -58, -39, -19, 7, 33, 54, 71, 77, 75, 66, + 52, 39, 27, 15, -2, -22, -35, -41, -41, -36, -27, -17, -8, 1, 11, 22, + 33, 41, 47, 45, 35, 21, 11, 4, -7, -24, -46, -66, -77, -81, -79, -73, + -62, -44, -24, -2, 23, 47, 69, 79, 79, 70, 57, 45, 33, 20, 5, -18, + -36, -43, -41, -37, -32, -23, -14, -3, 8, 20, 34, 45, 53, 52, 41, 27, + 16, 7, -5, -24, -47, -69, -83, -86, -84, -74, -62, -44, -22, 1, 24, 47, + 66, 78, 76, 69, 57, 43, 31, 17, 5, -13, -33, -43, -46, -41, -31, -22, + -12, 0, 11, 24, 39, 49, 57, 58, 48, 30, 15, 4, -8, -26, -52, -74, + -86, -89, -83, -74, -60, -43, -21, 1, 22, 45, 65, 78, 79, 68, 54, 40, + 26, 17, 7, -9, -31, -45, -46, -40, -31, -21, -11, 0, 8, 21, 39, 51, + 60, 60, 52, 36, 19, 4, -9, -25, -49, -71, -87, -92, -89, -79, -63, -45, + -24, 0, 22, 43, 65, 75, 80, 70, 57, 44, 30, 16, 2, -14, -31, -46, + -52, -47, -35, -21, -9, 1, 12, 26, 44, 59, 68, 68, 59, 42, 22, 6, + -11, -29, -49, -72, -87, -96, -95, -86, -67, -46, -23, -4, 16, 38, 59, 76, + 82, 74, 61, 45, 31, 20, 3, -14, -30, -44, -51, -51, -41, -26, -11, 3, + 13, 25, 44, 61, 71, 72, 59, 45, 28, 9, -10, -33, -53, -70, -83, -93, + -96, -91, -74, -53, -27, -6, 15, 35, 53, 71, 80, 77, 66, 51, 34, 20, + 3, -15, -30, -45, -53, -55, -48, -32, -17, 1, 16, 29, 47, 62, 73, 77, + 67, 50, 30, 9, -10, -32, -55, -73, -86, -93, -94, -90, -76, -54, -27, -4, + 17, 32, 48, 64, 74, 78, 68, 55, 38, 17, 1, -15, -28, -39, -47, -52, + -49, -37, -21, -3, 16, 31, 46, 61, 70, 75, 70, 55, 36, 13, -9, -32, + -56, -72, -84, -89, -93, -91, -81, -61, -30, -5, 18, 32, 45, 58, 71, 76, + 70, 57, 40, 18, 1, -17, -28, -35, -45, -52, -50, -39, -25, -7, 15, 33, + 48, 60, 67, 73, 70, 60, 42, 19, -8, -34, -57, -69, -77, -83, -87, -92, + -85, -66, -39, -10, 12, 27, 39, 52, 62, 73, 72, 61, 46, 25, 4, -14, + -27, -34, -41, -46, -48, -43, -30, -11, 14, 38, 53, 63, 66, 69, 72, 65, + 48, 23, -4, -31, -56, -72, -81, -83, -87, -91, -87, -72, -46, -15, 11, 28, + 40, 50, 60, 71, 75, 69, 54, 32, 8, -13, -29, -39, -45, -48, -50, -48, + -40, -21, 9, 37, 57, 66, 71, 74, 75, 71, 55, 32, 2, -29, -55, -73, + -81, -84, -87, -89, -88, -75, -49, -19, 10, 29, 39, 48, 53, 62, 72, 68, + 58, 35, 9, -11, -27, -34, -39, -42, -44, -46, -41, -26, 5, 35, 56, 65, + 69, 72, 73, 72, 59, 37, 9, -22, -50, -71, -83, -83, -83, -86, -88, -81, + -55, -24, 5, 24, 37, 48, 54, 59, 64, 66, 59, 41, 17, -9, -27, -36, + -38, -39, -42, -45, -41, -28, -2, 28, 53, 65, 68, 71, 71, 70, 58, 40, + 16, -14, -46, -67, -79, -81, -80, -83, -87, -83, -64, -36, -4, 19, 35, 46, + 51, 58, 65, 69, 64, 49, 26, -2, -25, -38, -41, -39, -40, -43, -45, -33, + -8, 24, 52, 65, 72, 74, 72, 66, 55, 40, 20, -7, -38, -65, -80, -85, + -80, -82, -84, -82, -65, -38, -9, 13, 29, 41, 49, 57, 62, 64, 59, 48, + 29, 6, -19, -36, -39, -37, -35, -38, -39, -31, -11, 19, 47, 63, 70, 71, + 71, 65, 55, 38, 17, -4, -33, -58, -76, -83, -79, -79, -80, -82, -70, -46, + -19, 8, 25, 36, 43, 51, 59, 63, 62, 50, 34, 14, -9, -27, -35, -38, + -36, -38, -39, -30, -15, 10, 34, 52, 67, 73, 74, 68, 54, 37, 21, 2, + -21, -45, -68, -78, -81, -81, -80, -79, -70, -51, -28, -4, 17, 32, 40, 48, + 56, 59, 57, 46, 34, 18, 3, -20, -34, -39, -35, -31, -30, -26, -13, 8, + 31, 48, 61, 67, 69, 66, 53, 38, 16, -4, -23, -41, -58, -72, -78, -80, + -76, -74, -64, -50, -33, -8, 12, 28, 35, 41, 50, 57, 53, 44, 31, 20, + 10, -8, -24, -34, -34, -30, -25, -21, -13, 5, 22, 38, 52, 61, 66, 65, + 53, 36, 15, -4, -18, -33, -45, -61, -73, -79, -78, -72, -62, -49, -33, -13, + 3, 19, 29, 38, 48, 52, 49, 41, 29, 22, 14, 2, -11, -25, -27, -25, + -20, -15, -8, 4, 19, 30, 42, 53, 57, 61, 50, 32, 15, -7, -18, -27, + -37, -50, -65, -73, -72, -66, -57, -49, -37, -19, -3, 13, 23, 32, 41, 44, + 41, 35, 29, 26, 21, 10, -2, -13, -21, -18, -14, -8, -4, 3, 12, 21, + 29, 42, 51, 54, 49, 32, 14, -5, -15, -22, -28, -39, -55, -69, -68, -62, + -52, -44, -37, -25, -11, 4, 16, 24, 32, 37, 35, 28, 23, 23, 23, 18, + 8, -4, -12, -12, -8, -2, 5, 9, 14, 18, 23, 31, 41, 45, 43, 29, + 11, -8, -18, -23, -21, -29, -43, -60, -65, -58, -50, -39, -32, -26, -17, -6, + 8, 18, 25, 31, 29, 24, 17, 20, 24, 25, 19, 8, 0, -5, -3, 4, + 11, 13, 12, 14, 16, 22, 31, 38, 37, 27, 9, -11, -22, -24, -22, -25, + -36, -50, -57, -53, -46, -37, -30, -24, -17, -9, 1, 10, 16, 20, 19, 17, + 13, 14, 21, 24, 24, 19, 10, 8, 9, 13, 18, 20, 15, 12, 11, 14, + 21, 27, 30, 21, 8, -12, -23, -24, -22, -20, -29, -40, -49, -47, -41, -33, + -26, -23, -20, -16, -11, -2, 7, 12, 14, 14, 13, 14, 19, 26, 30, 26, + 20, 11, 11, 16, 21, 26, 22, 18, 15, 14, 15, 19, 20, 16, 4, -15, + -29, -32, -27, -21, -24, -34, -40, -41, -33, -28, -24, -21, -20, -15, -14, -10, + -5, 1, 7, 10, 10, 12, 18, 26, 36, 34, 27, 21, 17, 20, 23, 25, + 24, 19, 11, 10, 9, 12, 16, 14, 3, -16, -32, -34, -27, -19, -20, -27, + -34, -35, -31, -27, -22, -18, -18, -19, -19, -20, -15, -7, 2, 6, 8, 9, + 18, 26, 38, 41, 37, 28, 21, 23, 25, 27, 25, 20, 13, 7, 3, 5, + 9, 11, 4, -14, -31, -35, -29, -20, -18, -23, -26, -32, -29, -25, -23, -15, + -17, -18, -21, -25, -23, -15, -6, 0, 5, 6, 16, 25, 37, 45, 43, 36, + 27, 25, 28, 30, 29, 26, 16, 7, -2, -2, 2, 3, -2, -15, -31, -38, + -35, -23, -15, -15, -19, -23, -26, -23, -21, -15, -12, -18, -24, -27, -25, -19, + -9, -3, 2, 5, 12, 19, 32, 42, 45, 41, 31, 28, 31, 33, 37, 33, + 26, 14, 4, -2, -3, -3, -5, -18, -34, -43, -42, -31, -20, -18, -17, -19, + -18, -16, -13, -9, -8, -13, -22, -32, -32, -28, -19, -11, -6, -2, 7, 18, + 31, 42, 46, 46, 41, 36, 32, 35, 39, 39, 30, 17, 5, -3, -3, -3, + -7, -19, -32, -39, -41, -36, -26, -17, -12, -13, -18, -20, -14, -7, -6, -11, + -23, -32, -34, -28, -23, -15, -9, -2, 9, 17, 28, 37, 44, 48, 45, 38, + 32, 35, 41, 45, 37, 23, 10, 1, -3, -5, -8, -20, -35, -44, -44, -42, + -34, -24, -14, -10, -12, -14, -11, -6, -2, -5, -15, -25, -32, -29, -24, -19, + -15, -10, 1, 10, 20, 31, 40, 45, 48, 43, 39, 39, 45, 51, 43, 28, + 15, 2, -4, -8, -13, -20, -34, -42, -45, -45, -36, -26, -13, -8, -11, -13, + -8, -2, 1, -4, -13, -22, -30, -33, -28, -25, -18, -12, -5, 3, 13, 25, + 37, 46, 47, 45, 40, 41, 47, 53, 49, 35, 21, 10, 2, -6, -11, -22, + -32, -43, -50, -50, -47, -34, -17, -9, -9, -12, -9, 3, 7, 4, -8, -18, + -25, -31, -31, -27, -21, -16, -11, -8, 2, 17, 31, 45, 47, 44, 40, 43, + 54, 60, 58, 42, 26, 14, 4, -5, -14, -26, -37, -47, -54, -53, -49, -38, + -22, -13, -9, -7, -3, 6, 11, 6, -5, -14, -22, -28, -31, -30, -29, -24, + -18, -15, -2, 14, 29, 42, 45, 47, 45, 48, 56, 63, 59, 46, 29, 17, + 5, -4, -11, -23, -36, -49, -53, -52, -48, -40, -29, -21, -16, -11, -2, 5, + 6, 3, -5, -10, -13, -17, -21, -25, -26, -23, -19, -15, -8, 5, 20, 31, + 38, 42, 41, 46, 55, 62, 63, 50, 36, 24, 12, 5, -7, -20, -33, -46, + -51, -51, -48, -40, -33, -27, -20, -15, 0, 9, 7, 1, -6, -10, -11, -16, + -22, -25, -30, -28, -25, -21, -11, 2, 17, 28, 32, 41, 47, 55, 64, 66, + 64, 54, 41, 32, 19, 4, -9, -24, -37, -48, -54, -55, -51, -41, -33, -29, + -24, -15, 0, 13, 14, 8, 1, -5, -6, -10, -17, -24, -30, -32, -33, -32, + -22, -9, 9, 21, 25, 35, 45, 56, 67, 71, 71, 63, 49, 37, 25, 11, + -5, -19, -32, -45, -54, -59, -54, -43, -36, -31, -27, -18, -3, 11, 13, 9, + 2, -3, -6, -9, -13, -20, -25, -29, -33, -30, -23, -9, 2, 11, 19, 28, + 40, 51, 63, 68, 71, 66, 55, 44, 31, 16, 1, -15, -30, -41, -50, -57, + -56, -46, -37, -32, -30, -21, -7, 8, 17, 12, 5, 3, -2, -6, -11, -19, + -23, -27, -33, -34, -28, -19, -6, 3, 13, 24, 38, 51, 62, 70, 72, 68, + 60, 48, 38, 22, 6, -13, -27, -39, -46, -53, -52, -48, -42, -37, -36, -25, + -9, 4, 11, 9, 7, 8, 6, 2, -6, -13, -20, -24, -28, -31, -30, -27, + -19, -10, 4, 19, 33, 45, 57, 67, 74, 74, 70, 60, 47, 31, 10, -8, + -25, -36, -42, -51, -56, -56, -51, -40, -35, -28, -16, -4, 7, 7, 10, 12, + 13, 11, 3, -8, -18, -21, -25, -29, -33, -33, -30, -20, -8, 11, 27, 42, + 54, 64, 72, 77, 76, 69, 56, 34, 14, -5, -20, -32, -43, -50, -57, -59, + -57, -47, -39, -31, -17, -5, 6, 8, 9, 17, 19, 16, 5, -9, -13, -18, + -21, -26, -33, -37, -35, -28, -15, 1, 18, 34, 47, 58, 68, 76, 77, 76, + 65, 47, 25, 6, -12, -24, -37, -49, -57, -62, -64, -58, -50, -40, -24, -12, + 3, 9, 13, 22, 26, 26, 17, 4, -9, -21, -25, -30, -36, -41, -44, -41, + -27, -8, 12, 31, 44, 57, 68, 77, 81, 80, 72, 56, 34, 12, -6, -19, + -30, -41, -53, -65, -68, -65, -56, -44, -30, -17, -8, 2, 10, 23, 31, 32, + 25, 10, -4, -14, -20, -25, -31, -39, -45, -45, -35, -17, 2, 22, 37, 51, + 63, 72, 79, 78, 74, 62, 43, 20, 2, -12, -24, -34, -49, -61, -69, -70, + -63, -48, -35, -23, -11, 0, 9, 20, 31, 36, 32, 20, 7, -9, -18, -24, + -30, -38, -47, -50, -44, -29, -9, 10, 27, 45, 60, 71, 78, 80, 78, 68, + 54, 33, 13, -5, -18, -29, -44, -57, -68, -74, -66, -54, -41, -30, -18, -5, + 8, 19, 26, 33, 32, 24, 13, -4, -15, -22, -24, -29, -40, -44, -42, -29, + -14, 0, 15, 31, 48, 63, 69, 74, 74, 72, 64, 47, 27, 11, -4, -17, + -33, -50, -66, -78, -78, -68, -54, -38, -25, -11, 4, 18, 31, 38, 40, 34, + 21, 5, -12, -23, -28, -34, -43, -50, -51, -39, -22, -6, 10, 26, 46, 61, + 70, 75, 79, 76, 67, 52, 34, 18, 4, -11, -27, -45, -63, -76, -78, -70, + -57, -44, -29, -15, 0, 14, 26, 35, 39, 34, 23, 9, -7, -18, -23, -30, + -40, -49, -51, -41, -24, -9, 5, 19, 39, 55, 67, 74, 77, 79, 72, 56, + 39, 24, 12, -5, -23, -42, -60, -73, -78, -74, -62, -48, -33, -18, -6, 10, + 25, 34, 37, 34, 26, 16, -2, -15, -23, -28, -32, -42, -46, -44, -31, -16, + -4, 11, 28, 44, 56, 64, 69, 75, 73, 63, 50, 37, 22, 6, -10, -27, + -47, -68, -81, -80, -68, -52, -39, -25, -13, 2, 17, 29, 36, 37, 32, 23, + 4, -14, -24, -26, -26, -36, -44, -45, -36, -20, -7, 9, 25, 38, 49, 58, + 66, 75, 77, 67, 52, 39, 26, 14, -3, -21, -43, -65, -81, -84, -74, -56, + -40, -27, -15, -2, 15, 27, 37, 38, 35, 26, 8, -11, -23, -26, -27, -34, + -42, -45, -40, -27, -13, 4, 19, 33, 45, 54, 60, 67, 72, 67, 57, 44, + 32, 20, 5, -11, -32, -55, -72, -82, -76, -62, -46, -31, -21, -5, 6, 19, + 29, 34, 33, 26, 12, -6, -17, -22, -23, -28, -38, -42, -38, -27, -14, 1, + 14, 27, 40, 48, 53, 62, 68, 67, 58, 44, 32, 21, 9, -5, -22, -43, + -63, -76, -75, -62, -46, -30, -24, -13, 0, 10, 20, 28, 31, 27, 12, -5, + -16, -20, -19, -21, -29, -35, -35, -27, -16, -6, 9, 21, 33, 41, 47, 53, + 61, 63, 60, 51, 39, 27, 15, 3, -13, -33, -55, -72, -75, -67, -52, -37, + -26, -18, -7, 4, 15, 26, 27, 25, 14, 0, -10, -15, -16, -19, -24, -31, + -32, -27, -17, -5, 5, 15, 26, 35, 43, 49, 54, 57, 57, 52, 42, 29, + 18, 10, -3, -23, -46, -64, -71, -66, -53, -39, -27, -19, -11, 0, 5, 16, + 22, 23, 15, 1, -10, -15, -18, -17, -17, -20, -24, -22, -14, -4, 7, 16, + 25, 31, 36, 41, 47, 49, 49, 46, 41, 32, 21, 13, 3, -14, -33, -51, + -60, -60, -52, -39, -28, -20, -14, -7, 1, 9, 14, 16, 10, 1, -10, -15, + -14, -15, -15, -15, -17, -14, -11, -4, 5, 13, 22, 29, 33, 35, 39, 43, + 45, 45, 42, 35, 26, 17, 7, -10, -25, -38, -48, -53, -53, -46, -33, -23, + -16, -13, -8, -3, 4, 9, 7, 1, -6, -10, -13, -12, -12, -8, -7, -6, + -2, 3, 6, 10, 14, 23, 28, 29, 30, 29, 34, 39, 40, 36, 30, 21, + 13, 1, -15, -27, -36, -44, -48, -45, -36, -26, -17, -13, -10, -6, -2, 2, + 3, -3, -6, -10, -14, -13, -12, -7, -3, 1, 2, 5, 6, 10, 15, 19, + 25, 25, 26, 26, 29, 34, 35, 32, 29, 20, 13, 4, -12, -20, -27, -33, + -38, -41, -36, -27, -19, -13, -10, -8, -8, -7, -5, -5, -7, -9, -13, -18, + -15, -12, -5, 3, 7, 10, 10, 11, 13, 20, 27, 27, 23, 20, 20, 24, + 27, 25, 26, 23, 17, 7, -6, -13, -16, -20, -26, -32, -33, -28, -20, -13, + -12, -12, -16, -15, -15, -12, -10, -13, -13, -16, -12, -7, 0, 9, 14, 18, + 18, 14, 11, 14, 18, 21, 17, 10, 11, 15, 20, 21, 20, 20, 17, 9, + 2, -5, -10, -14, -21, -25, -29, -27, -23, -17, -13, -13, -16, -18, -20, -20, + -12, -8, -9, -15, -16, -10, -2, 9, 14, 18, 18, 18, 14, 14, 17, 20, + 18, 12, 8, 11, 13, 16, 18, 19, 16, 9, 3, 1, 1, -6, -13, -20, + -23, -21, -19, -15, -15, -14, -17, -21, -22, -22, -17, -11, -11, -13, -18, -14, + -4, 12, 21, 22, 23, 21, 20, 17, 16, 16, 12, 7, 1, 5, 7, 8, + 12, 15, 15, 10, 3, 0, 3, 1, -5, -12, -19, -19, -16, -11, -9, -11, + -14, -23, -28, -29, -24, -17, -13, -15, -19, -18, -10, 7, 22, 29, 30, 24, + 22, 18, 17, 17, 11, 4, -2, -3, 2, 4, 8, 13, 16, 13, 7, 4, + 9, 8, 2, -7, -16, -15, -14, -12, -10, -12, -12, -19, -25, -29, -25, -18, + -15, -18, -21, -19, -12, 1, 16, 28, 34, 32, 29, 23, 18, 15, 11, 4, + -3, -10, -8, -5, 0, 7, 12, 14, 10, 6, 10, 15, 13, 3, -7, -11, + -13, -13, -13, -12, -14, -20, -28, -31, -29, -20, -13, -14, -18, -18, -15, -3, + 12, 24, 33, 32, 29, 25, 22, 16, 11, 3, -3, -6, -7, -8, -3, 2, + 8, 11, 11, 9, 10, 13, 13, 8, 0, -6, -9, -9, -9, -10, -11, -18, + -26, -30, -29, -22, -17, -18, -20, -21, -17, -7, 6, 21, 34, 38, 34, 29, + 21, 17, 13, 8, 1, -8, -13, -15, -10, -3, 5, 10, 11, 10, 11, 15, + 16, 11, 3, -4, -7, -9, -8, -10, -13, -19, -26, -26, -23, -17, -15, -16, + -17, -17, -15, -9, -2, 10, 26, 31, 31, 24, 21, 18, 13, 6, 1, -6, + -8, -9, -8, -4, 0, 6, 10, 12, 15, 14, 13, 9, 5, -2, -7, -8, + -9, -8, -10, -18, -25, -25, -23, -18, -16, -19, -22, -18, -16, -10, 0, 10, + 24, 33, 35, 29, 22, 17, 13, 7, -3, -8, -12, -14, -12, -7, -3, 4, + 10, 14, 16, 17, 16, 16, 11, 3, -7, -11, -10, -7, -10, -19, -26, -27, + -23, -17, -14, -14, -17, -18, -16, -12, -3, 7, 20, 26, 28, 24, 20, 16, + 15, 10, 2, -8, -13, -11, -7, -2, -2, 4, 6, 9, 14, 17, 19, 15, + 8, -4, -12, -15, -11, -5, -8, -18, -25, -24, -17, -9, -6, -7, -11, -15, + -15, -13, -6, 4, 11, 15, 16, 15, 16, 13, 9, 5, 1, -3, -7, -5, + -2, 3, 5, 6, 8, 10, 14, 17, 18, 14, 3, -8, -15, -13, -9, -6, + -9, -19, -22, -19, -13, -6, -4, -5, -8, -13, -15, -10, -5, 5, 8, 8, + 8, 11, 14, 14, 8, 2, 1, 1, 2, -2, 1, 5, 6, 7, 7, 6, + 11, 13, 16, 13, 3, -6, -13, -14, -8, -5, -6, -15, -20, -15, -10, -5, + -2, -6, -6, -8, -12, -10, -8, -3, 5, 3, 3, 5, 7, 10, 6, 2, + -3, -2, 2, 8, 9, 12, 11, 8, 9, 8, 11, 13, 11, 10, 0, -12, + -20, -21, -13, -10, -11, -14, -16, -10, -3, 4, 8, 5, 2, -2, -4, -4, + -7, -4, -4, -5, -7, -8, -5, 0, 2, 2, 0, 1, 6, 11, 15, 19, + 19, 18, 14, 10, 12, 12, 11, 6, -6, -16, -23, -23, -17, -13, -12, -12, + -13, -8, -2, 8, 13, 13, 8, 4, 1, -3, -3, -3, -4, -11, -16, -16, + -13, -9, -5, -4, -2, 1, 6, 13, 17, 21, 24, 23, 18, 14, 10, 11, + 12, 8, -3, -16, -26, -27, -20, -17, -21, -21, -17, -7, 2, 10, 16, 19, + 18, 13, 10, 5, 2, -2, -5, -14, -22, -26, -21, -15, -11, -11, -6, -2, + 6, 16, 22, 27, 28, 28, 23, 17, 13, 10, 12, 7, -4, -18, -29, -32, + -24, -20, -21, -22, -18, -5, 5, 14, 19, 21, 20, 17, 13, 8, 5, -2, + -9, -18, -26, -26, -21, -14, -12, -11, -8, -2, 10, 16, 21, 24, 25, 27, + 24, 16, 11, 6, 7, 6, -4, -16, -25, -29, -25, -19, -19, -22, -18, -7, + 6, 15, 17, 18, 19, 18, 15, 10, 8, 3, -5, -15, -24, -30, -27, -19, + -15, -15, -13, -8, 5, 14, 20, 25, 28, 31, 30, 26, 18, 11, 9, 7, + -2, -14, -27, -33, -30, -25, -25, -27, -26, -15, 2, 17, 22, 23, 23, 22, + 22, 18, 14, 7, -4, -14, -24, -31, -30, -25, -19, -16, -16, -11, -3, 8, + 17, 24, 29, 31, 31, 29, 22, 17, 12, 8, 2, -12, -26, -36, -35, -30, + -26, -26, -29, -20, -5, 13, 24, 26, 26, 26, 28, 23, 19, 11, 1, -9, + -24, -34, -33, -30, -24, -21, -21, -17, -11, 1, 9, 19, 27, 33, 34, 30, + 28, 24, 21, 16, 7, -6, -23, -35, -40, -36, -33, -31, -32, -27, -13, 3, + 17, 25, 29, 34, 34, 30, 23, 17, 11, 0, -14, -27, -32, -33, -30, -26, + -21, -18, -15, -9, 1, 11, 22, 29, 32, 33, 30, 28, 23, 21, 13, 3, + -15, -30, -37, -38, -35, -35, -33, -28, -18, -5, 10, 22, 30, 37, 36, 32, + 26, 21, 14, 7, -6, -19, -28, -34, -32, -27, -21, -20, -21, -20, -11, 5, + 17, 25, 29, 30, 33, 35, 31, 27, 19, 8, -7, -25, -37, -42, -41, -39, + -35, -30, -22, -11, 4, 21, 32, 38, 39, 36, 29, 22, 15, 9, -4, -15, + -24, -32, -35, -31, -24, -18, -18, -19, -14, -3, 11, 21, 27, 31, 32, 34, + 34, 31, 27, 18, 1, -19, -33, -39, -38, -40, -39, -35, -28, -17, -3, 14, + 28, 37, 41, 40, 34, 30, 24, 18, 7, -6, -20, -30, -36, -34, -30, -26, + -26, -27, -26, -16, 0, 16, 26, 30, 33, 36, 42, 43, 38, 27, 10, -10, + -27, -39, -43, -43, -43, -40, -34, -26, -14, 2, 21, 36, 42, 40, 36, 33, + 30, 24, 16, 5, -11, -25, -34, -35, -32, -29, -30, -31, -31, -27, -15, 5, + 21, 27, 30, 34, 42, 51, 48, 40, 20, -3, -21, -32, -38, -40, -43, -42, + -38, -30, -18, -3, 15, 29, 40, 41, 39, 34, 31, 28, 20, 10, -4, -18, + -29, -33, -34, -34, -35, -37, -38, -34, -21, -6, 12, 22, 26, 33, 44, 55, + 56, 46, 26, 5, -11, -25, -36, -42, -47, -47, -43, -37, -24, -11, 9, 25, + 36, 38, 38, 40, 39, 39, 28, 17, 3, -10, -23, -30, -37, -38, -42, -44, + -43, -40, -30, -16, 3, 17, 26, 34, 44, 57, 61, 52, 34, 9, -7, -21, + -30, -38, -46, -49, -48, -39, -27, -13, 5, 22, 32, 35, 35, 37, 41, 43, + 33, 19, 4, -8, -16, -25, -32, -39, -42, -44, -42, -41, -33, -20, -4, 11, + 21, 28, 38, 49, 58, 54, 36, 16, -6, -16, -21, -28, -36, -46, -49, -42, + -29, -17, 0, 13, 26, 30, 30, 35, 41, 47, 41, 25, 9, -4, -12, -17, + -28, -38, -46, -52, -51, -49, -39, -23, -9, 4, 12, 23, 39, 54, 66, 62, + 43, 23, 2, -10, -16, -26, -36, -45, -51, -50, -37, -20, 0, 16, 27, 28, + 29, 38, 47, 50, 44, 28, 13, -2, -10, -16, -26, -35, -45, -55, -57, -56, + -44, -27, -13, -4, 5, 17, 34, 53, 64, 64, 46, 29, 13, 1, -8, -17, + -28, -39, -48, -51, -42, -26, -8, 9, 18, 20, 24, 34, 46, 53, 47, 33, + 15, 4, -4, -13, -22, -35, -47, -56, -59, -56, -48, -32, -18, -8, 3, 14, + 33, 52, 65, 64, 49, 31, 17, 5, -3, -13, -25, -36, -45, -49, -44, -31, + -14, 7, 16, 21, 21, 31, 48, 57, 53, 38, 20, 8, -3, -9, -21, -35, + -47, -57, -62, -62, -54, -38, -22, -12, -5, 7, 26, 49, 66, 69, 56, 37, + 24, 15, 6, -4, -17, -30, -43, -53, -47, -34, -18, -2, 9, 14, 17, 29, + 46, 58, 56, 43, 25, 13, 2, -5, -15, -30, -45, -59, -66, -65, -57, -43, + -28, -16, -10, 2, 21, 44, 66, 71, 62, 43, 28, 19, 13, 3, -12, -25, + -42, -51, -50, -38, -18, -3, 5, 12, 17, 30, 48, 59, 58, 45, 26, 11, + 0, -6, -15, -29, -45, -63, -71, -68, -58, -41, -28, -19, -12, -4, 16, 42, + 62, 70, 61, 43, 29, 21, 16, 8, -6, -20, -35, -45, -45, -37, -21, -6, + 3, 8, 14, 24, 42, 54, 58, 47, 29, 16, 3, -3, -12, -27, -42, -62, + -73, -74, -66, -52, -34, -23, -14, -5, 12, 38, 60, 72, 68, 49, 34, 23, + 17, 10, -3, -18, -31, -42, -42, -36, -20, -4, 5, 9, 11, 22, 37, 51, + 55, 46, 29, 13, 2, -9, -14, -25, -38, -53, -67, -72, -67, -53, -35, -23, + -17, -10, 6, 32, 55, 69, 67, 53, 36, 26, 19, 12, 2, -13, -26, -37, + -40, -36, -24, -7, 3, 9, 13, 20, 36, 49, 52, 47, 32, 17, 3, -12, + -19, -29, -38, -52, -66, -75, -72, -56, -36, -20, -15, -10, 2, 25, 48, 63, + 63, 52, 39, 28, 20, 14, 5, -6, -19, -30, -38, -35, -25, -8, 4, 8, + 11, 17, 33, 47, 54, 47, 34, 18, 4, -9, -19, -28, -40, -53, -65, -75, + -74, -60, -41, -22, -15, -12, -2, 18, 43, 59, 63, 55, 41, 31, 27, 20, + 13, 3, -11, -24, -35, -34, -26, -11, 2, 8, 9, 11, 22, 37, 47, 49, + 39, 22, 6, -7, -19, -26, -36, -48, -60, -74, -77, -66, -47, -26, -13, -8, + 1, 15, 36, 53, 63, 56, 45, 30, 22, 16, 10, 5, -7, -19, -32, -34, + -25, -7, 8, 16, 17, 17, 23, 37, 48, 51, 40, 22, 4, -14, -24, -33, + -39, -49, -61, -72, -77, -66, -47, -27, -13, -5, 1, 13, 30, 47, 59, 57, + 47, 31, 23, 17, 15, 6, -5, -18, -26, -30, -24, -10, 8, 19, 21, 20, + 22, 30, 40, 48, 41, 25, 3, -17, -29, -32, -37, -46, -59, -70, -73, -65, + -46, -27, -14, -4, 3, 15, 29, 41, 52, 54, 45, 31, 19, 15, 15, 9, + 1, -14, -26, -27, -21, -8, 10, 17, 23, 23, 23, 32, 39, 45, 44, 29, + 7, -16, -32, -40, -42, -49, -61, -72, -76, -69, -50, -28, -12, -2, 5, 17, + 31, 43, 48, 49, 44, 34, 24, 15, 13, 9, 5, -8, -24, -27, -21, -7, + 10, 20, 25, 29, 29, 32, 36, 41, 41, 34, 14, -12, -35, -46, -49, -52, + -61, -74, -78, -73, -56, -31, -14, 2, 10, 19, 31, 44, 54, 53, 47, 34, + 24, 16, 9, 4, -2, -12, -25, -28, -22, -7, 9, 23, 32, 36, 36, 36, + 37, 42, 42, 33, 15, -14, -36, -50, -57, -56, -62, -74, -81, -77, -59, -36, + -15, 2, 11, 20, 31, 44, 56, 56, 51, 39, 26, 15, 7, 1, -3, -13, + -26, -33, -31, -14, 9, 25, 36, 41, 40, 41, 40, 44, 44, 35, 17, -13, + -39, -54, -61, -64, -69, -76, -81, -78, -63, -39, -15, 4, 14, 24, 35, 45, + 54, 56, 53, 41, 25, 14, 7, 3, -4, -14, -26, -34, -31, -15, 9, 25, + 36, 41, 43, 44, 43, 46, 45, 35, 16, -9, -31, -49, -63, -69, -75, -78, + -84, -79, -66, -45, -22, 0, 13, 23, 35, 48, 56, 58, 53, 43, 30, 19, + 10, 4, -7, -18, -26, -33, -30, -17, 4, 24, 37, 44, 50, 50, 49, 46, + 43, 35, 16, -7, -30, -52, -65, -75, -78, -83, -85, -82, -70, -50, -26, -4, + 14, 26, 39, 53, 63, 64, 59, 49, 35, 18, 6, -2, -13, -25, -35, -40, + -36, -22, 3, 26, 38, 47, 54, 60, 61, 57, 50, 39, 20, -5, -26, -49, + -66, -80, -87, -91, -93, -88, -74, -54, -34, -12, 8, 24, 40, 55, 68, 70, + 66, 55, 41, 26, 14, 6, -9, -25, -37, -43, -39, -28, -9, 15, 32, 41, + 48, 59, 65, 65, 58, 45, 25, 5, -17, -38, -61, -77, -91, -97, -100, -94, + -79, -64, -44, -23, -2, 24, 42, 57, 72, 77, 74, 63, 48, 33, 21, 10, + -7, -27, -43, -45, -41, -29, -14, 4, 26, 40, 49, 58, 66, 69, 64, 48, + 29, 7, -13, -31, -53, -73, -89, -100, -102, -95, -83, -67, -51, -29, -7, 17, + 37, 55, 72, 81, 77, 67, 55, 40, 25, 12, -4, -22, -40, -45, -42, -31, + -19, -4, 15, 34, 48, 55, 63, 67, 66, 57, 41, 20, -4, -25, -46, -69, + -88, -104, -110, -106, -95, -79, -63, -39, -13, 15, 39, 60, 75, 88, 91, 81, + 66, 44, 27, 13, -3, -22, -41, -50, -48, -38, -26, -13, 6, 29, 46, 55, + 62, 66, 69, 63, 48, 26, 5, -14, -33, -57, -84, -105, -115, -113, -102, -88, + -73, -53, -26, 1, 31, 57, 78, 91, 95, 88, 75, 60, 41, 22, 1, -19, + -38, -51, -53, -48, -36, -22, -6, 19, 39, 53, 62, 65, 69, 67, 55, 36, + 14, -6, -28, -54, -79, -100, -111, -116, -110, -98, -83, -61, -35, -6, 26, 53, + 75, 89, 96, 96, 87, 71, 50, 29, 10, -9, -30, -44, -53, -50, -45, -32, + -19, 2, 23, 43, 55, 62, 66, 66, 62, 49, 30, 11, -12, -39, -70, -95, + -112, -118, -118, -109, -94, -74, -48, -18, 17, 47, 70, 88, 98, 99, 95, 80, + 61, 37, 14, -9, -26, -43, -51, -52, -48, -40, -25, -6, 17, 37, 52, 57, + 63, 64, 62, 55, 36, 17, -8, -34, -62, -86, -106, -117, -118, -110, -99, -83, + -57, -27, 10, 42, 67, 85, 96, 101, 101, 91, 69, 46, 21, 1, -21, -38, + -49, -54, -49, -44, -35, -18, 2, 24, 44, 55, 64, 67, 63, 59, 46, 29, + 7, -21, -51, -79, -104, -117, -122, -117, -108, -94, -70, -40, 0, 34, 63, 85, + 96, 104, 105, 99, 82, 59, 31, 4, -20, -37, -46, -51, -51, -50, -44, -28, + -8, 17, 38, 53, 60, 65, 67, 64, 54, 40, 18, -10, -40, -71, -98, -115, + -121, -118, -113, -103, -82, -52, -14, 22, 53, 77, 94, 106, 109, 104, 93, 76, + 50, 21, -11, -33, -43, -48, -53, -56, -56, -46, -27, 2, 29, 48, 58, 62, + 63, 62, 58, 49, 33, 5, -27, -57, -87, -108, -119, -118, -114, -106, -91, -68, + -31, 8, 42, 69, 88, 102, 110, 110, 100, 83, 60, 33, 3, -23, -39, -46, + -52, -57, -57, -51, -35, -14, 15, 38, 54, 63, 65, 66, 58, 51, 40, 17, + -11, -44, -76, -101, -114, -116, -111, -106, -96, -77, -47, -11, 28, 58, 81, 97, + 109, 112, 105, 95, 77, 53, 23, -9, -30, -45, -52, -58, -64, -61, -52, -35, + -9, 20, 44, 62, 67, 67, 65, 62, 54, 35, 7, -24, -60, -91, -110, -119, + -116, -112, -105, -90, -65, -31, 8, 43, 73, 94, 109, 117, 113, 105, 91, 68, + 39, 4, -24, -43, -56, -64, -67, -67, -61, -47, -21, 9, 35, 55, 63, 66, + 66, 61, 56, 46, 23, -10, -46, -81, -100, -111, -115, -112, -107, -94, -75, -48, + -12, 28, 59, 84, 103, 116, 120, 114, 103, 81, 56, 22, -10, -35, -53, -64, + -71, -73, -71, -59, -39, -10, 19, 43, 60, 66, 68, 67, 64, 53, 33, 7, + -27, -64, -91, -108, -115, -113, -108, -97, -82, -59, -27, 11, 46, 75, 98, 112, + 119, 117, 109, 89, 64, 34, 4, -24, -50, -62, -69, -69, -70, -65, -49, -23, + 8, 32, 52, 61, 64, 65, 64, 55, 39, 15, -16, -46, -76, -97, -109, -110, + -107, -102, -91, -71, -42, -4, 34, 66, 90, 106, 116, 121, 118, 101, 78, 47, + 15, -15, -44, -60, -70, -73, -75, -74, -63, -39, -7, 23, 45, 60, 66, 69, + 69, 62, 49, 29, 1, -32, -65, -94, -108, -112, -109, -102, -97, -83, -58, -22, + 18, 54, 84, 103, 116, 121, 120, 112, 91, 63, 29, -6, -34, -54, -66, -75, + -79, -81, -72, -50, -22, 9, 33, 50, 59, 67, 70, 70, 60, 43, 13, -20, + -51, -78, -97, -107, -111, -109, -105, -94, -72, -37, 5, 42, 72, 96, 114, 124, + 127, 118, 100, 75, 42, 10, -22, -47, -62, -72, -79, -84, -82, -64, -35, -2, + 23, 39, 50, 61, 69, 71, 66, 51, 27, -6, -36, -62, -81, -96, -104, -105, + -106, -101, -83, -52, -11, 27, 57, 82, 103, 120, 127, 122, 107, 82, 53, 19, + -12, -39, -55, -65, -73, -81, -81, -67, -40, -8, 16, 30, 41, 52, 62, 68, + 66, 56, 34, 3, -28, -53, -71, -86, -96, -102, -106, -103, -88, -62, -25, 15, + 47, 72, 90, 109, 120, 123, 115, 93, 63, 31, 1, -24, -40, -52, -64, -76, + -82, -73, -50, -22, 1, 18, 27, 39, 51, 63, 67, 61, 44, 18, -13, -38, + -53, -69, -83, -96, -105, -103, -93, -69, -36, -3, 30, 56, 77, 95, 111, 116, + 113, 97, 72, 42, 13, -12, -25, -38, -54, -70, -79, -74, -57, -32, -11, 4, + 15, 26, 40, 55, 65, 62, 51, 28, 1, -24, -40, -56, -73, -89, -101, -102, + -95, -79, -50, -17, 16, 47, 68, 88, 104, 114, 115, 102, 80, 53, 24, 0, + -18, -31, -45, -60, -73, -74, -63, -42, -21, -6, 6, 16, 28, 45, 56, 59, + 51, 35, 14, -9, -26, -41, -57, -73, -87, -97, -95, -85, -62, -32, -2, 26, + 50, 71, 91, 105, 111, 105, 89, 64, 40, 16, -4, -20, -35, -49, -64, -70, + -68, -53, -35, -18, -6, 5, 14, 29, 45, 55, 54, 39, 21, 4, -13, -25, + -42, -63, -77, -89, -90, -80, -66, -44, -19, 10, 35, 57, 76, 93, 104, 104, + 91, 68, 48, 29, 13, -6, -24, -42, -56, -63, -61, -54, -42, -27, -17, -6, + 5, 18, 33, 44, 47, 39, 25, 10, 0, -14, -29, -50, -67, -79, -85, -81, + -70, -53, -32, -5, 24, 47, 67, 84, 98, 103, 95, 77, 56, 37, 22, 6, + -14, -34, -48, -56, -57, -52, -48, -37, -28, -17, -6, 8, 23, 34, 41, 38, + 28, 15, 4, -4, -16, -38, -59, -73, -78, -75, -66, -54, -37, -19, 7, 32, + 53, 72, 87, 95, 92, 78, 58, 44, 32, 20, 2, -21, -38, -47, -48, -47, + -46, -42, -36, -26, -14, -5, 9, 20, 32, 35, 30, 19, 12, 8, -5, -25, + -48, -63, -71, -70, -63, -58, -44, -26, -6, 20, 40, 59, 79, 92, 93, 83, + 60, 47, 37, 29, 13, -10, -28, -40, -44, -44, -48, -47, -41, -33, -22, -13, + 0, 14, 29, 36, 34, 24, 18, 15, 4, -13, -39, -60, -69, -72, -68, -62, + -51, -34, -13, 9, 31, 52, 73, 88, 95, 87, 70, 55, 45, 35, 20, -2, + -23, -36, -42, -47, -48, -51, -50, -40, -30, -17, -8, 7, 23, 36, 37, 30, + 22, 19, 13, -3, -24, -49, -65, -71, -71, -64, -54, -40, -20, -3, 21, 44, + 65, 85, 92, 87, 72, 57, 48, 39, 29, 11, -12, -27, -36, -41, -42, -47, + -49, -45, -37, -28, -17, -4, 13, 28, 33, 29, 26, 23, 17, 6, -11, -33, + -53, -64, -66, -62, -55, -44, -29, -12, 10, 31, 51, 71, 84, 85, 77, 61, + 50, 41, 36, 22, 2, -17, -33, -38, -42, -45, -48, -46, -41, -34, -23, -9, + 7, 24, 35, 32, 28, 23, 17, 10, -4, -26, -49, -64, -68, -64, -58, -46, + -32, -13, 8, 28, 45, 65, 78, 82, 76, 62, 52, 45, 37, 23, 6, -10, + -26, -35, -41, -45, -46, -48, -48, -39, -27, -11, 3, 14, 23, 27, 28, 25, + 23, 15, 2, -17, -34, -52, -60, -61, -56, -44, -32, -17, -3, 16, 34, 54, + 66, 73, 68, 58, 47, 42, 37, 29, 17, 3, -14, -25, -31, -36, -39, -44, + -48, -44, -33, -20, -9, 2, 13, 22, 26, 24, 20, 14, 5, -7, -22, -39, + -50, -55, -51, -43, -32, -20, -7, 10, 28, 44, 57, 65, 67, 64, 54, 44, + 36, 28, 18, 4, -9, -23, -32, -39, -42, -46, -44, -38, -29, -19, -12, -4, + 10, 22, 27, 22, 14, 8, 1, -6, -17, -30, -43, -49, -47, -38, -26, -18, + -10, 3, 17, 34, 45, 54, 59, 57, 53, 45, 37, 30, 22, 11, -3, -14, + -24, -34, -40, -45, -43, -39, -29, -21, -14, -6, 3, 16, 20, 17, 10, 3, + 0, -6, -15, -25, -33, -38, -37, -31, -21, -12, -6, 5, 15, 27, 39, 46, + 50, 51, 47, 44, 36, 29, 20, 10, 1, -10, -18, -27, -36, -40, -42, -37, + -29, -21, -14, -7, 1, 10, 16, 10, 3, -2, -3, -6, -12, -22, -28, -30, + -28, -23, -16, -11, -7, 0, 7, 19, 31, 42, 47, 47, 46, 46, 40, 33, + 21, 10, 2, -6, -12, -24, -33, -37, -38, -36, -31, -21, -14, -7, -2, 2, + 7, 8, 4, -2, -7, -12, -14, -19, -23, -24, -20, -16, -11, -6, -2, 3, + 9, 16, 24, 33, 37, 40, 44, 44, 40, 33, 22, 13, 5, -3, -8, -21, + -30, -35, -34, -32, -30, -23, -13, -6, -3, -3, -2, -2, -4, -7, -9, -12, + -13, -13, -14, -14, -11, -12, -4, -2, 2, 0, 3, 10, 18, 27, 32, 35, + 38, 40, 37, 32, 23, 13, 8, 2, -4, -11, -22, -27, -31, -30, -29, -24, + -14, -7, -8, -7, -10, -10, -10, -10, -11, -12, -13, -12, -11, -11, -7, -2, + 4, 5, 3, -2, 0, 8, 15, 21, 26, 30, 32, 37, 37, 32, 26, 16, + 10, 4, -4, -9, -16, -21, -26, -29, -28, -23, -15, -11, -9, -11, -13, -14, + -14, -13, -13, -12, -13, -12, -8, -3, 3, 6, 8, 10, 7, 1, -3, 2, + 8, 17, 22, 22, 27, 32, 37, 35, 29, 18, 11, 2, -4, -8, -14, -17, + -21, -23, -25, -22, -17, -11, -9, -11, -16, -16, -16, -16, -14, -15, -14, -11, + -5, 0, 4, 5, 6, 7, 6, 4, 0, 3, 8, 16, 21, 20, 24, 28, + 34, 35, 29, 17, 8, 3, 1, -3, -9, -15, -20, -21, -23, -22, -21, -17, + -13, -14, -18, -23, -22, -17, -13, -10, -9, -8, 0, 6, 9, 10, 8, 6, + 6, 4, 0, -2, 1, 10, 17, 20, 22, 25, 29, 31, 29, 20, 10, 2, + -2, 0, -5, -11, -18, -20, -19, -19, -19, -18, -16, -14, -18, -26, -26, -22, + -16, -13, -9, -6, 1, 7, 10, 10, 7, 7, 7, 5, 0, -4, -2, 7, + 14, 19, 22, 26, 30, 32, 30, 22, 13, 6, 1, -2, -7, -13, -16, -18, + -19, -19, -21, -21, -19, -17, -16, -23, -25, -23, -17, -10, -9, -4, 2, 8, + 10, 12, 9, 7, 5, 4, 2, -3, -2, 3, 9, 18, 23, 28, 29, 28, + 27, 26, 19, 12, 6, 0, -7, -11, -15, -17, -20, -21, -20, -22, -23, -25, + -24, -26, -27, -25, -20, -13, -5, 3, 9, 11, 15, 17, 15, 10, 4, 0, + -4, -5, -4, 2, 5, 13, 19, 25, 29, 28, 26, 25, 20, 16, 11, 2, + -5, -10, -10, -10, -14, -17, -21, -24, -26, -29, -27, -28, -28, -26, -23, -17, + -8, 1, 12, 15, 16, 14, 13, 10, 6, 0, -5, -6, -5, 1, 6, 12, + 20, 27, 30, 28, 24, 23, 21, 17, 11, 4, -6, -9, -10, -10, -11, -16, + -18, -21, -24, -26, -29, -28, -27, -25, -23, -18, -11, -2, 11, 15, 15, 12, + 11, 9, 6, 1, -6, -6, -2, 3, 7, 11, 19, 26, 28, 26, 22, 21, + 23, 24, 17, 10, 4, 0, -2, -5, -10, -15, -20, -25, -32, -36, -36, -35, + -32, -30, -26, -19, -10, 2, 14, 21, 21, 17, 13, 10, 7, 1, -5, -5, + -6, -4, 0, 6, 12, 19, 22, 24, 20, 21, 24, 29, 28, 20, 13, 8, + 3, 2, -4, -9, -16, -27, -34, -41, -44, -41, -38, -35, -31, -27, -18, -3, + 13, 26, 29, 23, 18, 14, 11, 8, 4, -2, -8, -11, -9, -6, 4, 9, + 16, 17, 16, 16, 23, 33, 37, 33, 26, 19, 12, 8, 1, -7, -15, -30, + -41, -50, -53, -50, -43, -38, -34, -28, -17, -3, 13, 26, 30, 26, 19, 14, + 12, 9, 4, -2, -10, -14, -13, -7, 4, 9, 12, 13, 13, 17, 25, 32, + 40, 39, 32, 24, 15, 11, 8, 1, -10, -27, -43, -51, -55, -52, -49, -45, + -40, -32, -21, -8, 9, 23, 31, 30, 24, 19, 17, 16, 11, 4, -7, -15, + -18, -14, -6, 2, 5, 7, 9, 14, 24, 35, 45, 48, 45, 34, 25, 16, + 8, 2, -11, -27, -46, -59, -64, -61, -53, -46, -40, -35, -24, -9, 8, 23, + 30, 31, 27, 24, 21, 17, 12, 4, -6, -15, -19, -17, -12, -3, 3, 4, + 6, 12, 25, 37, 45, 47, 47, 43, 35, 23, 12, 2, -10, -24, -42, -60, + -71, -71, -63, -55, -45, -36, -22, -7, 9, 22, 30, 35, 34, 31, 24, 19, + 13, 6, -3, -13, -20, -21, -16, -9, -3, -2, 4, 11, 26, 38, 45, 50, + 49, 48, 42, 31, 16, 4, -9, -21, -38, -59, -72, -77, -70, -61, -53, -41, + -26, -9, 7, 17, 26, 34, 41, 41, 35, 25, 17, 9, 0, -10, -21, -24, + -22, -15, -9, -7, -2, 10, 25, 39, 44, 47, 49, 52, 50, 39, 22, 6, + -8, -20, -34, -54, -70, -78, -77, -68, -61, -49, -33, -15, 3, 16, 25, 32, + 43, 49, 47, 37, 25, 16, 3, -10, -22, -29, -27, -22, -15, -12, -7, 7, + 25, 42, 47, 50, 53, 57, 57, 46, 31, 11, -5, -22, -39, -56, -72, -81, + -85, -81, -71, -56, -36, -16, 4, 19, 29, 37, 48, 55, 56, 48, 34, 20, + 7, -10, -25, -32, -34, -28, -21, -17, -14, 0, 20, 40, 50, 51, 53, 58, + 61, 53, 39, 18, -2, -18, -36, -53, -70, -80, -85, -86, -79, -67, -46, -23, + -2, 17, 27, 35, 44, 55, 62, 57, 44, 26, 9, -10, -23, -29, -32, -28, + -24, -20, -15, -4, 15, 35, 47, 50, 49, 53, 57, 53, 43, 24, 5, -14, + -32, -50, -64, -5, 0, -2, -3, -3, -3, -3, -2, -2, 1, 2, 3, 5, + 8, 11, 11, 10, 8, 5, 1, -6, -13, -19, -21, -18, -15, -13, -10, -7, + -2, 4, 8, 12, 17, 28, 33, 29, 23, 14, 7, -5, -19, -33, -42, -36, + -28, -24, -17, -13, -8, 1, 7, 15, 23, 33, 42, 42, 35, 26, 15, 0, + -16, -30, -44, -45, -34, -27, -20, -16, -13, -4, 4, 12, 21, 29, 40, 45, + 40, 30, 20, 6, -13, -25, -38, -45, -38, -31, -24, -18, -15, -10, -4, 5, + 17, 27, 35, 44, 43, 37, 27, 15, -4, -19, -31, -44, -44, -35, -30, -22, + -19, -16, -8, 2, 15, 25, 32, 42, 47, 42, 32, 18, 0, -16, -26, -39, + -45, -38, -31, -25, -19, -18, -14, -5, 11, 23, 29, 39, 46, 45, 38, 25, + 7, -8, -18, -31, -44, -43, -35, -30, -25, -25, -20, -9, 7, 21, 27, 36, + 48, 51, 44, 32, 14, -3, -16, -28, -42, -46, -41, -33, -27, -24, -23, -15, + 1, 16, 27, 33, 42, 47, 46, 38, 21, 5, -9, -21, -34, -44, -45, -39, + -31, -28, -26, -20, -8, 9, 25, 34, 41, 49, 51, 47, 31, 11, -6, -18, + -30, -42, -48, -45, -36, -28, -26, -23, -12, 6, 23, 33, 38, 43, 51, 50, + 36, 15, 0, -12, -22, -35, -50, -50, -40, -31, -29, -27, -18, 1, 20, 32, + 36, 43, 52, 56, 45, 23, 2, -10, -20, -33, -48, -56, -49, -36, -30, -26, + -18, -5, 17, 33, 39, 40, 46, 52, 49, 32, 9, -8, -18, -26, -40, -54, + -53, -39, -30, -28, -23, -12, 10, 31, 39, 38, 42, 54, 54, 41, 17, -5, + -15, -22, -35, -53, -59, -47, -36, -30, -24, -14, 6, 27, 40, 42, 43, 51, + 56, 46, 26, 3, -13, -22, -33, -49, -61, -55, -41, -32, -26, -18, 0, 22, + 38, 45, 43, 48, 55, 50, 33, 11, -10, -21, -29, -43, -59, -60, -46, -35, + -28, -18, -6, 15, 35, 45, 46, 45, 52, 53, 41, 20, -6, -19, -26, -38, + -54, -62, -53, -39, -29, -19, -11, 6, 29, 44, 48, 45, 47, 52, 49, 32, + 5, -18, -26, -32, -45, -61, -61, -48, -35, -23, -14, -2, 22, 42, 52, 50, + 46, 50, 50, 38, 12, -15, -26, -31, -43, -59, -65, -53, -37, -25, -16, -6, + 16, 40, 53, 53, 47, 49, 51, 42, 22, -10, -27, -31, -38, -54, -67, -63, + -46, -27, -18, -7, 10, 31, 52, 59, 53, 48, 50, 46, 32, 3, -24, -34, + -39, -50, -66, -68, -54, -35, -20, -8, 6, 23, 47, 62, 59, 52, 50, 48, + 37, 13, -18, -35, -40, -46, -62, -72, -63, -43, -25, -10, 6, 20, 41, 59, + 63, 55, 49, 46, 39, 21, -9, -31, -39, -42, -52, -68, -68, -52, -32, -17, + -4, 9, 31, 54, 66, 63, 54, 51, 44, 32, 6, -26, -40, -44, -51, -65, + -72, -61, -41, -23, -5, 9, 25, 48, 64, 66, 59, 54, 46, 33, 12, -17, + -36, -45, -51, -62, -73, -67, -48, -31, -11, 8, 21, 44, 64, 70, 64, 57, + 49, 36, 20, -8, -34, -47, -52, -58, -68, -73, -59, -40, -19, 4, 17, 36, + 58, 72, 73, 65, 56, 41, 26, 4, -24, -44, -55, -63, -69, -73, -66, -51, + -28, -2, 18, 32, 51, 67, 75, 72, 62, 46, 29, 11, -13, -37, -54, -64, + -70, -71, -70, -58, -38, -13, 14, 30, 48, 64, 73, 76, 69, 52, 34, 15, + -7, -31, -50, -62, -69, -71, -71, -66, -47, -19, 8, 26, 40, 58, 73, 81, + 76, 57, 39, 23, 2, -22, -45, -62, -71, -73, -71, -69, -57, -32, 0, 26, + 41, 55, 70, 81, 83, 64, 41, 24, 6, -15, -39, -60, -71, -73, -69, -69, + -62, -40, -11, 20, 39, 51, 65, 78, 86, 75, 50, 29, 11, -8, -30, -53, + -70, -77, -71, -66, -67, -53, -22, 13, 37, 49, 60, 75, 89, 84, 58, 33, + 16, -2, -22, -47, -68, -77, -72, -67, -68, -60, -34, 0, 29, 47, 56, 69, + 85, 88, 69, 40, 20, 4, -13, -35, -61, -76, -74, -65, -66, -65, -47, -15, + 20, 43, 53, 64, 81, 89, 77, 50, 26, 9, -10, -29, -51, -71, -78, -71, + -66, -64, -52, -27, 9, 38, 54, 62, 73, 85, 82, 60, 34, 13, -3, -19, + -40, -65, -80, -74, -68, -69, -61, -40, -4, 29, 49, 61, 72, 86, 86, 70, + 45, 21, 3, -16, -33, -56, -80, -78, -70, -70, -65, -50, -18, 20, 48, 62, + 68, 80, 88, 78, 53, 26, 5, -12, -26, -45, -72, -81, -71, -67, -64, -56, + -34, 4, 37, 57, 63, 73, 85, 83, 63, 37, 16, 0, -17, -36, -63, -79, + -74, -70, -69, -63, -44, -10, 26, 52, 62, 69, 81, 84, 69, 45, 22, 3, + -15, -28, -52, -75, -76, -69, -67, -64, -52, -24, 14, 45, 60, 65, 74, 82, + 75, 54, 32, 12, -6, -21, -44, -68, -78, -74, -71, -69, -60, -34, 2, 34, + 55, 66, 73, 79, 78, 61, 39, 20, 2, -16, -34, -56, -72, -74, -70, -71, + -66, -47, -14, 21, 48, 61, 68, 76, 80, 69, 46, 27, 11, -7, -26, -50, + -68, -72, -70, -70, -69, -54, -24, 10, 39, 57, 66, 72, 76, 70, 52, 33, + 16, -4, -20, -39, -59, -70, -71, -69, -67, -60, -37, -6, 27, 50, 62, 67, + 72, 74, 61, 41, 25, 10, -10, -31, -51, -67, -74, -73, -73, -68, -48, -16, + 17, 45, 60, 66, 73, 75, 66, 48, 29, 15, -3, -24, -45, -62, -70, -72, + -74, -70, -55, -26, 7, 32, 51, 63, 70, 73, 67, 51, 35, 24, 9, -16, + -38, -54, -64, -68, -75, -75, -62, -36, -5, 22, 45, 60, 69, 74, 68, 57, + 43, 29, 15, -9, -29, -45, -60, -67, -75, -76, -64, -44, -16, 10, 32, 52, + 63, 68, 66, 59, 48, 36, 24, 6, -17, -35, -51, -60, -70, -78, -72, -55, + -27, 1, 20, 39, 56, 65, 68, 60, 51, 41, 31, 15, -9, -27, -44, -58, + -67, -75, -73, -58, -35, -8, 11, 32, 50, 60, 61, 57, 53, 47, 37, 25, + 4, -19, -35, -48, -60, -73, -76, -67, -46, -18, 2, 20, 40, 56, 64, 62, + 56, 49, 43, 34, 15, -10, -31, -45, -57, -70, -78, -69, -52, -27, -4, 13, + 34, 52, 60, 57, 53, 52, 46, 36, 22, 1, -19, -35, -50, -65, -73, -70, + -58, -41, -17, 4, 22, 42, 55, 58, 57, 55, 50, 43, 32, 12, -11, -30, + -47, -61, -71, -72, -63, -46, -26, -6, 13, 30, 47, 53, 54, 56, 52, 46, + 38, 24, 5, -20, -39, -52, -63, -67, -66, -57, -37, -15, 3, 18, 37, 50, + 55, 59, 55, 49, 45, 32, 15, -10, -34, -50, -61, -66, -66, -58, -42, -24, + -4, 11, 27, 44, 50, 54, 57, 53, 49, 39, 23, 2, -23, -43, -57, -64, + -67, -62, -50, -33, -14, 4, 18, 37, 48, 53, 57, 55, 52, 44, 30, 13, + -14, -38, -54, -62, -65, -62, -54, -42, -24, -2, 13, 28, 41, 48, 56, 57, + 52, 45, 37, 23, 0, -28, -47, -57, -62, -63, -59, -50, -34, -14, 1, 16, + 35, 48, 56, 59, 59, 54, 45, 31, 8, -20, -42, -56, -62, -64, -60, -52, + -40, -23, -5, 10, 28, 43, 52, 56, 57, 56, 49, 38, 21, -8, -33, -46, + -56, -60, -59, -56, -47, -32, -15, 0, 17, 34, 47, 55, 58, 57, 53, 43, + 30, 8, -24, -42, -52, -59, -58, -57, -51, -42, -26, -8, 11, 29, 42, 50, + 57, 59, 55, 48, 34, 15, -15, -36, -45, -52, -55, -58, -55, -43, -31, -17, + -2, 16, 37, 50, 56, 58, 58, 54, 43, 23, -8, -33, -40, -47, -54, -57, + -58, -48, -34, -23, -10, 9, 31, 48, 54, 55, 55, 57, 50, 32, 3, -28, + -37, -41, -49, -55, -58, -49, -36, -27, -17, 1, 21, 41, 50, 52, 51, 54, + 55, 41, 13, -18, -32, -35, -42, -50, -57, -55, -41, -32, -24, -10, 10, 33, + 47, 50, 51, 54, 59, 49, 24, -8, -26, -30, -37, -46, -56, -59, -46, -35, + -29, -18, 2, 25, 44, 48, 47, 51, 57, 56, 36, 5, -20, -28, -31, -40, + -51, -58, -52, -39, -33, -25, -8, 15, 38, 49, 47, 50, 56, 60, 46, 15, + -11, -25, -30, -36, -49, -60, -54, -39, -33, -30, -14, 8, 32, 47, 44, 44, + 51, 59, 52, 26, -4, -20, -24, -29, -41, -54, -55, -43, -34, -33, -26, -8, + 17, 37, 43, 42, 48, 59, 60, 42, 13, -11, -21, -25, -36, -51, -59, -51, + -38, -34, -32, -17, 10, 33, 43, 43, 44, 55, 60, 46, 21, -6, -18, -22, + -28, -42, -54, -52, -39, -30, -32, -25, -4, 20, 36, 39, 39, 48, 60, 57, + 36, 10, -11, -19, -22, -34, -51, -58, -48, -35, -36, -34, -13, 13, 35, 41, + 38, 46, 59, 61, 44, 20, -5, -20, -22, -30, -46, -56, -53, -39, -34, -36, + -22, 1, 25, 39, 39, 42, 53, 60, 54, 34, 10, -10, -17, -21, -39, -57, + -59, -48, -38, -43, -35, -11, 16, 37, 43, 42, 52, 61, 58, 41, 19, -3, + -16, -21, -31, -50, -59, -53, -40, -39, -39, -22, 5, 30, 40, 38, 45, 58, + 64, 52, 28, 5, -12, -17, -23, -44, -58, -56, -46, -40, -43, -33, -7, 22, + 39, 41, 44, 55, 64, 60, 40, 13, -7, -16, -21, -35, -56, -60, -52, -44, + -43, -40, -21, 11, 34, 40, 40, 50, 61, 64, 53, 29, 6, -10, -16, -25, + -47, -62, -61, -53, -49, -47, -35, -5, 26, 42, 45, 49, 58, 65, 59, 39, + 15, -5, -16, -22, -37, -56, -61, -56, -50, -47, -42, -21, 11, 33, 40, 44, + 53, 63, 66, 54, 29, 8, -6, -15, -28, -52, -64, -60, -57, -53, -49, -31, + 1, 28, 40, 42, 51, 63, 66, 56, 36, 14, -3, -13, -25, -45, -61, -61, + -58, -54, -47, -38, -11, 20, 36, 41, 44, 55, 64, 60, 47, 28, 9, -4, + -15, -32, -56, -67, -64, -62, -55, -48, -27, 8, 29, 41, 47, 57, 66, 65, + 56, 39, 17, 0, -13, -27, -49, -66, -68, -67, -58, -48, -36, -8, 22, 38, + 45, 53, 63, 65, 61, 51, 28, 11, -4, -20, -40, -62, -70, -71, -68, -55, + -44, -24, 9, 30, 42, 52, 66, 69, 64, 58, 42, 20, 4, -14, -34, -57, + -71, -73, -73, -63, -51, -35, -5, 23, 38, 48, 62, 71, 69, 65, 54, 32, + 14, -6, -26, -48, -68, -79, -82, -72, -57, -42, -18, 11, 33, 48, 63, 73, + 72, 68, 62, 46, 22, 0, -21, -42, -63, -76, -83, -80, -65, -49, -28, -2, + 23, 42, 58, 71, 75, 72, 68, 56, 33, 10, -12, -32, -54, -73, -84, -87, + -73, -54, -36, -15, 11, 34, 52, 67, 73, 73, 72, 66, 48, 21, -6, -26, + -47, -67, -80, -88, -81, -62, -41, -23, 0, 27, 47, 65, 74, 74, 71, 67, + 57, 33, 4, -20, -42, -64, -77, -88, -88, -72, -49, -27, -7, 16, 40, 63, + 75, 75, 74, 69, 64, 46, 16, -13, -35, -57, -74, -87, -93, -81, -58, -35, + -17, 6, 33, 59, 73, 76, 76, 71, 68, 58, 29, -4, -29, -48, -68, -83, + -94, -92, -70, -42, -22, -4, 21, 51, 73, 78, 76, 73, 70, 63, 40, 7, + -24, -42, -60, -79, -91, -92, -76, -52, -30, -12, 9, 39, 66, 76, 76, 75, + 74, 70, 54, 24, -12, -36, -52, -72, -93, -100, -90, -64, -38, -21, -5, 25, + 61, 81, 81, 77, 78, 76, 63, 33, -5, -33, -49, -67, -90, -100, -92, -71, + -44, -21, -8, 14, 49, 75, 82, 77, 76, 75, 66, 45, 10, -27, -45, -59, + -80, -98, -98, -81, -52, -26, -12, 2, 34, 71, 86, 80, 75, 77, 71, 54, + 23, -17, -44, -57, -74, -93, -99, -87, -65, -36, -14, -4, 20, 55, 79, 82, + 78, 78, 75, 65, 41, 1, -34, -52, -67, -88, -104, -98, -76, -47, -23, -12, + 6, 45, 81, 90, 81, 79, 81, 72, 50, 11, -28, -50, -61, -81, -102, -103, + -84, -57, -30, -13, 1, 30, 70, 92, 88, 81, 80, 75, 59, 27, -15, -48, + -62, -76, -97, -106, -94, -69, -39, -16, -4, 17, 59, 92, 94, 87, 86, 83, + 67, 36, -4, -38, -61, -77, -96, -111, -102, -80, -53, -26, -8, 14, 50, 89, + 101, 93, 87, 83, 73, 46, 7, -31, -58, -72, -87, -106, -106, -88, -59, -31, + -12, 5, 33, 74, 99, 99, 90, 84, 78, 57, 22, -18, -49, -70, -84, -100, + -108, -96, -72, -43, -21, -3, 24, 61, 95, 106, 99, 90, 82, 65, 34, -6, + -40, -66, -83, -96, -106, -102, -82, -52, -27, -8, 15, 48, 86, 107, 105, 94, + 85, 73, 45, 6, -32, -61, -80, -91, -102, -106, -92, -63, -35, -15, 8, 37, + 74, 102, 109, 98, 87, 76, 54, 21, -16, -50, -76, -89, -98, -104, -98, -76, + -46, -23, -2, 25, 60, 93, 111, 106, 92, 82, 65, 35, -5, -39, -66, -83, + -95, -105, -105, -86, -57, -33, -11, 15, 50, 86, 111, 115, 102, 88, 71, 43, + 7, -32, -64, -86, -96, -100, -102, -92, -67, -40, -13, 13, 42, 75, 103, 116, + 106, 90, 74, 49, 16, -21, -54, -80, -94, -98, -100, -94, -75, -50, -23, 4, + 30, 62, 95, 117, 115, 100, 81, 57, 28, -10, -46, -75, -95, -102, -101, -97, + -83, -61, -32, -2, 24, 55, 87, 111, 118, 106, 88, 65, 35, 0, -36, -67, + -89, -101, -102, -98, -89, -68, -43, -13, 16, 46, 80, 107, 121, 116, 98, 75, + 47, 11, -27, -62, -87, -101, -104, -100, -93, -77, -51, -18, 13, 36, 67, 99, + 119, 119, 103, 81, 53, 21, -16, -52, -79, -96, -106, -102, -93, -82, -60, -30, + 3, 30, 59, 88, 111, 121, 111, 89, 61, 30, -4, -41, -74, -94, -106, -104, + -95, -87, -70, -41, -8, 22, 49, 81, 106, 120, 118, 98, 73, 41, 8, -30, + -64, -87, -104, -111, -100, -91, -77, -51, -21, 13, 41, 73, 100, 117, 122, 107, + 83, 52, 19, -18, -55, -82, -101, -111, -105, -93, -83, -60, -29, 5, 35, 64, + 92, 112, 121, 112, 88, 61, 29, -7, -45, -75, -94, -108, -108, -96, -87, -67, + -37, -5, 26, 52, 83, 105, 116, 116, 97, 70, 41, 7, -33, -67, -91, -105, + -110, -99, -88, -73, -48, -18, 15, 45, 74, 98, 114, 118, 104, 79, 51, 17, + -21, -58, -86, -102, -109, -103, -90, -77, -54, -23, 9, 36, 62, 88, 107, 114, + 107, 88, 63, 30, -8, -46, -77, -96, -107, -108, -97, -81, -63, -36, -4, 30, + 59, 84, 104, 115, 112, 95, 69, 38, 5, -33, -69, -94, -104, -105, -99, -87, + -72, -44, -11, 21, 47, 71, 97, 113, 113, 99, 77, 49, 17, -19, -57, -87, + -101, -105, -103, -90, -72, -54, -24, 10, 41, 64, 86, 104, 111, 104, 85, 57, + 25, -7, -42, -75, -96, -101, -98, -92, -79, -61, -36, -4, 28, 51, 74, 98, + 110, 107, 94, 70, 38, 5, -30, -64, -89, -101, -101, -95, -79, -63, -43, -14, + 21, 48, 68, 90, 105, 108, 97, 74, 44, 12, -20, -52, -83, -96, -96, -92, + -82, -67, -49, -24, 10, 39, 59, 79, 99, 107, 101, 83, 54, 21, -11, -41, + -71, -92, -98, -95, -84, -68, -54, -35, -5, 28, 54, 73, 92, 103, 103, 90, + 64, 31, -4, -34, -63, -85, -94, -92, -84, -70, -56, -38, -11, 19, 44, 64, + 83, 95, 98, 90, 66, 39, 9, -22, -50, -73, -86, -89, -84, -72, -59, -45, + -23, 6, 35, 58, 75, 89, 96, 92, 75, 49, 19, -14, -42, -63, -80, -88, + -84, -74, -60, -48, -30, -5, 23, 52, 70, 82, 91, 91, 79, 57, 29, -3, + -33, -54, -70, -84, -87, -79, -65, -50, -35, -16, 10, 41, 68, 80, 85, 88, + 82, 64, 36, 3, -28, -49, -60, -72, -83, -81, -66, -49, -37, -22, -2, 28, + 58, 74, 78, 83, 81, 69, 45, 14, -18, -42, -55, -66, -77, -79, -68, -53, + -39, -25, -8, 17, 46, 67, 72, 75, 74, 70, 53, 24, -9, -34, -48, -55, + -64, -74, -70, -55, -40, -28, -17, 3, 33, 61, 70, 71, 69, 68, 61, 37, + 3, -28, -44, -50, -57, -70, -73, -58, -41, -30, -21, -8, 21, 52, 67, 69, + 66, 66, 64, 44, 10, -22, -39, -48, -52, -61, -72, -62, -43, -29, -20, -12, + 7, 38, 62, 68, 61, 56, 60, 51, 23, -12, -36, -43, -44, -49, -65, -65, + -45, -29, -22, -19, -7, 24, 52, 65, 57, 52, 58, 57, 36, 0, -30, -38, + -37, -39, -55, -66, -52, -33, -23, -21, -14, 10, 40, 60, 59, 49, 51, 54, + 43, 11, -21, -35, -37, -33, -42, -55, -49, -29, -19, -20, -19, -5, 23, 49, + 54, 43, 42, 50, 49, 23, -12, -30, -34, -29, -31, -49, -54, -35, -19, -16, + -18, -11, 10, 39, 55, 45, 35, 41, 47, 31, -3, -26, -33, -28, -23, -36, + -47, -36, -18, -11, -16, -16, -3, 21, 42, 42, 32, 32, 40, 35, 13, -13, + -25, -24, -17, -22, -37, -38, -25, -16, -16, -19, -11, 7, 30, 42, 34, 27, + 33, 35, 19, -6, -21, -23, -17, -14, -23, -29, -21, -11, -10, -17, -16, -4, + 14, 30, 31, 20, 21, 29, 24, 6, -11, -16, -11, -5, -10, -20, -22, -15, + -12, -17, -21, -15, 0, 20, 29, 22, 17, 23, 25, 16, -2, -14, -14, -7, + -2, -9, -14, -12, -9, -11, -17, -17, -11, 3, 18, 17, 9, 13, 19, 17, + 7, -5, -5, 3, 8, 3, -7, -10, -12, -14, -20, -22, -17, -7, 9, 17, + 10, 8, 15, 18, 11, 2, -3, 1, 8, 9, 5, -3, -9, -12, -18, -21, + -21, -19, -4, 10, 9, 2, 5, 14, 16, 11, 4, 5, 13, 16, 14, 6, + -8, -14, -19, -23, -24, -21, -13, -2, 7, 3, -2, 8, 12, 11, 9, 10, + 14, 19, 20, 16, 4, -9, -17, -23, -26, -27, -24, -14, -2, 1, -5, 3, + 15, 17, 14, 14, 17, 22, 25, 20, 9, -8, -19, -25, -30, -29, -26, -22, + -11, 0, -3, -3, 9, 16, 19, 20, 21, 24, 28, 28, 20, 2, -16, -25, + -30, -34, -33, -32, -23, -9, -6, -8, 2, 15, 21, 24, 26, 29, 33, 34, + 30, 14, -11, -26, -33, -38, -38, -37, -34, -23, -12, -7, 0, 11, 21, 29, + 34, 35, 37, 39, 35, 21, -5, -26, -34, -39, -40, -42, -42, -31, -17, -9, + -4, 7, 19, 31, 38, 38, 41, 42, 40, 28, 3, -22, -36, -42, -45, -46, + -46, -37, -23, -14, -6, 6, 20, 32, 40, 40, 44, 46, 41, 31, 13, -12, + -32, -44, -47, -48, -49, -44, -32, -20, -8, 3, 15, 27, 40, 45, 47, 50, + 47, 39, 21, -6, -29, -42, -46, -51, -56, -52, -41, -24, -13, -4, 11, 27, + 41, 51, 52, 53, 52, 45, 29, 2, -25, -45, -50, -52, -57, -56, -49, -32, + -16, -4, 9, 22, 36, 49, 55, 56, 56, 50, 35, 11, -14, -37, -51, -57, + -61, -61, -56, -41, -23, -8, 8, 21, 33, 48, 61, 64, 60, 54, 40, 17, + -8, -34, -52, -59, -62, -63, -60, -49, -30, -14, 2, 19, 33, 47, 60, 66, + 67, 65, 50, 25, -3, -26, -47, -59, -68, -72, -66, -57, -38, -20, -5, 14, + 30, 44, 61, 71, 71, 68, 57, 34, 7, -20, -43, -58, -68, -72, -69, -62, + -45, -25, -10, 7, 24, 42, 59, 70, 74, 73, 65, 46, 16, -15, -38, -53, + -65, -77, -77, -70, -54, -34, -19, 0, 20, 41, 60, 74, 82, 80, 71, 54, + 27, -8, -36, -55, -68, -78, -82, -76, -61, -40, -20, -2, 17, 36, 57, 74, + 83, 82, 74, 62, 39, 3, -31, -49, -62, -75, -84, -84, -69, -47, -27, -13, + 6, 31, 56, 73, 82, 86, 80, 68, 49, 14, -24, -46, -60, -74, -83, -86, + -76, -54, -32, -15, 3, 23, 48, 71, 85, 87, 80, 71, 57, 27, -12, -41, + -57, -68, -78, -88, -84, -64, -41, -23, -5, 16, 40, 65, 84, 90, 87, 77, + 63, 36, -3, -34, -57, -69, -76, -85, -87, -73, -48, -27, -8, 13, 34, 60, + 83, 91, 86, 77, 66, 44, 9, -26, -53, -68, -74, -83, -88, -80, -56, -33, + -13, 9, 29, 55, 79, 93, 89, 76, 67, 52, 21, -15, -46, -69, -74, -77, + -84, -86, -67, -42, -20, 4, 23, 43, 71, 94, 95, 80, 67, 56, 32, 0, + -37, -66, -74, -73, -78, -87, -76, -50, -25, 1, 21, 37, 61, 88, 97, 84, + 67, 57, 38, 8, -25, -59, -77, -77, -76, -81, -80, -61, -34, -6, 20, 36, + 55, 80, 96, 91, 70, 54, 39, 17, -14, -51, -75, -79, -75, -77, -80, -68, + -40, -11, 15, 33, 48, 71, 92, 91, 73, 57, 45, 24, -3, -38, -68, -79, + -77, -76, -80, -74, -51, -19, 12, 32, 46, 65, 88, 96, 83, 59, 40, 24, + 4, -31, -67, -83, -80, -73, -73, -72, -55, -24, 9, 31, 44, 58, 78, 90, + 84, 63, 42, 28, 10, -18, -53, -77, -82, -76, -73, -74, -65, -37, -2, 27, + 42, 55, 73, 88, 90, 72, 47, 28, 13, -12, -45, -74, -84, -78, -70, -68, + -63, -43, -9, 23, 42, 52, 64, 78, 84, 75, 52, 32, 17, -3, -32, -62, + -79, -78, -71, -67, -65, -52, -19, 15, 38, 50, 61, 73, 80, 79, 59, 34, + 18, 3, -21, -51, -75, -81, -72, -64, -61, -54, -31, 4, 31, 48, 55, 63, + 73, 78, 67, 40, 21, 8, -12, -39, -65, -80, -76, -65, -58, -52, -38, -8, + 25, 45, 56, 61, 67, 74, 69, 47, 22, 7, -10, -31, -56, -75, -77, -66, + -57, -49, -37, -14, 16, 40, 53, 57, 61, 67, 69, 55, 30, 11, -6, -25, + -47, -69, -78, -70, -59, -51, -40, -20, 10, 34, 51, 58, 59, 63, 66, 59, + 36, 14, -2, -19, -40, -61, -75, -71, -59, -51, -41, -27, -2, 26, 47, 58, + 58, 59, 64, 63, 46, 19, -2, -17, -35, -56, -71, -75, -64, -50, -40, -26, + -6, 21, 43, 55, 57, 56, 58, 59, 47, 23, 1, -13, -29, -48, -63, -69, + -61, -48, -40, -29, -11, 13, 35, 48, 53, 51, 53, 57, 50, 33, 9, -10, + -25, -42, -56, -65, -64, -51, -40, -29, -13, 9, 30, 44, 50, 48, 47, 50, + 46, 35, 13, -8, -20, -33, -47, -57, -56, -48, -38, -30, -16, 1, 21, 35, + 44, 46, 42, 44, 44, 39, 21, -3, -18, -30, -40, -51, -57, -51, -37, -26, + -14, 0, 16, 33, 42, 43, 37, 34, 37, 35, 22, 1, -17, -27, -34, -41, + -48, -45, -36, -25, -11, 0, 11, 24, 34, 38, 35, 30, 29, 30, 24, 8, + -11, -24, -31, -36, -42, -42, -35, -25, -12, -2, 9, 21, 29, 33, 32, 27, + 25, 26, 23, 9, -8, -21, -31, -34, -36, -37, -33, -26, -13, -2, 8, 18, + 24, 28, 29, 27, 22, 20, 21, 14, -2, -17, -27, -30, -31, -33, -32, -26, + -14, -3, 6, 15, 22, 27, 26, 25, 22, 17, 17, 13, 3, -12, -25, -30, + -31, -30, -27, -24, -14, 0, 8, 16, 20, 22, 22, 21, 16, 11, 13, 13, + 3, -8, -21, -27, -26, -25, -25, -23, -12, 0, 6, 12, 18, 20, 22, 20, + 15, 9, 9, 10, 3, -9, -21, -29, -28, -23, -20, -19, -10, 3, 13, 17, + 19, 19, 21, 17, 11, 4, 1, 4, 0, -8, -17, -25, -24, -21, -19, -16, + -9, 4, 13, 17, 19, 20, 22, 19, 11, 3, -4, -3, -4, -12, -18, -26, + -28, -23, -16, -10, -5, 5, 18, 25, 25, 22, 21, 19, 9, 0, -9, -11, + -10, -13, -16, -24, -27, -22, -14, -8, -2, 7, 17, 25, 25, 22, 20, 17, + 10, -2, -10, -12, -13, -15, -18, -20, -24, -22, -16, -8, 3, 11, 17, 25, + 27, 23, 21, 17, 9, 0, -10, -12, -13, -18, -19, -20, -24, -23, -17, -10, + 0, 11, 19, 26, 30, 26, 24, 20, 12, 3, -8, -15, -18, -22, -25, -25, + -25, -24, -20, -12, 2, 15, 20, 25, 31, 33, 29, 23, 12, 3, -5, -15, + -23, -28, -28, -25, -22, -22, -18, -10, 2, 15, 19, 23, 30, 32, 28, 24, + 15, 7, 1, -13, -23, -27, -29, -28, -26, -24, -20, -14, -2, 13, 20, 24, + 32, 34, 32, 29, 22, 9, -2, -10, -21, -30, -34, -34, -29, -22, -20, -18, + -5, 14, 23, 25, 31, 36, 35, 30, 22, 10, 0, -8, -21, -34, -39, -36, + -32, -27, -20, -15, -5, 14, 27, 28, 32, 36, 35, 33, 25, 14, 0, -11, + -21, -34, -40, -41, -39, -30, -20, -13, -6, 10, 27, 30, 32, 35, 34, 36, + 29, 17, 5, -7, -16, -33, -45, -45, -43, -33, -24, -18, -9, 8, 26, 32, + 33, 39, 38, 36, 31, 20, 10, -6, -19, -32, -45, -47, -46, -39, -25, -12, + -3, 8, 22, 32, 32, 35, 35, 32, 31, 23, 14, 0, -15, -26, -43, -51, + -50, -43, -29, -17, -6, 5, 19, 34, 36, 33, 37, 37, 34, 25, 16, 5, + -11, -26, -41, -51, -55, -51, -36, -21, -7, 7, 16, 28, 37, 35, 35, 36, + 34, 30, 20, 9, -7, -22, -37, -49, -56, -54, -42, -25, -11, 2, 13, 24, + 35, 38, 37, 38, 37, 32, 25, 16, 1, -21, -38, -47, -56, -58, -50, -34, + -14, 4, 13, 20, 31, 40, 39, 35, 36, 34, 28, 20, 5, -15, -33, -44, + -55, -63, -54, -38, -19, -2, 10, 17, 30, 40, 41, 36, 38, 41, 33, 22, + 9, -13, -36, -50, -55, -63, -61, -44, -22, 2, 18, 22, 28, 38, 42, 39, + 34, 35, 34, 27, 14, -7, -29, -43, -51, -60, -63, -50, -30, -10, 8, 16, + 21, 32, 40, 40, 38, 39, 41, 35, 24, 6, -20, -41, -54, -62, -65, -58, + -39, -16, 7, 18, 22, 29, 39, 43, 40, 35, 38, 37, 27, 12, -14, -37, + -51, -58, -64, -64, -47, -22, -2, 14, 18, 24, 36, 44, 45, 41, 43, 43, + 32, 17, -8, -35, -54, -63, -67, -68, -56, -29, -4, 16, 24, 26, 35, 44, + 47, 43, 38, 38, 36, 24, 0, -30, -50, -57, -59, -63, -61, -40, -11, 11, + 20, 20, 26, 39, 48, 46, 40, 39, 42, 33, 12, -20, -47, -58, -60, -62, + -61, -49, -23, 2, 17, 21, 22, 33, 48, 51, 45, 43, 43, 38, 20, -10, + -41, -58, -61, -64, -62, -55, -35, -9, 10, 21, 23, 32, 50, 57, 49, 45, + 45, 43, 26, -6, -38, -58, -62, -65, -67, -61, -44, -15, 10, 23, 26, 28, + 44, 59, 55, 46, 42, 41, 33, 6, -30, -57, -64, -62, -64, -62, -50, -26, + 2, 18, 26, 28, 39, 59, 60, 48, 43, 43, 37, 14, -22, -53, -67, -63, + -65, -66, -55, -33, -2, 19, 28, 31, 37, 55, 64, 53, 41, 39, 37, 20, + -16, -48, -66, -65, -62, -66, -60, -43, -12, 15, 26, 31, 37, 53, 69, 63, + 46, 39, 38, 27, -5, -44, -72, -73, -65, -65, -63, -52, -24, 11, 31, 36, + 38, 48, 65, 70, 53, 38, 34, 28, 5, -35, -69, -78, -70, -65, -63, -53, + -30, 2, 26, 38, 43, 49, 62, 69, 58, 40, 33, 28, 9, -25, -61, -78, + -75, -69, -64, -55, -37, -7, 22, 36, 43, 49, 57, 66, 62, 44, 31, 29, + 15, -16, -52, -76, -77, -69, -63, -57, -44, -16, 14, 33, 42, 48, 54, 65, + 68, 52, 33, 27, 19, -6, -41, -72, -82, -74, -65, -59, -48, -24, 7, 29, + 43, 50, 53, 60, 67, 58, 39, 28, 22, 2, -31, -64, -82, -79, -71, -61, + -49, -31, -2, 22, 40, 51, 55, 58, 65, 63, 46, 29, 21, 9, -21, -56, + -79, -83, -77, -65, -54, -37, -10, 16, 36, 50, 57, 60, 65, 64, 50, 33, + 22, 11, -13, -47, -73, -82, -80, -70, -57, -42, -19, 8, 30, 49, 58, 61, + 62, 64, 56, 41, 24, 11, -6, -35, -66, -80, -82, -75, -61, -45, -25, -2, + 22, 43, 57, 63, 64, 63, 58, 49, 31, 15, -2, -26, -58, -79, -85, -81, + -66, -49, -31, -9, 17, 39, 55, 64, 69, 67, 61, 53, 35, 16, 1, -20, + -49, -75, -86, -85, -74, -54, -34, -11, 11, 33, 53, 64, 70, 68, 59, 51, + 40, 22, 5, -15, -40, -66, -79, -81, -78, -63, -41, -19, 4, 25, 44, 58, + 67, 72, 65, 57, 47, 29, 11, -8, -31, -61, -81, -85, -82, -68, -47, -25, + -3, 21, 44, 59, 68, 73, 68, 56, 47, 33, 15, -7, -27, -52, -76, -82, + -82, -72, -52, -30, -7, 13, 36, 57, 67, 74, 72, 61, 48, 36, 20, -4, + -25, -47, -71, -81, -81, -75, -56, -33, -10, 11, 30, 49, 63, 73, 74, 63, + 48, 37, 25, 6, -20, -41, -63, -79, -81, -77, -65, -43, -19, 4, 25, 45, + 63, 73, 76, 70, 55, 41, 28, 10, -15, -38, -59, -77, -83, -79, -70, -49, + -25, -4, 20, 40, 59, 74, 76, 73, 62, 46, 33, 16, -10, -34, -51, -68, + -83, -85, -75, -58, -34, -11, 14, 35, 55, 73, 79, 76, 69, 51, 33, 20, + -2, -30, -53, -67, -81, -84, -76, -61, -39, -14, 11, 32, 49, 67, 77, 74, + 68, 55, 37, 23, 5, -22, -45, -59, -73, -84, -82, -68, -46, -24, 3, 26, + 43, 62, 75, 74, 72, 61, 42, 25, 10, -15, -40, -57, -70, -83, -84, -71, + -49, -28, -6, 20, 41, 59, 72, 72, 69, 63, 48, 29, 13, -8, -31, -51, + -66, -79, -84, -75, -56, -37, -16, 12, 36, 55, 71, 74, 72, 69, 54, 34, + 16, -5, -28, -47, -61, -75, -85, -80, -60, -38, -20, 4, 30, 53, 68, 71, + 69, 67, 57, 39, 20, 0, -21, -41, -58, -71, -79, -79, -66, -45, -25, -3, + 23, 45, 61, 68, 69, 70, 63, 47, 29, 8, -16, -37, -56, -71, -80, -81, + -71, -52, -30, -7, 17, 41, 60, 67, 67, 68, 65, 50, 30, 10, -14, -31, + -47, -65, -77, -79, -70, -53, -33, -14, 8, 34, 56, 62, 62, 66, 64, 54, + 36, 15, -8, -27, -42, -61, -73, -75, -70, -56, -36, -14, 5, 26, 49, 60, + 59, 61, 60, 54, 42, 23, -2, -22, -35, -53, -69, -75, -70, -58, -41, -20, + -3, 18, 43, 59, 57, 57, 60, 56, 44, 28, 7, -17, -32, -47, -63, -73, + -72, -62, -46, -23, -6, 12, 35, 55, 60, 57, 59, 56, 49, 35, 14, -13, + -28, -40, -58, -72, -73, -62, -50, -31, -13, 5, 30, 51, 59, 56, 58, 61, + 56, 38, 17, -9, -26, -37, -52, -68, -74, -63, -50, -32, -14, 1, 22, 45, + 57, 56, 51, 54, 54, 41, 21, -4, -22, -31, -44, -59, -69, -63, -48, -36, + -21, -7, 11, 35, 52, 56, 53, 54, 58, 48, 30, 8, -17, -32, -43, -57, + -68, -69, -56, -39, -22, -8, 6, 28, 49, 57, 54, 51, 55, 52, 35, 13, + -13, -29, -36, -49, -64, -70, -58, -39, -23, -11, 0, 19, 43, 57, 55, 47, + 49, 55, 43, 18, -9, -28, -35, -42, -57, -69, -65, -45, -25, -11, 1, 14, + 37, 55, 60, 50, 45, 48, 42, 21, -4, -25, -35, -40, -50, -60, -61, -46, + -27, -15, -6, 6, 25, 46, 56, 50, 43, 45, 47, 33, 9, -15, -30, -37, + -45, -58, -64, -56, -36, -18, -8, 4, 18, 40, 58, 59, 47, 39, 41, 35, + 12, -15, -32, -38, -39, -46, -57, -55, -37, -17, -7, 1, 11, 27, 48, 56, + 47, 37, 38, 38, 21, -6, -24, -32, -37, -43, -54, -57, -44, -25, -9, 2, + 11, 24, 44, 57, 51, 38, 32, 31, 21, -5, -28, -35, -36, -36, -45, -51, + -41, -25, -8, 3, 8, 17, 33, 48, 49, 37, 31, 30, 25, 7, -18, -30, + -34, -37, -40, -48, -47, -33, -16, 1, 11, 16, 28, 42, 50, 43, 30, 25, + 22, 10, -12, -28, -33, -34, -35, -41, -44, -33, -18, -2, 9, 12, 20, 32, + 43, 41, 29, 24, 22, 14, -3, -21, -29, -30, -31, -35, -41, -35, -21, -6, + 9, 13, 18, 27, 38, 42, 29, 18, 16, 13, 4, -15, -27, -28, -27, -28, + -34, -34, -23, -10, 5, 11, 14, 22, 32, 37, 31, 20, 16, 12, 6, -9, + -22, -25, -27, -26, -32, -34, -27, -15, 0, 10, 12, 18, 28, 36, 35, 23, + 14, 11, 8, -3, -19, -28, -28, -25, -27, -32, -28, -16, -2, 11, 14, 14, + 22, 30, 31, 24, 15, 11, 8, 2, -11, -22, -25, -25, -26, -30, -28, -18, + -7, 5, 12, 14, 19, 27, 30, 26, 19, 13, 9, 4, -6, -20, -26, -23, + -24, -27, -27, -19, -6, 4, 12, 12, 13, 22, 26, 22, 15, 11, 10, 6, + -2, -12, -19, -19, -21, -25, -25, -20, -11, -3, 5, 9, 13, 19, 24, 24, + 21, 15, 12, 7, 2, -9, -20, -22, -22, -23, -24, -22, -11, -2, 7, 11, + 13, 17, 21, 21, 18, 13, 11, 7, 1, -7, -15, -19, -19, -21, -20, -18, + -12, -4, 2, 8, 11, 15, 17, 16, 15, 13, 11, 8, 4, -3, -11, -16, + -15, -19, -20, -16, -12, -5, 2, 5, 8, 14, 17, 15, 11, 10, 9, 8, + 4, -2, -6, -11, -12, -14, -18, -13, -7, -6, -3, 2, 6, 10, 13, 13, + 9, 8, 9, 6, 1, 0, -5, -9, -12, -12, -13, -12, -4, 1, 3, 4, + 4, 7, 11, 10, 7, 3, 3, 4, 2, -2, -3, -6, -7, -6, -6, -8, + -5, 2, 1, 1, 0, 1, 5, 5, 3, 0, 0, 5, 5, 2, 3, 0, + -3, -5, -6, -8, -7, -2, -3, -4, -2, -2, 3, 6, 4, 1, -3, 1, + 5, 3, 2, 0, -2, -3, -4, -5, -5, 1, 2, -3, -3, -4, -3, 4, + 4, 0, -5, -3, 3, 3, 2, 1, 1, 0, 0, 0, -3, -2, 1, -2, + -4, -3, -4, 1, 5, 2, -5, -7, -2, 2, -2, -2, 0, 2, 3, 2, + 2, 3, 6, 4, -2, -5, -6, -2, 3, -2, -9, -11, -5, 0, -3, -4, + -2, 3, 7, 8, 4, 2, 4, 3, 0, -6, -8, -6, 2, 4, -3, -10, + -10, -5, -2, -4, -5, -3, 5, 11, 11, 8, 5, 5, 4, -2, -9, -9, + -2, 0, -5, -13, -14, -10, -5, -4, -2, 2, 6, 14, 15, 11, 8, 6, + 1, -5, -10, -12, -6, 1, -2, -10, -15, -11, -4, -3, -6, -5, 2, 14, + 19, 14, 10, 10, 8, 3, -6, -15, -12, -4, -4, -12, -18, -17, -10, -2, + 0, 1, 6, 16, 25, 21, 12, 8, 4, -2, -8, -18, -20, -11, -6, -9, + -14, -14, -10, -3, 0, 1, 6, 13, 23, 25, 17, 13, 9, 1, -6, -13, + -18, -14, -11, -13, -17, -19, -14, -8, -3, 1, 7, 14, 24, 30, 24, 16, + 12, 4, -5, -11, -18, -19, -15, -12, -14, -19, -18, -14, -9, 0, 8, 13, + 19, 27, 28, 22, 18, 9, -4, -11, -14, -16, -15, -16, -16, -17, -16, -14, + -13, -6, 4, 12, 19, 26, 31, 27, 19, 13, 3, -8, -12, -16, -18, -19, + -17, -16, -20, -18, -15, -10, 1, 10, 18, 24, 31, 30, 22, 18, 9, -4, + -10, -14, -17, -20, -22, -19, -19, -22, -18, -13, -2, 9, 16, 21, 29, 36, + 29, 19, 12, 1, -7, -10, -15, -22, -24, -20, -18, -21, -21, -17, -8, 7, + 16, 23, 27, 33, 35, 26, 17, 7, -5, -11, -14, -22, -27, -24, -19, -22, + -25, -19, -11, 5, 16, 21, 25, 33, 38, 31, 18, 9, -2, -10, -13, -22, + -29, -28, -21, -18, -24, -22, -15, -3, 14, 21, 24, 30, 38, 36, 24, 13, + 4, -5, -9, -16, -28, -32, -25, -21, -25, -27, -18, -7, 8, 18, 24, 31, + 40, 40, 29, 16, 6, -3, -8, -16, -27, -31, -27, -22, -24, -27, -21, -10, + 4, 16, 22, 28, 37, 40, 33, 19, 7, 1, -5, -12, -23, -32, -28, -23, + -23, -27, -26, -15, -2, 13, 21, 25, 34, 41, 38, 28, 14, 4, -3, -11, + -22, -34, -35, -30, -26, -28, -29, -20, -3, 14, 24, 27, 32, 41, 42, 34, + 17, 4, -4, -11, -20, -32, -38, -33, -28, -27, -27, -22, -9, 7, 20, 29, + 34, 39, 40, 37, 24, 10, 2, -7, -16, -28, -40, -40, -33, -29, -28, -27, + -16, 5, 21, 28, 32, 36, 41, 40, 30, 12, 1, -6, -11, -22, -37, -42, + -34, -30, -29, -27, -20, -3, 16, 27, 32, 34, 39, 41, 35, 20, 6, -4, + -11, -16, -32, -45, -41, -33, -31, -27, -23, -10, 13, 28, 33, 35, 38, 39, + 36, 25, 8, -6, -11, -14, -26, -42, -45, -34, -29, -25, -23, -15, 6, 26, + 36, 36, 36, 37, 36, 29, 14, -2, -12, -14, -23, -42, -50, -42, -32, -23, + -18, -15, 3, 25, 38, 39, 35, 35, 37, 33, 18, -3, -15, -18, -20, -34, + -48, -47, -34, -22, -14, -12, -4, 17, 35, 41, 37, 34, 33, 33, 24, 6, + -13, -22, -22, -30, -45, -51, -39, -23, -10, -6, -3, 13, 32, 41, 37, 30, + 29, 31, 27, 10, -10, -22, -23, -26, -38, -48, -44, -28, -12, -5, -3, 9, + 27, 38, 38, 32, 28, 29, 27, 17, -4, -21, -26, -27, -35, -47, -49, -33, + -12, 2, 5, 9, 23, 35, 40, 34, 21, 23, 25, 22, 5, -20, -28, -28, + -29, -39, -50, -43, -19, 3, 10, 7, 15, 29, 41, 43, 28, 22, 23, 22, + 12, -16, -33, -32, -32, -38, -46, -43, -21, 3, 15, 13, 16, 29, 35, 35, + 27, 19, 19, 19, 15, -8, -30, -31, -30, -32, -40, -44, -29, -2, 18, 17, + 11, 22, 34, 37, 32, 21, 18, 20, 17, -2, -28, -37, -34, -34, -38, -42, + -30, -7, 16, 22, 16, 20, 31, 31, 29, 23, 17, 18, 19, 6, -21, -37, + -35, -34, -35, -38, -35, -15, 14, 27, 21, 13, 23, 31, 31, 26, 16, 12, + 16, 12, -10, -35, -39, -35, -36, -36, -34, -21, 6, 24, 24, 16, 20, 29, + 28, 27, 22, 16, 17, 15, -4, -29, -41, -39, -40, -39, -36, -29, -6, 20, + 27, 21, 19, 28, 33, 31, 27, 18, 14, 13, 2, -22, -41, -43, -40, -39, + -34, -28, -12, 16, 28, 24, 19, 25, 29, 27, 24, 19, 15, 12, 4, -15, + -34, -41, -40, -37, -32, -26, -18, 5, 24, 24, 20, 21, 26, 27, 26, 24, + 18, 12, 6, -9, -30, -44, -45, -41, -33, -26, -19, -2, 23, 29, 24, 22, + 24, 28, 25, 22, 18, 13, 7, -7, -24, -40, -46, -42, -36, -28, -21, -6, + 15, 28, 25, 22, 25, 29, 28, 23, 20, 14, 6, -6, -22, -40, -47, -42, + -36, -28, -23, -10, 13, 30, 28, 21, 23, 27, 28, 21, 18, 16, 9, -2, + -17, -33, -44, -44, -38, -31, -23, -14, 5, 25, 32, 25, 23, 26, 29, 24, + 16, 13, 8, -2, -15, -31, -43, -44, -37, -30, -23, -14, 1, 21, 31, 27, + 22, 24, 28, 25, 17, 13, 10, 3, -10, -27, -40, -44, -38, -32, -26, -17, + -3, 16, 31, 31, 25, 25, 30, 29, 17, 8, 7, 3, -8, -25, -39, -43, + -37, -31, -27, -18, -4, 13, 29, 32, 26, 24, 27, 27, 17, 9, 8, 6, + -5, -20, -34, -39, -37, -34, -30, -21, -8, 6, 23, 34, 31, 29, 28, 27, + 22, 13, 6, 5, -4, -18, -34, -40, -37, -34, -29, -23, -10, 5, 21, 32, + 29, 27, 29, 26, 20, 12, 4, 3, 0, -12, -28, -37, -35, -31, -29, -23, + -13, 1, 16, 30, 33, 29, 27, 25, 21, 15, 5, -2, -3, -9, -22, -35, + -36, -31, -29, -24, -14, 0, 12, 27, 35, 31, 29, 26, 21, 16, 8, -2, + -3, -7, -19, -34, -36, -32, -31, -28, -18, -3, 11, 22, 32, 32, 30, 29, + 23, 16, 11, 2, -3, -6, -17, -32, -37, -32, -30, -31, -23, -6, 9, 18, + 30, 36, 32, 31, 25, 17, 13, 4, -6, -8, -14, -26, -36, -34, -31, -31, + -25, -11, 6, 16, 24, 34, 35, 33, 28, 17, 16, 10, -3, -9, -13, -23, + -34, -36, -32, -31, -27, -16, 2, 16, 22, 30, 35, 33, 30, 21, 15, 11, + 0, -7, -11, -20, -31, -35, -31, -31, -29, -21, -6, 13, 21, 25, 32, 34, + 33, 26, 18, 13, 4, -6, -10, -19, -29, -34, -34, -29, -27, -24, -12, 7, + 20, 25, 30, 33, 32, 29, 21, 13, 7, -5, -11, -18, -28, -35, -36, -29, + -25, -24, -16, 3, 21, 26, 28, 34, 37, 34, 26, 12, 4, -5, -13, -20, + -30, -35, -39, -35, -24, -19, -13, -2, 15, 27, 30, 32, 34, 31, 28, 18, + 5, -6, -15, -20, -24, -31, -37, -35, -24, -19, -16, -9, 8, 24, 30, 30, + 33, 35, 35, 24, 5, -5, -11, -20, -27, -34, -40, -39, -30, -21, -16, -9, + 4, 20, 32, 36, 36, 36, 35, 31, 13, -3, -13, -23, -27, -29, -41, -44, + -33, -19, -11, -10, -4, 14, 32, 38, 34, 33, 36, 33, 18, -4, -13, -20, + -25, -28, -37, -43, -34, -22, -14, -8, -4, 9, 26, 39, 38, 35, 35, 34, + 23, 3, -12, -21, -28, -28, -31, -41, -40, -27, -15, -7, -6, 2, 20, 37, + 42, 36, 34, 35, 28, 9, -10, -18, -24, -26, -29, -38, -42, -32, -21, -11, + -6, -3, 12, 33, 45, 41, 37, 37, 29, 13, -4, -17, -26, -28, -28, -33, + -39, -37, -26, -15, -8, -7, 6, 29, 47, 46, 39, 34, 30, 20, 1, -18, + -26, -26, -25, -29, -37, -40, -31, -17, -8, -7, 0, 20, 42, 51, 45, 38, + 30, 18, 7, -10, -24, -27, -26, -24, -29, -38, -37, -27, -14, -9, -6, 11, + 36, 51, 47, 42, 34, 24, 14, -3, -20, -25, -23, -22, -26, -37, -42, -33, + -17, -8, -7, 4, 28, 50, 54, 45, 35, 24, 15, 3, -16, -24, -25, -22, + -23, -32, -41, -37, -22, -11, -8, 0, 21, 44, 54, 46, 34, 26, 18, 7, + -11, -22, -21, -20, -21, -28, -40, -43, -30, -15, -10, -3, 16, 40, 56, 52, + 37, 24, 16, 9, -6, -21, -22, -18, -17, -22, -35, -43, -34, -21, -14, -9, + 7, 34, 53, 54, 40, 29, 21, 14, 4, -14, -21, -17, -17, -22, -33, -46, + -45, -31, -16, -8, 4, 25, 50, 60, 49, 31, 20, 15, 9, -5, -17, -18, + -15, -17, -26, -42, -50, -40, -24, -11, -2, 18, 43, 56, 52, 35, 21, 17, + 11, 0, -12, -18, -14, -15, -22, -36, -50, -46, -30, -15, -3, 12, 35, 53, + 55, 41, 24, 18, 12, 5, -4, -15, -18, -15, -20, -33, -46, -49, -37, -21, + -7, 7, 25, 46, 54, 45, 27, 18, 14, 10, 3, -8, -15, -16, -18, -28, + -41, -49, -44, -29, -12, 4, 17, 35, 49, 49, 34, 19, 16, 15, 9, 1, + -10, -14, -16, -24, -38, -50, -49, -36, -18, -3, 10, 26, 43, 49, 38, 22, + 18, 20, 16, 9, -5, -13, -16, -23, -36, -50, -53, -43, -25, -8, 6, 21, + 38, 48, 44, 27, 19, 21, 19, 13, -2, -13, -17, -21, -30, -45, -52, -46, + -29, -10, 3, 14, 29, 42, 44, 30, 17, 19, 21, 17, 6, -8, -14, -19, + -26, -39, -49, -48, -36, -18, -2, 11, 27, 37, 42, 37, 22, 18, 21, 19, + 9, -5, -13, -18, -24, -33, -45, -46, -39, -24, -8, 6, 20, 33, 40, 38, + 27, 19, 22, 23, 17, 4, -8, -14, -22, -29, -43, -48, -43, -32, -16, -2, + 13, 25, 34, 39, 33, 23, 21, 23, 20, 9, -4, -11, -19, -25, -33, -43, + -42, -34, -20, -7, 3, 14, 24, 32, 31, 22, 20, 26, 28, 20, 6, -5, + -11, -18, -28, -42, -44, -38, -28, -15, -5, 8, 19, 28, 31, 24, 21, 25, + 27, 22, 10, 0, -6, -12, -22, -34, -38, -34, -30, -20, -11, 0, 11, 20, + 26, 23, 19, 22, 27, 25, 17, 7, -2, -7, -17, -29, -35, -35, -34, -26, + -16, -5, 7, 15, 23, 28, 24, 21, 22, 24, 20, 11, -2, -8, -14, -24, + -29, -31, -31, -27, -18, -9, 0, 8, 15, 22, 23, 20, 21, 24, 24, 19, + 7, -4, -10, -19, -26, -32, -34, -33, -24, -12, -2, 6, 14, 22, 26, 23, + 22, 22, 22, 21, 10, 0, -6, -15, -21, -24, -28, -31, -28, -17, -7, 2, + 7, 13, 19, 23, 23, 21, 19, 21, 18, 8, -2, -11, -17, -21, -24, -30, + -33, -25, -11, 0, 4, 9, 16, 20, 21, 20, 18, 18, 20, 14, 4, -6, + -12, -15, -17, -25, -32, -32, -20, -6, -3, -3, 7, 18, 23, 19, 16, 19, + 26, 24, 11, 0, -6, -9, -15, -25, -33, -35, -26, -15, -9, -6, 5, 17, + 22, 21, 17, 18, 25, 26, 16, 4, -5, -7, -9, -18, -29, -38, -35, -21, + -11, -9, -4, 9, 22, 25, 20, 16, 22, 30, 24, 8, -4, -5, -5, -13, + -25, -36, -38, -26, -16, -11, -10, 2, 19, 25, 18, 12, 19, 30, 28, 14, + 1, -2, 3, -3, -17, -31, -36, -29, -21, -18, -19, -11, 7, 20, 16, 10, + 16, 30, 36, 24, 8, 4, 8, 6, -12, -32, -40, -35, -26, -21, -20, -14, + 2, 19, 20, 10, 12, 24, 35, 29, 13, 5, 7, 9, -3, -23, -37, -37, + -31, -23, -21, -19, -8, 12, 19, 10, 6, 19, 36, 37, 23, 11, 12, 16, + 7, -15, -35, -43, -38, -30, -27, -23, -16, 2, 18, 16, 7, 13, 30, 38, + 29, 17, 12, 16, 15, -4, -27, -40, -39, -32, -28, -28, -24, -8, 12, 14, + 5, 7, 26, 40, 36, 24, 18, 21, 21, 4, -20, -38, -41, -37, -34, -30, + -26, -15, 4, 14, 7, 3, 18, 37, 41, 33, 24, 22, 25, 14, -10, -33, + -44, -42, -36, -32, -29, -22, -6, 10, 9, 2, 9, 29, 40, 37, 32, 28, + 29, 21, 0, -24, -39, -44, -44, -38, -31, -24, -16, 0, 7, 3, 8, 24, + 38, 43, 41, 32, 28, 25, 9, -15, -34, -44, -44, -39, -31, -26, -20, -10, + 3, 2, 1, 14, 32, 44, 46, 39, 33, 31, 20, -7, -31, -45, -47, -44, + -38, -30, -26, -16, 0, 5, 4, 12, 30, 45, 52, 47, 36, 30, 22, 0, + -24, -40, -50, -49, -42, -31, -24, -19, -10, -3, 3, 11, 24, 39, 51, 55, + 49, 37, 27, 8, -18, -36, -50, -54, -47, -36, -29, -25, -16, -6, 4, 10, + 18, 34, 52, 59, 53, 39, 28, 15, -8, -29, -45, -53, -51, -43, -34, -29, + -23, -14, -4, 7, 17, 33, 52, 62, 61, 50, 37, 23, -4, -28, -44, -55, + -55, -48, -38, -30, -25, -18, -8, 5, 13, 25, 46, 61, 65, 57, 43, 30, + 8, -17, -36, -50, -55, -53, -47, -39, -32, -24, -15, -3, 11, 25, 45, 62, + 68, 63, 51, 37, 14, -14, -34, -46, -56, -57, -51, -44, -33, -25, -18, -6, + 8, 19, 36, 55, 67, 65, 53, 42, 23, -4, -26, -40, -50, -56, -54, -49, + -41, -31, -23, -12, 1, 15, 34, 53, 65, 68, 59, 49, 33, 6, -21, -37, + -47, -57, -60, -56, -48, -38, -28, -16, -2, 14, 33, 51, 64, 70, 63, 53, + 38, 13, -14, -34, -44, -53, -59, -59, -53, -42, -30, -19, -8, 5, 26, 47, + 61, 68, 64, 57, 48, 26, -3, -26, -39, -49, -58, -63, -59, -49, -37, -24, + -13, 1, 20, 42, 55, 65, 69, 64, 54, 34, 7, -18, -34, -44, -55, -65, + -64, -54, -42, -31, -19, -8, 12, 37, 54, 61, 67, 67, 60, 46, 22, -8, + -29, -40, -50, -64, -70, -63, -50, -34, -21, -13, 2, 28, 51, 62, 68, 68, + 61, 51, 32, 3, -23, -36, -47, -60, -70, -67, -58, -44, -27, -14, -2, 22, + 45, 58, 65, 70, 68, 56, 38, 16, -11, -32, -45, -58, -69, -70, -62, -52, + -34, -17, -6, 13, 38, 54, 64, 70, 67, 59, 47, 29, -2, -28, -40, -51, + -65, -74, -67, -54, -37, -20, -11, 5, 33, 53, 59, 63, 67, 62, 51, 34, + 7, -20, -35, -46, -59, -72, -70, -60, -46, -27, -12, 1, 24, 47, 60, 64, + 69, 66, 54, 39, 15, -13, -32, -44, -54, -68, -71, -60, -48, -32, -18, -7, + 14, 38, 54, 61, 68, 70, 60, 46, 26, -2, -23, -38, -50, -63, -72, -68, + -55, -39, -24, -13, 5, 31, 52, 61, 67, 71, 64, 53, 34, 7, -21, -36, + -46, -57, -69, -72, -60, -42, -27, -17, -2, 21, 45, 58, 65, 69, 66, 57, + 42, 15, -13, -30, -43, -54, -66, -72, -65, -47, -30, -18, -5, 15, 40, 57, + 64, 67, 62, 56, 46, 23, -6, -27, -39, -50, -58, -67, -67, -51, -32, -20, + -9, 9, 31, 51, 60, 64, 64, 58, 48, 27, 1, -20, -34, -46, -56, -65, + -70, -57, -37, -22, -14, 2, 26, 48, 62, 66, 64, 59, 51, 34, 8, -18, + -31, -42, -52, -61, -70, -63, -42, -24, -15, -3, 19, 43, 60, 63, 60, 57, + 52, 39, 14, -14, -28, -36, -46, -54, -65, -66, -49, -29, -17, -9, 10, 33, + 54, 64, 62, 58, 53, 42, 23, -5, -25, -35, -46, -54, -63, -67, -54, -33, + -17, -7, 7, 30, 51, 61, 58, 55, 51, 43, 28, 3, -21, -30, -37, -46, + -56, -63, -56, -39, -22, -12, -5, 16, 40, 57, 58, 55, 53, 48, 38, 19, + -10, -27, -35, -45, -56, -66, -65, -49, -28, -14, -6, 8, 34, 57, 60, 55, + 54, 50, 42, 26, -4, -28, -35, -42, -52, -62, -63, -51, -32, -14, -5, 3, + 24, 47, 57, 53, 50, 47, 41, 33, 11, -20, -35, -40, -46, -56, -65, -58, + -38, -17, -4, 1, 15, 41, 57, 55, 47, 45, 42, 35, 17, -13, -33, -38, + -41, -49, -58, -55, -41, -21, -4, 0, 7, 29, 50, 52, 45, 42, 40, 37, + 25, 0, -28, -38, -38, -44, -53, -58, -46, -26, -6, 3, 4, 18, 42, 53, + 47, 41, 39, 37, 30, 10, -21, -41, -43, -41, -47, -54, -46, -29, -8, 7, + 9, 13, 31, 46, 45, 37, 33, 33, 28, 15, -10, -35, -42, -38, -39, -45, + -46, -32, -10, 6, 9, 8, 19, 38, 44, 38, 30, 29, 30, 19, -3, -29, + -42, -38, -34, -40, -43, -32, -14, 3, 11, 11, 15, 30, 41, 39, 30, 25, + 25, 19, 4, -21, -40, -42, -32, -30, -33, -29, -15, 2, 11, 10, 8, 17, + 30, 35, 30, 23, 24, 23, 11, -11, -32, -43, -34, -26, -29, -29, -18, -3, + 9, 12, 9, 12, 26, 35, 32, 21, 18, 18, 12, -6, -29, -43, -36, -22, + -22, -25, -15, 1, 10, 11, 10, 8, 17, 29, 29, 21, 16, 17, 15, 2, + -21, -39, -39, -24, -17, -20, -16, -5, 9, 13, 10, 7, 12, 24, 28, 23, + 14, 12, 11, 4, -14, -33, -39, -28, -15, -14, -12, -6, 5, 11, 9, 7, + 7, 16, 26, 25, 16, 10, 11, 6, -8, -24, -37, -32, -17, -12, -11, -5, + 5, 11, 11, 10, 7, 12, 21, 21, 16, 7, 4, 3, -6, -20, -32, -32, + -20, -8, -5, 0, 5, 11, 11, 9, 8, 8, 13, 17, 16, 9, 3, 2, + -3, -13, -25, -31, -23, -9, -4, -2, 5, 11, 14, 11, 7, 6, 12, 15, + 12, 5, -2, -2, -3, -11, -22, -29, -24, -9, 0, 3, 8, 13, 13, 12, + 8, 4, 5, 7, 9, 6, -3, -5, -4, -5, -14, -24, -23, -13, 0, 4, + 6, 10, 14, 14, 9, 3, 3, 5, 6, 4, -4, -6, -5, -5, -9, -18, + -20, -15, -4, 6, 9, 11, 13, 13, 10, 5, 1, 0, -3, 0, -4, -6, + -6, -5, -4, -11, -16, -16, -9, 3, 8, 11, 11, 10, 11, 8, 3, -2, + -5, -4, -3, -5, -6, -6, -2, -5, -12, -15, -13, -2, 8, 9, 11, 11, + 11, 7, 4, 0, -6, -6, -4, -4, -6, -6, -2, 0, -7, -13, -15, -5, + 8, 13, 12, 9, 11, 9, 4, -5, -11, -11, -8, -5, -5, -5, 0, 4, + 3, -4, -11, -8, 3, 11, 12, 8, 7, 4, 2, -2, -10, -14, -13, -7, + -3, -4, -2, 3, 4, 1, -8, -8, 3, 13, 17, 12, 11, 7, 1, -6, + -16, -21, -19, -13, -7, -2, 3, 7, 10, 10, 1, -6, -2, 8, 14, 12, + 10, 4, -2, -6, -15, -21, -20, -15, -8, -2, 3, 5, 9, 14, 5, -6, + 1, 12, 18, 14, 9, 7, 2, -4, -18, -28, -27, -22, -12, -5, 3, 9, + 13, 18, 16, 5, 1, 7, 14, 13, 8, 5, -5, -9, -17, -26, -26, -23, + -15, -4, 5, 8, 11, 17, 17, 7, 2, 7, 16, 18, 10, 4, -2, -6, + -16, -31, -33, -27, -18, -9, 0, 7, 12, 18, 22, 16, 9, 9, 16, 20, + 13, 5, -2, -9, -18, -33, -37, -29, -22, -13, -4, 7, 15, 21, 25, 21, + 15, 13, 17, 20, 14, 5, -3, -8, -18, -35, -42, -36, -24, -16, -6, 5, + 13, 23, 27, 25, 20, 17, 19, 20, 15, 5, -3, -8, -21, -35, -45, -39, + -25, -18, -11, 3, 16, 25, 29, 27, 26, 24, 23, 21, 17, 8, -4, -12, + -23, -35, -46, -46, -34, -22, -15, -3, 13, 25, 31, 33, 34, 31, 28, 25, + 20, 11, -4, -12, -22, -38, -49, -51, -39, -26, -21, -11, 8, 24, 34, 35, + 36, 37, 35, 29, 21, 13, 0, -11, -20, -36, -48, -52, -46, -31, -22, -14, + 1, 19, 34, 38, 39, 40, 38, 34, 24, 15, 0, -14, -21, -34, -47, -53, + -50, -35, -22, -17, -5, 13, 31, 37, 38, 42, 41, 37, 28, 21, 9, -8, + -19, -30, -44, -50, -53, -46, -32, -23, -11, 7, 26, 39, 43, 49, 48, 42, + 32, 20, 9, -9, -21, -31, -46, -52, -54, -50, -35, -24, -13, 4, 23, 40, + 46, 48, 49, 46, 37, 26, 13, -4, -20, -29, -42, -50, -53, -54, -43, -31, + -21, -2, 17, 36, 47, 53, 56, 51, 42, 29, 17, 3, -16, -30, -41, -51, + -55, -57, -51, -35, -24, -9, 11, 30, 47, 53, 57, 55, 46, 34, 20, 6, + -12, -29, -43, -52, -55, -55, -55, -42, -29, -12, 8, 25, 41, 55, 62, 59, + 51, 37, 23, 10, -6, -24, -40, -51, -56, -58, -58, -48, -33, -19, 2, 22, + 41, 55, 61, 61, 56, 45, 28, 11, -3, -19, -37, -51, -57, -58, -58, -54, + -39, -23, -2, 20, 36, 52, 64, 65, 58, 48, 33, 19, 4, -13, -35, -51, + -58, -61, -62, -60, -47, -29, -7, 17, 34, 50, 67, 70, 62, 50, 35, 20, + 6, -8, -29, -47, -57, -62, -61, -60, -54, -37, -15, 10, 29, 44, 60, 68, + 66, 56, 42, 24, 12, 1, -19, -41, -55, -60, -62, -61, -57, -43, -21, 7, + 24, 36, 53, 66, 67, 59, 46, 30, 15, 5, -11, -32, -48, -58, -63, -62, + -59, -50, -32, -3, 22, 35, 49, 60, 66, 63, 53, 38, 19, 8, -5, -25, + -43, -57, -64, -64, -62, -54, -39, -13, 16, 32, 46, 59, 65, 66, 56, 45, + 26, 11, 3, -17, -39, -56, -65, -67, -62, -56, -44, -21, 10, 29, 40, 54, + 63, 68, 61, 49, 33, 13, 2, -14, -34, -50, -64, -67, -63, -56, -44, -26, + 2, 27, 38, 49, 57, 64, 61, 50, 36, 17, 6, -7, -27, -44, -60, -67, + -63, -57, -48, -32, -7, 22, 36, 44, 53, 60, 62, 55, 41, 21, 7, -3, + -20, -40, -58, -68, -65, -57, -47, -34, -14, 16, 37, 42, 47, 55, 59, 53, + 42, 27, 10, -2, -14, -30, -47, -60, -63, -57, -49, -38, -20, 5, 30, 40, + 44, 52, 57, 57, 46, 31, 13, -2, -12, -27, -44, -57, -64, -61, -50, -38, + -20, 2, 25, 39, 41, 49, 55, 54, 45, 32, 17, 0, -12, -23, -37, -50, + -59, -61, -52, -38, -22, -6, 17, 35, 39, 42, 48, 53, 48, 36, 22, 4, + -9, -18, -30, -45, -56, -59, -54, -42, -27, -10, 12, 29, 37, 38, 44, 50, + 47, 37, 25, 9, -5, -13, -23, -38, -50, -55, -54, -45, -32, -17, 5, 25, + 34, 35, 39, 46, 48, 40, 29, 13, -3, -11, -21, -33, -44, -51, -54, -47, + -34, -17, 2, 21, 32, 34, 34, 38, 42, 39, 27, 15, 1, -7, -13, -25, + -36, -45, -49, -46, -36, -23, -6, 15, 27, 31, 31, 34, 39, 38, 30, 18, + 3, -6, -10, -19, -32, -40, -46, -45, -36, -24, -11, 8, 24, 29, 27, 29, + 34, 36, 30, 18, 4, -5, -5, -12, -25, -34, -39, -41, -37, -24, -11, 4, + 18, 24, 25, 25, 29, 29, 26, 19, 5, -6, -6, -6, -18, -28, -33, -37, + -34, -24, -11, 2, 15, 24, 23, 20, 24, 27, 22, 14, 4, -4, -4, -5, + -15, -24, -26, -29, -32, -27, -13, 2, 14, 21, 21, 18, 21, 23, 20, 13, + 5, -3, -5, -4, -9, -16, -21, -25, -28, -25, -14, 1, 10, 16, 19, 16, + 16, 18, 16, 11, 5, -2, -5, -4, -6, -12, -17, -20, -22, -22, -17, -4, + 8, 13, 16, 15, 13, 15, 14, 10, 4, -4, -6, -6, -5, -7, -11, -15, + -17, -17, -15, -3, 10, 13, 14, 11, 7, 8, 9, 5, -3, -8, -7, -4, + -2, -2, -6, -10, -9, -10, -12, -5, 11, 15, 13, 11, 5, 6, 7, 3, + -6, -10, -8, -6, -6, -2, 1, -2, -6, -6, -7, -5, 8, 14, 10, 7, + 4, 0, 1, -2, -6, -12, -11, -6, -2, 4, 8, 4, -2, -2, -4, -5, + 3, 12, 8, 5, 4, 0, 0, -2, -8, -13, -15, -12, -7, -3, 6, 10, + 7, 5, 6, 4, 6, 14, 10, 3, 0, -6, -10, -7, -10, -16, -19, -15, + -8, 0, 11, 17, 13, 10, 11, 7, 5, 8, 9, 2, -4, -7, -12, -10, + -10, -16, -21, -19, -13, -4, 10, 21, 22, 17, 17, 14, 9, 9, 9, 3, + -7, -12, -17, -16, -14, -20, -25, -21, -15, -5, 10, 23, 27, 25, 22, 18, + 11, 8, 4, -2, -9, -14, -18, -19, -14, -15, -23, -25, -20, -10, 9, 22, + 29, 29, 26, 23, 16, 12, 6, 1, -6, -14, -18, -22, -20, -19, -27, -28, + -25, -18, 0, 19, 32, 36, 33, 31, 23, 14, 7, 1, -4, -15, -23, -25, + -24, -19, -25, -32, -29, -20, -3, 16, 31, 40, 38, 36, 29, 16, 9, 1, + -4, -12, -23, -26, -28, -24, -26, -34, -33, -24, -8, 12, 29, 41, 44, 44, + 37, 22, 11, 4, -4, -11, -24, -31, -32, -31, -30, -36, -39, -30, -11, 11, + 29, 43, 51, 50, 44, 32, 15, 4, -4, -11, -24, -32, -33, -33, -34, -38, + -42, -35, -17, 4, 24, 42, 56, 60, 52, 38, 19, 7, 1, -13, -28, -37, + -37, -35, -37, -39, -43, -37, -19, 3, 22, 41, 57, 64, 57, 44, 26, 7, + -2, -11, -24, -35, -41, -40, -38, -39, -43, -40, -24, 0, 20, 37, 55, 65, + 63, 50, 32, 9, -4, -10, -24, -36, -42, -42, -41, -41, -41, -39, -26, -2, + 19, 34, 51, 64, 66, 55, 38, 15, -3, -8, -20, -34, -42, -44, -43, -44, + -45, -45, -35, -12, 14, 31, 50, 66, 73, 65, 49, 28, 7, -6, -18, -35, + -45, -49, -51, -53, -51, -47, -37, -16, 10, 30, 49, 69, 78, 72, 56, 35, + 14, -4, -17, -33, -46, -51, -55, -56, -54, -51, -40, -20, 5, 26, 44, 64, + 76, 77, 64, 41, 19, 1, -14, -30, -43, -50, -57, -60, -58, -54, -43, -24, + -2, 21, 39, 61, 76, 79, 72, 52, 28, 9, -10, -26, -41, -49, -54, -61, + -62, -59, -51, -33, -10, 14, 34, 55, 75, 81, 79, 63, 39, 19, -2, -23, + -40, -51, -56, -64, -67, -64, -56, -39, -16, 9, 29, 51, 73, 83, 82, 73, + 50, 27, 9, -18, -40, -52, -56, -63, -69, -69, -61, -43, -20, 2, 21, 42, + 66, 81, 82, 76, 59, 36, 19, -6, -33, -50, -57, -61, -71, -76, -68, -52, + -28, -2, 17, 36, 62, 83, 86, 82, 69, 43, 22, 2, -28, -51, -60, -63, + -67, -76, -74, -57, -34, -7, 14, 29, 53, 76, 87, 84, 75, 54, 33, 14, + -18, -46, -58, -62, -69, -80, -84, -68, -44, -18, 7, 26, 49, 75, 91, 92, + 82, 64, 42, 21, -8, -43, -63, -68, -68, -75, -86, -76, -48, -22, 4, 23, + 41, 66, 87, 92, 83, 69, 51, 31, 6, -31, -59, -67, -69, -74, -88, -87, + -62, -34, -7, 17, 36, 62, 87, 96, 90, 76, 60, 39, 14, -23, -58, -70, + -71, -73, -83, -89, -68, -37, -13, 9, 26, 51, 79, 94, 91, 80, 68, 52, + 28, -8, -48, -67, -70, -73, -84, -96, -83, -49, -22, 0, 20, 44, 75, 96, + 98, 88, 75, 61, 40, 6, -39, -67, -72, -75, -83, -95, -91, -60, -29, -7, + 13, 36, 66, 89, 97, 92, 78, 65, 50, 22, -21, -58, -71, -73, -78, -91, + -98, -79, -45, -15, 4, 25, 56, 84, 101, 99, 86, 73, 60, 35, -9, -53, + -72, -77, -80, -90, -98, -85, -51, -20, -2, 18, 48, 77, 96, 99, 87, 75, + 62, 46, 9, -39, -68, -75, -75, -83, -95, -94, -67, -30, -7, 8, 34, 68, + 92, 102, 93, 82, 72, 58, 26, -24, -61, -75, -78, -85, -97, -99, -78, -42, + -12, 6, 28, 59, 87, 102, 99, 86, 74, 62, 38, -7, -52, -76, -81, -83, + -93, -100, -90, -57, -23, -2, 18, 48, 80, 102, 103, 92, 81, 71, 51, 9, + -41, -72, -83, -85, -93, -100, -92, -65, -32, -7, 13, 39, 72, 97, 103, 95, + 85, 73, 55, 25, -21, -61, -79, -83, -90, -99, -97, -77, -45, -17, 1, 24, + 59, 93, 107, 103, 92, 85, 72, 42, -6, -54, -80, -86, -91, -104, -105, -87, + -56, -23, 0, 18, 48, 85, 106, 106, 96, 87, 77, 52, 13, -35, -71, -84, + -88, -98, -106, -96, -70, -40, -14, 6, 31, 70, 103, 111, 103, 95, 88, 68, + 29, -19, -61, -84, -91, -99, -106, -101, -80, -51, -22, 2, 23, 56, 91, 109, + 108, 98, 89, 76, 45, 1, -44, -76, -87, -92, -102, -104, -90, -64, -34, -11, + 8, 37, 78, 108, 113, 106, 96, 85, 61, 19, -29, -68, -88, -94, -102, -104, + -93, -73, -46, -21, 2, 28, 63, 98, 113, 109, 100, 89, 70, 33, -14, -55, + -81, -91, -98, -104, -98, -79, -54, -30, -9, 18, 52, 89, 108, 110, 104, 96, + 79, 46, 2, -40, -71, -90, -100, -104, -100, -86, -67, -44, -19, 7, 40, 77, + 105, 115, 109, 99, 86, 58, 17, -29, -63, -86, -97, -101, -101, -92, -74, -50, + -26, -4, 28, 66, 98, 114, 113, 102, 90, 68, 33, -15, -53, -76, -93, -101, + -104, -96, -79, -57, -34, -15, 15, 56, 90, 110, 115, 105, 93, 75, 44, 0, + -43, -68, -86, -98, -101, -98, -83, -65, -42, -22, 4, 41, 79, 104, 113, 107, + 96, 81, 57, 16, -31, -59, -79, -95, -101, -100, -90, -71, -49, -30, -9, 28, + 67, 97, 110, 107, 97, 86, 65, 30, -14, -47, -67, -84, -98, -102, -96, -79, + -59, -41, -22, 14, 53, 90, 110, 111, 101, 90, 75, 45, 2, -39, -64, -79, + -93, -102, -101, -87, -64, -44, -28, 0, 39, 81, 108, 110, 102, 93, 82, 58, + 18, -25, -54, -70, -85, -101, -103, -94, -72, -53, -39, -14, 25, 70, 104, 112, + 103, 96, 88, 70, 34, -13, -48, -65, -78, -97, -108, -101, -79, -55, -42, -24, + 11, 56, 96, 111, 103, 94, 90, 77, 46, 5, -34, -56, -71, -92, -109, -109, + -91, -64, -46, -30, 0, 44, 89, 112, 108, 95, 88, 80, 57, 16, -27, -54, + -66, -82, -104, -112, -100, -71, -46, -34, -13, 29, 80, 111, 112, 97, 86, 84, + 69, 32, -15, -48, -61, -72, -94, -109, -106, -82, -54, -37, -23, 11, 61, 101, + 113, 101, 85, 80, 75, 48, 4, -37, -56, -64, -84, -107, -112, -90, -60, -37, + -29, -7, 43, 91, 111, 103, 86, 80, 77, 58, 20, -24, -52, -61, -75, -100, + -111, -99, -72, -44, -27, -12, 29, 77, 105, 106, 91, 80, 75, 64, 33, -9, + -43, -58, -69, -94, -111, -104, -78, -49, -28, -18, 11, 62, 97, 107, 94, 80, + 75, 69, 47, 6, -36, -55, -62, -81, -105, -108, -87, -59, -33, -18, 1, 46, + 86, 103, 97, 83, 75, 69, 52, 19, -23, -50, -59, -74, -97, -106, -91, -64, + -38, -21, -9, 26, 70, 95, 95, 80, 71, 69, 60, 35, -6, -40, -53, -64, + -87, -102, -96, -72, -45, -25, -14, 13, 56, 87, 95, 86, 75, 69, 60, 41, + 6, -32, -54, -62, -77, -95, -99, -79, -51, -23, -8, 6, 39, 75, 92, 87, + 72, 64, 62, 49, 21, -17, -47, -57, -67, -86, -97, -87, -59, -32, -16, -4, + 25, 63, 89, 92, 78, 67, 63, 53, 27, -10, -40, -55, -63, -78, -93, -89, + -65, -36, -17, -7, 11, 44, 77, 89, 79, 65, 61, 58, 41, 8, -26, -50, + -59, -67, -83, -90, -76, -47, -25, -13, 3, 30, 63, 85, 82, 70, 63, 58, + 45, 14, -18, -43, -56, -63, -74, -84, -78, -52, -26, -13, -2, 19, 46, 73, + 81, 68, 57, 55, 49, 27, -5, -32, -48, -54, -63, -77, -80, -60, -34, -17, + -5, 10, 34, 62, 79, 71, 57, 52, 48, 31, 2, -26, -45, -50, -53, -65, + -75, -63, -37, -16, -6, 4, 19, 45, 68, 70, 57, 49, 49, 39, 16, -11, + -33, -45, -49, -56, -70, -71, -51, -26, -8, 2, 13, 35, 63, 76, 63, 48, + 43, 38, 23, -7, -32, -45, -47, -47, -58, -67, -55, -30, -8, 0, 4, 20, + 46, 68, 65, 47, 38, 38, 31, 8, -19, -37, -44, -42, -48, -63, -62, -41, + -16, -2, 5, 16, 37, 61, 68, 53, 38, 34, 31, 14, -14, -33, -40, -38, + -41, -54, -60, -46, -20, -5, -3, 6, 25, 49, 63, 55, 38, 32, 33, 24, + 1, -23, -34, -35, -36, -45, -59, -55, -30, -9, -3, 2, 16, 39, 59, 59, + 44, 32, 30, 26, 7, -20, -33, -33, -32, -40, -53, -54, -35, -12, -3, -2, + 10, 29, 48, 55, 45, 32, 28, 27, 14, -10, -27, -30, -28, -34, -46, -53, + -41, -17, -5, -5, 5, 24, 44, 54, 46, 32, 25, 25, 18, -4, -25, -31, + -24, -27, -39, -47, -42, -21, -4, -2, 1, 15, 35, 46, 44, 31, 22, 23, + 20, 6, -15, -26, -23, -20, -29, -41, -42, -29, -11, -4, -4, 7, 26, 42, + 47, 37, 25, 21, 19, 9, -10, -25, -25, -18, -24, -38, -40, -29, -11, 1, + 0, 3, 19, 34, 42, 33, 19, 14, 15, 10, -5, -21, -24, -15, -13, -26, + -35, -31, -17, -2, 0, -2, 11, 26, 37, 34, 20, 14, 13, 12, 2, -17, + -25, -17, -12, -21, -31, -30, -19, -4, 4, 1, 9, 22, 32, 32, 19, 9, + 9, 10, 4, -11, -21, -16, -9, -14, -23, -26, -20, -8, 0, -2, 3, 15, + 26, 31, 24, 12, 9, 10, 6, -5, -17, -19, -12, -11, -18, -25, -22, -10, + 1, 2, 2, 11, 22, 29, 24, 10, 3, 5, 4, -4, -13, -15, -8, -5, + -10, -16, -18, -14, -5, -2, 0, 6, 13, 20, 23, 16, 6, 5, 5, 0, + -7, -12, -12, -8, -7, -12, -19, -18, -7, 0, 2, 7, 13, 18, 20, 13, + 3, -2, 1, -2, -6, -8, -6, -3, -2, -2, -10, -14, -10, -6, -4, 0, + 4, 9, 14, 15, 6, -2, -2, -2, -4, -4, -5, -3, 2, 3, -3, -10, + -9, -5, 0, 0, 0, 3, 8, 10, 3, -5, -7, -6, -4, 0, -2, -2, + 3, 7, 7, 2, -5, -6, -3, 2, 2, 0, 0, 2, 2, -4, -9, -9, + -7, -3, 2, 4, 8, 9, 6, 2, -3, -4, -3, -2, -2, -2, 0, 1, + -3, -8, -11, -8, -6, -4, 2, 6, 9, 10, 9, 8, 5, -4, -7, -3, + 1, 1, -6, -7, -6, -6, -11, -14, -10, -5, 3, 9, 12, 14, 13, 10, + 9, 1, -6, -5, -4, -3, -4, -6, -8, -12, -12, -13, -13, -11, -3, 9, + 16, 18, 15, 13, 14, 11, -2, -6, -4, -3, -5, -11, -13, -12, -14, -15, + -14, -10, -4, 6, 15, 22, 21, 16, 13, 12, 3, -7, -8, -7, -7, -10, + -14, -17, -16, -13, -12, -10, -7, 3, 15, 24, 26, 19, 16, 18, 12, -3, + -9, -10, -9, -11, -18, -22, -21, -17, -14, -14, -10, 0, 14, 26, 32, 28, + 23, 22, 21, 5, -9, -12, -16, -18, -22, -27, -27, -23, -17, -13, -8, 2, + 12, 25, 35, 36, 29, 21, 20, 11, -6, -14, -17, -19, -22, -27, -28, -24, + -20, -15, -11, -4, 7, 19, 32, 39, 35, 28, 25, 19, 4, -10, -17, -24, + -28, -31, -33, -30, -26, -19, -11, -3, 8, 19, 31, 42, 42, 34, 27, 21, + 9, -9, -19, -26, -31, -35, -34, -30, -26, -23, -13, -4, 4, 14, 25, 42, + 49, 41, 31, 27, 20, 3, -15, -28, -37, -38, -39, -38, -35, -29, -16, 0, + 9, 17, 26, 41, 52, 48, 36, 26, 19, 6, -16, -30, -39, -43, -41, -39, + -33, -29, -22, -5, 7, 13, 21, 36, 55, 56, 46, 34, 24, 15, -8, -29, + -44, -54, -50, -44, -39, -35, -27, -7, 11, 20, 25, 34, 54, 63, 53, 38, + 22, 14, 0, -27, -45, -56, -56, -46, -39, -36, -31, -14, 8, 19, 23, 29, + 46, 63, 61, 47, 30, 20, 8, -15, -39, -56, -62, -54, -44, -41, -38, -23, + -2, 16, 23, 28, 42, 63, 69, 58, 41, 25, 13, -7, -34, -56, -68, -64, + -50, -45, -43, -29, -7, 15, 26, 29, 40, 58, 72, 67, 48, 30, 16, 0, + -26, -53, -68, -69, -57, -47, -46, -36, -16, 9, 25, 30, 38, 53, 71, 74, + 58, 37, 17, 2, -21, -49, -70, -76, -64, -49, -43, -38, -21, 3, 25, 33, + 37, 49, 65, 74, 65, 45, 24, 8, -11, -40, -68, -79, -72, -57, -48, -42, + -29, -6, 20, 34, 39, 48, 63, 77, 74, 56, 31, 11, -8, -33, -61, -79, + -80, -68, -53, -45, -34, -16, 11, 31, 41, 51, 61, 75, 78, 64, 42, 19, + -3, -27, -55, -78, -84, -73, -59, -48, -37, -20, 5, 27, 40, 49, 58, 71, + 80, 71, 49, 23, 2, -20, -47, -72, -86, -82, -66, -52, -39, -26, -5, 20, + 39, 51, 59, 69, 79, 77, 61, 34, 7, -16, -42, -68, -88, -90, -75, -58, + -41, -26, -8, 17, 39, 52, 59, 65, 74, 77, 65, 41, 12, -12, -35, -60, + -81, -89, -79, -60, -45, -33, -17, 6, 31, 49, 59, 64, 73, 80, 74, 51, + 22, -5, -29, -54, -78, -92, -90, -70, -49, -35, -18, 3, 26, 48, 60, 64, + 68, 75, 75, 58, 31, 1, -25, -48, -73, -88, -90, -77, -56, -41, -23, -3, + 21, 43, 58, 64, 70, 75, 77, 64, 40, 12, -18, -44, -70, -87, -94, -87, + -64, -42, -22, -4, 16, 39, 58, 65, 66, 67, 74, 68, 46, 18, -12, -38, + -62, -82, -92, -89, -67, -45, -28, -9, 13, 31, 52, 64, 67, 66, 72, 71, + 53, 29, -3, -34, -59, -79, -94, -96, -77, -50, -29, -8, 12, 30, 49, 63, + 68, 67, 68, 70, 56, 34, 6, -29, -57, -77, -92, -99, -84, -56, -32, -10, + 11, 29, 45, 61, 69, 69, 68, 70, 60, 37, 12, -20, -50, -73, -90, -100, + -91, -64, -37, -14, 7, 25, 42, 57, 66, 67, 65, 67, 64, 45, 21, -9, + -41, -66, -84, -98, -95, -74, -47, -21, 3, 23, 39, 54, 64, 69, 69, 67, + 63, 50, 27, 0, -33, -63, -83, -94, -95, -79, -54, -26, -2, 18, 35, 49, + 61, 67, 67, 65, 64, 55, 33, 6, -25, -55, -82, -95, -98, -84, -60, -32, + -6, 17, 36, 48, 56, 64, 66, 65, 62, 55, 39, 14, -16, -46, -76, -92, + -96, -88, -69, -41, -9, 15, 33, 46, 54, 62, 68, 66, 59, 54, 44, 20, + -12, -41, -72, -92, -97, -90, -71, -46, -14, 15, 34, 48, 55, 59, 62, 63, + 60, 51, 42, 24, -6, -34, -63, -87, -95, -89, -75, -52, -23, 10, 31, 45, + 54, 58, 62, 66, 63, 51, 42, 30, 1, -32, -59, -84, -96, -93, -80, -58, + -28, 7, 32, 45, 53, 60, 64, 67, 62, 52, 41, 31, 9, -25, -55, -78, + -92, -91, -82, -65, -39, -2, 30, 43, 49, 56, 61, 65, 63, 54, 44, 33, + 16, -15, -47, -72, -88, -91, -84, -70, -45, -12, 22, 42, 48, 54, 58, 61, + 63, 56, 43, 32, 20, -4, -36, -65, -82, -87, -82, -72, -53, -23, 15, 40, + 46, 48, 55, 61, 62, 55, 43, 32, 21, 4, -26, -57, -75, -82, -80, -73, + -58, -30, 5, 35, 46, 47, 51, 57, 61, 57, 46, 34, 22, 9, -15, -47, + -71, -81, -80, -75, -62, -36, -4, 28, 46, 47, 49, 56, 60, 57, 48, 35, + 23, 12, -9, -39, -67, -78, -76, -71, -65, -45, -13, 21, 45, 50, 46, 50, + 58, 59, 49, 35, 23, 12, -4, -31, -62, -78, -74, -70, -65, -49, -18, 18, + 43, 51, 45, 48, 56, 56, 45, 30, 20, 12, 0, -24, -53, -71, -69, -63, + -60, -51, -25, 9, 36, 50, 47, 44, 50, 52, 45, 32, 21, 12, 1, -18, + -44, -66, -70, -64, -59, -51, -31, 2, 32, 50, 51, 46, 47, 52, 47, 32, + 17, 9, 0, -14, -34, -57, -67, -62, -56, -50, -33, -6, 24, 44, 51, 48, + 47, 48, 46, 34, 21, 12, 2, -13, -32, -51, -62, -62, -56, -51, -38, -13, + 18, 40, 51, 50, 45, 47, 46, 36, 20, 9, -2, -14, -28, -45, -59, -61, + -54, -48, -37, -15, 14, 36, 49, 52, 48, 44, 42, 33, 19, 10, 0, -13, + -26, -39, -52, -58, -54, -47, -37, -19, 9, 30, 44, 52, 48, 40, 38, 31, + 19, 7, -3, -12, -22, -31, -42, -51, -49, -43, -36, -22, 1, 22, 35, 45, + 47, 41, 37, 31, 23, 13, 3, -11, -22, -28, -36, -48, -53, -46, -35, -23, + -4, 17, 31, 45, 49, 41, 33, 29, 23, 13, 2, -11, -22, -26, -29, -38, + -46, -45, -34, -21, -6, 14, 25, 38, 46, 43, 35, 27, 19, 10, 3, -7, + -20, -28, -28, -32, -38, -41, -35, -23, -8, 10, 23, 33, 44, 44, 36, 27, + 18, 10, 0, -9, -22, -28, -28, -28, -33, -37, -32, -21, -7, 8, 20, 28, + 38, 41, 36, 27, 17, 8, -2, -6, -17, -28, -31, -28, -27, -30, -30, -22, + -7, 9, 19, 26, 35, 41, 37, 26, 16, 6, -5, -11, -18, -28, -31, -28, + -22, -23, -23, -18, -4, 11, 19, 24, 27, 33, 33, 24, 14, 3, -8, -11, + -15, -23, -29, -29, -21, -18, -19, -15, -5, 9, 16, 21, 26, 30, 32, 25, + 13, 2, -9, -13, -16, -21, -27, -27, -20, -12, -13, -14, -7, 9, 17, 20, + 24, 25, 26, 27, 15, 2, -9, -17, -17, -20, -25, -28, -23, -11, -6, -8, + -5, 7, 19, 23, 24, 24, 24, 25, 16, 0, -13, -22, -22, -22, -26, -28, + -22, -8, 2, 1, 0, 8, 18, 24, 24, 20, 18, 20, 15, 1, -12, -22, + -24, -22, -23, -25, -22, -13, 2, 7, 3, 8, 16, 25, 28, 21, 15, 15, + 15, 4, -13, -25, -29, -24, -20, -24, -21, -12, 1, 12, 10, 9, 16, 23, + 27, 21, 14, 12, 10, 3, -10, -21, -28, -27, -22, -22, -20, -14, -4, 10, + 14, 11, 17, 23, 29, 26, 15, 11, 10, 4, -12, -25, -33, -33, -26, -23, + -22, -12, 0, 13, 22, 19, 20, 25, 29, 25, 12, 5, 3, 0, -12, -25, + -32, -34, -27, -21, -20, -11, -2, 7, 18, 21, 22, 26, 30, 29, 21, 11, + 4, -5, -14, -29, -38, -38, -33, -27, -23, -10, 4, 12, 22, 29, 30, 30, + 31, 30, 21, 10, 0, -11, -19, -30, -39, -40, -36, -28, -20, -9, 4, 12, + 20, 29, 32, 30, 32, 32, 23, 12, 3, -8, -18, -27, -39, -44, -40, -32, + -25, -15, 1, 13, 22, 30, 37, 38, 36, 34, 26, 14, 2, -11, -22, -31, + -40, -45, -42, -35, -26, -14, 0, 12, 19, 26, 35, 39, 36, 33, 28, 18, + 6, -7, -18, -28, -37, -43, -43, -37, -30, -19, -6, 8, 20, 25, 34, 42, + 41, 37, 32, 22, 8, -7, -19, -32, -40, -44, -44, -38, -30, -20, -6, 8, + 19, 24, 30, 40, 41, 36, 29, 23, 13, -3, -16, -28, -39, -43, -44, -41, + -34, -23, -11, 2, 16, 25, 32, 41, 46, 42, 34, 26, 15, 0, -16, -29, + -40, -45, -45, -40, -32, -24, -12, -2, 12, 22, 26, 37, 45, 44, 34, 24, + 18, 6, -12, -24, -37, -41, -40, -40, -36, -30, -17, -4, 9, 18, 25, 37, + 45, 45, 40, 29, 19, 8, -8, -22, -38, -43, -42, -42, -35, -28, -17, -4, + 7, 17, 23, 33, 43, 43, 38, 28, 19, 12, -3, -19, -34, -40, -38, -40, + -38, -31, -22, -8, 5, 14, 21, 31, 44, 47, 41, 31, 20, 13, 3, -15, + -33, -45, -45, -41, -38, -31, -24, -10, 4, 15, 21, 29, 42, 47, 41, 33, + 22, 13, 4, -13, -29, -40, -41, -41, -41, -36, -26, -14, -2, 8, 17, 29, + 42, 50, 46, 37, 27, 17, 7, -9, -27, -41, -48, -45, -42, -38, -29, -15, + -2, 10, 18, 26, 38, 50, 51, 40, 28, 17, 6, -7, -24, -36, -43, -45, + -41, -38, -31, -18, -8, 2, 13, 26, 38, 44, 49, 42, 33, 22, 8, -4, + -20, -32, -41, -46, -44, -37, -32, -21, -8, 2, 14, 25, 35, 42, 47, 44, + 31, 19, 7, -4, -15, -28, -36, -42, -40, -34, -31, -24, -9, 0, 7, 18, + 30, 40, 44, 42, 32, 22, 12, 2, -10, -23, -31, -38, -42, -38, -31, -26, + -13, -3, 2, 14, 29, 40, 41, 40, 36, 26, 13, 1, -10, -19, -26, -35, + -43, -41, -33, -27, -17, -6, 1, 12, 27, 43, 47, 42, 37, 29, 14, 0, + -10, -21, -29, -34, -40, -42, -33, -26, -18, -5, 3, 10, 23, 39, 45, 39, + 33, 30, 18, 3, -8, -15, -22, -29, -37, -43, -36, -27, -22, -13, -4, 6, + 19, 36, 47, 47, 37, 33, 25, 6, -8, -15, -25, -31, -36, -43, -42, -32, + -21, -11, 0, 5, 15, 32, 46, 45, 35, 31, 28, 12, -6, -13, -20, -24, + -31, -41, -46, -38, -26, -18, -9, 1, 14, 31, 43, 48, 42, 33, 28, 15, + -5, -15, -18, -24, -31, -38, -41, -34, -26, -19, -8, 1, 10, 23, 37, 43, + 41, 32, 26, 19, 3, -12, -15, -18, -24, -34, -42, -38, -28, -20, -13, -4, + 6, 21, 37, 44, 43, 36, 28, 21, 8, -9, -16, -19, -25, -34, -42, -39, + -29, -21, -13, -3, 8, 19, 34, 42, 41, 36, 28, 20, 8, -7, -15, -16, + -19, -30, -41, -42, -31, -23, -15, -8, 3, 19, 36, 43, 39, 36, 30, 23, + 13, -6, -19, -21, -20, -26, -38, -43, -35, -25, -15, -7, 3, 14, 30, 42, + 40, 35, 28, 23, 16, 0, -14, -20, -19, -22, -34, -42, -37, -26, -15, -8, + 0, 12, 27, 40, 41, 35, 29, 22, 16, 4, -9, -19, -20, -20, -29, -39, + -39, -30, -19, -10, -3, 10, 24, 37, 42, 37, 31, 25, 18, 7, -7, -17, + -21, -20, -28, -38, -40, -33, -22, -11, -5, 9, 25, 37, 44, 40, 32, 24, + 17, 10, -5, -18, -24, -23, -28, -35, -38, -35, -26, -14, -5, 5, 19, 34, + 44, 42, 33, 23, 18, 13, 0, -15, -20, -22, -26, -33, -39, -35, -28, -18, + -10, 1, 18, 33, 43, 45, 38, 28, 20, 11, 2, -12, -22, -24, -28, -31, + -36, -35, -29, -21, -11, 0, 15, 30, 40, 44, 39, 31, 21, 13, 8, -5, + -17, -20, -25, -28, -32, -36, -34, -27, -18, -7, 9, 26, 39, 46, 45, 36, + 25, 14, 10, -2, -16, -24, -29, -31, -31, -36, -36, -27, -16, -7, 6, 23, + 37, 45, 44, 36, 26, 14, 8, 1, -14, -22, -23, -29, -32, -35, -36, -29, + -21, -14, 0, 16, 35, 46, 45, 39, 33, 20, 8, 3, -9, -21, -28, -32, + -34, -35, -36, -32, -25, -15, 1, 17, 32, 45, 49, 44, 35, 23, 7, 0, + -7, -17, -25, -30, -31, -32, -34, -31, -25, -18, -7, 10, 27, 43, 50, 45, + 35, 24, 13, 3, -7, -17, -24, -28, -30, -30, -33, -34, -26, -19, -11, 5, + 22, 39, 50, 48, 37, 26, 16, 5, -7, -18, -23, -27, -28, -28, -33, -34, + -24, -16, -11, 2, 17, 33, 48, 48, 37, 27, 18, 7, -5, -14, -20, -25, + -30, -31, -32, -37, -31, -20, -15, -3, 15, 30, 46, 53, 43, 31, 20, 11, + 0, -12, -21, -27, -31, -30, -30, -36, -33, -20, -10, -5, 9, 25, 41, 52, + 46, 34, 23, 15, 6, -9, -21, -27, -30, -31, -31, -37, -39, -25, -12, -7, + 1, 18, 36, 52, 53, 40, 28, 22, 13, -2, -18, -29, -32, -35, -34, -39, + -40, -28, -13, -7, -2, 12, 33, 50, 56, 44, 30, 24, 18, 4, -15, -29, + -32, -33, -33, -35, -40, -35, -20, -7, -2, 8, 25, 43, 54, 49, 35, 25, + 18, 8, -7, -23, -32, -32, -34, -34, -37, -36, -24, -11, -5, 2, 18, 36, + 51, 51, 39, 30, 24, 14, 0, -19, -32, -35, -35, -37, -38, -39, -29, -12, + -2, 3, 14, 29, 47, 54, 45, 33, 26, 17, 5, -12, -31, -37, -36, -38, + -38, -38, -32, -17, -3, 3, 9, 25, 42, 53, 49, 39, 31, 23, 10, -9, + -27, -38, -40, -41, -41, -41, -36, -23, -5, 5, 8, 18, 36, 51, 51, 43, + 34, 26, 16, 1, -20, -36, -40, -41, -42, -40, -38, -28, -10, 4, 7, 14, + 30, 48, 51, 45, 39, 31, 21, 4, -16, -33, -41, -43, -43, -39, -38, -32, + -15, 1, 7, 13, 25, 42, 52, 48, 39, 31, 22, 9, -10, -29, -40, -40, + -40, -38, -35, -34, -20, -2, 5, 9, 17, 33, 49, 50, 43, 34, 25, 13, + -4, -21, -36, -44, -44, -40, -35, -34, -26, -8, 5, 11, 17, 26, 43, 51, + 46, 36, 27, 16, 1, -16, -31, -42, -46, -43, -37, -35, -29, -12, 3, 11, + 17, 23, 37, 50, 52, 41, 29, 20, 4, -15, -30, -43, -49, -46, -39, -37, + -33, -15, 3, 13, 19, 23, 35, 52, 55, 44, 29, 20, 8, -12, -28, -40, + -48, -45, -39, -35, -32, -20, -2, 12, 16, 19, 28, 45, 55, 49, 35, 24, + 14, -3, -20, -36, -49, -53, -45, -38, -35, -27, -9, 8, 19, 23, 26, 40, + 55, 55, 41, 25, 15, -2, -19, -33, -46, -53, -47, -39, -35, -29, -14, 6, + 19, 24, 25, 35, 53, 59, 47, 29, 17, 7, -12, -30, -47, -58, -56, -47, + -39, -35, -22, -2, 17, 28, 30, 34, 50, 63, 56, 35, 19, 8, -9, -26, + -43, -56, -58, -49, -42, -38, -27, -9, 12, 26, 33, 34, 44, 60, 62, 44, + 23, 9, -4, -20, -40, -56, -63, -56, -44, -39, -30, -14, 8, 26, 35, 35, + 43, 60, 64, 50, 28, 13, 2, -16, -37, -53, -62, -61, -50, -42, -32, -17, + 2, 18, 32, 40, 44, 54, 63, 55, 37, 17, 4, -10, -31, -48, -61, -67, + -59, -45, -36, -24, -5, 17, 33, 43, 47, 54, 64, 59, 42, 20, 3, -10, + -28, -49, -63, -68, -63, -50, -37, -25, -7, 13, 31, 44, 48, 54, 61, 59, + 48, 27, 6, -10, -24, -43, -59, -67, -67, -56, -39, -28, -13, 8, 24, 42, + 51, 54, 58, 58, 52, 37, 14, -6, -20, -38, -54, -65, -70, -63, -45, -29, + -17, 2, 18, 37, 52, 56, 58, 56, 51, 42, 23, -2, -19, -34, -50, -62, + -70, -69, -52, -30, -17, -3, 15, 33, 50, 58, 58, 56, 52, 46, 29, 3, + -15, -31, -45, -58, -68, -71, -60, -38, -20, -5, 11, 25, 42, 58, 62, 58, + 51, 44, 36, 15, -10, -29, -43, -53, -64, -72, -67, -45, -21, -8, 4, 20, + 40, 60, 65, 57, 53, 48, 42, 21, -8, -27, -40, -50, -62, -71, -71, -54, + -29, -9, 3, 18, 34, 54, 68, 65, 57, 48, 40, 28, 2, -23, -41, -52, + -60, -71, -75, -60, -34, -12, 0, 13, 31, 52, 69, 66, 56, 50, 44, 33, + 7, -21, -38, -47, -55, -65, -75, -67, -41, -15, 2, 11, 23, 41, 61, 68, + 59, 49, 40, 34, 17, -11, -35, -47, -48, -55, -69, -72, -50, -21, 0, 8, + 15, 33, 56, 69, 62, 52, 44, 40, 26, -4, -30, -44, -48, -56, -69, -77, + -59, -28, -7, 7, 15, 30, 52, 68, 66, 55, 45, 38, 30, 6, -24, -43, + -49, -52, -64, -75, -65, -35, -10, 4, 11, 25, 45, 65, 67, 55, 48, 43, + 34, 13, -18, -39, -45, -49, -61, -75, -72, -45, -17, -2, 9, 20, 39, 61, + 70, 62, 52, 45, 36, 18, -9, -34, -47, -52, -58, -69, -72, -52, -23, -5, + 7, 17, 35, 54, 65, 63, 55, 45, 37, 23, 0, -27, -45, -49, -53, -63, + -71, -59, -31, -8, 7, 15, 28, 47, 61, 65, 58, 47, 38, 27, 6, -21, + -41, -49, -53, -62, -69, -62, -39, -14, 3, 14, 28, 46, 59, 64, 62, 51, + 39, 29, 11, -16, -40, -52, -55, -58, -65, -65, -47, -20, 1, 14, 24, 39, + 52, 59, 64, 56, 43, 33, 16, -8, -32, -49, -55, -58, -63, -65, -54, -29, + -3, 12, 21, 36, 51, 60, 65, 59, 46, 35, 21, -4, -28, -48, -56, -57, + -59, -60, -55, -37, -12, 9, 19, 32, 46, 54, 58, 58, 48, 36, 26, 7, + -18, -41, -53, -53, -52, -57, -58, -45, -19, 6, 15, 26, 42, 54, 59, 59, + 52, 39, 28, 10, -16, -40, -56, -56, -52, -51, -53, -45, -22, 4, 17, 24, + 35, 46, 56, 57, 52, 40, 30, 18, -7, -33, -54, -58, -52, -49, -53, -51, + -33, -5, 17, 26, 34, 43, 54, 58, 53, 42, 31, 19, 0, -24, -47, -60, + -55, -46, -46, -50, -39, -13, 13, 25, 32, 38, 48, 56, 52, 41, 30, 20, + 7, -15, -41, -58, -55, -44, -41, -44, -40, -19, 10, 25, 28, 32, 41, 53, + 52, 42, 31, 21, 13, -5, -32, -55, -60, -47, -36, -38, -40, -26, 2, 24, + 29, 28, 32, 46, 48, 40, 29, 21, 14, 1, -23, -48, -56, -46, -34, -33, + -36, -29, -7, 20, 28, 25, 26, 37, 46, 42, 30, 19, 15, 7, -13, -39, + -58, -54, -37, -27, -27, -29, -17, 13, 29, 28, 24, 31, 42, 42, 34, 21, + 11, 5, -10, -32, -51, -52, -40, -28, -24, -24, -18, 6, 27, 30, 26, 28, + 36, 38, 33, 22, 11, 6, -7, -26, -44, -49, -42, -30, -21, -17, -16, -5, + 18, 29, 26, 25, 29, 33, 33, 25, 13, 7, 0, -18, -36, -46, -45, -31, + -20, -16, -16, -9, 12, 28, 29, 24, 25, 29, 31, 26, 13, 2, -5, -15, + -26, -39, -46, -37, -19, -9, -9, -11, 1, 21, 31, 26, 21, 23, 26, 25, + 15, 4, -4, -10, -20, -32, -41, -38, -22, -10, -7, -9, -6, 11, 26, 29, + 22, 20, 21, 24, 19, 7, -6, -12, -17, -23, -30, -36, -27, -12, -3, 0, + -5, 3, 18, 28, 25, 18, 15, 16, 15, 7, -4, -10, -14, -19, -24, -30, + -26, -13, -3, 2, -3, -2, 12, 23, 26, 18, 13, 13, 14, 9, 0, -11, + -14, -15, -18, -24, -26, -16, -4, 4, 0, -5, 6, 17, 25, 21, 11, 7, + 8, 8, 1, -11, -14, -11, -10, -13, -20, -18, -7, 5, 7, -3, -2, 8, + 21, 23, 12, 4, 4, 8, 7, -5, -15, -14, -11, -9, -15, -20, -13, 1, + 8, 3, 0, 6, 17, 24, 16, 3, -2, 1, 0, -10, -17, -14, -8, -4, + -5, -11, -12, 0, 9, 6, -3, 1, 10, 18, 16, 5, -3, 0, 3, -4, + -13, -15, -10, -6, -4, -8, -13, -8, 5, 8, 5, 3, 9, 17, 18, 13, + 0, -7, -5, -5, -11, -14, -11, -6, 2, 2, -6, -9, 1, 8, 5, -2, + 1, 8, 14, 12, 2, -6, -5, -2, -6, -12, -10, -2, 3, 4, -5, -11, + -6, 5, 6, 0, 0, 7, 12, 14, 6, -7, -8, -6, -6, -9, -10, -5, + 4, 8, 4, -7, -11, -2, 6, 3, -2, 2, 9, 15, 12, -2, -8, -6, + -3, -5, -11, -9, 2, 10, 7, -5, -15, -10, 4, 6, -2, -2, 8, 14, + 14, 3, -9, -8, -5, -4, -8, -10, 0, 8, 9, 3, -9, -12, -3, 6, + 3, -3, 1, 8, 13, 5, -9, -13, -7, -2, -2, -6, -2, 9, 13, 6, + -6, -13, -10, 2, 4, -3, -2, 7, 13, 9, -6, -12, -11, -6, 0, -5, + -5, 7, 15, 13, 1, -10, -13, -4, 5, -2, -7, -2, 9, 9, -3, -11, + -11, -8, 2, 1, -3, 7, 15, 12, 4, -7, -13, -11, -2, 1, -4, -3, + 7, 11, 3, -8, -11, -10, 0, 1, -5, 2, 12, 17, 11, -2, -11, -11, + -3, 4, -4, -9, 1, 10, 3, -9, -11, -8, 0, 5, 1, 2, 11, 14, + 9, 1, -11, -15, -11, -3, 1, -3, 3, 12, 11, 1, -7, -9, -6, -3, + -5, -5, 5, 12, 9, 4, -3, -8, -8, -5, 0, -4, -3, 5, 6, -3, + -10, -7, -3, 0, 2, 3, 10, 14, 11, 4, -3, -11, -15, -15, -9, -5, + -5, 5, 13, 5, -2, 0, 2, 4, 1, -3, 4, 12, 11, 2, -5, -10, + -13, -13, -11, -6, -4, 3, 13, 9, 1, -2, 4, 5, 1, -5, 3, 12, + 13, 4, -9, -12, -14, -16, -17, -12, -5, 5, 16, 17, 6, 3, 9, 9, + 2, -8, -7, 2, 7, 4, -8, -12, -10, -13, -14, -13, -6, 4, 13, 19, + 10, 0, 6, 14, 8, -6, -9, 0, 7, 5, -8, -17, -13, -9, -14, -18, + -13, 2, 15, 23, 16, 4, 5, 16, 15, 0, -10, -6, 3, 6, -4, -15, + -15, -10, -11, -16, -16, -5, 10, 21, 18, 7, 2, 12, 18, 6, -7, -9, + 1, 7, 1, -14, -19, -15, -13, -16, -18, -8, 7, 19, 24, 16, 5, 8, + 16, 9, -4, -9, -5, 3, 4, -9, -19, -18, -13, -12, -17, -12, 2, 16, + 22, 17, 6, 4, 14, 13, 1, -8, -6, 2, 6, -5, -18, -20, -16, -14, + -18, -17, -5, 12, 23, 24, 14, 9, 15, 19, 9, -5, -8, -3, 2, -6, + -17, -23, -19, -14, -16, -17, -8, 7, 19, 24, 19, 10, 11, 17, 13, 3, + -5, -3, -2, -4, -14, -24, -25, -20, -18, -16, -10, 3, 16, 26, 28, 18, + 11, 15, 17, 9, -4, -7, -6, -6, -12, -24, -29, -22, -16, -15, -10, 0, + 13, 24, 27, 22, 14, 13, 16, 13, 2, -6, -7, -9, -12, -21, -29, -27, + -21, -15, -10, -3, 8, 21, 29, 26, 17, 13, 17, 19, 9, -5, -10, -9, + -12, -21, -30, -29, -22, -14, -10, -4, 7, 17, 26, 23, 17, 13, 12, 18, + 16, 5, -6, -10, -11, -19, -29, -32, -27, -18, -10, -4, 4, 13, 25, 26, + 21, 16, 11, 16, 17, 8, -5, -12, -12, -16, -25, -30, -27, -19, -10, -6, + 0, 10, 21, 24, 18, 15, 13, 16, 20, 14, 1, -10, -12, -15, -26, -31, + -29, -22, -12, -5, 0, 8, 19, 25, 22, 17, 14, 14, 19, 17, 4, -10, + -15, -15, -22, -30, -30, -26, -16, -6, 1, 7, 15, 23, 23, 18, 17, 17, + 17, 17, 8, -6, -15, -18, -24, -31, -29, -26, -19, -8, 2, 7, 15, 23, + 24, 21, 17, 15, 15, 17, 13, -4, -16, -20, -23, -30, -32, -27, -19, -8, + 3, 7, 14, 23, 24, 20, 16, 16, 15, 14, 10, 0, -12, -20, -24, -31, + -32, -25, -19, -10, 0, 9, 14, 22, 27, 23, 17, 17, 18, 12, 8, 1, + -12, -18, -23, -31, -34, -26, -17, -9, -2, 6, 14, 22, 27, 22, 16, 15, + 18, 17, 10, 3, -9, -17, -21, -31, -38, -32, -23, -13, -5, 4, 14, 21, + 30, 30, 21, 17, 18, 17, 10, 3, -8, -20, -23, -29, -38, -34, -25, -12, + 0, 3, 11, 17, 26, 31, 23, 15, 13, 16, 14, 5, -4, -15, -19, -23, + -35, -38, -32, -19, -7, -5, 6, 16, 25, 36, 32, 22, 19, 19, 15, 3, + -7, -16, -23, -26, -35, -42, -34, -19, -3, 1, 6, 18, 26, 37, 34, 20, + 15, 14, 14, 5, -7, -15, -21, -23, -28, -39, -37, -22, -5, 1, 3, 15, + 25, 35, 40, 27, 14, 14, 14, 6, -7, -14, -20, -25, -27, -36, -41, -28, + -8, 2, 4, 14, 24, 33, 40, 32, 17, 13, 12, 5, -7, -14, -17, -24, + -28, -34, -40, -32, -14, 1, 4, 13, 26, 33, 41, 40, 26, 15, 12, 4, + -9, -17, -20, -25, -31, -34, -41, -38, -20, 0, 7, 12, 24, 32, 40, 41, + 30, 17, 11, 4, -10, -18, -19, -21, -27, -31, -35, -36, -24, -5, 5, 9, + 21, 31, 37, 41, 36, 21, 11, 4, -8, -15, -18, -21, -26, -31, -34, -37, + -30, -12, 3, 9, 18, 30, 38, 44, 42, 29, 15, 7, -6, -18, -23, -24, + -25, -31, -34, -36, -33, -15, 3, 9, 17, 28, 38, 44, 42, 34, 20, 8, + -5, -18, -23, -22, -24, -30, -35, -35, -35, -24, -6, 6, 14, 25, 36, 42, + 45, 42, 28, 13, 1, -15, -26, -27, -26, -29, -35, -39, -38, -28, -10, 5, + 13, 21, 36, 47, 48, 45, 36, 21, 6, -11, -25, -31, -30, -29, -35, -41, + -41, -34, -18, 1, 15, 24, 35, 47, 52, 51, 42, 26, 8, -9, -25, -32, + -34, -32, -34, -40, -41, -35, -22, -5, 11, 21, 30, 44, 52, 51, 45, 32, + 15, -3, -19, -28, -33, -34, -36, -42, -44, -41, -30, -13, 6, 20, 29, 43, + 54, 56, 50, 37, 22, 4, -17, -31, -39, -39, -38, -40, -44, -41, -31, -14, + 4, 18, 26, 37, 52, 57, 54, 44, 29, 11, -9, -26, -38, -42, -40, -41, + -45, -46, -39, -24, -2, 17, 25, 35, 49, 59, 59, 52, 36, 19, -2, -22, + -38, -46, -45, -43, -44, -47, -41, -28, -7, 12, 22, 32, 45, 58, 60, 52, + 40, 26, 9, -14, -36, -46, -47, -44, -44, -50, -47, -34, -14, 8, 21, 30, + 42, 58, 65, 58, 46, 32, 14, -7, -30, -47, -51, -50, -45, -50, -51, -38, + -20, 4, 19, 28, 38, 53, 67, 63, 50, 40, 23, 2, -22, -43, -54, -55, + -50, -53, -57, -48, -31, -6, 17, 28, 39, 53, 69, 72, 60, 47, 29, 7, + -18, -39, -54, -59, -56, -53, -55, -52, -37, -16, 10, 25, 36, 48, 65, 75, + 68, 54, 40, 20, -6, -31, -52, -61, -61, -59, -63, -62, -46, -24, 2, 20, + 33, 50, 67, 79, 75, 62, 49, 30, 2, -29, -50, -63, -66, -65, -64, -64, + -50, -28, -6, 18, 34, 48, 62, 74, 79, 70, 54, 38, 14, -19, -45, -62, + -70, -71, -67, -68, -61, -39, -15, 10, 28, 45, 63, 77, 82, 77, 62, 47, + 25, -9, -40, -61, -70, -73, -69, -70, -66, -47, -23, 2, 23, 41, 57, 71, + 79, 83, 72, 55, 37, 6, -27, -51, -67, -76, -78, -77, -75, -60, -35, -12, + 13, 37, 59, 75, 82, 86, 81, 66, 48, 17, -23, -50, -66, -77, -83, -83, + -78, -66, -43, -18, 7, 31, 54, 73, 83, 87, 87, 74, 55, 29, -10, -41, + -61, -76, -85, -88, -84, -72, -53, -28, -3, 22, 51, 75, 84, 88, 92, 87, + 67, 40, 0, -38, -60, -77, -89, -94, -89, -77, -59, -34, -7, 17, 44, 73, + 88, 90, 91, 88, 74, 49, 12, -29, -57, -73, -84, -93, -94, -84, -68, -44, + -17, 8, 33, 64, 85, 90, 92, 91, 83, 63, 30, -15, -50, -71, -82, -92, + -96, -90, -74, -52, -26, 0, 24, 56, 82, 92, 93, 92, 89, 74, 42, 0, + -41, -67, -80, -93, -100, -97, -83, -62, -35, -8, 16, 43, 74, 91, 96, 96, + 93, 83, 56, 16, -28, -61, -79, -92, -99, -99, -90, -71, -45, -16, 9, 36, + 66, 88, 98, 97, 93, 87, 68, 31, -16, -52, -75, -89, -98, -103, -98, -81, + -54, -23, 1, 25, 56, 83, 97, 98, 92, 88, 76, 46, 1, -42, -68, -81, + -91, -99, -97, -82, -58, -30, -6, 15, 44, 73, 91, 94, 89, 85, 78, 55, + 16, -28, -59, -77, -87, -93, -95, -85, -65, -40, -16, 6, 33, 62, 85, 94, + 90, 86, 81, 66, 32, -15, -52, -73, -84, -90, -93, -87, -69, -45, -22, 0, + 22, 48, 75, 88, 88, 85, 80, 67, 42, 4, -36, -62, -77, -87, -90, -85, + -72, -52, -30, -11, 11, 36, 63, 83, 86, 86, 82, 74, 54, 17, -25, -55, + -72, -81, -88, -87, -77, -57, -34, -16, 4, 26, 54, 77, 84, 84, 82, 75, + 58, 27, -12, -45, -65, -76, -84, -84, -76, -61, -41, -24, -7, 15, 41, 67, + 78, 81, 80, 76, 67, 42, 5, -30, -54, -67, -79, -85, -79, -67, -50, -32, + -16, 6, 32, 58, 73, 77, 81, 78, 68, 49, 16, -19, -45, -63, -74, -80, + -77, -67, -53, -35, -20, -3, 20, 45, 65, 72, 76, 75, 68, 56, 29, -6, + -33, -52, -65, -75, -77, -70, -57, -42, -28, -13, 9, 34, 57, 70, 73, 75, + 72, 63, 41, 7, -24, -46, -60, -70, -75, -72, -59, -45, -31, -18, 0, 25, + 48, 63, 68, 70, 71, 65, 47, 17, -13, -33, -49, -62, -73, -73, -61, -48, + -37, -25, -10, 14, 39, 57, 64, 67, 70, 69, 54, 28, -3, -27, -44, -57, + -68, -74, -66, -50, -39, -26, -13, 5, 30, 50, 60, 62, 64, 65, 58, 38, + 9, -17, -35, -46, -59, -69, -67, -52, -40, -31, -20, -6, 18, 42, 55, 58, + 60, 65, 62, 47, 20, -10, -28, -39, -51, -66, -70, -58, -44, -34, -23, -10, + 11, 34, 51, 57, 58, 62, 63, 51, 29, 2, -21, -34, -46, -60, -69, -63, + -49, -37, -27, -15, 3, 26, 45, 55, 56, 58, 62, 55, 37, 11, -14, -29, + -39, -52, -65, -66, -52, -40, -30, -18, -5, 17, 39, 52, 54, 55, 58, 57, + 44, 21, -8, -24, -33, -45, -59, -66, -57, -43, -31, -20, -11, 7, 30, 47, + 53, 51, 52, 55, 51, 33, 4, -20, -29, -36, -49, -64, -63, -50, -36, -24, + -14, 0, 22, 43, 55, 53, 49, 52, 51, 39, 12, -16, -27, -33, -45, -60, + -66, -53, -37, -25, -16, -6, 16, 40, 53, 53, 47, 49, 51, 43, 22, 0, + 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, -2, -2, -2, -2, 0, -2, + 0, 0, 1, 2, 3, 4, 4, 4, 5, 6, 7, 6, 3, 1, 0, -3, + -5, -11, -17, -20, -20, -18, -16, -17, -17, -14, -10, -9, -13, -18, -19, -15, + -13, -12, -13, -8, 1, 12, 25, 32, 40, 45, 50, 49, 41, 32, 24, 16, + 9, 1, -12, -20, -23, -24, -20, -20, -18, -12, -11, -12, -7, 0, 10, 17, + 23, 25, 24, 21, 22, 23, 21, 10, 1, -5, -8, -11, -19, -29, -33, -32, + -26, -19, -16, -14, -12, -8, -7, -11, -19, -27, -29, -27, -25, -25, -24, -17, + -4, 13, 26, 34, 43, 54, 59, 56, 46, 33, 23, 15, 5, -11, -23, -32, + -35, -32, -30, -27, -23, -16, -11, -5, 3, 11, 23, 31, 36, 33, 28, 27, + 26, 21, 11, 1, -9, -14, -18, -23, -28, -35, -33, -26, -18, -12, -11, -7, + -4, -2, 0, -8, -19, -29, -33, -32, -30, -30, -25, -17, -4, 13, 26, 36, + 47, 55, 59, 53, 43, 32, 23, 12, 0, -14, -23, -30, -35, -35, -35, -33, + -28, -19, -11, -6, 3, 11, 22, 33, 39, 38, 34, 30, 27, 20, 11, 0, + -9, -17, -21, -26, -31, -34, -29, -19, -8, -3, 0, -3, 1, 4, 1, -11, + -25, -35, -37, -39, -35, -32, -27, -17, 0, 15, 29, 42, 55, 63, 62, 55, + 47, 38, 27, 14, -4, -20, -31, -40, -44, -46, -45, -41, -34, -25, -14, -3, + 8, 22, 32, 43, 44, 40, 36, 34, 26, 18, 8, -2, -11, -20, -25, -29, + -33, -31, -21, -10, -2, -2, -2, 4, 6, 9, 0, -14, -28, -35, -39, -38, + -38, -36, -30, -16, 0, 16, 29, 41, 55, 65, 67, 59, 49, 39, 28, 13, + -3, -19, -32, -42, -48, -51, -53, -47, -36, -22, -12, 0, 10, 24, 38, 46, + 48, 43, 39, 32, 26, 17, 6, -7, -16, -21, -26, -31, -34, -28, -16, -2, + 3, 1, 2, 8, 16, 12, 2, -15, -27, -34, -37, -41, -47, -44, -33, -16, + 1, 16, 31, 47, 65, 75, 73, 63, 52, 41, 27, 9, -14, -34, -47, -54, + -55, -58, -57, -50, -35, -17, 0, 8, 20, 34, 47, 54, 49, 42, 36, 29, + 21, 9, -4, -14, -21, -26, -30, -33, -28, -18, -5, 4, 6, 6, 8, 13, + 17, 12, -4, -21, -33, -39, -44, -49, -50, -46, -35, -15, 4, 22, 36, 55, + 72, 81, 78, 69, 54, 42, 27, 6, -19, -38, -52, -57, -62, -65, -64, -52, + -35, -17, -3, 8, 19, 33, 45, 50, 48, 42, 35, 29, 18, 7, -5, -11, + -20, -26, -29, -27, -20, -13, -4, 3, 8, 9, 11, 12, 12, 5, -8, -22, + -33, -42, -50, -53, -51, -42, -27, -11, 9, 27, 45, 62, 75, 78, 73, 60, + 48, 32, 14, -8, -30, -46, -54, -60, -64, -62, -53, -39, -23, -8, 5, 17, + 30, 41, 46, 44, 38, 30, 22, 11, 4, -5, -12, -20, -25, -26, -24, -17, + -7, 3, 8, 11, 12, 14, 15, 14, 9, -4, -17, -32, -44, -54, -57, -56, + -48, -36, -22, -5, 18, 41, 61, 74, 79, 75, 67, 55, 39, 20, -2, -20, + -37, -47, -56, -62, -63, -57, -44, -31, -18, -5, 7, 16, 28, 35, 38, 37, + 32, 25, 16, 8, 3, -2, -5, -11, -19, -21, -16, -7, 3, 6, 8, 7, + 8, 10, 9, 5, -4, -13, -23, -37, -49, -54, -54, -47, -38, -25, -9, 9, + 30, 50, 67, 77, 75, 69, 58, 42, 26, 7, -12, -31, -46, -52, -56, -59, + -58, -49, -36, -19, -5, 8, 14, 22, 28, 33, 35, 30, 23, 13, 4, 3, + 3, 0, -8, -12, -13, -10, -6, 2, 8, 11, 12, 11, 9, 4, -2, -5, + -12, -23, -35, -46, -52, -54, -48, -36, -22, -8, 9, 28, 46, 61, 70, 72, + 68, 58, 45, 27, 9, -8, -22, -35, -43, -48, -48, -46, -39, -33, -23, -12, + 1, 8, 11, 14, 16, 19, 19, 17, 11, 7, 8, 11, 13, 7, 5, 2, + 2, 2, 4, 6, 6, 5, 2, -3, -5, -9, -11, -17, -23, -29, -34, -40, + -45, -41, -32, -18, -5, 7, 19, 36, 54, 64, 67, 61, 55, 48, 36, 18, + 3, -11, -23, -36, -45, -46, -42, -39, -34, -27, -20, -11, 0, 10, 13, 14, + 12, 13, 13, 10, 7, 6, 9, 11, 11, 11, 10, 10, 8, 9, 9, 9, + 6, 1, -4, -12, -16, -22, -25, -28, -29, -30, -39, -43, -39, -26, -11, 0, + 8, 19, 33, 48, 58, 63, 61, 56, 50, 40, 25, 8, -5, -15, -24, -35, + -41, -42, -39, -32, -29, -25, -21, -13, -6, 0, 4, 2, 2, 3, 6, 6, + 7, 11, 17, 20, 22, 23, 24, 23, 21, 17, 12, 4, -5, -13, -22, -29, + -37, -41, -40, -36, -31, -32, -34, -34, -22, -6, 8, 14, 20, 29, 41, 50, + 56, 56, 49, 45, 39, 30, 17, 5, -8, -19, -28, -34, -35, -32, -27, -25, + -25, -23, -19, -12, -7, -4, -6, -10, -11, -7, 0, 4, 10, 14, 19, 26, + 32, 35, 34, 31, 25, 16, 6, -5, -17, -29, -39, -47, -51, -50, -44, -35, + -28, -27, -25, -18, -6, 10, 18, 21, 25, 31, 40, 46, 49, 48, 44, 42, + 37, 29, 19, 8, -5, -14, -21, -29, -30, -30, -27, -28, -32, -33, -31, -22, + -17, -15, -17, -19, -19, -9, 5, 16, 22, 25, 31, 38, 44, 47, 43, 34, + 20, 6, -9, -21, -35, -49, -59, -62, -60, -53, -42, -30, -22, -15, -6, 4, + 14, 23, 27, 28, 27, 30, 35, 38, 39, 42, 38, 35, 30, 25, 20, 12, + 4, -6, -18, -23, -22, -20, -22, -30, -37, -39, -34, -29, -27, -27, -26, -23, + -16, -3, 10, 21, 29, 35, 43, 46, 50, 49, 41, 28, 15, -2, -19, -35, + -50, -62, -67, -67, -60, -50, -36, -23, -14, -6, 3, 11, 21, 27, 27, 24, + 25, 27, 29, 31, 36, 41, 42, 39, 33, 27, 22, 17, 8, -3, -11, -15, + -15, -18, -25, -35, -42, -45, -42, -41, -41, -40, -38, -28, -12, 7, 22, 34, + 43, 51, 59, 62, 59, 49, 37, 20, 1, -19, -38, -54, -65, -73, -74, -69, + -55, -35, -19, -10, -2, 8, 18, 23, 25, 25, 22, 20, 19, 20, 22, 30, + 39, 44, 42, 39, 35, 32, 29, 18, 4, -8, -13, -15, -17, -24, -33, -43, + -47, -44, -42, -40, -40, -39, -32, -17, 3, 16, 28, 39, 47, 53, 56, 56, + 52, 40, 24, 5, -12, -29, -43, -54, -65, -72, -71, -56, -36, -20, -13, -4, + 5, 12, 18, 21, 23, 20, 18, 14, 16, 19, 27, 38, 45, 45, 42, 41, + 42, 37, 27, 15, 1, -8, -12, -13, -17, -30, -40, -47, -48, -47, -46, -46, + -45, -41, -28, -9, 11, 26, 38, 45, 51, 55, 58, 55, 47, 31, 10, -12, + -27, -39, -49, -58, -67, -69, -62, -46, -26, -13, -4, 2, 7, 14, 18, 21, + 20, 15, 11, 12, 14, 21, 32, 40, 44, 42, 42, 40, 37, 33, 22, 11, + 1, -7, -11, -11, -19, -30, -39, -43, -43, -42, -43, -44, -44, -36, -20, 0, + 14, 25, 35, 42, 46, 50, 50, 48, 36, 17, -3, -18, -30, -36, -43, -52, + -59, -60, -49, -35, -20, -12, -7, -4, 2, 8, 12, 12, 9, 9, 12, 16, + 23, 29, 39, 45, 46, 46, 43, 41, 37, 30, 20, 7, -5, -10, -11, -15, + -25, -39, -46, -45, -43, -42, -45, -46, -39, -26, -8, 8, 20, 31, 41, 45, + 48, 46, 44, 36, 21, 1, -20, -31, -33, -36, -44, -53, -59, -54, -41, -26, + -17, -12, -6, -3, 5, 7, 9, 11, 11, 12, 15, 20, 29, 36, 42, 46, + 45, 42, 40, 38, 33, 25, 13, 4, -7, -10, -11, -17, -29, -38, -38, -34, + -35, -39, -41, -39, -31, -16, -6, 4, 14, 24, 30, 34, 34, 35, 32, 22, + 8, -9, -16, -16, -17, -22, -33, -43, -46, -41, -34, -30, -25, -19, -14, -9, + -6, -2, 5, 9, 13, 15, 21, 29, 36, 43, 47, 46, 46, 42, 39, 37, + 31, 20, 10, 0, -6, -9, -14, -22, -29, -33, -31, -30, -34, -37, -37, -30, + -21, -12, -5, 1, 10, 20, 28, 31, 31, 28, 20, 12, 0, -8, -10, -10, + -16, -24, -33, -39, -44, -42, -35, -28, -23, -18, -14, -10, -4, 6, 12, 16, + 17, 22, 29, 33, 35, 38, 41, 43, 41, 38, 34, 30, 24, 16, 9, 3, + -4, -10, -15, -21, -23, -23, -23, -24, -28, -32, -31, -28, -22, -15, -10, -6, + 2, 11, 20, 23, 25, 19, 14, 9, 5, 3, 2, -2, -8, -19, -28, -36, + -42, -44, -39, -33, -28, -26, -20, -11, 0, 8, 15, 22, 28, 33, 35, 36, + 37, 38, 41, 40, 38, 32, 27, 21, 17, 11, 4, -3, -8, -12, -17, -18, + -16, -16, -15, -18, -22, -25, -26, -25, -23, -19, -15, -9, -2, 8, 13, 17, + 18, 17, 16, 15, 13, 10, 6, 0, -9, -21, -32, -42, -47, -46, -43, -36, + -30, -22, -15, -6, 4, 14, 22, 28, 33, 36, 37, 36, 35, 37, 36, 36, + 32, 27, 23, 16, 10, 5, 0, -7, -10, -12, -11, -11, -11, -10, -9, -11, + -16, -22, -27, -30, -30, -30, -25, -19, -9, 0, 7, 13, 18, 23, 27, 27, + 26, 20, 12, 1, -13, -27, -40, -50, -54, -54, -49, -42, -33, -21, -10, 1, + 14, 24, 30, 39, 44, 43, 38, 36, 38, 37, 34, 31, 28, 22, 13, 7, + 5, -2, -7, -11, -14, -13, -13, -8, -6, -6, -10, -12, -14, -19, -26, -34, + -38, -33, -26, -15, -7, 2, 7, 17, 26, 35, 40, 37, 29, 19, 7, -12, + -31, -44, -53, -56, -61, -62, -59, -46, -27, -9, 5, 14, 25, 36, 47, 53, + 51, 45, 37, 34, 32, 29, 26, 23, 18, 13, 5, 0, -3, -4, -6, -10, + -12, -12, -6, 2, 6, 2, -6, -12, -17, -21, -31, -41, -47, -43, -32, -20, + -11, -4, 9, 21, 40, 50, 48, 42, 34, 22, 5, -16, -36, -53, -58, -63, + -69, -73, -63, -43, -19, -2, 9, 19, 34, 50, 60, 61, 53, 42, 37, 32, + 30, 24, 21, 16, 11, 4, -4, -7, -6, -5, -5, -10, -14, -11, -4, 3, + 2, -2, -8, -13, -19, -26, -36, -42, -40, -33, -21, -9, 1, 10, 22, 36, + 49, 53, 47, 36, 19, 1, -18, -36, -51, -60, -65, -67, -67, -63, -47, -24, + -4, 11, 20, 33, 48, 57, 57, 52, 42, 33, 30, 28, 25, 19, 16, 12, + 8, 3, -2, -2, -2, -2, -5, -8, -10, -5, -2, 0, 0, -5, -8, -15, + -23, -32, -39, -38, -33, -24, -15, -7, 5, 16, 30, 45, 52, 49, 40, 23, + 4, -14, -29, -42, -55, -63, -67, -67, -61, -50, -35, -19, 0, 16, 31, 46, + 56, 59, 56, 47, 38, 34, 31, 28, 23, 16, 10, 4, 0, -2, -2, 0, + -5, -9, -12, -11, -7, -3, -3, -4, -5, -4, -7, -14, -26, -33, -32, -27, + -20, -15, -7, 2, 13, 21, 34, 42, 46, 40, 25, 7, -13, -27, -35, -44, + -54, -62, -64, -60, -51, -39, -26, -10, 8, 24, 40, 51, 58, 60, 54, 44, + 36, 29, 24, 19, 13, 8, 0, -6, -5, 0, 1, 0, -4, -3, -2, 0, + 1, -2, -5, -5, -4, -7, -17, -27, -31, -29, -24, -19, -15, -9, -3, 7, + 18, 27, 34, 39, 37, 26, 9, -9, -24, -32, -39, -47, -55, -60, -57, -51, + -42, -32, -20, -6, 14, 31, 48, 57, 60, 58, 52, 45, 35, 25, 21, 17, + 9, 0, -8, -10, -8, -7, -6, -9, -9, -6, -2, 0, -3, -6, -6, -2, + 1, -6, -15, -25, -25, -20, -17, -13, -11, -7, 1, 8, 16, 24, 31, 34, + 29, 16, -3, -17, -28, -35, -41, -47, -54, -56, -54, -46, -37, -27, -15, 4, + 23, 40, 50, 58, 60, 58, 50, 42, 34, 26, 19, 14, 4, -6, -13, -13, + -13, -14, -16, -15, -12, -9, -7, -7, -4, -4, 2, 7, 5, 0, -8, -11, + -13, -13, -11, -10, -11, -11, -9, 0, 8, 14, 22, 24, 19, 9, -3, -14, + -23, -29, -32, -38, -47, -54, -52, -44, -32, -23, -9, 8, 23, 39, 52, 59, + 58, 51, 46, 43, 33, 25, 16, 9, 4, -4, -11, -15, -16, -16, -15, -14, + -15, -16, -13, -7, -5, 2, 5, 5, 5, 6, 3, -4, -6, -4, -5, -10, + -16, -16, -13, -6, 4, 12, 15, 17, 14, 10, 4, -8, -17, -23, -30, -38, + -46, -52, -51, -41, -30, -20, -8, 9, 29, 47, 56, 57, 55, 52, 50, 45, + 34, 20, 10, 2, -2, -9, -16, -22, -24, -22, -21, -22, -19, -14, -7, -4, + 1, 5, 11, 15, 20, 17, 9, 3, 3, 0, -6, -15, -21, -23, -16, -9, + -3, 4, 10, 13, 15, 13, 4, -9, -15, -20, -27, -39, -48, -51, -47, -38, + -29, -21, -7, 16, 36, 48, 51, 52, 55, 60, 59, 49, 33, 20, 12, 7, + -2, -13, -24, -28, -27, -26, -30, -32, -29, -20, -9, 0, 3, 8, 16, 25, + 28, 23, 17, 12, 6, -2, -14, -26, -31, -27, -18, -10, -3, 7, 15, 22, + 24, 18, 9, 0, -9, -19, -34, -46, -57, -57, -51, -44, -38, -26, -5, 21, + 42, 48, 53, 58, 67, 75, 71, 57, 37, 23, 12, 3, -12, -27, -39, -43, + -43, -45, -47, -42, -28, -12, 2, 7, 12, 20, 32, 38, 37, 30, 21, 13, + 1, -13, -26, -34, -33, -26, -17, -10, -3, 9, 20, 25, 22, 13, 5, -3, + -13, -28, -43, -53, -56, -51, -46, -40, -31, -14, 10, 31, 41, 47, 56, 67, + 76, 73, 63, 46, 30, 19, 9, -7, -25, -39, -47, -50, -54, -52, -50, -38, + -22, -9, 4, 12, 22, 30, 39, 41, 39, 31, 22, 12, -3, -19, -30, -32, + -29, -23, -17, -9, 1, 12, 20, 24, 18, 10, 2, -7, -19, -35, -50, -59, + -59, -54, -49, -43, -31, -9, 15, 32, 41, 53, 70, 85, 87, 80, 64, 49, + 37, 23, 2, -23, -42, -52, -59, -66, -69, -68, -56, -38, -18, -2, 9, 19, + 31, 41, 49, 51, 44, 35, 21, 5, -9, -22, -29, -30, -26, -20, -14, -7, + 5, 15, 17, 14, 9, 2, -4, -16, -29, -45, -55, -56, -50, -46, -44, -36, + -19, 1, 19, 33, 46, 63, 79, 86, 84, 73, 60, 47, 32, 12, -10, -30, + -48, -59, -68, -72, -73, -64, -49, -30, -12, 2, 12, 26, 35, 45, 51, 51, + 44, 30, 15, 3, -9, -17, -20, -21, -19, -18, -14, 0, 10, 16, 15, 7, + -4, -10, -14, -24, -38, -51, -58, -55, -50, -44, -36, -23, -7, 10, 26, 41, + 57, 76, 89, 89, 81, 70, 59, 45, 25, 0, -24, -41, -56, -67, -75, -80, + -76, -63, -45, -26, -9, 6, 20, 32, 44, 52, 54, 53, 47, 35, 18, 3, + -6, -11, -14, -16, -19, -19, -12, -4, 5, 5, 0, -8, -12, -15, -21, -34, + -47, -51, -45, -39, -34, -30, -23, -12, 4, 17, 31, 45, 60, 72, 78, 75, + 69, 62, 53, 40, 18, -5, -24, -38, -50, -62, -73, -78, -74, -59, -41, -28, + -17, -4, 14, 33, 47, 55, 58, 55, 48, 39, 29, 16, 4, -5, -11, -18, + -21, -20, -15, -8, -7, -9, -13, -15, -16, -17, -23, -33, -43, -44, -41, -34, + -28, -23, -16, -8, 5, 21, 36, 50, 62, 73, 76, 73, 68, 59, 48, 30, + 9, -16, -35, -48, -59, -70, -77, -79, -72, -54, -38, -24, -8, 8, 29, 45, + 56, 61, 62, 56, 51, 39, 27, 16, 4, -8, -16, -22, -23, -25, -19, -16, + -17, -19, -20, -21, -18, -19, -25, -32, -38, -34, -24, -19, -15, -12, -7, 3, + 15, 28, 39, 48, 56, 63, 63, 63, 57, 47, 32, 14, -5, -22, -36, -46, + -58, -68, -73, -71, -61, -47, -35, -23, -9, 10, 29, 43, 52, 56, 56, 56, + 52, 45, 33, 19, 6, -5, -15, -22, -25, -26, -26, -29, -29, -26, -24, -20, + -19, -23, -27, -30, -27, -21, -18, -14, -10, -7, 0, 8, 18, 30, 40, 47, + 52, 54, 54, 55, 49, 39, 22, 7, -9, -24, -37, -50, -58, -65, -71, -67, + -59, -50, -39, -23, -6, 15, 32, 43, 51, 57, 61, 64, 61, 52, 37, 21, + 4, -11, -20, -26, -30, -35, -37, -39, -35, -29, -22, -17, -20, -22, -20, -18, + -17, -16, -13, -8, -3, 2, 7, 10, 17, 27, 35, 42, 43, 44, 45, 44, + 38, 28, 16, 3, -10, -22, -33, -46, -57, -64, -64, -59, -53, -46, -34, -17, + 3, 21, 32, 41, 48, 55, 60, 60, 54, 44, 31, 18, 3, -10, -19, -27, + -30, -32, -34, -35, -30, -23, -17, -17, -20, -20, -20, -17, -15, -13, -11, -8, + 1, 8, 12, 17, 23, 30, 39, 39, 37, 36, 35, 34, 27, 14, 0, -10, + -15, -23, -34, -46, -56, -60, -56, -49, -39, -32, -23, -8, 8, 23, 32, 38, + 44, 54, 58, 57, 48, 37, 29, 17, 4, -11, -21, -28, -29, -31, -34, -35, + -27, -20, -15, -16, -16, -17, -13, -10, -10, -11, -10, -4, 5, 11, 13, 15, + 21, 29, 33, 32, 28, 25, 25, 23, 16, 5, -6, -10, -16, -21, -30, -42, + -48, -48, -43, -34, -29, -21, -13, -3, 11, 22, 27, 34, 39, 48, 53, 48, + 42, 32, 23, 16, 4, -7, -18, -24, -24, -26, -28, -24, -19, -14, -13, -16, + -18, -18, -16, -14, -15, -16, -15, -7, 3, 11, 14, 21, 27, 33, 36, 33, + 30, 25, 22, 17, 9, -4, -15, -21, -24, -31, -39, -44, -44, -39, -30, -23, + -16, -8, 4, 14, 21, 23, 25, 29, 37, 43, 42, 36, 31, 25, 18, 11, + 4, -7, -11, -13, -16, -21, -22, -18, -14, -13, -16, -19, -21, -21, -19, -19, + -20, -18, -11, -2, 8, 14, 18, 23, 30, 34, 35, 31, 27, 21, 13, 2, + -11, -17, -23, -28, -36, -39, -40, -37, -31, -23, -14, -9, 0, 7, 13, 15, + 15, 16, 22, 27, 30, 28, 29, 32, 29, 23, 16, 9, 4, 1, -2, -7, + -14, -19, -14, -10, -10, -14, -18, -22, -24, -23, -26, -28, -27, -18, -8, -3, + 2, 9, 22, 33, 40, 40, 36, 30, 25, 20, 8, -8, -22, -29, -32, -39, + -48, -50, -42, -30, -19, -13, -8, 2, 11, 22, 25, 21, 17, 15, 20, 23, + 21, 20, 20, 19, 19, 16, 11, 9, 7, 7, 3, 0, -3, -5, -5, -5, + -7, -12, -22, -28, -32, -35, -35, -36, -30, -21, -12, -4, 3, 16, 29, 39, + 46, 45, 40, 34, 26, 13, -2, -17, -28, -37, -48, -57, -60, -52, -36, -19, + -12, -8, 2, 16, 28, 33, 28, 23, 21, 22, 21, 19, 18, 16, 14, 12, + 8, 6, 5, 5, 7, 5, 4, 5, 7, 9, 7, 3, -5, -13, -22, -28, + -35, -44, -49, -48, -38, -26, -14, -7, 4, 20, 38, 49, 54, 53, 49, 40, + 26, 8, -11, -24, -33, -46, -61, -70, -67, -52, -31, -14, -5, 4, 14, 27, + 36, 36, 33, 29, 26, 25, 21, 14, 10, 7, 8, 6, 5, 5, 6, 8, + 9, 10, 14, 18, 17, 13, 5, -4, -12, -20, -28, -37, -49, -56, -56, -48, + -36, -25, -15, -2, 16, 36, 51, 55, 57, 55, 48, 37, 20, 1, -17, -30, + -43, -60, -73, -76, -63, -43, -24, -14, -6, 7, 23, 39, 44, 38, 34, 31, + 32, 30, 24, 16, 8, 5, 6, 6, 5, 5, 6, 10, 10, 13, 16, 19, + 19, 14, 5, -7, -18, -25, -34, -45, -55, -61, -59, -51, -39, -25, -12, 5, + 27, 48, 58, 60, 61, 58, 49, 32, 14, -4, -20, -36, -54, -69, -79, -75, + -57, -35, -21, -15, -4, 12, 28, 39, 42, 41, 38, 38, 38, 33, 23, 13, + 8, 9, 11, 9, 5, 3, 6, 10, 13, 14, 15, 17, 16, 9, -6, -16, + -21, -27, -40, -56, -65, -67, -57, -45, -33, -23, -5, 21, 44, 60, 66, 67, + 65, 61, 47, 25, 2, -16, -34, -53, -72, -83, -82, -70, -51, -33, -20, -8, + 8, 25, 39, 46, 43, 43, 43, 43, 38, 27, 17, 9, 8, 10, 11, 9, + 5, 5, 8, 13, 14, 18, 20, 18, 12, -2, -13, -19, -25, -34, -48, -62, + -69, -67, -58, -46, -32, -14, 9, 30, 48, 60, 69, 72, 69, 57, 36, 13, + -6, -27, -47, -66, -79, -83, -77, -64, -46, -29, -13, 4, 17, 30, 39, 41, + 46, 48, 45, 40, 31, 20, 12, 10, 13, 14, 12, 11, 10, 10, 15, 17, + 20, 20, 17, 12, 0, -14, -24, -30, -37, -47, -60, -69, -68, -62, -51, -36, + -18, 5, 25, 45, 58, 65, 68, 67, 59, 42, 20, -2, -22, -42, -61, -75, + -81, -77, -66, -51, -35, -20, -4, 14, 28, 37, 38, 38, 42, 47, 43, 35, + 24, 17, 14, 14, 17, 20, 20, 17, 13, 14, 17, 18, 18, 17, 11, -2, + -15, -24, -31, -38, -46, -52, -58, -62, -61, -52, -38, -22, -4, 16, 35, 48, + 55, 60, 62, 57, 46, 26, 6, -17, -35, -53, -68, -76, -75, -66, -51, -38, + -23, -7, 10, 25, 35, 38, 37, 39, 40, 39, 30, 21, 16, 15, 15, 16, + 20, 24, 26, 27, 27, 26, 24, 21, 19, 11, -3, -16, -29, -40, -44, -50, + -54, -57, -58, -55, -48, -36, -21, -5, 13, 29, 41, 48, 52, 53, 50, 41, + 26, 7, -14, -33, -49, -62, -70, -69, -61, -48, -36, -21, -5, 16, 30, 35, + 35, 35, 32, 31, 29, 24, 17, 13, 13, 14, 15, 18, 26, 34, 39, 37, + 32, 29, 26, 22, 13, 1, -15, -29, -40, -46, -51, -54, -55, -52, -46, -40, + -32, -22, -10, 5, 19, 28, 33, 35, 37, 38, 33, 21, 8, -7, -20, -35, + -50, -57, -57, -49, -37, -28, -21, -8, 10, 25, 32, 32, 31, 27, 24, 22, + 20, 15, 13, 13, 15, 15, 19, 26, 36, 42, 43, 40, 33, 27, 22, 16, + 3, -13, -26, -37, -44, -50, -55, -54, -48, -42, -32, -24, -18, -10, -3, 8, + 20, 30, 31, 26, 22, 20, 15, 7, -7, -20, -32, -43, -52, -52, -46, -36, + -25, -16, -5, 9, 24, 38, 42, 39, 30, 23, 19, 15, 11, 8, 6, 6, + 6, 9, 18, 30, 42, 47, 45, 43, 38, 31, 22, 8, -9, -21, -33, -45, + -55, -59, -56, -47, -37, -29, -21, -13, -5, 2, 8, 13, 19, 22, 20, 15, + 9, 5, -3, -9, -20, -30, -39, -46, -45, -40, -31, -24, -16, -6, 7, 21, + 35, 39, 36, 31, 24, 22, 15, 10, 8, 5, 6, 3, 4, 12, 25, 40, + 48, 50, 48, 43, 37, 30, 17, -2, -18, -33, -45, -57, -64, -62, -53, -40, + -31, -23, -13, -3, 4, 11, 16, 19, 18, 17, 13, 7, -3, -10, -16, -22, + -31, -40, -45, -45, -41, -32, -24, -15, -5, 8, 24, 39, 47, 44, 38, 32, + 26, 20, 12, 3, -4, -4, -5, -4, 1, 11, 29, 41, 49, 51, 49, 45, + 38, 27, 9, -11, -27, -38, -52, -60, -64, -58, -45, -32, -21, -14, -5, 3, + 10, 13, 13, 14, 14, 12, 4, -6, -12, -17, -21, -25, -31, -35, -40, -39, + -33, -27, -19, -12, 1, 16, 29, 38, 42, 40, 36, 33, 30, 22, 11, 1, + -2, -2, -3, -2, 2, 16, 32, 44, 48, 46, 44, 39, 31, 19, 1, -21, + -36, -48, -58, -62, -59, -49, -38, -28, -20, -12, -2, 9, 16, 16, 15, 16, + 14, 9, 2, -7, -14, -19, -25, -31, -36, -38, -38, -36, -34, -28, -20, -7, + 8, 22, 33, 41, 46, 46, 42, 39, 33, 25, 14, 4, -4, -8, -8, -4, + 4, 16, 30, 38, 42, 46, 45, 38, 25, 10, -7, -24, -39, -51, -58, -59, + -53, -43, -34, -28, -21, -9, 5, 15, 17, 16, 15, 16, 15, 10, 2, -10, + -17, -21, -26, -33, -38, -40, -37, -34, -33, -28, -17, 0, 15, 29, 40, 48, + 50, 48, 44, 40, 34, 26, 15, 3, -6, -11, -11, -4, 7, 18, 24, 30, + 36, 38, 35, 31, 24, 13, -7, -25, -40, -50, -53, -51, -47, -41, -38, -33, + -25, -10, 4, 14, 19, 21, 22, 19, 19, 17, 7, -5, -15, -23, -31, -39, + -46, -49, -49, -46, -41, -33, -19, 0, 21, 39, 53, 61, 64, 63, 56, 50, + 42, 31, 15, -2, -13, -19, -19, -11, 0, 10, 15, 19, 27, 33, 37, 35, + 25, 9, -13, -28, -38, -44, -46, -50, -53, -51, -46, -38, -23, -7, 10, 20, + 21, 24, 25, 28, 28, 19, 8, -7, -18, -28, -36, -43, -52, -56, -57, -51, + -44, -31, -13, 7, 29, 46, 60, 66, 71, 68, 61, 54, 45, 32, 13, -5, + -17, -22, -20, -15, -8, -2, 8, 14, 24, 31, 35, 32, 21, 4, -13, -24, + -34, -42, -49, -55, -58, -54, -48, -38, -23, -4, 14, 26, 32, 31, 32, 36, + 34, 23, 7, -12, -25, -35, -47, -61, -68, -68, -61, -53, -42, -26, -7, 22, + 45, 61, 71, 75, 78, 74, 66, 56, 42, 24, 7, -13, -24, -29, -25, -18, + -11, -7, 2, 14, 27, 36, 38, 32, 19, 1, -14, -22, -33, -44, -56, -64, + -65, -60, -47, -32, -16, 3, 18, 31, 37, 37, 38, 41, 35, 20, 0, -18, + -31, -43, -56, -64, -69, -68, -60, -50, -36, -15, 6, 31, 50, 62, 71, 77, + 78, 74, 66, 54, 38, 20, 2, -15, -23, -26, -24, -22, -17, -7, 8, 20, + 29, 35, 33, 25, 13, -2, -14, -29, -42, -57, -67, -72, -67, -57, -42, -24, + -5, 13, 31, 43, 46, 47, 48, 43, 32, 14, -5, -22, -40, -55, -63, -68, + -69, -66, -57, -44, -25, -5, 18, 37, 55, 66, 75, 78, 75, 70, 62, 47, + 28, 9, -7, -19, -27, -30, -27, -21, -11, 5, 18, 28, 34, 36, 32, 24, + 12, -4, -20, -38, -55, -68, -75, -71, -65, -53, -35, -14, 6, 24, 39, 47, + 50, 48, 44, 36, 22, 5, -16, -34, -47, -56, -60, -60, -59, -54, -45, -28, + -9, 9, 25, 41, 53, 63, 67, 66, 65, 62, 54, 40, 22, 6, -8, -16, + -22, -23, -20, -11, 1, 13, 22, 27, 29, 26, 24, 15, 2, -15, -33, -49, + -64, -74, -74, -67, -55, -39, -20, -2, 16, 32, 45, 50, 49, 43, 35, 26, + 11, -9, -25, -35, -44, -49, -52, -54, -50, -39, -26, -12, 1, 14, 27, 39, + 48, 53, 55, 57, 56, 48, 36, 25, 15, 6, -5, -12, -17, -14, -8, 3, + 14, 21, 26, 23, 21, 21, 14, 3, -11, -26, -44, -61, -72, -72, -68, -56, + -42, -25, -11, 7, 24, 37, 44, 44, 40, 33, 25, 13, 0, -12, -24, -32, + -39, -41, -39, -36, -30, -24, -18, -10, 1, 11, 21, 29, 36, 41, 47, 51, + 51, 42, 35, 27, 19, 10, 1, -6, -10, -9, -2, 6, 11, 13, 13, 15, + 14, 10, 4, -9, -19, -31, -45, -58, -67, -68, -56, -43, -31, -20, -9, 7, + 21, 31, 35, 35, 33, 27, 18, 7, -3, -9, -13, -20, -27, -32, -33, -29, + -23, -19, -16, -12, -4, 6, 15, 23, 30, 39, 47, 49, 42, 35, 31, 27, + 22, 14, 2, -8, -9, -4, 5, 8, 8, 9, 7, 6, 3, 0, -5, -12, + -22, -35, -50, -58, -58, -50, -39, -32, -26, -19, -8, 7, 21, 26, 27, 25, + 22, 18, 11, 5, 2, 1, -3, -10, -19, -24, -23, -16, -15, -17, -20, -17, + -10, -2, 6, 12, 21, 32, 44, 45, 38, 30, 27, 31, 31, 21, 8, 1, + 0, 2, 8, 10, 7, 1, -3, -2, -4, -9, -12, -17, -25, -37, -47, -53, + -50, -42, -32, -27, -26, -22, -11, 5, 15, 18, 20, 22, 23, 22, 18, 15, + 14, 11, 7, -3, -14, -18, -17, -18, -22, -27, -27, -21, -14, -6, 3, 12, + 24, 34, 40, 39, 35, 32, 31, 34, 30, 19, 10, 4, 2, 5, 7, 7, + 1, -6, -10, -9, -8, -8, -11, -16, -25, -34, -41, -41, -36, -32, -33, -33, + -29, -22, -11, -2, 6, 13, 17, 22, 23, 22, 22, 24, 23, 20, 12, 0, + -7, -11, -14, -20, -26, -28, -26, -22, -15, -9, 2, 13, 25, 32, 33, 35, + 36, 37, 38, 35, 29, 19, 9, 5, 7, 6, 4, -3, -9, -12, -11, -6, + -4, -5, -10, -17, -26, -33, -37, -38, -38, -38, -41, -39, -31, -20, -9, -2, + 6, 15, 23, 31, 31, 31, 30, 29, 28, 21, 13, 2, -9, -17, -20, -23, + -26, -27, -26, -20, -14, -6, 6, 14, 22, 26, 32, 34, 35, 37, 37, 36, + 27, 15, 6, 6, 7, 5, -3, -13, -17, -17, -11, -5, -5, -6, -11, -18, + -24, -27, -30, -35, -40, -44, -44, -39, -28, -16, -6, 1, 9, 20, 31, 34, + 36, 37, 36, 33, 23, 14, 5, -3, -10, -17, -23, -30, -34, -31, -22, -14, + -8, 0, 7, 15, 20, 26, 30, 35, 40, 40, 34, 27, 18, 14, 9, 8, + 5, -2, -11, -15, -13, -8, -4, 0, 1, -6, -12, -18, -23, -29, -38, -45, + -52, -53, -47, -37, -28, -16, -5, 6, 17, 28, 37, 42, 43, 40, 37, 31, + 19, 8, 1, -7, -14, -22, -27, -33, -34, -28, -18, -8, 0, 5, 10, 14, + 19, 25, 33, 38, 39, 35, 27, 18, 13, 9, 8, 4, -3, -8, -12, -13, + -10, -4, 4, 4, -2, -7, -14, -21, -28, -36, -45, -53, -54, -50, -44, -34, + -20, -5, 7, 18, 28, 37, 39, 42, 40, 35, 28, 17, 7, 0, -7, -12, + -18, -23, -28, -28, -23, -17, -8, 2, 8, 9, 10, 12, 17, 25, 32, 33, + 28, 20, 13, 10, 10, 8, 6, 5, 1, -5, -6, -3, 3, 10, 10, 5, + -6, -15, -21, -28, -38, -49, -59, -62, -59, -51, -39, -25, -8, 7, 17, 28, + 37, 42, 44, 43, 38, 30, 17, 7, 0, -4, -10, -16, -24, -26, -27, -21, + -14, -9, -2, 5, 11, 14, 12, 13, 19, 26, 29, 26, 19, 13, 8, 8, + 9, 5, 2, 2, 4, 3, 1, 1, 5, 8, 7, 0, -10, -18, -25, -32, + -42, -52, -56, -53, -48, -38, -29, -14, 1, 14, 23, 30, 33, 33, 35, 33, + 26, 17, 9, 2, 1, 0, -5, -12, -19, -22, -21, -13, -8, -4, 5, 10, + 12, 10, 10, 14, 21, 25, 24, 15, 5, 3, 5, 7, 5, 2, 5, 10, + 12, 10, 9, 11, 13, 10, 2, -8, -18, -25, -32, -40, -50, -55, -53, -45, + -35, -27, -17, -4, 11, 20, 28, 30, 28, 29, 30, 28, 19, 10, 6, 6, + 5, 0, -10, -18, -20, -18, -14, -11, -10, -4, 6, 13, 13, 11, 13, 20, + 25, 24, 15, 7, 3, 4, 5, 4, 0, 3, 9, 14, 15, 11, 9, 8, + 8, 6, -5, -16, -24, -29, -35, -43, -48, -47, -42, -31, -23, -17, -7, 5, + 17, 24, 26, 22, 19, 19, 20, 17, 11, 5, 2, 2, 0, -4, -10, -14, + -14, -10, -8, -6, 1, 10, 19, 23, 22, 17, 16, 19, 18, 11, 1, -8, + -11, -10, -7, -4, 1, 7, 15, 22, 22, 18, 17, 16, 12, 4, -8, -21, + -29, -34, -39, -46, -49, -46, -37, -28, -19, -9, -2, 8, 19, 22, 20, 18, + 18, 19, 19, 12, 6, 3, 2, 0, -5, -10, -16, -18, -14, -9, -8, -3, + 6, 17, 25, 27, 26, 24, 25, 22, 15, 3, -8, -13, -13, -12, -11, -6, + 0, 9, 16, 19, 19, 16, 13, 10, 6, -5, -14, -22, -26, -32, -37, -41, + -39, -32, -23, -17, -14, -10, -3, 9, 17, 18, 10, 7, 10, 16, 18, 12, + 5, 1, 1, -4, -13, -18, -18, -15, -12, -11, -10, 1, 15, 29, 37, 35, + 31, 30, 30, 24, 11, -8, -18, -18, -15, -17, -20, -17, -6, 8, 15, 18, + 16, 15, 11, 12, 8, 0, -10, -16, -20, -28, -35, -38, -33, -27, -23, -21, + -19, -13, 0, 11, 14, 12, 9, 11, 18, 21, 19, 10, 2, -3, -5, -12, + -21, -28, -26, -20, -15, -12, -6, 9, 25, 38, 43, 42, 40, 38, 34, 23, + 6, -12, -18, -18, -18, -23, -25, -22, -13, 0, 7, 9, 8, 8, 11, 12, + 9, 6, 2, -5, -14, -21, -24, -24, -22, -22, -21, -22, -20, -12, -3, 4, + 5, 5, 6, 11, 15, 16, 10, 4, -2, -7, -11, -20, -25, -27, -21, -13, + -11, -5, 6, 22, 37, 46, 50, 49, 44, 39, 31, 16, -3, -15, -21, -24, + -27, -32, -33, -28, -17, -5, 5, 7, 7, 10, 15, 16, 15, 10, 4, -4, + -11, -18, -22, -22, -20, -22, -21, -21, -17, -10, 1, 6, 9, 10, 15, 19, + 18, 12, 5, 0, -9, -15, -23, -31, -36, -32, -24, -17, -11, -4, 12, 31, + 47, 53, 58, 60, 56, 49, 35, 15, -4, -16, -21, -25, -32, -42, -45, -35, + -23, -14, -8, 0, 6, 13, 20, 21, 19, 15, 9, 1, -6, -11, -13, -16, + -18, -20, -23, -20, -14, -8, 0, 2, 5, 11, 18, 18, 14, 6, -2, -10, + -18, -27, -34, -41, -40, -31, -20, -12, -7, 4, 23, 47, 64, 71, 71, 63, + 56, 46, 30, 12, -7, -22, -35, -42, -49, -52, -48, -34, -22, -14, -7, 3, + 15, 24, 27, 27, 24, 15, 6, -4, -8, -11, -13, -13, -15, -16, -14, -12, + -7, -2, 3, 10, 12, 14, 15, 7, 0, -7, -16, -25, -32, -40, -44, -44, + -36, -24, -11, 0, 6, 16, 36, 58, 72, 76, 71, 62, 51, 38, 24, 5, + -13, -30, -42, -50, -52, -53, -46, -33, -21, -15, -6, 7, 20, 25, 25, 21, + 18, 14, 7, 2, -5, -9, -9, -7, -8, -9, -10, -7, -3, 1, 6, 7, + 8, 9, 6, -2, -13, -23, -30, -35, -41, -45, -44, -38, -26, -15, -3, 11, + 19, 33, 52, 69, 75, 72, 65, 54, 42, 29, 13, -6, -25, -41, -49, -54, + -55, -48, -38, -26, -18, -8, 1, 13, 24, 29, 26, 19, 11, 5, 2, -2, + -6, -6, -6, -5, -7, -5, 1, 5, 9, 11, 8, 8, 7, 4, -6, -17, + -28, -35, -42, -47, -48, -45, -39, -29, -16, -5, 7, 18, 32, 45, 57, 64, + 67, 62, 54, 45, 35, 22, 5, -13, -28, -40, -47, -49, -46, -42, -32, -21, + -11, -4, 6, 15, 21, 21, 16, 12, 6, 1, -3, -5, -3, 3, 8, 9, + 8, 7, 7, 11, 12, 11, 6, -2, -9, -13, -20, -29, -40, -47, -47, -45, + -42, -37, -29, -16, -5, 7, 17, 27, 38, 48, 56, 59, 53, 44, 40, 37, + 30, 17, -2, -16, -25, -32, -35, -36, -35, -31, -23, -16, -10, -3, 4, 10, + 11, 8, 1, 0, 0, 0, 0, 1, 6, 14, 20, 21, 19, 15, 14, 13, + 11, 7, 0, -13, -21, -28, -37, -46, -51, -48, -43, -37, -32, -28, -21, -9, + 4, 17, 27, 32, 40, 45, 50, 51, 46, 40, 38, 35, 27, 12, -3, -13, + -23, -27, -29, -30, -29, -28, -23, -15, -10, -5, 2, 5, 5, 1, -2, -2, + 1, 4, 4, 8, 14, 19, 25, 26, 21, 15, 13, 12, 12, 5, -9, -21, + -30, -37, -43, -50, -51, -47, -42, -38, -34, -27, -17, -5, 10, 22, 30, 38, + 44, 49, 50, 46, 40, 37, 38, 33, 19, 4, -8, -14, -18, -22, -24, -24, + -22, -18, -16, -14, -10, -6, 1, 1, -6, -8, -9, -6, 0, 2, 8, 14, + 21, 28, 31, 27, 24, 21, 20, 16, 9, -3, -16, -26, -33, -42, -50, -55, + -56, -50, -43, -39, -38, -29, -13, 6, 18, 27, 33, 42, 51, 54, 53, 48, + 41, 39, 38, 29, 12, -5, -15, -19, -20, -23, -24, -22, -18, -17, -13, -12, + -10, -4, -3, -4, -7, -8, -9, -9, -7, 2, 9, 14, 21, 26, 27, 27, + 22, 20, 19, 17, 12, 1, -14, -25, -35, -41, -45, -50, -53, -54, -51, -47, + -41, -31, -18, -3, 12, 24, 35, 47, 55, 58, 57, 55, 49, 46, 40, 26, + 11, -5, -17, -22, -23, -23, -22, -21, -21, -18, -15, -9, -5, -3, -4, -6, + -7, -9, -12, -12, -8, 1, 7, 13, 14, 19, 23, 27, 26, 25, 25, 20, + 13, 4, -9, -22, -36, -42, -48, -55, -61, -62, -59, -54, -43, -32, -18, 0, + 18, 35, 49, 57, 60, 62, 63, 61, 57, 48, 33, 15, -2, -15, -24, -28, + -27, -22, -23, -24, -21, -13, -4, 3, 3, 1, -2, -4, -4, -9, -15, -16, + -13, -9, -5, 2, 7, 11, 19, 24, 28, 31, 29, 28, 24, 12, -4, -21, + -33, -38, -48, -61, -72, -76, -71, -61, -47, -34, -20, 2, 26, 45, 58, 65, + 69, 74, 75, 68, 55, 41, 28, 13, -7, -22, -32, -32, -29, -24, -23, -22, + -19, -7, 6, 7, 2, -2, -3, 0, -3, -10, -20, -24, -19, -12, -5, 1, + 5, 14, 23, 30, 33, 37, 39, 36, 24, 8, -10, -25, -33, -43, -55, -71, + -82, -82, -71, -57, -44, -29, -11, 13, 34, 52, 64, 70, 73, 77, 76, 65, + 50, 35, 20, 4, -13, -26, -31, -32, -27, -26, -25, -21, -10, 2, 8, 5, + 3, 0, 1, 2, -3, -12, -22, -24, -21, -16, -9, -3, 6, 14, 22, 28, + 34, 41, 42, 35, 23, 6, -10, -21, -32, -45, -61, -76, -85, -82, -70, -54, + -43, -29, -7, 18, 40, 55, 64, 71, 77, 81, 76, 62, 48, 32, 19, 6, + -10, -23, -30, -29, -28, -30, -27, -20, -10, -2, 3, 1, 0, 3, 6, 4, + -9, -18, -24, -22, -18, -14, -8, 0, 8, 16, 24, 32, 38, 42, 42, 31, + 15, -2, -14, -25, -38, -52, -67, -81, -85, -76, -63, -49, -37, -19, 3, 26, + 43, 57, 67, 75, 82, 79, 70, 56, 41, 28, 15, 1, -12, -22, -27, -27, + -28, -26, -21, -12, -3, 3, -2, -2, 1, 3, 1, -12, -22, -28, -29, -27, + -23, -18, -11, 3, 16, 25, 34, 44, 51, 52, 43, 27, 12, -2, -17, -34, + -51, -71, -82, -86, -83, -75, -61, -45, -27, -7, 16, 37, 53, 63, 72, 78, + 77, 68, 60, 45, 33, 20, 10, -2, -9, -15, -18, -22, -23, -19, -15, -8, + -5, -7, -8, -7, -4, -3, -10, -22, -29, -29, -24, -21, -18, -14, -3, 12, + 23, 27, 35, 44, 49, 47, 34, 18, 1, -11, -23, -40, -57, -73, -81, -80, + -74, -64, -50, -36, -19, 2, 22, 38, 49, 61, 69, 74, 69, 60, 50, 40, + 29, 20, 10, 2, -5, -9, -12, -16, -18, -14, -9, -6, -10, -13, -12, -10, + -11, -15, -23, -30, -31, -27, -25, -23, -19, -8, 8, 20, 28, 36, 45, 49, + 49, 41, 29, 15, -2, -15, -31, -49, -65, -76, -79, -77, -67, -55, -43, -30, + -13, 7, 25, 40, 51, 60, 66, 66, 62, 54, 45, 37, 29, 22, 14, 7, + 3, -3, -7, -10, -12, -10, -8, -12, -18, -19, -16, -13, -15, -23, -31, -33, + -29, -26, -25, -23, -15, 1, 14, 23, 31, 40, 50, 52, 46, 36, 21, 7, + -8, -24, -41, -58, -70, -75, -74, -67, -57, -43, -30, -18, -3, 13, 26, 39, + 48, 56, 60, 58, 51, 45, 42, 36, 29, 25, 20, 14, 9, 6, 3, 0, + -5, -6, -12, -17, -22, -21, -20, -24, -33, -37, -38, -35, -30, -28, -24, -17, + -3, 12, 24, 33, 43, 50, 52, 49, 40, 28, 13, -3, -18, -34, -51, -63, + -71, -72, -67, -59, -49, -37, -24, -10, 3, 16, 27, 37, 46, 50, 53, 51, + 49, 46, 43, 37, 32, 29, 25, 21, 17, 10, 4, -3, -8, -10, -11, -18, + -25, -29, -31, -34, -37, -40, -40, -37, -31, -25, -20, -13, 0, 17, 31, 41, + 48, 50, 49, 46, 36, 22, 8, -5, -20, -36, -49, -61, -67, -67, -61, -51, + -44, -36, -23, -9, 4, 13, 20, 30, 38, 46, 48, 47, 44, 44, 44, 46, + 42, 35, 31, 28, 24, 15, 5, -3, -6, -10, -18, -28, -35, -39, -41, -41, + -43, -45, -42, -36, -29, -23, -15, 1, 15, 28, 40, 47, 51, 51, 46, 37, + 27, 14, 2, -14, -29, -42, -49, -54, -62, -63, -57, -49, -41, -31, -21, -12, + -3, 6, 17, 25, 32, 40, 45, 49, 50, 48, 49, 49, 48, 44, 39, 34, + 26, 13, 4, -4, -11, -17, -23, -32, -41, -48, -48, -49, -48, -44, -39, -36, + -31, -21, -5, 13, 24, 35, 44, 51, 52, 47, 39, 30, 21, 8, -6, -18, + -34, -44, -50, -54, -59, -58, -53, -46, -38, -28, -18, -10, -4, 6, 16, 24, + 30, 37, 42, 48, 49, 47, 48, 51, 51, 49, 45, 35, 27, 17, 9, 0, + -12, -23, -32, -41, -48, -53, -55, -54, -53, -49, -43, -38, -27, -13, 5, 20, + 33, 44, 52, 58, 57, 50, 40, 29, 16, 5, -11, -29, -43, -53, -56, -62, + -65, -63, -54, -42, -33, -24, -16, -8, 3, 16, 23, 29, 33, 38, 44, 46, + 45, 43, 45, 49, 52, 48, 42, 37, 28, 19, 10, 0, -13, -25, -36, -42, + -47, -56, -58, -56, -53, -49, -48, -40, -26, -6, 13, 27, 39, 49, 59, 64, + 62, 53, 42, 29, 16, 2, -18, -37, -52, -60, -65, -71, -75, -68, -55, -41, + -30, -19, -10, 0, 14, 24, 33, 37, 38, 39, 42, 45, 45, 43, 45, 48, + 47, 46, 41, 35, 28, 19, 8, -6, -20, -30, -38, -44, -50, -55, -57, -59, + -57, -53, -46, -35, -19, 0, 17, 32, 45, 59, 66, 66, 59, 54, 46, 32, + 15, -5, -24, -43, -57, -65, -71, -76, -78, -71, -58, -41, -27, -16, -5, 5, + 15, 27, 37, 43, 43, 42, 42, 42, 43, 46, 46, 46, 45, 42, 41, 35, + 28, 18, 7, -6, -18, -29, -37, -44, -51, -56, -59, -61, -60, -55, -45, -33, + -18, -2, 18, 37, 50, 61, 67, 68, 65, 59, 47, 31, 10, -11, -32, -47, + -58, -71, -81, -86, -83, -70, -52, -36, -21, -9, 2, 13, 25, 35, 41, 44, + 43, 40, 39, 39, 40, 43, 43, 40, 39, 40, 40, 36, 28, 18, 9, -5, + -18, -28, -36, -44, -52, -57, -61, -64, -63, -56, -43, -27, -13, 6, 26, 44, + 56, 66, 71, 71, 64, 55, 42, 23, 3, -19, -38, -52, -66, -76, -82, -86, + -81, -67, -49, -32, -19, -8, 3, 15, 28, 36, 42, 43, 43, 41, 41, 40, + 40, 41, 40, 40, 41, 41, 36, 30, 24, 17, 10, -5, -19, -29, -37, -43, + -50, -57, -64, -66, -60, -50, -40, -28, -10, 12, 32, 45, 54, 59, 64, 67, + 63, 54, 35, 14, -6, -22, -35, -50, -64, -75, -82, -81, -73, -59, -46, -33, + -21, -8, 5, 19, 27, 33, 40, 44, 44, 42, 40, 42, 41, 40, 38, 39, + 38, 38, 35, 30, 21, 13, 4, -8, -16, -25, -35, -45, -53, -62, -65, -63, + -56, -47, -39, -25, -6, 15, 32, 45, 53, 58, 64, 65, 60, 48, 30, 9, + -7, -19, -31, -47, -60, -72, -79, -79, -73, -61, -50, -37, -24, -10, 3, 12, + 22, 33, 43, 47, 46, 44, 43, 45, 46, 45, 45, 43, 41, 38, 34, 26, + 16, 7, -2, -10, -19, -29, -39, -50, -59, -64, -62, -58, -51, -44, -34, -22, + -2, 16, 30, 41, 52, 56, 57, 58, 54, 42, 29, 13, 2, -12, -27, -42, + -56, -67, -71, -73, -70, -63, -55, -42, -26, -10, 2, 11, 20, 33, 41, 46, + 45, 43, 49, 53, 52, 48, 44, 43, 42, 38, 33, 22, 12, 4, -5, -13, + -23, -34, -43, -50, -57, -61, -60, -55, -49, -40, -29, -14, -2, 12, 25, 35, + 44, 51, 56, 56, 49, 39, 30, 20, 10, -2, -17, -32, -48, -60, -67, -74, + -77, -74, -66, -50, -36, -21, -9, 0, 14, 30, 43, 51, 53, 57, 62, 64, + 62, 58, 53, 48, 42, 36, 25, 12, 4, -4, -12, -21, -31, -38, -43, -45, + -47, -49, -47, -44, -40, -34, -28, -22, -11, 1, 11, 21, 28, 39, 49, 53, + 52, 49, 44, 38, 29, 16, -4, -24, -41, -57, -74, -86, -90, -86, -73, -59, + -44, -30, -16, 1, 21, 40, 54, 61, 66, 67, 71, 72, 65, 57, 49, 41, + 33, 24, 12, 1, -8, -12, -15, -22, -31, -37, -35, -31, -33, -36, -39, -40, + -38, -34, -32, -29, -24, -14, -2, 11, 24, 36, 48, 56, 61, 63, 59, 54, + 44, 27, 6, -19, -46, -68, -84, -94, -99, -98, -90, -72, -51, -30, -15, 1, + 22, 46, 64, 76, 78, 80, 81, 78, 72, 60, 45, 34, 24, 13, 0, -13, + -18, -18, -18, -22, -28, -29, -24, -19, -19, -26, -33, -38, -40, -40, -41, -42, + -41, -32, -15, 6, 22, 37, 50, 62, 74, 79, 76, 65, 50, 30, 6, -24, + -54, -78, -94, -106, -110, -103, -89, -69, -49, -29, -10, 11, 36, 57, 73, 78, + 80, 82, 83, 77, 66, 51, 37, 24, 14, 5, -5, -12, -17, -17, -17, -18, + -19, -17, -13, -13, -19, -28, -37, -44, -44, -48, -53, -59, -54, -35, -12, 11, + 29, 46, 61, 78, 88, 90, 84, 68, 49, 24, -6, -39, -71, -92, -104, -115, + -116, -108, -89, -66, -43, -21, 1, 24, 49, 68, 78, 82, 81, 81, 79, 71, + 56, 37, 24, 15, 6, -4, -9, -11, -9, -6, -6, -10, -11, -6, -4, -8, + -20, -33, -44, -55, -61, -65, -70, -68, -55, -31, -6, 15, 38, 61, 82, 97, + 101, 94, 80, 61, 37, 9, -25, -60, -88, -107, -119, -123, -116, -99, -77, -53, + -30, -5, 20, 47, 68, 80, 82, 82, 80, 77, 70, 57, 40, 23, 10, 3, + -2, -3, -4, -3, 2, 5, 7, 5, 5, 4, -4, -17, -32, -45, -60, -69, + -74, -79, -80, -70, -47, -20, 9, 32, 55, 76, 94, 104, 103, 91, 71, 46, + 16, -16, -48, -75, -97, -115, -121, -117, -101, -80, -57, -32, -8, 15, 39, 58, + 68, 73, 73, 73, 69, 61, 50, 39, 26, 15, 7, 4, 7, 12, 18, 19, + 20, 18, 17, 15, 10, -4, -20, -41, -57, -68, -77, -85, -91, -90, -76, -53, + -25, 2, 28, 55, 79, 97, 106, 104, 94, 77, 52, 22, -9, -39, -67, -92, + -111, -119, -115, -99, -79, -55, -33, -11, 15, 37, 55, 67, 71, 68, 61, 51, + 44, 40, 35, 24, 10, 3, 4, 13, 25, 36, 42, 41, 34, 29, 20, 12, + -2, -21, -43, -66, -84, -94, -96, -96, -93, -81, -55, -26, 4, 30, 56, 80, + 98, 107, 106, 95, 77, 53, 24, -8, -38, -64, -85, -101, -109, -109, -100, -80, + -55, -31, -8, 13, 31, 46, 56, 61, 59, 52, 43, 36, 30, 25, 16, 8, + 7, 11, 23, 37, 48, 56, 59, 56, 48, 33, 17, -5, -29, -54, -79, -96, + -106, -109, -105, -96, -82, -57, -25, 8, 38, 61, 79, 94, 103, 102, 92, 73, + 46, 19, -10, -36, -62, -81, -95, -101, -100, -90, -71, -47, -25, -3, 18, 31, + 41, 49, 53, 50, 42, 32, 21, 13, 9, 7, 8, 8, 12, 30, 49, 63, + 71, 76, 75, 67, 48, 25, -3, -30, -59, -87, -107, -120, -124, -117, -105, -89, + -63, -31, 5, 40, 63, 81, 92, 100, 100, 88, 69, 46, 20, -6, -31, -55, + -73, -87, -91, -88, -80, -64, -45, -22, 1, 16, 27, 34, 39, 45, 41, 31, + 20, 9, 4, 3, 1, 3, 6, 15, 32, 53, 71, 81, 85, 86, 78, 61, + 35, 3, -29, -63, -93, -113, -124, -128, -124, -110, -89, -64, -32, 5, 38, 62, + 80, 91, 98, 93, 80, 63, 42, 19, -5, -29, -51, -68, -78, -81, -79, -72, + -58, -40, -19, 0, 13, 21, 29, 35, 35, 29, 21, 14, 8, 2, -2, -3, + 1, 10, 20, 36, 56, 73, 84, 89, 89, 81, 65, 41, 6, -32, -63, -90, + -110, -124, -127, -123, -110, -89, -61, -30, 2, 33, 56, 71, 81, 86, 85, 74, + 58, 38, 17, -5, -21, -38, -52, -62, -69, -69, -64, -50, -34, -18, -5, 5, + 13, 23, 28, 27, 22, 15, 10, 6, 1, 0, -2, 2, 9, 23, 41, 56, + 72, 84, 88, 89, 81, 66, 45, 15, -20, -55, -84, -106, -119, -121, -116, -105, + -89, -67, -38, -7, 21, 44, 58, 69, 75, 74, 64, 50, 36, 22, 8, -10, + -26, -39, -47, -54, -56, -53, -47, -36, -25, -11, -2, 5, 14, 23, 24, 20, + 12, 7, 6, 6, 6, 4, 5, 10, 22, 39, 57, 72, 80, 82, 80, 73, + 62, 45, 18, -13, -48, -78, -96, -105, -105, -104, -97, -81, -64, -40, -15, 10, + 28, 40, 49, 54, 53, 49, 42, 31, 22, 13, 2, -9, -17, -22, -30, -38, + -40, -37, -33, -28, -22, -16, -10, -5, 5, 11, 11, 6, 3, 5, 11, 16, + 16, 18, 22, 29, 40, 54, 68, 75, 74, 72, 63, 49, 35, 15, -10, -37, + -63, -83, -94, -95, -89, -82, -73, -63, -46, -24, -2, 16, 25, 31, 35, 39, + 41, 37, 30, 22, 15, 11, 4, -3, -11, -18, -25, -31, -35, -33, -28, -22, + -18, -16, -13, -4, 5, 10, 11, 10, 5, 6, 14, 21, 23, 24, 27, 33, + 45, 59, 68, 72, 67, 57, 46, 34, 19, 0, -24, -49, -70, -81, -82, -77, + -70, -65, -60, -49, -34, -15, 2, 9, 13, 14, 18, 20, 21, 19, 18, 17, + 16, 15, 13, 10, 5, -3, -12, -20, -26, -28, -27, -24, -26, -25, -18, -9, + 3, 9, 10, 10, 11, 18, 27, 32, 33, 33, 35, 42, 51, 58, 59, 55, + 46, 36, 25, 16, 3, -15, -33, -50, -61, -65, -64, -59, -57, -56, -52, -42, + -29, -14, -5, -2, -3, 1, 8, 12, 13, 13, 16, 16, 18, 19, 19, 14, + 4, -3, -10, -19, -24, -24, -22, -20, -24, -23, -16, -2, 10, 16, 14, 13, + 16, 28, 35, 36, 35, 32, 33, 40, 45, 49, 47, 41, 31, 20, 12, 4, + -8, -16, -29, -41, -50, -53, -50, -49, -51, -51, -48, -40, -30, -20, -13, -13, + -12, -6, 2, 8, 12, 13, 16, 21, 26, 27, 23, 15, 8, 0, -10, -19, + -23, -24, -24, -26, -25, -21, -9, 5, 15, 19, 20, 22, 28, 36, 39, 38, + 36, 33, 33, 35, 37, 38, 36, 30, 20, 9, 4, -3, -10, -17, -26, -35, + -40, -45, -47, -51, -52, -49, -46, -39, -30, -23, -19, -17, -12, -5, 1, 4, + 7, 11, 18, 22, 22, 22, 20, 17, 12, 3, -8, -16, -18, -16, -17, -19, + -18, -12, 3, 13, 19, 20, 24, 29, 34, 35, 33, 32, 31, 31, 30, 26, + 24, 24, 25, 21, 14, 6, 0, -4, -5, -10, -19, -31, -37, -40, -47, -51, + -50, -49, -45, -39, -31, -25, -19, -12, -6, -3, 0, 2, 6, 13, 17, 18, + 16, 15, 16, 14, 7, -3, -10, -12, -13, -13, -14, -13, -6, 6, 18, 24, + 25, 26, 29, 33, 32, 26, 24, 23, 23, 22, 18, 14, 15, 21, 24, 22, + 14, 6, 4, 4, 1, -9, -21, -32, -41, -47, -50, -54, -54, -51, -47, -37, + -30, -21, -10, -3, 1, 4, 6, 7, 8, 7, 7, 7, 7, 6, 6, 5, + 2, -3, -8, -8, -6, -3, 1, 3, 9, 17, 25, 29, 32, 33, 29, 26, + 24, 23, 20, 17, 14, 11, 8, 8, 14, 21, 22, 17, 13, 9, 9, 7, + 1, -11, -25, -37, -44, -52, -53, -55, -55, -51, -43, -35, -24, -14, -4, 3, + 4, 4, 6, 7, 6, 3, -2, -2, 2, 6, 5, 1, -4, -8, -7, -5, + 3, 9, 9, 12, 17, 25, 32, 37, 37, 32, 25, 21, 19, 17, 15, 9, + 6, 6, 6, 8, 14, 23, 24, 20, 15, 14, 11, 3, -6, -18, -31, -44, + -53, -54, -57, -58, -55, -47, -37, -26, -16, -4, 7, 10, 10, 9, 7, 3, + -2, -6, -8, -6, -5, -4, -7, -10, -8, -6, 0, 6, 12, 16, 20, 27, + 33, 35, 35, 36, 34, 28, 21, 16, 10, 7, 7, 5, 3, 1, 5, 12, + 21, 25, 23, 17, 14, 13, 9, -3, -17, -30, -41, -50, -54, -59, -61, -55, + -46, -37, -26, -15, -4, 7, 14, 15, 12, 6, 1, -3, -7, -12, -14, -15, + -13, -12, -12, -12, -8, 0, 8, 15, 20, 25, 31, 36, 40, 41, 41, 38, + 33, 27, 21, 12, 4, 1, 0, -4, -5, -2, 5, 12, 17, 19, 19, 18, + 14, 11, 2, -9, -21, -32, -42, -49, -55, -57, -56, -49, -39, -30, -20, -8, + 3, 12, 17, 18, 12, 5, -2, -8, -14, -18, -21, -22, -21, -21, -19, -13, + -7, 4, 14, 24, 32, 39, 44, 48, 47, 44, 41, 38, 33, 27, 17, 7, + -3, -5, -5, -5, -5, -5, 3, 12, 17, 19, 16, 11, 7, 3, -6, -15, + -26, -36, -42, -48, -53, -54, -50, -40, -31, -22, -12, -2, 11, 19, 20, 13, + 6, 2, -5, -12, -21, -26, -29, -31, -30, -27, -21, -13, -2, 12, 25, 36, + 48, 57, 62, 60, 51, 46, 43, 37, 28, 15, 3, -8, -12, -14, -12, -10, + -7, -4, 8, 16, 20, 17, 14, 10, 6, -2, -12, -24, -32, -39, -45, -51, + -54, -52, -43, -32, -21, -12, -2, 11, 22, 28, 24, 13, 4, -6, -14, -23, + -32, -38, -41, -42, -39, -31, -20, -8, 6, 21, 37, 50, 63, 69, 68, 61, + 55, 48, 39, 29, 20, 9, -6, -15, -17, -13, -11, -7, -4, 3, 11, 13, + 16, 15, 10, 5, 0, -8, -15, -25, -31, -37, -42, -49, -52, -46, -37, -30, + -21, -12, 0, 14, 25, 28, 25, 15, 2, -11, -22, -29, -36, -44, -49, -49, + -43, -32, -18, -5, 13, 30, 50, 66, 74, 75, 71, 68, 61, 50, 37, 26, + 15, 3, -13, -22, -22, -20, -16, -14, -9, 1, 9, 11, 11, 9, 9, 9, + 6, -3, -15, -25, -32, -37, -41, -50, -53, -50, -41, -30, -20, -8, 6, 21, + 31, 33, 26, 15, 0, -12, -23, -34, -46, -56, -60, -54, -44, -31, -19, -2, + 21, 44, 66, 77, 81, 79, 75, 72, 63, 51, 35, 23, 10, -4, -16, -25, + -28, -26, -22, -16, -12, -7, -2, 4, 8, 10, 14, 14, 7, -3, -12, -20, + -28, -36, -42, -48, -53, -53, -43, -31, -19, -6, 12, 25, 31, 30, 26, 15, + -2, -17, -28, -40, -52, -60, -61, -53, -40, -25, -9, 11, 32, 56, 74, 84, + 85, 81, 76, 72, 61, 46, 29, 13, -2, -16, -23, -29, -33, -31, -25, -19, + -14, -8, 2, 10, 14, 18, 19, 17, 8, 1, -12, -24, -35, -42, -49, -54, + -57, -53, -43, -30, -13, 7, 22, 32, 34, 32, 26, 11, -8, -24, -40, -50, + -60, -66, -63, -53, -36, -17, 2, 23, 45, 67, 84, 90, 91, 85, 78, 72, + 62, 44, 24, 4, -9, -21, -32, -39, -41, -36, -30, -23, -17, -9, 2, 13, + 23, 27, 26, 19, 12, 2, -12, -26, -38, -47, -54, -59, -59, -53, -41, -23, + -5, 14, 28, 36, 36, 31, 21, 6, -13, -31, -46, -58, -66, -70, -65, -50, + -28, -7, 14, 35, 58, 76, 89, 96, 94, 90, 82, 72, 54, 35, 16, -5, + -21, -31, -40, -48, -47, -38, -28, -20, -13, 1, 15, 28, 33, 33, 27, 18, + 8, -6, -21, -37, -52, -64, -66, -65, -58, -47, -30, -9, 13, 28, 38, 43, + 40, 31, 15, -5, -24, -40, -57, -69, -75, -74, -65, -48, -26, -2, 24, 47, + 66, 83, 97, 102, 102, 101, 91, 73, 51, 28, 7, -15, -33, -45, -56, -60, + -54, -42, -28, -17, -4, 13, 26, 36, 38, 36, 29, 16, 2, -14, -34, -52, + -62, -66, -65, -63, -53, -36, -15, 9, 27, 36, 41, 40, 35, 25, 8, -16, + -37, -55, -68, -77, -81, -75, -60, -37, -12, 12, 35, 57, 75, 94, 105, 107, + 103, 97, 84, 64, 41, 18, -6, -25, -40, -51, -57, -56, -46, -32, -19, -6, + 7, 20, 30, 34, 32, 24, 12, 0, -17, -33, -47, -60, -65, -64, -58, -46, + -31, -12, 8, 26, 37, 43, 44, 41, 28, 11, -12, -31, -49, -67, -81, -87, + -85, -72, -52, -30, -6, 21, 45, 69, 87, 101, 110, 113, 110, 100, 77, 51, + 27, 8, -11, -32, -49, -59, -59, -53, -41, -27, -11, 3, 14, 24, 28, 28, + 24, 17, 5, -15, -32, -45, -54, -61, -58, -54, -44, -32, -13, 8, 26, 37, + 41, 40, 36, 29, 16, -3, -24, -47, -66, -81, -89, -88, -76, -58, -37, -16, + 10, 34, 58, 78, 94, 106, 111, 107, 97, 81, 58, 37, 17, 0, -17, -33, + -45, -51, -48, -38, -26, -14, -3, 9, 16, 19, 17, 14, 10, 0, -15, -30, + -42, -49, -52, -49, -44, -37, -25, -8, 9, 21, 29, 32, 35, 33, 29, 19, + 1, -18, -38, -58, -75, -85, -85, -79, -70, -52, -29, -6, 20, 44, 67, 89, + 101, 110, 114, 107, 93, 72, 49, 28, 10, -9, -25, -38, -48, -49, -42, -31, + -20, -11, 0, 9, 13, 12, 7, 5, 0, -11, -24, -36, -42, -44, -43, -38, + -28, -16, -4, 8, 16, 22, 29, 30, 29, 24, 13, 2, -14, -32, -51, -68, + -79, -83, -77, -69, -56, -41, -19, 6, 31, 53, 74, 90, 101, 108, 109, 101, + 83, 60, 38, 24, 9, -10, -25, -36, -40, -37, -29, -21, -13, -8, 0, 3, + 0, -5, -6, -8, -16, -27, -35, -39, -40, -33, -27, -21, -11, 3, 14, 21, + 24, 27, 26, 22, 19, 13, 3, -14, -32, -53, -66, -74, -80, -80, -75, -63, + -47, -28, -4, 19, 41, 66, 85, 99, 105, 106, 104, 95, 76, 51, 29, 13, + 2, -12, -27, -36, -38, -32, -22, -15, -12, -8, -3, -4, -9, -12, -14, -18, + -26, -31, -35, -36, -29, -20, -10, -2, 7, 16, 25, 25, 24, 19, 15, 10, + 4, -4, -16, -30, -44, -57, -67, -73, -75, -70, -60, -48, -34, -16, 5, 27, + 51, 71, 85, 92, 99, 101, 95, 82, 64, 44, 28, 14, 1, -12, -22, -28, + -27, -22, -18, -17, -15, -15, -15, -21, -23, -25, -24, -27, -31, -34, -30, -21, + -6, 7, 13, 17, 22, 27, 28, 24, 16, 7, -3, -10, -17, -27, -35, -43, + -50, -58, -68, -70, -65, -53, -42, -32, -22, -4, 15, 36, 54, 70, 83, 89, + 92, 91, 82, 68, 54, 42, 29, 14, 2, -9, -17, -21, -22, -20, -21, -20, + -23, -26, -30, -32, -32, -29, -27, -28, -30, -26, -15, 0, 15, 25, 25, 25, + 26, 27, 21, 11, 0, -9, -17, -24, -30, -38, -45, -47, -49, -55, -59, -56, + -48, -39, -28, -20, -9, 7, 26, 44, 55, 65, 72, 79, 80, 77, 66, 57, + 49, 41, 30, 19, 7, -2, -7, -12, -17, -22, -25, -29, -33, -36, -39, -41, + -36, -29, -26, -26, -22, -11, 2, 17, 28, 32, 31, 29, 28, 23, 11, -2, + -9, -17, -24, -36, -44, -48, -49, -50, -53, -54, -54, -47, -36, -25, -17, -7, + 7, 21, 36, 47, 55, 63, 70, 72, 69, 60, 52, 46, 42, 34, 23, 15, + 8, 3, 0, -7, -14, -21, -24, -27, -32, -39, -44, -43, -37, -29, -25, -23, + -16, -2, 14, 26, 32, 33, 32, 30, 25, 16, 4, -6, -16, -25, -36, -45, + -50, -54, -51, -51, -54, -54, -48, -36, -23, -15, -6, 5, 17, 31, 42, 51, + 59, 62, 63, 61, 56, 51, 43, 40, 38, 28, 20, 13, 9, 7, 2, -8, + -16, -23, -27, -31, -36, -40, -43, -39, -31, -23, -20, -15, -4, 11, 24, 31, + 32, 31, 30, 25, 17, 7, -3, -13, -23, -36, -48, -56, -58, -57, -53, -50, + -52, -51, -40, -25, -12, 0, 7, 16, 25, 36, 49, 58, 60, 59, 57, 54, + 49, 43, 36, 31, 26, 18, 13, 10, 6, 4, 0, -6, -12, -19, -22, -26, + -31, -35, -35, -32, -27, -22, -16, -7, 4, 13, 21, 26, 30, 29, 27, 22, + 15, 4, -7, -19, -31, -44, -55, -59, -59, -58, -54, -52, -49, -41, -28, -14, + 0, 10, 18, 26, 33, 44, 50, 53, 51, 50, 48, 46, 41, 37, 30, 24, + 21, 18, 15, 13, 8, 4, 0, -6, -9, -14, -19, -23, -27, -33, -33, -31, + -25, -19, -11, -3, 3, 11, 20, 28, 31, 28, 22, 14, 8, -3, -15, -29, + -40, -49, -57, -62, -60, -56, -50, -47, -42, -32, -18, -3, 11, 20, 25, 29, + 35, 43, 49, 51, 47, 43, 41, 37, 33, 29, 24, 18, 15, 14, 13, 11, + 8, 5, 1, 0, -5, -11, -19, -23, -24, -25, -25, -26, -22, -15, -9, -3, + 4, 12, 19, 25, 26, 24, 17, 11, 2, -11, -26, -37, -45, -53, -58, -59, + -57, -53, -47, -42, -35, -25, -10, 5, 15, 19, 22, 29, 37, 45, 48, 47, + 44, 44, 43, 40, 33, 24, 19, 14, 13, 12, 8, 2, -2, 1, 1, 1, + -4, -12, -15, -14, -13, -14, -18, -18, -15, -12, -8, -5, 2, 10, 18, 21, + 20, 15, 10, 3, -7, -18, -31, -42, -47, -50, -53, -57, -57, -51, -42, -34, + -25, -15, -5, 7, 16, 22, 30, 35, 40, 43, 42, 39, 39, 38, 38, 31, + 22, 16, 14, 15, 17, 16, 12, 6, 4, 5, 7, 6, 0, -8, -12, -13, + -15, -19, -21, -20, -17, -14, -11, -6, 2, 10, 18, 21, 21, 19, 11, -2, + -17, -29, -37, -42, -46, -52, -55, -58, -52, -42, -34, -24, -15, -5, 5, 12, + 17, 24, 32, 37, 37, 36, 33, 33, 35, 35, 32, 26, 22, 16, 17, 19, + 19, 14, 7, 5, 5, 6, 5, 0, -7, -10, -9, -6, -7, -13, -17, -15, + -11, -8, -7, -6, 1, 7, 12, 13, 11, 7, 0, -12, -25, -35, -40, -42, + -43, -44, -47, -49, -43, -34, -22, -12, -7, 0, 4, 9, 17, 25, 31, 33, + 33, 31, 30, 27, 28, 30, 29, 25, 20, 17, 20, 24, 22, 17, 11, 10, + 9, 9, 5, -6, -11, -13, -9, -5, -9, -16, -19, -16, -9, -6, -6, -2, + 4, 8, 11, 11, 6, -4, -11, -21, -34, -39, -41, -40, -38, -40, -44, -38, + -28, -17, -10, -6, -5, -3, 3, 10, 15, 17, 20, 23, 26, 25, 24, 26, + 28, 30, 30, 28, 25, 24, 23, 25, 22, 18, 14, 9, 5, 0, -7, -12, + -13, -12, -7, -6, -9, -12, -10, -4, 2, 2, 3, 3, 3, 6, 7, 3, + -9, -21, -28, -35, -40, -40, -37, -37, -36, -36, -29, -22, -11, -3, 2, 3, + 0, 1, 3, 6, 9, 10, 10, 10, 13, 16, 21, 24, 29, 31, 33, 33, + 33, 32, 30, 27, 23, 16, 12, 7, -2, -7, -14, -19, -16, -10, -5, -7, + -9, -9, -6, 2, 6, 8, 7, 4, 3, 1, -3, -9, -16, -25, -34, -39, + -41, -37, -33, -31, -31, -29, -22, -12, -4, 2, 7, 5, 1, -2, 0, 4, + 4, 2, 2, 5, 10, 14, 19, 24, 28, 32, 36, 38, 36, 34, 31, 27, + 23, 18, 11, 3, -5, -12, -15, -15, -11, -6, -5, -6, -8, -7, -3, 1, + 4, 6, 3, -2, -7, -9, -12, -19, -24, -30, -34, -36, -35, -32, -29, -26, + -22, -16, -10, -3, 4, 8, 9, 4, 0, -3, 0, 1, -5, -7, -5, 1, + 7, 13, 14, 17, 27, 35, 38, 37, 35, 33, 31, 29, 25, 19, 11, 3, + 0, -6, -10, -10, -7, -5, -5, -7, -7, -6, -3, 1, 4, 3, 0, -8, + -15, -18, -20, -23, -27, -30, -32, -33, -29, -28, -25, -20, -16, -13, -6, 1, + 6, 7, 4, 0, -5, -5, -5, -6, -7, -6, -2, 5, 10, 15, 20, 25, + 32, 34, 34, 34, 32, 29, 24, 22, 19, 14, 9, 6, 4, 2, 0, 0, + 2, 2, -2, -4, -6, -5, -5, -4, -4, -7, -12, -19, -25, -26, -26, -26, + -26, -29, -28, -28, -25, -22, -18, -14, -10, -5, 0, 3, 4, 5, 4, 3, + -2, -7, -10, -12, -9, -6, 0, 6, 11, 14, 16, 22, 30, 33, 34, 29, + 25, 23, 21, 22, 22, 20, 18, 16, 14, 13, 11, 11, 11, 6, -4, -12, + -16, -17, -16, -13, -16, -22, -26, -30, -30, -25, -21, -18, -17, -19, -18, -20, + -19, -15, -13, -9, -7, -6, -5, -2, 3, 5, 4, 0, -5, -8, -6, -6, + -6, -2, 4, 9, 11, 13, 15, 19, 23, 25, 22, 19, 16, 17, 20, 21, + 22, 23, 24, 25, 24, 23, 22, 21, 16, 7, -4, -14, -21, -23, -24, -24, + -28, -34, -38, -36, -31, -21, -13, -9, -8, -10, -11, -12, -14, -13, -12, -9, + -10, -12, -11, -9, -4, 3, 4, 1, -3, -4, 1, 4, 7, 10, 10, 11, + 12, 11, 8, 9, 11, 13, 11, 5, 4, 11, 20, 26, 29, 32, 35, 39, + 39, 34, 30, 23, 15, 5, -10, -23, -31, -34, -32, -33, -37, -42, -41, -32, + -21, -11, -6, -3, -3, -6, -8, -11, -14, -15, -14, -14, -14, -19, -20, -15, + -7, 0, -2, -3, 0, 4, 10, 17, 19, 18, 18, 20, 18, 11, 5, 1, + -2, -4, -7, -8, -4, 4, 14, 24, 32, 38, 46, 51, 52, 46, 37, 28, + 19, 5, -12, -29, -39, -44, -46, -46, -50, -48, -39, -29, -14, -4, 6, 9, + 8, 6, 0, -8, -13, -15, -18, -22, -28, -30, -26, -18, -9, -7, -4, 2, + 10, 18, 24, 26, 26, 23, 22, 21, 14, 3, -5, -9, -14, -16, -16, -11, + -4, 6, 14, 24, 37, 50, 58, 58, 53, 45, 36, 28, 17, 1, -18, -36, + -47, -53, -54, -53, -51, -43, -33, -20, -8, 5, 15, 17, 13, 5, -4, -12, + -14, -18, -23, -30, -34, -32, -24, -15, -10, -6, -3, 7, 18, 27, 32, 33, + 30, 28, 24, 19, 12, 2, -10, -18, -24, -26, -23, -16, -6, 4, 12, 25, + 39, 53, 60, 60, 58, 51, 42, 30, 16, 0, -20, -37, -49, -57, -61, -57, + -50, -40, -29, -17, -4, 9, 17, 17, 11, 5, -3, -8, -13, -21, -30, -35, + -34, -29, -22, -16, -11, -6, 1, 12, 24, 34, 39, 39, 35, 28, 21, 16, + 8, -3, -16, -29, -35, -34, -26, -16, -9, 1, 14, 30, 46, 56, 60, 62, + 59, 57, 46, 32, 15, -2, -17, -35, -51, -61, -61, -55, -46, -39, -30, -19, + -4, 10, 14, 13, 7, 3, -2, -6, -15, -24, -31, -33, -31, -26, -23, -19, + -11, -2, 6, 17, 30, 38, 41, 39, 34, 25, 18, 14, 6, -9, -24, -34, + -38, -34, -28, -18, -9, 0, 14, 32, 44, 52, 58, 63, 66, 59, 45, 31, + 18, 4, -17, -36, -53, -60, -59, -54, -46, -39, -30, -18, -3, 6, 8, 6, + 3, 1, -3, -11, -22, -29, -28, -23, -20, -20, -18, -10, -2, 7, 17, 27, + 34, 37, 38, 33, 26, 19, 15, 11, 0, -17, -31, -39, -40, -34, -27, -20, + -11, 1, 16, 31, 43, 52, 59, 67, 70, 62, 47, 32, 19, 4, -18, -39, + -53, -60, -57, -51, -44, -37, -30, -17, -6, 1, 2, 1, 0, -2, -7, -15, + -23, -27, -25, -19, -16, -15, -12, -4, 5, 15, 25, 33, 37, 34, 31, 27, + 22, 17, 11, 2, -11, -25, -35, -41, -41, -34, -23, -13, -4, 6, 18, 31, + 43, 54, 61, 65, 62, 53, 44, 34, 22, 2, -20, -38, -47, -50, -47, -43, + -42, -41, -32, -19, -13, -11, -10, -7, -5, -5, -9, -14, -18, -17, -12, -9, + -8, -6, 1, 6, 12, 16, 21, 25, 25, 23, 19, 18, 14, 11, 8, 0, + -10, -23, -34, -36, -32, -24, -16, -12, -6, 4, 15, 30, 42, 52, 59, 60, + 58, 53, 46, 39, 27, 5, -19, -35, -43, -44, -43, -45, -49, -48, -39, -31, + -27, -24, -19, -11, -6, -3, -4, -6, -8, -5, 3, 5, 7, 6, 7, 9, + 12, 13, 15, 14, 12, 11, 11, 9, 8, 5, 4, 0, -12, -22, -28, -26, + -21, -17, -13, -10, -5, 4, 14, 22, 32, 44, 56, 61, 59, 56, 48, 38, + 25, 7, -10, -24, -33, -38, -44, -50, -51, -47, -41, -41, -41, -37, -26, -14, + -6, 0, -2, -3, 5, 13, 19, 21, 16, 12, 9, 9, 10, 7, 3, 2, + 2, 1, -2, 0, 3, 4, 1, -4, -12, -16, -16, -9, -9, -10, -9, -5, + 2, 7, 11, 17, 27, 39, 51, 54, 52, 52, 49, 42, 28, 10, -4, -15, + -25, -36, -48, -56, -58, -56, -52, -53, -54, -45, -28, -11, -2, 3, 8, 15, + 24, 30, 34, 30, 22, 16, 12, 6, -4, -9, -9, -8, -12, -14, -12, -5, + 3, 4, 2, -3, -4, 0, 3, 2, -4, -6, -6, -5, -4, -5, -3, 8, + 21, 36, 44, 50, 55, 58, 55, 45, 33, 20, 5, -11, -27, -43, -55, -60, + -61, -62, -64, -66, -58, -40, -20, -6, 3, 8, 16, 26, 34, 39, 38, 30, + 21, 11, 2, -9, -14, -13, -13, -15, -16, -14, -6, 1, 4, 4, 3, 4, + 7, 10, 10, 5, -3, -7, -8, -9, -12, -14, -11, 0, 13, 28, 40, 51, + 58, 61, 60, 56, 47, 33, 15, -8, -28, -44, -55, -62, -72, -81, -83, -74, + -58, -39, -21, -6, 8, 18, 30, 40, 47, 49, 44, 33, 19, 6, -6, -14, + -19, -23, -26, -24, -19, -13, -5, -2, 2, 5, 8, 11, 14, 13, 9, 2, + -4, -8, -12, -15, -19, -18, -13, -3, 14, 30, 44, 53, 62, 66, 66, 59, + 48, 33, 12, -10, -31, -46, -58, -71, -79, -84, -81, -71, -54, -34, -14, 1, + 14, 26, 37, 44, 48, 49, 41, 29, 12, -3, -13, -17, -19, -24, -26, -22, + -16, -8, -3, -2, 3, 6, 10, 13, 12, 10, 6, 2, -4, -11, -18, -22, + -22, -19, -14, -3, 13, 30, 46, 61, 68, 71, 70, 64, 52, 32, 10, -12, + -31, -51, -67, -81, -88, -91, -84, -69, -51, -32, -12, 8, 25, 37, 43, 47, + 52, 50, 40, 23, 5, -8, -13, -18, -23, -28, -26, -19, -12, -6, -4, -2, + 2, 6, 11, 11, 5, 3, 4, 1, -9, -17, -21, -23, -22, -19, -14, 0, + 17, 37, 54, 65, 70, 75, 76, 67, 50, 30, 6, -15, -35, -56, -75, -88, + -93, -88, -78, -64, -47, -26, -3, 17, 31, 37, 42, 46, 48, 42, 27, 10, + 0, -3, -7, -14, -21, -21, -13, -4, 1, -2, -3, 1, 5, 7, 4, -3, + -8, -7, -7, -14, -19, -22, -23, -21, -20, -16, -6, 12, 32, 51, 63, 70, + 76, 78, 75, 63, 44, 20, -5, -26, -46, -67, -83, -94, -93, -83, -69, -55, + -40, -17, 8, 25, 34, 38, 43, 48, 45, 35, 20, 8, 2, 3, -2, -12, + -18, -15, -8, 0, 0, -5, -6, -4, -3, -5, -11, -15, -14, -12, -13, -16, + -19, -20, -20, -16, -10, -2, 11, 24, 42, 57, 64, 70, 73, 72, 64, 48, + 26, 4, -15, -35, -50, -68, -81, -88, -81, -68, -55, -44, -29, -10, 9, 22, + 25, 30, 37, 38, 35, 24, 14, 11, 13, 14, 9, 0, -5, -3, 3, 4, + -2, -10, -15, -15, -15, -19, -25, -24, -20, -18, -19, -20, -18, -16, -13, -9, + 1, 12, 25, 37, 53, 63, 69, 74, 73, 69, 56, 37, 15, -6, -25, -42, + -59, -75, -82, -81, -72, -61, -50, -35, -17, -2, 13, 20, 27, 31, 34, 34, + 28, 19, 14, 13, 15, 14, 8, 4, 3, 5, 5, 1, -6, -15, -18, -22, + -27, -33, -34, -31, -25, -24, -20, -19, -17, -10, -2, 9, 18, 28, 39, 51, + 60, 67, 71, 72, 67, 53, 35, 16, -4, -21, -40, -57, -70, -76, -74, -65, + -55, -44, -34, -21, -7, 6, 15, 18, 20, 24, 24, 21, 16, 15, 16, 17, + 17, 16, 13, 12, 13, 13, 9, 0, -12, -17, -22, -31, -40, -43, -40, -35, + -30, -26, -24, -20, -11, -2, 9, 19, 29, 39, 46, 54, 60, 66, 67, 66, + 58, 41, 21, 5, -11, -29, -47, -62, -68, -68, -65, -57, -49, -39, -27, -13, + -2, 6, 11, 18, 23, 24, 21, 19, 19, 21, 21, 18, 15, 11, 13, 15, + 15, 10, -2, -8, -14, -21, -30, -39, -44, -44, -40, -33, -29, -27, -21, -12, + -3, 6, 16, 28, 40, 48, 54, 56, 59, 61, 62, 57, 44, 28, 12, -3, + -22, -40, -55, -64, -63, -61, -56, -51, -41, -29, -15, -6, 1, 8, 15, 20, + 20, 18, 17, 18, 23, 23, 20, 17, 15, 18, 20, 20, 15, 4, -5, -11, + -20, -32, -43, -49, -48, -43, -36, -32, -29, -21, -13, 0, 11, 20, 30, 38, + 46, 50, 51, 53, 56, 53, 48, 41, 30, 19, 5, -10, -26, -42, -50, -56, + -57, -56, -53, -46, -38, -27, -18, -10, -2, 8, 16, 19, 24, 24, 22, 23, + 25, 23, 17, 16, 15, 16, 14, 10, 3, -5, -11, -20, -28, -35, -42, -44, + -42, -35, -29, -25, -19, -11, 0, 10, 20, 26, 31, 38, 45, 48, 46, 46, + 44, 41, 37, 30, 22, 13, 1, -15, -27, -36, -44, -49, -51, -52, -49, -44, + -37, -27, -20, -12, 1, 10, 19, 23, 28, 29, 28, 28, 24, 19, 17, 16, + 15, 14, 10, 4, -3, -10, -15, -23, -31, -36, -41, -41, -39, -32, -24, -19, + -11, -3, 5, 15, 24, 31, 36, 42, 45, 44, 41, 37, 33, 31, 29, 23, + 14, 2, -8, -16, -22, -31, -40, -44, -46, -46, -46, -44, -37, -28, -20, -10, + 2, 11, 20, 28, 32, 32, 29, 26, 22, 19, 17, 14, 12, 11, 8, 2, + -5, -14, -20, -24, -30, -34, -37, -38, -36, -30, -21, -14, -6, 2, 11, 19, + 26, 30, 34, 41, 44, 42, 38, 32, 27, 25, 24, 21, 11, 1, -9, -16, + -25, -34, -40, -43, -45, -48, -50, -49, -40, -27, -15, -6, 4, 15, 27, 36, + 40, 37, 32, 27, 22, 15, 11, 10, 8, 6, 0, -8, -14, -16, -17, -18, + -24, -31, -33, -33, -27, -22, -17, -10, -4, 6, 13, 17, 22, 27, 33, 38, + 39, 37, 35, 33, 31, 27, 23, 19, 11, 3, -7, -20, -30, -38, -42, -42, + -46, -53, -58, -53, -41, -27, -13, -2, 10, 19, 30, 39, 43, 38, 29, 23, + 18, 12, 8, 6, 6, 4, -3, -8, -12, -13, -10, -12, -17, -24, -25, -23, + -23, -23, -19, -12, -4, 2, 5, 9, 14, 22, 32, 37, 39, 39, 37, 37, + 33, 28, 27, 21, 12, 0, -14, -25, -33, -38, -43, -48, -54, -60, -59, -48, + -36, -20, -8, 2, 12, 26, 39, 44, 40, 32, 27, 23, 16, 8, 3, 3, + 2, 1, -4, -9, -9, -6, -6, -8, -13, -16, -18, -21, -22, -21, -16, -7, + -2, 0, -2, 2, 13, 25, 30, 34, 34, 34, 34, 33, 33, 31, 26, 21, + 11, -3, -15, -25, -31, -37, -48, -57, -62, -63, -56, -46, -35, -25, -12, 5, + 18, 32, 40, 40, 36, 32, 29, 22, 15, 7, 3, 0, 0, 0, 1, -2, + -2, 0, 0, -3, -4, -7, -13, -22, -28, -25, -17, -10, -10, -11, -10, -4, + 12, 26, 36, 39, 40, 41, 40, 37, 35, 33, 28, 19, 3, -11, -22, -30, + -37, -46, -56, -63, -65, -59, -52, -43, -29, -17, -4, 10, 23, 32, 36, 36, + 34, 29, 24, 19, 12, 5, -2, 0, 4, 7, 10, 9, 6, 5, 5, 5, + 0, -10, -20, -26, -29, -26, -20, -18, -19, -17, -9, 3, 16, 28, 36, 40, + 42, 43, 41, 40, 36, 33, 26, 16, 3, -10, -21, -31, -42, -53, -61, -65, + -63, -58, -52, -41, -31, -18, -4, 9, 21, 26, 29, 30, 31, 31, 28, 21, + 12, 6, 5, 10, 13, 13, 14, 9, 8, 7, 5, 0, -8, -17, -24, -28, + -27, -23, -17, -14, -12, -8, 2, 15, 26, 32, 36, 39, 38, 37, 36, 33, + 28, 21, 16, 10, 1, -13, -25, -34, -41, -50, -59, -62, -62, -53, -44, -37, + -28, -19, -6, 7, 14, 18, 22, 26, 28, 28, 21, 13, 6, 6, 15, 19, + 21, 20, 20, 18, 16, 13, 7, -3, -12, -21, -27, -31, -30, -24, -15, -11, + -8, 0, 10, 23, 29, 32, 34, 34, 34, 33, 32, 27, 23, 20, 17, 10, + -2, -15, -25, -34, -43, -52, -61, -63, -58, -49, -43, -41, -33, -22, -9, 3, + 11, 17, 21, 26, 30, 28, 23, 17, 15, 18, 22, 22, 20, 21, 21, 18, + 12, 4, -5, -11, -16, -22, -28, -32, -24, -14, -7, -5, 1, 11, 20, 27, + 30, 26, 25, 29, 30, 29, 22, 17, 18, 22, 20, 9, -8, -18, -25, -31, + -40, -53, -60, -58, -54, -46, -45, -42, -32, -20, -10, -2, 5, 12, 19, 25, + 27, 22, 18, 18, 21, 24, 25, 22, 24, 26, 27, 22, 10, 0, -7, -9, + -12, -21, -28, -28, -20, -9, -4, -2, 5, 14, 22, 24, 21, 15, 18, 24, + 28, 24, 19, 21, 26, 30, 22, 7, -6, -15, -23, -34, -50, -61, -66, -61, + -52, -50, -49, -45, -36, -22, -10, 1, 11, 15, 20, 26, 26, 24, 21, 21, + 27, 28, 24, 21, 22, 26, 24, 16, 5, -5, -7, -5, -11, -17, -22, -17, + -7, 0, 1, 4, 9, 16, 19, 18, 13, 12, 16, 22, 24, 23, 23, 28, + 33, 27, 16, 2, -12, -23, -33, -45, -57, -64, -64, -55, -51, -52, -49, -39, + -25, -13, -6, 1, 6, 12, 16, 18, 20, 18, 20, 25, 28, 28, 29, 31, + 36, 37, 28, 15, 7, 3, 0, -4, -14, -21, -23, -16, -7, -4, -3, 1, + 10, 16, 17, 10, 7, 9, 18, 24, 24, 24, 28, 34, 34, 26, 12, -3, + -15, -26, -40, -53, -61, -65, -62, -59, -57, -55, -49, -39, -27, -18, -6, 3, + 8, 14, 17, 21, 25, 26, 27, 28, 30, 32, 32, 31, 32, 28, 22, 14, + 6, 3, 0, -3, -8, -12, -12, -5, 0, 2, 1, 3, 6, 11, 11, 7, + 4, 6, 13, 20, 24, 28, 31, 32, 28, 19, 7, -7, -20, -32, -44, -53, + -58, -58, -55, -54, -53, -50, -46, -40, -27, -14, -6, -6, -5, 0, 8, 16, + 20, 23, 25, 30, 37, 42, 43, 41, 39, 34, 28, 18, 9, 4, 3, 0, + -10, -13, -12, -10, -5, 1, 1, 0, 4, 8, 7, 5, 6, 11, 19, 23, + 27, 32, 33, 27, 20, 10, 0, -15, -30, -41, -49, -52, -54, -55, -55, -53, + -50, -45, -40, -32, -24, -16, -11, -10, -8, -3, 6, 13, 17, 21, 29, 37, + 43, 48, 47, 43, 38, 35, 30, 19, 11, 7, 2, -5, -9, -9, -5, 1, + 1, 0, -2, 1, 3, 6, 5, 4, 5, 10, 16, 20, 24, 27, 25, 18, + 10, 3, -9, -21, -31, -39, -44, -47, -47, -44, -46, -48, -48, -45, -39, -36, + -30, -26, -25, -23, -19, -9, 4, 14, 24, 32, 41, 48, 54, 56, 57, 52, + 47, 40, 28, 17, 10, 4, -3, -8, -10, -8, -6, -5, -5, -5, -3, 0, + 3, 4, 4, 5, 7, 12, 19, 26, 27, 24, 18, 12, 5, -3, -12, -24, + -34, -43, -46, -48, -48, -46, -46, -45, -44, -42, -38, -33, -29, -26, -26, -22, + -14, -5, 5, 13, 23, 32, 40, 47, 52, 56, 57, 55, 52, 47, 36, 27, + 19, 11, 3, -5, -6, -8, -10, -13, -15, -14, -13, -11, -6, 1, 4, 7, + 11, 17, 21, 26, 28, 26, 19, 10, 2, -7, -17, -26, -36, -41, -45, -47, + -45, -44, -44, -41, -39, -40, -40, -37, -33, -34, -32, -26, -18, -9, 2, 12, + 26, 40, 47, 56, 63, 66, 66, 63, 60, 53, 40, 27, 14, 3, -8, -11, + -12, -15, -19, -19, -18, -15, -12, -8, 0, 6, 11, 13, 14, 17, 23, 29, + 27, 18, 9, 1, -7, -16, -25, -35, -43, -49, -47, -44, -43, -42, -40, -36, + -34, -33, -33, -33, -35, -34, -30, -23, -16, -9, 2, 14, 27, 39, 49, 58, + 66, 69, 68, 66, 61, 53, 45, 32, 18, 1, -11, -14, -17, -17, -20, -23, + -21, -17, -13, -3, 4, 10, 13, 14, 17, 18, 21, 24, 22, 15, 6, -4, + -12, -22, -28, -38, -49, -51, -48, -45, -43, -40, -38, -36, -35, -34, -33, -33, + -34, -35, -33, -29, -18, -6, 6, 19, 33, 46, 59, 71, 78, 78, 78, 74, + 67, 54, 39, 22, 6, -8, -16, -22, -25, -25, -26, -22, -17, -12, -3, 6, + 15, 17, 16, 14, 14, 16, 17, 16, 13, 6, -2, -11, -20, -27, -34, -43, + -49, -48, -44, -41, -39, -36, -33, -34, -33, -34, -32, -33, -35, -35, -30, -21, + -11, 0, 9, 23, 38, 52, 65, 74, 76, 76, 74, 70, 62, 47, 28, 13, + 2, -6, -14, -21, -23, -20, -18, -16, -13, -7, 1, 8, 10, 11, 9, 11, + 11, 13, 15, 16, 13, 8, -2, -11, -19, -27, -37, -47, -52, -51, -48, -46, + -43, -40, -38, -36, -35, -35, -38, -38, -33, -27, -21, -16, -7, 6, 21, 36, + 49, 61, 70, 75, 79, 78, 73, 62, 49, 35, 22, 8, -3, -12, -17, -20, + -18, -14, -13, -15, -12, -5, 4, 7, 8, 8, 9, 8, 9, 11, 14, 14, + 10, 4, -6, -15, -25, -35, -41, -48, -54, -53, -47, -42, -38, -37, -35, -31, + -31, -30, -30, -29, -26, -24, -19, -12, -2, 10, 22, 35, 48, 60, 70, 76, + 76, 73, 67, 57, 44, 28, 14, 5, -3, -8, -13, -14, -13, -10, -11, -11, + -8, -2, 4, 6, 5, 5, 5, 6, 10, 11, 10, 8, 4, -2, -9, -15, + -24, -35, -44, -50, -52, -49, -45, -42, -42, -40, -37, -37, -37, -33, -29, -26, + -24, -21, -16, -7, 6, 18, 30, 41, 54, 66, 75, 77, 79, 76, 67, 53, + 37, 21, 8, 2, -5, -10, -14, -14, -12, -12, -11, -10, -5, 4, 7, 4, + 1, 2, 6, 9, 9, 7, 5, 4, 0, -7, -14, -23, -32, -37, -43, -48, + -50, -51, -47, -42, -34, -32, -32, -34, -32, -26, -21, -18, -17, -14, -11, -4, + 5, 13, 24, 40, 55, 67, 72, 74, 76, 75, 67, 51, 37, 23, 11, 4, + -4, -11, -15, -17, -17, -16, -14, -13, -8, -2, 1, 1, 1, 3, 5, 9, + 7, 5, 4, 4, 3, -5, -14, -24, -32, -38, -41, -47, -52, -53, -49, -41, + -35, -34, -35, -33, -29, -24, -19, -13, -10, -9, -7, -2, 8, 17, 29, 43, + 56, 67, 74, 75, 75, 72, 64, 53, 38, 23, 13, 4, -5, -12, -16, -20, + -21, -18, -16, -14, -11, -8, -5, -3, 0, 2, 6, 6, 6, 5, 5, 6, + 3, -6, -19, -31, -37, -41, -45, -50, -52, -53, -48, -39, -32, -30, -26, -25, + -22, -16, -10, -7, -11, -10, -8, -2, 6, 17, 31, 45, 58, 68, 78, 80, + 76, 70, 65, 55, 37, 18, 5, -4, -10, -19, -25, -26, -24, -18, -13, -11, + -9, -6, -2, 4, 6, 5, 4, 3, 4, 2, 1, -3, -4, -11, -20, -29, + -38, -43, -45, -48, -51, -48, -44, -39, -35, -34, -31, -30, -25, -15, -8, -8, + -10, -8, 1, 11, 22, 33, 42, 54, 66, 76, 80, 75, 70, 66, 59, 42, + 23, 6, -4, -9, -17, -22, -27, -25, -19, -9, -7, -8, -5, 0, 4, 5, + 2, -2, -5, -5, -4, -6, -7, -6, -10, -16, -21, -29, -34, -37, -38, -41, + -44, -42, -36, -32, -33, -37, -39, -35, -27, -17, -12, -13, -12, -6, 6, 22, + 36, 44, 54, 66, 77, 82, 80, 75, 68, 59, 47, 29, 10, -3, -13, -18, + -23, -26, -27, -24, -16, -9, -5, -4, -2, 3, 6, 4, -2, -6, -8, -7, + -8, -8, -9, -10, -13, -16, -22, -29, -31, -30, -34, -36, -36, -32, -28, -30, + -36, -39, -38, -33, -28, -24, -24, -22, -15, -2, 13, 26, 38, 53, 67, 78, + 84, 88, 85, 81, 71, 59, 39, 13, -5, -14, -19, -26, -32, -34, -30, -22, + -13, -5, 0, 6, 7, 10, 8, 2, -4, -10, -12, -15, -18, -20, -20, -20, + -22, -24, -26, -26, -23, -23, -23, -24, -21, -17, -18, -25, -31, -35, -37, -37, + -36, -33, -29, -22, -10, 5, 19, 31, 45, 62, 75, 84, 86, 88, 87, 80, + 66, 45, 22, 4, -9, -18, -26, -34, -37, -33, -24, -15, -9, -3, 6, 13, + 15, 11, 2, -5, -10, -13, -20, -25, -27, -26, -25, -26, -29, -29, -23, -18, + -16, -19, -18, -15, -9, -6, -12, -21, -32, -36, -36, -40, -39, -36, -30, -21, + -10, 6, 20, 36, 55, 69, 79, 85, 90, 92, 88, 75, 56, 33, 12, -3, + -15, -24, -33, -37, -35, -28, -20, -12, -4, 6, 14, 18, 16, 9, 0, -8, + -15, -19, -27, -33, -35, -34, -34, -36, -36, -29, -19, -10, -10, -10, -8, -4, + -2, -2, -8, -18, -28, -36, -43, -48, -46, -36, -25, -14, -4, 10, 27, 46, + 65, 78, 86, 89, 87, 85, 78, 64, 42, 19, 0, -12, -20, -29, -34, -36, + -30, -22, -12, -6, 1, 8, 16, 18, 13, 2, -7, -12, -17, -24, -33, -38, + -39, -36, -36, -36, -34, -26, -18, -11, -7, -6, -5, -5, 1, 1, -5, -14, + -24, -33, -41, -42, -37, -28, -19, -10, 3, 16, 30, 47, 64, 76, 83, 85, + 83, 78, 69, 54, 37, 17, -2, -14, -21, -28, -32, -32, -27, -18, -11, -6, + 2, 12, 18, 16, 5, -5, -11, -14, -19, -30, -40, -47, -45, -38, -36, -34, + -33, -26, -15, -6, -2, 1, 1, 3, 5, 4, -3, -13, -26, -35, -41, -39, + -33, -23, -13, -5, 7, 21, 36, 53, 68, 79, 82, 78, 72, 66, 59, 47, + 30, 10, -6, -16, -21, -22, -25, -27, -25, -18, -10, -4, 4, 10, 11, 6, + -4, -11, -13, -18, -25, -34, -43, -45, -41, -36, -34, -32, -27, -19, -10, -5, + 0, 2, 5, 5, 5, 1, -7, -16, -25, -33, -38, -35, -25, -13, -6, 0, + 11, 27, 46, 60, 69, 70, 68, 69, 68, 62, 52, 39, 22, 8, -2, -11, + -18, -21, -22, -23, -24, -17, -10, -5, 1, 5, 5, 2, -3, -5, -9, -17, + -28, -41, -46, -48, -43, -42, -42, -39, -30, -19, -9, -3, 6, 11, 15, 16, + 12, 5, -2, -12, -23, -33, -37, -34, -25, -18, -8, 1, 15, 32, 48, 62, + 69, 68, 67, 63, 62, 58, 50, 34, 15, -2, -8, -10, -11, -16, -24, -24, + -19, -12, -6, -2, 2, 3, 1, 0, -6, -10, -17, -26, -37, -46, -48, -45, + -44, -42, -38, -32, -22, -12, -6, 4, 10, 14, 16, 15, 11, 5, -2, -11, + -23, -31, -29, -22, -18, -16, -11, 3, 17, 34, 50, 56, 59, 61, 63, 62, + 59, 53, 44, 32, 16, 3, -8, -9, -13, -20, -26, -27, -21, -16, -11, -9, + -6, 1, 7, 7, 0, -10, -15, -20, -30, -39, -45, -48, -48, -46, -41, -36, + -29, -20, -11, 3, 11, 14, 19, 21, 19, 15, 6, -3, -13, -18, -18, -17, + -20, -19, -12, 2, 15, 26, 36, 43, 51, 59, 61, 61, 57, 54, 49, 37, + 21, 9, 1, -8, -17, -25, -29, -28, -27, -23, -19, -13, -5, 2, 8, 5, + -4, -11, -13, -17, -27, -40, -49, -53, -53, -50, -44, -37, -28, -19, -7, 8, + 18, 22, 26, 26, 23, 17, 10, 0, -8, -15, -20, -25, -23, -19, -11, 0, + 13, 25, 34, 44, 54, 60, 62, 60, 58, 56, 52, 38, 21, 6, -6, -16, + -26, -32, -33, -30, -26, -24, -17, -8, 3, 13, 16, 10, 1, -7, -12, -18, + -34, -50, -61, -63, -58, -54, -50, -45, -33, -13, 6, 21, 27, 34, 37, 36, + 30, 20, 11, -2, -13, -24, -32, -37, -34, -24, -10, 2, 12, 25, 41, 55, + 61, 64, 65, 67, 64, 59, 48, 32, 16, 0, -12, -20, -27, -33, -33, -31, + -28, -23, -12, 0, 10, 13, 9, 2, -2, -7, -13, -25, -41, -56, -65, -66, + -62, -56, -53, -42, -25, -5, 13, 24, 34, 39, 42, 39, 32, 22, 11, -2, + -15, -27, -36, -37, -31, -22, -13, 0, 12, 27, 43, 55, 61, 64, 65, 63, + 60, 53, 42, 28, 10, -6, -20, -27, -28, -28, -25, -23, -20, -13, -2, 11, + 16, 14, 8, 2, -6, -14, -25, -38, -53, -67, -73, -73, -67, -58, -46, -32, + -14, 6, 24, 36, 43, 45, 44, 39, 30, 18, 5, -11, -25, -35, -39, -37, + -28, -17, -7, 4, 16, 32, 48, 58, 64, 66, 63, 61, 56, 46, 31, 18, + 3, -13, -21, -25, -23, -19, -15, -11, -7, -2, 6, 13, 14, 8, -3, -12, + -21, -32, -40, -55, -70, -78, -75, -67, -56, -47, -29, -12, 10, 29, 40, 47, + 49, 48, 43, 31, 15, 0, -16, -29, -39, -45, -41, -32, -18, -6, 3, 13, + 27, 43, 57, 64, 65, 61, 58, 52, 43, 32, 18, 6, -9, -18, -20, -17, + -12, -4, 1, 3, 7, 12, 17, 16, 9, -3, -15, -27, -39, -48, -60, -72, + -82, -82, -73, -58, -45, -33, -14, 7, 28, 42, 49, 51, 51, 48, 38, 22, + 2, -16, -30, -37, -42, -45, -40, -26, -11, 3, 11, 20, 34, 52, 65, 69, + 64, 54, 46, 38, 28, 16, 4, -11, -18, -16, -10, -4, 3, 13, 21, 23, + 22, 20, 18, 11, -2, -16, -34, -47, -59, -70, -76, -83, -83, -76, -64, -48, + -31, -12, 10, 30, 42, 50, 53, 51, 46, 37, 25, 8, -13, -30, -41, -45, + -43, -35, -23, -15, -5, 8, 17, 28, 40, 56, 64, 63, 55, 45, 34, 24, + 14, 7, -4, -12, -13, -9, -2, 11, 23, 31, 33, 33, 31, 26, 17, 4, + -14, -31, -48, -62, -75, -86, -90, -87, -79, -68, -54, -39, -18, 4, 23, 39, + 47, 52, 52, 47, 39, 29, 15, -5, -23, -35, -41, -40, -34, -26, -16, -8, + 2, 12, 22, 30, 43, 52, 58, 54, 45, 36, 25, 16, 7, -2, -7, -8, + -3, 4, 13, 24, 32, 39, 42, 39, 30, 19, 6, -10, -25, -44, -62, -79, + -88, -90, -85, -78, -70, -59, -45, -24, 0, 20, 35, 43, 48, 48, 46, 42, + 33, 20, 2, -19, -32, -38, -41, -37, -29, -19, -8, 1, 11, 19, 26, 35, + 43, 48, 48, 41, 35, 26, 16, 7, 0, 0, 3, 6, 10, 16, 24, 32, + 40, 44, 43, 33, 21, 8, -5, -19, -37, -54, -72, -84, -87, -81, -75, -68, + -61, -50, -33, -12, 8, 22, 29, 34, 40, 42, 41, 35, 24, 13, -2, -16, + -27, -33, -33, -27, -22, -17, -13, -4, 9, 18, 25, 31, 36, 42, 44, 40, + 32, 21, 12, 9, 7, 8, 9, 13, 17, 23, 29, 35, 40, 40, 35, 26, + 13, 0, -11, -24, -41, -60, -74, -80, -79, -73, -68, -63, -56, -43, -27, -10, + 6, 18, 24, 29, 34, 38, 37, 30, 20, 9, -3, -14, -24, -27, -27, -25, + -23, -18, -9, 2, 10, 19, 25, 30, 37, 40, 41, 33, 22, 16, 10, 6, + 6, 10, 16, 21, 28, 31, 35, 38, 44, 45, 34, 19, 5, -5, -17, -33, + -52, -68, -76, -78, -75, -71, -67, -62, -51, -37, -20, -7, 4, 13, 21, 29, + 34, 36, 33, 26, 17, 10, 0, -8, -13, -19, -21, -21, -17, -11, -6, 4, + 10, 13, 19, 25, 30, 31, 28, 20, 14, 10, 7, 7, 11, 20, 26, 32, + 36, 39, 41, 44, 46, 41, 30, 13, 0, -13, -27, -44, -62, -72, -74, -74, + -74, -71, -66, -57, -47, -32, -19, -9, 2, 14, 24, 28, 32, 34, 33, 25, + 17, 9, 2, -5, -10, -17, -22, -18, -13, -7, 0, 4, 10, 17, 23, 26, + 25, 21, 15, 9, 9, 7, 4, 7, 16, 27, 34, 39, 43, 48, 49, 52, + 49, 39, 24, 9, -3, -17, -32, -52, -67, -75, -75, -71, -70, -70, -66, -56, + -43, -31, -21, -12, -2, 11, 21, 27, 30, 33, 31, 29, 22, 15, 8, 0, + -6, -13, -14, -14, -11, -5, 0, 4, 8, 13, 16, 18, 15, 12, 10, 7, + 7, 6, 7, 14, 24, 36, 44, 46, 46, 49, 52, 53, 47, 35, 21, 9, + -6, -23, -43, -59, -68, -71, -74, -74, -76, -73, -64, -52, -39, -31, -25, -15, + 0, 12, 20, 24, 29, 32, 30, 26, 21, 16, 10, 4, -2, -7, -7, -5, + -3, 0, 3, 5, 6, 9, 8, 8, 6, 3, 2, 4, 5, 7, 14, 22, + 34, 43, 49, 57, 57, 55, 52, 48, 43, 31, 17, 2, -13, -33, -49, -59, + -63, -66, -72, -75, -76, -70, -61, -52, -44, -37, -30, -18, -4, 11, 20, 25, + 28, 32, 32, 30, 26, 19, 13, 5, 0, -4, -5, -3, 1, 2, 1, -3, + -2, 2, 6, 4, 2, -3, -2, 3, 10, 13, 18, 27, 40, 49, 56, 59, + 60, 56, 52, 47, 41, 30, 17, 1, -19, -39, -55, -64, -67, -70, -76, -81, + -78, -69, -56, -46, -40, -33, -24, -12, 3, 15, 22, 25, 26, 29, 27, 23, + 19, 14, 9, 4, 0, -2, 1, 5, 9, 7, 2, -3, -3, 3, 3, -2, + -10, -13, -10, -2, 7, 14, 22, 31, 45, 59, 65, 68, 65, 62, 58, 50, + 41, 28, 12, -9, -31, -49, -59, -65, -70, -76, -84, -84, -77, -63, -50, -45, + -40, -32, -21, -7, 7, 16, 24, 28, 29, 28, 23, 18, 15, 11, 6, 0, + -4, -3, 4, 11, 14, 11, 6, 5, 7, 7, 2, -7, -12, -16, -13, -6, + 1, 8, 17, 32, 50, 63, 68, 68, 69, 70, 65, 56, 43, 27, 7, -17, + -38, -52, -62, -71, -78, -86, -88, -84, -73, -59, -50, -43, -34, -25, -11, 2, + 11, 19, 23, 26, 26, 21, 17, 12, 9, 7, 5, 2, 2, 4, 11, 16, + 14, 10, 9, 10, 9, 1, -8, -16, -19, -16, -11, -6, 0, 8, 24, 43, + 57, 66, 70, 72, 72, 67, 63, 52, 37, 18, -5, -23, -41, -54, -62, -70, + -78, -81, -82, -76, -67, -56, -45, -36, -31, -22, -12, 0, 10, 16, 20, 21, + 17, 13, 7, 3, 3, 6, 6, 6, 9, 14, 20, 21, 20, 17, 17, 15, + 9, -3, -15, -23, -27, -20, -14, -9, -4, 9, 31, 49, 64, 70, 75, 78, + 76, 70, 60, 45, 31, 12, -11, -31, -46, -58, -66, -70, -73, -77, -74, -67, + -59, -52, -44, -36, -29, -22, -14, -6, 1, 11, 14, 14, 11, 6, 6, 7, + 10, 11, 12, 15, 18, 24, 23, 21, 19, 20, 18, 12, 0, -13, -20, -27, + -27, -22, -16, -11, 1, 19, 36, 52, 64, 73, 79, 81, 77, 69, 56, 43, + 26, 5, -16, -37, -54, -62, -66, -69, -72, -71, -65, -62, -56, -47, -39, -33, + -26, -19, -14, -12, -3, 9, 9, 3, -6, -4, 5, 11, 12, 11, 12, 20, + 29, 31, 29, 25, 25, 27, 24, 11, -6, -17, -25, -31, -32, -30, -26, -16, + 0, 17, 35, 51, 66, 78, 87, 88, 84, 73, 57, 40, 23, 3, -20, -42, + -57, -65, -69, -71, -70, -68, -63, -58, -52, -45, -38, -30, -26, -24, -23, -16, + -8, -2, -5, -9, -6, 1, 9, 12, 13, 17, 24, 32, 37, 37, 34, 32, + 33, 31, 19, 2, -15, -25, -31, -36, -38, -35, -27, -13, 4, 23, 40, 59, + 76, 91, 96, 91, 80, 69, 55, 35, 13, -12, -35, -52, -61, -66, -71, -70, + -63, -54, -48, -44, -42, -36, -31, -30, -34, -36, -33, -26, -20, -20, -21, -18, + -9, 5, 13, 18, 21, 29, 40, 47, 50, 49, 44, 40, 34, 23, 6, -14, + -27, -39, -45, -48, -45, -35, -23, -7, 11, 30, 51, 73, 89, 97, 96, 89, + 80, 63, 44, 25, 4, -18, -39, -53, -59, -63, -61, -58, -55, -52, -49, -45, + -39, -35, -37, -41, -46, -43, -38, -33, -29, -25, -18, -11, 3, 13, 20, 25, + 30, 38, 46, 51, 50, 47, 43, 37, 26, 9, -7, -19, -32, -45, -52, -51, + -40, -28, -12, 4, 19, 38, 61, 83, 94, 95, 89, 82, 67, 50, 30, 12, + -8, -26, -40, -52, -57, -56, -52, -48, -46, -44, -40, -34, -32, -32, -37, -44, + -47, -45, -41, -39, -35, -28, -17, -6, 7, 15, 23, 32, 40, 47, 52, 52, + 51, 46, 39, 32, 17, 1, -14, -26, -37, -46, -50, -45, -35, -25, -11, 5, + 24, 44, 62, 79, 88, 86, 79, 70, 59, 45, 25, 7, -13, -25, -36, -46, + -50, -51, -50, -46, -43, -41, -37, -34, -33, -36, -40, -43, -46, -46, -41, -36, + -31, -22, -10, 4, 13, 21, 30, 40, 47, 50, 53, 52, 47, 39, 30, 18, + 3, -12, -22, -33, -42, -47, -45, -36, -25, -14, -2, 14, 34, 52, 67, 76, + 77, 72, 65, 55, 43, 27, 12, -7, -21, -29, -36, -41, -44, -43, -39, -36, + -32, -27, -26, -26, -29, -33, -36, -43, -49, -48, -44, -38, -32, -22, -11, 4, + 15, 25, 34, 44, 50, 53, 54, 52, 44, 35, 23, 9, -4, -15, -27, -37, + -43, -45, -42, -34, -21, -9, 5, 19, 34, 50, 63, 70, 69, 63, 54, 46, + 35, 20, 4, -11, -23, -29, -33, -37, -41, -40, -33, -25, -20, -19, -21, -22, + -23, -26, -34, -42, -47, -46, -43, -36, -30, -22, -11, 5, 17, 28, 37, 45, + 52, 55, 53, 49, 41, 30, 19, 4, -12, -23, -33, -41, -45, -45, -40, -31, + -18, -3, 11, 23, 38, 51, 63, 64, 58, 51, 45, 36, 25, 10, -4, -15, + -24, -28, -32, -36, -35, -29, -19, -13, -13, -14, -13, -13, -13, -21, -33, -43, + -45, -45, -41, -38, -34, -25, -11, 4, 17, 29, 39, 49, 57, 60, 55, 48, + 39, 29, 16, 1, -14, -27, -35, -42, -47, -48, -42, -29, -15, -3, 10, 20, + 34, 48, 56, 57, 51, 45, 38, 30, 20, 7, -7, -17, -22, -26, -32, -36, + -31, -21, -9, -6, -8, -8, -4, 1, -4, -13, -26, -35, -39, -40, -42, -44, + -40, -29, -13, 3, 16, 29, 43, 58, 67, 67, 59, 49, 39, 27, 11, -9, + -28, -39, -47, -50, -53, -52, -44, -29, -12, 5, 13, 25, 38, 51, 57, 52, + 45, 38, 30, 21, 9, -4, -14, -21, -26, -29, -33, -28, -18, -7, 2, 2, + 2, 4, 8, 10, 5, -10, -25, -36, -42, -45, -49, -49, -45, -33, -14, 5, + 22, 35, 54, 69, 78, 76, 67, 53, 41, 27, 6, -17, -36, -50, -55, -60, + -63, -62, -51, -34, -16, -2, 9, 20, 34, 45, 50, 48, 42, 35, 29, 18, + 7, 0, 0, 0, 0, 0, 0, 7, 0, -1, -7, -18, -16, 3, 6, -18, + -29, -21, 6, 6, -12, -10, -10, -2, 4, 15, 21, 14, 4, 9, 29, 27, + 15, 9, 13, 20, 0, -21, -11, 3, -11, -37, -36, -7, 11, -4, -26, -23, + -4, 15, -4, -15, -11, -10, -1, 9, 23, 15, 8, 6, 24, 35, 19, 14, + 6, 17, 10, -15, -26, -7, -1, -23, -40, -24, 4, 10, -16, -25, -13, 11, + 10, -14, -15, -12, -6, 1, 19, 22, 6, 7, 15, 40, 31, 22, 7, 7, + 15, 5, -22, -21, -5, -9, -33, -32, -15, 5, -4, -19, -20, 1, 17, -4, + -15, -11, -12, -4, 9, 27, 13, 7, 11, 32, 44, 30, 14, 2, 7, 9, + -8, -25, -18, -9, -19, -30, -21, -4, 2, -10, -21, -13, 15, 8, -11, -13, + -16, -12, 0, 20, 24, 9, 9, 19, 44, 47, 25, 6, 2, 11, -1, -21, + -27, -19, -17, -20, -23, -17, -5, -5, -14, -20, 0, 15, -4, -7, -17, -17, + -8, 7, 25, 18, 7, 11, 31, 54, 41, 14, -1, 10, 3, -14, -27, -29, + -21, -16, -16, -18, -17, -11, -10, -16, -16, 10, 6, -3, -9, -19, -16, -2, + 18, 27, 16, 8, 19, 45, 54, 29, 5, 6, 4, -9, -18, -29, -30, -18, + -10, -9, -14, -20, -12, -13, -17, -5, 12, 7, 2, -16, -22, -13, 8, 25, + 23, 12, 11, 32, 53, 48, 17, 9, 9, -7, -16, -24, -37, -28, -12, -4, + -2, -18, -21, -18, -23, -17, 7, 11, 10, -4, -16, -22, -7, 21, 28, 18, + 9, 20, 43, 55, 37, 11, 11, 1, -14, -17, -31, -34, -21, -10, 4, -2, + -20, -23, -26, -29, -3, 6, 13, 8, -5, -23, -27, 7, 28, 27, 15, 12, + 32, 48, 50, 24, 9, 8, -12, -19, -26, -37, -35, -19, 3, 6, -12, -21, + -31, -38, -17, 6, 4, 14, 6, -8, -35, -15, 19, 26, 21, 7, 23, 43, + 52, 42, 14, 9, -2, -16, -21, -25, -33, -33, -4, 13, 3, -13, -30, -47, + -37, 1, 6, 7, 12, 6, -15, -31, -1, 22, 30, 14, 9, 37, 48, 50, + 26, 8, 6, -11, -22, -22, -25, -45, -22, 13, 15, 1, -22, -43, -56, -21, + 7, 6, 10, 15, -7, -25, -21, 7, 28, 21, 2, 25, 47, 53, 39, 11, + 10, 1, -20, -22, -18, -37, -42, 2, 15, 15, -8, -32, -57, -48, -9, 9, + 5, 14, 8, -14, -20, -13, 17, 33, 8, 9, 37, 52, 55, 25, 7, 8, + -11, -23, -15, -23, -47, -20, 12, 21, 10, -23, -50, -57, -31, 2, 10, 9, + 11, -8, -10, -18, -3, 30, 22, 1, 22, 45, 57, 45, 11, 11, 0, -23, + -22, -16, -36, -36, -6, 15, 18, -3, -43, -56, -49, -21, 5, 11, 12, -2, + -8, -9, -15, 12, 31, 9, 10, 34, 48, 60, 29, 16, 10, -17, -24, -21, + -27, -31, -17, 5, 14, 12, -22, -50, -48, -41, -9, 7, 13, -1, -8, -2, + -11, -5, 26, 19, 6, 21, 37, 55, 49, 25, 22, -5, -20, -24, -26, -29, + -23, -9, 8, 13, -1, -41, -48, -47, -30, -3, 12, 7, -12, -2, 1, -8, + 10, 20, 11, 16, 26, 40, 54, 42, 36, 7, -13, -18, -26, -29, -26, -14, + -2, 7, 8, -18, -45, -48, -45, -19, 6, 11, -10, -8, 5, -7, 2, 12, + 17, 15, 16, 23, 45, 55, 48, 27, -7, -12, -18, -30, -31, -17, -5, -3, + 4, 5, -24, -40, -50, -38, -8, 8, 1, -13, 1, -1, 3, 8, 15, 18, + 15, 15, 28, 52, 59, 47, 9, -9, -10, -25, -40, -29, -3, -5, -13, 1, + 3, -26, -47, -53, -23, -2, 5, -11, -6, 4, 6, 10, 10, 19, 11, 13, + 15, 42, 61, 61, 32, 3, -5, -12, -35, -43, -14, 1, -16, -13, 9, -1, + -33, -57, -46, -19, -3, -1, -16, -2, 5, 15, 6, 17, 9, 5, 9, 26, + 54, 65, 52, 21, 3, -6, -21, -48, -33, -4, -7, -22, -2, 18, -4, -47, + -58, -33, -11, 2, -13, -15, 3, 16, 15, 9, 15, -1, 5, 14, 48, 66, + 65, 37, 23, 2, -11, -42, -48, -20, -4, -23, -18, 18, 19, -17, -61, -52, + -27, -2, -5, -24, -7, 9, 20, 14, 18, 2, -3, 7, 34, 63, 68, 50, + 37, 19, -9, -25, -49, -38, -14, -14, -28, 6, 25, 9, -40, -62, -45, -17, + 3, -21, -16, -3, 12, 18, 18, 10, -6, 0, 16, 56, 69, 63, 43, 38, + 2, -20, -42, -44, -33, -14, -25, -10, 22, 18, -11, -55, -57, -37, -3, -10, + -26, -10, 2, 17, 21, 20, -3, -2, 5, 39, 67, 73, 56, 47, 22, -17, + -35, -43, -36, -28, -18, -20, 9, 22, 8, -33, -56, -53, -26, -2, -23, -24, + -11, 4, 23, 30, 4, -3, 0, 27, 60, 71, 69, 58, 43, -6, -35, -43, + -35, -36, -27, -18, -2, 19, 17, -9, -41, -51, -45, -10, -12, -31, -21, -9, + 8, 33, 17, 0, 2, 8, 50, 69, 75, 70, 64, 16, -31, -47, -35, -32, + -34, -25, -14, 10, 16, 5, -26, -42, -50, -32, -8, -22, -31, -22, -8, 22, + 32, 7, 6, 4, 28, 63, 69, 71, 78, 43, -20, -51, -41, -23, -34, -30, + -22, 2, 13, 9, -10, -31, -45, -44, -21, -19, -27, -36, -26, 2, 29, 24, + 12, 11, 13, 45, 69, 68, 81, 70, 6, -47, -52, -28, -23, -27, -26, -14, + 11, 10, -2, -18, -33, -43, -34, -25, -22, -36, -44, -14, 14, 29, 27, 22, + 18, 29, 60, 65, 71, 86, 41, -32, -57, -41, -23, -22, -22, -24, -4, 10, + 0, -11, -21, -31, -37, -37, -29, -29, -53, -33, -3, 16, 33, 31, 27, 23, + 46, 64, 65, 85, 71, -4, -48, -47, -31, -20, -15, -15, -19, 1, 0, -5, + -14, -21, -26, -40, -39, -28, -51, -50, -18, 4, 26, 38, 36, 30, 32, 61, + 64, 70, 80, 31, -35, -43, -40, -25, -19, -6, -17, -11, 0, -6, -11, -17, + -15, -31, -47, -39, -45, -62, -34, -8, 12, 36, 38, 41, 37, 51, 65, 60, + 71, 56, -7, -36, -38, -35, -27, -11, -5, -17, -8, -8, -9, -17, -13, -20, + -37, -47, -50, -62, -49, -16, 1, 25, 34, 43, 53, 49, 62, 58, 62, 65, + 22, -23, -31, -34, -35, -19, -3, -8, -18, -7, -4, -14, -17, -9, -27, -40, + -56, -68, -64, -27, -4, 9, 28, 37, 54, 60, 61, 59, 54, 63, 43, -1, + -25, -23, -37, -28, -8, 4, -10, -15, -3, -7, -26, -15, -11, -29, -51, -71, + -71, -49, -8, 5, 14, 30, 48, 66, 68, 63, 51, 56, 51, 18, -18, -20, + -25, -39, -23, -5, 3, -13, -6, -5, -21, -28, -10, -18, -43, -67, -78, -64, + -25, 1, 8, 15, 38, 60, 75, 74, 58, 54, 57, 28, -7, -18, -8, -31, + -34, -15, 4, -2, -4, 0, -15, -32, -21, -8, -28, -57, -77, -75, -44, -12, + 6, 8, 20, 49, 68, 77, 71, 53, 61, 41, 3, -18, -4, -14, -36, -28, + -7, 1, 7, 6, -8, -34, -35, -16, -15, -41, -66, -75, -59, -31, -4, 10, + 11, 31, 56, 72, 85, 63, 58, 55, 14, -17, -10, -1, -24, -30, -22, -6, + 11, 16, 9, -27, -43, -27, -15, -26, -53, -63, -66, -46, -21, 3, 13, 15, + 40, 63, 83, 78, 60, 67, 38, -9, -20, 4, -7, -23, -25, -22, 6, 24, + 20, -8, -48, -43, -24, -16, -39, -55, -57, -57, -36, -10, 9, 11, 22, 50, + 73, 88, 71, 65, 59, 14, -24, -9, -3, -15, -18, -31, -14, 25, 28, 10, + -36, -56, -41, -21, -29, -48, -47, -51, -50, -26, -2, 11, 6, 30, 57, 82, + 83, 69, 65, 35, -12, -16, -3, -10, -12, -21, -26, 11, 33, 26, -7, -56, + -54, -32, -26, -41, -39, -37, -52, -41, -16, 5, 7, 11, 37, 72, 91, 78, + 66, 55, 11, -19, -14, -15, -9, -7, -19, -8, 22, 30, 13, -32, -62, -44, + -31, -34, -40, -29, -40, -46, -29, -8, 2, 1, 18, 49, 84, 86, 72, 67, + 39, -6, -21, -25, -16, 2, -6, -12, 6, 23, 18, -7, -51, -56, -39, -33, + -41, -30, -24, -41, -36, -17, -8, -5, 7, 32, 66, 84, 78, 75, 58, 20, + -15, -29, -33, 2, 4, -1, 1, 11, 17, 4, -27, -56, -46, -36, -37, -39, + -22, -24, -38, -23, -16, -16, -7, 18, 46, 72, 82, 81, 72, 44, -1, -25, + -41, -18, 14, 8, 10, 0, 5, 2, -11, -40, -50, -42, -38, -37, -33, -11, + -27, -26, -20, -22, -13, 0, 31, 52, 73, 82, 80, 61, 26, -16, -37, -40, + 0, 18, 17, 12, -5, -8, -10, -21, -41, -43, -44, -36, -35, -20, -12, -23, + -14, -32, -21, -12, 15, 38, 58, 76, 82, 72, 46, 4, -26, -41, -23, 14, + 25, 18, 2, -23, -18, -14, -29, -35, -45, -42, -35, -29, -15, -19, -3, -23, + -32, -19, -1, 27, 40, 67, 81, 76, 61, 26, -11, -33, -36, -6, 28, 28, + 13, -15, -38, -19, -20, -26, -36, -46, -35, -32, -20, -21, -4, -4, -28, -25, + -16, 13, 31, 49, 74, 79, 69, 48, 8, -16, -33, -21, 7, 33, 24, 5, + -32, -38, -22, -21, -22, -41, -43, -32, -25, -23, -16, 6, -9, -29, -28, -5, + 20, 39, 58, 75, 71, 60, 22, 0, -18, -27, -10, 16, 30, 15, -14, -49, + -34, -19, -16, -27, -43, -31, -25, -27, -24, -1, 7, -15, -32, -22, 3, 28, + 50, 61, 67, 59, 38, 13, 5, -17, -16, -3, 21, 23, 3, -34, -49, -28, + -17, -19, -34, -34, -18, -26, -32, -16, 14, 6, -23, -34, -11, 14, 44, 54, + 56, 60, 44, 25, 18, 2, -18, -9, 3, 21, 9, -14, -45, -39, -24, -22, + -28, -32, -18, -17, -36, -30, 5, 21, -5, -31, -27, 1, 30, 56, 46, 50, + 47, 32, 29, 20, -4, -9, -9, 4, 10, -2, -28, -38, -31, -33, -26, -26, + -19, -9, -24, -38, -11, 24, 10, -17, -36, -14, 14, 48, 49, 37, 43, 39, + 33, 32, 11, 1, -5, -11, -6, -3, -16, -29, -28, -40, -38, -27, -20, -6, + -11, -31, -29, 15, 22, 0, -25, -25, 2, 31, 51, 38, 35, 41, 41, 34, + 27, 8, 6, -7, -20, -14, -7, -20, -19, -34, -52, -35, -23, -11, -5, -18, + -33, -5, 26, 5, -11, -27, -11, 17, 43, 43, 30, 29, 46, 45, 38, 17, + 6, 2, -22, -27, -16, -16, -18, -18, -53, -48, -23, -19, -3, -10, -21, -19, + 18, 12, -6, -20, -21, 6, 29, 42, 31, 23, 37, 54, 48, 31, 13, 13, + -13, -31, -25, -16, -16, -11, -38, -62, -33, -28, -7, -3, -12, -17, 6, 16, + 2, -11, -17, -5, 15, 35, 34, 25, 23, 44, 55, 41, 22, 14, 2, -29, + -32, -23, -11, -13, -18, -60, -50, -32, -16, -6, -11, -4, 3, 11, 3, -1, + -14, -8, 5, 20, 39, 31, 24, 26, 54, 57, 37, 16, 8, -19, -32, -27, + -17, -17, -17, -36, -58, -40, -32, -11, -11, -2, 6, 10, 2, 0, -4, -12, + 1, 8, 33, 42, 26, 17, 35, 63, 53, 26, 6, -9, -27, -30, -25, -17, + -23, -24, -47, -51, -38, -17, -11, -6, 12, 17, 8, -8, -1, -10, -7, 4, + 18, 40, 33, 18, 22, 49, 70, 46, 12, -11, -16, -23, -27, -19, -28, -26, + -36, -50, -48, -31, -13, -13, 10, 20, 21, 0, -6, -1, -7, 3, 15, 32, + 40, 24, 17, 31, 58, 67, 28, -2, -21, -14, -31, -18, -24, -33, -33, -49, + -49, -41, -18, -20, -2, 20, 23, 19, -12, -7, -2, -3, 10, 22, 33, 37, + 21, 23, 39, 72, 51, 10, -17, -18, -20, -29, -17, -33, -36, -49, -48, -47, + -24, -16, -15, 11, 24, 30, 6, -12, -2, -2, -1, 18, 29, 35, 27, 25, + 25, 56, 63, 23, -5, -19, -14, -23, -21, -21, -38, -52, -54, -40, -32, -15, + -23, -7, 18, 31, 22, -2, -7, 3, 0, 12, 21, 34, 31, 28, 22, 35, + 66, 40, 2, -19, -19, -15, -21, -16, -30, -60, -62, -42, -33, -18, -18, -22, + 4, 29, 29, 14, -2, -4, 5, 6, 16, 28, 36, 24, 29, 26, 52, 49, + 14, -13, -24, -19, -14, -15, -17, -53, -75, -54, -32, -18, -11, -26, -18, 18, + 28, 25, 13, -6, 4, 13, 9, 17, 37, 24, 28, 33, 37, 49, 26, 1, + -19, -26, -16, -11, -7, -33, -77, -71, -45, -15, -8, -18, -30, 1, 25, 21, + 26, 3, 5, 17, 14, 11, 33, 27, 17, 34, 38, 42, 33, 6, -11, -28, + -22, -12, -3, -16, -60, -81, -62, -25, -2, -14, -27, -17, 20, 18, 24, 18, + 6, 16, 21, 12, 24, 28, 12, 26, 44, 42, 35, 13, -5, -21, -31, -18, + -2, -2, -42, -77, -76, -47, -10, -6, -22, -24, 4, 16, 18, 25, 18, 18, + 24, 20, 20, 32, 14, 11, 40, 49, 41, 21, -6, -13, -27, -28, -5, 5, + -18, -59, -79, -63, -30, -6, -11, -28, -11, 8, 10, 23, 27, 17, 24, 25, + 25, 28, 19, 8, 25, 47, 46, 27, -5, -15, -18, -33, -20, -5, -3, -35, + -70, -66, -51, -22, -7, -21, -19, -3, 6, 17, 29, 26, 23, 28, 25, 32, + 23, 14, 11, 39, 50, 38, 3, -19, -10, -21, -29, -12, -3, -12, -55, -65, + -56, -42, -14, -10, -23, -11, -3, 10, 23, 32, 26, 28, 28, 35, 29, 22, + 13, 18, 41, 43, 18, -16, -18, -14, -29, -21, -11, -8, -32, -61, -52, -52, + -30, -11, -18, -16, -10, 2, 22, 35, 30, 25, 32, 34, 40, 27, 19, 11, + 23, 39, 32, -1, -22, -14, -22, -23, -14, -11, -17, -45, -52, -51, -51, -22, + -17, -19, -17, -10, 11, 35, 39, 29, 26, 34, 43, 43, 27, 16, 12, 25, + 31, 18, -13, -20, -19, -22, -12, -14, -15, -28, -44, -47, -53, -33, -15, -22, + -24, -20, 5, 27, 38, 31, 21, 27, 46, 51, 40, 18, 8, 13, 23, 24, + 3, -21, -22, -22, -8, -9, -22, -26, -31, -40, -51, -44, -17, -15, -26, -31, + -10, 24, 35, 37, 25, 21, 42, 57, 53, 30, 11, 7, 11, 21, 12, -11, + -23, -25, -12, 0, -18, -32, -31, -30, -45, -46, -26, -13, -25, -39, -25, 15, + 36, 29, 25, 20, 37, 58, 63, 46, 15, 3, -2, 19, 16, -2, -19, -25, + -23, 4, -4, -31, -36, -29, -32, -43, -37, -17, -16, -39, -43, -2, 34, 31, + 21, 17, 30, 62, 67, 62, 27, 9, -9, 3, 26, 8, -18, -26, -26, -5, + 9, -23, -44, -33, -26, -33, -40, -28, -12, -30, -52, -24, 23, 33, 15, 14, + 22, 54, 75, 68, 47, 14, -9, -12, 19, 23, -12, -20, -20, -13, 11, -6, + -40, -41, -19, -23, -34, -34, -14, -13, -48, -48, 4, 35, 23, 7, 13, 40, + 77, 78, 57, 31, -3, -18, 3, 27, 7, -24, -19, -16, 1, 5, -29, -49, + -28, -13, -26, -34, -26, -4, -30, -57, -24, 22, 30, 6, 7, 31, 63, 86, + 68, 42, 10, -19, -13, 15, 25, -10, -22, -14, -7, 6, -11, -45, -40, -14, + -24, -35, -31, -12, -8, -51, -44, -2, 29, 11, -1, 22, 47, 74, 78, 49, + 25, -8, -26, -4, 26, 12, -16, -19, -11, -1, -1, -28, -45, -22, -13, -29, + -29, -23, -1, -26, -55, -26, 14, 20, -3, 13, 39, 63, 80, 61, 33, 8, + -22, -25, 10, 22, -1, -14, -15, -7, -1, -14, -37, -26, -13, -25, -28, -26, + -2, -5, -48, -44, -7, 18, 3, 9, 30, 49, 71, 70, 45, 23, -13, -33, + -5, 22, 11, -7, -17, -14, -6, -8, -29, -29, -15, -19, -26, -31, -15, 6, + -25, -52, -30, 7, 7, 2, 21, 40, 60, 67, 52, 33, 7, -29, -19, 16, + 22, 4, -8, -15, -11, -6, -23, -24, -10, -11, -23, -27, -22, 1, 0, -34, + -45, -14, 2, 1, 15, 35, 52, 62, 49, 36, 21, -16, -26, 1, 20, 12, + -7, -10, -20, -10, -19, -28, -9, -8, -15, -26, -27, -11, 2, -15, -41, -34, + -10, -7, 6, 32, 48, 56, 51, 35, 26, 1, -24, -10, 15, 18, 2, -9, + -17, -18, -11, -32, -6, 2, -9, -18, -22, -17, -3, -2, -21, -34, -26, -13, + -8, 20, 47, 53, 52, 38, 24, 5, -14, -15, 9, 14, 4, -6, -14, -21, + -14, -28, -22, 12, 0, -10, -23, -24, -13, 2, -10, -23, -34, -26, -13, 4, + 39, 58, 51, 45, 28, 6, -9, -11, 3, 17, 7, -3, -10, -18, -15, -22, + -35, 2, 18, 2, -11, -23, -20, -1, 0, -15, -24, -39, -25, -6, 17, 52, + 56, 47, 35, 6, -10, -8, 0, 13, 13, -2, -9, -13, -13, -25, -43, -16, + 21, 19, -3, -21, -25, -10, 2, -5, -14, -30, -40, -13, -1, 34, 58, 51, + 44, 18, -10, -9, -2, 6, 12, 7, -7, -12, -12, -18, -40, -33, 9, 32, + 19, -9, -23, -15, 1, 3, -9, -18, -40, -28, -4, 7, 47, 59, 49, 24, + 1, -13, -5, 1, 10, 11, 5, -12, -12, -15, -35, -42, -9, 23, 33, 9, + -22, -24, -5, 1, -5, -12, -30, -40, -7, -3, 22, 56, 58, 35, 11, -12, + -9, -5, -1, 7, 13, -4, -13, -13, -25, -43, -29, 10, 34, 32, -6, -27, + -8, 3, -5, -13, -22, -40, -18, -3, -1, 37, 61, 46, 23, -5, -13, -4, + -4, -7, 12, 14, -10, -18, -22, -34, -35, -10, 22, 39, 23, -15, -14, 5, + 3, -8, -15, -36, -23, -1, -7, 14, 51, 57, 37, 8, -13, -7, -2, -14, + -6, 20, 3, -21, -26, -27, -30, -27, 1, 28, 36, 7, -10, 0, 5, -8, + -14, -30, -29, -3, -10, -5, 31, 56, 46, 19, -7, -10, 3, -11, -21, 9, + 19, -10, -30, -29, -19, -24, -20, 10, 35, 29, 8, -1, 5, -2, -13, -28, + -33, -3, -1, -13, 12, 49, 55, 31, -1, -12, 2, -3, -26, -2, 21, 2, + -28, -34, -21, -17, -29, -12, 23, 34, 19, 6, 7, 4, -4, -23, -40, -10, + 7, -12, -2, 34, 55, 36, 8, -10, 1, 3, -19, -18, 15, 15, -10, -33, + -30, -9, -19, -25, 4, 32, 30, 16, 11, 10, 3, -15, -35, -27, 9, -4, + -10, 16, 52, 42, 12, -7, -6, 4, -6, -21, -2, 17, 0, -20, -41, -13, + -9, -31, -16, 18, 34, 23, 14, 9, 10, -7, -26, -34, -3, 10, -10, 2, + 42, 51, 16, -8, -11, -2, -2, -11, -9, 9, 2, -8, -36, -31, 3, -23, + -30, -1, 27, 27, 23, 15, 18, 3, -17, -31, -19, 8, 1, -4, 24, 51, + 30, -11, -16, -6, -3, -5, -10, 3, 1, -10, -22, -41, -4, -6, -29, -18, + 12, 25, 26, 23, 20, 11, -10, -21, -27, -4, 7, 0, 13, 41, 40, 3, + -24, -11, -1, -2, -3, 5, 5, -14, -15, -35, -20, 0, -19, -24, -4, 11, + 23, 31, 24, 16, -3, -13, -23, -14, 2, 3, 18, 32, 38, 21, -20, -29, + -5, -2, 0, 5, 11, -14, -22, -25, -26, -3, -11, -26, -11, -2, 8, 32, + 34, 24, 2, -8, -16, -13, 1, 1, 10, 31, 31, 33, 1, -36, -22, 0, + 0, 8, 18, -3, -27, -22, -22, -10, -9, -24, -16, -5, -16, 16, 40, 34, + 8, -3, -13, -12, 1, 1, 3, 30, 30, 24, 18, -28, -35, -13, -2, 6, + 19, 10, -25, -28, -15, -9, -10, -19, -20, -3, -15, -8, 27, 42, 25, 1, + -14, -18, 7, 9, -1, 19, 37, 19, 23, -10, -41, -26, -9, 2, 20, 19, + -17, -35, -21, 0, -9, -18, -20, -7, -8, -24, 6, 37, 43, 14, -10, -22, + 3, 18, 4, 6, 36, 23, 16, 4, -32, -37, -19, -3, 17, 27, 0, -37, + -34, -3, 7, -17, -27, -19, -1, -20, -13, 17, 44, 35, 2, -22, -9, 19, + 20, 2, 26, 32, 15, 5, -17, -40, -29, -9, 10, 28, 17, -23, -41, -21, + 9, -2, -27, -30, -5, -7, -21, -4, 27, 47, 27, -14, -21, 11, 29, 14, + 15, 32, 20, 4, -11, -31, -38, -15, 2, 22, 22, -3, -32, -34, -6, 8, + -13, -38, -19, 0, -16, -14, 6, 37, 39, 11, -18, -4, 25, 25, 16, 24, + 27, 7, -10, -24, -38, -25, 0, 12, 23, 8, -16, -31, -23, 0, 0, -27, + -33, -2, -9, -16, -11, 17, 41, 32, 5, -15, 12, 25, 24, 21, 27, 14, + -4, -21, -31, -29, -4, 9, 19, 9, -9, -19, -25, -10, -5, -15, -38, -13, + -6, -13, -17, -1, 30, 36, 27, -2, 2, 20, 24, 25, 24, 19, 2, -16, + -32, -29, -13, 8, 18, 16, -6, -13, -21, -15, -14, -13, -26, -22, -6, -11, + -14, -14, 11, 30, 37, 17, 1, 13, 20, 23, 24, 21, 5, -10, -32, -31, + -15, 0, 17, 22, -3, -15, -17, -11, -15, -19, -23, -22, -8, -8, -13, -18, + -8, 18, 40, 38, 12, 12, 15, 21, 23, 24, 7, -9, -22, -34, -19, -6, + 11, 30, 9, -17, -20, -16, -11, -22, -30, -27, -8, -7, -10, -19, -16, -2, + 32, 52, 31, 17, 16, 13, 21, 19, 19, -9, -17, -30, -25, -7, 3, 29, + 25, -9, -21, -20, -11, -14, -29, -37, -14, 2, -5, -14, -22, -12, 13, 50, + 49, 27, 23, 15, 13, 9, 18, 7, -22, -22, -28, -11, -5, 19, 35, 13, + -20, -24, -18, -8, -22, -38, -31, 2, 3, -6, -26, -22, -3, 38, 56, 42, + 34, 21, 12, 6, 11, 17, -15, -24, -20, -15, -6, 9, 29, 29, -4, -28, + -23, -14, -13, -30, -39, -16, 9, 6, -12, -33, -16, 19, 57, 49, 41, 30, + 13, 4, -1, 6, -4, -27, -21, -13, -6, 2, 12, 34, 12, -24, -24, -20, + -16, -24, -38, -33, 2, 12, -2, -30, -31, 2, 45, 59, 46, 41, 24, 8, + -3, -6, 1, -15, -25, -16, -3, 5, 2, 21, 28, -11, -26, -23, -18, -20, + -32, -40, -14, 14, 11, -10, -40, -20, 30, 60, 55, 42, 34, 15, 6, -12, + -12, -4, -19, -21, -9, 8, 4, 10, 28, 6, -25, -22, -20, -22, -29, -38, + -27, 5, 16, 4, -24, -39, 12, 51, 61, 51, 41, 27, 10, -7, -25, -9, + -10, -17, -15, 0, 9, 5, 21, 15, -13, -27, -17, -21, -23, -38, -33, -11, + 10, 6, -4, -38, -17, 36, 55, 55, 45, 35, 21, 4, -27, -25, -2, -10, + -14, -13, 3, 5, 14, 16, 0, -24, -21, -18, -22, -36, -39, -17, -3, 5, + 3, -15, -28, 16, 50, 53, 52, 43, 29, 13, -14, -36, -10, -1, -15, -15, + -6, 6, 5, 13, 4, -11, -24, -17, -18, -27, -43, -18, -12, -7, 4, 3, + -17, -4, 38, 53, 52, 48, 41, 23, 0, -31, -30, 2, -7, -14, -13, -5, + 3, 11, 7, -4, -21, -25, -21, -19, -39, -23, -9, -19, -8, 5, -1, -10, + 24, 46, 48, 46, 44, 32, 10, -18, -37, -7, 0, -12, -14, -13, -4, 8, + 9, 1, -16, -29, -28, -17, -33, -31, -6, -21, -21, -4, 12, 3, 13, 41, + 46, 44, 46, 44, 20, -7, -36, -27, 6, -3, -18, -21, -12, 2, 12, 6, + -5, -27, -36, -21, -20, -34, -12, -8, -29, -16, 11, 15, 10, 28, 47, 46, + 41, 45, 35, 5, -24, -30, -5, 3, -14, -26, -16, -7, 7, 8, -3, -18, + -39, -32, -16, -28, -26, -8, -23, -26, 0, 19, 16, 20, 42, 55, 45, 38, + 39, 20, -11, -24, -13, -2, -6, -25, -22, -7, -5, 13, 0, -11, -36, -41, + -20, -16, -29, -16, -14, -28, -12, 13, 17, 15, 32, 50, 57, 41, 38, 30, + 2, -14, -9, -3, -3, -19, -33, -10, -7, 7, 7, -13, -30, -42, -28, -13, + -17, -26, -14, -22, -15, 7, 19, 15, 26, 46, 59, 51, 34, 33, 12, -7, + -11, -4, -5, -13, -38, -23, -3, 3, 15, -7, -32, -45, -34, -21, -11, -27, + -25, -21, -19, -1, 13, 15, 22, 37, 53, 62, 46, 34, 15, -2, 0, -4, + -8, -9, -34, -38, -8, 4, 17, 3, -25, -50, -44, -26, -12, -13, -32, -24, + -20, -7, 11, 18, 17, 33, 50, 65, 57, 41, 24, 0, 5, 5, -9, -11, + -25, -44, -25, -1, 17, 13, -18, -42, -51, -33, -20, -7, -27, -29, -23, -16, + 0, 14, 14, 28, 48, 60, 66, 51, 34, 4, 0, 15, -3, -14, -20, -35, + -37, -12, 12, 27, -7, -37, -50, -40, -29, -15, -15, -30, -24, -15, -7, 6, + 17, 25, 46, 59, 68, 63, 43, 20, -6, 14, 10, -8, -20, -30, -34, -22, + -2, 24, 15, -30, -49, -49, -37, -28, -15, -26, -28, -18, -11, -7, 7, 27, + 42, 58, 70, 70, 53, 35, 4, 0, 18, -1, -15, -32, -31, -26, -12, 12, + 28, -4, -44, -53, -44, -39, -25, -23, -28, -19, -11, -12, -16, 13, 42, 56, + 71, 71, 57, 45, 23, -3, 10, 11, -6, -27, -35, -25, -22, -1, 23, 17, + -29, -54, -46, -44, -39, -29, -28, -21, -15, -15, -26, -12, 39, 57, 70, 73, + 60, 49, 41, 13, 1, 11, 0, -16, -32, -25, -15, -14, 10, 23, -5, -48, + -46, -42, -49, -43, -31, -24, -15, -13, -24, -32, 18, 59, 71, 77, 67, 57, + 47, 33, 3, 5, 5, -9, -23, -33, -16, -14, -5, 17, 12, -29, -44, -35, + -50, -57, -43, -30, -18, -11, -22, -39, -9, 44, 68, 82, 69, 61, 49, 42, + 18, 5, 5, -8, -12, -26, -14, -7, -9, 5, 16, -6, -36, -32, -42, -62, + -55, -39, -29, -15, -14, -34, -30, 20, 59, 82, 79, 66, 58, 45, 38, 9, + 1, -7, -11, -16, -19, -3, -6, -6, 9, 5, -22, -32, -32, -58, -70, -56, + -42, -24, -16, -25, -39, -9, 41, 72, 86, 73, 65, 46, 40, 30, -4, -7, + -14, -12, -20, -3, 4, -5, 1, 8, -9, -27, -25, -40, -67, -67, -55, -38, + -24, -17, -25, -28, 16, 61, 81, 82, 71, 60, 37, 42, 17, -14, -17, -11, + -13, -8, 10, 2, -2, 1, -1, -17, -20, -26, -54, -69, -70, -58, -34, -25, + -16, -23, -9, 37, 70, 87, 80, 68, 44, 38, 39, -5, -27, -19, -12, -6, + 13, 10, 4, 1, 1, -5, -19, -20, -37, -59, -71, -71, -54, -35, -17, -9, + -20, 11, 49, 80, 86, 72, 54, 36, 45, 23, -25, -34, -16, -9, 11, 17, + 8, 5, -4, -2, -15, -19, -26, -50, -69, -77, -71, -51, -29, -7, -11, -6, + 26, 64, 87, 78, 60, 40, 42, 45, 2, -38, -34, -12, 10, 24, 10, 11, + 3, -1, -6, -20, -16, -31, -61, -81, -80, -69, -41, -16, -5, -8, 10, 47, + 81, 86, 70, 44, 36, 48, 32, -21, -48, -31, -3, 24, 24, 10, 15, 0, + 2, -17, -21, -18, -45, -81, -87, -80, -57, -33, -11, -6, 2, 30, 74, 86, + 77, 55, 34, 42, 48, 13, -39, -50, -20, 15, 34, 14, 16, 12, 4, -5, + -26, -16, -19, -64, -92, -91, -65, -43, -26, -12, -1, 16, 47, 83, 76, 66, + 40, 33, 45, 33, -8, -52, -41, -5, 32, 30, 15, 25, 13, 8, -22, -28, + -11, -34, -85, -101, -86, -52, -36, -25, -13, 15, 32, 69, 80, 69, 52, 32, + 37, 39, 19, -30, -54, -24, 10, 38, 25, 25, 22, 18, -6, -35, -20, -14, + -59, -98, -99, -68, -41, -30, -23, 5, 28, 52, 74, 67, 59, 43, 32, 35, + 32, -2, -47, -38, -13, 23, 33, 31, 26, 27, 16, -29, -37, -15, -33, -80, + -104, -89, -54, -35, -31, -11, 17, 42, 63, 68, 60, 59, 37, 27, 33, 22, + -28, -37, -26, 3, 32, 38, 30, 25, 30, -3, -41, -29, -23, -55, -90, -98, + -76, -39, -32, -21, 4, 36, 52, 61, 61, 63, 48, 24, 28, 34, -10, -31, + -29, -14, 15, 37, 37, 28, 31, 19, -27, -40, -24, -38, -69, -95, -96, -60, + -32, -26, -10, 19, 45, 53, 58, 59, 58, 29, 23, 39, 14, -21, -25, -23, + 1, 27, 43, 34, 34, 21, 0, -36, -32, -31, -49, -84, -102, -83, -41, -22, + -19, -1, 35, 49, 52, 53, 56, 39, 23, 34, 33, -3, -23, -22, -10, 17, + 36, 36, 39, 26, 8, -16, -34, -29, -36, -61, -93, -95, -58, -26, -18, -11, + 22, 48, 53, 53, 51, 41, 31, 33, 37, 16, -15, -24, -14, 4, 29, 34, + 41, 32, 8, -7, -19, -28, -30, -54, -83, -101, -76, -40, -20, -21, 1, 36, + 54, 55, 44, 33, 32, 35, 36, 30, 7, -26, -19, -5, 22, 36, 37, 37, + 15, -3, -5, -15, -24, -43, -75, -94, -87, -47, -29, -25, -14, 26, 48, 62, + 49, 29, 23, 35, 45, 38, 19, -16, -28, -7, 10, 29, 32, 38, 23, -2, + -10, -6, -12, -28, -67, -90, -98, -59, -32, -28, -25, 3, 43, 56, 59, 25, + 16, 24, 46, 43, 31, 0, -31, -14, 5, 25, 29, 32, 29, 6, -13, -6, + -3, -8, -49, -85, -97, -75, -31, -30, -30, -12, 31, 50, 61, 40, 12, 14, + 34, 53, 43, 20, -23, -20, -3, 21, 29, 23, 24, 15, -10, -8, -1, 2, + -25, -75, -98, -92, -42, -31, -35, -24, 14, 41, 50, 49, 22, 11, 20, 45, + 52, 39, 0, -26, -12, 9, 35, 25, 18, 14, 1, -13, -6, 4, 3, -49, + -89, -102, -61, -27, -30, -27, -4, 34, 46, 46, 32, 17, 13, 26, 47, 50, + 29, -19, -22, -4, 30, 37, 15, 7, 7, -5, -10, -4, 9, -20, -72, -100, + -86, -41, -33, -31, -16, 18, 43, 34, 32, 27, 23, 15, 31, 47, 48, 9, + -24, -16, 12, 43, 25, -2, 0, 9, -9, -15, 2, 8, -40, -87, -99, -69, + -37, -31, -19, 6, 38, 35, 25, 31, 35, 26, 18, 36, 49, 40, -10, -22, + -9, 29, 40, 6, -12, 6, 6, -16, -11, 9, -6, -61, -95, -90, -58, -35, + -26, -5, 23, 36, 18, 21, 36, 41, 28, 22, 38, 52, 23, -17, -17, 7, + 39, 21, -12, -13, 16, -8, -22, -5, 6, -25, -77, -93, -79, -46, -30, -11, + 15, 36, 22, 5, 29, 47, 47, 24, 22, 41, 48, 7, -15, -4, 22, 33, + 6, -23, 4, 8, -21, -15, -1, -5, -49, -79, -92, -71, -43, -20, 11, 31, + 29, 4, 16, 40, 55, 41, 22, 31, 50, 25, -9, -2, 8, 23, 16, -17, + -6, 8, -10, -15, -6, -4, -29, -56, -80, -86, -61, -42, 0, 30, 33, 12, + 2, 24, 47, 55, 37, 28, 39, 40, 4, -1, 6, 6, 16, -4, -13, 1, + -2, -9, -11, -11, -21, -35, -55, -82, -80, -64, -24, 27, 36, 23, 3, 10, + 35, 61, 55, 40, 35, 35, 19, 6, 12, 4, 1, 3, -12, -3, -2, -4, + -4, -14, -23, -30, -37, -58, -83, -84, -58, 8, 37, 33, 11, 3, 20, 46, + 62, 55, 50, 28, 16, 12, 15, 9, -4, -9, -9, -4, -5, -7, 2, -7, + -28, -35, -31, -36, -67, -90, -86, -23, 28, 38, 25, 5, 13, 34, 58, 58, + 69, 50, 15, 10, 20, 16, -3, -14, -14, -2, 1, -12, -3, 3, -20, -36, + -39, -26, -46, -81, -98, -61, 6, 27, 30, 16, 12, 25, 50, 57, 66, 74, + 31, 4, 16, 21, 8, -13, -21, -10, 8, -5, -11, 6, -8, -31, -40, -29, + -30, -66, -93, -84, -22, 17, 22, 26, 16, 20, 43, 56, 56, 70, 60, 17, + 8, 18, 15, -10, -26, -21, 6, 7, -12, -1, 1, -20, -33, -34, -31, -51, + -79, -92, -52, -6, 9, 19, 23, 21, 40, 57, 59, 60, 72, 43, 17, 13, + 18, 3, -23, -32, -5, 14, -7, -11, 7, -12, -26, -31, -37, -46, -66, -85, + -67, -21, -5, 3, 16, 22, 37, 54, 59, 55, 60, 58, 30, 16, 13, 11, + -15, -34, -23, 9, 7, -12, -2, -4, -19, -16, -31, -49, -64, -76, -72, -35, + -12, -14, 0, 15, 34, 53, 60, 58, 53, 57, 43, 30, 18, 12, -4, -27, + -28, -8, 14, -3, -9, -2, -13, -9, -17, -49, -66, -70, -69, -44, -15, -19, + -11, 2, 21, 53, 64, 68, 55, 48, 44, 36, 28, 15, -1, -18, -23, -19, + -4, 5, -3, 1, -9, -7, -1, -35, -70, -74, -70, -50, -21, -14, -22, -7, + -1, 39, 66, 77, 69, 46, 38, 36, 38, 22, 5, -12, -16, -12, -17, -8, + -5, 2, 1, -6, 5, -13, -64, -78, -73, -60, -31, -14, -17, -16, -10, 7, + 61, 79, 81, 57, 38, 28, 32, 24, 9, -4, -10, -4, -11, -20, -13, -2, + 11, 4, 4, -2, -41, -76, -76, -69, -43, -22, -12, -17, -14, -14, 25, 74, + 92, 79, 47, 31, 26, 26, 11, 3, -5, 0, 0, -20, -26, -11, 9, 14, + 9, 4, -24, -61, -76, -74, -53, -30, -13, -8, -12, -25, -8, 51, 90, 93, + 63, 42, 21, 18, 13, 6, 2, 1, 8, -12, -30, -27, -2, 14, 18, 11, + -13, -48, -68, -79, -70, -44, -19, -2, -5, -21, -31, 18, 77, 100, 81, 55, + 29, 7, 8, 6, 7, 4, 14, 0, -26, -34, -13, 9, 16, 17, 1, -35, + -58, -70, -82, -62, -29, -2, 1, -14, -36, -15, 50, 89, 95, 71, 46, 5, + -6, 4, 11, 3, 11, 14, -12, -31, -22, -2, 8, 16, 16, -15, -53, -56, + -80, -81, -41, -5, 9, -3, -30, -34, 17, 73, 97, 86, 63, 25, -12, -6, + 11, 13, 1, 15, 4, -19, -25, -5, 2, 9, 19, 10, -39, -48, -61, -95, + -67, -17, 12, 8, -23, -43, -9, 49, 85, 91, 76, 50, 1, -23, 2, 22, + 5, 2, 14, -5, -23, -12, 0, -2, 13, 17, -15, -48, -43, -83, -88, -38, + 5, 17, -11, -41, -28, 27, 67, 83, 82, 65, 29, -21, -18, 21, 19, -7, + 3, 6, -8, -14, 1, 0, 0, 13, 2, -34, -42, -59, -99, -63, -12, 17, + 0, -35, -42, 1, 53, 69, 79, 72, 53, -1, -34, 2, 32, 3, -8, 1, + 2, -2, -3, 8, -2, 3, 7, -18, -40, -39, -76, -81, -35, 9, 17, -22, + -46, -24, 34, 59, 68, 74, 66, 27, -26, -22, 31, 24, -10, -11, 0, 14, + 1, 5, 8, -5, -2, -10, -34, -35, -48, -77, -59, -13, 20, -4, -37, -35, + 8, 47, 55, 68, 74, 49, -4, -34, 10, 39, 1, -13, -11, 14, 14, 3, + 20, 6, -9, -14, -29, -37, -28, -56, -66, -42, 9, 9, -25, -38, -14, 27, + 45, 54, 72, 61, 21, -25, -14, 31, 19, -10, -15, -2, 22, 6, 22, 24, + -4, -20, -28, -38, -24, -28, -54, -57, -20, 14, -10, -29, -26, 2, 29, 39, + 61, 66, 39, -6, -25, 16, 30, 0, -16, -8, 12, 13, 18, 38, 10, -20, + -36, -34, -31, -16, -33, -56, -42, 0, 0, -21, -22, -12, 11, 25, 49, 68, + 53, 14, -20, -3, 29, 15, -11, -12, 3, 13, 13, 42, 34, -12, -39, -37, + -27, -22, -18, -44, -50, -21, 3, -12, -15, -18, -5, 9, 27, 60, 60, 32, + -6, -12, 21, 25, -4, -12, -2, 7, 8, 33, 53, 8, -37, -41, -25, -22, + -16, -27, -47, -34, -10, -10, -15, -15, -15, -5, 5, 41, 63, 44, 12, -11, + 10, 32, 10, -14, -8, 8, 5, 19, 53, 34, -24, -43, -25, -14, -15, -19, + -35, -35, -20, -12, -8, -14, -17, -19, -13, 19, 55, 53, 22, -8, 4, 31, + 26, -8, -13, 6, 10, 7, 39, 50, -2, -41, -31, -10, -13, -23, -31, -33, + -24, -15, -7, -13, -16, -22, -23, -6, 38, 55, 34, 1, -1, 23, 34, 9, + -18, -3, 14, 9, 20, 51, 24, -28, -37, -6, 2, -20, -30, -27, -21, -22, + -6, -12, -17, -21, -32, -27, 9, 49, 43, 12, -4, 14, 34, 24, -9, -12, + 12, 19, 13, 30, 37, -3, -35, -15, 12, -10, -31, -30, -15, -18, -13, -3, + -19, -20, -31, -35, -17, 28, 44, 22, 0, 7, 28, 27, 5, -15, 1, 20, + 20, 17, 28, 19, -21, -23, 12, 8, -22, -32, -20, -8, -15, 0, -13, -23, + -25, -43, -36, 4, 37, 30, 11, 4, 22, 28, 15, 0, -10, 9, 23, 14, + 11, 24, 5, -21, 2, 17, -8, -27, -27, -7, -10, -6, -1, -20, -26, -39, + -53, -20, 23, 36, 17, 7, 14, 28, 16, 12, -3, 2, 19, 16, 2, 14, + 19, -8, -5, 17, 4, -15, -26, -10, -4, -12, 1, -8, -23, -38, -58, -41, + 0, 29, 23, 11, 16, 21, 15, 9, 11, -6, 11, 20, 4, 3, 24, 5, + -5, 10, 17, -6, -15, -15, 6, -15, -8, 0, -11, -37, -54, -56, -24, 13, + 29, 12, 15, 20, 19, 6, 16, 5, -2, 10, 11, -3, 22, 18, 0, 6, + 20, 10, -6, -12, 1, -6, -23, 0, 1, -23, -56, -60, -43, -10, 19, 22, + 15, 22, 18, 6, 11, 17, -2, -5, 10, 4, 7, 23, 1, 3, 16, 22, + 5, -1, 0, 5, -21, -14, 6, -6, -46, -64, -54, -29, 1, 17, 18, 24, + 25, 10, 1, 17, 9, -8, -1, 15, 6, 20, 11, 2, 14, 25, 16, 9, + 5, 7, -11, -26, -5, 4, -27, -62, -62, -40, -17, 8, 11, 21, 29, 17, + -2, 10, 17, -8, -16, 6, 13, 11, 15, 3, 8, 24, 26, 14, 12, 12, + 4, -26, -15, 1, -12, -50, -64, -48, -27, -10, 5, 8, 32, 31, 1, -1, + 18, 0, -23, -6, 18, 14, 11, 5, 3, 17, 35, 25, 16, 18, 14, -11, + -27, -8, -6, -30, -55, -53, -36, -20, -5, 5, 14, 43, 13, -6, 11, 11, + -22, -22, 7, 19, 13, 10, 1, 7, 30, 36, 22, 23, 23, 6, -28, -20, + -6, -23, -43, -49, -43, -29, -19, 3, 1, 34, 29, -4, 3, 13, -13, -32, + -3, 20, 14, 11, 5, 2, 23, 42, 34, 22, 23, 21, -13, -26, -14, -19, + -32, -38, -43, -32, -29, -6, 4, 16, 35, 9, -4, 11, 0, -33, -22, 9, + 13, 12, 9, 3, 14, 35, 47, 34, 23, 27, 8, -22, -19, -16, -30, -29, + -42, -33, -32, -23, 4, 9, 24, 20, -1, 3, 10, -20, -36, -5, 13, 9, + 11, 8, 8, 21, 43, 48, 27, 22, 23, -7, -25, -20, -28, -25, -31, -36, + -28, -33, -8, 11, 14, 14, 6, -8, 7, -5, -39, -25, 7, 14, 9, 10, + 12, 15, 29, 55, 41, 23, 22, 9, -12, -23, -28, -24, -23, -34, -26, -31, + -21, 9, 19, 9, 1, -3, -1, 7, -32, -38, -9, 13, 11, 9, 11, 14, + 21, 46, 53, 32, 24, 12, -2, -16, -26, -24, -17, -34, -33, -25, -24, -4, + 17, 14, -3, -4, -7, 3, -13, -46, -25, 2, 17, 5, 8, 12, 18, 32, + 56, 38, 29, 15, 8, -4, -22, -30, -14, -22, -42, -25, -15, -10, 6, 17, + 1, -5, -7, -10, -2, -38, -37, -7, 15, 9, 2, 8, 21, 26, 43, 44, + 29, 18, 7, 12, -9, -25, -24, -11, -35, -43, -17, -5, 3, 10, 9, -3, + -3, -23, -9, -23, -45, -22, 7, 15, 2, 4, 17, 33, 31, 45, 35, 23, + 8, 17, 6, -16, -26, -14, -20, -48, -27, -2, 6, 11, 9, -1, 6, -15, + -28, -18, -39, -32, -7, 11, 7, 6, 7, 33, 30, 31, 41, 27, 7, 13, + 24, -3, -18, -22, -9, -40, -41, -10, 4, 9, 17, 3, 5, -4, -37, -29, + -29, -35, -19, 1, 10, 3, 7, 25, 41, 19, 31, 32, 13, 5, 27, 14, + -6, -19, -12, -23, -48, -22, 7, 8, 16, 11, 1, 6, -29, -46, -32, -32, + -20, -5, 7, 4, 3, 21, 43, 32, 15, 29, 16, 8, 19, 26, 3, -9, + -22, -13, -42, -37, -8, 11, 14, 25, 9, 4, -17, -50, -44, -30, -25, -14, + -1, 11, 1, 18, 36, 41, 12, 14, 18, 14, 15, 20, 17, 6, -14, -18, + -27, -39, -19, 5, 12, 24, 27, 8, -13, -49, -53, -32, -27, -19, -12, 7, + 7, 12, 31, 43, 26, 2, 8, 14, 22, 13, 17, 18, 6, -17, -26, -36, + -28, -6, 14, 25, 35, 20, -6, -42, -57, -37, -23, -23, -20, 0, 9, 8, + 25, 41, 40, 7, -4, 1, 23, 21, 14, 22, 20, -2, -24, -34, -31, -13, + 8, 24, 37, 33, 8, -32, -62, -44, -20, -22, -27, -9, 9, 7, 16, 31, + 42, 20, -10, -13, 10, 26, 7, 13, 25, 18, -11, -35, -39, -20, 0, 17, + 37, 37, 19, -17, -58, -55, -26, -18, -25, -21, 0, 14, 12, 20, 38, 35, + 0, -19, -9, 24, 19, 3, 21, 31, 17, -24, -42, -30, -3, 13, 34, 42, + 28, -2, -45, -62, -38, -22, -19, -20, -12, 12, 17, 11, 29, 42, 18, -16, + -20, 3, 24, 2, 4, 26, 36, 0, -38, -45, -13, 12, 27, 41, 34, 14, + -27, -62, -55, -30, -19, -15, -16, -2, 18, 11, 14, 37, 31, -6, -22, -12, + 15, 10, -10, 12, 36, 30, -19, -46, -33, 11, 24, 28, 35, 28, -5, -44, + -65, -44, -23, -11, -9, -8, 5, 14, 10, 25, 37, 14, -17, -18, -2, 14, + -7, -6, 23, 43, 10, -33, -38, -9, 24, 24, 28, 30, 11, -21, -57, -61, + -39, -12, -5, -5, -3, 7, 10, 17, 31, 30, -3, -20, -14, 6, 1, -16, + 2, 38, 38, -5, -30, -24, 13, 25, 21, 28, 15, 1, -34, -64, -62, -23, + 0, 2, -1, -1, 5, 14, 24, 33, 14, -12, -23, -4, 7, -18, -18, 18, + 43, 25, -9, -22, -2, 21, 19, 24, 20, 11, -13, -47, -69, -46, -7, 5, + 6, -1, -4, 9, 21, 31, 25, 5, -15, -20, 3, -8, -33, -7, 29, 37, + 20, -10, -10, 9, 15, 17, 14, 12, 1, -23, -55, -70, -30, 5, 13, 2, + -8, -1, 15, 25, 30, 15, -1, -20, -8, -3, -31, -28, 8, 31, 41, 15, + -6, 0, 9, 14, 12, 9, 8, -10, -28, -63, -55, -12, 17, 11, -7, -13, + 8, 22, 26, 19, 9, -7, -13, -5, -23, -39, -10, 17, 41, 38, 8, 0, + 5, 7, 12, 5, 7, -6, -8, -39, -60, -35, 7, 19, 6, -10, -6, 15, + 26, 22, 15, 9, -8, -13, -24, -45, -29, -1, 29, 48, 30, 2, 6, 5, + 9, 5, -1, -5, -4, -13, -51, -51, -16, 20, 13, 0, -11, 7, 25, 22, + 18, 17, 10, -8, -22, -50, -43, -13, 15, 46, 42, 16, 7, 8, 7, 7, + -1, -6, -10, -4, -27, -45, -36, 5, 16, 7, -5, -5, 20, 22, 19, 19, + 22, 7, -15, -43, -62, -29, 3, 35, 43, 27, 11, 9, 8, 4, 2, -9, + -13, -7, -15, -30, -43, -16, 12, 13, 4, -8, 12, 24, 17, 16, 24, 25, + -3, -38, -72, -52, -9, 25, 42, 30, 21, 8, 14, 4, 6, -3, -13, -12, + -13, -18, -36, -34, 3, 14, 9, -9, 5, 26, 18, 13, 26, 34, 13, -31, + -69, -68, -16, 19, 35, 29, 22, 6, 16, 3, 2, 6, -5, -15, -20, -19, + -21, -34, -17, 8, 16, -2, -3, 24, 27, 16, 23, 34, 32, -10, -56, -80, + -45, 6, 29, 29, 22, 10, 14, 13, -4, 6, 7, -8, -27, -27, -18, -20, + -28, -8, 14, 8, -7, 11, 29, 21, 17, 25, 35, 16, -36, -77, -67, -14, + 25, 30, 22, 11, 10, 19, 5, 2, 6, 5, -18, -34, -25, -13, -23, -19, + 4, 13, 0, 7, 24, 32, 24, 22, 31, 30, -12, -62, -76, -41, 9, 28, + 24, 15, 6, 18, 16, 6, 6, 7, -7, -32, -37, -16, -18, -24, -8, 11, + 7, 7, 20, 31, 35, 25, 24, 33, 9, -40, -72, -58, -16, 17, 27, 16, + 6, 10, 22, 12, 8, 8, 2, -23, -43, -26, -16, -24, -18, 2, 6, 7, + 21, 29, 36, 32, 21, 27, 22, -21, -57, -67, -38, -4, 26, 21, 9, 3, + 18, 25, 18, 10, 2, -11, -42, -36, -24, -27, -23, -9, 5, 2, 17, 32, + 42, 36, 27, 18, 25, -2, -39, -58, -51, -27, 11, 27, 11, 1, 9, 24, + 25, 21, 5, -8, -31, -37, -30, -33, -24, -15, 0, -2, 13, 31, 48, 47, + 33, 15, 18, 10, -27, -50, -52, -44, -12, 21, 21, 5, -1, 13, 33, 30, + 16, -6, -26, -39, -33, -35, -28, -20, -10, -8, 4, 27, 51, 61, 45, 21, + 13, 14, -11, -39, -40, -44, -36, 1, 25, 16, 1, 2, 27, 40, 28, 3, + -22, -38, -38, -32, -33, -21, -18, -14, -8, 18, 50, 66, 60, 27, 7, 12, + -3, -31, -36, -37, -46, -27, 18, 26, 5, -3, 8, 35, 43, 16, -14, -36, + -43, -32, -32, -25, -16, -23, -14, 6, 46, 64, 74, 49, 9, 4, 7, -23, + -37, -34, -41, -44, -8, 31, 19, -5, 0, 21, 47, 33, -2, -33, -43, -43, + -32, -29, -14, -22, -23, -6, 34, 62, 75, 71, 30, 0, 8, -13, -37, -34, + -35, -45, -34, 18, 31, 5, -5, 7, 35, 44, 12, -23, -45, -49, -40, -29, + -18, -18, -27, -15, 22, 57, 74, 80, 57, 15, 4, -1, -39, -34, -34, -40, + -46, -4, 25, 13, -3, 2, 22, 44, 25, -10, -38, -44, -50, -34, -20, -14, + -31, -21, 5, 47, 63, 81, 76, 38, 8, 9, -30, -45, -35, -36, -43, -20, + 9, 14, 5, 3, 7, 36, 32, 3, -32, -43, -50, -40, -28, -13, -24, -28, + -2, 35, 56, 73, 86, 58, 23, 21, -10, -49, -45, -33, -39, -25, -3, 5, + 5, 8, 5, 18, 32, 17, -19, -45, -49, -41, -35, -22, -19, -31, -12, 28, + 52, 59, 76, 74, 41, 31, 10, -39, -58, -41, -32, -27, -5, -3, 3, 8, + 8, 10, 24, 22, -4, -39, -52, -42, -35, -30, -18, -28, -22, 20, 53, 52, + 60, 73, 62, 43, 31, -18, -56, -61, -35, -28, -9, -6, -3, 3, 9, 10, + 12, 18, 8, -23, -53, -50, -31, -35, -24, -28, -26, 3, 48, 55, 52, 59, + 66, 57, 46, 7, -37, -67, -53, -24, -11, -4, -6, 0, 3, 13, 10, 7, + 10, -6, -38, -58, -36, -30, -30, -26, -26, -11, 33, 60, 56, 49, 59, 67, + 58, 32, -15, -58, -69, -34, -14, -8, -6, 1, -4, 7, 8, 2, 4, 4, + -21, -54, -49, -30, -30, -28, -29, -18, 13, 53, 60, 50, 44, 63, 61, 49, + 11, -33, -71, -49, -19, -9, -10, 5, 2, -1, 4, -1, 4, 5, -5, -38, + -55, -40, -28, -21, -25, -26, -2, 40, 61, 56, 39, 53, 66, 54, 33, -4, + -55, -63, -29, -18, -12, 3, 11, -4, -4, -9, -3, 4, 4, -18, -49, -49, + -35, -18, -18, -25, -16, 24, 51, 60, 42, 43, 66, 57, 42, 21, -23, -63, + -44, -26, -18, -10, 13, 9, -8, -18, -17, 5, 5, -4, -35, -47, -42, -24, + -11, -20, -21, 5, 36, 56, 53, 37, 60, 59, 40, 34, 11, -34, -52, -33, + -21, -15, 1, 21, 2, -19, -33, -10, 8, 3, -20, -42, -41, -33, -14, -16, + -18, -7, 21, 43, 54, 39, 47, 61, 44, 31, 27, -4, -41, -47, -28, -23, + -9, 11, 15, -9, -34, -34, 1, 10, -2, -30, -38, -34, -18, -15, -17, -10, + 10, 27, 43, 42, 42, 53, 54, 36, 24, 14, -15, -42, -36, -32, -22, 1, + 13, 7, -26, -48, -24, 11, 10, -14, -35, -32, -19, -16, -15, -11, 5, 18, + 31, 34, 41, 48, 51, 46, 28, 26, 8, -26, -36, -33, -35, -12, 7, 12, + -8, -45, -47, -9, 13, 5, -24, -32, -17, -14, -16, -11, 6, 14, 20, 26, + 27, 47, 49, 49, 34, 25, 22, -6, -31, -27, -39, -30, -10, 13, 6, -28, + -57, -31, -3, 12, -7, -28, -19, -8, -21, -18, -2, 18, 17, 17, 19, 34, + 47, 53, 42, 34, 30, 13, -22, -20, -30, -44, -32, -4, 15, -7, -45, -49, + -18, 4, 10, -14, -18, 0, -11, -26, -7, 15, 23, 10, 10, 20, 34, 51, + 49, 38, 41, 30, -8, -28, -15, -39, -47, -28, 5, 10, -26, -55, -34, -9, + 10, 3, -13, -4, 1, -21, -19, 3, 25, 13, 5, 9, 18, 36, 54, 39, + 40, 46, 16, -27, -17, -23, -47, -47, -18, 9, -2, -47, -51, -23, 0, 4, + 0, 1, 9, -11, -20, -9, 20, 23, 4, 2, 8, 20, 45, 46, 38, 53, + 41, -13, -30, -19, -36, -52, -40, -9, 5, -23, -53, -35, -6, 4, 3, 6, + 10, 5, -16, -17, 6, 30, 12, 0, -4, 9, 32, 47, 43, 55, 57, 16, + -27, -30, -28, -44, -52, -31, -6, -8, -43, -43, -15, -1, -1, 8, 10, 13, + 2, -18, -11, 21, 23, 6, -5, 0, 19, 33, 41, 56, 67, 44, -5, -34, + -35, -32, -46, -47, -27, -7, -30, -44, -23, -2, -2, 3, 7, 14, 18, -1, + -19, 4, 20, 16, -5, -9, 10, 27, 30, 46, 65, 63, 26, -22, -42, -34, + -41, -46, -40, -18, -25, -39, -28, -4, 1, -1, 5, 10, 24, 19, -8, -6, + 11, 20, 4, -13, 2, 22, 24, 36, 59, 70, 51, 5, -39, -39, -43, -47, + -45, -31, -30, -39, -33, -7, 1, -2, 1, 4, 19, 25, 5, -5, 1, 12, + 13, -12, -12, 18, 25, 21, 46, 68, 69, 36, -17, -39, -44, -51, -43, -33, + -35, -41, -38, -15, 8, 0, 0, 0, 13, 26, 19, 5, 0, -1, 10, -2, + -14, 5, 25, 19, 29, 54, 71, 59, 9, -31, -43, -56, -50, -32, -38, -47, + -42, -26, 8, 10, -3, -3, 7, 20, 23, 16, 8, -5, 3, 2, -17, -6, + 22, 20, 18, 40, 66, 71, 37, -13, -36, -52, -61, -38, -32, -47, -51, -38, + -7, 19, 6, -6, 4, 14, 19, 21, 19, 2, -5, 0, -13, -12, 14, 21, + 13, 27, 53, 71, 57, 12, -25, -42, -61, -54, -33, -38, -52, -50, -22, 13, + 17, -4, 1, 16, 17, 19, 25, 11, -2, -2, -11, -18, 6, 21, 15, 18, + 43, 66, 67, 34, -7, -30, -49, -58, -42, -36, -42, -54, -36, -2, 20, 4, + -4, 11, 16, 17, 26, 17, 4, 1, -8, -22, -8, 17, 16, 17, 27, 55, + 66, 48, 10, -25, -36, -49, -52, -42, -39, -47, -46, -18, 13, 14, -1, 3, + 13, 19, 27, 18, 2, 5, 1, -14, -17, 6, 13, 16, 26, 44, 64, 54, + 27, -15, -30, -33, -49, -50, -43, -44, -45, -30, -1, 13, 3, 6, 10, 22, + 30, 21, 3, 2, 2, -3, -18, -9, 8, 11, 23, 35, 55, 58, 37, 1, + -25, -18, -33, -51, -48, -46, -41, -30, -17, 6, 3, 7, 9, 16, 30, 27, + 9, 3, 3, 1, -10, -18, 0, 3, 12, 37, 46, 52, 40, 15, -23, -16, + -14, -39, -48, -48, -45, -31, -20, -7, 1, 4, 14, 13, 21, 26, 16, 2, + 1, 1, 1, -16, -12, 1, 5, 29, 50, 47, 39, 21, -11, -21, -3, -23, + -41, -45, -47, -37, -21, -13, -6, 1, 16, 20, 22, 22, 18, 10, 2, 1, + 6, -7, -16, -10, 0, 16, 51, 53, 38, 22, -1, -21, -1, -4, -30, -41, + -45, -45, -28, -13, -13, -8, 13, 24, 26, 15, 13, 15, 8, -4, 1, -2, + -11, -15, -11, 2, 40, 56, 44, 21, 1, -16, -10, 5, -16, -32, -38, -41, + -36, -22, -14, -15, 4, 24, 32, 18, 7, 14, 14, 4, -2, -1, -8, -12, + -15, -6, 24, 50, 51, 28, 1, -13, -14, 4, 1, -18, -31, -35, -36, -33, + -21, -21, -5, 19, 38, 23, 3, 5, 17, 15, 2, -3, -7, -8, -18, -14, + 12, 39, 50, 35, 2, -14, -14, -3, 6, -6, -24, -27, -32, -40, -25, -22, + -12, 8, 35, 34, 10, 2, 5, 19, 9, -6, -4, -3, -15, -18, 4, 30, + 42, 40, 13, -17, -16, -7, 3, 5, -14, -21, -24, -41, -37, -23, -18, -1, + 22, 37, 17, 4, -1, 11, 17, 1, -7, -4, -12, -22, -6, 24, 35, 33, + 25, -7, -26, -15, 2, 14, 3, -16, -19, -33, -42, -27, -23, -10, 15, 28, + 27, 8, 2, 5, 20, 11, -4, -6, -7, -19, -11, 17, 31, 26, 25, 6, + -24, -25, -6, 11, 14, -3, -13, -25, -39, -33, -23, -17, 7, 19, 26, 19, + 4, 1, 15, 14, -1, -5, -10, -14, -22, 8, 33, 28, 20, 16, -13, -26, + -17, 9, 22, 5, -8, -18, -37, -35, -28, -23, -4, 12, 16, 28, 12, 1, + 12, 18, 3, -2, -9, -10, -27, -10, 29, 34, 18, 16, 2, -26, -29, -3, + 27, 19, -4, -10, -29, -36, -30, -29, -12, 9, 3, 18, 21, 7, 12, 17, + 3, -2, -7, -7, -19, -26, 15, 36, 21, 12, 9, -15, -30, -18, 19, 30, + 6, -5, -21, -32, -25, -29, -22, 6, 0, 3, 20, 14, 12, 18, 12, 0, + -9, -12, -9, -26, -4, 31, 28, 11, 10, -6, -24, -29, 3, 35, 19, -3, + -15, -26, -19, -23, -31, -6, 4, -7, 13, 19, 17, 20, 18, 9, -9, -19, + -5, -17, -20, 16, 34, 18, 9, 0, -16, -25, -10, 30, 29, 3, -10, -19, + -19, -16, -29, -19, 3, -9, -5, 13, 21, 24, 16, 13, 1, -23, -14, -12, + -19, -2, 28, 21, 8, 1, -11, -23, -19, 16, 41, 14, -8, -13, -9, -13, + -18, -27, -4, -5, -12, -1, 19, 31, 18, 10, 16, -20, -22, -13, -14, -12, + 18, 26, 12, 4, -4, -17, -18, -1, 38, 31, -5, -14, -7, -7, -14, -24, + -13, -3, -13, -12, 7, 30, 34, 14, 18, -5, -33, -18, -10, -14, 1, 19, + 14, 6, -8, -13, -15, -2, 19, 40, 8, -13, -9, -4, -8, -18, -20, -9, + -14, -16, -7, 22, 37, 23, 16, 10, -26, -28, -13, -9, -5, 14, 14, 9, + -9, -17, -13, -1, 8, 31, 26, -6, -10, -4, -2, -12, -19, -11, -11, -17, + -12, 6, 34, 29, 15, 16, -7, -35, -25, -9, -6, 8, 14, 12, 1, -15, + -14, 3, 10, 19, 29, 8, -10, -9, 1, -7, -20, -10, -9, -17, -17, -1, + 30, 35, 18, 15, 5, -28, -33, -17, -6, -4, 8, 13, 5, -14, -19, 1, + 14, 14, 20, 17, 0, -8, -2, -3, -14, -18, -9, -12, -18, -6, 21, 37, + 26, 7, 10, -13, -33, -24, -6, -2, 0, 9, 11, -5, -19, -7, 16, 18, + 13, 18, 11, -2, -6, -3, -6, -22, -10, -11, -16, -11, 17, 34, 32, 9, + 9, 2, -26, -30, -14, -2, -5, 3, 8, 3, -16, -12, 8, 21, 13, 13, + 15, 2, -3, -5, -5, -20, -16, -8, -16, -20, 6, 32, 34, 14, -4, 6, + -12, -26, -20, -7, -6, -4, 4, 7, -2, -15, 1, 17, 15, 9, 15, 10, + 0, -3, -7, -15, -22, -4, -7, -19, -7, 29, 36, 20, -6, -1, 0, -17, + -19, -12, -9, -7, -1, 2, 6, -3, -8, 10, 18, 9, 8, 21, 4, -2, + -8, -13, -20, -12, -2, -16, -14, 14, 39, 26, -3, -17, 1, -6, -16, -12, + -7, -9, -9, 0, 3, 11, -3, 0, 15, 13, 3, 19, 12, -8, -6, -14, + -19, -16, 0, -6, -17, 3, 33, 35, 5, -18, -9, 1, -15, -11, -8, -8, + -16, -8, 1, 15, 15, 3, 11, 19, 2, 12, 26, 0, -10, -13, -21, -11, + 1, -1, -18, -2, 23, 35, 17, -12, -21, -2, -8, -9, -8, -9, -12, -17, + -5, 10, 22, 8, 7, 18, 7, -1, 23, 13, -13, -19, -23, -14, 5, 2, + -15, -13, 17, 30, 22, -3, -24, -7, -2, -9, -6, -10, -8, -21, -19, 5, + 22, 22, 13, 15, 13, -3, 11, 18, -4, -20, -28, -20, 4, 11, -10, -18, + 6, 26, 17, 3, -20, -12, -2, -11, -7, -8, -8, -16, -27, -7, 19, 30, + 21, 19, 15, 4, 3, 18, 2, -17, -33, -24, 0, 17, 1, -16, -6, 24, + 19, 5, -17, -18, 1, -8, -12, -7, -11, -10, -22, -14, 10, 29, 29, 32, + 23, 13, 0, 9, 6, -12, -28, -36, -7, 13, 12, -8, -17, 12, 24, 6, + -10, -20, 1, 1, -13, -9, -12, -16, -20, -17, 0, 21, 27, 31, 35, 20, + 7, 0, 2, -13, -19, -37, -19, 8, 18, 9, -16, -9, 20, 11, -2, -25, + -13, 8, -4, -16, -13, -18, -23, -17, 0, 14, 29, 27, 43, 35, 17, -1, + -4, -13, -22, -29, -31, -2, 17, 20, -5, -21, 6, 16, 5, -16, -25, 4, + 11, -12, -17, -20, -27, -19, -2, 13, 26, 27, 36, 46, 32, 7, -8, -18, + -26, -25, -32, -16, 12, 26, 11, -18, -11, 4, 13, -1, -27, -12, 14, 2, + -21, -23, -31, -26, -11, 10, 24, 30, 29, 43, 50, 24, -4, -16, -34, -28, + -28, -27, -1, 27, 24, -5, -21, -12, 6, 16, -13, -28, 1, 13, -9, -23, + -33, -32, -18, 2, 24, 34, 33, 34, 50, 49, 12, -11, -34, -37, -28, -25, + -14, 14, 28, 10, -10, -25, -9, 21, 15, -27, -15, 12, 2, -18, -33, -36, + -24, -7, 13, 30, 39, 42, 35, 54, 36, 1, -29, -45, -35, -26, -17, -1, + 20, 19, 2, -23, -30, 1, 30, -5, -32, 1, 7, -8, -27, -37, -25, -12, + -1, 23, 37, 51, 38, 41, 49, 16, -15, -41, -40, -31, -21, -11, 4, 19, + 15, -8, -33, -19, 22, 20, -21, -13, 2, -6, -17, -36, -32, -11, -8, 9, + 28, 48, 54, 36, 48, 30, 3, -30, -41, -34, -24, -15, -6, 2, 17, 8, + -19, -37, 0, 31, 3, -20, -6, -4, -7, -31, -35, -9, -3, -4, 16, 37, + 62, 44, 41, 33, 13, -11, -36, -39, -29, -21, -11, -11, 6, 14, -2, -28, + -24, 15, 22, -5, -10, -11, -10, -20, -35, -13, 2, -5, 2, 21, 55, 64, + 46, 37, 19, 2, -23, -36, -28, -23, -17, -18, -17, 10, 11, -12, -32, -7, + 23, 16, -7, -14, -17, -8, -27, -23, 1, 1, 0, 6, 31, 63, 60, 46, + 21, 7, -12, -29, -24, -18, -24, -23, -27, -11, 11, 5, -16, -19, 11, 21, + 4, -9, -21, -15, -17, -30, -5, 7, 2, -1, 9, 48, 65, 59, 30, 13, + -4, -25, -19, -6, -22, -33, -32, -31, -3, 7, -3, -20, -4, 14, 11, -1, + -11, -19, -13, -20, -16, 9, 7, 2, -3, 27, 60, 69, 44, 12, 7, -18, + -20, 1, -4, -35, -38, -34, -22, -9, 4, -2, -11, 8, 8, 2, -6, -19, + -23, -14, -16, 3, 13, 2, 2, 12, 47, 65, 62, 22, 10, -3, -21, -9, + 9, -17, -46, -40, -34, -23, -6, 4, -1, 3, 7, 2, -4, -13, -25, -18, + -11, -4, 18, 3, -2, 5, 30, 58, 66, 39, 12, 9, -10, -18, 8, 5, + -41, -49, -38, -33, -18, -4, 2, 7, 8, 2, -7, -12, -18, -23, -12, -6, + 18, 15, -8, 0, 21, 44, 62, 48, 22, 14, 7, -16, -7, 18, -18, -52, + -44, -42, -32, -18, -1, 12, 10, 6, -8, -20, -11, -18, -19, -10, 14, 24, + 2, -5, 14, 34, 57, 51, 27, 19, 20, -1, -13, 15, -1, -42, -45, -49, + -38, -28, -15, 13, 19, 10, -1, -23, -16, -11, -24, -10, 6, 21, 14, -5, + 3, 24, 48, 58, 29, 17, 24, 18, -6, 4, 8, -28, -38, -46, -50, -36, + -29, 3, 22, 15, 4, -18, -31, -7, -20, -17, 5, 11, 18, 4, -2, 15, + 37, 58, 35, 11, 26, 31, 11, -2, 6, -13, -32, -39, -55, -45, -38, -17, + 21, 23, 11, -10, -31, -18, -11, -25, 1, 9, 14, 15, 0, 7, 26, 49, + 49, 13, 10, 33, 26, 8, 4, -5, -25, -35, -46, -53, -41, -35, 5, 24, + 17, 0, -25, -26, -14, -24, -9, 6, 5, 17, 6, 6, 20, 38, 55, 30, + 3, 25, 38, 18, 10, -4, -16, -30, -42, -51, -46, -41, -16, 21, 23, 14, + -16, -30, -16, -17, -17, 0, 2, 12, 16, 3, 17, 28, 46, 49, 14, 13, + 39, 30, 17, 4, -9, -20, -38, -49, -50, -50, -34, 4, 21, 20, 4, -29, + -23, -15, -15, -8, -3, 7, 19, 8, 9, 26, 35, 47, 29, 6, 29, 35, + 26, 13, -5, -18, -29, -42, -49, -51, -50, -16, 11, 23, 18, -17, -34, -14, + -15, -9, -10, -2, 17, 14, 5, 21, 33, 44, 38, 14, 23, 37, 30, 20, + 6, -8, -26, -34, -47, -52, -54, -34, 0, 16, 19, 5, -29, -20, -13, -10, + -9, -10, 4, 19, 11, 13, 29, 37, 36, 22, 22, 39, 32, 23, 10, 2, + -18, -32, -40, -54, -56, -49, -23, 8, 17, 11, -15, -26, -11, -13, -9, -15, + -11, 14, 17, 10, 23, 34, 36, 24, 21, 35, 42, 26, 12, 2, -4, -23, + -31, -47, -57, -50, -33, -7, 17, 11, -2, -18, -12, -12, -11, -10, -21, -6, + 18, 19, 21, 33, 35, 28, 23, 34, 51, 40, 12, -2, 1, -9, -27, -43, + -59, -53, -39, -23, 4, 15, 1, -10, -14, -9, -8, -10, -22, -18, 5, 19, + 16, 27, 34, 28, 23, 27, 47, 53, 27, -3, -4, -1, -13, -33, -53, -57, + -45, -31, -13, 14, 4, -4, -11, -9, -9, -11, -19, -28, -16, 10, 24, 23, + 35, 24, 26, 26, 38, 60, 44, 2, -13, -3, -5, -19, -44, -58, -49, -33, + -26, 1, 14, 1, -4, -5, 0, -7, -14, -29, -26, -11, 20, 27, 30, 32, + 21, 27, 34, 59, 58, 22, -11, -10, -6, -10, -29, -55, -53, -38, -34, -16, + 12, 9, -5, -8, 5, 1, -16, -31, -32, -28, 0, 26, 26, 33, 23, 24, + 33, 49, 61, 37, 3, -15, -8, -11, -19, -43, -56, -44, -34, -25, -2, 17, + 5, -11, 2, 12, -2, -23, -32, -35, -23, 14, 26, 27, 35, 23, 32, 45, + 58, 47, 19, -5, -9, -10, -16, -27, -46, -48, -41, -34, -18, 11, 20, -6, + -10, 12, 9, -18, -34, -38, -29, -7, 17, 27, 32, 30, 30, 46, 52, 51, + 28, 6, -8, -9, -15, -24, -32, -41, -45, -40, -30, -1, 23, 10, -12, 2, + 17, -2, -31, -39, -32, -18, -6, 18, 29, 38, 32, 45, 54, 54, 33, 11, + 2, -9, -11, -19, -32, -33, -41, -45, -40, -18, 16, 19, 2, -6, 13, 12, + -20, -43, -35, -21, -18, -5, 21, 35, 36, 46, 58, 52, 38, 17, 9, -5, + -9, -13, -29, -32, -28, -41, -43, -36, 0, 22, 18, -4, -3, 17, 2, -33, + -43, -25, -18, -16, 4, 27, 38, 47, 64, 57, 40, 18, 10, 5, -7, -10, + -22, -39, -24, -30, -42, -39, -22, 13, 28, 14, -9, 3, 17, -16, -51, -36, + -17, -23, -18, 8, 35, 50, 66, 68, 43, 23, 12, 13, -1, -11, -17, -32, + -27, -22, -40, -38, -37, -10, 22, 34, 1, -10, 8, 6, -39, -48, -27, -19, + -25, -10, 18, 49, 66, 78, 54, 26, 17, 16, 3, -7, -15, -25, -29, -12, + -32, -37, -35, -28, 3, 38, 26, -7, -4, 11, -15, -46, -42, -26, -23, -24, + -2, 34, 66, 81, 70, 30, 19, 21, 10, -5, -11, -25, -29, -12, -20, -37, + -33, -39, -17, 25, 46, 6, -11, 2, 0, -29, -44, -41, -30, -27, -17, 12, + 58, 79, 84, 46, 19, 22, 19, 2, -7, -26, -35, -12, -1, -29, -33, -39, + -36, 3, 46, 31, -11, -6, -1, -14, -38, -46, -39, -32, -22, -5, 40, 76, + 88, 64, 23, 22, 30, 12, -8, -20, -39, -22, 0, -13, -29, -33, -43, -20, + 24, 49, 13, -12, 2, -6, -26, -45, -45, -39, -32, -15, 19, 68, 85, 77, + 32, 22, 35, 27, 0, -18, -36, -38, -6, 3, -17, -29, -44, -37, -2, 40, + 34, -8, -6, 3, -18, -44, -47, -44, -43, -21, 3, 49, 76, 80, 53, 21, + 35, 39, 15, -18, -35, -42, -23, 2, -3, -19, -33, -42, -23, 16, 46, 16, + -8, 2, -6, -37, -45, -47, -51, -33, -8, 31, 68, 74, 66, 33, 35, 45, + 36, -3, -33, -40, -34, -7, 5, -8, -18, -35, -39, -13, 32, 32, 3, -1, + 5, -26, -46, -50, -52, -44, -20, 15, 59, 68, 69, 50, 32, 42, 48, 21, + -26, -42, -42, -24, 2, 2, -8, -20, -38, -35, 6, 33, 17, -2, 5, -6, + -41, -55, -57, -46, -33, -6, 40, 64, 62, 63, 45, 38, 54, 40, -4, -42, + -50, -40, -11, 6, -2, -8, -24, -41, -19, 17, 28, 10, 0, 1, -26, -52, + -64, -51, -40, -23, 19, 54, 56, 61, 60, 38, 52, 55, 24, -30, -50, -47, + -27, 4, 8, -6, -11, -30, -36, -6, 19, 25, 4, 1, -9, -38, -64, -61, + -42, -36, 0, 44, 55, 51, 66, 50, 49, 62, 46, -5, -48, -51, -40, -11, + 11, 4, -14, -15, -36, -25, 1, 19, 15, -1, -2, -18, -53, -69, -48, -42, + -20, 21, 51, 45, 56, 62, 51, 60, 59, 23, -32, -53, -49, -28, 5, 17, + -12, -18, -22, -32, -12, 9, 20, 1, -6, -5, -29, -70, -62, -48, -32, 2, + 36, 45, 44, 62, 62, 60, 64, 47, -10, -45, -54, -42, -11, 21, 5, -19, + -18, -23, -20, -1, 15, 4, -6, -2, -6, -51, -72, -57, -44, -13, 19, 40, + 41, 51, 65, 66, 69, 63, 14, -32, -47, -50, -30, 10, 14, -12, -16, -18, + -16, -14, 7, 8, -6, -8, -1, -21, -65, -67, -54, -29, 1, 26, 38, 44, + 53, 69, 77, 73, 37, -17, -41, -46, -37, -10, 13, -1, -11, -14, -14, -10, + -6, 9, -5, -6, -11, -3, -43, -67, -68, -42, -15, 12, 27, 40, 47, 65, + 80, 83, 55, 7, -34, -43, -34, -22, -5, 2, -3, -2, -13, -10, -11, 3, + -2, -4, -13, -5, -15, -51, -72, -63, -31, -3, 16, 29, 42, 55, 78, 91, + 68, 25, -11, -40, -32, -22, -21, -9, -1, 8, -1, -19, -11, -3, 1, -5, + -11, -12, -3, -29, -58, -70, -48, -18, 6, 15, 35, 50, 68, 89, 84, 37, + 11, -27, -38, -19, -20, -23, -8, 10, 18, -10, -19, -8, 4, 0, -11, -14, + -7, -20, -42, -63, -60, -37, -4, 7, 23, 41, 67, 82, 90, 53, 19, -4, + -34, -23, -20, -31, -22, 5, 25, 8, -17, -20, 0, 10, -5, -20, -9, -12, + -31, -47, -60, -53, -26, -3, 12, 32, 58, 81, 85, 70, 27, 9, -19, -26, + -19, -28, -31, -8, 24, 21, -2, -26, -11, 14, 10, -20, -18, -8, -24, -33, + -53, -56, -44, -23, 3, 22, 44, 77, 85, 74, 40, 17, -3, -21, -21, -24, + -36, -25, 11, 22, 15, -13, -28, 5, 23, 0, -28, -12, -19, -26, -42, -56, + -48, -39, -17, 12, 34, 62, 84, 73, 52, 26, 9, -12, -21, -22, -31, -30, + -1, 15, 16, 6, -25, -14, 23, 19, -17, -21, -13, -24, -34, -54, -44, -39, + -36, -9, 27, 46, 79, 79, 59, 38, 16, -2, -17, -25, -25, -27, -10, 5, + 10, 15, -4, -24, 5, 29, 5, -24, -18, -19, -28, -48, -50, -35, -38, -28, + 10, 33, 62, 82, 62, 46, 27, 4, -8, -23, -24, -25, -15, -3, 0, 8, + 6, -12, -9, 22, 25, -6, -21, -22, -28, -45, -53, -39, -30, -37, -11, 20, + 43, 75, 66, 53, 41, 10, -8, -16, -25, -23, -15, -2, -4, -5, 4, 1, + -7, 8, 29, 19, -9, -21, -24, -42, -55, -48, -30, -31, -19, 5, 23, 61, + 74, 58, 53, 26, -7, -11, -18, -25, -14, 0, 1, -16, -8, 4, 0, 3, + 20, 28, 11, -16, -19, -38, -58, -55, -35, -27, -16, -1, 5, 32, 63, 61, + 56, 44, 3, -17, -13, -22, -19, -4, 5, -8, -21, -6, 7, 8, 12, 25, + 25, 2, -17, -26, -54, -64, -47, -32, -11, 5, 3, 16, 40, 60, 58, 56, + 26, -16, -19, -16, -20, -8, 0, -4, -20, -22, 1, 12, 9, 17, 30, 20, + -2, -15, -42, -68, -57, -44, -19, 11, 6, 10, 19, 42, 58, 58, 45, 6, + -23, -18, -13, -13, -3, -3, -10, -26, -14, 9, 15, 12, 26, 27, 10, -7, + -25, -61, -68, -54, -36, 10, 15, 13, 16, 19, 42, 55, 52, 31, -9, -25, + -18, -15, -7, -3, -9, -23, -26, -2, 15, 19, 19, 26, 18, 7, -10, -41, + -72, -60, -51, -8, 25, 22, 20, 13, 19, 45, 51, 44, 19, -15, -28, -15, + -7, -4, -9, -19, -28, -14, 6, 18, 18, 24, 22, 12, 1, -17, -55, -67, + -56, -35, 19, 33, 30, 20, 9, 23, 44, 48, 39, 6, -22, -25, -9, -8, + -9, -15, -29, -21, -3, 10, 16, 20, 23, 13, 7, -4, -31, -63, -61, -50, + -11, 33, 37, 30, 12, 7, 24, 44, 48, 28, -4, -28, -14, -4, -14, -14, + -27, -27, -8, 5, 13, 15, 19, 19, 11, 3, -12, -44, -64, -58, -31, 17, + 40, 39, 24, 8, 3, 30, 46, 42, 16, -18, -21, -6, -16, -18, -26, -32, + -15, 1, 6, 10, 10, 15, 12, 10, -3, -23, -51, -63, -50, -4, 34, 41, + 33, 17, -4, 10, 35, 42, 32, 5, -15, -8, -10, -18, -21, -30, -22, 0, + 3, -2, -2, 6, 5, 4, 3, -7, -25, -45, -45, -18, 25, 33, 32, 21, + 7, 8, 20, 30, 31, 20, 3, -7, -10, -14, -17, -23, -29, -12, 6, -2, + -11, -11, -4, 2, 3, -7, -10, -27, -33, -21, 13, 27, 23, 19, 8, 15, + 17, 18, 21, 23, 19, 2, -12, -10, -9, -15, -27, -28, -2, 9, -8, -18, + -17, -4, 9, -6, -7, -10, -17, -13, 2, 21, 20, 14, 4, 15, 25, 15, + 11, 14, 19, 13, -13, -17, -6, -5, -20, -36, -23, 4, 6, -18, -28, -20, + 6, 6, 0, 3, 5, 5, 28, 31, 31, 49, 55, 35, 11, 27, 26, 4, + 7, 11, 31, 54, 38, 26, 34, 35, 20, -10, -32, -43, -47, -43, -20, -7, + -37, -55, -62, -61, -63, -34, -21, -35, -28, -10, 15, 24, 23, 5, -31, -38, + -6, 23, 19, 15, 24, 20, 31, 57, 54, 28, 13, 33, 20, 1, 4, 17, + 38, 44, 33, 31, 43, 36, 10, -14, -34, -53, -53, -46, -22, -22, -38, -46, + -54, -60, -58, -29, -25, -39, -29, -12, 11, 25, 27, 6, -31, -33, -3, 27, + 32, 21, 13, 16, 38, 60, 53, 26, 18, 28, 11, -2, 8, 26, 37, 34, + 36, 42, 47, 31, 6, -14, -41, -61, -54, -49, -26, -30, -41, -40, -44, -54, + -48, -23, -28, -41, -33, -7, 14, 26, 29, 3, -32, -27, 6, 33, 35, 18, + 5, 21, 45, 61, 49, 25, 30, 22, 0, -5, 9, 37, 39, 27, 33, 47, + 50, 31, 1, -22, -51, -65, -59, -45, -31, -40, -36, -29, -35, -49, -41, -28, + -39, -44, -26, -8, 6, 27, 31, -5, -31, -18, 14, 33, 31, 17, 4, 25, + 48, 57, 45, 32, 27, 9, -6, -5, 14, 43, 36, 29, 39, 51, 50, 31, + 0, -32, -65, -73, -62, -37, -36, -46, -36, -23, -26, -37, -32, -35, -46, -42, + -22, -11, 2, 30, 28, -8, -29, -12, 22, 33, 32, 15, 4, 25, 49, 58, + 50, 36, 20, 2, -9, -3, 21, 43, 37, 32, 44, 55, 53, 33, -7, -42, + -67, -72, -64, -43, -43, -46, -35, -17, -17, -24, -31, -40, -47, -39, -18, -15, + 0, 33, 22, -14, -22, 5, 29, 29, 28, 11, 7, 23, 49, 54, 50, 37, + 13, -6, -11, -6, 25, 44, 38, 26, 40, 57, 54, 28, -12, -48, -70, -73, + -66, -43, -43, -43, -29, -12, -15, -16, -32, -48, -51, -38, -24, -19, 4, 31, + 12, -16, -14, 21, 34, 24, 24, 13, 10, 27, 49, 53, 53, 33, 6, -9, + -16, -4, 33, 48, 37, 24, 45, 61, 54, 23, -15, -60, -76, -76, -60, -48, + -45, -38, -26, -11, -3, -5, -33, -49, -52, -35, -25, -21, 7, 24, 1, -15, + -1, 34, 30, 23, 29, 17, 5, 26, 49, 55, 53, 26, -3, -16, -16, 4, + 38, 43, 33, 33, 49, 59, 45, 19, -18, -63, -78, -79, -58, -50, -39, -31, + -21, -11, -2, -3, -30, -49, -51, -35, -29, -20, 8, 12, -10, -11, 17, 37, + 27, 29, 29, 13, 2, 33, 56, 55, 38, 18, -7, -19, -17, 13, 40, 42, + 33, 35, 52, 58, 40, 10, -28, -68, -84, -78, -56, -47, -36, -30, -17, -7, + 5, -4, -30, -49, -51, -34, -30, -18, 10, 1, -18, -9, 30, 39, 26, 32, + 28, 9, 7, 38, 51, 45, 35, 16, -13, -28, -11, 27, 41, 41, 34, 45, + 58, 54, 29, 7, -33, -69, -80, -78, -59, -43, -31, -24, -15, -3, 9, -4, + -29, -51, -51, -33, -27, -8, 8, -13, -24, -1, 40, 41, 29, 31, 22, 7, + 15, 46, 48, 38, 33, 11, -19, -28, -7, 26, 42, 36, 39, 54, 54, 48, + 20, 3, -39, -68, -79, -78, -54, -37, -32, -27, -16, 5, 11, -6, -31, -50, + -49, -33, -24, -3, -3, -29, -26, 13, 44, 36, 30, 32, 17, 7, 28, 43, + 37, 31, 28, 4, -17, -27, -5, 24, 46, 43, 48, 56, 50, 41, 20, -1, + -47, -64, -82, -78, -48, -35, -34, -26, -14, 6, 9, -10, -31, -46, -43, -33, + -21, 1, -16, -38, -15, 24, 38, 35, 44, 33, 10, 15, 37, 43, 30, 22, + 18, 4, -20, -29, 0, 30, 43, 48, 54, 52, 46, 35, 19, -9, -41, -60, + -83, -73, -44, -29, -37, -27, -12, 6, 8, -10, -28, -45, -43, -25, -9, -3, + -33, -43, -4, 32, 35, 37, 49, 24, 7, 26, 47, 35, 17, 11, 14, 3, + -21, -30, 6, 30, 44, 60, 56, 44, 37, 33, 15, -11, -40, -63, -82, -61, + -36, -33, -39, -26, -13, 0, 4, -9, -29, -42, -37, -18, -7, -13, -39, -34, + 2, 30, 34, 45, 49, 16, 11, 37, 45, 26, 11, 8, 9, -1, -26, -25, + 17, 31, 46, 62, 52, 42, 29, 26, 15, -12, -45, -64, -71, -48, -34, -35, + -33, -27, -16, 1, 2, -10, -23, -41, -32, -12, -6, -29, -46, -28, 12, 26, + 36, 54, 43, 10, 23, 52, 43, 18, -2, 5, 5, -7, -25, -11, 19, 22, + 49, 61, 50, 40, 24, 20, 15, -10, -47, -62, -62, -45, -34, -30, -30, -23, + -16, -6, -1, -8, -25, -38, -29, -9, -10, -39, -42, -19, 5, 23, 48, 57, + 33, 7, 32, 57, 39, 8, -7, 3, -2, -16, -16, 1, 20, 22, 48, 55, + 46, 39, 17, 16, 17, -9, -48, -58, -54, -40, -37, -28, -26, -22, -23, -5, + 2, -11, -28, -37, -27, -10, -18, -44, -35, -18, 3, 31, 54, 52, 25, 13, + 45, 61, 29, -4, -10, 0, -5, -16, -8, 4, 21, 21, 50, 54, 45, 31, + 4, 20, 18, -15, -43, -48, -48, -39, -33, -28, -25, -22, -21, 0, -1, -19, + -29, -29, -22, -11, -29, -42, -30, -17, 3, 38, 61, 46, 24, 25, 53, 58, + 20, -10, -9, -5, -16, -12, 4, 11, 22, 17, 48, 51, 43, 16, 2, 18, + 13, -15, -35, -46, -43, -38, -31, -23, -27, -24, -13, 3, -8, -25, -29, -27, + -22, -18, -36, -38, -31, -19, 6, 46, 60, 36, 24, 33, 56, 44, 10, -8, + -9, -12, -24, -7, 14, 23, 18, 11, 45, 47, 39, 13, 5, 16, 1, -19, + -22, -39, -45, -45, -31, -20, -24, -16, -6, -3, -19, -24, -25, -26, -22, -24, + -39, -35, -25, -13, 8, 54, 64, 36, 29, 41, 56, 36, 5, -12, -11, -14, + -26, -6, 24, 33, 7, 12, 45, 44, 30, 13, 10, 17, -4, -17, -16, -34, + -46, -50, -30, -20, -23, -12, 1, -11, -26, -27, -24, -21, -19, -34, -48, -32, + -23, -10, 13, 66, 65, 33, 32, 48, 55, 25, 0, -8, -1, -18, -36, -4, + 40, 33, -1, 17, 37, 35, 25, 10, 14, 10, -13, -15, -9, -26, -46, -51, + -32, -18, -15, -4, 3, -17, -31, -28, -25, -20, -26, -48, -48, -27, -20, -13, + 19, 71, 61, 28, 33, 56, 50, 12, -8, -2, 5, -24, -41, 2, 52, 29, + -1, 24, 36, 26, 16, 14, 19, 6, -19, -12, 1, -21, -49, -50, -28, -12, + -3, 2, -2, -25, -32, -29, -24, -14, -31, -61, -44, -17, -15, -9, 28, 72, + 61, 25, 38, 61, 41, 7, -7, 4, 3, -32, -36, 9, 45, 21, 4, 30, + 33, 15, 11, 18, 17, -1, -18, -7, -4, -22, -47, -45, -24, -6, 2, 5, + -7, -27, -34, -28, -21, -14, -42, -69, -40, -11, -16, -3, 41, 68, 53, 29, + 48, 61, 32, 0, -5, 8, 2, -33, -28, 9, 31, 16, 16, 34, 22, 0, + 10, 24, 10, -9, -19, -6, -8, -26, -38, -34, -20, -10, 1, 11, -9, -33, + -31, -32, -25, -18, -50, -65, -40, -15, -8, 13, 47, 65, 50, 33, 54, 62, + 24, -2, 2, 12, -6, -31, -20, 12, 21, 10, 28, 34, 9, -5, 20, 20, + -2, -13, -10, -4, -18, -33, -26, -16, -19, -14, 6, 8, -14, -31, -32, -29, + -29, -31, -51, -69, -47, -12, 2, 21, 49, 56, 43, 45, 62, 54, 16, -2, + 7, 9, -13, -22, -4, 12, 7, 13, 37, 33, 7, -4, 23, 9, -8, -8, + -2, -8, -33, -38, -7, -1, -22, -19, 11, 7, -21, -29, -29, -29, -31, -32, + -55, -80, -49, -7, 16, 31, 43, 45, 44, 56, 66, 45, 12, 2, 10, 3, + -18, -13, 7, 9, -2, 17, 38, 22, 1, 5, 17, 4, -14, -12, -1, -11, + -43, -38, 6, 5, -22, -15, 12, 0, -23, -26, -28, -31, -32, -36, -60, -82, + -46, 3, 24, 35, 38, 41, 46, 59, 62, 41, 13, -1, 3, -6, -18, 3, + 22, 2, -9, 20, 36, 18, 10, 7, 4, -5, -17, -9, -2, -18, -55, -30, + 17, 6, -20, -10, 6, -5, -16, -26, -32, -27, -30, -42, -69, -84, -41, 13, + 31, 42, 37, 38, 45, 63, 65, 41, 12, 3, 1, -18, -10, 23, 27, -2, + -12, 17, 36, 26, 13, 4, -2, -5, -14, -14, -11, -26, -54, -19, 21, 8, + -16, -8, 6, -7, -20, -30, -33, -24, -33, -50, -74, -82, -32, 18, 34, 42, + 38, 34, 50, 69, 58, 34, 16, 7, -9, -29, -2, 41, 32, -7, -15, 11, + 34, 30, 9, 2, -3, -7, -23, -21, -15, -30, -52, -10, 18, 10, -8, -4, + 5, -4, -25, -33, -26, -22, -42, -59, -79, -72, -20, 23, 36, 41, 37, 34, + 54, 74, 53, 22, 17, 15, -17, -34, 10, 52, 37, -8, -11, 12, 33, 23, + 8, 4, -1, -16, -31, -25, -18, -38, -49, -3, 19, 11, -4, 0, 7, -8, + -34, -31, -19, -26, -52, -62, -79, -55, -7, 23, 41, 47, 41, 33, 61, 75, + 43, 22, 21, 13, -26, -33, 17, 58, 39, -6, -8, 13, 27, 10, 5, 13, + -2, -32, -43, -32, -19, -38, -36, -3, 12, 4, 4, 13, 6, -22, -41, -31, + -13, -33, -59, -71, -76, -35, 2, 20, 39, 53, 47, 39, 60, 62, 37, 26, + 22, 5, -33, -29, 26, 64, 40, 0, -5, 12, 21, 8, 16, 10, -13, -39, + -49, -37, -25, -41, -30, -6, 9, 9, 13, 23, 0, -30, -44, -26, -13, -45, + -67, -76, -68, -20, 10, 19, 39, 55, 50, 46, 57, 50, 37, 30, 16, -3, + -34, -22, 34, 65, 40, 13, -2, 6, 19, 12, 21, 5, -23, -49, -52, -38, + -33, -36, -24, -9, 10, 12, 25, 23, -11, -29, -43, -27, -21, -55, -73, -77, + -50, -2, 19, 19, 35, 59, 59, 49, 45, 40, 36, 27, 4, -10, -24, -12, + 31, 59, 44, 22, -5, 4, 19, 20, 12, -4, -27, -52, -50, -45, -39, -24, + -23, -13, 16, 20, 30, 15, -16, -28, -37, -30, -36, -64, -79, -73, -28, 17, + 24, 14, 36, 65, 68, 45, 33, 39, 40, 22, -2, -5, -11, -11, 28, 58, + 57, 20, -13, 0, 27, 23, 1, -15, -35, -58, -55, -52, -39, -20, -22, -9, + 20, 29, 30, 10, -15, -31, -39, -32, -48, -72, -86, -59, -4, 27, 19, 17, + 44, 77, 69, 31, 26, 40, 38, 14, -6, 0, 1, -11, 26, 67, 62, 10, + -18, 6, 31, 20, -5, -22, -44, -66, -61, -50, -31, -17, -24, -7, 24, 34, + 31, 3, -17, -31, -36, -40, -61, -73, -76, -46, 11, 34, 20, 22, 56, 83, + 60, 22, 24, 46, 32, 5, -4, 9, 0, -8, 31, 73, 53, 0, -13, 16, + 28, 14, -15, -31, -51, -74, -64, -43, -25, -22, -25, -1, 30, 37, 20, -2, + -20, -36, -39, -55, -69, -75, -69, -32, 21, 36, 22, 31, 63, 76, 50, 22, + 25, 49, 29, 3, 4, 9, 2, 0, 43, 74, 37, -8, -1, 28, 24, 8, + -22, -42, -65, -80, -60, -31, -25, -31, -24, 8, 41, 37, 10, -3, -22, -40, + -45, -60, -69, -69, -55, -15, 32, 37, 25, 42, 72, 70, 37, 21, 32, 41, + 20, 5, 15, 8, 0, 9, 46, 62, 26, -7, 8, 28, 21, 4, -29, -53, + -79, -82, -57, -25, -27, -32, -21, 14, 48, 35, -1, -7, -24, -44, -52, -70, + -69, -60, -38, 1, 34, 33, 32, 57, 70, 58, 34, 26, 31, 31, 16, 14, + 14, 3, 8, 25, 47, 47, 18, -2, 13, 25, 19, -2, -33, -64, -87, -83, + -53, -24, -29, -32, -17, 21, 46, 27, -4, -12, -30, -51, -61, -73, -60, -46, + -17, 9, 25, 32, 47, 69, 61, 48, 41, 30, 26, 24, 18, 24, 15, 2, + 14, 37, 42, 34, 17, 9, 19, 20, 11, -7, -35, -79, -97, -79, -45, -21, + -29, -33, -12, 26, 43, 27, -3, -15, -43, -58, -66, -69, -52, -37, -2, 16, + 24, 38, 61, 72, 56, 43, 41, 32, 28, 22, 22, 26, 12, 1, 23, 45, + 34, 21, 8, 17, 22, 19, 4, -18, -47, -93, -97, -70, -40, -29, -33, -22, + -5, 24, 44, 19, -6, -23, -53, -60, -74, -63, -41, -20, 10, 18, 19, 40, + 70, 70, 47, 41, 43, 37, 27, 14, 24, 32, 10, 1, 29, 44, 27, 12, + 7, 28, 32, 9, -11, -27, -56, -100, -94, -64, -43, -38, -31, -7, 0, 27, + 41, 11, -7, -35, -60, -62, -75, -54, -29, -5, 17, 22, 14, 46, 80, 72, + 46, 42, 44, 42, 24, 16, 31, 32, 9, 4, 33, 45, 22, 5, 8, 41, + 34, 0, -22, -36, -69, -100, -92, -65, -40, -44, -25, 0, 5, 28, 36, 4, + -12, -50, -64, -64, -68, -46, -19, 2, 25, 28, 19, 44, 72, 67, 46, 45, + 44, 39, 21, 21, 38, 29, 1, 9, 39, 39, 13, -4, 9, 54, 41, -11, + -38, -51, -76, -91, -92, -65, -44, -47, -17, 12, 11, 21, 27, 6, -24, -59, + -65, -67, -61, -40, -17, 8, 31, 26, 20, 49, 74, 65, 45, 48, 47, 36, + 25, 28, 36, 25, 5, 19, 42, 28, 6, -2, 21, 56, 27, -22, -45, -62, + -83, -92, -84, -65, -49, -37, -8, 15, 16, 22, 23, -1, -38, -65, -66, -65, + -51, -35, -15, 20, 42, 26, 25, 51, 70, 60, 45, 52, 47, 25, 25, 39, + 33, 24, 16, 31, 37, 14, 3, 2, 33, 55, 14, -35, -55, -67, -84, -88, + -84, -68, -47, -28, -1, 17, 22, 24, 17, -14, -54, -66, -64, -61, -46, -32, + -10, 26, 45, 24, 29, 52, 66, 57, 49, 56, 41, 16, 29, 46, 31, 22, + 24, 37, 30, 12, -1, 5, 40, 39, 1, -41, -63, -72, -89, -89, -77, -62, + -48, -17, 5, 13, 26, 31, 10, -29, -62, -64, -65, -54, -41, -25, -4, 32, + 52, 29, 32, 55, 61, 55, 56, 57, 35, 17, 33, 40, 28, 27, 37, 36, + 26, 14, -3, 13, 41, 22, -13, -45, -65, -78, -90, -87, -70, -56, -47, -12, + 9, 18, 35, 27, -5, -41, -63, -61, -65, -52, -37, -17, 5, 35, 52, 34, + 38, 55, 58, 53, 60, 54, 31, 21, 33, 34, 30, 35, 40, 32, 29, 15, + -4, 18, 30, 11, -25, -53, -69, -85, -91, -82, -66, -54, -36, -7, 6, 20, + 40, 19, -17, -52, -63, -60, -65, -50, -32, -11, 9, 34, 50, 40, 46, 51, + 56, 60, 60, 50, 28, 23, 33, 33, 31, 40, 43, 38, 38, 13, -6, 13, + 19, -2, -34, -57, -78, -91, -85, -73, -63, -55, -28, -1, 6, 26, 39, 13, + -28, -56, -61, -55, -61, -43, -27, -13, 12, 38, 48, 49, 54, 46, 52, 64, + 64, 48, 27, 22, 28, 33, 36, 44, 42, 39, 44, 15, -3, 10, 6, -19, + -46, -60, -81, -92, -83, -73, -52, -44, -22, -5, 5, 38, 37, -6, -41, -55, + -54, -49, -53, -45, -28, -9, 19, 41, 47, 56, 57, 41, 56, 69, 64, 42, + 26, 23, 27, 36, 39, 44, 39, 48, 53, 12, -4, 2, -8, -33, -61, -72, + -84, -87, -80, -73, -49, -36, -12, -5, 9, 42, 24, -15, -44, -50, -51, -51, + -51, -45, -26, -4, 20, 40, 47, 64, 58, 38, 61, 71, 55, 37, 32, 23, + 30, 34, 39, 50, 43, 58, 53, 9, 4, -3, -27, -49, -71, -79, -79, -79, + -82, -70, -44, -26, -7, -5, 16, 36, 9, -18, -40, -47, -49, -45, -42, -43, + -20, 1, 21, 40, 53, 72, 54, 36, 64, 66, 41, 30, 36, 26, 28, 31, + 44, 57, 48, 62, 45, 13, 3, -14, -47, -65, -77, -87, -78, -71, -75, -68, + -43, -16, -2, -1, 18, 20, -4, -18, -37, -46, -50, -36, -39, -46, -15, 7, + 23, 41, 62, 72, 49, 41, 69, 59, 33, 29, 38, 24, 28, 31, 52, 59, + 49, 61, 45, 21, 2, -31, -64, -73, -78, -89, -79, -71, -77, -62, -36, -8, + 3, 5, 15, 5, -10, -17, -34, -49, -50, -27, -37, -43, -12, 14, 25, 45, + 67, 68, 48, 48, 64, 48, 27, 33, 41, 25, 24, 32, 64, 66, 51, 62, + 41, 21, -7, -43, -77, -81, -83, -87, -74, -71, -77, -54, -29, -1, 7, 13, + 12, -6, -9, -18, -38, -54, -44, -21, -37, -41, -8, 16, 28, 53, 73, 61, + 46, 52, 60, 35, 25, 34, 38, 20, 25, 42, 73, 62, 60, 58, 39, 22, + -19, -54, -85, -88, -95, -88, -65, -69, -73, -47, -22, 3, 14, 15, -5, -14, + -6, -23, -42, -52, -34, -19, -42, -38, 0, 18, 30, 62, 76, 61, 49, 52, + 49, 26, 23, 34, 33, 22, 21, 50, 78, 68, 66, 47, 40, 22, -23, -66, + -95, -102, -97, -74, -61, -77, -68, -36, -12, 9, 15, 13, -18, -14, -5, -31, + -50, -44, -21, -25, -49, -25, 8, 16, 30, 70, 82, 56, 45, 55, 39, 21, + 25, 31, 24, 21, 28, 64, 81, 68, 64, 47, 44, 15, -30, -77, -101, -104, + -96, -71, -66, -76, -53, -22, -9, 6, 22, 10, -22, -15, -13, -38, -48, -32, + -9, -33, -49, -14, 10, 11, 37, 77, 85, 51, 44, 48, 30, 18, 21, 26, + 16, 21, 36, 71, 76, 73, 68, 48, 35, 4, -38, -81, -103, -109, -91, -67, + -71, -69, -40, -15, -12, 3, 23, 7, -23, -17, -24, -41, -45, -24, -11, -46, + -46, -1, 10, 8, 49, 84, 83, 48, 50, 48, 27, 16, 18, 20, 14, 26, + 44, 72, 75, 82, 71, 47, 26, -6, -45, -80, -107, -110, -88, -70, -69, -58, + -28, -9, -12, 2, 23, 2, -21, -19, -35, -38, -33, -13, -17, -50, -35, 8, + 9, 10, 57, 89, 74, 45, 52, 41, 24, 15, 11, 14, 13, 22, 54, 72, + 74, 86, 72, 41, 13, -14, -47, -86, -113, -111, -88, -72, -67, -42, -18, -11, + -11, 2, 18, -2, -17, -27, -44, -37, -28, -12, -26, -49, -22, 9, 3, 21, + 69, 87, 63, 46, 49, 36, 24, 13, 11, 11, 8, 26, 64, 68, 76, 89, + 74, 38, 3, -17, -44, -86, -117, -114, -86, -65, -58, -38, -19, -7, 0, 8, + 9, -5, -20, -37, -45, -29, -19, -15, -36, -39, -10, 6, 4, 33, 79, 81, + 55, 48, 42, 30, 23, 10, 13, 10, 3, 27, 62, 60, 76, 88, 68, 30, + -5, -21, -49, -89, -120, -115, -81, -54, -46, -34, -14, -1, 7, 9, 1, -6, + -18, -45, -52, -29, -16, -17, -35, -36, -12, 5, 11, 47, 81, 72, 53, 51, + 39, 28, 24, 9, 13, 7, 5, 36, 57, 55, 82, 90, 62, 31, -10, -29, + -55, -91, -121, -115, -76, -47, -38, -34, -13, 1, 13, 9, -4, -9, -17, -49, + -56, -26, -9, -12, -33, -40, -17, 12, 25, 57, 71, 62, 52, 50, 35, 22, + 21, 14, 11, -2, 10, 41, 50, 48, 85, 87, 66, 29, -15, -34, -64, -97, + -121, -108, -73, -43, -37, -28, -7, 7, 16, 6, -7, -5, -15, -59, -56, -19, + -4, -14, -37, -42, -10, 21, 38, 66, 63, 57, 52, 49, 28, 22, 28, 16, + 5, -3, 22, 47, 38, 45, 79, 85, 68, 23, -16, -34, -70, -100, -122, -107, + -62, -39, -38, -25, -4, 15, 18, 2, -3, 0, -27, -70, -51, -17, -3, -16, + -44, -40, -1, 27, 45, 67, 57, 54, 48, 39, 17, 18, 28, 17, 3, -3, + 27, 49, 37, 42, 69, 86, 66, 16, -17, -37, -72, -99, -117, -101, -55, -39, + -36, -24, 1, 20, 13, 4, 4, -5, -46, -74, -43, -9, -4, -28, -49, -33, + 6, 33, 63, 68, 54, 53, 49, 33, 18, 21, 24, 15, 7, 9, 33, 42, + 35, 39, 70, 85, 55, 10, -16, -40, -75, -98, -113, -92, -47, -38, -35, -21, + 1, 21, 15, 8, 7, -14, -62, -70, -30, -11, -15, -34, -49, -23, 9, 39, + 64, 58, 51, 56, 42, 20, 16, 19, 16, 16, 4, 13, 40, 46, 33, 31, + 65, 83, 49, 3, -24, -41, -73, -98, -105, -77, -45, -41, -30, -13, 7, 19, + 12, 13, 8, -26, -68, -61, -22, -14, -25, -38, -40, -18, 12, 47, 68, 59, + 49, 51, 42, 19, 17, 17, 12, 13, 5, 18, 41, 47, 26, 26, 67, 78, + 44, -2, -31, -47, -71, -97, -96, -67, -44, -42, -29, -11, 13, 21, 13, 17, + 8, -34, -68, -54, -17, -18, -36, -43, -35, -12, 14, 50, 69, 56, 49, 44, + 35, 16, 13, 17, 13, 13, 6, 27, 46, 50, 24, 28, 66, 64, 28, 0, + -25, -49, -75, -99, -87, -54, -42, -38, -28, -8, 20, 19, 11, 17, 1, -41, + -62, -49, -18, -27, -41, -39, -29, -8, 15, 55, 73, 55, 42, 42, 33, 16, + 12, 12, 9, 6, 14, 40, 52, 48, 21, 31, 60, 50, 23, 0, -32, -60, + -76, -90, -73, -44, -39, -36, -32, 1, 29, 20, 6, 13, -3, -41, -53, -43, + -21, -34, -47, -38, -22, -2, 22, 54, 65, 49, 38, 42, 32, 17, 12, 7, + 6, 3, 21, 48, 53, 42, 24, 39, 53, 38, 15, -3, -38, -65, -76, -85, + -59, -36, -35, -40, -26, 15, 26, 12, 6, 10, -12, -40, -49, -33, -26, -41, + -53, -36, -12, 5, 28, 50, 61, 46, 34, 37, 31, 20, 12, 1, 0, 5, + 32, 53, 56, 41, 23, 39, 48, 35, 13, -10, -44, -72, -81, -79, -50, -27, + -34, -41, -18, 20, 27, 12, 5, 1, -19, -36, -40, -22, -34, -50, -55, -33, + -3, 14, 33, 52, 54, 35, 27, 36, 37, 25, 7, -13, 1, 19, 41, 50, + 50, 38, 32, 43, 41, 32, 6, -17, -46, -69, -79, -75, -43, -20, -34, -38, + -8, 23, 26, 12, 6, -8, -23, -30, -30, -23, -46, -56, -52, -29, 6, 23, + 35, 44, 47, 31, 25, 33, 40, 26, -4, -22, 3, 28, 39, 40, 50, 40, + 28, 34, 37, 28, 0, -22, -50, -70, -81, -72, -34, -22, -36, -33, 2, 24, + 25, 12, 4, -15, -24, -26, -25, -23, -46, -56, -50, -24, 10, 33, 36, 40, + 35, 21, 25, 43, 47, 25, -13, -25, 11, 40, 36, 40, 56, 38, 27, 31, + 33, 24, -4, -24, -53, -71, -80, -59, -34, -27, -31, -27, 8, 24, 25, 17, + 2, -22, -25, -26, -19, -24, -51, -58, -40, -9, 14, 37, 36, 35, 27, 14, + 28, 48, 46, 19, -19, -24, 18, 40, 29, 41, 50, 29, 29, 27, 33, 18, + -12, -29, -53, -71, -75, -48, -33, -32, -25, -14, 13, 24, 19, 17, 2, -25, + -28, -28, -18, -28, -55, -59, -30, -3, 20, 41, 34, 24, 15, 15, 36, 49, + 39, 17, -17, -17, 22, 41, 33, 45, 38, 26, 30, 24, 27, 10, -11, -34, + -58, -70, -66, -38, -32, -36, -21, -2, 14, 28, 19, 14, 0, -25, -29, -28, + -17, -30, -57, -51, -22, 3, 23, 39, 34, 15, 11, 17, 38, 46, 39, 15, + -18, -14, 27, 40, 37, 45, 32, 28, 30, 29, 28, 1, -16, -38, -55, -65, + -62, -37, -31, -34, -17, 9, 18, 27, 18, 9, -1, -22, -35, -29, -17, -32, + -57, -45, -17, 15, 30, 30, 25, 8, 10, 19, 35, 46, 37, 4, -19, -8, + 31, 33, 33, 42, 28, 22, 24, 29, 23, -6, -21, -43, -54, -59, -55, -32, + -34, -39, -10, 19, 30, 25, 9, 2, -2, -20, -38, -30, -23, -41, -51, -35, + -12, 24, 32, 22, 12, 8, 16, 23, 32, 48, 33, 1, -16, 0, 29, 30, + 33, 36, 24, 23, 22, 33, 14, -14, -20, -42, -55, -50, -44, -27, -38, -41, + -3, 31, 35, 23, 5, -2, -4, -15, -34, -33, -38, -47, -40, -26, -3, 31, + 31, 9, 2, 13, 14, 20, 38, 53, 27, -6, -14, 11, 30, 23, 32, 28, + 25, 22, 24, 32, 5, -20, -26, -45, -49, -40, -36, -37, -48, -40, 8, 40, + 37, 16, -3, -6, -2, -9, -27, -42, -52, -48, -32, -21, 8, 39, 28, -2, + -5, 13, 17, 23, 40, 45, 19, -4, -3, 18, 15, 19, 33, 30, 29, 22, + 21, 22, 0, -17, -27, -46, -48, -33, -31, -38, -53, -33, 23, 43, 31, 11, + -7, -5, -3, -8, -26, -49, -59, -48, -25, -14, 15, 41, 23, -8, -6, 11, + 10, 26, 49, 41, 12, 0, 10, 19, 4, 22, 31, 25, 25, 24, 20, 12, + -4, -10, -37, -50, -37, -23, -26, -43, -55, -18, 34, 41, 28, 10, -9, -6, + -3, -8, -27, -57, -62, -37, -15, -8, 24, 44, 23, -10, -6, 3, 8, 39, + 55, 30, 12, 11, 20, 8, 3, 27, 26, 20, 21, 24, 19, -1, -10, -14, + -42, -47, -25, -14, -28, -49, -50, -5, 38, 38, 23, 9, -11, -9, -1, -5, + -33, -64, -59, -34, -14, -2, 32, 49, 17, -11, -6, -2, 11, 46, 46, 19, + 16, 23, 24, -3, 3, 29, 29, 16, 17, 22, 11, -12, -12, -18, -50, -43, + -15, -11, -30, -53, -38, 10, 31, 31, 25, 3, -16, -3, 3, -8, -41, -67, + -53, -24, -14, 3, 35, 46, 17, -2, -7, -9, 16, 49, 41, 20, 22, 34, + 21, -5, 5, 31, 29, 12, 14, 18, 8, -22, -17, -20, -52, -38, -13, -19, + -32, -48, -25, 11, 23, 29, 26, 1, -14, 1, 1, -18, -47, -60, -47, -31, + -11, 13, 45, 39, 8, -2, -2, -11, 16, 43, 35, 25, 34, 40, 18, -7, + 6, 34, 28, 14, 7, 11, 2, -23, -25, -29, -51, -30, -11, -24, -38, -40, + -15, 9, 18, 29, 32, -1, -10, 0, -9, -27, -48, -52, -46, -30, -2, 27, + 47, 30, 10, 7, -6, -15, 12, 35, 28, 30, 45, 42, 19, -4, 11, 29, + 21, 6, 1, 3, -3, -27, -31, -34, -40, -22, -18, -31, -35, -30, -18, 5, + 19, 32, 28, -9, -7, 1, -14, -30, -42, -45, -47, -28, 7, 38, 45, 23, + 14, 20, -2, -24, 7, 32, 30, 37, 43, 41, 22, 7, 18, 22, 14, 4, + -7, 4, -7, -36, -37, -37, -27, -15, -26, -34, -34, -29, -18, 4, 19, 31, + 20, -4, 0, -3, -21, -32, -37, -41, -40, -25, 14, 49, 44, 18, 19, 25, + -1, -19, 5, 26, 35, 38, 46, 41, 18, 18, 16, 13, 12, 2, -5, -3, + -23, -44, -37, -32, -20, -20, -33, -28, -32, -32, -16, 1, 17, 31, 17, -2, + 2, -3, -22, -33, -39, -40, -34, -23, 15, 56, 44, 15, 27, 23, -4, -14, + 2, 22, 38, 37, 48, 40, 25, 24, 15, 11, 2, -2, -3, -15, -31, -40, + -37, -33, -17, -17, -28, -29, -41, -34, -7, 1, 13, 31, 17, -2, 4, 1, + -20, -35, -47, -37, -24, -10, 22, 52, 38, 26, 35, 26, -2, -9, 4, 23, + 40, 38, 46, 39, 32, 31, 16, 2, -7, -8, -2, -21, -38, -44, -38, -31, + -18, -15, -29, -35, -45, -32, -1, -3, 4, 30, 16, 3, 8, 4, -20, -42, + -48, -30, -17, -8, 21, 49, 41, 30, 38, 23, -2, -5, 1, 21, 35, 37, + 44, 40, 40, 33, 17, 1, -13, -10, -9, -35, -41, -41, -39, -33, -19, -12, + -27, -40, -48, -28, -4, -10, 10, 28, 15, 9, 12, 5, -24, -43, -43, -23, + -18, 0, 26, 47, 43, 35, 40, 20, -1, 1, 4, 20, 28, 37, 42, 42, + 46, 31, 22, 8, -17, -15, -15, -42, -41, -37, -44, -37, -16, -13, -33, -41, + -41, -20, -11, -17, 10, 18, 13, 16, 17, 1, -24, -38, -38, -27, -21, 9, + 29, 46, 44, 43, 38, 18, 3, 6, 6, 12, 19, 38, 41, 47, 44, 28, + 29, 11, -26, -25, -27, -45, -39, -39, -48, -41, -18, -13, -33, -38, -36, -21, + -19, -14, 13, 11, 11, 26, 17, -6, -25, -32, -32, -35, -14, 21, 31, 38, + 49, 49, 34, 19, 13, 10, 4, 9, 20, 37, 41, 45, 39, 29, 35, 6, + -28, -28, -35, -43, -37, -42, -50, -44, -20, -20, -37, -37, -27, -16, -23, -11, + 10, 5, 17, 36, 16, -16, -23, -21, -33, -38, -5, 23, 28, 35, 55, 55, + 31, 17, 18, 12, 3, 4, 21, 33, 41, 45, 31, 32, 39, 3, -29, -35, + -41, -40, -38, -45, -55, -45, -26, -31, -36, -26, -22, -22, -29, 1, 9, -1, + 24, 39, 8, -19, -17, -14, -32, -34, 5, 29, 29, 35, 58, 51, 32, 29, + 23, 11, 1, 6, 29, 37, 38, 36, 24, 43, 39, -2, -32, -44, -45, -36, + -36, -45, -55, -51, -37, -35, -30, -22, -20, -32, -24, 6, 2, 3, 30, 36, + 3, -17, -16, -18, -29, -24, 10, 31, 25, 34, 58, 44, 33, 37, 26, 8, + 5, 10, 37, 36, 35, 29, 22, 47, 36, -6, -36, -51, -49, -34, -38, -48, + -58, -53, -46, -42, -24, -23, -22, -32, -13, 4, -7, 8, 35, 30, 6, -14, + -20, -19, -21, -20, 14, 34, 29, 43, 52, 37, 39, 43, 24, 8, 7, 15, + 45, 33, 36, 24, 25, 43, 25, -10, -39, -53, -47, -34, -39, -53, -56, -54, + -56, -42, -21, -23, -29, -25, -5, 1, -10, 12, 35, 27, 7, -14, -25, -19, + -11, -10, 13, 31, 37, 44, 42, 37, 45, 44, 24, 14, 13, 24, 40, 28, + 35, 23, 31, 35, 15, -16, -38, -53, -45, -37, -48, -56, -54, -63, -63, -40, + -23, -24, -27, -19, 3, 1, -11, 14, 33, 24, 5, -16, -28, -17, -6, -1, + 15, 38, 39, 38, 29, 36, 54, 42, 20, 20, 19, 32, 38, 30, 31, 23, + 33, 23, -1, -17, -35, -44, -43, -47, -51, -51, -56, -71, -67, -45, -28, -23, + -23, -13, 12, -1, -15, 15, 33, 20, -2, -22, -25, -17, -3, 10, 24, 46, + 44, 31, 26, 41, 53, 42, 23, 23, 26, 39, 37, 32, 24, 28, 36, 11, + -7, -19, -38, -39, -37, -49, -54, -51, -62, -76, -68, -51, -28, -19, -21, 1, + 22, -3, -11, 14, 25, 16, -5, -25, -25, -15, -2, 20, 36, 51, 42, 19, + 19, 43, 58, 43, 25, 21, 35, 46, 41, 34, 17, 26, 33, 5, -15, -25, + -39, -34, -37, -55, -50, -49, -69, -80, -67, -50, -31, -18, -12, 12, 17, -5, + -5, 14, 17, 6, -15, -27, -22, -14, 3, 37, 49, 48, 40, 22, 22, 36, + 51, 44, 29, 22, 42, 49, 41, 29, 16, 29, 31, -9, -30, -33, -35, -29, + -38, -55, -45, -54, -79, -80, -65, -51, -34, -16, -2, 18, 18, 5, 7, 8, + 6, 3, -19, -21, -22, -19, 12, 51, 53, 48, 39, 22, 18, 36, 46, 42, + 35, 31, 44, 46, 42, 31, 24, 35, 21, -25, -39, -33, -30, -24, -41, -53, + -47, -60, -81, -81, -63, -53, -40, -14, 6, 24, 20, 8, 7, 0, -1, -4, + -21, -23, -29, -16, 30, 60, 55, 50, 37, 19, 19, 35, 43, 46, 37, 29, + 43, 49, 43, 32, 27, 31, 13, -35, -46, -36, -26, -28, -44, -52, -47, -65, + -84, -84, -68, -49, -27, 0, 10, 15, 19, 15, 9, -3, -10, -16, -20, -26, + -28, -2, 41, 59, 62, 56, 37, 16, 15, 31, 43, 50, 42, 30, 41, 49, + 49, 38, 28, 23, 5, -42, -55, -42, -21, -22, -40, -49, -54, -71, -86, -81, + -62, -44, -21, 5, 17, 16, 25, 23, 0, -13, -17, -17, -24, -32, -21, 15, + 45, 58, 66, 52, 33, 15, 9, 35, 42, 44, 44, 36, 38, 50, 52, 40, + 28, 16, -11, -48, -60, -43, -22, -21, -40, -53, -58, -78, -90, -79, -61, -42, + -9, 14, 15, 16, 22, 21, -4, -20, -21, -19, -30, -31, -10, 26, 54, 63, + 69, 51, 33, 12, 13, 40, 42, 45, 42, 33, 36, 53, 57, 44, 24, 3, + -24, -53, -63, -45, -21, -15, -39, -57, -63, -78, -89, -76, -55, -34, 3, 18, + 9, 16, 21, 15, -8, -26, -28, -25, -32, -24, 4, 34, 56, 67, 75, 48, + 22, 7, 23, 44, 39, 40, 40, 35, 40, 59, 59, 44, 18, -6, -31, -54, + -58, -44, -20, -13, -43, -63, -69, -80, -88, -71, -48, -21, 12, 16, 12, 18, + 13, 6, -12, -27, -32, -30, -34, -20, 13, 46, 63, 74, 73, 40, 15, 13, + 39, 46, 33, 32, 35, 36, 48, 58, 61, 43, 16, -13, -36, -57, -62, -41, + -22, -16, -42, -66, -73, -79, -85, -65, -38, -7, 13, 9, 7, 16, 11, -2, + -18, -36, -39, -26, -25, -16, 21, 53, 64, 74, 68, 36, 19, 22, 38, 44, + 32, 28, 32, 38, 52, 60, 56, 43, 13, -25, -39, -54, -52, -35, -30, -27, + -46, -70, -79, -80, -79, -58, -26, 3, 15, 6, 0, 12, 6, -8, -27, -45, + -39, -17, -16, -13, 28, 57, 67, 71, 57, 37, 22, 25, 41, 46, 29, 24, + 34, 44, 56, 55, 52, 44, 7, -27, -38, -48, -44, -35, -31, -29, -46, -77, + -83, -73, -70, -48, -15, 6, 9, 1, 1, 9, -3, -20, -41, -48, -30, -5, + -14, -9, 39, 63, 70, 66, 47, 36, 25, 32, 40, 43, 26, 21, 36, 47, + 59, 50, 49, 35, 0, -26, -36, -44, -41, -36, -35, -33, -50, -79, -79, -66, + -63, -36, -8, 6, -3, -9, 2, 3, -13, -30, -49, -46, -18, -2, -15, 4, + 42, 58, 65, 61, 50, 38, 28, 37, 40, 38, 28, 30, 38, 48, 50, 42, + 46, 28, -3, -28, -37, -36, -36, -39, -36, -37, -59, -79, -69, -62, -52, -24, + -2, 3, -12, -11, 4, -5, -29, -42, -53, -39, -12, -4, -4, 14, 37, 52, + 63, 58, 50, 37, 34, 37, 36, 37, 38, 36, 35, 47, 46, 44, 42, 18, + -7, -30, -34, -32, -34, -41, -37, -45, -66, -74, -64, -57, -36, -12, 1, -8, + -23, -7, 6, -18, -39, -49, -53, -29, -5, -1, 10, 19, 30, 46, 59, 58, + 50, 36, 37, 37, 32, 40, 46, 38, 34, 44, 42, 41, 36, 9, -9, -27, + -29, -26, -34, -40, -40, -56, -69, -66, -56, -46, -22, -7, -7, -19, -21, 3, + 1, -35, -48, -53, -49, -22, -3, 12, 23, 18, 22, 46, 66, 59, 47, 38, + 43, 35, 30, 46, 51, 39, 33, 41, 37, 42, 24, 2, -8, -22, -23, -24, + -33, -39, -50, -66, -69, -59, -49, -31, -13, -10, -17, -25, -16, 1, -17, -50, + -55, -58, -42, -17, -1, 20, 31, 14, 15, 48, 70, 59, 42, 38, 45, 33, + 33, 51, 53, 36, 35, 37, 36, 37, 12, 0, -9, -16, -18, -22, -33, -42, + -59, -67, -62, -52, -40, -20, -11, -15, -23, -23, -11, -3, -28, -51, -59, -61, + -38, -14, 4, 26, 30, 10, 18, 53, 71, 56, 40, 42, 45, 32, 34, 53, + 52, 37, 36, 32, 37, 32, 10, -3, -10, -10, -11, -17, -31, -46, -62, -63, + -54, -44, -30, -14, -14, -23, -27, -22, -11, -11, -35, -51, -65, -59, -32, -11, + 11, 29, 25, 8, 24, 63, 73, 51, 38, 46, 44, 29, 34, 51, 51, 39, + 34, 27, 34, 23, 3, -5, -9, -6, -10, -18, -33, -51, -66, -60, -50, -35, + -20, -10, -21, -33, -29, -17, -9, -20, -39, -55, -71, -57, -26, -7, 11, 23, + 22, 11, 35, 70, 71, 46, 39, 48, 42, 29, 33, 51, 47, 38, 31, 28, + 35, 17, 0, -12, -7, 0, -4, -15, -36, -56, -67, -56, -42, -26, -15, -12, + -29, -36, -28, -15, -13, -25, -40, -58, -70, -49, -23, -6, 8, 19, 17, 18, + 49, 76, 66, 40, 42, 49, 39, 25, 35, 51, 43, 40, 30, 31, 32, 15, + -1, -14, -7, 1, -2, -17, -40, -59, -61, -51, -38, -21, -10, -17, -34, -35, + -28, -18, -17, -24, -40, -64, -65, -40, -18, -8, 5, 13, 17, 31, 61, 75, + 60, 41, 43, 47, 34, 20, 36, 47, 43, 41, 31, 32, 26, 7, -7, -16, + -6, 0, -3, -22, -44, -60, -56, -47, -34, -19, -8, -20, -39, -40, -27, -18, + -20, -29, -44, -63, -56, -38, -23, -11, 4, 14, 21, 42, 65, 71, 59, 45, + 42, 34, 21, 20, 42, 48, 44, 41, 31, 34, 24, 6, -10, -20, -11, 4, + 0, -20, -48, -57, -47, -39, -30, -17, -4, -24, -43, -40, -26, -19, -24, -29, + -45, -59, -51, -37, -25, -14, 3, 15, 27, 51, 72, 76, 61, 44, 38, 23, + 12, 21, 43, 46, 45, 40, 31, 35, 21, 5, -17, -22, -13, 3, 1, -24, + -51, -52, -43, -37, -28, -8, -7, -38, -46, -36, -21, -21, -31, -33, -45, -51, + -47, -40, -30, -13, 4, 14, 33, 60, 76, 76, 61, 47, 30, 16, 8, 20, + 40, 45, 48, 37, 37, 37, 22, 3, -19, -20, -10, 4, -6, -30, -49, -44, + -41, -38, -23, -1, -14, -41, -44, -36, -22, -26, -35, -33, -45, -52, -48, -40, + -32, -9, 6, 18, 35, 65, 85, 80, 62, 46, 24, 6, -1, 23, 41, 48, + 45, 31, 42, 40, 23, -6, -21, -15, -6, 0, -13, -31, -44, -41, -38, -32, + -15, 0, -22, -40, -41, -36, -24, -31, -28, -32, -46, -49, -47, -43, -30, -6, + 9, 19, 46, 77, 87, 77, 61, 42, 18, -2, -7, 22, 39, 51, 41, 32, + 43, 35, 13, -18, -18, -10, -5, -8, -21, -29, -39, -42, -41, -23, -3, -3, + -32, -39, -38, -34, -31, -35, -23, -32, -46, -50, -51, -46, -26, 0, 12, 20, + 54, 87, 91, 72, 60, 38, 13, -10, -11, 24, 44, 52, 43, 39, 45, 34, + 2, -19, -8, -1, -8, -19, -19, -25, -35, -42, -39, -17, 7, -7, -38, -36, + -36, -37, -37, -31, -20, -34, -49, -53, -50, -43, -19, 6, 10, 25, 66, 91, + 84, 67, 60, 36, 1, -18, -10, 27, 48, 52, 42, 42, 38, 25, -3, -18, + -5, -2, -13, -22, -24, -28, -35, -45, -35, -4, 14, -17, -41, -36, -33, -35, + -41, -29, -20, -38, -51, -54, -46, -33, -14, 6, 14, 37, 74, 87, 76, 65, + 64, 29, -9, -22, -7, 23, 52, 55, 46, 42, 25, 17, -5, -12, -4, -3, + -17, -25, -33, -36, -33, -39, -30, 5, 12, -25, -37, -33, -34, -42, -41, -25, + -22, -41, -52, -53, -40, -25, -10, 11, 21, 43, 72, 78, 74, 69, 58, 15, + -13, -15, -4, 22, 54, 58, 53, 41, 15, 6, -2, -1, -3, -6, -18, -24, + -42, -40, -29, -32, -20, 13, 8, -25, -35, -34, -29, -42, -43, -27, -27, -42, + -51, -50, -30, -14, -5, 17, 26, 46, 70, 72, 72, 69, 48, 2, -13, -9, + -3, 19, 55, 59, 53, 30, 1, -1, 5, 8, -7, -15, -19, -25, -48, -45, + -31, -28, -10, 15, 1, -24, -35, -35, -22, -37, -43, -36, -35, -41, -47, -45, + -18, -6, -1, 24, 32, 51, 65, 65, 67, 63, 37, -3, -13, -9, 1, 29, + 54, 60, 50, 18, -4, -4, 13, 9, -10, -15, -17, -30, -54, -47, -29, -20, + -8, 4, -8, -15, -29, -35, -21, -37, -43, -46, -37, -33, -48, -39, -10, 3, + 13, 31, 34, 54, 56, 57, 63, 56, 32, -3, -16, -6, 14, 38, 48, 53, + 40, 11, -3, 1, 6, -2, -11, -9, -11, -28, -54, -54, -29, -8, 2, -8, + -16, -13, -27, -31, -21, -32, -45, -54, -36, -27, -44, -33, 1, 16, 25, 29, + 39, 56, 48, 51, 57, 48, 22, 3, -14, 0, 22, 39, 42, 46, 36, 7, + -7, 0, 0, -3, -8, -8, -15, -34, -50, -49, -27, -3, 0, -15, -14, -16, + -28, -26, -21, -34, -56, -55, -32, -30, -41, -23, 8, 20, 31, 33, 45, 53, + 38, 42, 54, 40, 18, -3, -9, 14, 33, 37, 34, 34, 27, 8, -5, -1, + -9, -3, -1, -8, -19, -35, -43, -42, -28, -7, 1, -18, -13, -17, -29, -24, + -21, -34, -55, -52, -34, -30, -26, -9, 15, 28, 28, 32, 55, 50, 29, 38, + 45, 35, 17, -3, -1, 18, 36, 40, 27, 24, 19, 0, -5, -1, -14, -7, + -2, -12, -20, -30, -40, -42, -25, -5, -5, -24, -14, -16, -25, -20, -26, -38, + -52, -49, -35, -31, -13, 8, 16, 28, 29, 42, 57, 40, 23, 32, 35, 30, + 12, -5, 9, 22, 40, 38, 19, 17, 16, -1, -9, -7, -12, -6, -5, -13, + -18, -29, -39, -39, -18, -3, -19, -26, -11, -18, -24, -19, -30, -40, -51, -45, + -30, -24, 0, 19, 22, 28, 36, 49, 54, 41, 22, 30, 31, 26, 10, 2, + 10, 26, 43, 28, 14, 16, 7, -6, -12, -9, -9, -5, -12, -19, -16, -29, + -35, -34, -8, -8, -35, -20, -7, -26, -23, -23, -30, -39, -53, -38, -25, -12, + 11, 24, 24, 29, 47, 50, 48, 36, 20, 29, 24, 15, 5, 8, 12, 32, + 40, 21, 17, 11, 0, -3, -15, -14, -7, -4, -13, -17, -16, -28, -31, -23, + -6, -20, -37, -15, -12, -29, -22, -28, -30, -38, -54, -34, -20, -4, 21, 33, + 24, 33, 50, 45, 40, 33, 27, 28, 14, 8, 8, 11, 11, 30, 33, 26, + 20, -1, -8, -4, -17, -16, -2, -7, -22, -20, -20, -26, -26, -15, -10, -27, + -35, -12, -19, -31, -21, -23, -23, -42, -57, -31, -11, 9, 35, 33, 23, 39, + 53, 47, 40, 31, 31, 21, 10, 9, 11, 10, 13, 26, 35, 33, 13, -11, + -10, -4, -19, -22, 3, -2, -28, -26, -16, -21, -24, -12, -12, -31, -34, -17, + -27, -34, -25, -17, -19, -48, -59, -29, -2, 27, 46, 26, 22, 43, 54, 44, + 38, 30, 29, 16, 6, 15, 15, 6, 9, 22, 36, 37, 9, -20, -10, -5, + -21, -21, 2, -5, -29, -31, -18, -11, -17, -11, -15, -32, -34, -23, -30, -30, + -25, -15, -22, -52, -50, -17, 9, 36, 42, 26, 29, 50, 53, 40, 33, 32, + 27, 14, 7, 9, 7, 4, 12, 22, 36, 36, 3, -27, -16, -9, -20, -21, + -1, -12, -31, -27, -13, -12, -18, -12, -17, -33, -39, -29, -34, -35, -23, -7, + -25, -55, -42, -10, 20, 43, 40, 27, 33, 51, 51, 37, 34, 31, 21, 9, + 8, 5, 2, 11, 16, 18, 34, 35, 3, -22, -17, -16, -20, -17, -7, -20, + -32, -28, -14, -12, -10, -8, -17, -34, -41, -35, -34, -31, -19, -8, -27, -48, + -29, -4, 26, 50, 44, 32, 37, 50, 49, 40, 36, 22, 11, 11, 12, 5, + 3, 14, 12, 13, 34, 37, 9, -23, -24, -16, -21, -16, -17, -30, -27, -27, + -20, -10, -10, -9, -18, -39, -46, -42, -35, -31, -14, -9, -33, -42, -19, 1, + 36, 55, 41, 32, 46, 55, 47, 35, 32, 18, 6, 7, 9, -2, 7, 17, + 8, 13, 34, 32, 10, -22, -27, -14, -20, -21, -26, -31, -23, -27, -22, -6, + -5, -11, -21, -39, -46, -46, -37, -30, -14, -12, -33, -31, -8, 6, 41, 55, + 40, 38, 54, 57, 39, 30, 33, 17, 2, 1, 4, 7, 14, 14, -2, 11, + 37, 31, 11, -26, -30, -16, -20, -18, -21, -27, -32, -28, -12, 0, -4, -11, + -23, -40, -46, -43, -33, -26, -16, -15, -29, -19, -1, 13, 44, 58, 41, 49, + 68, 59, 36, 28, 36, 18, -9, -9, 4, 17, 20, 7, -6, 18, 36, 22, + -1, -30, -26, -19, -25, -26, -31, -35, -33, -21, -3, -8, -10, -14, -24, -40, + -45, -43, -35, -20, -18, -20, -22, -12, 0, 15, 48, 58, 41, 58, 77, 57, + 30, 27, 33, 7, -23, -16, 11, 23, 21, 2, -5, 24, 33, 10, -10, -24, + -19, -25, -37, -30, -30, -34, -29, -14, -5, -16, -8, -8, -26, -50, -47, -41, + -30, -16, -25, -24, -14, -6, 3, 23, 50, 51, 49, 69, 81, 56, 29, 33, + 30, -2, -29, -14, 15, 26, 18, 2, -1, 31, 28, 0, -20, -21, -21, -32, + -43, -34, -33, -36, -23, -4, -8, -20, -8, -11, -25, -44, -41, -39, -32, -17, + -30, -22, -4, 1, 6, 31, 48, 47, 63, 80, 82, 52, 31, 38, 23, -13, + -33, -11, 20, 29, 14, -1, 9, 34, 19, -12, -26, -13, -23, -46, -46, -38, + -39, -35, -24, -3, -7, -17, -15, -16, -25, -45, -37, -37, -33, -26, -36, -20, + 5, 3, 4, 32, 42, 50, 76, 83, 75, 49, 34, 36, 17, -24, -33, -12, + 23, 32, 10, 1, 23, 30, 7, -17, -22, -8, -27, -49, -50, -42, -38, -28, + -18, -3, -8, -13, -14, -15, -24, -43, -35, -33, -29, -27, -34, -15, 16, 8, + 5, 32, 43, 62, 84, 84, 73, 53, 40, 30, 6, -26, -34, -15, 25, 28, + 8, 9, 38, 27, -4, -26, -21, -12, -33, -54, -47, -48, -38, -21, -14, -2, + -3, -11, -25, -18, -26, -32, -34, -34, -29, -31, -35, -10, 18, 11, 7, 33, + 47, 68, 83, 81, 71, 58, 42, 20, -5, -25, -36, -15, 23, 23, 7, 20, + 40, 21, -14, -35, -21, -16, -40, -58, -52, -52, -31, -11, -9, -6, -1, -15, + -26, -15, -29, -31, -36, -31, -29, -36, -32, -4, 17, 8, 15, 36, 48, 66, + 77, 83, 77, 59, 38, 9, -11, -20, -34, -12, 22, 20, 14, 33, 39, 16, + -22, -36, -23, -21, -40, -56, -52, -47, -24, -10, -4, 3, 1, -17, -22, -18, + -28, -26, -32, -30, -32, -30, -22, 1, 15, 15, 27, 42, 52, 62, 75, 85, + 80, 59, 35, 1, -16, -20, -35, -12, 18, 17, 18, 40, 34, 5, -34, -38, + -27, -28, -42, -60, -58, -48, -18, -4, 0, 3, -4, -18, -20, -22, -35, -29, + -27, -34, -42, -28, -12, 3, 8, 19, 31, 40, 45, 60, 75, 79, 76, 62, + 37, -2, -20, -22, -31, -11, 13, 15, 31, 43, 27, 0, -28, -33, -36, -37, + -43, -58, -61, -47, -13, 1, 1, 3, -5, -12, -17, -25, -36, -27, -25, -39, + -45, -24, 1, 0, 8, 25, 43, 45, 42, 57, 76, 76, 73, 60, 37, -8, + -25, -22, -25, -6, 9, 21, 41, 41, 15, -6, -18, -33, -48, -40, -38, -57, + -64, -46, -6, 9, -4, 1, -1, -9, -18, -28, -33, -24, -27, -42, -45, -18, + 2, 3, 13, 31, 49, 43, 37, 60, 74, 68, 68, 60, 30, -12, -28, -23, + -19, -8, 5, 26, 48, 37, 11, -12, -17, -37, -54, -40, -41, -58, -65, -42, + 5, 12, -8, 0, 2, -6, -22, -29, -30, -28, -37, -44, -42, -9, 6, 7, + 17, 33, 44, 42, 40, 61, 72, 57, 63, 61, 24, -16, -34, -21, -15, -12, + 3, 31, 47, 28, 7, -10, -15, -43, -51, -38, -45, -61, -61, -31, 10, 8, + -3, 6, 5, -8, -24, -27, -28, -31, -44, -42, -29, -3, 6, 10, 24, 40, + 44, 45, 46, 57, 62, 56, 65, 56, 16, -13, -32, -18, -12, -10, 11, 32, + 39, 25, 6, -10, -19, -48, -44, -38, -49, -63, -61, -19, 12, 3, 4, 6, + 3, -9, -25, -26, -27, -38, -46, -39, -18, 1, 12, 20, 29, 33, 36, 49, + 47, 54, 59, 49, 63, 51, 8, -12, -25, -18, -18, -6, 20, 33, 28, 19, + 4, -9, -27, -43, -41, -45, -55, -64, -51, -13, 7, -3, 0, 7, 3, -12, + -28, -27, -33, -46, -51, -33, -10, -5, 15, 31, 34, 26, 32, 47, 51, 53, + 47, 50, 61, 41, 1, -8, -12, -21, -20, 5, 27, 29, 16, 13, 8, -9, + -28, -40, -40, -44, -55, -62, -40, -8, 5, -2, 4, 11, 4, -15, -26, -26, + -37, -49, -47, -27, -8, -3, 22, 45, 38, 22, 34, 47, 55, 52, 39, 44, + 58, 32, 2, 0, -7, -25, -21, 10, 29, 30, 9, 0, 0, -7, -26, -38, + -40, -53, -61, -53, -30, -5, 1, -2, 5, 10, 3, -18, -25, -33, -43, -51, + -46, -20, -10, -8, 26, 52, 35, 19, 32, 47, 56, 46, 33, 44, 48, 20, + 10, 11, -7, -29, -20, 15, 35, 28, 2, -9, -8, -6, -26, -32, -36, -54, + -64, -52, -22, 1, 3, 2, 3, 15, 2, -22, -24, -34, -41, -45, -39, -19, + -9, 1, 35, 57, 37, 18, 27, 46, 52, 41, 37, 44, 40, 18, 16, 13, + -7, -29, -14, 23, 36, 17, -6, -17, -2, 1, -24, -38, -43, -59, -62, -44, + -22, -4, 7, 2, 5, 16, -2, -24, -27, -36, -43, -48, -37, -20, -5, 14, + 40, 52, 36, 20, 26, 43, 46, 40, 41, 42, 28, 19, 19, 9, -4, -21, + -10, 27, 32, 10, -6, -16, -4, -5, -14, -37, -48, -59, -58, -36, -24, -1, + 13, -3, 7, 16, -5, -19, -32, -38, -46, -43, -32, -22, -7, 22, 49, 57, + 37, 22, 20, 37, 41, 36, 46, 41, 21, 19, 16, 9, -2, -25, -9, 27, + 24, 8, -12, -11, -2, -9, -10, -39, -51, -59, -59, -35, -21, 2, 15, -5, + 10, 11, -12, -19, -35, -39, -46, -35, -29, -26, -5, 37, 60, 53, 36, 26, + 19, 33, 37, 33, 48, 41, 18, 17, 19, 11, -8, -23, -3, 30, 21, -5, + -14, -2, -6, -9, -9, -42, -59, -64, -54, -33, -16, 6, 14, 0, 15, 4, + -14, -17, -35, -45, -46, -33, -27, -22, 2, 42, 56, 49, 37, 26, 19, 26, + 23, 36, 58, 44, 11, 8, 23, 10, -7, -15, 3, 26, 12, -10, -8, 3, + -10, -7, -13, -46, -58, -60, -57, -40, -11, 9, 9, 3, 13, -6, -12, -17, + -42, -53, -45, -28, -23, -14, 11, 49, 60, 49, 40, 27, 14, 16, 13, 43, + 62, 46, 6, 8, 22, 7, -9, -10, 11, 23, 4, -17, 2, 6, -6, -7, + -21, -51, -58, -58, -55, -38, -12, 12, 10, 13, 1, -15, -7, -14, -47, -62, + -45, -29, -19, -2, 21, 51, 63, 46, 37, 31, 16, 0, 4, 43, 64, 43, + 6, 9, 24, 4, -15, -2, 14, 9, -9, -15, 14, 7, -11, -10, -29, -53, + -54, -57, -48, -35, -9, 13, 9, 11, -5, -6, -2, -22, -57, -60, -39, -24, + -11, 5, 30, 52, 62, 49, 42, 38, 11, -9, 7, 45, 61, 44, 10, 15, + 21, -4, -15, 3, 13, 1, -13, -9, 13, 7, -9, -13, -32, -51, -53, -56, + -44, -35, -9, 15, 11, 7, -8, 0, -2, -34, -65, -56, -31, -24, -7, 20, + 37, 49, 56, 47, 47, 39, -3, -16, 12, 40, 53, 45, 16, 23, 17, -7, + -8, 7, 8, -5, -12, -7, 7, 7, -4, -17, -38, -56, -60, -50, -37, -33, + -8, 7, 9, 0, -6, 7, -8, -47, -71, -50, -25, -23, 0, 33, 41, 46, + 52, 53, 54, 35, -6, -9, 13, 32, 50, 48, 23, 25, 13, -4, -3, 0, + -1, -7, -7, -8, 3, 6, -3, -22, -41, -55, -62, -46, -30, -24, -5, 0, + 5, 2, 3, 10, -20, -57, -69, -41, -19, -16, 5, 37, 47, 46, 49, 54, + 58, 29, -4, -6, 7, 21, 49, 49, 24, 24, 12, -2, -5, -9, 0, 0, + -10, -15, 2, 8, -4, -23, -42, -57, -66, -43, -22, -16, -11, -8, 3, 5, + 7, 4, -28, -61, -61, -36, -19, -11, 10, 45, 51, 43, 46, 52, 54, 26, + 3, -8, -3, 15, 52, 48, 27, 30, 15, -1, -9, -14, 0, -2, -15, -17, + -2, -1, -5, -23, -37, -62, -64, -34, -17, -15, -19, -8, 4, 7, 8, -8, + -37, -55, -50, -33, -19, -5, 16, 49, 54, 44, 45, 52, 53, 32, 3, -12, + -5, 14, 46, 46, 38, 34, 21, 6, -13, -21, -2, -3, -18, -19, -14, -9, + -2, -14, -44, -74, -56, -26, -15, -16, -18, -6, -1, 7, 6, -20, -43, -48, + -35, -32, -24, 1, 23, 51, 54, 41, 42, 52, 49, 32, 3, -14, -5, 19, + 42, 47, 43, 38, 27, 10, -18, -19, -5, -7, -18, -27, -23, -9, 2, -8, + -51, -75, -41, -19, -15, -13, -15, -11, -5, 10, 1, -30, -37, -40, -30, -33, + -24, 6, 30, 49, 49, 45, 43, 52, 39, 24, 7, -10, -7, 12, 33, 44, + 48, 43, 36, 7, -29, -18, -6, -14, -23, -36, -32, -12, 2, -16, -60, -65, + -27, -22, -22, -9, -6, -14, -6, 11, -10, -38, -35, -27, -26, -35, -15, 18, + 39, 47, 48, 51, 55, 51, 28, 22, 13, -5, -6, 5, 27, 46, 57, 49, + 39, 1, -29, -12, -7, -15, -28, -48, -39, -11, -1, -28, -61, -51, -22, -30, + -22, -3, -4, -21, -6, 8, -23, -45, -29, -18, -27, -32, -11, 24, 44, 40, + 46, 56, 61, 44, 17, 18, 19, 1, -11, -2, 24, 48, 57, 54, 45, 2, + -27, -12, -11, -18, -32, -49, -41, -16, -10, -32, -47, -33, -25, -34, -13, 6, + -5, -24, -13, -4, -29, -43, -29, -18, -25, -21, -1, 25, 44, 40, 49, 67, + 60, 31, 12, 18, 24, -2, -18, -5, 22, 45, 62, 65, 46, -5, -21, -12, + -12, -17, -36, -57, -48, -23, -15, -29, -35, -28, -33, -31, -3, 12, -16, -32, + -12, -19, -36, -33, -25, -22, -29, -10, 14, 30, 41, 35, 51, 73, 57, 27, + 16, 21, 14, -4, -12, -2, 21, 41, 62, 71, 43, -7, -12, -19, -22, -23, + -46, -57, -51, -35, -20, -17, -22, -26, -37, -27, 7, 12, -24, -31, -14, -29, + -34, -30, -22, -20, -21, 2, 15, 26, 40, 45, 55, 66, 52, 28, 20, 17, + 10, -1, -12, -4, 21, 43, 65, 74, 39, 1, -9, -25, -27, -24, -45, -61, + -55, -43, -22, -9, -12, -24, -32, -26, 9, 7, -25, -31, -30, -40, -31, -26, + -19, -20, -11, 14, 18, 27, 45, 54, 52, 61, 49, 33, 24, 15, 5, 0, + -14, -2, 24, 44, 62, 67, 37, 12, -9, -30, -29, -33, -49, -66, -58, -51, + -25, -2, -6, -19, -31, -24, 6, 3, -21, -37, -43, -42, -31, -25, -17, -19, + -5, 15, 19, 30, 52, 56, 45, 54, 52, 38, 22, 11, 8, 0, -16, 2, + 27, 44, 63, 60, 34, 16, -10, -25, -31, -38, -55, -68, -62, -53, -18, 5, + -2, -17, -31, -16, 5, -4, -22, -43, -50, -38, -32, -21, -16, -11, 8, 10, + 19, 32, 60, 60, 43, 46, 51, 37, 24, 13, 8, -6, -17, 4, 32, 52, + 56, 52, 39, 23, -5, -23, -41, -48, -64, -65, -63, -57, -14, 9, 3, -18, + -28, -9, 0, -11, -25, -47, -53, -38, -30, -19, -11, 0, 10, 11, 23, 42, + 66, 60, 42, 49, 53, 36, 24, 20, 9, -17, -18, 3, 39, 59, 49, 41, + 39, 26, 1, -24, -53, -59, -70, -61, -66, -58, -12, 17, 7, -20, -26, -7, + -7, -16, -30, -51, -60, -45, -26, -11, -5, 5, 8, 10, 23, 48, 66, 55, + 40, 48, 48, 33, 30, 25, 2, -21, -15, 10, 41, 51, 44, 37, 41, 27, + 6, -28, -60, -65, -70, -63, -70, -55, -6, 21, 1, -20, -15, -2, -15, -24, + -32, -54, -66, -45, -22, -8, 6, 13, 5, 15, 31, 51, 64, 58, 41, 42, + 44, 35, 36, 29, 0, -20, -9, 14, 43, 53, 46, 39, 39, 24, 7, -33, + -69, -75, -73, -70, -75, -46, 4, 17, -2, -18, -6, 3, -18, -32, -38, -61, + -65, -39, -17, -2, 10, 10, 5, 19, 33, 55, 61, 54, 39, 40, 41, 41, + 40, 30, -6, -25, -6, 22, 44, 48, 42, 42, 37, 23, 11, -42, -73, -77, + -75, -74, -75, -39, 4, 8, -5, -15, 1, -1, -30, -33, -38, -69, -66, -40, + -14, 3, 16, 8, 5, 21, 39, 60, 59, 48, 40, 38, 39, 42, 42, 30, + -8, -20, 0, 26, 48, 51, 48, 43, 29, 21, 1, -47, -70, -80, -83, -80, + -70, -25, 0, -2, -9, -6, 9, -7, -29, -33, -49, -72, -59, -29, -3, 3, + 11, 6, 14, 27, 47, 61, 54, 47, 43, 34, 42, 45, 39, 21, -10, -17, + 4, 29, 53, 54, 47, 39, 29, 22, -11, -53, -70, -83, -86, -77, -61, -19, + -6, -7, -12, -2, 9, -14, -29, -35, -61, -70, -54, -25, -8, 2, 11, 8, + 17, 27, 54, 60, 50, 45, 42, 40, 43, 39, 35, 18, -9, -7, 8, 28, + 55, 56, 49, 32, 30, 15, -21, -53, -71, -88, -87, -74, -45, -12, -11, -15, + -14, 6, 12, -12, -30, -48, -66, -60, -44, -18, -8, 5, 13, 15, 21, 31, + 51, 57, 48, 43, 42, 40, 43, 37, 29, 16, -3, -1, 7, 35, 60, 54, + 38, 26, 29, 5, -30, -54, -72, -93, -87, -69, -34, -14, -19, -25, -12, 13, + 6, -17, -37, -56, -66, -49, -38, -18, -11, 1, 17, 24, 26, 32, 47, 52, + 50, 49, 45, 39, 40, 33, 32, 13, 4, 3, 3, 47, 65, 52, 29, 27, + 20, -5, -35, -56, -76, -90, -79, -63, -27, -17, -26, -24, 0, 12, -2, -16, + -33, -61, -61, -42, -33, -17, -16, -6, 22, 30, 25, 29, 45, 50, 46, 53, + 41, 37, 37, 33, 28, 17, 15, 2, 15, 54, 64, 46, 21, 25, 9, -12, + -39, -58, -77, -87, -75, -46, -21, -23, -34, -24, 9, 9, -7, -17, -40, -67, + -53, -33, -27, -22, -26, -4, 34, 34, 25, 27, 46, 44, 52, 59, 37, 30, + 35, 32, 26, 25, 16, 2, 30, 62, 57, 33, 19, 17, -7, -25, -43, -58, + -80, -82, -64, -36, -26, -26, -33, -17, 11, 4, -9, -18, -45, -62, -44, -30, + -24, -28, -29, 5, 38, 32, 25, 30, 48, 41, 53, 57, 35, 28, 26, 27, + 31, 29, 14, 12, 47, 63, 48, 35, 24, 4, -19, -32, -46, -55, -76, -77, + -58, -31, -30, -33, -36, -8, 12, -4, -9, -22, -51, -57, -30, -23, -27, -40, + -31, 18, 36, 31, 30, 33, 39, 36, 56, 51, 32, 27, 20, 24, 39, 30, + 16, 29, 55, 53, 43, 36, 21, -5, -28, -39, -45, -55, -71, -70, -47, -27, + -35, -36, -25, -2, 1, -4, -6, -23, -48, -48, -25, -16, -25, -46, -23, 24, + 30, 35, 34, 29, 33, 37, 51, 41, 30, 21, 12, 27, 47, 33, 19, 38, + 51, 43, 39, 36, 15, -17, -35, -35, -42, -55, -68, -62, -45, -33, -40, -36, + -19, -5, -4, -3, -6, -24, -47, -38, -17, -13, -37, -48, -13, 26, 30, 36, + 32, 27, 29, 36, 48, 38, 27, 9, 5, 34, 47, 31, 30, 49, 47, 36, + 38, 28, 11, -21, -32, -32, -47, -56, -60, -54, -40, -39, -42, -31, -12, -5, + -7, -1, -4, -21, -39, -28, -11, -13, -45, -42, -2, 23, 25, 42, 33, 26, + 26, 33, 44, 34, 20, 1, 5, 36, 47, 38, 40, 47, 37, 35, 38, 20, + 1, -23, -26, -35, -49, -56, -55, -48, -40, -46, -42, -28, -12, -12, -10, 2, + -6, -25, -32, -25, -13, -22, -43, -30, 5, 18, 24, 45, 35, 29, 21, 27, + 39, 28, 16, 2, 9, 39, 40, 44, 55, 45, 25, 31, 34, 15, -1, -18, + -25, -41, -49, -50, -52, -46, -42, -48, -40, -23, -9, -18, -13, 9, -1, -24, + -27, -22, -14, -30, -41, -26, 8, 15, 25, 40, 36, 26, 15, 26, 35, 21, + 11, 2, 17, 44, 37, 54, 63, 37, 16, 31, 27, 12, -3, -12, -24, -45, + -47, -46, -45, -40, -44, -55, -40, -17, -12, -22, -7, 19, -2, -22, -24, -15, + -17, -36, -36, -11, 16, 10, 17, 38, 43, 25, 15, 25, 26, 14, 7, 2, + 25, 39, 38, 63, 67, 30, 16, 25, 18, 14, -5, -9, -26, -43, -45, -47, + -42, -38, -52, -57, -35, -14, -22, -27, 0, 23, -5, -24, -22, -12, -21, -40, + -31, 1, 19, 6, 11, 35, 44, 22, 18, 28, 14, 4, 4, 11, 32, 34, + 38, 70, 68, 22, 18, 17, 15, 17, 0, -10, -31, -45, -43, -42, -34, -36, + -62, -61, -25, -11, -28, -29, 3, 25, -3, -26, -15, -12, -28, -34, -21, 9, + 17, 2, 10, 31, 40, 24, 23, 28, 5, -3, 6, 19, 35, 33, 42, 72, + 59, 22, 22, 12, 17, 17, 2, -11, -31, -40, -40, -36, -28, -40, -66, -57, + -18, -15, -32, -22, 9, 22, -3, -23, -8, -12, -31, -32, -12, 18, 15, -1, + 9, 25, 36, 26, 27, 20, -7, -5, 12, 23, 29, 33, 45, 70, 48, 25, + 20, 8, 16, 9, 4, -11, -33, -39, -37, -34, -30, -46, -65, -50, -23, -22, + -30, -19, 13, 22, -4, -21, -6, -15, -32, -28, -3, 18, 9, 0, 9, 21, + 30, 28, 30, 12, -14, -1, 17, 19, 27, 41, 51, 63, 35, 28, 22, 12, + 10, 6, 9, -14, -31, -36, -31, -27, -38, -49, -62, -48, -29, -25, -27, -13, + 13, 13, -3, -9, -9, -21, -30, -20, 4, 12, 4, 5, 12, 19, 27, 33, + 29, 6, -12, 2, 21, 17, 31, 45, 54, 55, 31, 31, 25, 14, 3, 5, + 11, -14, -27, -33, -24, -27, -41, -49, -63, -53, -37, -26, -22, -7, 11, 8, + 0, -3, -14, -19, -27, -14, 8, 5, 2, 9, 12, 20, 25, 31, 18, 0, + -6, 8, 20, 14, 27, 43, 59, 48, 24, 28, 25, 14, 2, 8, 6, -15, + -26, -30, -16, -28, -44, -53, -61, -58, -37, -27, -21, -4, 8, 3, 1, -2, + -18, -21, -24, -11, 3, -4, 3, 15, 17, 20, 22, 29, 15, 3, -2, 8, + 17, 18, 30, 46, 56, 40, 21, 29, 26, 14, -1, 5, 4, -6, -22, -29, + -13, -27, -46, -51, -62, -61, -37, -28, -14, 2, 7, 0, 5, -2, -16, -17, + -19, -10, -7, -9, 11, 20, 22, 18, 17, 25, 19, 4, -1, 10, 19, 25, + 32, 44, 53, 36, 19, 29, 24, 10, -4, 5, 4, -2, -22, -24, -13, -31, + -48, -56, -63, -60, -40, -31, -11, 8, 8, 2, 8, -6, -20, -17, -12, -10, + -20, -12, 14, 30, 26, 10, 14, 24, 24, -1, -7, 12, 25, 27, 30, 40, + 52, 34, 17, 28, 24, 7, -9, 1, 8, 3, -20, -20, -16, -33, -53, -59, + -62, -61, -47, -29, -5, 15, 5, 1, 9, -8, -20, -14, -5, -12, -30, -11, + 20, 37, 25, 10, 19, 25, 19, -5, -2, 18, 28, 26, 29, 41, 49, 31, + 20, 30, 24, 1, -8, 4, 10, 3, -17, -12, -18, -40, -57, -61, -62, -59, + -48, -23, 0, 18, 5, 5, 12, -9, -19, -9, -2, -20, -37, -7, 25, 39, + 23, 11, 25, 26, 10, -10, 5, 23, 24, 26, 30, 40, 42, 27, 23, 31, + 18, -7, -5, 2, 7, -1, -10, -10, -22, -45, -59, -63, -62, -58, -45, -21, + -1, 17, 10, 13, 7, -18, -21, -5, -3, -27, -38, -7, 26, 38, 21, 20, + 31, 23, 0, -9, 15, 25, 21, 28, 33, 35, 35, 29, 28, 31, 12, -5, + 0, 0, 4, 0, -3, -14, -27, -48, -57, -69, -66, -61, -40, -19, 1, 16, + 13, 16, -3, -18, -17, -4, -9, -30, -33, -1, 24, 35, 28, 34, 31, 16, + -4, -2, 22, 29, 20, 27, 38, 33, 30, 30, 31, 33, 9, 1, -3, -7, + 2, 6, -1, -22, -31, -50, -61, -74, -67, -52, -34, -25, 1, 19, 21, 14, + -8, -18, -14, -10, -14, -27, -26, -5, 21, 35, 38, 40, 31, 12, -1, 5, + 22, 29, 19, 31, 41, 28, 30, 28, 31, 28, 12, 7, -13, -11, -2, 13, + -5, -26, -32, -52, -67, -80, -65, -46, -34, -26, 2, 15, 25, 9, -8, -14, + -16, -10, -18, -25, -25, -9, 20, 37, 46, 35, 26, 10, 7, 8, 18, 27, + 18, 31, 39, 25, 29, 29, 34, 26, 20, 2, -18, -10, -5, 12, -9, -22, + -31, -48, -74, -79, -66, -42, -34, -22, -1, 14, 25, 13, -6, -19, -16, -8, + -19, -22, -21, -5, 21, 41, 51, 32, 25, 14, 19, 13, 14, 21, 21, 32, + 34, 26, 26, 30, 32, 25, 25, -3, -19, -13, -2, 8, -12, -24, -32, -46, + -75, -79, -67, -43, -33, -18, -7, 12, 25, 18, 0, -23, -13, -7, -23, -18, + -15, -4, 21, 48, 51, 27, 27, 23, 22, 12, 12, 19, 22, 28, 28, 28, + 28, 31, 28, 23, 28, -3, -20, -22, -5, 0, -14, -23, -28, -50, -78, -81, + -63, -44, -34, -19, -14, 10, 25, 18, -6, -19, -5, -11, -30, -17, -8, 2, + 21, 54, 45, 25, 28, 33, 25, 9, 12, 21, 26, 23, 24, 33, 37, 35, + 20, 23, 32, -1, -21, -25, -12, -11, -12, -19, -27, -53, -78, -79, -55, -42, + -31, -26, -18, 12, 24, 13, -9, -12, 0, -20, -33, -13, 1, 6, 26, 55, + 38, 25, 33, 45, 26, 7, 13, 21, 26, 16, 18, 38, 44, 33, 14, 25, + 30, 4, -24, -32, -21, -18, -19, -19, -25, -54, -79, -78, -53, -43, -29, -28, + -20, 6, 20, 12, -3, 0, -3, -35, -28, 1, 9, 8, 25, 46, 34, 30, + 37, 44, 19, 13, 20, 17, 20, 12, 18, 49, 49, 23, 13, 28, 33, 3, + -34, -37, -28, -30, -21, -10, -26, -57, -77, -74, -52, -40, -25, -32, -22, 3, + 17, 12, 3, 8, -15, -40, -18, 10, 10, 4, 32, 39, 27, 38, 48, 39, + 11, 18, 28, 17, 15, 5, 23, 61, 46, 21, 23, 35, 26, -3, -31, -37, + -39, -38, -23, -3, -29, -60, -74, -68, -58, -37, -27, -35, -22, -7, 15, 23, + 14, 8, -27, -41, -6, 19, 14, 9, 35, 31, 31, 48, 54, 35, 11, 27, + 26, 4, 7, 11, 31, 54, 38, 25, 34, 35, 20, -10, 19, 3, -8, -45, + 64, -15, -41, 23, 40, -58, 22, 29, -27, -28, 42, -36, 21, -12, -19, 39, + -14, 3, -18, 32, -27, 18, -8, -43, 43, 25, -52, 6, 19, 13, -7, -50, + 55, 5, -46, -22, 94, -53, -33, 35, 27, -45, -2, 20, 19, -30, -23, 47, + 8, -58, 5, 76, -67, -22, 42, 30, -54, 8, 23, 11, -51, 3, 47, -33, + -7, 5, 27, -33, 34, -35, 17, 4, -26, 5, 17, -30, 33, 5, -29, -5, + 44, -18, -50, 60, -33, 10, -5, 10, -7, 1, -5, 19, -36, 3, 37, -17, + -51, 52, 37, -64, 9, 4, 37, -44, -13, 25, 45, -75, -9, 79, -34, -57, + 53, 24, -59, 18, 22, -3, -24, 10, -2, 18, -53, 29, 35, -20, -43, 37, + 18, -17, -31, 8, 45, -49, 8, 11, 9, -23, 30, -24, -22, 29, 14, -43, + 27, 13, -22, -1, 2, 22, -37, 5, -5, 38, -43, 6, 36, -21, -20, 20, + 0, -5, -27, 27, 21, -53, 4, 52, -2, -84, 70, 5, -29, -19, 36, -6, + -8, -12, 3, 35, -32, -25, 48, 6, -60, 49, 4, -27, -13, 31, -15, -9, + -4, 31, -13, -25, 29, 12, -34, -6, 30, -41, 36, -23, 6, 31, -30, 0, + 17, -45, 47, -5, -47, 19, 28, -8, -30, 27, -6, 15, -54, 34, 21, -27, + -9, 25, 3, -45, 26, 27, -52, 22, 20, -29, 34, -46, 22, 40, -69, -27, + 108, -49, -54, 69, -11, -3, -18, 3, 15, -12, -23, 29, -8, 4, -23, 50, + -38, -8, 33, -32, -2, 26, -27, 12, 13, -39, 56, -31, -22, 28, 2, -39, + 54, -20, -36, 51, -6, -34, 15, 2, 1, 2, -36, 42, 2, -10, -39, 64, + -36, -16, 24, 1, -1, -18, -10, 54, -27, -54, 80, -18, -61, 51, 27, -76, + 64, -30, -1, 9, -19, 24, 13, -29, -13, 49, -18, -46, 43, 6, -47, 42, + -28, 14, 18, -18, 2, 14, -39, 25, 16, -58, 33, 29, -49, 16, 41, -62, + 43, -17, -17, 25, -10, -28, 41, -5, -30, 27, 14, -53, 27, 35, -63, 16, + 30, 0, -30, -10, 22, 31, -57, 0, 68, -59, 2, 37, -30, 6, -3, -19, + 35, -29, 1, 20, 22, -68, 33, 39, -71, 21, 27, -22, -1, 3, 0, 18, + -16, -13, 17, 4, -37, 44, -15, -26, 48, -29, -11, 34, -25, -4, 25, -48, + 43, 4, -49, 28, 42, -72, 7, 59, -36, -28, 45, -9, -28, 25, -19, 23, + -9, -40, 47, 18, -85, 78, -2, -53, 39, -17, 2, 14, -36, 10, 63, -78, + 17, 59, -66, -8, 54, -49, 14, 1, 5, 2, -18, 16, -12, 30, -58, 22, + 53, -83, 17, 79, -84, 19, 17, -34, 44, -33, -27, 82, -62, -19, 91, -93, + 22, 49, -51, -25, 48, -12, -6, 1, -2, -1, 22, -32, -1, 59, -78, 12, + 58, -49, -26, 70, -40, -8, 16, -8, 12, 10, -65, 74, -1, -97, 90, 0, + -56, 23, 25, -17, 11, -23, 14, 9, -24, -31, 77, -41, -48, 95, -38, -46, + 59, -1, -57, 49, -33, 19, 18, -46, 34, 31, -79, 47, 11, -38, 10, 19, + -14, -10, 26, -29, 28, -17, -27, 48, -15, -51, 78, -14, -73, 64, 12, -55, + 29, 3, -24, 52, -65, 26, 50, -75, -5, 81, -76, 0, 42, -6, -26, 10, + 18, -14, 4, -24, 33, 2, -69, 61, 43, -101, 40, 54, -73, 22, 18, -41, + 44, -19, -43, 94, -69, -13, 65, -26, -46, 35, 24, -34, -2, 23, -13, 6, + -19, 4, 38, -56, 14, 40, -37, -19, 66, -57, -9, 50, -47, 21, 6, -31, + 55, -34, -50, 98, -44, -47, 44, 28, -51, 6, 31, -3, -34, 8, 11, 6, + -18, -27, 78, -48, -28, 55, -2, -60, 57, -37, 14, 15, -48, 49, 22, -96, + 74, 23, -83, 36, 18, -17, -25, 41, -12, -4, -2, 1, 9, -14, -18, 36, + 12, -77, 54, 32, -67, 20, 38, -67, 61, -53, 32, 21, -60, 27, 41, -74, + 27, 33, -30, -6, 22, -1, -30, 20, 1, -4, -22, 9, 8, 37, -65, 18, + 61, -69, -3, 37, -19, -15, 15, -16, 57, -78, 20, 66, -67, -27, 76, -37, + -16, 11, 11, -5, -18, 10, 16, -5, -38, 36, 9, -20, -32, 73, -41, -36, + 62, -33, -9, 34, -41, 35, -7, -40, 65, -35, -26, 33, 2, -43, 42, -4, + -9, 5, -11, 19, -10, -16, 11, 16, -28, -9, 41, 2, -70, 67, -3, -55, + 23, 33, -26, 6, -29, 43, 16, -85, 51, 28, -54, 7, 27, -9, 2, -18, + 27, -4, -42, 31, 10, -19, -9, 18, 8, -24, -3, 45, -57, 25, 0, -7, + 15, -28, 10, 33, -46, -6, 52, -36, -15, 46, -29, -4, 12, -14, 34, -57, + 16, 40, -41, 3, 16, 8, -32, 16, 15, -17, -27, 47, -30, -1, 14, -5, + 16, -17, -33, 70, -44, -42, 84, -34, -27, 18, 15, 3, -20, -22, 55, -35, + -22, 31, 10, -11, -27, 27, 13, -28, -10, 41, -21, -3, -22, 41, -21, -13, + 6, 34, -68, 46, 25, -65, 50, -21, -1, 10, -33, 34, 1, -43, 58, -34, + -2, 13, 8, -25, 0, -2, 34, -29, -26, 45, -12, 4, -34, 32, 15, -54, + 17, 53, -76, 41, 4, -17, 13, -26, 13, 31, -47, 1, 52, -53, 11, 8, + 14, -31, -7, 19, 30, -60, 26, 27, -22, -10, 0, 18, -13, -24, 52, -38, + -17, 68, -60, 26, -9, -25, 41, -29, -8, 40, -25, -9, 26, -28, 15, -9, + -3, 11, -21, -1, 44, -47, 19, 0, 3, -14, -12, 38, -22, -23, 37, -10, + -13, 9, -6, 21, -14, -39, 61, -4, -68, 60, 6, -43, 28, -14, 21, -22, + -13, 36, -7, -40, 46, -14, -5, -18, 20, 22, -49, 22, 10, -18, 21, -30, + 9, 34, -54, 19, 22, -34, 27, 7, -45, 30, 0, -20, 23, -23, 29, -10, + -21, 25, 3, -23, -1, 5, 16, -33, 14, 25, -21, -11, 16, 3, -22, 5, + 6, 32, -73, 27, 62, -72, 5, 26, -21, 30, -37, 4, 40, -45, 5, 18, + -18, -1, 12, -3, 0, -18, 28, -8, -14, 11, -11, 13, -15, -3, 27, -17, + -30, 65, -45, -5, 28, -25, 1, 20, -36, 38, -11, -20, 35, -23, -20, 27, + 11, -42, 13, 17, 1, -25, 20, 10, -33, 10, 6, -7, 9, -26, 40, -3, + -63, 74, -30, -11, 10, -10, 5, 17, -47, 53, -10, -47, 29, 31, -45, 4, + 16, 14, -15, -33, 40, -11, -3, -10, 2, 18, -20, 9, 22, -44, 19, 20, + -42, 25, -5, -11, 25, -25, -3, 47, -63, 28, 20, -42, 7, 39, -41, 2, + 13, 10, -24, -8, 41, -26, -1, -13, 9, 42, -60, 0, 61, -54, -4, 19, + -6, 11, -19, -13, 52, -37, -26, 66, -38, -30, 49, -18, -11, 5, 7, 10, + -30, 4, 17, 2, -12, -15, 38, -19, -20, 30, -16, -23, 38, -13, -16, 29, + -22, 26, -17, -35, 62, -30, -35, 51, -16, -27, 40, -16, 3, -8, -4, 9, + 4, -26, 11, 20, -11, -38, 56, -19, -29, 31, 7, -39, 17, 10, 6, -8, + -41, 45, 26, -79, 36, 42, -58, 21, 6, -10, 7, -19, 17, -1, -15, -12, + 53, -22, -32, 24, 25, -59, 24, 22, -36, 10, 18, -27, 44, -45, 0, 42, + -45, -2, 30, -27, 12, 23, -38, 13, 5, 4, -4, -20, 1, 43, -27, -36, + 43, 14, -51, 12, 40, -41, 5, 18, -11, -1, -5, -11, 53, -56, -29, 91, + -41, -45, 57, -7, -18, -3, -4, 29, -20, -19, 20, 26, -57, 31, 17, -22, + -13, 28, -31, 3, 36, -33, 9, 17, -39, 42, -9, -54, 58, 6, -69, 44, + 30, -50, 24, 3, -17, 9, -20, 17, 8, -23, 1, 46, -50, 1, 27, 1, + -49, 37, 5, -17, 4, -5, 7, 18, -55, 39, 36, -85, 37, 48, -63, 5, + 27, -13, -6, -4, 5, 24, -26, -12, 42, -25, -34, 33, 20, -33, -13, 29, + -2, 7, -34, 12, 37, -50, 1, 47, -46, -1, 56, -54, -18, 59, -35, -6, + 12, -16, 20, -2, -27, 43, -12, -34, 22, 25, -41, -7, 43, -20, -18, 19, + -1, 1, -6, -20, 54, -55, -12, 67, -24, -56, 56, -8, -12, -7, -3, 16, + 20, -48, 20, 32, -46, 8, 23, -17, -38, 54, 1, -34, 2, 30, -1, -21, + -18, 38, -14, -35, 41, 3, -36, 19, 22, -45, 40, -32, 12, 12, -26, 2, + 35, -54, 34, 14, -25, -30, 47, 10, -53, 24, 13, -4, -18, 3, 5, 27, + -61, 38, 15, -39, 6, 40, -36, 0, 2, -6, 28, -40, 7, 46, -37, -30, + 59, -21, -29, 6, 48, -55, 12, 30, -21, -6, 5, -2, 1, -14, -7, 46, + -41, -4, 35, -8, -33, 29, -20, 26, -31, -10, 63, -46, -4, 12, 7, -11, + -15, 26, -14, -22, 54, -47, 12, 9, -1, -8, -7, -8, 41, -12, -60, 77, + -21, -26, 11, 13, 1, -26, -9, 59, -45, -16, 38, -3, -27, -1, 28, -8, + -19, 11, 20, -41, 34, -23, 22, -20, -9, 6, 51, -79, 40, 18, -40, 23, + -5, -19, 13, 2, 3, -4, -35, 71, -39, 5, -30, 33, 6, -29, -3, 38, + -29, -5, 18, -9, -4, -11, 16, 15, -32, -14, 77, -83, 30, 10, -10, -19, + 20, 15, -17, -19, 29, 7, -32, 6, -1, 14, -14, -6, 5, 36, -58, 47, + -18, -14, 4, 8, 8, -24, -15, 60, -36, -20, 43, -32, 3, -2, 1, 9, + -5, -8, 30, -33, 6, 6, 2, -12, -11, 24, 1, -22, 9, 34, -61, 25, + 11, -5, -18, -1, 38, -19, -33, 49, -19, -21, 18, -7, 1, 5, -4, -3, + 13, -30, 25, -5, -12, 2, 8, 17, -37, 0, 50, -38, -26, 40, -15, 7, + -24, 31, -11, -8, 6, -6, -3, 1, 9, -8, 6, -20, 25, 0, -21, 7, + 22, -48, 29, -4, 10, -22, 7, 22, -9, -34, 45, -15, -31, 30, -2, 0, + -30, 46, -18, -6, -17, 31, -6, -7, -21, 8, 45, -47, -7, 31, -17, -11, + 25, -20, 17, -30, 47, -38, -2, 5, 16, -36, 24, -2, 3, -7, 6, 10, + -23, 5, -11, 35, -42, 17, 0, 21, -35, 11, 16, -18, -15, 36, -24, -3, + 9, 5, 13, -49, 36, -11, -2, -14, 37, -32, 13, -1, 0, -2, -2, -8, + 17, -11, -21, 30, -1, -1, -41, 72, -65, 14, 14, 12, -41, 21, 4, 15, + -32, -1, 25, -9, -18, 3, 29, -38, 35, -22, 14, -20, 16, -6, -6, -13, + 29, -4, -17, 7, 14, -6, -38, 54, -32, 3, -16, 36, -39, 42, -40, 36, + -22, -13, 17, 14, -36, 12, 23, -25, 6, -25, 53, -33, -12, 5, 37, -46, + 6, 20, 9, -53, 52, -16, -22, 24, -9, 10, -17, 12, -20, 48, -73, 40, + 18, -30, -20, 52, -34, 11, -6, 0, 1, -15, 24, -16, 16, -30, 44, -27, + -10, 0, 34, -52, 24, 3, 2, -6, 12, -25, 35, -38, -14, 72, -73, 7, + 31, 15, -50, 20, 12, -5, -25, 23, 3, -10, -9, 15, 9, -41, 28, 6, + -5, -36, 44, -13, 10, -19, 2, 14, -10, -29, 56, -27, -35, 58, -19, -27, + 17, 16, -30, 10, -7, 15, -12, -3, 11, 18, -30, -13, 38, -17, -16, 3, + 32, -37, 23, -24, 30, -12, -26, 40, -14, -52, 59, 12, -55, 16, 35, -20, + -30, 39, -24, 21, -26, 12, 13, -10, -19, 23, 2, -35, 17, 33, -30, -17, + 39, -15, 12, -53, 50, -13, -25, 2, 50, -42, -1, 25, -22, 6, -5, 3, + -4, 2, -18, 39, -25, -3, 1, 29, -57, 22, 26, -22, -18, 34, -10, -10, + -11, 13, 31, -77, 46, 23, -22, -35, 61, -24, -13, 7, -3, 0, 4, -24, + 27, 12, -50, 35, 13, -19, -37, 69, -46, -4, 13, 5, -8, 6, -25, 40, + -26, -13, 38, -12, -28, 21, 22, -57, 40, -15, 11, -19, 4, 19, 9, -36, + 3, 42, -35, -30, 46, 0, -50, 59, -26, 9, -16, 12, -10, 10, -33, 44, + -8, -29, 8, 42, -43, -6, 26, -19, 14, -30, 34, 4, -21, -17, 49, -31, + -24, 34, 14, -53, 32, 13, -26, 12, -22, 26, -3, -22, -11, 66, -59, 0, + 43, -27, -23, 42, -32, 7, -7, 11, 9, -19, -1, 15, 16, -58, 43, 1, + -32, 11, 36, -44, 18, 0, 4, -4, -7, -22, 50, -22, -44, 67, -14, -43, + 37, 2, -32, 15, 7, 8, -22, -1, 14, 19, -43, 0, 40, -30, -14, 28, + 10, -32, 11, 1, 21, -33, -9, 31, 15, -72, 61, 4, -40, 21, 14, -37, + 22, 4, -4, -9, 5, -8, 23, -16, -22, 35, -24, 0, 12, 3, -17, 15, + 2, -10, -6, -8, 21, 7, -58, 40, 43, -75, 25, 28, -25, -18, 28, -15, + 6, -5, -4, 22, -5, -39, 37, 1, -30, 12, 23, -27, -8, 34, -22, 0, + -12, 15, 10, -28, 2, 45, -45, -9, 36, -22, -7, 13, -7, 6, 2, -18, + 17, 10, -34, 9, 18, -22, -1, 22, -9, -17, 23, -1, -22, 21, -20, 20, + -17, -6, 38, -33, -18, 55, -32, -21, 26, -5, -9, 5, -8, 16, 9, -47, + 36, 11, -36, -3, 38, -7, -48, 44, -2, -11, 2, -16, 15, 11, -36, 33, + -3, -18, 9, 19, -46, 26, -1, -11, 20, -24, 12, 16, -16, -17, 37, -32, + -6, 13, 13, -33, 25, 14, -27, 8, 1, -18, 22, -5, -15, 32, -46, 37, + -2, -19, -13, 38, -32, 8, 2, -4, 15, -12, -4, 19, -25, -10, 37, -19, + -11, -10, 57, -54, 19, -17, 18, 3, -18, -9, 27, -6, -36, 57, -23, -21, + 14, 11, -23, 32, -53, 56, -24, -5, -3, 11, -16, 16, -7, -20, 17, 11, + -3, -31, 42, -33, 14, -6, -2, -8, 39, -56, 48, -21, -20, 30, -8, -20, + 12, 15, -32, 41, -36, 29, -25, 14, -22, 22, -19, 9, 4, 10, -31, 17, + 11, -14, -1, -7, 17, -16, 6, -18, 64, -88, 47, 6, -20, -5, 22, -13, + 18, -28, 2, 25, -19, -10, -3, 29, -23, 11, -22, 39, -25, 13, -27, 20, + -2, -18, 15, -3, 3, 9, -17, -8, 38, -57, 35, 1, -9, -24, 43, -32, + 30, -30, -3, 19, -3, -21, 12, 14, -12, 2, -5, 11, -37, 37, -3, -13, + -4, 10, 11, -4, -38, 41, -9, -27, 37, -37, 16, 17, -7, -15, 22, -40, + 33, -2, -16, 4, 3, 8, -4, -20, 21, -3, -10, 8, -26, 37, -21, 8, + 0, -3, -3, 0, -8, 20, -15, -32, 54, -10, -26, 17, -12, 10, 24, -71, + 51, 3, -21, 9, -3, 17, -22, 2, 15, -21, -11, 39, -25, 11, -27, 28, + 3, -11, -26, 45, -43, 24, 7, -39, 47, -24, -15, 27, -13, -15, 35, -27, + 15, -17, 9, 0, -7, 0, 4, -9, 13, -3, -16, 28, -29, 21, -23, 11, + -4, 10, -30, 64, -63, 13, 28, -30, 16, -13, 0, 25, -39, -2, 53, -40, + 5, -19, 41, -25, -6, -3, 37, -40, 6, 8, 0, 6, -34, 32, 4, -27, + 13, 15, -34, 52, -63, 40, -5, -22, 5, 24, -32, 22, 11, -26, 14, -22, + 26, -21, 10, -8, 5, -10, 46, -66, 44, -20, 14, -7, -27, 23, 30, -53, + 24, 10, -37, 44, -40, 21, -11, 3, 6, 20, -47, 27, 5, -2, -18, -4, + 29, -13, -20, 27, 9, -47, 43, -37, 55, -62, 14, 33, -13, -28, 24, -9, + 23, -35, -4, 32, -14, -13, 28, -10, -30, 46, -43, 43, -46, 13, 13, -10, + 7, -3, -20, 39, -19, -19, 14, -15, 39, -31, -10, 25, 2, -34, 41, -35, + 15, -4, -3, 22, -18, -27, 46, -1, -36, 10, -4, 42, -56, 13, 31, -19, + -18, 28, -29, 27, -32, 24, 10, -44, 20, 32, -32, -17, 32, -13, 13, -35, + 20, 32, -53, 20, 9, -16, 16, -36, 39, -3, -33, 43, -26, 2, 2, 2, + -17, 24, -22, 14, -3, -12, 31, -28, -8, 26, -29, 19, -4, -15, 33, -39, + 22, 16, -37, 6, 17, -4, -13, -12, 37, 9, -65, 34, 25, -27, -9, 7, + 5, 10, -36, 45, -11, -41, 42, -6, -21, 7, -5, 31, -5, -57, 62, -12, + -15, -16, 23, 4, -24, 12, 26, -35, -11, 44, -25, -8, -1, -4, 28, -11, + -37, 61, -48, 23, -1, -30, 29, -8, -2, 6, -19, 18, 15, -41, 30, -4, + -11, -11, 28, -10, -4, -37, 81, -45, -43, 61, -19, 1, -11, 0, 31, -30, + -25, 68, -43, -11, 0, 27, -1, -33, -7, 77, -54, -30, 44, -6, -5, -14, + 17, -6, -10, 6, 30, -68, 50, -16, 5, 5, -30, 30, 26, -69, 36, 8, + -34, 37, -28, 11, 0, -1, 9, 1, -41, 53, -22, -24, 23, 5, -9, -11, + 12, 28, -61, 28, 36, -68, 51, -33, 25, -6, -26, 7, 53, -65, 2, 47, + -25, -23, 17, 20, -4, -51, 38, 29, -67, 31, 1, 22, -35, -8, 40, -9, + -46, 47, -13, -8, 5, -15, 37, -27, -20, 45, -16, -45, 59, -37, 19, -6, + 2, 1, -11, -3, 34, -42, 0, 33, -30, 16, -13, 13, 2, -23, 18, -5, + -26, 43, -24, 15, -26, 4, 35, -15, -62, 64, 19, -75, 50, -8, 8, -14, + -12, 31, -19, -30, 45, -10, -12, -10, 36, 3, -53, 14, 45, -37, -22, 42, + -25, 21, -36, 21, 37, -61, 5, 47, -49, 19, -4, 5, 1, -12, 7, 3, + -11, 2, 18, -28, 13, -4, 18, -13, -20, 33, -22, -8, 21, -12, -10, 24, + -9, 2, -27, 15, 33, -41, -18, 56, -40, 9, -5, 6, 20, -44, 11, 39, + -35, -22, 50, -7, -36, -6, 41, -10, -30, 15, 20, -22, 7, -11, 16, 6, + -51, 59, -21, -26, 24, 12, -24, 8, -7, 12, 3, -36, 27, 18, -42, 22, + 9, -22, 11, -2, 15, -40, 38, -13, -16, 8, 24, -33, 15, -13, 4, 23, + -42, 17, 30, -34, -5, 28, -22, 11, -23, 30, -14, -28, 37, 12, -46, 11, + 31, -23, -12, -7, 36, -17, -6, -4, 25, -18, 4, -29, 53, -48, 4, 24, + -9, -21, 30, -1, -20, 2, -13, 51, -51, -1, 39, -23, -18, 33, -23, 3, + 3, 2, -13, 11, 4, -13, 15, -14, -3, 1, 24, -53, 55, -24, -17, 36, + -1, -49, 45, -7, -12, -2, -4, 24, -23, 1, 6, 23, -51, 30, -8, 14, + -29, 17, 12, -9, -21, 21, 1, 3, -32, 21, 30, -59, 27, 25, -21, -26, + 36, -24, 16, -23, 15, 10, -15, 11, -11, -3, 14, 1, -30, 32, -24, 27, + -25, 10, -12, 29, -33, 7, -5, 25, -29, 14, 15, -42, 20, 18, -27, 1, + 21, -19, 17, -18, 2, 19, -12, -34, 47, -21, -6, 9, -2, 14, -32, 32, + -23, 14, -21, 21, 0, -13, -8, 42, -35, -19, 33, 4, -34, 23, -5, -6, + 22, -31, 21, -8, -5, -3, 15, -22, 10, 2, 7, -17, 11, 3, -10, 2, + -1, -2, -9, 25, -20, 11, -18, 17, -3, -12, 2, 9, -1, -10, 5, 0, + 15, -40, 36, -5, -28, 16, 24, -34, 16, -1, 13, -32, 11, 9, 5, -26, + 5, 32, -32, 4, -1, 29, -38, 8, 7, -6, 5, -2, -5, 18, -26, -2, + 39, -42, 0, 26, 2, -43, 45, -30, 20, -11, -6, -3, 16, -7, -6, 3, + 12, -13, 5, -7, -21, 47, -29, -11, 9, 36, -45, 8, 0, 22, -28, -7, + 32, -22, -9, 20, 12, -40, 24, -8, 14, -28, 10, 9, 12, -29, 15, -7, + 15, -23, 5, 14, -24, 12, 8, 4, -38, 36, -4, -7, -30, 47, -13, -24, + 16, 23, -46, 29, -3, -10, 20, -43, 35, 0, -4, -30, 47, -18, -21, 16, + 19, -35, 11, 19, -21, -11, 27, -12, -9, 16, -21, 23, -32, 30, 3, -22, + -15, 51, -38, -1, -2, 11, 15, -28, -1, 16, 13, -42, 23, 4, -6, -32, + 61, -24, -35, 34, 29, -55, 4, 13, 9, -6, -26, 35, -6, -11, -11, 19, + -6, -3, -15, 43, -41, 4, 22, -1, -34, 18, 15, -35, 18, -1, 23, -35, + 18, -2, -9, 1, 10, -18, 17, -18, 21, -8, -17, 24, -1, -20, -7, 26, + -11, 6, -33, 42, 0, -40, 9, 46, -48, -6, 24, 13, -39, 8, 41, -43, + 3, 6, 6, -7, -6, -8, 42, -37, -11, 39, -16, -26, 25, 3, -24, 9, + 11, 6, -34, 17, 14, -12, -22, 20, 0, 14, -38, 27, 10, -37, 22, -1, + -5, -7, 11, 4, -3, -29, 38, -5, -26, 4, 20, -17, 6, 2, 11, -17, + -10, 40, -49, 10, 26, -8, -24, 11, 12, 5, -36, 21, 20, -22, -29, 28, + 30, -30, -24, 31, 25, -70, 39, 4, -16, 3, 9, -13, 16, -26, 23, 19, + -46, 1, 29, 6, -37, 8, 27, -8, -33, 36, -24, 5, 14, -8, -8, 1, + 4, 15, -27, -11, 44, -38, 6, 12, -3, -12, 20, -17, 16, -35, 28, -4, + 0, -13, 8, 23, -24, -16, 28, 11, -58, 48, 6, -39, 11, 24, -9, -8, + -25, 42, -16, -14, 12, 2, 13, -31, 6, 26, -10, -48, 64, -22, -21, 6, + 28, -15, -11, -2, 22, -30, 11, 15, -25, 13, 2, -1, -7, -4, 6, 17, + -37, 17, 0, 1, 14, -23, 4, 16, -23, 6, 12, -31, 30, 6, -18, -25, + 45, -7, -20, -15, 44, -38, 9, 22, -37, 24, 6, -20, 14, -17, -8, 44, + -27, -22, 16, 30, -33, -18, 20, 31, -50, 11, 27, -21, -4, -3, 26, -15, + -24, 15, 20, -27, 16, -12, 9, 5, -24, 3, 26, -27, 5, 15, -19, 9, + -9, 26, -25, -5, 10, -4, -6, 31, -45, 18, 24, -23, -23, 27, -3, 2, + -18, 9, 13, -18, 19, -17, 7, -1, -24, 31, 5, -49, 31, 32, -40, -7, + 10, 14, -12, -12, 5, 21, -30, 25, -12, 4, -18, 9, 11, -13, -20, 37, + -8, -3, -13, -3, 33, -21, -32, 44, -7, -22, 28, -24, 5, 12, -19, 2, + 6, 2, -16, 11, 10, -6, -23, 31, -25, 7, 6, -16, 18, 1, -35, 40, + -9, -18, 12, 4, -2, -25, 20, 19, -16, -35, 46, -14, -8, -3, -1, 24, + -12, -25, 26, -4, -6, 3, -12, 20, -24, 18, 9, -20, -2, 18, -13, -1, + -16, 8, 26, -35, 12, 10, -11, 6, 2, -30, 46, -43, 16, 6, 1, -20, + 26, -18, 8, -13, 9, -3, 3, 1, -25, 29, 13, -50, 12, 41, -47, 15, + 14, -12, 2, -3, -1, 14, -25, -3, 26, -23, 19, -35, 41, -5, -23, -1, + 31, -30, 8, -15, 32, -29, -7, 22, 10, -35, 12, 6, -2, 20, -50, 36, + 7, -17, -4, -1, 7, 2, -21, 19, -12, 1, 28, -25, -5, 9, -3, -12, + 32, -45, 16, 21, 0, -43, 21, 28, -19, -38, 45, -15, -8, 28, -43, 39, + -12, -23, 13, 19, -39, 23, -3, 17, -32, 6, 20, -5, -32, 23, 8, -15, + -1, 11, 9, -28, 5, 20, -18, -6, 9, -18, 50, -50, -8, 49, -30, -5, + -4, 14, -19, 28, -21, 2, 4, 11, -20, 6, 3, -5, -24, 54, -34, -14, + 26, -4, -2, -16, 5, 20, -23, 1, 6, -9, 32, -37, 1, 25, -22, -8, + 31, -6, -37, 31, 0, 3, -37, 24, 25, -27, -20, 27, 1, 4, -26, 13, + 3, -14, 12, -6, 6, -3, -6, 18, -14, -27, 38, 5, -36, 14, 13, -22, + 26, -13, -22, 36, -23, -5, 3, 18, -12, -23, 31, -5, -24, 23, -15, 17, + -7, -23, 20, 6, -4, -19, 20, -8, 15, -32, 13, 17, -30, 17, 13, -19, + -8, 4, 24, -18, -29, 36, 7, -21, -20, 28, 13, -17, -31, 36, -9, -7, + 7, 6, -9, -4, 7, -6, 10, -32, 41, -26, 12, -10, -12, 35, -10, -39, + 36, -9, -7, 7, 6, -9, -4, 11, -14, 5, -7, 9, -13, 24, -27, 4, + 14, 7, -31, 19, -14, 17, -5, -34, 57, -31, -7, -6, 28, -15, -11, 2, + 25, -21, -14, 15, 18, -35, 12, 1, 9, -20, -2, 32, -37, 26, -17, 7, + 1, -10, -18, 54, -37, -16, 23, 11, -13, -23, 34, -5, -16, -10, 25, -28, + 30, -10, -7, -5, 18, -24, 25, -24, 18, -11, 0, 3, -19, 34, -12, -12, + 2, 3, -13, 32, -37, 20, 4, -6, -25, 29, -3, -2, -11, -2, 28, -38, + 18, 7, -5, -7, 0, -4, 21, -36, 30, -19, 25, -29, -15, 48, -11, -43, + 33, 33, -64, 17, 26, -12, -18, 9, -1, 18, -33, 23, -13, 21, -18, -13, + 18, -2, -20, 20, 6, -15, 4, -12, 28, -27, 1, 10, -5, 3, 0, -17, + 15, 17, -30, 2, 5, -8, 17, -11, -2, 9, -20, 23, -27, 23, -10, -3, + 7, -3, -25, 31, 9, -28, -9, 30, -5, -28, 15, 29, -36, -9, 29, -11, + -20, 33, -27, 21, -14, -12, 21, -3, -9, -2, 12, -5, -27, 27, 7, -20, + -11, 32, -9, -15, -1, 9, 20, -42, 12, 9, -4, 3, -6, -3, 6, 0, + -12, 15, -25, 27, -6, -6, -6, 6, -2, -4, 5, 9, -20, 12, 8, -17, + -10, 30, -12, -24, 25, -15, 18, -21, 21, -8, -6, -9, 12, -6, 15, -33, + 26, 8, -32, 13, 21, -12, -28, 20, 11, -6, -28, 27, 11, -21, -10, 22, + -1, -11, -7, 24, -12, -27, 35, -8, 0, -20, 23, -10, 9, -30, 32, -15, + 3, -7, 6, -2, 10, -17, 1, 8, -4, -5, -3, 14, -9, 1, -11, 18, + -13, 15, -33, 22, 14, -32, 11, 9, -1, -17, 14, 0, -3, -16, 29, -21, + -4, -1, 28, -24, -2, -11, 41, -25, -23, 24, 6, -18, -13, 37, -21, -2, + -4, 29, -40, 11, 12, 4, -25, 12, -9, 23, -17, -14, 27, -2, -26, 9, + 18, -14, -1, -15, 29, -18, -4, 5, 12, -26, 18, -3, -7, 3, 13, -10, + -25, 44, -38, 11, 8, -2, -25, 28, -9, 12, -13, -13, 10, 27, -53, 19, + 16, -4, -20, 12, 12, -21, 5, 12, 3, -35, 22, 8, 0, -28, 18, 16, + -25, -3, 9, 8, -3, -19, 8, 24, -34, -4, 38, -16, -30, 29, -1, -2, + -25, 28, -1, -21, 11, 10, -18, -1, 10, 1, -7, 0, 1, -7, 15, -15, + -5, 16, 2, -22, 8, 0, -1, 26, -34, -22, 56, -26, -11, 12, 9, -9, + -9, 4, 7, -8, -1, 8, 0, -21, 10, 19, -8, -25, 17, 10, -18, 3, + -4, 26, -15, -29, 30, 9, -46, 36, 12, -33, 1, 18, -2, -16, 4, 16, + -10, -16, 11, 2, 8, -19, 5, 1, 10, -21, 20, -8, -1, -3, 1, 7, + -19, 7, 11, -12, 5, 5, -26, 29, -11, -5, -2, 12, -13, 9, -22, 23, + 3, -20, 4, 17, -16, -13, 17, 15, -16, -34, 37, -5, 8, -32, 23, 17, + -36, -2, 36, -25, -4, 28, -18, -20, 15, 4, 7, -12, -24, 43, -19, 0, + -11, 25, -9, -12, -7, 10, -1, 11, -2, -12, 13, -27, 30, -9, -15, 8, + 17, -28, 18, -9, 3, 7, -8, -10, 16, -26, 35, -22, -10, 37, -35, 1, + 11, 11, -19, -2, 9, 17, -37, 11, 10, 9, -16, -12, 27, -11, -22, 16, + 24, -48, 25, -1, -3, 4, -20, 13, 39, -72, 34, 1, 2, -6, 4, -1, + -8, 2, -8, 18, -10, -1, -5, 19, -30, 5, 30, -16, -26, 36, -26, 3, + 21, -27, 10, 4, -10, 0, -4, 15, 9, -41, 32, -11, 2, -11, 15, -3, + -7, -8, 16, -3, -21, 23, -2, -9, -4, -2, 20, -5, -37, 49, -20, -6, + -9, 17, 17, -36, -8, 40, -24, -5, 3, 8, 5, -12, -6, 15, 2, -27, + 28, -4, -23, 16, 5, -1, -26, 29, 11, -38, 22, -12, -8, 38, -34, -3, + 10, 4, -2, -5, -8, 24, -16, -20, 21, 1, -7, 11, -7, -4, -15, 15, + 15, -21, -6, 10, -1, 17, -45, 23, 29, -42, 2, 18, -5, -6, -1, 22, + -20, -19, 16, 21, -20, -18, 23, 2, 5, -41, 36, 10, -34, 12, 12, -25, + 11, 1, 6, -6, -11, 20, -11, 10, -11, -12, 13, 8, -21, 5, -1, 14, + 3, -26, 5, 27, -39, 18, 7, -27, 34, -20, 13, -20, 7, -4, 25, -23, + -16, 7, 47, -35, -29, 37, 10, -35, 4, 12, -1, 0, -15, 25, -23, -12, + 35, 7, -51, 28, -1, 16, -33, 5, 27, -21, 2, -5, 13, -3, 0, -20, + 27, -30, 8, 16, -4, -13, 14, -15, 19, -12, -6, 8, -9, 19, -27, 4, + 20, -9, -12, 21, -37, 41, -22, 1, 1, 13, -33, 20, 14, -30, -2, 22, + 21, -51, 3, 38, -7, -35, 17, 6, 11, -43, 33, 9, -36, 10, 31, -24, + -13, 16, -6, 24, -36, -1, 16, 19, -45, 20, 11, 2, -30, 31, -21, -14, + 29, -4, -12, 3, -6, 9, 15, -37, 20, -4, 8, -18, 12, -7, 17, -8, + -12, -9, 23, 8, -28, 1, 29, -19, -18, 27, -2, -8, -28, 44, -4, -36, + 15, 33, -30, -13, 13, 14, -20, -7, 25, -11, -5, -8, 21, -1, -8, -37, + 50, 1, -53, 27, 28, -21, -10, 4, 16, -24, 10, 6, -12, 0, 2, 6, + 1, -13, 2, 21, -26, 3, 13, -19, 10, 9, -18, -3, 22, -18, -1, -2, + 14, -1, -23, 21, -6, -2, -9, 20, 5, -35, 1, 34, -21, -16, 22, 1, + -8, -5, 1, 18, -12, -23, 18, 5, -17, -7, 37, -6, -35, 6, 47, -44, + -7, 20, 5, -10, -23, 35, -6, -12, -12, 39, -27, -10, 9, 21, -21, -6, + 2, 5, 1, 6, -28, 17, 20, -31, -3, 15, 7, -26, 31, -40, 43, -32, + 23, -19, 11, -22, 26, -6, -1, -25, 33, 2, -25, -7, 9, 26, -16, -30, + 29, 20, -47, 13, 16, -9, -19, 18, 23, -32, -17, 32, 21, -38, -13, 14, + 43, -66, 19, 23, 5, -50, 47, -20, 2, -11, 22, -5, -6, -21, 4, 38, + -15, -32, 12, 35, -35, -4, 7, 18, -17, -1, -7, 6, 5, 0, 0, -7, + 0, -8, 21, -10, 5, -28, 30, 3, -17, -29, 57, -16, -17, -10, 28, -9, + -20, 26, -12, 3, -20, 27, -3, -7, -42, 65, -9, -45, -3, 63, -33, -11, + -6, 28, -17, -1, -6, 6, 7, -12, 0, 25, -21, -30, 54, -9, -37, 1, + 28, 7, -42, 18, 11, 17, -46, 24, -9, 27, -38, 22, -20, 23, -21, 11, + -6, 42, -71, 20, 32, -11, -43, 44, -3, -4, -27, 12, 24, -8, -18, -8, + 30, -19, -23, 44, -8, -30, 0, 45, -39, 0, -1, 28, -16, -17, -15, 44, + -13, -11, -13, 36, -24, -11, 12, 17, -30, 8, 17, -10, -18, 9, 22, -18, + -15, 3, 25, -25, 11, -6, 5, 7, -18, -3, 15, -1, -17, 8, 28, -32, + -17, 36, 8, -41, 12, 7, 13, -22, -14, 18, 41, -57, -1, 25, 10, -40, + 18, 11, -8, -23, 25, -16, 37, -45, 17, 10, 2, -60, 64, -15, -3, -16, + 22, -9, 9, -27, 30, -7, -21, 3, 20, -10, 6, -12, 15, -19, 14, -19, + 3, 22, -8, -29, 37, -28, 29, -26, 11, -15, 15, -17, 21, -26, 18, 5, + -5, -11, 2, 16, -10, -10, -5, 29, -30, 4, 3, 18, -21, 4, 1, 8, + -13, -10, 1, 40, -35, -26, 44, 5, -38, 8, 30, -24, 0, -1, 0, 12, + -18, -1, 18, -8, -28, 39, -18, 24, -35, 24, -36, 46, -41, 12, -3, 24, + -37, 31, -28, 32, -16, 2, -27, 39, -34, 7, 24, -19, -6, 14, -10, -1, + 14, -16, -4, 25, -26, -4, 8, 22, -40, 33, -30, 22, -15, 36, -63, 39, + 1, 10, -54, 36, 9, 5, -51, 49, -13, 5, -7, -7, 15, -9, -10, 2, + 12, -18, 6, 3, 18, -29, 9, 10, -10, 1, -20, 20, -3, -1, -13, 21, + -26, 41, -36, 2, 23, -23, -10, 39, -41, 17, -10, 8, 7, -13, 23, -54, + 66, -26, -50, 54, 17, -66, 59, -46, 30, -10, 6, -8, -18, 19, 16, -32, + 12, 6, -2, 3, -36, 33, -6, -7, 12, -16, 6, 14, -21, 14, 16, -58, + 37, 3, 0, -35, 44, -16, 17, -38, 28, -14, 25, -45, 28, -21, 32, -31, + 11, 17, -24, 11, 5, -24, 18, -6, -3, 0, -3, 21, -33, 24, 20, -78, + 66, -8, -24, 3, 17, -14, 24, -41, 34, -25, 27, -32, 17, -5, 13, -26, + 28, -29, 22, -8, -16, 33, -30, 2, 25, -27, 1, 31, -36, -7, 31, -8, + -12, -5, 17, -7, 5, -26, 32, 1, -18, -16, 27, -7, -10, 2, 21, -42, + 30, -3, -19, 33, -40, 19, 6, -13, -5, 17, -10, 28, -63, 40, 6, -10, + -9, 7, -3, 12, -20, -1, 17, -1, -6, -14, 18, 1, -19, 12, 5, -9, + -2, -14, 33, -3, -44, 51, -17, -6, -16, 36, -35, 29, -31, 31, -24, 15, + -23, 33, -35, 20, -4, -1, -19, 27, -1, -29, 25, 1, -20, 25, -23, -13, + 62, -50, -18, 43, -20, 1, -4, 16, -18, 4, -16, 36, -42, 42, -42, 38, + -28, 9, -10, 31, -40, 30, -39, 30, 8, -28, 11, 9, -7, -6, -8, 10, + 22, -36, -5, 26, 4, -41, 30, 12, -11, -10, -14, 37, -29, 3, -6, 9, + -5, 15, -30, 40, -26, 12, -25, 25, -21, -12, 46, -17, -39, 47, 7, -57, + 45, -14, 1, -13, 21, -21, 14, -7, 7, -11, 18, -34, 25, 7, -28, 22, + 1, -12, 11, -24, 4, 38, -44, 17, 2, -12, 19, -17, 0, 9, 17, -55, + 29, 3, 3, -27, 48, -38, 16, -17, 24, -19, 26, -49, 29, 9, -18, -25, + 50, 2, -31, -20, 43, -3, -35, 23, 13, -34, 9, 20, -15, -8, 29, -37, + 29, -21, 4, -8, 36, -52, 29, -8, 6, -18, 35, -34, 22, -21, 10, 5, + -11, -13, 35, -26, -3, 12, -17, 13, 1, -12, -4, 24, -18, -6, 18, -7, + -13, 17, -4, -30, 48, -41, 10, 34, -39, -22, 73, -48, -12, 12, 22, -14, + -31, 18, 29, -17, -21, 22, -3, -8, -12, 25, -11, 13, -41, 36, -3, -2, + -27, 37, -6, -36, 17, 18, -7, -10, 4, -5, 10, -21, 13, 15, -21, 2, + -1, -5, 8, -1, -16, 29, -24, 14, -18, 26, -24, 17, -26, 21, -18, 24, + -49, 82, -52, -11, 36, -22, -17, 30, -21, 1, 1, -1, 8, -2, -7, 2, + 17, -9, -36, 37, -5, -15, -4, 27, -20, 11, -31, 46, -18, -13, -11, 58, + -67, 19, -4, 40, -43, 9, -14, 41, -32, -16, 46, -19, -13, 5, -5, 6, + 2, -16, 10, -9, 18, -13, 3, 24, -37, 11, 1, 0, -8, -9, 28, -1, + -41, 40, -10, 6, -13, 1, -11, 30, -28, -10, 30, 1, -36, 17, 28, -54, + 51, -24, 1, -6, 6, -12, 33, -48, 23, 18, -17, -23, 27, 11, -23, -13, + 27, -7, -1, -24, 35, 3, -48, 35, 8, -20, -3, 3, 16, -11, 8, -35, + 32, 7, -27, -22, 81, -85, 36, -7, 16, -16, 2, 0, 13, -28, 12, -16, + 24, 6, -25, -14, 47, -15, -25, 3, 37, -41, -5, 32, -25, 11, 6, -16, + 25, -34, 14, 8, 13, -52, 30, 6, 13, -56, 56, -27, 13, -11, -6, 16, + -12, -1, 18, -40, 18, 19, -13, -11, 7, -2, 9, 10, -39, 9, 46, -48, + -18, 59, -32, -3, 14, -10, 10, -13, 10, -13, 14, -11, -10, 5, 31, -43, + 10, 23, -16, 3, -29, 50, -23, -19, 16, 15, -19, 3, -20, 39, -19, -14, + -6, 54, -44, -12, 18, 30, -56, 28, -15, 22, -16, -15, 31, -8, -9, -1, + 1, 1, 2, -8, 9, 10, -43, 41, -9, 8, -48, 62, -30, -9, 13, 6, + -24, 32, -31, 8, -4, 16, -27, 27, -19, -1, -6, 37, -40, 14, -3, 0, + 25, -59, 34, 18, -18, -21, 17, 13, -11, -8, -11, 43, -40, 1, 6, 24, + -37, 10, 14, -4, -12, -2, 17, 11, -40, 10, 16, 17, -51, 24, 14, -4, + -31, 22, 18, -32, 15, -24, 46, -38, 9, 2, -2, 14, -15, -12, 15, 3, + -28, 29, -7, -6, 13, -7, -6, 2, 3, -17, 28, -28, -9, 37, -17, 0, + 3, 10, -19, -5, 19, -17, 12, -25, 30, -19, 8, -27, 49, -15, -27, 9, + 10, 7, -31, 6, 30, -12, -45, 41, 24, -42, -1, 28, -2, -38, 29, -18, + 23, -4, -43, 35, 26, -54, 23, 7, 6, -30, 17, -14, 32, -40, 24, -13, + 17, -15, -11, 16, 16, -20, -26, 47, -10, -26, -6, 41, -19, -22, 36, -41, + 33, 5, -32, 12, 28, -51, 19, 27, -40, 7, 35, -34, 9, -22, 42, -20, + -15, -3, 43, -55, 15, 23, -10, -11, 3, 14, -32, 31, -26, 21, 7, -44, + 15, 40, -22, -41, 54, -17, -17, 8, -6, 10, 11, -17, -6, 15, -2, -20, + 31, -19, 4, -17, 22, 0, 2, -36, 39, 0, -31, 23, -38, 59, -15, -29, + -13, 69, -50, -22, 43, -11, -16, 0, 16, -9, -10, 13, 5, -8, -18, 27, + -8, -2, -12, 13, -1, -16, 16, -18, 27, -11, -19, 39, -28, -26, 28, 36, + -85, 72, -40, 24, -10, 0, -9, 30, -29, -11, 22, -13, -7, 23, -10, -14, + 6, 13, -15, 22, -31, 12, 0, 0, -3, -15, 19, 14, -21, -22, 27, 35, + -72, 36, -3, 18, -54, 50, -29, 38, -47, 14, 19, -11, -25, 27, 9, -23, + -2, 2, 16, -6, -24, 22, 10, -27, 7, 16, -30, 11, 24, -40, 31, -28, + 29, 1, -28, 7, 17, 3, -45, 40, -11, -7, 4, 19, -45, 24, 24, -50, + 48, -35, 11, 9, -12, -14, 30, -23, 8, 7, -15, -7, 53, -59, 13, 5, + 15, -46, 49, -48, 57, -36, -20, 34, 1, -10, -15, 15, 20, -36, -9, 35, + 6, -39, 7, 14, 27, -81, 70, -21, 5, -22, 21, -6, 1, -13, 19, -19, + 4, -10, 35, -43, 31, -3, -7, -15, 40, -56, 33, -1, -33, 51, -35, -2, + 24, -18, 5, 0, 4, -16, 10, -6, 9, -28, 37, -38, 45, -35, 0, 37, + -38, 7, 19, -32, 3, 17, -2, -23, 19, 15, -23, 5, -2, 13, 1, -37, + 8, 59, -80, 26, 13, 15, -31, -8, 30, -7, -7, -19, 22, -2, -9, -2, + 12, -7, 3, 1, -25, 47, -53, 35, -5, -27, 21, 15, -25, 13, -24, 42, + -41, 19, 2, -13, 1, 23, -40, 37, -45, 46, -8, -41, 44, -11, -17, 23, + -9, -20, 22, -3, -15, 22, -23, 19, -7, 2, -34, 65, -56, 7, 28, -8, + -37, 37, 3, -8, -34, 39, -11, 9, -29, 6, 35, -14, -49, 48, 5, -25, + 5, -25, 66, -47, -9, 28, -7, -12, 0, 17, -20, -2, 21, -12, -23, 54, + -50, 20, 7, -20, 7, -2, 3, 4, -26, 26, -6, -14, 15, -3, -10, 12, + -10, -4, 23, -33, 14, -12, 38, -55, 36, 0, -6, -5, 0, -4, 7, 0, + -14, 2, 8, -11, 13, 5, -33, 41, 4, -62, 40, 8, -6, -8, -31, 52, + -4, -44, 25, 20, -18, -24, 32, -11, -9, -4, 30, -37, 34, -31, 7, 30, + -29, -14, 28, -10, -9, 6, 0, -5, 14, -9, -3, -2, 10, -22, 29, -22, + -2, 6, -5, 16, -25, 6, 27, -19, -9, -11, 29, -13, -5, -6, 16, 5, + -20, -1, 30, -20, -8, 7, -8, -2, 3, 14, -9, -24, 35, -7, -14, -12, + 32, -5, -18, -15, 35, -7, -13, -1, -4, 27, -20, -30, 58, -15, -29, 9, + 15, -16, -3, 1, 4, 5, -4, -11, 17, 3, -29, 28, -10, -18, 20, -7, + -2, 4, 2, -17, 22, -3, -31, 23, 23, -32, -14, 34, -3, -14, -13, 11, + 21, -26, -16, 36, -7, -13, 15, -8, -3, -1, -11, 15, -8, -4, -4, 24, + -21, 1, 11, 3, -22, 5, 15, -24, 0, 37, -31, 7, -18, 15, 16, -15, + -19, 26, 0, -10, -26, 31, 6, -19, -6, 21, -19, 20, -13, -3, 13, -2, + -32, 24, 2, -8, -10, 36, -29, -10, 19, 10, -25, 5, -9, 31, -23, -21, + 21, 26, -25, -9, -5, 35, -17, -34, 17, 42, -44, -11, 30, 11, -40, 18, + 8, -6, -11, 11, -26, 39, -18, -23, 37, -12, -32, 45, -8, -22, 5, 16, + -15, -10, 6, 17, -15, -3, 9, -22, 41, -22, -25, 29, 5, -30, 6, 12, + 17, -32, 7, 20, -26, 9, 9, -10, 7, -17, 10, 11, -16, -7, 12, 5, + -4, -26, 25, 24, -46, -4, 50, -39, -11, 8, 35, -36, 2, -9, 33, -7, + -22, -26, 76, -37, -41, 33, 28, -43, 14, 6, 2, -8, 2, -20, 34, -19, + -2, -4, 15, -6, -23, 28, -3, -32, 33, -16, 7, -11, 14, 9, -10, -30, + 35, -25, 17, -14, 1, 14, 12, -38, 16, 15, -7, -30, 15, 18, -24, -6, + 47, -38, 6, 7, -9, -2, -3, 1, 12, -8, -23, 20, 35, -47, -14, 51, + -9, -48, 19, 20, 0, -25, -2, 20, 16, -29, -25, 60, -17, -23, -8, 31, + -4, -30, 12, 20, -14, -4, -1, 17, -11, -9, 7, 7, -17, 1, -12, 25, + -5, -20, 15, 19, -29, 2, 5, 11, -19, -18, 31, 1, -27, 18, -17, 51, + -53, -2, 29, 4, -37, 17, 11, -11, -23, 41, -17, -10, 13, -4, -8, 18, + -27, 17, 1, -19, -7, 51, -37, -28, 53, 4, -47, 5, 18, 17, -32, -8, + 14, 36, -46, 3, 11, 11, -24, 4, 0, 16, -7, -26, 25, 20, -44, 7, + 20, -12, 2, -14, 4, 33, -38, 1, 8, 20, -34, -12, 61, -46, -19, 44, + -10, -4, -18, 12, 12, -8, -26, 16, 22, 2, -51, 18, 53, -56, -5, 30, + -9, -22, 32, -11, -18, 18, 13, -25, -7, 8, 9, 3, -20, 1, 32, -27, + -9, 5, 19, -20, -13, 18, 8, 3, -35, 22, 31, -47, -2, 16, -8, 15, + -10, -22, 54, -20, -23, -6, 51, -52, -13, 48, -23, -11, 28, -30, 38, -6, + -50, 28, 33, -58, 2, 34, 16, -53, -1, 55, -13, -42, 15, 23, -7, -33, + 13, 21, -14, -6, 2, -2, 27, -43, 27, 11, -19, -16, 26, -16, -4, 16, + -17, 1, 20, -17, 8, -17, 6, 26, -25, -24, 40, -13, 6, -14, -14, 29, + 3, -32, -5, 46, -21, -28, 38, -30, 6, 28, -47, 3, 65, -67, -5, 61, + -34, -27, 31, 12, -30, -7, 11, 19, 0, -43, 18, 47, -52, -20, 52, -14, + -9, -10, -5, 55, -45, -29, 55, 16, -83, 28, 36, -23, 6, -8, -13, 37, + -17, -30, 32, -9, -6, 10, -19, 16, 4, 9, -35, 22, -1, -17, 3, 8, + 10, -10, -21, 40, -27, -5, 16, -6, -27, 47, -23, -26, 48, -18, -19, 14, + -1, -9, 5, 1, -20, 58, -57, -14, 55, -16, -40, 37, -6, 11, -19, -22, + 43, 2, -55, 27, 37, -38, -29, 58, -6, -11, -22, 4, 26, -7, -67, 67, + 21, -56, 19, 15, -5, 0, 2, -41, 37, 10, -65, 49, 8, 1, -19, 1, + 9, 8, -20, -9, 22, -14, -3, 4, -1, 13, -6, -11, 15, -8, -15, 13, + 16, -38, 14, 24, -39, 20, 9, -17, 14, -15, 7, 3, -12, -3, 30, -25, + -24, 43, -1, -40, 18, 17, 0, -22, -14, 31, 20, -68, 35, 32, -43, -9, + 35, -16, 4, 2, -35, 35, 27, -81, 40, 31, -21, -30, 29, -12, 13, 10, + -42, 26, 17, -33, -1, 16, 12, -29, 6, 4, 21, -27, -9, 39, -6, -54, + 40, -14, 15, -4, -17, 20, 4, -18, -4, 23, -24, -3, 30, -41, 15, 17, + -4, -29, 19, 4, -9, -10, 12, 17, -21, -7, 26, -19, -17, 17, 3, 1, + -3, -30, 47, 16, -62, -4, 68, -29, -54, 43, -1, -4, 20, -42, 22, 34, + -32, -43, 63, -12, -26, 8, -6, 10, 22, -66, 55, 25, -65, 15, 9, 21, + -22, -28, 36, 5, -16, -51, 102, -49, -12, 6, 21, -12, -23, 24, -15, 11, + -14, -8, 31, 4, -53, 64, -35, 13, -28, 23, -23, 22, -16, 13, -22, 23, + 27, -51, -8, 41, 6, -66, 36, 13, 4, -26, 7, 11, 9, -34, 0, 35, + -21, -15, 10, 34, -57, 60, -69, 60, -22, 1, -27, 27, 14, -27, 1, -13, + 35, -2, -51, 36, 35, -49, 5, -1, 31, -42, 25, -26, 34, -7, -60, 98, + -46, -22, -1, 49, -45, -2, 10, 26, -33, 25, -36, 37, -19, 4, -3, -7, + 9, 7, -8, -29, 48, -23, 0, -33, 45, 0, -23, -16, 47, -7, -31, -9, + 38, -2, -36, 18, -8, 43, -55, 16, -1, 41, -72, 54, -35, 24, 4, -46, + 47, -11, 6, -40, 24, 10, 8, -38, 16, 16, 24, -98, 80, 2, -28, -28, + 44, 11, -47, 31, -7, 35, -42, -25, 41, 12, -64, 34, 14, -2, -21, 24, + -14, 11, -3, -24, 22, -28, 46, -51, 38, -22, 35, -40, 2, 11, 22, -48, + 23, -9, 34, -35, -24, 52, -7, -37, 9, 36, -21, 0, -32, 61, -44, 6, + -1, -16, 41, -28, 19, -37, 49, -11, -38, -8, 65, -53, 9, -21, 59, -37, + 8, -33, 59, -13, -80, 67, 19, -39, -28, 70, -21, -25, -3, 23, 17, -29, + -44, 83, -41, 0, -23, 53, -27, -12, 21, -19, 21, -21, 13, -4, -12, -5, + 38, -58, 34, 10, -22, -16, 47, -8, -39, 19, 12, 4, -46, 39, -24, 48, + -69, 45, -18, 10, -5, -2, -4, 10, -5, 7, -17, -3, 20, 0, -40, 26, + 40, -64, 11, 34, 1, -49, 11, 35, -22, -14, -32, 98, -47, -37, 9, 76, + -70, -8, 7, 63, -92, 56, -49, 77, -64, 2, 41, -28, -25, 37, 0, -26, + 35, -40, 16, 3, 14, -46, 22, 18, -6, -9, -11, 22, 26, -44, -46, 94, + -60, 18, -37, 69, -33, 5, -20, 42, -32, -20, 24, -1, -10, -12, 39, -31, + 13, 1, 9, -47, 42, -26, 39, -73, 48, 48, -73, -13, 56, 14, -78, 38, + 11, 12, -50, 8, 39, 3, -79, 73, 2, -25, -17, 23, 27, -58, 26, -37, + 67, -49, 11, -12, 62, -82, 64, -41, 3, 26, -17, -45, 55, -4, -22, 10, + -2, 38, -54, 8, 5, 47, -79, 7, 54, -7, -64, 41, 49, -73, 29, -24, + 54, -51, -4, 14, 33, -84, 82, -46, 17, -25, 57, -44, -2, 11, 8, 15, + -66, 46, 19, -25, -44, 58, 10, -38, -23, 77, -48, -3, -12, 24, 24, -70, + 37, 21, -15, -48, 81, -66, 44, -29, 6, 4, 9, -30, 31, -24, 5, 19, + -51, 34, 21, 11, -92, 78, 19, -44, -54, 104, -47, -8, -19, 29, 45, -78, + 6, 55, -11, -75, 66, -10, 8, -38, 24, 10, 4, -57, 66, -20, -25, 20, + 6, 9, -71, 100, -60, -6, 8, 28, -37, 29, -42, 78, -58, -22, 42, 10, + -69, 34, 33, -36, 29, -54, 81, -54, 0, 7, 1, -19, 22, -14, 4, -3, + 32, -13, -59, 86, -54, 4, 0, 21, -35, 43, -68, 91, -31, -53, 38, 48, + -72, -15, 50, 3, -11, -72, 96, -1, -49, -23, 81, -21, -57, 15, 63, -67, + 5, 25, -27, 34, -48, 49, -26, 12, -33, 66, -73, 14, 35, -20, -27, 45, + -24, 12, -12, 0, 24, -50, 33, -26, 45, -65, 47, -7, -4, -9, 19, -19, + -2, 15, -17, 30, -39, 25, 2, -3, -57, 109, -86, 10, 14, 31, -53, 7, + 32, 5, -44, -20, 84, -35, -34, -6, 99, -97, 1, 23, 40, -65, 15, 9, + 36, -45, -22, 55, 4, -55, -3, 73, -80, 63, -49, 28, 2, -10, -19, 24, + -13, 8, 1, -15, 5, 22, -4, -57, 72, -41, 16, -45, 76, -57, 30, -26, + 38, -16, -34, 32, 12, -53, 22, 47, -46, -4, 6, 45, -65, 32, -21, 45, + -44, -22, 69, -44, -16, 29, 19, -59, 40, -7, 42, -77, 39, -4, 29, -74, + 27, 38, -12, -60, 69, 7, -32, 1, -9, 50, -56, -15, 19, 47, -75, 44, + 5, -22, 27, -7, -22, 0, 23, -30, 1, 4, 33, -44, 29, -24, 57, -67, + 17, 18, 4, -59, 32, 48, -72, 28, -2, 13, -10, -21, 16, 58, -117, 85, + -14, -5, -34, 21, 29, -27, -20, 31, 23, -49, 16, -14, 51, -74, 24, 38, + -38, -16, 56, -33, -7, 3, 0, 36, -80, 49, 23, -19, -48, 76, -61, 43, + -41, 27, -11, 23, -30, 8, 3, 15, -14, -22, 16, 3, 15, -39, 11, 38, + -13, -70, 88, -41, 2, 4, -30, 80, -84, 15, 37, -6, -61, 58, -19, 27, + -72, 64, -6, -16, -30, 59, -21, -21, -12, 44, 22, -101, 78, -10, -16, -11, + 20, -21, 31, -36, 37, -18, -20, 46, -24, -23, 10, 21, -36, 32, -38, 68, + -50, 12, -6, 19, -33, 14, -16, 20, -11, -14, 47, -59, 56, -14, -27, 5, + 29, -43, 49, -96, 106, -35, -41, 28, 35, -30, -29, 37, 12, -11, -58, 79, + -31, -16, -11, 43, -13, -25, 3, 71, -76, -13, 64, -39, 3, -45, 66, -13, + -1, -45, 80, -40, 6, -29, 26, -12, 6, -19, 21, -4, 9, 0, -37, 44, + -28, 11, -22, 19, 7, 1, -45, 60, -13, -42, 32, -16, 31, -50, 35, 10, + -22, -23, 60, -62, 21, -2, 39, -49, -4, 24, 30, -53, -23, 66, -33, 2, + -34, 69, -33, -10, 7, 24, -51, 28, 0, 9, -24, -3, 38, -24, -16, -9, + 68, -81, 38, -16, 35, -34, -4, 16, 20, -43, 10, 7, -3, 14, -30, 38, + -39, 38, -20, -12, -20, 78, -79, 22, -4, 44, -48, -6, 37, -2, -25, -24, + 60, -41, 15, -30, 50, -43, 7, 9, 27, -64, 45, 5, -15, -17, 1, 49, + -56, 3, -11, 69, -78, 37, -5, 38, -60, 26, -2, 9, -51, 53, -20, -3, + 9, -1, 38, -74, 40, 6, -13, -54, 69, -24, 6, -22, 31, 0, -17, 12, + -13, 8, -9, 20, -53, 56, -27, 29, -63, 41, 8, 11, -73, 59, 15, -25, + -21, -1, 61, -69, 10, 17, 28, -59, 34, -14, 32, -54, 17, 22, -11, -47, + 63, 7, -56, 46, -28, 50, -96, 60, 2, 0, -37, 36, -11, 15, -38, 41, + -19, -31, 46, -12, -25, 9, 49, -67, 47, -48, 51, -30, -15, 23, 19, -43, + 8, 17, 4, -11, -29, 54, -48, 38, -28, 10, -9, 38, -48, 27, -47, 55, + 3, -59, 22, 41, -5, -59, 38, 5, 31, -101, 72, 11, -36, -18, 54, -25, + -1, -30, 54, -28, -34, 61, -27, 13, -46, 55, -21, -10, -21, 52, -34, -8, + 30, -21, 20, -11, -21, 22, -2, -46, 79, -84, 60, -9, 13, -57, 51, 2, + -16, -38, 34, 15, -23, -7, -6, 53, -38, -22, 29, 23, -63, 65, -34, -21, + 34, -7, -19, -8, 24, 13, -8, -63, 110, -56, -8, -37, 79, -56, -3, -3, + 62, -57, 19, 9, 8, -20, -29, 27, 13, -28, -19, 79, -80, 58, -31, 24, + -16, -35, 46, 0, -52, 36, 21, -29, 16, -23, 26, -29, 38, -42, 26, -41, + 60, -29, -16, -4, 42, 7, -85, 53, 47, -54, -29, 67, -53, 39, -58, 45, + -5, 5, -37, 61, -56, 27, 17, -40, 1, 15, 17, -43, 19, 4, 30, -49, + 12, -1, 49, -64, -27, 96, -41, -47, 45, 8, -38, 35, -50, 74, -81, 54, + -14, 24, -64, 57, -5, -25, -19, 27, 16, -27, 4, 16, 2, -25, 26, -31, + 22, -35, 56, -54, 0, 55, -23, -29, 9, 38, -38, 12, -41, 74, -28, -29, + -3, 61, -71, 36, -32, 43, -19, -14, 21, 0, -10, -19, 32, -42, 20, 11, + 23, -94, 107, -13, -53, 5, 35, -17, -11, -25, 32, 40, -76, 29, 32, -9, + -65, 80, -42, 6, -22, 42, -27, -2, 10, -2, 13, -41, 32, 10, -17, -26, + 53, -50, 40, -42, 30, -19, 41, -50, 33, -20, -1, 40, -67, 8, 29, 15, + -58, 25, 32, 15, -81, 46, 14, -8, -51, 24, 40, -44, 17, 10, 2, -26, + 47, -68, 49, -49, 50, -27, -3, -20, 84, -62, -32, 52, 12, -52, 0, 42, + -30, 24, -47, 45, -16, 11, -51, 74, -47, -9, 45, -19, -18, -5, 41, -39, + 11, -33, 56, -20, -14, -8, 64, -85, 60, -23, -13, -3, 33, -20, -25, 57, + -34, 2, -23, 42, -21, 3, -49, 85, -35, -27, 1, 54, -34, -31, 24, 15, + 6, -45, 54, -30, 12, -27, 40, -61, 39, 1, -5, -18, 17, 14, 7, -33, + -27, 83, -44, -40, 21, 66, -82, 32, -7, 33, -54, 27, 3, 2, -13, -15, + 52, -57, 14, 14, -6, -27, 54, -45, 23, -11, 16, -27, 27, -33, -3, 36, + -46, 47, -15, -8, -7, 67, -93, 12, 34, 17, -73, 32, 15, 29, -44, -17, + 47, 2, -40, -31, 81, -43, 3, -24, 52, -32, 4, 1, 20, -48, 20, 40, + -68, 23, 14, 19, -64, 46, -8, 17, -48, 55, -29, 23, -59, 48, -2, -27, + 11, 1, 21, -30, 25, -24, 29, -41, 21, 0, -15, -17, 64, -47, 1, 31, + -22, 2, -11, 22, -56, 69, -53, 32, -30, 31, -16, 32, -68, 29, 42, -39, + -49, 80, 17, -74, 17, 0, 55, -88, 25, 29, 14, -72, 56, 0, 0, -33, + 20, 5, -34, 35, -33, 45, -37, 23, -9, 10, -54, 67, -22, -13, -15, 41, + -14, -16, 8, 0, 19, -51, 56, -51, 39, -20, 19, -34, 26, -18, 19, -31, + 23, 0, 12, -31, 7, 45, -65, 22, 4, 24, -73, 74, -13, -34, 18, 23, + -16, -25, -2, 40, 5, -84, 76, -4, 6, -74, 75, -7, -10, -51, 60, -13, + 0, -45, 50, 18, -57, 20, 21, -7, -26, 47, -51, 28, -19, 12, -13, 3, + -1, 20, -23, 1, 28, -18, 3, -41, 67, -72, 34, -11, 33, -47, 47, -9, + -20, -2, 28, -21, -27, 11, 26, -15, -25, 57, -44, 46, -67, 49, -5, -30, + 1, 42, -36, -9, 22, 7, -13, -34, 67, -29, -16, -26, 84, -49, -21, -11, + 77, -53, -43, 62, 0, -3, -32, 23, 13, -5, -69, 88, -42, 7, -17, 37, + -35, 27, -6, -13, -11, 31, -17, -28, 45, -17, 8, -32, 41, -48, 39, -35, + 41, -16, -28, 41, -3, -13, -26, 23, 12, -22, -50, 104, -57, 9, -28, 67, + -53, -7, 0, 45, -41, -22, 50, -8, -21, -9, 38, -19, -18, -2, 55, -76, + 38, -12, 39, -49, -14, 64, -24, -45, 25, 50, -66, 23, -15, 32, -36, 32, + -46, 44, -14, 2, -16, 22, -7, -11, 14, -28, 21, 4, -10, -18, 63, -66, + 30, -20, 36, -35, -16, 26, 12, -37, 6, 50, -35, -15, 6, 48, -64, 4, + 12, 46, -85, 33, 12, 25, -49, -11, 77, -53, -18, 19, 29, -41, -1, 3, + 39, -70, 55, -6, -1, -23, 38, -22, -12, 1, -11, 36, -39, 5, 15, 33, + -55, 32, -8, 6, -37, 39, -32, 4, 27, -23, 11, -1, 10, -28, 19, -24, + 52, -69, 27, 21, 11, -72, 52, 17, -35, -13, 16, 33, -44, 4, 19, 18, + -60, 13, 35, 12, -93, 82, 9, -35, -20, 26, 40, -74, 14, 18, 28, -66, + 37, 4, 9, -43, 34, -15, 17, -35, 38, -11, -14, 14, -5, 2, -36, 54, + -35, 2, 1, 29, -35, 9, -4, 24, -32, -5, 31, -19, -17, 28, 34, -86, + 49, 13, -16, -52, 71, -29, 3, -30, 51, -1, -36, 6, 25, 4, -75, 56, + 10, -21, -18, 37, -16, 17, -53, 60, -7, -38, -9, 63, -18, -70, 67, 1, + -19, -32, 50, -20, 11, -23, 24, -10, -3, -21, 32, -26, 7, 12, -19, 35, + -29, 26, -41, 32, -22, 14, -43, 41, 7, -16, -24, 57, -20, -35, 25, 7, + -11, -20, 31, -18, 10, -34, 44, -7, -22, -9, 49, -33, -18, 26, -4, 12, + -63, 51, 11, -16, -40, 80, -28, -37, 5, 61, -78, 22, 16, -3, -10, -5, + 26, -8, -2, -43, 68, -42, -24, 39, 11, -31, 15, -9, 18, -20, -1, 7, + -17, 26, -30, 31, -31, 42, -28, -1, -15, 49, -51, -2, 26, 3, -12, -11, + 7, 22, -9, -51, 70, -27, -14, -13, 53, -37, -12, 9, 44, -57, -14, 51, + -6, -27, -10, 60, -55, 2, 14, 18, -45, 32, -19, 29, -27, -12, 31, 14, + -54, 17, 41, -62, 51, -40, 40, -40, 12, -8, 28, -39, 16, 10, 10, -46, + 37, 12, -42, 17, -4, 2, -17, 35, -34, 38, -30, 21, -6, -36, 36, 13, + -56, 14, 53, -36, -13, -1, 61, -64, 7, -3, 54, -63, 5, 14, 34, -67, + 10, 46, -27, -18, 26, 20, -41, 14, -13, 40, -66, 20, 38, -34, -11, 39, + -16, 11, -26, 7, 28, -58, 26, 0, 30, -61, 44, 11, -30, -17, 66, -40, + -33, 35, 6, -21, -2, 9, 16, -13, -39, 79, -71, 27, 9, -9, -29, 28, + 4, -17, 1, 14, 2, -20, -2, 16, 24, -67, 20, 37, -4, -80, 75, 18, + -46, 2, 10, 25, -31, -28, 43, 19, -75, 59, -13, 14, -40, 29, 7, -22, + -20, 44, -20, -16, 10, 32, -21, -42, 61, -19, -29, 12, 39, -55, 32, -4, + 0, -2, -24, 40, -19, -38, 34, 22, -33, 11, -3, 31, -49, 21, -16, 40, + -54, 12, 29, -19, -8, 17, 17, -52, 28, 22, -39, -2, 45, -42, 23, -46, + 51, 11, -68, 26, 55, -34, -44, 45, 9, -19, -43, 57, -16, -5, -9, 40, + -24, -12, 8, 29, -54, -4, 50, -37, 0, 11, 7, -4, 0, -25, 57, -62, + 19, 18, -7, -22, 12, 19, -27, 9, -5, 15, -19, 2, 15, 4, -45, 36, + -5, 8, -48, 60, -13, -35, 36, -19, 21, -24, -7, 23, -24, -22, 73, -58, + -5, 34, 25, -71, 19, 30, 0, -43, -4, 50, -9, -21, -21, 69, -28, -46, + 24, 29, -45, 12, 3, 21, -13, -28, 47, -9, -37, 21, 22, -46, 21, 8, + -1, -32, 42, -22, 14, -27, 19, 16, -29, 3, 17, -1, -39, 28, 21, -42, + 8, 47, -45, 2, -16, 50, -20, -54, 50, 9, -25, -12, 41, -29, 8, -3, + -5, -13, 25, -16, 19, -30, 15, 15, -2, -52, 38, 38, -69, 12, 37, 9, + -54, 10, 36, 5, -79, 27, 57, -35, -40, 48, 21, -41, 13, -3, 10, -29, + 4, 18, 4, -50, 52, 1, -28, -6, 41, -25, -22, 34, -22, 10, -5, 3, + -6, -1, 2, 26, -48, 24, 12, 5, -54, 36, 18, -32, -6, -3, 48, -28, + -21, 22, 35, -63, 6, 43, -28, -27, 42, -7, -22, 6, 21, 8, -56, 31, + 23, -10, -73, 76, 18, -49, -26, 70, -21, -23, -8, 35, 0, -42, 7, 42, + -26, -28, 47, -31, 0, 13, 11, -25, 14, -6, 10, -13, -26, 40, -14, -5, + -8, 42, -36, 1, 15, -10, -34, 47, -24, 5, -22, 38, 14, -39, -10, 53, + -26, -67, 72, 0, -15, -25, 29, 19, -29, -25, 50, -14, -31, 10, 42, -44, + -24, 81, -40, -32, 12, 45, -41, -5, -1, 47, -27, -54, 54, 32, -64, 4, + 26, 1, -1, -41, 44, 4, -22, -22, 47, -30, 7, 5, 3, -37, 45, 1, + -53, 44, -1, -20, 7, 12, -13, 9, -23, 26, -2, -47, 32, 37, -61, 6, + 42, 0, -25, -43, 76, -23, -38, -10, 73, -24, -57, 47, 45, -70, 3, 19, + 7, -19, -8, 10, 24, -12, -36, 66, -60, -1, 50, -32, -19, 8, 26, 2, + -44, 11, 53, -42, -26, 20, 42, -52, 14, 16, -26, -11, 42, -41, 16, 16, + -23, 13, 1, -6, 17, -18, -41, 71, -39, -23, 40, 13, -30, 2, 19, 0, + -39, 10, 24, -15, -25, 12, 66, -81, 6, 47, 9, -69, 12, 47, -9, -36, + -27, 76, 9, -107, 58, 53, -68, 19, -10, 39, -49, 8, 14, -11, -17, 21, + 18, -25, -17, 47, -4, -48, 32, -9, -4, -3, 8, -5, 29, -40, 13, 14, + -31, 24, 7, -48, 27, 37, -61, 22, 15, 7, -46, 17, 10, 22, -45, -9, + 56, 1, -73, 43, 34, -51, -15, 40, 2, -47, 35, 8, 27, -87, 31, 86, + -94, -27, 67, 10, -44, -15, 43, 11, -46, 6, 9, 33, -71, 35, 26, -30, + -18, 37, -18, -9, 20, -15, 1, 5, 9, -2, -23, -11, 50, -42, -3, 24, + 6, -21, 17, -5, -8, 11, -26, 24, -19, -9, 33, 22, -78, 38, 44, -48, + -53, 80, 6, -66, 14, 36, 8, -37, -15, 66, -24, -75, 87, -14, -27, -10, + 45, -12, -38, 13, 33, 7, -67, 20, 75, -55, -67, 85, 8, -52, -11, 45, + -10, 13, -34, 12, 26, -36, 7, -1, -1, -7, 23, -27, 18, 15, -12, -28, + 27, -6, 9, -52, 40, 26, -50, 3, 51, -10, -71, 67, 10, -59, 4, 56, + -27, -20, -19, 58, 6, -81, 38, 49, -39, -39, 47, 14, -25, -40, 54, -2, + -20, -38, 82, -25, -51, 44, 24, -60, 8, 51, -47, -2, 6, 22, 9, -34, + -20, 78, -56, -25, 36, 19, -49, 17, 32, -50, 44, -29, 4, -11, 14, 3, + -13, -11, 19, 13, -24, 28, -32, 33, -37, 39, -61, 119, -76, 120, -70, 99, + -122, 89, -113, 91, -123, 122, -123, 77, 86, -116, 6, -118, 123, -23, 64, -93, + 17, 24, -125, 124, -125, 124, -24, -12, 56, 87, -54, 38, -91, 64, -2, -41, + 126, -127, 20, 8, -48, -62, 127, -128, 88, -43, -18, 86, -100, 44, -32, -26, + 71, -13, 6, 51, -33, -50, 106, -59, 33, 5, -20, 69, -56, 54, -48, -6, + 38, -5, -38, 35, -1, 12, -1, 4, 23, -56, 19, -7, 5, -4, 31, -38, + 3, -12, -9, -25, -7, 24, -32, 17, -21, -22, 24, -20, 6, -18, 0, -15, + 5, -16, 15, 3, 2, -10, 3, 27, -31, 37, -12, 32, -5, 2, -21, 27, + -14, 20, -8, 5, 15, -7, -11, 20, -37, 7, -23, 17, -22, 11, -14, 8, + -44, 39, -52, 26, 3, 14, -10, 51, -45, 29, -19, 19, -3, 41, -21, 46, + -23, 10, 16, -25, 3, 7, -30, 19, -9, -5, -1, 1, -19, 1, -24, -23, + 51, -48, -10, 17, -34, -38, 60, -71, 26, -43, 65, -59, 70, -26, 61, -51, + 63, -51, 42, -25, 58, -36, 31, 10, -14, -9, 8, -18, 8, 4, 8, 7, + 31, -52, 39, -53, 53, -56, 24, 11, 1, -20, -8, -32, -18, -10, -25, 4, + 1, 37, -37, 42, -42, 53, -57, 52, -18, 30, 11, 20, -52, 55, -61, 56, + -50, 24, -26, 38, -42, 36, -1, -43, 58, -46, 6, 18, -35, 31, -36, 28, + -55, 55, -98, 52, -41, 26, -24, 48, -31, 48, -26, 30, 19, -17, 23, -8, + 13, 15, 19, -7, -23, 41, -36, 20, -39, 65, -64, 66, -38, -9, 7, -14, + -10, -3, 6, 15, -19, -40, 53, -67, -11, -12, -25, 23, -11, -12, 46, -48, + 39, -20, 20, -14, 31, -54, 71, -25, 2, -8, -5, -9, 1, 7, 27, 17, + -14, 43, -31, 27, 11, -33, 20, -2, -33, 45, -38, 17, -9, -11, -17, -22, + -19, 20, -25, 4, 29, -35, 14, -17, 1, -7, 19, 2, 16, 32, -3, -17, + 4, 0, -9, 17, 5, -8, 52, -32, 40, -39, -5, -18, 14, -21, 31, 10, + -17, 8, -34, -7, 1, -44, 7, 10, -8, -6, -18, -25, -1, -19, 16, -29, + 62, 6, 9, 21, 0, -14, 4, 5, 20, 13, 27, -1, 18, -5, 21, -31, + 11, 2, -9, -4, 21, -27, 8, -21, -28, -19, 14, -12, 5, -20, 20, -36, + 4, -18, -27, -4, -4, 15, 4, 48, -7, -11, 20, -6, 7, 20, 1, 20, + 0, 35, -35, 28, -37, 7, -43, 21, -22, 23, -18, 12, -22, -13, -20, -11, + 7, 23, -10, 19, -18, 17, -41, 4, -16, -8, 21, 11, -4, 10, 30, -24, + 32, -15, 15, -13, 28, -5, 38, -10, 0, -22, -13, -12, 24, -18, 30, -7, + 4, -16, 27, -28, -3, -1, 18, -14, 31, -24, -3, -13, -19, -36, -2, -31, + 9, -2, -12, 17, 12, -50, 46, -49, 43, -15, 13, 22, 15, -25, 10, -8, + -6, 14, -2, 24, 15, 9, 17, -13, 5, 14, -15, 7, 20, 4, 4, 18, + -16, 3, -47, 31, -46, 19, -24, 5, -19, -1, -42, 14, -44, 18, -7, -1, + 15, 9, -35, 32, -44, 39, -46, 23, -16, 36, -25, 45, -34, 32, -8, 10, + 5, 28, 0, 12, 11, 3, 20, -23, 6, -8, 16, 7, 17, -19, 32, -44, + 3, -8, -21, -8, -5, 2, -29, 2, -3, -19, -14, 3, 7, -23, 10, 1, + 3, 8, 13, -44, 20, 21, -16, 23, 3, 5, 10, -11, 32, -11, 13, -7, + 30, 4, 16, -7, -6, -7, 14, -40, 4, -16, -26, 3, -1, 0, -6, 5, + -50, 37, -27, 18, -16, -14, 6, -1, -4, -15, 8, -12, 14, 9, -22, 42, + -10, 23, -11, 36, -15, 13, 30, 1, 47, -20, 33, -14, -12, 1, -20, -9, + -9, -11, -13, 7, -37, 25, -47, 14, -13, 4, -12, 9, -32, 18, -48, -1, + -35, -1, -7, 35, -20, 53, -4, 34, -7, 13, 19, 9, 30, 6, 45, -22, + 23, -18, -6, -1, 3, -30, 14, -15, 9, -39, 10, -33, -13, -24, 10, 14, + 14, -10, 2, -34, -4, -20, -21, -14, 40, -10, 17, -14, 28, -17, 37, -26, + 69, -15, 38, 2, 21, -25, 37, -61, 13, -9, 5, -17, 18, -41, 22, -57, + -1, -9, -13, 24, -10, 38, -5, 8, -16, -2, 1, 12, -25, -2, -13, 2, + 2, -16, -19, 32, -30, 22, 20, -4, 12, 11, -17, 19, -17, -3, 20, -33, + 65, -27, 32, -14, 8, -8, 13, -19, 9, -2, 7, 33, -40, 18, -18, -18, + 6, -23, -11, -11, -28, 4, -11, -15, -14, -8, -5, 34, -6, 19, 1, -3, + 9, -1, 5, 5, 14, -11, 40, -3, 18, -20, 16, -7, 2, -5, 9, -16, + 9, -17, 0, -17, 4, -17, -3, 3, 8, -14, -19, 12, -21, -7, 1, -2, + -8, 16, 3, -6, 35, -23, 33, -13, 11, 12, 3, -7, 26, -11, 19, -18, + 23, -22, 39, -49, 39, -50, 11, -38, 26, -29, 10, -6, -22, 15, -8, 15, + -37, 36, -43, 39, -43, 18, -26, 1, 11, 4, -2, 9, 7, 2, 7, 19, + 1, 1, -4, 16, -5, 16, -9, -3, 4, -4, -1, -17, 0, 11, 16, -27, + 12, -15, 15, -3, 0, 10, -3, -5, 12, -13, -7, -13, -31, -1, -3, -17, + 15, -31, 25, -10, 15, -1, 2, 4, 10, 7, 32, -13, 7, -22, 2, -10, + 16, 1, -15, 19, -24, 16, -18, -12, 18, -9, 9, 24, -8, 8, 11, 0, + -31, 17, -55, 21, -43, 40, -40, 29, -54, 44, -34, 22, 11, 16, 7, 19, + 21, -6, 2, -7, -16, 22, 0, -1, -4, 5, -8, 26, -42, 4, -6, -21, + 35, -16, 8, 0, -22, -13, 11, -31, 7, -28, 4, 17, -12, -18, -2, -23, + 23, -1, 19, 34, 7, 7, 35, -19, 11, -8, -17, 8, 4, 16, -16, -13, + 9, -15, -5, -1, -6, 7, 3, 11, 1, -7, -24, 21, -31, 36, -3, -10, + 8, 2, -17, 12, -24, 6, -3, 9, 15, 3, 13, -8, -13, -3, 6, -19, + 14, -33, 16, -17, -5, -31, 3, -29, 24, -7, -6, 35, -20, -5, 34, -20, + 25, -3, 10, 25, 8, 14, -13, 0, 1, 17, -33, 51, -38, 45, -32, 39, + -3, -2, -24, 3, -18, 14, -4, -44, 2, -25, -15, -2, -23, 3, -2, -2, + 20, -14, 8, -10, -4, 21, 11, -13, 32, -4, 8, 19, -16, -2, -2, -2, + 14, -2, -1, 27, -26, 20, 11, -13, 10, -3, -7, 12, -13, -3, -30, -16, + 10, -26, -3, -10, -2, -9, 15, -17, 1, -2, -7, 14, -8, 12, -3, -1, + 2, 47, -26, 22, -19, 16, 2, 13, -3, 21, -10, 22, -32, 43, -24, 16, + 0, 5, -2, 12, -44, -12, 1, -26, 1, -36, 5, 2, 9, -17, 20, -37, + 14, -9, -5, 6, -3, -13, 23, -19, 25, -33, 6, 17, 10, 19, 15, -4, + 12, 5, -9, 33, -20, 26, -9, 11, -2, 11, -21, -7, -13, -4, -8, -12, + 0, -10, -9, 8, -33, 9, -26, 8, 6, -8, 12, 7, -8, 0, 7, -16, + 25, -8, 27, 12, 0, 9, -9, 4, -17, 14, -16, 11, -8, 18, -2, 4, + 2, -20, -18, 22, -16, -5, 3, -24, 13, -10, -12, -10, 2, -16, 33, -15, + 21, -15, -4, -19, 29, -22, 18, 2, 20, 12, 18, -22, -7, -16, 7, -19, + 14, 1, -17, 33, -22, 38, -8, 3, -3, 21, -17, 51, -43, 15, -22, -23, + -6, -12, -14, 14, 9, 6, 4, -31, 3, -16, -14, 22, -22, 5, 13, -25, + 17, -2, -18, 7, 1, 5, 36, -16, 23, 4, -15, 29, -20, 10, 1, 24, + 17, 16, -4, -16, -37, -11, 1, -33, 27, -36, 17, -22, 2, -33, 16, -29, + 32, -7, 24, -12, 14, -12, 22, -16, 15, -20, 19, 9, 14, 12, -1, -24, + 13, -6, -1, 32, -19, 24, 12, -26, 4, -31, -38, 18, -16, -13, 3, -14, + -1, 11, -15, 15, 0, -2, 30, -6, 35, -23, 10, -35, 5, -14, 17, -21, + 20, 4, 7, 8, -5, -15, 20, -25, 26, 6, -3, 3, 5, -24, 26, -35, + 4, 0, -6, 13, -23, 8, -25, 1, -2, 9, 3, 17, 4, 0, 13, -15, + 3, -21, -16, 4, -5, -10, 11, -2, 7, 23, -22, 25, -19, 18, 25, -9, + 14, -21, -7, 11, -24, 22, -12, -7, 6, 9, -33, 11, -20, 2, -9, 2, + 3, -13, 12, -15, 23, -21, 16, -16, -2, 8, 13, -12, 18, -10, 16, -12, + 20, -18, 18, -1, 21, -21, 20, -30, -6, 10, -2, 13, -6, -15, 6, 2, + -1, 1, -19, 9, -15, -3, -11, 0, -5, 1, 5, 1, -4, -8, 1, -16, + 23, 0, -23, 2, 8, -6, 38, -4, 2, 13, -17, 31, -4, -8, 22, -14, + 0, 12, -22, 7, -7, 11, 4, -4, -12, -9, -22, 2, -17, -17, -11, 7, + -17, 19, -24, 9, -8, -6, 29, -4, 10, 4, 4, 23, -1, 9, -6, -12, + 23, 16, -6, 33, -29, 12, -7, -10, 17, -4, -18, 21, 0, -14, -2, -20, + -21, 10, -28, 5, -18, -4, 0, -11, 1, 5, -17, 3, 9, 20, 6, 1, + -7, 2, -7, 3, 9, -22, 29, 6, -1, 25, -10, 6, -1, 4, 12, 18, + -13, 28, -11, 6, -15, -14, -22, -7, 5, -14, 1, -16, -12, -5, 5, -9, + 4, -1, -14, 21, -10, -5, 0, -17, -7, 2, -10, 6, 11, 1, 37, -17, + 6, 21, -24, 41, 2, 23, 0, 10, -18, 16, -26, 14, -21, -19, 18, -9, + -14, -1, -9, -14, -3, -7, -10, 7, -7, 19, -11, 15, -25, -3, -6, 2, + 8, -10, 4, 12, -3, 11, -2, -2, 5, 31, -9, 39, -21, 14, -23, 18, + -16, -1, -3, -6, 0, 22, -9, -5, -17, -4, -12, 2, -3, -7, 10, -10, + 7, -20, -19, -10, 0, -14, 32, -15, -18, 13, -9, 2, 17, -14, 6, 36, + -9, 28, 1, 0, 17, -10, 5, 17, -8, 12, -2, 3, 2, -22, -6, -14, + 6, 8, -11, -14, 2, -23, 25, -35, 3, -18, 1, -14, 22, -1, -12, -7, + -9, 13, -4, 12, 4, -3, 18, 0, 1, 8, -14, 14, -2, 1, 17, -3, + -14, 35, -17, 19, -14, -6, 1, -9, 18, -17, -4, -13, -2, -14, 10, -10, + -6, 0, 3, 5, -12, -13, -3, -6, -6, 11, -13, -7, 13, -2, 6, 13, + -7, 11, -5, 23, 1, 29, -17, 23, -10, 18, -16, 12, -20, 10, 7, -9, + -5, -21, -9, 5, -13, -2, 0, -15, -11, 3, 0, -18, 5, -25, -2, 3, + -2, -3, 4, 8, 14, -7, 15, 4, 8, 19, 9, 11, 7, -3, 14, -11, + 1, 15, -35, 3, 3, -10, -16, 0, -15, 2, 3, -12, 27, -23, 32, -15, + 10, -14, 3, -27, 10, -15, 12, -24, 7, 2, 9, -2, -2, -1, 3, 1, + 1, 8, -4, 0, 6, -6, 1, 1, -1, 8, -11, 31, -27, 13, 4, -3, + 5, -1, 0, 2, 9, 0, 12, -31, 4, -27, 1, -25, 20, -21, -14, 12, + -14, 0, -5, -23, 18, -1, 15, 19, -5, 20, -8, 14, -7, 16, 3, 0, + 8, 10, 0, -8, -10, 3, -8, 9, -12, 4, 15, -6, 2, -12, -29, -3, + -16, -11, 35, -18, -1, -28, 7, -12, 0, 7, -5, 22, 10, 10, -4, 6, + -13, 21, -23, 20, 8, -13, 11, 15, -6, -6, -22, -1, 3, 14, 7, 11, + -27, 12, -17, -12, 8, -15, 3, -8, 12, -12, 5, -30, 12, -18, 9, -2, + 3, 4, 15, 1, 5, -9, 0, -8, 24, -2, 21, 5, -4, -4, 14, -15, + 0, -1, 3, 17, -5, 13, -19, -10, -4, -6, -4, -7, 18, -27, 8, 1, + -12, -21, -13, 1, -9, 11, 1, -3, -1, 22, -21, 9, 6, -3, 20, -2, + 17, 7, -12, 1, 4, 4, -9, 9, -20, 24, 7, -9, -3, -7, -6, 10, + 7, 3, 9, -2, -3, -4, 1, -19, -8, -16, 0, -12, 0, -25, 4, -22, + 10, -9, 0, -3, 15, -1, 8, 11, -15, 10, 13, 1, 22, -5, 15, 1, + 24, 6, 0, -6, 5, 5, 10, 8, -1, -11, -14, 3, -31, 2, -22, -4, + -8, -15, -2, -31, -12, 6, -7, 5, 2, 3, -4, 19, 3, 4, 7, 7, + -8, 31, -6, 26, 1, -2, 2, -3, -10, -4, -4, 9, 3, 12, -16, 16, + -9, -1, 5, 4, -7, 13, -17, 0, -11, -13, -22, 1, -9, 4, -7, 7, + -10, 5, -1, -6, -3, -21, 7, -10, 18, -3, 1, -7, -11, 11, -8, 12, + 20, 3, 13, 16, -1, 3, 13, -3, 23, 16, -3, 15, -14, 12, -6, -8, + -28, 0, -33, 4, -11, -12, -13, -21, -17, -16, -5, -12, 16, -7, 15, -6, + -5, 3, -9, 21, 17, 13, 14, 11, 21, -12, 31, -18, 7, 12, 8, 9, + 7, 1, -3, -7, -14, 17, -35, -10, -2, -18, -8, -10, -20, -22, 2, -10, + -3, 1, -1, 4, -5, 11, -20, 11, -6, 27, 7, 18, 8, -1, 2, 3, + 11, -9, 5, 5, -7, 29, -6, 20, -21, 23, -15, 19, -19, 2, -22, 11, + -26, -7, -10, -30, -1, -3, -6, 15, -22, 16, -7, -9, -2, -7, -5, 11, + 17, -13, 2, 8, -5, 6, 27, -6, 12, -6, 4, 15, 3, 14, -3, -12, + 11, -2, 6, 5, 4, -6, -12, 0, -32, 2, -22, 22, -12, -5, -7, -11, + -7, 6, -1, -3, -3, -16, 2, -1, 0, 0, -7, -2, 1, 12, -4, 5, + 20, 1, 16, -2, 14, -1, 19, 8, 29, -8, 7, -14, -2, 3, -13, 8, + -40, 22, -18, 2, -14, -8, -11, -8, 12, -21, -1, -10, -12, -6, -4, -14, + 6, -19, 7, 14, 1, 11, 11, -11, 25, 1, 14, -5, 31, 0, 22, 4, + 1, 3, 6, -3, 4, -2, -20, -7, -26, 1, -12, -7, -10, 2, -1, -5, + -7, -8, -10, 6, -7, -6, 10, -17, 6, 3, 15, -8, 15, -7, 12, 1, + 9, -4, -2, 10, 9, -1, 10, -4, 9, -8, 17, 0, -13, -7, -2, -11, + 3, -2, -15, -4, -11, -5, -9, 1, 8, -10, 8, -8, -6, -18, 21, -19, + 26, -19, -1, -11, 10, 4, 12, -10, 16, -10, 17, 8, 13, -1, 17, 1, + 5, -1, 11, -8, 9, 16, -17, 3, -26, -17, -14, 6, -17, 4, -20, 0, + -1, -6, -4, 2, -15, 13, -3, -1, 0, -2, -8, 11, 7, -3, -8, 5, + 14, -1, 28, -19, 13, -4, 8, 1, 11, 7, 6, -8, -2, -13, -10, -22, + 6, 11, -1, -1, -5, -13, 18, 3, -10, 9, -17, -8, 9, -9, 1, -17, + -4, -16, 18, -6, 15, -10, 17, 5, 0, -5, 0, -11, 12, 15, 4, 8, + 5, -4, 0, -2, 3, -17, -2, -1, 11, -6, -7, 2, -33, 23, -6, -1, + -2, -2, -1, -8, 3, -29, -2, -34, 16, -3, 16, 1, 10, -12, 23, 0, + -3, 16, 12, 19, 23, -1, 8, -26, 16, -32, 26, -13, 2, -11, 5, -1, + -15, -9, -16, 7, -6, 14, -15, 5, -10, -7, -9, -9, 6, -17, 13, 18, + -5, -3, -4, -4, -18, 28, -6, 13, 17, 24, -2, 9, -14, 1, -11, 7, + 17, 1, -15, 10, -23, -4, -12, 5, -20, 17, -10, 6, 0, -9, 4, -8, + -15, 6, -16, 7, 9, 3, 6, -12, -17, 0, 4, 13, 22, -4, 10, -8, + 7, -12, 5, 5, 1, 11, 2, 10, -3, -2, 3, -10, -5, -7, -4, -18, + 17, -2, -14, -16, -7, -10, -3, 6, -1, 14, -11, 15, -18, 2, -6, 0, + -1, 0, 20, -17, 1, 6, 2, 6, 12, -3, 7, 25, -5, 17, -14, 0, + -6, 0, -2, -5, -1, -10, 8, 2, -9, -19, -7, -17, 5, 3, -7, 4, + -15, -5, 9, -12, -1, -5, 3, -5, 26, -2, 3, -4, 5, 3, 7, 10, + 5, 6, 6, 26, -17, 0, -1, 3, -3, 10, -7, -7, -9, 11, -18, 0, + -16, -6, -5, 3, 7, -14, -14, 0, -21, 14, -8, -1, -12, 2, 1, 2, + -3, -1, -3, 18, 5, 5, 9, 12, 7, 18, 8, 5, -25, 16, -15, 16, + -7, 9, -22, 1, 14, -13, -5, 2, -6, -8, 13, -17, 6, -16, 1, -5, + -14, -6, -6, -15, -2, 9, -9, -18, 15, -19, 12, 7, 4, 8, 14, 15, + 6, 10, -3, 9, -7, 23, -17, 21, -20, 7, 0, -9, 8, -10, 1, 4, + 2, 3, -9, -9, -15, -6, -21, -16, -6, 0, -11, 19, -8, -9, 5, -6, + 0, 5, 14, 7, 1, 12, 8, 7, -5, 12, 8, -4, 19, 4, -7, 2, + 3, -12, -8, -1, 0, 5, 7, -5, -8, -22, -8, -21, -2, -9, 10, -20, + 13, -6, 8, -17, -9, -6, 2, 5, 8, 6, -3, 10, -9, -2, 15, -6, + 20, 7, 11, 10, -3, -4, -8, 25, -25, 18, -12, 17, -6, 20, -22, -1, + -17, -10, 5, -10, 9, -13, -9, -6, 10, -25, -5, -2, -5, 13, 2, -5, + -8, -10, 11, -27, 10, -4, 11, 0, 33, -4, 10, -14, 1, 12, -2, 27, + -8, 6, 11, 9, -12, -4, -10, -13, 12, 5, 1, -10, -14, -15, -8, -7, + -9, 3, -5, 10, 3, -11, -12, -13, -3, -3, 3, 2, 9, 17, -6, 25, + -3, -3, -8, 19, 3, 30, -10, 12, -22, 7, -5, -10, -3, 21, -8, 12, + 6, -5, -13, -13, -9, -9, -1, -23, 13, -17, 15, -22, -11, -18, 8, -14, + 20, 1, 4, -5, 3, 3, 5, 11, 1, 2, 27, 1, 10, -7, -8, -2, + -2, 7, -1, 17, -5, 24, -7, 5, -10, -20, -6, 5, -4, -5, -1, -18, + -5, -14, -1, -20, 1, 7, -7, 12, -4, -2, -4, 2, 8, 0, 7, 1, + 6, -2, 18, -5, -7, 4, 3, -2, 13, 4, 0, 2, -3, 2, -10, -6, + 1, -6, 6, -7, -3, -21, -2, -12, 5, -1, -9, 7, -3, 13, 5, 5, + -8, 0, -8, 19, -5, 13, 13, -7, 3, 0, -10, 0, -8, 20, -8, 13, + -20, -5, -7, 3, 5, -7, 2, -5, -4, -14, 11, -23, -13, 2, -1, 12, + 13, 5, -6, 23, -9, 9, -6, -9, 18, -13, 16, -3, -7, -17, 3, -13, + 12, -9, 4, 0, 0, 13, -18, -1, 3, -13, 20, -5, 1, -20, 15, -23, + 18, -4, -8, 5, -7, 16, 4, 6, -3, 7, -21, 19, -17, -7, 9, 5, + 3, -5, -3, -16, -9, 25, -9, 12, -5, 10, -5, 9, -4, -6, -3, 4, + 10, -2, 11, -12, -2, -14, 8, -23, -5, 0, -8, 9, -2, -11, -3, -9, + 9, 2, 2, 4, -5, 7, 11, -16, 0, -6, 7, 6, 25, 5, 6, -4, + 3, 4, 3, 2, -8, -3, 5, -1, -11, -4, -9, -3, -15, 10, -12, -5, + 11, -4, -7, 6, -29, -5, 6, 11, 3, 9, -18, 13, -14, 19, -1, -2, + 4, 5, 12, 1, 5, -8, 3, 1, 20, -6, 2, 3, -16, 10, -10, -18, + -11, -7, -7, 9, -4, -8, 9, -15, 13, -13, -3, -7, 3, 8, 11, -6, + -16, 1, -8, 20, 4, 15, -5, -3, 11, -5, 6, 0, -5, 10, 13, 0, + -6, -11, 0, 11, -11, 10, -7, -8, 1, 16, -9, 2, -22, -9, 0, 4, + 5, -12, -22, 2, -8, -8, 14, -16, 0, 13, 0, 9, -7, 2, -1, 7, + 8, -3, -3, 2, 15, 5, 10, -7, 12, -4, 22, -4, -3, -12, -2, -15, + 8, -2, -22, 7, -10, 5, 12, -20, -9, -11, -2, -12, 2, -9, 5, -3, + 11, 7, -9, 4, -4, 24, -7, 21, -15, -3, 2, 14, -1, 5, 18, -12, + 13, 3, 5, -10, -11, 0, -8, -2, -4, 2, -15, 9, -10, -16, -9, -7, + 0, -1, 3, -8, -10, 5, -8, 4, -3, 8, -2, 20, 1, 6, -4, -9, + 4, 14, 7, -1, 3, -5, 18, -7, 20, -6, -10, 8, 1, -2, 3, -4, + -5, -3, -6, 0, -16, -7, 12, 0, -17, 4, -31, -7, 1, 1, -4, 8, + -11, 6, -1, 11, -5, -7, -4, 2, 4, 15, -3, 21, -5, 20, 3, -12, + 21, -1, 10, 5, 6, -20, -1, -18, 2, 3, -4, -5, -1, 6, -2, -11, + -17, -15, -13, 0, 6, -18, 7, -18, 7, -7, 6, 7, -10, 18, 16, 2, + -1, 3, -11, 6, 14, 1, 15, -2, 29, -8, 17, -14, 2, -19, 12, 8, + -6, -1, -23, 6, -11, 7, -19, -18, 0, 1, -8, -8, -4, -20, 8, -8, + 4, 10, -12, 13, 0, 18, -10, -3, -4, 6, 4, 17, 7, -2, 18, -9, + 14, -10, -4, -11, 4, 3, 23, -17, -6, -2, -7, -7, 9, -10, 1, 2, + -4, -14, -7, -6, -8, -4, 7, 2, -3, 3, 0, 13, -10, -4, -9, -6, + 18, 11, -4, 16, -8, -4, 1, -1, 7, 3, 3, 3, 10, -15, -2, -9, + 9, 0, 2, 2, -9, 12, -7, 0, -23, -7, -19, 2, -1, 0, 4, -15, + 7, 3, -3, 0, 9, -12, 19, 4, 8, -13, -6, 5, -1, 14, 10, 9, + 13, -3, 16, -18, 13, -18, 7, -10, 13, -6, -11, -3, 7, -23, -6, -11, + -21, 9, -1, 4, -3, -16, 0, -12, 7, 14, -5, 15, 0, 6, -5, -3, + -9, 9, 4, 10, 4, -2, -7, 10, -1, 10, -6, -14, 15, -4, 13, -4, + -4, -14, 5, -2, 4, -9, 3, -14, 2, 3, -10, -1, -9, 0, 3, -6, + 12, -16, 0, 4, 10, -25, 6, -5, 2, 8, 3, -2, -4, 15, 4, 7, + 2, -1, -6, 10, 11, 2, -2, -14, 6, -3, 0, -3, -9, -10, 1, -1, + -15, 9, -29, 9, -10, 7, -3, -3, -10, -2, 14, 4, -6, 0, 1, 12, + 4, 18, -15, 19, 1, 15, 1, 1, 3, -10, 8, -1, 7, -30, 8, -19, + -2, -5, -9, -10, 0, -1, 6, -4, -12, 1, -18, 10, -1, -12, 2, 7, + 12, 11, 0, -4, -1, 6, 10, 17, -8, 1, -12, 5, -2, 1, -7, -1, + 4, 3, -3, -1, -18, 8, -9, 0, -2, 8, -12, 12, 7, -5, -2, -16, + -7, 9, -5, 11, -9, -4, 3, 1, -9, -1, -2, -6, 7, 12, 0, -8, + 9, -10, 3, 0, 2, -3, 11, 14, 4, 3, -12, 3, -3, 2, 12, -4, + -2, -2, 9, -21, -5, -28, -6, -10, 6, 7, -6, -3, -24, 7, -11, 10, + 0, 8, 13, 10, 6, -7, -2, -5, 7, -1, 9, 18, -2, 12, -4, 7, + -26, 13, -6, 19, 6, 6, -5, -16, -6, -8, -18, -2, 1, -11, 3, 4, + -16, -8, -10, -3, 2, -3, 5, 5, 0, 11, 0, -14, 0, 1, 14, 11, + 13, 0, -2, 5, -1, -4, -2, -4, 5, 21, 3, 14, -5, -22, 5, -11, + -3, -6, -3, -11, 0, -5, -13, -10, -18, 3, 9, -10, 2, 3, -11, 11, + -11, 5, -19, 23, -1, 20, 18, 4, -3, -6, 9, 4, -3, 8, 4, 6, + 2, 5, -14, -6, -3, 2, -6, -4, -3, -11, 0, -5, 0, -21, -2, -10, + 11, 5, -4, -5, -5, -8, 10, -10, 4, -1, 6, 12, 9, 2, 8, -20, + 8, -2, 11, -11, 1, -4, 5, 6, -6, 6, -14, 14, 4, -2, 12, -3, + -10, 8, -5, -15, -9, -1, 5, 8, -3, 0, -23, -9, -11, 4, -12, 3, + -4, 4, 1, 15, -12, 3, 13, 2, 5, 8, -8, 7, 11, -3, 17, -11, + 5, 3, 19, 13, 3, -11, -11, -2, -9, -7, -4, -24, -1, -17, -3, -17, + 0, -15, 2, -1, -5, -4, 3, 2, 2, 11, -4, 3, -6, 11, 8, 3, + 6, 3, 7, 7, 6, -6, 2, 0, 14, 14, 3, 8, -6, 4, -3, 6, + -13, -2, -9, -4, 5, -13, -5, -21, -1, -6, -1, -5, -14, 8, -7, 5, + -7, -17, -11, 7, 3, 20, 7, 1, -3, 4, 5, 14, -3, 5, 3, 10, + 8, 6, -6, -2, 6, 3, 7, -6, -3, -3, -6, -1, -27, -11, -17, 0, + 11, 7, 1, -7, -9, -13, 5, -11, 0, -10, 15, 2, 5, -2, -5, 1, + 6, 6, -6, -5, 6, 2, 5, 3, 10, -16, 11, 8, 18, 3, 13, -11, + 7, 5, -7, -6, -20, 15, -1, 10, -1, -13, -17, -11, -3, -13, -4, -14, + -3, -2, -6, 6, -28, 9, -8, 10, 0, 12, -2, 10, 9, 1, 3, -6, + 5, 17, 24, 18, 3, 4, -9, -4, 2, -8, -4, -2, -11, 1, -8, -12, + -9, -10, 5, 0, -7, -9, 7, -18, 6, -10, -12, -1, -1, 13, 1, 18, + 2, -3, 4, 3, 3, -3, 3, 10, 9, 7, 5, -8, -7, 0, 3, -7, + 7, -2, -2, 5, -10, 2, -5, -3, -1, 4, 1, -2, -10, 4, -9, -5, + -12, -18, 3, 6, -3, 3, -15, -1, -13, 6, -2, 8, 0, 8, 16, -2, + 17, -4, 8, 3, 23, -1, 11, -8, 10, -4, -5, -3, -13, -2, -1, -2, + 2, -9, -13, -13, -2, -11, -2, -20, -5, 0, 3, 2, -1, -10, 1, 8, + 3, 9, 6, 4, -3, 13, 3, 4, 11, 2, 11, 8, -2, -1, -2, -2, + -2, -1, -21, -1, -14, 8, 6, -8, -10, 2, -16, 4, -3, -1, -10, 7, + -1, 4, -4, -12, 3, -2, 13, 2, -3, -9, -2, 6, -7, 8, -8, -5, + 12, 7, 8, -3, 6, -1, 16, 0, 7, -8, 3, -7, -1, 0, -6, -4, + -8, 6, -1, 4, -19, 2, -3, -8, -3, -12, 4, -6, 2, -7, 1, -13, + 2, 9, -1, 17, -19, 3, -3, 23, 9, 6, 3, 6, 6, -5, 11, -11, + 1, 0, -5, 6, -6, -4, -5, -7, 3, -4, -14, -9, -7, -1, 5, -11, + 4, -19, 14, -4, 3, 4, 2, 0, 9, -2, -3, 2, -2, 10, 15, -3, + 14, -6, -4, 6, 1, -8, 11, -9, 4, 3, -9, 2, 2, -2, 2, -2, + -9, -2, -2, 1, -6, -6, -22, -16, -10, 12, 0, 5, -8, -2, -4, -2, + 5, -1, 7, 7, 9, 1, 7, 6, -1, 10, 11, 5, -3, 8, 1, -1, + 8, -15, -6, -10, 12, 0, 2, -5, -9, -12, -7, -4, -14, -4, 0, -1, + 5, -7, -8, -12, 0, 2, 16, -3, 11, -4, 16, 11, 2, -3, 2, 8, + -1, 7, -13, 4, -3, -1, 3, -10, -2, -11, 3, 2, 3, -7, -10, -5, + -10, 12, -8, 5, -7, 15, 1, -10, 7, -16, 1, 3, 4, -5, 7, -7, + 4, -2, -1, -8, 0, -2, 17, 10, -2, 6, -5, 3, 10, -7, 2, -3, + 4, 5, 5, -3, -8, -8, -1, 1, 7, -5, -11, -2, -10, -4, -15, -7, + -10, -2, 2, -4, -10, -8, 0, 2, 6, 3, 2, 3, 10, 14, 8, 7, + 3, 5, -5, 20, -6, -1, -2, 0, 1, -2, -2, -8, 3, -3, 10, -14, + 3, -3, -2, 0, -5, 0, -15, 4, -2, 0, 4, -7, 3, -8, 7, -14, + -2, -6, 4, 2, 3, -10, -2, 5, -3, 12, -2, -5, -9, 1, 4, 1, + 11, -12, 15, 5, 20, 10, -5, 1, 5, 3, -13, 6, -16, 5, 1, -5, + -8, -3, -14, -6, -2, -5, -8, -17, -9, 3, -6, -2, -3, -3, 1, 14, + 2, 4, 5, 3, 8, 7, 12, 0, 11, 4, 16, 2, -3, -9, -1, 1, + -1, -3, -6, -14, 4, -6, 2, -14, -9, -11, -1, 0, 0, -5, -6, -10, + 5, -5, 2, -3, 2, 2, 17, -2, -1, -3, 3, 11, 1, 10, 2, 7, + 6, 5, -5, -3, -3, -2, 7, 2, 1, -18, -5, -2, -3, -5, 0, -2, + 0, 8, -9, -10, -15, -7, -2, -1, 6, -8, 16, -10, 13, -4, 2, -4, + 4, 7, 9, 6, -5, -2, 8, -1, 11, -6, -1, 5, 8, 0, 9, -20, + 0, -9, 4, -3, 1, -4, -11, 2, -6, 0, -12, 0, 1, 5, -2, 1, + -7, -4, 3, -1, -10, 3, -3, 7, 4, 8, -9, -6, -10, 0, 0, 2, + -4, 6, 9, 10, 2, 0, -1, 2, 14, 3, 7, -7, 2, -2, -2, -6, + -9, 2, -3, 6, -3, -7, -9, -10, -2, 2, -1, -11, 2, 1, 7, -4, + -7, -19, 3, -1, 6, 6, 6, 6, 0, 6, 7, 3, -1, 3, 8, 3, + 4, -10, -5, -7, 5, -4, -14, 2, -8, 5, -2, 2, -16, -4, -11, 2, + 4, -1, 2, -1, 0, 5, 4, -12, 3, 9, 7, 13, -3, -7, 2, 6, + -1, 7, -1, -1, 5, -5, 7, -11, -9, -13, 2, 5, 2, -2, -7, 5, + 4, -4, -2, -15, -4, 3, 0, 0, -5, 2, -7, -1, 9, -2, -1, 5, + 1, 1, -4, -5, -4, 6, 8, 7, -5, 4, -7, 4, 0, 1, -6, -5, + -2, 5, -1, 0, 1, 1, 3, 9, -4, -2, -4, -9, -1, 4, -17, 1, + -13, 11, -1, 6, -9, -1, 5, 1, 8, -3, 4, -5, 1, 7, -5, 1, + -3, 5, 3, 4, -7, -11, -7, 1, 5, -13, 11, -11, 1, 3, 6, -9, + 6, -5, -7, 4, -13, 5, -7, 10, 5, 6, -15, -1, 6, 4, 18, -7, + -7, -3, -4, 2, -5, 3, -4, 9, -4, 3, 3, -3, -10, 0, -1, 2, + 5, -3, 7, 3, 2, -6, -11, -2, -1, 4, -5, 4, -5, 0, -5, 5, + -5, -4, 2, 4, 2, 5, -8, -13, -3, 0, -1, -2, 4, 6, 9, 1, + 3, -7, -1, 1, 12, 1, 1, -1, -5, -1, 2, -8, -9, -7, -2, 3, + 10, -6, -7, -12, -7, -4, -5, 6, 0, 10, 5, 7, -4, -2, -8, 10, + 5, 9, 4, -1, -1, -1, -1, -1, -2, -3, 3, 9, -2, 9, -14, -13, + -8, -10, 1, 1, 3, 3, 1, -3, -12, -5, -7, 1, 6, 6, -2, -7, + -3, -3, 2, 2, 4, -9, 14, 8, 11, -3, 5, -11, 1, -1, 5, 3, + 8, 2, 8, -2, -6, -13, -10, 0, 4, 3, 4, -3, -9, 1, -5, -5, + -6, 1, -2, 2, -10, -6, -15, 1, -5, 4, -1, 2, 2, 4, 10, 4, + 2, -13, 0, 4, 8, 17, 2, 5, 4, 2, -6, 5, -5, 0, 8, -2, + -1, -5, -4, -5, -1, -5, -4, -5, 0, 0, 1, -9, -15, -3, -12, 1, + -1, -7, 10, 2, 5, -1, 2, -6, 2, 2, 10, 10, -1, 2, -2, 4, + 5, 0, -6, 12, 5, 3, -1, -8, -8, -4, -4, 3, -11, 0, -1, -1, + 0, -2, -14, -6, -9, 2, 1, 7, -4, 3, -1, 0, -3, 1, 2, 7, + 5, 4, 3, -2, -3, 1, 6, -1, 6, -11, 7, 2, -6, 2, -4, 0, + 2, 3, -7, -9, 3, 0, 4, -6, 0, -21, 0, -5, -1, 0, -1, 1, + -6, -1, -1, 0, -7, 5, 7, -2, 8, -4, -1, 3, 9, -6, 10, -6, + 7, 9, 10, 9, -6, 5, -14, 6, -5, 1, 2, -3, 0, -9, -10, -14, + -2, -3, 6, -8, -15, 3, -9, 0, -3, 0, -6, -1, 3, 9, 10, 3, + 3, -10, 6, 1, 3, -1, 9, 12, 4, 4, -9, -7, -5, 8, 6, 1, + 1, -4, -5, -5, -1, -11, -3, -4, 1, -1, 1, -10, -7, -2, -3, -4, + -3, -6, 11, 5, 3, 2, -8, -5, -2, 3, 9, 13, 5, 4, 4, 0, + -5, -1, -5, 9, 2, 3, -9, -4, 3, -6, 2, 1, -9, 5, -2, 3, + -2, -9, -8, -15, -5, -3, 3, -13, 11, 6, -3, 1, -6, -6, -1, 6, + 4, 6, 7, 1, 5, 0, 8, -6, 7, 2, 6, 2, -5, 0, -3, -1, + 3, -7, -1, -3, 5, 7, 6, -18, -10, -11, -7, -3, 10, -4, 3, -4, + -8, -5, -12, -3, -4, 12, 10, 2, -4, 6, 3, 1, 2, 0, -3, 3, + 7, 7, -5, 2, -4, 1, 3, 11, 2, 3, 4, -2, -7, -5, -17, -11, + 4, -3, 5, -7, -7, -6, -1, -8, -5, -5, 1, 7, 1, 2, -1, -9, + 7, 1, 7, 3, 3, 6, 9, 6, 1, -6, -4, 2, 5, 7, 4, -2, + 1, 3, -11, -1, -16, -2, -6, 1, 3, -8, -15, -11, 4, -1, 9, -2, + -5, 0, 6, 0, -7, 0, -8, 4, 2, 6, 2, 0, 2, 6, 2, -2, + 4, -2, 4, 14, 2, 2, -6, -6, -3, 4, -4, -1, -4, 1, -3, -6, + -1, -13, -1, -2, 7, -8, -7, -10, 0, 4, 3, -8, -3, 1, 4, 6, + 4, 6, -3, 5, 3, 4, 0, 6, 1, 4, 7, -3, -10, 8, -1, 9, + -1, 1, -11, -7, -3, -3, -6, -8, -9, -6, 1, -3, -6, -6, -5, 0, + 0, 2, -3, 0, 6, 4, 3, 2, 7, 4, 11, 14, 5, -1, -5, 1, + -2, 7, 3, 0, 1, 2, -5, -7, -10, -12, -10, -5, -5, -6, -6, -9, + 1, -8, -2, -1, -9, 1, 8, 2, -5, -2, -5, 0, 5, 6, 6, 7, + 8, 10, 2, 0, -3, -1, 2, 13, 3, 0, -6, 0, 1, -3, 0, -12, + -2, 4, -4, 4, -8, -11, -1, -2, 1, -1, 2, -12, 3, -6, 1, -12, + -7, -7, 3, 0, 9, 0, 1, 6, 1, -1, 2, 1, 2, 8, 9, -3, + -1, 0, 7, 3, 8, -1, -4, -1, 1, 3, -9, -1, -17, -3, -2, -4, + -4, -3, -4, -6, -11, -15, -2, -5, 6, 10, 1, 3, -1, -3, 13, 7, + 1, 6, 4, 4, 9, 5, -3, -5, 9, 3, 5, -3, 1, -3, 3, 0, + -7, -5, -7, 0, -5, 0, -1, -15, -11, -4, -5, -10, 2, -7, 5, -4, + 1, -9, 2, 1, 8, 7, 10, 2, 2, 0, 4, 3, -2, 0, 4, 2, + 6, 8, -2, 4, 4, -2, 5, -3, -6, 3, -3, -5, -9, -8, -11, -5, + -1, -1, -5, -7, -5, -8, 0, -3, 5, -7, 11, 1, 0, 2, -3, -1, + 3, 9, 6, -3, 8, 1, 11, 2, 8, -3, -3, 6, 2, 1, 2, -7, + -3, -2, -4, -8, -3, -3, 5, -10, -10, -4, -12, -2, 3, -5, 3, -6, + -8, -2, 5, -3, 0, 1, 4, 8, 4, 5, 0, 4, 8, 1, 7, -3, + 0, 3, 4, 4, -5, -2, -7, -3, 0, 5, -5, -9, 3, -2, -1, -2, + -5, -1, -4, -3, -11, -4, -5, -6, 0, 5, 0, -5, 5, 3, 8, -1, + 3, 3, 2, 5, 7, -4, 3, 1, 3, 10, 2, -7, 1, 0, 6, -4, + -3, -5, -7, -2, -4, -3, -6, 0, -10, 4, -6, -4, -7, -2, 1, -4, + -1, -3, -1, 2, 6, 2, 4, -2, 2, 4, 2, 5, -3, 4, 2, 1, + 0, 8, -3, 2, 5, -5, 3, -5, -2, 5, -5, 3, -1, -4, -3, 4, + -10, -5, -7, -4, -4, 0, 0, -7, -1, -1, 2, 1, -2, -12, -4, -1, + 0, 4, -5, 2, 0, 3, 12, 11, 3, 11, -1, -3, 6, -6, 1, 1, + 7, 6, -7, -1, -7, -4, -4, -7, -8, -1, -6, -6, -2, -3, -5, 0, + -4, 8, -7, 1, 4, -3, 6, 1, -7, 3, 5, 6, 5, 13, 2, 2, + -4, 4, -3, 1, 4, -4, 2, -3, -10, -10, -7, -2, -2, -2, 0, -6, + -2, 1, -3, -4, -2, -5, -2, 7, 1, 6, -5, 6, -1, -1, 2, -3, + 4, 11, 2, -1, 2, -7, -5, 8, 0, 3, -3, -5, -1, -2, 3, 1, + -4, 4, 7, 0, 2, 3, -3, 0, 1, -5, -15, -5, -3, 1, 3, -3, + -11, -4, -7, 1, -2, -1, -1, 0, 1, 1, -5, -1, 3, -2, 7, 1, + -4, -1, 0, 4, 5, 3, 3, -1, 8, 11, 1, 4, 1, -5, 7, -6, + -4, -2, -4, -2, 3, -8, -3, -13, -6, 3, -3, -7, -4, -7, 3, 3, + -3, 2, -1, 1, -4, -2, -2, -5, 1, 11, 9, -2, 6, -3, 7, 7, + 1, 1, -7, 2, -3, 1, 4, -4, -4, 5, 1, 0, -3, -6, 2, -3, + 0, -8, -12, -6, -2, -3, 6, -1, -9, 0, -1, 1, 3, -2, -1, 0, + 1, 6, 0, -3, 5, 1, 6, 1, -1, 4, 1, 7, -3, -1, -1, -4, + 4, 14, -1, -1, 2, -4, -1, -6, -8, -8, -3, -2, 2, -9, -5, -7, + -12, 5, 0, -3, -4, -3, 5, 4, 3, -2, -6, 4, 7, 3, 5, 7, + -3, 8, 0, -5, -1, -1, 11, 10, 3, 4, -8, -3, -3, 1, -3, 0, + -4, -3, 1, -7, -8, -16, -7, -6, -2, 3, -7, -2, 1, -4, 0, -5, + -5, 1, 5, 10, 5, 0, 3, 0, 1, 13, 0, 5, 9, 6, 8, -1, + -4, 0, -3, 6, 4, -4, 0, -3, -15, -2, -12, -15, -3, -6, 2, 1, + -3, -4, -9, -9, -3, -3, -2, 3, 4, 9, 0, 2, 1, 2, 14, 5, + 3, 8, 2, 7, 4, -4, -4, -1, -9, 9, -5, -1, -7, -10, -2, -7, + -4, 0, -5, 2, 5, 1, 0, -5, -5, -1, -1, -3, 4, -8, 5, 3, + -4, 4, -5, -3, 9, 4, 8, 0, 0, 2, 0, -2, 0, -2, -7, 12, + -1, 5, -4, 2, -3, 0, 2, -2, -4, -2, 2, -5, 3, -7, -9, -4, + -3, -2, -6, -6, -2, -6, -1, -7, -8, 1, 3, 6, 10, 4, 5, 0, + 5, 8, 1, 3, 8, 5, 11, 12, -7, 4, 0, -3, 2, -1, -8, -7, + -4, -2, -6, -9, -6, -13, -4, -1, 0, -9, -5, -3, -4, -2, 3, 1, + 1, 9, 4, 2, 6, -1, 3, 6, 2, 0, -3, 3, 2, 6, 3, -1, + -4, 4, 1, 2, 2, -5, -8, -1, -3, -1, -9, -4, 1, -5, 5, -7, + -4, 0, 3, -10, 3, -3, -5, 1, 5, 4, 1, -5, 1, -5, 4, 1, + -6, 0, 5, 8, 8, 1, 6, 0, 3, 4, 2, -3, 1, -3, -3, 3, + -10, -6, -8, -2, -1, -3, -6, -6, -5, -6, -6, -5, 5, -3, 5, 6, + -2, -1, -1, -4, 6, -2, 6, 6, 2, 12, 8, -2, 3, -6, -2, 5, + 4, -3, -2, -5, -4, -7, -6, 1, -5, 2, 2, 0, 1, -7, 0, -4, + -2, -1, -2, -5, 7, -5, -2, -3, -2, -3, 4, 4, 9, 0, 1, 1, + -5, -3, -4, -4, 4, 3, 6, 1, -2, -2, -7, 4, 1, 1, -3, 3, + -1, 2, 0, -7, 0, 0, -1, -3, -2, -1, -5, -2, -3, -8, -5, -5, + -1, 5, 5, 2, 2, -3, 4, 3, 4, 6, 3, -1, 10, -4, -3, -2, + -3, 0, -4, 0, -2, -2, 0, 2, -5, -2, -5, -9, 8, -2, -1, -1, + -3, -3, -2, -6, 2, 1, 2, 9, 0, 1, 4, -5, 2, 4, -6, -1, + 2, -1, 6, 3, 0, -5, -3, -1, 0, 3, -3, 0, -6, -2, -3, -4, + -2, 0, 3, 2, 2, 0, -10, 1, -6, -5, -1, -2, 5, 3, 6, -2, + -6, -1, -3, 2, 4, 1, -1, 0, 1, 1, 3, -1, 5, -1, 7, 6, + 1, -2, 0, -6, -2, -2, -8, -2, -2, -3, -5, -5, -8, -3, -1, 5, + -3, 1, 2, 1, 2, -3, -2, -3, 2, 6, 2, 6, 0, 0, -2, 9, + -1, 3, -2, 3, 0, 0, 0, -6, -6, -1, -5, -7, 1, -3, -6, 2, + -2, -1, -5, -2, 1, 4, 2, 2, -3, -1, 6, -2, 2, 4, -3, 2, + 2, 2, -3, 1, 0, -4, 2, -1, -2, 3, 1, 1, -1, -5, -8, -2, + -5, 0, 1, -6, 3, -4, 2, 3, -6, 3, 0, 2, -2, -1, -4, -2, + -4, 4, 0, -3, 0, -6, -3, 10, -3, 3, 0, 4, 7, 3, 0, 5, + 1, 5, 1, -3, -2, 0, -6, 3, -1, -7, -5, -7, -1, -2, -2, -2, + -3, -2, 2, -2, -1, -3, -3, 2, -2, -6, -3, -3, 4, 3, 2, 0, + -1, 5, 5, 8, 2, 2, -2, 4, 0, 5, -5, -3, -1, -3, -3, -6, + -4, -2, 3, 0, -2, -2, -5, 5, -1, 3, -1, -1, -3, 0, 0, -5, + -4, -3, -2, 5, 0, -4, -4, 1, 2, 6, 0, -3, -1, 2, 3, 7, + -3, 0, -4, -2, 4, 3, 0, 1, 3, -3, 1, -7, -4, 0, 1, 1, + -4, -4, -4, -9, -1, -2, -3, -2, -3, -3, 4, 3, -1, -4, 2, 4, + 4, 3, 2, -1, 0, 9, -1, 4, 2, 7, -1, 6, -2, -2, -5, -1, + -9, -2, -2, -6, -1, -1, 1, -8, -6, -5, -1, -1, 1, -4, -5, 3, + 1, 5, 3, -3, 0, -2, 7, 0, 1, -2, 3, -1, 5, -1, -5, 7, + -1, 3, 2, -5, -6, -2, 4, 2, -1, -3, -1, -1, -1, -1, -2, -4, + 1, -5, 3, -1, -3, -5, 2, 6, -6, -1, -5, -4, 4, -1, -1, -2, + -1, 2, 0, 3, 1, 4, 2, 7, -1, 2, 0, -2, 1, 4, -5, -3, + -7, -2, 0, -1, -1, -3, 0, 0, -2, -6, 2, -4, 2, -4, 1, -7, + -2, -1, 5, 3, -2, -7, -4, 1, 6, 4, 5, 1, 4, 0, 5, 1, + -1, 2, 0, -3, -3, -5, -6, 3, -1, 5, -1, -2, 1, 1, 4, 2, + -6, -3, -4, -3, 2, -2, -8, -3, -6, -4, -2, -11, 0, 0, 1, 6, + -3, -2, 1, 2, 10, 8, 4, -2, -1, 2, 2, 1, -2, 3, 1, 5, + 3, -1, 0, -4, 4, -7, -2, -7, -8, -4, -3, -2, -7, -7, -3, -1, + 5, -2, 0, -7, 2, -1, 3, 1, 4, 6, 5, 8, 3, 2, -1, 3, + -3, 0, 0, -5, -1, 1, 1, -5, -3, -2, 6, 4, 5, -4, -8, -4, + -3, -2, -5, -4, -4, -4, 2, -3, -2, -4, -4, -4, 6, 1, 0, 1, + 3, 3, 5, 2, 1, 0, 6, 2, -1, 1, -3, -3, 2, -1, 0, 1, + 3, 1, 4, -4, -5, -10, -8, 1, -6, -3, -4, -6, -3, 0, 2, -3, + -1, 2, 0, 8, 1, 4, 4, 3, 6, 3, 1, 3, 5, 1, 2, -4, + -7, -3, -3, 3, 0, -7, -5, 0, -3, -1, -2, -4, 0, -5, 1, -6, + -1, -5, -3, 1, 4, -1, -3, 3, 3, 5, -1, -2, 2, -1, 2, 1, + -1, -5, 5, 1, 2, 2, -4, 0, -1, 3, 0, -2, -1, 2, 1, 5, + 4, -3, -5, 0, -2, -2, -6, -3, -3, -4, -1, -5, -4, -1, -2, 0, + 2, -2, -6, -3, 1, 1, 1, -1, 3, 4, 7, 2, 3, 4, -1, 7, + 2, 3, 1, -1, 1, -2, 0, -4, -5, -6, 0, -2, -7, -2, -5, -5, + 1, -4, -5, -5, 3, -1, 1, 2, -2, 0, 1, 4, 1, -4, 2, 2, + 0, 9, 2, 0, 4, 3, 1, 2, -4, -2, -4, 3, -4, -2, -6, 0, + -1, 5, 2, -4, 0, -4, -4, -1, -5, -4, -7, -3, 1, 0, -2, -1, + -5, 1, 0, -1, 0, 2, 4, 0, 3, -2, 1, 2, 6, 0, 1, 5, + 0, 3, 3, 2, -5, -2, 1, 5, 2, -2, -5, -9, 0, -6, -1, -6, + -7, -5, -4, 0, -2, -5, -3, 2, -2, 3, 2, 0, 9, 2, 0, 4, + -3, 4, 5, 8, 6, -2, -4, -1, 0, -2, -2, 1, -5, 2, -5, -1, + -4, -3, -4, 0, -2, -7, -3, -1, 0, -1, 0, -6, 3, -2, 5, 2, + -1, -2, 1, 0, 1, -1, -3, 2, 3, 1, 2, -4, -3, -1, 5, 5, + 3, -4, 0, 1, 2, 5, -5, 1, -5, 2, -2, 2, -4, -3, 0, -4, + -3, -9, -7, -4, 2, -2, 1, -6, -3, 0, 1, 5, 1, -5, 0, 0, + 2, 1, 2, 0, 6, 4, 6, 3, 2, 3, 1, -2, -2, -9, -4, -1, + 4, 0, -1, -5, -8, -5, -4, 0, -4, -1, -3, 0, 0, -4, -3, -1, + 1, 2, 0, -2, -3, 1, 3, 2, 3, 3, 0, 8, 2, 7, -1, 3, + -2, 4, 0, 0, 1, -4, 5, -1, -3, -3, -6, -4, 2, 1, -5, -4, + -7, -4, -4, -7, -2, -10, 1, 0, 1, -3, 4, -2, 5, 2, 1, -3, + -1, 2, 8, 4, 5, 0, 1, 4, 5, 2, 2, -2, 1, -4, 0, -3, + -3, -1, 0, 2, -4, -4, -5, -1, -7, 0, -4, -5, -1, -3, 2, -2, + 0, 3, 0, 2, 0, 1, -2, 2, 4, -1, 0, -3, -1, 1, 3, 2, + -3, 2, 0, 2, 2, -1, 2, -2, -3, 0, 0, -2, 2, -2, 4, -3, + -6, -7, -6, 2, -1, -4, -1, -7, -1, -3, 3, -1, 0, -2, 2, 2, + -3, 3, -4, 5, 7, 6, 3, 1, -1, 6, 2, 1, 0, -1, -1, 1, + -3, 1, -3, -5, -5, -3, -8, -3, -11, -1, -1, 0, -8, -2, -5, 3, + 4, 0, 1, -2, 2, 0, 6, 4, 1, 4, 1, 5, 0, 0, 1, 2, + 5, 0, 1, -10, 0, -5, 2, 0, -6, -6, -2, -2, 2, -3, 0, -4, + 2, -4, 1, -3, -4, 1, -2, 2, 1, -2, 0, 3, 2, -3, -1, -5, + -3, 4, 2, 3, -1, 4, 1, 5, -1, 2, -3, 2, -3, 0, -3, -2, + 1, 1, 5, 1, -2, -5, 1, -1, -4, -3, -7, 0, -5, -4, -4, 0, + -4, 4, 0, -1, 1, -8, 1, 0, 9, 1, 2, -2, 5, 5, 1, 6, + -1, 6, 3, 1, 1, -2, -2, -4, -3, -2, -3, -7, -4, -4, -1, -3, + -8, -1, -8, 4, -5, 0, -3, 1, 0, 4, -1, 0, 1, 3, 3, 4, + -4, 6, -2, 2, 5, 4, -3, 4, -3, 5, 0, -4, 0, 0, -1, 0, + -4, -4, 3, -1, -2, -4, -8, -9, -5, -4, 4, -4, 1, -4, 1, 1, + -1, -1, -1, 3, 2, 3, 0, 1, 2, 1, 5, 3, 1, 0, 5, 3, + 3, 0, -5, -4, -2, 5, 0, -2, -5, -2, -6, -2, -5, -8, -2, 1, + -1, -3, -7, -8, -6, 0, 4, 7, -2, 7, -1, 7, 3, 2, -5, 0, + 2, 0, 1, -3, 2, 2, 3, 3, -3, 0, -2, 3, -1, -1, -4, -6, + -2, -3, 4, -4, 0, -4, 6, -2, -6, -2, -7, 1, 2, -1, -3, -2, + -2, 3, -1, 0, -3, -1, 4, 7, 4, 0, 2, -1, 0, 6, -2, 1, + 1, 5, 4, 1, -3, -3, -2, 2, 2, 1, -6, -6, -3, -4, -2, -6, + -5, -4, -5, -2, -8, -8, -3, 0, 4, 0, 1, -1, 2, 5, 4, 2, + 2, 3, 3, 4, 10, 0, 2, 0, 3, 1, 1, 0, -3, 1, -3, 1, + -7, 0, 1, -2, 1, -6, -4, -10, -1, -4, -2, -2, -3, 2, -4, 1, + -5, -4, -4, 2, 1, 1, -4, -1, 3, 1, 6, 2, -2, -2, 3, 3, + 2, 7, -5, 5, 0, 8, 1, -1, 2, 3, -1, -6, 0, -10, 3, -1, + -1, -5, -6, -8, -2, 0, -3, -5, -8, -4, 2, -3, -1, -2, 0, -1, + 7, -1, 3, 2, 4, 7, 3, 4, -1, 5, 1, 9, 1, -2, -1, -1, + 1, -3, -2, -6, -7, 1, -3, -1, -9, -4, -6, 0, 2, -3, -2, -4, + -3, 0, -4, -1, -4, 0, 1, 6, -1, 1, -1, 3, 5, -1, 3, 4, + 5, 7, 4, -2, 0, -2, 0, 3, 1, -1, -8, -2, -1, -2, -5, -1, + -2, -2, 2, -5, -7, -9, -2, -3, -2, 1, -5, 4, -4, 5, -1, -1, + -3, 2, 3, 7, 3, -1, 3, 4, -1, 5, -4, 0, 4, 4, 3, 4, + -9, 1, -5, 2, -2, -2, -3, -7, -1, -2, -2, -5, -3, -1, 1, -2, + -1, -4, -4, 1, -1, -7, 0, -1, 2, 5, 4, -4, -5, -4, 0, 2, + 1, -1, 3, 5, 4, 0, 0, -1, 3, 8, 3, 3, -4, 0, 1, 0, + -2, -6, -2, -4, 3, -2, -3, -5, -6, -3, -1, -1, -7, 0, 0, 3, + -5, -4, -11, 0, 0, 3, 3, 1, 1, 1, 4, 6, 1, 1, 2, 9, + 3, 3, -4, -4, -3, 2, -1, -6, 1, -5, 2, 0, -1, -8, -5, -6, + 1, 0, -2, -1, -2, -1, 2, 0, -9, 0, 5, 4, 7, -3, -3, 3, + 4, 2, 4, 0, -1, 3, 1, 5, -5, -6, -7, 0, 3, 0, -2, -4, + 3, 3, -3, -4, -7, -2, 4, 1, -1, -4, -1, -6, -2, 3, -2, -3, + 1, 4, 1, -1, -4, -3, 3, 4, 5, -2, 2, -3, 4, 0, 3, -3, + -3, 0, 3, 1, -2, -1, -3, 2, 4, -2, -2, -3, -1, -1, 3, -11, + -2, -8, 5, -1, 3, -5, -2, 2, -1, 3, -3, 0, -1, -1, 5, -2, + 0, -2, 3, 2, 3, -2, -6, -3, 2, 4, -6, 5, -6, 1, 2, 3, + -6, 2, -3, -4, 3, -9, 2, -6, 3, 4, 2, -9, -1, 1, 2, 8, + -3, -4, -1, -2, 2, -2, 2, -3, 3, -1, 1, 2, -1, -6, 1, 2, + 2, 1, -2, 2, 3, 1, -3, -6, -3, 0, 1, -3, 0, -3, -1, -4, + 2, -4, -3, -1, 4, 0, 5, -6, -7, -1, 0, 0, -3, -1, 2, 4, + 0, 3, -4, -1, 1, 7, 4, 2, -1, -4, 0, 2, -4, -5, -5, -1, + 1, 4, -5, -4, -6, -3, -2, -3, 2, -2, 5, 2, 3, -4, -2, -5, + 6, 3, 4, 2, -3, 1, 0, 0, 1, -3, -1, 1, 7, 0, 6, -6, + -7, -2, -7, 0, -1, 0, 2, 1, -2, -7, -2, -5, 0, 2, 0, -3, + -5, -1, -3, 0, -1, 0, -6, 8, 4, 5, -1, 1, -4, 1, 1, 4, + 2, 5, 3, 6, 0, -2, -9, -4, -1, 0, 0, 1, -1, -4, -1, -5, + -5, -5, 0, 0, 1, -6, -5, -9, 0, -3, 0, -2, 0, 0, 3, 4, + 2, 1, -7, 1, 3, 4, 9, 1, 4, 4, 2, -4, 2, -2, 1, 5, + -2, 0, -3, -4, -3, -2, -4, -4, -4, 1, -1, 2, -6, -8, -3, -8, + -1, -2, -4, 5, 2, 3, -1, 0, -4, 2, -1, 5, 5, -1, 3, 0, + 3, 3, 0, -4, 9, 4, 2, -1, -6, -4, -2, -2, 2, -7, 0, 0, + -2, -2, -2, -10, -4, -7, 0, -2, 2, -2, 2, 1, 0, -3, 0, 1, + 6, 3, 2, 0, 0, -1, 2, 3, -1, 4, -5, 6, 2, -3, 0, -3, + 0, 1, 0, -5, -6, 1, 0, 1, -5, -2, -14, 0, -4, -1, -1, -1, + 1, -3, 0, -2, -1, -4, 4, 5, -1, 5, -1, 3, 3, 5, -3, 5, + -3, 5, 5, 6, 4, -6, 2, -9, 4, -4, 0, 1, -2, -1, -8, -6, + -11, -2, -3, 3, -6, -8, 3, -5, 1, -3, 1, -3, 1, 3, 5, 6, + 2, 1, -6, 4, -1, 1, 0, 7, 7, 2, 3, -6, -4, -4, 3, 3, + 0, 1, -1, -2, -4, 0, -8, -2, -3, 1, -2, 1, -5, -2, -1, -3, + -3, -4, -3, 7, 4, 1, -1, -6, -5, -3, 2, 5, 8, 3, 3, 2, + 1, -4, -1, -2, 6, 3, 2, -4, -1, 1, -5, -1, -1, -5, 2, -2, + 1, -2, -7, -5, -11, -4, -3, 3, -8, 8, 4, -2, -2, -4, -4, -1, + 4, 3, 5, 5, 2, 4, -1, 6, -3, 6, 2, 3, 0, -4, 0, -2, + -2, 0, -5, -2, -1, 4, 3, 1, -13, -8, -8, -5, -3, 7, -2, 3, + -2, -5, -3, -8, -2, -3, 8, 6, 1, -2, 5, 3, 1, 2, 0, -1, + 2, 4, 3, -5, 1, -3, 0, 1, 7, 1, 2, 3, -1, -4, -4, -10, + -7, 3, 0, 2, -5, -5, -4, -1, -7, -3, -3, 1, 3, 0, 0, -1, + -6, 6, 1, 4, 1, 2, 5, 6, 4, -1, -4, -3, 1, 2, 5, 2, + -1, 1, 3, -8, -1, -10, -2, -5, 0, -1, -6, -10, -7, 2, -2, 6, + -1, -2, 1, 4, -1, -5, -1, -5, 4, 1, 4, 2, 1, 3, 4, 0, + -2, 1, -1, 3, 8, 2, 1, -4, -3, -3, 3, -3, -1, -4, 0, -4, + -6, -2, -8, 1, -2, 5, -6, -5, -6, 0, 3, 1, -6, -3, 1, 2, + 4, 2, 4, -2, 3, 3, 3, 1, 5, 1, 2, 3, -2, -6, 6, -1, + 6, -2, 1, -7, -5, -2, -3, -6, -6, -6, -4, 0, -2, -4, -4, -3, + 0, -1, 1, -3, -1, 3, 1, 1, 0, 6, 4, 8, 10, 5, 0, -3, + 1, -2, 5, 2, 1, 1, 1, -4, -6, -8, -8, -8, -5, -4, -5, -4, + -5, 0, -5, -3, 0, -7, 0, 4, 1, -4, -1, -4, -2, 4, 4, 5, + 6, 6, 7, 0, 0, -1, 0, 2, 9, 2, 1, -3, 0, 1, -3, 1, + -9, -1, 3, -4, 3, -6, -7, -2, -1, -1, -1, 1, -9, 2, -5, 1, + -8, -6, -6, 1, -1, 6, 0, 2, 5, 2, 0, 2, 1, 2, 6, 5, + -2, -1, 0, 4, 1, 6, 0, -2, 1, 0, 3, -7, -1, -13, -4, -3, + -3, -3, -2, -3, -5, -9, -11, -2, -3, 4, 7, -1, 2, 0, -2, 8, + 5, 1, 4, 3, 2, 7, 3, -2, -4, 7, 2, 3, -2, 1, -1, 2, + 0, -5, -4, -4, 0, -4, 0, -1, -10, -9, -3, -5, -8, 1, -5, 3, + -3, 0, -7, 1, 0, 5, 4, 7, 1, 1, 0, 2, 2, -2, -1, 2, + 1, 4, 6, -1, 4, 3, -1, 4, -2, -3, 3, -1, -2, -6, -6, -7, + -3, -1, 0, -4, -6, -5, -6, 0, -3, 3, -5, 7, 0, -1, 1, -3, + -1, 1, 6, 3, -3, 7, 1, 10, 1, 6, -1, -2, 5, 2, 1, 1, + -4, -2, 0, -3, -7, -2, -4, 4, -8, -8, -4, -10, -2, 2, -4, 1, + -5, -7, -1, 3, -1, 1, 1, 4, 6, 2, 2, 0, 4, 7, 0, 5, + -2, 0, 3, 3, 3, -3, -1, -5, -2, 0, 3, -4, -6, 2, -1, 0, + -2, -4, 0, -4, -3, -9, -3, -4, -4, 0, 3, -1, -4, 3, 1, 5, + -2, 1, 2, 2, 4, 5, -3, 2, 1, 3, 7, 1, -5, 1, 0, 5, + -3, -2, -3, -4, 0, -3, -2, -5, 0, -8, 3, -6, -4, -6, -2, 2, + -4, -2, -3, -2, 1, 4, 2, 3, -2, 2, 4, 1, 4, -2, 3, 2, + 1, 1, 7, -1, 2, 4, -4, 2, -4, -2, 5, -4, 3, -1, -3, -2, + 3, -8, -4, -6, -3, -3, -1, 0, -6, -1, 0, 1, 1, -2, -10, -3, + -1, 0, 2, -5, 1, 1, 2, 10, 8, 2, 8, -1, -2, 4, -5, 2, + 2, 7, 6, -6, -1, -5, -4, -3, -6, -7, 0, -5, -5, -1, -2, -5, + 0, -4, 6, -6, 0, 3, -3, 4, 0, -6, 2, 5, 5, 4, 10, 0, + 2, -3, 3, -2, 0, 3, -3, 2, -3, -8, -8, -5, -1, -1, -1, 0, + -5, -2, 0, -3, -4, -1, -5, -2, 5, 0, 5, -4, 4, -1, -1, 1, + -3, 3, 9, 2, -1, 1, -6, -3, 7, 1, 3, -2, -4, 0, -1, 3, + 1, -3, 4, 6, 0, 1, 2, -3, 0, 0, -5, -13, -4, -2, 1, 2, + -3, -10, -4, -7, 1, -2, -2, -1, 0, 1, 1, -4, -1, 2, -2, 7, + 1, -3, 0, 0, 4, 5, 2, 2, -1, 6, 9, 1, 3, 1, -5, 5, + -6, -5, -2, -4, -2, 2, -7, -4, -11, -5, 3, -3, -6, -4, -6, 3, + 3, -3, 2, 0, 1, -3, -1, -2, -4, 1, 10, 8, -2, 4, -3, 6, + 6, 1, 0, -7, 2, -2, 1, 3, -4, -4, 4, 1, 0, -2, -5, 2, + -2, 0, -7, -11, -5, -2, -2, 5, -1, -8, -1, -1, 1, 2, -2, -1, + 1, 1, 5, 0, -3, 5, 1, 6, 1, -1, 3, 1, 6, -3, -1, -1, + -3, 4, 12, -1, -1, 2, -4, -1, -6, -8, -7, -3, -2, 1, -9, -5, + -6, -10, 5, 1, -2, -3, -2, 5, 4, 3, -1, -5, 4, 6, 3, 4, + 6, -2, 7, 0, -4, -1, -1, 9, 8, 2, 2, -8, -3, -3, 0, -2, + 0, -4, -2, 0, -6, -7, -14, -6, -5, -1, 3, -6, -2, 1, -3, 0, + -4, -5, 1, 5, 9, 4, 0, 3, 0, 1, 12, 0, 4, 8, 5, 7, + -1, -4, 0, -3, 5, 4, -4, 0, -3, -13, -2, -10, -14, -3, -5, 2, + 1, -3, -4, -8, -8, -3, -2, -2, 3, 4, 8, 0, 2, 1, 2, 12, + 5, 3, 8, 2, 6, 3, -4, -4, -2, -8, 8, -5, -2, -6, -10, -2, + -6, -4, 0, -4, 2, 5, 1, 0, -4, -4, -1, -1, -3, 4, -7, 4, + 3, -3, 4, -4, -3, 8, 4, 7, 0, 0, 2, -1, -2, -1, -2, -7, + 11, -1, 5, -4, 2, -2, 0, 2, -2, -4, -2, 1, -5, 3, -6, -9, + -3, -3, -2, -5, -5, -2, -6, -2, -7, -8, 1, 3, 5, 9, 4, 4, + 0, 5, 8, 1, 3, 7, 5, 10, 11, -7, 3, 0, -3, 1, -1, -7, + -7, -3, -2, -6, -9, -6, -12, -4, -1, 0, -8, -5, -3, -3, -2, 3, + 1, 1, 9, 4, 2, 5, -1, 2, 6, 2, 0, -3, 2, 2, 5, 2, + -1, -4, 4, 1, 1, 2, -5, -8, -1, -3, -1, -9, -4, 1, -4, 5, + -6, -4, 0, 3, -9, 3, -3, -5, 1, 4, 4, 1, -4, 1, -4, 4, + 1, -6, 0, 5, 7, 8, 1, 6, 0, 3, 4, 2, -3, 1, -3, -3, + 3, -9, -6, -7, -2, -1, -3, -5, -6, -5, -5, -6, -5, 4, -3, 5, + 5, -2, -1, -1, -3, 6, -2, 5, 6, 2, 11, 8, -1, 3, -6, -2, + 5, 4, -3, -3, -5, -3, -7, -5, 0, -5, 2, 1, 0, 1, -7, 0, + -3, -2, -1, -2, -5, 7, -4, -2, -3, -2, -3, 4, 4, 9, 0, 1, + 1, -5, -3, -4, -4, 4, 3, 6, 0, -2, -2, -6, 4, 1, 1, -3, + 3, -1, 2, 0, -7, 0, 0, -1, -3, -2, -1, -5, -2, -3, -8, -5, + -5, -1, 5, 5, 2, 2, -3, 4, 3, 3, 6, 3, -1, 10, -4, -3, + -2, -3, 0, -4, 0, -2, -2, 0, 1, -4, -2, -5, -9, 8, -2, -1, + -1, -3, -3, -2, -6, 2, 1, 2, 9, 0, 1, 3, -4, 2, 4, -6, + -1, 2, -1, 6, 3, 0, -5, -3, -1, 0, 3, -3, 0, -6, -2, -3, + -4, -2, 0, 3, 2, 2, 0, -10, 1, -6, -5, -1, -2, 5, 3, 6, + -2, -6, -1, -3, 2, -1, 0, 0, -1, 0, 0, 0, 1, -2, 2, -2, + -5, -1, -2, 16, 12, -18, -10, 3, -14, -10, 16, -1, -3, -16, 28, 3, + -1, -1, 12, -5, -6, 6, 7, -7, -18, -28, 11, 0, 6, -2, 26, -21, + -10, -1, 24, -3, 20, -19, 15, -14, -3, -3, 15, -35, -2, 6, -14, 30, + 6, -36, -8, 17, 0, -27, 26, 16, -38, 8, -14, 57, 3, -31, -14, 34, + -20, 33, 2, -6, -7, -28, 20, -24, 8, 13, 8, -39, 17, 40, -42, -11, + 13, -46, 1, 28, -22, 11, -3, -14, 5, 20, -12, -4, 49, -22, -24, 39, + -11, -1, -9, 37, -30, 13, 34, 4, -11, -25, 18, -22, 1, 29, -17, -3, + -26, -16, -21, 12, -18, 7, -17, -6, 51, 0, -21, 10, 24, -45, 8, 14, + 31, -10, -37, 6, 0, 24, 3, -18, -13, 14, 11, 0, 7, -1, -38, -29, + -21, 32, -30, 22, -26, 14, -40, 55, -36, 30, -12, 8, 31, -16, 19, -15, + 23, -48, 36, 1, 63, 3, 24, 0, -3, 14, 26, -21, 15, 47, -21, -80, + 14, -4, -25, -33, 11, 25, -35, -44, 13, -2, -48, -11, -23, -7, 27, -4, + -15, -22, 5, 26, -36, 50, 23, 11, -23, -14, 19, 32, 14, 38, -66, 56, + -11, 26, 18, -12, 17, -30, -6, -54, 22, 77, -62, -12, -16, 34, -25, 2, + 14, -62, 12, 20, -22, -50, 58, -29, -58, 4, 28, 30, 13, 25, -78, 38, + 45, -19, -7, 52, -61, 27, 17, -21, -4, 6, 37, -24, -38, 73, 8, -16, + 21, -2, -15, -19, -19, 18, 3, 7, -48, -10, -10, 10, 4, 13, -13, -4, + 0, 46, -12, 6, -18, -25, 4, 14, 27, -22, -37, 14, -6, -17, 55, 40, + -111, 63, 9, -38, -16, 46, -35, 4, 0, -10, -8, -12, 58, -69, 1, 66, + -38, 21, -33, -6, 10, 0, 10, -11, 18, -16, 32, -7, -10, -25, 65, -42, + 42, -62, 18, -3, -2, -8, 21, 4, -71, 13, 40, -3, 18, -19, -29, 15, + -66, 60, -50, -6, 67, -80, 17, 66, -21, -20, -15, 68, -16, 72, -4, -23, + 4, 53, -8, 8, -4, 0, 27, -26, -22, 25, -31, 7, -39, -18, 27, -43, + -25, -33, -6, 17, -16, 0, -55, 6, 26, -3, -67, 7, 60, -83, 25, 15, + 45, -8, 51, -55, 28, 42, 42, -17, 37, -6, 17, 8, 11, -1, 59, -7, + -45, 14, -41, 107, -49, -50, -25, 63, -58, -27, -57, 19, 13, -13, -27, 19, + -42, 63, -113, -1, 44, 8, 1, -10, -33, 0, 55, -41, 15, 0, 76, -17, + -39, 60, -20, 28, 54, -93, 15, 83, -30, 4, -56, 49, -58, 30, -28, 2, + 54, -64, 83, -128, 86, 24, -40, -27, -66, 51, 11, -51, 59, 6, 20, -58, + -24, 78, -7, -23, -27, 1, -3, -24, 10, -6, -16, 34, 39, -37, -17, 26, + 52, -69, -7, 11, 24, -62, 38, -13, 41, 5, -2, -5, -12, 15, 77, -49, + -10, 74, -12, -11, -38, 32, -24, 25, -6, 19, -24, -2, -38, 63, -91, 64, + -27, -11, -56, -43, 27, -41, -55, -15, 1, -4, 27, 8, 37, -57, 3, 28, + -11, -4, 46, -39, 3, 12, 100, -33, 39, 17, 6, 49, 5, 38, -12, 10, + 21, -35, 23, -6, -36, 10, -9, 3, -1, 13, -65, -40, 36, -25, -28, 5, + -37, -20, -14, 31, -16, -32, -16, 4, 15, -11, 26, -16, 29, -42, 46, 7, + 39, -1, -5, -9, 33, -31, 35, -33, -7, 17, 56, -24, 22, 14, -22, -34, + 44, 16, 11, -46, 43, -48, -27, 43, 36, -45, 21, 11, 0, -98, -22, 87, + -126, 52, -45, 34, -28, -17, -31, 23, -38, 23, 25, -11, 25, -63, 21, 13, + 19, 47, 28, -23, 20, 21, -5, -14, 112, -30, -67, 37, 43, -12, -57, 34, + -9, -29, 52, -19, 14, -51, 0, 26, -69, 3, -18, -24, -34, 31, -15, -33, + -36, 10, -20, -38, 63, 0, 44, -50, 72, 25, -16, -6, 6, 15, 23, 31, + 3, -20, -9, 19, 63, 17, -18, -5, -12, -87, 31, 26, -37, -29, 49, -42, + -15, 14, 11, -16, -31, 46, -19, -13, -37, 59, -91, 47, 4, -11, -26, 39, + -29, -24, 48, 10, 39, -11, 45, -51, -1, -24, 47, -19, 39, -34, -29, -17, + 1, 56, -25, -16, -13, 0, 48, -71, 49, 2, -2, -45, -10, 59, -17, -25, + 9, 9, 44, 42, -32, -23, -49, 46, -11, -50, 76, -43, -45, -1, 41, -8, + 2, 71, -36, -61, 35, 21, -13, -36, 44, -45, 26, -45, -21, 28, -37, 39, + -29, 15, 4, -5, 24, -7, 7, 3, 68, -80, 26, 24, -22, 8, 26, 28, + 10, -26, -3, 16, -51, 85, -8, -14, -54, 39, -28, -9, -25, 46, -39, -20, + 34, 11, -25, -7, -12, -41, 12, -17, -5, -43, -8, 0, 18, 13, 9, 28, + -40, 34, 0, 13, 40, -20, 5, 22, -25, -13, 51, 9, -34, 43, -16, -18, + 2, 35, -4, -28, 14, -37, 6, -8, 31, -49, 9, -31, 61, -55, 35, -46, + -37, -12, 32, 74, -59, -30, -21, 5, 38, 3, 48, -35, -42, 2, 29, 81, + -8, -37, 24, 42, -31, 18, -11, -21, -67, 98, -18, 11, -26, -14, -76, 11, + 71, -70, 30, -52, 37, -45, 61, 6, -33, -44, 58, 24, -16, -51, 49, -28, + 51, -6, -15, 46, 10, -24, 36, -4, 6, -30, 46, -66, 54, 27, -16, -34, + -23, 90, -61, -49, 22, -3, -22, 17, -35, -11, -59, 23, 2, -25, 69, -24, + -26, -28, 37, 12, 11, -63, 27, 18, 3, 34, -25, 9, -14, 29, 4, 24, + 21, -77, 12, 14, 37, 1, 45, -63, 1, 49, -14, -23, -7, -4, -42, 48, + -57, 18, -36, 17, 15, -37, 47, 1, -41, -14, 11, 49, -32, 32, -36, -19, + 21, -11, 39, -31, 43, 0, -24, 15, 6, 9, -46, 5, 21, -23, 2, -28, + -15, 59, -13, -29, 50, -7, -45, -12, 23, -1, 27, 6, -17, 7, -4, -3, + -3, 53, -10, 17, -52, 19, 24, -8, -7, 19, -51, -30, 55, -22, -22, 29, + -38, -25, 39, 3, 34, -84, 26, -37, 42, 15, 4, -4, -16, -33, 29, 17, + 43, -93, 24, -6, -20, -14, 107, -29, -36, 69, -21, 10, -7, 74, -67, 38, + -23, -8, 27, -35, -49, 29, -8, -4, 7, -8, 5, -38, -28, -33, 22, 70, + -37, -10, -56, 26, 5, 7, 59, -21, -58, 10, -2, 6, 49, -16, -9, -38, + 60, 13, 43, -43, 23, -14, -9, 38, 17, -38, -15, 29, 6, -5, -11, -3, + -4, -65, 45, -13, 26, -13, -4, -5, -38, 48, 0, 4, -40, 40, -48, 23, + 21, 23, -42, 5, -17, 13, -9, 12, -3, 5, -25, 34, -24, -3, -18, 16, + -44, 13, 27, -30, 44, -54, 6, -18, -3, 4, 21, -25, -13, 22, -20, -12, + 37, -10, -10, 5, 24, -17, 23, 9, 0, 4, 3, 12, 26, -27, 17, 9, + -41, 69, -1, 15, -37, 15, -6, 0, -1, 3, -13, -23, -18, 27, -5, 21, + -16, -41, -2, 20, 13, -27, 6, -21, 8, 6, 0, 6, -5, -21, -22, 73, + -40, 4, 6, 21, -8, -5, 29, -47, -1, 1, 19, 3, -10, -1, 2, -48, + -11, 45, -27, 11, -33, -21, 21, 7, 12, -22, 21, -40, 13, 27, -20, 37, + 5, -18, -18, 35, 40, -11, 20, -25, 10, -4, 33, 12, -29, 9, -20, -30, + 34, 24, -9, -10, -24, -16, 8, 22, 6, -58, -5, -13, 18, 5, -43, 10, + -16, -25, 13, 70, -25, -7, -25, -19, 16, 58, -46, -5, 6, -5, 40, -24, + 22, 50, -73, -7, 7, 32, 39, -27, -23, -23, 56, -35, 21, 17, -40, 40, + -52, 4, 0, 49, -29, -42, 24, 9, 31, 2, -46, 0, -9, -5, 9, -31, + 64, -5, -45, -26, 42, -4, -34, -8, -3, 32, -15, -8, 22, -24, 13, -31, + -2, 31, 10, -10, -18, 8, 24, 20, -29, 2, 14, 23, 25, -4, -19, 20, + -25, -5, -3, 23, -8, 52, -42, -17, -7, 29, -26, 2, -19, 55, -50, -28, + 1, -10, -7, 7, -41, 16, 21, 1, -20, 0, 16, -19, 14, -39, 86, -17, + -34, -64, 73, 0, 20, -28, 30, -22, 9, 58, -4, -8, -18, -20, 31, -21, + 1, 26, -49, 5, 41, -25, -13, -6, -7, 6, 10, 42, -30, -26, -43, 11, + 44, -54, 31, -10, -11, -17, 25, 32, -43, 64, -23, 3, -37, 33, -30, -4, + -35, 47, -29, 9, 23, -34, -5, 64, -37, 32, -11, -44, 21, 25, -19, 8, + 6, -25, 34, 2, -18, -23, 38, 20, 7, 21, 1, -32, -37, 50, -9, -25, + 34, -61, 55, -32, 7, -48, 20, 13, 0, -35, 17, 9, -42, -28, 14, 42, + -33, -25, -5, 21, 41, -60, 32, -7, 38, -9, -3, 20, -4, 29, -69, 62, + -16, 35, -64, 45, 10, 5, -1, -18, -18, -1, 5, 32, 0, -21, -12, -23, + 29, -15, 13, -39, -3, -3, 6, 35, -24, -23, -7, -2, 44, -10, -37, 25, + 25, -25, -23, 7, 40, 4, -40, -18, 21, -2, -3, 1, -16, 45, -26, -2, + -16, 18, 41, -64, 8, -26, 40, 5, -32, 8, 18, -1, 15, -1, 9, 2, + 2, -13, -12, 35, -9, 13, -62, -29, 72, 18, 7, -30, 26, -7, -29, 39, + -38, 31, -56, -25, -3, 17, 2, -3, -46, 35, 6, 27, -39, -3, 3, 31, + -25, -19, -2, 38, 26, -77, 22, 18, 40, 3, -22, 65, -48, 33, -16, -37, + 78, -34, 1, -52, 23, 16, 1, -37, 17, 12, 1, -4, 8, -27, -1, -11, + -18, 27, -23, -10, -11, -19, -6, -7, 51, -74, 16, 20, 17, -14, 7, 7, + -13, -8, -5, -11, 39, 21, -5, -44, 31, 64, -38, -18, 20, 40, -4, -10, + 10, -23, 23, -6, -20, 11, 9, 10, 6, -23, -11, 1, 17, -56, 56, -40, + 0, -17, -60, 84, -80, 16, -13, 4, -25, 12, 17, -42, -26, 54, -29, 12, + -5, 37, 16, -62, 94, -5, -2, -2, -2, -9, 5, 51, -25, -5, -11, 5, + 16, -14, -9, 43, -44, -8, 27, 2, -1, 9, -18, -6, 5, 23, -46, -9, + 13, 16, -10, -10, -23, 59, -47, -14, 23, 29, -15, -14, -30, 21, -21, 0, + 14, -3, 25, -16, -35, -2, -8, 32, -19, 22, -23, -37, 30, -33, -19, 11, + 12, -32, 47, -4, 27, 11, 9, -35, 39, 29, -18, -2, -11, 27, -2, 13, + 0, 18, -26, 15, -25, 26, -4, 21, -29, -33, 18, -8, -31, -5, 21, -1, + -38, -28, 41, -18, -4, -22, 47, -12, -44, 55, -79, -5, 19, -10, 25, 4, + 21, 15, -28, 13, -6, 45, -24, 25, 10, -26, 4, 2, 31, 3, -7, 3, + 5, -23, 51, -9, -32, -5, 35, -32, -21, -20, 35, -40, -10, 20, -8, 7, + -5, -38, -1, -24, 39, -26, 20, -16, -9, -27, 25, 34, -32, 1, 12, -13, + 3, 37, 13, 3, -31, 27, 30, 5, -15, -21, 2, 10, -13, 16, 36, -9, + -59, 41, -10, 61, -60, -35, -11, 7, 5, -28, 30, 5, -23, -66, 34, 50, + -26, -19, -10, 11, 8, 8, -35, -5, -11, 56, -24, 10, 35, 16, -10, -19, + 30, 4, -11, 23, 0, -6, 6, 36, -15, 0, 15, -14, -26, -8, -5, 15, + -31, -45, 42, -30, 0, -9, 6, -22, 9, -22, 7, -8, 15, -19, -3, -13, + 29, -14, 9, -16, 3, -5, -10, 63, 0, 4, 4, 20, 16, -21, 18, 31, + -24, -19, 31, 54, -39, -7, -16, 5, -3, 0, -29, 16, 6, -29, -25, -52, + 49, -9, -66, -3, 50, -3, -2, -14, 4, -8, 33, -40, 2, 15, -6, -17, + -4, 10, 48, -16, 14, -9, 27, 10, 2, 2, 40, -35, 5, -10, 7, 28, + 1, 4, -30, -4, 0, 1, -14, -13, -11, 26, -17, 13, -44, -9, -6, -23, + 17, 11, 11, -21, -11, 0, 9, 8, 8, -30, 29, 10, -26, -12, 15, 17, + 4, -26, 14, 19, 20, -9, -24, 39, 23, -10, -35, 8, -6, 18, -25, 15, + -17, 41, -48, -31, -5, 47, -14, -20, -4, -7, 5, -19, 3, 21, 12, -23, + 15, -24, 8, 3, -25, 2, 28, 14, 21, 25, -72, 15, 26, -6, 45, -27, + 29, -30, -17, 23, 6, -2, 27, -46, 13, 9, 15, -57, 27, 1, -18, 1, + -11, -2, -20, -16, -23, 24, 18, -21, -5, -15, -14, 26, -12, 30, -48, 37, + -24, -3, 23, 9, -5, 9, 8, -43, 23, 26, 6, 28, -29, 30, -8, -12, + 25, -18, 33, -48, -4, 29, 1, -8, -4, -20, 41, -22, 1, 12, -33, 0, + -17, -16, 29, -3, -2, -36, 6, -1, -11, 4, -24, 40, -24, -5, 26, -2, + -28, 13, -11, 35, -9, -2, -3, -6, 13, 10, 1, 11, -22, 22, -27, -5, + 20, 11, -1, 8, -23, 8, 7, -7, 17, -6, 16, -9, -10, 3, 13, -3, + -17, 19, -21, 6, -13, -15, -7, 22, -15, -7, 11, -20, -19, -6, 0, 28, + -10, -7, -13, 9, 7, 1, -11, -6, 21, -33, -4, 52, -11, -1, -2, -2, + -4, 32, 17, -31, 7, 12, 2, -5, 11, -1, -6, 1, 3, -11, 5, 4, + -15, -8, 10, 5, -18, 5, -26, -11, 22, -15, -23, 22, 19, -30, 3, 1, + -5, 10, -17, 10, -2, 10, 7, -17, -5, 36, -12, -24, 27, 22, -3, -11, + -6, -7, 20, 5, -21, 0, 23, -31, -27, 14, 2, 8, 7, -15, 0, 13, + -7, -3, -21, 33, -4, -26, 7, 5, -7, -7, 1, 3, 4, 11, -24, 6, + 11, -7, 14, -9, -11, -1, 34, -22, 11, 1, -18, 17, 4, -19, 28, -15, + -7, -11, 12, 1, -7, -9, -12, 17, -20, 6, 5, 2, -10, 12, -23, -3, + 26, -1, 4, 6, -25, 12, -3, -26, 2, 15, 14, -18, -6, -17, 14, 4, + -10, 21, -13, 5, -15, -20, 27, 6, 8, -11, 18, 15, -34, 17, -2, -13, + 41, -9, -10, -6, -2, 7, -11, -4, 28, -26, -6, 25, 17, -36, -2, 33, + -39, -15, 11, -2, 26, -32, -31, 21, 26, -11, -24, 12, -17, 4, -33, 24, + 14, -10, 12, -19, -3, 28, 11, -8, 0, 26, -17, -7, 8, -6, 20, 26, + -29, -27, 25, -14, -2, 10, -16, 39, -24, -17, -4, -13, 24, -10, -3, -20, + 25, -1, -24, 24, -20, -5, 21, -26, 7, 21, -26, 15, 17, 6, -34, 5, + 11, -27, 20, 17, -13, -8, -16, 9, 33, -36, 19, 5, 4, -2, -33, -12, + 38, -17, -10, -4, 19, 14, -4, -32, -41, 64, 5, -38, 28, 6, -2, -11, + -22, 11, 17, 17, -24, 23, -7, 9, 10, -38, 0, 25, -9, -6, -27, 20, + 2, -27, 34, -23, 17, -22, 4, 12, -43, 29, -8, 25, -19, 13, -17, -11, + 27, -8, 14, -19, 12, 9, -22, -6, 11, -10, 17, -4, 2, -3, 15, -47, + 32, -18, 11, 14, 0, 8, -33, -14, -12, 23, 17, -12, -4, 13, -27, 10, + -17, 20, -2, -11, -11, 27, 18, -21, -6, 26, -18, 9, -7, 27, -12, 3, + -9, -9, 22, 7, -38, -2, 14, -16, 12, -21, -10, 22, 1, -28, 20, 31, + -11, -49, 9, 16, -4, -7, -4, -5, 46, -39, 9, -18, 16, 22, -24, -13, + 14, 29, -10, 3, -23, 4, 11, -33, 30, 18, -9, 5, -11, 4, -20, 30, + -9, -14, -7, -9, 4, 0, 4, -15, -11, 23, 5, -24, 26, -6, -8, -17, + 21, 0, 3, 13, -10, -13, 19, -16, -10, -5, 10, 8, 22, -19, 4, -8, + 0, -24, 38, 12, -33, 10, -9, 5, -13, 11, 3, 7, -18, -12, 11, -4, + 8, -17, -7, 16, -9, -2, -9, 0, 10, -2, -1, -1, 12, -6, 13, -18, + 18, -6, 10, 1, -3, 9, -2, -30, 23, -9, 29, -11, -31, 10, 6, -21, + -19, 54, -30, 18, -12, -26, 23, -10, -31, 23, -5, 49, -34, 4, -18, 3, + 11, -24, 27, 12, -24, 3, -13, 3, 16, -6, -7, 1, 19, -8, -3, -11, + 13, -14, 19, 10, 17, -21, 14, -40, 12, 13, -5, -3, 21, -14, -29, 16, + -24, 1, 10, -1, -3, 6, -15, -16, 16, -4, 2, 23, -32, -1, 7, -5, + 13, 4, -15, 33, 1, -7, -7, -12, 13, 6, -8, 2, 21, 2, -21, 17, + -14, -19, 36, -2, -16, -4, 3, 9, 15, -39, 3, 9, -10, -3, -12, -7, + 28, -19, 8, -18, 22, -18, -11, -2, 17, 23, -15, -24, 11, 13, -14, -10, + 9, 4, 14, -10, -13, 13, -3, -12, 25, 6, -12, 12, -19, -3, 19, -10, + -13, 19, 10, 18, -31, -15, 19, -9, -14, -6, 25, -18, 2, 17, -41, 11, + 16, -20, 3, -10, 16, 9, 14, -27, -1, -3, 9, -19, 36, -6, -4, -4, + -16, 5, -7, 24, -1, -30, 13, -8, -4, -9, 47, -37, 3, 21, -24, 1, + 3, 11, 5, -10, -8, 20, -31, 16, 10, -1, 0, -9, -1, -6, 14, -6, + 6, -17, 20, 3, -23, 10, -14, 17, -16, -2, 26, 7, -20, -10, 9, -18, + 31, -35, 3, 14, -8, 13, -27, -4, -4, 26, -20, -9, 14, 22, -27, -4, + 18, 9, 9, 3, -13, -20, 15, -13, 6, 12, -5, -6, -12, 0, 4, -10, + 18, -7, -8, -15, 1, -11, 17, 5, -11, 14, -6, -11, 4, 10, -5, 13, + 0, -7, 15, -2, -16, 2, -3, 9, -6, 2, 34, -11, -17, -8, 21, 13, + -21, -4, 14, -7, -7, -19, 13, -7, 4, -25, 7, 16, -14, -40, -11, 36, + 3, -10, 4, -10, 7, -1, -1, 4, 14, 6, -14, -14, 17, 23, -13, -2, + -1, -12, 9, 8, 1, -7, 22, -29, 7, 7, 0, -24, 13, -10, 18, -1, + -3, 13, -24, 30, -32, -5, 18, -2, -6, -8, 11, -18, -12, 17, -11, 0, + 5, -4, -14, 31, -15, -16, 13, 12, -4, 4, -4, -1, -11, -15, 26, -18, + 29, -15, -3, -8, 6, 6, -34, 22, 0, 11, -18, 16, 20, -19, -21, -5, + 11, 21, 10, 10, -27, -5, 3, 2, -5, 9, -9, -1, 1, -11, -3, 8, + 4, 1, -1, -11, 19, -1, -21, -5, -2, 11, -2, -8, 10, -7, -1, 2, + -18, 3, 0, 7, 2, 7, 1, 1, -28, -14, 10, 19, 12, -21, 7, -19, + 20, -2, -3, -1, 17, -11, -13, -16, 32, 4, -5, -3, 4, -4, 18, -2, + -17, -6, 16, -3, 4, -12, 4, -2, 2, 6, -18, 20, -24, 17, -10, 19, + -16, -17, 8, -7, -5, 16, -12, -18, 11, 9, 2, -8, 17, -9, -3, -13, + 7, -6, 30, -15, -11, 5, 14, -2, -15, -5, 14, 13, -12, -24, -10, 22, + -2, -8, -1, 21, -5, -19, -16, 8, 42, -6, -27, -12, 23, 10, -17, -14, + 16, 14, -16, -2, 9, -2, 16, -9, -31, 22, 0, -2, 3, 4, -5, 20, + -24, -5, 13, -1, -5, -10, -6, 8, -11, 2, 8, -8, -5, -9, 1, -6, + 16, -1, -18, 4, 9, -3, 6, -4, 6, 9, -7, -9, -1, 10, -7, 4, + 3, -3, 4, -8, -5, 3, -4, 10, 6, -15, 2, 3, -5, -2, -3, -12, + 18, 2, -16, 7, 13, 0, -19, -8, 11, -6, -1, -9, 5, 13, -8, -6, + 6, 7, 11, -11, -6, 13, -2, -5, -1, 9, -2, -7, -15, 10, 5, -1, + -13, 8, 0, -6, -2, -2, 18, -16, -7, 2, 3, -4, 6, -11, 4, 6, + 1, -5, 22, -11, -5, -6, -3, 11, -1, -1, 4, 1, -4, -13, -4, 11, + -9, 1, 9, -1, -8, 1, -5, -7, 5, -14, 18, -1, -12, 11, -12, 16, + -5, -11, 11, -2, 15, -7, -18, -10, 0, 18, -12, 8, 3, 6, -16, -3, + 3, 6, 0, -1, -3, 4, 9, 3, -17, -7, 11, 11, -19, 5, 15, -12, + -3, -12, 4, 11, -19, 0, 0, -14, 21, -15, 2, 8, 3, 8, -8, 5, + -18, 9, -2, -8, 23, -5, -16, 5, 3, -20, 13, 11, -6, -15, 5, 4, + -12, 2, 10, -5, -12, 5, -14, -2, 18, 11, -14, 0, 28, -10, -20, 4, + 7, 9, -13, -6, 15, 11, -9, -6, 14, -8, 10, 4, -12, 11, -18, 13, + -17, -9, 16, -4, -14, -7, 17, -24, -5, 4, 6, -6, 14, 2, -24, -22, + 11, 13, 8, -16, 6, 13, -28, 10, -2, 11, 8, -1, -8, -14, 22, 3, + -5, -13, 18, 7, -26, 15, 20, -6, -10, 4, 11, 5, -8, -3, -5, 0, + -1, -6, 0, 4, 4, -14, -1, 1, 8, -14, -10, -4, 6, 4, -8, 3, + -9, 0, 11, -4, -7, 5, 4, 6, -29, 18, 22, -19, -16, -11, 17, 7, + -4, 3, -23, 20, 8, -19, 3, 13, 13, -16, -18, 15, -6, 0, 3, 17, + -7, -4, 2, -22, 21, -1, -2, -1, -15, 13, 3, -7, 4, 0, -7, 8, + -7, 11, 3, -2, -8, 10, -15, 0, 9, -14, -8, 8, -2, -9, 10, -13, + 9, 7, -6, 2, -12, -4, 6, -12, 8, 12, 3, -10, 6, 7, 1, -2, + -11, -1, 7, -7, 8, -13, -10, 11, -9, -10, -8, 20, 9, -11, 8, -5, + -4, 6, -3, 5, 13, -13, -7, -7, 6, 19, 0, -9, 9, -1, -3, 4, + -7, 0, -2, -4, -5, 5, 0, -5, 14, -19, -14, 18, -1, -5, 3, -12, + 18, -19, 4, -15, -10, 10, 10, -17, -4, 19, -6, -2, 5, 11, -4, -3, + 9, -22, 28, -6, -5, 0, -1, 11, -11, -13, 22, 3, -8, -9, 1, 3, + 0, 1, 2, 7, -5, -25, 10, 6, 6, 2, -11, 8, -16, 15, -20, 5, + 9, -6, -13, -5, 14, 6, -21, 22, -7, -14, 4, 26, -8, -13, 8, 1, + -10, -13, 11, 10, -10, 2, -13, -9, 15, 0, 10, -30, 14, 7, -13, -5, + -12, 8, 10, -4, 10, 12, -15, -7, 5, 2, 2, 10, -13, -3, 0, 21, + -2, -16, 9, 3, -1, 6, 15, -3, -21, 10, -8, 5, 1, 1, 2, -19, + 10, -7, -3, -1, 8, 6, -26, -10, 18, -28, -3, -3, 4, 0, -7, 6, + -10, -2, 25, -19, 5, -11, -2, 14, 4, -5, -3, 4, -5, 6, -2, -3, + 11, -1, 13, -12, 5, 20, -15, -3, 17, 4, -14, -5, 11, 3, 1, 6, + 11, -20, 10, -4, -4, -4, -4, -18, -7, 5, 10, -25, 7, -9, -15, 1, + -4, 4, 4, -4, -1, -18, 9, -6, 4, 7, -19, 10, 0, 3, -6, 12, + 18, -5, 2, 4, -4, 11, 2, 5, 2, 1, 3, -4, 3, 4, -3, -2, + -8, 11, 5, -10, -12, 12, -6, 6, -9, -6, 4, 9, 0, -9, 4, 3, + -7, -5, -12, 19, 2, -28, 1, 0, 9, -10, -6, 3, 3, -11, -4, 6, + 7, -7, -3, 5, -12, 9, 10, -12, 7, 5, 5, -6, -9, 16, 6, -16, + 3, 8, -17, 12, -5, 2, 1, 21, -25, -10, 5, -2, 15, -6, 1, 3, + 5, -16, -2, -16, 32, -17, 7, -13, 6, -1, -4, 0, -4, 10, -2, -17, + -7, 29, 0, -13, -1, -1, 2, 12, -4, 3, -2, 4, -19, -1, 18, 2, + -3, -15, -2, 10, -4, 1, -2, -5, 20, -5, -6, -7, 9, 0, -2, -24, + 5, 15, -2, -11, 1, 0, -2, -14, -2, -4, 7, 4, -4, -9, 2, 4, + -8, 8, -1, 2, 10, -13, 4, 10, -4, 27, -22, 17, -18, -2, 5, 8, + -1, 4, -6, 2, -1, 9, 1, -3, 16, -21, -18, 2, 10, -14, 9, 3, + -14, -9, 0, -16, 9, -10, 11, -12, -3, 1, -10, 3, -2, 2, -13, 13, + 10, -1, 4, 4, 1, -3, 9, 0, 4, 8, -14, 10, -4, 0, 8, 11, + -2, 2, -11, 3, -13, -8, 11, 4, 1, -7, 4, -21, 0, 1, -4, -22, + 17, -8, -16, 10, 4, -2, 0, -4, 2, -2, 2, -6, 10, 3, 3, 5, + -1, 6, 5, 2, -6, -3, -2, 7, -4, -4, 12, 1, -30, 12, -7, 3, + 4, -6, -7, -9, 9, -1, 7, -10, 12, -16, 2, -8, 23, -5, -5, -1, + -8, 10, 3, -14, -12, 25, 7, -13, -6, 4, 15, -3, -23, 9, 12, -9, + -13, 18, -9, 5, 1, -17, -4, 13, -10, 11, -10, -1, 6, 0, -7, -2, + 9, -4, 9, -24, 7, 6, -5, 4, 15, -15, 11, -5, -24, 9, 11, -16, + 2, 0, -9, -2, 10, 7, -12, 8, -12, -6, 10, 6, 10, -14, -5, 20, + -16, 7, 8, -1, -19, 24, 2, -10, 15, 6, -6, -21, 3, -3, 15, -9, + -3, 3, -2, -4, -3, -9, 5, 0, -5, -3, -15, -4, -1, 1, -14, 33, + -12, -18, 9, -2, -10, 9, 9, -1, -1, -5, 10, -3, 2, 4, 2, -9, + -1, 25, -2, -3, 15, -17, -7, 8, -7, 0, 10, -13, 9, -11, 0, -3, + 18, -15, -11, 5, 0, -12, -2, 7, -6, -4, -9, 11, -6, 8, 1, -14, + 3, 16, -10, -3, 2, 6, 4, 9, -9, -2, 0, 2, -3, 15, 3, -10, + -4, -8, -1, 10, -13, -9, 16, -9, -3, -2, 5, -6, -6, -9, 10, 8, + -4, 14, -7, -19, 12, 1, 2, 1, 4, -1, -6, -3, -3, 5, 7, -2, + 0, 0, -5, 0, -6, 1, 6, -5, -4, 5, -6, 5, -4, -8, 15, -5, + -7, 0, 3, -8, 0, 3, -8, -4, 6, -4, -4, 15, -5, -8, -7, 4, + 7, -10, -6, 15, -4, -13, 7, 2, 2, 1, -4, 5, 0, 0, 1, 4, + -7, 4, 4, -2, 4, 5, 1, -18, 12, 4, -3, -6, 11, 0, -13, -1, + 1, -12, 3, 13, -9, -15, 7, 0, -4, -8, 0, 5, 0, -9, 1, 1, + -3, 0, 3, 5, -10, 6, -1, -4, 4, 15, -15, -5, -9, 18, -2, 0, + 15, -11, -9, 0, 6, -2, 8, 1, -8, -9, 7, 3, -7, -3, 6, 1, + -5, 0, -5, -5, 0, -3, 11, 1, -3, -8, -4, -4, 5, 9, -6, -7, + 4, 15, -13, 5, -4, 2, -6, -2, 0, 5, 4, -4, 0, -6, 8, 3, + -2, -4, -4, -11, 4, 10, -1, -4, -2, -1, -3, 1, -4, -2, 3, 1, + -4, -11, 12, -4, 5, -2, 7, -12, -2, 4, -4, 5, 8, 1, -8, 14, + -11, -1, 1, 4, 0, 5, -5, 2, -7, -7, 10, 3, 1, -13, 0, -4, + 5, -9, -1, 1, -11, -5, 5, 2, -6, 5, -5, -8, 12, -2, 7, -1, + -10, -5, -7, 14, 9, 3, -5, -2, 5, 4, -2, 0, -5, 2, 3, 3, + -12, 6, 3, 2, -9, -1, 24, -13, -9, -1, -2, 0, 7, -6, -17, 14, + -12, -5, 10, 1, -4, -1, -1, 1, -3, 2, -2, -11, 1, -1, -1, 1, + 10, -3, 2, 1, 5, -7, 1, -1, -5, 7, 1, 7, -4, 5, -11, -8, + -8, 7, 8, 6, 0, -15, -1, 7, 0, -6, -3, 7, -4, -3, -2, 1, + 5, 8, -6, -4, 11, 3, -14, -6, -3, -6, 9, -5, 4, -5, 2, 3, + -13, -3, 1, -4, -3, 11, -1, 0, 7, -16, -6, 11, 5, 0, 4, 5, + -2, -3, -2, 8, 7, -16, 1, 2, 6, 3, -17, 11, -2, -2, -9, 6, + 0, -7, 6, -22, -2, 14, 3, -11, 0, -6, -2, -7, -7, 1, 4, 14, + -1, -6, 0, 7, 3, -14, 4, 15, -4, -9, -2, 12, 14, -10, 5, 9, + -11, -2, -9, 2, -9, 11, 2, -21, 7, 6, -11, -1, 0, 0, 1, -9, + 4, 0, -10, 1, 3, -3, -7, 12, -9, -2, 4, 6, 3, -8, 0, 1, + -2, -14, 12, 11, -5, 10, -3, -1, 3, -6, 1, 0, -3, 8, -1, -18, + 12, 5, -13, -4, 17, -1, -6, 1, -11, 0, -6, 2, -2, -2, 5, 3, + -17, 2, -5, 11, -4, 8, 8, -19, -6, 14, -6, -6, 0, 5, 0, -8, + 7, 13, -6, -5, 6, -2, -9, -1, 8, 3, -4, -4, 10, -10, -9, 7, + 2, -6, 14, 0, -15, 3, 5, -4, -10, 8, 0, -6, -11, 3, 10, -9, + 1, 8, -7, 2, -1, -6, -8, 6, 2, -8, -2, 16, -3, -3, -1, 5, + -3, -8, 6, 9, -6, 1, -1, -1, 2, -6, 6, -1, -9, 3, 9, -10, + 1, 5, -4, -14, 2, 1, 7, -5, 3, -2, -13, 5, 10, -9, -8, 14, + -6, -19, -3, 19, -3, -3, 6, -4, -10, 3, -1, -4, 5, 5, 1, 0, + -1, 11, 4, -10, 3, -5, 4, -7, 1, 8, -3, 1, 2, 0, -10, 2, + 5, -15, -3, 8, -8, -6, 5, -2, -5, -5, 11, 0, -12, -7, 5, 2, + -5, 2, -1, -4, 2, 7, -12, 5, 6, -3, 5, -1, 12, 7, -13, -3, + 0, 3, 0, 13, -1, -4, 0, -9, 5, -6, 5, -2, -10, -6, -2, 9, + -8, 5, -6, -10, 5, 4, -6, -2, 1, 1, 6, -14, 10, -3, -4, -5, + 1, 8, -16, 7, 7, -1, 0, 3, -5, 2, -1, -3, 11, -11, 9, 8, + -18, 3, 8, 13, -4, -5, -9, 4, -2, -4, 9, 5, -6, -5, -15, -3, + 17, -6, 2, -8, 4, 4, -4, -12, -3, -2, -2, -4, 5, -4, 1, 7, + -12, -6, 8, 6, -2, 1, -3, 3, 10, -3, 7, -11, 12, 4, -1, -1, + 1, 0, -11, 11, 4, 0, -2, -9, -2, -2, -8, -1, 5, -4, -5, -5, + 1, 10, -8, -11, -5, -4, 5, -1, 1, 6, -2, -5, -5, 3, 6, -2, + 6, -3, 0, 4, 5, 2, 4, -2, 1, 5, -2, -6, 11, -1, -5, 8, + -14, 6, -2, -6, -11, 4, 2, -14, 6, -9, 5, -4, -3, 4, -12, -2, + 2, -5, 4, 7, -5, 3, 6, -1, -3, -6, 0, 7, 0, 1, 6, 9, + 4, -2, -7, -4, 7, 4, 4, -5, -5, 0, 3, -6, -1, 7, -2, -18, + -1, 3, -15, 5, -2, -2, 0, 4, -10, -4, 3, 4, -10, 4, -1, 5, + 4, -7, 8, -7, 0, 3, 2, -7, 13, 0, -2, -6, -6, 5, 10, -10, + 4, -1, 2, -1, -5, 7, 5, -3, -7, 1, -5, 10, 1, -11, 7, 6, + -10, -15, 12, 2, -4, 1, 0, -5, 3, 0, -2, 6, -5, -4, -13, -2, + 3, 1, 4, 3, 3, -10, -7, -7, 11, -2, 2, 2, -7, 4, -1, 6, + 2, 0, 8, 3, 0, -7, 8, 3, 5, -8, -3, -2, 2, 3, -12, -4, + -3, 12, -12, -4, 7, -3, -10, -10, -4, 6, -2, -8, 9, 1, 1, 1, + -3, -6, 12, -5, -6, -1, 11, -7, 5, 6, 2, 9, -11, 6, -2, 8, + 1, -6, 4, 3, -6, -3, 5, -4, 4, 1, -19, -1, 3, 4, 0, 0, + -10, -1, -3, -5, -3, 0, 11, -1, -12, -2, 6, 0, -3, 3, 4, -1, + -7, 1, -2, -1, 2, -1, 0, 2, -2, 4, -5, -4, 11, -4, -5, -3, + 7, 5, -8, 3, 6, -9, 0, 9, -5, -2, 5, -4, -6, 0, 7, -1, + -2, 0, -1, -6, -9, -6, -1, 8, 4, -1, -9, -5, 13, 2, -11, -5, + 9, 0, -8, -1, 5, -2, -5, -3, -2, 7, 5, -4, -13, 3, 11, -8, + 3, 0, 2, 5, -12, -6, 6, 3, -4, -1, 8, 1, -5, -7, -6, 2, + 8, 5, -2, -9, 7, -6, -2, 13, -7, 2, 1, -1, -5, 3, 7, -1, + -11, 9, -6, -4, -2, -5, -1, 2, -1, 3, 8, -7, -1, -9, 0, 0, + -1, 2, 5, -2, 1, -2, -3, 6, 6, -3, -6, -5, 4, -1, 1, 5, + 1, -1, -2, -3, -4, 4, 3, 1, -7, 5, -1, 0, -8, -6, 1, 7, + -3, -6, -2, 3, -1, -3, 2, 2, 0, -9, 1, -2, 4, 4, -5, 1, + -1, 1, 6, -2, 2, -5, -4, -1, 14, -3, 2, -9, 1, -2, -4, 1, + -1, 7, -9, 5, 2, -3, 2, -2, -9, -2, 4, -1, 2, -2, -2, 0, + -1, -1, -2, 3, 1, -1, -3, -6, 3, 7, -5, -3, 9, -5, -4, -5, + 8, -4, 2, 2, 8, -10, -1, 8, -14, 0, 6, -7, -1, 2, -3, 2, + -4, 5, 2, -5, -4, 5, 1, -6, 3, 6, -4, -1, -3, 3, -7, 0, + 1, 0, -4, 7, 6, -13, -3, 3, 2, -15, 8, 3, -3, -6, 9, -4, + -1, 9, 1, -6, -6, 7, 1, 1, -2, 6, -1, -4, -1, -1, -7, 5, + 3, 0, -5, -2, 8, -2, -8, 6, 7, -16, -5, 6, -6, -1, 1, 7, + -4, -3, -6, 3, -10, -3, 8, -9, -1, 5, -1, -7, 5, 2, -1, 1, + 5, 1, 2, -4, -5, 1, 1, 3, 1, -5, -2, 3, 2, -7, -1, 7, + 5, -5, -7, 5, 0, 3, -1, -4, -4, 4, 0, -4, 1, 6, -3, -7, + 0, -3, -3, -1, 0, -2, -4, 2, 1, -2, 3, -1, 0, -1, -6, 9, + -5, 4, -1, -1, 4, -2, 5, -8, 2, -3, -2, 2, -3, 10, 2, -3, + -5, 2, -4, -1, -3, -7, 9, 1, 0, 0, -5, 1, -2, -12, 6, 8, + -18, 4, -1, 4, -1, 5, -5, -3, 3, -1, 4, -5, 9, -5, -4, -5, + 2, 5, -1, -4, 0, -3, -2, 8, -5, 2, 1, -13, 3, 1, 4, 5, + -8, 2, 8, 1, -1, 1, -9, 1, -2, -4, 1, 4, -3, 4, -4, -5, + 6, 5, -6, -3, -3, 1, 1, -7, 1, 2, 1, -5, -4, -2, 2, -6, + 6, 3, 7, -10, -9, 4, 1, -5, 6, 9, 3, 1, -2, -4, 3, 4, + -1, -6, 3, 1, -2, -9, 4, 4, -5, 4, -10, 2, -4, -5, -1, 1, + 2, 0, 2, -8, 1, 3, -4, -13, 0, 10, -1, -4, 5, 0, -4, 5, + -3, 2, -5, 2, 1, 2, 4, 2, 2, -10, 5, 3, -11, -2, 3, 3, + 0, -6, -2, 1, 1, 2, -1, -8, -1, -5, -4, -3, 5, 8, -4, -4, + 2, 0, -2, -2, 1, -5, 0, 13, -8, -6, 4, 8, -6, -1, 6, -2, + 4, -5, 3, 5, -7, -8, -2, -3, 7, 8, -8, -3, 1, 5, -5, -5, + 9, -4, -7, -5, 4, 3, -6, 5, 1, -1, 3, 0, -6, -9, 0, -6, + 1, 4, 10, 5, -13, 0, 6, -2, -4, 2, -2, 6, -1, -4, 0, -11, + 6, 3, -1, -3, 14, -1, -15, 1, 2, 3, -1, 4, -3, -6, 0, 3, + 0, -6, 10, -3, -14, -2, 10, -3, -9, -4, 0, 6, -1, 7, -3, -5, + -6, 1, 0, -5, 11, -2, 1, -2, 5, -1, -4, -1, -3, -4, 2, 11, + 2, -4, 1, 2, -12, 7, 3, -1, -11, 3, 15, -8, -11, 0, 0, 2, + -7, 1, -3, -4, -3, -5, -4, 6, 11, -7, -8, -1, 6, -5, -3, 6, + 8, 3, -6, 1, -1, -1, -1, -5, -3, 8, 7, 4, -9, 1, -2, -4, + -6, 9, -4, 3, -8, 0, 6, -2, -4, -2, -2, -6, 8, -7, 3, 1, + 3, -1, -3, 2, 1, -6, -9, 3, -5, 8, 5, -10, 7, 5, -3, -2, + -1, -3, -1, -4, -7, 6, 6, 3, -7, 0, 0, 1, 0, -7, 3, -1, + 0, 1, 2, 2, 2, -11, -8, 9, 6, 2, -6, -1, 1, -3, 3, 1, + -6, 2, -3, -2, -1, 2, -4, 0, -4, -2, 0, -3, -2, -6, 5, 2, + 0, -1, -3, -1, 3, 1, -2, 0, 2, 2, 0, 1, 7, 1, -4, -2, + -6, 4, 3, -1, -4, -1, 3, 3, -9, -2, 0, -2, -1, -5, 6, 1, + -5, 1, -5, 9, -10, -4, 0, -4, 6, 1, -3, -5, 9, -2, -5, 2, + 0, 6, -6, 2, 5, 10, -8, -3, -2, -1, 4, -3, -1, -4, 0, -1, + 1, -4, 0, 5, -8, -1, -5, -1, -1, 3, 3, 3, 2, -14, -5, 1, + 2, 3, 1, -1, 2, 5, -2, 2, -5, 2, 3, -2, -2, -3, 4, 4, + 4, -6, 3, 1, -10, 1, -6, 6, -2, -3, 0, -3, 1, -3, 1, -1, + -4, -5, -4, 7, -2, -2, -3, 6, -5, -5, 2, -6, 1, 4, 3, -8, + 11, 4, -4, -1, 2, 3, -5, -2, 1, 7, -4, 2, 4, -10, 7, -7, + -1, 0, -3, 5, -4, -1, -4, 5, -7, 3, 3, -11, -2, -1, 5, 1, + -1, 0, 6, -11, 0, 1, -2, 1, 0, -1, -4, 2, 9, -2, -9, -4, + 2, 0, 2, -1, 1, 1, -7, 5, -3, 4, -1, -3, -8, 5, 7, -1, + -1, -3, 3, -7, 0, 4, -3, -3, 1, 6, 0, -1, 0, -5, -1, 0, + -4, 0, 0, -3, 1, -4, 1, 7, -3, -13, -2, -2, -1, 3, 5, 2, + -6, 1, 6, -2, -6, 8, -1, -6, 0, 4, 6, -2, 0, -2, -4, 3, + 5, -4, -7, 2, 5, -3, -3, 3, 1, -10, -7, 3, 1, -3, 2, 4, + -7, -3, 0, 2, -5, -3, 3, -2, 0, 3, 5, -6, -1, 4, -2, 0, + 5, 1, -2, -2, 3, 2, -1, -3, -3, -7, 7, 3, -1, -2, 0, 0, + 1, -2, 1, 0, -15, -1, 3, 2, -3, 4, 0, -7, 0, -1, -1, -4, + -3, 2, -1, -1, 11, -3, -1, -5, -1, 2, 2, 0, 1, 2, 3, 4, + -6, -3, -2, 1, 0, -4, 2, 1, -1, -5, 1, -1, -7, 2, -2, -5, + 0, 2, -2, 3, 5, 0, -2, -6, 6, -7, 3, -4, -6, 1, 6, 3, + 1, -2, -3, -4, -6, -1, 7, -2, 0, -3, 0, 9, -3, -5, -1, 3, + 0, -1, -3, 6, 1, -6, -3, 3, 6, 0, -6, -4, 2, 1, -1, 2, + -5, 4, 1, -2, -5, 0, 7, -9, 3, -1, 1, -6, 0, -5, -1, 1, + -1, 0, -4, 2, -2, -2, 1, 6, -1, -5, 0, 0, 0, 1, 3, 2, + 2, -1, -3, 0, 1, 5, 1, -5, -7, 2, 6, -3, -3, -3, 2, -7, + -5, 5, 0, 0, -3, -4, -1, 3, -4, -5, 1, 5, -1, -2, -4, 0, + 5, 2, 0, 2, 2, -1, -1, -5, 5, 3, -1, -4, 1, 0, -1, -2, + -1, 2, 2, -4, -4, 2, -2, -3, -4, -3, 0, 3, -3, -2, -2, 4, + 1, -2, -2, 1, 2, -6, -1, 2, 6, 1, -2, 0, 4, -3, -1, -2, + -1, 5, 1, -11, 4, 3, -1, -6, 2, -2, 3, -4, -8, -2, -1, 4, + 0, 3, -2, -1, -2, -2, 1, 3, 3, -7, 0, 2, 10, 0, -4, 3, + -3, 0, 0, 3, -4, 6, -4, -8, 2, 1, 3, -14, 1, -1, -2, 0, + 0, -5, -1, 2, -6, -1, 3, 0, -5, -3, 3, 1, 6, -2, 0, 6, + 2, -7, 1, 3, -5, 5, 8, 0, -1, 1, -4, -6, -2, 6, 4, -4, + -1, 1, -10, 0, -4, 0, -3, 2, 0, -8, 3, -3, 0, 2, -1, 1, + -8, -1, -1, -3, -1, 4, 1, 6, 1, 0, 0, -2, 0, -2, 7, -4, + 3, -1, 2, 0, -2, -2, -8, 3, 2, -1, -4, 3, 0, -3, -5, 2, + -3, -3, -2, 5, 2, 1, 1, -4, 1, -1, 4, 6, -4, 0, -6, -4, + 1, 3, 3, -1, -2, -7, -1, -3, 6, -6, 2, 1, 5, -8, -5, -1, + 2, -1, -3, -1, -1, 5, -7, 3, 3, 1, 4, -4, -3, -3, 8, 1, + -2, 4, 4, -2, -8, 2, 1, 0, 2, 0, -6, 3, -2, -8, -2, 5, + -1, -6, 0, 2, -1, -5, -2, -2, 6, 0, -5, -2, 3, 0, -5, -1, + 6, 7, 2, -8, -4, 6, 2, -6, -4, 12, 2, -5, -2, -6, 1, 1, + -3, -7, -3, 11, -3, -6, -1, 3, -2, -4, -4, 4, -3, 4, -2, -3, + 1, 7, 0, -8, 7, 1, -2, -4, -6, 13, 0, -3, 1, 2, -1, -4, + -3, 1, 3, -2, -3, -1, 0, 3, -1, -10, -1, 2, -8, -3, 3, 2, + 1, 4, -6, -2, 1, -3, -1, -4, 6, 5, -1, -5, -1, 9, -2, 0, + -4, 0, 1, -3, 4, -5, 1, 3, -4, -6, 0, 4, -2, -6, 9, -1, + -3, 2, -4, 0, 4, -7, -4, -1, 1, 4, 0, -1, 6, -2, -2, 4, + -3, -1, -6, -2, 2, 3, 1, -3, 8, -10, -10, 7, 0, -2, -1, -4, + 3, -6, 0, -5, -5, 5, 3, -6, 1, 5, 0, -1, 1, -1, 0, 0, + 0, -5, 7, -2, -1, 2, -1, 3, 0, -6, 4, -3, -2, -3, -2, 1, + 3, 3, 0, -2, -1, -9, 2, 2, -1, 4, -4, 4, -10, 7, -8, 2, + 1, -1, 0, -1, 4, 2, -7, 7, -6, -4, 3, 11, -5, -6, 1, 3, + -4, -6, 2, 2, -2, -3, -7, -4, 6, 0, 7, -13, 6, 2, -9, -2, + -5, 3, 8, 0, 0, 5, -5, -4, 3, 0, 2, 4, -7, 0, -1, 10, + -3, -6, 7, 2, -1, 0, 6, -2, -7, 4, -2, -1, -2, 1, -3, -9, + 6, 0, -4, 0, 3, 3, -11, -4, 7, -16, -2, 0, 2, 1, -2, 2, + -5, -1, 12, -6, 2, -7, 2, 6, 0, -4, -1, 1, -3, 2, -1, 0, + 7, -2, 2, -6, 2, 7, -9, -4, 8, 2, -9, -3, 8, 1, -1, 4, + 5, -11, 2, 1, -1, 0, 0, -6, -2, 2, 6, -13, 2, -3, -8, 1, + 1, 3, -2, -3, -2, -7, 4, -6, -2, 3, -10, 5, -2, 1, -3, 5, + 8, -4, -1, 2, -1, 6, 2, 3, 2, -2, 0, -1, 0, 4, 1, -1, + -2, 7, 1, -7, -5, 7, -5, 2, -5, -4, 0, 3, 3, -2, 0, -1, + -9, -4, -9, 10, 1, -14, 0, -1, 6, -8, -3, 3, -1, -6, -1, 5, + 3, -5, -1, 3, -6, 5, 7, -10, 5, 5, 2, -4, -3, 9, 4, -11, + 0, 5, -11, 7, -6, 2, 2, 12, -15, -8, 2, -3, 7, -5, 3, 3, + 1, -10, 0, -9, 17, -11, 7, -6, 2, 1, -3, 0, -1, 5, -2, -10, + -4, 16, -1, -7, -1, -3, 1, 11, -3, 1, -3, 2, -12, -2, 12, 3, + -1, -10, -2, 6, -3, 1, -1, -4, 12, -1, -2, -7, 6, -1, -1, -16, + 5, 11, -3, -7, 1, -1, -2, -6, -4, -5, 3, 4, -3, -8, -1, 3, + -5, 3, 1, 2, 6, -10, 1, 7, 0, 21, -15, 11, -12, 0, 1, 4, + 1, 4, -4, -1, 3, 7, 0, -5, 10, -15, -14, 2, 6, -11, 5, 3, + -10, -6, -1, -11, 4, -9, 6, -9, -2, 2, -8, 3, 0, 2, -9, 7, + 7, 2, 2, 0, 3, 1, 6, 0, 3, 6, -10, 6, -4, 1, 7, 9, + -1, 0, -7, 1, -11, -8, 9, 4, 0, -6, 2, -16, 0, 1, -2, -16, + 10, -7, -12, 7, 4, -1, -1, -4, 2, -1, 2, -5, 8, 3, 3, 4, + -2, 4, 3, 2, -4, -2, -1, 5, -5, -3, 9, 2, -22, 8, -6, 1, + 3, -5, -4, -6, 7, 0, 5, -8, 9, -13, 0, -6, 18, -3, -3, -1, + -6, 7, 3, -11, -9, 19, 6, -10, -6, 3, 12, -2, -18, 7, 8, -7, + -10, 14, -8, 5, 1, -15, -4, 11, -6, 9, -8, -1, 5, 1, -6, -2, + 7, -3, 7, -20, 6, 5, -4, 3, 12, -12, 11, -4, -22, 7, 9, -13, + 1, 0, -8, -1, 9, 6, -10, 5, -9, -5, 8, 5, 8, -12, -4, 16, + -14, 7, 6, -1, -16, 21, 2, -9, 13, 5, -4, -19, 2, -3, 12, -7, + -2, 3, -2, -4, -3, -8, 4, 1, -4, -4, -14, -3, -1, 1, -11, 30, + -11, -16, 8, -2, -9, 8, 8, -1, -1, -5, 10, -4, 1, 4, 3, -8, + -1, 23, -2, -2, 14, -15, -7, 7, -7, 0, 9, -12, 8, -10, 0, -3, + 16, -13, -11, 5, -1, -10, -2, 6, -5, -4, -9, 10, -6, 7, 1, -13, + 2, 14, -9, -3, 2, 6, 4, 8, -8, -2, 0, 2, -3, 14, 3, -10, + -4, -8, -1, 10, -13, -8, 15, -9, -3, -2, 5, -5, -6, -9, 9, 7, + -4, 14, -7, -18, 12, 1, 2, 1, 4, -2, -6, -3, -2, 5, 7, -2, + 0, 0, -4, 0, -6, 1, 5, -5, -4, 5, -6, 5, -4, -8, 15, -5, + -6, 0, 3, -8, 0, 3, 0, -1, 0, -4, 6, -16, 22, -7, 3, -5, + 2, 2, 1, -3, 4, -8, 4, 4, 0, -5, -9, 4, -5, -4, 3, 2, + 1, 3, -4, 6, -15, -1, 4, 1, -9, 3, 1, -8, 3, -6, 11, -5, + 6, -11, 17, -15, -2, -19, -11, 1, -4, 8, 0, 5, 18, -11, 0, 13, + -4, 6, -13, 4, -11, -1, -7, -7, 11, 10, -9, 17, -11, 20, -6, 7, + -14, 23, -7, -2, -2, 7, -10, 2, 0, 2, 5, 6, -8, 5, -4, -10, + 9, -4, 6, 0, -7, 8, -7, 1, -20, -4, -1, -3, 6, -10, -6, -15, + -11, 10, -5, 19, 3, 1, -19, -11, -1, -9, 9, 22, 24, 10, -5, -18, + -8, -23, 14, 11, 0, 31, 43, -9, 0, -7, -15, -28, -35, -30, 3, 5, + -5, 11, 52, 55, 7, -5, -10, -12, -25, -43, -12, 4, -37, -47, -21, -5, + 4, -11, 1, 31, 27, 34, 46, 48, 61, 10, 16, 8, 7, -14, -40, -47, + -36, -51, -42, -15, 4, 12, -32, -42, -10, -4, 10, 1, 15, 50, 31, 5, + 15, 38, 37, 29, 15, 22, 11, -4, -35, 10, 3, -18, 1, -14, -33, -5, + -47, -25, -13, -2, 15, -6, 5, -29, -17, -19, -1, 3, 7, 2, 17, 28, + -8, -23, 7, 7, 36, 15, 2, 1, -2, -9, 1, 6, 20, 6, 14, -3, + 21, -11, -12, -35, 11, -20, -18, -36, -23, -27, -19, 1, 10, 14, 27, 6, + 44, 14, -9, 3, 20, 27, 45, -8, -13, 16, -16, 24, -10, -9, -3, -38, + -19, -14, -38, -38, -41, 13, 40, -37, 5, -7, -7, -4, 4, -31, 32, 22, + 15, 9, 13, 10, 10, -17, 22, 30, 9, -6, 27, 66, 47, -17, -21, -20, + -9, -36, -73, -3, 22, -35, -12, 6, 7, 4, -17, -45, 22, 17, -17, 3, + -9, -4, 11, -10, 13, -4, 8, 38, 3, 20, 42, -22, 9, 23, -28, -21, + 3, 10, 1, 26, -28, -18, -9, 7, -30, -41, -24, -9, 10, -6, 31, -5, + 2, 29, -9, 1, -27, -24, 7, -19, -5, 10, -13, 21, 21, 3, 30, -11, + -17, 34, -11, 8, 7, -8, 1, 11, -1, 7, -13, 1, -3, 23, -12, 8, + -19, -3, 20, -78, 42, -23, 4, -29, -16, -5, 38, -49, 30, -26, 26, 16, + 8, -33, 53, 19, -20, 12, 5, 23, -11, 4, -6, 42, -111, 67, -40, 29, + -32, -20, -77, 113, -46, -12, 8, -5, -14, 35, -52, 94, -5, -61, 58, -36, + 41, -83, 21, -19, 61, -68, 37, -37, 12, 66, -69, -16, 100, -88, 48, 21, + -39, 73, -24, -2, 45, 65, -59, 53, -103, 95, -97, 1, -14, -4, -41, 9, + -13, -18, 16, -26, 9, 26, -15, 25, -16, 6, 8, 26, -52, 35, -21, 4, + -2, -11, -4, 22, 0, 21, -40, 65, -6, -13, -11, -7, 32, -46, -48, 16, + -26, -3, 0, -42, 87, -68, 34, 17, -14, 43, 23, -15, 30, 20, 47, -19, + -33, -12, 15, 1, -37, 15, -12, -11, -7, 15, -75, 36, -41, 27, -8, -7, + -12, 10, -4, 49, -6, 42, -32, 4, 20, 33, -65, 24, -52, 10, 13, -17, + -15, 60, -14, -55, 35, -16, 50, -83, -3, 29, 58, -75, 71, -46, 47, -32, + 44, -57, 10, -43, 33, 22, -48, 51, -41, 6, 7, 39, -3, -41, 7, -9, + 37, -66, 22, 26, -13, 74, -87, 127, -39, -16, -29, -11, -8, -57, -15, -45, + 52, -74, -5, -2, 103, -126, 85, 20, 28, -7, 53, -38, 58, -10, -11, 33, + -70, 20, 1, 40, -36, 26, -58, 58, -23, 61, -71, -7, -39, 43, 22, -18, + -1, -61, 90, -37, 35, -58, 30, -62, 27, -45, 47, -59, -6, -35, 70, -49, + 9, -30, 92, -15, 21, 1, 26, 6, -19, 90, -43, 49, -46, 10, 6, 15, + -90, 67, -51, -11, 4, 28, -36, 24, 41, -68, 24, -34, 63, -40, 17, -30, + 18, -39, 14, -38, 15, 9, -54, 54, -20, 36, -21, -14, -13, 11, 23, 11, + -54, 56, -25, 37, -46, 49, -74, 81, -40, 51, -44, 57, -69, 51, -50, 61, + 27, -112, 111, -114, 106, -85, 49, -61, 75, -18, 26, -68, 32, -15, -25, 21, + -15, 38, -46, 80, -119, 126, -85, 41, -40, 77, -65, 28, -6, -39, 45, -87, + 39, -63, 81, -32, 4, -32, 44, -25, 42, -12, -15, 21, -1, -56, 21, 23, + -30, 33, -28, -3, 32, 4, -36, 60, -20, 13, -3, 22, -43, 101, -88, 59, + -53, 18, 8, 22, -33, -52, 34, -32, 35, -90, 112, -107, 56, -59, 43, -60, + -18, -4, -21, 45, 11, -48, 11, 38, -27, 58, -49, 65, 19, 54, -38, 35, + -37, 24, -11, 44, -62, 41, -16, -48, -8, 31, -68, 17, -3, -5, 52, -51, + -10, 16, -26, 18, -29, 56, -41, 3, 5, -10, -37, 61, -14, -10, -9, 20, + -8, 8, -2, -16, 44, -17, 14, -33, 30, -2, -27, 16, 3, 0, 51, -42, + 32, -20, 8, -11, -24, 10, 12, -15, 6, -32, 10, 21, -38, -11, -12, 23, + 13, -64, 19, 34, -23, -23, 16, 10, 39, 2, -36, 55, -31, 0, -29, 18, + 8, 12, -61, 73, -28, 54, -34, 21, 9, 7, 53, -34, -29, 19, -7, -44, + 7, 15, -16, -18, -31, 10, -29, 36, -69, 7, 4, 33, -72, 45, 14, 0, + -8, 35, -13, 26, 16, -28, -3, -32, 45, -4, 8, -20, 65, -24, 2, -24, + 40, -16, -16, 20, 8, 2, -3, -2, 23, -15, -11, -30, 19, -51, -19, -5, + -36, 18, 24, -4, -1, 46, -90, 60, 4, 23, -17, 16, 60, -24, 0, 18, + 0, 5, -6, -24, 27, -34, -28, -7, -4, 22, -30, -11, -3, -1, -44, 36, + -38, -6, -9, 55, -34, 16, 27, 28, -65, 62, 22, -32, 36, 7, 2, 27, + -19, 50, -71, 44, -19, -67, 13, -3, -14, -30, 33, 5, -12, -48, 60, -47, + -28, 9, -6, 24, -11, -1, 13, 62, -53, 26, 7, -9, 6, 58, -38, -10, + 0, 5, -23, 23, 8, -14, -19, 21, -9, 35, -17, -28, 14, 27, -17, -14, + -29, 24, 6, -85, 74, -16, -18, -2, -19, 47, -29, -18, -15, 52, 0, 7, + -10, -23, 45, 13, -11, 12, -28, 27, -26, 19, -69, 74, -55, 35, -21, 41, + -24, -11, 39, -19, 7, 0, 7, -31, 10, 7, -45, -17, 25, -12, 9, -19, + 3, 28, -53, 76, -19, -25, 49, -2, 6, -11, 24, -12, -23, 17, -1, -15, + -10, -36, 26, -25, 0, -44, 59, -67, 45, -31, 5, 15, 56, -12, -14, 12, + 10, 24, -52, 37, 5, -35, 52, 23, -55, -6, 24, -49, 26, 31, -24, 10, + -33, 33, -11, 1, -49, 8, 7, 6, -78, 12, -22, 10, -11, 13, 13, -18, + 38, 50, -18, -5, 64, -52, 59, 33, 3, -9, -6, -6, 26, -64, 18, -38, + -47, 18, -33, 4, -39, 40, -31, -1, -23, 48, -30, 18, 17, 32, -20, 32, + 19, 24, -58, 49, -38, -9, 15, -28, 16, -3, -2, -28, 33, -22, 23, -1, + -34, 33, -48, 67, -55, 21, 51, -66, -2, 21, -5, -17, 24, -63, 53, 8, + -19, 9, -11, 36, -37, -35, 43, -35, -3, -44, 68, -43, 53, -24, -5, 45, + -16, -7, 14, 49, 3, -16, 22, -10, 2, -28, -9, -6, -5, 32, -76, -22, + 35, -26, -35, -12, 0, 3, 13, 6, 36, 7, -32, 69, -15, 45, -20, -21, + 35, 35, 1, -25, 11, 34, -24, -33, -9, 5, -25, -49, 31, -41, 15, -42, + 25, -30, 42, -80, 32, 2, -18, 33, -12, -9, 43, -1, 4, -12, 54, -51, + 22, -1, 18, 28, -29, 18, 7, 10, -19, 8, -1, 12, -21, -6, -11, 4, + 4, -28, -8, 22, -27, -5, 9, -25, 20, -19, -36, 41, -8, 20, -32, 16, + -29, 29, -13, 13, 4, 1, 17, 8, 0, 9, 22, -1, -3, 28, -11, -39, + 36, -31, 5, -11, -27, 22, -39, 7, 15, -24, 19, 8, -37, 75, -52, 54, + -65, 22, -13, 23, -26, 32, -19, 10, -8, -3, 12, 16, -44, 25, -23, 14, + 9, -46, 20, 2, -4, -8, -6, 18, 4, -2, -3, -15, 4, 16, -9, -5, + 34, -29, 27, -54, 98, -65, 11, -18, 16, -13, 0, -2, 0, 22, -43, 31, + -46, 58, 2, -25, -2, 16, -2, -29, 17, 18, -26, 21, -17, 5, -4, -9, + 0, -34, 50, -27, -3, 4, 31, -3, -47, 32, -25, 36, 6, -47, 33, -28, + 39, -36, 42, -28, 5, -3, -2, 25, 27, -47, 20, 22, -5, -15, 1, -9, + 16, -25, -10, -43, 40, -12, -19, 22, -24, -5, 14, -44, 42, -32, 32, -45, + 40, 41, -17, 27, -44, 38, -16, 15, -36, 39, -13, -19, -4, 34, 1, -9, + 9, -16, -2, -29, 31, -31, -4, 35, -21, -52, 63, -41, 2, -7, 30, -35, + 13, 9, 15, -4, 14, -36, 18, -14, 55, -50, -6, 22, -23, -11, -5, 12, + 17, -13, -43, 44, -33, 41, -42, 45, 3, -12, 26, 11, -11, 35, -76, 39, + 2, 0, 3, -4, 15, -19, -6, -33, 11, 5, 16, -25, -2, 19, -7, -43, + 30, 20, -27, -18, 12, 14, 33, -50, 14, -15, 23, 8, 2, -10, -4, 53, + -86, 24, -9, 41, -34, -21, 22, 24, -54, 27, 13, 2, -9, 14, -29, 21, + 40, -43, -9, -3, 27, -3, -22, 18, 10, -23, -15, 1, 14, -12, 3, -30, + 30, -22, -28, 36, -15, 39, -57, 21, 3, -3, 33, -13, -2, 6, 20, -6, + 4, -13, -5, -18, 13, -7, 7, 26, -26, 16, 7, -64, 37, -7, 10, -20, + 12, -11, 7, -34, 37, -12, -24, 34, -18, -18, 39, 9, -42, -24, 43, 2, + -16, 25, 12, -16, 8, 12, -44, 32, -9, 23, 1, -37, 40, -23, -17, 18, + -42, 23, -12, -7, 10, -6, 6, -13, -13, 30, -23, 36, -4, 7, 17, -18, + 18, -3, 8, 5, -1, -13, -15, 2, -5, -16, 7, -52, 23, -38, 30, -30, + 16, -26, 21, -22, 24, 3, 20, -28, 22, 22, -31, 42, -16, -11, 32, -26, + 0, 31, -14, 11, -15, 14, -17, -9, 10, 11, 27, -38, -4, 14, -18, 36, + -44, 0, -11, 16, -14, -2, 16, -34, -23, 22, 4, -24, 14, -13, 16, 31, + -28, -10, -6, 51, -27, 13, -49, 3, 68, -38, 1, 8, -27, 26, -16, 0, + 15, -36, 7, -6, 38, -11, 0, -14, 10, -4, 22, -48, 31, -1, 23, -38, + 1, 15, -7, 10, -1, -3, 4, -1, 10, -2, -12, 3, -22, 5, 9, 8, + 4, -14, 12, -3, -7, 22, -20, 3, -6, 13, -15, -8, -7, 16, -14, -1, + -3, 6, -17, 12, 22, -44, 68, -67, 50, 13, -20, -11, -4, -20, -3, 22, + -13, -20, 28, -7, 2, 11, -9, -23, 5, 5, -26, 24, -31, 2, 20, 15, + 2, -7, 4, 19, -6, 41, -51, -3, 24, 27, -30, 25, -37, 1, -7, -2, + -4, -26, -1, 12, 5, -12, 9, -30, 5, 11, 26, -18, -32, 42, 7, 0, + -23, 10, 10, -20, 53, -49, 6, -39, 18, 3, -27, 41, -21, 16, 28, 14, + -24, -15, 19, 5, 16, -31, -1, 45, -25, -6, -16, -4, -19, 37, -47, 21, + 2, -14, -7, 30, -35, 13, -30, 14, 21, 11, -18, -28, 37, 12, -18, 9, + 5, -1, 33, -41, 3, -7, -19, 8, -14, 12, 15, -18, -4, 44, -25, 22, + -46, 19, 40, -25, -12, -5, 17, 7, -53, 25, 4, -10, 14, 16, -31, 40, + -27, -11, -4, 28, -40, -5, -9, -3, 34, -47, 33, -5, 11, -33, 33, 0, + -14, 35, -18, -27, 11, 14, -37, 35, -20, 7, 15, 2, 27, -17, 15, -31, + -1, 11, -27, 24, -26, 14, 13, -35, 20, -13, -2, 16, 16, -6, 2, 15, + -7, -22, 51, -36, -2, 20, -19, 23, -20, -19, -9, -14, 8, -4, -13, 35, + -66, 36, -37, 3, 19, -1, 15, 32, -45, 71, -15, -5, 12, 34, -33, 24, + -5, 20, -43, 42, -59, 13, -12, -69, 66, -29, -34, 17, 7, -28, 24, 5, + -27, 51, -40, -9, 46, 3, -17, 36, -56, 63, -7, -31, -19, 53, -12, -10, + 4, 19, -47, 35, 0, -40, 17, -14, 13, -11, 11, 3, -39, 22, 5, 21, + -19, -11, 25, -4, -5, 20, -13, 25, -6, -16, -16, 29, -61, 25, -33, 12, + -17, 7, -19, 34, -27, 15, -19, 32, -26, 54, -46, 6, 9, 14, -6, -6, + 23, -32, 58, -19, -5, 15, 46, -42, 39, -7, -23, -7, -14, -22, 42, -66, + 0, 4, -8, -11, -4, -3, -7, 7, -23, 30, -14, 19, 8, -9, 20, 36, + 5, -24, 25, 12, -20, 16, -53, 60, -49, -26, 24, -87, 67, -49, 13, -7, + 5, -14, 5, 11, 38, -3, -15, 27, 26, -36, 20, 30, -47, 29, -5, 9, + -10, 38, -65, 47, -49, -4, -10, -6, 1, -1, -28, 16, -14, 3, -14, 27, + -8, 1, 2, 23, 21, -53, 40, 24, -16, -12, -2, 11, 17, -8, -18, 8, + -25, 28, -10, -12, 13, -51, 10, 35, -10, -8, -9, 8, 10, 14, -20, 4, + -9, 37, -5, -2, 2, 4, -9, -5, 16, -16, -23, 13, 7, -9, 14, -49, + 13, 8, -3, -13, -9, 22, -8, 12, -13, 36, -36, 35, -17, 23, -12, 0, + -37, 50, -31, -8, -31, 43, -4, -11, 0, 3, -7, -19, 16, -16, -28, 46, + -28, 27, -13, 33, -21, -1, 39, -13, 3, -4, 4, -39, 74, -30, -17, 33, + -3, -20, -12, 24, -94, 75, -63, 54, -62, 23, 4, 12, -33, 22, -35, 16, + 12, -28, 34, 2, -12, -3, 22, 23, -31, -6, 26, 4, -41, 8, 37, -15, + 21, -7, 18, -51, 42, -27, 35, -45, 35, -30, 18, 9, -20, 1, 18, -12, + -51, 61, -61, 24, -20, 1, 11, -5, -2, -12, 11, 20, -35, -2, 37, -21, + 23, -15, -2, 19, -51, 82, -50, 20, 29, -26, -34, 49, -2, -16, 11, -17, + -4, 6, 15, -35, 13, -15, -10, -17, 15, 4, -42, 43, -31, 34, -30, 53, + -43, 40, -22, 9, 9, -24, 64, -41, 29, -17, 8, -15, 8, 2, -27, 7, + 10, -28, 0, 30, -50, 6, -13, -14, -21, 11, 9, 13, -47, 35, -11, 32, + 28, -28, 1, 32, 2, -19, 28, -24, 9, 0, 19, -6, 16, -33, 6, -23, + 33, -31, -1, -4, 26, -22, -22, -10, -11, 18, -26, 19, -8, -4, 21, -14, + 36, -2, 12, -48, 49, -1, -13, -5, 8, -3, 9, -4, -18, 15, 28, -50, + 10, 4, -7, 4, -39, 37, -39, 11, 2, -20, 13, 4, -6, 0, 35, -17, + -9, 6, 38, -21, -1, -1, 12, -2, -16, 15, 7, -22, 18, -23, 11, 3, + -9, -39, 29, -31, 44, -41, 0, 5, 21, -9, -25, 25, -6, 38, -55, 38, + -14, 6, -26, 38, -24, 39, -39, -15, 17, 16, -20, -27, 17, 24, -20, -20, + 33, 8, -31, 2, 2, 27, 11, -4, -7, 31, -20, -9, 4, -4, 17, -32, + 2, -18, 31, -35, 38, -52, 42, -1, -28, -26, 25, 3, -51, 42, -35, 35, + -39, 44, -38, 20, 20, -51, 34, 45, -10, -7, 27, -19, 33, -49, 22, 2, + -7, -5, -27, 59, -24, -20, 21, -8, -15, 24, -51, 3, 9, -23, 24, -30, + 2, 29, -26, -2, 4, 10, 0, -18, 50, 3, 9, -14, 17, -18, 24, -13, + -33, 7, 25, -50, 2, -2, 30, -58, 31, -8, 23, -11, -1, -24, 21, 1, + -41, 47, -30, 28, -39, 56, -16, -20, 51, -45, 33, 6, 23, -12, -19, -2, + 7, 1, -14, -5, -11, -20, 25, -17, 7, -22, 21, -19, 34, -47, -2, 1, + 33, -30, 14, 20, 6, -9, 17, 13, -22, 19, -58, 23, 26, -15, -52, 2, + 18, 10, -13, 46, -5, -8, -6, 4, -14, 5, 11, -13, -7, 42, -25, 8, + -37, 35, -10, 6, -25, 16, 15, -15, -9, -20, 18, -23, 26, -34, 35, -22, + -10, 9, 14, -6, -21, 27, -8, 4, 1, 3, -19, 28, 2, -7, 30, -8, + -13, 11, -9, -9, -19, 12, 0, -23, -1, -23, -6, 27, -31, 41, -28, 13, + 5, 9, -21, 6, 2, -2, 18, -16, 31, -25, 40, -38, 39, -13, 8, 14, + -3, 9, -30, 6, -12, -7, -15, 30, -64, 6, -22, 13, -8, 14, -40, 9, + 32, -35, 14, -1, 12, -25, 63, -25, 35, -2, 19, -5, -3, 20, -29, -1, + 35, -37, 53, -46, 4, -14, 22, -27, 23, -64, 8, 5, -25, 41, -18, 14, + -42, 53, -56, 35, -42, 71, -63, 45, -38, 29, -12, 33, -22, 0, 24, -13, + 3, 13, 1, -10, -19, 11, 19, -38, 5, -2, -18, -21, 33, -54, 41, 9, + 4, -1, -21, 3, 3, 37, -31, 34, -40, 34, -19, 30, -26, 23, -53, 55, + -8, -13, -16, 7, -13, 46, -38, 2, -3, 17, -1, -26, 18, -57, 68, -27, + 23, -19, 32, -39, 2, 2, -18, 12, -16, 4, -23, 38, -65, 40, -5, 13, + 19, -26, -13, 60, -25, 7, 1, 10, 22, -24, 23, -20, -16, -17, 14, -32, + 26, -4, 17, -15, 9, -29, 4, -29, 11, 36, -18, -19, -2, 5, 28, -23, + 31, 6, 4, 18, -14, 4, -7, 0, -45, 61, -31, 5, -15, -23, -21, 52, + -62, 4, 22, 1, -9, 15, -24, -27, 60, -49, 38, 0, -6, 1, 13, 7, + 4, 19, 6, 0, 27, -28, -14, -21, 17, -1, -30, 23, 10, -36, 18, -19, + 2, -18, 0, 6, -1, 7, -1, -37, 26, 15, -35, 41, -24, 10, 10, -9, + -12, 12, 7, 3, 10, -11, 11, -14, 27, -49, 71, -55, 25, 8, -11, 11, + -5, -22, 7, 15, -17, -11, 18, 4, -54, 43, -38, 27, -1, 7, -13, 19, + 10, -41, 50, -41, 13, 9, 10, -41, 38, -13, 13, -2, -2, -4, 9, -36, + -5, 22, -31, -18, 8, 21, -22, 21, -24, 12, 3, 16, -24, 25, -16, 22, + -35, 14, 3, 11, 12, -22, 40, -11, -25, 14, 0, 14, -2, 2, -10, -12, + 14, -51, 11, -21, 55, -27, 9, 3, 38, 7, -25, 5, -19, 6, -14, 0, + -10, 21, -57, 35, 18, -21, 21, -40, -13, 24, -24, -12, 10, -1, 11, 10, + -12, -5, 38, -45, 23, 26, -13, -9, 32, 6, -3, 30, -28, -28, 27, 3, + -10, -11, -10, 16, -28, 21, -12, -3, -1, -33, 14, -30, 12, -20, 40, -15, + 7, 19, -18, -1, -1, 9, 4, -23, 32, 17, -19, 12, 16, -45, 4, -6, + 18, -28, 36, -44, 44, -29, 10, 4, 14, -8, -13, 9, -30, 39, -17, -5, + 10, -10, 5, -1, -16, 17, -7, -9, -10, 15, -21, 9, 10, 8, -10, -6, + 3, -21, 34, -3, 6, -4, 15, 3, -2, 4, 26, -44, 30, -43, 2, 9, + -5, -7, -18, 16, -28, 0, 5, -7, 0, 7, 0, -7, 21, -14, 17, 15, + 2, -40, 7, 44, -30, 55, -33, -19, 40, -30, 17, -1, -20, -20, -20, 5, + 14, 1, -7, -32, 26, -11, -11, 24, -23, 17, 17, 8, -19, 18, 11, -6, + 17, -4, -13, 14, -9, 21, 9, -16, -8, 2, -16, 3, -9, -32, 6, -36, + -4, 0, 10, -36, 26, -11, 3, 31, -20, 1, 7, 4, 45, -35, 39, 0, + 4, 28, -21, 29, -39, 27, 15, -6, -14, 17, -25, -33, 16, -15, 18, -43, + 28, -61, 33, 1, -27, 13, -19, -20, 26, 11, -27, 16, -21, 33, -13, 43, + -44, 13, 24, -10, 35, -39, 36, 20, -39, 68, -68, 23, -16, -7, 0, 36, + -30, -13, -27, 42, -21, -4, -23, -2, 23, 0, -3, -3, 2, 4, -15, -5, + 28, -10, -20, 24, -7, 27, -58, 31, -7, -29, 39, -40, 41, -35, 8, -25, + 30, 31, -17, -9, 3, 36, -8, -18, -11, 29, -2, 6, -25, 21, -5, -8, + -17, -24, 20, -26, 20, -23, 46, -26, -13, 8, 13, 2, -15, 4, -9, 28, + -25, -19, 49, 18, -50, 45, -11, -17, 5, -61, 15, 4, -22, -1, 22, 23, + 33, -55, 46, -25, 37, 18, 2, -9, 11, -47, 23, -8, -25, 37, -32, 2, + 5, 12, -18, -5, 19, -27, -7, 20, -40, 32, -44, -21, -29, 58, 8, -9, + 57, -28, 29, -32, 14, -14, 4, 23, -33, 16, -4, -16, 21, 38, -37, 23, + 10, -32, 17, 17, -12, -59, 9, -3, -12, 22, -13, -8, -26, 16, 1, 33, + -9, -17, 16, -7, 21, -44, 26, 5, 35, -36, -1, 13, 36, -36, 39, -36, + 17, -13, 2, -33, 20, -13, -51, -2, 9, -2, 35, -21, 19, -20, 18, -19, + -5, 30, -39, 30, 22, -35, 74, -52, 33, -15, 17, -21, -13, 11, 6, -25, + 25, -31, 29, -18, 18, -52, 40, -11, -17, -26, 56, -56, 69, -53, -14, 32, + -10, -8, -2, 18, -14, 20, -18, 20, 22, -27, 0, -25, 56, -46, 16, -28, + 52, -5, -33, 76, -75, 36, -1, -42, 42, -46, 13, -13, 25, -7, 35, -55, + 5, 63, -56, 11, -24, 13, -8, -10, -27, 15, -15, 44, -66, 52, -3, -6, + 0, 23, -33, 79, -55, 30, -27, 37, -18, -6, -2, -19, 52, -22, -50, 60, + -32, 28, -56, 44, -28, 15, -37, -9, -28, 63, -75, 9, 39, 28, -21, 5, + -17, 15, 2, -13, 30, 13, -14, 10, -12, 30, -22, -10, 4, -8, -9, 14, + 6, -39, 34, -6, 4, 1, -5, 0, 33, -73, 34, -12, 23, -9, 53, -47, + 17, 3, -18, -6, 2, -19, -12, -7, -45, 72, -9, -71, 55, -58, 50, -18, + -36, 37, 19, -11, 13, -35, 32, 6, 5, 18, -6, 19, -26, 32, 16, 20, + -43, 20, -10, -7, 16, -7, -68, 21, -36, 7, 19, -22, 19, -3, -35, -37, + 25, 21, -57, 67, -9, 9, 32, -11, 28, -18, 35, -41, 60, -19, 29, 0, + -38, 29, -6, -35, 0, 25, -37, -1, -31, -42, 30, -19, -21, 36, -66, 53, + -33, 15, 16, -13, 20, -35, 73, -4, 18, 39, 4, 1, 3, 21, -2, -12, + -18, -51, 44, -17, -50, 48, -30, -16, -13, -35, -7, 25, -33, -14, 14, 0, + 8, -30, 45, -13, 50, -53, 28, 60, -33, 23, -7, -2, 15, 36, -11, 9, + 19, -44, 4, -21, 19, -5, -27, -45, 48, 9, -47, -23, 12, 3, -25, -8, + -21, 63, 1, -29, 31, -18, 19, 16, -24, -17, 50, -65, 65, -56, 93, -45, + -17, -25, 45, -18, 23, -53, 50, -15, -12, -39, 51, -11, 11, 13, -31, 54, + -14, -29, 22, -11, 10, -41, -19, 52, 10, -51, -60, 72, -13, 12, -38, 19, + -2, 31, -56, 37, -4, -10, 22, -14, -33, 48, -40, 38, -14, 27, -24, 19, + 29, 17, -31, -2, -41, 34, -17, 2, 5, 5, -13, -30, 14, 9, -9, 7, + -11, 15, 5, -28, -2, 0, 45, -30, -25, 1, 10, 29, -55, -24, 52, -5, + 5, 20, -25, 20, -15, 14, -64, 95, -53, 32, 13, -26, 31, -8, -27, 18, + 48, -57, -3, -10, 25, -24, -32, -9, 18, 18, -33, -15, 27, -22, 14, -5, + 10, 51, -21, -25, 19, 5, -15, -29, 16, 1, 33, -39, -12, 56, 14, -63, + 36, -2, -17, 52, -11, -37, 5, 19, -52, 38, -23, -60, 93, -75, 52, -30, + -2, -11, 49, -11, -25, 1, 42, -35, 26, -35, -9, 24, -1, 10, -6, -12, + 7, 4, 22, -10, 41, -25, -8, -4, -2, 28, -43, 19, -32, 4, -27, 9, + -47, 51, -16, 12, -52, 49, 8, 7, -37, 27, -33, 80, -44, 6, 5, 28, + -15, 16, 15, 2, -12, 50, -77, 38, -38, -45, 30, 8, -37, -13, -8, -18, + 50, 3, -54, 29, 29, -20, 4, 52, -57, 62, -52, -2, -9, 62, -64, -5, + 24, 23, 0, -7, -23, 48, 25, -78, -9, 38, 18, -46, 30, -51, 39, 4, + -48, 22, 15, 13, -39, 8, 10, 31, -20, -22, 21, -17, 17, -23, 22, 22, + -24, -36, 11, 31, -16, -28, 34, -4, 0, -20, 6, -2, 35, -13, -60, 36, + 24, -45, 21, -2, 36, 0, -73, 66, -37, 39, -66, -18, 22, 17, -17, -25, + 24, 36, -47, 3, 25, 7, 8, 0, 1, 14, 20, -21, 4, 21, 12, -77, + 17, -4, -12, 31, -57, 38, -11, -4, -31, -6, 29, -34, 11, 13, -20, 82, + -36, -36, 40, -28, 77, -68, 12, 2, 34, -23, 5, -31, 11, -5, 44, -105, + 79, -31, -29, -16, 37, 8, 18, -14, -9, 32, -10, -11, -7, 0, 41, 34, + -56, 7, 13, -2, -31, 33, -67, 42, -31, -2, 22, -49, 18, -34, -11, 38, + -40, 56, -16, 14, -2, 24, 0, 0, 41, -21, -8, 6, -11, 11, 11, -45, + 26, 4, -17, -7, -26, -30, 7, -21, -29, 56, -29, 37, -3, 2, -8, -3, + 22, 11, 40, -13, 58, -6, -38, 48, -23, 15, -52, -14, -6, 49, -66, -20, + -11, 34, -32, -44, 41, 4, 20, -59, -24, 77, 23, -24, -17, 42, 19, -3, + -19, -34, 54, 17, -22, -17, 46, -24, -9, 3, -22, 40, -47, -49, 72, 4, + -18, -48, -33, 55, -4, -41, -51, 105, -26, -3, -22, 64, 28, -51, 31, 2, + 15, 27, -62, 18, 21, 6, -15, -54, 52, -14, -46, 7, -30, 32, -1, 6, + -37, 39, -3, -23, -20, 24, 23, 17, -25, -6, 67, -36, -11, -37, 56, -79, + 3, 30, 45, -39, -17, -2, 21, 2, -4, -3, 3, 1, 16, -16, 9, 30, + -37, 8, -6, 46, -65, 3, 14, -59, 104, -60, 2, 46, -29, -30, -2, -10, + 24, -52, 63, -31, 81, -85, 18, 35, 16, -32, -18, -24, 45, -16, -15, -13, + 37, -15, -20, -42, 91, -45, -15, -9, -16, 64, -11, -23, 31, -18, 38, -42, + 3, 12, 1, 5, -5, 22, -44, 69, -31, -18, 15, 21, -64, -13, 34, -37, + 30, -26, -15, 6, -3, 44, -28, 11, -3, -1, 16, -18, 25, -14, -26, 69, + -56, -5, 31, -51, 24, 3, -36, 9, 52, -34, 31, 21, -11, -68, 31, -24, + 53, -25, -29, 31, 23, -20, 9, -15, -11, 19, 12, -47, 84, -60, -16, -11, + 17, -4, -15, 30, -45, 32, 34, -63, -7, 68, 0, -35, 17, 7, 33, -31, + -8, 7, -32, 43, -13, -18, 15, 31, -32, -34, 5, 8, -16, 20, -26, -29, + 32, -9, -20, 17, 33, -31, -13, -5, 86, -52, 23, -19, 2, 13, 14, -7, + -20, 36, -16, -3, 8, 0, 14, -69, 76, -77, 25, -14, -17, 3, 39, -14, + -46, 31, -2, -7, 37, -45, -6, 24, 28, -37, 22, 13, -35, 4, 8, 23, + 7, -43, 53, -59, 23, 16, 4, -25, -15, 23, -9, -20, 26, -18, -1, 25, + -3, -48, 53, 2, -43, 7, 14, -34, 15, 28, -33, 53, -2, -59, 31, -34, + 40, 19, -27, 20, -2, 8, 2, 3, -8, -8, 4, -57, 62, 24, -72, -4, + 17, -17, -3, -10, -26, 42, -30, 12, -29, 31, -10, 3, 24, 2, 21, -1, + -36, 52, -7, 21, 14, -32, -18, 73, -45, -6, 8, -12, -66, 21, 25, -17, + -6, -35, -14, 27, 26, -47, 40, -51, 56, -19, -24, 31, 6, 4, 11, -3, + 37, -47, 41, -32, 50, 0, -72, 25, 16, -19, -1, -2, -4, -41, 20, 6, + 9, -3, -44, 32, -54, 83, -30, -26, -8, 46, -47, 29, 5, -19, 37, -9, + -20, 65, -14, -21, -4, 10, 28, -28, 18, -29, 35, -25, 3, -17, -31, 4, + -4, 0, -9, 41, -42, -34, 40, -15, 8, -24, -8, 36, 22, -18, -27, 70, + -39, 39, 1, -5, 57, -54, 12, 36, 3, -13, -1, -32, 69, 6, -64, -50, + 13, -13, -34, 22, -13, 0, -10, -38, 41, -11, -22, -3, 11, 4, 38, 22, + -10, 24, 32, -23, 23, -6, 8, -4, 21, -61, 66, -35, -41, 7, 5, -29, + -19, -45, 23, -2, 46, -84, 78, -59, 40, -10, -18, 79, -35, -5, -1, 36, + 16, 13, -21, -31, 52, 2, -50, 34, -5, -36, -37, 65, -42, 1, 16, -42, + 35, -8, -50, -6, 41, -16, 27, -41, 22, 64, -50, -11, 31, -18, -17, 5, + -3, 34, 34, -40, -41, 66, -37, 20, -11, -20, 29, -5, -14, -15, 45, -33, + -37, -11, 36, -25, 18, -8, 20, 1, -23, 60, -32, 0, 34, -24, -32, 64, + -39, -35, 48, -7, -13, 4, -39, 32, 0, 1, -31, 2, -12, 43, -38, -8, + 26, 0, -57, 53, 19, -22, -10, 17, -30, 57, 6, -31, 33, 10, 0, -48, + 29, -4, -23, 6, -7, 31, -39, 15, -41, 38, -19, 5, -37, 23, 11, -28, + -14, 59, -48, 8, 22, -20, 50, 15, -34, -26, 67, -8, -15, -21, 53, -27, + -9, 13, -24, -35, -10, 9, -15, -13, 18, -38, 28, 22, -14, 2, -22, 42, + -20, 22, 12, -20, 45, -16, 17, -16, 22, 34, -27, -13, -7, 1, -21, -1, + 13, -44, 36, -51, -8, 16, -7, -30, -46, 90, -54, 35, 1, 11, 9, 5, + 1, -19, 20, 11, 21, -1, -49, 41, -6, 0, 37, -74, 9, 20, -12, -47, + 65, -68, 28, -5, -26, 15, 14, -3, -23, 8, 18, -22, 13, 3, 31, -21, + -5, 8, 24, -21, 48, -20, -21, 41, -43, 4, 18, 21, -60, 9, -27, 1, + 13, -15, -33, 15, 23, -48, -8, 53, -50, 1, 6, -40, 90, -10, -15, 51, + -52, 53, 29, -68, 50, 52, -30, -21, 7, -1, -8, -29, 11, -47, 6, 18, + -12, -25, 53, -34, -23, -6, 19, -7, -13, 7, 5, -2, 14, 11, -15, 51, + -29, 6, 12, 20, -27, 29, -12, 4, -18, -5, 2, -17, 10, -19, 2, -8, + -5, 56, -82, 49, 0, -42, 48, -25, 19, 6, -41, 17, 35, -18, -17, -29, + 26, 10, 4, -24, 26, -35, 47, -36, 2, 2, -23, 27, -42, 55, 0, -21, + 19, 21, -8, 1, -3, -15, 7, 12, -23, -29, 47, -12, 4, -28, 17, 16, + -7, -31, -8, 25, -6, 0, 13, -20, 6, 3, -7, 19, -21, -37, 27, 41, + 7, -14, 12, -59, 57, 6, -49, -2, -8, 0, 19, 13, -20, -5, 16, 23, + 4, -15, -33, 14, 2, 15, -26, -28, 10, 45, -17, -24, 14, 17, -39, 22, + -8, 48, -51, -1, -16, 52, -34, -21, 11, 13, 18, -57, 26, 15, 27, -36, + -12, 40, -7, -14, 15, -86, 91, -20, -13, -7, 53, -43, 33, -25, 13, 3, + -38, -19, 28, 28, -18, -74, 58, -3, 40, -27, -34, 30, 28, -1, -22, 2, + 9, -8, -12, 12, 21, -35, -2, -17, 17, 2, -27, 22, -36, 38, -11, 2, + -20, 7, 20, -29, 39, 11, -3, 9, -24, 47, -36, 28, -14, -16, 38, -37, + 12, -15, 18, -69, 56, -31, 17, -16, -18, -13, 21, -6, -9, -25, 37, 6, + -1, -2, 5, -1, -26, 39, 6, -3, -10, 0, 12, 30, -12, -31, 24, 13, + -14, 9, -23, 31, -43, -17, -2, 13, -23, -14, -21, 21, 19, -22, -12, 24, + 41, -26, 10, 12, 19, -3, 9, -12, 26, 12, -52, -4, 16, -3, 0, -43, + 7, 5, -14, -9, 12, -28, 15, -23, -2, 35, -12, -8, -10, 24, 57, -55, + 26, -18, 19, 44, -30, 0, -5, 50, -56, -1, 8, -5, -39, 9, 19, -39, + 38, -73, 30, -1, 2, 16, -24, 6, 29, -71, 70, -18, -6, 8, 31, 4, + -13, 23, -11, 31, -56, 57, -25, 10, 15, -44, -10, 16, -17, -44, 18, -28, + 10, 8, -21, -4, -9, 28, 20, -16, 17, -17, -6, 30, 0, 11, -21, 25, + 25, -1, 31, -56, 31, 14, -32, 2, -19, 4, -17, -26, -13, 42, -59, 15, + -29, 53, -4, 1, -23, 13, 31, 5, -22, 3, 30, -28, 2, -24, 37, 1, + -3, -18, 18, 41, -40, 3, -40, 48, -31, -5, -20, 5, 9, 0, -30, -1, + 26, -15, -5, -6, 51, -25, -27, 7, 44, -11, 10, -32, 14, 46, -31, 6, + -11, 37, -33, -14, 19, -4, 22, -50, 26, -45, 21, 1, -23, 10, -15, 17, + -63, 53, -14, -18, 56, -49, 21, 25, -7, 4, -21, 52, -33, 19, 3, 11, + -9, -7, 0, -49, 22, -17, 25, -10, -11, 5, -19, 35, -26, 20, -7, -21, + 37, -25, 29, -23, 3, 6, 17, -26, 27, 5, -16, 10, -9, -24, 11, -4, + -17, 9, -5, -13, 1, -2, 10, 5, -13, 21, 0, 8, 9, -22, 12, 13, + -24, -3, -22, 42, -18, 3, -4, -15, 1, -2, 8, -17, -13, -2, 1, 23, + 10, -2, -31, 23, 17, -15, -9, -24, 31, 2, 19, -24, 4, -22, 28, -5, + -20, 34, -57, 26, 71, -51, 28, -24, -12, 28, 10, -35, -4, -6, 7, -7, + 8, -52, 61, -52, 7, -9, -21, 9, 18, -19, 3, 34, -53, 56, -29, 20, + -11, 22, 4, -1, 23, 2, 1, 24, -15, 3, -32, 13, 21, -37, 6, -11, + -25, 22, 7, -2, -41, 4, 10, -30, 39, -24, -7, 8, 12, 9, -1, -35, + 13, 3, 9, -18, 21, 26, -14, 41, -8, -35, 31, -29, 17, -20, -12, 20, + -30, 27, -26, 21, -9, -6, 5, -14, 3, -11, 15, 2, 8, -14, -5, 20, + 4, 0, -31, 9, 4, 25, -24, 5, -5, -13, 27, -7, -32, 1, -5, -10, + 28, 7, -4, 11, 10, 22, -3, -22, -15, 6, -3, -3, -27, -25, 5, 8, + -10, -17, 18, -18, 12, 32, -18, 1, 25, -25, 50, 7, 2, 0, -3, -3, + 16, -20, 9, -14, -15, 21, -27, -3, -17, 23, -31, -4, -18, 31, -21, 6, + 0, 18, -16, 27, 3, -7, -17, 17, -15, -11, 19, -16, 6, 1, 12, -18, + 5, -6, 24, 0, -19, 22, -23, 43, -35, 18, 22, -40, 1, 12, -4, -18, + 26, -53, 34, 1, -10, 1, -18, 27, -25, -24, 33, -31, 9, -43, 53, -29, + 33, -17, 5, 23, -7, 2, 23, 29, 1, -8, 20, -10, -1, -22, -3, -17, + 4, 22, -61, -23, 31, -26, -29, -12, 2, -3, 12, 10, 26, 5, -29, 61, + -9, 32, -18, -14, 29, 31, 2, -19, 9, 31, -20, -31, -7, 5, -22, -47, + 31, -40, 15, -39, 22, -27, 40, -78, 31, 4, -19, 33, -13, -8, 41, -1, + 5, -12, 53, -51, 22, -1, 18, 28, -29, -1, 0, 0, 11, 13, -2, -7, + -5, -3, -3, 1, 2, -6, 0, 3, 8, 9, 5, 0, 14, -5, -28, -39, + -39, -36, -37, -27, -43, -49, -13, 4, 6, -7, 0, -1, 3, 23, 39, 29, + 35, 41, 21, 35, 0, 0, 21, 59, 67, 31, 21, 13, -3, 18, 34, 28, + 5, 3, 13, 3, 0, 12, -7, -33, -27, -39, -14, -34, -50, -30, -37, -35, + -53, -74, -70, -61, -62, -62, -50, -44, -61, -36, -3, -23, -15, -12, -17, -20, + -6, 11, -6, -12, -6, -17, 7, 46, 71, 87, 79, 70, 77, 104, 109, 66, + 37, 34, 27, 31, 40, 43, 31, 23, 17, 2, 10, 24, 32, 66, 56, 17, + -13, -55, -54, -21, 19, -19, -56, -77, -37, -27, -10, -6, -38, -36, -37, -3, + 23, 25, 25, 19, 35, 34, -7, -5, 28, 60, 66, 65, 51, 34, 22, 53, + 51, 15, 20, 11, 21, 21, 16, 24, -2, -23, -36, -35, -21, -29, -51, -51, + -47, -57, -85, -80, -70, -100, -97, -82, -78, -76, -64, -51, -56, -54, -49, -70, + -62, -53, -54, -60, -57, -65, -78, -76, -62, -39, 0, 31, 13, 6, 31, 54, + 55, 43, 30, 13, 9, 31, 23, 43, 28, 24, 36, 36, 24, 30, 54, 70, + 113, 103, 75, 4, -3, 40, 55, 50, 23, 9, 25, 29, 48, 41, 29, 14, + 6, 40, 63, 49, 39, 71, 80, 64, 21, 12, 17, 29, 68, 71, 52, 36, + 24, 37, 24, 1, 5, 3, -6, -4, 1, 13, -3, -22, -35, -31, -27, -58, + -59, -43, -55, -71, -76, -71, -88, -103, -95, -98, -85, -77, -68, -71, -58, -50, + -47, -52, -46, -40, -47, -44, -48, -56, -60, -91, -96, -68, -15, -6, -16, 9, + 3, 29, 31, 29, 8, 10, -6, 5, 10, -6, -4, -6, 15, 7, -2, 2, + -5, 30, 91, 107, 74, 8, -3, 14, 27, 32, 26, 17, 21, 18, 34, 49, + 20, -3, 2, 30, 42, 20, 36, 68, 79, 81, 52, 27, 22, 37, 80, 95, + 77, 77, 72, 74, 57, 55, 56, 41, 35, 22, 40, 58, 32, 23, 24, 26, + 0, -7, 6, -2, -16, -26, -31, -45, -46, -64, -77, -79, -73, -72, -75, -59, + -49, -56, -35, -48, -44, -50, -43, -59, -58, -40, -78, -119, -123, -95, -73, -40, + -52, -45, -29, -18, -3, -1, -11, -21, -28, -12, -24, -29, -21, -29, -16, -3, + -5, -30, -40, 1, 69, 96, 78, 31, 14, 23, 17, 19, 33, 20, 9, 9, + 45, 50, 14, 3, 12, 13, 16, 7, 14, 35, 54, 75, 56, 24, 1, 18, + 47, 47, 60, 62, 66, 69, 46, 54, 53, 38, 11, 18, 44, 41, 28, 33, + 37, 22, 14, 15, 13, 13, 1, -1, -13, -6, -11, -38, -33, -47, -40, -46, + -31, -29, -22, -9, -5, -9, 9, 4, -23, -14, -4, -3, -26, -69, -87, -74, + -60, -42, -49, -33, -28, -16, 9, 2, -16, -22, -25, -25, -33, -32, -44, -58, + -41, -11, -19, -51, -77, -43, 24, 47, 49, 34, 21, 5, -9, 5, 18, -10, + -14, 2, 23, 26, -3, -7, -4, 2, -3, -10, -4, -6, 38, 64, 50, 25, + 1, 11, 17, 21, 36, 58, 62, 46, 46, 61, 56, 27, 11, 20, 18, 27, + 15, 31, 26, 23, 17, 7, 16, 0, -9, -10, -3, -8, -14, -25, -36, -56, + -41, -39, -50, -30, -12, -23, -8, 10, 23, 17, -2, 3, 14, 26, 7, -33, + -48, -53, -52, -35, -30, -30, -23, 3, 21, 17, 8, 7, -8, -1, 0, -6, + -29, -50, -26, 10, 5, -38, -64, -41, 5, 22, 49, 63, 38, 20, 13, 26, + 15, -7, -9, -1, 28, 9, 1, -4, -12, -1, -5, -20, -38, -32, 6, 38, + 36, 16, 10, 0, -8, -13, 15, 41, 25, 30, 30, 52, 35, 17, 8, 3, + -5, -5, -6, 4, 7, 4, 4, 3, 3, -20, -25, -23, -28, -22, -18, -47, + -50, -54, -62, -67, -62, -48, -43, -44, -31, -10, 17, 10, -8, 1, 22, 24, + 17, -1, -21, -40, -39, -26, -38, -32, -21, 2, 17, 26, 29, 18, 5, 15, + 35, 19, -11, -37, -9, 33, 17, -6, -30, -23, -10, 22, 65, 73, 71, 47, + 57, 66, 38, 15, 16, 23, 34, 35, 27, 10, 11, 21, 32, -4, -26, -29, + 4, 29, 28, 38, 32, 17, -6, -6, 17, 32, 21, 31, 39, 49, 36, 27, + 25, 13, -1, -11, -8, -1, -15, -11, 4, -7, -9, -14, -38, -46, -35, -31, + -43, -53, -54, -72, -84, -88, -86, -79, -73, -86, -69, -40, -16, -23, -28, -13, + -9, 5, 5, -10, -34, -45, -48, -52, -61, -59, -42, -38, -9, 13, 19, 8, + -14, 18, 42, 28, -18, -31, -3, 11, 21, 13, -9, -17, -22, 9, 57, 71, + 62, 68, 83, 82, 65, 38, 38, 31, 52, 57, 45, 23, 25, 51, 56, 21, + -2, -8, 7, 21, 28, 55, 55, 37, 15, 17, 30, 30, 30, 48, 55, 65, + 55, 54, 61, 42, 24, 22, 13, 6, 6, 4, 4, 17, 19, 1, -20, -23, + -25, -27, -26, -44, -44, -62, -79, -91, -83, -76, -99, -104, -87, -63, -51, -40, + -42, -40, -29, -16, -6, -31, -40, -47, -63, -68, -81, -76, -81, -75, -49, -15, + -5, -34, -38, 2, 15, 8, -29, -43, -33, -18, -11, 8, -9, -42, -45, -14, + 25, 33, 41, 54, 67, 75, 71, 46, 30, 23, 52, 55, 38, 20, 25, 53, + 59, 35, 17, 6, 3, 5, 27, 64, 61, 49, 40, 40, 45, 36, 38, 63, + 69, 69, 77, 85, 78, 76, 63, 48, 38, 42, 28, 15, 30, 35, 41, 27, + 14, 0, -4, -2, -14, -16, -15, -35, -65, -63, -56, -64, -80, -94, -77, -71, + -46, -34, -42, -37, -21, -6, -5, -16, -20, -35, -44, -62, -66, -66, -96, -94, + -58, -26, -32, -44, -50, -14, 2, -9, -26, -41, -53, -49, -27, -5, -28, -59, + -65, -47, -20, -11, 7, 15, 28, 51, 57, 32, 7, 2, 30, 32, 15, 0, + 7, 30, 30, 24, 21, -2, -19, -20, 6, 37, 40, 31, 40, 45, 30, 29, + 35, 49, 52, 69, 74, 78, 89, 79, 72, 62, 60, 51, 37, 29, 29, 42, + 51, 46, 30, 32, 18, 2, 8, 13, 15, -13, -35, -35, -38, -40, -53, -71, + -70, -58, -34, -38, -32, -28, -9, 10, 10, 7, 11, -7, -28, -21, -26, -47, + -80, -84, -49, -18, -28, -38, -32, -8, -4, 4, 3, -23, -46, -44, -19, -5, + -22, -42, -55, -56, -35, -25, -12, -8, 11, 43, 51, 33, 1, 0, 24, 18, + 1, -5, 0, 1, 9, 15, 21, -2, -38, -36, -19, 2, 2, 19, 26, 19, + 20, 10, 11, 20, 31, 37, 49, 62, 64, 61, 60, 61, 50, 51, 32, 10, + 16, 27, 31, 33, 33, 36, 7, -6, 3, 14, 12, -10, -21, -40, -34, -33, + -47, -65, -67, -60, -40, -40, -44, -25, -10, -4, 14, 26, 22, 4, -7, 8, + 8, -22, -67, -65, -33, -19, -24, -20, -18, -8, 1, 26, 30, -2, -22, -25, + -6, 5, -1, -13, -38, -43, -31, -21, -16, -16, 9, 47, 61, 35, 22, 22, + 31, 24, 10, 13, 5, -2, 0, 28, 34, 1, -21, -30, -28, -18, -5, 5, + 18, 20, 14, 6, 6, 12, 9, 20, 33, 39, 51, 51, 42, 51, 51, 48, + 20, 9, 7, 5, 7, 15, 28, 19, -1, -16, -15, -4, 4, -16, -30, -41, + -45, -41, -50, -79, -77, -69, -65, -64, -56, -45, -40, -28, -4, 21, 17, -8, + -9, 21, 16, -18, -56, -58, -44, -39, -24, -22, -28, -22, -4, 29, 31, 13, + -9, -16, -3, 11, 13, 1, -18, -33, -15, -11, -23, -22, 11, 52, 58, 50, + 46, 50, 49, 36, 40, 40, 17, 6, 20, 37, 45, 29, 9, -7, -12, -11, + -6, 9, 30, 25, 26, 26, 17, 19, 15, 21, 24, 46, 55, 47, 43, 56, + 64, 52, 33, 25, 13, -3, 2, 10, 21, 26, 4, -15, -16, -13, -2, -11, + -32, -43, -37, -44, -61, -77, -78, -82, -82, -80, -71, -61, -72, -59, -21, 5, + -2, -27, -10, 15, 7, -14, -44, -59, -67, -55, -37, -38, -50, -45, -23, 5, + 23, 9, -6, -19, -15, 5, 14, 2, -22, -22, -10, -17, -35, -38, -3, 35, + 38, 43, 57, 51, 44, 49, 57, 46, 25, 14, 24, 35, 54, 41, 31, 22, + 1, -7, -4, 12, 23, 34, 37, 35, 35, 36, 26, 24, 33, 55, 62, 53, + 58, 70, 70, 73, 62, 51, 38, 14, 6, 20, 31, 32, 27, 4, -9, -1, + 9, -8, -21, -22, -27, -33, -53, -64, -67, -82, -86, -83, -67, -75, -97, -77, + -36, -15, -27, -32, -18, -1, -1, -6, -31, -62, -73, -68, -52, -52, -68, -69, + -50, -21, -2, 4, -10, -33, -29, -4, 2, -10, -29, -22, -8, -27, -55, -49, + -27, -6, 12, 31, 43, 31, 38, 44, 54, 48, 25, 11, 19, 30, 36, 41, + 41, 29, 11, -1, -9, 0, 15, 27, 34, 36, 46, 46, 26, 27, 39, 51, + 59, 62, 62, 73, 76, 77, 85, 78, 58, 35, 23, 21, 37, 53, 37, 22, + 15, 16, 20, 3, 0, -2, -2, -14, -33, -35, -45, -69, -77, -59, -53, -76, + -96, -74, -41, -30, -25, -26, -19, -4, 7, 11, -8, -40, -62, -62, -51, -55, + -69, -74, -71, -44, -15, -2, -14, -36, -38, -8, -7, -27, -33, -17, -12, -38, + -51, -57, -58, -41, -14, 8, 19, 15, 15, 31, 46, 40, 21, 9, 7, 10, + 20, 25, 33, 28, 16, 1, -18, -13, 0, 6, 12, 30, 39, 39, 26, 20, + 32, 41, 45, 53, 64, 63, 62, 80, 84, 87, 81, 51, 29, 21, 44, 52, + 41, 33, 29, 31, 27, 12, 8, 16, 10, -4, -7, -7, -29, -62, -57, -37, + -44, -68, -81, -70, -48, -33, -23, -22, -17, -5, 16, 31, 14, -15, -33, -42, + -41, -37, -53, -65, -74, -54, -16, 2, -12, -33, -19, -1, -10, -22, -17, -8, + -8, -18, -33, -48, -62, -57, -31, -1, 7, 0, 9, 22, 40, 40, 27, 14, + 4, 3, 10, 14, 21, 31, 20, 0, -13, -19, -17, -15, -7, 12, 29, 28, + 13, 20, 18, 18, 31, 38, 47, 49, 51, 56, 67, 87, 84, 56, 30, 20, + 31, 41, 31, 24, 32, 33, 20, 7, 14, 15, -2, -1, 13, 4, -28, -53, + -45, -34, -38, -59, -75, -72, -58, -44, -26, -26, -29, -8, 14, 34, 28, 10, + -9, -22, -26, -24, -30, -54, -78, -56, -13, -4, -17, -16, -5, 1, -6, -9, + -8, -1, 3, -2, -4, -28, -53, -58, -37, -10, 1, -1, 6, 20, 34, 46, + 40, 25, 19, 11, 7, 10, 23, 33, 28, 16, -3, -3, -17, -31, -14, 4, + 15, 20, 20, 16, 10, 14, 19, 23, 37, 45, 35, 37, 53, 76, 83, 62, + 34, 20, 27, 28, 13, 17, 29, 21, 7, 9, 13, -4, -17, -4, 13, 2, + -27, -53, -47, -39, -46, -56, -77, -87, -77, -58, -45, -46, -47, -33, -6, 17, + 22, 16, 1, -20, -25, -10, -21, -57, -79, -57, -32, -24, -23, -18, -3, -1, + -6, -4, -4, -5, 3, 13, 14, -6, -38, -51, -39, -22, -4, -1, 3, 14, + 32, 45, 46, 46, 33, 25, 15, 9, 28, 38, 32, 28, 26, 14, -9, -21, + -15, -5, 10, 24, 22, 22, 21, 15, 15, 23, 36, 42, 35, 31, 41, 72, + 87, 68, 46, 42, 34, 19, 14, 25, 25, 11, 14, 18, 14, -7, -24, -7, + 12, 4, -19, -41, -47, -44, -41, -52, -74, -92, -88, -72, -59, -63, -68, -53, + -34, -11, 12, 19, -7, -27, -15, -5, -22, -54, -76, -66, -52, -47, -41, -29, + -17, -12, -12, -10, -11, -19, -7, 12, 19, 3, -23, -42, -48, -31, -19, -14, + -6, 1, 20, 35, 39, 50, 51, 33, 16, 17, 30, 31, 32, 41, 39, 28, + 14, -7, -14, -5, 8, 18, 27, 34, 29, 22, 21, 26, 38, 51, 39, 27, + 43, 75, 84, 73, 75, 68, 46, 32, 31, 35, 27, 15, 23, 36, 26, 0, + -13, -4, 12, 14, 1, -23, -36, -36, -32, -36, -60, -83, -84, -70, -67, -70, + -66, -67, -62, -27, 8, 13, -11, -22, -7, 4, -16, -44, -63, -67, -63, -63, + -53, -42, -33, -25, -15, -10, -22, -27, -18, -1, 16, 9, -13, -32, -46, -42, + -31, -30, -24, -8, 5, 11, 25, 49, 50, 33, 25, 20, 21, 24, 29, 34, + 41, 41, 26, 5, -5, -7, -4, 12, 23, 33, 37, 29, 19, 24, 49, 53, + 33, 33, 49, 65, 73, 80, 89, 85, 63, 48, 50, 46, 30, 20, 35, 46, + 39, 17, 0, 2, 15, 23, 18, -2, -20, -24, -12, -19, -45, -60, -66, -70, + -66, -56, -61, -74, -74, -38, 0, 6, -8, -15, 3, 13, -1, -24, -42, -52, + -65, -64, -54, -54, -47, -31, -19, -12, -21, -32, -27, -12, 7, 13, -2, -24, + -36, -37, -44, -47, -32, -20, -18, -9, 12, 30, 38, 35, 26, 18, 17, 16, + 13, 25, 36, 37, 32, 18, 2, -11, -10, -5, 3, 28, 38, 20, 8, 25, + 42, 40, 28, 30, 40, 46, 54, 70, 87, 82, 66, 61, 59, 48, 28, 20, + 32, 43, 43, 24, 8, 1, 7, 23, 25, 3, -13, -9, -8, -15, -28, -40, + -58, -71, -60, -49, -58, -80, -82, -50, -17, -5, -13, -12, 6, 13, 8, -3, + -24, -42, -54, -59, -57, -60, -59, -43, -24, -15, -20, -30, -35, -25, 1, 11, + -2, -12, -18, -33, -48, -49, -41, -37, -32, -21, -8, 13, 27, 27, 27, 23, + 16, 8, 7, 15, 22, 32, 35, 22, 9, 0, -18, -26, -8, 20, 25, 11, + 4, 18, 32, 29, 22, 29, 30, 27, 38, 60, 75, 70, 68, 69, 67, 52, + 30, 19, 27, 36, 40, 34, 10, -2, 6, 21, 20, 4, -2, -4, -7, -9, + -12, -25, -52, -66, -53, -42, -53, -79, -86, -58, -33, -23, -16, -12, 0, 12, + 17, 13, -5, -24, -38, -44, -50, -59, -61, -51, -33, -15, -11, -28, -36, -23, + -4, 5, 5, 7, -3, -17, -31, -40, -38, -37, -36, -29, -14, 4, 15, 25, + 34, 30, 24, 19, 9, 8, 22, 33, 31, 30, 31, 16, -14, -26, -13, 14, + 17, 7, 8, 18, 24, 23, 28, 31, 23, 18, 30, 50, 62, 61, 63, 75, + 73, 59, 40, 23, 20, 30, 43, 35, 11, 0, 8, 15, 12, 6, 3, -6, + -10, -3, -1, -15, -46, -62, -47, -38, -54, -77, -84, -70, -53, -40, -30, -21, + -12, 1, 16, 20, 5, -12, -21, -33, -44, -52, -64, -64, -44, -17, -15, -27, + -30, -26, -15, -3, 6, 12, 9, -2, -17, -26, -29, -36, -41, -32, -21, -10, + 6, 18, 27, 34, 37, 25, 11, 14, 21, 26, 27, 37, 48, 33, -1, -19, + -8, 7, 8, 8, 16, 16, 17, 25, 34, 36, 23, 16, 28, 44, 53, 54, + 61, 74, 79, 75, 56, 30, 19, 31, 45, 35, 15, 9, 9, 9, 11, 9, + 5, -8, -14, 0, 9, -10, -40, -53, -44, -38, -51, -72, -84, -80, -69, -58, + -45, -38, -30, -13, 5, 13, 8, 0, -14, -25, -30, -46, -67, -72, -55, -34, + -26, -28, -31, -31, -26, -17, -4, 9, 11, 2, -4, -12, -22, -33, -38, -40, + -34, -18, -7, 2, 17, 33, 38, 29, 19, 20, 22, 17, 19, 38, 57, 43, + 15, 2, -1, 1, 3, 10, 18, 15, 14, 25, 38, 40, 27, 21, 28, 38, + 46, 50, 55, 66, 81, 90, 71, 40, 30, 37, 44, 39, 26, 18, 12, 8, + 14, 19, 8, -11, -13, 5, 15, -2, -28, -42, -36, -34, -45, -60, -76, -83, + -77, -65, -59, -55, -43, -28, -13, 5, 11, 2, -9, -11, -17, -37, -61, -71, + -65, -49, -38, -36, -34, -35, -36, -32, -16, -2, 1, 3, 0, -7, -13, -25, + -39, -46, -42, -30, -22, -15, 2, 21, 30, 24, 22, 28, 19, 5, 11, 33, + 50, 45, 31, 17, 6, -1, 0, 8, 16, 12, 11, 23, 37, 40, 33, 29, + 29, 33, 45, 48, 46, 58, 83, 97, 84, 59, 45, 46, 47, 46, 42, 31, + 16, 12, 23, 29, 16, -5, -9, 10, 21, 10, -12, -24, -25, -25, -29, -42, + -64, -73, -70, -66, -63, -58, -52, -42, -22, 0, 8, 4, 1, 3, -1, -19, + -44, -61, -63, -57, -50, -39, -33, -37, -39, -36, -27, -14, -4, 0, 0, 0, + -1, -13, -30, -42, -43, -37, -36, -30, -10, 8, 12, 15, 26, 31, 16, 1, + 4, 21, 37, 41, 38, 29, 13, 0, -1, 6, 8, 3, 7, 17, 26, 34, + 35, 27, 24, 32, 40, 37, 32, 45, 72, 89, 86, 70, 57, 48, 45, 49, + 50, 37, 16, 11, 25, 34, 20, -3, -7, 7, 18, 15, 2, -14, -20, -15, + -17, -32, -49, -61, -67, -65, -60, -61, -63, -54, -33, -12, -1, 1, 2, 10, + 12, -3, -26, -43, -57, -60, -54, -45, -38, -38, -39, -39, -35, -23, -13, -6, + -3, 2, 7, -2, -20, -30, -34, -42, -47, -38, -19, -9, -5, 7, 24, 31, + 19, 3, 0, 10, 23, 33, 40, 36, 18, 5, 4, 4, 0, 0, 0, 5, + 16, 29, 30, 22, 22, 31, 36, 27, 21, 32, 54, 74, 81, 77, 65, 49, + 44, 50, 55, 40, 16, 10, 24, 31, 20, 3, -6, -1, 11, 16, 5, -9, + -13, -12, -14, -22, -36, -53, -63, -62, -59, -63, -69, -67, -48, -25, -14, -10, + -1, 10, 16, 10, -6, -26, -45, -54, -55, -50, -42, -39, -39, -40, -39, -29, + -19, -15, -8, 4, 11, 3, -6, -11, -21, -38, -48, -40, -26, -21, -16, -3, + 18, 30, 24, 12, 6, 4, 11, 29, 41, 39, 28, 18, 11, 8, 5, 1, + -4, -2, 11, 25, 25, 19, 23, 33, 35, 25, 17, 23, 39, 57, 74, 81, + 72, 53, 47, 56, 60, 44, 23, 16, 22, 29, 25, 10, -4, -3, 7, 11, + 6, -3, -9, -11, -9, -12, -26, -42, -56, -59, -55, -61, -73, -75, -60, -42, + -32, -23, -12, 0, 12, 15, 7, -10, -30, -46, -53, -53, -46, -41, -43, -45, + -41, -32, -30, -26, -14, -1, 5, 2, 3, 3, -9, -30, -43, -40, -31, -31, + -28, -12, 8, 20, 25, 22, 9, 0, 6, 21, 34, 39, 35, 26, 18, 16, + 14, 4, -7, -5, 9, 21, 19, 16, 23, 35, 37, 28, 20, 20, 26, 43, + 67, 82, 74, 57, 54, 62, 63, 52, 33, 21, 23, 30, 28, 14, 1, -1, + 3, 8, 7, -1, -7, -9, -6, -5, -15, -34, -49, -51, -51, -60, -72, -76, + -70, -57, -46, -37, -25, -13, 3, 14, 14, 3, -15, -33, -48, -52, -47, -45, + -49, -49, -41, -37, -39, -35, -21, -10, -5, -2, 6, 12, 1, -19, -32, -34, + -36, -39, -34, -23, -9, 9, 23, 25, 14, 3, 2, 12, 25, 36, 37, 30, + 24, 25, 24, 10, -5, -4, 9, 18, 15, 14, 23, 34, 38, 36, 30, 19, + 15, 32, 61, 78, 75, 63, 60, 67, 71, 62, 42, 29, 30, 33, 32, 20, + 8, 4, 6, 8, 8, 3, -5, -9, -2, 3, -7, -25, -37, -42, -45, -54, + -66, -74, -74, -67, -58, -49, -40, -27, -9, 5, 13, 13, 0, -21, -39, -45, + -44, -49, -54, -50, -44, -44, -47, -42, -29, -21, -19, -11, 5, 12, 4, -8, + -18, -28, -36, -40, -40, -36, -24, -4, 14, 21, 17, 7, 0, 3, 17, 32, + 34, 29, 28, 34, 33, 17, 0, 0, 9, 13, 12, 14, 20, 27, 38, 46, + 39, 21, 11, 24, 51, 71, 74, 66, 64, 73, 78, 71, 54, 40, 38, 41, + 38, 28, 17, 11, 9, 12, 14, 7, -3, -5, 3, 9, 2, -12, -23, -28, + -35, -45, -55, -65, -71, -68, -62, -57, -50, -37, -22, -7, 10, 20, 12, -8, + -24, -32, -39, -48, -52, -49, -45, -49, -52, -44, -34, -33, -30, -18, -3, 5, + 5, 1, -8, -19, -29, -37, -43, -45, -37, -18, 0, 13, 18, 10, -1, -3, + 10, 24, 26, 23, 29, 38, 37, 21, 8, 5, 6, 8, 10, 12, 11, 16, + 34, 49, 46, 27, 10, 15, 38, 59, 67, 63, 63, 72, 81, 77, 61, 48, + 45, 45, 42, 35, 23, 13, 11, 17, 18, 9, -3, -5, 3, 10, 6, -3, + -12, -19, -24, -34, -46, -57, -64, -65, -66, -63, -56, -48, -39, -22, 1, 17, + 16, 3, -8, -17, -30, -44, -47, -44, -47, -53, -52, -44, -41, -41, -38, -28, + -14, -3, 3, 3, -2, -9, -17, -28, -42, -49, -46, -34, -17, 3, 14, 9, + -3, -6, 5, 15, 13, 15, 26, 36, 35, 25, 16, 8, 2, 4, 9, 6, + 1, 4, 22, 43, 48, 31, 11, 7, 24, 45, 55, 54, 55, 68, 79, 77, + 66, 54, 48, 47, 47, 41, 27, 14, 11, 18, 20, 10, -2, -6, 0, 7, + 8, 2, -6, -12, -14, -23, -38, -49, -55, -62, -66, -63, -60, -59, -53, -37, + -12, 8, 13, 10, 7, -4, -21, -35, -37, -39, -47, -53, -51, -45, -44, -44, + -42, -36, -24, -10, 0, 2, 1, 1, -3, -15, -30, -42, -49, -45, -30, -6, + 10, 7, -2, -3, 5, 9, 6, 11, 23, 32, 35, 33, 25, 14, 6, 9, + 12, 8, -2, -4, 13, 36, 48, 39, 18, 7, 17, 34, 43, 45, 50, 62, + 74, 78, 71, 59, 51, 49, 52, 48, 32, 16, 12, 19, 21, 13, 1, -6, + -5, 2, 6, 2, -4, -6, -9, -18, -29, -40, -51, -60, -65, -63, -63, -68, + -68, -53, -30, -12, 0, 10, 13, 3, -14, -25, -29, -35, -45, -52, -52, -49, + -47, -47, -47, -46, -35, -20, -10, -5, -1, 4, 4, -4, -15, -30, -47, -54, + -41, -15, 1, 0, -2, 2, 6, 4, 3, 7, 16, 26, 35, 38, 32, 20, + 12, 14, 18, 12, -1, -8, 3, 27, 46, 44, 26, 14, 17, 28, 35, 38, + 44, 55, 69, 78, 77, 66, 55, 54, 60, 58, 41, 24, 17, 19, 23, 20, + 7, -4, -4, 0, 2, 1, 0, -2, -4, -10, -17, -28, -42, -55, -59, -56, + -61, -72, -74, -63, -47, -32, -14, 5, 13, 7, -4, -12, -19, -28, -38, -46, + -51, -50, -46, -47, -51, -52, -43, -30, -20, -13, -5, 0, 4, 4, 2, -13, + -40, -55, -47, -25, -12, -8, -3, 3, 5, 4, 2, 3, 7, 18, 32, 41, + 36, 25, 18, 21, 25, 21, 5, -9, -3, 19, 41, 45, 34, 24, 23, 27, + 30, 33, 38, 47, 62, 78, 82, 72, 61, 61, 67, 66, 54, 37, 24, 23, + 28, 25, 15, 5, 0, 0, 0, 1, 2, 2, -1, -4, -5, -15, -34, -47, + -49, -49, -58, -69, -73, -70, -63, -51, -30, -8, 5, 7, 3, -4, -11, -20, + -29, -41, -49, -50, -46, -49, -54, -56, -50, -42, -33, -22, -13, -10, -6, 5, + 12, -1, -30, -50, -50, -38, -27, -18, -10, -3, 1, 2, 2, -2, -4, 6, + 24, 36, 36, 27, 19, 22, 30, 28, 10, -8, -10, 9, 30, 39, 35, 30, + 26, 26, 28, 29, 29, 35, 53, 73, 80, 74, 65, 63, 69, 72, 64, 47, + 33, 28, 29, 28, 21, 12, 6, 2, -2, 1, 4, 1, -2, 2, 6, -4, + -23, -35, -38, -42, -51, -60, -66, -70, -71, -63, -45, -23, -5, 4, 6, 3, + -2, -7, -18, -32, -42, -43, -43, -47, -52, -54, -53, -51, -42, -27, -20, -21, + -14, 4, 17, 10, -13, -35, -45, -44, -37, -26, -17, -11, -3, 3, 3, -3, + -9, -4, 13, 31, 35, 27, 19, 23, 34, 36, 19, -3, -10, 2, 19, 31, + 35, 33, 29, 30, 32, 28, 22, 26, 43, 63, 76, 75, 67, 65, 71, 75, + 70, 57, 43, 36, 34, 30, 26, 21, 14, 5, 1, 4, 3, -2, -2, 6, + 11, 3, -11, -22, -29, -36, -43, -50, -57, -67, -74, -72, -60, -40, -19, -5, + 2, 4, 6, 3, -8, -23, -32, -35, -40, -45, -47, -51, -57, -58, -47, -33, + -30, -32, -24, -5, 13, 14, 1, -18, -36, -45, -42, -35, -27, -20, -11, 0, + 3, -3, -12, -12, 1, 21, 31, 25, 16, 20, 34, 40, 26, 5, -7, -6, + 7, 21, 27, 26, 27, 31, 33, 27, 17, 15, 28, 50, 65, 68, 64, 62, + 68, 74, 72, 61, 51, 44, 35, 29, 28, 25, 15, 7, 5, 5, -1, -8, + -5, 3, 8, 4, -4, -12, -22, -32, -38, -42, -50, -61, -72, -77, -73, -57, + -36, -20, -11, -2, 7, 8, -3, -14, -22, -30, -38, -41, -42, -49, -60, -62, + -52, -41, -40, -41, -34, -18, 0, 11, 10, -3, -23, -38, -42, -40, -36, -31, + -20, -6, 2, -1, -13, -19, -9, 12, 25, 20, 12, 17, 30, 39, 34, 17, + -2, -8, 1, 13, 19, 21, 23, 31, 37, 32, 18, 10, 18, 36, 55, 62, + 60, 60, 67, 73, 72, 68, 61, 51, 41, 35, 34, 28, 18, 12, 11, 8, + -2, -9, -7, 0, 4, 5, 3, -3, -14, -24, -31, -36, -41, -50, -64, -77, + -80, -68, -51, -37, -26, -11, 3, 6, 2, -3, -13, -24, -32, -33, -34, -46, + -60, -62, -54, -47, -46, -47, -43, -31, -13, 4, 12, 6, -9, -23, -34, -39, + -40, -38, -29, -14, 0, 2, -11, -22, -15, 4, 17, 16, 11, 13, 25, 39, + 41, 28, 9, -3, 0, 9, 15, 15, 19, 30, 40, 39, 26, 12, 11, 28, + 45, 54, 56, 60, 66, 70, 73, 74, 69, 58, 49, 45, 42, 32, 22, 18, + 19, 14, 3, -6, -7, -4, 0, 5, 6, 3, -5, -14, -24, -30, -32, -38, + -53, -71, -78, -72, -63, -54, -39, -22, -8, 1, 6, 6, -4, -18, -25, -23, + -25, -39, -54, -58, -54, -49, -49, -50, -49, -42, -26, -7, 7, 9, 2, -9, + -20, -30, -38, -43, -39, -22, -2, 3, -9, -20, -16, -2, 11, 14, 10, 10, + 20, 36, 46, 40, 22, 8, 6, 11, 13, 12, 15, 26, 41, 46, 36, 20, + 14, 24, 38, 47, 54, 60, 64, 69, 76, 81, 76, 66, 60, 58, 53, 40, + 30, 27, 27, 22, 12, 3, -3, -4, -1, 4, 8, 8, 5, -4, -15, -21, + -21, -25, -41, -58, -69, -71, -70, -64, -51, -35, -23, -9, 5, 10, 1, -13, + -17, -15, -19, -32, -46, -54, -54, -51, -50, -52, -55, -53, -40, -22, -6, 3, + 4, -2, -10, -19, -32, -47, -49, -32, -11, -3, -10, -20, -20, -10, 2, 7, + 5, 2, 10, 28, 42, 41, 29, 16, 10, 11, 11, 7, 6, 17, 35, 45, + 39, 26, 18, 19, 26, 37, 47, 53, 56, 61, 73, 81, 76, 68, 65, 65, + 59, 46, 36, 31, 28, 25, 19, 9, -1, -6, -4, -1, 2, 8, 9, 0, + -10, -15, -14, -18, -32, -46, -57, -68, -74, -71, -61, -51, -41, -23, -2, 8, + 2, -8, -11, -10, -13, -23, -37, -48, -53, -51, -49, -53, -59, -60, -53, -37, + -19, -7, -3, -2, -1, -6, -22, -43, -52, -42, -21, -9, -12, -20, -23, -16, + -4, 3, -1, -6, 0, 18, 34, 40, 33, 22, 16, 16, 13, 5, 0, 9, + 27, 39, 40, 32, 24, 18, 19, 29, 40, 44, 46, 55, 69, 77, 75, 71, + 70, 70, 65, 55, 45, 37, 32, 30, 26, 17, 7, 0, -5, -6, -1, 8, + 11, 4, -5, -7, -7, -13, -21, -30, -44, -59, -69, -69, -65, -63, -56, -36, + -13, 1, 1, -4, -6, -5, -6, -12, -25, -40, -47, -47, -46, -50, -56, -62, + -61, -48, -30, -18, -12, -6, 4, 6, -7, -32, -49, -46, -30, -16, -12, -19, + -25, -20, -7, 0, -3, -9, -7, 8, 26, 36, 34, 27, 24, 24, 19, 7, + -2, 4, 18, 31, 38, 38, 30, 20, 18, 26, 34, 35, 38, 48, 62, 71, + 73, 72, 73, 72, 70, 64, 53, 43, 38, 35, 30, 23, 16, 7, -4, -10, + -4, 6, 8, 3, -1, -2, -4, -9, -12, -19, -33, -51, -61, -65, -69, -73, + -70, -52, -30, -13, -6, -5, -7, -5, -2, -5, -17, -31, -41, -45, -44, -45, + -53, -64, -67, -58, -43, -31, -26, -17, -1, 10, 3, -19, -41, -48, -39, -23, + -16, -21, -27, -24, -12, -3, -5, -13, -15, -3, 16, 28, 29, 26, 28, 31, + 24, 10, 0, 0, 8, 20, 33, 38, 32, 22, 19, 24, 28, 28, 30, 40, + 52, 61, 68, 71, 72, 73, 73, 69, 59, 51, 45, 39, 32, 28, 26, 15, + 0, -9, -5, 2, 4, 2, 1, -1, -4, -6, -5, -10, -24, -41, -50, -56, + -66, -76, -77, -66, -47, -27, -15, -11, -10, -5, 0, -1, -8, -20, -33, -40, + -40, -40, -48, -62, -70, -64, -51, -43, -39, -29, -11, 7, 10, -5, -28, -43, + -41, -28, -20, -22, -29, -28, -17, -6, -5, -14, -20, -12, 6, 19, 22, 23, + 30, 35, 31, 20, 8, 0, 1, 13, 29, 37, 33, 26, 25, 27, 27, 25, + 26, 33, 43, 54, 63, 67, 70, 74, 76, 72, 66, 61, 54, 44, 37, 36, + 34, 24, 8, -3, -4, -2, 0, 2, 3, -1, -5, -3, 2, -2, -16, -29, + -36, -44, -57, -70, -79, -76, -60, -41, -27, -19, -14, -8, -1, 3, 0, -10, + -24, -33, -33, -32, -40, -55, -65, -63, -56, -51, -48, -40, -23, -1, 12, 7, + -13, -32, -37, -29, -21, -21, -28, -29, -19, -6, -2, -12, -20, -14, 0, 11, + 16, 22, 30, 37, 38, 33, 21, 7, 0, 9, 26, 36, 35, 32, 32, 32, + 31, 28, 27, 30, 38, 50, 58, 63, 70, 78, 79, 76, 74, 72, 64, 53, + 46, 45, 44, 34, 20, 9, 3, -1, 1, 7, 7, 0, -4, 2, 8, 5, + -5, -15, -23, -30, -41, -58, -73, -77, -68, -53, -38, -28, -21, -14, -5, 4, + 7, -1, -15, -25, -25, -24, -32, -48, -59, -61, -59, -57, -57, -54, -39, -16, + 4, 8, -5, -24, -33, -30, -24, -24, -32, -35, -26, -11, -6, -14, -20, -19, + -10, -2, 5, 13, 21, 29, 37, 40, 30, 11, 0, 4, 17, 27, 30, 31, + 31, 32, 32, 29, 23, 23, 31, 40, 45, 52, 63, 72, 74, 73, 75, 75, + 67, 56, 51, 50, 46, 38, 29, 18, 6, -3, -1, 5, 3, -4, -7, -2, + 4, 5, -2, -11, -17, -21, -30, -47, -66, -78, -77, -66, -53, -42, -34, -27, + -16, -3, 6, 1, -12, -21, -21, -21, -28, -42, -54, -60, -60, -61, -65, -67, + -57, -35, -11, 1, -3, -18, -30, -30, -25, -27, -36, -41, -32, -19, -13, -17, + -22, -22, -19, -14, -6, 2, 7, 17, 31, 41, 34, 17, 3, 1, 8, 17, + 23, 25, 26, 30, 32, 28, 22, 21, 25, 30, 34, 42, 54, 63, 66, 70, + 77, 77, 69, 61, 57, 55, 49, 44, 39, 28, 11, 2, 2, 5, 3, -3, + -8, -4, 3, 6, 2, -4, -9, -11, -16, -31, -52, -68, -75, -71, -61, -50, + -43, -38, -26, -8, 5, 4, -6, -13, -14, -13, -19, -31, -44, -51, -52, -55, + -64, -71, -67, -49, -24, -4, -1, -12, -22, -21, -18, -22, -33, -39, -33, -22, + -16, -16, -17, -19, -20, -16, -9, -4, -2, 5, 18, 31, 37, 32, 21, 11, + 9, 12, 17, 20, 24, 28, 32, 31, 28, 26, 26, 26, 28, 34, 43, 51, + 57, 65, 74, 77, 75, 72, 68, 63, 59, 56, 53, 44, 31, 19, 12, 11, + 8, 3, -2, -3, 0, 4, 5, 2, 0, -1, -3, -11, -25, -42, -58, -66, + -65, -59, -54, -51, -42, -27, -11, -2, -3, -6, -7, -7, -9, -16, -27, -36, + -40, -44, -52, -63, -70, -66, -49, -28, -15, -13, -16, -16, -13, -16, -24, -31, + -33, -29, -24, -19, -17, -19, -20, -18, -14, -13, -12, -6, 7, 22, 33, 35, + 28, 18, 12, 12, 14, 17, 21, 27, 31, 31, 30, 30, 28, 25, 25, 30, + 36, 42, 49, 58, 67, 74, 76, 75, 71, 66, 62, 60, 59, 53, 41, 29, + 19, 14, 11, 7, 1, -3, -2, 1, 3, 3, 1, 0, 0, -3, -11, -26, + -44, -59, -65, -63, -60, -57, -52, -41, -25, -11, -4, -4, -6, -6, -6, -9, + -17, -27, -35, -39, -44, -53, -65, -71, -65, -47, -28, -16, -15, -16, -15, -14, + -17, -25, -32, -33, -29, -24, -19, -17, -19, -20, -18, -14, -13, -12, -6, -2, + 1, 6, 5, 21, 46, 42, 15, 0, 5, 34, 48, 29, -4, -31, -33, -17, + 26, 49, 32, 0, -21, -15, 14, 24, 24, 16, 0, 3, 11, 11, 11, 5, + 9, 9, 8, 11, 30, 27, 22, 7, -3, -3, 10, 2, -2, -4, -13, -4, + -4, -2, -2, -3, -7, -6, -14, -15, -14, -14, -13, -3, -14, -16, -18, -13, + -15, -16, -22, -20, -14, -3, -6, -4, -14, -11, -6, -10, -15, -15, -16, -9, + -10, -19, -3, -5, -17, -15, -18, -16, -14, -14, -12, -15, -7, -22, -19, -17, + -20, -11, -17, -14, -11, -8, -10, -13, -12, -11, -6, -6, -9, 1, 1, -3, + 0, 6, -2, -9, 7, -8, 8, 4, 3, 1, -6, -2, -2, 2, -5, -7, + -4, -7, -8, -9, -6, -6, 0, -8, -12, -12, -13, -8, -4, -7, -3, -11, + -6, -15, -7, -9, -9, -3, -10, -8, -9, -15, -10, -2, 2, -7, -16, -17, + -15, -13, -9, -6, -5, -7, -9, -15, -17, -12, -19, -12, -8, -8, -4, -6, + -3, 0, -4, -11, -13, -7, -6, -2, 4, 4, 8, 10, 4, 3, 3, 4, + 7, 12, 11, 14, 15, 20, 20, 18, 16, 17, 15, 14, 15, 22, 23, 28, + 34, 29, 28, 17, 22, 24, 23, 25, 28, 28, 30, 24, 19, 16, 13, 18, + 20, 15, 8, 2, 3, 0, 2, 0, -3, -2, -9, -20, -23, -25, -24, -23, + -27, -33, -38, -39, -44, -36, -42, -44, -48, -53, -54, -56, -52, -50, -40, -35, + -44, -43, -44, -39, -28, -24, -23, -22, -15, -9, 2, 11, 19, 28, 31, 31, + 32, 35, 43, 61, 70, 78, 81, 73, 78, 78, 78, 85, 82, 85, 88, 87, + 84, 83, 83, 79, 74, 62, 49, 45, 42, 43, 44, 38, 30, 18, 6, -5, + -15, -17, -15, -22, -28, -38, -46, -48, -50, -58, -59, -72, -80, -83, -89, -88, + -89, -87, -81, -84, -93, -105, -110, -109, -110, -102, -96, -82, -65, -62, -60, -60, + -60, -51, -43, -37, -28, -16, 1, 15, 28, 35, 41, 46, 53, 56, 60, 66, + 77, 91, 101, 102, 101, 99, 104, 103, 97, 91, 86, 90, 91, 86, 85, 79, + 75, 71, 59, 48, 39, 35, 33, 32, 28, 22, 15, 13, 7, 3, -7, -15, + -16, -18, -19, -23, -28, -29, -33, -37, -47, -52, -56, -63, -61, -70, -67, -70, + -72, -72, -80, -93, -91, -99, -103, -96, -108, -105, -109, -112, -94, -81, -73, -67, + -71, -77, -69, -63, -57, -38, -27, -15, 0, 4, 6, 19, 26, 41, 53, 49, + 56, 58, 69, 84, 91, 95, 101, 103, 98, 93, 85, 87, 102, 102, 103, 95, + 81, 78, 78, 71, 66, 60, 51, 50, 44, 39, 34, 34, 32, 27, 15, 0, + -6, -8, -3, -3, -11, -10, -18, -21, -26, -35, -39, -38, -44, -48, -53, -63, + -61, -61, -71, -63, -86, -89, -86, -107, -99, -109, -108, -109, -108, -121, -128, -105, + -102, -83, -67, -88, -82, -76, -78, -62, -47, -41, -19, -6, 1, 7, 13, 33, + 44, 64, 61, 59, 68, 73, 93, 98, 107, 114, 109, 123, 107, 100, 105, 100, + 111, 117, 100, 93, 92, 86, 85, 80, 70, 59, 58, 47, 38, 41, 33, 40, + 38, 25, 16, 1, -2, -3, -3, -4, -10, -16, -12, -21, -28, -28, -36, -38, + -39, -52, -61, -61, -67, -63, -65, -76, -77, -86, -95, -95, -107, -109, -112, -112, + -121, -121, -122, -105, -79, -80, -71, -80, -84, -73, -70, -56, -43, -28, -10, 6, + 11, 17, 31, 43, 63, 69, 69, 65, 77, 88, 101, 113, 112, 127, 122, 122, + 115, 104, 112, 116, 122, 117, 106, 99, 97, 96, 94, 86, 75, 70, 61, 53, + 44, 41, 46, 47, 45, 28, 19, 9, 5, 9, 1, -8, -14, -20, -24, -26, + -28, -29, -36, -39, -42, -45, -41, -42, -45, -46, -49, -47, -50, -55, -53, -61, + -63, -67, -83, -78, -89, -91, -88, -100, -93, -108, -110, -110, -115, -90, -100, -91, + -80, -91, -73, -62, -60, -41, -33, -36, -25, -16, -9, 8, 18, 35, 40, 57, + 61, 66, 95, 94, 106, 114, 105, 117, 111, 117, 118, 115, 120, 111, 109, 111, + 104, 102, 106, 93, 88, 76, 66, 63, 52, 53, 31, 27, 25, 5, 12, 1, + -5, 0, -15, -17, -23, -27, -27, -31, -31, -37, -44, -41, -43, -43, -35, -45, + -43, -41, -50, -49, -51, -57, -58, -62, -72, -76, -79, -81, -82, -86, -92, -94, + -100, -109, -110, -102, -99, -96, -83, -96, -83, -67, -73, -45, -41, -42, -27, -27, + -19, -5, 7, 14, 30, 44, 46, 57, 75, 84, 98, 108, 102, 112, 114, 110, + 120, 115, 116, 117, 108, 112, 107, 104, 108, 99, 96, 90, 73, 69, 66, 57, + 48, 36, 26, 18, 13, 6, -3, 3, -8, -14, -15, -26, -25, -26, -33, -33, + -40, -45, -45, -45, -42, -43, -44, -45, -48, -46, -55, -57, -58, -62, -67, -73, + -78, -80, -81, -82, -89, -93, -99, -106, -108, -115, -100, -95, -103, -77, -91, -85, + -59, -63, -48, -32, -36, -33, -18, -14, -6, 11, 21, 27, 47, 55, 56, 81, + 92, 96, 114, 106, 111, 116, 110, 121, 113, 115, 115, 105, 111, 106, 101, 103, + 100, 92, 84, 74, 66, 60, 58, 43, 29, 29, 13, 9, 10, -6, -2, -6, + -16, -18, -22, -27, -30, -30, -35, -44, -43, -46, -46, -42, -44, -48, -45, -46, + -50, -54, -51, -61, -63, -61, -85, -76, -80, -94, -75, -98, -97, -93, -111, -103, + -106, -97, -97, -90, -79, -93, -73, -64, -67, -39, -38, -41, -20, -20, -12, 11, + 10, 30, 40, 48, 62, 62, 85, 91, 99, 111, 101, 112, 111, 113, 120, 112, + 119, 111, 108, 114, 101, 102, 104, 89, 91, 79, 63, 67, 56, 52, 41, 29, + 26, 12, 14, 3, -5, 1, -14, -15, -19, -27, -24, -30, -31, -34, -43, -43, + -45, -48, -40, -48, -48, -45, -51, -49, -53, -56, -57, -63, -69, -76, -86, -80, + -86, -90, -87, -98, -101, -101, -108, -103, -88, -96, -88, -77, -89, -70, -60, -56, + -39, -34, -30, -26, -11, -4, 6, 26, 27, 42, 54, 57, 72, 86, 95, 105, + 107, 108, 112, 109, 116, 118, 112, 117, 108, 109, 107, 104, 103, 99, 97, 83, + 77, 71, 57, 60, 49, 35, 30, 21, 11, 11, 4, -2, -3, -13, -17, -22, + -24, -28, -29, -29, -39, -39, -44, -44, -41, -45, -44, -50, -49, -49, -56, -50, + -60, -62, -55, -82, -70, -82, -90, -80, -95, -95, -100, -105, -112, -112, -93, -102, + -91, -81, -91, -77, -60, -65, -45, -33, -40, -25, -21, -14, 5, 10, 30, 35, + 49, 61, 61, 87, 94, 102, 109, 109, 112, 112, 116, 117, 116, 118, 116, 106, + 113, 108, 101, 110, 96, 91, 84, 69, 66, 58, 54, 38, 29, 26, 12, 11, + 6, -2, -2, -8, -16, -20, -23, -27, -28, -33, -34, -44, -43, -43, -47, -39, + -44, -47, -43, -47, -49, -50, -52, -57, -58, -68, -75, -76, -83, -86, -86, -91, + -97, -98, -103, -109, -102, -91, -99, -84, -81, -93, -65, -66, -60, -37, -42, -33, + -25, -18, -9, 6, 16, 28, 41, 49, 57, 68, 84, 93, 102, 106, 106, 110, + 107, 116, 114, 111, 119, 106, 111, 108, 101, 104, 99, 94, 85, 76, 68, 61, + 56, 49, 34, 28, 21, 10, 10, 2, -3, -3, -13, -15, -24, -26, -28, -34, + -31, -42, -45, -43, -48, -44, -43, -47, -47, -47, -48, -51, -57, -57, -63, -70, + -72, -80, -86, -81, -92, -88, -96, -103, -100, -113, -110, -96, -101, -96, -79, -91, + -82, -59, -68, -47, -34, -39, -29, -18, -13, -5, 18, 22, 32, 54, 52, 64, + 83, 90, 100, 108, 109, 110, 113, 113, 116, 113, 117, 113, 106, 111, 103, 100, + 101, 98, 86, 82, 73, 59, 61, 53, 36, 34, 24, 12, 10, 5, -5, -3, + -8, -17, -18, -24, -27, -29, -30, -35, -40, -41, -45, -43, -43, -42, -45, -46, + -44, -50, -49, -55, -58, -55, -71, -70, -79, -87, -77, -92, -88, -95, -104, -100, + -115, -107, -91, -105, -85, -83, -97, -67, -68, -65, -37, -43, -33, -29, -21, -9, + 0, 18, 23, 35, 55, 48, 69, 87, 86, 108, 107, 103, 117, 106, 117, 118, + 113, 122, 109, 111, 111, 102, 110, 101, 98, 92, 77, 73, 62, 59, 54, 34, + 34, 21, 11, 15, 2, 2, 2, -14, -12, -23, -26, -26, -33, -30, -40, -44, + -42, -49, -41, -41, -44, -43, -46, -49, -51, -59, -54, -63, -67, -64, -84, -79, + -76, -91, -82, -87, -100, -100, -101, -118, -101, -89, -107, -81, -82, -93, -65, -57, + -57, -36, -26, -39, -17, -9, -13, 14, 21, 26, 45, 53, 54, 76, 88, 95, + 111, 106, 111, 114, 109, 120, 115, 115, 116, 110, 105, 109, 104, 98, 105, 94, + 83, 81, 68, 60, 62, 49, 32, 33, 18, 9, 12, 0, -3, -3, -13, -18, + -20, -24, -27, -26, -31, -37, -40, -42, -42, -43, -42, -44, -48, -48, -47, -51, + -54, -52, -56, -64, -68, -75, -84, -79, -89, -91, -93, -104, -105, -110, -114, -97, + -97, -96, -78, -89, -81, -58, -66, -47, -34, -40, -31, -23, -14, -6, 14, 22, + 31, 54, 55, 63, 87, 91, 103, 113, 105, 111, 113, 109, 119, 112, 117, 114, + 106, 113, 106, 105, 105, 99, 93, 81, 74, 61, 58, 55, 36, 30, 25, 10, + 11, 6, -5, 1, -8, -16, -19, -25, -27, -32, -32, -37, -44, -41, -47, -43, + -39, -43, -44, -45, -46, -46, -56, -53, -55, -72, -64, -74, -91, -72, -88, -97, + -80, -100, -105, -100, -111, -111, -88, -100, -99, -74, -97, -79, -54, -68, -43, -32, + -41, -26, -10, -16, 6, 22, 19, 41, 51, 49, 69, 86, 88, 103, 107, 100, + 119, 110, 111, 125, 110, 115, 115, 104, 108, 106, 99, 98, 98, 82, 76, 71, + 60, 60, 52, 34, 30, 25, 9, 11, 3, -6, 0, -15, -18, -21, -27, -27, + -30, -31, -38, -39, -43, -43, -39, -43, -44, -46, -47, -47, -54, -53, -59, -58, + -65, -71, -75, -81, -75, -90, -83, -90, -100, -95, -111, -109, -101, -97, -100, -84, + -86, -89, -62, -64, -50, -34, -37, -30, -21, -11, -8, 10, 19, 26, 47, 49, + 59, 76, 89, 99, 107, 109, 110, 115, 113, 119, 115, 114, 115, 106, 111, 103, + 103, 101, 98, 94, 81, 78, 65, 63, 59, 43, 34, 25, 17, 10, 7, -4, + -3, -6, -14, -16, -23, -24, -28, -29, -33, -41, -41, -46, -43, -40, -44, -44, + -46, -46, -47, -50, -54, -56, -58, -69, -70, -76, -83, -75, -87, -87, -91, -100, + -100, -109, -108, -97, -98, -93, -83, -88, -76, -61, -59, -43, -36, -33, -28, -18, + -11, -4, 14, 21, 31, 52, 51, 63, 84, 90, 101, 111, 104, 113, 113, 111, + 118, 112, 114, 109, 108, 109, 102, 106, 101, 98, 94, 79, 74, 66, 58, 55, + 39, 29, 24, 13, 11, 5, -4, 0, -10, -15, -17, -24, -25, -28, -29, -34, + -41, -41, -47, -42, -44, -46, -45, -50, -45, -50, -55, -48, -60, -60, -65, -76, + -77, -83, -84, -91, -92, -94, -106, -103, -109, -106, -89, -101, -82, -81, -88, -63, + -66, -54, -36, -40, -31, -25, -16, -7, 6, 17, 30, 41, 55, 56, 73, 89, + 92, 109, 104, 106, 114, 104, 117, 113, 110, 116, 105, 108, 106, 100, 102, 98, + 94, 85, 74, 67, 59, 55, 48, 31, 28, 19, 10, 12, 0, 2, -2, -11, + -11, -21, -21, -26, -30, -30, -40, -43, -43, -44, -40, -39, -41, -43, -42, -46, + -52, -52, -58, -63, -65, -75, -79, -83, -80, -89, -85, -88, -101, -94, -104, -114, + -93, -97, -104, -78, -92, -89, -60, -68, -48, -36, -36, -26, -21, -8, -5, 12, + 23, 26, 47, 50, 54, 77, 85, 96, 109, 102, 114, 112, 109, 125, 112, 114, + 118, 102, 110, 103, 99, 101, 96, 92, 79, 76, 66, 59, 61, 43, 32, 31, + 14, 10, 9, -5, -2, -9, -17, -18, -28, -25, -31, -31, -31, -42, -38, -43, + -41, -39, -43, -44, -47, -45, -48, -51, -53, -54, -61, -64, -67, -77, -76, -82, + -81, -89, -93, -97, -106, -108, -105, -96, -99, -88, -82, -92, -67, -64, -60, -38, + -38, -36, -24, -20, -16, 4, 11, 21, 36, 46, 53, 66, 85, 88, 103, 108, + 102, 115, 107, 112, 115, 109, 114, 104, 106, 106, 99, 102, 101, 92, 89, 81, + 67, 66, 58, 47, 39, 28, 21, 11, 12, 2, -2, 2, -12, -12, -17, -25, + -24, -29, -30, -36, -39, -41, -41, -41, -39, -41, -44, -44, -47, -51, -52, -54, + -59, -63, -65, -75, -79, -75, -90, -81, -89, -99, -92, -109, -109, -105, -99, -97, + -92, -80, -90, -71, -58, -60, -37, -32, -37, -19, -15, -14, 9, 14, 23, 42, + 46, 56, 67, 83, 96, 100, 111, 106, 111, 114, 111, 117, 111, 112, 109, 103, + 107, 100, 99, 103, 92, 88, 82, 65, 66, 59, 48, 39, 27, 22, 12, 9, + 5, -5, 0, -12, -16, -17, -26, -25, -26, -31, -34, -40, -41, -41, -41, -40, + -42, -47, -43, -46, -46, -52, -50, -52, -61, -59, -74, -75, -77, -83, -84, -91, + -92, -105, -100, -106, -109, -81, -103, -86, -73, -96, -64, -62, -59, -38, -39, -36, + -28, -15, -11, 3, 18, 25, 37, 53, 53, 67, 89, 85, 106, 103, 98, 115, + 99, 114, 115, 103, 116, 103, 104, 109, 98, 101, 98, 91, 84, 75, 67, 60, + 55, 50, 31, 28, 20, 7, 15, 0, -3, 2, -15, -12, -19, -25, -24, -32, + -32, -38, -44, -44, -45, -42, -41, -44, -43, -46, -44, -44, -58, -48, -63, -67, + -63, -87, -75, -83, -90, -81, -94, -95, -95, -107, -109, -99, -95, -99, -85, -85, + -90, -68, -62, -60, -36, -34, -39, -15, -13, -9, 14, 15, 29, 42, 50, 55, + 68, 87, 91, 101, 107, 106, 110, 113, 114, 115, 114, 112, 108, 105, 106, 98, + 98, 100, 88, 84, 75, 63, 63, 57, 46, 34, 28, 18, 10, 8, 0, -5, + -5, -15, -19, -20, -26, -26, -26, -31, -36, -40, -42, -43, -42, -39, -44, -44, + -42, -44, -47, -51, -52, -54, -65, -63, -76, -81, -68, -93, -84, -85, -104, -92, + -105, -109, -95, -95, -96, -84, -82, -84, -64, -64, -52, -39, -37, -33, -23, -11, + -9, 10, 20, 25, 49, 46, 60, 76, 82, 98, 101, 104, 110, 108, 108, 116, + 111, 111, 113, 104, 108, 106, 101, 98, 99, 92, 80, 79, 63, 61, 59, 41, + 35, 27, 18, 13, 9, 2, 0, -5, -12, -15, -20, -22, -26, -27, -30, -38, + -39, -42, -40, -39, -40, -40, -45, -43, -47, -49, -54, -53, -57, -70, -59, -80, + -77, -72, -93, -75, -91, -99, -93, -105, -108, -97, -92, -99, -80, -84, -84, -61, + -59, -49, -35, -28, -34, -14, -9, -10, 19, 17, 27, 47, 47, 61, 72, 87, + 95, 105, 104, 110, 111, 109, 117, 109, 111, 109, 103, 103, 102, 97, 95, 100, + 85, 81, 77, 61, 64, 55, 42, 34, 26, 17, 10, 9, -3, -2, -5, -13, + -15, -20, -23, -27, -27, -32, -37, -38, -41, -40, -41, -39, -43, -43, -40, -48, + -47, -49, -55, -61, -59, -70, -80, -69, -87, -83, -79, -97, -89, -98, -101, -107, + -96, -93, -101, -77, -90, -84, -62, -63, -49, -36, -34, -30, -15, -12, -2, 11, + 20, 32, 39, 53, 56, 71, 87, 89, 103, 101, 109, 109, 109, 118, 106, 114, + 111, 101, 107, 102, 93, 99, 94, 84, 85, 71, 65, 62, 54, 45, 32, 30, + 16, 12, 8, -5, -2, -9, -14, -16, -24, -22, -27, -29, -31, -38, -41, -38, + -44, -42, -41, -47, -45, -44, -48, -50, -50, -52, -62, -57, -69, -79, -69, -83, + -88, -78, -99, -97, -92, -109, -106, -91, -100, -93, -76, -91, -80, -60, -66, -48, + -37, -38, -32, -18, -15, -4, 11, 14, 31, 42, 48, 60, 69, 85, 94, 96, + 102, 107, 103, 109, 115, 104, 112, 109, 100, 106, 103, 95, 97, 96, 84, 82, + 73, 60, 62, 54, 41, 33, 27, 17, 14, 7, 0, 0, -8, -11, -16, -23, + -23, -29, -29, -32, -39, -40, -40, -40, -41, -40, -46, -48, -45, -50, -51, -54, + -56, -64, -63, -71, -78, -73, -84, -82, -87, -95, -93, -102, -102, -108, -95, -96, + -95, -76, -90, -77, -57, -61, -42, -33, -35, -26, -13, -14, 3, 15, 17, 36, + 45, 54, 60, 80, 89, 96, 108, 101, 111, 110, 109, 118, 107, 110, 109, 102, + 103, 103, 95, 97, 96, 83, 82, 70, 60, 61, 51, 38, 28, 23, 11, 8, + 4, -7, -3, -10, -16, -17, -22, -25, -27, -29, -35, -38, -43, -42, -41, -40, + -39, -43, -42, -44, -45, -46, -53, -51, -55, -68, -65, -75, -79, -77, -88, -83, + -94, -93, -101, -105, -96, -96, -92, -85, -85, -83, -71, -64, -57, -41, -41, -31, + -27, -17, -7, 2, 18, 23, 38, 48, 51, 68, 78, 91, 98, 102, 106, 108, + 110, 112, 115, 110, 115, 107, 107, 108, 99, 102, 97, 94, 87, 76, 70, 63, + 60, 49, 39, 30, 22, 16, 8, 4, 0, -4, -10, -14, -20, -24, -25, -31, + -30, -37, -41, -40, -41, -38, -39, -40, -42, -41, -43, -48, -44, -55, -58, -57, + -71, -71, -73, -78, -79, -80, -88, -89, -95, -99, -103, -101, -88, -98, -85, -79, + -90, -62, -60, -54, -35, -35, -27, -21, -9, -3, 7, 22, 26, 38, 52, 54, + 67, 87, 89, 101, 105, 103, 114, 107, 117, 112, 107, 116, 100, 105, 103, 94, + 98, 93, 87, 80, 73, 65, 59, 56, 45, 31, 28, 19, 6, 10, -3, -5, + -4, -17, -16, -22, -24, -25, -30, -28, -39, -37, -40, -44, -40, -44, -46, -46, + -47, -51, -50, -55, -55, -60, -67, -65, -81, -75, -78, -93, -78, -97, -101, -94, + -113, -104, -92, -96, -91, -79, -86, -79, -58, -58, -49, -34, -34, -33, -14, -12, + -5, 20, 19, 34, 49, 49, 66, 76, 91, 98, 98, 105, 104, 107, 111, 110, + 109, 108, 108, 103, 101, 102, 97, 95, 96, 80, 75, 71, 56, 58, 49, 33, + 28, 20, 13, 7, 4, -4, -7, -9, -18, -22, -22, -28, -30, -30, -38, -41, + -41, -43, -40, -41, -40, -44, -43, -45, -48, -49, -55, -55, -59, -67, -66, -82, + -70, -81, -86, -78, -101, -92, -98, -111, -98, -95, -95, -89, -76, -91, -70, -56, + -61, -38, -34, -33, -25, -12, -10, 1, 21, 15, 39, 47, 48, 68, 75, 90, + 97, 101, 103, 106, 106, 110, 111, 104, 111, 101, 99, 103, 96, 94, 95, 92, + 75, 79, 64, 55, 64, 43, 36, 30, 17, 13, 9, 3, -4, -3, -12, -16, + -18, -23, -25, -26, -29, -35, -38, -42, -40, -39, -41, -38, -48, -42, -45, -50, + -49, -52, -57, -63, -57, -78, -76, -67, -94, -75, -88, -100, -92, -103, -106, -97, + -88, -96, -81, -77, -85, -60, -55, -51, -35, -30, -33, -19, -9, -10, 17, 16, + 30, 46, 48, 64, 72, 86, 96, 101, 104, 105, 111, 104, 116, 109, 107, 110, + 104, 101, 104, 100, 93, 100, 86, 77, 78, 59, 60, 54, 40, 32, 23, 18, + 9, 9, 0, -5, -6, -14, -17, -20, -23, -25, -26, -31, -35, -39, -40, -36, + -40, -37, -40, -45, -42, -45, -48, -51, -50, -57, -64, -62, -76, -78, -71, -90, + -84, -88, -101, -97, -105, -108, -94, -97, -92, -81, -87, -76, -63, -58, -42, -36, + -33, -27, -15, -10, -2, 18, 19, 34, 49, 47, 66, 78, 86, 102, 104, 104, + 111, 109, 112, 115, 112, 110, 108, 106, 101, 102, 98, 96, 97, 86, 79, 72, + 62, 61, 51, 39, 32, 20, 15, 10, 2, 1, -4, -9, -13, -18, -22, -24, + -25, -29, -33, -37, -41, -39, -37, -39, -39, -43, -46, -46, -49, -49, -56, -54, + -57, -68, -66, -73, -77, -79, -83, -90, -96, -95, -107, -110, -98, -97, -98, -76, + -87, -83, -56, -68, -49, -34, -43, -28, -26, -18, -8, 3, 14, 22, 39, 47, + 54, 70, 83, 90, 101, 100, 104, 107, 102, 113, 103, 106, 109, 95, 106, 99, + 95, 101, 92, 93, 83, 74, 66, 60, 56, 44, 33, 26, 17, 12, 8, 1, + 2, -4, -11, -10, -21, -19, -25, -29, -28, -39, -38, -41, -41, -37, -40, -42, + -43, -42, -45, -47, -48, -56, -52, -59, -69, -67, -78, -78, -79, -88, -86, -95, + -100, -99, -112, -95, -92, -101, -77, -86, -86, -62, -65, -51, -39, -35, -31, -26, + -8, -11, 7, 26, 21, 45, 53, 50, 76, 86, 90, 105, 102, 105, 109, 108, + 115, 107, 112, 110, 100, 108, 100, 96, 100, 93, 89, 79, 72, 64, 58, 56, + 42, 31, 28, 14, 10, 9, -5, -2, -6, -14, -15, -22, -22, -27, -28, -31, + -41, -37, -41, -42, -37, -41, -45, -43, -45, -47, -48, -49, -58, -53, -64, -71, + -68, -82, -75, -83, -91, -87, -103, -97, -104, -111, -90, -98, -95, -77, -91, -76, + -61, -63, -43, -41, -35, -29, -23, -7, -7, 13, 22, 24, 50, 50, 59, 82, + 82, 99, 102, 100, 110, 105, 111, 113, 104, 114, 103, 104, 107, 96, 102, 97, + 92, 90, 77, 73, 64, 58, 53, 38, 31, 23, 13, 12, 3, 0, -2, -11, + -10, -17, -21, -20, -29, -27, -33, -40, -38, -44, -39, -39, -43, -41, -42, -42, + -46, -42, -53, -53, -52, -71, -67, -73, -83, -80, -81, -89, -93, -91, -100, -106, + -97, -96, -93, -88, -81, -85, -79, -59, -58, -48, -30, -36, -28, -11, -9, -2, + 21, 22, 32, 50, 52, 58, 79, 89, 90, 104, 104, 100, 113, 111, 109, 114, + 109, 107, 103, 104, 99, 94, 97, 91, 78, 79, 65, 58, 61, 47, 37, 30, + 23, 14, 10, 7, -7, -4, -8, -21, -17, -23, -30, -26, -30, -36, -37, -39, + -38, -38, -36, -38, -45, -41, -45, -49, -51, -56, -57, -63, -64, -69, -78, -70, + -80, -84, -84, -91, -100, -98, -106, -108, -90, -103, -90, -80, -93, -65, -64, -52, + -38, -37, -27, -26, -12, -6, 3, 18, 22, 36, 48, 54, 69, 84, 89, 105, + 103, 106, 117, 105, 117, 113, 106, 113, 101, 105, 101, 99, 98, 93, 94, 83, + 75, 70, 60, 55, 49, 33, 27, 19, 10, 8, -2, -2, -7, -13, -12, -22, + -20, -23, -28, -28, -35, -39, -40, -41, -40, -42, -40, -43, -42, -42, -44, -46, + -49, -52, -59, -60, -70, -74, -71, -84, -82, -88, -96, -98, -100, -105, -102, -88, + -95, -83, -79, -87, -62, -62, -52, -40, -39, -31, -27, -14, -10, 7, 17, 25, + 42, 49, 59, 72, 85, 92, 103, 103, 102, 111, 104, 113, 110, 104, 112, 102, + 107, 103, 101, 99, 97, 92, 81, 76, 64, 61, 54, 42, 33, 24, 17, 11, + 8, -2, -2, -5, -13, -12, -22, -23, -26, -31, -32, -38, -40, -43, -39, -40, + -41, -40, -44, -41, -44, -47, -51, -49, -62, -55, -68, -78, -68, -89, -79, -81, + -96, -85, -101, -100, -103, -98, -91, -97, -79, -83, -87, -61, -64, -55, -31, -41, + -29, -15, -19, 3, 9, 18, 33, 36, 56, 54, 71, 87, 87, 103, 103, 103, + 110, 107, 113, 112, 108, 111, 101, 104, 103, 92, 101, 92, 84, 84, 66, 65, + 59, 51, 45, 31, 27, 16, 10, 6, -3, -3, -9, -15, -16, -22, -24, -25, + -30, -28, -36, -40, -36, -42, -38, -41, -45, -44, -47, -47, -49, -51, -52, -54, + -62, -68, -73, -78, -81, -84, -83, -97, -94, -101, -113, -100, -99, -96, -87, -83, + -85, -75, -60, -60, -43, -36, -38, -27, -20, -15, 0, 14, 19, 33, 47, 49, + 67, 78, 90, 100, 103, 105, 107, 108, 110, 112, 109, 109, 107, 102, 105, 100, + 99, 98, 95, 84, 80, 69, 59, 60, 48, 36, 31, 18, 14, 9, 3, -2, + -5, -10, -15, -19, -24, -25, -28, -31, -34, -39, -41, -40, -38, -40, -38, -43, + -43, -42, -48, -47, -53, -54, -58, -67, -63, -79, -73, -78, -90, -80, -98, -97, + -101, -109, -105, -93, -98, -90, -76, -93, -66, -60, -59, -33, -42, -32, -26, -18, + -9, 0, 17, 21, 38, 48, 53, 69, 82, 93, 101, 107, 102, 112, 108, 111, + 115, 105, 112, 103, 105, 104, 96, 103, 95, 95, 85, 76, 68, 63, 59, 47, + 38, 26, 19, 13, 7, 1, -3, -4, -14, -12, -19, -23, -21, -29, -29, -35, + -40, -41, -42, -39, -43, -42, -46, -43, -47, -45, -48, -54, -47, -66, -61, -68, + -85, -66, -90, -84, -84, -103, -91, -106, -105, -96, -90, -92, -81, -79, -86, -59, + -59, -53, -34, -36, -33, -19, -10, -10, 17, 20, 26, 52, 48, 60, 75, 85, + 95, 102, 104, 102, 111, 107, 113, 110, 109, 111, 103, 107, 102, 97, 96, 95, + 85, 77, 73, 56, 60, 52, 37, 33, 22, 16, 11, 7, -3, -4, -6, -16, + -14, -21, -24, -24, -28, -32, -37, -38, -42, -36, -37, -39, -39, -43, -40, -42, + -48, -50, -50, -64, -57, -70, -84, -63, -90, -81, -77, -101, -85, -99, -105, -102, + -100, -92, -99, -79, -89, -86, -58, -65, -49, -29, -41, -26, -11, -19, 6, 12, + 14, 39, 37, 52, 60, 68, 90, 90, 104, 102, 106, 111, 108, 118, 109, 109, + 111, 98, 106, 101, 90, 101, 90, 82, 86, 63, 65, 63, 48, 47, 29, 25, + 16, 10, 6, -6, -3, -13, -18, -16, -26, -25, -25, -32, -30, -39, -43, -37, + -43, -39, -39, -48, -44, -46, -53, -50, -56, -59, -59, -67, -72, -77, -76, -84, + -83, -84, -100, -95, -103, -115, -98, -93, -103, -82, -82, -91, -60, -62, -54, -34, + -35, -31, -23, -13, -11, 7, 19, 21, 43, 48, 55, 73, 85, 94, 104, 102, + 109, 110, 105, 118, 107, 109, 113, 98, 106, 103, 96, 99, 98, 90, 82, 79, + 62, 62, 58, 41, 34, 26, 14, 10, 8, -3, -2, -5, -14, -13, -20, -20, + -24, -26, -28, -38, -39, -42, -42, -41, -41, -42, -48, -41, -43, -50, -41, -49, + -59, -50, -68, -74, -67, -82, -80, -89, -87, -101, -101, -93, -121, -85, -90, -105, + -65, -93, -82, -55, -69, -49, -38, -46, -32, -27, -19, -5, 3, 19, 26, 41, + 53, 52, 81, 81, 95, 104, 90, 113, 101, 105, 118, 99, 113, 109, 100, 109, + 104, 98, 104, 96, 89, 83, 71, 66, 57, 56, 38, 28, 29, 8, 17, 6, + -2, 3, -24, -13, -79, -103, -120, -116, -104, -87, -76, -63, 63, 82, 97, 108, + 119, 99, 70, 69, 80, 91, 92, 98, 115, 124, 127, 113, 82, 42, 4, -44, + -70, -82, -100, -87, -62, -58, -71, -65, -79, -60, -102, -113, -62, -44, -31, -31, + -22, -18, -3, 4, 11, 20, 28, 11, 15, 18, 27, 18, 7, 13, 26, 11, + -19, -69, -108, -84, -51, -21, -3, -6, -18, -17, -31, -33, -18, 2, 4, 26, + 47, 48, 77, 117, 127, 127, 127, 121, 110, 86, 72, 62, 46, 11, 17, -2, + -7, -13, -44, -60, -61, -61, -63, -72, -79, -99, -116, -127, -128, -128, -124, -81, + -51, -4, 5, -6, 7, 8, 9, 31, 31, 16, 34, 28, 34, 34, 46, 78, + 84, 93, 69, 47, 40, 64, 44, 27, 22, 0, -29, -8, 15, -6, -36, -66, + -68, -42, 0, 6, 1, 13, 24, 41, 64, 58, 50, 40, 4, 0, 3, -24, + -3, 21, 28, 26, 9, -30, -42, -61, -85, -92, -91, -96, -87, -74, -31, -20, + -38, -14, -44, -17, 18, -25, -9, 7, 1, 11, -2, -19, 12, 47, 76, 72, + 58, 68, 69, 82, 86, 76, 58, 9, -23, -12, -7, -22, -2, 0, -9, -2, + -15, -10, -3, -22, -17, -38, -44, -33, -24, -27, -16, 0, -15, 20, 19, 18, + 1, 10, 41, -1, -25, -25, -11, 30, 37, 9, 45, 37, -30, -30, 21, 5, + -26, -43, -56, -42, -48, -48, -29, -62, -76, -42, -23, -12, -14, 8, 45, 36, + 40, 25, 14, 11, 40, 46, 55, 65, 30, 17, 30, 36, 33, 18, 13, 16, + 15, 46, 37, 2, -1, -26, -36, -19, -21, -36, -62, -51, -48, -20, -2, 3, + -12, -12, -10, -35, -37, -49, -22, 14, 61, 40, 60, 75, 33, 41, 48, 38, + 29, -32, -45, -56, -64, -61, -30, -20, 30, 10, -46, -37, -35, -30, -24, -12, + -23, -34, -29, -22, -20, -14, 4, 44, 77, 49, 10, 8, 24, 20, 28, 31, + 27, 40, 35, 69, 39, 54, 38, 26, 22, 43, 36, 7, 14, 2, -25, -50, + -51, -56, -42, -55, -46, -36, -44, -36, -35, 1, 23, 11, -3, -34, -66, -33, + -12, -31, -27, -13, -1, 21, 31, 23, 0, -11, -3, -2, 9, 27, 5, -8, + -2, -17, -13, 10, 9, 3, 35, 32, 43, 24, 15, 2, -15, -9, -5, 2, + 5, 27, 25, 42, 76, 61, 17, 25, 14, -5, -17, -24, -6, 11, 23, 7, + -8, 5, -11, -23, -27, -48, -30, -12, -26, -36, -37, -39, -46, -61, -55, -23, + -20, -22, -14, -10, -16, -16, -22, -11, -3, -14, -34, -16, 9, 28, 25, 50, + 63, 52, 56, 46, 50, 54, 56, 45, 54, 29, 20, 21, 0, 0, 6, 16, + 28, 14, -1, -9, -10, -4, -9, -13, -7, -21, -27, -29, -40, -41, -35, -42, + -64, -11, 9, 2, -12, -24, -37, -40, -34, -29, -34, -12, -26, -20, -6, -4, + 5, 5, 27, 1, -17, 2, 21, 12, 8, 9, 15, 23, 24, 1, 5, 22, + 25, 28, 57, 55, 41, 33, 36, 27, 5, 1, 15, 34, 23, 4, 20, 18, + -1, -21, -22, -15, -17, -8, -6, -6, -12, -15, -26, 1, 29, -8, -40, -52, + -55, -19, -21, -36, -48, -56, -29, -15, -29, -39, -46, -35, -14, -11, -16, 1, + 27, 22, -10, -14, -7, -12, -12, 23, 55, 48, 65, 42, 20, 46, 45, 49, + 42, 38, 34, 25, 33, 21, 10, 38, 40, 26, 22, 37, 33, 12, 4, 7, + -14, -49, -41, -36, -53, -40, -35, -44, -31, -22, -19, -50, -78, -80, -78, -48, + -31, -18, -27, -28, -7, -17, -11, 5, 32, 39, 19, 14, 22, 34, 37, 23, + 20, 40, 40, 27, 14, 11, 7, 29, 34, 19, 32, 7, -15, -12, -24, -12, + 8, 6, 21, 34, 29, -6, -22, -15, 1, -1, 24, 27, 20, 36, 42, 45, + 27, -14, -50, -34, -14, -26, -25, -10, 10, -4, -28, -30, -34, -69, -91, -85, + -74, -51, -38, -24, -19, -9, -7, -30, -35, -30, -36, -12, 25, 32, 44, 50, + 45, 51, 68, 94, 90, 74, 60, 52, 64, 48, 30, 11, 11, 11, 2, 14, + 24, 16, 13, -7, -17, -9, -12, -20, -32, -45, -54, -58, -35, -23, -46, -51, + -33, -28, -29, -24, -36, -30, -24, -22, -20, -13, -9, -14, -7, 10, 26, 22, + 9, 9, 10, -2, -9, -15, -11, -1, 19, 27, 33, 28, 5, 3, 5, 6, + 10, 14, 24, 32, 36, 40, 41, 37, 19, 11, 3, -7, -10, -7, 6, 27, + 38, 28, 23, 16, 18, 15, -7, -33, -20, -13, -24, -25, -19, -15, -26, -52, + -56, -48, -41, -36, -30, -32, -30, -15, -38, -49, -47, -32, -17, -17, -11, -3, + 3, 8, 24, 28, 16, 6, 1, 7, 28, 41, 42, 69, 87, 78, 73, 62, + 30, 14, 9, 7, 15, 32, 20, 10, -8, -20, 2, 9, -2, 5, 12, -4, + -12, -19, -32, -37, -29, -24, -28, -39, -43, -40, -44, -28, -25, -33, -39, -37, + -34, -29, -28, -25, -19, -1, -5, -22, -12, 2, 6, 38, 46, 25, 30, 41, + 47, 37, 21, 7, -7, -8, 11, 39, 48, 43, 35, 27, 25, 22, -1, -22, + -11, 13, -4, -13, -3, -8, -7, -11, -17, -5, 5, 9, 8, 15, 25, 16, + 22, 20, 5, -16, -27, -29, -30, -9, 9, 9, 3, -14, -50, -56, -56, -79, + -92, -80, -57, -24, 12, 10, 11, 4, -22, -21, -13, -2, 4, 10, 15, 8, + 35, 72, 53, 44, 25, 25, 48, 56, 69, 53, 50, 75, 85, 71, 33, 12, + -16, -32, -25, -14, -5, -16, -23, -19, -22, -39, -41, -47, -45, -33, -35, -39, + -38, -35, -34, -29, -28, -28, -23, -10, -7, -9, -11, -18, -5, 13, 1, -13, + -8, -5, 6, 27, 46, 43, 25, 8, 11, 16, 18, 23, 30, 12, 5, 10, + 7, 5, -6, -4, -5, 1, 10, 9, 15, 21, 17, 10, -8, -16, 10, 33, + 34, 23, 13, 17, 17, 9, 11, 7, -4, -8, -8, -22, -27, -26, -19, -7, + -18, -16, -16, -47, -62, -55, -36, -16, -25, -33, -30, -34, -42, -49, -41, -43, + -31, -20, -3, 28, 48, 66, 64, 36, 20, 26, 21, 22, 39, 51, 45, 39, + 40, 53, 56, 39, 24, 16, 12, 16, 24, 27, 16, 13, 7, -18, -33, -50, + -47, -33, -24, -20, -26, -32, -31, -46, -53, -58, -56, -29, -13, -11, -2, 8, + -11, -24, -11, -9, -6, -2, -6, 1, 4, 5, 11, 6, 7, 16, 30, 28, + 19, 15, 7, 4, 11, 27, 22, 6, 9, 11, 3, 4, 17, 27, 18, 11, + 12, 5, 2, -2, -6, -7, -2, 10, 12, 9, 1, -2, 3, 4, 11, 21, + 30, 28, 6, -9, -18, -22, -22, -38, -41, -27, -18, -18, -27, -27, -23, -32, + -35, -32, -34, -30, -25, -24, -18, -9, -5, 5, -5, -26, -19, -11, -4, 11, + 37, 48, 46, 50, 53, 50, 45, 45, 37, 18, 24, 44, 38, 43, 47, 29, + 15, 11, 10, 12, 4, -8, -6, -4, -17, -27, -28, -36, -34, -37, -53, -53, + -46, -38, -38, -37, -28, -24, -23, -37, -42, -30, 0, 20, 18, 12, 14, 9, + 2, 6, 15, 13, 10, 14, 12, 2, 12, 29, 21, 1, 7, 21, 19, 14, + 15, 15, 4, -1, 5, -1, -4, 0, -2, 3, 6, 6, 13, 21, 15, 7, + 3, 5, 2, -3, 3, 3, 5, 8, 10, 16, 14, -1, -7, 2, 11, 12, + -10, -35, -42, -26, -21, -37, -44, -44, -47, -42, -27, -27, -23, -15, -16, -20, + -21, -14, -12, -9, -7, -6, 0, 13, 30, 32, 37, 38, 31, 24, 25, 43, + 54, 49, 46, 44, 40, 41, 30, 9, -1, 6, 22, 31, 22, 9, 0, -14, + -23, -29, -29, -28, -35, -39, -39, -39, -33, -25, -30, -44, -49, -45, -45, -35, + -19, 2, 16, 16, 9, 0, 0, 6, 2, -1, 11, 27, 40, 32, 16, -2, + -2, 1, 3, 1, 7, 12, 6, 8, 11, 5, -1, -2, -1, 1, 8, 10, + 5, 4, 14, 17, 6, -1, 0, 4, 4, 17, 23, 19, 25, 20, 5, -8, + -9, -2, -1, -6, -3, 13, 16, 1, -13, -19, -21, -26, -34, -37, -23, -13, + -13, -24, -40, -42, -40, -39, -29, -22, -21, -18, -12, -2, 18, 24, 10, 0, + -6, -4, 15, 33, 34, 34, 44, 41, 31, 33, 44, 43, 31, 22, 20, 17, + 16, 23, 22, 19, 21, 10, -5, -6, -9, -8, -2, -5, -16, -28, -36, -47, + -53, -39, -23, -21, -24, -32, -43, -39, -34, -24, -18, -14, -11, -12, -6, 10, + 29, 41, 40, 27, 14, 10, 4, 1, 3, 2, 9, 19, 21, 9, -10, -16, + -10, 8, 18, 20, 13, -3, -8, -4, -1, 2, 5, 5, -1, 3, 9, 12, + 16, 16, 14, 9, 3, 5, 10, 4, -6, 1, 6, 5, 13, 20, 11, 1, + -7, -21, -30, -25, -12, -9, -13, -19, -24, -29, -34, -30, -32, -39, -33, -24, + -20, -22, -24, -13, 3, 6, 2, 1, 3, 5, 16, 30, 35, 35, 24, 16, + 15, 19, 31, 37, 33, 28, 29, 29, 30, 26, 20, 15, 13, 10, 10, 12, + 9, 7, -3, -21, -39, -44, -43, -42, -34, -26, -23, -18, -12, -18, -32, -36, + -31, -27, -20, -10, -7, -9, -11, -5, 2, 12, 19, 19, 25, 24, 11, 3, + 15, 29, 30, 20, 9, 1, -1, 1, 5, 2, -3, -2, 0, -6, -18, -27, + -20, -3, 8, 13, 15, 11, 7, 10, 18, 16, 10, 6, 3, -1, 1, 11, + 19, 19, 15, 14, 5, -2, -2, -7, -12, -15, -20, -16, -10, -5, 2, 1, + -13, -29, -33, -24, -10, -6, -13, -18, -23, -31, -32, -26, -22, -18, -13, -3, + 2, 3, 7, 8, 10, 19, 27, 32, 33, 33, 35, 38, 43, 41, 29, 9, + -4, -9, 2, 16, 17, 13, 15, 17, 13, 10, 5, -1, -8, -18, -29, -32, + -27, -21, -22, -30, -31, -31, -33, -31, -27, -18, -7, -6, -15, -16, -8, -1, + 4, 12, 18, 22, 20, 16, 11, 10, 14, 18, 16, 15, 14, 9, 6, 4, + 3, 3, 0, -5, -13, -18, -15, -13, -9, -7, -8, -5, -2, -5, -1, 5, + 8, 10, 11, 12, 17, 19, 16, 10, 4, 4, 8, 8, 8, 13, 14, 9, + 3, 0, -1, 0, 0, -7, -19, -24, -20, -15, -12, -15, -21, -23, -24, -26, + -28, -29, -28, -21, -10, -1, 5, 6, -3, -12, -14, -11, -1, 12, 16, 17, + 28, 36, 28, 20, 25, 27, 24, 25, 28, 21, 15, 11, 3, 4, 12, 11, + 0, -7, -5, -1, -1, -5, -8, -11, -17, -23, -22, -19, -21, -20, -20, -22, + -24, -22, -17, -20, -24, -20, -10, 2, 10, 13, 14, 14, 11, 8, 8, 12, + 17, 18, 20, 20, 14, 4, -1, -2, -1, 3, 11, 12, 6, 0, -9, -20, + -25, -18, -9, -8, -13, -18, -19, -14, -6, 0, 4, 11, 19, 22, 20, 19, + 15, 13, 14, 18, 17, 12, 7, 9, 14, 9, -1, -4, -1, -5, -10, -12, + -16, -23, -19, -7, -5, -10, -10, -11, -19, -27, -24, -14, -6, -3, -10, -21, + -24, -15, -6, 0, 9, 15, 12, 8, 6, 9, 9, 11, 20, 26, 31, 35, + 30, 21, 16, 16, 13, 6, 2, 4, 5, 3, -2, -10, -13, -11, -8, -9, + -13, -16, -18, -18, -19, -22, -18, -8, -3, -1, 0, -5, -11, -10, -9, -11, + -9, -2, 2, 4, 10, 15, 18, 19, 21, 21, 22, 22, 15, 4, -4, -8, + -7, -6, -10, -14, -18, -23, -20, -15, -8, -1, 0, -4, -7, -9, -9, -6, + -2, 2, 6, 7, 4, 1, 0, 7, 13, 11, 14, 22, 22, 15, 8, 2, + 4, 10, 16, 17, 13, 10, 9, 6, -3, -13, -23, -26, -21, -17, -14, -12, + -13, -16, -14, -9, -8, -8, -11, -18, -18, -12, -4, 0, 2, 6, 6, -1, + -6, 0, 8, 11, 13, 11, 6, 6, 9, 13, 16, 16, 15, 10, 7, 10, + 10, 4, 0, -2, -3, -1, 2, 2, -1, -5, -13, -21, -27, -30, -26, -16, + -4, 5, 8, 6, 2, -3, -5, -1, 4, 8, 9, 11, 11, 6, 0, 0, + 7, 12, 13, 11, 7, 1, -4, -3, 0, 5, 6, 5, -2, -10, -13, -13, + -10, -5, -4, -9, -18, -28, -31, -24, -14, -10, -4, 2, 5, 4, 2, 4, + 13, 20, 21, 19, 14, 11, 11, 12, 13, 14, 15, 17, 18, 18, 14, 5, + -3, -5, -8, -11, -11, -12, -15, -15, -13, -13, -15, -13, -12, -15, -16, -11, + -7, -6, -4, -1, 4, 6, -1, -10, -11, -7, -4, -1, 4, 9, 11, 12, + 9, 7, 8, 8, 7, 9, 13, 15, 12, 4, 1, 1, -2, -9, -10, -7, + -1, 3, 3, -1, -9, -12, -9, -5, 1, 3, -2, -10, -10, -7, -4, 2, + 8, 6, 4, 6, 5, -1, -1, 7, 17, 20, 17, 16, 19, 16, 7, -3, + -8, -9, -9, -11, -15, -24, -27, -20, -15, -12, -11, -7, -3, -4, -6, -7, + -6, -8, -14, -18, -18, -15, -10, -5, 3, 12, 18, 20, 17, 11, 10, 16, + 21, 22, 23, 23, 22, 17, 9, 0, -3, 2, 10, 15, 16, 11, 2, -9, + -19, -23, -22, -15, -10, -8, -11, -13, -15, -17, -19, -18, -15, -10, -3, 1, + -2, -6, -3, 0, -3, -3, 0, 6, 10, 9, 7, 4, -1, -4, 0, 10, + 17, 16, 11, 5, 0, -1, 2, 5, 1, -6, -10, -10, -8, -6, -4, -2, + -4, -7, -9, -9, -6, 2, 12, 17, 16, 11, 8, 7, 6, 5, 7, 9, + 12, 14, 14, 9, 3, -1, -3, -5, -4, 0, 4, -1, -10, -18, -24, -29, + -28, -20, -14, -13, -12, -8, -5, -5, -9, -13, -14, -11, -10, -9, -4, 1, + 3, 2, 3, 8, 16, 20, 18, 13, 10, 14, 24, 29, 29, 27, 23, 17, + 14, 16, 17, 15, 9, -1, -7, -10, -14, -18, -16, -11, -8, -7, -8, -12, + -18, -26, -29, -26, -19, -11, -5, -3, -3, -2, 0, 2, 0, -3, -3, -2, + -3, -4, -2, -1, 3, 7, 9, 8, 7, 3, 1, 4, 5, 2, 3, 5, + 5, 0, -7, -9, -6, -1, 5, 9, 8, 3, -2, -6, -5, 3, 9, 12, + 11, 8, 4, 3, 4, 6, 11, 13, 8, 1, 0, 4, 9, 13, 12, 5, + 2, 3, 3, 0, -6, -16, -26, -30, -28, -26, -22, -18, -17, -19, -22, -24, + -19, -12, -7, -2, 1, 0, -2, -4, -5, -2, 4, 10, 14, 15, 15, 16, + 16, 17, 19, 22, 26, 25, 19, 13, 10, 7, 9, 11, 10, 7, 4, 1, + -5, -8, -8, -4, 0, 1, -4, -11, -16, -17, -16, -14, -12, -10, -11, -14, + -15, -16, -13, -9, -3, 1, 2, 1, 0, 0, -3, -9, -13, -10, -8, -7, + -4, 0, 3, 6, 9, 9, 5, 3, 3, 5, 8, 12, 12, 6, -1, -2, + 2, 8, 8, 4, -2, -5, -1, 4, 10, 13, 14, 13, 13, 14, 14, 12, + 10, 8, 8, 8, 6, 6, 9, 6, -1, -9, -15, -19, -22, -24, -23, -25, + -25, -23, -20, -19, -19, -21, -20, -20, -21, -19, -11, -2, 2, 1, 0, 3, + 9, 13, 15, 16, 14, 10, 5, 3, 8, 14, 16, 18, 20, 22, 24, 21, + 15, 9, 6, 8, 14, 18, 15, 9, 4, 1, 0, -2, -4, -4, -3, -3, + -4, -7, -11, -13, -12, -11, -15, -19, -22, -25, -25, -21, -14, -11, -15, -19, + -18, -14, -7, -1, 4, 2, -3, -6, -4, 0, 5, 10, 16, 17, 12, 7, + 2, -1, -3, 0, 3, 6, 10, 14, 12, 6, 2, 5, 10, 15, 18, 18, + 16, 14, 11, 6, 4, 3, 1, 1, 2, 6, 9, 9, 3, -2, -3, -4, + -6, -8, -10, -15, -19, -20, -19, -18, -17, -15, -16, -17, -18, -20, -22, -21, + -16, -11, -4, 1, 0, -4, -4, -1, 1, 2, 4, 4, 3, 3, 4, 7, + 11, 16, 21, 20, 15, 11, 9, 12, 16, 21, 24, 23, 21, 17, 13, 11, + 9, 4, 0, 0, 1, 3, 4, 0, -4, -7, -7, -9, -13, -17, -20, -22, + -23, -21, -16, -12, -12, -15, -17, -17, -15, -12, -10, -10, -11, -12, -15, -15, + -10, -4, 0, -1, -1, 1, 4, 7, 13, 19, 22, 23, 21, 19, 18, 17, + 11, 5, 2, 5, 10, 13, 15, 15, 14, 13, 10, 5, 1, 0, 2, 5, + 8, 10, 9, 6, 4, 2, -1, -5, -7, -8, -7, -8, -11, -13, -14, -16, + -19, -21, -22, -22, -24, -23, -20, -17, -16, -16, -15, -16, -16, -15, -13, -11, + -9, -5, 0, 6, 12, 15, 18, 18, 17, 17, 19, 20, 19, 19, 20, 23, + 25, 25, 23, 20, 17, 13, 11, 9, 9, 8, 6, 3, 1, -2, -5, -5, + -2, -1, -3, -7, -6, -3, 0, -2, -9, -21, -29, -32, -32, -30, -27, -27, + -29, -30, -28, -24, -23, -21, -16, -7, 0, 1, 2, 2, 4, 7, 10, 14, + 16, 14, 12, 13, 15, 18, 20, 22, 23, 20, 15, 8, 3, 2, 7, 13, + 15, 13, 7, 2, 0, 0, -1, -2, -1, 1, 2, 1, 0, 2, 3, 4, + 4, 6, 7, 5, 0, -10, -21, -30, -36, -36, -33, -28, -23, -18, -15, -14, + -17, -19, -19, -17, -12, -5, -2, -2, -3, -1, 2, 6, 10, 12, 14, 13, + 12, 13, 18, 25, 29, 28, 24, 19, 14, 10, 6, 6, 9, 12, 13, 15, + 17, 18, 18, 14, 7, 0, -1, 1, 1, -2, -6, -8, -10, -11, -13, -17, + -19, -18, -17, -16, -14, -14, -15, -17, -19, -22, -26, -26, -24, -20, -17, -14, + -13, -12, -10, -7, -4, 1, 5, 7, 9, 10, 13, 15, 17, 18, 21, 24, + 22, 21, 19, 17, 15, 13, 14, 14, 16, 17, 18, 16, 12, 10, 8, 6, + 5, 3, 0, -3, -6, -7, -5, -4, -4, -5, -5, -4, -4, -4, -8, -13, + -19, -24, -27, -28, -27, -25, -25, -27, -27, -25, -19, -14, -8, -3, 1, 6, + 9, 8, 3, -3, -6, -4, -1, 4, 9, 14, 18, 20, 22, 22, 23, 23, + 22, 21, 20, 20, 21, 21, 19, 15, 9, 3, -2, -4, -3, 0, 2, 2, + 2, 3, 3, 1, -4, -10, -15, -19, -19, -16, -11, -7, -7, -9, -13, -17, + -23, -28, -30, -29, -24, -20, -18, -19, -20, -19, -18, -19, -18, -13, -5, 1, + 6, 9, 11, 13, 16, 21, 26, 29, 30, 29, 29, 28, 26, 23, 20, 20, + 21, 21, 20, 18, 15, 9, 2, -4, -6, -5, -3, -3, -4, -6, -7, -9, + -10, -10, -10, -10, -11, -13, -12, -11, -8, -6, -6, -10, -17, -26, -32, -35, + -35, -34, -32, -27, -19, -9, -3, -1, -2, -5, -7, -6, -1, 7, 14, 18, + 21, 23, 25, 26, 26, 23, 20, 20, 23, 24, 24, 21, 19, 14, 8, 2, + -1, 0, 1, 2, 3, 6, 8, 8, 5, 2, -2, -5, -5, -4, -1, 1, + 1, -1, -6, -9, -11, -13, -17, -20, -24, -26, -27, -26, -23, -21, -20, -23, + -26, -27, -26, -24, -20, -15, -9, -2, 4, 8, 10, 13, 16, 19, 21, 23, + 25, 28, 33, 36, 38, 38, 35, 32, 29, 24, 16, 11, 6, 2, -2, -6, + -6, -5, -4, -4, -7, -11, -14, -13, -10, -8, -8, -8, -9, -11, -12, -12, + -11, -11, -12, -14, -17, -19, -19, -18, -18, -20, -22, -23, -21, -18, -14, -11, + -8, -4, -1, 5, 11, 13, 11, 8, 6, 7, 9, 11, 13, 15, 19, 22, + 23, 25, 27, 27, 22, 17, 11, 6, 4, 5, 9, 13, 15, 15, 11, 6, + 0, -4, -7, -8, -6, -3, -2, -3, -6, -9, -13, -18, -22, -23, -20, -15, + -11, -10, -11, -14, -19, -24, -27, -28, -28, -27, -26, -23, -19, -15, -10, -6, + -1, 4, 8, 10, 11, 11, 13, 15, 17, 20, 23, 24, 24, 26, 28, 28, + 28, 27, 26, 24, 22, 20, 16, 13, 10, 8, 6, 3, -3, -9, -15, -17, + -16, -15, -13, -13, -14, -17, -19, -20, -20, -17, -14, -12, -13, -14, -13, -13, + -14, -15, -14, -13, -12, -12, -12, -10, -8, -7, -8, -9, -9, -7, -4, 0, + 3, 6, 8, 10, 12, 14, 18, 22, 25, 26, 27, 28, 28, 27, 24, 20, + 16, 13, 11, 9, 6, 3, 0, -3, -3, -2, 1, 3, 5, 3, 0, -4, + -8, -12, -17, -21, -22, -20, -17, -15, -14, -14, -13, -15, -19, -22, -21, -18, + -14, -13, -15, -16, -17, -17, -19, -19, -16, -11, -4, 1, 6, 10, 13, 17, + 20, 23, 24, 24, 24, 25, 28, 33, 37, 38, 35, 30, 24, 20, 16, 13, + 9, 2, -4, -8, -8, -8, -7, -7, -9, -12, -16, -18, -18, -16, -15, -16, + -16, -16, -13, -10, -10, -11, -13, -15, -15, -15, -15, -16, -17, -16, -14, -13, + -13, -13, -13, -12, -9, -5, -2, 1, 3, 6, 12, 18, 22, 22, 21, 18, + 16, 16, 19, 23, 29, 32, 30, 24, 18, 13, 9, 6, 3, 0, -2, -4, + -6, -8, -10, -11, -10, -6, -3, -2, -3, -5, -5, -6, -6, -7, -6, -5, + -4, -5, -8, -10, -11, -12, -14, -16, -18, -20, -21, -21, -22, -23, -24, -24, + -22, -18, -11, -4, 1, 4, 5, 6, 8, 11, 15, 20, 24, 26, 27, 28, + 31, 32, 31, 30, 28, 27, 24, 20, 17, 14, 12, 9, 3, -3, -9, -12, + -15, -16, -17, -15, -13, -10, -10, -11, -13, -14, -15, -17, -19, -21, -23, -24, + -22, -18, -13, -9, -8, -8, -8, -9, -9, -9, -7, -4, 0, 2, 3, 5, + 5, 3, 3, 4, 5, 6, 7, 10, 14, 17, 20, 20, 20, 21, 22, 20, + 18, 16, 15, 14, 12, 9, 7, 6, 4, 2, -2, -5, -7, -9, -9, -8, + -5, -2, 0, 0, -1, -3, -7, -12, -16, -16, -15, -13, -12, -13, -13, -12, + -11, -11, -12, -15, -19, -23, -24, -22, -19, -16, -13, -10, -5, -1, 3, 6, + 7, 8, 8, 10, 13, 17, 21, 25, 27, 28, 28, 26, 24, 24, 25, 27, + 28, 29, 28, 25, 19, 12, 4, -3, -10, -15, -19, -22, -24, -25, -26, -25, + -23, -21, -20, -18, -17, -16, -14, -12, -11, -12, -14, -14, -13, -13, -15, -16, + -16, -16, -15, -11, -4, 0, -2, 0, 0, 3, 14, 34, 24, -3, -14, -12, + 6, 6, -11, -23, -5, 15, 20, 15, -19, -12, 3, 19, 11, -5, 1, 4, + 7, -13, -3, 5, -13, 0, -2, 8, 0, -6, 16, 23, 13, 6, 2, 14, + 25, 2, 11, 3, -7, -8, -24, -6, -4, -18, 6, 30, 14, 9, 0, 0, + 13, -7, 0, -3, 9, 8, -6, -14, -15, -23, -19, -7, 0, -3, 1, -8, + -10, -10, -17, -12, -7, -10, 1, -12, -13, 0, -15, -20, -25, -16, -6, -7, + -6, -6, -2, -4, -13, -12, -6, -6, -5, 2, 8, -5, -13, -3, -4, -11, + -16, -3, 12, -2, -8, -4, -4, 4, -15, -17, -6, -2, 5, -4, 3, -2, + -10, -4, -5, -7, -8, 4, 17, 1, -3, -14, -4, -2, -7, -4, -6, 10, + 5, -6, -7, -8, 10, -5, -3, 3, -8, 11, 7, -5, -3, -13, -7, 0, + -6, 4, 0, -7, 12, -9, -17, -7, 5, 2, -3, -4, -7, 7, -2, -13, + -5, -2, 5, 4, 0, 7, -3, 4, 1, -2, -4, 6, 8, 8, 0, -2, + 2, 3, 2, 1, -2, 5, 12, 6, 3, 2, -3, 2, 3, 1, 8, 6, + 7, 2, -5, -3, 1, 5, 2, 0, -3, 2, 7, 2, 0, -9, 0, 5, + 1, 3, 1, 4, 6, -5, -3, -2, 2, 6, 4, 6, 1, 2, 4, 4, + -2, 2, 5, 5, 7, 7, 2, 6, 0, 3, 0, -3, 8, 4, 4, 9, + -3, 2, 1, 1, 2, 1, 5, 5, 4, 6, 1, -6, -2, 3, 5, 6, + 4, 3, 4, 1, 2, -4, 0, 6, 2, 2, 4, 3, 5, -3, -2, -5, + -3, 5, 2, 1, 3, 1, -2, -3, -4, -6, 3, 5, 1, -2, 1, 2, + -2, -2, -2, -3, 3, 5, 3, 4, 2, 2, 1, 0, 1, 4, 9, 9, + 5, 2, 1, 6, 4, 4, 5, 5, 7, 8, 4, 5, 1, 2, 3, 1, + 1, 4, 2, 3, 0, -4, -7, -5, 0, -3, -3, -3, -5, 0, -8, -7, + -8, -5, -3, -6, -3, -4, -5, 0, -7, -4, -5, -3, 1, 1, -2, 1, + -2, 2, 0, 0, -2, 3, 5, 4, 5, 4, 2, 4, 2, 4, 5, 6, + 5, 6, 4, 4, 4, 4, 3, 4, 2, 4, 4, 2, -2, -2, 0, -3, + -3, -3, -4, -2, -7, -6, -7, -9, -7, -10, -9, -10, -10, -8, -11, -9, + -9, -12, -10, -13, -12, -7, -8, -6, -6, -9, -6, -5, -3, 0, 0, 1, + 1, 4, 3, 4, 8, 6, 8, 7, 6, 10, 9, 12, 12, 11, 12, 8, + 13, 10, 11, 10, 8, 9, 8, 6, 9, 4, 5, 0, -3, -5, -5, -6, + -7, -9, -12, -15, -17, -21, -18, -22, -21, -23, -25, -24, -27, -27, -26, -30, + -27, -27, -28, -20, -22, -19, -14, -15, -12, -10, -10, -2, 3, 4, 12, 12, + 14, 20, 17, 25, 27, 29, 33, 35, 35, 40, 38, 41, 39, 36, 38, 36, + 36, 38, 31, 33, 25, 21, 14, 8, 1, 2, 0, -3, -5, -15, -23, -28, + -40, -39, -43, -46, -43, -52, -53, -59, -66, -62, -69, -63, -64, -64, -50, -56, + -44, -45, -43, -38, -36, -31, -20, -8, 4, 12, 19, 18, 28, 31, 40, 52, + 57, 68, 73, 73, 77, 73, 81, 79, 82, 82, 77, 82, 77, 75, 69, 59, + 53, 42, 33, 24, 22, 17, 11, 1, -17, -25, -36, -42, -46, -55, -60, -64, + -73, -77, -88, -90, -92, -97, -98, -100, -100, -92, -85, -79, -80, -76, -79, -69, + -56, -50, -32, -24, -15, 0, -2, 11, 15, 29, 45, 55, 67, 72, 82, 88, + 95, 101, 102, 109, 109, 112, 109, 110, 110, 106, 104, 91, 81, 77, 68, 66, + 54, 42, 32, 14, 6, -6, -12, -20, -29, -43, -55, -65, -76, -76, -85, -89, + -97, -105, -107, -114, -115, -117, -117, -113, -112, -104, -101, -91, -85, -84, -70, -72, + -55, -42, -34, -14, -8, 5, 16, 22, 35, 44, 57, 69, 78, 89, 94, 101, + 104, 109, 109, 119, 118, 117, 120, 110, 114, 114, 99, 102, 84, 74, 72, 57, + 52, 43, 32, 22, 10, -7, -20, -28, -34, -47, -54, -60, -67, -71, -80, -87, + -90, -105, -105, -110, -120, -115, -120, -123, -113, -111, -109, -97, -98, -92, -83, -82, + -76, -63, -61, -48, -39, -30, -16, -3, 10, 22, 32, 42, 49, 61, 67, 76, + 84, 91, 101, 105, 115, 116, 117, 125, 115, 119, 116, 106, 111, 102, 97, 92, + 84, 79, 70, 64, 50, 45, 31, 19, 14, -2, -9, -19, -30, -35, -47, -54, + -62, -67, -73, -82, -86, -96, -100, -105, -109, -116, -118, -120, -120, -117, -111, -110, + -97, -96, -90, -84, -78, -73, -64, -55, -50, -39, -25, -20, 1, 11, 19, 37, + 40, 51, 61, 68, 76, 85, 94, 97, 105, 114, 112, 120, 122, 119, 121, 117, + 110, 106, 105, 92, 90, 84, 69, 71, 57, 48, 45, 29, 22, 14, -2, -9, + -22, -31, -40, -47, -59, -62, -68, -76, -80, -87, -97, -96, -111, -111, -116, -124, + -119, -123, -120, -109, -109, -98, -95, -93, -84, -81, -75, -66, -55, -51, -37, -28, + -16, 1, 12, 23, 39, 40, 55, 59, 68, 77, 86, 94, 103, 104, 116, 117, + 118, 125, 122, 117, 120, 107, 108, 104, 95, 92, 85, 72, 70, 60, 48, 43, + 29, 18, 10, -7, -12, -22, -30, -38, -49, -58, -63, -72, -75, -84, -90, -93, + -100, -110, -103, -121, -115, -115, -124, -110, -112, -111, -92, -98, -86, -81, -77, -69, + -61, -53, -48, -34, -27, -13, 1, 9, 28, 37, 45, 58, 59, 76, 78, 85, + 97, 98, 109, 114, 111, 123, 120, 119, 121, 116, 111, 110, 101, 93, 92, 79, + 73, 68, 55, 52, 40, 30, 21, 10, 0, -13, -23, -29, -41, -47, -58, -64, + -69, -75, -84, -89, -93, -103, -105, -110, -120, -115, -117, -128, -105, -114, -109, -88, + -102, -86, -76, -84, -64, -63, -56, -43, -37, -25, -10, 4, 11, 31, 36, 46, + 56, 58, 74, 78, 84, 100, 95, 110, 114, 110, 124, 120, 116, 121, 110, 105, + 108, 97, 96, 91, 79, 75, 66, 57, 51, 38, 29, 17, 5, -3, -13, -20, + -28, -40, -46, -55, -66, -68, -76, -85, -88, -97, -102, -106, -110, -117, -115, -120, + -122, -108, -117, -103, -98, -96, -86, -79, -77, -66, -59, -54, -46, -33, -31, -10, + -2, 11, 27, 36, 47, 58, 62, 74, 78, 86, 94, 96, 106, 109, 115, 120, + 118, 121, 119, 112, 114, 104, 98, 94, 85, 77, 72, 63, 56, 49, 37, 31, + 20, 6, -2, -15, -24, -33, -44, -50, -58, -63, -68, -76, -82, -89, -95, -105, + -105, -116, -118, -117, -126, -114, -111, -118, -92, -105, -92, -83, -88, -72, -71, -65, + -51, -50, -31, -25, -9, 2, 16, 29, 35, 50, 53, 67, 73, 75, 92, 88, + 104, 112, 108, 122, 117, 119, 123, 114, 116, 110, 104, 98, 94, 86, 80, 75, + 63, 59, 47, 36, 29, 13, 9, -5, -16, -21, -36, -40, -50, -61, -61, -73, + -77, -85, -93, -95, -103, -108, -117, -120, -118, -125, -117, -108, -116, -96, -98, -97, + -83, -82, -78, -66, -61, -54, -43, -32, -25, -2, 3, 16, 33, 36, 52, 56, + 66, 75, 78, 94, 91, 103, 113, 108, 122, 119, 119, 121, 116, 112, 110, 106, + 93, 96, 83, 76, 74, 59, 58, 47, 34, 28, 14, 6, -6, -17, -27, -36, + -44, -54, -61, -63, -70, -76, -86, -90, -99, -102, -108, -117, -115, -121, -123, -111, + -120, -102, -100, -101, -84, -91, -76, -74, -70, -54, -56, -41, -30, -20, -3, 8, + 23, 31, 46, 47, 59, 70, 71, 83, 89, 90, 108, 108, 115, 120, 121, 122, + 118, 118, 109, 110, 102, 93, 93, 82, 78, 72, 62, 57, 45, 37, 22, 15, + 4, -10, -18, -30, -36, -42, -54, -57, -63, -68, -77, -86, -91, -102, -103, -108, + -117, -114, -119, -117, -115, -110, -106, -100, -91, -99, -79, -81, -77, -59, -61, -50, + -36, -33, -16, -4, 10, 16, 35, 39, 48, 62, 64, 76, 85, 89, 98, 105, + 110, 113, 120, 119, 118, 123, 112, 111, 110, 100, 98, 93, 82, 78, 70, 58, + 54, 45, 30, 24, 12, 0, -7, -20, -28, -36, -45, -55, -61, -66, -73, -79, + -88, -93, -103, -105, -112, -119, -115, -124, -123, -109, -119, -103, -98, -102, -92, -84, + -83, -75, -62, -59, -50, -34, -34, -12, 1, 7, 26, 33, 42, 50, 62, 67, + 76, 88, 90, 101, 110, 108, 118, 121, 119, 122, 121, 111, 113, 110, 98, 98, + 91, 80, 78, 66, 58, 53, 40, 29, 20, 8, -4, -11, -22, -33, -37, -49, + -57, -61, -68, -77, -81, -90, -96, -101, -110, -112, -116, -120, -116, -121, -119, -104, + -111, -96, -91, -96, -79, -79, -76, -59, -57, -46, -33, -25, -14, 5, 11, 26, + 39, 42, 55, 61, 70, 81, 86, 94, 101, 105, 114, 116, 120, 121, 119, 119, + 115, 111, 107, 102, 94, 90, 82, 73, 68, 59, 50, 41, 28, 20, 7, -4, + -12, -22, -30, -41, -48, -56, -62, -69, -75, -83, -90, -98, -100, -107, -111, -119, + -112, -124, -120, -107, -119, -101, -93, -104, -80, -85, -83, -61, -65, -55, -40, -38, + -25, -7, -3, 13, 29, 34, 45, 57, 59, 74, 79, 87, 98, 98, 108, 111, + 112, 122, 117, 119, 119, 111, 110, 107, 96, 96, 89, 76, 74, 63, 54, 51, + 35, 27, 19, 5, -3, -12, -25, -29, -43, -52, -58, -64, -71, -78, -82, -92, + -98, -101, -108, -110, -114, -120, -119, -118, -115, -110, -106, -95, -97, -82, -84, -76, + -62, -63, -51, -42, -39, -20, -12, 2, 15, 29, 36, 47, 58, 62, 74, 80, + 85, 95, 101, 106, 111, 116, 118, 117, 122, 113, 115, 111, 99, 103, 90, 85, + 80, 68, 63, 56, 46, 36, 28, 17, 5, -5, -19, -25, -35, -43, -52, -58, + -62, -72, -75, -83, -94, -94, -105, -105, -115, -115, -116, -122, -114, -112, -108, -98, + -99, -89, -86, -82, -72, -69, -58, -52, -44, -31, -21, -6, 4, 17, 28, 39, + 48, 53, 66, 72, 80, 88, 92, 104, 108, 113, 116, 119, 121, 116, 119, 112, + 108, 107, 94, 94, 85, 79, 72, 62, 57, 48, 37, 25, 17, 8, -8, -15, + -26, -35, -42, -55, -59, -65, -73, -75, -87, -89, -97, -104, -109, -116, -116, -121, + -120, -120, -109, -108, -103, -90, -97, -78, -78, -77, -60, -64, -50, -41, -34, -16, + -7, 9, 19, 33, 42, 52, 60, 65, 77, 79, 87, 96, 99, 109, 113, 118, + 124, 117, 121, 117, 109, 110, 99, 94, 93, 83, 77, 73, 63, 55, 50, 32, + 26, 18, 0, -6, -20, -29, -34, -49, -53, -57, -63, -71, -76, -83, -91, -97, + -108, -112, -114, -122, -115, -124, -112, -105, -112, -89, -99, -90, -78, -89, -72, -66, + -61, -49, -41, -28, -16, 2, 6, 25, 35, 36, 53, 54, 67, 77, 79, 93, + 97, 105, 112, 111, 122, 118, 119, 117, 112, 109, 108, 99, 95, 92, 82, 76, + 71, 59, 56, 43, 30, 24, 10, 0, -9, -18, -26, -36, -45, -55, -59, -68, + -75, -81, -88, -94, -99, -106, -109, -110, -119, -117, -119, -116, -111, -105, -101, -91, + -92, -83, -75, -75, -61, -52, -52, -35, -29, -18, 0, 9, 22, 36, 41, 51, + 64, 68, 78, 88, 90, 101, 103, 109, 113, 115, 121, 117, 118, 116, 109, 109, + 102, 94, 90, 80, 71, 67, 57, 47, 42, 30, 19, 14, -4, -9, -19, -31, + -36, -50, -55, -61, -68, -74, -79, -87, -93, -101, -107, -107, -115, -118, -118, -123, + -112, -110, -109, -92, -93, -94, -74, -83, -71, -57, -61, -45, -34, -31, -10, 0, + 12, 27, 37, 42, 55, 61, 70, 77, 87, 95, 96, 106, 112, 113, 123, 122, + 117, 122, 112, 109, 110, 96, 96, 92, 76, 74, 68, 55, 50, 40, 28, 20, + 7, -6, -10, -23, -31, -42, -51, -59, -65, -70, -76, -82, -88, -92, -104, -104, + -105, -122, -113, -122, -126, -106, -119, -103, -91, -99, -82, -80, -76, -66, -59, -54, + -46, -34, -30, -9, 1, 13, 33, 34, 51, 57, 63, 76, 77, 91, 95, 95, + 110, 108, 115, 122, 120, 120, 123, 112, 110, 110, 94, 95, 87, 70, 74, 62, + 55, 50, 39, 29, 20, 7, -5, -13, -26, -35, -44, -56, -61, -65, -69, -75, + -83, -86, -98, -104, -104, -121, -115, -119, -128, -110, -117, -116, -92, -100, -90, -78, + -83, -75, -63, -64, -55, -41, -39, -20, -7, 1, 21, 31, 40, 51, 55, 67, + 72, 77, 91, 93, 99, 110, 109, 118, 125, 118, 124, 119, 108, 114, 101, 93, + 96, 81, 75, 73, 59, 57, 48, 35, 27, 15, 1, -7, -20, -29, -37, -49, + -56, -61, -65, -69, -74, -83, -91, -98, -107, -113, -117, -120, -122, -118, -115, -111, + -103, -101, -92, -89, -85, -80, -77, -65, -61, -51, -41, -33, -16, -4, 8, 21, + 34, 40, 49, 57, 63, 73, 82, 89, 98, 104, 109, 117, 118, 123, 122, 119, + 116, 110, 108, 100, 97, 93, 83, 80, 70, 64, 55, 45, 34, 22, 12, -2, + -10, -20, -30, -35, -48, -55, -62, -67, -71, -78, -86, -91, -101, -104, -110, -117, + -117, -120, -123, -111, -111, -110, -90, -99, -90, -76, -85, -71, -58, -63, -45, -37, + -33, -14, 1, 4, 27, 34, 41, 53, 59, 66, 79, 84, 92, 100, 103, 110, + 115, 116, 123, 118, 118, 117, 107, 110, 101, 95, 93, 79, 76, 68, 57, 52, + 43, 30, 23, 11, -3, -8, -20, -30, -34, -48, -55, -60, -69, -74, -81, -89, + -92, -101, -105, -108, -114, -117, -118, -122, -112, -113, -108, -95, -101, -87, -82, -83, + -68, -60, -56, -45, -38, -28, -17, -2, 6, 23, 33, 40, 54, 60, 68, 80, + 85, 94, 96, 103, 109, 110, 119, 118, 118, 121, 113, 112, 110, 100, 98, 90, + 77, 73, 66, 55, 51, 41, 29, 25, 8, 1, -9, -23, -28, -42, -51, -59, + -64, -67, -75, -79, -86, -94, -98, -105, -111, -115, -117, -121, -123, -111, -120, -102, + -95, -100, -79, -84, -81, -61, -69, -55, -46, -42, -27, -14, -3, 11, 30, 35, + 49, 57, 60, 76, 76, 86, 95, 95, 109, 108, 116, 122, 121, 123, 120, 116, + 114, 106, 100, 94, 88, 78, 73, 65, 59, 52, 38, 33, 20, 10, -2, -15, + -22, -32, -42, -51, -58, -62, -67, -77, -80, -86, -94, -100, -106, -113, -115, -119, + -122, -118, -117, -107, -106, -98, -89, -89, -78, -76, -71, -57, -56, -46, -36, -25, + -12, 0, 16, 26, 39, 49, 54, 67, 72, 80, 88, 94, 101, 104, 115, 113, + 121, 125, 116, 123, 116, 110, 109, 98, 93, 88, 78, 69, 65, 56, 47, 42, + 27, 20, 8, -6, -15, -27, -33, -43, -53, -58, -64, -68, -74, -86, -87, -96, + -106, -103, -117, -116, -117, -123, -117, -106, -114, -97, -96, -96, -81, -81, -80, -62, + -64, -49, -45, -34, -19, -8, 4, 17, 28, 40, 47, 54, 66, 73, 79, 93, + 95, 102, 113, 110, 117, 123, 119, 121, 117, 113, 111, 106, 96, 95, 88, 78, + 72, 63, 55, 47, 35, 26, 14, 4, -9, -19, -24, -35, -43, -51, -61, -65, + -72, -79, -88, -88, -99, -107, -107, -120, -114, -120, -122, -113, -116, -102, -106, -95, + -89, -95, -72, -80, -70, -50, -58, -37, -30, -20, -5, 6, 18, 29, 44, 45, + 57, 72, 68, 89, 89, 97, 109, 104, 120, 113, 118, 124, 112, 120, 112, 107, + 106, 96, 91, 87, 78, 66, 65, 52, 40, 39, 17, 17, 4, -13, -13, -30, + -35, -44, -58, -59, -66, -72, -78, -85, -93, -97, -106, -114, -110, -120, -120, -118, + -120, -109, -110, -98, -100, -89, -81, -87, -68, -68, -59, -44, -46, -29, -18, -5, + 5, 22, 32, 39, 54, 56, 68, 79, 79, 94, 98, 102, 110, 112, 117, 119, + 124, 117, 116, 116, 104, 106, 97, 89, 86, 74, 67, 60, 53, 41, 34, 24, + 12, 4, -9, -19, -28, -38, -47, -58, -60, -68, -73, -77, -88, -93, -96, -111, + -109, -115, -124, -118, -122, -120, -107, -109, -102, -91, -95, -82, -78, -78, -60, -59, + -51, -36, -35, -14, -3, 6, 24, 34, 41, 56, 59, 67, 81, 82, 92, 103, + 102, 112, 119, 114, 123, 123, 116, 121, 112, 106, 107, 93, 91, 84, 74, 69, + 61, 52, 43, 32, 21, 13, -2, -10, -22, -31, -38, -51, -56, -59, -69, -71, + -76, -87, -90, -100, -107, -110, -119, -118, -120, -123, -108, -118, -101, -92, -102, -77, + -85, -83, -63, -71, -58, -45, -44, -27, -15, -2, 10, 30, 32, 46, 57, 56, + 74, 73, 84, 93, 95, 109, 108, 117, 117, 124, 119, 119, 119, 112, 109, 100, + 96, 90, 81, 75, 65, 59, 51, 41, 33, 22, 12, 0, -12, -23, -30, -40, + -51, -57, -64, -71, -73, -83, -84, -95, -102, -102, -116, -117, -118, -128, -116, -114, + -116, -102, -99, -95, -86, -80, -80, -71, -58, -61, -46, -38, -30, -10, -4, 12, + 26, 37, 47, 54, 67, 68, 79, 89, 86, 104, 104, 111, 118, 118, 123, 121, + 119, 116, 112, 109, 99, 96, 88, 80, 75, 66, 58, 49, 41, 29, 19, 10, + -5, -10, -25, -35, -39, -53, -58, -64, -69, -75, -81, -87, -100, -99, -112, -116, + -118, -126, -123, -115, -120, -111, -102, -100, -93, -86, -85, -76, -69, -64, -56, -47, + -38, -25, -10, 4, 16, 31, 40, 46, 61, 65, 70, 83, 86, 93, 103, 105, + 114, 125, 118, 124, 125, 112, 120, 111, 98, 103, 91, 86, 83, 71, 66, 61, + 49, 38, 32, 16, 7, -4, -17, -26, -36, -44, -54, -60, -59, -71, -75, -79, + -94, -95, -103, -117, -112, -120, -127, -120, -118, -117, -104, -102, -99, -88, -84, -86, + -73, -70, -64, -51, -47, -37, -17, -10, 7, 19, 32, 40, 52, 56, 67, 73, + 80, 87, 92, 103, 109, 110, 123, 119, 121, 126, 111, 113, 112, 98, 98, 91, + 80, 80, 71, 60, 61, 47, 36, 30, 13, 5, -5, -19, -27, -35, -43, -52, + -58, -62, -71, -76, -84, -96, -100, -105, -118, -115, -121, -123, -121, -114, -117, -110, + -98, -105, -91, -83, -90, -71, -68, -64, -48, -43, -33, -17, -5, 3, 23, 32, + 38, 54, 59, 66, 79, 82, 92, 100, 105, 108, 116, 119, 117, 126, 116, 115, + 118, 106, 105, 99, 91, 85, 78, 67, 60, 54, 41, 33, 24, 11, 0, 3, + 10, 14, -8, 46, 7, -20, -23, -28, 17, 9, 47, -7, -15, -35, -1, -26, + 44, 34, -31, 31, -47, -32, 30, -2, 32, 15, -15, -17, -39, 16, -2, 26, + 23, 3, -43, 11, -37, 14, 37, 7, 4, -21, -30, -9, 14, 18, 38, -13, + -16, -21, -24, 8, 38, 3, 16, -29, -11, -26, 20, 15, 24, -9, 0, -34, + -21, 32, -16, 41, -1, -20, -7, -7, -7, 27, 0, -2, -2, -11, -11, 19, + -16, 32, -19, -4, 11, -40, 49, -13, -12, 12, -32, 12, 17, 1, 23, -34, + -20, 14, -20, 33, 44, -51, 7, -21, -38, 46, 19, 37, -28, -29, -17, -40, + 63, 36, -33, 42, -45, -57, 16, 37, -3, 54, 0, -64, -25, -7, 15, 37, + 34, -2, -65, -12, -3, -7, 76, -2, -6, -28, -22, -30, 40, 11, 12, 21, + -43, -6, -1, -31, 73, -35, 33, -1, -67, 29, -24, 16, 42, 4, -26, 17, + -71, 32, 0, 0, 72, -56, 4, -2, -75, 76, -25, 39, 24, -42, -6, -20, + -31, 56, 1, 3, 49, -63, -12, -16, -10, 49, 12, 29, -32, -59, 35, -39, + 35, 45, -33, -21, 46, -68, 13, 16, 12, 0, 2, 32, -70, 12, 30, -62, + 64, 5, -31, 22, -30, 11, -30, 43, 2, -8, 16, -3, -60, 39, -11, -13, + 63, -32, 8, -6, -45, 39, -38, 30, 49, -89, 96, -84, 0, 43, -51, 52, + -4, -6, 7, -31, -10, 12, -22, 62, 8, -57, 65, -101, 1, 69, -46, 76, + -18, -34, -24, -33, 50, -6, 55, 16, -70, -19, 2, -33, 59, 61, -40, 7, + -44, -33, -7, 61, 31, -15, 5, -32, -70, 47, 34, 8, 22, -16, -44, -47, + 56, -6, 12, 56, -46, -32, -3, 7, -4, 42, 19, -41, -35, 41, -59, 43, + 45, -44, 9, -9, -7, -19, 36, 2, -50, 49, -6, -34, 33, -1, -38, 17, + 44, -33, 5, 28, -68, -13, 62, -25, 15, 45, -57, -32, 23, -14, 37, 11, + 29, -56, -48, 46, -55, 48, 94, -74, 22, -40, -59, 36, 9, 75, -19, -31, + 6, -104, 39, 80, -23, 59, -12, -104, 10, -12, 24, 59, 5, 9, -78, -12, + 24, -47, 116, -6, -51, 34, -71, -26, 55, 3, 11, 38, -31, -9, -45, 21, + -11, 4, 92, -79, 16, -16, -41, 29, 27, 19, -5, -19, -13, -35, 29, 22, + -7, 20, -35, 6, -21, 30, -2, 6, -8, -20, -12, 30, -13, 8, 23, -52, + 21, 8, -16, 40, -20, -7, -15, -38, 62, -33, 48, 5, -66, 28, -25, 15, + 39, 5, -46, 8, -46, 32, 12, 37, -9, -49, 43, -78, 43, 46, -43, 39, + -41, -36, 13, 19, 48, -21, 9, -37, -54, 45, 32, -14, 41, -32, -66, 42, + -8, 37, 12, -10, -12, -74, 71, -30, 16, 65, -64, -1, -13, -12, 17, 24, + 10, -16, -31, -1, -3, 1, 68, -47, -7, -8, -41, 74, -16, 32, -27, -42, + 22, -49, 80, -11, 0, 23, -84, 34, -24, 31, 48, -37, 23, -55, -25, 22, + 14, 22, 59, -78, -11, -1, -45, 90, -35, 32, 0, -75, 63, -65, 34, 52, + -71, 70, -56, -14, 30, -22, 10, 55, -74, 41, -19, -47, 88, -62, 50, -11, + -57, 44, -54, 59, 17, -23, 12, -40, -41, 60, 3, 15, 28, -71, -1, -17, + 11, 61, -28, 47, -59, -48, 35, -18, 51, 27, -20, -35, -36, 14, 6, 44, + 23, -30, -33, -17, -1, 14, 49, -2, -32, -12, -20, 5, 29, 34, -33, 9, + -34, -26, 36, -2, 40, -28, 5, -26, -39, 65, -27, 19, 31, -54, 0, -8, + 12, 2, 30, -5, -25, -22, 24, -29, 26, 52, -57, 7, 5, -56, 46, 1, + 8, 4, -5, 1, -51, 28, 14, -21, 48, -17, -46, 4, 11, -6, 35, 7, + -16, -31, -10, 25, -49, 95, -28, -29, 19, -46, -5, 32, 21, 8, -1, -24, + -36, -17, 59, -7, 33, 10, -76, -14, 19, -1, 56, 16, -23, -64, -8, 7, + 8, 85, 0, -57, -21, -35, -7, 72, 23, 28, -66, -16, -47, 2, 68, 24, + 5, 0, -69, -26, 22, -7, 72, 0, -12, -20, -51, 15, -11, 44, 44, -46, + 36, -59, -38, 32, 19, -3, 71, -45, -28, -29, -17, 36, 8, 79, -47, -53, + 18, -65, 38, 75, -24, 20, -36, -34, -26, 38, 39, -7, -3, 7, -85, 44, + 26, -17, 42, -20, -29, -26, 26, 18, -8, 36, -17, -73, 40, 4, -1, 52, + -16, -47, -15, 14, 4, 29, 30, -41, -44, 15, -2, 16, 60, -26, -54, 17, + -33, 22, 48, -5, -15, -20, -13, -15, 31, 37, -28, 6, -17, -22, -10, 64, + -43, 16, 22, -71, 41, 3, -1, 6, -12, 12, -38, 11, 38, -49, 37, 24, + -64, 27, 18, -73, 81, -33, 14, -3, -32, 43, -60, 53, 24, -76, 70, -29, + -33, 50, -18, -34, 48, -38, 37, -15, -5, 25, -80, 70, -4, -45, 89, -72, + -3, 13, -23, 28, 21, -9, -9, -25, -11, 24, -26, 62, -14, -49, 67, -97, + 57, 12, -23, 46, -46, 9, -20, -4, 25, -1, 5, 18, -31, -25, 38, -43, + 44, 17, -42, 37, -66, 37, -16, 26, 18, -16, -17, -4, -17, 7, 38, -11, + 4, -3, -51, 32, -17, 38, 18, -34, 23, -58, 4, 25, 0, 26, 3, -35, + -11, -10, 16, 24, 8, 4, -33, -30, 22, -2, 14, 52, -61, 10, -23, -4, + 20, 10, 32, -44, -2, 1, -36, 37, 32, -25, 2, 0, -40, 14, 24, -5, + 13, -28, 20, -51, 41, 15, -23, 25, -12, -41, 30, -2, -11, 40, -34, 14, + -24, 3, 22, -31, 44, -22, -31, 57, -55, 28, 0, -9, 1, 11, -10, 8, + -13, 3, -2, -23, 60, -49, 23, 10, -59, 36, -3, -3, 35, -23, 5, -42, + 15, 7, -2, 35, 0, -45, 8, -4, -27, 63, -4, -14, 9, -39, 1, 1, + 27, 19, -27, 24, -49, -6, 34, -5, 10, 19, -32, -20, 14, -12, 16, 26, + -9, -19, -9, -8, 8, 7, 40, -29, -14, -4, -25, 7, 56, -15, 6, -20, + -36, 3, 10, 33, 20, -23, -5, -42, -18, 54, -17, 63, -5, -59, 2, -44, + 12, 57, 17, 15, -33, -44, -16, -17, 65, 40, -9, 10, -72, -51, 39, 10, + 65, 19, -25, -47, -51, 17, 20, 53, 30, -35, -35, -34, -16, 36, 48, 12, + -3, -35, -42, -9, 28, 34, 12, 15, -42, -39, 7, 8, 24, 28, 1, -31, + -36, 9, -1, 28, 29, -14, -34, 14, -43, 23, 34, -7, 24, -44, 10, -28, + -5, 53, -29, 29, -7, -33, 2, -1, 5, 19, 10, -17, 2, -33, 14, 1, + 8, 32, -36, 17, -28, -18, 36, -22, 29, 2, -25, 5, -17, 13, 1, 16, + -1, -10, -12, 3, -9, 10, 19, -22, 16, -3, -20, 24, -22, 15, -3, -14, + 22, -30, 31, -14, -11, 12, -11, 8, 17, -9, -4, -13, -13, 7, 10, 19, + -6, -7, -2, -32, 24, 8, 0, 17, -20, -10, -15, 13, 10, 11, 4, -1, + -40, 19, -4, -6, 42, -31, -1, -5, -12, 19, 6, 7, -5, -26, 10, -12, + 15, 20, -8, -19, 12, -40, 31, 15, -3, 16, -23, -27, 7, -5, 31, 6, + 3, -6, -41, 14, -2, 7, 38, -10, -29, 11, -44, 17, 29, 6, 20, -26, + 1, -45, 9, 31, -18, 40, -1, -47, 8, -10, -4, 29, 33, -25, 1, -31, + -12, -9, 35, 30, -25, 31, -48, -28, 20, 17, 9, 30, -19, -39, -13, 6, + 8, 38, 15, -10, -42, 0, -24, 15, 49, -9, -12, 5, -44, -5, 42, 4, + 6, 8, -27, -29, 5, 24, -2, 10, 28, -56, 1, 23, -29, 29, 15, -19, + -11, 1, -4, -8, 24, 6, -15, 2, 7, -27, 12, 21, -40, 36, -15, -12, + 22, -16, 17, -17, 15, -6, -18, 23, -3, -26, 39, -27, -5, 26, -20, 8, + 5, -11, 7, -21, 19, -11, -8, 35, -25, 2, 18, -35, 9, 16, -21, 29, + -16, 1, -13, -13, 28, -18, 23, 13, -36, 6, -1, -23, 26, 12, -15, 17, + -20, -2, -7, 3, 22, -22, 27, -11, -34, 36, -30, 11, 17, 2, -12, 13, + -22, -11, 11, -5, 26, -17, 26, -25, -32, 44, -47, 39, 25, -31, 16, -35, + -1, -4, 26, 16, 3, -16, -10, -23, -8, 55, -27, 26, 0, -63, 41, -26, + 28, 22, -23, 14, -42, 5, 20, -13, 28, 3, -42, 20, -6, -17, 52, -32, + 6, -2, -37, 42, -27, 29, 15, -51, 40, -38, 2, 33, -19, 6, 11, -43, + 25, 0, -19, 57, -54, 31, -9, -43, 58, -52, 36, 11, -44, 50, -44, 8, + 23, -24, 12, 6, -34, 25, -9, -15, 50, -55, 35, -7, -25, 49, -48, 32, + -23, -18, 37, -30, 28, 8, -27, 7, -2, -19, 22, 10, -11, 10, -27, 4, + -16, 18, 29, -19, 20, -22, -36, 16, -2, 18, 14, 3, -24, -15, -5, 12, + 13, 20, 4, -40, 2, -23, 8, 29, 7, 9, -23, -10, -13, 5, 19, 9, + -3, -14, -7, -19, 21, 6, 5, 10, -20, 0, -14, 12, 0, 2, 5, -13, + 1, -3, 12, -12, 20, -13, -7, 6, -11, 5, 0, 5, -5, -4, 10, -10, + 2, 6, -5, -12, 18, -13, -9, 19, -17, 11, -1, 8, -5, -22, 26, -26, + 1, 29, -17, -7, 16, -22, -8, 23, -3, 4, -3, -2, -15, -20, 42, -21, + 4, 40, -55, 8, 8, -22, 21, 20, -17, 2, -14, -7, -2, 10, 31, -25, + 10, -3, -54, 40, 5, -12, 42, -17, -37, 13, -12, 7, 24, 10, -6, -36, + 12, -9, -25, 74, -24, -19, 38, -64, 5, 25, 0, 16, 1, -9, -25, -23, + 36, -8, 6, 50, -58, -12, 22, -53, 52, 18, -12, 16, -51, 15, -30, 25, + 46, -37, 31, -26, -49, 30, 9, -1, 42, -19, -28, -13, -5, 16, 4, 42, + -18, -40, 20, -30, 1, 49, -4, -15, 0, -21, -19, 21, 26, 0, -9, 9, + -43, -1, 26, -5, 21, -7, -6, -32, 9, 12, -3, 34, -17, -12, -17, -4, + 9, 7, 28, -19, -3, -13, -11, 7, 15, 15, -19, 15, -38, -5, 17, -1, + 29, -20, 15, -39, -11, 41, -33, 45, -8, -21, -11, -3, 7, 0, 28, -7, + -19, -8, 7, -20, 23, 24, -40, 24, -17, -16, 26, -9, 21, -27, 13, -11, + -22, 29, -7, 0, 22, -22, -16, 14, -12, 12, 11, -5, -6, -17, 14, -15, + 9, 30, -28, 5, 1, -26, 8, 18, -7, 1, 6, -12, -15, 9, 13, -13, + 13, 13, -42, 14, 3, -16, 20, 7, -3, -22, 25, -26, 4, 16, -7, 3, + -8, 17, -33, 14, 9, -21, 25, -3, -11, -1, 1, -13, 1, 23, -20, 26, + -18, 0, -18, 3, 24, -25, 36, -15, -29, 22, -22, 3, 24, -5, -1, 0, + -18, 2, -11, 20, 10, -17, 30, -37, -15, 29, -33, 39, 11, -23, 7, -34, + 8, 0, 11, 36, -27, -12, 9, -47, 29, 31, -29, 40, -37, -14, 3, -17, + 45, -11, 8, 12, -60, 20, -2, -2, 41, -12, -18, 3, -37, 27, 12, -4, + 37, -56, 17, -21, -5, 44, -20, 14, -2, -40, 20, 0, 3, 22, -13, -10, + -6, -16, 29, -12, 14, 15, -49, 24, -11, -7, 39, -18, 3, -20, -12, 19, + -10, 32, 2, -34, 10, -13, -13, 37, 1, -7, 3, -33, 4, 2, 18, 25, + -25, 8, -33, -13, 34, -7, 24, 4, -33, -10, -2, 2, 25, 12, -1, -25, + -12, 3, -18, 34, 12, -15, 4, -9, -25, 10, 17, -3, 9, 2, -13, -23, + 9, 8, -13, 37, -10, -15, 1, -13, -1, 0, 31, -15, 0, 5, -29, 6, + 5, 15, -9, 16, -9, -29, 15, -10, 3, 15, 9, -11, -12, 11, -29, 17, + 14, -7, 6, -6, -7, -24, 30, -11, 9, 18, -20, -8, -6, 6, -10, 22, + 10, -29, 14, -13, -8, 13, 17, -13, 2, 1, -24, 5, 5, 12, -10, 15, + -7, -28, 21, -2, -8, 22, -9, -14, -2, 6, -5, 5, 12, -7, -15, 14, + -4, -16, 27, -10, -14, 13, -5, -9, 10, 5, -8, -5, 16, -20, 2, 13, + -14, -3, 17, -18, 2, 10, -12, 9, -6, -2, -16, 13, 10, -15, 33, -24, + -17, 10, -4, 15, 1, 9, -23, -9, 6, -5, 5, 21, -10, -13, 11, -21, + -2, 19, -10, 23, -20, 10, -16, -21, 33, -17, 17, 18, -30, 1, -14, -1, + 20, -2, 18, -15, -24, 6, -5, 6, 36, -26, 6, -18, -23, 34, -12, 25, + 1, -30, -1, -11, 10, 22, -1, 4, -19, -28, 21, -11, 22, 25, -33, 4, + -21, -7, 22, 7, 19, -23, -13, -3, -13, 21, 17, -11, 7, -19, -12, 12, + -10, 30, -13, -5, 4, -30, 27, -9, 17, -3, -25, 13, -23, 13, 27, -15, + -5, 3, -35, 17, 19, -8, 29, -37, 1, -15, -10, 48, -20, 26, -7, -49, + 22, -23, 21, 33, -10, -8, -17, -34, 11, 19, 12, 40, -39, -14, -13, -36, + 64, -4, 20, 9, -55, 3, -24, 21, 31, 10, -1, -22, -30, -7, 12, 18, + 29, -10, -7, -28, -22, 22, 3, 26, 4, -13, -18, -16, 21, -9, 28, -1, + -21, 0, -12, 5, 6, 5, 10, -20, 1, 3, -20, 21, 7, -23, 24, -25, + -6, 21, -13, 25, -19, -8, 2, -14, 20, 13, -23, 25, -31, -7, 24, -16, + 20, 6, -25, 8, -24, 12, 15, -10, 24, -25, -2, 0, -12, 14, 10, -13, + 4, 1, -17, 9, 6, -9, 9, 0, -3, -8, 11, -10, -2, 7, -1, -6, + 6, 1, -12, 1, 18, -31, 23, -2, -21, 21, -6, -8, 15, -14, 4, -6, + -1, 17, -22, 20, -6, -35, 37, -17, -6, 47, -41, 6, -6, -16, 12, 16, + 6, 1, -36, 18, -26, 4, 59, -36, -1, 16, -64, 30, 14, 1, 16, -13, + 0, -35, 17, 13, -8, 12, 14, -45, 11, 12, -24, 27, 12, -27, 10, -6, + -9, 1, 14, -7, -6, 8, -4, -8, 8, 8, -24, 13, 7, -27, 28, -1, + -28, 27, -19, -2, 17, -5, 6, -10, -5, 4, -25, 32, 2, -22, 32, -28, + -20, 35, -20, 16, 7, -18, 1, -22, 20, 0, 2, 20, -15, -25, 24, -25, + 12, 25, -23, 10, -19, -5, 8, 2, 20, -6, -13, 0, -22, 12, 15, -3, + 13, -13, -25, 12, -6, 18, 13, -3, -14, -22, 3, -2, 14, 25, -10, -16, + -5, -13, 2, 22, 9, -2, -11, -12, -20, 15, 20, 1, 14, -19, -17, -9, + 1, 19, 5, 0, 4, -35, 17, -7, 5, 20, -16, 2, -8, -11, 11, -2, + 2, 7, -19, 15, -10, 2, 12, -14, -3, 2, -9, 17, -3, 2, -7, -16, + 10, 2, 9, 10, -14, -9, -6, -11, 21, 5, 4, 6, -24, -5, -4, 6, + 18, 0, 8, -21, -18, 8, -8, 21, 16, -11, -9, -12, -15, 15, 3, 27, + -9, -16, 5, -30, 13, 23, -11, 21, -19, -15, -3, -9, 30, -9, 14, -6, + -22, -5, 15, -11, 23, -1, -14, -4, -9, 8, 4, 1, 20, -34, 9, 1, + -17, 24, -6, 1, -9, 1, -4, 3, 6, 8, -16, 0, 2, -13, 11, 21, + -31, 24, -21, -4, 13, -2, 7, -9, -3, 0, -18, 29, -4, -9, 16, -19, + -13, 25, -5, -1, 15, -24, 4, -15, 22, 4, -11, 20, -21, -25, 39, -23, + 14, 14, -23, 1, -8, 3, 12, -9, 23, -19, -18, 24, -22, 5, 30, -32, + 11, 2, -21, 18, -6, 5, 1, -9, 13, -22, 4, 19, -28, 26, 3, -28, + 21, -4, -25, 32, -15, 5, 0, -2, -4, -9, 15, 0, -13, 21, -14, -20, + 31, -19, 2, 17, -14, -9, 12, -6, 4, -1, 4, -17, -1, 12, -2, 0, + 20, -31, -8, 12, -8, 17, 14, -13, -16, -9, -7, 20, 11, 18, -13, -28, + -3, -12, 13, 40, -12, 4, -20, -32, 8, 17, 14, 21, -10, -28, -18, -2, + 11, 22, 17, 0, -34, -6, -3, -17, 50, 1, -13, 4, -22, -21, 17, 16, + 4, 7, 0, -27, -11, 4, 10, 2, 24, -6, -28, 7, -12, -2, 33, -3, + -6, 2, -37, 3, 9, 7, 24, -4, -14, -6, -24, 25, -1, 11, 16, -36, + -9, 12, -25, 45, 5, -20, 11, -36, 11, 7, 0, 30, -32, -1, 7, -33, + 37, 0, -9, 15, -21, -10, 12, -15, 24, -8, 3, 4, -20, 7, 3, -15, + 28, -14, -7, 13, -23, 2, 11, 0, 4, 7, -9, -16, 1, 7, -7, 19, + -3, -12, -14, 15, -10, 7, 30, -26, -13, 15, -30, 15, 26, -12, -1, -8, + -9, -5, 13, 22, -12, -12, 7, -36, 17, 31, -24, 27, -21, -24, 15, -10, + 26, 4, -12, 4, -36, 13, 14, -5, 27, -14, -22, 7, -12, 6, 23, -13, + 7, -19, -2, 7, -8, 25, -5, -17, 18, -25, 3, 14, -8, 4, 0, -1, + -11, 4, 12, -18, 15, 2, -23, 12, -2, -7, 12, 1, -1, -15, 11, -3, + -17, 41, -24, -7, 13, -25, 3, 22, -9, 15, -12, -9, 0, -17, 32, -5, + -5, 19, -49, 19, 3, -11, 45, -30, 2, -4, -28, 29, 0, 7, 12, -34, + 6, -10, 1, 33, -9, -6, 4, -41, 25, 2, 4, 29, -40, 8, -17, -9, + 42, -16, 16, -10, -33, 11, -7, 22, 12, -6, -6, -25, -4, 18, -3, 25, + -4, -29, 5, -17, 8, 22, 1, 4, -22, 1, -13, 2, 31, -19, 9, 2, + -36, 17, 5, -7, 20, -11, -2, -13, 4, 9, -18, 24, -3, -30, 33, -19, + -11, 31, -21, 6, 0, -5, 3, -10, 17, -7, -19, 30, -24, 0, 26, -23, + 3, 7, -17, 9, -3, 9, -1, -17, 23, -25, -3, 34, -27, 10, 15, -34, + 9, 1, 1, 7, -1, 12, -31, 4, 16, -27, 32, 10, -33, 10, -1, -27, + 29, 9, -9, 0, -1, -16, -6, 24, 2, -17, 23, -20, -24, 33, -11, -2, + 17, -7, -21, 13, 1, -7, 10, 1, -12, -9, 13, -1, -5, 20, -16, -15, + 15, -8, 5, 13, -10, -7, -9, 5, 2, 10, 7, -7, -22, 12, -13, 6, + 26, -14, -6, 0, -17, 3, 16, 6, 0, -11, 3, -26, 13, 15, -6, 7, + 4, -29, 6, 7, -3, 13, 1, -11, -9, 2, -1, 3, 9, -3, -8, 1, + -4, 0, 5, 0, 0, -2, 0, -1, 0, 0, -2, 11, 23, 22, 24, 25, + 20, 21, 15, 40, -1, -24, -42, -5, -19, -11, -8, 4, -46, -31, -14, -33, + -40, -44, -48, -89, -63, -47, -33, -27, -10, -6, 22, 25, 26, 28, 37, 11, + 15, 51, 44, 54, 66, 66, 71, 111, 84, 70, 63, 47, 39, 22, 47, -28, + -79, -111, -90, -91, -112, -81, -87, -49, -46, -5, -24, 26, 24, 47, 29, 23, + 30, 30, 13, -1, 4, -14, 17, 35, 62, 31, 53, 59, 72, 64, 27, 26, + 9, 9, -61, -44, -88, -74, -81, -83, -124, -96, -37, -78, -48, -56, -68, -60, + 7, 44, 39, 54, 77, 102, 110, 108, 89, 101, 100, 105, 64, 22, -1, 44, + 40, -19, -29, -35, -16, -27, -40, -77, -82, -113, -104, -93, -57, -72, -56, -3, + 1, 7, -1, 49, 39, 30, 31, 23, 10, 31, 11, 7, -19, -2, -2, 28, + 62, 92, 75, 33, 34, -20, -47, -61, -85, -105, -93, -119, -112, -54, -70, -67, + -32, -1, 4, 4, 20, 29, 62, 70, 54, 62, 78, 115, 92, 85, 78, 52, + 21, 19, 27, 2, -8, 13, 0, 5, 3, 9, 18, 0, -59, -61, -45, -57, + -65, -76, -89, -102, -48, -24, 17, 6, 26, 33, 35, 26, 41, 63, 20, 12, + 29, 34, 8, 7, 31, 21, 31, 39, 33, -5, -8, -55, -57, -98, -94, -88, + -64, -82, -74, -39, -14, 3, 16, 22, 8, 2, 17, 5, 36, 76, 74, 71, + 57, 73, 62, 47, 30, 32, 19, 4, 7, -14, -18, -2, 17, -5, 13, 22, + 31, 10, 8, -13, -47, -80, -85, -86, -71, -73, -60, -35, -10, 9, 19, 49, + 53, 47, 60, 73, 43, 33, 20, 13, -1, -7, -7, 7, 9, -2, 5, -14, + -40, -69, -61, -66, -67, -84, -58, -58, -33, 2, -7, -5, 12, 32, 18, 25, + 19, 24, 65, 59, 62, 64, 63, 55, 60, 52, 31, 19, -12, -26, -4, -7, + -10, -3, 6, -22, -14, 12, 19, 4, -26, -38, -40, -56, -61, -66, -59, -65, + -51, -20, 29, 40, 51, 52, 62, 61, 53, 26, 20, 6, 8, 6, 9, -14, + -14, -15, -2, -11, -23, -36, -38, -60, -77, -69, -60, -51, -56, -44, -27, 10, + -2, 14, 10, 22, 16, 41, 60, 39, 35, 60, 62, 43, 45, 63, 52, 17, + 12, 15, -1, -2, 0, -38, -48, -32, -22, -7, 3, 13, 10, -2, -1, -8, + -12, -25, -48, -46, -52, -49, -36, -17, 9, 17, 26, 48, 57, 55, 69, 60, + 32, 6, 4, -6, -20, -24, -9, -21, -25, -14, -18, -38, -38, -32, -51, -52, + -60, -34, -6, -6, -16, -11, -2, -1, 17, 19, 3, 11, 25, 31, 41, 39, + 33, 33, 41, 34, 34, 23, 21, 15, 6, -13, -24, -28, -20, -8, -12, -19, + -12, -5, 9, 14, 2, -12, -25, -28, -21, -28, -23, -22, -18, -26, -5, 24, + 45, 46, 47, 39, 33, 36, 42, 29, 7, -5, -10, -21, -29, -39, -39, -31, + -24, -29, -39, -51, -43, -27, -22, -18, -25, -26, -20, 9, 19, 18, 4, -2, + 19, 30, 38, 25, 24, 28, 33, 41, 38, 34, 32, 38, 24, 8, 4, -8, + -11, -15, -25, -31, -25, -20, -22, -15, -11, -9, -12, -17, -20, -20, -15, -6, + -11, -8, 0, 11, 29, 19, 17, 17, 18, 28, 31, 25, 18, 23, 18, 10, + 1, -7, -18, -26, -24, -30, -41, -38, -44, -32, -31, -31, -35, -25, -12, -2, + -8, -11, -13, -13, -2, 8, 15, 19, 29, 35, 37, 39, 43, 42, 40, 35, + 27, 25, 18, 15, 9, 4, -4, -15, -28, -28, -26, -28, -18, -15, -25, -23, + -12, -11, -14, -10, -2, -4, -1, 8, 15, 19, 22, 25, 16, 16, 17, 5, + 7, 13, 18, 13, 9, 6, 6, 4, -4, -21, -31, -28, -37, -39, -34, -38, + -38, -32, -17, -6, -4, -14, -19, -9, 3, -2, 3, 4, 7, 8, 13, 23, + 35, 38, 43, 42, 31, 25, 23, 17, 8, 3, 4, -7, -7, -10, -13, -20, + -19, -28, -33, -30, -23, -18, -13, -17, -12, 3, 14, 23, 31, 27, 23, 21, + 22, 19, 12, 4, 2, 2, -2, 0, 4, 11, 11, 6, 4, -2, -5, -14, + -17, -30, -38, -44, -42, -28, -21, -23, -21, -15, -15, -4, 8, 11, 4, -7, + -15, -7, 5, 10, 21, 26, 28, 27, 34, 37, 36, 28, 19, 10, 11, 8, + -2, -18, -17, -19, -19, -22, -24, -21, -24, -18, -17, -13, -19, -13, -1, 12, + 19, 22, 21, 19, 19, 30, 34, 24, 13, 7, 2, 1, 1, 2, -1, -2, + -6, 0, 0, -2, -15, -21, -17, -21, -28, -32, -31, -31, -32, -27, -24, -17, + -4, 1, -3, -1, 1, 4, 7, 8, 15, 16, 15, 15, 20, 32, 36, 38, + 32, 19, 12, 3, 2, -2, -4, -11, -19, -17, -15, -11, -16, -20, -27, -30, + -28, -22, -13, -6, -2, 2, 12, 23, 29, 45, 44, 36, 32, 21, 16, 14, + 10, 1, -9, -8, -2, -1, -7, -13, -13, -12, -9, -11, -18, -24, -26, -28, + -30, -24, -21, -21, -21, -11, -11, -10, 0, -2, 0, 4, 12, 13, 14, 12, + 17, 22, 28, 30, 28, 20, 16, 13, 8, 2, -2, -6, -15, -14, -18, -15, + -15, -16, -18, -18, -16, -19, -18, -17, -10, 0, -1, 4, 13, 22, 37, 39, + 36, 27, 27, 32, 26, 15, 6, -1, -4, -5, -7, -11, -11, -9, -15, -15, + -14, -18, -21, -19, -17, -21, -19, -15, -15, -10, -15, -14, -12, -11, -6, -2, + 1, -2, 1, 5, 14, 22, 33, 35, 23, 18, 16, 13, 11, 6, 1, -9, + -18, -11, -6, -7, -8, -9, -11, -11, -12, -13, -17, -21, -24, -24, -15, -4, + 7, 12, 17, 25, 30, 28, 31, 32, 31, 27, 22, 15, 12, 3, -2, -8, + -6, -3, -9, -13, -22, -24, -20, -18, -22, -24, -18, -14, -13, -10, -11, -9, + -3, -2, -3, -5, -10, -10, -5, -1, 4, 11, 15, 19, 22, 27, 23, 20, + 16, 14, 5, -3, -11, -15, -16, -12, -12, -11, -5, 1, -3, -10, -13, -15, + -11, -10, -10, -11, -8, -3, 2, 7, 9, 15, 25, 30, 33, 31, 25, 21, + 20, 16, 13, 7, -2, -8, -5, -4, -11, -20, -21, -22, -21, -17, -20, -21, + -22, -19, -19, -11, -4, -2, -2, -2, 2, 5, 2, 0, 0, -3, 1, 8, + 16, 13, 14, 17, 15, 13, 8, 5, -1, -6, -10, -13, -14, -14, -13, -10, + -7, -8, -8, -6, -6, -3, -1, -1, -9, -12, -7, 3, 13, 17, 14, 13, + 17, 22, 23, 24, 18, 15, 18, 18, 18, 15, 8, 0, -5, -8, -11, -15, + -17, -21, -26, -26, -24, -26, -24, -13, -9, -6, -3, -2, 3, 4, 6, 7, + 5, 2, 4, 2, -2, -4, -3, 5, 13, 17, 10, 3, -1, -2, -4, -5, + -11, -14, -13, -11, -8, -8, -8, -6, -3, 0, -1, -5, -5, 0, 4, 3, + 1, 2, 0, 0, 6, 13, 20, 17, 17, 18, 21, 18, 14, 13, 11, 11, + 7, 9, 3, -5, -12, -14, -18, -21, -23, -26, -26, -13, -3, -6, -13, -14, + -5, 5, 8, 3, 0, 1, 3, 6, 4, -1, -1, 1, 3, 7, 5, 3, + 0, 1, -1, 3, 0, -3, -11, -11, -9, -10, -9, -8, -5, -7, -7, -10, + -9, -6, -1, 4, 6, 4, 2, 5, 10, 13, 9, 12, 13, 14, 15, 16, + 13, 12, 10, 13, 14, 13, 8, 2, -1, -4, -6, -9, -15, -20, -21, -19, + -14, -16, -22, -21, -13, -5, -3, -3, -1, 3, 5, 10, 9, 9, 6, 8, + 7, 7, 7, 3, -4, -6, -4, -1, -4, -8, -10, -11, -8, -4, -6, -10, + -7, -8, -11, -11, -8, -5, -4, 0, 3, 3, 8, 10, 10, 12, 12, 11, + 10, 13, 12, 10, 6, 8, 9, 9, 11, 13, 11, 9, 10, 7, 2, -3, + -8, -9, -14, -16, -16, -19, -18, -14, -13, -11, -11, -10, -5, -1, 3, 5, + 2, 2, 9, 14, 11, 9, 10, 7, 2, 0, 2, -2, -9, -13, -15, -18, + -17, -15, -13, -10, -5, -5, -7, -7, -4, -1, 0, -2, -4, -2, 1, 4, + 9, 10, 10, 11, 11, 13, 14, 10, 11, 9, 9, 4, 6, 5, 4, 5, + 7, 8, 10, 9, 4, -4, -8, -9, -10, -11, -12, -14, -15, -17, -15, -9, + -4, -1, -6, -5, 2, 8, 8, 6, 5, 3, 4, 5, 9, 10, 10, 5, + -1, -5, -10, -12, -14, -16, -18, -17, -11, -10, -11, -8, -5, -2, -2, 0, + 3, 4, 5, 3, 2, 3, 5, 9, 12, 12, 11, 10, 12, 14, 12, 8, + 5, 0, -1, 1, 3, 0, 1, 3, 5, 6, 5, 0, -5, -11, -10, -13, + -12, -13, -15, -14, -8, -4, -3, -3, -4, 0, 4, 5, 3, 6, 4, 4, + 7, 10, 9, 9, 8, 5, 5, 2, -4, -10, -15, -17, -20, -22, -22, -19, + -14, -11, -10, -8, -6, 0, 3, 5, 3, 4, 8, 11, 11, 12, 13, 12, + 12, 15, 15, 16, 16, 13, 11, 6, 3, -2, -5, -5, -3, -2, -1, 2, + 0, -3, -4, -5, -7, -10, -12, -11, -12, -11, -8, -4, -2, 0, 1, 2, + 2, 2, 4, 3, 3, 4, 5, 9, 10, 6, 2, 1, 2, 0, -3, -7, + -13, -18, -19, -18, -16, -18, -20, -19, -14, -8, -4, -1, 3, 3, 5, 7, + 9, 9, 10, 12, 13, 13, 13, 13, 16, 15, 13, 9, 6, 3, 2, 1, + 0, -3, -5, -6, -4, -2, -2, -4, -4, -5, -5, -3, -3, -4, -6, -6, + -7, -4, 0, 2, 3, 2, 2, 1, 2, 2, 1, 4, 5, 4, 1, 0, + 2, 2, 0, -2, -6, -8, -6, -7, -9, -11, -15, -18, -19, -18, -18, -17, + -13, -9, -2, 2, 3, 5, 10, 12, 13, 14, 14, 15, 17, 17, 16, 16, + 15, 13, 11, 7, 2, -6, -10, -8, -6, -8, -8, -7, -6, -6, -3, -4, + -6, -5, -3, -2, -2, 0, 1, 0, 2, 2, 3, 2, 3, 2, 3, 3, + 5, 2, 0, 4, 6, 5, -1, -4, -2, -1, -2, -6, -8, -9, -10, -12, + -10, -14, -17, -22, -22, -21, -19, -15, -8, -3, 1, 7, 12, 12, 15, 19, + 22, 21, 18, 16, 16, 16, 13, 12, 6, 3, 3, 2, -3, -6, -7, -12, + -12, -11, -8, -9, -8, -7, -3, 0, 0, 0, 0, -2, -2, 0, 1, 2, + 2, 4, 6, 6, 7, 5, 4, 3, 4, 5, 3, 0, -2, -2, -4, -6, + -10, -8, -8, -10, -11, -12, -12, -12, -13, -16, -16, -16, -14, -11, -8, -4, + -2, 1, 6, 12, 17, 19, 20, 20, 21, 21, 19, 13, 10, 9, 5, 0, + -3, -4, -4, -5, -6, -6, -4, -7, -10, -12, -12, -12, -10, -7, -4, -2, + 4, 6, 8, 7, 7, 7, 7, 8, 8, 7, 5, 6, 6, 4, 1, -1, + -1, 0, -3, -7, -10, -10, -8, -11, -14, -14, -12, -11, -9, -6, -8, -8, + -8, -11, -13, -12, -9, -8, -5, 0, 4, 8, 11, 14, 18, 18, 20, 23, + 23, 20, 14, 9, 4, 0, -3, -6, -8, -8, -8, -8, -9, -10, -11, -10, + -9, -8, -8, -7, -6, -3, 0, 3, 6, 12, 16, 16, 14, 10, 8, 9, + 7, 4, 1, 0, 0, -2, -1, 0, 0, -3, -7, -10, -13, -13, -12, -13, + -15, -14, -13, -9, -6, -5, -5, -7, -8, -9, -7, -6, -5, -7, -5, 1, + 8, 13, 17, 19, 20, 21, 22, 22, 18, 12, 9, 5, -1, -5, -9, -11, + -13, -12, -12, -11, -10, -8, -7, -7, -6, -7, -6, -3, 0, 1, 3, 7, + 10, 11, 12, 15, 15, 14, 9, 6, 3, 1, 0, -2, -2, -2, -3, -6, + -8, -10, -11, -13, -15, -15, -15, -13, -12, -12, -7, -5, -5, -5, -4, -3, + -3, -4, -4, -1, -1, 1, 4, 7, 10, 12, 14, 17, 20, 22, 19, 14, + 8, 5, 2, -2, -5, -10, -14, -13, -11, -10, -10, -10, -10, -8, -6, -3, + -3, -3, -1, -1, 2, 6, 10, 13, 14, 15, 15, 15, 13, 11, 8, 5, + 1, -1, -3, -3, -6, -10, -12, -12, -12, -12, -13, -15, -18, -19, -15, -11, + -6, -4, -3, -4, -4, -2, 1, 4, 2, -1, -2, 1, 4, 6, 8, 7, + 7, 11, 14, 15, 15, 15, 13, 10, 6, 1, -3, -6, -9, -13, -15, -15, + -13, -11, -9, -9, -9, -7, -3, 0, 2, 2, 4, 7, 11, 15, 16, 14, + 11, 12, 13, 15, 13, 9, 4, 1, -1, -4, -6, -8, -11, -15, -17, -17, + -17, -17, -15, -13, -13, -12, -10, -7, -6, -4, 1, 2, 2, 3, 4, 5, + 4, 4, 3, 5, 6, 6, 8, 7, 7, 9, 11, 10, 9, 8, 5, 2, + 0, -2, -6, -10, -13, -13, -14, -14, -13, -11, -9, -4, -1, -1, -1, 2, + 6, 8, 10, 11, 12, 14, 14, 14, 13, 11, 10, 7, 4, 2, 3, 1, + -3, -6, -10, -14, -17, -18, -18, -19, -19, -17, -15, -13, -9, -5, -1, 1, + 0, 1, 3, 5, 6, 6, 6, 7, 8, 9, 8, 4, 1, 0, 2, 4, + 5, 6, 5, 4, 4, 4, 3, 1, -3, -7, -9, -11, -12, -12, -12, -11, + -10, -7, -4, -2, 1, 4, 5, 8, 11, 13, 14, 14, 11, 11, 11, 10, + 10, 9, 6, 5, 3, 1, -2, -5, -10, -14, -16, -17, -18, -19, -20, -19, + -17, -14, -10, -5, -1, 1, 3, 5, 6, 6, 6, 6, 6, 6, 6, 6, + 8, 7, 6, 4, 2, 0, -1, 0, 0, 1, 2, 1, 1, 2, 1, -2, + -5, -8, -9, -10, -11, -12, -12, -10, -7, -4, -1, 2, 8, 11, 13, 15, + 15, 13, 12, 11, 10, 9, 8, 6, 5, 4, 4, 3, 0, -3, -6, -10, + -14, -18, -21, -22, -21, -18, -16, -13, -10, -6, -3, 0, 3, 5, 5, 5, + 6, 7, 8, 8, 8, 7, 8, 7, 6, 5, 4, 1, 0, -2, -4, -4, + -5, -4, -4, -3, -2, -1, -2, -3, -4, -7, -8, -9, -9, -9, -8, -5, + -2, 2, 4, 8, 11, 14, 15, 15, 14, 12, 10, 7, 5, 4, 4, 2, + 1, 1, 2, -1, -3, -7, -10, -15, -18, -18, -18, -18, -17, -15, -11, -7, + -3, 1, 3, 4, 5, 6, 7, 7, 8, 8, 9, 10, 10, 9, 6, 4, + 2, 0, -3, -4, -6, -7, -7, -6, -5, -3, -2, -2, -2, -2, -3, -4, + -5, -6, -6, -6, -6, -5, -4, -1, 4, 7, 9, 11, 12, 12, 11, 10, + 9, 8, 7, 5, 3, 3, 2, 1, 0, -1, -4, -7, -8, -10, -13, -14, + -15, -15, -15, -14, -11, -9, -6, -3, 0, 2, 4, 5, 6, 7, 8, 9, + 10, 10, 9, 8, 6, 5, 3, 1, -3, -6, -8, -8, -7, -7, -7, -6, + -4, -2, 0, -1, -2, -3, -3, -3, -3, -4, -3, -3, -1, 1, 3, 4, + 6, 7, 8, 9, 10, 10, 9, 7, 6, 6, 4, 3, 2, 1, -1, -2, + -4, -6, -9, -11, -12, -12, -12, -11, -11, -10, -9, -8, -7, -5, -4, -1, + 1, 3, 5, 7, 9, 10, 11, 10, 9, 8, 7, 6, 2, -1, -3, -4, + -6, -7, -7, -7, -7, -6, -5, -5, -4, -3, -3, -4, -4, -4, -3, -2, + 0, 0, 1, 1, 2, 4, 6, 6, 7, 7, 8, 7, 7, 7, 7, 7, + 6, 5, 2, 0, -2, -4, -5, -7, -8, -8, -8, -9, -10, -10, -9, -8, + -7, -7, -7, -5, -3, -2, 0, 1, 2, 4, 6, 9, 10, 11, 12, 10, + 8, 6, 3, 1, -2, -4, -6, -7, -7, -7, -7, -8, -7, -7, -6, -6, + -5, -4, -3, -3, -2, -1, 1, 2, 2, 3, 4, 5, 5, 5, 6, 6, + 6, 5, 5, 6, 6, 6, 4, 3, 2, 1, -1, -3, -4, -6, -8, -9, + -9, -8, -8, -6, -5, -5, -5, -6, -6, -6, -5, -4, -2, 0, 2, 4, + 6, 7, 8, 9, 9, 9, 9, 6, 4, 1, -1, -3, -5, -6, -7, -7, + -7, -6, -6, -6, -6, -6, -5, -4, -3, -3, -2, -1, 1, 3, 4, 5, + 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 1, + -1, -3, -4, -5, -6, -7, -7, -7, -7, -7, -6, -5, -4, -4, -3, -3, + -3, -3, -2, -1, 0, 1, 3, 5, 7, 8, 8, 8, 7, 6, 4, 2, + 0, -2, -3, -4, -5, -6, -7, -7, -7, -7, -6, -6, -5, -5, -5, -3, + -2, 0, 1, 2, 3, 4, 5, 6, 6, 6, 5, 5, 4, 3, 3, 3, + 3, 3, 3, 2, 1, 1, -1, -2, -3, -4, -5, -6, -6, -7, -6, -5, + -4, -3, -3, -3, -3, -3, -2, -1, -1, 0, 1, 1, 1, 2, 3, 5, + 6, 6, 6, 5, 4, 2, 1, 0, -2, -4, -5, -5, -6, -6, -6, -7, + -7, -7, -6, -5, -4, -3, -2, -1, 0, 2, 3, 3, 4, 4, 5, 5, + 5, 4, 4, 4, 4, 3, 3, 2, 1, 1, 0, 0, -1, -1, -2, -3, + -4, -5, -5, -5, -5, -5, -4, -4, -3, -3, -2, -1, -1, -1, -1, 0, + 0, 0, 1, 2, 3, 3, 4, 4, 4, 4, 4, 3, 1, 0, 0, -2, + -3, -4, -5, -5, -6, -6, -6, -5, -4, -4, -4, -3, -2, -2, -1, 0, + 2, 3, 3, 4, 4, 4, 4, 3, 3, 3, 3, 2, 2, 1, 1, 1, + 0, -1, -1, -2, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -2, -2, + -2, -1, -1, -1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, + 2, 1, 1, 0, 0, -1, -1, -2, -3, -3, -3, -4, -4, -4, -4, -3, + -3, -2, -1, -1, -1, 0, 1, 1, 1, 2, 2, 2, 3, 3, 2, 2, + 1, 1, 1, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -5, -41, -25, -37, -9, 28, 14, 6, 1, + 19, 16, -83, -53, -35, -44, -29, 8, -23, -29, -6, -20, -22, -19, -40, -2, + 14, 34, 78, 59, 73, 93, 73, 83, 124, 94, 87, 61, 98, 80, 29, 27, + 6, 8, -9, -8, -26, -33, -35, -32, -25, -32, -28, -59, -46, -31, -19, -12, + -12, 14, 14, -41, -59, -46, -33, -32, -52, -31, -29, -49, -51, -53, -85, -53, + -60, -100, -85, -84, -66, -37, -26, -11, -8, 22, 41, 33, 39, 27, 29, 75, + 59, 45, 52, 69, 66, 73, 90, 91, 103, 81, 46, 16, -21, -32, -13, -34, + -22, -42, -51, -35, -53, -62, -45, -35, -34, -29, 25, 62, 61, 39, -8, -20, + -5, -7, 2, 28, 1, -24, 8, 29, 11, -9, -54, -34, -35, -57, -41, -63, + -50, -16, -18, 26, 23, -2, 38, 9, 17, 41, 39, 82, 64, 64, 103, 64, + 43, 43, 51, 26, -3, 30, 1, 9, 14, -26, 20, -27, -50, -39, -47, -31, + -23, -33, 25, 56, 51, 20, -19, -60, -41, -27, -10, 3, -36, -30, -22, -46, + -5, -12, -7, -4, -54, 3, -25, -10, -1, -42, -75, -27, -84, -60, -88, -107, + -73, -29, -67, -53, 9, -10, 17, -29, -33, 55, 12, 7, 121, 70, 42, 123, + 96, 127, 74, 28, 51, 21, 60, 23, -10, 25, 103, 113, 65, 45, 15, -1, + 10, 2, -26, 1, -16, 19, 27, -8, -8, -24, -20, -17, -35, -86, -87, -32, + -51, -26, -60, -60, -50, -15, -31, -30, -50, -55, -19, 22, 14, 30, 49, 42, + 15, -11, -57, -15, -29, -65, -37, -56, -29, 15, 70, 69, 36, 24, 19, 21, + 19, 4, 60, 55, 18, -17, 0, -2, -21, 51, 49, -6, 22, 14, -24, -63, + -5, 4, -53, -33, -1, -37, -34, 40, 30, 12, -6, -1, 12, 12, 23, 20, + 43, 34, 11, -26, -40, 25, 56, -1, -41, -50, -37, -10, 20, -58, -65, -43, + -26, 42, 57, 77, 57, 26, -4, -10, -57, -45, -23, -49, -1, -59, -41, -26, + -27, 24, 52, -3, -12, 19, -44, -31, 33, 11, -14, 43, 31, 7, 58, 84, + 45, 35, 18, -5, 6, -21, -6, -20, -7, 41, 53, 29, 25, 55, 68, 37, + -29, -17, -41, -67, -76, -90, -112, -104, -60, -21, 25, 16, -23, -9, 30, 47, + 17, 3, 19, 4, -2, 30, 24, 1, 26, 33, 34, 10, 14, 1, -5, 16, + -2, -60, -32, -51, -48, -38, -34, -42, -20, 16, 17, -16, -32, -6, 4, -39, + -18, 1, -20, -22, 55, 70, 34, 5, -1, 13, 2, 1, 28, 20, -31, -2, + 51, 26, 24, 19, 11, -1, 2, 30, 13, 2, 70, 36, 15, 24, 5, 9, + 14, 48, 43, 8, 2, -10, 18, 33, 22, -27, -19, -17, -22, 11, 19, -5, + 0, -55, -60, -49, -63, -72, -45, -80, -55, -18, -8, 32, 52, 22, 0, -40, + -42, -30, -68, -51, -9, -67, -52, -10, 7, 35, 12, 36, 64, 23, 13, 64, + 39, 32, 73, 3, 6, -10, -6, 16, 18, 53, 51, 21, -20, -15, 13, -3, + 2, -39, -30, -7, -3, 6, 10, -4, -25, -7, -10, -10, -18, -31, -23, -38, + -48, -3, -26, -43, -7, 11, 31, 62, 41, -7, -34, -42, -24, 17, 12, 44, + 25, 24, 18, 11, 32, 51, 46, 46, 51, 33, 24, 32, 30, 40, 8, -30, + -39, -30, -44, -19, -33, -55, -41, -36, -70, -67, -64, -34, -37, -46, 1, 19, + 27, 81, 23, 13, 10, -5, -18, -19, -51, -14, -48, -75, 11, 51, 43, 63, + 37, 20, 19, 4, -23, 27, 47, 71, 29, 16, 15, -17, -11, 32, 40, 22, + 6, 16, -7, 5, 34, 61, 12, -21, -24, -13, -38, -41, -36, -33, 2, 9, + -45, -54, -36, 12, -18, -41, -25, -18, 19, 31, -11, -16, -22, -62, -65, -68, + -42, -4, -48, -49, 4, 38, 65, 47, 12, -20, -20, -8, 3, 32, 69, 84, + 44, 28, 31, 18, 36, 57, 74, 35, 19, 6, 24, 29, 36, 35, 6, -13, + -25, -43, -45, -35, -33, -44, -23, -41, -57, -52, -41, -35, -21, -16, -22, -11, + 33, 42, 14, 19, 16, 0, -6, -34, -17, -37, -25, -7, 6, 48, 47, 3, + -14, -17, -19, -11, -9, -11, 42, 42, 16, 1, 6, 15, 51, 42, 33, 29, + 20, -5, -3, 4, 54, 42, 8, -30, -19, -15, -15, -20, -6, -7, -24, -32, + -24, -17, -1, -16, -18, -36, -55, -38, -2, 8, 16, 7, -21, -35, -56, -67, + -17, -58, -67, -36, 21, 67, 48, 15, 8, 13, -9, -8, -1, 21, 107, 56, + 40, 56, 32, 33, 71, 60, 36, 30, 3, 31, 15, 4, 21, 2, -2, -25, + -30, -26, -13, -9, -26, -20, -34, -34, -51, -28, 6, -9, -24, -49, -67, -54, + -54, -52, -41, -42, -58, -37, 16, 39, 31, 16, 19, 11, -4, -23, -5, 24, + 1, 10, 24, 26, 15, 34, 70, 77, 56, 33, 43, 28, 17, 25, 12, 2, + 0, -12, -15, -2, 10, -19, -28, -45, -41, -28, -17, -3, -2, -9, -3, -25, + -45, -14, 23, 10, -5, -19, -32, -22, -10, -1, -15, -16, -6, 13, 48, 70, + 55, 23, 23, 10, -8, -14, 6, 8, -12, -5, 13, 10, -14, 0, 33, 23, + 18, 43, 21, 26, 33, 13, -14, -7, -3, -31, -29, -5, -5, -25, -27, -35, + -56, -45, -21, -17, -40, -14, 2, -23, -38, -9, 8, -16, -16, -7, -13, -25, + -4, -12, -21, -14, 3, 13, 44, 65, 60, 40, 15, 5, -20, -22, -3, 3, + 20, 39, 39, 9, 6, 21, 48, 24, 25, 25, 11, 0, 4, -5, -31, -34, + -22, -45, -40, -24, -24, -41, -38, -47, -54, -45, -16, -22, -32, -7, 16, -1, + -11, 23, 31, -1, -10, -20, -19, -9, 15, -10, -28, -21, 4, 24, 45, 60, + 56, 46, 30, 26, 23, 36, 48, 33, 46, 40, 34, 19, 12, 23, 43, 37, + 41, 43, 22, 24, 11, -11, -2, -5, 8, -28, -33, -11, -5, -26, -30, -25, + -45, -21, -8, -26, -35, -37, -39, -54, -56, -20, -23, -42, -52, -49, -63, -47, + -31, -29, -16, -21, -7, 14, 26, 48, 32, 12, -10, -22, -24, -6, 0, 33, + 44, 31, 25, 15, 10, 34, 48, 38, 14, 9, 16, 12, -23, -15, -15, -8, + -9, -19, -22, -2, -8, -10, -32, -27, 4, 12, -5, 1, -1, 4, -5, -3, + -5, 10, 37, 18, -8, -19, -3, 0, -10, -5, -31, -32, -29, -2, 18, 32, + 33, 14, -12, -15, 6, 8, 36, 66, 48, 38, 37, 42, 29, 49, 50, 42, + 28, 25, 33, 15, 2, 4, 2, 4, 2, -11, -1, 6, 3, 9, -14, -12, + -5, -12, -33, -36, -29, -26, -38, -44, -42, -38, -38, -52, -67, -70, -50, -32, + -27, -29, -38, -26, -27, 1, 21, 23, 16, -17, -34, -26, -18, -20, 2, 11, + 13, 5, 10, 13, 12, 28, 33, 35, 14, 14, 14, -8, -24, -25, -8, -16, + -23, -14, 12, 8, 21, 25, 13, 25, 29, 25, 6, 3, 36, 26, 34, 11, + 30, 29, 34, 23, 0, 1, 7, 8, 1, -10, -9, -13, 5, 17, 30, 26, + 25, 3, -11, -4, -4, 9, 13, 17, 6, 4, 17, -1, -4, 9, 16, 22, + 3, -2, -4, -16, -28, -22, -13, -34, -37, -31, -9, -7, -12, -16, -26, -12, + -14, -11, -23, -16, -24, -33, -24, -30, -17, -28, -34, -44, -51, -34, -24, -22, + -25, -2, 14, 23, 38, 46, 43, 28, 10, -6, -11, 1, 0, 5, 18, 16, + -3, 12, 27, 23, 32, 48, 42, 34, 21, 21, 10, -3, -10, -10, -20, -38, + -34, -29, -22, -16, -15, -17, -9, 7, 6, 6, -6, 1, 7, 6, 3, 11, + 30, 30, 15, 11, 11, 10, 17, 22, 23, 24, 9, 15, 5, -2, 4, 3, + -17, -21, -4, -21, -6, 8, -9, -1, 0, 8, -7, -18, -16, -3, -14, -13, + -8, -17, -10, -8, -26, -37, -28, -17, -35, -17, -10, 1, -6, 1, 25, 32, + 26, 9, -18, -19, 1, -12, -20, 2, 12, 5, -4, 15, 14, 15, 15, 17, + 14, 2, 6, 3, -18, -21, -9, -1, -15, -11, -15, -22, -1, 3, -7, 0, + 14, 14, -4, -13, 4, 18, 12, 15, 19, 25, 28, 27, 12, 9, 9, -10, + -17, -4, -5, -4, -20, -19, 11, 20, 13, 0, -19, -8, 6, -9, 6, 26, + 18, 14, 17, 22, 24, 18, 21, 37, 20, 7, 11, -8, -11, -4, -3, -8, + -22, -16, -18, -15, -4, -9, -21, -10, 5, -8, -7, -17, -7, -9, -20, -28, + -35, -31, -23, -23, -29, -28, -28, -33, -28, -24, -6, 0, -4, 7, 29, 25, + 15, -6, -19, 1, -2, -22, 4, 10, 1, 9, 10, 13, 4, 6, 21, 15, + 5, 21, 11, -18, -21, -15, -3, -4, -15, -15, -19, 4, 19, 11, 2, 17, + 16, 2, 14, 14, 17, 20, 22, 20, 10, 16, 27, 12, 8, 11, 5, -9, + -10, -6, -1, -7, -12, -3, 3, 8, 9, -5, -3, 6, -5, -6, 23, 14, + 11, 12, 21, 21, 4, 18, 30, 7, 12, 25, 3, -11, -16, -15, -10, -13, + -8, -6, -21, 2, -2, -25, -18, -8, -22, -22, -17, -12, -7, -12, -15, -20, + -41, -28, -24, -23, -12, -12, -15, -10, -7, 2, 1, 6, 18, 29, 23, 21, + 20, 9, -3, -9, -9, -10, -15, -8, -11, -2, 6, 14, 7, 7, 11, 9, + 14, 2, 3, 7, 6, 6, -21, -20, -10, -12, -15, -16, -18, -14, -11, -14, + 0, 0, -5, 3, 14, 12, 9, 0, -11, 5, 5, 12, 11, -1, 5, 3, + 1, 4, -1, -1, 13, 16, 8, 14, 9, -2, -7, -11, -17, -12, -5, -9, + -10, -13, -4, 1, 0, 4, 5, 0, 2, 3, 5, 14, 18, 9, -3, 2, + 15, 14, 6, 2, 1, -1, -5, -6, 0, 0, 0, 7, 20, 22, 23, 13, + 13, 17, 20, 35, 25, 20, 20, 14, 17, 16, 3, 7, 18, 15, 13, 17, + 6, -5, -6, -13, -23, -19, -19, -22, -22, -24, -17, -18, -22, -27, -31, -30, + -29, -30, -33, -36, -34, -37, -47, -38, -24, -28, -27, -31, -30, -28, -26, -20, + -14, -14, -9, 4, 17, 21, 15, 12, 25, 29, 33, 33, 30, 30, 31, 19, + 20, 14, 4, 10, 17, 18, 21, 28, 19, 20, 20, 5, -2, -3, -7, -10, + -2, 1, 4, 6, 4, 5, 3, 2, -1, -4, -7, -10, -3, -6, -16, -5, + -1, -8, -7, -6, -9, -10, -11, -7, -6, -10, -11, 2, 11, 7, 1, 6, + 12, 16, 18, 15, 11, 14, 16, 9, 11, 6, 5, 13, 14, 13, 11, 0, + -11, -4, -4, -8, -7, -5, -6, -3, -1, 2, -1, -6, -7, -9, -9, -9, + -15, -11, -14, -17, -16, -18, -17, -12, -7, -8, -7, -6, -2, -3, -12, -15, + -15, -18, -13, -19, -23, -24, -21, -21, -13, -12, -7, -3, -7, -6, -4, 2, + 1, 1, 3, 9, 23, 28, 23, 17, 24, 27, 22, 19, 16, 19, 10, 9, + 10, 10, 19, 8, 11, 16, 15, 11, 13, 14, 7, 5, -3, -7, -12, -15, + -16, -17, -10, -5, 4, -2, -2, -9, -13, -9, -8, -10, -10, -12, -5, 3, + 7, 3, 9, 3, 4, -1, -2, 2, -4, -9, -4, 0, 4, 4, -6, -3, + 12, 10, 15, 12, 7, 7, 1, -1, 8, 11, 9, 9, 13, 17, 17, 9, + 11, 4, 0, -3, -6, -8, -9, -10, -17, -20, -24, -17, -19, -22, -20, -21, + -15, -16, -19, -23, -21, -28, -26, -15, -14, -4, -1, -6, -3, -1, 4, 9, + 2, 4, 7, 7, 11, 15, 6, 17, 24, 16, 15, 9, 6, 6, 3, 1, + 3, 2, -2, 6, 6, 6, 3, -6, -3, -8, -7, -10, -13, -17, -18, -16, + -19, -13, -9, -3, 4, 10, 7, 7, 12, 11, 13, 10, 6, 1, 2, 4, + 4, 10, 10, 7, 4, 1, 4, -5, -12, -3, 1, 10, 7, 6, 4, 19, + 22, 20, 23, 16, 15, 19, 17, 14, 9, 7, 4, 4, 2, 5, 3, 0, + 0, -7, -7, -8, -7, -14, -15, -18, -25, -21, -21, -16, -13, -14, -17, -18, + -23, -21, -23, -29, -32, -33, -30, -23, -13, -11, -10, -8, -7, -2, 1, -3, + -1, 5, 13, 17, 13, 11, 13, 16, 14, 10, 11, 8, 16, 13, 4, 0, + 7, 13, 14, 15, 15, 17, 17, 9, 8, 9, 9, 2, 5, 11, 14, 7, + 4, 11, 10, 5, 7, 2, -1, -4, -9, -16, -15, -12, -9, -15, -23, -21, + -22, -22, -20, -22, -22, -21, -22, -22, -13, -6, 4, 2, -2, 2, 7, 6, + 10, 8, 9, 12, 21, 16, 11, 7, 11, 13, 11, 10, 11, 13, 9, 6, + 6, 5, 4, -5, 1, 4, 5, -1, -2, 6, 3, 3, -3, -10, -14, -14, + -14, -16, -8, -6, -1, -6, -7, -5, -7, -6, -9, -8, -8, -4, -5, -8, + -6, 3, 12, 4, -2, 3, 1, 1, -1, -4, -4, 5, 6, 1, -4, -3, + 5, 9, 8, 18, 20, 22, 15, 11, 11, 15, 12, 9, 11, 11, 11, 5, + 10, 12, 5, 3, -2, -4, -9, -9, -16, -17, -14, -12, -14, -20, -15, -16, + -17, -17, -19, -20, -19, -15, -17, -15, -13, -2, -3, -13, -8, 0, 4, 7, + 6, 4, 11, 13, 14, 11, 5, 6, 3, -1, -2, 2, 3, -1, -2, -6, + -4, -1, -3, 0, 3, 1, -2, -5, -5, -3, -6, -9, -7, -15, -13, -10, + -8, -4, 1, 9, 7, 2, 8, 8, 9, 12, 14, 7, 12, 12, 12, 8, + 14, 19, 11, 7, 10, 13, 10, 2, -2, -6, -1, 2, 6, 3, 1, 4, + 2, 2, 5, 8, 8, 7, 7, 2, 0, -3, -6, -3, -1, -6, -12, -9, + -6, -7, -9, -10, -14, -16, -12, -12, -11, -13, -16, -16, -20, -18, -14, -10, + -8, -9, -13, -9, -8, -9, -7, -9, -8, -3, -4, -3, -6, 0, 2, 3, + -3, 2, 5, 1, 6, 5, 5, 10, 11, 17, 15, 20, 25, 20, 15, 17, + 13, 12, 11, 7, 4, -1, -2, 6, 7, 7, 9, 10, 7, 9, 7, 5, + 5, 1, -6, -2, -5, -6, -3, -3, -1, -3, -5, -3, -6, -8, -7, -8, + -11, -12, -16, -19, -19, -14, -14, -17, -17, -11, -12, -15, -6, -8, -12, -12, + -9, -7, -6, 2, 9, 6, 8, 11, 13, 15, 14, 11, 7, 3, 3, 4, + 7, 9, 10, 6, 6, 5, 7, 11, 11, 4, 1, 1, -3, -5, -1, -1, + -1, -5, -2, -1, -1, 1, 1, -3, -7, -7, -9, -12, -11, -3, -3, -7, + -6, -6, -5, -5, 0, -3, -4, -2, 2, -1, 0, 6, 7, 7, 4, 3, + 5, -1, 0, -1, -7, -9, -8, -11, -5, 0, -1, 0, 2, 2, 5, 10, + 10, 7, 7, 7, 8, 8, 9, 11, 9, 8, 9, 6, 4, 2, 0, -3, + -5, -8, -8, -12, -8, -1, -4, -4, -5, -7, -9, -6, -5, -6, -8, -6, + -3, -7, 0, 5, 6, 3, 1, 6, 6, 4, 3, 1, -2, -4, -6, -4, + 3, 7, 3, 0, -1, -3, -2, -1, -2, -5, -8, -9, -7, -9, -8, -6, + -9, -7, -9, -7, -6, -7, -6, -7, -7, -7, -7, -8, -2, 1, 2, 4, + 3, 5, 6, 10, 11, 9, 10, 12, 9, 9, 11, 9, 10, 8, 7, 7, + 6, 7, 5, 4, 5, 4, -1, -4, -3, -5, -1, -2, -4, -4, -4, -4, + -2, -2, -3, -4, -2, -1, 0, 1, 8, 8, 4, 4, 4, 2, -2, -3, + -5, -6, -9, -10, -8, -5, 2, 1, -2, -2, -2, -2, -2, -5, -5, -7, + -7, -3, -4, -6, -4, -3, -5, -7, -5, -4, -7, -9, -6, -6, -9, -7, + -6, -2, 3, 3, 4, 5, 3, 4, 5, 2, 0, 2, 3, 2, 5, 7, + 10, 9, 7, 7, 6, 4, 1, -2, -5, -6, -10, -10, -8, 2, 8, 7, + 6, 7, 5, 5, 7, 6, 3, 4, 3, 4, 1, 3, 2, 4, 2, 1, + 1, -1, -3, -3, -4, -6, -9, -9, -9, -7, -6, -5, -5, -4, -5, -2, + -1, -2, -3, -1, -1, -3, -2, 2, 2, 3, 4, 4, 2, 0, -1, -3, + -4, -4, -5, -7, -2, 2, 2, -1, -3, -1, -4, -3, -2, -4, -4, -2, + -1, -2, -4, -2, -2, -1, -2, -2, -2, -3, -2, 0, 2, 0, -2, -2, + 0, 2, 3, 5, 4, 4, 4, 6, 3, 1, 0, 0, 0, 0, 5, 5, + 4, 6, 4, 2, 0, -2, -3, -6, -9, -8, -10, -10, -2, 3, 4, 4, + 4, 5, 4, 4, 5, 4, 4, 4, 4, 2, 3, 2, 2, 2, 1, 1, + 0, -2, -3, -3, -4, -6, -8, -7, -4, -6, -3, -3, -3, -2, 1, 0, + -1, -2, -2, -1, -1, 0, 1, 0, 0, 1, 0, 0, 0, -1, -2, -3, + -3, -4, -5, -4, -3, -3, -3, -3, -3, -3, -2, -1, 0, -1, 0, 0, + 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 2, 3, + 3, 2, 2, 0, -1, -1, -2, -3, -3, -4, -5, -4, 0, 3, 3, 3, + 3, 2, 3, 4, 6, 4, 4, 3, 2, 1, 2, 1, 0, 0, -1, -2, + -3, -3, -2, -2, -3, -3, -3, -3, -3, -2, -2, -2, -2, -2, -2, -2, + -2, -3, -2, -3, -2, -2, 0, 0, 0, 0, 0, -1, -1, -2, -2, -3, + -2, -4, -4, -3, 0, -1, 0, 0, 0, 0, 0, 1, 2, 1, 1, 1, + 0, 0, 0, -1, 0, -1, -1, -1, -1, -1, 0, 0, -1, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, + 0, 0, -1, -1, -2, -2, -2, -2, -2, -3, -3, -1, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 1, 0, 0, 0, -8, -33, -24, -25, -25, -26, -27, + -32, -28, -36, -31, -36, -22, -34, 11, -74, -14, 94, 41, 28, 33, 30, 40, + 34, 23, 41, 40, 60, 56, 59, 60, 44, 39, 54, 45, 52, 17, 44, 62, + 34, 33, 19, 18, 43, 35, 22, 36, -15, -10, 32, -7, -12, -6, -8, -50, + -47, -44, -4, -25, -48, -76, -58, -75, -96, -85, -118, -114, -63, -106, -103, -83, + -110, -99, -84, -76, -58, -63, -61, -51, -53, -36, -32, -41, -27, -11, 11, 8, + 27, 19, 30, 35, 28, 57, 53, 38, 71, 51, 68, 110, 78, 89, 109, 97, + 82, 94, 115, 114, 79, 70, 79, 94, 85, 76, 84, 95, 83, 82, 55, 54, + 54, 41, 41, 27, 20, 6, -11, -21, -16, -14, -33, -33, -52, -54, -59, -62, + -71, -79, -88, -88, -78, -78, -72, -71, -94, -99, -93, -90, -78, -87, -105, -103, + -79, -62, -71, -78, -63, -61, -66, -49, -23, -10, -11, -24, -20, -4, -22, 9, + 8, 27, 43, 34, 38, 51, 83, 65, 58, 74, 75, 70, 73, 71, 65, 100, + 89, 94, 65, 84, 49, 49, 61, 54, 43, 51, 58, 53, 35, 40, 36, 38, + 34, 23, 14, -12, -10, -1, -1, -11, -12, -19, -33, -66, -52, -42, -37, -55, + -42, -28, -32, -29, -35, -41, -28, -25, -46, -85, -64, -62, -55, -49, -68, -55, + -53, -52, -47, -43, -26, -32, -41, -34, -35, -40, -26, -8, -1, -6, -11, 5, + -2, 8, 3, 8, 6, 4, 20, 29, 43, 24, 33, 20, 30, 24, 39, 38, + 40, 29, 37, 36, 39, 61, 58, 41, 51, 59, 51, 55, 58, 48, 32, 45, + 40, 27, 30, 41, 44, 26, 19, 23, -3, 7, 0, -3, 2, 3, -6, -5, + -14, -6, -10, -27, -45, -47, -41, -38, -50, -51, -46, -43, -45, -65, -65, -80, + -95, -82, -74, -66, -69, -67, -33, -31, -53, -48, -51, -43, -18, -24, -24, -33, + -26, -10, 0, -17, -6, 17, 31, 2, 23, 45, 46, 12, 75, 38, 63, 69, + 31, 38, 80, 57, 48, 59, 81, 74, 32, 52, 72, 24, 60, 44, 55, 40, + 28, 48, 33, 24, 10, -2, 21, 34, 13, 18, 7, -1, -12, -20, -18, -30, + -9, -7, -30, -27, -26, -38, -20, -54, -55, -64, -53, -36, -62, -37, -71, -47, + -42, -71, -45, -55, -50, -54, -56, -36, -37, -54, -36, -12, -38, -33, -26, -7, + -22, -44, -10, 2, 3, 15, 8, 18, 6, 12, 8, 15, 28, 22, 50, 35, + 55, 42, 36, 49, 52, 64, 48, 60, 49, 60, 62, 40, 47, 68, 52, 59, + 61, 44, 53, 44, 35, 31, 31, 47, 22, 6, 4, -7, 5, -4, -21, -13, + -9, -10, -27, -46, -32, -44, -46, -62, -44, -51, -67, -53, -59, -63, -74, -67, + -61, -61, -65, -47, -58, -57, -45, -41, -46, -41, -38, -22, -25, -34, -16, -10, + -18, 0, 1, -6, 5, 17, 15, 10, 23, 38, 28, 28, 54, 40, 19, 55, + 55, 41, 46, 53, 40, 49, 51, 52, 41, 56, 39, 53, 38, 33, 35, 18, + 15, 38, 30, 23, 27, 13, 11, 7, 16, -1, 0, 0, 13, -6, -10, -15, + -10, -10, -24, -20, -16, -38, -36, -21, -40, -32, -42, -38, -52, -53, -41, -48, + -58, -50, -47, -37, -41, -45, -29, -41, -6, -48, -24, -25, -15, -9, -10, -10, + -10, -1, -17, 4, 3, 10, -4, 9, 15, 25, 24, 19, 23, 34, 28, 33, + 37, 38, 26, 36, 47, 35, 46, 45, 28, 35, 32, 32, 24, 21, 26, 23, + 19, 37, 20, 9, 29, -2, 26, 24, 8, 4, 14, 21, 11, -9, -8, 4, + -9, -31, -11, -15, -21, -24, -29, -22, -33, -26, -29, -48, -32, -44, -28, -22, + -35, -30, -38, -31, -46, -44, -36, -27, -23, -29, -24, -11, -20, -28, -13, -34, + -19, -1, 7, -3, -1, 6, -3, 5, 4, 8, 17, 26, 19, 33, 27, 16, + 35, 14, 36, 39, 22, 32, 31, 19, 32, 23, 29, 21, 30, 29, 23, 31, + 13, 24, 17, 11, 26, 18, 12, 5, 23, 16, 9, 15, -10, 3, 18, -15, + -4, -4, 6, -14, -15, -5, -34, -11, -20, -18, -8, -17, -29, -30, -29, -19, + -34, -35, -20, -36, -20, -16, -21, -38, -16, -30, -24, -25, -19, -18, -15, -7, + -5, -5, -10, -23, -3, -14, 0, -1, -12, -9, 7, 7, 2, 12, 5, 7, + 19, 10, 21, 21, 27, 30, 22, 18, 34, 22, 11, 26, 24, 20, 21, 25, + 29, 22, 27, 27, 20, 10, 20, 16, 22, 15, 16, 16, 5, 19, 10, 3, + 22, -5, -5, -7, -16, -4, -11, -22, -7, -16, -11, -23, -16, -30, -24, -28, + -20, -29, -24, -32, -22, -22, -30, -17, -23, -28, -22, -20, -21, -21, -17, -30, + -15, -14, -20, -9, 3, 6, 5, -20, 10, 13, -2, 11, 8, -1, 7, 16, + 5, 22, 23, 13, 22, 13, 22, 25, 15, 16, 11, 15, 13, 7, 12, 19, + 18, 20, 12, 23, 11, 6, 10, 1, 11, 19, 5, 20, 0, 11, 11, 1, + 14, 15, -3, -1, -7, 6, -6, -9, -9, 4, -3, -10, -20, -14, -9, -14, + -7, -10, -5, -4, -29, -14, -12, -26, -21, -27, -18, -10, -19, -27, -18, -8, + -25, -8, -13, -15, -14, -15, 5, -13, -7, -11, -4, -12, 0, 15, 5, 4, + 1, 11, 6, 4, 3, 6, 21, 19, 8, 15, 13, 6, 14, 16, 18, 17, + 20, 15, 11, 15, 24, 13, 11, 19, 7, 17, 14, 6, 17, 7, 7, 6, + 6, 5, 11, 0, 6, 0, -6, 5, 1, -11, -6, -1, -8, -9, -15, -7, + -4, -16, -17, -13, -13, -17, -14, -12, -12, -28, -13, -19, -25, -31, -24, -17, + -17, -16, -7, -15, -12, -8, -15, -8, -16, -10, -4, -1, -2, 3, 5, 2, + -2, 5, 3, 6, 10, 8, 11, 14, 14, 13, 15, 22, 16, 14, 18, 13, + 17, 19, 16, 10, 17, 8, 17, 14, 3, 14, 7, 10, 10, 7, 6, 6, + -1, 6, 1, 0, 12, -6, 6, 12, -4, -5, -4, -2, -2, -1, -2, -8, + -11, -9, -11, -11, -18, -6, -5, -16, -9, -14, -10, -13, -10, -11, -15, -14, + -14, -12, -17, -17, -17, -7, -11, -14, -15, -12, -6, -15, -5, -13, -9, 0, + 12, -2, -2, 6, 2, -7, 4, 10, 2, 9, 8, 7, 4, 5, 11, 15, + 11, 10, 18, 9, 13, 13, 13, 21, 11, 18, 19, 13, 14, 16, 6, 8, + 1, 19, 11, 10, 11, 1, 3, -1, -1, 5, -11, 5, -1, -5, -3, -13, + -10, -6, -7, -5, -15, -10, -11, -18, -8, -16, -20, -18, -9, -12, -17, -21, + -21, -13, -21, -8, -10, -10, -5, -16, -7, 2, -6, -6, -9, -7, -2, -9, + -5, 6, -7, 1, 3, -1, 2, 1, 2, 9, 8, 5, 15, 12, 1, 11, + 9, 8, 10, 15, 14, 5, 13, 17, 14, 15, 10, 7, 16, 5, 5, 5, + 8, 9, 10, 10, 7, 0, 4, 6, 9, -10, -4, 5, 2, -1, 0, -3, + -4, -5, -10, -5, -8, -9, -10, -3, -13, -6, -9, -20, -15, -11, -18, -14, + -10, -12, -20, -14, -14, -7, -12, -21, -14, -9, -8, -11, -5, -2, -7, -4, + 4, -2, -3, -1, 0, -1, 8, 6, 9, 7, 10, 6, 3, 4, 7, 10, + 11, 6, 9, 17, 11, 9, 7, -2, 16, 13, 12, 18, 5, 16, 9, 4, + 9, 6, 8, 9, 4, 4, 3, -2, -3, 2, -6, -3, 1, -7, -6, -3, + -6, -14, -8, -9, -4, -13, -9, -8, -16, -10, -12, -13, -11, -7, -8, -12, + -9, -8, -7, -11, -4, -8, -7, -8, -3, -13, -10, -3, 6, -5, -5, 0, + -5, -3, 6, -2, -2, 4, -2, 6, 2, -2, 5, 5, -2, 5, 15, 13, + 4, 6, 6, 14, 9, 4, 8, 7, 3, 11, 12, 2, 10, 7, 10, 8, + 4, 6, 2, 0, 3, 2, 4, 2, -6, -2, 2, -4, 3, -5, -6, -5, + -5, -5, -4, -8, -7, -4, -4, -7, -8, -7, -13, -10, -10, -11, -9, -8, + -8, -7, -11, -7, -3, -9, -6, -7, -3, -4, -5, 3, -3, -1, -2, -4, + 1, 4, 0, 3, 0, 5, 2, 0, 5, 4, 1, 3, 1, 0, 1, 7, + 3, 0, 4, 3, 6, 5, 0, 9, 5, 7, 6, 3, 6, 2, 3, 5, + -4, 9, 0, 4, 10, 0, 5, 1, -2, 4, -3, -3, -2, 0, 2, -7, + 3, -10, -1, -6, -9, -2, -4, -10, -3, -7, -6, -4, -10, -6, -6, -11, + -6, 0, -6, -8, -4, -1, -9, -10, 0, -6, -7, -2, -7, 1, -5, -5, + -1, 1, -6, 2, 0, -3, -1, 7, -4, 0, 7, 0, 8, 2, 3, 4, + 4, 2, 5, -1, 6, 7, 5, 6, 4, 2, 4, 6, 8, 6, 3, 1, + 8, 9, 2, -1, 4, 3, 4, 3, -3, 7, 4, 3, -2, 2, -4, -6, + -2, -5, -2, -3, 0, -5, -6, -13, -5, -6, -11, -9, -10, -5, -4, -9, + -9, -7, -7, -8, -8, -6, -5, -7, -5, -1, -3, -4, -2, -2, 2, -3, + 1, 2, -3, 1, 2, 1, 0, 1, 5, 0, 2, 5, 2, 0, 4, 1, + 7, 3, 2, 6, 0, 5, 7, 5, 5, 1, 3, 3, 5, 10, 3, 4, + 8, 2, 7, 3, -2, 3, 0, -1, -1, 1, 0, 1, -3, -2, -5, -4, + -3, -1, -7, -8, -4, -4, -10, -2, -8, -8, -8, -8, -9, -6, -8, -9, + -4, -2, -7, -5, -2, -7, -6, -9, -2, 0, -4, 4, -6, -3, -4, -1, + 2, 1, 2, 9, 0, 3, 0, 6, 4, 0, 5, 6, 2, 7, 7, 5, + 7, 6, 8, 6, 6, 5, 5, 1, 6, 5, -1, 3, 4, -1, 4, 1, + 4, 3, -5, 0, 4, 1, 4, -2, -3, -4, 0, -4, -8, -2, -5, -4, + -8, -6, -5, -3, -3, -7, -9, -6, -10, -10, -6, -6, -5, -4, -7, -6, + -4, -10, -3, -10, 0, -2, -2, -6, -1, 3, -3, -3, 1, 2, 1, 4, + 3, 4, 3, 4, 1, 2, 6, 5, 5, 5, 7, 9, 1, 5, 4, 4, + 7, 2, 9, 2, 4, 8, 2, 5, 6, 3, -2, -2, -1, -2, -1, 1, + -2, -4, 1, -6, -2, -5, -3, -5, -5, -6, -4, -3, -4, -10, -4, -3, + -8, -4, 0, -3, -5, -6, -6, -3, -1, -7, -3, 1, -1, -4, -2, 1, + -2, 0, -1, -2, 0, 0, 5, -2, 0, 3, 3, 1, 5, 2, 4, 1, + 4, 1, 2, 3, 3, 3, 4, 3, 3, 5, 1, 4, 2, 3, 1, 2, + 0, 2, 1, -2, -2, -1, 0, -2, -1, -1, -3, -5, -2, 0, -5, -1, + 0, -5, -2, -2, -2, -3, -3, -1, -4, -1, -2, -4, -2, -1, -2, -1, + 0, -3, -1, -1, 0, 1, -1, -1, 3, -4, -2, -2, 4, -2, -1, -1, + -1, 0, 0, -1, -1, -1, -1, 2, 0, -1, 2, -1, 0, -1, 2, 0, + 3, 5, -2, 1, 2, 0, 5, 0, -3, 4, -3, 1, 2, 0, 4, -1, + -2, 1, 0, 0, 0, -1, 1, -2, 0, 1, 1, 0, -5, 1, -2, -1, + 0, -2, -3, -1, -3, 0, -2, -3, -4, 1, -2, -3, -2, -2, -1, -1, + -2, -1, -4, -5, 2, -4, 0, 1, -1, 2, -2, -1, 0, 0, 1, -3, + 3, 2, 0, -2, 2, 1, 2, -2, 5, 3, -2, -2, -1, 1, 0, 0, + 1, 3, 2, 0, 0, -1, -2, 1, 1, 2, 1, 1, -1, 0, -1, -1, + -1, -3, 1, 1, 2, -2, -1, 0, 0, -2, 0, -1, -1, 2, -2, 1, + -1, 0, 0, -1, -1, -2, 0, -1, 1, -1, -1, 2, -2, 0, -1, -1, + 2, -1, 0, -3, -1, 0, 0, 0, -3, -3, -2, 0, 0, -1, -1, 0, + -4, 2, 0, -2, 0, 1, -3, -1, 2, 1, 0, -1, 0, 0, -1, 0, + 2, -1, -1, 0, 0, -2, 1, 1, 0, 1, 0, 2, -3, -2, 2, -1, + -1, 2, -2, 1, 1, 0, 0, 1, 1, 0, -4, 3, -1, 2, 0, 2, + -1, -2, 0, 1, 1, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -1, + -1, 1, 0, -5, 0, -1, -1, -1, 1, -1, 1, -1, 1, 0, -2, 0, + -2, 1, -1, 1, 0, -1, -2, 0, -1, 0, 0, 2, 0, 0, 0, 1, + 0, 0, 2, 0, -1, 0, 0, 0, 2, -1, 1, 1, -1, -1, 0, 0, + 1, 1, 0, 0, 0, 0, -1, 0, 0, -2, 0, 0, -1, 1, -2, -1, + -1, -1, -2, -1, -2, 1, -1, 0, -2, -2, 1, -2, -1, 1, 0, 1, + 1, -1, -1, 0, -1, 0, 0, 0, -2, 0, -1, 0, 0, -1, -2, -2, + -2, 1, -1, 0, 0, -1, 1, 1, -2, -1, -2, -1, 1, -1, -1, -2, + -2, 0, 0, 1, -1, -1, -1, -1, -2, 2, 0, 0, 1, 1, 1, -2, + 0, -1, 0, -1, -1, 2, 0, -1, -1, -1, 1, -1, 2, 0, -1, 1, + 1, 0, 1, 0, -1, -1, -1, -1, -3, 0, 0, -1, 1, 0, 0, -2, + -2, -2, 0, -1, 0, 0, -1, 0, -1, -2, -1, -2, 0, -2, 0, 0, + -1, -2, 1, -2, 0, -1, -2, 2, 0, -1, 2, -1, 1, -1, 0, 0, + -1, 0, 0, 0, -1, 0, 1, 0, 0, 1, 0, -1, -1, 0, -2, -1, + 0, 0, 1, 0, 0, 0, 0, -1, -1, 1, -1, -2, -1, 0, 0, -2, + 0, -1, 0, 0, 0, 1, 0, 0, -1, 1, 0, -1, 0, 1, -1, 0, + -1, -2, 0, -1, 0, -1, -1, -1, 0, -1, 0, 0, 0, -1, -1, 0, + -2, 0, 0, 0, -2, -2, 0, -2, -1, -1, -1, -2, 0, -1, -1, -1, + 0, 0, -1, -1, 0, 1, -1, -1, 0, -1, 0, 0, 1, 1, 0, 0, + -1, 0, 0, 0, 0, 0, 1, -1, 0, 0, 0, 1, 0, 0, -1, 0, + 0, -1, -1, 0, -1, -1, 0, -1, 0, -1, -1, 0, -2, -1, 0, -1, + -1, -1, -1, 0, -1, 0, 0, 0, 0, -1, 1, 0, 0, 0, -1, -1, + 0, -1, -1, 0, 0, 0, 0, 0, -1, -1, 0, -1, -1, 0, 0, -1, + 0, -2, 0, -1, -1, -1, 0, -1, -1, 0, -1, 0, 0, 0, -2, -1, + 0, -1, -1, 0, 1, -1, -1, 0, 0, 0, 0, -1, -1, -1, -1, 0, + 1, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, -1, 0, 0, + -1, 0, 0, -1, -1, -1, 0, 0, -1, -1, 0, -1, 0, 0, 0, -1, + 0, -1, -1, 0, -2, -1, -1, -1, 0, -1, 0, -1, -1, 0, 0, -1, + 0, -1, 0, -1, -1, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, + 0, -1, -1, 0, 0, 0, -1, 0, -1, 0, 1, -1, 0, 0, 0, 0, + 0, -1, 0, 0, 0, -1, 0, 0, -1, -1, 0, 0, 0, -1, 0, 1, + -1, -1, -1, 0, 0, -1, -1, -1, -1, 0, -1, 0, 0, 0, 0, 0, + 0, -1, -1, 0, -1, -1, 0, -1, 0, -1, -1, -1, -1, 0, -1, -1, + -1, -1, -1, -1, -1, 0, -1, 0, -1, 0, 0, -1, -1, 0, -1, 0, + -1, 0, 0, -1, 0, -1, -1, -1, 0, -1, 0, 0, 0, 0, 0, -1, + -1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, -1, 0, 0, 0, + 0, -1, 0, -1, 0, 0, 0, -1, -1, 0, 0, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 0, 0, -1, -1, -1, 0, 0, 0, -1, 0, -1, -1, + 0, -1, 0, 0, -1, -1, -1, -1, -1, 0, 0, -1, 0, 0, -1, 0, + 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, + -1, 0, 0, 0, 0, -1, 0, 0, -1, 0, -1, 0, 0, -1, -1, -1, + 0, -1, -1, 0, -1, -1, 0, 0, -1, -1, -1, -1, 0, -1, -1, 0, + 0, -1, 0, 0, 0, -1, -1, 0, -1, -1, -1, 0, 0, -1, -1, -1, + -1, -1, 0, -1, 0, 0, -1, -1, 0, 0, -1, 0, 0, -1, -1, -1, + 0, -1, 0, 0, -1, -1, 0, 0, -1, -1, 0, 0, 0, -1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, + 0, 0, 0, -1, 0, -1, 0, -1, -1, -1, -1, -1, -1, 0, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 0, -4, 11, 6, 16, 10, -16, -48, + -44, 2, 67, 42, -17, -51, 15, 71, 12, -22, -14, -44, -35, 11, 17, -18, + 2, -15, 19, 12, -1, -44, -15, 50, 45, -25, -61, 17, 10, -10, 31, 18, + -72, -27, 57, 26, -13, -17, -2, 6, -1, -23, -54, 17, 39, 8, 30, 28, + -6, -71, -5, 33, 27, -5, 17, 10, -23, -6, 12, -26, -6, -7, -9, -14, + 11, 37, 41, 8, -33, -14, 8, -31, -38, 13, 9, 15, 35, 33, 11, 17, + -41, -48, -33, 29, 25, 16, -9, -9, -17, -19, -29, 43, 64, -2, -55, -42, + -1, -21, -4, 29, 34, -25, -67, -29, 1, 51, 49, 25, -6, -15, -48, -76, + -3, 60, 78, 33, 19, 13, -38, -35, -35, -2, 62, 19, -4, -12, -4, -4, + -32, -30, 8, 68, -43, -66, -28, 55, 51, 20, -28, -29, -19, 20, -2, 8, + 21, -15, -43, 24, 22, -7, -2, 35, 15, -2, -24, -12, 3, 31, 13, -15, + -20, -17, -17, 26, -26, 24, -3, 7, 21, 26, -3, -17, -26, -50, -26, 33, + 58, 49, -22, -67, -17, 24, 7, -57, 5, 42, -11, -3, 32, -3, 7, 13, + -11, -9, 27, 17, 1, -5, -9, -18, -19, -3, -23, -5, 7, -8, 9, 13, + 12, -5, 7, -37, 22, 26, 21, 24, -20, -35, 23, 24, -35, -15, 46, -38, + -48, -14, -4, 0, -22, 3, 43, 38, -1, -14, -8, -5, -14, 1, 21, 23, + 29, -19, -47, -42, -49, -10, 66, 77, 48, -29, -32, 1, -11, 8, 17, -17, + 3, 43, 33, -22, -19, -41, 29, 22, -42, 9, 63, 28, -23, -59, -65, 7, + 53, -22, -10, -27, -30, 36, 48, -4, -6, -22, -16, 10, 14, -7, 22, 50, + -4, -25, -41, -55, -62, 23, 68, -16, -31, 49, 57, 21, -38, 14, 12, -43, + -49, -16, 28, 7, -12, -50, -17, 49, 65, 18, 1, -8, 28, 2, -27, -13, + 12, -11, -52, 4, 31, -32, -39, 15, 8, -19, 6, 25, -1, -23, 13, 34, + 59, 36, -16, -5, -7, -28, -30, 1, -14, -42, 10, 43, 26, -25, -37, -61, + 1, 63, 62, 1, -36, -24, 38, -7, -26, 27, 10, 4, 2, -19, -22, -27, + -24, 0, 33, -8, -57, -12, 62, 77, 51, -10, -42, -27, -28, -31, -3, 5, + 21, 10, 15, -27, -18, -18, -10, 3, 17, 19, 18, -16, -20, 25, -3, -19, + -5, 32, 17, -3, -32, -8, 2, -11, -24, -17, -11, 3, 42, 15, -12, -2, + 26, 9, -4, -30, -3, 16, 7, 13, 34, 40, 114, 11, -104, -71, 7, -14, + -34, -26, 35, 45, 47, 7, -7, -16, 11, -6, -29, -32, 1, 24, 32, 10, + 29, -10, -74, -80, -20, 18, 9, 18, 61, 38, -27, -44, 13, 16, -26, 20, + 69, 14, -14, -46, -7, -6, -35, 0, 9, 5, 58, 71, -36, -78, -15, 43, + 34, -61, -101, -27, 45, 26, -10, 23, 69, 69, 5, -72, -62, 19, 16, -37, + -60, 37, 60, 10, -49, -10, -2, -1, 43, 44, 10, -50, -5, 19, 8, -43, + -58, -17, 32, 28, 4, -1, -18, -10, 13, 8, 1, 1, 22, -3, -4, 9, + -8, -9, 17, 3, -15, -8, 14, 11, -14, -11, -5, 13, -24, -34, -1, -16, + -4, 32, 35, -32, 9, 22, 12, -27, -16, 14, 15, 0, -2, -12, -31, -24, + 14, 48, 10, -14, -7, -22, 4, -8, -14, 19, 21, -21, -25, -12, 19, 24, + 19, 27, -3, -15, -16, 10, 21, -14, 3, 8, 3, -11, -33, -16, 7, 5, + -8, 2, -3, 12, 5, -34, -19, -6, 26, 19, 0, -4, -12, 5, 12, 20, + 16, 19, 18, -13, -42, -26, -1, 0, -18, -16, 10, 27, 23, -5, -7, 9, + -8, 7, 22, 10, -28, -51, -26, 13, 44, 17, 16, 25, 14, -32, -45, -36, + -40, -3, 22, 41, 34, -12, -35, -31, 18, 3, 31, 28, 4, -21, 2, -14, + -24, -23, 19, -6, -7, -10, -1, -13, -13, 21, 52, 28, 7, 1, -25, -36, + 2, 34, 10, -37, -31, -13, 19, 11, -4, -20, 15, -5, -18, 40, -13, 15, + -36, 14, 18, 17, -21, 6, -39, 21, 7, -26, 8, -33, 24, 30, 32, -11, + -26, -47, -39, 62, 10, 11, 5, -17, -21, 10, 0, 18, 15, -22, 7, 13, + 14, -8, -9, 30, 33, -34, -41, -32, 37, 24, -19, -15, 1, 2, 10, 10, + -27, -46, -14, -9, 9, 47, 1, -22, -18, 5, 37, 29, -3, -19, -19, -18, + 8, 17, 1, -11, -6, -20, 27, 37, -2, -28, -34, -3, 22, 54, 34, -31, + -43, -28, -30, -33, 26, 49, 45, 43, -15, -58, -13, -2, -27, -7, 41, 11, + 19, -50, -74, -28, 31, 75, 39, -45, -7, 99, 44, -83, -47, 45, -1, -30, + 23, 29, -55, -30, 31, 28, -19, 2, -44, -46, -49, 30, 22, 58, 31, -50, + -20, 9, -38, -53, 49, 37, -9, 13, -25, -18, 18, -27, -7, 17, 3, 24, + 57, 26, -51, -52, -54, -43, 53, 85, 31, -36, -44, 7, 13, 19, -23, -33, + 36, 47, -38, -11, 37, -19, -6, 18, 17, 2, 31, 54, -29, -72, -80, -1, + 27, 52, 10, -29, -40, -48, -72, 24, 108, 66, -44, -76, -32, -24, 21, 69, + 54, 24, -2, -8, -28, -44, -50, 34, 95, 45, -40, -72, -32, 6, 28, -1, + 18, -7, 27, 1, -14, 21, -8, -51, -62, -24, 64, 56, 12, 19, -36, -22, + 10, 20, -10, -1, -5, -51, 36, 72, -42, -51, 70, 45, -48, -27, 54, 19, + -46, 8, 0, -46, 10, 37, 35, -21, -32, -22, -44, -82, -33, 59, 105, 48, + -32, -36, -31, 18, 60, -12, -49, 10, 89, 28, 12, 8, -45, -21, -6, -16, + -32, -17, -18, 3, 29, -3, 0, -20, -51, -31, 24, 52, 1, -17, -20, 1, + 35, 15, 5, 35, 27, 18, -19, 8, -71, -74, -8, 88, 57, -45, -37, 17, + 51, -1, -13, -4, 3, -13, -24, -7, 30, -7, -25, -1, 16, -8, -43, -70, + 11, 85, 77, 12, -62, -57, 35, 53, -33, -96, 8, 82, 21, -38, 25, 39, + -1, -27, -14, 18, -16, -45, -24, 42, 7, -9, 22, 32, -39, -5, -8, -49, + -17, 60, 88, 21, -93, -20, 82, 31, -26, -63, -17, 52, -28, -25, 13, -2, + -32, -46, 55, 56, -37, 6, -57, -33, 65, 63, 5, -25, -31, 69, 86, -32, + -34, -56, -23, -47, 14, 44, -23, 19, 6, 60, -27, -69, -37, 20, -14, -5, + 50, 44, 15, 13, -23, -60, -46, 23, 40, -5, -25, 6, 46, -4, -10, -27, + -12, 28, 45, 10, -13, -33, -19, -39, 42, 32, -23, -25, 24, -17, 13, 25, + 13, -32, 13, 48, 4, -93, -5, 40, -7, 37, -39, -37, 41, 1, -13, -33, + 43, -53, 106, 8, -57, -93, 55, 40, 56, -24, -4, -19, 7, -23, -65, -18, + 34, -30, 7, 66, 92, 3, -43, -37, -23, 12, -7, -17, 14, -15, -9, -18, + 18, 51, -1, -57, -17, 23, 19, 15, -40, -1, 0, -8, 39, -13, -43, 72, + 57, -1, -54, -17, 32, -19, 11, 0, 36, 25, -23, -86, 21, -3, 14, -17, + 76, 37, 23, 2, -23, -54, -42, -80, 61, 60, 63, -12, -57, -44, 15, 35, + 26, 11, -44, -22, 8, 33, -24, -17, 21, 38, -25, -39, 16, 43, -36, -28, + 54, 10, -52, -18, -34, -14, 76, 60, 24, -32, -19, 16, -13, -68, -5, 30, + -13, -23, -14, 61, 24, 35, 39, 4, -50, -58, -39, 0, 43, 43, 21, 24, + -20, -46, -36, 38, 8, -67, -8, 61, 38, 10, -12, 5, -4, -16, -47, -5, + -18, -20, 37, 41, 24, 4, 7, -19, 11, -52, 0, 17, 20, -30, -33, -16, + 60, 34, -15, -46, -77, 14, 29, 26, 21, 25, 8, 7, 36, 23, -39, -16, + 21, 11, -23, 11, -4, -6, -35, 13, -8, -49, -17, 44, 19, -25, -17, 9, + -5, -5, -1, -31, 11, 15, 17, -8, -31, -51, 12, 54, 85, 32, 4, -58, + -35, -31, 0, 10, 21, -20, -20, -29, 15, 26, -7, 8, 4, 0, 30, 2, + -26, 2, 19, 15, -18, -13, -20, -19, 47, 33, -6, -51, -30, -12, 12, 30, + 34, 31, 4, -45, -81, -7, -22, 1, 73, 98, 24, -67, -13, 19, -32, -86, + 6, 94, 4, -47, 21, -11, -50, 22, -3, -2, 50, 20, -37, -59, 35, 28, + -16, -36, -30, -11, 4, 69, 98, -65, -84, 73, 27, -90, -17, 84, 10, -51, + -14, 40, -24, -11, 16, -34, -26, 38, -43, -34, 58, 85, -33, -51, 17, 7, + 4, 52, 25, -35, 0, 44, -21, -47, 40, 44, -69, -65, 37, 35, -21, 4, + 32, -60, -75, 21, 64, 60, -6, -11, 6, 2, -41, -34, 19, 31, 9, 7, + -1, 11, 6, -11, -26, -23, 16, 35, -39, -68, 6, 56, -3, -42, 29, 28, + 3, 28, 14, -37, -16, 11, -8, -18, 15, -1, -8, 43, -20, -67, -12, 34, + 7, -12, -9, 5, -4, 7, -12, 27, -3, -68, 26, 96, 30, -33, -28, -25, + 19, 27, -33, -48, -3, 37, -1, -35, -11, 5, 42, 36, 6, -48, -38, 26, + 54, -23, -41, 52, 44, -32, -22, 28, -23, -32, 12, 41, -16, -6, -6, -17, + -18, -14, -12, -5, 18, 52, 45, -10, -16, 29, 11, -36, -26, 7, 36, 12, + -57, -48, 48, 70, 16, 21, -13, -46, -33, -62, -63, -21, 94, 94, 20, -110, + -47, 41, 67, -16, -57, -40, 85, 71, 7, -39, 15, -29, -50, -41, 18, -40, + -42, 38, 69, 21, -8, -58, -19, 23, 24, -20, -10, 11, 41, 7, -6, -30, + -23, 2, 16, 57, 38, -11, -50, 36, -16, -51, -51, 81, 24, -68, -84, 39, + 112, 62, -79, -104, 24, 102, 15, -38, 20, 22, -49, -91, 15, 51, 30, -1, + -15, -30, -12, 17, 42, -17, -48, 0, 49, 35, 2, -19, -16, -30, 9, 17, + -12, -4, -15, 5, 34, -1, -56, -64, 7, 48, 54, -16, -51, 20, 62, -17, + -27, -9, -10, -29, -1, 35, 44, -20, -23, -2, -12, -4, 31, 24, -24, -14, + 2, -28, -27, 49, 61, -54, -61, 6, 23, -20, 2, 41, 26, 2, 15, -5, + 6, -16, -36, -16, 2, -54, -53, -18, 62, 64, 10, -3, 91, 39, -54, -103, + -5, 16, -31, -28, 75, 105, -32, -114, -52, 68, 32, -52, -19, 25, 54, 61, + 14, -40, 12, 1, -56, -31, 74, 40, -73, -66, 0, 49, 36, 24, -20, 0, + 13, -40, -99, -11, 55, 31, -33, 39, 24, 3, -18, 7, 10, 4, -29, 17, + 19, 27, -30, -41, 9, 33, -24, -25, 30, 28, -34, -57, 8, -7, -46, 5, + 48, -22, -6, 57, 58, -31, -72, -2, 72, 44, -53, -42, 41, 1, -54, 30, + 54, -6, -79, -14, 33, -6, -22, 14, 10, -5, -8, 13, 23, 21, -47, -74, + 22, 24, -10, -7, 39, 2, 12, -7, -2, 4, 33, -20, -33, 18, 22, -88, + -71, 26, 81, 14, -37, 3, -24, 6, -8, 11, 40, 18, -7, -17, 20, -8, + -15, -41, -11, 27, 52, -27, -46, 33, 21, 46, -30, -13, 26, -91, -106, -47, + 54, 109, 67, -87, -90, 38, 92, 31, -10, -69, -73, -27, -6, 24, -6, 20, + 30, 45, 33, -13, -25, 10, 57, -16, -32, 0, -14, -55, -20, 4, 7, -4, + 3, 18, -11, 34, 11, -45, -45, -125, -38, -2, 19, 72, 82, 99, 98, 35, + -51, -81, -53, 3, -39, 23, -4, -58, -63, -24, 40, 84, 48, -7, -18, -2, + -8, -20, -10, 3, 21, 17, -39, -66, -20, -2, 37, 30, 39, 34, -5, -41, + -26, 33, 40, 18, -2, 11, 13, -20, -60, -21, 33, -25, -35, 30, 65, 22, + 13, -15, 2, 16, 11, -68, -18, 74, 10, -74, -34, -39, -17, 8, 59, 39, + -22, -38, -8, 9, 30, 23, 11, -3, -12, 10, -1, 59, 9, -28, -72, -27, + 32, 68, -11, -3, 27, 4, -33, -39, 7, -1, -5, -7, 26, -14, -26, -40, + -12, 5, 5, 1, -12, 64, 63, -41, -56, 10, 26, 40, -26, -44, -42, 25, + -6, 3, -1, 10, 9, -1, 9, 1, -28, 10, 24, 26, -33, -36, 46, 20, + -43, -52, -35, 22, 53, 30, -6, 18, -16, -49, -36, 45, 10, 21, 7, 9, + -33, -50, 21, 73, 33, -42, -46, 42, -12, -18, 5, -50, -25, 68, 55, -31, + -79, -7, 77, 25, -6, 29, 78, 24, -87, -41, -30, -41, -23, 75, 35, -32, + -65, -7, -13, 3, 41, 34, -24, -33, 25, 14, -52, -28, 19, 76, 45, -45, + -47, -5, 24, 9, -14, -41, -5, 49, 22, 10, -31, -35, -1, -6, 3, 10, + -1, -12, -20, -51, 9, 79, 53, -36, -38, -13, -14, -15, 50, 50, -36, -33, + 0, 5, 22, 23, 24, -51, -81, -27, 56, 42, -10, -16, 0, 0, -5, 16, + 12, -19, 11, 10, -15, -1, -32, -17, 1, 11, 62, -16, -21, 9, 21, -29, + -50, 16, 82, 17, -35, -4, 11, 3, 8, 8, -9, -13, 10, -39, -63, -19, + 54, 58, -16, -25, 18, 38, -8, -50, -54, -17, 18, 47, 17, -33, -45, 0, + 52, 57, -5, -34, -17, 32, 10, -28, -10, -21, -3, -9, -20, 20, 47, 22, + 5, -4, -15, -37, -22, -28, 9, 37, -18, -13, 3, 15, -33, -47, 20, 73, + 0, -36, 33, 60, -11, -77, -13, 42, 13, -20, 9, 47, 22, -27, 29, 6, + -71, -78, -20, 21, 4, 27, 23, 19, 31, 45, -29, -54, -10, 37, -78, -46, + -14, 67, 108, 57, 12, -62, -108, -15, 116, 56, -58, -110, -33, 33, 30, -39, + -26, 11, 29, 22, 8, 52, 76, 31, 0, -31, -50, -10, 59, 54, -13, -84, + -65, -60, 0, 35, 105, 61, -30, -117, -62, 35, 88, 57, 48, -38, -85, 41, + 12, -21, -6, 7, 15, 73, -30, -72, -37, 25, 0, -5, 65, 76, -90, -78, + 24, 47, 2, -14, 40, 83, 0, -32, -46, -62, -26, 50, 37, -4, -44, -40, + 55, 31, -38, -13, -17, -30, -4, 7, 68, 39, 1, -23, -38, -30, 6, -35, + 14, 52, -9, -62, -47, 45, 44, 11, -17, -9, 6, 16, 34, -3, -32, -21, + -33, -3, 21, 26, -39, 11, 65, 33, 19, -1, -49, -85, -97, 66, 58, -93, + -15, 15, 5, 81, 76, 29, -2, -52, -51, -30, 65, 38, -45, -14, 1, 28, + 22, 43, 19, -59, -109, -29, 29, -14, -22, -41, 0, 54, 76, 16, 8, 23, + 15, -47, -39, -8, 5, 36, -6, -3, -4, 13, 13, 21, -47, -53, -6, -9, + -27, -44, 8, 86, 64, 12, -5, -32, -10, -20, -27, -23, 8, 30, 1, 16, + 42, -35, -8, 4, -39, -11, -62, -29, 108, 87, -20, -104, -18, -55, 8, 47, + -16, 29, 38, 4, -44, -39, -20, 38, -13, 23, 82, 30, -67, -93, 26, 79, + 20, -79, -74, -23, 33, 59, 80, 39, -42, -100, 0, 19, 38, 9, -55, 9, + -15, 22, 68, -17, -55, -23, 1, 87, 19, -56, -60, 32, 37, 38, -67, -33, + -1, 31, 24, 15, -30, -5, -36, -29, -27, 8, 27, -9, 12, 29, 38, 33, + 0, -39, -18, 6, 19, 18, 8, 1, -33, 9, -1, 2, -29, -66, 0, 41, + 6, -50, -13, 9, 73, -28, -47, -21, 30, 68, 31, 32, 29, -46, -14, 13, + -44, -75, -3, 62, 55, 9, -49, -1, 54, 19, -6, 7, 16, 38, 13, -26, + -55, -76, -23, 16, 21, -33, -22, 16, 61, 25, -14, -35, 12, 23, -7, -17, + -32, -10, -16, -1, 7, 18, -1, 19, -2, -1, 21, -14, 1, -44, -44, -23, + -29, -1, 28, -28, 47, 64, 12, -4, -15, -37, -7, 24, 50, 6, -15, -26, + -5, 20, 12, -25, -21, -2, -18, -23, 9, 16, 24, 36, -30, -35, -12, 32, + 19, -13, 19, -6, 2, -2, -22, -11, 14, 50, 10, -21, -55, -14, 23, 6, + 6, -6, -26, -25, -8, 25, 14, 24, 14, -13, 18, 11, 23, -34, -49, -45, + 6, 39, 37, 3, 0, -29, 8, 26, -6, -7, -21, 2, -11, 6, 16, -1, + -17, 6, 32, -4, -54, -9, 22, -14, 6, 27, -1, -2, 34, 33, 8, 1, + -8, -14, -32, 23, -22, -23, -29, -12, 5, 25, 22, -4, 14, 5, 24, -39, + -29, 17, -21, -80, -60, -9, 78, 99, 81, -41, -53, 22, 11, -69, -22, -2, + 70, 80, 18, -56, -54, -79, -27, 56, 46, 28, -1, 12, -37, -76, 23, 64, + -4, -5, 4, 0, -2, -5, 10, -4, -9, 5, 3, 3, -2, 6, -2, -1, + 0, 2, 0, 1, -2, 2, -3, -2, 0, 1, -1, 0, 0, -1, -1, -1, + 0, -1, -1, -1, -1, 0, 0, -1, 0, -1, -1, -1, -1, -1, -1, 0, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -2, -3, -5, -6, -5, -5, + -3, 0, -1, -3, -1, 7, 16, 20, 8, -8, -24, -35, -39, -36, -35, -42, + -47, -35, -14, 0, 8, 17, 28, 45, 60, 65, 64, 66, 67, 60, 50, 39, + 26, 14, 5, -14, -40, -54, -56, -56, -55, -47, -36, -20, 1, 13, 15, 16, + 12, 2, -10, -20, -33, -43, -42, -38, -43, -40, -28, -17, -7, 6, 21, 34, + 48, 60, 63, 64, 66, 61, 54, 51, 41, 23, 10, 1, -18, -37, -46, -54, + -63, -60, -46, -30, -13, 5, 15, 16, 17, 11, -2, -11, -21, -34, -44, -45, + -43, -42, -33, -21, -17, -10, 5, 23, 39, 54, 62, 61, 62, 63, 59, 53, + 47, 38, 23, 10, -5, -23, -36, -42, -51, -61, -61, -48, -26, -2, 14, 16, + 13, 13, 9, -1, -14, -27, -36, -42, -44, -48, -44, -31, -17, -10, -8, 1, + 21, 47, 65, 67, 58, 54, 58, 61, 54, 41, 31, 23, 11, -9, -30, -41, + -44, -45, -54, -61, -52, -21, 11, 25, 19, 8, 4, 7, 2, -15, -33, -39, + -39, -44, -51, -48, -34, -12, -2, -4, -2, 19, 54, 74, 72, 58, 47, 51, + 59, 54, 40, 26, 20, 7, -16, -37, -46, -44, -42, -51, -58, -47, -15, 19, + 31, 25, 9, -1, -1, -4, -15, -30, -37, -41, -51, -55, -48, -28, -11, -4, + -2, 6, 28, 58, 73, 74, 63, 50, 45, 46, 49, 42, 31, 19, -6, -30, + -43, -44, -42, -51, -54, -49, -33, -3, 18, 30, 31, 17, 2, -13, -15, -15, + -25, -31, -45, -62, -60, -45, -24, -16, -10, 6, 20, 40, 58, 68, 74, 69, + 55, 41, 37, 44, 43, 34, 15, -17, -41, -48, -46, -51, -59, -51, -34, -16, + 3, 17, 29, 33, 23, 2, -15, -18, -18, -22, -31, -50, -64, -61, -42, -30, + -24, -8, 13, 35, 50, 57, 65, 70, 70, 58, 42, 40, 41, 40, 32, 6, + -23, -45, -53, -55, -64, -60, -45, -24, -1, 10, 19, 27, 28, 23, 4, -9, + -17, -22, -23, -36, -53, -61, -60, -47, -36, -22, -3, 19, 44, 56, 60, 65, + 65, 65, 60, 52, 45, 39, 37, 23, -2, -26, -49, -63, -66, -63, -55, -42, + -16, 3, 14, 25, 25, 22, 19, 11, -2, -17, -20, -29, -44, -50, -58, -64, + -53, -32, -13, 0, 25, 45, 53, 65, 68, 61, 60, 63, 60, 47, 42, 33, + 7, -10, -26, -56, -73, -68, -57, -53, -37, -12, -1, 14, 32, 26, 16, 17, + 16, 1, -12, -19, -38, -52, -47, -55, -65, -50, -23, -9, 4, 27, 40, 48, + 68, 72, 59, 58, 67, 64, 52, 42, 21, -5, -16, -31, -60, -73, -62, -54, + -49, -34, -17, -4, 17, 32, 24, 13, 18, 20, 6, -11, -29, -46, -48, -46, + -54, -59, -41, -17, -5, 6, 20, 35, 54, 71, 68, 55, 60, 74, 71, 53, + 27, 5, -6, -16, -35, -62, -70, -57, -49, -45, -40, -25, 4, 25, 29, 15, + 7, 23, 27, 10, -20, -46, -47, -41, -39, -47, -55, -34, -11, -1, 4, 11, + 38, 67, 72, 62, 48, 61, 83, 76, 49, 9, -9, -7, -15, -31, -59, -70, + -55, -48, -46, -43, -21, 16, 29, 22, 6, 1, 25, 32, 10, -28, -57, -47, + -34, -30, -38, -49, -33, -12, -4, 3, 17, 50, 72, 68, 55, 44, 61, 86, + 77, 41, -2, -16, -10, -13, -28, -56, -69, -58, -52, -47, -35, -7, 22, 25, + 13, -4, -2, 25, 33, 7, -35, -58, -46, -29, -22, -32, -44, -34, -16, -5, + 8, 30, 59, 72, 65, 46, 39, 62, 87, 76, 33, -8, -20, -13, -10, -28, + -57, -70, -62, -51, -42, -24, 3, 23, 23, 4, -15, -4, 25, 34, 3, -38, + -55, -45, -23, -17, -32, -43, -34, -15, -1, 14, 41, 64, 73, 59, 35, 35, + 64, 89, 73, 26, -11, -23, -14, -11, -33, -60, -69, -59, -48, -39, -14, 11, + 25, 17, -11, -24, -3, 30, 35, -3, -40, -54, -41, -18, -19, -36, -41, -28, + -10, 0, 21, 51, 70, 71, 47, 24, 36, 72, 93, 65, 17, -14, -22, -13, + -17, -43, -62, -63, -52, -48, -36, -5, 19, 26, 5, -26, -27, 5, 40, 31, + -12, -42, -50, -34, -20, -28, -37, -33, -17, -8, -1, 29, 61, 75, 64, 31, + 19, 44, 85, 93, 51, 9, -15, -18, -16, -30, -50, -57, -52, -48, -52, -32, + 3, 25, 20, -10, -34, -21, 19, 42, 20, -17, -40, -43, -35, -30, -32, -32, + -21, -12, -12, 3, 37, 67, 72, 50, 25, 24, 57, 92, 81, 42, 6, -12, + -18, -25, -39, -53, -52, -44, -49, -51, -28, 6, 25, 13, -17, -32, -11, 29, + 39, 8, -24, -38, -37, -33, -36, -39, -30, -10, -3, -9, 3, 38, 68, 71, + 46, 23, 32, 68, 92, 71, 31, 5, -7, -16, -31, -50, -55, -45, -37, -49, + -53, -27, 8, 23, 8, -20, -24, 3, 34, 28, -6, -28, -32, -30, -35, -46, + -43, -23, 0, 0, -10, 5, 41, 67, 65, 42, 30, 47, 77, 83, 52, 23, + 10, 2, -16, -43, -60, -55, -38, -36, -53, -53, -25, 8, 19, 3, -14, -8, + 17, 29, 9, -17, -24, -22, -26, -43, -53, -42, -14, 4, -3, -9, 10, 44, + 63, 58, 43, 43, 63, 77, 64, 38, 24, 20, 7, -23, -52, -62, -49, -38, + -45, -57, -49, -19, 6, 11, 2, -1, 12, 22, 13, -7, -18, -15, -17, -32, + -50, -52, -32, -11, -4, -8, -3, 21, 44, 55, 53, 52, 63, 70, 64, 49, + 35, 34, 24, 0, -29, -53, -54, -50, -51, -56, -57, -37, -17, -2, 7, 9, + 20, 21, 12, 1, -13, -11, -13, -24, -36, -49, -40, -30, -22, -12, -9, 10, + 25, 38, 51, 57, 70, 71, 62, 57, 44, 42, 34, 15, -4, -30, -42, -53, + -65, -61, -61, -49, -35, -22, -2, 10, 25, 27, 15, 11, -1, -8, -14, -22, + -27, -37, -37, -37, -40, -26, -14, -2, 10, 24, 42, 54, 68, 73, 65, 65, + 60, 49, 36, 27, 15, -7, -25, -43, -63, -69, -65, -61, -54, -36, -13, 3, + 18, 26, 23, 20, 16, 1, -16, -21, -20, -31, -37, -38, -40, -38, -25, -15, + -7, 11, 34, 48, 56, 66, 71, 72, 73, 61, 43, 34, 29, 11, -14, -31, + -46, -63, -69, -72, -69, -53, -28, -7, 3, 16, 27, 30, 28, 15, -3, -14, + -19, -25, -39, -42, -37, -38, -35, -30, -19, -2, 18, 39, 47, 56, 69, 75, + 78, 71, 60, 49, 35, 22, -1, -20, -32, -50, -65, -76, -75, -63, -49, -27, + -9, 6, 22, 28, 31, 27, 16, 6, -13, -26, -36, -43, -41, -42, -42, -36, + -27, -10, 2, 18, 38, 52, 64, 70, 73, 79, 76, 70, 50, 27, 11, -5, + -21, -41, -62, -69, -72, -68, -61, -50, -26, -4, 13, 21, 23, 32, 35, 27, + 6, -21, -33, -37, -42, -48, -53, -45, -31, -19, -8, 3, 23, 45, 59, 65, + 65, 73, 88, 88, 69, 40, 19, 10, -6, -30, -54, -69, -69, -68, -67, -59, + -43, -18, 2, 10, 15, 22, 39, 46, 27, -3, -28, -34, -37, -48, -56, -60, + -48, -29, -16, -1, 14, 35, 52, 58, 60, 64, 80, 96, 88, 64, 34, 16, + 6, -11, -36, -62, -77, -75, -68, -58, -47, -33, -14, -1, 7, 15, 28, 43, + 44, 24, -6, -30, -38, -40, -49, -63, -68, -56, -30, -5, 15, 27, 40, 51, + 59, 63, 72, 84, 91, 83, 60, 32, 12, 1, -14, -45, -73, -84, -78, -62, + -46, -36, -28, -17, 0, 11, 20, 31, 38, 35, 20, -6, -28, -40, -46, -58, + -72, -71, -52, -26, 4, 26, 37, 45, 54, 64, 69, 74, 81, 80, 73, 59, + 35, 13, -5, -28, -54, -75, -79, -74, -63, -43, -30, -21, -11, 0, 14, 23, + 29, 33, 23, 14, -2, -25, -41, -58, -69, -71, -64, -43, -24, 3, 33, 47, + 56, 60, 64, 73, 74, 75, 73, 62, 56, 38, 13, -12, -42, -57, -69, -77, + -71, -63, -44, -25, -15, -3, 2, 13, 26, 23, 24, 19, 8, -2, -24, -44, + -64, -74, -64, -60, -45, -16, 9, 34, 53, 63, 68, 66, 75, 73, 63, 66, + 62, 49, 34, 11, -17, -43, -54, -66, -82, -72, -52, -43, -28, -10, 0, 4, + 18, 27, 16, 13, 20, 8, -11, -26, -47, -66, -63, -59, -63, -47, -7, 20, + 34, 56, 69, 65, 73, 81, 67, 54, 61, 63, 44, 25, 6, -23, -37, -44, + -69, -85, -69, -48, -39, -26, -7, -4, 5, 27, 25, 9, 10, 15, 5, -17, + -34, -52, -62, -54, -54, -60, -40, -5, 21, 41, 59, 67, 66, 78, 81, 64, + 53, 58, 56, 39, 18, -3, -24, -34, -45, -64, -76, -67, -51, -37, -21, -8, + -3, 11, 22, 20, 11, 9, 11, -4, -23, -38, -56, -57, -53, -50, -42, -31, + -5, 21, 41, 63, 67, 72, 77, 69, 67, 58, 56, 49, 28, 16, -8, -28, + -35, -50, -53, -62, -65, -53, -44, -20, -2, 2, 14, 10, 14, 17, 7, 5, + -13, -27, -37, -60, -58, -55, -42, -22, -18, -2, 13, 36, 69, 73, 76, 71, + 62, 70, 60, 53, 42, 23, 16, -13, -35, -45, -51, -40, -46, -58, -60, -52, + -17, 4, 8, 11, 5, 14, 15, 4, -4, -20, -23, -37, -62, -67, -59, -27, + -2, -3, -3, 3, 36, 70, 77, 75, 66, 67, 70, 57, 46, 32, 29, 19, + -17, -49, -62, -46, -25, -33, -54, -68, -51, -15, 4, 8, 6, 11, 18, 8, + -7, -19, -16, -12, -35, -68, -83, -56, -9, 13, 7, -7, 4, 40, 66, 73, + 69, 73, 80, 69, 46, 27, 31, 42, 24, -23, -68, -69, -36, -14, -25, -57, + -66, -43, -16, -3, -2, 11, 28, 23, -2, -31, -29, -4, -1, -34, -83, -89, + -45, 3, 22, 6, -3, 16, 41, 56, 55, 68, 93, 93, 65, 23, 12, 38, + 53, 27, -38, -80, -64, -29, -12, -31, -54, -49, -34, -22, -24, -11, 28, 47, + 25, -24, -51, -27, 5, 5, -43, -90, -79, -34, 6, 11, 4, 17, 31, 39, + 34, 38, 79, 114, 105, 50, 3, 12, 44, 56, 16, -49, -72, -54, -28, -29, + -44, -37, -27, -28, -41, -45, -5, 46, 61, 17, -44, -53, -20, 7, -6, -53, + -78, -62, -27, -7, -6, 14, 41, 45, 26, 11, 38, 93, 127, 101, 34, 1, + 20, 48, 42, -1, -41, -53, -45, -40, -51, -44, -18, -9, -34, -61, -47, 7, + 57, 58, 2, -46, -43, -14, -5, -27, -52, -58, -46, -31, -26, -12, 28, 59, + 45, 10, 6, 50, 104, 124, 87, 30, 11, 30, 40, 19, -9, -26, -35, -44, + -58, -62, -38, -4, -6, -46, -67, -37, 21, 56, 43, -4, -37, -30, -15, -25, + -40, -44, -38, -38, -43, -38, -9, 40, 64, 37, 5, 14, 65, 106, 107, 75, + 36, 26, 34, 24, 4, -8, -10, -24, -53, -70, -64, -30, 0, -16, -53, -61, + -22, 28, 43, 29, -2, -21, -20, -26, -39, -43, -34, -26, -43, -54, -40, 0, + 46, 56, 30, 12, 30, 75, 97, 90, 69, 47, 38, 29, 13, 2, 0, -1, + -27, -61, -71, -55, -25, -14, -32, -50, -41, -6, 22, 25, 17, 4, -8, -19, + -31, -38, -35, -28, -35, -53, -54, -29, 7, 31, 32, 23, 28, 51, 72, 78, + 72, 65, 55, 42, 30, 19, 15, 11, -8, -36, -58, -58, -42, -35, -35, -43, + -40, -18, 0, 12, 14, 11, 9, -4, -15, -25, -31, -28, -36, -49, -53, -45, + -18, 1, 12, 19, 23, 43, 58, 64, 68, 64, 64, 57, 46, 40, 28, 22, + 9, -17, -35, -48, -47, -44, -47, -45, -44, -31, -12, -2, 7, 10, 9, 7, + -2, -8, -19, -28, -32, -44, -51, -48, -37, -21, -9, 5, 16, 26, 43, 55, + 60, 64, 63, 61, 58, 55, 48, 34, 21, 6, -13, -27, -39, -49, -53, -50, + -46, -41, -32, -16, -3, 5, 11, 9, 6, 5, -4, -17, -32, -40, -42, -44, + -42, -40, -32, -12, 5, 17, 24, 35, 50, 58, 64, 64, 60, 65, 61, 50, + 34, 18, 10, -2, -18, -38, -58, -56, -49, -45, -41, -38, -22, -4, 8, 14, + 8, 11, 10, -5, -20, -38, -41, -36, -37, -40, -48, -37, -12, 4, 14, 19, + 27, 46, 59, 66, 63, 62, 70, 64, 50, 34, 22, 17, 8, -11, -38, -59, + -57, -50, -49, -47, -43, -28, -6, 10, 16, 10, 14, 8, 1, -5, -5, -4, + -5, 5, 2, 2, 1, -1, 0, 1, 0, 2, 0, 0, -2, -1, -1, 2, + 1, 1, 0, 0, -1, 0, -1, 0, 0, 0, 0, 0, 0, -1, -1, -1, + 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, -1, + -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, + -1, 0, 1, 0, 0, 0, 1, 0, 1, 0, -3, -10, -11, -8, -13, -25, + -21, -10, 0, 2, 18, 41, 44, 42, 66, 62, 28, 10, 17, 17, -16, -10, + 25, 28, 29, 34, 47, 34, -7, 7, 25, -12, -43, -44, -40, -61, -85, -78, + -55, -42, -33, -10, 17, 31, 43, 59, 51, 25, 25, 40, 27, -1, 2, 25, + 30, 15, 12, 27, 26, 13, 16, 9, -24, -43, -37, -49, -83, -92, -62, -40, + -42, -36, 1, 33, 34, 45, 61, 46, 27, 32, 33, 10, -6, 15, 38, 26, + 4, 15, 35, 19, 7, 17, 3, -26, -41, -50, -67, -91, -82, -48, -40, -46, + -24, 18, 33, 32, 54, 62, 46, 30, 22, 20, 7, 4, 28, 33, 15, 10, + 22, 25, 9, 13, 18, -2, -29, -54, -65, -74, -86, -68, -49, -46, -32, -8, + 17, 29, 45, 65, 60, 43, 23, 13, 17, 12, 18, 28, 22, 19, 16, 13, + 14, 16, 24, 13, -13, -40, -66, -72, -75, -74, -64, -55, -36, -20, -9, 15, + 43, 63, 65, 51, 37, 17, 9, 19, 23, 21, 19, 24, 21, 3, 4, 24, + 31, 18, -2, -20, -49, -77, -74, -65, -71, -69, -47, -27, -27, -10, 38, 66, + 59, 52, 51, 34, 4, 11, 36, 26, 12, 22, 26, 2, -11, 25, 45, 18, + 0, -1, -23, -72, -83, -55, -65, -83, -61, -34, -37, -36, 23, 71, 55, 43, + 60, 55, 11, 1, 40, 37, 8, 16, 31, 6, -22, 14, 55, 27, -3, 8, + 2, -52, -83, -57, -56, -89, -79, -43, -43, -55, -4, 66, 61, 35, 56, 68, + 31, 4, 32, 46, 13, 7, 31, 16, -24, -4, 50, 42, 2, 7, 16, -25, + -67, -60, -54, -86, -95, -55, -44, -63, -32, 40, 62, 40, 47, 67, 48, 22, + 32, 42, 18, 4, 25, 25, -15, -16, 29, 44, 21, 11, 15, -5, -39, -49, + -59, -85, -96, -72, -52, -62, -50, 7, 45, 49, 50, 56, 56, 43, 42, 39, + 19, 9, 16, 21, 1, -16, 9, 32, 31, 24, 14, 5, -14, -34, -52, -81, + -94, -85, -71, -62, -55, -21, 21, 41, 53, 55, 55, 57, 51, 44, 26, 13, + 15, 11, 3, -3, 0, 19, 27, 29, 26, 11, 0, -16, -41, -70, -90, -88, + -85, -80, -57, -34, -3, 26, 42, 57, 57, 60, 64, 50, 33, 20, 17, 9, + -6, -1, 6, 10, 23, 26, 28, 22, 10, 1, -27, -60, -78, -87, -90, -94, + -74, -42, -20, 10, 34, 44, 57, 65, 71, 58, 35, 30, 23, 8, -5, -7, + 4, 7, 19, 33, 23, 19, 24, 17, -13, -53, -65, -75, -96, -98, -83, -61, + -40, -7, 32, 38, 38, 66, 83, 65, 36, 36, 37, 8, -7, 1, 0, -5, + 11, 39, 34, 10, 21, 36, 4, -45, -59, -59, -89, -106, -84, -67, -62, -32, + 21, 41, 30, 47, 85, 80, 41, 34, 45, 20, -8, 0, 9, -7, -6, 31, + 45, 21, 12, 32, 25, -27, -55, -52, -76, -104, -95, -70, -64, -57, -7, 33, + 34, 38, 67, 84, 57, 35, 46, 29, -1, -4, 7, 7, -8, 12, 41, 31, + 21, 24, 25, -5, -43, -45, -65, -98, -98, -82, -62, -58, -35, 13, 27, 38, + 59, 70, 67, 45, 49, 39, 2, -3, 2, 9, 9, 6, 30, 30, 24, 31, + 20, 3, -26, -37, -48, -91, -100, -88, -75, -53, -41, -9, 12, 23, 55, 65, + 61, 54, 51, 51, 14, -6, 1, 1, 15, 18, 26, 29, 16, 30, 28, 4, + -14, -29, -36, -71, -100, -93, -87, -64, -38, -16, 2, 6, 33, 61, 59, 56, + 54, 55, 32, 1, -3, -4, 5, 25, 36, 36, 17, 14, 25, 14, -4, -19, + -30, -53, -84, -94, -95, -82, -49, -16, 4, 2, 10, 37, 56, 61, 58, 54, + 42, 19, 3, -9, -8, 14, 41, 53, 32, 10, 7, 10, 10, -7, -25, -43, + -65, -81, -97, -99, -72, -29, 9, 11, 3, 10, 33, 61, 65, 55, 46, 30, + 19, 0, -17, -5, 29, 62, 57, 24, -1, -6, 10, 8, -16, -35, -54, -64, + -80, -105, -99, -57, -2, 26, 13, -2, 6, 42, 67, 60, 49, 36, 31, 22, + -10, -24, 1, 49, 77, 53, 9, -14, -4, 10, -4, -26, -47, -56, -58, -89, + -115, -93, -34, 23, 33, 6, -6, 16, 50, 62, 53, 39, 34, 40, 16, -24, + -26, 15, 71, 82, 38, -5, -13, -1, 3, -13, -39, -53, -48, -61, -103, -119, + -80, -6, 42, 27, -1, 2, 26, 51, 56, 43, 33, 43, 42, 4, -34, -23, + 37, 87, 70, 20, -6, -10, -3, -5, -27, -49, -48, -44, -72, -115, -118, -56, + 22, 43, 17, 3, 12, 33, 51, 45, 34, 38, 51, 38, -11, -42, -9, 59, + 86, 53, 13, -5, -5, -3, -19, -42, -50, -43, -45, -85, -127, -105, -28, 34, + 37, 15, 8, 23, 41, 42, 34, 33, 45, 55, 26, -27, -38, 12, 69, 77, + 40, 9, 1, 0, -13, -33, -48, -49, -39, -55, -102, -124, -83, -8, 37, 31, + 14, 19, 35, 39, 34, 30, 35, 51, 50, 9, -31, -25, 27, 72, 65, 30, + 12, 9, -2, -23, -42, -52, -46, -43, -71, -109, -112, -63, 7, 36, 25, 20, + 33, 42, 35, 29, 29, 40, 52, 35, -2, -28, -12, 40, 69, 51, 26, 18, + 13, -8, -33, -48, -50, -46, -57, -84, -107, -98, -43, 14, 29, 24, 30, 44, + 43, 30, 26, 34, 44, 40, 19, -8, -20, 4, 46, 59, 42, 29, 25, 10, + -18, -40, -46, -47, -57, -73, -91, -100, -78, -30, 13, 25, 30, 44, 48, 39, + 29, 31, 41, 35, 23, 9, -9, -5, 16, 43, 52, 40, 37, 25, 0, -23, + -41, -43, -54, -74, -82, -93, -86, -60, -26, 12, 26, 41, 53, 44, 40, 33, + 36, 38, 19, 12, 2, -3, 9, 18, 40, 48, 42, 41, 16, -6, -23, -41, + -45, -68, -84, -86, -90, -71, -52, -22, 15, 32, 52, 54, 45, 45, 36, 36, + 25, 6, 6, 0, 5, 15, 21, 41, 46, 46, 37, 10, -7, -24, -42, -57, + -81, -88, -88, -83, -62, -43, -14, 16, 41, 59, 55, 48, 48, 40, 27, 10, + 2, 2, 0, 8, 22, 30, 36, 45, 50, 32, 5, -9, -23, -48, -75, -86, + -86, -88, -81, -54, -26, -11, 16, 52, 65, 55, 50, 53, 39, 9, -2, 4, + 2, -4, 11, 36, 34, 27, 47, 51, 26, 0, -9, -23, -63, -91, -85, -81, + -89, -79, -38, -13, -11, 23, 62, 67, 55, 52, 56, 29, -8, -7, 7, 0, + -5, 19, 44, 30, 28, 49, 46, 21, -2, -10, -32, -79, -96, -83, -81, -87, + -67, -27, -11, 0, 36, 65, 67, 58, 54, 48, 14, -15, -7, 3, 1, 6, + 26, 35, 30, 38, 46, 37, 18, -2, -18, -48, -85, -96, -89, -81, -70, -52, + -30, -8, 20, 48, 63, 66, 59, 50, 33, 6, -14, -15, -2, 13, 20, 21, + 25, 36, 45, 42, 31, 12, -10, -31, -56, -84, -103, -96, -70, -50, -43, -31, + 0, 35, 58, 68, 65, 51, 37, 26, 8, -19, -25, 2, 27, 27, 17, 20, + 36, 45, 45, 29, 0, -27, -41, -55, -87, -111, -93, -57, -37, -33, -23, 5, + 41, 70, 77, 59, 36, 26, 24, 4, -24, -22, 7, 31, 33, 19, 14, 29, + 49, 50, 22, -16, -39, -48, -63, -92, -104, -86, -51, -25, -19, -16, 10, 53, + 82, 74, 47, 26, 19, 16, -1, -18, -16, 7, 35, 37, 18, 10, 31, 55, + 41, 4, -25, -45, -57, -73, -90, -95, -82, -42, -9, -8, -11, 20, 71, 84, + 57, 39, 27, 13, 2, -6, -9, -12, 8, 45, 41, 8, 5, 42, 56, 20, + -10, -24, -50, -73, -83, -83, -87, -76, -25, 10, -5, -9, 39, 84, 71, 44, + 38, 26, 2, -9, -2, -4, -11, 17, 52, 36, 0, 11, 50, 43, 3, -19, + -31, -57, -84, -84, -77, -82, -59, -9, 14, 1, 7, 55, 81, 61, 38, 29, + 20, -2, -10, -1, -4, 0, 26, 42, 30, 8, 20, 41, 28, -4, -31, -46, + -64, -84, -82, -79, -66, -37, -7, 15, 18, 30, 58, 68, 57, 33, 17, 9, + 0, -3, -7, 0, 15, 23, 31, 29, 23, 24, 22, 14, -12, -43, -63, -72, + -73, -83, -75, -47, -26, -2, 20, 37, 48, 50, 57, 52, 30, 6, -1, 11, + 0, -9, 7, 16, 24, 28, 32, 33, 15, 7, 2, -21, -55, -79, -66, -67, + -81, -63, -38, -12, 9, 29, 53, 48, 42, 51, 47, 22, -6, 5, 18, -4, + -7, 6, 22, 28, 26, 39, 28, 2, -2, -8, -35, -73, -76, -56, -67, -77, + -55, -20, 4, 16, 40, 54, 42, 41, 51, 37, 7, 0, 17, 13, -12, -9, + 20, 31, 25, 29, 33, 15, -5, -8, -22, -57, -74, -62, -57, -74, -71, -33, + 0, 11, 26, 44, 45, 41, 47, 45, 22, 3, 12, 19, 0, -15, 4, 30, + 32, 27, 26, 17, 3, -4, -14, -44, -69, -66, -56, -63, -74, -52, -11, 12, + 21, 29, 35, 41, 49, 51, 31, 9, 11, 19, 11, -8, -7, 20, 36, 34, + 22, 10, 6, 5, -4, -33, -64, -66, -58, -58, -67, -63, -29, 4, 20, 21, + 21, 35, 52, 57, 39, 12, 10, 18, 16, 3, -7, 8, 31, 39, 25, 5, + 3, 10, 5, -22, -58, -67, -58, -56, -60, -64, -45, -11, 15, 19, 12, 24, + 50, 62, 46, 17, 9, 18, 20, 12, 0, 2, 21, 37, 31, 7, 0, 11, + 14, -12, -51, -66, -58, -53, -54, -59, -54, -29, 3, 16, 9, 17, 44, 62, + 51, 22, 8, 17, 24, 21, 9, 1, 11, 30, 31, 14, 3, 11, 16, -4, + -43, -65, -58, -49, -50, -53, -55, -43, -16, 5, 10, 16, 38, 59, 54, 26, + 7, 18, 29, 24, 18, 8, 5, 16, 27, 23, 11, 14, 18, -1, -36, -63, + -56, -43, -48, -47, -49, -52, -36, -12, 8, 17, 35, 55, 50, 28, 9, 17, + 33, 25, 24, 20, 5, 4, 15, 27, 23, 20, 22, 0, -32, -58, -55, -40, + -47, -44, -39, -52, -54, -34, -2, 19, 35, 53, 46, 27, 12, 18, 34, 26, + 26, 33, 13, -6, 0, 22, 34, 32, 28, 3, -31, -53, -51, -39, -47, -45, + -30, -45, -66, -56, -19, 15, 38, 52, 43, 22, 13, 22, 35, 26, 26, 41, + 25, -7, -13, 10, 35, 46, 39, 10, -29, -50, -46, -37, -47, -46, -27, -35, + -65, -72, -42, 2, 38, 55, 43, 19, 11, 24, 36, 27, 26, 43, 37, 2, + -19, -6, 25, 53, 56, 20, -24, -46, -43, -36, -46, -48, -29, -28, -56, -77, + -64, -22, 31, 61, 45, 16, 10, 23, 35, 30, 26, 41, 42, 16, -14, -21, + 7, 51, 70, 36, -15, -38, -40, -35, -42, -49, -35, -29, -44, -71, -81, -49, + 14, 60, 50, 18, 10, 21, 34, 34, 26, 37, 43, 30, 0, -27, -13, 37, + 74, 54, 2, -29, -35, -32, -37, -49, -42, -32, -36, -57, -85, -73, -12, 46, + 57, 27, 9, 17, 32, 38, 28, 30, 41, 39, 18, -20, -27, 15, 62, 68, + 26, -17, -30, -28, -29, -45, -51, -40, -34, -45, -77, -86, -42, 18, 54, 43, + 14, 12, 29, 42, 34, 25, 33, 41, 30, -2, -24, -5, 36, 65, 50, 3, + -24, -24, -19, -33, -54, -52, -42, -45, -61, -75, -58, -15, 32, 48, 25, 10, + 24, 45, 45, 27, 26, 32, 28, 13, -4, -6, 14, 44, 55, 24, -11, -18, + -12, -20, -46, -57, -53, -54, -57, -63, -57, -33, 4, 35, 32, 16, 22, 40, + 49, 36, 26, 28, 23, 17, 8, 1, 10, 27, 43, 33, 5, -6, -8, -14, + -33, -53, -57, -61, -62, -61, -59, -38, -10, 15, 26, 20, 26, 40, 44, 41, + 30, 27, 25, 18, 12, 3, 9, 26, 33, 28, 13, 5, 5, -8, -25, -45, + -57, -60, -64, -66, -65, -49, -17, 6, 13, 16, 26, 43, 47, 39, 32, 27, + 27, 25, 13, 3, 6, 22, 35, 26, 13, 10, 12, 5, -17, -40, -54, -58, + -58, -68, -74, -61, -31, -1, 9, 10, 23, 40, 50, 45, 31, 24, 27, 31, + 20, 3, 2, 17, 32, 31, 16, 12, 15, 12, -4, -31, -51, -55, -54, -62, + -76, -73, -47, -17, 2, 8, 19, 37, 51, 50, 34, 24, 26, 31, 25, 9, + 4, 13, 26, 34, 25, 9, 13, 20, -2, -33, -44, -43, -58, -78, -77, -59, + -44, -33, -10, 17, 6, 12, -9, 32, 13, 4, -4, 6, -9, 27, 8, 2, + -1, -3, -2, 3, -4, -3, 2, 0, -2, 1, -2, 1, -4, 2, 1, 0, + -2, -1, -3, 2, 0, -1, -2, -2, -2, -1, -2, -2, -1, -2, -2, -2, + -2, -1, -2, -1, 0, -1, -2, -2, -2, -1, 0, -2, -2, -2, -2, -1, + -1, -2, -1, -2, -2, -2, -3, -1, -1, 0, 0, -1, -3, -2, 1, 3, + 0, 0, -2, -8, -21, -17, -2, 12, 20, 19, 6, -13, -28, -73, -67, -64, + -58, -39, -11, 19, 38, 60, 96, 80, 38, 12, 6, -20, -65, -83, -65, -61, + -56, -17, 22, 35, 49, 74, 94, 55, 16, 20, -5, -52, -89, -81, -53, -65, + -36, 21, 37, 48, 51, 85, 82, 25, 23, 9, -36, -80, -105, -58, -57, -54, + 7, 36, 54, 44, 58, 97, 48, 26, 16, -21, -61, -115, -83, -45, -57, -12, + 23, 57, 54, 36, 86, 77, 37, 21, -16, -40, -103, -110, -54, -46, -24, 6, + 43, 68, 36, 62, 86, 60, 30, -12, -34, -80, -119, -76, -44, -24, -5, 24, + 64, 51, 50, 76, 72, 48, 0, -34, -68, -106, -94, -56, -26, -7, 11, 45, + 59, 58, 66, 71, 60, 23, -27, -68, -93, -93, -72, -37, -8, 10, 25, 50, + 70, 68, 62, 62, 45, -10, -70, -88, -83, -79, -57, -15, 15, 13, 31, 73, + 80, 59, 53, 61, 15, -67, -89, -73, -75, -75, -33, 21, 11, 10, 66, 92, + 65, 42, 63, 42, -56, -92, -66, -66, -84, -57, 16, 19, -5, 50, 98, 76, + 39, 56, 60, -35, -95, -64, -53, -84, -79, 0, 28, -8, 29, 96, 89, 42, + 46, 69, -10, -90, -69, -41, -74, -95, -25, 28, -1, 13, 81, 101, 53, 37, + 69, 11, -77, -75, -38, -53, -103, -55, 22, 8, 6, 61, 104, 75, 29, 59, + 31, -61, -76, -43, -36, -91, -88, 6, 17, 1, 46, 96, 94, 34, 40, 48, + -40, -80, -47, -27, -69, -107, -27, 26, 4, 29, 87, 105, 51, 24, 46, -10, + -76, -58, -21, -49, -107, -62, 17, 16, 17, 70, 110, 67, 22, 38, 10, -60, + -71, -24, -28, -97, -85, -6, 25, 18, 50, 106, 84, 28, 31, 16, -38, -71, + -38, -17, -78, -94, -30, 15, 30, 41, 86, 92, 44, 31, 15, -25, -54, -53, + -26, -57, -88, -51, -2, 33, 45, 68, 88, 59, 35, 17, -15, -42, -55, -41, + -48, -73, -60, -19, 24, 50, 61, 74, 67, 46, 21, -8, -32, -48, -54, -53, + -57, -57, -34, 9, 50, 63, 59, 65, 58, 29, -1, -24, -38, -62, -67, -48, + -47, -40, -8, 43, 68, 48, 58, 66, 38, 6, -19, -26, -62, -85, -45, -35, + -39, -21, 28, 72, 41, 47, 74, 45, 15, -14, -17, -53, -102, -50, -24, -36, + -26, 10, 69, 42, 32, 81, 52, 21, -4, -15, -39, -109, -64, -12, -35, -26, + -1, 54, 47, 21, 79, 65, 20, 7, -12, -33, -100, -82, -8, -27, -32, -2, + 36, 47, 21, 66, 77, 25, 12, -2, -36, -88, -87, -18, -16, -36, -8, 27, + 36, 30, 56, 77, 39, 12, 6, -33, -84, -79, -30, -11, -29, -20, 19, 27, + 31, 58, 66, 50, 21, 5, -25, -81, -75, -32, -17, -17, -27, 2, 24, 28, + 61, 61, 48, 35, 4, -22, -71, -77, -31, -19, -12, -23, -18, 16, 29, 59, + 65, 45, 41, 10, -23, -59, -76, -37, -14, -11, -18, -29, -2, 29, 57, 68, + 51, 37, 16, -21, -55, -67, -44, -12, -5, -21, -29, -19, 19, 59, 68, 61, + 36, 14, -12, -55, -61, -44, -16, 3, -21, -29, -25, 0, 55, 72, 69, 43, + 8, -6, -49, -63, -39, -18, 5, -15, -31, -26, -18, 39, 78, 75, 53, 8, + -8, -40, -67, -37, -15, 2, -8, -30, -26, -29, 16, 79, 84, 59, 14, -11, + -33, -66, -42, -9, -2, -6, -23, -26, -33, -7, 66, 94, 67, 22, -9, -32, + -62, -48, -8, 0, -9, -16, -20, -35, -24, 46, 96, 78, 31, -2, -29, -59, + -51, -13, 1, -10, -13, -9, -31, -35, 23, 86, 88, 42, 5, -22, -57, -53, + -18, -3, -10, -13, 0, -19, -44, 2, 69, 90, 57, 12, -13, -50, -57, -21, + -9, -13, -13, 1, -3, -41, -17, 51, 82, 69, 23, -9, -37, -57, -25, -12, + -22, -15, 0, 10, -25, -32, 32, 69, 71, 37, -4, -25, -48, -30, -12, -32, + -23, -3, 14, -2, -33, 11, 56, 63, 49, 3, -18, -32, -31, -13, -37, -38, + -9, 11, 17, -16, -6, 41, 53, 51, 11, -17, -15, -23, -14, -35, -54, -22, + 4, 26, 10, -10, 26, 43, 46, 19, -19, -6, -5, -10, -30, -65, -42, -9, + 24, 35, 3, 12, 32, 37, 24, -20, -8, 14, 2, -23, -68, -62, -26, 10, + 50, 28, 11, 22, 27, 24, -19, -19, 24, 21, -8, -63, -78, -45, -11, 47, + 53, 23, 21, 19, 22, -17, -34, 21, 40, 15, -48, -89, -65, -34, 30, 68, + 44, 27, 16, 16, -11, -47, 3, 49, 39, -22, -89, -82, -55, 3, 68, 61, + 44, 21, 11, -6, -53, -21, 45, 56, 11, -74, -96, -72, -26, 52, 73, 60, + 39, 10, -3, -48, -44, 27, 61, 42, -43, -101, -88, -52, 27, 73, 70, 59, + 21, -1, -40, -60, 2, 52, 60, -4, -90, -100, -74, -2, 62, 72, 76, 42, + 5, -30, -66, -22, 34, 63, 33, -62, -104, -92, -31, 44, 68, 84, 66, 21, + -21, -64, -41, 13, 54, 55, -26, -94, -104, -57, 20, 56, 82, 84, 43, -6, + -57, -54, -10, 36, 60, 7, -70, -107, -78, -6, 40, 73, 92, 66, 12, -45, + -57, -27, 16, 52, 29, -41, -96, -90, -32, 20, 60, 91, 83, 34, -27, -52, + -37, -3, 34, 36, -15, -77, -91, -52, -1, 43, 83, 93, 53, -5, -42, -40, + -17, 14, 32, 1, -54, -81, -65, -21, 23, 71, 96, 67, 16, -25, -37, -24, + -5, 21, 6, -36, -64, -69, -37, 3, 54, 93, 73, 35, -6, -28, -25, -19, + 8, 4, -27, -46, -65, -46, -14, 34, 86, 73, 49, 15, -17, -19, -28, -4, + -3, -28, -32, -56, -48, -24, 15, 74, 67, 55, 36, -2, -10, -28, -14, -9, + -36, -25, -42, -50, -29, 1, 60, 59, 50, 55, 16, -3, -22, -20, -14, -46, + -29, -28, -48, -33, -5, 47, 50, 40, 64, 40, 4, -14, -17, -19, -53, -40, + -18, -40, -41, -6, 39, 39, 28, 61, 62, 17, -10, -7, -21, -59, -53, -20, + -28, -47, -11, 38, 29, 15, 52, 77, 36, -6, 1, -12, -63, -66, -25, -20, + -46, -19, 37, 28, 0, 38, 83, 54, 5, 5, -2, -57, -81, -34, -15, -44, + -22, 29, 31, -4, 16, 85, 68, 17, 15, 1, -44, -87, -54, -8, -42, -27, + 25, 24, 2, 0, 69, 88, 24, 25, 11, -42, -76, -75, -14, -25, -40, 23, + 18, -3, 3, 42, 96, 45, 22, 29, -39, -70, -75, -40, -8, -39, 7, 24, + -17, 8, 33, 79, 76, 22, 35, -21, -75, -64, -60, -15, -17, -14, 21, -21, + -4, 40, 59, 88, 45, 24, -3, -71, -61, -59, -38, 1, -14, 0, -17, -18, + 41, 54, 82, 74, 22, -3, -53, -61, -53, -54, -2, 3, -19, -25, -22, 30, + 57, 73, 92, 38, -15, -40, -51, -50, -58, -17, 17, -23, -44, -22, 19, 55, + 72, 97, 60, -22, -40, -35, -45, -55, -32, 14, -17, -60, -26, 11, 46, 75, + 97, 78, -17, -46, -23, -38, -45, -37, -1, -14, -66, -31, 3, 34, 80, 98, + 85, -4, -47, -19, -33, -33, -30, -20, -25, -63, -34, -4, 18, 79, 104, 84, + 9, -38, -18, -29, -27, -14, -30, -46, -63, -32, -5, 3, 68, 111, 84, 18, + -23, -12, -25, -28, -2, -25, -67, -75, -29, 1, -6, 46, 112, 91, 22, -11, + 0, -18, -33, -1, -9, -76, -96, -34, 9, -8, 22, 101, 102, 27, -2, 14, + -7, -36, -9, 4, -68, -114, -48, 13, -3, 5, 80, 109, 40, 4, 26, 6, + -33, -18, 6, -52, -120, -67, 7, 4, -1, 55, 103, 58, 14, 31, 17, -21, + -24, -4, -39, -110, -84, -10, 6, 2, 34, 87, 71, 29, 36, 25, -7, -23, + -16, -33, -96, -90, -29, -1, 6, 22, 68, 75, 45, 45, 31, 4, -15, -24, + -37, -84, -87, -43, -15, 3, 18, 53, 68, 57, 58, 38, 11, -7, -22, -45, + -81, -79, -48, -29, -10, 17, 45, 57, 61, 71, 50, 17, 0, -15, -49, -85, + -74, -45, -40, -25, 10, 42, 49, 55, 82, 65, 22, 7, -9, -43, -89, -80, + -34, -47, -40, -1, 35, 52, 43, 85, 84, 25, 17, -4, -38, -85, -92, -28, + -44, -55, -9, 21, 53, 42, 75, 100, 35, 22, 6, -38, -74, -99, -38, -34, + -65, -18, 12, 42, 51, 63, 102, 52, 25, 21, -36, -70, -90, -56, -30, -64, + -30, 7, 27, 55, 63, 90, 69, 33, 26, -26, -69, -79, -66, -43, -54, -37, + -1, 17, 49, 69, 79, 72, 50, 30, -15, -61, -75, -68, -58, -52, -33, -12, + 9, 42, 69, 78, 64, 60, 42, -9, -49, -71, -69, -68, -61, -25, -17, -1, + 38, 64, 77, 59, 62, 58, -3, -37, -62, -72, -72, -73, -24, -12, -11, 35, + 55, 73, 59, 58, 69, 8, -29, -48, -75, -76, -82, -31, -4, -14, 28, 49, + 63, 61, 54, 73, 22, -21, -36, -71, -82, -88, -42, 0, -9, 21, 43, 53, + 57, 56, 73, 33, -12, -25, -62, -89, -95, -49, -2, -2, 18, 37, 43, 49, + 60, 75, 38, -2, -16, -49, -89, -105, -54, -7, 1, 19, 31, 37, 38, 59, + 81, 39, 4, -7, -35, -83, -115, -62, -10, 0, 20, 27, 32, 30, 53, 87, + 43, 4, 0, -24, -70, -118, -75, -12, -2, 19, 24, 27, 27, 45, 89, 52, + 4, 1, -14, -55, -113, -87, -18, -3, 13, 20, 24, 28, 41, 85, 60, 7, + -3, -9, -40, -100, -91, -28, -4, 7, 10, 21, 30, 43, 82, 62, 13, -8, + -11, -26, -85, -87, -36, -10, 2, -4, 14, 35, 47, 81, 62, 18, -9, -21, + -20, -65, -78, -38, -19, -4, -16, 0, 39, 54, 85, 65, 20, -7, -31, -24, + -47, -62, -33, -26, -15, -25, -19, 35, 63, 90, 73, 22, -3, -39, -39, -35, + -43, -20, -26, -30, -34, -36, 24, 71, 94, 85, 29, -3, -40, -58, -34, -24, + -4, -16, -46, -47, -47, 6, 73, 100, 97, 42, -4, -39, -73, -45, -8, 12, + 0, -51, -64, -56, -13, 66, 104, 106, 64, 2, -40, -82, -63, -3, 27, 18, + -43, -82, -68, -28, 51, 104, 112, 86, 19, -42, -86, -81, -10, 40, 34, -26, + -90, -86, -41, 31, 98, 116, 104, 46, -38, -92, -95, -25, 46, 48, -6, -84, + -105, -55, 13, 84, 117, 114, 76, -20, -95, -105, -45, 41, 54, 8, -65, -112, + -70, -1, 65, 109, 115, 100, 14, -85, -106, -62, 21, 50, 13, -44, -104, -84, + -14, 45, 98, 112, 111, 53, -62, -105, -75, -3, 44, 12, -31, -85, -93, -27, + 27, 82, 110, 110, 81, -27, -95, -81, -27, 31, 11, -31, -66, -90, -39, 12, + 61, 106, 107, 94, 12, -73, -79, -48, 11, 13, -32, -57, -78, -46, -1, 38, + 97, 109, 96, 43, -41, -69, -62, -13, 13, -30, -58, -68, -46, -11, 17, 81, + 112, 97, 59, -7, -51, -67, -37, 6, -23, -62, -67, -42, -14, 2, 60, 110, + 99, 65, 20, -24, -63, -56, -7, -15, -63, -75, -40, -12, -8, 39, 102, 103, + 67, 35, 6, -48, -68, -25, -11, -56, -85, -46, -7, -10, 22, 86, 107, 72, + 41, 29, -25, -70, -42, -14, -42, -91, -62, -5, -6, 9, 67, 105, 84, 40, + 40, 3, -64, -56, -23, -30, -83, -85, -12, 3, 1, 50, 97, 96, 44, 36, + 28, -45, -69, -33, -22, -67, -101, -34, 13, 2, 31, 88, 104, 56, 28, 37, + -16, -71, -51, -18, -49, -103, -62, 9, 14, 18, 70, 109, 68, 26, 36, 6, + -58, -68, -23, -28, -97, -84, -7, 23, 19, 50, 106, 84, 28, 31, -21, -26, + -18, -30, -24, -77, -76, -48, -46, 31, 0, -1, 0, 0, 2, 0, 1, -2, + 1, 0, -6, -7, -5, -3, 0, -3, -4, -2, 2, 0, -8, -11, -14, -10, + -8, -4, 6, 13, 14, 9, 2, -6, -10, -9, -6, 9, 17, 15, 8, 0, + 1, -4, -12, -19, -14, -8, -4, 3, 6, -2, -4, -6, -7, -10, -8, -12, + -11, 3, 23, 27, 11, 4, -3, -5, 0, -9, -3, 6, 11, 19, 4, -8, + -17, -20, -21, -3, 5, 8, 2, 3, 5, 2, -3, -3, -12, 4, 1, 3, + -7, 0, 5, 6, 0, -7, -8, -5, -7, -5, -3, 4, 9, 5, -5, -5, + -5, -17, -7, 3, 17, 15, 7, -2, -5, -3, 3, -8, -5, -3, 3, 8, + 12, 5, -10, -27, -20, 1, 5, -4, -9, -17, 4, 10, 9, -2, -12, -16, + -12, -2, 8, 16, 13, 11, 16, 19, 10, -2, -16, -21, -11, 14, 15, 21, + 11, 6, -10, -8, -11, -24, -35, -31, -13, 9, 24, 17, -2, -11, -20, -11, + -19, -7, 3, 8, 22, 21, 21, 2, -7, -10, 12, 24, 18, -3, -19, -6, + 0, -5, -18, -17, 6, 12, 7, -16, -20, -22, -27, -19, -14, 12, 14, 3, + 0, 2, 8, -3, -5, -3, 21, 29, 17, 6, -8, 3, 3, 10, 10, 3, + 12, 4, -9, -18, -20, -20, -9, 6, 3, -9, -7, -14, -9, -8, -9, -23, + -19, 7, 17, 20, 9, 8, 5, 9, 18, 9, 8, -10, -10, -4, 9, 25, + -6, -19, -19, -5, -4, -7, -7, -17, -15, -7, -4, 0, 2, -2, -17, -4, + 14, 23, 15, 2, -7, -5, 9, 11, 1, 0, -3, 0, 0, 15, 14, -4, + -15, -20, -26, -22, -13, 0, 6, 12, 5, -10, 2, 8, -2, -18, -8, 6, + 20, 28, 23, 0, -16, -7, 9, 7, 10, -12, -21, -19, 7, 12, 4, -17, + -28, -24, -3, 14, 4, -19, -18, -9, 11, 22, 16, -13, -23, -15, 18, 32, + 32, 17, -4, 1, 14, 11, 1, -20, -19, -3, 9, 13, -4, -13, -16, -18, + -23, -12, -17, -16, -20, -15, -14, -4, 8, 12, 0, 8, 5, 12, 17, 26, + 25, 14, 10, 11, 11, 18, 15, 4, -9, -13, -8, -9, -14, -20, -28, -32, + -12, -9, -16, -17, -24, -18, -12, 5, 10, 4, 6, 8, 18, 35, 31, 17, + 1, 12, 21, 33, 18, 6, -10, -11, -4, -9, -13, -19, -24, -24, -24, -18, + -20, -18, -20, -13, -15, -10, -9, -5, 8, 10, 13, 23, 26, 29, 14, 13, + 13, 13, 16, 25, 19, 17, 4, -15, -18, -15, -14, -17, -34, -23, -16, -12, + -16, -26, -33, -23, -15, -4, 4, 10, 16, 19, 22, 29, 28, 7, 1, 2, + 18, 26, 30, 21, 9, 3, -4, -10, -16, -29, -31, -27, -4, -9, -11, -28, + -23, -17, -15, -13, -11, 4, 11, 9, 13, 16, 25, 18, 8, 10, 18, 17, + 8, 18, 17, 11, -5, -19, -17, -12, -19, -38, -27, -8, 0, -3, -14, -19, + -20, -14, -10, -13, -3, 6, 12, 26, 38, 34, 14, 2, -2, 11, 19, 14, + 8, 5, 16, 9, -7, -19, -24, -29, -36, -26, -13, -12, -22, -28, -20, 5, + -3, -10, -19, 7, 20, 18, 17, 24, 25, 14, 18, 19, 29, 21, 11, 10, + 9, 13, -13, -29, -27, -20, -24, -30, -22, -12, -7, -15, -22, -21, -13, -14, + -20, -8, 12, 26, 25, 21, 33, 27, 25, 16, 13, 16, 16, -2, 2, 11, + 9, -2, -17, -18, -16, -25, -25, -26, -27, -30, -35, -30, -12, -6, -6, -6, + -5, 19, 19, 11, 15, 17, 24, 23, 34, 28, 23, 13, 2, 9, 18, 16, + -14, -18, -12, -7, -9, -31, -37, -33, -24, -14, -24, -20, -16, -21, -15, -7, + 5, 9, 15, 20, 28, 38, 29, 21, 15, 22, 17, 4, 12, 6, 12, -4, + -9, -15, -16, -19, -40, -38, -34, -23, -18, -17, -8, -10, -3, -7, 1, 3, + 4, 11, 13, 36, 41, 36, 24, 9, 17, 20, 21, 14, -5, -9, -11, -8, + -19, -14, -24, -30, -23, -18, -25, -30, -24, -17, -20, -9, -3, 6, 8, 22, + 23, 20, 27, 18, 10, 10, 14, 18, 14, 23, 17, 6, 5, -4, -8, -26, + -19, -24, -25, -24, -21, -27, -28, -15, -19, -16, -9, 0, 7, 9, 17, 14, + 15, 24, 30, 29, 29, 32, 16, 10, 8, 0, -3, -10, -7, -17, -22, -25, + -30, -36, -32, -25, -26, -22, -12, -16, -11, -3, 5, 7, 13, 21, 21, 26, + 32, 28, 26, 28, 31, 17, 15, 15, 5, -4, -14, -18, -28, -25, -24, -28, + -32, -33, -32, -29, -18, -17, -20, -10, -4, 6, 6, 18, 22, 22, 37, 38, + 31, 27, 26, 23, 22, 23, 12, 4, -5, -2, -11, -19, -25, -35, -35, -36, + -36, -43, -32, -24, -20, -12, -7, -3, -7, 3, 13, 23, 29, 35, 37, 35, + 42, 33, 26, 22, 17, 12, 6, 4, -9, -23, -28, -34, -34, -33, -31, -40, + -36, -27, -25, -22, -30, -20, -11, 2, 12, 22, 22, 26, 28, 35, 47, 44, + 27, 29, 29, 29, 19, 2, 1, -9, -15, -21, -34, -35, -34, -40, -44, -42, + -34, -31, -26, -21, -9, -12, -3, 10, 17, 29, 26, 27, 34, 48, 50, 34, + 33, 25, 21, 16, 8, 3, -8, -11, -25, -30, -37, -37, -42, -51, -34, -28, + -21, -26, -25, -19, -13, 4, 9, 17, 29, 41, 33, 33, 44, 45, 32, 31, + 28, 22, 16, 5, -10, -13, -16, -23, -38, -39, -39, -45, -54, -40, -32, -24, + -22, -17, -14, 0, 6, 9, 18, 41, 43, 34, 32, 40, 40, 31, 30, 27, + 22, 19, 14, -2, -16, -21, -34, -48, -45, -41, -41, -41, -45, -38, -25, -21, + -17, -20, -7, 11, 17, 19, 36, 40, 42, 44, 47, 46, 39, 33, 26, 15, + 11, 8, -5, -19, -24, -29, -40, -44, -48, -44, -37, -37, -43, -43, -26, -19, + -14, -2, 13, 23, 31, 36, 36, 43, 41, 47, 46, 44, 40, 24, 15, 14, + 3, -12, -21, -23, -30, -36, -47, -51, -50, -47, -44, -46, -31, -19, -16, -11, + 2, 16, 20, 25, 29, 40, 53, 51, 49, 45, 41, 35, 25, 18, 7, 5, + -12, -18, -23, -34, -39, -56, -58, -54, -49, -50, -45, -35, -26, -12, -5, 6, + 17, 29, 41, 42, 47, 50, 46, 49, 50, 50, 39, 30, 16, 2, -8, -15, + -21, -30, -41, -49, -50, -46, -57, -63, -57, -41, -29, -24, -12, -3, 5, 12, + 22, 33, 41, 50, 51, 53, 57, 55, 46, 36, 29, 16, 2, -4, -11, -21, + -33, -40, -49, -47, -53, -60, -58, -51, -42, -34, -23, -13, -2, 5, 17, 27, + 39, 49, 48, 51, 56, 54, 58, 44, 37, 28, 18, 4, -3, -15, -29, -39, + -49, -49, -51, -62, -65, -64, -47, -42, -36, -26, -14, -5, 10, 24, 32, 45, + 50, 49, 62, 65, 63, 47, 42, 41, 36, 23, 7, -7, -22, -31, -41, -53, + -58, -62, -59, -62, -56, -54, -50, -44, -32, -16, 0, 11, 25, 35, 50, 54, + 55, 56, 66, 65, 62, 54, 45, 36, 23, 14, -4, -22, -44, -55, -52, -62, + -61, -66, -70, -68, -60, -54, -45, -29, -15, 4, 21, 34, 36, 44, 54, 62, + 70, 73, 68, 67, 59, 50, 37, 21, -5, -12, -25, -39, -48, -53, -63, -76, + -73, -71, -71, -67, -57, -45, -29, -12, 2, 13, 30, 42, 51, 61, 76, 71, + 63, 66, 71, 60, 50, 40, 23, -2, -9, -20, -41, -54, -59, -72, -79, -71, + -64, -73, -68, -60, -51, -36, -13, 2, 13, 27, 47, 54, 71, 78, 71, 60, + 72, 74, 65, 54, 39, 28, 7, -6, -23, -50, -59, -64, -69, -75, -70, -78, + -74, -73, -64, -52, -37, -13, 6, 18, 40, 51, 58, 64, 78, 79, 75, 68, + 64, 68, 57, 45, 21, 4, -16, -34, -50, -65, -75, -83, -80, -71, -69, -68, + -73, -63, -57, -36, -16, 6, 26, 45, 60, 70, 71, 79, 79, 81, 78, 80, + 64, 55, 36, 16, -4, -23, -38, -54, -63, -69, -81, -85, -87, -76, -72, -66, + -61, -52, -30, -12, 12, 24, 44, 55, 69, 78, 85, 84, 74, 70, 71, 71, + 62, 41, 17, -11, -25, -42, -55, -66, -75, -87, -87, -81, -74, -76, -76, -63, + -48, -32, -13, 7, 30, 51, 64, 76, 80, 82, 83, 81, 80, 82, 70, 61, + 42, 19, 0, -28, -49, -61, -72, -78, -87, -90, -89, -88, -87, -82, -69, -54, + -33, -13, 15, 36, 58, 68, 79, 90, 96, 90, 84, 86, 89, 79, 62, 38, + 22, -3, -29, -55, -69, -81, -89, -94, -94, -94, -94, -89, -74, -62, -52, -35, + -18, 14, 39, 54, 65, 76, 87, 98, 95, 94, 90, 82, 75, 69, 47, 26, + -6, -33, -57, -72, -82, -88, -97, -90, -91, -88, -83, -80, -75, -59, -33, -9, + 20, 42, 58, 68, 82, 90, 94, 93, 94, 88, 85, 77, 65, 43, 16, -10, + -37, -60, -71, -84, -89, -95, -97, -102, -95, -84, -80, -72, -57, -26, -4, 19, + 42, 62, 80, 89, 94, 97, 100, 99, 90, 83, 71, 65, 39, 14, -9, -43, + -65, -83, -90, -95, -98, -96, -100, -96, -88, -76, -66, -51, -24, -12, 21, 45, + 70, 85, 93, 95, 97, 101, 105, 92, 84, 69, 58, 35, 16, -14, -44, -68, + -86, -88, -96, -101, -101, -102, -97, -90, -74, -69, -50, -19, 9, 35, 56, 76, + 84, 92, 98, 96, 99, 97, 93, 84, 77, 59, 24, 2, -30, -52, -76, -87, + -93, -98, -100, -102, -100, -96, -89, -81, -73, -46, -18, 12, 36, 62, 82, 88, + 96, 104, 107, 105, 102, 92, 84, 77, 53, 26, -6, -35, -57, -75, -81, -92, + -103, -114, -111, -108, -98, -88, -83, -67, -35, -7, 20, 39, 60, 70, 89, 106, + 116, 107, 103, 99, 86, 90, 82, 53, 18, -13, -31, -52, -73, -92, -102, -106, + -104, -97, -106, -99, -101, -92, -72, -42, -5, 16, 38, 66, 86, 101, 99, 101, + 95, 112, 107, 99, 95, 81, 53, 16, -3, -29, -60, -81, -102, -98, -102, -102, + -112, -114, -101, -104, -88, -69, -34, -8, 14, 41, 67, 92, 94, 99, 103, 104, + 115, 109, 103, 90, 78, 52, 22, 0, -39, -65, -92, -95, -91, -103, -104, -118, + -110, -102, -93, -84, -71, -36, -15, 19, 52, 81, 94, 89, 98, 103, 115, 117, + 102, 92, 83, 80, 49, 23, -11, -43, -67, -90, -93, -102, -105, -110, -118, -104, + -100, -89, -83, -64, -36, -7, 28, 50, 74, 88, 95, 104, 103, 115, 107, 106, + 97, 87, 74, 50, 20, -17, -47, -75, -89, -93, -101, -102, -115, -117, -106, -97, + -88, -90, -73, -38, 2, 36, 60, 75, 84, 96, 104, 115, 115, 102, 98, 96, + 96, 84, 52, 10, -12, -32, -53, -71, -87, -101, -109, -112, -109, -106, -105, -102, + -92, -74, -48, -19, 7, 33, 56, 76, 91, 101, 108, 111, 111, 108, 103, 96, + 85, 63, 33, 1, -27, -51, -73, -90, -102, -109, -112, -110, -107, -103, -100, -93, + -76, -50, -19, 10, 36, 58, 76, 91, 101, 108, 111, 111, 108, 103, 96, 85, + 63, 33, 1, -27, -51, -73, -90, -102, -109, -112, -110, -107, -103, -100, -93, -76, + -50, -19, 10, 36, 58, 76, -1, -2, -15, 21, -17, 23, -30, 1, 34, -34, + 6, 5, -15, 19, 1, -25, 6, 20, -2, -28, 15, 10, -15, 0, -7, 10, + 7, -5, -9, -6, 19, -3, -21, 3, 20, -4, -20, 1, 16, -3, -8, -2, + 5, 1, -8, -6, 3, 9, 2, -13, -4, 15, -7, -9, 0, 3, 6, -7, + -7, 5, 8, -8, -4, 0, 1, 1, -6, -4, 7, 2, -2, -7, 0, 4, + -3, -4, 0, 2, 0, -2, -4, 1, 4, -2, -4, -3, 1, 3, -5, -4, + 4, 3, -6, -5, 4, -1, -2, -3, 0, 3, -3, -1, -4, 3, 3, -5, + -3, 1, 1, -2, -3, 1, 2, -2, -4, 0, 0, 0, -1, -3, 1, 1, + -3, -2, 1, 0, -2, -2, 0, 0, -2, -1, 0, -1, 1, -2, -2, 1, + 0, -2, 0, -1, 0, -1, -1, -1, 0, 0, -1, -3, 1, 1, -2, -2, + 0, 1, -1, -2, -1, 0, 0, 0, -2, -1, 1, 0, -3, 0, 2, -1, + -2, 0, 0, 0, -2, 0, -1, 0, -1, -1, 1, 0, -1, 0, -1, 1, + 0, -13, 5, 7, -11, 24, -50, 41, 4, -29, 14, -11, 8, 11, -15, -12, + 15, 18, -21, -14, 22, -2, -11, -3, -3, 18, -3, -5, -14, 9, 22, -24, + -16, 23, 12, -23, -8, 9, 10, -4, -8, -3, 11, -4, -14, 0, 8, 8, + -5, -14, 8, 10, -12, -4, -2, 10, 0, -11, -3, 11, 0, -7, -2, -1, + 7, -6, -8, 3, 6, 0, -3, -8, 7, 2, -7, -2, 2, 1, -2, -4, + -1, 3, 3, -4, -5, 1, 3, -3, -6, 2, 5, -1, -7, -1, 3, -1, + -4, -3, 5, 0, -3, -2, -1, 4, -1, -5, -1, 3, -1, -4, -1, 3, + 1, -4, -2, 1, 0, -2, -3, 0, 2, -1, -4, 1, 1, -1, -2, -2, + 1, -1, -3, 0, 0, 0, -1, -2, 0, 0, -2, -1, 0, -1, 0, -2, + -1, 0, -1, 0, -1, -2, 2, -1, -2, -1, 0, 1, -2, 0, -1, -1, + 0, -1, -2, 0, 1, -1, -3, 0, 1, -1, -3, 0, 1, -2, -1, 0, + 0, -1, -1, 0, -1, -1, -1, -1, 0, 0, -1, -1, 0, 0, -2, 0, + 0, 0, 0, -2, 1, -1, 0, -1, 0, 0, 0, -1, 0, 0, 0, 0, + -1, 0, 0, -1, 0, -1, 1, 0, 0, 0, 1, -1, -1, 0, 0, 0, + 1, -2, 4, -3, 3, -40, 71, -73, 67, -27, -68, 127, -80, 3, 5, 1, + 17, -14, 1, -30, 53, -3, -42, 15, 19, -9, -17, -1, 13, 16, -17, 4, + -32, 43, 15, -68, 18, 54, -38, -7, -1, 11, 7, -3, -18, 5, 25, -27, + -9, 9, 19, -6, -12, -8, 20, -1, -15, -1, 1, 17, -10, -16, 12, 12, + -13, 0, -6, 10, 2, -16, -1, 14, -4, 4, -11, -2, 12, -6, -8, 4, + 4, -2, -4, 1, -2, 4, 3, -7, -5, 8, 0, -10, 1, 4, 2, -4, + -6, 4, 1, -1, -7, 1, 8, -9, 2, -5, 3, 3, -4, -3, 0, 3, + -3, -5, 4, 3, -3, -4, 0, 2, 0, -3, -4, 5, 0, -5, -1, 2, + 0, -3, 0, -1, 2, -2, -4, 3, 0, -1, -2, -1, 2, -2, -2, 1, + -1, 0, -1, -3, 1, 1, -2, 1, -3, 1, 1, -3, -1, 1, 0, -1, + -2, 1, -1, -1, 1, -2, 1, -1, -1, -1, -1, 0, 1, -3, 0, 0, + 1, -4, 0, 1, -2, 0, -2, 0, 0, 0, -2, 1, -1, 0, -2, 0, + 2, -2, -1, 0, -1, 2, -2, -1, 1, -2, 0, -1, 1, -1, -1, -1, + 1, -2, 1, -1, -1, 2, -3, 0, 0, -1, 1, -1, 0, 1, 0, -2, + 0, -1, 1, -2, 0, 0, -1, 1, 0, -2, 0, 1, -2, 1, 0, 0, + -1, 0, 1, -1, -1, -1, 1, 1, -1, 0, 0, 0, -1, 1, 0, -1, + 1, 0, 0, 1, 0, -1, 1, 0, 3, -40, 58, -39, 12, 42, -117, 108, + 1, -66, 22, 17, 0, -9, 10, -39, 42, 4, -23, -12, 28, 3, -34, 9, + 17, 3, -9, 10, -29, 13, 53, -79, 3, 64, -26, -24, 16, -9, 14, 2, + -8, -15, 31, -9, -30, 11, 29, -15, -7, 0, 3, 6, -4, -9, -6, 22, + 1, -24, 9, 11, -8, 0, -2, 2, 8, -12, -6, 10, 2, 2, -9, -4, + 11, -2, -10, 3, 2, 3, -5, -1, 1, -1, 6, -4, -8, 9, 2, -8, + -3, 6, 3, -4, -3, -1, 6, -2, -8, 0, 9, -4, -3, -2, 2, 4, + -4, -1, -1, 4, -2, -6, 4, 2, -1, -4, 0, 1, 2, -3, -5, 3, + 3, -3, -4, 3, 0, -1, 0, -2, 2, 0, -3, 0, 3, 0, -3, -1, + 2, 0, -3, 1, 0, -1, 2, -2, -2, 2, -1, 0, -1, -1, 1, -1, + -2, 0, 0, 1, -3, 1, 0, -1, 1, -2, -1, 2, -2, -1, 0, -1, + 2, -3, -1, 1, 1, -2, -2, 2, 1, -2, -1, 0, 0, 1, -3, 1, + 0, 0, 0, -2, 3, 0, -2, 0, 0, 1, 0, -1, 1, -2, 0, 0, + 0, -1, 1, 0, 0, 0, -1, 1, -1, 1, 0, -1, 1, -2, 0, 1, + 1, 0, 1, -2, 1, 0, 1, 0, 0, 3, -1, 0, 1, 0, 0, 3, + -29, 35, -12, -16, 56, -88, 39, 62, -79, 5, 29, 1, -13, 12, -29, 26, + 17, -28, -3, 12, 5, -11, -19, 28, 1, -5, 9, -21, -7, 60, -56, -20, + 57, -10, -27, 21, -21, 16, 12, -12, -21, 24, 6, -29, 4, 19, 2, -7, + -5, -3, 7, 6, -11, -9, 11, 13, -18, -4, 13, 1, -3, -6, -1, 10, + -8, -6, 5, 3, 5, -3, -11, 4, 9, -11, 0, 4, 3, -4, -1, 0, + 0, 7, 0, -14, 7, 5, -7, -4, 4, 5, -1, -4, -4, 4, 1, -4, + -4, 7, -1, -1, -3, 0, 5, -1, -4, -1, 2, 0, -3, 1, 1, 2, + -2, -4, 1, 2, 0, -5, 2, 3, -2, -2, 1, 1, -2, 2, -3, 0, + 0, -1, -1, 0, 1, 0, -3, 0, 0, -1, 1, -1, -2, 1, -1, 0, + -2, 2, 1, -2, -1, 1, 0, -1, -1, 0, 1, -1, 0, -2, 1, 1, + -1, 0, -1, -1, 0, 0, -1, -1, 0, -1, -1, 2, -2, -1, 1, 0, + 0, -1, -1, 1, 0, -1, 1, -1, 0, 1, -3, 1, 1, -1, -1, 0, + 1, 0, 0, 0, -1, 0, 0, -1, 0, 1, 0, 0, 2, -2, 0, 1, + 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, -1, -1, -7, -9, 35, -52, + 59, -33, -32, 64, -15, -41, 19, 22, -20, 9, -11, -3, 33, -27, 2, 7, + -9, 19, -37, 24, 7, -11, 11, -1, -30, 37, 8, -57, 36, 19, -33, 14, + 0, -17, 26, 1, -20, -5, 26, -18, -13, 14, 7, -6, 4, -9, -4, 11, + 3, -14, -7, 20, 0, -18, 10, 1, 4, -5, -7, 6, 0, -3, -2, -2, + 8, 5, -11, -6, 10, -1, -10, 6, -2, -1, 1, -3, 0, 3, 5, -9, + -5, 9, -3, -4, 1, 1, 3, -1, -4, -1, 2, -2, -5, 5, -3, 0, + 1, -5, 4, 2, -3, -3, 0, 0, -2, 1, 0, -2, 3, -2, -5, 2, + 2, -2, -4, 3, 0, -2, 1, -2, -2, 5, -2, -6, 1, 2, -1, -1, + 0, 1, -1, -2, -1, -1, 2, 0, -4, 0, 1, 0, -3, 0, 2, 0, + -3, 0, 0, 1, -1, -1, 1, 0, -1, -2, 1, 0, 0, -1, 0, -2, + 1, 0, -1, 1, -1, 0, -2, 1, 1, -2, -1, 2, -2, 1, -3, 1, + 1, -1, 0, 0, -1, 1, 0, -2, 2, -1, -1, 0, 0, 1, 0, 1, + 0, -2, 1, 0, 0, -1, 1, 0, 0, 0, 0, -3, -20, 45, -56, 40, + -5, -34, 27, 24, -42, -1, 29, -14, -4, 2, -7, 24, -20, -1, 18, -25, + 25, -29, 9, 21, -26, 14, 4, -20, 7, 27, -42, 5, 31, -24, -2, 19, + -30, 21, 8, -11, -17, 20, 1, -22, 11, 7, -7, 6, -5, -7, 3, 11, + -6, -18, 11, 16, -20, 1, 5, 2, -3, -3, 0, -3, 4, -1, -7, 2, + 10, -9, -8, 7, 2, -9, 5, -1, -5, 2, 1, -3, -2, 9, -5, -8, + 4, 1, -5, 0, 1, 2, -1, 0, -5, 4, -1, -5, 4, -3, 1, 1, + -5, 3, 0, 0, -3, 0, -1, -2, 1, 2, -5, 2, 1, -5, -2, 3, + -1, -5, 2, 1, -4, 2, -1, -4, 2, 3, -7, -1, 2, 0, -2, 1, + 0, -2, -1, 0, -3, 1, 2, -3, -2, 3, 0, -3, -1, 1, 0, -1, + -2, -1, 1, 0, 0, -1, 0, 0, -2, 0, 0, 1, -2, 2, -3, 1, + 0, 0, -2, 1, 0, -1, 0, 0, -1, -1, 2, -3, 0, 0, -1, 0, + 0, -1, 1, 0, -4, -13, 32, -41, 31, -10, -10, 4, 22, -25, -8, 21, + -3, -14, 5, 1, 12, -23, 8, 18, -31, 25, -26, 10, 17, -23, 8, 5, + -9, 0, 16, -25, 2, 23, -22, -2, 22, -30, 15, 7, -6, -13, 12, 1, + -17, 9, 5, -6, 4, -3, -7, 5, 7, -6, -13, 7, 10, -11, 0, 0, + 4, -3, -3, 2, -7, 4, 2, -5, 0, 6, -3, -8, 4, 2, -8, 7, + 0, -8, -1, 6, 0, -8, 6, 0, -5, 1, 0, -5, 3, 2, -3, -2, + 4, -5, -1, -1, -2, 3, -4, 1, -1, -3, 3, -1, -2, -2, 1, -2, + -2, 1, 1, -4, 1, 2, -5, -3, 5, -3, -4, 4, -1, -4, 2, -1, + -4, 3, 1, -5, -2, 2, 0, -2, 2, -1, -4, 3, -1, -3, 0, 1, + -2, -2, 1, -1, -1, -1, 0, 0, -1, -1, -1, 0, -1, 1, -1, -1, + 0, -2, 1, 0, -1, -1, 0, -1, -1, -1, 2, -2, -1, 1, -1, -2, + 1, -1, -1, 1, -2, 1, -7, -3, 15, -23, 20, -16, 9, -12, 16, -12, + -8, 11, 5, -18, 6, 8, 0, -18, 16, 4, -19, 16, -17, 10, 5, -8, + -2, 9, -5, -4, 10, -17, 5, 13, -18, 2, 12, -17, 10, 0, -2, -8, + 7, -4, -7, 6, 1, -3, 1, 3, -9, -2, 10, -7, -8, 4, 6, -6, + 1, 0, 0, -2, 1, -1, -8, 6, 1, -5, 2, 4, -2, -4, 1, 1, + -7, 5, -1, -4, -2, 4, 0, -4, 4, -3, -4, 1, 0, -3, 0, 2, + -1, -2, 2, -2, -1, -3, 0, 3, -4, 3, -3, 0, 2, 0, -3, -1, + 1, -3, -1, 2, 0, -1, 0, 0, -3, 0, 1, -4, -1, 2, 0, -2, + 0, 1, -3, 1, 1, -3, -2, 2, -1, -1, 2, -1, -2, 1, 0, -1, + -1, -1, -3, -8, -16, -20, -7, 14, 20, 19, 18, 16, 11, 3, -9, -21, + -36, -43, -39, -24, 6, 38, 57, 55, 26, 0, -7, -10, -13, -12, -11, -29, + -56, -59, -37, 0, 43, 74, 87, 75, 37, -2, -31, -51, -59, -45, -15, -16, + -34, -20, -10, -5, 29, 61, 72, 51, 18, -2, -21, -39, -35, -24, 1, 0, + -31, -29, -23, -44, -13, 48, 82, 79, 46, 16, -4, -44, -58, -26, 3, 6, + -38, -52, -24, -42, -35, 47, 95, 88, 55, 19, 12, -22, -72, -38, 4, 3, + -31, -67, -29, -24, -60, 23, 112, 111, 72, 22, 7, -20, -90, -73, -1, 19, + -4, -57, -36, 3, -54, -32, 98, 125, 71, 14, 14, 0, -82, -106, 0, 42, + 10, -48, -32, -2, -54, -63, 72, 125, 82, 24, 14, -8, -57, -104, -22, 52, + 34, -34, -46, -16, -35, -83, 32, 127, 99, 26, 19, 4, -55, -110, -48, 45, + 36, -12, -26, -22, -41, -64, -7, 107, 113, 56, 6, 4, -41, -92, -74, 35, + 57, 12, -41, -21, -39, -67, -40, 86, 114, 71, 10, 22, -31, -83, -83, 16, + 46, 34, -28, -18, -42, -58, -60, 55, 108, 97, 3, 21, -8, -77, -102, 10, + 45, 42, -26, -2, -27, -68, -73, 45, 83, 92, 29, 25, -8, -56, -104, -13, + 35, 52, -6, -7, -22, -46, -91, 10, 80, 95, 35, 26, 8, -38, -106, -34, + 34, 42, 5, 1, -23, -39, -73, -28, 61, 89, 60, 20, 2, -7, -73, -86, + 24, 52, 26, -12, -11, -19, -58, -86, 46, 91, 62, 17, 22, -15, -39, -106, + 8, 55, 45, -13, -6, -30, -21, -102, 4, 82, 87, 7, 28, -3, -9, -115, + -32, 50, 63, -23, 8, -19, -18, -94, -28, 61, 96, 14, 39, -4, 1, -85, + -60, 23, 79, -3, 2, -20, -10, -82, -65, 25, 108, 28, 31, 19, 9, -65, + -74, -5, 78, 16, -3, -9, -14, -65, -76, -3, 93, 60, 29, 22, 13, -43, + -90, -30, 61, 49, -9, -1, 4, -52, -98, -16, 68, 72, 21, 38, 15, -31, + -94, -34, 32, 67, 5, 9, 0, -28, -111, -33, 40, 85, 24, 37, 23, -6, + -104, -44, 13, 69, 9, 14, 8, -11, -110, -53, 20, 80, 32, 48, 30, 5, + -87, -66, -7, 63, 33, 12, 2, 5, -86, -94, -2, 79, 46, 26, 44, 22, + -59, -88, -19, 54, 48, 13, 14, 4, -51, -112, -37, 67, 71, 21, 38, 29, + -29, -104, -50, 44, 63, 11, 10, 14, -24, -103, -67, 49, 88, 20, 27, 43, + -10, -90, -79, 24, 69, 21, 7, 18, -8, -82, -103, 17, 94, 38, 10, 54, + 12, -70, -97, 1, 68, 37, -4, 27, -6, -56, -104, -21, 82, 67, -3, 46, + 23, -37, -108, -31, 57, 58, -13, 29, 11, -32, -106, -50, 53, 92, -6, 38, + 38, -15, -105, -54, 34, 79, -12, 20, 22, -11, -98, -70, 22, 99, 4, 16, + 48, 14, -99, -75, 15, 82, 2, 0, 44, 8, -93, -80, 0, 84, 29, -3, + 57, 32, -79, -94, 1, 66, 27, -19, 49, 29, -73, -109, -7, 54, 52, -17, + 62, 53, -46, -113, -4, 43, 51, -30, 46, 37, -42, -128, -23, 26, 69, -18, + 51, 59, -2, -122, -30, 24, 66, -27, 31, 51, 1, -128, -48, 13, 71, -11, + 33, 66, 22, -110, -57, 8, 68, -9, 12, 53, 28, -104, -87, -4, 67, 8, + 8, 72, 53, -80, -91, -4, 59, 10, -13, 63, 44, -81, -109, -19, 46, 33, + -6, 76, 57, -43, -104, -24, 36, 42, -26, 55, 51, -34, -126, -39, 19, 58, + -21, 68, 71, -8, -114, -32, 2, 62, -24, 52, 54, -4, -120, -53, -22, 71, + -8, 49, 62, 31, -102, -52, -25, 70, -5, 24, 55, 35, -109, -69, -40, 59, + 16, 25, 65, 55, -80, -70, -37, 47, 23, 7, 48, 51, -73, -97, -48, 30, + 46, 6, 57, 74, -37, -98, -34, 21, 48, -10, 44, 58, -34, -123, -46, -2, + 61, 2, 50, 69, 10, -110, -40, -5, 59, -9, 31, 53, 19, -126, -59, -20, + 62, 8, 32, 64, 49, -105, -59, -16, 58, 2, 17, 50, 45, -102, -83, -31, + 46, 24, 15, 53, 69, -65, -86, -24, 42, 25, -4, 45, 64, -58, -112, -37, + 30, 41, -6, 51, 75, -24, -105, -32, 26, 41, -19, 39, 62, -14, -117, -51, + 7, 54, -13, 35, 78, 19, -105, -47, 9, 58, -19, 21, 69, 18, -113, -66, + -10, 52, -10, 14, 75, 42, -83, -60, -5, 52, 0, -3, 69, 43, -83, -83, + -21, 35, 17, -13, 72, 57, -54, -82, -10, 29, 28, -29, 65, 52, -45, -98, + -21, 1, 40, -30, 64, 63, -7, -94, -9, 1, 51, -36, 51, 54, -8, -115, + -23, -22, 47, -30, 48, 65, 24, -90, -13, -15, 46, -26, 30, 55, 21, -100, + -37, -26, 31, -10, 24, 65, 41, -71, -35, -10, 25, -2, 4, 58, 32, -69, + -61, -16, 2, 8, 1, 67, 42, -33, -56, -1, -1, 20, -13, 59, 33, -28, + -82, -10, -20, 22, -15, 64, 40, -1, -70, 0, -17, 29, -22, 53, 33, 1, + -84, -15, -29, 22, -19, 53, 43, 22, -64, -7, -19, 25, -18, 37, 38, 16, + -73, -30, -33, 11, -14, 32, 50, 31, -45, -17, -15, 16, -4, 16, 43, 23, + -49, -43, -30, -2, -1, 8, 52, 36, -25, -32, -13, -1, 11, -1, 42, 30, + -25, -49, -25, -18, 10, -7, 44, 40, -2, -34, -11, -15, 21, -6, 29, 33, + -5, -54, -29, -30, 13, -6, 29, 46, 15, -32, -10, -18, 16, -1, 13, 36, + 9, -45, -30, -32, 0, 1, 12, 43, 28, -23, -16, -16, 6, 9, 2, 33, + 22, -33, -34, -27, -11, 2, 1, 35, 36, -14, -16, -11, -5, 8, 3, 24, + 32, -19, -30, -29, -17, -4, 1, 20, 43, -5, -14, -13, -4, 0, 7, 11, + 39, -9, -23, -28, -17, -16, 1, 9, 44, 3, -7, -15, -4, -4, 7, 5, + 38, 3, -20, -30, -19, -19, -8, 0, 40, 17, -6, -7, -3, -2, -1, 4, + 32, 16, -20, -21, -26, -17, -18, -3, 28, 32, -7, -1, -9, 4, -9, 3, + 22, 34, -19, -14, -27, -13, -27, -10, 16, 44, -8, 5, -6, 3, -12, 1, + 13, 40, -12, -11, -25, -17, -27, -15, 5, 45, 4, 2, 0, 0, -9, -5, + 6, 38, 2, -17, -14, -20, -24, -23, 0, 38, 19, -4, 11, -4, -7, -10, + 4, 27, 20, -20, -9, -23, -22, -30, -6, 26, 35, -8, 12, 2, -4, -15, + 2, 20, 32, -16, -7, -15, -22, -37, -14, 18, 39, -3, 5, 8, -5, -18, + -2, 18, 34, -4, -14, -4, -21, -35, -25, 15, 36, 8, -4, 21, -5, -17, + -14, 23, 26, 9, -22, 4, -25, -32, -40, 14, 27, 24, -12, 30, 1, -8, + -26, 24, 21, 19, -28, 9, -20, -28, -51, 7, 23, 30, -15, 27, 9, -7, + -32, 16, 25, 23, -21, 4, -8, -27, -50, -10, 25, 29, -9, 13, 24, -7, + -28, -3, 34, 20, -12, -9, 10, -31, -43, -29, 30, 23, 2, -3, 38, -9, + -19, -19, 39, 18, -1, -20, 25, -29, -36, -42, 26, 17, 12, -14, 43, -3, + -15, -29, 35, 19, 6, -28, 27, -18, -36, -48, 16, 17, 15, -15, 39, 12, + -13, -29, 24, 24, 9, -25, 19, -1, -39, -50, 1, 18, 11, -11, 25, 26, + -14, -26, 12, 32, 10, -17, 6, 17, -33, -48, -14, 20, 6, -7, 11, 36, + -9, -26, -1, 34, 11, -9, -4, 25, -25, -49, -26, 19, 4, -4, 5, 41, + 3, -21, -8, 31, 12, -7, -11, 23, -13, -47, -37, 13, 6, -3, 1, 40, + 14, -17, -14, 26, 16, -2, -12, 20, -3, -40, -44, 2, 6, -2, -4, 35, + 24, -9, -19, 19, 17, 2, -13, 16, 5, -29, -48, -7, 4, 3, -7, 28, + 28, 2, -21, 13, 14, 9, -14, 11, 9, -15, -49, -17, -3, 6, -11, 20, + 30, 14, -23, 7, 12, 14, -11, 6, 10, -4, -46, -24, -10, 6, -8, 11, + 29, 24, -15, 0, 11, 14, -4, -2, 11, 3, -37, -36, -13, -3, -2, 2, + 28, 27, -2, -10, 14, 9, 7, -8, 13, 3, -21, -42, -14, -14, 4, -6, + 24, 24, 13, -16, 12, 3, 14, -8, 12, 4, -7, -44, -18, -20, 5, -6, + 18, 22, 23, -13, 6, 2, 13, -4, 5, 5, 1, -36, -26, -20, -1, -1, + 10, 23, 25, -3, -4, 5, 9, 5, -2, 8, 1, -24, -36, -18, -10, 4, + 1, 24, 23, 11, -9, 8, 4, 12, -7, 9, 1, -12, -40, -19, -16, 4, + -4, 21, 21, 16, -9, 6, 2, 13, -4, 6, 6, -4, -33, -24, -18, -2, + -2, 10, 21, 18, 0, -3, 3, 8, 6, -1, 8, 0, -18, -31, -19, -10, + 1, 0, 19, 20, 13, -5, 4, 5, 12, -4, 5, 2, -7, -34, -24, -17, + 1, -4, 13, 20, 21, -3, 2, 5, 14, 0, 2, 4, 0, -26, -28, -20, + -6, -4, 4, 18, 23, 6, -3, 5, 9, 7, -1, 6, 3, -14, -33, -22, + -14, -1, -1, 16, 22, 17, -4, 4, 4, 10, -2, 4, 3, -4, -30, -25, + -19, -2, -2, 11, 20, 23, 0, 0, 2, 10, 3, 1, 4, 1, -23, -30, + -22, -8, -1, 4, 19, 23, 10, -3, 4, 6, 8, -2, 5, 2, -13, -33, + -23, -15, 0, -1, 16, 21, 16, -3, 3, 4, 11, 0, 5, 6, -3, -27, + -25, -19, -4, -2, 9, 19, 19, 2, -3, 2, 8, 6, -1, 8, 0, 0, + 2, 33, 42, 58, 71, 79, 85, 88, 91, 94, 79, 95, 82, 106, 86, 105, + 47, 16, -6, 13, 44, 31, -15, -38, -36, 20, 70, 41, 48, 58, 24, -57, + -127, -119, -102, -126, -128, -111, -78, -82, -88, -87, -60, -66, -98, -104, -99, -97, + -99, -104, -101, -88, -87, -91, -61, -27, -34, -54, -55, -45, -24, -10, -5, -4, + 5, 34, 63, 101, 94, 78, 52, 51, 52, 74, 81, 77, 59, 46, 17, 7, + 39, 53, 47, 42, 66, 83, 73, 52, 28, 22, 11, 8, 11, 0, -15, -23, + -15, -14, -6, 16, 46, 62, 71, 76, 90, 102, 103, 103, 101, 100, 90, 75, + 63, 67, 49, 37, 28, 12, 5, 6, 15, 15, 8, -7, -12, -4, -10, -28, + -24, -17, -25, -50, -64, -81, -103, -116, -116, -113, -95, -72, -54, -41, -47, -65, + -65, -50, -33, -24, -7, 11, 8, -4, -13, -28, -51, -75, -90, -91, -90, -90, + -87, -88, -83, -84, -82, -81, -81, -76, -65, -71, -85, -84, -79, -83, -81, -77, + -72, -70, -65, -66, -66, -65, -66, -68, -61, -56, -51, -36, -13, -3, -5, -8, + -12, -12, 3, 16, 21, 31, 50, 69, 77, 82, 90, 102, 110, 114, 116, 117, + 118, 119, 116, 112, 109, 105, 98, 99, 103, 102, 91, 73, 64, 63, 61, 57, + 51, 40, 24, 35, 57, 75, 84, 79, 65, 37, 4, -26, -45, -57, -54, -46, + -45, -54, -67, -67, -48, -16, 15, 35, 44, 45, 44, 45, 46, 38, 23, 2, + -15, -34, -52, -60, -70, -77, -80, -79, -74, -77, -84, -86, -80, -72, -68, -72, + -80, -87, -92, -96, -101, -104, -104, -101, -93, -90, -89, -86, -85, -84, -83, -82, + -81, -79, -77, -76, -73, -71, -66, -62, -55, -39, -31, -27, -25, -31, -37, -46, + -51, -53, -54, -48, -45, -38, -20, 3, 24, 35, 39, 32, 16, 5, 3, 0, + -6, -13, -13, -11, -2, 14, 28, 40, 50, 53, 50, 55, 64, 74, 90, 105, + 108, 112, 106, 104, 109, 112, 123, 127, 127, 127, 127, 127, 127, 118, 113, 107, + 110, 114, 111, 104, 101, 101, 102, 103, 99, 99, 89, 73, 53, 35, 20, 0, + -22, -43, -63, -77, -82, -76, -65, -48, -36, -29, -24, -25, -29, -37, -40, -49, + -59, -67, -73, -76, -78, -79, -75, -73, -74, -75, -68, -52, -44, -30, -19, -9, + -6, -9, -13, -24, -33, -35, -31, -30, -35, -40, -44, -45, -51, -53, -54, -50, + -50, -47, -42, -50, -55, -54, -56, -56, -54, -54, -49, -48, -41, -32, -28, -18, + -13, -5, 6, 18, 33, 49, 60, 71, 78, 88, 95, 97, 93, 88, 91, 93, + 97, 98, 97, 94, 91, 85, 81, 72, 70, 66, 61, 60, 64, 66, 74, 83, + 92, 102, 108, 109, 107, 102, 97, 95, 91, 87, 80, 74, 67, 62, 61, 58, + 61, 61, 57, 53, 43, 35, 27, 25, 24, 20, 20, 22, 27, 34, 36, 32, + 21, 8, -3, -10, -16, -18, -16, -16, -19, -15, -11, -11, -12, -20, -34, -45, + -59, -72, -80, -89, -94, -95, -102, -111, -114, -111, -111, -108, -106, -104, -101, -98, + -93, -90, -86, -86, -83, -82, -81, -79, -76, -73, -70, -72, -78, -81, -79, -79, + -72, -60, -43, -31, -25, -27, -34, -37, -40, -42, -41, -39, -36, -34, -25, -12, + -4, 5, 12, 16, 17, 15, 13, 6, -4, -7, -8, -6, -1, 4, 7, 9, + 12, 16, 19, 19, 22, 28, 29, 28, 29, 30, 34, 40, 49, 57, 71, 78, + 85, 92, 96, 95, 89, 85, 86, 93, 99, 104, 102, 100, 94, 85, 77, 73, + 69, 66, 63, 60, 60, 59, 57, 52, 47, 41, 31, 18, 6, -3, -7, -11, + -12, -14, -18, -22, -23, -22, -24, -30, -37, -41, -44, -50, -56, -64, -67, -65, + -62, -58, -58, -58, -59, -61, -62, -66, -72, -78, -79, -77, -73, -68, -64, -61, + -56, -53, -54, -52, -52, -57, -63, -69, -70, -68, -65, -62, -59, -57, -56, -58, + -60, -61, -63, -64, -62, -61, -60, -58, -54, -49, -45, -42, -39, -36, -32, -28, + -22, -13, -7, -3, 2, 13, 28, 41, 52, 64, 71, 73, 73, 70, 64, 61, + 60, 64, 66, 65, 66, 64, 61, 60, 62, 65, 64, 66, 67, 67, 68, 66, + 64, 66, 68, 73, 76, 74, 72, 66, 58, 52, 46, 42, 38, 38, 41, 47, + 52, 52, 48, 45, 42, 40, 38, 34, 29, 27, 26, 28, 29, 28, 29, 30, + 31, 28, 24, 21, 19, 17, 14, 10, 6, 3, -4, -9, -15, -19, -26, -33, + -40, -49, -55, -60, -65, -70, -73, -72, -72, -71, -70, -71, -75, -78, -81, -83, + -86, -86, -85, -84, -82, -80, -77, -72, -69, -66, -63, -61, -61, -61, -61, -61, + -60, -58, -53, -48, -42, -36, -30, -28, -30, -32, -33, -32, -31, -28, -22, -18, + -10, -5, 0, 3, 6, 11, 16, 19, 22, 24, 26, 27, 29, 34, 40, 46, + 48, 48, 48, 45, 40, 36, 33, 31, 33, 35, 40, 48, 55, 62, 68, 73, + 76, 78, 78, 77, 79, 82, 85, 87, 87, 87, 86, 86, 86, 83, 78, 71, + 63, 55, 48, 44, 39, 36, 36, 36, 35, 32, 28, 24, 18, 13, 9, 6, + 4, 1, -2, -5, -11, -17, -20, -21, -20, -21, -24, -28, -32, -34, -33, -33, + -35, -37, -40, -43, -47, -52, -58, -63, -69, -74, -77, -80, -81, -82, -81, -80, + -77, -74, -69, -62, -54, -48, -48, -51, -54, -57, -57, -57, -56, -55, -55, -56, + -57, -56, -55, -54, -54, -54, -54, -52, -49, -45, -41, -38, -34, -31, -29, -27, + -24, -20, -17, -11, -7, -3, 0, 5, 10, 16, 22, 27, 31, 34, 38, 42, + 44, 45, 48, 50, 52, 57, 61, 64, 64, 65, 65, 63, 60, 57, 55, 55, + 58, 61, 63, 65, 67, 69, 71, 74, 77, 79, 79, 77, 74, 71, 68, 66, + 63, 60, 57, 55, 51, 46, 40, 36, 30, 25, 20, 17, 16, 17, 16, 14, + 12, 10, 7, 3, -1, -5, -11, -15, -17, -18, -18, -19, -21, -25, -29, -32, + -33, -33, -36, -39, -43, -46, -50, -53, -56, -58, -59, -60, -61, -62, -63, -65, + -66, -67, -68, -70, -72, -72, -70, -67, -63, -61, -60, -60, -58, -56, -54, -53, + -52, -52, -52, -51, -50, -49, -47, -45, -43, -40, -37, -35, -34, -32, -29, -25, + -21, -18, -14, -9, -4, 0, 4, 7, 11, 15, 18, 21, 25, 28, 33, 37, + 41, 44, 46, 47, 47, 46, 46, 45, 43, 42, 42, 43, 46, 48, 49, 50, + 52, 55, 59, 62, 65, 66, 67, 68, 69, 69, 70, 72, 74, 74, 73, 72, + 71, 69, 65, 61, 57, 53, 50, 46, 43, 38, 35, 32, 28, 23, 19, 17, + 17, 15, 13, 11, 9, 5, 1, -3, -6, -9, -12, -14, -17, -19, -23, -27, + -31, -35, -38, -40, -43, -46, -48, -52, -55, -57, -61, -64, -66, -67, -68, -69, + -70, -70, -70, -69, -69, -70, -71, -70, -66, -62, -59, -55, -52, -50, -46, -43, + -41, -38, -36, -35, -35, -34, -33, -33, -33, -33, -31, -30, -28, -26, -25, -24, + -21, -20, -20, -19, -19, -18, -17, -16, -15, -13, -11, -8, -3, 2, 9, 15, + 21, 27, 33, 38, 41, 45, 48, 51, 53, 55, 56, 56, 56, 56, 56, 56, + 56, 55, 57, 58, 60, 61, 62, 62, 64, 66, 68, 69, 71, 72, 73, 74, + 72, 70, 67, 63, 60, 57, 54, 50, 46, 41, 36, 31, 27, 23, 19, 16, + 14, 12, 11, 9, 8, 5, 2, -1, -4, -8, -10, -15, -18, -19, -20, -22, + -22, -23, -23, -24, -26, -29, -31, -33, -35, -36, -37, -38, -41, -44, -46, -48, + -50, -52, -54, -56, -59, -61, -63, -63, -64, -65, -64, -63, -62, -61, -60, -59, + -58, -57, -58, -57, -57, -55, -53, -50, -49, -47, -46, -43, -40, -37, -33, -31, + -28, -26, -23, -20, -16, -14, -12, -9, -5, -2, 1, 5, 9, 13, 17, 21, + 24, 26, 29, 32, 35, 37, 37, 38, 39, 41, 43, 44, 45, 46, 48, 50, + 51, 53, 52, 52, 50, 48, 47, 46, 46, 46, 46, 47, 48, 49, 51, 54, + 56, 58, 60, 61, 62, 62, 62, 61, 59, 57, 55, 54, 53, 52, 51, 49, + 46, 41, 36, 31, 27, 22, 18, 14, 11, 9, 6, 3, 0, -2, -5, -8, + -11, -16, -20, -25, -28, -31, -34, -37, -39, -41, -41, -42, -42, -42, -43, -45, + -46, -47, -49, -50, -52, -54, -56, -57, -58, -60, -61, -63, -64, -64, -64, -63, + -63, -61, -59, -58, -57, -55, -54, -53, -52, -52, -51, -50, -49, -47, -46, -45, + -44, -42, -40, -38, -35, -32, -30, -28, -25, -22, -19, -17, -15, -12, -9, -5, + -1, 3, 7, 11, 15, 19, 23, 25, 27, 30, 34, 36, 37, 38, 39, 40, + 42, 44, 45, 46, 47, 49, 50, 52, 53, 52, 51, 49, 47, 47, 46, 46, + 46, 47, 47, 48, 50, 52, 55, 57, 59, 61, 62, 62, 62, 61, 60, 58, + 56, 54, 54, 53, 51, 50, 47, 44, 39, 34, 29, 25, 20, 16, 13, 10, + 7, 4, 2, -1, -3, -6, -9, -14, -18, -22, -26, -30, -33, -35, -38, -40, + -41, -41, -42, -42, -43, -44, -46, -47, -48, -49, -51, -53, -55, -56, -57, -59, + -60, -62, -63, -64, -64, -63, -63, -62, -60, -59, -57, -56, -55, -53, -52, -52, + -51, -51, -50, -48, -46, -45, -44, -43, -41, -39, -36, -34, -31, -29, -26, -24, + -21, -16, -1, -2, -1, -3, 1, -2, -2, -4, 2, 6, 2, -2, -2, 0, + 7, 8, 4, -2, -2, 6, 5, 6, 0, -2, 5, 12, 10, 0, -5, -3, + 5, 10, 9, -7, -8, -7, 5, 8, 3, -9, -13, -5, 3, 5, -5, -9, + -4, 0, 6, 0, -4, -11, -7, 3, 4, 0, -5, 0, -1, 5, 1, 4, + -6, -5, -3, 12, 9, -2, -10, 4, 11, 8, -4, -5, -9, -6, 1, 19, + 13, -2, -22, 4, 9, 6, -26, -4, 3, 12, -9, 0, 2, 0, -15, 4, + 8, -8, -20, 0, 15, 8, -13, -2, -4, -4, -2, 12, 3, -14, -18, 1, + 21, 13, -9, -25, -8, 17, 15, 5, -14, -17, 5, 19, 13, -15, -17, -3, + 10, 20, 10, -27, -19, 5, 11, 12, 3, -13, -17, -1, 6, -3, -2, 1, + -1, -11, -17, 7, 7, -7, -7, -13, 9, 0, -5, 9, -5, -9, 6, 5, + -2, -16, -5, 15, 17, -10, -20, 1, 11, 14, -1, 1, 10, -11, -8, -1, + 18, 13, -2, -12, 1, -16, -2, 34, 27, -28, -42, -3, 42, 26, -14, -39, + -19, 7, 26, 25, -16, -55, -26, 32, 57, 4, -69, -48, 6, 75, 29, -51, + -67, -32, 51, 56, 7, -57, -75, 14, 63, 43, -29, -82, -27, 31, 56, 28, + -43, -81, -31, 59, 85, 1, -100, -59, 8, 102, 41, -42, -92, -52, 72, 79, + 29, -103, -85, -1, 117, 49, -54, -113, 7, 24, 94, -28, -39, -84, 39, 28, + 61, -44, -28, -67, 61, 23, 35, -40, -23, -37, 6, 38, 69, -42, -61, -53, + 58, 86, 2, -93, -24, 19, 72, 17, -19, -87, 45, 10, 64, -13, -45, -57, + 38, 48, 36, -51, -35, -37, 46, 26, 37, -73, -28, -12, 44, 22, 27, -84, + -22, 6, 70, 17, -24, -82, -7, 26, 79, 9, -63, -78, 6, 90, 68, -55, + -118, -3, 92, 62, -10, -73, -50, 14, 110, 15, -5, -118, 5, 69, 53, 22, + -81, -45, 29, 47, 80, -69, -28, -52, 58, 66, -1, -25, -59, -22, 107, 2, + 43, -108, -13, 20, 59, 56, -58, -66, -7, 34, 114, -42, -63, -50, 42, 69, + 44, -63, -37, -50, 114, 27, 18, -49, -81, 20, 74, 51, -14, -102, -4, 40, + 70, 38, -64, -73, 11, 60, 76, -41, -30, -78, 42, 46, 68, -63, -48, -56, + 89, 43, 28, -100, -53, 41, 60, 11, -6, -76, -16, 44, 52, 9, -67, -48, + 10, 69, 30, -1, -84, -4, 36, 72, -23, -22, -27, -33, 55, 74, -11, -86, + -1, 27, 36, 31, -7, -101, 49, 5, 66, -7, -46, -39, 9, 64, 44, -63, + -33, -22, 55, 23, 43, -79, -24, 5, 29, 54, -14, -59, -53, 63, 32, 20, + -34, -32, -36, 93, -2, 20, -35, -38, 18, 51, 61, -94, 15, -14, 17, 69, + 5, -87, 16, 28, 34, 1, 34, -57, -53, 118, -22, 34, -10, -71, 23, 70, + 25, -29, -7, -19, -3, 117, -33, -12, -21, -19, 43, 84, -38, -57, 33, 0, + 32, 41, -7, -103, 85, 2, 2, 58, -14, -103, 103, 7, -17, 34, -32, -59, + 71, 51, -78, 76, -65, -30, 63, 48, -66, 9, -11, -28, 52, 50, -72, -37, + 73, -61, 75, 7, -51, -44, 73, -3, -11, 40, -78, 7, 63, -15, -16, 30, + -53, 12, 38, 12, -42, 39, -63, 47, 23, 0, -23, -11, 8, -25, 60, -37, + -15, -3, -9, 12, 27, -14, -40, 22, 12, 14, 15, -31, -14, 15, 23, -12, + 14, -31, 19, 13, 32, -39, 27, -51, 43, 8, 0, 5, -26, 16, 4, 19, + -24, 17, -18, 6, -2, 49, -67, 39, -1, -30, 46, -13, -16, -9, 21, -17, + 27, 2, -34, 19, -3, 24, 8, -38, 13, -10, 22, 15, -34, 2, 4, -10, + 18, 14, -15, -15, 26, -12, 28, -21, 0, -6, 0, 7, 0, -15, 6, -2, + -18, 9, 8, -18, -15, 59, -94, 81, -40, -24, 14, -18, 25, -15, 4, -21, + -9, 24, -20, 3, 3, -52, 56, -29, 4, 5, -51, 45, -50, 73, -75, 13, + 17, -48, 38, -10, -16, 5, 4, -22, 3, 17, -27, -23, 42, -30, -5, 41, + -53, 10, 23, -28, 1, 29, -47, 9, 13, -3, -18, 9, -13, -11, 18, 12, + -53, 28, 1, -41, 41, 7, -61, 32, 0, -34, 16, 9, -74, 45, -23, -33, + 22, 39, -104, 49, 23, -96, 83, 5, -46, 36, -4, -45, 54, -25, -26, 21, + 2, -39, 51, -25, -25, 43, -22, -25, 30, -2, -32, 39, 14, -69, 42, 22, + -78, 60, 23, -83, 33, 44, -74, 19, 69, -113, 43, 53, -88, 51, 17, -74, + 42, 1, -38, 4, 39, -67, 12, 35, -39, -23, 73, -82, -5, 67, -71, -5, + 42, -36, -48, 78, -64, -4, 40, -48, -7, 50, -80, 17, 31, -56, 9, 6, + -18, -36, 43, -37, -29, 47, -47, -18, 33, -29, -27, 40, -30, -37, 51, -46, + -25, 61, -66, 7, 28, -48, 30, -15, -8, -6, 17, -14, -9, 26, -23, 4, + 9, -15, 12, -9, 16, -22, 7, 22, -51, 59, -29, -23, 54, -49, 6, 20, + -19, -11, 17, -3, -30, 32, -27, -5, 16, -28, 4, 4, -27, 32, -46, 27, + -18, -8, 11, -25, 18, -6, -17, 10, 1, -18, 24, -33, 10, 8, -12, -10, + 21, -19, 0, 8, -18, 14, 11, -44, 39, -22, -4, -6, 11, -15, -13, 17, + -17, -6, 13, -22, -1, 7, -5, -8, 0, 4, -24, 29, -23, 0, 20, -25, + -8, 30, -34, 31, -29, 11, -9, 21, -15, -1, 10, -9, -11, 32, -23, -2, + -14, 27, -19, 10, -4, -23, 14, 13, -45, 48, -44, 11, -4, -7, -3, 4, + -2, -34, -8, 37, -41, 20, -24, -4, -10, 2, 4, 12, -28, -30, 9, 32, + -16, 6, -46, -23, 60, 0, -22, -3, -23, -15, 48, 12, -34, -17, -18, 10, + 46, -1, -56, -8, 12, 9, 18, 13, -72, -3, 26, 9, 28, -14, -89, 15, + 67, -18, 1, -19, -52, 45, 26, -8, -5, -25, -25, 36, 38, -13, -36, -18, + -6, 55, 23, -51, -14, 4, 6, 25, 24, -41, -44, 38, 19, 10, 10, -59, + -14, 42, 1, 6, -8, -43, -1, 43, 10, -30, -10, -36, 18, 35, -20, -14, + -11, -19, 9, 20, -5, -22, -9, -6, 13, 26, -30, -23, 4, 1, 20, 9, + -20, -22, 3, -1, 17, 28, -26, -25, 16, -2, -4, 12, -10, -16, 24, -2, + -18, 17, -27, -1, 36, -6, -7, -4, -26, 6, 29, -3, -17, -6, -4, 18, + 18, -26, -10, -4, 6, 30, -1, -6, -24, 0, 24, 12, 2, -16, -25, 13, + 32, -3, -4, -3, -24, 15, 16, -7, 8, -20, -13, 36, 9, -24, -11, -10, + 10, 20, -1, -13, -10, -9, 20, 17, -12, -9, -15, 9, 20, -11, -14, -6, + 5, 10, 6, 5, -7, -11, 7, 19, 1, 3, -11, -10, 24, 14, -16, 2, + -9, 11, 14, 7, -1, -11, -4, 15, 24, 3, -24, -4, 4, 15, 13, -3, + -15, 0, 15, 8, 2, 0, -19, 16, 12, -1, 7, -13, -2, 18, 3, -3, + 5, -9, -10, 12, 9, -2, 8, -9, 4, 9, 6, 1, -8, 10, 4, -2, + 11, -14, 3, 5, 1, 9, 4, -15, 0, 10, 1, 5, -4, -10, 3, 7, + -1, 8, -13, 1, 4, 10, 6, -9, -3, 1, 6, 14, -3, -4, 4, -10, + 10, 13, -1, -4, 5, -3, 10, 13, -13, 4, 7, 1, 8, -1, 1, 4, + 5, 4, 11, -5, -2, 1, 8, 6, 1, 3, -1, -5, 11, 3, -3, 4, + -5, -1, 17, -4, -2, 6, -10, 10, 10, -4, 2, 3, -10, 10, 5, -2, + -2, -1, 4, 3, -1, -2, -4, 1, 6, -4, 6, -4, -10, 8, 2, -4, + 6, -4, -4, 12, -2, 2, 6, -9, 3, 2, 0, 7, -5, -3, 3, 2, + 4, -4, -2, 7, 3, 5, 9, -3, 1, 12, -3, 7, 6, -9, 4, 9, + -4, 12, 1, -7, 9, 2, 1, 10, -3, 1, 0, 0, 8, 0, -1, 5, + -2, 8, 1, -3, 10, 2, 0, 11, -4, -1, 6, -3, 2, 3, -5, 4, + 0, -5, 5, -3, 1, 3, 0, 4, -3, -3, 4, -2, -2, 5, -2, -1, + 6, -5, 2, 3, -4, 4, -2, -3, 11, -8, 0, 5, -1, 1, 0, -3, + 4, 2, 2, 6, -2, 4, 5, -3, 4, 7, -4, 11, -1, 0, 3, 0, + 3, 7, -2, 5, 1, 0, 6, 3, 2, 4, -1, 2, 6, 0, 3, 5, + -4, 6, 0, 2, 7, -4, -1, 2, -2, 7, 1, -1, 1, -2, 2, 4, + -5, 0, 4, -1, 2, -1, -2, 1, -2, 3, 2, -3, 3, -1, -4, 5, + -2, -2, 3, 0, -1, 2, -5, 2, 1, -4, 0, 1, -3, 5, -2, 2, + 2, -3, 1, 3, -2, 3, 1, -2, 4, 1, 2, 5, -2, 3, 1, 2, + 5, 0, -1, 4, 0, 1, 4, 2, 4, 4, -2, 0, 2, 3, 5, 0, + 0, 0, 1, 5, -2, -3, 4, 0, 1, 2, -2, -4, -4, -5, -6, -7, + -8, -9, -10, -11, -12, -13, -13, -14, -16, -18, -21, -25, -29, -34, -36, -38, + -39, -40, -42, -44, -47, -50, -53, -56, -58, -59, -58, -55, -50, -44, -38, -31, + -24, -18, -13, -9, -6, -3, 0, 3, 6, 9, 13, 17, 21, 27, 33, 42, + 53, 63, 74, 83, 91, 98, 104, 108, 111, 113, 115, 118, 119, 121, 123, 125, + 126, 127, 127, 127, 127, 126, 126, 126, 126, 127, 127, 127, 127, 127, 127, 127, + 126, 125, 123, 121, 118, 114, 111, 107, 104, 101, 100, 99, 98, 98, 98, 98, + 98, 99, 98, 98, 97, 95, 92, 88, 81, 73, 63, 54, 46, 39, 33, 29, + 27, 25, 24, 22, 20, 18, 14, 10, 5, 0, -5, -8, -8, -7, -3, 2, + 8, 14, 19, 23, 26, 28, 29, 30, 31, 32, 32, 31, 30, 28, 24, 20, + 14, 9, 4, -1, -4, -7, -9, -10, -12, -13, -15, -17, -19, -22, -24, -25, + -25, -23, -21, -19, -17, -15, -15, -14, -15, -15, -16, -17, -17, -17, -16, -16, + -16, -17, -19, -22, -25, -30, -35, -39, -44, -47, -50, -53, -56, -58, -61, -63, + -64, -65, -65, -63, -60, -55, -49, -43, -38, -34, -32, -31, -31, -32, -33, -35, + -36, -37, -37, -36, -35, -34, -34, -34, -36, -39, -43, -49, -55, -61, -67, -72, + -77, -81, -85, -88, -90, -92, -94, -94, -95, -94, -94, -94, -94, -95, -96, -98, + -100, -102, -104, -105, -107, -108, -108, -109, -110, -110, -110, -109, -109, -109, -108, -108, + -109, -109, -109, -109, -108, -108, -107, -106, -106, -105, -105, -105, -105, -105, -105, -104, + -103, -101, -98, -93, -88, -82, -76, -70, -64, -58, -52, -47, -42, -38, -34, -31, + -29, -27, -25, -22, -18, -13, -7, -1, 6, 13, 20, 26, 32, 37, 41, 45, + 48, 51, 55, 58, 63, 68, 73, 77, 82, 85, 89, 91, 94, 96, 97, 98, + 99, 99, 99, 100, 100, 100, 101, 101, 101, 101, 101, 101, 99, 97, 95, 93, + 90, 87, 84, 81, 77, 73, 67, 60, 51, 40, 29, 17, 6, -5, -14, -23, + -31, -38, -45, -52, -58, -65, -70, -75, -80, -84, -87, -90, -92, -94, -95, -96, + -97, -98, -100, -101, -102, -102, -103, -103, -104, -104, -103, -102, -100, -97, -93, -89, + -86, -82, -79, -77, -75, -72, -70, -67, -63, -59, -53, -47, -40, -33, -26, -20, + -14, -9, -6, -3, 0, 3, 6, 9, 13, 17, 21, 26, 31, 37, 44, 51, + 58, 64, 70, 75, 79, 83, 86, 88, 90, 92, 93, 95, 96, 97, 98, 100, + 100, 101, 102, 102, 102, 102, 102, 102, 102, 102, 102, 103, 103, 103, 102, 102, + 102, 101, 100, 98, 96, 94, 92, 90, 89, 88, 88, 87, 87, 87, 87, 87, + 86, 85, 84, 82, 79, 76, 72, 67, 61, 55, 49, 43, 39, 35, 32, 30, + 29, 27, 25, 24, 21, 18, 15, 12, 8, 5, 3, 3, 4, 6, 9, 12, + 15, 18, 21, 23, 25, 27, 28, 30, 31, 31, 31, 30, 28, 25, 22, 18, + 14, 10, 7, 5, 3, 1, 0, -2, -4, -6, -9, -11, -14, -16, -17, -17, + -16, -14, -12, -11, -9, -9, -9, -10, -11, -12, -13, -14, -15, -15, -16, -16, + -17, -19, -22, -26, -30, -34, -38, -42, -45, -48, -50, -52, -53, -54, -55, -56, + -56, -55, -53, -50, -46, -42, -38, -35, -32, -31, -30, -31, -31, -33, -34, -35, + -36, -36, -36, -35, -35, -35, -36, -38, -41, -45, -49, -54, -59, -64, -68, -73, + -76, -80, -83, -86, -88, -89, -90, -91, -91, -91, -92, -92, -93, -95, -96, -98, + -100, -101, -102, -103, -104, -105, -105, -105, -105, -105, -105, -105, -105, -105, -105, -105, + -105, -105, -104, -104, -103, -102, -102, -101, -100, -100, -100, -99, -99, -99, -98, -96, + -94, -91, -86, -82, -76, -71, -65, -59, -53, -48, -42, -37, -32, -28, -25, -22, + -19, -16, -13, -8, -3, 3, 9, 16, 22, 28, 35, 40, 45, 49, 53, 56, + 60, 63, 67, 71, 76, 80, 85, 88, 92, 94, 97, 99, 100, 102, 103, 103, + 104, 104, 104, 104, 105, 105, 105, 105, 105, 104, 103, 101, 99, 97, 94, 91, + 87, 84, 80, 76, 71, 65, 57, 48, 39, 28, 18, 8, -2, -11, -19, -27, + -34, -41, -47, -54, -60, -65, -70, -75, -79, -82, -85, -87, -89, -91, -92, -94, + -95, -96, -97, -98, -99, -100, -100, -100, -100, -100, -98, -96, -94, -90, -87, -84, + -81, -78, -76, -73, -71, -68, -65, -61, -57, -52, -46, -40, -33, -27, -21, -15, + -11, -7, -4, 0, 3, 7, 11, 15, 20, 24, 29, 35, 41, 48, 54, 61, + 67, 72, 77, 81, 85, 88, 90, 92, 94, 95, 97, 98, 99, 101, 102, 103, + 104, 104, 104, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 104, + 104, 103, 101, 99, 98, 96, 95, 93, 93, 92, 92, 91, 91, 90, 90, 88, + 87, 86, 84, 81, 78, 74, 69, 64, 59, 54, 49, 45, 42, 39, 37, 35, + 33, 31, 29, 27, 24, 21, 18, 15, 13, 11, 11, 12, 13, 15, 17, 20, + 22, 24, 25, 27, 28, 29, 30, 31, 31, 31, 30, 28, 26, 23, 20, 17, + 14, 11, 9, 8, 6, 5, 3, 1, -1, -4, -6, -8, -10, -11, -11, -11, + -10, -9, -8, -8, -8, -9, -10, -11, -13, -14, -15, -16, -17, -17, -18, -20, + -22, -25, -28, -31, -35, -38, -41, -44, -46, -47, -49, -50, -51, -52, -52, -52, + -51, -49, -47, -44, -40, -38, -35, -33, -33, -32, -33, -33, -34, -35, -36, -37, + -38, -38, -38, -38, -39, -40, -42, -45, -49, -53, -57, -61, -65, -69, -73, -76, + -79, -82, -85, -87, -88, -89, -90, -91, -91, -92, -93, -94, -95, -97, -98, -99, + -100, -101, -102, -103, -103, -104, -104, -104, -104, -104, -104, -104, -104, -104, -103, -103, + -103, -102, -102, -101, -100, -99, -99, -98, -97, -97, -96, -96, -95, -94, -92, -89, + -86, -82, -77, -72, -67, -61, -56, -50, -45, -39, -34, -29, -25, -21, -18, -14, + -11, -5, 4, 8, 14, 19, 25, 31, 37, 42, 47, 52, 57, 61, 65, 69, + 72, 76, 79, 83, 86, 89, 92, 95, 97, 99, 101, 102, 104, 104, 105, 106, + 106, 106, 106, 106, 106, 105, 104, 104, 103, 101, 99, 97, 95, 92, 89, 85, + 81, 77, 73, 68, 62, 57, 50, 43, 35, 28, 19, 12, 4, -4, -11, -18, + -25, -32, -38, -44, -50, -55, -61, -65, -69, -73, -77, -80, -82, -85, -87, -89, + -91, -92, -93, -95, -95, -96, -97, -97, -97, -96, -96, -95, -93, -92, -90, -88, + -86, -84, -82, -79, -77, -74, -71, -68, -64, -60, -55, -51, -46, -41, -36, -31, + -26, -21, -16, -11, -7, -2, 3, 8, 14, 19, 25, 30, 36, 42, 47, 53, + 58, 63, 68, 72, 76, 79, 82, 85, 87, 89, 91, 93, 95, 96, 98, 99, + 101, 102, 103, 103, 104, 105, 105, 105, 106, 106, 106, 106, 106, 106, 106, 105, + 105, 105, 104, 103, 103, 102, 101, 100, 99, 99, 98, 97, 96, 95, 93, 92, + 91, 89, 87, 85, 82, 79, 76, 73, 70, 67, 63, 60, 58, 55, 53, 50, + 48, 46, 44, 41, 39, 37, 34, 32, 31, 29, 28, 28, 27, 28, 28, 28, + 28, 29, 29, 29, 29, 30, 30, 30, 29, 29, 28, 27, 26, 25, 23, 22, + 20, 19, 17, 16, 15, 13, 12, 10, 8, 6, 4, 2, 1, -1, -2, -4, + -5, -6, -7, -9, -10, -12, -13, -15, -17, -19, -21, -22, -24, -26, -27, -29, + -31, -32, -34, -36, -38, -40, -42, -43, -45, -46, -47, -47, -48, -48, -49, -49, + -48, -48, -47, -46, -45, -44, -44, -43, -43, -43, -44, -44, -45, -46, -47, -48, + -49, -50, -51, -52, -53, -55, -57, -59, -61, -64, -67, -70, -72, -75, -78, -80, + -82, -84, -86, -88, -90, -91, -92, -94, -95, -96, -97, -98, -98, -99, -100, -101, + -101, -101, -102, -102, -102, -102, -102, -102, -102, -102, -102, -102, -101, -101, -100, -100, + -99, -98, -97, -96, -95, -94, -93, -92, -91, -89, -88, -87, -85, -83, -81, -78, + -75, -71, -67, -63, -58, -54, -49, -44, -39, -33, -28, -23, -18, -13, -8, -3, + 2, 7, 13, 18, 23, 29, 35, 40, 45, 51, 55, 60, 64, 68, 71, 75, + 78, 82, 85, 88, 91, 93, 96, 98, 100, 101, 103, 104, 105, 105, 106, 106, + 106, 106, 105, 105, 104, 104, 103, 101, 100, 98, 95, 93, 90, 86, 83, 79, + 75, 70, 65, 60, 54, 47, 40, 33, 25, 18, 10, 2, -5, -12, -19, -26, + -32, -38, -44, -50, -55, -60, -65, -69, -73, -76, -79, -82, -84, -87, -89, -90, + -92, -93, -94, -95, -96, -96, -96, -96, -96, -95, -94, -93, -91, -90, -88, -86, + -84, -81, -79, -76, -74, -70, -67, -63, -59, -54, -49, -44, -39, -34, -29, -24, + -19, -14, -10, -5, -2, -1, 3, -2, 1, -3, 4, -2, 0, 0, 8, 0, + 10, -9, -7, -128, -72, 13, -44, -13, -18, 4, -4, 12, 3, 31, 4, 66, + 74, 38, 38, 36, 30, 25, 22, 18, 13, 7, 5, 2, 1, -5, -7, -9, + -9, -11, -14, -12, -14, -12, -16, -13, -16, -13, -14, -16, -11, -14, -10, -13, + -11, -13, -8, -8, -6, -6, -5, 0, -6, -3, -3, 3, -4, 6, -13, 17, + -5, -5, 15, -1, -23, 6, 23, 28, 35, 13, 41, -3, 24, 25, -4, 6, + 30, 4, 18, 10, -32, -64, -120, -64, -91, -76, -33, -45, -58, 2, 1, -19, + -14, 18, 48, 50, 59, 51, 53, 47, 46, 41, 37, 35, 26, 28, 19, 21, + 10, 13, 9, 3, 5, -4, 2, -5, -3, -8, -5, -8, -8, -10, -9, -10, + -10, -12, -7, -17, -8, -11, -14, -5, -15, -5, -4, -10, -13, 11, -22, 3, + -3, -4, -5, -11, 13, 2, -16, -9, -5, -12, 27, 15, 17, 21, 20, 20, + 8, 14, 13, 0, 10, 35, 10, -1, -12, -52, -89, -78, -58, -85, -74, -51, + -25, -25, -28, -30, -14, 12, 29, 44, 44, 51, 46, 50, 49, 43, 38, 36, + 32, 29, 23, 19, 17, 14, 10, 6, 6, 2, 4, -8, 3, -7, -3, -6, + -7, -11, -4, -12, -7, -6, -20, 1, -15, -14, -8, -7, -10, -10, -10, 2, + -14, -12, 7, -10, -8, -5, -6, 1, 6, -2, -12, -19, -3, 3, 2, 19, + 19, 14, 19, 24, 13, 5, 12, 12, 13, 21, 29, 5, -18, -43, -48, -64, + -82, -82, -71, -44, -37, -37, -40, -33, -23, 5, 20, 33, 38, 45, 48, 51, + 46, 44, 41, 38, 36, 27, 26, 24, 19, 13, 16, 5, 11, 4, -1, 3, + -4, -3, 1, -9, -7, -2, -9, -6, -13, -4, -6, -17, -8, -6, -15, -10, + -5, -10, -8, -10, -5, -7, -5, -2, -14, -10, 3, 5, -4, -3, -10, -17, + -10, 3, 4, 5, 18, 18, 18, 16, 16, 10, 5, 11, 23, 26, 22, 7, + -9, -16, -37, -62, -80, -76, -65, -46, -43, -43, -51, -41, -24, -4, 11, 24, + 32, 41, 47, 43, 49, 45, 41, 40, 33, 31, 31, 20, 23, 18, 11, 16, + 9, 5, 3, 2, 5, -2, -7, 2, -4, -10, -3, -5, -8, -10, -7, -8, + -14, -10, -8, -11, -9, -6, -14, -10, -2, -3, -12, -10, -7, -9, 0, 6, + -1, -11, -12, -11, -10, -7, 4, 7, 12, 17, 20, 18, 13, 6, 8, 19, + 22, 24, 17, 14, 5, -8, -29, -54, -77, -71, -55, -50, -44, -54, -57, -39, + -32, -15, 3, 15, 31, 34, 39, 47, 45, 44, 44, 37, 37, 33, 28, 27, + 18, 20, 21, 10, 7, 10, 7, 1, 2, 2, 0, -5, 0, -2, -7, -3, + -5, -8, -8, -5, -13, -13, -5, -6, -14, -11, -8, -8, -5, -5, -9, -17, + -10, -2, 0, -2, -1, -9, -12, -14, -12, -6, -1, 3, 11, 19, 19, 14, + 7, 9, 13, 17, 23, 22, 19, 21, 12, 2, -21, -55, -65, -59, -52, -47, + -56, -56, -50, -53, -38, -22, -7, 10, 18, 29, 36, 40, 45, 43, 38, 41, + 40, 32, 27, 26, 26, 19, 17, 17, 12, 9, 9, 6, 2, 4, 4, -1, + -2, 2, -3, -3, 0, -2, -8, -9, -7, -7, -7, -6, -8, -12, -6, -4, + -7, -12, -13, -10, -5, -2, -2, -3, -8, -12, -15, -16, -14, -13, -7, 2, + 8, 11, 8, 4, 5, 8, 13, 20, 22, 23, 24, 23, 19, 6, -13, -23, + -29, -32, -37, -42, -46, -53, -57, -53, -49, -39, -25, -12, -1, 10, 21, 28, + 32, 35, 36, 34, 34, 32, 28, 25, 24, 21, 18, 19, 16, 10, 7, 8, + 9, 8, 6, 5, 2, 3, 6, 7, 5, 2, -2, -4, -3, -1, -3, -4, + -3, -1, -3, -8, -13, -14, -11, -4, -1, -2, -4, -6, -11, -16, -19, -21, + -21, -17, -9, -3, 0, 0, -3, -5, -2, 4, 11, 18, 23, 25, 26, 24, + 17, 10, 5, -1, -7, -12, -20, -29, -37, -44, -51, -55, -54, -47, -39, -28, + -16, -4, 9, 18, 23, 27, 31, 31, 30, 30, 28, 23, 20, 22, 23, 20, + 14, 10, 9, 9, 10, 9, 6, 4, 4, 6, 9, 10, 7, 2, 0, 1, + -1, -2, -2, -1, 1, 2, -2, -10, -14, -11, -8, -5, -2, -1, -3, -6, + -9, -14, -20, -23, -23, -18, -11, -5, -3, -4, -6, -8, -4, 2, 7, 14, + 21, 25, 25, 23, 19, 13, 8, 4, -1, -9, -15, -23, -31, -39, -48, -53, + -51, -48, -44, -34, -20, -8, 3, 12, 20, 24, 27, 30, 31, 29, 24, 22, + 22, 23, 22, 18, 13, 10, 10, 11, 11, 9, 5, 3, 5, 10, 11, 9, + 7, 5, 4, 2, 0, -3, -1, 3, 5, 2, -3, -8, -11, -10, -7, -5, + -3, -2, -2, -4, -7, -14, -20, -24, -24, -19, -12, -6, -6, -8, -8, -8, + -7, -2, 5, 12, 19, 23, 24, 22, 20, 16, 12, 7, 1, -5, -10, -17, + -27, -36, -42, -47, -52, -51, -45, -36, -26, -12, 0, 9, 15, 21, 27, 30, + 29, 26, 23, 22, 23, 23, 21, 17, 12, 9, 10, 12, 10, 6, 3, 4, + 7, 10, 11, 9, 8, 9, 7, 2, -1, 0, 2, 6, 6, 3, -2, -7, + -9, -8, -6, -4, -3, -1, -1, -2, -6, -13, -21, -26, -24, -18, -13, -10, + -9, -10, -11, -11, -10, -5, 3, 10, 17, 21, 22, 22, 21, 19, 14, 8, + 5, 1, -7, -14, -21, -29, -38, -45, -49, -50, -48, -40, -28, -16, -6, 3, + 11, 19, 26, 27, 26, 24, 22, 22, 24, 24, 20, 14, 11, 11, 12, 11, + 8, 4, 3, 6, 8, 9, 9, 10, 11, 10, 6, 2, 0, 2, 5, 8, + 7, 3, -2, -5, -6, -7, -6, -4, -3, -1, 1, 1, -5, -13, -21, -24, + -23, -18, -14, -12, -11, -12, -13, -14, -13, -8, 0, 8, 14, 17, 21, 22, + 21, 18, 15, 12, 8, 2, -3, -9, -16, -24, -32, -40, -47, -51, -49, -41, + -30, -21, -12, -1, 9, 17, 23, 25, 24, 21, 21, 24, 24, 22, 17, 12, + 11, 13, 12, 8, 4, 3, 4, 6, 7, 7, 9, 11, 12, 10, 6, 3, + 3, 6, 9, 10, 8, 5, 1, -2, -3, -3, -2, -1, 1, 3, 3, 1, + -5, -12, -18, -20, -20, -18, -16, -16, -16, -17, -19, -20, -17, -11, -5, 1, + 8, 13, 17, 18, 18, 17, 16, 14, 11, 7, 2, -3, -8, -14, -22, -34, + -43, -46, -42, -35, -28, -20, -11, -2, 7, 15, 19, 19, 19, 19, 20, 20, + 17, 14, 11, 10, 9, 7, 1, -4, -6, -4, 0, 2, 4, 6, 7, 8, + 9, 8, 7, 7, 10, 13, 15, 15, 13, 9, 6, 3, 2, 4, 7, 9, + 11, 11, 7, 1, -5, -10, -13, -14, -14, -14, -16, -19, -23, -26, -28, -27, + -23, -18, -13, -7, -1, 6, 11, 14, 15, 14, 14, 15, 15, 12, 7, 2, + -1, -4, -11, -22, -34, -41, -40, -34, -26, -19, -12, -4, 4, 10, 14, 17, + 17, 18, 19, 18, 15, 12, 10, 9, 8, 6, 0, -6, -11, -10, -6, -1, + 3, 5, 6, 6, 6, 7, 7, 8, 10, 13, 16, 18, 17, 13, 9, 5, + 3, 4, 7, 11, 13, 14, 11, 5, -2, -7, -11, -12, -12, -13, -14, -17, + -22, -26, -28, -29, -27, -22, -17, -11, -5, 1, 7, 12, 14, 14, 13, 14, + 15, 14, 11, 5, 0, -2, -6, -15, -27, -37, -42, -38, -31, -24, -17, -9, + -1, 6, 12, 15, 17, 18, 19, 19, 17, 13, 11, 9, 9, 8, 4, -2, + -8, -11, -9, -4, 1, 4, 5, 6, 6, 6, 7, 7, 9, 11, 14, 17, + 18, 16, 12, 8, 4, 3, 5, 9, 12, 14, 13, 9, 2, -4, -9, -12, + -13, -12, -13, -15, -19, -23, -27, -29, -28, -25, -20, -15, -9, -3, 3, 9, + 13, 15, 14, 13, 15, 15, 13, 9, 3, -1, -3, -9, -19, -31, -40, -41, + -36, -28, -21, -14, -6, 2, 9, 13, 16, 17, 18, 19, 18, 16, 12, 10, + 9, 9, 7, 2, -4, -10, -11, -8, -2, 2, 5, 5, 6, 6, 7, 7, + 8, 9, 12, 16, 18, 17, 14, 10, 6, 4, 4, 6, 10, 13, 14, 12, + 7, 0, -6, -10, -12, -13, -13, -14, -16, -21, -25, -28, -29, -28, -24, -18, + -13, -7, -1, 6, 11, 14, 15, 13, 14, 15, 15, 12, 7, 2, -1, -5, + -12, -23, -35, -41, -40, -34, -26, -19, -12, -3, 4, 10, 14, 17, 18, 18, + 19, 18, 14, 11, 9, 9, 8, 6, 0, -7, -11, -10, -6, 0, 2, -1, + -2, -9, -24, 4, -3, 3, -3, 10, 7, 4, 13, -4, 1, 3, 3, 0, + 2, 8, -9, -9, 2, 1, -1, 7, 17, 21, 37, 25, 13, 14, -2, 15, + 20, 5, 0, -3, -7, -27, -14, -18, -19, -29, -20, -4, -18, -32, -30, -30, + -29, -32, -22, -26, -19, -19, -1, -6, 4, 7, 5, 2, 0, -8, -16, -12, + -13, -17, -17, 19, 20, 24, 16, 8, -4, 8, 0, 13, 28, 33, 16, 11, + 5, -3, -1, 4, 12, 12, 40, 20, 11, 4, 5, 8, -1, 2, 5, 5, + 22, 13, 21, 8, 9, 18, 20, 13, 20, 26, 11, 24, 17, 10, 27, 30, + 22, 28, 30, 41, 47, 57, 36, 36, 20, -16, 4, 6, -19, -21, -41, -39, + -33, -38, -41, -46, -42, -36, -18, -37, -65, -75, -77, -78, -62, -63, -62, -68, + -63, -63, -44, -50, -30, -41, -43, -26, -34, -35, -36, -45, -49, -27, 1, -6, + -4, -7, -20, -16, -20, -21, -13, 2, -6, -1, -12, 0, -1, 15, 19, 20, + 26, 37, 40, 46, 37, 50, 35, 34, 41, 43, 51, 54, 55, 50, 56, 47, + 59, 51, 51, 75, 67, 66, 71, 59, 60, 72, 75, 72, 80, 79, 82, 98, + 99, 87, 93, 62, 49, 58, 41, 42, 28, 5, -6, -6, -18, -24, -23, -30, + -25, -20, -38, -60, -75, -77, -80, -75, -71, -75, -70, -73, -69, -76, -60, -66, + -71, -66, -57, -62, -61, -61, -87, -90, -69, -63, -46, -31, -35, -47, -42, -53, + -63, -53, -45, -33, -36, -39, -37, -43, -39, -34, -30, -19, -9, 2, -9, -1, + -3, 1, -3, 5, 7, 15, 24, 22, 23, 20, 32, 43, 33, 48, 63, 67, + 70, 68, 52, 59, 73, 73, 77, 85, 73, 81, 103, 98, 116, 115, 87, 80, + 76, 72, 69, 60, 37, 27, 29, 12, 19, 4, -12, 1, 3, -3, -31, -42, + -57, -67, -67, -61, -61, -61, -48, -58, -51, -41, -46, -48, -40, -35, -33, -26, + -36, -67, -68, -65, -59, -47, -28, -34, -37, -36, -52, -61, -61, -47, -34, -39, + -39, -42, -42, -48, -36, -38, -37, -20, -19, -16, -16, -18, -20, -22, -26, -22, + -16, -15, 1, -4, -6, 10, 12, 13, 22, 32, 41, 54, 52, 44, 54, 66, + 61, 78, 81, 71, 87, 89, 99, 119, 107, 91, 77, 76, 69, 76, 68, 47, + 49, 35, 33, 37, 22, 14, 24, 37, 26, 13, -10, -26, -41, -43, -34, -40, + -34, -33, -43, -39, -25, -27, -27, -18, -25, -15, -1, -10, -29, -42, -39, -39, + -19, -7, -10, -10, -11, -20, -35, -44, -33, -30, -28, -36, -34, -47, -41, -36, + -46, -42, -34, -27, -29, -25, -34, -30, -32, -40, -36, -36, -31, -16, -25, -25, + -15, -21, -14, -9, -11, 1, 17, 15, 9, 25, 20, 25, 46, 39, 46, 50, + 51, 68, 85, 87, 72, 65, 52, 50, 59, 44, 42, 29, 23, 22, 23, 11, + -5, 8, 14, 19, 8, -6, -23, -38, -43, -42, -48, -41, -34, -42, -38, -19, + -23, -16, -15, -19, -10, 8, 8, -9, -18, -27, -30, -10, -4, 7, 6, 15, + 8, -8, -17, -15, -8, -11, -3, -15, -17, -14, -16, -27, -30, -26, -22, -19, + -21, -22, -19, -30, -27, -26, -36, -22, -9, -13, -10, -10, -8, -9, -6, -12, + -1, 16, 6, 11, 16, 6, 19, 24, 27, 38, 38, 38, 48, 71, 72, 78, + 66, 51, 54, 52, 49, 42, 32, 21, 25, 26, 13, 1, -1, 10, 15, 8, + 1, -22, -38, -47, -56, -58, -46, -43, -46, -33, -25, -17, -11, -9, -19, -9, + 16, 18, 12, 1, -17, -18, -9, 3, 9, 17, 24, 26, 9, -4, -1, -6, + 2, 9, 0, -2, 2, -3, -13, -16, -15, -8, -8, -8, -1, -6, -17, -11, + -22, -24, -16, -12, -9, -9, -9, -9, -6, -8, -16, 2, 6, 2, 13, 9, + 7, 10, 17, 19, 30, 31, 22, 37, 49, 61, 70, 56, 43, 37, 36, 31, + 32, 15, 4, 11, 9, 4, -14, -16, -7, -5, -1, -8, -28, -46, -56, -75, + -74, -67, -70, -67, -62, -55, -47, -36, -32, -42, -28, -9, 1, 4, -4, -17, + -30, -18, -12, -2, 4, 15, 21, 7, 1, -7, -6, -1, 7, 0, 0, 3, + -3, -8, -15, -18, -6, -9, -6, 5, -2, -2, 0, -7, -12, -7, -3, 2, + 7, 3, 4, 14, 2, 1, 12, 11, 17, 20, 19, 16, 19, 20, 24, 39, + 36, 37, 42, 55, 71, 84, 76, 63, 56, 47, 49, 46, 29, 18, 14, 18, + 11, -5, -11, -8, -3, 4, 4, -16, -27, -44, -60, -64, -59, -62, -62, -55, + -55, -47, -28, -32, -35, -29, -15, -3, 4, 3, -15, -25, -24, -13, -11, -3, + 10, 14, 12, 4, -5, -9, -1, 2, -1, 1, 1, -1, -7, -17, -16, -12, + -17, -8, 0, -1, -1, -2, -8, -13, -9, -9, 0, 9, 1, 14, 16, 6, + 7, 10, 12, 18, 26, 20, 22, 22, 16, 25, 32, 36, 34, 36, 43, 60, + 75, 72, 67, 52, 44, 50, 45, 38, 17, 14, 17, 11, -2, -9, -14, -10, + 0, -4, -12, -24, -41, -59, -67, -63, -70, -69, -62, -70, -55, -40, -38, -42, + -38, -29, -16, -3, -3, -9, -29, -31, -25, -26, -20, -7, 0, 2, -1, -14, + -18, -14, -14, -12, -10, -10, -4, -13, -21, -19, -22, -24, -16, -10, -6, -2, + -2, -10, -12, -15, -17, -4, -4, -5, 7, 9, 3, 4, 7, 5, 18, 23, + 22, 28, 25, 22, 27, 34, 39, 43, 38, 41, 62, 71, 79, 78, 62, 55, + 55, 57, 49, 31, 23, 30, 21, 15, 7, -5, 1, 8, 9, 8, -3, -16, + -39, -46, -50, -60, -55, -58, -62, -53, -36, -33, -34, -34, -29, -18, -6, 5, + -2, -17, -23, -22, -24, -17, -8, 1, 9, 10, -4, -7, -8, -9, -6, -9, + -6, 0, -11, -14, -14, -21, -24, -21, -16, -10, 1, -3, -3, -5, -14, -11, + -7, -7, -5, 6, 9, 4, 8, 1, 3, 11, 16, 20, 26, 24, 20, 25, + 29, 36, 41, 32, 40, 51, 64, 77, 78, 67, 55, 54, 57, 53, 33, 27, + 25, 22, 20, 9, -3, -3, 3, 7, 6, 4, -16, -32, -42, -55, -60, -61, + -64, -70, -62, -49, -39, -41, -40, -37, -33, -18, -5, -8, -16, -24, -29, -31, + -28, -24, -15, -1, 1, -7, -11, -14, -13, -14, -18, -11, -8, -14, -16, -16, + -25, -31, -29, -31, -20, -12, -13, -6, -11, -19, -19, -14, -17, -12, -1, 2, + 6, 7, 2, 4, 8, 11, 18, 24, 21, 22, 19, 21, 33, 33, 32, 32, + 40, 55, 71, 76, 72, 58, 55, 62, 56, 42, 34, 28, 29, 26, 17, 4, + 2, 6, 4, 13, 12, -4, -18, -30, -45, -50, -51, -59, -63, -61, -47, -37, + -33, -32, -34, -32, -19, -4, -3, -5, -13, -21, -23, -22, -24, -13, 1, 5, + 5, -3, -6, -1, -7, -9, -2, 1, -2, -2, -4, -13, -16, -22, -22, -15, + -10, -4, 2, -1, -11, -8, -7, -12, -6, 1, 6, 12, 11, 8, 9, 9, + 9, 20, 23, 26, 25, 20, 24, 32, 34, 35, 33, 35, 49, 63, 74, 74, + 58, 55, 60, 54, 45, 33, 27, 25, 26, 19, 6, 4, 1, 1, 9, 12, + -1, -10, -26, -43, -50, -54, -61, -70, -69, -61, -50, -43, -40, -44, -44, -34, + -18, -12, -9, -15, -24, -25, -28, -31, -22, -12, -2, 1, -8, -8, -5, -12, + -14, -8, -8, -8, -5, -9, -11, -18, -27, -26, -22, -19, -12, -1, -4, -9, + -8, -11, -14, -12, -8, 0, 7, 5, 5, 6, 0, 3, 8, 13, 20, 18, + 13, 15, 22, 27, 29, 25, 26, 36, 51, 70, 71, 59, 56, 57, 55, 47, + 37, 25, 24, 27, 17, 9, 3, -2, -2, 8, 9, 6, -2, -16, -34, -44, + -47, -54, -63, -66, -63, -55, -44, -39, -42, -44, -35, -23, -11, -4, -10, -16, + -17, -23, -25, -22, -13, 1, 6, 1, 1, 4, -2, -4, 1, -1, 4, 3, + 2, 2, -3, -12, -15, -14, -15, -7, 3, 5, 3, 2, 1, -2, -4, -4, + 3, 9, 10, 13, 11, 9, 8, 9, 15, 22, 22, 20, 19, 21, 27, 30, + 28, 28, 28, 42, 61, 69, 65, 60, 60, 58, 55, 47, 35, 30, 30, 24, + 18, 10, 0, -1, 2, 6, 7, 3, -8, -24, -36, -43, -50, -59, -65, -66, + -62, -52, -43, -43, -44, -41, -35, -21, -12, -12, -13, -17, -23, -26, -30, -24, + -12, -4, -5, -3, -2, -5, -6, -6, -5, -3, -2, -1, 2, 2, -5, -3, + 2, 8, 17, 26, 32, 42, 50, 56, 68, 73, 64, 63, 65, 48, 56, 71, + 48, 49, 50, 26, 30, 30, 16, 25, 21, -2, 0, -13, -15, -2, -19, -17, + -16, -50, -49, -49, -81, -85, -88, -108, -112, -116, -127, -126, -113, -113, -106, -79, + -65, -48, -17, 5, 20, 41, 58, 63, 69, 59, 28, 17, 0, -32, -41, -52, + -69, -63, -61, -59, -41, -26, -19, 6, 28, 33, 52, 67, 70, 81, 87, 84, + 90, 93, 84, 72, 69, 60, 45, 56, 57, 40, 46, 39, 25, 29, 25, 16, + 21, 12, -1, -3, -11, -8, -5, -16, -12, -21, -41, -38, -48, -68, -70, -77, + -91, -93, -98, -106, -103, -93, -92, -82, -60, -47, -30, -4, 13, 27, 44, 56, + 60, 62, 47, 23, 13, -8, -32, -40, -54, -64, -59, -59, -53, -36, -26, -14, + 12, 27, 36, 56, 66, 72, 84, 86, 86, 93, 92, 82, 73, 70, 57, 49, + 59, 52, 43, 47, 37, 29, 30, 24, 18, 18, 7, -2, -6, -11, -7, -10, + -16, -14, -29, -42, -42, -57, -71, -73, -83, -93, -96, -102, -107, -101, -93, -90, + -75, -55, -41, -22, 3, 19, 33, 50, 59, 61, 60, 41, 21, 10, -14, -33, + -43, -57, -63, -60, -61, -51, -36, -27, -9, 15, 26, 40, 59, 66, 74, 85, + 85, 88, 94, 90, 80, 75, 69, 56, 54, 60, 50, 47, 46, 36, 31, 30, + 23, 19, 15, 4, -3, -7, -10, -9, -14, -17, -19, -35, -44, -47, -63, -73, + -77, -88, -96, -98, -104, -107, -99, -92, -86, -69, -50, -35, -14, 9, 24, 38, + 54, 60, 61, 56, 36, 19, 4, -20, -35, -46, -60, -62, -61, -60, -48, -35, + -25, -3, 17, 27, 45, 60, 66, 77, 85, 86, 91, 94, 88, 80, 75, 67, + 56, 58, 59, 50, 49, 45, 36, 33, 30, 23, 19, 13, 2, -5, -8, -10, + -11, -16, -18, -25, -40, -45, -53, -68, -76, -81, -91, -97, -100, -106, -106, -97, + -90, -81, -63, -44, -28, -6, 15, 28, 44, 57, 61, 61, 52, 31, 16, -1, + -24, -37, -50, -61, -62, -62, -59, -46, -35, -22, 1, 18, 30, 48, 61, 68, + 79, 85, 87, 92, 93, 86, 80, 75, 66, 58, 60, 58, 51, 50, 44, 37, + 33, 29, 23, 17, 10, 0, -6, -9, -10, -14, -18, -21, -31, -43, -48, -59, + -72, -78, -85, -94, -99, -102, -107, -104, -95, -88, -76, -56, -39, -22, 2, 20, + 33, 49, 59, 61, 60, 47, 27, 12, -7, -27, -40, -53, -62, -62, -63, -57, + -44, -34, -18, 5, 19, 33, 51, 61, 70, 81, 85, 88, 94, 92, 85, 80, + 74, 65, 60, 62, 57, 52, 50, 43, 37, 33, 28, 22, 15, 8, -2, -7, + -10, -12, -16, -20, -24, -36, -46, -52, -64, -75, -81, -89, -97, -100, -104, -107, + -102, -93, -85, -70, -50, -33, -14, 8, 25, 38, 53, 61, 61, 58, 42, 24, + 8, -12, -30, -43, -56, -62, -63, -63, -54, -43, -32, -13, 7, 20, 37, 53, + 62, 72, 82, 85, 89, 94, 90, 84, 80, 73, 64, 62, 62, 56, 53, 49, + 43, 37, 33, 27, 20, 14, 5, -3, -8, -11, -13, -18, -22, -28, -40, -49, + -57, -69, -78, -84, -92, -99, -102, -105, -106, -99, -90, -81, -64, -44, -27, -7, + 14, 29, 43, 56, 61, 61, 54, 37, 20, 4, -17, -33, -46, -58, -62, -64, + -62, -52, -42, -29, -9, 9, 23, 40, 55, 64, 74, 83, 86, 91, 93, 89, + 84, 80, 72, 65, 64, 62, 56, 53, 49, 42, 37, 33, 26, 19, 12, 3, + -5, -8, -12, -16, -20, -24, -33, -44, -52, -61, -73, -80, -87, -95, -100, -103, + -106, -104, -96, -88, -76, -57, -38, -21, 0, 20, 33, 47, 59, 62, 60, 51, + 33, 17, -1, -21, -36, -49, -59, -63, -64, -61, -51, -40, -25, -5, 11, 26, + 43, 56, 65, 76, 83, 87, 92, 93, 88, 84, 79, 71, 65, 65, 61, 56, + 53, 48, 42, 37, 32, 25, 17, 10, 1, -6, -10, -13, -18, -22, -27, -37, + -48, -55, -65, -76, -83, -90, -97, -101, -104, -106, -102, -94, -84, -71, -51, -33, + -15, 7, 24, 38, 51, 60, 62, 59, 46, 29, 13, -6, -25, -39, -52, -60, + -63, -64, -59, -49, -38, -21, -1, 14, 29, 46, 57, 67, 78, 84, 88, 92, + 92, 87, 83, 78, 70, 66, 65, 61, 57, 53, 48, 42, 37, 31, 23, 15, + 7, -1, -7, -11, -15, -20, -24, -31, -41, -51, -59, -69, -79, -85, -93, -99, + -102, -105, -106, -100, -91, -80, -65, -45, -27, -8, 13, 29, 42, 55, 61, 61, + 56, 42, 25, 8, -11, -28, -42, -54, -61, -64, -64, -57, -47, -35, -17, 1, + 16, 33, 48, 59, 69, 79, 84, 89, 93, 91, 87, 83, 77, 70, 67, 65, + 60, 57, 53, 47, 41, 36, 29, 21, 14, 5, -3, -8, -12, -17, -22, -27, + -35, -45, -54, -63, -73, -81, -88, -95, -100, -103, -105, -104, -97, -88, -76, -58, + -39, -21, -1, 18, 33, 46, 58, 62, 61, 53, 38, 21, 4, -15, -31, -45, + -56, -62, -65, -64, -56, -46, -32, -13, 4, 19, 36, 50, 61, 71, 80, 85, + 90, 92, 90, 86, 82, 76, 70, 68, 65, 60, 57, 52, 46, 41, 35, 27, + 19, 12, 3, -5, -9, -14, -19, -24, -29, -38, -48, -57, -66, -76, -84, -91, + -97, -101, -104, -105, -102, -94, -84, -71, -52, -33, -15, 5, 23, 37, 50, 60, + 62, 60, 50, 34, 17, -1, -19, -35, -48, -58, -63, -65, -62, -54, -43, -28, + -10, 7, 22, 39, 52, 62, 73, 81, 86, 91, 92, 89, 86, 82, 75, 70, + 68, 64, 60, 57, 52, 46, 40, 34, 26, 17, 9, 1, -6, -11, -15, -21, + -26, -32, -42, -52, -60, -70, -79, -86, -93, -99, -102, -104, -105, -100, -91, -80, + -65, -46, -27, -9, 11, 28, 42, 54, 61, 62, 58, 46, 30, 13, -6, -23, + -38, -51, -60, -64, -65, -61, -52, -41, -25, -6, 9, 26, 42, 54, 64, 75, + 82, 87, 91, 91, 89, 85, 81, 74, 71, 68, 64, 60, 56, 51, 45, 39, + 32, 24, 16, 7, -1, -7, -12, -17, -23, -28, -36, -45, -55, -64, -73, -82, + -88, -95, -100, -103, -105, -104, -97, -88, -76, -59, -40, -22, -2, 17, 32, 45, + 57, 62, 62, 56, 42, 26, 9, -10, -27, -41, -53, -61, -65, -65, -60, -50, + -38, -21, -3, 12, 29, 44, 55, 66, 76, 82, 88, 91, 91, 88, 85, 80, + 74, 71, 68, 63, 60, 56, 50, 44, 38, 30, 22, 14, 5, -3, -9, -14, + -19, -25, -31, -39, -49, -58, -67, -77, -84, -91, -97, -101, -103, -105, -102, -95, + -84, -71, -53, -34, -16, 4, 22, 37, 49, 59, 63, 61, 53, 38, 22, 4, + -14, -30, -44, -56, -62, -66, -65, -58, -48, -35, -17, -1, 15, 32, 46, 57, + 68, 77, 83, 88, 91, 90, 88, 84, 79, 74, 71, 67, 63, 60, 55, 49, + 43, 37, 28, 20, 12, 3, -5, -10, -15, -21, -27, -33, -43, -52, -61, -70, + -79, -86, -93, -98, -102, -104, -104, -100, -92, -81, -66, -47, -28, -10, 10, 27, + 40, 53, 61, 63, 59, 49, 34, 18, -1, -18, -34, -47, -58, -63, -66, -64, + -56, -46, -31, -14, 2, 18, 35, 48, 59, 70, 78, 84, 89, 91, 90, 87, + 83, 78, 74, 71, 67, 63, 59, 54, 49, 42, 35, 27, 18, 9, 1, -6, + -12, -17, -23, -29, -36, -46, -55, -64, -73, -82, -89, -95, -100, -102, -104, -103, + -97, -88, -76, -60, -41, -23, -4, 15, 31, 44, 55, 62, 62, 57, 46, 30, + 13, -5, -22, -37, -50, -59, -64, -66, -62, -55, -43, -28, -11, 5, 22, 37, + 50, 61, 71, 79, 85, 89, 91, 89, 87, 82, 77, 73, 70, 66, 63, 59, + 53, 47, 41, 33, 24, 16, 7, -1, -8, -14, -19, -25, -32, -40, -49, -58, + -67, -76, -84, -91, -96, -101, -103, -104, -102, -95, -85, -72, -55, -37, -18, 1, + 19, 34, 47, 57, 62, 62, 56, 43, 28, 10, -8, -25, -39, -52, -60, -65, + -66, -62, -53, -42, -25, -9, 8, 24, 39, 51, 62, 72, 80, 86, 90, 90, + 89, 86, 82, 77, 73, 70, 66, 62, 58, 53, 47, 40, 33, 24, 15, 6, + -2, -8, -14, -19, -25, -32, -40, -49, -58, -67, -72, -103, -18, -76, 0, 0, + 0, 0, 1, 2, 3, 5, 6, 0, -7, -8, -15, -9, 10, 8, 17, 33, + 14, 5, 38, 44, 31, 63, 70, 51, 73, 82, 68, 85, 100, 96, 97, 103, + 115, 114, 112, 127, 122, 110, 116, 113, 109, 120, 120, 118, 113, 91, 93, 109, + 97, 98, 115, 110, 109, 120, 112, 94, 75, 63, 69, 72, 64, 64, 59, 45, + 39, 36, 35, 42, 42, 24, 5, 2, 3, 4, 7, 9, 11, 14, 17, 19, + 14, -3, -20, -26, -30, -26, -24, -31, -32, -34, -40, -39, -33, -34, -45, -56, + -60, -66, -64, -55, -60, -62, -56, -59, -58, -50, -56, -70, -73, -76, -86, -77, + -70, -80, -76, -71, -77, -71, -66, -76, -85, -82, -90, -95, -80, -82, -92, -85, + -86, -94, -85, -79, -86, -92, -90, -94, -101, -92, -85, -90, -84, -77, -78, -74, + -73, -85, -86, -85, -95, -85, -77, -90, -88, -83, -94, -93, -83, -81, -81, -86, + -89, -89, -94, -88, -77, -77, -71, -59, -58, -59, -63, -72, -74, -77, -73, -61, + -67, -72, -67, -73, -80, -74, -68, -60, -56, -65, -70, -67, -72, -66, -52, -49, + -40, -27, -27, -32, -39, -47, -50, -42, -30, -31, -34, -32, -38, -46, -46, -43, + -35, -20, -16, -24, -30, -30, -31, -24, -13, -6, 4, 13, 11, 3, -5, -9, + -2, 12, 15, 15, 16, 9, 3, -2, -5, -1, 12, 24, 30, 29, 20, 17, + 22, 25, 30, 41, 47, 49, 46, 37, 32, 41, 52, 54, 60, 61, 52, 48, + 45, 36, 35, 43, 51, 60, 67, 69, 60, 57, 63, 63, 64, 73, 75, 72, + 69, 63, 67, 78, 78, 82, 89, 80, 73, 76, 67, 60, 64, 67, 73, 79, + 83, 88, 82, 75, 80, 81, 77, 83, 83, 76, 74, 77, 83, 85, 86, 94, + 89, 80, 82, 78, 69, 68, 68, 69, 78, 80, 81, 90, 83, 73, 79, 77, + 70, 73, 70, 62, 65, 73, 75, 76, 84, 82, 70, 71, 69, 59, 57, 54, + 48, 53, 63, 64, 68, 76, 66, 57, 58, 51, 42, 40, 33, 28, 37, 46, + 49, 55, 56, 42, 37, 37, 27, 22, 20, 10, 4, 8, 15, 24, 30, 31, + 24, 14, 8, -3, -14, -21, -26, -26, -15, -4, -1, -4, -13, -21, -26, -34, + -39, -42, -50, -57, -63, -66, -60, -47, -43, -48, -51, -57, -66, -75, -82, -88, + -91, -88, -78, -74, -81, -86, -85, -92, -101, -100, -102, -109, -109, -110, -112, -113, + -115, -109, -106, -113, -113, -107, -110, -110, -106, -108, -112, -109, -110, -114, -111, -98, + -95, -98, -93, -93, -98, -94, -89, -81, -69, -65, -71, -73, -73, -77, -73, -62, + -56, -48, -40, -41, -45, -47, -47, -37, -20, -11, -4, 5, 4, 3, 6, 9, + 16, 30, 39, 47, 51, 44, 40, 45, 47, 50, 59, 64, 66, 68, 65, 65, + 75, 80, 78, 87, 95, 91, 93, 98, 96, 98, 104, 100, 96, 99, 104, 101, + 100, 106, 107, 105, 108, 109, 109, 110, 111, 110, 101, 87, 82, 84, 81, 82, + 88, 89, 90, 91, 85, 71, 57, 49, 48, 51, 52, 55, 59, 58, 58, 60, + 61, 61, 57, 42, 24, 14, 7, 5, 9, 11, 15, 20, 21, 19, 11, -3, + -18, -27, -33, -31, -25, -24, -21, -16, -16, -14, -11, -17, -29, -40, -49, -59, + -61, -55, -54, -52, -45, -42, -41, -41, -48, -59, -65, -72, -81, -79, -72, -73, + -69, -62, -61, -59, -60, -69, -76, -79, -87, -92, -84, -81, -82, -76, -72, -71, + -67, -66, -72, -79, -81, -87, -94, -92, -87, -86, -82, -76, -75, -75, -78, -85, + -87, -91, -96, -91, -82, -83, -80, -74, -74, -71, -64, -64, -68, -73, -77, -81, + -87, -88, -82, -79, -76, -70, -69, -72, -76, -80, -84, -87, -82, -71, -67, -64, + -58, -57, -55, -49, -43, -39, -40, -47, -54, -58, -64, -66, -61, -58, -54, -49, + -50, -55, -59, -63, -65, -58, -45, -38, -32, -25, -24, -23, -18, -13, -5, 3, + 4, -2, -11, -17, -23, -26, -23, -20, -18, -15, -18, -24, -28, -28, -21, -7, + 3, 11, 18, 20, 19, 22, 24, 30, 40, 47, 51, 49, 40, 32, 28, 24, + 23, 25, 25, 23, 20, 15, 15, 23, 34, 43, 51, 59, 59, 58, 59, 58, + 60, 67, 73, 78, 84, 85, 78, 71, 68, 63, 60, 60, 57, 53, 50, 50, + 56, 65, 70, 76, 84, 84, 81, 81, 79, 76, 79, 84, 87, 91, 96, 98, + 94, 88, 85, 81, 76, 73, 70, 66, 66, 70, 76, 80, 84, 91, 92, 87, + 86, 83, 78, 76, 78, 81, 85, 88, 91, 96, 93, 86, 83, 78, 71, 68, + 64, 61, 64, 71, 74, 78, 84, 86, 80, 76, 72, 64, 59, 56, 55, 59, + 66, 69, 74, 79, 76, 69, 64, 57, 48, 43, 39, 39, 45, 52, 56, 62, + 63, 55, 47, 41, 31, 21, 15, 8, 5, 9, 16, 24, 31, 35, 33, 26, + 19, 10, 0, -6, -9, -7, -7, -13, -17, -22, -26, -31, -34, -37, -40, -42, + -44, -46, -48, -50, -51, -54, -56, -58, -61, -64, -67, -70, -74, -78, -82, -86, + -90, -93, -97, -99, -102, -104, -106, -108, -109, -110, -111, -112, -113, -113, -114, -114, + -115, -115, -115, -115, -115, -114, -113, -111, -109, -107, -104, -100, -97, -93, -90, -87, + -84, -82, -80, -78, -76, -74, -73, -71, -69, -67, -65, -61, -58, -53, -48, -42, + -35, -28, -21, -13, -6, 1, 8, 15, 21, 26, 31, 35, 38, 41, 44, 46, + 48, 50, 52, 55, 58, 61, 64, 68, 72, 76, 80, 83, 87, 90, 92, 94, + 96, 98, 99, 100, 101, 102, 102, 103, 103, 103, 103, 104, 103, 103, 103, 102, + 101, 99, 97, 94, 92, 88, 85, 81, 78, 74, 71, 67, 64, 61, 58, 55, + 53, 51, 49, 47, 46, 44, 42, 40, 37, 34, 30, 26, 22, 17, 12, 8, + 3, -1, -5, -9, -13, -16, -20, -23, -26, -29, -31, -33, -35, -37, -38, -40, + -42, -44, -46, -48, -51, -54, -56, -59, -61, -64, -65, -67, -69, -70, -72, -74, + -75, -77, -78, -80, -81, -82, -83, -84, -85, -86, -86, -87, -88, -89, -90, -90, + -91, -92, -92, -92, -92, -92, -92, -91, -91, -92, -92, -92, -93, -93, -94, -94, + -94, -95, -95, -95, -95, -95, -95, -95, -95, -95, -94, -93, -92, -91, -90, -89, + -87, -86, -85, -85, -85, -84, -84, -85, -85, -85, -85, -85, -85, -85, -85, -85, + -84, -83, -82, -81, -79, -77, -75, -73, -70, -68, -65, -63, -62, -60, -59, -59, + -59, -59, -59, -59, -59, -60, -59, -59, -59, -58, -57, -55, -53, -50, -47, -44, + -40, -36, -32, -29, -25, -22, -20, -18, -17, -16, -15, -15, -16, -16, -16, -16, + -16, -16, -15, -13, -11, -9, -6, -2, 2, 6, 10, 15, 19, 22, 26, 29, + 31, 33, 35, 36, 36, 36, 36, 35, 35, 35, 35, 35, 36, 38, 40, 42, + 45, 48, 52, 55, 58, 61, 64, 67, 70, 72, 73, 74, 75, 76, 76, 76, + 75, 75, 74, 74, 74, 74, 74, 75, 77, 78, 80, 82, 83, 85, 87, 89, + 90, 91, 92, 93, 94, 94, 94, 94, 94, 93, 93, 92, 91, 91, 90, 90, + 90, 90, 91, 91, 92, 92, 93, 93, 94, 94, 94, 94, 94, 94, 94, 94, + 93, 93, 92, 92, 91, 90, 89, 88, 87, 87, 86, 86, 85, 85, 85, 84, + 84, 83, 83, 82, 81, 80, 79, 78, 77, 77, 76, 75, 74, 72, 71, 70, + 68, 67, 65, 64, 63, 61, 60, 58, 57, 55, 53, 50, 48, 45, 43, 40, + 38, 36, 34, 32, 30, 29, 27, 25, 23, 21, 19, 17, 14, 12, 9, 6, + 3, 0, -4, -8, -12, -17, -21, -25, -29, -33, -36, -39, -42, -45, -47, -49, + -51, -53, -55, -58, -60, -63, -65, -68, -71, -74, -77, -81, -84, -87, -91, -94, + -97, -99, -102, -104, -105, -107, -108, -109, -110, -111, -111, -112, -112, -113, -113, -113, + -113, -113, -113, -112, -111, -109, -107, -105, -102, -99, -96, -93, -90, -87, -84, -82, + -79, -77, -75, -73, -70, -69, -66, -64, -60, -58, -53, -49, -44, -39, -32, -27, + -19, -14, -8, -3, 3, 11, 22, 10, 8, 1, 1, 1, 1, 1, 2, 2, + 2, 2, 3, 3, 3, 3, 4, 4, 5, 5, 6, 5, 6, 6, 6, 6, + 6, 6, 7, 5, 7, 5, 6, 4, 6, 4, 4, 4, 4, 3, 3, 2, + 3, 1, 3, -2, 2, 0, 0, 0, 0, -2, -1, -2, -3, -3, 0, -5, + -1, -2, -2, -2, -1, 0, -3, -1, -1, 0, 1, -1, 0, -1, 0, 0, + 1, 0, 0, 1, -1, 1, -1, 1, -2, -1, -3, 0, -2, -1, -2, -2, + -2, -3, -2, -3, -4, -5, -6, -5, -9, -8, -9, -9, -9, -11, -10, -13, + -14, -14, -15, -16, -15, -17, -19, -19, -21, -18, -21, -20, -22, -20, -24, -21, + -22, -19, -20, -21, -17, -19, -16, -17, -15, -17, -13, -11, -10, -7, -5, -3, + 2, 6, 4, 8, 9, 18, 14, 31, 25, 24, 25, 24, 21, 13, 15, 15, + 11, 9, 1, 4, -20, -18, -38, -44, -57, -57, -55, -55, -52, -55, -46, -47, + -40, -32, -26, -19, -16, -2, 3, 13, 19, 28, 30, 37, 40, 44, 39, 38, + 35, 34, 37, 41, 48, 51, 53, 58, 61, 70, 74, 76, 76, 80, 81, 86, + 83, 83, 78, 78, 73, 69, 65, 55, 47, 40, 36, 29, 23, 16, 14, 8, + -2, -4, -11, -11, -19, -22, -26, -25, -34, -39, -40, -41, -45, -49, -51, -57, + -56, -58, -59, -66, -70, -70, -72, -65, -64, -59, -53, -49, -45, -34, -29, -21, + -15, -10, -6, -6, -3, -4, 2, 3, 3, 3, -1, -3, -11, -11, -13, -16, + -22, -24, -27, -32, -34, -37, -35, -31, -30, -26, -25, -22, -21, -15, -13, -15, + -10, -12, -12, -7, 2, 15, 22, 27, 24, 28, 22, 22, 21, 22, 17, 13, + 14, 9, 5, 2, -8, -12, -16, -14, -17, -17, -17, -17, -14, -8, -3, -3, + 0, 5, 3, 5, 6, 3, -2, -6, -9, -11, -13, -18, -19, -29, -42, -61, + -72, -79, -81, -83, -82, -79, -76, -65, -54, -42, -33, -24, -14, 0, 18, 33, + 48, 62, 75, 87, 93, 99, 100, 102, 102, 104, 102, 100, 100, 96, 93, 95, + 96, 105, 109, 112, 111, 110, 106, 106, 104, 102, 97, 93, 85, 80, 71, 60, + 48, 36, 26, 12, 0, -5, -13, -21, -28, -31, -36, -42, -49, -53, -56, -59, + -61, -63, -64, -64, -63, -67, -70, -77, -75, -77, -78, -79, -80, -81, -80, -75, + -69, -64, -57, -50, -43, -35, -26, -16, -6, 6, 13, 17, 22, 26, 25, 27, + 27, 26, 23, 19, 11, 5, -5, -12, -19, -24, -31, -37, -42, -45, -50, -49, + -48, -47, -43, -41, -38, -38, -37, -35, -35, -37, -42, -40, -33, -27, -20, -12, + -11, -13, -10, -9, -10, -10, -10, -13, -11, -9, -8, -11, -13, -16, -18, -17, + -15, -15, -14, -12, -8, -3, 3, 8, 16, 22, 25, 31, 34, 36, 36, 34, + 31, 25, 23, 24, 26, 23, 13, -1, -16, -29, -38, -45, -51, -56, -57, -54, + -48, -39, -34, -29, -20, -10, 0, 13, 27, 39, 54, 68, 79, 87, 92, 94, + 96, 94, 92, 89, 87, 82, 76, 72, 71, 74, 76, 81, 83, 83, 84, 84, + 85, 85, 82, 81, 82, 80, 75, 71, 66, 57, 46, 34, 24, 15, 5, -2, + -8, -13, -19, -26, -31, -37, -41, -44, -48, -53, -54, -53, -54, -54, -57, -61, + -64, -67, -70, -72, -75, -77, -79, -79, -76, -73, -70, -63, -58, -53, -47, -38, + -29, -21, -13, -6, 0, 4, 7, 7, 8, 8, 6, 5, -1, -8, -15, -22, + -30, -36, -41, -47, -51, -54, -56, -58, -59, -56, -50, -45, -42, -37, -31, -26, + -23, -23, -23, -24, -21, -14, -6, 2, 8, 12, 15, 18, 21, 20, 20, 20, + 20, 21, 23, 22, 18, 13, 10, 8, 6, 5, 4, 3, 2, 2, 4, 7, + 10, 13, 18, 22, 24, 26, 28, 27, 21, 14, 8, 5, 4, 2, -3, -12, + -24, -37, -50, -59, -67, -76, -80, -79, -75, -69, -61, -55, -47, -38, -27, -15, + -2, 11, 27, 43, 58, 71, 82, 90, 94, 96, 98, 98, 98, 95, 89, 84, + 81, 79, 81, 85, 88, 89, 91, 92, 92, 90, 89, 89, 88, 85, 82, 79, + 75, 67, 58, 48, 37, 25, 14, 4, -4, -10, -17, -24, -31, -37, -42, -47, + -51, -56, -59, -59, -59, -59, -61, -63, -65, -67, -70, -72, -74, -76, -78, -78, + -78, -75, -70, -66, -61, -56, -50, -41, -33, -23, -14, -6, 2, 10, 16, 19, + 21, 23, 24, 24, 22, 19, 13, 7, 0, -6, -14, -20, -25, -27, -32, -37, + -39, -39, -38, -36, -33, -30, -27, -22, -19, -19, -20, -23, -24, -22, -18, -13, + -8, -4, 0, 2, 5, 6, 5, 3, 2, 4, 6, 6, 5, 1, -2, -6, + -8, -9, -10, -11, -13, -12, -12, -11, -9, -4, 0, 4, 8, 13, 18, 20, + 19, 14, 10, 6, 4, 4, 4, 0, -8, -17, -28, -38, -49, -60, -68, -72, + -72, -70, -65, -59, -54, -46, -37, -27, -17, -5, 8, 22, 37, 51, 66, 77, + 84, 88, 91, 93, 94, 94, 91, 85, 79, 75, 74, 76, 77, 80, 83, 85, + 85, 85, 86, 86, 85, 85, 85, 83, 81, 77, 70, 64, 55, 44, 32, 22, + 13, 6, -1, -9, -16, -22, -27, -32, -38, -43, -46, -47, -47, -47, -48, -49, + -49, -50, -52, -54, -56, -59, -62, -64, -66, -65, -64, -61, -59, -56, -53, -48, + -41, -33, -25, -17, -10, -2, 4, 9, 13, 15, 16, 17, 17, 15, 11, 7, + 1, -7, -15, -22, -27, -33, -38, -43, -47, -49, -50, -50, -49, -46, -42, -37, + -31, -28, -28, -29, -30, -29, -26, -22, -17, -13, -8, -3, 2, 6, 7, 6, + 5, 6, 8, 10, 12, 11, 8, 5, 3, 1, -1, -2, -3, -4, -6, -7, + -6, -3, 0, 1, 5, 10, 16, 20, 21, 19, 15, 10, 8, 6, 6, 4, + 0, -5, -12, -22, -33, -45, -57, -65, -70, -72, -70, -68, -64, -58, -51, -44, + -36, -24, -13, -2, 11, 27, 43, 58, 70, 78, 83, 88, 92, 96, 97, 93, + 89, 85, 81, 80, 81, 83, 86, 88, 90, 91, 91, 91, 91, 91, 91, 91, + 89, 86, 83, 79, 72, 63, 52, 41, 30, 21, 13, 4, -5, -11, -17, -23, + -31, -38, -44, -47, -49, -50, -52, -54, -55, -57, -57, -58, -60, -63, -66, -69, + -72, -74, -73, -72, -70, -69, -67, -64, -59, -53, -45, -37, -30, -22, -14, -7, + -2, 3, 8, 10, 12, 12, 13, 12, 8, 3, -4, -10, -16, -21, -27, -33, + -37, -41, -44, -46, -48, -48, -45, -48, -43, -37, -33, -31, -32, -33, -32, -29, + -26, -22, -18, -12, -5, 1, 6, 9, 9, 9, 9, 11, 14, 16, 16, 14, + 12, 8, 5, 3, 2, 1, -1, -3, -4, -4, -2, -1, 2, 5, 11, 18, + 24, 27, 27, 24, 20, 17, 15, 13, 11, 9, 5, -1, -10, -22, -35, -49, + -61, -70, -75, -77, -76, -73, -69, -63, -56, -47, -36, -25, -13, 0, 16, 34, + 52, 67, 79, 88, 95, 101, 106, 109, 108, 105, 100, 95, 92, 90, 91, 93, + 96, 99, 100, 101, 101, 101, 101, 101, 101, 100, 97, 95, 91, 85, 78, 67, + 55, 43, 31, 21, 11, 1, -7, -14, -21, -29, -37, -45, -51, -54, -56, -58, + -60, -62, -64, -65, -66, -67, -69, -72, -76, -80, -82, -84, -83, -82, -80, -79, + -77, -73, -67, -60, -51, -42, -34, -25, -16, -8, -2, 4, 9, 12, 13, 14, + 14, 13, 9, 3, -5, -12, -18, -25, -31, -37, -42, -47, -50, -53, -54, -53, + -48, -41, -36, -32, -31, -31, -32, -31, -28, -25, -22, -17, -12, -5, 1, 1, + -2, -1, -9, -9, -6, 5, 6, -1, -10, 8, 24, 11, -2, -14, -9, -15, + -13, 5, 14, 12, -6, -1, -12, 1, -9, 12, 12, 10, 5, -19, -11, -13, + -2, 8, 5, 1, -2, -3, 9, -6, 6, 5, 6, -3, -17, -7, 3, 2, + -1, 0, 7, -7, 5, 4, 6, -18, -24, 6, 20, -1, -4, -1, 10, 3, + -10, 8, 7, -11, -17, -15, 5, 18, 4, 1, 8, -16, -4, 0, 11, 9, + -10, -15, 0, -22, -12, 19, 34, 16, -9, -16, -7, -12, -10, 13, 23, -1, + -10, -2, -3, -11, 13, 7, -6, -9, 3, 11, -10, -18, 12, 22, 7, -27, + -29, -4, 20, 20, 10, 8, -16, -26, -6, 22, 21, 7, 15, 8, -50, -50, + -7, 35, 22, -13, 32, 41, -33, -46, -10, 23, -7, -25, 23, 21, -38, -36, + 14, 44, 2, 2, 34, -14, -51, -29, 11, 19, 7, 22, 13, -23, -21, -8, + -9, 1, 14, 26, 26, -8, -34, -33, 4, 1, -6, -2, 16, -7, -23, 12, + 27, 5, 6, 6, 0, -8, 0, -1, -17, -13, -12, 3, 9, 4, 11, 23, + 36, 0, -43, -16, 4, -21, -26, 27, 16, -25, 3, 65, 4, -34, 24, -10, + -38, -14, 13, 4, -15, 36, 44, -42, -51, 20, -5, -6, 68, 20, -18, -39, + -11, 9, 17, 6, -33, -20, -13, 48, 30, 22, -4, -9, -53, -20, 32, 32, + -16, 17, -11, -36, -8, -5, 39, 28, 33, 21, -64, -48, 3, -22, 15, 62, + -26, 0, 3, 5, 73, -14, -48, -20, -59, 4, 70, 60, -7, -2, -88, -22, + -17, 39, 17, 33, -3, 15, 28, -47, -80, -37, 5, 7, 104, 16, -99, -92, + -36, 109, 78, 26, -15, -92, -21, 62, 48, -51, -81, -25, 55, 63, 35, 21, + -115, -54, 101, 73, -41, -110, -66, 50, 107, 45, -8, -109, -38, 12, 102, 3, + 17, -45, -2, -36, 39, 46, -12, -28, -27, -17, 17, -18, 82, -5, -3, -25, + -5, -14, 15, 9, -3, -17, -6, 2, 7, -36, -13, 6, 21, -23, -20, 16, + -18, 3, -2, 26, 0, 13, -23, -2, -19, -28, -18, 15, 12, 22, -4, 23, + -17, -22, -9, -18, -4, 11, 13, 0, 34, -16, -20, 26, 23, 15, -4, -25, + 7, 8, -9, 8, 44, 1, -40, 17, -32, 9, -30, -52, 52, 3, 2, -21, + 83, 58, -14, -46, -61, -12, -67, -20, 64, 72, 57, -10, 5, 1, -77, 31, + -47, -39, 12, 22, 57, 28, 0, 9, -76, 15, -74, 33, -12, 39, 114, -35, + -36, -38, -23, 27, -21, 14, 56, 47, 6, -72, -61, -4, 18, -4, 19, 13, + 45, 71, 48, -1, -125, -52, -56, -20, -18, -12, 51, 78, 68, -46, 32, -40, + -29, -28, -81, -25, 75, 42, 58, -38, 1, -29, -34, 31, -36, -14, 10, 64, + 37, 2, -31, -72, -17, -33, 30, -52, -54, 25, 43, 70, 81, -9, -73, 4, + -65, 15, -28, 25, 0, 28, 19, 51, -26, 6, 0, -37, -15, -22, -20, -16, + -5, 50, 56, 67, 25, 16, -35, -29, -14, -39, 19, -24, -52, -13, -32, -10, + 39, 33, 59, 6, 37, 55, 11, -9, -35, -15, -57, -56, -36, -34, 19, 19, + 6, 20, 17, -11, 5, 26, 19, 16, 7, -20, -26, -55, -62, -36, -18, 19, + 37, 47, 25, -6, -14, 1, -4, -13, 12, 23, 34, 38, 41, 33, 31, -10, + -56, -52, -49, -31, -40, -21, -12, 0, 5, 12, 22, 22, 21, 31, 12, 2, + -8, -4, -18, -7, 3, 1, -1, 11, 12, 18, 17, 9, -2, -12, -13, -11, + -1, 8, 3, 3, 2, 5, -5, -16, -15, -13, -8, -12, -9, -2, -1, 2, + 7, 10, 7, 11, 14, 7, -1, -4, 5, -3, -2, 0, -6, -10, -1, -5, + 3, 9, 0, -8, -9, -6, -6, 0, 6, 3, 6, 7, 10, 0, -8, -3, + -5, -1, -8, -7, -4, -3, -3, 0, -1, -6, 2, 7, 7, 5, 4, 10, + 5, 8, -1, -11, -15, -11, -15, -10, -1, -8, -12, -5, 1, 3, 6, 8, + 11, 18, 22, 26, 10, -10, -1, -15, -3, -21, -16, -14, -12, -7, -8, -18, + -20, -11, 9, 20, 27, 26, 11, 1, 21, 6, 3, -9, -15, -9, -20, 3, + 5, 21, 14, 6, 11, -21, -22, -6, -21, -23, -18, 11, 6, 5, 21, 9, + 23, 16, -3, -30, -7, -27, -4, 5, 18, 22, 16, 2, 7, -1, -2, -10, + -14, -10, -17, -10, -15, -16, 3, 12, 30, 18, -1, -6, -15, -3, 5, 11, + -18, -2, 8, 21, 11, -13, -4, -30, -7, 0, 12, 25, -3, 17, 14, -20, + -6, -27, -41, -11, -12, 23, -8, 13, 24, 18, 27, -11, -8, -12, -2, 17, + 23, 13, -20, -21, -2, -21, -34, -46, -23, 28, 48, 9, -10, 8, 29, 27, + 5, -29, -12, 13, -5, -2, -35, 1, 3, 24, 13, 17, -18, -30, -21, 14, + -1, 6, -8, 48, 45, -7, -34, -49, -32, -6, -26, 20, 29, 76, 30, -21, + -66, -36, -15, 40, -5, 29, 3, 10, -39, -25, -2, 24, 19, 19, -4, -8, + 3, -22, -23, -18, 13, 17, -3, -25, 23, 66, 26, -18, -27, -34, -30, -30, + 36, 25, 28, -22, -17, -7, -22, 21, 18, 42, 8, -25, -28, -31, -10, 15, + 18, 0, -1, -5, 16, -12, 13, 13, 12, -8, -37, -9, 13, -5, 8, -3, + 13, -8, 4, 24, -16, -43, -18, 26, 26, -11, -9, 19, 9, -15, 9, 15, + -12, -31, -27, 8, 29, 5, 7, 17, -33, -14, 14, 23, -1, -18, -18, -4, + -35, -17, 47, 71, -16, -20, -11, -16, -25, 6, 37, 14, -18, 1, -8, -14, + 10, 14, 2, -20, 0, 20, -10, -25, 14, 32, 7, -39, -38, -3, 34, 25, + 13, 3, -24, -34, 5, 38, 18, 7, 29, -30, -74, -41, 36, 40, -12, 26, + 55, -17, -59, -26, 28, -2, -31, 24, 25, -44, -39, 21, 44, -1, 10, 33, + -34, -50, -12, 18, 13, 20, 17, -6, -31, -10, -6, -1, 7, 12, 14, 6, + -16, -24, 6, 9, -16, -16, 6, 2, -10, 13, 12, -10, 0, 11, 11, 10, + -3, -22, -22, -12, -7, 19, 17, -2, -12, 6, 16, 7, -11, -1, -20, -22, + -8, 26, 16, -3, 12, 1, -33, 2, 30, -23, -5, 28, -17, -19, 21, 9, + -28, -14, 25, -1, 4, 24, 0, -26, -9, 7, 2, -2, 20, -10, -11, 5, + -3, -4, 8, -9, 14, 18, 25, -22, -15, -22, -3, -12, 27, 30, 15, -11, + -26, -4, 15, -7, -14, 23, -23, -4, 34, -2, -38, 14, -11, -24, 16, 34, + 11, -13, 3, -3, -19, -34, 0, -3, 24, 43, 1, -12, -38, -25, -11, 23, + 35, 12, -28, -25, -16, 7, 22, 1, -10, 8, 8, -3, 6, -24, -20, -13, + 9, 31, 12, -16, 7, -29, 5, 8, -28, 3, 4, 12, 26, -9, -15, -5, + -20, 9, 21, 0, 1, -9, 0, 8, -3, -7, -9, -3, 22, 8, 3, -11, + -9, -11, 3, 15, 9, -10, 1, -3, -3, -2, -5, 9, 0, 12, 7, -15, + -7, 0, -8, 5, 9, -5, 7, -7, 10, 4, -11, -2, -8, -4, 9, 9, + 0, -2, -11, -3, -4, 3, 4, 3, -2, 3, 3, -8, -9, -2, 0, 3, + 5, -1, -10, -7, 2, 8, 3, 0, -5, -5, 2, 4, -2, -5, -3, 2, + 3, 0, 2, -5, -3, 3, 2, -2, -4, -2, 1, 2, 1, 0, 0, 0, + 0, -1, -7, -9, -5, 0, 2, 2, 5, 6, 0, -11, -13, -5, 3, 1, + 0, 0, 1, -3, -9, -6, -1, 5, 3, -3, -5, -3, -1, -4, -3, -1, + 2, -2, -9, -7, -2, -5, -18, -31, -36, -36, -41, -38, -29, -21, -27, -31, + -26, -4, 37, 65, 67, 44, 22, 10, 2, -4, 8, 32, 44, 38, 24, 17, + 9, 4, 3, 12, 26, 32, 32, 23, 16, 7, 1, -7, -13, -8, 1, -5, + -39, -72, -79, -64, -49, -40, -24, -1, 12, 0, -25, -44, -43, -30, -14, 1, + 13, 13, 4, 4, 16, 34, 46, 55, 65, 73, 67, 53, 54, 58, 62, 60, + 51, 38, 33, 20, -7, -27, -40, -46, -55, -58, -41, -9, 7, 8, 2, -26, + -49, -71, -92, -101, -93, -80, -70, -71, -73, -65, -67, -69, -61, -42, -15, 15, + 18, -5, -33, -54, -54, -40, -18, 2, 21, 21, 3, -28, -52, -33, 9, 35, + 33, 30, 34, 45, 46, 43, 54, 63, 65, 61, 56, 43, 45, 59, 77, 96, + 104, 112, 115, 100, 78, 53, 22, -3, -6, 5, 24, 37, 38, 35, 25, 3, + -19, -38, -51, -46, -33, -34, -42, -47, -48, -38, -27, -30, -40, -48, -45, -30, + -24, -38, -44, -43, -47, -34, -13, 7, 27, 30, 9, -18, -38, -22, 19, 47, + 70, 83, 68, 28, -13, -41, -41, -19, -1, 10, 8, 4, 4, -7, -12, 6, + 32, 42, 31, 0, -39, -71, -99, -115, -111, -85, -56, -46, -61, -74, -66, -45, + -22, 4, 21, 27, 25, 1, -30, -51, -37, 4, 37, 40, 26, 17, 12, 12, + 5, 1, 2, 12, 29, 43, 44, 45, 54, 45, 28, 10, 13, 26, 32, 43, + 59, 67, 62, 60, 66, 72, 61, 34, 11, 0, 1, -6, -18, -12, 19, 47, + 51, 32, 9, -8, -22, -26, -27, -30, -29, -12, 7, 18, 13, -1, -11, -11, + 5, 16, 14, 11, 5, -19, -47, -54, -29, 13, 37, 42, 33, 9, -17, -31, + -21, 14, 61, 81, 68, 39, 4, -26, -46, -38, -17, -1, 1, -4, -14, -25, + -23, -4, 24, 43, 49, 37, 4, -48, -97, -123, -116, -89, -66, -65, -73, -67, + -64, -66, -69, -46, 3, 36, 27, -3, -25, -39, -38, -39, -36, -24, -9, 5, + 13, 13, 4, -1, -13, -15, 0, 22, 47, 65, 76, 67, 35, 3, -4, 6, + 27, 47, 58, 68, 72, 73, 72, 66, 59, 62, 61, 49, 28, -5, -30, -27, + 9, 40, 51, 46, 40, 28, 1, -30, -56, -57, -41, -13, 5, 12, 7, -11, + -38, -54, -40, -16, 12, 23, 13, -16, -49, -62, -55, -29, 4, 38, 45, 28, + -5, -36, -36, -5, 39, 68, 77, 73, 55, 8, -35, -46, -29, -15, -15, -16, + -12, -9, -23, -30, -18, 16, 48, 51, 24, -18, -45, -72, -96, -111, -101, -80, + -67, -71, -79, -77, -70, -46, -22, -7, -4, -5, -4, -2, -15, -37, -43, -42, + -27, -5, 9, 27, 38, 27, 4, -14, -15, 6, 30, 61, 93, 90, 52, 16, + 2, 1, 5, 11, 34, 64, 79, 71, 48, 35, 43, 61, 59, 46, 27, 1, + -22, -33, -25, -9, 15, 37, 56, 54, 28, -10, -44, -58, -49, -27, -8, 20, + 29, 0, -42, -66, -60, -34, -7, 16, 30, 15, -20, -50, -64, -49, -11, 21, + 34, 34, 17, -7, -31, -29, 3, 43, 69, 78, 73, 45, 10, -20, -32, -33, + -26, -12, -6, -18, -41, -44, -27, -6, 10, 17, 19, 18, -4, -49, -87, -108, + -100, -84, -87, -93, -83, -67, -54, -45, -45, -35, -23, -13, 6, 17, 14, 1, + -22, -40, -35, -18, 2, 28, 57, 63, 33, -7, -21, -4, 23, 57, 89, 102, + 94, 68, 37, 8, -4, 4, 37, 71, 88, 79, 54, 46, 55, 62, 55, 53, + 54, 46, 20, -14, -40, -41, -16, 15, 44, 60, 59, 30, -21, -61, -70, -54, + -26, 10, 29, 19, -16, -49, -63, -58, -33, 4, 29, 26, -1, -33, -49, -50, + -34, -9, 16, 34, 34, 9, -20, -25, -9, 13, 29, 54, 87, 91, 56, 11, + -12, -11, -12, -20, -22, -17, -11, -12, -22, -25, -15, 3, 19, 19, 9, -11, + -38, -62, -76, -92, -107, -109, -95, -68, -53, -49, -49, -58, -63, -48, -25, -5, + 12, 12, -7, -36, -56, -56, -32, 8, 50, 64, 36, 6, -10, -15, -11, 9, + 47, 94, 118, 100, 58, 14, -3, 3, 19, 44, 72, 83, 78, 75, 66, 53, + 45, 52, 66, 70, 52, 22, -8, -36, -36, -14, 21, 63, 84, 63, 14, -29, + -55, -54, -42, -12, 28, 40, 14, -24, -52, -58, -42, -22, 6, 19, 16, -5, + -34, -49, -43, -24, -12, 2, 14, 22, 10, -10, -20, -16, 3, 28, 60, 72, + 61, 42, 25, 1, -26, -44, -46, -31, -25, -26, -32, -30, -24, -12, -12, -15, + 0, 6, -3, -23, -47, -79, -112, -128, -115, -84, -61, -45, -42, -51, -64, -68, + -61, -33, 9, 29, 12, -28, -54, -64, -56, -30, 9, 36, 41, 34, 10, -18, + -38, -29, 13, 70, 105, 106, 79, 48, 31, 12, -1, 12, 51, 78, 89, 87, + 75, 66, 49, 44, 56, 73, 79, 66, 23, -23, -42, -39, -9, 31, 65, 75, + 52, 7, -32, -54, -57, -30, 3, 24, 19, 2, -18, -39, -50, -39, -10, 8, + 10, -2, -12, -18, -21, -29, -33, -16, 11, 28, 17, 1, -4, 3, -3, -6, + 13, 42, 64, 67, 56, 29, 2, -21, -36, -42, -40, -25, -15, -10, -7, -10, + -27, -38, -24, 2, 19, 14, -6, -44, -86, -115, -121, -109, -81, -45, -27, -36, + -58, -76, -81, -53, -13, 11, 8, -11, -24, -40, -58, -62, -30, 11, 42, 44, + 17, -15, -36, -38, -22, 15, 53, 84, 88, 73, 52, 19, -6, -9, 13, 44, + 71, 88, 93, 79, 54, 42, 46, 67, 82, 79, 54, 20, -10, -28, -27, 0, + 46, 70, 61, 29, 2, -18, -38, -45, -23, 7, 16, 10, -8, -22, -26, -30, + -32, -23, -13, -2, 6, -6, -15, -16, -18, -20, -9, 0, 2, 11, 19, 17, + -2, -21, -12, 14, 33, 50, 65, 61, 43, 19, -17, -44, -50, -42, -21, 1, + 11, 1, -31, -56, -45, -22, -1, 17, 18, -4, -44, -95, -126, -123, -95, -56, + -36, -41, -51, -59, -68, -60, -38, -15, 5, 14, 7, -17, -47, -61, -37, 1, + 27, 33, 24, 7, -13, -30, -43, -26, 13, 47, 70, 74, 68, 48, 12, -19, + -14, 14, 46, 74, 81, 75, 64, 52, 48, 56, 67, 82, 78, 44, 9, -12, + -20, -8, 18, 41, 57, 46, 23, 0, -23, -33, -21, -10, -10, -2, 3, 5, + -2, -19, -33, -32, -24, -16, -11, -14, -6, 7, -2, -20, -25, -16, -6, 6, + 17, 27, 22, 2, -10, -11, 0, 24, 51, 68, 79, 65, 25, -19, -49, -48, + -30, -9, 8, 10, -12, -40, -57, -57, -34, -1, 25, 24, -7, -56, -95, -111, + -102, -84, -69, -57, -44, -42, -59, -74, -71, -47, -17, 0, 3, -6, -21, -37, + -38, -27, -6, 15, 23, 22, 12, -4, -23, -32, -26, 1, 36, 63, 82, 78, + 46, 12, -1, 2, 20, 41, 64, 81, 79, 66, 59, 61, 67, 75, 76, 66, + 49, 27, 5, -7, 2, 24, 41, 44, 38, 28, 13, -5, -19, -21, -17, -11, + -2, 4, 4, -2, -14, -28, -32, -27, -21, -16, -13, -1, 6, -4, -21, -25, + -17, -7, 6, 0, 0, -4, -4, -5, -8, -4, 3, 8, 6, 1, 1, 2, + 3, 3, -2, -7, -11, -10, -5, -2, 4, 6, 0, -2, -5, -4, -4, -9, + -9, -7, -11, -11, -10, -7, 4, 0, -4, -4, -1, 4, 0, -4, -3, -5, + -6, -5, -4, 4, -1, 2, 11, 5, -13, -20, -30, -49, -50, -34, -22, -33, + -27, -20, -17, 0, 34, 70, 73, 42, 3, -26, -37, -25, -1, 25, 48, 71, + 75, 44, 22, 45, 69, 57, 44, 52, 58, 24, -23, -41, -50, -58, -67, -82, + -66, -29, -29, -41, -34, -19, -4, -4, -1, 20, 50, 56, 35, 12, 4, -8, + -15, 4, 28, 44, 46, 34, 17, 2, 0, 11, 28, 42, 22, -28, -51, -45, + -34, -39, -37, -19, -17, -30, -32, -18, -4, 9, 19, 38, 35, 3, -24, -35, + -40, -23, -11, -25, -47, -52, -51, -58, -61, -52, -47, -37, -17, -5, -5, -16, + -31, -24, -11, -1, -3, -23, -40, -48, -40, -12, 15, 25, 17, -5, -2, 14, + 21, 15, -12, -26, -18, -2, 28, 48, 55, 52, 42, 35, 35, 42, 38, 36, + 40, 53, 55, 52, 44, 36, 49, 57, 56, 57, 55, 50, 39, 27, 31, 30, + 15, 11, 12, 6, 4, 14, 28, 23, 1, -6, -17, -35, -44, -41, -33, -22, + -9, -6, -12, -15, -13, -27, -29, -7, 14, -5, -55, -71, -49, -33, -37, -46, + -33, -18, -43, -89, -96, -65, -23, 2, 8, 20, 24, -11, -50, -51, -12, 15, + 4, 1, 20, 47, 53, 43, 52, 77, 98, 114, 110, 100, 88, 53, 10, -29, + -55, -71, -83, -77, -58, -55, -57, -52, -48, -47, -46, -12, 34, 59, 52, 25, + -10, -33, -21, 18, 49, 54, 46, 18, 13, 30, 41, 48, 54, 53, 44, 24, + 1, -13, -25, -43, -38, -28, -35, -55, -71, -64, -40, -13, 10, 24, 38, 41, + 21, -1, -11, 1, 15, 7, -6, -13, -39, -57, -64, -51, -20, -12, -24, -37, + -30, -4, 17, 21, 12, -7, -16, -15, -7, 6, 1, -20, -34, -30, -1, 32, + 44, 36, 22, 25, 21, 6, 1, -2, -13, -5, 19, 28, 24, 12, 11, 16, + 19, 38, 54, 49, 38, 28, 28, 39, 52, 49, 32, 25, 33, 45, 49, 39, + 40, 46, 20, -9, -6, 6, 1, -22, -29, 10, 48, 33, -17, -51, -55, -44, + -49, -50, -36, -33, -57, -84, -71, -21, 11, 13, 4, -1, -8, -32, -45, -32, + -10, 2, -13, -37, -39, -42, -57, -65, -63, -36, -11, 10, 33, 22, -12, -34, + -28, -12, 2, 8, 6, -2, -4, 0, 10, 22, 36, 57, 82, 104, 122, 127, + 109, 70, 17, -28, -45, -36, -20, -33, -68, -102, -114, -103, -76, -45, -20, -7, + -11, -10, -2, 6, 0, -14, -5, 30, 48, 29, 3, -8, 10, 39, 67, 86, + 83, 59, 32, 17, 32, 46, 40, 11, -29, -48, -57, -68, -69, -57, -43, -26, + -13, -2, 1, 1, 3, 4, 8, 21, 20, 11, 3, -2, -6, -26, -39, -33, + -34, -36, -28, -23, -27, -28, -17, -1, 0, -6, -10, -9, -7, -12, -26, -44, + -54, -38, -16, 0, 18, 27, 17, -3, -18, -3, 19, 11, -9, -7, 10, 14, + 5, 5, 18, 29, 29, 12, 16, 38, 43, 14, 2, 24, 55, 59, 33, 17, + 24, 44, 65, 75, 77, 55, 15, -16, -20, 6, 31, 27, 17, 18, 19, 17, + 7, 0, -5, -20, -22, -25, -49, -69, -73, -58, -45, -29, -4, 9, -1, -23, + -51, -52, -24, -2, 11, 12, -16, -51, -75, -77, -67, -59, -59, -54, -35, -15, + -9, -9, -9, -7, -8, -12, -1, 15, 22, 10, -14, -34, -28, -14, 11, 64, + 113, 127, 117, 97, 87, 84, 68, 50, 37, 36, 24, -15, -58, -78, -84, -71, + -40, -14, -12, -34, -48, -41, -14, 20, 37, 35, 16, -6, 1, 14, 15, 20, + 23, 24, 38, 58, 69, 57, 40, 54, 73, 75, 65, 40, -3, -49, -68, -56, + -42, -42, -53, -59, -44, -23, -9, -3, -11, -18, -13, -11, -5, 3, 13, 4, + -25, -39, -22, -14, -16, -27, -38, -37, -42, -55, -51, -21, 8, 10, -8, -12, + -4, -10, -39, -55, -38, -13, -4, -11, -15, -3, 15, 12, 2, 11, 28, 34, + 15, -5, 3, 11, 6, 12, 25, 25, 13, 10, 15, 27, 48, 55, 38, 23, + 17, 23, 32, 23, 32, 57, 75, 75, 52, 22, 10, 5, 12, 28, 33, 23, + 2, -14, -4, 19, 30, 25, 15, 1, -27, -64, -78, -67, -49, -45, -48, -42, + -31, -25, -40, -50, -39, -18, -4, 13, 19, 12, -10, -43, -59, -53, -47, -54, + -61, -51, -20, -2, -12, -23, -25, -18, 5, 33, 51, 45, 16, -16, -46, -53, + -38, -6, 33, 57, 74, 81, 75, 77, 89, 105, 114, 110, 83, 39, -6, -25, + -28, -39, -48, -52, -55, -59, -67, -67, -57, -42, -23, -3, 10, 3, -19, -33, + -30, -8, 20, 23, 2, -18, -17, 12, 40, 58, 65, 65, 66, 71, 64, 54, + 38, 1, -41, -62, -47, -26, -31, -49, -55, -42, -21, -17, -19, -10, -2, -3, + -10, -13, 2, 13, -10, -38, -27, 3, 8, -18, -46, -61, -65, -53, -36, -18, + -5, -6, -14, -22, -18, -12, -19, -29, -28, -21, -10, -15, -24, -18, -4, 16, + 23, 17, 14, 10, 9, 13, 15, 28, 35, 19, 4, 2, -2, 9, 34, 62, + 66, 43, 13, -2, 15, 42, 50, 48, 51, 56, 56, 45, 44, 45, 48, 40, + 33, 31, 27, 10, -10, -4, 16, 41, 52, 48, 31, -1, -36, -56, -50, -27, + -14, -25, -43, -60, -67, -47, -31, -38, -47, -40, -17, 13, 32, 28, -10, -50, + -68, -62, -40, -21, -20, -33, -58, -72, -63, -45, -28, -11, 18, 48, 42, 15, + -14, -43, -54, -40, -15, 4, 2, -5, 0, 20, 55, 91, 113, 120, 109, 89, + 77, 63, 43, 26, 20, 12, -13, -47, -69, -68, -53, -49, -49, -36, -28, -27, + -27, -28, -12, 5, 1, -9, -2, 14, 10, -25, -39, -6, 21, 35, 41, 53, + 73, 82, 74, 64, 54, 39, 9, -23, -37, -30, -22, -30, -52, -62, -54, -32, + -9, 2, 5, -3, -17, -25, -17, -1, 13, 8, -7, -12, -7, -7, -21, -40, + -51, -51, -38, -21, -16, -22, -29, -33, -23, -10, -2, -9, -24, -33, -33, -29, + -21, -8, 3, 2, -10, -18, -11, 8, 26, 32, 27, 21, 14, 7, 1, 3, + 12, 22, 35, 45, 43, 29, 13, 10, 20, 37, 54, 59, 45, 28, 28, 37, + 48, 55, 60, 60, 43, 17, 0, -3, 9, 24, 31, 31, 28, 28, 26, 14, + -5, -22, -31, -30, -21, -7, -8, -34, -63, -82, -80, -63, -45, -28, -14, -5, + 3, 2, -11, -27, -39, -33, -11, 2, -8, -39, -73, -95, -91, -54, -8, 19, + 16, 4, 5, 14, 14, 2, -8, -14, -19, -33, -45, -38, -19, 2, 21, 54, + 93, 106, 90, 74, 80, 97, 98, 76, 52, 34, 10, -18, -37, -36, -27, -35, + -52, -62, -56, -44, -39, -37, -29, -17, -8, -2, 3, 4, -4, -16, -27, -32, + -19, 1, 19, 41, 60, 70, 71, 67, 64, 61, 53, 38, 14, -8, -21, -29, + -34, -38, -39, -29, -15, 0, 5, -5, -19, -25, -16, 5, 19, 17, 6, -3, + -7, 0, -1, 1, -2, -5, 0, 0, 2, 0, -3, -2, 0, 1, 0, -2, + -2, -2, 0, 3, 3, -2, -5, -1, -1, -1, -4, 3, 9, 1, -1, -2, + -11, -7, 1, 9, 11, 8, -4, -11, -12, -9, -4, 18, 15, 14, 1, -22, + -29, -14, 3, 30, 29, 14, -2, -35, -43, -11, 13, 36, 42, 15, -16, -49, + -44, -10, 28, 47, 38, 11, -25, -66, -39, 4, 36, 58, 33, -3, -44, -65, + -29, 19, 52, 54, 23, -13, -59, -65, -15, 32, 69, 49, 8, -30, -74, -51, + 3, 43, 71, 40, -5, -48, -77, -31, 16, 57, 67, 24, -15, -67, -72, -12, + 36, 66, 59, 5, -31, -80, -51, 3, 49, 75, 37, -2, -59, -81, -28, 20, + 67, 66, 22, -23, -76, -65, -10, 41, 78, 48, 4, -36, -85, -47, 6, 59, + 80, 31, -8, -69, -82, -22, 29, 73, 63, 17, -31, -81, -63, -1, 47, 79, + 47, 3, -56, -90, -40, 19, 75, 73, 28, -25, -86, -74, -10, 48, 85, 56, + 6, -51, -93, -48, 11, 67, 86, 33, -11, -78, -87, -29, 36, 89, 66, 13, + -38, -91, -60, 2, 50, 83, 48, 0, -56, -90, -41, 16, 71, 78, 30, -17, + -80, -75, -20, 31, 82, 62, 15, -32, -85, -66, -7, 48, 84, 50, 4, -53, + -87, -44, 8, 62, 78, 35, -8, -65, -83, -30, 23, 70, 71, 24, -20, -76, + -75, -12, 32, 73, 62, 15, -30, -85, -62, -2, 41, 76, 51, 9, -39, -86, + -52, 1, 45, 79, 46, 8, -49, -89, -46, 3, 54, 80, 43, 7, -55, -83, + -50, 0, 53, 76, 54, 11, -52, -83, -55, 0, 40, 67, 58, 22, -32, -79, + -67, -11, 28, 63, 52, 37, -9, -70, -63, -28, 10, 42, 49, 53, 8, -46, + -64, -41, 1, 22, 38, 51, 39, -16, -63, -46, -23, 5, 33, 38, 48, 14, + -42, -57, -29, -5, 22, 37, 40, 28, -23, -53, -39, -10, 14, 30, 40, 31, + -1, -48, -40, -18, 11, 19, 31, 26, 14, -20, -50, -25, -5, 11, 31, 30, + 14, 0, -35, -39, -4, -1, 19, 27, 17, 9, -10, -39, -21, -8, 9, 24, + 26, 13, -5, -19, -30, -12, -1, 17, 25, 16, 3, -19, -26, -13, -6, 17, + 22, 20, 5, -16, -32, -19, -1, 23, 27, 23, 4, -30, -33, -23, -1, 35, + 35, 24, -2, -41, -45, -21, 9, 45, 41, 22, -12, -50, -46, -18, 28, 55, + 45, 10, -27, -78, -42, 0, 53, 66, 32, -1, -61, -74, -28, 27, 64, 64, + 24, -28, -80, -66, -15, 53, 84, 48, 5, -59, -94, -41, 17, 75, 80, 26, + -21, -91, -79, -12, 48, 87, 55, 10, -58, -96, -46, 9, 80, 81, 30, -23, + -84, -80, -15, 49, 90, 49, 9, -57, -95, -45, 17, 76, 79, 26, -20, -91, + -75, -18, 52, 90, 52, 6, -59, -92, -41, 15, 68, 80, 31, -21, -87, -76, + -13, 45, 87, 49, 11, -60, -94, -35, 14, 80, 68, 22, -23, -89, -66, -7, + 47, 93, 44, -8, -61, -95, -31, 24, 86, 75, 10, -35, -96, -66, -1, 61, + 100, 44, -12, -77, -105, -33, 32, 97, 92, 16, -44, -111, -90, -5, 65, 121, + 65, -3, -80, -123, -59, 17, 98, 111, 46, -25, -112, -109, -33, 42, 112, 90, + 30, -55, -115, -84, -17, 66, 105, 71, 13, -73, -113, -61, 0, 77, 96, 56, + 4, -80, -108, -50, 8, 78, 93, 47, 3, -88, -98, -40, 7, 65, 76, 53, + 18, -71, -90, -44, 0, 39, 57, 43, 34, -19, -69, -54, -19, 18, 32, 31, + 34, 7, -40, -36, -21, -1, 12, 12, 25, 27, -9, -32, -14, -14, 2, 0, + 1, 20, 19, -2, -13, -11, -18, -12, -2, 18, 24, 12, -2, -14, -19, -19, + -12, 18, 24, 22, -2, -15, -32, -20, 3, 22, 26, 17, -13, -31, -27, -13, + 17, 33, 32, 5, -29, -47, -29, 2, 33, 42, 32, -6, -53, -52, -24, 22, + 51, 41, 27, -32, -74, -45, 0, 45, 59, 33, -1, -62, -66, -31, 26, 73, + 49, 17, -42, -80, -42, -8, 63, 72, 28, -10, -75, -72, -23, 32, 88, 47, + 13, -56, -93, -38, 10, 76, 69, 26, -20, -96, -66, -10, 48, 90, 47, 0, + -69, -103, -29, 25, 87, 73, 18, -35, -104, -68, -2, 61, 93, 47, -5, -83, + -98, -31, 30, 92, 68, 17, -39, -97, -63, -5, 64, 88, 35, -9, -74, -86, + -22, 31, 85, 54, 13, -44, -93, -46, 9, 65, 75, 23, -17, -75, -78, -15, + 39, 84, 54, 3, -52, -96, -46, 12, 71, 90, 29, -18, -89, -87, -26, 36, + 86, 72, 26, -37, -106, -77, -12, 45, 99, 68, 22, -46, -108, -73, -10, 43, + 87, 69, 19, -27, -92, -79, -12, 27, 63, 57, 26, 4, -53, -75, -35, 12, + 33, 37, 31, 26, -9, -53, -39, -16, 6, 20, 23, 22, 13, -8, -22, -23, + -18, -3, 9, 25, 19, 4, -8, -20, -17, -10, 6, 16, 17, 13, -8, -34, + -21, -6, 17, 33, 23, 6, -32, -51, -23, 11, 36, 46, 31, -11, -46, -65, + -31, 15, 59, 55, 28, -20, -73, -64, -26, 42, 78, 51, 14, -53, -85, -48, + -4, 70, 80, 38, -16, -80, -76, -32, 39, 90, 58, 19, -59, -99, -50, 14, + 71, 75, 36, -21, -94, -70, -23, 51, 88, 53, 9, -68, -97, -40, 16, 83, + 73, 29, -33, -100, -61, -13, 58, 87, 41, 0, -74, -81, -35, 24, 87, 55, + 20, -41, -88, -58, 0, 69, 73, 34, -5, -86, -75, -20, 38, 79, 49, 13, + -48, -90, -39, 2, 71, 68, 31, -16, -84, -67, -15, 38, 79, 42, 12, -50, + -85, -37, 2, 62, 71, 34, -5, -83, -75, -24, 27, 82, 51, 27, -30, -88, + -54, -15, 44, 73, 50, 16, -49, -81, -47, -6, 38, 58, 50, 27, -31, -69, + -52, -13, 15, 36, 45, 33, -5, -41, -44, -23, 2, 14, 27, 33, 10, -25, + -20, -18, -6, 1, -1, 17, 22, 3, -13, -10, -17, -13, -6, 13, 24, 15, + 1, -11, -19, -19, -16, 12, 24, 24, 3, -12, -29, -26, -1, 18, 27, 19, + -4, -31, -28, -19, 11, 30, 35, 12, -21, -46, -35, -6, 28, 42, 36, 5, + -46, -57, -31, 10, 50, 43, 33, -16, -71, -55, -9, 35, 62, 38, 10, -51, + -71, -40, 11, 69, 58, 24, -26, -81, -50, -18, 48, 79, 37, 1, -62, -81, + -32, 16, 84, 59, 20, -37, -96, -50, -2, 63, 78, 33, -4, -85, -80, -20, + 33, 88, 59, 10, -50, -107, -47, 14, 75, 85, 27, -19, -95, -83, -15, 47, + 94, 60, 8, -66, -105, -46, 15, 83, 81, 26, -23, -91, -76, -18, 48, 92, + 47, 1, -59, -94, -36, 18, 78, 66, 19, -27, -91, -60, -3, 53, 80, 35, + -8, -62, -86, -28, 27, 79, 66, 13, -38, -94, -62, 1, 56, 95, 42, -6, + -75, -96, -39, 22, 80, 80, 36, -20, -97, -92, -24, 30, 93, 79, 32, -27, + -102, -87, -22, 31, 81, 79, 29, -14, -81, -91, -25, 19, 56, 63, 31, 11, + -39, -77, -47, 3, 31, 37, 33, 27, 3, -48, -46, -20, 0, 18, 22, 23, + 16, -3, -20, -19, -15, -4, 2, 8, 5, 0, 0, 0, 0, 2, 2, 5, + 9, 12, 14, 12, 7, 6, 4, 0, -1, -1, 1, -2, -2, -11, -17, -32, + -41, -49, -55, -58, -61, -61, -65, -61, -57, -47, -37, -27, -22, -15, -5, 6, + 12, 16, 21, 27, 28, 32, 33, 35, 41, 44, 45, 47, 50, 54, 57, 56, + 53, 53, 54, 50, 50, 52, 54, 56, 52, 53, 54, 50, 49, 46, 43, 38, + 33, 27, 19, 8, 2, -11, -20, -27, -29, -30, -32, -35, -42, -52, -57, -57, + -59, -48, -40, -27, -13, 4, 13, 20, 18, 14, 11, 7, 3, -1, -3, -10, + -11, -20, -28, -46, -60, -72, -82, -92, -97, -97, -97, -94, -90, -81, -71, -61, + -55, -55, -53, -47, -38, -29, -23, -11, -6, -3, 1, 2, 5, 6, 3, 3, + 5, 15, 24, 28, 30, 30, 35, 37, 36, 39, 39, 44, 47, 48, 56, 62, + 73, 84, 91, 96, 95, 91, 85, 76, 72, 63, 55, 47, 44, 43, 41, 38, + 31, 19, 7, 0, -9, -7, -4, 8, 22, 40, 54, 67, 71, 70, 64, 56, + 45, 32, 24, 15, 12, 3, -3, -21, -42, -66, -84, -102, -117, -124, -128, -127, + -124, -118, -107, -96, -86, -86, -88, -86, -80, -70, -63, -50, -40, -33, -25, -23, + -20, -18, -18, -21, -25, -22, -14, -8, -3, -3, -1, 1, 0, 1, -3, -1, + 2, 4, 13, 24, 35, 49, 59, 67, 70, 69, 68, 59, 54, 46, 40, 31, + 29, 27, 25, 23, 20, 12, -1, -9, -19, -22, -21, -11, 3, 23, 41, 60, + 71, 76, 73, 71, 65, 56, 50, 44, 42, 35, 33, 24, 9, -13, -31, -48, + -65, -76, -83, -83, -82, -77, -69, -59, -46, -40, -40, -41, -38, -30, -24, -13, + -2, 8, 17, 22, 24, 25, 23, 20, 13, 9, 11, 15, 19, 16, 12, 9, + 4, 1, -6, -10, -11, -14, -12, -5, 3, 15, 26, 35, 40, 41, 41, 35, + 28, 19, 12, 3, -2, -6, -7, -10, -13, -19, -31, -39, -50, -56, -58, -52, + -41, -22, -3, 18, 34, 46, 48, 47, 45, 38, 32, 26, 24, 20, 19, 15, + 5, -14, -32, -49, -65, -79, -88, -91, -91, -88, -82, -75, -63, -52, -47, -46, + -46, -38, -31, -21, -8, 4, 17, 26, 31, 36, 39, 42, 40, 35, 36, 39, + 47, 48, 45, 43, 38, 36, 30, 24, 22, 19, 18, 23, 29, 40, 50, 61, + 68, 72, 74, 71, 66, 57, 50, 40, 32, 24, 21, 16, 12, 7, -3, -14, + -26, -38, -45, -46, -43, -31, -16, 3, 18, 33, 39, 39, 36, 31, 22, 13, + 8, 3, -1, -4, -9, -24, -42, -60, -77, -94, -107, -115, -119, -120, -116, -112, + -103, -91, -81, -78, -80, -75, -69, -61, -51, -39, -25, -13, -5, 2, 8, 14, + 17, 16, 15, 16, 24, 31, 32, 32, 29, 29, 27, 22, 21, 20, 19, 22, + 26, 35, 46, 59, 70, 77, 83, 85, 84, 79, 74, 66, 59, 50, 46, 41, + 38, 35, 29, 21, 11, 0, -9, -14, -16, -11, 0, 16, 30, 48, 58, 62, + 61, 58, 51, 40, 31, 25, 19, 15, 13, 4, -11, -28, -44, -61, -76, -87, + -95, -100, -100, -99, -95, -86, -75, -68, -69, -68, -67, -62, -56, -49, -38, -27, + -19, -13, -9, -3, 2, 1, -1, -3, 0, 7, 10, 10, 6, 5, 4, 0, + -4, -5, -7, -7, -7, -2, 5, 16, 27, 36, 44, 49, 52, 50, 46, 40, + 35, 26, 22, 18, 15, 15, 13, 9, 4, -5, -14, -19, -23, -21, -14, 0, + 15, 33, 49, 60, 63, 63, 61, 53, 44, 38, 32, 27, 27, 23, 14, 0, + -14, -29, -44, -58, -67, -74, -76, -76, -73, -67, -55, -45, -41, -41, -41, -39, + -35, -30, -23, -12, -3, 4, 9, 14, 20, 21, 20, 17, 15, 19, 24, 26, + 24, 21, 20, 18, 12, 9, 6, 3, 0, 1, 4, 11, 21, 30, 38, 43, + 47, 48, 45, 38, 32, 23, 15, 9, 5, 3, 1, -2, -5, -13, -22, -30, + -37, -41, -40, -30, -18, -3, 15, 30, 38, 41, 41, 37, 27, 19, 12, 6, + 3, 2, -2, -13, -25, -39, -53, -67, -78, -88, -92, -92, -91, -86, -77, -63, + -54, -50, -48, -47, -43, -38, -32, -23, -11, -1, 6, 11, 19, 25, 27, 26, + 24, 26, 31, 36, 38, 36, 37, 37, 34, 32, 29, 27, 24, 22, 23, 27, + 35, 45, 53, 61, 67, 70, 71, 66, 60, 51, 42, 34, 28, 24, 21, 18, + 16, 11, 2, -8, -16, -24, -28, -25, -17, -5, 10, 26, 39, 45, 47, 45, + 37, 27, 18, 9, 3, 0, -2, -10, -22, -36, -51, -67, -81, -93, -102, -107, + -108, -107, -102, -90, -78, -71, -67, -66, -63, -59, -56, -49, -39, -28, -19, -13, + -6, 1, 7, 8, 6, 5, 8, 14, 19, 19, 19, 20, 20, 19, 16, 15, + 13, 12, 11, 13, 20, 30, 39, 49, 57, 63, 68, 68, 65, 58, 51, 43, + 37, 32, 29, 27, 26, 24, 19, 11, 2, -5, -12, -14, -9, 0, 13, 30, + 46, 56, 62, 65, 61, 53, 44, 35, 26, 22, 20, 15, 6, -6, -20, -36, + -51, -66, -78, -87, -91, -92, -92, -85, -74, -65, -58, -56, -55, -52, -50, -46, + -40, -30, -20, -14, -8, -2, 5, 7, 6, 3, 2, 5, 10, 11, 10, 9, + 9, 8, 5, 2, 0, -2, -5, -5, -3, 5, 14, 23, 32, 39, 46, 50, + 49, 45, 38, 31, 24, 17, 14, 11, 10, 9, 7, 2, -5, -12, -20, -25, + -25, -19, -8, 7, 24, 40, 50, 58, 60, 56, 49, 41, 31, 24, 22, 20, + 15, 6, -5, -19, -34, -48, -61, -72, -79, -83, -85, -81, -72, -62, -52, -47, + -44, -41, -39, -35, -31, -24, -13, -5, 1, 7, 14, 20, 22, 21, 19, 18, + 22, 25, 25, 24, 23, 23, 20, 17, 15, 12, 10, 7, 5, 9, 16, 24, + 33, 40, 47, 53, 56, 54, 48, 41, 33, 25, 20, 15, 11, 9, 8, 5, + -2, -10, -19, -27, -32, -31, -25, -15, 0, 17, 30, 40, 46, 46, 42, 35, + 25, 15, 10, 9, 5, -2, -11, -23, -37, -52, -65, -79, -89, -95, -99, -100, + -95, -85, -74, -65, -60, -55, -52, -48, -44, -40, -29, -18, -10, -4, 4, 12, + 18, 20, 19, 17, 20, 24, 27, 27, 26, 26, 25, 23, 21, 19, 17, 15, + 12, 13, 17, 25, 34, 41, 49, 57, 62, 65, 63, 57, 51, 42, 35, 30, + 25, 22, 21, 19, 15, 8, 0, -9, -17, -21, -20, -14, -3, 13, 26, 38, + 48, 53, 52, 47, 39, 28, 19, 15, 13, 8, 0, -10, -22, -37, -51, -65, + -79, -88, -95, -100, -99, -94, -84, -74, -67, -61, -58, -55, -51, -49, -43, -33, + -23, -17, -10, -2, 6, 10, 11, 9, 9, 12, 15, 17, 16, 16, 16, 14, + 12, 11, 9, 8, 5, 3, 4, 10, 18, 26, 34, 42, 50, 57, 59, 57, + 52, 45, 38, 32, 27, 23, 21, 20, 19, 14, 8, 1, -9, 2, 5, 7, + 8, -1, 6, 15, 1, 20, 28, 1, 37, 41, 31, 29, 27, 61, 40, -12, + 38, 52, -16, -20, -1, -23, -48, -56, -63, -61, -77, -100, -88, -76, -103, -113, + -98, -103, -118, -120, -108, -107, -104, -110, -118, -104, -109, -128, -107, -83, -106, -86, + -94, -100, -77, -113, -88, -43, -77, -46, -44, -69, -34, -54, -39, 4, -30, 11, + 18, -25, 20, 16, 10, 52, 35, 52, 74, 33, 55, 74, 59, 70, 81, 85, + 91, 81, 72, 89, 94, 82, 80, 99, 100, 85, 86, 91, 100, 91, 81, 91, + 102, 83, 74, 92, 95, 63, 62, 75, 71, 63, 39, 54, 74, 15, 1, 31, + 6, -5, -13, -20, -8, -44, -59, -38, -69, -73, -67, -86, -90, -68, -73, -77, + -49, -82, -70, -43, -76, -27, 0, -29, 22, 25, -5, 44, 45, 29, 66, 71, + 49, 84, 92, 73, 92, 74, 72, 91, 37, 48, 99, 47, 31, 44, 36, 33, + -5, -11, 26, 6, -33, -22, -6, -32, -55, -44, -45, -52, -63, -73, -55, -51, + -77, -79, -61, -73, -91, -83, -70, -77, -74, -82, -85, -68, -88, -98, -57, -67, + -77, -58, -75, -66, -64, -78, -33, -37, -50, -19, -47, -38, -23, -41, 3, 6, + -7, 30, 0, -4, 24, 15, 31, 45, 44, 66, 44, 34, 58, 54, 59, 67, + 71, 87, 78, 60, 73, 84, 78, 76, 86, 95, 89, 76, 85, 94, 89, 73, + 82, 99, 85, 66, 75, 93, 75, 50, 56, 69, 59, 31, 31, 61, 29, -15, + 15, 5, -15, -14, -36, -25, -29, -69, -55, -53, -82, -78, -76, -95, -88, -69, + -80, -65, -63, -86, -58, -67, -59, -12, -28, -9, 29, -8, 13, 44, 22, 44, + 68, 53, 62, 91, 74, 81, 89, 64, 84, 78, 35, 78, 86, 44, 43, 47, + 45, 22, -5, 17, 21, -16, -24, -14, -14, -34, -50, -40, -36, -63, -71, -58, + -60, -69, -78, -78, -67, -81, -98, -78, -71, -89, -85, -84, -86, -82, -99, -82, + -60, -76, -75, -74, -76, -71, -86, -68, -37, -51, -34, -41, -57, -37, -51, -31, + -7, -17, -3, 1, 7, 22, 31, 46, 57, 41, 43, 56, 63, 62, 68, 85, + 86, 80, 84, 92, 96, 93, 93, 104, 105, 96, 99, 108, 106, 102, 98, 102, + 111, 99, 87, 106, 110, 85, 80, 88, 89, 79, 68, 70, 81, 48, 25, 39, + 32, 18, 9, 12, 0, -29, -31, -38, -60, -52, -63, -79, -71, -66, -62, -59, + -62, -74, -72, -73, -81, -43, -21, -28, 8, 10, -10, 16, 28, 27, 42, 50, + 47, 66, 76, 68, 81, 73, 67, 72, 39, 40, 67, 41, 23, 25, 22, 12, + -16, -22, -5, -27, -51, -44, -45, -57, -68, -73, -71, -74, -91, -89, -84, -90, + -97, -98, -98, -102, -105, -108, -103, -97, -105, -109, -101, -107, -113, -106, -92, -87, + -90, -92, -92, -92, -100, -92, -57, -56, -54, -40, -59, -58, -54, -61, -23, -9, + -12, 16, 0, -14, 4, 5, 17, 32, 41, 57, 55, 43, 54, 66, 67, 68, + 84, 89, 87, 87, 91, 98, 100, 96, 104, 109, 105, 103, 108, 111, 109, 105, + 105, 113, 111, 99, 102, 115, 104, 88, 90, 97, 93, 80, 75, 86, 75, 37, + 40, 43, 33, 20, 20, -14, -26, -36, -53, -52, -65, -75, -75, -69, -69, -69, + -74, -77, -76, -74, -59, -34, -26, -9, 9, 5, 13, 32, 39, 42, 53, 58, + 61, 73, 77, 77, 73, 61, 57, 46, 29, 37, 37, 17, 6, 2, -10, -27, + -38, -41, -46, -58, -68, -69, -75, -85, -89, -92, -97, -101, -103, -106, -107, -108, + -112, -111, -112, -115, -115, -115, -113, -111, -116, -115, -112, -116, -117, -110, -101, -98, + -101, -101, -98, -101, -101, -86, -69, -65, -59, -57, -62, -58, -54, -39, -19, -12, + 1, 7, -1, 5, 16, 24, 36, 46, 58, 64, 61, 64, 74, 79, 81, 90, + 96, 97, 100, 100, 104, 108, 107, 111, 114, 113, 115, 115, 115, 118, 117, 116, + 118, 119, 116, 115, 116, 117, 111, 104, 105, 107, 99, 93, 95, 91, 71, 57, + 53, 47, 38, 29, 23, 14, -11, -28, -38, -49, -58, -67, -73, -80, -84, -84, + -83, -82, -80, -78, -74, -67, -56, -42, -29, -16, -4, 7, 18, 29, 40, 49, + 57, 64, 70, 74, 78, 79, 77, 72, 67, 60, 53, 48, 42, 33, 23, 14, + 4, -6, -16, -24, -32, -40, -48, -55, -61, -68, -74, -78, -83, -87, -91, -94, + -96, -99, -101, -103, -104, -106, -107, -107, -107, -107, -107, -108, -107, -107, -107, -105, + -101, -98, -96, -94, -93, -91, -87, -82, -74, -67, -62, -57, -54, -49, -43, -35, + -25, -16, -7, -1, 4, 10, 17, 25, 33, 41, 49, 55, 59, 63, 69, 74, + 78, 83, 88, 91, 93, 96, 98, 100, 102, 104, 106, 107, 107, 108, 108, 109, + 109, 108, 108, 108, 107, 105, 104, 102, 99, 94, 91, 87, 83, 78, 73, 66, + 56, 46, 37, 28, 19, 9, 0, -11, -23, -35, -45, -55, -64, -71, -78, -83, + -85, -84, -83, -81, -79, -75, -70, -61, -49, -36, -23, -10, 2, 12, 24, 35, + 45, 53, 61, 67, 72, 76, 79, 78, 75, 70, 65, 58, 52, 46, 39, 29, + 20, 11, 1, -9, -18, -26, -34, -42, -50, -56, -63, -69, -74, -79, -83, -88, + -91, -94, -96, -98, -101, -102, -104, -105, -106, -106, -106, -106, -106, -106, -106, -106, + -105, -102, -98, -96, -94, -92, -90, -88, -84, -77, -70, -64, -59, -55, -51, -45, + -38, -29, -20, -11, -4, 2, 7, 13, 21, 29, 37, 44, 51, 56, 60, 65, + 70, 75, 80, 84, 88, 91, 93, 96, 98, 100, 102, 104, 105, 106, 107, 107, + 108, 108, 107, 107, 107, 106, 104, 103, 101, 99, 95, 91, 87, 83, 78, 73, + 67, 59, 49, 39, 30, 21, 12, 3, -8, -19, -31, -41, -51, -60, -68, -75, + -81, -84, -85, -84, -82, -80, -77, -73, -65, -55, -42, -29, -16, -4, 7, 18, + 29, 40, 49, 57, 64, 70, 74, 78, 79, 77, 73, 68, 62, 56, 50, 44, + 36, 26, 17, 7, -3, -12, -20, -28, -36, -44, -51, -58, -64, -70, -75, -79, + -84, -88, -91, -93, -96, -98, -100, -102, -103, -105, -105, -105, -105, -105, -105, -105, + -105, -104, -102, -99, -96, -94, -92, -90, -88, -85, -79, -72, -66, -61, -56, -52, + -47, -41, -33, -24, -15, -8, -1, 4, 10, 17, 24, 32, 40, 47, 53, 57, + 62, 67, 72, 77, 81, 85, 89, 91, 94, 96, 98, 100, 102, 104, 105, 105, + 106, 106, 107, 106, 106, 106, 105, 104, 102, 101, 99, 95, 91, 87, 83, 79, + 74, 68, 61, 52, 42, 33, 24, 15, 5, -5, -15, -27, -38, -48, -57, -66, + -72, -79, -83, -85, -85, -83, -81, -79, -75, -69, -60, -48, -35, -23, -10, 2, + 13, 24, 35, 45, 54, 61, 67, 72, 77, 78, 79, 76, 72, 66, 60, 54, + 49, 41, 32, 23, 12, 3, -4, -17, -15, 1, -1, 0, 0, 1, 3, 5, + 9, 13, 18, 24, 32, 38, 32, 18, -9, -48, -73, -41, 2, -3, -24, -34, + -44, -72, -111, -124, -62, 40, 40, -51, -35, 45, 46, -22, -79, 35, 78, -47, + -98, -88, -69, -57, -44, -31, -17, -9, -3, 6, 41, 85, 43, -91, -128, -65, + -25, -21, -19, -12, 2, 16, 29, 39, 49, 48, 10, -69, -47, 50, 8, -52, + -44, 5, 21, -40, -42, 33, 79, 66, 38, 24, 25, 26, 18, 21, 70, 117, + 98, 28, -1, 20, 22, 0, 1, 9, -10, -49, -33, 39, 68, 39, -5, -17, + -58, -76, 78, 104, 17, 6, -23, -43, -13, 58, 85, 43, 21, 35, 46, 31, + 22, 35, 14, -48, -74, -38, 6, 10, -8, -17, -24, -37, -60, -69, -41, 15, + 27, -21, -26, 18, 28, -1, -41, 5, 51, -9, -51, -48, -38, -31, -24, -16, + -8, -2, 1, 6, 23, 52, 41, -39, -83, -50, -19, -13, -12, -8, 1, 10, + 20, 27, 34, 35, 15, -40, -46, 27, 16, -35, -38, -6, 19, -18, -35, 17, + 61, 55, 33, 21, 22, 25, 21, 18, 52, 98, 92, 31, -5, 9, 17, -1, + -2, 7, -7, -47, -43, 24, 62, 39, -3, -20, -48, -88, 46, 113, 25, 4, + -20, -45, -25, 42, 82, 47, 19, 28, 42, 32, 18, 30, 19, -39, -77, -51, + -4, 10, -6, -18, -25, -37, -57, -70, -50, 4, 26, -15, -33, 9, 27, 6, + -38, -12, 50, 6, -47, -50, -40, -32, -25, -17, -10, -3, 0, 4, 17, 45, + 47, -23, -82, -60, -24, -14, -13, -10, -2, 7, 16, 24, 30, 33, 18, -32, + -56, 13, 23, -31, -41, -15, 19, -6, -35, 4, 52, 55, 35, 21, 22, 25, + 22, 15, 41, 89, 94, 38, -5, 4, 16, 2, -2, 7, -4, -41, -48, 12, + 58, 43, 2, -20, -38, -89, 14, 118, 38, 3, -15, -43, -32, 28, 78, 53, + 19, 24, 40, 34, 18, 26, 23, -28, -75, -61, -14, 10, -2, -16, -24, -34, + -53, -68, -55, -7, 25, -8, -36, 1, 27, 12, -31, -26, 45, 22, -39, -50, + -41, -32, -25, -17, -10, -4, 0, 3, 13, 38, 51, -5, -77, -69, -31, -15, + -14, -11, -4, 5, 13, 21, 27, 31, 20, -24, -61, -3, 28, -23, -43, -23, + 15, 5, -32, -6, 43, 53, 36, 22, 21, 26, 24, 14, 32, 79, 95, 46, + -3, 0, 15, 5, -1, 7, -1, -36, -52, 2, 53, 46, 7, -18, -30, -84, + -15, 114, 55, 4, -10, -40, -37, 15, 72, 59, 22, 20, 36, 36, 19, 23, + 26, -18, -70, -68, -25, 7, 2, -13, -22, -32, -49, -65, -59, -16, 22, -1, + -36, -8, 25, 17, -22, -35, 34, 36, -29, -48, -42, -32, -25, -18, -10, -4, + 0, 3, 10, 32, 52, 11, -67, -76, -38, -16, -13, -11, -6, 3, 11, 19, + 25, 30, 22, -15, -62, -19, 30, -14, -43, -30, 9, 13, -25, -15, 33, 51, + 37, 23, 21, 26, 26, 15, 24, 68, 94, 54, 0, -3, 13, 8, 1, 8, + 2, -30, -53, -8, 47, 49, 13, -16, -25, -75, -41, 102, 73, 6, -5, -36, + -40, 2, 65, 64, 25, 18, 33, 37, 21, 21, 27, -8, -63, -73, -36, 2, + 5, -10, -21, -30, -45, -62, -61, -25, 17, 5, -35, -17, 21, 21, -13, -39, + 20, 46, -16, -46, -42, -32, -25, -17, -10, -4, 0, 3, 8, 27, 50, 25, + -54, -81, -46, -19, -13, -12, -7, 1, 9, 17, 23, 28, 23, -8, -59, -35, + 27, -5, -42, -35, 2, 20, -16, -20, 24, 47, 38, 24, 21, 27, 28, 17, + 18, 58, 91, 62, 5, -6, 10, 10, 3, 9, 5, -24, -52, -17, 40, 50, + 18, -13, -22, -64, -60, 83, 90, 12, -3, -31, -41, -8, 55, 67, 30, 17, + 30, 37, 24, 19, 27, 1, -54, -75, -46, -4, 7, -7, -18, -28, -41, -58, + -61, -32, 11, 10, -31, -24, 17, 23, -4, -39, 5, 52, -2, -42, -42, -32, + -25, -17, -10, -4, 0, 3, 6, 22, 47, 35, -38, -82, -55, -23, -13, -12, + -8, -1, 7, 15, 21, 26, 23, -1, -53, -48, 20, 5, -39, -39, -6, 22, + -5, -22, 14, 43, 38, 25, 21, 27, 29, 19, 15, 47, 86, 68, 12, -7, + 7, 11, 4, 10, 7, -18, -50, -25, 33, 51, 24, -10, -20, -52, -72, 58, + 103, 21, -1, -26, -41, -17, 44, 67, 35, 16, 27, 36, 26, 18, 25, 8, + -45, -76, -55, -13, 7, -3, -16, -26, -38, -55, -61, -38, 4, 13, -26, -30, + 11, 25, 4, -36, -10, 51, 14, -37, -42, -33, -24, -17, -10, -4, 1, 3, + 6, 18, 42, 42, -22, -80, -63, -28, -14, -12, -9, -3, 5, 12, 19, 24, + 23, 3, -46, -58, 9, 14, -34, -41, -14, 21, 6, -21, 4, 36, 38, 26, + 21, 26, 30, 22, 13, 37, 78, 73, 20, -7, 4, 11, 6, 10, 10, -11, + -45, -33, 22, 49, 29, -4, -18, -40, -75, 23, 108, 40, 1, -18, -39, -26, + 28, 65, 42, 17, 22, 34, 29, 18, 23, 15, -30, -71, -65, -27, 3, 2, + -11, -22, -34, -49, -58, -45, -7, 13, -16, -35, -1, 24, 13, -23, -26, 37, + 36, -20, -39, -34, -24, -17, -10, -4, 1, 3, 5, 12, 33, 46, 6, -64, + -75, -40, -17, -12, -10, -5, 2, 9, 15, 20, 22, 10, -30, -65, -18, 20, + -19, -42, -27, 11, 21, -8, -8, 22, 34, 27, 22, 26, 31, 27, 14, 22, + 60, 75, 34, -4, -2, 8, 8, 11, 14, -2, -36, -42, 6, 44, 36, 4, + -15, -26, -66, -24, 95, 71, 8, -10, -33, -32, 7, 56, 51, 21, 17, 29, + 32, 20, 19, 20, -12, -59, -72, -45, -8, 5, -5, -17, -28, -42, -54, -50, + -21, 9, -5, -36, -16, 19, 21, -7, -34, 12, 51, 4, -33, -34, -25, -17, + -10, -4, 1, 4, 5, 9, 23, 44, 29, -39, -79, -55, -24, -13, -10, -7, + -1, 6, 12, 16, 20, 14, -15, -62, -46, 16, -2, -39, -36, -2, 29, 9, + -12, 8, 28, 27, 23, 25, 31, 31, 17, 13, 43, 72, 46, 2, -5, 5, + 8, 11, 16, 5, -26, -44, -8, 36, 40, 12, -12, -19, -52, -53, 67, 94, + 20, -5, -27, -35, -7, 45, 55, 27, 15, 25, 32, 23, 17, 21, 0, -47, + -73, -57, -19, 4, 0, -13, -24, -37, -50, -51, -29, 3, 1, -32, -26, 12, + 23, 3, -32, -6, 52, 22, -26, -34, -25, -17, -10, -4, 1, 5, 6, 8, + 18, 39, 38, -21, -76, -64, -30, -14, -10, -8, -2, 4, 10, 15, 18, 14, + -9, -56, -57, 7, 7, -35, -39, -10, 27, 18, -10, 2, 23, 26, 23, 24, + 31, 32, 20, 11, 35, 67, 51, 7, -6, 3, 8, 11, 17, 8, -20, -44, + -15, 31, 41, 16, -9, -17, -43, -61, 44, 102, 31, -2, -23, -35, -15, 36, + 56, 32, 0, -27, 1, -1, -1, 3, -4, -2, 1, -1, -2, 2, 3, -6, + 1, 2, -6, 2, 2, -4, -1, 2, -5, 1, 4, -4, 0, -1, 0, -1, + -2, 2, 2, -6, 0, 4, -3, -3, 4, -2, -3, -2, 0, 1, 1, -2, + -2, 3, -8, 27, -42, 11, 21, -35, 34, -25, 12, 9, -24, 14, 13, -38, + 53, -42, -3, 46, -73, 55, -16, -9, 28, -49, 38, -12, -21, 49, -51, 20, + 32, -73, 64, -28, -7, 32, -50, 42, -11, -30, 49, -21, -31, 46, -25, -7, + 20, -22, 18, -16, -10, 21, -23, 5, 28, -35, 8, 0, 8, -26, 19, 6, + -11, -20, 64, -46, -18, 51, -73, 119, -117, 46, 36, -80, 67, -46, 22, 0, + -24, 56, -59, 14, 26, -40, 24, -9, 20, -20, -15, 43, -26, -11, 9, 14, + -3, -31, 6, 54, -62, 3, 67, -78, 20, 21, -25, 31, -41, 18, 27, -53, + 32, 15, -48, 37, -11, 4, -12, -3, 31, -24, -21, 42, -10, -45, 55, -32, + 34, -43, -14, 86, -78, 8, 39, -35, -2, 13, 2, 5, -11, -4, 7, 5, + -31, 37, -4, -28, 28, -9, -11, 10, -1, 4, -18, 17, -9, -13, 24, -18, + 20, -18, -30, 59, -25, -29, 48, -15, -29, 23, 4, -3, -18, 14, 6, -8, + -19, 19, 8, -13, 0, 13, -18, 4, 1, 0, 0, 10, -14, -12, 39, -46, + 23, 9, -22, 23, -20, -22, 63, -42, -28, 77, -66, 12, 38, -56, 31, 27, + -77, 66, -11, -39, 59, -33, -41, 92, -54, -50, 96, -36, -46, 46, -17, 31, + -43, -28, 98, -57, -50, 84, -22, -44, 39, -8, 17, -28, -13, 63, -67, 16, + 10, 3, -15, -4, 36, -34, -1, 26, -27, -2, 13, 7, -22, 0, 27, -11, + -19, 6, 26, -42, 14, 18, -7, -14, -10, 37, -14, -24, 25, -4, -5, -10, + 3, 35, -39, -7, 31, -8, -23, 15, 4, -1, -25, 28, 7, -35, 34, -16, + -1, 9, -35, 45, -22, -17, 48, -52, 24, 22, -65, 48, 7, -45, 47, -19, + -33, 71, -70, 46, -7, -52, 68, -25, -35, 48, -13, -17, 14, 2, -12, 8, + -10, 1, 22, -32, 4, 34, -26, -18, 29, -7, -19, 15, -7, 15, -8, -29, + 50, -22, -35, 53, -19, -37, 47, -9, -40, 41, 1, -27, 7, 3, 0, 0, + -7, 13, -7, -21, 26, 14, -44, 11, 40, -51, 10, 26, -28, 16, -13, -3, + 31, -42, 11, 34, -52, 11, 34, -43, 10, 29, -19, -21, 27, -10, -5, 10, + -14, 11, 3, -35, 43, 3, -52, 37, 22, -66, 49, -12, -19, 50, -58, 16, + 42, -70, 50, -2, -42, 60, -69, 43, 11, -57, 54, -8, -31, 23, -8, -7, + 24, -32, 11, 21, -51, 60, -44, -6, 68, -87, 33, 45, -79, 50, -7, -13, + 21, -40, 31, 12, -41, 18, 24, -39, 15, 7, -17, 25, -20, -12, 43, -47, + 17, 6, -16, 10, 4, -11, -1, 14, -10, -7, 6, 9, -23, 9, 3, 13, + -30, 16, 16, -33, 17, 4, -17, 23, -29, 3, 54, -86, 50, 11, -41, 30, + -23, 15, 18, -60, 56, 7, -65, 49, -4, -12, 1, -6, 19, -4, -33, 35, + -10, -12, 13, -2, -2, -2, 2, -10, 16, -8, -11, 19, -6, -19, 24, -14, + 9, 3, -24, 24, -6, -13, 19, -11, -6, 6, -9, 16, -8, -10, 14, -10, + -1, -5, 16, -8, -25, 37, -11, -27, 37, -14, -13, 19, -17, 14, -5, -15, + 26, -27, 10, 11, -23, 22, -5, -19, 25, -7, -28, 44, -35, 0, 25, -31, + 31, -10, -26, 46, -41, 2, 33, -40, 24, 8, -43, 44, -12, -25, 37, -25, + -6, 29, -27, 5, 24, -40, 24, -1, -25, 23, -1, -6, -2, -1, 14, -24, + 8, 13, -11, 0, -13, 16, 15, -56, 43, 12, -35, 14, -9, 18, -10, -19, + 28, -3, -27, 23, -2, -14, 27, -35, 10, 35, -68, 44, 7, -43, 46, -21, + -25, 56, -35, -21, 51, -33, -8, 28, -27, 19, -2, -26, 36, -26, 3, 13, + -12, 6, -10, 8, -14, 15, -12, 0, 13, -9, -16, 32, -27, 3, 23, -49, + 49, -17, -31, 63, -64, 25, 36, -76, 61, -11, -47, 75, -54, -9, 69, -81, + 32, 29, -63, 46, -7, -26, 39, -31, 6, 18, -26, 13, -5, 5, -5, -2, + 5, -12, 17, -17, -2, 22, -25, 1, 20, -19, 3, 6, -6, 3, -9, 10, + -6, -3, 7, -7, -3, 12, -5, -5, -11, 24, -7, -23, 24, 0, -14, 0, + 12, -10, -2, 5, 0, 1, -10, 10, -2, -17, 26, -11, -16, 28, -22, 6, + 4, -17, 30, -27, -7, 46, -54, 15, 29, -42, 25, -4, -15, 26, -29, 11, + 15, -28, 19, -7, 1, 8, -20, 14, 1, -15, 11, -2, -2, 0, -10, 15, + -5, -12, 15, -1, -15, 12, 4, -15, 9, -1, -9, 9, -5, -6, 13, -12, + 1, 6, -6, -3, 6, -4, 0, -6, 11, -9, -2, 13, -12, -2, -1, 8, + -11, 4, 2, -6, 4, -4, 4, 0, -13, 15, 0, -21, 23, -5, -15, 15, + -2, -9, 6, -2, -4, 2, 3, -1, -7, 7, -2, -9, 6, 2, -9, 4, + 5, -12, 10, -9, 4, 5, -16, 12, -2, -13, 20, -13, -4, 17, -23, 14, + 2, -20, 22, -13, -3, 15, -22, 12, 4, -18, 17, -7, -7, 13, -14, 6, + 4, -10, 9, -5, -6, 7, 0, -7, 8, -4, -1, 0, -6, 4, 7, -14, + 2, 13, -16, 3, 10, -15, 7, -1, -10, 14, -10, -2, 11, -9, -4, 7, + -6, 3, -3, -5, 9, -6, -3, 5, 1, -7, 3, -2, 0, -2, 0, 4, + -3, -2, 4, -6, 4, -2, -2, 0, 1, 0, -7, 7, -2, -7, 9, -7, + -4, 11, -15, 11, -2, -9, 9, -4, -3, 2, 3, -7, 5, 0, -5, 6, + -7, 1, 7, -10, -2, 13, -9, -4, 8, -4, -2, -1, 1, 1, -7, 4, + 5, -8, 0, 6, -6, 0, 3, -4, 0, 1, -2, 2, -4, -4, 8, -7, + -1, 6, -9, 8, -3, -6, 12, -12, 1, 10, -11, 1, 5, -6, 3, -2, + -3, 7, -10, 2, 7, -12, 5, 2, -5, 3, -5, 0, 6, -10, 3, 4, + -8, 2, 2, -3, 3, -8, 8, 2, -14, 10, 3, -12, 8, 2, -11, 8, + -2, -6, 9, -7, -4, 10, -9, -1, 7, -7, 1, 3, -8, 8, -2, -8, + 10, -3, -5, 5, -6, 3, 1, -8, 10, -5, -5, 7, -4, -2, 2, -3, + 1, -1, -3, 4, -3, 0, 0, 0, 0, -4, 3, -2, -3, 3, -5, 3, + 0, -7, 5, 1, -8, 5, 1, -6, 6, -5, 0, 3, -7, 3, 2, -6, + 3, 2, -6, 3, 1, -3, -2, 5, -4, -1, 3, -4, 0, 0, -3, 5, + -5, -3, 7, -5, -3, 6, -4, 0, -1, -3, 3, -2, -1, 2, -1, -2, + 1, -2, 1, -1, -7, 8, -1, 5, -7, 13, -22, 8, -7, 8, -110, -28, + 24, 54, 36, 2, 60, -45, 57, 42, -43, 20, 41, -66, 24, -11, 18, -18, + -38, -63, -36, 30, -11, 33, 25, 30, 18, 11, -18, -5, 5, -46, 40, 1, + -13, -18, -20, -31, 20, 10, 29, -7, -18, 40, -29, -17, 42, -19, 6, -4, + 6, -8, 10, -26, -5, 3, 1, -17, 6, 0, 19, -1, 8, 0, -6, -10, + -1, -12, -1, 1, -3, 8, -7, 4, 11, 4, 14, -13, 16, -19, -4, -13, + -13, -14, 6, 4, -1, 4, 11, -1, 11, -1, 1, -4, -1, -15, 6, -9, + 1, -1, 0, 3, 1, -8, 3, -1, -1, 2, -2, 2, -2, 1, -5, -7, + 3, -3, 6, -3, 4, -1, 0, -4, 2, -7, 3, -6, -1, -1, 4, 0, + 3, -2, 2, -5, 5, -8, -3, -3, 2, -5, 7, -1, 4, -2, 4, -10, + 6, -6, -1, -4, 5, -13, 7, -6, 5, -8, 17, -20, 14, -6, 9, -40, + 71, -127, 9, -73, 127, 76, -28, 74, -32, 8, -62, -49, -38, 40, -68, 22, + -12, 68, 10, 39, -10, 0, 35, -23, 0, -59, -15, -7, -3, -23, 1, -20, + 37, 27, 2, 30, -2, 17, 2, -5, -7, -27, -29, 16, -3, -11, 1, -16, + -5, -8, -10, 7, 32, 9, 5, -4, 16, 5, -8, -17, -16, 5, -13, 8, + 11, 15, -10, -9, 0, -1, 2, 7, -3, -23, 9, 2, 3, 1, -13, -1, + -6, 11, -6, 8, 1, 12, -12, 9, -14, 8, -1, 0, -3, -13, 4, -7, + -4, 8, 5, -5, -7, 4, -2, -3, 2, 3, -6, 8, -3, 1, -3, -2, + 2, -6, 2, -4, -3, -4, 3, 1, 0, 0, 1, -1, -1, 2, -2, 0, + -4, -2, 1, 2, 0, -3, 1, -3, 0, -1, -3, -6, 2, -2, 3, -4, + 10, -8, 9, -5, 12, -19, 46, 37, -128, 60, -90, 102, -65, 40, -57, 39, + -6, 23, -8, 19, 24, 15, -17, -47, -27, -36, -16, 21, 3, 23, 14, 50, + -8, 19, 25, 7, -9, -28, -63, -37, 0, -42, 54, -17, 68, -3, 30, -12, + -4, 11, -15, 9, -25, -15, -2, -27, -25, 38, -8, -13, 33, 24, 12, -38, + 39, -12, -3, -17, -44, 38, 2, 27, 3, -5, -4, -13, -30, -56, -4, 11, + 1, 9, 17, 46, 25, -14, 6, -3, -7, -21, 2, 16, -5, -22, 2, -2, + 6, -12, -25, -15, 10, 9, 8, 11, 43, 8, -5, -22, -16, 14, -31, 16, + 7, -7, -26, -20, -2, 9, 11, 26, 7, 6, -20, -13, 0, 4, 17, -17, + -18, 10, 2, -10, 27, -8, 24, -23, -14, 1, 0, 13, -19, 14, 10, -16, + 16, -4, -20, 20, -33, 2, 2, 24, 21, -3, -26, -24, -18, -18, 10, 10, + 24, 18, 2, 9, -24, 16, -14, -8, 9, -5, -14, 8, -5, 30, -11, 11, + -13, -15, -12, 7, 4, -13, -13, 13, -13, 12, 23, 9, 0, 14, -10, -9, + -35, -2, -21, 12, -1, 17, 19, 11, -4, 0, -18, -24, 11, -10, 1, 11, + 12, -13, -16, 10, -23, 21, 9, -9, 3, 12, -6, 3, -5, 12, 0, -2, + 0, -19, -9, 5, -11, -7, 10, 1, -3, 9, 18, -6, 0, -1, 1, -13, + 2, 1, -3, -8, 17, -4, -9, 18, -15, 8, -1, -11, -5, -14, 11, -5, + -7, 12, 16, -7, 7, -3, -11, -5, -6, 1, 4, -3, -3, 15, 5, 0, + 3, 6, -16, 4, -14, -6, -9, -4, 2, 11, 11, 7, -2, 4, -12, -7, + -14, -6, -7, 9, 4, 7, -2, 6, 5, 6, -4, -3, -4, 7, -7, -11, + -9, 0, -3, 7, -2, -2, 3, 13, -4, -6, -15, 9, -7, -1, 4, 6, + 5, 8, -6, -8, 0, -11, -4, 6, -8, 4, 3, 5, 13, -4, -9, -3, + 4, -3, -3, 4, -1, -12, 6, -14, 2, 3, 15, 2, 6, -7, -8, 3, + 1, -2, 3, -3, -12, -6, -14, 7, -2, 13, 6, 10, 6, 0, -2, -10, + -12, -8, -6, -7, -6, 6, 4, -2, 5, 2, 0, -1, 3, -11, 4, 0, + 20, -8, -2, 0, -1, -3, 7, -3, -4, -2, -6, -10, -10, -8, 1, 2, + 5, 8, 2, 5, 8, 3, 4, 3, -2, -15, 0, -1, -7, -2, -5, -10, + 10, -1, 5, 3, 5, -1, -2, -8, -5, -9, 1, -8, 6, 5, 4, 1, + 1, 2, 3, -2, 4, -7, 1, -7, -9, -2, 0, 2, 3, 6, -8, 8, + 3, 0, -2, -9, -3, -2, 0, 3, -1, -2, -3, 7, -3, 10, -8, 1, + -12, 3, -7, 2, -3, 7, 4, 4, 0, 0, -6, -1, -5, -3, -4, -7, + 0, 5, 7, 0, 2, -3, 10, -1, 3, -7, -5, -4, -9, -3, -7, 5, + -4, 9, 2, 1, 4, 5, 0, -5, 1, -8, 4, -9, 5, -5, 0, 3, + -2, -1, 1, 1, -7, 7, 0, 3, -5, 0, -3, -1, -1, -5, -1, 1, + -1, 1, -1, 0, 2, 0, 2, -7, -7, 4, -1, 0, 3, 4, -1, -3, + -4, -6, 3, -2, 4, -1, 5, -2, -1, -5, -2, -4, 1, 3, 2, 2, + 0, -3, 1, 1, -3, -3, -1, 1, -3, -2, -1, -2, -3, -1, 0, 4, + 3, 5, 2, 1, -4, -9, -3, -7, 1, -2, 7, -2, 3, 3, 3, 1, + 0, -1, -6, -7, -6, -4, -1, 1, 0, 5, 2, -2, 2, -3, -1, 3, + -1, 1, -4, -4, -5, 0, -7, 2, -4, 3, 4, 1, 2, -1, -1, -2, + -2, 0, -1, 1, -1, -1, -3, 1, 1, 3, -3, -1, 1, 1, -2, -3, + -8, -5, 0, -1, 5, 2, 3, 1, -2, -1, -1, -3, 1, 1, -2, -3, + -3, -1, 0, -1, 1, 2, 2, 5, 0, -1, -2, -1, -2, 0, -4, 0, + -5, -1, -1, 0, 1, 5, 4, -2, -1, -2, 0, -6, -1, 0, 1, -1, + -2, 1, 0, 0, 3, 1, -2, 1, -2, -4, -1, 0, -1, -1, -4, -2, + -4, 2, -1, 1, 0, 3, 2, 0, 4, -1, 4, -6, 2, -4, -3, -5, + -4, -3, 0, 2, 0, 1, 4, 2, 2, -2, -2, -5, -6, -5, -3, -2, + 1, -1, 0, 0, 2, 2, 2, 0, 4, -2, 3, 2, -1, -2, -3, -3, + -3, -5, -5, -5, -1, -1, 0, 2, 2, 4, 1, 2, 1, 2, -1, -1, + -3, -4, -5, -3, -2, -2, -1, 1, 4, 2, 2, 2, 1, -1, -2, -6, + -2, -3, 2, -1, 1, -2, 0, 2, 1, 2, -2, 1, 0, -2, -2, -3, + 0, -2, -1, -1, 0, -2, -2, 1, 0, 2, -1, 1, -1, 0, -1, -1, + 0, -1, 0, -2, 2, 0, 2, 2, 5, 3, 6, 8, 12, 13, -6, -110, + -7, 51, -99, -128, 10, -28, -39, 25, -33, -27, 41, 34, -5, 17, 23, 25, + 24, 23, 20, 24, 25, 24, 21, 20, 23, 23, 16, 20, 9, 20, 18, 10, + 14, 5, 14, 11, 7, 5, 3, 10, 2, 7, -4, 0, 3, 0, -3, -5, + -6, -1, -12, -4, -17, -10, 9, -42, -40, 65, 40, -58, 29, 72, 39, 50, + 31, -1, 30, 25, -7, -4, -33, -47, -29, -49, -74, -69, -71, -79, -61, -51, + -57, -53, -34, -20, -22, -16, -10, -6, -2, 1, 3, 4, 8, 8, 12, 10, + 9, 14, 13, 12, 12, 13, 12, 12, 14, 12, 12, 12, 12, 13, 12, 9, + 11, 11, 11, 7, 8, 7, 8, 9, 2, 5, 8, -6, 2, 17, -17, -20, + 18, 5, -15, 15, 27, 21, 37, 44, 41, 46, 38, 26, 32, 26, -4, -15, + -6, -20, -44, -50, -54, -60, -59, -58, -58, -54, -46, -38, -32, -26, -19, -14, + -9, -5, -1, 2, 5, 7, 8, 10, 11, 12, 13, 13, 14, 14, 14, 13, + 13, 14, 15, 14, 11, 13, 14, 13, 12, 10, 12, 12, 10, 10, 8, 6, + 11, 9, -1, 5, 11, -1, -6, 1, -1, -4, 0, -1, 0, 14, 25, 24, + 28, 37, 38, 38, 38, 31, 22, 14, 4, -5, -15, -26, -38, -47, -52, -54, + -56, -57, -55, -51, -45, -39, -34, -28, -22, -17, -13, -8, -3, -1, 2, 5, + 7, 8, 10, 11, 12, 13, 13, 13, 13, 14, 14, 13, 13, 14, 13, 12, + 13, 13, 12, 11, 12, 11, 9, 11, 9, 6, 7, 8, 5, 3, 2, 0, + 0, 0, -2, -3, 0, 3, 6, 11, 18, 23, 27, 31, 34, 35, 32, 27, + 21, 14, 5, -5, -15, -26, -35, -43, -48, -52, -53, -53, -52, -49, -44, -40, + -35, -29, -24, -19, -14, -10, -6, -3, 1, 3, 5, 7, 9, 10, 11, 12, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 12, 13, 12, 11, 13, 11, 10, + 10, 9, 9, 8, 7, 7, 5, 4, 3, 2, 0, -1, -1, 0, 2, 4, + 8, 12, 17, 22, 25, 28, 30, 30, 28, 24, 19, 12, 3, -5, -14, -23, + -31, -37, -43, -46, -46, -48, -47, -43, -41, -38, -33, -29, -25, -21, -16, -12, + -8, -5, -2, 0, 3, 5, 7, 9, 10, 11, 12, 12, 13, 14, 13, 13, + 13, 13, 13, 12, 12, 12, 11, 11, 11, 10, 9, 9, 8, 7, 7, 6, + 5, 4, 4, 3, 3, 3, 3, 5, 6, 8, 10, 12, 14, 17, 18, 19, + 20, 19, 17, 14, 10, 5, 0, -6, -11, -17, -22, -26, -29, -32, -34, -34, + -35, -34, -32, -31, -28, -26, -23, -20, -17, -14, -11, -8, -5, -3, 0, 2, + 4, 6, 7, 8, 9, 10, 11, 11, 12, 12, 12, 12, 11, 11, 11, 10, + 10, 9, 9, 8, 8, 7, 7, 6, 5, 5, 5, 4, 4, 5, 5, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 13, 13, 13, 12, 10, 8, 5, 2, + -2, -6, -10, -14, -18, -21, -24, -26, -28, -29, -29, -30, -29, -28, -27, -25, + -23, -20, -18, -15, -12, -10, -7, -4, -2, 0, 2, 4, 6, 7, 9, 10, + 10, 11, 11, 12, 12, 12, 12, 11, 11, 11, 10, 10, 9, 9, 8, 8, + 7, 7, 6, 6, 5, 5, 5, 5, 6, 6, 7, 7, 8, 9, 10, 11, + 12, 13, 13, 13, 12, 11, 10, 8, 5, 2, -1, -5, -9, -13, -16, -19, + -22, -24, -26, -27, -28, -28, -28, -27, -26, -24, -22, -20, -18, -15, -13, -10, + -7, -5, -2, 0, 2, 4, 5, 7, 8, 9, 10, 11, 11, 11, 11, 11, + 11, 11, 11, 10, 10, 9, 9, 8, 8, 7, 7, 6, 6, 6, 5, 5, + 5, 5, 6, 6, 6, 7, 8, 9, 10, 11, 11, 12, 12, 12, 11, 10, + 9, 7, 5, 2, -1, -5, -8, -12, -15, -18, -21, -23, -25, -26, -27, -27, + -27, -26, -25, -24, -22, -20, -18, -16, -13, -11, -8, -6, -3, -1, 1, 3, + 4, 6, 7, 8, 9, 10, 10, 10, 11, 11, 11, 10, 10, 10, 10, 9, + 9, 8, 8, 7, 7, 6, 6, 6, 5, 5, 5, 5, 6, 6, 6, 7, + 8, 9, 9, 10, 11, 11, 11, 11, 11, 10, 9, 7, 4, 2, -1, -4, + -7, -11, -14, -17, -19, -21, -23, -24, -25, -26, -26, -25, -24, -23, -22, -20, + -18, -16, -13, -11, -9, -6, -4, -2, 0, 2, 4, 5, 7, 8, 9, 9, + 10, 10, 11, 11, 11, 11, 10, 10, 10, 9, 9, 8, 8, 7, 7, 7, + 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 8, 9, 9, 10, 11, 11, + 11, 11, 10, 10, 8, 7, 5, 2, -1, -3, -7, -10, -13, -15, -18, -20, + -22, -23, -24, -25, -25, -24, -24, -23, -21, -20, -18, -16, -14, -11, -9, -7, + -5, -2, 0, 1, 3, 5, 6, 7, 8, 9, 9, 10, 10, 10, 10, 10, + 10, 10, 9, 9, 8, 8, 8, 7, 7, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 7, 7, 8, 8, 9, 9, 9, 10, 9, 9, 8, 7, 6, 4, + 2, 0, -2, -5, -7, -10, -12, -15, -17, -18, -20, -21, -21, -22, -22, -21, + -21, -20, -18, -17, -15, -13, -12, -10, -8, -6, -4, -2, 0, 1, 3, 4, + 5, 6, 7, 8, 8, 8, 9, 9, 9, 9, 9, 8, 8, 8, 8, 7, + 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, + 8, 8, 8, 8, 7, 6, 5, 4, 3, 1, -1, -3, -5, -7, -9, -10, + -12, -14, -15, -16, -17, -18, -18, -18, -18, -17, -17, -16, -15, -13, -12, -11, + -9, -7, -6, -4, -3, -1, 0, 1, 3, 4, 5, 5, 6, 7, 7, 7, + 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 5, + 4, 3, 2, 0, -1, -3, -5, -7, -9, -10, -12, -13, -15, -16, -17, -17, + -18, -18, -18, -17, -17, -16, -15, -14, -12, -11, -9, -8, -6, -5, -3, -2, + -1, 1, 2, 3, 4, 5, 5, 6, 6, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 6, 6, 5, 4, 3, 2, 0, -1, -3, + 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 3, 4, 5, + 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 6, 7, 8, 9, 10, 10, + 11, 12, 12, 13, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23, 24, 26, + 27, 29, 29, 29, 28, 28, 28, 29, 30, 31, 31, 31, 31, 28, 19, -8, + -41, -53, -57, -59, -60, -62, -62, -63, -64, -65, -65, -66, -67, -69, -69, -69, + -72, -74, -73, -74, -76, -78, -79, -81, -82, -82, -83, -81, -83, -85, -81, -81, + -88, -90, -80, -64, -47, -32, -23, -18, -15, -13, -12, -12, -12, -13, -13, -13, + -13, -13, -12, -12, -11, -9, -7, -6, -4, -2, -1, 0, 1, 2, 4, 5, + 7, 10, 12, 14, 16, 18, 19, 18, 19, 21, 19, 20, 22, 22, 22, 25, + 27, 28, 29, 29, 29, 29, 29, 30, 31, 31, 31, 33, 34, 34, 35, 34, + 33, 31, 30, 29, 26, 25, 26, 25, 22, 22, 21, 20, 20, 19, 19, 19, + 18, 18, 18, 17, 17, 17, 17, 16, 16, 16, 15, 13, 13, 14, 14, 15, + 13, 12, 13, 13, 11, 12, 14, 14, 16, 17, 15, 16, 19, 19, 19, 19, + 21, 19, 17, 18, 19, 18, 15, 15, 17, 18, 18, 13, 11, 14, 15, 14, + 11, 6, 5, 10, 13, 17, 18, 11, 2, -2, -2, -3, 2, 14, 24, 30, + 37, 47, 52, 52, 56, 63, 65, 65, 63, 65, 72, 75, 73, 71, 73, 77, + 82, 82, 77, 77, 82, 90, 99, 104, 99, 89, 84, 86, 94, 106, 119, 127, + 126, 117, 104, 87, 64, 42, 24, 10, -2, -15, -22, -25, -27, -30, -35, -37, + -36, -34, -33, -36, -40, -42, -44, -43, -44, -48, -53, -57, -59, -57, -53, -52, + -53, -57, -62, -68, -73, -75, -75, -71, -63, -56, -48, -40, -34, -29, -26, -23, + -22, -21, -19, -19, -20, -21, -22, -22, -22, -22, -22, -21, -21, -21, -20, -19, + -19, -18, -18, -17, -17, -16, -14, -14, -13, -11, -9, -9, -9, -9, -9, -8, + -8, -8, -8, -8, -7, -6, -7, -6, -4, -3, -2, -2, -3, -4, -3, -3, + -2, -1, 0, 0, -1, -1, 0, -1, -1, -1, -3, -5, -5, -8, -10, -10, + -9, -9, -10, -11, -11, -11, -11, -11, -10, -9, -10, -10, -10, -11, -12, -12, + -13, -12, -11, -12, -14, -14, -11, -10, -12, -11, -11, -12, -12, -11, -11, -13, + -12, -9, -6, -6, -7, -7, -6, -5, -4, -4, -5, -8, -12, -11, -8, -4, + -3, -5, -6, -7, -9, -12, -13, -8, -3, -2, -4, -8, -11, -14, -15, -17, + -19, -19, -15, -8, -1, 2, 4, 8, 12, 17, 23, 26, 25, 24, 25, 30, + 36, 40, 39, 36, 33, 32, 33, 37, 43, 49, 53, 53, 49, 45, 43, 43, + 46, 52, 60, 67, 76, 82, 82, 78, 69, 58, 47, 37, 26, 14, 2, -9, + -16, -21, -24, -28, -32, -35, -37, -38, -37, -36, -36, -36, -39, -43, -46, -49, + -51, -49, -47, -46, -45, -45, -48, -52, -58, -62, -65, -66, -65, -62, -58, -54, + -50, -45, -39, -34, -30, -28, -25, -23, -21, -20, -20, -20, -20, -19, -18, -19, + -20, -18, -17, -18, -17, -17, -18, -17, -16, -15, -15, -13, -12, -10, -10, -10, + -9, -8, -7, -6, -4, -4, -5, -6, -5, -4, -4, -3, -2, -2, -1, -1, + -1, 0, 2, 3, 2, 2, 3, 2, 1, 2, 4, 5, 5, 4, 4, 4, + 3, 2, 2, 1, 0, 0, -1, -4, -5, -4, -2, -2, -3, -3, -3, -2, + -1, -2, -3, -2, -3, -4, -4, -3, -4, -6, -7, -4, 0, 0, -2, -4, + -4, -3, -2, -2, -3, -4, -4, -3, -2, -1, 3, 6, 8, 6, 3, 0, + 0, 2, 4, 5, 4, 3, 2, 2, 2, 1, 0, -1, 2, 7, 11, 9, + 6, 2, -1, -3, -3, -5, -7, -8, -6, -3, 2, 8, 13, 17, 18, 18, + 19, 23, 28, 34, 40, 42, 42, 40, 39, 39, 40, 42, 46, 50, 55, 59, + 59, 55, 51, 48, 48, 51, 57, 63, 70, 76, 82, 86, 88, 89, 86, 80, + 71, 61, 51, 43, 34, 25, 18, 10, 2, -5, -9, -12, -13, -12, -12, -13, + -14, -17, -22, -26, -29, -28, -27, -25, -24, -24, -25, -27, -31, -35, -40, -43, + -46, -47, -49, -49, -46, -43, -40, -36, -32, -28, -24, -21, -18, -16, -14, -13, + -13, -12, -11, -11, -12, -11, -10, -9, -11, -11, -11, -12, -12, -12, -10, -10, + -10, -10, -9, -8, -7, -6, -5, -4, -4, -4, -4, -4, -3, -2, -2, -1, + -2, -3, -2, -1, 0, 0, 1, 2, 3, 2, 1, 1, 2, 3, 3, 4, + 5, 4, 4, 5, 6, 7, 6, 4, 3, 3, 3, 2, -1, -3, -3, -1, + -1, -2, -3, -3, -2, -1, 1, 0, -1, -1, -2, -5, -6, -5, -4, -4, + -4, -4, -6, -6, -4, -1, 0, -2, -6, -9, -10, -8, -5, -4, -3, -3, + -1, 1, 1, -1, -3, -4, -2, 0, 2, 2, 0, -3, -6, -7, -6, -4, + -3, -2, -1, -1, -1, 0, 1, 0, -3, -9, -14, -18, -18, -15, -12, -9, + -8, -7, -5, -3, -2, 0, 5, 11, 17, 22, 25, 24, 23, 21, 20, 22, + 27, 32, 37, 40, 41, 40, 39, 37, 35, 34, 34, 35, 39, 45, 52, 59, + 66, 71, 73, 75, 74, 71, 65, 60, 55, 48, 39, 28, 17, 7, -1, -7, + -11, -13, -13, -14, -17, -21, -24, -28, -31, -32, -32, -32, -32, -31, -29, -29, + -30, -33, -36, -40, -44, -47, -50, -52, -54, -55, -54, -52, -49, -47, -43, -39, + -35, -31, -28, -26, -24, -22, -21, -19, -18, -17, -17, -16, -15, -16, -18, -17, + -16, -16, -17, -18, -18, -17, -16, -16, -14, -13, -13, -12, -12, -12, -11, -10, + -10, -9, -7, -8, -9, -10, -10, -8, -6, -5, -6, -6, -5, -3, -3, -4, + -4, -4, -3, -2, -2, -1, -1, -1, 0, 2, 3, 3, 3, 2, 1, 0, + -1, -1, -1, -2, -3, -5, -5, -4, -2, -3, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 3, 2, 0, + -1, 1, 2, 1, -1, -1, 2, 2, 0, 1, 2, 2, -1, -4, -10, -21, + -30, -36, -41, -44, -40, -30, -18, -10, -8, -11, -13, -8, 3, 18, 32, 41, + 44, 45, 48, 49, 43, 32, 23, 14, 7, 8, 16, 27, 35, 37, 30, 18, + 9, 5, 3, 2, 1, 1, -1, -6, -11, -12, -6, -2, -5, -11, -18, -28, + -39, -47, -55, -69, -86, -99, -102, -92, -70, -46, -28, -15, -3, 7, 17, 26, + 28, 24, 23, 30, 42, 53, 57, 50, 36, 21, 5, -5, -4, 6, 20, 31, + 35, 34, 29, 26, 27, 37, 56, 76, 85, 80, 71, 63, 55, 47, 34, 13, + -13, -32, -39, -40, -46, -65, -93, -117, -128, -128, -126, -120, -110, -96, -78, -58, + -36, -14, 3, 10, 20, 41, 60, 68, 63, 54, 45, 39, 36, 32, 28, 29, + 35, 41, 47, 46, 41, 39, 43, 53, 68, 80, 78, 64, 46, 28, 13, 3, + -9, -35, -64, -80, -82, -74, -66, -71, -91, -111, -121, -118, -105, -86, -68, -57, + -49, -37, -22, -7, 5, 14, 26, 42, 55, 56, 46, 35, 25, 14, 6, 2, + 1, 3, 11, 22, 32, 40, 43, 42, 46, 60, 77, 88, 90, 78, 54, 30, + 14, 2, -15, -37, -62, -82, -90, -89, -86, -90, -99, -107, -109, -101, -81, -54, + -29, -14, -5, 7, 24, 40, 49, 56, 68, 83, 92, 92, 87, 74, 54, 32, + 12, -5, -19, -25, -24, -18, -7, 1, -1, -6, -4, 13, 41, 69, 84, 80, + 63, 44, 32, 29, 25, 11, -10, -25, -31, -35, -40, -48, -65, -87, -104, -109, + -102, -87, -69, -58, -54, -42, -21, 0, 13, 29, 51, 71, 84, 89, 86, 75, + 54, 33, 14, -3, -19, -29, -27, -22, -18, -11, -8, -16, -26, -19, 2, 24, + 40, 48, 42, 27, 21, 29, 34, 24, 7, -5, -14, -23, -28, -32, -45, -67, + -82, -85, -78, -63, -46, -34, -29, -24, -13, 0, 12, 25, 44, 65, 79, 85, + 86, 78, 60, 41, 27, 12, -5, -15, -15, -14, -13, -8, -7, -17, -27, -23, + -3, 23, 44, 51, 43, 25, 12, 11, 14, 8, -3, -10, -15, -22, -28, -30, + -36, -55, -73, -78, -74, -71, -63, -51, -43, -39, -34, -25, -18, -9, 8, 28, + 46, 56, 61, 62, 58, 47, 36, 28, 20, 12, 11, 16, 19, 20, 21, 15, + 0, -6, 10, 37, 57, 63, 55, 36, 15, 2, -3, -9, -19, -27, -34, -43, + -49, -49, -52, -66, -82, -86, -81, -77, -71, -61, -51, -47, -43, -35, -22, -12, + 2, 24, 47, 58, 63, 67, 66, 58, 51, 45, 34, 18, 9, 7, 7, 7, + 8, 1, -14, -24, -12, 18, 47, 64, 68, 63, 53, 42, 37, 38, 36, 29, + 21, 16, 11, 5, -2, -17, -36, -49, -52, -56, -62, -63, -61, -61, -63, -60, + -56, -49, -37, -19, 2, 17, 25, 30, 34, 37, 37, 37, 34, 25, 15, 11, + 13, 14, 14, 8, -7, -21, -16, 9, 37, 53, 60, 61, 53, 40, 33, 34, + 32, 22, 14, 12, 10, 6, -2, -15, -32, -48, -57, -60, -63, -67, -66, -63, + -63, -65, -64, -58, -49, -34, -13, 6, 16, 21, 28, 34, 38, 41, 43, 36, + 25, 19, 21, 26, 27, 20, 4, -11, -11, 7, 31, 53, 66, 70, 66, 57, + 49, 47, 44, 33, 21, 17, 16, 10, 1, -9, -26, -46, -60, -67, -76, -84, + -84, -80, -78, -79, -78, -73, -65, -52, -32, -11, 4, 10, 17, 25, 32, 36, + 40, 37, 24, 13, 15, 23, 23, 11, -5, -19, -25, -16, 9, 38, 59, 70, + 72, 67, 63, 63, 60, 50, 39, 32, 28, 22, 14, 3, -14, -34, -53, -65, + -76, -87, -94, -93, -91, -94, -96, -93, -86, -76, -56, -30, -9, 4, 16, 29, + 40, 51, 63, 65, 52, 39, 39, 45, 42, 29, 11, -7, -22, -24, -8, 19, + 42, 54, 60, 63, 61, 58, 57, 53, 43, 36, 36, 34, 28, 21, 11, -5, + -24, -39, -52, -65, -75, -77, -75, -75, -78, -80, -78, -73, -61, -43, -23, -9, + 1, 10, 23, 39, 52, 56, 47, 36, 35, 41, 42, 33, 17, -2, -24, -35, + -26, -3, 18, 32, 42, 50, 52, 53, 52, 47, 38, 31, 30, 31, 29, 26, + 22, 14, -1, -18, -33, -46, -58, -65, -65, -65, -71, -79, -81, -79, -75, -62, + -42, -27, -21, -14, 1, 19, 34, 40, 36, 29, 27, 31, 38, 39, 29, 9, + -12, -27, -28, -14, 8, 25, 37, 50, 62, 67, 66, 62, 53, 42, 36, 37, + 36, 32, 30, 25, 12, -7, -24, -39, -54, -65, -67, -67, -72, -78, -81, -82, + -81, -70, -51, -35, -29, -23, -7, 15, 30, 37, 40, 35, 25, 25, 36, 41, + 33, 15, -6, -26, -36, -27, -9, 7, 20, 35, 50, 58, 59, 58, 52, 43, + 37, 37, 37, 36, 34, 31, 24, 8, -11, -29, -44, -57, -67, -70, -73, -79, + -86, -92, -93, -87, -72, -59, -53, -46, -29, -9, 7, 20, 28, 26, 19, 17, + 27, 38, 38, 26, 7, -12, -25, -26, -15, 1, 14, 28, 47, 61, 67, 68, + 68, 63, 54, 51, 53, 51, 49, 49, 47, 34, 14, -5, -22, -39, -56, -65, + -67, -73, -86, -96, -97, -92, -86, -77, -69, -61, -49, -28, -6, 10, 22, 27, + 25, 24, 33, 49, 56, 48, 32, 13, -5, -15, -12, -2, 7, 18, 35, 50, + 59, 63, 65, 61, 53, 48, 46, 44, 43, 46, 49, 43, 27, 10, -6, -25, + -45, -53, -53, -60, -75, -87, -90, -90, -88, -81, -75, -72, -65, -48, -25, -6, + 5, 10, 13, 18, 31, 49, 60, 58, 44, 28, 12, -1, -7, -7, -1, 8, + 23, 41, 54, 61, 65, 66, 63, 56, 48, 43, 41, 42, 44, 43, 37, 25, + 8, -12, -32, -44, -49, -53, -64, -80, -91, -95, -93, -89, -85, -82, -78, -68, + -50, -27, -6, 0, -1, 0, 0, 0, 1, 2, 3, 6, 9, 13, 17, 19, + 13, -4, -15, -10, 4, 19, 26, 15, -9, -16, 6, -2, -18, 38, 64, 21, + -48, 30, 82, -23, -63, -50, -26, -7, 12, 26, 47, 83, 100, 3, -108, -87, + -30, -6, 5, 18, 33, 46, 47, 21, -52, -46, 48, 3, -54, -32, 22, 25, + -7, 12, 9, -18, -33, -24, 2, 44, 88, 92, 10, -28, -1, 1, 20, 42, + 1, -17, 53, 72, 12, -16, -74, -31, 127, 52, 1, -35, -46, 13, 39, -13, + -13, 13, 12, 11, 8, -57, -80, -44, -5, 14, 18, 6, -13, -26, -11, -8, + -24, 3, 30, 14, -28, -12, 41, -2, -37, -35, -23, -12, -1, 6, 17, 34, + 53, 19, -55, -67, -32, -13, -5, 2, 12, 19, 24, 14, -24, -47, 12, 11, + -36, -35, -1, 18, -3, 0, 5, -13, -25, -22, -5, 19, 53, 69, 21, -28, + -10, -5, 6, 28, 8, -25, 23, 57, 17, -17, -49, -63, 84, 70, 3, -23, + -50, -6, 36, -2, -20, 8, 14, 9, 13, -37, -82, -58, -19, 8, 17, 10, + -9, -26, -19, -7, -24, -9, 25, 22, -17, -28, 33, 16, -32, -37, -27, -15, + -4, 4, 13, 27, 48, 35, -35, -72, -43, -17, -7, -1, 9, 16, 23, 17, + -12, -51, -7, 21, -27, -40, -12, 19, 6, -3, 5, -9, -22, -23, -8, 11, + 42, 68, 38, -23, -16, -6, 3, 25, 19, -24, 8, 54, 31, -13, -33, -76, + 46, 95, 13, -13, -48, -20, 32, 13, -22, 2, 15, 10, 15, -17, -77, -67, + -31, 3, 17, 15, -3, -21, -23, -7, -20, -18, 18, 27, -4, -34, 17, 33, + -21, -36, -29, -16, -6, 4, 11, 23, 42, 47, -12, -69, -54, -22, -8, -2, + 7, 15, 22, 20, -2, -46, -27, 23, -13, -41, -22, 15, 16, -2, 4, -5, + -18, -21, -10, 5, 32, 64, 53, -12, -21, -6, 0, 21, 27, -16, -6, 48, + 42, -6, -22, -71, 2, 106, 31, -6, -41, -32, 22, 25, -18, -4, 15, 12, + 14, -1, -64, -74, -42, -5, 16, 19, 4, -16, -25, -10, -14, -23, 9, 29, + 9, -31, -2, 42, -5, -33, -30, -18, -8, 3, 9, 19, 36, 51, 10, -58, + -63, -29, -11, -2, 4, 13, 20, 21, 6, -35, -44, 16, 1, -38, -30, 7, + 23, 3, 2, -2, -16, -20, -12, 2, 23, 56, 62, 3, -24, -7, -2, 17, + 30, -5, -17, 37, 49, 4, -17, -57, -37, 99, 55, 0, -31, -41, 9, 33, + -10, -11, 13, 14, 12, 9, -47, -78, -53, -15, 12, 20, 9, -10, -24, -14, + -11, -25, -2, 27, 18, -21, -20, 39, 13, -29, -31, -20, -9, 1, 8, 17, + 30, 49, 29, -41, -70, -39, -15, -4, 2, 11, 17, 21, 11, -22, -52, 0, + 14, -31, -36, -4, 25, 11, 1, -1, -13, -19, -13, 0, 15, 45, 65, 20, + -24, -10, -4, 12, 30, 8, -22, 24, 52, 17, -14, -39, -61, 71, 81, 8, + -21, -44, -5, 34, 2, -16, 9, 16, 11, 14, -29, -76, -62, -27, 6, 20, + 15, -4, -21, -19, -9, -23, -12, 22, 25, -8, -30, 26, 30, -20, -31, -23, + -11, -1, 8, 14, 25, 44, 42, -19, -69, -50, -20, -6, 1, 9, 15, 20, + 15, -11, -51, -19, 20, -20, -39, -15, 23, 20, 2, 0, -11, -17, -14, -2, + 9, 35, 63, 37, -19, -14, -5, 8, 28, 18, -22, 9, 50, 28, -11, -26, + -68, 32, 100, 22, -13, -43, -18, 30, 15, -17, 4, 16, 12, 15, -12, -69, + -69, -39, -2, 18, 19, 2, -17, -22, -10, -19, -20, 15, 27, 4, -31, 7, + 41, -7, -30, -25, -13, -3, 6, 12, 22, 38, 48, 3, -61, -60, -27, -9, + 0, 7, 13, 19, 17, -2, -44, -37, 18, -7, -39, -24, 15, 28, 7, 0, + -9, -16, -14, -3, 6, 25, 57, 49, -9, -18, -7, 3, 25, 26, -15, -4, + 45, 38, -5, -18, -61, -8, 103, 42, -6, -37, -30, 21, 25, -13, -3, 16, + 13, 14, 2, -56, -73, -49, -12, 15, 21, 8, -11, -23, -13, -15, -24, 4, + 28, 14, -25, -12, 42, 9, -26, -26, -15, -5, 5, 11, 19, 32, 48, 22, + -46, -67, -36, -12, -2, 4, 12, 17, 18, 4, -33, -50, 6, 6, -35, -31, + 4, 31, 14, 0, -8, -15, -14, -4, 4, 17, 48, 57, 4, -21, -8, -1, + 21, 30, -5, -15, 36, 44, 5, -14, -46, -40, 88, 67, 2, -29, -37, 9, + 31, -6, -9, 14, 15, 13, 11, -40, -74, -58, -24, 9, 22, 13, -6, -21, + -17, -13, -25, -6, 25, 21, -13, -25, 33, 26, -19, -27, -18, -6, 3, 10, + 16, 27, 45, 36, -26, -69, -46, -17, -4, 2, 10, 15, 18, 9, -22, -55, + -11, 15, -26, -36, -8, 30, 23, 2, -6, -14, -14, -6, 4, 11, 37, 59, + 19, -20, -10, -4, 16, 31, 7, -20, 23, 47, 15, -13, -32, -58, 58, 88, + 13, -21, -40, -5, 32, 4, -13, 10, 17, 12, 14, -23, -70, -65, -35, 1, + 20, 17, 0, -18, -20, -12, -23, -16, 19, 25, -1, -30, 16, 39, -8, -26, + -20, -8, 1, 9, 14, 23, 39, 44, -5, -63, -57, -24, -7, 1, 8, 13, + 17, 12, -12, -52, -30, 17, -15, -38, -18, 23, 32, 7, -6, -13, -14, -7, + 3, 8, 27, 55, 33, -16, -13, -6, 10, 30, 17, -20, 10, 46, 25, -9, + -21, -60, 19, 100, 31, -13, -39, -17, 27, 15, -13, 4, 17, 13, 15, -8, + -61, -69, -46, -10, 17, 21, 6, -13, -22, -13, -20, -22, 10, 27, 9, -27, + -4, 44, 6, -24, -22, -11, -1, 8, 13, 20, 33, 46, 14, -50, -65, -33, + -11, 0, 5, 12, 15, 14, -4, -43, -46, 10, -2, -36, -27, 13, 36, 15, + -4, -13, -14, -8, 3, 7, 18, 49, 43, -7, -16, -7, 5, 27, 24, -14, + -3, 42, 33, -3, -16, -51, -17, 97, 51, -3, -38, -5, -13, 1, -7, 5, + -22, -32, -35, -32, -43, -35, -55, -42, -66, -48, -80, -57, -17, -128, -59, -76, + 0, -26, 1, -33, 21, 3, 16, 15, 26, 43, 28, 66, 6, 97, 40, 103, + 67, 101, 102, 98, 94, 21, 98, 90, 57, 78, 89, 81, 61, -6, 54, 4, + 62, 19, 27, 34, 12, 16, 14, -17, 19, -5, -2, -13, -38, -24, -3, -33, + -14, -11, -16, 0, -13, 7, -26, -13, -16, 6, -57, -23, -28, -13, -9, -34, + -32, -20, -87, -62, -28, -38, -75, -37, -27, -41, -71, -48, -30, -44, -83, -67, + -52, -48, -45, -46, -45, -63, -47, -40, -32, -45, -24, -32, -43, -21, -17, 0, + 21, 26, 43, 51, 62, 47, 41, 55, 57, 68, 34, 53, 63, 62, 71, 60, + 61, 56, 53, 56, 54, 38, 50, 58, 50, 40, 28, 54, 39, 41, 38, 22, + 32, 20, -3, 19, -1, -7, -6, -16, -16, -14, -27, -29, -46, -66, -61, -51, + -54, -61, -41, -50, -47, -52, -55, -45, -44, -28, -58, -56, -31, -37, -36, -32, + -18, -16, -34, -29, -9, -21, -20, -30, -22, -17, -19, -8, -12, -14, -6, -14, + -6, -11, -2, 4, -6, 9, 8, 17, 23, 13, 31, 13, 24, 30, 28, 29, + 30, 43, 34, 37, 52, 42, 44, 50, 67, 59, 49, 54, 48, 43, 51, 45, + 42, 62, 47, 39, 37, 36, 24, 28, 13, 3, 9, -11, -3, -9, -14, -18, + -34, -27, -29, -39, -42, -38, -46, -37, -46, -43, -41, -35, -38, -31, -38, -34, + -39, -39, -34, -48, -44, -47, -49, -54, -52, -44, -53, -37, -47, -38, -31, -38, + -27, -19, -19, -15, -16, 0, 0, 2, 7, 13, 29, 22, 32, 32, 39, 47, + 41, 40, 55, 48, 41, 44, 57, 43, 36, 47, 43, 42, 37, 32, 32, 27, + 33, 36, 30, 23, 25, 25, 22, 18, 22, 20, 16, 8, 6, 12, 7, 0, + 1, 3, -5, -14, -9, -7, -8, -19, -15, -16, -23, -21, -21, -32, -31, -29, + -26, -27, -29, -33, -26, -29, -30, -39, -28, -41, -43, -35, -34, -32, -29, -28, + -28, -25, -27, -24, -27, -27, -27, -22, -23, -17, -9, -10, -14, -10, -8, -4, + -2, -1, -3, 5, 4, 10, 11, 7, 13, 11, 14, 27, 22, 22, 22, 27, + 36, 34, 36, 37, 45, 44, 47, 48, 51, 49, 52, 51, 52, 48, 50, 47, + 48, 42, 40, 29, 33, 24, 22, 12, 5, 0, -3, -5, -9, -21, -21, -25, + -19, -28, -28, -30, -33, -39, -42, -42, -46, -46, -45, -42, -43, -47, -47, -36, + -32, -30, -34, -31, -22, -29, -29, -30, -26, -28, -30, -21, -26, -27, -21, -19, + -16, -11, -12, -8, -2, 1, -4, 1, 0, 1, 9, 8, 7, 12, 10, 13, + 20, 17, 18, 21, 26, 29, 30, 30, 29, 34, 33, 34, 33, 30, 32, 33, + 28, 33, 29, 35, 32, 31, 30, 31, 30, 25, 27, 24, 21, 21, 20, 16, + 17, 12, 6, 4, -3, 1, -6, -7, -11, -13, -11, -10, -8, -13, -12, -9, + -17, -14, -19, -24, -22, -24, -30, -32, -30, -33, -37, -39, -40, -42, -39, -41, + -39, -40, -41, -35, -35, -35, -37, -36, -33, -30, -25, -25, -19, -16, -16, -10, + -6, -7, -4, -2, 1, 3, 6, 10, 9, 15, 17, 18, 17, 13, 19, 18, + 17, 19, 20, 24, 24, 27, 27, 29, 30, 26, 28, 28, 27, 28, 26, 25, + 24, 25, 20, 19, 17, 18, 15, 12, 13, 10, 6, 8, 6, 3, 4, 3, + 0, -3, 0, -1, -2, -5, -4, -5, -4, -5, -6, -8, -9, -9, -12, -11, + -16, -16, -15, -15, -13, -17, -16, -17, -17, -21, -20, -25, -24, -24, -24, -26, + -30, -30, -27, -30, -26, -26, -27, -27, -25, -24, -19, -20, -17, -13, -12, -8, + -8, -8, -6, -5, -2, -1, 0, 3, 8, 10, 12, 16, 18, 24, 25, 25, + 28, 30, 28, 32, 33, 31, 32, 31, 35, 33, 31, 31, 27, 28, 26, 23, + 23, 20, 22, 18, 16, 13, 11, 9, 5, 4, -2, -2, -3, -8, -9, -11, + -12, -13, -15, -15, -15, -15, -15, -14, -12, -12, -13, -13, -8, -11, -10, -12, + -10, -12, -12, -8, -8, -9, -9, -9, -8, -9, -10, -11, -11, -10, -13, -14, + -13, -16, -16, -17, -17, -18, -19, -18, -17, -16, -16, -15, -15, -13, -12, -10, + -12, -10, -9, -8, -6, -6, -3, 0, 0, 1, 2, 2, 3, 4, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 12, 13, 14, 14, 15, 15, 15, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 14, 13, 13, 12, 11, 10, + 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -1, -2, -3, -4, -5, + -5, -6, -7, -7, -8, -9, -9, -10, -11, -11, -12, -12, -13, -13, -13, -13, + -14, -14, -14, -15, -15, -15, -15, -15, -15, -16, -16, -16, -15, -15, -15, -14, + -13, -13, -12, -11, -10, -9, -8, -7, -6, -5, -4, -2, -1, 0, 1, 2, + 4, 5, 6, 7, 8, 9, 10, 11, 12, 12, 13, 13, 14, 14, 15, 15, + 15, 15, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 16, 16, 15, 15, + 14, 14, 13, 12, 11, 10, 9, 7, 6, 5, 3, 1, 0, -2, -4, -5, + -7, -9, -10, -11, -13, -14, -15, -15, -16, -17, -17, -18, -18, -18, -18, -18, + -18, -18, -18, -18, -18, -18, -18, -17, -17, -16, -16, -15, -14, -14, -13, -12, + -11, -10, -9, -8, -7, -6, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 9, 10, 11, 11, 12, 13, 13, 13, 14, 14, 14, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, 13, 12, 12, + 11, 10, 9, 8, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, -1, 0, + 0, -1, 2, 1, 0, 1, 4, 2, 2, 2, 5, 2, 5, 5, 8, 4, + 13, 15, 19, -62, -65, 56, -18, -128, -39, 15, -57, -10, 19, -22, -11, 36, + 30, 5, 19, 25, 17, 21, 21, 16, 21, 18, 17, 17, 15, 14, 13, 12, + 10, 6, 8, 6, 6, -1, 1, -4, 7, -10, -36, 35, 64, -25, -18, 83, + 50, 22, 39, 21, 19, -4, -20, 28, 0, -88, -55, -5, -55, -83, -64, -58, + -77, -61, -22, -39, -57, -15, 2, -14, -9, -1, 1, 1, 2, 9, 5, 6, + 11, 9, 9, 10, 11, 12, 12, 10, 9, 9, 13, 7, 3, 14, 4, -3, + 2, 2, 17, 40, 12, 14, 55, 58, 44, 39, 38, 37, 6, 4, 31, -6, + -50, -25, -15, -49, -52, -41, -60, -68, -32, -25, -47, -36, -9, -5, -7, -3, + 3, 4, 6, 8, 11, 9, 10, 14, 14, 11, 13, 15, 14, 13, 14, 12, + 11, 12, 12, 8, 8, 3, 4, 5, -1, 8, 32, 21, 14, 43, 50, 39, + 47, 39, 20, 23, 16, 5, -9, -23, -26, -34, -48, -37, -48, -71, -56, -34, + -43, -49, -36, -20, -14, -13, -9, -4, -1, 1, 3, 6, 6, 6, 9, 10, + 8, 10, 11, 11, 11, 11, 10, 10, 10, 10, 6, 6, 4, 3, 6, -3, + 2, 25, 23, 16, 34, 38, 43, 51, 31, 19, 38, 22, -10, -7, 0, -25, + -45, -34, -32, -54, -62, -47, -39, -45, -47, -36, -24, -19, -16, -11, -6, -3, + 0, 2, 4, 6, 7, 8, 10, 11, 9, 11, 12, 11, 11, 12, 11, 10, + 10, 8, 7, 6, 3, 5, 4, 0, 13, 28, 23, 19, 36, 50, 42, 30, + 31, 39, 24, -6, -2, 7, -21, -40, -27, -34, -51, -51, -44, -42, -45, -45, + -37, -27, -22, -18, -13, -9, -6, -2, 1, 2, 5, 7, 7, 9, 11, 10, + 10, 12, 12, 11, 12, 11, 10, 10, 9, 7, 7, 4, 5, 7, 1, 7, + 27, 24, 15, 34, 47, 37, 32, 36, 36, 26, 4, -1, 4, -13, -30, -27, + -34, -47, -46, -42, -43, -45, -44, -38, -31, -25, -21, -17, -12, -8, -5, -1, + 1, 3, 5, 6, 8, 9, 10, 10, 10, 11, 11, 11, 11, 11, 10, 9, + 7, 7, 6, 3, 6, 5, 6, 17, 23, 19, 29, 40, 35, 33, 36, 34, + 26, 14, 3, 0, -6, -18, -26, -32, -39, -40, -38, -39, -41, -40, -36, -31, + -27, -23, -19, -15, -12, -8, -4, -2, 0, 3, 4, 5, 7, 8, 9, 9, + 9, 10, 10, 10, 10, 10, 9, 8, 8, 8, 7, 8, 10, 11, 14, 19, + 22, 25, 28, 29, 29, 29, 27, 21, 14, 7, -1, -5, -11, -19, -26, -29, + -31, -32, -33, -34, -33, -32, -29, -26, -24, -21, -18, -15, -12, -9, -6, -4, + -2, 0, 2, 3, 5, 6, 7, 7, 8, 8, 9, 9, 9, 9, 9, 9, + 10, 10, 11, 12, 14, 16, 18, 20, 22, 23, 24, 24, 23, 20, 17, 12, + 7, 2, -3, -8, -13, -17, -21, -23, -25, -26, -27, -27, -27, -26, -25, -23, + -21, -19, -17, -14, -12, -9, -7, -5, -3, -1, 1, 2, 4, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 12, 13, 15, 16, 18, 19, 21, + 22, 22, 22, 21, 19, 17, 13, 9, 4, 0, -5, -10, -14, -18, -21, -23, + -25, -26, -26, -26, -26, -25, -23, -22, -20, -18, -15, -13, -11, -9, -6, -4, + -2, 0, 1, 3, 4, 5, 6, 7, 7, 8, 8, 8, 9, 9, 10, 11, + 12, 13, 14, 15, 17, 18, 20, 21, 21, 21, 21, 19, 17, 14, 11, 7, + 2, -3, -7, -11, -15, -19, -21, -23, -25, -25, -26, -25, -25, -24, -22, -21, + -19, -17, -15, -12, -10, -8, -6, -4, -2, 0, 1, 3, 4, 5, 6, 6, + 7, 8, 8, 9, 9, 10, 11, 11, 12, 13, 15, 16, 17, 19, 20, 20, + 21, 20, 19, 18, 15, 12, 8, 4, 0, -4, -9, -13, -16, -19, -21, -23, + -24, -25, -25, -25, -24, -23, -21, -20, -18, -16, -14, -12, -9, -7, -5, -3, + -2, 0, 1, 3, 4, 5, 6, 6, 7, 8, 8, 9, 10, 10, 11, 12, + 13, 14, 15, 17, 18, 19, 20, 20, 20, 19, 18, 16, 13, 10, 6, 2, + -2, -6, -10, -13, -16, -19, -21, -23, -24, -24, -24, -24, -23, -22, -20, -19, + -17, -15, -13, -11, -8, -6, -5, -3, -1, 0, 2, 3, 4, 5, 6, 7, + 7, 8, 9, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, + 19, 18, 16, 14, 11, 8, 4, 0, -3, -7, -11, -14, -17, -19, -21, -22, + -23, -23, -23, -23, -22, -21, -19, -18, -16, -14, -12, -10, -8, -6, -4, -2, + -1, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 10, 11, 12, 12, 13, + 14, 15, 16, 17, 18, 19, 19, 19, 18, 17, 15, 12, 9, 6, 3, -1, + -5, -9, -12, -15, -17, -19, -21, -22, -23, -23, -23, -22, -21, -20, -18, -17, + -15, -13, -11, -9, -7, -6, -4, -2, -1, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 9, 10, 11, 12, 13, 14, 15, 16, 17, 17, 18, 18, 18, 17, + 16, 14, 12, 10, 7, 4, 0, -3, -6, -9, -12, -15, -17, -18, -20, -20, + -21, -21, -21, -20, -19, -18, -17, -15, -14, -12, -10, -9, -7, -5, -4, -2, + -1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 14, + 15, 15, 16, 16, 16, 16, 16, 15, 14, 12, 11, 8, 6, 3, 0, -3, + -6, -9, -12, 1, -1, 2, -1, 4, 2, 8, 5, 10, -5, 0, 5, 17, + -11, 0, 19, -17, 26, 65, 15, 29, 3, 35, 67, 50, 88, 59, 117, 28, + -6, -16, 29, 63, 62, -40, 59, 22, -95, -49, -55, 19, 36, -15, 26, -117, + 60, 8, -101, -115, 23, 60, -32, -106, -84, -88, -127, -99, -117, -110, -56, -42, + -53, -79, -44, 43, 10, -11, 72, 22, 61, 10, -92, -106, -111, -35, -68, -128, + -67, -36, -118, -97, -96, -4, 75, 70, 113, 36, 73, 115, 37, 6, 79, 97, + 89, -8, -38, -8, -72, -8, -29, -35, 73, 98, 66, 12, 40, 113, 106, 87, + 126, 112, 127, 87, -3, -21, -23, 40, 14, -68, -20, 21, -57, -67, -67, -4, + 69, 53, 90, 17, 36, 78, -7, -54, -2, 32, 21, -71, -109, -89, -124, -103, + -114, -113, -37, -4, -30, -88, -83, 15, 13, -35, 42, 28, 33, 14, -90, -92, + -104, -37, -34, -115, -73, -9, -75, -89, -85, -29, 67, 51, 97, 55, 47, 115, + 46, -9, 42, 90, 96, 26, -36, 11, -43, -25, -6, -37, 59, 104, 88, 31, + 22, 96, 116, 69, 110, 119, 119, 109, 11, -15, -26, 18, 37, -45, -32, 34, + -13, -62, -62, -30, 61, 47, 75, 46, 14, 72, 14, -58, -35, 16, 30, -38, + -109, -78, -109, -116, -102, -123, -57, -2, -11, -58, -95, -18, 22, -41, -3, 36, + 20, 31, -69, -94, -100, -72, -21, -91, -92, -9, -33, -82, -81, -57, 48, 52, + 70, 81, 35, 97, 69, -10, 8, 66, 94, 55, -27, 4, -5, -40, -1, -33, + 30, 102, 101, 61, 19, 70, 121, 72, 77, 123, 112, 121, 36, -13, -21, -10, + 38, -18, -43, 27, 25, -40, -59, -45, 40, 54, 52, 68, 15, 56, 35, -48, + -58, -12, 25, -10, -98, -84, -83, -122, -101, -123, -81, -8, -3, -28, -85, -47, + 20, -28, -39, 23, 18, 31, -38, -99, -92, -97, -35, -66, -102, -26, -3, -60, + -77, -69, 18, 59, 47, 87, 46, 73, 86, 3, -13, 34, 80, 70, -8, -12, + 19, -32, -12, -21, 3, 91, 105, 87, 34, 51, 114, 89, 53, 106, 115, 119, + 65, -10, -13, -25, 20, 4, -45, 9, 44, -8, -49, -51, 14, 61, 39, 68, + 34, 39, 51, -30, -67, -41, 7, 5, -76, -96, -65, -111, -110, -115, -103, -20, + -1, -9, -58, -65, 8, -9, -55, -6, 17, 24, -11, -94, -89, -102, -64, -50, + -101, -51, 6, -30, -66, -71, -12, 59, 40, 72, 67, 58, 91, 24, -21, 6, + 56, 74, 14, -22, 23, -8, -24, -14, -13, 71, 106, 101, 62, 42, 101, 105, + 49, 76, 114, 114, 87, 3, -12, -23, -6, 13, -37, -11, 45, 24, -29, -49, + -8, 57, 40, 53, 54, 32, 56, -6, -65, -61, -21, 6, -52, -101, -65, -85, + -115, -109, -116, -42, 0, -1, -27, -65, -12, 7, -51, -37, 7, 17, 6, -76, + -95, -94, -91, -52, -90, -76, -2, -4, -46, -66, -35, 46, 46, 49, 78, 57, + 85, 50, -17, -13, 26, 64, 34, -22, 9, 18, -22, -14, -18, 42, 103, 105, + 88, 50, 83, 114, 63, 49, 96, 110, 99, 26, -14, -15, -23, 6, -24, -29, + 33, 45, 0, -38, -23, 44, 50, 37, 60, 38, 52, 21, -54, -70, -48, -7, + -31, -95, -78, -63, -104, -108, -117, -69, -4, -1, -5, -47, -30, 13, -33, -58, + -14, 8, 11, -50, -99, -87, -101, -70, -77, -92, -22, 10, -22, -52, -46, 23, + 55, 36, 70, 66, 74, 69, -2, -23, 1, 43, 43, -11, -8, 29, -4, -17, + -16, 18, 91, 105, 102, 71, 72, 112, 83, 40, 70, 101, 102, 50, -10, -10, + -24, -10, -13, -36, 14, 52, 27, -18, -28, 26, 58, 33, 51, 49, 46, 40, + -34, -70, -66, -31, -22, -81, -92, -56, -83, -105, -112, -91, -17, 0, 2, -22, + -37, 7, -12, -61, -39, -5, 7, -27, -93, -90, -96, -90, -72, -95, -48, 9, + -1, -33, -46, 0, 55, 37, 50, 72, 68, 77, 20, -25, -15, 17, 40, 3, + -20, 22, 19, -12, -14, 2, 70, 105, 106, 92, 72, 104, 100, 48, 46, 83, + 98, 70, 3, -12, -16, -23, -11, -34, -8, 46, 47, 11, -21, 8, 57, 41, + 36, 53, 45, 48, -6, -64, -72, -57, -28, -61, -98, -65, -60, -94, -105, -103, + -41, 1, 0, -1, -29, -6, 5, -48, -60, -26, -3, -12, -74, -97, -86, -100, + -80, -89, -74, -6, 13, -10, -35, -18, 41, 48, 33, 64, 68, 75, 46, -15, + -25, -7, 24, 16, -20, 4, 33, 5, -11, -5, 43, 98, 105, 105, 85, 93, + 110, 67, 35, 59, 87, 81, 25, -13, -9, -23, -18, -27, -25, 30, 55, 37, + -1, -3, 46, 53, 29, 44, 47, 48, 20, -48, -72, -72, -47, -48, -93, -82, + -51, -73, -96, -102, -66, -6, 0, 5, -10, -16, 10, -26, -66, -49, -20, -10, + -51, -98, -86, -93, -93, -85, -88, -32, 14, 8, -16, -23, 22, 54, 32, 45, + 67, 70, 61, 4, -27, -21, 2, 17, -13, -13, 29, 26, -1, -5, 23, 83, + 104, 106, 100, 90, 110, 87, 40, 38, 68, 80, 45, -6, -9, -14, -24, -23, + -32, 8, 52, 53, 25, 1, 31, 60, 35, 30, 45, 45, 36, -24, -68, -76, + -67, -49, -80, -94, -57, -54, -81, -95, -82, -23, 2, 1, 4, -12, 4, -5, + -57, -65, -40, -20, -36, -87, -94, -83, -97, -87, -90, -57, 2, 18, 2, -12, + 8, 10, -20, 30, 25, 21, 14, 4, 15, -48, -33, 11, -70, 54, -5, -21, + -8, -3, 73, -52, 65, -55, 80, -28, -67, -3, -13, 21, -49, -2, 11, 36, + 59, -60, 34, -28, 21, -25, -45, 54, 5, 0, -19, -12, 20, 54, -51, -23, + 22, 36, -59, -20, 8, 28, -9, -54, 127, -44, 69, -128, 5, 69, -8, -98, + 45, 69, 20, -97, 23, -7, 121, -81, -2, -21, 51, -67, -14, -24, 127, -60, + 45, -116, 127, -29, -93, -23, 107, -5, -21, -62, 37, 41, 29, -74, -63, 103, + 24, -59, -44, 62, 43, -28, -46, 7, 72, 19, -70, -47, 42, 53, -68, -13, + 37, 59, -38, -60, 39, 66, 27, -128, 36, 77, 15, -74, -15, 75, 38, -49, + -11, -39, 16, -8, -30, 35, 41, -1, -2, 17, -68, 99, -97, 60, -49, 32, + -44, -29, 82, -26, 39, -35, 10, 38, -20, -21, -92, 83, -24, 13, 31, -33, + 22, 45, -31, -24, 9, -24, -32, 42, -17, 34, 7, -27, 6, 61, -9, -34, + -5, -8, -17, -6, -34, 17, 43, -9, 35, -34, 16, 27, -24, -17, -17, 5, + -17, 42, -31, 22, 17, -26, -22, 32, 41, -27, -25, -10, -5, 16, -2, 13, + -1, 48, -33, -27, 6, 16, 13, -37, -11, 18, 25, -42, -11, 46, -7, -15, + 9, 15, 4, -3, -36, -24, 31, -8, 14, 12, 27, -19, -17, -14, -7, 42, + -5, -15, 5, 1, -15, 14, 43, -19, 1, -25, -35, 16, 16, 29, -12, 8, + -14, 1, 21, -8, -12, -22, -4, 24, 26, -16, -22, 37, 3, -41, 7, 4, + 3, 30, 4, -27, 11, -6, -26, 33, 23, -23, -14, -20, -7, -4, 36, 0, + 18, 10, -27, 1, 1, 16, -1, -4, -44, -5, 17, 9, 13, -4, -3, 31, + 24, -14, -26, 9, -27, -28, 19, 22, 32, -11, -15, 5, 15, -23, -21, 16, + 14, 18, -11, -26, 13, 10, -12, -12, 11, 14, -6, -13, -3, 6, -6, 3, + 12, 32, 14, -22, -45, -10, 37, 11, -50, -11, 50, 22, -13, -4, -4, 15, + -16, -33, 7, 34, -9, -14, -1, 21, 15, -14, -12, -6, 7, 8, 2, 0, + -5, 6, 15, 4, -9, 13, 3, -51, -18, 27, 10, 5, -11, 6, -1, 5, + 22, 2, -14, -39, -12, 19, 17, 4, 11, 5, -25, 2, 23, 8, 2, -3, + -39, -22, 4, 18, 6, 14, 25, 20, -17, -20, 17, 7, -43, -38, -18, 17, + 24, -6, 30, 44, 6, -36, -20, 7, 24, 1, -69, -25, 47, 15, -4, 35, + 19, -18, -22, -12, 20, 39, -36, -49, 9, 28, -16, 9, 34, 36, -22, -69, + -16, 39, 7, -28, -3, 33, -18, -7, 18, 53, 24, -37, -61, -10, 38, 2, + -24, -11, 12, 17, 0, 28, 50, -5, -59, -57, 22, 14, -15, -5, 22, 9, + -20, 19, 33, 31, -33, -62, -13, -2, 45, -9, -4, -3, 19, 8, -8, 40, + 8, -16, -44, -19, 16, 3, 23, -32, 22, 5, -9, 5, 26, 21, -27, -18, + -45, 3, 15, 0, 7, 7, 7, 13, 18, -10, 3, -5, -30, -30, -3, 9, + 31, 17, -10, 19, 28, -33, -20, 31, 14, -67, -27, 13, 20, 29, 1, -2, + 24, -3, -26, -12, 32, -7, -31, -17, 5, 22, 11, -6, 6, 7, 2, 7, + 5, -12, -22, -17, -24, 22, 47, 1, 2, 10, 5, -29, -5, 13, 1, -30, + -28, -5, 23, 25, 6, 5, 1, 7, 0, 5, 3, -33, -37, -6, 19, 20, + 26, -1, -15, 21, 9, -14, -13, 0, -11, -24, -9, 9, 23, 1, 1, 32, + 11, -25, -18, 5, -5, -6, -9, -10, 2, 18, 4, 12, 6, -2, -8, 2, + 2, -7, 2, -22, -5, 17, 25, 15, -5, -1, -24, -8, -10, -5, 12, 7, + -4, -10, 4, 8, 22, 11, -1, -12, -31, -17, 6, 12, 11, 5, -3, -1, + 22, 0, -4, 3, -18, -17, -3, 16, 9, 2, -5, 0, 4, -9, 18, 17, + -22, -19, -8, -6, 21, 11, -6, -16, 33, 13, -15, -3, -15, 1, -3, -10, + -7, 8, 17, -11, 9, 19, 0, 5, 0, -18, -13, 2, -20, 10, 29, -11, + -13, 5, 11, 16, 4, -25, -21, 13, -5, 1, 3, -1, 6, 13, -7, -1, + 17, -6, -6, -9, -6, -3, -1, 1, 18, 11, -22, 2, 18, -2, -15, 1, + 5, -12, -10, -7, 9, 26, 10, -11, 5, 0, -7, -3, -11, -9, -3, 2, + -10, 19, 28, -3, -3, -4, 9, -14, -5, -7, 8, -3, -27, 5, 37, 11, + -2, 3, -27, -15, 12, -2, 14, 2, -8, -16, 22, 11, -1, 10, -17, -8, + -5, -23, 2, 29, 8, -21, 8, 12, 6, 8, -17, 3, -2, -12, -27, 16, + 25, -5, -7, 2, 19, 1, -15, 7, 2, -5, -34, 2, 18, 17, -10, 2, + 18, -1, -12, -10, 5, 1, -16, -9, 12, 21, 4, -10, 2, 12, 1, -19, + -11, 20, 5, -14, -21, 5, 17, -5, 3, 17, 4, -25, -5, 5, 4, 0, + -5, 2, 2, -1, 1, 13, 0, -11, -8, 3, 2, -1, -3, -3, 11, 8, + -6, 2, 7, 4, -5, -23, -2, 14, -1, -15, -2, 15, 10, 1, -4, 16, + 1, -24, -12, 8, 8, -20, -2, 14, 13, 10, 2, 2, -9, -6, -9, -3, + 5, 7, -3, -9, 0, 2, 8, 3, -1, 2, -4, 0, -1, -1, -1, -2, + -8, -14, -19, -28, -51, -53, -49, -48, -49, -44, -37, -30, -23, -14, -8, -11, + -5, 3, 11, 2, 0, 8, 19, 10, 1, 6, 18, 15, 4, 4, 17, 19, + 13, 9, 20, 27, 26, 26, 33, 42, 45, 53, 59, 68, 69, 83, 89, 92, + 85, 88, 91, 80, 56, 37, 29, 9, -25, -54, -65, -74, -94, -113, -112, -103, + -101, -103, -93, -79, -66, -62, -50, -41, -33, -27, -17, -11, -12, -8, 0, 7, + -1, -2, 5, 15, 8, -1, 3, 15, 13, 2, 2, 12, 17, 12, 8, 15, + 23, 24, 25, 29, 38, 42, 50, 56, 65, 68, 78, 87, 91, 87, 87, 91, + 84, 64, 43, 33, 16, -14, -44, -60, -70, -87, -107, -111, -105, -101, -103, -96, + -84, -70, -64, -55, -45, -36, -30, -22, -14, -14, -11, -4, 4, 0, -3, 1, + 11, 8, -1, 0, 10, 12, 3, 0, 9, 15, 11, 7, 14, 22, 23, 24, + 28, 37, 42, 49, 55, 64, 67, 78, 87, 91, 88, 88, 93, 86, 67, 47, + 36, 20, -10, -40, -56, -67, -84, -104, -109, -105, -101, -103, -96, -85, -71, -65, + -56, -46, -38, -31, -23, -16, -15, -12, -6, 2, -1, -5, 0, 9, 6, -1, + -1, 8, 11, 3, 0, 8, 14, 11, 7, 13, 21, 23, 23, 27, 37, 41, + 48, 54, 63, 67, 77, 86, 91, 89, 89, 93, 87, 70, 51, 39, 23, -6, + -36, -53, -64, -81, -101, -107, -103, -100, -102, -96, -85, -72, -66, -57, -47, -39, + -32, -25, -17, -16, -13, -7, 0, -3, -5, -1, 7, 6, -2, -2, 7, 9, + 2, -1, 7, 13, 10, 7, 12, 20, 22, 23, 27, 36, 41, 48, 54, 63, + 68, 77, 87, 91, 91, 91, 95, 89, 73, 54, 43, 27, -1, -31, -49, -61, + -78, -98, -105, -102, -99, -101, -96, -85, -73, -66, -58, -48, -40, -33, -26, -19, + -17, -14, -9, -2, -4, -6, -3, 5, 4, -3, -3, 5, 8, 1, -1, 6, + 12, 10, 7, 11, 20, 22, 23, 27, 35, 41, 47, 54, 62, 68, 76, 86, + 91, 91, 92, 96, 91, 76, 58, 46, 30, 3, -27, -45, -57, -75, -94, -103, + -100, -98, -100, -96, -85, -74, -67, -59, -49, -41, -34, -28, -20, -19, -15, -10, + -3, -5, -7, -4, 3, 3, -4, -4, 4, 7, 1, -2, 5, 11, 9, 6, + 11, 19, 21, 22, 26, 35, 40, 46, 53, 61, 67, 76, 86, 91, 92, 93, + 97, 93, 78, 61, 49, 33, 7, -22, -41, -54, -72, -91, -100, -99, -97, -100, + -96, -86, -74, -67, -60, -51, -42, -35, -29, -22, -20, -17, -11, -5, -6, -8, + -5, 2, 1, -5, -5, 2, 5, 0, -3, 3, 10, 8, 5, 10, 18, 21, + 21, 25, 34, 39, 45, 52, 61, 67, 75, 85, 91, 92, 94, 97, 94, 81, + 64, 52, 37, 11, -18, -37, -51, -69, -88, -98, -98, -96, -99, -95, -86, -75, + -68, -61, -52, -44, -36, -30, -23, -21, -17, -13, -6, -7, -9, -6, 0, 0, + -5, -5, 1, 4, -1, -3, 2, 8, 8, 5, 10, 17, 20, 21, 25, 33, + 39, 45, 51, 60, 66, 75, 85, 91, 93, 94, 98, 95, 83, 67, 55, 40, + 15, -14, -33, -48, -66, -85, -96, -96, -95, -98, -95, -86, -75, -69, -62, -53, + -45, -38, -32, -25, -22, -19, -14, -8, -9, -10, -8, -2, -1, -6, -7, -1, + 2, -2, -4, 1, 7, 6, 5, 8, 16, 19, 20, 24, 32, 38, 44, 50, + 59, 66, 74, 84, 91, 93, 95, 99, 97, 85, 70, 58, 43, 18, -10, -30, + -45, -63, -82, -93, -95, -94, -97, -95, -87, -76, -70, -63, -54, -46, -39, -33, + -26, -23, -20, -16, -10, -10, -12, -9, -3, -3, -7, -8, -2, 1, -2, -5, + 0, 6, 6, 4, 8, 15, 18, 20, 23, 31, 37, 43, 50, 58, 65, 74, + 83, 91, 93, 96, 100, 98, 87, 72, 61, 46, 22, -6, -27, -42, -60, -79, + -91, -94, -93, -97, -95, -87, -77, -70, -64, -55, -47, -40, -34, -28, -25, -22, + -17, -12, -11, -13, -11, -5, -4, -8, -9, -3, 0, -4, -6, -1, 5, 5, + 3, 7, 14, 18, 19, 23, 30, 36, 42, 49, 57, 65, 73, 83, 90, 94, + 96, 100, 99, 89, 75, 63, 49, 25, -2, -23, -38, -56, -76, -88, -92, -92, + -95, -94, -87, -77, -71, -65, -57, -48, -41, -36, -29, -26, -23, -19, -13, -12, + -14, -12, -7, -6, -9, -10, -5, -1, -4, -7, -2, 2, 5, 4, 6, 12, + 18, 20, 24, 30, 38, 45, 52, 61, 70, 79, 89, 99, 106, 109, 113, 115, + 109, 96, 81, 66, 44, 16, -12, -32, -52, -74, -92, -101, -104, -107, -108, -103, + -94, -85, -78, -70, -60, -52, -45, -38, -33, -29, -25, -19, -16, -17, -16, -12, + -9, -10, -12, -9, -5, -5, -7, -5, 0, 3, 3, 5, 11, 17, 20, 23, + 29, 37, 44, 51, 59, 69, 78, 88, 98, 105, 110, 114, 116, 110, 98, 84, + 69, 48, 20, -7, -29, -49, -71, -89, -99, -102, -105, -107, -103, -94, -86, -79, + -71, -62, -54, -47, -40, -34, -30, -26, -21, -18, -18, -17, -14, -10, -12, -14, + -11, -5, -10, 43, -94, 44, -13, 27, -98, 1, 9, 77, 63, 4, 8, -128, + 63, -73, 78, -116, 127, -14, 111, -87, -67, -43, -45, 38, 53, 99, -37, 14, + -51, -58, -23, -32, 34, 27, 75, 9, 51, -104, -71, -33, 27, 67, 0, -1, + 25, 0, -35, 1, -70, 28, -4, 109, 3, 5, -42, -7, 42, -15, 37, -62, + 67, -14, 48, -85, -46, -94, 37, 35, 23, 15, -79, 35, -50, 91, -64, 40, + -69, 46, 20, 43, -21, -51, 8, -1, 95, -47, 69, -104, 98, -44, 74, -61, + -14, -19, 7, 52, -40, 8, -89, 58, -53, 106, -106, 42, -82, 61, -1, -8, + -10, -59, 53, -18, 85, -83, 63, -73, 89, -32, 50, -62, 10, 13, 20, 62, + -81, 41, -84, 88, -32, 41, -78, 27, -30, 51, -6, -42, 6, -49, 74, -41, + 41, -89, 27, -33, 57, 0, -16, -8, -4, 45, 8, 20, -63, 36, -29, 75, + -23, -17, -23, -14, 45, -7, 17, -56, 20, -12, 45, -16, -13, -31, 6, 31, + -7, 17, -81, 40, -35, 73, -34, 0, -31, 10, 35, -4, 19, -60, 44, -30, + 83, -66, 41, -87, 59, -6, 23, -4, -59, 34, -33, 77, -70, 49, -89, 88, + -45, 63, -62, 4, -20, 18, 46, -49, 45, -101, 91, -56, 78, -79, 35, -51, + 67, -12, -2, -14, -49, 66, -35, 72, -87, 51, -74, 83, -38, 29, -36, -10, + 23, 3, 30, -59, 27, -59, 91, -44, 41, -63, 12, 2, 23, 8, -36, 14, + -35, 66, -38, 32, -59, 25, -11, 40, -6, -25, -2, -24, 55, -25, 29, -58, + 30, -17, 41, -18, -17, -3, -13, 50, -25, 26, -63, 35, -23, 50, -22, -5, + -18, 0, 33, -19, 22, -67, 57, -39, 63, -45, 6, -27, 13, 23, -6, 15, + -55, 44, -42, 70, -59, 36, -60, 56, -13, 15, -9, -50, 49, -38, 72, -63, + 37, -65, 67, -48, 55, -51, 10, 2, -5, 45, -61, 46, -83, 91, -58, 72, + -69, 23, -27, 35, -8, -3, -2, -33, 66, -61, 79, -100, 67, -60, 66, -26, + 13, -21, -13, 23, -11, 29, -49, 40, -53, 80, -67, 52, -63, 28, 6, -1, + 23, -45, 25, -30, 42, -25, 22, -42, 33, -26, 39, -26, -9, 10, -28, 61, + -50, 33, -43, 18, 2, 6, 4, -18, 4, -8, 24, -21, 22, -49, 50, -40, + 52, -35, -10, 17, -34, 64, -53, 38, -47, 37, -28, 40, -47, 33, -32, 28, + 3, -20, 30, -69, 79, -75, 88, -72, 39, -34, 22, -7, 9, -18, 1, 19, + -27, 58, -89, 81, -90, 89, -58, 42, -27, -5, 16, -21, 29, -34, 28, -37, + 59, -65, 72, -90, 69, -45, 31, 6, -36, 40, -53, 56, -47, 39, -42, 40, + -38, 50, -52, 34, -31, 7, 32, -47, 62, -79, 66, -51, 41, -27, 12, -10, + 12, -5, 3, -5, -18, 33, -44, 70, -75, 60, -52, 27, 4, -19, 22, -29, + 27, -15, 18, -31, 26, -36, 50, -41, 35, -31, 3, 19, -37, 55, -62, 51, + -38, 25, -11, 1, -13, 12, -7, 13, 4, -33, 38, -56, 72, -64, 52, -43, + 20, 6, -20, 25, -40, 34, -25, 38, -41, 43, -68, 68, -59, 53, -28, -7, + 27, -45, 63, -70, 56, -60, 59, -41, 48, -56, 39, -43, 35, -3, -19, 40, + -70, 85, -81, 76, -75, 48, -36, 41, -20, 12, -23, 0, 16, -23, 51, -76, + 78, -82, 80, -57, 29, -23, 3, 14, -2, 9, -29, 17, -31, 55, -51, 53, + -66, 49, -27, 17, 3, -35, 36, -33, 44, -27, 11, -30, 24, -18, 37, -29, + 4, -3, -15, 45, -47, 42, -57, 46, -19, 18, -11, -20, 10, -3, 24, -18, + 14, -46, 52, -50, 64, -57, 25, -14, 1, 33, -42, 30, -52, 50, -28, 47, + -54, 32, -49, 53, -25, 14, -4, -34, 57, -54, 69, -78, 46, -45, 52, -21, + 21, -37, 7, 1, 3, 29, -57, 56, -74, 90, -66, 47, -51, 16, 6, 10, + 10, -29, 9, -32, 58, -47, 59, -84, 65, -49, 52, -24, -18, 14, -30, 61, + -39, 31, -57, 39, -38, 67, -56, 37, -46, 26, 10, -15, 18, -49, 45, -27, + 42, -37, 11, -24, 30, -15, 21, -34, 15, -5, 11, 5, -24, 11, -16, 30, + -16, 6, -20, 7, 3, 11, -9, -5, -6, 4, 16, -15, 9, -29, 22, -6, + 14, -6, -16, 9, -12, 28, -22, 15, -27, 22, -11, 21, -23, 5, -10, 8, + 17, -22, 19, -42, 41, -31, 39, -37, 20, -20, 19, -3, -7, 2, -17, 27, + -20, 30, -43, 30, -34, 38, -24, 13, -13, -1, 16, -16, 19, -36, 28, -21, + 30, -22, 7, -17, 11, 2, 1, 1, -19, 22, -21, 32, -34, 18, -21, 17, + 6, -8, 5, -25, 21, -13, 24, -24, 12, -22, 24, -11, 10, -14, -7, 15, + -11, 28, -36, 21, -30, 30, -10, 10, -13, -5, 6, -2, 14, -22, 15, -25, + 33, -22, 23, -31, 11, -6, 8, 11, -21, 14, -28, 32, -23, 25, -31, 19, + -15, 19, -7, -7, 1, -13, 26, -19, 24, -37, 25, -24, 30, -18, 6, -9, + -2, 17, -16, 17, -34, 27, -19, 28, -21, 6, -15, 10, 4, 0, 2, -20, + 22, -19, -21, 0, -3, -3, 2, 1, -1, 2, -2, -1, 4, 3, -3, -15, + -21, -20, -23, -42, -45, -31, -27, -17, -8, 9, 29, 41, 44, 33, 20, 13, + 6, 12, 16, 25, 43, 44, 33, 33, 35, 15, -5, -3, 8, 16, 8, -10, + -6, 8, 4, -4, 1, -18, -38, -43, -51, -54, -55, -71, -85, -68, -58, -61, + -50, -33, -27, -15, -5, 22, 67, 100, 109, 114, 110, 91, 69, 50, 37, 35, + 46, 48, 37, 36, 14, -24, -38, -42, -38, -38, -59, -91, -86, -57, -44, -32, + -15, -26, -44, -30, -30, -30, -16, -31, -50, -34, -43, -59, -49, -44, -52, -62, + -69, -50, -4, 47, 83, 105, 120, 111, 88, 72, 55, 57, 76, 69, 59, 55, + 41, 10, -18, -32, -28, -19, -36, -68, -76, -72, -71, -46, -35, -47, -43, -43, + -61, -48, -28, -25, -22, -19, -23, -15, -7, 3, 4, -8, -28, -37, -5, 42, + 72, 107, 127, 122, 117, 90, 48, 37, 48, 51, 54, 56, 43, 24, -8, -37, + -33, -11, -28, -55, -61, -75, -75, -51, -58, -55, -33, -33, -41, -35, -30, -21, + -16, -17, -24, -26, -20, -18, -17, -12, -36, -72, -65, -45, -6, 53, 88, 106, + 119, 107, 71, 52, 50, 59, 75, 87, 85, 76, 43, -1, -7, 9, -1, -13, + -34, -69, -80, -74, -80, -73, -65, -67, -65, -56, -44, -33, -23, -18, -24, -25, + -16, -20, -9, -1, -21, -38, -55, -64, -40, 3, 39, 82, 113, 114, 95, 71, + 54, 56, 68, 76, 87, 94, 57, 10, -9, -17, -17, -15, -35, -60, -75, -89, + -92, -85, -76, -71, -74, -70, -53, -41, -20, -9, -9, 4, 4, 10, 33, 38, + 25, 15, -17, -43, -33, -15, 3, 40, 77, 94, 91, 69, 37, 31, 33, 37, + 68, 96, 82, 53, 25, 8, 22, 28, 9, -9, -27, -46, -56, -65, -62, -61, + -60, -51, -51, -39, -25, -23, -11, -3, -15, -10, 5, 12, 20, 18, -11, -41, + -52, -47, -34, -2, 33, 65, 82, 70, 51, 45, 28, 21, 49, 74, 86, 74, + 33, 5, 10, 14, 7, -10, -28, -45, -67, -68, -73, -76, -66, -66, -65, -46, + -39, -31, -9, -3, -6, 1, 8, 22, 41, 49, 33, 8, -16, -34, -30, -17, + 7, 49, 73, 64, 63, 50, 19, 5, 13, 32, 62, 65, 37, 8, -5, 4, + -1, -8, -15, -36, -50, -57, -71, -65, -53, -58, -49, -37, -40, -28, -10, -3, + 0, 2, -2, 5, 30, 41, 36, 22, -7, -33, -39, -46, -30, 15, 44, 56, + 72, 65, 44, 21, 2, 15, 42, 59, 49, 18, 2, -3, -4, 0, -10, -25, + -34, -52, -65, -59, -56, -50, -37, -33, -33, -25, -12, -2, 10, 12, 3, 6, + 27, 42, 52, 43, 16, -3, -24, -48, -41, -11, 16, 48, 67, 78, 75, 49, + 21, 13, 36, 64, 63, 47, 25, -1, -2, 2, -12, -18, -28, -53, -65, -71, + -76, -70, -55, -53, -49, -41, -35, -24, -1, 5, 1, 4, 8, 28, 51, 43, + 26, 18, -14, -42, -51, -49, -23, 5, 31, 55, 67, 58, 26, -2, 11, 35, + 49, 55, 35, 8, 3, -2, -5, -6, -13, -30, -38, -49, -61, -56, -45, -43, + -36, -31, -37, -25, -7, 1, 6, 1, -10, 11, 33, 29, 27, 17, -6, -34, + -58, -67, -57, -34, -4, 21, 50, 63, 37, 11, 8, 17, 45, 63, 55, 39, + 26, 12, 11, 10, -1, -11, -19, -35, -51, -52, -52, -45, -35, -36, -41, -31, + -24, -9, 9, -3, -12, 2, 19, 33, 40, 37, 25, -3, -30, -51, -59, -42, + -24, -3, 38, 58, 51, 32, 8, 2, 25, 45, 50, 49, 35, 18, 16, 19, + 10, 9, 4, -13, -27, -36, -45, -36, -24, -32, -29, -31, -33, -10, 6, 1, + -4, -6, 4, 19, 30, 37, 30, 12, -13, -48, -59, -57, -56, -35, 2, 31, + 48, 41, 12, -2, 7, 25, 41, 52, 44, 29, 25, 22, 18, 20, 15, 1, + -6, -26, -38, -28, -26, -21, -17, -31, -33, -19, -4, 0, -8, -16, -15, -11, + 9, 19, 22, 24, -2, -34, -49, -61, -70, -57, -32, 4, 38, 46, 26, 5, + -1, 7, 29, 45, 44, 38, 32, 23, 27, 30, 23, 24, 14, -8, -16, -24, + -24, -12, -10, -19, -27, -26, -9, -2, -4, -6, -16, -14, -2, 8, 23, 34, + 17, -6, -26, -47, -61, -62, -50, -18, 26, 50, 48, 31, 12, 6, 24, 40, + 44, 51, 40, 29, 34, 28, 27, 32, 20, 7, -5, -23, -26, -19, -9, -12, + -25, -25, -17, -8, 1, -4, -13, -12, -16, -9, 13, 26, 23, 8, -13, -37, + -55, -71, -78, -59, -18, 16, 35, 34, 8, -3, 4, 13, 31, 40, 34, 34, + 29, 23, 30, 31, 27, 21, 7, -6, -21, -21, -10, -10, -19, -24, -28, -17, + -6, -8, -9, -9, -19, -21, -5, 12, 23, 22, 5, -16, -34, -55, -80, -78, + -56, -22, 18, 33, 24, 14, 3, 7, 25, 31, 37, 41, 33, 29, 29, 32, + 33, 30, 24, 7, -16, -22, -18, -15, -14, -24, -31, -22, -13, -12, -8, -6, + -18, -27, -22, -6, -5, -1, -1, -1, 1, 2, 7, 13, 19, 10, -12, -31, + -13, 17, 29, -4, -29, 24, 53, 18, 92, 15, -15, 23, 13, -35, -52, 127, + 9, 3, -9, 31, -63, -64, -5, -50, 14, 33, -29, -42, 0, 43, 39, -15, + -59, -45, 3, 33, 12, -35, -10, 51, 18, 49, 55, -28, 16, 4, 3, -64, + 54, 53, -12, 0, 5, -4, -72, -7, -31, -14, 26, -2, -37, -14, 17, 35, + 4, -33, -45, -12, 15, 21, -16, -23, 22, 28, 12, 55, -7, -2, 7, 7, + -34, -10, 65, -4, 1, -5, 14, -46, -28, -9, -29, 13, 13, -23, -23, 4, + 27, 18, -17, -39, -25, 5, 20, 0, -26, 1, 34, 7, 41, 24, -20, 11, + 1, -6, -45, 53, 22, -6, -4, 9, -17, -52, -4, -30, -6, 20, -9, -29, + -8, 18, 27, -2, -33, -36, -6, 16, 13, -20, -16, 27, 19, 18, 49, -17, + 3, 2, 6, -42, 9, 55, -9, 1, -3, 9, -54, -19, -16, -24, 16, 7, + -27, -19, 8, 28, 12, -22, -40, -20, 8, 19, -7, -25, 9, 31, 7, 48, + 9, -14, 9, 2, -17, -35, 62, 9, -2, -6, 13, -30, -44, -4, -31, 2, + 18, -15, -27, -3, 22, 24, -8, -36, -32, -2, 17, 8, -23, -9, 31, 13, + 28, 40, -21, 8, 1, 3, -47, 29, 43, -9, 0, 1, 1, -57, -11, -22, + -17, 19, 2, -28, -14, 12, 29, 7, -27, -39, -14, 11, 17, -13, -22, 17, + 27, 10, 51, -4, -7, 7, 5, -27, -19, 64, -1, 1, -6, 14, -41, -34, + -8, -30, 8, 15, -20, -24, 2, 25, 20, -14, -38, -27, 2, 18, 2, -25, + -1, 33, 9, 37, 29, -21, 11, 0, -3, -46, 46, 29, -7, -2, 7, -9, + -54, -6, -27, -10, 20, -4, -28, -9, 16, 28, 1, -30, -37, -8, 14, 14, + -18, -17, 25, 22, 16, 50, -13, 1, 4, 5, -37, 0, 59, -7, 2, -4, + 12, -49, -24, -13, -26, 13, 11, -23, -19, 6, 27, 15, -19, -39, -21, 6, + 18, -4, -24, 7, 32, 8, 45, 15, -16, 10, 2, -12, -39, 58, 16, -3, + -5, 11, -22, -48, -4, -30, -2, 19, -10, -26, -4, 20, 25, -5, -34, -33, + -4, 16, 10, -21, -11, 30, 16, 25, 43, -19, 7, 1, 4, -44, 20, 49, + -8, 1, -1, 6, -54, -15, -19, -20, 17, 6, -26, -15, 10, 29, 9, -23, + -39, -16, 9, 17, -10, -22, 15, 29, 10, 50, 2, -10, 8, 3, -22, -26, + 63, 5, 0, -6, 14, -34, -39, -6, -30, 4, 17, -15, -24, 0, 24, 22, + -11, -36, -28, 1, 17, 5, -23, -3, 32, 12, 34, 33, -21, 10, 0, 0, + -46, 39, 36, -7, -1, 4, -3, -54, -9, -24, -14, 19, 0, -26, -10, 14, + 28, 4, -27, -37, -11, 12, 15, -15, -18, 22, 24, 14, 50, -9, -2, 5, + 5, -32, -8, 61, -3, 2, -5, 14, -44, -29, -10, -27, 10, 13, -20, -20, + 4, 26, 17, -16, -37, -23, 4, 18, -1, -23, 5, 32, 9, 42, 20, -18, + 11, 1, -7, -41, 53, 22, -4, -3, 9, -14, -50, -6, -27, -7, 19, -6, + -26, -5, 18, 26, -2, -31, -34, -6, 14, 11, -19, -12, 28, 19, 22, 45, + -17, 4, 2, 5, -40, 11, 54, -6, 2, -3, 10, -51, -20, -16, -23, 14, + 9, -23, -15, 8, 28, 12, -20, -38, -18, 7, 17, -7, -22, 13, 30, 10, + 47, 7, -12, 9, 2, -17, -31, 61, 10, 0, -5, 13, -26, -43, -6, -29, + 0, 18, -11, -23, -1, 22, 23, -8, -34, -30, -1, 15, 7, -22, -5, 31, + 14, 30, 37, -20, 9, 0, 2, -44, 30, 42, -7, 1, 2, 2, -53, -12, + -21, -17, 17, 4, -25, -11, 12, 28, 6, -25, -37, -13, 10, 15, -13, -18, + 20, 26, 13, 49, -5, -5, 6, 4, -27, -16, 62, 1, 2, -5, 14, -38, + -34, -9, -28, 6, 15, -16, -20, 3, 25, 19, -13, -36, -25, 2, 16, 1, + -23, 3, 32, 11, 38, 25, -19, 11, 0, -4, -43, 46, 29, -4, -2, 7, + -8, -51, -8, -25, -10, 18, -2, -25, -7, 16, 27, 0, -28, -35, -8, 12, + 12, -17, -13, 26, 21, 19, 46, -14, 2, 3, 4, -36, 2, 57, -4, 3, + -4, 12, -46, -25, -13, -25, 11, 12, -20, -16, 7, 27, 14, -18, -37, -20, + 5, 16, -5, -21, 10, 31, 10, 45, 12, -14, 10, 1, -12, -36, 57, 16, + -1, -4, 11, -20, -46, -6, -28, -4, 18, -8, -23, -3, 20, 24, -5, -32, + -31, -4, 13, 8, -20, -6, 29, 17, 27, 39, -19, 7, 0, 3, -42, 21, + 47, -6, 2, 0, 7, -51, -17, -18, -20, 15, 7, -23, -12, 10, 28, 8, + -22, -37, -15, 8, 15, -10, -19, 18, 27, 13, 47, 0, -8, 8, 3, -24, + -20, 52, -36, -2, 0, -2, 3, 5, -4, -28, 22, -43, 36, -13, -127, -43, + 2, -18, 126, 78, -127, -48, 68, -74, -67, 33, 62, 83, 42, -32, -46, -70, + -26, 115, 21, -66, 72, 52, -27, 44, 50, 50, 61, 28, -12, 3, -59, 49, + 3, -19, 39, 94, 16, 31, 6, 29, 3, -100, -1, -4, -60, 19, 7, -29, + -28, -38, -3, -47, -20, -21, -1, 5, -55, -12, -55, -39, 26, 47, -22, -9, + -41, -21, -19, -37, 0, 45, -56, 24, 75, -50, -9, 31, 28, 26, 13, -3, + -15, -27, 1, 1, -31, -10, 38, -1, 7, 43, 19, 21, 41, 33, 9, -17, + -3, -42, -76, -30, -8, -9, -1, 21, 22, 38, 32, 22, 0, -18, -32, -58, + -12, 5, -48, -13, 64, 29, -2, 2, 19, 43, 25, -19, -39, -69, -92, -15, + 23, 30, 30, 51, 37, 35, 37, 30, -27, -63, 5, -30, -56, -16, 26, 52, + 20, 14, 59, 27, -9, 22, -4, -20, -37, -17, -34, -34, -1, 35, 26, 31, + 5, -16, 4, 33, 22, 8, 5, -28, -41, -20, -10, -6, -2, -16, 12, 31, + -23, 7, -2, -39, -28, -13, 8, 5, 16, -4, -6, -18, -24, -27, -50, -6, + 5, 12, 0, -2, -14, -23, 5, -28, -10, 2, 28, 15, 2, 22, 27, 41, + 31, 2, 12, 31, 5, 12, -6, 15, 40, 34, 18, 26, 26, 12, 34, 23, + 34, 30, 22, 10, -26, -22, 1, 0, -1, 12, -4, -21, -5, -5, -20, -31, + -25, -24, -42, -44, -41, -41, -37, -29, -28, -29, -40, -17, -21, -38, -42, -38, + -40, -36, -13, -14, -8, -15, -7, -6, 5, 12, -1, -17, -1, 9, 2, 16, + 30, 27, 37, 36, 38, 36, 36, 19, 45, 45, 33, 26, 33, 28, 36, 31, + 17, 12, 22, 11, 11, 17, 5, -13, 6, 10, 2, -6, 2, 9, 15, -6, + -8, -23, -44, -3, -11, -35, -25, -35, -23, -21, 0, -11, -21, -17, 11, -6, + -11, -17, -33, -16, -16, -4, -7, -7, -9, -4, 1, 1, -3, 6, 7, 4, + -17, -11, -6, -4, 1, 3, 6, 4, 5, -4, 17, 7, 3, 9, -20, 0, + -7, -3, -5, 4, 9, 16, 2, 3, 8, 15, 15, 1, -3, 8, -1, 5, + 14, 7, 4, 8, -8, 2, -3, 5, 11, 5, 3, -4, 10, 17, 13, -11, + -5, 1, -3, 0, -6, -12, 2, -3, 13, -5, -25, -15, -7, 4, 1, -8, + -4, -12, -16, 3, 9, -6, 3, -21, -4, 4, -14, 1, -1, -2, 3, -8, + -5, 0, 7, -2, -3, -1, 3, -9, 5, -4, -17, -1, 9, 3, 7, 1, + -4, -3, 5, 2, -7, -9, 12, -6, -14, -16, 2, -1, 16, 2, 2, 7, + -6, -26, 3, -2, -4, -2, 10, 3, -7, 3, 8, 9, 5, 4, 1, -5, + -5, 11, 8, 7, 11, 12, -1, -5, -16, 13, 7, 2, 11, 4, -4, 9, + -8, -8, 14, 11, -8, 0, -1, -5, -2, -1, -10, -5, -9, -9, -16, -12, + -8, -16, 5, -10, -4, -11, -3, 1, 0, -3, -5, -13, -9, -2, -8, 5, + -9, -7, -2, 2, -11, -7, 13, 8, -3, 2, 7, -2, -1, 5, 0, 11, + 6, 13, 15, 1, -4, 9, 5, 3, 8, -3, -4, 16, 4, 11, 9, 0, + 8, 1, -6, -5, -18, 3, 7, -18, -4, 0, -3, -3, -6, -4, -5, -5, + -10, -2, -9, -5, -2, -4, -11, -2, 1, -5, -2, 11, -6, -9, 1, 4, + -6, -1, -5, 1, 2, 9, 5, 0, 4, 4, -2, 7, 0, -10, 5, 2, + -3, 0, -6, 7, -4, -3, 6, -1, -6, -1, -1, 2, -2, -6, -3, 0, + 8, -6, 4, -1, -5, -3, 3, 1, -5, -6, -2, -3, 5, 6, 0, 7, + -3, 3, -1, 0, -2, 9, 1, 1, -3, 4, 5, -5, 2, -2, 2, -11, + -2, -4, 11, 4, 5, 0, -5, -12, -6, -5, -5, 3, -2, -2, 2, 2, + 1, 0, -1, -8, -5, -5, -3, 2, -1, 3, -1, 3, 0, -1, 0, -1, + 1, 1, -4, -4, 2, -2, 1, -6, 1, 2, 4, 2, 2, -5, -1, 6, + -3, -1, -4, 11, 3, -9, -2, -6, -3, 2, 4, 2, 1, 2, 4, 3, + -6, -4, -3, -2, 0, 2, -2, 5, 2, -1, 3, -9, -3, -3, -4, -4, + -1, 0, -2, 7, 3, 1, 1, -2, -4, -2, -3, -2, -4, 2, 4, -1, + 2, 3, 0, 3, -1, 0, -2, -2, -3, 1, -1, -4, 5, -1, 5, 0, + -3, -2, -1, -4, 3, -1, -3, -2, -2, -1, 0, 0, 1, -1, 0, -2, + -2, 0, -3, -1, 0, 0, 1, 1, -2, -1, 1, -3, 1, 2, 0, -1, + 0, -1, 1, 5, -2, 1, -3, -3, -1, -3, 0, 1, 3, 2, -1, -1, + -2, -2, -1, 1, 0, -1, -2, -2, -2, -3, -3, -3, -2, -2, -2, -2, + -2, -2, -2, -1, 0, 1, 1, -2, -2, 0, 0, 2, -3, -16, -22, -20, + -28, -35, -31, -17, 19, 33, 36, 33, 34, 40, 36, 25, 18, 20, 18, 14, + 17, 12, 14, 10, -24, -36, -27, -38, -55, -69, -66, -47, -33, -13, 3, 5, + 10, 22, 25, 15, 28, 43, 41, 51, 56, 58, 58, 31, -18, -52, -64, -71, + -92, -105, -98, -77, -50, -17, 23, 59, 85, 99, 94, 76, 55, 14, -9, -5, + -7, -18, -17, -35, -53, -53, -33, -23, -33, -36, -15, 17, 32, 24, 12, 19, + 37, 54, 49, 38, 21, -14, -44, -30, -22, -15, 5, 8, -1, -26, -42, -46, + -49, -51, -37, -17, 1, -4, -19, -4, 45, 84, 91, 79, 57, 3, -30, -29, + -35, -25, -8, -6, -26, -61, -75, -73, -77, -72, -54, -19, 9, 6, -10, 3, + 47, 85, 92, 103, 92, 45, 21, 6, 4, 16, 27, 27, -1, -48, -69, -78, + -80, -84, -72, -33, -10, -24, -41, -20, 40, 82, 99, 123, 102, 69, 49, 30, + 27, 34, 42, 41, -2, -58, -96, -108, -103, -106, -83, -37, -10, -18, -38, -18, + 40, 65, 92, 110, 84, 44, 1, -26, -23, -7, 21, 32, 7, -39, -78, -84, + -79, -82, -61, -19, 5, -14, -52, -25, 25, 59, 102, 127, 116, 86, 40, 13, + 4, 9, 27, 29, 4, -47, -88, -94, -87, -83, -56, -18, 15, -13, -49, -30, + -2, 29, 69, 87, 80, 50, 9, -15, -27, -10, 18, 44, 36, -9, -45, -53, + -53, -46, -33, 6, 31, -8, -36, -28, -11, 21, 54, 76, 76, 44, 4, -33, + -53, -45, -18, 13, 10, -35, -62, -70, -61, -44, -19, 38, 63, 30, 9, 4, + 9, 35, 60, 81, 75, 51, 14, -25, -44, -37, -9, 29, 24, -11, -41, -59, + -51, -54, -33, 23, 35, 6, -13, -28, -18, 8, 43, 73, 76, 63, 33, -1, + -21, -22, 10, 43, 35, 5, -32, -47, -51, -68, -44, 6, 14, 0, -21, -34, + -25, 0, 37, 65, 73, 64, 35, 5, -22, -25, 11, 40, 39, 13, -20, -28, + -42, -64, -32, 6, 15, -1, -25, -39, -39, -16, 19, 44, 58, 53, 27, -2, + -39, -38, -2, 30, 40, 13, -16, -19, -45, -60, -29, 6, 17, 1, -21, -40, + -44, -24, 9, 38, 58, 51, 38, 8, -31, -29, 0, 34, 44, 9, -11, -23, + -58, -69, -42, -6, 9, 0, -16, -33, -36, -12, 19, 55, 72, 68, 58, 18, + -22, -25, -6, 29, 31, 2, -5, -23, -57, -69, -45, -8, 12, 10, 0, -22, + -24, -7, 20, 52, 61, 65, 59, 21, -15, -28, -11, 26, 20, 2, -2, -22, + -56, -71, -49, -14, 3, 8, -5, -26, -28, -19, 14, 42, 54, 71, 67, 38, + 8, -11, 16, 47, 37, 26, 18, -10, -51, -74, -59, -35, -19, -12, -24, -37, + -44, -34, 0, 24, 44, 67, 64, 43, 3, -18, 11, 35, 28, 22, 18, -4, + -47, -68, -55, -34, -11, -7, -15, -27, -43, -32, -1, 18, 42, 58, 60, 43, + -8, -29, -6, 11, 7, 4, 4, -17, -59, -75, -66, -41, -13, -3, 1, -11, + -29, -19, 1, 19, 42, 53, 64, 45, -8, -28, -9, 7, 4, 4, 9, -13, + -51, -71, -69, -43, -19, -7, 3, -11, -25, -17, -2, 23, 43, 60, 78, 55, + 1, -19, -5, 8, 3, 7, 13, -8, -41, -66, -67, -40, -19, 3, 16, 1, + -7, -5, 10, 34, 46, 67, 87, 62, 11, -13, -1, 8, 4, 15, 20, 1, + -33, -64, -65, -48, -30, -2, 6, -5, -14, -18, 1, 21, 32, 62, 86, 66, + 20, -3, 6, 7, 5, 16, 20, 7, -29, -62, -65, -59, -39, -13, -5, -8, + -22, -27, -6, 7, 17, 49, 74, 58, 14, -5, -2, -4, -3, 7, 14, 6, + -32, -59, -66, -63, -40, -16, -2, -2, -19, -20, -1, 6, 18, 49, 77, 62, + 21, 3, -1, -5, -2, 5, 18, 10, -26, -50, -65, -64, -43, -24, -5, -6, + -24, -23, -8, -2, 10, 45, 75, 60, 25, 6, -4, -4, -5, 3, 20, 8, + -20, -43, -60, -58, -45, -24, 1, -1, -15, -12, -1, 3, 16, 53, 83, 70, + 42, 19, 9, 7, 3, 16, 29, 17, -7, -35, -55, -56, -49, -24, 2, -1, + -11, -7, 3, 4, 16, 55, 83, 75, 50, 25, 15, 6, 0, 13, 21, 13, + -9, -40, -58, -66, -62, -35, -11, -11, -18, -13, -3, -7, 9, 49, 75, 74, + 51, 28, 19, 5, 1, 13, 20, 16, -3, -28, -48, -62, -61, -37, -16, -13, + -20, -15, -12, -19, -5, 21, 50, 61, 47, 28, 15, -1, -6, 0, 9, 14, + 1, -19, -37, -55, -56, -38, -16, -11, -13, -9, -9, -16, -8, 18, 48, 59, + 44, 28, 9, 15, -3, 2, -5, 3, 3, 4, 1, 7, -2, 7, -4, 2, + -124, -37, 33, -48, 7, -27, 8, -14, 77, 26, -9, 26, 7, 20, 10, 13, + 8, 9, 7, 4, 5, 2, 3, 2, 1, -1, 0, -3, -2, -5, 1, -10, + 11, 70, -6, 21, 5, 27, -2, 41, -15, -61, -66, -128, 0, -48, -21, -46, + -6, -55, 23, 53, -6, 11, 2, 14, 11, 10, 11, 8, 9, 9, 8, 5, + 8, 5, 6, 5, 6, 2, 7, -4, 6, 5, -23, 62, 29, 24, 8, 33, + 4, 32, 36, -30, -16, -124, -58, -39, -18, -51, -3, -43, -40, 53, 19, 12, + 4, 9, 12, 13, 10, 11, 9, 8, 11, 6, 5, 8, 6, 3, 9, 1, + 7, 2, -5, 22, -33, 20, 37, 35, 7, 29, 14, 8, 52, -5, 17, -64, + -84, -70, -15, -55, -23, -12, -72, 1, 28, 16, 8, 6, 7, 12, 10, 8, + 11, 6, 8, 10, 5, 4, 10, 1, 8, 4, 2, 10, -15, 26, -16, -9, + 14, 42, 17, 19, 29, -3, 42, 14, 28, -8, -45, -92, -37, -41, -54, 0, + -53, -48, 2, 18, 10, 8, 4, 8, 12, 8, 10, 10, 6, 9, 10, 2, + 10, 5, 3, 9, -2, 18, -16, 17, 3, -9, -12, 26, 28, 13, 35, 3, + 27, 19, 31, 17, 4, -60, -67, -33, -66, -22, -22, -58, -38, 2, 11, 9, + 7, 4, 9, 10, 8, 10, 9, 5, 12, 5, 5, 9, 2, 11, -5, 21, + -8, 4, 10, 5, -17, -1, 28, 11, 34, 13, 20, 17, 28, 24, 27, -6, + -61, -41, -57, -51, -17, -36, -56, -32, -1, 7, 8, 5, 6, 8, 10, 8, + 12, 6, 9, 9, 5, 9, 1, 15, -7, 15, 5, -2, 4, 14, -3, -18, + 15, 8, 28, 21, 20, 16, 23, 23, 29, 30, -20, -38, -45, -63, -38, -23, + -43, -53, -29, -5, 5, 5, 5, 5, 9, 7, 11, 8, 8, 10, 5, 12, + -2, 16, -1, 4, 11, 4, -3, 8, 15, -16, 0, 1, 16, 23, 23, 17, + 20, 21, 21, 39, 19, -14, -28, -52, -58, -33, -28, -47, -50, -30, -6, 2, + 5, 4, 6, 6, 9, 10, 7, 12, 3, 15, 0, 10, 8, 1, 6, 11, + 2, -4, 20, -1, -6, -5, 4, 15, 24, 20, 18, 23, 15, 30, 38, 13, + -6, -27, -56, -52, -30, -34, -48, -50, -28, -8, 2, 3, 5, 5, 6, 11, + 5, 13, 3, 12, 6, 5, 10, 5, 2, 7, 13, -8, 10, 11, 0, -6, + -4, 3, 17, 23, 16, 24, 18, 17, 36, 32, 13, -1, -30, -57, -45, -31, + -36, -51, -49, -28, -7, -1, 3, 6, 2, 11, 5, 12, 6, 9, 10, 5, + 8, 8, 5, -1, 16, 1, -1, 11, 9, -1, -5, -5, 4, 20, 17, 20, + 24, 14, 23, 37, 29, 16, 2, -33, -53, -42, -30, -39, -52, -49, -27, -9, + -3, 5, 0, 8, 5, 10, 8, 6, 10, 6, 7, 6, 11, -3, 8, 11, + 0, 2, 11, 8, -1, -5, -7, 9, 18, 16, 24, 20, 14, 27, 35, 27, + 21, 1, -33, -50, -38, -32, -42, -53, -48, -25, -14, -1, -2, 4, 3, 6, + 9, 5, 9, 7, 7, 4, 12, 4, 1, 10, 6, 2, 6, 10, 4, 0, + -6, -2, 11, 14, 18, 22, 17, 20, 32, 34, 28, 20, 0, -26, -36, -34, + -37, -45, -54, -44, -30, -13, -8, -3, 1, 2, 6, 4, 7, 8, 8, 2, + 8, 10, 1, 4, 6, 5, 5, 9, 6, 1, -3, -5, 3, 10, 14, 18, + 18, 17, 26, 35, 35, 29, 17, -1, -17, -24, -32, -41, -50, -51, -44, -28, + -18, -12, -5, -2, 2, 3, 3, 6, 9, 4, 3, 9, 6, 2, 2, 4, + 5, 9, 10, 4, -2, -5, -1, 5, 10, 14, 16, 15, 19, 30, 38, 37, + 29, 15, 1, -5, -14, -31, -43, -50, -52, -42, -29, -22, -16, -9, -3, 0, + 0, 2, 6, 6, 2, 4, 7, 6, 2, 1, 2, 6, 11, 10, 2, -5, + -4, 0, 5, 10, 14, 15, 14, 21, 32, 39, 38, 29, 14, 4, 0, -3, + -19, -32, -40, -43, -41, -36, -31, -25, -19, -12, -9, -8, -6, -1, 2, 2, + 0, -3, -4, -1, 3, 6, 6, 2, -3, -6, -2, 2, 2, 1, 2, 7, + 16, 25, 32, 35, 35, 36, 36, 33, 24, 11, -3, -18, -32, -40, -42, -40, + -36, -30, -25, -18, -12, -9, -8, -5, -1, 2, 2, 0, -3, -4, -1, 3, + 7, 6, 2, -4, -5, -2, 2, 2, 1, 2, 8, 17, 25, 32, 35, 36, + 36, 36, 32, 23, 10, -4, -20, -33, -41, -42, -40, -35, -30, -24, -18, -12, + -9, -8, -5, -1, 3, 2, -1, -4, -4, -1, 4, 7, 6, 1, -4, -5, + -2, -1, 3, 1, 3, 5, 3, -3, -1, -1, 1, -15, 1, 1, -5, -7, + 7, -2, -4, 3, -2, -5, -1, -3, -3, -1, 6, 3, 2, 3, -26, -117, + 35, -8, -19, 24, 58, -7, -6, 25, -9, 7, 4, 10, 2, 7, 6, 6, + 0, 6, -2, -1, -3, -3, 8, 71, 0, 17, 27, 20, -102, -115, 39, -32, + -18, -5, 58, -15, -12, 13, -10, -4, 1, 2, 1, 0, 6, 2, 1, 2, + 0, -4, 0, -5, 2, 67, 9, 14, 28, 29, -72, -126, 27, -25, -19, -14, + 58, -6, -11, 13, -5, -3, 3, 3, 4, 1, 8, 3, 3, 3, 3, -2, + 2, -3, -3, 62, 17, 14, 27, 35, -45, -128, 11, -19, -20, -22, 53, 1, + -12, 11, -3, -4, 2, 3, 4, 1, 7, 3, 3, 3, 3, -2, 2, -2, + -9, 57, 22, 14, 25, 37, -23, -125, -8, -15, -20, -30, 46, 9, -12, 10, + -2, -3, 0, 3, 3, 1, 6, 4, 2, 3, 2, -2, 1, 0, -16, 50, + 26, 13, 22, 37, -2, -117, -27, -13, -18, -36, 36, 16, -13, 9, -2, -2, + -2, 3, 2, 2, 4, 5, 1, 4, 2, -1, 0, 4, -20, 43, 29, 15, + 20, 36, 14, -102, -43, -15, -16, -40, 26, 22, -12, 8, -2, -2, -3, 3, + 1, 3, 2, 6, 1, 5, 1, 0, -1, 7, -23, 35, 31, 18, 18, 33, + 27, -83, -57, -20, -14, -42, 14, 26, -9, 7, -2, 0, -5, 3, 1, 4, + 1, 7, 0, 5, 1, 1, -2, 10, -24, 26, 31, 20, 17, 30, 36, -62, + -65, -27, -12, -43, 2, 28, -7, 6, -2, 0, -5, 3, 0, 4, 0, 7, + 0, 5, 1, 2, -4, 11, -23, 17, 32, 22, 16, 27, 42, -44, -67, -36, + -9, -42, -8, 28, -3, 5, -1, 1, -5, 2, 0, 4, 1, 7, 1, 5, + 1, 3, -5, 13, -22, 10, 31, 23, 17, 22, 45, -25, -66, -45, -8, -40, + -18, 27, 0, 5, -1, 1, -5, 1, 0, 4, 0, 6, 2, 4, 2, 3, + -6, 14, -19, 2, 29, 25, 19, 19, 47, -10, -60, -54, -10, -37, -27, 24, + 4, 4, 0, 1, -5, 0, 0, 3, 1, 5, 2, 4, 2, 4, -7, 15, + -16, -4, 27, 25, 21, 15, 48, 4, -51, -61, -12, -33, -34, 19, 7, 4, + 1, 0, -4, -1, 0, 3, 2, 5, 3, 3, 3, 5, -8, 15, -11, -10, + 24, 25, 23, 12, 45, 15, -39, -66, -18, -28, -40, 12, 10, 4, 2, 1, + -3, -2, 0, 2, 2, 4, 3, 3, 3, 5, -8, 13, -6, -14, 19, 25, + 25, 10, 43, 24, -25, -67, -25, -24, -45, 4, 11, 5, 3, 0, -2, -3, + -1, 1, 2, 3, 3, 3, 2, 6, -9, 11, -2, -17, 15, 24, 27, 9, + 39, 31, -13, -66, -33, -19, -48, -3, 11, 5, 3, 1, -2, -3, -1, 1, + 2, 4, 3, 3, 2, 8, -9, 9, 3, -18, 10, 22, 29, 9, 35, 35, + 0, -61, -41, -17, -49, -11, 10, 6, 3, 2, -2, -3, -2, 1, 1, 4, + 3, 5, 1, 9, -9, 7, 6, -18, 5, 20, 29, 10, 32, 38, 11, -47, + -45, -18, -47, -20, 5, 6, 4, 2, -1, -3, -2, 0, 1, 5, 1, 6, + 1, 7, -7, 6, 6, -16, 1, 16, 27, 11, 29, 40, 20, -30, -43, -23, + -46, -28, -2, 4, 4, 2, -1, -3, -2, -1, 0, 6, -1, 7, 2, 5, + -6, 5, 6, -15, -3, 13, 25, 12, 26, 41, 26, -14, -36, -26, -44, -35, + -11, 1, 4, 2, 0, -4, -3, -3, -1, 7, -2, 7, 4, 4, -6, 4, + 7, -13, -6, 10, 23, 12, 24, 42, 31, 0, -24, -28, -42, -40, -19, -4, + 4, 2, 1, -4, -3, -4, -3, 8, -3, 6, 6, 3, -6, 4, 7, -11, + -8, 7, 20, 12, 21, 41, 34, -2, -31, -34, -29, -21, -12, -3, -4, -10, + -7, -5, -6, -4, 5, 8, -3, -1, 7, -1, -11, -7, 0, 1, 6, 16, + 28, 33, 33, 30, 13, -1, -26, -35, -30, -24, -14, -5, -4, -11, -7, -5, + -6, -6, 3, 8, -2, -2, 7, 1, -11, -9, -1, 0, 4, 14, 26, 32, + 33, 32, 17, 3, -22, -34, -31, -25, -16, -6, -3, -10, -8, -5, -6, -7, + 2, 9, 0, -3, 6, 3, -9, -10, -2, 0, 3, 12, 24, 32, -1, 0, + -3, -1, -8, -5, -16, -5, -14, -4, -13, -5, -1, -7, 16, -17, 28, -16, + 47, 1, 70, 35, 97, 71, 98, 66, 32, -5, -71, -69, -122, -69, -105, -33, + -67, -6, -35, 2, -12, -2, 4, -12, 16, -19, 29, -16, 44, 2, 66, 37, + 92, 76, 95, 74, 33, 5, -69, -63, -122, -69, -106, -36, -66, -11, -33, -3, + -9, -7, 7, -16, 18, -22, 29, -17, 42, 3, 61, 40, 86, 81, 91, 82, + 34, 15, -67, -57, -122, -69, -105, -40, -64, -17, -29, -9, -6, -12, 10, -20, + 20, -23, 28, -17, 39, 4, 56, 42, 80, 85, 88, 89, 35, 24, -63, -53, + -119, -70, -104, -45, -62, -22, -26, -14, -2, -16, 12, -23, 20, -25, 27, -16, + 35, 7, 51, 45, 74, 89, 85, 96, 38, 32, -58, -49, -116, -72, -102, -50, + -60, -27, -24, -19, 0, -20, 14, -24, 20, -24, 24, -14, 31, 10, 45, 48, + 69, 92, 82, 102, 40, 39, -53, -45, -112, -74, -100, -55, -57, -33, -21, -24, + 3, -24, 15, -26, 19, -24, 22, -12, 27, 12, 40, 50, 63, 95, 80, 106, + 43, 45, -47, -42, -107, -76, -97, -60, -55, -38, -18, -28, 4, -26, 15, -27, + 18, -23, 19, -10, 23, 15, 35, 53, 59, 97, 78, 110, 47, 50, -39, -39, + -102, -79, -94, -65, -52, -43, -16, -32, 5, -28, 14, -27, 16, -21, 15, -7, + 18, 18, 30, 55, 54, 98, 76, 113, 51, 55, -32, -37, -96, -81, -91, -70, + -50, -48, -15, -35, 6, -30, 13, -26, 13, -19, 11, -5, 13, 20, 25, 56, + 50, 99, 75, 115, 56, 59, -24, -35, -90, -83, -88, -75, -48, -52, -14, -38, + 5, -30, 11, -25, 10, -17, 7, -2, 9, 22, 21, 57, 47, 99, 75, 116, + 61, 62, -15, -33, -82, -86, -84, -80, -47, -56, -14, -39, 4, -30, 9, -24, + 6, -15, 3, 1, 5, 24, 17, 57, 44, 98, 75, 116, 66, 65, -6, -31, + -75, -88, -81, -83, -46, -59, -14, -41, 3, -30, 6, -22, 3, -12, -1, 3, + 1, 26, 13, 57, 41, 96, 75, 115, 72, 68, 2, -29, -69, -89, -78, -87, + -45, -62, -15, -42, 0, -29, 3, -20, -1, -10, -5, 5, -2, 26, 11, 56, + 40, 94, 76, 114, 77, 69, 12, -28, -61, -91, -75, -89, -45, -64, -16, -42, + -2, -28, 0, -18, -5, -8, -9, 7, -6, 27, 8, 55, 38, 91, 77, 112, + 82, 71, 20, -25, -55, -91, -73, -91, -46, -65, -18, -42, -5, -26, -4, -15, + -10, -5, -13, 9, -9, 27, 7, 53, 37, 88, 78, 110, 87, 72, 29, -23, + -48, -90, -71, -93, -47, -66, -21, -41, -9, -24, -8, -13, -13, -3, -16, 9, + -11, 27, 5, 51, 37, 84, 79, 108, 93, 74, 37, -20, -42, -90, -70, -94, + -49, -66, -24, -40, -12, -23, -12, -12, -16, -2, -18, 10, -12, 25, 5, 48, + 37, 80, 81, 105, 98, 75, 45, -16, -36, -88, -68, -94, -51, -66, -28, -39, + -16, -21, -15, -10, -19, -1, -21, 10, -13, 24, 4, 45, 37, 76, 82, 102, + 102, 76, 52, -13, -30, -85, -67, -94, -54, -66, -31, -38, -20, -19, -19, -9, + -22, 0, -22, 9, -14, 22, 4, 41, 37, 71, 83, 99, 105, 77, 59, -8, + -25, -82, -67, -93, -56, -65, -35, -37, -23, -18, -22, -7, -25, 0, -24, 8, + -14, 20, 5, 37, 38, 67, 84, 96, 108, 79, 65, -3, -20, -79, -66, -92, + -59, -65, -39, -36, -27, -17, -25, -7, -27, -1, -24, 6, -14, 17, 6, 34, + 39, 63, 84, 93, 111, 80, 71, 1, -15, -75, -66, -90, -62, -64, -43, -35, + -31, -16, -28, -6, -28, -1, -25, 5, -14, 14, 6, 30, 39, 58, 85, 90, + 113, 82, 76, 7, -11, -70, -66, -88, -66, -62, -46, -34, -34, -15, -30, -7, + -30, -2, -25, 2, -13, 11, 7, 26, 40, 53, 84, 87, 115, 84, 81, 13, + -7, -65, -66, -85, -68, -61, -50, -33, -37, -15, -32, -7, -30, -4, -25, 0, + -12, 7, 9, 19, 37, 52, 80, 97, 118, 113, 98, 54, 7, -41, -72, -87, + -87, -75, -65, -47, -42, -29, -30, -22, -24, -19, -19, -14, -9, -2, 8, 17, + 36, 50, 77, 95, 117, 115, 101, 60, 13, -35, -69, -85, -88, -75, -66, -49, + -44, -31, -31, -23, -25, -20, -20, -15, -9, -2, -1, 0, 0, 0, 0, -1, + -1, -1, 3, 9, 14, 14, 10, -3, -17, -13, 1, 1, 23, 33, -14, -55, + -59, -80, -75, -35, -7, 51, 40, -29, -35, -53, -128, -31, 111, 72, 46, 55, + -19, -73, -23, 14, 64, 104, 87, 105, 68, -54, -76, -1, -18, 12, 92, 23, + -79, -93, -105, -119, -64, -20, 39, 70, 2, -45, -52, -107, -82, 73, 106, 56, + 53, 12, -57, -37, 14, 52, 105, 101, 94, 85, -5, -75, -25, -1, -8, 59, + 52, -45, -89, -94, -117, -90, -42, 1, 53, 29, -29, -45, -79, -104, 3, 99, + 78, 63, 42, -25, -49, -7, 30, 83, 112, 103, 99, 40, -54, -58, -11, -7, + 36, 68, -4, -80, -98, -114, -106, -57, -15, 33, 42, -10, -46, -66, -97, -45, + 68, 90, 67, 53, 4, -40, -20, 18, 60, 103, 107, 100, 69, -15, -62, -31, + -9, 15, 60, 31, -50, -90, -108, -115, -79, -33, 11, 42, 15, -33, -58, -87, + -75, 21, 87, 79, 63, 27, -26, -33, 1, 40, 88, 111, 105, 85, 20, -50, + -49, -17, 5, 46, 49, -17, -77, -102, -115, -95, -49, -7, 31, 28, -15, -50, + -76, -84, -21, 64, 84, 71, 45, -4, -32, -13, 22, 66, 103, 108, 95, 50, + -23, -56, -32, -5, 30, 55, 14, -53, -92, -111, -107, -68, -24, 16, 34, 4, + -37, -66, -85, -53, 32, 81, 77, 58, 17, -25, -24, 6, 46, 89, 108, 101, + 71, 6, -49, -45, -16, 15, 49, 36, -26, -77, -103, -110, -85, -41, 0, 30, + 20, -21, -55, -79, -72, -5, 65, 81, 67, 36, -10, -28, -8, 27, 71, 102, + 104, 85, 34, -31, -51, -29, 1, 37, 48, 2, -57, -93, -109, -97, -58, -16, + 20, 28, -4, -42, -70, -79, -36, 39, 78, 74, 51, 9, -24, -18, 11, 51, + 91, 105, 94, 57, -6, -48, -41, -12, 22, 48, 26, -33, -79, -103, -104, -74, + -32, 6, 28, 12, -27, -60, -78, -59, 8, 66, 78, 62, 27, -13, -24, -3, + 33, 74, 100, 99, 74, 20, -35, -48, -25, 8, 40, 40, -7, -61, -94, -106, + -88, -49, -9, 21, 21, -11, -47, -72, -71, -22, 45, 76, 71, 43, 2, -22, + -13, 16, 56, 91, 101, 85, 43, -15, -47, -36, -6, 28, 45, 16, -38, -80, + -102, -97, -65, -24, 11, 25, 4, -33, -63, -75, -46, 18, 66, 75, 56, 19, + -15, -20, 2, 38, 77, 98, 93, 62, 8, -38, -44, -20, 14, 41, 32, -15, + -64, -94, -101, -79, -40, -2, 22, 15, -17, -52, -72, -61, -9, 49, 74, 66, + 36, -2, -21, -9, 22, 61, 91, 96, 76, 31, -22, -45, -32, 0, 32, 40, + 7, -43, -82, -99, -89, -56, -17, 14, 21, -2, -38, -65, -69, -33, 26, 66, + 71, 50, 13, -16, -16, 7, 43, 79, 95, 85, 50, -2, -40, -40, -14, 20, + 40, 24, -22, -66, -93, -95, -70, -32, 3, 21, 9, -23, -55, -70, -51, 1, + 52, 71, 60, 28, -6, -19, -4, 27, 64, 90, 91, 66, 19, -27, -43, -26, + 6, 34, 35, -1, -48, -83, -96, -81, -47, -10, 16, 17, -9, -43, -66, -62, + -22, 33, 66, 67, 43, 7, -16, -13, 12, 48, 80, 91, 77, 39, -10, -40, + -36, -8, 24, 38, 17, -28, -69, -92, -89, -62, -25, 7, 19, 4, -29, -58, + -67, -42, 10, 55, 70, 55, 22, -9, -17, 0, 33, 68, 90, 86, 57, 10, + -31, -41, -21, 12, 36, 30, -8, -53, -85, -94, -75, -41, -5, 17, 13, -15, + -48, -67, -57, -13, 39, 68, 64, 37, 3, -16, -9, 18, 54, 84, 91, 72, + 30, -17, -41, -33, -2, 28, 37, 10, -35, -74, -94, -86, -56, -19, 10, 17, + -2, -36, -63, -66, -34, 19, 60, 70, 51, 17, -11, -15, 5, 39, 74, 92, + 83, 49, 1, -36, -40, -16, 18, 37, 24, -17, -61, -90, -93, -70, -34, 1, + 18, 8, -22, -55, -69, -50, -2, 47, 70, 61, 31, -3, -17, -5, 26, 62, + 88, 90, 65, 19, -25, -42, -27, 5, 33, 33, 1, -45, -81, -95, -81, -48, + -11, 14, 15, -10, -43, -66, -61, -22, 31, 65, 68, 43, 9, -14, -11, 12, + 49, 80, 92, 76, 38, -10, -39, -36, -8, 24, 38, 16, -27, -70, -92, -89, + -61, -25, 7, 17, 3, -31, -59, -68, -39, 8, 55, 55, 19, 0, -9, -10, + -14, -13, -21, -30, -32, -44, -49, -57, -65, -72, -83, -98, -104, -117, -123, -128, + -127, -128, -128, -128, -128, -127, -128, -120, -117, -109, -100, -90, -83, -72, -66, -55, + -50, -33, -42, -18, -29, -18, 15, -6, 11, 7, 19, 3, 38, 5, 48, 44, + 64, 57, 97, 82, 111, 104, 110, 107, 120, 116, 125, 126, 126, 126, 126, 127, + 117, 125, 123, 100, 127, 101, 124, 102, 121, 109, 126, 96, 125, 116, 127, 90, + 119, 87, 127, 90, 118, 95, 123, 93, 106, 90, 100, 104, 74, 84, 73, 97, + 72, 71, 57, 66, 80, 36, 59, 38, 55, 35, 57, -6, 64, 10, 25, 19, + 19, -22, 65, -26, 14, 2, -17, -12, 22, -40, -3, -31, -24, -38, -1, -56, + -6, -48, -36, -54, -19, -56, -33, -49, -69, -49, -52, -53, -60, -61, -84, -76, + -85, -96, -95, -95, -114, -93, -117, -104, -93, -101, -98, -100, -101, -96, -78, -95, + -71, -70, -72, -52, -63, -70, -43, -77, -41, -48, -65, -53, -53, -59, -42, -56, + -37, -64, -54, -52, -50, -54, -56, -54, -55, -62, -51, -47, -44, -67, -60, -63, + -56, -64, -53, -48, -61, -53, -58, -38, -48, -32, -38, -34, -28, -26, -23, -25, + -22, -6, -7, -12, -1, 5, 6, 6, -7, 22, -4, 27, 15, 18, 24, 37, + 30, 47, 24, 53, 29, 63, 29, 46, 46, 51, 52, 53, 36, 54, 65, 55, + 33, 64, 36, 69, 54, 26, 62, 66, 36, 68, 30, 47, 54, 58, 20, 55, + 31, 40, 50, 35, 19, 56, 33, 25, 46, 18, 22, 42, 21, 25, 32, 19, + 19, 26, 18, 23, 29, 24, 7, 27, 6, 33, 8, 17, -2, 14, 3, 23, + 14, 7, 5, -9, -13, -10, -23, -12, -16, -27, -8, -18, -15, -3, -18, -24, + -5, -23, -9, 0, -11, 4, -1, 4, 2, 5, -2, 3, -1, -7, 4, -11, + 1, -12, -4, -7, -10, -11, -11, -16, -23, -15, -20, -22, -23, -20, -30, -23, + -31, -25, -32, -35, -41, -34, -44, -39, -34, -49, -33, -30, -36, -29, -33, -14, + -24, -32, -18, -15, -7, -9, -11, 5, -14, 27, -11, 16, -10, 13, -9, 23, + -10, 19, 10, 18, 11, 29, 1, 47, 27, -4, 45, 3, 43, 40, 14, 13, + 57, 16, 34, 27, 22, 30, 32, 14, 24, 27, 20, 20, 17, 4, 20, 20, + 8, 8, 0, 10, -3, 17, -8, -1, -4, 1, 0, 6, -7, -3, -3, -13, + -5, -6, -18, -5, -28, -12, -13, -5, -11, -5, -28, -7, -15, -10, -6, -28, + -16, -12, -17, -8, -10, -19, -10, -24, -30, -32, -26, -31, -36, -32, -33, -27, + -25, -26, -26, -25, -25, -23, -16, -22, -10, -11, -7, -7, 4, -10, 10, -9, + 11, -8, 4, -6, 4, -8, 3, -4, 2, -3, -5, -3, -11, -8, -6, -12, + -11, -7, -24, -4, -17, -9, -18, -28, -16, -29, -23, -38, -24, -34, -22, -38, + -18, -27, -10, -22, -19, -21, -2, -23, 10, -19, 0, 4, 16, 7, 0, 3, + 17, 14, 26, 8, 25, 27, 30, 25, 38, 31, 49, 37, 42, 45, 48, 55, + 63, 46, 54, 54, 56, 59, 56, 47, 50, 53, 47, 50, 44, 42, 35, 40, + 31, 37, 35, 27, 20, 23, 19, 26, 24, 18, 11, 14, 18, 24, 18, 12, + 10, 3, 12, 2, 9, 4, 0, 0, 3, -4, 11, 1, 1, -1, -5, -7, + 1, -6, -1, 2, -4, 1, -1, -7, -9, -11, -21, -19, -20, -28, -27, -22, + -29, -24, -26, -32, -22, -25, -31, -24, -19, -22, -11, -19, -15, -4, -5, -4, + 0, -6, -6, 2, -9, -5, -5, -9, -10, -7, -18, -8, -14, -14, -19, -29, + -25, -16, -25, -30, -30, -30, -21, -29, -38, -37, -36, -41, -44, -53, -48, -43, + -44, -55, -46, -40, -33, -36, -40, -40, -28, -25, -24, -23, -17, -15, 1, -3, + -1, 5, 2, 9, 1, 4, 12, 13, 14, 15, 9, 21, 26, 32, 31, 28, + 28, 41, 38, 49, 45, 46, 53, 56, 57, 57, 57, 58, 55, 48, 56, 56, + 56, 45, 39, 41, 41, 44, 42, 25, 28, 27, 24, 28, 21, 14, 17, 8, + 15, 22, 13, 15, 16, 3, 11, 10, 4, 6, 4, -8, 0, -2, -2, -3, + -2, 1, 3, -3, -3, -6, -8, -5, 4, 3, 2, -4, -2, -1, 5, 3, + -2, -2, -2, 3, 7, -2, -26, -37, -34, -30, -13, -14, -21, -24, -27, -24, + -13, -7, -15, 6, 3, -30, -50, -48, -47, -41, -26, -8, 28, 43, 38, 57, + 63, 56, 75, 118, 127, 117, 99, 86, 85, 66, 46, 59, 80, 69, 43, 27, + -6, -47, -74, -80, -71, -57, -40, -44, -56, -78, -88, -78, -59, -52, -51, -56, + -57, -47, -36, -36, -39, -39, -32, -17, 6, 24, 33, 10, -14, -14, -2, -11, + -20, -15, -24, -28, -28, -25, -28, -54, -73, -65, -43, -18, 6, 27, 21, 23, + 17, 22, 18, 16, 31, 50, 45, 25, 22, 8, -20, -17, 8, 29, 10, -22, + -41, -45, -51, -53, -31, -18, -23, -7, 37, 54, 38, 36, 60, 100, 119, 120, + 122, 125, 110, 88, 94, 99, 90, 85, 82, 54, 26, -5, -49, -83, -85, -67, + -36, -14, -30, -55, -76, -86, -65, -41, -45, -60, -53, -43, -35, -34, -41, -43, + -45, -35, 10, 40, 32, 3, -3, -14, -30, -38, -33, -23, -29, -26, -18, -10, + -17, -37, -46, -58, -61, -45, -17, -4, -2, 19, 31, 27, 13, 22, 38, 49, + 59, 69, 60, 23, -13, -11, 13, 24, 19, 24, 8, -30, -58, -58, -66, -85, + -90, -61, -19, -1, -11, -5, 25, 42, 61, 92, 109, 106, 110, 104, 93, 93, + 89, 82, 86, 81, 71, 51, 13, -40, -74, -87, -73, -35, -24, -50, -71, -73, + -53, -50, -58, -68, -60, -61, -54, -30, -25, -40, -52, -25, 13, 32, 45, 49, + 44, 28, 22, 29, 32, 20, 3, 7, 6, 0, -1, -4, -30, -63, -69, -62, + -57, -49, -25, 2, 17, 24, 27, 30, 10, 4, 38, 77, 66, 32, 13, 7, + 0, 9, 31, 43, 23, -11, -25, -23, -46, -83, -87, -63, -42, -19, -6, -3, + 6, 27, 49, 81, 108, 121, 123, 124, 115, 110, 98, 80, 78, 77, 77, 69, + 54, 8, -56, -99, -92, -53, -46, -64, -75, -73, -70, -75, -62, -67, -86, -88, + -54, -28, -33, -46, -50, -40, -24, -3, 29, 51, 48, 34, 44, 44, 30, 18, + 13, -3, -15, -7, -1, -10, -36, -56, -65, -79, -100, -91, -64, -52, -40, -5, + 20, 9, -14, -9, 21, 49, 59, 58, 49, 25, -1, 11, 39, 39, 22, 19, + 20, 8, -19, -49, -72, -69, -58, -43, -27, -24, -13, -5, 12, 38, 74, 97, + 110, 124, 126, 126, 114, 105, 100, 87, 91, 108, 115, 73, 5, -41, -49, -49, + -53, -45, -49, -69, -77, -60, -51, -71, -94, -96, -68, -49, -46, -44, -45, -60, + -60, -27, 0, 11, 26, 37, 37, 37, 40, 42, 34, 8, -1, 14, 15, -5, + -12, -18, -44, -75, -85, -88, -98, -99, -76, -36, -12, -19, -24, -11, -9, 1, + 36, 71, 58, 29, 13, 17, 33, 33, 30, 35, 44, 44, 27, -3, -39, -51, + -61, -55, -41, -31, -25, -29, -21, -1, 23, 46, 76, 102, 109, 110, 116, 118, + 92, 61, 76, 112, 120, 93, 57, 14, -28, -54, -50, -46, -60, -83, -82, -64, + -62, -82, -89, -93, -101, -88, -59, -52, -64, -75, -76, -63, -50, -30, -1, 9, + 8, 11, 32, 44, 36, 29, 32, 27, 20, 22, 28, 24, 0, -21, -30, -45, + -78, -97, -83, -66, -50, -32, -17, -16, -23, -20, 4, 38, 51, 47, 37, 28, + 29, 27, 27, 31, 42, 54, 55, 43, 20, -5, -29, -40, -37, -30, -27, -23, + -15, -12, -11, 8, 43, 67, 78, 100, 122, 126, 107, 84, 81, 92, 106, 115, + 110, 79, 31, -3, -13, -26, -47, -56, -56, -58, -58, -56, -59, -72, -86, -84, + -66, -57, -56, -56, -60, -74, -74, -51, -32, -24, -14, 3, 14, 15, 19, 28, + 33, 19, 11, 22, 29, 18, 8, 9, 0, 0, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, + -1, -1, -1, -1, -1, -1, -1, 0, -1, -3, -2, -1, 0, 2, -4, -13, + -21, -23, -19, -8, 7, 17, 23, 26, 33, 38, 32, 17, -5, -17, -24, -20, + -6, -3, -16, -29, -26, -17, -5, -1, 2, 7, 11, 17, 15, 9, 9, 3, + 10, 15, 9, -14, -33, -27, -18, -6, -7, -10, -6, 0, 12, 15, 29, 38, + 36, 32, 11, 0, -30, -45, -50, -39, -23, -27, -24, -15, 6, 25, 37, 51, + 46, 40, 0, -19, -22, -34, -30, -40, -45, -51, -34, -1, 25, 48, 40, 43, + 51, 64, 58, 5, -22, -49, -63, -69, -68, -58, -54, -16, 13, 44, 66, 61, + 68, 72, 86, 47, -17, -56, -82, -88, -93, -72, -58, -40, 4, 45, 94, 98, + 84, 65, 68, 71, 15, -46, -88, -90, -88, -85, -62, -56, -34, -4, 41, 80, + 82, 74, 54, 70, 66, 25, -29, -70, -74, -90, -87, -79, -73, -46, -10, 54, + 90, 103, 88, 76, 90, 69, 25, -38, -76, -96, -119, -111, -103, -81, -57, -12, + 50, 90, 113, 98, 100, 112, 103, 60, -11, -54, -95, -121, -124, -119, -95, -71, + -10, 53, 103, 116, 93, 91, 89, 80, 31, -28, -67, -108, -122, -128, -110, -87, + -53, 8, 60, 107, 107, 89, 83, 83, 76, 27, -14, -52, -84, -99, -103, -82, + -72, -40, 4, 53, 92, 92, 88, 85, 97, 87, 42, 3, -45, -74, -106, -111, + -105, -101, -70, -30, 27, 65, 77, 83, 87, 106, 90, 58, 16, -30, -67, -101, + -100, -101, -93, -68, -27, 29, 60, 77, 79, 93, 111, 96, 71, 24, -21, -73, + -109, -118, -127, -118, -98, -50, 6, 43, 65, 70, 99, 115, 108, 82, 40, -1, + -53, -80, -94, -105, -101, -82, -31, 18, 56, 66, 72, 95, 103, 97, 64, 29, + -15, -63, -85, -102, -105, -104, -81, -35, 13, 53, 58, 69, 86, 97, 94, 67, + 39, -12, -54, -80, -97, -102, -103, -77, -38, 9, 40, 45, 60, 77, 95, 88, + 70, 41, -8, -46, -74, -87, -99, -100, -78, -42, 10, 37, 50, 66, 89, 110, + 103, 91, 57, 9, -33, -68, -86, -105, -105, -89, -51, -2, 23, 40, 53, 80, + 99, 98, 89, 53, 8, -37, -68, -90, -107, -106, -94, -51, -5, 25, 43, 58, + 86, 95, 98, 86, 52, 9, -36, -64, -92, -105, -108, -95, -53, -11, 22, 37, + 57, 81, 90, 96, 82, 52, 6, -34, -64, -92, -104, -113, -97, -59, -18, 15, + 31, 58, 79, 92, 98, 87, 57, 9, -29, -63, -87, -100, -109, -91, -58, -13, + 16, 36, 62, 78, 93, 96, 88, 56, 12, -25, -62, -83, -101, -106, -89, -57, + -15, 6, 30, 52, 71, 87, 94, 89, 55, 18, -21, -55, -76, -96, -100, -88, + -53, -16, 6, 31, 53, 76, 93, 105, 98, 64, 26, -18, -52, -78, -99, -105, + -95, -59, -26, 0, 24, 45, 66, 81, 97, 88, 62, 28, -12, -40, -67, -84, + -95, -83, -50, -21, 4, 24, 47, 64, 81, 96, 85, 63, 26, -11, -41, -69, + -88, -102, -91, -64, -36, -12, 10, 34, 51, 74, 87, 81, 62, 26, -7, -40, + -63, -83, -95, -83, -58, -31, -10, 14, 34, 51, 75, 85, 82, 61, 30, -3, + -34, -57, -81, -92, -83, -60, -36, -15, 11, 27, 47, 69, 80, 79, 59, 30, + -5, -33, -57, -82, -93, -84, -61, -38, -15, 10, 25, 48, 68, 80, 77, 58, + 29, -4, -30, -56, -80, -89, -78, -54, -34, -8, 10, 0, 0, 1, 0, -2, + -2, -5, -8, -3, 3, -4, -10, 2, 8, 3, 4, 5, -3, -9, 10, 26, + 26, 12, -4, -40, -64, -50, 1, 55, 69, 28, -23, -65, -83, -52, 13, 67, + 67, 39, 16, -15, -48, -38, 10, 53, 44, 5, -5, -14, -43, -35, 16, 54, + 37, -1, -26, -53, -82, -37, 35, 67, 44, 2, -10, -20, -39, -19, 27, 55, + 42, 3, -26, -67, -107, -62, 43, 110, 102, 43, -18, -63, -91, -35, 73, 120, + 77, -6, -72, -113, -109, -36, 53, 78, 50, 0, -46, -72, -71, -20, 67, 112, + 100, 44, -24, -88, -123, -84, 5, 71, 97, 66, 7, -53, -100, -80, -1, 83, + 127, 108, 38, -57, -121, -119, -57, 24, 84, 97, 62, -4, -77, -97, -46, 32, + 101, 108, 56, -20, -103, -119, -69, 18, 105, 126, 90, 6, -92, -126, -90, -3, + 85, 108, 75, 0, -86, -117, -85, -6, 76, 115, 101, 30, -68, -118, -105, -33, + 57, 105, 102, 41, -46, -104, -112, -59, 25, 95, 121, 81, -5, -88, -126, -94, + -12, 63, 101, 76, 7, -67, -107, -73, 11, 94, 127, 102, 21, -74, -124, -95, + -21, 57, 101, 82, 21, -48, -89, -59, 6, 67, 95, 60, -11, -82, -115, -81, + -13, 52, 84, 52, -9, -68, -96, -56, 9, 66, 93, 63, 10, -52, -86, -54, + 1, 60, 96, 70, 19, -44, -80, -51, 0, 55, 94, 69, 20, -42, -88, -76, + -40, 24, 79, 72, 34, -28, -75, -63, -23, 35, 71, 48, 4, -57, -95, -67, + -10, 62, 103, 75, 18, -61, -110, -86, -22, 61, 110, 90, 37, -45, -100, -87, + -39, 34, 81, 70, 33, -39, -88, -76, -24, 54, 94, 76, 32, -46, -100, -92, + -42, 35, 73, 62, 26, -46, -97, -93, -44, 36, 81, 75, 35, -38, -87, -81, + -26, 58, 99, 85, 37, -44, -101, -103, -46, 47, 98, 97, 56, -27, -90, -99, + -49, 37, 88, 95, 62, -12, -74, -93, -51, 27, 69, 71, 35, -30, -78, -87, + -38, 41, 84, 90, 57, -11, -71, -96, -56, 21, 69, 86, 60, -4, -67, -97, + -61, 12, 65, 88, 65, 3, -61, -94, -60, 14, 71, 96, 68, 3, -66, -104, + -70, 3, 59, 84, 59, -1, -67, -107, -76, -3, 59, 89, 64, 3, -67, -111, + -82, -9, 57, 92, 76, 26, -43, -93, -71, -9, 50, 80, 64, 16, -51, -100, + -79, -17, 49, 88, 77, 30, -41, -95, -79, -17, 49, 87, 77, 34, -36, -92, + -78, -19, 44, 82, 73, 33, -37, -95, -84, -23, 47, 89, 83, 43, -30, -92, + -83, -28, 39, 79, 74, 40, -28, -87, -82, -31, 34, 71, 67, 35, -31, -88, + -85, -36, 28, 68, 69, 44, -20, -79, -83, -43, 19, 59, 64, 41, -25, -89, + -100, -61, 9, 60, 76, 57, -10, -75, -90, -51, 22, 74, 88, 66, 1, -61, + -78, -42, 25, 71, 84, 63, -1, -67, -90, -59, 8, 59, 81, 68, 8, -56, + -85, -62, 1, 50, 74, 63, 7, -53, -84, -60, 5, 55, 80, 70, 17, -43, + -76, -55, 4, 49, 73, 65, 17, -41, -77, -62, -9, 38, 68, 64, 17, -43, + -84, -73, -22, 23, 56, 57, 18, -36, -77, -68, -23, 20, 51, 52, 16, -36, + -77, -70, -26, 18, 54, 59, 28, -22, -64, -59, -20, 21, 56, 63, 36, -12, + -55, -52, -16, 25, 58, 63, 35, -14, -59, -57, -22, 18, 51, 57, 31, -16, + -58, -58, -27, 10, 43, 51, 30, -16, -59, -60, -28, 12, 48, 57, 35, -13, + -59, -64, -35, 7, 47, 63, 47, 1, -46, -55, -32, 7, 47, 0, 0, -1, + -1, -4, 1, -1, -3, -13, -8, -14, -3, -2, -2, 1, 8, 5, 7, -21, + -13, -2, -6, -8, -22, -6, 5, 11, 34, 41, 33, 13, 28, 33, 48, 35, + 21, -3, -26, -18, -10, 3, 7, 22, 21, 63, 40, 41, 43, 4, -8, -43, + -63, -77, -77, -59, -18, 3, 2, -21, -46, -74, -90, -108, -101, -94, -89, -84, + -85, -77, -59, -50, -33, -7, 18, 37, 47, 64, 101, 127, 125, 127, 126, 126, + 126, 122, 100, 87, 62, 37, 28, 27, 25, 27, 34, 25, -4, -45, -85, -123, + -128, -126, -128, -127, -123, -92, -73, -55, -45, -37, -33, -32, -33, -43, -53, -55, + -43, -20, 3, 20, 34, 42, 49, 55, 63, 74, 84, 93, 101, 107, 112, 117, + 109, 92, 63, 33, 8, -13, -25, -29, -30, -27, -27, -32, -46, -63, -82, -98, + -109, -116, -121, -118, -104, -80, -49, -12, 21, 45, 58, 64, 66, 66, 61, 51, + 44, 37, 32, 32, 33, 33, 28, 23, 15, 8, 3, 2, 9, 16, 20, 24, + 23, 14, -1, -20, -37, -48, -53, -52, -47, -38, -26, -13, -5, -1, -4, -10, + -22, -34, -43, -48, -46, -34, -16, 5, 25, 45, 65, 78, 84, 83, 71, 55, + 39, 24, 9, -3, -12, -23, -34, -45, -57, -65, -71, -71, -63, -49, -34, -21, + -11, -2, 2, 8, 11, 12, 14, 14, 20, 28, 38, 50, 58, 63, 61, 56, + 46, 33, 17, -1, -19, -34, -45, -48, -44, -32, -19, -5, 5, 7, 4, -2, + -7, -11, -15, -18, -21, -23, -26, -28, -30, -31, -29, -26, -20, -12, -1, 11, + 21, 32, 42, 51, 55, 55, 52, 46, 41, 37, 32, 30, 28, 27, 24, 19, + 12, -1, -21, -45, -67, -89, -103, -107, -101, -90, -70, -51, -33, -18, -2, 11, + 23, 33, 39, 44, 49, 52, 57, 59, 59, 56, 52, 48, 41, 35, 28, 20, + 15, 11, 4, 0, -5, -11, -18, -25, -34, -42, -47, -48, -46, -40, -33, -27, + -24, -21, -24, -32, -42, -51, -56, -58, -56, -47, -35, -18, 2, 24, 48, 70, + 88, 99, 104, 102, 97, 89, 79, 69, 59, 49, 37, 27, 14, 0, -14, -29, + -44, -58, -71, -81, -87, -88, -88, -85, -81, -77, -72, -63, -51, -37, -21, -5, + 12, 29, 43, 53, 59, 61, 57, 48, 36, 24, 13, 8, 8, 15, 25, 38, + 48, 54, 54, 50, 43, 33, 22, 11, 3, -6, -15, -25, -35, -46, -54, -61, + -65, -68, -69, -69, -68, -64, -59, -52, -43, -32, -20, -7, 6, 19, 31, 42, + 51, 58, 62, 64, 62, 58, 52, 44, 35, 26, 17, 9, 1, -5, -10, -15, + -18, -19, -20, -19, -18, -16, -15, -14, -14, -15, -16, -17, -18, -19, -19, -19, + -19, -18, -16, -14, -11, -9, -6, -3, 0, 3, 6, 10, 14, 18, 22, 27, + 32, 35, 37, 37, 35, 30, 23, 14, 4, -6, -15, -24, -31, -36, -39, -40, + -39, -37, -32, -26, -19, -10, -1, 8, 17, 24, 29, 32, 33, 32, 29, 25, + 20, 15, 11, 7, 3, -1, -5, -9, -14, -19, -24, -28, -31, -32, -31, -27, + -23, -16, -10, -3, 2, 7, 10, 12, 13, 13, 13, 12, 10, 8, 7, 5, + 5, 5, 5, 6, 8, 10, 13, 17, 20, 23, 25, 26, 25, 21, 16, 9, + 1, -7, -16, -24, -31, -37, -42, -47, -49, -51, -52, -51, -48, -43, -37, -30, + -20, -7, 6, 19, -1, -4, -4, 0, -1, -4, -3, 4, 4, -2, -3, 2, + 1, -4, 0, 5, 0, -4, 2, -10, -26, -29, -34, -49, -61, -44, -21, -8, + -3, -3, 1, 20, 32, 38, 32, 12, -4, 1, 14, 28, 51, 68, 78, 80, + 72, 38, 1, -6, 16, 23, 2, -14, -15, -20, -33, -62, -65, -37, -18, -27, + -29, -26, -45, -38, 8, 52, 55, 31, 26, 16, 17, 45, 80, 87, 77, 62, + 54, 24, -23, -50, -43, -28, -47, -72, -86, -86, -87, -61, -35, -38, -57, -69, + -55, -27, 1, 4, 22, 45, 54, 31, 0, -7, -5, -3, 0, -9, -21, -20, + -15, -27, -31, -10, 5, 9, 3, -21, -67, -83, -46, -3, 8, 18, 22, 4, + -3, 5, 35, 52, 67, 72, 83, 89, 71, 37, 19, 25, 8, -11, -37, -58, + -80, -85, -68, -33, -24, -57, -60, -34, -16, -14, 17, 73, 96, 77, 48, 17, + -7, -9, 4, -1, -3, 6, 3, -12, -10, 19, 33, 33, 41, 35, -29, -70, + -64, -38, -18, 3, 17, -5, -26, -35, -5, 31, 63, 73, 86, 94, 80, 64, + 50, 46, 37, 28, -2, -32, -65, -91, -84, -63, -59, -82, -97, -80, -66, -65, + -43, 8, 49, 60, 61, 42, 27, 23, 23, 14, 15, 18, 10, -12, -17, -9, + -13, 8, 35, 42, 2, -41, -76, -87, -67, -46, -31, -32, -45, -72, -53, -5, + 32, 46, 72, 92, 96, 92, 77, 75, 73, 61, 44, 12, -32, -68, -72, -54, + -58, -75, -85, -67, -57, -61, -60, -46, -11, 24, 35, 22, 15, 6, -1, -13, + 8, 23, 8, -1, -1, -6, -8, 35, 71, 86, 79, 50, -11, -46, -38, -31, + -29, -21, -30, -64, -68, -43, -12, 10, 28, 62, 89, 88, 84, 85, 90, 89, + 95, 83, 28, -32, -53, -36, -44, -62, -64, -55, -59, -54, -52, -48, -23, 19, + 48, 37, 39, 42, 31, 12, 19, 20, 5, 4, 1, -23, -40, -14, 14, 42, + 68, 64, 14, -33, -53, -52, -32, -18, -24, -43, -67, -62, -36, -18, -1, 25, + 54, 57, 58, 56, 54, 50, 66, 80, 44, -21, -50, -40, -52, -69, -77, -60, + -56, -54, -53, -62, -49, -9, 28, 41, 58, 58, 47, 43, 49, 41, 34, 37, + 18, -19, -44, -47, -36, 1, 35, 38, 19, -20, -62, -71, -59, -36, -34, -47, + -63, -63, -50, -38, -17, 7, 37, 56, 74, 80, 73, 61, 87, 116, 99, 47, + -7, -26, -22, -20, -32, -57, -72, -76, -76, -71, -47, -9, 13, 24, 29, 29, + 25, 27, 52, 68, 62, 9, -38, -67, -66, -39, -11, -4, -24, -37, -47, -51, + -49, -44, -55, -39, -6, -17, -52, -54, -19, 1, 15, 24, 31, 41, 55, 71, + 79, 89, 111, 115, 88, 54, 22, -2, -8, -5, -7, -27, -49, -57, -69, -72, + -64, -30, -3, 17, 31, 37, 29, 14, 39, 67, 73, 47, 10, -40, -72, -58, + -23, -12, -19, -19, -39, -49, -42, -46, -62, -44, -8, -11, -36, -51, -39, -15, + 0, 13, 21, 25, 40, 55, 63, 73, 95, 115, 115, 85, 53, 20, 2, -1, + -2, -10, -32, -48, -64, -73, -77, -62, -33, -9, 16, 33, 31, 18, 17, 44, + 67, 70, 49, 6, -45, -69, -53, -24, -13, -19, -24, -40, -47, -45, -50, -62, + -43, -10, -13, -37, -51, -39, -15, 0, -3, -1, 1, -1, -6, -6, -4, -1, + -2, -6, -8, -7, -4, -5, -10, -14, -16, -16, -16, -17, -18, -18, -17, -15, + -15, -16, -15, -13, -10, -9, -9, -11, -13, -14, -11, -9, -8, -9, -7, -3, + -2, -5, -8, -6, 1, 5, 4, 1, 0, 1, 4, 4, 4, 5, 7, 9, + 9, 8, 8, 9, 10, 9, 5, 2, 3, 5, 7, 7, 9, 11, 11, 12, + 14, 14, 12, 8, 7, 8, 5, 1, 3, 8, 9, 9, 10, 14, 16, 15, + 14, 12, 11, 9, 7, 3, -2, -3, 3, 5, 0, -5, -1, -1, -6, -10, + -16, -23, -28, -29, -32, -39, -36, -23, -16, -19, -19, -10, -7, -12, -11, -5, + -6, -11, -13, -11, -9, -8, -2, 6, 8, 8, 9, 6, 2, 4, 8, 9, + 4, 4, 12, 18, 17, 14, 17, 20, 20, 16, 9, 7, 7, 5, 3, 4, + 1, -2, 0, 3, 2, -1, 1, 3, 3, 1, 2, 2, 0, 3, 6, 9, + 8, 0, -5, -3, 7, 12, 8, -2, -2, 9, 10, 2, -3, 2, 5, 1, + -3, -5, -6, -2, -3, -11, -20, -26, -28, -30, -32, -37, -43, -45, -43, -40, + -42, -41, -31, -22, -20, -18, -16, -16, -19, -15, -8, -3, -3, 3, 17, 26, + 22, 16, 18, 23, 27, 26, 23, 17, 15, 21, 25, 24, 25, 31, 36, 32, + 29, 23, 17, 15, 11, 5, 1, 4, 6, 8, 6, 7, 8, 10, 14, 18, + 22, 20, 17, 14, 15, 13, 10, 15, 15, 12, 9, 10, 15, 14, 9, 3, + 6, 10, 5, -3, -9, -16, -16, -10, -11, -20, -24, -18, -20, -32, -42, -48, + -55, -70, -84, -95, -100, -92, -75, -65, -68, -67, -56, -55, -51, -41, -33, -37, + -42, -38, -33, -31, -26, -6, 19, 30, 25, 25, 28, 30, 27, 19, 16, 18, + 31, 44, 46, 48, 56, 71, 77, 74, 66, 54, 47, 37, 19, 3, 2, 3, + 3, 4, 13, 20, 21, 25, 24, 25, 19, 18, 19, 19, 14, 6, 17, 14, + 1, 3, 12, 27, 29, 25, 13, 14, 24, 22, 6, -7, -7, 0, 11, 12, + 1, 0, 10, 8, -13, -32, -46, -52, -57, -70, -88, -106, -101, -81, -74, -82, + -75, -49, -37, -42, -44, -42, -46, -51, -47, -40, -32, -27, -6, 3, 16, 32, + 29, 25, 24, 30, 54, 69, 74, 78, 90, 108, 118, 124, 117, 107, 102, 93, + 76, 61, 50, 41, 35, 31, 26, 13, 4, 0, -1, 0, -6, -12, -10, -8, + -4, 0, -3, -20, -31, -27, -18, -16, -22, -29, -28, -9, 0, -3, -1, 2, + 11, 20, 24, 18, 22, 34, 32, 16, -1, -18, -34, -46, -55, -67, -91, -102, + -91, -72, -73, -81, -68, -55, -55, -65, -74, -79, -87, -87, -83, -81, -77, -60, + -25, 4, 4, -3, 0, 13, 29, 29, 24, 23, 29, 51, 67, 72, 77, 88, + 105, 114, 122, 116, 106, 100, 93, 77, 63, 51, 42, 36, 31, 27, 15, 5, + 0, -1, 0, -4, -10, -9, -7, -3, 2, -1, -16, -28, -26, -16, -13, -18, + -25, -25, -8, 2, 1, 2, 5, 13, 21, 26, 20, 23, 35, 35, 20, 3, + -14, -32, -45, -54, -67, -91, -102, -90, -72, -75, -82, -68, -56, -56, -66, -75, + -81, -88, -88, -83, -82, -77, -59, -22, 4, 1, -1, -2, -3, -3, -1, -1, + -6, -8, -9, -12, -5, 6, 15, 21, 22, 21, 9, -8, -16, -23, -32, -22, + 4, 27, 32, 17, -2, -21, -34, -37, -30, -24, -3, 24, 47, 58, 50, 23, + -12, -41, -52, -47, -33, -2, 28, 48, 45, 28, 0, -36, -58, -53, -34, -4, + 26, 52, 75, 73, 45, -5, -66, -101, -90, -61, -14, 23, 59, 87, 89, 63, + 10, -46, -79, -80, -55, -23, -3, 27, 58, 62, 41, -6, -66, -92, -77, -29, + 19, 41, 65, 74, 69, 42, -9, -73, -109, -107, -67, -17, 23, 70, 104, 111, + 83, 21, -56, -104, -109, -62, -21, 4, 34, 68, 89, 75, 19, -46, -89, -85, + -38, -1, 23, 45, 64, 74, 62, 8, -53, -98, -93, -47, -9, 16, 36, 62, + 86, 78, 13, -67, -121, -109, -56, -9, 25, 58, 89, 109, 81, 8, -70, -119, + -106, -56, -7, 32, 63, 90, 108, 74, -3, -89, -128, -118, -70, -22, 23, 62, + 101, 126, 98, 26, -64, -117, -110, -72, -32, 6, 44, 93, 124, 100, 28, -63, + -116, -110, -71, -26, 16, 54, 101, 121, 92, 13, -86, -128, -120, -79, -28, 15, + 60, 111, 127, 95, 11, -83, -127, -116, -80, -29, 15, 67, 117, 127, 100, 17, + -75, -118, -108, -75, -31, 7, 60, 109, 123, 87, 3, -83, -118, -106, -67, -23, + 13, 62, 106, 119, 85, 3, -77, -106, -95, -61, -27, 2, 52, 103, 124, 97, + 19, -61, -95, -92, -63, -34, -4, 45, 94, 116, 87, 8, -63, -91, -85, -58, + -36, -9, 36, 81, 104, 76, 2, -60, -87, -77, -52, -32, -2, 48, 97, 119, + 86, 7, -59, -90, -85, -65, -50, -22, 26, 78, 107, 79, 11, -49, -78, -73, + -58, -46, -18, 31, 85, 112, 75, 1, -59, -84, -73, -55, -40, -12, 30, 80, + 106, 74, 10, -46, -70, -62, -49, -39, -13, 31, 86, 110, 74, 8, -49, -70, + -59, -46, -33, -6, 38, 92, 111, 76, 13, -42, -62, -56, -51, -44, -23, 19, + 75, 97, 67, 8, -44, -63, -58, -56, -48, -26, 19, 75, 94, 64, 8, -40, + -55, -50, -49, -42, -25, 18, 69, 85, 57, 4, -41, -54, -51, -50, -45, -28, + 18, 71, 88, 60, 8, -35, -46, -47, -48, -46, -30, 16, 66, 84, 59, 9, + -30, -41, -43, -42, -40, -22, 25, 73, 88, 60, 8, -30, -42, -46, -45, -42, + -21, 28, 74, 83, 52, -1, -36, -46, -45, -40, -37, -17, 26, 66, 73, 41, + -10, -42, -54, -53, -48, -43, -19, 27, 68, 76, 44, -4, -34, -44, -41, -37, + -33, -10, 34, 71, 75, 40, -7, -36, -47, -43, -39, -35, -9, 35, 72, 75, + 39, -7, -38, -49, -45, -43, -38, -11, 33, 68, 70, 36, -4, -31, -39, -36, + -35, -31, -5, 36, 69, 69, 35, -4, -31, -38, -35, -37, -33, -8, 31, 64, + 63, 31, -7, -34, -42, -40, -43, -38, -12, 28, 61, 59, 27, -10, -34, -40, + -38, -41, -35, -9, 31, 63, 60, 29, -6, -31, -37, -38, -42, -35, -10, 29, + 60, 56, 27, -8, -30, -33, -34, -38, -32, -10, 28, 56, 51, 23, -9, -29, + -32, -34, -38, -33, -10, 29, 55, 50, 23, -9, -28, -30, -33, -37, -32, -8, + 32, 56, 52, 23, 23, 0, -2, 0, -2, -6, -6, -6, -5, -2, -1, 5, + 15, 20, 11, 12, 12, 6, 0, -8, -19, -12, -4, -19, -19, -4, 4, -7, + -3, 5, 8, 11, 14, 9, 9, 8, -4, -11, -6, -8, -16, -14, -7, -1, + -3, 1, 10, 13, 24, 28, 12, 10, 14, 11, -14, -29, -19, -12, -21, -25, + -16, 2, 0, -11, -7, 7, 10, 0, 0, 5, 11, 6, 10, 21, 13, 7, + 14, 4, -4, -9, -5, -11, -16, -7, -3, 3, 15, -2, 2, 17, 6, -19, + -16, 3, 3, -14, -10, 7, 7, 4, 8, 11, 4, -5, -12, -9, -6, -14, + -13, -17, -13, -8, 5, 9, 3, 10, 12, 24, 28, 26, 35, 20, -3, 24, + 23, -19, -31, -23, -23, -38, -34, -18, -10, -8, -6, -4, -1, 5, -4, -8, + 2, 15, 12, 26, 56, 37, 10, 25, 25, -4, -21, -24, -23, -26, -30, -27, + -8, 10, -5, 3, 30, 6, -26, -7, 13, -2, -19, -2, 11, 3, 14, 21, + 8, 12, 5, -19, -26, -12, 9, 1, -8, -8, 20, 27, 17, 16, 15, 0, + 23, 39, 11, -4, -13, -21, -21, -32, -36, -27, -20, -24, -10, -4, 5, 14, + 4, -11, -10, 7, -8, -7, 7, 7, 2, 15, 29, 55, 26, 4, 22, 37, + 32, 14, 10, 18, 7, -1, -28, -49, -24, -14, -41, -53, -37, -28, -27, -15, + 1, 2, 14, 14, 13, 3, 0, 1, 18, 9, 7, 11, 23, 23, 25, 16, + -7, 1, 13, 26, 26, 9, 13, 28, 28, 1, -29, -29, -26, -27, -43, -43, + -31, -12, -26, -15, 6, 16, 6, 22, 11, -4, 0, 3, 0, -4, -20, -9, + 15, 23, 19, 7, 25, 19, 42, 63, 40, 13, 22, 24, 1, -41, -60, -55, + -63, -69, -61, -31, -7, 10, 8, 0, 7, 4, 4, 20, 5, -4, 9, 27, + 31, 27, 23, 13, 19, 12, 2, 4, 15, 20, 35, 19, 16, 26, 3, -30, + -48, -31, -40, -60, -59, -47, -13, -3, 12, 22, 11, 7, 9, 8, 3, -10, + -34, -5, 6, 24, 38, 19, 13, 21, 40, 15, 2, 27, 26, 16, 44, 47, + -7, -43, -41, -29, -44, -80, -81, -58, -26, -17, 3, 16, 30, 19, 10, 25, + 16, 6, -12, -3, 13, 30, 38, 20, 17, 22, 25, 18, 13, 16, -3, 1, + 32, 44, -11, -48, -51, -34, -38, -49, -64, -70, -23, -10, -14, -1, 20, 18, + 20, 21, 11, 3, -8, -3, 13, 14, 22, 18, 32, 37, 30, 25, 16, 27, + 27, 18, 37, 52, 12, -26, -56, -57, -46, -71, -92, -86, -50, -21, -10, 8, + 15, 15, 18, 28, 17, 1, 1, 2, 13, 13, 23, 23, 21, 29, 31, 29, + 15, 20, 33, 32, 29, 46, 21, -31, -49, -53, -51, -66, -82, -76, -54, -32, + -10, 12, 19, 29, 18, 3, 0, 16, 20, 29, 31, 20, 25, 31, 43, 41, + 34, 44, 27, 29, 65, 54, -15, -70, -79, -63, -86, -114, -114, -79, -26, -2, + 6, 18, 19, 10, 19, 26, 15, 5, 0, 16, 23, 29, 30, 21, 25, 28, + 37, 37, 38, 44, 32, 29, 66, 65, -7, -67, -74, -59, -82, -114, -117, -85, + -31, -2, 11, 20, 18, 9, 20, 30, 15, 5, 0, 0, 1, 1, 2, 3, + 3, 3, 4, 4, 5, 6, 6, 7, 8, 8, 7, 7, 7, 7, 7, 6, + 4, 3, 2, 0, -1, -2, -3, -5, -6, -8, -9, -9, -11, -12, -14, -15, + -17, -17, -17, -18, -19, -19, -19, -18, -17, -16, -15, -13, -11, -8, -7, -6, + -5, -3, -1, 0, 0, 1, 3, 5, 8, 10, 12, 14, 17, 19, 21, 23, + 26, 27, 28, 28, 28, 26, 25, 24, 23, 23, 21, 19, 18, 16, 15, 14, + 13, 12, 11, 11, 11, 10, 8, 6, 5, 5, 4, 2, 0, -2, -4, -5, + -7, -10, -11, -12, -13, -14, -15, -15, -15, -15, -15, -16, -17, -18, -18, -19, + -21, -23, -25, -27, -28, -29, -29, -30, -30, -29, -27, -25, -23, -22, -20, -18, + -16, -14, -13, -12, -11, -11, -10, -9, -8, -6, -5, -4, -3, -1, 1, 3, + 4, 6, 7, 8, 8, 9, 10, 11, 12, 13, 13, 13, 13, 15, 18, 21, + 23, 24, 25, 25, 28, 31, 33, 34, 34, 32, 31, 31, 31, 30, 27, 22, + 16, 12, 10, 9, 7, 3, -5, -13, -19, -22, -22, -23, -25, -28, -31, -33, + -33, -32, -32, -31, -32, -33, -32, -29, -25, -21, -19, -19, -19, -19, -18, -15, + -9, -3, 2, 6, 9, 12, 16, 21, 27, 32, 37, 39, 40, 40, 39, 39, + 40, 41, 40, 38, 35, 34, 34, 33, 29, 22, 16, 11, 10, 11, 12, 12, + 10, 8, 7, 5, 3, 2, 0, -6, -12, -19, -23, -23, -22, -23, -26, -30, + -33, -33, -33, -34, -35, -37, -40, -45, -50, -53, -52, -48, -42, -37, -32, -27, + -22, -20, -18, -16, -16, -18, -21, -26, -30, -33, -34, -35, -36, -38, -40, -41, + -41, -38, -36, -36, -38, -41, -40, -38, -34, -30, -27, -25, -22, -20, -16, -15, + -16, -17, -18, -16, -13, -10, -7, -4, -2, 1, 6, 11, 16, 21, 24, 25, + 26, 24, 22, 19, 18, 19, 22, 24, 26, 30, 33, 38, 44, 50, 56, 61, + 63, 68, 72, 74, 73, 68, 64, 57, 50, 47, 46, 44, 37, 21, 3, -11, + -20, -23, -25, -30, -33, -36, -36, -34, -31, -27, -22, -21, -22, -21, -18, -21, + -24, -27, -31, -33, -32, -27, -21, -14, -13, -17, -17, -10, 0, 10, 15, 16, + 14, 8, 6, 10, 16, 25, 34, 39, 43, 47, 53, 62, 72, 82, 89, 92, + 90, 84, 79, 77, 77, 76, 67, 54, 42, 33, 26, 18, 5, -11, -27, -41, + -53, -65, -73, -77, -79, -81, -86, -93, -102, -110, -116, -118, -120, -124, -127, -128, + -128, -126, -122, -116, -107, -96, -85, -78, -72, -64, -54, -45, -39, -40, -46, -49, + -49, -47, -45, -44, -45, -45, -44, -42, -38, -33, -29, -26, -23, -20, -18, -14, + -11, -8, -5, -2, 2, 7, 11, 10, 8, 7, 9, 16, 22, 26, 28, 31, + 34, 39, 44, 49, 53, 57, 60, 62, 63, 63, 65, 66, 63, 57, 51, 46, + 46, 50, 53, 54, 55, 54, 55, 57, 63, 69, 73, 75, 73, 69, 66, 64, + 65, 63, 55, 43, 30, 18, 11, 3, -6, -15, -23, -29, -32, -32, -28, -22, + -16, -13, -16, -16, -11, -2, 9, 15, 1, 0, 0, 0, -1, 0, -3, 0, + -1, 0, -18, 21, -22, 23, -41, 20, 84, -39, 50, -61, 26, -126, -19, -37, + 15, 2, 70, -33, 127, -55, 117, -73, 15, -45, -50, 8, -11, 23, 33, 1, + 26, -67, 26, -25, 14, -45, 57, -124, 12, -4, -23, 107, -54, 127, -49, 43, + 27, -59, -30, 15, -128, 5, -128, 86, -39, 82, 12, 62, 9, 51, -59, 53, + -95, 67, -92, 68, -28, 94, 21, 47, -11, -1, -41, 0, -25, -9, 18, -68, + 15, -27, 49, -27, 103, -4, 3, -36, 58, -98, 56, -116, -31, -123, 25, -58, + 89, -21, 110, -25, 73, -28, 39, -21, 35, -40, 37, -20, 50, 55, 51, 6, + 1, -47, -11, -32, -23, 38, -67, 3, -54, 34, -55, 79, 1, 32, -61, 89, + -86, 53, -67, -10, -128, -6, -68, 51, -4, 82, 15, 83, -16, 63, -24, 55, + -29, 8, 0, 6, 11, 54, 14, 16, -39, -9, -12, -47, 37, -40, -22, -60, + 21, -76, 51, -17, 74, -63, 98, -36, 44, -33, 24, -113, -37, -89, 20, -30, + 67, 18, 87, 0, 67, -6, 38, 1, -2, -18, -5, -20, 32, 17, 21, -8, + -30, 15, -47, 11, -17, 11, -97, 43, -87, 27, -36, 91, -41, 66, 3, 44, + -28, 55, -74, -37, -92, -21, -37, 33, -1, 75, 22, 36, 14, 26, 8, 8, + -12, -7, -21, -1, 27, 11, 21, -30, 21, -37, -3, -13, 23, -27, -32, -10, + -23, -44, 56, -1, 43, -12, 76, -29, 48, -9, -25, -71, -70, -48, -20, 2, + 9, 56, 8, 56, -10, 52, -12, 31, -29, 27, -60, 62, -42, 83, -45, 30, + -24, 4, -26, 33, -23, 5, -18, -25, -53, -7, -6, -6, 19, 16, 31, 3, + 58, -14, 0, -64, -33, -58, -8, -43, 42, -18, 57, -9, 54, 1, 47, -3, + 36, -18, 3, 4, 6, 2, -17, 8, -14, -27, 35, 2, -3, 1, -8, -43, + -34, -1, -22, 12, 2, 37, -6, 53, 14, 16, -43, -22, -75, -2, -67, 23, + -24, 39, -3, 39, 6, 44, 9, 37, 5, 1, 3, 5, 12, -18, 0, 0, + -31, 5, 23, 1, -3, 10, -20, -48, -6, -30, 7, -18, 35, -4, 32, 21, + 39, -26, -1, -75, -9, -65, -3, -28, 20, -5, 32, 5, 36, 20, 30, 30, + 3, 10, -1, 16, -10, -7, -1, -17, -23, 18, 14, -3, 8, 9, -45, -14, + -35, -1, -27, 18, -2, 29, 1, 61, -14, 20, -56, -19, -51, -22, -38, 9, + -14, 22, 5, 24, 27, 23, 41, 13, 20, -7, 23, -2, -8, -2, -9, -26, + -6, 14, 11, -11, 37, -33, -12, -38, -6, -33, 7, -14, 30, -12, 55, 4, + 33, -32, -14, -45, -22, -43, -7, -15, 18, 18, 33, 17, 41, 22, 15, 14, + 8, -24, -16, -18, -16, -7, 6, 16, -2, 8, -14, -6, -23, 0, -22, 1, + -23, 21, 4, 24, -1, 9, -9, -11, -14, -13, -16, -14, -15, -12, -16, -5, + 8, 28, 25, 28, 34, 27, 15, 16, 2, -20, -22, -20, -15, -8, 10, 11, + 7, -3, -5, -16, -10, -13, -5, -16, -5, 4, 17, 13, 6, 1, -9, -1, + -2, -3, -4, -4, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -6, + -6, -6, -6, -6, -5, -3, -3, -5, -5, -5, -7, -8, -5, 4, 5, 13, + 12, -12, -5, 10, 5, 4, 0, 3, 26, 33, 10, -15, -69, -89, -25, 25, + 58, 70, 22, -41, -62, -31, 18, 17, -17, -12, -9, 20, 99, 96, 0, -88, + -123, -69, 61, 116, 54, -11, -45, -28, 40, 38, -42, -59, -53, -31, 63, 78, + -9, -65, -83, -59, 48, 110, 50, -11, -51, -54, 41, 96, 9, -87, -119, -77, + 42, 118, 67, -18, -57, -46, 24, 89, 81, 22, -43, -77, -65, -41, -23, -3, + 4, 8, -13, -54, -52, -21, 30, 89, 86, 8, -49, -76, -56, 30, 55, 52, + 47, -7, -45, -49, -48, -10, 68, 74, 43, 22, -27, -25, 12, 20, -5, -43, + -69, -46, 21, 53, 51, 38, -8, -32, 6, 20, -1, -19, -56, -67, -26, 27, + 76, 95, 23, -64, -60, -15, 33, 39, -8, -37, -24, -7, 7, 4, -25, -23, + -10, -14, -7, -5, -12, 2, 28, 31, 37, 21, -18, -16, -4, -22, -37, -46, + -56, -8, 58, 64, 53, 31, -9, -9, -2, -57, -85, -52, -13, 59, 92, 21, + -42, -47, -33, 27, 75, 27, -22, -38, -44, 18, 77, 32, -21, -46, -50, 34, + 89, 22, -37, -60, -56, 31, 95, 36, -27, -57, -82, -15, 53, 15, -13, -25, + -44, 14, 66, 14, -32, -53, -62, 25, 96, 50, 3, -32, -56, 25, 98, 51, + -9, -56, -78, 7, 92, 71, 28, -31, -92, -42, 28, 20, 24, 8, -34, 22, + 70, 18, -17, -53, -88, -20, 39, 7, -2, -8, -28, 35, 80, 19, -23, -55, + -93, -22, 63, 54, 47, 19, -52, -35, 2, -36, -32, -18, -49, -9, 41, 15, + 26, 34, -22, -6, 31, 1, 8, 9, -43, -15, 30, -3, -1, -7, -73, -48, + 6, -14, 5, 13, -47, -30, 12, -13, 6, 18, -37, -13, 39, 27, 45, 38, + -37, -32, 12, 3, 32, 46, -10, 6, 48, 16, 15, 15, -32, -2, 47, 24, + 26, 18, -51, -51, -15, -29, -1, 19, -28, -15, 21, 2, 18, 22, -34, -24, + 13, -3, 15, 14, -45, -34, 7, 10, 38, 31, -34, -30, 4, 5, 43, 61, + 13, 4, 6, -22, 4, 24, -13, -13, -10, -34, 0, 23, -16, -16, -13, -42, + -18, -4, -36, -17, 5, -10, 14, 22, -21, -22, -16, -37, -6, 20, -2, 17, + 36, 19, 43, 43, -9, -15, -12, -29, 6, 31, 6, 10, 7, -23, -2, 9, + -23, -15, -10, -26, 3, 20, -5, 1, 0, -22, 5, 22, -6, -8, -16, -37, + -5, 20, 2, 11, 6, -19, 11, 33, 12, 20, 16, -7, 20, 35, 11, 11, + -3, -28, 2, 19, -1, 3, -6, -29, -5, 2, -25, -17, -12, -16, 22, 34, + 3, -4, -21, -36, 4, 26, 8, -1, -30, -54, -23, -3, -11, 0, -12, -27, + 7, 24, 13, 19, -1, -21, 10, 27, 14, 17, 0, -14, 18, 33, 19, 14, + -17, -41, -10, 9, 2, 7, -14, -30, 4, 20, 9, 9, -15, -35, -3, 16, + 9, 0, -1, -2, -3, 4, 7, 4, -2, -3, 0, 3, -1, -1, 4, 5, + -2, -13, -9, 1, 4, 2, 1, 2, 2, -2, -8, -4, 0, 4, 4, -3, + -4, -3, 1, 2, -1, 3, 14, 1, -7, -12, -4, -2, 1, 1, 9, 5, + -6, -5, -2, -1, -1, 1, 14, 6, -6, -7, 3, 8, -2, -4, 13, 12, + -10, -17, -10, -5, -4, 2, 3, 7, -6, -6, -1, -1, -4, 1, 11, 6, + -6, -9, 10, 11, 3, 1, 14, 15, -12, -20, -12, -9, -15, -1, 7, 2, + -16, -7, 6, 0, -2, 10, 26, 17, -6, -11, 24, 21, 1, 0, 18, 15, + -17, -31, -28, -23, -14, 0, -4, 0, -16, -8, 8, -4, -3, 7, 15, 5, + -3, -3, 26, 25, 12, 8, 28, 17, -15, -28, -18, -17, -18, -7, -3, -7, + -20, 0, 7, 1, -9, 6, 9, -4, -9, 2, 15, 24, 34, 31, 10, -4, + -15, -29, -17, -21, -41, -40, -5, 19, -20, 3, 11, 33, 28, 21, 18, 15, + 16, 3, -1, 18, 17, 15, 1, -15, -10, -5, -14, -42, -48, -43, -26, 4, + -29, -14, -9, 32, 20, 12, 15, 21, 39, 24, 8, 26, 33, 6, -3, 0, + 1, -7, -16, -41, -44, -51, -34, -3, -6, -6, -19, 26, 10, 15, 35, 46, + 32, 20, 16, 23, 38, 15, -4, -10, 17, -6, -41, -48, -53, -70, -52, -9, + -9, -22, -15, 19, 24, 22, 30, 49, 34, 10, 1, 15, 33, 15, 1, 17, + 46, 12, -38, -59, -50, -57, -46, -13, -16, -30, -24, 26, 37, 33, 30, 45, + 40, 2, -11, 17, 41, 24, -4, 16, 48, 15, -38, -67, -64, -65, -46, -18, + -18, -35, -32, 35, 39, 37, 21, 45, 42, -2, -19, 14, 37, 22, 7, 24, + 40, 13, -42, -68, -63, -63, -38, -6, -12, -34, -25, 39, 43, 39, 17, 47, + 45, 3, -19, 21, 45, 25, 2, 21, 31, 0, -45, -71, -78, -83, -48, 2, + 7, -27, -32, 34, 45, 49, 23, 44, 36, 5, -5, 38, 60, 27, -13, 21, + 42, -13, -69, -81, -86, -79, -38, -9, -11, -41, -36, 38, 56, 45, 10, 43, + 43, 10, -6, 36, 57, 41, 10, 36, 46, -16, -67, -66, -71, -80, -44, -8, + -5, -29, -27, 30, 43, 46, 20, 52, 39, -9, -21, 40, 68, 42, -1, 20, + 32, -14, -70, -86, -94, -90, -45, -2, 0, -31, -17, 36, 47, 46, 18, 44, + 29, -2, -11, 46, 74, 51, 14, 36, 46, -15, -78, -87, -91, -89, -46, -12, + -11, -28, -5, 41, 46, 40, 17, 51, 33, -6, -13, 49, 75, 52, 15, 30, + 34, -21, -79, -88, -93, -88, -42, -9, -4, -25, -3, 36, 40, 34, 16, 44, + 23, -8, -10, 52, 83, 55, 17, 38, 31, -31, -82, -91, -93, -82, -39, -16, + -10, -25, 5, 33, 42, 32, 20, 54, 25, -9, -3, 59, 85, 63, 24, 37, + 24, -39, -86, -92, -97, -80, -34, -17, -15, -24, 10, 35, 45, 32, 16, 45, + 12, -23, -2, 62, 78, 53, 21, 37, 26, -39, -91, -95, -96, -77, -29, -16, + -16, -25, 10, -1, 0, 3, 21, -26, 18, -30, 32, -19, -15, -27, 2, 0, + 103, -84, -53, -52, 79, 51, 36, -69, -31, 48, 71, 33, -74, -64, 10, 51, + 49, -68, -91, -16, 30, 33, -31, -58, -42, 14, 24, -25, 23, -71, 79, -22, + 123, -74, 28, 28, 115, 99, -7, 9, -15, 72, 1, 16, -47, -5, -71, -18, + -75, -26, -71, -28, -56, -24, -57, -19, -33, -5, 7, -3, 14, -8, 82, 100, + 23, -32, -15, 80, 98, 68, -30, -21, 24, 71, 28, -41, -96, -22, 32, 37, + -57, -110, -67, 28, 35, -22, -112, -79, 13, 70, 27, -55, -63, 31, 95, 86, + -4, -40, 29, 110, 110, 28, -50, -12, 66, 80, 14, -87, -81, -7, 36, -5, + -95, -118, -42, 26, 8, -69, -121, -48, 37, 60, -6, -68, -29, 67, 104, 61, + -24, -17, 70, 123, 92, -5, -43, 23, 82, 67, -28, -96, -54, 18, 30, -39, + -115, -96, -7, 25, -13, -99, -101, -13, 52, 42, -35, -62, 9, 88, 93, 28, + -32, 15, 97, 118, 58, -29, -24, 51, 82, 39, -61, -88, -26, 28, 9, -70, + -117, -63, 7, 14, -46, -109, -71, 15, 55, 16, -51, -42, 43, 94, 75, 2, + -21, 48, 107, 101, 23, -36, 4, 65, 70, 1, -81, -69, -3, 26, -19, -94, + -106, -32, 14, -3, -74, -103, -37, 34, 46, -10, -56, -12, 66, 91, 49, -15, + 1, 74, 111, 76, -4, -28, 31, 72, 50, -33, -85, -43, 11, 15, -46, -106, + -80, -11, 13, -26, -92, -84, -8, 44, 29, -30, -48, 19, 80, 81, 26, -18, + 27, 91, 103, 49, -22, -10, 48, 68, 22, -60, -75, -22, 17, -5, -71, -105, + -54, 3, 3, -49, -98, -58, 14, 44, 11, -44, -27, 45, 85, 65, 5, -8, + 53, 100, 87, 21, -26, 11, 60, 56, -6, -74, -58, -4, 13, -25, -90, -91, + -29, 7, -12, -72, -90, -29, 32, 37, -10, -46, -2, 66, 83, 47, -8, 10, + 74, 101, 68, -3, -19, 31, 62, 38, -36, -77, -40, 6, 4, -49, -100, -72, + -12, 3, -31, -86, -73, -4, 37, 25, -28, -36, 25, 75, 74, 25, -9, 34, + 88, 94, 43, -16, -4, 47, 58, 15, -57, -69, -22, 6, -12, -73, -96, -50, + -4, -7, -53, -89, -49, 13, 36, 5, -37, -17, 47, 77, 59, 9, 2, 58, + 92, 79, 19, -17, 16, 54, 45, -13, -69, -52, -8, 3, -33, -85, -82, -29, + -2, -20, -68, -79, -23, 24, 29, -11, -34, 7, 61, 73, 41, 0, 22, 73, + 90, 58, 1, -9, 32, 52, 26, -36, -69, -35, -3, -7, -53, -90, -63, -16, + -7, -36, -78, -60, -4, 29, 16, -22, -23, 29, 68, 64, 26, 2, 42, 80, + 81, 38, -8, 5, 42, 44, 4, -53, -57, -21, -2, -22, -69, -83, -43, -10, + -15, -51, -77, -38, 11, 27, 3, -27, -5, 46, 68, 52, 13, 15, 58, 83, + 68, 19, -8, 21, 46, 32, -16, -60, -44, -12, -6, -36, -76, -74, -34, -10, + -20, -57, -73, -33, 12, 27, 3, -1, -6, -11, -3, 4, 0, -7, -8, 1, + 21, 14, 28, 33, 25, -1, 7, 4, -13, -21, -44, -29, -17, -31, -32, 2, + 0, -20, 4, 3, 4, 0, -2, -5, -4, -14, 3, 14, 9, 28, 34, 54, + 43, 54, 39, 19, 17, -1, 5, -23, -31, -25, -35, -46, -60, -29, -29, -13, + -37, -22, -16, -20, -27, -21, -6, -16, 8, -5, 15, 26, 69, 65, 74, 85, + 81, 76, 51, 22, -10, -10, -19, -3, -39, -73, -55, -36, -18, -45, -49, -45, + -52, -47, -74, -73, -56, -31, -15, -16, -5, 18, 65, 86, 108, 94, 97, 90, + 79, 54, 30, 19, 10, 25, -16, -34, -37, -9, -16, -35, -44, -60, -60, -50, + -62, -70, -66, -44, -34, -34, -29, -10, 23, 61, 85, 79, 75, 70, 61, 41, + 31, 7, 8, 3, -22, -42, -28, 0, -13, -29, -39, -52, -56, -55, -58, -60, + -57, -41, -35, -37, -19, 5, 35, 71, 87, 85, 97, 112, 97, 71, 56, 52, + 53, 43, 18, -7, -3, 10, 0, -17, -39, -55, -58, -64, -80, -106, -121, -112, + -110, -113, -105, -82, -51, -8, 16, 20, 45, 66, 66, 49, 46, 59, 75, 78, + 63, 62, 74, 80, 80, 69, 51, 27, 11, 0, -14, -40, -53, -48, -55, -68, + -71, -56, -34, -1, 14, 24, 49, 62, 59, 42, 34, 43, 47, 43, 26, 30, + 33, 38, 26, 4, -17, -41, -66, -81, -92, -112, -120, -115, -116, -128, -125, -103, + -71, -36, -11, 9, 33, 56, 59, 54, 61, 67, 77, 77, 77, 79, 74, 75, + 73, 55, 30, 10, -21, -38, -46, -61, -70, -67, -70, -81, -77, -64, -45, -23, + -4, 10, 30, 44, 44, 39, 42, 48, 51, 50, 51, 58, 58, 65, 65, 47, + 29, 12, -14, -31, -41, -53, -63, -60, -62, -64, -58, -44, -26, -11, 1, 10, + 20, 22, 17, 9, 5, 6, 6, 2, 4, 10, 10, 17, 19, 9, 7, -1, + -14, -18, -13, -14, -9, 1, 7, 12, 17, 23, 31, 35, 36, 35, 38, 31, + 21, 16, 3, 0, -8, -11, -11, -13, -19, -20, -23, -34, -39, -51, -69, -78, + -81, -83, -83, -78, -70, -60, -47, -34, -19, 2, 20, 39, 57, 60, 66, 67, + 63, 61, 53, 50, 51, 47, 37, 32, 23, 13, 6, -3, -17, -23, -28, -34, + -37, -35, -27, -15, -2, 4, 12, 23, 30, 44, 47, 43, 41, 35, 29, 22, + 15, 13, 14, 7, -1, -5, -11, -19, -20, -25, -37, -43, -41, -43, -47, -47, + -40, -29, -17, -7, 5, 13, 23, 38, 44, 37, 34, 31, 23, 17, 6, 1, + -2, -10, -20, -25, -35, -45, -50, -54, -64, -68, -65, -66, -65, -59, -47, -30, + -19, -7, 5, 14, 28, 48, 62, 66, 72, 75, 78, 76, 67, 60, 56, 46, + 32, 20, 9, -2, -10, -21, -35, -43, -44, -49, -56, -57, -51, -38, -25, -13, + -2, 9, 25, 42, 56, 59, 64, 65, 67, 65, 57, 52, 49, 41, 28, 18, + 8, -2, -10, 0, 8, 13, 21, 20, 20, 17, 10, 8, -2, -6, -17, -21, + -29, -23, -25, -14, -7, -2, 7, 10, 20, 21, 22, 23, 19, 14, 9, -2, + -6, -18, -20, -28, -25, -23, -18, -10, -3, 5, 9, 22, 17, 28, 22, 21, + 17, 11, 2, -8, -18, -23, -27, -26, -24, -19, -13, -6, 3, 9, 17, 20, + 28, 24, 25, 21, 13, 6, -5, -14, -21, -29, -29, -30, -23, -19, -7, -1, + 10, 18, 25, 29, 27, 28, 20, 17, 5, -7, -13, -26, -29, -30, -30, -27, + -20, -12, 0, 11, 19, 25, 27, 30, 26, 28, 19, 11, -2, -12, -24, -30, + -35, -34, -30, -24, -14, -2, 9, 18, 23, 28, 26, 33, 31, 29, 24, 12, + 5, -12, -23, -30, -37, -36, -36, -26, -19, -5, 5, 19, 22, 32, 32, 36, + 35, 26, 21, 3, -6, -22, -34, -41, -44, -38, -31, -18, -6, 6, 15, 23, + 32, 33, 39, 34, 31, 23, 10, -2, -21, -32, -44, -47, -45, -37, -23, -12, + 6, 13, 28, 30, 38, 40, 40, 38, 23, 17, -6, -15, -35, -42, -50, -49, + -41, -31, -14, 0, 14, 26, 35, 42, 45, 45, 40, 27, 18, -4, -14, -33, + -42, -54, -52, -47, -36, -21, -5, 13, 24, 39, 43, 52, 47, 42, 36, 20, + 7, -15, -32, -45, -55, -56, -54, -43, -27, -8, 12, 26, 38, 45, 50, 51, + 48, 40, 27, 9, -11, -30, -46, -58, -62, -58, -49, -31, -11, 9, 24, 41, + 45, 54, 53, 54, 45, 30, 14, -10, -27, -48, -58, -67, -64, -56, -35, -15, + 6, 24, 37, 45, 54, 56, 56, 49, 39, 18, 0, -26, -45, -60, -74, -70, + -63, -41, -23, 4, 21, 39, 48, 53, 61, 58, 59, 43, 29, 3, -20, -46, + -64, -77, -77, -69, -50, -27, 0, 20, 36, 49, 56, 64, 64, 63, 51, 34, + 6, -17, -46, -65, -79, -83, -76, -58, -33, -6, 17, 38, 49, 60, 67, 68, + 66, 53, 37, 13, -13, -38, -65, -79, -90, -82, -68, -41, -15, 14, 36, 52, + 63, 70, 73, 69, 62, 44, 19, -8, -38, -63, -83, -93, -90, -77, -49, -20, + 12, 34, 54, 65, 72, 75, 76, 65, 51, 26, -1, -33, -62, -86, -98, -96, + -86, -58, -29, 6, 32, 54, 66, 73, 79, 76, 73, 58, 36, 4, -27, -60, + -85, -101, -104, -92, -70, -36, -1, 31, 53, 70, 75, 81, 80, 78, 65, 41, + 15, -24, -56, -84, -105, -109, -101, -79, -46, -7, 25, 56, 65, 77, 82, 85, + 83, 69, 51, 19, -14, -50, -83, -103, -115, -107, -88, -55, -17, 21, 50, 67, + 81, 86, 89, 85, 79, 55, 28, -8, -46, -77, -103, -116, -117, -97, -67, -25, + 1, 39, 66, 81, 92, 96, 97, 90, 73, 45, 11, -27, -64, -97, -120, -128, + -117, -89, -49, -5, 35, 65, 81, 93, 98, 99, 91, 75, 46, 12, -27, 28, + -9, -42, -57, -50, -18, 33, 77, 77, 17, -64, -96, -55, 22, 73, 68, 17, + -43, -77, -67, -15, 59, 102, 79, 12, -48, -71, -57, -28, -3, 11, 10, -3, + -17, -4, 44, 88, 79, 10, -69, -103, -74, -6, 54, 75, 53, -4, -63, -80, + -38, 32, 73, 59, 7, -43, -67, -57, -18, 33, 71, 71, 24, -31, -47, -17, + 20, 23, -14, -58, -73, -47, 10, 73, 110, 93, 20, -62, -97, -68, -6, 43, + 54, 28, -13, -51, -65, -35, 26, 74, 69, 12, -50, -68, -37, 9, 37, 37, + 16, -12, -26, -7, 36, 65, 45, -19, -87, -112, -75, -7, 58, 97, 92, 41, + -30, -75, -62, -3, 49, 52, 7, -44, -63, -45, -6, 37, 60, 42, -5, -42, + -41, -3, 38, 41, 8, -33, -51, -38, 3, 54, 90, 79, 12, -76, -127, -106, + -29, 47, 78, 63, 23, -19, -36, -16, 24, 50, 35, -15, -59, -64, -27, 17, + 40, 35, 11, -20, -39, -26, 19, 63, 67, 14, -61, -97, -72, -5, 64, 101, + 87, 26, -49, -96, -86, -32, 24, 40, 17, -11, -17, -3, 24, 51, 55, 29, + -20, -66, -69, -23, 35, 55, 25, -26, -59, -55, -14, 44, 86, 80, 23, -56, + -105, -87, -19, 48, 79, 67, 27, -18, -46, -43, -14, 17, 16, -20, -54, -47, + 3, 59, 83, 66, 18, -35, -64, -54, -8, 44, 59, 18, -48, -87, -72, -16, + 49, 88, 84, 37, -31, -81, -79, -26, 33, 52, 29, -5, -19, -6, 20, 34, + 27, -5, -51, -84, -71, -9, 62, 95, 71, 12, -40, -58, -37, 8, 52, 63, + 22, -53, -103, -88, -23, 47, 80, 64, 24, -14, -33, -28, -3, 21, 18, -15, + -45, -39, 5, 57, 78, 54, -1, -60, -97, -89, -29, 50, 92, 67, 0, -53, + -57, -13, 38, 64, 52, 10, -44, -82, -76, -26, 28, 49, 32, 1, -14, -1, + 24, 40, 38, 9, -43, -87, -79, -13, 69, 110, 80, 4, -65, -90, -69, -21, + 32, 58, 39, -9, -48, -45, 0, 52, 69, 46, 5, -34, -57, -50, -14, 23, + 28, -8, -48, -48, 4, 71, 99, 69, 3, -63, -99, -88, -30, 46, 92, 78, + 16, -45, -66, -44, -6, 25, 34, 16, -24, -55, -43, 10, 67, 80, 37, -22, + -48, -29, 7, 30, 27, -5, -51, -84, -73, -11, 71, 116, 95, 27, -43, -84, + -84, -43, 18, 63, 60, 10, -44, -53, -9, 41, 49, 14, -31, -57, -50, -15, + 29, 61, 57, 14, -37, -51, -14, 38, 63, 47, -1, -61, -106, -105, -47, 44, + 115, 113, 42, -36, -64, -42, -2, 23, 20, -3, -28, -39, -21, 24, 64, 59, + 7, -48, -67, -47, -7, 36, 59, 47, 2, -55, -77, -31, 55, 111, 89, 7, + -75, -113, -96, -42, 21, 62, 64, 28, -13, -18, 17, 45, 28, -2, -7, -6, + -7, -7, -8, -8, -8, -8, -7, -6, -5, -4, -3, -3, -2, -2, -1, 0, + 1, 2, 4, 5, 6, 8, 9, 10, 11, 12, 13, 13, 14, 15, 16, 17, + 17, 17, 17, 17, 16, 16, 15, 15, 14, 14, 13, 12, 10, 10, 9, 8, + 7, 6, 5, 5, 4, 3, 2, 1, 0, -2, -3, -4, -5, -6, -7, -8, + -9, -10, -11, -12, -13, -13, -14, -14, -14, -14, -14, -15, -15, -15, -15, -16, + -16, -14, -14, -12, -10, -13, -10, -13, -7, -3, -5, -1, -1, -5, -5, 8, + 13, 10, 10, 15, 16, 17, 30, 34, 19, 17, 22, 29, 27, 22, 16, 1, + -3, 8, 18, 11, 6, 8, 8, 1, 6, 18, 5, -8, -4, 4, 5, 3, + 5, -3, -6, 12, 30, 23, 9, 5, 6, 9, 15, 27, 20, 2, 0, 10, + 17, 8, -1, -4, -8, -8, -3, -7, -19, -28, -24, -22, -31, -42, -47, -50, + -50, -42, -35, -35, -43, -41, -31, -27, -23, -17, -9, -7, 3, 26, 37, 38, + 37, 41, 39, 39, 49, 55, 50, 46, 53, 58, 51, 44, 36, 24, 9, 5, + 2, -12, -25, -28, -26, -33, -42, -44, -55, -66, -69, -62, -60, -65, -57, -42, + -33, -26, -15, -5, -6, 0, 15, 29, 34, 41, 55, 61, 62, 68, 71, 62, + 49, 49, 49, 39, 29, 24, 14, -2, -10, -16, -34, -56, -67, -70, -77, -83, + -85, -88, -93, -92, -79, -74, -78, -74, -61, -49, -41, -23, -9, -2, 11, 35, + 54, 56, 58, 64, 69, 73, 81, 91, 86, 77, 78, 77, 67, 50, 39, 24, + 6, -4, -10, -22, -41, -49, -52, -62, -73, -81, -87, -98, -97, -83, -74, -70, + -63, -46, -33, -23, -6, 9, 18, 26, 48, 69, 77, 85, 97, 106, 107, 111, + 114, 104, 89, 83, 84, 75, 60, 50, 34, 13, -5, -16, -34, -59, -74, -80, + -86, -95, -97, -96, -104, -104, -95, -86, -86, -82, -66, -49, -32, -11, 12, 26, + 36, 55, 73, 81, 84, 94, 104, 107, 114, 120, 116, 102, 92, 88, 73, 54, + 37, 21, 0, -16, -23, -37, -58, -76, -85, -94, -108, -114, -116, -120, -119, -106, + -89, -84, -78, -64, -49, -37, -21, 1, 13, 25, 46, 71, 88, 95, 105, 113, + 112, 113, 116, 112, 97, 91, 91, 83, 68, 51, 35, 11, -10, -23, -38, -60, + -80, -86, -93, -102, -107, -110, -116, -121, -114, -102, -98, -93, -77, -55, -38, -18, + 1, 13, 25, 46, 71, 88, 95, 105, 113, 112, 113, 116, 112, 97, 91, 91, + 83, 68, 51, 35, 11, -10, -23, -38, -60, -80, -86, -93, -102, -107, -110, -116, + -121, -114, -102, -98, -93, -77, -55, -38, -18, 1, -3, -7, -8, -3, 1, 0, + 3, -5, -9, -14, -15, -4, 0, 7, 12, 12, 11, 18, 16, 14, 14, 11, + 20, 14, 19, 7, 12, 8, 13, 8, 7, 9, 0, 9, -7, -4, -5, -8, + -7, -9, -7, -2, -7, -4, 1, 1, 0, -2, 3, 2, 1, 2, 1, -2, + -3, -7, -2, -2, -2, -5, -4, -4, -4, 3, 6, 8, 3, 0, -3, -2, + 3, 4, 3, 2, 2, -2, 1, 0, 2, 3, 9, 8, 2, -3, -4, -2, + 1, 4, 0, -2, 3, 1, 7, 1, -4, 0, 2, 3, 1, 1, 2, -5, + 3, -3, -4, -3, -8, 2, -7, 1, -3, -2, -5, -8, -7, -8, -7, -5, + -7, -4, -8, -10, -7, -8, -7, -5, 0, -2, 0, -2, -3, -3, -2, 0, + 1, 0, 1, 0, -3, -3, -5, -5, -9, -9, -13, -16, -21, -26, -25, -25, + -16, -16, -12, -13, -15, -9, 3, 25, 44, 66, 68, 66, 49, 17, 13, 18, + 41, 51, 40, 35, 25, 23, -2, -16, -28, -8, -4, -12, -18, -34, -29, -31, + -28, -18, -4, 2, 16, 13, 20, 9, 4, 2, -3, -4, -9, -9, -9, -8, + -9, -10, -13, -14, -15, -13, -4, 7, 13, 19, 18, 16, 9, 7, 4, 6, + 8, 7, 7, 3, -3, -15, -19, -24, -21, -16, -9, 0, 3, 7, 4, 4, + -3, -2, 6, 13, 20, 14, 16, 14, 11, 7, 0, -4, -3, -3, -7, -12, + -12, -9, -5, -5, -7, -9, -4, -2, -2, -2, -4, -9, -10, -13, -13, -14, + -15, -13, -9, -8, -9, -9, -7, -4, 2, 2, 6, 9, 8, 11, 9, 11, + 9, 8, 6, 0, -7, -13, -21, -29, -36, -45, -53, -63, -72, -73, -61, -41, + 0, 52, 98, 109, 81, 64, 54, 78, 77, 45, 39, 44, 25, 19, 6, -8, + 25, 30, 44, 62, 46, -20, -85, -89, -88, -47, -29, -30, 2, 11, 8, 12, + 24, 33, 29, 25, 22, 1, -15, -34, -37, -36, -41, -36, -28, -15, 2, 9, + 11, 14, 12, 8, 12, 17, 18, 19, 23, 20, 20, 20, 8, -5, -14, -15, + -15, -13, -13, -18, -19, -24, -29, -32, -31, -23, -12, -2, 12, 20, 23, 24, + 25, 20, 22, 18, 16, 14, 9, 7, 2, 1, -9, -10, -19, -15, -12, -13, + -8, -5, -4, -4, -7, -10, -12, -12, -16, -14, -8, -9, -13, -14, -18, -15, + -10, -5, -3, 3, 4, 6, 11, 13, 13, 16, 16, 16, 12, 6, -3, -10, + -16, -21, -28, -37, -48, -61, -77, -88, -87, -68, -34, 28, 92, 127, 99, 64, + 50, 72, 92, 55, 43, 51, 41, 32, 4, -8, -7, -17, -23, -31, -33, -35, + -32, -28, -23, -18, -12, -8, -4, -2, 0, 1, 2, 2, 3, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 3, 4, 6, 7, 7, 7, 8, 9, 9, 8, + 8, 9, 11, 14, 18, 22, 27, 32, 33, 30, 21, 6, -12, -30, -45, -54, + -56, -51, -41, -29, -17, -9, -3, 0, 1, 1, 1, 1, 1, 1, 1, 2, + 2, 3, 3, 3, 3, 3, 2, 3, 4, 5, 8, 9, 10, 9, 8, 7, + 7, 8, 10, 15, 20, 25, 30, 35, 39, 39, 32, 19, 0, -22, -42, -56, + -62, -61, -53, -40, -27, -15, -7, -3, -1, 0, 0, 0, 0, 2, 3, 4, + 5, 5, 5, 4, 2, 0, -1, 0, 2, 5, 8, 9, 10, 10, 9, 9, + 8, 9, 10, 14, 19, 24, 28, 32, 34, 38, 36, 29, 17, -5, -28, -49, + -61, -65, -61, -52, -39, -25, -14, -7, -3, -2, -1, -2, -1, 0, 2, 4, + 6, 7, 7, 5, 3, 0, -1, -1, 0, 3, 7, 11, 13, 14, 13, 12, + 10, 8, 8, 9, 12, 17, 22, 26, 29, 31, 33, 31, 26, 18, 3, -16, + -35, -50, -59, -61, -56, -46, -35, -23, -14, -6, -2, 0, 1, 2, 3, 4, + 4, 5, 5, 5, 4, 2, 1, -1, -1, 0, 2, 5, 9, 12, 13, 13, + 12, 11, 9, 7, 7, 8, 11, 15, 20, 24, 29, 33, 35, 34, 30, 21, + 4, -16, -37, -55, -66, -68, -63, -50, -35, -21, -9, -1, 4, 5, 5, 4, + 4, 3, 3, 3, 3, 2, 2, 1, 0, -1, -1, 1, 6, 10, 13, 15, + 15, 13, 11, 8, 5, 4, 4, 7, 11, 17, 22, 27, 32, 36, 39, 39, + 36, 24, 6, -20, -48, -70, -81, -79, -67, -48, -29, -12, -1, 5, 7, 7, + 4, 2, 1, 1, 2, 2, 3, 2, 2, -1, -2, -3, -3, -1, 3, 8, + 13, 16, 17, 16, 12, 8, 3, -1, -3, -2, 2, 11, 21, 29, 36, 38, + 39, 42, 48, 57, 52, 23, -27, -76, -107, -113, -98, -71, -42, -18, -1, 8, + 12, 13, 10, 7, 3, 1, 1, 2, 3, 2, 1, 0, -2, -3, -3, -1, + 2, 8, 13, 17, 18, 17, 12, 7, 1, -3, -4, -3, 20, 30, 38, 41, + 39, 38, 46, 65, 75, 45, -23, -89, -126, -127, -101, -64, -31, -7, 5, 11, + 13, 14, 13, 9, 4, 1, 0, 1, 2, 1, -1, -3, -4, -4, -2, 2, + 6, 10, 14, 18, 18, 15, 9, 1, -6, -10, -13, -10, -4, 7, 20, 0, + 14, 19, 23, 26, 28, 28, 26, 23, 18, 11, 3, -4, -10, -16, -21, -23, + -24, -22, -20, -16, -12, -8, -3, 3, 8, 13, 19, 23, 26, 27, 26, 23, + 17, 10, 4, -3, -9, -15, -20, -24, -25, -25, -22, -17, -11, -3, 3, 9, + 14, 18, 20, 22, 23, 23, 21, 17, 13, 6, 1, -6, -11, -15, -18, -20, + -19, -19, -17, -16, -13, -11, -8, -5, -1, 2, 5, 7, 9, 9, 8, 6, + 3, 0, -3, -7, -10, -14, -17, -19, -19, -18, -16, -12, -7, -2, 3, 8, + 13, 16, 18, 19, 17, 14, 8, -1, -11, -21, -31, -38, -41, -40, -34, -25, + -12, 2, 17, 32, 45, 56, 62, 65, 63, 58, 49, 38, 25, 10, -6, -18, + -28, -37, -44, -51, -59, -64, -64, -56, -40, -17, 7, 29, 46, 56, 58, 59, + 56, 51, 45, 33, 19, 4, -13, -26, -39, -49, -56, -59, -55, -46, -34, -19, + -4, 10, 21, 30, 40, 46, 51, 52, 49, 43, 31, 18, 5, -8, -16, -21, + -23, -26, -29, -35, -39, -42, -40, -34, -22, -11, 2, 11, 18, 21, 24, 23, + 22, 19, 14, 7, -3, -13, -21, -30, -39, -46, -50, -52, -49, -42, -31, -17, + -3, 12, 26, 39, 49, 57, 60, 58, 51, 39, 22, 1, -23, -47, -68, -82, + -89, -88, -77, -60, -37, -11, 16, 43, 65, 83, 94, 100, 101, 96, 87, 71, + 51, 29, 4, -18, -38, -58, -75, -91, -104, -109, -105, -87, -61, -27, 8, 39, + 67, 87, 97, 97, 88, 71, 54, 36, 16, -2, -23, -42, -57, -70, -75, -75, + -71, -60, -43, -23, -1, 18, 31, 47, 57, 66, 71, 68, 61, 49, 32, 17, + 1, -11, -22, -33, -41, -47, -54, -59, -63, -62, -57, -46, -30, -12, 1, 17, + 30, 41, 49, 50, 47, 40, 29, 17, 3, -14, -30, -46, -60, -70, -76, -77, + -73, -63, -48, -28, -4, 20, 44, 65, 81, 91, 93, 88, 77, 60, 37, 11, + -19, -49, -76, -97, -109, -110, -100, -81, -56, -25, 7, 38, 67, 91, 109, 121, + 127, 126, 116, 96, 68, 38, 8, -18, -43, -68, -90, -110, -124, -127, -116, -91, + -59, -22, 14, 47, 77, 98, 107, 105, 93, 74, 54, 33, 13, -6, -26, -45, + -60, -71, -78, -79, -74, -61, -42, -21, 1, 18, 33, 49, 60, 68, 73, 70, + 62, 48, 32, 15, 0, -13, -24, -34, -42, -48, -55, -61, -65, -65, -60, -48, + -32, -15, 2, 19, 32, 43, 50, 51, 47, 40, 28, 16, 1, -14, 2, -2, + 2, -5, -3, -1, 0, -4, -4, -6, -4, -6, -4, -4, -7, -6, -7, -6, + -1, 0, 3, 13, 14, 16, 12, 13, 2, 1, 0, -1, -1, -1, -2, -2, + -2, -3, -3, -4, -8, -4, -4, -5, -5, -5, -7, -9, -12, -8, -14, -11, + -14, -18, -8, 1, 31, 71, 68, 24, -5, -11, -7, -5, -5, -5, -3, -2, + -5, -5, -9, -8, -7, -7, -9, -12, -11, -17, -14, -16, -15, -20, -26, -30, + -27, -15, 16, 51, 87, 101, 70, 8, -18, -11, -14, -7, -7, -1, -2, -5, + -7, -12, -14, -10, -10, -13, -14, -13, -16, -16, -17, -18, -35, -31, -30, -34, + -9, 16, 56, 84, 89, 60, 30, 5, -7, -5, -8, -3, -4, -4, -6, -12, + -14, -13, -10, -12, -12, -9, -10, -8, -12, -13, -15, -19, -23, -26, -33, -29, + -28, -9, 12, 43, 71, 88, 72, 48, 29, -2, -16, -19, -12, -12, -12, -7, + -11, -10, -10, -10, -11, -13, -15, -18, -19, -17, -16, -15, -13, -12, -13, -9, + -13, -17, -21, -18, 2, 34, 59, 87, 92, 98, 38, -30, -24, -27, -18, -16, + -11, -11, -13, -15, -12, -14, -15, -18, -17, -20, -18, -15, -10, -7, -3, -1, + 2, -8, -11, -22, -22, -20, 7, 31, 61, 97, 106, 43, -23, -28, -25, -20, + -12, -7, -5, -7, -10, -13, -13, -13, -11, -14, -15, -15, -12, -8, -7, -4, + -2, -4, -10, -15, -19, -26, -10, 12, 42, 72, 101, 90, 20, -25, -27, -22, + -18, -10, -6, -9, -11, -16, -17, -16, -14, -10, -8, -9, -9, -9, -9, -9, + -8, -5, -3, -6, -10, -17, -24, -21, 4, 30, 61, 84, 96, 79, -16, -38, + -27, -26, -17, -12, -8, -12, -13, -14, -14, -11, -8, -4, -4, -7, -9, -8, + -10, -12, -8, -5, -4, -7, -10, -18, -24, -11, 14, 42, 70, 79, 93, 36, + -32, -26, -28, -19, -15, -9, -9, -13, -16, -14, -12, -8, -5, -3, -7, -9, + -9, -9, -11, -8, -5, -1, -6, -9, -15, -24, -23, 6, 28, 63, 86, 127, + 37, -45, -27, -28, -26, -19, -4, -5, -8, -11, -12, -14, -12, -8, -4, -8, + -8, -10, -8, -13, -8, -8, -3, -8, -8, -16, -23, -17, 7, 34, 69, 83, + 113, 37, -50, -28, -25, -22, -16, 0, -3, -8, -12, -12, -14, -14, -10, -5, + -7, -6, -9, -9, -13, -9, -10, -7, -9, -9, -15, -20, -14, 8, 33, 64, + 81, 90, 57, -29, -28, 0, -4, 10, 10, 11, -15, 4, -1, 3, -11, 11, + 2, -12, 3, 18, -10, -62, 89, -16, -95, 118, -128, 122, -128, 112, -100, 109, + -121, 120, -104, 58, 10, -88, 127, -102, 6, 98, -126, 35, 89, -111, -7, 112, + -53, -94, 92, 64, -106, -53, 109, 52, -100, -75, 86, 95, -45, -119, -12, 111, + 74, -58, -118, -27, 97, 100, -4, -107, -95, 17, 109, 92, -4, -99, -109, -26, + 78, 115, 66, -27, -104, -109, -41, 55, 112, 98, 32, -53, -109, -105, -44, 41, + 102, 109, 67, -4, -74, -112, -102, -47, 27, 88, 112, 93, 45, -19, -78, -110, + -105, -65, -4, 59, 101, 110, 87, 43, -13, -67, -103, -111, -89, -44, 13, 65, + 100, 109, 93, 59, 14, -36, -78, -104, -108, -90, -53, -6, 43, 83, 104, 106, + 88, 57, 17, -27, -66, -95, -108, -102, -80, -44, -2, 41, 77, 99, 106, 98, + 77, 46, 10, -29, -64, -91, -105, -105, -91, -64, -29, 10, 48, 78, 98, 105, + 100, 84, 59, 30, -3, -36, -65, -88, -101, -105, -99, -83, -60, -32, -1, 30, + 58, 80, 96, 103, 102, 94, 80, 62, 40, 16, -10, -35, -58, -78, -92, -101, + -104, -100, -91, -77, -58, -36, -13, 12, 36, 57, 75, 89, 98, 102, 102, 97, + 88, 76, 61, 44, 25, 5, -15, -35, -54, -70, -84, -94, -101, -104, -103, -98, + -89, -77, -63, -46, -27, -8, 12, 31, 49, 65, 79, 90, 97, 102, 104, 102, + 97, 90, 81, 70, 57, 42, 27, 10, -7, -24, -40, -56, -70, -81, -91, -99, + -103, -105, -105, -101, -95, -87, -76, -63, -49, -34, -18, -1, 16, 32, 48, 62, + 74, 85, 93, 100, 104, 105, 105, 102, 97, 90, 82, 72, 61, 48, 35, 21, + 6, -9, -24, -38, -52, -65, -76, -86, -94, -101, -105, -108, -108, -106, -102, -96, + -87, -78, -66, -54, -40, -26, -11, 4, 19, 34, 48, 61, 73, 83, 92, 99, + 104, 107, 108, 108, 105, 101, 96, 89, 80, 70, 60, 48, 36, 22, 9, -5, + -19, -33, -46, -58, -69, -80, -89, -96, -102, -107, -109, -110, -110, -107, -102, -97, + -89, -80, -70, -59, -47, -33, -20, -6, 7, 19, 30, 41, 50, 58, 65, 71, + 75, 78, 79, 80, 79, 77, 74, 70, 65, 60, 54, 48, 42, 36, 29, 22, + 16, 10, 4, -2, -7, -12, -16, -19, -22, -24, -26, -27, -27, -27, -26, -25, + -23, -22, -19, -17, -14, -12, -10, -1, -1, -4, -9, -9, -7, -6, -7, -3, + 4, 8, 10, 11, 13, 10, 4, -3, -10, -15, -13, -9, -10, -11, -5, 4, + 12, 14, 12, 13, 14, 9, 1, -8, -15, -21, -23, -22, -13, -3, 7, 17, + 24, 27, 19, 11, 16, 15, -5, -24, -29, -23, -27, -32, -21, 5, 18, 20, + 21, 24, 24, 15, 11, 8, -6, -30, -31, -19, -17, -24, -14, 2, 17, 15, + 12, 17, 16, 19, 8, -5, -2, -1, -17, -17, -3, 6, 5, -4, 0, 1, + -12, -9, 9, 11, -4, -14, -8, 9, -2, -21, -14, 4, 9, 9, 11, 18, + 21, 10, 8, 16, 10, 26, 35, 6, -14, -28, -25, -24, -55, -65, -33, -17, + 1, -6, -6, 8, 23, 33, 49, 37, 19, 16, 11, 24, 42, 17, -37, -36, + 3, 7, -23, -36, -9, 9, -12, -20, -8, -2, -4, -23, -17, -6, 0, 10, + 24, 24, 40, 46, 33, 39, 26, 5, 6, 9, -12, -26, -33, -42, -61, -52, + -43, -37, -21, -4, 7, 13, 28, 36, 31, 24, 1, -1, 20, 24, 23, 21, + 26, 27, 8, -32, -44, -3, 28, -1, -36, -30, -6, 13, -12, -34, -18, -6, + 9, 21, 25, 16, 10, 38, 62, 46, 17, -11, -7, 10, -8, -44, -53, -33, + -35, -38, -29, -27, -16, 0, 1, 9, 37, 50, 36, 2, -20, -12, 15, 21, + 24, 32, 29, 20, 23, 12, -8, -3, 4, -10, -5, 2, -19, -63, -70, -21, + 20, 41, 23, 33, 57, 61, 42, 21, 15, 10, -45, -82, -60, -29, -44, -77, + -50, -7, 4, -4, 10, 32, 56, 42, 1, -10, -18, 2, 22, 28, 33, 42, + 47, 43, 47, 11, -23, 0, 10, -40, -81, -70, -28, -29, -68, -29, 19, 6, + 7, 21, 40, 41, 32, 22, 28, 47, 69, 66, 35, 21, 15, -3, -20, -34, + -24, -6, -19, -59, -47, -42, -35, -28, 15, 45, 51, 66, 78, 83, 37, 1, + 13, 7, -51, -81, -92, -83, -87, -74, -58, -73, -51, 12, 35, 26, 35, 47, + 69, 70, 63, 65, 49, 47, 68, 73, 52, 33, 15, -12, -30, -50, -51, -46, + -45, -60, -50, -50, -50, -54, -24, 38, 78, 90, 106, 99, 40, -6, -11, -46, + -110, -127, -107, -76, -67, -53, -41, -41, -23, 14, 33, 27, 34, 49, 70, 71, + 66, 65, 51, 51, 69, 72, 52, 32, 10, -12, 0, -5, -2, -5, 2, -29, + 22, 0, -27, 67, -59, 45, -13, -37, 28, 65, -4, 6, 60, 5, 58, 44, + 60, 27, 43, 96, 71, 81, 48, 96, 70, 23, 90, 66, 80, 88, 40, 20, + 61, 64, 12, 36, 24, 4, 7, 5, -27, -38, -26, -33, -49, -50, -70, -69, + -93, -92, -94, -104, -104, -101, -110, -107, -111, -111, -126, -87, -119, -100, -94, -112, + -93, -93, -80, -81, -76, -58, -56, -70, -30, -21, -42, -13, -3, 2, 8, 20, + 28, 41, 45, 59, 62, 69, 84, 85, 90, 103, 109, 111, 118, 121, 121, 123, + 121, 122, 121, 122, 121, 122, 121, 121, 120, 121, 120, 121, 120, 121, 120, 120, + 119, 120, 119, 120, 118, 105, 106, 110, 83, 89, 92, 75, 67, 61, 57, 47, + 40, 33, 24, 17, 10, 3, -2, -10, -20, -31, -31, -37, -49, -50, -63, -66, + -69, -74, -79, -91, -89, -92, -95, -102, -106, -104, -107, -113, -113, -110, -113, -116, + -114, -115, -114, -115, -114, -113, -114, -113, -114, -113, -112, -113, -109, -105, -111, -106, + -107, -103, -100, -103, -99, -97, -98, -99, -92, -92, -93, -92, -92, -90, -88, -90, + -88, -86, -89, -85, -85, -87, -85, -85, -82, -83, -82, -80, -78, -79, -76, -74, + -73, -73, -69, -68, -66, -64, -65, -62, -58, -56, -56, -52, -50, -47, -43, -42, + -39, -35, -33, -31, -27, -23, -21, -16, -16, -8, -7, -3, 1, 0, 10, 15, + 15, 19, 26, 29, 30, 38, 41, 42, 47, 54, 54, 57, 63, 68, 69, 72, + 77, 78, 80, 85, 84, 86, 87, 86, 87, 86, 85, 86, 85, 84, 85, 84, + 83, 84, 83, 82, 82, 83, 82, 81, 82, 81, 80, 81, 80, 79, 80, 79, + 79, 78, 79, 78, 78, 77, 74, 70, 66, 64, 61, 55, 52, 49, 45, 40, + 35, 32, 29, 24, 19, 15, 12, 8, 4, 0, -4, -8, -11, -15, -17, -20, + -25, -26, -29, -32, -34, -37, -39, -41, -43, -45, -46, -48, -49, -50, -50, -52, + -52, -53, -52, -53, -54, -53, -53, -52, -52, -51, -50, -50, -49, -48, -48, -46, + -45, -44, -42, -41, -40, -39, -37, -35, -34, -32, -30, -28, -27, -24, -23, -22, + -20, -19, -17, -15, -14, -13, -12, -10, -9, -8, -8, -6, -6, -5, -4, -4, + -3, -3, -2, -2, -1, -2, -1, -2, -1, -1, 0, -1, -1, 1, 0, 0, + -3, -1, 1, -4, -4, -3, -2, -5, -3, 0, -1, -1, -3, -1, 0, 2, + 0, -2, -5, 5, 4, 1, 7, 2, 2, 1, 8, 1, 6, 2, -4, 2, + 1, -4, 6, -8, -3, -7, -2, -6, -1, -9, 1, -2, -4, 1, 2, 1, + -2, 8, 2, 0, 14, 9, 10, 5, 3, 5, 6, 4, 3, -8, -2, -4, + -10, -1, -5, -3, -4, -6, -13, -5, -4, -4, -3, 2, -13, -6, 3, 6, + 6, 7, 1, 1, 6, 6, 16, 13, 9, 10, 9, 2, 7, 10, 4, -4, + -3, -17, -7, -6, -6, -10, -17, -17, -10, -11, -9, -5, -6, -8, 2, 1, + 8, 19, 15, 18, 24, 19, 16, 17, 19, 11, 7, 1, -5, -8, -9, -15, + -8, -9, -14, -20, -19, -9, -18, -10, -13, -23, -13, -12, -7, 0, -1, 5, + 16, 12, 28, 30, 32, 34, 34, 19, 24, 23, 16, 11, 5, -7, -19, -17, + -16, -21, -26, -23, -32, -31, -30, -25, -26, -24, -19, -13, -9, -1, 0, 4, + 6, 13, 15, 19, 17, 13, 8, 8, 8, 7, 0, -4, -8, -10, -7, -5, + -6, -6, -9, -12, -8, -10, -9, -9, -11, -13, -12, -9, -4, -1, 4, 9, + 19, 27, 31, 26, 16, 14, 16, 16, 12, 1, -8, -14, -11, -9, -6, -11, + -11, -12, -14, -10, -11, -13, -15, -19, -23, -19, -14, -8, -5, -1, 8, 34, + 62, 59, 12, 14, 32, 22, 6, 20, 6, -9, -54, -16, -1, -19, 7, -15, + -13, -12, -14, -15, -14, -22, -24, -30, -30, -20, -12, -6, 3, 26, 66, 88, + 39, 0, 47, 36, -2, 26, -23, 21, 13, -6, -60, -42, 6, -22, 4, -18, + -16, -4, -16, -19, -24, -39, -31, -25, -32, -26, -11, 12, 55, 104, 75, 10, + 35, 62, 9, 26, -16, -8, 19, 3, -9, -61, -46, 2, -26, -7, -16, -10, + 2, -7, -22, -23, -38, -40, -37, -44, -33, -8, 37, 101, 124, 36, -5, 89, + 20, 38, 5, -26, 3, 1, 5, -28, -65, -21, 1, -22, -12, -26, 1, -7, + -10, -24, -26, -33, -37, -48, -50, -36, 5, 63, 122, 109, 7, 35, 84, 5, + 59, -36, -4, -11, -1, -5, -40, -55, -4, -15, -21, -16, -22, 5, -10, -17, + -20, -27, -23, -44, -54, -62, -23, 29, 114, 127, 51, 7, -2, -4, -2, 4, + 11, 14, 10, 2, -7, -9, -9, -15, -16, -7, 3, 2, -10, -21, -17, 6, + 10, -8, -28, -11, 45, 66, 64, 47, 36, 49, 49, 27, 9, -12, -18, -25, + -30, -11, 0, -5, 0, -1, -18, -36, -33, -18, -10, -13, -31, -26, -25, -17, + 4, 28, 70, 89, 48, 9, -32, -58, -56, -70, -57, -17, -38, -48, -35, -32, + -7, 35, 38, 53, 62, 44, 33, 27, -6, -35, -52, -65, -54, -40, -43, -30, + -25, 2, 63, 54, 34, 17, 34, 70, 60, 8, -15, -3, 0, 39, 55, 35, + 39, 60, 75, 36, 20, -7, -25, -66, -110, -89, -89, -71, -36, -12, 9, 31, + 41, 54, 46, 45, 59, 41, 22, 3, -69, -110, -126, -116, -64, -15, 9, 29, + 33, 30, 56, 42, 12, 23, 6, -27, -36, -21, -22, -32, -21, -30, -29, -5, + 9, 16, 22, -9, -12, 31, 24, -17, -41, -23, 32, 32, 26, 34, 64, 66, + 109, 104, 51, 5, 12, 16, -36, -58, -59, -66, -63, -82, -64, -23, -9, 11, + 16, 20, 19, 13, 12, 33, 37, 41, 46, 28, 7, -58, -93, -79, -64, -33, + -1, 22, -4, 2, 19, 4, -7, -3, -3, 5, 1, -10, -3, 12, -6, -38, + -29, -17, -5, 11, 2, -33, -20, 44, 42, 20, -30, -24, 9, 44, 38, 20, + 36, 71, 61, 86, 72, 25, -8, 10, 17, -35, -54, -63, -67, -70, -78, -58, + -16, -7, 19, 22, 20, 21, 29, 21, 16, 35, 36, 16, -8, -27, -61, -58, + -67, -43, 3, 35, 38, -2, -2, 10, -9, -29, -14, -5, -1, -5, 2, 12, + -6, -32, -23, -22, -16, -5, 3, -9, -29, 27, 56, 39, 11, -27, -28, 23, + 34, 28, 18, 20, 62, 82, 71, 74, 24, -4, 16, 18, -39, -54, -65, -61, + -52, -64, -49, -11, -4, 12, 17, 16, 25, 24, 6, 23, 36, 18, 18, -1, + -42, -50, -90, -43, 3, 35, 38, -2, -2, 10, -9, -29, -14, -5, -1, -5, + 2, 12, -6, -32, -23, -22, -16, -5, 3, -9, -29, 27, 56, 39, 11, -27, + -28, 23, 34, 28, 18, 20, 62, 82, 71, 74, 24, -4, 16, 18, -39, -54, + -65, -61, -52, -64, -49, -11, -4, 12, 17, 16, 25, 24, 6, 23, 36, 18, + 18, -1, -42, -50, -90, -43, 0, 1, 6, -11, 19, -25, 24, -15, 11, -6, + 1, 9, -6, -3, 11, -18, 28, -23, 8, 6, -2, -1, 0, -5, 18, -23, + 24, -28, 27, -12, -1, -2, 6, 4, -14, 19, -29, 42, -40, 22, -6, -3, + 14, -16, 4, 8, -9, 13, -22, 17, 5, -24, 37, -34, 20, -4, -11, 19, + -20, 21, -16, 1, 17, -17, 5, -9, 25, -31, 31, -40, 32, -11, -7, 4, + -4, 13, -23, 29, -40, 51, -49, 20, 3, -20, 38, -47, 34, -21, 14, -9, + 4, -13, 20, -29, 37, -57, 59, -48, 23, -5, -7, 5, -6, -5, 13, -17, + 9, -4, -12, 22, -19, -8, 10, -5, -7, 8, -18, 19, -13, 5, -12, 6, + -10, 18, -40, 66, -91, 82, -56, 17, 19, -51, 56, -45, 30, -19, 5, -6, + 7, -9, -4, -2, -5, 13, -19, 1, 20, -28, 13, -6, 0, -17, 33, -48, + 38, -16, -20, 53, -75, 75, -61, 30, -12, -9, 2, 5, -9, -7, 15, -17, + 9, 4, -46, 70, -85, 86, -67, 29, 18, -60, 76, -70, 29, -8, -1, 1, + 14, -58, 93, -118, 127, -125, 85, -36, -2, 17, -39, 46, -61, 70, -99, 122, + -120, 56, 15, -85, 116, -101, 30, 43, -108, 127, -122, 72, -38, -3, 20, -31, + 29, -37, 42, -50, 63, -72, 40, -7, -46, 66, -82, 53, -25, 1, 1, -1, + -3, 3, -24, 24, -34, 27, -24, 36, -49, 37, -38, 35, -42, 13, -4, -14, + 14, -29, 42, -58, 58, -60, 41, -39, 27, -35, 27, -32, 25, -37, 43, -50, + 32, -20, -4, 4, -14, 16, -43, 66, -93, 79, -58, 27, -11, -21, 34, -40, + 24, -7, -25, 31, -29, 19, -18, -2, 1, -6, 4, -31, 47, -63, 62, -64, + 32, 2, -29, 23, -21, 19, -41, 59, -76, 62, -52, 26, -11, -1, -10, 6, + -10, -7, 17, -42, 34, -12, -34, 73, -106, 92, -61, 26, -24, 8, -7, -2, + 3, -24, 31, -44, 27, -9, -22, 38, -43, 15, -4, -3, -2, -12, 5, 1, + -7, 7, -25, 17, -17, 4, -15, 27, -40, 34, -18, 6, -13, 12, -3, -9, + -6, 8, -18, 18, -36, 54, -55, 30, -25, 26, -41, 38, -49, 48, -38, 8, + 16, -40, 47, -52, 34, -12, -4, 2, -13, 0, 1, 6, -11, 19, -25, 24, + -15, 11, -6, 1, 9, -6, -3, 11, -18, 28, -23, 8, 6, -2, -1, 0, + -5, 18, -23, 24, -28, 27, -12, -1, -2, 6, 4, -14, 19, -29, 42, -40, + 22, -6, -3, 14, -16, 4, 8, -9, 13, -22, 17, 5, -24, 37, -34, 20, + -4, -11, 19, -20, 21, -16, 1, 17, -17, 5, -9, 25, -31, 31, -40, 32, + -11, -7, 4, -4, 13, -23, 29, -40, 51, -49, 20, 3, -20, 38, -47, 34, + -21, 14, -9, 4, -13, 20, -29, 37, -57, 59, -48, 23, -5, -7, 5, -6, + -5, 13, -17, 9, -4, -12, 22, -19, -8, 10, -5, -7, 8, -18, 19, -13, + 5, -12, 6, -10, 18, -40, 66, -91, 82, -56, 17, 19, -51, 56, -45, 30, + -19, 5, -6, 7, -9, -4, -2, -5, 13, -19, 1, 20, -28, 13, -6, 0, + -17, 33, -48, 38, -16, -20, 53, -75, 75, -61, 30, -12, -9, 2, 5, -9, + -7, 15, -17, 9, 4, -46, 70, -85, 86, -67, 29, 18, -60, 76, -70, 29, + -8, -1, 1, 14, -58, 93, -118, 127, -125, 85, -36, -2, 17, -39, 46, -61, + 70, -99, 122, -120, 56, 15, -85, 116, -101, 30, 43, -108, 127, -122, 72, -38, + -3, 20, -31, 29, -37, 42, -50, 63, -72, 40, -7, -46, 66, -82, 53, -25, + 1, 1, -1, -3, 3, -24, 24, -34, 27, -24, 36, -49, 37, -38, 35, -42, + 13, -4, -14, 14, -29, 42, -58, 58, -60, 41, -39, 27, -35, 27, -32, 25, + -37, 43, -50, 32, -20, -4, 4, -14, 16, -43, 66, -93, 79, -58, 27, -11, + -21, 34, -40, 24, -7, -25, 31, -29, 19, -18, -2, 1, -6, 4, -31, 47, + -63, 62, -64, 32, 2, -29, 23, -21, 19, -41, 59, -76, 62, -52, 26, -11, + -1, -10, 6, -10, -7, 17, -42, 34, -12, -34, 73, -106, 92, -61, 26, -24, + 8, -7, -2, 3, -24, 31, -44, 27, -9, -22, 38, -43, 15, -4, -3, -2, + -12, 5, 1, -7, 7, -25, 17, -17, 4, -15, 27, -40, 34, -18, 6, -13, + 12, -3, -9, -6, 8, -18, 18, -36, 54, -55, 30, -25, 26, -41, 38, -49, + 48, -38, 8, 16, -40, 47, -52, 34, -12, -4, 2, -13, -1, -2, -1, -4, + -3, -25, -41, 8, 16, 27, 2, 16, 1, 13, 21, -8, -6, -29, 17, 8, + 8, 20, -13, 5, 4, 25, 17, 30, 22, 14, 15, 19, 7, 51, -16, -15, + -32, -13, 12, -8, -17, -49, -27, -29, -29, -52, -66, -55, -32, -20, -41, -21, + -36, -11, -16, 22, 3, 19, 0, -6, -10, 0, -38, -17, -35, -19, -27, 0, + -35, -27, -9, -17, -14, -2, 20, 50, 63, 57, 49, 70, 70, 97, 81, 68, + 52, 78, 93, 98, 102, 56, 34, 20, 53, 60, 45, 24, -18, 21, -10, 0, + -38, -79, -38, -37, -13, -27, -41, -50, -51, 14, 10, 16, -21, -13, -22, -20, + -48, -53, -55, -66, -76, -65, -91, -105, -92, -87, -101, -79, -56, -34, -7, -4, + 7, 20, 15, 26, 29, 32, -8, 36, 47, 50, 66, 29, 18, -33, -11, -4, + -10, -24, -42, -31, -22, 2, -23, -75, -34, -36, 5, 1, 1, -17, -47, 20, + 43, 68, 28, 30, 9, 29, 7, -9, -5, -32, -46, -36, -15, -40, -35, -15, + -26, -21, 2, 21, 49, 62, 83, 87, 106, 77, 97, 94, 67, 60, 85, 79, + 110, 80, 61, 1, 8, 16, 50, 36, 2, -22, 4, -2, 21, -35, -33, -19, + 4, 24, 19, 10, -58, -23, 18, 45, 34, 8, -12, -6, -5, -48, -51, -75, + -72, -77, -37, -65, -80, -57, -66, -68, -38, -38, 2, 10, 38, 31, 58, 22, + 39, 37, 27, -9, 23, 9, 35, 18, 15, -31, -50, -44, -5, 6, -10, -63, + -41, -56, -15, -41, -71, -45, -37, 7, -6, 5, -56, -71, -6, 21, 41, 8, + -13, -14, -40, -30, -41, -40, -56, -31, -31, -9, -15, -5, 10, 42, 27, 73, + 82, 73, 73, 79, 70, 38, 28, 31, 23, 45, 42, 44, 30, -40, 8, 28, + 52, 30, -18, -29, -40, -14, -45, -50, -55, -68, -39, -6, -29, -45, -59, -32, + 4, 31, 23, 16, 20, 11, -1, 1, -28, -45, -53, -56, -67, -60, -55, -40, + -31, -25, -16, 11, 20, 36, 67, 70, 75, 77, 81, 65, 46, 38, 34, 39, + 51, 44, 57, 7, -4, 13, 37, 46, 19, -8, -29, -1, -9, -21, -32, -43, + -55, -58, -40, -8, 15, 29, 38, 44, 59, 63, 51, 20, -20, -47, -61, -58, + -48, -42, -43, -35, -15, 15, 41, 55, 61, 62, 70, 67, 45, 11, -31, -62, + -80, -78, -71, -62, -54, -39, -15, 18, 50, 68, 79, 83, 92, 88, 57, 16, + -31, -71, -94, -95, -90, -83, -71, -55, -28, 7, 49, 77, 93, 100, 109, 107, + 78, 36, -20, -71, -99, -104, -100, -92, -83, -69, -43, -5, 42, 79, 100, 108, + 114, 112, 90, 51, -9, -65, -100, -110, -105, -95, -87, -76, -52, -11, 35, 75, + 100, 107, 111, 106, 90, 52, -4, -60, -97, -109, -99, -87, -80, -65, -35, 5, + 43, 75, 91, 95, 93, 87, 71, 31, -19, -64, -93, -99, -88, -76, -66, -44, + -9, 28, 59, 79, 84, 80, 71, 59, 35, -5, -45, -76, -96, -95, -77, -59, + -39, -9, 28, 61, 86, 98, 93, 74, 52, 28, -6, -43, -72, -94, -108, -99, + -77, -52, -20, 19, 56, 84, 106, 115, 106, 79, 45, 3, -40, -74, -93, -108, + -112, -100, -79, -46, -1, 45, 78, 100, 113, 118, 108, 81, 39, -19, -67, -93, + -103, -108, -104, -94, -74, -32, 19, 61, 88, 102, 108, 109, 100, 73, 21, -44, + -87, -102, -104, -97, -90, -78, -49, 0, 46, 78, 90, 92, 89, 87, 77, 43, + -15, -72, -101, -104, -93, -79, -69, -47, -3, 47, 84, 96, 89, 74, 65, 58, + 37, -7, -61, -99, -110, -101, -82, -62, -38, 2, 49, 92, 112, 106, 82, 59, + 41, 18, -19, -61, -95, -111, -110, -98, -74, -39, 6, 54, 99, 122, 123, 104, + 79, 50, 12, -32, -72, -100, -111, -110, -106, -90, -54, -4, 49, 99, 123, 126, + 113, 95, 69, 24, -27, -72, -102, -114, -109, -104, -94, -64, -16, 36, 87, 116, + 121, 111, 97, 76, 36, -15, -61, -94, -110, -108, -98, -86, -60, -19, 29, 77, + 104, 109, 99, 86, 67, 35, -7, -47, -82, -98, -101, -92, -77, -48, -14, 25, + 67, 92, 95, 83, 66, 45, 18, -9, -37, -62, -77, -81, -78, -54, -16, 0, + 0, 0, 12, -10, 16, -14, -18, 17, -31, -2, 3, -19, -8, 17, 28, 37, + 31, -1, -25, -16, -47, -13, -43, -22, 6, 34, 41, 49, 41, 27, 6, -33, + -62, -54, -59, -32, -13, 29, 53, 73, 60, 54, 16, -19, -58, -77, -89, -42, + -46, 17, 55, 78, 86, 81, 33, -3, -35, -84, -110, -75, -70, 0, 39, 78, + 92, 105, 70, 13, -15, -82, -107, -103, -84, -41, 20, 81, 85, 127, 86, 39, + -4, -63, -103, -99, -107, -69, 2, 68, 82, 127, 84, 58, 28, -44, -88, -104, + -108, -83, -13, 29, 69, 116, 87, 77, 40, -16, -65, -89, -104, -89, -40, -1, + 47, 96, 90, 85, 52, 9, -38, -62, -96, -95, -62, -22, 21, 73, 78, 86, + 65, 35, -15, -41, -80, -92, -69, -48, 1, 43, 65, 80, 73, 49, 8, -23, + -59, -75, -74, -60, -22, 17, 49, 69, 65, 60, 25, -1, -36, -59, -70, -61, + -40, -9, 30, 52, 57, 63, 37, 17, -12, -41, -61, -57, -50, -30, 9, 30, + 49, 60, 47, 28, 6, -20, -49, -51, -53, -42, -11, 13, 34, 53, 50, 34, + 18, -3, -35, -39, -52, -49, -23, 0, 18, 41, 47, 36, 31, 10, -21, -28, + -43, -49, -31, -13, 2, 28, 39, 35, 38, 19, -7, -18, -33, -42, -36, -26, + -12, 19, 30, 34, 36, 22, 6, -5, -25, -38, -36, -29, -17, 8, 19, 26, + 35, 28, 12, 3, -17, -30, -29, -29, -22, -3, 9, 19, 33, 26, 14, 8, + -9, -18, -22, -28, -25, -9, 3, 15, 22, 20, 18, 12, 1, -11, -22, -24, + -21, -13, -3, 8, 11, 20, 21, 12, 5, -6, -19, -16, -17, -17, -7, 3, + 8, 20, 17, 7, 7, -2, -11, -13, -16, -17, -5, 2, 5, 12, 13, 8, + 6, 3, -9, -11, -9, -14, -5, 1, -3, 6, 11, 6, 7, 2, -6, -4, + -4, -10, -6, -3, -4, 5, 8, 2, 5, 4, -2, 0, -3, -9, -4, -3, + -3, 2, 3, 0, 6, 4, 0, -1, -2, -2, 0, 0, 0, 12, -10, 16, + -14, -18, 17, -31, -2, 3, -19, -8, 17, 28, 37, 31, -1, -25, -16, -47, + -13, -43, -22, 6, 34, 41, 49, 41, 27, 6, -33, -62, -54, -59, -32, -13, + 29, 53, 73, 60, 54, 16, -19, -58, -77, -89, -42, -46, 17, 55, 78, 86, + 81, 33, -3, -35, -84, -110, -75, -70, 0, 39, 78, 92, 105, 70, 13, -15, + -82, -107, -103, -84, -41, 20, 81, 85, 127, 86, 39, -4, -63, -103, -99, -107, + -69, 2, 68, 82, 127, 84, 58, 28, -44, -88, -104, -108, -83, -13, 29, 69, + 116, 87, 77, 40, -16, -65, -89, -104, -89, -40, -1, 47, 96, 90, 85, 52, + 9, -38, -62, -96, -95, -62, -22, 21, 73, 78, 86, 65, 35, -15, -41, -80, + -92, -69, -48, 1, 43, 65, 80, 73, 49, 8, -23, -59, -75, -74, -60, -22, + 17, 49, 69, 65, 60, 25, -1, -36, -59, -70, -61, -40, -9, 30, 52, 57, + 63, 37, 17, -12, -41, -61, -57, -50, -30, 9, 30, 49, 60, 47, 28, 6, + -20, -49, -51, -53, -42, -11, 13, 34, 53, 50, 34, 18, -3, -35, -39, -52, + -49, -23, 0, 18, 41, 47, 36, 31, 10, -21, -28, -43, -49, -31, -13, 2, + 28, 39, 35, 38, 19, -7, -18, -33, -42, -36, -26, -12, 19, 30, 34, 36, + 22, 6, -5, -25, -38, -36, -29, -17, 8, 19, 26, 35, 28, 12, 3, -17, + -30, -29, -29, -22, -3, 9, 19, 33, 26, 14, 8, -9, -18, -22, -28, -25, + -9, 3, 15, 22, 20, 18, 12, 1, -11, -22, -24, -21, -13, -3, 8, 11, + 20, 21, 12, 5, -6, -19, -16, -17, -17, -7, 3, 8, 20, 17, 7, 7, + -2, -11, -13, -16, -17, -5, 2, 5, 12, 13, 8, 6, 3, -9, -11, -9, + -14, -5, 1, -3, 6, 11, 6, 7, 2, -6, -4, -4, -10, -6, -3, -4, + 5, 8, 2, 5, 4, -2, 0, -3, -9, -4, -3, -3, 2, 3, 0, 6, + 4, 0, -1, -2, -2, 0, -1, -1, -3, -7, -14, -23, -32, -45, -55, -66, + -74, -83, -88, -80, -77, -71, -64, -54, -46, -37, -31, -25, -19, -12, -6, -1, + 4, 8, 12, 17, 21, 23, 25, 25, 27, 29, 32, 35, 36, 34, 32, 31, + 32, 35, 37, 37, 35, 31, 29, 29, 31, 33, 34, 32, 29, 26, 25, 27, + 30, 32, 31, 29, 27, 27, 29, 31, 34, 35, 35, 35, 36, 38, 41, 43, + 45, 47, 49, 52, 55, 57, 59, 61, 63, 66, 69, 70, 70, 68, 66, 63, + 61, 58, 54, 47, 36, 24, 11, 1, -9, -20, -33, -48, -64, -78, -89, -97, + -103, -110, -116, -123, -128, -128, -126, -121, -116, -112, -107, -102, -95, -88, -78, -69, + -61, -54, -47, -41, -34, -27, -21, -16, -12, -7, -2, 2, 5, 6, 8, 10, + 13, 16, 19, 19, 19, 17, 18, 19, 22, 24, 24, 22, 19, 18, 19, 21, + 23, 24, 22, 19, 17, 18, 20, 22, 24, 24, 22, 21, 22, 24, 27, 29, + 30, 30, 31, 32, 35, 37, 40, 42, 45, 47, 50, 53, 56, 58, 60, 62, + 66, 68, 70, 69, 68, 65, 63, 61, 59, 54, 46, 36, 24, 13, -1, -14, + -28, -43, -57, -68, -78, -86, -94, -102, -109, -114, -117, -117, -115, -112, -109, -106, + -101, -96, -89, -81, -73, -67, -59, -53, -46, -40, -34, -28, -23, -18, -13, -9, + -5, -2, 0, 2, 5, 7, 10, 12, 14, 15, 15, 15, 16, 18, 19, 20, + 20, 19, 18, 18, 19, 21, 22, 22, 21, 20, 19, 21, 23, 24, 25, 25, + 25, 25, 26, 29, 31, 33, 34, 35, 36, 38, 40, 43, 46, 48, 51, 53, + 56, 59, 62, 65, 68, 71, 74, 77, 78, 79, 78, 77, 76, 74, 71, 66, + 58, 49, 39, 28, 17, 6, -6, -20, -35, -50, -64, -75, -85, -94, -102, -110, + -117, -122, -124, -123, -121, -118, -114, -110, -106, -99, -92, -84, -76, -69, -61, -55, + -48, -41, -34, -29, -23, -18, -13, -9, -5, -2, 0, -1, -1, 0, 2, 0, + 3, 2, 2, 4, 5, 4, 4, 4, 4, 5, 3, 4, 3, 1, 2, 0, + 0, -1, -3, -4, -2, -3, -5, -3, -4, -5, -5, -4, -3, -3, -6, -5, + -4, -2, -5, -5, -2, -3, -3, -3, 1, 4, 4, 8, 8, 8, 13, 12, + 13, 14, 12, 9, 8, 6, 6, 3, -2, -2, -5, -5, -4, -5, -11, -16, + -12, -7, -3, -5, -10, -11, -6, -2, -2, -1, -4, -6, -6, -7, -8, -5, + -2, 2, 5, 6, 8, 8, 9, 13, 16, 16, 14, 11, 7, 5, 4, 2, + 0, -2, -3, -3, 0, -3, -13, -28, -11, 7, -1, -15, -1, -5, -18, -10, + 6, 11, -11, -1, -10, -14, -13, -13, -4, 4, 6, 14, 13, 10, 10, 15, + 17, 24, 24, 13, 12, 10, 1, 0, 2, -4, 0, -6, 2, 7, -22, -68, + 2, 35, -40, 14, -24, -3, -10, -9, -20, -3, 28, 2, -9, -12, -28, -19, + -4, -1, 15, 17, 17, 16, 12, 16, 22, 25, 28, 6, 17, 9, -1, -2, + -3, 2, 12, -6, 6, -5, -35, -89, 32, 28, -39, 20, -36, 9, -20, -9, + -34, 3, 34, 8, -16, -11, -37, -15, -3, 0, 26, 18, 13, 15, 13, 25, + 27, 29, 20, 3, 21, 2, -2, 0, -8, 11, 16, -1, 8, -21, -76, -81, + 87, -25, 4, -4, -23, 6, -26, -20, -35, 23, 28, 0, -18, -16, -43, 2, + -9, 17, 25, 15, 9, 18, 17, 37, 28, 35, 3, 14, 12, -5, -1, -1, + -5, 27, 0, 16, -11, -49, -128, 36, 40, -36, 35, -41, 21, -27, -14, -45, + 4, 24, 20, -23, -6, -41, -9, -1, 6, 23, 19, 5, 15, 14, 33, 35, + 40, 16, 5, 16, -3, -5, 4, -12, 24, 10, 18, 1, -38, -128, -21, 72, + -50, 42, -38, 19, -16, -16, -43, -10, 21, 24, -22, -11, -30, -15, 6, 4, + 22, 18, 6, 11, 13, 27, 39, 42, 22, 4, -3, -2, -2, -5, -3, -5, + -3, -2, -6, -5, -5, -6, -5, -3, -5, -3, -5, -4, -6, -3, -1, -2, + -1, 0, -2, 1, 2, 1, 4, 4, 5, 5, 5, 8, 10, 11, 9, 10, + 11, 8, 5, 10, 7, 5, 5, 0, -3, 1, 0, -5, -2, -8, -9, -7, + -7, -5, -9, -11, -9, -8, -8, -7, -9, -7, -6, -7, -5, -6, -5, -3, + -3, -3, -4, -4, -2, 0, 1, 2, 5, 9, 12, 16, 19, 22, 22, 24, + 22, 22, 19, 13, 11, 7, 7, 4, -2, -7, -9, -9, -8, -10, -14, -14, + -15, -15, -13, -14, -17, -18, -14, -12, -12, -8, -9, -7, -6, -6, -6, -8, + -9, -9, -11, -13, -11, -6, -1, 3, 9, 20, 27, 33, 37, 46, 46, 42, + 37, 28, 21, 14, 11, 10, 14, 20, -2, -40, -47, -22, -5, -4, -1, 4, + -15, -53, -56, -7, -33, -14, -2, -19, -7, -8, -15, -6, -9, -8, -3, -9, + -15, -18, -26, -19, -6, -5, -6, 0, 12, 22, 29, 30, 28, 32, 29, 21, + 15, 13, 5, 5, 3, 19, 30, 3, -68, -26, 2, -17, 17, -12, 15, -1, + -12, -48, -43, -19, -1, 3, 6, -8, -4, -10, -10, -4, 0, -6, -1, -7, + -9, -17, -12, -6, -9, -14, -5, 14, 33, 33, 41, 32, 41, 35, 20, 10, + 8, 4, 10, -2, 36, 40, 3, -110, -8, -7, -6, 16, -18, 27, -2, -4, + -56, -57, -33, 16, -2, 12, -11, -5, -17, -9, -5, 10, -6, 0, -12, -11, + -20, -10, -8, -12, -17, -3, 17, 38, 34, 45, 36, 51, 37, 18, 4, -3, + 3, 8, 8, 54, 48, -34, -128, 28, -33, 28, -13, 1, 21, 3, -20, -59, + -65, -10, 17, -1, 7, -17, -10, -19, -8, 5, 11, -4, -2, -16, -17, -20, + -9, -11, -18, -11, 3, 31, 36, 41, 41, 44, 53, 30, 10, 1, -13, 12, + -5, 42, 63, 43, -127, -55, 19, -27, 28, -1, 0, 3, 5, 8, 12, 14, + 15, 15, 14, 12, 8, 5, 1, -3, -9, -14, -17, -19, -18, -16, -12, -8, + -5, -4, -2, -1, -1, -2, -3, -4, -3, -2, -1, -1, 0, 0, 0, 2, + 8, 12, 16, 19, 23, 26, 34, 40, 39, 28, 11, -8, -26, -36, -40, -39, + -35, -27, -19, -10, -5, -6, -10, -12, -15, -14, -12, -9, -5, -3, -1, 1, + 6, 8, 7, 7, 7, 8, 13, 20, 28, 35, 43, 48, 55, 57, 51, 32, + 3, -29, -56, -68, -67, -60, -46, -31, -17, -7, -4, -7, -11, -15, -16, -15, + -10, -5, -1, 1, 3, 5, 7, 9, 11, 12, 12, 10, 13, 19, 26, 36, + 43, 51, 58, 65, 61, 40, 6, -30, -60, -75, -73, -64, -49, -32, -16, -5, + -1, -4, -11, -18, -23, -23, -19, -12, -5, 2, 8, 12, 13, 11, 9, 8, + 8, 10, 15, 21, 27, 32, 37, 42, 49, 55, 63, 55, 32, -3, -39, -66, + -79, -73, -56, -39, -24, -12, -7, -7, -12, -19, -24, -24, -21, -14, -6, 3, + 8, 11, 12, 11, 10, 10, 10, 11, 14, 17, 21, 27, 33, 41, 49, 56, + 63, 66, 49, 15, -27, -61, -82, -85, -73, -52, -33, -18, -9, -5, -7, -12, + -18, -21, -20, -15, -9, -1, 4, 8, 12, 15, 15, 14, 11, 8, 7, 10, + 15, 22, 32, 45, 59, 72, 86, 95, 75, 22, -40, -93, -119, -120, -97, -64, + -32, -9, 5, 9, 5, -3, -14, -21, -23, -20, -13, -5, 4, 12, 17, 18, + 15, 10, 7, 4, 3, 6, 9, 15, 21, 30, 40, 56, 77, 99, 99, 54, + -19, -86, -123, -127, -103, -66, -27, 1, 16, 18, 11, -1, -12, -21, -23, -21, + -16, -8, 1, 9, 16, 19, 16, 11, 8, 5, 5, 7, 9, 14, 19, 27, + 35, 49, 68, 90, 101, 73, 6, -66, -114, -128, -113, -78, -39, -6, 13, 19, + 11, -1, 0, 10, 30, 35, 40, 39, 37, 28, 18, 6, -9, -20, -30, -35, + -33, -30, -28, -23, -24, -23, -19, -20, -15, -11, -8, -3, 0, 1, 0, -2, + -4, -1, 0, 10, 15, 21, 27, 25, 25, 22, 13, 10, -5, -9, -15, -19, + -17, -17, -12, -7, 0, 4, 10, 8, 5, -5, -13, -23, -31, -30, -24, -13, + 11, 36, 62, 81, 83, 78, 54, 35, 19, -11, -29, -49, -57, -47, -35, -20, + -19, -26, -27, -33, -30, -26, -22, -11, -8, 3, 11, 6, 0, -16, -23, -23, + -11, 9, 23, 35, 45, 51, 46, 49, 26, 12, -13, -26, -37, -45, -31, -35, + -17, -4, 8, 23, 24, 23, 9, -10, -22, -37, -40, -38, -33, -12, 22, 67, + 100, 119, 111, 79, 50, 10, -12, -32, -52, -69, -62, -38, -14, -9, -21, -42, + -60, -50, -39, -19, -4, -1, 3, 15, 19, 2, -16, -43, -57, -48, -21, 19, + 38, 63, 66, 69, 74, 59, 39, 4, -33, -52, -67, -58, -39, -25, 2, 10, + 32, 35, 36, 18, -7, -25, -37, -31, -28, -23, -10, 11, 53, 101, 121, 123, + 92, 48, 11, -24, -42, -60, -66, -67, -48, -20, 2, -16, -41, -67, -87, -62, + -44, -10, 8, 19, 30, 34, 35, 4, -36, -66, -78, -75, -27, 22, 49, 83, + 91, 97, 90, 69, 39, -18, -61, -104, -98, -75, -32, 19, 47, 68, 70, 56, + 16, -33, -77, -89, -76, -47, 7, 35, 64, 100, 123, 125, 107, 60, 5, -39, + -76, -94, -101, -93, -69, -36, -3, 17, 10, -15, -56, -80, -86, -69, -40, -7, + 25, 49, 66, 72, 54, 19, -19, -55, -77, -67, -40, 4, 45, 76, 96, 100, + 92, 67, 32, -11, -56, -88, -91, -73, -33, 9, 41, 61, 65, 52, 17, -28, + -67, -80, -68, -36, 6, 47, 82, 114, 126, 114, 74, 18, -32, -73, -93, -101, + -93, -70, -36, -3, 17, 10, -15, 0, -1, -2, -2, 0, 2, 3, 6, 7, + 6, 6, 3, 2, -1, -4, -8, -12, -14, -13, -13, -11, -5, -1, 5, 10, + 14, 17, 19, 18, 15, 12, 7, 3, 1, -2, -4, -4, -7, -11, -13, -16, + -16, -12, -9, -6, -3, -1, -1, -1, -4, -8, -11, -15, -16, -15, -10, -2, + 7, 18, 25, 28, 28, 24, 16, 10, 4, -2, -5, -5, -4, -4, -1, 0, + 0, 1, 1, 0, -1, -3, -6, -11, -11, -14, -16, -17, -19, -19, -16, -10, + -2, 8, 19, 27, 33, 35, 32, 26, 21, 14, 7, 0, -6, -11, -18, -25, + -31, -32, -27, -19, -9, 1, 10, 15, 14, 10, 0, -13, -28, -38, -42, -40, + -26, -4, 17, 40, 58, 66, 62, 51, 35, 17, 3, -8, -16, -18, -18, -15, + -13, -15, -17, -17, -15, -13, -11, -12, -3, -2, 1, -3, -15, -28, -36, -42, + -40, -28, -11, 14, 45, 63, 70, 69, 56, 44, 36, 21, 3, -12, -18, -26, + -37, -47, -58, -55, -41, -20, 4, 22, 34, 43, 37, 22, -7, -43, -71, -88, + -86, -64, -31, 7, 56, 99, 115, 106, 85, 48, 17, 1, -14, -28, -33, -20, + -11, -12, -18, -37, -44, -41, -29, -23, -7, 15, 31, 40, 33, 8, -27, -56, + -73, -74, -63, -33, 4, 50, 93, 101, 91, 79, 56, 43, 24, 5, -17, -32, + -31, -43, -56, -63, -72, -57, -32, 3, 26, 46, 62, 63, 45, 9, -39, -85, + -112, -106, -84, -49, 6, 60, 104, 127, 115, 83, 46, 16, -1, -16, -21, -26, + -16, -2, -8, -25, -47, -67, -62, -49, -26, 2, 34, 60, 74, 65, 33, -21, + -71, -98, -92, -77, -36, 21, 69, 106, 112, 88, 58, 29, 9, -8, -18, -24, + -17, -4, -10, -26, -47, -67, -62, -49, -26, 2, 34, 60, 74, 65, 33, 17, + 16, -38, 9, 40, -58, 27, 43, -80, 52, -2, -54, 64, -27, -17, 32, 4, + -49, 53, -22, -47, 90, -73, 17, 42, -45, 8, 23, -41, -1, 58, -74, 40, + 25, -66, 56, -19, -45, 58, -9, -39, 45, 3, -48, 55, -41, -27, 78, -66, + 13, 40, -38, 0, 29, -51, 12, 57, -79, 38, 31, -64, 40, -4, -47, 63, + -16, -40, 55, -16, -32, 45, -31, -29, 76, -64, 0, 58, -49, 4, 31, -52, + 31, 5, -35, 45, -21, 4, -5, 3, -17, -7, 55, -72, 43, 35, -88, 80, + -57, 3, 45, -62, 53, -14, -2, -17, 46, -77, 42, 23, -61, 75, -54, 39, + -40, 31, -42, 25, 11, -48, 93, -97, 62, -27, -13, 7, 0, 30, -59, 82, + -74, 28, 10, -53, 65, -47, 46, -41, 40, -48, 7, 45, -95, 127, -99, 43, + -9, -25, 40, -58, 84, -84, 78, -66, 11, 50, -96, 111, -85, 51, -26, -14, + 36, -60, 91, -84, 58, -26, -22, 56, -87, 98, -71, 47, -25, -11, 44, -84, + 103, -92, 69, -32, -3, 25, -59, 87, -90, 70, -45, 17, 16, -57, 81, -73, + 50, -33, 14, 0, -35, 75, -84, 69, -42, 8, 11, -46, 74, -69, 57, -47, + 36, -26, -20, 69, -89, 83, -58, 37, -24, -7, 41, -58, 54, -53, 53, -42, + 14, 28, -54, 52, -55, 46, -41, 22, 30, -57, 58, -64, 56, -54, 26, 31, + -55, 63, -73, 66, -68, 49, -3, -38, 61, -71, 75, -87, 69, -15, -27, 37, + -55, 74, -84, 73, -34, -5, 26, -59, 74, -85, 84, -33, -12, 30, -57, 65, + -85, 86, -40, 9, 15, -50, 69, -94, 93, -53, 15, 11, -38, 58, -86, 96, + -64, 11, 21, -30, 17, -3, -3, 0, 0, -3, -4, -4, -3, -4, -4, -5, + -6, -6, -8, -5, -6, -3, 0, 2, 4, 7, 8, 12, 12, 14, 13, 13, + 12, 8, 7, 2, 2, -4, -6, -10, -11, -12, -12, -14, -10, -9, -3, -3, + 2, 3, 3, 2, 1, 1, -3, -3, -4, -3, -3, -3, -4, 0, -3, -3, + -3, 0, -3, 0, -3, 0, 1, 0, 0, 0, 0, 0, -3, 1, -3, 1, + -3, 2, 1, 0, 0, -3, -4, -5, -9, -10, -15, -16, -17, -17, -14, -10, + -3, 4, 9, 14, 19, 24, 25, 26, 28, 30, 34, 42, 31, 9, -31, -39, + -23, -15, -17, -23, -30, -23, -12, -10, 4, 9, 19, 13, 14, 6, 0, -9, + -11, -12, -9, -8, 0, 0, 2, 1, 1, -3, -3, -5, -3, -5, -3, -4, + 0, -3, -4, -4, -3, -5, -3, -5, -3, 0, 3, 2, 7, 7, 7, 3, + 0, -14, -17, -26, -26, -28, -21, -17, -11, -10, 2, 6, 19, 18, 32, 32, + 60, 69, 98, 60, 7, -58, -8, -8, -14, -39, -30, -14, -47, -21, -45, -3, + 7, 20, 14, 31, 12, 10, -15, -5, -23, -14, -15, -4, -8, 2, 1, 7, + -3, 2, -8, -4, -6, -6, -3, 0, -6, -6, -8, -10, -11, -12, -9, -9, + -4, -3, 0, 8, 10, 12, 15, 13, 4, -10, -15, -30, -32, -30, -23, -22, + -19, -14, -4, 3, 10, 14, 26, 40, 70, 102, 127, 62, -17, -39, 9, -25, + -9, -87, -12, -16, 0, -30, -27, -19, -9, 6, 18, 21, 19, 6, 0, -9, + -17, -14, -16, -8, -6, 0, 4, 4, -5, -4, -11, -3, -6, 2, 2, 0, + -6, 0, -2, -4, -8, -14, -21, -25, -28, -32, -36, -40, -44, -48, -51, -55, + -59, -63, -67, -71, -74, -78, -82, -86, -90, -94, -98, -101, -84, -60, -38, -15, + 8, 28, 27, 23, 19, 16, 11, 21, 46, 68, 93, 109, 106, 102, 98, 95, + 91, 87, 83, 79, 75, 71, 67, 64, 60, 56, 52, 49, 45, 41, 37, 33, + 30, 26, 22, 18, 15, 11, 7, 3, -1, -5, -9, -13, -17, -20, -24, -28, + -32, -35, -39, -43, -47, -51, -54, -58, -62, -66, -69, -73, -77, -81, -85, -89, + -93, -97, -100, -105, -95, -70, -48, -23, -7, -10, -14, -17, -22, -18, 4, 26, + 50, 72, 96, 107, 103, 100, 96, 92, 88, 84, 80, 76, 72, 68, 64, 61, + 57, 53, 49, 46, 42, 38, 34, 30, 26, 23, 19, 15, 11, 8, 4, 0, + -4, -8, -11, -15, -19, -23, -27, -30, -35, -38, -43, -46, -51, -54, -58, -61, + -66, -56, -31, -9, 16, 33, 30, 26, 22, 18, 15, 11, 7, 3, -1, -5, + -9, -13, -16, -20, -24, -28, -32, -36, -40, -43, -48, -51, -55, -59, -63, -50, + -26, -4, 20, 42, 64, 67, 62, 59, 55, 51, 47, 43, 39, 35, 31, 27, + 23, 20, 16, 12, 8, 4, 0, -4, -7, -11, -15, -19, -22, -27, -17, 8, + 30, 55, 72, 69, 65, 61, 57, 54, 50, 46, 42, 38, 34, 30, 26, 22, + 18, 15, 11, 7, 3, 0, -4, -8, -12, -15, -19, -23, -27, -31, -35, -38, + -42, -46, -50, -54, -57, -61, -65, -69, -73, -77, -81, -85, -89, -92, -96, -100, + -100, -79, -64, -47, -31, -15, 0, 0, -4, -3, -6, -8, 6, 10, -8, -13, + 22, 55, 15, -58, -102, -88, -25, 51, 77, 79, 82, 19, -45, -107, -128, -88, + 19, 81, 86, 71, 35, -16, -50, -73, -55, -27, -14, 7, 77, 89, 31, -22, + -27, -61, -86, -34, 40, 55, 67, 80, 57, -1, -48, -60, -41, -46, -31, 28, + 62, 47, 43, 33, -5, -34, -45, -52, -33, 26, 66, 70, 41, 17, -34, -79, + -93, -41, -6, 22, 53, 93, 62, 17, -20, -66, -118, -88, -4, 45, 60, 69, + 67, 2, -72, -109, -95, -78, -7, 67, 101, 78, 69, 19, -56, -110, -89, -64, + -19, 45, 100, 86, 36, -11, -65, -107, -108, -41, 24, 69, 93, 111, 56, -15, + -70, -81, -88, -38, 30, 88, 90, 83, 43, -24, -81, -82, -57, -24, 38, 100, + 115, 70, 26, -25, -75, -108, -66, -20, 29, 71, 105, 67, 7, -46, -67, -83, + -60, 0, 58, 82, 81, 57, -9, -72, -99, -78, -60, -8, 54, 95, 69, 44, + 0, -51, -92, -69, -26, 18, 53, 81, 63, 6, -44, -74, -88, -79, -19, 40, + 75, 75, 72, 18, -42, -80, -74, -69, -25, 32, 76, 66, 39, 5, -41, -82, + -76, -34, 3, 42, 79, 88, 38, -12, -49, -74, -92, -48, 8, 51, 70, 83, + 50, -7, -58, -68, -65, -43, 13, 70, 82, 62, 34, -17, -72, -94, -65, -28, + 17, 69, 101, 71, 25, -21, -60, -88, -66, -13, 37, 62, 82, 68, 11, -47, + -73, -79, -66, -15, 49, 82, 76, 57, 11, -51, -88, -78, -48, -9, 49, 0, + 0, 0, 0, 0, 0, -3, -5, -5, -7, -6, -2, 5, 16, 24, 21, 17, + 12, 3, -10, -31, -44, -47, -42, -28, -2, 26, 29, 36, 35, 1, -26, -39, + -52, -53, -38, -10, -32, -41, -7, 2, 22, 65, 89, 74, 15, -16, -24, 12, + 62, 39, 6, -12, -3, 47, 48, 21, 109, 127, 119, 53, -9, 19, 9, -50, + -55, -43, -71, -46, -5, -2, -20, -12, -9, 12, -27, -66, -50, -8, -19, -58, + -22, -8, -19, -34, -42, 10, 32, -4, 4, 46, 96, 34, -51, -10, -8, -93, + -70, -58, -46, -16, -32, -30, 6, 7, -41, -29, 3, 25, 73, 67, 45, 37, + 30, 83, 0, -31, -4, -50, -28, -41, -75, -110, -53, -13, -3, 22, 14, 14, + 13, 7, 9, 38, 47, 39, 17, -8, 90, 75, -5, -29, -46, -54, -102, -66, + -35, -27, -29, -21, 32, 5, 1, 1, -2, 16, 16, 19, 30, 50, 89, 41, + 6, 40, -10, -15, -41, -46, -43, -77, -100, -100, -48, -37, -26, -4, -9, 0, + 13, 36, 70, 75, 59, 34, 12, -13, -27, 37, 71, 48, 53, 37, 7, 8, + 34, 48, 40, 31, 25, 2, -20, -15, -5, 12, -11, -49, -20, 15, -13, -42, + -29, 16, -6, -58, -28, 17, 12, -20, -11, 16, -3, -37, -14, 3, -32, -10, + 40, 54, 53, 27, -3, -5, -34, -47, -49, -90, -68, -36, -32, -31, -16, 26, + 3, 0, -2, -2, 15, 16, 19, 30, 51, 88, 40, 6, 39, -10, 3, -2, + 11, -7, 23, 19, 74, 39, 32, -13, -21, -7, -39, -44, -128, -58, -21, 52, + -86, -74, -94, 75, 61, 72, -38, 13, 59, 116, 71, -9, -33, -12, 68, -2, + -35, -128, -42, -43, 39, -78, -57, -81, 56, 59, 63, -13, 7, 69, 98, 87, + -13, -9, -24, 70, -11, -23, -128, -42, -48, 28, -68, -61, -69, 34, 64, 46, + 8, -5, 79, 82, 100, -17, 5, -29, 69, -13, -21, -122, -49, -43, 11, -55, + -72, -54, 13, 73, 30, 23, -16, 87, 72, 107, -17, 10, -26, 64, -6, -26, + -109, -61, -31, -6, -40, -86, -41, -4, 80, 17, 31, -22, 88, 70, 106, -10, + 6, -16, 53, 7, -37, -93, -76, -17, -21, -28, -99, -33, -15, 83, 12, 31, + -21, 83, 76, 98, 2, -4, -1, 41, 24, -49, -77, -89, -6, -31, -20, -106, + -32, -19, 79, 14, 23, -15, 71, 87, 87, 17, -16, 13, 30, 39, -57, -67, + -97, -1, -34, -19, -106, -38, -16, 69, 23, 11, -5, 56, 100, 75, 32, -28, + 25, 22, 50, -59, -62, -98, -2, -30, -24, -100, -52, -9, 55, 36, -4, 5, + 41, 112, 67, 43, -34, 30, 21, 55, -53, -65, -93, -11, -18, -34, -88, -69, + 0, 41, 48, -17, 12, 29, 118, 65, 49, -34, 28, 27, 53, -42, -72, -83, + -23, -6, -44, -77, -85, 5, -69, 1, -12, -29, -28, -13, 1, 9, -4, -27, + -18, -5, 11, 65, 87, 54, 59, 66, 30, 12, 8, -6, -7, 4, -7, -39, + -59, -63, -48, -23, -13, -6, 22, 61, 68, 15, -59, -87, -41, 3, 5, -10, + -17, -17, -20, -23, -20, -28, -17, -3, -10, -29, 23, 11, 25, 52, 56, 62, + 80, 54, 22, -15, -31, -38, -5, 11, -9, -7, -36, -44, -6, 52, 127, 26, + -68, -125, -105, 22, 15, -27, -27, 13, 25, 69, 28, -42, -77, -57, -70, 15, + 44, 14, 26, 57, 69, 43, 33, 41, 33, 32, 25, -50, -98, -100, -38, 24, + 7, -35, -38, -2, 76, 64, 15, -79, -93, -50, -12, 27, 45, 32, -4, 23, + 6, -36, -47, -33, -52, -15, 37, 78, 49, 40, 17, 14, 14, 70, 81, 60, + -3, -4, -12, -42, -50, -28, -20, 5, 9, 27, 46, -13, -69, -99, -88, -47, + 5, -4, -10, 17, 39, -12, -8, -21, -16, 22, 9, -9, 1, 15, 15, 33, + 29, 17, 11, 38, 72, 29, -8, -36, -27, -42, 17, -40, 25, 25, 8, -3, + 14, 15, 2, 43, 33, -2, -19, -24, -8, 2, -69, -114, -94, -77, -87, 22, + 27, 19, 24, 57, 121, 94, 40, -27, -29, 4, 28, -12, 5, -21, -28, -18, + 0, -9, 1, 36, 22, 7, 6, 12, 7, 8, 55, 6, -2, -7, -13, -12, + -12, -8, -5, -5, -1, -4, -4, -3, -1, 5, 11, 15, 18, 16, 11, 5, + -5, -12, -16, -17, -14, -10, -7, -3, -2, -3, -3, -5, -3, 2, 9, 18, + 22, 23, 18, 11, -2, -14, -20, -22, -18, -12, -8, -5, -3, -5, -6, -6, + -5, 1, 11, 22, 30, 31, 24, 15, -1, -12, -20, -23, -19, -13, -8, -3, + -3, -2, -6, -8, -9, -5, 6, 21, 32, 35, 29, 19, 1, -15, -27, -29, + -25, -15, -9, -4, -1, -2, -7, -14, -15, -10, 4, 24, 42, 48, 43, 26, + 4, -20, -36, -38, -30, -17, -7, -3, 0, -1, -4, -16, -24, -19, -3, 26, + 49, 61, 60, 40, 9, -23, -45, -52, -39, -22, -5, -2, 1, 3, -2, -18, + -32, -30, -10, 22, 55, 77, 78, 52, 15, -22, -51, -66, -52, -29, -5, 0, + 2, 9, 6, -15, -37, -42, -22, 10, 55, 89, 99, 71, 22, -20, -58, -79, + -68, -35, -8, 6, 1, 12, 13, -9, -37, -50, -35, 0, 46, 93, 116, 90, + 33, -15, -60, -89, -84, -44, -9, 10, 3, 13, 19, -3, -35, -53, -43, -12, + 34, 91, 127, 109, 46, -9, -57, -95, -96, -57, -13, 11, 7, 10, 25, 2, + -2, -35, 0, 2, 7, 12, -7, -79, -68, 2, -6, -5, 19, 40, 33, 55, + 56, 17, 32, 32, 2, -20, 5, 51, 27, -21, -13, -11, -17, -20, -6, -63, + -125, -116, -86, -59, -34, 11, 23, 20, 39, 66, 50, 47, 54, 46, 11, -4, + 44, 67, 30, 11, 16, 6, -2, 7, -4, -77, -114, -107, -70, -50, -20, 29, + 26, 12, 48, 69, 44, 47, 49, 28, -8, 9, 53, 49, 15, 9, 8, -3, + -11, 7, -33, -107, -123, -101, -62, -49, -5, 25, 6, 13, 55, 49, 32, 40, + 39, 7, -17, 18, 49, 32, 7, 8, 1, -12, -3, 7, -62, -113, -109, -74, + -50, -31, 23, 32, 13, 40, 69, 48, 46, 54, 42, 2, 1, 42, 52, 25, + 10, 11, 0, -11, 10, -10, -90, -115, -101, -64, -52, -15, 29, 16, 10, 51, + 59, 41, 46, 49, 25, -9, 15, 48, 42, 15, 10, 7, -9, -7, 16, -43, + -107, -113, -89, -60, -47, 4, 27, 4, 19, 58, 47, 38, 46, 43, 6, -9, + 28, 47, 29, 10, 11, 2, -14, 5, 5, -73, -111, -106, -73, -56, -29, 24, + 22, 6, 40, 61, 43, 43, 52, 37, -3, 6, 41, 47, 23, 12, 11, 0, + -14, 1, 3, 5, 5, 6, 8, 6, 4, 0, -4, -5, -6, -9, -9, -11, + -11, -12, -13, -13, -13, -12, -11, -9, -5, -2, -1, 1, 4, 6, 9, 11, + 12, 12, 11, 8, 5, 2, -2, -2, -2, -2, 0, -1, -1, -2, -5, -5, + -5, -1, 4, 10, 17, 20, 22, 19, 15, 7, -1, -9, -15, -19, -21, -21, + -18, -16, -13, -11, -12, -15, -19, -23, -24, -20, -13, -3, 9, 20, 34, 44, + 50, 46, 35, 21, 7, -4, -14, -20, -19, -13, -8, 2, 0, -5, -15, -28, + -32, -29, -14, 0, 11, 27, 42, 58, 59, 45, 22, 4, -15, -26, -37, -43, + -42, -37, -17, 1, 18, 23, 8, -5, -29, -47, -47, -43, -25, -5, 20, 52, + 80, 92, 76, 43, 9, -20, -35, -38, -46, -41, -29, -12, 19, 35, 22, 4, + -34, -53, -58, -40, -26, -16, 14, 47, 88, 108, 90, 50, 16, -9, -36, -51, + -64, -64, -52, -33, -1, 32, 40, 24, 3, -29, -62, -58, -65, -52, -18, 23, + 68, 114, 127, 95, 41, 1, -36, -54, -56, -68, -55, -35, -17, 19, 42, 29, + 13, -16, -46, -60, -54, -56, -47, -11, 29, 72, 116, 127, 94, 41, -3, 0, + 16, 39, 54, 46, 18, 7, -15, -36, -9, -6, -16, -5, -15, -30, -23, -35, + -20, 22, 3, -19, -20, -13, -9, 19, 23, 10, 12, 35, 66, 54, 4, -43, + -58, -15, -10, 16, 55, 18, -39, -38, -30, 2, 9, 27, 51, -32, -60, -72, + -4, 32, 71, 19, -8, 56, -2, -42, 10, 21, -6, 31, -9, -70, 8, -6, + -19, -93, -20, -5, -31, 10, 5, 56, 24, -45, 11, 66, 48, 61, 89, 49, + -57, -6, -20, -69, -104, -83, -50, 32, 10, -16, -87, -78, 30, 127, 63, -17, + -91, -2, -12, 45, 83, 30, 56, 54, 42, 7, 79, -26, -52, -64, -97, 12, + -3, -107, -99, -39, 34, 86, 19, -25, 25, 90, -8, -38, 65, 36, 10, 30, + 36, 19, -6, 38, -47, -101, -52, -45, 30, -9, -106, 18, -10, -37, 16, 100, + -94, -111, -25, -35, -12, -8, -9, 51, 24, -5, -70, -52, -52, -19, -11, 48, + 93, 61, 17, 113, 125, 73, -16, -30, -57, -78, -116, -55, -38, -10, -5, -4, + 38, 31, -3, -46, -46, -50, -20, -10, 52, 84, 48, 14, 115, 119, 64, -16, + -1, 4, 0, -9, -11, -1, 6, 2, -2, 4, -6, -10, -2, 11, 14, 3, + -10, -15, -1, 17, 4, 6, 4, -12, -18, 6, 10, 4, 6, -8, -36, 2, + 3, 3, 5, 15, -20, -17, 9, 8, 11, 17, -8, -26, 18, 2, 5, 5, + 13, -24, -8, -2, 2, 5, 7, -21, -18, 13, 5, -5, 17, 7, -14, -13, + -12, 0, 14, 3, -12, -26, 13, 3, 10, 18, 12, -15, -14, -1, 3, 19, + 0, -10, -29, 11, 4, 17, 15, 12, -24, -20, 6, 9, 22, -3, -13, -15, + 9, 1, 7, 6, 18, -19, -26, -18, 2, 22, 0, -25, -20, 15, 8, -4, + 8, 31, -12, -20, -15, 9, 33, 9, -29, -2, 27, 7, -11, 8, 20, -20, + -41, -10, 15, 35, 15, -21, 11, 49, 6, -6, 4, 3, -48, -76, -35, 14, + 37, 22, -24, 29, 68, 20, 3, 7, -5, -68, -90, -59, 19, 36, 28, -13, + 59, 93, 30, 2, 18, -25, -88, -105, -81, 13, 26, 30, -4, 88, 109, 33, + 0, 22, -30, -88, -112, -76, 17, 31, 18, 5, 94, 114, 30, -4, 0, 4, + -30, -1, 0, -2, -2, -2, -1, 4, 11, 18, 30, 7, -64, -60, -30, -7, + 0, 2, 22, 67, 117, 23, -128, -74, -30, -5, -2, 1, 19, 62, 116, 38, + -123, -82, -31, -8, -1, -1, 16, 57, 114, 52, -117, -88, -33, -10, -2, -3, + 14, 52, 112, 64, -108, -96, -35, -13, -2, -4, 12, 49, 108, 77, -99, -102, + -37, -15, -2, -5, 10, 43, 104, 86, -87, -109, -40, -18, -2, -6, 8, 40, + 100, 95, -73, -115, -42, -21, -2, -8, 7, 35, 95, 102, -59, -120, -45, -24, + -2, -8, 5, 32, 90, 109, -44, -124, -49, -26, -3, -9, 3, 28, 85, 114, + -29, -126, -53, -28, -4, -9, 2, 25, 81, 116, -13, -127, -58, -29, -6, -9, + 0, 22, 75, 119, 3, -126, -63, -31, -7, -9, -2, 19, 70, 120, 18, -124, + -69, -32, -9, -9, -3, 16, 65, 119, 34, -63, -107, -58, -23, -11, -7, 7, + 46, 107, 89, -52, -109, -62, -25, -12, -8, 5, 42, 104, 97, -41, -87, -70, + -36, -18, -11, 0, 30, 85, 100, -2, -87, -5, 11, -23, -10, -3, -20, -3, + -17, -24, -33, -26, -1, -13, -12, -6, -9, 6, 25, 19, -7, -1, 22, -6, + -20, 13, 6, -12, 26, 48, 0, -7, 34, 23, 4, 32, 23, -41, -11, 49, + -3, -30, 35, 45, -14, -2, 62, 18, -44, -2, 26, -4, -28, -6, 16, 2, + -9, -9, 2, 18, 24, 9, -25, -57, -36, 30, 38, -21, -63, -37, 9, 37, + 40, 0, -56, -56, 3, 39, 20, -23, -52, -58, -46, 8, 67, 56, -18, -61, + -18, 36, 70, 95, 73, -35, -128, -127, -73, -17, 32, 48, 29, 28, 60, 106, + 113, 91, 36, -26, -67, -90, -91, -71, -44, -25, -13, 9, 36, 51, 69, 70, + 32, -40, -92, -99, -70, -25, 12, 29, 21, 3, -9, 10, 21, 12, -11, -22, + -27, -44, -23, 10, 30, 25, 24, 39, 18, 3, 8, 19, -1, -19, -8, 6, + 5, 13, 50, 43, 37, 36, 40, 37, 4, 12, -10, -33, -31, -25, -1, 1, + 7, 14, 10, -4, -11, -10, -6, -19, -42, -28, -54, -51, -18, -5, 3, 2, + -10, -10, 10, 28, 27, 16, 5, -5, -24, -26, -7, -14, -25, -16, 53, 33, + -49, -30, 53, 50, -24, -34, 40, 82, -118, -23, 120, -56, -70, -72, 106, -10, + -48, 3, 87, 28, -126, -16, 81, 4, -84, -51, 38, 62, -32, 36, 84, -12, + -41, 72, -42, -60, -64, 4, 77, -24, -79, -9, 122, 6, -94, 52, 43, 35, + 13, -62, -7, -89, 24, -30, 16, 29, 56, -59, 83, 42, 31, 36, -76, -2, + -128, -2, 45, 27, -104, -31, 66, 21, 19, 36, 121, 11, -76, -26, -93, 34, + 24, -34, -65, -53, 53, 17, 73, 46, 75, -9, -64, -21, -103, 41, 51, -41, + -83, -43, 108, 6, -11, 28, 127, 2, -84, -38, -72, 39, 17, -23, -15, -67, + 37, 6, 29, 64, 79, 17, -39, -39, -120, 55, 23, -17, -62, -51, 81, 23, + 20, 24, 99, -38, -99, 4, 17, -66, -41, -33, 63, 62, 16, 53, 91, 56, + -65, -36, -99, -38, 14, -47, -29, -38, 35, 83, 9, 48, 83, 62, -45, -31, + -103, -49, 14, 2, 6, -33, 33, -4, -1, 34, -93, 60, -49, 68, -21, 41, + -38, -38, 27, -87, 127, -34, 38, -3, -34, -2, -85, 79, -24, 4, 75, -23, + 11, -70, 1, -6, -6, 63, -48, 76, -71, 2, -7, -15, 46, -32, 48, -25, + -5, 10, -31, 18, -23, 5, 6, 17, 11, 3, 24, -46, -21, -1, -5, 31, + 1, 36, -23, -11, -4, -29, 14, -5, 29, 9, -2, -2, -20, -2, -15, 13, + 7, 4, 15, -11, 4, -13, -1, 1, -13, 15, -6, 9, 9, -2, -4, -11, + -2, -11, 7, 12, 9, 5, -6, -6, -16, -2, 3, 6, 13, 1, 7, -14, + -3, -11, -1, 8, 0, 18, -3, -3, -6, -13, 0, 4, 2, 9, 2, 2, + -6, -4, -1, -8, 2, 4, 2, 7, -4, 2, 1, -7, -3, -2, 0, 2, + 8, -2, 2, -1, -7, -3, -1, 3, 4, 3, 3, -3, -4, -4, 0, 2, + 1, 5, -1, -2, 1, -4, -1, 1, 0, 2, -5, -8, -3, -3, -9, -2, + -2, 5, 10, 16, 11, 5, -3, -5, -1, -4, -6, -7, -15, -18, -27, -31, + -21, -11, 22, 56, 90, 66, -17, -25, -25, 0, -12, -15, -25, -32, -39, -37, + -26, 6, 33, 65, 69, 44, -1, -13, -12, 1, 0, -9, -14, -22, -40, -44, + -42, -23, 8, 39, 60, 84, 57, -16, -25, -19, 2, -8, -11, -18, -32, -51, + -45, -32, -6, 28, 54, 85, 96, -5, -29, -23, -7, -10, -17, -16, -28, -53, + -44, -40, -7, 22, 52, 82, 112, 17, -37, -25, -20, -11, -18, -10, -23, -33, + -51, -40, -23, 10, 45, 65, 96, 64, -21, -35, -34, -19, -20, -13, -5, -14, + -35, -41, -39, -17, 9, 45, 58, 82, 98, -2, -57, -47, -23, -12, -11, -2, + -18, -28, -39, -36, -24, -1, 26, 57, 84, 121, 23, -65, -50, -40, -12, -11, + -4, -14, -20, -34, -32, -27, -5, 19, 56, 80, 127, 15, -66, -50, -2, -5, + -5, 2, 10, 8, -7, -16, -9, 6, 17, 8, -19, -20, 14, 38, 34, 20, + -5, 1, 50, 37, -50, -54, -66, -32, 32, -3, -13, -18, -17, 46, 89, -17, + -62, 45, 127, 57, -57, -67, -109, -11, 88, -31, -90, -88, -27, 63, 97, -27, + -105, -44, 65, 110, 60, -12, -30, -27, 17, 49, -2, -39, -6, 30, -16, -36, + -43, 32, 67, -54, -58, -38, -21, 47, 95, 76, -33, -78, -62, 10, 107, 24, + -106, -107, 12, 52, 27, 78, 8, -75, 25, 6, -26, 59, 32, -17, -7, -19, + 11, 32, -51, -52, 41, -9, -13, 94, 2, -65, 5, -46, -86, 34, 62, 85, + 29, -93, -89, -29, 44, 35, -31, -33, -19, 56, 127, 7, -9, -62, -52, 23, + 46, 44, -56, -16, -55, -46, 22, 83, -13, -42, -7, 13, 81, 49, 3, -9, + -30, -47, -30, 3, 23, 6, -7, -20, -44, 10, 96, -13, 0, 16, 31, 47, + 61, 75, 87, 98, 107, 115, 121, 125, 127, 127, 125, 121, 116, 108, 99, 88, + 75, 62, 47, 32, 16, 0, -16, -31, -47, -61, -75, -87, -98, -108, -116, -122, + -126, -128, -128, -126, -123, -117, -109, -100, -89, -77, -64, -49, -34, -18, -2, 14, + 29, 45, 59, 73, 86, 97, 106, 114, 121, 125, 127, 127, 126, 122, 116, 109, + 100, 89, 77, 63, 49, 34, 18, 2, -14, -30, -45, -60, -73, -86, -97, -107, + -115, -121, -126, -128, -128, -127, -123, -118, -110, -101, -91, -79, -65, -51, -36, -20, + -4, 12, 28, 43, 58, 72, 84, 96, 106, 114, 120, 124, 127, 127, 126, 122, + 117, 109, 100, 90, 78, 64, 50, 35, 19, 3, -13, -29, -44, -59, -73, -85, + -97, -107, -115, -121, -125, -128, -128, -127, -123, -118, -110, -101, -91, -79, -65, -51, + -36, -20, -4, 12, 2, 5, 5, 0, -16, -9, -2, -19, 4, 18, 6, 10, + -16, -21, 22, -2, 3, -7, 21, 43, -57, -37, 46, -39, -31, 78, 23, -23, + -10, -10, -7, -52, 44, 50, -44, 9, -9, -46, 47, 12, -75, 40, 45, 32, + -10, -25, -15, -45, 24, 44, -40, -10, 18, -48, -29, 63, 44, -30, -1, 83, + -45, -94, 96, 0, -103, 21, 29, -42, 21, 80, -25, -15, 26, 39, -79, -18, + 73, -111, -45, 61, 29, 55, -22, -77, 40, 9, -72, 78, 35, -1, -1, -69, + 12, -50, -42, 123, 45, -7, -39, -86, 3, 51, 30, 28, -4, -33, -41, -66, + 54, -8, -30, 127, -7, -30, -32, -39, 48, -65, 20, 121, -33, -14, -53, -32, + 46, -24, 36, 98, -49, -39, -61, 1, 49, -54, 65, 59, -83, -11, -49, 32, + 39, -72, 113, 59, -83, -11, -49, 32, 39, -72, 113, 59, -2, -4, -4, -7, + -8, -8, -7, -4, -3, -2, 1, 4, 6, 6, 6, 4, 2, 0, -2, -3, + -4, -7, -7, -5, -3, 0, 4, 9, 11, 11, 9, 7, 4, 1, -3, -7, + -9, -12, -13, -16, -19, -19, -13, -2, 9, 17, 19, 20, 18, 13, 8, 3, + 0, -2, -3, -8, -14, -21, -25, -21, -9, 4, 15, 23, 28, 25, 20, 9, + -7, -21, -14, 3, 3, -18, -38, -49, -32, -7, 8, 14, 26, 37, 42, 37, + 26, 7, -18, -27, -5, 8, -7, -24, -34, -40, -32, -19, 1, 17, 42, 56, + 58, 40, -19, -81, 1, 67, 0, -60, -49, -27, -24, 0, -18, -24, -8, 37, + 67, 70, 59, 34, -42, -81, 7, 51, -12, -54, -37, -14, -25, -14, -16, -24, + 4, 55, 75, 102, 52, -102, -104, 90, 30, -48, -76, 1, -14, 0, -2, -2, + -3, -5, -7, -8, -8, -7, -6, -4, -2, 0, 1, 3, 4, 6, 6, 6, + 6, 5, 4, 3, 1, 0, 0, -3, -4, -7, -10, -11, -11, -8, -6, 1, + 5, 6, 8, 11, 11, 8, 5, 5, 2, 1, 0, 0, -2, 1, -4, -16, + -36, -27, -5, 6, -3, -6, 0, -6, 2, 27, 24, 19, 16, 9, 3, 0, + -4, 2, 1, 9, 19, -14, -79, -32, 22, -4, -22, -14, 25, 8, -11, 13, + 28, 16, 19, 16, 1, -2, -4, -3, -6, 28, 38, -59, -111, 25, 16, -16, + -40, 16, 24, -20, 4, 24, 29, 17, 27, 13, 1, -10, -6, -10, -8, 43, + 61, -68, -128, 28, 12, -15, -39, 12, 21, -28, 12, 37, 25, 12, 27, 11, + 0, -16, -2, -12, -11, 52, 67, -68, 35, 54, 47, 4, -60, -92, -68, -27, + 0, -2, -18, -20, -6, 2, -8, -15, -11, -3, 3, -7, -11, -6, -2, 7, + 15, 18, 19, 22, 27, 40, 40, 29, 20, 24, 28, 34, 30, 25, 32, 20, + 14, 9, 16, 19, 17, 6, -1, 3, -6, -14, -23, -18, -7, 1, -18, -18, + -24, -25, -24, -35, -35, -35, -21, -12, -14, -21, -17, -29, -24, -31, -34, -9, + -11, -9, -3, -7, -7, 6, -17, -22, 7, 16, 14, -4, -11, 10, 33, 24, + 21, 27, 3, -19, -25, -18, 17, 50, 48, 49, 61, 31, -48, -103, -73, 9, + 56, 70, 82, 109, 127, 71, -46, -127, -96, -30, -4, 9, 47, 103, 117, 60, + -39, -110, -119, -94, -64, -40, -4, 35, -8, -14, -9, -5, -4, -3, 6, 18, + 19, 6, -14, -20, -12, -3, -3, -6, 2, 21, 28, 13, -16, -26, -14, -6, + -6, -7, 1, 27, 36, 18, -15, -27, -15, -3, -2, -10, -6, 25, 41, 22, + -17, -34, -18, -4, -3, -16, -12, 29, 56, 31, -24, -44, -20, -4, -1, -19, + -22, 31, 73, 47, -27, -62, -25, -2, 4, -21, -36, 26, 91, 61, -27, -79, + -33, 0, 10, -18, -49, 14, 106, 82, -24, -94, -40, 8, 14, -12, -59, 1, + 112, 105, -19, -106, -51, 12, 16, -4, -63, -13, 110, 127, -12, -114, -51, 0, + -1, -4, -8, -11, -8, -2, 0, 7, 14, 21, 46, 92, 120, 76, -36, -121, + -119, -73, -31, -7, 3, 2, -4, -6, 2, 22, 60, 106, 116, 43, -72, -128, + -105, -57, -21, -3, 3, -1, -6, -5, 7, 33, 76, 117, 102, 5, -100, -127, + -89, -43, -13, 0, 2, -3, -7, -2, 14, 46, 92, 122, 79, -34, -118, -118, + -72, -31, -8, 1, 0, -5, -7, 2, 23, 61, 107, 118, 46, -69, -126, -104, + -56, -21, -4, 1, 0, -4, -5, 0, 16, 48, 87, 103, 60, -25, -87, -94, + -58, -20, -4, -11, 12, 24, 31, -36, 29, -9, 2, -38, -5, -5, -10, -33, + -10, -24, -20, -39, -36, -18, -38, -58, -5, -22, -15, -15, 90, -42, -3, -8, + 25, 6, 28, 25, 17, 25, -16, 28, 80, 22, 12, -6, 35, 22, 8, -7, + 28, 29, -19, 7, 8, -1, -29, -23, 10, -23, -13, -26, -17, -20, -33, -41, + -19, -28, -64, -13, -21, -13, -29, 54, 25, -20, -36, 42, -4, 13, 52, -8, + 47, -14, 9, 42, 88, -12, 20, -5, 43, 22, -11, 127, 127, -128, -128, -128, + -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, + -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, + -128, -128, -128, -128, -128, -128, -128, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, -128, 1, 4, 7, 10, 12, 16, 19, 22, 25, 28, 31, 35, 38, 42, + 45, 49, 51, 56, 58, 63, 65, 70, 73, 78, 80, 85, 87, 93, 95, 100, + 102, 108, 109, 117, 114, 127, 85, -63, -60, -64, -60, -62, -59, -61, -59, -61, + -58, -60, -58, -59, -58, -58, -57, -57, -55, -55, -54, -54, -52, -51, -50, -49, + -47, -46, -44, -43, -41, -40, -37, -36, -34, -32, -30, -28, -25, -24, -21, -19, + -16, -14, -11, -9, -6, 1, 1, 4, 7, 10, 12, 16, 19, 22, 25, 28, + 31, 35, 38, 42, 45, 49, 51, 56, 58, 63, 65, 70, 73, 78, 80, 85, + 87, 93, 95, 100, 102, 108, 109, 117, 114, 127, 85, -63, -60, -64, -60, -62, + -59, -61, -59, -61, -58, -60, -58, -59, -58, -58, -57, -57, -55, -55, -54, -54, + -52, -51, -50, -49, -47, -46, -44, -43, -41, -40, -37, -36, -34, -32, -30, -28, + -25, -24, -21, -19, -16, -14, -11, -9, -6, 1, -3, -19, -24, -14, -8, -19, + -12, -10, -5, -12, -50, -19, 23, 35, 4, -20, -7, -26, 9, 40, 69, 16, + -88, -69, -38, -32, -27, 41, 65, 55, 18, -40, -38, -20, 66, 127, 121, 57, + -23, -55, -48, 13, 53, 31, -20, -38, -13, 10, 8, 0, 12, 17, 13, 2, + -1, -3, -3, 6, 13, 7, -17, -24, -12, 4, 3, -10, -20, -32, -22, -18, + -12, -3, 6, 16, 22, 29, 30, 27, 20, 11, 0, -7, -12, -11, -5, 0, + -3, -14, -20, -16, -9, -9, -17, -25, -29, -31, -33, -35, -33, -29, -25, -22, + -20, -17, -14, -13, -12, -11, -9, -10, -13, -15, -11, -5, 3, 9, 10, 9, + 9, 12, 18, 30, 50, 80, 119, 127, 102, 82, 77, 60, 37, 5, -34, -70, + -84, -83, -74, -60, -46, -29, -12, -2, 6, -23, 28, -20, 50, 50, -14, 14, + -28, -2, 28, 52, -25, -13, -52, 43, -41, -9, -26, 36, -25, -20, -17, 3, + -11, 38, 30, -61, 12, -6, 5, 45, 41, -4, 4, -20, -12, 45, 33, -11, + -29, -44, 27, -17, -36, -1, 17, -11, -31, -12, 4, -10, 37, 20, -39, -23, + 0, -104, -55, -11, 24, 33, 30, 7, -15, -31, -30, -25, -23, -20, -9, 10, + 31, 59, 91, 111, 115, 92, 51, 7, -33, -64, -81, -81, -71, -51, -22, 16, + 52, 74, 82, 81, 68, 38, 0, -40, -81, -112, -124, -102, -57, -11, 0, 7, + -23, -58, -85, -100, -104, -100, -92, -81, -69, -57, -45, -33, -22, -11, -1, 8, + 18, 27, 37, 49, 62, 79, 99, 118, 124, 111, 84, 53, 26, 5, -8, -14, + -15, -12, -6, 2, 12, 21, 28, 26, 9, -22, -58, -20, 7, 10, 21, -14, + 9, 22, 57, 62, 127, 56, 28, 26, -28, 10, -81, -31, -81, -35, -19, -55, + -27, -4, -4, 23, 49, 88, 85, 22, 1, 0, -3, 18, -22, -12, -39, -14, + -47, -67, -53, -53, -33, -20, 8, -22, 25, 30, 6, -19, -62, -19, 10, 83, + 57, -67, -88, -52, 63, 127, 42, -63, -121, -70, 82, 111, 46, -43, -114, -35, + 45, 73, 39, -19, -54, -41, 9, 49, 24, -16, -14, -9, -6, 10, 8, -22, + 25, 30, 6, -19, -62, -19, 10, 83, 57, -67, -88, -52, 63, 127, 42, -63, + -121, -70, 82, 111, 46, -43, -114, -35, 45, 73, 39, -19, -54, -41, 9, 49, + 24, -16, -14, -9, -6, 10, 8, -22, 25, 30, 6, -19, -62, -19, 10, 83, + 57, -67, -88, -52, 63, 127, 42, -63, -121, -70, 82, 111, 46, -43, -114, -35, + 45, 73, 39, -19, -54, -41, 9, 49, 24, -16, -14, -9, -6, 10, -18, -15, + 80, 127, 20, 18, 72, 60, -36, 22, 33, -73, -105, -27, 29, 25, 8, 43, + 23, -22, -35, -14, -8, -34, -25, -5, -18, -46, -13, -28, -3, -19, -10, -28, + -10, 17, -18, 96, 127, 123, 127, 126, 126, 95, 61, 22, -17, -56, -95, -118, + -123, -128, -128, -128, -128, -128, -128, -128, -128, -124, -93, -55, -17, 25, 62, 100, + 107, 119, 119, 127, 41, -4, -4, -10, -27, -62, -102, -128, -117, -85, -76, -49, + -25, -7, 15, 24, 14, 0, -9, -12, -3, 33, 81, 105, 111, 101, 80, 62, + 45, 30, 16, 8, 1, -4, 126, 86, -44, -68, -88, -63, 4, 84, 127, 14, + -29, -51, -127, -47, 58, 87, 82, 24, -17, -112, -113, 18, 46, 72, 102, 19, + -72, -118, -51, 9, 27, 126, 19, -53, -114, -108, 15, 122, 111, 21, -71, -70, + 5, 59, 83, 23, -72, -84, -49, 12, 37, 38, -28, -65, -26, 7, -2, 11, + 5, 23, 68, 19, 27, -54, 15, -24, -31, 46, 71, 81, -24, -33, -87, -41, + -71, -61, -70, -36, -44, -3, 12, -25, -20, 20, 68, 85, 127, 15, 50, -5, + 27, 51, 82, 106, 127, 118, 101, 92, 74, 52, 39, 37, 14, -41, -105, -108, + -94, -119, -124, -93, -57, -40, -37, -45, -51, -41, -5, 51, 127, 127, -128, -128, + -128, -128, -128, -128, -128, -128, -128, -128, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127 +}; + +const EAS_U32 eas_sampleLengths[] = +{ + 16820, 16708, 16592, 11754, 10954, 10295, 9922, 7489, + 5779, 5462, 4452, 3779, 3115, 3093, 3057, 3024, + 2818, 2776, 2171, 2168, 2052, 1902, 1835, 1614, + 1603, 1528, 1517, 1480, 1455, 1424, 1387, 1302, + 1262, 1254, 1230, 1227, 1185, 1181, 1178, 1168, + 1132, 1120, 1034, 1033, 1018, 994, 964, 926, + 907, 886, 881, 866, 830, 817, 816, 813, + 749, 748, 739, 720, 652, 610, 610, 583, + 564, 561, 556, 549, 542, 535, 530, 530, + 516, 508, 492, 478, 461, 448, 437, 431, + 423, 418, 403, 402, 400, 394, 387, 387, + 367, 357, 347, 347, 341, 336, 334, 329, + 325, 312, 294, 284, 277, 265, 255, 233, + 230, 213, 207, 205, 194, 193, 184, 181, + 181, 167, 164, 158, 152, 152, 145, 139, + 128, 103, 100, 88, 87, 84, 84, 72, + 71, 55, 46, 45, 43, 40, 40, 40, + 37, 35, 32, 32, 30, 29, 27, 23, + 22, 21, 21, 21, 21, 20 +}; + +const EAS_U32 eas_sampleOffsets[] = +{ + 0x00000000, 0x000041b4, 0x000082f8, 0x0000c3c8, 0x0000f1b2, 0x00011c7c, 0x000144b3, 0x00016b75, + 0x000188b6, 0x00019f49, 0x0001b49f, 0x0001c603, 0x0001d4c6, 0x0001e0f1, 0x0001ed06, 0x0001f8f7, + 0x000204c7, 0x00020fc9, 0x00021aa1, 0x0002231c, 0x00022b94, 0x00023398, 0x00023b06, 0x00024231, + 0x0002487f, 0x00024ec2, 0x000254ba, 0x00025aa7, 0x0002606f, 0x0002661e, 0x00026bae, 0x00027119, + 0x0002762f, 0x00027b1d, 0x00028003, 0x000284d1, 0x0002899c, 0x00028e3d, 0x000292da, 0x00029774, + 0x00029c04, 0x0002a070, 0x0002a4d0, 0x0002a8da, 0x0002ace3, 0x0002b0dd, 0x0002b4bf, 0x0002b883, + 0x0002bc21, 0x0002bfac, 0x0002c322, 0x0002c693, 0x0002c9f5, 0x0002cd33, 0x0002d064, 0x0002d394, + 0x0002d6c1, 0x0002d9ae, 0x0002dc9a, 0x0002df7d, 0x0002e24d, 0x0002e4d9, 0x0002e73b, 0x0002e99d, + 0x0002ebe4, 0x0002ee18, 0x0002f049, 0x0002f275, 0x0002f49a, 0x0002f6b8, 0x0002f8cf, 0x0002fae1, + 0x0002fcf3, 0x0002fef7, 0x000300f3, 0x000302df, 0x000304bd, 0x0003068a, 0x0003084a, 0x000309ff, + 0x00030bae, 0x00030d55, 0x00030ef7, 0x0003108a, 0x0003121c, 0x000313ac, 0x00031536, 0x000316b9, + 0x0003183c, 0x000319ab, 0x00031b10, 0x00031c6b, 0x00031dc6, 0x00031f1b, 0x0003206b, 0x000321b9, + 0x00032302, 0x00032447, 0x0003257f, 0x000326a5, 0x000327c1, 0x000328d6, 0x000329df, 0x00032ade, + 0x00032bc7, 0x00032cad, 0x00032d82, 0x00032e51, 0x00032f1e, 0x00032fe0, 0x000330a1, 0x00033159, + 0x0003320e, 0x000332c3, 0x0003336a, 0x0003340e, 0x000334ac, 0x00033544, 0x000335dc, 0x0003366d, + 0x000336f8, 0x00033778, 0x000337df, 0x00033843, 0x0003389b, 0x000338f2, 0x00033946, 0x0003399a, + 0x000339e2, 0x00033a29, 0x00033a60, 0x00033a8e, 0x00033abb, 0x00033ae6, 0x00033b0e, 0x00033b36, + 0x00033b5e, 0x00033b83, 0x00033ba6, 0x00033bc6, 0x00033be6, 0x00033c04, 0x00033c21, 0x00033c3c, + 0x00033c53, 0x00033c69, 0x00033c7e, 0x00033c93, 0x00033ca8, 0x00033cbd +}; + +/*---------------------------------------------------------------------------- + * S_EAS + *---------------------------------------------------------------------------- +*/ +const S_EAS easSoundLib = +{ + 0x01534145, + 0x00105622, + eas_banks, + eas_programs, + eas_regions, + eas_articulations, + eas_sampleLengths, + eas_sampleOffsets, + eas_samples, + 0, + 1, + 1, + 377, + 185, + 150, + 0 +}; /* end S_EAS */ + +/*---------------------------------------------------------------------------- + * Statistics + * + * Number of banks: 1 + * Number of programs: 1 + * Number of regions: 377 + * Number of articulations: 185 + * Number of samples: 150 + * Size of sample pool: 212050 + *---------------------------------------------------------------------------- +*/ +/* end wt_200k_G.c */ diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/misc/eas_host.c b/common/embeddedaudiosynthesis/arm-wt-22k/misc/eas_host.c new file mode 100755 index 0000000..01e5ce3 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/misc/eas_host.c @@ -0,0 +1,787 @@ +/*---------------------------------------------------------------------------- + * + * File: + * eas_host.c + * + * Contents and purpose: + * This file contains the host wrapper functions for stdio, stdlib, etc. + * This is a sample version that wraps the standard library functions. + * Modify this file to suit the needs of your particular system. + * + * EAS_MAX_FILE_HANDLES sets the maximum number of MIDI streams within + * a MIDI type 1 file that can be played. To maintain efficiency, data + * is buffered locally when byte access is used (EAS_HWGetByte). The + * size of the buffer is set by EAS_FILE_BUFFER_SIZE. + * + * EAS_HW_FILE is a structure to support local file buffering. It + * comprises the OS File handle, some data related to the local file + * buffer, the position of the next byte of data to be read, the dup + * flag which when set, indicates that the handle has been duplicated, + * and the data buffer. Since the data buffer is only used for byte + * access, it does not need to be large. + * + * If the file system supports duplicate file handles and buffering, + * this entire subsystem can be replaced with direct calls to the + * native file I/O routines. + * + * If the system has enough memory to support reading the entire file + * into memory, it will be much more efficient to do so on the call to + * EAS_HWOpenFile and then close the file. Simply substitute a memory + * pointer for the FILE* pointer. Calls to EAS_HW_DupHandle will work + * as they do in this version. In the call to EAS_HWCloseFile, instead + * of calling fclose, free the memory containing the file data. + * + * Copyright 2005 Sonic Network Inc. + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 853 $ + * $Date: 2007-09-05 09:54:17 -0700 (Wed, 05 Sep 2007) $ + *---------------------------------------------------------------------------- +*/ + +#ifdef _lint +#include "lint_stdlib.h" +#else +#include +#include +#include +#endif + +#include "eas_host.h" + +// #define DEBUG_FILE_IO + +/* Only for debugging LED, vibrate, and backlight functions */ +#include "eas_report.h" + +#ifndef EAS_MAX_FILE_HANDLES +#define EAS_MAX_FILE_HANDLES 32 +#endif + +#ifndef EAS_FILE_BUFFER_SIZE +#define EAS_FILE_BUFFER_SIZE 32 +#endif + +/* + * this structure and the related function are here + * to support the ability to create duplicate handles + * and buffering into a single file. If the OS supports + * duplicate file handles natively, this code can be + * stripped to eliminate double-buffering. + */ +typedef struct eas_hw_file_tag +{ + FILE *pFile; + EAS_I32 bytesInBuffer; + EAS_I32 readIndex; + EAS_I32 filePos; + EAS_BOOL dup; + EAS_U8 buffer[EAS_FILE_BUFFER_SIZE]; +} EAS_HW_FILE; + +typedef struct eas_hw_inst_data_tag +{ + EAS_HW_FILE files[EAS_MAX_FILE_HANDLES]; +} EAS_HW_INST_DATA; + +/* local memory for files and streams */ +#ifdef _STATIC_MEMORY +EAS_HW_INST_DATA fileData; +#endif + +/*---------------------------------------------------------------------------- + * EAS_HWInit + * + * Initialize host wrapper interface + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_HWInit (EAS_HW_DATA_HANDLE *pHWInstData) +{ + + /* need to track file opens for duplicate handles */ +#ifndef _STATIC_MEMORY + *pHWInstData = malloc(sizeof(EAS_HW_INST_DATA)); + if (!(*pHWInstData)) + return EAS_ERROR_MALLOC_FAILED; +#else + *pHWInstData = &fileData; +#endif + EAS_HWMemSet(*pHWInstData, 0, sizeof(EAS_HW_INST_DATA)); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * EAS_HWShutdown + * + * Shut down host wrapper interface + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWShutdown (EAS_HW_DATA_HANDLE hwInstData) +{ + +#ifndef _STATIC_MEMORY + free(hwInstData); +#endif + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWMalloc + * + * Allocates dynamic memory + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +#ifdef _STATIC_MEMORY +/*lint -esym(715, size) not used in static memory model */ +#endif +void *EAS_HWMalloc (EAS_HW_DATA_HANDLE hwInstData, EAS_I32 size) +{ +#ifdef _STATIC_MEMORY + return NULL; +#else + return malloc((EAS_U32)size); +#endif +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWFree + * + * Frees dynamic memory + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +#ifdef _STATIC_MEMORY +/*lint -esym(715, p) not used in static memory model */ +#endif +void EAS_HWFree(EAS_HW_DATA_HANDLE hwInstData, void *p) +{ +#ifndef _STATIC_MEMORY + free(p); +#endif +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWMemCpy + * + * Copy memory wrapper + * + *---------------------------------------------------------------------------- +*/ +void *EAS_HWMemCpy (void *dest, const void *src, EAS_I32 amount) +{ + return memcpy(dest,src,(size_t) amount); +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWMemSet + * + * Set memory wrapper + * + *---------------------------------------------------------------------------- +*/ +void *EAS_HWMemSet (void *dest, int val, EAS_I32 amount) +{ + return memset(dest,val,(size_t) amount); +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWMemCmp + * + * Compare memory wrapper + * + *---------------------------------------------------------------------------- +*/ +EAS_I32 EAS_HWMemCmp (const void *s1, const void *s2, EAS_I32 amount) +{ + return (EAS_I32) memcmp(s1, s2, (size_t) amount); +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWOpenFile + * + * Open a file for read or write + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_HWOpenFile (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_LOCATOR locator, EAS_FILE_HANDLE *pFile, EAS_FILE_MODE mode) +{ + EAS_HW_FILE *file; + int i; + + /* set return value to NULL */ + *pFile = NULL; + + /* only support read mode at this time */ + if (mode != EAS_FILE_READ) + return EAS_ERROR_INVALID_FILE_MODE; + + /* find an empty entry in the file table */ + file = hwInstData->files; + for (i = 0; i < EAS_MAX_FILE_HANDLES; i++) + { + /* is this slot being used? */ + if (file->pFile == NULL) + { + /* open the file */ + if (locator->path) + file->pFile = fopen((const char*) locator->path, "rb"); + if (file->pFile == NULL) + return EAS_ERROR_FILE_OPEN_FAILED; + +#ifdef DEBUG_FILE_IO + EAS_ReportX(_EAS_SEVERITY_NOFILTER, "EAS_HWOpenFile: Open file %d\n", i); +#endif + + /* initialize some values */ + file->bytesInBuffer = 0; + file->readIndex = 0; + file->filePos = 0; + file->dup = EAS_FALSE; + + *pFile = file; + return EAS_SUCCESS; + } + file++; + } + + /* too many open files */ + return EAS_ERROR_MAX_FILES_OPEN; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWFillBuffer + * + * Fill buffer from file + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWFillBuffer (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file) +{ + /* reposition the file pointer */ + if (fseek(file->pFile, file->filePos, SEEK_SET) != 0) + return EAS_ERROR_FILE_SEEK; + + /* read some data from the file */ + file->bytesInBuffer = (EAS_I32) fread(file->buffer, 1, EAS_FILE_BUFFER_SIZE, file->pFile); + file->readIndex = 0; + if (file->bytesInBuffer == 0) + return EAS_EOF; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWReadFile + * + * Read data from a file + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWReadFile (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *pBuffer, EAS_I32 n, EAS_I32 *pBytesRead) +{ + EAS_RESULT result; + EAS_I32 temp; + EAS_U8 *p = pBuffer; + EAS_I32 bytesLeft = n; + + *pBytesRead = 0; + + /* check handle integrity */ + if (file->pFile == NULL) + return EAS_ERROR_INVALID_HANDLE; + +#ifdef DEBUG_FILE_IO + EAS_ReportX(_EAS_SEVERITY_NOFILTER, "EAS_HWReadFile: Reading %d bytes from position %d\n", n, file->filePos); +#endif + + /* try to fulfill request from buffer */ + for (;bytesLeft > 0;) + { + /* how many bytes can we get from buffer? */ + temp = file->bytesInBuffer - file->readIndex; + if (temp > bytesLeft) + temp = bytesLeft; + + /* copy data from buffer */ + EAS_HWMemCpy(p, &file->buffer[file->readIndex], temp); + *pBytesRead += temp; + file->readIndex += temp; + file->filePos += temp; + bytesLeft -= temp; + p += temp; + + /* don't refill buffer if request is bigger than buffer */ + if ((bytesLeft == 0) || (bytesLeft >= EAS_FILE_BUFFER_SIZE)) + break; + + /* refill buffer */ + if ((result = EAS_HWFillBuffer(hwInstData, file)) != EAS_SUCCESS) + return result; + } + + /* more to read? do unbuffered read directly to target memory */ + if (bytesLeft) + { + + /* position the file pointer */ + if (fseek(file->pFile, file->filePos, SEEK_SET) != 0) + return EAS_ERROR_FILE_SEEK; + + /* read data in the buffer */ + /*lint -e{826} lint doesn't like this with STATIC_MEMORY defined for some reason */ + temp = (EAS_I32) fread(p, 1, (size_t) bytesLeft, file->pFile); + *pBytesRead += temp; + file->filePos += temp; + + /* reset buffer info */ + file->bytesInBuffer = 0; + file->readIndex = 0; + } + +#ifdef DEBUG_FILE_IO + { +#define BYTES_PER_LINE 16 + char str[BYTES_PER_LINE * 3 + 1]; + EAS_INT i; + for (i = 0; i < (n > BYTES_PER_LINE ? BYTES_PER_LINE : n) ; i ++) + sprintf(&str[i*3], "%02x ", ((EAS_U8*)pBuffer)[i]); + if (i) + EAS_ReportX(_EAS_SEVERITY_NOFILTER, "%s\n", str); + } +#endif + + /* were n bytes read? */ + if (*pBytesRead != n) + return EAS_EOF; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWGetByte + * + * Read a byte from a file + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWGetByte (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *p) +{ + EAS_RESULT result; + + /* check handle integrity */ + if (file->pFile == NULL) + return EAS_ERROR_INVALID_HANDLE; + + /* use local buffer - do we have any data? */ + if (file->readIndex >= file->bytesInBuffer) + { + if ((result = EAS_HWFillBuffer(hwInstData, file)) != EAS_SUCCESS) + return result; + + /* if nothing to read, return EOF */ + if (file->bytesInBuffer == 0) + return EAS_EOF; + } + + /* get a character from the buffer */ + *((EAS_U8*) p) = file->buffer[file->readIndex++]; + +#ifdef DEBUG_FILE_IO + EAS_ReportX(_EAS_SEVERITY_NOFILTER, "EAS_HWGetByte: Reading from position %d, byte = 0x%02x\n", file->filePos, *(EAS_U8*)p); +#endif + + file->filePos++; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWGetWord + * + * Read a 16-bit value from the file + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_HWGetWord (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *p, EAS_BOOL msbFirst) +{ + EAS_RESULT result; + EAS_I32 count; + EAS_U8 c[2]; + +#ifdef DEBUG_FILE_IO + EAS_ReportX(_EAS_SEVERITY_NOFILTER, "EAS_HWGetWord: Reading 2 bytes from position %d\n", file->filePos); +#endif + + /* read 2 bytes from the file */ + if ((result = EAS_HWReadFile(hwInstData, file, c, 2, &count)) != EAS_SUCCESS) + return result; + + /* order them as requested */ + if (msbFirst) + *((EAS_U16*) p) = ((EAS_U16) c[0] << 8) | c[1]; + else + *((EAS_U16*) p) = ((EAS_U16) c[1] << 8) | c[0]; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWGetDWord + * + * Read a 16-bit value from the file + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_HWGetDWord (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, void *p, EAS_BOOL msbFirst) +{ + EAS_RESULT result; + EAS_I32 count; + EAS_U8 c[4]; + +#ifdef DEBUG_FILE_IO + EAS_ReportX(_EAS_SEVERITY_NOFILTER, "EAS_HWGetDWord: Reading 4 bytes from position %d\n", file->filePos); +#endif + + /* read 4 bytes from the file */ + if ((result = EAS_HWReadFile(hwInstData, file, c, 4, &count)) != EAS_SUCCESS) + return result; + + /* order them as requested */ + if (msbFirst) + *((EAS_U32*) p) = ((EAS_U32) c[0] << 24) | ((EAS_U32) c[1] << 16) | ((EAS_U32) c[2] << 8) | c[3]; + else + *((EAS_U32*) p) = ((EAS_U32) c[3] << 24) | ((EAS_U32) c[2] << 16) | ((EAS_U32) c[1] << 8) | c[0]; + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWFilePos + * + * Returns the current location in the file + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWFilePos (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 *pPosition) +{ + + /* check handle integrity */ + if (file->pFile == NULL) + return EAS_ERROR_INVALID_HANDLE; + + *pPosition = file->filePos; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWFileSeek + * + * Seek to a specific location in the file + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWFileSeek (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 position) +{ + EAS_I32 newIndex; + + /* check handle integrity */ + if (file->pFile == NULL) + return EAS_ERROR_INVALID_HANDLE; + +#ifdef DEBUG_FILE_IO + EAS_ReportX(_EAS_SEVERITY_NOFILTER, "EAS_HWFileSeek: Seeking to new position %d\n", file->filePos); +#endif + + /* is new position in current buffer? */ + newIndex = position - file->filePos + file->readIndex; + if ((newIndex >= 0) && (newIndex < file->bytesInBuffer)) + { + file->readIndex = newIndex; + file->filePos = position; + return EAS_SUCCESS; + } + + /* save new position and reset buffer info so EAS_HWGetByte doesn't fail */ + file->filePos = position; + file->bytesInBuffer = 0; + file->readIndex = 0; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWFileSeekOfs + * + * Seek forward or back relative to the current position + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWFileSeekOfs (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 position) +{ + EAS_I32 temp; + +#ifdef DEBUG_FILE_IO + EAS_ReportX(_EAS_SEVERITY_NOFILTER, "EAS_HWFileSeekOfs: Seeking to new position %d\n", file->filePos + position); +#endif + + /* check handle integrity */ + if (file->pFile == NULL) + return EAS_ERROR_INVALID_HANDLE; + + /* is new position in current buffer? */ + temp = position + file->readIndex; + if ((temp >= 0) && (temp < file->bytesInBuffer)) + { + file->readIndex = temp; + file->filePos += position; + return EAS_SUCCESS; + } + + /* save new position and reset buffer info so EAS_HWGetByte doesn't fail */ + file->filePos += position; + file->bytesInBuffer = 0; + file->readIndex = 0; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWFileLength + * + * Return the file length + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWFileLength (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_I32 *pLength) +{ + long pos; + + /* check handle integrity */ + if (file->pFile == NULL) + return EAS_ERROR_INVALID_HANDLE; + + if ((pos = ftell(file->pFile)) == -1L) + return EAS_ERROR_FILE_LENGTH; + if (fseek(file->pFile, 0L, SEEK_END) != 0) + return EAS_ERROR_FILE_LENGTH; + if ((*pLength = ftell(file->pFile)) == -1L) + return EAS_ERROR_FILE_LENGTH; + if (fseek(file->pFile, pos, SEEK_SET) != 0) + return EAS_ERROR_FILE_LENGTH; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWDupHandle + * + * Duplicate a file handle + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_HWDupHandle (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file, EAS_FILE_HANDLE* pDupFile) +{ + EAS_HW_FILE *dupfile; + int i; + + /* check handle integrity */ + *pDupFile = NULL; + if (file->pFile == NULL) + return EAS_ERROR_INVALID_HANDLE; + + /* find an empty entry in the file table */ + dupfile = hwInstData->files; + for (i = 0; i < EAS_MAX_FILE_HANDLES; i++) + { + /* is this slot being used? */ + if (dupfile->pFile == NULL) + { + + /* copy info from the handle to be duplicated */ + dupfile->filePos = file->filePos; + dupfile->pFile = file->pFile; + + /* set the duplicate handle flag */ + dupfile->dup = file->dup = EAS_TRUE; + + /* initialize some values */ + dupfile->bytesInBuffer = 0; + dupfile->readIndex = 0; + + *pDupFile = dupfile; + return EAS_SUCCESS; + } + dupfile++; + } + + /* too many open files */ + return EAS_ERROR_MAX_FILES_OPEN; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWClose + * + * Wrapper for fclose function + * + *---------------------------------------------------------------------------- +*/ +EAS_RESULT EAS_HWCloseFile (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE file1) +{ + EAS_HW_FILE *file2,*dupFile; + int i; + + /* check handle integrity */ + if (file1->pFile == NULL) + return EAS_ERROR_INVALID_HANDLE; + + /* check for duplicate handle */ + if (file1->dup) + { + dupFile = NULL; + file2 = hwInstData->files; + for (i = 0; i < EAS_MAX_FILE_HANDLES; i++) + { + /* check for duplicate */ + if ((file1 != file2) && (file2->pFile == file1->pFile)) + { + /* is there more than one duplicate? */ + if (dupFile != NULL) + { + /* clear this entry and return */ + file1->pFile = NULL; + return EAS_SUCCESS; + } + + /* this is the first duplicate found */ + dupFile = file2; + } + file2++; + } + + /* there is only one duplicate, clear the dup flag */ + if (dupFile) + dupFile->dup = EAS_FALSE; + else + /* if we get here, there's a serious problem */ + return EAS_ERROR_HANDLE_INTEGRITY; + + /* clear this entry and return */ + file1->pFile = NULL; + return EAS_SUCCESS; + } + + /* no duplicates - close the file */ + if (fclose(file1->pFile) != 0) + return EAS_ERROR_CLOSE_FAILED; + + /* clear this entry and return */ + file1->pFile = NULL; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWVibrate + * + * Turn on/off vibrate function + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWVibrate (EAS_HW_DATA_HANDLE hwInstData, EAS_BOOL state) +{ + EAS_ReportX(_EAS_SEVERITY_NOFILTER, "Vibrate state: %d\n", state); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWLED + * + * Turn on/off LED + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWLED (EAS_HW_DATA_HANDLE hwInstData, EAS_BOOL state) +{ + EAS_ReportX(_EAS_SEVERITY_NOFILTER, "LED state: %d\n", state); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWBackLight + * + * Turn on/off backlight + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_RESULT EAS_HWBackLight (EAS_HW_DATA_HANDLE hwInstData, EAS_BOOL state) +{ + EAS_ReportX(_EAS_SEVERITY_NOFILTER, "Backlight state: %d\n", state); + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * + * EAS_HWYield + * + * This function is called periodically by the EAS library to give the + * host an opportunity to allow other tasks to run. There are two ways to + * use this call: + * + * If you have a multi-tasking OS, you can call the yield function in the + * OS to allow other tasks to run. In this case, return EAS_FALSE to tell + * the EAS library to continue processing when control returns from this + * function. + * + * If tasks run in a single thread by sequential function calls (sometimes + * call a "commutator loop"), return EAS_TRUE to cause the EAS Library to + * return to the caller. Be sure to check the number of bytes rendered + * before passing the audio buffer to the codec - it may not be filled. + * The next call to EAS_Render will continue processing until the buffer + * has been filled. + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, hwInstData) hwInstData available for customer use */ +EAS_BOOL EAS_HWYield (EAS_HW_DATA_HANDLE hwInstData) +{ + /* put your code here */ + return EAS_FALSE; +} diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/vectors/Leadsol.mxmf b/common/embeddedaudiosynthesis/arm-wt-22k/vectors/Leadsol.mxmf new file mode 100755 index 0000000..239f500 Binary files /dev/null and b/common/embeddedaudiosynthesis/arm-wt-22k/vectors/Leadsol.mxmf differ diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/vectors/Leadsol_out.wav b/common/embeddedaudiosynthesis/arm-wt-22k/vectors/Leadsol_out.wav new file mode 100755 index 0000000..43d326c Binary files /dev/null and b/common/embeddedaudiosynthesis/arm-wt-22k/vectors/Leadsol_out.wav differ diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/vectors/WAVEtest.wav b/common/embeddedaudiosynthesis/arm-wt-22k/vectors/WAVEtest.wav new file mode 100755 index 0000000..0d8178a Binary files /dev/null and b/common/embeddedaudiosynthesis/arm-wt-22k/vectors/WAVEtest.wav differ diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/vectors/WAVEtest_out.wav b/common/embeddedaudiosynthesis/arm-wt-22k/vectors/WAVEtest_out.wav new file mode 100755 index 0000000..1a66130 Binary files /dev/null and b/common/embeddedaudiosynthesis/arm-wt-22k/vectors/WAVEtest_out.wav differ diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/vectors/abba.imy b/common/embeddedaudiosynthesis/arm-wt-22k/vectors/abba.imy new file mode 100755 index 0000000..9a056e6 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/vectors/abba.imy @@ -0,0 +1,10 @@ +BEGIN:IMELODY +VERSION:1.2 +FORMAT:CLASS1.0 +NAME:DanceQueen +COMPOSER: downloaded at www.ringtones.perbang.dk +BEAT:112 +STYLE:S1 +VOLUME:V10 +MELODY:*5#c1*4b2*5d1*5#c4*4b3*4a4*4b3.*5#c3*5#c2*5a4*5a3*5#g4*5#g3*5#f4*5#f1*5#c1*4b2*5d1*5#c4*4b3*4a4*4b3.*5#c3*5#c2*4b2*4a1.r2*5#c2*4b3*4b1r4r5*5#c2*4b3*4b2*5#c2*4a3.*4b3.*4#g3*4a3.*4b3.*4#g3*4a4*4#g4*4#f2.*5#c3*4b3.*4a3*4#g2*4a3*4a1r4*4#g2*4a3*4a2.*4b4*4a3*4#g4*4#g3.*4a3.*4a1 +END:IMELODY diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/vectors/abba_out.wav b/common/embeddedaudiosynthesis/arm-wt-22k/vectors/abba_out.wav new file mode 100755 index 0000000..acf40d5 Binary files /dev/null and b/common/embeddedaudiosynthesis/arm-wt-22k/vectors/abba_out.wav differ diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/vectors/ants.mid b/common/embeddedaudiosynthesis/arm-wt-22k/vectors/ants.mid new file mode 100755 index 0000000..d4ead53 Binary files /dev/null and b/common/embeddedaudiosynthesis/arm-wt-22k/vectors/ants.mid differ diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/vectors/ants_out.wav b/common/embeddedaudiosynthesis/arm-wt-22k/vectors/ants_out.wav new file mode 100755 index 0000000..abb724d Binary files /dev/null and b/common/embeddedaudiosynthesis/arm-wt-22k/vectors/ants_out.wav differ diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/vectors/greensleeves.rtttl b/common/embeddedaudiosynthesis/arm-wt-22k/vectors/greensleeves.rtttl new file mode 100755 index 0000000..37865d1 --- /dev/null +++ b/common/embeddedaudiosynthesis/arm-wt-22k/vectors/greensleeves.rtttl @@ -0,0 +1 @@ +Greensleaves:d=4, o=5, b=140:g, 2a#, c6, d.6, 8d#6, d6, 2c6, a, f., 8g, a, 2a#, g, g., 8f, g, 2a, f, 2d, g, 2a#, c6, d.6, 8e6, d6, 2c6, a, f., 8g, a, a#., 8a, g, f#., 8e, f#, 2g \ No newline at end of file diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/vectors/greensleeves_out.wav b/common/embeddedaudiosynthesis/arm-wt-22k/vectors/greensleeves_out.wav new file mode 100755 index 0000000..5d61fb2 Binary files /dev/null and b/common/embeddedaudiosynthesis/arm-wt-22k/vectors/greensleeves_out.wav differ diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/vectors/test.ota b/common/embeddedaudiosynthesis/arm-wt-22k/vectors/test.ota new file mode 100755 index 0000000..7aa5f99 Binary files /dev/null and b/common/embeddedaudiosynthesis/arm-wt-22k/vectors/test.ota differ diff --git a/common/embeddedaudiosynthesis/arm-wt-22k/vectors/test_out.wav b/common/embeddedaudiosynthesis/arm-wt-22k/vectors/test_out.wav new file mode 100755 index 0000000..45ef142 Binary files /dev/null and b/common/embeddedaudiosynthesis/arm-wt-22k/vectors/test_out.wav differ diff --git a/common/embeddedaudiosynthesis/docs/EASLibrary3_5.odt b/common/embeddedaudiosynthesis/docs/EASLibrary3_5.odt new file mode 100755 index 0000000..5fd3f37 Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/EASLibrary3_5.odt differ diff --git a/common/embeddedaudiosynthesis/docs/EASLibrary3_5.pdf b/common/embeddedaudiosynthesis/docs/EASLibrary3_5.pdf new file mode 100755 index 0000000..910ccc1 Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/EASLibrary3_5.pdf differ diff --git a/common/embeddedaudiosynthesis/docs/EAS_API_Reference.odt b/common/embeddedaudiosynthesis/docs/EAS_API_Reference.odt new file mode 100755 index 0000000..bdfa441 Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/EAS_API_Reference.odt differ diff --git a/common/embeddedaudiosynthesis/docs/EAS_API_Reference.pdf b/common/embeddedaudiosynthesis/docs/EAS_API_Reference.pdf new file mode 100755 index 0000000..71645cf Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/EAS_API_Reference.pdf differ diff --git a/common/embeddedaudiosynthesis/docs/EAS_Library_Integration_Guide.odt b/common/embeddedaudiosynthesis/docs/EAS_Library_Integration_Guide.odt new file mode 100755 index 0000000..b0bcb0d Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/EAS_Library_Integration_Guide.odt differ diff --git a/common/embeddedaudiosynthesis/docs/EAS_Library_Integration_Guide.pdf b/common/embeddedaudiosynthesis/docs/EAS_Library_Integration_Guide.pdf new file mode 100755 index 0000000..6cb4541 Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/EAS_Library_Integration_Guide.pdf differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines.html b/common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines.html new file mode 100755 index 0000000..2ade2e3 --- /dev/null +++ b/common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines.html @@ -0,0 +1,2442 @@ + + + + + + + + +JET Authoring Guidelines + + + + + + + + +
+   Copyright (C) 2009 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ +
+ +

JET™ Content Authoring Guidelines

+ +

JET Interactive Music Engine

+ +

Vrs 1.0

+ +

Authored by SONiVOX

+ +

www.sonivoxrocks.com

+ +

Copyright 2009 Sonic Network, Inc.

+ +

 

+ +

 

+ +

1         +Introduction

+ +

1.1        +Overview

+ +

This document contains content creation +guidelines for composers and sound designers authoring music and sound effects +for the SONiVOX JET platform.  JET is an +interactive music player for small embedded devices, including the Google Android +platform. It allows applications to include interactive music soundtracks, in MIDI format, that respond in real-time to game play +events and user interaction.

+ +

 

+ +

JET works in conjunction with SONiVOX’s +Embedded Audio Synthesizer (EAS) which is the MIDI +playback device for Android.  Both the +JET and EAS engines are integrated into the Android embedded platform as well +as inherent in the JET Creator application. As such, the JET content author can +be sure that the playback will sound exactly the same in both the JET Creator +and the final Android application playing back on Android mobile devices.

+ +

 

+ +

The JET content author works in up to three +different applications to create JET content; a standard MIDI +sequencer (Logic, Cubase, etc.), optionally a DLS2 instrument editor (Awave), +and the JET Creator application to add and audition JET interactive elements.

+ +

 

+ +

The final result is a .jet file that the +content author gives to the application programmer for use in the game or +application.

+ +

 

+ +

 

+ +

1.2        +Abbreviations and Common Terms

+ +

It is important to use a common set of +terms to minimize confusion. Since JET uses MIDI +in a unique way, normal industry terms may not always suffice. Here is the +definition of terms as they are used in this document and in the JET Creator +application:

+ +

 

+ +

Channel: MIDI data associated with a specific MIDI +channel. Standard MIDI allows for 16 channels of MIDI +data each of which are typically associated with a specific instrument.

+ +

 

+ +

Controller: A MIDI event consisting of a +channel number, controller number, and a controller value. The MIDI spec associates many controller numbers with +specific functions, such as volume, expression, sustain pedal, etc. JET also +uses controller events as a means of embedding special control information in a +MIDI sequence to provide for audio +synchronization.

+ +

 

+ +

DAW: Digital Audio Workstation. A common term for MIDI +and audio sequencing applications such as Logic, SONAR, Cubase and others.

+ +

 

+ +

EAS: Embedded MIDI Synthesizer. The +name of the SONiVOX MIDI synthesizer engine.

+ +

 

+ +

JET: Jet Interactive Engine. The name of the SONiVOX JET interactive +music engine.

+ +

 

+ +

Segment: A musical section such as a chorus or verse that is a component of +the overall composition. In JET, a segment can be an entire MIDI file or a +derived from a portion of a MIDI file.

+ +

 

+ +

SMF-0: Standard MIDI File Type 0, a MIDI file that contains a single +track, but may be made up of multiple channels of MIDI +data.

+ +

 

+ +

SMF-1: Standard MIDI File Type 1, a MIDI file that contains a one more +tracks, and each track may in turn be made up of one or more channels of MIDI data. By convention, each channel is stored on a +separate track in an SMF-1 file. However, it is possible to have multiple MIDI +channels on a single track, or multiple tracks that contain data for the same MIDI channel.

+ +

 

+ +

Track: A single track in a DAW containing a timed sequence of MIDI events. Be careful not to confuse Tracks with +Channels. A MIDI file may contain many tracks with several tracks utilizing the +same MIDI channel.

+ +

 

+ +

 

+ +

1         +The JET Interactive Music Concept

+ +

Interactive music can be defined as music +that changes in real-time according to non-predictable events such as user +interaction or game play events. In this way, interactive music is much more +engaging as it has the ability to match the energy and mood of a game much +closer than a pre-composed composition that never changes. In some applications +and games, interactive music is central to the game play. Guitar Hero is one +such popular game. When the end user successfully ‘captures’ the musical notes +coming down the fret board, the music adapts itself and simultaneously keeps +score of successes and failures. JET allows for these types of music driven +games as well.

+ +

 

+ +

There are several methods for making and +controlling interactive music and JET is one such method. This section +describes the features of JET and how they might be used in a game or software +application. It also describes how JET can be used to save memory in small +footprint devices such as Android enabled mobile handsets.

+ +

1.1.1       Data Compression

+ +

JET supports a flexible music format that +can be used to create extended musical sequences with a minimal amount of data. +A musical composition is broken up into segments that can be sequenced to +create a longer piece. The sequencing can be fixed at the time the music file +is authored, or it can be created dynamically under program control.

+ +

1.1.2       Linear Music Example

+ +

+ +

Figure 1: Linear Music Piece

+ +

 

+ +

This diagram shows how musical segments are +stored. Each segment is authored as a separate MIDI +file. A post-processing tool combines the files into a single container file. +Each segment can contain alternate music tracks that can be muted or un-muted +to create additional interest. An example might be a brass accent in the chorus +that is played only the last time through. Also, segments can be transposed up +or down.

+ +

 

+ +

The bottom part of the diagram shows how +the musical segments can be recombined to create a linear music piece. In this +example, the bridge might end with a half-step key modulation and the remaining +segments could be transposed up a half-step to match.

+ +

1.1.3          +Non-linear Music Example

+ +

+ +

Figure 2: Non-linear music piece

+ +

 

+ +

In this diagram, we see a non-linear music +piece. The scenario is a first-person-shooter (FPS) and JET is providing the +background music. The intro plays as the level is loading and then transitions +under program control to the Searching segment. This segment is repeated +indefinitely, perhaps with small variations (using the mute/un-mute feature) +until activity in the game dictates a change.

+ +

 

+ +

As the player nears a monster lair, the +program starts a synchronized transition to the Danger segment, increasing the +tension level in the audio. As the player draws closer to the lair, additional +tracks are un-muted to increase the tension.

+ +

 

+ +

As the player enters into combat with the +monster, the program starts a synchronized transition to the Combat segment. +The segment repeats indefinitely as the combat continues. A Bonus Hit +temporarily un-mutes a decorative track that notifies the player of a +successful attack, and similarly, another track is temporarily un-muted to +signify when the player receives Special Damage.

+ +

 

+ +

At the end of combat, the music transitions +to a victory or defeat segment based on the outcome of battle.

+ +

1.1.4          +Mute/Un-mute Synchronization

+ +

JET can also synchronize the muting and +un-muting of tracks to events in the music. For example, in the FPS game, it +would probably be desirable to place the musical events relating to bonuses and +damage as close to the actual game event as possible. However, simply un-muting +a track at the moment the game event occurs might result in a music clip +starting in the middle. Alternatively, a clip could be started from the +beginning, but then it wouldn’t be synchronized with the other music tracks.

+ +

 

+ +

However, with the JET sync engine, a clip +can be started at the next opportune moment and maintain synchronization. This +can be accomplished by placing a number of short music clips on a decorative +track. A MIDI event in the stream signifies +the start of a clip and a second event signifies the end of a clip. When the +application calls the JET clip function, the next clip in the track is allowed +to play fully synchronized to the music. Optionally, the track can be +automatically muted by a second MIDI event.

+ +

 

+ +

+ +

Figure 3: Synchronized Mute/Unmute

+ +

1.2        +Audio Synchronization

+ +

JET provides an audio synchronization API +that allows game play to be synchronized to events in the audio. The mechanism +relies on data embedded in the MIDI file at +the time the content is authored. When the JET engine senses an event during +playback it generates a callback into the application program. The timing of +the callback can be adjusted to compensate for any latency in the audio +playback system so that audio and video can be synchronized. The diagram below +shows an example of a simple music game that involves pressing the left and +right arrows in time with the music.

+ +

 

+ +

 

+ +

+ +

Figure 4: Music Game with Synchronization

+ +

 

+ +

The arrows represent events in the music +sequence where game events need to be synchronized. In this case, the blue +arrow represents a time where the player is supposed to press the left button, +and the red arrow is for the right button. The yellow arrow tells the game +engine that the sequence is complete. The player is allowed a certain time +window before and after the event to press the appropriate key.

+ +

 

+ +

If an event is received and the player has +not pressed a button, a timer is set to half the length of the window. If the +player presses the button before the timer expires, the game registers a +success, and if not, the game registers a failure.

+ +

 

+ +

If the player presses the button before the +event is received, a timer is set to half the length of the window. If an event +is received before the timer expires, the game registers a success, and if not, +the game registers a failure. Game play might also include bonuses for getting +close to the timing of the actual event.

+ +

 

+ +

2         +JET Content Authoring Overview

+ +

To author JET files and hear them playback interactively, +the content author will work in two or three applications which are designed to +work together smoothly. The first is application is any off-the-shelf MIDI sequencing application or Digital Audio Workstation +that supports VST (for PC) or AU (for Mac) plugins. (Logic, SONAR, Cubase, etc) +Here the author will compose their MIDI music +files using the SONiVOX EAS Synth plugin as the playback synthesizer.

+ +

 

+ +

Once the composer has completed their MIDI file(s), they import them into the JET Creator application. +Here the author will setup and audition the conditions for interactive playback +within the JET enabled game.

+ +

 

+ +

Optionally, the author may elect to create +a custom DLS soundbank. This can be created in any off-the-shelf DLS authoring +application, such as Awave from MJSoft, and loaded into JET Creator along with +the MIDI files.

+ +

 

+ +

Below is an overview of this process. A +more detailed explanation of each step follows.

+ +

 

+ +
    +
  • Launch digital audio workstation (DAW)
  • +
      +
    • Assign the SONiVOX EAS Synth plugin as the playback + synthesizer
    • +
    • Optionally load a custom DLS2 soundset
    • +
    • Compose and save MIDI file(s)
    • +
    +
  • Launch the JET Creator application
  • +
      +
    • Create segments using the MIDI + and DLS2 source files
    • +
    • Add interactive elements
    • +
    • Audition interactive elements
    • +
    • Save and Export JET files for use in the Android application
    • +
    +
+ +

 

+ +

Launch DAW – Content authors will need to +use a third party MIDI authoring application to compose their MIDI +files. It is recommended they use a digital audio workstation (DAW) application +that supports VST or AU plugins as this will enable them to listen to the EAS +MIDI Synthesizer and DLS2 soundsets that will be utilized in the Android +application itself. Some examples of popular DAWs include SONAR (PC) and LOGIC +(MAC).

+ +

 

+ +

Assign SONiVOX EAS Synth plugin as the +playback synthesizer – The SONiVOX EAS Synth plugin is a VST and AU compatible +virtual instrument that plugs into VST or AU compatible DAWs. This software +plugin uses the same SONiVOX EAS MIDI synthesizer engine and default General +MIDI  wavetable soundset inherent in +Android. Using this plugin allows content authors to hear the exact audio +rendering of the instruments and MIDI file +that will be used in their Android applications.

+ +

 

+ +

Optionally Load DLS2 Soundset – The SONiVOX +EAS Synth plugin allows for the loading of any DLS2 compatible soundset for +playback. These could include a new GM wavetable set, or a small collection of +just a few custom instruments for a given application. Note, the DLS file does +not replace the internal GM wavetable used by the EAS engine. DLS soundsets +play in conjunction with the internal GM wavetable.

+ +

 

+ +

Compose MIDI File – Compose MIDI soundtracks for the Android application.

+ +

 

+ +

Launch JET Creator – Once all DLS2 and MIDI source files have been authored, the content author +should launch the JET Creator and begin creating JET Segments. The segments +will reference the MIDI files and any custom +DLS2 soundbanks.

+ +

 

+ +

Assign JET Segment Attributes – After +creating segments the content author interactive elements. Interactive elements +include mute and unmute settings of individual tracks in the MIDI file(s) as +well as MIDI controller numbers that serve as +“events” in the game. These attributes tell the JET engine how and when to play +the different musical segments according to the JET API commands in the Android +application. See below for more detail on this.

+ +

 

+ +

Audition Interactive Playback – After +assigning the segment attributes and creating the JET file, the content author +can audition all interactive playback elements in the JET Audition window.

+ +

 

+ +

Save .jtc File – After the author is +satisfied with the result, it is recommended they save the JET Creator .jtc +file which will save their settings, references to source files, etc.

+ +

 

+ +

Export Files – Exporting the JET Creator +file will bundle all source files and their attributes into a single .zip file. +The zip file will also contain a .jet file for use by the Android application.

+ +

 

+ +

 

+ +

3         +EAS Synth Virtual Instrument Plugin

+ +

Included in the JET Creator package is the +EAS software synthesizer in plug-in format. The EAS plugin synth allows the +composer to hear the instruments used in Android as they are composing their MIDI sequence. The EAS Synth plugin allows for the +loading of custom DLS2 sounds as well.

+ +

 

+ +

3.1        +Installing the EAS Synth Plugin

+ +

Follow the instructions for your individual +DAW to install and utilize the plugin. For Mac users this will typically +involve copying the “EAS Synth.componant” file into your plugins folder which +is usually located at /Library/Audio/Plug-ins/Components. PC users will want to +install the “EAS Synth.dll” into the plugin folder that their DAW requires.

+ +

 

+ +

3.2        +Requirements and Settings for +using the EAS Synth Plugin

+ +

The EAS Synth is an embedded synthesizer +for small mobile devices. This means it does not have the flexibility of high +end synthesizers typically utilized in a professional application such as +Logic, Digital Performer, etc. As such, only the following attributes are +supported.

+ +

 

+ +

Macintosh:

+ +

 

+ +

Mac OSX (Intel) Macs

+ +

ASIO Supported Soundcards

+ +

Sample Rate:    44100 hz

+ +

Buffer Size:       256 kbytes

+ +

 

+ +

PC:

+ +

 

+ +

Windows 2000 or Vista +operating systems

+ +

ASIO supported soundcards

+ +

Sample Rate:    44100 hz

+ +

Buffer Size:       256 kbytes

+ +

 

+ +

3.3        +Assigning MIDI +Tracks to use the EAS Synth

+ +

Each DAW has its own particular method of +assigning MIDI tracks to virtual instrument +plugins such as the SONiVOX EAS Synth. Please consult the user manual for your +DAW for detailed instructions. Below are some general guidelines for Logic +(Mac) and SONAR (PC).

+ +

3.3.1          +LOGIC 8

+ +

The SONiVOX EAS Synth virtual instrument is +a multi-timbral synthesizer. (i.e. it plays back multiple instruments on unique +MIDI channels in a single instance) In Logic +8, however, you’ll want to set up 16 Logic Instruments, +each with their own instance of the EAS Synth. Each Instrument should be assigned +its own MIDI channel. Use Channel 10 for +Drums. The reason for this is that MIDI controller messages, such as Volume +(CC7) and Pan (CC10) will not be channelized if the plugin is assigned to only +a single Instrument and all MIDI tracks are +set to playback on that Instrument. In order for each MIDI +channel to respond to its own controller messages, you must assign 16 different +EAS Synth instances to 16 unique Logic Instruments.

+ +

 

+ +

A Logic 8 template file has been included +in the Android Cupcake release to facilitate the above.

+ +

 

+ +

Playback in Logic 8 may require you to be +in record enable mode for each track you are auditioning. To record enable +multiple tracks hold down the Option key.

+ +

 

+ +

To write out a standard MIDI +(type 1) file from Logic, you need to use the File Export command. IMPORTANT: +Most edits in Logic are non-destructive edits meaning they are not modifying +the actual data but rather adding an overlay onto to the data. Quantize is one +such non-destructive edit. Therefore when you export a MIDI +file, you may not see your quanitization settings.

+ +

 

+ +

In addition, the mix parameters for volume, +pan and program changes may not appear in the event list and therefore may not +write out with the MIDI file. Before exporting +a MIDI file in Logic it is recommended you do +the following:

+ +

 

+ +

Select All and use the “Insert MIDI > +Insert MIDI Settings as Events” command.

+ +

 

+ +

Select All and use the “Apply Quantization +Settings Destructively” command.

+ +

 

+ +

3.3.2          +Cakewalk SONAR 7

+ +

Sonar 7 is a bit easier to set up, use and +save than Logic 8. Simply open or start a new MIDI +file. Go to the Insert menu and select Insert Soft Synth>SONiVOX>EAS +Synth. Then assign each MIDI track’s output to +the EAS Synth. There is no need to record enable a track to hear it play back. +When saving, be sure to select MIDI Type 1.

+ +

 

+ +

SONAR 8 works similarly to SONAR 7.

+ +

 

+ +

3.3.3          +Digital Performer

+ +

We’ve seen some instances when creating +content with Digital Performer where notes with a release velocity of non-0 +will generate an extra note-on event in the EAS synth. If you are hearing a +doubling, editing the release velocity events to zero should fix this problem.

+ +

 

+ +

3.4        +Using Custom DLS2 Soundsets

+ +

The SONiVOX EAS Synthesizer supports two +simultaneous soundsets or wavetables. One is the internal General MIDI wavetable +inherent to the SONiVOX EAS Synthesizer. The other is a Downloadable Sounds +Level 2 (DLS2) soundset. The internal wavetable is a GM Level 1 compliant +wavetable with 127 melodic instruments and 1 drumkit. It is in a proprietary +SONiVOX format. The DLS2 soundsets are an open format published by the MIDI +Manufactures Association.

+ +

 

+ +

In the Android Cupcake release, the +internal wavetable is only 200 kbytes, very small, in order to be compliant +with all Android devices which may not have a lot of memory. DLS2 soundsets can +be any size that a particular device supports. Upgraded (larger) internal +wavetables as well as custom DLS2 instruments can be licensed from SONiVOX.

+ +

3.4.1          +Loading a DLS2 Soundset

+ +

To load a custom soundset, click on the +Load DLS button in the EAS Synth plugin interface. Browse to the DLS2 file you +wish to load and say OK. Only DLS Level 2 formatted soundsets are +supported.

+ +

 

+ +

3.4.2          +Using a DLS2 Soundset

+ +

Since both the internal EAS GM wavetable +and a custom DLS2 soundset are used simultaneously, you must be sure you have +your MIDI Program Changes set correctly. DLS2 instruments must be assigned to a +Bank other than the default GM bank +used by the internal synthesizer.

+ +

 

+ +

The internal EAS synthesizer is assigned to +Banks 121 (melodic instruments) and 120 (drum instruments). This follows the +General MIDI Level 1 specification. Note: Most MIDI +sequencers require you to use Bank 0 to select the default wavetable. Custom +DLS2 soundsets, therefore, should utilize a different Bank. We recommend Bank +1.

+ +

 

+ +

The EAS synth supports MSB (Controller 0), +LSB (Controller 32) Bank change messages. There are two places you need to set +this Bank and Program Change number. The first is in your DLS2 soundset. Using +Bank 1, each Instrument would be assigned MSB 1, LSB 0, then the Instrument +Program Change number. The second place to use the Bank and Program Change +number is in your MIDI sequence.

+ +

 

+ +

In your MIDI +track, the MSB should be sent first followed by the LSB and then the Instrument +number. For example, if your DLS2 instrument is assigned MSB 1, LSB 0, +Program1, you would send CC0, 1 followed by CC32, 0 followed by Program Change +Message 1. This might look like the following in an event window:

+ +

 

+ +

 

+ +

+ +

 

+ +

 

+ +

 

+ +

4         +JET Creator Guidelines

+ +

JET Creator is the desktop application +where you’ll edit and audition the JET interactive music elements. For details +on the JET Creator application please see the “JET Creator User Manual”. Below +are some additional guidelines to help you out.

+ +

 

+ +

 

+ +

 

+ +

4.1        +Order of Tasks

+ +

As with all projects, its best to discuss and +design the interactive music scheme with the game designer and programmer +before beginning your composition. An outline and/or specification can go a +long way in saving you from having to redo things after the game is in place.

+ +

 

+ +

In general you’ll want to first write your +music in your DAW of choice the way you’re used to composing, then break up the +final MIDI file as needed for the application. +Next, move to JET Creator and create all of your music segments in the order +easiest to preview them when played in order. Finally, add the JET Events to +control the segments via the Android game and Audition them as needed in JET +Creator. Finally, save the project in JET Creator and hand off the .jet file to +the programmer to integrate it in the game. After previewing there will likely +be changes to the MIDI file(s) and JET Creator +attributes.

+ +

 

+ +

4.2        +Conserving Memory

+ +

If you’re trying to conserve memory, +compose as few MIDI files as possible, and create several segments from that MIDI file. For example a 12 bar MIDI +file with three sections of 4 bars, A, B, C, can create a much longer song. +Simply create multiple segments that reference the one MIDI +file, then order them however you like. For example, A, A, B, A, C, A, B, A, A +would create a 36 bar song. Use JET to add repeats, transpose segments, and +interactively mute and unmute tracks to keep it even more interesting.

+ +

 

+ +

4.3        +Replicate

+ +

To make adding segments or events faster, +use the Replicate command. Replicate can add multiple segments or events at one +time and uses an offset parameter and prefix naming convention to keep things +easy to read. The MOVE command is also useful for moving multiple events by a +set number of measures, beats or ticks.

+ +

 

+ +

4.4        +Interactive Options

+ +

There are several interactive audio +concepts possible in JET. Below are a few examples although we hope developers +will come up with others we haven’t thought of! These are:

+ +

4.4.1          +Multiple Segment Triggering

+ +

In this method the application is +triggering specific segments based on events in the game. For example a hallway +with lots of fighting might trigger segment 1 and a hallway with no fighting +might trigger segment 2. Using JET TriggerClips in conjunction with this method +creates even more diversity.

+ +

4.4.2          +Mute Arrays

+ +

In this method the application is +triggering mute and unmute events to specific tracks in a single MIDI sequence. For example a hallway with lots of +fighting might play MIDI tracks 1-16 and a +hallway with no fighting might play the same midi file but mute tracks 9-16. +Using JET TriggerClips in conjunction with this method creates even more +diversity.

+ +

4.4.3          +Music Driven Gameplay

+ +

Music driven gaming is similar to what +Guitar Hero and JETBOY have done in that the music content determines how +graphic events are displayed. The application then queries the user response to +the graphic events and interactively modifies the music in response. In this +method the game is utilizing JET Application Events, MIDI controllers that are +embedded in the MIDI file and read by the game +in real-time. Based on the user response, multiple segment triggering and/or +mute arrays can be set.

+ +

 

+ +

 

+ +
+ + + + diff --git a/common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines_files/header.htm b/common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines_files/header.htm new file mode 100755 index 0000000..4284a7a --- /dev/null +++ b/common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines_files/header.htm @@ -0,0 +1,202 @@ + + + + + + + + + + + + + + +
+ +

+ +


+ +

+ +

 

+ +

 

+ +

 

+ +

 

+ +
+ +
+ +

+ +


+ +

+ +

 

+ +

 

+ +

 

+ +

 

+ +
+ +
+ +

+ +


+ +

+ +

 

+ +

 

+ +

 

+ +

 

+ +
+ +
+ +

+ +


+ +

+ +

 

+ +

 

+ +

 

+ +

 

+ +
+ +
+ +

 

+ +

 

+ +

 

+ +

 

+ +

 

+ +

 

+ +

 

+ +

 

+ +

 

+ +

 

+ +

 

+ +

 

+ +

 

+ +
+ +
+ +

+ +

 

+ +

 

+ +

 

+ +

 

+ +
+ +
+ +

 

+ +

 

+ +
+ +
+ +

 

+ +

 

+ +

 

+ +

 

+ +
+ +
+ +

SONiVOX JET Creator User Documentation    +Vrs.3   Page 1/13

+ +
+ + + + diff --git a/common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines_files/image001.jpg b/common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines_files/image001.jpg new file mode 100755 index 0000000..d244843 Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines_files/image001.jpg differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines_files/image002.emz b/common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines_files/image002.emz new file mode 100755 index 0000000..f152c11 Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines_files/image002.emz differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines_files/image004.emz b/common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines_files/image004.emz new file mode 100755 index 0000000..010c4bd Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines_files/image004.emz differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines_files/image006.emz b/common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines_files/image006.emz new file mode 100755 index 0000000..a29ebfd Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines_files/image006.emz differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines_files/image008.gif b/common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines_files/image008.gif new file mode 100755 index 0000000..17919fd Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines_files/image008.gif differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines_files/image010.gif b/common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines_files/image010.gif new file mode 100755 index 0000000..54111a0 Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines_files/image010.gif differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines_files/image011.png b/common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines_files/image011.png new file mode 100755 index 0000000..1573b01 Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines_files/image011.png differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines_files/image012.gif b/common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines_files/image012.gif new file mode 100755 index 0000000..4300d15 Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines_files/image012.gif differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines_files/image013.gif b/common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines_files/image013.gif new file mode 100755 index 0000000..eb1aa37 Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines_files/image013.gif differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines_files/image014.gif b/common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines_files/image014.gif new file mode 100755 index 0000000..4e99824 Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines_files/image014.gif differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines_files/image015.emz b/common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines_files/image015.emz new file mode 100755 index 0000000..31cba25 Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Authoring_Guidelines_files/image015.emz differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual.html b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual.html new file mode 100755 index 0000000..8582f5f --- /dev/null +++ b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual.html @@ -0,0 +1,3032 @@ + + + + + + + + + + + +SONiVOX JET Creator User Manual + + + + + + + + +
+   Copyright (C) 2009 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ +
+ +

JETCreator™ User Manual

+ +

Vrs 1.0

+ +

Content +Authoring Application for the

+ +

JET +Interactive Music Engine

+ +

Authored by SONiVOX

+ +

www.sonivoxrocks.com

+ +

Copyright 2009 Sonic Network, Inc.

+ + + +

 

+ +

 

+ +

1         +Introduction

+ +

1.1        +Overview

+ +

This document contains the user guidelines +for the SONiVOX JET Creator, an authoring application for creating and +auditioning JET files. JET is an interactive music player for small embedded +devices, including the Google Android platform. It allows applications to +include interactive music soundtracks, in MIDI +format, that respond in real-time to game play events and user interaction.

+ +

 

+ +

JET works in conjunction with SONiVOX’s +Embedded Audio Synthesizer (EAS) which is the MIDI +playback device for Android.  Both the +JET and EAS engines are integrated into the Android embedded platform as well +as inherent in the JET Creator application. As such, the JET content author can +be sure that the playback will sound exactly the same in both the JET Creator +and the final Android application playing back on Android mobile devices.

+ +

 

+ +

In addition to the graphical user +interface, there are two main functionalities taking place in JET Creator. The +first involves gathering all the source data (MIDI +files and DLS file), adding JET’s real-time attributes and building a JET +(.jet) file that the Android application will use. The second functionality +involves auditioning the interactive playback elements as they will take place +in the Android application.

+ +

 

+ +

The JET Creator application is written in +the Python programming language, therefore you need to have the current version +of Python and WXWidgets installed. There is both a Mac and Windows version.

+ +

 

+ +

 

+ +

1.2        +Abbreviations and Common Terms

+ +

 

+ +

It is important to use a common set of +terms to minimize confusion. Since JET uses MIDI +in a unique way, normal industry terms may not always suffice. Here is the +definition of terms as they are used in this document and in the JET Creator +application:

+ +

 

+ +

Channel: MIDI data associated with a specific MIDI +channel. Standard MIDI allows for 16 channels of MIDI +data each of which are typically associated with a specific instrument.

+ +

 

+ +

Controller: A MIDI event consisting of a +channel number, controller number, and a controller value. The MIDI spec associates many controller numbers with +specific functions, such as volume, expression, sustain pedal, etc. JET also +uses controller events as a means of embedding special control information in a +MIDI sequence to provide for audio synchronization.

+ +

 

+ +

DAW: Digital Audio Workstation. A common term for MIDI +and audio sequencing applications such as Logic, SONAR, Cubase and others.

+ +

 

+ +

EAS: Embedded MIDI Synthesizer. The +name of the SONiVOX MIDI synthesizer engine.

+ +

 

+ +

JET: Jet Interactive Engine. The name of the SONiVOX JET interactive +music engine.

+ +

 

+ +

M/B/T: Measures, Beats and Ticks

+ +

 

+ +

Segment: A musical section such as a chorus or verse that is a component of +the overall composition. In JET, a segment can be an entire MIDI file or a +derived from a portion of a MIDI file.

+ +

 

+ +

SMF-0: Standard MIDI File Type 0, a MIDI file that contains a single +track, but may be made up of multiple channels of MIDI +data.

+ +

 

+ +

SMF-1: Standard MIDI File Type 1, a MIDI file that contains a one more +tracks, and each track may in turn be made up of one or more channels of MIDI data. By convention, each channel is stored on a +separate track in an SMF-1 file. However, it is possible to have multiple MIDI +channels on a single track, or multiple tracks that contain data for the same MIDI channel.

+ +

 

+ +

Track: A single track in a DAW containing a timed sequence of MIDI events. Be careful not to confuse Tracks with +Channels. A MIDI file may contain many tracks with several tracks utilizing the +same MIDI channel.

+ +

 

+ +

 

+ +

1         +The JET Interactive Music Concept

+ +

Interactive music can be defined as music +that changes in real-time according to non-predictable events such as user +interaction or game play events. In this way, interactive music is much more +engaging as it has the ability to match the energy and mood of a game much +closer than a pre-composed composition that never changes. In some applications +and games, interactive music is central to the game play. Guitar Hero is one +such popular game. When the end user successfully ‘captures’ the musical notes +coming down the fret board, the music adapts itself and simultaneously keeps +score of successes and failures. JET allows for these types of music driven +games as well.

+ +

 

+ +

There are several methods for making and +controlling interactive music and JET is one such method. This section +describes the features of JET and how they might be used in a game or software +application. It also describes how JET can be used to save memory in small +footprint devices such as Android enabled mobile handsets.

+ +

1.1.1       Data Compression

+ +

JET supports a flexible music format that +can be used to create extended musical sequences with a minimal amount of data. +A musical composition is broken up into segments that can be sequenced to +create a longer piece. The sequencing can be fixed at the time the music file +is authored, or it can be created dynamically under program control.

+ +

1.1.2       Linear Music Example

+ +

+ +

Figure 1: Linear Music Piece

+ +

 

+ +

This diagram shows how musical segments are +stored. Each segment is authored as a separate MIDI +file. A post-processing tool combines the files into a single container file. +Each segment can contain alternate music tracks that can be muted or un-muted +to create additional interest. An example might be a brass accent in the chorus +that is played only the last time through. Also, segments can be transposed up +or down.

+ +

 

+ +

The bottom part of the diagram shows how +the musical segments can be recombined to create a linear music piece. In this +example, the bridge might end with a half-step key modulation and the remaining +segments could be transposed up a half-step to match.

+ +

1.1.3          +Non-linear Music Example

+ +

+ +

Figure 2: Non-linear music piece

+ +

 

+ +

In this diagram, we see a non-linear music +piece. The scenario is a first-person-shooter (FPS) and JET is providing the +background music. The intro plays as the level is loading and then transitions +under program control to the Searching segment. This segment is repeated indefinitely, +perhaps with small variations (using the mute/un-mute feature) until activity +in the game dictates a change.

+ +

 

+ +

As the player nears a monster lair, the +program starts a synchronized transition to the Danger segment, increasing the +tension level in the audio. As the player draws closer to the lair, additional +tracks are un-muted to increase the tension.

+ +

 

+ +

As the player enters into combat with the +monster, the program starts a synchronized transition to the Combat segment. +The segment repeats indefinitely as the combat continues. A Bonus Hit +temporarily un-mutes a decorative track that notifies the player of a +successful attack, and similarly, another track is temporarily un-muted to +signify when the player receives Special Damage.

+ +

 

+ +

At the end of combat, the music transitions +to a victory or defeat segment based on the outcome of battle.

+ +

1.1.4          +Mute/Un-mute Synchronization

+ +

JET can also synchronize the muting and +un-muting of tracks to events in the music. For example, in the FPS game, it would +probably be desirable to place the musical events relating to bonuses and +damage as close to the actual game event as possible. However, simply un-muting +a track at the moment the game event occurs might result in a music clip +starting in the middle. Alternatively, a clip could be started from the +beginning, but then it wouldn’t be synchronized with the other music tracks.

+ +

 

+ +

However, with the JET sync engine, a clip +can be started at the next opportune moment and maintain synchronization. This +can be accomplished by placing a number of short music clips on a decorative +track. A MIDI event in the stream signifies +the start of a clip and a second event signifies the end of a clip. When the +application calls the JET clip function, the next clip in the track is allowed +to play fully synchronized to the music. Optionally, the track can be +automatically muted by a second MIDI event.

+ +

 

+ +

+ +

Figure 3: Synchronized Mute/Unmute

+ +

1.2        +Audio Synchronization

+ +

JET provides an audio synchronization API +that allows game play to be synchronized to events in the audio. The mechanism +relies on data embedded in the MIDI file at +the time the content is authored. When the JET engine senses an event during +playback it generates a callback into the application program. The timing of +the callback can be adjusted to compensate for any latency in the audio +playback system so that audio and video can be synchronized. The diagram below +shows an example of a simple music game that involves pressing the left and +right arrows in time with the music.

+ +

 

+ +

 

+ +

+ +

Figure 4: Music Game with Synchronization

+ +

 

+ +

The arrows represent events in the music sequence +where game events need to be synchronized. In this case, the blue arrow +represents a time where the player is supposed to press the left button, and +the red arrow is for the right button. The yellow arrow tells the game engine +that the sequence is complete. The player is allowed a certain time window +before and after the event to press the appropriate key.

+ +

 

+ +

If an event is received and the player has +not pressed a button, a timer is set to half the length of the window. If the +player presses the button before the timer expires, the game registers a +success, and if not, the game registers a failure.

+ +

 

+ +

If the player presses the button before the +event is received, a timer is set to half the length of the window. If an event +is received before the timer expires, the game registers a success, and if not, +the game registers a failure. Game play might also include bonuses for getting +close to the timing of the actual event.

+ +

 

+ +

2         +JET Content Authoring Overview

+ +

To author JET files and hear them playback +interactively, the content author will work in two applications which are +designed to work together smoothly. The first is application is any +off-the-shelf MIDI sequencing application that +supports VST (for PC) or AU (for Mac) plugins. Here the author will compose +their MIDI music files using the plugin as the +synthesizer device. The second application is the JET Creator application. Here +the author will import their MIDI music files +(and optionally a DLS2 soundset) and setup the conditions for interactive +playback within the JET enabled game. Optionally the content author may create +a custom set of DLS instruments using an instrument editor that supports the +DLS Level 2 format. One such application is Awave from MJSoft.

+ +

 

+ +

Please see the JET Content Authoring Guidelines documentation for additional +details on content authoring.

+ +

 

+ +

3         +Installing and Launching JET +Creator

+ +

JET Creator is a python language +application, therefore, you must have Python and wxPython installed on your +machine.

+ +

 

+ +

JetCreator was created and tested with:

+ +

 

+ +

Python Version 2.5.4

+ +

wxPython Version 2.8.7.1

+ +

 

+ +

These can be downloaded here:

+ +

 

+ +

PC:

+ +

http://www.python.org/download/releases/2.5.4/

+ +

http://www.wxpython.org/download.php

+ +

 

+ +

MAC:

+ +

http://wiki.python.org/moin/MacPython/Leopard

+ +

http://www.wxpython.org/download.php

+ +

 

+ +

After installing Python and wxPython, +simply unzip or copy all the files in the JET Creator application directory to +a folder on your hard drive.

+ +

                                                    

+ +

To launch JET Creator go to a command +prompt and set the directory to where you’ve installed Python. Next run python +with the command:

+ +

 

+ +

python +jetcreator.py

+ +

 

+ +

 

+ +

4         +Using JET Creator

+ +

 

+ +

4.1        +File Types

+ +

There are a few different file types +associated with JET Creator.

+ +

 

+ +

.jtc        JET +Creator project file. This file contains all the information associated with a +JET Creator project. When you Save or Save-as out of JET Creator, this file +type is saved.

+ +

 

+ +

.jet        JET +File. This output file is automatically generated from JET Creator whenever you +save your JET Creator project. This is the file that bundles all JET assets +together into a single file that the Android application will use. Give this +file to the Android application developer.

+ +

 

+ +

.mid      MIDI File. This is the standard MIDI +type 1 file that JET Creator will use to make segments.

+ +

 

+ +

.seg      Segment +File. This is a JET Segment file. It has the same name as the MIDI +file which it references but contains additional Segment information.

+ +

 

+ +

.zip       Zip +Archive file. When you Export a JET Archive, a zip file is created that +contains all the assets (files) necessary for JET Creator. Use this to transfer +JET Creator projects to other people.

+ +

 

+ +

4.2        +Open Dialog

+ +

When +you first launch JET Creator you are presented with an open dialog like the +following.

+ +

 

+ +

+ +

 

+ +

 

+ +

Open will open an existing .jtc (JET Creator file) file. Use the browser +button to browse to the directory where you have saved your .jtc file.

+ +

 

+ +

New will create a new .jtc file.

+ +

 

+ +

Import will import a JET Archive (.zip) file.

+ +

 

+ +

Cancel will cancel the dialog and exit the application.

+ +

 

+ + + +

5         +Main Window

+ +

The main window of the JET Creator +application looks like the picture below. There are three main sections from +top to bottom: segment view, event view, and timeline.

+ +

 

+ +

The segment view section displays a list of +the current segments, which MIDI file and +(optionally) DLS2 file each segment is derived from. It also shows each +segments start and stop time and each segments quantize, transpose, repeat and +mute flag settings.

+ +

 

+ +

Just below the Segment view is the event +view. The event view section displays all events associated with a given +segment. Events only display when the segment they are assigned to is +highlighted. Each event displays its type, start and end points, track and midi +channel assignment, and its event ID.

+ +

 

+ +

Just below the Event view is the timeline +display. The timeline shows how many measures a given segment is as well as any +events associated with that segment. The timeline changes to display the +currently selected or playing segment. You can trigger an event in this window +while the segment is play by simply clicking on the event in the timeline +display.

+ +

 

+ +

 

+ +

+ +

 

+ +

JET +Creator Main Window

+ +

 

+ +

 

+ +

The buttons along the left side of main +window do the following:

+ +

 

+ +

Add:                    - +Displays the segment or event window for adding a new segment or event

+ +

Revise:                - +Displays the segment or event window for updating an existing segment or event

+ +

Delete:                 - +Deletes the selected segment or event (will ask for confirmation)

+ +

Move:                  - +Displays the move window which allows you to move selected segments or events +in time

+ +

Queue All:            - Queue’s +(selects) all segments for playback

+ +

Dequeue All:        - Dequeue’s +(deselects) all segments

+ +

Play:                    - +Starts playback of all queue’d segments. This button changes to Stop if any +segments are playing

+ +

Audition:              - +Displays the Audition window (see below)

+ +

 

+ +

5.1        +Segment Window

+ +

The segment window is where a given +segment’s attributes are assigned and auditioned, as shown in the picture +below. The left side of the window displays the segments attributes that are +stored in the JET file. The right side of the window allows the author to set +mute flags, repeat and transpose settings and audition the segment as it will +play in the JET game.

+ +

 

+ +

Note: the audition attributes (mute flags, repeat and transpose) are not stored in the JET content file +(.jet) but rather are defined by the game or application itself. In programming +language, these settings correspond directly with the API calls to the JET +engine. By including them here, the JET content author can simulate how the +segment will respond to the applications API commands during game play.

+ +

 

+ +

 

+ +

+ +

 

+ +

 

+ +

The segment parameters do the following:

+ +

 

+ +

Segment Name             - Sets +the name of the segment

+ +

MIDI File                       - +The name and location of the MIDI file from which +the segment is derived. The button to the immediate right will bring up a +browser for locating a midi file on the hard drive.

+ +

DLS File                       - +The name and location of the DLS2 file, if any, that the MIDI +file uses for that segment.

+ +

Starting M/B/T               - +Starting measure, beat and tick of the segment

+ +

Ending M/B/T                - +Ending measure, beat and tick of the segment

+ +

Quantize                       - +Quantize value for quantizing the current segment during playback

+ +

 

+ +

 

+ +

The audition fields are as follows:

+ +

 

+ +

Track Mutes                  - +Shows the MIDI tracks (not channels) +in the MIDI file. Clicking on a track’s +checkbox will mute that track.

+ +

Channel                        - +Displays the MIDI channel assigned to each +track

+ +

Name                            - +Displays the track name meta event (if present) for each track

+ +

Repeat                          - +Indicates the number of times a segment should repeat during playback

+ +

Transpose                     - +Indicates the transposition in semi-tones or half-steps a segment should +transpose during playback

+ +

 

+ +

To the right of the Audition window are a few additional buttons. +These do as follows:

+ +

 

+ +

OK                               - +Selecting OK confirms all segment settings and closes the segment window

+ +

Cancel                          - +Selecting Cancel cancels any changes and closes the segment window

+ +

Replicate                      - +Displays the Replicate Segment window for entering multiple segments at once. +See below.

+ +

Play/Stop Segment       - Starts +or Stops playback of the segment using the segment attributes assigned.

+ +

Play/Stop MIDI File       - +Starts or Stops playback of the MIDI file +which the segment is assigned to.

+ +

Pause/Resume              - +Pauses or Resumes playback.

+ +

 

+ +

 

+ +

5.2        +Event Window

+ +

The event window is where a given segment’s +event attributes are assigned and auditioned, as shown in the picture below. To +add an event to a segment, the author must first select the segment which will +contain the event, then select the Add button. This will bring up the Event +window.

+ +

 

+ +

+ +

 

+ +

 

+ +

There are two main sections to the event +window. The segment section on the left side of the event window is for display +only. It shows what the segment attributes are for the given segment. The Event +section, on the right side, is where events can be assigned. The following +parameters are available:

+ +

 

+ +

Event Name                    - +Assigns a name to an event

+ +

Event Type                     - +Selects which type of event to assign.

+ +

Starting M/B/T                - +Sets the starting measure, beat, and tick for the event

+ +

Ending M/B/T                 - +Sets the ending measure, beat, and tick for the event, if applicable

+ +

Track                              - +Sets which track in the given segment the event will apply to

+ +

Channel                          - +Sets which MIDI channel the event will apply +to. The MIDI channel should match the MIDI +channel of the track

+ +

Event ID                         - +Sets the event ID for the event. Multiple events can be assigned to the same +segment and therefore the Event ID is used to identify them

+ +

 

+ +

To the right of the Audition window are a few additional buttons. +These do as follows:

+ +

 

+ +

OK                               - +Selecting OK confirms all event settings and closes the event window

+ +

Cancel                          - +Selecting Cancel cancels any changes and closes the event window

+ +

Replicate                      - +Displays the Replicate Event window for entering multiple events at once. See +below.

+ +

Play/Stop                     - +Starts or Stops playback of the segment using the segment attributes assigned. +While the segment is playing, events can be triggered and auditioned.

+ +

Trigger                          - +Triggers the event assigned. This replicates the API command that the JET game +will use to trigger the event, therefore giving the content author a method for +auditioning the behaviour of the event.

+ +

Mute/UnMute                 - +Mute/UnMute will mute or unmute the track that the event is assigned to

+ +

Pause/Resume              - +Pauses or Resumes playback.

+ +

 

+ +

To audition the behaviour of an event, you +can select the Play button. This will initiate playback. The trigger button +will send the trigger event when pressed. This is equivalent to selecting the +green trigger event in the timeline.

+ +

 

+ +

Note: Trigger events are meant to unmute a +single track of a segment when triggered, then mute that track at the end of +the trigger segment. Therefore you should make sure the mute flag is set to +mute the track that a trigger event will be unmuting when receiving a trigger event. +

+ +

 

+ +

Please read Section 7 “Under The Hood” +below for details on how trigger events work and behave.

+ +

 

+ +

5.3        +Replicate Windows

+ +

Often in creating JET files, you’ll need to +create tens or even hundreds of events. You may also need to move events. The +Replicate and Move windows allow for this. There are two Replicate windows for +creating multiple segments or events. They look like the following:

+ +

 

+ +

+ +

 

+ +

Replicate Segment Window

+ +

 

+ +

 

+ +

 

+ +

+ +

 

+ +

Replicate Event Window

+ +

 

+ +

Both Replicate windows function the same. +After creating an initial segment or event, you can select the Replicate +button. The parameters are as follows:

+ +

 

+ +

Name Prefix                  - +Sets the prefix for the name of each segment or event created

+ +

Starting M/B/T               - +Sets the starting time for the first segment or event

+ +

Increment M/B/T            - +Sets the time between segments or events created.

+ +

Number                         - +Sets the number of segments or events you wish to create. If the number +overflows the length of the MIDI file (for +segments) or segment (for events), those objects will not be created.

+ +

Preview                         - +Preview allows you to examine the objects created before saying OK to insert +them.

+ +

 

+ +

 

+ +

5.4        +Move Windows

+ +

The Move function acts similarly to the +Replicate function in that it allows you to edit multiple segments or events at +one time, in this case move them in time. Like Replicate, there are two Move +windows, one for Segments and one for Events. The windows look like the +following:

+ +

 

+ +

+ +

 

+ +

Move Event Window

+ +

 

+ +

To use Move, first select the segments or +events you wish to move in time, then click the Move button. The parameters are +as follows:

+ +

 

+ +

Starting M/B/T               - +Sets the starting time for the first segment or event

+ +

Increment M/B/T            - +Sets the time in M/B/T you wish to move the objects by.

+ +

Preview                         - +Preview allows you to examine the objects created before saying OK to move +them.

+ +

 

+ +

 

+ +

5.5        +Audition Window

+ +

Clicking the Audition button in the main +window of the JET Creator application will open the Audition window. This is +where the content author or application programmer can simulate the interactive +playback as it may occur in the mobile application or game itself.

+ +

 

+ +

+ +

 

+ +

JET Audition Window

+ +

 

+ +

 

+ +

There are four main sections to the +audition window. The left most section displays the available segments and +their length in seconds. The middle section displays a running list of what +segments are queued for playback and what their playback status is. The far +right section displays the mute flags for the currently playing segment. The +timeline section at the bottom is the same as in the main window. It displays +the currently playing segment as well as a visual display of any event triggers +associated with that segment.

+ +

 

+ +

The Audition window allows you to queue up +any segment in any order for playback. To do this simply select the segment you +wish to cue and hit Queue. That segment will appear in the queue window and +start playing (if it is the first segment). Subsequently you can select any +other segment or segments and cue them up for playback. As the segments +complete playback, the next segment in the queue will begin playing. As is the +other windows of JET Creator, you can mute, unmute, trigger event clips, etc. +in realtime as each segment is playing back.

+ +

 

+ +

Specifically the buttons behave as follows:

+ +

 

+ +

Queue                           - +loads the selected segment into the queue and starts playback

+ +

Cancel and Queue         - +cancels the currently playing segment before queueing the selected segment for +playback

+ +

Cancel Current               - +cancels the currently playing segment in the queue and begins playback of the +next segment

+ +

Stop                             - +stops playback of all queued segments

+ +

Mute All                        - +mutes all tracks in the current segment

+ +

Mute None                    - +unmutes all tracks in the current segment

+ +

Original Mutes               - +sets the original mute flags for the current segment

+ +

 

+ +

The combination of these playback options +allows an author or application programmer to audition any behaviour an +interactive music application may encounter.

+ +

 

+ +

 

+ +

5.6        +JET Creator Menus

+ +

The JET Creator menus provide access to +many of the parameters in the main window plus a few additional parameters.

+ +

5.6.1          +File Menu

+ +

The File Menu contains the following +elements:

+ +

 

+ +

New                              - +Creates a new JET Creator file (.jtc)

+ +

Open                            - +Opens an existing JET Creator file

+ +

Save                             - +Saves the currently opened JET Creator file

+ +

Save As                        - +Saves the currently opened JET Creator file to a new file

+ +

Import Project               - Imports a JET Creator archive (.zip)

+ +

Export Project               - Exports a JET Creator archive (.zip)

+ +

Exit                              - +Exits the application

+ +

 

+ +

5.6.2          +Edit Menu

+ +

The Edit Menu contains the following +elements:

+ +

 

+ +

Undo                            - +Undo will undo the last edit made

+ +

Redo                            - +Redo will redo the last undo

+ +

Cut                               - +Copy selected parameter into clipboard and Delete selection

+ +

Copy                            - +Copy selected parameter into clipboard and keep selection

+ +

Paste                            - +Paste selected parameter

+ +

 

+ +

5.6.3          +JET

+ +

The Edit Menu contains the following +elements:

+ +

 

+ +

Properties                     - +Brings up the JET Creator priorities window. This window allows you to set the +following conditions for a given JET file:

+ +

Copyright Info               - Contains copyright info to be inserted into JET file

+ +

Chase Controllers          - Option to chase controllers (on/off). This should usually +be ON.

+ +

Delete Empty Tracks     - Deletes any empty MIDI tracks

+ +

 

+ +

5.6.4          +Segments

+ +

The Segments Menu contains the following +elements:

+ +

 

+ +

Add Segment                - +Brings up the Segment window

+ +

Update Segment           - Updates segment attributes

+ +

Delete Segment                        - Deletes the current segment from the +Segment List

+ +

 

+ +

5.6.5          +Help

+ +

The Help Menu will contain at least the +following elements:

+ +

 

+ +

JET Creator Help           - will launch PDF help document or go to on-line help

+ +

About                           - +JET Creator version number, SONiVOX info

+ +

 

+ +

 

+ +

6         +Trigger Events Explained

+ +

Breaking a MIDI +file into individual (non-linear) segments and queueing up those segments for +playback in a game based on events within the game is one way JET music files are +interactive. Trigger events are an additional method for interactive playback. +Both would be used together in an interactive game or application.

+ +

 

+ +

Trigger events allow for the following:

+ +

 

+ +
    +
  1. Tracks within a MIDI segment can be turned on or off based on game + events. For example the composer could author two drum tracks, one fast + and one slow. If the action in a game is fast, the fast drum track could + play. If the action in the game is slow, the slow drum track can play.
  2. +
  3. User actions can be compared to trigger events which are + pre-inserted into a music file at musically ‘correct’ places. Based on the + results, scoring or other game actions can take place.
  4. +
  5. Musical transitions between levels or action sequences can be + synchronized to be musically seemless.
  6. +
+ +

 

+ +

Under the hood, JET uses standard MIDI CC +events to accomplish these actions and to synchronize audio. The controllers +used by JET are among those not defined for specific use by the MIDI specification. The specific controller definitions +are as follows:

+ +

 

+ +

            Controllers +80-83           Reserved for use by +application

+ +

            Controller +102                JET event marker

+ +

            Controller +103                JET clip marker

+ +

            Controllers +104-119        Reserved for future use

+ +

 

+ +

6.1        +JET Clip Marker (CC103)

+ +

Controller 103 is reserved for marking +clips in a MIDI track that can be triggered by +the JET_TriggerClip API call. The clip ID is encoded in the low 6 bits of the +controller value. Bit 6 is set to one to indicate the start of a clip, and set +to zero to indicate the end of a clip.

+ +

 

+ +

For example, to identify a clip with a clip +ID of 1, the author inserts a MIDI controller +event with controller=103 and value=65 at the start of the clip and another +event with controller=103 and value=1 at the end of the clip. When the +JET_TriggerClip() function is called with a clip ID of 1, the track will be +un-muted when the controller value 65 is encountered and muted again when the +controller value 1 is encountered.

+ +

 

+ +

+ +

Figure 5: Synchronized Clip

+ +

 

+ +

In the figure above, if the +JET_TriggerClip() function is called prior to the first controller event, Track +3 will be un-muted when the first controller event occurs, the first clip will +play, and the track will be muted when the second controller event occurs. If +the JET_TriggerClip() function is called after the first controller event has +occurred, Track 3 will be un-muted when the third controller event occurs, the +second clip will play, and the track will be muted again when the fourth +controller event occurs.

+ +

 

+ +

Note: Normally, the track containing the clip is muted by the application +when the segment is initially queued by the call to JET_QueueSegment(). If it +is not muted, the clip will always play until Jet_TriggerClip() has been called +with the clip ID.

+ +

 

+ +

6.2        +JET Event Marker (CC102)

+ +

Controller 102 is reserved for marking +events in the MIDI streams that are specific +to JET functionality. Currently, the only defined value is 0, which marks the +end of a segment for timing purposes.

+ +

 

+ +

Normally, JET starts playback of the next +segment (or repeats the current segment) when the MIDI +end-of-track meta-event is encountered. Some MIDI +authoring tools make it difficult to place the end-of-track marker accurately, +resulting in synchronization problems when segments are joined together.

+ +

 

+ +

To avoid this problem, the author can place +a JET end-of-segment marker (controller=102, value=0) at the point where the +segment is to be looped. When the end-of-segment marker is encountered, the +next segment will be triggered, or if the current segment is looped, playback +will resume at the start of the segment.

+ +

 

+ +

The end-of-segment marker can also be used +to allow for completion of a musical figure beyond the end of measure that +marks the start of the next segment. For example, the content author might +create a 4-bar segment with a drum fill that ends on beat 1 of the 5th +bar – a bar beyond the natural end of the segment. By placing an end-of-segment +marker at the end of the 4th bar, the next segment will be +triggered, but the drum fill will continue in parallel with the next segment +providing musical continuity.

+ +

 

+ +

+ +

Figure 6: End-of-segment Marker

+ +

6.3        +Application Controllers +(CC80-83)

+ +

The application may use controllers in this +range for its own purposes. When a controller in this range is encountered, the +event is entered into an event queue that can be queried by the application. +Some possible uses include synchronizing video events with audio and marking a +point in a MIDI segment to queue up the next +segment. The range of controllers monitored by the application can be modified +by the application during initialization.

+ +

 

+ +
+ + + + diff --git a/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/header.htm b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/header.htm new file mode 100755 index 0000000..e7a72f2 --- /dev/null +++ b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/header.htm @@ -0,0 +1,220 @@ + + + + + + + + + + + + + + +
+ +

+ +


+ +

+ +

 

+ +

 

+ +

 

+ +

 

+ +

 

+ +
+ +
+ +

+ +


+ +

+ +

 

+ +

 

+ +

 

+ +

 

+ +

 

+ +
+ +
+ +

+ +


+ +

+ +

 

+ +

 

+ +

 

+ +

 

+ +

 

+ +
+ +
+ +

+ +


+ +

+ +

 

+ +

 

+ +

 

+ +

 

+ +

 

+ +
+ +
+ +

 

+ +

 

+ +

 

+ +

 

+ +

 

+ +

 

+ +

 

+ +

 

+ +

 

+ +

 

+ +

 

+ +

 

+ +

 

+ +

 

+ +
+ +
+ +

+ +

 

+ +

 

+ +

 

+ +

 

+ +

 

+ +
+ +
+ +

 

+ +

 

+ +

 

+ +
+ +
+ +

 

+ +

 

+ +

 

+ +

 

+ +

 

+ +
+ +
+ +

SONiVOX JET Creator User Documentation    +Vrs.3   Page 1/20

+ +

 

+ +
+ + + + diff --git a/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image001.emz b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image001.emz new file mode 100755 index 0000000..f152c11 Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image001.emz differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image002.gif b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image002.gif new file mode 100755 index 0000000..eb1aa37 Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image002.gif differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image003.emz b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image003.emz new file mode 100755 index 0000000..010c4bd Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image003.emz differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image004.gif b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image004.gif new file mode 100755 index 0000000..4e99824 Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image004.gif differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image005.emz b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image005.emz new file mode 100755 index 0000000..a29ebfd Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image005.emz differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image006.gif b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image006.gif new file mode 100755 index 0000000..17919fd Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image006.gif differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image007.emz b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image007.emz new file mode 100755 index 0000000..31cba25 Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image007.emz differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image008.gif b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image008.gif new file mode 100755 index 0000000..54111a0 Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image008.gif differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image009.png b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image009.png new file mode 100755 index 0000000..0d5a14d Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image009.png differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image010.jpg b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image010.jpg new file mode 100755 index 0000000..d0dbb1d Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image010.jpg differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image011.png b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image011.png new file mode 100755 index 0000000..29c47ec Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image011.png differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image012.jpg b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image012.jpg new file mode 100755 index 0000000..ac54829 Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image012.jpg differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image013.png b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image013.png new file mode 100755 index 0000000..b0434d7 Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image013.png differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image014.jpg b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image014.jpg new file mode 100755 index 0000000..18212b3 Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image014.jpg differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image015.png b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image015.png new file mode 100755 index 0000000..807797e Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image015.png differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image016.jpg b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image016.jpg new file mode 100755 index 0000000..fa7931d Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image016.jpg differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image017.png b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image017.png new file mode 100755 index 0000000..ca200d1 Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image017.png differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image018.jpg b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image018.jpg new file mode 100755 index 0000000..64bb5c3 Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image018.jpg differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image019.png b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image019.png new file mode 100755 index 0000000..7867902 Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image019.png differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image020.jpg b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image020.jpg new file mode 100755 index 0000000..9943ae2 Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image020.jpg differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image021.png b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image021.png new file mode 100755 index 0000000..690dcad Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image021.png differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image022.jpg b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image022.jpg new file mode 100755 index 0000000..7b517fa Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image022.jpg differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image023.png b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image023.png new file mode 100755 index 0000000..43f0fb1 Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image023.png differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image024.jpg b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image024.jpg new file mode 100755 index 0000000..cea31c8 Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image024.jpg differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image025.emz b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image025.emz new file mode 100755 index 0000000..1668a8e Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image025.emz differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image026.gif b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image026.gif new file mode 100755 index 0000000..f9a4a89 Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image026.gif differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image027.emz b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image027.emz new file mode 100755 index 0000000..2b06699 Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image027.emz differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image028.gif b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image028.gif new file mode 100755 index 0000000..1d18152 Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image028.gif differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image029.jpg b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image029.jpg new file mode 100755 index 0000000..d244843 Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image029.jpg differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image030.emz b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image030.emz new file mode 100755 index 0000000..f152c11 Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image030.emz differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image031.emz b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image031.emz new file mode 100755 index 0000000..010c4bd Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image031.emz differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image032.emz b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image032.emz new file mode 100755 index 0000000..a29ebfd Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image032.emz differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image033.emz b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image033.emz new file mode 100755 index 0000000..31cba25 Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image033.emz differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image034.emz b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image034.emz new file mode 100755 index 0000000..1668a8e Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image034.emz differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image035.emz b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image035.emz new file mode 100755 index 0000000..2b06699 Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Creator_User_Manual_files/image035.emz differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Programming_Manual.html b/common/embeddedaudiosynthesis/docs/JET_Programming_Manual.html new file mode 100755 index 0000000..198a9e6 --- /dev/null +++ b/common/embeddedaudiosynthesis/docs/JET_Programming_Manual.html @@ -0,0 +1,1333 @@ + + + + + + + + + + + +JET PROGRAMMING MANUAL + + + + + + + + +
+   Copyright (C) 2009 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ +
+ +

JET™ Programming Manual

+ +

JET +Interactive Music Engine

+ +

Vrs 2.0

+ +

Authored by SONiVOX

+ +

www.sonivoxrocks.com

+ +

Copyright 2009 Sonic Network, Inc.

+ + + +

 

+ +

 

+ +

 

+ +

Introduction

+ +

This document contains programmer guidelines for the SONiVOX +JET Interactive Music System. JET is an interactive music player for small +embedded devices, including the Google Android platform. It allows applications +to include interactive music soundtracks, in MIDI +format, that respond in real-time to game play events and user interaction.

+ +

 

+ +

JET works in conjunction with SONiVOX’s Embedded Audio +Synthesizer (EAS) which is the MIDI playback +device for Android.  Both the JET and EAS +engines are integrated into the Android embedded platform as well as inherent +in JET Creator, an application for +authoring JET content files. As such, the JET content author can be sure that +the playback will sound exactly the same in both JET Creator and the final Android application playing back on +Android mobile devices.

+ +

 

+ +

The programmer of a JET application will want to work +closely with the content author in designing how real-time application events +and music will interactively work together. Once decided, the content author +will create the content and ultimately save a .jet file for the programmer to +include in the application.

+ +

 

+ +

Please see “JET Creator User Documentation” for additional +information on authoring JET content.

+ +

 

+ +

Abbreviations and Common Terms

+ +

It is important to use a common set of terms to minimize confusion. +Since JET uses MIDI in a unique way, normal +industry terms may not always suffice. Here is the definition of terms as they +are used in this document and in the JET Creator application:

+ +

 

+ +

Channel: MIDI data +associated with a specific MIDI channel. +Standard MIDI allows for 16 channels of MIDI +data each of which are typically associated with a specific instrument.

+ +

 

+ +

Controller: A MIDI event consisting of a channel number, controller +number, and a controller value. The MIDI spec +associates many controller numbers with specific functions, such as volume, +expression, sustain pedal, etc. JET also uses controller events as a means of +embedding special control information in a MIDI +sequence to provide for audio synchronization.

+ +

 

+ +

DAW: Digital Audio +Workstation. A common term for MIDI and audio +sequencing applications such as Logic, SONAR, Cubase and others.

+ +

 

+ +

EAS: Embedded MIDI Synthesizer. The name of the SONiVOX MIDI +synthesizer engine.

+ +

 

+ +

JET: Jet +Interactive Engine. The name of the SONiVOX JET interactive music engine.

+ +

 

+ +

Segment: A musical +section such as a chorus or verse that is a component of the overall +composition. In JET, a segment can be an entire MIDI file or a derived from a +portion of a MIDI file.

+ +

 

+ +

SMF-0: Standard +MIDI File Type 0, a MIDI file that contains a single track, but may be made up +of multiple channels of MIDI data.

+ +

 

+ +

SMF-1: Standard +MIDI File Type 1, a MIDI file that contains a one more tracks, and each track +may in turn be made up of one or more channels of MIDI +data. By convention, each channel is stored on a separate track in an SMF-1 +file. However, it is possible to have multiple MIDI channels on a single track, +or multiple tracks that contain data for the same MIDI +channel.

+ +

 

+ +

Track: A single +track in a DAW containing a timed sequence of MIDI +events. Be careful not to confuse Tracks with Channels. A MIDI file may contain +many tracks with several tracks utilizing the same MIDI +channel.

+ +

 

+ +

 

+ +

The JET +Interactive Music Concept

+ +

Interactive music can be defined as music that changes in +real-time according to non-predictable events such as user interaction or game +play events. In this way, interactive music is much more engaging as it has the +ability to match the energy and mood of a game much closer than a pre-composed +composition that never changes. In some applications and games, interactive +music is central to the game play. Guitar Hero is one such popular game. When +the end user successfully ‘captures’ the musical notes coming down the fret +board, the music adapts itself and simultaneously keeps score of successes and +failures. JET allows for these types of music driven games as well.

+ +

 

+ +

There are several methods for making and controlling +interactive music and JET is one such method. This section describes the +features of JET and how they might be used in a game or software application. +It also describes how JET can be used to save memory in small footprint devices +such as Android enabled mobile handsets.

+ +

 

+ +

JET Operation

+ +

JET supports a flexible music format that can be used to +create extended musical sequences with a minimal amount of data. A musical +composition is broken up into segments that can be sequenced to create a longer +piece. The sequencing can be fixed at the time the music file is authored, or +it can be created dynamically under program control.

+ +

Linear Music +Example

+ +

+ +

Figure 1: Linear Music Piece

+ +

 

+ +

This diagram shows how musical segments are stored. Each +segment is authored as a separate MIDI file. A +post-processing tool combines the files into a single container file. Each +segment can contain alternate music tracks that can be muted or un-muted to +create additional interest. An example might be a brass accent in the chorus +that is played only the last time through. Also, segments can be transposed up +or down.

+ +

 

+ +

The bottom part of the diagram shows how the musical +segments can be recombined to create a linear music piece. In this example, the +bridge might end with a half-step key modulation and the remaining segments +could be transposed up a half-step to match.

+ +

Non-linear Music Example

+ +

+ +

Figure 2: Non-linear music piece

+ +

 

+ +

In this diagram, we see a non-linear music piece. The +scenario is a first-person-shooter (FPS) and JET is providing the background +music. The intro plays as the level is loading and then transitions under +program control to the Searching segment. This segment is repeated +indefinitely, perhaps with small variations (using the mute/un-mute feature) +until activity in the game dictates a change.

+ +

 

+ +

As the player nears a monster lair, the program starts a +synchronized transition to the Danger segment, increasing the tension level in +the audio. As the player draws closer to the lair, additional tracks are +un-muted to increase the tension.

+ +

 

+ +

As the player enters into combat with the monster, the +program starts a synchronized transition to the Combat segment. The segment +repeats indefinitely as the combat continues. A Bonus Hit temporarily un-mutes +a decorative track that notifies the player of a successful attack, and +similarly, another track is temporarily un-muted to signify when the player +receives Special Damage.

+ +

 

+ +

At the end of combat, the music transitions to a victory or +defeat segment based on the outcome of battle.

+ +

Mute/Un-mute Synchronization

+ +

JET can also synchronize the muting and un-muting of tracks +to events in the music. For example, in the FPS game, it would probably be +desirable to place the musical events relating to bonuses and damage as close +to the actual game event as possible. However, simply un-muting a track at the +moment the game event occurs might result in a music clip starting in the +middle. Alternatively, a clip could be started from the beginning, but then it +wouldn’t be synchronized with the other music tracks.

+ +

 

+ +

However, with the JET sync engine, a clip can be started at +the next opportune moment and maintain synchronization. This can be +accomplished by placing a number of short music clips on a decorative track. A MIDI event in the stream signifies the start of a clip +and a second event signifies the end of a clip. When the application calls the +JET clip function, the next clip in the track is allowed to play fully +synchronized to the music. Optionally, the track can be automatically muted by +a second MIDI event.

+ +

 

+ +

+ +

Figure 3: Synchronized Mute/Unmute

+ +

Audio Synchronization

+ +

JET provides an audio synchronization API that allows game +play to be synchronized to events in the audio. The mechanism relies on data +embedded in the MIDI file at the time the +content is authored. When the JET engine senses an event during playback it +generates a callback into the application program. The timing of the callback +can be adjusted to compensate for any latency in the audio playback system so +that audio and video can be synchronized. The diagram below shows an example of +a simple music game that involves pressing the left and right arrows in time +with the music.

+ +

 

+ +

 

+ +

+ +

Figure 4: Music Game with +Synchronization

+ +

 

+ +

The arrows represent events in the music sequence where game +events need to be synchronized. In this case, the blue arrow represents a time +where the player is supposed to press the left button, and the red arrow is for +the right button. The yellow arrow tells the game engine that the sequence is +complete. The player is allowed a certain time window before and after the +event to press the appropriate key.

+ +

 

+ +

If an event is received and the player has not pressed a +button, a timer is set to half the length of the window. If the player presses +the button before the timer expires, the game registers a success, and if not, +the game registers a failure.

+ +

 

+ +

If the player presses the button before the event is +received, a timer is set to half the length of the window. If an event is +received before the timer expires, the game registers a success, and if not, +the game registers a failure. Game play might also include bonuses for getting +close to the timing of the actual event.

+ +

 

+ +

Operational Details

+ +

JET uses the standard EAS library calls to manage multiple MIDI streams that are synchronized to sound like a +seamless audio track. JET requires the use of the dynamic memory model, i.e. +support for malloc() and free() memory allocation functions or their +equivalent. JET also requires the DLS parser and synthesizer module to support +custom instruments in JET content files.

+ +

 

+ +

JET uses standard MIDI +events for audio synchronization. This simplifies the authoring process by +allowing content authors to use their favorite tools for developing content. +After the content has been developed, a simple post-processing tool pulls the +content together into a JET compatible content file.

+ +

Synchronization Events

+ +

JET uses MIDI controller +events to synchronize audio. The controllers used by JET are among those not +defined for specific use by the MIDI +specification. The specific controller definitions are as follows:

+ +

 

+ +

            Controllers +80-83                 Reserved for use by +application

+ +

            Controller 102                       JET event marker

+ +

            Controller +103                       JET clip marker

+ +

            Controllers +104-119             Reserved for future +use

+ +

 

+ +

Controllers 80-83 – Application Controllers

+ +

The application may use controllers in this range for its +own purposes. When a controller in this range is encountered, the event is +entered into an event queue that can be queried by the application. Some +possible uses include synchronizing video events with audio and marking a point +in a MIDI segment to queue up the next +segment. The range of controllers monitored by the application can be modified +by the application during initialization.

+ +

Controller 102 – JET Event Marker

+ +

Controller 102 is reserved for marking events in the MIDI streams that are specific to JET functionality. +Currently, the only defined value is 0, which marks the end of a segment for +timing purposes.

+ +

 

+ +

Normally, JET starts playback of the next segment (or +repeats the current segment) when the MIDI +end-of-track meta-event is encountered. Some MIDI +authoring tools make it difficult to place the end-of-track marker accurately, +resulting in synchronization problems when segments are joined together.

+ +

 

+ +

To avoid this problem, the author can place a JET +end-of-segment marker (controller=102, value=0) at the point where the segment is +to be looped. When the end-of-segment marker is encountered, the next segment +will be triggered, or if the current segment is looped, playback will resume at +the start of the segment.

+ +

 

+ +

The end-of-segment marker can also be used to allow for +completion of a musical figure beyond the end of measure that marks the start +of the next segment. For example, the content author might create a 4-bar +segment with a drum fill that ends on beat 1 of the 5th bar – a bar +beyond the natural end of the segment. By placing an end-of-segment marker at +the end of the 4th bar, the next segment will be triggered, but the +drum fill will continue in parallel with the next segment providing musical +continuity.

+ +

 

+ +

+ +

Figure 5: End-of-segment Marker

+ +

Controller 103 – JET Clip Marker

+ +

Controller 103 is reserved for marking clips in a MIDI track that can be triggered by the JET_TriggerClip +API call. The clip ID is encoded in the low 6 bits of the controller value. Bit +6 is set to one to indicate the start of a clip, and set to zero to indicate +the end of a clip.

+ +

 

+ +

For example, to identify a clip with a clip ID of 1, the +author inserts a MIDI controller event with +controller=103 and value=65 at the start of the clip and another event with controller=103 +and value=1 at the end of the clip. When the JET_TriggerClip() function is +called with a clip ID of 1, the track will be un-muted when the controller +value 65 is encountered and muted again when the controller value 1 is +encountered.

+ +

 

+ +

+ +

Figure 6: Synchronized Clip

+ +

 

+ +

In the figure above, if the JET_TriggerClip() function is +called prior to the first controller event, Track 3 will be un-muted when the +first controller event occurs, the first clip will play, and the track will be +muted when the second controller event occurs. If the JET_TriggerClip() +function is called after the first controller event has occurred, Track 3 will +be un-muted when the third controller event occurs, the second clip will play, +and the track will be muted again when the fourth controller event occurs.

+ +

 

+ +

Note: Normally, +the track containing the clip is muted by the application when the segment is +initially queued by the call to JET_QueueSegment(). If it is not muted, the clip +will always play until Jet_TriggerClip() has been called with the clip ID.

+ +

JET Programming

+ +

The JET library builds on functionality in the EAS library. +It is assumed that the reader is familiar with EAS and has implemented basic +EAS audio functionality in the application. Specifically, the application must +first initialize EAS by calling EAS_Init() and must call EAS_Render() at +appropriate times to render audio and stream it to the audio hardware. JET also +requires the use of the dynamic memory model which uses malloc() and free() or +functional equivalents.

+ +

 

+ +

Most JET function calls return an EAS_RESULT type which +should be checked against the EAS_SUCCESS return code. Most failures are not +fatal, i.e. they will not put the library in a state where it must be +re-initialized. However, some failures such as memory allocation or file +open/read errors will likely result in the specific open content failing to +render.

+ +

JET Application Initialization

+ +

The JET library is initialized by the JET_Init() function. +The application must first call EAS_Init() and then pass the EAS data handle +returned by EAS_Init() to the JET_Init() function. Currently, only a single JET +application can be active at a time.

+ +

 

+ +

The JET_Init function takes 3 arguments: The first is the +EAS data handle. The second is a pointer to a configuration structure +S_JET_CONFIG and the third is the size of the configuration structure. For most +applications, it is sufficient to pass a NULL pointer and size 0 for the +configuration data.

+ +

 

+ +

However, if desired, the configuration can be modified to +allow the application to monitor MIDI events +outside the normal range of controllers allocated for JET application events. +In this case, a configuration structure should be allocated and the data fields +initialized with the appropriate values with the low and high controller +numbers to be monitored. The size field should be the sizeof() of the data +structure. This is to allow for future enhancement of the configuration data +while maintaining compatibility.

+ +

JET Application Termination

+ +

When the JET application terminates, it should call +JET_Shutdown() to release the resources allocated by the JET engine.  If the application has no other use for the +EAS library, it should also call EAS_Shutdown().

+ +

JET Audio Processing

+ +

To start the JET engine, the content must first be opened +with the JET_OpenFile() function. Just as with EAS_OpenFile(), the file locator +is an opaque value that is passed to the EAS_HWOpenFile() function. It can +either be a pointer to a filename, or a pointer to an in-memory object, +depending on the user implementation of file I/O in the eas_host.c or +eas_hostmm.c module. Only a single JET content file can be opened at a time.

+ +

 

+ +

Once the JET file is opened, the application can begin +queuing up segments for playback by calling the JET_QueueSegment() function. +Generally, it is advisable to keep a minimum of two segments queued at all +times:  the currently playing segment +plus an additional segment that is ready to start playing when the current +segment finishes. However, with proper programming, it is possible to queue up +segments using a “just-in-time” technique. This technique typically involves +careful placement of application controller events near the end of a segment so +that the application is informed when a segment is about to end.

+ +

 

+ +

After the segment(s) are queued up, playback can begin. By +default, the segments are initialized in a paused state. To start playback, +call the JET_Play() function. Playback can be paused again by calling the JET_Pause() +function. Once initiated, playback will continue as long as the application +continues to queue up new segments before all the segments in the queue are +exhausted.

+ +

 

+ +

The JET_Status() function can be used to monitor progress. +It returns the number of segments queued, repeat count, current segment ID, and +play status. By monitor the number of segments queued, the application can +determine when it needs to queue another segment and when playback has +completed.

+ +

 

+ +

When playback has completed and the application is finished +with the contents of the currently open file, the application should call +JET_CloseFile() to close the file and release any resources associated with the +file.

+ +

JET_Init

+ +

EAS_PUBLIC EAS_RESULT JET_Init +(EAS_DATA_HANDLE easHandle, S_JET_CONFIG *pConfig, EAS_INT configSize)

+ +

 

+ +

Initializes JET library for use by application. Most +application should simply pass a NULL for pConfig and 0 for configSize, which +means that only controller events in the application range (80-83) will end up +in the application event queue. If desired, the application can instantiate an +S_JET_CONFIG data structure and set the controller range to a different range. +In this case, the configSize parameter should be set to sizeof(S_JET_CONFIG).

+ +

JET_Shutdown

+ +

EAS_PUBLIC EAS_RESULT JET_Shutdown +(EAS_DATA_HANDLE easHandle)

+ +

 

+ +

Releases resources used by the JET library. The application +should call this function when it is no longer using the JET library.

+ +

JET_ OpenFile

+ +

EAS_PUBLIC EAS_RESULT JET_OpenFile +(EAS_DATA_HANDLE easHandle, EAS_FILE_LOCATOR locator)

+ +

 

+ +

Opens a JET content file for playback. Content must be +formatted for use by the JET library, which is typically accomplished with the +jetfile.py script (see “Creating JET Content”). Only a single JET content file +can be opened at a time. However, since JET can contain many MIDI +files and DLS libraries, this limitation is normally not an issue.

+ +

JET_ CloseFile

+ +

EAS_PUBLIC EAS_RESULT JET_CloseFile +(EAS_DATA_HANDLE easHandle)

+ +

 

+ +

Closes a JET file and release the resources associated with it.

+ +

JET_ Status

+ +

EAS_PUBLIC EAS_RESULT JET_Status +(EAS_DATA_HANDLE easHandle, S_JET_STATUS *pStatus)

+ +

 

+ +

Returns the current JET status. The elements of the status +data structure are as follows:

+ +

 

+ +

typedef struct s_jet_status_tag

+ +

{

+ +

     EAS_INT   currentUserID;

+ +

     EAS_INT   segmentRepeatCount;

+ +

     EAS_INT   numQueuedSegments;

+ +

     EAS_BOOL paused;

+ +

} S_JET_STATUS;

+ +

 

+ +

currentUserID: An +8-bit value assigned by the application.

+ +

 

+ +

segmentRepeatCount: +Number of times left to repeat. Zero indicates no repeats, a negative number +indicates an infinite number of repeats. Any positive value indicates that the +segment will play n+1 times.

+ +

 

+ +

numQueuedSegments: +Number of segments currently queued to play including the currently playing +segment. A value of zero indicates that nothing is playing. Normally, the +application will queue a new segment each time the value is 1 so that playback +is uninterrupted.

+ +

JET_ QueueSegment

+ +

EAS_PUBLIC EAS_RESULT JET_QueueSegment +(EAS_DATA_HANDLE easHandle, EAS_INT segmentNum, EAS_INT libNum, EAS_INT +repeatCount, EAS_INT transpose, EAS_U32 muteFlags, EAS_U8 userID)

+ +

 

+ +

Queues up a JET MIDI segment for playback. The parameters +are as follows:

+ +

 

+ +

segmentNum: +Segment number as identified in the JET content configuration file.

+ +

 

+ +

libNum: The library +number as specified in the JET content configuration file. Use -1 to select the +standard General MIDI library.

+ +

 

+ +

repeatCount: The +number of times this segment should repeat. Zero indicates no repeat, i.e. play +only once. Any positive number indicates to play n+1 times. Set to -1 to repeat +indefinitely.

+ +

 

+ +

transpose: The +amount of pitch transposition. Set to 0 for normal playback. Range is -12 to ++12.

+ +

 

+ +

muteFlags: +Specific which MIDI tracks (not MIDI channels) +should be muted during playback. These flags can be changed dynamically using +the mute functions. Bit 0 = track 0, bit 1 = track 1, etc.

+ +

 

+ +

userID: 8-bit +value specified by the application that uniquely identifies the segment. This +value is returned in the JET_Status() function as well as by the application +event when an event is detected in a segment. Normally, the application keeps +an 8-bit value that is incremented each time a new segment is queued up. This +can be used to look up any special characteristics of that track including +trigger clips and mute flags.

+ +

JET_ Play

+ +

EAS_PUBLIC EAS_RESULT JET_Play +(EAS_DATA_HANDLE easHandle)

+ +

 

+ +

Starts playback of the current segment. This function must +be called once after the initial segments are queued up to start playback. It +is also called after JET_Pause() to resume playback.

+ +

JET_ Pause

+ +

EAS_PUBLIC EAS_RESULT JET_Pause +(EAS_DATA_HANDLE easHandle)

+ +

 

+ +

Pauses playback of the current segment. Call JET_Pause() to +resume playback.

+ +

JET_ SetMuteFlags

+ +

EAS_PUBLIC EAS_RESULT JET_SetMuteFlags +(EAS_DATA_HANDLE easHandle, EAS_U32 muteFlags, EAS_BOOL sync)

+ +

 

+ +

Modifies the mute flags during playback. If the sync parameter is false, the mute flags +are updated at the beginning of the next render. This means that any new notes +or controller events will be processed during the next audio frame. If the sync parameter is true, the mute flags +will be updated at the start of the next segment. If the segment is repeated, +the flags will take effect the next time segment is repeated.

+ +

JET_ SetMuteFlag

+ +

EAS_PUBLIC EAS_RESULT JET_SetMuteFlag +(EAS_DATA_HANDLE easHandle, EAS_INT trackNum, EAS_BOOL muteFlag, EAS_BOOL sync)

+ +

Modifies a mute flag for a single track during playback. If +the sync parameter is false, the mute +flag is updated at the beginning of the next render. This means that any new +notes or controller events will be processed during the next audio frame. If +the sync parameter is true, the mute +flag will be updated at the start of the next segment. If the segment is +repeated, the flag will take effect the next time segment is repeated.

+ +

JET_ TriggerClip

+ +

EAS_PUBLIC EAS_RESULT JET_TriggerClip +(EAS_DATA_HANDLE easHandle, EAS_INT clipID)

+ +

 

+ +

Automatically updates mute flags in sync with the JET Clip +Marker (controller 103). The parameter clipID +must be in the range of 0-63. After the call to JET_TriggerClip, when JET next +encounters a controller event 103 with bits 0-5 of the value equal to clipID and bit 6 set to 1, it will automatically un-mute the track containing +the controller event. When JET encounters the complementary controller event +103 with bits 0-5 of the value equal to clipID +and bit 6 set to 0, it will mute +the track again.

+ +

JET_ GetEvent

+ +

EAS_BOOL JET_GetEvent (EAS_DATA_HANDLE +easHandle, EAS_U32 *pEventRaw, S_JET_EVENT *pEvent)

+ +

 

+ +

Attempts to read an event from the application event queue, +return EAS_TRUE if an event is found and EAS_FALSE if not. If the application +passes a valid pointer for pEventRaw, +a 32-bit compressed event code is returned. If the application passes a valid +pointer for pEvent, the event is +parsed into the S_JET_EVENT fields. The application can pass NULL for either +parameter and that variable will be ignored. Normally, the application will +call JET_GetEvent() repeatedly to retrieve events until it returns EAS_FALSE.

+ +

JET_ ParseEvent

+ +

EAS_PUBLIC void JET_ParseEvent (EAS_U32 +event, S_JET_EVENT *pEvent)

+ +

Parses a 32-bit compressed event code into a data structure. +The application passes the event code received from JET_GetEvent(). The parsed +event data is returned in the memory pointed to by pEvent.

+ +

JET_GetAppData

+ +

EAS_RESULT JET_GetAppData +(EAS_DATA_HANDLE easHandle, EAS_I32 *pAppDataOffset, EAS_I32 *pAppDataSize)

+ +

Returns the offset and size of the JAPP chunk in the JET +file. The application can use the file I/O functions in the eas_host module to +retrieve application specific data from the file.

+ +

 

+ +

 

+ +

Creating JET Content

+ +

JET uses standard MIDI files and DLS files that can be +created with commercially available content tools such as Logic, Cubase, +Digital Performer, or SONAR for MIDI files and +Awave for DLS2 files. These source files are then bundled into a .jet package +file suitable for use in a JET application.

+ +

 

+ +

To create JET file use the “JET Creator” desktop +application. The JET Creator application is written in Python and includes a +full graphical interface. It is available for MAC and PC platforms. See “JET +Creator User Manual” for more information.

+ +
+ + + + diff --git a/common/embeddedaudiosynthesis/docs/JET_Programming_Manual.odt b/common/embeddedaudiosynthesis/docs/JET_Programming_Manual.odt new file mode 100755 index 0000000..943b818 Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Programming_Manual.odt differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Programming_Manual.pdf b/common/embeddedaudiosynthesis/docs/JET_Programming_Manual.pdf new file mode 100755 index 0000000..3e45005 Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Programming_Manual.pdf differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/header.htm b/common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/header.htm new file mode 100755 index 0000000..8cc7121 --- /dev/null +++ b/common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/header.htm @@ -0,0 +1,73 @@ + + + + + + + + + + + + + +
+ +

+ +


+ +

+ +
+ +
+ +

+ +


+ +

+ +
+ +
+ +

+ +


+ +

+ +
+ +
+ +

+ +


+ +

+ +
+ +
+ +

                                        JET +Programming Guide   vrs.2   Page 1/19

+ +
+ + + + diff --git a/common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/image002.png b/common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/image002.png new file mode 100755 index 0000000..931d4a4 Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/image002.png differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/image004.png b/common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/image004.png new file mode 100755 index 0000000..93086b5 Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/image004.png differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/image006.png b/common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/image006.png new file mode 100755 index 0000000..2916ddd Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/image006.png differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/image008.png b/common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/image008.png new file mode 100755 index 0000000..d80d93c Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/image008.png differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/image010.png b/common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/image010.png new file mode 100755 index 0000000..542a7f7 Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/image010.png differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/image012.png b/common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/image012.png new file mode 100755 index 0000000..547759c Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/image012.png differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/image013.emz b/common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/image013.emz new file mode 100755 index 0000000..f152c11 Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/image013.emz differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/image014.emz b/common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/image014.emz new file mode 100755 index 0000000..010c4bd Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/image014.emz differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/image015.emz b/common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/image015.emz new file mode 100755 index 0000000..a29ebfd Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/image015.emz differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/image016.emz b/common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/image016.emz new file mode 100755 index 0000000..31cba25 Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/image016.emz differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/image017.emz b/common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/image017.emz new file mode 100755 index 0000000..2b06699 Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/image017.emz differ diff --git a/common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/image018.emz b/common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/image018.emz new file mode 100755 index 0000000..1668a8e Binary files /dev/null and b/common/embeddedaudiosynthesis/docs/JET_Programming_Manual_files/image018.emz differ diff --git a/common/idmobilelib/ios/AnimatedImage.h b/common/idmobilelib/ios/AnimatedImage.h new file mode 100755 index 0000000..a8951ea --- /dev/null +++ b/common/idmobilelib/ios/AnimatedImage.h @@ -0,0 +1,31 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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. + + */ +#import + + +@interface idAnimatedImage : UIImageView { + +} + +- (void) SetupAnimation:( NSString * )animationBaseName + :( float )animationDuration + :( int )animationRepeat; + +@end diff --git a/common/idmobilelib/ios/AnimatedImage.mm b/common/idmobilelib/ios/AnimatedImage.mm new file mode 100755 index 0000000..ec7efe5 --- /dev/null +++ b/common/idmobilelib/ios/AnimatedImage.mm @@ -0,0 +1,67 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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. + + */ +#import +#import +#import "AnimatedImage.h" + + +@implementation idAnimatedImage + + +/* + ======================== + SetupAnimation + ======================== + */ +- (void) SetupAnimation:( NSString * )animationBaseName + :( float )animationDuration + :( int )animationRepeat { + + // Create an Array to store our images in. + const static int MAX_NUM_ANIMFRAMES = 20; + NSMutableArray * imageArray = [ [ NSMutableArray alloc ] initWithCapacity:MAX_NUM_ANIMFRAMES ]; + + for( int index = 1; index < MAX_NUM_ANIMFRAMES; index++ ) { + NSString * imageName = [ [ NSString alloc ] initWithFormat:@"%@_%d.png", animationBaseName, index ]; + + // Try and Load the Image. + UIImage * imageCheck = [UIImage imageNamed: imageName ]; + + // are we good? + if( imageCheck != nil ) { + + // add it to the array of Images. + [ imageArray addObject:imageCheck ]; + + } else { + break; + } + } + // Set the Animation Data. + [ self setAnimationImages: imageArray ]; + [ self setAnimationDuration: animationDuration]; + [ self setAnimationRepeatCount: animationRepeat ]; +} + + + + + +@end diff --git a/common/idmobilelib/ios/Carousel.h b/common/idmobilelib/ios/Carousel.h new file mode 100755 index 0000000..a851c0a --- /dev/null +++ b/common/idmobilelib/ios/Carousel.h @@ -0,0 +1,91 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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. + + */ + + +/* +============================================================================== + Carousel - + + This UI Object must be setup by Interface builder. + + items must be added by code. + +============================================================================== +*/ + +#import +#import +#import "Label.h" + +@interface idCarouselItem : NSObject +{ +@public + + UIImage * image; // Image Of the Item. + NSString * title; // Title of the Item. + int hash; // Optional Item Hash Value. +} + +@property (nonatomic, retain) NSString *title; +@property (nonatomic, retain) UIImage *image; +@property (nonatomic, assign) int hash; + +@end + + +@interface idCarousel : UIControl { +@public + + NSInteger currentItem; // The Current Carousel Item. + NSInteger prevItem; // The Prev Carousel Item. + NSInteger nextItem; // The Next Carousel Item. + +@private + IBOutlet UIImageView * mainSelection; // Renderable Main Selection + IBOutlet UIImageView * prevSelection; // Renderable Prev Selection + IBOutlet UIImageView * nextSelection; // Renderable Next Selection + IBOutlet idLabel * selectionLabel; // Title Label. + + CGRect mainRect; // Main Selection Layout Rect. + CGRect prevRect; // Prev Selection Layout Rect. + CGRect nextRect; // Next Selection Layout Rect. + + NSMutableArray * carouselItems; // All the Available Items to choose from. + + int hasDragged; // if the User has Dragged for a revolution. + CGPoint startDragPoint; // the starting point where the user has touched. +} + +- (void) Init; +- (void) AddCarouselItem:( NSString* )Image + :( NSString* )Title + :( int )ItemHash; + +- (NSInteger) GetSelectedItem_Index; +- (int) GetSelectedItem_Hash; + +- (IBAction) MoveForward; +- (IBAction) MoveBackward; + +- (void) RotateToOrigin; +- (void) RotateForward; +- (void) RotateBackward; + +@end diff --git a/common/idmobilelib/ios/Carousel.mm b/common/idmobilelib/ios/Carousel.mm new file mode 100755 index 0000000..6632be8 --- /dev/null +++ b/common/idmobilelib/ios/Carousel.mm @@ -0,0 +1,512 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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. + + */ +#import +#import +#import "Carousel.h" +#include +@implementation idCarouselItem + +@synthesize image; +@synthesize title; +@synthesize hash; + +@end + +@implementation idCarousel + +// Move full turn at this percentage +const static float CAROUSEL_CHANGE_DRAG = 0.2f; +const static float CAROUSEL_BACKITEMS_ALPHA = 0.5f; +const static float CAROUSEL_FRONTITEM_ALPHA = 1.0f; + +enum idCarouselDrag_t { + CAROUSEL_DRAG_MOVE_NONE = 0, + CAROUSEL_DRAG_MOVE_FORWARD, + CAROUSEL_DRAG_MOVE_BACKWARD +}; + +/* + ======================== + Lerp + ======================== + */ +static CGFloat Lerp(CGFloat from, CGFloat to, CGFloat f ) +{ + return from + ( ( to - from ) * f ); +} + +/* + ======================== + LerpPoint + ======================== + */ +static CGPoint LerpPoint(CGPoint a, CGPoint b, CGFloat t) +{ + CGPoint p; + p.x = Lerp(a.x, b.x, t); + p.y = Lerp(a.y, b.y, t); + return p; +} + +/* + ======================== + LerpSize + ======================== + */ +static CGSize LerpSize(CGSize a, CGSize b, CGFloat t) +{ + CGSize s; + s.width = Lerp(a.width, b.width, t); + s.height = Lerp(a.height, b.height, t); + return s; +} + +/* + ======================== + LerpRect + ======================== + */ +static CGRect LerpRect( CGRect a, CGRect b, CGFloat t ) { + + CGRect r; + r.origin = LerpPoint( a.origin, b.origin, t ); + r.size = LerpSize( a.size, b.size, t ); + return r; + +} + +/* + ======================== + awakeFromNib + ======================== + */ +- (void) awakeFromNib { + + mainRect = mainSelection.frame; + prevRect = prevSelection.frame; + nextRect = nextSelection.frame; + + // Allocate our Items Array + carouselItems = [[ NSMutableArray alloc ] init ]; +} + +/* + ======================== + touchesBegan + ======================== + */ +- (void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event { + (void)(event); + hasDragged = 0; + startDragPoint = [[touches anyObject] locationInView:self]; +} + +/* + ======================== + touchesMoved + ======================== + */ +- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { + (void)(event); + if( prevSelection == nil || nextSelection == nil ) { + // Nothing to transition to... dont swip transition + return; + } + + CGPoint movedPoint = [[touches anyObject] locationInView:self]; + CGFloat offsetX = movedPoint.x - startDragPoint.x; + + // Find out where im at relative to the side of the screen + CGFloat percentage = offsetX / self.frame.size.width; + percentage = (float)fmin( percentage, 1.0f ); + percentage = (float)fmax( percentage, -1.0f ); + + if( percentage > CAROUSEL_CHANGE_DRAG ) { + hasDragged = CAROUSEL_DRAG_MOVE_FORWARD; + } else if( percentage < -CAROUSEL_CHANGE_DRAG ) { + hasDragged = CAROUSEL_DRAG_MOVE_BACKWARD; + } + + if( percentage > 0 ) { // Going to the right of the screen.. + + CGRect newMainRect = LerpRect( mainRect, nextRect , percentage ); + CGRect newNextRect = LerpRect( nextRect, prevRect , percentage ); + CGRect newPrevRect = LerpRect( prevRect, mainRect , percentage ); + + mainSelection.frame = newMainRect; + prevSelection.frame = newPrevRect; + nextSelection.frame = newNextRect; + + mainSelection.alpha = Lerp( CAROUSEL_FRONTITEM_ALPHA, CAROUSEL_BACKITEMS_ALPHA, percentage ); + prevSelection.alpha = Lerp( CAROUSEL_BACKITEMS_ALPHA, CAROUSEL_FRONTITEM_ALPHA, percentage ); + + } else { // Going the left. + + percentage = fabsf( percentage ); + + CGRect newMainRect = LerpRect( mainRect, prevRect , percentage ); + CGRect newNextRect = LerpRect( nextRect, mainRect , percentage ); + CGRect newPrevRect = LerpRect( prevRect, nextRect , percentage ); + + mainSelection.frame = newMainRect; + prevSelection.frame = newPrevRect; + nextSelection.frame = newNextRect; + + mainSelection.alpha = Lerp( CAROUSEL_FRONTITEM_ALPHA, CAROUSEL_BACKITEMS_ALPHA, percentage ); + nextSelection.alpha = Lerp( CAROUSEL_BACKITEMS_ALPHA, CAROUSEL_FRONTITEM_ALPHA, percentage ); + } +} + +/* + ======================== + touchesEnded + ======================== + */ +- (void) touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event { + (void)(event); + (void)(touches); + + if( hasDragged == CAROUSEL_DRAG_MOVE_FORWARD ) { + [ self RotateForward ]; + } else if( hasDragged == CAROUSEL_DRAG_MOVE_BACKWARD ) { + [ self RotateBackward ]; + } else { + [ self RotateToOrigin ]; + } +} + +/* + ======================== + Init + ======================== + */ +- (void) Init { + + // Get the items At the new layout. + idCarouselItem * cItem = [ carouselItems objectAtIndex: (NSUInteger)currentItem ]; + idCarouselItem * nItem = [ carouselItems objectAtIndex: (NSUInteger)nextItem ]; + idCarouselItem * pItem = [ carouselItems objectAtIndex: (NSUInteger)prevItem ]; + + // Set the Main Selection Text. + [ selectionLabel setText: cItem.title ]; + + // Set the prev selection UIImage + mainSelection.image = cItem.image; + prevSelection.image = nItem.image; + nextSelection.image = pItem.image; +} + +/* + ======================== + AddCarouselItem + ======================== + */ +- (void) AddCarouselItem:( NSString* )Image + :( NSString* )Title + :( int ) ItemHash { + + idCarouselItem * Item = [ idCarouselItem alloc ]; + + // Initialize the Item with the data passed in. + Item.image = [UIImage imageNamed: Image ]; + Item.title = Title; + Item.hash = ItemHash; + + // Add the Item to our object array. + [ carouselItems addObject: Item ]; + + // Set the Cur Item as the one just added. + currentItem = 0; + nextItem = 1; + prevItem = (NSInteger)[ carouselItems count ] - 1; + +} + +/* + ======================== + GetSelectedItem_Index + ======================== + */ +- (NSInteger) GetSelectedItem_Index { + return currentItem; +} + +/* + ======================== + GetSelectedItem_Hash + ======================== + */ +- (int) GetSelectedItem_Hash { + idCarouselItem * item = [ carouselItems objectAtIndex: (NSUInteger)currentItem ]; + + return item.hash; +} + +/* + ======================== + MoveForward + +Interface Builder Direct Access to moving the Carousel + ======================== + */ +- (IBAction) MoveForward { + [ self RotateForward ]; +} + +/* + ======================== + MoveBackward - + + Interface Builder Direct Access to moving the Carousel + ======================== + */ +- (IBAction) MoveBackward { + [ self RotateBackward ]; +} + +/* + ======================== + RotateToOrigin + ======================== + */ +- (void) RotateToOrigin { + + // Animate back to the correct position. + // Move the Current Selection to Next Selection + [UIView beginAnimations:nil context:nil]; + [UIView setAnimationCurve:UIViewAnimationCurveEaseOut]; + [UIView setAnimationBeginsFromCurrentState:YES]; + + // Move them into Place. + mainSelection.frame = mainRect; + prevSelection.frame = prevRect; + nextSelection.frame = nextRect; + + mainSelection.alpha = 1.0f; + nextSelection.alpha = CAROUSEL_BACKITEMS_ALPHA; + prevSelection.alpha = CAROUSEL_BACKITEMS_ALPHA; + + [UIView commitAnimations]; +} + +/* + ======================== + RotateForward + ======================== + */ +- (void) RotateForward { + + if( prevSelection == nil || nextSelection == nil ) { + + // Flip book to the next selection. + // increment the item indicies. + currentItem++; + nextItem++; + prevItem++; + + // Check the Extents. + if( currentItem >= (NSInteger)[ carouselItems count ] ) { + currentItem = 0; + } + if( nextItem >= (NSInteger)[ carouselItems count ] ) { + nextItem = 0; + } + if( prevItem >= (NSInteger)[ carouselItems count ] ) { + prevItem = 0; + } + + idCarouselItem * cItem = [ carouselItems objectAtIndex: (NSUInteger)currentItem ]; + + // Set the Main Selection Text. + [ selectionLabel setText: cItem.title ]; + + // Set the prev selection UIImage + mainSelection.image = cItem.image; + + [self sendActionsForControlEvents:UIControlEventValueChanged]; + + return; + } + + + UIImageView * tempMain = mainSelection; + UIImageView * tempPrev = prevSelection; + UIImageView * tempNext = nextSelection; + + // Move the Current Selection to Next Selection + [UIView beginAnimations:nil context:nil]; + [UIView setAnimationCurve:UIViewAnimationCurveEaseOut]; + [UIView setAnimationBeginsFromCurrentState:YES]; + + // Move them into Place. + mainSelection.frame = nextRect; + prevSelection.frame = mainRect; + nextSelection.frame = prevRect; + + // Darken the prev/next + mainSelection.alpha = CAROUSEL_BACKITEMS_ALPHA; + prevSelection.alpha = CAROUSEL_FRONTITEM_ALPHA; + nextSelection.alpha = CAROUSEL_BACKITEMS_ALPHA; + + [UIView commitAnimations]; + + + // Swap out the ImageViews so that they are in the correct order. + nextSelection = tempMain; + mainSelection = tempPrev; + prevSelection = tempNext; + + // Make sure they are in back of the main selection. + [ self sendSubviewToBack: nextSelection ]; + [ self sendSubviewToBack: prevSelection ]; + + // increment the item indicies. + currentItem++; + nextItem++; + prevItem++; + + // Check the Extents. + if( currentItem >= (NSInteger)[ carouselItems count ] ) { + currentItem = 0; + } + if( nextItem >= (NSInteger)[ carouselItems count ] ) { + nextItem = 0; + } + if( prevItem >= (NSInteger)[ carouselItems count ] ) { + prevItem = 0; + } + + // Get the items At the new layout. + idCarouselItem * cItem = [ carouselItems objectAtIndex: (NSUInteger)currentItem ]; + idCarouselItem * nItem = [ carouselItems objectAtIndex: (NSUInteger)nextItem ]; + idCarouselItem * pItem = [ carouselItems objectAtIndex: (NSUInteger)prevItem ]; + + // Set the Main Selection Text. + [ selectionLabel setText: cItem.title ]; + + // Set the prev selection UIImage + mainSelection.image = cItem.image; + prevSelection.image = nItem.image; + nextSelection.image = pItem.image; + + [self sendActionsForControlEvents:UIControlEventValueChanged]; +} + +/* + ======================== + RotateBackward + ======================== + */ +- (void) RotateBackward { + + if( nextSelection == nil || prevSelection == nil ) { + + // increment the item indicies. + currentItem--; + nextItem--; + prevItem--; + + // Check the Extents. + if( currentItem < 0 ) { + currentItem = (NSInteger)[ carouselItems count ] - 1; + } + if( nextItem < 0 ) { + nextItem = (NSInteger)[ carouselItems count ] - 1;; + } + if( prevItem < 0 ) { + prevItem = (NSInteger)[ carouselItems count ] - 1;; + } + + idCarouselItem * cItem = [ carouselItems objectAtIndex: (NSUInteger)currentItem ]; + + // Set the Main Selection Text. + [ selectionLabel setText: cItem.title ]; + + // Set the prev selection UIImage + mainSelection.image = cItem.image; + + [self sendActionsForControlEvents:UIControlEventValueChanged]; + + return; + } + + UIImageView * tempMain = mainSelection; + UIImageView * tempPrev = prevSelection; + UIImageView * tempNext = nextSelection; + + // Move the Current Selection to Next Selection + [UIView beginAnimations:nil context:nil]; + [UIView setAnimationCurve:UIViewAnimationCurveEaseOut]; + [UIView setAnimationBeginsFromCurrentState:YES]; + + // Move them into Place. + mainSelection.frame = prevRect; + prevSelection.frame = nextRect; + nextSelection.frame = mainRect; + + // Darken the prev/next + mainSelection.alpha = CAROUSEL_BACKITEMS_ALPHA; + prevSelection.alpha = CAROUSEL_BACKITEMS_ALPHA; + nextSelection.alpha = CAROUSEL_FRONTITEM_ALPHA; + + [UIView commitAnimations]; + + // Swap out the ImageViews so that they are in the correct order. + nextSelection = tempPrev; + mainSelection = tempNext; + prevSelection = tempMain; + + // Make sure they are in back of the main selection. + [ self sendSubviewToBack: nextSelection ]; + [ self sendSubviewToBack: prevSelection ]; + + // increment the item indicies. + currentItem--; + nextItem--; + prevItem--; + + // Check the Extents. + if( currentItem < 0 ) { + currentItem = (NSInteger)[ carouselItems count ] - 1; + } + if( nextItem < 0 ) { + nextItem = (NSInteger)[ carouselItems count ] - 1;; + } + if( prevItem < 0 ) { + prevItem = (NSInteger)[ carouselItems count ] - 1;; + } + + // Get the items At the new layout. + idCarouselItem * cItem = [ carouselItems objectAtIndex: (NSUInteger) currentItem ]; + idCarouselItem * nItem = [ carouselItems objectAtIndex: (NSUInteger)nextItem ]; + idCarouselItem * pItem = [ carouselItems objectAtIndex: (NSUInteger)prevItem ]; + + // Set the Main Selection Text. + [ selectionLabel setText: cItem.title ]; + + // Set the prev selection UIImage + mainSelection.image = cItem.image; + prevSelection.image = nItem.image; + nextSelection.image = pItem.image; + + [self sendActionsForControlEvents:UIControlEventValueChanged]; +} + +@end diff --git a/common/idmobilelib/ios/GameCenter.h b/common/idmobilelib/ios/GameCenter.h new file mode 100755 index 0000000..efd2f2b --- /dev/null +++ b/common/idmobilelib/ios/GameCenter.h @@ -0,0 +1,134 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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. + + */ + + +/* +================================================================================================ + +A game-generic C++ wrapper around the iOS Game Center functionality. + + +The class checks for Game Center availability in the constructor, and if Game Center is found +to be unsupported, a flag is set that causes all other function calls to early-exit and +do nothing. This way, the game code doesn't have to worry about whether Game Center is supported +for every call it makes, but can still check for support in order to, say, adjust the UI +if necessary. + +This class is not meant to be subclassed. + +This class uses the pimpl idiom (see http://herbsutter.com/gotw/_100/) to hide many of the +implementation details. I've found this to be a decent way to hide all the Objective-C code +from user code, so that C++-only portions of code can still access iOS functionality. + +================================================================================================ +*/ + +#ifndef IDMOBILELIB_GAMECENTER_H +#define IDMOBILELIB_GAMECENTER_H + +#include + +#include +#include +#include + +#include "../sys/sys_defines.h" + + +/* +================================================ +Contains function definitions to be overridden by specific games. +================================================ +*/ +class idGameCenterMatchHandler +{ +public: + + virtual ~idGameCenterMatchHandler() {} + + void createdMatch() { createdMatchImpl(); } + void allPlayersConnected( std::vector connectedPlayerIDs ) { + allPlayersConnectedImpl( connectedPlayerIDs ); + } + + void playerConnected( std::string playerIdentifier ) { + playerConnectedImpl( playerIdentifier ); + } + + void playerDisconnected( std::string playerIdentifer ) { + playerDisconnectedImpl( playerIdentifer ); + } + + void receivedData( std::string fromPlayerID, const void * data, int numBytes ) { + receivedDataImpl( fromPlayerID, data, numBytes ); + } + +private: + virtual void createdMatchImpl() = 0; + virtual void allPlayersConnectedImpl( std::vector connectedPlayerIDs ) = 0; + virtual void playerConnectedImpl( std::string playerIdentifer ) = 0; + virtual void playerDisconnectedImpl( std::string playerIdentifer ) = 0; + + virtual void receivedDataImpl( std::string fromPlayerID, const void * data, int numBytes ) = 0; +}; + + +namespace idGameCenter { + + static const int MAX_PACKET_SIZE_IN_BYTES = 1500; + + struct matchParms_t { + unsigned int minimumPlayers; + unsigned int maximumPlayers; + std::tr1::uint32_t automatchGroup; + }; + + void Initialize(); + void Shutdown(); + + void AuthenticateLocalPlayer( id currentViewController, idGameCenterMatchHandler * handler ); + + bool IsAvailable(); + bool IsLocalPlayerAuthenticated(); + + void HandleMoveToBackground(); + + void PresentMatchmaker( id currentViewController, matchParms_t parms, idGameCenterMatchHandler * handler ); + + void PushMatchmakerToNavigationController( id navigationController, + matchParms_t parms, + idGameCenterMatchHandler * handler ); + + bool IsInMatch(); + + void SendPacketToPlayerUnreliable( std::string destinationPlayer, + void * packet, + std::size_t packetSize ); + + void SendPacketToPlayerReliable( std::string destinationPlayer, + void * packet, + std::size_t packetSize ); + + void BroadcastPacketReliable( void * packet, int numBytes ); + + void DisconnectFromMatch(); +} + +#endif diff --git a/common/idmobilelib/ios/GameCenter.mm b/common/idmobilelib/ios/GameCenter.mm new file mode 100755 index 0000000..e38b2dd --- /dev/null +++ b/common/idmobilelib/ios/GameCenter.mm @@ -0,0 +1,712 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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 "GameCenter.h" +#include "objectivec_utilities.h" +#include "LocalizationObjectiveC.h" +#include "ios_interface.h" + +#include + +#import +#import +#import +#import + +namespace { + enum matchmakerViewMode_t { + MATCH_VIEW_MODAL, + MATCH_VIEW_PUSH_TO_NAVIGATION_CONTROLLER + }; +} + +/* +================================================ +The Objective-C delegate required for implementing Game Kit matches. +================================================ +*/ +@interface MatchDelegate : NSObject< GKMatchmakerViewControllerDelegate, GKMatchDelegate > + +@property(nonatomic, assign) UIViewController * gameViewController; +@property(nonatomic, assign) idGameCenterMatchHandler * matchHandler; +@property(nonatomic, retain) GKMatch * currentMatch; +@property(nonatomic, assign) BOOL matchHasStarted; +@property(nonatomic, assign) matchmakerViewMode_t matchmakerMode; + ++ (MatchDelegate*)sharedMatchDelegate; + +@end + + +static MatchDelegate * sharedMatchDelegateInstance = nil; + + + +// Unnamed-namespace for internal-linkage definitions. +namespace { + /* + ======================== + Game Center is only supported on iOS 4.1 and later. If we are running on a device + that doesn't support Game Center, we must disable its functionality. + The implementation of the check was taken straight form the Apple documentation. + ======================== + */ + bool HasGameCenterSupport() { + BOOL localPlayerClassAvailable = (NSClassFromString(@"GKLocalPlayer")) != nil; + + // The device must be running iOS 4.1 or later. + NSString *reqSysVer = @"4.1"; + NSString *currSysVer = [[UIDevice currentDevice] systemVersion]; + BOOL osVersionSupported = ([currSysVer compare:reqSysVer options:NSNumericSearch] != NSOrderedAscending); + + return (localPlayerClassAvailable && osVersionSupported); + } +} + + +@implementation MatchDelegate + +@synthesize matchHandler; +@synthesize gameViewController; +@synthesize currentMatch; +@synthesize matchHasStarted; +@synthesize matchmakerMode; + +/* +======================== +Singleton implementation. Since we should only ever have one match going on at a time, +the delegate might as well be a singleton. This is Apple's idiomatic example of a Singleton +in Objective-C. +======================== +*/ ++ (MatchDelegate*)sharedMatchDelegate +{ + if (sharedMatchDelegateInstance == nil) { + sharedMatchDelegateInstance = [[super allocWithZone:NULL] init]; + sharedMatchDelegateInstance->matchHandler = NULL; + sharedMatchDelegateInstance->matchHasStarted = NO; + sharedMatchDelegateInstance->currentMatch = nil; + + } + return sharedMatchDelegateInstance; +} + ++ (id)allocWithZone:(NSZone *)zone +{ + (void)zone; + return [[self sharedMatchDelegate] retain]; +} + +- (id)copyWithZone:(NSZone *)zone +{ + (void)zone; + return self; +} + +- (id)retain +{ + return self; +} + +- (NSUInteger)retainCount +{ + return NSUIntegerMax; //denotes an object that cannot be released +} + +- (oneway void)release +{ + //do nothing +} + +- (id)autorelease +{ + return self; +} + + + +/* +======================== +Called by the system when Game Center receives a packet from another player. I was +somewhat surprised that this method actually runs on the main thread. +======================== +*/ +- (void)match:(GKMatch *)match didReceiveData:(NSData *)data fromPlayer:(NSString *)playerID { + (void)match; + (void)playerID; + + // Sanity-check the size of the data. Discard any packets that won't fit. + if ( static_cast( [data length] ) > idGameCenter::MAX_PACKET_SIZE_IN_BYTES ) { + printf( "Received a packet that was too big. Discarding.\n" ); + return; + } + + // Sanity-check the size of the data. Discard any packets with zero length. + if ( [data length] == 0 ) { + printf( "Received a packet with zero length. Discarding.\n" ); + return; + } + + // Give the callback a chance to process the packet. + self.matchHandler->receivedData( NSStringToStdString( playerID ), + [data bytes], + static_cast( [data length] ) ); +} + +/* +======================== +Called by the system when a player's state changes (for example, they connect or disconnect). +======================== +*/ +- (void)match:(GKMatch *)match player:(NSString *)playerID didChangeState:(GKPlayerConnectionState)state { + switch (state) + { + case GKPlayerStateConnected: + matchHandler->playerConnected( NSStringToStdString( playerID ) ); + + if (!matchHasStarted && match.expectedPlayerCount == 0) + { + matchHasStarted = YES; + + std::vector players; + + for( NSString* currentID in match.playerIDs ) { + players.push_back( NSStringToStdString( currentID ) ); + } + matchHandler->allPlayersConnected( players ); + } + + break; + case GKPlayerStateDisconnected: + matchHandler->playerDisconnected( NSStringToStdString( playerID ) ); + break; + } +} + +/* +======================== +Called by the system if the connection with a player fails. +======================== +*/ +- (void)match:(GKMatch *)match connectionWithPlayerFailed:(NSString *)playerID withError:(NSError *)error { + (void)match; + (void)playerID; + + DisplayNSErrorMessage( @"GameKit Error", error ); +} + +/* +======================== +Called by the system if the matchmaking interface fails. +======================== +*/ +- (void)match:(GKMatch *)match didFailWithError:(NSError *)error { + (void)match; + + DisplayNSErrorMessage( @"GameKit Error", error ); +} + + +// GKMatchmakerViewController + +/* +======================== +Called by the system if the user dismisses the matchmaking interface. +======================== +*/ +- (void)matchmakerViewControllerWasCancelled:(GKMatchmakerViewController *)viewController +{ + switch ( matchmakerMode ) { + case MATCH_VIEW_MODAL: { + [gameViewController dismissModalViewControllerAnimated:YES]; + break; + } + + case MATCH_VIEW_PUSH_TO_NAVIGATION_CONTROLLER: { + [viewController.navigationController popViewControllerAnimated:YES]; + break; + } + } +} + +/* +======================== +Called by the system if there is an error in the matchmaking process. +======================== +*/ +- (void)matchmakerViewController:(GKMatchmakerViewController *)viewController didFailWithError:(NSError *)error +{ + (void)viewController; + + DisplayNSErrorMessage( idLocalization_GetNSString( @"Matchmaking error" ), error ); + + switch ( matchmakerMode ) { + case MATCH_VIEW_MODAL: { + [gameViewController dismissModalViewControllerAnimated:YES]; + break; + } + + case MATCH_VIEW_PUSH_TO_NAVIGATION_CONTROLLER: { + [viewController.navigationController popViewControllerAnimated:YES]; + break; + } + } + +} + +/* +======================== +Called by the system if it finds a match. +======================== +*/ +- (void)matchmakerViewController:(GKMatchmakerViewController *)viewController didFindMatch:(GKMatch *)match +{ + (void)viewController; + (void)match; + + switch ( matchmakerMode ) { + case MATCH_VIEW_MODAL: { + [gameViewController dismissModalViewControllerAnimated:YES]; + break; + } + + case MATCH_VIEW_PUSH_TO_NAVIGATION_CONTROLLER: { + [viewController.navigationController popViewControllerAnimated:NO]; + break; + } + } + + NSLog(@"Found a Game Center match!!!"); + + self.currentMatch = match; + match.delegate = self; + + matchHandler->createdMatch(); + + if (!matchHasStarted && match.expectedPlayerCount == 0) + { + matchHasStarted = NO; + + std::vector players; + + for( NSString* currentID in match.playerIDs ) { + players.push_back( NSStringToStdString( currentID ) ); + } + matchHandler->allPlayersConnected( players ); + } +} + +@end + + +/* +================================================ +The private implementation of idGameCenter, defined here in order to insulate user code from +Objective-C land. +================================================ +*/ +namespace { + // Cache the result of HasGameCenterSupport. Even if HasGameCenterSupport returns true, + // it's possible that a Game Kit method may cause a GKErrorNotSupported. If it does, this + // variable will be set to false in HandleError. + bool isAvailable; + + // Cache the player identifier. This is the unique key used to distiguish players in + // Game Kit. All data associated with a player should be tied to this ID, such as + // achievement and savegame progress. Note that this ID can change if a user task-switches + // to the Game Center app and logs in with a different account. + // The string will be empty if no local player is authenticated. + // The string is UTF8 encoded. + std::string playerIdentifier; + + // Store the match handler object. This is how we deal with "callbacks" from the Game Center + // API. + idGameCenterMatchHandler * matchHandler; + + void HandleError( NSError * error ); + + void ConfigureDelegate( matchmakerViewMode_t mode, + id currentViewController, + idGameCenterMatchHandler * handler ); + + void SendPacketToPlayerHelper( std::string destinationPlayer, + void *packet, + std::size_t numBytes, + GKMatchSendDataMode mode ); + + + + + /* + ======================== + Handles errors reported by the Game Kit APIs. If it gets GKErrorNotSupported, this function + sets isAvailable to false. + ======================== + */ + void HandleError( NSError * error ) { + if ( error == nil ) { + return; + } + + switch ( [error code] ) { + case GKErrorGameUnrecognized: { + NSLog( @"GameKit error: Game unrecognized." ); + break; + } + case GKErrorNotSupported: { + NSLog( @"GameKit error: Not supported. Disabling GameKit features." ); + isAvailable = false; + break; + } + default: { + break; + } + } + } + + + /* + ======================== + Sets up neede properties of the match delegate. Call this before showing the matchmaking view + controller. This implementation supports two ways of showing the built-in matchmaker, either + modally or as a new view controller on a navigation controller's stack. If using a + navigation controller, the currentViewController parameter can be left nil. + ======================== + */ + void ConfigureDelegate( matchmakerViewMode_t mode, + id currentViewController, + idGameCenterMatchHandler * handler ) { + + [MatchDelegate sharedMatchDelegate].matchmakerMode = mode; + [MatchDelegate sharedMatchDelegate].matchHandler = handler; + [MatchDelegate sharedMatchDelegate].gameViewController = currentViewController; + [MatchDelegate sharedMatchDelegate].matchHasStarted = NO; + } + + + + /* + ======================== + Sends a packet to a player ID with the data mode specified in the parameter. + ======================== + */ + void SendPacketToPlayerHelper( std::string destinationPlayer, + void *packet, + std::size_t numBytes, + GKMatchSendDataMode mode ) { + + if ( idGameCenter::IsAvailable() == false || idGameCenter::IsLocalPlayerAuthenticated() == false ) { + return; + } + + if ( idGameCenter::IsInMatch() == false ) { + return; + } + + + GKMatch * theMatch = [MatchDelegate sharedMatchDelegate].currentMatch; + + + NSError * theError = nil; + + NSData *nsPacket = [ NSData dataWithBytes:packet length:static_cast( numBytes ) ]; + NSArray *playerArray = [ NSArray arrayWithObject:StdStringToNSString( destinationPlayer ) ]; + + [theMatch sendData:nsPacket toPlayers:playerArray withDataMode:mode error:&theError]; + + if ( theError != nil ) + { + DisplayNSErrorMessage( @"GameKit Error", theError ); + } + } +} + +namespace idGameCenter { +/* +======================== +impl constructor. Sets the inital value of isAvailable based on the OS checks in +HasGameCenterSupport. Note that isAvailable might be set to false later if a GameKit API +returns a GKErrorNotSupported. +======================== +*/ +void Initialize() { + isAvailable = HasGameCenterSupport(); + matchHandler = NULL; +} + + +/* +======================== +Returns true if the runtime device supports Game Center. If it doesn't, we may need to +disable UI elements, etc. +======================== +*/ +bool IsAvailable() { + return isAvailable; +} + +/* +======================== +Returns true if there is a local player authenticated. +======================== +*/ +bool IsLocalPlayerAuthenticated() { + return !playerIdentifier.empty(); +} + +/* +======================== +Attempts to authenticate the local player. Apple recommends that this be done as soon as +possible after the game starts up and is able to display a UI (probably in +applicationDidFinishLaunching). +======================== +*/ +void AuthenticateLocalPlayer( id currentViewController, idGameCenterMatchHandler * handler ) { + // Early exit if Game Center is not supported. + if ( IsAvailable() == false ) { + return; + } + + GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer]; + [localPlayer authenticateWithCompletionHandler:^(NSError * error) { + if ( localPlayer.isAuthenticated ) + { + // Perform additional tasks for the authenticated player. + GKLocalPlayer * lp = [GKLocalPlayer localPlayer]; + + // Cache the player identifier string. + std::string newPlayerIdentifier = NSStringToStdString( [lp playerID] ); + + // If the player changed while the app was in the background, the playerIDs will + // be different. If they are, we have to switch any game state to reflect the + // new player. + if ( newPlayerIdentifier != playerIdentifier ) { + // TODO: Switch game state to reflect the newly logged in player. + } + + playerIdentifier = newPlayerIdentifier; + + // Set up the invitation handler. This code handles the cases where a friend + // is invited to the game from the matchmaking UI or the Game Center application. + [GKMatchmaker sharedMatchmaker].inviteHandler = ^(GKInvite *acceptedInvite, NSArray *playersToInvite) { + // Disconnect from any previous game. + idGameCenter::DisconnectFromMatch(); + + ConfigureDelegate( MATCH_VIEW_MODAL, currentViewController, handler ); + + if (acceptedInvite) + { + GKMatchmakerViewController *mmvc = [[[GKMatchmakerViewController alloc] initWithInvite:acceptedInvite] autorelease]; + mmvc.matchmakerDelegate = [MatchDelegate sharedMatchDelegate]; + [currentViewController presentModalViewController:mmvc animated:YES]; + } + else if (playersToInvite) + { + GKMatchRequest *request = [[[GKMatchRequest alloc] init] autorelease]; + request.minPlayers = 2; + request.maxPlayers = 4; + request.playersToInvite = playersToInvite; + + GKMatchmakerViewController *mmvc = [[[GKMatchmakerViewController alloc] initWithMatchRequest:request] autorelease]; + mmvc.matchmakerDelegate = [MatchDelegate sharedMatchDelegate]; + [currentViewController presentModalViewController:mmvc animated:YES]; + } + }; + } else { + // No new local player is logged in. If no player was logged in before, we shouldn't + // have to do anything here. + // But if a player was previously logged in, we need to update the game state, for + // example, clear achievement progress or load different saved games. + if ( !playerIdentifier.empty() ) { + // TODO: Clean up state related to the old playerIdentifier. + } + + // Empty the string to indicate no one is logged in. + playerIdentifier.clear(); + } + + HandleError( error ); + }]; +} + +/* +======================== +This function must be called when the app is moving to the background (such as from +applicationWillResignActive). It will de-authenticate the local player, because the user +might sign out while our app is in the background. + +According to the Apple documentation, we need to de-authenticate the local player when the app +moves to the background. The implication of this is that for lockstep games like DOOM, we +can't continue to update the game while our app is in the background. In order to not cause +problems for other players, we just disconnect from a match (if any) right here. + +TODO: When we support achievements and/or leaderboards, serialize out any data that hasn't +been successfully sent to Game Center yet. We'll need to do this because the OS might kill +our app while it's in the background. +======================== +*/ +void HandleMoveToBackground() { + if ( IsInMatch() ) { + ShowSystemAlert( "Connection lost", "Lost connection to server" ); + } + + DisconnectFromMatch(); + playerIdentifier.empty(); +} + + + +/* +======================== +Presents Game Center's built-in matchmaking view controller as a model view controller on top +of currentViewController. +MAKE SURE the handler object survives the duration of the app! +======================== +*/ +void PresentMatchmaker( id currentViewController, matchParms_t parms, idGameCenterMatchHandler * handler ) { + // Early exit if Game Center is not active. + if ( IsAvailable() == false || IsLocalPlayerAuthenticated() == false ) { + return; + } + + ConfigureDelegate( MATCH_VIEW_MODAL, currentViewController, handler ); + + + GKMatchRequest *request = [[[GKMatchRequest alloc] init] autorelease]; + request.minPlayers = parms.minimumPlayers; + request.maxPlayers = parms.maximumPlayers; + request.playerGroup = parms.automatchGroup; + + GKMatchmakerViewController *mmvc = [[[GKMatchmakerViewController alloc] initWithMatchRequest:request] autorelease]; + mmvc.matchmakerDelegate = [MatchDelegate sharedMatchDelegate]; + + [(UIViewController*)currentViewController presentModalViewController:mmvc animated:YES]; +} + +/* +======================== +Presents Game Center's built-in matchmaking view controller as a new controller on top +of the navigationController's stack. +MAKE SURE the handler object survives the duration of the app! +======================== +*/ +void PushMatchmakerToNavigationController( id navigationController, + matchParms_t parms, + idGameCenterMatchHandler * handler ) { + // Early exit if Game Center is not active. + if ( IsAvailable() == false || IsLocalPlayerAuthenticated() == false ) { + return; + } + + ConfigureDelegate( MATCH_VIEW_PUSH_TO_NAVIGATION_CONTROLLER, nil, handler ); + + GKMatchRequest *request = [[[GKMatchRequest alloc] init] autorelease]; + request.minPlayers = parms.minimumPlayers; + request.maxPlayers = parms.maximumPlayers; + request.playerGroup = parms.automatchGroup; + + GKMatchmakerViewController *mmvc = [[[GKMatchmakerViewController alloc] initWithMatchRequest:request] autorelease]; + mmvc.matchmakerDelegate = [MatchDelegate sharedMatchDelegate]; + + [navigationController pushViewController:mmvc animated:YES]; +} + +/* +======================== +Returns true if the player is currently connected to a Game Center match, false if not. +======================== +*/ +bool IsInMatch() { + return [MatchDelegate sharedMatchDelegate].currentMatch != nil; +} + +/* +======================== +Sends an unreliable packet to a single player. +======================== +*/ +void SendPacketToPlayerUnreliable( std::string destinationPlayer, + void *packet, + std::size_t numBytes ) { + SendPacketToPlayerHelper( destinationPlayer, packet, numBytes, GKMatchSendDataUnreliable ); +} + + +/* +======================== +Sends a reliable packet to a single player. +======================== +*/ +void SendPacketToPlayerReliable( std::string destinationPlayer, + void *packet, + std::size_t numBytes ) { + SendPacketToPlayerHelper( destinationPlayer, packet, numBytes, GKMatchSendDataReliable ); +} + + + +/* +======================== +Sends a packet to all other players in the current match. Just returns if Game Center is not +available or if the local player is not in a match. +======================== +*/ +void BroadcastPacketReliable( void * packet, int numBytes ) { + if ( IsAvailable() == false || IsLocalPlayerAuthenticated() == false ) { + return; + } + + if ( IsInMatch() == false ) { + return; + } + + + GKMatch * theMatch = [MatchDelegate sharedMatchDelegate].currentMatch; + + + NSError * theError = nil; + + NSData *nsPacket = [NSData dataWithBytes:packet length:static_cast(numBytes)]; + + [theMatch sendDataToAllPlayers:nsPacket withDataMode:GKMatchSendDataReliable error:&theError]; + + if ( theError != nil ) + { + DisplayNSErrorMessage( @"GameKit Error", theError ); + } +} + +/* +======================== +If this player is currently connected to a match. this will disconnect them. +======================== +*/ +void DisconnectFromMatch() { + if ( IsInMatch() ) { + [[MatchDelegate sharedMatchDelegate].currentMatch disconnect]; + + // currentMatch is a retained property, so this will release it. + [MatchDelegate sharedMatchDelegate].currentMatch = nil; + } +} + +} + + diff --git a/common/idmobilelib/ios/InAppStore.h b/common/idmobilelib/ios/InAppStore.h new file mode 100755 index 0000000..1e1ec3b --- /dev/null +++ b/common/idmobilelib/ios/InAppStore.h @@ -0,0 +1,95 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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. + + */ + + +/* +================================================================================================ + +Interface to the device's In-App Purchase system. + + +This interface was designed to be dropped into any game that needs support for in-app purchases, +that is, there is nothing game-specific about this interface or its implementation. + +It is essentially a singleton implemented in the idInAppPurchase namespace. The singleton must +be initialized at application launch (via Initialize()) and shut down at application exit (via +Shutdown()). + +There are functions to request information about products for sale within the app, check whether +a particular product has been purchased, and get the localized price for a product, suitable +for displaying in the user interface. + +Generally an app should call RequestInformation() at startup (but after Initialize()) and pass +in all the product identifiers that the app offers for sale. The request will run in the +background so that the interface will remain responsive. Once the requests have been returned, +the application can get the price information and actually initiate purchases of products. + +================================================================================================ +*/ + + +#ifndef INAPPSTORE_H +#define INAPPSTORE_H + +#include +#include +#include + +namespace idInAppStore { + + void Initialize( const std::vector & productIdentifiers ); + void Shutdown(); + + bool IsEnabled(); + + void ShowDisabledAlert( std::string title, + std::string description, + std::string okButton ); + + bool HasPurchased( const char * const productIdentifier ); + bool CanPurchase( const char * const productIdentifier ); + bool IsWaitingForInformation( const char * const productIdentifier ); + bool IsWaitingForPurchase( const char * const productIdentifier ); + + std::string GetLocalizedPrice( const char * const productIdentifier ); + + void StartPurchase( const char * const productIdentifier ); + + /* + ======================== + The application can register callbacks to be notified of events that occur relating to + the in-app store. The first parameter to the callback function is the product identifier + string for the product that was affected, the second is the status of that product. + ======================== + */ + enum productStatus_t { + PRODUCT_STATUS_TRANSACTION_FAILED, + PRODUCT_STATUS_RECEIVED_INFORMATION, + PRODUCT_STATUS_PURCHASED + }; + + typedef std::tr1::function< void ( const char * const, productStatus_t ) > callback_t; + + void SetCallback( callback_t callback ); + void ClearCallback(); +} + + +#endif diff --git a/common/idmobilelib/ios/InAppStore.mm b/common/idmobilelib/ios/InAppStore.mm new file mode 100755 index 0000000..0454483 --- /dev/null +++ b/common/idmobilelib/ios/InAppStore.mm @@ -0,0 +1,683 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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. + + */ + +/* +================================================================================================ + +Implentation of the In-App Purchase system for iOS devices. + + +This implementation conforms to the interface in InAppStore.h. It uses the NSUserDefaults object +provided by the system to keep track of the state of the products that the application offers. + +================================================================================================ +*/ + + +#include "InAppStore.h" + +#import +#import + +#include +#include +#include +#include + +// For ease of development, leave this defined to skip in-app purchase prompts. +//#define TEST_ALL_PRODUCTS_PURCHASED + +@interface MyStoreObserver : NSObject { + +} + +// SKProductsRequestDelegate methods +- (void)productsRequest: (SKProductsRequest *)request didReceiveResponse: (SKProductsResponse *)response; + +// SKPaymentTransactionObserver methods +- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions; +- (void)paymentQueue:(SKPaymentQueue *)queue removedTransactions:(NSArray *)transactions; + +- (void)paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error; +- (void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue; + +// MyStoreObserver methods +- (void)completeTransaction:(SKPaymentTransaction *)transaction; +- (void)failedTransaction:(SKPaymentTransaction *)transaction; +- (void)restoreTransaction:(SKPaymentTransaction *)transaction; +- (void)finalizeTransaction:(SKPaymentTransaction *)transaction; + +@end + +// Unnamed-namespace for stuff that's "private" to this file (internal linkage). +namespace { + // The single instance of the store observer. This is created in Initialize and released + // in Shutdown. + MyStoreObserver * observer; + + // The callback to invoke when an interesting event occurs. + idInAppStore::callback_t callbackObject; + + /* + ================================================ + Each product identifier has an associated state to keep track of the progress of + in-app purchases. These states are stored in the NSUserDefaults for the corresponding + product identifier. These states are not in an enum because the the NSUserDefaults store + NSIntegers, and we can't define the type of an enum in C++03. + ================================================ + */ + typedef NSInteger productState_t; + + // This is the state of a product if it not found in the user's defaults. + const productState_t PRODUCT_NOT_FOUND = 0; + + // Information from this product has been requested, but has not been received yet. + const productState_t PRODUCT_WAIT_FOR_INFORMATION = 1; + + // Information for this product is available, but a purchase has not been initiated. + const productState_t PRODUCT_HAS_INFORMATION = 2; + + // A purchase was initiated, and the application is waiting for the App Store to + // process the purchase. + const productState_t PRODUCT_WAIT_FOR_PURCHASE = 3; + + // The app store has fully processed the purchase and the product is available for the + // user/ + const productState_t PRODUCT_PURCHASED = 4; + + + void RequestInformation( const std::vector & productIdentifiers ); + + /* + ================================================ + Store product information in a C++ friendly way. + ================================================ + */ + struct productInformation_t { + std::string identifier; + std::string localizedPrice; + + productInformation_t( const std::string & identifier_, const std::string & localizedPrice_ ) + : identifier( identifier_ ) + , localizedPrice( localizedPrice_ ) + { + } + }; + + // Cache the product information that has been received from the App Store. + typedef std::map productMap_t; + productMap_t productCache; + + /* + ======================== + GetProductState + + Queries the NSUserDefaults for the state of the product corresponding to the + productIdentifier. + ======================== + */ + productState_t GetProductState( const char * const productIdentifier ) { +#if defined( TEST_ALL_PRODUCTS_PURCHASED ) + return PRODUCT_PURCHASED; +#endif + + // Convert the C string to an NSString for use with NSUserDefaults. + NSString *productKey = [NSString stringWithCString:productIdentifier + encoding:NSUTF8StringEncoding]; + + // Purchase records are stored in the standardUserDefaults, with a key equal to the + // product identifier. + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + NSInteger productState = [defaults integerForKey:productKey]; + + return productState; + } + + /* + ======================== + SetProductState + + Sets the NSUserDefaults value corresponding to product identifier to the given state. + ======================== + */ + void SetProductState( NSString * productIdentifier, productState_t state ) { + // Purchase records are stored in the standardUserDefaults, with a key equal to the + // product identifier. + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + [defaults setInteger:state forKey:productIdentifier]; + } + + /* + ======================== + SetProductState + + Sets the NSUserDefaults value corresponding to product identifier to the given state. + ======================== + */ + void SetProductState( const char * const productIdentifier, productState_t state ) { + // Convert the C string to an NSString for use with NSUserDefaults. + NSString *productKey = [NSString stringWithCString:productIdentifier + encoding:NSUTF8StringEncoding]; + + SetProductState( productKey, state ); + } + + /* + ======================== + RequestInformation + + Queries the App Store for information about the all the identifiers in the vector. + When the App Store responds, calls the callback. The product identifiers are UTF8 encoded. + + If in-app purchases are disabled, this function does nothing. The application may want to + show an alert in this case. The application can call IsEnabled() to check for this. + ======================== + */ + void RequestInformation( const std::vector & productIdentifiers ) { + // Early exit if the system hasn't been initialized. + if ( observer == nil ) { + printf( "In-App Purchase system not initialized. Can't purchase anything!\n" ); + return; + } + + // Early exit if in-app purchases are disabled. + if ( [SKPaymentQueue canMakePayments] == FALSE ) { + printf( "In-App Purchases are disabled for this device. Can't purchase anything!\n" ); + return; + } + + // This will be the set of product identifiers to request from the App Store. + NSMutableSet * identifiersToRequest = [NSMutableSet setWithCapacity: productIdentifiers.size()]; + +#ifndef NDEBUG + // For debugging purposes, set this flag to 'true' and all in-app purchase products + // will be reset to the unpurchased state. + bool resetPurchases = false; + + if ( resetPurchases ) { + for( std::vector::const_iterator i = productIdentifiers.begin(); i != productIdentifiers.end(); ++i ) { + SetProductState( i->c_str(), PRODUCT_NOT_FOUND ); + } + } +#endif + + // Check the NSUserDefaults for each identifier requested, to get the state of + // the product. + for( std::vector::const_iterator i = productIdentifiers.begin(); i != productIdentifiers.end(); ++i ) { + // If the user has not purchased this product, we need to request information about + // it from the App Store. + productState_t productState = GetProductState( i->c_str() ); + if ( productState != PRODUCT_PURCHASED ) { + + SetProductState( i->c_str(), PRODUCT_WAIT_FOR_INFORMATION ); + + NSString * nsIdentifier = [NSString stringWithCString:i->c_str() + encoding:NSUTF8StringEncoding]; + + [identifiersToRequest addObject:nsIdentifier]; + } + } + + // Now we know which identifiers to request from the store, start the request object. + if ( [identifiersToRequest count] > 0 ) { + SKProductsRequest *request= [[SKProductsRequest alloc] + initWithProductIdentifiers:identifiersToRequest ]; + + request.delegate = observer; + [request start]; + } + } +} + +namespace idInAppStore { + + /* + ======================== + Initialize + + Creates the StoreKit observer object and registers it with the payment queue. The + application must provide all the product IDs it has available for sale to this function, + so that it can request information from the app store. + ======================== + */ + void Initialize( const std::vector & productIdentifiers ) { + if ( !observer ) { + observer = [[MyStoreObserver alloc] init]; + + // Add the observer here in case purchase requests were interrupted last time. + [[SKPaymentQueue defaultQueue] addTransactionObserver:observer]; + } + + RequestInformation( productIdentifiers ); + } + + /* + ======================== + Shutdown + + Frees the StoreKit observer object. + ======================== + */ + void Shutdown() { + [observer release]; + observer = nil; + } + + /* + ======================== + IsEnabled + + Returns true if in-app purchases are enabled, false if they are not. + ======================== + */ + bool IsEnabled() { + return ( [SKPaymentQueue canMakePayments] )? true: false; + } + + /* + ======================== + StartPurchase + + Begins the purchase process with the App Store. The product id must have been + previously requested through RequestInformation. This will launch the OS-controlled + confirmation prompt after a moment, and it might take a while to actually complete the + purchase. + ======================== + */ + void StartPurchase( const char * const productIdentifier ) { + if ( ![SKPaymentQueue canMakePayments] ) { + return; + } + + if ( !CanPurchase( productIdentifier ) ) { + return; + } + + SetProductState( productIdentifier, PRODUCT_WAIT_FOR_PURCHASE ); + + NSString * nsProductIdentifier = [NSString stringWithCString:productIdentifier + encoding:NSUTF8StringEncoding]; + + SKPayment * payment = [SKPayment paymentWithProductIdentifier:nsProductIdentifier]; + [[SKPaymentQueue defaultQueue] addPayment:payment]; + } + + /* + ======================== + ShowDisabledAlert + + If and only if in-app purchases are disabled, shows an alert notifying the user of this fact + and reminds him or her that he or she can enable in-app purchases in settings. + + If in-app purchasees are enabled, this function does nothing. + + The string parameters must be encoded in UTF8. + ======================== + */ + void ShowDisabledAlert( std::string title, + std::string description, + std::string okButton ) { + if ( ![SKPaymentQueue canMakePayments] ) { + // User has disabled In-App purchases in settings. Kindly remind him that he can + // enable purchases again. + + if ( title.empty() ) { + title = "In-App Purchases are disabled"; + } + + if ( description.empty() ) { + description = "You can enable In-App purchases in your device's settings."; + } + + if ( okButton.empty() ) { + title = "OK"; + } + + NSString * nsTitle = [NSString stringWithCString:title.c_str() encoding:NSUTF8StringEncoding]; + NSString * nsDescription = [NSString stringWithCString:description.c_str() encoding:NSUTF8StringEncoding]; + NSString * nsOkButton = [NSString stringWithCString:okButton.c_str() encoding:NSUTF8StringEncoding]; + + UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nsTitle + message:nsDescription + delegate:nil + cancelButtonTitle:nsOkButton + otherButtonTitles:nil]; + + // Make sure the alert shows up on the main thread. + [alert show]; + [alert release]; + } + } + + /* + ======================== + HasPurchased + + Queries the standard NSUserDefaults object for the state of the product with the given + identifier. If the state is PRODUCT_PURCHASED, the user has purchased the product. + If the state is anything else, the user has not purchased the product. + ======================== + */ + bool HasPurchased( const char * const productIdentifier ) { + const productState_t state = GetProductState( productIdentifier ); + const bool stateIsPurchased = (state == PRODUCT_PURCHASED); + return ( stateIsPurchased ); + } + + /* + ======================== + CanPurchase + + Returns true if it is safe for the application to start a purchase, false if the application + should not start a purchase at this time. + ======================== + */ + bool CanPurchase( const char * const productIdentifier ) { + const productState_t state = GetProductState( productIdentifier ); + const bool stateHasInformaion = ( state == PRODUCT_HAS_INFORMATION ); + return ( stateHasInformaion ); + } + + + /* + ======================== + IsWaitingForInformation + + Queries the standard NSUserDefaults object for the state of the product with the given + identifier. If the application is still waiting for the App Store to return information, + this function returns true. If the application has information, this function returns false. + ======================== + */ + bool IsWaitingForInformation( const char * const productIdentifier ) { + return ( GetProductState( productIdentifier ) == PRODUCT_WAIT_FOR_INFORMATION ); + } + + /* + ======================== + IsWaitingForPurchase + + Queries the standard NSUserDefaults object for the state of the product with the given + identifier. If the application is still waiting for the App Store to purchase the item, + this function returns true. If the application is not waiting on the app store, returns false. + ======================== + */ + bool IsWaitingForPurchase( const char * const productIdentifier ) { + return ( GetProductState( productIdentifier ) == PRODUCT_WAIT_FOR_PURCHASE ); + } + + /* + ======================== + GetLocalizedPrice + + Returns a UTF-8 encoded string that represents the price of the product. This string is + suitable for display to the user. If the string isn't available yet, for example, if the + App Store hasn't responded to an information request, the return value will be an empty + string. + ======================== + */ + std::string GetLocalizedPrice( const char * const productIdentifier ) { + productMap_t::iterator found = productCache.find( productIdentifier ); + + if ( found != productCache.end() ) { + return found->second.localizedPrice; + } + + return std::string(); + } + + /* + ======================== + SetCallback + + Stores a callback function to be invoked when something happens relating to a product. + ======================== + */ + void SetCallback( callback_t callback ) { + callbackObject = callback; + } + + /* + ======================== + ClearCallback + + Removes the callback function previously registered through SetCallback. + ======================== + */ + void ClearCallback() { + callbackObject = callback_t(); + } +} + + + +@implementation MyStoreObserver + +- (void) showInvalidProductIdAlert +{ + NSString * nsTitle = @"In-app purchase error"; + NSString * nsDescription = @"Invalid product ID requested. In-app purchase will not work!"; + NSString * nsOkButton = @"OK"; + + UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nsTitle + message:nsDescription + delegate:nil + cancelButtonTitle:nsOkButton + otherButtonTitles:nil]; + + [alert show]; + [alert release]; +} + +/* +======================== +productsRequest:didReceiveResponse + +Called by the OS when the application gets product information about an In-App Purchase. +======================== +*/ +- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response +{ + NSArray *myProduct = response.products; + NSArray *invalidProducts = response.invalidProductIdentifiers; + + for ( SKProduct * product in myProduct ) + { + NSLog( @"Valid product: %@", product.productIdentifier); + } + + for ( NSString * productId in invalidProducts ) + { + NSLog( @"Invalid product: %@", productId); + + [self performSelectorOnMainThread:@selector(showInvalidProductIdAlert) withObject:nil waitUntilDone:NO]; + return; + } + + // We should handle the case of an empty array, this seems to occur if we send a request + // with a nonexistant product ID, but there may be other cases. + // TODO: Need a timeout to be even more robust. + if ( [myProduct count] == 0 ) { + //if ( clientCallback ) { + // clientCallback( IAP_FAILURE ); + //} + return; + } + + // We can use the same number formatter for all the products. + NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init]; + [numberFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4]; + [numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle]; + + // Get the response and cache it. + for ( SKProduct * product in response.products ) + { + // Convert the price to user-interface worthy representation. + [numberFormatter setLocale:product.priceLocale]; + NSString *formattedString = [numberFormatter stringFromNumber:product.price]; + + const std::string priceString = [formattedString cStringUsingEncoding:NSUTF8StringEncoding]; + + // Convert the NSString identifier to a C++ string. + const std::string identifierString = [product.productIdentifier cStringUsingEncoding:NSUTF8StringEncoding]; + + productInformation_t productInformation( identifierString, priceString ); + + // Add the C++ product information to the cache. + productCache.insert( std::make_pair( identifierString, productInformation ) ); + + // Store the fact that we have information in the defaults. + SetProductState( identifierString.c_str(), PRODUCT_HAS_INFORMATION ); + + if ( callbackObject ) { + callbackObject( identifierString.c_str(), idInAppStore::PRODUCT_STATUS_RECEIVED_INFORMATION ); + } + } + + [numberFormatter release]; + [request autorelease]; +} + +/* + ======================== + paymentQueue:updatedTransactions + + Called by the system when purchase requests are updated. + ======================== + */ +- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions +{ + (void)queue; + for (SKPaymentTransaction *transaction in transactions) + { + switch (transaction.transactionState) + { + case SKPaymentTransactionStatePurchased: + [self completeTransaction:transaction]; + break; + case SKPaymentTransactionStateFailed: + [self failedTransaction:transaction]; + break; + case SKPaymentTransactionStateRestored: + [self restoreTransaction:transaction]; + default: + break; + } + } +} + +- (void)paymentQueue:(SKPaymentQueue *)queue removedTransactions:(NSArray *)transactions +{ + (void)queue; (void)transactions; +} + +- (void)paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error +{ + (void)queue; (void)error; +} + + +- (void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue +{ + (void)queue;} + +/* +======================== +completeTransaction + +Called by updatedTransactions when a request is completed. +======================== +*/ +- (void)completeTransaction:(SKPaymentTransaction *)transaction +{ + [self finalizeTransaction:transaction]; +} + +/* +======================== +failedTransaction + +Called by updatedTransactions when a request fails. +======================== +*/ +- (void)failedTransaction:(SKPaymentTransaction *)transaction +{ + if (transaction.error.code != SKErrorPaymentCancelled) + { + UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"In-App Purchase error" + message:[transaction.error localizedDescription] + delegate:nil + cancelButtonTitle:@"OK" + otherButtonTitles:nil]; + + [alert show]; + [alert release]; + } + [[SKPaymentQueue defaultQueue] finishTransaction: transaction]; + + const char * const cProductIdentifier = [transaction.payment.productIdentifier cStringUsingEncoding:NSUTF8StringEncoding]; + + // Since we can get failed transactions after the user has already purchased a product, + // don't do anthing if the user has already purchased the product. + if ( GetProductState( cProductIdentifier ) != PRODUCT_PURCHASED ) { + SetProductState( transaction.payment.productIdentifier, PRODUCT_HAS_INFORMATION ); + + + if ( callbackObject ) { + callbackObject( cProductIdentifier, idInAppStore::PRODUCT_STATUS_TRANSACTION_FAILED ); + } + } +} + +/* +======================== +restoreTransaction + +Called by updatedTransactions when a request is restored. This can behave identically to +completeTransaction. +======================== +*/ +- (void)restoreTransaction:(SKPaymentTransaction *)transaction +{ + [self finalizeTransaction:transaction.originalTransaction]; +} + +/* +======================== +finalizeTransaction + +This method actually delivers the purchased item to the user. Currently, this means setting +the state in NSUserDefaults to PRODUCT_PURCHASED. +======================== +*/ +- (void)finalizeTransaction:(SKPaymentTransaction *)transaction +{ + SetProductState( transaction.payment.productIdentifier, PRODUCT_PURCHASED ); + + [[SKPaymentQueue defaultQueue] finishTransaction: transaction]; + + const char * const cProductIdentifier = [transaction.payment.productIdentifier cStringUsingEncoding:NSUTF8StringEncoding]; + + if ( callbackObject ) { + callbackObject( cProductIdentifier, idInAppStore::PRODUCT_STATUS_PURCHASED ); + } +} + +@end + diff --git a/common/idmobilelib/ios/Label.h b/common/idmobilelib/ios/Label.h new file mode 100755 index 0000000..8081abd --- /dev/null +++ b/common/idmobilelib/ios/Label.h @@ -0,0 +1,30 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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. + + */ + +#import + + +@interface idLabel : UILabel { + +} + +- (void) SetupLabel: ( NSString * )fontName ; + +@end diff --git a/common/idmobilelib/ios/Label.mm b/common/idmobilelib/ios/Label.mm new file mode 100755 index 0000000..f3302e8 --- /dev/null +++ b/common/idmobilelib/ios/Label.mm @@ -0,0 +1,55 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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. + + */ +#import +#import +#import "Label.h" +#include "Localization.h" + +@implementation idLabel + +/* + ======================== + awakeFromNib + ======================== + */ +- (void)awakeFromNib { + + [ self SetupLabel:@"idGinza Narrow" ]; +} + + +/* + ======================== + SetupLabel + ======================== + */ +- (void) SetupLabel: ( NSString * )fontName { + + // Set the Font + CGFloat points = self.font.pointSize; + self.font = [UIFont fontWithName:fontName size:points]; + + // Localize the text. + NSString * unLocText = self.text; + const char * utf8string = idLocalization_GetString( [unLocText UTF8String ] ); + self.text = [ NSString stringWithCString: utf8string encoding:NSUTF8StringEncoding ]; +} + +@end diff --git a/common/idmobilelib/ios/LabelButton.h b/common/idmobilelib/ios/LabelButton.h new file mode 100755 index 0000000..d4e226f --- /dev/null +++ b/common/idmobilelib/ios/LabelButton.h @@ -0,0 +1,40 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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. + + */ + +#import +#import +#import "Label.h" + +@interface idLabelButton : UIButton { + + UIColor * labelColor; + UIColor * label2Color; +} + + +@property (nonatomic, retain) IBOutlet idLabel *label; +@property (nonatomic, retain) IBOutlet idLabel *label2; + +- (void) Hide; +- (void) Show; +- (void) Enable; +- (void) Disable; + +@end diff --git a/common/idmobilelib/ios/LabelButton.mm b/common/idmobilelib/ios/LabelButton.mm new file mode 100755 index 0000000..34aa9f9 --- /dev/null +++ b/common/idmobilelib/ios/LabelButton.mm @@ -0,0 +1,202 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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. + + */ +#import "LabelButton.h" +#import "Label.h" +#import "Slider.h" +#import "Switch.h" +#import "Carousel.h" +#import "Localization.h" +@implementation idLabelButton + +@synthesize label; +@synthesize label2; + +/* + ======================== + idLabelButton::awakeFromNib + ======================== + */ +- (void)awakeFromNib { + + // Do not optimize my class out + [idLabel class ]; + [idSlider class]; + [idSwitch class]; + [idCarousel class]; + + CGFloat points = self.titleLabel.font.pointSize; + + self.titleLabel.font = [UIFont fontWithName:@"idGinza Narrow" size:points]; + + // Localize the text. + NSString * unLocText = self.titleLabel.text; + if( unLocText ) { + const char * utf8string = idLocalization_GetString( [unLocText UTF8String ] ); + + NSString * localizedString = [ NSString stringWithCString: utf8string encoding:NSUTF8StringEncoding ]; + [self setTitle: localizedString forState:UIControlStateNormal]; + [self setTitle: localizedString forState:UIControlStateHighlighted]; + } + + if( self.label2 ) + label2Color = self.label2.textColor; + if( self.label ) { + labelColor = self.label.textColor; + } + +} + +/* + ======================== + idLabelButton::setHighlighted + ======================== + */ +- (void)setHighlighted:(BOOL)highlight { + if( highlight ) { + if( self.label ) + self.label.textColor = self.label.highlightedTextColor; + if( self.label2 ) + self.label2.textColor = self.label2.highlightedTextColor; + } else if( self.enabled ) { + if( self.label ) + self.label.textColor = labelColor; + if( self.label2 ) + self.label2.textColor = label2Color; + } + + [super setHighlighted:highlight]; + + // Localize the text. + NSString * unLocText = self.titleLabel.text; + if( unLocText ) { + const char * utf8string = idLocalization_GetString( [unLocText UTF8String ] ); + self.titleLabel.text = [ NSString stringWithCString: utf8string encoding:NSUTF8StringEncoding ]; + } +} + +/* + ======================== + idLabelButton::setEnabled + ======================== + */ +- (void)setEnabled:(BOOL)enabled { + if( !enabled ) { + if( self.label ) + self.label.textColor = self.label.highlightedTextColor; + if( self.label2 ) + self.label2.textColor = self.label2.highlightedTextColor; + } else { + if( self.label ) + self.label.textColor = labelColor; + if( self.label2 ) + self.label2.textColor = label2Color; + } + + [super setEnabled:enabled]; + + // Localize the text. + NSString * unLocText = self.titleLabel.text; + if( unLocText ) { + const char * utf8string = idLocalization_GetString( [unLocText UTF8String ] ); + self.titleLabel.text = [ NSString stringWithCString: utf8string encoding:NSUTF8StringEncoding ]; + } +} + +/* + ======================== + idLabelButton::Enable + ======================== + */ +- (void) Enable { + + self.enabled = YES; + if( self.label ) + label.enabled = YES; + if( self.label2 ) + label2.enabled = YES; +} + +/* + ======================== + idLabelButton::Disable + ======================== + */ +- (void) Disable { + self.enabled = NO; + if( self.label ) + label.enabled = NO; + if( self.label2 ) + label2.enabled = NO; +} + +/* + ======================== + idLabelButton::Hide + ======================== + */ +- (void) Hide { + + [UIView beginAnimations:@"Hide" context:nil]; + [UIView setAnimationDuration:1.0f]; + [UIView setAnimationCurve: UIViewAnimationCurveEaseInOut]; + [UIView setAnimationBeginsFromCurrentState:YES]; + [UIView setAnimationDelegate:self]; + [UIView setAnimationDidStopSelector:@selector(Disable)]; + + self.alpha = 0.0f; + if( self.label ) + label.alpha = 0.0f; + if( self.label2 ) + label2.alpha = 0.0f; + + [UIView commitAnimations]; +} + +/* + ======================== + idLabelButton::Show + ======================== + */ +- (void) Show { + + [UIView beginAnimations:@"Show" context:nil]; + [UIView setAnimationDuration:1.0f]; + [UIView setAnimationCurve: UIViewAnimationCurveEaseInOut]; + [UIView setAnimationBeginsFromCurrentState:YES]; + [UIView setAnimationDelegate:self]; + [UIView setAnimationDidStopSelector:@selector(Enable)]; + + self.alpha = 1.0f; + if( self.label ) + label.alpha = 1.0f; + if( self.label2 ) + label2.alpha = 1.0f; + + [UIView commitAnimations]; +} + +- (void) dealloc { + label = nil; + label2 = nil; + + [super dealloc]; +} + +@end diff --git a/common/idmobilelib/ios/Localization.h b/common/idmobilelib/ios/Localization.h new file mode 100755 index 0000000..7faf09f --- /dev/null +++ b/common/idmobilelib/ios/Localization.h @@ -0,0 +1,83 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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. + + */ + +/* + ================================================================================================ + + A game-generic C++ wrapper around the iOS Localizable Strings functionality. + + Basics of Localaization on Apple platforms: + + Each Localization language has a bundle associated with it ( *.lproj ). + We gather the bundle for the current ( or needed ) language. + [[NSBundle mainBundle ] pathForResource:@"en" ofType:@"lproj" ]; + + You MUST add a Localizable.strings file ( named exactly that ) to the project. + + Apple provides a system for getting strings from the localizable.strings file. + NSString* nsString = [ bundle localizedStringForKey:key value:nil table:nil ]; + + The Localizable.strings file must be formatted like: + "KEY" = "VALUE"; + and end with a semi-coln. + + Apple Developer Reference: + http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/LoadingResources/Strings/Strings.html + + We wrapper this up into 4 easy functions. + "Localization_Initialize" Must be called to create/set the current language bundle for the system. + "Localization_SetLanguage" Can be called at dynamically to set the language. + "Localization_GetString" Gets a string value from a key'd pair + + SUPPORTED LANGUAGES: + ENGLISH, + FRENCH, + ITALIAN, + GERMAN, + SPANISH + + ================================================================================================ + */ + +#ifndef IDMOBILELIB_LOCALIZATION_H +#define IDMOBILELIB_LOCALIZATION_H + +#ifdef __cplusplus + extern "C" { +#endif + + enum ID_LANGUAGE { + LANGUAGE_ENGLISH = 0, + LANGUAGE_FRENCH, + LANGUAGE_ITALIAN, + LANGUAGE_GERMAN, + LANGUAGE_SPANISH + }; + + void idLocalization_Initialize(); + void idLocalization_SetLanguage( enum ID_LANGUAGE language ); + enum ID_LANGUAGE idLocalization_GetLanguage(); + const char * idLocalization_GetString( const char * key ); + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/common/idmobilelib/ios/Localization.mm b/common/idmobilelib/ios/Localization.mm new file mode 100755 index 0000000..e7632c9 --- /dev/null +++ b/common/idmobilelib/ios/Localization.mm @@ -0,0 +1,134 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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 "Localization.h" +#include "LocalizationObjectiveC.h" + +#import + +static NSBundle* mCurrentBundle = NULL; +static ID_LANGUAGE mCurrentLanguage; +static const char* mCurrentLanguageStr; + +/* + ======================== + idLocalization::SetLanguage + Sets the language of the system with an enumeration passed in. + ======================== + */ +void idLocalization_SetLanguage( ID_LANGUAGE language ) { + + NSString* langPath = nil; + + switch( language ) { + case LANGUAGE_ENGLISH: + langPath = [[NSBundle mainBundle ] pathForResource:@"en" ofType:@"lproj" ]; + break; + case LANGUAGE_FRENCH: + langPath = [[NSBundle mainBundle ] pathForResource:@"fr" ofType:@"lproj" ]; + break; + case LANGUAGE_ITALIAN: + langPath = [[NSBundle mainBundle ] pathForResource:@"it" ofType:@"lproj" ]; + break; + case LANGUAGE_GERMAN: + langPath = [[NSBundle mainBundle ] pathForResource:@"de" ofType:@"lproj" ]; + break; + case LANGUAGE_SPANISH: + langPath = [[NSBundle mainBundle ] pathForResource:@"es" ofType:@"lproj" ]; + break; + default: + langPath = [[NSBundle mainBundle ] pathForResource:@"en" ofType:@"lproj" ]; + break; + } + + mCurrentBundle = [[NSBundle bundleWithPath:langPath] retain ]; +} + + +/* + ======================== + idLocalization::GetLanguage + Gets the current system's language + ======================== + */ +ID_LANGUAGE idLocalization_GetLanguage() { + return mCurrentLanguage; +} + +/* + ======================== + idLocalization::Initialize + Gathers the local device's language, and sets that as the systems language. + ======================== + */ +void idLocalization_Initialize() { + + NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; + NSArray* languages = [defaults objectForKey:@"AppleLanguages"]; + NSString* current = [[languages objectAtIndex:0] retain ]; + mCurrentLanguageStr = [current UTF8String]; + + if([current isEqualToString:@"en"]){ + mCurrentLanguage = LANGUAGE_ENGLISH; + } else if([current isEqualToString:@"fr"]){ + mCurrentLanguage = LANGUAGE_FRENCH; + } else if([current isEqualToString:@"it"]){ + mCurrentLanguage = LANGUAGE_ENGLISH; + } else if([current isEqualToString:@"sp"] || [current isEqualToString:@"es"]){ + mCurrentLanguage = LANGUAGE_SPANISH; + } else if([current isEqualToString:@"ge"] || [current isEqualToString:@"de"]){ + mCurrentLanguage = LANGUAGE_GERMAN; + } else { + mCurrentLanguage = LANGUAGE_ENGLISH; + } + + idLocalization_SetLanguage( mCurrentLanguage ); +} + +/* + ======================== + idLocalization::GetString + Gets a String value from the pair key passed in from Localizable.strings file. + ======================== + */ +const char * idLocalization_GetString( const char * key ) { + + NSString* nsKey = [NSString stringWithUTF8String:key]; + NSString* nsString = [mCurrentBundle localizedStringForKey:nsKey value:nil table:nil]; + const char* cString = nil; + + if( nsString != nil ) { + cString = [nsString cStringUsingEncoding:NSWindowsCP1252StringEncoding]; + } else { + cString = key; + } + + return cString; +} + +/* + ======================== + idLocalization::GetString + Gets a String value from the pair key passed in from Localizable.strings file. + ======================== + */ +NSString * idLocalization_GetNSString( NSString * key ) { + return [mCurrentBundle localizedStringForKey:key value:nil table:nil]; +} diff --git a/common/idmobilelib/ios/LocalizationObjectiveC.h b/common/idmobilelib/ios/LocalizationObjectiveC.h new file mode 100755 index 0000000..d401f98 --- /dev/null +++ b/common/idmobilelib/ios/LocalizationObjectiveC.h @@ -0,0 +1,39 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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. + + */ + +#ifndef idmobilelib_LocalizationObjectiveC_h +#define idmobilelib_LocalizationObjectiveC_h + +@class NSString; + +#ifdef __cplusplus +extern "C" { +#endif + +// If we already have an NSString localization key, we can use this function and avoid the +// overhead of the const char * <-> NSString * conversions. +NSString * idLocalization_GetNSString( NSString * key ); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/common/idmobilelib/ios/RenderContext.h b/common/idmobilelib/ios/RenderContext.h new file mode 100755 index 0000000..81070f8 --- /dev/null +++ b/common/idmobilelib/ios/RenderContext.h @@ -0,0 +1,70 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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. + + */ + +#ifndef IDMOBILELIB_RENDER_CONTEXT_H +#define IDMOBILELIB_RENDER_CONTEXT_H + +#if defined(__OBJC__) && defined(__cplusplus) + +#import +#include +#include +#import +#import + + +class idRenderContext { +public: + + idRenderContext(); + virtual ~idRenderContext(); + + void Initialize( EAGLRenderingAPI apiVersion, EAGLSharegroup * sharegroup ); + void InitFrameBuffer( CAEAGLLayer * layer ); + + void Begin(); + void End(); + + void SetActiveContext(); + void SwapBuffers(); + + void SetContextWidth( int width ); + void SetContextHeight( int height ); + + int GetContextWidth() const { return mWidth; } + int GetContextHeight() const { return mHeight; } + EAGLSharegroup * GetShareGroup() { return [mEAGLContext sharegroup]; } + +protected: + + GLuint mViewRenderbuffer; + GLuint mViewFramebuffer; + GLuint mDepthRenderbuffer; + + EAGLContext *mEAGLContext; + + int mWidth; + int mHeight; + +}; + +#endif + +#endif // _RENDER_CONTEXT_H diff --git a/common/idmobilelib/ios/RenderContext.mm b/common/idmobilelib/ios/RenderContext.mm new file mode 100755 index 0000000..d10daaf --- /dev/null +++ b/common/idmobilelib/ios/RenderContext.mm @@ -0,0 +1,174 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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 "RenderContext.h" + +/* + ========================================= + idRenderContext::idRenderContext + ========================================= + */ +idRenderContext::idRenderContext() : +mViewRenderbuffer( 0 ), +mViewFramebuffer( 0 ), +mDepthRenderbuffer( 0 ), +mEAGLContext( NULL ) { + + mWidth = 0; + mHeight = 0; +} + +/* + ========================================= + idRenderContext::Initialize + ========================================= + */ +void idRenderContext::Initialize( EAGLRenderingAPI apiVersion, EAGLSharegroup * sharegroup ) { + + // Allocate and initialize the Rendering context for this view. + if( sharegroup == NULL ) { + mEAGLContext = [[EAGLContext alloc] initWithAPI:apiVersion]; + } else { + + mEAGLContext = [[EAGLContext alloc] initWithAPI:apiVersion sharegroup: sharegroup]; + } + + assert( mEAGLContext ); + assert( [mEAGLContext API] == apiVersion ); + + SetActiveContext(); +} + +/* + ========================================= + idRenderContext::~idRenderContext + ========================================= + */ +idRenderContext::~idRenderContext() { + + glDeleteFramebuffersOES( 1, &mViewFramebuffer ); + mViewFramebuffer = 0; + glDeleteRenderbuffersOES( 1, &mViewRenderbuffer ); + mViewRenderbuffer = 0; + glDeleteRenderbuffersOES( 1, &mDepthRenderbuffer ); + mDepthRenderbuffer = 0; + + [ mEAGLContext release ]; +} + +/* + ========================================= + idRenderContext::SetActiveContext + ========================================= + */ +void idRenderContext::SetActiveContext() { + + if ( ![EAGLContext setCurrentContext:mEAGLContext]) { + assert( 0 ); + return; + } + +} + +/* + ========================================= + idRenderContext::SwapBuffers + ========================================= + */ +void idRenderContext::SwapBuffers() { + + glBindRenderbufferOES(GL_RENDERBUFFER_OES, mViewRenderbuffer); + + // present the renderbuffer for display + [mEAGLContext presentRenderbuffer:GL_RENDERBUFFER_OES]; + +} + +/* + ========================================= + idRenderContext::RenderBufferStorage + ========================================= + */ +void idRenderContext::InitFrameBuffer( CAEAGLLayer * layer ) { + + + glDeleteFramebuffersOES( 1, &mViewFramebuffer ); + mViewFramebuffer = 0; + glDeleteRenderbuffersOES( 1, &mViewRenderbuffer ); + mViewRenderbuffer = 0; + glDeleteRenderbuffersOES( 1, &mDepthRenderbuffer ); + mDepthRenderbuffer = 0; + + glGenFramebuffersOES(1, &mViewFramebuffer); + glBindFramebufferOES(GL_FRAMEBUFFER_OES, mViewFramebuffer); + + glGenRenderbuffersOES(1, &mViewRenderbuffer); + glBindRenderbufferOES(GL_RENDERBUFFER_OES, mViewRenderbuffer); + + [mEAGLContext renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:layer]; + + // the backing sizes should be the same as the screen + glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &mWidth); + glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &mHeight); + + glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, mViewRenderbuffer); + + glGenRenderbuffersOES(1, &mDepthRenderbuffer); + glBindRenderbufferOES(GL_RENDERBUFFER_OES, mDepthRenderbuffer); + glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, mWidth, mHeight); + glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, mDepthRenderbuffer); + + // the framebuffer will stay constant + glBindRenderbufferOES(GL_RENDERBUFFER_OES, mViewRenderbuffer); + glBindFramebufferOES(GL_FRAMEBUFFER_OES, mViewFramebuffer); + + + if ( glCheckFramebufferStatusOES( GL_FRAMEBUFFER_OES ) != GL_FRAMEBUFFER_COMPLETE_OES ) { + assert( 0 ); + } + +} + +/* + ========================================= + idRenderContext::Begin + ========================================= + */ +void idRenderContext::Begin() { + + SetActiveContext(); + + // Clear the Buffer to begin for a new Frame. + //GL_Clear( true, true, false ); + + // Set the Viewport for our Context. + // GL_Viewport( 0, 0, mWidth, mHeight ); + +} + +/* + ========================================= + idRenderContext::End + ========================================= + */ +void idRenderContext::End() { + + SwapBuffers(); +} diff --git a/common/idmobilelib/ios/Slider.h b/common/idmobilelib/ios/Slider.h new file mode 100755 index 0000000..fab0831 --- /dev/null +++ b/common/idmobilelib/ios/Slider.h @@ -0,0 +1,33 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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. + + */ +#import +#import + + +@interface idSlider : UISlider { + + +} + +- (void) CustomizeSlider:( UIImage* )minimumImage + :( UIImage* )maximumImage + :( UIImage* )thumbImage; + +@end diff --git a/common/idmobilelib/ios/Slider.mm b/common/idmobilelib/ios/Slider.mm new file mode 100755 index 0000000..fc776d5 --- /dev/null +++ b/common/idmobilelib/ios/Slider.mm @@ -0,0 +1,52 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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. + + */ + +#import "Slider.h" + + +@implementation idSlider + + + + +/* + ======================== + CustomizeSlider + ======================== + */ +- (void) CustomizeSlider:( UIImage* )minimumImage + :( UIImage* )maximumImage + :( UIImage* )thumbImage { + + minimumImage = nil; + maximumImage = nil; + + //[ self setMinimumTrackImage:minimumImage forState:UIControlStateNormal ]; + //[ self setMaximumTrackImage:maximumImage forState:UIControlStateNormal ]; + + [ self setThumbImage:thumbImage forState:UIControlStateNormal ]; + [ self setThumbImage:thumbImage forState:UIControlStateHighlighted ]; + +} + + + + +@end diff --git a/common/idmobilelib/ios/Switch.h b/common/idmobilelib/ios/Switch.h new file mode 100755 index 0000000..44eb71a --- /dev/null +++ b/common/idmobilelib/ios/Switch.h @@ -0,0 +1,31 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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. + + */ + +#import +#import + + +@interface idSwitch : UIButton { + BOOL on; +} + +@property(nonatomic,getter=isOn) BOOL on; + +@end diff --git a/common/idmobilelib/ios/Switch.mm b/common/idmobilelib/ios/Switch.mm new file mode 100755 index 0000000..262e6cd --- /dev/null +++ b/common/idmobilelib/ios/Switch.mm @@ -0,0 +1,79 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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. + + */ + +#import "Switch.h" + + +@implementation idSwitch + +@synthesize on; + +/* + ======================== + setOn + ======================== + */ +- (void)setOn:(BOOL)turnOn +{ + on = turnOn; + + if (on) + { + [ self setHighlighted: YES ]; + } + else + { + [ self setHighlighted: NO ]; + } +} + +/* + ======================== + touchesBegan + ======================== + */ +- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event +{ + [super touchesBegan:touches withEvent:event]; + [self setOn: !on ]; + +} + + +/* + ======================== + touchesEnded + ======================== + */ +- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event +{ + [super touchesEnded:touches withEvent:event]; + + if (on) + { + [ self setHighlighted: YES ]; + } + else + { + [ self setHighlighted: NO ]; + } +} + +@end diff --git a/common/idmobilelib/ios/View.h b/common/idmobilelib/ios/View.h new file mode 100755 index 0000000..d970965 --- /dev/null +++ b/common/idmobilelib/ios/View.h @@ -0,0 +1,49 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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. + + */ + +#ifndef IDMOBILELIB_VIEW_H +#define IDMOBILELIB_VIEW_H + +#import +#import +#import +#import +#include "RenderContext.h" + +/* + ================================================ + idView + + Standard Objective C OpenGL UIView Class + ================================================ + */ +@interface idView : UIView { +@public + idRenderContext mRenderContext; + +} +extern idView * gMainView; + +- (void) Initialize; +- (void) EndFrame; + +@end + +#endif diff --git a/common/idmobilelib/ios/View.mm b/common/idmobilelib/ios/View.mm new file mode 100755 index 0000000..50d8134 --- /dev/null +++ b/common/idmobilelib/ios/View.mm @@ -0,0 +1,165 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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. + + */ + +#import "View.h" + +/* + ================================================ + idView + + Standard Objective C UIView Class + ================================================ + */ + +idView * gMainView; // global openGL View. + +@implementation idView + +/* + ================================== + idView::layerClass + ================================== + */ ++ (Class) layerClass +{ + return [CAEAGLLayer class]; +} + +/* + ================================== + idView::initWithCoder + ================================== + */ +- (id) initWithCoder:(NSCoder *)aCoder{ + + if ( ( self = [super initWithCoder:aCoder] ) ) { + [self Initialize]; + } + + return self; +} + +/* + ================================== + idView::initWithFrame + ================================== + */ +- (id) initWithFrame:(CGRect)rect{ + if ( ( self = [super initWithFrame:rect] ) ) { + [self Initialize]; + } + return self; +} + +/* + ================================== + idView::handleTouches + ================================== + */ +- (void) handleTouches:(UIEvent*)event { + (void)event; +} + + +/* + ================================== + idView::touchesBegan + ================================== +*/ +- (void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event { + (void)touches; + + [self handleTouches:event]; +} + +/* + ================================== + idView::touchesMoved + ================================== +*/ +- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { + (void)touches; + + [self handleTouches:event]; +} + +/* + ================================== + idView::touchesEnded + ================================== +*/ +- (void) touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event { + + (void)touches; + + [self handleTouches:event]; +} + +/* + ================================== + idView::touchesCancelled + ================================== + */ +- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { + + (void)touches; + + [self handleTouches:event]; +} + +/* + ================================== + idView::Initialize + ================================== + */ +- (void) Initialize { + + self.multipleTouchEnabled = YES; + gMainView = self; + + // Double the resolution on iPhone 4. + [self setContentScaleFactor:[UIScreen mainScreen].scale]; + + // Get the layer for this view + CAEAGLLayer *glLayer = (CAEAGLLayer *)self.layer; + glLayer.opaque = TRUE; + glLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithBool:FALSE], kEAGLDrawablePropertyRetainedBacking, + kEAGLColorFormatRGB565, + kEAGLDrawablePropertyColorFormat, nil]; + + // Create Our Render Context. + mRenderContext.Initialize( kEAGLRenderingAPIOpenGLES1, NULL ); + + // Create our Frame Buffers. + mRenderContext.InitFrameBuffer( glLayer ); +} + +/* + ================================== + idView::EndFrame + ================================== + */ +- (void) EndFrame { + + mRenderContext.SwapBuffers(); +} + +@end diff --git a/common/idmobilelib/ios/idmobilelib.xcodeproj/project.pbxproj b/common/idmobilelib/ios/idmobilelib.xcodeproj/project.pbxproj new file mode 100755 index 0000000..f4d0bde --- /dev/null +++ b/common/idmobilelib/ios/idmobilelib.xcodeproj/project.pbxproj @@ -0,0 +1,432 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 3D7D557F14D21FEC00A0F1FF /* ios_interface.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D7D557E14D21FEC00A0F1FF /* ios_interface.h */; }; + 3D7D558214D2201E00A0F1FF /* ios_interface.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3D7D558114D2201E00A0F1FF /* ios_interface.mm */; }; + 3D80884B14928766002D6CC3 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3D80884A14928766002D6CC3 /* Foundation.framework */; }; + 3D80885E149287EB002D6CC3 /* GameCenter.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D80885D149287EB002D6CC3 /* GameCenter.h */; }; + 3D80886D14928AED002D6CC3 /* GameCenter.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3D80886C14928AED002D6CC3 /* GameCenter.mm */; }; + 3D80886F14928C16002D6CC3 /* GameKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3D80886E14928C16002D6CC3 /* GameKit.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; + 3D8088721492B362002D6CC3 /* sys_defines.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D8088711492B362002D6CC3 /* sys_defines.h */; }; + 3D8088741492CA59002D6CC3 /* objectivec_utilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D8088731492CA59002D6CC3 /* objectivec_utilities.h */; }; + 3D8088761492CBCB002D6CC3 /* objectivec_utilities.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3D8088751492CBCB002D6CC3 /* objectivec_utilities.mm */; }; + 3DCB047B1498279D00E986AF /* LocalizationObjectiveC.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DCB04781498279D00E986AF /* LocalizationObjectiveC.h */; }; + C8011C8D14C0EB7A007AC5C5 /* InAppStore.h in Headers */ = {isa = PBXBuildFile; fileRef = C8011C8B14C0EB7A007AC5C5 /* InAppStore.h */; }; + C8011C8E14C0EB7A007AC5C5 /* InAppStore.mm in Sources */ = {isa = PBXBuildFile; fileRef = C8011C8C14C0EB7A007AC5C5 /* InAppStore.mm */; }; + C8011C9414C0EC70007AC5C5 /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C8011C9314C0EC70007AC5C5 /* StoreKit.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; + C8012E5F14B61D4900B0E213 /* AnimatedImage.h in Headers */ = {isa = PBXBuildFile; fileRef = C8012E5314B61D4900B0E213 /* AnimatedImage.h */; }; + C8012E6014B61D4900B0E213 /* AnimatedImage.mm in Sources */ = {isa = PBXBuildFile; fileRef = C8012E5414B61D4900B0E213 /* AnimatedImage.mm */; }; + C8012E6114B61D4900B0E213 /* Carousel.h in Headers */ = {isa = PBXBuildFile; fileRef = C8012E5514B61D4900B0E213 /* Carousel.h */; }; + C8012E6214B61D4900B0E213 /* Carousel.mm in Sources */ = {isa = PBXBuildFile; fileRef = C8012E5614B61D4900B0E213 /* Carousel.mm */; }; + C8012E6314B61D4900B0E213 /* Label.h in Headers */ = {isa = PBXBuildFile; fileRef = C8012E5714B61D4900B0E213 /* Label.h */; }; + C8012E6414B61D4900B0E213 /* Label.mm in Sources */ = {isa = PBXBuildFile; fileRef = C8012E5814B61D4900B0E213 /* Label.mm */; }; + C8012E6514B61D4900B0E213 /* LabelButton.h in Headers */ = {isa = PBXBuildFile; fileRef = C8012E5914B61D4900B0E213 /* LabelButton.h */; }; + C8012E6614B61D4900B0E213 /* LabelButton.mm in Sources */ = {isa = PBXBuildFile; fileRef = C8012E5A14B61D4900B0E213 /* LabelButton.mm */; }; + C8012E6714B61D4900B0E213 /* Slider.h in Headers */ = {isa = PBXBuildFile; fileRef = C8012E5B14B61D4900B0E213 /* Slider.h */; }; + C8012E6814B61D4900B0E213 /* Slider.mm in Sources */ = {isa = PBXBuildFile; fileRef = C8012E5C14B61D4900B0E213 /* Slider.mm */; }; + C8012E6914B61D4900B0E213 /* Switch.h in Headers */ = {isa = PBXBuildFile; fileRef = C8012E5D14B61D4900B0E213 /* Switch.h */; }; + C8012E6A14B61D4900B0E213 /* Switch.mm in Sources */ = {isa = PBXBuildFile; fileRef = C8012E5E14B61D4900B0E213 /* Switch.mm */; }; + C8A6294514969EEE002EF3F5 /* Localization.h in Headers */ = {isa = PBXBuildFile; fileRef = C8A6294414969EEE002EF3F5 /* Localization.h */; }; + C8A6294814969F07002EF3F5 /* Localization.mm in Sources */ = {isa = PBXBuildFile; fileRef = C8A6294714969F07002EF3F5 /* Localization.mm */; }; + C8A629611497F318002EF3F5 /* View.mm in Sources */ = {isa = PBXBuildFile; fileRef = C8A629601497F318002EF3F5 /* View.mm */; }; + C8A629631497F329002EF3F5 /* View.h in Headers */ = {isa = PBXBuildFile; fileRef = C8A629621497F329002EF3F5 /* View.h */; }; + C8A629651497F509002EF3F5 /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C8A629641497F508002EF3F5 /* OpenGLES.framework */; }; + C8A629671497F510002EF3F5 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C8A629661497F510002EF3F5 /* QuartzCore.framework */; }; + C8A6296914980C5B002EF3F5 /* RenderContext.h in Headers */ = {isa = PBXBuildFile; fileRef = C8A6296814980C5B002EF3F5 /* RenderContext.h */; }; + C8A6296B14980C6E002EF3F5 /* RenderContext.mm in Sources */ = {isa = PBXBuildFile; fileRef = C8A6296A14980C6E002EF3F5 /* RenderContext.mm */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 3D7D557E14D21FEC00A0F1FF /* ios_interface.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ios_interface.h; sourceTree = ""; }; + 3D7D558114D2201E00A0F1FF /* ios_interface.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ios_interface.mm; sourceTree = ""; }; + 3D80884714928766002D6CC3 /* libidmobilelib.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libidmobilelib.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 3D80884A14928766002D6CC3 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 3D80885D149287EB002D6CC3 /* GameCenter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GameCenter.h; sourceTree = ""; }; + 3D80886C14928AED002D6CC3 /* GameCenter.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = GameCenter.mm; sourceTree = ""; }; + 3D80886E14928C16002D6CC3 /* GameKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GameKit.framework; path = System/Library/Frameworks/GameKit.framework; sourceTree = SDKROOT; }; + 3D8088711492B362002D6CC3 /* sys_defines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sys_defines.h; path = ../sys/sys_defines.h; sourceTree = ""; }; + 3D8088731492CA59002D6CC3 /* objectivec_utilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = objectivec_utilities.h; sourceTree = ""; }; + 3D8088751492CBCB002D6CC3 /* objectivec_utilities.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = objectivec_utilities.mm; sourceTree = ""; }; + 3DCB04781498279D00E986AF /* LocalizationObjectiveC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LocalizationObjectiveC.h; sourceTree = ""; }; + C8011C8B14C0EB7A007AC5C5 /* InAppStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InAppStore.h; sourceTree = ""; }; + C8011C8C14C0EB7A007AC5C5 /* InAppStore.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = InAppStore.mm; sourceTree = ""; }; + C8011C9314C0EC70007AC5C5 /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; }; + C8012E5314B61D4900B0E213 /* AnimatedImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AnimatedImage.h; sourceTree = ""; }; + C8012E5414B61D4900B0E213 /* AnimatedImage.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AnimatedImage.mm; sourceTree = ""; }; + C8012E5514B61D4900B0E213 /* Carousel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Carousel.h; sourceTree = ""; }; + C8012E5614B61D4900B0E213 /* Carousel.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = Carousel.mm; sourceTree = ""; }; + C8012E5714B61D4900B0E213 /* Label.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Label.h; sourceTree = ""; }; + C8012E5814B61D4900B0E213 /* Label.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = Label.mm; sourceTree = ""; }; + C8012E5914B61D4900B0E213 /* LabelButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LabelButton.h; sourceTree = ""; }; + C8012E5A14B61D4900B0E213 /* LabelButton.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = LabelButton.mm; sourceTree = ""; }; + C8012E5B14B61D4900B0E213 /* Slider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Slider.h; sourceTree = ""; }; + C8012E5C14B61D4900B0E213 /* Slider.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = Slider.mm; sourceTree = ""; }; + C8012E5D14B61D4900B0E213 /* Switch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Switch.h; sourceTree = ""; }; + C8012E5E14B61D4900B0E213 /* Switch.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = Switch.mm; sourceTree = ""; }; + C8A6294414969EEE002EF3F5 /* Localization.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Localization.h; sourceTree = ""; }; + C8A6294714969F07002EF3F5 /* Localization.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = Localization.mm; sourceTree = ""; }; + C8A629601497F318002EF3F5 /* View.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = View.mm; sourceTree = ""; }; + C8A629621497F329002EF3F5 /* View.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = View.h; sourceTree = ""; }; + C8A629641497F508002EF3F5 /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = System/Library/Frameworks/OpenGLES.framework; sourceTree = SDKROOT; }; + C8A629661497F510002EF3F5 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; + C8A6296814980C5B002EF3F5 /* RenderContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RenderContext.h; sourceTree = ""; }; + C8A6296A14980C6E002EF3F5 /* RenderContext.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = RenderContext.mm; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 3D80884414928766002D6CC3 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + C8011C9414C0EC70007AC5C5 /* StoreKit.framework in Frameworks */, + C8A629671497F510002EF3F5 /* QuartzCore.framework in Frameworks */, + C8A629651497F509002EF3F5 /* OpenGLES.framework in Frameworks */, + 3D80886F14928C16002D6CC3 /* GameKit.framework in Frameworks */, + 3D80884B14928766002D6CC3 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 3D80883C14928766002D6CC3 = { + isa = PBXGroup; + children = ( + 3D80885714928798002D6CC3 /* idmobilelib */, + 3D80884914928766002D6CC3 /* Frameworks */, + 3D80884814928766002D6CC3 /* Products */, + ); + sourceTree = ""; + }; + 3D80884814928766002D6CC3 /* Products */ = { + isa = PBXGroup; + children = ( + 3D80884714928766002D6CC3 /* libidmobilelib.a */, + ); + name = Products; + sourceTree = ""; + }; + 3D80884914928766002D6CC3 /* Frameworks */ = { + isa = PBXGroup; + children = ( + C8011C9314C0EC70007AC5C5 /* StoreKit.framework */, + C8A629661497F510002EF3F5 /* QuartzCore.framework */, + C8A629641497F508002EF3F5 /* OpenGLES.framework */, + 3D80884A14928766002D6CC3 /* Foundation.framework */, + 3D80886E14928C16002D6CC3 /* GameKit.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 3D80885714928798002D6CC3 /* idmobilelib */ = { + isa = PBXGroup; + children = ( + 3D808858149287A1002D6CC3 /* ios */, + 3D8088701492B34E002D6CC3 /* sys */, + ); + name = idmobilelib; + sourceTree = ""; + }; + 3D808858149287A1002D6CC3 /* ios */ = { + isa = PBXGroup; + children = ( + C8A6295E1497F2A6002EF3F5 /* Interface Builder */, + 3D80885D149287EB002D6CC3 /* GameCenter.h */, + 3D80886C14928AED002D6CC3 /* GameCenter.mm */, + 3D8088731492CA59002D6CC3 /* objectivec_utilities.h */, + 3D8088751492CBCB002D6CC3 /* objectivec_utilities.mm */, + C8A6294414969EEE002EF3F5 /* Localization.h */, + C8A6294714969F07002EF3F5 /* Localization.mm */, + 3DCB04781498279D00E986AF /* LocalizationObjectiveC.h */, + C8A6296814980C5B002EF3F5 /* RenderContext.h */, + C8A6296A14980C6E002EF3F5 /* RenderContext.mm */, + C8011C8B14C0EB7A007AC5C5 /* InAppStore.h */, + C8011C8C14C0EB7A007AC5C5 /* InAppStore.mm */, + 3D7D557E14D21FEC00A0F1FF /* ios_interface.h */, + 3D7D558114D2201E00A0F1FF /* ios_interface.mm */, + ); + name = ios; + sourceTree = ""; + }; + 3D8088701492B34E002D6CC3 /* sys */ = { + isa = PBXGroup; + children = ( + 3D8088711492B362002D6CC3 /* sys_defines.h */, + ); + name = sys; + sourceTree = ""; + }; + C8A6295E1497F2A6002EF3F5 /* Interface Builder */ = { + isa = PBXGroup; + children = ( + C8012E5314B61D4900B0E213 /* AnimatedImage.h */, + C8012E5414B61D4900B0E213 /* AnimatedImage.mm */, + C8012E5514B61D4900B0E213 /* Carousel.h */, + C8012E5614B61D4900B0E213 /* Carousel.mm */, + C8012E5714B61D4900B0E213 /* Label.h */, + C8012E5814B61D4900B0E213 /* Label.mm */, + C8012E5914B61D4900B0E213 /* LabelButton.h */, + C8012E5A14B61D4900B0E213 /* LabelButton.mm */, + C8012E5B14B61D4900B0E213 /* Slider.h */, + C8012E5C14B61D4900B0E213 /* Slider.mm */, + C8012E5D14B61D4900B0E213 /* Switch.h */, + C8012E5E14B61D4900B0E213 /* Switch.mm */, + C8A629621497F329002EF3F5 /* View.h */, + C8A629601497F318002EF3F5 /* View.mm */, + ); + name = "Interface Builder"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 3D80884514928766002D6CC3 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 3D80885E149287EB002D6CC3 /* GameCenter.h in Headers */, + 3D8088721492B362002D6CC3 /* sys_defines.h in Headers */, + 3D8088741492CA59002D6CC3 /* objectivec_utilities.h in Headers */, + C8A6294514969EEE002EF3F5 /* Localization.h in Headers */, + C8A629631497F329002EF3F5 /* View.h in Headers */, + C8A6296914980C5B002EF3F5 /* RenderContext.h in Headers */, + 3DCB047B1498279D00E986AF /* LocalizationObjectiveC.h in Headers */, + C8012E5F14B61D4900B0E213 /* AnimatedImage.h in Headers */, + C8012E6114B61D4900B0E213 /* Carousel.h in Headers */, + C8012E6314B61D4900B0E213 /* Label.h in Headers */, + C8012E6514B61D4900B0E213 /* LabelButton.h in Headers */, + C8012E6714B61D4900B0E213 /* Slider.h in Headers */, + C8012E6914B61D4900B0E213 /* Switch.h in Headers */, + C8011C8D14C0EB7A007AC5C5 /* InAppStore.h in Headers */, + 3D7D557F14D21FEC00A0F1FF /* ios_interface.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 3D80884614928766002D6CC3 /* idmobilelib */ = { + isa = PBXNativeTarget; + buildConfigurationList = 3D80885414928766002D6CC3 /* Build configuration list for PBXNativeTarget "idmobilelib" */; + buildPhases = ( + 3D80884314928766002D6CC3 /* Sources */, + 3D80884414928766002D6CC3 /* Frameworks */, + 3D80884514928766002D6CC3 /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = idmobilelib; + productName = idmobilelib; + productReference = 3D80884714928766002D6CC3 /* libidmobilelib.a */; + productType = "com.apple.product-type.library.static"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 3D80883E14928766002D6CC3 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0500; + }; + buildConfigurationList = 3D80884114928766002D6CC3 /* Build configuration list for PBXProject "idmobilelib" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 3D80883C14928766002D6CC3; + productRefGroup = 3D80884814928766002D6CC3 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 3D80884614928766002D6CC3 /* idmobilelib */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 3D80884314928766002D6CC3 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 3D80886D14928AED002D6CC3 /* GameCenter.mm in Sources */, + 3D8088761492CBCB002D6CC3 /* objectivec_utilities.mm in Sources */, + C8A6294814969F07002EF3F5 /* Localization.mm in Sources */, + C8A629611497F318002EF3F5 /* View.mm in Sources */, + C8A6296B14980C6E002EF3F5 /* RenderContext.mm in Sources */, + C8012E6014B61D4900B0E213 /* AnimatedImage.mm in Sources */, + C8012E6214B61D4900B0E213 /* Carousel.mm in Sources */, + C8012E6414B61D4900B0E213 /* Label.mm in Sources */, + C8012E6614B61D4900B0E213 /* LabelButton.mm in Sources */, + C8012E6814B61D4900B0E213 /* Slider.mm in Sources */, + C8012E6A14B61D4900B0E213 /* Switch.mm in Sources */, + C8011C8E14C0EB7A007AC5C5 /* InAppStore.mm in Sources */, + 3D7D558214D2201E00A0F1FF /* ios_interface.mm in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 3D80885214928766002D6CC3 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES; + CLANG_WARN_OBJCPP_ARC_ABI = YES; + CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES; + CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; + COPY_PHASE_STRIP = NO; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_THUMB_SUPPORT = NO; + GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; + GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES; + GCC_TREAT_WARNINGS_AS_ERRORS = YES; + GCC_VERSION = ""; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; + GCC_WARN_ABOUT_MISSING_NEWLINE = YES; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES; + GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES; + GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; + GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES; + GCC_WARN_PEDANTIC = YES; + GCC_WARN_PROTOTYPE_CONVERSION = YES; + GCC_WARN_SIGN_COMPARE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = NO; + GCC_WARN_UNKNOWN_PRAGMAS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_LABEL = YES; + GCC_WARN_UNUSED_PARAMETER = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 3.2; + ONLY_ACTIVE_ARCH = NO; + SDKROOT = iphoneos; + USER_HEADER_SEARCH_PATHS = ../; + WARNING_CFLAGS = ( + "-Wall", + "-Wextra", + "-pedantic-errors", + ); + }; + name = Debug; + }; + 3D80885314928766002D6CC3 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES; + CLANG_WARN_OBJCPP_ARC_ABI = YES; + CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES; + CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; + COPY_PHASE_STRIP = YES; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_PREPROCESSOR_DEFINITIONS = NDEBUG; + GCC_THUMB_SUPPORT = NO; + GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; + GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES; + GCC_TREAT_WARNINGS_AS_ERRORS = YES; + GCC_VERSION = ""; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; + GCC_WARN_ABOUT_MISSING_NEWLINE = YES; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES; + GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES; + GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; + GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES; + GCC_WARN_PEDANTIC = YES; + GCC_WARN_PROTOTYPE_CONVERSION = YES; + GCC_WARN_SIGN_COMPARE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNKNOWN_PRAGMAS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_LABEL = YES; + GCC_WARN_UNUSED_PARAMETER = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 3.2; + SDKROOT = iphoneos; + USER_HEADER_SEARCH_PATHS = ../; + VALIDATE_PRODUCT = YES; + WARNING_CFLAGS = ( + "-Wall", + "-Wextra", + "-pedantic-errors", + ); + }; + name = Release; + }; + 3D80885514928766002D6CC3 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + DSTROOT = /tmp/idmobilelib.dst; + GCC_VERSION = ""; + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + USE_HEADERMAP = NO; + }; + name = Debug; + }; + 3D80885614928766002D6CC3 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + DSTROOT = /tmp/idmobilelib.dst; + GCC_VERSION = ""; + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + USE_HEADERMAP = NO; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 3D80884114928766002D6CC3 /* Build configuration list for PBXProject "idmobilelib" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 3D80885214928766002D6CC3 /* Debug */, + 3D80885314928766002D6CC3 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 3D80885414928766002D6CC3 /* Build configuration list for PBXNativeTarget "idmobilelib" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 3D80885514928766002D6CC3 /* Debug */, + 3D80885614928766002D6CC3 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 3D80883E14928766002D6CC3 /* Project object */; +} diff --git a/common/idmobilelib/ios/idmobilelib.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/common/idmobilelib/ios/idmobilelib.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100755 index 0000000..70c8c12 --- /dev/null +++ b/common/idmobilelib/ios/idmobilelib.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/common/idmobilelib/ios/idmobilelib.xcodeproj/xcshareddata/xcschemes/idmobilelib.xcscheme b/common/idmobilelib/ios/idmobilelib.xcodeproj/xcshareddata/xcschemes/idmobilelib.xcscheme new file mode 100755 index 0000000..a68fc4d --- /dev/null +++ b/common/idmobilelib/ios/idmobilelib.xcodeproj/xcshareddata/xcschemes/idmobilelib.xcscheme @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/common/idmobilelib/ios/idmobilelib.xcodeproj/xcuserdata/Farrand.xcuserdatad/xcschemes/xcschememanagement.plist b/common/idmobilelib/ios/idmobilelib.xcodeproj/xcuserdata/Farrand.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..e962236 --- /dev/null +++ b/common/idmobilelib/ios/idmobilelib.xcodeproj/xcuserdata/Farrand.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,14 @@ + + + + + SuppressBuildableAutocreation + + 3D80884614928766002D6CC3 + + primary + + + + + diff --git a/common/idmobilelib/ios/idmobilelib.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/xcschememanagement.plist b/common/idmobilelib/ios/idmobilelib.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100755 index 0000000..8866191 --- /dev/null +++ b/common/idmobilelib/ios/idmobilelib.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,24 @@ + + + + + SchemeUserState + + idmobilelib.xcscheme_^#shared#^_ + + isShown + + orderHint + 3 + + + SuppressBuildableAutocreation + + 3D80884614928766002D6CC3 + + primary + + + + + diff --git a/common/idmobilelib/ios/ios_interface.h b/common/idmobilelib/ios/ios_interface.h new file mode 100755 index 0000000..bb4fd5d --- /dev/null +++ b/common/idmobilelib/ios/ios_interface.h @@ -0,0 +1,28 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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. + + */ + +#ifndef idmobilelib_ios_interface_h +#define idmobilelib_ios_interface_h + +#include + +void ShowSystemAlert( const std::string & title, const std::string & message ) ; + +#endif diff --git a/common/idmobilelib/ios/ios_interface.mm b/common/idmobilelib/ios/ios_interface.mm new file mode 100755 index 0000000..d23da44 --- /dev/null +++ b/common/idmobilelib/ios/ios_interface.mm @@ -0,0 +1,42 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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 "ios_interface.h" +#import "objectivec_utilities.h" +#import "LocalizationObjectiveC.h" + +#import + +/* + ======================= + Shows the blue system alert box with localized text. + ======================= + */ +void ShowSystemAlert( const std::string & title, const std::string & message ) { + NSString * nsTitle = idLocalization_GetNSString( StdStringToNSString( title ) ); + NSString * nsMessage = idLocalization_GetNSString( StdStringToNSString( message ) ); + NSString * nsCancelButton = idLocalization_GetNSString( @"#OK" ); + + UIAlertView * alert = [[UIAlertView alloc] initWithTitle:nsTitle message:nsMessage delegate:nil cancelButtonTitle:nsCancelButton otherButtonTitles:nil]; + + [alert show]; + [alert release]; +} + diff --git a/common/idmobilelib/ios/objectivec_utilities.h b/common/idmobilelib/ios/objectivec_utilities.h new file mode 100755 index 0000000..10388df --- /dev/null +++ b/common/idmobilelib/ios/objectivec_utilities.h @@ -0,0 +1,47 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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. + + */ + + +/* +================================================================================================ + +This header collects miscellaneous utilities that automate certain tasks in +Objective-C programming. + +================================================================================================ +*/ + +#ifndef IDMOBILELIB_IOS_OBJECTIVEC_UTILITIES_H +#define IDMOBILELIB_IOS_OBJECTIVEC_UTILITIES_H + + +#include + +@class NSString; +@class NSError; + +std::string NSStringToStdString( NSString * toConvert ); +NSString * StdStringToNSString( const std::string & toConvert ); + + +void DisplayNSErrorMessage( NSString* title, NSError * error ); + + +#endif diff --git a/common/idmobilelib/ios/objectivec_utilities.mm b/common/idmobilelib/ios/objectivec_utilities.mm new file mode 100755 index 0000000..d87c9cc --- /dev/null +++ b/common/idmobilelib/ios/objectivec_utilities.mm @@ -0,0 +1,67 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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 "objectivec_utilities.h" +#include "LocalizationObjectiveC.h" + +#import +#import +#import + +/* +======================== +Copies an NSString object to a C++ string encoded in UTF8. +======================== +*/ +std::string NSStringToStdString( NSString * toConvert ) { + const char * cString = [toConvert cStringUsingEncoding:NSUTF8StringEncoding]; + return std::string( cString ); +} + +/* +======================== +Copies a C++ string encoded in UTF8 to an NSString object. +======================== +*/ +NSString * StdStringToNSString( const std::string & toConvert ) { + return [NSString stringWithCString:toConvert.c_str() encoding:NSUTF8StringEncoding]; +} + +/* +======================== +Disaplys a system alert with information about the given error. +======================== +*/ +void DisplayNSErrorMessage( NSString * title, NSError * error ) { + NSString *messageString = [error localizedDescription]; + NSString *reasonString = [error localizedFailureReason]; + + if ( reasonString != nil ) { + messageString = [NSString stringWithFormat:@"%@. %@", messageString, reasonString]; + } else { + messageString = [NSString stringWithFormat:@"%@", messageString]; + } + + UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:idLocalization_GetNSString( title ) + message:messageString delegate:nil + cancelButtonTitle:idLocalization_GetNSString(@"OK") otherButtonTitles:nil]; + [alertView show]; + [alertView release]; +} diff --git a/common/idmobilelib/sys/sys_defines.h b/common/idmobilelib/sys/sys_defines.h new file mode 100755 index 0000000..82aaaf2 --- /dev/null +++ b/common/idmobilelib/sys/sys_defines.h @@ -0,0 +1,44 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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. + + */ + + +#ifndef IDMOBILELIB_SYS_SYS_DEFINES_H +#define IDMOBILELIB_SYS_SYS_DEFINES_H + +/* +================================================================================================ + +Defines and macros usable in all code + +================================================================================================ +*/ + + +// A macro to disallow the copy constructor and operator= functions +// NOTE: The macro contains "private:" so all members defined after it will be private until +// public: or protected: is specified. +#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ +private: \ + TypeName(const TypeName&); \ + TypeName& operator=(const TypeName&) + + + +#endif diff --git a/common/ios/EmbeddedAudioSynthesis/EmbeddedAudioSynthesis.xcodeproj/project.pbxproj b/common/ios/EmbeddedAudioSynthesis/EmbeddedAudioSynthesis.xcodeproj/project.pbxproj new file mode 100755 index 0000000..42e3c39 --- /dev/null +++ b/common/ios/EmbeddedAudioSynthesis/EmbeddedAudioSynthesis.xcodeproj/project.pbxproj @@ -0,0 +1,612 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 3DC1C7D814B6252E00680D02 /* eas.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C6A614B6252D00680D02 /* eas.h */; }; + 3DC1C7D914B6252E00680D02 /* eas_build.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C6A714B6252D00680D02 /* eas_build.h */; }; + 3DC1C7DA14B6252E00680D02 /* eas_chorus.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C6A814B6252D00680D02 /* eas_chorus.h */; }; + 3DC1C7DB14B6252E00680D02 /* eas_config.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C6A914B6252D00680D02 /* eas_config.c */; }; + 3DC1C7DC14B6252E00680D02 /* eas_config.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C6AA14B6252D00680D02 /* eas_config.h */; }; + 3DC1C7DD14B6252E00680D02 /* eas_debugmsgs.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C6AB14B6252D00680D02 /* eas_debugmsgs.h */; }; + 3DC1C7DE14B6252E00680D02 /* eas_host.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C6AC14B6252D00680D02 /* eas_host.h */; }; + 3DC1C7DF14B6252E00680D02 /* eas_hostmm.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C6AD14B6252D00680D02 /* eas_hostmm.c */; }; + 3DC1C7E114B6252E00680D02 /* eas_report.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C6AF14B6252D00680D02 /* eas_report.c */; }; + 3DC1C7E214B6252E00680D02 /* eas_report.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C6B014B6252D00680D02 /* eas_report.h */; }; + 3DC1C7E314B6252E00680D02 /* eas_reverb.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C6B114B6252D00680D02 /* eas_reverb.h */; }; + 3DC1C7E414B6252E00680D02 /* eas_types.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C6B214B6252D00680D02 /* eas_types.h */; }; + 3DC1C7E514B6252E00680D02 /* eas_wave.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C6B314B6252D00680D02 /* eas_wave.c */; }; + 3DC1C7E614B6252E00680D02 /* eas_wave.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C6B414B6252D00680D02 /* eas_wave.h */; }; + 3DC1C7E714B6252E00680D02 /* jet.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C6B514B6252D00680D02 /* jet.h */; }; + 3DC1C7F614B6252E00680D02 /* dls.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C6CF14B6252D00680D02 /* dls.h */; }; + 3DC1C7F714B6252E00680D02 /* dls2.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C6D014B6252D00680D02 /* dls2.h */; }; + 3DC1C7F814B6252E00680D02 /* eas_audioconst.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C6D114B6252D00680D02 /* eas_audioconst.h */; }; + 3DC1C7F914B6252E00680D02 /* eas_chorus.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C6D214B6252D00680D02 /* eas_chorus.c */; }; + 3DC1C7FA14B6252E00680D02 /* eas_chorusdata.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C6D314B6252D00680D02 /* eas_chorusdata.c */; }; + 3DC1C7FB14B6252E00680D02 /* eas_chorusdata.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C6D414B6252D00680D02 /* eas_chorusdata.h */; }; + 3DC1C7FC14B6252E00680D02 /* eas_ctype.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C6D514B6252D00680D02 /* eas_ctype.h */; }; + 3DC1C7FD14B6252E00680D02 /* eas_data.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C6D614B6252D00680D02 /* eas_data.c */; }; + 3DC1C7FE14B6252E00680D02 /* eas_data.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C6D714B6252D00680D02 /* eas_data.h */; }; + 3DC1C80014B6252E00680D02 /* eas_dlssynth.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C6D914B6252D00680D02 /* eas_dlssynth.h */; }; + 3DC1C80114B6252E00680D02 /* eas_effects.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C6DA14B6252D00680D02 /* eas_effects.h */; }; + 3DC1C80214B6252E00680D02 /* eas_flog.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C6DB14B6252D00680D02 /* eas_flog.c */; }; + 3DC1C80314B6252E00680D02 /* eas_ima_tables.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C6DC14B6252D00680D02 /* eas_ima_tables.c */; }; + 3DC1C80414B6252E00680D02 /* eas_imaadpcm.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C6DD14B6252D00680D02 /* eas_imaadpcm.c */; }; + 3DC1C80514B6252E00680D02 /* eas_imelody.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C6DE14B6252D00680D02 /* eas_imelody.c */; }; + 3DC1C80614B6252E00680D02 /* eas_imelodydata.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C6DF14B6252D00680D02 /* eas_imelodydata.c */; }; + 3DC1C80714B6252E00680D02 /* eas_imelodydata.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C6E014B6252D00680D02 /* eas_imelodydata.h */; }; + 3DC1C80814B6252E00680D02 /* eas_math.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C6E114B6252D00680D02 /* eas_math.c */; }; + 3DC1C80914B6252E00680D02 /* eas_math.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C6E214B6252D00680D02 /* eas_math.h */; }; + 3DC1C80B14B6252E00680D02 /* eas_mdls.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C6E414B6252D00680D02 /* eas_mdls.h */; }; + 3DC1C80C14B6252E00680D02 /* eas_midi.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C6E514B6252D00680D02 /* eas_midi.c */; }; + 3DC1C80D14B6252E00680D02 /* eas_midi.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C6E614B6252D00680D02 /* eas_midi.h */; }; + 3DC1C80E14B6252E00680D02 /* eas_midictrl.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C6E714B6252D00680D02 /* eas_midictrl.h */; }; + 3DC1C80F14B6252E00680D02 /* eas_mididata.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C6E814B6252D00680D02 /* eas_mididata.c */; }; + 3DC1C81014B6252E00680D02 /* eas_miditypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C6E914B6252D00680D02 /* eas_miditypes.h */; }; + 3DC1C81114B6252E00680D02 /* eas_mixbuf.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C6EA14B6252D00680D02 /* eas_mixbuf.c */; }; + 3DC1C81214B6252E00680D02 /* eas_mixer.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C6EB14B6252D00680D02 /* eas_mixer.c */; }; + 3DC1C81314B6252E00680D02 /* eas_mixer.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C6EC14B6252D00680D02 /* eas_mixer.h */; }; + 3DC1C81414B6252E00680D02 /* eas_ota.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C6ED14B6252D00680D02 /* eas_ota.c */; }; + 3DC1C81514B6252E00680D02 /* eas_otadata.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C6EE14B6252D00680D02 /* eas_otadata.c */; }; + 3DC1C81614B6252E00680D02 /* eas_otadata.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C6EF14B6252D00680D02 /* eas_otadata.h */; }; + 3DC1C81714B6252E00680D02 /* eas_pan.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C6F014B6252D00680D02 /* eas_pan.c */; }; + 3DC1C81814B6252E00680D02 /* eas_pan.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C6F114B6252D00680D02 /* eas_pan.h */; }; + 3DC1C81914B6252E00680D02 /* eas_parser.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C6F214B6252D00680D02 /* eas_parser.h */; }; + 3DC1C81A14B6252E00680D02 /* eas_pcm.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C6F314B6252D00680D02 /* eas_pcm.c */; }; + 3DC1C81B14B6252E00680D02 /* eas_pcm.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C6F414B6252D00680D02 /* eas_pcm.h */; }; + 3DC1C81C14B6252E00680D02 /* eas_pcmdata.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C6F514B6252D00680D02 /* eas_pcmdata.c */; }; + 3DC1C81D14B6252E00680D02 /* eas_pcmdata.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C6F614B6252D00680D02 /* eas_pcmdata.h */; }; + 3DC1C81E14B6252E00680D02 /* eas_public.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C6F714B6252D00680D02 /* eas_public.c */; }; + 3DC1C81F14B6252E00680D02 /* eas_reverb.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C6F814B6252D00680D02 /* eas_reverb.c */; }; + 3DC1C82014B6252E00680D02 /* eas_reverbdata.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C6F914B6252D00680D02 /* eas_reverbdata.c */; }; + 3DC1C82114B6252E00680D02 /* eas_reverbdata.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C6FA14B6252D00680D02 /* eas_reverbdata.h */; }; + 3DC1C82214B6252E00680D02 /* eas_rtttl.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C6FB14B6252D00680D02 /* eas_rtttl.c */; }; + 3DC1C82314B6252E00680D02 /* eas_rtttldata.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C6FC14B6252D00680D02 /* eas_rtttldata.c */; }; + 3DC1C82414B6252E00680D02 /* eas_rtttldata.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C6FD14B6252D00680D02 /* eas_rtttldata.h */; }; + 3DC1C82514B6252E00680D02 /* eas_smf.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C6FE14B6252D00680D02 /* eas_smf.c */; }; + 3DC1C82614B6252E00680D02 /* eas_smf.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C6FF14B6252D00680D02 /* eas_smf.h */; }; + 3DC1C82714B6252E00680D02 /* eas_smfdata.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C70014B6252D00680D02 /* eas_smfdata.c */; }; + 3DC1C82814B6252E00680D02 /* eas_smfdata.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C70114B6252D00680D02 /* eas_smfdata.h */; }; + 3DC1C82914B6252E00680D02 /* eas_sndlib.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C70214B6252D00680D02 /* eas_sndlib.h */; }; + 3DC1C82A14B6252E00680D02 /* eas_synth.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C70314B6252D00680D02 /* eas_synth.h */; }; + 3DC1C82B14B6252E00680D02 /* eas_synth_protos.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C70414B6252D00680D02 /* eas_synth_protos.h */; }; + 3DC1C82C14B6252E00680D02 /* eas_synthcfg.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C70514B6252D00680D02 /* eas_synthcfg.h */; }; + 3DC1C82D14B6252E00680D02 /* eas_tcdata.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C70614B6252D00680D02 /* eas_tcdata.c */; }; + 3DC1C82E14B6252E00680D02 /* eas_tcdata.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C70714B6252D00680D02 /* eas_tcdata.h */; }; + 3DC1C82F14B6252E00680D02 /* eas_tonecontrol.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C70814B6252D00680D02 /* eas_tonecontrol.c */; }; + 3DC1C83014B6252E00680D02 /* eas_vm_protos.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C70914B6252D00680D02 /* eas_vm_protos.h */; }; + 3DC1C83114B6252E00680D02 /* eas_voicemgt.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C70A14B6252D00680D02 /* eas_voicemgt.c */; }; + 3DC1C83214B6252E00680D02 /* eas_wavefile.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C70B14B6252D00680D02 /* eas_wavefile.c */; }; + 3DC1C83314B6252E00680D02 /* eas_wavefile.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C70C14B6252D00680D02 /* eas_wavefile.h */; }; + 3DC1C83414B6252E00680D02 /* eas_wavefiledata.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C70D14B6252D00680D02 /* eas_wavefiledata.c */; }; + 3DC1C83514B6252E00680D02 /* eas_wt_IPC_frame.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C70E14B6252D00680D02 /* eas_wt_IPC_frame.h */; }; + 3DC1C83614B6252E00680D02 /* eas_wtengine.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C70F14B6252D00680D02 /* eas_wtengine.c */; }; + 3DC1C83714B6252E00680D02 /* eas_wtengine.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C71014B6252D00680D02 /* eas_wtengine.h */; }; + 3DC1C83814B6252E00680D02 /* eas_wtsynth.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C71114B6252D00680D02 /* eas_wtsynth.c */; }; + 3DC1C83914B6252E00680D02 /* eas_wtsynth.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C71214B6252D00680D02 /* eas_wtsynth.h */; }; + 3DC1C83B14B6252E00680D02 /* eas_xmf.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C71414B6252D00680D02 /* eas_xmf.h */; }; + 3DC1C83D14B6252E00680D02 /* eas_xmfdata.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C71614B6252D00680D02 /* eas_xmfdata.h */; }; + 3DC1C83F14B6252E00680D02 /* jet_data.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C71814B6252D00680D02 /* jet_data.h */; }; + 3DC1C84014B6252E00680D02 /* wt_22khz.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C71914B6252D00680D02 /* wt_22khz.c */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 3DC1C5D614B624ED00680D02 /* libEmbeddedAudioSynthesis.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libEmbeddedAudioSynthesis.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 3DC1C6A614B6252D00680D02 /* eas.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eas.h; sourceTree = ""; }; + 3DC1C6A714B6252D00680D02 /* eas_build.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eas_build.h; sourceTree = ""; }; + 3DC1C6A814B6252D00680D02 /* eas_chorus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eas_chorus.h; sourceTree = ""; }; + 3DC1C6A914B6252D00680D02 /* eas_config.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eas_config.c; sourceTree = ""; }; + 3DC1C6AA14B6252D00680D02 /* eas_config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eas_config.h; sourceTree = ""; }; + 3DC1C6AB14B6252D00680D02 /* eas_debugmsgs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eas_debugmsgs.h; sourceTree = ""; }; + 3DC1C6AC14B6252D00680D02 /* eas_host.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eas_host.h; sourceTree = ""; }; + 3DC1C6AD14B6252D00680D02 /* eas_hostmm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eas_hostmm.c; sourceTree = ""; }; + 3DC1C6AF14B6252D00680D02 /* eas_report.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eas_report.c; sourceTree = ""; }; + 3DC1C6B014B6252D00680D02 /* eas_report.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eas_report.h; sourceTree = ""; }; + 3DC1C6B114B6252D00680D02 /* eas_reverb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eas_reverb.h; sourceTree = ""; }; + 3DC1C6B214B6252D00680D02 /* eas_types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eas_types.h; sourceTree = ""; }; + 3DC1C6B314B6252D00680D02 /* eas_wave.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eas_wave.c; sourceTree = ""; }; + 3DC1C6B414B6252D00680D02 /* eas_wave.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eas_wave.h; sourceTree = ""; }; + 3DC1C6B514B6252D00680D02 /* jet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jet.h; sourceTree = ""; }; + 3DC1C6CF14B6252D00680D02 /* dls.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dls.h; sourceTree = ""; }; + 3DC1C6D014B6252D00680D02 /* dls2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dls2.h; sourceTree = ""; }; + 3DC1C6D114B6252D00680D02 /* eas_audioconst.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eas_audioconst.h; sourceTree = ""; }; + 3DC1C6D214B6252D00680D02 /* eas_chorus.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eas_chorus.c; sourceTree = ""; }; + 3DC1C6D314B6252D00680D02 /* eas_chorusdata.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eas_chorusdata.c; sourceTree = ""; }; + 3DC1C6D414B6252D00680D02 /* eas_chorusdata.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eas_chorusdata.h; sourceTree = ""; }; + 3DC1C6D514B6252D00680D02 /* eas_ctype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eas_ctype.h; sourceTree = ""; }; + 3DC1C6D614B6252D00680D02 /* eas_data.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eas_data.c; sourceTree = ""; }; + 3DC1C6D714B6252D00680D02 /* eas_data.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eas_data.h; sourceTree = ""; }; + 3DC1C6D814B6252D00680D02 /* eas_dlssynth.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eas_dlssynth.c; sourceTree = ""; }; + 3DC1C6D914B6252D00680D02 /* eas_dlssynth.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eas_dlssynth.h; sourceTree = ""; }; + 3DC1C6DA14B6252D00680D02 /* eas_effects.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eas_effects.h; sourceTree = ""; }; + 3DC1C6DB14B6252D00680D02 /* eas_flog.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eas_flog.c; sourceTree = ""; }; + 3DC1C6DC14B6252D00680D02 /* eas_ima_tables.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eas_ima_tables.c; sourceTree = ""; }; + 3DC1C6DD14B6252D00680D02 /* eas_imaadpcm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eas_imaadpcm.c; sourceTree = ""; }; + 3DC1C6DE14B6252D00680D02 /* eas_imelody.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eas_imelody.c; sourceTree = ""; }; + 3DC1C6DF14B6252D00680D02 /* eas_imelodydata.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eas_imelodydata.c; sourceTree = ""; }; + 3DC1C6E014B6252D00680D02 /* eas_imelodydata.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eas_imelodydata.h; sourceTree = ""; }; + 3DC1C6E114B6252D00680D02 /* eas_math.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eas_math.c; sourceTree = ""; }; + 3DC1C6E214B6252D00680D02 /* eas_math.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eas_math.h; sourceTree = ""; }; + 3DC1C6E314B6252D00680D02 /* eas_mdls.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eas_mdls.c; sourceTree = ""; }; + 3DC1C6E414B6252D00680D02 /* eas_mdls.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eas_mdls.h; sourceTree = ""; }; + 3DC1C6E514B6252D00680D02 /* eas_midi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eas_midi.c; sourceTree = ""; }; + 3DC1C6E614B6252D00680D02 /* eas_midi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eas_midi.h; sourceTree = ""; }; + 3DC1C6E714B6252D00680D02 /* eas_midictrl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eas_midictrl.h; sourceTree = ""; }; + 3DC1C6E814B6252D00680D02 /* eas_mididata.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eas_mididata.c; sourceTree = ""; }; + 3DC1C6E914B6252D00680D02 /* eas_miditypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eas_miditypes.h; sourceTree = ""; }; + 3DC1C6EA14B6252D00680D02 /* eas_mixbuf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eas_mixbuf.c; sourceTree = ""; }; + 3DC1C6EB14B6252D00680D02 /* eas_mixer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eas_mixer.c; sourceTree = ""; }; + 3DC1C6EC14B6252D00680D02 /* eas_mixer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eas_mixer.h; sourceTree = ""; }; + 3DC1C6ED14B6252D00680D02 /* eas_ota.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eas_ota.c; sourceTree = ""; }; + 3DC1C6EE14B6252D00680D02 /* eas_otadata.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eas_otadata.c; sourceTree = ""; }; + 3DC1C6EF14B6252D00680D02 /* eas_otadata.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eas_otadata.h; sourceTree = ""; }; + 3DC1C6F014B6252D00680D02 /* eas_pan.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eas_pan.c; sourceTree = ""; }; + 3DC1C6F114B6252D00680D02 /* eas_pan.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eas_pan.h; sourceTree = ""; }; + 3DC1C6F214B6252D00680D02 /* eas_parser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eas_parser.h; sourceTree = ""; }; + 3DC1C6F314B6252D00680D02 /* eas_pcm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eas_pcm.c; sourceTree = ""; }; + 3DC1C6F414B6252D00680D02 /* eas_pcm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eas_pcm.h; sourceTree = ""; }; + 3DC1C6F514B6252D00680D02 /* eas_pcmdata.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eas_pcmdata.c; sourceTree = ""; }; + 3DC1C6F614B6252D00680D02 /* eas_pcmdata.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eas_pcmdata.h; sourceTree = ""; }; + 3DC1C6F714B6252D00680D02 /* eas_public.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eas_public.c; sourceTree = ""; }; + 3DC1C6F814B6252D00680D02 /* eas_reverb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eas_reverb.c; sourceTree = ""; }; + 3DC1C6F914B6252D00680D02 /* eas_reverbdata.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eas_reverbdata.c; sourceTree = ""; }; + 3DC1C6FA14B6252D00680D02 /* eas_reverbdata.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eas_reverbdata.h; sourceTree = ""; }; + 3DC1C6FB14B6252D00680D02 /* eas_rtttl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eas_rtttl.c; sourceTree = ""; }; + 3DC1C6FC14B6252D00680D02 /* eas_rtttldata.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eas_rtttldata.c; sourceTree = ""; }; + 3DC1C6FD14B6252D00680D02 /* eas_rtttldata.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eas_rtttldata.h; sourceTree = ""; }; + 3DC1C6FE14B6252D00680D02 /* eas_smf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eas_smf.c; sourceTree = ""; }; + 3DC1C6FF14B6252D00680D02 /* eas_smf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eas_smf.h; sourceTree = ""; }; + 3DC1C70014B6252D00680D02 /* eas_smfdata.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eas_smfdata.c; sourceTree = ""; }; + 3DC1C70114B6252D00680D02 /* eas_smfdata.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eas_smfdata.h; sourceTree = ""; }; + 3DC1C70214B6252D00680D02 /* eas_sndlib.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eas_sndlib.h; sourceTree = ""; }; + 3DC1C70314B6252D00680D02 /* eas_synth.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eas_synth.h; sourceTree = ""; }; + 3DC1C70414B6252D00680D02 /* eas_synth_protos.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eas_synth_protos.h; sourceTree = ""; }; + 3DC1C70514B6252D00680D02 /* eas_synthcfg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eas_synthcfg.h; sourceTree = ""; }; + 3DC1C70614B6252D00680D02 /* eas_tcdata.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eas_tcdata.c; sourceTree = ""; }; + 3DC1C70714B6252D00680D02 /* eas_tcdata.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eas_tcdata.h; sourceTree = ""; }; + 3DC1C70814B6252D00680D02 /* eas_tonecontrol.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eas_tonecontrol.c; sourceTree = ""; }; + 3DC1C70914B6252D00680D02 /* eas_vm_protos.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eas_vm_protos.h; sourceTree = ""; }; + 3DC1C70A14B6252D00680D02 /* eas_voicemgt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eas_voicemgt.c; sourceTree = ""; }; + 3DC1C70B14B6252D00680D02 /* eas_wavefile.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eas_wavefile.c; sourceTree = ""; }; + 3DC1C70C14B6252D00680D02 /* eas_wavefile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eas_wavefile.h; sourceTree = ""; }; + 3DC1C70D14B6252D00680D02 /* eas_wavefiledata.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eas_wavefiledata.c; sourceTree = ""; }; + 3DC1C70E14B6252D00680D02 /* eas_wt_IPC_frame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eas_wt_IPC_frame.h; sourceTree = ""; }; + 3DC1C70F14B6252D00680D02 /* eas_wtengine.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eas_wtengine.c; sourceTree = ""; }; + 3DC1C71014B6252D00680D02 /* eas_wtengine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eas_wtengine.h; sourceTree = ""; }; + 3DC1C71114B6252D00680D02 /* eas_wtsynth.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eas_wtsynth.c; sourceTree = ""; }; + 3DC1C71214B6252D00680D02 /* eas_wtsynth.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eas_wtsynth.h; sourceTree = ""; }; + 3DC1C71314B6252D00680D02 /* eas_xmf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eas_xmf.c; sourceTree = ""; }; + 3DC1C71414B6252D00680D02 /* eas_xmf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eas_xmf.h; sourceTree = ""; }; + 3DC1C71514B6252D00680D02 /* eas_xmfdata.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eas_xmfdata.c; sourceTree = ""; }; + 3DC1C71614B6252D00680D02 /* eas_xmfdata.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eas_xmfdata.h; sourceTree = ""; }; + 3DC1C71714B6252D00680D02 /* jet.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = jet.c; sourceTree = ""; }; + 3DC1C71814B6252D00680D02 /* jet_data.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jet_data.h; sourceTree = ""; }; + 3DC1C71914B6252D00680D02 /* wt_22khz.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = wt_22khz.c; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 3DC1C5D314B624ED00680D02 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 3DC1C5CB14B624ED00680D02 = { + isa = PBXGroup; + children = ( + 3DC1C5EC14B6250600680D02 /* EAS */, + 3DC1C5D714B624ED00680D02 /* Products */, + ); + sourceTree = ""; + }; + 3DC1C5D714B624ED00680D02 /* Products */ = { + isa = PBXGroup; + children = ( + 3DC1C5D614B624ED00680D02 /* libEmbeddedAudioSynthesis.a */, + ); + name = Products; + sourceTree = ""; + }; + 3DC1C5EC14B6250600680D02 /* EAS */ = { + isa = PBXGroup; + children = ( + 3DC1C6A014B6252D00680D02 /* arm-wt-22k */, + ); + name = EAS; + sourceTree = ""; + }; + 3DC1C6A014B6252D00680D02 /* arm-wt-22k */ = { + isa = PBXGroup; + children = ( + 3DC1C6A414B6252D00680D02 /* host_src */, + 3DC1C6C714B6252D00680D02 /* lib_src */, + ); + name = "arm-wt-22k"; + path = "../../embeddedaudiosynthesis/arm-wt-22k"; + sourceTree = ""; + }; + 3DC1C6A414B6252D00680D02 /* host_src */ = { + isa = PBXGroup; + children = ( + 3DC1C6A614B6252D00680D02 /* eas.h */, + 3DC1C6A714B6252D00680D02 /* eas_build.h */, + 3DC1C6A814B6252D00680D02 /* eas_chorus.h */, + 3DC1C6A914B6252D00680D02 /* eas_config.c */, + 3DC1C6AA14B6252D00680D02 /* eas_config.h */, + 3DC1C6AB14B6252D00680D02 /* eas_debugmsgs.h */, + 3DC1C6AC14B6252D00680D02 /* eas_host.h */, + 3DC1C6AD14B6252D00680D02 /* eas_hostmm.c */, + 3DC1C6AF14B6252D00680D02 /* eas_report.c */, + 3DC1C6B014B6252D00680D02 /* eas_report.h */, + 3DC1C6B114B6252D00680D02 /* eas_reverb.h */, + 3DC1C6B214B6252D00680D02 /* eas_types.h */, + 3DC1C6B314B6252D00680D02 /* eas_wave.c */, + 3DC1C6B414B6252D00680D02 /* eas_wave.h */, + 3DC1C6B514B6252D00680D02 /* jet.h */, + ); + path = host_src; + sourceTree = ""; + }; + 3DC1C6C714B6252D00680D02 /* lib_src */ = { + isa = PBXGroup; + children = ( + 3DC1C6CF14B6252D00680D02 /* dls.h */, + 3DC1C6D014B6252D00680D02 /* dls2.h */, + 3DC1C6D114B6252D00680D02 /* eas_audioconst.h */, + 3DC1C6D214B6252D00680D02 /* eas_chorus.c */, + 3DC1C6D314B6252D00680D02 /* eas_chorusdata.c */, + 3DC1C6D414B6252D00680D02 /* eas_chorusdata.h */, + 3DC1C6D514B6252D00680D02 /* eas_ctype.h */, + 3DC1C6D614B6252D00680D02 /* eas_data.c */, + 3DC1C6D714B6252D00680D02 /* eas_data.h */, + 3DC1C6D814B6252D00680D02 /* eas_dlssynth.c */, + 3DC1C6D914B6252D00680D02 /* eas_dlssynth.h */, + 3DC1C6DA14B6252D00680D02 /* eas_effects.h */, + 3DC1C6DB14B6252D00680D02 /* eas_flog.c */, + 3DC1C6DC14B6252D00680D02 /* eas_ima_tables.c */, + 3DC1C6DD14B6252D00680D02 /* eas_imaadpcm.c */, + 3DC1C6DE14B6252D00680D02 /* eas_imelody.c */, + 3DC1C6DF14B6252D00680D02 /* eas_imelodydata.c */, + 3DC1C6E014B6252D00680D02 /* eas_imelodydata.h */, + 3DC1C6E114B6252D00680D02 /* eas_math.c */, + 3DC1C6E214B6252D00680D02 /* eas_math.h */, + 3DC1C6E314B6252D00680D02 /* eas_mdls.c */, + 3DC1C6E414B6252D00680D02 /* eas_mdls.h */, + 3DC1C6E514B6252D00680D02 /* eas_midi.c */, + 3DC1C6E614B6252D00680D02 /* eas_midi.h */, + 3DC1C6E714B6252D00680D02 /* eas_midictrl.h */, + 3DC1C6E814B6252D00680D02 /* eas_mididata.c */, + 3DC1C6E914B6252D00680D02 /* eas_miditypes.h */, + 3DC1C6EA14B6252D00680D02 /* eas_mixbuf.c */, + 3DC1C6EB14B6252D00680D02 /* eas_mixer.c */, + 3DC1C6EC14B6252D00680D02 /* eas_mixer.h */, + 3DC1C6ED14B6252D00680D02 /* eas_ota.c */, + 3DC1C6EE14B6252D00680D02 /* eas_otadata.c */, + 3DC1C6EF14B6252D00680D02 /* eas_otadata.h */, + 3DC1C6F014B6252D00680D02 /* eas_pan.c */, + 3DC1C6F114B6252D00680D02 /* eas_pan.h */, + 3DC1C6F214B6252D00680D02 /* eas_parser.h */, + 3DC1C6F314B6252D00680D02 /* eas_pcm.c */, + 3DC1C6F414B6252D00680D02 /* eas_pcm.h */, + 3DC1C6F514B6252D00680D02 /* eas_pcmdata.c */, + 3DC1C6F614B6252D00680D02 /* eas_pcmdata.h */, + 3DC1C6F714B6252D00680D02 /* eas_public.c */, + 3DC1C6F814B6252D00680D02 /* eas_reverb.c */, + 3DC1C6F914B6252D00680D02 /* eas_reverbdata.c */, + 3DC1C6FA14B6252D00680D02 /* eas_reverbdata.h */, + 3DC1C6FB14B6252D00680D02 /* eas_rtttl.c */, + 3DC1C6FC14B6252D00680D02 /* eas_rtttldata.c */, + 3DC1C6FD14B6252D00680D02 /* eas_rtttldata.h */, + 3DC1C6FE14B6252D00680D02 /* eas_smf.c */, + 3DC1C6FF14B6252D00680D02 /* eas_smf.h */, + 3DC1C70014B6252D00680D02 /* eas_smfdata.c */, + 3DC1C70114B6252D00680D02 /* eas_smfdata.h */, + 3DC1C70214B6252D00680D02 /* eas_sndlib.h */, + 3DC1C70314B6252D00680D02 /* eas_synth.h */, + 3DC1C70414B6252D00680D02 /* eas_synth_protos.h */, + 3DC1C70514B6252D00680D02 /* eas_synthcfg.h */, + 3DC1C70614B6252D00680D02 /* eas_tcdata.c */, + 3DC1C70714B6252D00680D02 /* eas_tcdata.h */, + 3DC1C70814B6252D00680D02 /* eas_tonecontrol.c */, + 3DC1C70914B6252D00680D02 /* eas_vm_protos.h */, + 3DC1C70A14B6252D00680D02 /* eas_voicemgt.c */, + 3DC1C70B14B6252D00680D02 /* eas_wavefile.c */, + 3DC1C70C14B6252D00680D02 /* eas_wavefile.h */, + 3DC1C70D14B6252D00680D02 /* eas_wavefiledata.c */, + 3DC1C70E14B6252D00680D02 /* eas_wt_IPC_frame.h */, + 3DC1C70F14B6252D00680D02 /* eas_wtengine.c */, + 3DC1C71014B6252D00680D02 /* eas_wtengine.h */, + 3DC1C71114B6252D00680D02 /* eas_wtsynth.c */, + 3DC1C71214B6252D00680D02 /* eas_wtsynth.h */, + 3DC1C71314B6252D00680D02 /* eas_xmf.c */, + 3DC1C71414B6252D00680D02 /* eas_xmf.h */, + 3DC1C71514B6252D00680D02 /* eas_xmfdata.c */, + 3DC1C71614B6252D00680D02 /* eas_xmfdata.h */, + 3DC1C71714B6252D00680D02 /* jet.c */, + 3DC1C71814B6252D00680D02 /* jet_data.h */, + 3DC1C71914B6252D00680D02 /* wt_22khz.c */, + ); + path = lib_src; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 3DC1C5D414B624ED00680D02 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 3DC1C7D814B6252E00680D02 /* eas.h in Headers */, + 3DC1C7D914B6252E00680D02 /* eas_build.h in Headers */, + 3DC1C7DA14B6252E00680D02 /* eas_chorus.h in Headers */, + 3DC1C7DC14B6252E00680D02 /* eas_config.h in Headers */, + 3DC1C7DD14B6252E00680D02 /* eas_debugmsgs.h in Headers */, + 3DC1C7DE14B6252E00680D02 /* eas_host.h in Headers */, + 3DC1C7E214B6252E00680D02 /* eas_report.h in Headers */, + 3DC1C7E314B6252E00680D02 /* eas_reverb.h in Headers */, + 3DC1C7E414B6252E00680D02 /* eas_types.h in Headers */, + 3DC1C7E614B6252E00680D02 /* eas_wave.h in Headers */, + 3DC1C7E714B6252E00680D02 /* jet.h in Headers */, + 3DC1C7F614B6252E00680D02 /* dls.h in Headers */, + 3DC1C7F714B6252E00680D02 /* dls2.h in Headers */, + 3DC1C7F814B6252E00680D02 /* eas_audioconst.h in Headers */, + 3DC1C7FB14B6252E00680D02 /* eas_chorusdata.h in Headers */, + 3DC1C7FC14B6252E00680D02 /* eas_ctype.h in Headers */, + 3DC1C7FE14B6252E00680D02 /* eas_data.h in Headers */, + 3DC1C80014B6252E00680D02 /* eas_dlssynth.h in Headers */, + 3DC1C80114B6252E00680D02 /* eas_effects.h in Headers */, + 3DC1C80714B6252E00680D02 /* eas_imelodydata.h in Headers */, + 3DC1C80914B6252E00680D02 /* eas_math.h in Headers */, + 3DC1C80B14B6252E00680D02 /* eas_mdls.h in Headers */, + 3DC1C80D14B6252E00680D02 /* eas_midi.h in Headers */, + 3DC1C80E14B6252E00680D02 /* eas_midictrl.h in Headers */, + 3DC1C81014B6252E00680D02 /* eas_miditypes.h in Headers */, + 3DC1C81314B6252E00680D02 /* eas_mixer.h in Headers */, + 3DC1C81614B6252E00680D02 /* eas_otadata.h in Headers */, + 3DC1C81814B6252E00680D02 /* eas_pan.h in Headers */, + 3DC1C81914B6252E00680D02 /* eas_parser.h in Headers */, + 3DC1C81B14B6252E00680D02 /* eas_pcm.h in Headers */, + 3DC1C81D14B6252E00680D02 /* eas_pcmdata.h in Headers */, + 3DC1C82114B6252E00680D02 /* eas_reverbdata.h in Headers */, + 3DC1C82414B6252E00680D02 /* eas_rtttldata.h in Headers */, + 3DC1C82614B6252E00680D02 /* eas_smf.h in Headers */, + 3DC1C82814B6252E00680D02 /* eas_smfdata.h in Headers */, + 3DC1C82914B6252E00680D02 /* eas_sndlib.h in Headers */, + 3DC1C82A14B6252E00680D02 /* eas_synth.h in Headers */, + 3DC1C82B14B6252E00680D02 /* eas_synth_protos.h in Headers */, + 3DC1C82C14B6252E00680D02 /* eas_synthcfg.h in Headers */, + 3DC1C82E14B6252E00680D02 /* eas_tcdata.h in Headers */, + 3DC1C83014B6252E00680D02 /* eas_vm_protos.h in Headers */, + 3DC1C83314B6252E00680D02 /* eas_wavefile.h in Headers */, + 3DC1C83514B6252E00680D02 /* eas_wt_IPC_frame.h in Headers */, + 3DC1C83714B6252E00680D02 /* eas_wtengine.h in Headers */, + 3DC1C83914B6252E00680D02 /* eas_wtsynth.h in Headers */, + 3DC1C83B14B6252E00680D02 /* eas_xmf.h in Headers */, + 3DC1C83D14B6252E00680D02 /* eas_xmfdata.h in Headers */, + 3DC1C83F14B6252E00680D02 /* jet_data.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 3DC1C5D514B624ED00680D02 /* EmbeddedAudioSynthesis */ = { + isa = PBXNativeTarget; + buildConfigurationList = 3DC1C5E314B624ED00680D02 /* Build configuration list for PBXNativeTarget "EmbeddedAudioSynthesis" */; + buildPhases = ( + 3DC1C5D214B624ED00680D02 /* Sources */, + 3DC1C5D314B624ED00680D02 /* Frameworks */, + 3DC1C5D414B624ED00680D02 /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = EmbeddedAudioSynthesis; + productName = EmbeddedAudioSynthesis; + productReference = 3DC1C5D614B624ED00680D02 /* libEmbeddedAudioSynthesis.a */; + productType = "com.apple.product-type.library.static"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 3DC1C5CD14B624ED00680D02 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0500; + }; + buildConfigurationList = 3DC1C5D014B624ED00680D02 /* Build configuration list for PBXProject "EmbeddedAudioSynthesis" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 3DC1C5CB14B624ED00680D02; + productRefGroup = 3DC1C5D714B624ED00680D02 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 3DC1C5D514B624ED00680D02 /* EmbeddedAudioSynthesis */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 3DC1C5D214B624ED00680D02 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 3DC1C7DB14B6252E00680D02 /* eas_config.c in Sources */, + 3DC1C7DF14B6252E00680D02 /* eas_hostmm.c in Sources */, + 3DC1C7E114B6252E00680D02 /* eas_report.c in Sources */, + 3DC1C7E514B6252E00680D02 /* eas_wave.c in Sources */, + 3DC1C7F914B6252E00680D02 /* eas_chorus.c in Sources */, + 3DC1C7FA14B6252E00680D02 /* eas_chorusdata.c in Sources */, + 3DC1C7FD14B6252E00680D02 /* eas_data.c in Sources */, + 3DC1C80214B6252E00680D02 /* eas_flog.c in Sources */, + 3DC1C80314B6252E00680D02 /* eas_ima_tables.c in Sources */, + 3DC1C80414B6252E00680D02 /* eas_imaadpcm.c in Sources */, + 3DC1C80514B6252E00680D02 /* eas_imelody.c in Sources */, + 3DC1C80614B6252E00680D02 /* eas_imelodydata.c in Sources */, + 3DC1C80814B6252E00680D02 /* eas_math.c in Sources */, + 3DC1C80C14B6252E00680D02 /* eas_midi.c in Sources */, + 3DC1C80F14B6252E00680D02 /* eas_mididata.c in Sources */, + 3DC1C81114B6252E00680D02 /* eas_mixbuf.c in Sources */, + 3DC1C81214B6252E00680D02 /* eas_mixer.c in Sources */, + 3DC1C81414B6252E00680D02 /* eas_ota.c in Sources */, + 3DC1C81514B6252E00680D02 /* eas_otadata.c in Sources */, + 3DC1C81714B6252E00680D02 /* eas_pan.c in Sources */, + 3DC1C81A14B6252E00680D02 /* eas_pcm.c in Sources */, + 3DC1C81C14B6252E00680D02 /* eas_pcmdata.c in Sources */, + 3DC1C81E14B6252E00680D02 /* eas_public.c in Sources */, + 3DC1C81F14B6252E00680D02 /* eas_reverb.c in Sources */, + 3DC1C82014B6252E00680D02 /* eas_reverbdata.c in Sources */, + 3DC1C82214B6252E00680D02 /* eas_rtttl.c in Sources */, + 3DC1C82314B6252E00680D02 /* eas_rtttldata.c in Sources */, + 3DC1C82514B6252E00680D02 /* eas_smf.c in Sources */, + 3DC1C82714B6252E00680D02 /* eas_smfdata.c in Sources */, + 3DC1C82D14B6252E00680D02 /* eas_tcdata.c in Sources */, + 3DC1C82F14B6252E00680D02 /* eas_tonecontrol.c in Sources */, + 3DC1C83114B6252E00680D02 /* eas_voicemgt.c in Sources */, + 3DC1C83214B6252E00680D02 /* eas_wavefile.c in Sources */, + 3DC1C83414B6252E00680D02 /* eas_wavefiledata.c in Sources */, + 3DC1C83614B6252E00680D02 /* eas_wtengine.c in Sources */, + 3DC1C83814B6252E00680D02 /* eas_wtsynth.c in Sources */, + 3DC1C84014B6252E00680D02 /* wt_22khz.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 3DC1C5E114B624ED00680D02 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + COPY_PHASE_STRIP = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + _DEBUG, + _SAMPLE_RATE_22050, + EAS_WT_SYNTH, + _8_BIT_SAMPLES, + _REVERB_ENABLED, + _CHORUS_ENABLED, + _FILTER_ENABLED, + "MAX_SYNTH_VOICES=32", + "NUM_OUTPUT_CHANNELS=2", + UNIFIED_DEBUG_MESSAGES, + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_THUMB_SUPPORT = NO; + GCC_VERSION = com.apple.compilers.llvmgcc42; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 3.0; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + USER_HEADER_SEARCH_PATHS = "../../embeddedaudiosynthesis/arm-wt-22k"; + }; + name = Debug; + }; + 3DC1C5E214B624ED00680D02 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + COPY_PHASE_STRIP = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_PREPROCESSOR_DEFINITIONS = ( + _DEBUG, + _SAMPLE_RATE_22050, + EAS_WT_SYNTH, + _8_BIT_SAMPLES, + _REVERB_ENABLED, + _CHORUS_ENABLED, + _FILTER_ENABLED, + "MAX_SYNTH_VOICES=32", + "NUM_OUTPUT_CHANNELS=2", + UNIFIED_DEBUG_MESSAGES, + ); + GCC_THUMB_SUPPORT = NO; + GCC_VERSION = com.apple.compilers.llvmgcc42; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 3.0; + SDKROOT = iphoneos; + USER_HEADER_SEARCH_PATHS = "../../embeddedaudiosynthesis/arm-wt-22k"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 3DC1C5E414B624ED00680D02 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + DSTROOT = /tmp/EmbeddedAudioSynthesis.dst; + GCC_VERSION = ""; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "\"$(SRCROOT)/../../embeddedaudiosynthesis/arm-fm-22k/lib\"", + "\"$(SRCROOT)/../../embeddedaudiosynthesis/arm-hybrid-22k/lib\"", + "\"$(SRCROOT)/../../embeddedaudiosynthesis/arm-wt-22k/lib\"", + ); + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + 3DC1C5E514B624ED00680D02 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + DSTROOT = /tmp/EmbeddedAudioSynthesis.dst; + GCC_VERSION = ""; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "\"$(SRCROOT)/../../embeddedaudiosynthesis/arm-fm-22k/lib\"", + "\"$(SRCROOT)/../../embeddedaudiosynthesis/arm-hybrid-22k/lib\"", + "\"$(SRCROOT)/../../embeddedaudiosynthesis/arm-wt-22k/lib\"", + ); + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 3DC1C5D014B624ED00680D02 /* Build configuration list for PBXProject "EmbeddedAudioSynthesis" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 3DC1C5E114B624ED00680D02 /* Debug */, + 3DC1C5E214B624ED00680D02 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 3DC1C5E314B624ED00680D02 /* Build configuration list for PBXNativeTarget "EmbeddedAudioSynthesis" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 3DC1C5E414B624ED00680D02 /* Debug */, + 3DC1C5E514B624ED00680D02 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 3DC1C5CD14B624ED00680D02 /* Project object */; +} diff --git a/common/ios/EmbeddedAudioSynthesis/EmbeddedAudioSynthesis.xcodeproj/xcuserdata/Farrand.xcuserdatad/xcschemes/EmbeddedAudioSynthesis.xcscheme b/common/ios/EmbeddedAudioSynthesis/EmbeddedAudioSynthesis.xcodeproj/xcuserdata/Farrand.xcuserdatad/xcschemes/EmbeddedAudioSynthesis.xcscheme new file mode 100644 index 0000000..7cda2e9 --- /dev/null +++ b/common/ios/EmbeddedAudioSynthesis/EmbeddedAudioSynthesis.xcodeproj/xcuserdata/Farrand.xcuserdatad/xcschemes/EmbeddedAudioSynthesis.xcscheme @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/common/ios/EmbeddedAudioSynthesis/EmbeddedAudioSynthesis.xcodeproj/xcuserdata/Farrand.xcuserdatad/xcschemes/xcschememanagement.plist b/common/ios/EmbeddedAudioSynthesis/EmbeddedAudioSynthesis.xcodeproj/xcuserdata/Farrand.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..d52b83a --- /dev/null +++ b/common/ios/EmbeddedAudioSynthesis/EmbeddedAudioSynthesis.xcodeproj/xcuserdata/Farrand.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,22 @@ + + + + + SchemeUserState + + EmbeddedAudioSynthesis.xcscheme + + orderHint + 4 + + + SuppressBuildableAutocreation + + 3DC1C5D514B624ED00680D02 + + primary + + + + + diff --git a/common/ios/EmbeddedAudioSynthesis/EmbeddedAudioSynthesis.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/EmbeddedAudioSynthesis.xcscheme b/common/ios/EmbeddedAudioSynthesis/EmbeddedAudioSynthesis.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/EmbeddedAudioSynthesis.xcscheme new file mode 100755 index 0000000..20e7b1a --- /dev/null +++ b/common/ios/EmbeddedAudioSynthesis/EmbeddedAudioSynthesis.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/EmbeddedAudioSynthesis.xcscheme @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/common/ios/EmbeddedAudioSynthesis/EmbeddedAudioSynthesis.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/xcschememanagement.plist b/common/ios/EmbeddedAudioSynthesis/EmbeddedAudioSynthesis.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100755 index 0000000..a92b9a2 --- /dev/null +++ b/common/ios/EmbeddedAudioSynthesis/EmbeddedAudioSynthesis.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,24 @@ + + + + + SchemeUserState + + EmbeddedAudioSynthesis.xcscheme + + isShown + + orderHint + 5 + + + SuppressBuildableAutocreation + + 3DC1C5D514B624ED00680D02 + + primary + + + + + diff --git a/common/ios/EmbeddedAudioSynthesis/EmbeddedAudioSynthesis.xcodeproj/xcuserdata/ryan.gerleve.xcuserdatad/xcschemes/EmbeddedAudioSynthesis.xcscheme b/common/ios/EmbeddedAudioSynthesis/EmbeddedAudioSynthesis.xcodeproj/xcuserdata/ryan.gerleve.xcuserdatad/xcschemes/EmbeddedAudioSynthesis.xcscheme new file mode 100755 index 0000000..20e7b1a --- /dev/null +++ b/common/ios/EmbeddedAudioSynthesis/EmbeddedAudioSynthesis.xcodeproj/xcuserdata/ryan.gerleve.xcuserdatad/xcschemes/EmbeddedAudioSynthesis.xcscheme @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/common/ios/EmbeddedAudioSynthesis/EmbeddedAudioSynthesis.xcodeproj/xcuserdata/ryan.gerleve.xcuserdatad/xcschemes/xcschememanagement.plist b/common/ios/EmbeddedAudioSynthesis/EmbeddedAudioSynthesis.xcodeproj/xcuserdata/ryan.gerleve.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100755 index 0000000..d216d86 --- /dev/null +++ b/common/ios/EmbeddedAudioSynthesis/EmbeddedAudioSynthesis.xcodeproj/xcuserdata/ryan.gerleve.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,22 @@ + + + + + SchemeUserState + + EmbeddedAudioSynthesis.xcscheme + + orderHint + 5 + + + SuppressBuildableAutocreation + + 3DC1C5D514B624ED00680D02 + + primary + + + + + diff --git a/common/ios/doomengine.xcodeproj/project.pbxproj b/common/ios/doomengine.xcodeproj/project.pbxproj new file mode 100755 index 0000000..aa94b29 --- /dev/null +++ b/common/ios/doomengine.xcodeproj/project.pbxproj @@ -0,0 +1,604 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 3D15600C14B51250000D33AA /* libtess.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3D155FD614B51128000D33AA /* libtess.a */; }; + 3D2B137714BFB57E00C8D221 /* iphone_loop.c in Sources */ = {isa = PBXBuildFile; fileRef = 3D2B137614BFB57E00C8D221 /* iphone_loop.c */; }; + 3D2EC246148EBA8300273241 /* EASGlue.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D2EC244148EBA8300273241 /* EASGlue.h */; }; + 3D2EC247148EBA8300273241 /* EASGlue.c in Sources */ = {isa = PBXBuildFile; fileRef = 3D2EC245148EBA8300273241 /* EASGlue.c */; }; + 3D460D2914BCA5430078262C /* iphone_async.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D460D2814BCA5430078262C /* iphone_async.cpp */; }; + 3D460D4F14BCFBD40078262C /* iphone_glViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3D460D4E14BCFBD40078262C /* iphone_glViewController.mm */; }; + 3D5BB94A14B79BFE00A9A7FB /* DoomGameCenterMatch.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D5BB94814B79BFE00A9A7FB /* DoomGameCenterMatch.h */; }; + 3D5BB94B14B79BFE00A9A7FB /* DoomGameCenterMatch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D5BB94914B79BFE00A9A7FB /* DoomGameCenterMatch.cpp */; }; + 3D7D555D14D1C53A00A0F1FF /* iphone_start.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D7D555C14D1C53900A0F1FF /* iphone_start.cpp */; }; + 3D80889A1492E2E8002D6CC3 /* iphone_common.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3D8088991492E2E7002D6CC3 /* iphone_common.mm */; }; + 3D80889C1492E378002D6CC3 /* iphone_common.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D80889B1492E378002D6CC3 /* iphone_common.h */; }; + 3DC1C84814B627E600680D02 /* libEmbeddedAudioSynthesis.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DC1C5EB14B624EE00680D02 /* libEmbeddedAudioSynthesis.a */; }; + 3DC1CAF814B641CC00680D02 /* libprboom.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DC1C86A14B63E1C00680D02 /* libprboom.a */; }; + 3DDA6FCE148D765100C834C7 /* SDL_Mixer.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DDA6FCD148D765100C834C7 /* SDL_Mixer.h */; }; + 3DDA6FD1148DA2C800C834C7 /* SDL_Mixer.m in Sources */ = {isa = PBXBuildFile; fileRef = 3DDA6FD0148DA2C800C834C7 /* SDL_Mixer.m */; }; + 3DE6943D1489AFDE0049CAA4 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DE6943C1489AFDE0049CAA4 /* Foundation.framework */; }; + 3DE6946D1489B0850049CAA4 /* arialGlyphRects.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DE6944E1489B0850049CAA4 /* arialGlyphRects.h */; }; + 3DE6946F1489B0850049CAA4 /* cmd.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DE694501489B0850049CAA4 /* cmd.c */; }; + 3DE694701489B0850049CAA4 /* cvar.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DE694511489B0850049CAA4 /* cvar.c */; }; + 3DE694711489B0850049CAA4 /* cvar.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DE694521489B0850049CAA4 /* cvar.h */; }; + 3DE694731489B0850049CAA4 /* doomiphone.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DE694541489B0850049CAA4 /* doomiphone.h */; }; + 3DE694741489B0850049CAA4 /* EAGLView.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DE694551489B0850049CAA4 /* EAGLView.h */; }; + 3DE694751489B0850049CAA4 /* EAGLView.m in Sources */ = {isa = PBXBuildFile; fileRef = 3DE694561489B0850049CAA4 /* EAGLView.m */; }; + 3DE694761489B0850049CAA4 /* gles_glue.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DE694571489B0850049CAA4 /* gles_glue.c */; }; + 3DE694771489B0850049CAA4 /* gles_glue.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DE694581489B0850049CAA4 /* gles_glue.h */; }; + 3DE694781489B0850049CAA4 /* ipak.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DE694591489B0850049CAA4 /* ipak.c */; }; + 3DE694791489B0850049CAA4 /* ipak.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DE6945A1489B0850049CAA4 /* ipak.h */; }; + 3DE6947A1489B0850049CAA4 /* iphone_doom.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DE6945B1489B0850049CAA4 /* iphone_doom.h */; }; + 3DE6947B1489B0850049CAA4 /* iphone_email.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DE6945C1489B0850049CAA4 /* iphone_email.h */; }; + 3DE6947C1489B0850049CAA4 /* iphone_email.m in Sources */ = {isa = PBXBuildFile; fileRef = 3DE6945D1489B0850049CAA4 /* iphone_email.m */; }; + 3DE6947D1489B0850049CAA4 /* iphone_main.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DE6945E1489B0850049CAA4 /* iphone_main.c */; }; + 3DE6947E1489B0850049CAA4 /* iphone_mapSelect.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DE6945F1489B0850049CAA4 /* iphone_mapSelect.c */; }; + 3DE694851489B0850049CAA4 /* misc.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DE694661489B0850049CAA4 /* misc.c */; }; + 3DE694861489B0850049CAA4 /* misc.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DE694671489B0850049CAA4 /* misc.h */; }; + 3DE694871489B0850049CAA4 /* prboomInterface.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DE694681489B0850049CAA4 /* prboomInterface.c */; }; + 3DE694881489B0850049CAA4 /* SoundEngine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3DE694691489B0850049CAA4 /* SoundEngine.cpp */; }; + 3DE694891489B0850049CAA4 /* SoundEngine.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DE6946A1489B0850049CAA4 /* SoundEngine.h */; }; + 3DE69620148C28810049CAA4 /* iphone_render.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DE6961F148C28810049CAA4 /* iphone_render.c */; }; + 3DF31FB0148C3A3600C66CD7 /* hud.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DF31FAF148C3A3600C66CD7 /* hud.c */; }; + 3DF31FB4148C3B5100C66CD7 /* iphone_sound.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DF31FB3148C3B5100C66CD7 /* iphone_sound.c */; }; + C82EE118149958A0003B9C74 /* BackgroundMusic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C82EE117149958A0003B9C74 /* BackgroundMusic.cpp */; }; + C86CA85814B4F3C40057FF54 /* iphone_delegate.h in Headers */ = {isa = PBXBuildFile; fileRef = C86CA85214B4F3C40057FF54 /* iphone_delegate.h */; }; + C86CA85914B4F3C40057FF54 /* iphone_delegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = C86CA85314B4F3C40057FF54 /* iphone_delegate.mm */; }; + C86CA85A14B4F3C40057FF54 /* iphone_glViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = C86CA85414B4F3C40057FF54 /* iphone_glViewController.h */; }; + C8DB8AD014BDFBE80006467C /* iphone_sys.mm in Sources */ = {isa = PBXBuildFile; fileRef = C8DB8ACF14BDFBE80006467C /* iphone_sys.mm */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 1391CE121882E50B0049671C /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 1391CE0E1882E50A0049671C /* idmobilelib.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 3D80884714928766002D6CC3; + remoteInfo = idmobilelib; + }; + 3D155FD514B51128000D33AA /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 3D155FD114B51127000D33AA /* tess.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 3D155FC114B51127000D33AA; + remoteInfo = tess; + }; + 3D15600A14B511BB000D33AA /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 3D155FD114B51127000D33AA /* tess.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = 3D155FC014B51127000D33AA; + remoteInfo = tess; + }; + 3DC1C5EA14B624EE00680D02 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 3DC1C5E614B624ED00680D02 /* EmbeddedAudioSynthesis.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 3DC1C5D614B624ED00680D02; + remoteInfo = EmbeddedAudioSynthesis; + }; + 3DC1C86914B63E1C00680D02 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 3DC1C86514B63E1B00680D02 /* prboom.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 3DC1C85514B63E1B00680D02; + remoteInfo = prboom; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 1391CE0E1882E50A0049671C /* idmobilelib.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = idmobilelib.xcodeproj; path = ../idmobilelib/ios/idmobilelib.xcodeproj; sourceTree = ""; }; + 3D155FD114B51127000D33AA /* tess.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = tess.xcodeproj; path = tess/tess.xcodeproj; sourceTree = ""; }; + 3D2B137614BFB57E00C8D221 /* iphone_loop.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = iphone_loop.c; sourceTree = ""; }; + 3D2EC244148EBA8300273241 /* EASGlue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EASGlue.h; sourceTree = ""; }; + 3D2EC245148EBA8300273241 /* EASGlue.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = EASGlue.c; sourceTree = ""; }; + 3D460D2814BCA5430078262C /* iphone_async.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = iphone_async.cpp; sourceTree = ""; }; + 3D460D4E14BCFBD40078262C /* iphone_glViewController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = iphone_glViewController.mm; sourceTree = ""; }; + 3D5BB94814B79BFE00A9A7FB /* DoomGameCenterMatch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DoomGameCenterMatch.h; sourceTree = ""; }; + 3D5BB94914B79BFE00A9A7FB /* DoomGameCenterMatch.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DoomGameCenterMatch.cpp; sourceTree = ""; }; + 3D7D555C14D1C53900A0F1FF /* iphone_start.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = iphone_start.cpp; sourceTree = ""; }; + 3D8088991492E2E7002D6CC3 /* iphone_common.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = iphone_common.mm; sourceTree = ""; }; + 3D80889B1492E378002D6CC3 /* iphone_common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = iphone_common.h; sourceTree = ""; }; + 3DC1C5E614B624ED00680D02 /* EmbeddedAudioSynthesis.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = EmbeddedAudioSynthesis.xcodeproj; path = EmbeddedAudioSynthesis/EmbeddedAudioSynthesis.xcodeproj; sourceTree = ""; }; + 3DC1C86514B63E1B00680D02 /* prboom.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = prboom.xcodeproj; path = prboom/prboom.xcodeproj; sourceTree = ""; }; + 3DDA6FCD148D765100C834C7 /* SDL_Mixer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SDL_Mixer.h; path = ../SDL_shim/SDL_Mixer.h; sourceTree = ""; }; + 3DDA6FD0148DA2C800C834C7 /* SDL_Mixer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SDL_Mixer.m; path = ../SDL_shim/ios/SDL_Mixer.m; sourceTree = ""; }; + 3DE694391489AFDE0049CAA4 /* libdoomengine.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libdoomengine.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 3DE6943C1489AFDE0049CAA4 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 3DE6944E1489B0850049CAA4 /* arialGlyphRects.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = arialGlyphRects.h; sourceTree = ""; }; + 3DE694501489B0850049CAA4 /* cmd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cmd.c; sourceTree = ""; }; + 3DE694511489B0850049CAA4 /* cvar.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cvar.c; sourceTree = ""; }; + 3DE694521489B0850049CAA4 /* cvar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cvar.h; sourceTree = ""; }; + 3DE694541489B0850049CAA4 /* doomiphone.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = doomiphone.h; sourceTree = ""; }; + 3DE694551489B0850049CAA4 /* EAGLView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EAGLView.h; sourceTree = ""; }; + 3DE694561489B0850049CAA4 /* EAGLView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EAGLView.m; sourceTree = ""; }; + 3DE694571489B0850049CAA4 /* gles_glue.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gles_glue.c; sourceTree = ""; }; + 3DE694581489B0850049CAA4 /* gles_glue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gles_glue.h; sourceTree = ""; }; + 3DE694591489B0850049CAA4 /* ipak.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ipak.c; sourceTree = ""; }; + 3DE6945A1489B0850049CAA4 /* ipak.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ipak.h; sourceTree = ""; }; + 3DE6945B1489B0850049CAA4 /* iphone_doom.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = iphone_doom.h; sourceTree = ""; }; + 3DE6945C1489B0850049CAA4 /* iphone_email.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = iphone_email.h; sourceTree = ""; }; + 3DE6945D1489B0850049CAA4 /* iphone_email.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = iphone_email.m; sourceTree = ""; }; + 3DE6945E1489B0850049CAA4 /* iphone_main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = iphone_main.c; sourceTree = ""; }; + 3DE6945F1489B0850049CAA4 /* iphone_mapSelect.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = iphone_mapSelect.c; sourceTree = ""; }; + 3DE694661489B0850049CAA4 /* misc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = misc.c; sourceTree = ""; }; + 3DE694671489B0850049CAA4 /* misc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = misc.h; sourceTree = ""; }; + 3DE694681489B0850049CAA4 /* prboomInterface.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = prboomInterface.c; sourceTree = ""; }; + 3DE694691489B0850049CAA4 /* SoundEngine.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SoundEngine.cpp; sourceTree = ""; }; + 3DE6946A1489B0850049CAA4 /* SoundEngine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SoundEngine.h; sourceTree = ""; }; + 3DE6961F148C28810049CAA4 /* iphone_render.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = iphone_render.c; sourceTree = ""; }; + 3DF31FAF148C3A3600C66CD7 /* hud.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hud.c; sourceTree = ""; }; + 3DF31FB3148C3B5100C66CD7 /* iphone_sound.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = iphone_sound.c; sourceTree = ""; }; + C82EE117149958A0003B9C74 /* BackgroundMusic.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BackgroundMusic.cpp; sourceTree = ""; }; + C86CA85214B4F3C40057FF54 /* iphone_delegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = iphone_delegate.h; sourceTree = ""; }; + C86CA85314B4F3C40057FF54 /* iphone_delegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = iphone_delegate.mm; sourceTree = ""; }; + C86CA85414B4F3C40057FF54 /* iphone_glViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = iphone_glViewController.h; sourceTree = ""; }; + C8DB8ACF14BDFBE80006467C /* iphone_sys.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = iphone_sys.mm; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 3DE694361489AFDE0049CAA4 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 3DC1CAF814B641CC00680D02 /* libprboom.a in Frameworks */, + 3DC1C84814B627E600680D02 /* libEmbeddedAudioSynthesis.a in Frameworks */, + 3D15600C14B51250000D33AA /* libtess.a in Frameworks */, + 3DE6943D1489AFDE0049CAA4 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 1391CE0F1882E50A0049671C /* Products */ = { + isa = PBXGroup; + children = ( + 1391CE131882E50B0049671C /* libidmobilelib.a */, + ); + name = Products; + sourceTree = ""; + }; + 3D155FD214B51127000D33AA /* Products */ = { + isa = PBXGroup; + children = ( + 3D155FD614B51128000D33AA /* libtess.a */, + ); + name = Products; + sourceTree = ""; + }; + 3D2EC141148EB77900273241 /* embeddedaudiosynthesis */ = { + isa = PBXGroup; + children = ( + 3D2EC244148EBA8300273241 /* EASGlue.h */, + 3D2EC245148EBA8300273241 /* EASGlue.c */, + ); + name = embeddedaudiosynthesis; + path = ../embeddedaudiosynthesis; + sourceTree = ""; + }; + 3DC1C5E714B624ED00680D02 /* Products */ = { + isa = PBXGroup; + children = ( + 3DC1C5EB14B624EE00680D02 /* libEmbeddedAudioSynthesis.a */, + ); + name = Products; + sourceTree = ""; + }; + 3DC1C86614B63E1B00680D02 /* Products */ = { + isa = PBXGroup; + children = ( + 3DC1C86A14B63E1C00680D02 /* libprboom.a */, + ); + name = Products; + sourceTree = ""; + }; + 3DDA6FCC148D75DB00C834C7 /* SDL_shim */ = { + isa = PBXGroup; + children = ( + 3DDA6FCF148DA2B000C834C7 /* ios */, + 3DDA6FCD148D765100C834C7 /* SDL_Mixer.h */, + ); + name = SDL_shim; + sourceTree = ""; + }; + 3DDA6FCF148DA2B000C834C7 /* ios */ = { + isa = PBXGroup; + children = ( + 3DDA6FD0148DA2C800C834C7 /* SDL_Mixer.m */, + ); + name = ios; + sourceTree = ""; + }; + 3DE6942E1489AFDE0049CAA4 = { + isa = PBXGroup; + children = ( + 1391CE0E1882E50A0049671C /* idmobilelib.xcodeproj */, + 3DC1C86514B63E1B00680D02 /* prboom.xcodeproj */, + 3DC1C5E614B624ED00680D02 /* EmbeddedAudioSynthesis.xcodeproj */, + 3D155FD114B51127000D33AA /* tess.xcodeproj */, + 3D2EC141148EB77900273241 /* embeddedaudiosynthesis */, + 3DDA6FCC148D75DB00C834C7 /* SDL_shim */, + 3DE6943E1489AFDE0049CAA4 /* doomengine */, + 3DE6943B1489AFDE0049CAA4 /* Frameworks */, + 3DE6943A1489AFDE0049CAA4 /* Products */, + ); + sourceTree = ""; + }; + 3DE6943A1489AFDE0049CAA4 /* Products */ = { + isa = PBXGroup; + children = ( + 3DE694391489AFDE0049CAA4 /* libdoomengine.a */, + ); + name = Products; + sourceTree = ""; + }; + 3DE6943B1489AFDE0049CAA4 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 3DE6943C1489AFDE0049CAA4 /* Foundation.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 3DE6943E1489AFDE0049CAA4 /* doomengine */ = { + isa = PBXGroup; + children = ( + C8DB8ACF14BDFBE80006467C /* iphone_sys.mm */, + C86CA85214B4F3C40057FF54 /* iphone_delegate.h */, + C86CA85314B4F3C40057FF54 /* iphone_delegate.mm */, + C86CA85414B4F3C40057FF54 /* iphone_glViewController.h */, + C82EE117149958A0003B9C74 /* BackgroundMusic.cpp */, + 3DE6944E1489B0850049CAA4 /* arialGlyphRects.h */, + 3DE694501489B0850049CAA4 /* cmd.c */, + 3DE694511489B0850049CAA4 /* cvar.c */, + 3DE694521489B0850049CAA4 /* cvar.h */, + 3DE694541489B0850049CAA4 /* doomiphone.h */, + 3DE694551489B0850049CAA4 /* EAGLView.h */, + 3DE694561489B0850049CAA4 /* EAGLView.m */, + 3DE694571489B0850049CAA4 /* gles_glue.c */, + 3DE694581489B0850049CAA4 /* gles_glue.h */, + 3DF31FAF148C3A3600C66CD7 /* hud.c */, + 3DE694591489B0850049CAA4 /* ipak.c */, + 3DE6945A1489B0850049CAA4 /* ipak.h */, + 3D460D2814BCA5430078262C /* iphone_async.cpp */, + 3D80889B1492E378002D6CC3 /* iphone_common.h */, + 3D8088991492E2E7002D6CC3 /* iphone_common.mm */, + 3DE6945B1489B0850049CAA4 /* iphone_doom.h */, + 3DE6945C1489B0850049CAA4 /* iphone_email.h */, + 3DE6945D1489B0850049CAA4 /* iphone_email.m */, + 3D460D4E14BCFBD40078262C /* iphone_glViewController.mm */, + 3D2B137614BFB57E00C8D221 /* iphone_loop.c */, + 3DE6945E1489B0850049CAA4 /* iphone_main.c */, + 3DE6945F1489B0850049CAA4 /* iphone_mapSelect.c */, + 3DE6961F148C28810049CAA4 /* iphone_render.c */, + 3D7D555C14D1C53900A0F1FF /* iphone_start.cpp */, + 3DF31FB3148C3B5100C66CD7 /* iphone_sound.c */, + 3DE694661489B0850049CAA4 /* misc.c */, + 3DE694671489B0850049CAA4 /* misc.h */, + 3DE694681489B0850049CAA4 /* prboomInterface.c */, + 3DE694691489B0850049CAA4 /* SoundEngine.cpp */, + 3DE6946A1489B0850049CAA4 /* SoundEngine.h */, + 3D5BB94814B79BFE00A9A7FB /* DoomGameCenterMatch.h */, + 3D5BB94914B79BFE00A9A7FB /* DoomGameCenterMatch.cpp */, + ); + path = doomengine; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 3DE694371489AFDE0049CAA4 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 3DE6946D1489B0850049CAA4 /* arialGlyphRects.h in Headers */, + 3DE694711489B0850049CAA4 /* cvar.h in Headers */, + 3DE694731489B0850049CAA4 /* doomiphone.h in Headers */, + 3DE694741489B0850049CAA4 /* EAGLView.h in Headers */, + 3DE694771489B0850049CAA4 /* gles_glue.h in Headers */, + 3DE694791489B0850049CAA4 /* ipak.h in Headers */, + 3DE6947A1489B0850049CAA4 /* iphone_doom.h in Headers */, + 3DE6947B1489B0850049CAA4 /* iphone_email.h in Headers */, + 3DE694861489B0850049CAA4 /* misc.h in Headers */, + 3DE694891489B0850049CAA4 /* SoundEngine.h in Headers */, + 3DDA6FCE148D765100C834C7 /* SDL_Mixer.h in Headers */, + 3D2EC246148EBA8300273241 /* EASGlue.h in Headers */, + 3D80889C1492E378002D6CC3 /* iphone_common.h in Headers */, + C86CA85814B4F3C40057FF54 /* iphone_delegate.h in Headers */, + C86CA85A14B4F3C40057FF54 /* iphone_glViewController.h in Headers */, + 3D5BB94A14B79BFE00A9A7FB /* DoomGameCenterMatch.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 3DE694381489AFDE0049CAA4 /* doomengine */ = { + isa = PBXNativeTarget; + buildConfigurationList = 3DE694461489AFDE0049CAA4 /* Build configuration list for PBXNativeTarget "doomengine" */; + buildPhases = ( + 3DE694351489AFDE0049CAA4 /* Sources */, + 3DE694361489AFDE0049CAA4 /* Frameworks */, + 3DE694371489AFDE0049CAA4 /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + 3D15600B14B511BB000D33AA /* PBXTargetDependency */, + ); + name = doomengine; + productName = doomengine; + productReference = 3DE694391489AFDE0049CAA4 /* libdoomengine.a */; + productType = "com.apple.product-type.library.static"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 3DE694301489AFDE0049CAA4 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0500; + }; + buildConfigurationList = 3DE694331489AFDE0049CAA4 /* Build configuration list for PBXProject "doomengine" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 3DE6942E1489AFDE0049CAA4; + productRefGroup = 3DE6943A1489AFDE0049CAA4 /* Products */; + projectDirPath = ""; + projectReferences = ( + { + ProductGroup = 3DC1C5E714B624ED00680D02 /* Products */; + ProjectRef = 3DC1C5E614B624ED00680D02 /* EmbeddedAudioSynthesis.xcodeproj */; + }, + { + ProductGroup = 1391CE0F1882E50A0049671C /* Products */; + ProjectRef = 1391CE0E1882E50A0049671C /* idmobilelib.xcodeproj */; + }, + { + ProductGroup = 3DC1C86614B63E1B00680D02 /* Products */; + ProjectRef = 3DC1C86514B63E1B00680D02 /* prboom.xcodeproj */; + }, + { + ProductGroup = 3D155FD214B51127000D33AA /* Products */; + ProjectRef = 3D155FD114B51127000D33AA /* tess.xcodeproj */; + }, + ); + projectRoot = ""; + targets = ( + 3DE694381489AFDE0049CAA4 /* doomengine */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXReferenceProxy section */ + 1391CE131882E50B0049671C /* libidmobilelib.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libidmobilelib.a; + remoteRef = 1391CE121882E50B0049671C /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 3D155FD614B51128000D33AA /* libtess.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libtess.a; + remoteRef = 3D155FD514B51128000D33AA /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 3DC1C5EB14B624EE00680D02 /* libEmbeddedAudioSynthesis.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libEmbeddedAudioSynthesis.a; + remoteRef = 3DC1C5EA14B624EE00680D02 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 3DC1C86A14B63E1C00680D02 /* libprboom.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libprboom.a; + remoteRef = 3DC1C86914B63E1C00680D02 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; +/* End PBXReferenceProxy section */ + +/* Begin PBXSourcesBuildPhase section */ + 3DE694351489AFDE0049CAA4 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 3DE6946F1489B0850049CAA4 /* cmd.c in Sources */, + 3DE694701489B0850049CAA4 /* cvar.c in Sources */, + 3DE694751489B0850049CAA4 /* EAGLView.m in Sources */, + 3DE694761489B0850049CAA4 /* gles_glue.c in Sources */, + 3DE694781489B0850049CAA4 /* ipak.c in Sources */, + 3DE6947C1489B0850049CAA4 /* iphone_email.m in Sources */, + 3DE6947D1489B0850049CAA4 /* iphone_main.c in Sources */, + 3DE6947E1489B0850049CAA4 /* iphone_mapSelect.c in Sources */, + 3DE694851489B0850049CAA4 /* misc.c in Sources */, + 3DE694871489B0850049CAA4 /* prboomInterface.c in Sources */, + 3DE694881489B0850049CAA4 /* SoundEngine.cpp in Sources */, + 3DE69620148C28810049CAA4 /* iphone_render.c in Sources */, + 3DF31FB0148C3A3600C66CD7 /* hud.c in Sources */, + 3DF31FB4148C3B5100C66CD7 /* iphone_sound.c in Sources */, + 3DDA6FD1148DA2C800C834C7 /* SDL_Mixer.m in Sources */, + 3D2EC247148EBA8300273241 /* EASGlue.c in Sources */, + 3D80889A1492E2E8002D6CC3 /* iphone_common.mm in Sources */, + C82EE118149958A0003B9C74 /* BackgroundMusic.cpp in Sources */, + C86CA85914B4F3C40057FF54 /* iphone_delegate.mm in Sources */, + 3D5BB94B14B79BFE00A9A7FB /* DoomGameCenterMatch.cpp in Sources */, + 3D460D2914BCA5430078262C /* iphone_async.cpp in Sources */, + 3D460D4F14BCFBD40078262C /* iphone_glViewController.mm in Sources */, + C8DB8AD014BDFBE80006467C /* iphone_sys.mm in Sources */, + 3D2B137714BFB57E00C8D221 /* iphone_loop.c in Sources */, + 3D7D555D14D1C53A00A0F1FF /* iphone_start.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 3D15600B14B511BB000D33AA /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = tess; + targetProxy = 3D15600A14B511BB000D33AA /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 3DE694441489AFDE0049CAA4 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_OBJCPP_ARC_ABI = YES; + CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES; + COPY_PHASE_STRIP = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(inherited)", + IPHONE, + ); + GCC_SYMBOLS_PRIVATE_EXTERN = YES; + GCC_THUMB_SUPPORT = NO; + GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES; + GCC_TREAT_WARNINGS_AS_ERRORS = YES; + GCC_VERSION = ""; + GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; + GCC_WARN_ABOUT_MISSING_NEWLINE = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES; + GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES; + GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; + GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES; + GCC_WARN_STRICT_SELECTOR_MATCH = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNKNOWN_PRAGMAS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_LABEL = YES; + GCC_WARN_UNUSED_PARAMETER = NO; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 3.2; + ONLY_ACTIVE_ARCH = NO; + SDKROOT = iphoneos; + USER_HEADER_SEARCH_PATHS = "../embeddedaudiosynthesis/arm-wt-22k/host_src ../ ../../../idTechM/idTechM/shared/idmobilelib ../prboom"; + VALID_ARCHS = "armv7 armv7s"; + }; + name = Debug; + }; + 3DE694451489AFDE0049CAA4 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_OBJCPP_ARC_ABI = YES; + CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES; + COPY_PHASE_STRIP = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_PREPROCESSOR_DEFINITIONS = ( + IPHONE, + NDEBUG, + ); + GCC_SYMBOLS_PRIVATE_EXTERN = YES; + GCC_THUMB_SUPPORT = NO; + GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES; + GCC_TREAT_WARNINGS_AS_ERRORS = YES; + GCC_VERSION = ""; + GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; + GCC_WARN_ABOUT_MISSING_NEWLINE = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES; + GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES; + GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; + GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES; + GCC_WARN_STRICT_SELECTOR_MATCH = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = NO; + GCC_WARN_UNKNOWN_PRAGMAS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_LABEL = YES; + GCC_WARN_UNUSED_PARAMETER = NO; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 3.2; + SDKROOT = iphoneos; + USER_HEADER_SEARCH_PATHS = "../embeddedaudiosynthesis/arm-wt-22k/host_src ../ ../../../idTechM/idTechM/shared/idmobilelib ../prboom"; + VALIDATE_PRODUCT = YES; + VALID_ARCHS = "armv7 armv7s"; + }; + name = Release; + }; + 3DE694471489AFDE0049CAA4 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + DSTROOT = /tmp/doomengine.dst; + GCC_PRECOMPILE_PREFIX_HEADER = NO; + GCC_PREFIX_HEADER = ""; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "\"$(SRCROOT)/../embeddedaudiosynthesis/arm-wt-22k/lib\"", + ); + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + USER_HEADER_SEARCH_PATHS = "../embeddedaudiosynthesis/arm-wt-22k/host_src ../ ../idmobilelib ../prboom"; + }; + name = Debug; + }; + 3DE694481489AFDE0049CAA4 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + DSTROOT = /tmp/doomengine.dst; + GCC_PRECOMPILE_PREFIX_HEADER = NO; + GCC_PREFIX_HEADER = ""; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "\"$(SRCROOT)/../embeddedaudiosynthesis/arm-wt-22k/lib\"", + ); + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + USER_HEADER_SEARCH_PATHS = "../embeddedaudiosynthesis/arm-wt-22k/host_src ../ ../idmobilelib ../prboom"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 3DE694331489AFDE0049CAA4 /* Build configuration list for PBXProject "doomengine" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 3DE694441489AFDE0049CAA4 /* Debug */, + 3DE694451489AFDE0049CAA4 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 3DE694461489AFDE0049CAA4 /* Build configuration list for PBXNativeTarget "doomengine" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 3DE694471489AFDE0049CAA4 /* Debug */, + 3DE694481489AFDE0049CAA4 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 3DE694301489AFDE0049CAA4 /* Project object */; +} diff --git a/common/ios/doomengine.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/common/ios/doomengine.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100755 index 0000000..0cbbe8a --- /dev/null +++ b/common/ios/doomengine.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/common/ios/doomengine.xcodeproj/project.xcworkspace/xcuserdata/ryan.gerleve.xcuserdatad/UserInterfaceState.xcuserstate b/common/ios/doomengine.xcodeproj/project.xcworkspace/xcuserdata/ryan.gerleve.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100755 index 0000000..237da36 Binary files /dev/null and b/common/ios/doomengine.xcodeproj/project.xcworkspace/xcuserdata/ryan.gerleve.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/common/ios/doomengine.xcodeproj/xcshareddata/xcschemes/doomengine.xcscheme b/common/ios/doomengine.xcodeproj/xcshareddata/xcschemes/doomengine.xcscheme new file mode 100755 index 0000000..ad2651c --- /dev/null +++ b/common/ios/doomengine.xcodeproj/xcshareddata/xcschemes/doomengine.xcscheme @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/common/ios/doomengine.xcodeproj/xcuserdata/Farrand.xcuserdatad/xcschemes/xcschememanagement.plist b/common/ios/doomengine.xcodeproj/xcuserdata/Farrand.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..537f89f --- /dev/null +++ b/common/ios/doomengine.xcodeproj/xcuserdata/Farrand.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,22 @@ + + + + + SchemeUserState + + doomengine.xcscheme_^#shared#^_ + + orderHint + 2 + + + SuppressBuildableAutocreation + + 3DE694381489AFDE0049CAA4 + + primary + + + + + diff --git a/common/ios/doomengine.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/xcschememanagement.plist b/common/ios/doomengine.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100755 index 0000000..a1cca34 --- /dev/null +++ b/common/ios/doomengine.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,24 @@ + + + + + SchemeUserState + + doomengine.xcscheme_^#shared#^_ + + isShown + + orderHint + 2 + + + SuppressBuildableAutocreation + + 3DE694381489AFDE0049CAA4 + + primary + + + + + diff --git a/common/ios/doomengine.xcodeproj/xcuserdata/ryan.gerleve.xcuserdatad/xcschemes/xcschememanagement.plist b/common/ios/doomengine.xcodeproj/xcuserdata/ryan.gerleve.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100755 index 0000000..537f89f --- /dev/null +++ b/common/ios/doomengine.xcodeproj/xcuserdata/ryan.gerleve.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,22 @@ + + + + + SchemeUserState + + doomengine.xcscheme_^#shared#^_ + + orderHint + 2 + + + SuppressBuildableAutocreation + + 3DE694381489AFDE0049CAA4 + + primary + + + + + diff --git a/common/ios/doomengine/BackgroundMusic.cpp b/common/ios/doomengine/BackgroundMusic.cpp new file mode 100755 index 0000000..a3b54ef --- /dev/null +++ b/common/ios/doomengine/BackgroundMusic.cpp @@ -0,0 +1,541 @@ +/* + * BackgroundMusic.cpp + * doom + * + * Created by John Carmack on 5/15/09. + * Copyright 2009 Id Software. All rights reserved. + * + */ +/* + 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. + + */ + + +//================================================================================================== +// Includes +//================================================================================================== + +// System Includes +#include +#include +#include +#include +#include +#include +#include + +extern "C" { +#include "doomiphone.h" +} + +enum { + kSoundEngineErrUnitialized = 1, + kSoundEngineErrInvalidID = 2, + kSoundEngineErrFileNotFound = 3, + kSoundEngineErrInvalidFileFormat = 4, + kSoundEngineErrDeviceNotFound = 5 +}; + + +#define AssertNoError(inMessage, inHandler) \ +if(result != noErr) \ +{ \ +printf("%s: %d\n", inMessage, (int)result); \ +goto inHandler; \ +} + + +#define kNumberBuffers 3 + + +static Float32 gMasterVolumeGain = 0.5f; + + +//================================================================================================== +// Helper functions +//================================================================================================== + +OSStatus LoadFileDataInfo(const char *inFilePath, AudioFileID &outAFID, AudioStreamBasicDescription &outFormat, UInt64 &outDataSize) +{ + UInt32 thePropSize; + + CFURLRef theURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (UInt8*)inFilePath, strlen(inFilePath), false); + if (theURL == NULL) + return kSoundEngineErrFileNotFound; + + OSStatus result = AudioFileOpenURL(theURL, kAudioFileReadPermission, 0, &outAFID); + CFRelease(theURL); + AssertNoError("Error opening file", end); + + thePropSize = sizeof(outFormat); + result = AudioFileGetProperty(outAFID, kAudioFilePropertyDataFormat, &thePropSize, &outFormat); + AssertNoError("Error getting file format", end); + + thePropSize = sizeof(UInt64); + result = AudioFileGetProperty(outAFID, kAudioFilePropertyAudioDataByteCount, &thePropSize, &outDataSize); + AssertNoError("Error getting file data size", end); + +end: + return result; +} + +void CalculateBytesForTime (AudioStreamBasicDescription & inDesc, UInt32 inMaxPacketSize, Float64 inSeconds, UInt32 *outBufferSize, UInt32 *outNumPackets) +{ + static const UInt32 maxBufferSize = 0x10000; // limit size to 64K + static const UInt32 minBufferSize = 0x4000; // limit size to 16K + + if (inDesc.mFramesPerPacket) { + Float64 numPacketsForTime = inDesc.mSampleRate / inDesc.mFramesPerPacket * inSeconds; + *outBufferSize = (long unsigned int)numPacketsForTime * inMaxPacketSize; + } else { + // if frames per packet is zero, then the codec has no predictable packet == time + // so we can't tailor this (we don't know how many Packets represent a time period + // we'll just return a default buffer size + *outBufferSize = maxBufferSize > inMaxPacketSize ? maxBufferSize : inMaxPacketSize; + } + + // we're going to limit our size to our default + if (*outBufferSize > maxBufferSize && *outBufferSize > inMaxPacketSize) + *outBufferSize = maxBufferSize; + else { + // also make sure we're not too small - we don't want to go the disk for too small chunks + if (*outBufferSize < minBufferSize) + *outBufferSize = minBufferSize; + } + *outNumPackets = *outBufferSize / inMaxPacketSize; +} + +static Boolean MatchFormatFlags(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) +{ + UInt32 xFlags = x.mFormatFlags; + UInt32 yFlags = y.mFormatFlags; + + // match wildcards + if (x.mFormatID == 0 || y.mFormatID == 0 || xFlags == 0 || yFlags == 0) + return true; + + if (x.mFormatID == kAudioFormatLinearPCM) + { + // knock off the all clear flag + xFlags = xFlags & ~kAudioFormatFlagsAreAllClear; + yFlags = yFlags & ~kAudioFormatFlagsAreAllClear; + + // if both kAudioFormatFlagIsPacked bits are set, then we don't care about the kAudioFormatFlagIsAlignedHigh bit. + if (xFlags & yFlags & kAudioFormatFlagIsPacked) { + xFlags = xFlags & ~kAudioFormatFlagIsAlignedHigh; + yFlags = yFlags & ~kAudioFormatFlagIsAlignedHigh; + } + + // if both kAudioFormatFlagIsFloat bits are set, then we don't care about the kAudioFormatFlagIsSignedInteger bit. + if (xFlags & yFlags & kAudioFormatFlagIsFloat) { + xFlags = xFlags & ~kAudioFormatFlagIsSignedInteger; + yFlags = yFlags & ~kAudioFormatFlagIsSignedInteger; + } + + // if the bit depth is 8 bits or less and the format is packed, we don't care about endianness + if((x.mBitsPerChannel <= 8) && ((xFlags & kAudioFormatFlagIsPacked) == kAudioFormatFlagIsPacked)) + { + xFlags = xFlags & ~kAudioFormatFlagIsBigEndian; + } + if((y.mBitsPerChannel <= 8) && ((yFlags & kAudioFormatFlagIsPacked) == kAudioFormatFlagIsPacked)) + { + yFlags = yFlags & ~kAudioFormatFlagIsBigEndian; + } + + // if the number of channels is 0 or 1, we don't care about non-interleavedness + if (x.mChannelsPerFrame <= 1 && y.mChannelsPerFrame <= 1) { + xFlags &= ~kLinearPCMFormatFlagIsNonInterleaved; + yFlags &= ~kLinearPCMFormatFlagIsNonInterleaved; + } + } + return xFlags == yFlags; +} + +Boolean FormatIsEqual(AudioStreamBasicDescription x, AudioStreamBasicDescription y) +{ + // the semantics for equality are: + // 1) Values must match exactly + // 2) wildcard's are ignored in the comparison + +#define MATCH(name) ((x.name) == 0 || (y.name) == 0 || (x.name) == (y.name)) + + return + ((x.mSampleRate==0.) || (y.mSampleRate==0.) || (x.mSampleRate==y.mSampleRate)) + && MATCH(mFormatID) + && MatchFormatFlags(x, y) + && MATCH(mBytesPerPacket) + && MATCH(mFramesPerPacket) + && MATCH(mBytesPerFrame) + && MATCH(mChannelsPerFrame) + && MATCH(mBitsPerChannel) ; +} + +#pragma mark ***** BackgroundTrackMgr ***** +//================================================================================================== +// BackgroundTrackMgr class +//================================================================================================== +typedef struct BG_FileInfo { + std::string mFilePath; + AudioFileID mAFID; + AudioStreamBasicDescription mFileFormat; + UInt64 mFileDataSize; + //UInt64 mFileNumPackets; // this is only used if loading file to memory + Boolean mLoadAtOnce; + Boolean mFileDataInQueue; +} BackgroundMusicFileInfo; + +class BackgroundTrackMgr + { + public: + BackgroundTrackMgr(); + ~BackgroundTrackMgr(); + + void Teardown(); + + static void QueueCallback( void * inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inCompleteAQBuffer); + + OSStatus SetupQueue(BG_FileInfo *inFileInfo); + OSStatus SetupBuffers(BG_FileInfo *inFileInfo); + OSStatus LoadTrack(const char* inFilePath, Boolean inAddToQueue, Boolean inLoadAtOnce); + + OSStatus SetVolume(Float32 inVolume); + Float32 GetVolume() const; + + OSStatus Start(); + OSStatus Stop(Boolean inStopAtEnd); + + AudioQueueRef mQueue; + AudioQueueBufferRef mBuffers[kNumberBuffers]; + UInt32 mBufferByteSize; + SInt64 mCurrentPacket; + UInt32 mNumPacketsToRead; + Float32 mVolume; + AudioStreamPacketDescription * mPacketDescs; + static BG_FileInfo * CurFileInfo; + Boolean mStopAtEnd; + }; + +BG_FileInfo *BackgroundTrackMgr::CurFileInfo; + + +BackgroundTrackMgr::BackgroundTrackMgr() +: mQueue(0), +mBufferByteSize(0), +mCurrentPacket(0), +mNumPacketsToRead(0), +mVolume(1.0f), +mPacketDescs(NULL), +mStopAtEnd(false) +{ } + +BackgroundTrackMgr::~BackgroundTrackMgr() { + Teardown(); +} + +void BackgroundTrackMgr::Teardown() { + if (mQueue) { + AudioQueueDispose(mQueue, true); + mQueue = NULL; + } + if ( CurFileInfo ) { + AudioFileClose( CurFileInfo->mAFID); + delete CurFileInfo; + CurFileInfo = NULL; + } + if (mPacketDescs) { + delete[] mPacketDescs; + mPacketDescs = NULL; + } +} + + +void BackgroundTrackMgr::QueueCallback( void * inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inCompleteAQBuffer ) { + // dispose of the buffer if no longer in use + OSStatus result = noErr; + BackgroundTrackMgr *THIS = (BackgroundTrackMgr*)inUserData; + UInt32 nPackets = 0; + // loop the current buffer if the following: + // 1. file was loaded into the buffer previously + // 2. only one file in the queue + // 3. we have not been told to stop at playlist completion + if ((CurFileInfo->mFileDataInQueue) && (!THIS->mStopAtEnd)) { + nPackets = THIS->mNumPacketsToRead; + } else { + UInt32 numBytes; + while (nPackets == 0) { + // if loadAtOnce, get all packets in the file, otherwise ~.5 seconds of data + nPackets = THIS->mNumPacketsToRead; + result = AudioFileReadPackets(CurFileInfo->mAFID, false, &numBytes, THIS->mPacketDescs, THIS->mCurrentPacket, &nPackets, + inCompleteAQBuffer->mAudioData); + AssertNoError("Error reading file data", end); + + inCompleteAQBuffer->mAudioDataByteSize = numBytes; + + if (nPackets == 0) { // no packets were read, this file has ended. + if (CurFileInfo->mLoadAtOnce) { + CurFileInfo->mFileDataInQueue = true; + } + + THIS->mCurrentPacket = 0; + + // we have gone through the playlist. if mStopAtEnd, stop the queue here + if ( THIS->mStopAtEnd ) { + result = AudioQueueStop(inAQ, false); + AssertNoError("Error stopping queue", end); + return; + } + } + } + } + + result = AudioQueueEnqueueBuffer(inAQ, inCompleteAQBuffer, (THIS->mPacketDescs ? nPackets : 0), THIS->mPacketDescs); + if(result != noErr) { + result = AudioQueueFreeBuffer(inAQ, inCompleteAQBuffer); + AssertNoError("Error freeing buffers that didn't enqueue", end); + } + AssertNoError("Error enqueuing new buffer", end); + if (CurFileInfo->mLoadAtOnce) { + CurFileInfo->mFileDataInQueue = true; + } + + THIS->mCurrentPacket += nPackets; + +end: + return; +} + +OSStatus BackgroundTrackMgr::SetupQueue(BG_FileInfo *inFileInfo) { + UInt32 size = 0; + OSStatus err; + OSStatus result = AudioQueueNewOutput(&inFileInfo->mFileFormat, QueueCallback, this, + CFRunLoopGetMain() /* CFRunLoopGetCurrent() */, kCFRunLoopCommonModes, 0, &mQueue); + AssertNoError("Error creating queue", end); +#if 0 + // (2) If the file has a cookie, we should get it and set it on the AQ + size = sizeof(UInt32); + result = AudioFileGetPropertyInfo (inFileInfo->mAFID, kAudioFilePropertyMagicCookieData, &size, NULL); + + if (!result && size) { + char* cookie = new char [size]; + result = AudioFileGetProperty (inFileInfo->mAFID, kAudioFilePropertyMagicCookieData, &size, cookie); + AssertNoError("Error getting magic cookie", end); + result = AudioQueueSetProperty(mQueue, kAudioQueueProperty_MagicCookie, cookie, size); + delete [] cookie; + AssertNoError("Error setting magic cookie", end); + } +#endif + // channel layout + err = AudioFileGetPropertyInfo(inFileInfo->mAFID, kAudioFilePropertyChannelLayout, &size, NULL); + if (err == noErr && size > 0) { + AudioChannelLayout *acl = (AudioChannelLayout *)malloc(size); + result = AudioFileGetProperty(inFileInfo->mAFID, kAudioFilePropertyChannelLayout, &size, acl); + AssertNoError("Error getting channel layout from file", end); + result = AudioQueueSetProperty(mQueue, kAudioQueueProperty_ChannelLayout, acl, size); + free(acl); + AssertNoError("Error setting channel layout on queue", end); + } + + // volume + result = SetVolume(mVolume); + +end: + return result; +} + +OSStatus BackgroundTrackMgr::SetupBuffers(BG_FileInfo *inFileInfo) { + int numBuffersToQueue = kNumberBuffers; + UInt32 maxPacketSize; + UInt32 size = sizeof(maxPacketSize); + bool isFormatVBR; + // we need to calculate how many packets we read at a time, and how big a buffer we need + // we base this on the size of the packets in the file and an approximate duration for each buffer + + // first check to see what the max size of a packet is - if it is bigger + // than our allocation default size, that needs to become larger + OSStatus result = AudioFileGetProperty(inFileInfo->mAFID, kAudioFilePropertyPacketSizeUpperBound, &size, &maxPacketSize); + AssertNoError("Error getting packet upper bound size", end); + isFormatVBR = (inFileInfo->mFileFormat.mBytesPerPacket == 0 || inFileInfo->mFileFormat.mFramesPerPacket == 0); + + CalculateBytesForTime(inFileInfo->mFileFormat, maxPacketSize, 0.5/*seconds*/, &mBufferByteSize, &mNumPacketsToRead); + + // if the file is smaller than the capacity of all the buffer queues, always load it at once + if ((mBufferByteSize * numBuffersToQueue) > inFileInfo->mFileDataSize) { + inFileInfo->mLoadAtOnce = true; + } + + if (inFileInfo->mLoadAtOnce) { + UInt64 theFileNumPackets; + size = sizeof(UInt64); + result = AudioFileGetProperty(inFileInfo->mAFID, kAudioFilePropertyAudioDataPacketCount, &size, &theFileNumPackets); + AssertNoError("Error getting packet count for file", end); + + mNumPacketsToRead = (UInt32)theFileNumPackets; + mBufferByteSize = (UInt32)inFileInfo->mFileDataSize; + numBuffersToQueue = 1; + } else { + mNumPacketsToRead = mBufferByteSize / maxPacketSize; + } + + if (isFormatVBR) { + mPacketDescs = new AudioStreamPacketDescription [mNumPacketsToRead]; + } else { + mPacketDescs = NULL; // we don't provide packet descriptions for constant bit rate formats (like linear PCM) + } + + // allocate the queue's buffers + for (int i = 0; i < numBuffersToQueue; ++i) { + result = AudioQueueAllocateBuffer(mQueue, mBufferByteSize, &mBuffers[i]); + AssertNoError("Error allocating buffer for queue", end); + QueueCallback (this, mQueue, mBuffers[i]); + if (inFileInfo->mLoadAtOnce) { + inFileInfo->mFileDataInQueue = true; + } + } + +end: + return result; +} + +OSStatus BackgroundTrackMgr::LoadTrack(const char* inFilePath, Boolean inAddToQueue, Boolean inLoadAtOnce) { +// OSStatus result = LoadFileDataInfo(CurFileInfo->mFilePath.c_str(), CurFileInfo->mAFID, CurFileInfo->mFileFormat, CurFileInfo->mFileDataSize); +// AssertNoError("Error getting file data info", fail); + OSStatus result; + UInt32 thePropSize; + + CFURLRef theURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (UInt8*)inFilePath, strlen(inFilePath), false); + if (theURL == NULL) + result = kSoundEngineErrFileNotFound; + else + result = 0; + AssertNoError("Error opening URL", fail); + + CurFileInfo = new BG_FileInfo; + CurFileInfo->mFilePath = inFilePath; + + result = AudioFileOpenURL(theURL, kAudioFileReadPermission, 0, &CurFileInfo->mAFID); + CFRelease(theURL); + AssertNoError("Error opening file", fail); + + thePropSize = sizeof(CurFileInfo->mFileFormat); + result = AudioFileGetProperty(CurFileInfo->mAFID, kAudioFilePropertyDataFormat, &thePropSize, &CurFileInfo->mFileFormat); + AssertNoError("Error getting file format", fail); + + thePropSize = sizeof(UInt64); + result = AudioFileGetProperty(CurFileInfo->mAFID, kAudioFilePropertyAudioDataByteCount, &thePropSize, &CurFileInfo->mFileDataSize); + AssertNoError("Error getting file data size", fail); + + CurFileInfo->mLoadAtOnce = inLoadAtOnce; + CurFileInfo->mFileDataInQueue = false; + + result = SetupQueue(CurFileInfo); + AssertNoError("Error setting up queue", fail); + + result = SetupBuffers(CurFileInfo); + AssertNoError("Error setting up queue buffers", fail); + + return result; + +fail: + if (CurFileInfo) { + delete CurFileInfo; + CurFileInfo = NULL; + } + return result; +} + +OSStatus BackgroundTrackMgr::SetVolume(Float32 inVolume) { + mVolume = inVolume; + return AudioQueueSetParameter(mQueue, kAudioQueueParam_Volume, mVolume * gMasterVolumeGain); +} + +Float32 BackgroundTrackMgr::GetVolume() const { + return mVolume; +} + +OSStatus BackgroundTrackMgr::Start() { + OSStatus result = AudioQueuePrime(mQueue, 1, NULL); + if (result) { + printf("BackgroundTrackMgr: Error priming queue: %d\n", (int)result); + return result; + } + return AudioQueueStart(mQueue, NULL); +} + +OSStatus BackgroundTrackMgr::Stop(Boolean inStopAtEnd) { + if (inStopAtEnd) { + mStopAtEnd = true; + return noErr; + } else { + return AudioQueueStop(mQueue, true); + } +} + + +static BackgroundTrackMgr sBackgroundTrackMgr; + +static char currentMusicName[1024]; + +void iphonePauseMusic() { + if( music ) { + if ( music->value == 0 ) { + // music is disabled + return; + } + AudioQueuePause(sBackgroundTrackMgr.mQueue); + } +} +void iphoneResumeMusic() { + if ( music->value == 0 ) { + // music is disabled + return; + } + AudioQueueStart(sBackgroundTrackMgr.mQueue,NULL); +} +void iphoneStopMusic() { + sBackgroundTrackMgr.Teardown(); +} + +void iphoneStartMusic() { + if ( music->value == 0 ) { + // music is disabled + return; + } + char fullName[1024]; + sprintf( fullName, "%s/base/music/d_%s.mp3", SysIphoneGetAppDir(), currentMusicName ); + + printf( "Starting music '%s'\n", fullName ); + + iphoneStopMusic(); + sBackgroundTrackMgr.LoadTrack( fullName, false, true); + sBackgroundTrackMgr.Start(); + + if ( !strcmp( currentMusicName, "intro" ) ) { + // stop the intro music at end, don't loop + sBackgroundTrackMgr.mStopAtEnd = true; + } else { + sBackgroundTrackMgr.mStopAtEnd = false; + } +} + +void iphonePlayMusic( const char *name ) { + strcpy( currentMusicName, name ); + + iphoneStartMusic(); +} + + + + diff --git a/common/ios/doomengine/DoomGameCenterMatch.cpp b/common/ios/doomengine/DoomGameCenterMatch.cpp new file mode 100755 index 0000000..f0c9645 --- /dev/null +++ b/common/ios/doomengine/DoomGameCenterMatch.cpp @@ -0,0 +1,422 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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 "DoomGameCenterMatch.h" +#include "doomiphone.h" +#include "ios/ios_interface.h" + +#include +#include +#include + +DoomGameCenterMatch gDoomGameCenterMatch; + +std::string serverGameCenterID; +std::tr1::array playerIndexToIDMap; + +namespace { + bool IsServer() { + return setupPacket.gameID == localGameID; + } + + int numPlayersToJoin = 0; +} + +DoomGameCenterMatch::~DoomGameCenterMatch() { +} + +void DoomGameCenterMatch::createdMatchImpl() { + std::printf( "Created a DOOM match!\n" ); +} + +void DoomGameCenterMatch::allPlayersConnectedImpl( std::vector connectedPlayerIDs ) { + std::printf( "All players connected to a DOOM match!\n" ); + + // Send an initial setup packet if this is the server, this will cause clients to + // send their join packets. + if ( IsServer() ) { + printf( "Server broadcasting initial setup packet.\n" ); + + numPlayersToJoin = connectedPlayerIDs.size(); + assert( numPlayersToJoin > 0 ); + SendGameCenterSetup(); + } +} + +void DoomGameCenterMatch::playerConnectedImpl( std::string playerIdentifier ) { + std::printf( "Player %s connected!\n", playerIdentifier.c_str() ); +} + +void DoomGameCenterMatch::playerDisconnectedImpl( std::string playerIdentifier ) { + std::printf( "Player %s disconnected!\n", playerIdentifier.c_str() ); + + if ( IsServer() ) { + // Only the server tracks disconnected players. The next server packet sent to each + // client will have the new playeringame[MAXPLAYERS] info. + for ( int i = 0; i < MAXPLAYERS; ++i ) { + if ( playerIndexToIDMap[i] == playerIdentifier ) { + playeringame[i] = false; + } + } + } else { + // If we are a client, and the server is the one that disconnected, we're hosed. + if ( !netGameFailure && playerIdentifier == serverGameCenterID ) { + netGameFailure = NF_LOST_SERVER; + + idGameCenter::DisconnectFromMatch(); + + ShowSystemAlert( "#LostServerTitle", "#LostServerMessage" ); + + iphoneMainMenu(); + } + } +} + +template +const Type * end( const Type (&testArray)[Size] ) { + return testArray + Size; +} + +template +bool ArrayContains( const Type (&testArray)[Size], const Type & value ) { + return std::find( testArray, end( testArray ), value ) != end( testArray ); +} + +/* + ================== + DoomGameCenterMatch::receivedDataImpl + + A packet has been received from Game Center. Because the Game Center "callback" actually runs + on the main thread, it should be safe to directly process the packets here. This should only + be called in between displaylink updates. + ================== + */ +void DoomGameCenterMatch::receivedDataImpl( std::string fromPlayerID, const void * data, int numBytes ) { + + if ( numBytes < 4 ) { + std::printf( "discarding packet because numBytes = %i.\n", numBytes ); + return; + } + + int packetID = *(int *)data; + + if ( packetID == PACKET_VERSION_SETUP ) { + std::printf( "Received a setup packet!\n" ); + + // Only the server sends setup packets, and we need to keep track of it's ID. + serverGameCenterID = fromPlayerID; + + if ( localGameID == setupPacket.gameID ) { + // if we are sending packets, always ignore other setup packets + printf( "discarding setup packet because we are the server\n" ); + return; + } + setupPacketFrameNum = iphoneFrameNum; + + // save this packet + setupPacket = *(packetSetup_t *)data; + + // Send a join packet to the server so that it's aware of this client, if this client + // isn't already in the list. + if ( !ArrayContains( setupPacket.playerID, localGameID ) ) { + printf( "This client has not notified the server yet - sending join packet.\n" ); + SendJoinPacket(); + } + + // check for game start in a received setup packet + if ( !netgame && setupPacket.startGame ) { + StartupWithCorrectWads( setupPacket.map.dataset ); + + ShowGLView(); + + if ( StartNetGame() ) { + setupPacket.startGame = false; + // we aren't in this game + } + + + } + + return; + } + + if ( packetID == PACKET_VERSION_JOIN ) { + // we should only process join packets if we are running the current game + if ( setupPacket.gameID != localGameID ) { + printf( "discarding join packet because we aren't the server\n" ); + return; + } + + packetJoin_t *pj = (packetJoin_t *)data; + if ( pj->playerID == 0 ) { + // should never happen + printf( "discarding join packet because playerID is 0\n" ); + return; + } + // add this player + int i; + for ( i = 0 ; i < MAXPLAYERS ; i++ ) { + if ( setupPacket.playerID[i] == pj->playerID ) { + netPlayers[i].peer.lastPacketTime = SysIphoneMilliseconds(); + break; + } + } + if ( i == MAXPLAYERS ) { + // not in yet, add if possible + for ( i = 0 ; i < MAXPLAYERS ; i++ ) { + if ( setupPacket.playerID[i] == 0 ) { + setupPacket.playerID[i] = pj->playerID; + + // Save this client's GameCenter ID to send it packets later. + playerIndexToIDMap[i] = fromPlayerID; + + //netPlayers[i].peer.address = *from; + netPlayers[i].peer.lastPacketTime = SysIphoneMilliseconds(); + + --numPlayersToJoin; + + break; + } + } + // if all players are active, the new join gets ignored + } + + printf( "valid join packet from %s\n", fromPlayerID.c_str() ); + + if ( numPlayersToJoin == 0 ) { + std::printf( "Server starting the game!\n" ); + + // Got the join packet from everyone, start the game! + setupPacket.startGame = 1; + + StartupWithCorrectWads( setupPacket.map.dataset ); + + StartNetGame(); + ShowGLView(); + } + + // Broadcast another setup packet to let each client know that someone else joined. + SendGameCenterSetup(); + + return; + } + + + // The only other packets we should be recieving are client and server packets. This call + // will handle those. + iphoneProcessPacket( NULL, data, numBytes ); + + return; +} + + + + +void SetupEmptyNetGame() { + // Disconnect from any previous multiplayer game + idGameCenter::DisconnectFromMatch(); + + // no current setup packet, so initialize with this phone's default values + localGameID = SysIphoneMicroseconds(); + memset( &setupPacket, 0, sizeof( setupPacket ) ); + setupPacket.gameID = localGameID; + setupPacket.packetType = PACKET_VERSION_SETUP; + setupPacket.map.dataset = mpExpansion->value; + setupPacket.map.episode = mpEpisode->value; + setupPacket.map.map = mpMap->value; + setupPacket.map.skill = mpSkill->value; + setupPacket.deathmatch = mpDeathmatch->value; + setupPacket.timelimit = timeLimit->value; + setupPacket.fraglimit = fragLimit->value; + setupPacket.playerID[0] = playerID; +} + +/* + ================== + SendJoinPacket + + These will be sent to the server ever frame we are in the multiplayer menu. + ================== + */ +void SendJoinPacket() { + packetJoin_t pj; + + pj.packetType = PACKET_VERSION_JOIN; + pj.gameID = setupPacket.gameID; + pj.playerID = playerID; + + idGameCenter::SendPacketToPlayerReliable( serverGameCenterID, &pj, sizeof( pj ) ); +} + +/* + ================== + SendGameCenterSetup + + the server sends out a setup packet to each joined client so they + can see the game options needed to start the game. + ================== + */ +void SendGameCenterSetup() { + if ( setupPacket.gameID != localGameID ) { + // we aren't the server + return; + } + + if ( gametic >= 2 ) { + // everyone has already started, so they don't need more setup packets + return; + } + + setupPacket.sendCount++; + idGameCenter::BroadcastPacketReliable( &setupPacket, sizeof( setupPacket ) ); + +} + + + + + + + +//------------------------ +// In order to facilitate automatching through Game Center, we can use a 32-bit playerGroup +// value. Players will only be matched with other players with the exact same playerGroup. +// Unfortunately, there doesn't seem to be a way to do more complex logical operations, such +// as match a player who is willing to play on any map with a player who has chosen a specific +// map. +// +// These functions will take the game setup parameters and create a 32-bit playerGroup value to +// match with other players who have chosen the same settings. +// +// In order to pack the game parameters into 32 bits, we use the following information: +// +// Deathmatch field requires 2 bits for 4 possible values. +// This will be 0 for co-op, 1 for deathmatch, and 2 for altdeath. +// +// Expansion pack field requires 3 bits for 8 possible values, but we only have 5 expansions +// currently. +// This will simply be the enum value of iphoneMissionPack_t. +// +// Map number will require 5 bits for 32 possible maps per expansion, but let's use 6 since a) +// we have the space b) it allows for future expansion and c) allows us to start counting at 1, +// which is the natural first index for map nums. +// +// The frag limit is capped by us at 20, so we'll use 5 bits for this value. +// Zero here will indicate an infinite frag limit. +// +// The time limit is capped to 20 minutes, so we'll use 5 bits for this value. +// Zero here will indicate unlimited time. +// +// Skill will require 3 bits for 8 possible values, as there are 5 skill levels. +// +// In summary, we will need 2 + 3 + 6 + 5 + 5 + 3 = 24 bits to completely specify multiplayer +// parameters. +// +// So, the actual format of the playerGroup is: +// +// Bits 0-1: Match type. +// Bits 2-4: Expansion pack. +// Bits 5-10: Map number. +// Bits 11-15: Frag limit. +// Bits 16-20: Time limit in minutes. +// Bits 21-23: Skill level. +//------------------------ + +namespace { + const unsigned int deathmatchGroupNumBits = 2; + const unsigned int expansionGroupNumBits = 3; + const unsigned int mapGroupNumBits = 6; + const unsigned int fragLimitGroupNumBits = 5; + const unsigned int timeLimitGroupNumBits = 5; + + // Currently unused + //static const unsigned int skillGroupNumBits = 3; + + const unsigned int deathmatchGroupOffset = 0; + const unsigned int expansionGroupOffset = deathmatchGroupOffset + deathmatchGroupNumBits; + const unsigned int mapGroupOffset = expansionGroupOffset + expansionGroupNumBits; + const unsigned int fragLimitGroupOffset = mapGroupOffset + mapGroupNumBits; + const unsigned int timeLimitGroupOffset = fragLimitGroupOffset + fragLimitGroupNumBits; + const unsigned int skillGroupOffset = timeLimitGroupOffset + timeLimitGroupNumBits; +} + +//------------------------ +// deathmatch: 1 for deathmatch, 2 for altdeath, 0 for cooperative +//------------------------ +std::tr1::uint32_t GeneratePlayerGroup( const int deathmatch, + const int missionPack, + const int mapNum, + const int fragLimit, + const int timeLimit, + const int skill ) { + + + const int deathmatchGroup = deathmatch << deathmatchGroupOffset; + const int expansionGroup = static_cast( missionPack ) << expansionGroupOffset; + const int mapNumGroup = mapNum << mapGroupOffset; + const int tempFragLimitGroup = fragLimit << fragLimitGroupOffset; + const int tempTimeLimitGroup = timeLimit << timeLimitGroupOffset; + const int tempSkillGroup = skill << skillGroupOffset; + + // Don't let deathmatch or co-op specific options influence the matchmaking process. + // If deathmatch, always set skill to 0. + // If co-op, always set frag limit and time limit to 0. + const int fragLimitGroup = ( deathmatch == 0 ) ? 0 : tempFragLimitGroup; + const int timeLimitGroup = ( deathmatch == 0 ) ? 0 : tempTimeLimitGroup; + const int skillGroup = ( deathmatch != 0 ) ? 0 : tempSkillGroup; + + const int playerGroup = deathmatchGroup + | expansionGroup + | mapNumGroup + | fragLimitGroup + | timeLimitGroup + | skillGroup; + + return playerGroup; +} + + + +//------------------------ +// Converts a playerGroup from Game Center into a setupPacket_t +//------------------------ +packetSetup_t GenerateSetupPacketFromPlayerGroup( std::tr1::uint32_t playerGroup ) { + packetSetup_t packet; + + packet.packetType = PACKET_VERSION_SETUP; + packet.gameID = 0; + packet.startGame = 0; + packet.sendCount = 0; + + packet.map.dataset = 0; + packet.map.episode = 0; + packet.map.map = 0; + packet.map.skill = 0; + + packet.deathmatch = 0; + packet.fraglimit = 0; + packet.timelimit = 0; + + std::fill( packet.playerID, packet.playerID + sizeof( packet.playerID ), 0 ); + + return packet; +} + + diff --git a/common/ios/doomengine/DoomGameCenterMatch.h b/common/ios/doomengine/DoomGameCenterMatch.h new file mode 100755 index 0000000..126d716 --- /dev/null +++ b/common/ios/doomengine/DoomGameCenterMatch.h @@ -0,0 +1,62 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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. + + */ + +#ifndef DOOM_GAME_CENTER_MATCH_H +#define DOOM_GAME_CENTER_MATCH_H + +#include "ios/GameCenter.h" +#include "iphone_doom.h" + +#include +#include +#include +#include + +class DoomGameCenterMatch : public idGameCenterMatchHandler { +public: + virtual ~DoomGameCenterMatch(); + +private: + virtual void createdMatchImpl(); + virtual void allPlayersConnectedImpl( std::vector connectedPlayerIDs ); + virtual void playerConnectedImpl( std::string playerIdentifier ); + virtual void playerDisconnectedImpl( std::string playerIdentifier ); + + virtual void receivedDataImpl( std::string fromPlayerID, const void * data, int numBytes ); +}; + +extern DoomGameCenterMatch gDoomGameCenterMatch; +extern std::string serverGameCenterID; +extern std::tr1::array playerIndexToIDMap; + +void SetupEmptyNetGame(); +void SendGameCenterSetup(); +void SendJoinPacket(); + +std::tr1::uint32_t GeneratePlayerGroup( const int deathmatch, + const int missionPack, + const int mapNum, + const int fragLimit, + const int timeLimit, + const int skill ); + +packetSetup_t GenerateSetupPacketFromPlayerGroup( std::tr1::uint32_t playerGroup ); + +#endif diff --git a/common/ios/doomengine/EAGLView.h b/common/ios/doomengine/EAGLView.h new file mode 100755 index 0000000..82b190a --- /dev/null +++ b/common/ios/doomengine/EAGLView.h @@ -0,0 +1,48 @@ +/* + + Copyright (C) 2009 Id Software, 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 + 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. + + */ + + +#import +#import +#import +#import + +/* +This class wraps the CAEAGLLayer from CoreAnimation into a convenient UIView subclass. +The view content is basically an EAGL surface you render your OpenGL scene into. +Note that setting the view non-opaque will only work if the EAGL surface has an alpha channel. +*/ +@interface EAGLView : UIView { +@public + UITextField *textField; + + GLuint mViewRenderbuffer; + GLuint mViewFramebuffer; + GLuint mDepthRenderbuffer; + +@private + /* The pixel dimensions of the backbuffer */ + GLint backingWidth; + GLint backingHeight; +} + +- (void) Initialize; + +@end diff --git a/common/ios/doomengine/EAGLView.m b/common/ios/doomengine/EAGLView.m new file mode 100755 index 0000000..eab48ac --- /dev/null +++ b/common/ios/doomengine/EAGLView.m @@ -0,0 +1,371 @@ +// +// EAGLView.m +// Doom +// +// Created by Cass Everitt on 2/20/09. +// Copyright Id Software 2009. All rights reserved. +// +/* + + Copyright (C) 2009 Id Software, 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 + 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. + + */ + + + + +#import +#import + +#import "EAGLView.h" + +#include "doomiphone.h" + +#include + +EAGLView *eaglview; +EAGLContext *context; + +@implementation EAGLView + +// You must implement this method ++ (Class)layerClass { + return [CAEAGLLayer class]; +} + +float screenResolutionScale = 1.0f; + +CAEAGLLayer *eaglLayer; + +- (void) Initialize { + + eaglview = self; + + // allow multiple touch events + self.multipleTouchEnabled = true; + + // Double the resolution on iPhone 4. + if ( [[UIScreen mainScreen] respondsToSelector:@selector(scale)] && + [self respondsToSelector:@selector(setContentScaleFactor:)] ) { + + screenResolutionScale = [UIScreen mainScreen].scale; + + // set scaling factor + [self setContentScaleFactor:[UIScreen mainScreen].scale]; + } + + // Get the layer + eaglLayer = (CAEAGLLayer *)self.layer; + + // set opaque so UIKit doesn't try to blend it over other layers + eaglLayer.opaque = YES; + + // set it to no-backing-retained so it can do ast pageflips instead + // of update copies, and go to 565 bit depth for higher performance. + eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys: + + [NSNumber numberWithBool:NO], + kEAGLDrawablePropertyRetainedBacking, + + kEAGLColorFormatRGB565, + /* kEAGLColorFormatRGBA8, */ + kEAGLDrawablePropertyColorFormat, + + nil]; + + context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1]; + assert( context ); + + if ( ![EAGLContext setCurrentContext:context]) { + [self release]; + return; + } + + glGenFramebuffersOES(1, &mViewFramebuffer); + glGenRenderbuffersOES(1, &mViewRenderbuffer); + + glBindFramebufferOES(GL_FRAMEBUFFER_OES, mViewFramebuffer); + glBindRenderbufferOES(GL_RENDERBUFFER_OES, mViewRenderbuffer); + + [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer*)self.layer]; + + glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, mViewRenderbuffer); + + // the backing sizes should be the same as the screen + glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth); + glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight); + + displaywidth = backingHeight; + displayheight = backingWidth; + + glGenRenderbuffersOES(1, &mDepthRenderbuffer); + glBindRenderbufferOES(GL_RENDERBUFFER_OES, mDepthRenderbuffer); + glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, backingWidth, backingHeight); + glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, mDepthRenderbuffer); + + // the framebuffer will stay constant + glBindRenderbufferOES(GL_RENDERBUFFER_OES, mViewRenderbuffer); + glBindFramebufferOES(GL_FRAMEBUFFER_OES, mViewFramebuffer); + + if ( glCheckFramebufferStatusOES( GL_FRAMEBUFFER_OES ) != GL_FRAMEBUFFER_COMPLETE_OES ) { + printf( "Failed to make complete framebuffer object %x", glCheckFramebufferStatusOES( GL_FRAMEBUFFER_OES ) ); + assert( 0 ); + } + + return; +} + +- (id) initWithCoder:(NSCoder *)aCoder{ + + if(self = [super initWithCoder:aCoder] ) { + [self Initialize]; + } + + return self; +} + +- (id) initWithFrame:(CGRect)rect{ + if(self = [super initWithFrame:rect] ) { + [self Initialize]; + } + return self; +} + +- (void) handleTouches:(UIEvent*)event { + int touchCount = 0; + static int previousTouchCount; + static int touchRover; + int touchThisSequence[MAX_TOUCHES]; + + memset( touchThisSequence, 0, sizeof( touchThisSequence ) ); + + NSSet *theTouches = [event allTouches]; +// printf( "count: %i\n", [touches count] ); + + for (UITouch *myTouch in theTouches) + { + CGPoint touchLocation = [myTouch locationInView:self]; + + // Scale Touches with the screen resolution. + touchLocation.x *= screenResolutionScale; + touchLocation.y *= screenResolutionScale; + + const int x = touchLocation.x; + const int y = touchLocation.y; +// printf( "%i, %i\n", x, y ); + touchCount++; + + + touch_t *t2; + + // find which one it is closest to + int minDist = 64 * 64; // allow up to 64 unit moves to be drags + int minIndex = -1; + for ( int i = 0 ; i < MAX_TOUCHES ; i++ ) { + t2 = &sysTouches[i]; + if ( !t2->down ) { + continue; + } + int dist = ( t2->x - x ) * ( t2->x - x ) + ( t2->y - y ) * ( t2->y - y ); + if ( dist < minDist ) { + minDist = dist; + minIndex = i; + } + } + if ( minIndex != -1 ) { + // reuse a touch + sysTouches[minIndex].x = x; + sysTouches[minIndex].y = y; + if (myTouch.phase == UITouchPhaseEnded) { + // if this was released before the game got to see it, + // make it a special case + if ( sysTouches[minIndex].stateCount == 1 ) { + // leave it in the down state with a special count + sysTouches[minIndex].stateCount = -1; +// printf( "Tap release touch on a reuse\n" ); + } else { + sysTouches[minIndex].down = false; + sysTouches[minIndex].stateCount = 1; +// printf( "Release touch on a reuse\n" ); + } + } else { + if (myTouch.phase == UITouchPhaseBegan) { + sysTouches[minIndex].stateCount = 1; + sysTouches[minIndex].controlOwner = NULL; +// printf( "Begin touch on a reuse\n" ); + } else { +// printf( "Drag touch on a reuse\n" ); + } + sysTouches[minIndex].down = true; + } + touchThisSequence[minIndex] = true; + } else { + if ( myTouch.phase != UITouchPhaseBegan ) { + printf( "Non-local touch wasn't a begin\n" ); + } else { + // allocate a new one + // grab the next rover spot + // don't just use first-not-down, because that might + // cause the release to be missed by the game code. + int i, j; + for ( j = 0 ; j < MAX_TOUCHES ; j++ ) { + i = touchRover; + t2 = &sysTouches[i]; + touchRover = ( touchRover + 1 ) % MAX_TOUCHES; + if ( !t2->down ) { + break; + } + } + if ( j == MAX_TOUCHES ) { + printf( "MAX_TOUCHES, clearing everything!\n" ); + memset( sysTouches, 0, sizeof( sysTouches ) ); + continue; + } +// printf( "new touch down\n" ); + t2->x = x; + t2->y = y; + t2->down = true; + t2->controlOwner = NULL; + t2->stateCount = 1; + + touchThisSequence[i] = true; + } + } + } + // Change any active touches to released if they weren't + // in the touch set. This will happen if we forced a break because + // a "moved" event was so large that it was very likely a release and + // press of a different finger that happened to be in the same frame. + for ( int i = 0 ; i < MAX_TOUCHES ; i++ ) { + if ( sysTouches[i].down && !touchThisSequence[i] ) { + printf( "clearing touch %i\n", i ); + sysTouches[i].down = false; + sysTouches[i].stateCount = 0; + touchCount--; + } + } + + // toggle the console with four touches + if ( touchCount == 4 && previousTouchCount != 4 ) { + touchCount = 0; // won't get the releases, because the text field will eat them + + if ( textField == nil ) { + // do this before starting the textField, which + // takes a long time + // iphoneActivateConsole(); + + textField = [UITextField alloc]; + [textField initWithFrame:CGRectMake( 0, 0, 20, 20 ) ]; + [self addSubview:textField]; + [textField release]; + textField.hidden = true; + textField.delegate = self; + textField.autocapitalizationType = UITextAutocapitalizationTypeNone; + textField.autocorrectionType = UITextAutocorrectionTypeNo; + [textField becomeFirstResponder]; + } else { + } + } + + previousTouchCount = touchCount; +} + + +- (void) touchesBegan:(NSSet*)touchSet withEvent:(UIEvent*)event { + (void)touchSet; + + [self handleTouches:event]; +} + +- (void)touchesMoved:(NSSet *)touchSet withEvent:(UIEvent *)event { + (void)touchSet; + + [self handleTouches:event]; +} + +- (void) touchesEnded:(NSSet*)touchSet withEvent:(UIEvent*)event { + (void)touchSet; + + [self handleTouches:event]; +} + +- (void)touchesCancelled:(NSSet *)touchSet withEvent:(UIEvent *)event { + (void)touchSet; + + [self handleTouches:event]; +} + + + +@end + + +@implementation EAGLView (UITextFieldDelegate) + +char consoleCommand[1024]; + +- (BOOL)textFieldShouldReturn:(UITextField *)_textField +{ + (void)_textField; + + if ( eaglview->textField == nil ) { + return YES; + } + + // we can't just execute this, because we are running in another + // thread, so fetch the line and the game will catch it next time + // around + + const char *line = [ eaglview->textField.text UTF8String ]; + strncpy( consoleCommand, line, sizeof(consoleCommand)-1 ); + eaglview->textField.text = [ NSString stringWithUTF8String: "" ]; + + // put it away + [textField resignFirstResponder]; + [textField removeFromSuperview]; + textField = nil; + + + return YES; +} + +@end + + +const char * SysIPhoneGetConsoleTextField() { + if ( eaglview->textField == nil ) { + return ""; + } + return [ eaglview->textField.text UTF8String ]; +} + +void SysIPhoneSetConsoleTextField( const char * str) { + assert( eaglview->textField != nil ); + eaglview->textField.text = [ NSString stringWithUTF8String: str ]; +} + +void SysIPhoneSwapBuffers() { + + glBindRenderbufferOES(GL_RENDERBUFFER_OES, eaglview->mViewRenderbuffer); + + // present the renderbuffer for display + [context presentRenderbuffer:GL_RENDERBUFFER_OES]; + +} + + + diff --git a/common/ios/doomengine/SoundEngine.cpp b/common/ios/doomengine/SoundEngine.cpp new file mode 100755 index 0000000..d6ccc35 --- /dev/null +++ b/common/ios/doomengine/SoundEngine.cpp @@ -0,0 +1,1818 @@ +/* + +File: SoundEngine.cpp +Abstract: These functions play background music tracks, multiple sound effects, +and support stereo panning with a low-latency response. + +Version: 1.7 + +Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. +("Apple") in consideration of your agreement to the following terms, and your +use, installation, modification or redistribution of this Apple software +constitutes acceptance of these terms. If you do not agree with these terms, +please do not use, install, modify or redistribute this Apple software. + +In consideration of your agreement to abide by the following terms, and subject +to these terms, Apple grants you a personal, non-exclusive license, under +Apple's copyrights in this original Apple software (the "Apple Software"), to +use, reproduce, modify and redistribute the Apple Software, with or without +modifications, in source and/or binary forms; provided that if you redistribute +the Apple Software in its entirety and without modifications, you must retain +this notice and the following text and disclaimers in all such redistributions +of the Apple Software. +Neither the name, trademarks, service marks or logos of Apple Inc. may be used +to endorse or promote products derived from the Apple Software without specific +prior written permission from Apple. Except as expressly stated in this notice, +no other rights or licenses, express or implied, are granted by Apple herein, +including but not limited to any patent rights that may be infringed by your +derivative works or by other works in which the Apple Software may be +incorporated. + +The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO +WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED +WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN +COMBINATION WITH YOUR PRODUCTS. + +IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR +DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF +CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Copyright (C) 2008 Apple Inc. All Rights Reserved. + +*/ + +// Local Includes +#include "SoundEngine.h" + +#ifndef WIN32 +/*================================================================================================== + SoundEngine.cpp +==================================================================================================*/ + +//================================================================================================== +// Includes +//================================================================================================== + +// System Includes +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define AssertNoError(inMessage, inHandler) \ + if(result != noErr) \ + { \ + printf("%s: %d\n", inMessage, (int)result); \ + goto inHandler; \ + } + +#define AssertNoOALError(inMessage, inHandler) \ + if((result = alGetError()) != AL_NO_ERROR) \ + { \ + printf("%s: %x\n", inMessage, (int)result); \ + goto inHandler; \ + } + +#define kNumberBuffers 3 + +class OpenALObject; +class BackgroundTrackMgr; + +static OpenALObject *sOpenALObject = NULL; +static BackgroundTrackMgr *sBackgroundTrackMgr = NULL; +static Float32 gMasterVolumeGain = 1.0f; +static bool isInitialized = false; +static bool gInterrupted = false; + + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +typedef ALvoid AL_APIENTRY (*alBufferDataStaticProcPtr) (const ALint bid, ALenum format, ALvoid* data, ALsizei size, ALsizei freq); +ALvoid alBufferDataStaticProc(const ALint bid, ALenum format, ALvoid* data, ALsizei size, ALsizei freq) +{ + static alBufferDataStaticProcPtr proc = NULL; + + if (proc == NULL) { + proc = (alBufferDataStaticProcPtr) alcGetProcAddress(NULL, (const ALCchar*) "alBufferDataStatic"); + } + + if (proc) + proc(bid, format, data, size, freq); + + return; +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +typedef ALvoid AL_APIENTRY (*alcMacOSXMixerOutputRateProcPtr) (const ALdouble value); +ALvoid alcMacOSXMixerOutputRateProc(const ALdouble value) +{ + static alcMacOSXMixerOutputRateProcPtr proc = NULL; + + if (proc == NULL) { + proc = (alcMacOSXMixerOutputRateProcPtr) alcGetProcAddress(NULL, (const ALCchar*) "alcMacOSXMixerOutputRate"); + } + + if (proc) + proc(value); + + return; +} + +#pragma mark ***** OpenALThread ***** +//================================================================================================== +// Threading functions +//================================================================================================== +class OpenALThread +{ +// returns the thread's priority as it was last set by the API +#define OpenALThread_SET_PRIORITY 0 +// returns the thread's priority as it was last scheduled by the Kernel +#define OpenALThread_SCHEDULED_PRIORITY 1 + +// Types +public: + typedef void* (*ThreadRoutine)(void* inParameter); + +// Constants +public: + enum + { + kMinThreadPriority = 1, + kMaxThreadPriority = 63, + kDefaultThreadPriority = 31 + }; + +// Construction/Destruction +public: + OpenALThread(ThreadRoutine inThreadRoutine, void* inParameter) + : mPThread(0), + mSpawningThreadPriority(getScheduledPriority(pthread_self(), OpenALThread_SET_PRIORITY)), + mThreadRoutine(inThreadRoutine), + mThreadParameter(inParameter), + mPriority(kDefaultThreadPriority), + mFixedPriority(false), + mAutoDelete(true) { } + + ~OpenALThread() { } + +// Properties + bool IsRunning() const { return 0 != mPThread; } + void SetAutoDelete(bool b) { mAutoDelete = b; } + + void SetPriority(UInt32 inPriority, bool inFixedPriority) + { + OSStatus result = noErr; + mPriority = inPriority; + mFixedPriority = inFixedPriority; + if(mPThread != 0) + { + if (mFixedPriority) + { + thread_extended_policy_data_t theFixedPolicy; + theFixedPolicy.timeshare = false; // set to true for a non-fixed thread + result = thread_policy_set(pthread_mach_thread_np(mPThread), THREAD_EXTENDED_POLICY, (thread_policy_t)&theFixedPolicy, THREAD_EXTENDED_POLICY_COUNT); + if (result) { + printf("OpenALThread::SetPriority: failed to set the fixed-priority policy"); + return; + } + } + // We keep a reference to the spawning thread's priority around (initialized in the constructor), + // and set the importance of the child thread relative to the spawning thread's priority. + thread_precedence_policy_data_t thePrecedencePolicy; + + thePrecedencePolicy.importance = mPriority - mSpawningThreadPriority; + result =thread_policy_set(pthread_mach_thread_np(mPThread), THREAD_PRECEDENCE_POLICY, (thread_policy_t)&thePrecedencePolicy, THREAD_PRECEDENCE_POLICY_COUNT); + if (result) { + printf("OpenALThread::SetPriority: failed to set the precedence policy"); + return; + } + } + } +// Actions + void Start() + { + if(mPThread != 0) + { + printf("OpenALThread::Start: can't start because the thread is already running\n"); + return; + } + + OSStatus result; + pthread_attr_t theThreadAttributes; + + result = pthread_attr_init(&theThreadAttributes); + AssertNoError("Error initializing thread", end); + + result = pthread_attr_setdetachstate(&theThreadAttributes, PTHREAD_CREATE_DETACHED); + AssertNoError("Error setting thread detach state", end); + + result = pthread_create(&mPThread, &theThreadAttributes, (ThreadRoutine)OpenALThread::Entry, this); + AssertNoError("Error creating thread", end); + + pthread_attr_destroy(&theThreadAttributes); + AssertNoError("Error destroying thread attributes", end); +end: + return; + } + +// Implementation +protected: + static void* Entry(OpenALThread* inOpenALThread) + { + void* theAnswer = NULL; + + inOpenALThread->SetPriority(inOpenALThread->mPriority, inOpenALThread->mFixedPriority); + + if(inOpenALThread->mThreadRoutine != NULL) + { + theAnswer = inOpenALThread->mThreadRoutine(inOpenALThread->mThreadParameter); + } + + inOpenALThread->mPThread = 0; + if (inOpenALThread->mAutoDelete) + delete inOpenALThread; + return theAnswer; + } + + static UInt32 getScheduledPriority(pthread_t inThread, int inPriorityKind) + { + thread_basic_info_data_t threadInfo; + policy_info_data_t thePolicyInfo; + unsigned int count; + + if (inThread == NULL) + return 0; + + // get basic info + count = THREAD_BASIC_INFO_COUNT; + thread_info (pthread_mach_thread_np (inThread), THREAD_BASIC_INFO, (thread_info_t)&threadInfo, &count); + + switch (threadInfo.policy) { + case POLICY_TIMESHARE: + count = POLICY_TIMESHARE_INFO_COUNT; + thread_info(pthread_mach_thread_np (inThread), THREAD_SCHED_TIMESHARE_INFO, (thread_info_t)&(thePolicyInfo.ts), &count); + if (inPriorityKind == OpenALThread_SCHEDULED_PRIORITY) { + return thePolicyInfo.ts.cur_priority; + } + return thePolicyInfo.ts.base_priority; + break; + + case POLICY_FIFO: + count = POLICY_FIFO_INFO_COUNT; + thread_info(pthread_mach_thread_np (inThread), THREAD_SCHED_FIFO_INFO, (thread_info_t)&(thePolicyInfo.fifo), &count); + if ( (thePolicyInfo.fifo.depressed) && (inPriorityKind == OpenALThread_SCHEDULED_PRIORITY) ) { + return thePolicyInfo.fifo.depress_priority; + } + return thePolicyInfo.fifo.base_priority; + break; + + case POLICY_RR: + count = POLICY_RR_INFO_COUNT; + thread_info(pthread_mach_thread_np (inThread), THREAD_SCHED_RR_INFO, (thread_info_t)&(thePolicyInfo.rr), &count); + if ( (thePolicyInfo.rr.depressed) && (inPriorityKind == OpenALThread_SCHEDULED_PRIORITY) ) { + return thePolicyInfo.rr.depress_priority; + } + return thePolicyInfo.rr.base_priority; + break; + } + + return 0; + } + + pthread_t mPThread; + UInt32 mSpawningThreadPriority; + ThreadRoutine mThreadRoutine; + void* mThreadParameter; + SInt32 mPriority; + bool mFixedPriority; + bool mAutoDelete; // delete self when thread terminates +}; + +//================================================================================================== +// Helper functions +//================================================================================================== +OSStatus OpenFile(const char *inFilePath, AudioFileID &outAFID) +{ + + CFURLRef theURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (UInt8*)inFilePath, strlen(inFilePath), false); + if (theURL == NULL) + return kSoundEngineErrFileNotFound; + +#if TARGET_OS_IPHONE + OSStatus result = AudioFileOpenURL(theURL, kAudioFileReadPermission, 0, &outAFID); +#else + OSStatus result = AudioFileOpenURL(theURL, fsRdPerm, 0, &outAFID); +#endif + CFRelease(theURL); + AssertNoError("Error opening file", end); + end: + return result; +} + +OSStatus LoadFileDataInfo(const char *inFilePath, AudioFileID &outAFID, AudioStreamBasicDescription &outFormat, UInt64 &outDataSize) +{ + UInt32 thePropSize = sizeof(outFormat); + OSStatus result = OpenFile(inFilePath, outAFID); + AssertNoError("Error opening file", end); + + result = AudioFileGetProperty(outAFID, kAudioFilePropertyDataFormat, &thePropSize, &outFormat); + AssertNoError("Error getting file format", end); + + thePropSize = sizeof(UInt64); + result = AudioFileGetProperty(outAFID, kAudioFilePropertyAudioDataByteCount, &thePropSize, &outDataSize); + AssertNoError("Error getting file data size", end); + +end: + return result; +} + +void CalculateBytesForTime (AudioStreamBasicDescription & inDesc, UInt32 inMaxPacketSize, Float64 inSeconds, UInt32 *outBufferSize, UInt32 *outNumPackets) +{ + static const UInt32 maxBufferSize = 0x10000; // limit size to 64K + static const UInt32 minBufferSize = 0x4000; // limit size to 16K + + if (inDesc.mFramesPerPacket) { + Float64 numPacketsForTime = inDesc.mSampleRate / inDesc.mFramesPerPacket * inSeconds; + *outBufferSize = (long unsigned int)numPacketsForTime * inMaxPacketSize; + } else { + // if frames per packet is zero, then the codec has no predictable packet == time + // so we can't tailor this (we don't know how many Packets represent a time period + // we'll just return a default buffer size + *outBufferSize = maxBufferSize > inMaxPacketSize ? maxBufferSize : inMaxPacketSize; + } + + // we're going to limit our size to our default + if (*outBufferSize > maxBufferSize && *outBufferSize > inMaxPacketSize) + *outBufferSize = maxBufferSize; + else { + // also make sure we're not too small - we don't want to go the disk for too small chunks + if (*outBufferSize < minBufferSize) + *outBufferSize = minBufferSize; + } + *outNumPackets = *outBufferSize / inMaxPacketSize; +} + +static Boolean MatchFormatFlags(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) +{ + UInt32 xFlags = x.mFormatFlags; + UInt32 yFlags = y.mFormatFlags; + + // match wildcards + if (x.mFormatID == 0 || y.mFormatID == 0 || xFlags == 0 || yFlags == 0) + return true; + + if (x.mFormatID == kAudioFormatLinearPCM) + { + // knock off the all clear flag + xFlags = xFlags & ~kAudioFormatFlagsAreAllClear; + yFlags = yFlags & ~kAudioFormatFlagsAreAllClear; + + // if both kAudioFormatFlagIsPacked bits are set, then we don't care about the kAudioFormatFlagIsAlignedHigh bit. + if (xFlags & yFlags & kAudioFormatFlagIsPacked) { + xFlags = xFlags & ~kAudioFormatFlagIsAlignedHigh; + yFlags = yFlags & ~kAudioFormatFlagIsAlignedHigh; + } + + // if both kAudioFormatFlagIsFloat bits are set, then we don't care about the kAudioFormatFlagIsSignedInteger bit. + if (xFlags & yFlags & kAudioFormatFlagIsFloat) { + xFlags = xFlags & ~kAudioFormatFlagIsSignedInteger; + yFlags = yFlags & ~kAudioFormatFlagIsSignedInteger; + } + + // if the bit depth is 8 bits or less and the format is packed, we don't care about endianness + if((x.mBitsPerChannel <= 8) && ((xFlags & kAudioFormatFlagIsPacked) == kAudioFormatFlagIsPacked)) + { + xFlags = xFlags & ~kAudioFormatFlagIsBigEndian; + } + if((y.mBitsPerChannel <= 8) && ((yFlags & kAudioFormatFlagIsPacked) == kAudioFormatFlagIsPacked)) + { + yFlags = yFlags & ~kAudioFormatFlagIsBigEndian; + } + + // if the number of channels is 0 or 1, we don't care about non-interleavedness + if (x.mChannelsPerFrame <= 1 && y.mChannelsPerFrame <= 1) { + xFlags &= ~kLinearPCMFormatFlagIsNonInterleaved; + yFlags &= ~kLinearPCMFormatFlagIsNonInterleaved; + } + } + return xFlags == yFlags; +} + +Boolean FormatIsEqual(AudioStreamBasicDescription x, AudioStreamBasicDescription y) +{ + // the semantics for equality are: + // 1) Values must match exactly + // 2) wildcard's are ignored in the comparison + +#define MATCH(name) ((x.name) == 0 || (y.name) == 0 || (x.name) == (y.name)) + + return + ((x.mSampleRate==0.) || (y.mSampleRate==0.) || (x.mSampleRate==y.mSampleRate)) + && MATCH(mFormatID) + && MatchFormatFlags(x, y) + && MATCH(mBytesPerPacket) + && MATCH(mFramesPerPacket) + && MATCH(mBytesPerFrame) + && MATCH(mChannelsPerFrame) + && MATCH(mBitsPerChannel) ; +} + +#pragma mark ***** BackgroundTrackMgr ***** +//================================================================================================== +// BackgroundTrackMgr class +//================================================================================================== +class BackgroundTrackMgr + { +#define CurFileInfo THIS->mBGFileInfo[THIS->mCurrentFileIndex] + public: + typedef struct BG_FileInfo { + std::string mFilePath; + AudioFileID mAFID; + AudioStreamBasicDescription mFileFormat; + UInt64 mFileDataSize; + //UInt64 mFileNumPackets; // this is only used if loading file to memory + Boolean mLoadAtOnce; + Boolean mFileDataInQueue; + } BackgroundMusicFileInfo; + + BackgroundTrackMgr(); + ~BackgroundTrackMgr(); + + void Teardown(); + void ClearFileInfo(); + + AudioStreamPacketDescription *GetPacketDescsPtr(); + + UInt32 GetNumPacketsToRead(BackgroundTrackMgr::BG_FileInfo *inFileInfo); + + static OSStatus AttachNewCookie(AudioQueueRef inQueue, BackgroundTrackMgr::BG_FileInfo *inFileInfo); + static void QueueStoppedProc( void * inUserData, AudioQueueRef inAQ, AudioQueuePropertyID inID ); + static Boolean DisposeBuffer(AudioQueueRef inAQ, std::vector inDisposeBufferList, AudioQueueBufferRef inBufferToDispose); + + enum { + kQueueState_DoNothing = 0, + kQueueState_ResizeBuffer = 1, + kQueueState_NeedNewCookie = 2, + kQueueState_NeedNewBuffers = 3, + kQueueState_NeedNewQueue = 4, + }; + + static SInt8 GetQueueStateForNextBuffer(BackgroundTrackMgr::BG_FileInfo *inFileInfo, BackgroundTrackMgr::BG_FileInfo *inNextFileInfo); + static void QueueCallback( void * inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inCompleteAQBuffer); + + OSStatus SetupQueue(BG_FileInfo *inFileInfo); + OSStatus SetupBuffers(BG_FileInfo *inFileInfo); + OSStatus LoadTrack(const char* inFilePath, Boolean inAddToQueue, Boolean inLoadAtOnce); + + OSStatus UpdateGain(); + OSStatus SetVolume(Float32 inVolume); + Float32 GetVolume() const; + + OSStatus Start(); + OSStatus Stop(Boolean inStopAtEnd); + + private: + AudioQueueRef mQueue; + AudioQueueBufferRef mBuffers[kNumberBuffers]; + UInt32 mBufferByteSize; + SInt64 mCurrentPacket; + UInt32 mNumPacketsToRead; + Float32 mVolume; + AudioStreamPacketDescription * mPacketDescs; + std::vector mBGFileInfo; + UInt32 mCurrentFileIndex; + Boolean mMakeNewQueueWhenStopped; + Boolean mStopAtEnd; + std::vector mBuffersToDispose; + }; + +BackgroundTrackMgr::BackgroundTrackMgr() + : mQueue(0), + mBufferByteSize(0), + mCurrentPacket(0), + mNumPacketsToRead(0), + mVolume(1.0f), + mPacketDescs(NULL), + mCurrentFileIndex(0), + mMakeNewQueueWhenStopped(false), + mStopAtEnd(false) +{ } + +BackgroundTrackMgr::~BackgroundTrackMgr() { + Teardown(); +} + +void BackgroundTrackMgr::Teardown() { + if (mQueue) { + AudioQueueDispose(mQueue, true); + } + for (UInt32 i=0; i < mBGFileInfo.size(); i++) { + if (mBGFileInfo[i]->mAFID) { + AudioFileClose(mBGFileInfo[i]->mAFID); + } + } + + if (mPacketDescs) { + delete mPacketDescs; + } + + ClearFileInfo(); +} + +void BackgroundTrackMgr::ClearFileInfo() { + std::vector< BG_FileInfo* >::iterator itr = mBGFileInfo.begin(); + std::vector< BG_FileInfo* >::iterator endItr = mBGFileInfo.end(); + for( ; itr != endItr; ++itr ) { + delete *itr; + *itr = NULL; + } + mBGFileInfo.clear(); +} + +AudioStreamPacketDescription *BackgroundTrackMgr::GetPacketDescsPtr() { + return mPacketDescs; +} + +UInt32 BackgroundTrackMgr::GetNumPacketsToRead(BackgroundTrackMgr::BG_FileInfo *inFileInfo) { + (void)inFileInfo; + return mNumPacketsToRead; +} + +OSStatus BackgroundTrackMgr::AttachNewCookie(AudioQueueRef inQueue, BackgroundTrackMgr::BG_FileInfo *inFileInfo) { + OSStatus result = noErr; + UInt32 size = sizeof(UInt32); + result = AudioFileGetPropertyInfo (inFileInfo->mAFID, kAudioFilePropertyMagicCookieData, &size, NULL); + if (!result && size) { + char* cookie = new char [size]; + result = AudioFileGetProperty (inFileInfo->mAFID, kAudioFilePropertyMagicCookieData, &size, cookie); + AssertNoError("Error getting cookie data", end); + result = AudioQueueSetProperty(inQueue, kAudioQueueProperty_MagicCookie, cookie, size); + delete [] cookie; + AssertNoError("Error setting cookie data for queue", end); + } + return noErr; + + end: + return noErr; +} + +void BackgroundTrackMgr::QueueStoppedProc( void * inUserData, AudioQueueRef inAQ, AudioQueuePropertyID inID ) { + (void)inID; + UInt32 isRunning; + UInt32 propSize = sizeof(isRunning); + + BackgroundTrackMgr *THIS = (BackgroundTrackMgr*)inUserData; + OSStatus result = AudioQueueGetProperty(inAQ, kAudioQueueProperty_IsRunning, &isRunning, &propSize); + + if ((!isRunning) && (THIS->mMakeNewQueueWhenStopped)) { + result = AudioQueueDispose(inAQ, true); + AssertNoError("Error disposing queue", end); + result = THIS->SetupQueue(CurFileInfo); + AssertNoError("Error setting up new queue", end); + result = THIS->SetupBuffers(CurFileInfo); + AssertNoError("Error setting up new queue buffers", end); + result = THIS->Start(); + AssertNoError("Error starting queue", end); + } + end: + return; +} + +Boolean BackgroundTrackMgr::DisposeBuffer(AudioQueueRef inAQ, std::vector inDisposeBufferList, AudioQueueBufferRef inBufferToDispose) { + for (unsigned int i=0; i < inDisposeBufferList.size(); i++) { + if (inBufferToDispose == inDisposeBufferList[i]) { + OSStatus result = AudioQueueFreeBuffer(inAQ, inBufferToDispose); + if (result == noErr) { + inDisposeBufferList.pop_back(); + } + return true; + } + } + return false; +} + +SInt8 BackgroundTrackMgr::GetQueueStateForNextBuffer(BackgroundTrackMgr::BG_FileInfo *inFileInfo, BackgroundTrackMgr::BG_FileInfo *inNextFileInfo) { + inFileInfo->mFileDataInQueue = false; + + // unless the data formats are the same, we need a new queue + if (!FormatIsEqual(inFileInfo->mFileFormat, inNextFileInfo->mFileFormat)) { + return kQueueState_NeedNewQueue; + } + + // if going from a load-at-once file to streaming or vice versa, we need new buffers + if (inFileInfo->mLoadAtOnce != inNextFileInfo->mLoadAtOnce) { + return kQueueState_NeedNewBuffers; + } + + // if the next file is smaller than the current, we just need to resize + if (inNextFileInfo->mLoadAtOnce) { + return (inFileInfo->mFileDataSize >= inNextFileInfo->mFileDataSize) ? kQueueState_ResizeBuffer : kQueueState_NeedNewBuffers; + } + + return kQueueState_NeedNewCookie; +} + +void BackgroundTrackMgr::QueueCallback( void * inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inCompleteAQBuffer ) { + // dispose of the buffer if no longer in use + OSStatus result = noErr; + BackgroundTrackMgr *THIS = (BackgroundTrackMgr*)inUserData; + if (DisposeBuffer(inAQ, THIS->mBuffersToDispose, inCompleteAQBuffer)) { + return; + } + + UInt32 nPackets = 0; + // loop the current buffer if the following: + // 1. file was loaded into the buffer previously + // 2. only one file in the queue + // 3. we have not been told to stop at playlist completion + if ((CurFileInfo->mFileDataInQueue) && (THIS->mBGFileInfo.size() == 1) && (!THIS->mStopAtEnd)) { + nPackets = THIS->GetNumPacketsToRead(CurFileInfo); + } else { + UInt32 numBytes; + while (nPackets == 0) { + // if loadAtOnce, get all packets in the file, otherwise ~.5 seconds of data + nPackets = THIS->GetNumPacketsToRead(CurFileInfo); + result = AudioFileReadPackets(CurFileInfo->mAFID, false, &numBytes, THIS->mPacketDescs, THIS->mCurrentPacket, &nPackets, + inCompleteAQBuffer->mAudioData); + AssertNoError("Error reading file data", end); + + inCompleteAQBuffer->mAudioDataByteSize = numBytes; + + if (nPackets == 0) { // no packets were read, this file has ended. + if (CurFileInfo->mLoadAtOnce) { + CurFileInfo->mFileDataInQueue = true; + } + + THIS->mCurrentPacket = 0; + UInt32 theNextFileIndex = (THIS->mCurrentFileIndex < THIS->mBGFileInfo.size()-1) ? THIS->mCurrentFileIndex+1 : 0; + + // we have gone through the playlist. if mStopAtEnd, stop the queue here + if (theNextFileIndex == 0 && THIS->mStopAtEnd) { + result = AudioQueueStop(inAQ, false); + AssertNoError("Error stopping queue", end); + return; + } + + SInt8 theQueueState = GetQueueStateForNextBuffer(CurFileInfo, THIS->mBGFileInfo[theNextFileIndex]); + if (theNextFileIndex != THIS->mCurrentFileIndex) { + // if were are not looping the same file. Close the old one and open the new + result = AudioFileClose(CurFileInfo->mAFID); + AssertNoError("Error closing file", end); + THIS->mCurrentFileIndex = theNextFileIndex; + + result = LoadFileDataInfo(CurFileInfo->mFilePath.c_str(), CurFileInfo->mAFID, CurFileInfo->mFileFormat, CurFileInfo->mFileDataSize); + AssertNoError("Error opening file", end); + } + + switch (theQueueState) { + // if we need to resize the buffer, set the buffer's audio data size to the new file's size + // we will also need to get the new file cookie + case kQueueState_ResizeBuffer: + inCompleteAQBuffer->mAudioDataByteSize = (UInt32)CurFileInfo->mFileDataSize; + // if the data format is the same but we just need a new cookie, attach a new cookie + case kQueueState_NeedNewCookie: + result = AttachNewCookie(inAQ, CurFileInfo); + AssertNoError("Error attaching new file cookie data to queue", end); + break; + + // we can keep the same queue, but not the same buffer(s) + case kQueueState_NeedNewBuffers: + THIS->mBuffersToDispose.push_back(inCompleteAQBuffer); + THIS->SetupBuffers(CurFileInfo); + break; + + // if the data formats are not the same, we need to dispose the current queue and create a new one + case kQueueState_NeedNewQueue: + THIS->mMakeNewQueueWhenStopped = true; + result = AudioQueueStop(inAQ, false); + AssertNoError("Error stopping queue", end); + return; + + default: + break; + } + } + } + } + + result = AudioQueueEnqueueBuffer(inAQ, inCompleteAQBuffer, (THIS->mPacketDescs ? nPackets : 0), THIS->mPacketDescs); + if(result != noErr) { + result = AudioQueueFreeBuffer(inAQ, inCompleteAQBuffer); + AssertNoError("Error freeing buffers that didn't enqueue", end); + } + AssertNoError("Error enqueuing new buffer", end); + if (CurFileInfo->mLoadAtOnce) { + CurFileInfo->mFileDataInQueue = true; + } + + THIS->mCurrentPacket += nPackets; + + end: + return; +} + +OSStatus BackgroundTrackMgr::SetupQueue(BG_FileInfo *inFileInfo) { + UInt32 size = 0; + OSStatus result = AudioQueueNewOutput(&inFileInfo->mFileFormat, QueueCallback, this, CFRunLoopGetCurrent(), kCFRunLoopCommonModes, 0, &mQueue); + OSStatus err = noErr; + + AssertNoError("Error creating queue", end); + + // (2) If the file has a cookie, we should get it and set it on the AQ + size = sizeof(UInt32); + result = AudioFileGetPropertyInfo (inFileInfo->mAFID, kAudioFilePropertyMagicCookieData, &size, NULL); + + if (!result && size) { + char* cookie = new char [size]; + result = AudioFileGetProperty (inFileInfo->mAFID, kAudioFilePropertyMagicCookieData, &size, cookie); + AssertNoError("Error getting magic cookie", end); + result = AudioQueueSetProperty(mQueue, kAudioQueueProperty_MagicCookie, cookie, size); + delete [] cookie; + AssertNoError("Error setting magic cookie", end); + } + + // channel layout + err = AudioFileGetPropertyInfo(inFileInfo->mAFID, kAudioFilePropertyChannelLayout, &size, NULL); + if (err == noErr && size > 0) { + AudioChannelLayout *acl = (AudioChannelLayout *)malloc(size); + result = AudioFileGetProperty(inFileInfo->mAFID, kAudioFilePropertyChannelLayout, &size, acl); + AssertNoError("Error getting channel layout from file", end); + result = AudioQueueSetProperty(mQueue, kAudioQueueProperty_ChannelLayout, acl, size); + free(acl); + AssertNoError("Error setting channel layout on queue", end); + } + + // add a notification proc for when the queue stops + result = AudioQueueAddPropertyListener(mQueue, kAudioQueueProperty_IsRunning, QueueStoppedProc, this); + AssertNoError("Error adding isRunning property listener to queue", end); + + // we need to reset this variable so that if the queue is stopped mid buffer we don't dispose it + mMakeNewQueueWhenStopped = false; + + // volume + result = SetVolume(mVolume); + + end: + return result; +} + +OSStatus BackgroundTrackMgr::SetupBuffers(BG_FileInfo *inFileInfo) { + int numBuffersToQueue = kNumberBuffers; + UInt32 maxPacketSize; + UInt32 size = sizeof(maxPacketSize); + bool isFormatVBR = false; + + // we need to calculate how many packets we read at a time, and how big a buffer we need + // we base this on the size of the packets in the file and an approximate duration for each buffer + + // first check to see what the max size of a packet is - if it is bigger + // than our allocation default size, that needs to become larger + OSStatus result = AudioFileGetProperty(inFileInfo->mAFID, kAudioFilePropertyPacketSizeUpperBound, &size, &maxPacketSize); + AssertNoError("Error getting packet upper bound size", end); + isFormatVBR = (inFileInfo->mFileFormat.mBytesPerPacket == 0 || inFileInfo->mFileFormat.mFramesPerPacket == 0); + + CalculateBytesForTime(inFileInfo->mFileFormat, maxPacketSize, 0.5/*seconds*/, &mBufferByteSize, &mNumPacketsToRead); + + // if the file is smaller than the capacity of all the buffer queues, always load it at once + if ((mBufferByteSize * numBuffersToQueue) > inFileInfo->mFileDataSize) { + inFileInfo->mLoadAtOnce = true; + } + + if (inFileInfo->mLoadAtOnce) { + UInt64 theFileNumPackets; + size = sizeof(UInt64); + result = AudioFileGetProperty(inFileInfo->mAFID, kAudioFilePropertyAudioDataPacketCount, &size, &theFileNumPackets); + AssertNoError("Error getting packet count for file", end); + + mNumPacketsToRead = (UInt32)theFileNumPackets; + mBufferByteSize = (UInt32)inFileInfo->mFileDataSize; + numBuffersToQueue = 1; + } else { + mNumPacketsToRead = mBufferByteSize / maxPacketSize; + } + + if (isFormatVBR) { + mPacketDescs = new AudioStreamPacketDescription [mNumPacketsToRead]; + } else { + mPacketDescs = NULL; // we don't provide packet descriptions for constant bit rate formats (like linear PCM) + } + + // allocate the queue's buffers + for (int i = 0; i < numBuffersToQueue; ++i) { + result = AudioQueueAllocateBuffer(mQueue, mBufferByteSize, &mBuffers[i]); + AssertNoError("Error allocating buffer for queue", end); + QueueCallback (this, mQueue, mBuffers[i]); + if (inFileInfo->mLoadAtOnce) { + inFileInfo->mFileDataInQueue = true; + } + } + + end: + return result; +} + +OSStatus BackgroundTrackMgr::LoadTrack(const char* inFilePath, Boolean inAddToQueue, Boolean inLoadAtOnce) { + BG_FileInfo *fileInfo = new BG_FileInfo; + fileInfo->mFilePath = inFilePath; + OSStatus result = LoadFileDataInfo(fileInfo->mFilePath.c_str(), fileInfo->mAFID, fileInfo->mFileFormat, fileInfo->mFileDataSize); + AssertNoError("Error getting file data info", fail); + fileInfo->mLoadAtOnce = inLoadAtOnce; + fileInfo->mFileDataInQueue = false; + // if not adding to the queue, clear the current file vector + if (!inAddToQueue) { + ClearFileInfo(); + } + + mBGFileInfo.push_back(fileInfo); + + // setup the queue if this is the first (or only) file + if (mBGFileInfo.size() == 1) { + result = SetupQueue(fileInfo); + AssertNoError("Error setting up queue", fail); + result = SetupBuffers(fileInfo); + AssertNoError("Error setting up queue buffers", fail); + } else { // if this is just part of the playlist, close the file for now + result = AudioFileClose(fileInfo->mAFID); + AssertNoError("Error closing file", fail); + } + return result; + + fail: + if (fileInfo) { + delete fileInfo; + } + return result; +} + +OSStatus BackgroundTrackMgr::UpdateGain() { + return SetVolume(mVolume); +} + +OSStatus BackgroundTrackMgr::SetVolume(Float32 inVolume) { + mVolume = inVolume; + return AudioQueueSetParameter(mQueue, kAudioQueueParam_Volume, mVolume * gMasterVolumeGain); +} + +Float32 BackgroundTrackMgr::GetVolume() const { + return mVolume; +} + +OSStatus BackgroundTrackMgr::Start() { + if(gInterrupted) { + printf("Start called, but interrupted so ignoring.\n"); + return noErr; + } + + OSStatus result = AudioQueuePrime(mQueue, 1, NULL); + if (result) { + printf("Error priming queue: %d\n", (int)result); + return result; + } + return AudioQueueStart(mQueue, NULL); +} + +OSStatus BackgroundTrackMgr::Stop(Boolean inStopAtEnd) { + if (inStopAtEnd) { + mStopAtEnd = true; + return noErr; + } else { + return AudioQueueStop(mQueue, true); + } +} + + +#pragma mark ***** SoundEngineEffect ***** +//================================================================================================== +// SoundEngineEffect class +//================================================================================================== +class SoundEngineEffect +{ + public: + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + SoundEngineEffect(const char* inLoopPath, const char* inAttackPath, const char* inDecayPath, Boolean inDoLoop) + : mSourceID(0), + mAttackBufferID(0), + mLoopBufferID(0), + mDecayBufferID(0), + mLoopPath(inLoopPath), + mAttackPath(inAttackPath), + mDecayPath(inDecayPath), + mLoopData(NULL), + mAttackData(NULL), + mDecayData(NULL), + mLoopDataSize(0), + mAttackDataSize(0), + mDecayDataSize(0), + mIsLoopingEffect(inDoLoop), + mPlayThread(NULL), + mPlayThreadState(kPlayThreadState_Loop) { alGenSources(1, &mSourceID); } + + ~SoundEngineEffect() + { + alDeleteSources(1, &mSourceID); + + if (mLoopData) + free(mLoopData); + if (mAttackData) + free(mAttackData); + if (mDecayData) + free(mDecayData); + } + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Accessors + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + UInt32 GetEffectID() { return mSourceID; } + UInt32 GetPlayThreadState() { return mPlayThreadState; } + Boolean HasAttackBuffer() { return mAttackBufferID != 0; } + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Helper Functions + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ALenum GetALFormat(AudioStreamBasicDescription inFileFormat) + { + if (inFileFormat.mFormatID != kAudioFormatLinearPCM) + return kSoundEngineErrInvalidFileFormat; + + if ((inFileFormat.mChannelsPerFrame > 2) || (inFileFormat.mChannelsPerFrame < 1)) + return kSoundEngineErrInvalidFileFormat; + + if(inFileFormat.mBitsPerChannel == 8) + return (inFileFormat.mChannelsPerFrame == 1) ? AL_FORMAT_MONO8 : AL_FORMAT_STEREO8; + else if(inFileFormat.mBitsPerChannel == 16) + return (inFileFormat.mChannelsPerFrame == 1) ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16; + + return kSoundEngineErrInvalidFileFormat; + } + + OSStatus LoadFileData(const char *inFilePath, void* &outData, UInt32 &outDataSize, ALuint &outBufferID) + { + AudioFileID theAFID = 0; + OSStatus result = noErr; + UInt64 theFileSize = 0; + AudioStreamBasicDescription theFileFormat; + + result = LoadFileDataInfo(inFilePath, theAFID, theFileFormat, theFileSize); + outDataSize = (UInt32)theFileSize; + AssertNoError("Error loading file info", fail) + + outData = malloc(outDataSize); + + result = AudioFileReadBytes(theAFID, false, 0, &outDataSize, outData); + AssertNoError("Error reading file data", fail) + + if (!TestAudioFormatNativeEndian(theFileFormat) && (theFileFormat.mBitsPerChannel > 8)) + return kSoundEngineErrInvalidFileFormat; + + alGenBuffers(1, &outBufferID); + AssertNoOALError("Error generating buffer\n", fail); + + alBufferDataStaticProc(outBufferID, GetALFormat(theFileFormat), outData, outDataSize, (ALsizei)theFileFormat.mSampleRate); + AssertNoOALError("Error attaching data to buffer\n", fail); + + AudioFileClose(theAFID); + return result; + + fail: + if (theAFID) + AudioFileClose(theAFID); + if (outData) + { + free(outData); + outData = NULL; + } + return result; + } + + OSStatus AttachFilesToSource() + { + OSStatus result = AL_NO_ERROR; + // first check for the attack file. That will be first in the queue if present + if (mAttackPath) + { + result = LoadFileData(mAttackPath, mAttackData, mAttackDataSize, mAttackBufferID); + AssertNoError("Error loading attack file info", end) + } + + result = LoadFileData(mLoopPath, mLoopData, mLoopDataSize, mLoopBufferID); + AssertNoError("Error loading looping file info", end) + + // if one-shot effect, attach the buffer to the source now + if (!mIsLoopingEffect) + { + alSourcei(mSourceID, AL_BUFFER, mLoopBufferID); + AssertNoOALError("Error attaching file data to effect", end) + } + + if (mDecayPath) + { + result = LoadFileData(mDecayPath, mDecayData, mDecayDataSize, mDecayBufferID); + AssertNoError("Error loading decay file info", end) + } + end: + return result; + } + + OSStatus ClearSourceBuffers() + { + OSStatus result = AL_NO_ERROR; + ALint numQueuedBuffers = 0; + ALuint *bufferIDs = (ALuint*)malloc(numQueuedBuffers * sizeof(ALint)); + alGetSourcei(mSourceID, AL_BUFFERS_QUEUED, &numQueuedBuffers); + AssertNoOALError("Error getting OpenAL queued buffer size", end) + + alSourceUnqueueBuffers(mSourceID, numQueuedBuffers, bufferIDs); + AssertNoOALError("Error unqueueing buffers from source", end) + + end: + free(bufferIDs); + return result; + } + + static void* PlaybackProc(void *args) + { + OSStatus result = AL_NO_ERROR; + SoundEngineEffect *THIS = (SoundEngineEffect*)args; + + alSourcePlay(THIS->GetEffectID()); + AssertNoOALError("Error starting effect playback", end) + + // if attack buffer is present, wait until it has completed, then turn looping on + if (THIS->HasAttackBuffer()) + { + ALint numBuffersProcessed = 0; + while (numBuffersProcessed < 1) + { + alGetSourcei(THIS->GetEffectID(), AL_BUFFERS_PROCESSED, &numBuffersProcessed); + AssertNoOALError("Error getting processed buffer number", end) + } + + ALuint tmpBuffer = 0; + alSourceUnqueueBuffers(THIS->GetEffectID(), 1, &tmpBuffer); + AssertNoOALError("Error unqueueing buffers from source", end) + } + // now that we have processed the attack buffer, loop the main one + THIS->SetLooping(true); + + end: + return NULL; + } + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Effect management + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + OSStatus Start() + { + OSStatus result = AL_NO_ERROR; + alSourceStop(mSourceID); + AssertNoOALError("Error stopping source", end) + + if (!mIsLoopingEffect) + { + // if we are just playing one-short effects, start playback here + alSourcePlay(mSourceID); + return alGetError(); + } + // for loops we need to spawn a new thread + mPlayThread = new OpenALThread(PlaybackProc, (void*)this); + // we want this to delete upon thread completion + mPlayThreadState = kPlayThreadState_Loop; + // clean up remnants from any previous playback of the source + result = ClearSourceBuffers(); + AssertNoError("Error clearing buffers", end) + + // if the effect has an attack sample, queue this first + if (HasAttackBuffer()) + { + alSourceQueueBuffers(mSourceID, 1, &mAttackBufferID); + AssertNoOALError("Error queueing buffers for attack", end) + // turn on looping after the attack buffer has been processed + SetLooping(false); + } + + alSourceQueueBuffers(mSourceID, 1, &mLoopBufferID); + AssertNoOALError("Error queueing looping buffer", end) + mPlayThread->Start(); + end: + return result; + } + + OSStatus StartDecay() + { + // turn off looping, and queue the decay buffer + OSStatus result = AL_NO_ERROR; + alSourcei(mSourceID, AL_LOOPING, 0); + AssertNoOALError("Error turning off looping", end) + alSourceQueueBuffers(mSourceID, 1, &mDecayBufferID); + AssertNoOALError("Error queueing decay file", end) + end: + return result; + } + + OSStatus Stop(Boolean inDoDecay) + { + OSStatus result = AL_NO_ERROR; + // for non looped effects and loops with no decay sample + if ((mDecayBufferID == 0) || !inDoDecay) + { + // if no decay to play, just stop the source + alSourceStop(mSourceID); + AssertNoOALError("Error stopping source", end) + } + else + return StartDecay(); + end: + return result; + } + + OSStatus SetPitch(Float32 inValue) + { + alSourcef(mSourceID, AL_PITCH, inValue); + return alGetError(); + } + + OSStatus SetLooping(Boolean inDoLoop) + { + ALint doLoop = inDoLoop ? 1 : 0; + alSourcei(mSourceID, AL_LOOPING, doLoop); + return alGetError(); + } + + OSStatus SetPosition(Float32 inX, Float32 inY, Float32 inZ) + { + alSource3f(mSourceID, AL_POSITION, inX, inY, inZ); + return alGetError(); + } + + OSStatus SetMaxDistance(Float32 inValue) + { + alSourcef(mSourceID, AL_MAX_DISTANCE, inValue); + return alGetError(); + } + + OSStatus SetReferenceDistance(Float32 inValue) + { + alSourcef(mSourceID, AL_REFERENCE_DISTANCE, inValue); + return alGetError(); + } + + OSStatus SetLevel(Float32 inValue) + { + alSourcef(mSourceID, AL_GAIN, inValue * gMasterVolumeGain); + return alGetError(); + } + + enum { + kPlayThreadState_Loop = 0, + kPlayThreadState_Decay = 1, + kPlayThreadState_End = 2 + }; + + private: + ALuint mSourceID; + ALuint mAttackBufferID; + ALuint mLoopBufferID; + ALuint mDecayBufferID; + UInt32 mNumberBuffers; + const char* mLoopPath; + const char* mAttackPath; + const char* mDecayPath; + void* mLoopData; + void* mAttackData; + void* mDecayData; + UInt32 mLoopDataSize; + UInt32 mAttackDataSize; + UInt32 mDecayDataSize; + Boolean mIsLoopingEffect; + OpenALThread* mPlayThread; + UInt32 mPlayThreadState; +}; + +#pragma mark ***** SoundEngineEffectMap ***** +//================================================================================================== +// SoundEngineEffectMap class +//================================================================================================== +class SoundEngineEffectMap + : std::multimap > +{ + public: + // add a new context to the map + void Add (const ALuint inEffectToken, SoundEngineEffect **inEffect) + { + iterator it = upper_bound(inEffectToken); + insert(it, value_type (inEffectToken, *inEffect)); + } + + SoundEngineEffect* Get(ALuint inEffectToken) + { + iterator it = find(inEffectToken); + if (it != end()) + return ((*it).second); + return (NULL); + } + + void Remove (const ALuint inSourceToken) { + iterator it = find(inSourceToken); + if (it != end()) + erase(it); + } + + SoundEngineEffect* GetEffectByIndex(UInt32 inIndex) { + iterator it = begin(); + + for (UInt32 i = 0; i < inIndex; i++) { + if (it != end()) + ++it; + else + i = inIndex; + } + + if (it != end()) + return ((*it).second); + return (NULL); + } + + iterator GetIterator() { return begin(); } + + UInt32 Size () const { return size(); } + bool Empty () const { return empty(); } +}; + +#pragma mark ***** OpenALObject ***** +//================================================================================================== +// OpenALObject class +//================================================================================================== +class OpenALObject +{ + public: + OpenALObject(Float32 inMixerOutputRate) + : mOutputRate(inMixerOutputRate), + mGain(1.0f), + mContext(NULL), + mDevice(NULL), + mEffectsMap(NULL) + { + mEffectsMap = new SoundEngineEffectMap(); + } + + ~OpenALObject() { Teardown(); } + + OSStatus Initialize() + { + OSStatus result = noErr; + mDevice = alcOpenDevice(NULL); + AssertNoOALError("Error opening output device", end) + if(mDevice == NULL) { return kSoundEngineErrDeviceNotFound; } + + // if a mixer output rate was specified, set it here + // must be done before the alcCreateContext() call + if (mOutputRate) + alcMacOSXMixerOutputRateProc(mOutputRate); + + // Create an OpenAL Context + mContext = alcCreateContext(mDevice, NULL); + AssertNoOALError("Error creating OpenAL context", end) + + alcMakeContextCurrent(mContext); + AssertNoOALError("Error setting current OpenAL context", end) + + end: + return result; + } + + void Teardown() + { + if (mEffectsMap) + { + for (UInt32 i = 0; i < mEffectsMap->Size(); i++) + { + SoundEngineEffect *theEffect = mEffectsMap->GetEffectByIndex(0); + if (theEffect) + { + mEffectsMap->Remove(theEffect->GetEffectID()); + delete theEffect; + } + } + delete mEffectsMap; + } + + if (mContext) alcDestroyContext(mContext); + + if (mDevice) alcCloseDevice(mDevice); + } + + OSStatus SetListenerPosition(Float32 inX, Float32 inY, Float32 inZ) + { + alListener3f(AL_POSITION, inX, inY, inZ); + return alGetError(); + } + + OSStatus SetListenerDirection(Float32 inX, Float32 inY, Float32 inZ) + { + alListener3f(AL_DIRECTION, inX, inY, inZ); + return alGetError(); + } + + OSStatus SetListenerGain(Float32 inValue) + { + alListenerf(AL_GAIN, inValue); + return alGetError(); + } + + OSStatus SetMaxDistance(Float32 inValue) + { + OSStatus result = 0; + for (UInt32 i=0; i < mEffectsMap->Size(); i++) + { + SoundEngineEffect *theEffect = mEffectsMap->GetEffectByIndex(i); + if ((result = theEffect->SetMaxDistance(inValue)) != AL_NO_ERROR) + return result; + } + return result; + } + + OSStatus SetReferenceDistance(Float32 inValue) + { + OSStatus result = 0; + for (UInt32 i=0; i < mEffectsMap->Size(); i++) + { + SoundEngineEffect *theEffect = mEffectsMap->GetEffectByIndex(i); + if ((result = theEffect->SetReferenceDistance(inValue)) != AL_NO_ERROR) + return result; + } + return result; + } + + OSStatus SetEffectReferenceDistance(UInt32 inEffectID, Float32 inValue) + { + SoundEngineEffect *theEffect = mEffectsMap->Get(inEffectID); + return (theEffect) ? theEffect->SetReferenceDistance(inValue) : kSoundEngineErrInvalidID; + } + + OSStatus SetEffectsVolume(Float32 inValue) + { + OSStatus result = 0; + for (UInt32 i=0; i < mEffectsMap->Size(); i++) + { + SoundEngineEffect *theEffect = mEffectsMap->GetEffectByIndex(i); + if ((result = theEffect->SetLevel(inValue)) != AL_NO_ERROR) + return result; + } + mGain = inValue; + return result; + } + + Float32 GetEffectsVolume() const + { + return mGain; + } + + OSStatus UpdateGain() + { + return SetEffectsVolume(mGain); + } + + OSStatus LoadEffect(const char *inFilePath, UInt32 *outEffectID) + { + SoundEngineEffect *theEffect = new SoundEngineEffect(inFilePath, NULL, NULL, false); + OSStatus result = theEffect->AttachFilesToSource(); + if (result == noErr) + { + *outEffectID = theEffect->GetEffectID(); + mEffectsMap->Add(*outEffectID, &theEffect); + } + return result; + } + + OSStatus LoadLoopingEffect(const char *inLoopFilePath, const char *inAttackFilePath, const char *inDecayFilePath, UInt32 *outEffectID) + { + SoundEngineEffect *theEffect = new SoundEngineEffect(inLoopFilePath, inAttackFilePath, inDecayFilePath, true); + OSStatus result = theEffect->AttachFilesToSource(); + if (result == noErr) + { + *outEffectID = theEffect->GetEffectID(); + mEffectsMap->Add(*outEffectID, &theEffect); + } + return result; + } + + OSStatus UnloadEffect(UInt32 inEffectID) + { + SoundEngineEffect *theEffect = mEffectsMap->Get(inEffectID); + if (theEffect) + { + mEffectsMap->Remove(inEffectID); + delete theEffect; + } + return 0; + } + + OSStatus StartEffect(UInt32 inEffectID) + { + SoundEngineEffect *theEffect = mEffectsMap->Get(inEffectID); + return (theEffect) ? theEffect->Start() : kSoundEngineErrInvalidID; + } + + OSStatus StopEffect(UInt32 inEffectID, Boolean inDoDecay) + { + SoundEngineEffect *theEffect = mEffectsMap->Get(inEffectID); + return (theEffect) ? theEffect->Stop(inDoDecay) : kSoundEngineErrInvalidID; + } + + OSStatus SetEffectPitch(UInt32 inEffectID, Float32 inValue) + { + SoundEngineEffect *theEffect = mEffectsMap->Get(inEffectID); + return (theEffect) ? theEffect->SetPitch(inValue) : kSoundEngineErrInvalidID; + } + + OSStatus SetEffectVolume(UInt32 inEffectID, Float32 inValue) + { + SoundEngineEffect *theEffect = mEffectsMap->Get(inEffectID); + return (theEffect) ? theEffect->SetLevel(inValue * mGain) : kSoundEngineErrInvalidID; + } + + OSStatus SetEffectPosition(UInt32 inEffectID, Float32 inX, Float32 inY, Float32 inZ) + { + SoundEngineEffect *theEffect = mEffectsMap->Get(inEffectID); + return (theEffect) ? theEffect->SetPosition(inX, inY, inZ) : kSoundEngineErrInvalidID; + } + + private: + Float32 mOutputRate; + Float32 mGain; + ALCcontext* mContext; + ALCdevice* mDevice; + SoundEngineEffectMap* mEffectsMap; +}; + + +#pragma mark ***** API ***** +//================================================================================================== +// Sound Engine +//================================================================================================== + + +extern "C" +void interruptionCallback(void* arg, UInt32 interruptionState) +{ + (void)arg; + + printf("Excuse this interruption...\n"); + switch(interruptionState) + { + case kAudioSessionBeginInterruption: + printf("begin interruption\n"); + SoundEngine_Teardown(); + gInterrupted = true; + break; + +// SCD: TODO Revisit when building with 2.2 where this callback is actually supposed to be made... +// case kAudioSessionEndInterruption: +// printf("end interruption.\n"); +// gInterrupted = false; +// break; + } +} + + +#endif // WIN32 + +extern "C" +OSStatus SoundEngine_Reactivate() +{ +#ifndef WIN32 + gInterrupted = false; + return noErr; +#else + return 0; +#endif +} + + +extern "C" +OSStatus SoundEngine_Initialize(Float32 inMixerOutputRate) +{ +#ifndef WIN32 + if(gInterrupted) + return noErr; + + if( !isInitialized ) + { + AudioSessionInitialize( NULL, NULL, interruptionCallback, NULL ); +// UInt32 sessionCategory = kAudioSessionCategory_AmbientSound; +// AudioSessionSetProperty( kAudioSessionProperty_AudioCategory, sizeof( sessionCategory ), &sessionCategory ); + isInitialized = true; + } + + if (sOpenALObject) + delete sOpenALObject; + + if (sBackgroundTrackMgr) + delete sBackgroundTrackMgr; + + sOpenALObject = new OpenALObject(inMixerOutputRate); + sBackgroundTrackMgr = new BackgroundTrackMgr(); + + return sOpenALObject->Initialize(); +#else + return 0; +#endif +} + +extern "C" +OSStatus SoundEngine_Teardown() +{ +#ifndef WIN32 + if (sOpenALObject) + { + delete sOpenALObject; + sOpenALObject = NULL; + } + + if (sBackgroundTrackMgr) + { + delete sBackgroundTrackMgr; + sBackgroundTrackMgr = NULL; + } + + return 0; +#else + return 0; +#endif +} + +extern "C" +OSStatus SoundEngine_SetMasterVolume(Float32 inValue) +{ +#ifndef WIN32 + OSStatus result = noErr; + gMasterVolumeGain = inValue; + if (sBackgroundTrackMgr) + result = sBackgroundTrackMgr->UpdateGain(); + + if (result) return result; + + if (sOpenALObject) + return sOpenALObject->UpdateGain(); + + return result; +#else + return 0; +#endif +} + +extern "C" +OSStatus SoundEngine_SetListenerPosition(Float32 inX, Float32 inY, Float32 inZ) +{ +#ifndef WIN32 + return (sOpenALObject) ? sOpenALObject->SetListenerPosition(inX, inY, inZ) : kSoundEngineErrUnitialized; +#else + return 0; +#endif +} + +extern "C" +OSStatus SoundEngine_SetListenerDirection(Float32 inX, Float32 inY, Float32 inZ) +{ +#ifndef WIN32 + return (sOpenALObject) ? sOpenALObject->SetListenerDirection(inX, inY, inZ) : kSoundEngineErrUnitialized; +#else + return 0; +#endif +} + + +extern "C" +OSStatus SoundEngine_SetListenerGain(Float32 inValue) +{ +#ifndef WIN32 + return (sOpenALObject) ? sOpenALObject->SetListenerGain(inValue) : kSoundEngineErrUnitialized; +#else + return 0; +#endif +} + +extern "C" +OSStatus SoundEngine_LoadBackgroundMusicTrack(const char* inPath, Boolean inAddToQueue, Boolean inLoadAtOnce) +{ +#ifndef WIN32 + if(gInterrupted) + return noErr; + + if (sBackgroundTrackMgr == NULL) + sBackgroundTrackMgr = new BackgroundTrackMgr(); + return sBackgroundTrackMgr->LoadTrack(inPath, inAddToQueue, inLoadAtOnce); +#else + return 0; +#endif +} + +extern "C" +OSStatus SoundEngine_UnloadBackgroundMusicTrack() +{ +#ifndef WIN32 + if (sBackgroundTrackMgr) + { + delete sBackgroundTrackMgr; + sBackgroundTrackMgr = NULL; + } + + return 0; +#else + return 0; +#endif +} + +extern "C" +OSStatus SoundEngine_StartBackgroundMusic() +{ +#ifndef WIN32 + return (sBackgroundTrackMgr) ? sBackgroundTrackMgr->Start() : kSoundEngineErrUnitialized; +#else + return 0; +#endif +} + +extern "C" +OSStatus SoundEngine_StopBackgroundMusic(Boolean stopAtEnd) +{ +#ifndef WIN32 + return (sBackgroundTrackMgr) ? sBackgroundTrackMgr->Stop(stopAtEnd) : kSoundEngineErrUnitialized; +#else + return 0; +#endif +} + +extern "C" +OSStatus SoundEngine_SetBackgroundMusicVolume(Float32 inValue) +{ +#ifndef WIN32 + return (sBackgroundTrackMgr) ? sBackgroundTrackMgr->SetVolume(inValue) : kSoundEngineErrUnitialized; +#else + return 0; +#endif +} + +extern "C" +Float32 SoundEngine_GetBackgroundMusicVolume() +{ +#ifndef WIN32 + return (sBackgroundTrackMgr) ? sBackgroundTrackMgr->GetVolume() : 0.0f; +#else + return 0; +#endif +} + +extern "C" +OSStatus SoundEngine_LoadEffect(const char* inPath, UInt32* outEffectID) +{ +#ifndef WIN32 + OSStatus result = noErr; + if (sOpenALObject == NULL) + { + sOpenALObject = new OpenALObject(0.0f); + result = sOpenALObject->Initialize(); + } + return (result) ? result : sOpenALObject->LoadEffect(inPath, outEffectID); +#else + return 0; +#endif +} + +extern "C" +OSStatus SoundEngine_LoadLoopingEffect(const char* inLoopFilePath, const char* inAttackFilePath, const char* inDecayFilePath, UInt32* outEffectID) +{ +#ifndef WIN32 + OSStatus result = noErr; + if (sOpenALObject == NULL) + { + sOpenALObject = new OpenALObject(0.0f); + result = sOpenALObject->Initialize(); + } + return (result) ? result : sOpenALObject->LoadLoopingEffect(inLoopFilePath, inAttackFilePath, inDecayFilePath, outEffectID); +#else + return 0; +#endif +} + +extern "C" +OSStatus SoundEngine_UnloadEffect(UInt32 inEffectID) +{ +#ifndef WIN32 + return (sOpenALObject) ? sOpenALObject->UnloadEffect(inEffectID) : kSoundEngineErrUnitialized; +#else + return 0; +#endif +} + + +extern "C" +OSStatus SoundEngine_StartEffect(UInt32 inEffectID) +{ +#ifndef WIN32 + return (sOpenALObject) ? sOpenALObject->StartEffect(inEffectID) : kSoundEngineErrUnitialized; +#else + return 0; +#endif +} + +extern "C" +OSStatus SoundEngine_StopEffect(UInt32 inEffectID, Boolean inDoDecay) +{ +#ifndef WIN32 + return (sOpenALObject) ? sOpenALObject->StopEffect(inEffectID, inDoDecay) : kSoundEngineErrUnitialized; +#else + return 0; +#endif +} + +extern "C" +OSStatus SoundEngine_SetEffectPitch(UInt32 inEffectID, Float32 inValue) +{ +#ifndef WIN32 + return (sOpenALObject) ? sOpenALObject->SetEffectPitch(inEffectID, inValue) : kSoundEngineErrUnitialized; +#else + return 0; +#endif +} + +extern "C" +OSStatus SoundEngine_SetEffectLevel(UInt32 inEffectID, Float32 inValue) +{ +#ifndef WIN32 + return (sOpenALObject) ? sOpenALObject->SetEffectVolume(inEffectID, inValue) : kSoundEngineErrUnitialized; +#else + return 0; +#endif +} + +extern "C" +OSStatus SoundEngine_SetEffectPosition(UInt32 inEffectID, Float32 inX, Float32 inY, Float32 inZ) +{ +#ifndef WIN32 + return (sOpenALObject) ? sOpenALObject->SetEffectPosition(inEffectID, inX, inY, inZ) : kSoundEngineErrUnitialized; +#else + return 0; +#endif +} + +extern "C" +OSStatus SoundEngine_SetEffectsVolume(Float32 inValue) +{ +#ifndef WIN32 + return (sOpenALObject) ? sOpenALObject->SetEffectsVolume(inValue) : kSoundEngineErrUnitialized; +#else + return 0; +#endif +} + +extern "C" +Float32 SoundEngine_GetEffectsVolume() +{ +#ifndef WIN32 + return (sOpenALObject) ? sOpenALObject->GetEffectsVolume() : 0.0f; +#else + return 0; +#endif +} + +extern "C" +OSStatus SoundEngine_SetMaxDistance(Float32 inValue) +{ +#ifndef WIN32 + return (sOpenALObject) ? sOpenALObject->SetMaxDistance(inValue) : kSoundEngineErrUnitialized; +#else + return 0; +#endif +} + +extern "C" +OSStatus SoundEngine_SetReferenceDistance(Float32 inValue) +{ +#ifndef WIN32 + return (sOpenALObject) ? sOpenALObject->SetReferenceDistance(inValue) : kSoundEngineErrUnitialized; +#else + return 0; +#endif +} + +extern "C" +OSStatus SoundEngine_SetEffectReferenceDistance(UInt32 inEffectID, Float32 inValue) +{ +#ifndef WIN32 + return (sOpenALObject) ? sOpenALObject->SetEffectReferenceDistance(inEffectID, inValue) : kSoundEngineErrUnitialized; +#else + return 0; +#endif +} + diff --git a/common/ios/doomengine/SoundEngine.h b/common/ios/doomengine/SoundEngine.h new file mode 100755 index 0000000..adbf0b1 --- /dev/null +++ b/common/ios/doomengine/SoundEngine.h @@ -0,0 +1,383 @@ +/* + +File: SoundEngine.h +Abstract: These functions play background music tracks, multiple sound effects, +and support stereo panning with a low-latency response. + +Version: 1.7 + +Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. +("Apple") in consideration of your agreement to the following terms, and your +use, installation, modification or redistribution of this Apple software +constitutes acceptance of these terms. If you do not agree with these terms, +please do not use, install, modify or redistribute this Apple software. + +In consideration of your agreement to abide by the following terms, and subject +to these terms, Apple grants you a personal, non-exclusive license, under +Apple's copyrights in this original Apple software (the "Apple Software"), to +use, reproduce, modify and redistribute the Apple Software, with or without +modifications, in source and/or binary forms; provided that if you redistribute +the Apple Software in its entirety and without modifications, you must retain +this notice and the following text and disclaimers in all such redistributions +of the Apple Software. +Neither the name, trademarks, service marks or logos of Apple Inc. may be used +to endorse or promote products derived from the Apple Software without specific +prior written permission from Apple. Except as expressly stated in this notice, +no other rights or licenses, express or implied, are granted by Apple herein, +including but not limited to any patent rights that may be infringed by your +derivative works or by other works in which the Apple Software may be +incorporated. + +The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO +WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED +WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN +COMBINATION WITH YOUR PRODUCTS. + +IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR +DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF +CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Copyright (C) 2008 Apple Inc. All Rights Reserved. + +*/ + +/*================================================================================================== + SoundEngine.h +==================================================================================================*/ +#if !defined(__SoundEngine_h__) +#define __SoundEngine_h__ + +//================================================================================================== +// Includes +//================================================================================================== + +// System Includes +#ifndef WIN32 +#include +#include +#else +typedef int OSStatus; +typedef int SInt32; +typedef unsigned int UInt32; +typedef float Float32; +typedef unsigned char Boolean; +#endif + +#if defined(__cplusplus) +extern "C" +{ +#endif + +//================================================================================================== +// Sound Engine +//================================================================================================== +/*! + @enum SoundEngine error codes + @abstract These are the error codes returned from the SoundEngine API. + @constant kSoundEngineErrUnitialized + The SoundEngine has not been initialized. Use SoundEngine_Initialize(). + @constant kSoundEngineErrInvalidID + The specified EffectID was not found. This can occur if the effect has not been loaded, or + if an unloaded is trying to be accessed. + @constant kSoundEngineErrFileNotFound + The specified file was not found. + @constant kSoundEngineErrInvalidFileFormat + The format of the file is invalid. Effect data must be little-endian 8 or 16 bit LPCM. + @constant kSoundEngineErrDeviceNotFound + The output device was not found. + +*/ +enum { + kSoundEngineErrUnitialized = 1, + kSoundEngineErrInvalidID = 2, + kSoundEngineErrFileNotFound = 3, + kSoundEngineErrInvalidFileFormat = 4, + kSoundEngineErrDeviceNotFound = 5 +}; + + +/*! + @function SoundEngine_Initialize + @abstract Initializes and sets up the sound engine. Calling after a previous initialize will + reset the state of the SoundEngine, with all previous effects and music tracks + erased. Note: This is not required, loading an effect or background track will + initialize as necessary. + @param inMixerOutputRate + A Float32 that represents the output sample rate of the mixer unit. Setting this to + 0 will use the default rate (the sample rate of the device) + @result A OSStatus indicating success or failure. +*/ +OSStatus SoundEngine_Initialize(Float32 inMixerOutputRate); + + +OSStatus SoundEngine_Reactivate(); + + +/*! + @function SoundEngine_Teardown + @abstract Tearsdown the sound engine. + @result A OSStatus indicating success or failure. +*/ +OSStatus SoundEngine_Teardown(); + +/*! + @function SoundEngine_SetMasterVolume + @abstract Sets the overall volume of all sounds coming from the process + @param inValue + A Float32 that represents the level. The range is between 0.0 and 1.0 (inclusive). + @result A OSStatus indicating success or failure. +*/ +OSStatus SoundEngine_SetMasterVolume(Float32 inValue); + +/*! + @function SoundEngine_SetListenerPosition + @abstract Sets the position of the listener in the 3D space + @param inX + A Float32 that represents the listener's position along the X axis. + @param inY + A Float32 that represents the listener's position along the Y axis. + @param inZ + A Float32 that represents the listener's position along the Z axis. + @result A OSStatus indicating success or failure. +*/ +OSStatus SoundEngine_SetListenerPosition(Float32 inX, Float32 inY, Float32 inZ); +OSStatus SoundEngine_SetListenerDirection(Float32 inX, Float32 inY, Float32 inZ); + +/*! + @function SoundEngine_SetListenerGain + @abstract Sets the gain of the listener. Must be >= 0.0 + @param inValue + A Float32 that represents the listener's gain + @result A OSStatus indicating success or failure. +*/ +OSStatus SoundEngine_SetListenerGain(Float32 inValue); + +/*! + @function SoundEngine_LoadBackgroundMusicTrack + @abstract Tells the background music player which file to play + @param inPath + The absolute path to the file to play. + @param inAddToQueue + If true, file will be added to the current background music queue. If + false, queue will be cleared and only loop the specified file. + @param inLoadAtOnce + If true, file will be loaded completely into memory. If false, data will be + streamed from the file as needed. For games without large memory pressure and/or + small background music files, this can save memory access and improve power efficiency + @result A OSStatus indicating success or failure. +*/ +OSStatus SoundEngine_LoadBackgroundMusicTrack(const char* inPath, Boolean inAddToQueue, Boolean inLoadAtOnce); + +/*! + @function SoundEngine_UnloadBackgroundMusicTrack + @abstract Tells the background music player to release all resources and stop playing. + @result A OSStatus indicating success or failure. +*/ +OSStatus SoundEngine_UnloadBackgroundMusicTrack(); + +/*! + @function SoundEngine_StartBackgroundMusic + @abstract Tells the background music player to start playing. + @result A OSStatus indicating success or failure. +*/ +OSStatus SoundEngine_StartBackgroundMusic(); + +/*! + @function SoundEngine_StopBackgroundMusic + @abstract Tells the background music player to stop playing. + @param inAddToQueue + If true, playback will stop when all tracks have completed. If false, playback + will stop immediately. + @result A OSStatus indicating success or failure. +*/ +OSStatus SoundEngine_StopBackgroundMusic(Boolean inStopAtEnd); + +/*! + @function SoundEngine_SetBackgroundMusicVolume + @abstract Sets the volume for the background music player + @param inValue + A Float32 that represents the level. The range is between 0.0 and 1.0 (inclusive). + @result A OSStatus indicating success or failure. +*/ +OSStatus SoundEngine_SetBackgroundMusicVolume(Float32 inValue); + +/*! + @function SoundEngine_GetBackgroundMusicVolume + @abstract Gets the volume for the background music player + @result A Float32 representing the background music player volume, or 0 if it's not enabled +*/ + Float32 SoundEngine_GetBackgroundMusicVolume(); + +/*! + @function SoundEngine_LoadLoopingEffect + @abstract Loads a sound effect from a file and return an ID to refer to that effect. Note: The files + MUST all be in the same data format and sample rate + @param inLoopFilePath + The absolute path to the file to load. This is the file that will loop continually. + @param inAttackFilePath + The absolute path to the file to load. This will play once at the start of the effect. + Set to NULL if no attack is desired, looping file will play immediately. + @param inDecayFilePath + The absolute path to the file to load. This will play once after looping has been ended. + Triggered using SoundEngine_StopEffect with the inDoDecay set to true. Set to NULL if no + decay is desired, looping file will stop immediately. + @param outEffectID + A UInt32 ID that refers to the effect. + @result A OSStatus indicating success or failure. +*/ +OSStatus SoundEngine_LoadLoopingEffect(const char* inLoopFilePath, const char* inAttackFilePath, const char* inDecayFilePath, UInt32* outEffectID); + +/*! + @function SoundEngine_LoadEffect + @abstract Loads a sound effect from a file and return an ID to refer to that effect. + @param inPath + The absolute path to the file to load. + @param outEffectID + A UInt32 ID that refers to the effect. + @result A OSStatus indicating success or failure. +*/ +OSStatus SoundEngine_LoadEffect(const char* inPath, UInt32* outEffectID); + +/*! + @function SoundEngine_UnloadEffect + @abstract Releases all resources associated with the given effect ID + @param inEffectID + The ID of the effect to unload. + @result A OSStatus indicating success or failure. +*/ +OSStatus SoundEngine_UnloadEffect(UInt32 inEffectID); + +/*! + @function SoundEngine_StartEffect + @abstract Starts playback of an effect + @param inEffectID + The ID of the effect to start. + @result A OSStatus indicating success or failure. +*/ +OSStatus SoundEngine_StartEffect(UInt32 inEffectID); + +/*! + @function SoundEngine_StopEffect + @abstract Stops playback of an effect + @param inEffectID + The ID of the effect to stop. + @param inDoDecay + Whether to play the decay file or stop immmediately (this is ignored + for non-looping effects) + @result A OSStatus indicating success or failure. +*/ +OSStatus SoundEngine_StopEffect(UInt32 inEffectID, Boolean inDoDecay); + +/*! + @function SoundEngine_Vibrate + @abstract Tells the device to vibrate +*/ +#if TARGET_OS_IPHONE + #define SoundEngine_Vibrate() AudioServicesPlaySystemSound(kSystemSoundID_Vibrate) +#endif + +/*! + @function SoundEngine_SetEffectPitch + @abstract Applies pitch shifting to an effect + @param inEffectID + The ID of the effect to adjust + @param inValue + A Float32 that represents the pitch scalar, with 1.0 being unchanged. Must + be greater than 0. + @result A OSStatus indicating success or failure. +*/ +OSStatus SoundEngine_SetEffectPitch(UInt32 inEffectID, Float32 inValue); + +/*! + @function SoundEngine_SetEffectVolume + @abstract Sets the volume for an effect + @param inEffectID + The ID of the effect to adjust + @param inValue + A Float32 that represents the level. The range is between 0.0 and 1.0 (inclusive). + @result A OSStatus indicating success or failure. +*/ +OSStatus SoundEngine_SetEffectLevel(UInt32 inEffectID, Float32 inValue); + +/*! + @function SoundEngine_SetEffectPosition + @abstract Tells the engine whether a given effect should loop when played or if it should + play through just once and stop. + @param inEffectID + The ID of the effect to adjust + @param inX + A Float32 that represents the effect's position along the X axis. Maximum distance + is 100000.0 (absolute, not per axis), reference distance (distance from which gain + begins to attenuate) is 1.0 + @param inY + A Float32 that represents the effect's position along the Y axis. Maximum distance + is 100000.0 (absolute, not per axis), reference distance (distance from which gain + begins to attenuate) is 1.0 + @param inZ + A Float32 that represents the effect's position along the Z axis. Maximum distance + is 100000.0 by default (absolute, not per axis), reference distance (distance from + which gain begins to attenuate) is 1.0 + @result A OSStatus indicating success or failure. +*/ +OSStatus SoundEngine_SetEffectPosition(UInt32 inEffectID, Float32 inX, Float32 inY, Float32 inZ); + +/*! + @function SoundEngine_SetEffectsVolume + @abstract Sets the overall volume for the effects + @param inValue + A Float32 that represents the level. The range is between 0.0 and 1.0 (inclusive). + @result A OSStatus indicating success or failure. +*/ +OSStatus SoundEngine_SetEffectsVolume(Float32 inValue); + +/*! + @function SoundEngine_GetEffectsVolume + @abstract Gets the overall volume for the effects + @result A Float32 representing the effects volume, or 0 if it's disabled +*/ +Float32 SoundEngine_GetEffectsVolume(); + +/*! + @function SoundEngine_SetMaxDistance + @abstract Sets the maximum distance for effect attenuation. Gain will attenuate between the + reference distance and the maximum distance, after which gain will be 0.0 + @param inValue + A Float32 that represents the level. Must be greater than 0.0. + @result A OSStatus indicating success or failure. +*/ +OSStatus SoundEngine_SetMaxDistance(Float32 inValue); + +/*! + @function SoundEngine_SetReferenceDistance + @abstract Sets the distance at which effect gain attenuation begins. It will attenuate between + the reference distance and the maximum distance. Sounds closer than the reference + distance will have no attenuation applied + @param inValue + A Float32 that represents the level. Must be greater than 0.0. + @result A OSStatus indicating success or failure. +*/ +OSStatus SoundEngine_SetReferenceDistance(Float32 inValue); + +/*! + @function SoundEngine_SetEffectReferenceDistance + @abstract Sets the distance at which effect gain attenuation begins. It will attenuate between + the reference distance and the maximum distance. Sounds closer than the reference + distance will have no attenuation applied + @param inEffectId + The sound engine effect Id + @param inValue + A Float32 that represents the level. Must be greater than 0.0. + @result A OSStatus indicating success or failure. +*/ +OSStatus SoundEngine_SetEffectReferenceDistance(UInt32 inEffectID, Float32 inValue); + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/common/ios/doomengine/arialGlyphRects.h b/common/ios/doomengine/arialGlyphRects.h new file mode 100755 index 0000000..1f95554 --- /dev/null +++ b/common/ios/doomengine/arialGlyphRects.h @@ -0,0 +1,123 @@ +/* + + Copyright (C) 2009 Id Software, 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 + 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. + + */ + + +// generated by fontimg +// + +// struct GlyphRect { unsigned short x0, y0, x1, y1; float xoff, yoff, xadvance; }; +GlyphRect glyphRects[] = { + /* ' ' */ { 2, 2, 2, 2, 0.000000, 0.000000, 7.958042 }, + /* '!' */ { 6, 2, 9, 22, 2.250000, -20.750000, 7.958042 }, + /* '"' */ { 14, 2, 21, 9, 1.250000, -20.750000, 10.167832 }, + /* '#' */ { 26, 2, 41, 23, 0.250000, -21.000000, 15.930070 }, + /* '$' */ { 46, 2, 59, 27, 1.000000, -22.500000, 15.930070 }, + /* '%' */ { 64, 2, 86, 24, 1.500000, -21.000000, 25.468531 }, + /* '&' */ { 92, 2, 109, 23, 1.000000, -21.000000, 19.104895 }, + /* ''' */ { 114, 2, 117, 9, 1.250000, -20.750000, 5.468532 }, + /* '(' */ { 122, 2, 129, 29, 1.500000, -21.000000, 9.538462 }, + /* ')' */ { 134, 2, 141, 29, 1.500000, -21.000000, 9.538462 }, + /* '*' */ { 146, 2, 155, 11, 0.750000, -21.000000, 11.146853 }, + /* '+' */ { 160, 2, 173, 15, 1.500000, -17.000000, 16.727272 }, + /* ',' */ { 178, 2, 181, 9, 2.250000, -3.000000, 7.958042 }, + /* '-' */ { 186, 2, 194, 4, 0.750000, -8.750000, 9.538462 }, + /* '.' */ { 198, 2, 201, 5, 2.500000, -3.000000, 7.958042 }, + /* '/' */ { 206, 2, 214, 23, 0.000000, -21.000000, 7.958042 }, + /* '0' */ { 218, 2, 231, 23, 1.000000, -20.750000, 15.930070 }, + /* '1' */ { 236, 2, 243, 22, 3.000000, -20.750000, 15.930070 }, + /* '2' */ { 2, 34, 15, 54, 0.750000, -20.750000, 15.930070 }, + /* '3' */ { 20, 34, 33, 55, 1.000000, -20.750000, 15.930070 }, + /* '4' */ { 38, 34, 52, 54, 0.250000, -20.750000, 15.930070 }, + /* '5' */ { 58, 34, 72, 54, 1.000000, -20.250000, 15.930070 }, + /* '6' */ { 76, 34, 89, 55, 1.000000, -20.750000, 15.930070 }, + /* '7' */ { 94, 34, 107, 54, 1.250000, -20.250000, 15.930070 }, + /* '8' */ { 112, 34, 125, 55, 1.000000, -20.750000, 15.930070 }, + /* '9' */ { 130, 34, 143, 55, 1.000000, -20.750000, 15.930070 }, + /* ':' */ { 148, 34, 151, 49, 2.500000, -15.000000, 7.958042 }, + /* ';' */ { 156, 34, 159, 53, 2.250000, -15.000000, 7.958042 }, + /* '<' */ { 164, 34, 177, 48, 1.500000, -17.250000, 16.727272 }, + /* '=' */ { 182, 34, 195, 42, 1.500000, -14.500000, 16.727272 }, + /* '>' */ { 200, 34, 213, 48, 1.500000, -17.250000, 16.727272 }, + /* '?' */ { 218, 34, 231, 55, 1.250000, -21.000000, 15.930070 }, + /* '@' */ { 2, 60, 28, 87, 1.500000, -21.000000, 29.076923 }, + /* 'A' */ { 34, 60, 53, 80, -0.250000, -20.750000, 19.104895 }, + /* 'B' */ { 58, 60, 73, 80, 2.000000, -20.750000, 19.104895 }, + /* 'C' */ { 78, 60, 96, 81, 1.250000, -21.000000, 20.685314 }, + /* 'D' */ { 102, 60, 119, 80, 2.000000, -20.750000, 20.685314 }, + /* 'E' */ { 124, 60, 139, 80, 2.250000, -20.750000, 19.104895 }, + /* 'F' */ { 144, 60, 158, 80, 2.250000, -20.750000, 17.496504 }, + /* 'G' */ { 162, 60, 181, 81, 1.500000, -21.000000, 22.279720 }, + /* 'H' */ { 186, 60, 202, 80, 2.250000, -20.750000, 20.685314 }, + /* 'I' */ { 208, 60, 211, 80, 2.500000, -20.750000, 7.958042 }, + /* 'J' */ { 216, 60, 227, 81, 0.750000, -20.750000, 14.321678 }, + /* 'K' */ { 232, 60, 249, 80, 2.000000, -20.750000, 19.104895 }, + /* 'L' */ { 2, 92, 15, 112, 2.000000, -20.750000, 15.930070 }, + /* 'M' */ { 20, 92, 39, 112, 2.000000, -20.750000, 23.860140 }, + /* 'N' */ { 44, 92, 60, 112, 2.000000, -20.750000, 20.685314 }, + /* 'O' */ { 66, 92, 85, 113, 1.250000, -21.000000, 22.279720 }, + /* 'P' */ { 90, 92, 106, 112, 2.000000, -20.750000, 19.104895 }, + /* 'Q' */ { 110, 92, 130, 114, 1.000000, -21.000000, 22.279720 }, + /* 'R' */ { 136, 92, 154, 112, 2.250000, -20.750000, 20.685314 }, + /* 'S' */ { 160, 92, 176, 113, 1.250000, -21.000000, 19.104895 }, + /* 'T' */ { 182, 92, 198, 112, 0.500000, -20.750000, 17.496504 }, + /* 'U' */ { 204, 92, 220, 113, 2.250000, -20.750000, 20.685314 }, + /* 'V' */ { 226, 92, 245, 112, 0.000000, -20.750000, 19.104895 }, + /* 'W' */ { 2, 120, 28, 140, 0.250000, -20.750000, 27.034966 }, + /* 'X' */ { 34, 120, 53, 140, 0.000000, -20.750000, 19.104895 }, + /* 'Y' */ { 58, 120, 77, 140, 0.000000, -20.750000, 19.104895 }, + /* 'Z' */ { 82, 120, 98, 140, 0.500000, -20.750000, 17.496504 }, + /* '[' */ { 104, 120, 109, 146, 1.750000, -20.750000, 7.958042 }, + /* '\' */ { 114, 120, 122, 141, 0.000000, -21.000000, 7.958042 }, + /* ']' */ { 126, 120, 131, 146, 0.500000, -20.750000, 7.958042 }, + /* '^' */ { 136, 120, 148, 131, 0.750000, -21.000000, 13.440559 }, + /* '_' */ { 152, 120, 169, 122, -0.500000, 3.750000, 15.930070 }, + /* '`' */ { 174, 120, 179, 124, 1.000000, -20.750000, 9.538462 }, + /* 'a' */ { 184, 120, 197, 135, 1.000000, -15.250000, 15.930070 }, + /* 'b' */ { 202, 120, 215, 141, 1.750000, -20.750000, 15.930070 }, + /* 'c' */ { 220, 120, 233, 135, 1.000000, -15.250000, 14.321678 }, + /* 'd' */ { 238, 120, 251, 141, 0.750000, -20.750000, 15.930070 }, + /* 'e' */ { 2, 152, 15, 167, 1.000000, -15.250000, 15.930070 }, + /* 'f' */ { 20, 152, 28, 173, 0.250000, -21.000000, 7.958042 }, + /* 'g' */ { 34, 152, 47, 173, 0.750000, -15.250000, 15.930070 }, + /* 'h' */ { 52, 152, 64, 172, 1.750000, -20.750000, 15.930070 }, + /* 'i' */ { 70, 152, 72, 172, 1.750000, -20.750000, 6.363636 }, + /* 'j' */ { 78, 152, 84, 179, -1.500000, -20.750000, 6.363636 }, + /* 'k' */ { 88, 152, 100, 172, 1.750000, -20.750000, 14.321678 }, + /* 'l' */ { 106, 152, 108, 172, 1.750000, -20.750000, 6.363636 }, + /* 'm' */ { 114, 152, 134, 167, 1.750000, -15.250000, 23.860140 }, + /* 'n' */ { 140, 152, 152, 167, 1.750000, -15.250000, 15.930070 }, + /* 'o' */ { 158, 152, 172, 167, 0.750000, -15.250000, 15.930070 }, + /* 'p' */ { 178, 152, 191, 173, 1.750000, -15.250000, 15.930070 }, + /* 'q' */ { 196, 152, 209, 173, 1.000000, -15.250000, 15.930070 }, + /* 'r' */ { 214, 152, 222, 167, 1.750000, -15.250000, 9.538462 }, + /* 's' */ { 228, 152, 240, 167, 0.750000, -15.250000, 14.321678 }, + /* 't' */ { 246, 152, 253, 172, 0.500000, -20.250000, 7.958042 }, + /* 'u' */ { 2, 184, 14, 199, 1.750000, -15.000000, 15.930070 }, + /* 'v' */ { 20, 184, 33, 199, 0.250000, -15.000000, 14.321678 }, + /* 'w' */ { 38, 184, 58, 199, 0.000000, -15.000000, 20.685314 }, + /* 'x' */ { 64, 184, 78, 199, 0.000000, -15.000000, 14.321678 }, + /* 'y' */ { 84, 184, 98, 205, 0.250000, -15.000000, 14.321678 }, + /* 'z' */ { 102, 184, 115, 199, 0.500000, -15.000000, 14.321678 }, + /* '{' */ { 120, 184, 128, 211, 0.750000, -21.000000, 9.566434 }, + /* '|' */ { 134, 184, 136, 211, 2.500000, -21.000000, 7.440559 }, + /* '}' */ { 142, 184, 150, 211, 0.500000, -21.000000, 9.566434 }, + /* '~' */ { 156, 184, 170, 188, 1.000000, -12.500000, 16.727272 }, + /* '' */ { 176, 184, 190, 202, 3.500000, -18.000000, 21.482517 } +}; diff --git a/common/ios/doomengine/cmd.c b/common/ios/doomengine/cmd.c new file mode 100755 index 0000000..56fa1b8 --- /dev/null +++ b/common/ios/doomengine/cmd.c @@ -0,0 +1,166 @@ +/* + * cmd.c + * doom + * + * Created by John Carmack on 4/14/09. + * Copyright 2009 id Software. All rights reserved. + * + */ +/* + 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 "doomiphone.h" + +typedef struct cmd_function_s { + struct cmd_function_s *next; + const char *name; + int hashid; + xcommand_t function; +} cmd_function_t; + + +#define MAX_STRING_TOKENS 16 +#define MAX_STRING_CHARS 1024 + +int cmd_argc; +char *cmd_argv[ MAX_STRING_TOKENS ]; + +cmd_function_t *cmd_functions; // possible commands to execute + +int Cmd_Argc( void ) { + return cmd_argc; +} + +const char *Cmd_Argv( int arg ) { + if( arg >= cmd_argc ) { + return ""; + } + + return cmd_argv[ arg ]; +} + + +void Cmd_TokenizeString( const char *text ) { + static char *stringCopy; + + // clear the args from the last string + // This better not be called recursively... + if ( stringCopy ) { + free( stringCopy ); + stringCopy = NULL; + } + + cmd_argc = 0; + + if( ! text ) { + return; + } + + stringCopy = strdup( text ); + char *strval = stringCopy; + + while( 1 ) { + char *start = strsep( &strval," \t\r\n"); + if ( !start ) { + break; + } + if ( start[0] != 0 ) { + cmd_argv[cmd_argc] = start; + if ( ++cmd_argc == MAX_STRING_TOKENS ) { + break; + } + } + } +} + +void Cmd_ListCommands_f() { + for( cmd_function_t *cmd = cmd_functions ; cmd ; cmd = cmd->next ) { + Com_Printf( "%s\n", cmd->name ); + } +} + +void Cmd_AddCommand( const char *cmd_name, xcommand_t function ) { + cmd_function_t *cmd; + int hashid; + + hashid = HashString( cmd_name ); + + // fail if the command already exists + for( cmd = cmd_functions ; cmd ; cmd = cmd->next ) { + if( hashid == cmd->hashid && !strcmp( cmd_name, cmd->name ) ) { + Com_Printf( "Cmd_AddCommand: \"%s\" already defined\n", cmd_name ); + return; + } + } + + cmd = malloc( sizeof( cmd_function_t ) ); + cmd->name = cmd_name; + cmd->hashid = hashid; + cmd->function = function; + cmd->next = cmd_functions; + cmd_functions = cmd; + +} + +void Cmd_ExecuteString( const char *str ) { + int l = strlen( str ); + if ( str[l-1] == '\n' ) { + char *stripped = alloca( l+1 ); + strcpy( stripped, str ); + str = stripped; + stripped[l-1] = 0; + } + + Com_Printf( "%s\n", str ); + Cmd_TokenizeString( str ); + + const char *arg0 = Cmd_Argv( 0 ); + int hashid = HashString( arg0 ); + + // check commands first + for( cmd_function_t *cmd = cmd_functions ; cmd ; cmd = cmd->next ) { + if( hashid == cmd->hashid && !strcmp( arg0, cmd->name ) ) { + cmd->function(); + return; + } + } + + // then check cvars + cvar_t *cvar = Cvar_FindVar( arg0 ); + if ( cvar ) { + Cvar_Set( arg0, Cmd_Argv( 1 ) ); + return; + } + Com_Printf( "Unknown command: %s\n", arg0 ); +} + +// execute each line of the config file +void Cmd_ExecuteFile( const char *fullPathName ) { + Com_Printf( "Executing command file '%s'\n", fullPathName ); + FILE *f = fopen( fullPathName, "rb" ); + if ( !f ) { + Com_Printf( "Failed to open.\n" ); + return; + } + char line[1024]; + while( fgets( line, sizeof( line ), f ) ) { + Cmd_ExecuteString( line ); + } + fclose( f ); +} + diff --git a/common/ios/doomengine/cvar.c b/common/ios/doomengine/cvar.c new file mode 100755 index 0000000..3b0f1c6 --- /dev/null +++ b/common/ios/doomengine/cvar.c @@ -0,0 +1,374 @@ +/* + + Copyright (C) 2004 Michael Liebscher + Copyright (C) 1997-2001 Id Software, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General 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 License for more details. + + You should have received a copy of the GNU General 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 "doomiphone.h" + + +cvar_t *cvar_vars; + + +/* +----------------------------------------------------------------------------- + Function: Cvar_FindVar -Return cvar; + + Parameters: var_name -[in] Name of cvar to lookup. + + Returns: NULL if cvar not found, otherwise returns the cvar. + + Notes: + +----------------------------------------------------------------------------- +*/ +cvar_t *Cvar_FindVar( const char *var_name ) +{ + cvar_t *var; + int hashid; + + hashid = HashString( var_name ); + + for( var = cvar_vars ; var ; var = var->next ) + { + if( hashid == var->hashid && !strcasecmp( var_name, var->name ) ) + { + return var; + } + } + + return NULL; +} + +/* +----------------------------------------------------------------------------- + Function: Cvar_VariableValue -Get value of cvar. + + Parameters: var_name -[in] Name of cvar to get value. + + Returns: 0 if not found, other the value of the cvar. + + Notes: + +----------------------------------------------------------------------------- +*/ + float Cvar_VariableValue( const char *var_name ) +{ + cvar_t *var; + + var = Cvar_FindVar( var_name ); + if( ! var ) + { + return 0; + } + + return (float)atof( var->string ); +} + + +/* +----------------------------------------------------------------------------- + Function: Cvar_VariableString -Get cvar variable as string. + + Parameters: var_name -[in] Name of cvar to get value. + + Returns: Blank string on error, otherwise value string. + + Notes: + +----------------------------------------------------------------------------- +*/ + char *Cvar_VariableString( const char *var_name ) +{ + cvar_t *var; + + var = Cvar_FindVar( var_name ); + if( ! var ) + { + return ""; + } + + return var->string; +} + +/* +----------------------------------------------------------------------------- + Function: Cvar_CompleteVariable -Complete cvar string name. + + Parameters: partial -[in] Partial name of string to look up. + + Returns: NULL if partial string not found, otherwise the complete + string name. + + Notes: + +----------------------------------------------------------------------------- +*/ + char *Cvar_CompleteVariable( const char *partial ) +{ + cvar_t *cvar; + size_t len; + + len = strlen( partial ); + + if( ! len ) + { + return NULL; + } + +// +// Check partial match. +// + for( cvar = cvar_vars ; cvar ; cvar = cvar->next ) + { + if( ! strncmp( partial, cvar->name, len ) ) + { + return cvar->name; + } + } + + return NULL; +} + +/* +----------------------------------------------------------------------------- + Function: Cvar_Get -Get cvar structure. + + Parameters: + var_name -[in] the name of the cvar variable. + var_value -[in] string value of the cvar variable. + flags -[in] see CVARFlags for more information. + + Returns: NULL on error, otherwise valid pointer to cvar_t structure. + + Notes: + If the variable already exists, the value will not be set and + the flags will be or'ed. +----------------------------------------------------------------------------- +*/ +cvar_t *Cvar_Get( const char *var_name, const char *var_value, CVARFlags flags ) { + cvar_t *var; + + var = Cvar_FindVar( var_name ); + if( var ) { + var->flags |= flags; + return var; + } + + if( ! var_value ) { + return NULL; + } + + var = malloc( sizeof( *var ) ); + var->name = strdup( var_name ); + var->string = strdup( var_value ); + var->defaultString = strdup( var_value ); + var->hashid = HashString( var_name ); + var->modified = true; + var->value = (float)atof( var->string ); + + // link the variable in + var->next = cvar_vars; + cvar_vars = var; + + var->flags = flags; + + return var; +} + +/* +----------------------------------------------------------------------------- + Function: + + Parameters: + + Returns: + + Notes: + +----------------------------------------------------------------------------- +*/ +void Cvar_Set( const char *var_name, const char *value ) { + cvar_t *var; + + var = Cvar_FindVar( var_name ); + if( ! var ) { + Com_Printf( "Cvar '%s' doesn't exist\n", var_name ); + return; + } + + if( var->flags & CVAR_NOSET ) { + Com_Printf( "%s is write protected.\n", var_name ); + return; + } + + + if( ! strcmp( value, var->string ) ) { + return; // not changed + } + + var->modified = true; + + free( var->string ); // free the old value string + + var->string = strdup( value ); + var->value = (float)atof( var->string ); +} + + +/* +----------------------------------------------------------------------------- + Function: + + Parameters: + + Returns: + + Notes: + +----------------------------------------------------------------------------- +*/ + void Cvar_SetValue( const char *var_name, float value ) +{ + char val[ 32 ]; + + if( value == (int)value ) + { + snprintf( val, sizeof( val ), "%i", (int)value ); + } + else + { + snprintf( val, sizeof( val ), "%f", value ); + } + + Cvar_Set( var_name, val ); +} + + + +/* +----------------------------------------------------------------------------- + Function: Cvar_Command -Handles variable inspection and changing from + the console. + + Parameters: Nothing. + + Returns: false if variable not found, otherwise true. + + Notes: + +----------------------------------------------------------------------------- +*/ +boolean Cvar_Command( void ) +{ + cvar_t *v; + +// check variables + v = Cvar_FindVar( Cmd_Argv( 0 ) ); + if( ! v ) + { + return false; + } + +// perform a variable print or set + if( Cmd_Argc() == 1 ) + { + Com_Printf( "\"%s\" is \"%s\"\n", v->name, v->string ); + return true; + } + + Cvar_Set( v->name, Cmd_Argv( 1 ) ); + return true; +} + + +/* +----------------------------------------------------------------------------- + Function: Cvar_WriteVariables -Appends lines containing "set variable value" + for all variables with the archive flag set + to true. + + Parameters: + + Returns: Nothing. + + Notes: + +----------------------------------------------------------------------------- +*/ + void Cvar_WriteVariables( const char *path ) +{ + cvar_t *var; + char buffer[1024]; + FILE *f; + + f = fopen( path, "a" ); + for( var = cvar_vars ; var ; var = var->next ) + { + if( var->flags & CVAR_ARCHIVE ) + { + snprintf( buffer, sizeof( buffer ), "set %s %s\n", var->name, var->string ); + fprintf( f, "%s", buffer ); + } + } + fclose( f ); +} + +/* +----------------------------------------------------------------------------- + Function: Cvar_List_f -Print all cvars to the console. + + Parameters: Nothing. + + Returns: Nothing. + + Notes: + +----------------------------------------------------------------------------- +*/ +void Cvar_List_f( void ) +{ + cvar_t *var; + int i; + + i = 0; + for( var = cvar_vars ; var ; var = var->next, ++i ) + { + if( var->flags & CVAR_ARCHIVE ) + { + Com_Printf ("*"); + } + else + { + Com_Printf (" "); + } + + + Com_Printf (" %s \"%s\"\n", var->name, var->string); + } + + Com_Printf ("%i cvars\n", i); +} + + +void Cvar_Reset_f( void ) { + for( cvar_t *var = cvar_vars ; var ; var = var->next ) { + Cvar_Set( var->name, var->defaultString ); + } +} + diff --git a/common/ios/doomengine/cvar.h b/common/ios/doomengine/cvar.h new file mode 100755 index 0000000..9ff86aa --- /dev/null +++ b/common/ios/doomengine/cvar.h @@ -0,0 +1,139 @@ +/* + + Copyright (C) 2004 Michael Liebscher + Copyright (C) 1997-2001 Id Software, 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 + 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. + +*/ + +/* + * cvar.h: Dynamic variable tracking. + * + * Author: Michael Liebscher + * Date: 2004 + * + * Acknowledgement: + * This code was derived from Quake II, and was originally + * written by Id Software, Inc. + * + */ + +/* + +Notes: + + Dynamic variable tracking. + + cvar_t variables are used to hold scalar or string variables + that can be changed or displayed at the console or prog code + as well as accessed directly in C code. + + The user can access cvars from the console in three ways: + r_draworder -prints the current value + r_draworder 0 -sets the current value to 0 + set r_draworder 0 -as above, but creates the cvar if not present + + Cvars are restricted from having the same names as commands to keep this + module from being ambiguous. + + This module is implemented by cvar.c + +*/ + +#ifndef __CVAR_H__ +#define __CVAR_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum _CVARFlags +{ + CVAR_INIT = 0x0, // Just create it with no flag value. + CVAR_ARCHIVE = 0x1, // Set to cause it to be saved to the config file + CVAR_NOSET = 0x8, // Don't allow change from console at all, + // but can be set from the command line. +} CVARFlags; + + +// nothing outside the Cvar_*() functions should modify these fields! +typedef struct cvar_s { + // By putting the value first, cvars can be referenced in other code + // as just extern float *name, without having to include the cvar_t + // declaration. This is probably a bad idea that I will + // regret at some point. + float value; + + char *name; + char *string; + char *defaultString; + int hashid; + int flags; + boolean modified; // set each time the cvar is changed + struct cvar_s *next; +} cvar_t; + +extern cvar_t *cvar_vars; + +void Cvar_List_f(); +void Cvar_Reset_f(); + +extern cvar_t *Cvar_Get( const char *var_name, const char *value, CVARFlags flags ); +// creates the variable if it doesn't exist, or returns the existing one +// if it exists, the value will not be changed, but flags will be ORed in +// that allows variables to be unarchived without needing bitflags + +extern cvar_t *Cvar_FindVar( const char *var_name ); +// returns NULL if it doesn't exist + +extern void Cvar_Set( const char *var_name, const char *value ); +// prints warning if it doesn't exist + +extern void Cvar_SetValue( const char *var_name, float value ); +// expands value to a string and calls Cvar_Set + +extern float Cvar_VariableValue( const char *var_name ); +// returns 0 if not defined or non numeric + +extern char *Cvar_VariableString( const char *var_name ); +// returns an empty string if not defined + +extern char *Cvar_CompleteVariable( const char *partial ); +// attempts to match a partial variable name for command line completion +// returns NULL if nothing fits + +extern void Cvar_GetLatchedVars( void ); +// any CVAR_LATCHED variables that have been set will now take effect + +extern void Cvar_WriteVariables( const char *path ); +// appends lines containing "set variable value" for all variables +// with the archive flag set to true. + +extern void Cvar_Init( void ); + +extern char *Cvar_Userinfo( void ); +// returns an info string containing all the CVAR_USERINFO cvars + +extern char *Cvar_Serverinfo( void ); +// returns an info string containing all the CVAR_SERVERINFO cvars + +#ifdef __cplusplus +} +#endif + + +#endif /* __CVAR_H__ */ + diff --git a/common/ios/doomengine/doomiphone.h b/common/ios/doomengine/doomiphone.h new file mode 100755 index 0000000..618875e --- /dev/null +++ b/common/ios/doomengine/doomiphone.h @@ -0,0 +1,140 @@ +/* + * doomiphone.h + * doom + * + * Created by John Carmack on 3/13/09. + * Copyright 2009 idSoftware. All rights reserved. + * + */ +/* + + Copyright (C) 2009 Id Software, 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 + 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. + + */ + +#ifndef _DOOM_IPHONE_H_ +#define _DOOM_IPHONE_H_ + +#define IS_IPAD (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) +#define IS_IPHONE (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) +#define IS_IPHONE_5 (IS_IPHONE && [[UIScreen mainScreen] bounds].size.height == 568.0f) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include "gles_glue.h" + +#include +#include +#include +#undef ALCAPI +#define ALCAPI + +#ifdef __cplusplus +extern "C" { +#endif + +#include "prboom/SDL_opengl.h" + +// prBoom code +#include "prboom/m_fixed.h" +#include "prboom/doomdef.h" +#include "prboom/doomtype.h" +#include "prboom/doomstat.h" +#include "prboom/d_net.h" +#include "prboom/dstrings.h" +#include "prboom/sounds.h" +#include "prboom/z_zone.h" +#include "prboom/w_wad.h" +#include "prboom/s_sound.h" +#include "prboom/v_video.h" +#include "prboom/f_finale.h" +#include "prboom/f_wipe.h" +#include "prboom/m_argv.h" +#include "prboom/m_misc.h" +#include "prboom/m_menu.h" +#include "prboom/p_checksum.h" +#include "prboom/i_main.h" +#include "prboom/i_system.h" +#include "prboom/i_sound.h" +#include "prboom/i_video.h" +#include "prboom/g_game.h" +#include "prboom/hu_stuff.h" +#include "prboom/wi_stuff.h" +#include "prboom/st_stuff.h" +#include "prboom/am_map.h" +#include "prboom/p_setup.h" +#include "prboom/r_draw.h" +#include "prboom/r_main.h" +#include "prboom/r_fps.h" +#include "prboom/d_main.h" +#include "prboom/d_deh.h" +#include "prboom/lprintf.h" +#include "prboom/am_map.h" +#include "prboom/gl_intern.h" +#include "prboom/p_mobj.h" +#include "prboom/p_maputl.h" +#include "prboom/p_map.h" +// open / close name collision problem... #include "prboom/p_spec.h" +#include "prboom/p_inter.h" +#include "prboom/m_random.h" +#include "prboom/m_bbox.h" +#include "prboom/m_cheat.h" + +// we will now define landscapeViewport / landscapeScissor to rotate the coords +#undef glViewport +#undef glScissor + +// our vestigial system environment +#include "misc.h" +#include "cvar.h" + +// new iphone code +#include "ipak.h" +#include "iphone_email.h" //gsh, adds support for emailing the console to id + +#ifdef __cplusplus +} +#endif + +#include "iphone_doom.h" + +#endif diff --git a/common/ios/doomengine/gles_glue.c b/common/ios/doomengine/gles_glue.c new file mode 100755 index 0000000..5a786ea --- /dev/null +++ b/common/ios/doomengine/gles_glue.c @@ -0,0 +1,228 @@ +/* + + Copyright (C) 2009 Id Software, 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 + 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 "doomiphone.h" + +//int registration_sequence; + +//#include "iphone_gl.h" + +void R_Draw_Blend( int x, int y, int w, int h, color4_t c ) { + + x *= ((float)displaywidth) / 480.0f; + y *= ((float)displayheight) / 320.0f; + w *= ((float)displaywidth) / 480.0f; + h *= ((float)displayheight) / 320.0f; + + glDisable( GL_TEXTURE_2D ); + glColor4ubv( c ); + + glBegin( GL_QUADS ); + + glVertex2i( x, y ); + glVertex2i( x+w, y ); + glVertex2i( x+w, y+h ); + glVertex2i( x, y+h ); + + glEnd(); + + glColor3f( 1, 1, 1 ); + glEnable( GL_TEXTURE_2D ); +} + + +void R_Draw_Fill( int x, int y, int w, int h, color3_t c ) { + // as of 2.2 OS, doing a clear with a small scissor rect is MUCH slower + // than drawing geometry + color4_t c4; + c4[0] = c[0]; + c4[1] = c[1]; + c4[2] = c[2]; + c4[3] = 255; + R_Draw_Blend( x, y, w, h, c4 ); +} + +void GLCheckError(const char *message) { + GLint err = glGetError(); + if ( err != GL_NO_ERROR ) { + printf( "GL ERROR %d from %s\n", err, message ); + } +} + +unsigned int QGLBeginStarted = 0; + +struct Vertex { + float xyz[3]; + float st[2]; +#ifdef VERTEX_COLOR + GLubyte c[4]; +#endif +}; + +#define MAX_VERTS 16384 + +typedef struct Vertex Vertex; +Vertex immediate[ MAX_VERTS ]; +Vertex vab; +short quad_indexes[MAX_VERTS * 3 / 2 ]; +int curr_vertex; +GLenum curr_prim; + +void SetImmediateModeGLVertexArrays( void ) { + glVertexPointer( 3, GL_FLOAT, sizeof( Vertex ), immediate[ 0 ].xyz ); + glEnableClientState( GL_VERTEX_ARRAY ); + glTexCoordPointer( 2, GL_FLOAT, sizeof( Vertex ), immediate[ 0 ].st ); + glEnableClientState( GL_TEXTURE_COORD_ARRAY ); +#ifdef VERTEX_COLOR + glColorPointer( 4, GL_UNSIGNED_BYTE, sizeof( Vertex ), immediate[ 0 ].c ); + glEnableClientState( GL_COLOR_ARRAY ); +#endif +} + +void InitImmediateModeGL( void ) { + for ( int i = 0; i < MAX_VERTS * 3 / 2; i+=6 ) { + int q = i / 6 * 4; + quad_indexes[ i + 0 ] = q + 0; + quad_indexes[ i + 1 ] = q + 1; + quad_indexes[ i + 2 ] = q + 2; + + quad_indexes[ i + 3 ] = q + 0; + quad_indexes[ i + 4 ] = q + 2; + quad_indexes[ i + 5 ] = q + 3; + } + + SetImmediateModeGLVertexArrays(); +} + +void glBegin( GLenum prim ) { + curr_vertex = 0; + curr_prim = prim; +} + +void glVertex3f( GLfloat x, GLfloat y, GLfloat z ) { + assert( curr_vertex < MAX_VERTS ); + vab.xyz[ 0 ] = x; + vab.xyz[ 1 ] = y; + vab.xyz[ 2 ] = z; + immediate[ curr_vertex ] = vab; + curr_vertex++; +} +void glVertex3fv( GLfloat *xyz ) { + assert( curr_vertex < MAX_VERTS ); + vab.xyz[ 0 ] = xyz[0]; + vab.xyz[ 1 ] = xyz[1]; + vab.xyz[ 2 ] = xyz[2]; + immediate[ curr_vertex ] = vab; + curr_vertex++; +} +void glVertex2f( GLfloat x, GLfloat y ) { + assert( curr_vertex < MAX_VERTS ); + vab.xyz[ 0 ] = (float)x; + vab.xyz[ 1 ] = (float)y; + vab.xyz[ 2 ] = 0.0f; + immediate[ curr_vertex ] = vab; + curr_vertex++; +} +void glVertex2i( GLint x, GLint y ) { + assert( curr_vertex < MAX_VERTS ); + vab.xyz[ 0 ] = (float)x; + vab.xyz[ 1 ] = (float)y; + vab.xyz[ 2 ] = 0.0f; + immediate[ curr_vertex ] = vab; + curr_vertex++; +} + +#ifdef VERTEX_COLOR +void glColor4ub( GLubyte r, GLubyte g, GLubyte b, GLubyte a ) { + vab.c[ 0 ] = r; + vab.c[ 1 ] = g; + vab.c[ 2 ] = b; + vab.c[ 3 ] = a; +} +void glColor4ubv( GLubyte *rgba ) { + vab.c[ 0 ] = rgba[0]; + vab.c[ 1 ] = rgba[1]; + vab.c[ 2 ] = rgba[2]; + vab.c[ 3 ] = rgba[3]; +} +void glColor4f( GLfloat r, GLfloat g, GLfloat b, GLfloat a ) { + vab.c[ 0 ] = (GLubyte) ( r * 255 ); + vab.c[ 1 ] = (GLubyte) ( g * 255 ); + vab.c[ 2 ] = (GLubyte) ( b * 255 ); + vab.c[ 3 ] = (GLubyte) ( a * 255 ); +} +void glColor4fv( GLfloat *rgba ) { + vab.c[ 0 ] = (GLubyte) ( rgba[0] * 255 ); + vab.c[ 1 ] = (GLubyte) ( rgba[1] * 255 ); + vab.c[ 2 ] = (GLubyte) ( rgba[2] * 255 ); + vab.c[ 3 ] = (GLubyte) ( rgba[3] * 255 ); +} +void glColor3f( GLfloat r, GLfloat g, GLfloat b ) { + vab.c[ 0 ] = (GLubyte) ( r * 255 ); + vab.c[ 1 ] = (GLubyte) ( g * 255 ); + vab.c[ 2 ] = (GLubyte) ( b * 255 ); + vab.c[ 3 ] = 255; +} +#endif + +void glTexCoord2i( GLint s, GLint t ) { + vab.st[ 0 ] = (float)s; + vab.st[ 1 ] = (float)t; +} +void glTexCoord2f( GLfloat s, GLfloat t ) { + vab.st[ 0 ] = s; + vab.st[ 1 ] = t; +} +void glTexCoord2fv( GLfloat *st ) { + vab.st[ 0 ] = st[0]; + vab.st[ 1 ] = st[1]; +} + +void glEnd( void ) { +#if 0 + glVertexPointer( 3, GL_FLOAT, sizeof( Vertex ), immediate[ 0 ].xyz ); + glTexCoordPointer( 2, GL_FLOAT, sizeof( Vertex ), immediate[ 0 ].st ); + glColorPointer( 4, GL_UNSIGNED_BYTE, sizeof( Vertex ), immediate[ 0 ].c ); + glEnableClientState( GL_VERTEX_ARRAY ); + glEnableClientState( GL_TEXTURE_COORD_ARRAY ); + glEnableClientState( GL_COLOR_ARRAY ); +#endif + if ( curr_prim == GL_QUADS ) { + glDrawElements( GL_TRIANGLES, curr_vertex / 4 * 6, GL_UNSIGNED_SHORT, quad_indexes ); + GLCheckError("DrawElements"); + } else { + glDrawArrays( curr_prim, 0, curr_vertex ); + GLCheckError("DrawArrays"); + } + curr_vertex = 0; + curr_prim = 0; +} + +void landscapeViewport( GLint x, GLint y, GLsizei width, GLsizei height ) { + y = 0; // !@# + glViewport( y, x, height, width ); +} + +void landscapeScissor( GLint x, GLint y, GLsizei width, GLsizei height ) { + y = 0; // !@# + glScissor( y, x, height, width ); +} + diff --git a/common/ios/doomengine/gles_glue.h b/common/ios/doomengine/gles_glue.h new file mode 100755 index 0000000..6c1a62b --- /dev/null +++ b/common/ios/doomengine/gles_glue.h @@ -0,0 +1,55 @@ +/* + + Copyright (C) 2009 Id Software, 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 + 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. + + */ + + +#ifndef __GLES_GLUE_H__ +#define __GLES_GLUE_H__ + +#include + +#define GL_QUADS 888 + +#ifdef __cplusplus +extern "C" { +#endif + +void GLCheckError( const char *message ); + +void glBegin( GLenum prim ); +void glVertex2f( GLfloat x, GLfloat y ); +void glVertex3f( float x, float y, float z ); +void glVertex3fv( GLfloat *xyz ); +void glVertex2i( GLint x, GLint y ); +void glColor4ub( GLubyte r, GLubyte g, GLubyte b, GLubyte a ); +void glColor4ubv( GLubyte *rgba ); +void glColor3f( GLfloat r, GLfloat g, GLfloat b ); +void glColor4f( GLfloat r, GLfloat g, GLfloat b, GLfloat a ); +void glColor4fv( GLfloat *rgba ); +void glTexCoord2i( GLint s, GLint t ); +void glTexCoord2f( GLfloat s, GLfloat t ); +void glEnd( void ); + +void SetImmediateModeGLVertexArrays( void ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/common/ios/doomengine/hud.c b/common/ios/doomengine/hud.c new file mode 100755 index 0000000..bc02615 --- /dev/null +++ b/common/ios/doomengine/hud.c @@ -0,0 +1,235 @@ +/* + + Copyright (C) 2009 Id Software, 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 + 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 "doomiphone.h" +#include + +hud_t huds; + +void HudDraw(); + +void HudWrite(); + +void HudRead(); + +ibutton_t *dragHud; +int dragX, dragY; + +void SetHudPic( ibutton_t *hp, const char *image ) { + pkTexture_t *gl; + gl = PK_FindTexture( image ); + assert( gl ); + hp->texture = gl; + hp->touch = NULL; // in case one was down when it was saved +} + +void SetHudSpot( ibutton_t *hp, int x, int y, int dw, int dh ) { + hp->touch = NULL; // in case one was down when it was saved + + float xRatio = ((float)displaywidth) / 480.0f; + float yRatio = ((float)displayheight) / 320.0f; + + float themin = MIN( xRatio, yRatio ); + + x *= ((float)displaywidth) / 480.0f; + y *= ((float)displayheight) / 320.0f; + + dw *= themin; + dh *= themin; + + hp->x = x - dw/2; + hp->y = y - dh/2; + hp->drawWidth = dw; + hp->drawHeight = dh; + hp->buttonFlags = 0; + hp->scale = 1.0f; +} + +void HudSetTexnums() { + SetHudPic( &huds.forwardStick, "iphone/up_down.tga" ); + SetHudPic( &huds.sideStick, "iphone/side_2_side.tga" ); + SetHudPic( &huds.turnStick, "iphone/directional_2.tga" ); + SetHudPic( &huds.turnRotor, "iphone/rotate.tga" ); + SetHudPic( &huds.fire, "iphone/fire.tga" ); + SetHudPic( &huds.menu, "iphone/menu_button.tga" ); + SetHudPic( &huds.map, "iphone/map_button.tga" ); + + SetHudSpot( &huds.weaponSelect, 240, 280, 40, 40 ); +} + +void HudSetForScheme( int schemeNum ) { + for ( ibutton_t *hud = (ibutton_t *)&huds ; hud != (ibutton_t *)(&huds+1) ; hud++ ) { + hud->buttonFlags = BF_IGNORE; + } + int STICK_SIZE = 128; + int HALF_STICK = 128/2; + + if( displaywidth >= 1024 ) { + STICK_SIZE = 64; + HALF_STICK = 64/2; + } + + static const int BOTTOM = 320 - 44; // above the status bar + SetHudSpot( &huds.weaponSelect, 240, 280, 40, 40 ); // the touch area is doubled + + // make the forward / back sticks touch taller than they draw + switch ( schemeNum ) { + default: + case 0: // turn stick + SetHudSpot( &huds.forwardStick, HALF_STICK, BOTTOM-HALF_STICK, STICK_SIZE, STICK_SIZE ); + SetHudSpot( &huds.turnStick, HALF_STICK, BOTTOM-HALF_STICK, STICK_SIZE, STICK_SIZE ); + SetHudSpot( &huds.fire, 480-40, BOTTOM-HALF_STICK, 80, 80 ); + SetHudSpot( &huds.menu, 480-24, 24, 48, 48 ); + SetHudSpot( &huds.map, 24, 24, 48, 48 ); + break; + case 1: // dual stick + SetHudSpot( &huds.forwardStick, HALF_STICK, BOTTOM-HALF_STICK, STICK_SIZE, STICK_SIZE ); + SetHudSpot( &huds.sideStick, HALF_STICK, BOTTOM-HALF_STICK, STICK_SIZE, STICK_SIZE ); + SetHudSpot( &huds.turnStick, 480-HALF_STICK, BOTTOM-HALF_STICK, STICK_SIZE, STICK_SIZE ); + SetHudSpot( &huds.fire, 480-40, 40, 80, 80 ); + SetHudSpot( &huds.menu, 48+24, 24, 48, 48 ); + SetHudSpot( &huds.map, 24, 24, 48, 48 ); + break; + case 2: // rotor + SetHudSpot( &huds.forwardStick, HALF_STICK, BOTTOM-HALF_STICK, STICK_SIZE, STICK_SIZE ); + SetHudSpot( &huds.sideStick, HALF_STICK, BOTTOM-HALF_STICK, STICK_SIZE, STICK_SIZE ); + SetHudSpot( &huds.turnRotor, 480-HALF_STICK, BOTTOM-HALF_STICK, STICK_SIZE, STICK_SIZE ); + SetHudSpot( &huds.fire, 480-40, 40, 80, 80 ); + SetHudSpot( &huds.menu, 48+24, 24, 48, 48 ); + SetHudSpot( &huds.map, 24, 24, 48, 48 ); + break; + } + + // don't process these in the update hud touch loop, because they will be + // handled with normal button calls + huds.menu.buttonFlags |= BF_HUDBUTTON; + huds.map.buttonFlags |= BF_HUDBUTTON; + + // don't make the big button click sound for the fire button + huds.fire.buttonFlags |= BF_SMALL_CLICK; + +} + +void SnapSticks( ibutton_t *test, const ibutton_t *to ) { + if ( abs( test->x - to->x ) < test->drawWidth && abs( test->y - to->y ) < test->drawHeight ) { + test->x = to->x; + test->y = to->y; + } +} + +/* + ================== + HudEditFrame + + ================== + */ +void HudEditFrame() { + color3_t gray = { 32, 32, 32 }; + + if ( numTouches == 0 && numPrevTouches == 1 && dragHud ) { + Sound_StartLocalSound( "iphone/baction_01.wav" ); + dragHud = NULL; + } + + if ( numTouches == 1 && numPrevTouches == 0 ) { + // identify the hud being touched for drag + int x = touches[0][0]; + int y = touches[0][1]; + dragHud = NULL; + for ( ibutton_t *hud = (ibutton_t *)&huds ; hud != (ibutton_t *)(&huds+1) ; hud++ ) { + if ( hud->buttonFlags & BF_IGNORE ) { + continue; + } + if ( x >= hud->x && x - hud->x < hud->drawWidth && y >= hud->y && y - hud->y < hud->drawHeight ) { + dragHud = hud; + dragX = dragHud->x - x; + dragY = dragHud->y - y; + Sound_StartLocalSound( "iphone/bdown_01.wav" ); + break; + } + } + } + + if ( numTouches == 1 && numPrevTouches == 1 && dragHud ) { + // adjust the position of the dragHud + dragHud->x = touches[0][0] + dragX; + dragHud->y = touches[0][1] + dragY; + if ( dragHud->x < 0 ) { + dragHud->x = 0; + } + if ( dragHud->x > displaywidth - dragHud->drawWidth ) { + dragHud->x = displaywidth - dragHud->drawWidth; + } + if ( dragHud->y < 0 ) { + dragHud->y = 0; + } + if ( dragHud->y > displayheight - dragHud->drawHeight ) { + dragHud->y = displayheight - dragHud->drawHeight; + } + + // magnet pull a matchable axis + if ( controlScheme->value == 0 ) { + if ( dragHud == &huds.forwardStick ) { + SnapSticks( &huds.turnStick, dragHud ); + } + } else { + if ( dragHud == &huds.forwardStick ) { + SnapSticks( &huds.sideStick, dragHud ); + } + } + } + + // solid background color and some UI elements for context + R_Draw_Fill( 0, 0, 480, 320, gray ); + glColor4f( 1, 1, 1, 1 ); + iphoneCenterText( 240, 20, 0.75, "Drag the controls" ); + + // draw the status bar + extern patchnum_t stbarbg; + if ( statusBar->value ) { + // force doom to rebind, since we have changed the active GL_TEXTURE_2D + last_gltexture = NULL; + gld_DrawNumPatch(0, ST_Y, stbarbg.lumpnum, CR_DEFAULT, VPT_STRETCH); + } + + // draw the active items at their current locations + for ( ibutton_t *hud = (ibutton_t *)&huds ; hud != (ibutton_t *)(&huds+1) ; hud++ ) { + if ( !hud->texture ) { + continue; + } + if ( hud->buttonFlags & BF_IGNORE ) { + continue; + } + PK_StretchTexture( hud->texture, hud->x, hud->y, hud->drawWidth, hud->drawHeight ); + } + + // draw the done button + static ibutton_t btnDone; + if ( !btnDone.texture ) { + // initial setup + SetButtonPicsAndSizes( &btnDone, "iphone/back_button.tga", "Done", 240 - 32, 160-32, 64, 64 ); + } + if ( HandleButton( &btnDone ) ) { + menuState = IPM_MAIN; + iphonePopGL(); + } + +} + diff --git a/common/ios/doomengine/ipak.c b/common/ios/doomengine/ipak.c new file mode 100755 index 0000000..d44d335 --- /dev/null +++ b/common/ios/doomengine/ipak.c @@ -0,0 +1,408 @@ +/* + * ipak.c + * doom + * + * Created by John Carmack on 4/9/09. + * Copyright 2009 Id Software. All rights reserved. + * + */ +/* + + Copyright (C) 2009 Id Software, 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 + 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 "doomiphone.h" + +pkHeader_t *pkHeader; +off_t pkSize; + +// images and wavs have writable state, so they need separate +// structs that also point to the source in the pak file +pkTexture_t *pkTextures; +pkWav_t *pkWavs; + +void PK_LoadTexture( pkTexture_t *image ); + +/* + ================== + PK_Init + + ================== + */ +void PK_Init( const char *pakFileName ) { + printf( "PK_Init( %s )\n", pakFileName ); + + int fd = open( pakFileName, O_RDONLY ); + if ( fd == -1 ) { + printf( "Couldn't open file\n" ); + assert( 0 ); + } + + struct stat s; + fstat( fd, &s ); + + pkSize = s.st_size; + pkHeader = mmap( NULL, (size_t)pkSize, PROT_READ, MAP_FILE|MAP_PRIVATE, fd, 0 ); + + // mmap keeps the file internally, we can close our descriptor + close( fd ); + + if ( (int)pkHeader == -1 ) { + printf( "mmap failed: %s\n", strerror( errno ) ); + assert( 0 ); + } + + if ( pkHeader->version != PKFILE_VERSION ) { + printf( "bad pak file version: 0x%x != 0x%x\n", pkHeader->version, PKFILE_VERSION ); + assert( 0 ); + } + + // build the local image table + pkTextures = malloc( sizeof( pkTextures[0] ) * pkHeader->textures.count ); + memset( pkTextures, 0, sizeof( pkTextures[0] ) * pkHeader->textures.count ); + for ( int i = 0 ; i < pkHeader->textures.count ; i++ ) { + pkTextures[i].textureData = (pkTextureData_t *)( (byte *)pkHeader + pkHeader->textures.tableOfs + i * pkHeader->textures.structSize ); + } + + // build the local wav table + int startLoadingWavs = SysIphoneMicroseconds(); + pkWavs = malloc( sizeof( pkWavs[0] ) * pkHeader->wavs.count ); + memset( pkWavs, 0, sizeof( pkWavs[0] ) * pkHeader->wavs.count ); + for ( int i = 0 ; i < pkHeader->wavs.count ; i++ ) { + pkWav_t *sfx = &pkWavs[i]; + sfx->wavData = (pkWavData_t *)( (byte *)pkHeader + pkHeader->wavs.tableOfs + i * pkHeader->wavs.structSize ); + // there is no harm in setting the OpenAl static buffer up for everything now + alGenBuffers( 1, &sfx->alBufferNum ); + + int alFormat; + if ( sfx->wavData->wavChannels == 1 ) { + if ( sfx->wavData->wavChannelBytes == 1 ) { + alFormat = AL_FORMAT_MONO8; + } else { + alFormat = AL_FORMAT_MONO16; + } + } else { + if ( sfx->wavData->wavChannelBytes == 1 ) { + alFormat = AL_FORMAT_STEREO8; + } else { + alFormat = AL_FORMAT_STEREO16; + } + } + alBufferData( sfx->alBufferNum, alFormat, (byte *)pkHeader + sfx->wavData->wavDataOfs + , sfx->wavData->wavChannels*sfx->wavData->wavChannelBytes*sfx->wavData->wavNumSamples + , sfx->wavData->wavRate ); + } + int endLoadingWavs = SysIphoneMicroseconds(); + printf( "%i usec to load wavs\n", endLoadingWavs - startLoadingWavs ); + + printf( "Mapped %lld bytes of %s at 0x%p\n", pkSize, pakFileName, (void*)pkHeader ); + printf( "%4i textures\n", pkHeader->textures.count ); + printf( "%4i wavs\n", pkHeader->wavs.count ); + printf( "%4i raws\n", pkHeader->raws.count ); +#if 0 + // testing + for ( int j = 0 ; j < 4 ; j++ ) { + int startTime = Sys_Microseconds(); + int sum = 0; + for ( off_t i = 0 ; i < pkSize ; i+=16 ) { + sum += ((byte *)pkHeader)[i]; + } + int endTime = Sys_Microseconds(); + printf( "%5.1f mb/s page-in speed (%i)\n", (float)pkSize / (endTime - startTime ), endTime - startTime ); + } + + for ( int i = 0 ; i < pkHeader->numTextures ; i++ ) { + printf( "-------------------------\n" ); + for ( int j = 0 ; j < 8 ; j++ ) { + pkTexture_t *tex = &pkTextures[i]; + int start = Sys_Microseconds(); + PK_LoadTexture( tex ); + int middle = Sys_Microseconds(); + PK_StretchTexture( tex, 0, 0, 0, 0 ); + int middle2 = Sys_Microseconds(); + PK_StretchTexture( tex, 0, 0, 0, 0 ); + int end = Sys_Microseconds(); + printf( "%i usec load, %i usec first draw, %i usec second draw\n", + middle - start, middle2 - middle, end - middle2 ); + + glDeleteTextures( 1, &tex->glTexNum ); + tex->glTexNum = 0; + } + } +#endif +} + + +/* + ================== + PK_LoadTexture + + ================== + */ +void PK_LoadTexture( pkTexture_t *tex ) { + int startTime = SysIphoneMicroseconds(); + + const pkTextureData_t *imd = tex->textureData; + + glGenTextures( 1, &tex->glTexNum ); + glBindTexture( GL_TEXTURE_2D, tex->glTexNum ); + + // load the image directly from the mapped file + typedef struct { + int internalFormat; + int externalFormat; + int type; + int bpp; + } formatInfo_t; + + static formatInfo_t formatInfo[9] = { + { GL_RGB , GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 16 }, + { GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, 16 }, + { GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, 16 }, + { GL_RGBA, GL_BGRA, GL_UNSIGNED_BYTE, 32 }, + { GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, 16 }, + { GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG, 0, 0, 4 }, + { GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG, 0, 0, 4 }, + { GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG, 0, 0, 2 }, + { GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG, 0, 0, 2 }, + }; + + assert( imd->format < 9 ); + formatInfo_t *fi = &formatInfo[imd->format]; + + unsigned char *s = (byte *)pkHeader + imd->picDataOfs; + int w = imd->uploadWidth; + int h = imd->uploadHeight; + // upload each mip level + int l = 0; + int totalSize = 0; + while( 1 ) { + int size = (w*h*fi->bpp)/8; + if ( fi->type == 0 ) { + if ( size < 32 ) { + // minimum PVRTC size + size = 32; + } + glCompressedTexImage2D( GL_TEXTURE_2D, l, fi->internalFormat, w, h, 0, + size, s ); + } else { + glTexImage2D( GL_TEXTURE_2D, l, fi->internalFormat, w, h, 0, + fi->externalFormat, fi->type, s ); + } + GLCheckError( "texture upload" ); + + totalSize += size; + if ( ++l == imd->numLevels ) { + break; + } + if ( w == 1 && h == 1 ) { + break; + } + s += size; + w >>= 1; + if ( w == 0 ) { + w = 1; + } + h >>= 1; + if ( h == 0 ) { + h = 1; + } + } + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, imd->minFilter ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, imd->magFilter ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, imd->wrapS ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, imd->wrapT ); + glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 2.0f ); + + int endTime = SysIphoneMicroseconds(); + + printf( "%5.1f mb/s TexImage for %s\n", (float)totalSize / + ( endTime - startTime ), imd->name.name ); +} + +/* + ================== + PK_FindTexture + + Fully creates the gl texture before returning. + ================== + */ +pkTexture_t *PK_FindTexture( const char *imageName ) { + int texIndex; + pkTexture_t *texData = (pkTexture_t *)PK_FindType( imageName, &pkHeader->textures, &texIndex ); + if ( !texData ) { + return NULL; + } + pkTexture_t *tex = pkTextures + texIndex; + if ( tex->glTexNum == 0 ) { + PK_LoadTexture( tex ); + } + return tex; +} + +/* + ================== + PK_FindWav + + ================== + */ +pkWav_t *PK_FindWav( const char *soundName ) { + int wavIndex; + pkWavData_t *wavData = (pkWavData_t *)PK_FindType( soundName, &pkHeader->wavs, &wavIndex ); + if ( !wavData ) { + return NULL; + } + pkWav_t *wav = pkWavs + wavIndex; + + // create the OpenAL buffer + + return wav; +} + +/* + ================== + PK_FindRaw + + ================== + */ +const byte *PK_FindRaw( const char *rawName, int *len ) { + pkRawData_t *raw = (pkRawData_t *)PK_FindType( rawName, &pkHeader->raws, NULL ); + if ( !raw ) { + if ( len ) { + *len = -1; + } + return NULL; + } + + if ( len ) { + *len = raw->rawDataLen; + } + return (byte *)pkHeader + raw->rawDataOfs; +} + +/* + ================== + PK_HashName + + ================== + */ +int PK_HashName( const char *name, char canonical[MAX_PK_NAME] ) { + int o = 0; + int hash = 0; + + do { + int c = name[o]; + if ( c == 0 ) { + break; + } + // backslashes to forward slashes + if ( c == '\\' ) { + c = '/'; + } + // to lowercase + c = tolower( c ); + canonical[o++] = c; + hash = (hash << 5) - hash + c; + } while ( o < MAX_PK_NAME-1 ); + canonical[o] = 0; + + return hash; +} + +/* + ================== + PK_FindType + + ================== + */ +const pkName_t *PK_FindType( const char *rawName, const pkType_t *type, int *indexOutput ) { + char canonicalName[MAX_PK_NAME]; + + int hash = PK_HashName( rawName, canonicalName ); + + int hashChain = hash & (PK_HASH_CHAINS-1); + + int typeIndex = type->hashChains[hashChain]; + while ( typeIndex != -1 ) { + assert( typeIndex >= 0 && typeIndex < type->count ); + const pkName_t *name = (pkName_t *)((byte *)pkHeader + type->tableOfs + typeIndex * type->structSize ); + if ( name->nameHash == hash && !strcmp( canonicalName, name->name ) ) { + // this is it + if ( indexOutput ) { + *indexOutput = typeIndex; + } + return name; + } + typeIndex = name->nextOnHashChain; + } + + // not found + if ( indexOutput ) { + *indexOutput = -1; + } + return NULL; +} + + +/* + ================== + PK_BindTexture + + ================== + */ +void PK_BindTexture( pkTexture_t *tex ) { + assert( tex->glTexNum ); + glBindTexture( GL_TEXTURE_2D, tex->glTexNum ); +} + +/* + ================== + PK_DrawTexture + + ================== + */ +void PK_DrawTexture( pkTexture_t *tex, int x, int y ) { + PK_BindTexture( tex ); + + int w = tex->textureData->srcWidth; + int h = tex->textureData->srcHeight; + + glBegin( GL_QUADS ); + + glTexCoord2f( 0.0f, 0.0f ); glVertex2i( x, y ); + glTexCoord2f( tex->textureData->maxS, 0.0f ); glVertex2i( x+w, y ); + glTexCoord2f( tex->textureData->maxS, tex->textureData->maxT ); glVertex2i( x+w, y+h ); + glTexCoord2f( 0.0f, tex->textureData->maxT ); glVertex2i( x, y+h ); + + glEnd(); +} + +void PK_StretchTexture( pkTexture_t *tex, float x, float y, float w, float h ) { + PK_BindTexture( tex ); + + glBegin( GL_QUADS ); + + glTexCoord2f( 0.0f, 0.0f ); glVertex2i( x, y ); + glTexCoord2f( tex->textureData->maxS, 0.0f ); glVertex2i( x+w, y ); + glTexCoord2f( tex->textureData->maxS, tex->textureData->maxT ); glVertex2i( x+w, y+h ); + glTexCoord2f( 0.0f, tex->textureData->maxT ); glVertex2i( x, y+h ); + + glEnd(); +} + diff --git a/common/ios/doomengine/ipak.h b/common/ios/doomengine/ipak.h new file mode 100755 index 0000000..3e8a536 --- /dev/null +++ b/common/ios/doomengine/ipak.h @@ -0,0 +1,183 @@ +/* + * ipak.h + * General purpose data file management intended to be used + * as a read-only memory mapped file to play nice with iPhone OS's + * non-swapping and variable memory management. + * + * Created by John Carmack on 4/9/09. + * Copyright 2009 id Software. All rights reserved. + * + */ +/* + + Copyright (C) 2009 Id Software, 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 + 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. + + */ + +#ifndef IPAK_H +#define IPAK_H + +//============================================================ +// +// In-file structures +// +// These stuctures are in the mapped data file, and shared +// between the app and utility. +// +// Type headers are stored separately from the bulk data to minimize the +// number of active pages. +// +// The full hash of the name is stored in nameHash, and nameHash&(PK_HASH_BUCKETS-1) is +// used to chain structures of a particular type together. +// +//============================================================ + +#define MAX_PK_NAME 64 +typedef struct { + int nameHash; // PK_HashName( name ) + int nextOnHashChain; // -1 = end of chain + char name[MAX_PK_NAME]; // in canonical form: backslashes to slashes and lowercase +} pkName_t; + +#define PK_HASH_CHAINS 256 +typedef struct { + int tableOfs; // // &firstStruct = (byte *)dfHeader + tableOfs + int count; + int structSize; // sizeof( pkWavData_t ), etc + int hashChains[PK_HASH_CHAINS]; // -1 = end of chain +} pkType_t; + +// dfWavData holds everything necessary to fully create an OpenAL sample buffer +typedef struct { + pkName_t name; + int wavDataOfs; + int wavChannels; // 1 or 2 + int wavChannelBytes; // 1 or 2 + int wavRate; // 22050, etc + int wavNumSamples; // each sample holds all the channels + // we may want looping information here later +} pkWavData_t; + +// iPhone does not natively support palettized textures, but we +// might conceivably want to support luminance and intensity textures +// in the future. +typedef enum { + TF_565, + TF_5551, + TF_4444, + TF_8888, + TF_LA, + TF_PVR4, + TF_PVR4A, + TF_PVR2, + TF_PVR2A, +} textureFormat_t; + +// dfImageData_t holds everything necessary to fully create an OpenGL texture object +typedef struct { + pkName_t name; + int picDataOfs; // the raw bits to pass to gl, mipmaps appended + // for PVR formats, the minimum size of each level is 32 bytes + + int format; + int uploadWidth; + int uploadHeight; + int numLevels; // 1 for non mipmapped, otherwise log2( largest dimension ) + + // glTexParameters + int wrapS; + int wrapT; + int minFilter; + int magFilter; + int aniso; + + // The upload sizes can be larger than the source sizes for + // non power of two sources, or for non square sources in the + // case of PVR compression. + int srcWidth; + int srcHeight; + + float maxS; // srcWidth / uploadWidth + float maxT; + + // Track the outlines of up to two boxes of non-transparent pixels + // to allow optimized drawing of sprites with large empty areas. + // The reason for two boxes is that the common lights have something + // at the top and something at the bottom, with nothing inbetween. + // These are inclusive bounds of the rows / columns in + // uploadWidth / uploadHeight with non-0 alpha + int numBounds; + int bounds[2][2][2]; +} pkTextureData_t; + +typedef struct { + pkName_t name; + int rawDataOfs; // (byte *)pkHeader + dataOfs + int rawDataLen; // there will always be a 0 byte appended to terminate strings + // that is not counted in this length +} pkRawData_t; + +#define PKFILE_VERSION 0x12340002 +typedef struct { + int version; + + pkType_t textures; + pkType_t wavs; + pkType_t raws; +} pkHeader_t; + + +//============================================================ +// +// In-memory, writable structures +// +//============================================================ + +typedef struct { + unsigned glTexNum; + const pkTextureData_t *textureData; + // we will need to add LRU links if texture caching is needed +} pkTexture_t; + +typedef struct { + unsigned alBufferNum; // created with the staticBuffer extension directly in the mapped memory + const pkWavData_t *wavData; +} pkWav_t; + +void PK_Init( const char *pakFileName ); +const pkName_t *PK_FindType( const char *rawName, const pkType_t *type, int *index ); +const byte * PK_FindRaw( const char *rawName, int *len ); // len can be NULL if you don't need it +pkTexture_t * PK_FindTexture( const char *imageName ); +pkWav_t * PK_FindWav( const char *soundName ); + +// The name will be converted to canonical name (backslashes converted to slashes and lowercase) +// before generating a hash. +int PK_HashName( const char *name, char canonical[MAX_PK_NAME] ); + +void PK_BindTexture( pkTexture_t *tex ); +void PK_DrawTexture( pkTexture_t *tex, int x, int y ); +void PK_StretchTexture( pkTexture_t *tex, float x, float y, float w, float h ); + +extern pkHeader_t * pkHeader; +extern off_t pkSize; + +// images and wavs have writable state, so they need separate +// structs that also point to the source in the pak file +extern pkTexture_t *pkTextures; +extern pkWav_t * pkWavs; + +#endif diff --git a/common/ios/doomengine/iphone_async.cpp b/common/ios/doomengine/iphone_async.cpp new file mode 100755 index 0000000..ea11de9 --- /dev/null +++ b/common/ios/doomengine/iphone_async.cpp @@ -0,0 +1,952 @@ +/* + * iphone_async.c + * doom + * + * Created by John Carmack on 7/2/09. + * Copyright 2009 id Software. All rights reserved. + * + */ +/* + + Copyright (C) 2009 Id Software, 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 + 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 "doomiphone.h" +#include "DoomGameCenterMatch.h" + +#include "ios/GameCenter.h" + +typedef struct { + int msecFromLast; + int msecToExecute; + int sent; + int received; + int latency; +} asyncStats_t; + +#define MAX_ASYNC_LOGS 256 +static asyncStats_t asyncStats[MAX_ASYNC_LOGS]; +int asyncTicNum; + +// we save this for the packet acknowledge, and also for debugging +static packetServer_t lastServerPacket; + +/* + ================== + ShowNet + + Graph packet receives and transmits + ================== + */ +void ShowNet() { + if ( !showNet->value ) { + return; + } + color4_t red = { 255, 0, 0, 255 }; + color4_t green = { 0, 255, 0, 255 }; + color4_t blue = { 0, 0, 255, 255 }; + + int now = asyncTicNum; // latch it in case it changes + + for ( int i = 1 ; i < 30 ; i++ ) { + asyncStats_t *lt = &asyncStats[(now - i ) & (MAX_ASYNC_LOGS-1)]; + R_Draw_Fill( 0, i * 4, lt->sent * 10, 2, red ); + R_Draw_Fill( 100, i * 4, lt->received * 10, 2, green ); + R_Draw_Fill( 200, i * 4, lt->latency * 10, 2, blue ); + } +} + +void ShowMiniNet() { + if ( !miniNet->value ) { + return; + } + + color4_t red = { 255, 0, 0, 255 }; + color4_t green = { 0, 255, 0, 255 }; + color4_t blue = { 0, 0, 255, 255 }; + + int now = asyncTicNum; // latch it in case it changes + now--; + + int x = huds.menu.x; + int y = huds.menu.y; + + for ( int i = 0 ; i < 10 ; i++ ) { + asyncStats_t *lt = &asyncStats[(now - i ) & (MAX_ASYNC_LOGS-1)]; + R_Draw_Fill( x, y+i * 4, lt->sent * 4, 2, red ); + R_Draw_Fill( x+20, y+i * 4, lt->received * 4, 2, green ); + R_Draw_Fill( x+40, y+i * 4, lt->latency * 4, 2, blue ); + } +} + +/* + ================== + UpdatePeerTiming + + Calculates one way latency based on local and remote times + ================== + */ +void UpdatePeerTiming( netPeer_t *peer, int remoteMilliseconds ) { + peer->lastPacketAsyncTic = asyncTicNum; + peer->lastPacketTime = SysIphoneMilliseconds(); + peer->lastTimeDelta = abs( remoteMilliseconds - peer->lastPacketTime ); + if ( peer->lowestTimeDelta == 0 || peer->lastTimeDelta < peer->lowestTimeDelta ) { + peer->lowestTimeDelta = peer->lastTimeDelta; + } + peer->oneWayLatency = peer->lastTimeDelta - peer->lowestTimeDelta; + if ( peer->oneWayLatency < 0 ) { + // this can happen if we context switched at a bad time + peer->lowestTimeDelta = peer->lastTimeDelta; + peer->oneWayLatency = 0; + } +// printf( "OWL:%i timeDelta:%i lowest:%i\n", peer->oneWayLatency, +// peer->lastTimeDelta, peer->lowestTimeDelta ); +} + +/* + ================== + iphoneProcessPacket + + A packet has been received over WiFi or bluetooth + ================== + */ +void iphoneProcessPacket( const struct sockaddr *from, const void *data, int len ) { + if ( len < 4 ) { + printf( "discarding packet because len = %i.\n", len ); + return; + } + int packetID = *(int *)data; + + if ( !netgame ) { + // setup and join are only processed while in the menu system + + if ( packetID == PACKET_VERSION_SETUP ) { + if ( localGameID == setupPacket.gameID ) { + // if we are sending packets, always ignore other setup packets + printf( "discarding setup packet because we are the server\n" ); + return; + } + setupPacketFrameNum = iphoneFrameNum; + + // save this packet +// printf( "valid setup packet\n" ); + setupPacket = *(packetSetup_t *)data; + return; + } + + if ( packetID == PACKET_VERSION_JOIN ) { + // we should only process join packets if we are in the multiplayer + // menu and running the current game + if ( menuState != IPM_MULTIPLAYER ) { + printf( "discarding join packet because not in IPM_MULTIPLAYER\n" ); + return; + } + if ( setupPacket.gameID != localGameID ) { + printf( "discarding join packet because we aren't the server\n" ); + return; + } + + packetJoin_t *pj = (packetJoin_t *)data; + if ( pj->playerID == 0 ) { + // should never happen + printf( "discarding join packet because playerID is 0\n" ); + return; + } + // add this player + int i; + for ( i = 0 ; i < MAXPLAYERS ; i++ ) { + if ( setupPacket.playerID[i] == pj->playerID ) { + netPlayers[i].peer.lastPacketTime = SysIphoneMilliseconds(); + break; + } + } + if ( i == MAXPLAYERS ) { + // not in yet, add if possible + for ( i = 0 ; i < MAXPLAYERS ; i++ ) { + if ( setupPacket.playerID[i] == 0 ) { + setupPacket.playerID[i] = pj->playerID; + netPlayers[i].peer.address = *from; + netPlayers[i].peer.lastPacketTime = SysIphoneMilliseconds(); + break; + } + } + // if all players are active, the new join gets ignored + } +// printf( "valid join packet\n" ); + return; + } + + // no other packets are processed unless we are in the game + printf( "discarding packet with id 0x%x when not in netgame\n", packetID ); + return; + } + + // the following are only for running games + + if ( consoleplayer == 0 ) { + // we are the server, and should only receive packetClient_t + if ( packetID != PACKET_VERSION_CLIENT ) { + static boolean typeErrorPrinted; + if ( !typeErrorPrinted ) { + typeErrorPrinted = true; + printf( "Packet received with type 0x%x instead of 0x%x\n", packetID, PACKET_VERSION_CLIENT ); + } + return; + } + packetClient_t *pc = (packetClient_t *)data; + if ( len != sizeof( *pc ) ) { + // this should always be an exact length match + return; + } + + if ( pc->gameID != gameID ) { + static boolean gameErrorPrinted; + if ( !gameErrorPrinted ) { + gameErrorPrinted = true; + printf( "Packet received with gameID 0x%x instead of 0x%x\n", pc->gameID, gameID ); + } + return; + } + assert( pc->consoleplayer > 0 && pc->consoleplayer < MAXPLAYERS ); + + netPlayer_t *np = &netPlayers[pc->consoleplayer]; + if ( np->pc.packetSequence >= pc->packetSequence ) { + printf( "Out of order or duplicated packet from player %i\n", pc->consoleplayer ); + return; + } + np->peer.currentPingTics = packetSequence - pc->packetAcknowledge; + if ( np->pc.packetSequence != pc->packetSequence - 1 ) { + printf( "Dropped %i packets from player %i\n", pc->packetSequence - 1 - np->pc.packetSequence, + pc->consoleplayer ); + } + + // good packet from client + np->pc = *pc; + UpdatePeerTiming( &np->peer, np->pc.milliseconds ); + } else { + // we are a client, and should only receive server packets + if ( packetID != PACKET_VERSION_SERVER ) { + static boolean typeErrorPrinted; + if ( !typeErrorPrinted ) { + typeErrorPrinted = true; + printf( "Packet received with type 0x%x instead of 0x%x\n", packetID, PACKET_VERSION_CLIENT ); + } + return; + } + packetServer_t *ps = (packetServer_t *)data; + if ( len > sizeof( *ps ) ) { + // packets will usually have less ticcmd_t, but never more + return; + } + + if ( ps->gameID != gameID ) { + static boolean gameErrorPrinted; + if ( !gameErrorPrinted ) { + gameErrorPrinted = true; + printf( "Packet received with gameID 0x%x instead of 0x%x\n", ps->gameID, gameID ); + } + return; + } + + if ( ps->packetSequence <= lastServerPacket.packetSequence ) { + printf( "Out of order or duplicated packet from server: %i <= %i\n", + ps->packetSequence , lastServerPacket.packetSequence ); + return; + } + int drop = ps->packetSequence - (lastServerPacket.packetSequence + 1); + if ( drop > 0 ) { + printf( "Dropped %i packets from server\n", drop ); + } + + // good packet from server + memcpy( &lastServerPacket, ps, len ); + UpdatePeerTiming( &netServer, ps->milliseconds ); + netServer.currentPingTics = packetSequence - ps->packetAcknowledge; + + // It is possible to have a client run a tic that hasn't been run yet on the game + // server, since the server can be generating cmds and sending packets while + // its game frame is hitched for an image load, so this is not an error condition. + // assert( ps->gametic >= gametic ); + + // this should never happen + assert( ps->maketic >= maketic ); + + // if a ticcmd_t that we need has permanently rolled off the end, we are hosed. + // This shouldn't happen, since we don't create commands if all the clients + // haven't processed most of the ones already sent. + if ( ps->maketic - gametic >= BACKUPTICS ) { + printf( "BACKUPTICS exceeded: ps->maketic %i, gametic %i\n", + ps->maketic, gametic ); + netGameFailure = NF_INTERRUPTED; + } + + // move over the new commands + // it is possible that some early frames of these are redundant, due + // to packets crossing in flight. + ticcmd_t *cmd_p = ps->netcmds; + for ( int i = ps->starttic ; i < ps->maketic ; i++ ) { + for ( int j = 0 ; j < MAXPLAYERS ; j++ ) { + if ( playeringame[j] ) { + netcmds[j][i&BACKUPTICMASK] = *cmd_p++; + } + } + } + + // copy this after the cmds have been updated + maketic = ps->maketic; + + // See if anyone has disconnected. + for ( int i = 0; i < MAXPLAYERS; ++i ) { + playeringame[i] = ps->playersInGame[i]; + } + + // check consistancy for all in-game players on the most + // recent gametic that the server knew this client had run + int checkTic = ps->consistancyTic; + assert( checkTic > gametic - BACKUPTICS ); // if older than this, we have lost the data + checkTic &= BACKUPTICMASK; + for ( int i = 0 ; i < MAXPLAYERS ; i++ ) { + if ( playeringame[i] ) { + if ( ps->consistancy[i] != consistancy[i][checkTic] ) { + printf( "ConsistancyFailure for player %i on consistancyTic %i\n", + i, ps->consistancyTic ); + netGameFailure = NF_CONSISTANCY; + } + } + } + } +} + +/* + ================== + SendSetupPacketIfNecessary + + the server sends out a setup packet to each joined client so they + can see the game options needed to start the game. + ================== + */ +void SendSetupPacketIfNecessary() { + if ( setupPacket.gameID != localGameID ) { + // we aren't the server + return; + } + + if ( gametic >= 2 ) { + // everyone has already started, so they don't need more setup packets + return; + } + + + setupPacket.sendCount++; + + // player 0 is always the server, no need to send to ourselves + for ( int i = 1 ; i < MAXPLAYERS ; i++ ) { + if ( setupPacket.playerID[i] == 0 ) { + continue; + } + int r = sendto( gameSocket, &setupPacket, sizeof( setupPacket ), 0, + &netPlayers[i].peer.address, sizeof( netPlayers[i].peer.address ) ); + if ( r == -1 ) { + Com_Printf( "UDP sendTo failed: %s\n", strerror( errno ) ); + close( gameSocket ); + gameSocket = -1; + } + } +} + + +/* + ================== + DeadBandAdjust + + Compresses the 0.0 - 1.0 range into deadband - 1.0 + ================== + */ +float DeadBandAdjust( float f, float deadBand ) { + if ( f < 0 ) { + return -DeadBandAdjust( -f, deadBand ); + } + if ( f > 1.0 ) { + return 1.0; + } + if ( f < deadBand ) { + return 0; + } + return (f-deadBand) / (1.0 - deadBand); +} + +/* + ================== + AxisHit + + Returns a -1 to 1 range + + If activeFraction is less than 1.0, the range will clamp + to the limits before the edge of the box is hit. + ================== + */ +float AxisHit( ibutton_t *hud ) { + // will be set true if -1 or 1 + hud->drawAsLimit = false; + + if ( hud->buttonFlags & BF_IGNORE ) { + return 0; + } + + touch_t *t = hud->touch; + if ( !t ) { + return 0; + } + + int centerX, centerY; + + if ( centerSticks->value ) { + // center on each touch + centerX = hud->downX; + centerY = hud->downY; + } else { + centerX = hud->x + hud->drawWidth / 2; + centerY = hud->y + hud->drawHeight / 2; + } + + float w = hud->drawWidth * 0.5 * hud->scale; + float h = hud->drawHeight * 0.5 * hud->scale; + int x = t->x - centerX; + int y = t->y - centerY; + float f; + int isXaxis = ( hud != &huds.forwardStick ); + if ( isXaxis ) { + f = (float)x / w; + } else { + f = (float)y / h; + } + float deadBand = stickDeadBand->value; + if ( hud == &huds.turnStick ) { + deadBand = 0; + } + if ( f > deadBand ) { + f -= deadBand; + } else if ( f < -deadBand ) { + f += deadBand; + } else { + // inside the deadband + return 0; + } + + // adjust so you can hit the limit even if the control is drawn at the very edge + // of the screen + f /= (0.95-deadBand); + if ( f > 1.0f ) { + f = 1.0f; + hud->drawAsLimit = true; + } else if ( f < -1.0f ) { + f = -1.0f; + hud->drawAsLimit = true; + } + + if ( hud == &huds.turnStick && rampTurn->value ) { + // do "gamma corrected" movement, so changes are always proportional + if ( f > 0 ) { + f = 0.01 * pow( 1.047, f * 100 ); + } else { + f = -0.01 * pow( 1.047, f * -100 ); + } + } + return f; +} + + +static const float NOT_TOUCHED_STATE = 99999.0f; + +float RotorControl( ibutton_t *hud ) { + if ( hud->buttonFlags & BF_IGNORE ) { + return 0; + } + touch_t *t = hud->touch; + if ( !t ) { + // no touches in the control + hud->touchState = NOT_TOUCHED_STATE; + return 0; + } + float delta[2]; + + int centerX = hud->x + hud->drawWidth / 2; + int centerY = hud->y + hud->drawHeight / 2; + + delta[0] = t->x - centerX; + delta[1] = t->y - centerY; + + float rotorAngle = atan2( delta[1], delta[0] ); + if ( hud->touchState == NOT_TOUCHED_STATE ) { + // just touched, haven't moved yet + hud->touchState = rotorAngle; + return 0; + } + float deltaAngle = rotorAngle - hud->touchState; + // handle the wrap around cases + if ( deltaAngle >= M_PI ) { + deltaAngle = deltaAngle - 2*M_PI; + } else if ( deltaAngle <= -M_PI ) { + deltaAngle = 2*M_PI + deltaAngle; + } + hud->touchState = rotorAngle; + hud->drawState += deltaAngle; + return deltaAngle / (2*M_PI); +} + +#define TURBOTHRESHOLD 0x32 +static int ClampMove( int v ) { + if ( v > TURBOTHRESHOLD ) { + return TURBOTHRESHOLD; + } + if ( v < -TURBOTHRESHOLD ) { + return -TURBOTHRESHOLD; + } + return v; +} + + +/* + ================== + iphoneBuildTiccmd + + Use touch and tilt controls to set up a doom ticcmd_t + ================== + */ +static void iphoneBuildTiccmd(ticcmd_t* cmd) { + memset(cmd,0,sizeof*cmd); + // cmd->consistancy = consistancy[consoleplayer][maketic & BACKUPTICMASK]; + + if ( menuState != IPM_GAME ) { + // if in the menus, always generate an empty event + return; + } + + // the respawn button triggers a use + if ( respawnActive ) { + cmd->buttons |= BT_USE; + respawnActive = false; + } + + if ( gamestate != GS_LEVEL ) { + // at intermissions, all taps equal attack + // FIXME: better latched value + if ( numTouches == numPrevTouches + 1 ) { + cmd->buttons |= BT_ATTACK; + } + return; + } + + // don't allow movement control use during automap + if ( automapmode & am_active ) { + return; + } + + // don't built a tic when dead, other than the respawn use + if ( players[consoleplayer].playerstate == PST_DEAD ) { + return; + } + + //------------------------ + // No controls during weapon-select screen + //------------------------ + boolean weaponCycle = false; + if ( drawWeaponSelect ) { + // if the weaponSelect overlay is up, continue tracking held touches + // until the are released + for ( ibutton_t *hud = (ibutton_t *)&huds ; hud != (ibutton_t *)(&huds+1) ; hud++ ) { + if ( hud->touch || hud == &huds.weaponSelect ) { + UpdateHudTouch( hud ); + } + } + + // Re-tapping in the weapon select area will cycle to the next weapon. + // The action happens on initial touch. + touch_t *t = huds.weaponSelect.touch; + if ( t && t->down && t->stateCount == 1 ) { + drawWeaponSelect = false; + t->stateCount++; // ensure it won't bring it back up + weaponCycle = true; + } else { + return; + } + } + + //------------------------ + // gameplay controls + //------------------------ + + // update all the hud touch states + if ( menuState == IPM_GAME ) { + UpdateHudTouch( &huds.forwardStick ); + UpdateHudTouch( &huds.sideStick ); + UpdateHudTouch( &huds.turnStick ); + UpdateHudTouch( &huds.turnRotor ); + UpdateHudTouch( &huds.weaponSelect ); + } + // tap in the lower center for weapon switch + touch_t *t = huds.weaponSelect.touch; + if ( t && t->down && t->stateCount == 1 ) { + drawWeaponSelect = true; + } + + // hack to let a single touch control both hud elements on combo sticks + // This is dependent on the order in the structure, and probably not a good + // way to do things. + if ( huds.sideStick.x == huds.forwardStick.x && huds.sideStick.y == huds.forwardStick.y ) { + huds.sideStick.touch = huds.forwardStick.touch; + huds.sideStick.downX = huds.forwardStick.downX; + huds.sideStick.downY = huds.forwardStick.downY; + } + if ( huds.turnStick.x == huds.forwardStick.x && huds.turnStick.y == huds.forwardStick.y ) { + huds.turnStick.touch = huds.forwardStick.touch; + huds.turnStick.downX = huds.forwardStick.downX; + huds.turnStick.downY = huds.forwardStick.downY; + } + + // the fire button doesn't grab touches + { + int x = huds.fire.x - ( huds.fire.drawWidth >> 1 ); + int y = huds.fire.y - ( huds.fire.drawHeight >> 1 ); + int w = huds.fire.drawWidth << 1; + int h = huds.fire.drawHeight << 1; + if ( AnyTouchInBounds( x, y, w, h ) ) { + cmd->buttons |= BT_ATTACK; + huds.fire.buttonFlags |= BF_DRAW_ACTIVE; // draw with color + } else { + huds.fire.buttonFlags &= ~BF_DRAW_ACTIVE; + } + } + int forwardmove; + int sidemove; + + // the edge of the drawn control should give the maximum + // legal doom movement speed + huds.forwardStick.scale = stickMove->value / 128.0f; + huds.sideStick.scale = stickMove->value / 128.0f; + + forwardmove = -TURBOTHRESHOLD * AxisHit( &huds.forwardStick ); + sidemove = TURBOTHRESHOLD * AxisHit( &huds.sideStick ); + + huds.turnStick.scale = stickTurn->value / 128.0f; + cmd->angleturn = -1500.0f * AxisHit( &huds.turnStick ); + + // rotary wheel + cmd->angleturn -= rotorTurn->value * RotorControl( &huds.turnRotor ); + + // accelerometer tilting + sidemove += tiltMove->value * DeadBandAdjust( tilt, tiltDeadBand->value ); + cmd->angleturn -= tiltTurn->value * DeadBandAdjust( tilt, tiltDeadBand->value ); + + // clamp movements + cmd->forwardmove = ClampMove( forwardmove ); + cmd->sidemove = ClampMove( sidemove ); + + // tap in the upper center for use + if ( TouchPressed( 140, 0, 240, 200 ) ) { + cmd->buttons |= BT_USE; + } + + // auto-use if the game thread found a usable line in front of the player + if ( autoUse->value && autoUseActive ) { + if ( cmd->buttons & BT_USE ) { + // Allow a tap to briefly cancel the auto-use, which works around + // some issues with incorrectly started auto-uses preventing + // a real door from opening. + cmd->buttons &= ~BT_USE; + } else { + cmd->buttons |= BT_USE; + } + } + + if ( weaponSelected != -1 ) { + cmd->buttons |= BT_CHANGE; + cmd->buttons |= weaponSelected<buttons |= BT_CHANGE; + cmd->buttons |= newweapon<value == 0 ) { + // disabled completely, always send + return true; + } + + if ( peer == &netServer ) { + if ( throttle->value == 2 ) { + return false; // don't send client messages at all + } + } else { + if ( throttle->value == 3 ) { // don't send server messages at all + return false; + } + } + + // immediately fire back a packet if it looks like we just got one through + // clearly + if ( peer->lastPacketAsyncTic == asyncTicNum && peer->oneWayLatency < okOneWayLatency ) { + return true; + } + + if ( packetLatency <= okPacketLatency ) { + return true; + } + // limit from 1 to 4, in worst case only transmit a packet + // every 16 frames, or about half a second + packetLatency -= okPacketLatency; + if ( packetLatency > 4 ) { + packetLatency = 4; + } + + if ( asyncTicNum & ((1<msecFromLast = now - prev; + stats->msecToExecute = 0; + + prev = now; + + // don't generate any commands while loading levels + if ( iphoneFrameNum == levelLoadFrameNum ) { + return; + } + + int afterLock = SysIphoneMilliseconds(); + + // latch the current touches for processing + for ( int i = 0 ; i < MAX_TOUCHES ; i++ ) { + touch_t *t = &sysTouches[i]; + + gameTouches[i] = *t; + + // handle the special case of a touch that went down and up + // inside a single frame + if ( t->stateCount == -1 ) { + gameTouches[i].stateCount = 1; + t->stateCount = 0; + t->down = false; + } else { + t->stateCount++; + } + } + + //--------------------------------- + // Create local user command + // + // We always create one, but it might not wind up being used for a game + // tic if it doesn't make it to the server at the right time. + //--------------------------------- + ticcmd_t cmd; + iphoneBuildTiccmd( &cmd ); + + //--------------------------------- + // If we are a client, send our command to the server + //--------------------------------- + if ( consoleplayer != 0 ) { + if ( gameID != 0 && netgame && !netGameFailure ) { + stats->latency = packetSequence - lastServerPacket.packetAcknowledge; + if ( ShouldSendPacket( &netServer, packetSequence - lastServerPacket.packetAcknowledge ) ) { + packetClient_t cp; + memset( &cp, 0, sizeof( cp ) ); + cp.packetType = PACKET_VERSION_CLIENT; + cp.gameID = gameID; + cp.packetAcknowledge = lastServerPacket.packetSequence; + cp.milliseconds = SysIphoneMilliseconds(); + cp.packetSequence = packetSequence++; + cp.consoleplayer = consoleplayer; + cp.gametic = gametic; + cp.cmd = cmd; + + idGameCenter::SendPacketToPlayerUnreliable( serverGameCenterID, &cp, sizeof ( cp ) ); + } + } + } else { + + // take our command directly + netPlayers[0].pc.cmd = cmd; + netPlayers[0].pc.gametic = gametic; + netPlayers[0].peer.lastPacketTime = now; + + + //--------------------------------- + // Decide if we want to latch the current commands for execution by the game + // + //--------------------------------- + int ticIndex = maketic & BACKUPTICMASK; + + int worstTic = gametic; + for ( int i = 0 ; i < MAXPLAYERS ; i++ ) { + if ( playeringame[i] ) { + netcmds[i][ticIndex] = netPlayers[i].pc.cmd; + if ( netPlayers[i].pc.gametic < worstTic ) { + worstTic = netPlayers[i].pc.gametic; + } + } + } + + // only let the server get a few tics ahead of any client, so if + // anyone is having significant net delivery problems, everyone will + // stall instead of losing the player. If this is too small, then + // every little hitch that any player gets will cause everyone to hitch. + if ( maketic - worstTic < netBuffer->value ) { + maketic++; + } + + + //--------------------------------- + // Build server packets to send to clients + // + // Always send out the current command set over the network + // even if we didn't create a new command, in case we are just + // recovering from a lot of dropped packets. + //--------------------------------- + if ( netgame && !netGameFailure ) { + // since we are sampling a shared wireless network, any of the player's + // latencies should be a good enough metric + stats->latency = packetSequence - netPlayers[1].pc.packetAcknowledge; + + if ( ShouldSendPacket( &netPlayers[1].peer, stats->latency ) ) { + packetServer_t gp; + memset( &gp, 0, sizeof( gp ) ); + gp.packetType = PACKET_VERSION_SERVER; + gp.gameID = gameID; + gp.packetSequence = packetSequence++; + gp.maketic = maketic; + for ( int i = 0; i < MAXPLAYERS; ++i ) { + gp.playersInGame[i] = playeringame[i]; + } + memcpy( gp.netcmds, netcmds, sizeof( gp.netcmds ) ); + + //--------------------------------- + // Send network packets to the clients + //--------------------------------- + for ( int i = 1 ; i < MAXPLAYERS ; i++ ) { + if ( !playeringame[i] ) { + continue; + } + + netPlayer_t *np = &netPlayers[i]; + + // only send over the ticcmd that this client needs + gp.starttic = np->pc.gametic; + ticcmd_t *cmd_p = gp.netcmds; + for ( int j = gp.starttic ; j < gp.maketic ; j++ ) { + for ( int k = 0 ; k < MAXPLAYERS ; k++ ) { + if ( playeringame[k] ) { + *cmd_p++ = netcmds[k][j&BACKUPTICMASK]; + } + } + } + int packetSize = (byte *)cmd_p - (byte *)&gp; + (void)packetSize; + + // use the most recent tic that both the client and + // server have run + gp.consistancyTic = np->pc.gametic < gametic ? np->pc.gametic : gametic; + gp.consistancyTic--; + + for ( int j = 0 ; j < MAXPLAYERS ; j++ ) { + gp.consistancy[j] = consistancy[j][gp.consistancyTic&BACKUPTICMASK]; + } + + gp.packetAcknowledge = np->pc.packetSequence; + gp.milliseconds = SysIphoneMilliseconds(); + + // transmit the packet + const std::string theClient = playerIndexToIDMap[i]; + idGameCenter::SendPacketToPlayerUnreliable( theClient, &gp, packetSize ); + } + } + } + } + + stats->msecToExecute = SysIphoneMilliseconds() - now; + if ( stats->msecToExecute > 6 ) { + printf( "long asyncTic %i: %i msec (%i in lock), %i packets\n", asyncTicNum - 1, stats->msecToExecute, + afterLock - now, stats->received ); + } +} + + diff --git a/common/ios/doomengine/iphone_common.h b/common/ios/doomengine/iphone_common.h new file mode 100755 index 0000000..27c0e52 --- /dev/null +++ b/common/ios/doomengine/iphone_common.h @@ -0,0 +1,35 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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. + + */ + +#ifndef doomengine_iphone_common_h +#define doomengine_iphone_common_h + + +@class UIViewController; + +void CommonSystemSetup( UIViewController * gameController ); + + + +extern char iphoneDocDirectory[PATH_MAX]; +extern char iphoneAppDirectory[PATH_MAX]; +extern char iphoneTempDirectory[PATH_MAX]; + +#endif diff --git a/common/ios/doomengine/iphone_common.mm b/common/ios/doomengine/iphone_common.mm new file mode 100755 index 0000000..5f1ef23 --- /dev/null +++ b/common/ios/doomengine/iphone_common.mm @@ -0,0 +1,105 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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. + + */ + +#import + +#include "iphone_common.h" +#include "doomiphone.h" +#include "ios/GameCenter.h" +#include "ios/Localization.h" +#import "ios/LocalizationObjectiveC.h" +#include "iphone_delegate.h" +#include "DoomGameCenterMatch.h" +#import "ios/objectivec_utilities.h" + +@class UIViewController; + +/* +======================= +CommonSystemSetup + +Called in each game's didFinishLaunching method. +======================= +*/ +void CommonSystemSetup( UIViewController * gameViewController ) { + + // Authenticate the Game Center player. + idGameCenter::Initialize(); + idGameCenter::AuthenticateLocalPlayer( gameViewController, &gDoomGameCenterMatch ); + + // get the documents directory, where we will write configs and save games + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + NSString *documentsDirectory = [paths objectAtIndex:0]; + [documentsDirectory getCString: iphoneDocDirectory + maxLength: sizeof( iphoneDocDirectory ) - 1 + encoding: NSASCIIStringEncoding ]; + + // get the app directory, where our data files live + // this gives something like: + // /var/mobile/Applications/71355F9F-6400-4267-B07D-E7980764F5A8/Applications + // when what we want is: + // /var/mobile/Applications/71355F9F-6400-4267-B07D-E7980764F5A8/doom.app + // so we get that in main() from argv[0] +#if 0 + paths = NSSearchPathForDirectoriesInDomains(NSApplicationDirectory, NSUserDomainMask, YES); + NSString *appDirectory = [paths objectAtIndex:0]; + + static char iphoneAppDirectoryFromAPI[1024]; + [appDirectory getCString: iphoneAppDirectoryFromAPI + maxLength: sizeof( iphoneAppDirectoryFromAPI ) - 1 + encoding: NSASCIIStringEncoding ]; +#endif + + + // Get the temporary directory. + NSString * tempDirectory = NSTemporaryDirectory(); + [tempDirectory getCString:iphoneTempDirectory maxLength:PATH_MAX encoding:NSUTF8StringEncoding]; + + // Initialize the localization system. + idLocalization_Initialize(); +} + +/* + ======================= + MainMenu + + Hides the OpenGL View and reverts back to Interface builder. + ======================= + */ +void iphoneMainMenu() { + + [ gAppDelegate HideGLView]; + menuState = IPM_MAIN; +} + +/* + ======================= + iphonePopGL + + Hides the OpenGL View and reverts back to Interface builder. + ======================= + */ +void iphonePopGL() { + + [ gAppDelegate PopGLView]; + menuState = IPM_MAIN; +} + + diff --git a/common/ios/doomengine/iphone_delegate.h b/common/ios/doomengine/iphone_delegate.h new file mode 100755 index 0000000..85235a2 --- /dev/null +++ b/common/ios/doomengine/iphone_delegate.h @@ -0,0 +1,50 @@ +/* + + Copyright (C) 2009 Id Software, 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 + 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. + + */ + +#import +#import +#import "iphone_glViewController.h" + +@class EAGLView; + +@interface iphoneApp : NSObject { + + UIWindow * window; // Main Application Window. + UINavigationController * navigationController; // Our View Stack + iphone_glViewController * openGLViewController; // our OpenGL (Game) View + BOOL hasPushedGLView; // Keep track of whether the GL view + // is on top of the stack, for the + // hacked delay used to hide the first + // frame of garbage. +} + +@property (nonatomic, retain) IBOutlet UIWindow *window; + +extern iphoneApp * gAppDelegate; + +- (void) InitializeInterfaceBuilder; + +- (void) HACK_PushController; +- (void) ShowGLView; +- (void) HideGLView; +- (void) PopGLView; + +@end + diff --git a/common/ios/doomengine/iphone_delegate.mm b/common/ios/doomengine/iphone_delegate.mm new file mode 100755 index 0000000..b0b0b7c --- /dev/null +++ b/common/ios/doomengine/iphone_delegate.mm @@ -0,0 +1,225 @@ +/* + + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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. + + */ + +#import "iphone_delegate.h" + +#import +#include "doomiphone.h" +#include "iphone_common.h" +#include "ios/InAppStore.h" +#include "ios/GameCenter.h" + + + +@implementation iphoneApp + +@synthesize window; + +iphoneApp * gAppDelegate = NULL; +bool inBackgroundProcess = false; + +touch_t sysTouches[MAX_TOUCHES]; +touch_t gameTouches[MAX_TOUCHES]; + +#define FRAME_HERTZ 30.0f +const static float ACCELEROMETER_UPDATE_INTERVAL = 1.0f / FRAME_HERTZ; + +/* + ======================== + applicationDidFinishLaunching + ======================== + */ +- (void)applicationDidFinishLaunching:(UIApplication *)application { + + gAppDelegate = self; + inBackgroundProcess = false; + hasPushedGLView = NO; + + // Create the window programmatically instead of loading from a nib file. + self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease]; + + // Disable Screen Dimming. + [[ UIApplication sharedApplication] setIdleTimerDisabled: YES ]; + + // Initial Application Style config. + [ application setStatusBarHidden: YES ]; + + // start the flow of accelerometer events + UIAccelerometer *accelerometer = [UIAccelerometer sharedAccelerometer]; + [ accelerometer setDelegate: self ]; + [ accelerometer setUpdateInterval: ACCELEROMETER_UPDATE_INTERVAL ]; + + [self InitializeInterfaceBuilder ]; + + CommonSystemSetup( [navigationController topViewController] ); + + // do all the game startup work + iphoneStartup(); + + UIView * view = navigationController.view; + + [window addSubview: view]; + [window setRootViewController:navigationController]; + [window setBackgroundColor: [UIColor blackColor] ]; + [window makeKeyAndVisible]; +} + +/* + ======================== + applicationWillResignActive + ======================== + */ +- (void)applicationWillResignActive:(UIApplication *)application { + inBackgroundProcess = YES; + + idGameCenter::HandleMoveToBackground(); + + // If we're in a multiplater game, and showing the OpenGL view, + // go back to the main menu since the multiplayer game is hosed. + if ( netgame && navigationController.topViewController == gAppDelegate->openGLViewController ) { + iphoneMainMenu(); + } + + iphonePauseMusic(); + iphoneShutdown(); +} + +/* + ======================== + applicationDidBecomeActive + ======================== + */ +- (void)applicationDidBecomeActive:(UIApplication *)application { + inBackgroundProcess = NO; +} + + +/* + ======================== + applicationWillTerminate + ======================== + */ +- (void)applicationWillTerminate:(UIApplication *)application { + iphoneStopMusic(); + iphoneShutdown(); +} + + +/* + ======================== + applicationDidReceiveMemoryWarning + ======================== + */ +- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application { + Com_Printf( "applicationDidReceiveMemoryWarning\n" ); +} + + +/* + ======================== + dealloc + ======================== + */ +- (void)dealloc { + [window release]; + [super dealloc]; +} + +/* + ======================== + accelerometer + ======================== + */ +- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration +{ + float acc[4]; + acc[0] = acceleration.x; + acc[1] = acceleration.y; + acc[2] = acceleration.z; + acc[3] = acceleration.timestamp; + + + iphoneTiltEvent( acc ); +} + +/* + ======================== + HACK_PushController - Removes Flicker from Loading Wads. + God forgive me. + + ======================== + */ +- (void) HACK_PushController { + [navigationController pushViewController:openGLViewController animated:NO]; +} + +/* + ======================== + ShowGLView + ======================== + */ +- (void)ShowGLView { + + if( hasPushedGLView == NO ) { + hasPushedGLView = YES; + // Hack city. + [NSTimer scheduledTimerWithTimeInterval:0.2f target:self selector:@selector(HACK_PushController) userInfo:nil repeats:NO]; + + [ openGLViewController StartDisplay ]; + } +} + +/* + ======================== + HideGLView + ======================== + */ +- (void) HideGLView { + + [ navigationController popToRootViewControllerAnimated:NO ]; + hasPushedGLView = NO; +} + +/* + ======================== + PopGLView + ======================== + */ +- (void) PopGLView { + [ navigationController popViewControllerAnimated:NO]; + hasPushedGLView = NO; +} + + +/* + ======================== + InitializeInterfaceBuilder + ======================== + */ +- (void) InitializeInterfaceBuilder { + +} + +@end + +void ShowGLView( void ) { + [ gAppDelegate ShowGLView ]; +} + diff --git a/common/ios/doomengine/iphone_doom.h b/common/ios/doomengine/iphone_doom.h new file mode 100755 index 0000000..8498c86 --- /dev/null +++ b/common/ios/doomengine/iphone_doom.h @@ -0,0 +1,589 @@ +/* + + Copyright (C) 2009 Id Software, 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 + 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. + + */ + +#ifndef IPHONE_DOOM_H +#define IPHONE_DOOM_H + +#include "prboom/doomtype.h" +#include "prboom/doomdef.h" +#include "prboom/doomstat.h" +#include "prboom/d_ticcmd.h" + +#include "ipak.h" +#include "cvar.h" + +#include + +// this is the version number displayed on the menu screen +#define DOOM_IPHONE_VERSION 0.9 + +// if defined, the game runs in a separate thread from the app event loop +#define USE_GAME_THREAD + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum menuState { + IPM_GAME, + IPM_MAIN, + IPM_MAPS, + IPM_MULTIPLAYER, + IPM_CONTROLS, + IPM_OPTIONS, + IPM_HUDEDIT, + IPM_PACKET_TEST +} menuState_t; + +extern menuState_t menuState; +extern menuState_t lastState; + +void iphoneDrawMenus(); + +#define VID_WIDTH 480 +#define VID_HEIGHT 320 + +#define MAX_SKILLS 5 +#define MAX_MAPS 200 + +#define MF_TRIED 1 +#define MF_COMPLETED 2 +#define MF_KILLS 4 +#define MF_SECRETS 8 +#define MF_TREASURE 16 +#define MF_TIME 32 + +// we want to track mapStats for downloaded content, so we +// won't have a known number of these +typedef struct { + int dataset; + int episode; + int map; + + int completionFlags[MAX_SKILLS]; +} mapStats_t; + +// the level select screen returns this +typedef struct { + int dataset; + int episode; + int map; + int skill; +} mapStart_t; + +// this structure is saved out at the head of the binary save file, +// and allows all the menus to work without having to load a game save +typedef struct { + mapStart_t map; // this is the map currently being run + + int saveGameIsValid; // when 0, resume game will just be a new game + + // if someone downloads more than MAX_MAPS, they won't get stat tracking on them. + int numMapStats; + mapStats_t mapStats[MAX_MAPS]; +} playState_t; + +extern playState_t playState; + +extern boolean levelHasBeenLoaded; // determines if "resume game" does a loadGame and exiting does a saveGame + +extern pkTexture_t *arialFontTexture; + +// set to 1 when app is exiting to cause game thread to do a save game, +// which would not be safe to do from the event thread +extern volatile int saveOnExitState; + +extern int asyncTicNum; // 30hz +extern int iphoneFrameNum; // frame rate dependent, max of 30hz +extern int levelLoadFrameNum; +extern int consoleActive; +extern boolean iphoneTimeDemo; +extern int timeDemoStart; +extern char timeDemoResultString[80]; + +extern cvar_t *skill; +extern cvar_t *episode; +extern cvar_t *controlScheme; +extern cvar_t *stickMove; +extern cvar_t *stickTurn; +extern cvar_t *rotorTurn; +extern cvar_t *stickDeadBand; +extern cvar_t *tiltTurn; +extern cvar_t *tiltMove; +extern cvar_t *tiltDeadBand; +extern cvar_t *tiltAverages; +extern cvar_t *music; +extern cvar_t *miniNet; +extern cvar_t *showTilt; +extern cvar_t *showTime; +extern cvar_t *showNet; +extern cvar_t *showSound; +extern cvar_t *cropSprites; +extern cvar_t *mapScale; +extern cvar_t *drawControls; +extern cvar_t *autoUse; +extern cvar_t *statusBar; +extern cvar_t *touchClick; +extern cvar_t *messages; +extern cvar_t *timeLimit; +extern cvar_t *fragLimit; +extern cvar_t *mpDeathmatch; +extern cvar_t *mpDataset; +extern cvar_t *mpSkill; +extern cvar_t *mpEpisode; +extern cvar_t *mpMap; +extern cvar_t *mpExpansion; +extern cvar_t *glfinish; +extern cvar_t *mapSelectY; +extern cvar_t *throttle; +extern cvar_t *centerSticks; +extern cvar_t *rampTurn; +extern cvar_t *netBuffer; + +extern int numTouches; +extern int touches[5][2]; // [0] = x, [1] = y in landscape mode, raster order with y = 0 at top +// so we can detect button releases +extern int numPrevTouches; +extern int prevTouches[5][2]; + +extern float tilt; // -1.0 to 1.0 +extern float tiltPitch; + +extern boolean drawWeaponSelect; // true when the weapon select overlay is up +extern int weaponSelected; // -1 for no change + +typedef unsigned char color4_t[4]; +typedef unsigned char color3_t[3]; + +// networking +typedef enum { + PACKET_VERSION_BASE = 0x24350010, + PACKET_VERSION_SETUP, + PACKET_VERSION_JOIN, + PACKET_VERSION_CLIENT, + PACKET_VERSION_SERVER +} packetType_t; + +#define DOOM_PORT 14666 // setup packets will go to DOOM_PORT+1 + +// the server sends out a setup packet by broadcast, and also directly addressed +// to each client that has joined the game because broadcast packets have truly +// crappy delivery characteristics over WiFi +typedef struct { + int packetType; + int gameID; // every change to anything in packetSetup_t must change gameID + int startGame; // when this is set, start running the game + + int sendCount; // just for packet drop tests + + mapStart_t map; + + int deathmatch; + int fraglimit; + int timelimit; + + int playerID[MAXPLAYERS]; // 0 = not in game +} packetSetup_t; + +// If we have received a recent setup packet before hitting the multiplayer +// button, we will send a join packet to that server. Otherwise, we will +// start acting as a new server. +typedef struct { + int packetType; + + // this should match the packetSetup.gameID + int gameID; + + int playerID; +} packetJoin_t; + +typedef struct { + int packetType; + + // gameID is determined randomly during setup, any packet that doesn't + // match is discarded + int gameID; + + // this could be used to tell when we are dropping client packets + // but it isn't critical + int packetSequence; + + // used to show current round trip latency + int packetAcknowledge; + + // the client's clock at the time the packet was sent, used + // to track one-way latency + int milliseconds; + + // the server could match this up based on ip alone, but it is nice to have + int consoleplayer; + + // the last tic that the client has run + int gametic; + + // some commands will get missed over the network + ticcmd_t cmd; +} packetClient_t; + +typedef struct { + int packetType; + + // gameID is determined randomly during setup, any packet that doesn't + // match is discarded + int gameID; + + // used to detect packet drops + int packetSequence; + + // used to show current round trip latency + int packetAcknowledge; + + // the server's clock at the time the packet was sent, used + // to track one-way latency + int milliseconds; + + // consistancyTic will be the last acknowledged gametic for this + // particular client + int consistancyTic; + + // constancy is used to see if somehow the game running on the + // client has diverged from the one running on the server, + // which is an unrecoverable error + short consistancy[MAXPLAYERS]; + + // this will be the last pc.gametic from the player + int starttic; + + // netcmds[][(maketic-1)&BACKUPTICMASK] is the most recent + int maketic; + + // notifies the server of which players are connected. This way we can handle players + // that disconnect in the middle of a game. + int playersInGame[MAXPLAYERS]; + + // only the [playersInGame*(maketic-starttic)] will be transmitted + ticcmd_t netcmds[MAXPLAYERS*BACKUPTICS]; +} packetServer_t; + +extern int gameSocket; +extern struct sockaddr_in gameSocketAddress; + +extern int playerID; +extern int gameID; +extern int localGameID; +extern int packetSequence; + +// Only one game can be set up at a time on a given wireless segment, although +// several independent games can be played. +// If a valid setupPacket has arrived in the last second, that will be the +// displayed game, otherwise the local system starts sending out setupPackets. +extern packetSetup_t setupPacket; +extern int setupPacketFrameNum; +extern int localGameID; // change every time we take over as the sender of setupPackets + +// set after each game tic if a usable line is in front of the player +extern boolean autoUseActive; +extern boolean respawnActive; + +typedef enum { + NF_NONE, + NF_CONSISTANCY, + NF_INTERRUPTED, + NF_LOST_SERVER +} netFail_t; +extern netFail_t netGameFailure; // set by asyncThread + +typedef struct { + int interfaceIndex; // we must use the right socket to send packets + struct sockaddr address; + int oneWayLatency; // will always have 30+ msec of jitter + int lastPacketAsyncTic; // to easily tell if it just arrived + int lastPacketTime; // local milliseconds of last receive + int lastTimeDelta; // packet milliseconds - local milliseconds + int lowestTimeDelta; // min'd with lastTimeDelta each arrival + int currentPingTics; // packetSequence - last packetAcknowledge +} netPeer_t; + +typedef struct { + netPeer_t peer; + packetClient_t pc; // most recent packet received + + // TODO: There would be some benefit to ensuring that no edge transitions on + // buttons are missed due to clock/net jitter. +} netPlayer_t; + +// all received packets, whether bluetooth or WiFi, go through here +void iphoneProcessPacket( const struct sockaddr *from, const void *data, int len ); + +extern netPeer_t netServer; +extern netPlayer_t netPlayers[MAXPLAYERS]; + +typedef struct { + int numGameTics; + int numPingTics; + int enterFrame; + int afterSleep; + int beforeSwap; + int afterSwap; +} logTime_t; +#define MAX_LOGGED_TIMES 512 +extern logTime_t loggedTimes[MAX_LOGGED_TIMES]; // indexed by iphoneFrameNum + +void LoadWallTexture( int wallPicNum ); + +float StringFontWidth( const char *str ); +int TouchDown( int x, int y, int w, int h ); +int TouchReleased( int x, int y, int w, int h ); +int TouchPressed( int x, int y, int w, int h ); + +// y is the baseline for font drawing +float iphoneDrawText( float x, float y, float scale, const char *str ); +float iphoneCenterText( float x, float y, float scale, const char *str ); + +void StartGame(); +void iphoneOpenAutomap(); +void iphoneDrawNotifyText(); +void iphoneSet2D( void ); + +void R_Draw_Fill( int x, int y, int w, int h, color3_t c ); +void R_Draw_Blend( int x, int y, int w, int h, color4_t c ); + +void InitImmediateModeGL(); + +void iphonePacifierUpdate(); +void iphoneDrawScreen(); + +extern int damageflash; +extern int bonusFrameNum; +extern int attackDirTime[2]; + +#define BF_IGNORE 1 // don't draw or process touches +#define BF_INACTIVE 2 // draw, but no touch processing at all +#define BF_GLOW 4 // animated overbright glow +#define BF_DIMMED 8 // draw darker, but still selectable +#define BF_CENTERTEXT 16 // text in middle of button, not underneath +#define BF_TRANSPARENT 32 // blend translucent +#define BF_HUDBUTTON 64 // don't process in UpdateHudTouch +#define BF_DRAW_ACTIVE 128 // for fire button +#define BF_SMALL_CLICK 256 // for fire button + +typedef struct { + int x, y; + int drawWidth, drawHeight; + pkTexture_t *texture; + + const char *title; + struct touch_s *touch; + float scale; // ramps up and down after touches + int frameNum; // reset scale if not checked on previous frame + int buttonFlags; + boolean twoFingerPress; // if a second finger came down before a release for timedemo / etc + boolean pressed; // true when a touch goes down in it + + // stuff for hud controls + boolean drawAsLimit; // color tint when further movement won't do anything + float touchState; // rotor angle + float drawState; // offsets for rotors + int downX, downY; // initial touch went down here +} ibutton_t; + +typedef struct { + ibutton_t forwardStick; + ibutton_t sideStick; + ibutton_t turnStick; + ibutton_t turnRotor; + ibutton_t fire; + ibutton_t menu; + ibutton_t map; + ibutton_t weaponSelect; +} hud_t; + +extern hud_t huds; + +void HudSetForScheme( int schemeNum ); +void HudSetTexnums(); +void HudEditFrame(); + +boolean StartNetGame(); + +int BackButton(); +void ResumeGame(); + +//--------------------------------------- +// Touch and button +//--------------------------------------- + +typedef struct touch_s { + boolean down; + int x, y; +// int prevX, prevY; // will be set to x, y on first touch, copied after each game frame + int stateCount; // set to 1 on first event that state changes, incremented each game frame (-1 is a special tapped-and-released code) + void *controlOwner; +} touch_t; + +#define MAX_TOUCHES 5 +extern touch_t sysTouches[MAX_TOUCHES]; +extern touch_t gameTouches[MAX_TOUCHES]; + +touch_t *TouchInBounds( int x, int y, int w, int h ); +touch_t *AnyTouchInBounds( int x, int y, int w, int h ); +touch_t *UpdateHudTouch( ibutton_t *hud ); + +bool NewTextButton( ibutton_t *b, const char *title, int x, int y, int w, int h ); +void SetButtonPics( ibutton_t *button, const char *picName, const char *title, int x, int y ); +void SetButtonPicsAndSizes( ibutton_t *button, const char *picBase, const char *title, int x, int y, int w, int h ); +boolean HandleButton( ibutton_t *button ); + +//--------------------------------------- +// Doom stuff we use directly +//--------------------------------------- +void G_DoSaveGame (boolean menu); +extern short consistancy[MAXPLAYERS][BACKUPTICS]; +extern boolean levelTimer; +extern int levelTimeCount; +extern boolean levelFragLimit; +extern int levelFragLimitCount; + +//--------------------------------------- +// iphone_sound.c +//--------------------------------------- + +void Sound_Init( void ); +void Sound_StartLocalSound( const char *sound ); +void Sound_StartLocalSoundAtVolume( const char *sound, float volume ); + +void ShowSound(); + +//--------------------------------------- +// iphone_net.c +//--------------------------------------- + +// dump all the interfaces and ip addresses for debugging +void ReportNetworkInterfaces(); + +// open a UDP socket, pass "en0" for wifi +int UDPSocket( const char *interfaceName, int portnum ); + +// return false if the multiplayer button should be disabled +boolean NetworkAvailable(); + +// this can be called every frame in the menu to highlight +// the multiplayer icon when a server is already up +boolean NetworkServerAvailable(); + +// returns "WiFi", "BlueTooth", or "" for display on the +// main menu multiplayer icon +const char *NetworkServerTransport(); + +// this queries DNS for the actual address +boolean ResolveNetworkServer( struct sockaddr *addr ); + +// If we are starting a server instead of joining one, make +// us available as a bonjour service until we start the game +// or back out of the multiplayer menu. Returns false if +// someone else grabbed it just before we could. +boolean RegisterGameService(); +void TerminateGameService(); + +// called by AsyncTic() to check for server state changes, +// registers for service browsing on first call. +void ProcessDNSMessages(); + +// draw a graph of packets sent and received +void ShowNet(); +void ShowMiniNet(); + +//--------------------------------------- +// iphone_mapSelect.c +//--------------------------------------- +mapStats_t *FindMapStats( int dataset, int episode, int map, boolean create ); +const char *FindMapName( int dataset, int episode, int map ); + +//--------------------------------------- +// iphone_start.c +// +// game harness routines +//--------------------------------------- +void ResumeGame(); +boolean StartNetGame(); +void StartSaveGame(); +void StartSinglePlayerGame( mapStart_t map ); +void StartDemoGame( boolean timeDemoMode ); +void StartupWithCorrectWads( int mission ); + +//--------------------------------------- +// interfaces from the original game code +//--------------------------------------- +void iphoneSetNotifyText( const char *str, ... ); +void iphoneIntermission( wbstartstruct_t* wbstartstruct ); +void iphoneStartLevel(); +void iphoneStartMusic(); +void iphoneStopMusic(); +void iphonePlayMusic( const char *name ); +void iphonePauseMusic(); +void iphoneResumeMusic(); +void iphoneDoomStartup( const char * iwad, const char * pwad ); +void iphoneLoadMissionPack(void); +void iphoneAddPWADFiles(void); + +//--------------------------------------- +// interfaces to Objective-C land +//--------------------------------------- + +// The event thread will fill this after hitting enter +// on the console. The game thread should check it, +// execute it, and clear it under mutex. +extern char consoleCommand[1024]; + +void SysIPhoneSwapBuffers(); +void SysIPhoneVibrate(); +void SysIPhoneOpenURL( const char *url ); +int SysIPhoneIsDeviceLandscapeRight( void ); +void SysIPhoneSetUIKitOrientation( int isLandscapeRight ); +const char * SysIPhoneGetConsoleTextField(); +void SysIPhoneSetConsoleTextField(const char *); +void SysIPhoneInitAudioSession(); +int SysIPhoneOtherAudioIsPlaying(); +int SysIphoneMilliseconds(); +int SysIphoneMicroseconds(); +const char * SysIphoneGetAppDir(); +const char * SysIphoneGetDocDir(); +const char * SysIphoneGetTempDir(); + +void ShowGLView( void ); + +//--------------------------------------- +// interfaces from Objective-C land +//--------------------------------------- +void iphoneStartup(); +void iphoneShutdown(); +void iphoneFrame(); +void iphoneAsyncTic(); +void iphoneTiltEvent( float *tilts ); +void iphoneMainMenu(); +void iphonePopGL(); + +#ifdef __cplusplus +} +#endif + +#define DEFAULTS_MISSIONPACK_KEY "missionPack" + +#endif diff --git a/common/ios/doomengine/iphone_email.h b/common/ios/doomengine/iphone_email.h new file mode 100755 index 0000000..7d60479 --- /dev/null +++ b/common/ios/doomengine/iphone_email.h @@ -0,0 +1,35 @@ +/* + * iphone_email.h + * Doom + * + * Created by Greg Hodges on 10/20/09. + * Copyright 2009 id Software. All rights reserved. + * + */ +/* + + Copyright (C) 2009 Id Software, 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 + 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. + + */ + + + +//Appends the console buffer while replacings non-URLscheme compatible text +void AppendConsoleBuffer(const char *buf); + +//Emails the console buffer to id software +void EmailConsole(); diff --git a/common/ios/doomengine/iphone_email.m b/common/ios/doomengine/iphone_email.m new file mode 100755 index 0000000..9c11c1e --- /dev/null +++ b/common/ios/doomengine/iphone_email.m @@ -0,0 +1,203 @@ +/* + * iphone_email.c + * Doom + * + * Created by Greg Hodges on 10/20/09. + * Copyright 2009 id Software. All rights reserved. + * + */ +/* + + Copyright (C) 2009 Id Software, 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 + 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 "iphone_email.h" +#include + +#import +#import + + +char *consoleBuffer = NULL; //buffer for the console output +int size = 0; + +/* + * ReplaceAt() + * Replaces the char at location with the insertString + */ +void ReplaceAt( char *oldString, const char *insertString, int location) +{ + int length = strlen(oldString); + int chunkLength = strlen(insertString); + + char *newString = malloc(length + chunkLength + 1);//the 1 includes space for the null terminating character + +#if 0 + //strcpy(newString, old); + strncpy(newString, oldString, location); + newString[location] = '\0'; + strcat(newString, insertString); + strcpy(&newString[location+chunkLength], &oldString[location + 1]); + + free(oldString); + oldString = newString; +#endif + + //copy the front part + char frontPart[location+1]; + strncpy(frontPart, oldString, location); + frontPart[location] = '\0'; + printf("\nfrontPart: %s", frontPart); + + //copy the back part + char backPart[length - location]; + strcpy(backPart, &oldString[location+1]); + backPart[length - location - 1] = '\0'; + printf("\nbackPart: %s\n\n", backPart); + + //put it all together in the new string + newString[0] = '\0'; + strcat(newString, frontPart); + strcat(newString, insertString); + strcat(newString, backPart); + + //delete old string + free(oldString); + + //replace old string + oldString = newString; +} + +/* + * AppendBuffer() + * Directly appends the console buffer + */ +void AppendBuffer(const char *buf) +{ + int length = strlen(buf) + 1; //strlen doesn't include the null terminating character + char *temp = malloc(length); + strcpy(temp, buf); + + + for (int i = 0; i < length; ++i) + { + if (temp[i] == ' ' || temp[i] == '\n' || temp[i] == '=' ) + temp[i] = '_'; + } + +#if 0 + int i = 0; + while (temp[i] != '\0') + { + if (temp[i] == ' ') + ReplaceAt(temp, "_testString_", i); + + ++i; + } + length = strlen(temp) + 1; +#endif + + //copy the old & new string into a buffer + char *newBuf = malloc(size + length); + if (consoleBuffer) + { + strcpy(newBuf, consoleBuffer); + } + strcpy(&newBuf[size], temp); + + + //delete the old string and have it point to the new one + free(consoleBuffer); + consoleBuffer = newBuf; + size = strlen(consoleBuffer); + + + //delete the temp string + free(temp); +} + +/* + * AppendChunk() + * Just append a chunk of the incoming string from start to i + */ +void AppendChunk(const char *buf, int start, int i) +{ + int chunkSize = i+1 - start; + char chunk[chunkSize]; + chunk[0] = '\0'; + strncpy(chunk, &buf[start], chunkSize-1); + chunk[chunkSize-1] = '\0'; + AppendBuffer(chunk); +} + +/* + * AppendConsoleBuffer() + * Appends the console buffer while replacings non-URLscheme compatible text + */ +void AppendConsoleBuffer(const char *buf) +{ + +} + + +/* + * + * Email the console buffer to id + * + */ +void EmailConsole() +{ + + return; // do not email me anymore. + +#if 0 + if (!consoleBuffer) + return; + + //copy everything from consoleBuffer into a char* + char *buffer = malloc(1024+size+1); + +#if 0 + time_t rawtime; + struct tm * timeinfo; + time ( &rawtime ); + timeinfo = gmtime ( &rawtime ); + char dateBuffer[128]; + sprintf(dateBuffer, asctime(timeinfo)); + for (int i = 0; i < strlen(dateBuffer); ++i) + { + if (dateBuffer[i] == ' ' || dateBuffer[i] == ':') + dateBuffer[i] = '_'; + } + printf("formatted time: %s\n", dateBuffer); + + sprintf( buffer, "mailto:iphonesupport@idsoftware.com?subject=DoomClassicReport%s&body=%s", dateBuffer, consoleBuffer); +#else + sprintf( buffer, "mailto:iphonesupport@idsoftware.com?subject=DoomClassicReport&body=%s", consoleBuffer); +#endif + + //call the mail app + NSURL *url = [[NSURL alloc] initWithString:[NSString stringWithCString:buffer encoding:NSUTF8StringEncoding]]; + [[UIApplication sharedApplication] openURL:url]; + + free(buffer); +#endif +} + + diff --git a/common/ios/doomengine/iphone_glViewController.h b/common/ios/doomengine/iphone_glViewController.h new file mode 100755 index 0000000..be38028 --- /dev/null +++ b/common/ios/doomengine/iphone_glViewController.h @@ -0,0 +1,36 @@ +/* + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + Copyright (C) 2009 Id Software, 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 + 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. + + */ + +#import + + +@interface iphone_glViewController : UIViewController { + + CADisplayLink *displayLink; + +} + +@property (nonatomic, retain) IBOutlet CADisplayLink *displayLink; + +- (void) StartDisplay; +- (void) StopDisplay; +- (bool) IsDisplaying; + +@end diff --git a/common/ios/doomengine/iphone_glViewController.mm b/common/ios/doomengine/iphone_glViewController.mm new file mode 100755 index 0000000..f2f5ec2 --- /dev/null +++ b/common/ios/doomengine/iphone_glViewController.mm @@ -0,0 +1,164 @@ +/* + Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. + + 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. + + */ + +#import "iphone_glViewController.h" +#import "EAGLView.h" +#import +#include "doomiphone.h" + +const static int DISPLAY_LINK_FRAME_INTERVAL = 2; + +// Need one buffer frame when transitioning from IB menus to the OpenGL game view. +// Otherwise, occasionally the IB view stays onscreen during the Doom loading frame. +// This seems to make precaching take way to long (about a whole minute). +// This flag will be set to true in StartDisplay, and reset to false after one display link +// frame has fired. +static bool inTransition = false; + +@implementation iphone_glViewController + +@synthesize displayLink; + +/* + ======================== + runFrame + ======================== + */ +- (void)runFrame { + + // Skip the frist frame after coming from IB menus, to give the view a chance to switch to + // OpenGL. For some reason, not doing this causes precaching to take way too long. + if ( inTransition ) { + inTransition = false; + return; + } + + // Update the Game + iphoneAsyncTic(); + + // Render the Game. + iphoneFrame(); +} + +/* + ======================== + initWithNibName + ======================== + */ +- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { + self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; + if (self) { + + // Create the OpenGL View. + EAGLView *glView = [[EAGLView alloc] initWithFrame:[UIScreen mainScreen].applicationFrame]; + self.view = glView; + [glView release]; + + + // Setup the Display Link + CADisplayLink *aDisplayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(runFrame)]; + [ aDisplayLink setFrameInterval: DISPLAY_LINK_FRAME_INTERVAL]; + [ aDisplayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; + [ self setDisplayLink: aDisplayLink ]; + + } + return self; +} + +/* +======================== +shouldAutorotateToInterfaceOrientation +======================== +*/ +- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { + // Return YES for supported orientations. + return UIInterfaceOrientationIsLandscape(interfaceOrientation); +} + +/* + ======================== + viewDidLoad + ======================== + */ +- (void)viewDidLoad { + [super viewDidLoad]; + + // Stop the Display link. + [self.displayLink invalidate]; + self.displayLink = nil; +} + + +/* + ======================== + didReceiveMemoryWarning + ======================== + */ +- (void)didReceiveMemoryWarning { + // Releases the view if it doesn't have a superview. + [super didReceiveMemoryWarning]; +} + +/* + ======================== + viewDidUnload + ======================== + */ +- (void)viewDidUnload { + [super viewDidUnload]; +} + +/* + ======================== + dealloc + ======================== + */ +- (void)dealloc { + [super dealloc]; +} + +/* + ======================== + StartDisplay + ======================== + */ +- (void) StartDisplay { + inTransition = true; + displayLink.paused = NO; +} + +/* + ======================== + StopDisplay + ======================== + */ +- (void) StopDisplay { + displayLink.paused = YES; +} + +/* + ======================== + IsDisplaying + ======================== + */ +- (bool) IsDisplaying { + return displayLink.paused; +} + +@end diff --git a/common/ios/doomengine/iphone_loop.c b/common/ios/doomengine/iphone_loop.c new file mode 100755 index 0000000..8aa6792 --- /dev/null +++ b/common/ios/doomengine/iphone_loop.c @@ -0,0 +1,1792 @@ +/* + + Copyright (C) 2009 Id Software, 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 + 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 "doomiphone.h" + +playState_t playState; + +#define OWNER_AUTOMAP (void *)0x123 + +int iphoneFrameNum; +int levelLoadFrameNum; +boolean iphoneTimeDemo; +char timeDemoResultString[80]; +int timeDemoFrames; +int timeDemoStart; + +// set to 1 when app is exiting to cause game thread to do a save game, +// which would not be safe to do from the event thread +volatile int saveOnExitState; + +// console mode +int consoleActive; + +// current touches latched from the system touches +int numTouches; +int touches[5][2]; // [0] = x, [1] = y in landscape mode, raster order with y = 0 at top + +// so we can detect button releases +int numPrevTouches; +int prevTouches[5][2]; + +float tilt; // -1.0 to 1.0 +float tiltPitch; + +#define MAX_TILT_HISTORY 64 +float tiltHistory[MAX_TILT_HISTORY][4]; +int tiltHistoryNum; + +// pressing on the weapon brings up the weaponSelect overlay +boolean drawWeaponSelect; +int weaponSelected = -1; + +pkTexture_t *arialFontTexture; + + +logTime_t loggedTimes[MAX_LOGGED_TIMES]; // indexed by iphoneFrameNum + +int gameSocket; +int gameID; +int playerID; +int packetSequence; // for logging dropped packets and estimating latency +netFail_t netGameFailure; // set by asyncThread +netPlayer_t netPlayers[MAXPLAYERS]; +netPeer_t netServer; + +// set after each game tic if a usable line is in front of the player +boolean autoUseActive; +boolean respawnActive; + +// if we haven't processed a game tic in a half second, draw the net problem icon +int lastGameProcessedTime; + +// this flag lets us give a shotgun and some ammo after the player has respawned +boolean addGear; + +extern bool inBackgroundProcess; +/* +================================================================================= + + Touch Handling + + With multiple draggable controls on screen, it is important to track touches + as continuous events, rather than discrete points, because we want to allow + a finger to start on a dragable control, but still function when it has + been dragged outside the original hot area, and not trigger anything else + as it wanders around. + + I considered a Down / Dragged / Released interface, but especially with + threading, it was better to keep them as a set of structures that could + be looked at at different points in the game loop. + + if touch goes down on a dragable control, it will be owned by that control until it + is released, even if it is dragged outside the original bounds. + + If we support pinch for anything, a single control will own multiple touches. + + Touches that aren't owned by a dragable control are free-roaming, and can hit buttons. + + ================================================================================= + */ + + +/* + + Does not claim ownership or play any sounds. + The touch can be dragged in if it isn't owned by + another control. + + */ +touch_t *TouchInBounds( int x, int y, int w, int h ) { + for ( int i = 0 ; i < MAX_TOUCHES ; i++ ) { + touch_t *t = &gameTouches[i]; + if ( t->controlOwner ) { + continue; // already claimed + } + if ( !t->down ) { + continue; // not pressed + } + if ( t->x >= x && t->x < x + w + && t->y >= y && t->y < y + h ) { + return t; + } + } + return NULL; +} + + +// even a touch claimed by another control will count (fire button) +touch_t *AnyTouchInBounds( int x, int y, int w, int h ) { + for ( int i = 0 ; i < MAX_TOUCHES ; i++ ) { + touch_t *t = &gameTouches[i]; + if ( !t->down ) { + continue; // not pressed + } + if ( t->x >= x && t->x < x + w + && t->y >= y && t->y < y + h ) { + return t; + } + } + return NULL; +} + + +touch_t *UpdateHudTouch( ibutton_t *hud ) { + if ( hud->buttonFlags & ( BF_IGNORE | BF_HUDBUTTON ) ) { + // hud element isn't active + return NULL; + } + + if ( !hud->touch ) { + // see if a free touch was just made in, or dragged into the bounds + // make the active boxes twice as large as the drawing bounds + int x = hud->x - ( hud->drawWidth >> 1 ); + int y = hud->y - ( hud->drawHeight >> 1 ); + int w = hud->drawWidth << 1; + int h = hud->drawHeight << 1; + + hud->touch = TouchInBounds( x, y, w, h ); + if ( hud->touch ) { + // claim this touch so it won't activate anything else + hud->touch->controlOwner = hud; + if ( touchClick->value ) { + Sound_StartLocalSoundAtVolume( "iphone/controller_down_01_SILENCE.wav", touchClick->value ? 0.15f : 0.0f ); + } + // save the initial touch position for auto-centering stcks + hud->downX = hud->touch->x; + hud->downY = hud->touch->y; + + // Clamp it so that you are guaranteed to have a full range of motion. + // This means that a touch at the edge of the screen won't center it, + // but will instead cause immediate movement. This prevents the main + // drawback of the centering controls -- if you pressed down too close + // to the side, you wouldn't have full mobility that direction. + int width = hud->drawWidth / 2; + int height = hud->drawHeight / 2; + if ( hud->downX < width ) { + hud->downX = width; + } + if ( hud->downX + width > displaywidth ) { + hud->downX = displaywidth - width; + } + if ( hud->downY < height ) { + hud->downY = height; + } + if ( hud->downY > displayheight - height ) { + hud->downY = displayheight - height; + } + } + } + + if ( hud->touch ) { + // see if the touch was released + if ( !hud->touch->down ) { + if ( touchClick->value ) { + Sound_StartLocalSoundAtVolume( "iphone/controller_up_01_SILENCE.wav", touchClick->value ? 0.15f : 0.0f ); + } + hud->touch = NULL; + } + } + return hud->touch; +} + + +void SetButtonPics( ibutton_t *button, const char *picBase, const char *title, int x, int y ) { + button->texture = PK_FindTexture( picBase ); + button->scale = 1.0f; + button->title = title; + button->x = x * ((float)displaywidth) / 480.0f; + button->y = y * ((float)displayheight) / 320.0f; + + float xRatio = ((float)displaywidth) / 480.0f; + float yRatio = ((float)displayheight) / 320.0f; + + float themin = MIN( xRatio, yRatio ); + + button->drawWidth = button->texture->textureData->srcWidth * themin; + button->drawHeight = button->texture->textureData->srcHeight * themin; +} + +void SetButtonPicsAndSizes( ibutton_t *button, const char *picBase, const char *title, int x, int y, int w, int h ) { + SetButtonPics( button, picBase, title, x, y ); + + + float xRatio = ((float)displaywidth) / 480.0f; + float yRatio = ((float)displayheight) / 320.0f; + + float themin = MIN( xRatio, yRatio ); + + button->drawWidth = w * themin; + button->drawHeight = h * themin; +} + +/* + ================== + HandleButton + + Plays enter / exit / action sounds, returns true if the + touch was released inside the bounds. + + Touches can slide onto a button, they aren't required + to tap initially inside it. + + Main menu buttons and the small in-game buttons are + done with this. Because these handle both drawing and + decision making, there is a frame of latency involved + versus splitting the decision making and drawing. + + Returns true if the button should perform its action. + ================== + */ +float buttonScaleStep = 0.01f; +float buttonScaleMin = 0.95f; +boolean HandleButton( ibutton_t *button ) { + if ( button->buttonFlags & BF_IGNORE ) { + return false; + } + + + // Hack + button->drawHeight = button->drawWidth; + + if ( ( button->buttonFlags & BF_TRANSPARENT ) && !button->touch ) { + // draw half-transparent + glColor4f( 1, 1, 1, 0.5 ); + } else if ( button->buttonFlags & BF_DIMMED ) { + // draw half-bright + glColor4f( 0.5, 0.5, 0.5, 1 ); + } else { + glColor4f( 1, 1, 1, 1 ); + } + + if ( button->touch && !button->touch->down ) { + button->touch->controlOwner = NULL; + button->touch = NULL; + } + + bool released = false; + if ( !(button->buttonFlags & BF_INACTIVE) ) { + if ( button->touch ) { + // see if the touch was dragged outside the button bounds + if ( button->touch->x < button->x || button->touch->x >= button->x + button->drawWidth + || button->touch->y < button->y || button->touch->y >= button->y + button->drawHeight ) { + // dragged outside, don't trigger on release now + if ( button->buttonFlags & BF_SMALL_CLICK ) { + Sound_StartLocalSoundAtVolume( "iphone/controller_up_01_SILENCE.wav", touchClick->value ? 0.15f : 0.0f ); + } else { + Sound_StartLocalSound( "iphone/baborted_01.wav" ); + } + button->touch->controlOwner = NULL; + button->touch = NULL; + button->pressed = false; + } + } + if ( !button->touch ) { + if ( button->pressed ) { + // released inside the button, so do the action + if ( button->buttonFlags & BF_SMALL_CLICK ) { + Sound_StartLocalSoundAtVolume( "iphone/controller_up_01_SILENCE.wav", touchClick->value ? 0.15f : 0.0f ); + } else { + Sound_StartLocalSound( "iphone/baction_01.wav" ); + } + button->pressed = false; + released = true; + } + } + + // see if a new touch went down or moved into the button + if ( !released && !button->touch ) { + button->twoFingerPress = false; + + for ( int i = 0 ; i < MAX_TOUCHES ; i++ ) { + touch_t *t = &gameTouches[i]; + if ( t->controlOwner ) { + continue; // already claimed + } + if ( !t->down ) { + continue; + } + if ( t->x >= button->x && t->x < button->x + button->drawWidth + && t->y >= button->y && t->y < button->y + button->drawHeight ) { + if ( button->buttonFlags & BF_SMALL_CLICK ) { + Sound_StartLocalSoundAtVolume( "iphone/controller_down_01_SILENCE.wav", touchClick->value ? 0.15f : 0.0f ); + } else { + Sound_StartLocalSound( "iphone/bdown_01.wav" ); + } + button->touch = t; + button->pressed = true; + t->controlOwner = &button; + break; + } + } + } + } + + // animate scale + if ( button->frameNum != iphoneFrameNum - 1 ) { + button->scale = 1.0f; // just came back to a menu + } + button->frameNum = iphoneFrameNum; + + if ( button->touch && button->touch->down ) { + // check for a two-finger touch for alternate modes + for ( int i = 0 ; i < MAX_TOUCHES ; i++ ) { + touch_t *t = &gameTouches[i]; + if ( t->controlOwner ) { + continue; // already claimed + } + if ( t == button->touch ) { + continue; // the primary touch + } + if ( !t->down ) { + continue; + } + if ( t->x >= button->x && t->x < button->x + button->drawWidth + && t->y >= button->y && t->y < button->y + button->drawHeight ) { + button->twoFingerPress = true; + break; + } + } + + // adjust the animated scale + button->scale -= buttonScaleStep; + if ( button->scale < buttonScaleMin ) { + button->scale = buttonScaleMin; + } + } else { + button->scale += buttonScaleStep; + if ( button->scale > 1.0f ) { + button->scale = 1.0f; + } + } + + if ( button->buttonFlags & BF_GLOW ) { + // cycle through double-bright + float f = 0.75 + 0.25 * sin( 3.14159 * 2 * ( iphoneFrameNum & 31 ) / 32.0 ); + + glColor4f( f, f, f, 1 ); + + glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE ); + glTexEnvf( GL_TEXTURE_ENV, GL_RGB_SCALE, 2.0 ); + } + PK_StretchTexture( button->texture, button->x+button->drawWidth/2 - button->drawWidth/2 * button->scale, + button->y + button->drawHeight/2 - button->drawHeight/2 * button->scale, + button->drawWidth * button->scale, button->drawHeight * button->scale ); + if ( button->buttonFlags & BF_GLOW ) { + glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); + glColor4f( 1, 1, 1, 1 ); + } + + if ( button->title ) { + float length = StringFontWidth( button->title ) * 0.75; + float x = button->x + button->drawWidth/2 - length/2; + // don't push the text off the edge of the screen + if ( x < 0 ) { + x = 0; + } else if ( x + length > displaywidth ) { + x = displaywidth - length; + } + float y; + float textScale = 0.75; + if ( button->buttonFlags & BF_CENTERTEXT ) { + glColor4f( 1, 1, 1, 1 ); // !@# remove when we get a button background that doesn't need dimming + y = button->y + button->drawHeight / 2 + 8; + textScale *= button->scale; // animate text scale when centered + } else { + y = button->y + button->drawHeight + 16; + } + iphoneDrawText( x, y, textScale, button->title ); + } + + glColor4f( 1, 1, 1, 1 ); + + return released; +} + +//========================================================================= + + +typedef struct { + unsigned short x0, y0, x1, y1; + float xoff, yoff, xadvance; +} GlyphRect; + +#include "arialGlyphRects.h" // precalculated offsets in the font image + +float StringFontWidth( const char *str ) { + float len = 0; + while ( *str ) { + int i = *str; + if ( i >= ' ' && i < 128 ) { + len += glyphRects[i-32].xadvance; + } + str++; + } + return len; +} + +/* + ================== + iphoneDrawText + + Returns the width in pixels + ================== + */ +float iphoneDrawText( float x, float y, float scale, const char *str ) { + + float fx = x; + float fy = y; + + PK_BindTexture( arialFontTexture ); + glBegin( GL_QUADS ); + + while ( *str ) { + int i = *str; + if ( i >= ' ' && i < 128 ) { + GlyphRect *glyph = &glyphRects[i-32]; + + // the glyphRects don't include the shadow outline + float x0 = ( glyph->x0 - 1 ) / 256.0; + float y0 = ( glyph->y0 - 1 ) / 256.0; + float x1 = ( glyph->x1 + 2 ) / 256.0; + float y1 = ( glyph->y1 + 2 ) / 256.0; + + float width = ( x1 - x0 ) * 256 * scale; + float height = ( y1 - y0 ) * 256 * scale; + + float xoff = ( glyph->xoff - 1 ) * scale; + float yoff = ( glyph->yoff - 1 ) * scale; + + glTexCoord2f( x0, y0 ); + glVertex2f( fx + xoff, fy + yoff ); + + glTexCoord2f( x1, y0 ); + glVertex2f( fx + xoff + width, fy + yoff ); + + glTexCoord2f( x1, y1 ); + glVertex2f( fx + xoff + width, fy + yoff + height ); + + glTexCoord2f( x0, y1 ); + glVertex2f( fx + xoff, fy + yoff + height ); + + // with our default texture, the difference is negligable + fx += glyph->xadvance * scale; +// fx += ceil(glyph->xadvance); // with the outline, ceil is probably the right thing + } + str++; + } + + glEnd(); + + return fx - x; +} + +/* + ================== + iphoneCenterText + + Returns the width in pixels + ================== + */ +float iphoneCenterText( float x, float y, float scale, const char *str ) { + float l = StringFontWidth( str ); + + x *= ((float)displaywidth) / 480.0f; + y *= ((float)displayheight) / 320.0f; + + x -= l * scale * 0.5; + + return iphoneDrawText( x, y, scale, str ); +} + + +/* + ================== + TouchDown + + Checks all touches against a square + ================== + */ +int TouchDown( int x, int y, int w, int h ) { + int i; + for ( i = 0 ; i < numTouches ; i++ ) { + if ( touches[i][0] >= x && touches[i][1] >= y + && touches[i][0] < x + w && touches[i][1] < y + h ) { + return 1; + } + } + return 0; +} + + +/* + ================== + TouchPressed + + Requires that the touch be inside the bounds, and that it didn't seem to be + dragged in from out of the bounds in the previous frame. + ================== + */ +int TouchPressed( int x, int y, int w, int h ) { + + x *= ((float)displaywidth) / 480.0f; + y *= ((float)displayheight) / 320.0f; + w *= ((float)displaywidth) / 480.0f; + h *= ((float)displayheight) / 320.0f; + + for ( int i = 0 ; i < MAX_TOUCHES ; i++ ) { + touch_t *t = &gameTouches[i]; + if ( !t->down ) { + continue; + } + if ( t->controlOwner ) { + continue; + } + if ( t->stateCount != 1 ) { + // not just pressed + continue; + } + + if ( t->x < x || t->x >= x + w + || t->y < y || t->y >= y + h ) { + continue; + } + // just pressed this frame + return 1; + } + return 0; +} + + +/* + ================== + TouchReleased + + Perform an action when released in the box. + If not down this frame, but down the previous frame, it is released + ================== + */ +int TouchReleased( int x, int y, int w, int h ) { +#if 0 + // only check when the touch count just went down by one + if ( numTouches != numPrevTouches - 1 ) { + return 0; + } + int i; + int downPrev = 0; + int downNow = 0; + + for ( i = 0 ; i < numPrevTouches ; i++ ) { + if ( prevTouches[i][0] >= x && prevTouches[i][1] >= y + && prevTouches[i][0] < x + w && prevTouches[i][1] < y + h ) { + downPrev = 1; + break; + } + } + + // see if not down this frame + for ( i = 0 ; i < numTouches ; i++ ) { + if ( touches[i][0] >= x && touches[i][1] >= y + && touches[i][0] < x + w && touches[i][1] < y + h ) { + downNow = 1; + break; + } + } + + if ( !downPrev ) { + if ( downNow ) { + Sound_StartLocalSound( "iphone/bdown_01.wav" ); + } + // wasn't down the previous frame + return 0; + } + + if ( downNow ) { + // still down + return 0; + } + + if ( numTouches == numPrevTouches ) { + // finger dragged off + Sound_StartLocalSound( "iphone/baborted_01.wav" ); + return 0; + } + + // released + Sound_StartLocalSound( "iphone/baction_01.wav" ); + return 1; +#else + for ( int i = 0 ; i < MAX_TOUCHES ; i++ ) { + touch_t *t = &gameTouches[i]; + if ( t->down ) { + continue; // still pressed + } + if ( t->x >= x && t->x < x + w + && t->y >= y && t->y < y + h ) { + if ( t->stateCount <= 1 ) { + // just released + Sound_StartLocalSound( "iphone/baction_01.wav" ); + return 1; + } + } + } + return 0; +#endif +} + +/* + ================== + iphoneSet2D + + ================== + */ +void iphoneSet2D( void ) { + // note that GL thinks the iphone is always + // in portrait mode as far as the framebuffer + // is concerned. + glViewport( 0,0, displayheight, displaywidth ); + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + glEnable( GL_TEXTURE_2D ); + glDisable( GL_DEPTH_TEST ); + glDisable( GL_SCISSOR_TEST ); + glDisable( GL_FOG ); + glDisable( GL_CULL_FACE ); + glEnable( GL_BLEND ); + glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + glDisable( GL_ALPHA_TEST ); + glColor4f( 1,1,1,1 ); + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + glOrthof( 0, displaywidth, displayheight, 0, -99999, 99999 ); +} + +void iphoneTiltEvent( float *tilts ) { + int i; + int j; + int c; + float sum[3]; + static float prevTime; + + // we probably should mutex this, but I doubt it causes any problems + /* + if ( revLand->value ) { + tilts[1] = -tilts[1]; + tilts[0] = -tilts[0]; + } + */ + + c = tiltAverages->value; + if ( c < 1 ) { + c = 1; + } else if ( c > MAX_TILT_HISTORY ) { + c = MAX_TILT_HISTORY; + } + + // acc[0] - [2] are accelerometer values, ax[3] is the timestamp + for ( i = 0 ; i < 3 ; i++ ) { + tiltHistory[tiltHistoryNum&(MAX_TILT_HISTORY-1)][i] = tilts[i]; + sum[i] = 0; + for ( j = 0 ; j < c ; j++ ) { + sum[i] += tiltHistory[(tiltHistoryNum-j)&(MAX_TILT_HISTORY-1)][i]; + } + sum[i] /= c; + } + // save the timestamp for analysis and tap detection + tiltHistory[tiltHistoryNum&(MAX_TILT_HISTORY-1)][3] = tilts[3] - prevTime; + prevTime = tilts[3]; + tiltHistoryNum++; + + tilt = sum[1]; + tiltPitch = sum[0]; +// Com_Printf( "%4.2f %4.2f %4.2f\n", tilts[0], tilts[1], tilts[2] ); +} + +void ShowTilt() { + int i; + int axis = (int)showTilt->value - 1; + color4_t fillColor = { 255, 0, 0, 255 }; + color4_t whiteColor = { 255, 255, 255, 255 }; + color4_t nowColor = { 0, 255, 0, 255 }; + float x; + + if ( axis < 0 || axis > 2 ) { + return; + } + for ( i = 0 ; i < MAX_TILT_HISTORY ; i++ ) { + x = tiltHistory[(tiltHistoryNum-1-i)&(MAX_TILT_HISTORY-1)][axis] * ( 10 / 0.018168604 ); + if ( x < 0 ) { + R_Draw_Fill( 240 + x, i*4, -x, 4, fillColor ); + } else if ( x > 0 ) { + R_Draw_Fill( 240, i*4, x, 4, fillColor ); + } + } + x = tilt * ( 10 / 0.018168604 ); + if ( x < 0 ) { + R_Draw_Fill( 240 + x, i*4, -x, 4, nowColor ); + } else if ( x > 0 ) { + R_Draw_Fill( 240, i*4, x, 4, nowColor ); + } + R_Draw_Fill( 240, 0, 1, MAX_TILT_HISTORY*4, whiteColor ); +} + +void ShowTime() { + if ( !showTime->value ) { + return; + } + color4_t sleepColor = { 255, 0, 0, 255 }; + color4_t activeColor = { 0, 255, 0, 255 }; + color4_t swapColor = { 0, 0, 255, 255 }; + color4_t ticColor = { 255, 255, 255, 255 }; + + for ( int i = 1 ; i < 30 ; i++ ) { + logTime_t *lt = &loggedTimes[(iphoneFrameNum - i ) & (MAX_LOGGED_TIMES-1)]; + int sleepTime = ( lt->afterSleep - lt->enterFrame ) >> 7; + int activeTime = ( lt->beforeSwap - lt->afterSleep ) >> 7; + int swapTime = ( lt->afterSwap - lt->beforeSwap ) >> 7; + R_Draw_Fill( 0, i * 4, activeTime, 2, activeColor ); + R_Draw_Fill( activeTime, i * 4, swapTime, 2, swapColor ); + R_Draw_Fill( activeTime + swapTime, i * 4, sleepTime, 2, sleepColor ); + + R_Draw_Fill( 480 - lt->numGameTics * 10, i * 4, lt->numGameTics * 10, 2, ticColor ); + R_Draw_Fill( 480 - lt->numPingTics * 10, i * 4+2, lt->numPingTics * 10, 2, swapColor ); + } +} + + +/* +================== +iphoneHighlightPicWhenTouched + +Draw transparent except when touched +================= +*/ +void iphoneHighlightPicWhenTouched( pkTexture_t *texture, int x, int y, int w, int h ) { + if ( TouchDown( x, y, w, h ) ) { + glColor4f(1,1,1,1); + } else { + glColor4f(1,1,1,0.5); + } + PK_StretchTexture( texture, x, y, w, h ); + glColor4f(1,1,1,1); +} + + +/* + ================== + iphoneSetNotifyText + + Notify text is a single centered line for "got a key", "found a secret", etc + ================== + */ +char notifyText[128]; +int notifyFrameNum; +void iphoneSetNotifyText( const char *str, ... ) { + va_list argptr; + + if ( !messages->value ) { + // option to disable all the message prints + return; + } + va_start( argptr, str ); + (void)vsnprintf( notifyText, sizeof( notifyText )-1, str, argptr ); + va_end( argptr ); + + notifyFrameNum = iphoneFrameNum; +} + +void iphoneDrawNotifyText() { + if ( notifyFrameNum == 0 ) { + return; + } + // display for three seconds, then fade over 0.3 + float f = iphoneFrameNum - notifyFrameNum - 80; + if ( f < 0 ) { + f = 1.0; + } else { + f = 1.0 - f * 0.1f; + if ( f < 0 ) { + notifyFrameNum = 0; + return; + } + } + + glColor4f( 1, 1, 1, f ); + iphoneCenterText( 240, 16, 0.75, notifyText ); + glColor4f( 1, 1, 1, 1 ); +} + + +/* + ================== + Rotor control + + ================== + */ +void iphoneDrawRotorControl( ibutton_t *hud ) { + if ( hud->buttonFlags & BF_IGNORE ) { + return; + } + pkTexture_t *tex = hud->texture; + PK_BindTexture( tex ); + + float cx = hud->x + hud->drawWidth / 2; + float cy = hud->y + hud->drawHeight / 2; + float as = sin( hud->drawState ); + float ac = cos( hud->drawState ); + float sz = hud->drawWidth / 2; + + float xv[2] = { sz*ac, sz*as }; + float yv[2] = { -sz*as, sz*ac }; + + glColor4f( 1, 1, 1, 1 ); + + glBegin( GL_TRIANGLE_STRIP ); + + glTexCoord2f( 0.0f, 0.0f ); glVertex2f( cx - xv[0] - yv[0], cy - xv[1] - yv[1] ); + glTexCoord2f( tex->textureData->maxS, 0.0f ); glVertex2f( cx + xv[0] - yv[0], cy + xv[1] - yv[1] ); + glTexCoord2f( 0.0f, tex->textureData->maxT ); glVertex2f( cx - xv[0] + yv[0], cy - xv[1] + yv[1] ); + glTexCoord2f( tex->textureData->maxS, tex->textureData->maxT ); glVertex2f( cx + xv[0] + yv[0], cy + xv[1] + yv[1] ); + + glEnd(); +} + +//=================================================================================== + + + + +void iphoneDrawHudControl( ibutton_t *hud ) { + if ( hud->buttonFlags & BF_IGNORE ) { + return; + } + if ( !hud->texture ) { + return; + } + if ( hud->drawAsLimit ) { + // green tint when at maximum displacement + glColor4f(0.5,1,0.5,1); + } else if ( hud->touch || ( hud->buttonFlags & BF_DRAW_ACTIVE ) ) { + // red tint when active + glColor4f(1,0.5,0.5,1); + } else { + glColor4f(1,1,1,1); + } + if ( hud->scale <= 0 ) { + hud->scale = 1.0f; + } + float w = hud->drawWidth * hud->scale; + float h = hud->drawHeight * hud->scale; + float x = hud->x + ( hud->drawWidth - w ) * 0.5f; + float y = hud->y + ( hud->drawHeight - w ) * 0.5f; + + if ( centerSticks->value && hud->touch ) { + // reposiition the control after each touch + x = hud->touch->x - w*0.5f; + y = hud->touch->y - h*0.5f; + } + PK_StretchTexture( hud->texture, x, y, w, h ); + glColor4f(1,1,1,1); +} + +bool NewTextButton( ibutton_t *b, const char *title, int x, int y, int w, int h ) { + if ( !b->texture ) { + const char *pic = (w>128 ? "iphone/long_string_box.tga" : "iphone/short_string_box.tga" ); + SetButtonPicsAndSizes( b, pic, "", x, y, w, h ); + b->buttonFlags = BF_DIMMED | BF_CENTERTEXT; + } + b->title = title; + return HandleButton( b ); +} + +/* + ===================================================================== + + Smart USE test -- determine if there is a usable line within range + of the player. This is done by the main thread after running a game tic, + the async thread just checks the flag, because calling the traverse + functions is not thread safe. + + ===================================================================== +*/ + +static boolean usableInRange; + +boolean PTR_UseTestTraverse (intercept_t* in) +{ + if (!in->d.line->special) + { + P_LineOpening (in->d.line); + if (openrange <= 0) + { + // can't use through a wall + return false; + } + + // not a special line, but keep checking + + return true; + } + + player_t* player = &players[consoleplayer]; + int side = 0; + if (P_PointOnLineSide (player->mo->x, player->mo->y, in->d.line) == 1) + side = 1; + + // e6y + // b.m. side test was broken in boom201 + if ((demoplayback ? (demover != 201) : (compatibility_level != boom_201_compatibility))) + if (side) //jff 6/1/98 fix inadvertent deletion of side test + return false; + + if ( in->d.line->special == 76 ) { + // The button that opens the final door at E1M6 has a trigger line + // right in front of it, which causes the use button to go down without + // doing anything, and it gets held down as you close to the actual + // button, so it doesn't get activated. You could turn to face the wall + // to get the use button up, then turn back towards the button, but it + // feels totally broken. The correct solution would be to return false + // for all line specials that won't actually be player-usable, but I can't + // tell if that is a simple range or a huge scattered list. For now, this + // hack to ignore this particular line type solves the problem. We'll + // see if other levels have similar issues... + return false; + } + if ( in->d.line->special == 88 ) { // yellow door above plat on E1M6 + return false; + } + + + // this is a reasonable target for use + usableInRange = true; + + //WAS can't use for than one special line in a row + //jff 3/21/98 NOW multiple use allowed with enabling line flag + + return (!demo_compatibility && (in->d.line->flags&ML_PASSUSE))? + true : false; +} + +boolean P_TestUseLines() +{ + int angle; + fixed_t x1; + fixed_t y1; + fixed_t x2; + fixed_t y2; + + player_t* player = &players[consoleplayer]; + if ( !player->mo ) { + return false; // at intermission + } + angle = player->mo->angle >> ANGLETOFINESHIFT; + + x1 = player->mo->x; + y1 = player->mo->y; + x2 = x1 + (USERANGE>>FRACBITS)*finecosine[angle]; + y2 = y1 + (USERANGE>>FRACBITS)*finesine[angle]; + + // itterate over the lines and run the callback function + usableInRange = false; + P_PathTraverse ( x1, y1, x2, y2, PT_ADDLINES, PTR_UseTestTraverse ); + return usableInRange; +} + +//===================================================================== + +/* + ================== + AutomapControls + + This is strictly client-side, done in the game thread instead of the async thread + ================== + */ +void AutomapControls() { + //------------------------ + // automap controls + //------------------------ + extern fixed_t m_x, m_y; // LL x,y window location on the map (map coords) + extern fixed_t m_x2, m_y2; // UR x,y window location on the map (map coords) + + // width/height of window on map (map coords) + extern fixed_t m_w; + extern fixed_t m_h; + + // used by MTOF to scale from map-to-frame-buffer coords + extern fixed_t scale_mtof; + // used by FTOM to scale from frame-buffer-to-map coords (=1/scale_mtof) + extern fixed_t scale_ftom; + + extern fixed_t min_scale_mtof; // used to tell when to stop zooming out + extern fixed_t max_scale_mtof; // used to tell when to stop zooming in + + static int prevX = -1, prevY = -1; + + // any touch not down in another control will + // drag-scroll and be claimed by the automap + int touchCount = 0; + touch_t *mapTouch[MAX_TOUCHES]; + for ( int i = 0 ; i < MAX_TOUCHES ; i++ ) { + touch_t *t = &gameTouches[i]; + if ( t->down ) { + if ( t->controlOwner == NULL || t->controlOwner == OWNER_AUTOMAP ) { + // claim it so dragging onto another control won't + // cause it to activate + t->controlOwner = OWNER_AUTOMAP; + mapTouch[touchCount] = t; + touchCount++; + } + } + } + if ( touchCount != 1 ) { + prevX = -1; + } + static int pinching; + if ( touchCount != 2 ) { + pinching = 0; + } + if ( touchCount == 1 ) { + // adjust the automap values, assume square aspect ratio + touch_t *t = mapTouch[0]; + // drag position + if ( prevX == -1 ) { + prevX = t->x; + prevY = t->y; + } + m_x -= ( t->x - prevX ) * (float)m_w / displaywidth; + m_y += ( t->y - prevY ) * (float)m_w / displaywidth; + m_x2 = m_x + m_w; + m_y2 = m_y + m_h; + + prevX = t->x; + prevY = t->y; + } else if ( touchCount == 2 ) { + // pinch scale + touch_t *t1 = mapTouch[0]; + touch_t *t2 = mapTouch[1]; + static float baseDist; + static float baseMtoF; + static int basem_w; + static int basem_h; + float dist = sqrt( (t2->x-t1->x)*(t2->x-t1->x)+(t2->y-t1->y)*(t2->y-t1->y) ); + if ( !pinching ) { + pinching = 1; + baseDist = dist; + baseMtoF = scale_mtof; + basem_w = m_w; + basem_h = m_h; + } + scale_mtof = baseMtoF * dist / baseDist; + if ( scale_mtof < min_scale_mtof ) { + scale_mtof = min_scale_mtof; + dist = (float)min_scale_mtof * baseDist / baseMtoF; + } else if ( scale_mtof > max_scale_mtof ) { + scale_mtof = max_scale_mtof; + dist = (float)max_scale_mtof * baseDist / baseMtoF; + } + scale_ftom = FixedDiv(FRACUNIT, scale_mtof); + + float midx = (t2->x+t1->x)*0.5; + float midy = (t2->y+t1->y)*0.5; + float midxDoom = m_x + m_w * midx / displaywidth; + float midyDoom = m_y + m_w * midy / displaywidth; + m_w = basem_w * baseDist / dist; + m_h = basem_h * baseDist / dist; + m_x = midxDoom - m_w * midx / displaywidth; + m_y = midyDoom - m_w * midy / displaywidth; + m_x2 = m_x + m_w; + m_y2 = m_y + m_h; + } + +} + +void SwapBuffersAndTouches() { + // debug graphs + ShowTilt(); + ShowTime(); + ShowNet(); + ShowSound(); + + for ( int i = 0 ; i < MAX_TOUCHES ; i++ ) { + if ( sysTouches[i].down && gameTouches[i].down ) { + sysTouches[i].controlOwner = gameTouches[i].controlOwner; + } + } + + loggedTimes[iphoneFrameNum&(MAX_LOGGED_TIMES-1)].beforeSwap = SysIphoneMicroseconds(); + SysIPhoneSwapBuffers(); + int now = SysIphoneMicroseconds(); + loggedTimes[iphoneFrameNum&(MAX_LOGGED_TIMES-1)].afterSwap = now; +} + +float weaponSelectDrawScale = 1.25f; +void DrawWeapon(int weaponlump, int x, int y, int w, int h, int lightlevel) +{ + GLTexture *gltexture; + float fU1,fU2,fV1,fV2; + int x1,y1,x2,y2; + + if( displaywidth >= 960 ) { + weaponSelectDrawScale = 1.25f; + } else { + weaponSelectDrawScale = 0.75f; + } + + x *= ((float)displaywidth) / 480.0f; + y *= ((float)displayheight) / 320.0f; + w *= ((float)displaywidth) / 480.0f; + h *= ((float)displayheight) / 320.0f; + + // force doom to rebind, since we have changed the active GL_TEXTURE_2D + last_gltexture = NULL; + + gltexture=gld_RegisterPatch(firstspritelump+weaponlump, CR_DEFAULT); + if (!gltexture) + return; + + float scaledWidth = gltexture->width * weaponSelectDrawScale; + float scaledHeight = gltexture->height * weaponSelectDrawScale; + + // pin the middle bottom of the patch to the middle bottom of + // the draw rectangle, then let everything else scale as needed + fU1=0; + fV1=0; + fU2=(float)gltexture->width/(float)gltexture->tex_width; + fV2=(float)gltexture->height/(float)gltexture->tex_height; + x1=x+(w-scaledWidth)*0.5; + x2=x1 + scaledWidth; + y1=y+h-scaledHeight; + y2=y+h;; + + gld_BindPatch(gltexture, CR_DEFAULT); + + glColor4f( lightlevel, lightlevel, lightlevel, 1 ); + + glBegin(GL_TRIANGLE_STRIP); + glTexCoord2f(fU1, fV1); glVertex2f((float)(x1),(float)(y1)); + glTexCoord2f(fU1, fV2); glVertex2f((float)(x1),(float)(y2)); + glTexCoord2f(fU2, fV1); glVertex2f((float)(x2),(float)(y1)); + glTexCoord2f(fU2, fV2); glVertex2f((float)(x2),(float)(y2)); + glEnd(); + + glColor4f(1.0f,1.0f,1.0f,1.0f); +} + + +/* + ================== + DrawWeaponSelect + + ================== + */ +static const char *weaponNames[9] = { +"fist", +"pistol", +"shotgun", +"chaingun", +"rockets", +"plasma", +"BFG", +"chainsaw", +"dblshotgun" +}; +int weaponSprites[9] = { +SPR_PUNG, +SPR_PISG, +SPR_SHTG, +SPR_CHGG, +SPR_MISG, +SPR_PLSG, +SPR_BFGG, +SPR_SAWG, +SPR_SHT2 +}; + +void DrawWeaponSelect() { + player_t *player = &players[consoleplayer]; + + for ( int i = wp_fist ; i <= wp_supershotgun ; i++ ) { + int bx = i % 3; + int by = i / 3; + color4_t color = { 0, 0, 255, 200 }; + color4_t textColor = { 255, 255, 255, 255 }; + boolean selectable = false; + int ammo = -1; + switch ( i ) { + case wp_pistol: ammo = player->ammo[am_clip]; break; + case wp_shotgun: ammo = player->ammo[am_shell]; break; + case wp_chaingun: ammo = player->ammo[am_clip]; break; + case wp_missile: ammo = player->ammo[am_misl]; break; + case wp_plasma: ammo = player->ammo[am_cell]; break; + case wp_bfg: ammo = player->ammo[am_cell]; if ( ammo < 40 ) ammo = 0; break; + case wp_supershotgun: ammo = player->ammo[am_shell]; if ( ammo < 2 ) ammo = 0; break; + + + // These cases were here originally - but they feel buggy. + /* + case wp_plasma: ammo = player->ammo[wp_plasma]; break; + case wp_bfg: ammo = player->ammo[wp_plasma]; if ( ammo < 40 ) ammo = 0; break; + case wp_supershotgun: ammo = player->ammo[wp_plasma]; if ( ammo < 2 ) ammo = 0; break; + */ + } + if ( !player->weaponowned[i] ) { + // don't have the weapon + color[0] = color[1] = color[2] = 50; + textColor[3] = 128; + } else { + // selectable + color[0] = 255; color[1] = 255; color[2] = 255; color[3] = 255; + selectable = true; + + if ( ammo == 0 ) { + // have it, but out of ammo + color[0] = 255; color[1] = color[2] = 0; + textColor[3] = 128; + } + } + + int x = bx * 160 + 20; + int y = by * 88; + int w = 120; + int h = 80; + + float nx = x * ((float)displaywidth) / 480.0f; + float ny = y * ((float)displayheight) / 320.0f; + float nw = w * ((float)displaywidth) / 480.0f; + float nh = h * ((float)displayheight) / 320.0f; + + if ( selectable && TouchDown( nx, ny, nw, nh ) ) { + color[0] = 128; + color[1] = color[2] = 128; + color[3] = 200; + } + + glColor4ubv( color ); + + + + + PK_StretchTexture( PK_FindTexture( "iphone/multi_backdrop.tga" ), nx, ny, nw, nh ); +// R_Draw_Blend( x, y, w, h, color ); + + glColor4ubv( textColor ); + iphoneCenterText( x + w/2, y+16, 0.75, weaponNames[i] ); + + // draw the weapon sprite full color if available or black if not + + spritedef_t *sprdef = &sprites[weaponSprites[i]]; + if ( sprdef->spriteframes ) { // restricted wads won't have all weapons + spriteframe_t *sprframe = &sprdef->spriteframes[0]; + DrawWeapon( sprframe->lump[0] , x, y - 2, w, h, player->weaponowned[i] ); + + if ( selectable && TouchReleased( nx, ny, nw, nh ) ) { + drawWeaponSelect = false; + weaponSelected = i; + } + } + } +} + +/* + ================== + iphoneFrame + + This is continuously called by the game thread main loop, any sleeping + is done explicitly. If the game isn't holding 30hz, it will be running + flat out with no sleeping at all. + ================== + */ +void iphoneFrame() { + iphoneFrameNum++; + loggedTimes[iphoneFrameNum&(MAX_LOGGED_TIMES-1)].numGameTics = 0; + loggedTimes[iphoneFrameNum&(MAX_LOGGED_TIMES-1)].afterSleep = + loggedTimes[iphoneFrameNum&(MAX_LOGGED_TIMES-1)].enterFrame = SysIphoneMicroseconds(); + + //------------------------------------------------- + // grabs the console command under mutex. + //------------------------------------------------- + + // execute a console command if one was typed + if ( consoleCommand[0] ) { + // send it a character at a time to the classic dooom cheat processing + // for idkfa, idclev, etc + for ( int i = 0 ; consoleCommand[i] != 0 ; i++ ) { + M_FindCheats( consoleCommand[i] ); + } + + // send it to the new concole command processing + Com_Printf( "%s\n", consoleCommand ); + Cmd_ExecuteString( consoleCommand ); + consoleCommand[0] = 0; + } + + // move touches to prevTouches (old style use, remove...) + numPrevTouches = numTouches; + memcpy( prevTouches, touches, sizeof( prevTouches ) ); + + // process old style touches + numTouches = 0; + for ( int i = 0 ; i < MAX_TOUCHES ; i++ ) { + touch_t *t = &gameTouches[i]; + if ( t->down ) { + touches[numTouches][0] = t->x; + touches[numTouches][1] = t->y; + numTouches++; + } + } + + // go to the next demo if needed + if ( advancedemo ) { + if ( iphoneTimeDemo && timeDemoStart ) { + // go back to the menu after a timedemo + menuState = IPM_MAIN; + timeDemoStart = 0; + iphoneMainMenu(); + return; + } + static int demoState; + players[consoleplayer].playerstate = PST_LIVE; /* not reborn */ + advancedemo = usergame = paused = false; + gameaction = ga_nothing; + gamestate = GS_DEMOSCREEN; + static const char *demoNames[3] = { "demo1", "demo2", "demo3" }; + G_DeferedPlayDemo( demoNames[demoState] ); + if ( ++demoState == 3 ) { + demoState = 0; + } + } + + if ( saveOnExitState == 1 ) { + printf( "SaveOnExitState == 1\n" ); + if ( !netgame && !demoplayback && usergame && gamestate == GS_LEVEL ) { + G_SaveGame( 0, "quicksave" ); + G_DoSaveGame(true); + } + saveOnExitState = 2; + return; + } + + if ( saveOnExitState == 2 ) { + // the app is exiting + return; + } + + //-------------------------------------------------------------------------------------- + // game tic processing + //-------------------------------------------------------------------------------------- + boolean runGame = false; + + if( inBackgroundProcess ) { + return; + } + + if ( menuState == IPM_GAME ) { + // don't run the game when in the menus + runGame = true; + } + if ( automapmode & am_active ) { + // Unlike PC Doom, don't run time when in the automap, since + // drawing the controls clutters the screen too much. + runGame = false; + } + if ( netgame ) { + // even when in the menus or automap, the tics must be processed if it is a net game + runGame = true; + } + + if ( netGameFailure ) { + // consistancy failure or interruption + runGame = false; + } + + // since we don't allow movement control in the automap, + // don't advance time. + if ( runGame ) { + int stopTic; + + // block until the AsyncTic() has said we can run at least one frame, + // unless we are doing a flat-out timedemo run + if ( iphoneTimeDemo ) { + stopTic = gametic+1; + maketic = stopTic+1; + } else { + + + loggedTimes[iphoneFrameNum&(MAX_LOGGED_TIMES-1)].afterSleep = SysIphoneMicroseconds(); + if ( localGameID == gameID ) { + loggedTimes[iphoneFrameNum&(MAX_LOGGED_TIMES-1)].numPingTics = netPlayers[1].peer.currentPingTics; + } else { + loggedTimes[iphoneFrameNum&(MAX_LOGGED_TIMES-1)].numPingTics = netServer.currentPingTics; + } + + // On the server, we always want to execute all available tics. + // For a remote client, that would also give the minimum lag, but things are much + // smoother if they instead try to leave one buffer tic, unless that would + // leave the frame without running a single gametic. + stopTic = maketic; + if ( consoleplayer != 0 ) { + // we are a client, so try to leave a buffer frame + static const int COMMAND_BUFFER_SIZE = 1; + + stopTic = maketic - COMMAND_BUFFER_SIZE; + + if ( gametic >= stopTic ) { + // Ideally, clients should run 1 gametic per frame. But if the client is + // waiting on the server to deliver more tics, the client has to stall + // if it runs out of buffered tics. + const int idealTic = gametic + 1; + + if ( idealTic < maketic ) { + stopTic = idealTic; + } else { + stopTic = maketic; + } + } + } + } + + //--------------------------------- + // run game tics + //--------------------------------- + while( gametic < stopTic ) { + // run the gametic with all the player and monster logic + // this will extract netcmds[player][gametic%BACKUPTICS] for each player +// Com_Printf( "gametic %i\n", gametic ); + G_Ticker(); + + // if we just respawned with add-gear, give items now + if ( addGear ) { + players[0].weaponowned[wp_shotgun] = true; + players[0].ammo[am_shell] = 20; + players[0].pendingweapon = wp_shotgun; + addGear = false; + } + + // show the network trouble icon if we haven't run a game tic in a long time + lastGameProcessedTime = SysIphoneMilliseconds(); + + // see if there is a usable line in front of the player right now, + // which can be picked up by the asyncTic + autoUseActive = P_TestUseLines(); + + // generate the checksum for consistency failure testing + P_Checksum(gametic); + + // on to the next tic + loggedTimes[iphoneFrameNum&(MAX_LOGGED_TIMES-1)].numGameTics++; + gametic++; + + // this probably doesn't need to be tic-synced, but it doesn't hurt + if (players[displayplayer].mo) { + // move positional sounds and free up channels that have completed + S_UpdateSounds(players[displayplayer].mo); + } + } + } + + + if ( consoleActive ) { + iphoneSet2D(); + // FIXME: actually draw a console... + // Console_Draw(); + SwapBuffersAndTouches(); + return; + } + if ( menuState != IPM_GAME ) { + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + iphoneSet2D(); + + if ( menuState == IPM_HUDEDIT ) { + HudEditFrame(); + } + + SwapBuffersAndTouches(); + + return; + } + + //------------------ + // any touch release during demo playback goes to main menu + //------------------ + if ( !usergame && !iphoneTimeDemo ) { + if ( numTouches == 0 && numPrevTouches == 1 ) { + menuState = IPM_MAIN; + iphoneMainMenu(); + } + } + + if( inBackgroundProcess ) { + return; + } + + // Draw the game screen. This can also be called by the pacifier update + // during level loading. + iphoneDrawScreen(); + + // If we just loaded a level, do the texture precaching after we + // have drawn and displayed the first frame, so the user has + // something to look at while it is loading. + if ( false ) { // iphoneFrameNum == levelLoadFrameNum + 1 ) { + int start = SysIphoneMilliseconds(); + gld_Precache(); + int end = SysIphoneMilliseconds(); + Com_Printf( "%3.1f seconds to gld_Precache()\n", (end-start)*0.001f ); + timeDemoStart = end; + timeDemoFrames = 0; + } +} + +int pacifierCycle; +int pacifierTime; + +void iphonePacifierUpdate() { + // Only update a few times a second so it doesn't actually make it + // take longer to load. + int now = SysIphoneMilliseconds(); + if ( now < pacifierTime + 200 ) { + return; + } + pacifierTime = now; + pacifierCycle = ( pacifierCycle + 1 ) & 7; + + // Is this causing a massive slowdown while precaching? + iphoneDrawScreen(); +} + +/* + ================== + iphoneDrawScreen + + Called by the main loop and also during pacifier update when preloading textures + ================== + */ +void iphoneDrawScreen() { + // tell the classic code about turning the status bar on or off + if ( statusBar->modified ) { + statusBar->modified = false; + + if ( statusBar->value ) { + R_SetViewSize( 10 ); + } else { + R_SetViewSize( 11 ); + } + } + + //------------------------------------------------ + // Update display with current state. + //------------------------------------------------ + + // force doom to rebind, since we have changed the active GL_TEXTURE_2D + last_gltexture = NULL; + + D_Display(); + + iphoneSet2D(); + + //----------------------------------- + // draw 2D overlays for game screen + //----------------------------------- + if ( automapmode & am_active ) { + if ( HandleButton( &huds.map ) ) { + AM_Stop(); + } + if ( !netgame ) { // no save game option during net play + static ibutton_t btnSave; + if ( NewTextButton( &btnSave, "SAVE", 480-64, 0, 64, 32 ) ) { + G_SaveGame( 0, "ManualSave" ); + G_DoSaveGame(true); + AM_Stop(); + } + } + // update scroll and zoom after the buttons have potentially claimed a touch + AutomapControls(); + } else if ( iphoneFrameNum == levelLoadFrameNum + 1 ) { + // don't draw hud elements during the precache + color4_t black = { 0, 0, 0, 255 }; + R_Draw_Fill( 0, 0, 480, 320, black ); + + + // draw rotating pacifier icon + PK_BindTexture( PK_FindTexture( "iphone/loading.tga" ) ); + glColor4f( 1, 1, 1, 1 ); + + float cx = 240 * ((float)displaywidth) / 480.0f; + float cy = 160 * ((float)displayheight) / 320.0f; + float as = sin( pacifierCycle * M_PI / 4 ); + float ac = cos( pacifierCycle * M_PI / 4 ); + float sz = 64; + + float xv[2] = { sz*ac, sz*as }; + float yv[2] = { -sz*as, sz*ac }; + + glBegin( GL_TRIANGLE_STRIP ); + + glTexCoord2f( 0, 0 ); glVertex2f( cx - xv[0] - yv[0], cy - xv[1] - yv[1] ); + glTexCoord2f( 1, 0 ); glVertex2f( cx + xv[0] - yv[0], cy + xv[1] - yv[1] ); + glTexCoord2f( 0, 1 ); glVertex2f( cx - xv[0] + yv[0], cy - xv[1] + yv[1] ); + glTexCoord2f( 1, 1 ); glVertex2f( cx + xv[0] + yv[0], cy + xv[1] + yv[1] ); + + glEnd(); + } else { + // normal gameplay + if ( gamestate == GS_FINALE ) { + // leave the main menu button on the screen so they can start the + // next episode + if ( HandleButton( &huds.menu ) ) { + iphonePauseMusic(); + menuState = IPM_MAIN; + iphoneMainMenu(); + } + } else if ( !menuactive && !demoplayback && usergame && gamestate == GS_LEVEL ) { + if ( players[consoleplayer].playerstate == PST_DEAD ) { + // when dead, only show the main menu con and the + // respawn / load game icons + if ( HandleButton( &huds.menu ) ) { + iphonePauseMusic(); + menuState = IPM_MAIN; + iphoneMainMenu(); + } + if ( !deathmatch && !netgame ) { + static ibutton_t btnSaved; + static ibutton_t btnRespawn; + static ibutton_t btnGear; + + if ( !btnSaved.texture ) { + // initial setup + SetButtonPicsAndSizes( &btnSaved, "iphone/load_saved.tga", "Saved game", 240 - 48 - 96 - 48, 80, 96, 96 ); + SetButtonPicsAndSizes( &btnRespawn, "iphone/respawn.tga", "Restart", 240 - 48, 80, 96, 96 ); + SetButtonPicsAndSizes( &btnGear, "iphone/respawn_gear.tga", "Add gear", 240 + 48 + 48, 80, 96, 96 ); + } + + if ( HandleButton( &btnSaved ) ) { + StartSaveGame(); + } + if ( HandleButton( &btnRespawn ) ) { + players[consoleplayer].playerstate = PST_REBORN; + } + if ( HandleButton( &btnGear ) ) { + players[consoleplayer].playerstate = PST_REBORN; + addGear = true; + } + } else { + static ibutton_t btnNetRespawn; + if ( !btnNetRespawn.texture ) { + // initial setup + SetButtonPicsAndSizes( &btnNetRespawn, "iphone/respawn.tga", "Respawn", 240 - 96/2, 90, 96, 96 ); + } + if ( HandleButton( &btnNetRespawn ) ) { + // this will cause the next command sent to include a use action, + // then clear this flag + respawnActive = true; + } + } + } else if ( drawWeaponSelect ) { + DrawWeaponSelect(); + } else { + if ( drawControls->value ) { + iphoneDrawHudControl( &huds.forwardStick ); + iphoneDrawHudControl( &huds.sideStick ); + iphoneDrawHudControl( &huds.turnStick ); + iphoneDrawRotorControl( &huds.turnRotor ); +// iphoneDrawHudControl( &huds.fire ); + } + + if ( HandleButton( &huds.menu ) ) { + iphonePauseMusic(); + menuState = IPM_MAIN; + iphoneMainMenu(); + } + if ( HandleButton( &huds.map ) ) { + AM_Start(); + } + if ( HandleButton( &huds.fire ) ) { + } + + if ( netgame ) { +#if 0 + static ibutton_t btnPlayer; + if ( NewTextButton( &btnPlayer, "PLAYER", 0, 48, 100, 32 ) ) { + displayplayer ^= 1; + } + + static ibutton_t btnNet; + if ( NewTextButton( &btnNet, "NET", 240-32, 0, 80, 32 ) ) { + showNet->value = !showNet->value; + } + static ibutton_t btnThrottle; + const char *title = throttle->value ? "Throttle:ON" : "Throttle:OFF"; + if ( NewTextButton( &btnThrottle, title, 0, 0, 128, 32 ) ) { + throttle->value = !throttle->value; + } +#endif + } + +#if 0 + static ibutton_t btnSpeeds; + if ( NewTextButton( &btnSpeeds, "SPEEDS", 240-32, 0, 80, 32 ) ) { + showTime->value = !showTime->value; + } + static ibutton_t btnTest; + if ( NewTextButton( &btnTest, "TEST", 0, 48, 70, 32 ) ) { + testNewRenderer = !testNewRenderer; + } +#endif + } + + // notify text last, so it is always on top and legible + iphoneDrawNotifyText(); + + // not getting network tics + const int timeSinceLastProcessed = SysIphoneMilliseconds() - lastGameProcessedTime; + if ( timeSinceLastProcessed > 800 ) { // Origianlly was 500, let's be a little more lenient for internet play. + PK_StretchTexture( PK_FindTexture("iphone/multiplay.tga"), 240 - 96/2, 90, 96, 96 ); + } + + // draw the little graph in the upper right corner +#ifndef NDEBUG + if ( netgame ) { + ShowMiniNet(); + } +#endif + } + } + + // update timedemo display + if ( iphoneTimeDemo ) { + if ( iphoneFrameNum > levelLoadFrameNum + 1 ) { + timeDemoFrames++; + float fps = timeDemoFrames * 1000.0f / ( SysIphoneMilliseconds() - timeDemoStart ); + sprintf( timeDemoResultString, "%5.1f fps", fps ); + } else { + strcpy( timeDemoResultString, "TIMEDEMO" ); + } + iphoneCenterText( 240, 80, 0.75, timeDemoResultString ); + } + + // time how long the GPU takes to render the entire frame + if ( glfinish->value ) { + int start = SysIphoneMicroseconds(); + glFinish(); + int end = SysIphoneMicroseconds(); + Com_Printf( "%4.1f msec for glFinish()\n", ( end - start ) * 0.001f ); + } + + SwapBuffersAndTouches(); +} diff --git a/common/ios/doomengine/iphone_main.c b/common/ios/doomengine/iphone_main.c new file mode 100755 index 0000000..b665c96 --- /dev/null +++ b/common/ios/doomengine/iphone_main.c @@ -0,0 +1,519 @@ +/* + + Copyright (C) 2004-2005 Michael Liebscher + Copyright (C) 1997-2001 Id Software, 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 + 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. + +*/ + + +/* + + doom + ---- + modifications to config.h + don't add the d_ipxgate.c file + don't add d_server.c file + don't add mmus2mid.[ch] files + don't add w_memcache.c, use w_mmap.c instead + added new SDL_opengl.h, changed code files from to "SDL_opengl.h" + commented out #include + + Commented out the static on D_DoomMainSetup(); + Add define HAVE_CONFIG_H to the target settings + Add define _DEBUG + + #if around uses of GL_TEXTURE_RESIDENT in gl_texture.c + // JDC: not in GLES, not needed since it is the default condition glDisable(GL_POLYGON_SMOOTH); + + // JDC #define USE_VERTEX_ARRAYS in gl_main.c + + add the iphoneRotateForLandscape calls + +static JDC removed short consistancy[MAXPLAYERS][BACKUPTICS]; + + // JDC glDisableClientState(GL_TEXTURE_COORD_ARRAY); + // JDC glDisableClientState(GL_VERTEX_ARRAY); + #ifdef IPHONE // JDC + #define MAX_SCREENWIDTH 480 + #define MAX_SCREENHEIGHT 320 + #else + + + code notes + ---------- + all the fixed point mess + goofy polar clipping + path traverse should have used a BSP tree + + rename vldoor_e close and open enums to not conflict with unistd + + opengl_error_break + + + WiFi internet play + --------- + voip instead of key chat + + extra asset work + ---------------------- + perfect weapon scales + demo of each level? + additive art separation -- attacks, buttons, etc + + tuned option + ------------ + last kill / last secret / last item messages + more achievements in general + better item pickup sounds + scale blood spray with distance + easier item pickup + crosshair + better movement clipping to walls + better key pickup sound + textured automap + better low health warning + better feedback on where bullets hit + better bob cycle when going down stairs + map item should also show all monsters and items to make it cool + barrels explode easier + wave FOV when berzerk + pistol shots are useless in deathmatch + show opponent / enemy health when attacking them? + + + cpu optimizations + ------------- + convert to 16 bit vertex data + void gld_BindPatch(GLTexture *gltexture, int cm) is expensive + fixedMul / fixedDiv in asm (negligable performance gain) + atlas all of the non-character items (and bodies?) + remove the pitch changes from sound? + + gpu optimizations + ------------------ + use fog instead of full screen blend for damage/pickup flash (3 msec on IP3G) + pvrtc walls and floors + + art needed + ---------- + new map / menu button + awards on medals + icon + thumbsticks + settings gears + + + must do + ------- + pause music in menu + timelimit carry over to new levels + server going to demo causes client to crash + + fixed 10/13/09 + -------------- + recover from sound interruption + caps for slider bar text + reset defaults doesn't reset reverse-landscape + pause music when going to the menu + reset timelimit each level on deathmatch + disable demos, new game, and web site during multiplayer + + fixed + ----- + automap / menu button actions with multi-thread + capitalized "game saved." + Added punctuation to "Ned a blue keycard", etc + added "defaults" button in options + + todo + ---- + don't accept fire from an owned touch? + text scaling in buttons isn't perfect + better view angle transport + audio bugs + rotor control shouldn't be dimmed + volume button hack? + change background color for networking + tapping weapon change to cycle + is openal thread safe? we issue touch clicks from asynctic + disable multiplayer button if no ethernet addresses found + touch latching issues + add one tic latency to server? + select new game while in netgame + multiplayer arrow colors + remove players with stale joins + rocket explosion offset + texture preload status bar stuff and blood / impacts + stereo panning for headphones + directly build 16 bit textures instead of translating from 32 bit + texture wrap seam after end of e3m8 + sliders should be touch-latch controls + respawn flash sounds sometimes not playing? + don't allow starting on secret levels + loaded savegame spot on different level didn't get view height on first frame + use graphic? + don't ever close doors with auto-use + separators in map select + rotor speed adjust + check all powerup effects + remove uses of prboom.wad? + check patch outlining code + flash all controls on initial level load + touch sounds when cancelling demo playback + play sound on respawn + catch memory warning, purge textures + use wad sound data + stop sound cleanly + entire gun doesn't get fullbright with muzzle flash + require four touches in line for console + restartable pwad interface + somewhat normal based lighting on walls + help menu + visual tilt indicator + tilt draw the turnstick when active + console + + */ + +#include "doomiphone.h" + +cvar_t *freeLevelOfWeek; +cvar_t *skill; +cvar_t *episode; +cvar_t *controlScheme; +cvar_t *stickTurn; +cvar_t *stickMove; +cvar_t *stickDeadBand; +cvar_t *rotorTurn; +cvar_t *tiltTurn; +cvar_t *tiltMove; +cvar_t *tiltDeadBand; +cvar_t *tiltAverages; +cvar_t *miniNet; +cvar_t *music; +cvar_t *showTilt; +cvar_t *showTime; +cvar_t *showNet; +cvar_t *showSound; +cvar_t *cropSprites; +cvar_t *mapScale; +cvar_t *drawControls; +cvar_t *autoUse; +cvar_t *statusBar; +cvar_t *touchClick; +cvar_t *messages; +cvar_t *timeLimit; +cvar_t *fragLimit; +cvar_t *mpDeathmatch; +cvar_t *mpSkill; +cvar_t *mpDataset; +cvar_t *mpEpisode; +cvar_t *mpMap; +cvar_t *mpExpansion; +cvar_t *noBlend; +cvar_t *glfinish; +cvar_t *mapSelectY; +cvar_t *throttle; +cvar_t *centerSticks; +cvar_t *rampTurn; +cvar_t *netBuffer; + +#define VERSION_BCONFIG ( 0x89490000 + sizeof( huds ) + sizeof( playState ) ) + +void Sys_Error( const char *format, ... ) +{ + va_list argptr; + char string[ 1024 ]; + + va_start( argptr, format ); + (void)vsnprintf( string, sizeof( string ), format, argptr ); + va_end( argptr ); + + fprintf( stderr, "Error: %s\n", string ); + + _exit( 1 ); + +} + +#define plyr (players+consoleplayer) /* the console player */ + +void Give_f() { + + plyr->armorpoints = idfa_armor; // Ty 03/09/98 - deh + plyr->armortype = idfa_armor_class; // Ty 03/09/98 - deh + + // You can't own weapons that aren't in the game // phares 02/27/98 + for (int i=0;iweaponowned[i] = true; + + for (int i=0;iammo[i] = plyr->maxammo[i]; + + plyr->message = s_STSTR_FAADDED; + + for (int i=0;icards[i]) // only print message if at least one key added + { // however, caller may overwrite message anyway + plyr->cards[i] = true; + } +} + +void God_f() { + plyr->cheats ^= CF_GODMODE; + if (plyr->cheats & CF_GODMODE) + { + if (plyr->mo) + plyr->mo->health = god_health; // Ty 03/09/98 - deh + + plyr->health = god_health; + plyr->message = s_STSTR_DQDON; // Ty 03/27/98 - externalized + } + else + plyr->message = s_STSTR_DQDOFF; // Ty 03/27/98 - externalized +} + +void ResetMaps_f() { + playState.numMapStats = 0; + memset( playState.mapStats, 0, sizeof( playState.mapStats ) ); +} + +/* + ================== + iphoneStartup + + ================== + */ +struct addrinfo *addrinfoHead; + +void D_DoomMainSetup( const char * iwad, const char * pwad ); +void iphoneStartup() { + int start = SysIphoneMilliseconds(); + + // microseconds will be plenty random for playerID and localGameID + playerID = localGameID = SysIphoneMicroseconds(); + + InitImmediateModeGL(); + + // init OpenAL before pak file, so the pak file can + // make all the al static buffers + Sound_Init(); + + char buffer[1028]; + sprintf( buffer, "%s/base.iPack", SysIphoneGetAppDir() ); + // get our new-style pak file + PK_Init( buffer ); + + // register console commands + Cmd_AddCommand( "listcvars", Cvar_List_f ); + Cmd_AddCommand( "resetcvars", Cvar_Reset_f ); + Cmd_AddCommand( "resetmaps", ResetMaps_f ); + Cmd_AddCommand( "listcmds", Cmd_ListCommands_f ); + Cmd_AddCommand( "give", Give_f ); + Cmd_AddCommand( "god", God_f ); + Cmd_AddCommand( "mail", EmailConsole ); //gsh, mails the console to id + + // register console variables + Cvar_Get( "version", va( "%3.1f %s %s", DOOM_IPHONE_VERSION, __DATE__, __TIME__ ), 0 ); + + freeLevelOfWeek = Cvar_Get("freeLevelOfWeek", "0", 0 ); + skill = Cvar_Get( "skill", "1", CVAR_ARCHIVE ); + episode = Cvar_Get( "episode", "0", CVAR_ARCHIVE ); + + controlScheme = Cvar_Get( "controlScheme", "0", CVAR_ARCHIVE ); + stickTurn = Cvar_Get( "stickTurn", "128", CVAR_ARCHIVE ); + stickMove = Cvar_Get( "stickMove", "128", CVAR_ARCHIVE ); + stickDeadBand = Cvar_Get( "stickDeadBand", "0.05", CVAR_ARCHIVE ); + rotorTurn = Cvar_Get( "rotorTurn", "50000", CVAR_ARCHIVE ); + tiltTurn = Cvar_Get( "tiltTurn", "0", CVAR_ARCHIVE ); + tiltMove = Cvar_Get( "tiltMove", "0", CVAR_ARCHIVE ); + tiltDeadBand = Cvar_Get( "tiltDeadBand", "0.08", CVAR_ARCHIVE ); + tiltAverages = Cvar_Get( "tiltAverages", "3", CVAR_ARCHIVE ); + centerSticks = Cvar_Get( "centerSticks", "1", CVAR_ARCHIVE ); + rampTurn = Cvar_Get( "rampTurn", "1", CVAR_ARCHIVE ); + + music = Cvar_Get( "music", "1", CVAR_ARCHIVE ); + cropSprites = Cvar_Get( "cropSprites", "1", 0 ); + mapScale = Cvar_Get( "mapScale", "10", CVAR_ARCHIVE ); + drawControls = Cvar_Get( "drawControls", "1", CVAR_ARCHIVE ); + autoUse = Cvar_Get( "autoUse", "1", CVAR_ARCHIVE ); + statusBar = Cvar_Get( "statusBar", "1", CVAR_ARCHIVE ); + touchClick = Cvar_Get( "touchClick", "1", CVAR_ARCHIVE ); + messages = Cvar_Get( "messages", "1", CVAR_ARCHIVE ); + mapSelectY = Cvar_Get( "mapSelectY", "0", CVAR_ARCHIVE ); + miniNet = Cvar_Get( "miniNet", "1", CVAR_ARCHIVE ); + + // multiplayer setup + timeLimit = Cvar_Get( "timeLimit", "0", CVAR_ARCHIVE ); + fragLimit = Cvar_Get( "fragLimit", "5", CVAR_ARCHIVE ); + mpDeathmatch = Cvar_Get( "mpDeathmatch", "0", CVAR_ARCHIVE ); + mpDataset = Cvar_Get( "mpDataset", "0", CVAR_ARCHIVE ); + mpEpisode = Cvar_Get( "mpEpisode", "1", CVAR_ARCHIVE ); + mpSkill = Cvar_Get( "mpSkill", "1", CVAR_ARCHIVE ); + mpMap = Cvar_Get( "mpMap", "1", CVAR_ARCHIVE ); + mpExpansion = Cvar_Get( "mpExpansion", "0", CVAR_ARCHIVE | CVAR_NOSET ); + + // debug tools + showTilt = Cvar_Get( "showTilt", "-1", 0 ); + showTime = Cvar_Get( "showTime", "0", 0 ); + showNet = Cvar_Get( "showNet", "0", 0 ); + showSound = Cvar_Get( "showSound", "0", 0 ); + noBlend = Cvar_Get( "noBlend", "0", 0 ); // disable the damae blends for screenshots + glfinish = Cvar_Get( "glfinish", "0", 0 ); + throttle = Cvar_Get( "throttle", "0", 0 ); // network packet throttle enable + + // Was origiinally 4. Trying different values to help internet play. + netBuffer = Cvar_Get( "netBuffer", "12", 0 ); // max tics to buffer ahead + + // load the archived cvars + Cmd_ExecuteFile( va( "%s/config.cfg", SysIphoneGetDocDir() ) ); + + // start the intro music if it wasn't disabled with the music cvar + iphonePlayMusic( "intro" ); +// iphonePlayMusic( "e1m1" ); + + // these should get overwritten by the config loading + memset( &playState, 0, sizeof( playState ) ); + playState.map.skill = 1; + playState.map.episode = 1; + playState.map.map = 1; + HudSetForScheme( 0 ); + + // load the binary config file + FILE *f = fopen( va( "%s/binaryConfig.bin", SysIphoneGetDocDir() ), "rb" ); + if ( f ) { + int version; + + version = 0; + fread( &version, 1, sizeof( version ), f ); + if ( version != VERSION_BCONFIG ) { + Com_Printf( "Binary config file bad version.\n" ); + } else { + fread( &playState, 1, sizeof( playState ), f ); + fread( &huds, 1, sizeof( huds ), f ); + + version = 0; + fread( &version, 1, sizeof( version ), f ); + if ( version != VERSION_BCONFIG ) { + Com_Error( "Binary config file bad trailing version.\n" ); + } + } + fclose( f ); + } + + + Com_Printf( "startup time: %i msec\n", SysIphoneMilliseconds() - start ); + + start = SysIphoneMilliseconds(); + + // the texnums might have been different in the savegame + HudSetTexnums(); + + arialFontTexture = PK_FindTexture( "iphone/arialImageLAL.tga" ); + + Com_Printf( "preloadBeforePlay(): %i msec\n", SysIphoneMilliseconds() - start ); + + // prBoom seems to draw the static pic screens without setting up 2D, causing + // a bad first frame + iphoneSet2D(); + + menuState = IPM_MAIN; + lastState = IPM_MAIN; + +#if 0 + // jump right to the save spot for debugging + ResumeGame(); +#endif +} + +/* + ================== + iphoneDoomSetup + + Run the Doom game setup functions. This was made seperate from iphoneStartup so that the user + could select a mission pack first. + ================== + */ +void iphoneDoomStartup( const char * iwad, const char * pwad ) { + Com_Printf( "---------- D_DoomMain ----------\n" ); + D_DoomMainSetup( iwad, pwad ); + + // put savegames here + strcpy( basesavegame, SysIphoneGetDocDir() ); + +} + +/* + ================== + iphoneShutdown + + Write out configs and save the game at this position + ================== + */ +void iphoneShutdown() { + FILE *fp; + char path[1024]; + cvar_t *var; + char buffer[1024]; + + if( lastState == IPM_GAME && gamestate != GS_INTERMISSION && !demoplayback ) { + G_DoSaveGame( false ); + } + + // write the ascii config file + snprintf( path, sizeof( path ), "%s/config.cfg", SysIphoneGetDocDir() ); + fp = fopen( path, "w" ); + if( ! fp ) { + Com_Printf( "Could not write config.cfg.\n" ); + return; + } + + // write out commands to set the archived cvars + for( var = cvar_vars ; var ; var = var->next ) { + if( var->flags & CVAR_ARCHIVE ) { + snprintf( buffer, sizeof( buffer ), "%s %s\n", var->name, var->string ); + fprintf( fp, "%s", buffer ); + Com_Printf( "%s", buffer ); + } + } + + fclose( fp ); + + + // write the binary config file + FILE *f = fopen( va( "%s/binaryConfig.bin", SysIphoneGetDocDir() ), "wb" ); + if ( !f ) { + Com_Printf( "Could not write binaryConfig.cfg.\n" ); + return; + } + + int version = VERSION_BCONFIG; + + fwrite( &version, 1, sizeof( version ), f ); + + fwrite( &playState, 1, sizeof( playState ), f ); + fwrite( &huds, 1, sizeof( huds ), f ); + + fwrite( &version, 1, sizeof( version ), f ); + fclose( f ); + +} + + diff --git a/common/ios/doomengine/iphone_mapSelect.c b/common/ios/doomengine/iphone_mapSelect.c new file mode 100755 index 0000000..9d7ff90 --- /dev/null +++ b/common/ios/doomengine/iphone_mapSelect.c @@ -0,0 +1,236 @@ +/* + * iphone_mapSelect.c + * doom + * + * Created by John Carmack on 4/19/09. + * Copyright 2009 id Software. All rights reserved. + * + */ +/* + + Copyright (C) 2009 Id Software, 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 + 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 "doomiphone.h" + +typedef struct { + int dataset; + int episode; + int map; + const char *name; +} mapData_t; + +mapData_t mapData[] = { +{ 0, 1, 1, "E1M1: Hangar" }, +{ 0, 1, 2, "E1M2: Nuclear Plant" }, +{ 0, 1, 3, "E1M3: Toxin Refinery" }, +{ 0, 1, 4, "E1M4: Command Control" }, +{ 0, 1, 5, "E1M5: Phobos Lab" }, +{ 0, 1, 6, "E1M6: Central Processing" }, +{ 0, 1, 7, "E1M7: Computer Station" }, +{ 0, 1, 8, "E1M8: Phobos Anomaly" }, +{ 0, 1, 9, "E1M9: Military Base" }, + +{ 0, 2, 1, "E2M1: Deimos Anomaly" }, +{ 0, 2, 2, "E2M2: Containment Area" }, +{ 0, 2, 3, "E2M3: Refinery" }, +{ 0, 2, 4, "E2M4: Deimos Lab" }, +{ 0, 2, 5, "E2M5: Command Center" }, +{ 0, 2, 6, "E2M6: Halls of the Damned" }, +{ 0, 2, 7, "E2M7: Spawning Vats" }, +{ 0, 2, 8, "E2M8: Tower of Babel" }, +{ 0, 2, 9, "E2M9: Fortress of Mystery" }, + +{ 0, 3, 1, "E3M1: Hell Keep" }, +{ 0, 3, 2, "E3M2: Slough of Despair" }, +{ 0, 3, 3, "E3M3: Pandemonium" }, +{ 0, 3, 4, "E3M4: House of Pain" }, +{ 0, 3, 5, "E3M5: Unholy Cathedral" }, +{ 0, 3, 6, "E3M6: Mt. Erebus" }, +{ 0, 3, 7, "E3M7: Limbo" }, +{ 0, 3, 8, "E3M8: Dis" }, +{ 0, 3, 9, "E3M9: Warrens" }, + +{ 0, 4, 1, "E4M1: Hell Beneath" }, +{ 0, 4, 2, "E4M2: Perfect Hatred" }, +{ 0, 4, 3, "E4M3: Sever The Wicked" }, +{ 0, 4, 4, "E4M4: Unruly Evil" }, +{ 0, 4, 5, "E4M5: They Will Repent" }, +{ 0, 4, 6, "E4M6: Against Thee Wickedly" }, +{ 0, 4, 7, "E4M7: And Hell Followed" }, +{ 0, 4, 8, "E4M8: Unto The Cruel" }, +{ 0, 4, 9, "E4M9: Fear" }, + +#if 0 + +{ 0, 0, 0, "level 1: entryway" }, +{ 0, 0, 0, "level 2: underhalls" }, +{ 0, 0, 0, "level 3: the gantlet" }, +{ 0, 0, 0, "level 4: the focus" }, +{ 0, 0, 0, "level 5: the waste tunnels" }, +{ 0, 0, 0, "level 6: the crusher" }, +{ 0, 0, 0, "level 7: dead simple" }, +{ 0, 0, 0, "level 8: tricks and traps" }, +{ 0, 0, 0, "level 9: the pit" }, +{ 0, 0, 0, "level 10: refueling base" }, +{ 0, 0, 0, "level 11: 'o' of destruction!" }, +{ 0, 0, 0, "level 12: the factory" }, +{ 0, 0, 0, "level 13: downtown" }, +{ 0, 0, 0, "level 14: the inmost dens" }, +{ 0, 0, 0, "level 15: industrial zone" }, +{ 0, 0, 0, "level 16: suburbs" }, +{ 0, 0, 0, "level 17: tenements" }, +{ 0, 0, 0, "level 18: the courtyard" }, +{ 0, 0, 0, "level 19: the citadel" }, +{ 0, 0, 0, "level 20: gotcha!" }, +{ 0, 0, 0, "level 21: nirvana" }, +{ 0, 0, 0, "level 22: the catacombs" }, +{ 0, 0, 0, "level 23: barrels o' fun" }, +{ 0, 0, 0, "level 24: the chasm" }, +{ 0, 0, 0, "level 25: bloodfalls" }, +{ 0, 0, 0, "level 26: the abandoned mines" }, +{ 0, 0, 0, "level 27: monster condo" }, +{ 0, 0, 0, "level 28: the spirit world" }, +{ 0, 0, 0, "level 29: the living end" }, +{ 0, 0, 0, "level 30: icon of sin" }, +{ 0, 0, 0, "level 31: wolfenstein" }, +{ 0, 0, 0, "level 32: grosse" }, + +{ 0, 0, 0, "level 1: congo" }, +{ 0, 0, 0, "level 2: well of souls" }, +{ 0, 0, 0, "level 3: aztec" }, +{ 0, 0, 0, "level 4: caged" }, +{ 0, 0, 0, "level 5: ghost town" }, +{ 0, 0, 0, "level 6: baron's lair" }, +{ 0, 0, 0, "level 7: caughtyard" }, +{ 0, 0, 0, "level 8: realm" }, +{ 0, 0, 0, "level 9: abattoire" }, +{ 0, 0, 0, "level 10: onslaught" }, +{ 0, 0, 0, "level 11: hunted" }, +{ 0, 0, 0, "level 12: speed" }, +{ 0, 0, 0, "level 13: the crypt" }, +{ 0, 0, 0, "level 14: genesis" }, +{ 0, 0, 0, "level 15: the twilight" }, +{ 0, 0, 0, "level 16: the omen" }, +{ 0, 0, 0, "level 17: compound" }, +{ 0, 0, 0, "level 18: neurosphere" }, +{ 0, 0, 0, "level 19: nme" }, +{ 0, 0, 0, "level 20: the death domain" }, +{ 0, 0, 0, "level 21: slayer" }, +{ 0, 0, 0, "level 22: impossible mission" }, +{ 0, 0, 0, "level 23: tombstone" }, +{ 0, 0, 0, "level 24: the final frontier" }, +{ 0, 0, 0, "level 25: the temple of darkness" }, +{ 0, 0, 0, "level 26: bunker" }, +{ 0, 0, 0, "level 27: anti-christ" }, +{ 0, 0, 0, "level 28: the sewers" }, +{ 0, 0, 0, "level 29: odyssey of noises" }, +{ 0, 0, 0, "level 30: the gateway of hell" }, +{ 0, 0, 0, "level 31: cyberden" }, +{ 0, 0, 0, "level 32: go 2 it" }, + +{ 0, 0, 0, "level 1: system control" }, +{ 0, 0, 0, "level 2: human bbq" }, +{ 0, 0, 0, "level 3: power control" }, +{ 0, 0, 0, "level 4: wormhole" }, +{ 0, 0, 0, "level 5: hanger" }, +{ 0, 0, 0, "level 6: open season" }, +{ 0, 0, 0, "level 7: prison" }, +{ 0, 0, 0, "level 8: metal" }, +{ 0, 0, 0, "level 9: stronghold" }, +{ 0, 0, 0, "level 10: redemption" }, +{ 0, 0, 0, "level 11: storage facility" }, +{ 0, 0, 0, "level 12: crater" }, +{ 0, 0, 0, "level 13: nukage processing" }, +{ 0, 0, 0, "level 14: steel works" }, +{ 0, 0, 0, "level 15: dead zone" }, +{ 0, 0, 0, "level 16: deepest reaches" }, +{ 0, 0, 0, "level 17: processing area" }, +{ 0, 0, 0, "level 18: mill" }, +{ 0, 0, 0, "level 19: shipping/respawning" }, +{ 0, 0, 0, "level 20: central processing" }, +{ 0, 0, 0, "level 21: administration center" }, +{ 0, 0, 0, "level 22: habitat" }, +{ 0, 0, 0, "level 23: lunar mining project" }, +{ 0, 0, 0, "level 24: quarry" }, +{ 0, 0, 0, "level 25: baron's den" }, +{ 0, 0, 0, "level 26: ballistyx" }, +{ 0, 0, 0, "level 27: mount pain" }, +{ 0, 0, 0, "level 28: heck" }, +{ 0, 0, 0, "level 29: river styx" }, +{ 0, 0, 0, "level 30: last call" }, +{ 0, 0, 0, "level 31: pharaoh" }, +{ 0, 0, 0, "level 32: caribbean" }, + +#endif + +{ 0, 0, 0, NULL } + +}; + + +/* + =================== + FindMapStats + + Finds or creats a mapStats_t structure for the given level. + This can return NULL if the entire array is filled up, which may + happen when people have an absurd number of downloaded levels. + =================== + */ +mapStats_t *FindMapStats( int dataset, int theEpisode, int map, boolean create ) { + for ( int i = 0 ; i < playState.numMapStats ; i++ ) { + mapStats_t *ms = &playState.mapStats[i]; + if ( ms->dataset == dataset && ms->episode == theEpisode && ms->map == map ) { + return ms; + } + } + if ( playState.numMapStats == MAX_MAPS ) { + // all full. + return NULL; + } + + if ( !create ) { + return NULL; + } + mapStats_t *cms = &playState.mapStats[playState.numMapStats]; + cms->dataset = dataset; + cms->episode = theEpisode; + cms->map = map; + playState.numMapStats++; + + return cms; +} + +/* + ================== + FindMapName + + episodes and maps are one base + ================== + */ +const char *FindMapName( int dataset, int theEpisode, int map ) { + for ( mapData_t *md = mapData ; md->name ; md++ ) { + if ( md->dataset == dataset && md->episode == theEpisode && md->map == map ) { + return md->name; + } + } + return "UNKNOWN MAP NAME"; +} + diff --git a/common/ios/doomengine/iphone_net.c b/common/ios/doomengine/iphone_net.c new file mode 100755 index 0000000..ad9b967 --- /dev/null +++ b/common/ios/doomengine/iphone_net.c @@ -0,0 +1,631 @@ +/* + * iphone_net.c + * doom + * + * Created by John Carmack on 7/8/09. + * Copyright 2009 id Software. All rights reserved. + * + */ +/* + + Copyright (C) 2009 Id Software, 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 + 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. + + */ + + +/* + + Deal with all the DNS / bonjour service discovery and resolution + + */ + +#include "doomiphone.h" + +#include +#include // for gethostbyname +#include // for if_nameindex() + +DNSServiceRef browseRef; +DNSServiceRef clientServiceRef; +DNSServiceRef serviceRef; +boolean serviceRefValid; + +typedef struct { + int interfaceIndex; + char browseName[1024]; + char browseRegtype[1024]; + char browseDomain[1024]; +} service_t; + +boolean localServer; + +// we can find services on both WiFi and Bluetooth interfaces +#define MAX_SERVICE_INTEFACES 4 +service_t serviceInterfaces[MAX_SERVICE_INTEFACES]; + +boolean gotServerAddress; +struct sockaddr resolvedServerAddress; + +static const char *serviceName = "_DoomServer._udp."; + +int InterfaceIndexForName( const char *ifname ); + +void DNSServiceRegisterReplyCallback ( + DNSServiceRef sdRef, + DNSServiceFlags flags, + DNSServiceErrorType errorCode, + const char *name, + const char *regtype, + const char *domain, + void *context ) { + (void)sdRef; + (void)flags; + (void)name; + (void)regtype; + (void)domain; + (void)context; + + if ( errorCode == kDNSServiceErr_NoError ) { + localServer = true; + } else { + localServer = false; + } +} + +boolean RegisterGameService() { + DNSServiceErrorType err = DNSServiceRegister( + &serviceRef, + kDNSServiceFlagsNoAutoRename, // we want a conflict error + InterfaceIndexForName( "en0" ), // pass 0 for all interfaces + "iPhone Doom Classic", + serviceName, + NULL, // domain + NULL, // host + htons( DOOM_PORT ), + 0, // txtLen + NULL, // txtRecord + DNSServiceRegisterReplyCallback, + NULL // context + ); + + if ( err != kDNSServiceErr_NoError ) { + printf( "DNSServiceRegister error\n" ); + } else { + // block until we get a response, process it, and run the callback + err = DNSServiceProcessResult( serviceRef ); + if ( err != kDNSServiceErr_NoError ) { + printf( "DNSServiceProcessResult error\n" ); + } + } + return localServer; +} + +void TerminateGameService() { + if ( localServer ) { + localServer = false; + } + DNSServiceRefDeallocate( serviceRef ); + memset( serviceInterfaces, 0, sizeof( serviceInterfaces ) ); +} + +void DNSServiceQueryRecordReplyCallback ( + DNSServiceRef DNSServiceRef, + DNSServiceFlags flags, + uint32_t interfaceIndex, + DNSServiceErrorType errorCode, + const char *fullname, + uint16_t rrtype, + uint16_t rrclass, + uint16_t rdlen, + const void *rdata, + uint32_t ttl, + void *context ) { + (void)DNSServiceRef; + (void)flags; + (void)errorCode; + (void)rrtype; + (void)rrclass; + (void)ttl; + (void)context; + + assert( rdlen == 4 ); + const byte *ip = (const byte *)rdata; + char interfaceName[IF_NAMESIZE]; + if_indextoname( interfaceIndex, interfaceName ); + printf( "DNSServiceQueryRecordReplyCallback: %s, interface[%i] = %s, [%i] = %i.%i.%i.%i\n", + fullname, interfaceIndex, interfaceName, rdlen, ip[0], ip[1], ip[2], ip[3] ); + + ReportNetworkInterfaces(); + + memset( &resolvedServerAddress, 0, sizeof( resolvedServerAddress ) ); + struct sockaddr_in *sin = (struct sockaddr_in *)&resolvedServerAddress; + sin->sin_len = sizeof( resolvedServerAddress ); + sin->sin_family = AF_INET; + sin->sin_port = htons( DOOM_PORT ); + memcpy( &sin->sin_addr, ip, 4 ); + + gotServerAddress = true; +} + + +DNSServiceFlags callbackFlags; + +void DNSServiceResolveReplyCallback ( + DNSServiceRef sdRef, + DNSServiceFlags flags, + uint32_t interfaceIndex, + DNSServiceErrorType errorCode, + const char *fullname, + const char *hosttarget, + uint16_t port, + uint16_t txtLen, + const unsigned char *txtRecord, + void *context ) { + (void)sdRef; + (void)errorCode; + (void)port; + (void)txtLen; + (void)txtRecord; + (void)context; + + char interfaceName[IF_NAMESIZE]; + if_indextoname( interfaceIndex, interfaceName ); + printf( "Resolve: interfaceIndex [%i]=%s : %s @ %s\n", interfaceIndex, interfaceName, fullname, hosttarget ); + callbackFlags = flags; + +#if 0 + struct hostent * host = gethostbyname( hosttarget ); + if ( host ) { + printf( "h_name: %s\n", host->h_name ); + if ( host->h_aliases ) { // this can be NULL + for ( char **list = host->h_aliases ; *list ; list++ ) { + printf( "h_alias: %s\n", *list ); + } + } + printf( "h_addrtype: %i\n", host->h_addrtype ); + printf( "h_length: %i\n", host->h_length ); + if ( !host->h_addr_list ) { // I doubt this would ever be NULL... + return; + } + for ( char **list = host->h_addr_list ; *list ; list++ ) { + printf( "addr: %i.%i.%i.%i\n", ((byte *)*list)[0], ((byte *)*list)[1], ((byte *)*list)[2], ((byte *)*list)[3] ); + } + + memset( &resolvedServerAddress, 0, sizeof( resolvedServerAddress ) ); + resolvedServerAddress.sin_len = sizeof( resolvedServerAddress ); + resolvedServerAddress.sin_family = host->h_addrtype; + resolvedServerAddress.sin_port = htons( DOOM_PORT ); + assert( host->h_length == 4 ); + memcpy( &resolvedServerAddress.sin_addr, *host->h_addr_list, host->h_length ); + + gotServerAddress = true; + } +#else + DNSServiceRef queryRef; + + // look up the name for this host + DNSServiceErrorType err = DNSServiceQueryRecord ( + &queryRef, + kDNSServiceFlagsForceMulticast, + interfaceIndex, + hosttarget, + kDNSServiceType_A, // we want the host address + kDNSServiceClass_IN, + DNSServiceQueryRecordReplyCallback, + NULL /* may be NULL */ + ); + if ( err != kDNSServiceErr_NoError ) { + printf( "DNSServiceQueryRecord error\n" ); + } else { + // block until we get a response, process it, and run the callback + err = DNSServiceProcessResult( queryRef ); + if ( err != kDNSServiceErr_NoError ) { + printf( "DNSServiceProcessResult error\n" ); + } + DNSServiceRefDeallocate( queryRef ); + } +#endif +} + +boolean NetworkServerAvailable() { + for ( int i = 0 ; i < MAX_SERVICE_INTEFACES ; i++ ) { + if ( serviceInterfaces[i].interfaceIndex != 0 ) { + return true; + } + } + return false; +} + +// returns "WiFi", "BlueTooth", or "" for display on the +// main menu multiplayer icon +const char *NetworkServerTransport() { + int count = 0; + for ( int i = 0 ; i < MAX_SERVICE_INTEFACES ; i++ ) { + if ( serviceInterfaces[i].interfaceIndex != 0 ) { + count++; + } + } + + static char str[1024]; + + str[0] = 0; + for ( int i = 0 ; i < MAX_SERVICE_INTEFACES ; i++ ) { + int index = serviceInterfaces[i].interfaceIndex; + if ( index == 0 ) { + continue; + } + if ( str[0] ) { + strcat( str, "+" ); + } + if ( index == -1 ) { + strcat( str, "BT-NEW" ); + } else if ( index == 1 ) { + strcat( str, "LOOP" ); // we should never see this! + } else if ( index == 2 ) { + strcat( str, "WiFi" ); + } else { + strcat( str, "BT-EST" ); + } + } + return str; +} + + + +boolean ResolveNetworkServer( struct sockaddr *addr ) { + if ( !NetworkServerAvailable() ) { + return false; + } + + gotServerAddress = false; + + DNSServiceRef resolveRef; + + // An unconnected bluetooth service will report an interfaceIndex of -1, so if + // we have a wifi link with an interfaceIndex > 0, use that + // explicitly. + service_t *service = NULL; + for ( int i = 0 ; i < MAX_SERVICE_INTEFACES ; i++ ) { + if ( serviceInterfaces[i].interfaceIndex > 0 ) { + service = &serviceInterfaces[i]; + char interfaceName[IF_NAMESIZE]; + if_indextoname( service->interfaceIndex, interfaceName ); + printf( "explicitly resolving server on interface %i = %s\n", service->interfaceIndex, interfaceName ); + break; + } + } + if ( !service ) { +#if 0 // don't support bluetooth now + // settle for the unconnected bluetooth service + for ( int i = 0 ; i < MAX_SERVICE_INTEFACES ; i++ ) { + if ( serviceInterfaces[i].interfaceIndex != 0 ) { + service = &serviceInterfaces[i]; + break; + } + } +#endif + if ( !service ) { + printf( "No serviceInterface current.\n" ); + return false; + } + } + + // look up the name for this service + + DNSServiceErrorType err = DNSServiceResolve ( + &resolveRef, + kDNSServiceFlagsForceMulticast, // always on local link + service->interfaceIndex > 0 ? service->interfaceIndex : 0, // don't use -1 for bluetooth + service->browseName, + service->browseRegtype, + service->browseDomain, + DNSServiceResolveReplyCallback, + NULL /* context */ + ); + + if ( err != kDNSServiceErr_NoError ) { + printf( "DNSServiceResolve error\n" ); + } else { + // We can get two callbacks when both wifi and bluetooth are enabled + callbackFlags = 0; + do { + err = DNSServiceProcessResult( resolveRef ); + if ( err != kDNSServiceErr_NoError ) { + printf( "DNSServiceProcessResult error\n" ); + } + } while ( callbackFlags & kDNSServiceFlagsMoreComing ); + DNSServiceRefDeallocate( resolveRef ); + } + + if ( gotServerAddress ) { + *addr = resolvedServerAddress; + return true; + } + + + return false; +} + + +void DNSServiceBrowseReplyCallback( + DNSServiceRef sdRef, + DNSServiceFlags flags, + uint32_t interfaceIndex, + DNSServiceErrorType errorCode, + const char *theServiceName, + const char *regtype, + const char *replyDomain, + void *context ) { + (void)sdRef; + (void)errorCode; + (void)context; + + printf( "DNSServiceBrowseReplyCallback %s: interface:%i name:%s regtype:%s domain:%s\n", + (flags & kDNSServiceFlagsAdd) ? "ADD" : "REMOVE", + interfaceIndex, theServiceName, regtype, replyDomain ); + if ( flags & kDNSServiceFlagsAdd ) { + // add it to the list + if ( interfaceIndex == 1 ) { + printf( "Not adding service on loopback interface.\n" ); + } else { + for ( int i = 0 ; i < MAX_SERVICE_INTEFACES ; i++ ) { + service_t *service = &serviceInterfaces[i]; + if ( service->interfaceIndex == 0 ) { + strncpy( service->browseName, theServiceName, sizeof( service->browseName ) -1 ); + strncpy( service->browseRegtype, regtype, sizeof( service->browseRegtype ) -1 ); + strncpy( service->browseDomain, replyDomain, sizeof( service->browseDomain ) -1 ); + service->interfaceIndex = interfaceIndex; + break; + } + } + } + } else { + // remove it from the list + for ( int i = 0 ; i < MAX_SERVICE_INTEFACES ; i++ ) { + if ( serviceInterfaces[i].interfaceIndex == interfaceIndex ) { + serviceInterfaces[i].interfaceIndex = 0; + } + } + } +} + +void ProcessDNSMessages() { + static boolean initialized; + + if ( !initialized ) { + initialized = true; + DNSServiceErrorType err = DNSServiceBrowse ( + &browseRef, + 0, /* flags */ + 0, /* interface */ + serviceName, + NULL, /* domain */ + DNSServiceBrowseReplyCallback, + NULL /* context */ + ); + if ( err != kDNSServiceErr_NoError ) { + printf( "DNSServiceBrowse error\n" ); + return; + } + } + + // poll the socket for updates + int socket = DNSServiceRefSockFD( browseRef ); + if ( socket <= 0 ) { + return; + } + fd_set set; + FD_ZERO( &set ); + FD_SET( socket, &set ); + + struct timeval tv; + memset( &tv, 0, sizeof( tv ) ); + if ( select( socket+1, &set, NULL, NULL, &tv ) > 0 ) { + DNSServiceProcessResult( browseRef ); + } +} + +void ReportNetworkInterfaces() { + struct ifaddrs *ifap; + printf( "getifaddrs():\n" ); + if ( getifaddrs( &ifap ) == -1 ) { + perror( "getifaddrs(): " ); + } else { + for ( struct ifaddrs *ifa = ifap ; ifa ; ifa = ifa->ifa_next ) { + struct sockaddr_in *ina = (struct sockaddr_in *)ifa->ifa_addr; + if ( ina->sin_family == AF_INET ) { + byte *ip = (byte *)&ina->sin_addr; + printf( "ifa_name: %s ifa_flags: %i sa_family: %i=AF_INET ip: %i.%i.%i.%i\n", ifa->ifa_name, ifa->ifa_flags, + ina->sin_family, ip[0], ip[1], ip[2], ip[3] ); + } else if ( ina->sin_family == AF_LINK ) { + struct if_data *data = (struct if_data *)ifa->ifa_data; + printf( "ifa_name: %s ifa_flags: %i sa_family: %i=AF_LINK ifi_ipackets: %i\n", ifa->ifa_name, ifa->ifa_flags, + ina->sin_family, data->ifi_ipackets ); + } else { + printf( "ifa_name: %s ifa_flags: %i sa_family: %i=???\n", ifa->ifa_name, ifa->ifa_flags, + ina->sin_family ); + } + } + freeifaddrs( ifap ); + } + + printf( "if_nameindex():\n" ); + struct if_nameindex *ifnames = if_nameindex(); + if ( !ifnames ) { + perror( "if_ameindex():" ); + } else { + for ( int i = 0 ; ifnames[i].if_index != 0 ; i++ ) { + printf( "%i : %s\n", ifnames[i].if_index, ifnames[i].if_name ); + } + if_freenameindex( ifnames ); + } + +} + +boolean NetworkAvailable() { + struct ifaddrs *ifap; + if ( getifaddrs( &ifap ) == -1 ) { + return false; + } + + // We can't tell if bluetooth is available from here, because + // the interface doesn't appear until after the service is found, + // but I decided not to support bluetooth for now due to the poor performance. + boolean goodInterface = false; + + for ( struct ifaddrs *ifa = ifap ; ifa ; ifa = ifa->ifa_next ) { + struct sockaddr_in *ina = (struct sockaddr_in *)ifa->ifa_addr; + if ( ina->sin_family == AF_INET ) { + if ( !strcmp( ifa->ifa_name, "en0" ) ) { + goodInterface = true; + } + } + } + freeifaddrs( ifap ); + + return goodInterface; +} + +int InterfaceIndexForAddress( struct sockaddr_in *adr ) { + (void)adr; + // FIXME: compare against getifaddrs + return 0; +} + +struct sockaddr_in AddressForInterfaceName( const char *ifname ) { + struct sockaddr_in s; + memset( &s, 0, sizeof( s ) ); + + struct ifaddrs *ifap; + if ( getifaddrs( &ifap ) == -1 ) { + perror( "getifaddrs()" ); + return s; + } + + struct ifaddrs *ifa; + for ( ifa = ifap ; ifa ; ifa = ifa->ifa_next ) { + struct sockaddr_in *ina = (struct sockaddr_in *)ifa->ifa_addr; + if ( ina->sin_family == AF_INET && !strcmp( ifa->ifa_name, ifname ) ) { + byte *ip = (byte *)&ina->sin_addr; + printf( "AddressForInterfaceName( %s ) = ifa_name: %s ifa_flags: %i sa_family: %i=AF_INET ip: %i.%i.%i.%i\n", + ifname, ifa->ifa_name, ifa->ifa_flags, + ina->sin_family, ip[0], ip[1], ip[2], ip[3] ); + freeifaddrs( ifap ); + return *ina; + } + } + freeifaddrs( ifap ); + printf( "AddressForInterfaceName( %s ): Couldn't find IP address\n", ifname ); + return s; +} + +int InterfaceIndexForName( const char *ifname ) { + struct if_nameindex *ifnames = if_nameindex(); + if ( !ifnames ) { + perror( "if_nameindex()" ); + return 0; + } + for ( int i = 0 ; ifnames[i].if_index != 0 ; i++ ) { + if ( !strcmp( ifname, ifnames[i].if_name ) ) { + int index = ifnames[i].if_index; + if_freenameindex( ifnames ); + return index; + } + } + printf( "InterfaceIndexForName( %s ): Couldn't find interface\n", ifname ); + if_freenameindex( ifnames ); + return 0; +} + +struct sockaddr_in AddressForInterfaceIndex( int interfaceIndex ) { + struct sockaddr_in addr; + + memset( &addr, 0, sizeof( addr ) ); + addr.sin_len = sizeof( addr ); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; + + if ( interfaceIndex == 0 ) { + return addr; + } + + struct if_nameindex *ifnames = if_nameindex(); + if ( !ifnames ) { + perror( "if_ameindex()" ); + return addr; + } + for ( int i = 0 ; ifnames[i].if_index != 0 ; i++ ) { + if ( ifnames[i].if_index == interfaceIndex ) { + addr = AddressForInterfaceName( ifnames[i].if_name ); + if_freenameindex( ifnames ); + return addr; + } + } + printf( "AddressForInterfaceIndex( %i ): Couldn't find interface\n", interfaceIndex ); + if_freenameindex( ifnames ); + return addr; +} + +struct sockaddr_in gameSocketAddress; + +int UDPSocket( const char *interfaceName, int portnum ) { + int udpSocket = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP ); + if ( udpSocket == -1 ) { + Com_Printf( "UDP socket failed: %s\n", strerror( errno ) ); + return -1; + } + struct sockaddr_in addr = AddressForInterfaceName( interfaceName ); + addr.sin_port = htons( portnum ); + byte *ip = (byte *)&addr.sin_addr; + gameSocketAddress = addr; + Com_Printf( "UDPSocket( %s, %i ) = %i.%i.%i.%i\n", interfaceName, portnum, + ip[0], ip[1], ip[2], ip[3] ); + if ( bind( udpSocket, (struct sockaddr *)&addr, sizeof( addr ) ) == -1 ) { + Com_Printf( "UDP bind failed: %s\n", strerror( errno ) ); + close( udpSocket ); + return -1; + } + +#if 0 + // enable broadcast + int on = 1; + if ( setsockopt( udpSocket, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on) ) == -1 ) { + Com_Printf( "UDP setsockopt failed: %s\n", strerror( errno ) ); + close( udpSocket ); + return -1; + } +#endif + +#if 0 + // set the type-of-service, in hopes that the link level drivers use it + // to stop buffering huge amounts of data when there are line errors + int tos = 0x10; /* IPTOS_LOWDELAY; */ /* see */ + if ( setsockopt( udpSocket, IPPROTO_IP, IP_TOS, &tos, sizeof(tos) ) == -1 ) { + Com_Printf( "setsockopt IP_TOS failed: %s\n", strerror( errno ) ); + } +#endif + + // enable non-blocking IO + if ( fcntl( udpSocket, F_SETFL, O_NONBLOCK ) == -1 ) { + Com_Printf( "UDP fcntl failed: %s\n", strerror( errno ) ); + close( udpSocket ); + return -1; + } + + return udpSocket; +} + diff --git a/common/ios/doomengine/iphone_qgl.h b/common/ios/doomengine/iphone_qgl.h new file mode 100755 index 0000000..02cf8ba --- /dev/null +++ b/common/ios/doomengine/iphone_qgl.h @@ -0,0 +1,2412 @@ +/**** This file is autogenerated. Run GenerateQGL.pl to update it ****/ +/* + + Copyright (C) 2009 Id Software, 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 + 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. + + */ + + +#ifndef _IPHONE_QGL_H_ +#define _IPHONE_QGL_H_ + +#ifdef QGL_LOG_GL_CALLS +extern unsigned int QGLLogGLCalls; +#ifdef __cplusplus +extern "C" { +#endif + FILE *QGLDebugFile(void); +#ifdef __cplusplus +} +#endif +#endif + +#include "iphone_qgl_enumerants.h" + + +#ifdef __cplusplus +extern "C" { +#endif + void QGLCheckError(const char *message); +#ifdef __cplusplus +} +#endif +extern unsigned int QGLBeginStarted; + +// This has to be done to avoid infinite recursion between our glGetError wrapper and QGLCheckError() +static inline GLenum _glGetError(void) { + return glGetError(); +} + +// void glAlphaFunc (GLenum func, GLclampf ref); +static inline void qglAlphaFunc(GLenum func, GLclampf ref) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glAlphaFunc(func=%s, ref=%f)\n", StringFromGLEnumerant( func ), ref); +#endif + glAlphaFunc(func, ref); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glAlphaFunc"); +#endif +} + +// void glClearColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); +static inline void qglClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glClearColor(red=%f, green=%f, blue=%f, alpha=%f)\n", red, green, blue, alpha); +#endif + glClearColor(red, green, blue, alpha); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glClearColor"); +#endif +} + +// void glClearDepthf (GLclampf depth); +static inline void qglClearDepthf(GLclampf depth) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glClearDepthf(depth=%f)\n", depth); +#endif + glClearDepthf(depth); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glClearDepthf"); +#endif +} + +// void glClipPlanef (GLenum plane, const GLfloat *equation); +static inline void qglClipPlanef(GLenum plane, const GLfloat *equation) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glClipPlanef(plane=%s, equation=%p)\n", StringFromGLEnumerant( plane ), equation); +#endif + glClipPlanef(plane, equation); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glClipPlanef"); +#endif +} + +// void glColor4f (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +// void glDepthRangef (GLclampf zNear, GLclampf zFar); +static inline void qglDepthRangef(GLclampf zNear, GLclampf zFar) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glDepthRangef(zNear=%f, zFar=%f)\n", zNear, zFar); +#endif + glDepthRangef(zNear, zFar); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glDepthRangef"); +#endif +} + +// void glFogf (GLenum pname, GLfloat param); +static inline void qglFogf(GLenum pname, GLfloat param) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glFogf(pname=%s, param=%f)\n", StringFromGLEnumerant( pname ), param); +#endif + glFogf(pname, param); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glFogf"); +#endif +} + +// void glFogfv (GLenum pname, const GLfloat *params); +static inline void qglFogfv(GLenum pname, const GLfloat *params) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glFogfv(pname=%s, params=%p)\n", StringFromGLEnumerant( pname ), params); +#endif + glFogfv(pname, params); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glFogfv"); +#endif +} + +// void glFrustumf (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar); +static inline void qglFrustumf(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glFrustumf(left=%f, right=%f, bottom=%f, top=%f, zNear=%f, zFar=%f)\n", left, right, bottom, top, zNear, zFar); +#endif + glFrustumf(left, right, bottom, top, zNear, zFar); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glFrustumf"); +#endif +} + +// void glGetClipPlanef (GLenum pname, GLfloat *equation); +static inline void qglGetClipPlanef(GLenum pname, GLfloat *equation) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glGetClipPlanef(pname=%s, equation=%p)\n", StringFromGLEnumerant( pname ), equation); +#endif + glGetClipPlanef(pname, equation); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glGetClipPlanef"); +#endif +} + +// void glGetFloatv (GLenum pname, GLfloat *params); +static inline void qglGetFloatv(GLenum pname, GLfloat *params) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glGetFloatv(pname=%s, params=%p)\n", StringFromGLEnumerant( pname ), params); +#endif + glGetFloatv(pname, params); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glGetFloatv"); +#endif +} + +// void glGetLightfv (GLenum light, GLenum pname, GLfloat *params); +static inline void qglGetLightfv(GLenum light, GLenum pname, GLfloat *params) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glGetLightfv(light=%s, pname=%s, params=%p)\n", StringFromGLEnumerant( light ), StringFromGLEnumerant( pname ), params); +#endif + glGetLightfv(light, pname, params); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glGetLightfv"); +#endif +} + +// void glGetMaterialfv (GLenum face, GLenum pname, GLfloat *params); +static inline void qglGetMaterialfv(GLenum face, GLenum pname, GLfloat *params) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glGetMaterialfv(face=%s, pname=%s, params=%p)\n", StringFromGLEnumerant( face ), StringFromGLEnumerant( pname ), params); +#endif + glGetMaterialfv(face, pname, params); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glGetMaterialfv"); +#endif +} + +// void glGetTexEnvfv (GLenum env, GLenum pname, GLfloat *params); +static inline void qglGetTexEnvfv(GLenum env, GLenum pname, GLfloat *params) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glGetTexEnvfv(env=%s, pname=%s, params=%p)\n", StringFromGLEnumerant( env ), StringFromGLEnumerant( pname ), params); +#endif + glGetTexEnvfv(env, pname, params); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glGetTexEnvfv"); +#endif +} + +// void glGetTexParameterfv (GLenum target, GLenum pname, GLfloat *params); +static inline void qglGetTexParameterfv(GLenum target, GLenum pname, GLfloat *params) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glGetTexParameterfv(target=%s, pname=%s, params=%p)\n", StringFromGLEnumerant( target ), StringFromGLEnumerant( pname ), params); +#endif + glGetTexParameterfv(target, pname, params); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glGetTexParameterfv"); +#endif +} + +// void glLightModelf (GLenum pname, GLfloat param); +static inline void qglLightModelf(GLenum pname, GLfloat param) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glLightModelf(pname=%s, param=%f)\n", StringFromGLEnumerant( pname ), param); +#endif + glLightModelf(pname, param); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glLightModelf"); +#endif +} + +// void glLightModelfv (GLenum pname, const GLfloat *params); +static inline void qglLightModelfv(GLenum pname, const GLfloat *params) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glLightModelfv(pname=%s, params=%p)\n", StringFromGLEnumerant( pname ), params); +#endif + glLightModelfv(pname, params); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glLightModelfv"); +#endif +} + +// void glLightf (GLenum light, GLenum pname, GLfloat param); +static inline void qglLightf(GLenum light, GLenum pname, GLfloat param) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glLightf(light=%s, pname=%s, param=%f)\n", StringFromGLEnumerant( light ), StringFromGLEnumerant( pname ), param); +#endif + glLightf(light, pname, param); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glLightf"); +#endif +} + +// void glLightfv (GLenum light, GLenum pname, const GLfloat *params); +static inline void qglLightfv(GLenum light, GLenum pname, const GLfloat *params) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glLightfv(light=%s, pname=%s, params=%p)\n", StringFromGLEnumerant( light ), StringFromGLEnumerant( pname ), params); +#endif + glLightfv(light, pname, params); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glLightfv"); +#endif +} + +// void glLineWidth (GLfloat width); +static inline void qglLineWidth(GLfloat width) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glLineWidth(width=%f)\n", width); +#endif + glLineWidth(width); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glLineWidth"); +#endif +} + +// void glLoadMatrixf (const GLfloat *m); +static inline void qglLoadMatrixf(const GLfloat *m) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glLoadMatrixf(m=%p)\n", m); +#endif + glLoadMatrixf(m); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glLoadMatrixf"); +#endif +} + +// void glMaterialf (GLenum face, GLenum pname, GLfloat param); +static inline void qglMaterialf(GLenum face, GLenum pname, GLfloat param) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glMaterialf(face=%s, pname=%s, param=%f)\n", StringFromGLEnumerant( face ), StringFromGLEnumerant( pname ), param); +#endif + glMaterialf(face, pname, param); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glMaterialf"); +#endif +} + +// void glMaterialfv (GLenum face, GLenum pname, const GLfloat *params); +static inline void qglMaterialfv(GLenum face, GLenum pname, const GLfloat *params) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glMaterialfv(face=%s, pname=%s, params=%p)\n", StringFromGLEnumerant( face ), StringFromGLEnumerant( pname ), params); +#endif + glMaterialfv(face, pname, params); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glMaterialfv"); +#endif +} + +// void glMultMatrixf (const GLfloat *m); +static inline void qglMultMatrixf(const GLfloat *m) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glMultMatrixf(m=%p)\n", m); +#endif + glMultMatrixf(m); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glMultMatrixf"); +#endif +} + +// void glMultiTexCoord4f (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); +static inline void qglMultiTexCoord4f(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glMultiTexCoord4f(target=%s, s=%f, t=%f, r=%f, q=%f)\n", StringFromGLEnumerant( target ), s, t, r, q); +#endif + glMultiTexCoord4f(target, s, t, r, q); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glMultiTexCoord4f"); +#endif +} + +// void glNormal3f (GLfloat nx, GLfloat ny, GLfloat nz); +static inline void qglNormal3f(GLfloat nx, GLfloat ny, GLfloat nz) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glNormal3f(nx=%f, ny=%f, nz=%f)\n", nx, ny, nz); +#endif + glNormal3f(nx, ny, nz); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glNormal3f"); +#endif +} + +// void glOrthof (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar); +static inline void qglOrthof(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glOrthof(left=%f, right=%f, bottom=%f, top=%f, zNear=%f, zFar=%f)\n", left, right, bottom, top, zNear, zFar); +#endif + glOrthof(left, right, bottom, top, zNear, zFar); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glOrthof"); +#endif +} + +// void glPointParameterf (GLenum pname, GLfloat param); +static inline void qglPointParameterf(GLenum pname, GLfloat param) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glPointParameterf(pname=%s, param=%f)\n", StringFromGLEnumerant( pname ), param); +#endif + glPointParameterf(pname, param); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glPointParameterf"); +#endif +} + +// void glPointParameterfv (GLenum pname, const GLfloat *params); +static inline void qglPointParameterfv(GLenum pname, const GLfloat *params) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glPointParameterfv(pname=%s, params=%p)\n", StringFromGLEnumerant( pname ), params); +#endif + glPointParameterfv(pname, params); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glPointParameterfv"); +#endif +} + +// void glPointSize (GLfloat size); +static inline void qglPointSize(GLfloat size) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glPointSize(size=%f)\n", size); +#endif + glPointSize(size); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glPointSize"); +#endif +} + +// void glPolygonOffset (GLfloat factor, GLfloat units); +static inline void qglPolygonOffset(GLfloat factor, GLfloat units) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glPolygonOffset(factor=%f, units=%f)\n", factor, units); +#endif + glPolygonOffset(factor, units); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glPolygonOffset"); +#endif +} + +// void glRotatef (GLfloat angle, GLfloat x, GLfloat y, GLfloat z); +static inline void qglRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glRotatef(angle=%f, x=%f, y=%f, z=%f)\n", angle, x, y, z); +#endif + glRotatef(angle, x, y, z); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glRotatef"); +#endif +} + +// void glScalef (GLfloat x, GLfloat y, GLfloat z); +static inline void qglScalef(GLfloat x, GLfloat y, GLfloat z) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glScalef(x=%f, y=%f, z=%f)\n", x, y, z); +#endif + glScalef(x, y, z); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glScalef"); +#endif +} + +// void glTexEnvf (GLenum target, GLenum pname, GLfloat param); +static inline void qglTexEnvf(GLenum target, GLenum pname, GLfloat param) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glTexEnvf(target=%s, pname=%s, param=%f)\n", StringFromGLEnumerant( target ), StringFromGLEnumerant( pname ), param); +#endif + glTexEnvf(target, pname, param); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glTexEnvf"); +#endif +} + +// void glTexEnvfv (GLenum target, GLenum pname, const GLfloat *params); +static inline void qglTexEnvfv(GLenum target, GLenum pname, const GLfloat *params) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glTexEnvfv(target=%s, pname=%s, params=%p)\n", StringFromGLEnumerant( target ), StringFromGLEnumerant( pname ), params); +#endif + glTexEnvfv(target, pname, params); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glTexEnvfv"); +#endif +} + +// void glTexParameterf (GLenum target, GLenum pname, GLfloat param); +static inline void qglTexParameterf(GLenum target, GLenum pname, GLfloat param) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glTexParameterf(target=%s, pname=%s, param=%f)\n", StringFromGLEnumerant( target ), StringFromGLEnumerant( pname ), param); +#endif + glTexParameterf(target, pname, param); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glTexParameterf"); +#endif +} + +// void glTexParameterfv (GLenum target, GLenum pname, const GLfloat *params); +static inline void qglTexParameterfv(GLenum target, GLenum pname, const GLfloat *params) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glTexParameterfv(target=%s, pname=%s, params=%p)\n", StringFromGLEnumerant( target ), StringFromGLEnumerant( pname ), params); +#endif + glTexParameterfv(target, pname, params); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glTexParameterfv"); +#endif +} + +// void glTranslatef (GLfloat x, GLfloat y, GLfloat z); +static inline void qglTranslatef(GLfloat x, GLfloat y, GLfloat z) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glTranslatef(x=%f, y=%f, z=%f)\n", x, y, z); +#endif + glTranslatef(x, y, z); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glTranslatef"); +#endif +} + +// void glActiveTexture (GLenum texture); +static inline void qglActiveTexture(GLenum texture) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glActiveTexture(texture=%s)\n", StringFromGLEnumerant( texture )); +#endif + glActiveTexture(texture); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glActiveTexture"); +#endif +} + +// void glAlphaFuncx (GLenum func, GLclampx ref); +static inline void qglAlphaFuncx(GLenum func, GLclampx ref) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glAlphaFuncx(func=%s, ref=%ld)\n", StringFromGLEnumerant( func ), ref); +#endif + glAlphaFuncx(func, ref); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glAlphaFuncx"); +#endif +} + +// void glBindBuffer (GLenum target, GLuint buffer); +static inline void qglBindBuffer(GLenum target, GLuint buffer) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glBindBuffer(target=%s, buffer=%lu)\n", StringFromGLEnumerant( target ), buffer); +#endif + glBindBuffer(target, buffer); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glBindBuffer"); +#endif +} + +// void glBindTexture (GLenum target, GLuint texture); +static inline void qglBindTexture(GLenum target, GLuint texture) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glBindTexture(target=%s, texture=%lu)\n", StringFromGLEnumerant( target ), texture); +#endif + glBindTexture(target, texture); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glBindTexture"); +#endif +} + +// void glBlendFunc (GLenum sfactor, GLenum dfactor); +static inline void qglBlendFunc(GLenum sfactor, GLenum dfactor) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glBlendFunc(sfactor=%s, dfactor=%s)\n", StringFromGLEnumerant( sfactor ), StringFromGLEnumerant( dfactor )); +#endif + glBlendFunc(sfactor, dfactor); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glBlendFunc"); +#endif +} + +// void glBufferData (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage); +static inline void qglBufferData(GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glBufferData(target=%s, size=%ld, data=%p, usage=%s)\n", StringFromGLEnumerant( target ), size, data, StringFromGLEnumerant( usage )); +#endif + glBufferData(target, size, data, usage); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glBufferData"); +#endif +} + +// void glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data); +static inline void qglBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glBufferSubData(target=%s, offset=%ld, size=%ld, data=%p)\n", StringFromGLEnumerant( target ), offset, size, data); +#endif + glBufferSubData(target, offset, size, data); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glBufferSubData"); +#endif +} + +// void glClear (GLbitfield mask); +static inline void qglClear(GLbitfield mask) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glClear(mask=%lu)\n", mask); +#endif + glClear(mask); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glClear"); +#endif +} + +// void glClearColorx (GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha); +static inline void qglClearColorx(GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glClearColorx(red=%ld, green=%ld, blue=%ld, alpha=%ld)\n", red, green, blue, alpha); +#endif + glClearColorx(red, green, blue, alpha); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glClearColorx"); +#endif +} + +// void glClearDepthx (GLclampx depth); +static inline void qglClearDepthx(GLclampx depth) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glClearDepthx(depth=%ld)\n", depth); +#endif + glClearDepthx(depth); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glClearDepthx"); +#endif +} + +// void glClearStencil (GLint s); +static inline void qglClearStencil(GLint s) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glClearStencil(s=%ld)\n", s); +#endif + glClearStencil(s); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glClearStencil"); +#endif +} + +// void glClientActiveTexture (GLenum texture); +static inline void qglClientActiveTexture(GLenum texture) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glClientActiveTexture(texture=%s)\n", StringFromGLEnumerant( texture )); +#endif + glClientActiveTexture(texture); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glClientActiveTexture"); +#endif +} + +// void glClipPlanex (GLenum plane, const GLfixed *equation); +static inline void qglClipPlanex(GLenum plane, const GLfixed *equation) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glClipPlanex(plane=%s, equation=%p)\n", StringFromGLEnumerant( plane ), equation); +#endif + glClipPlanex(plane, equation); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glClipPlanex"); +#endif +} + +// void glColor4ub (GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha); +static inline void qglColor4ub(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glColor4ub(red=%u, green=%u, blue=%u, alpha=%u)\n", red, green, blue, alpha); +#endif + glColor4ub(red, green, blue, alpha); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glColor4ub"); +#endif +} + +// void glColor4x (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); +static inline void qglColor4x(GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glColor4x(red=%ld, green=%ld, blue=%ld, alpha=%ld)\n", red, green, blue, alpha); +#endif + glColor4x(red, green, blue, alpha); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glColor4x"); +#endif +} + +// void glColorMask (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); +static inline void qglColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glColorMask(red=%u, green=%u, blue=%u, alpha=%u)\n", red, green, blue, alpha); +#endif + glColorMask(red, green, blue, alpha); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glColorMask"); +#endif +} + +// void glColorPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +static inline void qglColorPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glColorPointer(size=%ld, type=%s, stride=%ld, pointer=%p)\n", size, StringFromGLEnumerant( type ), stride, pointer); +#endif + glColorPointer(size, type, stride, pointer); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glColorPointer"); +#endif +} + +// void glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); +static inline void qglCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glCompressedTexImage2D(target=%s, level=%ld, internalformat=%s, width=%ld, height=%ld, border=%ld, imageSize=%ld, data=%p)\n", StringFromGLEnumerant( target ), level, StringFromGLEnumerant( internalformat ), width, height, border, imageSize, data); +#endif + glCompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glCompressedTexImage2D"); +#endif +} + +// void glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); +static inline void qglCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glCompressedTexSubImage2D(target=%s, level=%ld, xoffset=%ld, yoffset=%ld, width=%ld, height=%ld, format=%s, imageSize=%ld, data=%p)\n", StringFromGLEnumerant( target ), level, xoffset, yoffset, width, height, StringFromGLEnumerant( format ), imageSize, data); +#endif + glCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glCompressedTexSubImage2D"); +#endif +} + +// void glCopyTexImage2D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +static inline void qglCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glCopyTexImage2D(target=%s, level=%ld, internalformat=%s, x=%ld, y=%ld, width=%ld, height=%ld, border=%ld)\n", StringFromGLEnumerant( target ), level, StringFromGLEnumerant( internalformat ), x, y, width, height, border); +#endif + glCopyTexImage2D(target, level, internalformat, x, y, width, height, border); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glCopyTexImage2D"); +#endif +} + +// void glCopyTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +static inline void qglCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glCopyTexSubImage2D(target=%s, level=%ld, xoffset=%ld, yoffset=%ld, x=%ld, y=%ld, width=%ld, height=%ld)\n", StringFromGLEnumerant( target ), level, xoffset, yoffset, x, y, width, height); +#endif + glCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glCopyTexSubImage2D"); +#endif +} + +// void glCullFace (GLenum mode); +static inline void qglCullFace(GLenum mode) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glCullFace(mode=%s)\n", StringFromGLEnumerant( mode )); +#endif + glCullFace(mode); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glCullFace"); +#endif +} + +// void glDeleteBuffers (GLsizei n, const GLuint *buffers); +static inline void qglDeleteBuffers(GLsizei n, const GLuint *buffers) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glDeleteBuffers(n=%ld, buffers=%p)\n", n, buffers); +#endif + glDeleteBuffers(n, buffers); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glDeleteBuffers"); +#endif +} + +// void glDeleteTextures (GLsizei n, const GLuint *textures); +static inline void qglDeleteTextures(GLsizei n, const GLuint *textures) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glDeleteTextures(n=%ld, textures=%p)\n", n, textures); +#endif + glDeleteTextures(n, textures); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glDeleteTextures"); +#endif +} + +// void glDepthFunc (GLenum func); +static inline void qglDepthFunc(GLenum func) +{ + func = GL_ALWAYS; +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glDepthFunc(func=%s)\n", StringFromGLEnumerant( func )); +#endif + glDepthFunc(func); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glDepthFunc"); +#endif +} + +// void glDepthMask (GLboolean flag); +static inline void qglDepthMask(GLboolean flag) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glDepthMask(flag=%u)\n", flag); +#endif + glDepthMask(flag); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glDepthMask"); +#endif +} + +// void glDepthRangex (GLclampx zNear, GLclampx zFar); +static inline void qglDepthRangex(GLclampx zNear, GLclampx zFar) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glDepthRangex(zNear=%ld, zFar=%ld)\n", zNear, zFar); +#endif + glDepthRangex(zNear, zFar); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glDepthRangex"); +#endif +} + +// void glDisable (GLenum cap); +static inline void qglDisable(GLenum cap) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glDisable(cap=%s)\n", StringFromGLEnumerant( cap )); +#endif + glDisable(cap); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glDisable"); +#endif +} + +// void glDisableClientState (GLenum array); +static inline void qglDisableClientState(GLenum array) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glDisableClientState(array=%s)\n", StringFromGLEnumerant( array )); +#endif + glDisableClientState(array); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glDisableClientState"); +#endif +} + +// void glDrawArrays (GLenum mode, GLint first, GLsizei count); +static inline void qglDrawArrays(GLenum mode, GLint first, GLsizei count) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glDrawArrays(mode=%s, first=%ld, count=%ld)\n", StringFromGLEnumerant( mode ), first, count); +#endif + glDrawArrays(mode, first, count); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glDrawArrays"); +#endif +} + +// void glDrawElements (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); +static inline void qglDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glDrawElements(mode=%s, count=%ld, type=%s, indices=%p)\n", StringFromGLEnumerant( mode ), count, StringFromGLEnumerant( type ), indices); +#endif + glDrawElements(mode, count, type, indices); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glDrawElements"); +#endif +} + +// void glEnable (GLenum cap); +static inline void qglEnable(GLenum cap) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glEnable(cap=%s)\n", StringFromGLEnumerant( cap )); +#endif + glEnable(cap); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glEnable"); +#endif +} + +// void glEnableClientState (GLenum array); +static inline void qglEnableClientState(GLenum array) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glEnableClientState(array=%s)\n", StringFromGLEnumerant( array )); +#endif + glEnableClientState(array); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glEnableClientState"); +#endif +} + +// void glFinish (void); +static inline void qglFinish(void) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glFinish(void)\n"); +#endif + glFinish(); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glFinish"); +#endif +} + +// void glFlush (void); +static inline void qglFlush(void) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glFlush(void)\n"); +#endif + glFlush(); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glFlush"); +#endif +} + +// void glFogx (GLenum pname, GLfixed param); +static inline void qglFogx(GLenum pname, GLfixed param) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glFogx(pname=%s, param=%ld)\n", StringFromGLEnumerant( pname ), param); +#endif + glFogx(pname, param); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glFogx"); +#endif +} + +// void glFogxv (GLenum pname, const GLfixed *params); +static inline void qglFogxv(GLenum pname, const GLfixed *params) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glFogxv(pname=%s, params=%p)\n", StringFromGLEnumerant( pname ), params); +#endif + glFogxv(pname, params); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glFogxv"); +#endif +} + +// void glFrontFace (GLenum mode); +static inline void qglFrontFace(GLenum mode) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glFrontFace(mode=%s)\n", StringFromGLEnumerant( mode )); +#endif + glFrontFace(mode); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glFrontFace"); +#endif +} + +// void glFrustumx (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar); +static inline void qglFrustumx(GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glFrustumx(left=%ld, right=%ld, bottom=%ld, top=%ld, zNear=%ld, zFar=%ld)\n", left, right, bottom, top, zNear, zFar); +#endif + glFrustumx(left, right, bottom, top, zNear, zFar); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glFrustumx"); +#endif +} + +// void glGetBooleanv (GLenum pname, GLboolean *params); +static inline void qglGetBooleanv(GLenum pname, GLboolean *params) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glGetBooleanv(pname=%s, params=%p)\n", StringFromGLEnumerant( pname ), params); +#endif + glGetBooleanv(pname, params); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glGetBooleanv"); +#endif +} + +// void glGetBufferParameteriv (GLenum target, GLenum pname, GLint *params); +static inline void qglGetBufferParameteriv(GLenum target, GLenum pname, GLint *params) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glGetBufferParameteriv(target=%s, pname=%s, params=%p)\n", StringFromGLEnumerant( target ), StringFromGLEnumerant( pname ), params); +#endif + glGetBufferParameteriv(target, pname, params); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glGetBufferParameteriv"); +#endif +} + +// void glGetClipPlanex (GLenum pname, GLfixed eqn[4]); +static inline void qglGetClipPlanex(GLenum pname, GLfixed eqn[4]) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glGetClipPlanex(pname=%s, eqn=%ld)\n", StringFromGLEnumerant( pname ), eqn); +#endif + glGetClipPlanex(pname, eqn); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glGetClipPlanex"); +#endif +} + +// void glGenBuffers (GLsizei n, GLuint *buffers); +static inline void qglGenBuffers(GLsizei n, GLuint *buffers) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glGenBuffers(n=%ld, buffers=%p)\n", n, buffers); +#endif + glGenBuffers(n, buffers); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glGenBuffers"); +#endif +} + +// void glGenTextures (GLsizei n, GLuint *textures); +static inline void qglGenTextures(GLsizei n, GLuint *textures) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glGenTextures(n=%ld, textures=%p)\n", n, textures); +#endif + glGenTextures(n, textures); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glGenTextures"); +#endif +} + +// GLenum glGetError (void); +static inline GLenum qglGetError(void) +{ + GLenum returnValue; +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glGetError(void)\n"); +#endif + returnValue = glGetError(); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glGetError"); +#endif + return returnValue; +} + +// void glGetFixedv (GLenum pname, GLfixed *params); +static inline void qglGetFixedv(GLenum pname, GLfixed *params) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glGetFixedv(pname=%s, params=%p)\n", StringFromGLEnumerant( pname ), params); +#endif + glGetFixedv(pname, params); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glGetFixedv"); +#endif +} + +// void glGetIntegerv (GLenum pname, GLint *params); +static inline void qglGetIntegerv(GLenum pname, GLint *params) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glGetIntegerv(pname=%s, params=%p)\n", StringFromGLEnumerant( pname ), params); +#endif + glGetIntegerv(pname, params); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glGetIntegerv"); +#endif +} + +// void glGetLightxv (GLenum light, GLenum pname, GLfixed *params); +static inline void qglGetLightxv(GLenum light, GLenum pname, GLfixed *params) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glGetLightxv(light=%s, pname=%s, params=%p)\n", StringFromGLEnumerant( light ), StringFromGLEnumerant( pname ), params); +#endif + glGetLightxv(light, pname, params); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glGetLightxv"); +#endif +} + +// void glGetMaterialxv (GLenum face, GLenum pname, GLfixed *params); +static inline void qglGetMaterialxv(GLenum face, GLenum pname, GLfixed *params) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glGetMaterialxv(face=%s, pname=%s, params=%p)\n", StringFromGLEnumerant( face ), StringFromGLEnumerant( pname ), params); +#endif + glGetMaterialxv(face, pname, params); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glGetMaterialxv"); +#endif +} + +// void glGetPointerv (GLenum pname, void **params); +static inline void qglGetPointerv(GLenum pname, void **params) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glGetPointerv(pname=%s, params=%p)\n", StringFromGLEnumerant( pname ), params); +#endif + glGetPointerv(pname, params); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glGetPointerv"); +#endif +} + +// const GLubyte * glGetString (GLenum name); +static inline const GLubyte * qglGetString(GLenum name) +{ + const GLubyte * returnValue; +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glGetString(name=%s)\n", StringFromGLEnumerant( name )); +#endif + returnValue = glGetString(name); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glGetString"); +#endif + return returnValue; +} + +// void glGetTexEnviv (GLenum env, GLenum pname, GLint *params); +static inline void qglGetTexEnviv(GLenum env, GLenum pname, GLint *params) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glGetTexEnviv(env=%s, pname=%s, params=%p)\n", StringFromGLEnumerant( env ), StringFromGLEnumerant( pname ), params); +#endif + glGetTexEnviv(env, pname, params); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glGetTexEnviv"); +#endif +} + +// void glGetTexEnvxv (GLenum env, GLenum pname, GLfixed *params); +static inline void qglGetTexEnvxv(GLenum env, GLenum pname, GLfixed *params) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glGetTexEnvxv(env=%s, pname=%s, params=%p)\n", StringFromGLEnumerant( env ), StringFromGLEnumerant( pname ), params); +#endif + glGetTexEnvxv(env, pname, params); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glGetTexEnvxv"); +#endif +} + +// void glGetTexParameteriv (GLenum target, GLenum pname, GLint *params); +static inline void qglGetTexParameteriv(GLenum target, GLenum pname, GLint *params) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glGetTexParameteriv(target=%s, pname=%s, params=%p)\n", StringFromGLEnumerant( target ), StringFromGLEnumerant( pname ), params); +#endif + glGetTexParameteriv(target, pname, params); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glGetTexParameteriv"); +#endif +} + +// void glGetTexParameterxv (GLenum target, GLenum pname, GLfixed *params); +static inline void qglGetTexParameterxv(GLenum target, GLenum pname, GLfixed *params) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glGetTexParameterxv(target=%s, pname=%s, params=%p)\n", StringFromGLEnumerant( target ), StringFromGLEnumerant( pname ), params); +#endif + glGetTexParameterxv(target, pname, params); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glGetTexParameterxv"); +#endif +} + +// void glHint (GLenum target, GLenum mode); +static inline void qglHint(GLenum target, GLenum mode) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glHint(target=%s, mode=%s)\n", StringFromGLEnumerant( target ), StringFromGLEnumerant( mode )); +#endif + glHint(target, mode); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glHint"); +#endif +} + +// GLboolean glIsBuffer (GLuint buffer); +static inline GLboolean qglIsBuffer(GLuint buffer) +{ + GLboolean returnValue; +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glIsBuffer(buffer=%lu)\n", buffer); +#endif + returnValue = glIsBuffer(buffer); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glIsBuffer"); +#endif + return returnValue; +} + +// GLboolean glIsEnabled (GLenum cap); +static inline GLboolean qglIsEnabled(GLenum cap) +{ + GLboolean returnValue; +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glIsEnabled(cap=%s)\n", StringFromGLEnumerant( cap )); +#endif + returnValue = glIsEnabled(cap); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glIsEnabled"); +#endif + return returnValue; +} + +// GLboolean glIsTexture (GLuint texture); +static inline GLboolean qglIsTexture(GLuint texture) +{ + GLboolean returnValue; +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glIsTexture(texture=%lu)\n", texture); +#endif + returnValue = glIsTexture(texture); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glIsTexture"); +#endif + return returnValue; +} + +// void glLightModelx (GLenum pname, GLfixed param); +static inline void qglLightModelx(GLenum pname, GLfixed param) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glLightModelx(pname=%s, param=%ld)\n", StringFromGLEnumerant( pname ), param); +#endif + glLightModelx(pname, param); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glLightModelx"); +#endif +} + +// void glLightModelxv (GLenum pname, const GLfixed *params); +static inline void qglLightModelxv(GLenum pname, const GLfixed *params) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glLightModelxv(pname=%s, params=%p)\n", StringFromGLEnumerant( pname ), params); +#endif + glLightModelxv(pname, params); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glLightModelxv"); +#endif +} + +// void glLightx (GLenum light, GLenum pname, GLfixed param); +static inline void qglLightx(GLenum light, GLenum pname, GLfixed param) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glLightx(light=%s, pname=%s, param=%ld)\n", StringFromGLEnumerant( light ), StringFromGLEnumerant( pname ), param); +#endif + glLightx(light, pname, param); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glLightx"); +#endif +} + +// void glLightxv (GLenum light, GLenum pname, const GLfixed *params); +static inline void qglLightxv(GLenum light, GLenum pname, const GLfixed *params) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glLightxv(light=%s, pname=%s, params=%p)\n", StringFromGLEnumerant( light ), StringFromGLEnumerant( pname ), params); +#endif + glLightxv(light, pname, params); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glLightxv"); +#endif +} + +// void glLineWidthx (GLfixed width); +static inline void qglLineWidthx(GLfixed width) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glLineWidthx(width=%ld)\n", width); +#endif + glLineWidthx(width); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glLineWidthx"); +#endif +} + +// void glLoadIdentity (void); +static inline void qglLoadIdentity(void) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glLoadIdentity(void)\n"); +#endif + glLoadIdentity(); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glLoadIdentity"); +#endif +} + +// void glLoadMatrixx (const GLfixed *m); +static inline void qglLoadMatrixx(const GLfixed *m) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glLoadMatrixx(m=%p)\n", m); +#endif + glLoadMatrixx(m); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glLoadMatrixx"); +#endif +} + +// void glLogicOp (GLenum opcode); +static inline void qglLogicOp(GLenum opcode) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glLogicOp(opcode=%s)\n", StringFromGLEnumerant( opcode )); +#endif + glLogicOp(opcode); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glLogicOp"); +#endif +} + +// void glMaterialx (GLenum face, GLenum pname, GLfixed param); +static inline void qglMaterialx(GLenum face, GLenum pname, GLfixed param) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glMaterialx(face=%s, pname=%s, param=%ld)\n", StringFromGLEnumerant( face ), StringFromGLEnumerant( pname ), param); +#endif + glMaterialx(face, pname, param); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glMaterialx"); +#endif +} + +// void glMaterialxv (GLenum face, GLenum pname, const GLfixed *params); +static inline void qglMaterialxv(GLenum face, GLenum pname, const GLfixed *params) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glMaterialxv(face=%s, pname=%s, params=%p)\n", StringFromGLEnumerant( face ), StringFromGLEnumerant( pname ), params); +#endif + glMaterialxv(face, pname, params); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glMaterialxv"); +#endif +} + +// void glMatrixMode (GLenum mode); +static inline void qglMatrixMode(GLenum mode) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glMatrixMode(mode=%s)\n", StringFromGLEnumerant( mode )); +#endif + glMatrixMode(mode); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glMatrixMode"); +#endif +} + +// void glMultMatrixx (const GLfixed *m); +static inline void qglMultMatrixx(const GLfixed *m) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glMultMatrixx(m=%p)\n", m); +#endif + glMultMatrixx(m); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glMultMatrixx"); +#endif +} + +// void glMultiTexCoord4x (GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q); +static inline void qglMultiTexCoord4x(GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glMultiTexCoord4x(target=%s, s=%ld, t=%ld, r=%ld, q=%ld)\n", StringFromGLEnumerant( target ), s, t, r, q); +#endif + glMultiTexCoord4x(target, s, t, r, q); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glMultiTexCoord4x"); +#endif +} + +// void glNormal3x (GLfixed nx, GLfixed ny, GLfixed nz); +static inline void qglNormal3x(GLfixed nx, GLfixed ny, GLfixed nz) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glNormal3x(nx=%ld, ny=%ld, nz=%ld)\n", nx, ny, nz); +#endif + glNormal3x(nx, ny, nz); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glNormal3x"); +#endif +} + +// void glNormalPointer (GLenum type, GLsizei stride, const GLvoid *pointer); +static inline void qglNormalPointer(GLenum type, GLsizei stride, const GLvoid *pointer) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glNormalPointer(type=%s, stride=%ld, pointer=%p)\n", StringFromGLEnumerant( type ), stride, pointer); +#endif + glNormalPointer(type, stride, pointer); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glNormalPointer"); +#endif +} + +// void glOrthox (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar); +static inline void qglOrthox(GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glOrthox(left=%ld, right=%ld, bottom=%ld, top=%ld, zNear=%ld, zFar=%ld)\n", left, right, bottom, top, zNear, zFar); +#endif + glOrthox(left, right, bottom, top, zNear, zFar); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glOrthox"); +#endif +} + +// void glPixelStorei (GLenum pname, GLint param); +static inline void qglPixelStorei(GLenum pname, GLint param) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glPixelStorei(pname=%s, param=%ld)\n", StringFromGLEnumerant( pname ), param); +#endif + glPixelStorei(pname, param); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glPixelStorei"); +#endif +} + +// void glPointParameterx (GLenum pname, GLfixed param); +static inline void qglPointParameterx(GLenum pname, GLfixed param) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glPointParameterx(pname=%s, param=%ld)\n", StringFromGLEnumerant( pname ), param); +#endif + glPointParameterx(pname, param); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glPointParameterx"); +#endif +} + +// void glPointParameterxv (GLenum pname, const GLfixed *params); +static inline void qglPointParameterxv(GLenum pname, const GLfixed *params) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glPointParameterxv(pname=%s, params=%p)\n", StringFromGLEnumerant( pname ), params); +#endif + glPointParameterxv(pname, params); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glPointParameterxv"); +#endif +} + +// void glPointSizex (GLfixed size); +static inline void qglPointSizex(GLfixed size) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glPointSizex(size=%ld)\n", size); +#endif + glPointSizex(size); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glPointSizex"); +#endif +} + +// void glPolygonOffsetx (GLfixed factor, GLfixed units); +static inline void qglPolygonOffsetx(GLfixed factor, GLfixed units) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glPolygonOffsetx(factor=%ld, units=%ld)\n", factor, units); +#endif + glPolygonOffsetx(factor, units); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glPolygonOffsetx"); +#endif +} + +// void glPopMatrix (void); +static inline void qglPopMatrix(void) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glPopMatrix(void)\n"); +#endif + glPopMatrix(); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glPopMatrix"); +#endif +} + +// void glPushMatrix (void); +static inline void qglPushMatrix(void) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glPushMatrix(void)\n"); +#endif + glPushMatrix(); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glPushMatrix"); +#endif +} + +// void glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels); +static inline void qglReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glReadPixels(x=%ld, y=%ld, width=%ld, height=%ld, format=%s, type=%s, pixels=%p)\n", x, y, width, height, StringFromGLEnumerant( format ), StringFromGLEnumerant( type ), pixels); +#endif + glReadPixels(x, y, width, height, format, type, pixels); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glReadPixels"); +#endif +} + +// void glRotatex (GLfixed angle, GLfixed x, GLfixed y, GLfixed z); +static inline void qglRotatex(GLfixed angle, GLfixed x, GLfixed y, GLfixed z) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glRotatex(angle=%ld, x=%ld, y=%ld, z=%ld)\n", angle, x, y, z); +#endif + glRotatex(angle, x, y, z); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glRotatex"); +#endif +} + +// void glSampleCoverage (GLclampf value, GLboolean invert); +static inline void qglSampleCoverage(GLclampf value, GLboolean invert) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glSampleCoverage(value=%f, invert=%u)\n", value, invert); +#endif + glSampleCoverage(value, invert); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glSampleCoverage"); +#endif +} + +// void glSampleCoveragex (GLclampx value, GLboolean invert); +static inline void qglSampleCoveragex(GLclampx value, GLboolean invert) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glSampleCoveragex(value=%ld, invert=%u)\n", value, invert); +#endif + glSampleCoveragex(value, invert); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glSampleCoveragex"); +#endif +} + +// void glScalex (GLfixed x, GLfixed y, GLfixed z); +static inline void qglScalex(GLfixed x, GLfixed y, GLfixed z) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glScalex(x=%ld, y=%ld, z=%ld)\n", x, y, z); +#endif + glScalex(x, y, z); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glScalex"); +#endif +} + +// void glScissor (GLint x, GLint y, GLsizei width, GLsizei height); +static inline void qglScissor(GLint x, GLint y, GLsizei width, GLsizei height) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glScissor(x=%ld, y=%ld, width=%ld, height=%ld)\n", x, y, width, height); +#endif + // fixme + int vidHeight = 320; +glScissor(vidHeight - y - height, x, height, width); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glScissor"); +#endif +} + +// void glShadeModel (GLenum mode); +static inline void qglShadeModel(GLenum mode) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glShadeModel(mode=%s)\n", StringFromGLEnumerant( mode )); +#endif + glShadeModel(mode); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glShadeModel"); +#endif +} + +// void glStencilFunc (GLenum func, GLint ref, GLuint mask); +static inline void qglStencilFunc(GLenum func, GLint ref, GLuint mask) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glStencilFunc(func=%s, ref=%ld, mask=%lu)\n", StringFromGLEnumerant( func ), ref, mask); +#endif + glStencilFunc(func, ref, mask); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glStencilFunc"); +#endif +} + +// void glStencilMask (GLuint mask); +static inline void qglStencilMask(GLuint mask) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glStencilMask(mask=%lu)\n", mask); +#endif + glStencilMask(mask); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glStencilMask"); +#endif +} + +// void glStencilOp (GLenum fail, GLenum zfail, GLenum zpass); +static inline void qglStencilOp(GLenum fail, GLenum zfail, GLenum zpass) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glStencilOp(fail=%s, zfail=%s, zpass=%s)\n", StringFromGLEnumerant( fail ), StringFromGLEnumerant( zfail ), StringFromGLEnumerant( zpass )); +#endif + glStencilOp(fail, zfail, zpass); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glStencilOp"); +#endif +} + +// void glTexCoordPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +static inline void qglTexCoordPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glTexCoordPointer(size=%ld, type=%s, stride=%ld, pointer=%p)\n", size, StringFromGLEnumerant( type ), stride, pointer); +#endif + glTexCoordPointer(size, type, stride, pointer); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glTexCoordPointer"); +#endif +} + +// void glTexEnvi (GLenum target, GLenum pname, GLint param); +static inline void qglTexEnvi(GLenum target, GLenum pname, GLint param) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glTexEnvi(target=%s, pname=%s, param=%ld)\n", StringFromGLEnumerant( target ), StringFromGLEnumerant( pname ), param); +#endif + glTexEnvi(target, pname, param); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glTexEnvi"); +#endif +} + +// void glTexEnvx (GLenum target, GLenum pname, GLfixed param); +static inline void qglTexEnvx(GLenum target, GLenum pname, GLfixed param) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glTexEnvx(target=%s, pname=%s, param=%ld)\n", StringFromGLEnumerant( target ), StringFromGLEnumerant( pname ), param); +#endif + glTexEnvx(target, pname, param); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glTexEnvx"); +#endif +} + +// void glTexEnviv (GLenum target, GLenum pname, const GLint *params); +static inline void qglTexEnviv(GLenum target, GLenum pname, const GLint *params) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glTexEnviv(target=%s, pname=%s, params=%p)\n", StringFromGLEnumerant( target ), StringFromGLEnumerant( pname ), params); +#endif + glTexEnviv(target, pname, params); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glTexEnviv"); +#endif +} + +// void glTexEnvxv (GLenum target, GLenum pname, const GLfixed *params); +static inline void qglTexEnvxv(GLenum target, GLenum pname, const GLfixed *params) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glTexEnvxv(target=%s, pname=%s, params=%p)\n", StringFromGLEnumerant( target ), StringFromGLEnumerant( pname ), params); +#endif + glTexEnvxv(target, pname, params); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glTexEnvxv"); +#endif +} + +// void glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +static inline void qglTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glTexImage2D(target=%s, level=%ld, internalformat=%ld, width=%ld, height=%ld, border=%ld, format=%s, type=%s, pixels=%p)\n", StringFromGLEnumerant( target ), level, internalformat, width, height, border, StringFromGLEnumerant( format ), StringFromGLEnumerant( type ), pixels); +#endif + glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glTexImage2D"); +#endif +} + +// void glTexParameteri (GLenum target, GLenum pname, GLint param); +static inline void qglTexParameteri(GLenum target, GLenum pname, GLint param) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glTexParameteri(target=%s, pname=%s, param=%ld)\n", StringFromGLEnumerant( target ), StringFromGLEnumerant( pname ), param); +#endif + glTexParameteri(target, pname, param); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glTexParameteri"); +#endif +} + +// void glTexParameterx (GLenum target, GLenum pname, GLfixed param); +static inline void qglTexParameterx(GLenum target, GLenum pname, GLfixed param) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glTexParameterx(target=%s, pname=%s, param=%ld)\n", StringFromGLEnumerant( target ), StringFromGLEnumerant( pname ), param); +#endif + glTexParameterx(target, pname, param); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glTexParameterx"); +#endif +} + +// void glTexParameteriv (GLenum target, GLenum pname, const GLint *params); +static inline void qglTexParameteriv(GLenum target, GLenum pname, const GLint *params) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glTexParameteriv(target=%s, pname=%s, params=%p)\n", StringFromGLEnumerant( target ), StringFromGLEnumerant( pname ), params); +#endif + glTexParameteriv(target, pname, params); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glTexParameteriv"); +#endif +} + +// void glTexParameterxv (GLenum target, GLenum pname, const GLfixed *params); +static inline void qglTexParameterxv(GLenum target, GLenum pname, const GLfixed *params) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glTexParameterxv(target=%s, pname=%s, params=%p)\n", StringFromGLEnumerant( target ), StringFromGLEnumerant( pname ), params); +#endif + glTexParameterxv(target, pname, params); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glTexParameterxv"); +#endif +} + +// void glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +static inline void qglTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glTexSubImage2D(target=%s, level=%ld, xoffset=%ld, yoffset=%ld, width=%ld, height=%ld, format=%s, type=%s, pixels=%p)\n", StringFromGLEnumerant( target ), level, xoffset, yoffset, width, height, StringFromGLEnumerant( format ), StringFromGLEnumerant( type ), pixels); +#endif + glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glTexSubImage2D"); +#endif +} + +// void glTranslatex (GLfixed x, GLfixed y, GLfixed z); +static inline void qglTranslatex(GLfixed x, GLfixed y, GLfixed z) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glTranslatex(x=%ld, y=%ld, z=%ld)\n", x, y, z); +#endif + glTranslatex(x, y, z); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glTranslatex"); +#endif +} + +// void glVertexPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +static inline void qglVertexPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glVertexPointer(size=%ld, type=%s, stride=%ld, pointer=%p)\n", size, StringFromGLEnumerant( type ), stride, pointer); +#endif + glVertexPointer(size, type, stride, pointer); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glVertexPointer"); +#endif +} + +// void glViewport (GLint x, GLint y, GLsizei width, GLsizei height); +static inline void qglViewport(GLint x, GLint y, GLsizei width, GLsizei height) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glViewport(x=%ld, y=%ld, width=%ld, height=%ld)\n", x, y, width, height); +#endif +//extern glconfig_t glConfig; + int vidHeight = 320; + glViewport(vidHeight - y - height, x, height, width); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glViewport"); +#endif +} + +// void glCurrentPaletteMatrixOES (GLuint matrixpaletteindex); +static inline void qglCurrentPaletteMatrixOES(GLuint matrixpaletteindex) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glCurrentPaletteMatrixOES(matrixpaletteindex=%lu)\n", matrixpaletteindex); +#endif + glCurrentPaletteMatrixOES(matrixpaletteindex); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glCurrentPaletteMatrixOES"); +#endif +} + +// void glLoadPaletteFromModelViewMatrixOES (void); +static inline void qglLoadPaletteFromModelViewMatrixOES(void) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glLoadPaletteFromModelViewMatrixOES(void)\n"); +#endif + glLoadPaletteFromModelViewMatrixOES(); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glLoadPaletteFromModelViewMatrixOES"); +#endif +} + +// void glMatrixIndexPointerOES (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +static inline void qglMatrixIndexPointerOES(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glMatrixIndexPointerOES(size=%ld, type=%s, stride=%ld, pointer=%p)\n", size, StringFromGLEnumerant( type ), stride, pointer); +#endif + glMatrixIndexPointerOES(size, type, stride, pointer); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glMatrixIndexPointerOES"); +#endif +} + +// void glWeightPointerOES (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +static inline void qglWeightPointerOES(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glWeightPointerOES(size=%ld, type=%s, stride=%ld, pointer=%p)\n", size, StringFromGLEnumerant( type ), stride, pointer); +#endif + glWeightPointerOES(size, type, stride, pointer); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glWeightPointerOES"); +#endif +} + +// void glPointSizePointerOES (GLenum type, GLsizei stride, const GLvoid *pointer); +static inline void qglPointSizePointerOES(GLenum type, GLsizei stride, const GLvoid *pointer) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glPointSizePointerOES(type=%s, stride=%ld, pointer=%p)\n", StringFromGLEnumerant( type ), stride, pointer); +#endif + glPointSizePointerOES(type, stride, pointer); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glPointSizePointerOES"); +#endif +} + +// void glDrawTexsOES (GLshort x, GLshort y, GLshort z, GLshort width, GLshort height); +static inline void qglDrawTexsOES(GLshort x, GLshort y, GLshort z, GLshort width, GLshort height) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glDrawTexsOES(x=%d, y=%d, z=%d, width=%d, height=%d)\n", x, y, z, width, height); +#endif + glDrawTexsOES(x, y, z, width, height); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glDrawTexsOES"); +#endif +} + +// void glDrawTexiOES (GLint x, GLint y, GLint z, GLint width, GLint height); +static inline void qglDrawTexiOES(GLint x, GLint y, GLint z, GLint width, GLint height) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glDrawTexiOES(x=%ld, y=%ld, z=%ld, width=%ld, height=%ld)\n", x, y, z, width, height); +#endif + glDrawTexiOES(x, y, z, width, height); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glDrawTexiOES"); +#endif +} + +// void glDrawTexxOES (GLfixed x, GLfixed y, GLfixed z, GLfixed width, GLfixed height); +static inline void qglDrawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed width, GLfixed height) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glDrawTexxOES(x=%ld, y=%ld, z=%ld, width=%ld, height=%ld)\n", x, y, z, width, height); +#endif + glDrawTexxOES(x, y, z, width, height); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glDrawTexxOES"); +#endif +} + +// void glDrawTexsvOES (const GLshort *coords); +static inline void qglDrawTexsvOES(const GLshort *coords) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glDrawTexsvOES(coords=%p)\n", coords); +#endif + glDrawTexsvOES(coords); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glDrawTexsvOES"); +#endif +} + +// void glDrawTexivOES (const GLint *coords); +static inline void qglDrawTexivOES(const GLint *coords) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glDrawTexivOES(coords=%p)\n", coords); +#endif + glDrawTexivOES(coords); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glDrawTexivOES"); +#endif +} + +// void glDrawTexxvOES (const GLfixed *coords); +static inline void qglDrawTexxvOES(const GLfixed *coords) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glDrawTexxvOES(coords=%p)\n", coords); +#endif + glDrawTexxvOES(coords); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glDrawTexxvOES"); +#endif +} + +// void glDrawTexfOES (GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height); +static inline void qglDrawTexfOES(GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glDrawTexfOES(x=%f, y=%f, z=%f, width=%f, height=%f)\n", x, y, z, width, height); +#endif + glDrawTexfOES(x, y, z, width, height); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glDrawTexfOES"); +#endif +} + +// void glDrawTexfvOES (const GLfloat *coords); +static inline void qglDrawTexfvOES(const GLfloat *coords) +{ +#if !defined(NDEBUG) && defined(QGL_LOG_GL_CALLS) + if (QGLLogGLCalls) + fprintf(QGLDebugFile(), "glDrawTexfvOES(coords=%p)\n", coords); +#endif + glDrawTexfvOES(coords); +#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS) + if (!QGLBeginStarted) + QGLCheckError("glDrawTexfvOES"); +#endif +} + +// Prevent calls to the 'normal' GL functions +#define glAlphaFunc CALL_THE_QGL_VERSION_OF_glAlphaFunc +#define glClearColor CALL_THE_QGL_VERSION_OF_glClearColor +#define glClearDepthf CALL_THE_QGL_VERSION_OF_glClearDepthf +#define glClipPlanef CALL_THE_QGL_VERSION_OF_glClipPlanef +#define glDepthRangef CALL_THE_QGL_VERSION_OF_glDepthRangef +#define glFogf CALL_THE_QGL_VERSION_OF_glFogf +#define glFogfv CALL_THE_QGL_VERSION_OF_glFogfv +#define glFrustumf CALL_THE_QGL_VERSION_OF_glFrustumf +#define glGetClipPlanef CALL_THE_QGL_VERSION_OF_glGetClipPlanef +#define glGetFloatv CALL_THE_QGL_VERSION_OF_glGetFloatv +#define glGetLightfv CALL_THE_QGL_VERSION_OF_glGetLightfv +#define glGetMaterialfv CALL_THE_QGL_VERSION_OF_glGetMaterialfv +#define glGetTexEnvfv CALL_THE_QGL_VERSION_OF_glGetTexEnvfv +#define glGetTexParameterfv CALL_THE_QGL_VERSION_OF_glGetTexParameterfv +#define glLightModelf CALL_THE_QGL_VERSION_OF_glLightModelf +#define glLightModelfv CALL_THE_QGL_VERSION_OF_glLightModelfv +#define glLightf CALL_THE_QGL_VERSION_OF_glLightf +#define glLightfv CALL_THE_QGL_VERSION_OF_glLightfv +#define glLineWidth CALL_THE_QGL_VERSION_OF_glLineWidth +#define glLoadMatrixf CALL_THE_QGL_VERSION_OF_glLoadMatrixf +#define glMaterialf CALL_THE_QGL_VERSION_OF_glMaterialf +#define glMaterialfv CALL_THE_QGL_VERSION_OF_glMaterialfv +#define glMultMatrixf CALL_THE_QGL_VERSION_OF_glMultMatrixf +#define glMultiTexCoord4f CALL_THE_QGL_VERSION_OF_glMultiTexCoord4f +#define glNormal3f CALL_THE_QGL_VERSION_OF_glNormal3f +#define glOrthof CALL_THE_QGL_VERSION_OF_glOrthof +#define glPointParameterf CALL_THE_QGL_VERSION_OF_glPointParameterf +#define glPointParameterfv CALL_THE_QGL_VERSION_OF_glPointParameterfv +#define glPointSize CALL_THE_QGL_VERSION_OF_glPointSize +#define glPolygonOffset CALL_THE_QGL_VERSION_OF_glPolygonOffset +#define glRotatef CALL_THE_QGL_VERSION_OF_glRotatef +#define glScalef CALL_THE_QGL_VERSION_OF_glScalef +#define glTexEnvf CALL_THE_QGL_VERSION_OF_glTexEnvf +#define glTexEnvfv CALL_THE_QGL_VERSION_OF_glTexEnvfv +#define glTexParameterf CALL_THE_QGL_VERSION_OF_glTexParameterf +#define glTexParameterfv CALL_THE_QGL_VERSION_OF_glTexParameterfv +#define glTranslatef CALL_THE_QGL_VERSION_OF_glTranslatef +#define glActiveTexture CALL_THE_QGL_VERSION_OF_glActiveTexture +#define glAlphaFuncx CALL_THE_QGL_VERSION_OF_glAlphaFuncx +#define glBindBuffer CALL_THE_QGL_VERSION_OF_glBindBuffer +#define glBindTexture CALL_THE_QGL_VERSION_OF_glBindTexture +#define glBlendFunc CALL_THE_QGL_VERSION_OF_glBlendFunc +#define glBufferData CALL_THE_QGL_VERSION_OF_glBufferData +#define glBufferSubData CALL_THE_QGL_VERSION_OF_glBufferSubData +#define glClear CALL_THE_QGL_VERSION_OF_glClear +#define glClearColorx CALL_THE_QGL_VERSION_OF_glClearColorx +#define glClearDepthx CALL_THE_QGL_VERSION_OF_glClearDepthx +#define glClearStencil CALL_THE_QGL_VERSION_OF_glClearStencil +#define glClientActiveTexture CALL_THE_QGL_VERSION_OF_glClientActiveTexture +#define glClipPlanex CALL_THE_QGL_VERSION_OF_glClipPlanex +#define glColor4ub CALL_THE_QGL_VERSION_OF_glColor4ub +#define glColor4x CALL_THE_QGL_VERSION_OF_glColor4x +#define glColorMask CALL_THE_QGL_VERSION_OF_glColorMask +#define glColorPointer CALL_THE_QGL_VERSION_OF_glColorPointer +#define glCompressedTexImage2D CALL_THE_QGL_VERSION_OF_glCompressedTexImage2D +#define glCompressedTexSubImage2D CALL_THE_QGL_VERSION_OF_glCompressedTexSubImage2D +#define glCopyTexImage2D CALL_THE_QGL_VERSION_OF_glCopyTexImage2D +#define glCopyTexSubImage2D CALL_THE_QGL_VERSION_OF_glCopyTexSubImage2D +#define glCullFace CALL_THE_QGL_VERSION_OF_glCullFace +#define glDeleteBuffers CALL_THE_QGL_VERSION_OF_glDeleteBuffers +#define glDeleteTextures CALL_THE_QGL_VERSION_OF_glDeleteTextures +#define glDepthFunc CALL_THE_QGL_VERSION_OF_glDepthFunc +#define glDepthMask CALL_THE_QGL_VERSION_OF_glDepthMask +#define glDepthRangex CALL_THE_QGL_VERSION_OF_glDepthRangex +#define glDisable CALL_THE_QGL_VERSION_OF_glDisable +#define glDisableClientState CALL_THE_QGL_VERSION_OF_glDisableClientState +#define glDrawArrays CALL_THE_QGL_VERSION_OF_glDrawArrays +#define glDrawElements CALL_THE_QGL_VERSION_OF_glDrawElements +#define glEnable CALL_THE_QGL_VERSION_OF_glEnable +#define glEnableClientState CALL_THE_QGL_VERSION_OF_glEnableClientState +#define glFinish CALL_THE_QGL_VERSION_OF_glFinish +#define glFlush CALL_THE_QGL_VERSION_OF_glFlush +#define glFogx CALL_THE_QGL_VERSION_OF_glFogx +#define glFogxv CALL_THE_QGL_VERSION_OF_glFogxv +#define glFrontFace CALL_THE_QGL_VERSION_OF_glFrontFace +#define glFrustumx CALL_THE_QGL_VERSION_OF_glFrustumx +#define glGetBooleanv CALL_THE_QGL_VERSION_OF_glGetBooleanv +#define glGetBufferParameteriv CALL_THE_QGL_VERSION_OF_glGetBufferParameteriv +#define glGetClipPlanex CALL_THE_QGL_VERSION_OF_glGetClipPlanex +#define glGenBuffers CALL_THE_QGL_VERSION_OF_glGenBuffers +#define glGenTextures CALL_THE_QGL_VERSION_OF_glGenTextures +#define glGetError CALL_THE_QGL_VERSION_OF_glGetError +#define glGetFixedv CALL_THE_QGL_VERSION_OF_glGetFixedv +#define glGetIntegerv CALL_THE_QGL_VERSION_OF_glGetIntegerv +#define glGetLightxv CALL_THE_QGL_VERSION_OF_glGetLightxv +#define glGetMaterialxv CALL_THE_QGL_VERSION_OF_glGetMaterialxv +#define glGetPointerv CALL_THE_QGL_VERSION_OF_glGetPointerv +#define glGetString CALL_THE_QGL_VERSION_OF_glGetString +#define glGetTexEnviv CALL_THE_QGL_VERSION_OF_glGetTexEnviv +#define glGetTexEnvxv CALL_THE_QGL_VERSION_OF_glGetTexEnvxv +#define glGetTexParameteriv CALL_THE_QGL_VERSION_OF_glGetTexParameteriv +#define glGetTexParameterxv CALL_THE_QGL_VERSION_OF_glGetTexParameterxv +#define glHint CALL_THE_QGL_VERSION_OF_glHint +#define glIsBuffer CALL_THE_QGL_VERSION_OF_glIsBuffer +#define glIsEnabled CALL_THE_QGL_VERSION_OF_glIsEnabled +#define glIsTexture CALL_THE_QGL_VERSION_OF_glIsTexture +#define glLightModelx CALL_THE_QGL_VERSION_OF_glLightModelx +#define glLightModelxv CALL_THE_QGL_VERSION_OF_glLightModelxv +#define glLightx CALL_THE_QGL_VERSION_OF_glLightx +#define glLightxv CALL_THE_QGL_VERSION_OF_glLightxv +#define glLineWidthx CALL_THE_QGL_VERSION_OF_glLineWidthx +#define glLoadIdentity CALL_THE_QGL_VERSION_OF_glLoadIdentity +#define glLoadMatrixx CALL_THE_QGL_VERSION_OF_glLoadMatrixx +#define glLogicOp CALL_THE_QGL_VERSION_OF_glLogicOp +#define glMaterialx CALL_THE_QGL_VERSION_OF_glMaterialx +#define glMaterialxv CALL_THE_QGL_VERSION_OF_glMaterialxv +#define glMatrixMode CALL_THE_QGL_VERSION_OF_glMatrixMode +#define glMultMatrixx CALL_THE_QGL_VERSION_OF_glMultMatrixx +#define glMultiTexCoord4x CALL_THE_QGL_VERSION_OF_glMultiTexCoord4x +#define glNormal3x CALL_THE_QGL_VERSION_OF_glNormal3x +#define glNormalPointer CALL_THE_QGL_VERSION_OF_glNormalPointer +#define glOrthox CALL_THE_QGL_VERSION_OF_glOrthox +#define glPixelStorei CALL_THE_QGL_VERSION_OF_glPixelStorei +#define glPointParameterx CALL_THE_QGL_VERSION_OF_glPointParameterx +#define glPointParameterxv CALL_THE_QGL_VERSION_OF_glPointParameterxv +#define glPointSizex CALL_THE_QGL_VERSION_OF_glPointSizex +#define glPolygonOffsetx CALL_THE_QGL_VERSION_OF_glPolygonOffsetx +#define glPopMatrix CALL_THE_QGL_VERSION_OF_glPopMatrix +#define glPushMatrix CALL_THE_QGL_VERSION_OF_glPushMatrix +#define glReadPixels CALL_THE_QGL_VERSION_OF_glReadPixels +#define glRotatex CALL_THE_QGL_VERSION_OF_glRotatex +#define glSampleCoverage CALL_THE_QGL_VERSION_OF_glSampleCoverage +#define glSampleCoveragex CALL_THE_QGL_VERSION_OF_glSampleCoveragex +#define glScalex CALL_THE_QGL_VERSION_OF_glScalex +#define glScissor CALL_THE_QGL_VERSION_OF_glScissor +#define glShadeModel CALL_THE_QGL_VERSION_OF_glShadeModel +#define glStencilFunc CALL_THE_QGL_VERSION_OF_glStencilFunc +#define glStencilMask CALL_THE_QGL_VERSION_OF_glStencilMask +#define glStencilOp CALL_THE_QGL_VERSION_OF_glStencilOp +#define glTexCoordPointer CALL_THE_QGL_VERSION_OF_glTexCoordPointer +#define glTexEnvi CALL_THE_QGL_VERSION_OF_glTexEnvi +#define glTexEnvx CALL_THE_QGL_VERSION_OF_glTexEnvx +#define glTexEnviv CALL_THE_QGL_VERSION_OF_glTexEnviv +#define glTexEnvxv CALL_THE_QGL_VERSION_OF_glTexEnvxv +#define glTexImage2D CALL_THE_QGL_VERSION_OF_glTexImage2D +#define glTexParameteri CALL_THE_QGL_VERSION_OF_glTexParameteri +#define glTexParameterx CALL_THE_QGL_VERSION_OF_glTexParameterx +#define glTexParameteriv CALL_THE_QGL_VERSION_OF_glTexParameteriv +#define glTexParameterxv CALL_THE_QGL_VERSION_OF_glTexParameterxv +#define glTexSubImage2D CALL_THE_QGL_VERSION_OF_glTexSubImage2D +#define glTranslatex CALL_THE_QGL_VERSION_OF_glTranslatex +#define glVertexPointer CALL_THE_QGL_VERSION_OF_glVertexPointer +#define glViewport CALL_THE_QGL_VERSION_OF_glViewport +#define glCurrentPaletteMatrixOES CALL_THE_QGL_VERSION_OF_glCurrentPaletteMatrixOES +#define glLoadPaletteFromModelViewMatrixOES CALL_THE_QGL_VERSION_OF_glLoadPaletteFromModelViewMatrixOES +#define glMatrixIndexPointerOES CALL_THE_QGL_VERSION_OF_glMatrixIndexPointerOES +#define glWeightPointerOES CALL_THE_QGL_VERSION_OF_glWeightPointerOES +#define glPointSizePointerOES CALL_THE_QGL_VERSION_OF_glPointSizePointerOES +#define glDrawTexsOES CALL_THE_QGL_VERSION_OF_glDrawTexsOES +#define glDrawTexiOES CALL_THE_QGL_VERSION_OF_glDrawTexiOES +#define glDrawTexxOES CALL_THE_QGL_VERSION_OF_glDrawTexxOES +#define glDrawTexsvOES CALL_THE_QGL_VERSION_OF_glDrawTexsvOES +#define glDrawTexivOES CALL_THE_QGL_VERSION_OF_glDrawTexivOES +#define glDrawTexxvOES CALL_THE_QGL_VERSION_OF_glDrawTexxvOES +#define glDrawTexfOES CALL_THE_QGL_VERSION_OF_glDrawTexfOES +#define glDrawTexfvOES CALL_THE_QGL_VERSION_OF_glDrawTexfvOES + +#endif // _IPHONE_QGL_H_ diff --git a/common/ios/doomengine/iphone_qgl_enumerants.h b/common/ios/doomengine/iphone_qgl_enumerants.h new file mode 100755 index 0000000..01892dd --- /dev/null +++ b/common/ios/doomengine/iphone_qgl_enumerants.h @@ -0,0 +1,40 @@ +/* + + Copyright (C) 2009 Id Software, 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 + 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. + + */ + +#ifndef IPHONE_QGL_ENUMERANTS_H +#define IPHONE_QGL_ENUMERANTS_H + +#ifdef QGL_LOG_GL_CALLS + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + const char *StringFromGLEnumerant( GLenum enumerant ); + +#ifdef __cplusplus +} +#endif + +#endif // QGL_LOG_GL_CALLS + +#endif // IPHONE_QGL_ENUMERANTS_H \ No newline at end of file diff --git a/common/ios/doomengine/iphone_render.c b/common/ios/doomengine/iphone_render.c new file mode 100755 index 0000000..b6e3274 --- /dev/null +++ b/common/ios/doomengine/iphone_render.c @@ -0,0 +1,1765 @@ +/* + * iphoneRender.c + * doom + * + * Created by John Carmack on 4/29/09. + * Copyright 2009 id Software. All rights reserved. + * + */ +/* + + Copyright (C) 2009 Id Software, 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 + 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 "SDL_opengl.h" +#include "doomtype.h" +#include "w_wad.h" +#include "m_argv.h" +#include "d_event.h" +#include "v_video.h" +#include "doomstat.h" +#include "r_bsp.h" +#include "r_main.h" +#include "r_draw.h" +#include "r_sky.h" +#include "r_plane.h" +#include "r_data.h" +#include "r_things.h" +#include "r_fps.h" +#include "p_maputl.h" +#include "m_bbox.h" +#include "lprintf.h" +#include "gl_intern.h" +#include "gl_struct.h" + +// If the Doom levels had been built with realistic visibility +// taken into account for the sky areas, we could just draw the +// sky first and then the walls, but that gives artifacts where +// you see some sectors floating in the sky now. This causes +// the walls to draw extended top and bottom sections for skies. +#define SKYWALLS + +#define MINZ (FRACUNIT*4) +#define BASEYCENTER 100 +#define MINZ_FLOAT 4 + +typedef struct { + GLTexture *tex; + side_t *side; + int flag; // GLDWF_TOP, GLDWF_M1S, etc +} sortLine_t; + +#define MAX_SORT_LINES 4096 +sortLine_t sortLines[MAX_SORT_LINES]; +int numSortLines; + +typedef struct { + GLTexture *texture; + sector_t *sector; + boolean ceiling; +} sortSectorPlane_t; + +#define MAX_SECTOR_PLANES 1024 +sortSectorPlane_t sectorPlanes[MAX_SECTOR_PLANES]; +int numSectorPlanes; + +typedef struct { + GLTexture *tex; +} sortSprite_t; + +// Cleared to 0 at frame start. +// Individual columns will be set to 1 as occluding segments are processed. +// An occluding segment is either a one-sided line, a line that has a back +// sector with equal floor and ceiling heights, a line with a back ceiling +// height lower than the fron floor height, or a line with a back floor height +// higher than the front ceiling height. +// Entire nodes are culled when their bounds does not include a 0 column. +// Individual line segments are culled when their span does not include 0 columns. +// Sprites could be checked against it, but it may not be worth it. +char occlusion[MAX_SCREENWIDTH+2]; // +2 for guard columns to avoid clamping + +// when the iphone is upside down, the occlusion segments are reversed +boolean reversedLandscape; + +// this matrix is exactly what GL uses, but there will still +// be floating point differences between the GPU and CPU +float glMVPmatrix[16]; + +// if any sector textures are the sky texture, we will draw the sky and +// ignore those sector geometries +boolean skyIsVisible; + +// these should really be initialized based on viewwidth somewhere... +float halfWidthFloat = 240.0f; + +// used during debugging to isolate incorrect culling +int failCount; + +// Some of the two sided line segments in the original game don't have a valid +// texture, so stick something there instead of leaving a gaping hole in the world. +GLTexture *defaultTexture; + +// just for the sky texture setup +float yaw; + +// counters +int c_occludedSprites; +int c_sectors; +int c_subsectors; + +// test options +int testClear = 0; +int testNewRenderer = 0; +int showRenderTime; +int blendAll; + + +void BuildIndexedTriangles(); +void BuildSideSegs(); + +void IR_MergeSectors( int fromSector, int intoSector ) { + // E3M8 (and possibly others somewhere) has a bad sector + // classification with two stray lines in sector 2 that + // should be a part of sector 1. This makes both of the + // sectors "broken" and unable to be properly tesselated. + assert( (unsigned)fromSector < numsectors ); + assert( (unsigned)intoSector < numsectors ); + sector_t *fromSectorPtr = §ors[fromSector]; + sector_t *intoSectorPtr = §ors[intoSector]; + + int moveLines = 0; + for ( int i = 0 ; i < numlines ; i++ ) { + if ( lines[i].frontsector == fromSectorPtr ) { + moveLines++; + } else if ( lines[i].backsector == fromSectorPtr ) { + moveLines++; + } + } + + // add these lines to intoSector + // Unfortunately, the sector->lines list is not allocated per-sector, but + // is a single block for the entire level, so we can't realloc it. I'm + // going to just let the new table leak. + line_t **newLines = Z_Malloc( ( intoSectorPtr->linecount + moveLines ) * sizeof( *intoSectorPtr->lines ), + PU_LEVEL,0); + memcpy( newLines, intoSectorPtr->lines, intoSectorPtr->linecount * sizeof( *newLines ) ); + intoSectorPtr->lines = newLines; + for ( int i = 0 ; i < numlines ; i++ ) { + if ( lines[i].frontsector == fromSectorPtr ) { + intoSectorPtr->lines[intoSectorPtr->linecount++] = &lines[i]; + lines[i].frontsector = intoSectorPtr; + } else if ( lines[i].backsector == fromSectorPtr ) { + intoSectorPtr->lines[intoSectorPtr->linecount++] = &lines[i]; + lines[i].backsector = intoSectorPtr; + } + } + + // change all the segs + for ( int i = 0 ; i < numsegs ; i++ ) { + if ( segs[i].frontsector == fromSectorPtr ) { + segs[i].frontsector = intoSectorPtr; + } + if ( segs[i].backsector == fromSectorPtr ) { + segs[i].backsector = intoSectorPtr; + } + } + + // change all the sides to point to the new one + for ( int i = 0 ; i < numsides ; i++ ) { + if ( sides[i].sector == fromSectorPtr ) { + sides[i].sector = intoSectorPtr; + } + } + + // change all the subsectors to point to the new one + for ( int i = 0 ; i < numsubsectors ; i++ ) { + if ( subsectors[i].sector == fromSectorPtr ) { + subsectors[i].sector = intoSectorPtr; + } + } + + + // make fromSector vestigial so it doesn't get tesselated + fromSectorPtr->linecount = 0; +} + +void IR_InitLevel() { + BuildIndexedTriangles(); // convert the loops into indexed triangles + BuildSideSegs(); // create a seg_t for each side_t so we can draw the + // unclipped versions that fit perfectly with the sectors + + // find something else used in the level for a default texture + for ( int i = 0 ; i < numsides ; i++ ) { + if ( sides[i].toptexture ) { + defaultTexture=gld_RegisterTexture(sides[i].toptexture, true, false); + if ( defaultTexture ) { + break; + } + } + } + assert( defaultTexture ); +} + + +float lightDistance = 10.0f; // in prBoom MAP_SCALE units, increasing this makes things get dimmer faster +#define MAX_LIGHT_DROP 96 +float lightingVector[3]; // transform and scale [ x y 1 ] to get color units to subtract +static int FadedLighting( float x, float y, int sectorLightLevel ) { + // Ramp down the lightover lightDistance world units. + // Triangles that extend across behind the view origin and past + // the lightDistance clamping boundary will not have completely linear fading, + // but nobody should notice. + + // A proportional drop in lighting sounds like a better idea, but + // this linear drop seems to look nicer. It's not like Doom's + // lighting is realistic in any case... + + int idist = x * lightingVector[0] + y * lightingVector[1] + lightingVector[2]; + if ( idist < 0 ) { + idist = 0; + } else if ( idist > MAX_LIGHT_DROP ) { + idist = MAX_LIGHT_DROP; + } + sectorLightLevel -= idist; + if ( sectorLightLevel < 0 ) { + sectorLightLevel = 0; + } + if ( sectorLightLevel > 255 ) { + sectorLightLevel = 255; + } + return sectorLightLevel | (sectorLightLevel<<8) | (sectorLightLevel<<16) | (255<<24); +} + + +// +// IR_ProjectSprite +// Generates a vissprite for a thing if it might be visible. +// + +static void IR_ProjectSprite (mobj_t* thing, int lightlevel) +{ + fixed_t gzt; // killough 3/27/98 + fixed_t tx; + fixed_t xscale; + int x1; + int x2; + spritedef_t *sprdef; + spriteframe_t *sprframe; + int lump; + boolean flip; + + // transform the origin point + fixed_t tr_x, tr_y; + fixed_t fx, fy, fz; + fixed_t gxt, gyt; + fixed_t tz; + int width; + + fx = thing->x; + fy = thing->y; + fz = thing->z; + + tr_x = fx - viewx; + tr_y = fy - viewy; + + gxt = FixedMul(tr_x,viewcos); + gyt = -FixedMul(tr_y,viewsin); + + tz = gxt-gyt; + + // thing is behind view plane? + if (tz < MINZ) + return; + + xscale = FixedDiv(projection, tz); + + gxt = -FixedMul(tr_x,viewsin); + gyt = FixedMul(tr_y,viewcos); + tx = -(gyt+gxt); + + // too far off the side? + if (D_abs(tx)>(tz<<2)) + return; + + // decide which patch to use for sprite relative to player +#ifdef RANGECHECK + if ((unsigned) thing->sprite >= (unsigned)numsprites) + I_Error ("R_ProjectSprite: Invalid sprite number %i", thing->sprite); +#endif + + sprdef = &sprites[thing->sprite]; + +#ifdef RANGECHECK + if ((thing->frame&FF_FRAMEMASK) >= sprdef->numframes) + I_Error ("R_ProjectSprite: Invalid sprite frame %i : %i", thing->sprite, + thing->frame); +#endif + + if (!sprdef->spriteframes) + I_Error ("R_ProjectSprite: Missing spriteframes %i : %i", thing->sprite, + thing->frame); + + sprframe = &sprdef->spriteframes[thing->frame & FF_FRAMEMASK]; + + if (sprframe->rotate) + { + // choose a different rotation based on player view + // JDC: this could be better... + angle_t ang = R_PointToAngle(fx, fy); + unsigned rot = (ang-thing->angle+(unsigned)(ANG45/2)*9)>>29; + lump = sprframe->lump[rot]; + flip = (boolean) sprframe->flip[rot]; + } + else + { + // use single rotation for all views + lump = sprframe->lump[0]; + flip = (boolean) sprframe->flip[0]; + } + + { + const rpatch_t* patch = R_CachePatchNum(lump+firstspritelump); + + /* calculate edges of the shape + * cph 2003/08/1 - fraggle points out that this offset must be flipped + * if the sprite is flipped; e.g. FreeDoom imp is messed up by this. */ + if (flip) { + tx -= (patch->width - patch->leftoffset) << FRACBITS; + } else { + tx -= patch->leftoffset << FRACBITS; + } + x1 = (centerxfrac + FixedMul(tx,xscale)) >> FRACBITS; + + tx += patch->width<> FRACBITS) - 1; + + gzt = fz + (patch->topoffset << FRACBITS); + width = patch->width; + + // JDC: we don't care if they never get freed, + // so don't bother changing the zone tag status each time + //R_UnlockPatchNum(lump+firstspritelump); + } + + // off the side? + if (x1 > viewwidth || x2 < 0) + return; + + // killough 4/9/98: clip things which are out of view due to height + // e6y: fix of hanging decoration disappearing in Batman Doom MAP02 + // centeryfrac -> viewheightfrac + if (fz > viewz + FixedDiv(viewheightfrac, xscale) || + gzt < viewz - FixedDiv(viewheightfrac-viewheight, xscale)) + return; + + // JDC: clip to the occlusio buffer + int testLow = x1 < 0 ? 0 : x1; + int testHigh = x2 >= viewwidth ? viewwidth - 1 : x2; + //if ( reversedLandscape ) { + // testLow = viewwidth-1-testLow; + // testHigh = viewwidth-1-testHigh; + //} + if ( !memchr( occlusion+testLow, 0, testHigh - testLow ) ) { + c_occludedSprites++; + return; + } + + // ------------ gld_AddSprite ---------- + mobj_t *pSpr= thing; + GLSprite sprite; + float voff,hoff; + + sprite.scale= FixedDiv(projectiony, tz); + if (pSpr->frame & FF_FULLBRIGHT) + sprite.light = 255; + else + sprite.light = pSpr->subsector->sector->lightlevel+(extralight<<5); + sprite.cm=CR_LIMIT+(int)((pSpr->flags & MF_TRANSLATION) >> (MF_TRANSSHIFT)); + sprite.gltexture=gld_RegisterPatch(lump+firstspritelump,sprite.cm); + if (!sprite.gltexture) + return; + sprite.shadow = (pSpr->flags & MF_SHADOW) != 0; + sprite.trans = (pSpr->flags & MF_TRANSLUCENT) != 0; + if (movement_smooth) + { + sprite.x = (float)(-pSpr->PrevX + FixedMul (tic_vars.frac, -pSpr->x - (-pSpr->PrevX)))/MAP_SCALE; + sprite.y = (float)(pSpr->PrevZ + FixedMul (tic_vars.frac, pSpr->z - pSpr->PrevZ))/MAP_SCALE; + sprite.z = (float)(pSpr->PrevY + FixedMul (tic_vars.frac, pSpr->y - pSpr->PrevY))/MAP_SCALE; + } + else + { + sprite.x=-(float)pSpr->x/MAP_SCALE; + sprite.y= (float)pSpr->z/MAP_SCALE; + sprite.z= (float)pSpr->y/MAP_SCALE; + } + + sprite.vt=0.0f; + sprite.vb=(float)sprite.gltexture->height/(float)sprite.gltexture->tex_height; + if (flip) + { + sprite.ul=0.0f; + sprite.ur=(float)sprite.gltexture->width/(float)sprite.gltexture->tex_width; + } + else + { + sprite.ul=(float)sprite.gltexture->width/(float)sprite.gltexture->tex_width; + sprite.ur=0.0f; + } + hoff=(float)sprite.gltexture->leftoffset/(float)(MAP_COEFF); + voff=(float)sprite.gltexture->topoffset/(float)(MAP_COEFF); + sprite.x1=hoff-((float)sprite.gltexture->realtexwidth/(float)(MAP_COEFF)); + sprite.x2=hoff; + sprite.y1=voff; + sprite.y2=voff-((float)sprite.gltexture->realtexheight/(float)(MAP_COEFF)); + + // JDC: don't let sprites poke below the ground level. + // Software rendering Doom didn't use depth buffering, + // so sprites always got drawn on top of the flat they + // were on, but in GL they tend to get a couple pixel + // rows clipped off. + if ( sprite.y2 < 0 ) { + sprite.y1 -= sprite.y2; + sprite.y2 = 0; + } + + if (gld_drawinfo.num_sprites>=gld_drawinfo.max_sprites) + { + gld_drawinfo.max_sprites+=128; + gld_drawinfo.sprites=Z_Realloc(gld_drawinfo.sprites,gld_drawinfo.max_sprites*sizeof(GLSprite),PU_LEVEL,0); + } + gld_drawinfo.sprites[gld_drawinfo.num_sprites++]=sprite; +} + +// JDC: removed the 0.001f epsilons that were presumably added +// to try to hide T-junction cracks, but now that we are drawing +// source lines instead of clipped segs, it is a non-problem. +#define LINE seg->linedef +#define CALC_Y_VALUES(w, lineheight, floor_height, ceiling_height)\ +(w).ytop=((float)(ceiling_height)/(float)MAP_SCALE);\ +(w).ybottom=((float)(floor_height)/(float)MAP_SCALE);\ +lineheight=((float)fabs(((ceiling_height)/(float)FRACUNIT)-((floor_height)/(float)FRACUNIT))) + +#define OU(w,seg) (((float)((seg)->sidedef->textureoffset+(seg)->offset)/(float)FRACUNIT)/(float)(w).gltexture->buffer_width) +#define OV(w,seg) (((float)((seg)->sidedef->rowoffset)/(float)FRACUNIT)/(float)(w).gltexture->buffer_height) +#define OV_PEG(w,seg,v_offset) (OV((w),(seg))-(((float)(v_offset)/(float)FRACUNIT)/(float)(w).gltexture->buffer_height)) + +#define CALC_TEX_VALUES_TOP(w, seg, peg, linelength, lineheight)\ +(w).flag=GLDWF_TOP;\ +(w).ul=OU((w),(seg))+(0.0f);\ +(w).ur=OU((w),(seg))+((linelength)/(float)(w).gltexture->buffer_width);\ +(peg)?\ +(\ +(w).vb=OV((w),(seg))+((float)(w).gltexture->height/(float)(w).gltexture->tex_height),\ +(w).vt=((w).vb-((float)(lineheight)/(float)(w).gltexture->buffer_height))\ +):(\ +(w).vt=OV((w),(seg))+(0.0f),\ +(w).vb=OV((w),(seg))+((float)(lineheight)/(float)(w).gltexture->buffer_height)\ +) + +#define CALC_TEX_VALUES_MIDDLE1S(w, seg, peg, linelength, lineheight)\ +(w).flag=GLDWF_M1S;\ +(w).ul=OU((w),(seg))+(0.0f);\ +(w).ur=OU((w),(seg))+((linelength)/(float)(w).gltexture->buffer_width);\ +(peg)?\ +(\ +(w).vb=OV((w),(seg))+((float)(w).gltexture->height/(float)(w).gltexture->tex_height),\ +(w).vt=((w).vb-((float)(lineheight)/(float)(w).gltexture->buffer_height))\ +):(\ +(w).vt=OV((w),(seg))+(0.0f),\ +(w).vb=OV((w),(seg))+((float)(lineheight)/(float)(w).gltexture->buffer_height)\ +) + +#define CALC_TEX_VALUES_MIDDLE2S(w, seg, peg, linelength, lineheight)\ +(w).flag=GLDWF_M2S;\ +(w).ul=OU((w),(seg))+(0.0f);\ +(w).ur=OU((w),(seg))+((linelength)/(float)(w).gltexture->buffer_width);\ +(peg)?\ +(\ +(w).vb=((float)(w).gltexture->height/(float)(w).gltexture->tex_height),\ +(w).vt=((w).vb-((float)(lineheight)/(float)(w).gltexture->buffer_height))\ +):(\ +(w).vt=(0.0f),\ +(w).vb=((float)(lineheight)/(float)(w).gltexture->buffer_height)\ +) + +#define CALC_TEX_VALUES_BOTTOM(w, seg, peg, linelength, lineheight, v_offset)\ +(w).flag=GLDWF_BOT;\ +(w).ul=OU((w),(seg))+(0.0f);\ +(w).ur=OU((w),(seg))+((linelength)/(float)(w).gltexture->realtexwidth);\ +(peg)?\ +(\ +(w).vb=OV_PEG((w),(seg),(v_offset))+((float)(w).gltexture->height/(float)(w).gltexture->tex_height),\ +(w).vt=((w).vb-((float)(lineheight)/(float)(w).gltexture->buffer_height))\ +):(\ +(w).vt=OV((w),(seg))+(0.0f),\ +(w).vb=OV((w),(seg))+((float)(lineheight)/(float)(w).gltexture->buffer_height)\ +) + +// e6y +// Sky textures with a zero index should be forced +// See third episode of requiem.wad +#define SKYTEXTURE_PRBOOM(sky1,sky2)\ +if ((sky1) & PL_SKYFLAT)\ +{\ +const line_t *l = &lines[sky1 & ~PL_SKYFLAT];\ +const side_t *s = *l->sidenum + sides;\ +wall.gltexture=gld_RegisterTexture(texturetranslation[s->toptexture], false, texturetranslation[s->toptexture]==skytexture);\ +wall.skyyaw=-2.0f*((-(float)((viewangle+s->textureoffset)>>ANGLETOFINESHIFT)*360.0f/FINEANGLES)/90.0f);\ +wall.skyymid = 200.0f/319.5f*(((float)s->rowoffset/(float)FRACUNIT - 28.0f)/100.0f);\ +wall.flag = l->special==272 ? GLDWF_SKY : GLDWF_SKYFLIP;\ +}\ +else\ + if ((sky2) & PL_SKYFLAT)\ +{\ +const line_t *l = &lines[sky2 & ~PL_SKYFLAT];\ +const side_t *s = *l->sidenum + sides;\ +wall.gltexture=gld_RegisterTexture(texturetranslation[s->toptexture], false, texturetranslation[s->toptexture]==skytexture);\ +wall.skyyaw=-2.0f*((-(float)((viewangle+s->textureoffset)>>ANGLETOFINESHIFT)*360.0f/FINEANGLES)/90.0f);\ +wall.skyymid = 200.0f/319.5f*(((float)s->rowoffset/(float)FRACUNIT - 28.0f)/100.0f);\ +wall.flag = l->special==272 ? GLDWF_SKY : GLDWF_SKYFLIP;\ +}\ +else\ +{\ +wall.gltexture=gld_RegisterTexture(skytexture, false, true);\ +wall.skyyaw=-2.0f*((yaw+90.0f)/90.0f);\ +wall.skyymid = 200.0f/319.5f*((100.0f)/100.0f);\ +wall.flag = GLDWF_SKY;\ +}; + +#define SKYTEXTURE(sky1,sky2)\ +wall.gltexture=NULL;\ +wall.flag = GLDWF_SKY; + +#define ADDWALL(wall)\ +{\ +if (gld_drawinfo.num_walls>=gld_drawinfo.max_walls)\ +{\ +gld_drawinfo.max_walls+=128;\ +gld_drawinfo.walls=Z_Realloc(gld_drawinfo.walls,gld_drawinfo.max_walls*sizeof(GLWall),PU_LEVEL,0);\ +}\ +gld_drawinfo.walls[gld_drawinfo.num_walls++]=*wall;\ +}; + +extern GLSeg *gl_segs; +extern byte rendermarker; +extern byte *segrendered; +extern int tran_filter_pct; + +void IR_AddWall(seg_t *seg) +{ + GLWall wall; + GLTexture *temptex; + sector_t *thefrontsector; + sector_t *thebacksector; + sector_t ftempsec; // needed for R_FakeFlat + sector_t btempsec; // needed for R_FakeFlat + float lineheight; + int rellight = 0; + + wall.glseg=NULL; + wall.side = seg->sidedef; + thefrontsector=R_FakeFlat(seg->frontsector, &ftempsec, NULL, NULL, false); // for boom effects + if (!thefrontsector) + return; + + // JDC: improve this lighting tweak + rellight = seg->linedef->dx==0? +8 : seg->linedef->dy==0 ? -8 : 0; + int light = thefrontsector->lightlevel+rellight+(extralight<<5); + wall.light = MAX(MIN((light),255),0); + wall.alpha=1.0f; + wall.gltexture=NULL; + + if (!seg->backsector) /* onesided */ + { +#ifdef SKYWALLS + if (thefrontsector->ceilingpic==skyflatnum) + { + wall.ytop=255.0f; + wall.ybottom=(float)thefrontsector->ceilingheight/MAP_SCALE; + SKYTEXTURE(thefrontsector->sky,thefrontsector->sky); + ADDWALL(&wall); + } + if (thefrontsector->floorpic==skyflatnum) + { + wall.ytop=(float)thefrontsector->floorheight/MAP_SCALE; + wall.ybottom=-255.0f; + SKYTEXTURE(thefrontsector->sky,thefrontsector->sky); + ADDWALL(&wall); + } +#endif + temptex=gld_RegisterTexture(texturetranslation[seg->sidedef->midtexture], true, false); + if (temptex) + { + wall.gltexture=temptex; + CALC_Y_VALUES(wall, lineheight, thefrontsector->floorheight, thefrontsector->ceilingheight); + CALC_TEX_VALUES_MIDDLE1S( + wall, seg, (LINE->flags & ML_DONTPEGBOTTOM)>0, + seg->length, lineheight + ); + ADDWALL(&wall); + } + } + else /* twosided */ + { + int floor_height,ceiling_height; + + thebacksector=R_FakeFlat(seg->backsector, &btempsec, NULL, NULL, true); // for boom effects + if(!thebacksector) + return; + /* toptexture */ + ceiling_height=thefrontsector->ceilingheight; + floor_height=thebacksector->ceilingheight; +#ifdef SKYWALLS + if (thefrontsector->ceilingpic==skyflatnum) + { + wall.ytop=255.0f; + if ( + // e6y + // Fix for HOM in the starting area on Memento Mori map29 and on map30. + // old code: (thebacksector->ceilingheight==thebacksector->floorheight) && + (thebacksector->ceilingheight==thebacksector->floorheight||(thebacksector->ceilingheight<=thefrontsector->floorheight)) && + (thebacksector->ceilingpic==skyflatnum) + ) + { + wall.ybottom=(float)thebacksector->floorheight/MAP_SCALE; + SKYTEXTURE(thefrontsector->sky,thebacksector->sky); + ADDWALL(&wall); + } + else + { + if ( (texturetranslation[seg->sidedef->toptexture]!=NO_TEXTURE) ) + { + // e6y + // It corrects some problem with sky, but I do not remember which one + // old code: wall.ybottom=(float)thefrontsector->ceilingheight/MAP_SCALE; + wall.ybottom=(float)MAX(thefrontsector->ceilingheight,thebacksector->ceilingheight)/MAP_SCALE; + + SKYTEXTURE(thefrontsector->sky,thebacksector->sky); + ADDWALL(&wall); + } + else + if ( (thebacksector->ceilingheight <= thefrontsector->floorheight) || + (thebacksector->ceilingpic != skyflatnum) ) + { + wall.ybottom=(float)thebacksector->ceilingheight/MAP_SCALE; + SKYTEXTURE(thefrontsector->sky,thebacksector->sky); + ADDWALL(&wall); + } + } + } +#endif + if (floor_heightceilingpic==skyflatnum) && (thebacksector->ceilingpic==skyflatnum))) + { + temptex=gld_RegisterTexture(texturetranslation[seg->sidedef->toptexture], true, false); + if ( !temptex ) { + temptex = defaultTexture; // it seems some line segments have bad data... + } + wall.gltexture=temptex; + CALC_Y_VALUES(wall, lineheight, floor_height, ceiling_height); + CALC_TEX_VALUES_TOP( + wall, seg, (LINE->flags & (ML_DONTPEGBOTTOM | ML_DONTPEGTOP))==0, + seg->length, lineheight + ); + ADDWALL(&wall); + } + } + + /* midtexture */ + //e6y + if (comp[comp_maskedanim]) + temptex=gld_RegisterTexture(seg->sidedef->midtexture, true, false); + else + // e6y + // Animated middle textures with a zero index should be forced + // See spacelab.wad (http://www.doomworld.com/idgames/index.php?id=6826) + temptex=gld_RegisterTexture(texturetranslation[seg->sidedef->midtexture], true, true); + + if (temptex && seg->sidedef->midtexture != NO_TEXTURE) + { + wall.gltexture=temptex; + if ( (LINE->flags & ML_DONTPEGBOTTOM) >0) + { + if (seg->backsector->ceilingheight<=seg->frontsector->floorheight) + goto bottomtexture; + floor_height=MAX(seg->frontsector->floorheight,seg->backsector->floorheight)+(seg->sidedef->rowoffset); + ceiling_height=floor_height+(wall.gltexture->realtexheight<backsector->ceilingheight<=seg->frontsector->floorheight) + goto bottomtexture; + ceiling_height=MIN(seg->frontsector->ceilingheight,seg->backsector->ceilingheight)+(seg->sidedef->rowoffset); + floor_height=ceiling_height-(wall.gltexture->realtexheight<flags & ML_DONTPEGBOTTOM)>0, + segs[seg->iSegID].length, lineheight + );*/ + { + int floormax, ceilingmin, linelen; + float mip; + mip = (float)wall.gltexture->realtexheight/(float)wall.gltexture->buffer_height; + // if ( (texturetranslation[seg->sidedef->bottomtexture]!=R_TextureNumForName("-")) ) + if (seg->sidedef->bottomtexture) + floormax=MAX(seg->frontsector->floorheight,seg->backsector->floorheight); + else + floormax=floor_height; + if (seg->sidedef->toptexture) + ceilingmin=MIN(seg->frontsector->ceilingheight,seg->backsector->ceilingheight); + else + ceilingmin=ceiling_height; + linelen=abs(ceiling_height-floor_height); + wall.ytop=((float)MIN(ceilingmin, ceiling_height)/(float)MAP_SCALE); + wall.ybottom=((float)MAX(floormax, floor_height)/(float)MAP_SCALE); + wall.flag=GLDWF_M2S; + wall.ul=OU((wall),(seg))+(0.0f); + wall.ur=OU(wall,(seg))+((seg->length)/(float)wall.gltexture->buffer_width); + if (floormax<=floor_height) + wall.vb=mip*1.0f; + else + wall.vb=mip*((float)(ceiling_height - floormax))/linelen; + if (ceilingmin>=ceiling_height) + wall.vt=0.0f; + else + wall.vt=mip*((float)(ceiling_height - ceilingmin))/linelen; + } + + if (seg->linedef->tranlump >= 0 && general_translucency) + wall.alpha=(float)tran_filter_pct/100.0f; + wall.alpha=1.0f; + ADDWALL(&wall); + } + bottomtexture: + /* bottomtexture */ + ceiling_height=thebacksector->floorheight; + floor_height=thefrontsector->floorheight; +#ifdef SKYWALLS + if (thefrontsector->floorpic==skyflatnum) + { + wall.ybottom=-255.0f; + if ( + (thebacksector->ceilingheight==thebacksector->floorheight) && + (thebacksector->floorpic==skyflatnum) + ) + { + wall.ytop=(float)thebacksector->floorheight/MAP_SCALE; + SKYTEXTURE(thefrontsector->sky,thebacksector->sky); + ADDWALL(&wall); + } + else + { + if ( (texturetranslation[seg->sidedef->bottomtexture]!=NO_TEXTURE) ) + { + wall.ytop=(float)thefrontsector->floorheight/MAP_SCALE; + SKYTEXTURE(thefrontsector->sky,thebacksector->sky); + ADDWALL(&wall); + } + else + if ( (thebacksector->floorheight >= thefrontsector->ceilingheight) || + (thebacksector->floorpic != skyflatnum) ) + { + wall.ytop=(float)thebacksector->floorheight/MAP_SCALE; + SKYTEXTURE(thefrontsector->sky,thebacksector->sky); + ADDWALL(&wall); + } + } + } +#endif + if (floor_heightsidedef->bottomtexture], true, false); + if ( !temptex ) { + temptex = defaultTexture; // it seems some line segments have bad data... + } + wall.gltexture=temptex; + CALC_Y_VALUES(wall, lineheight, floor_height, ceiling_height); + CALC_TEX_VALUES_BOTTOM( + wall, seg, (LINE->flags & ML_DONTPEGBOTTOM)>0, + seg->length, lineheight, + floor_height-thefrontsector->ceilingheight + ); + ADDWALL(&wall); + } + } +} + +#undef LINE +#undef CALC_Y_VALUES +#undef OU +#undef OV +#undef OV_PEG +#undef CALC_TEX_VALUES_TOP +#undef CALC_TEX_VALUES_MIDDLE1S +#undef CALC_TEX_VALUES_MIDDLE2S +#undef CALC_TEX_VALUES_BOTTOM +#undef SKYTEXTURE +#undef ADDWALL + + + +/* + TransformAndClipSegment + + Converts a world coordinate line segment to screen space. + Returns false if the segment is off screen. + + There would be some savings if all the points in a subsector + were transformed and clip tested as a unit, instead of as discrete segments. + */ +boolean TransformAndClipSegment( float v[2][2], float ends[2] ) { + float clip[2][4]; + + // if we are in iphone reverse-landscape mode, we need + // to flip the coordinates around + float *v0, *v1; + //if ( reversedLandscape ) { + // v0 = v[1]; + // v1 = v[0]; + //} else { + v0 = v[0]; + v1 = v[1]; + //} + + // transform from model to clip space + // because the iPhone screen hardware is portrait mode, + // we need to look at the Y axis for the segment ends, + // not the X axis. + clip[0][1] = v0[0] * glMVPmatrix[1] + v0[1] * glMVPmatrix[2*4+1] + glMVPmatrix[3*4+1]; + clip[0][3] = v0[0] * glMVPmatrix[3] + v0[1] * glMVPmatrix[2*4+3] + glMVPmatrix[3*4+3]; + + clip[1][1] = v1[0] * glMVPmatrix[1] + v1[1] * glMVPmatrix[2*4+1] + glMVPmatrix[3*4+1]; + clip[1][3] = v1[0] * glMVPmatrix[3] + v1[1] * glMVPmatrix[2*4+3] + glMVPmatrix[3*4+3]; + + float d0, d1; + + // clip to the near plane + float nearClip = 0.01f; + d0 = clip[0][3] - nearClip; + d1 = clip[1][3] - nearClip; + if ( d0 < 0 && d1 < 0 ) { + // near clipped + return false; + } + if ( d0 < 0 ) { + float f = d0 / ( d0 - d1 ); + clip[0][1] = clip[0][1] + f * ( clip[1][1] - clip[0][1] ); + clip[0][3] = nearClip; + } else if ( d1 < 0 ) { + float f = d1 / ( d1 - d0 ); + clip[1][1] = clip[1][1] + f * ( clip[0][1] - clip[1][1] ); + clip[1][3] = nearClip; + } + + if ( clip[0][1] > clip[0][3] ) { + // entire segment is off the right side of the screen + return false; + } + if ( clip[1][1] < -clip[1][3] ) { + // entire segment is off the left side of the screen + return false; + } + + // project + for ( int i = 0 ; i < 2 ; i++ ) { + float x = viewwidth * ( ( clip[i][1] / clip[i][3] ) * 0.5f + 0.5f ); + if ( x < 0 ) { + x = 0; + } else if ( x > viewwidth ) { + x = viewwidth; + } + ends[i] = x; + } + + // part of the segment is on screen + return true; +} + +/* + IR_Subsector + + All possible culling should be performed here, but most calculations should be + deferred until draw time, rather than storing intermediate values that are + later referenced. + + Don't make this static, or the compiler inlines it in the recursive node + function, which bloats the stack. +*/ +void IR_Subsector(int num) +{ + subsector_t *sub = &subsectors[num]; + c_subsectors++; + // at this point we know that at least part of the subsector is + // not covered in the occlusion array + + // if the sector that this subsector is a part of has not already had its + // planes and sprites added, add them now. + sector_t *thefrontsector = sub->sector; + int lightlevel = thefrontsector->lightlevel+(extralight<<5); + + // There can be several subsectors in each sector due to non-convex + // sectors or BSP splits, but we draw the floors, ceilings and lines + // with a single draw call for the entire thing, so ensure that they + // are only added once per frame. + if ( thefrontsector->validcount != validcount ) { + thefrontsector->validcount = validcount; + + c_sectors++; + GLFlat flat; + flat.sectornum = thefrontsector->iSectorID; + flat.light = lightlevel; + flat.uoffs= 0; // no support in standard doom + flat.voffs= 0; + + if ( thefrontsector->floorheight < viewz ) { + if (thefrontsector->floorpic == skyflatnum) { + skyIsVisible = true; + } else { + // get the texture. flattranslation is maintained by doom and + // contains the number of the current animation frame + GLTexture *tex = gld_RegisterFlat(flattranslation[thefrontsector->floorpic], true); + if ( tex ) { + sectorPlanes[numSectorPlanes].texture = tex; + sectorPlanes[numSectorPlanes].ceiling = false; + sectorPlanes[numSectorPlanes].sector = thefrontsector; + numSectorPlanes++; + } + } + } + if ( thefrontsector->ceilingheight > viewz ) { + if (thefrontsector->ceilingpic == skyflatnum) { + skyIsVisible = true; + } else { + // get the texture. flattranslation is maintained by doom and + // contains the number of the current animation frame + GLTexture *tex = gld_RegisterFlat(flattranslation[thefrontsector->ceilingpic], true); + if ( tex ) { + sectorPlanes[numSectorPlanes].texture = tex; + sectorPlanes[numSectorPlanes].ceiling = true; + sectorPlanes[numSectorPlanes].sector = thefrontsector; + numSectorPlanes++; + } + } + } + + // Add all the sprites in this sector. + // It would be better if they were linked into all the subsectors, because + // we could do more accurate occlusion culling. With non-convex sectors, + // occasionally a sprite will be added in a rear portion of the sector that + // would have been occluded away if everything was done in BSP subsector order. + for ( mobj_t *thing = thefrontsector->thinglist; thing; thing = thing->snext) { + IR_ProjectSprite( thing, lightlevel ); + } + } + + // If a segment in this subsector is not fully occluded, mark + // the line that it is a part of as needing to be drawn. Because + // we are using a depth buffer, we can draw complete line segments + // instead of just segments. + for ( int i = 0 ; i < sub->numlines ; i++ ) { + seg_t *seg = &segs[sub->firstline+i]; + + line_t *line = seg->linedef; + + // Determine if it will completely occlude farther objects. + // Given that changing sector heights is much less common than + // traversing lines during every render, it would be marginally better if + // lines had an "occluder" flag on them that was updated as sectors + // moved, but it hardly matters. + boolean occluder; + if ( seg->backsector == NULL || + seg->backsector->floorheight >= seg->backsector->ceilingheight || + seg->backsector->floorheight >= seg->frontsector->ceilingheight || + seg->backsector->ceilingheight <= seg->frontsector->floorheight ) { + // this segment can't be seen past, so fill in the occlusion table + occluder = true; + } else { + // If the line has already been made visible and we don't need to + // update the occlusion buffer, we don't need to do anything else here. + // This happens when a line is split into multiple segs, and also + // when the line is reached from the backsector. In the backsector + // case, it would be back-face culled, but this test throws it out + // without having to transform and clip the ends. + if ( line->validcount == validcount ) { + continue; + } + + // check to see if the seg won't draw any walls at all + + // we won't fill in the occlusion table for this + occluder = false; + } + + // transform and clip the two endpoints + float v[2][2]; + float floatEnds[2]; + v[0][0] = -seg->v1->x/MAP_SCALE; + v[0][1] = seg->v1->y/MAP_SCALE; + v[1][0] = -seg->v2->x/MAP_SCALE; + v[1][1] = seg->v2->y/MAP_SCALE; + if ( !TransformAndClipSegment( v, floatEnds ) ) { + // the line is off to the side or facing away + continue; + } + + // Allow segs that we consider to be slightly back + // facing to still pass through, because GPU floating + // point calculations may not see them exactly the same. + if ( floatEnds[0] > floatEnds[1] + 1.0f ) { + // back face + continue; + } + // Check it against the occlusion buffer. + // Because the perspective divide is not going to be bit-exact between + // the CPU and GPU, we check an extra column here. That will result + // in an occasional line being drawn that might not need to be, but + // it avoids missing columns. + int checkMin = floor( floatEnds[0] - 1 ); + int checkMax = ceil( floatEnds[1] + 1 ); + if ( checkMin < 0 ) { + checkMin = 0; + } + if ( checkMax > viewwidth ) { + checkMax = viewwidth; + } + if ( !memchr( occlusion + checkMin, 0, checkMax - checkMin ) ) { + failCount++; + // every column it would touch is already solid, so it isn't visible + continue; + } + if ( occluder ) { + // It is important to update the occlusion array as individual + // segs are processed to maintain pure front to back order. If + // the occlusion buffer was updated by complete lines, it would + // result in some elements being incorrectly occlusion culled. + + // Use a consistant fill rule for the occlusion, which is only + // referenced by the CPU, and should be water tight. + int fillMin = (int) (floatEnds[0]+0.5); + int fillMax = (int) (floatEnds[1]+0.5); + if ( fillMax > fillMin ) { + memset( occlusion + fillMin, 1, fillMax-fillMin ); + } + } + + if ( line->validcount == validcount ) { + continue; + } + line->validcount = validcount; + + // this line can show up on the automap now + line->flags |= ML_MAPPED; + + // Adding a line may generate up to four drawn walls -- a top wall, + // a bottom wall, a perforated middle wall, and a sky wall. + + // Use the complete, unclipped segment for the side + IR_AddWall( &seg->sidedef->sideSeg ); + } +} + +PUREFUNC static int IR_PointOnSide(fixed_t x, fixed_t y, const node_t *node) +{ + // JDC: these early tests probably aren't worth it on iphone... + if (!node->dx) + return x <= node->x ? node->dy > 0 : node->dy < 0; + + if (!node->dy) + return y <= node->y ? node->dx < 0 : node->dx > 0; + + x -= node->x; + y -= node->y; + + // Try to quickly decide by looking at sign bits. + if ((node->dy ^ node->dx ^ x ^ y) < 0) + return (node->dy ^ x) < 0; // (left is negative) + + return (__int64_t)y * (__int64_t)node->dx >= (__int64_t)x * (__int64_t)node->dy; +} + + +static const int checkcoord[12][4] = // killough -- static const +{ +{3,0,2,1}, +{3,0,2,0}, +{3,1,2,0}, +{0}, +{2,0,2,1}, +{0,0,0,0}, +{3,1,3,0}, +{0}, +{2,0,3,1}, +{2,1,3,1}, +{2,1,3,0} +}; +static boolean IR_IsBBoxCompletelyOccluded(const fixed_t *bspcoord) { + // conservatively accept if close to the box, so + // we don't need to worry about the near clip plane + // in TrnasformAndClipSegment. Mapscale is 128*fracunit + // and nearclip is 0.1, so accepting 2 fracunits away works. + if ( viewx > bspcoord[BOXLEFT]-2*FRACUNIT && viewx < bspcoord[BOXRIGHT] + 2*FRACUNIT + && viewy > bspcoord[BOXBOTTOM]-2*FRACUNIT && viewy < bspcoord[BOXTOP] + 2*FRACUNIT ) { + return false; + } + + // Find the corners of the box + // that define the edges from current viewpoint. + int boxpos = (viewx <= bspcoord[BOXLEFT] ? 0 : viewx < bspcoord[BOXRIGHT ] ? 1 : 2) + + (viewy >= bspcoord[BOXTOP ] ? 0 : viewy > bspcoord[BOXBOTTOM] ? 4 : 8); + + const int *check = checkcoord[boxpos]; + float v[2][2]; + + v[0][0] = -bspcoord[check[0]]/MAP_SCALE; + v[0][1] = bspcoord[check[1]]/MAP_SCALE; + + v[1][0] = -bspcoord[check[2]]/MAP_SCALE; + v[1][1] = bspcoord[check[3]]/MAP_SCALE; + float ends[2]; + if ( !TransformAndClipSegment( v, ends ) ) { + // the line is off to the side or facing away + return true; + } + + if ( ends[0] >= ends[1] ) { + return true; + } + + assert( ends[0] >= 0 ); + assert( ends[1] <= viewwidth ); + + // Check it against the occlusion buffer, with an extra column + // of slop to account for GPU / CPU floating point differences. + if ( !memchr( occlusion + (int)ends[0], 0, (int)ends[1]-(int)ends[0]+1 ) ) { + // every column it would touch is already solid, so it isn't visible + return true; + } + // there are gaps, so we may need to draw something + return false; +} + + +/* + RenderBSPNode + + Renders all subsectors below a given node, + traversing subtree recursively. + Because this function is recursive, avoid doing work that + would give a large stack frame. Important that the compiler + doesn't inline big functions. + */ +static void IR_RenderBSPNode( int bspnum ) { + while (!(bspnum & NF_SUBSECTOR)) { + // decision node + const node_t *bsp = &nodes[bspnum]; + + // Decide which side the view point is on. + int side = IR_PointOnSide(viewx, viewy, bsp); + + // check the front space + if ( !IR_IsBBoxCompletelyOccluded(bsp->bbox[side]) ) { + IR_RenderBSPNode( bsp->children[side] ); + } + // continue down the back space + if ( IR_IsBBoxCompletelyOccluded( bsp->bbox[side^1]) ) { + return; + } + bspnum = bsp->children[side^1]; + } + + // subsector with contents + // add all the drawable elements in the subsector + if ( bspnum == -1 ) { + bspnum = 0; + } + bspnum &= ~NF_SUBSECTOR; + IR_Subsector( bspnum ); +} + + +typedef struct { + void *texture; + void *user; +} texSort_t; + +static int TexSort( const void *a, const void *b ) { + if ( ((texSort_t *)a)->texture < ((texSort_t *)b)->texture ) { + return -1; + } + return 1; +} + +int SysIphoneMicroseconds(); +void SetImmediateModeGLVertexArrays(); +extern float yaw; +extern GLTexture **gld_GLTextures; +extern GLTexture **gld_GLPatchTextures; +extern GLVertex *gld_vertexes; +extern GLTexcoord *gld_texcoords; + +#define MAX_DRAW_INDEXES 0x10000 +unsigned short drawIndexes[MAX_DRAW_INDEXES]; +int numDrawIndexes; + +drawVert_t drawVerts[MAX_DRAW_VERTS]; +int numDrawVerts; + +void NewDrawScene(player_t *player) // JDC: new version +{ + int i,k; + + glDisable( GL_ALPHA_TEST ); + glDisable(GL_CULL_FACE); + glDisable(GL_FOG); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glEnableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); + + // Use the 2x texture combiner mode to allow the game to be brightened up + // above the normal maximum. All calculated color values for lighting will + // be multiplied by a value ranging from 0.5 for original brightness, up to + // 1.0 for 2x brightness. This combine mode will be canceled after all + // the 3D and view weapon drawing is completed, so the hud elements are + // drawn at normal brightness. + glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE ); + glTexEnvf( GL_TEXTURE_ENV, GL_RGB_SCALE, 2.0 ); + + // opaque skies, flats, and walls write to the depth buffer and don't blend + glDisable( GL_BLEND ); + glDepthMask( 1 ); + + // debug tool to check for things being drawn that shouldn't be + if ( blendAll ) { + glClearColor( 0, 0, 0, 0 ); + glClear( GL_COLOR_BUFFER_BIT ); + glEnable( GL_BLEND ); + glDisable( GL_DEPTH_TEST ); + glBlendFunc( GL_ONE, GL_ONE ); + skyIsVisible = false; + } + + // debug tool to look for pixel cracks + if ( testClear ) { + glClearColor( 1, 0, 0, 0 ); + glClear( GL_COLOR_BUFFER_BIT ); + skyIsVisible = false; + } + + //----------------------------------------- + // draw the sky if needed + //----------------------------------------- + if ( skyIsVisible ) { + float s; + float y; + + // Note that these texcoords would have to be corrected + // for different screen aspect ratios or fields of view! + s = ((yaw+90.0f)/90.0f); + y = 1 - 2 * 128.0 / 200; + + // With identity matricies, the vertex coordinates + // can just be in the 0-1 range. + glMatrixMode( GL_MODELVIEW ); + glPushMatrix(); + glLoadIdentity(); + glMatrixMode( GL_PROJECTION ); + glPushMatrix(); + glLoadIdentity(); + + gld_BindTexture( gld_RegisterTexture( skytexture, true, true ) ); + glColor4f( 0.5, 0.5, 0.5, 1.0 ); // native texture color, not double bright + glBegin(GL_TRIANGLE_STRIP); + glTexCoord2f( s, 1 ); glVertex3f(-1,y,0.999); + glTexCoord2f( s, 0 ); glVertex3f(-1,1,0.999); + glTexCoord2f( s+1, 1 ); glVertex3f(1,y,0.999); + glTexCoord2f( s+1, 0 ); glVertex3f(1,1,0.999); + glEnd(); + + // back to the normal drawing matrix + glPopMatrix(); + glMatrixMode( GL_MODELVIEW ); + glPopMatrix(); + } + + // walls and flats use the drawVerts array for everything + glTexCoordPointer(2,GL_FLOAT,sizeof(drawVert_t),drawVerts[0].st); + glVertexPointer(3,GL_FLOAT,sizeof(drawVert_t),drawVerts[0].xyz); + glColorPointer(4,GL_UNSIGNED_BYTE,sizeof(drawVert_t),drawVerts[0].rgba); + + // everything will draw at full brightness in this case + if (player->fixedcolormap) { + glColor4f(1.0f, 1.0f, 1.0f, 1.0f ); + glDisableClientState(GL_COLOR_ARRAY); + } else { + glEnableClientState( GL_COLOR_ARRAY ); + } + + int c_drawElements = 0; + numDrawIndexes = 0; + + //----------------------------------------- + // draw all the walls, sky walls sorted first + //----------------------------------------- + // sort the walls by texture + texSort_t *wallSort = alloca( sizeof( wallSort[0] ) * gld_drawinfo.num_walls ); + for (i=0 ; i < gld_drawinfo.num_walls ; i++ ) { + GLWall *wall = &gld_drawinfo.walls[i]; + wallSort[i].texture = wall->gltexture; + wallSort[i].user = wall; + } + qsort( wallSort, gld_drawinfo.num_walls, sizeof( wallSort[0] ), TexSort ); + + // continue building drawverts after the floor and ceiling data + int tempDrawVert = numDrawVerts; + + // alpha tested walls will use half alpha to get the best edging effects + glAlphaFunc( GL_GREATER, 0.5 ); + + for (i=0 ; i < gld_drawinfo.num_walls ; i++ ) { + texSort_t *sort = &wallSort[i]; + GLWall *wall = sort->user; + rendered_segs++; + + // add two tris to draw the wall + drawIndexes[numDrawIndexes+0] = tempDrawVert; + drawIndexes[numDrawIndexes+1] = tempDrawVert+1; + drawIndexes[numDrawIndexes+2] = tempDrawVert+2; + + drawIndexes[numDrawIndexes+3] = tempDrawVert+1; + drawIndexes[numDrawIndexes+4] = tempDrawVert+2; + drawIndexes[numDrawIndexes+5] = tempDrawVert+3; + + numDrawIndexes += 6; + + unsigned char rgba[4]; + rgba[0] = rgba[1] = rgba[2] = wall->light; + rgba[3] = 255; + int lightInt = *(int *)rgba; + + drawVerts[tempDrawVert].st[0] = wall->ul; + drawVerts[tempDrawVert].st[1] = wall->vt; + drawVerts[tempDrawVert].xyz[0] = -wall->side->sideSeg.v1->x / MAP_SCALE; + drawVerts[tempDrawVert].xyz[1] = wall->ytop; + drawVerts[tempDrawVert].xyz[2] = wall->side->sideSeg.v1->y / MAP_SCALE; + + lightInt = FadedLighting( drawVerts[tempDrawVert].xyz[0], drawVerts[tempDrawVert].xyz[2], wall->light ); + + *(int *)drawVerts[tempDrawVert].rgba = lightInt; + tempDrawVert++; + + drawVerts[tempDrawVert].st[0] = wall->ul; + drawVerts[tempDrawVert].st[1] = wall->vb; + drawVerts[tempDrawVert].xyz[0] = -wall->side->sideSeg.v1->x / MAP_SCALE; + drawVerts[tempDrawVert].xyz[1] = wall->ybottom; + drawVerts[tempDrawVert].xyz[2] = wall->side->sideSeg.v1->y / MAP_SCALE; + *(int *)drawVerts[tempDrawVert].rgba = lightInt; + tempDrawVert++; + + drawVerts[tempDrawVert].st[0] = wall->ur; + drawVerts[tempDrawVert].st[1] = wall->vt; + drawVerts[tempDrawVert].xyz[0] = -wall->side->sideSeg.v2->x / MAP_SCALE; + drawVerts[tempDrawVert].xyz[1] = wall->ytop; + drawVerts[tempDrawVert].xyz[2] = wall->side->sideSeg.v2->y / MAP_SCALE; + + lightInt = FadedLighting( drawVerts[tempDrawVert].xyz[0], drawVerts[tempDrawVert].xyz[2], wall->light ); + *(int *)drawVerts[tempDrawVert].rgba = lightInt; + tempDrawVert++; + + drawVerts[tempDrawVert].st[0] = wall->ur; + drawVerts[tempDrawVert].st[1] = wall->vb; + drawVerts[tempDrawVert].xyz[0] = -wall->side->sideSeg.v2->x / MAP_SCALE; + drawVerts[tempDrawVert].xyz[1] = wall->ybottom; + drawVerts[tempDrawVert].xyz[2] = wall->side->sideSeg.v2->y / MAP_SCALE; + *(int *)drawVerts[tempDrawVert].rgba = lightInt; + tempDrawVert++; + + // only draw when textures change + if ( i == gld_drawinfo.num_walls-1 || sort->texture != (sort+1)->texture ) { + if ( numDrawIndexes ) { + if ( wall->flag == GLDWF_SKY ) { + // we aren't actually drawing anything with this, + // we are just masking off areas in the depth + // buffer so nothing can overwrite the already + // drawn sky image + glColorMask( 0, 0, 0, 0 ); + } + if ( wall->flag == GLDWF_M2S ) { + glEnable( GL_ALPHA_TEST ); + } + + if ( wall->gltexture ) { // skies are texture = NULL + gld_BindTexture( wall->gltexture ); + } + + glDrawElements( GL_TRIANGLES, numDrawIndexes, GL_UNSIGNED_SHORT, + drawIndexes ); + + if ( wall->flag == GLDWF_M1S ) { + glDisable( GL_ALPHA_TEST ); + } + if ( wall->flag == GLDWF_SKY ) { + glColorMask( 1, 1, 1, 1 ); + } + + numDrawIndexes = 0; + tempDrawVert = numDrawVerts; + c_drawElements++; + } + } + + } + + //----------------------------------------- + // draw all the flats + // + // If we were able to directly fill the GPU command buffers, + // we would be using multiple DrawArrays instead of a single DrawElements, + // and we would fill the plane height and color in as we copied vertexes + // from a single set of verts per sector, but because the driver validation + // overhead is the main poison on the iPhone currently, it is better to + // duplicate the windings for the floors and ceilings, patch the + // vertex data, and generate new index lists to minimize the number of + // draw calls. + //----------------------------------------- + + // sort the flats by texture + qsort( sectorPlanes, numSectorPlanes, sizeof( sectorPlanes[0] ), TexSort ); + + // draw them in texture order + for (i=0 ; i < numSectorPlanes ; i++ ) { + sortSectorPlane_t *sort = §orPlanes[i]; + sector_t *sector = sort->sector; + + drawVert_t *dv = sector->verts[(int)sort->ceiling]; + + // Patch the height values if they have changed since the last draw. + float y = sort->ceiling ? sector->ceilingheight : sector->floorheight; + y *= ( 1.0 / MAP_SCALE ); + if ( y != dv->xyz[1] ) { + for ( int j = 0 ; j < sector->numVerts ; j++ ) { + (dv+j)->xyz[1] = y; + } + } + + // per-vertex faded light color + int light = sector->lightlevel + (extralight<<5); + if ( light > 255 ) { + light = 255; + } + for ( int j = 0 ; j < sector->numVerts ; j++ ) { + *(int *)(dv+j)->rgba = FadedLighting( (dv+j)->xyz[0], (dv+j)->xyz[2], light ); + } + + // copy the indexes + assert( numDrawIndexes + sector->numIndexes < MAX_DRAW_INDEXES ); + memcpy( drawIndexes + numDrawIndexes, sector->indexes[(int)sort->ceiling], sector->numIndexes*sizeof(drawIndexes[0]) ); + numDrawIndexes += sector->numIndexes; + + // only change textures when necessary + if ( i == numSectorPlanes - 1 || sort->texture != (sort+1)->texture ) { + if ( numDrawIndexes ) { + gld_BindFlat( sort->texture ); + glDrawElements( GL_TRIANGLES, numDrawIndexes, GL_UNSIGNED_SHORT, + drawIndexes ); + numDrawIndexes = 0; + c_drawElements++; + } + } + } + + glDisableClientState( GL_COLOR_ARRAY ); + + // back to our immediate mode vertex arrays + SetImmediateModeGLVertexArrays(); + + + //----------------------------------------- + // draw all the sprites + //----------------------------------------- + + // transparent sprites blend and don't write to the depth buffer + glEnable( GL_BLEND ); + glDepthMask( 0 ); + + glEnable( GL_ALPHA_TEST ); + + // get the screen space vector for sprites + float yaws = -sin( yaw * 3.141592657 / 180.0 ); + float yawc = -cos( yaw * 3.141592657 / 180.0 ); + int c_spriteBind = 0; + int c_spriteDraw = 0; + while( 1 ) + { + // pick out the sprites from farthest to nearest + fixed_t max_scale=INT_MAX; + k=-1; + for (i=0 ; i < gld_drawinfo.num_sprites ; i++ ) { + GLSprite *sprite = &gld_drawinfo.sprites[i]; + if (sprite->scalescale; + k=i; + } + } + if ( k == -1 ) { + break; + } + + GLSprite *sprite = &gld_drawinfo.sprites[k]; + sprite->scale=INT_MAX; + + if ( sprite->gltexture != last_gltexture ) { + c_spriteBind++; + } + c_spriteDraw++; + + gld_BindPatch(sprite->gltexture,sprite->cm); + if(sprite->shadow) + { + glBlendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA); + glColor4f(0.2f,0.2f,0.2f,0.33f); + glAlphaFunc( GL_GREATER, 0.1 ); // don't alpha test away the blended-down version + } + else + { + float flight = (float)sprite->light*(1.0f/255); + + // We could do the distance-lighting here, but leaving the sprites + // brighter is a good accent in most cases. There are a few places + // where environmental sprites look a little wrong, but it is probably + // better in general. + + if (player->fixedcolormap) { + flight = 1.0; // light amp goggles + } + glColor4f(flight, flight, flight, 1.0f ); + } + glBegin(GL_TRIANGLE_STRIP); + glTexCoord2f(sprite->ul, sprite->vt); + glVertex3f(sprite->x + sprite->x1 * yawc, sprite->y + sprite->y1, sprite->z + sprite->x1 * yaws ); + glTexCoord2f(sprite->ur, sprite->vt); + glVertex3f(sprite->x + sprite->x2 * yawc, sprite->y + sprite->y1, sprite->z + sprite->x2 * yaws ); + glTexCoord2f(sprite->ul, sprite->vb); + glVertex3f(sprite->x + sprite->x1 * yawc, sprite->y + sprite->y2, sprite->z + sprite->x1 * yaws ); + glTexCoord2f(sprite->ur, sprite->vb); + glVertex3f(sprite->x + sprite->x2 * yawc, sprite->y + sprite->y2, sprite->z + sprite->x2 * yaws ); + glEnd(); + + if(sprite->shadow) + { + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glAlphaFunc( GL_GREATER, 0.5 ); + } + } + + glDisable( GL_ALPHA_TEST ); + glDepthMask( 1 ); +} + + +static float roll = 0.0f; +/* JDC static */ float yaw = 0.0f; +static float inv_yaw = 0.0f; +static float pitch = 0.0f; + +#define __glPi 3.14159265358979323846 + +static void infinitePerspective(GLdouble fovy, GLdouble aspect, GLdouble znear) +{ + GLfloat left, right, bottom, top; // JDC: was GLdouble + GLfloat m[16]; // JDC: was GLdouble + + top = znear * tan(fovy * __glPi / 360.0); + bottom = -top; + left = bottom * aspect; + right = top * aspect; + + //qglFrustum(left, right, bottom, top, znear, zfar); + + m[ 0] = (2 * znear) / (right - left); + m[ 4] = 0; + m[ 8] = (right + left) / (right - left); + m[12] = 0; + + m[ 1] = 0; + m[ 5] = (2 * znear) / (top - bottom); + m[ 9] = (top + bottom) / (top - bottom); + m[13] = 0; + + m[ 2] = 0; + m[ 6] = 0; + //m[10] = - (zfar + znear) / (zfar - znear); + //m[14] = - (2 * zfar * znear) / (zfar - znear); + m[10] = -1; + m[14] = -2 * znear; + + m[ 3] = 0; + m[ 7] = 0; + m[11] = -1; + m[15] = 0; + + glMultMatrixf(m); // JDC: was glMultMatrixd +} + +/* + IR_RenderPlayerView + + Replace the prBoom rendering code with a higher performance + version. Most of the fancy new features are gone, because I + have no idea what the reight test cases would be for them. + */ +void IR_RenderPlayerView (player_t* player) { + int start = 0; + if ( showRenderTime ) { + start = SysIphoneMicroseconds(); + } + + viewplayer = player; + tic_vars.frac = FRACUNIT; + + viewx = player->mo->x; + viewy = player->mo->y; + viewz = player->viewz; + viewangle = player->mo->angle; + extralight = player->extralight; // gun flashes + + yaw=270.0f-(float)(viewangle>>ANGLETOFINESHIFT)*360.0f/FINEANGLES; + + viewsin = finesine[viewangle>>ANGLETOFINESHIFT]; + viewcos = finecosine[viewangle>>ANGLETOFINESHIFT]; + + // IR goggles + if (player->fixedcolormap) { + fixedcolormap = fullcolormap + player->fixedcolormap*256*sizeof(lighttable_t); + } else { + fixedcolormap = 0; + } + + // this is used to tell if a line, sector, or sprite is going to be drawn this frame + validcount++; + + // clear the 1D occlusion buffer, set a final guard column to occluded so we can + // check an extra pixel to account for slight floating point differences between + // the GPU and CPU transformations + assert( viewwidth <= MAX_SCREENWIDTH ); + memset( occlusion, 0, sizeof( occlusion ) ); + occlusion[viewwidth] = 1; + + float trY ; + float xCamera,yCamera; + + extern int screenblocks; + int height; + + gld_SetPalette(-1); + + if (screenblocks == 11) + height = SCREENHEIGHT; + else if (screenblocks == 10) + height = SCREENHEIGHT; + else + height = (screenblocks*SCREENHEIGHT/10) & ~7; + + glViewport(viewwindowx, SCREENHEIGHT-(height+viewwindowy-((height-viewheight)/2)), viewwidth, height); + glScissor(viewwindowx, SCREENHEIGHT-(viewheight+viewwindowy), viewwidth, viewheight); + glEnable(GL_SCISSOR_TEST); + glEnable(GL_DEPTH_TEST); + glDisable(GL_FOG); + glShadeModel(GL_SMOOTH); + + // Player coordinates + xCamera=-(float)viewx/MAP_SCALE; + yCamera=(float)viewy/MAP_SCALE; + trY=(float)viewz/MAP_SCALE; + + yaw=270.0f-(float)(viewangle>>ANGLETOFINESHIFT)*360.0f/FINEANGLES; + inv_yaw=-90.0f+(float)(viewangle>>ANGLETOFINESHIFT)*360.0f/FINEANGLES; + +#ifdef _DEBUG + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +#else + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +#endif + + // To make it easier to accurately mimic the GL model to screen transformation, + // this is set up so that the projection transformation is also done in the + // modelview matrix, leaving the projection matrix as an identity. This means + // that things done in eye space, like lighting and fog, won't work, but + // we don't need them. + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + infinitePerspective(64.0f, 320.0f/200.0f, 5.0f/100.0f); + + glRotatef(roll, 0.0f, 0.0f, 1.0f); + glRotatef(pitch, 1.0f, 0.0f, 0.0f); + glRotatef(yaw, 0.0f, 1.0f, 0.0f); + glTranslatef(-xCamera, -trY, -yCamera); + + // read back the matrix so we can do exact calculations that match + // what GL is doing. It would probably be better to build the matricies + // ourselves and just do a loadMatrix... + glGetFloatv( GL_MODELVIEW_MATRIX, glMVPmatrix ); + + // setup the vector for calculating light fades, which is just a scale + // of the forward vector + lightingVector[0] = lightDistance * glMVPmatrix[2]; + lightingVector[1] = lightDistance * glMVPmatrix[10]; + lightingVector[2] = lightDistance * glMVPmatrix[14]; + + + rendermarker++; + gld_drawinfo.num_walls=0; + gld_drawinfo.num_flats=0; + gld_drawinfo.num_sprites=0; + gld_drawinfo.num_drawitems=0; + + c_occludedSprites = 0; + c_sectors = 0; + c_subsectors = 0; + numSectorPlanes = 0; + failCount = 0; + + // Find everything we need to draw, but don't draw anything yet, + // because we want to sort by texture to reduce GL driver overhead. + IR_RenderBSPNode( numnodes-1 ); + + NewDrawScene(player); + + gld_EndDrawScene(); + + if ( showRenderTime ) { + int end = SysIphoneMicroseconds(); + printf( "%i usec\n", end - start ); + } +} + + diff --git a/common/ios/doomengine/iphone_sound.c b/common/ios/doomengine/iphone_sound.c new file mode 100755 index 0000000..866cc7c --- /dev/null +++ b/common/ios/doomengine/iphone_sound.c @@ -0,0 +1,293 @@ +/* + * iphone_sound.c + * doom + * + * Created by John Carmack on 4/16/09. + * Copyright 2009 Id Software. All rights reserved. + * + */ +/* + + Copyright (C) 2009 Id Software, 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 + 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 "doomiphone.h" +#include + + +typedef struct { + unsigned sourceName; // OpenAL sourceName + pkWav_t *sfx; // NULL if unused + float volume; // stored for showSound display +} channel_t; + +static ALCcontext *Context; +static ALCdevice *Device; + +#define MAX_CHANNELS 16 +static channel_t s_channels[ MAX_CHANNELS ]; + +cvar_t *s_sfxVolume; + +void Sound_StartLocalSound( const char *filename ) { + Sound_StartLocalSoundAtVolume( filename, 1.0f ); +} + +void Sound_StartLocalSoundAtVolume( const char *filename, float volume ) { + pkWav_t *sfx; + + sfx = PK_FindWav( filename ); + if( ! sfx ) { + Com_Printf( "Sound_StartLocalSound: could not cache (%s)\n", filename ); + return; + } +// printf( "sound:%s\n", filename ); + // channel 0 is reserved for UI sounds, the other channels + // are for DOOM sounds + channel_t *ch = &s_channels[ 0 ]; + + ch->sfx = sfx; + ch->volume = s_sfxVolume->value * volume; + + alSourceStop( ch->sourceName ); + alSourcef( ch->sourceName, AL_GAIN, ch->volume ); + alSourcei( ch->sourceName, AL_BUFFER, sfx->alBufferNum ); + alSourcef( ch->sourceName, AL_PITCH, 1.0f ); + alSourcePlay( ch->sourceName ); +} + + +static void Sound_Play_f( void ) { + if( Cmd_Argc() == 1 ) { + Com_Printf( "Usage: play \n" ); + return; + } + Sound_StartLocalSound( Cmd_Argv( 1 ) ); +} + +// we won't allow music to be toggled on or off in the menu when this is true +int otherAudioIsPlaying; + +int SysIPhoneOtherAudioIsPlaying() { + return otherAudioIsPlaying; +} + +void interruptionListener( void *inUserData, UInt32 inInterruption) +{ + printf("Session interrupted! --- %s ---\n", inInterruption == kAudioSessionBeginInterruption ? "Begin Interruption" : "End Interruption"); + + if ( inInterruption == kAudioSessionBeginInterruption ) { + printf("Audio interrupted.\n" ); + iphonePauseMusic(); + alcMakeContextCurrent( NULL ); + AudioSessionSetActive( false ); + } else if ( inInterruption == kAudioSessionEndInterruption ) { + printf("Audio restored.\n" ); + + OSStatus r = AudioSessionSetActive( true ); + if ( r != kAudioSessionNoError ) { + printf( "AudioSessionSetActive( true ) failed: 0x%x\n", (unsigned int)r ); + } else { + printf( "AudioSessionSetActive( true ) succeeded.\n" ); + } + alcMakeContextCurrent( Context ); + if( alcGetError( Device ) != ALC_NO_ERROR ) { + Com_Error( "Failed to alcMakeContextCurrent\n" ); + } + iphoneResumeMusic(); + } +} + +void Sound_Init( void ) { + + Com_Printf( "\n------- Sound Initialization -------\n" ); + + s_sfxVolume = Cvar_Get( "s_sfxVolume", "1.0", 0 ); + + Cmd_AddCommand( "play", Sound_Play_f ); + + // make sure background ipod music mixes with our sound effects + Com_Printf( "...Initializing AudioSession\n" ); + OSStatus status = 0; + status = AudioSessionInitialize(NULL, NULL, interruptionListener, NULL); // else "couldn't initialize audio session" + + // if there is iPod music playing in the background, we want to use + // the AmbientSound catagory, otherwise we will leave it at the default. + // If we always set it to AmbientSound, then the mp3 background music + // playback goes to software on 3.0 for a huge slowdown. + UInt32 propOtherAudioIsPlaying = kAudioSessionProperty_OtherAudioIsPlaying; + UInt32 size = sizeof( otherAudioIsPlaying ); + AudioSessionGetProperty( propOtherAudioIsPlaying, &size, &otherAudioIsPlaying ); + Com_Printf("OtherAudioIsPlaying = %d\n", otherAudioIsPlaying ); + + if ( otherAudioIsPlaying ) { + UInt32 audioCategory = kAudioSessionCategory_AmbientSound; + status = AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(audioCategory), &audioCategory); + } + + status = AudioSessionSetActive(true); // else "couldn't set audio session active\n" + + Com_Printf( "...Initializing OpenAL subsystem\n" ); + + // get the OpenAL device + Device = alcOpenDevice( NULL ); + if( Device == NULL ) { + Com_Printf( "Failed to alcOpenDevice\n" ); + } + + // Create context(s) + Context = alcCreateContext( Device, NULL ); + if( Context == NULL ) { + Com_Error( "Failed to alcCreateContext\n" ); + } + + // Set active context + alcGetError( Device ); + alcMakeContextCurrent( Context ); + if( alcGetError( Device ) != ALC_NO_ERROR ) { + Com_Error( "Failed to alcMakeContextCurrent\n" ); + } + + // allocate all the channels we are going to use + channel_t *ch; + int i; + for( i = 0, ch = s_channels ; i < MAX_CHANNELS ; ++i, ++ch ) { + alGenSources( 1, &ch->sourceName ); + + if( alGetError() != AL_NO_ERROR ) { + Com_Error( "Allocating AL sound sources" ); + } + alSourcei( ch->sourceName, AL_SOURCE_RELATIVE, AL_FALSE ); + } + + Com_Printf( "------------------------------------\n" ); +} + +/* + ================== + ShowSound + + Display active sound channels + ================== + */ +void ShowSound() { + + if ( !showSound->value ) { + return; + } + channel_t *ch; + int i; + for( i = 0, ch = s_channels ; i < MAX_CHANNELS ; ++i, ++ch ) { + int state; + alGetSourcei( ch->sourceName, AL_SOURCE_STATE, &state ); + if ( state != AL_PLAYING ) { + continue; + } + + int v = ch->volume * 255; + if ( v > 255 ) { + v = 255; + } + color4_t color = { v, v, v, 255 }; + R_Draw_Fill( i*16, 0, 12, 12, color ); + } +} + + +/* + ================================================================== + + PrBoom interface + + ================================================================== +*/ + +// Initialize channels? +void I_SetChannels(void) {} + +// Get raw data lump index for sound descriptor. +int I_GetSfxLumpNum (sfxinfo_t *sfx) { + // find the pkWav_t for this sfxinfo + char upper[16], *d = upper; + for ( const char *c = sfx->name ; *c ; c++ ) { + *d++ = toupper( *c ); + } + *d = 0; + pkWav_t *pkwav = PK_FindWav( va( "newsfx/DS%s.wav", upper ) ); + + return pkwav - pkWavs; +} + +// Starts a sound in a particular sound channel. +// volume ranges 0 - 64 +// seperation tanges is 128 straight ahead, 0 = all left ear, 255 = all right ear +// pitch centers around 128 +int I_StartSound(int sfx_id, int channel, int vol, int sep, int pitch, int priority) { + + sfxinfo_t *dsfx = &S_sfx[sfx_id]; + + assert( dsfx->lumpnum >= 0 && dsfx->lumpnum < pkHeader->wavs.count ); + + pkWav_t *sfx = &pkWavs[dsfx->lumpnum]; +// printf( "sound: %s chan:%i vol:%i sep:%i pitch:%i priority:%i\n", sfx->wavData->name.name, channel, vol, sep, pitch, priority ); + + assert( channel >= 0 && channel < MAX_CHANNELS - 1 ); + channel_t *ch = &s_channels[ 1+channel ]; + + alSourceStop( ch->sourceName ); + if ( ch->sfx == sfx ) { + // restarting the same sound + alSourceRewind( ch->sourceName ); + } else { + alSourcei( ch->sourceName, AL_BUFFER, sfx->alBufferNum ); + } + + ch->sfx = sfx; + ch->volume = s_sfxVolume->value * vol / 64.0; + alSourcef( ch->sourceName, AL_GAIN, ch->volume ); + alSourcef( ch->sourceName, AL_PITCH, pitch / 128.0f ); + alSourcePlay( ch->sourceName ); + + return (int)ch; +} + +// Stops a sound channel. +void I_StopSound(int handle) {} + +// Called by S_*() functions +// to see if a channel is still playing. +// Returns 0 if no longer playing, 1 if playing. +boolean I_SoundIsPlaying(int handle) { + + channel_t *ch = (channel_t *)handle; + if ( !ch ) { + return false; + } + int state; + alGetSourcei( ch->sourceName, AL_SOURCE_STATE, &state ); + + return state == AL_PLAYING; +} + +// Called by m_menu.c to let the quit sound play and quit right after it stops +boolean I_AnySoundStillPlaying(void) { return false; } + +// Updates the volume, separation, +// and pitch of a sound channel. +void I_UpdateSoundParams(int handle, int vol, int sep, int pitch) {} diff --git a/common/ios/doomengine/iphone_start.cpp b/common/ios/doomengine/iphone_start.cpp new file mode 100755 index 0000000..2c73db5 --- /dev/null +++ b/common/ios/doomengine/iphone_start.cpp @@ -0,0 +1,261 @@ +/* + * iphone_start.c + * doom + * + * Created by John Carmack on 7/7/09. + * Copyright 2009 id Software. All rights reserved. + * + */ +/* + + Copyright (C) 2009 Id Software, 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 + 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 "doomiphone.h" +#include "ios/GameCenter.h" + +// Only one game can be set up at a time on a given wireless segment, although +// several independent games can be played. +// If a valid setupPacket has arrived in the last second, that will be the +// displayed game, otherwise the local system starts sending out setupPackets. +packetSetup_t setupPacket; +int setupPacketFrameNum; +int localGameID; // change every time we take over as the sender of setupPackets + +boolean levelHasBeenLoaded; // determines if "resume game" does a loadGame and exiting does a saveGame + +menuState_t menuState; +menuState_t lastState = IPM_GAME; +color4_t highlightColor = { 128, 128, 128, 255 }; +color4_t colorPressed = { 128, 128, 0, 255 }; + +/* + ================== + ResumeGame + + ================== + */ +void ResumeGame() { + if ( levelHasBeenLoaded && !demoplayback ) { + // return to the already started game + iphoneResumeMusic(); + drawWeaponSelect = false; + weaponSelected = -1; + automapmode = am_none; + advancedemo = false; + menuState = IPM_GAME; + lastState = IPM_GAME; + return; + } + + if ( !playState.saveGameIsValid || !G_SaveGameValid() ) { + // they hit "resume game" on the first app lounch, so just start E1M1 + mapStart_t map; + map.skill = 1; + map.episode = 1; + map.map = 1; + StartSinglePlayerGame( map ); + lastState = IPM_GAME; + } else { + StartSaveGame(); + lastState = IPM_GAME; + } +} + + +/* + ================== + GameSetup + + ================== + */ +void GameSetup() { + netGameFailure = NF_NONE; + + // resume game just goes back to playing, it doesn't load anything + levelHasBeenLoaded = true; + + // make sure doom doesn't cycle to the next demo loop and kill the new game + advancedemo = false; + + // not in a timedemo yet + timeDemoStart = 0; + iphoneTimeDemo = false; + + // display the game next time through the main loop + drawWeaponSelect = false; + weaponSelected = -1; + automapmode = am_none; + menuState = IPM_GAME; + + demoplayback = false; + + levelTimer = false; + levelFragLimit = false; + + // single player game + netgame = false; + deathmatch = false; + nomonsters = false; + memset( playeringame, 0, sizeof( playeringame ) ); + consoleplayer = 0; + displayplayer = 0; + playeringame[consoleplayer] = 1; +} + +/* + ======================= + StartSaveGame + + Can be called by both the resume game button after launch, or the + load game button after a player death + ======================= + */ +void StartSaveGame() { + GameSetup(); + G_LoadGame( 0, true ); + G_DoLoadGame(); +} + +/* + ======================= + StartSinglePlayerGame + + ======================= + */ +void StartSinglePlayerGame( mapStart_t map ) { + // Disconnect from a multiplayer game + idGameCenter::DisconnectFromMatch(); + + playState.map = map; + playState.saveGameIsValid = true; // assume we will save the game on exit + lastState = IPM_GAME; + + // mark this level / skill combination as tried + // + mapStats_t *cms = FindMapStats( playState.map.dataset, playState.map.episode, playState.map.map, true ); + if ( cms ) { + // if we are at MAX_MAPS, no stat tracking... + cms->completionFlags[playState.map.skill] |= MF_TRIED; + } + + GameSetup(); + + // start the map + G_InitNew( static_cast( playState.map.skill ), playState.map.episode, playState.map.map ); +} + + +/* + ======================= + StartNetGame + + Begins a game based on the contents of setupPacket + ======================= + */ +boolean StartNetGame() { + // make sure we are supposed to be in this game + int slot = -1; + for ( int i = 0 ; i < MAXPLAYERS ; i++ ) { + if ( setupPacket.playerID[i] == playerID ) { + slot = i; + } + } + if ( slot == -1 ) { + return false; + } + + + + GameSetup(); + + consoleplayer = displayplayer = slot; + + netgame = true; // respawn without restarting levels + + if ( setupPacket.deathmatch ) { + // deathmatch game + deathmatch = setupPacket.deathmatch; // could be either 1 or 2 for altdeath + nomonsters = true; + + if ( setupPacket.timelimit > 0 ) { + levelTimer = true; + // 30 hz, minutes + levelTimeCount = setupPacket.timelimit * 30 * 60; + } + + if ( setupPacket.fraglimit > 0 ) { + levelFragLimit = true; + levelFragLimitCount = setupPacket.fraglimit; + } + } else { + // coop game + deathmatch = false; + nomonsters = false; + } + + for ( int i = 0 ; i < MAXPLAYERS ; i++ ) { + if ( setupPacket.playerID[i] != 0 ) { + playeringame[i] = 1; + } else { + playeringame[i] = 0; + } + } + + gametic = 0; + maketic = 1; // allow everyone to run the first frame without waiting for a packet + + memset( netcmds, 0, sizeof( netcmds ) ); + memset( consistancy, 0, sizeof( consistancy ) ); + + gameID = setupPacket.gameID; + + // start the map + G_InitNew( static_cast( setupPacket.map.skill ), setupPacket.map.episode, setupPacket.map.map ); + + return true; +} + +/* + ======================= + StartDemoGame + + The demo button has been hit on the main menu + ======================= + */ +void StartDemoGame( boolean timeDemoMode ) { + if ( levelHasBeenLoaded && !netgame && !demoplayback && usergame && gamestate == GS_LEVEL ) { + // save the current game before starting the demos + levelHasBeenLoaded = false; + G_SaveGame( 0, "quicksave" ); + G_DoSaveGame(true); + } + lastState = IPM_GAME; + + GameSetup(); + if ( timeDemoMode ) { + iphoneTimeDemo = true; + } + + // always skip to the next one on each exit from the menu + advancedemo = true; +} + + + diff --git a/common/ios/doomengine/iphone_sys.mm b/common/ios/doomengine/iphone_sys.mm new file mode 100755 index 0000000..d6db4f6 --- /dev/null +++ b/common/ios/doomengine/iphone_sys.mm @@ -0,0 +1,93 @@ +/* + + Copyright (C) 2009 Id Software, 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 + 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 "doomiphone.h" +#import +#import +#import "ios/View.h" + +char consoleCommand[1024]; + +int SysIphoneMicroseconds() { + struct timeval tp; + struct timezone tzp; + static int secbase; + + gettimeofday( &tp, &tzp ); + + if( ! secbase ) { + secbase = tp.tv_sec; + return tp.tv_usec; + } + + int curtime = (tp.tv_sec - secbase) * 1000000 + tp.tv_usec; + + return curtime; +} + +int SysIphoneMilliseconds() { + return SysIphoneMicroseconds()/1000; +} + + +char iphoneDocDirectory[PATH_MAX]; +char iphoneAppDirectory[PATH_MAX]; +char iphoneTempDirectory[PATH_MAX]; + +const char *SysIphoneGetAppDir() { + return iphoneAppDirectory; +} + +const char *SysIphoneGetDocDir() { + return iphoneDocDirectory; +} + +const char *SysIphoneGetTempDir() { + return iphoneTempDirectory; +} + +void SysIPhoneVibrate() { + AudioServicesPlaySystemSound( kSystemSoundID_Vibrate ); +} + + +void SysIPhoneOpenURL( const char *url ) { + Com_Printf( "OpenURL char *: %s\n", url ); + + NSString *nss = [NSString stringWithCString: url encoding: NSASCIIStringEncoding]; + [[UIApplication sharedApplication] openURL:[NSURL URLWithString: nss]]; +} + +int SysIPhoneIsDeviceLandscapeRight( void ) { + return [UIDevice currentDevice].orientation == UIDeviceOrientationLandscapeRight; +} + +void SysIPhoneSetUIKitOrientation( int isLandscapeRight ) { + // Using OS autorotation for now. If we ever want to support 60FPS on MBX devices, + // we'll probably have to go back to manual rotation for the GL view. + /* + if ( isLandscapeRight ) { + [UIApplication sharedApplication].statusBarOrientation = UIInterfaceOrientationLandscapeRight; + } else { + [UIApplication sharedApplication].statusBarOrientation = UIInterfaceOrientationLandscapeLeft; + } + */ +} diff --git a/common/ios/doomengine/misc.c b/common/ios/doomengine/misc.c new file mode 100755 index 0000000..d054c51 --- /dev/null +++ b/common/ios/doomengine/misc.c @@ -0,0 +1,91 @@ +/* + * misc.c + * doom + * + * Created by John Carmack on 4/13/09. + * Copyright 2009 idSoftware. All rights reserved. + * + */ +/* + + Copyright (C) 2009 Id Software, 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 + 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 "doomiphone.h" + +void Com_Printf( const char *fmt, ... ) { + va_list argptr; + + va_start( argptr, fmt ); + + //gsh, send output to the console buffer + char buffer[1024]; + vsnprintf( buffer, sizeof( buffer ), fmt, argptr ); + AppendConsoleBuffer(buffer); + + vprintf( fmt, argptr ); + va_end( argptr ); +} + +void Com_Error( const char *fmt, ... ) { + va_list argptr; + + va_start( argptr, fmt ); + + //gsh, send output to the console buffer + char buffer[1024]; + vsnprintf( buffer, sizeof( buffer ), fmt, argptr ); + AppendConsoleBuffer(buffer); + + vprintf( fmt, argptr ); + va_end( argptr ); + + //gsh, email the console to id + EmailConsole(); + + // drop into the editor + abort(); + exit( 1 ); +} + +char *va( const char *format, ... ) { + va_list argptr; + static char string[ 1024 ]; + + va_start( argptr, format ); + (void)vsnprintf( string, sizeof( string ), format, argptr ); + va_end( argptr ); + + string[ sizeof( string ) - 1 ] = '\0'; + + return string; +} + +int HashString( const char *string ) { + int hash = *string; + + if( hash ) { + for( string += 1; *string != '\0'; ++string ) { + hash = (hash << 5) - hash + tolower(*string); + } + } + + return hash; +} + diff --git a/common/ios/doomengine/misc.h b/common/ios/doomengine/misc.h new file mode 100755 index 0000000..558f010 --- /dev/null +++ b/common/ios/doomengine/misc.h @@ -0,0 +1,74 @@ +/* + * misc.h + * doom + * + * Created by John Carmack on 4/13/09. + * Copyright 2009 idSoftware. All rights reserved. + * + */ +/* + + Copyright (C) 2009 Id Software, 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 + 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. + + */ + + +char *va( const char *format, ... ); +void Com_Printf( const char *fmt, ... ); +void Com_Error( const char *fmt, ... ); +int HashString( const char *string ); + +/* + + Command execution takes a NUL-terminated string, breaks it into tokens, + then searches for a command or variable that matches the first token. + + */ + +typedef void (*xcommand_t) (void); + +// called by the init functions of other parts of the program to +// register commands and functions to call for them. +// The cmd_name is referenced later, so it should not be in temp memory +// if function is NULL, the command will be forwarded to the server +// as a clc_stringcmd instead of executed locally +void Cmd_AddCommand( const char *cmd_name, xcommand_t function ); + +// print all the added commands +void Cmd_ListCommands_f(); + +// attempts to match a partial command for automatic command line completion +// returns NULL if nothing fits +char *Cmd_CompleteCommand( const char *partial ); + +// The functions that execute commands get their parameters with these +// functions. Cmd_Argv () will return an empty string, not a NULL +// if arg > argc, so string operations are always safe. +int Cmd_Argc( void ); +const char *Cmd_Argv( int arg ); + +// Takes a NUL-terminated string. Does not need to be /n terminated. +// breaks the string up into argc / argv tokens. +void Cmd_TokenizeString( const char *text ); + +// Parses a single line of text into arguments and tries to execute it +// as if it was typed at the console +void Cmd_ExecuteString( const char *text ); + +// execute each line of the config file +void Cmd_ExecuteFile( const char *fullPathName ); + diff --git a/common/ios/doomengine/prboomInterface.c b/common/ios/doomengine/prboomInterface.c new file mode 100755 index 0000000..e7e4b98 --- /dev/null +++ b/common/ios/doomengine/prboomInterface.c @@ -0,0 +1,324 @@ +/* + * prboomInterface.c + * doom + * + * Created by John Carmack on 4/14/09. + * Copyright 2009 Id Software. All rights reserved. + * + * Stuff to get prboom to compile without SDL + */ +/* + + Copyright (C) 2009 Id Software, 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 + 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 "doomiphone.h" + +int desired_fullscreen; +int usejoystick; +int joyright; +int joyleft; +int joydown; +int joyup; +int gl_colorbuffer_bits; +int gl_depthbuffer_bits; +int snd_card; +int mus_card; +int endoom_mode; +int use_fullscreen; +int snd_samplerate; +int ms_to_next_tick; +int realtic_clock_rate; + + +/* I_SafeExit + * This function is called instead of exit() by functions that might be called + * during the exit process (i.e. after exit() has already been called) + * Prevent infinitely recursive exits -- killough + * + * JDC: we don't do any atexit() calls on iphone, so this shouldn't be necessary + */ +void I_SafeExit(int rc) { + static int has_exited; + if (!has_exited) { + has_exited=rc ? 2 : 1; + exit(rc); + } +} + +void I_uSleep( unsigned long usec ) { + usleep( usec ); +} + +/* + * HasTrailingSlash + * + * cphipps - simple test for trailing slash on dir names + */ + +boolean HasTrailingSlash(const char* dn) +{ + return ( (dn[strlen(dn)-1] == '/') ); +} + +void I_FindFile(const char* wfname, const char* ext, char * returnFileName ) +{ + sprintf( returnFileName, "%s/%s", SysIphoneGetAppDir(), wfname ); + if (access(returnFileName,F_OK)) + strcat(returnFileName, ext); // try adding the extension + if (!access(returnFileName,F_OK)) { + lprintf(LO_INFO, " found %s\n", returnFileName); + + // Found the file. + return; + } + // did not find the file. + returnFileName[0] = '\0'; + lprintf(LO_INFO, " NOT found %s\n", wfname ); + +#if 0 + // lookup table of directories to search + static const struct { + const char *dir; // directory + const char *sub; // subdirectory + const char *env; // environment variable + const char *(*func)(void); // for I_DoomExeDir + } search[] = { + {NULL}, // current working directory + {NULL, NULL, "DOOMWADDIR"}, // run-time $DOOMWADDIR + {DOOMWADDIR}, // build-time configured DOOMWADDIR + {NULL, "doom", "HOME"}, // ~/doom + {NULL, NULL, "HOME"}, // ~ + {NULL, NULL, NULL, I_DoomExeDir}, // config directory + {"/usr/local/share/games/doom"}, + {"/usr/share/games/doom"}, + {"/usr/local/share/doom"}, + {"/usr/share/doom"}, + }; + + int i; + /* Precalculate a length we will need in the loop */ + size_t pl = strlen(wfname) + strlen(ext) + 4; + + for (i = 0; i < sizeof(search)/sizeof(*search); i++) { + char * p; + const char * d = NULL; + const char * s = NULL; + /* Each entry in the switch sets d to the directory to look in, + * and optionally s to a subdirectory of d */ + // switch replaced with lookup table + if (search[i].env) { + if (!(d = getenv(search[i].env))) + continue; + } else if (search[i].func) + d = search[i].func(); + else + d = search[i].dir; + s = search[i].sub; + + p = malloc((d ? strlen(d) : 0) + (s ? strlen(s) : 0) + pl); + sprintf(p, "%s%s%s%s%s", d ? d : "", (d && !HasTrailingSlash(d)) ? "/" : "", + s ? s : "", (s && !HasTrailingSlash(s)) ? "/" : "", + wfname); + + if (access(p,F_OK)) + strcat(p, ext); + if (!access(p,F_OK)) { + lprintf(LO_INFO, " found %s\n", p); + return p; + } + free(p); + } + + return NULL; +#endif +} + + + +boolean I_StartDisplay(void) { + return true; +} + +void I_EndDisplay(void) {} +int I_GetTime_RealTime(void) { return 0; } +fixed_t I_GetTimeFrac (void) { return 0; } +void I_GetTime_SaveMS(void) {} +unsigned long I_GetRandomTimeSeed(void) { return 0; } + +//const char* I_GetVersionString(char* buf, size_t sz); +//const char* I_SigString(char* buf, size_t sz, int signum); + +const char *I_DoomExeDir(void) { return SysIphoneGetAppDir(); } + +//void I_SetAffinityMask(void); + + +/* + * I_Read + * + * cph 2001/11/18 - wrapper for read(2) which handles partial reads and aborts + * on error. + */ +void I_Read(int fd, void* vbuf, size_t sz) +{ + unsigned char* buf = vbuf; + + while (sz) { + int rc = read(fd,buf,sz); + if (rc <= 0) { + I_Error("I_Read: read failed: %s", rc ? strerror(errno) : "EOF"); + } + sz -= rc; buf += rc; + } +} + +/* + * I_Filelength + * + * Return length of an open file. + */ + +int I_Filelength(int handle) +{ + struct stat fileinfo; + if (fstat(handle,&fileinfo) == -1) + I_Error("I_Filelength: %s",strerror(errno)); + return (int)fileinfo.st_size; +} + + + + + +void I_PreInitGraphics(void){} +void I_CalculateRes(unsigned int width, unsigned int height){ (void)width; (void)height; } +void I_ShutdownGraphics(void){} +void I_SetPalette(int pal){ (void)pal; } +void I_UpdateNoBlit (void){} +void I_FinishUpdate (void){} +int I_ScreenShot (const char *fname){ (void)fname; return 0;} + + +// CPhipps - +// I_SetRes +// Sets the screen resolution +void I_SetRes(void) +{ + int i; + + I_CalculateRes(SCREENWIDTH, SCREENHEIGHT); + + // set first three to standard values + for (i=0; i<3; i++) { + screens[i].width = SCREENWIDTH; + screens[i].height = SCREENHEIGHT; + screens[i].byte_pitch = SCREENPITCH; + screens[i].short_pitch = SCREENPITCH / V_GetModePixelDepth(VID_MODE16); + screens[i].int_pitch = SCREENPITCH / V_GetModePixelDepth(VID_MODE32); + } + + // statusbar + screens[4].width = SCREENWIDTH; + screens[4].height = (ST_SCALED_HEIGHT+1); + screens[4].byte_pitch = SCREENPITCH; + screens[4].short_pitch = SCREENPITCH / V_GetModePixelDepth(VID_MODE16); + screens[4].int_pitch = SCREENPITCH / V_GetModePixelDepth(VID_MODE32); + + lprintf(LO_INFO,"I_SetRes: Using resolution %dx%d\n", SCREENWIDTH, SCREENHEIGHT); +} + +void I_UpdateVideoMode(void) +{ + lprintf(LO_INFO, "I_UpdateVideoMode: %dx%d\n", SCREENWIDTH, SCREENHEIGHT ); + + V_InitMode(VID_MODEGL); + I_SetRes(); +#if 0 + screens[0].not_on_heap = true; + screens[0].data = NULL; + screens[0].byte_pitch = screen->pitch; + screens[0].short_pitch = screen->pitch / V_GetModePixelDepth(VID_MODE16); + screens[0].int_pitch = screen->pitch / V_GetModePixelDepth(VID_MODE32); +#endif + + V_AllocScreens(); + + R_InitBuffer(SCREENWIDTH, SCREENHEIGHT); + gld_Init(SCREENWIDTH, SCREENHEIGHT); +} + +void I_InitGraphics(void) +{ + char titlebuffer[2048]; + static int firsttime=1; + + SCREENWIDTH = displaywidth; + SCREENHEIGHT = displayheight; + + if (firsttime) + { + firsttime = 0; + + atexit(I_ShutdownGraphics); + lprintf(LO_INFO, "I_InitGraphics: %dx%d\n", SCREENWIDTH, SCREENHEIGHT); + + /* Set the video mode */ + I_UpdateVideoMode(); + + /* Setup the window title */ + strcpy(titlebuffer,PACKAGE); + strcat(titlebuffer," "); + strcat(titlebuffer,VERSION); +// SDL_WM_SetCaption(titlebuffer, titlebuffer); + + /* Initialize the input system */ +// I_InitInputs(); + } +} + + +/* I_StartTic + * Called by D_DoomLoop, + * called before processing each tic in a frame. + * Quick syncronous operations are performed here. + * Can call D_PostEvent. + */ +void I_StartTic (void){} + +/* I_StartFrame + * Called by D_DoomLoop, + * called before processing any tics in a frame + * (just after displaying a frame). + * Time consuming syncronous operations + * are performed here (joystick reading). + * Can call D_PostEvent. + */ + +void I_StartFrame (void){} + + +void I_Init() { + I_InitSound(); +} + +unsigned int SDL_GetTicks() { return 0; } + +int (*I_GetTime)(void) = I_GetTime_RealTime; + diff --git a/common/ios/prboom/prboom.xcodeproj/project.pbxproj b/common/ios/prboom/prboom.xcodeproj/project.pbxproj new file mode 100755 index 0000000..d86ecec --- /dev/null +++ b/common/ios/prboom/prboom.xcodeproj/project.pbxproj @@ -0,0 +1,842 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 3DC1CA5814B63EC900680D02 /* am_map.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C9B214B63EC900680D02 /* am_map.c */; }; + 3DC1CA5914B63EC900680D02 /* am_map.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C9B314B63EC900680D02 /* am_map.h */; }; + 3DC1CA5A14B63EC900680D02 /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C9B414B63EC900680D02 /* config.h */; }; + 3DC1CA5B14B63EC900680D02 /* d_client.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C9B514B63EC900680D02 /* d_client.c */; }; + 3DC1CA5C14B63EC900680D02 /* d_deh.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C9B614B63EC900680D02 /* d_deh.c */; }; + 3DC1CA5D14B63EC900680D02 /* d_deh.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C9B714B63EC900680D02 /* d_deh.h */; }; + 3DC1CA5E14B63EC900680D02 /* d_englsh.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C9B814B63EC900680D02 /* d_englsh.h */; }; + 3DC1CA5F14B63EC900680D02 /* d_event.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C9B914B63EC900680D02 /* d_event.h */; }; + 3DC1CA6114B63EC900680D02 /* d_items.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C9BB14B63EC900680D02 /* d_items.c */; }; + 3DC1CA6214B63EC900680D02 /* d_items.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C9BC14B63EC900680D02 /* d_items.h */; }; + 3DC1CA6314B63EC900680D02 /* d_main.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C9BD14B63EC900680D02 /* d_main.c */; }; + 3DC1CA6414B63EC900680D02 /* d_main.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C9BE14B63EC900680D02 /* d_main.h */; }; + 3DC1CA6514B63EC900680D02 /* d_net.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C9BF14B63EC900680D02 /* d_net.h */; }; + 3DC1CA6614B63EC900680D02 /* d_player.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C9C014B63EC900680D02 /* d_player.h */; }; + 3DC1CA6714B63EC900680D02 /* d_server.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C9C114B63EC900680D02 /* d_server.c */; }; + 3DC1CA6814B63EC900680D02 /* d_think.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C9C214B63EC900680D02 /* d_think.h */; }; + 3DC1CA6914B63EC900680D02 /* d_ticcmd.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C9C314B63EC900680D02 /* d_ticcmd.h */; }; + 3DC1CA6A14B63EC900680D02 /* doomdata.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C9C414B63EC900680D02 /* doomdata.h */; }; + 3DC1CA6B14B63EC900680D02 /* doomdef.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C9C514B63EC900680D02 /* doomdef.c */; }; + 3DC1CA6C14B63EC900680D02 /* doomdef.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C9C614B63EC900680D02 /* doomdef.h */; }; + 3DC1CA6D14B63EC900680D02 /* doomstat.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C9C714B63EC900680D02 /* doomstat.c */; }; + 3DC1CA6E14B63EC900680D02 /* doomstat.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C9C814B63EC900680D02 /* doomstat.h */; }; + 3DC1CA6F14B63EC900680D02 /* doomtype.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C9C914B63EC900680D02 /* doomtype.h */; }; + 3DC1CA7014B63EC900680D02 /* dstrings.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C9CA14B63EC900680D02 /* dstrings.c */; }; + 3DC1CA7114B63EC900680D02 /* dstrings.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C9CB14B63EC900680D02 /* dstrings.h */; }; + 3DC1CA7214B63EC900680D02 /* f_finale.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C9CC14B63EC900680D02 /* f_finale.c */; }; + 3DC1CA7314B63EC900680D02 /* f_finale.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C9CD14B63EC900680D02 /* f_finale.h */; }; + 3DC1CA7414B63EC900680D02 /* f_wipe.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C9CE14B63EC900680D02 /* f_wipe.c */; }; + 3DC1CA7514B63EC900680D02 /* f_wipe.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C9CF14B63EC900680D02 /* f_wipe.h */; }; + 3DC1CA7614B63EC900680D02 /* g_game.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C9D014B63EC900680D02 /* g_game.c */; }; + 3DC1CA7714B63EC900680D02 /* g_game.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C9D114B63EC900680D02 /* g_game.h */; }; + 3DC1CA7814B63EC900680D02 /* gl_intern.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C9D214B63EC900680D02 /* gl_intern.h */; }; + 3DC1CA7914B63EC900680D02 /* gl_main.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C9D314B63EC900680D02 /* gl_main.c */; }; + 3DC1CA7A14B63EC900680D02 /* gl_struct.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C9D414B63EC900680D02 /* gl_struct.h */; }; + 3DC1CA7B14B63EC900680D02 /* gl_texture.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C9D514B63EC900680D02 /* gl_texture.c */; }; + 3DC1CA7C14B63EC900680D02 /* hu_lib.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C9D614B63EC900680D02 /* hu_lib.c */; }; + 3DC1CA7D14B63EC900680D02 /* hu_lib.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C9D714B63EC900680D02 /* hu_lib.h */; }; + 3DC1CA7E14B63EC900680D02 /* hu_stuff.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C9D814B63EC900680D02 /* hu_stuff.c */; }; + 3DC1CA7F14B63EC900680D02 /* hu_stuff.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C9D914B63EC900680D02 /* hu_stuff.h */; }; + 3DC1CA8014B63EC900680D02 /* i_joy.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C9DA14B63EC900680D02 /* i_joy.h */; }; + 3DC1CA8114B63EC900680D02 /* i_main.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C9DB14B63EC900680D02 /* i_main.h */; }; + 3DC1CA8214B63EC900680D02 /* i_network.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C9DC14B63EC900680D02 /* i_network.h */; }; + 3DC1CA8314B63EC900680D02 /* i_sound.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C9DD14B63EC900680D02 /* i_sound.h */; }; + 3DC1CA8414B63EC900680D02 /* i_system.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C9DE14B63EC900680D02 /* i_system.h */; }; + 3DC1CA8514B63EC900680D02 /* i_video.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C9DF14B63EC900680D02 /* i_video.h */; }; + 3DC1CA8614B63EC900680D02 /* info.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C9E014B63EC900680D02 /* info.c */; }; + 3DC1CA8714B63EC900680D02 /* info.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C9E114B63EC900680D02 /* info.h */; }; + 3DC1CA8814B63EC900680D02 /* lprintf.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C9E214B63EC900680D02 /* lprintf.c */; }; + 3DC1CA8914B63EC900680D02 /* lprintf.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C9E314B63EC900680D02 /* lprintf.h */; }; + 3DC1CA8A14B63EC900680D02 /* m_argv.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C9E414B63EC900680D02 /* m_argv.c */; }; + 3DC1CA8B14B63EC900680D02 /* m_argv.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C9E514B63EC900680D02 /* m_argv.h */; }; + 3DC1CA8C14B63EC900680D02 /* m_bbox.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C9E614B63EC900680D02 /* m_bbox.c */; }; + 3DC1CA8D14B63EC900680D02 /* m_bbox.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C9E714B63EC900680D02 /* m_bbox.h */; }; + 3DC1CA8E14B63EC900680D02 /* m_cheat.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C9E814B63EC900680D02 /* m_cheat.c */; }; + 3DC1CA8F14B63EC900680D02 /* m_cheat.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C9E914B63EC900680D02 /* m_cheat.h */; }; + 3DC1CA9014B63EC900680D02 /* m_fixed.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C9EA14B63EC900680D02 /* m_fixed.h */; }; + 3DC1CA9114B63EC900680D02 /* m_menu.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C9EB14B63EC900680D02 /* m_menu.c */; }; + 3DC1CA9214B63EC900680D02 /* m_menu.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C9EC14B63EC900680D02 /* m_menu.h */; }; + 3DC1CA9314B63EC900680D02 /* m_misc.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C9ED14B63EC900680D02 /* m_misc.c */; }; + 3DC1CA9414B63EC900680D02 /* m_misc.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C9EE14B63EC900680D02 /* m_misc.h */; }; + 3DC1CA9514B63EC900680D02 /* m_random.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C9EF14B63EC900680D02 /* m_random.c */; }; + 3DC1CA9614B63EC900680D02 /* m_random.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C9F014B63EC900680D02 /* m_random.h */; }; + 3DC1CA9714B63EC900680D02 /* m_swap.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C9F114B63EC900680D02 /* m_swap.h */; }; + 3DC1CA9814B63EC900680D02 /* md5.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C9F314B63EC900680D02 /* md5.c */; }; + 3DC1CA9914B63EC900680D02 /* md5.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C9F414B63EC900680D02 /* md5.h */; }; + 3DC1CA9A14B63EC900680D02 /* mmus2mid.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C9F514B63EC900680D02 /* mmus2mid.c */; }; + 3DC1CA9B14B63EC900680D02 /* mmus2mid.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C9F614B63EC900680D02 /* mmus2mid.h */; }; + 3DC1CA9C14B63EC900680D02 /* p_ceilng.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C9F714B63EC900680D02 /* p_ceilng.c */; }; + 3DC1CA9D14B63EC900680D02 /* p_checksum.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C9F814B63EC900680D02 /* p_checksum.c */; }; + 3DC1CA9E14B63EC900680D02 /* p_checksum.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C9F914B63EC900680D02 /* p_checksum.h */; }; + 3DC1CA9F14B63EC900680D02 /* p_doors.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C9FA14B63EC900680D02 /* p_doors.c */; }; + 3DC1CAA014B63EC900680D02 /* p_enemy.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C9FB14B63EC900680D02 /* p_enemy.c */; }; + 3DC1CAA114B63EC900680D02 /* p_enemy.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1C9FC14B63EC900680D02 /* p_enemy.h */; }; + 3DC1CAA214B63EC900680D02 /* p_floor.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C9FD14B63EC900680D02 /* p_floor.c */; }; + 3DC1CAA314B63EC900680D02 /* p_genlin.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C9FE14B63EC900680D02 /* p_genlin.c */; }; + 3DC1CAA414B63EC900680D02 /* p_inter.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1C9FF14B63EC900680D02 /* p_inter.c */; }; + 3DC1CAA514B63EC900680D02 /* p_inter.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1CA0014B63EC900680D02 /* p_inter.h */; }; + 3DC1CAA614B63EC900680D02 /* p_lights.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1CA0114B63EC900680D02 /* p_lights.c */; }; + 3DC1CAA714B63EC900680D02 /* p_map.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1CA0214B63EC900680D02 /* p_map.c */; }; + 3DC1CAA814B63EC900680D02 /* p_map.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1CA0314B63EC900680D02 /* p_map.h */; }; + 3DC1CAA914B63EC900680D02 /* p_maputl.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1CA0414B63EC900680D02 /* p_maputl.c */; }; + 3DC1CAAA14B63EC900680D02 /* p_maputl.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1CA0514B63EC900680D02 /* p_maputl.h */; }; + 3DC1CAAB14B63EC900680D02 /* p_mobj.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1CA0614B63EC900680D02 /* p_mobj.c */; }; + 3DC1CAAC14B63EC900680D02 /* p_mobj.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1CA0714B63EC900680D02 /* p_mobj.h */; }; + 3DC1CAAD14B63EC900680D02 /* p_plats.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1CA0814B63EC900680D02 /* p_plats.c */; }; + 3DC1CAAE14B63EC900680D02 /* p_pspr.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1CA0914B63EC900680D02 /* p_pspr.c */; }; + 3DC1CAAF14B63EC900680D02 /* p_pspr.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1CA0A14B63EC900680D02 /* p_pspr.h */; }; + 3DC1CAB014B63EC900680D02 /* p_saveg.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1CA0B14B63EC900680D02 /* p_saveg.c */; }; + 3DC1CAB114B63EC900680D02 /* p_saveg.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1CA0C14B63EC900680D02 /* p_saveg.h */; }; + 3DC1CAB214B63EC900680D02 /* p_setup.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1CA0D14B63EC900680D02 /* p_setup.c */; }; + 3DC1CAB314B63EC900680D02 /* p_setup.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1CA0E14B63EC900680D02 /* p_setup.h */; }; + 3DC1CAB414B63EC900680D02 /* p_sight.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1CA0F14B63EC900680D02 /* p_sight.c */; }; + 3DC1CAB514B63EC900680D02 /* p_spec.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1CA1014B63EC900680D02 /* p_spec.c */; }; + 3DC1CAB614B63EC900680D02 /* p_spec.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1CA1114B63EC900680D02 /* p_spec.h */; }; + 3DC1CAB714B63EC900680D02 /* p_switch.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1CA1214B63EC900680D02 /* p_switch.c */; }; + 3DC1CAB814B63EC900680D02 /* p_telept.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1CA1314B63EC900680D02 /* p_telept.c */; }; + 3DC1CAB914B63EC900680D02 /* p_tick.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1CA1414B63EC900680D02 /* p_tick.c */; }; + 3DC1CABA14B63EC900680D02 /* p_tick.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1CA1514B63EC900680D02 /* p_tick.h */; }; + 3DC1CABB14B63EC900680D02 /* p_user.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1CA1614B63EC900680D02 /* p_user.c */; }; + 3DC1CABC14B63EC900680D02 /* p_user.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1CA1714B63EC900680D02 /* p_user.h */; }; + 3DC1CABD14B63EC900680D02 /* protocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1CA1814B63EC900680D02 /* protocol.h */; }; + 3DC1CABE14B63EC900680D02 /* r_bsp.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1CA1914B63EC900680D02 /* r_bsp.c */; }; + 3DC1CABF14B63EC900680D02 /* r_bsp.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1CA1A14B63EC900680D02 /* r_bsp.h */; }; + 3DC1CAC014B63EC900680D02 /* r_data.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1CA1B14B63EC900680D02 /* r_data.c */; }; + 3DC1CAC114B63EC900680D02 /* r_data.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1CA1C14B63EC900680D02 /* r_data.h */; }; + 3DC1CAC214B63EC900680D02 /* r_defs.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1CA1D14B63EC900680D02 /* r_defs.h */; }; + 3DC1CAC314B63EC900680D02 /* r_demo.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1CA1E14B63EC900680D02 /* r_demo.c */; }; + 3DC1CAC414B63EC900680D02 /* r_demo.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1CA1F14B63EC900680D02 /* r_demo.h */; }; + 3DC1CAC514B63EC900680D02 /* r_draw.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1CA2014B63EC900680D02 /* r_draw.c */; }; + 3DC1CAC614B63EC900680D02 /* r_draw.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1CA2114B63EC900680D02 /* r_draw.h */; }; + 3DC1CAC714B63EC900680D02 /* r_filter.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1CA2614B63EC900680D02 /* r_filter.c */; }; + 3DC1CAC814B63EC900680D02 /* r_filter.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1CA2714B63EC900680D02 /* r_filter.h */; }; + 3DC1CAC914B63EC900680D02 /* r_fps.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1CA2814B63EC900680D02 /* r_fps.c */; }; + 3DC1CACA14B63EC900680D02 /* r_fps.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1CA2914B63EC900680D02 /* r_fps.h */; }; + 3DC1CACB14B63EC900680D02 /* r_main.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1CA2A14B63EC900680D02 /* r_main.c */; }; + 3DC1CACC14B63EC900680D02 /* r_main.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1CA2B14B63EC900680D02 /* r_main.h */; }; + 3DC1CACD14B63EC900680D02 /* r_patch.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1CA2C14B63EC900680D02 /* r_patch.c */; }; + 3DC1CACE14B63EC900680D02 /* r_patch.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1CA2D14B63EC900680D02 /* r_patch.h */; }; + 3DC1CACF14B63EC900680D02 /* r_plane.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1CA2E14B63EC900680D02 /* r_plane.c */; }; + 3DC1CAD014B63EC900680D02 /* r_plane.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1CA2F14B63EC900680D02 /* r_plane.h */; }; + 3DC1CAD114B63EC900680D02 /* r_segs.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1CA3014B63EC900680D02 /* r_segs.c */; }; + 3DC1CAD214B63EC900680D02 /* r_segs.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1CA3114B63EC900680D02 /* r_segs.h */; }; + 3DC1CAD314B63EC900680D02 /* r_sky.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1CA3214B63EC900680D02 /* r_sky.c */; }; + 3DC1CAD414B63EC900680D02 /* r_sky.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1CA3314B63EC900680D02 /* r_sky.h */; }; + 3DC1CAD514B63EC900680D02 /* r_state.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1CA3414B63EC900680D02 /* r_state.h */; }; + 3DC1CAD614B63EC900680D02 /* r_things.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1CA3514B63EC900680D02 /* r_things.c */; }; + 3DC1CAD714B63EC900680D02 /* r_things.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1CA3614B63EC900680D02 /* r_things.h */; }; + 3DC1CAD814B63EC900680D02 /* s_sound.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1CA3714B63EC900680D02 /* s_sound.c */; }; + 3DC1CAD914B63EC900680D02 /* s_sound.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1CA3814B63EC900680D02 /* s_sound.h */; }; + 3DC1CADD14B63ECA00680D02 /* i_sound.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1CA3D14B63EC900680D02 /* i_sound.c */; }; + 3DC1CAE114B63ECA00680D02 /* SDL_opengl.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1CA4114B63EC900680D02 /* SDL_opengl.h */; }; + 3DC1CAE214B63ECA00680D02 /* sounds.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1CA4214B63EC900680D02 /* sounds.c */; }; + 3DC1CAE314B63ECA00680D02 /* sounds.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1CA4314B63EC900680D02 /* sounds.h */; }; + 3DC1CAE414B63ECA00680D02 /* st_lib.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1CA4414B63EC900680D02 /* st_lib.c */; }; + 3DC1CAE514B63ECA00680D02 /* st_lib.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1CA4514B63EC900680D02 /* st_lib.h */; }; + 3DC1CAE614B63ECA00680D02 /* st_stuff.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1CA4614B63EC900680D02 /* st_stuff.c */; }; + 3DC1CAE714B63ECA00680D02 /* st_stuff.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1CA4714B63EC900680D02 /* st_stuff.h */; }; + 3DC1CAE814B63ECA00680D02 /* tables.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1CA4814B63EC900680D02 /* tables.c */; }; + 3DC1CAE914B63ECA00680D02 /* tables.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1CA4914B63EC900680D02 /* tables.h */; }; + 3DC1CAEA14B63ECA00680D02 /* v_video.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1CA4A14B63EC900680D02 /* v_video.c */; }; + 3DC1CAEB14B63ECA00680D02 /* v_video.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1CA4B14B63EC900680D02 /* v_video.h */; }; + 3DC1CAEC14B63ECA00680D02 /* version.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1CA4C14B63EC900680D02 /* version.c */; }; + 3DC1CAED14B63ECA00680D02 /* version.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1CA4D14B63EC900680D02 /* version.h */; }; + 3DC1CAEE14B63ECA00680D02 /* w_memcache.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1CA4E14B63EC900680D02 /* w_memcache.c */; }; + 3DC1CAEF14B63ECA00680D02 /* w_mmap.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1CA4F14B63EC900680D02 /* w_mmap.c */; }; + 3DC1CAF014B63ECA00680D02 /* w_wad.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1CA5014B63EC900680D02 /* w_wad.c */; }; + 3DC1CAF114B63ECA00680D02 /* w_wad.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1CA5114B63EC900680D02 /* w_wad.h */; }; + 3DC1CAF214B63ECA00680D02 /* wi_stuff.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1CA5214B63EC900680D02 /* wi_stuff.c */; }; + 3DC1CAF314B63ECA00680D02 /* wi_stuff.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1CA5314B63EC900680D02 /* wi_stuff.h */; }; + 3DC1CAF414B63ECA00680D02 /* z_bmalloc.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1CA5414B63EC900680D02 /* z_bmalloc.c */; }; + 3DC1CAF514B63ECA00680D02 /* z_bmalloc.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1CA5514B63EC900680D02 /* z_bmalloc.h */; }; + 3DC1CAF614B63ECA00680D02 /* z_zone.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1CA5614B63EC900680D02 /* z_zone.c */; }; + 3DC1CAF714B63ECA00680D02 /* z_zone.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1CA5714B63EC900680D02 /* z_zone.h */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 3DC1C85514B63E1B00680D02 /* libprboom.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libprboom.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 3DC1C9B214B63EC900680D02 /* am_map.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = am_map.c; path = ../../prboom/am_map.c; sourceTree = ""; }; + 3DC1C9B314B63EC900680D02 /* am_map.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = am_map.h; path = ../../prboom/am_map.h; sourceTree = ""; }; + 3DC1C9B414B63EC900680D02 /* config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = config.h; path = ../../prboom/config.h; sourceTree = ""; }; + 3DC1C9B514B63EC900680D02 /* d_client.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = d_client.c; path = ../../prboom/d_client.c; sourceTree = ""; }; + 3DC1C9B614B63EC900680D02 /* d_deh.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = d_deh.c; path = ../../prboom/d_deh.c; sourceTree = ""; }; + 3DC1C9B714B63EC900680D02 /* d_deh.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = d_deh.h; path = ../../prboom/d_deh.h; sourceTree = ""; }; + 3DC1C9B814B63EC900680D02 /* d_englsh.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = d_englsh.h; path = ../../prboom/d_englsh.h; sourceTree = ""; }; + 3DC1C9B914B63EC900680D02 /* d_event.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = d_event.h; path = ../../prboom/d_event.h; sourceTree = ""; }; + 3DC1C9BB14B63EC900680D02 /* d_items.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = d_items.c; path = ../../prboom/d_items.c; sourceTree = ""; }; + 3DC1C9BC14B63EC900680D02 /* d_items.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = d_items.h; path = ../../prboom/d_items.h; sourceTree = ""; }; + 3DC1C9BD14B63EC900680D02 /* d_main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = d_main.c; path = ../../prboom/d_main.c; sourceTree = ""; }; + 3DC1C9BE14B63EC900680D02 /* d_main.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = d_main.h; path = ../../prboom/d_main.h; sourceTree = ""; }; + 3DC1C9BF14B63EC900680D02 /* d_net.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = d_net.h; path = ../../prboom/d_net.h; sourceTree = ""; }; + 3DC1C9C014B63EC900680D02 /* d_player.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = d_player.h; path = ../../prboom/d_player.h; sourceTree = ""; }; + 3DC1C9C114B63EC900680D02 /* d_server.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = d_server.c; path = ../../prboom/d_server.c; sourceTree = ""; }; + 3DC1C9C214B63EC900680D02 /* d_think.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = d_think.h; path = ../../prboom/d_think.h; sourceTree = ""; }; + 3DC1C9C314B63EC900680D02 /* d_ticcmd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = d_ticcmd.h; path = ../../prboom/d_ticcmd.h; sourceTree = ""; }; + 3DC1C9C414B63EC900680D02 /* doomdata.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = doomdata.h; path = ../../prboom/doomdata.h; sourceTree = ""; }; + 3DC1C9C514B63EC900680D02 /* doomdef.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = doomdef.c; path = ../../prboom/doomdef.c; sourceTree = ""; }; + 3DC1C9C614B63EC900680D02 /* doomdef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = doomdef.h; path = ../../prboom/doomdef.h; sourceTree = ""; }; + 3DC1C9C714B63EC900680D02 /* doomstat.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = doomstat.c; path = ../../prboom/doomstat.c; sourceTree = ""; }; + 3DC1C9C814B63EC900680D02 /* doomstat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = doomstat.h; path = ../../prboom/doomstat.h; sourceTree = ""; }; + 3DC1C9C914B63EC900680D02 /* doomtype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = doomtype.h; path = ../../prboom/doomtype.h; sourceTree = ""; }; + 3DC1C9CA14B63EC900680D02 /* dstrings.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dstrings.c; path = ../../prboom/dstrings.c; sourceTree = ""; }; + 3DC1C9CB14B63EC900680D02 /* dstrings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dstrings.h; path = ../../prboom/dstrings.h; sourceTree = ""; }; + 3DC1C9CC14B63EC900680D02 /* f_finale.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = f_finale.c; path = ../../prboom/f_finale.c; sourceTree = ""; }; + 3DC1C9CD14B63EC900680D02 /* f_finale.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = f_finale.h; path = ../../prboom/f_finale.h; sourceTree = ""; }; + 3DC1C9CE14B63EC900680D02 /* f_wipe.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = f_wipe.c; path = ../../prboom/f_wipe.c; sourceTree = ""; }; + 3DC1C9CF14B63EC900680D02 /* f_wipe.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = f_wipe.h; path = ../../prboom/f_wipe.h; sourceTree = ""; }; + 3DC1C9D014B63EC900680D02 /* g_game.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = g_game.c; path = ../../prboom/g_game.c; sourceTree = ""; }; + 3DC1C9D114B63EC900680D02 /* g_game.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = g_game.h; path = ../../prboom/g_game.h; sourceTree = ""; }; + 3DC1C9D214B63EC900680D02 /* gl_intern.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = gl_intern.h; path = ../../prboom/gl_intern.h; sourceTree = ""; }; + 3DC1C9D314B63EC900680D02 /* gl_main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = gl_main.c; path = ../../prboom/gl_main.c; sourceTree = ""; }; + 3DC1C9D414B63EC900680D02 /* gl_struct.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = gl_struct.h; path = ../../prboom/gl_struct.h; sourceTree = ""; }; + 3DC1C9D514B63EC900680D02 /* gl_texture.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = gl_texture.c; path = ../../prboom/gl_texture.c; sourceTree = ""; }; + 3DC1C9D614B63EC900680D02 /* hu_lib.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = hu_lib.c; path = ../../prboom/hu_lib.c; sourceTree = ""; }; + 3DC1C9D714B63EC900680D02 /* hu_lib.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = hu_lib.h; path = ../../prboom/hu_lib.h; sourceTree = ""; }; + 3DC1C9D814B63EC900680D02 /* hu_stuff.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = hu_stuff.c; path = ../../prboom/hu_stuff.c; sourceTree = ""; }; + 3DC1C9D914B63EC900680D02 /* hu_stuff.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = hu_stuff.h; path = ../../prboom/hu_stuff.h; sourceTree = ""; }; + 3DC1C9DA14B63EC900680D02 /* i_joy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = i_joy.h; path = ../../prboom/i_joy.h; sourceTree = ""; }; + 3DC1C9DB14B63EC900680D02 /* i_main.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = i_main.h; path = ../../prboom/i_main.h; sourceTree = ""; }; + 3DC1C9DC14B63EC900680D02 /* i_network.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = i_network.h; path = ../../prboom/i_network.h; sourceTree = ""; }; + 3DC1C9DD14B63EC900680D02 /* i_sound.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = i_sound.h; path = ../../prboom/i_sound.h; sourceTree = ""; }; + 3DC1C9DE14B63EC900680D02 /* i_system.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = i_system.h; path = ../../prboom/i_system.h; sourceTree = ""; }; + 3DC1C9DF14B63EC900680D02 /* i_video.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = i_video.h; path = ../../prboom/i_video.h; sourceTree = ""; }; + 3DC1C9E014B63EC900680D02 /* info.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = info.c; path = ../../prboom/info.c; sourceTree = ""; }; + 3DC1C9E114B63EC900680D02 /* info.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = info.h; path = ../../prboom/info.h; sourceTree = ""; }; + 3DC1C9E214B63EC900680D02 /* lprintf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = lprintf.c; path = ../../prboom/lprintf.c; sourceTree = ""; }; + 3DC1C9E314B63EC900680D02 /* lprintf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = lprintf.h; path = ../../prboom/lprintf.h; sourceTree = ""; }; + 3DC1C9E414B63EC900680D02 /* m_argv.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = m_argv.c; path = ../../prboom/m_argv.c; sourceTree = ""; }; + 3DC1C9E514B63EC900680D02 /* m_argv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = m_argv.h; path = ../../prboom/m_argv.h; sourceTree = ""; }; + 3DC1C9E614B63EC900680D02 /* m_bbox.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = m_bbox.c; path = ../../prboom/m_bbox.c; sourceTree = ""; }; + 3DC1C9E714B63EC900680D02 /* m_bbox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = m_bbox.h; path = ../../prboom/m_bbox.h; sourceTree = ""; }; + 3DC1C9E814B63EC900680D02 /* m_cheat.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = m_cheat.c; path = ../../prboom/m_cheat.c; sourceTree = ""; }; + 3DC1C9E914B63EC900680D02 /* m_cheat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = m_cheat.h; path = ../../prboom/m_cheat.h; sourceTree = ""; }; + 3DC1C9EA14B63EC900680D02 /* m_fixed.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = m_fixed.h; path = ../../prboom/m_fixed.h; sourceTree = ""; }; + 3DC1C9EB14B63EC900680D02 /* m_menu.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = m_menu.c; path = ../../prboom/m_menu.c; sourceTree = ""; }; + 3DC1C9EC14B63EC900680D02 /* m_menu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = m_menu.h; path = ../../prboom/m_menu.h; sourceTree = ""; }; + 3DC1C9ED14B63EC900680D02 /* m_misc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = m_misc.c; path = ../../prboom/m_misc.c; sourceTree = ""; }; + 3DC1C9EE14B63EC900680D02 /* m_misc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = m_misc.h; path = ../../prboom/m_misc.h; sourceTree = ""; }; + 3DC1C9EF14B63EC900680D02 /* m_random.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = m_random.c; path = ../../prboom/m_random.c; sourceTree = ""; }; + 3DC1C9F014B63EC900680D02 /* m_random.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = m_random.h; path = ../../prboom/m_random.h; sourceTree = ""; }; + 3DC1C9F114B63EC900680D02 /* m_swap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = m_swap.h; path = ../../prboom/m_swap.h; sourceTree = ""; }; + 3DC1C9F214B63EC900680D02 /* Makefile.am */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Makefile.am; path = ../../prboom/Makefile.am; sourceTree = ""; }; + 3DC1C9F314B63EC900680D02 /* md5.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = md5.c; path = ../../prboom/md5.c; sourceTree = ""; }; + 3DC1C9F414B63EC900680D02 /* md5.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = md5.h; path = ../../prboom/md5.h; sourceTree = ""; }; + 3DC1C9F514B63EC900680D02 /* mmus2mid.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mmus2mid.c; path = ../../prboom/mmus2mid.c; sourceTree = ""; }; + 3DC1C9F614B63EC900680D02 /* mmus2mid.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mmus2mid.h; path = ../../prboom/mmus2mid.h; sourceTree = ""; }; + 3DC1C9F714B63EC900680D02 /* p_ceilng.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = p_ceilng.c; path = ../../prboom/p_ceilng.c; sourceTree = ""; }; + 3DC1C9F814B63EC900680D02 /* p_checksum.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = p_checksum.c; path = ../../prboom/p_checksum.c; sourceTree = ""; }; + 3DC1C9F914B63EC900680D02 /* p_checksum.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = p_checksum.h; path = ../../prboom/p_checksum.h; sourceTree = ""; }; + 3DC1C9FA14B63EC900680D02 /* p_doors.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = p_doors.c; path = ../../prboom/p_doors.c; sourceTree = ""; }; + 3DC1C9FB14B63EC900680D02 /* p_enemy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = p_enemy.c; path = ../../prboom/p_enemy.c; sourceTree = ""; }; + 3DC1C9FC14B63EC900680D02 /* p_enemy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = p_enemy.h; path = ../../prboom/p_enemy.h; sourceTree = ""; }; + 3DC1C9FD14B63EC900680D02 /* p_floor.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = p_floor.c; path = ../../prboom/p_floor.c; sourceTree = ""; }; + 3DC1C9FE14B63EC900680D02 /* p_genlin.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = p_genlin.c; path = ../../prboom/p_genlin.c; sourceTree = ""; }; + 3DC1C9FF14B63EC900680D02 /* p_inter.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = p_inter.c; path = ../../prboom/p_inter.c; sourceTree = ""; }; + 3DC1CA0014B63EC900680D02 /* p_inter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = p_inter.h; path = ../../prboom/p_inter.h; sourceTree = ""; }; + 3DC1CA0114B63EC900680D02 /* p_lights.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = p_lights.c; path = ../../prboom/p_lights.c; sourceTree = ""; }; + 3DC1CA0214B63EC900680D02 /* p_map.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = p_map.c; path = ../../prboom/p_map.c; sourceTree = ""; }; + 3DC1CA0314B63EC900680D02 /* p_map.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = p_map.h; path = ../../prboom/p_map.h; sourceTree = ""; }; + 3DC1CA0414B63EC900680D02 /* p_maputl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = p_maputl.c; path = ../../prboom/p_maputl.c; sourceTree = ""; }; + 3DC1CA0514B63EC900680D02 /* p_maputl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = p_maputl.h; path = ../../prboom/p_maputl.h; sourceTree = ""; }; + 3DC1CA0614B63EC900680D02 /* p_mobj.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = p_mobj.c; path = ../../prboom/p_mobj.c; sourceTree = ""; }; + 3DC1CA0714B63EC900680D02 /* p_mobj.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = p_mobj.h; path = ../../prboom/p_mobj.h; sourceTree = ""; }; + 3DC1CA0814B63EC900680D02 /* p_plats.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = p_plats.c; path = ../../prboom/p_plats.c; sourceTree = ""; }; + 3DC1CA0914B63EC900680D02 /* p_pspr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = p_pspr.c; path = ../../prboom/p_pspr.c; sourceTree = ""; }; + 3DC1CA0A14B63EC900680D02 /* p_pspr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = p_pspr.h; path = ../../prboom/p_pspr.h; sourceTree = ""; }; + 3DC1CA0B14B63EC900680D02 /* p_saveg.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = p_saveg.c; path = ../../prboom/p_saveg.c; sourceTree = ""; }; + 3DC1CA0C14B63EC900680D02 /* p_saveg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = p_saveg.h; path = ../../prboom/p_saveg.h; sourceTree = ""; }; + 3DC1CA0D14B63EC900680D02 /* p_setup.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = p_setup.c; path = ../../prboom/p_setup.c; sourceTree = ""; }; + 3DC1CA0E14B63EC900680D02 /* p_setup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = p_setup.h; path = ../../prboom/p_setup.h; sourceTree = ""; }; + 3DC1CA0F14B63EC900680D02 /* p_sight.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = p_sight.c; path = ../../prboom/p_sight.c; sourceTree = ""; }; + 3DC1CA1014B63EC900680D02 /* p_spec.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = p_spec.c; path = ../../prboom/p_spec.c; sourceTree = ""; }; + 3DC1CA1114B63EC900680D02 /* p_spec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = p_spec.h; path = ../../prboom/p_spec.h; sourceTree = ""; }; + 3DC1CA1214B63EC900680D02 /* p_switch.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = p_switch.c; path = ../../prboom/p_switch.c; sourceTree = ""; }; + 3DC1CA1314B63EC900680D02 /* p_telept.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = p_telept.c; path = ../../prboom/p_telept.c; sourceTree = ""; }; + 3DC1CA1414B63EC900680D02 /* p_tick.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = p_tick.c; path = ../../prboom/p_tick.c; sourceTree = ""; }; + 3DC1CA1514B63EC900680D02 /* p_tick.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = p_tick.h; path = ../../prboom/p_tick.h; sourceTree = ""; }; + 3DC1CA1614B63EC900680D02 /* p_user.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = p_user.c; path = ../../prboom/p_user.c; sourceTree = ""; }; + 3DC1CA1714B63EC900680D02 /* p_user.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = p_user.h; path = ../../prboom/p_user.h; sourceTree = ""; }; + 3DC1CA1814B63EC900680D02 /* protocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = protocol.h; path = ../../prboom/protocol.h; sourceTree = ""; }; + 3DC1CA1914B63EC900680D02 /* r_bsp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = r_bsp.c; path = ../../prboom/r_bsp.c; sourceTree = ""; }; + 3DC1CA1A14B63EC900680D02 /* r_bsp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = r_bsp.h; path = ../../prboom/r_bsp.h; sourceTree = ""; }; + 3DC1CA1B14B63EC900680D02 /* r_data.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = r_data.c; path = ../../prboom/r_data.c; sourceTree = ""; }; + 3DC1CA1C14B63EC900680D02 /* r_data.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = r_data.h; path = ../../prboom/r_data.h; sourceTree = ""; }; + 3DC1CA1D14B63EC900680D02 /* r_defs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = r_defs.h; path = ../../prboom/r_defs.h; sourceTree = ""; }; + 3DC1CA1E14B63EC900680D02 /* r_demo.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = r_demo.c; path = ../../prboom/r_demo.c; sourceTree = ""; }; + 3DC1CA1F14B63EC900680D02 /* r_demo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = r_demo.h; path = ../../prboom/r_demo.h; sourceTree = ""; }; + 3DC1CA2014B63EC900680D02 /* r_draw.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = r_draw.c; path = ../../prboom/r_draw.c; sourceTree = ""; }; + 3DC1CA2114B63EC900680D02 /* r_draw.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = r_draw.h; path = ../../prboom/r_draw.h; sourceTree = ""; }; + 3DC1CA2214B63EC900680D02 /* r_drawcolpipeline.inl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = r_drawcolpipeline.inl; path = ../../prboom/r_drawcolpipeline.inl; sourceTree = ""; }; + 3DC1CA2314B63EC900680D02 /* r_drawcolumn.inl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = r_drawcolumn.inl; path = ../../prboom/r_drawcolumn.inl; sourceTree = ""; }; + 3DC1CA2414B63EC900680D02 /* r_drawflush.inl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = r_drawflush.inl; path = ../../prboom/r_drawflush.inl; sourceTree = ""; }; + 3DC1CA2514B63EC900680D02 /* r_drawspan.inl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = r_drawspan.inl; path = ../../prboom/r_drawspan.inl; sourceTree = ""; }; + 3DC1CA2614B63EC900680D02 /* r_filter.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = r_filter.c; path = ../../prboom/r_filter.c; sourceTree = ""; }; + 3DC1CA2714B63EC900680D02 /* r_filter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = r_filter.h; path = ../../prboom/r_filter.h; sourceTree = ""; }; + 3DC1CA2814B63EC900680D02 /* r_fps.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = r_fps.c; path = ../../prboom/r_fps.c; sourceTree = ""; }; + 3DC1CA2914B63EC900680D02 /* r_fps.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = r_fps.h; path = ../../prboom/r_fps.h; sourceTree = ""; }; + 3DC1CA2A14B63EC900680D02 /* r_main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = r_main.c; path = ../../prboom/r_main.c; sourceTree = ""; }; + 3DC1CA2B14B63EC900680D02 /* r_main.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = r_main.h; path = ../../prboom/r_main.h; sourceTree = ""; }; + 3DC1CA2C14B63EC900680D02 /* r_patch.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = r_patch.c; path = ../../prboom/r_patch.c; sourceTree = ""; }; + 3DC1CA2D14B63EC900680D02 /* r_patch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = r_patch.h; path = ../../prboom/r_patch.h; sourceTree = ""; }; + 3DC1CA2E14B63EC900680D02 /* r_plane.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = r_plane.c; path = ../../prboom/r_plane.c; sourceTree = ""; }; + 3DC1CA2F14B63EC900680D02 /* r_plane.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = r_plane.h; path = ../../prboom/r_plane.h; sourceTree = ""; }; + 3DC1CA3014B63EC900680D02 /* r_segs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = r_segs.c; path = ../../prboom/r_segs.c; sourceTree = ""; }; + 3DC1CA3114B63EC900680D02 /* r_segs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = r_segs.h; path = ../../prboom/r_segs.h; sourceTree = ""; }; + 3DC1CA3214B63EC900680D02 /* r_sky.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = r_sky.c; path = ../../prboom/r_sky.c; sourceTree = ""; }; + 3DC1CA3314B63EC900680D02 /* r_sky.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = r_sky.h; path = ../../prboom/r_sky.h; sourceTree = ""; }; + 3DC1CA3414B63EC900680D02 /* r_state.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = r_state.h; path = ../../prboom/r_state.h; sourceTree = ""; }; + 3DC1CA3514B63EC900680D02 /* r_things.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = r_things.c; path = ../../prboom/r_things.c; sourceTree = ""; }; + 3DC1CA3614B63EC900680D02 /* r_things.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = r_things.h; path = ../../prboom/r_things.h; sourceTree = ""; }; + 3DC1CA3714B63EC900680D02 /* s_sound.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = s_sound.c; path = ../../prboom/s_sound.c; sourceTree = ""; }; + 3DC1CA3814B63EC900680D02 /* s_sound.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = s_sound.h; path = ../../prboom/s_sound.h; sourceTree = ""; }; + 3DC1CA3D14B63EC900680D02 /* i_sound.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = i_sound.c; sourceTree = ""; }; + 3DC1CA4114B63EC900680D02 /* SDL_opengl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SDL_opengl.h; path = ../../prboom/SDL_opengl.h; sourceTree = ""; }; + 3DC1CA4214B63EC900680D02 /* sounds.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = sounds.c; path = ../../prboom/sounds.c; sourceTree = ""; }; + 3DC1CA4314B63EC900680D02 /* sounds.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sounds.h; path = ../../prboom/sounds.h; sourceTree = ""; }; + 3DC1CA4414B63EC900680D02 /* st_lib.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = st_lib.c; path = ../../prboom/st_lib.c; sourceTree = ""; }; + 3DC1CA4514B63EC900680D02 /* st_lib.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = st_lib.h; path = ../../prboom/st_lib.h; sourceTree = ""; }; + 3DC1CA4614B63EC900680D02 /* st_stuff.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = st_stuff.c; path = ../../prboom/st_stuff.c; sourceTree = ""; }; + 3DC1CA4714B63EC900680D02 /* st_stuff.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = st_stuff.h; path = ../../prboom/st_stuff.h; sourceTree = ""; }; + 3DC1CA4814B63EC900680D02 /* tables.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = tables.c; path = ../../prboom/tables.c; sourceTree = ""; }; + 3DC1CA4914B63EC900680D02 /* tables.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = tables.h; path = ../../prboom/tables.h; sourceTree = ""; }; + 3DC1CA4A14B63EC900680D02 /* v_video.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = v_video.c; path = ../../prboom/v_video.c; sourceTree = ""; }; + 3DC1CA4B14B63EC900680D02 /* v_video.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = v_video.h; path = ../../prboom/v_video.h; sourceTree = ""; }; + 3DC1CA4C14B63EC900680D02 /* version.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = version.c; path = ../../prboom/version.c; sourceTree = ""; }; + 3DC1CA4D14B63EC900680D02 /* version.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = version.h; path = ../../prboom/version.h; sourceTree = ""; }; + 3DC1CA4E14B63EC900680D02 /* w_memcache.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = w_memcache.c; path = ../../prboom/w_memcache.c; sourceTree = ""; }; + 3DC1CA4F14B63EC900680D02 /* w_mmap.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = w_mmap.c; path = ../../prboom/w_mmap.c; sourceTree = ""; }; + 3DC1CA5014B63EC900680D02 /* w_wad.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = w_wad.c; path = ../../prboom/w_wad.c; sourceTree = ""; }; + 3DC1CA5114B63EC900680D02 /* w_wad.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = w_wad.h; path = ../../prboom/w_wad.h; sourceTree = ""; }; + 3DC1CA5214B63EC900680D02 /* wi_stuff.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wi_stuff.c; path = ../../prboom/wi_stuff.c; sourceTree = ""; }; + 3DC1CA5314B63EC900680D02 /* wi_stuff.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = wi_stuff.h; path = ../../prboom/wi_stuff.h; sourceTree = ""; }; + 3DC1CA5414B63EC900680D02 /* z_bmalloc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = z_bmalloc.c; path = ../../prboom/z_bmalloc.c; sourceTree = ""; }; + 3DC1CA5514B63EC900680D02 /* z_bmalloc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = z_bmalloc.h; path = ../../prboom/z_bmalloc.h; sourceTree = ""; }; + 3DC1CA5614B63EC900680D02 /* z_zone.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = z_zone.c; path = ../../prboom/z_zone.c; sourceTree = ""; }; + 3DC1CA5714B63EC900680D02 /* z_zone.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = z_zone.h; path = ../../prboom/z_zone.h; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 3DC1C85214B63E1B00680D02 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 3DC1C84A14B63E1B00680D02 = { + isa = PBXGroup; + children = ( + 3DC1C9B114B63EBA00680D02 /* prboom */, + 3DC1C85614B63E1B00680D02 /* Products */, + ); + sourceTree = ""; + }; + 3DC1C85614B63E1B00680D02 /* Products */ = { + isa = PBXGroup; + children = ( + 3DC1C85514B63E1B00680D02 /* libprboom.a */, + ); + name = Products; + sourceTree = ""; + }; + 3DC1C9B114B63EBA00680D02 /* prboom */ = { + isa = PBXGroup; + children = ( + 3DC1C9B214B63EC900680D02 /* am_map.c */, + 3DC1C9B314B63EC900680D02 /* am_map.h */, + 3DC1C9B414B63EC900680D02 /* config.h */, + 3DC1C9B514B63EC900680D02 /* d_client.c */, + 3DC1C9B614B63EC900680D02 /* d_deh.c */, + 3DC1C9B714B63EC900680D02 /* d_deh.h */, + 3DC1C9B814B63EC900680D02 /* d_englsh.h */, + 3DC1C9B914B63EC900680D02 /* d_event.h */, + 3DC1C9BB14B63EC900680D02 /* d_items.c */, + 3DC1C9BC14B63EC900680D02 /* d_items.h */, + 3DC1C9BD14B63EC900680D02 /* d_main.c */, + 3DC1C9BE14B63EC900680D02 /* d_main.h */, + 3DC1C9BF14B63EC900680D02 /* d_net.h */, + 3DC1C9C014B63EC900680D02 /* d_player.h */, + 3DC1C9C114B63EC900680D02 /* d_server.c */, + 3DC1C9C214B63EC900680D02 /* d_think.h */, + 3DC1C9C314B63EC900680D02 /* d_ticcmd.h */, + 3DC1C9C414B63EC900680D02 /* doomdata.h */, + 3DC1C9C514B63EC900680D02 /* doomdef.c */, + 3DC1C9C614B63EC900680D02 /* doomdef.h */, + 3DC1C9C714B63EC900680D02 /* doomstat.c */, + 3DC1C9C814B63EC900680D02 /* doomstat.h */, + 3DC1C9C914B63EC900680D02 /* doomtype.h */, + 3DC1C9CA14B63EC900680D02 /* dstrings.c */, + 3DC1C9CB14B63EC900680D02 /* dstrings.h */, + 3DC1C9CC14B63EC900680D02 /* f_finale.c */, + 3DC1C9CD14B63EC900680D02 /* f_finale.h */, + 3DC1C9CE14B63EC900680D02 /* f_wipe.c */, + 3DC1C9CF14B63EC900680D02 /* f_wipe.h */, + 3DC1C9D014B63EC900680D02 /* g_game.c */, + 3DC1C9D114B63EC900680D02 /* g_game.h */, + 3DC1C9D214B63EC900680D02 /* gl_intern.h */, + 3DC1C9D314B63EC900680D02 /* gl_main.c */, + 3DC1C9D414B63EC900680D02 /* gl_struct.h */, + 3DC1C9D514B63EC900680D02 /* gl_texture.c */, + 3DC1C9D614B63EC900680D02 /* hu_lib.c */, + 3DC1C9D714B63EC900680D02 /* hu_lib.h */, + 3DC1C9D814B63EC900680D02 /* hu_stuff.c */, + 3DC1C9D914B63EC900680D02 /* hu_stuff.h */, + 3DC1C9DA14B63EC900680D02 /* i_joy.h */, + 3DC1C9DB14B63EC900680D02 /* i_main.h */, + 3DC1C9DC14B63EC900680D02 /* i_network.h */, + 3DC1C9DD14B63EC900680D02 /* i_sound.h */, + 3DC1C9DE14B63EC900680D02 /* i_system.h */, + 3DC1C9DF14B63EC900680D02 /* i_video.h */, + 3DC1C9E014B63EC900680D02 /* info.c */, + 3DC1C9E114B63EC900680D02 /* info.h */, + 3DC1C9E214B63EC900680D02 /* lprintf.c */, + 3DC1C9E314B63EC900680D02 /* lprintf.h */, + 3DC1C9E414B63EC900680D02 /* m_argv.c */, + 3DC1C9E514B63EC900680D02 /* m_argv.h */, + 3DC1C9E614B63EC900680D02 /* m_bbox.c */, + 3DC1C9E714B63EC900680D02 /* m_bbox.h */, + 3DC1C9E814B63EC900680D02 /* m_cheat.c */, + 3DC1C9E914B63EC900680D02 /* m_cheat.h */, + 3DC1C9EA14B63EC900680D02 /* m_fixed.h */, + 3DC1C9EB14B63EC900680D02 /* m_menu.c */, + 3DC1C9EC14B63EC900680D02 /* m_menu.h */, + 3DC1C9ED14B63EC900680D02 /* m_misc.c */, + 3DC1C9EE14B63EC900680D02 /* m_misc.h */, + 3DC1C9EF14B63EC900680D02 /* m_random.c */, + 3DC1C9F014B63EC900680D02 /* m_random.h */, + 3DC1C9F114B63EC900680D02 /* m_swap.h */, + 3DC1C9F214B63EC900680D02 /* Makefile.am */, + 3DC1C9F314B63EC900680D02 /* md5.c */, + 3DC1C9F414B63EC900680D02 /* md5.h */, + 3DC1C9F514B63EC900680D02 /* mmus2mid.c */, + 3DC1C9F614B63EC900680D02 /* mmus2mid.h */, + 3DC1C9F714B63EC900680D02 /* p_ceilng.c */, + 3DC1C9F814B63EC900680D02 /* p_checksum.c */, + 3DC1C9F914B63EC900680D02 /* p_checksum.h */, + 3DC1C9FA14B63EC900680D02 /* p_doors.c */, + 3DC1C9FB14B63EC900680D02 /* p_enemy.c */, + 3DC1C9FC14B63EC900680D02 /* p_enemy.h */, + 3DC1C9FD14B63EC900680D02 /* p_floor.c */, + 3DC1C9FE14B63EC900680D02 /* p_genlin.c */, + 3DC1C9FF14B63EC900680D02 /* p_inter.c */, + 3DC1CA0014B63EC900680D02 /* p_inter.h */, + 3DC1CA0114B63EC900680D02 /* p_lights.c */, + 3DC1CA0214B63EC900680D02 /* p_map.c */, + 3DC1CA0314B63EC900680D02 /* p_map.h */, + 3DC1CA0414B63EC900680D02 /* p_maputl.c */, + 3DC1CA0514B63EC900680D02 /* p_maputl.h */, + 3DC1CA0614B63EC900680D02 /* p_mobj.c */, + 3DC1CA0714B63EC900680D02 /* p_mobj.h */, + 3DC1CA0814B63EC900680D02 /* p_plats.c */, + 3DC1CA0914B63EC900680D02 /* p_pspr.c */, + 3DC1CA0A14B63EC900680D02 /* p_pspr.h */, + 3DC1CA0B14B63EC900680D02 /* p_saveg.c */, + 3DC1CA0C14B63EC900680D02 /* p_saveg.h */, + 3DC1CA0D14B63EC900680D02 /* p_setup.c */, + 3DC1CA0E14B63EC900680D02 /* p_setup.h */, + 3DC1CA0F14B63EC900680D02 /* p_sight.c */, + 3DC1CA1014B63EC900680D02 /* p_spec.c */, + 3DC1CA1114B63EC900680D02 /* p_spec.h */, + 3DC1CA1214B63EC900680D02 /* p_switch.c */, + 3DC1CA1314B63EC900680D02 /* p_telept.c */, + 3DC1CA1414B63EC900680D02 /* p_tick.c */, + 3DC1CA1514B63EC900680D02 /* p_tick.h */, + 3DC1CA1614B63EC900680D02 /* p_user.c */, + 3DC1CA1714B63EC900680D02 /* p_user.h */, + 3DC1CA1814B63EC900680D02 /* protocol.h */, + 3DC1CA1914B63EC900680D02 /* r_bsp.c */, + 3DC1CA1A14B63EC900680D02 /* r_bsp.h */, + 3DC1CA1B14B63EC900680D02 /* r_data.c */, + 3DC1CA1C14B63EC900680D02 /* r_data.h */, + 3DC1CA1D14B63EC900680D02 /* r_defs.h */, + 3DC1CA1E14B63EC900680D02 /* r_demo.c */, + 3DC1CA1F14B63EC900680D02 /* r_demo.h */, + 3DC1CA2014B63EC900680D02 /* r_draw.c */, + 3DC1CA2114B63EC900680D02 /* r_draw.h */, + 3DC1CA2214B63EC900680D02 /* r_drawcolpipeline.inl */, + 3DC1CA2314B63EC900680D02 /* r_drawcolumn.inl */, + 3DC1CA2414B63EC900680D02 /* r_drawflush.inl */, + 3DC1CA2514B63EC900680D02 /* r_drawspan.inl */, + 3DC1CA2614B63EC900680D02 /* r_filter.c */, + 3DC1CA2714B63EC900680D02 /* r_filter.h */, + 3DC1CA2814B63EC900680D02 /* r_fps.c */, + 3DC1CA2914B63EC900680D02 /* r_fps.h */, + 3DC1CA2A14B63EC900680D02 /* r_main.c */, + 3DC1CA2B14B63EC900680D02 /* r_main.h */, + 3DC1CA2C14B63EC900680D02 /* r_patch.c */, + 3DC1CA2D14B63EC900680D02 /* r_patch.h */, + 3DC1CA2E14B63EC900680D02 /* r_plane.c */, + 3DC1CA2F14B63EC900680D02 /* r_plane.h */, + 3DC1CA3014B63EC900680D02 /* r_segs.c */, + 3DC1CA3114B63EC900680D02 /* r_segs.h */, + 3DC1CA3214B63EC900680D02 /* r_sky.c */, + 3DC1CA3314B63EC900680D02 /* r_sky.h */, + 3DC1CA3414B63EC900680D02 /* r_state.h */, + 3DC1CA3514B63EC900680D02 /* r_things.c */, + 3DC1CA3614B63EC900680D02 /* r_things.h */, + 3DC1CA3714B63EC900680D02 /* s_sound.c */, + 3DC1CA3814B63EC900680D02 /* s_sound.h */, + 3DC1CA3914B63EC900680D02 /* SDL */, + 3DC1CA4114B63EC900680D02 /* SDL_opengl.h */, + 3DC1CA4214B63EC900680D02 /* sounds.c */, + 3DC1CA4314B63EC900680D02 /* sounds.h */, + 3DC1CA4414B63EC900680D02 /* st_lib.c */, + 3DC1CA4514B63EC900680D02 /* st_lib.h */, + 3DC1CA4614B63EC900680D02 /* st_stuff.c */, + 3DC1CA4714B63EC900680D02 /* st_stuff.h */, + 3DC1CA4814B63EC900680D02 /* tables.c */, + 3DC1CA4914B63EC900680D02 /* tables.h */, + 3DC1CA4A14B63EC900680D02 /* v_video.c */, + 3DC1CA4B14B63EC900680D02 /* v_video.h */, + 3DC1CA4C14B63EC900680D02 /* version.c */, + 3DC1CA4D14B63EC900680D02 /* version.h */, + 3DC1CA4E14B63EC900680D02 /* w_memcache.c */, + 3DC1CA4F14B63EC900680D02 /* w_mmap.c */, + 3DC1CA5014B63EC900680D02 /* w_wad.c */, + 3DC1CA5114B63EC900680D02 /* w_wad.h */, + 3DC1CA5214B63EC900680D02 /* wi_stuff.c */, + 3DC1CA5314B63EC900680D02 /* wi_stuff.h */, + 3DC1CA5414B63EC900680D02 /* z_bmalloc.c */, + 3DC1CA5514B63EC900680D02 /* z_bmalloc.h */, + 3DC1CA5614B63EC900680D02 /* z_zone.c */, + 3DC1CA5714B63EC900680D02 /* z_zone.h */, + ); + name = prboom; + sourceTree = ""; + }; + 3DC1CA3914B63EC900680D02 /* SDL */ = { + isa = PBXGroup; + children = ( + 3DC1CA3D14B63EC900680D02 /* i_sound.c */, + ); + name = SDL; + path = ../../prboom/SDL; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 3DC1C85314B63E1B00680D02 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 3DC1CA5914B63EC900680D02 /* am_map.h in Headers */, + 3DC1CA5A14B63EC900680D02 /* config.h in Headers */, + 3DC1CA5D14B63EC900680D02 /* d_deh.h in Headers */, + 3DC1CA5E14B63EC900680D02 /* d_englsh.h in Headers */, + 3DC1CA5F14B63EC900680D02 /* d_event.h in Headers */, + 3DC1CA6214B63EC900680D02 /* d_items.h in Headers */, + 3DC1CA6414B63EC900680D02 /* d_main.h in Headers */, + 3DC1CA6514B63EC900680D02 /* d_net.h in Headers */, + 3DC1CA6614B63EC900680D02 /* d_player.h in Headers */, + 3DC1CA6814B63EC900680D02 /* d_think.h in Headers */, + 3DC1CA6914B63EC900680D02 /* d_ticcmd.h in Headers */, + 3DC1CA6A14B63EC900680D02 /* doomdata.h in Headers */, + 3DC1CA6C14B63EC900680D02 /* doomdef.h in Headers */, + 3DC1CA6E14B63EC900680D02 /* doomstat.h in Headers */, + 3DC1CA6F14B63EC900680D02 /* doomtype.h in Headers */, + 3DC1CA7114B63EC900680D02 /* dstrings.h in Headers */, + 3DC1CA7314B63EC900680D02 /* f_finale.h in Headers */, + 3DC1CA7514B63EC900680D02 /* f_wipe.h in Headers */, + 3DC1CA7714B63EC900680D02 /* g_game.h in Headers */, + 3DC1CA7814B63EC900680D02 /* gl_intern.h in Headers */, + 3DC1CA7A14B63EC900680D02 /* gl_struct.h in Headers */, + 3DC1CA7D14B63EC900680D02 /* hu_lib.h in Headers */, + 3DC1CA7F14B63EC900680D02 /* hu_stuff.h in Headers */, + 3DC1CA8014B63EC900680D02 /* i_joy.h in Headers */, + 3DC1CA8114B63EC900680D02 /* i_main.h in Headers */, + 3DC1CA8214B63EC900680D02 /* i_network.h in Headers */, + 3DC1CA8314B63EC900680D02 /* i_sound.h in Headers */, + 3DC1CA8414B63EC900680D02 /* i_system.h in Headers */, + 3DC1CA8514B63EC900680D02 /* i_video.h in Headers */, + 3DC1CA8714B63EC900680D02 /* info.h in Headers */, + 3DC1CA8914B63EC900680D02 /* lprintf.h in Headers */, + 3DC1CA8B14B63EC900680D02 /* m_argv.h in Headers */, + 3DC1CA8D14B63EC900680D02 /* m_bbox.h in Headers */, + 3DC1CA8F14B63EC900680D02 /* m_cheat.h in Headers */, + 3DC1CA9014B63EC900680D02 /* m_fixed.h in Headers */, + 3DC1CA9214B63EC900680D02 /* m_menu.h in Headers */, + 3DC1CA9414B63EC900680D02 /* m_misc.h in Headers */, + 3DC1CA9614B63EC900680D02 /* m_random.h in Headers */, + 3DC1CA9714B63EC900680D02 /* m_swap.h in Headers */, + 3DC1CA9914B63EC900680D02 /* md5.h in Headers */, + 3DC1CA9B14B63EC900680D02 /* mmus2mid.h in Headers */, + 3DC1CA9E14B63EC900680D02 /* p_checksum.h in Headers */, + 3DC1CAA114B63EC900680D02 /* p_enemy.h in Headers */, + 3DC1CAA514B63EC900680D02 /* p_inter.h in Headers */, + 3DC1CAA814B63EC900680D02 /* p_map.h in Headers */, + 3DC1CAAA14B63EC900680D02 /* p_maputl.h in Headers */, + 3DC1CAAC14B63EC900680D02 /* p_mobj.h in Headers */, + 3DC1CAAF14B63EC900680D02 /* p_pspr.h in Headers */, + 3DC1CAB114B63EC900680D02 /* p_saveg.h in Headers */, + 3DC1CAB314B63EC900680D02 /* p_setup.h in Headers */, + 3DC1CAB614B63EC900680D02 /* p_spec.h in Headers */, + 3DC1CABA14B63EC900680D02 /* p_tick.h in Headers */, + 3DC1CABC14B63EC900680D02 /* p_user.h in Headers */, + 3DC1CABD14B63EC900680D02 /* protocol.h in Headers */, + 3DC1CABF14B63EC900680D02 /* r_bsp.h in Headers */, + 3DC1CAC114B63EC900680D02 /* r_data.h in Headers */, + 3DC1CAC214B63EC900680D02 /* r_defs.h in Headers */, + 3DC1CAC414B63EC900680D02 /* r_demo.h in Headers */, + 3DC1CAC614B63EC900680D02 /* r_draw.h in Headers */, + 3DC1CAC814B63EC900680D02 /* r_filter.h in Headers */, + 3DC1CACA14B63EC900680D02 /* r_fps.h in Headers */, + 3DC1CACC14B63EC900680D02 /* r_main.h in Headers */, + 3DC1CACE14B63EC900680D02 /* r_patch.h in Headers */, + 3DC1CAD014B63EC900680D02 /* r_plane.h in Headers */, + 3DC1CAD214B63EC900680D02 /* r_segs.h in Headers */, + 3DC1CAD414B63EC900680D02 /* r_sky.h in Headers */, + 3DC1CAD514B63EC900680D02 /* r_state.h in Headers */, + 3DC1CAD714B63EC900680D02 /* r_things.h in Headers */, + 3DC1CAD914B63EC900680D02 /* s_sound.h in Headers */, + 3DC1CAE114B63ECA00680D02 /* SDL_opengl.h in Headers */, + 3DC1CAE314B63ECA00680D02 /* sounds.h in Headers */, + 3DC1CAE514B63ECA00680D02 /* st_lib.h in Headers */, + 3DC1CAE714B63ECA00680D02 /* st_stuff.h in Headers */, + 3DC1CAE914B63ECA00680D02 /* tables.h in Headers */, + 3DC1CAEB14B63ECA00680D02 /* v_video.h in Headers */, + 3DC1CAED14B63ECA00680D02 /* version.h in Headers */, + 3DC1CAF114B63ECA00680D02 /* w_wad.h in Headers */, + 3DC1CAF314B63ECA00680D02 /* wi_stuff.h in Headers */, + 3DC1CAF514B63ECA00680D02 /* z_bmalloc.h in Headers */, + 3DC1CAF714B63ECA00680D02 /* z_zone.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 3DC1C85414B63E1B00680D02 /* prboom */ = { + isa = PBXNativeTarget; + buildConfigurationList = 3DC1C86214B63E1B00680D02 /* Build configuration list for PBXNativeTarget "prboom" */; + buildPhases = ( + 3DC1C85114B63E1B00680D02 /* Sources */, + 3DC1C85214B63E1B00680D02 /* Frameworks */, + 3DC1C85314B63E1B00680D02 /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = prboom; + productName = prboom; + productReference = 3DC1C85514B63E1B00680D02 /* libprboom.a */; + productType = "com.apple.product-type.library.static"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 3DC1C84C14B63E1B00680D02 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0500; + }; + buildConfigurationList = 3DC1C84F14B63E1B00680D02 /* Build configuration list for PBXProject "prboom" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 3DC1C84A14B63E1B00680D02; + productRefGroup = 3DC1C85614B63E1B00680D02 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 3DC1C85414B63E1B00680D02 /* prboom */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 3DC1C85114B63E1B00680D02 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 3DC1CA5814B63EC900680D02 /* am_map.c in Sources */, + 3DC1CA5B14B63EC900680D02 /* d_client.c in Sources */, + 3DC1CA5C14B63EC900680D02 /* d_deh.c in Sources */, + 3DC1CA6114B63EC900680D02 /* d_items.c in Sources */, + 3DC1CA6314B63EC900680D02 /* d_main.c in Sources */, + 3DC1CA6714B63EC900680D02 /* d_server.c in Sources */, + 3DC1CA6B14B63EC900680D02 /* doomdef.c in Sources */, + 3DC1CA6D14B63EC900680D02 /* doomstat.c in Sources */, + 3DC1CA7014B63EC900680D02 /* dstrings.c in Sources */, + 3DC1CA7214B63EC900680D02 /* f_finale.c in Sources */, + 3DC1CA7414B63EC900680D02 /* f_wipe.c in Sources */, + 3DC1CA7614B63EC900680D02 /* g_game.c in Sources */, + 3DC1CA7914B63EC900680D02 /* gl_main.c in Sources */, + 3DC1CA7B14B63EC900680D02 /* gl_texture.c in Sources */, + 3DC1CA7C14B63EC900680D02 /* hu_lib.c in Sources */, + 3DC1CA7E14B63EC900680D02 /* hu_stuff.c in Sources */, + 3DC1CA8614B63EC900680D02 /* info.c in Sources */, + 3DC1CA8814B63EC900680D02 /* lprintf.c in Sources */, + 3DC1CA8A14B63EC900680D02 /* m_argv.c in Sources */, + 3DC1CA8C14B63EC900680D02 /* m_bbox.c in Sources */, + 3DC1CA8E14B63EC900680D02 /* m_cheat.c in Sources */, + 3DC1CA9114B63EC900680D02 /* m_menu.c in Sources */, + 3DC1CA9314B63EC900680D02 /* m_misc.c in Sources */, + 3DC1CA9514B63EC900680D02 /* m_random.c in Sources */, + 3DC1CA9814B63EC900680D02 /* md5.c in Sources */, + 3DC1CA9A14B63EC900680D02 /* mmus2mid.c in Sources */, + 3DC1CA9C14B63EC900680D02 /* p_ceilng.c in Sources */, + 3DC1CA9D14B63EC900680D02 /* p_checksum.c in Sources */, + 3DC1CA9F14B63EC900680D02 /* p_doors.c in Sources */, + 3DC1CAA014B63EC900680D02 /* p_enemy.c in Sources */, + 3DC1CAA214B63EC900680D02 /* p_floor.c in Sources */, + 3DC1CAA314B63EC900680D02 /* p_genlin.c in Sources */, + 3DC1CAA414B63EC900680D02 /* p_inter.c in Sources */, + 3DC1CAA614B63EC900680D02 /* p_lights.c in Sources */, + 3DC1CAA714B63EC900680D02 /* p_map.c in Sources */, + 3DC1CAA914B63EC900680D02 /* p_maputl.c in Sources */, + 3DC1CAAB14B63EC900680D02 /* p_mobj.c in Sources */, + 3DC1CAAD14B63EC900680D02 /* p_plats.c in Sources */, + 3DC1CAAE14B63EC900680D02 /* p_pspr.c in Sources */, + 3DC1CAB014B63EC900680D02 /* p_saveg.c in Sources */, + 3DC1CAB214B63EC900680D02 /* p_setup.c in Sources */, + 3DC1CAB414B63EC900680D02 /* p_sight.c in Sources */, + 3DC1CAB514B63EC900680D02 /* p_spec.c in Sources */, + 3DC1CAB714B63EC900680D02 /* p_switch.c in Sources */, + 3DC1CAB814B63EC900680D02 /* p_telept.c in Sources */, + 3DC1CAB914B63EC900680D02 /* p_tick.c in Sources */, + 3DC1CABB14B63EC900680D02 /* p_user.c in Sources */, + 3DC1CABE14B63EC900680D02 /* r_bsp.c in Sources */, + 3DC1CAC014B63EC900680D02 /* r_data.c in Sources */, + 3DC1CAC314B63EC900680D02 /* r_demo.c in Sources */, + 3DC1CAC514B63EC900680D02 /* r_draw.c in Sources */, + 3DC1CAC714B63EC900680D02 /* r_filter.c in Sources */, + 3DC1CAC914B63EC900680D02 /* r_fps.c in Sources */, + 3DC1CACB14B63EC900680D02 /* r_main.c in Sources */, + 3DC1CACD14B63EC900680D02 /* r_patch.c in Sources */, + 3DC1CACF14B63EC900680D02 /* r_plane.c in Sources */, + 3DC1CAD114B63EC900680D02 /* r_segs.c in Sources */, + 3DC1CAD314B63EC900680D02 /* r_sky.c in Sources */, + 3DC1CAD614B63EC900680D02 /* r_things.c in Sources */, + 3DC1CAD814B63EC900680D02 /* s_sound.c in Sources */, + 3DC1CADD14B63ECA00680D02 /* i_sound.c in Sources */, + 3DC1CAE214B63ECA00680D02 /* sounds.c in Sources */, + 3DC1CAE414B63ECA00680D02 /* st_lib.c in Sources */, + 3DC1CAE614B63ECA00680D02 /* st_stuff.c in Sources */, + 3DC1CAE814B63ECA00680D02 /* tables.c in Sources */, + 3DC1CAEA14B63ECA00680D02 /* v_video.c in Sources */, + 3DC1CAEC14B63ECA00680D02 /* version.c in Sources */, + 3DC1CAEE14B63ECA00680D02 /* w_memcache.c in Sources */, + 3DC1CAEF14B63ECA00680D02 /* w_mmap.c in Sources */, + 3DC1CAF014B63ECA00680D02 /* w_wad.c in Sources */, + 3DC1CAF214B63ECA00680D02 /* wi_stuff.c in Sources */, + 3DC1CAF414B63ECA00680D02 /* z_bmalloc.c in Sources */, + 3DC1CAF614B63ECA00680D02 /* z_zone.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 3DC1C86014B63E1B00680D02 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + COPY_PHASE_STRIP = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(inherited)", + HAVE_CONFIG_H, + IPHONE, + ); + GCC_SYMBOLS_PRIVATE_EXTERN = YES; + GCC_THUMB_SUPPORT = NO; + GCC_VERSION = com.apple.compilers.llvmgcc42; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = NO; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 3.0; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + USER_HEADER_SEARCH_PATHS = "../doomengine ../../SDL_shim"; + }; + name = Debug; + }; + 3DC1C86114B63E1B00680D02 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + COPY_PHASE_STRIP = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_PREPROCESSOR_DEFINITIONS = ( + HAVE_CONFIG_H, + IPHONE, + ); + GCC_SYMBOLS_PRIVATE_EXTERN = YES; + GCC_THUMB_SUPPORT = NO; + GCC_VERSION = com.apple.compilers.llvmgcc42; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = NO; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 3.0; + SDKROOT = iphoneos; + USER_HEADER_SEARCH_PATHS = "../doomengine ../../SDL_shim"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 3DC1C86314B63E1B00680D02 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + DSTROOT = /tmp/prboom.dst; + GCC_VERSION = ""; + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + 3DC1C86414B63E1B00680D02 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + DSTROOT = /tmp/prboom.dst; + GCC_VERSION = ""; + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 3DC1C84F14B63E1B00680D02 /* Build configuration list for PBXProject "prboom" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 3DC1C86014B63E1B00680D02 /* Debug */, + 3DC1C86114B63E1B00680D02 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 3DC1C86214B63E1B00680D02 /* Build configuration list for PBXNativeTarget "prboom" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 3DC1C86314B63E1B00680D02 /* Debug */, + 3DC1C86414B63E1B00680D02 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 3DC1C84C14B63E1B00680D02 /* Project object */; +} diff --git a/common/ios/prboom/prboom.xcodeproj/xcuserdata/Farrand.xcuserdatad/xcschemes/prboom.xcscheme b/common/ios/prboom/prboom.xcodeproj/xcuserdata/Farrand.xcuserdatad/xcschemes/prboom.xcscheme new file mode 100644 index 0000000..8521216 --- /dev/null +++ b/common/ios/prboom/prboom.xcodeproj/xcuserdata/Farrand.xcuserdatad/xcschemes/prboom.xcscheme @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/common/ios/prboom/prboom.xcodeproj/xcuserdata/Farrand.xcuserdatad/xcschemes/xcschememanagement.plist b/common/ios/prboom/prboom.xcodeproj/xcuserdata/Farrand.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..f4e9da4 --- /dev/null +++ b/common/ios/prboom/prboom.xcodeproj/xcuserdata/Farrand.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,22 @@ + + + + + SchemeUserState + + prboom.xcscheme + + orderHint + 3 + + + SuppressBuildableAutocreation + + 3DC1C85414B63E1B00680D02 + + primary + + + + + diff --git a/common/ios/prboom/prboom.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/prboom.xcscheme b/common/ios/prboom/prboom.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/prboom.xcscheme new file mode 100755 index 0000000..5a118ec --- /dev/null +++ b/common/ios/prboom/prboom.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/prboom.xcscheme @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/common/ios/prboom/prboom.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/xcschememanagement.plist b/common/ios/prboom/prboom.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100755 index 0000000..84a67f9 --- /dev/null +++ b/common/ios/prboom/prboom.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,24 @@ + + + + + SchemeUserState + + prboom.xcscheme + + isShown + + orderHint + 4 + + + SuppressBuildableAutocreation + + 3DC1C85414B63E1B00680D02 + + primary + + + + + diff --git a/common/ios/prboom/prboom.xcodeproj/xcuserdata/ryan.gerleve.xcuserdatad/xcschemes/prboom.xcscheme b/common/ios/prboom/prboom.xcodeproj/xcuserdata/ryan.gerleve.xcuserdatad/xcschemes/prboom.xcscheme new file mode 100755 index 0000000..5a118ec --- /dev/null +++ b/common/ios/prboom/prboom.xcodeproj/xcuserdata/ryan.gerleve.xcuserdatad/xcschemes/prboom.xcscheme @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/common/ios/prboom/prboom.xcodeproj/xcuserdata/ryan.gerleve.xcuserdatad/xcschemes/xcschememanagement.plist b/common/ios/prboom/prboom.xcodeproj/xcuserdata/ryan.gerleve.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100755 index 0000000..d520a7f --- /dev/null +++ b/common/ios/prboom/prboom.xcodeproj/xcuserdata/ryan.gerleve.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,22 @@ + + + + + SchemeUserState + + prboom.xcscheme + + orderHint + 6 + + + SuppressBuildableAutocreation + + 3DC1C85414B63E1B00680D02 + + primary + + + + + diff --git a/common/ios/tess/tess.xcodeproj/project.pbxproj b/common/ios/tess/tess.xcodeproj/project.pbxproj new file mode 100755 index 0000000..d8d611a --- /dev/null +++ b/common/ios/tess/tess.xcodeproj/project.pbxproj @@ -0,0 +1,299 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 3D155FF014B51175000D33AA /* dict-list.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D155FD814B51175000D33AA /* dict-list.h */; }; + 3D155FF114B51175000D33AA /* dict.c in Sources */ = {isa = PBXBuildFile; fileRef = 3D155FD914B51175000D33AA /* dict.c */; }; + 3D155FF214B51175000D33AA /* dict.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D155FDA14B51175000D33AA /* dict.h */; }; + 3D155FF314B51175000D33AA /* geom.c in Sources */ = {isa = PBXBuildFile; fileRef = 3D155FDB14B51175000D33AA /* geom.c */; }; + 3D155FF414B51175000D33AA /* geom.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D155FDC14B51175000D33AA /* geom.h */; }; + 3D155FF514B51175000D33AA /* memalloc.c in Sources */ = {isa = PBXBuildFile; fileRef = 3D155FDD14B51175000D33AA /* memalloc.c */; }; + 3D155FF614B51175000D33AA /* memalloc.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D155FDE14B51175000D33AA /* memalloc.h */; }; + 3D155FF714B51175000D33AA /* mesh.c in Sources */ = {isa = PBXBuildFile; fileRef = 3D155FDF14B51175000D33AA /* mesh.c */; }; + 3D155FF814B51175000D33AA /* mesh.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D155FE014B51175000D33AA /* mesh.h */; }; + 3D155FF914B51175000D33AA /* normal.c in Sources */ = {isa = PBXBuildFile; fileRef = 3D155FE114B51175000D33AA /* normal.c */; }; + 3D155FFA14B51175000D33AA /* normal.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D155FE214B51175000D33AA /* normal.h */; }; + 3D155FFB14B51175000D33AA /* priorityq-heap.c in Sources */ = {isa = PBXBuildFile; fileRef = 3D155FE314B51175000D33AA /* priorityq-heap.c */; }; + 3D155FFC14B51175000D33AA /* priorityq-heap.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D155FE414B51175000D33AA /* priorityq-heap.h */; }; + 3D155FFD14B51175000D33AA /* priorityq-sort.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D155FE514B51175000D33AA /* priorityq-sort.h */; }; + 3D155FFE14B51175000D33AA /* priorityq.c in Sources */ = {isa = PBXBuildFile; fileRef = 3D155FE614B51175000D33AA /* priorityq.c */; }; + 3D155FFF14B51175000D33AA /* priorityq.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D155FE714B51175000D33AA /* priorityq.h */; }; + 3D15600014B51175000D33AA /* render.c in Sources */ = {isa = PBXBuildFile; fileRef = 3D155FE814B51175000D33AA /* render.c */; }; + 3D15600114B51175000D33AA /* render.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D155FE914B51175000D33AA /* render.h */; }; + 3D15600214B51175000D33AA /* sweep.c in Sources */ = {isa = PBXBuildFile; fileRef = 3D155FEA14B51175000D33AA /* sweep.c */; }; + 3D15600314B51175000D33AA /* sweep.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D155FEB14B51175000D33AA /* sweep.h */; }; + 3D15600414B51175000D33AA /* tess.c in Sources */ = {isa = PBXBuildFile; fileRef = 3D155FEC14B51175000D33AA /* tess.c */; }; + 3D15600514B51175000D33AA /* tess.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D155FED14B51175000D33AA /* tess.h */; }; + 3D15600614B51175000D33AA /* tessmono.c in Sources */ = {isa = PBXBuildFile; fileRef = 3D155FEE14B51175000D33AA /* tessmono.c */; }; + 3D15600714B51175000D33AA /* tessmono.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D155FEF14B51175000D33AA /* tessmono.h */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 3D155FC114B51127000D33AA /* libtess.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libtess.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 3D155FD814B51175000D33AA /* dict-list.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "dict-list.h"; path = "../../libtess/dict-list.h"; sourceTree = ""; }; + 3D155FD914B51175000D33AA /* dict.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dict.c; path = ../../libtess/dict.c; sourceTree = ""; }; + 3D155FDA14B51175000D33AA /* dict.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dict.h; path = ../../libtess/dict.h; sourceTree = ""; }; + 3D155FDB14B51175000D33AA /* geom.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = geom.c; path = ../../libtess/geom.c; sourceTree = ""; }; + 3D155FDC14B51175000D33AA /* geom.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = geom.h; path = ../../libtess/geom.h; sourceTree = ""; }; + 3D155FDD14B51175000D33AA /* memalloc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = memalloc.c; path = ../../libtess/memalloc.c; sourceTree = ""; }; + 3D155FDE14B51175000D33AA /* memalloc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = memalloc.h; path = ../../libtess/memalloc.h; sourceTree = ""; }; + 3D155FDF14B51175000D33AA /* mesh.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mesh.c; path = ../../libtess/mesh.c; sourceTree = ""; }; + 3D155FE014B51175000D33AA /* mesh.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mesh.h; path = ../../libtess/mesh.h; sourceTree = ""; }; + 3D155FE114B51175000D33AA /* normal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = normal.c; path = ../../libtess/normal.c; sourceTree = ""; }; + 3D155FE214B51175000D33AA /* normal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = normal.h; path = ../../libtess/normal.h; sourceTree = ""; }; + 3D155FE314B51175000D33AA /* priorityq-heap.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "priorityq-heap.c"; path = "../../libtess/priorityq-heap.c"; sourceTree = ""; }; + 3D155FE414B51175000D33AA /* priorityq-heap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "priorityq-heap.h"; path = "../../libtess/priorityq-heap.h"; sourceTree = ""; }; + 3D155FE514B51175000D33AA /* priorityq-sort.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "priorityq-sort.h"; path = "../../libtess/priorityq-sort.h"; sourceTree = ""; }; + 3D155FE614B51175000D33AA /* priorityq.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = priorityq.c; path = ../../libtess/priorityq.c; sourceTree = ""; }; + 3D155FE714B51175000D33AA /* priorityq.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = priorityq.h; path = ../../libtess/priorityq.h; sourceTree = ""; }; + 3D155FE814B51175000D33AA /* render.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = render.c; path = ../../libtess/render.c; sourceTree = ""; }; + 3D155FE914B51175000D33AA /* render.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = render.h; path = ../../libtess/render.h; sourceTree = ""; }; + 3D155FEA14B51175000D33AA /* sweep.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = sweep.c; path = ../../libtess/sweep.c; sourceTree = ""; }; + 3D155FEB14B51175000D33AA /* sweep.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sweep.h; path = ../../libtess/sweep.h; sourceTree = ""; }; + 3D155FEC14B51175000D33AA /* tess.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = tess.c; path = ../../libtess/tess.c; sourceTree = ""; }; + 3D155FED14B51175000D33AA /* tess.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = tess.h; path = ../../libtess/tess.h; sourceTree = ""; }; + 3D155FEE14B51175000D33AA /* tessmono.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = tessmono.c; path = ../../libtess/tessmono.c; sourceTree = ""; }; + 3D155FEF14B51175000D33AA /* tessmono.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = tessmono.h; path = ../../libtess/tessmono.h; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 3D155FBE14B51127000D33AA /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 3D155FB614B51127000D33AA = { + isa = PBXGroup; + children = ( + 3D155FD714B51142000D33AA /* libtess */, + 3D155FC214B51127000D33AA /* Products */, + ); + sourceTree = ""; + }; + 3D155FC214B51127000D33AA /* Products */ = { + isa = PBXGroup; + children = ( + 3D155FC114B51127000D33AA /* libtess.a */, + ); + name = Products; + sourceTree = ""; + }; + 3D155FD714B51142000D33AA /* libtess */ = { + isa = PBXGroup; + children = ( + 3D155FD814B51175000D33AA /* dict-list.h */, + 3D155FD914B51175000D33AA /* dict.c */, + 3D155FDA14B51175000D33AA /* dict.h */, + 3D155FDB14B51175000D33AA /* geom.c */, + 3D155FDC14B51175000D33AA /* geom.h */, + 3D155FDD14B51175000D33AA /* memalloc.c */, + 3D155FDE14B51175000D33AA /* memalloc.h */, + 3D155FDF14B51175000D33AA /* mesh.c */, + 3D155FE014B51175000D33AA /* mesh.h */, + 3D155FE114B51175000D33AA /* normal.c */, + 3D155FE214B51175000D33AA /* normal.h */, + 3D155FE314B51175000D33AA /* priorityq-heap.c */, + 3D155FE414B51175000D33AA /* priorityq-heap.h */, + 3D155FE514B51175000D33AA /* priorityq-sort.h */, + 3D155FE614B51175000D33AA /* priorityq.c */, + 3D155FE714B51175000D33AA /* priorityq.h */, + 3D155FE814B51175000D33AA /* render.c */, + 3D155FE914B51175000D33AA /* render.h */, + 3D155FEA14B51175000D33AA /* sweep.c */, + 3D155FEB14B51175000D33AA /* sweep.h */, + 3D155FEC14B51175000D33AA /* tess.c */, + 3D155FED14B51175000D33AA /* tess.h */, + 3D155FEE14B51175000D33AA /* tessmono.c */, + 3D155FEF14B51175000D33AA /* tessmono.h */, + ); + name = libtess; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 3D155FBF14B51127000D33AA /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 3D155FF014B51175000D33AA /* dict-list.h in Headers */, + 3D155FF214B51175000D33AA /* dict.h in Headers */, + 3D155FF414B51175000D33AA /* geom.h in Headers */, + 3D155FF614B51175000D33AA /* memalloc.h in Headers */, + 3D155FF814B51175000D33AA /* mesh.h in Headers */, + 3D155FFA14B51175000D33AA /* normal.h in Headers */, + 3D155FFC14B51175000D33AA /* priorityq-heap.h in Headers */, + 3D155FFD14B51175000D33AA /* priorityq-sort.h in Headers */, + 3D155FFF14B51175000D33AA /* priorityq.h in Headers */, + 3D15600114B51175000D33AA /* render.h in Headers */, + 3D15600314B51175000D33AA /* sweep.h in Headers */, + 3D15600514B51175000D33AA /* tess.h in Headers */, + 3D15600714B51175000D33AA /* tessmono.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 3D155FC014B51127000D33AA /* tess */ = { + isa = PBXNativeTarget; + buildConfigurationList = 3D155FCE14B51127000D33AA /* Build configuration list for PBXNativeTarget "tess" */; + buildPhases = ( + 3D155FBD14B51127000D33AA /* Sources */, + 3D155FBE14B51127000D33AA /* Frameworks */, + 3D155FBF14B51127000D33AA /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = tess; + productName = tess; + productReference = 3D155FC114B51127000D33AA /* libtess.a */; + productType = "com.apple.product-type.library.static"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 3D155FB814B51127000D33AA /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0500; + }; + buildConfigurationList = 3D155FBB14B51127000D33AA /* Build configuration list for PBXProject "tess" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 3D155FB614B51127000D33AA; + productRefGroup = 3D155FC214B51127000D33AA /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 3D155FC014B51127000D33AA /* tess */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 3D155FBD14B51127000D33AA /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 3D155FF114B51175000D33AA /* dict.c in Sources */, + 3D155FF314B51175000D33AA /* geom.c in Sources */, + 3D155FF514B51175000D33AA /* memalloc.c in Sources */, + 3D155FF714B51175000D33AA /* mesh.c in Sources */, + 3D155FF914B51175000D33AA /* normal.c in Sources */, + 3D155FFB14B51175000D33AA /* priorityq-heap.c in Sources */, + 3D155FFE14B51175000D33AA /* priorityq.c in Sources */, + 3D15600014B51175000D33AA /* render.c in Sources */, + 3D15600214B51175000D33AA /* sweep.c in Sources */, + 3D15600414B51175000D33AA /* tess.c in Sources */, + 3D15600614B51175000D33AA /* tessmono.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 3D155FCC14B51127000D33AA /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + COPY_PHASE_STRIP = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_THUMB_SUPPORT = NO; + GCC_VERSION = com.apple.compilers.llvmgcc42; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 3.0; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + }; + name = Debug; + }; + 3D155FCD14B51127000D33AA /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + COPY_PHASE_STRIP = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_THUMB_SUPPORT = NO; + GCC_VERSION = com.apple.compilers.llvmgcc42; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 3.0; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 3D155FCF14B51127000D33AA /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + DSTROOT = /tmp/tess.dst; + GCC_VERSION = ""; + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + 3D155FD014B51127000D33AA /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + DSTROOT = /tmp/tess.dst; + GCC_VERSION = ""; + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 3D155FBB14B51127000D33AA /* Build configuration list for PBXProject "tess" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 3D155FCC14B51127000D33AA /* Debug */, + 3D155FCD14B51127000D33AA /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 3D155FCE14B51127000D33AA /* Build configuration list for PBXNativeTarget "tess" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 3D155FCF14B51127000D33AA /* Debug */, + 3D155FD014B51127000D33AA /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 3D155FB814B51127000D33AA /* Project object */; +} diff --git a/common/ios/tess/tess.xcodeproj/xcuserdata/Farrand.xcuserdatad/xcschemes/tess.xcscheme b/common/ios/tess/tess.xcodeproj/xcuserdata/Farrand.xcuserdatad/xcschemes/tess.xcscheme new file mode 100644 index 0000000..3763caa --- /dev/null +++ b/common/ios/tess/tess.xcodeproj/xcuserdata/Farrand.xcuserdatad/xcschemes/tess.xcscheme @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/common/ios/tess/tess.xcodeproj/xcuserdata/Farrand.xcuserdatad/xcschemes/xcschememanagement.plist b/common/ios/tess/tess.xcodeproj/xcuserdata/Farrand.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..34e1225 --- /dev/null +++ b/common/ios/tess/tess.xcodeproj/xcuserdata/Farrand.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,22 @@ + + + + + SchemeUserState + + tess.xcscheme + + orderHint + 5 + + + SuppressBuildableAutocreation + + 3D155FC014B51127000D33AA + + primary + + + + + diff --git a/common/ios/tess/tess.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/tess.xcscheme b/common/ios/tess/tess.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/tess.xcscheme new file mode 100755 index 0000000..8d099a8 --- /dev/null +++ b/common/ios/tess/tess.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/tess.xcscheme @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/common/ios/tess/tess.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/xcschememanagement.plist b/common/ios/tess/tess.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100755 index 0000000..43dd611 --- /dev/null +++ b/common/ios/tess/tess.xcodeproj/xcuserdata/jeff.farrand.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,24 @@ + + + + + SchemeUserState + + tess.xcscheme + + isShown + + orderHint + 7 + + + SuppressBuildableAutocreation + + 3D155FC014B51127000D33AA + + primary + + + + + diff --git a/common/ios/tess/tess.xcodeproj/xcuserdata/ryan.gerleve.xcuserdatad/xcschemes/tess.xcscheme b/common/ios/tess/tess.xcodeproj/xcuserdata/ryan.gerleve.xcuserdatad/xcschemes/tess.xcscheme new file mode 100755 index 0000000..8d099a8 --- /dev/null +++ b/common/ios/tess/tess.xcodeproj/xcuserdata/ryan.gerleve.xcuserdatad/xcschemes/tess.xcscheme @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/common/ios/tess/tess.xcodeproj/xcuserdata/ryan.gerleve.xcuserdatad/xcschemes/xcschememanagement.plist b/common/ios/tess/tess.xcodeproj/xcuserdata/ryan.gerleve.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100755 index 0000000..405f2cd --- /dev/null +++ b/common/ios/tess/tess.xcodeproj/xcuserdata/ryan.gerleve.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,22 @@ + + + + + SchemeUserState + + tess.xcscheme + + orderHint + 4 + + + SuppressBuildableAutocreation + + 3D155FC014B51127000D33AA + + primary + + + + + diff --git a/common/libtess/README b/common/libtess/README new file mode 100755 index 0000000..66a6011 --- /dev/null +++ b/common/libtess/README @@ -0,0 +1,446 @@ +/* +*/ + +General Polygon Tesselation +--------------------------- + + This note describes a tesselator for polygons consisting of one or + more closed contours. It is backward-compatible with the current + OpenGL Utilities tesselator, and is intended to replace it. Here is + a summary of the major differences: + + - input contours can be intersecting, self-intersecting, or degenerate. + + - supports a choice of several winding rules for determining which parts + of the polygon are on the "interior". This makes it possible to do + CSG operations on polygons. + + - boundary extraction: instead of tesselating the polygon, returns a + set of closed contours which separate the interior from the exterior. + + - returns the output as a small number of triangle fans and strips, + rather than a list of independent triangles (when possible). + + - output is available as an explicit mesh (a quad-edge structure), + in addition to the normal callback interface. + + - the algorithm used is extremely robust. + + +The interface +------------- + + The tesselator state is maintained in a "tesselator object". + These are allocated and destroyed using + + GLUtesselator *gluNewTess( void ); + void gluDeleteTess( GLUtesselator *tess ); + + Several tesselator objects may be used simultaneously. + + Inputs + ------ + + The input contours are specified with the following routines: + + void gluTessBeginPolygon( GLUtesselator *tess ); + void gluTessBeginContour( GLUtesselator *tess ); + void gluTessVertex( GLUtesselator *tess, GLUcoord coords[3], void *data ); + void gluTessEndContour( GLUtesselator *tess ); + void gluTessEndPolygon( GLUtesselator *tess ); + + Within each BeginPolygon/EndPolygon pair, there can be zero or more + calls to BeginContour/EndContour. Within each contour, there are zero + or more calls to gluTessVertex(). The vertices specify a closed + contour (the last vertex of each contour is automatically linked to + the first). + + "coords" give the coordinates of the vertex in 3-space. For useful + results, all vertices should lie in some plane, since the vertices + are projected onto a plane before tesselation. "data" is a pointer + to a user-defined vertex structure, which typically contains other + information such as color, texture coordinates, normal, etc. It is + used to refer to the vertex during rendering. + + The library can be compiled in single- or double-precision; the type + GLUcoord represents either "float" or "double" accordingly. The GLU + version will be available in double-precision only. Compile with + GLU_TESS_API_FLOAT defined to get the single-precision version. + + When EndPolygon is called, the tesselation algorithm determines + which regions are interior to the given contours, according to one + of several "winding rules" described below. The interior regions + are then tesselated, and the output is provided as callbacks. + + + Rendering Callbacks + ------------------- + + Callbacks are specified by the client using + + void gluTessCallback( GLUtesselator *tess, GLenum which, void (*fn)()); + + If "fn" is NULL, any previously defined callback is discarded. + + The callbacks used to provide output are: /* which == */ + + void begin( GLenum type ); /* GLU_TESS_BEGIN */ + void edgeFlag( GLboolean flag ); /* GLU_TESS_EDGE_FLAG */ + void vertex( void *data ); /* GLU_TESS_VERTEX */ + void end( void ); /* GLU_TESS_END */ + + Any of the callbacks may be left undefined; if so, the corresponding + information will not be supplied during rendering. + + The "begin" callback indicates the start of a primitive; type is one + of GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, or GL_TRIANGLES (but see the + notes on "boundary extraction" below). + + It is followed by any number of "vertex" callbacks, which supply the + vertices in the same order as expected by the corresponding glBegin() + call. After the last vertex of a given primitive, there is a callback + to "end". + + If the "edgeFlag" callback is provided, no triangle fans or strips + will be used. When edgeFlag is called, if "flag" is GL_TRUE then each + vertex which follows begins an edge which lies on the polygon boundary + (ie. an edge which separates an interior region from an exterior one). + If "flag" is GL_FALSE, each vertex which follows begins an edge which lies + in the polygon interior. "edgeFlag" will be called before the first + call to "vertex". + + Other Callbacks + --------------- + + void mesh( GLUmesh *mesh ); /* GLU_TESS_MESH */ + + - Returns an explicit mesh, represented using the quad-edge structure + (Guibas/Stolfi '85). Other implementations of this interface might + use a different mesh structure, so this is available only only as an + SGI extension. When the mesh is no longer needed, it should be freed + using + + void gluDeleteMesh( GLUmesh *mesh ); + + There is a brief description of this data structure in the include + file "mesh.h". For the full details, see L. Guibas and J. Stolfi, + Primitives for the manipulation of general subdivisions and the + computation of Voronoi diagrams, ACM Transactions on Graphics, + 4(2):74-123, April 1985. For an introduction, see the course notes + for CS348a, "Mathematical Foundations of Computer Graphics", + available at the Stanford bookstore (and taught during the fall + quarter). + + void error( GLenum errno ); /* GLU_TESS_ERROR */ + + - errno is one of GLU_TESS_MISSING_BEGIN_POLYGON, + GLU_TESS_MISSING_END_POLYGON, + GLU_TESS_MISSING_BEGIN_CONTOUR, + GLU_TESS_MISSING_END_CONTOUR, + GLU_TESS_COORD_TOO_LARGE, + GLU_TESS_NEED_COMBINE_CALLBACK + + The first four are obvious. The interface recovers from these + errors by inserting the missing call(s). + + GLU_TESS_COORD_TOO_LARGE says that some vertex coordinate exceeded + the predefined constant GLU_TESS_MAX_COORD in absolute value, and + that the value has been clamped. (Coordinate values must be small + enough so that two can be multiplied together without overflow.) + + GLU_TESS_NEED_COMBINE_CALLBACK says that the algorithm detected an + intersection between two edges in the input data, and the "combine" + callback (below) was not provided. No output will be generated. + + + void combine( GLUcoord coords[3], void *data[4], /* GLU_TESS_COMBINE */ + GLUcoord weight[4], void **outData ); + + - When the algorithm detects an intersection, or wishes to merge + features, it needs to create a new vertex. The vertex is defined + as a linear combination of up to 4 existing vertices, referenced + by data[0..3]. The coefficients of the linear combination are + given by weight[0..3]; these weights always sum to 1.0. All vertex + pointers are valid even when some of the weights are zero. + "coords" gives the location of the new vertex. + + The user must allocate another vertex, interpolate parameters + using "data" and "weights", and return the new vertex pointer in + "outData". This handle is supplied during rendering callbacks. + For example, if the polygon lies in an arbitrary plane in 3-space, + and we associate a color with each vertex, the combine callback might + look like this: + + void myCombine( GLUcoord coords[3], VERTEX *d[4], + GLUcoord w[4], VERTEX **dataOut ) + { + VERTEX *new = new_vertex(); + + new->x = coords[0]; + new->y = coords[1]; + new->z = coords[2]; + new->r = w[0]*d[0]->r + w[1]*d[1]->r + w[2]*d[2]->r + w[3]*d[3]->r; + new->g = w[0]*d[0]->g + w[1]*d[1]->g + w[2]*d[2]->g + w[3]*d[3]->g; + new->b = w[0]*d[0]->b + w[1]*d[1]->b + w[2]*d[2]->b + w[3]*d[3]->b; + new->a = w[0]*d[0]->a + w[1]*d[1]->a + w[2]*d[2]->a + w[3]*d[3]->a; + *dataOut = new; + } + + If the algorithm detects an intersection, then the "combine" callback + must be defined, and must write a non-NULL pointer into "dataOut". + Otherwise the GLU_TESS_NEED_COMBINE_CALLBACK error occurs, and no + output is generated. This is the only error that can occur during + tesselation and rendering. + + + Control over Tesselation + ------------------------ + + void gluTessProperty( GLUtesselator *tess, GLenum which, GLUcoord value ); + + Properties defined: + + - GLU_TESS_WINDING_RULE. Possible values: + + GLU_TESS_WINDING_ODD + GLU_TESS_WINDING_NONZERO + GLU_TESS_WINDING_POSITIVE + GLU_TESS_WINDING_NEGATIVE + GLU_TESS_WINDING_ABS_GEQ_TWO + + The input contours parition the plane into regions. A winding + rule determines which of these regions are inside the polygon. + + For a single contour C, the winding number of a point x is simply + the signed number of revolutions we make around x as we travel + once around C (where CCW is positive). When there are several + contours, the individual winding numbers are summed. This + procedure associates a signed integer value with each point x in + the plane. Note that the winding number is the same for all + points in a single region. + + The winding rule classifies a region as "inside" if its winding + number belongs to the chosen category (odd, nonzero, positive, + negative, or absolute value of at least two). The current GLU + tesselator implements the "odd" rule. The "nonzero" rule is another + common way to define the interior. The other three rules are + useful for polygon CSG operations (see below). + + - GLU_TESS_BOUNDARY_ONLY. Values: TRUE (non-zero) or FALSE (zero). + + If TRUE, returns a set of closed contours which separate the + polygon interior and exterior (rather than a tesselation). + Exterior contours are oriented CCW with respect to the normal, + interior contours are oriented CW. The GLU_TESS_BEGIN callback + uses the type GL_LINE_LOOP for each contour. + + - GLU_TESS_TOLERANCE. Value: a real number between 0.0 and 1.0. + + This specifies a tolerance for merging features to reduce the size + of the output. For example, two vertices which are very close to + each other might be replaced by a single vertex. The tolerance + is multiplied by the largest coordinate magnitude of any input vertex; + this specifies the maximum distance that any feature can move as the + result of a single merge operation. If a single feature takes part + in several merge operations, the total distance moved could be larger. + + Feature merging is completely optional; the tolerance is only a hint. + The implementation is free to merge in some cases and not in others, + or to never merge features at all. The default tolerance is zero. + + The current implementation merges vertices only if they are exactly + coincident, regardless of the current tolerance. A vertex is + spliced into an edge only if the implementation is unable to + distinguish which side of the edge the vertex lies on. + Two edges are merged only when both endpoints are identical. + + + void gluTessNormal( GLUtesselator *tess, + GLUcoord x, GLUcoord y, GLUcoord z ) + + - Lets the user supply the polygon normal, if known. All input data + is projected into a plane perpendicular to the normal before + tesselation. All output triangles are oriented CCW with + respect to the normal (CW orientation can be obtained by + reversing the sign of the supplied normal). For example, if + you know that all polygons lie in the x-y plane, call + "gluTessNormal(tess, 0.0, 0.0, 1.0)" before rendering any polygons. + + - If the supplied normal is (0,0,0) (the default value), the + normal is determined as follows. The direction of the normal, + up to its sign, is found by fitting a plane to the vertices, + without regard to how the vertices are connected. It is + expected that the input data lies approximately in plane; + otherwise projection perpendicular to the computed normal may + substantially change the geometry. The sign of the normal is + chosen so that the sum of the signed areas of all input contours + is non-negative (where a CCW contour has positive area). + + - The supplied normal persists until it is changed by another + call to gluTessNormal. + + + Backward compatibility with the GLU tesselator + ---------------------------------------------- + + The preferred interface is the one described above. The following + routines are obsolete, and are provided only for backward compatibility: + + typedef GLUtesselator GLUtriangulatorObj; /* obsolete name */ + + void gluBeginPolygon( GLUtesselator *tess ); + void gluNextContour( GLUtesselator *tess, GLenum type ); + void gluEndPolygon( GLUtesselator *tess ); + + "type" is one of GLU_EXTERIOR, GLU_INTERIOR, GLU_CCW, GLU_CW, or + GLU_UNKNOWN. It is ignored by the current GLU tesselator. + + GLU_BEGIN, GLU_VERTEX, GLU_END, GLU_ERROR, and GLU_EDGE_FLAG are defined + as synonyms for GLU_TESS_BEGIN, GLU_TESS_VERTEX, GLU_TESS_END, + GLU_TESS_ERROR, and GLU_TESS_EDGE_FLAG. + + +Polygon CSG operations +---------------------- + + The features of the tesselator make it easy to find the union, difference, + or intersection of several polygons. + + First, assume that each polygon is defined so that the winding number + is 0 for each exterior region, and 1 for each interior region. Under + this model, CCW contours define the outer boundary of the polygon, and + CW contours define holes. Contours may be nested, but a nested + contour must be oriented oppositely from the contour that contains it. + + If the original polygons do not satisfy this description, they can be + converted to this form by first running the tesselator with the + GLU_TESS_BOUNDARY_ONLY property turned on. This returns a list of + contours satisfying the restriction above. By allocating two + tesselator objects, the callbacks from one tesselator can be fed + directly to the input of another. + + Given two or more polygons of the form above, CSG operations can be + implemented as follows: + + Union + Draw all the input contours as a single polygon. The winding number + of each resulting region is the number of original polygons + which cover it. The union can be extracted using the + GLU_TESS_WINDING_NONZERO or GLU_TESS_WINDING_POSITIVE winding rules. + Note that with the nonzero rule, we would get the same result if + all contour orientations were reversed. + + Intersection (two polygons at a time only) + Draw a single polygon using the contours from both input polygons. + Extract the result using GLU_TESS_WINDING_ABS_GEQ_TWO. (Since this + winding rule looks at the absolute value, reversing all contour + orientations does not change the result.) + + Difference + + Suppose we want to compute A \ (B union C union D). Draw a single + polygon consisting of the unmodified contours from A, followed by + the contours of B,C,D with the vertex order reversed (this changes + the winding number of the interior regions to -1). To extract the + result, use the GLU_TESS_WINDING_POSITIVE rule. + + If B,C,D are the result of a GLU_TESS_BOUNDARY_ONLY call, an + alternative to reversing the vertex order is to reverse the sign of + the supplied normal. For example in the x-y plane, call + gluTessNormal( tess, 0.0, 0.0, -1.0 ). + + +Performance +----------- + + The tesselator is not intended for immediate-mode rendering; when + possible the output should be cached in a user structure or display + list. General polygon tesselation is an inherently difficult problem, + especially given the goal of extreme robustness. + + The implementation makes an effort to output a small number of fans + and strips; this should improve the rendering performance when the + output is used in a display list. + + Single-contour input polygons are first tested to see whether they can + be rendered as a triangle fan with respect to the first vertex (to + avoid running the full decomposition algorithm on convex polygons). + Non-convex polygons may be rendered by this "fast path" as well, if + the algorithm gets lucky in its choice of a starting vertex. + + For best performance follow these guidelines: + + - supply the polygon normal, if available, using gluTessNormal(). + This represents about 10% of the computation time. For example, + if all polygons lie in the x-y plane, use gluTessNormal(tess,0,0,1). + + - render many polygons using the same tesselator object, rather than + allocating a new tesselator for each one. (In a multi-threaded, + multi-processor environment you may get better performance using + several tesselators.) + + +Comparison with the GLU tesselator +---------------------------------- + + On polygons which make it through the "fast path", the tesselator is + 3 to 5 times faster than the GLU tesselator. + + On polygons which don't make it through the fast path (but which don't + have self-intersections or degeneracies), it is about 2 times slower. + + On polygons with self-intersections or degeneraces, there is nothing + to compare against. + + The new tesselator generates many more fans and strips, reducing the + number of vertices that need to be sent to the hardware. + + Key to the statistics: + + vert number of input vertices on all contours + cntr number of input contours + tri number of triangles in all output primitives + strip number of triangle strips + fan number of triangle fans + ind number of independent triangles + ms number of milliseconds for tesselation + (on a 150MHz R4400 Indy) + + Convex polygon examples: + +New: 3 vert, 1 cntr, 1 tri, 0 strip, 0 fan, 1 ind, 0.0459 ms +Old: 3 vert, 1 cntr, 1 tri, 0 strip, 0 fan, 1 ind, 0.149 ms +New: 4 vert, 1 cntr, 2 tri, 0 strip, 1 fan, 0 ind, 0.0459 ms +Old: 4 vert, 1 cntr, 2 tri, 0 strip, 0 fan, 2 ind, 0.161 ms +New: 36 vert, 1 cntr, 34 tri, 0 strip, 1 fan, 0 ind, 0.153 ms +Old: 36 vert, 1 cntr, 34 tri, 0 strip, 0 fan, 34 ind, 0.621 ms + + Concave single-contour polygons: + +New: 5 vert, 1 cntr, 3 tri, 0 strip, 1 fan, 0 ind, 0.052 ms +Old: 5 vert, 1 cntr, 3 tri, 0 strip, 0 fan, 3 ind, 0.252 ms +New: 19 vert, 1 cntr, 17 tri, 2 strip, 2 fan, 1 ind, 0.911 ms +Old: 19 vert, 1 cntr, 17 tri, 0 strip, 0 fan, 17 ind, 0.529 ms +New: 151 vert, 1 cntr, 149 tri, 13 strip, 18 fan, 3 ind, 6.82 ms +Old: 151 vert, 1 cntr, 149 tri, 0 strip, 3 fan, 143 ind, 2.7 ms +New: 574 vert, 1 cntr, 572 tri, 59 strip, 54 fan, 11 ind, 26.6 ms +Old: 574 vert, 1 cntr, 572 tri, 0 strip, 31 fan, 499 ind, 12.4 ms + + Multiple contours, but no intersections: + +New: 7 vert, 2 cntr, 7 tri, 1 strip, 0 fan, 0 ind, 0.527 ms +Old: 7 vert, 2 cntr, 7 tri, 0 strip, 0 fan, 7 ind, 0.274 ms +New: 81 vert, 6 cntr, 89 tri, 9 strip, 7 fan, 6 ind, 3.88 ms +Old: 81 vert, 6 cntr, 89 tri, 0 strip, 13 fan, 61 ind, 2.2 ms +New: 391 vert, 19 cntr, 413 tri, 37 strip, 32 fan, 26 ind, 20.2 ms +Old: 391 vert, 19 cntr, 413 tri, 0 strip, 25 fan, 363 ind, 8.68 ms + + Self-intersecting and degenerate examples: + +Bowtie: 4 vert, 1 cntr, 2 tri, 0 strip, 0 fan, 2 ind, 0.483 ms +Star: 5 vert, 1 cntr, 5 tri, 0 strip, 0 fan, 5 ind, 0.91 ms +Random: 24 vert, 7 cntr, 46 tri, 2 strip, 12 fan, 7 ind, 5.32 ms +Font: 333 vert, 2 cntr, 331 tri, 32 strip, 16 fan, 3 ind, 14.1 ms +: 167 vert, 35 cntr, 254 tri, 8 strip, 56 fan, 52 ind, 46.3 ms +: 78 vert, 1 cntr, 2675 tri, 148 strip, 207 fan, 180 ind, 243 ms +: 12480 vert, 2 cntr, 12478 tri, 736 strip,1275 fan, 5 ind, 1010 ms diff --git a/common/libtess/alg-outline b/common/libtess/alg-outline new file mode 100755 index 0000000..33fd697 --- /dev/null +++ b/common/libtess/alg-outline @@ -0,0 +1,228 @@ +/* +*/ + +This is only a very brief overview. There is quite a bit of +additional documentation in the source code itself. + + +Goals of robust tesselation +--------------------------- + +The tesselation algorithm is fundamentally a 2D algorithm. We +initially project all data into a plane; our goal is to robustly +tesselate the projected data. The same topological tesselation is +then applied to the input data. + +Topologically, the output should always be a tesselation. If the +input is even slightly non-planar, then some triangles will +necessarily be back-facing when viewed from some angles, but the goal +is to minimize this effect. + +The algorithm needs some capability of cleaning up the input data as +well as the numerical errors in its own calculations. One way to do +this is to specify a tolerance as defined above, and clean up the +input and output during the line sweep process. At the very least, +the algorithm must handle coincident vertices, vertices incident to an +edge, and coincident edges. + + +Phases of the algorithm +----------------------- + +1. Find the polygon normal N. +2. Project the vertex data onto a plane. It does not need to be + perpendicular to the normal, eg. we can project onto the plane + perpendicular to the coordinate axis whose dot product with N + is largest. +3. Using a line-sweep algorithm, partition the plane into x-monotone + regions. Any vertical line intersects an x-monotone region in + at most one interval. +4. Triangulate the x-monotone regions. +5. Group the triangles into strips and fans. + + +Finding the normal vector +------------------------- + +A common way to find a polygon normal is to compute the signed area +when the polygon is projected along the three coordinate axes. We +can't do this, since contours can have zero area without being +degenerate (eg. a bowtie). + +We fit a plane to the vertex data, ignoring how they are connected +into contours. Ideally this would be a least-squares fit; however for +our purpose the accuracy of the normal is not important. Instead we +find three vertices which are widely separated, and compute the normal +to the triangle they form. The vertices are chosen so that the +triangle has an area at least 1/sqrt(3) times the largest area of any +triangle formed using the input vertices. + +The contours do affect the orientation of the normal; after computing +the normal, we check that the sum of the signed contour areas is +non-negative, and reverse the normal if necessary. + + +Projecting the vertices +----------------------- + +We project the vertices onto a plane perpendicular to one of the three +coordinate axes. This helps numerical accuracy by removing a +transformation step between the original input data and the data +processed by the algorithm. The projection also compresses the input +data; the 2D distance between vertices after projection may be smaller +than the original 2D distance. However by choosing the coordinate +axis whose dot product with the normal is greatest, the compression +factor is at most 1/sqrt(3). + +Even though the *accuracy* of the normal is not that important (since +we are projecting perpendicular to a coordinate axis anyway), the +*robustness* of the computation is important. For example, if there +are many vertices which lie almost along a line, and one vertex V +which is well-separated from the line, then our normal computation +should involve V otherwise the results will be garbage. + +The advantage of projecting perpendicular to the polygon normal is +that computed intersection points will be as close as possible to +their ideal locations. To get this behavior, define TRUE_PROJECT. + + +The Line Sweep +-------------- + +There are three data structures: the mesh, the event queue, and the +edge dictionary. + +The mesh is a "quad-edge" data structure which records the topology of +the current decomposition; for details see the include file "mesh.h". + +The event queue simply holds all vertices (both original and computed +ones), organized so that we can quickly extract the vertex with the +minimum x-coord (and among those, the one with the minimum y-coord). + +The edge dictionary describes the current intersection of the sweep +line with the regions of the polygon. This is just an ordering of the +edges which intersect the sweep line, sorted by their current order of +intersection. For each pair of edges, we store some information about +the monotone region between them -- these are call "active regions" +(since they are crossed by the current sweep line). + +The basic algorithm is to sweep from left to right, processing each +vertex. The processed portion of the mesh (left of the sweep line) is +a planar decomposition. As we cross each vertex, we update the mesh +and the edge dictionary, then we check any newly adjacent pairs of +edges to see if they intersect. + +A vertex can have any number of edges. Vertices with many edges can +be created as vertices are merged and intersection points are +computed. For unprocessed vertices (right of the sweep line), these +edges are in no particular order around the vertex; for processed +vertices, the topological ordering should match the geometric ordering. + +The vertex processing happens in two phases: first we process are the +left-going edges (all these edges are currently in the edge +dictionary). This involves: + + - deleting the left-going edges from the dictionary; + - relinking the mesh if necessary, so that the order of these edges around + the event vertex matches the order in the dictionary; + - marking any terminated regions (regions which lie between two left-going + edges) as either "inside" or "outside" according to their winding number. + +When there are no left-going edges, and the event vertex is in an +"interior" region, we need to add an edge (to split the region into +monotone pieces). To do this we simply join the event vertex to the +rightmost left endpoint of the upper or lower edge of the containing +region. + +Then we process the right-going edges. This involves: + + - inserting the edges in the edge dictionary; + - computing the winding number of any newly created active regions. + We can compute this incrementally using the winding of each edge + that we cross as we walk through the dictionary. + - relinking the mesh if necessary, so that the order of these edges around + the event vertex matches the order in the dictionary; + - checking any newly adjacent edges for intersection and/or merging. + +If there are no right-going edges, again we need to add one to split +the containing region into monotone pieces. In our case it is most +convenient to add an edge to the leftmost right endpoint of either +containing edge; however we may need to change this later (see the +code for details). + + +Invariants +---------- + +These are the most important invariants maintained during the sweep. +We define a function VertLeq(v1,v2) which defines the order in which +vertices cross the sweep line, and a function EdgeLeq(e1,e2; loc) +which says whether e1 is below e2 at the sweep event location "loc". +This function is defined only at sweep event locations which lie +between the rightmost left endpoint of {e1,e2}, and the leftmost right +endpoint of {e1,e2}. + +Invariants for the Edge Dictionary. + + - Each pair of adjacent edges e2=Succ(e1) satisfies EdgeLeq(e1,e2) + at any valid location of the sweep event. + - If EdgeLeq(e2,e1) as well (at any valid sweep event), then e1 and e2 + share a common endpoint. + - For each e in the dictionary, e->Dst has been processed but not e->Org. + - Each edge e satisfies VertLeq(e->Dst,event) && VertLeq(event,e->Org) + where "event" is the current sweep line event. + - No edge e has zero length. + - No two edges have identical left and right endpoints. + +Invariants for the Mesh (the processed portion). + + - The portion of the mesh left of the sweep line is a planar graph, + ie. there is *some* way to embed it in the plane. + - No processed edge has zero length. + - No two processed vertices have identical coordinates. + - Each "inside" region is monotone, ie. can be broken into two chains + of monotonically increasing vertices according to VertLeq(v1,v2) + - a non-invariant: these chains may intersect (slightly) due to + numerical errors, but this does not affect the algorithm's operation. + +Invariants for the Sweep. + + - If a vertex has any left-going edges, then these must be in the edge + dictionary at the time the vertex is processed. + - If an edge is marked "fixUpperEdge" (it is a temporary edge introduced + by ConnectRightVertex), then it is the only right-going edge from + its associated vertex. (This says that these edges exist only + when it is necessary.) + + +Robustness +---------- + +The key to the robustness of the algorithm is maintaining the +invariants above, especially the correct ordering of the edge +dictionary. We achieve this by: + + 1. Writing the numerical computations for maximum precision rather + than maximum speed. + + 2. Making no assumptions at all about the results of the edge + intersection calculations -- for sufficiently degenerate inputs, + the computed location is not much better than a random number. + + 3. When numerical errors violate the invariants, restore them + by making *topological* changes when necessary (ie. relinking + the mesh structure). + + +Triangulation and Grouping +-------------------------- + +We finish the line sweep before doing any triangulation. This is +because even after a monotone region is complete, there can be further +changes to its vertex data because of further vertex merging. + +After triangulating all monotone regions, we want to group the +triangles into fans and strips. We do this using a greedy approach. +The triangulation itself is not optimized to reduce the number of +primitives; we just try to get a reasonable decomposition of the +computed triangulation. diff --git a/common/libtess/dict-list.h b/common/libtess/dict-list.h new file mode 100755 index 0000000..11331a7 --- /dev/null +++ b/common/libtess/dict-list.h @@ -0,0 +1,100 @@ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * 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 including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * 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 + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ +/* +** Author: Eric Veach, July 1994. +** +*/ + +#ifndef __dict_list_h_ +#define __dict_list_h_ + +/* Use #define's so that another heap implementation can use this one */ + +#define DictKey DictListKey +#define Dict DictList +#define DictNode DictListNode + +#define dictNewDict(frame,leq) __gl_dictListNewDict(frame,leq) +#define dictDeleteDict(dict) __gl_dictListDeleteDict(dict) + +#define dictSearch(dict,key) __gl_dictListSearch(dict,key) +#define dictInsert(dict,key) __gl_dictListInsert(dict,key) +#define dictInsertBefore(dict,node,key) __gl_dictListInsertBefore(dict,node,key) +#define dictDelete(dict,node) __gl_dictListDelete(dict,node) + +#define dictKey(n) __gl_dictListKey(n) +#define dictSucc(n) __gl_dictListSucc(n) +#define dictPred(n) __gl_dictListPred(n) +#define dictMin(d) __gl_dictListMin(d) +#define dictMax(d) __gl_dictListMax(d) + + + +typedef void *DictKey; +typedef struct Dict Dict; +typedef struct DictNode DictNode; + +Dict *dictNewDict( + void *frame, + int (*leq)(void *frame, DictKey key1, DictKey key2) ); + +void dictDeleteDict( Dict *dict ); + +/* Search returns the node with the smallest key greater than or equal + * to the given key. If there is no such key, returns a node whose + * key is NULL. Similarly, Succ(Max(d)) has a NULL key, etc. + */ +DictNode *dictSearch( Dict *dict, DictKey key ); +DictNode *dictInsertBefore( Dict *dict, DictNode *node, DictKey key ); +void dictDelete( Dict *dict, DictNode *node ); + +#define __gl_dictListKey(n) ((n)->key) +#define __gl_dictListSucc(n) ((n)->next) +#define __gl_dictListPred(n) ((n)->prev) +#define __gl_dictListMin(d) ((d)->head.next) +#define __gl_dictListMax(d) ((d)->head.prev) +#define __gl_dictListInsert(d,k) (dictInsertBefore((d),&(d)->head,(k))) + + +/*** Private data structures ***/ + +struct DictNode { + DictKey key; + DictNode *next; + DictNode *prev; +}; + +struct Dict { + DictNode head; + void *frame; + int (*leq)(void *frame, DictKey key1, DictKey key2); +}; + +#endif diff --git a/common/libtess/dict.c b/common/libtess/dict.c new file mode 100755 index 0000000..49d4f75 --- /dev/null +++ b/common/libtess/dict.c @@ -0,0 +1,111 @@ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * 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 including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * 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 + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ +/* +** Author: Eric Veach, July 1994. +** +*/ + +#include +#include "dict-list.h" +#include "memalloc.h" + +/* really __gl_dictListNewDict */ +Dict *dictNewDict( void *frame, + int (*leq)(void *frame, DictKey key1, DictKey key2) ) +{ + Dict *dict = (Dict *) memAlloc( sizeof( Dict )); + DictNode *head; + + if (dict == NULL) return NULL; + + head = &dict->head; + + head->key = NULL; + head->next = head; + head->prev = head; + + dict->frame = frame; + dict->leq = leq; + + return dict; +} + +/* really __gl_dictListDeleteDict */ +void dictDeleteDict( Dict *dict ) +{ + DictNode *node, *next; + + for( node = dict->head.next; node != &dict->head; node = next ) { + next = node->next; + memFree( node ); + } + memFree( dict ); +} + +/* really __gl_dictListInsertBefore */ +DictNode *dictInsertBefore( Dict *dict, DictNode *node, DictKey key ) +{ + DictNode *newNode; + + do { + node = node->prev; + } while( node->key != NULL && ! (*dict->leq)(dict->frame, node->key, key)); + + newNode = (DictNode *) memAlloc( sizeof( DictNode )); + if (newNode == NULL) return NULL; + + newNode->key = key; + newNode->next = node->next; + node->next->prev = newNode; + newNode->prev = node; + node->next = newNode; + + return newNode; +} + +/* really __gl_dictListDelete */ +void dictDelete( Dict *dict, DictNode *node ) /*ARGSUSED*/ +{ + node->next->prev = node->prev; + node->prev->next = node->next; + memFree( node ); +} + +/* really __gl_dictListSearch */ +DictNode *dictSearch( Dict *dict, DictKey key ) +{ + DictNode *node = &dict->head; + + do { + node = node->next; + } while( node->key != NULL && ! (*dict->leq)(dict->frame, key, node->key)); + + return node; +} diff --git a/common/libtess/dict.h b/common/libtess/dict.h new file mode 100755 index 0000000..11331a7 --- /dev/null +++ b/common/libtess/dict.h @@ -0,0 +1,100 @@ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * 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 including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * 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 + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ +/* +** Author: Eric Veach, July 1994. +** +*/ + +#ifndef __dict_list_h_ +#define __dict_list_h_ + +/* Use #define's so that another heap implementation can use this one */ + +#define DictKey DictListKey +#define Dict DictList +#define DictNode DictListNode + +#define dictNewDict(frame,leq) __gl_dictListNewDict(frame,leq) +#define dictDeleteDict(dict) __gl_dictListDeleteDict(dict) + +#define dictSearch(dict,key) __gl_dictListSearch(dict,key) +#define dictInsert(dict,key) __gl_dictListInsert(dict,key) +#define dictInsertBefore(dict,node,key) __gl_dictListInsertBefore(dict,node,key) +#define dictDelete(dict,node) __gl_dictListDelete(dict,node) + +#define dictKey(n) __gl_dictListKey(n) +#define dictSucc(n) __gl_dictListSucc(n) +#define dictPred(n) __gl_dictListPred(n) +#define dictMin(d) __gl_dictListMin(d) +#define dictMax(d) __gl_dictListMax(d) + + + +typedef void *DictKey; +typedef struct Dict Dict; +typedef struct DictNode DictNode; + +Dict *dictNewDict( + void *frame, + int (*leq)(void *frame, DictKey key1, DictKey key2) ); + +void dictDeleteDict( Dict *dict ); + +/* Search returns the node with the smallest key greater than or equal + * to the given key. If there is no such key, returns a node whose + * key is NULL. Similarly, Succ(Max(d)) has a NULL key, etc. + */ +DictNode *dictSearch( Dict *dict, DictKey key ); +DictNode *dictInsertBefore( Dict *dict, DictNode *node, DictKey key ); +void dictDelete( Dict *dict, DictNode *node ); + +#define __gl_dictListKey(n) ((n)->key) +#define __gl_dictListSucc(n) ((n)->next) +#define __gl_dictListPred(n) ((n)->prev) +#define __gl_dictListMin(d) ((d)->head.next) +#define __gl_dictListMax(d) ((d)->head.prev) +#define __gl_dictListInsert(d,k) (dictInsertBefore((d),&(d)->head,(k))) + + +/*** Private data structures ***/ + +struct DictNode { + DictKey key; + DictNode *next; + DictNode *prev; +}; + +struct Dict { + DictNode head; + void *frame; + int (*leq)(void *frame, DictKey key1, DictKey key2); +}; + +#endif diff --git a/common/libtess/geom.c b/common/libtess/geom.c new file mode 100755 index 0000000..8f7c7a6 --- /dev/null +++ b/common/libtess/geom.c @@ -0,0 +1,265 @@ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * 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 including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * 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 + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ +/* +** Author: Eric Veach, July 1994. +** +*/ + +#include "../prboom/SDL_opengl.h" // JDC +//#include "gluos.h" +#include +#include "mesh.h" +#include "geom.h" + +int __gl_vertLeq( GLUvertex *u, GLUvertex *v ) +{ + /* Returns TRUE if u is lexicographically <= v. */ + + return VertLeq( u, v ); +} + +GLdouble __gl_edgeEval( GLUvertex *u, GLUvertex *v, GLUvertex *w ) +{ + /* Given three vertices u,v,w such that VertLeq(u,v) && VertLeq(v,w), + * evaluates the t-coord of the edge uw at the s-coord of the vertex v. + * Returns v->t - (uw)(v->s), ie. the signed distance from uw to v. + * If uw is vertical (and thus passes thru v), the result is zero. + * + * The calculation is extremely accurate and stable, even when v + * is very close to u or w. In particular if we set v->t = 0 and + * let r be the negated result (this evaluates (uw)(v->s)), then + * r is guaranteed to satisfy MIN(u->t,w->t) <= r <= MAX(u->t,w->t). + */ + GLdouble gapL, gapR; + + assert( VertLeq( u, v ) && VertLeq( v, w )); + + gapL = v->s - u->s; + gapR = w->s - v->s; + + if( gapL + gapR > 0 ) { + if( gapL < gapR ) { + return (v->t - u->t) + (u->t - w->t) * (gapL / (gapL + gapR)); + } else { + return (v->t - w->t) + (w->t - u->t) * (gapR / (gapL + gapR)); + } + } + /* vertical line */ + return 0; +} + +GLdouble __gl_edgeSign( GLUvertex *u, GLUvertex *v, GLUvertex *w ) +{ + /* Returns a number whose sign matches EdgeEval(u,v,w) but which + * is cheaper to evaluate. Returns > 0, == 0 , or < 0 + * as v is above, on, or below the edge uw. + */ + GLdouble gapL, gapR; + + assert( VertLeq( u, v ) && VertLeq( v, w )); + + gapL = v->s - u->s; + gapR = w->s - v->s; + + if( gapL + gapR > 0 ) { + return (v->t - w->t) * gapL + (v->t - u->t) * gapR; + } + /* vertical line */ + return 0; +} + + +/*********************************************************************** + * Define versions of EdgeSign, EdgeEval with s and t transposed. + */ + +GLdouble __gl_transEval( GLUvertex *u, GLUvertex *v, GLUvertex *w ) +{ + /* Given three vertices u,v,w such that TransLeq(u,v) && TransLeq(v,w), + * evaluates the t-coord of the edge uw at the s-coord of the vertex v. + * Returns v->s - (uw)(v->t), ie. the signed distance from uw to v. + * If uw is vertical (and thus passes thru v), the result is zero. + * + * The calculation is extremely accurate and stable, even when v + * is very close to u or w. In particular if we set v->s = 0 and + * let r be the negated result (this evaluates (uw)(v->t)), then + * r is guaranteed to satisfy MIN(u->s,w->s) <= r <= MAX(u->s,w->s). + */ + GLdouble gapL, gapR; + + assert( TransLeq( u, v ) && TransLeq( v, w )); + + gapL = v->t - u->t; + gapR = w->t - v->t; + + if( gapL + gapR > 0 ) { + if( gapL < gapR ) { + return (v->s - u->s) + (u->s - w->s) * (gapL / (gapL + gapR)); + } else { + return (v->s - w->s) + (w->s - u->s) * (gapR / (gapL + gapR)); + } + } + /* vertical line */ + return 0; +} + +GLdouble __gl_transSign( GLUvertex *u, GLUvertex *v, GLUvertex *w ) +{ + /* Returns a number whose sign matches TransEval(u,v,w) but which + * is cheaper to evaluate. Returns > 0, == 0 , or < 0 + * as v is above, on, or below the edge uw. + */ + GLdouble gapL, gapR; + + assert( TransLeq( u, v ) && TransLeq( v, w )); + + gapL = v->t - u->t; + gapR = w->t - v->t; + + if( gapL + gapR > 0 ) { + return (v->s - w->s) * gapL + (v->s - u->s) * gapR; + } + /* vertical line */ + return 0; +} + + +int __gl_vertCCW( GLUvertex *u, GLUvertex *v, GLUvertex *w ) +{ + /* For almost-degenerate situations, the results are not reliable. + * Unless the floating-point arithmetic can be performed without + * rounding errors, *any* implementation will give incorrect results + * on some degenerate inputs, so the client must have some way to + * handle this situation. + */ + return (u->s*(v->t - w->t) + v->s*(w->t - u->t) + w->s*(u->t - v->t)) >= 0; +} + +/* Given parameters a,x,b,y returns the value (b*x+a*y)/(a+b), + * or (x+y)/2 if a==b==0. It requires that a,b >= 0, and enforces + * this in the rare case that one argument is slightly negative. + * The implementation is extremely stable numerically. + * In particular it guarantees that the result r satisfies + * MIN(x,y) <= r <= MAX(x,y), and the results are very accurate + * even when a and b differ greatly in magnitude. + */ +#define RealInterpolate(a,x,b,y) \ + (a = (a < 0) ? 0 : a, b = (b < 0) ? 0 : b, \ + ((a <= b) ? ((b == 0) ? ((x+y) / 2) \ + : (x + (y-x) * (a/(a+b)))) \ + : (y + (x-y) * (b/(a+b))))) + +#ifndef FOR_TRITE_TEST_PROGRAM +#define Interpolate(a,x,b,y) RealInterpolate(a,x,b,y) +#else + +/* Claim: the ONLY property the sweep algorithm relies on is that + * MIN(x,y) <= r <= MAX(x,y). This is a nasty way to test that. + */ +#include +extern int RandomInterpolate; + +GLdouble Interpolate( GLdouble a, GLdouble x, GLdouble b, GLdouble y) +{ +printf("*********************%d\n",RandomInterpolate); + if( RandomInterpolate ) { + a = 1.2 * drand48() - 0.1; + a = (a < 0) ? 0 : ((a > 1) ? 1 : a); + b = 1.0 - a; + } + return RealInterpolate(a,x,b,y); +} + +#endif + +#define Swap(a,b) if (1) { GLUvertex *t = a; a = b; b = t; } else + +void __gl_edgeIntersect( GLUvertex *o1, GLUvertex *d1, + GLUvertex *o2, GLUvertex *d2, + GLUvertex *v ) +/* Given edges (o1,d1) and (o2,d2), compute their point of intersection. + * The computed point is guaranteed to lie in the intersection of the + * bounding rectangles defined by each edge. + */ +{ + GLdouble z1, z2; + + /* This is certainly not the most efficient way to find the intersection + * of two line segments, but it is very numerically stable. + * + * Strategy: find the two middle vertices in the VertLeq ordering, + * and interpolate the intersection s-value from these. Then repeat + * using the TransLeq ordering to find the intersection t-value. + */ + + if( ! VertLeq( o1, d1 )) { Swap( o1, d1 ); } + if( ! VertLeq( o2, d2 )) { Swap( o2, d2 ); } + if( ! VertLeq( o1, o2 )) { Swap( o1, o2 ); Swap( d1, d2 ); } + + if( ! VertLeq( o2, d1 )) { + /* Technically, no intersection -- do our best */ + v->s = (o2->s + d1->s) / 2; + } else if( VertLeq( d1, d2 )) { + /* Interpolate between o2 and d1 */ + z1 = EdgeEval( o1, o2, d1 ); + z2 = EdgeEval( o2, d1, d2 ); + if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; } + v->s = Interpolate( z1, o2->s, z2, d1->s ); + } else { + /* Interpolate between o2 and d2 */ + z1 = EdgeSign( o1, o2, d1 ); + z2 = -EdgeSign( o1, d2, d1 ); + if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; } + v->s = Interpolate( z1, o2->s, z2, d2->s ); + } + + /* Now repeat the process for t */ + + if( ! TransLeq( o1, d1 )) { Swap( o1, d1 ); } + if( ! TransLeq( o2, d2 )) { Swap( o2, d2 ); } + if( ! TransLeq( o1, o2 )) { Swap( o1, o2 ); Swap( d1, d2 ); } + + if( ! TransLeq( o2, d1 )) { + /* Technically, no intersection -- do our best */ + v->t = (o2->t + d1->t) / 2; + } else if( TransLeq( d1, d2 )) { + /* Interpolate between o2 and d1 */ + z1 = TransEval( o1, o2, d1 ); + z2 = TransEval( o2, d1, d2 ); + if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; } + v->t = Interpolate( z1, o2->t, z2, d1->t ); + } else { + /* Interpolate between o2 and d2 */ + z1 = TransSign( o1, o2, d1 ); + z2 = -TransSign( o1, d2, d1 ); + if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; } + v->t = Interpolate( z1, o2->t, z2, d2->t ); + } +} diff --git a/common/libtess/geom.h b/common/libtess/geom.h new file mode 100755 index 0000000..c87b4f0 --- /dev/null +++ b/common/libtess/geom.h @@ -0,0 +1,84 @@ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * 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 including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * 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 + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ +/* +** Author: Eric Veach, July 1994. +** +*/ + +#ifndef __geom_h_ +#define __geom_h_ + +#include "mesh.h" + +#ifdef NO_BRANCH_CONDITIONS +/* MIPS architecture has special instructions to evaluate boolean + * conditions -- more efficient than branching, IF you can get the + * compiler to generate the right instructions (SGI compiler doesn't) + */ +#define VertEq(u,v) (((u)->s == (v)->s) & ((u)->t == (v)->t)) +#define VertLeq(u,v) (((u)->s < (v)->s) | \ + ((u)->s == (v)->s & (u)->t <= (v)->t)) +#else +#define VertEq(u,v) ((u)->s == (v)->s && (u)->t == (v)->t) +#define VertLeq(u,v) (((u)->s < (v)->s) || \ + ((u)->s == (v)->s && (u)->t <= (v)->t)) +#endif + +#define EdgeEval(u,v,w) __gl_edgeEval(u,v,w) +#define EdgeSign(u,v,w) __gl_edgeSign(u,v,w) + +/* Versions of VertLeq, EdgeSign, EdgeEval with s and t transposed. */ + +#define TransLeq(u,v) (((u)->t < (v)->t) || \ + ((u)->t == (v)->t && (u)->s <= (v)->s)) +#define TransEval(u,v,w) __gl_transEval(u,v,w) +#define TransSign(u,v,w) __gl_transSign(u,v,w) + + +#define EdgeGoesLeft(e) VertLeq( (e)->Dst, (e)->Org ) +#define EdgeGoesRight(e) VertLeq( (e)->Org, (e)->Dst ) + +#undef ABS +#define ABS(x) ((x) < 0 ? -(x) : (x)) +#define VertL1dist(u,v) (ABS(u->s - v->s) + ABS(u->t - v->t)) + +#define VertCCW(u,v,w) __gl_vertCCW(u,v,w) + +int __gl_vertLeq( GLUvertex *u, GLUvertex *v ); +double __gl_edgeEval( GLUvertex *u, GLUvertex *v, GLUvertex *w ); +double __gl_edgeSign( GLUvertex *u, GLUvertex *v, GLUvertex *w ); +double __gl_transEval( GLUvertex *u, GLUvertex *v, GLUvertex *w ); +double __gl_transSign( GLUvertex *u, GLUvertex *v, GLUvertex *w ); +int __gl_vertCCW( GLUvertex *u, GLUvertex *v, GLUvertex *w ); +void __gl_edgeIntersect( GLUvertex *o1, GLUvertex *d1, + GLUvertex *o2, GLUvertex *d2, + GLUvertex *v ); + +#endif diff --git a/common/libtess/memalloc.c b/common/libtess/memalloc.c new file mode 100755 index 0000000..81879ef --- /dev/null +++ b/common/libtess/memalloc.c @@ -0,0 +1,55 @@ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * 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 including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * 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 + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ +/* +** Author: Eric Veach, July 1994. +** +*/ + +#include "memalloc.h" +#include "string.h" + +int __gl_memInit( size_t maxFast ) +{ +#ifndef NO_MALLOPT +/* mallopt( M_MXFAST, maxFast );*/ +#ifdef MEMORY_DEBUG + mallopt( M_DEBUG, 1 ); +#endif +#endif + return 1; +} + +#ifdef MEMORY_DEBUG +void *__gl_memAlloc( size_t n ) +{ + return memset( malloc( n ), 0xa5, n ); +} +#endif + diff --git a/common/libtess/memalloc.h b/common/libtess/memalloc.h new file mode 100755 index 0000000..c2f969b --- /dev/null +++ b/common/libtess/memalloc.h @@ -0,0 +1,54 @@ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * 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 including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * 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 + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ +/* +** Author: Eric Veach, July 1994. +** +*/ + +#ifndef __memalloc_simple_h_ +#define __memalloc_simple_h_ + +#include + +#define memRealloc realloc +#define memFree free + +#define memInit __gl_memInit +/*extern void __gl_memInit( size_t );*/ +extern int __gl_memInit( size_t ); + +#ifndef MEMORY_DEBUG +#define memAlloc malloc +#else +#define memAlloc __gl_memAlloc +extern void * __gl_memAlloc( size_t ); +#endif + +#endif diff --git a/common/libtess/mesh.c b/common/libtess/mesh.c new file mode 100755 index 0000000..497c3d4 --- /dev/null +++ b/common/libtess/mesh.c @@ -0,0 +1,790 @@ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * 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 including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * 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 + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ +/* +** Author: Eric Veach, July 1994. +** +*/ + +#include "../prboom/SDL_opengl.h" // JDC +//#include "gluos.h" +#include +#include +#include "mesh.h" +#include "memalloc.h" + +#define TRUE 1 +#define FALSE 0 + +static GLUvertex *allocVertex() +{ + return (GLUvertex *)memAlloc( sizeof( GLUvertex )); +} + +static GLUface *allocFace() +{ + return (GLUface *)memAlloc( sizeof( GLUface )); +} + +/************************ Utility Routines ************************/ + +/* Allocate and free half-edges in pairs for efficiency. + * The *only* place that should use this fact is allocation/free. + */ +typedef struct { GLUhalfEdge e, eSym; } EdgePair; + +/* MakeEdge creates a new pair of half-edges which form their own loop. + * No vertex or face structures are allocated, but these must be assigned + * before the current edge operation is completed. + */ +static GLUhalfEdge *MakeEdge( GLUhalfEdge *eNext ) +{ + GLUhalfEdge *e; + GLUhalfEdge *eSym; + GLUhalfEdge *ePrev; + EdgePair *pair = (EdgePair *)memAlloc( sizeof( EdgePair )); + if (pair == NULL) return NULL; + + e = &pair->e; + eSym = &pair->eSym; + + /* Make sure eNext points to the first edge of the edge pair */ + if( eNext->Sym < eNext ) { eNext = eNext->Sym; } + + /* Insert in circular doubly-linked list before eNext. + * Note that the prev pointer is stored in Sym->next. + */ + ePrev = eNext->Sym->next; + eSym->next = ePrev; + ePrev->Sym->next = e; + e->next = eNext; + eNext->Sym->next = eSym; + + e->Sym = eSym; + e->Onext = e; + e->Lnext = eSym; + e->Org = NULL; + e->Lface = NULL; + e->winding = 0; + e->activeRegion = NULL; + + eSym->Sym = e; + eSym->Onext = eSym; + eSym->Lnext = e; + eSym->Org = NULL; + eSym->Lface = NULL; + eSym->winding = 0; + eSym->activeRegion = NULL; + + return e; +} + +/* Splice( a, b ) is best described by the Guibas/Stolfi paper or the + * CS348a notes (see mesh.h). Basically it modifies the mesh so that + * a->Onext and b->Onext are exchanged. This can have various effects + * depending on whether a and b belong to different face or vertex rings. + * For more explanation see __gl_meshSplice() below. + */ +static void Splice( GLUhalfEdge *a, GLUhalfEdge *b ) +{ + GLUhalfEdge *aOnext = a->Onext; + GLUhalfEdge *bOnext = b->Onext; + + aOnext->Sym->Lnext = b; + bOnext->Sym->Lnext = a; + a->Onext = bOnext; + b->Onext = aOnext; +} + +/* MakeVertex( newVertex, eOrig, vNext ) attaches a new vertex and makes it the + * origin of all edges in the vertex loop to which eOrig belongs. "vNext" gives + * a place to insert the new vertex in the global vertex list. We insert + * the new vertex *before* vNext so that algorithms which walk the vertex + * list will not see the newly created vertices. + */ +static void MakeVertex( GLUvertex *newVertex, + GLUhalfEdge *eOrig, GLUvertex *vNext ) +{ + GLUhalfEdge *e; + GLUvertex *vPrev; + GLUvertex *vNew = newVertex; + + assert(vNew != NULL); + + /* insert in circular doubly-linked list before vNext */ + vPrev = vNext->prev; + vNew->prev = vPrev; + vPrev->next = vNew; + vNew->next = vNext; + vNext->prev = vNew; + + vNew->anEdge = eOrig; + vNew->data = NULL; + /* leave coords, s, t undefined */ + + /* fix other edges on this vertex loop */ + e = eOrig; + do { + e->Org = vNew; + e = e->Onext; + } while( e != eOrig ); +} + +/* MakeFace( newFace, eOrig, fNext ) attaches a new face and makes it the left + * face of all edges in the face loop to which eOrig belongs. "fNext" gives + * a place to insert the new face in the global face list. We insert + * the new face *before* fNext so that algorithms which walk the face + * list will not see the newly created faces. + */ +static void MakeFace( GLUface *newFace, GLUhalfEdge *eOrig, GLUface *fNext ) +{ + GLUhalfEdge *e; + GLUface *fPrev; + GLUface *fNew = newFace; + + assert(fNew != NULL); + + /* insert in circular doubly-linked list before fNext */ + fPrev = fNext->prev; + fNew->prev = fPrev; + fPrev->next = fNew; + fNew->next = fNext; + fNext->prev = fNew; + + fNew->anEdge = eOrig; + fNew->data = NULL; + fNew->trail = NULL; + fNew->marked = FALSE; + + /* The new face is marked "inside" if the old one was. This is a + * convenience for the common case where a face has been split in two. + */ + fNew->inside = fNext->inside; + + /* fix other edges on this face loop */ + e = eOrig; + do { + e->Lface = fNew; + e = e->Lnext; + } while( e != eOrig ); +} + +/* KillEdge( eDel ) destroys an edge (the half-edges eDel and eDel->Sym), + * and removes from the global edge list. + */ +static void KillEdge( GLUhalfEdge *eDel ) +{ + GLUhalfEdge *ePrev, *eNext; + + /* Half-edges are allocated in pairs, see EdgePair above */ + if( eDel->Sym < eDel ) { eDel = eDel->Sym; } + + /* delete from circular doubly-linked list */ + eNext = eDel->next; + ePrev = eDel->Sym->next; + eNext->Sym->next = ePrev; + ePrev->Sym->next = eNext; + + memFree( eDel ); +} + + +/* KillVertex( vDel ) destroys a vertex and removes it from the global + * vertex list. It updates the vertex loop to point to a given new vertex. + */ +static void KillVertex( GLUvertex *vDel, GLUvertex *newOrg ) +{ + GLUhalfEdge *e, *eStart = vDel->anEdge; + GLUvertex *vPrev, *vNext; + + /* change the origin of all affected edges */ + e = eStart; + do { + e->Org = newOrg; + e = e->Onext; + } while( e != eStart ); + + /* delete from circular doubly-linked list */ + vPrev = vDel->prev; + vNext = vDel->next; + vNext->prev = vPrev; + vPrev->next = vNext; + + memFree( vDel ); +} + +/* KillFace( fDel ) destroys a face and removes it from the global face + * list. It updates the face loop to point to a given new face. + */ +static void KillFace( GLUface *fDel, GLUface *newLface ) +{ + GLUhalfEdge *e, *eStart = fDel->anEdge; + GLUface *fPrev, *fNext; + + /* change the left face of all affected edges */ + e = eStart; + do { + e->Lface = newLface; + e = e->Lnext; + } while( e != eStart ); + + /* delete from circular doubly-linked list */ + fPrev = fDel->prev; + fNext = fDel->next; + fNext->prev = fPrev; + fPrev->next = fNext; + + memFree( fDel ); +} + + +/****************** Basic Edge Operations **********************/ + +/* __gl_meshMakeEdge creates one edge, two vertices, and a loop (face). + * The loop consists of the two new half-edges. + */ +GLUhalfEdge *__gl_meshMakeEdge( GLUmesh *mesh ) +{ + GLUvertex *newVertex1= allocVertex(); + GLUvertex *newVertex2= allocVertex(); + GLUface *newFace= allocFace(); + GLUhalfEdge *e; + + /* if any one is null then all get freed */ + if (newVertex1 == NULL || newVertex2 == NULL || newFace == NULL) { + if (newVertex1 != NULL) memFree(newVertex1); + if (newVertex2 != NULL) memFree(newVertex2); + if (newFace != NULL) memFree(newFace); + return NULL; + } + + e = MakeEdge( &mesh->eHead ); + if (e == NULL) return NULL; + + MakeVertex( newVertex1, e, &mesh->vHead ); + MakeVertex( newVertex2, e->Sym, &mesh->vHead ); + MakeFace( newFace, e, &mesh->fHead ); + return e; +} + + +/* __gl_meshSplice( eOrg, eDst ) is the basic operation for changing the + * mesh connectivity and topology. It changes the mesh so that + * eOrg->Onext <- OLD( eDst->Onext ) + * eDst->Onext <- OLD( eOrg->Onext ) + * where OLD(...) means the value before the meshSplice operation. + * + * This can have two effects on the vertex structure: + * - if eOrg->Org != eDst->Org, the two vertices are merged together + * - if eOrg->Org == eDst->Org, the origin is split into two vertices + * In both cases, eDst->Org is changed and eOrg->Org is untouched. + * + * Similarly (and independently) for the face structure, + * - if eOrg->Lface == eDst->Lface, one loop is split into two + * - if eOrg->Lface != eDst->Lface, two distinct loops are joined into one + * In both cases, eDst->Lface is changed and eOrg->Lface is unaffected. + * + * Some special cases: + * If eDst == eOrg, the operation has no effect. + * If eDst == eOrg->Lnext, the new face will have a single edge. + * If eDst == eOrg->Lprev, the old face will have a single edge. + * If eDst == eOrg->Onext, the new vertex will have a single edge. + * If eDst == eOrg->Oprev, the old vertex will have a single edge. + */ +int __gl_meshSplice( GLUhalfEdge *eOrg, GLUhalfEdge *eDst ) +{ + int joiningLoops = FALSE; + int joiningVertices = FALSE; + + if( eOrg == eDst ) return 1; + + if( eDst->Org != eOrg->Org ) { + /* We are merging two disjoint vertices -- destroy eDst->Org */ + joiningVertices = TRUE; + KillVertex( eDst->Org, eOrg->Org ); + } + if( eDst->Lface != eOrg->Lface ) { + /* We are connecting two disjoint loops -- destroy eDst->Lface */ + joiningLoops = TRUE; + KillFace( eDst->Lface, eOrg->Lface ); + } + + /* Change the edge structure */ + Splice( eDst, eOrg ); + + if( ! joiningVertices ) { + GLUvertex *newVertex= allocVertex(); + if (newVertex == NULL) return 0; + + /* We split one vertex into two -- the new vertex is eDst->Org. + * Make sure the old vertex points to a valid half-edge. + */ + MakeVertex( newVertex, eDst, eOrg->Org ); + eOrg->Org->anEdge = eOrg; + } + if( ! joiningLoops ) { + GLUface *newFace= allocFace(); + if (newFace == NULL) return 0; + + /* We split one loop into two -- the new loop is eDst->Lface. + * Make sure the old face points to a valid half-edge. + */ + MakeFace( newFace, eDst, eOrg->Lface ); + eOrg->Lface->anEdge = eOrg; + } + + return 1; +} + + +/* __gl_meshDelete( eDel ) removes the edge eDel. There are several cases: + * if (eDel->Lface != eDel->Rface), we join two loops into one; the loop + * eDel->Lface is deleted. Otherwise, we are splitting one loop into two; + * the newly created loop will contain eDel->Dst. If the deletion of eDel + * would create isolated vertices, those are deleted as well. + * + * This function could be implemented as two calls to __gl_meshSplice + * plus a few calls to memFree, but this would allocate and delete + * unnecessary vertices and faces. + */ +int __gl_meshDelete( GLUhalfEdge *eDel ) +{ + GLUhalfEdge *eDelSym = eDel->Sym; + int joiningLoops = FALSE; + + /* First step: disconnect the origin vertex eDel->Org. We make all + * changes to get a consistent mesh in this "intermediate" state. + */ + if( eDel->Lface != eDel->Rface ) { + /* We are joining two loops into one -- remove the left face */ + joiningLoops = TRUE; + KillFace( eDel->Lface, eDel->Rface ); + } + + if( eDel->Onext == eDel ) { + KillVertex( eDel->Org, NULL ); + } else { + /* Make sure that eDel->Org and eDel->Rface point to valid half-edges */ + eDel->Rface->anEdge = eDel->Oprev; + eDel->Org->anEdge = eDel->Onext; + + Splice( eDel, eDel->Oprev ); + if( ! joiningLoops ) { + GLUface *newFace= allocFace(); + if (newFace == NULL) return 0; + + /* We are splitting one loop into two -- create a new loop for eDel. */ + MakeFace( newFace, eDel, eDel->Lface ); + } + } + + /* Claim: the mesh is now in a consistent state, except that eDel->Org + * may have been deleted. Now we disconnect eDel->Dst. + */ + if( eDelSym->Onext == eDelSym ) { + KillVertex( eDelSym->Org, NULL ); + KillFace( eDelSym->Lface, NULL ); + } else { + /* Make sure that eDel->Dst and eDel->Lface point to valid half-edges */ + eDel->Lface->anEdge = eDelSym->Oprev; + eDelSym->Org->anEdge = eDelSym->Onext; + Splice( eDelSym, eDelSym->Oprev ); + } + + /* Any isolated vertices or faces have already been freed. */ + KillEdge( eDel ); + + return 1; +} + + +/******************** Other Edge Operations **********************/ + +/* All these routines can be implemented with the basic edge + * operations above. They are provided for convenience and efficiency. + */ + + +/* __gl_meshAddEdgeVertex( eOrg ) creates a new edge eNew such that + * eNew == eOrg->Lnext, and eNew->Dst is a newly created vertex. + * eOrg and eNew will have the same left face. + */ +GLUhalfEdge *__gl_meshAddEdgeVertex( GLUhalfEdge *eOrg ) +{ + GLUhalfEdge *eNewSym; + GLUhalfEdge *eNew = MakeEdge( eOrg ); + if (eNew == NULL) return NULL; + + eNewSym = eNew->Sym; + + /* Connect the new edge appropriately */ + Splice( eNew, eOrg->Lnext ); + + /* Set the vertex and face information */ + eNew->Org = eOrg->Dst; + { + GLUvertex *newVertex= allocVertex(); + if (newVertex == NULL) return NULL; + + MakeVertex( newVertex, eNewSym, eNew->Org ); + } + eNew->Lface = eNewSym->Lface = eOrg->Lface; + + return eNew; +} + + +/* __gl_meshSplitEdge( eOrg ) splits eOrg into two edges eOrg and eNew, + * such that eNew == eOrg->Lnext. The new vertex is eOrg->Dst == eNew->Org. + * eOrg and eNew will have the same left face. + */ +GLUhalfEdge *__gl_meshSplitEdge( GLUhalfEdge *eOrg ) +{ + GLUhalfEdge *eNew; + GLUhalfEdge *tempHalfEdge= __gl_meshAddEdgeVertex( eOrg ); + if (tempHalfEdge == NULL) return NULL; + + eNew = tempHalfEdge->Sym; + + /* Disconnect eOrg from eOrg->Dst and connect it to eNew->Org */ + Splice( eOrg->Sym, eOrg->Sym->Oprev ); + Splice( eOrg->Sym, eNew ); + + /* Set the vertex and face information */ + eOrg->Dst = eNew->Org; + eNew->Dst->anEdge = eNew->Sym; /* may have pointed to eOrg->Sym */ + eNew->Rface = eOrg->Rface; + eNew->winding = eOrg->winding; /* copy old winding information */ + eNew->Sym->winding = eOrg->Sym->winding; + + return eNew; +} + + +/* __gl_meshConnect( eOrg, eDst ) creates a new edge from eOrg->Dst + * to eDst->Org, and returns the corresponding half-edge eNew. + * If eOrg->Lface == eDst->Lface, this splits one loop into two, + * and the newly created loop is eNew->Lface. Otherwise, two disjoint + * loops are merged into one, and the loop eDst->Lface is destroyed. + * + * If (eOrg == eDst), the new face will have only two edges. + * If (eOrg->Lnext == eDst), the old face is reduced to a single edge. + * If (eOrg->Lnext->Lnext == eDst), the old face is reduced to two edges. + */ +GLUhalfEdge *__gl_meshConnect( GLUhalfEdge *eOrg, GLUhalfEdge *eDst ) +{ + GLUhalfEdge *eNewSym; + int joiningLoops = FALSE; + GLUhalfEdge *eNew = MakeEdge( eOrg ); + if (eNew == NULL) return NULL; + + eNewSym = eNew->Sym; + + if( eDst->Lface != eOrg->Lface ) { + /* We are connecting two disjoint loops -- destroy eDst->Lface */ + joiningLoops = TRUE; + KillFace( eDst->Lface, eOrg->Lface ); + } + + /* Connect the new edge appropriately */ + Splice( eNew, eOrg->Lnext ); + Splice( eNewSym, eDst ); + + /* Set the vertex and face information */ + eNew->Org = eOrg->Dst; + eNewSym->Org = eDst->Org; + eNew->Lface = eNewSym->Lface = eOrg->Lface; + + /* Make sure the old face points to a valid half-edge */ + eOrg->Lface->anEdge = eNewSym; + + if( ! joiningLoops ) { + GLUface *newFace= allocFace(); + if (newFace == NULL) return NULL; + + /* We split one loop into two -- the new loop is eNew->Lface */ + MakeFace( newFace, eNew, eOrg->Lface ); + } + return eNew; +} + + +/******************** Other Operations **********************/ + +/* __gl_meshZapFace( fZap ) destroys a face and removes it from the + * global face list. All edges of fZap will have a NULL pointer as their + * left face. Any edges which also have a NULL pointer as their right face + * are deleted entirely (along with any isolated vertices this produces). + * An entire mesh can be deleted by zapping its faces, one at a time, + * in any order. Zapped faces cannot be used in further mesh operations! + */ +void __gl_meshZapFace( GLUface *fZap ) +{ + GLUhalfEdge *eStart = fZap->anEdge; + GLUhalfEdge *e, *eNext, *eSym; + GLUface *fPrev, *fNext; + + /* walk around face, deleting edges whose right face is also NULL */ + eNext = eStart->Lnext; + do { + e = eNext; + eNext = e->Lnext; + + e->Lface = NULL; + if( e->Rface == NULL ) { + /* delete the edge -- see __gl_MeshDelete above */ + + if( e->Onext == e ) { + KillVertex( e->Org, NULL ); + } else { + /* Make sure that e->Org points to a valid half-edge */ + e->Org->anEdge = e->Onext; + Splice( e, e->Oprev ); + } + eSym = e->Sym; + if( eSym->Onext == eSym ) { + KillVertex( eSym->Org, NULL ); + } else { + /* Make sure that eSym->Org points to a valid half-edge */ + eSym->Org->anEdge = eSym->Onext; + Splice( eSym, eSym->Oprev ); + } + KillEdge( e ); + } + } while( e != eStart ); + + /* delete from circular doubly-linked list */ + fPrev = fZap->prev; + fNext = fZap->next; + fNext->prev = fPrev; + fPrev->next = fNext; + + memFree( fZap ); +} + + +/* __gl_meshNewMesh() creates a new mesh with no edges, no vertices, + * and no loops (what we usually call a "face"). + */ +GLUmesh *__gl_meshNewMesh( void ) +{ + GLUvertex *v; + GLUface *f; + GLUhalfEdge *e; + GLUhalfEdge *eSym; + GLUmesh *mesh = (GLUmesh *)memAlloc( sizeof( GLUmesh )); + if (mesh == NULL) { + return NULL; + } + + v = &mesh->vHead; + f = &mesh->fHead; + e = &mesh->eHead; + eSym = &mesh->eHeadSym; + + v->next = v->prev = v; + v->anEdge = NULL; + v->data = NULL; + + f->next = f->prev = f; + f->anEdge = NULL; + f->data = NULL; + f->trail = NULL; + f->marked = FALSE; + f->inside = FALSE; + + e->next = e; + e->Sym = eSym; + e->Onext = NULL; + e->Lnext = NULL; + e->Org = NULL; + e->Lface = NULL; + e->winding = 0; + e->activeRegion = NULL; + + eSym->next = eSym; + eSym->Sym = e; + eSym->Onext = NULL; + eSym->Lnext = NULL; + eSym->Org = NULL; + eSym->Lface = NULL; + eSym->winding = 0; + eSym->activeRegion = NULL; + + return mesh; +} + + +/* __gl_meshUnion( mesh1, mesh2 ) forms the union of all structures in + * both meshes, and returns the new mesh (the old meshes are destroyed). + */ +GLUmesh *__gl_meshUnion( GLUmesh *mesh1, GLUmesh *mesh2 ) +{ + GLUface *f1 = &mesh1->fHead; + GLUvertex *v1 = &mesh1->vHead; + GLUhalfEdge *e1 = &mesh1->eHead; + GLUface *f2 = &mesh2->fHead; + GLUvertex *v2 = &mesh2->vHead; + GLUhalfEdge *e2 = &mesh2->eHead; + + /* Add the faces, vertices, and edges of mesh2 to those of mesh1 */ + if( f2->next != f2 ) { + f1->prev->next = f2->next; + f2->next->prev = f1->prev; + f2->prev->next = f1; + f1->prev = f2->prev; + } + + if( v2->next != v2 ) { + v1->prev->next = v2->next; + v2->next->prev = v1->prev; + v2->prev->next = v1; + v1->prev = v2->prev; + } + + if( e2->next != e2 ) { + e1->Sym->next->Sym->next = e2->next; + e2->next->Sym->next = e1->Sym->next; + e2->Sym->next->Sym->next = e1; + e1->Sym->next = e2->Sym->next; + } + + memFree( mesh2 ); + return mesh1; +} + + +#ifdef DELETE_BY_ZAPPING + +/* __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh. + */ +void __gl_meshDeleteMesh( GLUmesh *mesh ) +{ + GLUface *fHead = &mesh->fHead; + + while( fHead->next != fHead ) { + __gl_meshZapFace( fHead->next ); + } + assert( mesh->vHead.next == &mesh->vHead ); + + memFree( mesh ); +} + +#else + +/* __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh. + */ +void __gl_meshDeleteMesh( GLUmesh *mesh ) +{ + GLUface *f, *fNext; + GLUvertex *v, *vNext; + GLUhalfEdge *e, *eNext; + + for( f = mesh->fHead.next; f != &mesh->fHead; f = fNext ) { + fNext = f->next; + memFree( f ); + } + + for( v = mesh->vHead.next; v != &mesh->vHead; v = vNext ) { + vNext = v->next; + memFree( v ); + } + + for( e = mesh->eHead.next; e != &mesh->eHead; e = eNext ) { + /* One call frees both e and e->Sym (see EdgePair above) */ + eNext = e->next; + memFree( e ); + } + + memFree( mesh ); +} + +#endif + +#ifndef NDEBUG + +/* __gl_meshCheckMesh( mesh ) checks a mesh for self-consistency. + */ +void __gl_meshCheckMesh( GLUmesh *mesh ) +{ + GLUface *fHead = &mesh->fHead; + GLUvertex *vHead = &mesh->vHead; + GLUhalfEdge *eHead = &mesh->eHead; + GLUface *f, *fPrev; + GLUvertex *v, *vPrev; + GLUhalfEdge *e, *ePrev; + + fPrev = fHead; + for( fPrev = fHead ; (f = fPrev->next) != fHead; fPrev = f) { + assert( f->prev == fPrev ); + e = f->anEdge; + do { + assert( e->Sym != e ); + assert( e->Sym->Sym == e ); + assert( e->Lnext->Onext->Sym == e ); + assert( e->Onext->Sym->Lnext == e ); + assert( e->Lface == f ); + e = e->Lnext; + } while( e != f->anEdge ); + } + assert( f->prev == fPrev && f->anEdge == NULL && f->data == NULL ); + + vPrev = vHead; + for( vPrev = vHead ; (v = vPrev->next) != vHead; vPrev = v) { + assert( v->prev == vPrev ); + e = v->anEdge; + do { + assert( e->Sym != e ); + assert( e->Sym->Sym == e ); + assert( e->Lnext->Onext->Sym == e ); + assert( e->Onext->Sym->Lnext == e ); + assert( e->Org == v ); + e = e->Onext; + } while( e != v->anEdge ); + } + assert( v->prev == vPrev && v->anEdge == NULL && v->data == NULL ); + + ePrev = eHead; + for( ePrev = eHead ; (e = ePrev->next) != eHead; ePrev = e) { + assert( e->Sym->next == ePrev->Sym ); + assert( e->Sym != e ); + assert( e->Sym->Sym == e ); + assert( e->Org != NULL ); + assert( e->Dst != NULL ); + assert( e->Lnext->Onext->Sym == e ); + assert( e->Onext->Sym->Lnext == e ); + } + assert( e->Sym->next == ePrev->Sym + && e->Sym == &mesh->eHeadSym + && e->Sym->Sym == e + && e->Org == NULL && e->Dst == NULL + && e->Lface == NULL && e->Rface == NULL ); +} + +#endif diff --git a/common/libtess/mesh.h b/common/libtess/mesh.h new file mode 100755 index 0000000..a24e76a --- /dev/null +++ b/common/libtess/mesh.h @@ -0,0 +1,266 @@ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * 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 including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * 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 + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ +/* +** Author: Eric Veach, July 1994. +** +*/ + +#ifndef __mesh_h_ +#define __mesh_h_ + +#include + +typedef struct GLUmesh GLUmesh; + +typedef struct GLUvertex GLUvertex; +typedef struct GLUface GLUface; +typedef struct GLUhalfEdge GLUhalfEdge; + +typedef struct ActiveRegion ActiveRegion; /* Internal data */ + +/* The mesh structure is similar in spirit, notation, and operations + * to the "quad-edge" structure (see L. Guibas and J. Stolfi, Primitives + * for the manipulation of general subdivisions and the computation of + * Voronoi diagrams, ACM Transactions on Graphics, 4(2):74-123, April 1985). + * For a simplified description, see the course notes for CS348a, + * "Mathematical Foundations of Computer Graphics", available at the + * Stanford bookstore (and taught during the fall quarter). + * The implementation also borrows a tiny subset of the graph-based approach + * use in Mantyla's Geometric Work Bench (see M. Mantyla, An Introduction + * to Sold Modeling, Computer Science Press, Rockville, Maryland, 1988). + * + * The fundamental data structure is the "half-edge". Two half-edges + * go together to make an edge, but they point in opposite directions. + * Each half-edge has a pointer to its mate (the "symmetric" half-edge Sym), + * its origin vertex (Org), the face on its left side (Lface), and the + * adjacent half-edges in the CCW direction around the origin vertex + * (Onext) and around the left face (Lnext). There is also a "next" + * pointer for the global edge list (see below). + * + * The notation used for mesh navigation: + * Sym = the mate of a half-edge (same edge, but opposite direction) + * Onext = edge CCW around origin vertex (keep same origin) + * Dnext = edge CCW around destination vertex (keep same dest) + * Lnext = edge CCW around left face (dest becomes new origin) + * Rnext = edge CCW around right face (origin becomes new dest) + * + * "prev" means to substitute CW for CCW in the definitions above. + * + * The mesh keeps global lists of all vertices, faces, and edges, + * stored as doubly-linked circular lists with a dummy header node. + * The mesh stores pointers to these dummy headers (vHead, fHead, eHead). + * + * The circular edge list is special; since half-edges always occur + * in pairs (e and e->Sym), each half-edge stores a pointer in only + * one direction. Starting at eHead and following the e->next pointers + * will visit each *edge* once (ie. e or e->Sym, but not both). + * e->Sym stores a pointer in the opposite direction, thus it is + * always true that e->Sym->next->Sym->next == e. + * + * Each vertex has a pointer to next and previous vertices in the + * circular list, and a pointer to a half-edge with this vertex as + * the origin (NULL if this is the dummy header). There is also a + * field "data" for client data. + * + * Each face has a pointer to the next and previous faces in the + * circular list, and a pointer to a half-edge with this face as + * the left face (NULL if this is the dummy header). There is also + * a field "data" for client data. + * + * Note that what we call a "face" is really a loop; faces may consist + * of more than one loop (ie. not simply connected), but there is no + * record of this in the data structure. The mesh may consist of + * several disconnected regions, so it may not be possible to visit + * the entire mesh by starting at a half-edge and traversing the edge + * structure. + * + * The mesh does NOT support isolated vertices; a vertex is deleted along + * with its last edge. Similarly when two faces are merged, one of the + * faces is deleted (see __gl_meshDelete below). For mesh operations, + * all face (loop) and vertex pointers must not be NULL. However, once + * mesh manipulation is finished, __gl_MeshZapFace can be used to delete + * faces of the mesh, one at a time. All external faces can be "zapped" + * before the mesh is returned to the client; then a NULL face indicates + * a region which is not part of the output polygon. + */ + +struct GLUvertex { + GLUvertex *next; /* next vertex (never NULL) */ + GLUvertex *prev; /* previous vertex (never NULL) */ + GLUhalfEdge *anEdge; /* a half-edge with this origin */ + void *data; /* client's data */ + + /* Internal data (keep hidden) */ + double coords[3]; /* vertex location in 3D */ + double s, t; /* projection onto the sweep plane */ + long pqHandle; /* to allow deletion from priority queue */ +}; + +struct GLUface { + GLUface *next; /* next face (never NULL) */ + GLUface *prev; /* previous face (never NULL) */ + GLUhalfEdge *anEdge; /* a half edge with this left face */ + void *data; /* room for client's data */ + + /* Internal data (keep hidden) */ + GLUface *trail; /* "stack" for conversion to strips */ + GLboolean marked; /* flag for conversion to strips */ + GLboolean inside; /* this face is in the polygon interior */ +}; + +struct GLUhalfEdge { + GLUhalfEdge *next; /* doubly-linked list (prev==Sym->next) */ + GLUhalfEdge *Sym; /* same edge, opposite direction */ + GLUhalfEdge *Onext; /* next edge CCW around origin */ + GLUhalfEdge *Lnext; /* next edge CCW around left face */ + GLUvertex *Org; /* origin vertex (Overtex too long) */ + GLUface *Lface; /* left face */ + + /* Internal data (keep hidden) */ + ActiveRegion *activeRegion; /* a region with this upper edge (sweep.c) */ + int winding; /* change in winding number when crossing + from the right face to the left face */ +}; + +#define Rface Sym->Lface +#define Dst Sym->Org + +#define Oprev Sym->Lnext +#define Lprev Onext->Sym +#define Dprev Lnext->Sym +#define Rprev Sym->Onext +#define Dnext Rprev->Sym /* 3 pointers */ +#define Rnext Oprev->Sym /* 3 pointers */ + + +struct GLUmesh { + GLUvertex vHead; /* dummy header for vertex list */ + GLUface fHead; /* dummy header for face list */ + GLUhalfEdge eHead; /* dummy header for edge list */ + GLUhalfEdge eHeadSym; /* and its symmetric counterpart */ +}; + +/* The mesh operations below have three motivations: completeness, + * convenience, and efficiency. The basic mesh operations are MakeEdge, + * Splice, and Delete. All the other edge operations can be implemented + * in terms of these. The other operations are provided for convenience + * and/or efficiency. + * + * When a face is split or a vertex is added, they are inserted into the + * global list *before* the existing vertex or face (ie. e->Org or e->Lface). + * This makes it easier to process all vertices or faces in the global lists + * without worrying about processing the same data twice. As a convenience, + * when a face is split, the "inside" flag is copied from the old face. + * Other internal data (v->data, v->activeRegion, f->data, f->marked, + * f->trail, e->winding) is set to zero. + * + * ********************** Basic Edge Operations ************************** + * + * __gl_meshMakeEdge( mesh ) creates one edge, two vertices, and a loop. + * The loop (face) consists of the two new half-edges. + * + * __gl_meshSplice( eOrg, eDst ) is the basic operation for changing the + * mesh connectivity and topology. It changes the mesh so that + * eOrg->Onext <- OLD( eDst->Onext ) + * eDst->Onext <- OLD( eOrg->Onext ) + * where OLD(...) means the value before the meshSplice operation. + * + * This can have two effects on the vertex structure: + * - if eOrg->Org != eDst->Org, the two vertices are merged together + * - if eOrg->Org == eDst->Org, the origin is split into two vertices + * In both cases, eDst->Org is changed and eOrg->Org is untouched. + * + * Similarly (and independently) for the face structure, + * - if eOrg->Lface == eDst->Lface, one loop is split into two + * - if eOrg->Lface != eDst->Lface, two distinct loops are joined into one + * In both cases, eDst->Lface is changed and eOrg->Lface is unaffected. + * + * __gl_meshDelete( eDel ) removes the edge eDel. There are several cases: + * if (eDel->Lface != eDel->Rface), we join two loops into one; the loop + * eDel->Lface is deleted. Otherwise, we are splitting one loop into two; + * the newly created loop will contain eDel->Dst. If the deletion of eDel + * would create isolated vertices, those are deleted as well. + * + * ********************** Other Edge Operations ************************** + * + * __gl_meshAddEdgeVertex( eOrg ) creates a new edge eNew such that + * eNew == eOrg->Lnext, and eNew->Dst is a newly created vertex. + * eOrg and eNew will have the same left face. + * + * __gl_meshSplitEdge( eOrg ) splits eOrg into two edges eOrg and eNew, + * such that eNew == eOrg->Lnext. The new vertex is eOrg->Dst == eNew->Org. + * eOrg and eNew will have the same left face. + * + * __gl_meshConnect( eOrg, eDst ) creates a new edge from eOrg->Dst + * to eDst->Org, and returns the corresponding half-edge eNew. + * If eOrg->Lface == eDst->Lface, this splits one loop into two, + * and the newly created loop is eNew->Lface. Otherwise, two disjoint + * loops are merged into one, and the loop eDst->Lface is destroyed. + * + * ************************ Other Operations ***************************** + * + * __gl_meshNewMesh() creates a new mesh with no edges, no vertices, + * and no loops (what we usually call a "face"). + * + * __gl_meshUnion( mesh1, mesh2 ) forms the union of all structures in + * both meshes, and returns the new mesh (the old meshes are destroyed). + * + * __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh. + * + * __gl_meshZapFace( fZap ) destroys a face and removes it from the + * global face list. All edges of fZap will have a NULL pointer as their + * left face. Any edges which also have a NULL pointer as their right face + * are deleted entirely (along with any isolated vertices this produces). + * An entire mesh can be deleted by zapping its faces, one at a time, + * in any order. Zapped faces cannot be used in further mesh operations! + * + * __gl_meshCheckMesh( mesh ) checks a mesh for self-consistency. + */ + +GLUhalfEdge *__gl_meshMakeEdge( GLUmesh *mesh ); +int __gl_meshSplice( GLUhalfEdge *eOrg, GLUhalfEdge *eDst ); +int __gl_meshDelete( GLUhalfEdge *eDel ); + +GLUhalfEdge *__gl_meshAddEdgeVertex( GLUhalfEdge *eOrg ); +GLUhalfEdge *__gl_meshSplitEdge( GLUhalfEdge *eOrg ); +GLUhalfEdge *__gl_meshConnect( GLUhalfEdge *eOrg, GLUhalfEdge *eDst ); + +GLUmesh *__gl_meshNewMesh( void ); +GLUmesh *__gl_meshUnion( GLUmesh *mesh1, GLUmesh *mesh2 ); +void __gl_meshDeleteMesh( GLUmesh *mesh ); +void __gl_meshZapFace( GLUface *fZap ); + +#ifdef NDEBUG +#define __gl_meshCheckMesh( mesh ) +#else +void __gl_meshCheckMesh( GLUmesh *mesh ); +#endif + +#endif diff --git a/common/libtess/normal.c b/common/libtess/normal.c new file mode 100755 index 0000000..db9b524 --- /dev/null +++ b/common/libtess/normal.c @@ -0,0 +1,254 @@ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * 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 including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * 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 + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ +/* +** Author: Eric Veach, July 1994. +** +*/ + +#include "../prboom/SDL_opengl.h" // JDC +//#include "gluos.h" +#include "mesh.h" +#include "tess.h" +#include "normal.h" +#include +#include + +#define TRUE 1 +#define FALSE 0 + +#define Dot(u,v) (u[0]*v[0] + u[1]*v[1] + u[2]*v[2]) + +#if 0 +static void Normalize( GLdouble v[3] ) +{ + GLdouble len = v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; + + assert( len > 0 ); + len = sqrt( len ); + v[0] /= len; + v[1] /= len; + v[2] /= len; +} +#endif + +#undef ABS +#define ABS(x) ((x) < 0 ? -(x) : (x)) + +static int LongAxis( GLdouble v[3] ) +{ + int i = 0; + + if( ABS(v[1]) > ABS(v[0]) ) { i = 1; } + if( ABS(v[2]) > ABS(v[i]) ) { i = 2; } + return i; +} + +static void ComputeNormal( GLUtesselator *tess, GLdouble norm[3] ) +{ + GLUvertex *v, *v1, *v2; + GLdouble c, tLen2, maxLen2; + GLdouble maxVal[3], minVal[3], d1[3], d2[3], tNorm[3]; + GLUvertex *maxVert[3], *minVert[3]; + GLUvertex *vHead = &tess->mesh->vHead; + int i; + + maxVal[0] = maxVal[1] = maxVal[2] = -2 * GLU_TESS_MAX_COORD; + minVal[0] = minVal[1] = minVal[2] = 2 * GLU_TESS_MAX_COORD; + + for( v = vHead->next; v != vHead; v = v->next ) { + for( i = 0; i < 3; ++i ) { + c = v->coords[i]; + if( c < minVal[i] ) { minVal[i] = c; minVert[i] = v; } + if( c > maxVal[i] ) { maxVal[i] = c; maxVert[i] = v; } + } + } + + /* Find two vertices separated by at least 1/sqrt(3) of the maximum + * distance between any two vertices + */ + i = 0; + if( maxVal[1] - minVal[1] > maxVal[0] - minVal[0] ) { i = 1; } + if( maxVal[2] - minVal[2] > maxVal[i] - minVal[i] ) { i = 2; } + if( minVal[i] >= maxVal[i] ) { + /* All vertices are the same -- normal doesn't matter */ + norm[0] = 0; norm[1] = 0; norm[2] = 1; + return; + } + + /* Look for a third vertex which forms the triangle with maximum area + * (Length of normal == twice the triangle area) + */ + maxLen2 = 0; + v1 = minVert[i]; + v2 = maxVert[i]; + d1[0] = v1->coords[0] - v2->coords[0]; + d1[1] = v1->coords[1] - v2->coords[1]; + d1[2] = v1->coords[2] - v2->coords[2]; + for( v = vHead->next; v != vHead; v = v->next ) { + d2[0] = v->coords[0] - v2->coords[0]; + d2[1] = v->coords[1] - v2->coords[1]; + d2[2] = v->coords[2] - v2->coords[2]; + tNorm[0] = d1[1]*d2[2] - d1[2]*d2[1]; + tNorm[1] = d1[2]*d2[0] - d1[0]*d2[2]; + tNorm[2] = d1[0]*d2[1] - d1[1]*d2[0]; + tLen2 = tNorm[0]*tNorm[0] + tNorm[1]*tNorm[1] + tNorm[2]*tNorm[2]; + if( tLen2 > maxLen2 ) { + maxLen2 = tLen2; + norm[0] = tNorm[0]; + norm[1] = tNorm[1]; + norm[2] = tNorm[2]; + } + } + + if( maxLen2 <= 0 ) { + /* All points lie on a single line -- any decent normal will do */ + norm[0] = norm[1] = norm[2] = 0; + norm[LongAxis(d1)] = 1; + } +} + + +static void CheckOrientation( GLUtesselator *tess ) +{ + GLdouble area; + GLUface *f, *fHead = &tess->mesh->fHead; + GLUvertex *v, *vHead = &tess->mesh->vHead; + GLUhalfEdge *e; + + /* When we compute the normal automatically, we choose the orientation + * so that the the sum of the signed areas of all contours is non-negative. + */ + area = 0; + for( f = fHead->next; f != fHead; f = f->next ) { + e = f->anEdge; + if( e->winding <= 0 ) continue; + do { + area += (e->Org->s - e->Dst->s) * (e->Org->t + e->Dst->t); + e = e->Lnext; + } while( e != f->anEdge ); + } + if( area < 0 ) { + /* Reverse the orientation by flipping all the t-coordinates */ + for( v = vHead->next; v != vHead; v = v->next ) { + v->t = - v->t; + } + tess->tUnit[0] = - tess->tUnit[0]; + tess->tUnit[1] = - tess->tUnit[1]; + tess->tUnit[2] = - tess->tUnit[2]; + } +} + +#ifdef FOR_TRITE_TEST_PROGRAM +#include +extern int RandomSweep; +#define S_UNIT_X (RandomSweep ? (2*drand48()-1) : 1.0) +#define S_UNIT_Y (RandomSweep ? (2*drand48()-1) : 0.0) +#else +#if defined(SLANTED_SWEEP) +/* The "feature merging" is not intended to be complete. There are + * special cases where edges are nearly parallel to the sweep line + * which are not implemented. The algorithm should still behave + * robustly (ie. produce a reasonable tesselation) in the presence + * of such edges, however it may miss features which could have been + * merged. We could minimize this effect by choosing the sweep line + * direction to be something unusual (ie. not parallel to one of the + * coordinate axes). + */ +#define S_UNIT_X 0.50941539564955385 /* Pre-normalized */ +#define S_UNIT_Y 0.86052074622010633 +#else +#define S_UNIT_X 1.0 +#define S_UNIT_Y 0.0 +#endif +#endif + +/* Determine the polygon normal and project vertices onto the plane + * of the polygon. + */ +void __gl_projectPolygon( GLUtesselator *tess ) +{ + GLUvertex *v, *vHead = &tess->mesh->vHead; + GLdouble norm[3]; + GLdouble *sUnit, *tUnit; + int i, computedNormal = FALSE; + + norm[0] = tess->normal[0]; + norm[1] = tess->normal[1]; + norm[2] = tess->normal[2]; + if( norm[0] == 0 && norm[1] == 0 && norm[2] == 0 ) { + ComputeNormal( tess, norm ); + computedNormal = TRUE; + } + sUnit = tess->sUnit; + tUnit = tess->tUnit; + i = LongAxis( norm ); + +#if defined(FOR_TRITE_TEST_PROGRAM) || defined(TRUE_PROJECT) + /* Choose the initial sUnit vector to be approximately perpendicular + * to the normal. + */ + Normalize( norm ); + + sUnit[i] = 0; + sUnit[(i+1)%3] = S_UNIT_X; + sUnit[(i+2)%3] = S_UNIT_Y; + + /* Now make it exactly perpendicular */ + w = Dot( sUnit, norm ); + sUnit[0] -= w * norm[0]; + sUnit[1] -= w * norm[1]; + sUnit[2] -= w * norm[2]; + Normalize( sUnit ); + + /* Choose tUnit so that (sUnit,tUnit,norm) form a right-handed frame */ + tUnit[0] = norm[1]*sUnit[2] - norm[2]*sUnit[1]; + tUnit[1] = norm[2]*sUnit[0] - norm[0]*sUnit[2]; + tUnit[2] = norm[0]*sUnit[1] - norm[1]*sUnit[0]; + Normalize( tUnit ); +#else + /* Project perpendicular to a coordinate axis -- better numerically */ + sUnit[i] = 0; + sUnit[(i+1)%3] = S_UNIT_X; + sUnit[(i+2)%3] = S_UNIT_Y; + + tUnit[i] = 0; + tUnit[(i+1)%3] = (norm[i] > 0) ? -S_UNIT_Y : S_UNIT_Y; + tUnit[(i+2)%3] = (norm[i] > 0) ? S_UNIT_X : -S_UNIT_X; +#endif + + /* Project the vertices onto the sweep plane */ + for( v = vHead->next; v != vHead; v = v->next ) { + v->s = Dot( v->coords, sUnit ); + v->t = Dot( v->coords, tUnit ); + } + if( computedNormal ) { + CheckOrientation( tess ); + } +} diff --git a/common/libtess/normal.h b/common/libtess/normal.h new file mode 100755 index 0000000..c376ca4 --- /dev/null +++ b/common/libtess/normal.h @@ -0,0 +1,45 @@ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * 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 including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * 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 + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ +/* +** Author: Eric Veach, July 1994. +** +*/ + +#ifndef __normal_h_ +#define __normal_h_ + +#include "tess.h" + +/* __gl_projectPolygon( tess ) determines the polygon normal + * and project vertices onto the plane of the polygon. + */ +void __gl_projectPolygon( GLUtesselator *tess ); + +#endif diff --git a/common/libtess/priorityq-heap.c b/common/libtess/priorityq-heap.c new file mode 100755 index 0000000..2d7d164 --- /dev/null +++ b/common/libtess/priorityq-heap.c @@ -0,0 +1,253 @@ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * 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 including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * 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 + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ +/* +** Author: Eric Veach, July 1994. +** +*/ + +#include +#include +#include +#include "priorityq-heap.h" +#include "memalloc.h" + +#define INIT_SIZE 32 + +#define TRUE 1 +#define FALSE 0 + +#ifdef FOR_TRITE_TEST_PROGRAM +#define LEQ(x,y) (*pq->leq)(x,y) +#else +/* Violates modularity, but a little faster */ +#include "geom.h" +#define LEQ(x,y) VertLeq((GLUvertex *)x, (GLUvertex *)y) +#endif + +/* really __gl_pqHeapNewPriorityQ */ +PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) ) +{ + PriorityQ *pq = (PriorityQ *)memAlloc( sizeof( PriorityQ )); + if (pq == NULL) return NULL; + + pq->size = 0; + pq->max = INIT_SIZE; + pq->nodes = (PQnode *)memAlloc( (INIT_SIZE + 1) * sizeof(pq->nodes[0]) ); + if (pq->nodes == NULL) { + memFree(pq); + return NULL; + } + + pq->handles = (PQhandleElem *)memAlloc( (INIT_SIZE + 1) * sizeof(pq->handles[0]) ); + if (pq->handles == NULL) { + memFree(pq->nodes); + memFree(pq); + return NULL; + } + + pq->initialized = FALSE; + pq->freeList = 0; + pq->leq = leq; + + pq->nodes[1].handle = 1; /* so that Minimum() returns NULL */ + pq->handles[1].key = NULL; + return pq; +} + +/* really __gl_pqHeapDeletePriorityQ */ +void pqDeletePriorityQ( PriorityQ *pq ) +{ + memFree( pq->handles ); + memFree( pq->nodes ); + memFree( pq ); +} + + +static void FloatDown( PriorityQ *pq, long curr ) +{ + PQnode *n = pq->nodes; + PQhandleElem *h = pq->handles; + PQhandle hCurr, hChild; + long child; + + hCurr = n[curr].handle; + for( ;; ) { + child = curr << 1; + if( child < pq->size && LEQ( h[n[child+1].handle].key, + h[n[child].handle].key )) { + ++child; + } + + assert(child <= pq->max); + + hChild = n[child].handle; + if( child > pq->size || LEQ( h[hCurr].key, h[hChild].key )) { + n[curr].handle = hCurr; + h[hCurr].node = curr; + break; + } + n[curr].handle = hChild; + h[hChild].node = curr; + curr = child; + } +} + + +static void FloatUp( PriorityQ *pq, long curr ) +{ + PQnode *n = pq->nodes; + PQhandleElem *h = pq->handles; + PQhandle hCurr, hParent; + long parent; + + hCurr = n[curr].handle; + for( ;; ) { + parent = curr >> 1; + hParent = n[parent].handle; + if( parent == 0 || LEQ( h[hParent].key, h[hCurr].key )) { + n[curr].handle = hCurr; + h[hCurr].node = curr; + break; + } + n[curr].handle = hParent; + h[hParent].node = curr; + curr = parent; + } +} + +/* really __gl_pqHeapInit */ +void pqInit( PriorityQ *pq ) +{ + long i; + + /* This method of building a heap is O(n), rather than O(n lg n). */ + + for( i = pq->size; i >= 1; --i ) { + FloatDown( pq, i ); + } + pq->initialized = TRUE; +} + +/* really __gl_pqHeapInsert */ +/* returns LONG_MAX iff out of memory */ +PQhandle pqInsert( PriorityQ *pq, PQkey keyNew ) +{ + long curr; + PQhandle free; + + curr = ++ pq->size; + if( (curr*2) > pq->max ) { + PQnode *saveNodes= pq->nodes; + PQhandleElem *saveHandles= pq->handles; + + /* If the heap overflows, double its size. */ + pq->max <<= 1; + pq->nodes = (PQnode *)memRealloc( pq->nodes, + (size_t) + ((pq->max + 1) * sizeof( pq->nodes[0] ))); + if (pq->nodes == NULL) { + pq->nodes = saveNodes; /* restore ptr to free upon return */ + return LONG_MAX; + } + pq->handles = (PQhandleElem *)memRealloc( pq->handles, + (size_t) + ((pq->max + 1) * + sizeof( pq->handles[0] ))); + if (pq->handles == NULL) { + pq->handles = saveHandles; /* restore ptr to free upon return */ + return LONG_MAX; + } + } + + if( pq->freeList == 0 ) { + free = curr; + } else { + free = pq->freeList; + pq->freeList = pq->handles[free].node; + } + + pq->nodes[curr].handle = free; + pq->handles[free].node = curr; + pq->handles[free].key = keyNew; + + if( pq->initialized ) { + FloatUp( pq, curr ); + } + assert(free != LONG_MAX); + return free; +} + +/* really __gl_pqHeapExtractMin */ +PQkey pqExtractMin( PriorityQ *pq ) +{ + PQnode *n = pq->nodes; + PQhandleElem *h = pq->handles; + PQhandle hMin = n[1].handle; + PQkey min = h[hMin].key; + + if( pq->size > 0 ) { + n[1].handle = n[pq->size].handle; + h[n[1].handle].node = 1; + + h[hMin].key = NULL; + h[hMin].node = pq->freeList; + pq->freeList = hMin; + + if( -- pq->size > 0 ) { + FloatDown( pq, 1 ); + } + } + return min; +} + +/* really __gl_pqHeapDelete */ +void pqDelete( PriorityQ *pq, PQhandle hCurr ) +{ + PQnode *n = pq->nodes; + PQhandleElem *h = pq->handles; + long curr; + + assert( hCurr >= 1 && hCurr <= pq->max && h[hCurr].key != NULL ); + + curr = h[hCurr].node; + n[curr].handle = n[pq->size].handle; + h[n[curr].handle].node = curr; + + if( curr <= -- pq->size ) { + if( curr <= 1 || LEQ( h[n[curr>>1].handle].key, h[n[curr].handle].key )) { + FloatDown( pq, curr ); + } else { + FloatUp( pq, curr ); + } + } + h[hCurr].key = NULL; + h[hCurr].node = pq->freeList; + pq->freeList = hCurr; +} diff --git a/common/libtess/priorityq-heap.h b/common/libtess/priorityq-heap.h new file mode 100755 index 0000000..dc9aaef --- /dev/null +++ b/common/libtess/priorityq-heap.h @@ -0,0 +1,107 @@ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * 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 including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * 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 + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ +/* +** Author: Eric Veach, July 1994. +** +*/ + +#ifndef __priorityq_heap_h_ +#define __priorityq_heap_h_ + +/* Use #define's so that another heap implementation can use this one */ + +#define PQkey PQHeapKey +#define PQhandle PQHeapHandle +#define PriorityQ PriorityQHeap + +#define pqNewPriorityQ(leq) __gl_pqHeapNewPriorityQ(leq) +#define pqDeletePriorityQ(pq) __gl_pqHeapDeletePriorityQ(pq) + +/* The basic operations are insertion of a new key (pqInsert), + * and examination/extraction of a key whose value is minimum + * (pqMinimum/pqExtractMin). Deletion is also allowed (pqDelete); + * for this purpose pqInsert returns a "handle" which is supplied + * as the argument. + * + * An initial heap may be created efficiently by calling pqInsert + * repeatedly, then calling pqInit. In any case pqInit must be called + * before any operations other than pqInsert are used. + * + * If the heap is empty, pqMinimum/pqExtractMin will return a NULL key. + * This may also be tested with pqIsEmpty. + */ +#define pqInit(pq) __gl_pqHeapInit(pq) +#define pqInsert(pq,key) __gl_pqHeapInsert(pq,key) +#define pqMinimum(pq) __gl_pqHeapMinimum(pq) +#define pqExtractMin(pq) __gl_pqHeapExtractMin(pq) +#define pqDelete(pq,handle) __gl_pqHeapDelete(pq,handle) +#define pqIsEmpty(pq) __gl_pqHeapIsEmpty(pq) + + +/* Since we support deletion the data structure is a little more + * complicated than an ordinary heap. "nodes" is the heap itself; + * active nodes are stored in the range 1..pq->size. When the + * heap exceeds its allocated size (pq->max), its size doubles. + * The children of node i are nodes 2i and 2i+1. + * + * Each node stores an index into an array "handles". Each handle + * stores a key, plus a pointer back to the node which currently + * represents that key (ie. nodes[handles[i].node].handle == i). + */ + +typedef void *PQkey; +typedef long PQhandle; +typedef struct PriorityQ PriorityQ; + +typedef struct { PQhandle handle; } PQnode; +typedef struct { PQkey key; PQhandle node; } PQhandleElem; + +struct PriorityQ { + PQnode *nodes; + PQhandleElem *handles; + long size, max; + PQhandle freeList; + int initialized; + int (*leq)(PQkey key1, PQkey key2); +}; + +PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) ); +void pqDeletePriorityQ( PriorityQ *pq ); + +void pqInit( PriorityQ *pq ); +PQhandle pqInsert( PriorityQ *pq, PQkey key ); +PQkey pqExtractMin( PriorityQ *pq ); +void pqDelete( PriorityQ *pq, PQhandle handle ); + + +#define __gl_pqHeapMinimum(pq) ((pq)->handles[(pq)->nodes[1].handle].key) +#define __gl_pqHeapIsEmpty(pq) ((pq)->size == 0) + +#endif diff --git a/common/libtess/priorityq-sort.h b/common/libtess/priorityq-sort.h new file mode 100755 index 0000000..746cf5f --- /dev/null +++ b/common/libtess/priorityq-sort.h @@ -0,0 +1,117 @@ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * 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 including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * 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 + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ +/* +** Author: Eric Veach, July 1994. +** +*/ + +#ifndef __priorityq_sort_h_ +#define __priorityq_sort_h_ + +#include "priorityq-heap.h" + +#undef PQkey +#undef PQhandle +#undef PriorityQ +#undef pqNewPriorityQ +#undef pqDeletePriorityQ +#undef pqInit +#undef pqInsert +#undef pqMinimum +#undef pqExtractMin +#undef pqDelete +#undef pqIsEmpty + +/* Use #define's so that another heap implementation can use this one */ + +#define PQkey PQSortKey +#define PQhandle PQSortHandle +#define PriorityQ PriorityQSort + +#define pqNewPriorityQ(leq) __gl_pqSortNewPriorityQ(leq) +#define pqDeletePriorityQ(pq) __gl_pqSortDeletePriorityQ(pq) + +/* The basic operations are insertion of a new key (pqInsert), + * and examination/extraction of a key whose value is minimum + * (pqMinimum/pqExtractMin). Deletion is also allowed (pqDelete); + * for this purpose pqInsert returns a "handle" which is supplied + * as the argument. + * + * An initial heap may be created efficiently by calling pqInsert + * repeatedly, then calling pqInit. In any case pqInit must be called + * before any operations other than pqInsert are used. + * + * If the heap is empty, pqMinimum/pqExtractMin will return a NULL key. + * This may also be tested with pqIsEmpty. + */ +#define pqInit(pq) __gl_pqSortInit(pq) +#define pqInsert(pq,key) __gl_pqSortInsert(pq,key) +#define pqMinimum(pq) __gl_pqSortMinimum(pq) +#define pqExtractMin(pq) __gl_pqSortExtractMin(pq) +#define pqDelete(pq,handle) __gl_pqSortDelete(pq,handle) +#define pqIsEmpty(pq) __gl_pqSortIsEmpty(pq) + + +/* Since we support deletion the data structure is a little more + * complicated than an ordinary heap. "nodes" is the heap itself; + * active nodes are stored in the range 1..pq->size. When the + * heap exceeds its allocated size (pq->max), its size doubles. + * The children of node i are nodes 2i and 2i+1. + * + * Each node stores an index into an array "handles". Each handle + * stores a key, plus a pointer back to the node which currently + * represents that key (ie. nodes[handles[i].node].handle == i). + */ + +typedef PQHeapKey PQkey; +typedef PQHeapHandle PQhandle; +typedef struct PriorityQ PriorityQ; + +struct PriorityQ { + PriorityQHeap *heap; + PQkey *keys; + PQkey **order; + PQhandle size, max; + int initialized; + int (*leq)(PQkey key1, PQkey key2); +}; + +PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) ); +void pqDeletePriorityQ( PriorityQ *pq ); + +int pqInit( PriorityQ *pq ); +PQhandle pqInsert( PriorityQ *pq, PQkey key ); +PQkey pqExtractMin( PriorityQ *pq ); +void pqDelete( PriorityQ *pq, PQhandle handle ); + +PQkey pqMinimum( PriorityQ *pq ); +int pqIsEmpty( PriorityQ *pq ); + +#endif diff --git a/common/libtess/priorityq.c b/common/libtess/priorityq.c new file mode 100755 index 0000000..5e15181 --- /dev/null +++ b/common/libtess/priorityq.c @@ -0,0 +1,264 @@ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * 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 including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * 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 + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ +/* +** Author: Eric Veach, July 1994. +** +*/ + +typedef double GLdouble; +typedef unsigned char GLboolean; + +//#include "gluos.h" + +#include +#include +#include /* LONG_MAX */ +#include "memalloc.h" + +/* Include all the code for the regular heap-based queue here. */ + +#include "priorityq-heap.c" + +/* Now redefine all the function names to map to their "Sort" versions. */ + +#include "priorityq-sort.h" + +/* really __gl_pqSortNewPriorityQ */ +PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) ) +{ + PriorityQ *pq = (PriorityQ *)memAlloc( sizeof( PriorityQ )); + if (pq == NULL) return NULL; + + pq->heap = __gl_pqHeapNewPriorityQ( leq ); + if (pq->heap == NULL) { + memFree(pq); + return NULL; + } + + pq->keys = (PQHeapKey *)memAlloc( INIT_SIZE * sizeof(pq->keys[0]) ); + if (pq->keys == NULL) { + __gl_pqHeapDeletePriorityQ(pq->heap); + memFree(pq); + return NULL; + } + + pq->size = 0; + pq->max = INIT_SIZE; + pq->initialized = FALSE; + pq->leq = leq; + return pq; +} + +/* really __gl_pqSortDeletePriorityQ */ +void pqDeletePriorityQ( PriorityQ *pq ) +{ + assert(pq != NULL); + if (pq->heap != NULL) __gl_pqHeapDeletePriorityQ( pq->heap ); + if (pq->order != NULL) memFree( pq->order ); + if (pq->keys != NULL) memFree( pq->keys ); + memFree( pq ); +} + + +#define LT(x,y) (! LEQ(y,x)) +#define GT(x,y) (! LEQ(x,y)) +#define Swap(a,b) if(1){PQkey *tmp = *a; *a = *b; *b = tmp;}else + +/* really __gl_pqSortInit */ +int pqInit( PriorityQ *pq ) +{ + PQkey **p, **r, **i, **j, *piv; + struct { PQkey **p, **r; } Stack[50], *top = Stack; + unsigned long seed = 2016473283; + + /* Create an array of indirect pointers to the keys, so that we + * the handles we have returned are still valid. + */ +/* + pq->order = (PQHeapKey **)memAlloc( (size_t) + (pq->size * sizeof(pq->order[0])) ); +*/ + pq->order = (PQHeapKey **)memAlloc( (size_t) + ((pq->size+1) * sizeof(pq->order[0])) ); +/* the previous line is a patch to compensate for the fact that IBM */ +/* machines return a null on a malloc of zero bytes (unlike SGI), */ +/* so we have to put in this defense to guard against a memory */ +/* fault four lines down. from fossum@austin.ibm.com. */ + if (pq->order == NULL) return 0; + + p = pq->order; + r = p + pq->size - 1; + for( piv = pq->keys, i = p; i <= r; ++piv, ++i ) { + *i = piv; + } + + /* Sort the indirect pointers in descending order, + * using randomized Quicksort + */ + top->p = p; top->r = r; ++top; + while( --top >= Stack ) { + p = top->p; + r = top->r; + while( r > p + 10 ) { + seed = seed * 1539415821 + 1; + i = p + seed % (r - p + 1); + piv = *i; + *i = *p; + *p = piv; + i = p - 1; + j = r + 1; + do { + do { ++i; } while( GT( **i, *piv )); + do { --j; } while( LT( **j, *piv )); + Swap( i, j ); + } while( i < j ); + Swap( i, j ); /* Undo last swap */ + if( i - p < r - j ) { + top->p = j+1; top->r = r; ++top; + r = i-1; + } else { + top->p = p; top->r = i-1; ++top; + p = j+1; + } + } + /* Insertion sort small lists */ + for( i = p+1; i <= r; ++i ) { + piv = *i; + for( j = i; j > p && LT( **(j-1), *piv ); --j ) { + *j = *(j-1); + } + *j = piv; + } + } + pq->max = pq->size; + pq->initialized = TRUE; + __gl_pqHeapInit( pq->heap ); /* always succeeds */ + +#ifndef NDEBUG + p = pq->order; + r = p + pq->size - 1; + for( i = p; i < r; ++i ) { + assert( LEQ( **(i+1), **i )); + } +#endif + + return 1; +} + +/* really __gl_pqSortInsert */ +/* returns LONG_MAX iff out of memory */ +PQhandle pqInsert( PriorityQ *pq, PQkey keyNew ) +{ + long curr; + + if( pq->initialized ) { + return __gl_pqHeapInsert( pq->heap, keyNew ); + } + curr = pq->size; + if( ++ pq->size >= pq->max ) { + PQkey *saveKey= pq->keys; + + /* If the heap overflows, double its size. */ + pq->max <<= 1; + pq->keys = (PQHeapKey *)memRealloc( pq->keys, + (size_t) + (pq->max * sizeof( pq->keys[0] ))); + if (pq->keys == NULL) { + pq->keys = saveKey; /* restore ptr to free upon return */ + return LONG_MAX; + } + } + assert(curr != LONG_MAX); + pq->keys[curr] = keyNew; + + /* Negative handles index the sorted array. */ + return -(curr+1); +} + +/* really __gl_pqSortExtractMin */ +PQkey pqExtractMin( PriorityQ *pq ) +{ + PQkey sortMin, heapMin; + + if( pq->size == 0 ) { + return __gl_pqHeapExtractMin( pq->heap ); + } + sortMin = *(pq->order[pq->size-1]); + if( ! __gl_pqHeapIsEmpty( pq->heap )) { + heapMin = __gl_pqHeapMinimum( pq->heap ); + if( LEQ( heapMin, sortMin )) { + return __gl_pqHeapExtractMin( pq->heap ); + } + } + do { + -- pq->size; + } while( pq->size > 0 && *(pq->order[pq->size-1]) == NULL ); + return sortMin; +} + +/* really __gl_pqSortMinimum */ +PQkey pqMinimum( PriorityQ *pq ) +{ + PQkey sortMin, heapMin; + + if( pq->size == 0 ) { + return __gl_pqHeapMinimum( pq->heap ); + } + sortMin = *(pq->order[pq->size-1]); + if( ! __gl_pqHeapIsEmpty( pq->heap )) { + heapMin = __gl_pqHeapMinimum( pq->heap ); + if( LEQ( heapMin, sortMin )) { + return heapMin; + } + } + return sortMin; +} + +/* really __gl_pqSortIsEmpty */ +int pqIsEmpty( PriorityQ *pq ) +{ + return (pq->size == 0) && __gl_pqHeapIsEmpty( pq->heap ); +} + +/* really __gl_pqSortDelete */ +void pqDelete( PriorityQ *pq, PQhandle curr ) +{ + if( curr >= 0 ) { + __gl_pqHeapDelete( pq->heap, curr ); + return; + } + curr = -(curr+1); + assert( curr < pq->max && pq->keys[curr] != NULL ); + + pq->keys[curr] = NULL; + while( pq->size > 0 && *(pq->order[pq->size-1]) == NULL ) { + -- pq->size; + } +} diff --git a/common/libtess/priorityq.h b/common/libtess/priorityq.h new file mode 100755 index 0000000..746cf5f --- /dev/null +++ b/common/libtess/priorityq.h @@ -0,0 +1,117 @@ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * 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 including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * 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 + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ +/* +** Author: Eric Veach, July 1994. +** +*/ + +#ifndef __priorityq_sort_h_ +#define __priorityq_sort_h_ + +#include "priorityq-heap.h" + +#undef PQkey +#undef PQhandle +#undef PriorityQ +#undef pqNewPriorityQ +#undef pqDeletePriorityQ +#undef pqInit +#undef pqInsert +#undef pqMinimum +#undef pqExtractMin +#undef pqDelete +#undef pqIsEmpty + +/* Use #define's so that another heap implementation can use this one */ + +#define PQkey PQSortKey +#define PQhandle PQSortHandle +#define PriorityQ PriorityQSort + +#define pqNewPriorityQ(leq) __gl_pqSortNewPriorityQ(leq) +#define pqDeletePriorityQ(pq) __gl_pqSortDeletePriorityQ(pq) + +/* The basic operations are insertion of a new key (pqInsert), + * and examination/extraction of a key whose value is minimum + * (pqMinimum/pqExtractMin). Deletion is also allowed (pqDelete); + * for this purpose pqInsert returns a "handle" which is supplied + * as the argument. + * + * An initial heap may be created efficiently by calling pqInsert + * repeatedly, then calling pqInit. In any case pqInit must be called + * before any operations other than pqInsert are used. + * + * If the heap is empty, pqMinimum/pqExtractMin will return a NULL key. + * This may also be tested with pqIsEmpty. + */ +#define pqInit(pq) __gl_pqSortInit(pq) +#define pqInsert(pq,key) __gl_pqSortInsert(pq,key) +#define pqMinimum(pq) __gl_pqSortMinimum(pq) +#define pqExtractMin(pq) __gl_pqSortExtractMin(pq) +#define pqDelete(pq,handle) __gl_pqSortDelete(pq,handle) +#define pqIsEmpty(pq) __gl_pqSortIsEmpty(pq) + + +/* Since we support deletion the data structure is a little more + * complicated than an ordinary heap. "nodes" is the heap itself; + * active nodes are stored in the range 1..pq->size. When the + * heap exceeds its allocated size (pq->max), its size doubles. + * The children of node i are nodes 2i and 2i+1. + * + * Each node stores an index into an array "handles". Each handle + * stores a key, plus a pointer back to the node which currently + * represents that key (ie. nodes[handles[i].node].handle == i). + */ + +typedef PQHeapKey PQkey; +typedef PQHeapHandle PQhandle; +typedef struct PriorityQ PriorityQ; + +struct PriorityQ { + PriorityQHeap *heap; + PQkey *keys; + PQkey **order; + PQhandle size, max; + int initialized; + int (*leq)(PQkey key1, PQkey key2); +}; + +PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) ); +void pqDeletePriorityQ( PriorityQ *pq ); + +int pqInit( PriorityQ *pq ); +PQhandle pqInsert( PriorityQ *pq, PQkey key ); +PQkey pqExtractMin( PriorityQ *pq ); +void pqDelete( PriorityQ *pq, PQhandle handle ); + +PQkey pqMinimum( PriorityQ *pq ); +int pqIsEmpty( PriorityQ *pq ); + +#endif diff --git a/common/libtess/render.c b/common/libtess/render.c new file mode 100755 index 0000000..410d6b8 --- /dev/null +++ b/common/libtess/render.c @@ -0,0 +1,499 @@ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * 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 including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * 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 + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ +/* +** Author: Eric Veach, July 1994. +** +*/ + +#include "../prboom/SDL_opengl.h" // JDC +//#include "gluos.h" +#include +#include +#include "mesh.h" +#include "tess.h" +#include "render.h" + +#define TRUE 1 +#define FALSE 0 + +/* This structure remembers the information we need about a primitive + * to be able to render it later, once we have determined which + * primitive is able to use the most triangles. + */ +struct FaceCount { + long size; /* number of triangles used */ + GLUhalfEdge *eStart; /* edge where this primitive starts */ + void (*render)(GLUtesselator *, GLUhalfEdge *, long); + /* routine to render this primitive */ +}; + +static struct FaceCount MaximumFan( GLUhalfEdge *eOrig ); +static struct FaceCount MaximumStrip( GLUhalfEdge *eOrig ); + +static void RenderFan( GLUtesselator *tess, GLUhalfEdge *eStart, long size ); +static void RenderStrip( GLUtesselator *tess, GLUhalfEdge *eStart, long size ); +static void RenderTriangle( GLUtesselator *tess, GLUhalfEdge *eStart, + long size ); + +static void RenderMaximumFaceGroup( GLUtesselator *tess, GLUface *fOrig ); +static void RenderLonelyTriangles( GLUtesselator *tess, GLUface *head ); + + + +/************************ Strips and Fans decomposition ******************/ + +/* __gl_renderMesh( tess, mesh ) takes a mesh and breaks it into triangle + * fans, strips, and separate triangles. A substantial effort is made + * to use as few rendering primitives as possible (ie. to make the fans + * and strips as large as possible). + * + * The rendering output is provided as callbacks (see the api). + */ +void __gl_renderMesh( GLUtesselator *tess, GLUmesh *mesh ) +{ + GLUface *f; + + /* Make a list of separate triangles so we can render them all at once */ + tess->lonelyTriList = NULL; + + for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) { + f->marked = FALSE; + } + for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) { + + /* We examine all faces in an arbitrary order. Whenever we find + * an unprocessed face F, we output a group of faces including F + * whose size is maximum. + */ + if( f->inside && ! f->marked ) { + RenderMaximumFaceGroup( tess, f ); + assert( f->marked ); + } + } + if( tess->lonelyTriList != NULL ) { + RenderLonelyTriangles( tess, tess->lonelyTriList ); + tess->lonelyTriList = NULL; + } +} + + +static void RenderMaximumFaceGroup( GLUtesselator *tess, GLUface *fOrig ) +{ + /* We want to find the largest triangle fan or strip of unmarked faces + * which includes the given face fOrig. There are 3 possible fans + * passing through fOrig (one centered at each vertex), and 3 possible + * strips (one for each CCW permutation of the vertices). Our strategy + * is to try all of these, and take the primitive which uses the most + * triangles (a greedy approach). + */ + GLUhalfEdge *e = fOrig->anEdge; + struct FaceCount max, newFace; + + max.size = 1; + max.eStart = e; + max.render = &RenderTriangle; + + if( ! tess->flagBoundary ) { + newFace = MaximumFan( e ); if( newFace.size > max.size ) { max = newFace; } + newFace = MaximumFan( e->Lnext ); if( newFace.size > max.size ) { max = newFace; } + newFace = MaximumFan( e->Lprev ); if( newFace.size > max.size ) { max = newFace; } + + newFace = MaximumStrip( e ); if( newFace.size > max.size ) { max = newFace; } + newFace = MaximumStrip( e->Lnext ); if( newFace.size > max.size ) { max = newFace; } + newFace = MaximumStrip( e->Lprev ); if( newFace.size > max.size ) { max = newFace; } + } + (*(max.render))( tess, max.eStart, max.size ); +} + + +/* Macros which keep track of faces we have marked temporarily, and allow + * us to backtrack when necessary. With triangle fans, this is not + * really necessary, since the only awkward case is a loop of triangles + * around a single origin vertex. However with strips the situation is + * more complicated, and we need a general tracking method like the + * one here. + */ +#define Marked(f) (! (f)->inside || (f)->marked) + +#define AddToTrail(f,t) ((f)->trail = (t), (t) = (f), (f)->marked = TRUE) + +#define FreeTrail(t) if( 1 ) { \ + while( (t) != NULL ) { \ + (t)->marked = FALSE; t = (t)->trail; \ + } \ + } else /* absorb trailing semicolon */ + + + +static struct FaceCount MaximumFan( GLUhalfEdge *eOrig ) +{ + /* eOrig->Lface is the face we want to render. We want to find the size + * of a maximal fan around eOrig->Org. To do this we just walk around + * the origin vertex as far as possible in both directions. + */ + struct FaceCount newFace = { 0, NULL, &RenderFan }; + GLUface *trail = NULL; + GLUhalfEdge *e; + + for( e = eOrig; ! Marked( e->Lface ); e = e->Onext ) { + AddToTrail( e->Lface, trail ); + ++newFace.size; + } + for( e = eOrig; ! Marked( e->Rface ); e = e->Oprev ) { + AddToTrail( e->Rface, trail ); + ++newFace.size; + } + newFace.eStart = e; + /*LINTED*/ + FreeTrail( trail ); + return newFace; +} + + +#define IsEven(n) (((n) & 1) == 0) + +static struct FaceCount MaximumStrip( GLUhalfEdge *eOrig ) +{ + /* Here we are looking for a maximal strip that contains the vertices + * eOrig->Org, eOrig->Dst, eOrig->Lnext->Dst (in that order or the + * reverse, such that all triangles are oriented CCW). + * + * Again we walk forward and backward as far as possible. However for + * strips there is a twist: to get CCW orientations, there must be + * an *even* number of triangles in the strip on one side of eOrig. + * We walk the strip starting on a side with an even number of triangles; + * if both side have an odd number, we are forced to shorten one side. + */ + struct FaceCount newFace = { 0, NULL, &RenderStrip }; + long headSize = 0, tailSize = 0; + GLUface *trail = NULL; + GLUhalfEdge *e, *eTail, *eHead; + + for( e = eOrig; ! Marked( e->Lface ); ++tailSize, e = e->Onext ) { + AddToTrail( e->Lface, trail ); + ++tailSize; + e = e->Dprev; + if( Marked( e->Lface )) break; + AddToTrail( e->Lface, trail ); + } + eTail = e; + + for( e = eOrig; ! Marked( e->Rface ); ++headSize, e = e->Dnext ) { + AddToTrail( e->Rface, trail ); + ++headSize; + e = e->Oprev; + if( Marked( e->Rface )) break; + AddToTrail( e->Rface, trail ); + } + eHead = e; + + newFace.size = tailSize + headSize; + if( IsEven( tailSize )) { + newFace.eStart = eTail->Sym; + } else if( IsEven( headSize )) { + newFace.eStart = eHead; + } else { + /* Both sides have odd length, we must shorten one of them. In fact, + * we must start from eHead to guarantee inclusion of eOrig->Lface. + */ + --newFace.size; + newFace.eStart = eHead->Onext; + } + /*LINTED*/ + FreeTrail( trail ); + return newFace; +} + + +static void RenderTriangle( GLUtesselator *tess, GLUhalfEdge *e, long size ) +{ + /* Just add the triangle to a triangle list, so we can render all + * the separate triangles at once. + */ + assert( size == 1 ); + AddToTrail( e->Lface, tess->lonelyTriList ); +} + + +static void RenderLonelyTriangles( GLUtesselator *tess, GLUface *f ) +{ + /* Now we render all the separate triangles which could not be + * grouped into a triangle fan or strip. + */ + GLUhalfEdge *e; + int newState; + int edgeState = -1; /* force edge state output for first vertex */ + + CALL_BEGIN_OR_BEGIN_DATA( GL_TRIANGLES ); + + for( ; f != NULL; f = f->trail ) { + /* Loop once for each edge (there will always be 3 edges) */ + + e = f->anEdge; + do { + if( tess->flagBoundary ) { + /* Set the "edge state" to TRUE just before we output the + * first vertex of each edge on the polygon boundary. + */ + newState = ! e->Rface->inside; + if( edgeState != newState ) { + edgeState = newState; + CALL_EDGE_FLAG_OR_EDGE_FLAG_DATA( edgeState ); + } + } + CALL_VERTEX_OR_VERTEX_DATA( e->Org->data ); + + e = e->Lnext; + } while( e != f->anEdge ); + } + CALL_END_OR_END_DATA(); +} + + +static void RenderFan( GLUtesselator *tess, GLUhalfEdge *e, long size ) +{ + /* Render as many CCW triangles as possible in a fan starting from + * edge "e". The fan *should* contain exactly "size" triangles + * (otherwise we've goofed up somewhere). + */ + CALL_BEGIN_OR_BEGIN_DATA( GL_TRIANGLE_FAN ); + CALL_VERTEX_OR_VERTEX_DATA( e->Org->data ); + CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data ); + + while( ! Marked( e->Lface )) { + e->Lface->marked = TRUE; + --size; + e = e->Onext; + CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data ); + } + + assert( size == 0 ); + CALL_END_OR_END_DATA(); +} + + +static void RenderStrip( GLUtesselator *tess, GLUhalfEdge *e, long size ) +{ + /* Render as many CCW triangles as possible in a strip starting from + * edge "e". The strip *should* contain exactly "size" triangles + * (otherwise we've goofed up somewhere). + */ + CALL_BEGIN_OR_BEGIN_DATA( GL_TRIANGLE_STRIP ); + CALL_VERTEX_OR_VERTEX_DATA( e->Org->data ); + CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data ); + + while( ! Marked( e->Lface )) { + e->Lface->marked = TRUE; + --size; + e = e->Dprev; + CALL_VERTEX_OR_VERTEX_DATA( e->Org->data ); + if( Marked( e->Lface )) break; + + e->Lface->marked = TRUE; + --size; + e = e->Onext; + CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data ); + } + + assert( size == 0 ); + CALL_END_OR_END_DATA(); +} + + +/************************ Boundary contour decomposition ******************/ + +/* __gl_renderBoundary( tess, mesh ) takes a mesh, and outputs one + * contour for each face marked "inside". The rendering output is + * provided as callbacks (see the api). + */ +void __gl_renderBoundary( GLUtesselator *tess, GLUmesh *mesh ) +{ + GLUface *f; + GLUhalfEdge *e; + + for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) { + if( f->inside ) { + CALL_BEGIN_OR_BEGIN_DATA( GL_LINE_LOOP ); + e = f->anEdge; + do { + CALL_VERTEX_OR_VERTEX_DATA( e->Org->data ); + e = e->Lnext; + } while( e != f->anEdge ); + CALL_END_OR_END_DATA(); + } + } +} + + +/************************ Quick-and-dirty decomposition ******************/ + +#define SIGN_INCONSISTENT 2 + +static int ComputeNormal( GLUtesselator *tess, GLdouble norm[3], int check ) +/* + * If check==FALSE, we compute the polygon normal and place it in norm[]. + * If check==TRUE, we check that each triangle in the fan from v0 has a + * consistent orientation with respect to norm[]. If triangles are + * consistently oriented CCW, return 1; if CW, return -1; if all triangles + * are degenerate return 0; otherwise (no consistent orientation) return + * SIGN_INCONSISTENT. + */ +{ + CachedVertex *v0 = tess->cache; + CachedVertex *vn = v0 + tess->cacheCount; + CachedVertex *vc; + GLdouble dot, xc, yc, zc, xp, yp, zp, n[3]; + int sign = 0; + + /* Find the polygon normal. It is important to get a reasonable + * normal even when the polygon is self-intersecting (eg. a bowtie). + * Otherwise, the computed normal could be very tiny, but perpendicular + * to the true plane of the polygon due to numerical noise. Then all + * the triangles would appear to be degenerate and we would incorrectly + * decompose the polygon as a fan (or simply not render it at all). + * + * We use a sum-of-triangles normal algorithm rather than the more + * efficient sum-of-trapezoids method (used in CheckOrientation() + * in normal.c). This lets us explicitly reverse the signed area + * of some triangles to get a reasonable normal in the self-intersecting + * case. + */ + if( ! check ) { + norm[0] = norm[1] = norm[2] = 0.0; + } + + vc = v0 + 1; + xc = vc->coords[0] - v0->coords[0]; + yc = vc->coords[1] - v0->coords[1]; + zc = vc->coords[2] - v0->coords[2]; + while( ++vc < vn ) { + xp = xc; yp = yc; zp = zc; + xc = vc->coords[0] - v0->coords[0]; + yc = vc->coords[1] - v0->coords[1]; + zc = vc->coords[2] - v0->coords[2]; + + /* Compute (vp - v0) cross (vc - v0) */ + n[0] = yp*zc - zp*yc; + n[1] = zp*xc - xp*zc; + n[2] = xp*yc - yp*xc; + + dot = n[0]*norm[0] + n[1]*norm[1] + n[2]*norm[2]; + if( ! check ) { + /* Reverse the contribution of back-facing triangles to get + * a reasonable normal for self-intersecting polygons (see above) + */ + if( dot >= 0 ) { + norm[0] += n[0]; norm[1] += n[1]; norm[2] += n[2]; + } else { + norm[0] -= n[0]; norm[1] -= n[1]; norm[2] -= n[2]; + } + } else if( dot != 0 ) { + /* Check the new orientation for consistency with previous triangles */ + if( dot > 0 ) { + if( sign < 0 ) return SIGN_INCONSISTENT; + sign = 1; + } else { + if( sign > 0 ) return SIGN_INCONSISTENT; + sign = -1; + } + } + } + return sign; +} + +/* __gl_renderCache( tess ) takes a single contour and tries to render it + * as a triangle fan. This handles convex polygons, as well as some + * non-convex polygons if we get lucky. + * + * Returns TRUE if the polygon was successfully rendered. The rendering + * output is provided as callbacks (see the api). + */ +GLboolean __gl_renderCache( GLUtesselator *tess ) +{ + CachedVertex *v0 = tess->cache; + CachedVertex *vn = v0 + tess->cacheCount; + CachedVertex *vc; + GLdouble norm[3]; + int sign; + + if( tess->cacheCount < 3 ) { + /* Degenerate contour -- no output */ + return TRUE; + } + + norm[0] = tess->normal[0]; + norm[1] = tess->normal[1]; + norm[2] = tess->normal[2]; + if( norm[0] == 0 && norm[1] == 0 && norm[2] == 0 ) { + ComputeNormal( tess, norm, FALSE ); + } + + sign = ComputeNormal( tess, norm, TRUE ); + if( sign == SIGN_INCONSISTENT ) { + /* Fan triangles did not have a consistent orientation */ + return FALSE; + } + if( sign == 0 ) { + /* All triangles were degenerate */ + return TRUE; + } + + /* Make sure we do the right thing for each winding rule */ + switch( tess->windingRule ) { + case GLU_TESS_WINDING_ODD: + case GLU_TESS_WINDING_NONZERO: + break; + case GLU_TESS_WINDING_POSITIVE: + if( sign < 0 ) return TRUE; + break; + case GLU_TESS_WINDING_NEGATIVE: + if( sign > 0 ) return TRUE; + break; + case GLU_TESS_WINDING_ABS_GEQ_TWO: + return TRUE; + } + + CALL_BEGIN_OR_BEGIN_DATA( tess->boundaryOnly ? GL_LINE_LOOP + : (tess->cacheCount > 3) ? GL_TRIANGLE_FAN + : GL_TRIANGLES ); + + CALL_VERTEX_OR_VERTEX_DATA( v0->data ); + if( sign > 0 ) { + for( vc = v0+1; vc < vn; ++vc ) { + CALL_VERTEX_OR_VERTEX_DATA( vc->data ); + } + } else { + for( vc = vn-1; vc > v0; --vc ) { + CALL_VERTEX_OR_VERTEX_DATA( vc->data ); + } + } + CALL_END_OR_END_DATA(); + return TRUE; +} diff --git a/common/libtess/render.h b/common/libtess/render.h new file mode 100755 index 0000000..a298c9a --- /dev/null +++ b/common/libtess/render.h @@ -0,0 +1,52 @@ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * 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 including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * 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 + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ +/* +** Author: Eric Veach, July 1994. +** +*/ + +#ifndef __render_h_ +#define __render_h_ + +#include "mesh.h" + +/* __gl_renderMesh( tess, mesh ) takes a mesh and breaks it into triangle + * fans, strips, and separate triangles. A substantial effort is made + * to use as few rendering primitives as possible (ie. to make the fans + * and strips as large as possible). + * + * The rendering output is provided as callbacks (see the api). + */ +void __gl_renderMesh( GLUtesselator *tess, GLUmesh *mesh ); +void __gl_renderBoundary( GLUtesselator *tess, GLUmesh *mesh ); + +GLboolean __gl_renderCache( GLUtesselator *tess ); + +#endif diff --git a/common/libtess/sweep.c b/common/libtess/sweep.c new file mode 100755 index 0000000..fdc0cb2 --- /dev/null +++ b/common/libtess/sweep.c @@ -0,0 +1,1358 @@ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * 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 including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * 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 + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ +/* +** Author: Eric Veach, July 1994. +** +*/ + +#include "../prboom/SDL_opengl.h" // JDC +//#include "gluos.h" +#include +#include +#include /* longjmp */ +#include /* LONG_MAX */ + +#include "mesh.h" +#include "geom.h" +#include "tess.h" +#include "dict.h" +#include "priorityq.h" +#include "memalloc.h" +#include "sweep.h" + +#define TRUE 1 +#define FALSE 0 + +#ifdef FOR_TRITE_TEST_PROGRAM +extern void DebugEvent( GLUtesselator *tess ); +#else +#define DebugEvent( tess ) +#endif + +/* + * Invariants for the Edge Dictionary. + * - each pair of adjacent edges e2=Succ(e1) satisfies EdgeLeq(e1,e2) + * at any valid location of the sweep event + * - if EdgeLeq(e2,e1) as well (at any valid sweep event), then e1 and e2 + * share a common endpoint + * - for each e, e->Dst has been processed, but not e->Org + * - each edge e satisfies VertLeq(e->Dst,event) && VertLeq(event,e->Org) + * where "event" is the current sweep line event. + * - no edge e has zero length + * + * Invariants for the Mesh (the processed portion). + * - the portion of the mesh left of the sweep line is a planar graph, + * ie. there is *some* way to embed it in the plane + * - no processed edge has zero length + * - no two processed vertices have identical coordinates + * - each "inside" region is monotone, ie. can be broken into two chains + * of monotonically increasing vertices according to VertLeq(v1,v2) + * - a non-invariant: these chains may intersect (very slightly) + * + * Invariants for the Sweep. + * - if none of the edges incident to the event vertex have an activeRegion + * (ie. none of these edges are in the edge dictionary), then the vertex + * has only right-going edges. + * - if an edge is marked "fixUpperEdge" (it is a temporary edge introduced + * by ConnectRightVertex), then it is the only right-going edge from + * its associated vertex. (This says that these edges exist only + * when it is necessary.) + */ + +#undef MAX +#undef MIN +#define MAX(x,y) ((x) >= (y) ? (x) : (y)) +#define MIN(x,y) ((x) <= (y) ? (x) : (y)) + +/* When we merge two edges into one, we need to compute the combined + * winding of the new edge. + */ +#define AddWinding(eDst,eSrc) (eDst->winding += eSrc->winding, \ + eDst->Sym->winding += eSrc->Sym->winding) + +static void SweepEvent( GLUtesselator *tess, GLUvertex *vEvent ); +static void WalkDirtyRegions( GLUtesselator *tess, ActiveRegion *regUp ); +static int CheckForRightSplice( GLUtesselator *tess, ActiveRegion *regUp ); + +static int EdgeLeq( GLUtesselator *tess, ActiveRegion *reg1, + ActiveRegion *reg2 ) +/* + * Both edges must be directed from right to left (this is the canonical + * direction for the upper edge of each region). + * + * The strategy is to evaluate a "t" value for each edge at the + * current sweep line position, given by tess->event. The calculations + * are designed to be very stable, but of course they are not perfect. + * + * Special case: if both edge destinations are at the sweep event, + * we sort the edges by slope (they would otherwise compare equally). + */ +{ + GLUvertex *event = tess->event; + GLUhalfEdge *e1, *e2; + GLdouble t1, t2; + + e1 = reg1->eUp; + e2 = reg2->eUp; + + if( e1->Dst == event ) { + if( e2->Dst == event ) { + /* Two edges right of the sweep line which meet at the sweep event. + * Sort them by slope. + */ + if( VertLeq( e1->Org, e2->Org )) { + return EdgeSign( e2->Dst, e1->Org, e2->Org ) <= 0; + } + return EdgeSign( e1->Dst, e2->Org, e1->Org ) >= 0; + } + return EdgeSign( e2->Dst, event, e2->Org ) <= 0; + } + if( e2->Dst == event ) { + return EdgeSign( e1->Dst, event, e1->Org ) >= 0; + } + + /* General case - compute signed distance *from* e1, e2 to event */ + t1 = EdgeEval( e1->Dst, event, e1->Org ); + t2 = EdgeEval( e2->Dst, event, e2->Org ); + return (t1 >= t2); +} + + +static void DeleteRegion( GLUtesselator *tess, ActiveRegion *reg ) +{ + if( reg->fixUpperEdge ) { + /* It was created with zero winding number, so it better be + * deleted with zero winding number (ie. it better not get merged + * with a real edge). + */ + assert( reg->eUp->winding == 0 ); + } + reg->eUp->activeRegion = NULL; + dictDelete( tess->dict, reg->nodeUp ); /* __gl_dictListDelete */ + memFree( reg ); +} + + +static int FixUpperEdge( ActiveRegion *reg, GLUhalfEdge *newEdge ) +/* + * Replace an upper edge which needs fixing (see ConnectRightVertex). + */ +{ + assert( reg->fixUpperEdge ); + if ( !__gl_meshDelete( reg->eUp ) ) return 0; + reg->fixUpperEdge = FALSE; + reg->eUp = newEdge; + newEdge->activeRegion = reg; + + return 1; +} + +static ActiveRegion *TopLeftRegion( ActiveRegion *reg ) +{ + GLUvertex *org = reg->eUp->Org; + GLUhalfEdge *e; + + /* Find the region above the uppermost edge with the same origin */ + do { + reg = RegionAbove( reg ); + } while( reg->eUp->Org == org ); + + /* If the edge above was a temporary edge introduced by ConnectRightVertex, + * now is the time to fix it. + */ + if( reg->fixUpperEdge ) { + e = __gl_meshConnect( RegionBelow(reg)->eUp->Sym, reg->eUp->Lnext ); + if (e == NULL) return NULL; + if ( !FixUpperEdge( reg, e ) ) return NULL; + reg = RegionAbove( reg ); + } + return reg; +} + +static ActiveRegion *TopRightRegion( ActiveRegion *reg ) +{ + GLUvertex *dst = reg->eUp->Dst; + + /* Find the region above the uppermost edge with the same destination */ + do { + reg = RegionAbove( reg ); + } while( reg->eUp->Dst == dst ); + return reg; +} + +static ActiveRegion *AddRegionBelow( GLUtesselator *tess, + ActiveRegion *regAbove, + GLUhalfEdge *eNewUp ) +/* + * Add a new active region to the sweep line, *somewhere* below "regAbove" + * (according to where the new edge belongs in the sweep-line dictionary). + * The upper edge of the new region will be "eNewUp". + * Winding number and "inside" flag are not updated. + */ +{ + ActiveRegion *regNew = (ActiveRegion *)memAlloc( sizeof( ActiveRegion )); + if (regNew == NULL) longjmp(tess->env,1); + + regNew->eUp = eNewUp; + /* __gl_dictListInsertBefore */ + regNew->nodeUp = dictInsertBefore( tess->dict, regAbove->nodeUp, regNew ); + if (regNew->nodeUp == NULL) longjmp(tess->env,1); + regNew->fixUpperEdge = FALSE; + regNew->sentinel = FALSE; + regNew->dirty = FALSE; + + eNewUp->activeRegion = regNew; + return regNew; +} + +static GLboolean IsWindingInside( GLUtesselator *tess, int n ) +{ + switch( tess->windingRule ) { + case GLU_TESS_WINDING_ODD: + return (n & 1); + case GLU_TESS_WINDING_NONZERO: + return (n != 0); + case GLU_TESS_WINDING_POSITIVE: + return (n > 0); + case GLU_TESS_WINDING_NEGATIVE: + return (n < 0); + case GLU_TESS_WINDING_ABS_GEQ_TWO: + return (n >= 2) || (n <= -2); + } + /*LINTED*/ + assert( FALSE ); + /*NOTREACHED*/ + return GL_FALSE; /* avoid compiler complaints */ +} + + +static void ComputeWinding( GLUtesselator *tess, ActiveRegion *reg ) +{ + reg->windingNumber = RegionAbove(reg)->windingNumber + reg->eUp->winding; + reg->inside = IsWindingInside( tess, reg->windingNumber ); +} + + +static void FinishRegion( GLUtesselator *tess, ActiveRegion *reg ) +/* + * Delete a region from the sweep line. This happens when the upper + * and lower chains of a region meet (at a vertex on the sweep line). + * The "inside" flag is copied to the appropriate mesh face (we could + * not do this before -- since the structure of the mesh is always + * changing, this face may not have even existed until now). + */ +{ + GLUhalfEdge *e = reg->eUp; + GLUface *f = e->Lface; + + f->inside = reg->inside; + f->anEdge = e; /* optimization for __gl_meshTessellateMonoRegion() */ + DeleteRegion( tess, reg ); +} + + +static GLUhalfEdge *FinishLeftRegions( GLUtesselator *tess, + ActiveRegion *regFirst, ActiveRegion *regLast ) +/* + * We are given a vertex with one or more left-going edges. All affected + * edges should be in the edge dictionary. Starting at regFirst->eUp, + * we walk down deleting all regions where both edges have the same + * origin vOrg. At the same time we copy the "inside" flag from the + * active region to the face, since at this point each face will belong + * to at most one region (this was not necessarily true until this point + * in the sweep). The walk stops at the region above regLast; if regLast + * is NULL we walk as far as possible. At the same time we relink the + * mesh if necessary, so that the ordering of edges around vOrg is the + * same as in the dictionary. + */ +{ + ActiveRegion *reg, *regPrev; + GLUhalfEdge *e, *ePrev; + + regPrev = regFirst; + ePrev = regFirst->eUp; + while( regPrev != regLast ) { + regPrev->fixUpperEdge = FALSE; /* placement was OK */ + reg = RegionBelow( regPrev ); + e = reg->eUp; + if( e->Org != ePrev->Org ) { + if( ! reg->fixUpperEdge ) { + /* Remove the last left-going edge. Even though there are no further + * edges in the dictionary with this origin, there may be further + * such edges in the mesh (if we are adding left edges to a vertex + * that has already been processed). Thus it is important to call + * FinishRegion rather than just DeleteRegion. + */ + FinishRegion( tess, regPrev ); + break; + } + /* If the edge below was a temporary edge introduced by + * ConnectRightVertex, now is the time to fix it. + */ + e = __gl_meshConnect( ePrev->Lprev, e->Sym ); + if (e == NULL) longjmp(tess->env,1); + if ( !FixUpperEdge( reg, e ) ) longjmp(tess->env,1); + } + + /* Relink edges so that ePrev->Onext == e */ + if( ePrev->Onext != e ) { + if ( !__gl_meshSplice( e->Oprev, e ) ) longjmp(tess->env,1); + if ( !__gl_meshSplice( ePrev, e ) ) longjmp(tess->env,1); + } + FinishRegion( tess, regPrev ); /* may change reg->eUp */ + ePrev = reg->eUp; + regPrev = reg; + } + return ePrev; +} + + +static void AddRightEdges( GLUtesselator *tess, ActiveRegion *regUp, + GLUhalfEdge *eFirst, GLUhalfEdge *eLast, GLUhalfEdge *eTopLeft, + GLboolean cleanUp ) +/* + * Purpose: insert right-going edges into the edge dictionary, and update + * winding numbers and mesh connectivity appropriately. All right-going + * edges share a common origin vOrg. Edges are inserted CCW starting at + * eFirst; the last edge inserted is eLast->Oprev. If vOrg has any + * left-going edges already processed, then eTopLeft must be the edge + * such that an imaginary upward vertical segment from vOrg would be + * contained between eTopLeft->Oprev and eTopLeft; otherwise eTopLeft + * should be NULL. + */ +{ + ActiveRegion *reg, *regPrev; + GLUhalfEdge *e, *ePrev; + int firstTime = TRUE; + + /* Insert the new right-going edges in the dictionary */ + e = eFirst; + do { + assert( VertLeq( e->Org, e->Dst )); + AddRegionBelow( tess, regUp, e->Sym ); + e = e->Onext; + } while ( e != eLast ); + + /* Walk *all* right-going edges from e->Org, in the dictionary order, + * updating the winding numbers of each region, and re-linking the mesh + * edges to match the dictionary ordering (if necessary). + */ + if( eTopLeft == NULL ) { + eTopLeft = RegionBelow( regUp )->eUp->Rprev; + } + regPrev = regUp; + ePrev = eTopLeft; + for( ;; ) { + reg = RegionBelow( regPrev ); + e = reg->eUp->Sym; + if( e->Org != ePrev->Org ) break; + + if( e->Onext != ePrev ) { + /* Unlink e from its current position, and relink below ePrev */ + if ( !__gl_meshSplice( e->Oprev, e ) ) longjmp(tess->env,1); + if ( !__gl_meshSplice( ePrev->Oprev, e ) ) longjmp(tess->env,1); + } + /* Compute the winding number and "inside" flag for the new regions */ + reg->windingNumber = regPrev->windingNumber - e->winding; + reg->inside = IsWindingInside( tess, reg->windingNumber ); + + /* Check for two outgoing edges with same slope -- process these + * before any intersection tests (see example in __gl_computeInterior). + */ + regPrev->dirty = TRUE; + if( ! firstTime && CheckForRightSplice( tess, regPrev )) { + AddWinding( e, ePrev ); + DeleteRegion( tess, regPrev ); + if ( !__gl_meshDelete( ePrev ) ) longjmp(tess->env,1); + } + firstTime = FALSE; + regPrev = reg; + ePrev = e; + } + regPrev->dirty = TRUE; + assert( regPrev->windingNumber - e->winding == reg->windingNumber ); + + if( cleanUp ) { + /* Check for intersections between newly adjacent edges. */ + WalkDirtyRegions( tess, regPrev ); + } +} + + +static void CallCombine( GLUtesselator *tess, GLUvertex *isect, + void *data[4], GLfloat weights[4], int needed ) +{ + GLdouble coords[3]; + + /* Copy coord data in case the callback changes it. */ + coords[0] = isect->coords[0]; + coords[1] = isect->coords[1]; + coords[2] = isect->coords[2]; + + isect->data = NULL; + CALL_COMBINE_OR_COMBINE_DATA( coords, data, weights, &isect->data ); + if( isect->data == NULL ) { + if( ! needed ) { + isect->data = data[0]; + } else if( ! tess->fatalError ) { + /* The only way fatal error is when two edges are found to intersect, + * but the user has not provided the callback necessary to handle + * generated intersection points. + */ + CALL_ERROR_OR_ERROR_DATA( GLU_TESS_NEED_COMBINE_CALLBACK ); + tess->fatalError = TRUE; + } + } +} + +static void SpliceMergeVertices( GLUtesselator *tess, GLUhalfEdge *e1, + GLUhalfEdge *e2 ) +/* + * Two vertices with idential coordinates are combined into one. + * e1->Org is kept, while e2->Org is discarded. + */ +{ + void *data[4] = { NULL, NULL, NULL, NULL }; + GLfloat weights[4] = { 0.5, 0.5, 0.0, 0.0 }; + + data[0] = e1->Org->data; + data[1] = e2->Org->data; + CallCombine( tess, e1->Org, data, weights, FALSE ); + if ( !__gl_meshSplice( e1, e2 ) ) longjmp(tess->env,1); +} + +static void VertexWeights( GLUvertex *isect, GLUvertex *org, GLUvertex *dst, + GLfloat *weights ) +/* + * Find some weights which describe how the intersection vertex is + * a linear combination of "org" and "dest". Each of the two edges + * which generated "isect" is allocated 50% of the weight; each edge + * splits the weight between its org and dst according to the + * relative distance to "isect". + */ +{ + GLdouble t1 = VertL1dist( org, isect ); + GLdouble t2 = VertL1dist( dst, isect ); + + weights[0] = 0.5 * t2 / (t1 + t2); + weights[1] = 0.5 * t1 / (t1 + t2); + isect->coords[0] += weights[0]*org->coords[0] + weights[1]*dst->coords[0]; + isect->coords[1] += weights[0]*org->coords[1] + weights[1]*dst->coords[1]; + isect->coords[2] += weights[0]*org->coords[2] + weights[1]*dst->coords[2]; +} + + +static void GetIntersectData( GLUtesselator *tess, GLUvertex *isect, + GLUvertex *orgUp, GLUvertex *dstUp, + GLUvertex *orgLo, GLUvertex *dstLo ) +/* + * We've computed a new intersection point, now we need a "data" pointer + * from the user so that we can refer to this new vertex in the + * rendering callbacks. + */ +{ + void *data[4]; + GLfloat weights[4]; + + data[0] = orgUp->data; + data[1] = dstUp->data; + data[2] = orgLo->data; + data[3] = dstLo->data; + + isect->coords[0] = isect->coords[1] = isect->coords[2] = 0; + VertexWeights( isect, orgUp, dstUp, &weights[0] ); + VertexWeights( isect, orgLo, dstLo, &weights[2] ); + + CallCombine( tess, isect, data, weights, TRUE ); +} + +static int CheckForRightSplice( GLUtesselator *tess, ActiveRegion *regUp ) +/* + * Check the upper and lower edge of "regUp", to make sure that the + * eUp->Org is above eLo, or eLo->Org is below eUp (depending on which + * origin is leftmost). + * + * The main purpose is to splice right-going edges with the same + * dest vertex and nearly identical slopes (ie. we can't distinguish + * the slopes numerically). However the splicing can also help us + * to recover from numerical errors. For example, suppose at one + * point we checked eUp and eLo, and decided that eUp->Org is barely + * above eLo. Then later, we split eLo into two edges (eg. from + * a splice operation like this one). This can change the result of + * our test so that now eUp->Org is incident to eLo, or barely below it. + * We must correct this condition to maintain the dictionary invariants. + * + * One possibility is to check these edges for intersection again + * (ie. CheckForIntersect). This is what we do if possible. However + * CheckForIntersect requires that tess->event lies between eUp and eLo, + * so that it has something to fall back on when the intersection + * calculation gives us an unusable answer. So, for those cases where + * we can't check for intersection, this routine fixes the problem + * by just splicing the offending vertex into the other edge. + * This is a guaranteed solution, no matter how degenerate things get. + * Basically this is a combinatorial solution to a numerical problem. + */ +{ + ActiveRegion *regLo = RegionBelow(regUp); + GLUhalfEdge *eUp = regUp->eUp; + GLUhalfEdge *eLo = regLo->eUp; + + if( VertLeq( eUp->Org, eLo->Org )) { + if( EdgeSign( eLo->Dst, eUp->Org, eLo->Org ) > 0 ) return FALSE; + + /* eUp->Org appears to be below eLo */ + if( ! VertEq( eUp->Org, eLo->Org )) { + /* Splice eUp->Org into eLo */ + if ( __gl_meshSplitEdge( eLo->Sym ) == NULL) longjmp(tess->env,1); + if ( !__gl_meshSplice( eUp, eLo->Oprev ) ) longjmp(tess->env,1); + regUp->dirty = regLo->dirty = TRUE; + + } else if( eUp->Org != eLo->Org ) { + /* merge the two vertices, discarding eUp->Org */ + pqDelete( tess->pq, eUp->Org->pqHandle ); /* __gl_pqSortDelete */ + SpliceMergeVertices( tess, eLo->Oprev, eUp ); + } + } else { + if( EdgeSign( eUp->Dst, eLo->Org, eUp->Org ) < 0 ) return FALSE; + + /* eLo->Org appears to be above eUp, so splice eLo->Org into eUp */ + RegionAbove(regUp)->dirty = regUp->dirty = TRUE; + if (__gl_meshSplitEdge( eUp->Sym ) == NULL) longjmp(tess->env,1); + if ( !__gl_meshSplice( eLo->Oprev, eUp ) ) longjmp(tess->env,1); + } + return TRUE; +} + +static int CheckForLeftSplice( GLUtesselator *tess, ActiveRegion *regUp ) +/* + * Check the upper and lower edge of "regUp", to make sure that the + * eUp->Dst is above eLo, or eLo->Dst is below eUp (depending on which + * destination is rightmost). + * + * Theoretically, this should always be true. However, splitting an edge + * into two pieces can change the results of previous tests. For example, + * suppose at one point we checked eUp and eLo, and decided that eUp->Dst + * is barely above eLo. Then later, we split eLo into two edges (eg. from + * a splice operation like this one). This can change the result of + * the test so that now eUp->Dst is incident to eLo, or barely below it. + * We must correct this condition to maintain the dictionary invariants + * (otherwise new edges might get inserted in the wrong place in the + * dictionary, and bad stuff will happen). + * + * We fix the problem by just splicing the offending vertex into the + * other edge. + */ +{ + ActiveRegion *regLo = RegionBelow(regUp); + GLUhalfEdge *eUp = regUp->eUp; + GLUhalfEdge *eLo = regLo->eUp; + GLUhalfEdge *e; + + assert( ! VertEq( eUp->Dst, eLo->Dst )); + + if( VertLeq( eUp->Dst, eLo->Dst )) { + if( EdgeSign( eUp->Dst, eLo->Dst, eUp->Org ) < 0 ) return FALSE; + + /* eLo->Dst is above eUp, so splice eLo->Dst into eUp */ + RegionAbove(regUp)->dirty = regUp->dirty = TRUE; + e = __gl_meshSplitEdge( eUp ); + if (e == NULL) longjmp(tess->env,1); + if ( !__gl_meshSplice( eLo->Sym, e ) ) longjmp(tess->env,1); + e->Lface->inside = regUp->inside; + } else { + if( EdgeSign( eLo->Dst, eUp->Dst, eLo->Org ) > 0 ) return FALSE; + + /* eUp->Dst is below eLo, so splice eUp->Dst into eLo */ + regUp->dirty = regLo->dirty = TRUE; + e = __gl_meshSplitEdge( eLo ); + if (e == NULL) longjmp(tess->env,1); + if ( !__gl_meshSplice( eUp->Lnext, eLo->Sym ) ) longjmp(tess->env,1); + e->Rface->inside = regUp->inside; + } + return TRUE; +} + + +static int CheckForIntersect( GLUtesselator *tess, ActiveRegion *regUp ) +/* + * Check the upper and lower edges of the given region to see if + * they intersect. If so, create the intersection and add it + * to the data structures. + * + * Returns TRUE if adding the new intersection resulted in a recursive + * call to AddRightEdges(); in this case all "dirty" regions have been + * checked for intersections, and possibly regUp has been deleted. + */ +{ + ActiveRegion *regLo = RegionBelow(regUp); + GLUhalfEdge *eUp = regUp->eUp; + GLUhalfEdge *eLo = regLo->eUp; + GLUvertex *orgUp = eUp->Org; + GLUvertex *orgLo = eLo->Org; + GLUvertex *dstUp = eUp->Dst; + GLUvertex *dstLo = eLo->Dst; + GLdouble tMinUp, tMaxLo; + GLUvertex isect, *orgMin; + GLUhalfEdge *e; + + assert( ! VertEq( dstLo, dstUp )); + assert( EdgeSign( dstUp, tess->event, orgUp ) <= 0 ); + assert( EdgeSign( dstLo, tess->event, orgLo ) >= 0 ); + assert( orgUp != tess->event && orgLo != tess->event ); + assert( ! regUp->fixUpperEdge && ! regLo->fixUpperEdge ); + + if( orgUp == orgLo ) return FALSE; /* right endpoints are the same */ + + tMinUp = MIN( orgUp->t, dstUp->t ); + tMaxLo = MAX( orgLo->t, dstLo->t ); + if( tMinUp > tMaxLo ) return FALSE; /* t ranges do not overlap */ + + if( VertLeq( orgUp, orgLo )) { + if( EdgeSign( dstLo, orgUp, orgLo ) > 0 ) return FALSE; + } else { + if( EdgeSign( dstUp, orgLo, orgUp ) < 0 ) return FALSE; + } + + /* At this point the edges intersect, at least marginally */ + DebugEvent( tess ); + + __gl_edgeIntersect( dstUp, orgUp, dstLo, orgLo, &isect ); + /* The following properties are guaranteed: */ + assert( MIN( orgUp->t, dstUp->t ) <= isect.t ); + assert( isect.t <= MAX( orgLo->t, dstLo->t )); + assert( MIN( dstLo->s, dstUp->s ) <= isect.s ); + assert( isect.s <= MAX( orgLo->s, orgUp->s )); + + if( VertLeq( &isect, tess->event )) { + /* The intersection point lies slightly to the left of the sweep line, + * so move it until it''s slightly to the right of the sweep line. + * (If we had perfect numerical precision, this would never happen + * in the first place). The easiest and safest thing to do is + * replace the intersection by tess->event. + */ + isect.s = tess->event->s; + isect.t = tess->event->t; + } + /* Similarly, if the computed intersection lies to the right of the + * rightmost origin (which should rarely happen), it can cause + * unbelievable inefficiency on sufficiently degenerate inputs. + * (If you have the test program, try running test54.d with the + * "X zoom" option turned on). + */ + orgMin = VertLeq( orgUp, orgLo ) ? orgUp : orgLo; + if( VertLeq( orgMin, &isect )) { + isect.s = orgMin->s; + isect.t = orgMin->t; + } + + if( VertEq( &isect, orgUp ) || VertEq( &isect, orgLo )) { + /* Easy case -- intersection at one of the right endpoints */ + (void) CheckForRightSplice( tess, regUp ); + return FALSE; + } + + if( (! VertEq( dstUp, tess->event ) + && EdgeSign( dstUp, tess->event, &isect ) >= 0) + || (! VertEq( dstLo, tess->event ) + && EdgeSign( dstLo, tess->event, &isect ) <= 0 )) + { + /* Very unusual -- the new upper or lower edge would pass on the + * wrong side of the sweep event, or through it. This can happen + * due to very small numerical errors in the intersection calculation. + */ + if( dstLo == tess->event ) { + /* Splice dstLo into eUp, and process the new region(s) */ + if (__gl_meshSplitEdge( eUp->Sym ) == NULL) longjmp(tess->env,1); + if ( !__gl_meshSplice( eLo->Sym, eUp ) ) longjmp(tess->env,1); + regUp = TopLeftRegion( regUp ); + if (regUp == NULL) longjmp(tess->env,1); + eUp = RegionBelow(regUp)->eUp; + FinishLeftRegions( tess, RegionBelow(regUp), regLo ); + AddRightEdges( tess, regUp, eUp->Oprev, eUp, eUp, TRUE ); + return TRUE; + } + if( dstUp == tess->event ) { + /* Splice dstUp into eLo, and process the new region(s) */ + if (__gl_meshSplitEdge( eLo->Sym ) == NULL) longjmp(tess->env,1); + if ( !__gl_meshSplice( eUp->Lnext, eLo->Oprev ) ) longjmp(tess->env,1); + regLo = regUp; + regUp = TopRightRegion( regUp ); + e = RegionBelow(regUp)->eUp->Rprev; + regLo->eUp = eLo->Oprev; + eLo = FinishLeftRegions( tess, regLo, NULL ); + AddRightEdges( tess, regUp, eLo->Onext, eUp->Rprev, e, TRUE ); + return TRUE; + } + /* Special case: called from ConnectRightVertex. If either + * edge passes on the wrong side of tess->event, split it + * (and wait for ConnectRightVertex to splice it appropriately). + */ + if( EdgeSign( dstUp, tess->event, &isect ) >= 0 ) { + RegionAbove(regUp)->dirty = regUp->dirty = TRUE; + if (__gl_meshSplitEdge( eUp->Sym ) == NULL) longjmp(tess->env,1); + eUp->Org->s = tess->event->s; + eUp->Org->t = tess->event->t; + } + if( EdgeSign( dstLo, tess->event, &isect ) <= 0 ) { + regUp->dirty = regLo->dirty = TRUE; + if (__gl_meshSplitEdge( eLo->Sym ) == NULL) longjmp(tess->env,1); + eLo->Org->s = tess->event->s; + eLo->Org->t = tess->event->t; + } + /* leave the rest for ConnectRightVertex */ + return FALSE; + } + + /* General case -- split both edges, splice into new vertex. + * When we do the splice operation, the order of the arguments is + * arbitrary as far as correctness goes. However, when the operation + * creates a new face, the work done is proportional to the size of + * the new face. We expect the faces in the processed part of + * the mesh (ie. eUp->Lface) to be smaller than the faces in the + * unprocessed original contours (which will be eLo->Oprev->Lface). + */ + if (__gl_meshSplitEdge( eUp->Sym ) == NULL) longjmp(tess->env,1); + if (__gl_meshSplitEdge( eLo->Sym ) == NULL) longjmp(tess->env,1); + if ( !__gl_meshSplice( eLo->Oprev, eUp ) ) longjmp(tess->env,1); + eUp->Org->s = isect.s; + eUp->Org->t = isect.t; + eUp->Org->pqHandle = pqInsert( tess->pq, eUp->Org ); /* __gl_pqSortInsert */ + if (eUp->Org->pqHandle == LONG_MAX) { + pqDeletePriorityQ(tess->pq); /* __gl_pqSortDeletePriorityQ */ + tess->pq = NULL; + longjmp(tess->env,1); + } + GetIntersectData( tess, eUp->Org, orgUp, dstUp, orgLo, dstLo ); + RegionAbove(regUp)->dirty = regUp->dirty = regLo->dirty = TRUE; + return FALSE; +} + +static void WalkDirtyRegions( GLUtesselator *tess, ActiveRegion *regUp ) +/* + * When the upper or lower edge of any region changes, the region is + * marked "dirty". This routine walks through all the dirty regions + * and makes sure that the dictionary invariants are satisfied + * (see the comments at the beginning of this file). Of course + * new dirty regions can be created as we make changes to restore + * the invariants. + */ +{ + ActiveRegion *regLo = RegionBelow(regUp); + GLUhalfEdge *eUp, *eLo; + + for( ;; ) { + /* Find the lowest dirty region (we walk from the bottom up). */ + while( regLo->dirty ) { + regUp = regLo; + regLo = RegionBelow(regLo); + } + if( ! regUp->dirty ) { + regLo = regUp; + regUp = RegionAbove( regUp ); + if( regUp == NULL || ! regUp->dirty ) { + /* We've walked all the dirty regions */ + return; + } + } + regUp->dirty = FALSE; + eUp = regUp->eUp; + eLo = regLo->eUp; + + if( eUp->Dst != eLo->Dst ) { + /* Check that the edge ordering is obeyed at the Dst vertices. */ + if( CheckForLeftSplice( tess, regUp )) { + + /* If the upper or lower edge was marked fixUpperEdge, then + * we no longer need it (since these edges are needed only for + * vertices which otherwise have no right-going edges). + */ + if( regLo->fixUpperEdge ) { + DeleteRegion( tess, regLo ); + if ( !__gl_meshDelete( eLo ) ) longjmp(tess->env,1); + regLo = RegionBelow( regUp ); + eLo = regLo->eUp; + } else if( regUp->fixUpperEdge ) { + DeleteRegion( tess, regUp ); + if ( !__gl_meshDelete( eUp ) ) longjmp(tess->env,1); + regUp = RegionAbove( regLo ); + eUp = regUp->eUp; + } + } + } + if( eUp->Org != eLo->Org ) { + if( eUp->Dst != eLo->Dst + && ! regUp->fixUpperEdge && ! regLo->fixUpperEdge + && (eUp->Dst == tess->event || eLo->Dst == tess->event) ) + { + /* When all else fails in CheckForIntersect(), it uses tess->event + * as the intersection location. To make this possible, it requires + * that tess->event lie between the upper and lower edges, and also + * that neither of these is marked fixUpperEdge (since in the worst + * case it might splice one of these edges into tess->event, and + * violate the invariant that fixable edges are the only right-going + * edge from their associated vertex). + */ + if( CheckForIntersect( tess, regUp )) { + /* WalkDirtyRegions() was called recursively; we're done */ + return; + } + } else { + /* Even though we can't use CheckForIntersect(), the Org vertices + * may violate the dictionary edge ordering. Check and correct this. + */ + (void) CheckForRightSplice( tess, regUp ); + } + } + if( eUp->Org == eLo->Org && eUp->Dst == eLo->Dst ) { + /* A degenerate loop consisting of only two edges -- delete it. */ + AddWinding( eLo, eUp ); + DeleteRegion( tess, regUp ); + if ( !__gl_meshDelete( eUp ) ) longjmp(tess->env,1); + regUp = RegionAbove( regLo ); + } + } +} + + +static void ConnectRightVertex( GLUtesselator *tess, ActiveRegion *regUp, + GLUhalfEdge *eBottomLeft ) +/* + * Purpose: connect a "right" vertex vEvent (one where all edges go left) + * to the unprocessed portion of the mesh. Since there are no right-going + * edges, two regions (one above vEvent and one below) are being merged + * into one. "regUp" is the upper of these two regions. + * + * There are two reasons for doing this (adding a right-going edge): + * - if the two regions being merged are "inside", we must add an edge + * to keep them separated (the combined region would not be monotone). + * - in any case, we must leave some record of vEvent in the dictionary, + * so that we can merge vEvent with features that we have not seen yet. + * For example, maybe there is a vertical edge which passes just to + * the right of vEvent; we would like to splice vEvent into this edge. + * + * However, we don't want to connect vEvent to just any vertex. We don''t + * want the new edge to cross any other edges; otherwise we will create + * intersection vertices even when the input data had no self-intersections. + * (This is a bad thing; if the user's input data has no intersections, + * we don't want to generate any false intersections ourselves.) + * + * Our eventual goal is to connect vEvent to the leftmost unprocessed + * vertex of the combined region (the union of regUp and regLo). + * But because of unseen vertices with all right-going edges, and also + * new vertices which may be created by edge intersections, we don''t + * know where that leftmost unprocessed vertex is. In the meantime, we + * connect vEvent to the closest vertex of either chain, and mark the region + * as "fixUpperEdge". This flag says to delete and reconnect this edge + * to the next processed vertex on the boundary of the combined region. + * Quite possibly the vertex we connected to will turn out to be the + * closest one, in which case we won''t need to make any changes. + */ +{ + GLUhalfEdge *eNew; + GLUhalfEdge *eTopLeft = eBottomLeft->Onext; + ActiveRegion *regLo = RegionBelow(regUp); + GLUhalfEdge *eUp = regUp->eUp; + GLUhalfEdge *eLo = regLo->eUp; + int degenerate = FALSE; + + if( eUp->Dst != eLo->Dst ) { + (void) CheckForIntersect( tess, regUp ); + } + + /* Possible new degeneracies: upper or lower edge of regUp may pass + * through vEvent, or may coincide with new intersection vertex + */ + if( VertEq( eUp->Org, tess->event )) { + if ( !__gl_meshSplice( eTopLeft->Oprev, eUp ) ) longjmp(tess->env,1); + regUp = TopLeftRegion( regUp ); + if (regUp == NULL) longjmp(tess->env,1); + eTopLeft = RegionBelow( regUp )->eUp; + FinishLeftRegions( tess, RegionBelow(regUp), regLo ); + degenerate = TRUE; + } + if( VertEq( eLo->Org, tess->event )) { + if ( !__gl_meshSplice( eBottomLeft, eLo->Oprev ) ) longjmp(tess->env,1); + eBottomLeft = FinishLeftRegions( tess, regLo, NULL ); + degenerate = TRUE; + } + if( degenerate ) { + AddRightEdges( tess, regUp, eBottomLeft->Onext, eTopLeft, eTopLeft, TRUE ); + return; + } + + /* Non-degenerate situation -- need to add a temporary, fixable edge. + * Connect to the closer of eLo->Org, eUp->Org. + */ + if( VertLeq( eLo->Org, eUp->Org )) { + eNew = eLo->Oprev; + } else { + eNew = eUp; + } + eNew = __gl_meshConnect( eBottomLeft->Lprev, eNew ); + if (eNew == NULL) longjmp(tess->env,1); + + /* Prevent cleanup, otherwise eNew might disappear before we've even + * had a chance to mark it as a temporary edge. + */ + AddRightEdges( tess, regUp, eNew, eNew->Onext, eNew->Onext, FALSE ); + eNew->Sym->activeRegion->fixUpperEdge = TRUE; + WalkDirtyRegions( tess, regUp ); +} + +/* Because vertices at exactly the same location are merged together + * before we process the sweep event, some degenerate cases can't occur. + * However if someone eventually makes the modifications required to + * merge features which are close together, the cases below marked + * TOLERANCE_NONZERO will be useful. They were debugged before the + * code to merge identical vertices in the main loop was added. + */ +#define TOLERANCE_NONZERO FALSE + +static void ConnectLeftDegenerate( GLUtesselator *tess, + ActiveRegion *regUp, GLUvertex *vEvent ) +/* + * The event vertex lies exacty on an already-processed edge or vertex. + * Adding the new vertex involves splicing it into the already-processed + * part of the mesh. + */ +{ + GLUhalfEdge *e, *eTopLeft, *eTopRight, *eLast; + ActiveRegion *reg; + + e = regUp->eUp; + if( VertEq( e->Org, vEvent )) { + /* e->Org is an unprocessed vertex - just combine them, and wait + * for e->Org to be pulled from the queue + */ + assert( TOLERANCE_NONZERO ); + SpliceMergeVertices( tess, e, vEvent->anEdge ); + return; + } + + if( ! VertEq( e->Dst, vEvent )) { + /* General case -- splice vEvent into edge e which passes through it */ + if (__gl_meshSplitEdge( e->Sym ) == NULL) longjmp(tess->env,1); + if( regUp->fixUpperEdge ) { + /* This edge was fixable -- delete unused portion of original edge */ + if ( !__gl_meshDelete( e->Onext ) ) longjmp(tess->env,1); + regUp->fixUpperEdge = FALSE; + } + if ( !__gl_meshSplice( vEvent->anEdge, e ) ) longjmp(tess->env,1); + SweepEvent( tess, vEvent ); /* recurse */ + return; + } + + /* vEvent coincides with e->Dst, which has already been processed. + * Splice in the additional right-going edges. + */ + assert( TOLERANCE_NONZERO ); + regUp = TopRightRegion( regUp ); + reg = RegionBelow( regUp ); + eTopRight = reg->eUp->Sym; + eTopLeft = eLast = eTopRight->Onext; + if( reg->fixUpperEdge ) { + /* Here e->Dst has only a single fixable edge going right. + * We can delete it since now we have some real right-going edges. + */ + assert( eTopLeft != eTopRight ); /* there are some left edges too */ + DeleteRegion( tess, reg ); + if ( !__gl_meshDelete( eTopRight ) ) longjmp(tess->env,1); + eTopRight = eTopLeft->Oprev; + } + if ( !__gl_meshSplice( vEvent->anEdge, eTopRight ) ) longjmp(tess->env,1); + if( ! EdgeGoesLeft( eTopLeft )) { + /* e->Dst had no left-going edges -- indicate this to AddRightEdges() */ + eTopLeft = NULL; + } + AddRightEdges( tess, regUp, eTopRight->Onext, eLast, eTopLeft, TRUE ); +} + + +static void ConnectLeftVertex( GLUtesselator *tess, GLUvertex *vEvent ) +/* + * Purpose: connect a "left" vertex (one where both edges go right) + * to the processed portion of the mesh. Let R be the active region + * containing vEvent, and let U and L be the upper and lower edge + * chains of R. There are two possibilities: + * + * - the normal case: split R into two regions, by connecting vEvent to + * the rightmost vertex of U or L lying to the left of the sweep line + * + * - the degenerate case: if vEvent is close enough to U or L, we + * merge vEvent into that edge chain. The subcases are: + * - merging with the rightmost vertex of U or L + * - merging with the active edge of U or L + * - merging with an already-processed portion of U or L + */ +{ + ActiveRegion *regUp, *regLo, *reg; + GLUhalfEdge *eUp, *eLo, *eNew; + ActiveRegion tmp; + + /* assert( vEvent->anEdge->Onext->Onext == vEvent->anEdge ); */ + + /* Get a pointer to the active region containing vEvent */ + tmp.eUp = vEvent->anEdge->Sym; + /* __GL_DICTLISTKEY */ /* __gl_dictListSearch */ + regUp = (ActiveRegion *)dictKey( dictSearch( tess->dict, &tmp )); + regLo = RegionBelow( regUp ); + eUp = regUp->eUp; + eLo = regLo->eUp; + + /* Try merging with U or L first */ + if( EdgeSign( eUp->Dst, vEvent, eUp->Org ) == 0 ) { + ConnectLeftDegenerate( tess, regUp, vEvent ); + return; + } + + /* Connect vEvent to rightmost processed vertex of either chain. + * e->Dst is the vertex that we will connect to vEvent. + */ + reg = VertLeq( eLo->Dst, eUp->Dst ) ? regUp : regLo; + + if( regUp->inside || reg->fixUpperEdge) { + if( reg == regUp ) { + eNew = __gl_meshConnect( vEvent->anEdge->Sym, eUp->Lnext ); + if (eNew == NULL) longjmp(tess->env,1); + } else { + GLUhalfEdge *tempHalfEdge= __gl_meshConnect( eLo->Dnext, vEvent->anEdge); + if (tempHalfEdge == NULL) longjmp(tess->env,1); + + eNew = tempHalfEdge->Sym; + } + if( reg->fixUpperEdge ) { + if ( !FixUpperEdge( reg, eNew ) ) longjmp(tess->env,1); + } else { + ComputeWinding( tess, AddRegionBelow( tess, regUp, eNew )); + } + SweepEvent( tess, vEvent ); + } else { + /* The new vertex is in a region which does not belong to the polygon. + * We don''t need to connect this vertex to the rest of the mesh. + */ + AddRightEdges( tess, regUp, vEvent->anEdge, vEvent->anEdge, NULL, TRUE ); + } +} + + +static void SweepEvent( GLUtesselator *tess, GLUvertex *vEvent ) +/* + * Does everything necessary when the sweep line crosses a vertex. + * Updates the mesh and the edge dictionary. + */ +{ + ActiveRegion *regUp, *reg; + GLUhalfEdge *e, *eTopLeft, *eBottomLeft; + + tess->event = vEvent; /* for access in EdgeLeq() */ + DebugEvent( tess ); + + /* Check if this vertex is the right endpoint of an edge that is + * already in the dictionary. In this case we don't need to waste + * time searching for the location to insert new edges. + */ + e = vEvent->anEdge; + while( e->activeRegion == NULL ) { + e = e->Onext; + if( e == vEvent->anEdge ) { + /* All edges go right -- not incident to any processed edges */ + ConnectLeftVertex( tess, vEvent ); + return; + } + } + + /* Processing consists of two phases: first we "finish" all the + * active regions where both the upper and lower edges terminate + * at vEvent (ie. vEvent is closing off these regions). + * We mark these faces "inside" or "outside" the polygon according + * to their winding number, and delete the edges from the dictionary. + * This takes care of all the left-going edges from vEvent. + */ + regUp = TopLeftRegion( e->activeRegion ); + if (regUp == NULL) longjmp(tess->env,1); + reg = RegionBelow( regUp ); + eTopLeft = reg->eUp; + eBottomLeft = FinishLeftRegions( tess, reg, NULL ); + + /* Next we process all the right-going edges from vEvent. This + * involves adding the edges to the dictionary, and creating the + * associated "active regions" which record information about the + * regions between adjacent dictionary edges. + */ + if( eBottomLeft->Onext == eTopLeft ) { + /* No right-going edges -- add a temporary "fixable" edge */ + ConnectRightVertex( tess, regUp, eBottomLeft ); + } else { + AddRightEdges( tess, regUp, eBottomLeft->Onext, eTopLeft, eTopLeft, TRUE ); + } +} + + +/* Make the sentinel coordinates big enough that they will never be + * merged with real input features. (Even with the largest possible + * input contour and the maximum tolerance of 1.0, no merging will be + * done with coordinates larger than 3 * GLU_TESS_MAX_COORD). + */ +#define SENTINEL_COORD (4 * GLU_TESS_MAX_COORD) + +static void AddSentinel( GLUtesselator *tess, GLdouble t ) +/* + * We add two sentinel edges above and below all other edges, + * to avoid special cases at the top and bottom. + */ +{ + GLUhalfEdge *e; + ActiveRegion *reg = (ActiveRegion *)memAlloc( sizeof( ActiveRegion )); + if (reg == NULL) longjmp(tess->env,1); + + e = __gl_meshMakeEdge( tess->mesh ); + if (e == NULL) longjmp(tess->env,1); + + e->Org->s = SENTINEL_COORD; + e->Org->t = t; + e->Dst->s = -SENTINEL_COORD; + e->Dst->t = t; + tess->event = e->Dst; /* initialize it */ + + reg->eUp = e; + reg->windingNumber = 0; + reg->inside = FALSE; + reg->fixUpperEdge = FALSE; + reg->sentinel = TRUE; + reg->dirty = FALSE; + reg->nodeUp = dictInsert( tess->dict, reg ); /* __gl_dictListInsertBefore */ + if (reg->nodeUp == NULL) longjmp(tess->env,1); +} + + +static void InitEdgeDict( GLUtesselator *tess ) +/* + * We maintain an ordering of edge intersections with the sweep line. + * This order is maintained in a dynamic dictionary. + */ +{ + /* __gl_dictListNewDict */ + tess->dict = dictNewDict( tess, (int (*)(void *, DictKey, DictKey)) EdgeLeq ); + if (tess->dict == NULL) longjmp(tess->env,1); + + AddSentinel( tess, -SENTINEL_COORD ); + AddSentinel( tess, SENTINEL_COORD ); +} + + +static void DoneEdgeDict( GLUtesselator *tess ) +{ + ActiveRegion *reg; +#ifndef NDEBUG + int fixedEdges = 0; +#endif + + /* __GL_DICTLISTKEY */ /* __GL_DICTLISTMIN */ + while( (reg = (ActiveRegion *)dictKey( dictMin( tess->dict ))) != NULL ) { + /* + * At the end of all processing, the dictionary should contain + * only the two sentinel edges, plus at most one "fixable" edge + * created by ConnectRightVertex(). + */ + if( ! reg->sentinel ) { + assert( reg->fixUpperEdge ); + assert( ++fixedEdges == 1 ); + } + assert( reg->windingNumber == 0 ); + DeleteRegion( tess, reg ); +/* __gl_meshDelete( reg->eUp );*/ + } + dictDeleteDict( tess->dict ); /* __gl_dictListDeleteDict */ +} + + +static void RemoveDegenerateEdges( GLUtesselator *tess ) +/* + * Remove zero-length edges, and contours with fewer than 3 vertices. + */ +{ + GLUhalfEdge *e, *eNext, *eLnext; + GLUhalfEdge *eHead = &tess->mesh->eHead; + + /*LINTED*/ + for( e = eHead->next; e != eHead; e = eNext ) { + eNext = e->next; + eLnext = e->Lnext; + + if( VertEq( e->Org, e->Dst ) && e->Lnext->Lnext != e ) { + /* Zero-length edge, contour has at least 3 edges */ + + SpliceMergeVertices( tess, eLnext, e ); /* deletes e->Org */ + if ( !__gl_meshDelete( e ) ) longjmp(tess->env,1); /* e is a self-loop */ + e = eLnext; + eLnext = e->Lnext; + } + if( eLnext->Lnext == e ) { + /* Degenerate contour (one or two edges) */ + + if( eLnext != e ) { + if( eLnext == eNext || eLnext == eNext->Sym ) { eNext = eNext->next; } + if ( !__gl_meshDelete( eLnext ) ) longjmp(tess->env,1); + } + if( e == eNext || e == eNext->Sym ) { eNext = eNext->next; } + if ( !__gl_meshDelete( e ) ) longjmp(tess->env,1); + } + } +} + +static int InitPriorityQ( GLUtesselator *tess ) +/* + * Insert all vertices into the priority queue which determines the + * order in which vertices cross the sweep line. + */ +{ + PriorityQ *pq; + GLUvertex *v, *vHead; + + /* __gl_pqSortNewPriorityQ */ + pq = tess->pq = pqNewPriorityQ( (int (*)(PQkey, PQkey)) __gl_vertLeq ); + if (pq == NULL) return 0; + + vHead = &tess->mesh->vHead; + for( v = vHead->next; v != vHead; v = v->next ) { + v->pqHandle = pqInsert( pq, v ); /* __gl_pqSortInsert */ + if (v->pqHandle == LONG_MAX) break; + } + if (v != vHead || !pqInit( pq ) ) { /* __gl_pqSortInit */ + pqDeletePriorityQ(tess->pq); /* __gl_pqSortDeletePriorityQ */ + tess->pq = NULL; + return 0; + } + + return 1; +} + + +static void DonePriorityQ( GLUtesselator *tess ) +{ + pqDeletePriorityQ( tess->pq ); /* __gl_pqSortDeletePriorityQ */ +} + + +static int RemoveDegenerateFaces( GLUmesh *mesh ) +/* + * Delete any degenerate faces with only two edges. WalkDirtyRegions() + * will catch almost all of these, but it won't catch degenerate faces + * produced by splice operations on already-processed edges. + * The two places this can happen are in FinishLeftRegions(), when + * we splice in a "temporary" edge produced by ConnectRightVertex(), + * and in CheckForLeftSplice(), where we splice already-processed + * edges to ensure that our dictionary invariants are not violated + * by numerical errors. + * + * In both these cases it is *very* dangerous to delete the offending + * edge at the time, since one of the routines further up the stack + * will sometimes be keeping a pointer to that edge. + */ +{ + GLUface *f, *fNext; + GLUhalfEdge *e; + + /*LINTED*/ + for( f = mesh->fHead.next; f != &mesh->fHead; f = fNext ) { + fNext = f->next; + e = f->anEdge; + assert( e->Lnext != e ); + + if( e->Lnext->Lnext == e ) { + /* A face with only two edges */ + AddWinding( e->Onext, e ); + if ( !__gl_meshDelete( e ) ) return 0; + } + } + return 1; +} + +int __gl_computeInterior( GLUtesselator *tess ) +/* + * __gl_computeInterior( tess ) computes the planar arrangement specified + * by the given contours, and further subdivides this arrangement + * into regions. Each region is marked "inside" if it belongs + * to the polygon, according to the rule given by tess->windingRule. + * Each interior region is guaranteed be monotone. + */ +{ + GLUvertex *v, *vNext; + + tess->fatalError = FALSE; + + /* Each vertex defines an event for our sweep line. Start by inserting + * all the vertices in a priority queue. Events are processed in + * lexicographic order, ie. + * + * e1 < e2 iff e1.x < e2.x || (e1.x == e2.x && e1.y < e2.y) + */ + RemoveDegenerateEdges( tess ); + if ( !InitPriorityQ( tess ) ) return 0; /* if error */ + InitEdgeDict( tess ); + + /* __gl_pqSortExtractMin */ + while( (v = (GLUvertex *)pqExtractMin( tess->pq )) != NULL ) { + for( ;; ) { + vNext = (GLUvertex *)pqMinimum( tess->pq ); /* __gl_pqSortMinimum */ + if( vNext == NULL || ! VertEq( vNext, v )) break; + + /* Merge together all vertices at exactly the same location. + * This is more efficient than processing them one at a time, + * simplifies the code (see ConnectLeftDegenerate), and is also + * important for correct handling of certain degenerate cases. + * For example, suppose there are two identical edges A and B + * that belong to different contours (so without this code they would + * be processed by separate sweep events). Suppose another edge C + * crosses A and B from above. When A is processed, we split it + * at its intersection point with C. However this also splits C, + * so when we insert B we may compute a slightly different + * intersection point. This might leave two edges with a small + * gap between them. This kind of error is especially obvious + * when using boundary extraction (GLU_TESS_BOUNDARY_ONLY). + */ + vNext = (GLUvertex *)pqExtractMin( tess->pq ); /* __gl_pqSortExtractMin*/ + SpliceMergeVertices( tess, v->anEdge, vNext->anEdge ); + } + SweepEvent( tess, v ); + } + + /* Set tess->event for debugging purposes */ + /* __GL_DICTLISTKEY */ /* __GL_DICTLISTMIN */ + tess->event = ((ActiveRegion *) dictKey( dictMin( tess->dict )))->eUp->Org; + DebugEvent( tess ); + DoneEdgeDict( tess ); + DonePriorityQ( tess ); + + if ( !RemoveDegenerateFaces( tess->mesh ) ) return 0; + __gl_meshCheckMesh( tess->mesh ); + + return 1; +} diff --git a/common/libtess/sweep.h b/common/libtess/sweep.h new file mode 100755 index 0000000..feb68b0 --- /dev/null +++ b/common/libtess/sweep.h @@ -0,0 +1,77 @@ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * 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 including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * 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 + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ +/* +** Author: Eric Veach, July 1994. +** +*/ + +#ifndef __sweep_h_ +#define __sweep_h_ + +#include "mesh.h" + +/* __gl_computeInterior( tess ) computes the planar arrangement specified + * by the given contours, and further subdivides this arrangement + * into regions. Each region is marked "inside" if it belongs + * to the polygon, according to the rule given by tess->windingRule. + * Each interior region is guaranteed be monotone. + */ +int __gl_computeInterior( GLUtesselator *tess ); + + +/* The following is here *only* for access by debugging routines */ + +#include "dict.h" + +/* For each pair of adjacent edges crossing the sweep line, there is + * an ActiveRegion to represent the region between them. The active + * regions are kept in sorted order in a dynamic dictionary. As the + * sweep line crosses each vertex, we update the affected regions. + */ + +struct ActiveRegion { + GLUhalfEdge *eUp; /* upper edge, directed right to left */ + DictNode *nodeUp; /* dictionary node corresponding to eUp */ + int windingNumber; /* used to determine which regions are + * inside the polygon */ + GLboolean inside; /* is this region inside the polygon? */ + GLboolean sentinel; /* marks fake edges at t = +/-infinity */ + GLboolean dirty; /* marks regions where the upper or lower + * edge has changed, but we haven't checked + * whether they intersect yet */ + GLboolean fixUpperEdge; /* marks temporary edges introduced when + * we process a "right vertex" (one without + * any edges leaving to the right) */ +}; + +#define RegionBelow(r) ((ActiveRegion *) dictKey(dictPred((r)->nodeUp))) +#define RegionAbove(r) ((ActiveRegion *) dictKey(dictSucc((r)->nodeUp))) + +#endif diff --git a/common/libtess/tess.c b/common/libtess/tess.c new file mode 100755 index 0000000..af1735f --- /dev/null +++ b/common/libtess/tess.c @@ -0,0 +1,632 @@ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * 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 including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * 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 + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ +/* +** Author: Eric Veach, July 1994. +** +*/ + +#include "../prboom/SDL_opengl.h" // JDC +//#include "gluos.h" +#include +#include +#include +#include "memalloc.h" +#include "tess.h" +#include "mesh.h" +#include "normal.h" +#include "sweep.h" +#include "tessmono.h" +#include "render.h" + +#define GLU_TESS_DEFAULT_TOLERANCE 0.0 +#define GLU_TESS_MESH 100112 /* void (*)(GLUmesh *mesh) */ + +#define TRUE 1 +#define FALSE 0 + +/*ARGSUSED*/ static void GLAPIENTRY noBegin( GLenum type ) {} +/*ARGSUSED*/ static void GLAPIENTRY noEdgeFlag( GLboolean boundaryEdge ) {} +/*ARGSUSED*/ static void GLAPIENTRY noVertex( void *data ) {} +/*ARGSUSED*/ static void GLAPIENTRY noEnd( void ) {} +/*ARGSUSED*/ static void GLAPIENTRY noError( GLenum errnum ) {} +/*ARGSUSED*/ static void GLAPIENTRY noCombine( GLdouble coords[3], void *data[4], + GLfloat weight[4], void **dataOut ) {} +/*ARGSUSED*/ static void GLAPIENTRY noMesh( GLUmesh *mesh ) {} + + +/*ARGSUSED*/ void GLAPIENTRY __gl_noBeginData( GLenum type, + void *polygonData ) {} +/*ARGSUSED*/ void GLAPIENTRY __gl_noEdgeFlagData( GLboolean boundaryEdge, + void *polygonData ) {} +/*ARGSUSED*/ void GLAPIENTRY __gl_noVertexData( void *data, + void *polygonData ) {} +/*ARGSUSED*/ void GLAPIENTRY __gl_noEndData( void *polygonData ) {} +/*ARGSUSED*/ void GLAPIENTRY __gl_noErrorData( GLenum errnum, + void *polygonData ) {} +/*ARGSUSED*/ void GLAPIENTRY __gl_noCombineData( GLdouble coords[3], + void *data[4], + GLfloat weight[4], + void **outData, + void *polygonData ) {} + +/* Half-edges are allocated in pairs (see mesh.c) */ +typedef struct { GLUhalfEdge e, eSym; } EdgePair; + +#undef MAX +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#define MAX_FAST_ALLOC (MAX(sizeof(EdgePair), \ + MAX(sizeof(GLUvertex),sizeof(GLUface)))) + + +GLUtesselator * GLAPIENTRY +gluNewTess( void ) +{ + GLUtesselator *tess; + + /* Only initialize fields which can be changed by the api. Other fields + * are initialized where they are used. + */ + + if (memInit( MAX_FAST_ALLOC ) == 0) { + return 0; /* out of memory */ + } + tess = (GLUtesselator *)memAlloc( sizeof( GLUtesselator )); + if (tess == NULL) { + return 0; /* out of memory */ + } + + tess->state = T_DORMANT; + + tess->normal[0] = 0; + tess->normal[1] = 0; + tess->normal[2] = 0; + + tess->relTolerance = GLU_TESS_DEFAULT_TOLERANCE; + tess->windingRule = GLU_TESS_WINDING_ODD; + tess->flagBoundary = FALSE; + tess->boundaryOnly = FALSE; + + tess->callBegin = &noBegin; + tess->callEdgeFlag = &noEdgeFlag; + tess->callVertex = &noVertex; + tess->callEnd = &noEnd; + + tess->callError = &noError; + tess->callCombine = &noCombine; + tess->callMesh = &noMesh; + + tess->callBeginData= &__gl_noBeginData; + tess->callEdgeFlagData= &__gl_noEdgeFlagData; + tess->callVertexData= &__gl_noVertexData; + tess->callEndData= &__gl_noEndData; + tess->callErrorData= &__gl_noErrorData; + tess->callCombineData= &__gl_noCombineData; + + tess->polygonData= NULL; + + return tess; +} + +static void MakeDormant( GLUtesselator *tess ) +{ + /* Return the tessellator to its original dormant state. */ + + if( tess->mesh != NULL ) { + __gl_meshDeleteMesh( tess->mesh ); + } + tess->state = T_DORMANT; + tess->lastEdge = NULL; + tess->mesh = NULL; +} + +#define RequireState( tess, s ) if( tess->state != s ) GotoState(tess,s) + +static void GotoState( GLUtesselator *tess, enum TessState newState ) +{ + while( tess->state != newState ) { + /* We change the current state one level at a time, to get to + * the desired state. + */ + if( tess->state < newState ) { + switch( tess->state ) { + case T_DORMANT: + CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_BEGIN_POLYGON ); + gluTessBeginPolygon( tess, NULL ); + break; + case T_IN_POLYGON: + CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_BEGIN_CONTOUR ); + gluTessBeginContour( tess ); + break; + default: + ; + } + } else { + switch( tess->state ) { + case T_IN_CONTOUR: + CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_END_CONTOUR ); + gluTessEndContour( tess ); + break; + case T_IN_POLYGON: + CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_END_POLYGON ); + /* gluTessEndPolygon( tess ) is too much work! */ + MakeDormant( tess ); + break; + default: + ; + } + } + } +} + + +void GLAPIENTRY +gluDeleteTess( GLUtesselator *tess ) +{ + RequireState( tess, T_DORMANT ); + memFree( tess ); +} + + +void GLAPIENTRY +gluTessProperty( GLUtesselator *tess, GLenum which, GLdouble value ) +{ + GLenum windingRule; + + switch( which ) { + case GLU_TESS_TOLERANCE: + if( value < 0.0 || value > 1.0 ) break; + tess->relTolerance = value; + return; + + case GLU_TESS_WINDING_RULE: + windingRule = (GLenum) value; + if( windingRule != value ) break; /* not an integer */ + + switch( windingRule ) { + case GLU_TESS_WINDING_ODD: + case GLU_TESS_WINDING_NONZERO: + case GLU_TESS_WINDING_POSITIVE: + case GLU_TESS_WINDING_NEGATIVE: + case GLU_TESS_WINDING_ABS_GEQ_TWO: + tess->windingRule = windingRule; + return; + default: + break; + } + + case GLU_TESS_BOUNDARY_ONLY: + tess->boundaryOnly = (value != 0); + return; + + default: + CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM ); + return; + } + CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_VALUE ); +} + +void GLAPIENTRY +gluGetTessProperty( GLUtesselator *tess, GLenum which, GLdouble *value ); + +/* Returns tessellator property */ +void GLAPIENTRY +gluGetTessProperty( GLUtesselator *tess, GLenum which, GLdouble *value ) +{ + switch (which) { + case GLU_TESS_TOLERANCE: + /* tolerance should be in range [0..1] */ + assert(0.0 <= tess->relTolerance && tess->relTolerance <= 1.0); + *value= tess->relTolerance; + break; + case GLU_TESS_WINDING_RULE: + assert(tess->windingRule == GLU_TESS_WINDING_ODD || + tess->windingRule == GLU_TESS_WINDING_NONZERO || + tess->windingRule == GLU_TESS_WINDING_POSITIVE || + tess->windingRule == GLU_TESS_WINDING_NEGATIVE || + tess->windingRule == GLU_TESS_WINDING_ABS_GEQ_TWO); + *value= tess->windingRule; + break; + case GLU_TESS_BOUNDARY_ONLY: + assert(tess->boundaryOnly == TRUE || tess->boundaryOnly == FALSE); + *value= tess->boundaryOnly; + break; + default: + *value= 0.0; + CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM ); + break; + } +} /* gluGetTessProperty() */ + +void GLAPIENTRY +gluTessNormal( GLUtesselator *tess, GLdouble x, GLdouble y, GLdouble z ) +{ + tess->normal[0] = x; + tess->normal[1] = y; + tess->normal[2] = z; +} + +void GLAPIENTRY +gluTessCallback( GLUtesselator *tess, GLenum which, _GLUfuncptr fn) +{ + switch( which ) { + case GLU_TESS_BEGIN: + tess->callBegin = (fn == NULL) ? &noBegin : (void (GLAPIENTRY *)(GLenum)) fn; + return; + case GLU_TESS_BEGIN_DATA: + tess->callBeginData = (fn == NULL) ? + &__gl_noBeginData : (void (GLAPIENTRY *)(GLenum, void *)) fn; + return; + case GLU_TESS_EDGE_FLAG: + tess->callEdgeFlag = (fn == NULL) ? &noEdgeFlag : + (void (GLAPIENTRY *)(GLboolean)) fn; + /* If the client wants boundary edges to be flagged, + * we render everything as separate triangles (no strips or fans). + */ + tess->flagBoundary = (fn != NULL); + return; + case GLU_TESS_EDGE_FLAG_DATA: + tess->callEdgeFlagData= (fn == NULL) ? + &__gl_noEdgeFlagData : (void (GLAPIENTRY *)(GLboolean, void *)) fn; + /* If the client wants boundary edges to be flagged, + * we render everything as separate triangles (no strips or fans). + */ + tess->flagBoundary = (fn != NULL); + return; + case GLU_TESS_VERTEX: + tess->callVertex = (fn == NULL) ? &noVertex : + (void (GLAPIENTRY *)(void *)) fn; + return; + case GLU_TESS_VERTEX_DATA: + tess->callVertexData = (fn == NULL) ? + &__gl_noVertexData : (void (GLAPIENTRY *)(void *, void *)) fn; + return; + case GLU_TESS_END: + tess->callEnd = (fn == NULL) ? &noEnd : (void (GLAPIENTRY *)(void)) fn; + return; + case GLU_TESS_END_DATA: + tess->callEndData = (fn == NULL) ? &__gl_noEndData : + (void (GLAPIENTRY *)(void *)) fn; + return; + case GLU_TESS_ERROR: + tess->callError = (fn == NULL) ? &noError : (void (GLAPIENTRY *)(GLenum)) fn; + return; + case GLU_TESS_ERROR_DATA: + tess->callErrorData = (fn == NULL) ? + &__gl_noErrorData : (void (GLAPIENTRY *)(GLenum, void *)) fn; + return; + case GLU_TESS_COMBINE: + tess->callCombine = (fn == NULL) ? &noCombine : + (void (GLAPIENTRY *)(GLdouble [3],void *[4], GLfloat [4], void ** )) fn; + return; + case GLU_TESS_COMBINE_DATA: + tess->callCombineData = (fn == NULL) ? &__gl_noCombineData : + (void (GLAPIENTRY *)(GLdouble [3], + void *[4], + GLfloat [4], + void **, + void *)) fn; + return; + case GLU_TESS_MESH: + tess->callMesh = (fn == NULL) ? &noMesh : (void (GLAPIENTRY *)(GLUmesh *)) fn; + return; + default: + CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM ); + return; + } +} + +static int AddVertex( GLUtesselator *tess, GLdouble coords[3], void *data ) +{ + GLUhalfEdge *e; + + e = tess->lastEdge; + if( e == NULL ) { + /* Make a self-loop (one vertex, one edge). */ + + e = __gl_meshMakeEdge( tess->mesh ); + if (e == NULL) return 0; + if ( !__gl_meshSplice( e, e->Sym ) ) return 0; + } else { + /* Create a new vertex and edge which immediately follow e + * in the ordering around the left face. + */ + if (__gl_meshSplitEdge( e ) == NULL) return 0; + e = e->Lnext; + } + + /* The new vertex is now e->Org. */ + e->Org->data = data; + e->Org->coords[0] = coords[0]; + e->Org->coords[1] = coords[1]; + e->Org->coords[2] = coords[2]; + + /* The winding of an edge says how the winding number changes as we + * cross from the edge''s right face to its left face. We add the + * vertices in such an order that a CCW contour will add +1 to + * the winding number of the region inside the contour. + */ + e->winding = 1; + e->Sym->winding = -1; + + tess->lastEdge = e; + + return 1; +} + + +static void CacheVertex( GLUtesselator *tess, GLdouble coords[3], void *data ) +{ + CachedVertex *v = &tess->cache[tess->cacheCount]; + + v->data = data; + v->coords[0] = coords[0]; + v->coords[1] = coords[1]; + v->coords[2] = coords[2]; + ++tess->cacheCount; +} + + +static int EmptyCache( GLUtesselator *tess ) +{ + CachedVertex *v = tess->cache; + CachedVertex *vLast; + + tess->mesh = __gl_meshNewMesh(); + if (tess->mesh == NULL) return 0; + + for( vLast = v + tess->cacheCount; v < vLast; ++v ) { + if ( !AddVertex( tess, v->coords, v->data ) ) return 0; + } + tess->cacheCount = 0; + tess->emptyCache = FALSE; + + return 1; +} + + +void GLAPIENTRY +gluTessVertex( GLUtesselator *tess, GLdouble coords[3], void *data ) +{ + int i, tooLarge = FALSE; + GLdouble x, clamped[3]; + + RequireState( tess, T_IN_CONTOUR ); + + if( tess->emptyCache ) { + if ( !EmptyCache( tess ) ) { + CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY ); + return; + } + tess->lastEdge = NULL; + } + for( i = 0; i < 3; ++i ) { + x = coords[i]; + if( x < - GLU_TESS_MAX_COORD ) { + x = - GLU_TESS_MAX_COORD; + tooLarge = TRUE; + } + if( x > GLU_TESS_MAX_COORD ) { + x = GLU_TESS_MAX_COORD; + tooLarge = TRUE; + } + clamped[i] = x; + } + if( tooLarge ) { + CALL_ERROR_OR_ERROR_DATA( GLU_TESS_COORD_TOO_LARGE ); + } + + if( tess->mesh == NULL ) { + if( tess->cacheCount < TESS_MAX_CACHE ) { + CacheVertex( tess, clamped, data ); + return; + } + if ( !EmptyCache( tess ) ) { + CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY ); + return; + } + } + if ( !AddVertex( tess, clamped, data ) ) { + CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY ); + } +} + + +void GLAPIENTRY +gluTessBeginPolygon( GLUtesselator *tess, void *data ) +{ + RequireState( tess, T_DORMANT ); + + tess->state = T_IN_POLYGON; + tess->cacheCount = 0; + tess->emptyCache = FALSE; + tess->mesh = NULL; + + tess->polygonData= data; +} + + +void GLAPIENTRY +gluTessBeginContour( GLUtesselator *tess ) +{ + RequireState( tess, T_IN_POLYGON ); + + tess->state = T_IN_CONTOUR; + tess->lastEdge = NULL; + if( tess->cacheCount > 0 ) { + /* Just set a flag so we don't get confused by empty contours + * -- these can be generated accidentally with the obsolete + * NextContour() interface. + */ + tess->emptyCache = TRUE; + } +} + + +void GLAPIENTRY +gluTessEndContour( GLUtesselator *tess ) +{ + RequireState( tess, T_IN_CONTOUR ); + tess->state = T_IN_POLYGON; +} + +void GLAPIENTRY +gluTessEndPolygon( GLUtesselator *tess ) +{ + GLUmesh *mesh; + + if (setjmp(tess->env) != 0) { + /* come back here if out of memory */ + CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY ); + return; + } + + RequireState( tess, T_IN_POLYGON ); + tess->state = T_DORMANT; + + if( tess->mesh == NULL ) { + if( ! tess->flagBoundary && tess->callMesh == &noMesh ) { + + /* Try some special code to make the easy cases go quickly + * (eg. convex polygons). This code does NOT handle multiple contours, + * intersections, edge flags, and of course it does not generate + * an explicit mesh either. + */ + if( __gl_renderCache( tess )) { + tess->polygonData= NULL; + return; + } + } + if ( !EmptyCache( tess ) ) longjmp(tess->env,1); /* could've used a label*/ + } + + /* Determine the polygon normal and project vertices onto the plane + * of the polygon. + */ + __gl_projectPolygon( tess ); + + /* __gl_computeInterior( tess ) computes the planar arrangement specified + * by the given contours, and further subdivides this arrangement + * into regions. Each region is marked "inside" if it belongs + * to the polygon, according to the rule given by tess->windingRule. + * Each interior region is guaranteed be monotone. + */ + if ( !__gl_computeInterior( tess ) ) { + longjmp(tess->env,1); /* could've used a label */ + } + + mesh = tess->mesh; + if( ! tess->fatalError ) { + int rc = 1; + + /* If the user wants only the boundary contours, we throw away all edges + * except those which separate the interior from the exterior. + * Otherwise we tessellate all the regions marked "inside". + */ + if( tess->boundaryOnly ) { + rc = __gl_meshSetWindingNumber( mesh, 1, TRUE ); + } else { + rc = __gl_meshTessellateInterior( mesh ); + } + if (rc == 0) longjmp(tess->env,1); /* could've used a label */ + + __gl_meshCheckMesh( mesh ); + + if( tess->callBegin != &noBegin || tess->callEnd != &noEnd + || tess->callVertex != &noVertex || tess->callEdgeFlag != &noEdgeFlag + || tess->callBeginData != &__gl_noBeginData + || tess->callEndData != &__gl_noEndData + || tess->callVertexData != &__gl_noVertexData + || tess->callEdgeFlagData != &__gl_noEdgeFlagData ) + { + if( tess->boundaryOnly ) { + __gl_renderBoundary( tess, mesh ); /* output boundary contours */ + } else { + __gl_renderMesh( tess, mesh ); /* output strips and fans */ + } + } + if( tess->callMesh != &noMesh ) { + + /* Throw away the exterior faces, so that all faces are interior. + * This way the user doesn't have to check the "inside" flag, + * and we don't need to even reveal its existence. It also leaves + * the freedom for an implementation to not generate the exterior + * faces in the first place. + */ + __gl_meshDiscardExterior( mesh ); + (*tess->callMesh)( mesh ); /* user wants the mesh itself */ + tess->mesh = NULL; + tess->polygonData= NULL; + return; + } + } + __gl_meshDeleteMesh( mesh ); + tess->polygonData= NULL; + tess->mesh = NULL; +} + + +/*XXXblythe unused function*/ +#if 0 +void GLAPIENTRY +gluDeleteMesh( GLUmesh *mesh ) +{ + __gl_meshDeleteMesh( mesh ); +} +#endif + + + +/*******************************************************/ + +/* Obsolete calls -- for backward compatibility */ +/* +void GLAPIENTRY +gluBeginPolygon( GLUtesselator *tess ) +{ + gluTessBeginPolygon( tess, NULL ); + gluTessBeginContour( tess ); +} +*/ + +/*ARGSUSED*//* +void GLAPIENTRY +gluNextContour( GLUtesselator *tess, GLenum type ) +{ + gluTessEndContour( tess ); + gluTessBeginContour( tess ); +} + + +void GLAPIENTRY +gluEndPolygon( GLUtesselator *tess ) +{ + gluTessEndContour( tess ); + gluTessEndPolygon( tess ); +}*/ diff --git a/common/libtess/tess.h b/common/libtess/tess.h new file mode 100755 index 0000000..606d7ba --- /dev/null +++ b/common/libtess/tess.h @@ -0,0 +1,166 @@ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * 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 including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * 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 + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ +/* +** Author: Eric Veach, July 1994. +** +*/ + +#ifndef __tess_h_ +#define __tess_h_ + +#include "../prboom/SDL_opengl.h" // JDC +// JDC #include +#include +#include "mesh.h" +#include "dict.h" +#include "priorityq.h" + +/* The begin/end calls must be properly nested. We keep track of + * the current state to enforce the ordering. + */ +enum TessState { T_DORMANT, T_IN_POLYGON, T_IN_CONTOUR }; + +/* We cache vertex data for single-contour polygons so that we can + * try a quick-and-dirty decomposition first. + */ +#define TESS_MAX_CACHE 100 + +typedef struct CachedVertex { + GLdouble coords[3]; + void *data; +} CachedVertex; + +struct GLUtesselator { + + /*** state needed for collecting the input data ***/ + + enum TessState state; /* what begin/end calls have we seen? */ + + GLUhalfEdge *lastEdge; /* lastEdge->Org is the most recent vertex */ + GLUmesh *mesh; /* stores the input contours, and eventually + the tessellation itself */ + + void (GLAPIENTRY *callError)( GLenum errnum ); + + /*** state needed for projecting onto the sweep plane ***/ + + GLdouble normal[3]; /* user-specified normal (if provided) */ + GLdouble sUnit[3]; /* unit vector in s-direction (debugging) */ + GLdouble tUnit[3]; /* unit vector in t-direction (debugging) */ + + /*** state needed for the line sweep ***/ + + GLdouble relTolerance; /* tolerance for merging features */ + GLenum windingRule; /* rule for determining polygon interior */ + GLboolean fatalError; /* fatal error: needed combine callback */ + + Dict *dict; /* edge dictionary for sweep line */ + PriorityQ *pq; /* priority queue of vertex events */ + GLUvertex *event; /* current sweep event being processed */ + + void (GLAPIENTRY *callCombine)( GLdouble coords[3], void *data[4], + GLfloat weight[4], void **outData ); + + /*** state needed for rendering callbacks (see render.c) ***/ + + GLboolean flagBoundary; /* mark boundary edges (use EdgeFlag) */ + GLboolean boundaryOnly; /* Extract contours, not triangles */ + GLUface *lonelyTriList; + /* list of triangles which could not be rendered as strips or fans */ + + void (GLAPIENTRY *callBegin)( GLenum type ); + void (GLAPIENTRY *callEdgeFlag)( GLboolean boundaryEdge ); + void (GLAPIENTRY *callVertex)( void *data ); + void (GLAPIENTRY *callEnd)( void ); + void (GLAPIENTRY *callMesh)( GLUmesh *mesh ); + + + /*** state needed to cache single-contour polygons for renderCache() */ + + GLboolean emptyCache; /* empty cache on next vertex() call */ + int cacheCount; /* number of cached vertices */ + CachedVertex cache[TESS_MAX_CACHE]; /* the vertex data */ + + /*** rendering callbacks that also pass polygon data ***/ + void (GLAPIENTRY *callBeginData)( GLenum type, void *polygonData ); + void (GLAPIENTRY *callEdgeFlagData)( GLboolean boundaryEdge, + void *polygonData ); + void (GLAPIENTRY *callVertexData)( void *data, void *polygonData ); + void (GLAPIENTRY *callEndData)( void *polygonData ); + void (GLAPIENTRY *callErrorData)( GLenum errnum, void *polygonData ); + void (GLAPIENTRY *callCombineData)( GLdouble coords[3], void *data[4], + GLfloat weight[4], void **outData, + void *polygonData ); + + jmp_buf env; /* place to jump to when memAllocs fail */ + + void *polygonData; /* client data for current polygon */ +}; + +void GLAPIENTRY __gl_noBeginData( GLenum type, void *polygonData ); +void GLAPIENTRY __gl_noEdgeFlagData( GLboolean boundaryEdge, void *polygonData ); +void GLAPIENTRY __gl_noVertexData( void *data, void *polygonData ); +void GLAPIENTRY __gl_noEndData( void *polygonData ); +void GLAPIENTRY __gl_noErrorData( GLenum errnum, void *polygonData ); +void GLAPIENTRY __gl_noCombineData( GLdouble coords[3], void *data[4], + GLfloat weight[4], void **outData, + void *polygonData ); + +#define CALL_BEGIN_OR_BEGIN_DATA(a) \ + if (tess->callBeginData != &__gl_noBeginData) \ + (*tess->callBeginData)((a),tess->polygonData); \ + else (*tess->callBegin)((a)); + +#define CALL_VERTEX_OR_VERTEX_DATA(a) \ + if (tess->callVertexData != &__gl_noVertexData) \ + (*tess->callVertexData)((a),tess->polygonData); \ + else (*tess->callVertex)((a)); + +#define CALL_EDGE_FLAG_OR_EDGE_FLAG_DATA(a) \ + if (tess->callEdgeFlagData != &__gl_noEdgeFlagData) \ + (*tess->callEdgeFlagData)((a),tess->polygonData); \ + else (*tess->callEdgeFlag)((a)); + +#define CALL_END_OR_END_DATA() \ + if (tess->callEndData != &__gl_noEndData) \ + (*tess->callEndData)(tess->polygonData); \ + else (*tess->callEnd)(); + +#define CALL_COMBINE_OR_COMBINE_DATA(a,b,c,d) \ + if (tess->callCombineData != &__gl_noCombineData) \ + (*tess->callCombineData)((a),(b),(c),(d),tess->polygonData); \ + else (*tess->callCombine)((a),(b),(c),(d)); + +#define CALL_ERROR_OR_ERROR_DATA(a) \ + if (tess->callErrorData != &__gl_noErrorData) \ + (*tess->callErrorData)((a),tess->polygonData); \ + else (*tess->callError)((a)); + +#endif diff --git a/common/libtess/tessmono.c b/common/libtess/tessmono.c new file mode 100755 index 0000000..964ef5b --- /dev/null +++ b/common/libtess/tessmono.c @@ -0,0 +1,202 @@ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * 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 including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * 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 + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ +/* +** Author: Eric Veach, July 1994. +** +*/ + +#include "../prboom/SDL_opengl.h" // JDC +//#include "gluos.h" +#include +#include "geom.h" +#include "mesh.h" +#include "tessmono.h" +#include + +#define AddWinding(eDst,eSrc) (eDst->winding += eSrc->winding, \ + eDst->Sym->winding += eSrc->Sym->winding) + +/* __gl_meshTessellateMonoRegion( face ) tessellates a monotone region + * (what else would it do??) The region must consist of a single + * loop of half-edges (see mesh.h) oriented CCW. "Monotone" in this + * case means that any vertical line intersects the interior of the + * region in a single interval. + * + * Tessellation consists of adding interior edges (actually pairs of + * half-edges), to split the region into non-overlapping triangles. + * + * The basic idea is explained in Preparata and Shamos (which I don''t + * have handy right now), although their implementation is more + * complicated than this one. The are two edge chains, an upper chain + * and a lower chain. We process all vertices from both chains in order, + * from right to left. + * + * The algorithm ensures that the following invariant holds after each + * vertex is processed: the untessellated region consists of two + * chains, where one chain (say the upper) is a single edge, and + * the other chain is concave. The left vertex of the single edge + * is always to the left of all vertices in the concave chain. + * + * Each step consists of adding the rightmost unprocessed vertex to one + * of the two chains, and forming a fan of triangles from the rightmost + * of two chain endpoints. Determining whether we can add each triangle + * to the fan is a simple orientation test. By making the fan as large + * as possible, we restore the invariant (check it yourself). + */ +int __gl_meshTessellateMonoRegion( GLUface *face ) +{ + GLUhalfEdge *up, *lo; + + /* All edges are oriented CCW around the boundary of the region. + * First, find the half-edge whose origin vertex is rightmost. + * Since the sweep goes from left to right, face->anEdge should + * be close to the edge we want. + */ + up = face->anEdge; + assert( up->Lnext != up && up->Lnext->Lnext != up ); + + for( ; VertLeq( up->Dst, up->Org ); up = up->Lprev ) + ; + for( ; VertLeq( up->Org, up->Dst ); up = up->Lnext ) + ; + lo = up->Lprev; + + while( up->Lnext != lo ) { + if( VertLeq( up->Dst, lo->Org )) { + /* up->Dst is on the left. It is safe to form triangles from lo->Org. + * The EdgeGoesLeft test guarantees progress even when some triangles + * are CW, given that the upper and lower chains are truly monotone. + */ + while( lo->Lnext != up && (EdgeGoesLeft( lo->Lnext ) + || EdgeSign( lo->Org, lo->Dst, lo->Lnext->Dst ) <= 0 )) { + GLUhalfEdge *tempHalfEdge= __gl_meshConnect( lo->Lnext, lo ); + if (tempHalfEdge == NULL) return 0; + lo = tempHalfEdge->Sym; + } + lo = lo->Lprev; + } else { + /* lo->Org is on the left. We can make CCW triangles from up->Dst. */ + while( lo->Lnext != up && (EdgeGoesRight( up->Lprev ) + || EdgeSign( up->Dst, up->Org, up->Lprev->Org ) >= 0 )) { + GLUhalfEdge *tempHalfEdge= __gl_meshConnect( up, up->Lprev ); + if (tempHalfEdge == NULL) return 0; + up = tempHalfEdge->Sym; + } + up = up->Lnext; + } + } + + /* Now lo->Org == up->Dst == the leftmost vertex. The remaining region + * can be tessellated in a fan from this leftmost vertex. + */ + assert( lo->Lnext != up ); + while( lo->Lnext->Lnext != up ) { + GLUhalfEdge *tempHalfEdge= __gl_meshConnect( lo->Lnext, lo ); + if (tempHalfEdge == NULL) return 0; + lo = tempHalfEdge->Sym; + } + + return 1; +} + + +/* __gl_meshTessellateInterior( mesh ) tessellates each region of + * the mesh which is marked "inside" the polygon. Each such region + * must be monotone. + */ +int __gl_meshTessellateInterior( GLUmesh *mesh ) +{ + GLUface *f, *next; + + /*LINTED*/ + for( f = mesh->fHead.next; f != &mesh->fHead; f = next ) { + /* Make sure we don''t try to tessellate the new triangles. */ + next = f->next; + if( f->inside ) { + if ( !__gl_meshTessellateMonoRegion( f ) ) return 0; + } + } + + return 1; +} + + +/* __gl_meshDiscardExterior( mesh ) zaps (ie. sets to NULL) all faces + * which are not marked "inside" the polygon. Since further mesh operations + * on NULL faces are not allowed, the main purpose is to clean up the + * mesh so that exterior loops are not represented in the data structure. + */ +void __gl_meshDiscardExterior( GLUmesh *mesh ) +{ + GLUface *f, *next; + + /*LINTED*/ + for( f = mesh->fHead.next; f != &mesh->fHead; f = next ) { + /* Since f will be destroyed, save its next pointer. */ + next = f->next; + if( ! f->inside ) { + __gl_meshZapFace( f ); + } + } +} + +#define MARKED_FOR_DELETION 0x7fffffff + +/* __gl_meshSetWindingNumber( mesh, value, keepOnlyBoundary ) resets the + * winding numbers on all edges so that regions marked "inside" the + * polygon have a winding number of "value", and regions outside + * have a winding number of 0. + * + * If keepOnlyBoundary is TRUE, it also deletes all edges which do not + * separate an interior region from an exterior one. + */ +int __gl_meshSetWindingNumber( GLUmesh *mesh, int value, + GLboolean keepOnlyBoundary ) +{ + GLUhalfEdge *e, *eNext; + + for( e = mesh->eHead.next; e != &mesh->eHead; e = eNext ) { + eNext = e->next; + if( e->Rface->inside != e->Lface->inside ) { + + /* This is a boundary edge (one side is interior, one is exterior). */ + e->winding = (e->Lface->inside) ? value : -value; + } else { + + /* Both regions are interior, or both are exterior. */ + if( ! keepOnlyBoundary ) { + e->winding = 0; + } else { + if ( !__gl_meshDelete( e ) ) return 0; + } + } + } + return 1; +} diff --git a/common/libtess/tessmono.h b/common/libtess/tessmono.h new file mode 100755 index 0000000..8ee1b2f --- /dev/null +++ b/common/libtess/tessmono.h @@ -0,0 +1,71 @@ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * 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 including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * 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 + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ +/* +** Author: Eric Veach, July 1994. +** +*/ + +#ifndef __tessmono_h_ +#define __tessmono_h_ + +/* __gl_meshTessellateMonoRegion( face ) tessellates a monotone region + * (what else would it do??) The region must consist of a single + * loop of half-edges (see mesh.h) oriented CCW. "Monotone" in this + * case means that any vertical line intersects the interior of the + * region in a single interval. + * + * Tessellation consists of adding interior edges (actually pairs of + * half-edges), to split the region into non-overlapping triangles. + * + * __gl_meshTessellateInterior( mesh ) tessellates each region of + * the mesh which is marked "inside" the polygon. Each such region + * must be monotone. + * + * __gl_meshDiscardExterior( mesh ) zaps (ie. sets to NULL) all faces + * which are not marked "inside" the polygon. Since further mesh operations + * on NULL faces are not allowed, the main purpose is to clean up the + * mesh so that exterior loops are not represented in the data structure. + * + * __gl_meshSetWindingNumber( mesh, value, keepOnlyBoundary ) resets the + * winding numbers on all edges so that regions marked "inside" the + * polygon have a winding number of "value", and regions outside + * have a winding number of 0. + * + * If keepOnlyBoundary is TRUE, it also deletes all edges which do not + * separate an interior region from an exterior one. + */ + +int __gl_meshTessellateMonoRegion( GLUface *face ); +int __gl_meshTessellateInterior( GLUmesh *mesh ); +void __gl_meshDiscardExterior( GLUmesh *mesh ); +int __gl_meshSetWindingNumber( GLUmesh *mesh, int value, + GLboolean keepOnlyBoundary ); + +#endif diff --git a/common/prboom/Makefile.am b/common/prboom/Makefile.am new file mode 100755 index 0000000..a972643 --- /dev/null +++ b/common/prboom/Makefile.am @@ -0,0 +1,72 @@ +# +# automake Makefile.am for the PrBoom source directory +# +# +# Process this file with automake to produce Makefile.in +# +# + +SUBDIRS = SDL POSIX MAC + +gamesdir=$(prefix)/games +games_PROGRAMS = prboom prboom-game-server + +CFLAGS = @CFLAGS@ @SDL_CFLAGS@ + +prboom_game_server_SOURCES = d_server.c protocol.h +prboom_game_server_LDADD = POSIX/libposixdoom.a SDL/i_network.o @NET_LIBS@ @SDL_LIBS@ + +COMMON_SRC = \ + am_map.c g_game.c p_maputl.h r_plane.h \ + am_map.h g_game.h p_mobj.c r_demo.c r_segs.c \ + hu_lib.c lprintf.c p_mobj.h r_demo.h r_segs.h \ + hu_lib.h lprintf.h p_plats.c r_sky.c \ + d_deh.c hu_stuff.c m_argv.c p_pspr.c r_sky.h \ + d_deh.h hu_stuff.h m_argv.h p_pspr.h r_state.h \ + d_englsh.h i_joy.h m_bbox.c p_saveg.c r_things.c \ + d_event.h m_bbox.h p_saveg.h r_things.h \ + d_items.c i_network.h m_cheat.c p_setup.c s_sound.c \ + d_items.h i_sound.h m_cheat.h p_setup.h s_sound.h \ + d_main.c i_system.h m_fixed.h p_sight.c sounds.c \ + d_main.h i_video.h m_menu.c p_spec.c sounds.h \ + info.c m_menu.h p_spec.h st_lib.c \ + d_net.h info.h m_misc.c p_switch.c st_lib.h \ + d_player.h m_misc.h p_telept.c st_stuff.c \ + m_random.c p_tick.c st_stuff.h i_main.h \ + d_think.h m_random.h p_tick.h tables.c \ + d_ticcmd.h m_swap.h p_user.c tables.h \ + doomdata.h p_ceilng.c p_user.h v_video.c \ + doomdef.c p_doors.c protocol.h v_video.h \ + doomdef.h p_enemy.c r_bsp.c version.c \ + doomstat.c p_enemy.h r_bsp.h version.h \ + doomstat.h p_floor.c r_data.c w_wad.c \ + doomtype.h p_genlin.c r_data.h w_wad.h \ + dstrings.c p_inter.c r_defs.h wi_stuff.c \ + dstrings.h p_inter.h r_draw.c wi_stuff.h \ + f_finale.c p_lights.c r_draw.h z_bmalloc.c \ + f_finale.h p_map.c r_main.c z_bmalloc.h \ + f_wipe.c p_map.h r_main.h z_zone.c \ + f_wipe.h p_maputl.c r_plane.c z_zone.h \ + md5.c md5.h p_checksum.h p_checksum.c \ + r_patch.c r_patch.h r_fps.c r_fps.h \ + r_filter.c r_filter.h + +NET_CLIENT_SRC = d_client.c + +if BUILD_GL +USE_GL_SRC = gl_intern.h gl_main.c gl_struct.h gl_texture.c +else +USE_GL_SRC = +endif + +if WAD_MMAP +WAD_SRC = w_mmap.c +else +WAD_SRC = w_memcache.c +endif + +prboom_SOURCES = mmus2mid.c mmus2mid.h $(COMMON_SRC) $(NET_CLIENT_SRC) $(USE_GL_SRC) $(WAD_SRC) +prboom_LDADD = SDL/libsdldoom.a @MIXER_LIBS@ @NET_LIBS@ @SDL_LIBS@ @GL_LIBS@ @MATH_LIB@ + +EXTRA_DIST = \ + r_drawcolumn.inl r_drawflush.inl r_drawspan.inl r_drawcolpipeline.inl diff --git a/common/prboom/SDL/i_sound.c b/common/prboom/SDL/i_sound.c new file mode 100755 index 0000000..67e3ed8 --- /dev/null +++ b/common/prboom/SDL/i_sound.c @@ -0,0 +1,808 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * System interface for sound. + * + *----------------------------------------------------------------------------- + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef HAVE_LIBSDL_MIXER +#define HAVE_MIXER +#endif +#include +#ifdef HAVE_UNISTD_H +#include +#endif + + +// I'm hacking back in the MIDI music support. At this time, I only want +// music-related functions, so I'm adding this macro to remove sfx-related +// functions. +#define ID_DISABLE_SDL_SOUND 1 + +#ifndef ID_DISABLE_SDL_SOUND + +#include "SDL.h" +#include "SDL_audio.h" +#include "SDL_mutex.h" +#include "SDL_byteorder.h" +#include "SDL_version.h" + +#endif // ID_DISABLE_SDL_SOUND + +#ifdef HAVE_MIXER +#include "SDL_mixer.h" +#endif + +#include "z_zone.h" + +#include "m_swap.h" +#include "i_sound.h" +#include "m_argv.h" +#include "m_misc.h" +#include "w_wad.h" +#include "lprintf.h" +#include "s_sound.h" + +#include "doomdef.h" +#include "doomstat.h" +#include "doomtype.h" + +#include "d_main.h" + +// The number of internal mixing channels, +// the samples calculated for each mixing step, +// the size of the 16bit, 2 hardware channel (stereo) +// mixing buffer, and the samplerate of the raw data. + +// Variables used by Boom from Allegro +// created here to avoid changes to core Boom files +int snd_card = 1; +int mus_card = 1; +int detect_voices = 0; // God knows + +static boolean sound_inited = false; +static boolean first_sound_init = true; + +// Needed for calling the actual sound output. +static int SAMPLECOUNT= 512; +#define MAX_CHANNELS 32 + +// MWM 2000-01-08: Sample rate in samples/second +int snd_samplerate=11025; + +// The actual output device. +int audio_fd; + +typedef struct { + // SFX id of the playing sound effect. + // Used to catch duplicates (like chainsaw). + int id; +// The channel step amount... + unsigned int step; +// ... and a 0.16 bit remainder of last step. + unsigned int stepremainder; + unsigned int samplerate; +// The channel data pointers, start and end. + const unsigned char* data; + const unsigned char* enddata; +// Time/gametic that the channel started playing, +// used to determine oldest, which automatically +// has lowest priority. +// In case number of active sounds exceeds +// available channels. + int starttime; + // Hardware left and right channel volume lookup. + int *leftvol_lookup; + int *rightvol_lookup; +} channel_info_t; + +channel_info_t channelinfo[MAX_CHANNELS]; + +// Pitch to stepping lookup, unused. +int steptable[256]; + +// Volume lookups. +int vol_lookup[128*256]; + + + + +#ifndef ID_DISABLE_SDL_SOUND + + + + +/* cph + * stopchan + * Stops a sound, unlocks the data + */ + +static void stopchan(int i) +{ + if (channelinfo[i].data) /* cph - prevent excess unlocks */ + { + channelinfo[i].data=NULL; + W_UnlockLumpNum(S_sfx[channelinfo[i].id].lumpnum); + } +} + +// +// This function adds a sound to the +// list of currently active sounds, +// which is maintained as a given number +// (eight, usually) of internal channels. +// Returns a handle. +// +static int addsfx(int sfxid, int channel, const unsigned char* data, size_t len) +{ + stopchan(channel); + + channelinfo[channel].data = data; + /* Set pointer to end of raw data. */ + channelinfo[channel].enddata = channelinfo[channel].data + len - 1; + channelinfo[channel].samplerate = (channelinfo[channel].data[3]<<8)+channelinfo[channel].data[2]; + channelinfo[channel].data += 8; /* Skip header */ + + channelinfo[channel].stepremainder = 0; + // Should be gametic, I presume. + channelinfo[channel].starttime = gametic; + + // Preserve sound SFX id, + // e.g. for avoiding duplicates of chainsaw. + channelinfo[channel].id = sfxid; + + return channel; +} + +static void updateSoundParams(int handle, int volume, int seperation, int pitch) +{ + int slot = handle; + int rightvol; + int leftvol; + int step = steptable[pitch]; + +#ifdef RANGECHECK + if ((handle < 0) || (handle >= MAX_CHANNELS)) + I_Error("I_UpdateSoundParams: handle out of range"); +#endif + // Set stepping + // MWM 2000-12-24: Calculates proportion of channel samplerate + // to global samplerate for mixing purposes. + // Patched to shift left *then* divide, to minimize roundoff errors + // as well as to use SAMPLERATE as defined above, not to assume 11025 Hz + if (pitched_sounds) + channelinfo[slot].step = step + (((channelinfo[slot].samplerate<<16)/snd_samplerate)-65536); + else + channelinfo[slot].step = ((channelinfo[slot].samplerate<<16)/snd_samplerate); + + // Separation, that is, orientation/stereo. + // range is: 1 - 256 + seperation += 1; + + // Per left/right channel. + // x^2 seperation, + // adjust volume properly. + leftvol = volume - ((volume*seperation*seperation) >> 16); + seperation = seperation - 257; + rightvol= volume - ((volume*seperation*seperation) >> 16); + + // Sanity check, clamp volume. + if (rightvol < 0 || rightvol > 127) + I_Error("rightvol out of bounds"); + + if (leftvol < 0 || leftvol > 127) + I_Error("leftvol out of bounds"); + + // Get the proper lookup table piece + // for this volume level??? + channelinfo[slot].leftvol_lookup = &vol_lookup[leftvol*256]; + channelinfo[slot].rightvol_lookup = &vol_lookup[rightvol*256]; +} + +void I_UpdateSoundParams(int handle, int volume, int seperation, int pitch) +{ + SDL_LockAudio(); + updateSoundParams(handle, volume, seperation, pitch); + SDL_UnlockAudio(); +} + +// +// SFX API +// Note: this was called by S_Init. +// However, whatever they did in the +// old DPMS based DOS version, this +// were simply dummies in the Linux +// version. +// See soundserver initdata(). +// +void I_SetChannels(void) +{ + // Init internal lookups (raw data, mixing buffer, channels). + // This function sets up internal lookups used during + // the mixing process. + int i; + int j; + + int* steptablemid = steptable + 128; + + // Okay, reset internal mixing channels to zero. + for (i=0; iname); + return W_GetNumForName(namebuf); +} + +// +// Starting a sound means adding it +// to the current list of active sounds +// in the internal channels. +// As the SFX info struct contains +// e.g. a pointer to the raw data, +// it is ignored. +// As our sound handling does not handle +// priority, it is ignored. +// Pitching (that is, increased speed of playback) +// is set, but currently not used by mixing. +// +int I_StartSound(int id, int channel, int vol, int sep, int pitch, int priority) +{ + const unsigned char* data; + int lump; + size_t len; + + if ((channel < 0) || (channel >= MAX_CHANNELS)) +#ifdef RANGECHECK + I_Error("I_StartSound: handle out of range"); +#else + return -1; +#endif + + lump = S_sfx[id].lumpnum; + + // We will handle the new SFX. + // Set pointer to raw data. + len = W_LumpLength(lump); + + // e6y: Crash with zero-length sounds. + // Example wad: dakills (http://www.doomworld.com/idgames/index.php?id=2803) + // The entries DSBSPWLK, DSBSPACT, DSSWTCHN and DSSWTCHX are all zero-length sounds + if (len<=8) return -1; + + /* Find padded length */ + len -= 8; + // do the lump caching outside the SDL_LockAudio/SDL_UnlockAudio pair + // use locking which makes sure the sound data is in a malloced area and + // not in a memory mapped one + data = W_LockLumpNum(lump); + + SDL_LockAudio(); + + // Returns a handle (not used). + addsfx(id, channel, data, len); + updateSoundParams(channel, vol, sep, pitch); + + SDL_UnlockAudio(); + + + return channel; +} + + + +void I_StopSound (int handle) +{ +#ifdef RANGECHECK + if ((handle < 0) || (handle >= MAX_CHANNELS)) + I_Error("I_StopSound: handle out of range"); +#endif + SDL_LockAudio(); + stopchan(handle); + SDL_UnlockAudio(); +} + + +boolean I_SoundIsPlaying(int handle) +{ +#ifdef RANGECHECK + if ((handle < 0) || (handle >= MAX_CHANNELS)) + I_Error("I_SoundIsPlaying: handle out of range"); +#endif + return channelinfo[handle].data != NULL; +} + + +boolean I_AnySoundStillPlaying(void) +{ + boolean result = false; + int i; + + for (i=0; i> 16; + + // Add left and right part + // for this channel (sound) + // to the current data. + // Adjust volume accordingly. + dl += channelinfo[chan].leftvol_lookup[sample]; + dr += channelinfo[chan].rightvol_lookup[sample]; + // Increment index ??? + channelinfo[chan].stepremainder += channelinfo[chan].step; + // MSB is next sample??? + channelinfo[chan].data += channelinfo[chan].stepremainder >> 16; + // Limit to LSB??? + channelinfo[chan].stepremainder &= 0xffff; + + // Check whether we are done. + if (channelinfo[chan].data >= channelinfo[chan].enddata) + stopchan(chan); + } + } + + // Clamp to range. Left hardware channel. + // Has been char instead of short. + // if (dl > 127) *leftout = 127; + // else if (dl < -128) *leftout = -128; + // else *leftout = dl; + + if (dl > SHRT_MAX) + *leftout = SHRT_MAX; + else if (dl < SHRT_MIN) + *leftout = SHRT_MIN; + else + *leftout = (signed short)dl; + + // Same for right hardware channel. + if (dr > SHRT_MAX) + *rightout = SHRT_MAX; + else if (dr < SHRT_MIN) + *rightout = SHRT_MIN; + else + *rightout = (signed short)dr; + + // Increment current pointers in stream + leftout += step; + rightout += step; + } +#endif +} + +void I_ShutdownSound(void) +{ + if (sound_inited) { + lprintf(LO_INFO, "I_ShutdownSound: "); +#ifdef HAVE_MIXER + Mix_CloseAudio(); +#else + SDL_CloseAudio(); +#endif + lprintf(LO_INFO, "\n"); + sound_inited = false; + } +} + +//static SDL_AudioSpec audio; + +// Hack! Fix this if real SDL sound is reintroduced. +#define AUDIO_S16MSB 0 +#define AUDIO_S16LSB 0 + + +void I_InitSound(void) +{ +#ifdef HAVE_MIXER + int audio_rate; + uint16_t audio_format; + int audio_channels; + int audio_buffers; + + if (sound_inited) + I_ShutdownSound(); + + // Secure and configure sound device first. + lprintf(LO_INFO,"I_InitSound: "); + + /* Initialize variables */ + audio_rate = snd_samplerate; +#if ( SDL_BYTEORDER == SDL_BIG_ENDIAN ) + audio_format = AUDIO_S16MSB; +#else + audio_format = AUDIO_S16LSB; +#endif + audio_channels = 2; + SAMPLECOUNT = 512; + audio_buffers = SAMPLECOUNT*snd_samplerate/11025; + + if (Mix_OpenAudio(audio_rate, audio_format, audio_channels, audio_buffers) < 0) { + lprintf(LO_INFO,"couldn't open audio with desired format\n"); + return; + } + sound_inited = true; + SAMPLECOUNT = audio_buffers; + Mix_SetPostMix(I_UpdateSound, NULL); + lprintf(LO_INFO," configured audio device with %d samples/slice\n", SAMPLECOUNT); +#else + SDL_AudioSpec audio; + + // Secure and configure sound device first. + lprintf(LO_INFO,"I_InitSound: "); + + // Open the audio device + audio.freq = snd_samplerate; +#if ( SDL_BYTEORDER == SDL_BIG_ENDIAN ) + audio.format = AUDIO_S16MSB; +#else + audio.format = AUDIO_S16LSB; +#endif + audio.channels = 2; + audio.samples = SAMPLECOUNT*snd_samplerate/11025; + audio.callback = I_UpdateSound; + if ( SDL_OpenAudio(&audio, NULL) < 0 ) { + lprintf(LO_INFO,"couldn't open audio with desired format\n"); + return; + } + SAMPLECOUNT = audio.samples; + lprintf(LO_INFO," configured audio device with %d samples/slice\n", SAMPLECOUNT); +#endif + + if (first_sound_init) { + atexit(I_ShutdownSound); + first_sound_init = false; + } + + if (!nomusicparm) + I_InitMusic(); + + // Finished initialization. + lprintf(LO_INFO,"I_InitSound: sound module ready\n"); +#ifndef HAVE_MIXER + SDL_PauseAudio(0); +#endif +} + + + +// +// MUSIC API. +// + +#ifndef HAVE_OWN_MUSIC + +#ifdef HAVE_MIXER +#include "SDL_mixer.h" +#include "mmus2mid.h" + +static Mix_Music *music[2] = { NULL, NULL }; + +char* music_tmp = NULL; /* cph - name of music temporary file */ + +#endif + +void I_ShutdownMusic(void) +{ +#ifdef HAVE_MIXER + if (music_tmp) { + //unlink(music_tmp); + //lprintf(LO_DEBUG, "I_ShutdownMusic: removing %s\n", music_tmp); + free(music_tmp); + music_tmp = NULL; + } +#endif +} + +#ifdef IPHONE + +const char * SysIphoneGetTempDir(); +static char iphoneMusicPath[PATH_MAX]; + +#endif + +void I_InitMusic(void) +{ + // Since we can load different IWADs in the same run of the iOS game, we need to clear + // the cached lumpnums for all the music, since they differ in different IWADs. + for ( int i = 0; i < NUMMUSIC; ++i ) { + S_music[i].lumpnum = 0; + } + +#ifdef HAVE_MIXER + if (!music_tmp) { +#ifndef _WIN32 + #ifdef IPHONE + + iphoneMusicPath[0] = '\0'; + strcat( iphoneMusicPath, SysIphoneGetTempDir() ); + strcat( iphoneMusicPath, "prboom-music-XXXXXX" ); + + music_tmp = strdup(iphoneMusicPath); + #else + music_tmp = strdup("/tmp/prboom-music-XXXXXX"); + #endif + { + int fd = mkstemp(music_tmp); + if (fd<0) { + lprintf(LO_ERROR, "I_InitMusic: failed to create music temp file %s", music_tmp); + free(music_tmp); return; + } else + close(fd); + } +#else /* !_WIN32 */ + music_tmp = strdup("doom.tmp"); +#endif + atexit(I_ShutdownMusic); + } +#endif +} + +extern int mus_pause_opt; // From m_misc.c +extern bool mus_on; + +void I_PlaySong(int handle, int looping) +{ +#ifdef HAVE_MIXER + if ( music[handle] && mus_on ) { + Mix_FadeInMusic(music[handle], looping ? -1 : 0, 500); + } + +#endif +} + +void I_PauseSong (int handle) +{ +#ifdef HAVE_MIXER + switch(mus_pause_opt) { + case 0: + I_StopSong(handle); + break; + case 1: + Mix_PauseMusic(); + break; + } +#endif + // Default - let music continue +} + +void I_ResumeSong (int handle) +{ +#ifdef HAVE_MIXER + switch(mus_pause_opt) { + case 0: + I_PlaySong(handle,1); + break; + case 1: + Mix_ResumeMusic(); + break; + } +#endif + /* Otherwise, music wasn't stopped */ +} + +void I_StopSong(int handle) +{ +#ifdef HAVE_MIXER + Mix_FadeOutMusic(500); +#endif +} + +void I_UnRegisterSong(int handle) +{ +#ifdef HAVE_MIXER + if ( music[handle] ) { + Mix_FreeMusic(music[handle]); + music[handle] = NULL; + } +#endif +} + +int I_RegisterSong(const void *data, size_t len) +{ +#ifdef HAVE_MIXER + MIDI *mididata; + FILE *midfile; + + if ( len < 32 ) + return 0; // the data should at least as big as the MUS header + if ( music_tmp == NULL ) + return 0; + midfile = fopen(music_tmp, "wb"); + if ( midfile == NULL ) { + lprintf(LO_ERROR,"Couldn't write MIDI to %s\n", music_tmp); + return 0; + } + /* Convert MUS chunk to MIDI? */ + if ( memcmp(data, "MUS", 3) == 0 ) + { + UBYTE *mid; + int midlen; + + mididata = malloc(sizeof(MIDI)); + int musResult = mmus2mid(data, mididata, 89, 0); + if ( musResult != 0 ) { + printf( "Failed to conver MUS to MIDI: %s\n", music_tmp ); + } + MIDIToMidi(mididata,&mid,&midlen); + M_WriteFile(music_tmp,mid,midlen); + free(mid); + free_mididata(mididata); + free(mididata); + } else { + fwrite(data, len, 1, midfile); + } + fclose(midfile); + + music[0] = Mix_LoadMUS(music_tmp); + if ( music[0] == NULL ) { + lprintf(LO_ERROR,"Couldn't load MIDI from %s: %s\n", music_tmp, Mix_GetError()); + } +#endif + return (0); +} + +// cournia - try to load a music file into SDL_Mixer +// returns true if could not load the file +int I_RegisterMusic( const char* filename, musicinfo_t *song ) +{ +#ifdef HAVE_MIXER + if (!filename) return 1; + if (!song) return 1; + music[0] = Mix_LoadMUS(filename); + if (music[0] == NULL) + { + lprintf(LO_WARN,"Couldn't load music from %s: %s\nAttempting to load default MIDI music.\n", filename, Mix_GetError()); + return 1; + } + else + { + song->data = 0; + song->handle = 0; + song->lumpnum = 0; + return 0; + } +#else + return 1; +#endif +} + +void I_SetMusicVolume(int volume) +{ +#ifdef HAVE_MIXER + Mix_VolumeMusic(volume*8); +#endif +} + +#endif /* HAVE_OWN_MUSIC */ + diff --git a/common/prboom/SDL_opengl.h b/common/prboom/SDL_opengl.h new file mode 100755 index 0000000..a118a1a --- /dev/null +++ b/common/prboom/SDL_opengl.h @@ -0,0 +1,215 @@ +/* + * SDL_opengl.h + * doom + * + * Created by John Carmack on 4/13/09. + * Copyright 2009 idSoftware. All rights reserved. + * + * iPhone glue to get the prBoom code compiling + * Replaces SDL_opengl.h + */ +#ifndef __SDL_OPENGL_H__ +#define __SDL_OPENGL_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define GLAPIENTRY + +// no colorTable in ES +typedef void (* PFNGLCOLORTABLEEXTPROC) (GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); + +static inline GLubyte *gluErrorString( int err ) { (void)err; return (GLubyte *)"GLU error"; } +static inline void *SDL_GL_GetProcAddress( const char * proc ) { (void)proc; return 0; } +static inline void SDL_GL_SwapBuffers() {} + +// we need to emulate immediate mode gl for ES +void glBegin( GLenum prim ); + +void glVertex3f( GLfloat x, GLfloat y, GLfloat z ); +void glVertex3fv( GLfloat *xyz ); +void glVertex2f( GLfloat x, GLfloat y ); +void glVertex2i( GLint x, GLint y ); + +void glTexCoord2i( GLint s, GLint t ); +void glTexCoord2f( GLfloat s, GLfloat t ); +void glTexCoord2fv( GLfloat *st ); + +void glEnd(); + +// Doom just uses state color for all draw calls, setting it once +// before a glBegin, rather than setting it each vertex, so we +// don't need to emulate the color functions. +//#defne VERTEX_COLOR +#ifdef VERTEX_COLOR +void glColor4ub( GLubyte r, GLubyte g, GLubyte b, GLubyte a ); +void glColor4f( GLfloat r, GLfloat g, GLfloat b, GLfloat a ); +void glColor4fv( GLfloat *rgba ); +void glColor3f( GLfloat r, GLfloat g, GLfloat b ); +#endif + +// GLES only defines glColor4ub and glColor4f, so define the others in terms of that +#define glColor4fv(x) glColor4f(x[0],x[1],x[2],x[3]) +#define glColor4ubv(x) glColor4ub(x[0],x[1],x[2],x[3]) +#define glColor3f(r,g,b) glColor4f(r,g,b,1) + + +// The width and height need to be flipped for iPhone landscape mode, +// so redefine these functions to something that can do the work behind +// the scenes. +void landscapeViewport( GLint x, GLint y, GLsizei width, GLsizei height ); +void landscapeScissor( GLint x, GLint y, GLsizei width, GLsizei height ); +#define glViewport landscapeViewport +#define glScissor landscapeScissor + +// ES made matching fixed and floating versions of some functions +#define glClearDepth glClearDepthf +#define glOrtho glOrthof +#define glFogi glFogx + +// no GLdouble in ES, but needed for glu tesselator +typedef double GLdouble; + +// ES doesn't have the messy clamp-to-half-border mode +#define GL_CLAMP GL_CLAMP_TO_EDGE + +// this is the internal format used by the prBoom gl code +// ES doesn't allow format conversions between external and internal, +// so we need to manually convert to 5551 before doing glTexSubImage +#define GL_RGBA8 GL_RGBA +#define GL_RGBA2 GL_RGBA + +// not available in ES, so prBoom's skies must be implemeted differently +static inline void glTexGenfv( int a, int b, void * c ) { (void)a; (void)b; (void)c; } +static inline void glTexGenf( int a, int b, int c ) { (void)a; (void)b; (void)c; } + +// texGen enums not present in ES +#define GL_S 0x2000 +#define GL_T 0x2001 +#define GL_R 0x2002 +#define GL_Q 0x2003 + +#define GL_OBJECT_LINEAR 0x2401 +#define GL_OBJECT_PLANE 0x2501 +#define GL_EYE_LINEAR 0x2400 +#define GL_EYE_PLANE 0x2502 + +#define GL_TEXTURE_GEN_MODE 0x2500 + +#define GL_TEXTURE_GEN_S 0x0C60 +#define GL_TEXTURE_GEN_T 0x0C61 +#define GL_TEXTURE_GEN_R 0x0C62 +#define GL_TEXTURE_GEN_Q 0x0C63 + +// other extensions not present in ES +// Whlle the iPhone exports the extension for paletted +// textures, it isn't actually supported in hardware, so +// they are expanded internally on glTexImage2D, making their +// use completely counterproductive. +#define GL_SHARED_TEXTURE_PALETTE_EXT 0x81FB +#define GL_COLOR_INDEX 0x1900 +#define GL_COLOR_INDEX8_EXT 0x80E5 + +//=========================== +// all this for the glu tesselator, used by prBoom to make drawable sector geometry +//=========================== + +#include "../libtess/tess.h" + +/* TessCallback */ +#define GLU_TESS_BEGIN 100100 +#define GLU_BEGIN 100100 +#define GLU_TESS_VERTEX 100101 +#define GLU_VERTEX 100101 +#define GLU_TESS_END 100102 +#define GLU_END 100102 +#define GLU_TESS_ERROR 100103 +#define GLU_TESS_EDGE_FLAG 100104 +#define GLU_EDGE_FLAG 100104 +#define GLU_TESS_COMBINE 100105 +#define GLU_TESS_BEGIN_DATA 100106 +#define GLU_TESS_VERTEX_DATA 100107 +#define GLU_TESS_END_DATA 100108 +#define GLU_TESS_ERROR_DATA 100109 +#define GLU_TESS_EDGE_FLAG_DATA 100110 +#define GLU_TESS_COMBINE_DATA 100111 + + +/* TessContour */ +#define GLU_CW 100120 +#define GLU_CCW 100121 +#define GLU_INTERIOR 100122 +#define GLU_EXTERIOR 100123 +#define GLU_UNKNOWN 100124 + +/* TessProperty */ +#define GLU_TESS_WINDING_RULE 100140 +#define GLU_TESS_BOUNDARY_ONLY 100141 +#define GLU_TESS_TOLERANCE 100142 + +/* TessError */ +#define GLU_TESS_ERROR1 100151 +#define GLU_TESS_ERROR2 100152 +#define GLU_TESS_ERROR3 100153 +#define GLU_TESS_ERROR4 100154 +#define GLU_TESS_ERROR5 100155 +#define GLU_TESS_ERROR6 100156 +#define GLU_TESS_ERROR7 100157 +#define GLU_TESS_ERROR8 100158 +#define GLU_TESS_MISSING_BEGIN_POLYGON 100151 +#define GLU_TESS_MISSING_BEGIN_CONTOUR 100152 +#define GLU_TESS_MISSING_END_POLYGON 100153 +#define GLU_TESS_MISSING_END_CONTOUR 100154 +#define GLU_TESS_COORD_TOO_LARGE 100155 +#define GLU_TESS_NEED_COMBINE_CALLBACK 100156 + +/* TessWinding */ +#define GLU_TESS_WINDING_ODD 100130 +#define GLU_TESS_WINDING_NONZERO 100131 +#define GLU_TESS_WINDING_POSITIVE 100132 +#define GLU_TESS_WINDING_NEGATIVE 100133 +#define GLU_TESS_WINDING_ABS_GEQ_TWO 100134 + +/* ErrorCode */ +#define GLU_INVALID_ENUM 100900 +#define GLU_INVALID_VALUE 100901 +#define GLU_OUT_OF_MEMORY 100902 +#define GLU_INCOMPATIBLE_GL_VERSION 100903 +#define GLU_INVALID_OPERATION 100904 + +#define GLAPI +#define GLAPIENTRYP + +typedef struct GLUtesselator GLUtesselator; +typedef GLUtesselator GLUtesselatorObj; +typedef GLUtesselator GLUtriangulatorObj; + +#define GLU_TESS_MAX_COORD 1.0e150 + +/* Internal convenience typedefs */ +typedef void (GLAPIENTRYP _GLUfuncptr)(); + +GLAPI void GLAPIENTRY gluTessBeginContour (GLUtesselator* tess); +GLAPI void GLAPIENTRY gluTessBeginPolygon (GLUtesselator* tess, GLvoid* data); +GLAPI void GLAPIENTRY gluTessCallback (GLUtesselator* tess, GLenum which, _GLUfuncptr CallBackFunc); +GLAPI void GLAPIENTRY gluTessEndContour (GLUtesselator* tess); +GLAPI void GLAPIENTRY gluTessEndPolygon (GLUtesselator* tess); +GLAPI void GLAPIENTRY gluTessNormal (GLUtesselator* tess, GLdouble valueX, GLdouble valueY, GLdouble valueZ); +GLAPI void GLAPIENTRY gluTessProperty (GLUtesselator* tess, GLenum which, GLdouble data); +GLAPI void GLAPIENTRY gluTessVertex (GLUtesselator* tess, GLdouble *location, GLvoid* data); + +GLUtesselator * GLAPIENTRY gluNewTess( void ); +void GLAPIENTRY gluDeleteTess( GLUtesselator *tess ); + +#ifdef __cplusplus +} +#endif + + +#endif + + diff --git a/common/prboom/am_map.c b/common/prboom/am_map.c new file mode 100755 index 0000000..875dd84 --- /dev/null +++ b/common/prboom/am_map.c @@ -0,0 +1,1595 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * the automap code + * + *----------------------------------------------------------------------------- + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "doomstat.h" +#include "st_stuff.h" +#include "r_main.h" +#include "p_setup.h" +#include "p_maputl.h" +#include "w_wad.h" +#include "v_video.h" +#include "p_spec.h" +#include "am_map.h" +#include "dstrings.h" +#include "d_deh.h" // Ty 03/27/98 - externalizations +#include "lprintf.h" // jff 08/03/98 - declaration of lprintf +#include "g_game.h" + +// IPHONE +#include "gles_glue.h" + +void iphoneSet2D( void ); + + +//jff 1/7/98 default automap colors added +int mapcolor_back; // map background +int mapcolor_grid; // grid lines color +int mapcolor_wall; // normal 1s wall color +int mapcolor_fchg; // line at floor height change color +int mapcolor_cchg; // line at ceiling height change color +int mapcolor_clsd; // line at sector with floor=ceiling color +int mapcolor_rkey; // red key color +int mapcolor_bkey; // blue key color +int mapcolor_ykey; // yellow key color +int mapcolor_rdor; // red door color (diff from keys to allow option) +int mapcolor_bdor; // blue door color (of enabling one but not other ) +int mapcolor_ydor; // yellow door color +int mapcolor_tele; // teleporter line color +int mapcolor_secr; // secret sector boundary color +int mapcolor_exit; // jff 4/23/98 add exit line color +int mapcolor_unsn; // computer map unseen line color +int mapcolor_flat; // line with no floor/ceiling changes +int mapcolor_sprt; // general sprite color +int mapcolor_item; // item sprite color +int mapcolor_frnd; // friendly sprite color +int mapcolor_enemy; // enemy sprite color +int mapcolor_hair; // crosshair color +int mapcolor_sngl; // single player arrow color +int mapcolor_plyr[4] = { 112, 88, 64, 32 }; // colors for player arrows in multiplayer + +//jff 3/9/98 add option to not show secret sectors until entered +int map_secret_after; +//jff 4/3/98 add symbols for "no-color" for disable and "black color" for black +#define NC 0 +#define BC 247 + +// drawing stuff +#define FB 0 + +// scale on entry +#define INITSCALEMTOF (.2*FRACUNIT) +// how much the automap moves window per tic in frame-buffer coordinates +// moves 140 pixels in 1 second +#define F_PANINC 4 +// how much zoom-in per tic +// goes to 2x in 1 second +#define M_ZOOMIN ((int) (1.02*FRACUNIT)) +// how much zoom-out per tic +// pulls out to 0.5x in 1 second +#define M_ZOOMOUT ((int) (FRACUNIT/1.02)) + +#define PLAYERRADIUS (16*(1<>16) +// translates between frame-buffer and map coordinates +#define CXMTOF(x) (f_x + MTOF((x)-m_x)) +#define CYMTOF(y) (f_y + (f_h - MTOF((y)-m_y))) + +typedef struct +{ + mpoint_t a, b; +} mline_t; + +// +// The vector graphics for the automap. +// A line drawing of the player pointing right, +// starting from the middle. +// +#define R ((8*PLAYERRADIUS)/7) +mline_t player_arrow[] = +{ + { { -R+R/8, 0 }, { R, 0 } }, // ----- + { { R, 0 }, { R-R/2, R/4 } }, // -----> + { { R, 0 }, { R-R/2, -R/4 } }, + { { -R+R/8, 0 }, { -R-R/8, R/4 } }, // >----> + { { -R+R/8, 0 }, { -R-R/8, -R/4 } }, + { { -R+3*R/8, 0 }, { -R+R/8, R/4 } }, // >>---> + { { -R+3*R/8, 0 }, { -R+R/8, -R/4 } } +}; +#undef R +#define NUMPLYRLINES (sizeof(player_arrow)/sizeof(mline_t)) + +#define R ((8*PLAYERRADIUS)/7) +mline_t cheat_player_arrow[] = +{ // killough 3/22/98: He's alive, Jim :) + { { -R+R/8, 0 }, { R, 0 } }, // ----- + { { R, 0 }, { R-R/2, R/4 } }, // -----> + { { R, 0 }, { R-R/2, -R/4 } }, + { { -R+R/8, 0 }, { -R-R/8, R/4 } }, // >----> + { { -R+R/8, 0 }, { -R-R/8, -R/4 } }, + { { -R+3*R/8, 0 }, { -R+R/8, R/4 } }, // >>---> + { { -R+3*R/8, 0 }, { -R+R/8, -R/4 } }, + { { -R/10-R/6, R/4}, {-R/10-R/6, -R/4} }, // J + { { -R/10-R/6, -R/4}, {-R/10-R/6-R/8, -R/4} }, + { { -R/10-R/6-R/8, -R/4}, {-R/10-R/6-R/8, -R/8} }, + { { -R/10, R/4}, {-R/10, -R/4}}, // F + { { -R/10, R/4}, {-R/10+R/8, R/4}}, + { { -R/10+R/4, R/4}, {-R/10+R/4, -R/4}}, // F + { { -R/10+R/4, R/4}, {-R/10+R/4+R/8, R/4}}, +}; +#undef R +#define NUMCHEATPLYRLINES (sizeof(cheat_player_arrow)/sizeof(mline_t)) + +#define R (FRACUNIT) +mline_t triangle_guy[] = +{ +{ { (fixed_t)(-.867*R), (fixed_t)(-.5*R) }, { (fixed_t)( .867*R), (fixed_t)(-.5*R) } }, +{ { (fixed_t)( .867*R), (fixed_t)(-.5*R) }, { (fixed_t)(0 ), (fixed_t)( R) } }, +{ { (fixed_t)(0 ), (fixed_t)( R) }, { (fixed_t)(-.867*R), (fixed_t)(-.5*R) } } +}; +#undef R +#define NUMTRIANGLEGUYLINES (sizeof(triangle_guy)/sizeof(mline_t)) + +//jff 1/5/98 new symbol for keys on automap +#define R (FRACUNIT) +mline_t cross_mark[] = +{ + { { -R, 0 }, { R, 0} }, + { { 0, -R }, { 0, R } }, +}; +#undef R +#define NUMCROSSMARKLINES (sizeof(cross_mark)/sizeof(mline_t)) +//jff 1/5/98 end of new symbol + +#define R (FRACUNIT) +mline_t thintriangle_guy[] = +{ +{ { (fixed_t)(-.5*R), (fixed_t)(-.7*R) }, { (fixed_t)( R), (fixed_t)( 0) } }, +{ { (fixed_t)( R), (fixed_t)( 0) }, { (fixed_t)(-.5*R), (fixed_t)( .7*R) } }, +{ { (fixed_t)(-.5*R), (fixed_t)( .7*R) }, { (fixed_t)(-.5*R), (fixed_t)(-.7*R) } } +}; +#undef R +#define NUMTHINTRIANGLEGUYLINES (sizeof(thintriangle_guy)/sizeof(mline_t)) + +int ddt_cheating = 0; // killough 2/7/98: make global, rename to ddt_* + +static int leveljuststarted = 1; // kluge until AM_LevelInit() is called + +enum automapmode_e automapmode; // Mode that the automap is in + +// location of window on screen +static int f_x; +static int f_y; + +// size of window on screen +static int f_w; +static int f_h; + +static mpoint_t m_paninc; // how far the window pans each tic (map coords) +static fixed_t mtof_zoommul; // how far the window zooms each tic (map coords) +static fixed_t ftom_zoommul; // how far the window zooms each tic (fb coords) + +/* JDC static */ fixed_t m_x, m_y; // LL x,y window location on the map (map coords) +/* JDC static */ fixed_t m_x2, m_y2; // UR x,y window location on the map (map coords) + +// +// width/height of window on map (map coords) +// +/* JDC static */ fixed_t m_w; +/* JDC static */ fixed_t m_h; + +// based on level size +static fixed_t min_x; +static fixed_t min_y; +static fixed_t max_x; +static fixed_t max_y; + +static fixed_t max_w; // max_x-min_x, +static fixed_t max_h; // max_y-min_y + +// based on player size +static fixed_t min_w; +static fixed_t min_h; + + +/* JDC static */ fixed_t min_scale_mtof; // used to tell when to stop zooming out +/* JDC static */ fixed_t max_scale_mtof; // used to tell when to stop zooming in + +// old stuff for recovery later +static fixed_t old_m_w, old_m_h; +static fixed_t old_m_x, old_m_y; + +// old location used by the Follower routine +static mpoint_t f_oldloc; + +// used by MTOF to scale from map-to-frame-buffer coords +/* JDC static */ fixed_t scale_mtof = (fixed_t)INITSCALEMTOF; +// used by FTOM to scale from frame-buffer-to-map coords (=1/scale_mtof) +/* JDC static */ fixed_t scale_ftom; + +static player_t *plr; // the player represented by an arrow + +// killough 2/22/98: Remove limit on automap marks, +// and make variables external for use in savegames. + +mpoint_t *markpoints = NULL; // where the points are +int markpointnum = 0; // next point to be assigned (also number of points now) +int markpointnum_max = 0; // killough 2/22/98 + +static boolean stopped = true; + +// +// AM_activateNewScale() +// +// Changes the map scale after zooming or translating +// +// Passed nothing, returns nothing +// +static void AM_activateNewScale(void) +{ + m_x += m_w/2; + m_y += m_h/2; + m_w = FTOM(f_w); + m_h = FTOM(f_h); + m_x -= m_w/2; + m_y -= m_h/2; + m_x2 = m_x + m_w; + m_y2 = m_y + m_h; +} + +// +// AM_saveScaleAndLoc() +// +// Saves the current center and zoom +// Affects the variables that remember old scale and loc +// +// Passed nothing, returns nothing +// +static void AM_saveScaleAndLoc(void) +{ + old_m_x = m_x; + old_m_y = m_y; + old_m_w = m_w; + old_m_h = m_h; +} + +// +// AM_restoreScaleAndLoc() +// +// restores the center and zoom from locally saved values +// Affects global variables for location and scale +// +// Passed nothing, returns nothing +// +static void AM_restoreScaleAndLoc(void) +{ + m_w = old_m_w; + m_h = old_m_h; + if (!(automapmode & am_follow)) + { + m_x = old_m_x; + m_y = old_m_y; + } + else + { + m_x = (plr->mo->x >> FRACTOMAPBITS) - m_w/2;//e6y + m_y = (plr->mo->y >> FRACTOMAPBITS) - m_h/2;//e6y + } + m_x2 = m_x + m_w; + m_y2 = m_y + m_h; + + // Change the scaling multipliers + scale_mtof = FixedDiv(f_w<= markpointnum_max) + markpoints = realloc(markpoints, + (markpointnum_max = markpointnum_max ? + markpointnum_max*2 : 16) * sizeof(*markpoints)); + + markpoints[markpointnum].x = m_x + m_w/2; + markpoints[markpointnum].y = m_y + m_h/2; + markpointnum++; +} + +// +// AM_findMinMaxBoundaries() +// +// Determines bounding box of all vertices, +// sets global variables controlling zoom range. +// +// Passed nothing, returns nothing +// +static void AM_findMinMaxBoundaries(void) +{ + int i; + fixed_t a; + fixed_t b; + + min_x = min_y = INT_MAX; + max_x = max_y = -INT_MAX; + + for (i=0;i max_x) + max_x = vertexes[i].x; + + if (vertexes[i].y < min_y) + min_y = vertexes[i].y; + else if (vertexes[i].y > max_y) + max_y = vertexes[i].y; + } + + max_w = (max_x >>= FRACTOMAPBITS) - (min_x >>= FRACTOMAPBITS);//e6y + max_h = (max_y >>= FRACTOMAPBITS) - (min_y >>= FRACTOMAPBITS);//e6y + + min_w = 2*PLAYERRADIUS; // const? never changed? + min_h = 2*PLAYERRADIUS; + + a = FixedDiv(f_w< max_x) + m_x = max_x - m_w/2; + else if (m_x + m_w/2 < min_x) + m_x = min_x - m_w/2; + + if (m_y + m_h/2 > max_y) + m_y = max_y - m_h/2; + else if (m_y + m_h/2 < min_y) + m_y = min_y - m_h/2; + + m_x2 = m_x + m_w; + m_y2 = m_y + m_h; +} + + +// +// AM_initVariables() +// +// Initialize the variables for the automap +// +// Affects the automap global variables +// Status bar is notified that the automap has been entered +// Passed nothing, returns nothing +// +static void AM_initVariables(void) +{ + int pnum; + static event_t st_notify = { ev_keyup, AM_MSGENTERED, 0, 0 }; + + automapmode |= am_active; + + f_oldloc.x = INT_MAX; + + m_paninc.x = m_paninc.y = 0; + ftom_zoommul = FRACUNIT; + mtof_zoommul = FRACUNIT; + + m_w = FTOM(f_w); + m_h = FTOM(f_h); + + // find player to center on initially + if (!playeringame[pnum = consoleplayer]) + for (pnum=0;pnummo->x >> FRACTOMAPBITS) - m_w/2;//e6y + m_y = (plr->mo->y >> FRACTOMAPBITS) - m_h/2;//e6y + AM_changeWindowLoc(); + + // for saving & restoring + old_m_x = m_x; + old_m_y = m_y; + old_m_w = m_w; + old_m_h = m_h; + + // inform the status bar of the change + ST_Responder(&st_notify); +} + +// +// AM_loadPics() +// +static void AM_loadPics(void) +{ + // cph - mark numbers no longer needed cached +} + +// +// AM_unloadPics() +// +static void AM_unloadPics(void) +{ + // cph - mark numbers no longer needed cached +} + +// +// AM_clearMarks() +// +// Sets the number of marks to 0, thereby clearing them from the display +// +// Affects the global variable markpointnum +// Passed nothing, returns nothing +// +void AM_clearMarks(void) +{ + markpointnum = 0; +} + +// +// AM_LevelInit() +// +// Initialize the automap at the start of a new level +// should be called at the start of every level +// +// Passed nothing, returns nothing +// Affects automap's global variables +// +// CPhipps - get status bar height from status bar code +static void AM_LevelInit(void) +{ + leveljuststarted = 0; + + f_x = f_y = 0; + f_w = SCREENWIDTH; // killough 2/7/98: get rid of finit_ vars + f_h = SCREENHEIGHT-ST_SCALED_HEIGHT;// to allow runtime setting of width/height + + AM_findMinMaxBoundaries(); + scale_mtof = FixedDiv(min_scale_mtof, (int) (0.7*FRACUNIT)); + if (scale_mtof > max_scale_mtof) + scale_mtof = min_scale_mtof; + scale_ftom = FixedDiv(FRACUNIT, scale_mtof); +} + +// +// AM_Stop() +// +// Cease automap operations, unload patches, notify status bar +// +// Passed nothing, returns nothing +// +void AM_Stop (void) +{ + static event_t st_notify = { 0, ev_keyup, AM_MSGEXITED, 0 }; + + AM_unloadPics(); + automapmode &= ~am_active; + ST_Responder(&st_notify); + stopped = true; +} + +// +// AM_Start() +// +// Start up automap operations, +// if a new level, or game start, (re)initialize level variables +// init map variables +// load mark patches +// +// Passed nothing, returns nothing +// +void AM_Start(void) +{ + static int lastlevel = -1, lastepisode = -1; + + if (!stopped) + AM_Stop(); + stopped = false; + if (lastlevel != gamemap || lastepisode != gameepisode) + { + AM_LevelInit(); + lastlevel = gamemap; + lastepisode = gameepisode; + } + AM_initVariables(); + AM_loadPics(); +} + +// +// AM_minOutWindowScale() +// +// Set the window scale to the maximum size +// +// Passed nothing, returns nothing +// +static void AM_minOutWindowScale(void) +{ + scale_mtof = min_scale_mtof; + scale_ftom = FixedDiv(FRACUNIT, scale_mtof); + AM_activateNewScale(); +} + +// +// AM_maxOutWindowScale(void) +// +// Set the window scale to the minimum size +// +// Passed nothing, returns nothing +// +static void AM_maxOutWindowScale(void) +{ + scale_mtof = max_scale_mtof; + scale_ftom = FixedDiv(FRACUNIT, scale_mtof); + AM_activateNewScale(); +} + +// +// AM_Responder() +// +// Handle events (user inputs) in automap mode +// +// Passed an input event, returns true if its handled +// +boolean AM_Responder +( event_t* ev ) +{ + int rc; + static int cheatstate=0; + static int bigstate=0; + int ch; // phares + + rc = false; + + if (!(automapmode & am_active)) + { + if (ev->type == ev_keydown && ev->data1 == key_map) // phares + { + AM_Start (); + rc = true; + } + } + else if (ev->type == ev_keydown) + { + rc = true; + ch = ev->data1; // phares + if (ch == key_map_right) // | + if (!(automapmode & am_follow)) // V + m_paninc.x = FTOM(F_PANINC); + else + rc = false; + else if (ch == key_map_left) + if (!(automapmode & am_follow)) + m_paninc.x = -FTOM(F_PANINC); + else + rc = false; + else if (ch == key_map_up) + if (!(automapmode & am_follow)) + m_paninc.y = FTOM(F_PANINC); + else + rc = false; + else if (ch == key_map_down) + if (!(automapmode & am_follow)) + m_paninc.y = -FTOM(F_PANINC); + else + rc = false; + else if (ch == key_map_zoomout) + { + mtof_zoommul = M_ZOOMOUT; + ftom_zoommul = M_ZOOMIN; + } + else if (ch == key_map_zoomin) + { + mtof_zoommul = M_ZOOMIN; + ftom_zoommul = M_ZOOMOUT; + } + else if (ch == key_map) + { + bigstate = 0; + AM_Stop (); + } + else if (ch == key_map_gobig) + { + bigstate = !bigstate; + if (bigstate) + { + AM_saveScaleAndLoc(); + AM_minOutWindowScale(); + } + else + AM_restoreScaleAndLoc(); + } + else if (ch == key_map_follow) + { + automapmode ^= am_follow; // CPhipps - put all automap mode stuff into one enum + f_oldloc.x = INT_MAX; + // Ty 03/27/98 - externalized + plr->message = (automapmode & am_follow) ? s_AMSTR_FOLLOWON : s_AMSTR_FOLLOWOFF; + } + else if (ch == key_map_grid) + { + automapmode ^= am_grid; // CPhipps + // Ty 03/27/98 - *not* externalized + plr->message = (automapmode & am_grid) ? s_AMSTR_GRIDON : s_AMSTR_GRIDOFF; + } + else if (ch == key_map_mark) + { + /* Ty 03/27/98 - *not* externalized + * cph 2001/11/20 - use doom_printf so we don't have our own buffer */ + doom_printf("%s %d", s_AMSTR_MARKEDSPOT, markpointnum); + AM_addMark(); + } + else if (ch == key_map_clear) + { + AM_clearMarks(); // Ty 03/27/98 - *not* externalized + plr->message = s_AMSTR_MARKSCLEARED; // ^ + } // | + else if (ch == key_map_rotate) { + automapmode ^= am_rotate; + plr->message = (automapmode & am_rotate) ? s_AMSTR_ROTATEON : s_AMSTR_ROTATEOFF; + } + else if (ch == key_map_overlay) { + automapmode ^= am_overlay; + plr->message = (automapmode & am_overlay) ? s_AMSTR_OVERLAYON : s_AMSTR_OVERLAYOFF; + } + else // phares + { + cheatstate=0; + rc = false; + } + } + else if (ev->type == ev_keyup) + { + rc = false; + ch = ev->data1; + if (ch == key_map_right) + { + if (!(automapmode & am_follow)) + m_paninc.x = 0; + } + else if (ch == key_map_left) + { + if (!(automapmode & am_follow)) + m_paninc.x = 0; + } + else if (ch == key_map_up) + { + if (!(automapmode & am_follow)) + m_paninc.y = 0; + } + else if (ch == key_map_down) + { + if (!(automapmode & am_follow)) + m_paninc.y = 0; + } + else if ((ch == key_map_zoomout) || (ch == key_map_zoomin)) + { + mtof_zoommul = FRACUNIT; + ftom_zoommul = FRACUNIT; + } + } + return rc; +} + +// +// AM_rotate() +// +// Rotation in 2D. +// Used to rotate player arrow line character. +// +// Passed the coordinates of a point, and an angle +// Returns the coordinates rotated by the angle +// +// CPhipps - made static & enhanced for automap rotation + +static void AM_rotate(fixed_t* x, fixed_t* y, angle_t a, fixed_t xorig, fixed_t yorig) +{ + fixed_t tmpx; + + //e6y + xorig>>=FRACTOMAPBITS; + yorig>>=FRACTOMAPBITS; + + tmpx = + FixedMul(*x - xorig,finecosine[a>>ANGLETOFINESHIFT]) + - FixedMul(*y - yorig,finesine[a>>ANGLETOFINESHIFT]); + + *y = yorig + + FixedMul(*x - xorig,finesine[a>>ANGLETOFINESHIFT]) + + FixedMul(*y - yorig,finecosine[a>>ANGLETOFINESHIFT]); + + *x = tmpx + xorig; +} + +// +// AM_changeWindowScale() +// +// Automap zooming +// +// Passed nothing, returns nothing +// +static void AM_changeWindowScale(void) +{ + // Change the scaling multipliers + scale_mtof = FixedMul(scale_mtof, mtof_zoommul); + scale_ftom = FixedDiv(FRACUNIT, scale_mtof); + + if (scale_mtof < min_scale_mtof) + AM_minOutWindowScale(); + else if (scale_mtof > max_scale_mtof) + AM_maxOutWindowScale(); + else + AM_activateNewScale(); +} + +// +// AM_doFollowPlayer() +// +// Turn on follow mode - the map scrolls opposite to player motion +// +// Passed nothing, returns nothing +// +static void AM_doFollowPlayer(void) +{ + if (f_oldloc.x != plr->mo->x || f_oldloc.y != plr->mo->y) + { + m_x = FTOM(MTOF(plr->mo->x >> FRACTOMAPBITS)) - m_w/2;//e6y + m_y = FTOM(MTOF(plr->mo->y >> FRACTOMAPBITS)) - m_h/2;//e6y + m_x2 = m_x + m_w; + m_y2 = m_y + m_h; + f_oldloc.x = plr->mo->x; + f_oldloc.y = plr->mo->y; + } +} + +// +// AM_Ticker() +// +// Updates on gametic - enter follow mode, zoom, or change map location +// +// Passed nothing, returns nothing +// +void AM_Ticker (void) +{ + if (!(automapmode & am_active)) + return; + + if (automapmode & am_follow) + AM_doFollowPlayer(); + + // Change the zoom if necessary + if (ftom_zoommul != FRACUNIT) + AM_changeWindowScale(); + + // Change x,y location + if (m_paninc.x || m_paninc.y) + AM_changeWindowLoc(); +} + +// +// AM_clipMline() +// +// Automap clipping of lines. +// +// Based on Cohen-Sutherland clipping algorithm but with a slightly +// faster reject and precalculated slopes. If the speed is needed, +// use a hash algorithm to handle the common cases. +// +// Passed the line's coordinates on map and in the frame buffer performs +// clipping on them in the lines frame coordinates. +// Returns true if any part of line was not clipped +// +static boolean AM_clipMline +( mline_t* ml, + fline_t* fl ) +{ + enum + { + LEFT =1, + RIGHT =2, + BOTTOM =4, + TOP =8 + }; + + register int outcode1 = 0; + register int outcode2 = 0; + register int outside; + + fpoint_t tmp; + int dx; + int dy; + + +#define DOOUTCODE(oc, mx, my) \ + (oc) = 0; \ + if ((my) < 0) (oc) |= TOP; \ + else if ((my) >= f_h) (oc) |= BOTTOM; \ + if ((mx) < 0) (oc) |= LEFT; \ + else if ((mx) >= f_w) (oc) |= RIGHT; + + + // do trivial rejects and outcodes + if (ml->a.y > m_y2) + outcode1 = TOP; + else if (ml->a.y < m_y) + outcode1 = BOTTOM; + + if (ml->b.y > m_y2) + outcode2 = TOP; + else if (ml->b.y < m_y) + outcode2 = BOTTOM; + + if (outcode1 & outcode2) + return false; // trivially outside + + if (ml->a.x < m_x) + outcode1 |= LEFT; + else if (ml->a.x > m_x2) + outcode1 |= RIGHT; + + if (ml->b.x < m_x) + outcode2 |= LEFT; + else if (ml->b.x > m_x2) + outcode2 |= RIGHT; + + if (outcode1 & outcode2) + return false; // trivially outside + + // transform to frame-buffer coordinates. + fl->a.x = CXMTOF(ml->a.x); + fl->a.y = CYMTOF(ml->a.y); + fl->b.x = CXMTOF(ml->b.x); + fl->b.y = CYMTOF(ml->b.y); + + DOOUTCODE(outcode1, fl->a.x, fl->a.y); + DOOUTCODE(outcode2, fl->b.x, fl->b.y); + + if (outcode1 & outcode2) + return false; + + while (outcode1 | outcode2) + { + // may be partially inside box + // find an outside point + if (outcode1) + outside = outcode1; + else + outside = outcode2; + + // clip to each side + if (outside & TOP) + { + dy = fl->a.y - fl->b.y; + dx = fl->b.x - fl->a.x; + tmp.x = fl->a.x + (dx*(fl->a.y))/dy; + tmp.y = 0; + } + else if (outside & BOTTOM) + { + dy = fl->a.y - fl->b.y; + dx = fl->b.x - fl->a.x; + tmp.x = fl->a.x + (dx*(fl->a.y-f_h))/dy; + tmp.y = f_h-1; + } + else if (outside & RIGHT) + { + dy = fl->b.y - fl->a.y; + dx = fl->b.x - fl->a.x; + tmp.y = fl->a.y + (dy*(f_w-1 - fl->a.x))/dx; + tmp.x = f_w-1; + } + else if (outside & LEFT) + { + dy = fl->b.y - fl->a.y; + dx = fl->b.x - fl->a.x; + tmp.y = fl->a.y + (dy*(-fl->a.x))/dx; + tmp.x = 0; + } + + if (outside == outcode1) + { + fl->a = tmp; + DOOUTCODE(outcode1, fl->a.x, fl->a.y); + } + else + { + fl->b = tmp; + DOOUTCODE(outcode2, fl->b.x, fl->b.y); + } + + if (outcode1 & outcode2) + return false; // trivially outside + } + + return true; +} +#undef DOOUTCODE + +// +// AM_drawMline() +// +// Clip lines, draw visible parts of lines. +// +// Passed the map coordinates of the line, and the color to draw it +// Color -1 is special and prevents drawing. Color 247 is special and +// is translated to black, allowing Color 0 to represent feature disable +// in the defaults file. +// Returns nothing. +// +static void AM_drawMline +( mline_t* ml, + int color ) +{ + static fline_t fl; + + if (color==-1) // jff 4/3/98 allow not drawing any sort of line + return; // by setting its color to -1 + if (color==247) // jff 4/3/98 if color is 247 (xparent), use black + color=0; + + if (AM_clipMline(ml, &fl)) + V_DrawLine(&fl, color); // draws it on frame buffer using fb coords +} + +// +// AM_drawGrid() +// +// Draws blockmap aligned grid lines. +// +// Passed the color to draw the grid lines +// Returns nothing +// +static void AM_drawGrid(int color) +{ + fixed_t x, y; + fixed_t start, end; + mline_t ml; + + // Figure out start of vertical gridlines + start = m_x; + if ((start-bmaporgx)%(MAPBLOCKUNITS<> LockedKeyShift; + if (!type || type==7) + return 3; //any or all keys + else return (type-1)%3; + } + switch (type) // closed keyed door + { + case 26: case 32: case 99: case 133: + /*bluekey*/ + return 1; + case 27: case 34: case 136: case 137: + /*yellowkey*/ + return 2; + case 28: case 33: case 134: case 135: + /*redkey*/ + return 0; + default: + return -1; //not a keyed door + } +} + +// +// Determines visible lines, draws them. +// This is LineDef based, not LineSeg based. +// +// jff 1/5/98 many changes in this routine +// backward compatibility not needed, so just changes, no ifs +// addition of clauses for: +// doors opening, keyed door id, secret sectors, +// teleports, exit lines, key things +// ability to suppress any of added features or lines with no height changes +// +// support for gamma correction in automap abandoned +// +// jff 4/3/98 changed mapcolor_xxxx=0 as control to disable feature +// jff 4/3/98 changed mapcolor_xxxx=-1 to disable drawing line completely +// +static void AM_drawWalls(void) +{ + int i; + static mline_t l; + + // draw the unclipped visible portions of all lines + for (i=0;ix >> FRACTOMAPBITS;//e6y + l.a.y = lines[i].v1->y >> FRACTOMAPBITS;//e6y + l.b.x = lines[i].v2->x >> FRACTOMAPBITS;//e6y + l.b.y = lines[i].v2->y >> FRACTOMAPBITS;//e6y + + if (automapmode & am_rotate) { + AM_rotate(&l.a.x, &l.a.y, ANG90-plr->mo->angle, plr->mo->x, plr->mo->y); + AM_rotate(&l.b.x, &l.b.y, ANG90-plr->mo->angle, plr->mo->x, plr->mo->y); + } + + // if line has been seen or IDDT has been used + if (ddt_cheating || (lines[i].flags & ML_MAPPED)) + { + if ((lines[i].flags & ML_DONTDRAW) && !ddt_cheating) + continue; + { + /* cph - show keyed doors and lines */ + int amd; + if ((mapcolor_bdor || mapcolor_ydor || mapcolor_rdor) && + !(lines[i].flags & ML_SECRET) && /* non-secret */ + (amd = AM_DoorColor(lines[i].special)) != -1 + ) + { + { + switch (amd) /* closed keyed door */ + { + case 1: + /*bluekey*/ + AM_drawMline(&l, + mapcolor_bdor? mapcolor_bdor : mapcolor_cchg); + continue; + case 2: + /*yellowkey*/ + AM_drawMline(&l, + mapcolor_ydor? mapcolor_ydor : mapcolor_cchg); + continue; + case 0: + /*redkey*/ + AM_drawMline(&l, + mapcolor_rdor? mapcolor_rdor : mapcolor_cchg); + continue; + case 3: + /*any or all*/ + AM_drawMline(&l, + mapcolor_clsd? mapcolor_clsd : mapcolor_cchg); + continue; + } + } + } + } + if /* jff 4/23/98 add exit lines to automap */ + ( + mapcolor_exit && + ( + lines[i].special==11 || + lines[i].special==52 || + lines[i].special==197 || + lines[i].special==51 || + lines[i].special==124 || + lines[i].special==198 + ) + ) { + AM_drawMline(&l, mapcolor_exit); /* exit line */ + continue; + } + + if (!lines[i].backsector) + { + // jff 1/10/98 add new color for 1S secret sector boundary + if (mapcolor_secr && //jff 4/3/98 0 is disable + ( + ( + map_secret_after && + P_WasSecret(lines[i].frontsector) && + !P_IsSecret(lines[i].frontsector) + ) + || + ( + !map_secret_after && + P_WasSecret(lines[i].frontsector) + ) + ) + ) + AM_drawMline(&l, mapcolor_secr); // line bounding secret sector + else //jff 2/16/98 fixed bug + AM_drawMline(&l, mapcolor_wall); // special was cleared + } + else /* now for 2S lines */ + { + // jff 1/10/98 add color change for all teleporter types + if + ( + mapcolor_tele && !(lines[i].flags & ML_SECRET) && + (lines[i].special == 39 || lines[i].special == 97 || + lines[i].special == 125 || lines[i].special == 126) + ) + { // teleporters + AM_drawMline(&l, mapcolor_tele); + } + else if (lines[i].flags & ML_SECRET) // secret door + { + AM_drawMline(&l, mapcolor_wall); // wall color + } + else if + ( + mapcolor_clsd && + !(lines[i].flags & ML_SECRET) && // non-secret closed door + ((lines[i].backsector->floorheight==lines[i].backsector->ceilingheight) || + (lines[i].frontsector->floorheight==lines[i].frontsector->ceilingheight)) + ) + { + AM_drawMline(&l, mapcolor_clsd); // non-secret closed door + } //jff 1/6/98 show secret sector 2S lines + else if + ( + mapcolor_secr && //jff 2/16/98 fixed bug + ( // special was cleared after getting it + (map_secret_after && + ( + (P_WasSecret(lines[i].frontsector) + && !P_IsSecret(lines[i].frontsector)) || + (P_WasSecret(lines[i].backsector) + && !P_IsSecret(lines[i].backsector)) + ) + ) + || //jff 3/9/98 add logic to not show secret til after entered + ( // if map_secret_after is true + !map_secret_after && + (P_WasSecret(lines[i].frontsector) || + P_WasSecret(lines[i].backsector)) + ) + ) + ) + { + AM_drawMline(&l, mapcolor_secr); // line bounding secret sector + } //jff 1/6/98 end secret sector line change + else if (lines[i].backsector->floorheight != + lines[i].frontsector->floorheight) + { + AM_drawMline(&l, mapcolor_fchg); // floor level change + } + else if (lines[i].backsector->ceilingheight != + lines[i].frontsector->ceilingheight) + { + AM_drawMline(&l, mapcolor_cchg); // ceiling level change + } + else if (mapcolor_flat && ddt_cheating) + { + AM_drawMline(&l, mapcolor_flat); //2S lines that appear only in IDDT + } + } + } // now draw the lines only visible because the player has computermap + else if (plr->powers[pw_allmap]) // computermap visible lines + { + if (!(lines[i].flags & ML_DONTDRAW)) // invisible flag lines do not show + { + if + ( + mapcolor_flat + || + !lines[i].backsector + || + lines[i].backsector->floorheight + != lines[i].frontsector->floorheight + || + lines[i].backsector->ceilingheight + != lines[i].frontsector->ceilingheight + ) + AM_drawMline(&l, mapcolor_unsn); + } + } + } +} + +// +// AM_drawLineCharacter() +// +// Draws a vector graphic according to numerous parameters +// +// Passed the structure defining the vector graphic shape, the number +// of vectors in it, the scale to draw it at, the angle to draw it at, +// the color to draw it with, and the map coordinates to draw it at. +// Returns nothing +// +static void AM_drawLineCharacter +( mline_t* lineguy, + int lineguylines, + fixed_t scale, + angle_t angle, + int color, + fixed_t x, + fixed_t y ) +{ + int i; + mline_t l; + + if (automapmode & am_rotate) angle -= plr->mo->angle - ANG90; // cph + + for (i=0;imo->angle, + mapcolor_sngl, //jff color + plr->mo->x >> FRACTOMAPBITS,//e6y + plr->mo->y >> FRACTOMAPBITS//e6y + ); + else + AM_drawLineCharacter + ( + player_arrow, + NUMPLYRLINES, + 0, + plr->mo->angle, + mapcolor_sngl, //jff color + plr->mo->x >> FRACTOMAPBITS,//e6y + plr->mo->y >> FRACTOMAPBITS);//e6y + return; + } + + for (i=0;imo->x >> FRACTOMAPBITS, y = p->mo->y >> FRACTOMAPBITS;//e6y + if (automapmode & am_rotate) + AM_rotate(&x, &y, ANG90-plr->mo->angle, plr->mo->x, plr->mo->y); + + AM_drawLineCharacter (player_arrow, NUMPLYRLINES, 0, p->mo->angle, + p->powers[pw_invisibility] ? 246 /* *close* to black */ + : mapcolor_plyr[i], //jff 1/6/98 use default color + x, y); + } + } +} + +// +// AM_drawThings() +// +// Draws the things on the automap in double IDDT cheat mode +// +// Passed colors and colorrange, no longer used +// Returns nothing +// +static void AM_drawThings(void) +{ + int i; + mobj_t* t; + + // for all sectors + for (i=0;ix >> FRACTOMAPBITS, y = t->y >> FRACTOMAPBITS;//e6y + + if (automapmode & am_rotate) + AM_rotate(&x, &y, ANG90-plr->mo->angle, plr->mo->x, plr->mo->y); + + //jff 1/5/98 case over doomednum of thing being drawn + if (mapcolor_rkey || mapcolor_ykey || mapcolor_bkey) + { + switch(t->info->doomednum) + { + //jff 1/5/98 treat keys special + case 38: case 13: //jff red key + AM_drawLineCharacter + ( + cross_mark, + NUMCROSSMARKLINES, + 16<angle, + mapcolor_rkey!=-1? mapcolor_rkey : mapcolor_sprt, + x, y + ); + t = t->snext; + continue; + case 39: case 6: //jff yellow key + AM_drawLineCharacter + ( + cross_mark, + NUMCROSSMARKLINES, + 16<angle, + mapcolor_ykey!=-1? mapcolor_ykey : mapcolor_sprt, + x, y + ); + t = t->snext; + continue; + case 40: case 5: //jff blue key + AM_drawLineCharacter + ( + cross_mark, + NUMCROSSMARKLINES, + 16<angle, + mapcolor_bkey!=-1? mapcolor_bkey : mapcolor_sprt, + x, y + ); + t = t->snext; + continue; + default: + break; + } + } + //jff 1/5/98 end added code for keys + //jff previously entire code + AM_drawLineCharacter + ( + thintriangle_guy, + NUMTHINTRIANGLEGUYLINES, + 16<angle, + t->flags & MF_FRIEND && !t->player ? mapcolor_frnd : + /* cph 2006/07/30 - Show count-as-kills in red. */ + ((t->flags & (MF_COUNTKILL | MF_CORPSE)) == MF_COUNTKILL) ? mapcolor_enemy : + /* bbm 2/28/03 Show countable items in yellow. */ + t->flags & MF_COUNTITEM ? mapcolor_item : mapcolor_sprt, + x, y + ); + t = t->snext; + } + } +} + +// +// AM_drawMarks() +// +// Draw the marked locations on the automap +// +// Passed nothing, returns nothing +// +// killough 2/22/98: +// Rewrote AM_drawMarks(). Removed limit on marks. +// +static void AM_drawMarks(void) +{ + int i; + for (i=0;imo->angle, plr->mo->x, plr->mo->y); + + fx = CXMTOF(fx); fy = CYMTOF(fy); + + do + { + int d = j % 10; + if (d==1) // killough 2/22/98: less spacing for '1' + fx++; + + if (fx >= f_x && fx < f_w - w && fy >= f_y && fy < f_h - h) { + // cph - construct patch name and draw marker + char namebuf[] = { 'A', 'M', 'M', 'N', 'U', 'M', '0'+d, 0 }; + + V_DrawNamePatch(fx, fy, FB, namebuf, CR_DEFAULT, VPT_NONE); + } + fx -= w-1; // killough 2/22/98: 1 space backwards + j /= 10; + } + while (j>0); + } +} + +// +// AM_drawCrosshair() +// +// Draw the single point crosshair representing map center +// +// Passed the color to draw the pixel with +// Returns nothing +// +// CPhipps - made static inline, and use the general pixel plotter function + +inline static void AM_drawCrosshair(int color) +{ + fline_t line; + + line.a.x = (f_w/2)-1; + line.a.y = (f_h/2); + line.b.x = (f_w/2)+1; + line.b.y = (f_h/2); + V_DrawLine(&line, color); + + line.a.x = (f_w/2); + line.a.y = (f_h/2)-1; + line.b.x = (f_w/2); + line.b.y = (f_h/2)+1; + V_DrawLine(&line, color); +} + +// +// AM_Drawer() +// +// Draws the entire automap +// +// Passed nothing, returns nothing +// +void AM_Drawer (void) +{ + // CPhipps - all automap modes put into one enum + if (!(automapmode & am_active)) return; + + if (!(automapmode & am_overlay)) // cph - If not overlay mode, clear background for the automap + V_FillRect(FB, f_x, f_y, f_w, f_h, (byte)mapcolor_back); //jff 1/5/98 background default color + if (automapmode & am_grid) + AM_drawGrid(mapcolor_grid); //jff 1/7/98 grid default color + AM_drawWalls(); + AM_drawPlayers(); + if (ddt_cheating==2) + AM_drawThings(); //jff 1/5/98 default double IDDT sprite +#ifdef IPHONE + glColor4f( 1, 1, 1, 1 ); // without the crosshair, colors can get left incorre3ctly set + iphoneSet2D(); // JDC: not sure why this is necessary, but the status bar doesn't draw without it +#else // JDC: I don't like the croshair on the map screen + AM_drawCrosshair(mapcolor_hair); //jff 1/7/98 default crosshair color +#endif + AM_drawMarks(); +} diff --git a/common/prboom/am_map.h b/common/prboom/am_map.h new file mode 100755 index 0000000..850c9ce --- /dev/null +++ b/common/prboom/am_map.h @@ -0,0 +1,111 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * AutoMap module. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __AMMAP_H__ +#define __AMMAP_H__ + +#include "d_event.h" + +#define MAPBITS 12 +#define FRACTOMAPBITS (FRACBITS-MAPBITS) + +// Used by ST StatusBar stuff. +#define AM_MSGHEADER (('a'<<24)+('m'<<16)) +#define AM_MSGENTERED (AM_MSGHEADER | ('e'<<8)) +#define AM_MSGEXITED (AM_MSGHEADER | ('x'<<8)) + +// Called by main loop. +boolean AM_Responder (event_t* ev); + +// Called by main loop. +void AM_Ticker (void); + +// Called by main loop, +// called instead of view drawer if automap active. +void AM_Drawer (void); + +// Called to force the automap to quit +// if the level is completed while it is up. +void AM_Stop (void); + +// killough 2/22/98: for saving automap information in savegame: + +extern void AM_Start(void); + +//jff 4/16/98 make externally available + +extern void AM_clearMarks(void); + +typedef struct +{ + fixed_t x,y; +} mpoint_t; + +extern mpoint_t *markpoints; +extern int markpointnum, markpointnum_max; + +// end changes -- killough 2/22/98 + +// killough 5/2/98: moved from m_misc.c + +//jff 1/7/98 automap colors added +extern int mapcolor_back; // map background +extern int mapcolor_grid; // grid lines color +extern int mapcolor_wall; // normal 1s wall color +extern int mapcolor_fchg; // line at floor height change color +extern int mapcolor_cchg; // line at ceiling height change color +extern int mapcolor_clsd; // line at sector with floor=ceiling color +extern int mapcolor_rkey; // red key color +extern int mapcolor_bkey; // blue key color +extern int mapcolor_ykey; // yellow key color +extern int mapcolor_rdor; // red door color (diff from keys to allow option) +extern int mapcolor_bdor; // blue door color (of enabling one not other) +extern int mapcolor_ydor; // yellow door color +extern int mapcolor_tele; // teleporter line color +extern int mapcolor_secr; // secret sector boundary color +//jff 4/23/98 +extern int mapcolor_exit; // exit line +extern int mapcolor_unsn; // computer map unseen line color +extern int mapcolor_flat; // line with no floor/ceiling changes +extern int mapcolor_sprt; // general sprite color +extern int mapcolor_item; // item sprite color +extern int mapcolor_enemy; // enemy sprite color +extern int mapcolor_frnd; // friendly sprite color +extern int mapcolor_hair; // crosshair color +extern int mapcolor_sngl; // single player arrow color +extern int mapcolor_plyr[4]; // colors for players in multiplayer +extern int mapcolor_me; // consoleplayer's chosen colour +//jff 3/9/98 +extern int map_secret_after; // secrets do not appear til after bagged + +#endif diff --git a/common/prboom/config.h b/common/prboom/config.h new file mode 100755 index 0000000..dd28273 --- /dev/null +++ b/common/prboom/config.h @@ -0,0 +1,109 @@ +/**/ +#define PACKAGE "prboom" +#define VERSION "2.5.0" + +#ifdef DEBUG + +/* Define to enable internal range checking */ +#define RANGECHECK 1 + +/* Define this to see real-time memory allocation + * statistics, and enable extra debugging features + */ +#define INSTRUMENTED 1 + +/* Uncomment this to exhaustively run memory checks + * while the game is running (this is EXTREMELY slow). + * Only useful if INSTRUMENTED is also defined. + */ +#define CHECKHEAP 1 + +/* Uncomment this to cause heap dumps to be generated. + * Only useful if INSTRUMENTED is also defined. + */ +#define HEAPDUMP 1 + +/* Uncomment this to perform id checks on zone blocks, + * to detect corrupted and illegally freed blocks + */ +#define ZONEIDCHECK 1 + +/* CPhipps - some debugging macros for the new wad lump handling code */ +/* Defining this causes quick checks which only impose an overhead if a + * posible error is detected. */ +#define SIMPLECHECKS 1 + +/* Defining this causes time stamps to be created each time a lump is locked, and + * lumps locked for long periods of time are reported */ +#define TIMEDIAG 1 + +#endif // DEBUG + +#define DOGS 1 +#define MONITOR_VISIBILITY 1 +/*#define DISABLE_LUMP_CACHING*/ + +/**/ +#define USE_SDL 1 +#define HAVE_LIBSDL_MIXER 1 +#define HAVE_NET 1 +#define USE_SDL_NET 1 + +/**/ +#define HIGHRES 1 +#define GL_DOOM 1 +#define USE_GLU_TESS 1 +#define USE_GLU_IMAGESCALE 1 +#define USE_GLU_MIPMAP 1 +#define DISABLE_DOUBLEBUFFER + +/**/ +#define STDC_HEADERS 1 + +#define stricmp strcasecmp +#define strnicmp strncasecmp + +#define HAVE_INET_ATON 1 +#define HAVE_INET_NTOP 1 +#define HAVE_INET_PTON 1 +#define HAVE_SETSOCKOPT 1 + +#define HAVE_SNPRINTF 1 +#define HAVE_VSNPRINTF 1 + +#define HAVE_MKSTEMPS 1 + +#define HAVE_IPv6 1 + +#define HAVE_UNISTD_H +#define HAVE_SYS_WAIT_H +#define HAVE_GETOPT +/* causes a duplicate define warning +#define HAVE_NETINET_IN_H +*/ +#define SYS_SIGLIST_DECLARED + +/**/ +#ifdef __BIG_ENDIAN__ +#define WORDS_BIGENDIAN +#endif + +#ifdef __i386__ +#define I386_ASM 1 +#endif + +#define PACKEDATTR __attribute__((packed)) + +#define MACOSX +#define HAVE_LIBKERN_OSBYTEORDER_H + + +//------ JDC config changes for iPhone ------------ +#undef I386_ASM +#undef USE_SDL +#undef USE_SDL_NET +#undef HAVE_NET +#undef DOGS // not sure why this needs to be removed, info.c complains +#undef USE_GLU_IMAGESCALE +#undef USE_GLU_MIPMAP + diff --git a/common/prboom/d_client.c b/common/prboom/d_client.c new file mode 100755 index 0000000..a340bc2 --- /dev/null +++ b/common/prboom/d_client.c @@ -0,0 +1,541 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Network client. Passes information to/from server, staying + * synchronised. + * Contains the main wait loop, waiting for network input or + * time before doing the next tic. + * Rewritten for LxDoom, but based around bits of the old code. + * + *----------------------------------------------------------------------------- + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_SYS_WAIT_H +#include +#endif + +#ifdef USE_SDL_NET + #include "SDL.h" +#endif + +#include "doomtype.h" +#include "doomstat.h" +#include "d_net.h" +#include "z_zone.h" + +#include "d_main.h" +#include "g_game.h" +#include "m_menu.h" +#include "p_checksum.h" + +#include "protocol.h" +#include "i_network.h" +#include "i_system.h" +#include "i_main.h" +#include "i_video.h" +#include "m_argv.h" +#include "r_fps.h" +#include "lprintf.h" + +static boolean server; +static int remotetic; // Tic expected from the remote +//static int remotesend; // Tic expected by the remote +ticcmd_t netcmds[MAXPLAYERS][BACKUPTICS]; +static ticcmd_t* localcmds; +//static unsigned numqueuedpackets; +//static packet_header_t** queuedpacket; +int maketic; +int ticdup = 1; +//static int xtratics = 0; +int wanted_player_number; + +static boolean isExtraDDisplay = false; + +#ifdef HAVE_NET +static void D_QuitNetGame (void); +#endif + +#ifndef HAVE_NET +doomcom_t* doomcom; +#endif + +#ifdef HAVE_NET +void D_InitNetGame (void) +{ + int i; + int numplayers = 1; + + i = M_CheckParm("-net"); + if (i && i < myargc-1) i++; + + if (!(netgame = server = !!i)) { + playeringame[consoleplayer = 0] = true; + // e6y + // for play, recording or playback using "single-player coop" mode. + // Equivalent to using prboom_server with -N 1 + netgame = M_CheckParm("-solo-net") || M_CheckParm("-net1"); + } else { + // Get game info from server + packet_header_t *packet = Z_Malloc(1000, PU_STATIC, NULL); + struct setup_packet_s *sinfo = (void*)(packet+1); + struct { packet_header_t head; short pn; } PACKEDATTR initpacket; + + I_InitNetwork(); + udp_socket = I_Socket(0); + I_ConnectToServer(myargv[i]); + + do + { + do { + // Send init packet + initpacket.pn = doom_htons(wanted_player_number); + packet_set(&initpacket.head, PKT_INIT, 0); + I_SendPacket(&initpacket.head, sizeof(initpacket)); + I_WaitForPacket(5000); + } while (!I_GetPacket(packet, 1000)); + if (packet->type == PKT_DOWN) I_Error("Server aborted the game"); + } while (packet->type != PKT_SETUP); + + // Once we have been accepted by the server, we should tell it when we leave + atexit(D_QuitNetGame); + + // Get info from the setup packet + consoleplayer = sinfo->yourplayer; + compatibility_level = sinfo->complevel; + G_Compatibility(); + startskill = sinfo->skill; + deathmatch = sinfo->deathmatch; + startmap = sinfo->level; + startepisode = sinfo->episode; + ticdup = sinfo->ticdup; + xtratics = sinfo->extratic; + G_ReadOptions(sinfo->game_options); + + lprintf(LO_INFO, "\tjoined game as player %d/%d; %d WADs specified\n", + consoleplayer+1, numplayers = sinfo->players, sinfo->numwads); + { + char *p = sinfo->wadnames; + int i = sinfo->numwads; + + while (i--) { + D_AddFile(p, source_net); + p += strlen(p) + 1; + } + } + Z_Free(packet); + } + localcmds = netcmds[displayplayer = consoleplayer]; + for (i=0; iconsoleplayer = 0; + doomcom->numnodes = 0; doomcom->numplayers = 1; + localcmds = netcmds[consoleplayer]; + netgame = (M_CheckParm("-solo-net") != 0) || (M_CheckParm("-net1") != 0); + + for (i=0; inumplayers; i++) + playeringame[i] = true; + for (; iconsoleplayer; +} +#endif // HAVE_NET + +#ifdef HAVE_NET +void D_CheckNetGame(void) +{ + packet_header_t *packet = Z_Malloc(sizeof(packet_header_t)+1, PU_STATIC, NULL); + + if (server) { + lprintf(LO_INFO, "D_CheckNetGame: waiting for server to signal game start\n"); + do { + while (!I_GetPacket(packet, sizeof(packet_header_t)+1)) { + packet_set(packet, PKT_GO, 0); + *(byte*)(packet+1) = consoleplayer; + I_SendPacket(packet, sizeof(packet_header_t)+1); + I_uSleep(100000); + } + } while (packet->type != PKT_GO); + } + Z_Free(packet); +} + +boolean D_NetGetWad(const char* name) +{ +#if defined(HAVE_WAIT_H) + size_t psize = sizeof(packet_header_t) + strlen(name) + 500; + packet_header_t *packet; + boolean done = false; + + if (!server || strchr(name, '/')) return false; // If it contains path info, reject + + do { + // Send WAD request to remote + packet = Z_Malloc(psize, PU_STATIC, NULL); + packet_set(packet, PKT_WAD, 0); + *(byte*)(packet+1) = consoleplayer; + strcpy(1+(byte*)(packet+1), name); + I_SendPacket(packet, sizeof(packet_header_t) + strlen(name) + 2); + + I_uSleep(10000); + } while (!I_GetPacket(packet, psize) || (packet->type != PKT_WAD)); + Z_Free(packet); + + if (!strcasecmp((void*)(packet+1), name)) { + pid_t pid; + int rv; + byte *p = (byte*)(packet+1) + strlen(name) + 1; + + /* Automatic wad file retrieval using wget (supports http and ftp, using URLs) + * Unix systems have all these commands handy, this kind of thing is easy + * Any windo$e port will have some awkward work replacing these. + */ + /* cph - caution here. This is data from an untrusted source. + * Don't pass it via a shell. */ + if ((pid = fork()) == -1) + perror("fork"); + else if (!pid) { + /* Child chains to wget, does the download */ + execlp("wget", "wget", p, NULL); + } + /* This is the parent, i.e. main LxDoom process */ + wait(&rv); + if (!(done = !access(name, R_OK))) { + if (!strcmp(p+strlen(p)-4, ".zip")) { + p = strrchr(p, '/')+1; + if ((pid = fork()) == -1) + perror("fork"); + else if (!pid) { + /* Child executes decompressor */ + execlp("unzip", "unzip", p, name, NULL); + } + /* Parent waits for the file */ + wait(&rv); + done = !!access(name, R_OK); + } + /* Add more decompression protocols here as desired */ + } + Z_Free(buffer); + } + return done; +#else /* HAVE_WAIT_H */ + return false; +#endif +} + +void NetUpdate(void) +{ + static int lastmadetic; + if (isExtraDDisplay) + return; + if (server) { // Receive network packets + size_t recvlen; + packet_header_t *packet = Z_Malloc(10000, PU_STATIC, NULL); + while ((recvlen = I_GetPacket(packet, 10000))) { + switch(packet->type) { + case PKT_TICS: + { + byte *p = (void*)(packet+1); + int tics = *p++; + unsigned long ptic = doom_ntohl(packet->tic); + if (ptic > (unsigned)remotetic) { // Missed some + packet_set(packet, PKT_RETRANS, remotetic); + *(byte*)(packet+1) = consoleplayer; + I_SendPacket(packet, sizeof(*packet)+1); + } else { + if (ptic + tics <= (unsigned)remotetic) break; // Will not improve things + remotetic = ptic; + while (tics--) { + int players = *p++; + while (players--) { + int n = *p++; + RawToTic(&netcmds[n][remotetic%BACKUPTICS], p); + p += sizeof(ticcmd_t); + } + remotetic++; + } + } + } + break; + case PKT_RETRANS: // Resend request + remotesend = doom_ntohl(packet->tic); + break; + case PKT_DOWN: // Server downed + { + int j; + for (j=0; j 0 ? newtics : 0); + lastmadetic += newtics; + if (ffmap) newtics++; + while (newtics--) { + I_StartTic(); + if (maketic - gametic > BACKUPTICS/2) break; + G_BuildTiccmd(&localcmds[maketic%BACKUPTICS]); + maketic++; + } + if (server && maketic > remotesend) { // Send the tics to the server + int sendtics; + remotesend -= xtratics; + if (remotesend < 0) remotesend = 0; + sendtics = maketic - remotesend; + { + size_t pkt_size = sizeof(packet_header_t) + 2 + sendtics * sizeof(ticcmd_t); + packet_header_t *packet = Z_Malloc(pkt_size, PU_STATIC, NULL); + + packet_set(packet, PKT_TICC, maketic - sendtics); + *(byte*)(packet+1) = sendtics; + *(((byte*)(packet+1))+1) = consoleplayer; + { + void *tic = ((byte*)(packet+1)) +2; + while (sendtics--) { + TicToRaw(tic, &localcmds[remotesend++%BACKUPTICS]); + tic = (byte *)tic + sizeof(ticcmd_t); + } + } + I_SendPacket(packet, pkt_size); + Z_Free(packet); + } + } + } +} +#else + +void D_BuildNewTiccmds(void) +{ + static int lastmadetic; + int newtics = I_GetTime() - lastmadetic; + lastmadetic += newtics; + while (newtics--) + { + I_StartTic(); + if (maketic - gametic > BACKUPTICS/2) break; + G_BuildTiccmd(&localcmds[maketic%BACKUPTICS]); + maketic++; + } +} +#endif + +#ifdef HAVE_NET +/* cph - data passed to this must be in the Doom (little-) endian */ +void D_NetSendMisc(netmisctype_t type, size_t len, void* data) +{ + if (server) { + size_t size = sizeof(packet_header_t) + 3*sizeof(int) + len; + packet_header_t *packet = Z_Malloc(size, PU_STATIC, NULL); + int *p = (void*)(packet+1); + + packet_set(packet, PKT_EXTRA, gametic); + *p++ = LONG(type); *p++ = LONG(consoleplayer); *p++ = LONG(len); + memcpy(p, data, len); + I_SendPacket(packet, size); + + Z_Free(packet); + } +} + +static void CheckQueuedPackets(void) +{ + int i; + for (i=0; (unsigned)itic) <= gametic) + switch (queuedpacket[i]->type) { + case PKT_QUIT: // Player quit the game + { + int pn = *(byte*)(queuedpacket[i]+1); + playeringame[pn] = false; + doom_printf("Player %d left the game\n", pn); + } + break; + case PKT_EXTRA: + { + int *p = (int*)(queuedpacket[i]+1); + size_t len = LONG(*(p+2)); + switch (LONG(*p)) { + case nm_plcolour: + G_ChangedPlayerColour(LONG(*(p+1)), LONG(*(p+3))); + break; + case nm_savegamename: + if (len < SAVEDESCLEN) { + memcpy(savedescription, p+3, len); + // Force terminating 0 in case + savedescription[len] = 0; + } + break; + } + } + break; + default: // Should not be queued + break; + } + + { // Requeue remaining packets + int newnum = 0; + packet_header_t **newqueue = NULL; + + for (i=0; (unsigned)itic) > gametic) { + newqueue = Z_Realloc(newqueue, ++newnum * sizeof *newqueue, + PU_STATIC, NULL); + newqueue[newnum-1] = queuedpacket[i]; + } else Z_Free(queuedpacket[i]); + + Z_Free(queuedpacket); + numqueuedpackets = newnum; queuedpacket = newqueue; + } +} +#endif // HAVE_NET + +void TryRunTics (void) +{ + int runtics; + int entertime = I_GetTime(); + + // Wait for tics to run + while (1) { +#ifdef HAVE_NET + NetUpdate(); +#else + D_BuildNewTiccmds(); +#endif + runtics = (server ? remotetic : maketic) - gametic; + if (!runtics) { + if (!movement_smooth) { +#ifdef HAVE_NET + if (server) + I_WaitForPacket(ms_to_next_tick); + else +#endif + I_uSleep(ms_to_next_tick*1000); + } + if (I_GetTime() - entertime > 10) { +#ifdef HAVE_NET + if (server) { + char buf[sizeof(packet_header_t)+1]; + remotesend--; + packet_set((packet_header_t *)buf, PKT_RETRANS, remotetic); + buf[sizeof(buf)-1] = consoleplayer; + I_SendPacket((packet_header_t *)buf, sizeof buf); + } +#endif + M_Ticker(); return; + } + //if ((displaytime) < (tic_vars.next-SDL_GetTicks())) + { + WasRenderedInTryRunTics = true; + if (V_GetMode() == VID_MODEGL ? + movement_smooth : + movement_smooth && gamestate==wipegamestate) + { + isExtraDDisplay = true; + D_Display(); + isExtraDDisplay = false; + } + } + } else break; + } + + while (runtics--) { +#ifdef HAVE_NET + if (server) CheckQueuedPackets(); +#endif + if (advancedemo) + D_DoAdvanceDemo (); + M_Ticker (); + I_GetTime_SaveMS(); + G_Ticker (); + P_Checksum(gametic); + gametic++; +#ifdef HAVE_NET + NetUpdate(); // Keep sending our tics to avoid stalling remote nodes +#endif + } +} + +#ifdef HAVE_NET +static void D_QuitNetGame (void) +{ + byte buf[1 + sizeof(packet_header_t)]; + packet_header_t *packet = (void*)buf; + int i; + + if (!server) return; + buf[sizeof(packet_header_t)] = consoleplayer; + packet_set(packet, PKT_QUIT, gametic); + + for (i=0; i<4; i++) { + I_SendPacket(packet, 1 + sizeof(packet_header_t)); + I_uSleep(10000); + } +} +#endif diff --git a/common/prboom/d_deh.c b/common/prboom/d_deh.c new file mode 100755 index 0000000..3f5ec14 --- /dev/null +++ b/common/prboom/d_deh.c @@ -0,0 +1,3115 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2004 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Dehacked file support + * New for the TeamTNT "Boom" engine + * + * Author: Ty Halderman, TeamTNT + * + *--------------------------------------------------------------------*/ + +// killough 5/2/98: fixed headers, removed rendunant external declarations: +#include "doomdef.h" +#include "doomtype.h" +#include "doomstat.h" +#include "d_deh.h" +#include "sounds.h" +#include "info.h" +#include "m_cheat.h" +#include "p_inter.h" +#include "p_enemy.h" +#include "g_game.h" +#include "d_think.h" +#include "w_wad.h" + +// CPhipps - modify to use logical output routine +#include "lprintf.h" + +#define TRUE 1 +#define FALSE 0 + +#ifndef HAVE_STRLWR +#include + +static char* strlwr(char* str) +{ + char* p; + for (p=str; *p; p++) *p = tolower(*p); + return str; +} +#endif + +// killough 10/98: new functions, to allow processing DEH files in-memory +// (e.g. from wads) + +typedef struct { + /* cph 2006/08/06 - + * if lump != NULL, lump is the start of the lump, + * inp is the current read pos. */ + const byte *inp, *lump; + long size; + /* else, !lump, and f is the file being read */ + FILE* f; +} DEHFILE; + +// killough 10/98: emulate IO whether input really comes from a file or not + +static char *dehfgets(char *buf, size_t n, DEHFILE *fp) +{ + if (!fp->lump) // If this is a real file, + return (fgets)(buf, n, fp->f); // return regular fgets + if (!n || !*fp->inp || fp->size<=0) // If no more characters + return NULL; + if (n==1) + fp->size--, *buf = *fp->inp++; + else + { // copy buffer + char *p = buf; + while (n>1 && *fp->inp && fp->size && + (n--, fp->size--, *p++ = *fp->inp++) != '\n') + ; + *p = 0; + } + return buf; // Return buffer pointer +} + +static int dehfeof(DEHFILE *fp) +{ + return !fp->lump ? feof(fp->f) : !*fp->inp || fp->size<=0; +} + +static int dehfgetc(DEHFILE *fp) +{ + return !fp->lump ? fgetc(fp->f) : fp->size > 0 ? + fp->size--, *fp->inp++ : EOF; +} + +// haleyjd 9/22/99 +int HelperThing = -1; // in P_SpawnMapThing to substitute helper thing + +// variables used in other routines +boolean deh_pars = FALSE; // in wi_stuff to allow pars in modified games + +// #include "d_deh.h" -- we don't do that here but we declare the +// variables. This externalizes everything that there is a string +// set for in the language files. See d_deh.h for detailed comments, +// original English values etc. These are set to the macro values, +// which are set by D_ENGLSH.H or D_FRENCH.H(etc). BEX files are a +// better way of changing these strings globally by language. + +// ==================================================================== +// Any of these can be changed using the bex extensions +#include "dstrings.h" // to get the initial values +/* cph - const's + * - removed redundant "can't XXX in a netgame" strings. + */ +const char *s_D_DEVSTR = D_DEVSTR; +const char *s_D_CDROM = D_CDROM; +const char *s_PRESSKEY = PRESSKEY; +const char *s_PRESSYN = PRESSYN; +const char *s_QUITMSG = QUITMSG; +const char *s_QSAVESPOT = QSAVESPOT; // PRESSKEY; +const char *s_SAVEDEAD = SAVEDEAD; // PRESSKEY; // remove duplicate y/n +const char *s_QSPROMPT = QSPROMPT; // PRESSYN; +const char *s_QLPROMPT = QLPROMPT; // PRESSYN; +const char *s_NEWGAME = NEWGAME; // PRESSKEY; +const char *s_RESTARTLEVEL= RESTARTLEVEL; // PRESSYN; +const char *s_NIGHTMARE = NIGHTMARE; // PRESSYN; +const char *s_SWSTRING = SWSTRING; // PRESSKEY; +const char *s_MSGOFF = MSGOFF; +const char *s_MSGON = MSGON; +const char *s_NETEND = NETEND; // PRESSKEY; +const char *s_ENDGAME = ENDGAME; // PRESSYN; // killough 4/4/98: end +const char *s_DOSY = DOSY; +const char *s_DETAILHI = DETAILHI; +const char *s_DETAILLO = DETAILLO; +const char *s_GAMMALVL0 = GAMMALVL0; +const char *s_GAMMALVL1 = GAMMALVL1; +const char *s_GAMMALVL2 = GAMMALVL2; +const char *s_GAMMALVL3 = GAMMALVL3; +const char *s_GAMMALVL4 = GAMMALVL4; +const char *s_EMPTYSTRING = EMPTYSTRING; +const char *s_GOTARMOR = GOTARMOR; +const char *s_GOTMEGA = GOTMEGA; +const char *s_GOTHTHBONUS = GOTHTHBONUS; +const char *s_GOTARMBONUS = GOTARMBONUS; +const char *s_GOTSTIM = GOTSTIM; +const char *s_GOTMEDINEED = GOTMEDINEED; +const char *s_GOTMEDIKIT = GOTMEDIKIT; +const char *s_GOTSUPER = GOTSUPER; +const char *s_GOTBLUECARD = GOTBLUECARD; +const char *s_GOTYELWCARD = GOTYELWCARD; +const char *s_GOTREDCARD = GOTREDCARD; +const char *s_GOTBLUESKUL = GOTBLUESKUL; +const char *s_GOTYELWSKUL = GOTYELWSKUL; +const char *s_GOTREDSKULL = GOTREDSKULL; +const char *s_GOTINVUL = GOTINVUL; +const char *s_GOTBERSERK = GOTBERSERK; +const char *s_GOTINVIS = GOTINVIS; +const char *s_GOTSUIT = GOTSUIT; +const char *s_GOTMAP = GOTMAP; +const char *s_GOTVISOR = GOTVISOR; +const char *s_GOTMSPHERE = GOTMSPHERE; +const char *s_GOTCLIP = GOTCLIP; +const char *s_GOTCLIPBOX = GOTCLIPBOX; +const char *s_GOTROCKET = GOTROCKET; +const char *s_GOTROCKBOX = GOTROCKBOX; +const char *s_GOTCELL = GOTCELL; +const char *s_GOTCELLBOX = GOTCELLBOX; +const char *s_GOTSHELLS = GOTSHELLS; +const char *s_GOTSHELLBOX = GOTSHELLBOX; +const char *s_GOTBACKPACK = GOTBACKPACK; +const char *s_GOTBFG9000 = GOTBFG9000; +const char *s_GOTCHAINGUN = GOTCHAINGUN; +const char *s_GOTCHAINSAW = GOTCHAINSAW; +const char *s_GOTLAUNCHER = GOTLAUNCHER; +const char *s_GOTPLASMA = GOTPLASMA; +const char *s_GOTSHOTGUN = GOTSHOTGUN; +const char *s_GOTSHOTGUN2 = GOTSHOTGUN2; +const char *s_PD_BLUEO = PD_BLUEO; +const char *s_PD_REDO = PD_REDO; +const char *s_PD_YELLOWO = PD_YELLOWO; +const char *s_PD_BLUEK = PD_BLUEK; +const char *s_PD_REDK = PD_REDK; +const char *s_PD_YELLOWK = PD_YELLOWK; +const char *s_PD_BLUEC = PD_BLUEC; +const char *s_PD_REDC = PD_REDC; +const char *s_PD_YELLOWC = PD_YELLOWC; +const char *s_PD_BLUES = PD_BLUES; +const char *s_PD_REDS = PD_REDS; +const char *s_PD_YELLOWS = PD_YELLOWS; +const char *s_PD_ANY = PD_ANY; +const char *s_PD_ALL3 = PD_ALL3; +const char *s_PD_ALL6 = PD_ALL6; +const char *s_GGSAVED = GGSAVED; +const char *s_HUSTR_MSGU = HUSTR_MSGU; +const char *s_HUSTR_E1M1 = HUSTR_E1M1; +const char *s_HUSTR_E1M2 = HUSTR_E1M2; +const char *s_HUSTR_E1M3 = HUSTR_E1M3; +const char *s_HUSTR_E1M4 = HUSTR_E1M4; +const char *s_HUSTR_E1M5 = HUSTR_E1M5; +const char *s_HUSTR_E1M6 = HUSTR_E1M6; +const char *s_HUSTR_E1M7 = HUSTR_E1M7; +const char *s_HUSTR_E1M8 = HUSTR_E1M8; +const char *s_HUSTR_E1M9 = HUSTR_E1M9; +const char *s_HUSTR_E2M1 = HUSTR_E2M1; +const char *s_HUSTR_E2M2 = HUSTR_E2M2; +const char *s_HUSTR_E2M3 = HUSTR_E2M3; +const char *s_HUSTR_E2M4 = HUSTR_E2M4; +const char *s_HUSTR_E2M5 = HUSTR_E2M5; +const char *s_HUSTR_E2M6 = HUSTR_E2M6; +const char *s_HUSTR_E2M7 = HUSTR_E2M7; +const char *s_HUSTR_E2M8 = HUSTR_E2M8; +const char *s_HUSTR_E2M9 = HUSTR_E2M9; +const char *s_HUSTR_E3M1 = HUSTR_E3M1; +const char *s_HUSTR_E3M2 = HUSTR_E3M2; +const char *s_HUSTR_E3M3 = HUSTR_E3M3; +const char *s_HUSTR_E3M4 = HUSTR_E3M4; +const char *s_HUSTR_E3M5 = HUSTR_E3M5; +const char *s_HUSTR_E3M6 = HUSTR_E3M6; +const char *s_HUSTR_E3M7 = HUSTR_E3M7; +const char *s_HUSTR_E3M8 = HUSTR_E3M8; +const char *s_HUSTR_E3M9 = HUSTR_E3M9; +const char *s_HUSTR_E4M1 = HUSTR_E4M1; +const char *s_HUSTR_E4M2 = HUSTR_E4M2; +const char *s_HUSTR_E4M3 = HUSTR_E4M3; +const char *s_HUSTR_E4M4 = HUSTR_E4M4; +const char *s_HUSTR_E4M5 = HUSTR_E4M5; +const char *s_HUSTR_E4M6 = HUSTR_E4M6; +const char *s_HUSTR_E4M7 = HUSTR_E4M7; +const char *s_HUSTR_E4M8 = HUSTR_E4M8; +const char *s_HUSTR_E4M9 = HUSTR_E4M9; +const char *s_HUSTR_1 = HUSTR_1; +const char *s_HUSTR_2 = HUSTR_2; +const char *s_HUSTR_3 = HUSTR_3; +const char *s_HUSTR_4 = HUSTR_4; +const char *s_HUSTR_5 = HUSTR_5; +const char *s_HUSTR_6 = HUSTR_6; +const char *s_HUSTR_7 = HUSTR_7; +const char *s_HUSTR_8 = HUSTR_8; +const char *s_HUSTR_9 = HUSTR_9; +const char *s_HUSTR_10 = HUSTR_10; +const char *s_HUSTR_11 = HUSTR_11; +const char *s_HUSTR_12 = HUSTR_12; +const char *s_HUSTR_13 = HUSTR_13; +const char *s_HUSTR_14 = HUSTR_14; +const char *s_HUSTR_15 = HUSTR_15; +const char *s_HUSTR_16 = HUSTR_16; +const char *s_HUSTR_17 = HUSTR_17; +const char *s_HUSTR_18 = HUSTR_18; +const char *s_HUSTR_19 = HUSTR_19; +const char *s_HUSTR_20 = HUSTR_20; +const char *s_HUSTR_21 = HUSTR_21; +const char *s_HUSTR_22 = HUSTR_22; +const char *s_HUSTR_23 = HUSTR_23; +const char *s_HUSTR_24 = HUSTR_24; +const char *s_HUSTR_25 = HUSTR_25; +const char *s_HUSTR_26 = HUSTR_26; +const char *s_HUSTR_27 = HUSTR_27; +const char *s_HUSTR_28 = HUSTR_28; +const char *s_HUSTR_29 = HUSTR_29; +const char *s_HUSTR_30 = HUSTR_30; +const char *s_HUSTR_31 = HUSTR_31; +const char *s_HUSTR_32 = HUSTR_32; +const char *s_PHUSTR_1 = PHUSTR_1; +const char *s_PHUSTR_2 = PHUSTR_2; +const char *s_PHUSTR_3 = PHUSTR_3; +const char *s_PHUSTR_4 = PHUSTR_4; +const char *s_PHUSTR_5 = PHUSTR_5; +const char *s_PHUSTR_6 = PHUSTR_6; +const char *s_PHUSTR_7 = PHUSTR_7; +const char *s_PHUSTR_8 = PHUSTR_8; +const char *s_PHUSTR_9 = PHUSTR_9; +const char *s_PHUSTR_10 = PHUSTR_10; +const char *s_PHUSTR_11 = PHUSTR_11; +const char *s_PHUSTR_12 = PHUSTR_12; +const char *s_PHUSTR_13 = PHUSTR_13; +const char *s_PHUSTR_14 = PHUSTR_14; +const char *s_PHUSTR_15 = PHUSTR_15; +const char *s_PHUSTR_16 = PHUSTR_16; +const char *s_PHUSTR_17 = PHUSTR_17; +const char *s_PHUSTR_18 = PHUSTR_18; +const char *s_PHUSTR_19 = PHUSTR_19; +const char *s_PHUSTR_20 = PHUSTR_20; +const char *s_PHUSTR_21 = PHUSTR_21; +const char *s_PHUSTR_22 = PHUSTR_22; +const char *s_PHUSTR_23 = PHUSTR_23; +const char *s_PHUSTR_24 = PHUSTR_24; +const char *s_PHUSTR_25 = PHUSTR_25; +const char *s_PHUSTR_26 = PHUSTR_26; +const char *s_PHUSTR_27 = PHUSTR_27; +const char *s_PHUSTR_28 = PHUSTR_28; +const char *s_PHUSTR_29 = PHUSTR_29; +const char *s_PHUSTR_30 = PHUSTR_30; +const char *s_PHUSTR_31 = PHUSTR_31; +const char *s_PHUSTR_32 = PHUSTR_32; +const char *s_THUSTR_1 = THUSTR_1; +const char *s_THUSTR_2 = THUSTR_2; +const char *s_THUSTR_3 = THUSTR_3; +const char *s_THUSTR_4 = THUSTR_4; +const char *s_THUSTR_5 = THUSTR_5; +const char *s_THUSTR_6 = THUSTR_6; +const char *s_THUSTR_7 = THUSTR_7; +const char *s_THUSTR_8 = THUSTR_8; +const char *s_THUSTR_9 = THUSTR_9; +const char *s_THUSTR_10 = THUSTR_10; +const char *s_THUSTR_11 = THUSTR_11; +const char *s_THUSTR_12 = THUSTR_12; +const char *s_THUSTR_13 = THUSTR_13; +const char *s_THUSTR_14 = THUSTR_14; +const char *s_THUSTR_15 = THUSTR_15; +const char *s_THUSTR_16 = THUSTR_16; +const char *s_THUSTR_17 = THUSTR_17; +const char *s_THUSTR_18 = THUSTR_18; +const char *s_THUSTR_19 = THUSTR_19; +const char *s_THUSTR_20 = THUSTR_20; +const char *s_THUSTR_21 = THUSTR_21; +const char *s_THUSTR_22 = THUSTR_22; +const char *s_THUSTR_23 = THUSTR_23; +const char *s_THUSTR_24 = THUSTR_24; +const char *s_THUSTR_25 = THUSTR_25; +const char *s_THUSTR_26 = THUSTR_26; +const char *s_THUSTR_27 = THUSTR_27; +const char *s_THUSTR_28 = THUSTR_28; +const char *s_THUSTR_29 = THUSTR_29; +const char *s_THUSTR_30 = THUSTR_30; +const char *s_THUSTR_31 = THUSTR_31; +const char *s_THUSTR_32 = THUSTR_32; +const char *s_HUSTR_CHATMACRO1 = HUSTR_CHATMACRO1; +const char *s_HUSTR_CHATMACRO2 = HUSTR_CHATMACRO2; +const char *s_HUSTR_CHATMACRO3 = HUSTR_CHATMACRO3; +const char *s_HUSTR_CHATMACRO4 = HUSTR_CHATMACRO4; +const char *s_HUSTR_CHATMACRO5 = HUSTR_CHATMACRO5; +const char *s_HUSTR_CHATMACRO6 = HUSTR_CHATMACRO6; +const char *s_HUSTR_CHATMACRO7 = HUSTR_CHATMACRO7; +const char *s_HUSTR_CHATMACRO8 = HUSTR_CHATMACRO8; +const char *s_HUSTR_CHATMACRO9 = HUSTR_CHATMACRO9; +const char *s_HUSTR_CHATMACRO0 = HUSTR_CHATMACRO0; +const char *s_HUSTR_TALKTOSELF1 = HUSTR_TALKTOSELF1; +const char *s_HUSTR_TALKTOSELF2 = HUSTR_TALKTOSELF2; +const char *s_HUSTR_TALKTOSELF3 = HUSTR_TALKTOSELF3; +const char *s_HUSTR_TALKTOSELF4 = HUSTR_TALKTOSELF4; +const char *s_HUSTR_TALKTOSELF5 = HUSTR_TALKTOSELF5; +const char *s_HUSTR_MESSAGESENT = HUSTR_MESSAGESENT; +const char *s_HUSTR_PLRGREEN = HUSTR_PLRGREEN; +const char *s_HUSTR_PLRINDIGO = HUSTR_PLRINDIGO; +const char *s_HUSTR_PLRBROWN = HUSTR_PLRBROWN; +const char *s_HUSTR_PLRRED = HUSTR_PLRRED; +const char *s_AMSTR_FOLLOWON = AMSTR_FOLLOWON; +const char *s_AMSTR_FOLLOWOFF = AMSTR_FOLLOWOFF; +const char *s_AMSTR_GRIDON = AMSTR_GRIDON; +const char *s_AMSTR_GRIDOFF = AMSTR_GRIDOFF; +const char *s_AMSTR_MARKEDSPOT = AMSTR_MARKEDSPOT; +const char *s_AMSTR_MARKSCLEARED = AMSTR_MARKSCLEARED; +// CPhipps - automap rotate & overlay +const char* s_AMSTR_ROTATEON = AMSTR_ROTATEON; +const char* s_AMSTR_ROTATEOFF = AMSTR_ROTATEOFF; +const char* s_AMSTR_OVERLAYON = AMSTR_OVERLAYON; +const char* s_AMSTR_OVERLAYOFF = AMSTR_OVERLAYOFF; +const char *s_STSTR_MUS = STSTR_MUS; +const char *s_STSTR_NOMUS = STSTR_NOMUS; +const char *s_STSTR_DQDON = STSTR_DQDON; +const char *s_STSTR_DQDOFF = STSTR_DQDOFF; +const char *s_STSTR_KFAADDED = STSTR_KFAADDED; +const char *s_STSTR_FAADDED = STSTR_FAADDED; +const char *s_STSTR_NCON = STSTR_NCON; +const char *s_STSTR_NCOFF = STSTR_NCOFF; +const char *s_STSTR_BEHOLD = STSTR_BEHOLD; +const char *s_STSTR_BEHOLDX = STSTR_BEHOLDX; +const char *s_STSTR_CHOPPERS = STSTR_CHOPPERS; +const char *s_STSTR_CLEV = STSTR_CLEV; +const char *s_STSTR_COMPON = STSTR_COMPON; +const char *s_STSTR_COMPOFF = STSTR_COMPOFF; +const char *s_E1TEXT = E1TEXT; +const char *s_E2TEXT = E2TEXT; +const char *s_E3TEXT = E3TEXT; +const char *s_E4TEXT = E4TEXT; +const char *s_C1TEXT = C1TEXT; +const char *s_C2TEXT = C2TEXT; +const char *s_C3TEXT = C3TEXT; +const char *s_C4TEXT = C4TEXT; +const char *s_C5TEXT = C5TEXT; +const char *s_C6TEXT = C6TEXT; +const char *s_P1TEXT = P1TEXT; +const char *s_P2TEXT = P2TEXT; +const char *s_P3TEXT = P3TEXT; +const char *s_P4TEXT = P4TEXT; +const char *s_P5TEXT = P5TEXT; +const char *s_P6TEXT = P6TEXT; +const char *s_T1TEXT = T1TEXT; +const char *s_T2TEXT = T2TEXT; +const char *s_T3TEXT = T3TEXT; +const char *s_T4TEXT = T4TEXT; +const char *s_T5TEXT = T5TEXT; +const char *s_T6TEXT = T6TEXT; +const char *s_CC_ZOMBIE = CC_ZOMBIE; +const char *s_CC_SHOTGUN = CC_SHOTGUN; +const char *s_CC_HEAVY = CC_HEAVY; +const char *s_CC_IMP = CC_IMP; +const char *s_CC_DEMON = CC_DEMON; +const char *s_CC_LOST = CC_LOST; +const char *s_CC_CACO = CC_CACO; +const char *s_CC_HELL = CC_HELL; +const char *s_CC_BARON = CC_BARON; +const char *s_CC_ARACH = CC_ARACH; +const char *s_CC_PAIN = CC_PAIN; +const char *s_CC_REVEN = CC_REVEN; +const char *s_CC_MANCU = CC_MANCU; +const char *s_CC_ARCH = CC_ARCH; +const char *s_CC_SPIDER = CC_SPIDER; +const char *s_CC_CYBER = CC_CYBER; +const char *s_CC_HERO = CC_HERO; +// Ty 03/30/98 - new substitutions for background textures +// during int screens +const char *bgflatE1 = "FLOOR4_8"; // end of DOOM Episode 1 +const char *bgflatE2 = "SFLR6_1"; // end of DOOM Episode 2 +const char *bgflatE3 = "MFLR8_4"; // end of DOOM Episode 3 +const char *bgflatE4 = "MFLR8_3"; // end of DOOM Episode 4 +const char *bgflat06 = "SLIME16"; // DOOM2 after MAP06 +const char *bgflat11 = "RROCK14"; // DOOM2 after MAP11 +const char *bgflat20 = "RROCK07"; // DOOM2 after MAP20 +const char *bgflat30 = "RROCK17"; // DOOM2 after MAP30 +const char *bgflat15 = "RROCK13"; // DOOM2 going MAP15 to MAP31 +const char *bgflat31 = "RROCK19"; // DOOM2 going MAP31 to MAP32 +const char *bgcastcall = "BOSSBACK"; // Panel behind cast call + +const char *startup1 = ""; // blank lines are default and are not printed +const char *startup2 = ""; +const char *startup3 = ""; +const char *startup4 = ""; +const char *startup5 = ""; + +/* Ty 05/03/98 - externalized + * cph - updated for prboom */ +const char *savegamename = "prbmsav"; + +// end d_deh.h variable declarations +// ==================================================================== + +// Do this for a lookup--the pointer (loaded above) is cross-referenced +// to a string key that is the same as the define above. We will use +// strdups to set these new values that we read from the file, orphaning +// the original value set above. + +// CPhipps - make strings pointed to const +typedef struct { + const char **ppstr; // doubly indirect pointer to string + const char *lookup; // pointer to lookup string name +} deh_strs; + +/* CPhipps - const, static + * - removed redundant "Can't XXX in a netgame" strings + */ +static const deh_strs deh_strlookup[] = { + {&s_D_DEVSTR,"D_DEVSTR"}, + {&s_D_CDROM,"D_CDROM"}, + {&s_PRESSKEY,"PRESSKEY"}, + {&s_PRESSYN,"PRESSYN"}, + {&s_QUITMSG,"QUITMSG"}, + {&s_QSAVESPOT,"QSAVESPOT"}, + {&s_SAVEDEAD,"SAVEDEAD"}, + /* cph - disabled to prevent format string attacks in WAD files + {&s_QSPROMPT,"QSPROMPT"}, + {&s_QLPROMPT,"QLPROMPT"},*/ + {&s_NEWGAME,"NEWGAME"}, + {&s_RESTARTLEVEL,"RESTARTLEVEL"}, + {&s_NIGHTMARE,"NIGHTMARE"}, + {&s_SWSTRING,"SWSTRING"}, + {&s_MSGOFF,"MSGOFF"}, + {&s_MSGON,"MSGON"}, + {&s_NETEND,"NETEND"}, + {&s_ENDGAME,"ENDGAME"}, + {&s_DOSY,"DOSY"}, + {&s_DETAILHI,"DETAILHI"}, + {&s_DETAILLO,"DETAILLO"}, + {&s_GAMMALVL0,"GAMMALVL0"}, + {&s_GAMMALVL1,"GAMMALVL1"}, + {&s_GAMMALVL2,"GAMMALVL2"}, + {&s_GAMMALVL3,"GAMMALVL3"}, + {&s_GAMMALVL4,"GAMMALVL4"}, + {&s_EMPTYSTRING,"EMPTYSTRING"}, + {&s_GOTARMOR,"GOTARMOR"}, + {&s_GOTMEGA,"GOTMEGA"}, + {&s_GOTHTHBONUS,"GOTHTHBONUS"}, + {&s_GOTARMBONUS,"GOTARMBONUS"}, + {&s_GOTSTIM,"GOTSTIM"}, + {&s_GOTMEDINEED,"GOTMEDINEED"}, + {&s_GOTMEDIKIT,"GOTMEDIKIT"}, + {&s_GOTSUPER,"GOTSUPER"}, + {&s_GOTBLUECARD,"GOTBLUECARD"}, + {&s_GOTYELWCARD,"GOTYELWCARD"}, + {&s_GOTREDCARD,"GOTREDCARD"}, + {&s_GOTBLUESKUL,"GOTBLUESKUL"}, + {&s_GOTYELWSKUL,"GOTYELWSKUL"}, + {&s_GOTREDSKULL,"GOTREDSKULL"}, + {&s_GOTINVUL,"GOTINVUL"}, + {&s_GOTBERSERK,"GOTBERSERK"}, + {&s_GOTINVIS,"GOTINVIS"}, + {&s_GOTSUIT,"GOTSUIT"}, + {&s_GOTMAP,"GOTMAP"}, + {&s_GOTVISOR,"GOTVISOR"}, + {&s_GOTMSPHERE,"GOTMSPHERE"}, + {&s_GOTCLIP,"GOTCLIP"}, + {&s_GOTCLIPBOX,"GOTCLIPBOX"}, + {&s_GOTROCKET,"GOTROCKET"}, + {&s_GOTROCKBOX,"GOTROCKBOX"}, + {&s_GOTCELL,"GOTCELL"}, + {&s_GOTCELLBOX,"GOTCELLBOX"}, + {&s_GOTSHELLS,"GOTSHELLS"}, + {&s_GOTSHELLBOX,"GOTSHELLBOX"}, + {&s_GOTBACKPACK,"GOTBACKPACK"}, + {&s_GOTBFG9000,"GOTBFG9000"}, + {&s_GOTCHAINGUN,"GOTCHAINGUN"}, + {&s_GOTCHAINSAW,"GOTCHAINSAW"}, + {&s_GOTLAUNCHER,"GOTLAUNCHER"}, + {&s_GOTPLASMA,"GOTPLASMA"}, + {&s_GOTSHOTGUN,"GOTSHOTGUN"}, + {&s_GOTSHOTGUN2,"GOTSHOTGUN2"}, + {&s_PD_BLUEO,"PD_BLUEO"}, + {&s_PD_REDO,"PD_REDO"}, + {&s_PD_YELLOWO,"PD_YELLOWO"}, + {&s_PD_BLUEK,"PD_BLUEK"}, + {&s_PD_REDK,"PD_REDK"}, + {&s_PD_YELLOWK,"PD_YELLOWK"}, + {&s_PD_BLUEC,"PD_BLUEC"}, + {&s_PD_REDC,"PD_REDC"}, + {&s_PD_YELLOWC,"PD_YELLOWC"}, + {&s_PD_BLUES,"PD_BLUES"}, + {&s_PD_REDS,"PD_REDS"}, + {&s_PD_YELLOWS,"PD_YELLOWS"}, + {&s_PD_ANY,"PD_ANY"}, + {&s_PD_ALL3,"PD_ALL3"}, + {&s_PD_ALL6,"PD_ALL6"}, + {&s_GGSAVED,"GGSAVED"}, + {&s_HUSTR_MSGU,"HUSTR_MSGU"}, + {&s_HUSTR_E1M1,"HUSTR_E1M1"}, + {&s_HUSTR_E1M2,"HUSTR_E1M2"}, + {&s_HUSTR_E1M3,"HUSTR_E1M3"}, + {&s_HUSTR_E1M4,"HUSTR_E1M4"}, + {&s_HUSTR_E1M5,"HUSTR_E1M5"}, + {&s_HUSTR_E1M6,"HUSTR_E1M6"}, + {&s_HUSTR_E1M7,"HUSTR_E1M7"}, + {&s_HUSTR_E1M8,"HUSTR_E1M8"}, + {&s_HUSTR_E1M9,"HUSTR_E1M9"}, + {&s_HUSTR_E2M1,"HUSTR_E2M1"}, + {&s_HUSTR_E2M2,"HUSTR_E2M2"}, + {&s_HUSTR_E2M3,"HUSTR_E2M3"}, + {&s_HUSTR_E2M4,"HUSTR_E2M4"}, + {&s_HUSTR_E2M5,"HUSTR_E2M5"}, + {&s_HUSTR_E2M6,"HUSTR_E2M6"}, + {&s_HUSTR_E2M7,"HUSTR_E2M7"}, + {&s_HUSTR_E2M8,"HUSTR_E2M8"}, + {&s_HUSTR_E2M9,"HUSTR_E2M9"}, + {&s_HUSTR_E3M1,"HUSTR_E3M1"}, + {&s_HUSTR_E3M2,"HUSTR_E3M2"}, + {&s_HUSTR_E3M3,"HUSTR_E3M3"}, + {&s_HUSTR_E3M4,"HUSTR_E3M4"}, + {&s_HUSTR_E3M5,"HUSTR_E3M5"}, + {&s_HUSTR_E3M6,"HUSTR_E3M6"}, + {&s_HUSTR_E3M7,"HUSTR_E3M7"}, + {&s_HUSTR_E3M8,"HUSTR_E3M8"}, + {&s_HUSTR_E3M9,"HUSTR_E3M9"}, + {&s_HUSTR_E4M1,"HUSTR_E4M1"}, + {&s_HUSTR_E4M2,"HUSTR_E4M2"}, + {&s_HUSTR_E4M3,"HUSTR_E4M3"}, + {&s_HUSTR_E4M4,"HUSTR_E4M4"}, + {&s_HUSTR_E4M5,"HUSTR_E4M5"}, + {&s_HUSTR_E4M6,"HUSTR_E4M6"}, + {&s_HUSTR_E4M7,"HUSTR_E4M7"}, + {&s_HUSTR_E4M8,"HUSTR_E4M8"}, + {&s_HUSTR_E4M9,"HUSTR_E4M9"}, + {&s_HUSTR_1,"HUSTR_1"}, + {&s_HUSTR_2,"HUSTR_2"}, + {&s_HUSTR_3,"HUSTR_3"}, + {&s_HUSTR_4,"HUSTR_4"}, + {&s_HUSTR_5,"HUSTR_5"}, + {&s_HUSTR_6,"HUSTR_6"}, + {&s_HUSTR_7,"HUSTR_7"}, + {&s_HUSTR_8,"HUSTR_8"}, + {&s_HUSTR_9,"HUSTR_9"}, + {&s_HUSTR_10,"HUSTR_10"}, + {&s_HUSTR_11,"HUSTR_11"}, + {&s_HUSTR_12,"HUSTR_12"}, + {&s_HUSTR_13,"HUSTR_13"}, + {&s_HUSTR_14,"HUSTR_14"}, + {&s_HUSTR_15,"HUSTR_15"}, + {&s_HUSTR_16,"HUSTR_16"}, + {&s_HUSTR_17,"HUSTR_17"}, + {&s_HUSTR_18,"HUSTR_18"}, + {&s_HUSTR_19,"HUSTR_19"}, + {&s_HUSTR_20,"HUSTR_20"}, + {&s_HUSTR_21,"HUSTR_21"}, + {&s_HUSTR_22,"HUSTR_22"}, + {&s_HUSTR_23,"HUSTR_23"}, + {&s_HUSTR_24,"HUSTR_24"}, + {&s_HUSTR_25,"HUSTR_25"}, + {&s_HUSTR_26,"HUSTR_26"}, + {&s_HUSTR_27,"HUSTR_27"}, + {&s_HUSTR_28,"HUSTR_28"}, + {&s_HUSTR_29,"HUSTR_29"}, + {&s_HUSTR_30,"HUSTR_30"}, + {&s_HUSTR_31,"HUSTR_31"}, + {&s_HUSTR_32,"HUSTR_32"}, + {&s_PHUSTR_1,"PHUSTR_1"}, + {&s_PHUSTR_2,"PHUSTR_2"}, + {&s_PHUSTR_3,"PHUSTR_3"}, + {&s_PHUSTR_4,"PHUSTR_4"}, + {&s_PHUSTR_5,"PHUSTR_5"}, + {&s_PHUSTR_6,"PHUSTR_6"}, + {&s_PHUSTR_7,"PHUSTR_7"}, + {&s_PHUSTR_8,"PHUSTR_8"}, + {&s_PHUSTR_9,"PHUSTR_9"}, + {&s_PHUSTR_10,"PHUSTR_10"}, + {&s_PHUSTR_11,"PHUSTR_11"}, + {&s_PHUSTR_12,"PHUSTR_12"}, + {&s_PHUSTR_13,"PHUSTR_13"}, + {&s_PHUSTR_14,"PHUSTR_14"}, + {&s_PHUSTR_15,"PHUSTR_15"}, + {&s_PHUSTR_16,"PHUSTR_16"}, + {&s_PHUSTR_17,"PHUSTR_17"}, + {&s_PHUSTR_18,"PHUSTR_18"}, + {&s_PHUSTR_19,"PHUSTR_19"}, + {&s_PHUSTR_20,"PHUSTR_20"}, + {&s_PHUSTR_21,"PHUSTR_21"}, + {&s_PHUSTR_22,"PHUSTR_22"}, + {&s_PHUSTR_23,"PHUSTR_23"}, + {&s_PHUSTR_24,"PHUSTR_24"}, + {&s_PHUSTR_25,"PHUSTR_25"}, + {&s_PHUSTR_26,"PHUSTR_26"}, + {&s_PHUSTR_27,"PHUSTR_27"}, + {&s_PHUSTR_28,"PHUSTR_28"}, + {&s_PHUSTR_29,"PHUSTR_29"}, + {&s_PHUSTR_30,"PHUSTR_30"}, + {&s_PHUSTR_31,"PHUSTR_31"}, + {&s_PHUSTR_32,"PHUSTR_32"}, + {&s_THUSTR_1,"THUSTR_1"}, + {&s_THUSTR_2,"THUSTR_2"}, + {&s_THUSTR_3,"THUSTR_3"}, + {&s_THUSTR_4,"THUSTR_4"}, + {&s_THUSTR_5,"THUSTR_5"}, + {&s_THUSTR_6,"THUSTR_6"}, + {&s_THUSTR_7,"THUSTR_7"}, + {&s_THUSTR_8,"THUSTR_8"}, + {&s_THUSTR_9,"THUSTR_9"}, + {&s_THUSTR_10,"THUSTR_10"}, + {&s_THUSTR_11,"THUSTR_11"}, + {&s_THUSTR_12,"THUSTR_12"}, + {&s_THUSTR_13,"THUSTR_13"}, + {&s_THUSTR_14,"THUSTR_14"}, + {&s_THUSTR_15,"THUSTR_15"}, + {&s_THUSTR_16,"THUSTR_16"}, + {&s_THUSTR_17,"THUSTR_17"}, + {&s_THUSTR_18,"THUSTR_18"}, + {&s_THUSTR_19,"THUSTR_19"}, + {&s_THUSTR_20,"THUSTR_20"}, + {&s_THUSTR_21,"THUSTR_21"}, + {&s_THUSTR_22,"THUSTR_22"}, + {&s_THUSTR_23,"THUSTR_23"}, + {&s_THUSTR_24,"THUSTR_24"}, + {&s_THUSTR_25,"THUSTR_25"}, + {&s_THUSTR_26,"THUSTR_26"}, + {&s_THUSTR_27,"THUSTR_27"}, + {&s_THUSTR_28,"THUSTR_28"}, + {&s_THUSTR_29,"THUSTR_29"}, + {&s_THUSTR_30,"THUSTR_30"}, + {&s_THUSTR_31,"THUSTR_31"}, + {&s_THUSTR_32,"THUSTR_32"}, + {&s_HUSTR_CHATMACRO1,"HUSTR_CHATMACRO1"}, + {&s_HUSTR_CHATMACRO2,"HUSTR_CHATMACRO2"}, + {&s_HUSTR_CHATMACRO3,"HUSTR_CHATMACRO3"}, + {&s_HUSTR_CHATMACRO4,"HUSTR_CHATMACRO4"}, + {&s_HUSTR_CHATMACRO5,"HUSTR_CHATMACRO5"}, + {&s_HUSTR_CHATMACRO6,"HUSTR_CHATMACRO6"}, + {&s_HUSTR_CHATMACRO7,"HUSTR_CHATMACRO7"}, + {&s_HUSTR_CHATMACRO8,"HUSTR_CHATMACRO8"}, + {&s_HUSTR_CHATMACRO9,"HUSTR_CHATMACRO9"}, + {&s_HUSTR_CHATMACRO0,"HUSTR_CHATMACRO0"}, + {&s_HUSTR_TALKTOSELF1,"HUSTR_TALKTOSELF1"}, + {&s_HUSTR_TALKTOSELF2,"HUSTR_TALKTOSELF2"}, + {&s_HUSTR_TALKTOSELF3,"HUSTR_TALKTOSELF3"}, + {&s_HUSTR_TALKTOSELF4,"HUSTR_TALKTOSELF4"}, + {&s_HUSTR_TALKTOSELF5,"HUSTR_TALKTOSELF5"}, + {&s_HUSTR_MESSAGESENT,"HUSTR_MESSAGESENT"}, + {&s_HUSTR_PLRGREEN,"HUSTR_PLRGREEN"}, + {&s_HUSTR_PLRINDIGO,"HUSTR_PLRINDIGO"}, + {&s_HUSTR_PLRBROWN,"HUSTR_PLRBROWN"}, + {&s_HUSTR_PLRRED,"HUSTR_PLRRED"}, + //{c_HUSTR_KEYGREEN,"HUSTR_KEYGREEN"}, + //{c_HUSTR_KEYINDIGO,"HUSTR_KEYINDIGO"}, + //{c_HUSTR_KEYBROWN,"HUSTR_KEYBROWN"}, + //{c_HUSTR_KEYRED,"HUSTR_KEYRED"}, + {&s_AMSTR_FOLLOWON,"AMSTR_FOLLOWON"}, + {&s_AMSTR_FOLLOWOFF,"AMSTR_FOLLOWOFF"}, + {&s_AMSTR_GRIDON,"AMSTR_GRIDON"}, + {&s_AMSTR_GRIDOFF,"AMSTR_GRIDOFF"}, + {&s_AMSTR_MARKEDSPOT,"AMSTR_MARKEDSPOT"}, + {&s_AMSTR_MARKSCLEARED,"AMSTR_MARKSCLEARED"}, + {&s_STSTR_MUS,"STSTR_MUS"}, + {&s_STSTR_NOMUS,"STSTR_NOMUS"}, + {&s_STSTR_DQDON,"STSTR_DQDON"}, + {&s_STSTR_DQDOFF,"STSTR_DQDOFF"}, + {&s_STSTR_KFAADDED,"STSTR_KFAADDED"}, + {&s_STSTR_FAADDED,"STSTR_FAADDED"}, + {&s_STSTR_NCON,"STSTR_NCON"}, + {&s_STSTR_NCOFF,"STSTR_NCOFF"}, + {&s_STSTR_BEHOLD,"STSTR_BEHOLD"}, + {&s_STSTR_BEHOLDX,"STSTR_BEHOLDX"}, + {&s_STSTR_CHOPPERS,"STSTR_CHOPPERS"}, + {&s_STSTR_CLEV,"STSTR_CLEV"}, + {&s_STSTR_COMPON,"STSTR_COMPON"}, + {&s_STSTR_COMPOFF,"STSTR_COMPOFF"}, + {&s_E1TEXT,"E1TEXT"}, + {&s_E2TEXT,"E2TEXT"}, + {&s_E3TEXT,"E3TEXT"}, + {&s_E4TEXT,"E4TEXT"}, + {&s_C1TEXT,"C1TEXT"}, + {&s_C2TEXT,"C2TEXT"}, + {&s_C3TEXT,"C3TEXT"}, + {&s_C4TEXT,"C4TEXT"}, + {&s_C5TEXT,"C5TEXT"}, + {&s_C6TEXT,"C6TEXT"}, + {&s_P1TEXT,"P1TEXT"}, + {&s_P2TEXT,"P2TEXT"}, + {&s_P3TEXT,"P3TEXT"}, + {&s_P4TEXT,"P4TEXT"}, + {&s_P5TEXT,"P5TEXT"}, + {&s_P6TEXT,"P6TEXT"}, + {&s_T1TEXT,"T1TEXT"}, + {&s_T2TEXT,"T2TEXT"}, + {&s_T3TEXT,"T3TEXT"}, + {&s_T4TEXT,"T4TEXT"}, + {&s_T5TEXT,"T5TEXT"}, + {&s_T6TEXT,"T6TEXT"}, + {&s_CC_ZOMBIE,"CC_ZOMBIE"}, + {&s_CC_SHOTGUN,"CC_SHOTGUN"}, + {&s_CC_HEAVY,"CC_HEAVY"}, + {&s_CC_IMP,"CC_IMP"}, + {&s_CC_DEMON,"CC_DEMON"}, + {&s_CC_LOST,"CC_LOST"}, + {&s_CC_CACO,"CC_CACO"}, + {&s_CC_HELL,"CC_HELL"}, + {&s_CC_BARON,"CC_BARON"}, + {&s_CC_ARACH,"CC_ARACH"}, + {&s_CC_PAIN,"CC_PAIN"}, + {&s_CC_REVEN,"CC_REVEN"}, + {&s_CC_MANCU,"CC_MANCU"}, + {&s_CC_ARCH,"CC_ARCH"}, + {&s_CC_SPIDER,"CC_SPIDER"}, + {&s_CC_CYBER,"CC_CYBER"}, + {&s_CC_HERO,"CC_HERO"}, + {&bgflatE1,"BGFLATE1"}, + {&bgflatE2,"BGFLATE2"}, + {&bgflatE3,"BGFLATE3"}, + {&bgflatE4,"BGFLATE4"}, + {&bgflat06,"BGFLAT06"}, + {&bgflat11,"BGFLAT11"}, + {&bgflat20,"BGFLAT20"}, + {&bgflat30,"BGFLAT30"}, + {&bgflat15,"BGFLAT15"}, + {&bgflat31,"BGFLAT31"}, + {&bgcastcall,"BGCASTCALL"}, + // Ty 04/08/98 - added 5 general purpose startup announcement + // strings for hacker use. See m_menu.c + {&startup1,"STARTUP1"}, + {&startup2,"STARTUP2"}, + {&startup3,"STARTUP3"}, + {&startup4,"STARTUP4"}, + {&startup5,"STARTUP5"}, + {&savegamename,"SAVEGAMENAME"}, // Ty 05/03/98 +}; + +static int deh_numstrlookup = +sizeof(deh_strlookup)/sizeof(deh_strlookup[0]); + +const char *deh_newlevel = "NEWLEVEL"; // CPhipps - const + +// DOOM shareware/registered/retail (Ultimate) names. +// CPhipps - const**const +const char **const mapnames[] = +{ + &s_HUSTR_E1M1, + &s_HUSTR_E1M2, + &s_HUSTR_E1M3, + &s_HUSTR_E1M4, + &s_HUSTR_E1M5, + &s_HUSTR_E1M6, + &s_HUSTR_E1M7, + &s_HUSTR_E1M8, + &s_HUSTR_E1M9, + + &s_HUSTR_E2M1, + &s_HUSTR_E2M2, + &s_HUSTR_E2M3, + &s_HUSTR_E2M4, + &s_HUSTR_E2M5, + &s_HUSTR_E2M6, + &s_HUSTR_E2M7, + &s_HUSTR_E2M8, + &s_HUSTR_E2M9, + + &s_HUSTR_E3M1, + &s_HUSTR_E3M2, + &s_HUSTR_E3M3, + &s_HUSTR_E3M4, + &s_HUSTR_E3M5, + &s_HUSTR_E3M6, + &s_HUSTR_E3M7, + &s_HUSTR_E3M8, + &s_HUSTR_E3M9, + + &s_HUSTR_E4M1, + &s_HUSTR_E4M2, + &s_HUSTR_E4M3, + &s_HUSTR_E4M4, + &s_HUSTR_E4M5, + &s_HUSTR_E4M6, + &s_HUSTR_E4M7, + &s_HUSTR_E4M8, + &s_HUSTR_E4M9, + + &deh_newlevel, // spares? Unused. + &deh_newlevel, + &deh_newlevel, + &deh_newlevel, + &deh_newlevel, + &deh_newlevel, + &deh_newlevel, + &deh_newlevel, + &deh_newlevel +}; + +// CPhipps - const**const +const char **const mapnames2[] = // DOOM 2 map names. +{ + &s_HUSTR_1, + &s_HUSTR_2, + &s_HUSTR_3, + &s_HUSTR_4, + &s_HUSTR_5, + &s_HUSTR_6, + &s_HUSTR_7, + &s_HUSTR_8, + &s_HUSTR_9, + &s_HUSTR_10, + &s_HUSTR_11, + + &s_HUSTR_12, + &s_HUSTR_13, + &s_HUSTR_14, + &s_HUSTR_15, + &s_HUSTR_16, + &s_HUSTR_17, + &s_HUSTR_18, + &s_HUSTR_19, + &s_HUSTR_20, + + &s_HUSTR_21, + &s_HUSTR_22, + &s_HUSTR_23, + &s_HUSTR_24, + &s_HUSTR_25, + &s_HUSTR_26, + &s_HUSTR_27, + &s_HUSTR_28, + &s_HUSTR_29, + &s_HUSTR_30, + &s_HUSTR_31, + &s_HUSTR_32, +}; + +// CPhipps - const**const +const char **const mapnamesp[] = // Plutonia WAD map names. +{ + &s_PHUSTR_1, + &s_PHUSTR_2, + &s_PHUSTR_3, + &s_PHUSTR_4, + &s_PHUSTR_5, + &s_PHUSTR_6, + &s_PHUSTR_7, + &s_PHUSTR_8, + &s_PHUSTR_9, + &s_PHUSTR_10, + &s_PHUSTR_11, + + &s_PHUSTR_12, + &s_PHUSTR_13, + &s_PHUSTR_14, + &s_PHUSTR_15, + &s_PHUSTR_16, + &s_PHUSTR_17, + &s_PHUSTR_18, + &s_PHUSTR_19, + &s_PHUSTR_20, + + &s_PHUSTR_21, + &s_PHUSTR_22, + &s_PHUSTR_23, + &s_PHUSTR_24, + &s_PHUSTR_25, + &s_PHUSTR_26, + &s_PHUSTR_27, + &s_PHUSTR_28, + &s_PHUSTR_29, + &s_PHUSTR_30, + &s_PHUSTR_31, + &s_PHUSTR_32, +}; + +// CPhipps - const**const +const char **const mapnamest[] = // TNT WAD map names. +{ + &s_THUSTR_1, + &s_THUSTR_2, + &s_THUSTR_3, + &s_THUSTR_4, + &s_THUSTR_5, + &s_THUSTR_6, + &s_THUSTR_7, + &s_THUSTR_8, + &s_THUSTR_9, + &s_THUSTR_10, + &s_THUSTR_11, + + &s_THUSTR_12, + &s_THUSTR_13, + &s_THUSTR_14, + &s_THUSTR_15, + &s_THUSTR_16, + &s_THUSTR_17, + &s_THUSTR_18, + &s_THUSTR_19, + &s_THUSTR_20, + + &s_THUSTR_21, + &s_THUSTR_22, + &s_THUSTR_23, + &s_THUSTR_24, + &s_THUSTR_25, + &s_THUSTR_26, + &s_THUSTR_27, + &s_THUSTR_28, + &s_THUSTR_29, + &s_THUSTR_30, + &s_THUSTR_31, + &s_THUSTR_32, +}; + +// Function prototypes +void lfstrip(char *); // strip the \r and/or \n off of a line +void rstrip(char *); // strip trailing whitespace +char * ptr_lstrip(char *); // point past leading whitespace +boolean deh_GetData(char *, char *, uint_64_t *, char **, FILE *); +boolean deh_procStringSub(char *, char *, char *, FILE *); +char * dehReformatStr(char *); + +// Prototypes for block processing functions +// Pointers to these functions are used as the blocks are encountered. + +static void deh_procThing(DEHFILE *fpin, FILE* fpout, char *line); +static void deh_procFrame(DEHFILE *, FILE*, char *); +static void deh_procPointer(DEHFILE *, FILE*, char *); +static void deh_procSounds(DEHFILE *, FILE*, char *); +static void deh_procAmmo(DEHFILE *, FILE*, char *); +static void deh_procWeapon(DEHFILE *, FILE*, char *); +static void deh_procSprite(DEHFILE *, FILE*, char *); +static void deh_procCheat(DEHFILE *, FILE*, char *); +static void deh_procMisc(DEHFILE *, FILE*, char *); +static void deh_procText(DEHFILE *, FILE*, char *); +static void deh_procPars(DEHFILE *, FILE*, char *); +static void deh_procStrings(DEHFILE *, FILE*, char *); +static void deh_procError(DEHFILE *, FILE*, char *); +static void deh_procBexCodePointers(DEHFILE *, FILE*, char *); +static void deh_procHelperThing(DEHFILE *, FILE *, char *); // haleyjd 9/22/99 +// haleyjd: handlers to fully deprecate the DeHackEd text section +static void deh_procBexSounds(DEHFILE *, FILE *, char *); +static void deh_procBexMusic(DEHFILE *, FILE *, char *); +static void deh_procBexSprites(DEHFILE *, FILE *, char *); + +// Structure deh_block is used to hold the block names that can +// be encountered, and the routines to use to decipher them + +typedef struct +{ + const char *key; // a mnemonic block code name // CPhipps - const* + void (*const fptr)(DEHFILE *, FILE*, char *); // handler +} deh_block; + +#define DEH_BUFFERMAX 1024 // input buffer area size, hardcodedfor now +// killough 8/9/98: make DEH_BLOCKMAX self-adjusting +#define DEH_BLOCKMAX (sizeof deh_blocks/sizeof*deh_blocks) // size of array +#define DEH_MAXKEYLEN 32 // as much of any key as we'll look at +#define DEH_MOBJINFOMAX 24 // number of ints in the mobjinfo_t structure (!) + +// Put all the block header values, and the function to be called when that +// one is encountered, in this array: +static const deh_block deh_blocks[] = { // CPhipps - static const + /* 0 */ {"Thing",deh_procThing}, + /* 1 */ {"Frame",deh_procFrame}, + /* 2 */ {"Pointer",deh_procPointer}, + /* 3 */ {"Sound",deh_procSounds}, // Ty 03/16/98 corrected from "Sounds" + /* 4 */ {"Ammo",deh_procAmmo}, + /* 5 */ {"Weapon",deh_procWeapon}, + /* 6 */ {"Sprite",deh_procSprite}, + /* 7 */ {"Cheat",deh_procCheat}, + /* 8 */ {"Misc",deh_procMisc}, + /* 9 */ {"Text",deh_procText}, // -- end of standard "deh" entries, + + // begin BOOM Extensions (BEX) + + /* 10 */ {"[STRINGS]",deh_procStrings}, // new string changes + /* 11 */ {"[PARS]",deh_procPars}, // alternative block marker + /* 12 */ {"[CODEPTR]",deh_procBexCodePointers}, // bex codepointers by mnemonic + /* 13 */ {"[HELPER]", deh_procHelperThing}, // helper thing substitution haleyjd 9/22/99 + /* 14 */ {"[SPRITES]", deh_procBexSprites}, // bex style sprites + /* 15 */ {"[SOUNDS]", deh_procBexSounds}, // bex style sounds + /* 16 */ {"[MUSIC]", deh_procBexMusic}, // bex style music + /* 17 */ {"", deh_procError} // dummy to handle anything else +}; + +// flag to skip included deh-style text, used with INCLUDE NOTEXT directive +static boolean includenotext = false; + +// MOBJINFO - Dehacked block name = "Thing" +// Usage: Thing nn (name) +// These are for mobjinfo_t types. Each is an integer +// within the structure, so we can use index of the string in this +// array to offset by sizeof(int) into the mobjinfo_t array at [nn] +// * things are base zero but dehacked considers them to start at #1. *** +// CPhipps - static const + +static const char *deh_mobjinfo[DEH_MOBJINFOMAX] = +{ + "ID #", // .doomednum + "Initial frame", // .spawnstate + "Hit points", // .spawnhealth + "First moving frame", // .seestate + "Alert sound", // .seesound + "Reaction time", // .reactiontime + "Attack sound", // .attacksound + "Injury frame", // .painstate + "Pain chance", // .painchance + "Pain sound", // .painsound + "Close attack frame", // .meleestate + "Far attack frame", // .missilestate + "Death frame", // .deathstate + "Exploding frame", // .xdeathstate + "Death sound", // .deathsound + "Speed", // .speed + "Width", // .radius + "Height", // .height + "Mass", // .mass + "Missile damage", // .damage + "Action sound", // .activesound + "Bits", // .flags + "Bits2", // .flags + "Respawn frame" // .raisestate +}; + +// Strings that are used to indicate flags ("Bits" in mobjinfo) +// This is an array of bit masks that are related to p_mobj.h +// values, using the smae names without the MF_ in front. +// Ty 08/27/98 new code +// +// killough 10/98: +// +// Convert array to struct to allow multiple values, make array size variable + +#define DEH_MOBJFLAGMAX (sizeof deh_mobjflags/sizeof*deh_mobjflags) + +struct deh_mobjflags_s { + const char *name; // CPhipps - const* + uint_64_t value; +}; + +// CPhipps - static const +static const struct deh_mobjflags_s deh_mobjflags[] = { + {"SPECIAL", MF_SPECIAL}, // call P_Specialthing when touched + {"SOLID", MF_SOLID}, // block movement + {"SHOOTABLE", MF_SHOOTABLE}, // can be hit + {"NOSECTOR", MF_NOSECTOR}, // invisible but touchable + {"NOBLOCKMAP", MF_NOBLOCKMAP}, // inert but displayable + {"AMBUSH", MF_AMBUSH}, // deaf monster + {"JUSTHIT", MF_JUSTHIT}, // will try to attack right back + {"JUSTATTACKED", MF_JUSTATTACKED}, // take at least 1 step before attacking + {"SPAWNCEILING", MF_SPAWNCEILING}, // initially hang from ceiling + {"NOGRAVITY", MF_NOGRAVITY}, // don't apply gravity during play + {"DROPOFF", MF_DROPOFF}, // can jump from high places + {"PICKUP", MF_PICKUP}, // will pick up items + {"NOCLIP", MF_NOCLIP}, // goes through walls + {"SLIDE", MF_SLIDE}, // keep info about sliding along walls + {"FLOAT", MF_FLOAT}, // allow movement to any height + {"TELEPORT", MF_TELEPORT}, // don't cross lines or look at heights + {"MISSILE", MF_MISSILE}, // don't hit same species, explode on block + {"DROPPED", MF_DROPPED}, // dropped, not spawned (like ammo clip) + {"SHADOW", MF_SHADOW}, // use fuzzy draw like spectres + {"NOBLOOD", MF_NOBLOOD}, // puffs instead of blood when shot + {"CORPSE", MF_CORPSE}, // so it will slide down steps when dead + {"INFLOAT", MF_INFLOAT}, // float but not to target height + {"COUNTKILL", MF_COUNTKILL}, // count toward the kills total + {"COUNTITEM", MF_COUNTITEM}, // count toward the items total + {"SKULLFLY", MF_SKULLFLY}, // special handling for flying skulls + {"NOTDMATCH", MF_NOTDMATCH}, // do not spawn in deathmatch + + // killough 10/98: TRANSLATION consists of 2 bits, not 1: + + {"TRANSLATION", MF_TRANSLATION1}, // for Boom bug-compatibility + {"TRANSLATION1", MF_TRANSLATION1}, // use translation table for color (players) + {"TRANSLATION2", MF_TRANSLATION2}, // use translation table for color (players) + {"UNUSED1", MF_TRANSLATION2}, // unused bit # 1 -- For Boom bug-compatibility + {"UNUSED2", MF_UNUSED2}, // unused bit # 2 -- For Boom compatibility + {"UNUSED3", MF_UNUSED3}, // unused bit # 3 -- For Boom compatibility + {"UNUSED4", MF_TRANSLUCENT}, // unused bit # 4 -- For Boom compatibility + {"TRANSLUCENT", MF_TRANSLUCENT}, // apply translucency to sprite (BOOM) + {"TOUCHY", MF_TOUCHY}, // dies on contact with solid objects (MBF) + {"BOUNCES", MF_BOUNCES}, // bounces off floors, ceilings and maybe walls (MBF) + {"FRIEND", MF_FRIEND}, // a friend of the player(s) (MBF) +}; + +// STATE - Dehacked block name = "Frame" and "Pointer" +// Usage: Frame nn +// Usage: Pointer nn (Frame nn) +// These are indexed separately, for lookup to the actual +// function pointers. Here we'll take whatever Dehacked gives +// us and go from there. The (Frame nn) after the pointer is the +// real place to put this value. The "Pointer" value is an xref +// that Dehacked uses and is useless to us. +// * states are base zero and have a dummy #0 (TROO) + +static const char *deh_state[] = // CPhipps - static const* +{ + "Sprite number", // .sprite (spritenum_t) // an enum + "Sprite subnumber", // .frame (long) + "Duration", // .tics (long) + "Next frame", // .nextstate (statenum_t) + // This is set in a separate "Pointer" block from Dehacked + "Codep Frame", // pointer to first use of action (actionf_t) + "Unknown 1", // .misc1 (long) + "Unknown 2" // .misc2 (long) +}; + +// SFXINFO_STRUCT - Dehacked block name = "Sounds" +// Sound effects, typically not changed (redirected, and new sfx put +// into the pwad, but not changed here. Can you tell that Gregdidn't +// know what they were for, mostly? Can you tell that I don't either? +// Mostly I just put these into the same slots as they are in the struct. +// This may not be supported in our -deh option if it doesn't make sense by then. + +// * sounds are base zero but have a dummy #0 + +static const char *deh_sfxinfo[] = // CPhipps - static const* +{ + "Offset", // pointer to a name string, changed in text + "Zero/One", // .singularity (int, one at a time flag) + "Value", // .priority + "Zero 1", // .link (sfxinfo_t*) referenced sound if linked + "Zero 2", // .pitch + "Zero 3", // .volume + "Zero 4", // .data (SAMPLE*) sound data + "Neg. One 1", // .usefulness + "Neg. One 2" // .lumpnum +}; + +// MUSICINFO is not supported in Dehacked. Ignored here. +// * music entries are base zero but have a dummy #0 + +// SPRITE - Dehacked block name = "Sprite" +// Usage = Sprite nn +// Sprite redirection by offset into the text area - unsupported by BOOM +// * sprites are base zero and dehacked uses it that way. + +// static const char *deh_sprite[] = // CPhipps - static const* +// { +// "Offset" // supposed to be the offset into the text section +// }; + +// AMMO - Dehacked block name = "Ammo" +// usage = Ammo n (name) +// Ammo information for the few types of ammo + +static const char *deh_ammo[] = // CPhipps - static const* +{ + "Max ammo", // maxammo[] + "Per ammo" // clipammo[] +}; + +// WEAPONS - Dehacked block name = "Weapon" +// Usage: Weapon nn (name) +// Basically a list of frames and what kind of ammo (see above)it uses. + +static const char *deh_weapon[] = // CPhipps - static const* +{ + "Ammo type", // .ammo + "Deselect frame", // .upstate + "Select frame", // .downstate + "Bobbing frame", // .readystate + "Shooting frame", // .atkstate + "Firing frame" // .flashstate +}; + +// CHEATS - Dehacked block name = "Cheat" +// Usage: Cheat 0 +// Always uses a zero in the dehacked file, for consistency. No meaning. +// These are just plain funky terms compared with id's +// +// killough 4/18/98: integrated into main cheat table now (see st_stuff.c) + +// MISC - Dehacked block name = "Misc" +// Usage: Misc 0 +// Always uses a zero in the dehacked file, for consistency. No meaning. + +static const char *deh_misc[] = // CPhipps - static const* +{ + "Initial Health", // initial_health + "Initial Bullets", // initial_bullets + "Max Health", // maxhealth + "Max Armor", // max_armor + "Green Armor Class", // green_armor_class + "Blue Armor Class", // blue_armor_class + "Max Soulsphere", // max_soul + "Soulsphere Health", // soul_health + "Megasphere Health", // mega_health + "God Mode Health", // god_health + "IDFA Armor", // idfa_armor + "IDFA Armor Class", // idfa_armor_class + "IDKFA Armor", // idkfa_armor + "IDKFA Armor Class", // idkfa_armor_class + "BFG Cells/Shot", // BFGCELLS + "Monsters Infight" // Unknown--not a specific number it seems, but + // the logic has to be here somewhere or + // it'd happen always +}; + +// TEXT - Dehacked block name = "Text" +// Usage: Text fromlen tolen +// Dehacked allows a bit of adjustment to the length (why?) + +// BEX extension [CODEPTR] +// Usage: Start block, then each line is: +// FRAME nnn = PointerMnemonic + +typedef struct { + actionf_t cptr; // actual pointer to the subroutine + const char *lookup; // mnemonic lookup string to be specified in BEX + // CPhipps - const* +} deh_bexptr; + +static const deh_bexptr deh_bexptrs[] = // CPhipps - static const +{ + {A_Light0, "A_Light0"}, + {A_WeaponReady, "A_WeaponReady"}, + {A_Lower, "A_Lower"}, + {A_Raise, "A_Raise"}, + {A_Punch, "A_Punch"}, + {A_ReFire, "A_ReFire"}, + {A_FirePistol, "A_FirePistol"}, + {A_Light1, "A_Light1"}, + {A_FireShotgun, "A_FireShotgun"}, + {A_Light2, "A_Light2"}, + {A_FireShotgun2, "A_FireShotgun2"}, + {A_CheckReload, "A_CheckReload"}, + {A_OpenShotgun2, "A_OpenShotgun2"}, + {A_LoadShotgun2, "A_LoadShotgun2"}, + {A_CloseShotgun2, "A_CloseShotgun2"}, + {A_FireCGun, "A_FireCGun"}, + {A_GunFlash, "A_GunFlash"}, + {A_FireMissile, "A_FireMissile"}, + {A_Saw, "A_Saw"}, + {A_FirePlasma, "A_FirePlasma"}, + {A_BFGsound, "A_BFGsound"}, + {A_FireBFG, "A_FireBFG"}, + {A_BFGSpray, "A_BFGSpray"}, + {A_Explode, "A_Explode"}, + {A_Pain, "A_Pain"}, + {A_PlayerScream, "A_PlayerScream"}, + {A_Fall, "A_Fall"}, + {A_XScream, "A_XScream"}, + {A_Look, "A_Look"}, + {A_Chase, "A_Chase"}, + {A_FaceTarget, "A_FaceTarget"}, + {A_PosAttack, "A_PosAttack"}, + {A_Scream, "A_Scream"}, + {A_SPosAttack, "A_SPosAttack"}, + {A_VileChase, "A_VileChase"}, + {A_VileStart, "A_VileStart"}, + {A_VileTarget, "A_VileTarget"}, + {A_VileAttack, "A_VileAttack"}, + {A_StartFire, "A_StartFire"}, + {A_Fire, "A_Fire"}, + {A_FireCrackle, "A_FireCrackle"}, + {A_Tracer, "A_Tracer"}, + {A_SkelWhoosh, "A_SkelWhoosh"}, + {A_SkelFist, "A_SkelFist"}, + {A_SkelMissile, "A_SkelMissile"}, + {A_FatRaise, "A_FatRaise"}, + {A_FatAttack1, "A_FatAttack1"}, + {A_FatAttack2, "A_FatAttack2"}, + {A_FatAttack3, "A_FatAttack3"}, + {A_BossDeath, "A_BossDeath"}, + {A_CPosAttack, "A_CPosAttack"}, + {A_CPosRefire, "A_CPosRefire"}, + {A_TroopAttack, "A_TroopAttack"}, + {A_SargAttack, "A_SargAttack"}, + {A_HeadAttack, "A_HeadAttack"}, + {A_BruisAttack, "A_BruisAttack"}, + {A_SkullAttack, "A_SkullAttack"}, + {A_Metal, "A_Metal"}, + {A_SpidRefire, "A_SpidRefire"}, + {A_BabyMetal, "A_BabyMetal"}, + {A_BspiAttack, "A_BspiAttack"}, + {A_Hoof, "A_Hoof"}, + {A_CyberAttack, "A_CyberAttack"}, + {A_PainAttack, "A_PainAttack"}, + {A_PainDie, "A_PainDie"}, + {A_KeenDie, "A_KeenDie"}, + {A_BrainPain, "A_BrainPain"}, + {A_BrainScream, "A_BrainScream"}, + {A_BrainDie, "A_BrainDie"}, + {A_BrainAwake, "A_BrainAwake"}, + {A_BrainSpit, "A_BrainSpit"}, + {A_SpawnSound, "A_SpawnSound"}, + {A_SpawnFly, "A_SpawnFly"}, + {A_BrainExplode, "A_BrainExplode"}, + {A_Detonate, "A_Detonate"}, // killough 8/9/98 + {A_Mushroom, "A_Mushroom"}, // killough 10/98 + {A_Die, "A_Die"}, // killough 11/98 + {A_Spawn, "A_Spawn"}, // killough 11/98 + {A_Turn, "A_Turn"}, // killough 11/98 + {A_Face, "A_Face"}, // killough 11/98 + {A_Scratch, "A_Scratch"}, // killough 11/98 + {A_PlaySound, "A_PlaySound"}, // killough 11/98 + {A_RandomJump, "A_RandomJump"}, // killough 11/98 + {A_LineEffect, "A_LineEffect"}, // killough 11/98 + + // This NULL entry must be the last in the list + {NULL, "A_NULL"}, // Ty 05/16/98 +}; + +// to hold startup code pointers from INFO.C +// CPhipps - static +static actionf_t deh_codeptr[NUMSTATES]; + +// haleyjd: support for BEX SPRITES, SOUNDS, and MUSIC +char *deh_spritenames[NUMSPRITES + 1]; +char *deh_musicnames[NUMMUSIC + 1]; +char *deh_soundnames[NUMSFX + 1]; + +void D_BuildBEXTables(void) +{ + int i; + + // moved from ProcessDehFile, then we don't need the static int i + for (i = 0; i < NUMSTATES; i++) // remember what they start as for deh xref + deh_codeptr[i] = states[i].action; + + for(i = 0; i < NUMSPRITES; i++) + deh_spritenames[i] = strdup(sprnames[i]); + deh_spritenames[NUMSPRITES] = NULL; + + for(i = 1; i < NUMMUSIC; i++) + deh_musicnames[i] = strdup(S_music[i].name); + deh_musicnames[0] = deh_musicnames[NUMMUSIC] = NULL; + + for(i = 1; i < NUMSFX; i++) + deh_soundnames[i] = strdup(S_sfx[i].name); + deh_soundnames[0] = deh_soundnames[NUMSFX] = NULL; +} + +// ==================================================================== +// ProcessDehFile +// Purpose: Read and process a DEH or BEX file +// Args: filename -- name of the DEH/BEX file +// outfilename -- output file (DEHOUT.TXT), appended to here +// Returns: void +// +// killough 10/98: +// substantially modified to allow input from wad lumps instead of .deh files. + +void ProcessDehFile(const char *filename, const char *outfilename, int lumpnum) +{ + static FILE *fileout; // In case -dehout was used + DEHFILE infile, *filein = &infile; // killough 10/98 + char inbuffer[DEH_BUFFERMAX]; // Place to put the primary infostring + + // Open output file if we're writing output + if (outfilename && *outfilename && !fileout) + { + static boolean firstfile = true; // to allow append to output log + if (!strcmp(outfilename, "-")) + fileout = stdout; + else + if (!(fileout=fopen(outfilename, firstfile ? "wt" : "at"))) + { + lprintf(LO_WARN, "Could not open -dehout file %s\n... using stdout.\n", + outfilename); + fileout = stdout; + } + firstfile = false; + } + + // killough 10/98: allow DEH files to come from wad lumps + + if (filename) + { + if (!(infile.f = fopen(filename,"rt"))) + { + lprintf(LO_WARN, "-deh file %s not found\n",filename); + return; // should be checked up front anyway + } + infile.lump = NULL; + } + else // DEH file comes from lump indicated by third argument + { + infile.size = W_LumpLength(lumpnum); + infile.inp = infile.lump = W_CacheLumpNum(lumpnum); + filename = "(WAD)"; + } + + lprintf(LO_INFO, "Loading DEH file %s\n",filename); + if (fileout) fprintf(fileout,"\nLoading DEH file %s\n\n",filename); + + // move deh_codeptr initialisation to D_BuildBEXTables + + // loop until end of file + + while (dehfgets(inbuffer,sizeof(inbuffer),filein)) + { + unsigned i; + + lfstrip(inbuffer); + if (fileout) fprintf(fileout,"Line='%s'\n",inbuffer); + if (!*inbuffer || *inbuffer == '#' || *inbuffer == ' ') + continue; /* Blank line or comment line */ + + // -- If DEH_BLOCKMAX is set right, the processing is independently + // -- handled based on data in the deh_blocks[] structure array + + // killough 10/98: INCLUDE code rewritten to allow arbitrary nesting, + // and to greatly simplify code, fix memory leaks, other bugs + + if (!strnicmp(inbuffer,"INCLUDE",7)) // include a file + { + // preserve state while including a file + // killough 10/98: moved to here + + char *nextfile; + boolean oldnotext = includenotext; // killough 10/98 + + // killough 10/98: exclude if inside wads (only to discourage + // the practice, since the code could otherwise handle it) + + if (infile.lump) + { + if (fileout) + fprintf(fileout, + "No files may be included from wads: %s\n",inbuffer); + continue; + } + + // check for no-text directive, used when including a DEH + // file but using the BEX format to handle strings + + if (!strnicmp(nextfile = ptr_lstrip(inbuffer+7),"NOTEXT",6)) + includenotext = true, nextfile = ptr_lstrip(nextfile+6); + + if (fileout) + fprintf(fileout,"Branching to include file %s...\n", nextfile); + + // killough 10/98: + // Second argument must be NULL to prevent closing fileout too soon + + ProcessDehFile(nextfile,NULL,0); // do the included file + + includenotext = oldnotext; + if (fileout) fprintf(fileout,"...continuing with %s\n",filename); + continue; + } + + for (i=0; i= NUMSTATES) + { + if (fpout) fprintf(fpout,"Bad pointer number %d of %d\n", + indexnum, NUMSTATES); + return; // killough 10/98: fix SegViol + } + strcpy(key,"A_"); // reusing the key area to prefix the mnemonic + strcat(key,ptr_lstrip(mnemonic)); + + found = FALSE; + i= -1; // incremented to start at zero at the top of the loop + do // Ty 05/16/98 - fix loop logic to look for null ending entry + { + ++i; + if (!stricmp(key,deh_bexptrs[i].lookup)) + { // Ty 06/01/98 - add to states[].action for new djgcc version + states[indexnum].action = deh_bexptrs[i].cptr; // assign + if (fpout) fprintf(fpout, + " - applied %s from codeptr[%d] to states[%d]\n", + deh_bexptrs[i].lookup,i,indexnum); + found = TRUE; + } + } while (!found && (deh_bexptrs[i].cptr != NULL)); + + if (!found) + if (fpout) fprintf(fpout, + "Invalid frame pointer mnemonic '%s' at %d\n", + mnemonic, indexnum); + } + return; +} + +//--------------------------------------------------------------------------- +// To be on the safe, compatible side, we manually convert DEH bitflags +// to prboom types - POPE +//--------------------------------------------------------------------------- +static uint_64_t getConvertedDEHBits(uint_64_t bits) { + static const uint_64_t bitMap[32] = { + /* cf linuxdoom-1.10 p_mobj.h */ + MF_SPECIAL, // 0 Can be picked up - When touched the thing can be picked up. + MF_SOLID, // 1 Obstacle - The thing is solid and will not let you (or others) pass through it + MF_SHOOTABLE, // 2 Shootable - Can be shot. + MF_NOSECTOR, // 3 Total Invisibility - Invisible, but can be touched + MF_NOBLOCKMAP, // 4 Don't use the blocklinks (inert but displayable) + MF_AMBUSH, // 5 Semi deaf - The thing is a deaf monster + MF_JUSTHIT, // 6 In pain - Will try to attack right back after being hit + MF_JUSTATTACKED, // 7 Steps before attack - Will take at least one step before attacking + MF_SPAWNCEILING, // 8 Hangs from ceiling - When the level starts, this thing will be at ceiling height. + MF_NOGRAVITY, // 9 No gravity - Gravity does not affect this thing + MF_DROPOFF, // 10 Travels over cliffs - Monsters normally do not walk off ledges/steps they could not walk up. With this set they can walk off any height of cliff. Usually only used for flying monsters. + MF_PICKUP, // 11 Pick up items - The thing can pick up gettable items. + MF_NOCLIP, // 12 No clipping - Thing can walk through walls. + MF_SLIDE, // 13 Slides along walls - Keep info about sliding along walls (don't really know much about this one). + MF_FLOAT, // 14 Floating - Thing can move to any height + MF_TELEPORT, // 15 Semi no clipping - Don't cross lines or look at teleport heights. (don't really know much about this one either). + MF_MISSILE, // 16 Projectiles - Behaves like a projectile, explodes when hitting something that blocks movement + MF_DROPPED, // 17 Disappearing weapon - Dropped, not spawned (like an ammo clip) I have not had much success in using this one. + MF_SHADOW, // 18 Partial invisibility - Drawn like a spectre. + MF_NOBLOOD, // 19 Puffs (vs. bleeds) - If hit will spawn bullet puffs instead of blood splats. + MF_CORPSE, // 20 Sliding helpless - Will slide down steps when dead. + MF_INFLOAT, // 21 No auto levelling - float but not to target height (?) + MF_COUNTKILL, // 22 Affects kill % - counted as a killable enemy and affects percentage kills on level summary. + MF_COUNTITEM, // 23 Affects item % - affects percentage items gathered on level summary. + MF_SKULLFLY, // 24 Running - special handling for flying skulls. + MF_NOTDMATCH, // 25 Not in deathmatch - do not spawn in deathmatch (like keys) + MF_TRANSLATION1, // 26 Color 1 (grey / red) + MF_TRANSLATION2, // 27 Color 2 (brown / red) + // Convert bit 28 to MF_TOUCHY, not (MF_TRANSLATION1|MF_TRANSLATION2) + // fixes bug #1576151 (part 1) + MF_TOUCHY, // 28 - explodes on contact (MBF) + MF_BOUNCES, // 29 - bounces off walls and floors (MBF) + MF_FRIEND, // 30 - friendly monster helps players (MBF) + MF_TRANSLUCENT // e6y: Translucency via dehacked/bex doesn't work without it + }; + int i; + uint_64_t shiftBits = bits; + uint_64_t convertedBits = 0; + for (i=0; i<32; i++) { + if (shiftBits & 0x1) convertedBits |= bitMap[i]; + shiftBits >>= 1; + } + return convertedBits; +} + +//--------------------------------------------------------------------------- +// See usage below for an explanation of this function's existence - POPE +//--------------------------------------------------------------------------- +static void setMobjInfoValue(int mobjInfoIndex, int keyIndex, uint_64_t value) { + mobjinfo_t *mi; + if (mobjInfoIndex >= NUMMOBJTYPES || mobjInfoIndex < 0) return; + mi = &mobjinfo[mobjInfoIndex]; + switch (keyIndex) { + case 0: mi->doomednum = (int)value; return; + case 1: mi->spawnstate = (int)value; return; + case 2: mi->spawnhealth = (int)value; return; + case 3: mi->seestate = (int)value; return; + case 4: mi->seesound = (int)value; return; + case 5: mi->reactiontime = (int)value; return; + case 6: mi->attacksound = (int)value; return; + case 7: mi->painstate = (int)value; return; + case 8: mi->painchance = (int)value; return; + case 9: mi->painsound = (int)value; return; + case 10: mi->meleestate = (int)value; return; + case 11: mi->missilestate = (int)value; return; + case 12: mi->deathstate = (int)value; return; + case 13: mi->xdeathstate = (int)value; return; + case 14: mi->deathsound = (int)value; return; + case 15: mi->speed = (int)value; return; + case 16: mi->radius = (int)value; return; + case 17: mi->height = (int)value; return; + case 18: mi->mass = (int)value; return; + case 19: mi->damage = (int)value; return; + case 20: mi->activesound = (int)value; return; + case 21: mi->flags = value; return; + case 22: return; // "Bits2", unused + case 23: mi->raisestate = (int)value; return; + default: return; + } +} + +// ==================================================================== +// deh_procThing +// Purpose: Handle DEH Thing block +// Args: fpin -- input file stream +// fpout -- output file stream (DEHOUT.TXT) +// line -- current line in file to process +// Returns: void +// +// Ty 8/27/98 - revised to also allow mnemonics for +// bit masks for monster attributes +// + +static void deh_procThing(DEHFILE *fpin, FILE* fpout, char *line) +{ + char key[DEH_MAXKEYLEN]; + char inbuffer[DEH_BUFFERMAX]; + uint_64_t value; // All deh values are ints or longs + int indexnum; + int ix; + char *strval; + + strncpy(inbuffer,line,DEH_BUFFERMAX); + if (fpout) fprintf(fpout,"Thing line: '%s'\n",inbuffer); + + // killough 8/98: allow hex numbers in input: + ix = sscanf(inbuffer,"%s %i",key, &indexnum); + if (fpout) fprintf(fpout,"count=%d, Thing %d\n",ix, indexnum); + + // Note that the mobjinfo[] array is base zero, but object numbers + // in the dehacked file start with one. Grumble. + --indexnum; + + // now process the stuff + // Note that for Things we can look up the key and use its offset + // in the array of key strings as an int offset in the structure + + // get a line until a blank or end of file--it's not + // blank now because it has our incoming key in it + while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' ')) + { + // e6y: Correction of wrong processing of Bits parameter if its value is equal to zero + // No more desync on HACX demos. + int bGetData; + + if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break; + lfstrip(inbuffer); // toss the end of line + + // killough 11/98: really bail out on blank lines (break != continue) + if (!*inbuffer) break; // bail out with blank line between sections + + // e6y: Correction of wrong processing of Bits parameter if its value is equal to zero + // No more desync on HACX demos. + bGetData = deh_GetData(inbuffer,key,&value,&strval,fpout); + if (!bGetData) + // Old code: if (!deh_GetData(inbuffer,key,&value,&strval,fpout)) // returns TRUE if ok + { + if (fpout) fprintf(fpout,"Bad data pair in '%s'\n",inbuffer); + continue; + } + for (ix=0; ix>32) & 0xffffffff, + (unsigned long)deh_mobjflags[iy].value & 0xffffffff, strval + ); + } + value |= deh_mobjflags[iy].value; + break; + } + if (iy >= DEH_MOBJFLAGMAX && fpout) { + fprintf(fpout, "Could not find bit mnemonic %s\n", strval); + } + } + + // Don't worry about conversion -- simply print values + if (fpout) { + fprintf(fpout, + "Bits = 0x%08lX%08lX\n", + (unsigned long)(value>>32) & 0xffffffff, + (unsigned long)value & 0xffffffff + ); + } + mobjinfo[indexnum].flags = value; // e6y + } + } + if (fpout) { + fprintf(fpout, + "Assigned 0x%08lx%08lx to %s(%d) at index %d\n", + (unsigned long)(value>>32) & 0xffffffff, + (unsigned long)value & 0xffffffff, key, indexnum, ix + ); + } + } + } + return; +} + +// ==================================================================== +// deh_procFrame +// Purpose: Handle DEH Frame block +// Args: fpin -- input file stream +// fpout -- output file stream (DEHOUT.TXT) +// line -- current line in file to process +// Returns: void +// +static void deh_procFrame(DEHFILE *fpin, FILE* fpout, char *line) +{ + char key[DEH_MAXKEYLEN]; + char inbuffer[DEH_BUFFERMAX]; + uint_64_t value; // All deh values are ints or longs + int indexnum; + + strncpy(inbuffer,line,DEH_BUFFERMAX); + + // killough 8/98: allow hex numbers in input: + sscanf(inbuffer,"%s %i",key, &indexnum); + if (fpout) fprintf(fpout,"Processing Frame at index %d: %s\n",indexnum,key); + if (indexnum < 0 || indexnum >= NUMSTATES) + if (fpout) fprintf(fpout,"Bad frame number %d of %d\n",indexnum, NUMSTATES); + + while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' ')) + { + if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break; + lfstrip(inbuffer); + if (!*inbuffer) break; // killough 11/98 + if (!deh_GetData(inbuffer,key,&value,NULL,fpout)) // returns TRUE if ok + { + if (fpout) fprintf(fpout,"Bad data pair in '%s'\n",inbuffer); + continue; + } + if (!strcasecmp(key,deh_state[0])) // Sprite number + { + if (fpout) fprintf(fpout," - sprite = %lld\n",value); + states[indexnum].sprite = (spritenum_t)value; + } + else + if (!strcasecmp(key,deh_state[1])) // Sprite subnumber + { + if (fpout) fprintf(fpout," - frame = %lld\n",value); + states[indexnum].frame = (long)value; // long + } + else + if (!strcasecmp(key,deh_state[2])) // Duration + { + if (fpout) fprintf(fpout," - tics = %lld\n",value); + states[indexnum].tics = (long)value; // long + } + else + if (!strcasecmp(key,deh_state[3])) // Next frame + { + if (fpout) fprintf(fpout," - nextstate = %lld\n",value); + states[indexnum].nextstate = (statenum_t)value; + } + else + if (!strcasecmp(key,deh_state[4])) // Codep frame (not set in Frame deh block) + { + if (fpout) fprintf(fpout," - codep, should not be set in Frame section!\n"); + /* nop */ ; + } + else + if (!strcasecmp(key,deh_state[5])) // Unknown 1 + { + if (fpout) fprintf(fpout," - misc1 = %lld\n",value); + states[indexnum].misc1 = (long)value; // long + } + else + if (!strcasecmp(key,deh_state[6])) // Unknown 2 + { + if (fpout) fprintf(fpout," - misc2 = %lld\n",value); + states[indexnum].misc2 = (long)value; // long + } + else + if (fpout) fprintf(fpout,"Invalid frame string index for '%s'\n",key); + } + return; +} + +// ==================================================================== +// deh_procPointer +// Purpose: Handle DEH Code pointer block, can use BEX [CODEPTR] instead +// Args: fpin -- input file stream +// fpout -- output file stream (DEHOUT.TXT) +// line -- current line in file to process +// Returns: void +// +static void deh_procPointer(DEHFILE *fpin, FILE* fpout, char *line) // done +{ + char key[DEH_MAXKEYLEN]; + char inbuffer[DEH_BUFFERMAX]; + uint_64_t value; // All deh values are ints or longs + int indexnum; + int i; // looper + + strncpy(inbuffer,line,DEH_BUFFERMAX); + // NOTE: different format from normal + + // killough 8/98: allow hex numbers in input, fix error case: + if (sscanf(inbuffer,"%*s %*i (%s %i)",key, &indexnum) != 2) + { + if (fpout) fprintf(fpout,"Bad data pair in '%s'\n",inbuffer); + return; + } + + if (fpout) fprintf(fpout,"Processing Pointer at index %d: %s\n",indexnum, key); + if (indexnum < 0 || indexnum >= NUMSTATES) + { + if (fpout) + fprintf(fpout,"Bad pointer number %d of %d\n",indexnum, NUMSTATES); + return; + } + + while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' ')) + { + if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break; + lfstrip(inbuffer); + if (!*inbuffer) break; // killough 11/98 + if (!deh_GetData(inbuffer,key,&value,NULL,fpout)) // returns TRUE if ok + { + if (fpout) fprintf(fpout,"Bad data pair in '%s'\n",inbuffer); + continue; + } + + if (value >= NUMSTATES) + { + if (fpout) + fprintf(fpout,"Bad pointer number %lld of %d\n",value, NUMSTATES); + return; + } + + if (!strcasecmp(key,deh_state[4])) // Codep frame (not set in Frame deh block) + { + states[indexnum].action = deh_codeptr[value]; + if (fpout) fprintf(fpout," - applied from codeptr[%lld] to states[%d]\n", + value,indexnum); + // Write BEX-oriented line to match: + // for (i=0;i FRAME %d = %s\n", + indexnum, &deh_bexptrs[i].lookup[2]); + break; + } + if (deh_bexptrs[i].cptr == NULL) // stop at null entry + break; + } + } + else + if (fpout) fprintf(fpout,"Invalid frame pointer index for '%s' at %lld\n", + key, value); + } + return; +} + +// ==================================================================== +// deh_procSounds +// Purpose: Handle DEH Sounds block +// Args: fpin -- input file stream +// fpout -- output file stream (DEHOUT.TXT) +// line -- current line in file to process +// Returns: void +// +static void deh_procSounds(DEHFILE *fpin, FILE* fpout, char *line) +{ + assert( false || "Does the iOS version ever call this function? I hope not." ); + (void)deh_sfxinfo; +#if 0 + char key[DEH_MAXKEYLEN]; + char inbuffer[DEH_BUFFERMAX]; + uint_64_t value; // All deh values are ints or longs + int indexnum; + + strncpy(inbuffer,line,DEH_BUFFERMAX); + + // killough 8/98: allow hex numbers in input: + sscanf(inbuffer,"%s %i",key, &indexnum); + if (fpout) fprintf(fpout,"Processing Sounds at index %d: %s\n", + indexnum, key); + if (indexnum < 0 || indexnum >= NUMSFX) + if (fpout) fprintf(fpout,"Bad sound number %d of %d\n", + indexnum, NUMSFX); + + while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' ')) + { + if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break; + lfstrip(inbuffer); + if (!*inbuffer) break; // killough 11/98 + if (!deh_GetData(inbuffer,key,&value,NULL,fpout)) // returns TRUE if ok + { + if (fpout) fprintf(fpout,"Bad data pair in '%s'\n",inbuffer); + continue; + } + if (!strcasecmp(key,deh_sfxinfo[0])) // Offset + /* nop */ ; // we don't know what this is, I don't think + else + if (!strcasecmp(key,deh_sfxinfo[1])) // Zero/One + S_sfx[indexnum].singularity = (int)value; + else + if (!strcasecmp(key,deh_sfxinfo[2])) // Value + S_sfx[indexnum].priority = (int)value; + else + if (!strcasecmp(key,deh_sfxinfo[3])) // Zero 1 + S_sfx[indexnum].link = (sfxinfo_t *)value; + else + if (!strcasecmp(key,deh_sfxinfo[4])) // Zero 2 + S_sfx[indexnum].pitch = (int)value; + else + if (!strcasecmp(key,deh_sfxinfo[5])) // Zero 3 + S_sfx[indexnum].volume = (int)value; + else + if (!strcasecmp(key,deh_sfxinfo[6])) // Zero 4 + S_sfx[indexnum].data = (void *) value; // killough 5/3/98: changed cast + else + if (!strcasecmp(key,deh_sfxinfo[7])) // Neg. One 1 + S_sfx[indexnum].usefulness = (int)value; + else + if (!strcasecmp(key,deh_sfxinfo[8])) // Neg. One 2 + S_sfx[indexnum].lumpnum = (int)value; + else + if (fpout) fprintf(fpout, + "Invalid sound string index for '%s'\n",key); + } + return; +#endif +} + +// ==================================================================== +// deh_procAmmo +// Purpose: Handle DEH Ammo block +// Args: fpin -- input file stream +// fpout -- output file stream (DEHOUT.TXT) +// line -- current line in file to process +// Returns: void +// +static void deh_procAmmo(DEHFILE *fpin, FILE* fpout, char *line) +{ + char key[DEH_MAXKEYLEN]; + char inbuffer[DEH_BUFFERMAX]; + uint_64_t value; // All deh values are ints or longs + int indexnum; + + strncpy(inbuffer,line,DEH_BUFFERMAX); + + // killough 8/98: allow hex numbers in input: + sscanf(inbuffer,"%s %i",key, &indexnum); + if (fpout) fprintf(fpout,"Processing Ammo at index %d: %s\n", + indexnum, key); + if (indexnum < 0 || indexnum >= NUMAMMO) + if (fpout) fprintf(fpout,"Bad ammo number %d of %d\n", + indexnum,NUMAMMO); + + while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' ')) + { + if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break; + lfstrip(inbuffer); + if (!*inbuffer) break; // killough 11/98 + if (!deh_GetData(inbuffer,key,&value,NULL,fpout)) // returns TRUE if ok + { + if (fpout) fprintf(fpout,"Bad data pair in '%s'\n",inbuffer); + continue; + } + if (!strcasecmp(key,deh_ammo[0])) // Max ammo + maxammo[indexnum] = (int)value; + else + if (!strcasecmp(key,deh_ammo[1])) // Per ammo + clipammo[indexnum] = (int)value; + else + if (fpout) fprintf(fpout,"Invalid ammo string index for '%s'\n",key); + } + return; +} + +// ==================================================================== +// deh_procWeapon +// Purpose: Handle DEH Weapon block +// Args: fpin -- input file stream +// fpout -- output file stream (DEHOUT.TXT) +// line -- current line in file to process +// Returns: void +// +static void deh_procWeapon(DEHFILE *fpin, FILE* fpout, char *line) +{ + char key[DEH_MAXKEYLEN]; + char inbuffer[DEH_BUFFERMAX]; + uint_64_t value; // All deh values are ints or longs + int indexnum; + + strncpy(inbuffer,line,DEH_BUFFERMAX); + + // killough 8/98: allow hex numbers in input: + sscanf(inbuffer,"%s %i",key, &indexnum); + if (fpout) fprintf(fpout,"Processing Weapon at index %d: %s\n", + indexnum, key); + if (indexnum < 0 || indexnum >= NUMWEAPONS) + if (fpout) fprintf(fpout,"Bad weapon number %d of %d\n", + indexnum, NUMAMMO); + + while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' ')) + { + if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break; + lfstrip(inbuffer); + if (!*inbuffer) break; // killough 11/98 + if (!deh_GetData(inbuffer,key,&value,NULL,fpout)) // returns TRUE if ok + { + if (fpout) fprintf(fpout,"Bad data pair in '%s'\n",inbuffer); + continue; + } + if (!strcasecmp(key,deh_weapon[0])) // Ammo type + weaponinfo[indexnum].ammo = (ammotype_t)value; + else + if (!strcasecmp(key,deh_weapon[1])) // Deselect frame + weaponinfo[indexnum].upstate = (int)value; + else + if (!strcasecmp(key,deh_weapon[2])) // Select frame + weaponinfo[indexnum].downstate = (int)value; + else + if (!strcasecmp(key,deh_weapon[3])) // Bobbing frame + weaponinfo[indexnum].readystate = (int)value; + else + if (!strcasecmp(key,deh_weapon[4])) // Shooting frame + weaponinfo[indexnum].atkstate = (int)value; + else + if (!strcasecmp(key,deh_weapon[5])) // Firing frame + weaponinfo[indexnum].flashstate = (int)value; + else + if (fpout) fprintf(fpout,"Invalid weapon string index for '%s'\n",key); + } + return; +} + +// ==================================================================== +// deh_procSprite +// Purpose: Dummy - we do not support the DEH Sprite block +// Args: fpin -- input file stream +// fpout -- output file stream (DEHOUT.TXT) +// line -- current line in file to process +// Returns: void +// +static void deh_procSprite(DEHFILE *fpin, FILE* fpout, char *line) // Not supported +{ + char key[DEH_MAXKEYLEN]; + char inbuffer[DEH_BUFFERMAX]; + int indexnum; + + // Too little is known about what this is supposed to do, and + // there are better ways of handling sprite renaming. Not supported. + + strncpy(inbuffer,line,DEH_BUFFERMAX); + + // killough 8/98: allow hex numbers in input: + sscanf(inbuffer,"%s %i",key, &indexnum); + if (fpout) fprintf(fpout, + "Ignoring Sprite offset change at index %d: %s\n",indexnum, key); + while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' ')) + { + if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break; + lfstrip(inbuffer); + if (!*inbuffer) break; // killough 11/98 + // ignore line + if (fpout) fprintf(fpout,"- %s\n",inbuffer); + } + return; +} + +// ==================================================================== +// deh_procPars +// Purpose: Handle BEX extension for PAR times +// Args: fpin -- input file stream +// fpout -- output file stream (DEHOUT.TXT) +// line -- current line in file to process +// Returns: void +// +static void deh_procPars(DEHFILE *fpin, FILE* fpout, char *line) // extension +{ + char key[DEH_MAXKEYLEN]; + char inbuffer[DEH_BUFFERMAX]; + int indexnum; + int episode, level, partime, oldpar; + + // new item, par times + // usage: After [PARS] Par 0 section identifier, use one or more of these + // lines: + // par 3 5 120 + // par 14 230 + // The first would make the par for E3M5 be 120 seconds, and the + // second one makes the par for MAP14 be 230 seconds. The number + // of parameters on the line determines which group of par values + // is being changed. Error checking is done based on current fixed + // array sizes of[4][10] and [32] + + strncpy(inbuffer,line,DEH_BUFFERMAX); + + // killough 8/98: allow hex numbers in input: + sscanf(inbuffer,"%s %i",key, &indexnum); + if (fpout) fprintf(fpout, + "Processing Par value at index %d: %s\n",indexnum, key); + // indexnum is a dummy entry + while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' ')) + { + if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break; + lfstrip(strlwr(inbuffer)); // lowercase it + if (!*inbuffer) break; // killough 11/98 + if (3 != sscanf(inbuffer,"par %i %i %i",&episode, &level, &partime)) + { // not 3 + if (2 != sscanf(inbuffer,"par %i %i",&level, &partime)) + { // not 2 + if (fpout) fprintf(fpout,"Invalid par time setting string: %s\n",inbuffer); + } + else + { // is 2 + // Ty 07/11/98 - wrong range check, not zero-based + if (level < 1 || level > 32) // base 0 array (but 1-based parm) + { + if (fpout) fprintf(fpout,"Invalid MAPnn value MAP%d\n",level); + } + else + { + oldpar = cpars[level-1]; + if (fpout) fprintf(fpout,"Changed par time for MAP%02d from %d to %d\n",level,oldpar,partime); + cpars[level-1] = partime; + deh_pars = TRUE; + } + } + } + else + { // is 3 + // note that though it's a [4][10] array, the "left" and "top" aren't used, + // effectively making it a base 1 array. + // Ty 07/11/98 - level was being checked against max 3 - dumb error + // Note that episode 4 does not have par times per original design + // in Ultimate DOOM so that is not supported here. + if (episode < 1 || episode > 3 || level < 1 || level > 9) + { + if (fpout) fprintf(fpout, + "Invalid ExMx values E%dM%d\n",episode, level); + } + else + { + oldpar = pars[episode][level]; + pars[episode][level] = partime; + if (fpout) fprintf(fpout, + "Changed par time for E%dM%d from %d to %d\n", + episode,level,oldpar,partime); + deh_pars = TRUE; + } + } + } + return; +} + +// ==================================================================== +// deh_procCheat +// Purpose: Handle DEH Cheat block +// Args: fpin -- input file stream +// fpout -- output file stream (DEHOUT.TXT) +// line -- current line in file to process +// Returns: void +// +static void deh_procCheat(DEHFILE *fpin, FILE* fpout, char *line) // done +{ + char key[DEH_MAXKEYLEN]; + char inbuffer[DEH_BUFFERMAX]; + uint_64_t value; // All deh values are ints or longs + char ch = 0; // CPhipps - `writable' null string to initialise... + char *strval = &ch; // pointer to the value area + int ix, iy; // array indices + char *p; // utility pointer + + if (fpout) fprintf(fpout,"Processing Cheat: %s\n",line); + + strncpy(inbuffer,line,DEH_BUFFERMAX); + while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' ')) + { + if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break; + lfstrip(inbuffer); + if (!*inbuffer) break; // killough 11/98 + if (!deh_GetData(inbuffer,key,&value,&strval,fpout)) // returns TRUE if ok + { + if (fpout) fprintf(fpout,"Bad data pair in '%s'\n",inbuffer); + continue; + } + // Otherwise we got a (perhaps valid) cheat name, + // so look up the key in the array + + // killough 4/18/98: use main cheat code table in st_stuff.c now + for (ix=0; cheat[ix].cheat; ix++) + if (cheat[ix].deh_cheat) // killough 4/18/98: skip non-deh + { + if (!stricmp(key,cheat[ix].deh_cheat)) // found the cheat, ignored case + { + // replace it but don't overflow it. Use current length as limit. + // Ty 03/13/98 - add 0xff code + // Deal with the fact that the cheats in deh files are extended + // with character 0xFF to the original cheat length, which we don't do. + for (iy=0; strval[iy]; iy++) + strval[iy] = (strval[iy]==(char)0xff) ? '\0' : strval[iy]; + + iy = ix; // killough 4/18/98 + + // Ty 03/14/98 - skip leading spaces + p = strval; + while (*p == ' ') ++p; + // Ty 03/16/98 - change to use a strdup and orphan the original + // Also has the advantage of allowing length changes. + // strncpy(cheat[iy].cheat,p,strlen(cheat[iy].cheat)); +#if 0 + { // killough 9/12/98: disable cheats which are prefixes of this one + int i; + for (i=0; cheat[i].cheat; i++) + if (cheat[i].when & not_deh && + !strncasecmp(cheat[i].cheat, + cheat[iy].cheat, + strlen(cheat[i].cheat)) && i != iy) + cheat[i].deh_modified = true; + } +#endif + cheat[iy].cheat = strdup(p); + if (fpout) fprintf(fpout, + "Assigned new cheat '%s' to cheat '%s'at index %d\n", + p, cheat[ix].deh_cheat, iy); // killough 4/18/98 + } + } + if (fpout) fprintf(fpout,"- %s\n",inbuffer); + } + return; +} + +// ==================================================================== +// deh_procMisc +// Purpose: Handle DEH Misc block +// Args: fpin -- input file stream +// fpout -- output file stream (DEHOUT.TXT) +// line -- current line in file to process +// Returns: void +// +static void deh_procMisc(DEHFILE *fpin, FILE* fpout, char *line) // done +{ + char key[DEH_MAXKEYLEN]; + char inbuffer[DEH_BUFFERMAX]; + uint_64_t value; // All deh values are ints or longs + + strncpy(inbuffer,line,DEH_BUFFERMAX); + while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' ')) + { + if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break; + lfstrip(inbuffer); + if (!*inbuffer) break; // killough 11/98 + if (!deh_GetData(inbuffer,key,&value,NULL,fpout)) // returns TRUE if ok + { + if (fpout) fprintf(fpout,"Bad data pair in '%s'\n",inbuffer); + continue; + } + // Otherwise it's ok + if (fpout) fprintf(fpout,"Processing Misc item '%s'\n", key); + + if (!strcasecmp(key,deh_misc[0])) // Initial Health + initial_health = (int)value; + else + if (!strcasecmp(key,deh_misc[1])) // Initial Bullets + initial_bullets = (int)value; + else + if (!strcasecmp(key,deh_misc[2])) // Max Health + maxhealth = (int)value; + else + if (!strcasecmp(key,deh_misc[3])) // Max Armor + max_armor = (int)value; + else + if (!strcasecmp(key,deh_misc[4])) // Green Armor Class + green_armor_class = (int)value; + else + if (!strcasecmp(key,deh_misc[5])) // Blue Armor Class + blue_armor_class = (int)value; + else + if (!strcasecmp(key,deh_misc[6])) // Max Soulsphere + max_soul = (int)value; + else + if (!strcasecmp(key,deh_misc[7])) // Soulsphere Health + soul_health = (int)value; + else + if (!strcasecmp(key,deh_misc[8])) // Megasphere Health + mega_health = (int)value; + else + if (!strcasecmp(key,deh_misc[9])) // God Mode Health + god_health = (int)value; + else + if (!strcasecmp(key,deh_misc[10])) // IDFA Armor + idfa_armor = (int)value; + else + if (!strcasecmp(key,deh_misc[11])) // IDFA Armor Class + idfa_armor_class = (int)value; + else + if (!strcasecmp(key,deh_misc[12])) // IDKFA Armor + idkfa_armor = (int)value; + else + if (!strcasecmp(key,deh_misc[13])) // IDKFA Armor Class + idkfa_armor_class = (int)value; + else + if (!strcasecmp(key,deh_misc[14])) // BFG Cells/Shot + bfgcells = (int)value; + else + if (!strcasecmp(key,deh_misc[15])) { // Monsters Infight + // e6y: Dehacked support - monsters infight + if (value == 202) monsters_infight = 0; + else if (value == 221) monsters_infight = 1; + else if (fpout) fprintf(fpout, + "Invalid value for 'Monsters Infight': %i", (int)value); + + /* No such switch in DOOM - nop */ //e6y ; + } else + if (fpout) fprintf(fpout, + "Invalid misc item string index for '%s'\n",key); + } + return; +} + +// ==================================================================== +// deh_procText +// Purpose: Handle DEH Text block +// Notes: We look things up in the current information and if found +// we replace it. At the same time we write the new and +// improved BEX syntax to the log file for future use. +// Args: fpin -- input file stream +// fpout -- output file stream (DEHOUT.TXT) +// line -- current line in file to process +// Returns: void +// +static void deh_procText(DEHFILE *fpin, FILE* fpout, char *line) +{ + char key[DEH_MAXKEYLEN]; + char inbuffer[DEH_BUFFERMAX*2]; // can't use line -- double size buffer too. + int i; // loop variable + int fromlen, tolen; // as specified on the text block line + int usedlen; // shorter of fromlen and tolen if not matched + boolean found = FALSE; // to allow early exit once found + char* line2 = NULL; // duplicate line for rerouting + + // e6y + // Correction for DEHs which swap the values of two strings. For example: + // Text 4 4 Text 4 4; Text 6 6 Text 6 6 + // BOSSBOS2 BOS2BOSS; RUNNINSTALKS STALKSRUNNIN + // It corrects buggy behaviour on "All Hell is Breaking Loose" TC + // http://www.doomworld.com/idgames/index.php?id=6480 + static boolean sprnames_state[NUMSPRITES+1]; + static boolean S_sfx_state[NUMSFX]; + static boolean S_music_state[NUMMUSIC]; + + // Ty 04/11/98 - Included file may have NOTEXT skip flag set + if (includenotext) // flag to skip included deh-style text + { + if (fpout) fprintf(fpout, + "Skipped text block because of notext directive\n"); + strcpy(inbuffer,line); + while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' ')) + dehfgets(inbuffer, sizeof(inbuffer), fpin); // skip block + // Ty 05/17/98 - don't care if this fails + return; // ************** Early return + } + + // killough 8/98: allow hex numbers in input: + sscanf(line,"%s %i %i",key,&fromlen,&tolen); + if (fpout) fprintf(fpout, + "Processing Text (key=%s, from=%d, to=%d)\n", + key, fromlen, tolen); + + // killough 10/98: fix incorrect usage of feof + { + int c, totlen = 0; + while (totlen < fromlen + tolen && (c = dehfgetc(fpin)) != EOF) + if (c != '\r') + inbuffer[totlen++] = c; + inbuffer[totlen]='\0'; + } + + // if the from and to are 4, this may be a sprite rename. Check it + // against the array and process it as such if it matches. Remember + // that the original names are (and should remain) uppercase. + // Future: this will be from a separate [SPRITES] block. + if (fromlen==4 && tolen==4) + { + i=0; + while (sprnames[i]) // null terminated list in info.c //jff 3/19/98 + { //check pointer + if (!strnicmp(sprnames[i],inbuffer,fromlen) && !sprnames_state[i]) //not first char + { + if (fpout) fprintf(fpout, + "Changing name of sprite at index %d from %s to %*s\n", + i,sprnames[i],tolen,&inbuffer[fromlen]); + // Ty 03/18/98 - not using strdup because length is fixed + + // killough 10/98: but it's an array of pointers, so we must + // use strdup unless we redeclare sprnames and change all else + { + // CPhipps - fix constness problem + char *s; + sprnames[i] = s = strdup(sprnames[i]); + + //e6y: flag the sprite as changed + sprnames_state[i] = true; + + strncpy(s,&inbuffer[fromlen],tolen); + } + found = TRUE; + break; // only one will match--quit early + } + ++i; // next array element + } + } + else + if (fromlen < 7 && tolen < 7) // lengths of music and sfx are 6 or shorter + { + usedlen = (fromlen < tolen) ? fromlen : tolen; + if (fromlen != tolen) + if (fpout) fprintf(fpout, + "Warning: Mismatched lengths from=%d, to=%d, used %d\n", + fromlen, tolen, usedlen); + // Try sound effects entries - see sounds.c + for (i=1; i 12) ? "..." : "",fromlen,tolen); + if ((size_t)fromlen <= strlen(inbuffer)) + { + line2 = strdup(&inbuffer[fromlen]); + inbuffer[fromlen] = '\0'; + } + + deh_procStringSub(NULL, inbuffer, line2, fpout); + } + free(line2); // may be NULL, ignored by free() + return; +} + +static void deh_procError(DEHFILE *fpin, FILE* fpout, char *line) +{ + char inbuffer[DEH_BUFFERMAX]; + + strncpy(inbuffer,line,DEH_BUFFERMAX); + if (fpout) fprintf(fpout,"Unmatched Block: '%s'\n",inbuffer); + return; +} + +// ==================================================================== +// deh_procStrings +// Purpose: Handle BEX [STRINGS] extension +// Args: fpin -- input file stream +// fpout -- output file stream (DEHOUT.TXT) +// line -- current line in file to process +// Returns: void +// +static void deh_procStrings(DEHFILE *fpin, FILE* fpout, char *line) +{ + char key[DEH_MAXKEYLEN]; + char inbuffer[DEH_BUFFERMAX]; + uint_64_t value; // All deh values are ints or longs + char *strval; // holds the string value of the line + static int maxstrlen = 128; // maximum string length, bumped 128 at + // a time as needed + // holds the final result of the string after concatenation + static char *holdstring = NULL; + boolean found = false; // looking for string continuation + + if (fpout) fprintf(fpout,"Processing extended string substitution\n"); + + if (!holdstring) holdstring = malloc(maxstrlen*sizeof(*holdstring)); + + *holdstring = '\0'; // empty string to start with + strncpy(inbuffer,line,DEH_BUFFERMAX); + // Ty 04/24/98 - have to allow inbuffer to start with a blank for + // the continuations of C1TEXT etc. + while (!dehfeof(fpin) && *inbuffer) /* && (*inbuffer != ' ') */ + { + if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break; + if (*inbuffer == '#') continue; // skip comment lines + lfstrip(inbuffer); + if (!*inbuffer) break; // killough 11/98 + if (!*holdstring) // first one--get the key + { + if (!deh_GetData(inbuffer,key,&value,&strval,fpout)) // returns TRUE if ok + { + if (fpout) fprintf(fpout,"Bad data pair in '%s'\n",inbuffer); + continue; + } + } + while (strlen(holdstring) + strlen(inbuffer) > (size_t)maxstrlen) // Ty03/29/98 - fix stupid error + { + // killough 11/98: allocate enough the first time + maxstrlen += strlen(holdstring) + strlen(inbuffer) - maxstrlen; + if (fpout) fprintf(fpout, + "* increased buffer from to %d for buffer size %d\n", + maxstrlen,(int)strlen(inbuffer)); + holdstring = realloc(holdstring,maxstrlen*sizeof(*holdstring)); + } + // concatenate the whole buffer if continuation or the value iffirst + strcat(holdstring,ptr_lstrip(((*holdstring) ? inbuffer : strval))); + rstrip(holdstring); + // delete any trailing blanks past the backslash + // note that blanks before the backslash will be concatenated + // but ones at the beginning of the next line will not, allowing + // indentation in the file to read well without affecting the + // string itself. + if (holdstring[strlen(holdstring)-1] == '\\') + { + holdstring[strlen(holdstring)-1] = '\0'; + continue; // ready to concatenate + } + if (*holdstring) // didn't have a backslash, trap above would catch that + { + // go process the current string + found = deh_procStringSub(key, NULL, holdstring, fpout); // supply keyand not search string + + if (!found) + if (fpout) fprintf(fpout, + "Invalid string key '%s', substitution skipped.\n",key); + + *holdstring = '\0'; // empty string for the next one + } + } + return; +} + +// ==================================================================== +// deh_procStringSub +// Purpose: Common string parsing and handling routine for DEH and BEX +// Args: key -- place to put the mnemonic for the string if found +// lookfor -- original value string to look for +// newstring -- string to put in its place if found +// fpout -- file stream pointer for log file (DEHOUT.TXT) +// Returns: boolean: True if string found, false if not +// +boolean deh_procStringSub(char *key, char *lookfor, char *newstring, FILE *fpout) +{ + boolean found; // loop exit flag + int i; // looper + + found = false; + for (i=0;i '%s'\n",key,newstring); + + if (!key) + if (fpout) fprintf(fpout, + "Assigned '%.12s%s' to'%.12s%s' at key %s\n", + lookfor, (strlen(lookfor) > 12) ? "..." : "", + newstring, (strlen(newstring) > 12) ? "..." :"", + deh_strlookup[i].lookup); + + if (!key) // must have passed an old style string so showBEX + if (fpout) fprintf(fpout, + "*BEX FORMAT:\n%s = %s\n*END BEX\n", + deh_strlookup[i].lookup, + dehReformatStr(newstring)); + + break; + } + } + if (!found) + if (fpout) fprintf(fpout, + "Could not find '%.12s'\n",key ? key: lookfor); + + return found; +} + +//======================================================================== +// haleyjd 9/22/99 +// +// deh_procHelperThing +// +// Allows handy substitution of any thing for helper dogs. DEH patches +// are being made frequently for this purpose and it requires a complete +// rewiring of the DOG thing. I feel this is a waste of effort, and so +// have added this new [HELPER] BEX block + +static void deh_procHelperThing(DEHFILE *fpin, FILE *fpout, char *line) +{ + char key[DEH_MAXKEYLEN]; + char inbuffer[DEH_BUFFERMAX]; + uint_64_t value; // All deh values are ints or longs + + strncpy(inbuffer,line,DEH_BUFFERMAX); + while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' ')) + { + if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break; + lfstrip(inbuffer); + if (!*inbuffer) break; + if (!deh_GetData(inbuffer,key,&value,NULL,fpout)) // returns TRUE if ok + { + if (fpout) fprintf(fpout,"Bad data pair in '%s'\n",inbuffer); + continue; + } + // Otherwise it's ok + if (fpout) + { + fprintf(fpout,"Processing Helper Thing item '%s'\n", key); + fprintf(fpout,"value is %i", (int)value); + } + if (!strncasecmp(key, "type", 4)) + HelperThing = (int)value; + } + return; +} + +// +// deh_procBexSprites +// +// Supports sprite name substitutions without requiring use +// of the DeHackEd Text block +// +static void deh_procBexSprites(DEHFILE *fpin, FILE *fpout, char *line) +{ + char key[DEH_MAXKEYLEN]; + char inbuffer[DEH_BUFFERMAX]; + uint_64_t value; // All deh values are ints or longs + char *strval; // holds the string value of the line + char candidate[5]; + int rover; + + if(fpout) + fprintf(fpout,"Processing sprite name substitution\n"); + + strncpy(inbuffer,line,DEH_BUFFERMAX); + + while(!dehfeof(fpin) && *inbuffer && (*inbuffer != ' ')) + { + if(!dehfgets(inbuffer, sizeof(inbuffer), fpin)) + break; + if(*inbuffer == '#') + continue; // skip comment lines + lfstrip(inbuffer); + if(!*inbuffer) + break; // killough 11/98 + if(!deh_GetData(inbuffer,key,&value,&strval,fpout)) // returns TRUE if ok + { + if(fpout) + fprintf(fpout,"Bad data pair in '%s'\n",inbuffer); + continue; + } + // do it + memset(candidate, 0, sizeof(candidate)); + strncpy(candidate, ptr_lstrip(strval), 4); + if(strlen(candidate) != 4) + { + if(fpout) + fprintf(fpout, "Bad length for sprite name '%s'\n", + candidate); + continue; + } + + rover = 0; + while(deh_spritenames[rover]) + { + if(!strncasecmp(deh_spritenames[rover], key, 4)) + { + if(fpout) + fprintf(fpout, "Substituting '%s' for sprite '%s'\n", + candidate, deh_spritenames[rover]); + + sprnames[rover] = strdup(candidate); + break; + } + rover++; + } + } +} + +// ditto for sound names +static void deh_procBexSounds(DEHFILE *fpin, FILE *fpout, char *line) +{ + char key[DEH_MAXKEYLEN]; + char inbuffer[DEH_BUFFERMAX]; + uint_64_t value; // All deh values are ints or longs + char *strval; // holds the string value of the line + char candidate[7]; + int rover, len; + + if(fpout) + fprintf(fpout,"Processing sound name substitution\n"); + + strncpy(inbuffer,line,DEH_BUFFERMAX); + + while(!dehfeof(fpin) && *inbuffer && (*inbuffer != ' ')) + { + if(!dehfgets(inbuffer, sizeof(inbuffer), fpin)) + break; + if(*inbuffer == '#') + continue; // skip comment lines + lfstrip(inbuffer); + if(!*inbuffer) + break; // killough 11/98 + if(!deh_GetData(inbuffer,key,&value,&strval,fpout)) // returns TRUE if ok + { + if(fpout) + fprintf(fpout,"Bad data pair in '%s'\n",inbuffer); + continue; + } + // do it + memset(candidate, 0, 7); + strncpy(candidate, ptr_lstrip(strval), 6); + len = strlen(candidate); + if(len < 1 || len > 6) + { + if(fpout) + fprintf(fpout, "Bad length for sound name '%s'\n", + candidate); + continue; + } + + rover = 1; + while(deh_soundnames[rover]) + { + if(!strncasecmp(deh_soundnames[rover], key, 6)) + { + if(fpout) + fprintf(fpout, "Substituting '%s' for sound '%s'\n", + candidate, deh_soundnames[rover]); + + S_sfx[rover].name = strdup(candidate); + break; + } + rover++; + } + } +} + +// ditto for music names +static void deh_procBexMusic(DEHFILE *fpin, FILE *fpout, char *line) +{ + char key[DEH_MAXKEYLEN]; + char inbuffer[DEH_BUFFERMAX]; + uint_64_t value; // All deh values are ints or longs + char *strval; // holds the string value of the line + char candidate[7]; + int rover, len; + + if(fpout) + fprintf(fpout,"Processing music name substitution\n"); + + strncpy(inbuffer,line,DEH_BUFFERMAX); + + while(!dehfeof(fpin) && *inbuffer && (*inbuffer != ' ')) + { + if(!dehfgets(inbuffer, sizeof(inbuffer), fpin)) + break; + if(*inbuffer == '#') + continue; // skip comment lines + lfstrip(inbuffer); + if(!*inbuffer) + break; // killough 11/98 + if(!deh_GetData(inbuffer,key,&value,&strval,fpout)) // returns TRUE if ok + { + if(fpout) + fprintf(fpout,"Bad data pair in '%s'\n",inbuffer); + continue; + } + // do it + memset(candidate, 0, 7); + strncpy(candidate, ptr_lstrip(strval), 6); + len = strlen(candidate); + if(len < 1 || len > 6) + { + if(fpout) + fprintf(fpout, "Bad length for music name '%s'\n", + candidate); + continue; + } + + rover = 1; + while(deh_musicnames[rover]) + { + if(!strncasecmp(deh_musicnames[rover], key, 6)) + { + if(fpout) + fprintf(fpout, "Substituting '%s' for music '%s'\n", + candidate, deh_musicnames[rover]); + + S_music[rover].name = strdup(candidate); + break; + } + rover++; + } + } +} + +// ==================================================================== +// General utility function(s) +// ==================================================================== + +// ==================================================================== +// dehReformatStr +// Purpose: Convert a string into a continuous string with embedded +// linefeeds for "\n" sequences in the source string +// Args: string -- the string to convert +// Returns: the converted string (converted in a static buffer) +// +char *dehReformatStr(char *string) +{ + static char buff[DEH_BUFFERMAX]; // only processing the changed string, + // don't need double buffer + char *s, *t; + + s = string; // source + t = buff; // target + // let's play... + + while (*s) + { + if (*s == '\n') + ++s, *t++ = '\\', *t++ = 'n', *t++ = '\\', *t++='\n'; + else + *t++ = *s++; + } + *t = '\0'; + return buff; +} + +// ==================================================================== +// lfstrip +// Purpose: Strips CR/LF off the end of a string +// Args: s -- the string to work on +// Returns: void -- the string is modified in place +// +// killough 10/98: only strip at end of line, not entire string + +void lfstrip(char *s) // strip the \r and/or \n off of a line +{ + char *p = s+strlen(s); + while (p > s && (*--p=='\r' || *p=='\n')) + *p = 0; +} + +// ==================================================================== +// rstrip +// Purpose: Strips trailing blanks off a string +// Args: s -- the string to work on +// Returns: void -- the string is modified in place +// +void rstrip(char *s) // strip trailing whitespace +{ + char *p = s+strlen(s); // killough 4/4/98: same here + while (p > s && isspace(*--p)) // break on first non-whitespace + *p='\0'; +} + +// ==================================================================== +// ptr_lstrip +// Purpose: Points past leading whitespace in a string +// Args: s -- the string to work on +// Returns: char * pointing to the first nonblank character in the +// string. The original string is not changed. +// +char *ptr_lstrip(char *p) // point past leading whitespace +{ + while (isspace(*p)) + p++; + return p; +} + +// e6y: Correction of wrong processing of Bits parameter if its value is equal to zero +// No more desync on HACX demos. +// FIXME!!! (lame) +static boolean StrToInt(char *s, long *l) +{ + return ( + (sscanf(s, " 0x%lx", l) == 1) || + (sscanf(s, " 0X%lx", l) == 1) || + (sscanf(s, " 0%lo", l) == 1) || + (sscanf(s, " %ld", l) == 1) + ); +} + +// ==================================================================== +// deh_GetData +// Purpose: Get a key and data pair from a passed string +// Args: s -- the string to be examined +// k -- a place to put the key +// l -- pointer to a long integer to store the number +// strval -- a pointer to the place in s where the number +// value comes from. Pass NULL to not use this. +// fpout -- stream pointer to output log (DEHOUT.TXT) +// Notes: Expects a key phrase, optional space, equal sign, +// optional space and a value, mostly an int but treated +// as a long just in case. The passed pointer to hold +// the key must be DEH_MAXKEYLEN in size. + +boolean deh_GetData(char *s, char *k, uint_64_t *l, char **strval, FILE *fpout) +{ + char *t; // current char + long val; // to hold value of pair + char buffer[DEH_MAXKEYLEN]; // to hold key in progress + // e6y: Correction of wrong processing of Bits parameter if its value is equal to zero + // No more desync on HACX demos. + boolean okrc = 1; // assume good unless we have problems + int i; // iterator + + *buffer = '\0'; + val = 0; // defaults in case not otherwise set + for (i=0, t=s; *t && i < DEH_MAXKEYLEN; t++, i++) + { + if (*t == '=') break; + buffer[i] = *t; // copy it + } + buffer[--i] = '\0'; // terminate the key before the '=' + if (!*t) // end of string with no equal sign + { + okrc = FALSE; + } + else + { + if (!*++t) + { + val = 0; // in case "thiskey =" with no value + okrc = FALSE; + } + // we've incremented t + // e6y: Correction of wrong processing of Bits parameter if its value is equal to zero + // No more desync on HACX demos. + // Old code: e6y val = strtol(t,NULL,0); // killough 8/9/98: allow hex or octal input + if (!StrToInt(t,&val)) + { + val = 0; + okrc = 2; + } + } + + // go put the results in the passed pointers + *l = val; // may be a faked zero + + // if spaces between key and equal sign, strip them + strcpy(k,ptr_lstrip(buffer)); // could be a zero-length string + + if (strval != NULL) // pass NULL if you don't want this back + *strval = t; // pointer, has to be somewhere in s, + // even if pointing at the zero byte. + + return(okrc); +} diff --git a/common/prboom/d_deh.h b/common/prboom/d_deh.h new file mode 100755 index 0000000..02cdffa --- /dev/null +++ b/common/prboom/d_deh.h @@ -0,0 +1,1118 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2006 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Dehacked file support + * New for the TeamTNT "Boom" engine + * + * Author: Ty Halderman, TeamTNT + * + * Description: This file translates the #defined string constants + * to named variables to externalize them for deh/bex changes. + * Should be able to compile with D_FRENCH (for example) and still + * work (untested). + * + */ + +#ifndef __D_DEH__ +#define __D_DEH__ + +void ProcessDehFile(const char *filename, const char *outfilename, int lumpnum); + +// +// Ty 03/22/98 - note that we are keeping the english versions and +// comments in this file +// New string names all start with an extra s_ to avoid conflicts, +// but are otherwise identical to the original including uppercase. +// This is partly to keep the changes simple and partly for easier +// identification of the locations in which they're used. +// +// Printed strings for translation +// + +// +// D_Main.C +// +//#define D_DEVSTR "Development mode ON.\n" +extern const char *s_D_DEVSTR; // = D_DEVSTR; +//#define D_CDROM "CD-ROM Version: default.cfg from c:\\doomdata\n" +extern const char *s_D_CDROM; // = D_CDROM; + +// +// M_Menu.C +// +//#define PRESSKEY "press a key." +extern const char *s_PRESSKEY; // = PRESSKEY; +//#define PRESSYN "press y or n." +extern const char *s_PRESSYN; // = PRESSYN; +//#define QUITMSG "are you sure you want to\nquit this great game?" +extern const char *s_QUITMSG; // = QUITMSG; +//#define LOADNET "you can't do load while in a net game!\n\n"PRESSKEY +extern const char *s_LOADNET; // = LOADNET; +//#define QLOADNET "you can't quickload during a netgame!\n\n"PRESSKEY +extern const char *s_QLOADNET; // = QLOADNET; +//#define QSAVESPOT "you haven't picked a quicksave slot yet!\n\n"PRESSKEY +extern const char *s_QSAVESPOT; // = QSAVESPOT; +//#define SAVEDEAD "you can't save if you aren't playing!\n\n"PRESSKEY +extern const char *s_SAVEDEAD; // = SAVEDEAD; +//#define QSPROMPT "quicksave over your game named\n\n'%s'?\n\n"PRESSYN +extern const char *s_QSPROMPT; // = QSPROMPT; +//#define QLPROMPT "do you want to quickload the game named\n\n'%s'?\n\n"PRESSYN +extern const char *s_QLPROMPT; // = QLPROMPT; + +/* +#define NEWGAME \ +"you can't start a new game\n"\ +"while in a network game.\n\n"PRESSKEY +*/ +extern const char *s_NEWGAME; // = NEWGAME; + +// CPhipps - message given when asked if to restart the level +extern const char *s_RESTARTLEVEL; + +/* +#define NIGHTMARE \ +"are you sure? this skill level\n"\ +"isn't even remotely fair.\n\n"PRESSYN +*/ +extern const char *s_NIGHTMARE; // = NIGHTMARE; + +/* +#define SWSTRING \ +"this is the shareware version of doom.\n\n"\ +"you need to order the entire trilogy.\n\n"PRESSKEY +*/ +extern const char *s_SWSTRING; // = SWSTRING; + +//#define MSGOFF "Messages OFF" +extern const char *s_MSGOFF; // = MSGOFF; +//#define MSGON "Messages ON" +extern const char *s_MSGON; // = MSGON; +//#define NETEND "you can't end a netgame!\n\n"PRESSKEY +extern const char *s_NETEND; // = NETEND; +//#define ENDGAME "are you sure you want to end the game?\n\n"PRESSYN +extern const char *s_ENDGAME; // = ENDGAME; + +//#define DOSY "(press y to quit)" +extern const char *s_DOSY; // = DOSY; + +//#define DETAILHI "High detail" +extern const char *s_DETAILHI; // = DETAILHI; +//#define DETAILLO "Low detail" +extern const char *s_DETAILLO; // = DETAILLO; +//#define GAMMALVL0 "Gamma correction OFF" +extern const char *s_GAMMALVL0; // = GAMMALVL0; +//#define GAMMALVL1 "Gamma correction level 1" +extern const char *s_GAMMALVL1; // = GAMMALVL1; +//#define GAMMALVL2 "Gamma correction level 2" +extern const char *s_GAMMALVL2; // = GAMMALVL2; +//#define GAMMALVL3 "Gamma correction level 3" +extern const char *s_GAMMALVL3; // = GAMMALVL3; +//#define GAMMALVL4 "Gamma correction level 4" +extern const char *s_GAMMALVL4; // = GAMMALVL4; +//#define EMPTYSTRING "empty slot" +extern const char *s_EMPTYSTRING; // = EMPTYSTRING; + +// +// P_inter.C +// +//#define GOTARMOR "Picked up the armor." +extern const char *s_GOTARMOR; // = GOTARMOR; +//#define GOTMEGA "Picked up the MegaArmor!" +extern const char *s_GOTMEGA; // = GOTMEGA; +//#define GOTHTHBONUS "Picked up a health bonus." +extern const char *s_GOTHTHBONUS; // = GOTHTHBONUS; +//#define GOTARMBONUS "Picked up an armor bonus." +extern const char *s_GOTARMBONUS; // = GOTARMBONUS; +//#define GOTSTIM "Picked up a stimpack." +extern const char *s_GOTSTIM; // = GOTSTIM; +//#define GOTMEDINEED "Picked up a medikit that you REALLY need!" +extern const char *s_GOTMEDINEED; // = GOTMEDINEED; +//#define GOTMEDIKIT "Picked up a medikit." +extern const char *s_GOTMEDIKIT; // = GOTMEDIKIT; +//#define GOTSUPER "Supercharge!" +extern const char *s_GOTSUPER; // = GOTSUPER; + +//#define GOTBLUECARD "Picked up a blue keycard." +extern const char *s_GOTBLUECARD; // = GOTBLUECARD; +//#define GOTYELWCARD "Picked up a yellow keycard." +extern const char *s_GOTYELWCARD; // = GOTYELWCARD; +//#define GOTREDCARD "Picked up a red keycard." +extern const char *s_GOTREDCARD; // = GOTREDCARD; +//#define GOTBLUESKUL "Picked up a blue skull key." +extern const char *s_GOTBLUESKUL; // = GOTBLUESKUL; +//#define GOTYELWSKUL "Picked up a yellow skull key." +extern const char *s_GOTYELWSKUL; // = GOTYELWSKUL; +//#define GOTREDSKULL "Picked up a red skull key." +extern const char *s_GOTREDSKULL; // = GOTREDSKULL; + +//#define GOTINVUL "Invulnerability!" +extern const char *s_GOTINVUL; // = GOTINVUL; +//#define GOTBERSERK "Berserk!" +extern const char *s_GOTBERSERK; // = GOTBERSERK; +//#define GOTINVIS "Partial Invisibility" +extern const char *s_GOTINVIS; // = GOTINVIS; +//#define GOTSUIT "Radiation Shielding Suit" +extern const char *s_GOTSUIT; // = GOTSUIT; +//#define GOTMAP "Computer Area Map" +extern const char *s_GOTMAP; // = GOTMAP; +//#define GOTVISOR "Light Amplification Visor" +extern const char *s_GOTVISOR; // = GOTVISOR; +//#define GOTMSPHERE "MegaSphere!" +extern const char *s_GOTMSPHERE; // = GOTMSPHERE; + +//#define GOTCLIP "Picked up a clip." +extern const char *s_GOTCLIP; // = GOTCLIP; +//#define GOTCLIPBOX "Picked up a box of bullets." +extern const char *s_GOTCLIPBOX; // = GOTCLIPBOX; +//#define GOTROCKET "Picked up a rocket." +extern const char *s_GOTROCKET; // = GOTROCKET; +//#define GOTROCKBOX "Picked up a box of rockets." +extern const char *s_GOTROCKBOX; // = GOTROCKBOX; +//#define GOTCELL "Picked up an energy cell." +extern const char *s_GOTCELL; // = GOTCELL; +//#define GOTCELLBOX "Picked up an energy cell pack." +extern const char *s_GOTCELLBOX; // = GOTCELLBOX; +//#define GOTSHELLS "Picked up 4 shotgun shells." +extern const char *s_GOTSHELLS; // = GOTSHELLS; +//#define GOTSHELLBOX "Picked up a box of shotgun shells." +extern const char *s_GOTSHELLBOX; // = GOTSHELLBOX; +//#define GOTBACKPACK "Picked up a backpack full of ammo!" +extern const char *s_GOTBACKPACK; // = GOTBACKPACK; + +//#define GOTBFG9000 "You got the BFG9000! Oh, yes." +extern const char *s_GOTBFG9000; // = GOTBFG9000; +//#define GOTCHAINGUN "You got the chaingun!" +extern const char *s_GOTCHAINGUN; // = GOTCHAINGUN; +//#define GOTCHAINSAW "A chainsaw! Find some meat!" +extern const char *s_GOTCHAINSAW; // = GOTCHAINSAW; +//#define GOTLAUNCHER "You got the rocket launcher!" +extern const char *s_GOTLAUNCHER; // = GOTLAUNCHER; +//#define GOTPLASMA "You got the plasma gun!" +extern const char *s_GOTPLASMA; // = GOTPLASMA; +//#define GOTSHOTGUN "You got the shotgun!" +extern const char *s_GOTSHOTGUN; // = GOTSHOTGUN; +//#define GOTSHOTGUN2 "You got the super shotgun!" +extern const char *s_GOTSHOTGUN2; // = GOTSHOTGUN2; + +// +// P_Doors.C +// +//#define PD_BLUEO "You need a blue key to activate this object" +extern const char *s_PD_BLUEO; // = PD_BLUEO; +//#define PD_REDO "You need a red key to activate this object" +extern const char *s_PD_REDO; // = PD_REDO; +//#define PD_YELLOWO "You need a yellow key to activate this object" +extern const char *s_PD_YELLOWO; // = PD_YELLOWO; +//#define PD_BLUEK "You need a blue key to open this door" +extern const char *s_PD_BLUEK; // = PD_BLUEK; +//#define PD_REDK "You need a red key to open this door" +extern const char *s_PD_REDK; // = PD_REDK; +//#define PD_YELLOWK "You need a yellow key to open this door" +extern const char *s_PD_YELLOWK; // = PD_YELLOWK; +//jff 02/05/98 Create messages specific to card and skull keys +//#define PD_BLUEC "You need a blue card to open this door" +extern const char *s_PD_BLUEC; // = PD_BLUEC; +//#define PD_REDC "You need a red card to open this door" +extern const char *s_PD_REDC; // = PD_REDC; +//#define PD_YELLOWC "You need a yellow card to open this door" +extern const char *s_PD_YELLOWC; // = PD_YELLOWC; +//#define PD_BLUES "You need a blue skull to open this door" +extern const char *s_PD_BLUES; // = PD_BLUES; +//#define PD_REDS "You need a red skull to open this door" +extern const char *s_PD_REDS; // = PD_REDS; +//#define PD_YELLOWS "You need a yellow skull to open this door" +extern const char *s_PD_YELLOWS; // = PD_YELLOWS; +//#define PD_ANY "Any key will open this door" +extern const char *s_PD_ANY; // = PD_ANY; +//#define PD_ALL3 "You need all three keys to open this door" +extern const char *s_PD_ALL3; // = PD_ALL3; +//#define PD_ALL6 "You need all six keys to open this door" +extern const char *s_PD_ALL6; // = PD_ALL6; + +// +// G_game.C +// +//#define GGSAVED "game saved." +extern const char *s_GGSAVED; // = GGSAVED; + +// +// HU_stuff.C +// +//#define HUSTR_MSGU "[Message unsent]" +extern const char *s_HUSTR_MSGU; // = HUSTR_MSGU; + +//#define HUSTR_E1M1 "E1M1: Hangar" +extern const char *s_HUSTR_E1M1; // = HUSTR_E1M1; +//#define HUSTR_E1M2 "E1M2: Nuclear Plant" +extern const char *s_HUSTR_E1M2; // = HUSTR_E1M2; +//#define HUSTR_E1M3 "E1M3: Toxin Refinery" +extern const char *s_HUSTR_E1M3; // = HUSTR_E1M3; +//#define HUSTR_E1M4 "E1M4: Command Control" +extern const char *s_HUSTR_E1M4; // = HUSTR_E1M4; +//#define HUSTR_E1M5 "E1M5: Phobos Lab" +extern const char *s_HUSTR_E1M5; // = HUSTR_E1M5; +//#define HUSTR_E1M6 "E1M6: Central Processing" +extern const char *s_HUSTR_E1M6; // = HUSTR_E1M6; +//#define HUSTR_E1M7 "E1M7: Computer Station" +extern const char *s_HUSTR_E1M7; // = HUSTR_E1M7; +//#define HUSTR_E1M8 "E1M8: Phobos Anomaly" +extern const char *s_HUSTR_E1M8; // = HUSTR_E1M8; +//#define HUSTR_E1M9 "E1M9: Military Base" +extern const char *s_HUSTR_E1M9; // = HUSTR_E1M9; + +//#define HUSTR_E2M1 "E2M1: Deimos Anomaly" +extern const char *s_HUSTR_E2M1; // = HUSTR_E2M1; +//#define HUSTR_E2M2 "E2M2: Containment Area" +extern const char *s_HUSTR_E2M2; // = HUSTR_E2M2; +//#define HUSTR_E2M3 "E2M3: Refinery" +extern const char *s_HUSTR_E2M3; // = HUSTR_E2M3; +//#define HUSTR_E2M4 "E2M4: Deimos Lab" +extern const char *s_HUSTR_E2M4; // = HUSTR_E2M4; +//#define HUSTR_E2M5 "E2M5: Command Center" +extern const char *s_HUSTR_E2M5; // = HUSTR_E2M5; +//#define HUSTR_E2M6 "E2M6: Halls of the Damned" +extern const char *s_HUSTR_E2M6; // = HUSTR_E2M6; +//#define HUSTR_E2M7 "E2M7: Spawning Vats" +extern const char *s_HUSTR_E2M7; // = HUSTR_E2M7; +//#define HUSTR_E2M8 "E2M8: Tower of Babel" +extern const char *s_HUSTR_E2M8; // = HUSTR_E2M8; +//#define HUSTR_E2M9 "E2M9: Fortress of Mystery" +extern const char *s_HUSTR_E2M9; // = HUSTR_E2M9; + +//#define HUSTR_E3M1 "E3M1: Hell Keep" +extern const char *s_HUSTR_E3M1; // = HUSTR_E3M1; +//#define HUSTR_E3M2 "E3M2: Slough of Despair" +extern const char *s_HUSTR_E3M2; // = HUSTR_E3M2; +//#define HUSTR_E3M3 "E3M3: Pandemonium" +extern const char *s_HUSTR_E3M3; // = HUSTR_E3M3; +//#define HUSTR_E3M4 "E3M4: House of Pain" +extern const char *s_HUSTR_E3M4; // = HUSTR_E3M4; +//#define HUSTR_E3M5 "E3M5: Unholy Cathedral" +extern const char *s_HUSTR_E3M5; // = HUSTR_E3M5; +//#define HUSTR_E3M6 "E3M6: Mt. Erebus" +extern const char *s_HUSTR_E3M6; // = HUSTR_E3M6; +//#define HUSTR_E3M7 "E3M7: Limbo" +extern const char *s_HUSTR_E3M7; // = HUSTR_E3M7; +//#define HUSTR_E3M8 "E3M8: Dis" +extern const char *s_HUSTR_E3M8; // = HUSTR_E3M8; +//#define HUSTR_E3M9 "E3M9: Warrens" +extern const char *s_HUSTR_E3M9; // = HUSTR_E3M9; + +//#define HUSTR_E4M1 "E4M1: Hell Beneath" +extern const char *s_HUSTR_E4M1; // = HUSTR_E4M1; +//#define HUSTR_E4M2 "E4M2: Perfect Hatred" +extern const char *s_HUSTR_E4M2; // = HUSTR_E4M2; +//#define HUSTR_E4M3 "E4M3: Sever The Wicked" +extern const char *s_HUSTR_E4M3; // = HUSTR_E4M3; +//#define HUSTR_E4M4 "E4M4: Unruly Evil" +extern const char *s_HUSTR_E4M4; // = HUSTR_E4M4; +//#define HUSTR_E4M5 "E4M5: They Will Repent" +extern const char *s_HUSTR_E4M5; // = HUSTR_E4M5; +//#define HUSTR_E4M6 "E4M6: Against Thee Wickedly" +extern const char *s_HUSTR_E4M6; // = HUSTR_E4M6; +//#define HUSTR_E4M7 "E4M7: And Hell Followed" +extern const char *s_HUSTR_E4M7; // = HUSTR_E4M7; +//#define HUSTR_E4M8 "E4M8: Unto The Cruel" +extern const char *s_HUSTR_E4M8; // = HUSTR_E4M8; +//#define HUSTR_E4M9 "E4M9: Fear" +extern const char *s_HUSTR_E4M9; // = HUSTR_E4M9; + +//#define HUSTR_1 "level 1: entryway" +extern const char *s_HUSTR_1; // = HUSTR_1; +//#define HUSTR_2 "level 2: underhalls" +extern const char *s_HUSTR_2; // = HUSTR_2; +//#define HUSTR_3 "level 3: the gantlet" +extern const char *s_HUSTR_3; // = HUSTR_3; +//#define HUSTR_4 "level 4: the focus" +extern const char *s_HUSTR_4; // = HUSTR_4; +//#define HUSTR_5 "level 5: the waste tunnels" +extern const char *s_HUSTR_5; // = HUSTR_5; +//#define HUSTR_6 "level 6: the crusher" +extern const char *s_HUSTR_6; // = HUSTR_6; +//#define HUSTR_7 "level 7: dead simple" +extern const char *s_HUSTR_7; // = HUSTR_7; +//#define HUSTR_8 "level 8: tricks and traps" +extern const char *s_HUSTR_8; // = HUSTR_8; +//#define HUSTR_9 "level 9: the pit" +extern const char *s_HUSTR_9; // = HUSTR_9; +//#define HUSTR_10 "level 10: refueling base" +extern const char *s_HUSTR_10; // = HUSTR_10; +//#define HUSTR_11 "level 11: 'o' of destruction!" +extern const char *s_HUSTR_11; // = HUSTR_11; + +//#define HUSTR_12 "level 12: the factory" +extern const char *s_HUSTR_12; // = HUSTR_12; +//#define HUSTR_13 "level 13: downtown" +extern const char *s_HUSTR_13; // = HUSTR_13; +//#define HUSTR_14 "level 14: the inmost dens" +extern const char *s_HUSTR_14; // = HUSTR_14; +//#define HUSTR_15 "level 15: industrial zone" +extern const char *s_HUSTR_15; // = HUSTR_15; +//#define HUSTR_16 "level 16: suburbs" +extern const char *s_HUSTR_16; // = HUSTR_16; +//#define HUSTR_17 "level 17: tenements" +extern const char *s_HUSTR_17; // = HUSTR_17; +//#define HUSTR_18 "level 18: the courtyard" +extern const char *s_HUSTR_18; // = HUSTR_18; +//#define HUSTR_19 "level 19: the citadel" +extern const char *s_HUSTR_19; // = HUSTR_19; +//#define HUSTR_20 "level 20: gotcha!" +extern const char *s_HUSTR_20; // = HUSTR_20; + +//#define HUSTR_21 "level 21: nirvana" +extern const char *s_HUSTR_21; // = HUSTR_21; +//#define HUSTR_22 "level 22: the catacombs" +extern const char *s_HUSTR_22; // = HUSTR_22; +//#define HUSTR_23 "level 23: barrels o' fun" +extern const char *s_HUSTR_23; // = HUSTR_23; +//#define HUSTR_24 "level 24: the chasm" +extern const char *s_HUSTR_24; // = HUSTR_24; +//#define HUSTR_25 "level 25: bloodfalls" +extern const char *s_HUSTR_25; // = HUSTR_25; +//#define HUSTR_26 "level 26: the abandoned mines" +extern const char *s_HUSTR_26; // = HUSTR_26; +//#define HUSTR_27 "level 27: monster condo" +extern const char *s_HUSTR_27; // = HUSTR_27; +//#define HUSTR_28 "level 28: the spirit world" +extern const char *s_HUSTR_28; // = HUSTR_28; +//#define HUSTR_29 "level 29: the living end" +extern const char *s_HUSTR_29; // = HUSTR_29; +//#define HUSTR_30 "level 30: icon of sin" +extern const char *s_HUSTR_30; // = HUSTR_30; + +//#define HUSTR_31 "level 31: wolfenstein" +extern const char *s_HUSTR_31; // = HUSTR_31; +//#define HUSTR_32 "level 32: grosse" +extern const char *s_HUSTR_32; // = HUSTR_32; + +//#define PHUSTR_1 "level 1: congo" +extern const char *s_PHUSTR_1; // = PHUSTR_1; +//#define PHUSTR_2 "level 2: well of souls" +extern const char *s_PHUSTR_2; // = PHUSTR_2; +//#define PHUSTR_3 "level 3: aztec" +extern const char *s_PHUSTR_3; // = PHUSTR_3; +//#define PHUSTR_4 "level 4: caged" +extern const char *s_PHUSTR_4; // = PHUSTR_4; +//#define PHUSTR_5 "level 5: ghost town" +extern const char *s_PHUSTR_5; // = PHUSTR_5; +//#define PHUSTR_6 "level 6: baron's lair" +extern const char *s_PHUSTR_6; // = PHUSTR_6; +//#define PHUSTR_7 "level 7: caughtyard" +extern const char *s_PHUSTR_7; // = PHUSTR_7; +//#define PHUSTR_8 "level 8: realm" +extern const char *s_PHUSTR_8; // = PHUSTR_8; +//#define PHUSTR_9 "level 9: abattoire" +extern const char *s_PHUSTR_9; // = PHUSTR_9; +//#define PHUSTR_10 "level 10: onslaught" +extern const char *s_PHUSTR_10; // = PHUSTR_10; +//#define PHUSTR_11 "level 11: hunted" +extern const char *s_PHUSTR_11; // = PHUSTR_11; + +//#define PHUSTR_12 "level 12: speed" +extern const char *s_PHUSTR_12; // = PHUSTR_12; +//#define PHUSTR_13 "level 13: the crypt" +extern const char *s_PHUSTR_13; // = PHUSTR_13; +//#define PHUSTR_14 "level 14: genesis" +extern const char *s_PHUSTR_14; // = PHUSTR_14; +//#define PHUSTR_15 "level 15: the twilight" +extern const char *s_PHUSTR_15; // = PHUSTR_15; +//#define PHUSTR_16 "level 16: the omen" +extern const char *s_PHUSTR_16; // = PHUSTR_16; +//#define PHUSTR_17 "level 17: compound" +extern const char *s_PHUSTR_17; // = PHUSTR_17; +//#define PHUSTR_18 "level 18: neurosphere" +extern const char *s_PHUSTR_18; // = PHUSTR_18; +//#define PHUSTR_19 "level 19: nme" +extern const char *s_PHUSTR_19; // = PHUSTR_19; +//#define PHUSTR_20 "level 20: the death domain" +extern const char *s_PHUSTR_20; // = PHUSTR_20; + +//#define PHUSTR_21 "level 21: slayer" +extern const char *s_PHUSTR_21; // = PHUSTR_21; +//#define PHUSTR_22 "level 22: impossible mission" +extern const char *s_PHUSTR_22; // = PHUSTR_22; +//#define PHUSTR_23 "level 23: tombstone" +extern const char *s_PHUSTR_23; // = PHUSTR_23; +//#define PHUSTR_24 "level 24: the final frontier" +extern const char *s_PHUSTR_24; // = PHUSTR_24; +//#define PHUSTR_25 "level 25: the temple of darkness" +extern const char *s_PHUSTR_25; // = PHUSTR_25; +//#define PHUSTR_26 "level 26: bunker" +extern const char *s_PHUSTR_26; // = PHUSTR_26; +//#define PHUSTR_27 "level 27: anti-christ" +extern const char *s_PHUSTR_27; // = PHUSTR_27; +//#define PHUSTR_28 "level 28: the sewers" +extern const char *s_PHUSTR_28; // = PHUSTR_28; +//#define PHUSTR_29 "level 29: odyssey of noises" +extern const char *s_PHUSTR_29; // = PHUSTR_29; +//#define PHUSTR_30 "level 30: the gateway of hell" +extern const char *s_PHUSTR_30; // = PHUSTR_30; + +//#define PHUSTR_31 "level 31: cyberden" +extern const char *s_PHUSTR_31; // = PHUSTR_31; +//#define PHUSTR_32 "level 32: go 2 it" +extern const char *s_PHUSTR_32; // = PHUSTR_32; + +//#define THUSTR_1 "level 1: system control" +extern const char *s_THUSTR_1; // = THUSTR_1; +//#define THUSTR_2 "level 2: human bbq" +extern const char *s_THUSTR_2; // = THUSTR_2; +//#define THUSTR_3 "level 3: power control" +extern const char *s_THUSTR_3; // = THUSTR_3; +//#define THUSTR_4 "level 4: wormhole" +extern const char *s_THUSTR_4; // = THUSTR_4; +//#define THUSTR_5 "level 5: hanger" +extern const char *s_THUSTR_5; // = THUSTR_5; +//#define THUSTR_6 "level 6: open season" +extern const char *s_THUSTR_6; // = THUSTR_6; +//#define THUSTR_7 "level 7: prison" +extern const char *s_THUSTR_7; // = THUSTR_7; +//#define THUSTR_8 "level 8: metal" +extern const char *s_THUSTR_8; // = THUSTR_8; +//#define THUSTR_9 "level 9: stronghold" +extern const char *s_THUSTR_9; // = THUSTR_9; +//#define THUSTR_10 "level 10: redemption" +extern const char *s_THUSTR_10; // = THUSTR_10; +//#define THUSTR_11 "level 11: storage facility" +extern const char *s_THUSTR_11; // = THUSTR_11; + +//#define THUSTR_12 "level 12: crater" +extern const char *s_THUSTR_12; // = THUSTR_12; +//#define THUSTR_13 "level 13: nukage processing" +extern const char *s_THUSTR_13; // = THUSTR_13; +//#define THUSTR_14 "level 14: steel works" +extern const char *s_THUSTR_14; // = THUSTR_14; +//#define THUSTR_15 "level 15: dead zone" +extern const char *s_THUSTR_15; // = THUSTR_15; +//#define THUSTR_16 "level 16: deepest reaches" +extern const char *s_THUSTR_16; // = THUSTR_16; +//#define THUSTR_17 "level 17: processing area" +extern const char *s_THUSTR_17; // = THUSTR_17; +//#define THUSTR_18 "level 18: mill" +extern const char *s_THUSTR_18; // = THUSTR_18; +//#define THUSTR_19 "level 19: shipping/respawning" +extern const char *s_THUSTR_19; // = THUSTR_19; +//#define THUSTR_20 "level 20: central processing" +extern const char *s_THUSTR_20; // = THUSTR_20; + +//#define THUSTR_21 "level 21: administration center" +extern const char *s_THUSTR_21; // = THUSTR_21; +//#define THUSTR_22 "level 22: habitat" +extern const char *s_THUSTR_22; // = THUSTR_22; +//#define THUSTR_23 "level 23: lunar mining project" +extern const char *s_THUSTR_23; // = THUSTR_23; +//#define THUSTR_24 "level 24: quarry" +extern const char *s_THUSTR_24; // = THUSTR_24; +//#define THUSTR_25 "level 25: baron's den" +extern const char *s_THUSTR_25; // = THUSTR_25; +//#define THUSTR_26 "level 26: ballistyx" +extern const char *s_THUSTR_26; // = THUSTR_26; +//#define THUSTR_27 "level 27: mount pain" +extern const char *s_THUSTR_27; // = THUSTR_27; +//#define THUSTR_28 "level 28: heck" +extern const char *s_THUSTR_28; // = THUSTR_28; +//#define THUSTR_29 "level 29: river styx" +extern const char *s_THUSTR_29; // = THUSTR_29; +//#define THUSTR_30 "level 30: last call" +extern const char *s_THUSTR_30; // = THUSTR_30; + +//#define THUSTR_31 "level 31: pharaoh" +extern const char *s_THUSTR_31; // = THUSTR_31; +//#define THUSTR_32 "level 32: caribbean" +extern const char *s_THUSTR_32; // = THUSTR_32; + +//#define HUSTR_CHATMACRO1 "I'm ready to kick butt!" +extern const char *s_HUSTR_CHATMACRO1; // = HUSTR_CHATMACRO1; +//#define HUSTR_CHATMACRO2 "I'm OK." +extern const char *s_HUSTR_CHATMACRO2; // = HUSTR_CHATMACRO2; +//#define HUSTR_CHATMACRO3 "I'm not looking too good!" +extern const char *s_HUSTR_CHATMACRO3; // = HUSTR_CHATMACRO3; +//#define HUSTR_CHATMACRO4 "Help!" +extern const char *s_HUSTR_CHATMACRO4; // = HUSTR_CHATMACRO4; +//#define HUSTR_CHATMACRO5 "You suck!" +extern const char *s_HUSTR_CHATMACRO5; // = HUSTR_CHATMACRO5; +//#define HUSTR_CHATMACRO6 "Next time, scumbag..." +extern const char *s_HUSTR_CHATMACRO6; // = HUSTR_CHATMACRO6; +//#define HUSTR_CHATMACRO7 "Come here!" +extern const char *s_HUSTR_CHATMACRO7; // = HUSTR_CHATMACRO7; +//#define HUSTR_CHATMACRO8 "I'll take care of it." +extern const char *s_HUSTR_CHATMACRO8; // = HUSTR_CHATMACRO8; +//#define HUSTR_CHATMACRO9 "Yes" +extern const char *s_HUSTR_CHATMACRO9; // = HUSTR_CHATMACRO9; +//#define HUSTR_CHATMACRO0 "No" +extern const char *s_HUSTR_CHATMACRO0; // = HUSTR_CHATMACRO0; + +//#define HUSTR_TALKTOSELF1 "You mumble to yourself" +extern const char *s_HUSTR_TALKTOSELF1; // = HUSTR_TALKTOSELF1; +//#define HUSTR_TALKTOSELF2 "Who's there?" +extern const char *s_HUSTR_TALKTOSELF2; // = HUSTR_TALKTOSELF2; +//#define HUSTR_TALKTOSELF3 "You scare yourself" +extern const char *s_HUSTR_TALKTOSELF3; // = HUSTR_TALKTOSELF3; +//#define HUSTR_TALKTOSELF4 "You start to rave" +extern const char *s_HUSTR_TALKTOSELF4; // = HUSTR_TALKTOSELF4; +//#define HUSTR_TALKTOSELF5 "You've lost it..." +extern const char *s_HUSTR_TALKTOSELF5; // = HUSTR_TALKTOSELF5; + +//#define HUSTR_MESSAGESENT "[Message Sent]" +extern const char *s_HUSTR_MESSAGESENT; // = HUSTR_MESSAGESENT; + +// The following should NOT be changed unless it seems +// just AWFULLY necessary + +//#define HUSTR_PLRGREEN "Green: " +extern const char *s_HUSTR_PLRGREEN; // = HUSTR_PLRGREEN; +//#define HUSTR_PLRINDIGO "Indigo: " +extern const char *s_HUSTR_PLRINDIGO; // = HUSTR_PLRINDIGO; +//#define HUSTR_PLRBROWN "Brown: " +extern const char *s_HUSTR_PLRBROWN; // = HUSTR_PLRBROWN; +//#define HUSTR_PLRRED "Red: " +extern const char *s_HUSTR_PLRRED; // = HUSTR_PLRRED; + +// +// AM_map.C +// + +//#define AMSTR_FOLLOWON "Follow Mode ON" +extern const char* s_AMSTR_FOLLOWON; // = AMSTR_FOLLOWON; +//#define AMSTR_FOLLOWOFF "Follow Mode OFF" +extern const char* s_AMSTR_FOLLOWOFF; // = AMSTR_FOLLOWOFF; + +//#define AMSTR_GRIDON "Grid ON" +extern const char* s_AMSTR_GRIDON; // = AMSTR_GRIDON; +//#define AMSTR_GRIDOFF "Grid OFF" +extern const char* s_AMSTR_GRIDOFF; // = AMSTR_GRIDOFF; + +//#define AMSTR_MARKEDSPOT "Marked Spot" +extern const char* s_AMSTR_MARKEDSPOT; // = AMSTR_MARKEDSPOT; +//#define AMSTR_MARKSCLEARED "All Marks Cleared" +extern const char* s_AMSTR_MARKSCLEARED; // = AMSTR_MARKSCLEARED; + +// CPhipps - automap rotate & overlay +extern const char* s_AMSTR_ROTATEON; +extern const char* s_AMSTR_ROTATEOFF; +extern const char* s_AMSTR_OVERLAYON; +extern const char* s_AMSTR_OVERLAYOFF; + +// +// ST_stuff.C +// + +//#define STSTR_MUS "Music Change" +extern const char* s_STSTR_MUS; // = STSTR_MUS; +//#define STSTR_NOMUS "IMPOSSIBLE SELECTION" +extern const char* s_STSTR_NOMUS; // = STSTR_NOMUS; +//#define STSTR_DQDON "Degreelessness Mode On" +extern const char* s_STSTR_DQDON; // = STSTR_DQDON; +//#define STSTR_DQDOFF "Degreelessness Mode Off" +extern const char* s_STSTR_DQDOFF; // = STSTR_DQDOFF; + +//#define STSTR_KFAADDED "Very Happy Ammo Added" +extern const char* s_STSTR_KFAADDED; // = STSTR_KFAADDED; +//#define STSTR_FAADDED "Ammo (no keys) Added" +extern const char* s_STSTR_FAADDED; // = STSTR_FAADDED; + +//#define STSTR_NCON "No Clipping Mode ON" +extern const char* s_STSTR_NCON; // = STSTR_NCON; +//#define STSTR_NCOFF "No Clipping Mode OFF" +extern const char* s_STSTR_NCOFF; // = STSTR_NCOFF; + +//#define STSTR_BEHOLD "inVuln, Str, Inviso, Rad, Allmap, or Lite-amp" +extern const char* s_STSTR_BEHOLD; // = STSTR_BEHOLD; +//#define STSTR_BEHOLDX "Power-up Toggled" +extern const char* s_STSTR_BEHOLDX; // = STSTR_BEHOLDX; + +//#define STSTR_CHOPPERS "... doesn't suck - GM" +extern const char* s_STSTR_CHOPPERS; // = STSTR_CHOPPERS; +//#define STSTR_CLEV "Changing Level..." +extern const char* s_STSTR_CLEV; // = STSTR_CLEV; + +// +// F_Finale.C +// +/* +#define E1TEXT \ +"Once you beat the big badasses and\n"\ +"clean out the moon base you're supposed\n"\ +"to win, aren't you? Aren't you? Where's\n"\ +"your fat reward and ticket home? What\n"\ +"the hell is this? It's not supposed to\n"\ +"end this way!\n"\ +"\n" \ +"It stinks like rotten meat, but looks\n"\ +"like the lost Deimos base. Looks like\n"\ +"you're stuck on The Shores of Hell.\n"\ +"The only way out is through.\n"\ +"\n"\ +"To continue the DOOM experience, play\n"\ +"The Shores of Hell and its amazing\n"\ +"sequel, Inferno!\n" +*/ +extern const char* s_E1TEXT; // = E1TEXT; + + +/* +#define E2TEXT \ +"You've done it! The hideous cyber-\n"\ +"demon lord that ruled the lost Deimos\n"\ +"moon base has been slain and you\n"\ +"are triumphant! But ... where are\n"\ +"you? You clamber to the edge of the\n"\ +"moon and look down to see the awful\n"\ +"truth.\n" \ +"\n"\ +"Deimos floats above Hell itself!\n"\ +"You've never heard of anyone escaping\n"\ +"from Hell, but you'll make the bastards\n"\ +"sorry they ever heard of you! Quickly,\n"\ +"you rappel down to the surface of\n"\ +"Hell.\n"\ +"\n" \ +"Now, it's on to the final chapter of\n"\ +"DOOM! -- Inferno." +*/ +extern const char* s_E2TEXT; // = E2TEXT; + + +/* +#define E3TEXT \ +"The loathsome spiderdemon that\n"\ +"masterminded the invasion of the moon\n"\ +"bases and caused so much death has had\n"\ +"its ass kicked for all time.\n"\ +"\n"\ +"A hidden doorway opens and you enter.\n"\ +"You've proven too tough for Hell to\n"\ +"contain, and now Hell at last plays\n"\ +"fair -- for you emerge from the door\n"\ +"to see the green fields of Earth!\n"\ +"Home at last.\n" \ +"\n"\ +"You wonder what's been happening on\n"\ +"Earth while you were battling evil\n"\ +"unleashed. It's good that no Hell-\n"\ +"spawn could have come through that\n"\ +"door with you ..." +*/ +extern const char* s_E3TEXT; // = E3TEXT; + + +/* +#define E4TEXT \ +"the spider mastermind must have sent forth\n"\ +"its legions of hellspawn before your\n"\ +"final confrontation with that terrible\n"\ +"beast from hell. but you stepped forward\n"\ +"and brought forth eternal damnation and\n"\ +"suffering upon the horde as a true hero\n"\ +"would in the face of something so evil.\n"\ +"\n"\ +"besides, someone was gonna pay for what\n"\ +"happened to daisy, your pet rabbit.\n"\ +"\n"\ +"but now, you see spread before you more\n"\ +"potential pain and gibbitude as a nation\n"\ +"of demons run amok among our cities.\n"\ +"\n"\ +"next stop, hell on earth!" +*/ +extern const char* s_E4TEXT; // = E4TEXT; + + +// after level 6, put this: + +/* +#define C1TEXT \ +"YOU HAVE ENTERED DEEPLY INTO THE INFESTED\n" \ +"STARPORT. BUT SOMETHING IS WRONG. THE\n" \ +"MONSTERS HAVE BROUGHT THEIR OWN REALITY\n" \ +"WITH THEM, AND THE STARPORT'S TECHNOLOGY\n" \ +"IS BEING SUBVERTED BY THEIR PRESENCE.\n" \ +"\n"\ +"AHEAD, YOU SEE AN OUTPOST OF HELL, A\n" \ +"FORTIFIED ZONE. IF YOU CAN GET PAST IT,\n" \ +"YOU CAN PENETRATE INTO THE HAUNTED HEART\n" \ +"OF THE STARBASE AND FIND THE CONTROLLING\n" \ +"SWITCH WHICH HOLDS EARTH'S POPULATION\n" \ +"HOSTAGE." +*/ +extern const char* s_C1TEXT; // = C1TEXT; + +// After level 11, put this: + +/* +#define C2TEXT \ +"YOU HAVE WON! YOUR VICTORY HAS ENABLED\n" \ +"HUMANKIND TO EVACUATE EARTH AND ESCAPE\n"\ +"THE NIGHTMARE. NOW YOU ARE THE ONLY\n"\ +"HUMAN LEFT ON THE FACE OF THE PLANET.\n"\ +"CANNIBAL MUTATIONS, CARNIVOROUS ALIENS,\n"\ +"AND EVIL SPIRITS ARE YOUR ONLY NEIGHBORS.\n"\ +"YOU SIT BACK AND WAIT FOR DEATH, CONTENT\n"\ +"THAT YOU HAVE SAVED YOUR SPECIES.\n"\ +"\n"\ +"BUT THEN, EARTH CONTROL BEAMS DOWN A\n"\ +"MESSAGE FROM SPACE: \"SENSORS HAVE LOCATED\n"\ +"THE SOURCE OF THE ALIEN INVASION. IF YOU\n"\ +"GO THERE, YOU MAY BE ABLE TO BLOCK THEIR\n"\ +"ENTRY. THE ALIEN BASE IS IN THE HEART OF\n"\ +"YOUR OWN HOME CITY, NOT FAR FROM THE\n"\ +"STARPORT.\" SLOWLY AND PAINFULLY YOU GET\n"\ +"UP AND RETURN TO THE FRAY." +*/ +extern const char* s_C2TEXT; // = C2TEXT; + + +// After level 20, put this: + +/* +#define C3TEXT \ +"YOU ARE AT THE CORRUPT HEART OF THE CITY,\n"\ +"SURROUNDED BY THE CORPSES OF YOUR ENEMIES.\n"\ +"YOU SEE NO WAY TO DESTROY THE CREATURES'\n"\ +"ENTRYWAY ON THIS SIDE, SO YOU CLENCH YOUR\n"\ +"TEETH AND PLUNGE THROUGH IT.\n"\ +"\n"\ +"THERE MUST BE A WAY TO CLOSE IT ON THE\n"\ +"OTHER SIDE. WHAT DO YOU CARE IF YOU'VE\n"\ +"GOT TO GO THROUGH HELL TO GET TO IT?" +*/ +extern const char* s_C3TEXT; // = C3TEXT; + + +// After level 29, put this: + +/* +#define C4TEXT \ +"THE HORRENDOUS VISAGE OF THE BIGGEST\n"\ +"DEMON YOU'VE EVER SEEN CRUMBLES BEFORE\n"\ +"YOU, AFTER YOU PUMP YOUR ROCKETS INTO\n"\ +"HIS EXPOSED BRAIN. THE MONSTER SHRIVELS\n"\ +"UP AND DIES, ITS THRASHING LIMBS\n"\ +"DEVASTATING UNTOLD MILES OF HELL'S\n"\ +"SURFACE.\n"\ +"\n"\ +"YOU'VE DONE IT. THE INVASION IS OVER.\n"\ +"EARTH IS SAVED. HELL IS A WRECK. YOU\n"\ +"WONDER WHERE BAD FOLKS WILL GO WHEN THEY\n"\ +"DIE, NOW. WIPING THE SWEAT FROM YOUR\n"\ +"FOREHEAD YOU BEGIN THE LONG TREK BACK\n"\ +"HOME. REBUILDING EARTH OUGHT TO BE A\n"\ +"LOT MORE FUN THAN RUINING IT WAS.\n" +*/ +extern const char* s_C4TEXT; // = C4TEXT; + + + +// Before level 31, put this: + +/* +#define C5TEXT \ +"CONGRATULATIONS, YOU'VE FOUND THE SECRET\n"\ +"LEVEL! LOOKS LIKE IT'S BEEN BUILT BY\n"\ +"HUMANS, RATHER THAN DEMONS. YOU WONDER\n"\ +"WHO THE INMATES OF THIS CORNER OF HELL\n"\ +"WILL BE." +*/ +extern const char* s_C5TEXT; // = C5TEXT; + + +// Before level 32, put this: + +/* +#define C6TEXT \ +"CONGRATULATIONS, YOU'VE FOUND THE\n"\ +"SUPER SECRET LEVEL! YOU'D BETTER\n"\ +"BLAZE THROUGH THIS ONE!\n" +*/ +extern const char* s_C6TEXT; // = C6TEXT; + + +// after map 06 + +/* +#define P1TEXT \ +"You gloat over the steaming carcass of the\n"\ +"Guardian. With its death, you've wrested\n"\ +"the Accelerator from the stinking claws\n"\ +"of Hell. You relax and glance around the\n"\ +"room. Damn! There was supposed to be at\n"\ +"least one working prototype, but you can't\n"\ +"see it. The demons must have taken it.\n"\ +"\n"\ +"You must find the prototype, or all your\n"\ +"struggles will have been wasted. Keep\n"\ +"moving, keep fighting, keep killing.\n"\ +"Oh yes, keep living, too." +*/ +extern const char* s_P1TEXT; // = P1TEXT; + + +// after map 11 + +/* +#define P2TEXT \ +"Even the deadly Arch-Vile labyrinth could\n"\ +"not stop you, and you've gotten to the\n"\ +"prototype Accelerator which is soon\n"\ +"efficiently and permanently deactivated.\n"\ +"\n"\ +"You're good at that kind of thing." +*/ +extern const char* s_P2TEXT; // = P2TEXT; + + +// after map 20 + +/* +#define P3TEXT \ +"You've bashed and battered your way into\n"\ +"the heart of the devil-hive. Time for a\n"\ +"Search-and-Destroy mission, aimed at the\n"\ +"Gatekeeper, whose foul offspring is\n"\ +"cascading to Earth. Yeah, he's bad. But\n"\ +"you know who's worse!\n"\ +"\n"\ +"Grinning evilly, you check your gear, and\n"\ +"get ready to give the bastard a little Hell\n"\ +"of your own making!" +*/ +extern const char* s_P3TEXT; // = P3TEXT; + +// after map 30 + +/* +#define P4TEXT \ +"The Gatekeeper's evil face is splattered\n"\ +"all over the place. As its tattered corpse\n"\ +"collapses, an inverted Gate forms and\n"\ +"sucks down the shards of the last\n"\ +"prototype Accelerator, not to mention the\n"\ +"few remaining demons. You're done. Hell\n"\ +"has gone back to pounding bad dead folks \n"\ +"instead of good live ones. Remember to\n"\ +"tell your grandkids to put a rocket\n"\ +"launcher in your coffin. If you go to Hell\n"\ +"when you die, you'll need it for some\n"\ +"final cleaning-up ..." +*/ +extern const char* s_P4TEXT; // = P4TEXT; + +// before map 31 + +/* +#define P5TEXT \ +"You've found the second-hardest level we\n"\ +"got. Hope you have a saved game a level or\n"\ +"two previous. If not, be prepared to die\n"\ +"aplenty. For master marines only." +*/ +extern const char* s_P5TEXT; // = P5TEXT; + +// before map 32 + +/* +#define P6TEXT \ +"Betcha wondered just what WAS the hardest\n"\ +"level we had ready for ya? Now you know.\n"\ +"No one gets out alive." +*/ +extern const char* s_P6TEXT; // = P6TEXT; + + +/* +#define T1TEXT \ +"You've fought your way out of the infested\n"\ +"experimental labs. It seems that UAC has\n"\ +"once again gulped it down. With their\n"\ +"high turnover, it must be hard for poor\n"\ +"old UAC to buy corporate health insurance\n"\ +"nowadays..\n"\ +"\n"\ +"Ahead lies the military complex, now\n"\ +"swarming with diseased horrors hot to get\n"\ +"their teeth into you. With luck, the\n"\ +"complex still has some warlike ordnance\n"\ +"laying around." +*/ +extern const char* s_T1TEXT; // = T1TEXT; + + +/* +#define T2TEXT \ +"You hear the grinding of heavy machinery\n"\ +"ahead. You sure hope they're not stamping\n"\ +"out new hellspawn, but you're ready to\n"\ +"ream out a whole herd if you have to.\n"\ +"They might be planning a blood feast, but\n"\ +"you feel about as mean as two thousand\n"\ +"maniacs packed into one mad killer.\n"\ +"\n"\ +"You don't plan to go down easy." +*/ +extern const char* s_T2TEXT; // = T2TEXT; + + +/* +#define T3TEXT \ +"The vista opening ahead looks real damn\n"\ +"familiar. Smells familiar, too -- like\n"\ +"fried excrement. You didn't like this\n"\ +"place before, and you sure as hell ain't\n"\ +"planning to like it now. The more you\n"\ +"brood on it, the madder you get.\n"\ +"Hefting your gun, an evil grin trickles\n"\ +"onto your face. Time to take some names." +*/ +extern const char* s_T3TEXT; // = T3TEXT; + +/* +#define T4TEXT \ +"Suddenly, all is silent, from one horizon\n"\ +"to the other. The agonizing echo of Hell\n"\ +"fades away, the nightmare sky turns to\n"\ +"blue, the heaps of monster corpses start \n"\ +"to evaporate along with the evil stench \n"\ +"that filled the air. Jeeze, maybe you've\n"\ +"done it. Have you really won?\n"\ +"\n"\ +"Something rumbles in the distance.\n"\ +"A blue light begins to glow inside the\n"\ +"ruined skull of the demon-spitter." +*/ +extern const char* s_T4TEXT; // = T4TEXT; + + +/* +#define T5TEXT \ +"What now? Looks totally different. Kind\n"\ +"of like King Tut's condo. Well,\n"\ +"whatever's here can't be any worse\n"\ +"than usual. Can it? Or maybe it's best\n"\ +"to let sleeping gods lie.." +*/ +extern const char* s_T5TEXT; // = T5TEXT; + + +/* +#define T6TEXT \ +"Time for a vacation. You've burst the\n"\ +"bowels of hell and by golly you're ready\n"\ +"for a break. You mutter to yourself,\n"\ +"Maybe someone else can kick Hell's ass\n"\ +"next time around. Ahead lies a quiet town,\n"\ +"with peaceful flowing water, quaint\n"\ +"buildings, and presumably no Hellspawn.\n"\ +"\n"\ +"As you step off the transport, you hear\n"\ +"the stomp of a cyberdemon's iron shoe." +*/ +extern const char* s_T6TEXT; // = T6TEXT; + +// +// Character cast strings F_FINALE.C +// +//#define CC_ZOMBIE "ZOMBIEMAN" +extern const char* s_CC_ZOMBIE; // = CC_ZOMBIE; +//#define CC_SHOTGUN "SHOTGUN GUY" +extern const char* s_CC_SHOTGUN; // = CC_SHOTGUN; +//#define CC_HEAVY "HEAVY WEAPON DUDE" +extern const char* s_CC_HEAVY; // = CC_HEAVY; +//#define CC_IMP "IMP" +extern const char* s_CC_IMP; // = CC_IMP; +//#define CC_DEMON "DEMON" +extern const char* s_CC_DEMON; // = CC_DEMON; +//#define CC_LOST "LOST SOUL" +extern const char* s_CC_LOST; // = CC_LOST; +//#define CC_CACO "CACODEMON" +extern const char* s_CC_CACO; // = CC_CACO; +//#define CC_HELL "HELL KNIGHT" +extern const char* s_CC_HELL; // = CC_HELL; +//#define CC_BARON "BARON OF HELL" +extern const char* s_CC_BARON; // = CC_BARON; +//#define CC_ARACH "ARACHNOTRON" +extern const char* s_CC_ARACH; // = CC_ARACH; +//#define CC_PAIN "PAIN ELEMENTAL" +extern const char* s_CC_PAIN; // = CC_PAIN; +//#define CC_REVEN "REVENANT" +extern const char* s_CC_REVEN; // = CC_REVEN; +//#define CC_MANCU "MANCUBUS" +extern const char* s_CC_MANCU; // = CC_MANCU; +//#define CC_ARCH "ARCH-VILE" +extern const char* s_CC_ARCH; // = CC_ARCH; +//#define CC_SPIDER "THE SPIDER MASTERMIND" +extern const char* s_CC_SPIDER; // = CC_SPIDER; +//#define CC_CYBER "THE CYBERDEMON" +extern const char* s_CC_CYBER; // = CC_CYBER; +//#define CC_HERO "OUR HERO" +extern const char* s_CC_HERO; // = CC_HERO; + +// Ty 03/30/98 - new substitutions for background textures during int screens +// char* bgflatE1 = "FLOOR4_8"; +extern const char* bgflatE1; +// char* bgflatE2 = "SFLR6_1"; +extern const char* bgflatE2; +// char* bgflatE3 = "MFLR8_4"; +extern const char* bgflatE3; +// char* bgflatE4 = "MFLR8_3"; +extern const char* bgflatE4; + +// char* bgflat06 = "SLIME16"; +extern const char* bgflat06; +// char* bgflat11 = "RROCK14"; +extern const char* bgflat11; +// char* bgflat20 = "RROCK07"; +extern const char* bgflat20; +// char* bgflat30 = "RROCK17"; +extern const char* bgflat30; +// char* bgflat15 = "RROCK13"; +extern const char* bgflat15; +// char* bgflat31 = "RROCK19"; +extern const char* bgflat31; + +// char* bgcastcall = "BOSSBACK"; // panel behind cast call +extern const char* bgcastcall; + +// ignored if blank, general purpose startup announcements +// char* startup1 = ""; +extern const char* startup1; +// char* startup2 = ""; +extern const char* startup2; +// char* startup3 = ""; +extern const char* startup3; +// char* startup4 = ""; +extern const char* startup4; +// char* startup5 = ""; +extern const char* startup5; + +// from g_game.c, prefix for savegame name like "boomsav" +extern const char* savegamename; + +void D_BuildBEXTables(void); + +#endif diff --git a/common/prboom/d_englsh.h b/common/prboom/d_englsh.h new file mode 100755 index 0000000..46c15be --- /dev/null +++ b/common/prboom/d_englsh.h @@ -0,0 +1,707 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Printed strings for translation. + * English language support (default). + * See dstrings.h for suggestions about foreign language BEX support + * + *-----------------------------------------------------------------------------*/ + +#ifndef __D_ENGLSH__ +#define __D_ENGLSH__ + +/* d_main.c */ +#define D_DEVSTR "Development mode ON.\n" +#define D_CDROM "CD-ROM Version: default.cfg from c:\\doomdata\n" + +/* m_menu.c */ +#define PRESSKEY "press a key." +#define PRESSYN "press y or n." +#define QUITMSG "are you sure you want to\nquit this great game?" +#define LOADNET "you can't do load while in a net game!\n\n" PRESSKEY +#define QLOADNET "you can't quickload during a netgame!\n\n" PRESSKEY +#define QSAVESPOT "you haven't picked a quicksave slot yet!\n\n" PRESSKEY +#define SAVEDEAD "you can't save if you aren't playing!\n\n" PRESSKEY +#define QSPROMPT "quicksave over your game named\n\n'%s'?\n\n" PRESSYN +#define QLPROMPT "do you want to quickload the game named\n\n'%s'?\n\n" PRESSYN + +#define NEWGAME \ + "you can't start a new game\n"\ + "while in a network game.\n\n" PRESSKEY + +#define NIGHTMARE \ + "are you sure? this skill level\n"\ + "isn't even remotely fair.\n\n" PRESSYN + +#define SWSTRING \ + "this is the shareware version of doom.\n\n"\ + "you need to order the entire trilogy.\n\n" PRESSKEY + +#define MSGOFF "Messages OFF" +#define MSGON "Messages ON" +#define NETEND "you can't end a netgame!\n\n" PRESSKEY +#define ENDGAME "are you sure you want to end the game?\n\n" PRESSYN +#define RESTARTLEVEL "restart the level?\n\n" PRESSYN + +#define DOSY "(press y to quit)" + +#define DETAILHI "High detail" +#define DETAILLO "Low detail" +#define GAMMALVL0 "Gamma correction OFF" +#define GAMMALVL1 "Gamma correction level 1" +#define GAMMALVL2 "Gamma correction level 2" +#define GAMMALVL3 "Gamma correction level 3" +#define GAMMALVL4 "Gamma correction level 4" +#define EMPTYSTRING "empty slot" + +/* p_inter.c */ +#define GOTARMOR "Picked up the armor." +#define GOTMEGA "Picked up the MegaArmor!" +#define GOTHTHBONUS "Picked up a health bonus." +#define GOTARMBONUS "Picked up an armor bonus." +#define GOTSTIM "Picked up a stimpack." +#define GOTMEDINEED "Picked up a medikit that you REALLY need!" +#define GOTMEDIKIT "Picked up a medikit." +#define GOTSUPER "Supercharge!" + +#define GOTBLUECARD "Picked up a blue keycard." +#define GOTYELWCARD "Picked up a yellow keycard." +#define GOTREDCARD "Picked up a red keycard." +#define GOTBLUESKUL "Picked up a blue skull key." +#define GOTYELWSKUL "Picked up a yellow skull key." +#define GOTREDSKULL "Picked up a red skull key." + +#define GOTINVUL "Invulnerability!" +#define GOTBERSERK "Berserk!" +#define GOTINVIS "Partial Invisibility" +#define GOTSUIT "Radiation Shielding Suit" +#define GOTMAP "Computer Area Map" +#define GOTVISOR "Light Amplification Visor" +#define GOTMSPHERE "MegaSphere!" + +#define GOTCLIP "Picked up a clip." +#define GOTCLIPBOX "Picked up a box of bullets." +#define GOTROCKET "Picked up a rocket." +#define GOTROCKBOX "Picked up a box of rockets." +#define GOTCELL "Picked up an energy cell." +#define GOTCELLBOX "Picked up an energy cell pack." +#define GOTSHELLS "Picked up shotgun shells." // JDC: removed number 4 so baby mode isn't incorrect +#define GOTSHELLBOX "Picked up a box of shotgun shells." +#define GOTBACKPACK "Picked up a backpack full of ammo!" + +#define GOTBFG9000 "You got the BFG9000! Oh, yes." +#define GOTCHAINGUN "You got the chaingun!" +#define GOTCHAINSAW "A chainsaw! Find some meat!" +#define GOTLAUNCHER "You got the rocket launcher!" +#define GOTPLASMA "You got the plasma gun!" +#define GOTSHOTGUN "You got the shotgun!" +#define GOTSHOTGUN2 "You got the super shotgun!" + +/* p_doors.c */ // JDC: added punctuation to these +#define PD_BLUEO "You need a blue key to activate this object." +#define PD_REDO "You need a red key to activate this object." +#define PD_YELLOWO "You need a yellow key to activate this object." +#define PD_BLUEK "You need a blue key to open this door." +#define PD_REDK "You need a red key to open this door." +#define PD_YELLOWK "You need a yellow key to open this door." +/* jff 02/05/98 Create messages specific to card and skull keys */ +#define PD_BLUEC "You need a blue card to open this door." +#define PD_REDC "You need a red card to open this door." +#define PD_YELLOWC "You need a yellow card to open this door." +#define PD_BLUES "You need a blue skull to open this door." +#define PD_REDS "You need a red skull to open this door." +#define PD_YELLOWS "You need a yellow skull to open this door." +#define PD_ANY "Any key will open this door." +#define PD_ALL3 "You need all three keys to open this door." +#define PD_ALL6 "You need all six keys to open this door." + +/* g_game.c */ +#define GGSAVED "Game saved." // JDC: capitalized per testing report + +/* hu_stuff.c */ +#define HUSTR_MSGU "[Message unsent]" + +#define HUSTR_E1M1 "E1M1: Hangar" +#define HUSTR_E1M2 "E1M2: Nuclear Plant" +#define HUSTR_E1M3 "E1M3: Toxin Refinery" +#define HUSTR_E1M4 "E1M4: Command Control" +#define HUSTR_E1M5 "E1M5: Phobos Lab" +#define HUSTR_E1M6 "E1M6: Central Processing" +#define HUSTR_E1M7 "E1M7: Computer Station" +#define HUSTR_E1M8 "E1M8: Phobos Anomaly" +#define HUSTR_E1M9 "E1M9: Military Base" + +#define HUSTR_E2M1 "E2M1: Deimos Anomaly" +#define HUSTR_E2M2 "E2M2: Containment Area" +#define HUSTR_E2M3 "E2M3: Refinery" +#define HUSTR_E2M4 "E2M4: Deimos Lab" +#define HUSTR_E2M5 "E2M5: Command Center" +#define HUSTR_E2M6 "E2M6: Halls of the Damned" +#define HUSTR_E2M7 "E2M7: Spawning Vats" +#define HUSTR_E2M8 "E2M8: Tower of Babel" +#define HUSTR_E2M9 "E2M9: Fortress of Mystery" + +#define HUSTR_E3M1 "E3M1: Hell Keep" +#define HUSTR_E3M2 "E3M2: Slough of Despair" +#define HUSTR_E3M3 "E3M3: Pandemonium" +#define HUSTR_E3M4 "E3M4: House of Pain" +#define HUSTR_E3M5 "E3M5: Unholy Cathedral" +#define HUSTR_E3M6 "E3M6: Mt. Erebus" +#define HUSTR_E3M7 "E3M7: Limbo" +#define HUSTR_E3M8 "E3M8: Dis" +#define HUSTR_E3M9 "E3M9: Warrens" + +#define HUSTR_E4M1 "E4M1: Hell Beneath" +#define HUSTR_E4M2 "E4M2: Perfect Hatred" +#define HUSTR_E4M3 "E4M3: Sever The Wicked" +#define HUSTR_E4M4 "E4M4: Unruly Evil" +#define HUSTR_E4M5 "E4M5: They Will Repent" +#define HUSTR_E4M6 "E4M6: Against Thee Wickedly" +#define HUSTR_E4M7 "E4M7: And Hell Followed" +#define HUSTR_E4M8 "E4M8: Unto The Cruel" +#define HUSTR_E4M9 "E4M9: Fear" + +#define HUSTR_1 "level 1: entryway" +#define HUSTR_2 "level 2: underhalls" +#define HUSTR_3 "level 3: the gantlet" +#define HUSTR_4 "level 4: the focus" +#define HUSTR_5 "level 5: the waste tunnels" +#define HUSTR_6 "level 6: the crusher" +#define HUSTR_7 "level 7: dead simple" +#define HUSTR_8 "level 8: tricks and traps" +#define HUSTR_9 "level 9: the pit" +#define HUSTR_10 "level 10: refueling base" +#define HUSTR_11 "level 11: 'o' of destruction!" + +#define HUSTR_12 "level 12: the factory" +#define HUSTR_13 "level 13: downtown" +#define HUSTR_14 "level 14: the inmost dens" +#define HUSTR_15 "level 15: industrial zone" +#define HUSTR_16 "level 16: suburbs" +#define HUSTR_17 "level 17: tenements" +#define HUSTR_18 "level 18: the courtyard" +#define HUSTR_19 "level 19: the citadel" +#define HUSTR_20 "level 20: gotcha!" + +#define HUSTR_21 "level 21: nirvana" +#define HUSTR_22 "level 22: the catacombs" +#define HUSTR_23 "level 23: barrels o' fun" +#define HUSTR_24 "level 24: the chasm" +#define HUSTR_25 "level 25: bloodfalls" +#define HUSTR_26 "level 26: the abandoned mines" +#define HUSTR_27 "level 27: monster condo" +#define HUSTR_28 "level 28: the spirit world" +#define HUSTR_29 "level 29: the living end" +#define HUSTR_30 "level 30: icon of sin" + +#define HUSTR_31 "level 31: wolfenstein" +#define HUSTR_32 "level 32: grosse" + +#define PHUSTR_1 "level 1: congo" +#define PHUSTR_2 "level 2: well of souls" +#define PHUSTR_3 "level 3: aztec" +#define PHUSTR_4 "level 4: caged" +#define PHUSTR_5 "level 5: ghost town" +#define PHUSTR_6 "level 6: baron's lair" +#define PHUSTR_7 "level 7: caughtyard" +#define PHUSTR_8 "level 8: realm" +#define PHUSTR_9 "level 9: abattoire" +#define PHUSTR_10 "level 10: onslaught" +#define PHUSTR_11 "level 11: hunted" + +#define PHUSTR_12 "level 12: speed" +#define PHUSTR_13 "level 13: the crypt" +#define PHUSTR_14 "level 14: genesis" +#define PHUSTR_15 "level 15: the twilight" +#define PHUSTR_16 "level 16: the omen" +#define PHUSTR_17 "level 17: compound" +#define PHUSTR_18 "level 18: neurosphere" +#define PHUSTR_19 "level 19: nme" +#define PHUSTR_20 "level 20: the death domain" + +#define PHUSTR_21 "level 21: slayer" +#define PHUSTR_22 "level 22: impossible mission" +#define PHUSTR_23 "level 23: tombstone" +#define PHUSTR_24 "level 24: the final frontier" +#define PHUSTR_25 "level 25: the temple of darkness" +#define PHUSTR_26 "level 26: bunker" +#define PHUSTR_27 "level 27: anti-christ" +#define PHUSTR_28 "level 28: the sewers" +#define PHUSTR_29 "level 29: odyssey of noises" +#define PHUSTR_30 "level 30: the gateway of hell" + +#define PHUSTR_31 "level 31: cyberden" +#define PHUSTR_32 "level 32: go 2 it" + +#define THUSTR_1 "level 1: system control" +#define THUSTR_2 "level 2: human bbq" +#define THUSTR_3 "level 3: power control" +#define THUSTR_4 "level 4: wormhole" +#define THUSTR_5 "level 5: hanger" +#define THUSTR_6 "level 6: open season" +#define THUSTR_7 "level 7: prison" +#define THUSTR_8 "level 8: metal" +#define THUSTR_9 "level 9: stronghold" +#define THUSTR_10 "level 10: redemption" +#define THUSTR_11 "level 11: storage facility" + +#define THUSTR_12 "level 12: crater" +#define THUSTR_13 "level 13: nukage processing" +#define THUSTR_14 "level 14: steel works" +#define THUSTR_15 "level 15: dead zone" +#define THUSTR_16 "level 16: deepest reaches" +#define THUSTR_17 "level 17: processing area" +#define THUSTR_18 "level 18: mill" +#define THUSTR_19 "level 19: shipping/respawning" +#define THUSTR_20 "level 20: central processing" + +#define THUSTR_21 "level 21: administration center" +#define THUSTR_22 "level 22: habitat" +#define THUSTR_23 "level 23: lunar mining project" +#define THUSTR_24 "level 24: quarry" +#define THUSTR_25 "level 25: baron's den" +#define THUSTR_26 "level 26: ballistyx" +#define THUSTR_27 "level 27: mount pain" +#define THUSTR_28 "level 28: heck" +#define THUSTR_29 "level 29: river styx" +#define THUSTR_30 "level 30: last call" + +#define THUSTR_31 "level 31: pharaoh" +#define THUSTR_32 "level 32: caribbean" + +#define HUSTR_CHATMACRO1 "I'm ready to kick butt!" +#define HUSTR_CHATMACRO2 "I'm OK." +#define HUSTR_CHATMACRO3 "I'm not looking too good!" +#define HUSTR_CHATMACRO4 "Help!" +#define HUSTR_CHATMACRO5 "You suck!" +#define HUSTR_CHATMACRO6 "Next time, scumbag..." +#define HUSTR_CHATMACRO7 "Come here!" +#define HUSTR_CHATMACRO8 "I'll take care of it." +#define HUSTR_CHATMACRO9 "Yes" +#define HUSTR_CHATMACRO0 "No" + +#define HUSTR_TALKTOSELF1 "You mumble to yourself" +#define HUSTR_TALKTOSELF2 "Who's there?" +#define HUSTR_TALKTOSELF3 "You scare yourself" +#define HUSTR_TALKTOSELF4 "You start to rave" +#define HUSTR_TALKTOSELF5 "You've lost it..." + +#define HUSTR_MESSAGESENT "[Message Sent]" + +/* The following should NOT be changed unless it seems + * just AWFULLY necessary */ + +#define HUSTR_PLRGREEN "Player 1: " +#define HUSTR_PLRINDIGO "Player 2: " +#define HUSTR_PLRBROWN "Player 3: " +#define HUSTR_PLRRED "Player 4: " + +#define HUSTR_KEYGREEN 'g' +#define HUSTR_KEYINDIGO 'i' +#define HUSTR_KEYBROWN 'b' +#define HUSTR_KEYRED 'r' + +/* am_map.c */ + +#define AMSTR_FOLLOWON "Follow Mode ON" +#define AMSTR_FOLLOWOFF "Follow Mode OFF" + +#define AMSTR_GRIDON "Grid ON" +#define AMSTR_GRIDOFF "Grid OFF" + +#define AMSTR_MARKEDSPOT "Marked Spot" +#define AMSTR_MARKSCLEARED "All Marks Cleared" + +#define AMSTR_ROTATEON "Rotate Mode ON" +#define AMSTR_ROTATEOFF "Rotate Mode OFF" + +#define AMSTR_OVERLAYON "Overlay Mode ON" +#define AMSTR_OVERLAYOFF "Overlay Mode OFF" + +/* st_stuff.c */ + +#define STSTR_MUS "Music Change" +#define STSTR_NOMUS "IMPOSSIBLE SELECTION" +#define STSTR_DQDON "Degreelessness Mode On" +#define STSTR_DQDOFF "Degreelessness Mode Off" + +#define STSTR_KFAADDED "Very Happy Ammo Added" +#define STSTR_FAADDED "Ammo (no keys) Added" + +#define STSTR_NCON "No Clipping Mode ON" +#define STSTR_NCOFF "No Clipping Mode OFF" + +#define STSTR_BEHOLD "inVuln, Str, Inviso, Rad, Allmap, or Lite-amp" +#define STSTR_BEHOLDX "Power-up Toggled" + +#define STSTR_CHOPPERS "... doesn't suck - GM" +#define STSTR_CLEV "Changing Level..." + +#define STSTR_COMPON "Compatibility Mode On" /* phares */ +#define STSTR_COMPOFF "Compatibility Mode Off" /* phares */ + +/* f_finale.c */ + +#define E1TEXT \ + "Once you beat the big badasses and\n"\ + "clean out the moon base you're supposed\n"\ + "to win, aren't you? Aren't you? Where's\n"\ + "your fat reward and ticket home? What\n"\ + "the hell is this? It's not supposed to\n"\ + "end this way!\n"\ + "\n" \ + "It stinks like rotten meat, but looks\n"\ + "like the lost Deimos base. Looks like\n"\ + "you're stuck on The Shores of Hell.\n"\ + "The only way out is through.\n"\ + "\n"\ + "To continue the DOOM experience, play\n"\ + "The Shores of Hell and its amazing\n"\ + "sequel, Inferno!\n" + + +#define E2TEXT \ + "You've done it! The hideous cyber-\n"\ + "demon lord that ruled the lost Deimos\n"\ + "moon base has been slain and you\n"\ + "are triumphant! But ... where are\n"\ + "you? You clamber to the edge of the\n"\ + "moon and look down to see the awful\n"\ + "truth.\n" \ + "\n"\ + "Deimos floats above Hell itself!\n"\ + "You've never heard of anyone escaping\n"\ + "from Hell, but you'll make the bastards\n"\ + "sorry they ever heard of you! Quickly,\n"\ + "you rappel down to the surface of\n"\ + "Hell.\n"\ + "\n" \ + "Now, it's on to the final chapter of\n"\ + "DOOM! -- Inferno." + + +#define E3TEXT \ + "The loathsome spiderdemon that\n"\ + "masterminded the invasion of the moon\n"\ + "bases and caused so much death has had\n"\ + "its ass kicked for all time.\n"\ + "\n"\ + "A hidden doorway opens and you enter.\n"\ + "You've proven too tough for Hell to\n"\ + "contain, and now Hell at last plays\n"\ + "fair -- for you emerge from the door\n"\ + "to see the green fields of Earth!\n"\ + "Home at last.\n" \ + "\n"\ + "You wonder what's been happening on\n"\ + "Earth while you were battling evil\n"\ + "unleashed. It's good that no Hell-\n"\ + "spawn could have come through that\n"\ + "door with you ..." + + +#define E4TEXT \ + "the spider mastermind must have sent forth\n"\ + "its legions of hellspawn before your\n"\ + "final confrontation with that terrible\n"\ + "beast from hell. but you stepped forward\n"\ + "and brought forth eternal damnation and\n"\ + "suffering upon the horde as a true hero\n"\ + "would in the face of something so evil.\n"\ + "\n"\ + "besides, someone was gonna pay for what\n"\ + "happened to daisy, your pet rabbit.\n"\ + "\n"\ + "but now, you see spread before you more\n"\ + "potential pain and gibbitude as a nation\n"\ + "of demons run amok among our cities.\n"\ + "\n"\ + "next stop, hell on earth!" + + +/* after level 6, put this: */ + +#define C1TEXT \ + "YOU HAVE ENTERED DEEPLY INTO THE INFESTED\n" \ + "STARPORT. BUT SOMETHING IS WRONG. THE\n" \ + "MONSTERS HAVE BROUGHT THEIR OWN REALITY\n" \ + "WITH THEM, AND THE STARPORT'S TECHNOLOGY\n" \ + "IS BEING SUBVERTED BY THEIR PRESENCE.\n" \ + "\n"\ + "AHEAD, YOU SEE AN OUTPOST OF HELL, A\n" \ + "FORTIFIED ZONE. IF YOU CAN GET PAST IT,\n" \ + "YOU CAN PENETRATE INTO THE HAUNTED HEART\n" \ + "OF THE STARBASE AND FIND THE CONTROLLING\n" \ + "SWITCH WHICH HOLDS EARTH'S POPULATION\n" \ + "HOSTAGE." + +/* After level 11, put this: */ + +#define C2TEXT \ + "YOU HAVE WON! YOUR VICTORY HAS ENABLED\n" \ + "HUMANKIND TO EVACUATE EARTH AND ESCAPE\n"\ + "THE NIGHTMARE. NOW YOU ARE THE ONLY\n"\ + "HUMAN LEFT ON THE FACE OF THE PLANET.\n"\ + "CANNIBAL MUTATIONS, CARNIVOROUS ALIENS,\n"\ + "AND EVIL SPIRITS ARE YOUR ONLY NEIGHBORS.\n"\ + "YOU SIT BACK AND WAIT FOR DEATH, CONTENT\n"\ + "THAT YOU HAVE SAVED YOUR SPECIES.\n"\ + "\n"\ + "BUT THEN, EARTH CONTROL BEAMS DOWN A\n"\ + "MESSAGE FROM SPACE: \"SENSORS HAVE LOCATED\n"\ + "THE SOURCE OF THE ALIEN INVASION. IF YOU\n"\ + "GO THERE, YOU MAY BE ABLE TO BLOCK THEIR\n"\ + "ENTRY. THE ALIEN BASE IS IN THE HEART OF\n"\ + "YOUR OWN HOME CITY, NOT FAR FROM THE\n"\ + "STARPORT.\" SLOWLY AND PAINFULLY YOU GET\n"\ + "UP AND RETURN TO THE FRAY." + + +/* After level 20, put this: */ + +#define C3TEXT \ + "YOU ARE AT THE CORRUPT HEART OF THE CITY,\n"\ + "SURROUNDED BY THE CORPSES OF YOUR ENEMIES.\n"\ + "YOU SEE NO WAY TO DESTROY THE CREATURES'\n"\ + "ENTRYWAY ON THIS SIDE, SO YOU CLENCH YOUR\n"\ + "TEETH AND PLUNGE THROUGH IT.\n"\ + "\n"\ + "THERE MUST BE A WAY TO CLOSE IT ON THE\n"\ + "OTHER SIDE. WHAT DO YOU CARE IF YOU'VE\n"\ + "GOT TO GO THROUGH HELL TO GET TO IT?" + + +/* After level 29, put this: */ + +#define C4TEXT \ + "THE HORRENDOUS VISAGE OF THE BIGGEST\n"\ + "DEMON YOU'VE EVER SEEN CRUMBLES BEFORE\n"\ + "YOU, AFTER YOU PUMP YOUR ROCKETS INTO\n"\ + "HIS EXPOSED BRAIN. THE MONSTER SHRIVELS\n"\ + "UP AND DIES, ITS THRASHING LIMBS\n"\ + "DEVASTATING UNTOLD MILES OF HELL'S\n"\ + "SURFACE.\n"\ + "\n"\ + "YOU'VE DONE IT. THE INVASION IS OVER.\n"\ + "EARTH IS SAVED. HELL IS A WRECK. YOU\n"\ + "WONDER WHERE BAD FOLKS WILL GO WHEN THEY\n"\ + "DIE, NOW. WIPING THE SWEAT FROM YOUR\n"\ + "FOREHEAD YOU BEGIN THE LONG TREK BACK\n"\ + "HOME. REBUILDING EARTH OUGHT TO BE A\n"\ + "LOT MORE FUN THAN RUINING IT WAS.\n" + +/* Before level 31, put this: */ + +#define C5TEXT \ + "CONGRATULATIONS, YOU'VE FOUND THE SECRET\n"\ + "LEVEL! LOOKS LIKE IT'S BEEN BUILT BY\n"\ + "HUMANS, RATHER THAN DEMONS. YOU WONDER\n"\ + "WHO THE INMATES OF THIS CORNER OF HELL\n"\ + "WILL BE." + + +/* Before level 32, put this: */ + +#define C6TEXT \ + "CONGRATULATIONS, YOU'VE FOUND THE\n"\ + "SUPER SECRET LEVEL! YOU'D BETTER\n"\ + "BLAZE THROUGH THIS ONE!\n" + +/*** Plutonia ***/ +/* after map 06 */ + +#define P1TEXT \ + "You gloat over the steaming carcass of the\n"\ + "Guardian. With its death, you've wrested\n"\ + "the Accelerator from the stinking claws\n"\ + "of Hell. You relax and glance around the\n"\ + "room. Damn! There was supposed to be at\n"\ + "least one working prototype, but you can't\n"\ + "see it. The demons must have taken it.\n"\ + "\n"\ + "You must find the prototype, or all your\n"\ + "struggles will have been wasted. Keep\n"\ + "moving, keep fighting, keep killing.\n"\ + "Oh yes, keep living, too." + + +/* after map 11 */ + +#define P2TEXT \ + "Even the deadly Arch-Vile labyrinth could\n"\ + "not stop you, and you've gotten to the\n"\ + "prototype Accelerator which is soon\n"\ + "efficiently and permanently deactivated.\n"\ + "\n"\ + "You're good at that kind of thing." + + +/* after map 20 */ + +#define P3TEXT \ + "You've bashed and battered your way into\n"\ + "the heart of the devil-hive. Time for a\n"\ + "Search-and-Destroy mission, aimed at the\n"\ + "Gatekeeper, whose foul offspring is\n"\ + "cascading to Earth. Yeah, he's bad. But\n"\ + "you know who's worse!\n"\ + "\n"\ + "Grinning evilly, you check your gear, and\n"\ + "get ready to give the bastard a little Hell\n"\ + "of your own making!" + +/* after map 30 */ + +#define P4TEXT \ + "The Gatekeeper's evil face is splattered\n"\ + "all over the place. As its tattered corpse\n"\ + "collapses, an inverted Gate forms and\n"\ + "sucks down the shards of the last\n"\ + "prototype Accelerator, not to mention the\n"\ + "few remaining demons. You're done. Hell\n"\ + "has gone back to pounding bad dead folks \n"\ + "instead of good live ones. Remember to\n"\ + "tell your grandkids to put a rocket\n"\ + "launcher in your coffin. If you go to Hell\n"\ + "when you die, you'll need it for some\n"\ + "final cleaning-up ..." + +/* before map 31 */ + +#define P5TEXT \ + "You've found the second-hardest level we\n"\ + "got. Hope you have a saved game a level or\n"\ + "two previous. If not, be prepared to die\n"\ + "aplenty. For master marines only." + +/* before map 32 */ + +#define P6TEXT \ + "Betcha wondered just what WAS the hardest\n"\ + "level we had ready for ya? Now you know.\n"\ + "No one gets out alive." + +/*** TNT: Evilution ***/ + +#define T1TEXT \ + "You've fought your way out of the infested\n"\ + "experimental labs. It seems that UAC has\n"\ + "once again gulped it down. With their\n"\ + "high turnover, it must be hard for poor\n"\ + "old UAC to buy corporate health insurance\n"\ + "nowadays..\n"\ + "\n"\ + "Ahead lies the military complex, now\n"\ + "swarming with diseased horrors hot to get\n"\ + "their teeth into you. With luck, the\n"\ + "complex still has some warlike ordnance\n"\ + "laying around." + + +#define T2TEXT \ + "You hear the grinding of heavy machinery\n"\ + "ahead. You sure hope they're not stamping\n"\ + "out new hellspawn, but you're ready to\n"\ + "ream out a whole herd if you have to.\n"\ + "They might be planning a blood feast, but\n"\ + "you feel about as mean as two thousand\n"\ + "maniacs packed into one mad killer.\n"\ + "\n"\ + "You don't plan to go down easy." + + +#define T3TEXT \ + "The vista opening ahead looks real damn\n"\ + "familiar. Smells familiar, too -- like\n"\ + "fried excrement. You didn't like this\n"\ + "place before, and you sure as hell ain't\n"\ + "planning to like it now. The more you\n"\ + "brood on it, the madder you get.\n"\ + "Hefting your gun, an evil grin trickles\n"\ + "onto your face. Time to take some names." + +#define T4TEXT \ + "Suddenly, all is silent, from one horizon\n"\ + "to the other. The agonizing echo of Hell\n"\ + "fades away, the nightmare sky turns to\n"\ + "blue, the heaps of monster corpses start \n"\ + "to evaporate along with the evil stench \n"\ + "that filled the air. Jeeze, maybe you've\n"\ + "done it. Have you really won?\n"\ + "\n"\ + "Something rumbles in the distance.\n"\ + "A blue light begins to glow inside the\n"\ + "ruined skull of the demon-spitter." + + +#define T5TEXT \ + "What now? Looks totally different. Kind\n"\ + "of like King Tut's condo. Well,\n"\ + "whatever's here can't be any worse\n"\ + "than usual. Can it? Or maybe it's best\n"\ + "to let sleeping gods lie.." + + +#define T6TEXT \ + "Time for a vacation. You've burst the\n"\ + "bowels of hell and by golly you're ready\n"\ + "for a break. You mutter to yourself,\n"\ + "Maybe someone else can kick Hell's ass\n"\ + "next time around. Ahead lies a quiet town,\n"\ + "with peaceful flowing water, quaint\n"\ + "buildings, and presumably no Hellspawn.\n"\ + "\n"\ + "As you step off the transport, you hear\n"\ + "the stomp of a cyberdemon's iron shoe." + + + +/* + * Character cast strings F_FINALE.C + */ +#define CC_ZOMBIE "ZOMBIEMAN" +#define CC_SHOTGUN "SHOTGUN GUY" +#define CC_HEAVY "HEAVY WEAPON DUDE" +#define CC_IMP "IMP" +#define CC_DEMON "DEMON" +#define CC_LOST "LOST SOUL" +#define CC_CACO "CACODEMON" +#define CC_HELL "HELL KNIGHT" +#define CC_BARON "BARON OF HELL" +#define CC_ARACH "ARACHNOTRON" +#define CC_PAIN "PAIN ELEMENTAL" +#define CC_REVEN "REVENANT" +#define CC_MANCU "MANCUBUS" +#define CC_ARCH "ARCH-VILE" +#define CC_SPIDER "THE SPIDER MASTERMIND" +#define CC_CYBER "THE CYBERDEMON" +#define CC_HERO "OUR HERO" + + +#endif diff --git a/common/prboom/d_event.h b/common/prboom/d_event.h new file mode 100755 index 0000000..da5e702 --- /dev/null +++ b/common/prboom/d_event.h @@ -0,0 +1,125 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Event information structures. + * + *-----------------------------------------------------------------------------*/ + + +#ifndef __D_EVENT__ +#define __D_EVENT__ + + +#include "doomtype.h" + + +// +// Event handling. +// + +// Input event types. +typedef enum +{ + ev_keydown, + ev_keyup, + ev_mouse, + ev_joystick +} evtype_t; + +// Event structure. +typedef struct +{ + evtype_t type; + int data1; // keys / mouse/joystick buttons + int data2; // mouse/joystick x move + int data3; // mouse/joystick y move +} event_t; + + +typedef enum +{ + ga_nothing, + ga_loadlevel, + ga_newgame, + ga_loadgame, + ga_savegame, + ga_playdemo, + ga_completed, + ga_victory, + ga_worlddone, +} gameaction_t; + + + +// +// Button/action code definitions. +// +typedef enum +{ + // Press "Fire". + BT_ATTACK = 1, + + // Use button, to open doors, activate switches. + BT_USE = 2, + + // Flag: game events, not really buttons. + BT_SPECIAL = 128, + BT_SPECIALMASK = 3, + + // Flag, weapon change pending. + // If true, the next 4 bits hold weapon num. + BT_CHANGE = 4, + + // The 4bit weapon mask and shift, convenience. +//BT_WEAPONMASK = (8+16+32), + BT_WEAPONMASK = (8+16+32+64), // extended to pick up SSG // phares + BT_WEAPONSHIFT = 3, + + // Special events + BTS_LOADGAME = 0, // Loads a game + // Pause the game. + BTS_PAUSE = 1, + // Save the game at each console. + BTS_SAVEGAME = 2, + BTS_RESTARTLEVEL= 3, // Restarts the current level + + // Savegame slot numbers occupy the second byte of buttons. + BTS_SAVEMASK = (4+8+16), + BTS_SAVESHIFT = 2, + +} buttoncode_t; + + +// +// GLOBAL VARIABLES +// + +extern gameaction_t gameaction; + +#endif diff --git a/common/prboom/d_ipxgate.c b/common/prboom/d_ipxgate.c new file mode 100755 index 0000000..aad28b6 --- /dev/null +++ b/common/prboom/d_ipxgate.c @@ -0,0 +1,291 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "protocol.h" + +#define BACKUPTICS 12 +#define NCMD_EXIT 0x80000000 +#define NCMD_RETRANSMIT 0x40000000 +#define NCMD_SETUP 0x20000000 +#define NCMD_KILL 0x10000000 // kill game +#define NCMD_CHECKSUM 0x0fffffff + +typedef struct +{ + short gameid; // so multiple games can setup at once + short drone; + short nodesfound; + short nodeswanted; +} setupdata_t; + +typedef struct +a +{ + // High bit is retransmit request. + unsigned checksum; + // Only valid if NCMD_RETRANSMIT. + byte retransmitfrom; + + byte starttic; + byte player; + byte numtics; + ticcmd_t cmds[BACKUPTICS]; +} doomdata_t; + +typedef struct +{ + signed int tic; + union altu { + setupdata_t s; + unsigned char data[100]; + doomdata_t d; + } u; +} ipxpacket_t; + +int nodes; + +unsigned short port = 0x869b; + +int ipx_socket(void) { + int s = socket(PF_IPX,SOCK_DGRAM,0); + struct sockaddr_ipx sa; + if (s == -1) { + fprintf(stderr,"socket(PF_PIPX): %s\n",strerror(errno)); + exit(-1); + } + memset(&sa,0,sizeof(sa)); + memset(sa.sipx_node,0xff,sizeof(sa.sipx_node)); + sa.sipx_port = htons(port); + if (bind(s,(struct sockaddr*)&sa,sizeof(sa)) == -1) { + fprintf(stderr,"bind(%d): %s\n",port,strerror(errno)); + exit(-1); + } + return s; +} + +int udp_socket(const char* ip) { + struct sockaddr_in sa; + int s = socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP); + + if (s == -1) { + fprintf(stderr,"socket(PF_INET): %s\n", strerror(errno)); + exit(-1); + } + sa.sin_family=PF_INET; + inet_aton(ip,&sa.sin_addr); + sa.sin_port = htons(5030); + + if (connect(s,(struct sockaddr*)&sa,sizeof sa) == -1) { + fprintf(stderr,"connect(%s:%d): %s\n", ip, 5030, strerror(errno)); + exit(-1); + } + return s; +} + +static byte ChecksumPacket(const packet_header_t* buffer, size_t len) +{ + const byte* p = (void*)buffer; + byte sum = 0; + + if (len==0) + return 0; + + while (p++, --len) + sum += *p; + + return sum; +} + +// +// Checksum +// +unsigned NetbufferChecksum (void* p, size_t l) +{ + unsigned c; + + c = 0x1234567; + + l = l/4; + for (int i=0 ; i= -64 && delta <= 64) + return (maketic&~0xff) + low; + if (delta > 64) + return (maketic&~0xff) - 256 + low; + if (delta < -64) + return (maketic&~0xff) + 256 + low; + fprintf(stderr,"ExpandTics strange value %i at maketic %i\n",low,maketic); + exit(-2); +} + +void send_udp_packet(enum packet_type_e type, unsigned tic, void* data, size_t len) { + packet_header_t* p = calloc(sizeof(packet_header_t)+len+1,1); + p->tic = doom_htonl(basetic = tic); p->type = type; + if (!data) { + data = (void*)&consoleplayer; len = 1; + } + memcpy(((char*)p)+sizeof(*p),data,len); + p->checksum = ChecksumPacket(p,sizeof(packet_header_t)+len); + write(udps,p,sizeof(packet_header_t)+len+1); +} + +int connected; +int ipxcounter; + +void ipx_receive(int s) { + ipxpacket_t buf; + int rc; + struct sockaddr from; + size_t sl = sizeof(from); + rc = recvfrom(s,&buf,sizeof buf,0,&from,&sl); + if (rc == -1) { + fprintf(stderr,"read(ipx): %s\n", strerror(errno)); + exit(-2); + } + if (rc > 0) { + if (buf.tic == -1) { + // Setup packet + if (!connected++) { + connect(s,&from,sl); + send_udp_packet(PKT_INIT,0,NULL,0); + } + } else { + if (buf.u.d.checksum & NCMD_SETUP) { + printf("setup packet, dropped\n"); + } else if (buf.u.d.checksum & NCMD_EXIT) { + send_udp_packet(PKT_QUIT,buf.u.d.starttic,NULL,0); + exit(0); + } else if ((buf.u.d.checksum & NCMD_CHECKSUM) == buf.u.d.checksum) { + // No flags, normal game packet + char outbuf[100]; + int tics; + outbuf[0] = tics = buf.u.d.numtics; + outbuf[1] = buf.u.d.player; + for (int i=0; i< tics; i++) + TicToRaw(outbuf+2+i*sizeof(ticcmd_t),&buf.u.d.cmds[i]); + send_udp_packet(PKT_TICC, ExpandTics(buf.u.d.starttic, basetic), outbuf, 2+tics*sizeof(ticcmd_t)); + } + } + } +} + +void udp_receive(int s) { + size_t len = 1024; + packet_header_t *p = malloc(len); + int rc; + + rc = read(s,p,len); + if (rc < 0) { + fprintf(stderr,"read(udp): %s\n", strerror(errno)); + exit(-2); + } + if (rc > 0) { + switch (p->type) { + case PKT_SETUP: + { + struct setup_packet_s *sinfo = (void*)(p+1); + consoleplayer = sinfo->yourplayer; + send_udp_packet(PKT_GO,0,NULL,0); + write(ipxs,"\xff\xff\xff\xff\x00\x00\x00\x00\x02\x00\x02\x00\x00\x00\x00\x00",16); + } + break; + case PKT_GO: + { + ipxpacket_t pkt; + memset(&pkt,0,sizeof(pkt)); + pkt.tic = ipxcounter++; + pkt.u.d.player = consoleplayer^1; + pkt.u.d.starttic = 0; + pkt.u.d.numtics = 0; + pkt.u.d.retransmitfrom = 0; + pkt.u.d.checksum = NetbufferChecksum(&pkt.u.d.retransmitfrom, 4); + write(ipxs,&pkt,16); + } + break; + case PKT_TICS: + { + ipxpacket_t pkt; + int tic = doom_ntohl(p->tic); + byte *pp = (void*)(p+1); + int tics = *pp++; + memset(&pkt,0,sizeof(pkt)); + size_t len; + + pkt.tic = ipxcounter++; + pkt.u.d.starttic = tic; + pkt.u.d.player = (consoleplayer == 0 ? 1 : 0); + pkt.u.d.numtics = tics; + + for (int t=0; t0) { + if (FD_ISSET(ipxs,&fds)) + ipx_receive(ipxs); + if (FD_ISSET(udps,&fds)) + udp_receive(udps); + } + } +} + +int main(int argc, char**argv) { + ipxs = ipx_socket(); + udps = udp_socket(argv[1]); + loop(ipxs,udps); + return 0; +} + diff --git a/common/prboom/d_items.c b/common/prboom/d_items.c new file mode 100755 index 0000000..5adc28d --- /dev/null +++ b/common/prboom/d_items.c @@ -0,0 +1,140 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Something to do with weapon sprite frames. Don't ask me. + * + *----------------------------------------------------------------------------- + */ + +// We are referring to sprite numbers. +#include "doomtype.h" +#include "info.h" + +#ifdef __GNUG__ +#pragma implementation "d_items.h" +#endif +#include "d_items.h" + + +// +// PSPRITE ACTIONS for waepons. +// This struct controls the weapon animations. +// +// Each entry is: +// ammo/amunition type +// upstate +// downstate +// readystate +// atkstate, i.e. attack/fire/hit frame +// flashstate, muzzle flash +// +weaponinfo_t weaponinfo[NUMWEAPONS] = +{ + { + // fist + am_noammo, + S_PUNCHUP, + S_PUNCHDOWN, + S_PUNCH, + S_PUNCH1, + S_NULL + }, + { + // pistol + am_clip, + S_PISTOLUP, + S_PISTOLDOWN, + S_PISTOL, + S_PISTOL1, + S_PISTOLFLASH + }, + { + // shotgun + am_shell, + S_SGUNUP, + S_SGUNDOWN, + S_SGUN, + S_SGUN1, + S_SGUNFLASH1 + }, + { + // chaingun + am_clip, + S_CHAINUP, + S_CHAINDOWN, + S_CHAIN, + S_CHAIN1, + S_CHAINFLASH1 + }, + { + // missile launcher + am_misl, + S_MISSILEUP, + S_MISSILEDOWN, + S_MISSILE, + S_MISSILE1, + S_MISSILEFLASH1 + }, + { + // plasma rifle + am_cell, + S_PLASMAUP, + S_PLASMADOWN, + S_PLASMA, + S_PLASMA1, + S_PLASMAFLASH1 + }, + { + // bfg 9000 + am_cell, + S_BFGUP, + S_BFGDOWN, + S_BFG, + S_BFG1, + S_BFGFLASH1 + }, + { + // chainsaw + am_noammo, + S_SAWUP, + S_SAWDOWN, + S_SAW, + S_SAW1, + S_NULL + }, + { + // super shotgun + am_shell, + S_DSGUNUP, + S_DSGUNDOWN, + S_DSGUN, + S_DSGUN1, + S_DSGUNFLASH1 + }, +}; diff --git a/common/prboom/d_items.h b/common/prboom/d_items.h new file mode 100755 index 0000000..766f9f4 --- /dev/null +++ b/common/prboom/d_items.h @@ -0,0 +1,56 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Items: key cards, artifacts, weapon, ammunition. + * + *-----------------------------------------------------------------------------*/ + + +#ifndef __D_ITEMS__ +#define __D_ITEMS__ + +#include "doomdef.h" + + + +/* Weapon info: sprite frames, ammunition use. */ +typedef struct +{ + ammotype_t ammo; + int upstate; + int downstate; + int readystate; + int atkstate; + int flashstate; + +} weaponinfo_t; + +extern weaponinfo_t weaponinfo[NUMWEAPONS]; + +#endif diff --git a/common/prboom/d_main.c b/common/prboom/d_main.c new file mode 100755 index 0000000..1ffaa27 --- /dev/null +++ b/common/prboom/d_main.c @@ -0,0 +1,1764 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2004 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * DOOM main program (D_DoomMain) and game loop (D_DoomLoop), + * plus functions to determine game mode (shareware, registered), + * parse command line parameters, configure game parameters (turbo), + * and call the startup functions. + * + *----------------------------------------------------------------------------- + */ + + +#ifdef _MSC_VER +#define F_OK 0 /* Check for file existence */ +#define W_OK 2 /* Check for write permission */ +#define R_OK 4 /* Check for read permission */ +#include +#include +#else +#include +#endif +#include +#include +#include + +#include "doomdef.h" +#include "doomtype.h" +#include "doomstat.h" +#include "d_net.h" +#include "dstrings.h" +#include "sounds.h" +#include "z_zone.h" +#include "w_wad.h" +#include "s_sound.h" +#include "v_video.h" +#include "f_finale.h" +#include "f_wipe.h" +#include "m_argv.h" +#include "m_misc.h" +#include "m_menu.h" +#include "p_checksum.h" +#include "i_main.h" +#include "i_system.h" +#include "i_sound.h" +#include "i_video.h" +#include "g_game.h" +#include "hu_stuff.h" +#include "wi_stuff.h" +#include "st_stuff.h" +#include "am_map.h" +#include "p_setup.h" +#include "r_draw.h" +#include "r_main.h" +#include "r_fps.h" +#include "d_main.h" +#include "d_deh.h" // Ty 04/08/98 - Externalizations +#include "lprintf.h" // jff 08/03/98 - declaration of lprintf +#include "am_map.h" + +void GetFirstMap(int *ep, int *map); // Ty 08/29/98 - add "-warp x" functionality +static void D_PageDrawer(void); + +// CPhipps - removed wadfiles[] stuff + +boolean devparm; // started game with -devparm + +// jff 1/24/98 add new versions of these variables to remember command line +boolean clnomonsters; // checkparm of -nomonsters +boolean clrespawnparm; // checkparm of -respawn +boolean clfastparm; // checkparm of -fast +// jff 1/24/98 end definition of command line version of play mode switches + +boolean nomonsters; // working -nomonsters +boolean respawnparm; // working -respawn +boolean fastparm; // working -fast + +boolean singletics = false; // debug flag to cancel adaptiveness + +//jff 1/22/98 parms for disabling music and sound +boolean nosfxparm; +boolean nomusicparm; + +//jff 4/18/98 +extern boolean inhelpscreens; + +skill_t startskill; +int startepisode; +int startmap; +boolean autostart; +FILE *debugfile; +int ffmap; + +boolean advancedemo; + +char wadfile[PATH_MAX+1]; // primary wad file +char mapdir[PATH_MAX+1]; // directory of development maps +char baseiwad[PATH_MAX+1]; // jff 3/23/98: iwad directory +char basesavegame[PATH_MAX+1]; // killough 2/16/98: savegame directory + +//jff 4/19/98 list of standard IWAD names +const char *const standard_iwads[]= +{ + "doom2f.wad", + "doom2.wad", + "plutonia.wad", + "tnt.wad", + "doom.wad", + "doom1.wad", + "doomu.wad", /* CPhipps - alow doomu.wad */ + "freedoom.wad", /* wart@kobold.org: added freedoom for Fedora Extras */ +}; +static const int nstandard_iwads = sizeof standard_iwads/sizeof*standard_iwads; + +/* + * D_PostEvent - Event handling + * + * Called by I/O functions when an event is received. + * Try event handlers for each code area in turn. + * cph - in the true spirit of the Boom source, let the + * short ciruit operator madness begin! + */ + +void D_PostEvent(event_t *ev) +{ + /* cph - suppress all input events at game start + * FIXME: This is a lousy kludge */ + if (gametic < 3) return; + M_Responder(ev) || + (gamestate == GS_LEVEL && ( + HU_Responder(ev) || + ST_Responder(ev) || + AM_Responder(ev) + ) + ) || + G_Responder(ev); +} + +// +// D_Wipe +// +// CPhipps - moved the screen wipe code from D_Display to here +// The screens to wipe between are already stored, this just does the timing +// and screen updating + +static void D_Wipe(void) +{ + boolean done; + int wipestart = I_GetTime () - 1; + + do + { + int nowtime, tics; + do + { + I_uSleep(5000); // CPhipps - don't thrash cpu in this loop + nowtime = I_GetTime(); + tics = nowtime - wipestart; + } + while (!tics); + wipestart = nowtime; + done = wipe_ScreenWipe(tics); + I_UpdateNoBlit(); + M_Drawer(); // menu is drawn even on top of wipes + I_FinishUpdate(); // page flip or blit buffer + } + while (!done); +} + +// +// D_Display +// draw current display, possibly wiping it from the previous +// + +// wipegamestate can be set to -1 to force a wipe on the next draw +gamestate_t wipegamestate = GS_DEMOSCREEN; +extern boolean setsizeneeded; +extern int showMessages; + +void D_Display (void) +{ + static boolean inhelpscreensstate = false; + static boolean isborderstate = false; + static boolean borderwillneedredraw = false; + static gamestate_t oldgamestate = -1; + boolean wipe; + boolean viewactive = false, isborder = false; + + if (nodrawers) // for comparative timing / profiling + return; + + if (!I_StartDisplay()) + return; + + // save the current screen if about to wipe + if ((wipe = gamestate != wipegamestate) && (V_GetMode() != VID_MODEGL)) + wipe_StartScreen(); + + if (gamestate != GS_LEVEL) { // Not a level + switch (oldgamestate) { + case -1: + case GS_LEVEL: + V_SetPalette(0); // cph - use default (basic) palette + default: + break; + } + + switch (gamestate) { + case GS_INTERMISSION: + WI_Drawer(); + break; + case GS_FINALE: + F_Drawer(); + break; + case GS_DEMOSCREEN: + D_PageDrawer(); + break; + default: + break; + } + } else if (gametic != basetic) { // In a level + boolean redrawborderstuff; + + HU_Erase(); + + if (setsizeneeded) { // change the view size if needed + R_ExecuteSetViewSize(); + oldgamestate = -1; // force background redraw + } + + // Work out if the player view is visible, and if there is a border + viewactive = (!(automapmode & am_active) || (automapmode & am_overlay)) && !inhelpscreens; + isborder = viewactive ? (viewheight != SCREENHEIGHT) : (!inhelpscreens && (automapmode & am_active)); + + if (oldgamestate != GS_LEVEL) { + R_FillBackScreen (); // draw the pattern into the back screen + redrawborderstuff = isborder; + } else { + // CPhipps - + // If there is a border, and either there was no border last time, + // or the border might need refreshing, then redraw it. + redrawborderstuff = isborder && (!isborderstate || borderwillneedredraw); + // The border may need redrawing next time if the border surrounds the screen, + // and there is a menu being displayed + borderwillneedredraw = menuactive && isborder && viewactive && (viewwidth != SCREENWIDTH); + } + if (redrawborderstuff || (V_GetMode() == VID_MODEGL)) + R_DrawViewBorder(); + + // Now do the drawing + if (viewactive) { + if ( testNewRenderer ) { // JDC + IR_RenderPlayerView (&players[displayplayer]); + } else { + R_RenderPlayerView (&players[displayplayer]); + } + } + if (automapmode & am_active) { + AM_Drawer(); + } + ST_Drawer((viewheight != SCREENHEIGHT) || ((automapmode & am_active) && !(automapmode & am_overlay)), redrawborderstuff); + if (V_GetMode() != VID_MODEGL) + R_DrawViewBorder(); + HU_Drawer(); + } + + inhelpscreensstate = inhelpscreens; + isborderstate = isborder; + oldgamestate = wipegamestate = gamestate; + + // draw pause pic + if (paused) { + // Simplified the "logic" here and no need for x-coord caching - POPE + V_DrawNamePatch((320 - V_NamePatchWidth("M_PAUSE"))/2, 4, + 0, "M_PAUSE", CR_DEFAULT, VPT_STRETCH); + } + + // menus go directly to the screen + M_Drawer(); // menu is drawn even on top of everything +#ifdef HAVE_NET + NetUpdate(); // send out any new accumulation +#else + D_BuildNewTiccmds(); +#endif + + // normal update + if (!wipe || (V_GetMode() == VID_MODEGL)) + I_FinishUpdate (); // page flip or blit buffer + else { + // wipe update + wipe_EndScreen(); + D_Wipe(); + } + + I_EndDisplay(); + + //e6y: don't thrash cpu during pausing + if (paused) { + I_uSleep(1000); + } +} + +// CPhipps - Auto screenshot Variables + +static int auto_shot_count, auto_shot_time; +static const char *auto_shot_fname; + +// +// D_DoomLoop() +// +// Not a globally visible function, +// just included for source reference, +// called by D_DoomMain, never exits. +// Manages timing and IO, +// calls all ?_Responder, ?_Ticker, and ?_Drawer, +// calls I_GetTime, I_StartFrame, and I_StartTic +// + +// This function is unused on iOS. +#ifndef IPHONE +static void D_DoomLoop(void) +{ + for (;;) + { + WasRenderedInTryRunTics = false; + // frame syncronous IO operations + I_StartFrame (); + + if (ffmap == gamemap) ffmap = 0; + + // process one or more tics + if (singletics) + { + I_StartTic (); + G_BuildTiccmd (&netcmds[consoleplayer][maketic%BACKUPTICS]); + if (advancedemo) + D_DoAdvanceDemo (); + M_Ticker (); + G_Ticker (); + P_Checksum(gametic); + gametic++; + maketic++; + } + else + TryRunTics (); // will run at least one tic + + // killough 3/16/98: change consoleplayer to displayplayer + if (players[displayplayer].mo) // cph 2002/08/10 + S_UpdateSounds(players[displayplayer].mo);// move positional sounds + + if (V_GetMode() == VID_MODEGL ? + !movement_smooth || !WasRenderedInTryRunTics : + !movement_smooth || !WasRenderedInTryRunTics || gamestate != wipegamestate + ) + { + // Update display, next frame, with current state. + D_Display(); + } + + // CPhipps - auto screenshot + if (auto_shot_fname && !--auto_shot_count) { + auto_shot_count = auto_shot_time; + M_DoScreenShot(auto_shot_fname); + } + } +} +#endif + +// +// DEMO LOOP +// + +static int demosequence; // killough 5/2/98: made static +static int pagetic; +static const char *pagename; // CPhipps - const + +// +// D_PageTicker +// Handles timing for warped projection +// +void D_PageTicker(void) +{ + if (--pagetic < 0) + D_AdvanceDemo(); +} + +// +// D_PageDrawer +// +static void D_PageDrawer(void) +{ + // proff/nicolas 09/14/98 -- now stretchs bitmaps to fullscreen! + // CPhipps - updated for new patch drawing + // proff - added M_DrawCredits + if (pagename) + { + V_DrawNamePatch(0, 0, 0, pagename, CR_DEFAULT, VPT_STRETCH); + } + else + M_DrawCredits(); +} + +// +// D_AdvanceDemo +// Called after each demo or intro demosequence finishes +// +void D_AdvanceDemo (void) +{ + advancedemo = true; +} + +/* killough 11/98: functions to perform demo sequences + * cphipps 10/99: constness fixes + */ + +static void D_SetPageName(const char *name) +{ + pagename = name; +} + +static void D_DrawTitle1(const char *name) +{ + S_StartMusic(mus_intro); + pagetic = (TICRATE*170)/35; + D_SetPageName(name); +} + +static void D_DrawTitle2(const char *name) +{ + S_StartMusic(mus_dm2ttl); + D_SetPageName(name); +} + +/* killough 11/98: tabulate demo sequences + */ + +static struct +{ + void (*func)(const char *); + const char *name; +} const demostates[][4] = + { + { + {D_DrawTitle1, "TITLEPIC"}, + {D_DrawTitle1, "TITLEPIC"}, + {D_DrawTitle2, "TITLEPIC"}, + {D_DrawTitle1, "TITLEPIC"}, + }, + + { + {G_DeferedPlayDemo, "demo1"}, + {G_DeferedPlayDemo, "demo1"}, + {G_DeferedPlayDemo, "demo1"}, + {G_DeferedPlayDemo, "demo1"}, + }, + { + {D_SetPageName, NULL}, + {D_SetPageName, NULL}, + {D_SetPageName, NULL}, + {D_SetPageName, NULL}, + }, + + { + {G_DeferedPlayDemo, "demo2"}, + {G_DeferedPlayDemo, "demo2"}, + {G_DeferedPlayDemo, "demo2"}, + {G_DeferedPlayDemo, "demo2"}, + }, + + { + {D_SetPageName, "HELP2"}, + {D_SetPageName, "HELP2"}, + {D_SetPageName, "CREDIT"}, + {D_DrawTitle1, "TITLEPIC"}, + }, + + { + {G_DeferedPlayDemo, "demo3"}, + {G_DeferedPlayDemo, "demo3"}, + {G_DeferedPlayDemo, "demo3"}, + {G_DeferedPlayDemo, "demo3"}, + }, + + { + {NULL, NULL}, + {NULL, NULL}, + {NULL, NULL}, + {D_SetPageName, "CREDIT"}, + }, + + { + {NULL, NULL}, + {NULL, NULL}, + {NULL, NULL}, + {G_DeferedPlayDemo, "demo4"}, + }, + + { + {NULL, NULL}, + {NULL, NULL}, + {NULL, NULL}, + {NULL, NULL}, + } + }; + +/* + * This cycles through the demo sequences. + * killough 11/98: made table-driven + */ + +void D_DoAdvanceDemo(void) +{ + players[consoleplayer].playerstate = PST_LIVE; /* not reborn */ + advancedemo = usergame = paused = false; + gameaction = ga_nothing; + + pagetic = TICRATE * 11; /* killough 11/98: default behavior */ + gamestate = GS_DEMOSCREEN; + + if (netgame && !demoplayback) { + demosequence = 0; + } else + if (!demostates[++demosequence][gamemode].func) + demosequence = 0; + demostates[demosequence][gamemode].func + (demostates[demosequence][gamemode].name); +} + +// +// D_StartTitle +// +void D_StartTitle (void) +{ + gameaction = ga_nothing; + demosequence = -1; + D_AdvanceDemo(); +} + +// +// D_AddFile +// +// Rewritten by Lee Killough +// +// Ty 08/29/98 - add source parm to indicate where this came from +// CPhipps - static, const char* parameter +// - source is an enum +// - modified to allocate & use new wadfiles array +void D_AddFile (const char *file, wad_source_t source) +{ + char *gwa_filename=NULL; + + wadfiles = realloc(wadfiles, sizeof(*wadfiles)*(numwadfiles+1)); + wadfiles[numwadfiles].name = + AddDefaultExtension(strcpy(malloc(strlen(file)+5), file), ".wad"); + wadfiles[numwadfiles].src = source; // Ty 08/29/98 + numwadfiles++; + // proff: automatically try to add the gwa files + // proff - moved from w_wad.c + gwa_filename=AddDefaultExtension(strcpy(malloc(strlen(file)+5), file), ".wad"); + if (strlen(gwa_filename)>4) + if (!strcasecmp(gwa_filename+(strlen(gwa_filename)-4),".wad")) + { + char *ext; + ext = &gwa_filename[strlen(gwa_filename)-4]; + ext[1] = 'g'; ext[2] = 'w'; ext[3] = 'a'; + wadfiles = realloc(wadfiles, sizeof(*wadfiles)*(numwadfiles+1)); + wadfiles[numwadfiles].name = gwa_filename; + wadfiles[numwadfiles].src = source; // Ty 08/29/98 + numwadfiles++; + } +} + +// killough 10/98: support -dehout filename +// cph - made const, don't cache results +static const char *D_dehout(void) +{ + int p = M_CheckParm("-dehout"); + if (!p) + p = M_CheckParm("-bexout"); + return (p && ++p < myargc ? myargv[p] : NULL); +} + +// +// CheckIWAD +// +// Verify a file is indeed tagged as an IWAD +// Scan its lumps for levelnames and return gamemode as indicated +// Detect missing wolf levels in DOOM II +// +// The filename to check is passed in iwadname, the gamemode detected is +// returned in gmode, hassec returns the presence of secret levels +// +// jff 4/19/98 Add routine to test IWAD for validity and determine +// the gamemode from it. Also note if DOOM II, whether secret levels exist +// CPhipps - const char* for iwadname, made static +static void CheckIWAD(const char *iwadname,GameMode_t *gmode,boolean *hassec) +{ + if ( !access (iwadname,R_OK) ) + { + int ud=0,rg=0,sw=0,cm=0,sc=0; + FILE* fp; + + // Identify IWAD correctly + if ((fp = fopen(iwadname, "rb"))) + { + wadinfo_t header; + + // read IWAD header + if (fread(&header, sizeof(header), 1, fp) == 1 && !strncmp(header.identification, "IWAD", 4)) + { + size_t length; + filelump_t *fileinfo; + + // read IWAD directory + header.numlumps = LONG(header.numlumps); + header.infotableofs = LONG(header.infotableofs); + length = header.numlumps; + fileinfo = malloc(length*sizeof(filelump_t)); + if (fseek (fp, header.infotableofs, SEEK_SET) || + fread (fileinfo, sizeof(filelump_t), length, fp) != length || + fclose(fp)) + I_Error("CheckIWAD: failed to read directory %s",iwadname); + + // scan directory for levelname lumps + while (length--) + if (fileinfo[length].name[0] == 'E' && + fileinfo[length].name[2] == 'M' && + fileinfo[length].name[4] == 0) + { + if (fileinfo[length].name[1] == '4') + ++ud; + else if (fileinfo[length].name[1] == '3') + ++rg; + else if (fileinfo[length].name[1] == '2') + ++rg; + else if (fileinfo[length].name[1] == '1') + ++sw; + } + else if (fileinfo[length].name[0] == 'M' && + fileinfo[length].name[1] == 'A' && + fileinfo[length].name[2] == 'P' && + fileinfo[length].name[5] == 0) + { + ++cm; + if (fileinfo[length].name[3] == '3') + if (fileinfo[length].name[4] == '1' || + fileinfo[length].name[4] == '2') + ++sc; + } + + free(fileinfo); + } + else // missing IWAD tag in header + I_Error("CheckIWAD: IWAD tag %s not present", iwadname); + } + else // error from open call + I_Error("CheckIWAD: Can't open IWAD %s", iwadname); + + // Determine game mode from levels present + // Must be a full set for whichever mode is present + // Lack of wolf-3d levels also detected here + + *gmode = indetermined; + *hassec = false; + if (cm>=30) + { + *gmode = commercial; + *hassec = sc>=2; + } + else if (ud>=9) + *gmode = retail; + else if (rg>=18) + *gmode = registered; + else if (sw>=9) + *gmode = shareware; + } + else // error from access call + I_Error("CheckIWAD: IWAD %s not readable", iwadname); +} + + + +// NormalizeSlashes +// +// Remove trailing slashes, translate backslashes to slashes +// The string to normalize is passed and returned in str +// +// jff 4/19/98 Make killoughs slash fixer a subroutine +// +static void NormalizeSlashes(char *str) +{ + int l; + + // killough 1/18/98: Neater / \ handling. + // Remove trailing / or \ to prevent // /\ \/ \\, and change \ to / + + if (!str || !(l = strlen(str))) + return; + if (str[--l]=='/' || str[l]=='\\') // killough 1/18/98 + str[l]=0; + while (l--) + if (str[l]=='\\') + str[l]='/'; +} + +/* + * FindIWADFIle + * + * Search for one of the standard IWADs + * CPhipps - static, proper prototype + * - 12/1999 - rewritten to use I_FindFile + */ +// TODO: We may restore this function later, if we send in iwad selection as a "parameter" +// in order to remain closer to vanilla prboom. +#ifndef IPHONE +static char *FindIWADFile(void) +{ + int i; + char * iwad = NULL; + + i = M_CheckParm("-iwad"); + if (i && (++i < myargc)) { + iwad = I_FindFile(myargv[i], ".wad"); + } else { + for (i=0; !iwad && i PATH_MAX-12) p = NULL; + + strcpy(basesavegame,(p == NULL) ? I_DoomExeDir() : p); + } + if ((i=M_CheckParm("-save")) && i=10 && !strnicmp(iwad+i-10,"doom2f.wad",10)) + language=french; + else if (i>=7 && !strnicmp(iwad+i-7,"tnt.wad",7)) + gamemission = pack_tnt; + else if (i>=12 && !strnicmp(iwad+i-12,"plutonia.wad",12)) + gamemission = pack_plut; + break; + default: + gamemission = none; + break; + } + if (gamemode == indetermined) + //jff 9/3/98 use logical output routine + lprintf(LO_WARN,"Unknown Game Version, may not work\n"); + D_AddFile(iwad,source_iwad); + + //free(iwad); + } + else + I_Error("IdentifyVersion: IWAD not found\n"); +} + + + +// killough 5/3/98: old code removed +// +// Find a Response File +// + +#define MAXARGVS 100 + +static void FindResponseFile (void) +{ + int i; + + for (i = 1;i < myargc;i++) + if (myargv[i][0] == '@') + { + int size; + int index; + int indexinfile; + byte *file = NULL; + const char **moreargs = malloc(myargc * sizeof(const char*)); + const char **newargv; + // proff 04/05/2000: Added for searching responsefile + char fname[PATH_MAX+1]; + + strcpy(fname,&myargv[i][1]); + AddDefaultExtension(fname,".rsp"); + + // READ THE RESPONSE FILE INTO MEMORY + // proff 04/05/2000: changed for searching responsefile + // cph 2002/08/09 - use M_ReadFile for simplicity + size = M_ReadFile(fname, &file); + // proff 04/05/2000: Added for searching responsefile + if (size < 0) + { + strcat(strcpy(fname,I_DoomExeDir()),&myargv[i][1]); + AddDefaultExtension(fname,".rsp"); + size = M_ReadFile(fname, &file); + } + if (size < 0) + { + /* proff 04/05/2000: Changed from LO_FATAL + * proff 04/05/2000: Simply removed the exit(1); + * cph - made fatal, don't drop through and SEGV + */ + I_Error("No such response file: %s",fname); + } + //jff 9/3/98 use logical output routine + lprintf(LO_CONFIRM,"Found response file %s\n",fname); + // proff 04/05/2000: Added check for empty rsp file + if (size<=0) + { + int k; + lprintf(LO_ERROR,"\nResponse file empty!\n"); + + newargv = calloc(sizeof(char *),MAXARGVS); + newargv[0] = myargv[0]; + for (k = 1,index = 1;k < myargc;k++) + { + if (i!=k) + newargv[index++] = myargv[k]; + } + myargc = index; myargv = newargv; + return; + } + + // KEEP ALL CMDLINE ARGS FOLLOWING @RESPONSEFILE ARG + memcpy((void *)moreargs,&myargv[i+1],(index = myargc - i - 1) * sizeof(myargv[0])); + + { + const char *firstargv = myargv[0]; + newargv = calloc(sizeof(char *),MAXARGVS); + newargv[0] = firstargv; + } + + { + byte *infile = file; + indexinfile = 0; + indexinfile++; // SKIP PAST ARGV[0] (KEEP IT) + do { + while (size > 0 && isspace(*infile)) { infile++; size--; } + if (size > 0) { + char *s = malloc(size+1); + char *p = s; + int quoted = 0; + + while (size > 0) { + // Whitespace terminates the token unless quoted + if (!quoted && isspace(*infile)) break; + if (*infile == '\"') { + // Quotes are removed but remembered + infile++; size--; quoted ^= 1; + } else { + *p++ = *infile++; size--; + } + } + if (quoted) I_Error("Runaway quoted string in response file"); + + // Terminate string, realloc and add to argv + *p = 0; + newargv[indexinfile++] = realloc(s,strlen(s)+1); + } + } while(size > 0); + } + free(file); + + memcpy((void *)&newargv[indexinfile],moreargs,index*sizeof(moreargs[0])); + free((void *)moreargs); + + myargc = indexinfile+index; myargv = newargv; + + // DISPLAY ARGS + //jff 9/3/98 use logical output routine + lprintf(LO_CONFIRM,"%d command-line args:\n",myargc); + for (index=1;index 0) + { + tmyargv[tmyargc++] = strdup("-file"); // put the switch in + for (i=0;i 0) + { + tmyargv[tmyargc++] = strdup("-deh"); + for (i=0;i 0) + { + tmyargv[tmyargc++] = strdup("-playdemo"); + for (i=0;i 400) + scale = 400; + //jff 9/3/98 use logical output routine + lprintf (LO_CONFIRM,"turbo scale: %i%%\n",scale); + forwardmove[0] = forwardmove[0]*scale/100; + forwardmove[1] = forwardmove[1]*scale/100; + sidemove[0] = sidemove[0]*scale/100; + sidemove[1] = sidemove[1]*scale/100; + } + + modifiedgame = false; + + // get skill / episode / map from parms + + startskill = sk_none; // jff 3/24/98 was sk_medium, just note not picked + startepisode = 1; + startmap = 1; + autostart = false; + + if ((p = M_CheckParm ("-skill")) && p < myargc-1) + { + startskill = myargv[p+1][0]-'1'; + autostart = true; + } + + if ((p = M_CheckParm ("-episode")) && p < myargc-1) + { + startepisode = myargv[p+1][0]-'0'; + startmap = 1; + autostart = true; + } + + if ((p = M_CheckParm ("-timer")) && p < myargc-1 && deathmatch) + { + int time = atoi(myargv[p+1]); + //jff 9/3/98 use logical output routine + lprintf(LO_CONFIRM,"Levels will end after %d minute%s.\n", time, time>1 ? "s" : ""); + } + + if ((p = M_CheckParm ("-avg")) && p < myargc-1 && deathmatch) + //jff 9/3/98 use logical output routine + lprintf(LO_CONFIRM,"Austin Virtual Gaming: Levels will end after 20 minutes\n"); + + if ((p = M_CheckParm ("-warp")) || // killough 5/2/98 + (p = M_CheckParm ("-wart"))) + // Ty 08/29/98 - moved this check later so we can have -warp alone: && p < myargc-1) + { + startmap = 0; // Ty 08/29/98 - allow "-warp x" to go to first map in wad(s) + autostart = true; // Ty 08/29/98 - move outside the decision tree + if (gamemode == commercial) + { + if (p < myargc-1) + startmap = atoi(myargv[p+1]); // Ty 08/29/98 - add test if last parm + } + else // 1/25/98 killough: fix -warp xxx from crashing Doom 1 / UD + { + if (p < myargc-2) + { + startepisode = atoi(myargv[++p]); + startmap = atoi(myargv[p+1]); + } + } + } + // Ty 08/29/98 - later we'll check for startmap=0 and autostart=true + // as a special case that -warp * was used. Actually -warp with any + // non-numeric will do that but we'll only document "*" + + //jff 1/22/98 add command line parms to disable sound and music + { + int nosound = M_CheckParm("-nosound"); + nomusicparm = nosound || M_CheckParm("-nomusic"); + nosfxparm = nosound || M_CheckParm("-nosfx"); + } + //jff end of sound/music command line parms + + // killough 3/2/98: allow -nodraw -noblit generally + nodrawers = M_CheckParm ("-nodraw"); + noblit = M_CheckParm ("-noblit"); + + //proff 11/22/98: Added setting of viewangleoffset + p = M_CheckParm("-viewangle"); + if (p) + { + viewangleoffset = atoi(myargv[p+1]); + viewangleoffset = viewangleoffset<0 ? 0 : (viewangleoffset>7 ? 7 : viewangleoffset); + viewangleoffset = (8-viewangleoffset) * ANG45; + } + + // init subsystems + + G_ReloadDefaults(); // killough 3/4/98: set defaults just loaded. + // jff 3/24/98 this sets startskill if it was -1 + + // Video stuff + if ((p = M_CheckParm("-width"))) + if (myargv[p+1]) + desired_screenwidth = atoi(myargv[p+1]); + + if ((p = M_CheckParm("-height"))) + if (myargv[p+1]) + desired_screenheight = atoi(myargv[p+1]); + + if ((p = M_CheckParm("-fullscreen"))) + use_fullscreen = 1; + + if ((p = M_CheckParm("-nofullscreen"))) + use_fullscreen = 0; + + // e6y + // New command-line options for setting a window (-window) + // or fullscreen (-nowindow) mode temporarily which is not saved in cfg. + // It works like "-geom" switch + desired_fullscreen = use_fullscreen; + if ((p = M_CheckParm("-window"))) + desired_fullscreen = 0; + + if ((p = M_CheckParm("-nowindow"))) + desired_fullscreen = 1; + + { // -geometry handling, change screen size for this session only + // e6y: new code by me + int w, h; + + if (!(p = M_CheckParm("-geom"))) + p = M_CheckParm("-geometry"); + + if (!(p && (p+1= MAXLOADFILES) + ProcessDehFile(fpath, D_dehout(), 0); + else { + D_AddFile(fpath,source_auto_load); + } + modifiedgame = true; + + } + } + + // e6y: DEH files preloaded in wrong order + // http://sourceforge.net/tracker/index.php?func=detail&aid=1418158&group_id=148658&atid=772943 + // The dachaked stuff has been moved from above + + // ty 03/09/98 do dehacked stuff + // Note: do this before any other since it is expected by + // the deh patch author that this is actually part of the EXE itself + // Using -deh in BOOM, others use -dehacked. + // Ty 03/18/98 also allow .bex extension. .bex overrides if both exist. + + p = M_CheckParm ("-deh"); + if (p) + { + char file[PATH_MAX+1]; // cph - localised + // the parms after p are deh/bex file names, + // until end of parms or another - preceded parm + // Ty 04/11/98 - Allow multiple -deh files in a row + + while (++p != myargc && *myargv[p] != '-') + { + AddDefaultExtension(strcpy(file, myargv[p]), ".bex"); + if (access(file, F_OK)) // nope + { + AddDefaultExtension(strcpy(file, myargv[p]), ".deh"); + if (access(file, F_OK)) // still nope + I_Error("D_DoomMainSetup: Cannot find .deh or .bex file named %s",myargv[p]); + } + // during the beta we have debug output to dehout.txt + ProcessDehFile(file,D_dehout(),0); + } + } + // ty 03/09/98 end of do dehacked stuff + + // add any files specified on the command line with -file wadfile + // to the wad list + + // killough 1/31/98, 5/2/98: reload hack removed, -wart same as -warp now. + + if ((p = M_CheckParm ("-file"))) + { + // the parms after p are wadfile/lump names, + // until end of parms or another - preceded parm + modifiedgame = true; // homebrew levels + while (++p != myargc && *myargv[p] != '-') + D_AddFile(myargv[p],source_pwad); + } + + // Add any iphone pwads (for example, No Rest for the Living is a pwad). + if ( pwad != NULL ) { + D_AddFile( pwad, source_pwad ); + } + + if (!(p = M_CheckParm("-playdemo")) || p >= myargc-1) { /* killough */ + if ((p = M_CheckParm ("-fastdemo")) && p < myargc-1) /* killough */ + fastdemo = true; // run at fastest speed possible + else + p = M_CheckParm ("-timedemo"); + } + + if (p && p < myargc-1) + { + char file[PATH_MAX+1]; // cph - localised + strcpy(file,myargv[p+1]); + AddDefaultExtension(file,".lmp"); // killough + D_AddFile (file,source_lmp); + //jff 9/3/98 use logical output routine + lprintf(LO_CONFIRM,"Playing demo %s\n",file); + if ((p = M_CheckParm ("-ffmap")) && p < myargc-1) { + ffmap = atoi(myargv[p+1]); + } + + } + + // internal translucency set to config file value // phares + general_translucency = default_translucency; // phares + + // 1/18/98 killough: Z_Init() call moved to i_main.c + + // CPhipps - move up netgame init + //jff 9/3/98 use logical output routine + lprintf(LO_INFO,"D_InitNetGame: Checking for network game.\n"); + D_InitNetGame(); + + //jff 9/3/98 use logical output routine + lprintf(LO_INFO,"W_Init: Init WADfiles.\n"); + W_Init(); // CPhipps - handling of wadfiles init changed + + lprintf(LO_INFO,"\n"); // killough 3/6/98: add a newline, by popular demand :) + + // e6y + // option to disable automatic loading of dehacked-in-wad lump + if (!M_CheckParm ("-nodeh")) + if ((p = W_CheckNumForName("DEHACKED")) != -1) // cph - add dehacked-in-a-wad support + ProcessDehFile(NULL, D_dehout(), p); + + V_InitColorTranslation(); //jff 4/24/98 load color translation lumps + + // killough 2/22/98: copyright / "modified game" / SPA banners removed + + // Ty 04/08/98 - Add 5 lines of misc. data, only if nonblank + // The expectation is that these will be set in a .bex file + //jff 9/3/98 use logical output routine + if (*startup1) lprintf(LO_INFO,"%s",startup1); + if (*startup2) lprintf(LO_INFO,"%s",startup2); + if (*startup3) lprintf(LO_INFO,"%s",startup3); + if (*startup4) lprintf(LO_INFO,"%s",startup4); + if (*startup5) lprintf(LO_INFO,"%s",startup5); + // End new startup strings + + //jff 9/3/98 use logical output routine + lprintf(LO_INFO,"M_Init: Init miscellaneous info.\n"); + //M_Init(); + +#ifdef HAVE_NET + // CPhipps - now wait for netgame start + D_CheckNetGame(); +#endif + + //jff 9/3/98 use logical output routine + lprintf(LO_INFO,"R_Init: Init DOOM refresh daemon - "); + R_Init(); + + //jff 9/3/98 use logical output routine + lprintf(LO_INFO,"\nP_Init: Init Playloop state.\n"); + P_Init(); + + //jff 9/3/98 use logical output routine + lprintf(LO_INFO,"I_Init: Setting up machine state.\n"); + I_Init(); + + //jff 9/3/98 use logical output routine + lprintf(LO_INFO,"S_Init: Setting up sound.\n"); + S_Init(snd_SfxVolume /* *8 */, snd_MusicVolume /* *8*/ ); + + //jff 9/3/98 use logical output routine + lprintf(LO_INFO,"HU_Init: Setting up heads up display.\n"); + HU_Init(); + + if (!(M_CheckParm("-nodraw") && M_CheckParm("-nosound"))) + I_InitGraphics(); + + //jff 9/3/98 use logical output routine + lprintf(LO_INFO,"ST_Init: Init status bar.\n"); + ST_Init(); + + idmusnum = -1; //jff 3/17/98 insure idmus number is blank + + // CPhipps - auto screenshots + if ((p = M_CheckParm("-autoshot")) && (p < myargc-2)) + if ((auto_shot_count = auto_shot_time = atoi(myargv[p+1]))) + auto_shot_fname = myargv[p+2]; + + // start the apropriate game based on parms + + // killough 12/98: + // Support -loadgame with -record and reimplement -recordfrom. + + if ((slot = M_CheckParm("-recordfrom")) && (p = slot+2) < myargc) + G_RecordDemo(myargv[p]); + else + { + slot = M_CheckParm("-loadgame"); + if ((p = M_CheckParm("-record")) && ++p < myargc) + { + autostart = true; + G_RecordDemo(myargv[p]); + } + } + + if ((p = M_CheckParm ("-checksum")) && ++p < myargc) + { + P_RecordChecksum (myargv[p]); + } + + if ((p = M_CheckParm ("-fastdemo")) && ++p < myargc) + { // killough + fastdemo = true; // run at fastest speed possible + timingdemo = true; // show stats after quit + G_DeferedPlayDemo(myargv[p]); + singledemo = true; // quit after one demo + } + else + if ((p = M_CheckParm("-timedemo")) && ++p < myargc) + { + singletics = true; + timingdemo = true; // show stats after quit + G_DeferedPlayDemo(myargv[p]); + singledemo = true; // quit after one demo + } + else + if ((p = M_CheckParm("-playdemo")) && ++p < myargc) + { + G_DeferedPlayDemo(myargv[p]); + singledemo = true; // quit after one demo + } + + if (slot && ++slot < myargc) + { + slot = atoi(myargv[slot]); // killough 3/16/98: add slot info + G_LoadGame(slot, true); // killough 5/15/98: add command flag // cph - no filename + } + else + if (!singledemo) { /* killough 12/98 */ + if (autostart || netgame) + { + G_InitNew(startskill, startepisode, startmap); + if (demorecording) + G_BeginRecording(); + } + else + D_StartTitle(); // start up intro loop + } +} + +// +// D_DoomMain +// +// Not called in iphone version. +/* +void D_DoomMain(void) +{ + D_DoomMainSetup(); // CPhipps - setup out of main execution stack + + D_DoomLoop (); // never returns +} +*/ + +// +// GetFirstMap +// +// Ty 08/29/98 - determine first available map from the loaded wads and run it +// + +void GetFirstMap(int *ep, int *map) +{ + int i,j; // used to generate map name + boolean done = false; // Ty 09/13/98 - to exit inner loops + char test[6]; // MAPxx or ExMx plus terminator for testing + char name[6]; // MAPxx or ExMx plus terminator for display + boolean newlevel = false; // Ty 10/04/98 - to test for new level + int ix; // index for lookup + + strcpy(name,""); // initialize + if (*map == 0) // unknown so go search for first changed one + { + *ep = 1; + *map = 1; // default E1M1 or MAP01 + if (gamemode == commercial) + { + for (i=1;!done && i<33;i++) // Ty 09/13/98 - add use of !done + { + sprintf(test,"MAP%02d",i); + ix = W_CheckNumForName(test); + if (ix != -1) // Ty 10/04/98 avoid -1 subscript + { + if (lumpinfo[ix].source == source_pwad) + { + *map = i; + strcpy(name,test); // Ty 10/04/98 + done = true; // Ty 09/13/98 + newlevel = true; // Ty 10/04/98 + } + else + { + if (!*name) // found one, not pwad. First default. + strcpy(name,test); + } + } + } + } + else // one of the others + { + strcpy(name,"E1M1"); // Ty 10/04/98 - default for display + for (i=1;!done && i<5;i++) // Ty 09/13/98 - add use of !done + { + for (j=1;!done && j<10;j++) // Ty 09/13/98 - add use of !done + { + sprintf(test,"E%dM%d",i,j); + ix = W_CheckNumForName(test); + if (ix != -1) // Ty 10/04/98 avoid -1 subscript + { + if (lumpinfo[ix].source == source_pwad) + { + *ep = i; + *map = j; + strcpy(name,test); // Ty 10/04/98 + done = true; // Ty 09/13/98 + newlevel = true; // Ty 10/04/98 + } + else + { + if (!*name) // found one, not pwad. First default. + strcpy(name,test); + } + } + } + } + } + //jff 9/3/98 use logical output routine + lprintf(LO_CONFIRM,"Auto-warping to first %slevel: %s\n", + newlevel ? "new " : "", name); // Ty 10/04/98 - new level test + } +} diff --git a/common/prboom/d_main.h b/common/prboom/d_main.h new file mode 100755 index 0000000..146b724 --- /dev/null +++ b/common/prboom/d_main.h @@ -0,0 +1,78 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Main startup and splash screenstuff. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __D_MAIN__ +#define __D_MAIN__ + +#include "d_event.h" +#include "w_wad.h" + + +/* CPhipps - removed wadfiles[] stuff to w_wad.h */ + +extern char basesavegame[]; // killough 2/16/98: savegame path + +//jff 1/24/98 make command line copies of play modes available +extern boolean clnomonsters; // checkparm of -nomonsters +extern boolean clrespawnparm; // checkparm of -respawn +extern boolean clfastparm; // checkparm of -fast +//jff end of external declaration of command line playmode + +extern boolean nosfxparm; +extern boolean nomusicparm; +extern int ffmap; + +// Called by IO functions when input is detected. +void D_PostEvent(event_t* ev); + +// Demo stuff +extern boolean advancedemo; +void D_AdvanceDemo(void); +void D_DoAdvanceDemo (void); + +// +// BASE LEVEL +// + +void D_Display(void); +void D_PageTicker(void); +void D_StartTitle(void); +void D_DoomMainSetup( const char * iwad, const char * pwad ); +void D_DoomMain(void); +void D_AddFile (const char *file, wad_source_t source); + +/* cph - MBF-like wad/deh/bex autoload code */ +#define MAXLOADFILES 2 +extern const char *wad_files[MAXLOADFILES], *deh_files[MAXLOADFILES]; + +#endif diff --git a/common/prboom/d_net.h b/common/prboom/d_net.h new file mode 100755 index 0000000..e5fd377 --- /dev/null +++ b/common/prboom/d_net.h @@ -0,0 +1,211 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Networking stuff. + * + *-----------------------------------------------------------------------------*/ + + +#ifndef __D_NET__ +#define __D_NET__ + +#include "d_player.h" + + + + +// +// Network play related stuff. +// There is a data struct that stores network +// communication related stuff, and another +// one that defines the actual packets to +// be transmitted. +// + +#define DOOMCOM_ID 0x12345678l + +// Max computers/players in a game. +#define MAXNETNODES 8 + + +typedef enum +{ + CMD_SEND = 1, + CMD_GET = 2 + +} command_t; + + +// +// Network packet data. +// +typedef struct +{ + // High bit is retransmit request. + unsigned checksum; + // Only valid if NCMD_RETRANSMIT. + byte retransmitfrom; + + byte starttic; + byte player; + byte numtics; + ticcmd_t cmds[BACKUPTICS]; + +} doomdata_t; + +// +// Startup packet difference +// SG: 4/12/98 +// Added so we can send more startup data to synch things like +// bobbing, recoil, etc. +// this is just mapped over the ticcmd_t array when setup packet is sent +// +// Note: the original code takes care of startskill, deathmatch, nomonsters +// respawn, startepisode, startmap +// Note: for phase 1 we need to add monsters_remember, variable_friction, +// weapon_recoil, allow_pushers, over_under, player_bobbing, +// fastparm, demo_insurance, and the rngseed +//Stick all options into bytes so we don't need to mess with bitfields +//WARNING: make sure this doesn't exceed the size of the ticcmds area! +//sizeof(ticcmd_t)*BACKUPTICS +//This is the current length of our extra stuff +// +//killough 5/2/98: this should all be replaced by calls to G_WriteOptions() +//and G_ReadOptions(), which were specifically designed to set up packets. +//By creating a separate struct and functions to read/write the options, +//you now have two functions and data to maintain instead of just one. +//If the array in g_game.c which G_WriteOptions()/G_ReadOptions() operates +//on, is too large (more than sizeof(ticcmd_t)*BACKUPTICS), it can +//either be shortened, or the net code needs to divide it up +//automatically into packets. The STARTUPLEN below is non-portable. +//There's a portable way to do it without having to know the sizes. + +#define STARTUPLEN 12 +typedef struct +{ + byte monsters_remember; + byte variable_friction; + byte weapon_recoil; + byte allow_pushers; + byte over_under; + byte player_bobbing; + byte fastparm; + byte demo_insurance; + unsigned long rngseed; + char filler[sizeof(ticcmd_t)*BACKUPTICS-STARTUPLEN]; +} startup_t; + +typedef enum { + // Leave space, so low values corresponding to normal netgame setup packets can be ignored + nm_plcolour = 3, + nm_savegamename = 4, +} netmisctype_t; + +typedef struct +{ + netmisctype_t type; + size_t len; + byte value[sizeof(ticcmd_t)*BACKUPTICS - sizeof(netmisctype_t) - sizeof(size_t)]; +} netmisc_t; + +typedef struct +{ + // Supposed to be DOOMCOM_ID? + long id; + + // DOOM executes an int to execute commands. + short intnum; + // Communication between DOOM and the driver. + // Is CMD_SEND or CMD_GET. + short command; + // Is dest for send, set by get (-1 = no packet). + short remotenode; + + // Number of bytes in doomdata to be sent + short datalength; + + // Info common to all nodes. + // Console is allways node 0. + short numnodes; + // Flag: 1 = no duplication, 2-5 = dup for slow nets. + short ticdup; + // Flag: 1 = send a backup tic in every packet. + short extratics; + // Flag: 1 = deathmatch. + short deathmatch; + // Flag: -1 = new game, 0-5 = load savegame + short savegame; + short episode; // 1-3 + short map; // 1-9 + short skill; // 1-5 + + // Info specific to this node. + short consoleplayer; + short numplayers; + + // These are related to the 3-display mode, + // in which two drones looking left and right + // were used to render two additional views + // on two additional computers. + // Probably not operational anymore. + // 1 = left, 0 = center, -1 = right + short angleoffset; + // 1 = drone + short drone; + + // The packet data to be sent. + doomdata_t data; + +} doomcom_t; + +// Create any new ticcmds and broadcast to other players. +#ifdef HAVE_NET +void NetUpdate (void); +#else +void D_BuildNewTiccmds(void); +#endif + +//? how many ticks to run? +void TryRunTics (void); + +// CPhipps - move to header file +void D_InitNetGame (void); // This does the setup +void D_CheckNetGame(void); // This waits for game start + +// CPhipps - misc info broadcast +void D_NetSendMisc(netmisctype_t type, size_t len, void* data); + +// CPhipps - ask server for a wad file we need +boolean D_NetGetWad(const char* name); + +// Netgame stuff (buffers and pointers, i.e. indices). +extern doomcom_t *doomcom; +extern doomdata_t *netbuffer; // This points inside doomcom. + +#endif diff --git a/common/prboom/d_player.h b/common/prboom/d_player.h new file mode 100755 index 0000000..363d43f --- /dev/null +++ b/common/prboom/d_player.h @@ -0,0 +1,231 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Player state structure. + * + *-----------------------------------------------------------------------------*/ + + +#ifndef __D_PLAYER__ +#define __D_PLAYER__ + + +// The player data structure depends on a number +// of other structs: items (internal inventory), +// animation states (closely tied to the sprites +// used to represent them, unfortunately). +#include "d_items.h" +#include "p_pspr.h" + +// In addition, the player is just a special +// case of the generic moving object/actor. +#include "p_mobj.h" + +// Finally, for odd reasons, the player input +// is buffered within the player data struct, +// as commands per game tick. +#include "d_ticcmd.h" + + + +// +// Player states. +// +typedef enum +{ + // Playing or camping. + PST_LIVE, + // Dead on the ground, view follows killer. + PST_DEAD, + // Ready to restart/respawn??? + PST_REBORN + +} playerstate_t; + + +// +// Player internal flags, for cheats and debug. +// +typedef enum +{ + // No clipping, walk through barriers. + CF_NOCLIP = 1, + // No damage, no health loss. + CF_GODMODE = 2, + // Not really a cheat, just a debug aid. + CF_NOMOMENTUM = 4 + +} cheat_t; + + +// +// Extended player object info: player_t +// +typedef struct player_s +{ + mobj_t* mo; + playerstate_t playerstate; + ticcmd_t cmd; + + // Determine POV, + // including viewpoint bobbing during movement. + // Focal origin above r.z + fixed_t viewz; + // Base height above floor for viewz. + fixed_t viewheight; + // Bob/squat speed. + fixed_t deltaviewheight; + // bounded/scaled total momentum. + fixed_t bob; + + /* killough 10/98: used for realistic bobbing (i.e. not simply overall speed) + * mo->momx and mo->momy represent true momenta experienced by player. + * This only represents the thrust that the player applies himself. + * This avoids anomolies with such things as Boom ice and conveyors. + */ + fixed_t momx, momy; // killough 10/98 + + // This is only used between levels, + // mo->health is used during levels. + int health; + int armorpoints; + // Armor type is 0-2. + int armortype; + + // Power ups. invinc and invis are tic counters. + int powers[NUMPOWERS]; + boolean cards[NUMCARDS]; + boolean backpack; + + // Frags, kills of other players. + int frags[MAXPLAYERS]; + weapontype_t readyweapon; + + // Is wp_nochange if not changing. + weapontype_t pendingweapon; + + boolean weaponowned[NUMWEAPONS]; + int ammo[NUMAMMO]; + int maxammo[NUMAMMO]; + + // True if button down last tic. + int attackdown; + int usedown; + + // Bit flags, for cheats and debug. + // See cheat_t, above. + int cheats; + + // Refired shots are less accurate. + int refire; + + // For intermission stats. + int killcount; + int itemcount; + int secretcount; + + // Hint messages. // CPhipps - const + const char* message; + + // For screen flashing (red or bright). + int damagecount; + int bonuscount; + + // Who did damage (NULL for floors/ceilings). + mobj_t* attacker; + + // So gun flashes light up areas. + int extralight; + + // Current PLAYPAL, ??? + // can be set to REDCOLORMAP for pain, etc. + int fixedcolormap; + + // Player skin colorshift, + // 0-3 for which color to draw player. + int colormap; + + // Overlay view sprites (gun, etc). + pspdef_t psprites[NUMPSPRITES]; + + // True if secret level has been done. + boolean didsecret; + +} player_t; + + +// +// INTERMISSION +// Structure passed e.g. to WI_Start(wb) +// +typedef struct +{ + boolean in; // whether the player is in game + + // Player stats, kills, collected items etc. + int skills; + int sitems; + int ssecret; + int stime; + int frags[4]; + int score; // current score on entry, modified on return + +} wbplayerstruct_t; + +typedef struct +{ + int epsd; // episode # (0-2) + + // if true, splash the secret level + boolean didsecret; + + // previous and next levels, origin 0 + int last; + int next; + + int maxkills; + int maxitems; + int maxsecret; + int maxfrags; + + // the par time + int partime; + + // index of this player in game + int pnum; + + wbplayerstruct_t plyr[MAXPLAYERS]; + + // CPhipps - total game time for completed levels so far + int totaltimes; + +} wbstartstruct_t; + + +#endif diff --git a/common/prboom/d_server.c b/common/prboom/d_server.c new file mode 100755 index 0000000..dd16483 --- /dev/null +++ b/common/prboom/d_server.c @@ -0,0 +1,754 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2004 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Network game server code + * New for LxDoom, but drawing ideas and code fragments from the + * earlier net code + *----------------------------------------------------------------------------- + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#include +#include +#include + +#ifdef USE_SDL_NET + #include "SDL.h" +#endif + +#include "doomtype.h" +#include "protocol.h" +#include "i_network.h" +#ifndef PRBOOM_SERVER +#include "m_fixed.h" +#endif +#include "i_system.h" +#include "m_swap.h" + +#ifndef HAVE_NET + +int main(void) +{ + fprintf(stderr, + PACKAGE "-server: You must compile with networking enabled!\n"); + exit(1); + return 1; +} + +#else + +#ifndef HAVE_GETOPT +/* The following code for getopt is from the libc-source of FreeBSD, + * it might be changed a little bit. + * Florian Schulze (florian.schulze@gmx.net) + */ + +/* + * Copyright (c) 1987, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)getopt.c 8.3 (Berkeley) 4/27/95"; +#endif +static const char rcsid[] = "$FreeBSD$"; +#endif /* LIBC_SCCS and not lint */ + +int opterr = 1, /* if error message should be printed */ + optind = 1, /* index into parent argv vector */ + optopt, /* character checked for validity */ + optreset; /* reset getopt */ +char *optarg; /* argument associated with option */ + +#define BADCH (int)'?' +#define BADARG (int)':' +#define EMSG "" + +char *__progname="prboom_server"; + +/* + * getopt -- + * Parse argc/argv argument vector. + */ +int +getopt(nargc, nargv, ostr) + int nargc; + char * const *nargv; + const char *ostr; +{ + extern char *__progname; + static char *place = EMSG; /* option letter processing */ + char *oli; /* option letter list index */ + int ret; + + if (optreset || !*place) { /* update scanning pointer */ + optreset = 0; + if (optind >= nargc || *(place = nargv[optind]) != '-') { + place = EMSG; + return (-1); + } + if (place[1] && *++place == '-') { /* found "--" */ + ++optind; + place = EMSG; + return (-1); + } + } /* option letter okay? */ + if ((optopt = (int)*place++) == (int)':' || + !(oli = strchr(ostr, optopt))) { + /* + * if the user didn't specify '-' as an option, + * assume it means -1. + */ + if (optopt == (int)'-') + return (-1); + if (!*place) + ++optind; + if (opterr && *ostr != ':') + (void)fprintf(stderr, + "%s: illegal option -- %c\n", __progname, optopt); + return (BADCH); + } + if (*++oli != ':') { /* don't need argument */ + optarg = NULL; + if (!*place) + ++optind; + } + else { /* need an argument */ + if (*place) /* no white space */ + optarg = place; + else if (nargc <= ++optind) { /* no arg */ + place = EMSG; + if (*ostr == ':') + ret = BADARG; + else + ret = BADCH; + if (opterr) + (void)fprintf(stderr, + "%s: option requires an argument -- %c\n", + __progname, optopt); + return (ret); + } + else /* white space */ + optarg = nargv[optind]; + place = EMSG; + ++optind; + } + return (optopt); /* dump back option letter */ +} +#else +#include +#endif + +#define MAXPLAYERS 4 +#define BACKUPTICS 12 + +// Dummies to forfill l_udp.c unused client stuff +int M_CheckParm(const char* p) { p = NULL; return 1; } +int myargc; +char** myargv; + +void NORETURN I_Error(const char *error, ...) // killough 3/20/98: add const +{ + va_list argptr; + va_start(argptr,error); + vfprintf(stderr,error,argptr); + va_end(argptr); + exit(-1); +} + +int playerjoingame[MAXPLAYERS], playerleftgame[MAXPLAYERS]; +UDP_CHANNEL remoteaddr[MAXPLAYERS]; +enum { pc_unused, pc_connected, pc_ready, pc_confirmedready, pc_playing, pc_quit } playerstate[MAXPLAYERS]; +int displaycounter; + +boolean n_players_in_state(int n, int ps) { + int i,j; + for (i=j=0;itic); +} + + + +void read_config_file(FILE* fp, struct setup_packet_s* sp) +{ + byte* gameopt = sp->game_options; + + while (!feof(fp)) { + char def[80]; + char strparm[100]; + if (fscanf (fp, "%79s %99[^\n]\n", def, strparm) == 2) { + int v = atoi(strparm); + if (!strcmp(def,"default_skill")) { + if (verbose) printf("config file sets default_skill to %d\n",v); + sp->skill = v-1; + } else if (!strcmp(def,"default_compatibility_level")) { + if (verbose) printf("config file sets compatibility_level to %d\n",v); + if (v == -1) v = MAX_COMPATIBILITY_LEVEL-1; //e6y: -1 => maxcompat + sp->complevel = v; + } else { + int i; + for (i=0; i= MAXPLAYERS); } + +int main(int argc, char** argv) +{ +#ifndef USE_SDL_NET + int localport = 5030; +#else + Uint16 localport = 5030; +#endif + int numplayers = 2, xtratics = 0, ticdup = 1; + int exectics = 0; // gametics completed + struct setup_packet_s setupinfo = { 2, 0, 1, 1, 1, 0, best_compatibility, 0, 0}; + char**wadname = NULL; + char**wadget = NULL; + int numwads = 0; + { + int opt; + byte *gameopt = setupinfo.game_options; + + memcpy(gameopt, &def_game_options, sizeof (setupinfo.game_options)); + while ((opt = getopt(argc, argv, "c:t:x:p:e:l:adrfns:N:vw:")) != EOF) + switch (opt) { + case 'c': + { + FILE *cf = fopen(optarg,"r"); + if (!cf) { perror("fopen"); return -1; } + read_config_file(cf,&setupinfo); + fclose(cf); + } + break; + case 't': + if (optarg) ticdup = atoi(optarg); + break; + case 'x': + if (optarg) xtratics = atoi(optarg); + break; + case 'p': + if (optarg) localport = atoi(optarg); + break; + case 'e': + if (optarg) setupinfo.episode = atoi(optarg); + break; + case 'l': + if (optarg) setupinfo.level = atoi(optarg); + break; + case 'a': + setupinfo.deathmatch = 2; + break; + case 'd': + setupinfo.deathmatch = 1; + break; + case 'r': + setupinfo.game_options[6] = 1; + break; + case 'f': + setupinfo.game_options[7] = 1; + break; + case 'n': + setupinfo.game_options[8] = 1; + break; + case 's': + if (optarg) setupinfo.skill = atoi(optarg)-1; + break; + case 'N': + if (optarg) setupinfo.players = numplayers = atoi(optarg); + break; + case 'v': + verbose++; + break; + case 'w': + if (optarg) { + char *p; + wadname = realloc(wadname, ++numwads * sizeof *wadname); + wadget = realloc(wadget , numwads * sizeof *wadget ); + wadname[numwads-1] = strdup(optarg); + if ((p = strchr(wadname[numwads-1], ','))) { + *p++ = 0; wadget[numwads-1] = p; + } else wadget[numwads-1] = NULL; + } + break; + } + } + + setupinfo.ticdup = ticdup; setupinfo.extratic = xtratics; + { /* Random number seed + * Mirrors the corresponding code in G_ReadOptions */ + int rngseed = (int)time(NULL); + setupinfo.game_options[13] = rngseed & 0xff; + rngseed >>= 8; + setupinfo.game_options[12] = rngseed & 0xff; + rngseed >>= 8; + setupinfo.game_options[11] = rngseed & 0xff; + rngseed >>= 8; + setupinfo.game_options[10] = rngseed & 0xff; + } + I_InitSockets(localport); + + printf("Listening on port %d, waiting for %d players\n", localport, numplayers); + + { // no players initially + int i; + for (i=0; i2) printf("Received packet:"); + switch (packet->type) { + case PKT_INIT: + if (!ingame) { + { + int n; + struct setup_packet_s *sinfo = (void*)(packet+1); + + /* Find player number and add to the game */ + n = *(short*)(packet+1); + + if (badplayer(n) || playerstate[n] != pc_unused) + for (n=0; nyourplayer = n; + sinfo->numwads = numwads; + for (i=0; iwadnames + extrabytes, wadname[i]); + extrabytes += strlen(wadname[i]) + 1; + } + I_SendPacketTo(packet, sizeof *packet + sizeof setupinfo + extrabytes, + remoteaddr+n); + I_uSleep(10000); + I_SendPacketTo(packet, sizeof *packet + sizeof setupinfo + extrabytes, + remoteaddr+n); + } + } + } + break; + case PKT_GO: + if (!ingame) { + int from = *(byte*)(packet+1); + + if (badplayer(from) || playerstate[from] == pc_unused) break; + if (confirming) { + if (playerstate[from] != pc_confirmedready) curplayers++; + playerstate[from] = pc_confirmedready; + } else + playerstate[from] = pc_ready; + } + break; + case PKT_TICC: + { + byte tics = *(byte*)(packet+1); + int from = *(((byte*)(packet+1))+1); + + if (badplayer(from)) break; + + if (verbose>2) + printf("tics %ld - %ld from %d\n", ptic(packet), ptic(packet) + tics - 1, from); + if (ptic(packet) > remoteticfrom[from]) { + // Missed tics, so request a resend + packet_set(packet, PKT_RETRANS, remoteticfrom[from]); + I_SendPacketTo(packet, sizeof *packet, remoteaddr+from); + } else { + ticcmd_t *newtic = (void*)(((byte*)(packet+1))+2); + if (ptic(packet) + tics < remoteticfrom[from]) break; // Won't help + remoteticfrom[from] = ptic(packet); + while (tics--) + netcmds[from][remoteticfrom[from]++%BACKUPTICS] = *newtic++; + } + } + break; + case PKT_RETRANS: + { + int from = *(byte*)(packet+1); + if (badplayer(from)) break; + + if (verbose>2) printf("%d requests resend from %d\n", from, ptic(packet)); + remoteticto[from] = ptic(packet); + } + break; + case PKT_QUIT: + { + int from = *(byte*)(packet+1); + if (badplayer(from)) break; + + if (!ingame && playerstate[from] != pc_unused) { + // If we already got a PKT_GO, we have to remove this player frmo the count of ready players. And we then flag this player slot as vacant. + printf("player %d pulls out\n", from); + if (playerstate[from] == pc_confirmedready) curplayers--; + playerstate[from] = pc_unused; + } else + if (playerleftgame[from] == INT_MAX) { // In the game + playerleftgame[from] = ptic(packet); + --curplayers; + if (verbose) printf("%d quits at %d (%d left)\n", from, ptic(packet),curplayers); + if (ingame && !curplayers) exit(0); // All players have exited + } + } + // Fall through and broadcast it + case PKT_EXTRA: + BroadcastPacket(packet, len); + if (packet->type == PKT_EXTRA) { + if (verbose>2) printf("misc from %d\n", *(((byte*)(packet+1))+1)); + } + break; + case PKT_WAD: + { + int i; + int from = *(byte*)(packet+1); + char *name = 1 + (char*)(packet+1); + size_t size = sizeof(packet_header_t); + packet_header_t *reply; + + if (badplayer(from) || playerstate[from] != pc_unused) break; + + if (verbose) printf("Request for %s ", name); + for (i=0; itype); + break; + } + } + free(packet); + if (!ingame && n_players_in_state(numplayers,pc_confirmedready)) { + int i; + packet_header_t gopacket; + packet = &gopacket; + ingame=true; + printf("All players joined, beginning game.\n"); + for (i=0; i1) printf("%d new tics can be run\n", lowtic - exectics); + + if (lowtic > exectics) + exectics = lowtic; // count exec'ed tics + // Now send all tics up to lowtic + for (i=0; i1) printf("sending %d tics to %d\n", tics, i); + while (tics--) { + int j, playersthistic = 0; + byte *q = p++; + for (j=0; j remoteticto[i])) { + *p++ = j; + memcpy(p, &netcmds[j][remoteticto[i]%BACKUPTICS], sizeof(ticcmd_t)); + p += sizeof(ticcmd_t); + playersthistic++; + } + *q = playersthistic; + remoteticto[i]++; + } + I_SendPacketTo(packet, p - ((byte*)packet), remoteaddr+i); + free(packet); + } + { + if (remoteticfrom[i] == remoteticto[i]) { + backoffcounter[i] = 0; + } else if (remoteticfrom[i] > remoteticto[i]+1) { + if ((backoffcounter[i] += remoteticfrom[i] - remoteticto[i] - 1) > 35) { + packet_header_t *packet = malloc(sizeof(packet_header_t)); + packet_set(packet, PKT_BACKOFF, remoteticto[i]); + I_SendPacketTo(packet,sizeof *packet,remoteaddr+i); + backoffcounter[i] = 0; + if (verbose) printf("telling client %d to back off\n",i); + free(packet); + } + } + } + } + } + if (!((ingame ? 0xff : 0xf) & displaycounter++)) { + int i; + fprintf(stderr,"Player states: ["); + for (i=0;i +#include +#include +#include +#include + +// this should go here, not in makefile/configure.ac -- josh +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +#include "m_swap.h" +#include "version.h" + +// Game mode handling - identify IWAD version +// to handle IWAD dependend animations etc. +typedef enum { + shareware, // DOOM 1 shareware, E1, M9 + registered, // DOOM 1 registered, E3, M27 + commercial, // DOOM 2 retail, E1 M34 (DOOM 2 german edition not handled) + retail, // DOOM 1 retail, E4, M36 + indetermined // Well, no IWAD found. +} GameMode_t; + +// Mission packs - might be useful for TC stuff? +typedef enum { + doom, // DOOM 1 + doom2, // DOOM 2 + pack_tnt, // TNT mission pack + pack_plut, // Plutonia pack + none +} GameMission_t; + +// Identify language to use, software localization. +typedef enum { + english, + french, + german, + unknown +} Language_t; + +// +// For resize of screen, at start of game. +// + +#define BASE_WIDTH 320 + +// It is educational but futile to change this +// scaling e.g. to 2. Drawing of status bar, +// menues etc. is tied to the scale implied +// by the graphics. + +#define INV_ASPECT_RATIO 0.625 /* 0.75, ideally */ + +// killough 2/8/98: MAX versions for maximum screen sizes +// allows us to avoid the overhead of dynamic allocation +// when multiple screen sizes are supported + +// proff 08/17/98: Changed for high-res +#define MAX_SCREENWIDTH 2048 +#define MAX_SCREENHEIGHT 1536 + + +// SCREENWIDTH and SCREENHEIGHT define the visible size +extern int SCREENWIDTH; +extern int SCREENHEIGHT; +// SCREENPITCH is the size of one line in the buffer and +// can be bigger than the SCREENWIDTH depending on the size +// of one pixel (8, 16 or 32 bit) and the padding at the +// end of the line caused by hardware considerations +extern int SCREENPITCH; + +// The maximum number of players, multiplayer/networking. +#define MAXPLAYERS 4 + +// phares 5/14/98: +// DOOM Editor Numbers (aka doomednum in mobj_t) + +#define DEN_PLAYER5 4001 +#define DEN_PLAYER6 4002 +#define DEN_PLAYER7 4003 +#define DEN_PLAYER8 4004 + +// State updates, number of tics / second. +#define TICRATE 35 + +// The current state of the game: whether we are playing, gazing +// at the intermission screen, the game final animation, or a demo. + +typedef enum { + GS_LEVEL, + GS_INTERMISSION, + GS_FINALE, + GS_DEMOSCREEN +} gamestate_t; + +// +// Difficulty/skill settings/filters. +// +// These are Thing flags + +// Skill flags. +#define MTF_EASY 1 +#define MTF_NORMAL 2 +#define MTF_HARD 4 +// Deaf monsters/do not react to sound. +#define MTF_AMBUSH 8 + +/* killough 11/98 */ +#define MTF_NOTSINGLE 16 +#define MTF_NOTDM 32 +#define MTF_NOTCOOP 64 +#define MTF_FRIEND 128 +#define MTF_RESERVED 256 + +typedef enum { + sk_none=-1, //jff 3/24/98 create unpicked skill setting + sk_baby=0, + sk_easy, + sk_medium, + sk_hard, + sk_nightmare +} skill_t; + +// +// Key cards. +// + +typedef enum { + it_bluecard, + it_yellowcard, + it_redcard, + it_blueskull, + it_yellowskull, + it_redskull, + NUMCARDS +} card_t; + +// The defined weapons, including a marker +// indicating user has not changed weapon. +typedef enum { + wp_fist, + wp_pistol, + wp_shotgun, + wp_chaingun, + wp_missile, + wp_plasma, + wp_bfg, + wp_chainsaw, + wp_supershotgun, + + NUMWEAPONS, + wp_nochange // No pending weapon change. +} weapontype_t; + +// Ammunition types defined. +typedef enum { + am_clip, // Pistol / chaingun ammo. + am_shell, // Shotgun / double barreled shotgun. + am_cell, // Plasma rifle, BFG. + am_misl, // Missile launcher. + NUMAMMO, + am_noammo // Unlimited for chainsaw / fist. +} ammotype_t; + +// Power up artifacts. +typedef enum { + pw_invulnerability, + pw_strength, + pw_invisibility, + pw_ironfeet, + pw_allmap, + pw_infrared, + NUMPOWERS +} powertype_t; + +// Power up durations (how many seconds till expiration). +typedef enum { + INVULNTICS = (30*TICRATE), + INVISTICS = (60*TICRATE), + INFRATICS = (120*TICRATE), + IRONTICS = (60*TICRATE) +} powerduration_t; + +// DOOM keyboard definition. +// This is the stuff configured by Setup.Exe. +// Most key data are simple ascii (uppercased). + +#define KEYD_RIGHTARROW 0xae +#define KEYD_LEFTARROW 0xac +#define KEYD_UPARROW 0xad +#define KEYD_DOWNARROW 0xaf +#define KEYD_ESCAPE 27 +#define KEYD_ENTER 13 +#define KEYD_TAB 9 +#define KEYD_F1 (0x80+0x3b) +#define KEYD_F2 (0x80+0x3c) +#define KEYD_F3 (0x80+0x3d) +#define KEYD_F4 (0x80+0x3e) +#define KEYD_F5 (0x80+0x3f) +#define KEYD_F6 (0x80+0x40) +#define KEYD_F7 (0x80+0x41) +#define KEYD_F8 (0x80+0x42) +#define KEYD_F9 (0x80+0x43) +#define KEYD_F10 (0x80+0x44) +#define KEYD_F11 (0x80+0x57) +#define KEYD_F12 (0x80+0x58) +#define KEYD_BACKSPACE 127 +#define KEYD_PAUSE 0xff +#define KEYD_EQUALS 0x3d +#define KEYD_MINUS 0x2d +#define KEYD_RSHIFT (0x80+0x36) +#define KEYD_RCTRL (0x80+0x1d) +#define KEYD_RALT (0x80+0x38) +#define KEYD_LALT KEYD_RALT +#define KEYD_CAPSLOCK 0xba // phares + +// phares 3/2/98: +#define KEYD_INSERT 0xd2 +#define KEYD_HOME 0xc7 +#define KEYD_PAGEUP 0xc9 +#define KEYD_PAGEDOWN 0xd1 +#define KEYD_DEL 0xc8 +#define KEYD_END 0xcf +#define KEYD_SCROLLLOCK 0xc6 +#define KEYD_SPACEBAR 0x20 +// phares 3/2/98 + +#define KEYD_NUMLOCK 0xC5 // killough 3/6/98 + +// cph - Add the numeric keypad keys, as suggested by krose 4/22/99: +// The way numbers are assigned to keys is a mess, but it's too late to +// change that easily. At least these additions are don neatly. +// Codes 0x100-0x200 are reserved for number pad + +#define KEYD_KEYPAD0 (0x100 + '0') +#define KEYD_KEYPAD1 (0x100 + '1') +#define KEYD_KEYPAD2 (0x100 + '2') +#define KEYD_KEYPAD3 (0x100 + '3') +#define KEYD_KEYPAD4 (0x100 + '4') +#define KEYD_KEYPAD5 (0x100 + '5') +#define KEYD_KEYPAD6 (0x100 + '6') +#define KEYD_KEYPAD7 (0x100 + '7') +#define KEYD_KEYPAD8 (0x100 + '8') +#define KEYD_KEYPAD9 (0x100 + '9') +#define KEYD_KEYPADENTER (0x100 + KEYD_ENTER) +#define KEYD_KEYPADDIVIDE (0x100 + '/') +#define KEYD_KEYPADMULTIPLY (0x100 + '*') +#define KEYD_KEYPADMINUS (0x100 + '-') +#define KEYD_KEYPADPLUS (0x100 + '+') +#define KEYD_KEYPADPERIOD (0x100 + '.') + +// phares 4/19/98: +// Defines Setup Screen groups that config variables appear in. +// Used when resetting the defaults for every item in a Setup group. + +typedef enum { + ss_none, + ss_keys, + ss_weap, + ss_stat, + ss_auto, + ss_enem, + ss_mess, + ss_chat, + ss_gen, /* killough 10/98 */ + ss_comp, /* killough 10/98 */ + ss_max +} ss_types; + +// phares 3/20/98: +// +// Player friction is variable, based on controlling +// linedefs. More friction can create mud, sludge, +// magnetized floors, etc. Less friction can create ice. + +#define MORE_FRICTION_MOMENTUM 15000 // mud factor based on momentum +#define ORIG_FRICTION 0xE800 // original value +#define ORIG_FRICTION_FACTOR 2048 // original value + +#endif // __DOOMDEF__ diff --git a/common/prboom/doomstat.c b/common/prboom/doomstat.c new file mode 100755 index 0000000..56506ad --- /dev/null +++ b/common/prboom/doomstat.c @@ -0,0 +1,108 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Put all global state variables here. + * + *----------------------------------------------------------------------------- + */ + +#ifdef __GNUG__ +#pragma implementation "doomstat.h" +#endif +#include "doomstat.h" + +// Game Mode - identify IWAD as shareware, retail etc. +GameMode_t gamemode = indetermined; +GameMission_t gamemission = doom; + +// Language. +Language_t language = english; + +// Set if homebrew PWAD stuff has been added. +boolean modifiedgame; + +//----------------------------------------------------------------------------- + +// CPhipps - compatibility vars +complevel_t compatibility_level, default_compatibility_level; + +int comp[COMP_TOTAL], default_comp[COMP_TOTAL]; // killough 10/98 + +// v1.1-like pitched sounds +int pitched_sounds; // killough + +int default_translucency; // config file says // phares +boolean general_translucency; // true if translucency is ok // phares + +int demo_insurance, default_demo_insurance; // killough 1/16/98 + +int allow_pushers = 1; // MT_PUSH Things // phares 3/10/98 +int default_allow_pushers; // killough 3/1/98: make local to each game + +int variable_friction = 1; // ice & mud // phares 3/10/98 +int default_variable_friction; // killough 3/1/98: make local to each game + +int weapon_recoil; // weapon recoil // phares +int default_weapon_recoil; // killough 3/1/98: make local to each game + +int player_bobbing; // whether player bobs or not // phares 2/25/98 +int default_player_bobbing; // killough 3/1/98: make local to each game + +int monsters_remember; // killough 3/1/98 +int default_monsters_remember; + +int monster_infighting=1; // killough 7/19/98: monster<=>monster attacks +int default_monster_infighting=1; + +int monster_friction=1; // killough 10/98: monsters affected by friction +int default_monster_friction=1; + +#ifdef DOGS +int dogs, default_dogs; // killough 7/19/98: Marine's best friend :) +int dog_jumping, default_dog_jumping; // killough 10/98 +#endif + +// killough 8/8/98: distance friends tend to move towards players +int distfriend = 128, default_distfriend = 128; + +// killough 9/8/98: whether monsters are allowed to strafe or retreat +int monster_backing, default_monster_backing; + +// killough 9/9/98: whether monsters are able to avoid hazards (e.g. crushers) +int monster_avoid_hazards, default_monster_avoid_hazards; + +// killough 9/9/98: whether monsters help friends +int help_friends, default_help_friends; + +int flashing_hom; // killough 10/98 + +int doom_weapon_toggles; // killough 10/98 + +int monkeys, default_monkeys; + diff --git a/common/prboom/doomstat.h b/common/prboom/doomstat.h new file mode 100755 index 0000000..c23c405 --- /dev/null +++ b/common/prboom/doomstat.h @@ -0,0 +1,333 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2006 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * All the global variables that store the internal state. + * Theoretically speaking, the internal state of the engine + * should be found by looking at the variables collected + * here, and every relevant module will have to include + * this header file. + * In practice, things are a bit messy. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __D_STATE__ +#define __D_STATE__ + +// We need the playr data structure as well. +#include "d_player.h" + +// ------------------------ +// Command line parameters. +// + +extern boolean nomonsters; // checkparm of -nomonsters +extern boolean respawnparm; // checkparm of -respawn +extern boolean fastparm; // checkparm of -fast +extern boolean devparm; // DEBUG: launched with -devparm + +// ----------------------------------------------------- +// Game Mode - identify IWAD as shareware, retail etc. +// + +extern GameMode_t gamemode; +extern GameMission_t gamemission; + +// Set if homebrew PWAD stuff has been added. +extern boolean modifiedgame; + +// CPhipps - new compatibility handling +extern complevel_t compatibility_level, default_compatibility_level; + +// CPhipps - old compatibility testing flags aliased to new handling +#define compatibility (compatibility_level<=boom_compatibility_compatibility) +#define demo_compatibility (compatibility_level < boom_compatibility_compatibility) +#define mbf_features (compatibility_level>=mbf_compatibility) + +// v1.1-like pitched sounds +extern int pitched_sounds; // killough + +extern int default_translucency; // config file says // phares +extern boolean general_translucency; // true if translucency is ok // phares + +extern int demo_insurance, default_demo_insurance; // killough 4/5/98 + +// ------------------------------------------- +// killough 10/98: compatibility vector + +enum { + comp_telefrag, + comp_dropoff, + comp_vile, + comp_pain, + comp_skull, + comp_blazing, + comp_doorlight, + comp_model, + comp_god, + comp_falloff, + comp_floors, + comp_skymap, + comp_pursuit, + comp_doorstuck, + comp_staylift, + comp_zombie, + comp_stairs, + comp_infcheat, + comp_zerotags, + comp_moveblock, + comp_respawn, /* cph - this is the inverse of comp_respawnfix from eternity */ + comp_sound, + comp_666, + comp_soul, + comp_maskedanim, + COMP_NUM, /* cph - should be last in sequence */ + COMP_TOTAL=32 // Some extra room for additional variables +}; + +extern int comp[COMP_TOTAL], default_comp[COMP_TOTAL]; + +// ------------------------------------------- +// Language. +extern Language_t language; + +// ------------------------------------------- +// Selected skill type, map etc. +// + +// Defaults for menu, methinks. +extern skill_t startskill; +extern int startepisode; +extern int startmap; + +extern boolean autostart; + +// Selected by user. +extern skill_t gameskill; +extern int gameepisode; +extern int gamemap; + +// Nightmare mode flag, single player. +extern boolean respawnmonsters; + +// Netgame? Only true if >1 player. +extern boolean netgame; + +// Flag: true only if started as net deathmatch. +// An enum might handle altdeath/cooperative better. +extern boolean deathmatch; + +// ------------------------------------------ +// Internal parameters for sound rendering. +// These have been taken from the DOS version, +// but are not (yet) supported with Linux +// (e.g. no sound volume adjustment with menu. + +// These are not used, but should be (menu). +// From m_menu.c: +// Sound FX volume has default, 0 - 15 +// Music volume has default, 0 - 15 +// These are multiplied by 8. +extern int snd_SfxVolume; // maximum volume for sound +extern int snd_MusicVolume; // maximum volume for music + +// CPhipps - screen parameters +extern int desired_screenwidth, desired_screenheight; + +// ------------------------- +// Status flags for refresh. +// + +enum automapmode_e { + am_none = 0, + am_active = 1, // currently shown + am_overlay= 2, // covers the screen, i.e. not overlay mode + am_rotate = 4, // rotates to the player facing direction + am_follow = 8, // keep the player centred + am_grid =16, // show grid +}; +extern enum automapmode_e automapmode; // Mode that the automap is in + +extern boolean menuactive; // Menu overlayed? +extern boolean paused; // Game Pause? +extern boolean nodrawers; +extern boolean noblit; + +// This one is related to the 3-screen display mode. +// ANG90 = left side, ANG270 = right +extern int viewangleoffset; + +// Player taking events, and displaying. +extern int consoleplayer; +extern int displayplayer; + +// ------------------------------------- +// Scores, rating. +// Statistics on a given map, for intermission. +// +extern int totalkills, totallive; +extern int totalitems; +extern int totalsecret; + +// Timer, for scores. +extern int basetic; /* killough 9/29/98: levelstarttic, adjusted */ +extern int leveltime; // tics in game play for par + +// -------------------------------------- +// DEMO playback/recording related stuff. + +extern boolean usergame; +extern boolean demoplayback; +extern boolean demorecording; +extern int demover; + +// Quit after playing a demo from cmdline. +extern boolean singledemo; +// Print timing information after quitting. killough +extern boolean timingdemo; +// Run tick clock at fastest speed possible while playing demo. killough +extern boolean fastdemo; + +extern gamestate_t gamestate; + +//----------------------------- +// Internal parameters, fixed. +// These are set by the engine, and not changed +// according to user inputs. Partly load from +// WAD, partly set at startup time. + +extern int gametic; + + +// Bookkeeping on players - state. +extern player_t players[MAXPLAYERS]; + +// Alive? Disconnected? +extern boolean playeringame[MAXPLAYERS]; +extern boolean realplayeringame[MAXPLAYERS]; + +extern mapthing_t *deathmatchstarts; // killough +extern size_t num_deathmatchstarts; // killough + +extern mapthing_t *deathmatch_p; + +// Player spawn spots. +extern mapthing_t playerstarts[]; + +// Intermission stats. +// Parameters for world map / intermission. +extern wbstartstruct_t wminfo; + +//----------------------------------------- +// Internal parameters, used for engine. +// + +// File handling stuff. +extern FILE *debugfile; + +// if true, load all graphics at level load +extern boolean precache; + +// wipegamestate can be set to -1 +// to force a wipe on the next draw +extern gamestate_t wipegamestate; + +extern int mouseSensitivity_horiz; // killough +extern int mouseSensitivity_vert; + +// debug flag to cancel adaptiveness +extern boolean singletics; + +extern int bodyqueslot; + +// Needed to store the number of the dummy sky flat. +// Used for rendering, as well as tracking projectiles etc. + +extern int skyflatnum; + +extern int maketic; + +// Networking and tick handling related. +#ifdef IPHONE +#define BACKUPTICS 32 // JDC: changed from 12 to 16 to allow and masking instead of mod +#define BACKUPTICMASK (BACKUPTICS-1) // JDC +#else +#define BACKUPTICS 12 +#endif +extern ticcmd_t netcmds[MAXPLAYERS][BACKUPTICS]; // JDC: added MAXPLAYERS +extern int ticdup; + +//----------------------------------------------------------------------------- + +extern int allow_pushers; // MT_PUSH Things // phares 3/10/98 +extern int default_allow_pushers; + +extern int variable_friction; // ice & mud // phares 3/10/98 +extern int default_variable_friction; + +extern int monsters_remember; // killough 3/1/98 +extern int default_monsters_remember; + +extern int weapon_recoil; // weapon recoil // phares +extern int default_weapon_recoil; + +extern int player_bobbing; // whether player bobs or not // phares 2/25/98 +extern int default_player_bobbing; // killough 3/1/98: make local to each game + +#ifdef DOGS +extern int dogs, default_dogs; // killough 7/19/98: Marine's best friend :) +extern int dog_jumping, default_dog_jumping; // killough 10/98 +#endif + +/* killough 8/8/98: distance friendly monsters tend to stay from player */ +extern int distfriend, default_distfriend; + +/* killough 9/8/98: whether monsters are allowed to strafe or retreat */ +extern int monster_backing, default_monster_backing; + +/* killough 9/9/98: whether monsters intelligently avoid hazards */ +extern int monster_avoid_hazards, default_monster_avoid_hazards; + +/* killough 10/98: whether monsters are affected by friction */ +extern int monster_friction, default_monster_friction; + +/* killough 9/9/98: whether monsters help friends */ +extern int help_friends, default_help_friends; + +extern int flashing_hom; // killough 10/98 + +extern int doom_weapon_toggles; // killough 10/98 + +/* killough 7/19/98: whether monsters should fight against each other */ +extern int monster_infighting, default_monster_infighting; + +extern int monkeys, default_monkeys; + +extern int HelperThing; // type of thing to use for helper + +#endif diff --git a/common/prboom/doomtype.h b/common/prboom/doomtype.h new file mode 100755 index 0000000..fb0160c --- /dev/null +++ b/common/prboom/doomtype.h @@ -0,0 +1,128 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2006 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Simple basic typedefs, isolated here to make it easier + * separating modules. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __DOOMTYPE__ +#define __DOOMTYPE__ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifndef __BYTEBOOL__ +#define __BYTEBOOL__ + +#include + +typedef int boolean; + +typedef unsigned char byte; + +#endif + +//e6y +#ifndef MAX +#define MAX(a,b) ((a)>(b)?(a):(b)) +#endif +#ifndef MIN +#define MIN(a,b) ((a)<(b)?(a):(b)) +#endif + +/* cph - Wrapper for the long long type, as Win32 used a different name. + * Except I don't know what to test as it's compiler specific + * Proff - I fixed it */ +#ifndef _MSC_VER +typedef signed long long int_64_t; +typedef unsigned long long uint_64_t; +// define compiled-specific long-long contstant notation here +#define LONGLONG(num) (uint_64_t)num ## ll +#else +typedef __int64 int_64_t; +typedef unsigned __int64 uint_64_t; +// define compiled-specific long-long contstant notation here +#define LONGLONG(num) (uint_64_t)num +#undef PATH_MAX +#define PATH_MAX 1024 +#define strcasecmp _stricmp +#define strncasecmp _strnicmp +#define S_ISDIR(x) (((sbuf.st_mode & S_IFDIR)==S_IFDIR)?1:0) +#endif + +#ifdef __GNUC__ +#define CONSTFUNC __attribute__((const)) +#define PUREFUNC __attribute__((pure)) +#define NORETURN __attribute__ ((noreturn)) +#else +#define CONSTFUNC +#define PUREFUNC +#define NORETURN +#endif + +/* CPhipps - use limits.h instead of depreciated values.h */ +#include + +/* cph - move compatibility levels here so we can use them in d_server.c */ +typedef enum { + doom_12_compatibility, /* Doom v1.2 */ + doom_1666_compatibility, /* Doom v1.666 */ + doom2_19_compatibility, /* Doom & Doom 2 v1.9 */ + ultdoom_compatibility, /* Doom 2 v1.9 */ + finaldoom_compatibility, /* Final & Ultimate Doom v1.9, and Doom95 */ + dosdoom_compatibility, /* Early dosdoom & tasdoom */ + tasdoom_compatibility, /* Early dosdoom & tasdoom */ + boom_compatibility_compatibility, /* Boom's compatibility mode */ + boom_201_compatibility, /* Compatible with Boom v2.01 */ + boom_202_compatibility, /* Compatible with Boom v2.01 */ + lxdoom_1_compatibility, /* LxDoom v1.3.2+ */ + mbf_compatibility, /* MBF */ + prboom_1_compatibility, /* PrBoom 2.03beta? */ + prboom_2_compatibility, /* PrBoom 2.1.0-2.1.1 */ + prboom_3_compatibility, /* PrBoom 2.2.x */ + prboom_4_compatibility, /* PrBoom 2.3.x */ + prboom_5_compatibility, /* PrBoom 2.4.0 */ + prboom_6_compatibility, /* Latest PrBoom */ + MAX_COMPATIBILITY_LEVEL, /* Must be last entry */ + /* Aliases follow */ + boom_compatibility = boom_201_compatibility, /* Alias used by G_Compatibility */ + best_compatibility = prboom_6_compatibility, +} complevel_t; + +/* cph - from v_video.h, needed by gl_struct.h */ +enum patch_translation_e { + VPT_NONE = 0, // Normal + VPT_FLIP = 1, // Flip image horizontally + VPT_TRANS = 2, // Translate image via a translation table + VPT_STRETCH = 4, // Stretch to compensate for high-res +}; + +#endif diff --git a/common/prboom/dstrings.c b/common/prboom/dstrings.c new file mode 100755 index 0000000..4e27ea5 --- /dev/null +++ b/common/prboom/dstrings.c @@ -0,0 +1,85 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Globally defined strings. + * + *----------------------------------------------------------------------------- + */ + +#ifdef __GNUG__ +#pragma implementation "dstrings.h" +#endif +#include "dstrings.h" + + +// killough 1/18/98: remove hardcoded limit, add const: +const char *const endmsg[]= +{ + // DOOM1 + QUITMSG, + "please don't leave, there's more\ndemons to toast!", + "let's beat it -- this is turning\ninto a bloodbath!", + "i wouldn't leave if i were you.\ndos is much worse.", + "you're trying to say you like dos\nbetter than me, right?", + "don't leave yet -- there's a\ndemon around that corner!", + "ya know, next time you come in here\ni'm gonna toast ya.", + "go ahead and leave. see if i care.", // 1/15/98 killough + + // QuitDOOM II messages + "you want to quit?\nthen, thou hast lost an eighth!", + "don't go now, there's a \ndimensional shambler waiting\nat the dos prompt!", + "get outta here and go back\nto your boring programs.", + "if i were your boss, i'd \n deathmatch ya in a minute!", + "look, bud. you leave now\nand you forfeit your body count!", + "just leave. when you come\nback, i'll be waiting with a bat.", + "you're lucky i don't smack\nyou for thinking about leaving.", // 1/15/98 killough + + // FinalDOOM? + +// Note that these ending "bad taste" strings were commented out +// in the original id code as the #else case of an #if 1 +// Obviously they were internal playthings before the release of +// DOOM2 and were not intended for public use. +// +// Following messages commented out for now. Bad taste. // phares + +// "fuck you, pussy!\nget the fuck out!", +// "you quit and i'll jizz\nin your cystholes!", +// "if you leave, i'll make\nthe lord drink my jizz.", +// "hey, ron! can we say\n'fuck' in the game?", +// "i'd leave: this is just\nmore monsters and levels.\nwhat a load.", +// "suck it down, asshole!\nyou're a fucking wimp!", +// "don't quit now! we're \nstill spending your money!", + + // Internal debug. Different style, too. + "THIS IS NO MESSAGE!\nPage intentionally left blank.", // 1/15/98 killough +}; + +// killough 1/18/98: remove hardcoded limit and replace with var (silly hack): +const size_t NUM_QUITMESSAGES = sizeof(endmsg)/sizeof(*endmsg) - 1; diff --git a/common/prboom/dstrings.h b/common/prboom/dstrings.h new file mode 100755 index 0000000..abb77f8 --- /dev/null +++ b/common/prboom/dstrings.h @@ -0,0 +1,80 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * DOOM strings, by language. + * Note: In BOOM, some new strings hav ebeen defined that are + * not found in the French version. A better approach is + * to create a BEX text-replacement file for other + * languages since any language can be supported that way + * without recompiling the program. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __DSTRINGS__ +#define __DSTRINGS__ + +/* All important printed strings. + * Language selection (message strings). + * Use -DFRENCH etc. + */ + +#ifdef FRENCH +#include "d_french.h" +#else +#include "d_englsh.h" +#endif + +/* Note this is not externally modifiable through DEH/BEX + * Misc. other strings. + * #define SAVEGAMENAME "boomsav" * killough 3/22/98 * + * Ty 05/04/98 - replaced with a modifiable string, see d_deh.c + */ + +/* + * File locations, + * relative to current position. + * Path names are OS-sensitive. + */ +#define DEVMAPS "devmaps" +#define DEVDATA "devdata" + + +/* Not done in french? + * QuitDOOM messages * + * killough 1/18/98: + * replace hardcoded limit with extern var (silly hack, I know) + */ + +#include + +extern const size_t NUM_QUITMESSAGES; /* Calculated in dstrings.c */ + +extern const char* const endmsg[]; /* killough 1/18/98 const added */ + +#endif diff --git a/common/prboom/f_finale.c b/common/prboom/f_finale.c new file mode 100755 index 0000000..1a96c33 --- /dev/null +++ b/common/prboom/f_finale.c @@ -0,0 +1,668 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Game completion, final screen animation. + * + *----------------------------------------------------------------------------- + */ + +#include "doomstat.h" +#include "d_event.h" +#include "v_video.h" +#include "w_wad.h" +#include "s_sound.h" +#include "sounds.h" +#include "d_deh.h" // Ty 03/22/98 - externalizations +#include "f_finale.h" // CPhipps - hmm... + +// Stage of animation: +// 0 = text, 1 = art screen, 2 = character cast +static int finalestage; // cph - +static int finalecount; // made static +static const char* finaletext; // cph - +static const char* finaleflat; // made static const + +// defines for the end mission display text // phares + +#define TEXTSPEED 3 // original value // phares +#define TEXTWAIT 250 // original value // phares +#define NEWTEXTSPEED 0.01f // new value // phares +#define NEWTEXTWAIT 1000 // new value // phares + +// CPhipps - removed the old finale screen text message strings; +// they were commented out for ages already +// Ty 03/22/98 - ... the new s_WHATEVER extern variables are used +// in the code below instead. + +void F_StartCast (void); +void F_CastTicker (void); +boolean F_CastResponder (event_t *ev); +void F_CastDrawer (void); + +void WI_checkForAccelerate(void); // killough 3/28/98: used to +extern int acceleratestage; // accelerate intermission screens +static int midstage; // whether we're in "mid-stage" + +// +// F_StartFinale +// +void F_StartFinale (void) +{ + gameaction = ga_nothing; + gamestate = GS_FINALE; + automapmode &= ~am_active; + + // killough 3/28/98: clear accelerative text flags + acceleratestage = midstage = 0; + + // Okay - IWAD dependend stuff. + // This has been changed severly, and + // some stuff might have changed in the process. + switch ( gamemode ) + { + // DOOM 1 - E1, E3 or E4, but each nine missions + case shareware: + case registered: + case retail: + { + S_ChangeMusic(mus_victor, true); + + switch (gameepisode) + { + case 1: + finaleflat = bgflatE1; // Ty 03/30/98 - new externalized bg flats + finaletext = s_E1TEXT; // Ty 03/23/98 - Was e1text variable. + break; + case 2: + finaleflat = bgflatE2; + finaletext = s_E2TEXT; // Ty 03/23/98 - Same stuff for each + break; + case 3: + finaleflat = bgflatE3; + finaletext = s_E3TEXT; + break; + case 4: + finaleflat = bgflatE4; + finaletext = s_E4TEXT; + break; + default: + // Ouch. + break; + } + break; + } + + // DOOM II and missions packs with E1, M34 + case commercial: + { + S_ChangeMusic(mus_read_m, true); + + // Ty 08/27/98 - added the gamemission logic + switch (gamemap) + { + case 6: + finaleflat = bgflat06; + finaletext = (gamemission==pack_tnt) ? s_T1TEXT : + (gamemission==pack_plut) ? s_P1TEXT : s_C1TEXT; + break; + case 11: + finaleflat = bgflat11; + finaletext = (gamemission==pack_tnt) ? s_T2TEXT : + (gamemission==pack_plut) ? s_P2TEXT : s_C2TEXT; + break; + case 20: + finaleflat = bgflat20; + finaletext = (gamemission==pack_tnt) ? s_T3TEXT : + (gamemission==pack_plut) ? s_P3TEXT : s_C3TEXT; + break; + case 30: + finaleflat = bgflat30; + finaletext = (gamemission==pack_tnt) ? s_T4TEXT : + (gamemission==pack_plut) ? s_P4TEXT : s_C4TEXT; + break; + case 15: + finaleflat = bgflat15; + finaletext = (gamemission==pack_tnt) ? s_T5TEXT : + (gamemission==pack_plut) ? s_P5TEXT : s_C5TEXT; + break; + case 31: + finaleflat = bgflat31; + finaletext = (gamemission==pack_tnt) ? s_T6TEXT : + (gamemission==pack_plut) ? s_P6TEXT : s_C6TEXT; + break; + default: + // Ouch. + break; + } + break; + // Ty 08/27/98 - end gamemission logic + } + + // Indeterminate. + default: // Ty 03/30/98 - not externalized + S_ChangeMusic(mus_read_m, true); + finaleflat = "F_SKY1"; // Not used anywhere else. + finaletext = s_C1TEXT; // FIXME - other text, music? + break; + } + + finalestage = 0; + finalecount = 0; +} + + + +boolean F_Responder (event_t *event) +{ + if (finalestage == 2) + return F_CastResponder (event); + + return false; +} + +// Get_TextSpeed() returns the value of the text display speed // phares +// Rewritten to allow user-directed acceleration -- killough 3/28/98 + +static float Get_TextSpeed(void) +{ + return midstage ? NEWTEXTSPEED : (midstage=acceleratestage) ? + acceleratestage=0, NEWTEXTSPEED : TEXTSPEED; +} + + +// +// F_Ticker +// +// killough 3/28/98: almost totally rewritten, to use +// player-directed acceleration instead of constant delays. +// Now the player can accelerate the text display by using +// the fire/use keys while it is being printed. The delay +// automatically responds to the user, and gives enough +// time to read. +// +// killough 5/10/98: add back v1.9 demo compatibility +// + +void F_Ticker(void) +{ + int i; + if (!demo_compatibility) + WI_checkForAccelerate(); // killough 3/28/98: check for acceleration + else + if (gamemode == commercial && finalecount > 50) // check for skipping + for (i=0; i strlen(finaletext)*speed + + (midstage ? NEWTEXTWAIT : TEXTWAIT) || + (midstage && acceleratestage)) { + if (gamemode != commercial) // Doom 1 / Ultimate Doom episode end + { // with enough time, it's automatic + finalecount = 0; + finalestage = 1; + wipegamestate = -1; // force a wipe + if (gameepisode == 3) + S_StartMusic(mus_bunny); + } + else // you must press a button to continue in Doom 2 + if (!demo_compatibility && midstage) + { + next_level: + if (gamemap == 30) + F_StartCast(); // cast of Doom 2 characters + else + gameaction = ga_worlddone; // next level, e.g. MAP07 + } + } + } +} + +// +// F_TextWrite +// +// This program displays the background and text at end-mission // phares +// text time. It draws both repeatedly so that other displays, // | +// like the main menu, can be drawn over it dynamically and // V +// erased dynamically. The TEXTSPEED constant is changed into +// the Get_TextSpeed function so that the speed of writing the // ^ +// text can be increased, and there's still time to read what's // | +// written. // phares +// CPhipps - reformatted + +#include "hu_stuff.h" +extern patchnum_t hu_font[HU_FONTSIZE]; + + +static void F_TextWrite (void) +{ + V_DrawBackground(finaleflat, 0); + { // draw some of the text onto the screen + int cx = 10; + int cy = 10; + const char* ch = finaletext; // CPhipps - const + int count = (int)((float)(finalecount - 10)/Get_TextSpeed()); // phares + int w; + + if (count < 0) + count = 0; + + for ( ; count ; count-- ) { + int c = *ch++; + + if (!c) + break; + if (c == '\n') { + cx = 10; + cy += 11; + continue; + } + + c = toupper(c) - HU_FONTSTART; + if (c < 0 || c> HU_FONTSIZE) { + cx += 4; + continue; + } + + w = hu_font[c].width; + if (cx+w > SCREENWIDTH) + break; + // CPhipps - patch drawing updated + V_DrawNumPatch(cx, cy, 0, hu_font[c].lumpnum, CR_DEFAULT, VPT_STRETCH); + cx+=w; + } + } +} + +// +// Final DOOM 2 animation +// Casting by id Software. +// in order of appearance +// +typedef struct +{ + const char **name; // CPhipps - const** + mobjtype_t type; +} castinfo_t; + +#define MAX_CASTORDER 18 /* Ty - hard coded for now */ +static const castinfo_t castorder[] = { // CPhipps - static const, initialised here + { &s_CC_ZOMBIE, MT_POSSESSED }, + { &s_CC_SHOTGUN, MT_SHOTGUY }, + { &s_CC_HEAVY, MT_CHAINGUY }, + { &s_CC_IMP, MT_TROOP }, + { &s_CC_DEMON, MT_SERGEANT }, + { &s_CC_LOST, MT_SKULL }, + { &s_CC_CACO, MT_HEAD }, + { &s_CC_HELL, MT_KNIGHT }, + { &s_CC_BARON, MT_BRUISER }, + { &s_CC_ARACH, MT_BABY }, + { &s_CC_PAIN, MT_PAIN }, + { &s_CC_REVEN, MT_UNDEAD }, + { &s_CC_MANCU, MT_FATSO }, + { &s_CC_ARCH, MT_VILE }, + { &s_CC_SPIDER, MT_SPIDER }, + { &s_CC_CYBER, MT_CYBORG }, + { &s_CC_HERO, MT_PLAYER }, + { NULL, 0} + }; + +int castnum; +int casttics; +state_t* caststate; +boolean castdeath; +int castframes; +int castonmelee; +boolean castattacking; + + +// +// F_StartCast +// + +void F_StartCast (void) +{ + wipegamestate = -1; // force a screen wipe + castnum = 0; + caststate = &states[mobjinfo[castorder[castnum].type].seestate]; + casttics = caststate->tics; + castdeath = false; + finalestage = 2; + castframes = 0; + castonmelee = 0; + castattacking = false; + S_ChangeMusic(mus_evil, true); +} + + +// +// F_CastTicker +// +void F_CastTicker (void) +{ + int st; + int sfx; + + if (--casttics > 0) + return; // not time to change state yet + + if (caststate->tics == -1 || caststate->nextstate == S_NULL) + { + // switch from deathstate to next monster + castnum++; + castdeath = false; + if (castorder[castnum].name == NULL) + castnum = 0; + if (mobjinfo[castorder[castnum].type].seesound) + S_StartSound (NULL, mobjinfo[castorder[castnum].type].seesound); + caststate = &states[mobjinfo[castorder[castnum].type].seestate]; + castframes = 0; + } + else + { + // just advance to next state in animation + if (caststate == &states[S_PLAY_ATK1]) + goto stopattack; // Oh, gross hack! + st = caststate->nextstate; + caststate = &states[st]; + castframes++; + + // sound hacks.... + switch (st) + { + case S_PLAY_ATK1: sfx = sfx_dshtgn; break; + case S_POSS_ATK2: sfx = sfx_pistol; break; + case S_SPOS_ATK2: sfx = sfx_shotgn; break; + case S_VILE_ATK2: sfx = sfx_vilatk; break; + case S_SKEL_FIST2: sfx = sfx_skeswg; break; + case S_SKEL_FIST4: sfx = sfx_skepch; break; + case S_SKEL_MISS2: sfx = sfx_skeatk; break; + case S_FATT_ATK8: + case S_FATT_ATK5: + case S_FATT_ATK2: sfx = sfx_firsht; break; + case S_CPOS_ATK2: + case S_CPOS_ATK3: + case S_CPOS_ATK4: sfx = sfx_shotgn; break; + case S_TROO_ATK3: sfx = sfx_claw; break; + case S_SARG_ATK2: sfx = sfx_sgtatk; break; + case S_BOSS_ATK2: + case S_BOS2_ATK2: + case S_HEAD_ATK2: sfx = sfx_firsht; break; + case S_SKULL_ATK2: sfx = sfx_sklatk; break; + case S_SPID_ATK2: + case S_SPID_ATK3: sfx = sfx_shotgn; break; + case S_BSPI_ATK2: sfx = sfx_plasma; break; + case S_CYBER_ATK2: + case S_CYBER_ATK4: + case S_CYBER_ATK6: sfx = sfx_rlaunc; break; + case S_PAIN_ATK3: sfx = sfx_sklatk; break; + default: sfx = 0; break; + } + + if (sfx) + S_StartSound (NULL, sfx); + } + + if (castframes == 12) + { + // go into attack frame + castattacking = true; + if (castonmelee) + caststate=&states[mobjinfo[castorder[castnum].type].meleestate]; + else + caststate=&states[mobjinfo[castorder[castnum].type].missilestate]; + castonmelee ^= 1; + if (caststate == &states[S_NULL]) + { + if (castonmelee) + caststate= + &states[mobjinfo[castorder[castnum].type].meleestate]; + else + caststate= + &states[mobjinfo[castorder[castnum].type].missilestate]; + } + } + + if (castattacking) + { + if (castframes == 24 + || caststate == &states[mobjinfo[castorder[castnum].type].seestate] ) + { + stopattack: + castattacking = false; + castframes = 0; + caststate = &states[mobjinfo[castorder[castnum].type].seestate]; + } + } + + casttics = caststate->tics; + if (casttics == -1) + casttics = 15; +} + + +// +// F_CastResponder +// + +boolean F_CastResponder (event_t* ev) +{ + if (ev->type != ev_keydown) + return false; + + if (castdeath) + return true; // already in dying frames + + // go into death frame + castdeath = true; + caststate = &states[mobjinfo[castorder[castnum].type].deathstate]; + casttics = caststate->tics; + castframes = 0; + castattacking = false; + if (mobjinfo[castorder[castnum].type].deathsound) + S_StartSound (NULL, mobjinfo[castorder[castnum].type].deathsound); + + return true; +} + + +static void F_CastPrint (const char* text) // CPhipps - static, const char* +{ + const char* ch; // CPhipps - const + int c; + int cx; + int w; + int width; + + // find width + ch = text; + width = 0; + + while (ch) + { + c = *ch++; + if (!c) + break; + c = toupper(c) - HU_FONTSTART; + if (c < 0 || c> HU_FONTSIZE) + { + width += 4; + continue; + } + + w = hu_font[c].width; + width += w; + } + + // draw it + cx = 160-width/2; + ch = text; + while (ch) + { + c = *ch++; + if (!c) + break; + c = toupper(c) - HU_FONTSTART; + if (c < 0 || c> HU_FONTSIZE) + { + cx += 4; + continue; + } + + w = hu_font[c].width; + // CPhipps - patch drawing updated + V_DrawNumPatch(cx, 180, 0, hu_font[c].lumpnum, CR_DEFAULT, VPT_STRETCH); + cx+=w; + } +} + + +// +// F_CastDrawer +// + +void F_CastDrawer (void) +{ + spritedef_t* sprdef; + spriteframe_t* sprframe; + int lump; + boolean flip; + + // erase the entire screen to a background + // CPhipps - patch drawing updated + V_DrawNamePatch(0,0,0, bgcastcall, CR_DEFAULT, VPT_STRETCH); // Ty 03/30/98 bg texture extern + + F_CastPrint (*(castorder[castnum].name)); + + // draw the current frame in the middle of the screen + sprdef = &sprites[caststate->sprite]; + sprframe = &sprdef->spriteframes[ caststate->frame & FF_FRAMEMASK]; + lump = sprframe->lump[0]; + flip = (boolean)sprframe->flip[0]; + + // CPhipps - patch drawing updated + V_DrawNumPatch(160, 170, 0, lump+firstspritelump, CR_DEFAULT, + VPT_STRETCH | (flip ? VPT_FLIP : 0)); +} + +// +// F_BunnyScroll +// +static const char pfub2[] = { "PFUB2" }; +static const char pfub1[] = { "PFUB1" }; + +static void F_BunnyScroll (void) +{ + char name[10]; + int stage; + static int laststage; + + { + int scrolled = 320 - (finalecount-230)/2; + if (scrolled <= 0) { + V_DrawNamePatch(0, 0, 0, pfub2, CR_DEFAULT, VPT_STRETCH); + } else if (scrolled >= 320) { + V_DrawNamePatch(0, 0, 0, pfub1, CR_DEFAULT, VPT_STRETCH); + } else { + V_DrawNamePatch(320-scrolled, 0, 0, pfub1, CR_DEFAULT, VPT_STRETCH); + V_DrawNamePatch(-scrolled, 0, 0, pfub2, CR_DEFAULT, VPT_STRETCH); + } + } + + if (finalecount < 1130) + return; + if (finalecount < 1180) + { + // CPhipps - patch drawing updated + V_DrawNamePatch((320-13*8)/2, (200-8*8)/2,0, "END0", CR_DEFAULT, VPT_STRETCH); + laststage = 0; + return; + } + + stage = (finalecount-1180) / 5; + if (stage > 6) + stage = 6; + if (stage > laststage) + { + S_StartSound (NULL, sfx_pistol); + laststage = stage; + } + + sprintf (name,"END%i",stage); + // CPhipps - patch drawing updated + V_DrawNamePatch((320-13*8)/2, (200-8*8)/2, 0, name, CR_DEFAULT, VPT_STRETCH); +} + + +// +// F_Drawer +// +void F_Drawer (void) +{ + if (finalestage == 2) + { + F_CastDrawer (); + return; + } + + if (!finalestage) + F_TextWrite (); + else + { + switch (gameepisode) + { + // CPhipps - patch drawing updated + case 1: + if ( gamemode == retail ) + V_DrawNamePatch(0, 0, 0, "CREDIT", CR_DEFAULT, VPT_STRETCH); + else + V_DrawNamePatch(0, 0, 0, "HELP2", CR_DEFAULT, VPT_STRETCH); + break; + case 2: + V_DrawNamePatch(0, 0, 0, "VICTORY2", CR_DEFAULT, VPT_STRETCH); + break; + case 3: + F_BunnyScroll (); + break; + case 4: + V_DrawNamePatch(0, 0, 0, "ENDPIC", CR_DEFAULT, VPT_STRETCH); + break; + } + } +} diff --git a/common/prboom/f_finale.h b/common/prboom/f_finale.h new file mode 100755 index 0000000..6214f38 --- /dev/null +++ b/common/prboom/f_finale.h @@ -0,0 +1,56 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Related to f_finale.c, which is called at the end of a level + * + *-----------------------------------------------------------------------------*/ + + +#ifndef __F_FINALE__ +#define __F_FINALE__ + +#include "doomtype.h" +#include "d_event.h" + +/* + * FINALE + */ + +/* Called by main loop. */ +boolean F_Responder (event_t* ev); + +/* Called by main loop. */ +void F_Ticker (void); + +/* Called by main loop. */ +void F_Drawer (void); + +void F_StartFinale (void); + +#endif diff --git a/common/prboom/f_wipe.c b/common/prboom/f_wipe.c new file mode 100755 index 0000000..fc3ac1d --- /dev/null +++ b/common/prboom/f_wipe.c @@ -0,0 +1,202 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Mission begin melt/wipe screen special effect. + * + *----------------------------------------------------------------------------- + */ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "z_zone.h" +#include "doomdef.h" +#include "i_video.h" +#include "v_video.h" +#include "m_random.h" +#include "f_wipe.h" + +// +// SCREEN WIPE PACKAGE +// + +// Parts re-written to support true-color video modes. Column-major +// formatting removed. - POPE + +// CPhipps - macros for the source and destination screens +#define SRC_SCR 2 +#define DEST_SCR 3 + +static screeninfo_t wipe_scr_start; +static screeninfo_t wipe_scr_end; +static screeninfo_t wipe_scr; + +static int y_lookup[MAX_SCREENWIDTH]; + + +static int wipe_initMelt(int ticks) +{ + int i; + + // copy start screen to main screen + for(i=0;i not ready to scroll yet) + y_lookup[0] = -(M_Random()%16); + for (i=1;i 0) + y_lookup[i] = 0; + else + if (y_lookup[i] == -16) + y_lookup[i] = -15; + } + return 0; +} + +static int wipe_doMelt(int ticks) +{ + boolean done = true; + int i; + const int depth = V_GetPixelDepth(); + + while (ticks--) { + for (i=0;i<(SCREENWIDTH);i++) { + if (y_lookup[i]<0) { + y_lookup[i]++; + done = false; + continue; + } + if (y_lookup[i] < SCREENHEIGHT) { + byte *s, *d; + int j, k, dy; + + /* cph 2001/07/29 - + * The original melt rate was 8 pixels/sec, i.e. 25 frames to melt + * the whole screen, so make the melt rate depend on SCREENHEIGHT + * so it takes no longer in high res + */ + dy = (y_lookup[i] < 16) ? y_lookup[i]+1 : SCREENHEIGHT/25; + if (y_lookup[i]+dy >= SCREENHEIGHT) + dy = SCREENHEIGHT - y_lookup[i]; + + s = wipe_scr_end.data + (y_lookup[i]*wipe_scr_end.byte_pitch+(i*depth)); + d = wipe_scr.data + (y_lookup[i]*wipe_scr.byte_pitch+(i*depth)); + for (j=dy;j;j--) { + for (k=0; k +#include +#include +#ifdef _MSC_VER +#define F_OK 0 /* Check for file existence */ +#define W_OK 2 /* Check for write permission */ +#define R_OK 4 /* Check for read permission */ +#include +#else +#include +#endif +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "doomstat.h" +#include "d_net.h" +#include "f_finale.h" +#include "m_argv.h" +#include "m_misc.h" +#include "m_menu.h" +#include "m_random.h" +#include "p_setup.h" +#include "p_saveg.h" +#include "p_tick.h" +#include "p_map.h" +#include "p_checksum.h" +#include "d_main.h" +#include "wi_stuff.h" +#include "hu_stuff.h" +#include "st_stuff.h" +#include "am_map.h" +#include "w_wad.h" +#include "r_main.h" +#include "r_draw.h" +#include "p_map.h" +#include "s_sound.h" +#include "dstrings.h" +#include "sounds.h" +#include "r_data.h" +#include "r_sky.h" +#include "d_deh.h" // Ty 3/27/98 deh declarations +#include "p_inter.h" +#include "g_game.h" +#include "lprintf.h" +#include "i_main.h" +#include "i_system.h" +#include "r_demo.h" +#include "r_fps.h" + +void iphoneStartLevel(); +void iphoneIntermission(); +void iphoneMainMenu(); + +#define SAVEGAMESIZE 0x20000 +#define SAVESTRINGSIZE 24 + +static size_t savegamesize = SAVEGAMESIZE; // killough +static boolean netdemo; +static const byte *demobuffer; /* cph - only used for playback */ +static int demolength; // check for overrun (missing DEMOMARKER) +static FILE *demofp; /* cph - record straight to file */ +static const byte *demo_p; +/* static JDC removed */ short consistancy[MAXPLAYERS][BACKUPTICS]; + +gameaction_t gameaction; +gamestate_t gamestate; +skill_t gameskill; +boolean respawnmonsters; +int gameepisode; +int gamemap; +boolean paused; +// CPhipps - moved *_loadgame vars here +static boolean forced_loadgame = false; +static boolean command_loadgame = false; + +boolean usergame; // ok to save / end game +boolean timingdemo; // if true, exit with report on completion +boolean fastdemo; // if true, run at full speed -- killough +boolean nodrawers; // for comparative timing purposes +boolean noblit; // for comparative timing purposes +int starttime; // for comparative timing purposes +boolean deathmatch; // only if started as net death +boolean netgame; // only true if packets are broadcast +boolean playeringame[MAXPLAYERS]; +player_t players[MAXPLAYERS]; +int consoleplayer; // player taking events and displaying +int displayplayer; // view being displayed +int gametic; +int basetic; /* killough 9/29/98: for demo sync */ +int totalkills, totallive, totalitems, totalsecret; // for intermission +boolean demorecording; +boolean demoplayback; +int demover; +boolean singledemo; // quit after playing a demo from cmdline +wbstartstruct_t wminfo; // parms for world map / intermission +boolean haswolflevels = false;// jff 4/18/98 wolf levels present +static byte *savebuffer; // CPhipps - static +int autorun = false; // always running? // phares +int totalleveltimes; // CPhipps - total time for all completed levels +int longtics; + +// +// controls (have defaults) +// + +int key_right; +int key_left; +int key_up; +int key_down; +int key_menu_right; // phares 3/7/98 +int key_menu_left; // | +int key_menu_up; // V +int key_menu_down; +int key_menu_backspace; // ^ +int key_menu_escape; // | +int key_menu_enter; // phares 3/7/98 +int key_strafeleft; +int key_straferight; +int key_fire; +int key_use; +int key_strafe; +int key_speed; +int key_escape = KEYD_ESCAPE; // phares 4/13/98 +int key_savegame; // phares +int key_loadgame; // | +int key_autorun; // V +int key_reverse; +int key_zoomin; +int key_zoomout; +int key_chat; +int key_backspace; +int key_enter; +int key_map_right; +int key_map_left; +int key_map_up; +int key_map_down; +int key_map_zoomin; +int key_map_zoomout; +int key_map; +int key_map_gobig; +int key_map_follow; +int key_map_mark; +int key_map_clear; +int key_map_grid; +int key_map_overlay; // cph - map overlay +int key_map_rotate; // cph - map rotation +int key_help = KEYD_F1; // phares 4/13/98 +int key_soundvolume; +int key_hud; +int key_quicksave; +int key_endgame; +int key_messages; +int key_quickload; +int key_quit; +int key_gamma; +int key_spy; +int key_pause; +int key_setup; +int destination_keys[MAXPLAYERS]; +int key_weapontoggle; +int key_weapon1; +int key_weapon2; +int key_weapon3; +int key_weapon4; +int key_weapon5; +int key_weapon6; +int key_weapon7; // ^ +int key_weapon8; // | +int key_weapon9; // phares + +int key_screenshot; // killough 2/22/98: screenshot key +int mousebfire; +int mousebstrafe; +int mousebforward; +int joybfire; +int joybstrafe; +int joybuse; +int joybspeed; + +#define MAXPLMOVE (forwardmove[1]) +#define TURBOTHRESHOLD 0x32 +#define SLOWTURNTICS 6 +#define QUICKREVERSE (short)32768 // 180 degree reverse // phares +#define NUMKEYS 512 + +fixed_t forwardmove[2] = {0x19, 0x32}; +fixed_t sidemove[2] = {0x18, 0x28}; +fixed_t angleturn[3] = {640, 1280, 320}; // + slow turn + +// CPhipps - made lots of key/button state vars static +static boolean gamekeydown[NUMKEYS]; +static int turnheld; // for accelerative turning + +static boolean mousearray[4]; +static boolean *mousebuttons = &mousearray[1]; // allow [-1] + +// mouse values are used once +static int mousex; +static int mousey; +static int dclicktime; +static int dclickstate; +static int dclicks; +static int dclicktime2; +static int dclickstate2; +static int dclicks2; + +// joystick values are repeated +static int joyxmove; +static int joyymove; +static boolean joyarray[5]; +static boolean *joybuttons = &joyarray[1]; // allow [-1] + +// Game events info +static buttoncode_t special_event; // Event triggered by local player, to send +static byte savegameslot; // Slot to load if gameaction == ga_loadgame +char savedescription[SAVEDESCLEN]; // Description to save in savegame if gameaction == ga_savegame + +//jff 3/24/98 define defaultskill here +int defaultskill; //note 1-based + +// killough 2/8/98: make corpse queue variable in size +int bodyqueslot, bodyquesize; // killough 2/8/98 +mobj_t **bodyque = 0; // phares 8/10/98 + +/* JDC: removed static */ void G_DoSaveGame (boolean menu); +static const byte* G_ReadDemoHeader(const byte* demo_p, size_t size, boolean failonerror); + +// +// G_BuildTiccmd +// Builds a ticcmd from all of the available inputs +// or reads it from the demo buffer. +// If recording a demo, write it out +// +static inline signed char fudgef(signed char b) +{ + static int c; + if (!b || !demo_compatibility || longtics) return b; + if (++c & 0x1f) return b; + b |= 1; if (b>2) b-=2; + return b; +} + +static inline signed short fudgea(signed short b) +{ + if (!b || !demo_compatibility || !longtics) return b; + b |= 1; if (b>2) b-=2; + return b; +} + + +void G_BuildTiccmd(ticcmd_t* cmd) +{ + boolean strafe; + boolean bstrafe; + int speed; + int tspeed; + int forward; + int side; + int newweapon; // phares + /* cphipps - remove needless I_BaseTiccmd call, just set the ticcmd to zero */ + memset(cmd,0,sizeof*cmd); + cmd->consistancy = consistancy[consoleplayer][maketic%BACKUPTICS]; + + strafe = gamekeydown[key_strafe] || mousebuttons[mousebstrafe] + || joybuttons[joybstrafe]; + //e6y: the "RUN" key inverts the autorun state + speed = (gamekeydown[key_speed] || joybuttons[joybspeed] ? !autorun : autorun); // phares + + forward = side = 0; + + // use two stage accelerative turning + // on the keyboard and joystick + if (joyxmove < 0 || joyxmove > 0 || + gamekeydown[key_right] || gamekeydown[key_left]) + turnheld += ticdup; + else + turnheld = 0; + + if (turnheld < SLOWTURNTICS) + tspeed = 2; // slow turn + else + tspeed = speed; + + // turn 180 degrees in one keystroke? // phares + // | + if (gamekeydown[key_reverse]) // V + { + cmd->angleturn += QUICKREVERSE; // ^ + gamekeydown[key_reverse] = false; // | + } // phares + + // let movement keys cancel each other out + + if (strafe) + { + if (gamekeydown[key_right]) + side += sidemove[speed]; + if (gamekeydown[key_left]) + side -= sidemove[speed]; + if (joyxmove > 0) + side += sidemove[speed]; + if (joyxmove < 0) + side -= sidemove[speed]; + } + else + { + if (gamekeydown[key_right]) + cmd->angleturn -= angleturn[tspeed]; + if (gamekeydown[key_left]) + cmd->angleturn += angleturn[tspeed]; + if (joyxmove > 0) + cmd->angleturn -= angleturn[tspeed]; + if (joyxmove < 0) + cmd->angleturn += angleturn[tspeed]; + } + + if (gamekeydown[key_up]) + forward += forwardmove[speed]; + if (gamekeydown[key_down]) + forward -= forwardmove[speed]; + if (joyymove < 0) + forward += forwardmove[speed]; + if (joyymove > 0) + forward -= forwardmove[speed]; + if (gamekeydown[key_straferight]) + side += sidemove[speed]; + if (gamekeydown[key_strafeleft]) + side -= sidemove[speed]; + + // buttons + cmd->chatchar = HU_dequeueChatChar(); + + if (gamekeydown[key_fire] || mousebuttons[mousebfire] || + joybuttons[joybfire]) + cmd->buttons |= BT_ATTACK; + + if (gamekeydown[key_use] || joybuttons[joybuse]) + { + cmd->buttons |= BT_USE; + // clear double clicks if hit use button + dclicks = 0; + } + + // Toggle between the top 2 favorite weapons. // phares + // If not currently aiming one of these, switch to // phares + // the favorite. Only switch if you possess the weapon. // phares + + // killough 3/22/98: + // + // Perform automatic weapons switch here rather than in p_pspr.c, + // except in demo_compatibility mode. + // + // killough 3/26/98, 4/2/98: fix autoswitch when no weapons are left + + if ((!demo_compatibility && players[consoleplayer].attackdown && // killough + !P_CheckAmmo(&players[consoleplayer])) || gamekeydown[key_weapontoggle]) + newweapon = P_SwitchWeapon(&players[consoleplayer]); // phares + else + { // phares 02/26/98: Added gamemode checks + newweapon = + gamekeydown[key_weapon1] ? wp_fist : // killough 5/2/98: reformatted + gamekeydown[key_weapon2] ? wp_pistol : + gamekeydown[key_weapon3] ? wp_shotgun : + gamekeydown[key_weapon4] ? wp_chaingun : + gamekeydown[key_weapon5] ? wp_missile : + gamekeydown[key_weapon6] && gamemode != shareware ? wp_plasma : + gamekeydown[key_weapon7] && gamemode != shareware ? wp_bfg : + gamekeydown[key_weapon8] ? wp_chainsaw : + (!demo_compatibility && gamekeydown[key_weapon9] && gamemode == commercial) ? wp_supershotgun : + wp_nochange; + + // killough 3/22/98: For network and demo consistency with the + // new weapons preferences, we must do the weapons switches here + // instead of in p_user.c. But for old demos we must do it in + // p_user.c according to the old rules. Therefore demo_compatibility + // determines where the weapons switch is made. + + // killough 2/8/98: + // Allow user to switch to fist even if they have chainsaw. + // Switch to fist or chainsaw based on preferences. + // Switch to shotgun or SSG based on preferences. + + if (!demo_compatibility) + { + const player_t *player = &players[consoleplayer]; + + // only select chainsaw from '1' if it's owned, it's + // not already in use, and the player prefers it or + // the fist is already in use, or the player does not + // have the berserker strength. + + if (newweapon==wp_fist && player->weaponowned[wp_chainsaw] && + player->readyweapon!=wp_chainsaw && + (player->readyweapon==wp_fist || + !player->powers[pw_strength] || + P_WeaponPreferred(wp_chainsaw, wp_fist))) + newweapon = wp_chainsaw; + + // Select SSG from '3' only if it's owned and the player + // does not have a shotgun, or if the shotgun is already + // in use, or if the SSG is not already in use and the + // player prefers it. + + if (newweapon == wp_shotgun && gamemode == commercial && + player->weaponowned[wp_supershotgun] && + (!player->weaponowned[wp_shotgun] || + player->readyweapon == wp_shotgun || + (player->readyweapon != wp_supershotgun && + P_WeaponPreferred(wp_supershotgun, wp_shotgun)))) + newweapon = wp_supershotgun; + } + // killough 2/8/98, 3/22/98 -- end of weapon selection changes + } + + if (newweapon != wp_nochange) + { + cmd->buttons |= BT_CHANGE; + cmd->buttons |= newweapon< 1 ) + { + dclickstate = mousebuttons[mousebforward]; + if (dclickstate) + dclicks++; + if (dclicks == 2) + { + cmd->buttons |= BT_USE; + dclicks = 0; + } + else + dclicktime = 0; + } + else + if ((dclicktime += ticdup) > 20) + { + dclicks = 0; + dclickstate = 0; + } + + // strafe double click + + bstrafe = mousebuttons[mousebstrafe] || joybuttons[joybstrafe]; + if (bstrafe != dclickstate2 && dclicktime2 > 1 ) + { + dclickstate2 = bstrafe; + if (dclickstate2) + dclicks2++; + if (dclicks2 == 2) + { + cmd->buttons |= BT_USE; + dclicks2 = 0; + } + else + dclicktime2 = 0; + } + else + if ((dclicktime2 += ticdup) > 20) + { + dclicks2 = 0; + dclickstate2 = 0; + } + forward += mousey; + if (strafe) + side += mousex / 4; /* mead Don't want to strafe as fast as turns.*/ + else + cmd->angleturn -= mousex; /* mead now have enough dynamic range 2-10-00 */ + + mousex = mousey = 0; + + if (forward > MAXPLMOVE) + forward = MAXPLMOVE; + else if (forward < -MAXPLMOVE) + forward = -MAXPLMOVE; + if (side > MAXPLMOVE) + side = MAXPLMOVE; + else if (side < -MAXPLMOVE) + side = -MAXPLMOVE; + + cmd->forwardmove += fudgef((signed char)forward); + cmd->sidemove += side; + cmd->angleturn = fudgea(cmd->angleturn); + + // CPhipps - special events (game new/load/save/pause) + if (special_event & BT_SPECIAL) { + cmd->buttons = special_event; + special_event = 0; + } +} + +// +// G_RestartLevel +// + +void G_RestartLevel(void) +{ + special_event = BT_SPECIAL | (BTS_RESTARTLEVEL & BT_SPECIALMASK); +} + +#include "z_bmalloc.h" +// +// G_DoLoadLevel +// + +static void G_DoLoadLevel (void) +{ + int i; + + // Set the sky map. + // First thing, we have a dummy sky texture name, + // a flat. The data is in the WAD only because + // we look for an actual index, instead of simply + // setting one. + + skyflatnum = R_FlatNumForName ( SKYFLATNAME ); + + // DOOM determines the sky texture to be used + // depending on the current episode, and the game version. + if (gamemode == commercial) + // || gamemode == pack_tnt //jff 3/27/98 sorry guys pack_tnt,pack_plut + // || gamemode == pack_plut) //aren't gamemodes, this was matching retail + { + skytexture = R_TextureNumForName ("SKY3"); + if (gamemap < 12) + skytexture = R_TextureNumForName ("SKY1"); + else + if (gamemap < 21) + skytexture = R_TextureNumForName ("SKY2"); + } + else //jff 3/27/98 and lets not forget about DOOM and Ultimate DOOM huh? + switch (gameepisode) + { + case 1: + skytexture = R_TextureNumForName ("SKY1"); + break; + case 2: + skytexture = R_TextureNumForName ("SKY2"); + break; + case 3: + skytexture = R_TextureNumForName ("SKY3"); + break; + case 4: // Special Edition sky + skytexture = R_TextureNumForName ("SKY4"); + break; + }//jff 3/27/98 end sky setting fix + + /* cph 2006/07/31 - took out unused levelstarttic variable */ + + if (!demo_compatibility && !mbf_features) // killough 9/29/98 + basetic = gametic; + + if (wipegamestate == GS_LEVEL) + wipegamestate = -1; // force a wipe + + gamestate = GS_LEVEL; + + for (i=0 ; idata1 == key_spy && netgame && (demoplayback || !deathmatch) && + gamestate == GS_LEVEL) + { + if (ev->type == ev_keyup) + gamekeydown[key_spy] = false; + if (ev->type == ev_keydown && !gamekeydown[key_spy]) + { + gamekeydown[key_spy] = true; + do // spy mode + if (++displayplayer >= MAXPLAYERS) + displayplayer = 0; + while (!playeringame[displayplayer] && displayplayer!=consoleplayer); + + ST_Start(); // killough 3/7/98: switch status bar views too + HU_Start(); + S_UpdateSounds(players[displayplayer].mo); + R_ActivateSectorInterpolations(); + R_SmoothPlaying_Reset(NULL); + } + return true; + } + + // any other key pops up menu if in demos + // + // killough 8/2/98: enable automap in -timedemo demos + // + // killough 9/29/98: make any key pop up menu regardless of + // which kind of demo, and allow other events during playback + + if (gameaction == ga_nothing && (demoplayback || gamestate == GS_DEMOSCREEN)) + { + // killough 9/29/98: allow user to pause demos during playback + if (ev->type == ev_keydown && ev->data1 == key_pause) + { + if (paused ^= 2) + S_PauseSound(); + else + S_ResumeSound(); + return true; + } + + // killough 10/98: + // Don't pop up menu, if paused in middle + // of demo playback, or if automap active. + // Don't suck up keys, which may be cheats + + return gamestate == GS_DEMOSCREEN && + !(paused & 2) && !(automapmode & am_active) && + ((ev->type == ev_keydown) || + (ev->type == ev_mouse && ev->data1) || + (ev->type == ev_joystick && ev->data1)) ? + M_StartControlPanel(), true : false; + } + + if (gamestate == GS_FINALE && F_Responder(ev)) + return true; // finale ate the event + + switch (ev->type) + { + case ev_keydown: + if (ev->data1 == key_pause) // phares + { + special_event = BT_SPECIAL | (BTS_PAUSE & BT_SPECIALMASK); + return true; + } + if (ev->data1 data1] = true; + return true; // eat key down events + + case ev_keyup: + if (ev->data1 data1] = false; + return false; // always let key up events filter down + + case ev_mouse: + mousebuttons[0] = ev->data1 & 1; + mousebuttons[1] = ev->data1 & 2; + mousebuttons[2] = ev->data1 & 4; + /* + * bmead@surfree.com + * Modified by Barry Mead after adding vastly more resolution + * to the Mouse Sensitivity Slider in the options menu 1-9-2000 + * Removed the mouseSensitivity "*4" to allow more low end + * sensitivity resolution especially for lsdoom users. + */ + mousex += (ev->data2*(mouseSensitivity_horiz))/10; /* killough */ + mousey += (ev->data3*(mouseSensitivity_vert))/10; /*Mead rm *4 */ + return true; // eat events + + case ev_joystick: + joybuttons[0] = ev->data1 & 1; + joybuttons[1] = ev->data1 & 2; + joybuttons[2] = ev->data1 & 4; + joybuttons[3] = ev->data1 & 8; + joyxmove = ev->data2; + joyymove = ev->data3; + return true; // eat events + + default: + break; + } + return false; +} + +// +// G_Ticker +// Make ticcmd_ts for the players. +// + +void G_Ticker (void) +{ + int i; + static gamestate_t prevgamestate; + + // CPhipps - player colour changing + if (!demoplayback && mapcolor_plyr[consoleplayer] != mapcolor_me) { + // Changed my multiplayer colour - Inform the whole game + int net_cl = LONG(mapcolor_me); +#ifdef HAVE_NET + D_NetSendMisc(nm_plcolour, sizeof(net_cl), &net_cl); +#endif + (void)net_cl; + G_ChangedPlayerColour(consoleplayer, mapcolor_me); + } + P_MapStart(); + // do player reborns if needed + for (i=0 ; iforwardmove > TURBOTHRESHOLD && + !(gametic&31) && ((gametic>>5)&3) == i ) + { + extern char *player_names[]; + /* cph - don't use sprintf, use doom_printf */ + doom_printf ("%s is turbo!", player_names[i]); + } + + if (netgame && !netdemo && !(gametic%ticdup) ) + { +#ifndef IPHONE // consistency checks are handled in AsyncTic() on packet receive + if (gametic > BACKUPTICS + && consistancy[i][buf] != cmd->consistancy) + I_Error("G_Ticker: Consistency failure (%i should be %i)", + cmd->consistancy, consistancy[i][buf]); +#endif + if (players[i].mo) + consistancy[i][buf] = players[i].mo->x; + else + consistancy[i][buf] = 0; // killough 2/14/98 + } + } + } + + // check for special buttons + for (i=0; i>BTS_SAVESHIFT; + gameaction = ga_savegame; + break; + + // CPhipps - remote loadgame request + case BTS_LOADGAME: + savegameslot = + (players[i].cmd.buttons & BTS_SAVEMASK)>>BTS_SAVESHIFT; + gameaction = ga_loadgame; + forced_loadgame = netgame; // Force if a netgame + command_loadgame = false; + break; + + // CPhipps - Restart the level + case BTS_RESTARTLEVEL: + if (demoplayback || (compatibility_level < lxdoom_1_compatibility)) + break; // CPhipps - Ignore in demos or old games + gameaction = ga_loadlevel; + break; + } + players[i].cmd.buttons = 0; + } + } + } + } + + // cph - if the gamestate changed, we may need to clean up the old gamestate + if (gamestate != prevgamestate) { + switch (prevgamestate) { + case GS_LEVEL: + // This causes crashes at level end - Neil Stevens + // The crash is because the sounds aren't stopped before freeing them + // the following is a possible fix + // This fix does avoid the crash wowever, with this fix in, the exit + // switch sound is cut off + // S_Stop(); + // Z_FreeTags(PU_LEVEL, PU_PURGELEVEL-1); + break; + case GS_INTERMISSION: + WI_End(); + default: + break; + } + prevgamestate = gamestate; + } + + // e6y + // do nothing if a pause has been pressed during playback + // pausing during intermission can cause desynchs without that + if (paused & 2 && gamestate != GS_LEVEL) + return; + + // do main actions + switch (gamestate) + { + case GS_LEVEL: + P_Ticker (); + ST_Ticker (); + AM_Ticker (); + HU_Ticker (); + break; + + case GS_INTERMISSION: + WI_Ticker (); + break; + + case GS_FINALE: + F_Ticker (); + break; + + case GS_DEMOSCREEN: + D_PageTicker (); + break; + } +} + +// +// PLAYER STRUCTURE FUNCTIONS +// also see P_SpawnPlayer in P_Things +// + +// +// G_PlayerFinishLevel +// Can when a player completes a level. +// + +static void G_PlayerFinishLevel(int player) +{ + player_t *p = &players[player]; + memset(p->powers, 0, sizeof p->powers); + memset(p->cards, 0, sizeof p->cards); + p->mo = NULL; // cph - this is allocated PU_LEVEL so it's gone + p->extralight = 0; // cancel gun flashes + p->fixedcolormap = 0; // cancel ir gogles + p->damagecount = 0; // no palette changes + p->bonuscount = 0; +} + +// CPhipps - G_SetPlayerColour +// Player colours stuff +// +// G_SetPlayerColour + +#include "r_draw.h" + +void G_ChangedPlayerColour(int pn, int cl) +{ + int i; + + if (!netgame) return; + + mapcolor_plyr[pn] = cl; + + // Rebuild colour translation tables accordingly + R_InitTranslationTables(); + // Change translations on existing player mobj's + for (i=0; iflags &= ~MF_TRANSLATION; + players[i].mo->flags |= playernumtotrans[i] << MF_TRANSSHIFT; + } + } +} + +// +// G_PlayerReborn +// Called after a player dies +// almost everything is cleared and initialized +// + +void G_PlayerReborn (int player) +{ + player_t *p; + int i; + int frags[MAXPLAYERS]; + int killcount; + int itemcount; + int secretcount; + + memcpy (frags, players[player].frags, sizeof frags); + killcount = players[player].killcount; + itemcount = players[player].itemcount; + secretcount = players[player].secretcount; + + p = &players[player]; + + // killough 3/10/98,3/21/98: preserve cheats across idclev + { + int cheats = p->cheats; + memset (p, 0, sizeof(*p)); + p->cheats = cheats; + } + + memcpy(players[player].frags, frags, sizeof(players[player].frags)); + players[player].killcount = killcount; + players[player].itemcount = itemcount; + players[player].secretcount = secretcount; + + p->usedown = p->attackdown = true; // don't do anything immediately + p->playerstate = PST_LIVE; + p->health = initial_health; // Ty 03/12/98 - use dehacked values + p->readyweapon = p->pendingweapon = wp_pistol; + p->weaponowned[wp_fist] = true; + p->weaponowned[wp_pistol] = true; + p->ammo[am_clip] = initial_bullets; // Ty 03/12/98 - use dehacked values + + for (i=0 ; imaxammo[i] = maxammo[i]; +} + +// +// G_CheckSpot +// Returns false if the player cannot be respawned +// at the given mapthing_t spot +// because something is occupying it +// + +static boolean G_CheckSpot(int playernum, mapthing_t *mthing) +{ + fixed_t x,y; + subsector_t *ss; + int i; + + if (!players[playernum].mo) + { + // first spawn of level, before corpses + for (i=0 ; ix == mthing->x << FRACBITS + && players[i].mo->y == mthing->y << FRACBITS) + return false; + return true; + } + + x = mthing->x << FRACBITS; + y = mthing->y << FRACBITS; + + // killough 4/2/98: fix bug where P_CheckPosition() uses a non-solid + // corpse to detect collisions with other players in DM starts + // + // Old code: + // if (!P_CheckPosition (players[playernum].mo, x, y)) + // return false; + + players[playernum].mo->flags |= MF_SOLID; + i = P_CheckPosition(players[playernum].mo, x, y); + players[playernum].mo->flags &= ~MF_SOLID; + if (!i) + return false; + + // flush an old corpse if needed + // killough 2/8/98: make corpse queue have an adjustable limit + // killough 8/1/98: Fix bugs causing strange crashes + + if (bodyquesize > 0) + { + static int queuesize; + if (queuesize < bodyquesize) + { + bodyque = realloc(bodyque, bodyquesize*sizeof*bodyque); + memset(bodyque+queuesize, 0, + (bodyquesize-queuesize)*sizeof*bodyque); + queuesize = bodyquesize; + } + if (bodyqueslot >= bodyquesize) + P_RemoveMobj(bodyque[bodyqueslot % bodyquesize]); + bodyque[bodyqueslot++ % bodyquesize] = players[playernum].mo; + } + else + if (!bodyquesize) + P_RemoveMobj(players[playernum].mo); + + // spawn a teleport fog + ss = R_PointInSubsector (x,y); + { // Teleport fog at respawn point + fixed_t xa,ya; + int an; + mobj_t *mo; + +/* BUG: an can end up negative, because mthing->angle is (signed) short. + * We have to emulate original Doom's behaviour, deferencing past the start + * of the array, into the previous array (finetangent) */ + an = ( ANG45 * ((signed)mthing->angle/45) ) >> ANGLETOFINESHIFT; + xa = finecosine[an]; + ya = finesine[an]; + + if (compatibility_level <= finaldoom_compatibility || compatibility_level == prboom_4_compatibility) + switch (an) { + case -4096: xa = finetangent[2048]; // finecosine[-4096] + ya = finetangent[0]; // finesine[-4096] + break; + case -3072: xa = finetangent[3072]; // finecosine[-3072] + ya = finetangent[1024]; // finesine[-3072] + break; + case -2048: xa = finesine[0]; // finecosine[-2048] + ya = finetangent[2048]; // finesine[-2048] + break; + case -1024: xa = finesine[1024]; // finecosine[-1024] + ya = finetangent[3072]; // finesine[-1024] + break; + case 1024: + case 2048: + case 3072: + case 4096: + case 0: break; /* correct angles set above */ + default: I_Error("G_CheckSpot: unexpected angle %d\n",an); + } + + mo = P_SpawnMobj(x+20*xa, y+20*ya, ss->sector->floorheight, MT_TFOG); + + if (players[consoleplayer].viewz != 1) + S_StartSound(mo, sfx_telept); // don't start sound on first frame + } + + return true; +} + + +// G_DeathMatchSpawnPlayer +// Spawns a player at one of the random death match spots +// called at level load and each death +// +void G_DeathMatchSpawnPlayer (int playernum) +{ + int j, selections = deathmatch_p - deathmatchstarts; + + if (selections < MAXPLAYERS) + I_Error("G_DeathMatchSpawnPlayer: Only %i deathmatch spots, %d required", + selections, MAXPLAYERS); + + for (j=0 ; j<20 ; j++) + { + int i = P_Random(pr_dmspawn) % selections; + if (G_CheckSpot (playernum, &deathmatchstarts[i]) ) + { + deathmatchstarts[i].type = playernum+1; + P_SpawnPlayer (playernum, &deathmatchstarts[i]); + return; + } + } + + // no good spot, so the player will probably get stuck + P_SpawnPlayer (playernum, &playerstarts[playernum]); +} + +// +// G_DoReborn +// + +void G_DoReborn (int playernum) +{ + if (!netgame) + gameaction = ga_loadlevel; // reload the level from scratch + else + { // respawn at the start + int i; + + // first dissasociate the corpse + players[playernum].mo->player = NULL; + + // spawn at random spot if in death match + if (deathmatch) + { + G_DeathMatchSpawnPlayer (playernum); + return; + } + + if (G_CheckSpot (playernum, &playerstarts[playernum]) ) + { + P_SpawnPlayer (playernum, &playerstarts[playernum]); + return; + } + + // try to spawn at one of the other players spots + for (i=0 ; i" when the player exits the current map + if (nodrawers && (demoplayback || timingdemo)) { + if (gamemode == commercial) + lprintf(LO_INFO, "FINISHED: MAP%02d\n", gamemap); + else + lprintf(LO_INFO, "FINISHED: E%dM%d\n", gameepisode, gamemap); + } + + WI_Start (&wminfo); +} + +// +// G_WorldDone +// + +void G_WorldDone (void) +{ + gameaction = ga_worlddone; + + if (secretexit) + players[consoleplayer].didsecret = true; + + if (gamemode == commercial) + { + switch (gamemap) + { + case 15: + case 31: + if (!secretexit) + break; + case 6: + case 11: + case 20: + case 30: + F_StartFinale (); + break; + } + } + else if (gamemap == 8) + gameaction = ga_victory; // cph - after ExM8 summary screen, show victory stuff +} + +extern float *freeLevelOfWeek; // actually cvar, but value is first element +extern boolean levelHasBeenLoaded; +void G_DoWorldDone (void) +{ + // JAF Added Free level of Week Check. + if( *freeLevelOfWeek == 1 ) { + gameaction = ga_nothing; + levelHasBeenLoaded = false; + iphoneMainMenu(); + return; + } + + idmusnum = -1; //jff 3/17/98 allow new level's music to be loaded + gamestate = GS_LEVEL; + gamemap = wminfo.next+1; + G_DoLoadLevel(); + gameaction = ga_nothing; + AM_clearMarks(); //jff 4/12/98 clear any marks on the automap + + // automatic save game + G_SaveGame( 0, "entersave" ); + G_DoSaveGame(true); +} + +// killough 2/28/98: A ridiculously large number +// of players, the most you'll ever need in a demo +// or savegame. This is used to prevent problems, in +// case more players in a game are supported later. + +#define MIN_MAXPLAYERS 32 + +extern boolean setsizeneeded; + +//CPhipps - savename variable redundant + +/* killough 12/98: + * This function returns a signature for the current wad. + * It is used to distinguish between wads, for the purposes + * of savegame compatibility warnings, and options lookups. + */ + +static uint_64_t G_UpdateSignature(uint_64_t s, const char *name) +{ + int i, lump = W_CheckNumForName(name); + if (lump != -1 && (i = lump+10) < numlumps) + do + { + int size = W_LumpLength(i); + const byte *p = W_CacheLumpNum(i); + while (size--) + s <<= 1, s += *p++; + W_UnlockLumpNum(i); + } + while (--i > lump); + return s; +} + +static uint_64_t G_Signature(void) +{ + static uint_64_t s = 0; + static boolean computed = false; + char name[9]; + int episode, map; + + if (!computed) { + computed = true; + if (gamemode == commercial) + for (map = haswolflevels ? 32 : 30; map; map--) + sprintf(name, "map%02d", map), s = G_UpdateSignature(s, name); + else + for (episode = gamemode==retail ? 4 : + gamemode==shareware ? 1 : 3; episode; episode--) + for (map = 9; map; map--) + sprintf(name, "E%dM%d", episode, map), s = G_UpdateSignature(s, name); + } + return s; +} + +// +// killough 5/15/98: add forced loadgames, which allow user to override checks +// + +void G_ForcedLoadGame(void) +{ + // CPhipps - net loadgames are always forced, so we only reach here + // in single player + gameaction = ga_loadgame; + forced_loadgame = true; +} + +// killough 3/16/98: add slot info +// killough 5/15/98: add command-line +void G_LoadGame(int slot, boolean command) +{ + if (!demoplayback && !command) { + // CPhipps - handle savegame filename in G_DoLoadGame + // - Delay load so it can be communicated in net game + // - store info in special_event + special_event = BT_SPECIAL | (BTS_LOADGAME & BT_SPECIALMASK) | + ((slot << BTS_SAVESHIFT) & BTS_SAVEMASK); + forced_loadgame = netgame; // CPhipps - always force load netgames + } else { + // Do the old thing, immediate load + gameaction = ga_loadgame; + forced_loadgame = false; + savegameslot = slot; + demoplayback = false; + // Don't stay in netgame state if loading single player save + // while watching multiplayer demo + netgame = false; + } + command_loadgame = command; + R_SmoothPlaying_Reset(NULL); // e6y +} + +// killough 5/15/98: +// Consistency Error when attempting to load savegame. + +static void G_LoadGameErr(const char *msg) +{ + Z_Free(savebuffer); // Free the savegame buffer + M_ForcedLoadGame(msg); // Print message asking for 'Y' to force + if (command_loadgame) // If this was a command-line -loadgame + { + D_StartTitle(); // Start the title screen + gamestate = GS_DEMOSCREEN; // And set the game state accordingly + } +} + +// CPhipps - size of version header +#define VERSIONSIZE 16 + +const char * comp_lev_str[MAX_COMPATIBILITY_LEVEL] = +{ "doom v1.2", "doom v1.666", "doom/doom2 v1.9", "ultimate doom", "final doom", + "dosdoom compatibility", "tasdoom compatibility", "\"boom compatibility\"", "boom v2.01", "boom v2.02", "lxdoom v1.3.2+", + "MBF", "PrBoom 2.03beta", "PrBoom v2.1.0-2.1.1", "PrBoom v2.1.2-v2.2.6", + "PrBoom v2.3.x", "PrBoom 2.4.0", "Current PrBoom" }; + +// comp_options_by_version removed - see G_Compatibility + +static byte map_old_comp_levels[] = +{ 0, 1, 2, 4, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }; + +static const struct { + int comp_level; + const char* ver_printf; + int version; +} version_headers[] = { + /* cph - we don't need a new version_header for prboom_3_comp/v2.1.1, since + * the file format is unchanged. */ + { prboom_3_compatibility, "PrBoom %d", 210}, + { prboom_5_compatibility, "PrBoom %d", 211}, + { prboom_6_compatibility, "PrBoom %d", 212} +}; + +static const size_t num_version_headers = sizeof(version_headers) / sizeof(version_headers[0]); + + +boolean G_SaveGameValid() { + + int length; + // CPhipps - do savegame filename stuff here + char name[PATH_MAX+1]; // killough 3/22/98 + //int savegame_compatibility = -1; + + G_SaveGameName(name,sizeof(name),savegameslot, demoplayback); + + gameaction = ga_nothing; + + length = M_ReadFile(name, &savebuffer); + if (length<=0) { + return false; + } + + return true; + +} + +void G_DoLoadGame(void) +{ + int length, i; + // CPhipps - do savegame filename stuff here + char name[PATH_MAX+1]; // killough 3/22/98 + int savegame_compatibility = -1; + + G_SaveGameName(name,sizeof(name),savegameslot, demoplayback); + + gameaction = ga_nothing; + + length = M_ReadFile(name, &savebuffer); + if (length<=0) + I_Error("Couldn't read file %s: %s", name, "(Unknown Error)"); + save_p = savebuffer + SAVESTRINGSIZE; + + // CPhipps - read the description field, compare with supported ones + for (i=0; (size_t)i= prboom_4_compatibility) ? *save_p : savegame_compatibility; + if (savegame_compatibility < prboom_6_compatibility) + compatibility_level = map_old_comp_levels[compatibility_level]; + save_p++; + + gameskill = *save_p++; + gameepisode = *save_p++; + gamemap = *save_p++; + + for (i=0 ; i= prboom_2_compatibility) { + memcpy(&totalleveltimes, save_p, sizeof totalleveltimes); + save_p += sizeof totalleveltimes; + } + else totalleveltimes = 0; + + // killough 11/98: load revenant tracer state + basetic = gametic - *save_p++; + + // dearchive all the modifications + P_MapStart(); + P_UnArchivePlayers (); + P_UnArchiveWorld (); + P_UnArchiveThinkers (); + P_UnArchiveSpecials (); + P_UnArchiveRNG (); // killough 1/18/98: load RNG information + P_UnArchiveMap (); // killough 1/22/98: load automap information + P_MapEnd(); + R_SmoothPlaying_Reset(NULL); // e6y + + if (*save_p != 0xe6) + I_Error ("G_DoLoadGame: Bad savegame"); + + // done + Z_Free (savebuffer); + + if (setsizeneeded) + R_ExecuteSetViewSize (); + + // draw the pattern into the back screen + R_FillBackScreen (); + + /* killough 12/98: support -recordfrom and -loadgame -playdemo */ + if (!command_loadgame) + singledemo = false; /* Clear singledemo flag if loading from menu */ + else + if (singledemo) { + gameaction = ga_loadgame; /* Mark that we're loading a game before demo */ + G_DoPlayDemo(); /* This will detect it and won't reinit level */ + } else /* Command line + record means it's a recordfrom */ + if (demorecording) + G_BeginRecording(); +} + +// +// G_SaveGame +// Called by the menu task. +// Description is a 24 byte text string +// + +void G_SaveGame(int slot, const char *description) +{ + strcpy(savedescription, description); + if (demoplayback) { + /* cph - We're doing a user-initiated save game while a demo is + * running so, go outside normal mechanisms + */ + savegameslot = slot; + G_DoSaveGame(true); + } + // CPhipps - store info in special_event + special_event = BT_SPECIAL | (BTS_SAVEGAME & BT_SPECIALMASK) | + ((slot << BTS_SAVESHIFT) & BTS_SAVEMASK); +#ifdef HAVE_NET + D_NetSendMisc(nm_savegamename, strlen(savedescription)+1, savedescription); +#endif +} + +// Check for overrun and realloc if necessary -- Lee Killough 1/22/98 +void (CheckSaveGame)(size_t size, const char* file, int line) +{ + size_t pos = save_p - savebuffer; + +#ifdef RANGECHECK + /* cph 2006/08/07 - after-the-fact sanity checking of CheckSaveGame calls */ + static size_t prev_check; + static const char* prevf; + static int prevl; + + if (pos > prev_check) + I_Error("CheckSaveGame at %s:%d called for insufficient buffer (%lu < %lu)", prevf, prevl, prev_check, pos); + prev_check = size + pos; + prevf = file; + prevl = line; +#endif + + size += 1024; // breathing room + if (pos+size > savegamesize) + save_p = (savebuffer = realloc(savebuffer, + savegamesize += (size+1023) & ~1023)) + pos; +} + +/* killough 3/22/98: form savegame name in one location + * (previously code was scattered around in multiple places) + * cph - Avoid possible buffer overflow problems by passing + * size to this function and using snprintf */ + +void G_SaveGameName(char *name, size_t size, int slot, boolean isDemoplayback) +{ + const char* sgn = savegamename; +#ifdef HAVE_SNPRINTF + snprintf (name, size, "%s/%s%d.dsg", basesavegame, sgn, slot); +#else + sprintf (name, "%s/%s%d.dsg", basesavegame, sgn, slot); +#endif +} + +/* JDC: removed static */ void G_DoSaveGame (boolean menu) +{ + char name[PATH_MAX+1]; + char name2[VERSIONSIZE]; + char *description; + int length, i; + + gameaction = ga_nothing; // cph - cancel savegame at top of this function, + // in case later problems cause a premature exit + + G_SaveGameName(name,sizeof(name),savegameslot, demoplayback && !menu); + + description = savedescription; + + save_p = savebuffer = malloc(savegamesize); + + CheckSaveGame(SAVESTRINGSIZE+VERSIONSIZE+sizeof(uint_64_t)); + memcpy (save_p, description, SAVESTRINGSIZE); + save_p += SAVESTRINGSIZE; + memset (name2,0,sizeof(name2)); + + // CPhipps - scan for the version header + for (i=0; (size_t)i= prboom_2_compatibility) { + memcpy(save_p, &totalleveltimes, sizeof totalleveltimes); + save_p += sizeof totalleveltimes; + } + else totalleveltimes = 0; + + // killough 11/98: save revenant tracer state + *save_p++ = (gametic-basetic) & 255; + + // killough 3/22/98: add Z_CheckHeap after each call to ensure consistency + Z_CheckHeap(); + P_ArchivePlayers(); + Z_CheckHeap(); + + // phares 9/13/98: Move mobj_t->index out of P_ArchiveThinkers so the + // indices can be used by P_ArchiveWorld when the sectors are saved. + // This is so we can save the index of the mobj_t of the thinker that + // caused a sound, referenced by sector_t->soundtarget. + P_ThinkerToIndex(); + + P_ArchiveWorld(); + Z_CheckHeap(); + P_ArchiveThinkers(); + + // phares 9/13/98: Move index->mobj_t out of P_ArchiveThinkers, simply + // for symmetry with the P_ThinkerToIndex call above. + + P_IndexToThinker(); + + Z_CheckHeap(); + P_ArchiveSpecials(); + P_ArchiveRNG(); // killough 1/18/98: save RNG information + Z_CheckHeap(); + P_ArchiveMap(); // killough 1/22/98: save automap information + + *save_p++ = 0xe6; // consistancy marker + + length = save_p - savebuffer; + + Z_CheckHeap(); + doom_printf( "%s", M_WriteFile(name, savebuffer, length) + ? s_GGSAVED /* Ty - externalised */ + : "Game save failed!"); // CPhipps - not externalised + + free(savebuffer); // killough + savebuffer = save_p = NULL; + + savedescription[0] = 0; +} + +static skill_t d_skill; +static int d_episode; +static int d_map; + +void G_DeferedInitNew(skill_t skill, int episode, int map) +{ + d_skill = skill; + d_episode = episode; + d_map = map; + gameaction = ga_newgame; +} + +/* cph - + * G_Compatibility + * + * Initialises the comp[] array based on the compatibility_level + * For reference, MBF did: + * for (i=0; i < COMP_TOTAL; i++) + * comp[i] = compatibility; + * + * Instead, we have a lookup table showing at what version a fix was + * introduced, and made optional (replaces comp_options_by_version) + */ + +void G_Compatibility(void) +{ + static const struct { + complevel_t fix; // level at which fix/change was introduced + complevel_t opt; // level at which fix/change was made optional + } levels[] = { + // comp_telefrag - monsters used to telefrag only on MAP30, now they do it for spawners only + { mbf_compatibility, mbf_compatibility }, + // comp_dropoff - MBF encourages things to drop off of overhangs + { mbf_compatibility, mbf_compatibility }, + // comp_vile - original Doom archville bugs like ghosts + { boom_compatibility, mbf_compatibility }, + // comp_pain - original Doom limits Pain Elementals from spawning too many skulls + { boom_compatibility, mbf_compatibility }, + // comp_skull - original Doom let skulls be spit through walls by Pain Elementals + { boom_compatibility, mbf_compatibility }, + // comp_blazing - original Doom duplicated blazing door sound + { boom_compatibility, mbf_compatibility }, + // e6y: "Tagged doors don't trigger special lighting" handled wrong + // http://sourceforge.net/tracker/index.php?func=detail&aid=1411400&group_id=148658&atid=772943 + // comp_doorlight - MBF made door lighting changes more gradual + { boom_compatibility, mbf_compatibility }, + // comp_model - improvements to the game physics + { boom_compatibility, mbf_compatibility }, + // comp_god - fixes to God mode + { boom_compatibility, mbf_compatibility }, + // comp_falloff - MBF encourages things to drop off of overhangs + { mbf_compatibility, mbf_compatibility }, + // comp_floors - fixes for moving floors bugs + { boom_compatibility_compatibility, mbf_compatibility }, + // comp_skymap + { boom_compatibility, mbf_compatibility }, + // comp_pursuit - MBF AI change, limited pursuit? + { mbf_compatibility, mbf_compatibility }, + // comp_doorstuck - monsters stuck in doors fix + { boom_202_compatibility, mbf_compatibility }, + // comp_staylift - MBF AI change, monsters try to stay on lifts + { mbf_compatibility, mbf_compatibility }, + // comp_zombie - prevent dead players triggering stuff + { lxdoom_1_compatibility, mbf_compatibility }, + // comp_stairs - see p_floor.c + { boom_202_compatibility, mbf_compatibility }, + // comp_infcheat - FIXME + { mbf_compatibility, mbf_compatibility }, + // comp_zerotags - allow zero tags in wads */ + { boom_compatibility, mbf_compatibility }, + // comp_moveblock - enables keygrab and mancubi shots going thru walls + { lxdoom_1_compatibility, prboom_2_compatibility }, + // comp_respawn - objects which aren't on the map at game start respawn at (0,0) + { prboom_2_compatibility, prboom_2_compatibility }, + // comp_sound - see s_sound.c + { boom_compatibility_compatibility, prboom_3_compatibility }, + // comp_666 - enables tag 666 in non-ExM8 levels + { ultdoom_compatibility, prboom_4_compatibility }, + // comp_soul - enables lost souls bouncing (see P_ZMovement) + { prboom_4_compatibility, prboom_4_compatibility }, + // comp_maskedanim - 2s mid textures don't animate + { doom_1666_compatibility, prboom_4_compatibility }, + }; + int i; + + if (sizeof(levels)/sizeof(*levels) != COMP_NUM) + I_Error("G_Compatibility: consistency error"); + + for (i = 0; i < sizeof(levels)/sizeof(*levels); i++) + if (compatibility_level < levels[i].opt) + comp[i] = (compatibility_level < levels[i].fix); + + if (!mbf_features) { + monster_infighting = 1; + monster_backing = 0; + monster_avoid_hazards = 0; + monster_friction = 0; + help_friends = 0; + +#ifdef DOGS + dogs = 0; + dog_jumping = 0; +#endif + + monkeys = 0; + } +} + +#ifdef DOGS +/* killough 7/19/98: Marine's best friend :) */ +static int G_GetHelpers(void) +{ + int j = M_CheckParm ("-dog"); + + if (!j) + j = M_CheckParm ("-dogs"); + return j ? j+1 < myargc ? atoi(myargv[j+1]) : 1 : default_dogs; +} +#endif + +// killough 3/1/98: function to reload all the default parameter +// settings before a new game begins + +void G_ReloadDefaults(void) +{ + // killough 3/1/98: Initialize options based on config file + // (allows functions above to load different values for demos + // and savegames without messing up defaults). + + weapon_recoil = default_weapon_recoil; // weapon recoil + + player_bobbing = default_player_bobbing; // whether player bobs or not + + /* cph 2007/06/31 - for some reason, the default_* of the next 2 vars was never implemented */ + variable_friction = default_variable_friction; + allow_pushers = default_allow_pushers; + + + monsters_remember = default_monsters_remember; // remember former enemies + + monster_infighting = default_monster_infighting; // killough 7/19/98 + +#ifdef DOGS + dogs = netgame ? 0 : G_GetHelpers(); // killough 7/19/98 + dog_jumping = default_dog_jumping; +#endif + + distfriend = default_distfriend; // killough 8/8/98 + + monster_backing = default_monster_backing; // killough 9/8/98 + + monster_avoid_hazards = default_monster_avoid_hazards; // killough 9/9/98 + + monster_friction = default_monster_friction; // killough 10/98 + + help_friends = default_help_friends; // killough 9/9/98 + + monkeys = default_monkeys; + + // jff 1/24/98 reset play mode to command line spec'd version + // killough 3/1/98: moved to here + respawnparm = clrespawnparm; + fastparm = clfastparm; + nomonsters = clnomonsters; + + //jff 3/24/98 set startskill from defaultskill in config file, unless + // it has already been set by a -skill parameter + if (startskill==sk_none) + startskill = (skill_t)(defaultskill-1); + + demoplayback = false; + singledemo = false; // killough 9/29/98: don't stop after 1 demo + netdemo = false; + + // killough 2/21/98: + memset(playeringame+1, 0, sizeof(*playeringame)*(MAXPLAYERS-1)); + + consoleplayer = 0; + + compatibility_level = default_compatibility_level; + { + int i = M_CheckParm("-complevel"); + if (i && (1+i) < myargc) { + int l = atoi(myargv[i+1]);; + if (l >= -1) compatibility_level = l; + } + } + if (compatibility_level == -1) + compatibility_level = best_compatibility; + + if (mbf_features) + memcpy(comp, default_comp, sizeof comp); + G_Compatibility(); + + // killough 3/31/98, 4/5/98: demo sync insurance + demo_insurance = default_demo_insurance == 1; + + rngseed += I_GetRandomTimeSeed() + gametic; // CPhipps +} + +void G_DoNewGame (void) +{ + G_ReloadDefaults(); // killough 3/1/98 + netgame = false; // killough 3/29/98 + deathmatch = false; + G_InitNew (d_skill, d_episode, d_map); + gameaction = ga_nothing; + + //jff 4/26/98 wake up the status bar in case were coming out of a DM demo + ST_Start(); +} + +// killough 4/10/98: New function to fix bug which caused Doom +// lockups when idclev was used in conjunction with -fast. + +void G_SetFastParms(int fast_pending) +{ + static int fast = 0; // remembers fast state + int i; + if (fast != fast_pending) { /* only change if necessary */ + if ((fast = fast_pending)) + { + for (i=S_SARG_RUN1; i<=S_SARG_PAIN2; i++) + if (states[i].tics != 1 || demo_compatibility) // killough 4/10/98 + states[i].tics >>= 1; // don't change 1->0 since it causes cycles + mobjinfo[MT_BRUISERSHOT].speed = 20*FRACUNIT; + mobjinfo[MT_HEADSHOT].speed = 20*FRACUNIT; + mobjinfo[MT_TROOPSHOT].speed = 20*FRACUNIT; + } + else + { + for (i=S_SARG_RUN1; i<=S_SARG_PAIN2; i++) + states[i].tics <<= 1; + mobjinfo[MT_BRUISERSHOT].speed = 15*FRACUNIT; + mobjinfo[MT_HEADSHOT].speed = 10*FRACUNIT; + mobjinfo[MT_TROOPSHOT].speed = 10*FRACUNIT; + } + } +} + +// +// G_InitNew +// Can be called by the startup code or the menu task, +// consoleplayer, displayplayer, playeringame[] should be set. +// + +void G_InitNew(skill_t skill, int episode, int map) +{ + int i; + + if (paused) + { + paused = false; + S_ResumeSound(); + } + + if (skill > sk_nightmare) + skill = sk_nightmare; + + if (episode < 1) + episode = 1; + + if (gamemode == retail) + { + if (episode > 4) + episode = 4; + } + else + if (gamemode == shareware) + { + if (episode > 1) + episode = 1; // only start episode 1 on shareware + } + + if (map < 1) + map = 1; + if (map > 9 && gamemode != commercial) + map = 9; + + G_SetFastParms(fastparm || skill == sk_nightmare); // killough 4/10/98 + + M_ClearRandom(); + + respawnmonsters = skill == sk_nightmare || respawnparm; + + // force players to be initialized upon first level load + for (i=0 ; i demobuffer + demolength) + { + lprintf(LO_WARN, "G_ReadDemoTiccmd: missing DEMOMARKER\n"); + G_CheckDemoStatus(); + } + else + { + cmd->forwardmove = ((signed char)*demo_p++); + cmd->sidemove = ((signed char)*demo_p++); + if (!longtics) { + cmd->angleturn = ((unsigned char)(at = *demo_p++))<<8; + } else { + unsigned int lowbyte = (unsigned char)*demo_p++; + cmd->angleturn = (((signed int)(*demo_p++))<<8) + lowbyte; + } + cmd->buttons = (unsigned char)*demo_p++; + // e6y: ability to play tasdoom demos directly + if (compatibility_level == tasdoom_compatibility) + { + signed char k = cmd->forwardmove; + cmd->forwardmove = cmd->sidemove; + cmd->sidemove = (signed char)at; + cmd->angleturn = ((unsigned char)cmd->buttons)<<8; + cmd->buttons = (byte)k; + } + } +} + +/* Demo limits removed -- killough + * cph - record straight to file + */ +void G_WriteDemoTiccmd (ticcmd_t* cmd) +{ + char buf[5]; + char *p = buf; + + *p++ = cmd->forwardmove; + *p++ = cmd->sidemove; + if (!longtics) { + *p++ = (cmd->angleturn+128)>>8; + } else { + signed short a = cmd->angleturn; + *p++ = a & 0xff; + *p++ = (a >> 8) & 0xff; + } + *p++ = cmd->buttons; + if (fwrite(buf, p-buf, 1, demofp) != 1) + I_Error("G_WriteDemoTiccmd: error writing demo"); + + /* cph - alias demo_p to it so we can read it back */ + demo_p = (const byte*)buf; + G_ReadDemoTiccmd (cmd); // make SURE it is exactly the same +} + +// +// G_RecordDemo +// + +void G_RecordDemo (const char* name) +{ + char demoname[PATH_MAX]; + usergame = false; + AddDefaultExtension(strcpy(demoname, name), ".lmp"); // 1/18/98 killough + demorecording = true; + /* cph - Record demos straight to file + * If file already exists, try to continue existing demo + */ + if (access(demoname, F_OK)) { + demofp = fopen(demoname, "wb"); + } else { + demofp = fopen(demoname, "r+"); + if (demofp) { + int slot = -1; + int rc; + int bytes_per_tic; + const byte* pos; + + { /* Read the demo header for options etc */ + byte buf[200]; + size_t len = fread(buf, 1, sizeof(buf), demofp); + pos = G_ReadDemoHeader(buf, len, false); + if (pos) + { + fseek(demofp, pos - buf, SEEK_SET); + } + } + bytes_per_tic = longtics ? 5 : 4; + if (pos) + /* Now read the demo to find the last save slot */ + do { + byte buf[5]; + + rc = fread(buf, 1, bytes_per_tic, demofp); + if (buf[0] == DEMOMARKER) break; + if (buf[bytes_per_tic-1] & BT_SPECIAL) + if ((buf[bytes_per_tic-1] & BT_SPECIALMASK) == BTS_SAVEGAME) + slot = (buf[bytes_per_tic-1] & BTS_SAVEMASK)>>BTS_SAVESHIFT; + } while (rc == bytes_per_tic); + + if (slot == -1) I_Error("G_RecordDemo: No save in demo, can't continue"); + + /* Return to the last save position, and load the relevant savegame */ + fseek(demofp, -rc, SEEK_CUR); + G_LoadGame(slot, false); + autostart = false; + } + } + if (!demofp) I_Error("G_RecordDemo: failed to open %s", name); +} + +// These functions are used to read and write game-specific options in demos +// and savegames so that demo sync is preserved and savegame restoration is +// complete. Not all options (for example "compatibility"), however, should +// be loaded and saved here. It is extremely important to use the same +// positions as before for the variables, so if one becomes obsolete, the +// byte(s) should still be skipped over or padded with 0's. +// Lee Killough 3/1/98 + +extern int forceOldBsp; + +byte *G_WriteOptions(byte *theDemo_p) +{ + byte *target = theDemo_p + GAME_OPTION_SIZE; + + *theDemo_p++ = monsters_remember; // part of monster AI + + *theDemo_p++ = variable_friction; // ice & mud + + *theDemo_p++ = weapon_recoil; // weapon recoil + + *theDemo_p++ = allow_pushers; // MT_PUSH Things + + *theDemo_p++ = 0; + + *theDemo_p++ = player_bobbing; // whether player bobs or not + + // killough 3/6/98: add parameters to savegame, move around some in demos + *theDemo_p++ = respawnparm; + *theDemo_p++ = fastparm; + *theDemo_p++ = nomonsters; + + *theDemo_p++ = demo_insurance; // killough 3/31/98 + + // killough 3/26/98: Added rngseed. 3/31/98: moved here + *theDemo_p++ = (byte)((rngseed >> 24) & 0xff); + *theDemo_p++ = (byte)((rngseed >> 16) & 0xff); + *theDemo_p++ = (byte)((rngseed >> 8) & 0xff); + *theDemo_p++ = (byte)( rngseed & 0xff); + + // Options new to v2.03 begin here + + *theDemo_p++ = monster_infighting; // killough 7/19/98 + +#ifdef DOGS + *theDemo_p++ = dogs; // killough 7/19/98 +#else + *theDemo_p++ = 0; +#endif + + *theDemo_p++ = 0; + *theDemo_p++ = 0; + + *theDemo_p++ = (distfriend >> 8) & 0xff; // killough 8/8/98 + *theDemo_p++ = distfriend & 0xff; // killough 8/8/98 + + *theDemo_p++ = monster_backing; // killough 9/8/98 + + *theDemo_p++ = monster_avoid_hazards; // killough 9/9/98 + + *theDemo_p++ = monster_friction; // killough 10/98 + + *theDemo_p++ = help_friends; // killough 9/9/98 + +#ifdef DOGS + *theDemo_p++ = dog_jumping; +#else + *theDemo_p++ = 0; +#endif + + *theDemo_p++ = monkeys; + + { // killough 10/98: a compatibility vector now + int i; + for (i=0; i < COMP_TOTAL; i++) + *theDemo_p++ = comp[i] != 0; + } + + *theDemo_p++ = (compatibility_level >= prboom_2_compatibility) && forceOldBsp; // cph 2002/07/20 + + //---------------- + // Padding at end + //---------------- + while (theDemo_p < target) + *theDemo_p++ = 0; + + if (theDemo_p != target) + I_Error("G_WriteOptions: GAME_OPTION_SIZE is too small"); + + return target; +} + +/* Same, but read instead of write + * cph - const byte*'s + */ + +const byte *G_ReadOptions(const byte *theDemo_p) +{ + const byte *target = theDemo_p + GAME_OPTION_SIZE; + + monsters_remember = *theDemo_p++; + + variable_friction = *theDemo_p; // ice & mud + theDemo_p++; + + weapon_recoil = *theDemo_p; // weapon recoil + theDemo_p++; + + allow_pushers = *theDemo_p; // MT_PUSH Things + theDemo_p++; + + theDemo_p++; + + player_bobbing = *theDemo_p; // whether player bobs or not + theDemo_p++; + + // killough 3/6/98: add parameters to savegame, move from demo + respawnparm = *theDemo_p++; + fastparm = *theDemo_p++; + nomonsters = *theDemo_p++; + + demo_insurance = *theDemo_p++; // killough 3/31/98 + + // killough 3/26/98: Added rngseed to demos; 3/31/98: moved here + + rngseed = *theDemo_p++ & 0xff; + rngseed <<= 8; + rngseed += *theDemo_p++ & 0xff; + rngseed <<= 8; + rngseed += *theDemo_p++ & 0xff; + rngseed <<= 8; + rngseed += *theDemo_p++ & 0xff; + + // Options new to v2.03 + if (mbf_features) + { + monster_infighting = *theDemo_p++; // killough 7/19/98 + +#ifdef DOGS + dogs = *theDemo_p++; // killough 7/19/98 +#else + theDemo_p++; +#endif + + theDemo_p += 2; + + distfriend = *theDemo_p++ << 8; // killough 8/8/98 + distfriend+= *theDemo_p++; + + monster_backing = *theDemo_p++; // killough 9/8/98 + + monster_avoid_hazards = *theDemo_p++; // killough 9/9/98 + + monster_friction = *theDemo_p++; // killough 10/98 + + help_friends = *theDemo_p++; // killough 9/9/98 + +#ifdef DOGS + dog_jumping = *theDemo_p++; // killough 10/98 +#else + theDemo_p++; +#endif + + monkeys = *theDemo_p++; + + { // killough 10/98: a compatibility vector now + int i; + for (i=0; i < COMP_TOTAL; i++) + comp[i] = *theDemo_p++; + } + + forceOldBsp = *theDemo_p++; // cph 2002/07/20 + } + else /* defaults for versions <= 2.02 */ + { + /* G_Compatibility will set these */ + } + + G_Compatibility(); + return target; +} + +void G_BeginRecording (void) +{ + int i; + byte *demostart, *theDemo_p; + demostart = theDemo_p = malloc(1000); + longtics = 0; + + /* cph - 3 demo record formats supported: MBF+, BOOM, and Doom v1.9 */ + if (mbf_features) { + { /* Write version code into demo */ + unsigned char v; + switch(compatibility_level) { + case mbf_compatibility: v = 203; break; // e6y: Bug in MBF compatibility mode fixed + case prboom_2_compatibility: v = 210; break; + case prboom_3_compatibility: v = 211; break; + case prboom_4_compatibility: v = 212; break; + case prboom_5_compatibility: v = 213; break; + case prboom_6_compatibility: + v = 214; + longtics = 1; + break; + default: break; + } + *theDemo_p++ = v; + } + + // signature + *theDemo_p++ = 0x1d; + *theDemo_p++ = 'M'; + *theDemo_p++ = 'B'; + *theDemo_p++ = 'F'; + *theDemo_p++ = 0xe6; + *theDemo_p++ = '\0'; + + /* killough 2/22/98: save compatibility flag in new demos + * cph - FIXME? MBF demos will always be not in compat. mode */ + *theDemo_p++ = 0; + + *theDemo_p++ = gameskill; + *theDemo_p++ = gameepisode; + *theDemo_p++ = gamemap; + *theDemo_p++ = deathmatch; + *theDemo_p++ = consoleplayer; + + theDemo_p = G_WriteOptions(theDemo_p); // killough 3/1/98: Save game options + + for (i=0 ; i boom_compatibility_compatibility) { + byte v, c; /* Nominally, version and compatibility bits */ + switch (compatibility_level) { + case boom_compatibility_compatibility: v = 202, c = 1; break; + case boom_201_compatibility: v = 201; c = 0; break; + case boom_202_compatibility: v = 202, c = 0; break; + default: I_Error("G_BeginRecording: Boom compatibility level unrecognised?"); + } + *theDemo_p++ = v; + + // signature + *theDemo_p++ = 0x1d; + *theDemo_p++ = 'B'; + *theDemo_p++ = 'o'; + *theDemo_p++ = 'o'; + *theDemo_p++ = 'm'; + *theDemo_p++ = 0xe6; + + /* CPhipps - save compatibility level in demos */ + *theDemo_p++ = c; + + *theDemo_p++ = gameskill; + *theDemo_p++ = gameepisode; + *theDemo_p++ = gamemap; + *theDemo_p++ = deathmatch; + *theDemo_p++ = consoleplayer; + + theDemo_p = G_WriteOptions(theDemo_p); // killough 3/1/98: Save game options + + for (i=0 ; i=0) + return lev; + } + } + if (ver < 107) return doom_1666_compatibility; + if (gamemode == retail) return ultdoom_compatibility; + if (gamemission >= pack_tnt) return finaldoom_compatibility; + return doom2_19_compatibility; +} + +//e6y: Check for overrun +static boolean CheckForOverrun(const byte *start_p, const byte *current_p, size_t maxsize, size_t size, boolean failonerror) +{ + size_t pos = current_p - start_p; + if (pos + size > maxsize) + { + if (failonerror) + I_Error("G_ReadDemoHeader: wrong demo header\n"); + else + return true; + } + return false; +} + +static const byte* G_ReadDemoHeader(const byte *theDemo_p, size_t size, boolean failonerror) +{ + skill_t skill; + int i, episode, map; + + // e6y + // The local variable should be used instead of demobuffer, + // because demobuffer can be uninitialized + const byte *header_p = theDemo_p; + + const byte *option_p = NULL; /* killough 11/98 */ + + basetic = gametic; // killough 9/29/98 + + // killough 2/22/98, 2/28/98: autodetect old demos and act accordingly. + // Old demos turn on demo_compatibility => compatibility; new demos load + // compatibility flag, and other flags as well, as a part of the demo. + + //e6y: check for overrun + if (CheckForOverrun(header_p, theDemo_p, size, 1, failonerror)) + return NULL; + + demover = *theDemo_p++; + longtics = 0; + + // e6y + // Handling of unrecognized demo formats + // Versions up to 1.2 use a 7-byte header - first byte is a skill level. + // Versions after 1.2 use a 13-byte header - first byte is a demoversion. + // BOOM's demoversion starts from 200 + if (!((demover >= 0 && demover <= 4) || + (demover >= 104 && demover <= 111) || + (demover >= 200 && demover <= 214))) + { + I_Error("G_ReadDemoHeader: Unknown demo format %d.", demover); + } + + if (demover < 200) // Autodetect old demos + { + if (demover >= 111) longtics = 1; + + // killough 3/2/98: force these variables to be 0 in demo_compatibility + + variable_friction = 0; + + weapon_recoil = 0; + + allow_pushers = 0; + + monster_infighting = 1; // killough 7/19/98 + +#ifdef DOGS + dogs = 0; // killough 7/19/98 + dog_jumping = 0; // killough 10/98 +#endif + + monster_backing = 0; // killough 9/8/98 + + monster_avoid_hazards = 0; // killough 9/9/98 + + monster_friction = 0; // killough 10/98 + help_friends = 0; // killough 9/9/98 + monkeys = 0; + + // killough 3/6/98: rearrange to fix savegame bugs (moved fastparm, + // respawnparm, nomonsters flags to G_LoadOptions()/G_SaveOptions()) + + if ((skill=demover) >= 100) // For demos from versions >= 1.4 + { + //e6y: check for overrun + if (CheckForOverrun(header_p, theDemo_p, size, 8, failonerror)) + return NULL; + + compatibility_level = G_GetOriginalDoomCompatLevel(demover); + skill = *theDemo_p++; + episode = *theDemo_p++; + map = *theDemo_p++; + deathmatch = *theDemo_p++; + respawnparm = *theDemo_p++; + fastparm = *theDemo_p++; + nomonsters = *theDemo_p++; + consoleplayer = *theDemo_p++; + } + else + { + //e6y: check for overrun + if (CheckForOverrun(header_p, theDemo_p, size, 2, failonerror)) + return NULL; + + compatibility_level = doom_12_compatibility; + episode = *theDemo_p++; + map = *theDemo_p++; + deathmatch = respawnparm = fastparm = + nomonsters = consoleplayer = 0; + } + G_Compatibility(); + } + else // new versions of demos + { + theDemo_p += 6; // skip signature; + switch (demover) { + case 200: /* BOOM */ + case 201: + //e6y: check for overrun + if (CheckForOverrun(header_p, theDemo_p, size, 1, failonerror)) + return NULL; + + if (!*theDemo_p++) + compatibility_level = boom_201_compatibility; + else + compatibility_level = boom_compatibility_compatibility; + break; + case 202: + //e6y: check for overrun + if (CheckForOverrun(header_p, theDemo_p, size, 1, failonerror)) + return NULL; + + if (!*theDemo_p++) + compatibility_level = boom_202_compatibility; + else + compatibility_level = boom_compatibility_compatibility; + break; + case 203: + /* LxDoom or MBF - determine from signature + * cph - load compatibility level */ + switch (*(header_p + 2)) { + case 'B': /* LxDoom */ + /* cph - DEMOSYNC - LxDoom demos recorded in compatibility modes support dropped */ + compatibility_level = lxdoom_1_compatibility; + break; + case 'M': + compatibility_level = mbf_compatibility; + theDemo_p++; + break; + } + break; + case 210: + compatibility_level = prboom_2_compatibility; + theDemo_p++; + break; + case 211: + compatibility_level = prboom_3_compatibility; + theDemo_p++; + break; + case 212: + compatibility_level = prboom_4_compatibility; + theDemo_p++; + break; + case 213: + compatibility_level = prboom_5_compatibility; + theDemo_p++; + break; + case 214: + compatibility_level = prboom_6_compatibility; + longtics = 1; + theDemo_p++; + break; + } + //e6y: check for overrun + if (CheckForOverrun(header_p, theDemo_p, size, 5, failonerror)) + return NULL; + + skill = *theDemo_p++; + episode = *theDemo_p++; + map = *theDemo_p++; + deathmatch = *theDemo_p++; + consoleplayer = *theDemo_p++; + + /* killough 11/98: save option pointer for below */ + if (mbf_features) + option_p = theDemo_p; + + //e6y: check for overrun + if (CheckForOverrun(header_p, theDemo_p, size, GAME_OPTION_SIZE, failonerror)) + return NULL; + + theDemo_p = G_ReadOptions(theDemo_p); // killough 3/1/98: Read game options + + if (demover == 200) // killough 6/3/98: partially fix v2.00 demos + theDemo_p += 256-GAME_OPTION_SIZE; + } + + if (sizeof(comp_lev_str)/sizeof(comp_lev_str[0]) != MAX_COMPATIBILITY_LEVEL) + I_Error("G_ReadDemoHeader: compatibility level strings incomplete"); + lprintf(LO_INFO, "G_DoPlayDemo: playing demo with %s compatibility\n", + comp_lev_str[compatibility_level]); + + if (demo_compatibility) // only 4 players can exist in old demos + { + //e6y: check for overrun + if (CheckForOverrun(header_p, theDemo_p, size, 4, failonerror)) + return NULL; + + for (i=0; i<4; i++) // intentionally hard-coded 4 -- killough + playeringame[i] = *theDemo_p++; + for (;i < MAXPLAYERS; i++) + playeringame[i] = 0; + } + else + { + //e6y: check for overrun + if (CheckForOverrun(header_p, theDemo_p, size, MAXPLAYERS, failonerror)) + return NULL; + + for (i=0 ; i < MAXPLAYERS; i++) + playeringame[i] = *theDemo_p++; + theDemo_p += MIN_MAXPLAYERS - MAXPLAYERS; + } + + if (playeringame[1]) + { + netgame = true; + netdemo = true; + } + + if (gameaction != ga_loadgame) { /* killough 12/98: support -loadgame */ + G_InitNew(skill, episode, map); + } + + for (i=0; imessage=... and so I've added this dprintf. +// +// killough 3/6/98: Made limit static to allow z_zone functions to call +// this function, without calling realloc(), which seems to cause problems. + +#define MAX_MESSAGE_SIZE 1024 + +// CPhipps - renamed to doom_printf to avoid name collision with glibc +void doom_printf(const char *s, ...) +{ + static char msg[MAX_MESSAGE_SIZE]; + va_list v; + va_start(v,s); +#ifdef HAVE_VSNPRINTF + vsnprintf(msg,sizeof(msg),s,v); /* print message in buffer */ +#else + vsprintf(msg,s,v); +#endif + va_end(v); + players[consoleplayer].message = msg; // set new message +} diff --git a/common/prboom/g_game.h b/common/prboom/g_game.h new file mode 100755 index 0000000..2a0e0f7 --- /dev/null +++ b/common/prboom/g_game.h @@ -0,0 +1,179 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: Main game control interface. + *-----------------------------------------------------------------------------*/ + +#ifndef __G_GAME__ +#define __G_GAME__ + +#include "doomdef.h" +#include "d_event.h" +#include "d_ticcmd.h" + +// +// GAME +// + +// killough 5/2/98: number of bytes reserved for saving options +#define GAME_OPTION_SIZE 64 + +boolean G_Responder(event_t *ev); +boolean G_CheckDemoStatus(void); +void G_DeathMatchSpawnPlayer(int playernum); +void G_InitNew(skill_t skill, int episode, int map); +void G_DeferedInitNew(skill_t skill, int episode, int map); +void G_DeferedPlayDemo(const char *demo); // CPhipps - const +void G_LoadGame(int slot, boolean is_command); // killough 5/15/98 +void G_ForcedLoadGame(void); // killough 5/15/98: forced loadgames +boolean G_SaveGameValid(void); +void G_DoLoadGame(void); +void G_SaveGame(int slot, const char *description); // Called by M_Responder. +void G_BeginRecording(void); +// CPhipps - const on these string params +void G_RecordDemo(const char *name); // Only called by startup code. +void G_ExitLevel(void); +void G_SecretExitLevel(void); +void G_WorldDone(void); +void G_EndGame(void); /* cph - make m_menu.c call a G_* function for this */ +void G_Ticker(void); +void G_ReloadDefaults(void); // killough 3/1/98: loads game defaults +void G_SaveGameName(char *, size_t, int, boolean); /* killough 3/22/98: sets savegame filename */ +void G_SetFastParms(int); // killough 4/10/98: sets -fast parameters +void G_DoNewGame(void); +void G_DoReborn(int playernum); +void G_DoPlayDemo(void); +void G_DoCompleted(void); +void G_ReadDemoTiccmd(ticcmd_t *cmd); +void G_WriteDemoTiccmd(ticcmd_t *cmd); +void G_DoWorldDone(void); +void G_Compatibility(void); +const byte *G_ReadOptions(const byte *demo_p); /* killough 3/1/98 - cph: const byte* */ +byte *G_WriteOptions(byte *demo_p); // killough 3/1/98 +void G_PlayerReborn(int player); +void G_RestartLevel(void); // CPhipps - menu involked level restart +void G_DoVictory(void); +void G_BuildTiccmd (ticcmd_t* cmd); // CPhipps - move decl to header +void G_ChangedPlayerColour(int pn, int cl); // CPhipps - On-the-fly player colour changing +void G_MakeSpecialEvent(buttoncode_t bc, ...); /* cph - new event stuff */ + +// killough 1/18/98: Doom-style printf; killough 4/25/98: add gcc attributes +// CPhipps - renames to doom_printf to avoid name collision with glibc +void doom_printf(const char *, ...) __attribute__((format(printf,1,2))); + +// killough 5/2/98: moved from m_misc.c: + +extern int key_right; +extern int key_left; +extern int key_up; +extern int key_down; +extern int key_menu_right; // phares 3/7/98 +extern int key_menu_left; // | +extern int key_menu_up; // V +extern int key_menu_down; +extern int key_menu_backspace; // ^ +extern int key_menu_escape; // | +extern int key_menu_enter; // phares 3/7/98 +extern int key_strafeleft; +extern int key_straferight; + +extern int key_fire; +extern int key_use; +extern int key_strafe; +extern int key_speed; +extern int key_escape; // phares +extern int key_savegame; // | +extern int key_loadgame; // V +extern int key_autorun; +extern int key_reverse; +extern int key_zoomin; +extern int key_zoomout; +extern int key_chat; +extern int key_backspace; +extern int key_enter; +extern int key_help; +extern int key_soundvolume; +extern int key_hud; +extern int key_quicksave; +extern int key_endgame; +extern int key_messages; +extern int key_quickload; +extern int key_quit; +extern int key_gamma; +extern int key_spy; +extern int key_pause; +extern int key_setup; +extern int key_forward; +extern int key_leftturn; +extern int key_rightturn; +extern int key_backward; +extern int key_weapontoggle; +extern int key_weapon1; +extern int key_weapon2; +extern int key_weapon3; +extern int key_weapon4; +extern int key_weapon5; +extern int key_weapon6; +extern int key_weapon7; +extern int key_weapon8; +extern int key_weapon9; +extern int destination_keys[MAXPLAYERS]; +extern int key_map_right; +extern int key_map_left; +extern int key_map_up; +extern int key_map_down; +extern int key_map_zoomin; +extern int key_map_zoomout; +extern int key_map; +extern int key_map_gobig; +extern int key_map_follow; +extern int key_map_mark; // ^ +extern int key_map_clear; // | +extern int key_map_grid; // phares +extern int key_map_rotate; // cph - map rotation +extern int key_map_overlay;// cph - map overlay +extern int key_screenshot; // killough 2/22/98 -- add key for screenshot +extern int autorun; // always running? // phares + +extern int defaultskill; //jff 3/24/98 default skill +extern boolean haswolflevels; //jff 4/18/98 wolf levels present + +extern int bodyquesize; // killough 2/8/98: adustable corpse limit + +// killough 5/2/98: moved from d_deh.c: +// Par times (new item with BOOM) - from g_game.c +extern int pars[4][10]; // hardcoded array size +extern int cpars[32]; // hardcoded array size +// CPhipps - Make savedesciption visible in wider scope +#define SAVEDESCLEN 32 +extern char savedescription[SAVEDESCLEN]; // Description to save in savegame + +/* cph - compatibility level strings */ +extern const char * comp_lev_str[]; + +#endif diff --git a/common/prboom/gl_intern.h b/common/prboom/gl_intern.h new file mode 100755 index 0000000..23bb757 --- /dev/null +++ b/common/prboom/gl_intern.h @@ -0,0 +1,228 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * + *--------------------------------------------------------------------- + */ + +#ifndef _GL_INTERN_H +#define _GL_INTERN_H + +typedef enum +{ + GLDT_UNREGISTERED, + GLDT_BROKEN, + GLDT_PATCH, + GLDT_TEXTURE, + GLDT_FLAT +} GLTexType; + +typedef struct +{ + int index; + int width,height; + int leftoffset,topoffset; + int tex_width,tex_height; + int realtexwidth, realtexheight; + int buffer_width,buffer_height; + int buffer_size; + GLuint glTexID[CR_LIMIT+MAXPLAYERS]; + GLTexType textype; + boolean mipmap; +} GLTexture; + +// JDC: moved these to header --------------------------- + +#define MAP_COEFF 128.0f +#define MAP_SCALE (MAP_COEFF*(float)FRACUNIT) + + +typedef struct + { + float x1,x2; + float z1,z2; + } GLSeg; + +#define GLDWF_TOP 1 +#define GLDWF_M1S 2 +#define GLDWF_M2S 3 +#define GLDWF_BOT 4 +#define GLDWF_SKY 5 +#define GLDWF_SKYFLIP 6 + +typedef struct + { + GLSeg *glseg; + float ytop,ybottom; + float ul,ur,vt,vb; + float light; + float alpha; + float skyymid; + float skyyaw; + GLTexture *gltexture; + byte flag; +#ifdef IPHONE + side_t *side; +#endif + } GLWall; + +typedef struct + { + int sectornum; + float light; // the lightlevel of the flat + float uoffs,voffs; // the texture coordinates + float z; // the z position of the flat (height) + GLTexture *gltexture; + boolean ceiling; + } GLFlat; + +typedef struct + { + int cm; + float x,y,z; + float vt,vb; + float ul,ur; + float x1,y1; + float x2,y2; + float light; + fixed_t scale; + GLTexture *gltexture; + boolean shadow; + boolean trans; + } GLSprite; + +typedef enum + { + GLDIT_NONE, + GLDIT_WALL, + GLDIT_FLAT, + GLDIT_SPRITE + } GLDrawItemType; + +typedef struct + { + GLDrawItemType itemtype; + int itemcount; + int firstitemindex; + byte rendermarker; + } GLDrawItem; + +typedef struct + { + GLWall *walls; + int num_walls; + int max_walls; + GLFlat *flats; + int num_flats; + int max_flats; + GLSprite *sprites; + int num_sprites; + int max_sprites; + GLDrawItem *drawitems; + int num_drawitems; + int max_drawitems; + } GLDrawInfo; + +extern GLDrawInfo gld_drawinfo; + +typedef struct + { + GLfloat x; + GLfloat y; + GLfloat z; + } GLVertex; + +typedef struct + { + GLfloat u; + GLfloat v; + } GLTexcoord; + + +/* GLLoopDef is the struct for one loop. A loop is a list of vertexes + * for triangles, which is calculated by the gluTesselator in gld_PrecalculateSector + * and in gld_PreprocessCarvedFlat + */ +typedef struct + { + GLenum mode; // GL_TRIANGLES, GL_TRIANGLE_STRIP or GL_TRIANGLE_FAN + int vertexcount; // number of vertexes in this loop + int vertexindex; // index into vertex list + } GLLoopDef; + +// GLSector is the struct for a sector with a list of loops. + +typedef struct + { + int loopcount; // number of loops for this sector + GLLoopDef *loops; // the loops itself + } GLSector; + +extern GLSector *sectorloops; + +typedef struct drawVert_s { // JDC + float xyz[3]; // TODO: adjust MAP_SCALE, make shorts + float st[2]; // TODO: set texture matrix, make shorts + unsigned char rgba[4]; +} drawVert_t; +#define MAX_DRAW_VERTS 0x10000 +extern drawVert_t drawVerts[MAX_DRAW_VERTS]; +extern int numDrawVerts; + +//-------------------------------------- + +extern int gld_max_texturesize; +extern const char *gl_tex_format_string; +extern int gl_tex_format; +extern int gl_tex_filter; +extern int gl_mipmap_filter; +extern int gl_texture_filter_anisotropic; +extern int gl_paletted_texture; +extern int gl_shared_texture_palette; +extern boolean use_mipmapping; +extern int transparent_pal_index; +extern unsigned char gld_palmap[256]; +extern GLTexture *last_gltexture; +extern int last_cm; + +//e6y: in some cases textures with a zero index (NO_TEXTURE) should be registered +GLTexture *gld_RegisterTexture(int texture_num, boolean mipmap, boolean force); +void gld_BindTexture(GLTexture *gltexture); +GLTexture *gld_RegisterPatch(int lump, int cm); +void gld_BindPatch(GLTexture *gltexture, int cm); +GLTexture *gld_RegisterFlat(int lump, boolean mipmap); +void gld_BindFlat(GLTexture *gltexture); +void gld_InitPalettedTextures(void); +int gld_GetTexDimension(int value); +void gld_SetTexturePalette(GLenum target); +void gld_Precache(void); + +extern PFNGLCOLORTABLEEXTPROC gld_ColorTableEXT; + +#endif // _GL_INTERN_H diff --git a/common/prboom/gl_main.c b/common/prboom/gl_main.c new file mode 100755 index 0000000..935e81e --- /dev/null +++ b/common/prboom/gl_main.c @@ -0,0 +1,2961 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * + *--------------------------------------------------------------------- + */ + +#include "z_zone.h" +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#endif +#ifndef CALLBACK +#define CALLBACK +#endif +#include +#include +#include +//#include +#include "SDL_opengl.h" +#include "doomtype.h" +#include "w_wad.h" +#include "m_argv.h" +#include "d_event.h" +#include "v_video.h" +#include "doomstat.h" +#include "r_bsp.h" +#include "r_main.h" +#include "r_draw.h" +#include "r_sky.h" +#include "r_plane.h" +#include "r_data.h" +#include "r_things.h" +#include "r_fps.h" +#include "p_maputl.h" +#include "m_bbox.h" +#include "lprintf.h" +#include "gl_intern.h" +#include "gl_struct.h" + +void IR_InitLevel(); + +extern int tran_filter_pct; + +// JDC #define USE_VERTEX_ARRAYS + +boolean use_fog=false; + +int gl_nearclip=5; +const char *gl_tex_filter_string; +int gl_tex_filter; +int gl_mipmap_filter; +int gl_drawskys=true; +int gl_sortsprites=true; +int gl_texture_filter_anisotropic = 0; +int gl_use_paletted_texture = 0; +int gl_use_shared_texture_palette = 0; +int gl_paletted_texture = 0; +int gl_shared_texture_palette = 0; +int gl_sprite_offset; // item out of floor offset Mead 8/13/03 + +GLuint gld_DisplayList=0; +int fog_density=200; +static float extra_red=0.0f; +static float extra_green=0.0f; +static float extra_blue=0.0f; +static float extra_alpha=0.0f; + +byte *staticPlaypal; // JDC: this was being looked up for every line + +PFNGLCOLORTABLEEXTPROC gld_ColorTableEXT; + +GLfloat gl_whitecolor[4]={1.0f,1.0f,1.0f,1.0f}; + +#if 0 // JDC: moved to header +#define MAP_COEFF 128.0f +#define MAP_SCALE (MAP_COEFF*(float)FRACUNIT) +#endif + +/* + * lookuptable for lightvalues + * calculated as follow: + * floatlight=(1.0-exp((light^3)*gamma)) / (1.0-exp(1.0*gamma)); + * gamma=-0,2;-2,0;-4,0;-6,0;-8,0 + * light=0,0 .. 1,0 + */ +static const float lighttable[5][256] = +{ + { + 0.00000f,0.00000f,0.00000f,0.00000f,0.00000f,0.00001f,0.00001f,0.00002f,0.00003f,0.00004f, + 0.00006f,0.00008f,0.00010f,0.00013f,0.00017f,0.00020f,0.00025f,0.00030f,0.00035f,0.00041f, + 0.00048f,0.00056f,0.00064f,0.00073f,0.00083f,0.00094f,0.00106f,0.00119f,0.00132f,0.00147f, + 0.00163f,0.00180f,0.00198f,0.00217f,0.00237f,0.00259f,0.00281f,0.00305f,0.00331f,0.00358f, + 0.00386f,0.00416f,0.00447f,0.00479f,0.00514f,0.00550f,0.00587f,0.00626f,0.00667f,0.00710f, + 0.00754f,0.00800f,0.00848f,0.00898f,0.00950f,0.01003f,0.01059f,0.01117f,0.01177f,0.01239f, + 0.01303f,0.01369f,0.01437f,0.01508f,0.01581f,0.01656f,0.01734f,0.01814f,0.01896f,0.01981f, + 0.02069f,0.02159f,0.02251f,0.02346f,0.02444f,0.02544f,0.02647f,0.02753f,0.02862f,0.02973f, + 0.03088f,0.03205f,0.03325f,0.03448f,0.03575f,0.03704f,0.03836f,0.03971f,0.04110f,0.04252f, + 0.04396f,0.04545f,0.04696f,0.04851f,0.05009f,0.05171f,0.05336f,0.05504f,0.05676f,0.05852f, + 0.06031f,0.06214f,0.06400f,0.06590f,0.06784f,0.06981f,0.07183f,0.07388f,0.07597f,0.07810f, + 0.08027f,0.08248f,0.08473f,0.08702f,0.08935f,0.09172f,0.09414f,0.09659f,0.09909f,0.10163f, + 0.10421f,0.10684f,0.10951f,0.11223f,0.11499f,0.11779f,0.12064f,0.12354f,0.12648f,0.12946f, + 0.13250f,0.13558f,0.13871f,0.14188f,0.14511f,0.14838f,0.15170f,0.15507f,0.15850f,0.16197f, + 0.16549f,0.16906f,0.17268f,0.17635f,0.18008f,0.18386f,0.18769f,0.19157f,0.19551f,0.19950f, + 0.20354f,0.20764f,0.21179f,0.21600f,0.22026f,0.22458f,0.22896f,0.23339f,0.23788f,0.24242f, + 0.24702f,0.25168f,0.25640f,0.26118f,0.26602f,0.27091f,0.27587f,0.28089f,0.28596f,0.29110f, + 0.29630f,0.30156f,0.30688f,0.31226f,0.31771f,0.32322f,0.32879f,0.33443f,0.34013f,0.34589f, + 0.35172f,0.35761f,0.36357f,0.36960f,0.37569f,0.38185f,0.38808f,0.39437f,0.40073f,0.40716f, + 0.41366f,0.42022f,0.42686f,0.43356f,0.44034f,0.44718f,0.45410f,0.46108f,0.46814f,0.47527f, + 0.48247f,0.48974f,0.49709f,0.50451f,0.51200f,0.51957f,0.52721f,0.53492f,0.54271f,0.55058f, + 0.55852f,0.56654f,0.57463f,0.58280f,0.59105f,0.59937f,0.60777f,0.61625f,0.62481f,0.63345f, + 0.64217f,0.65096f,0.65984f,0.66880f,0.67783f,0.68695f,0.69615f,0.70544f,0.71480f,0.72425f, + 0.73378f,0.74339f,0.75308f,0.76286f,0.77273f,0.78268f,0.79271f,0.80283f,0.81304f,0.82333f, + 0.83371f,0.84417f,0.85472f,0.86536f,0.87609f,0.88691f,0.89781f,0.90880f,0.91989f,0.93106f, + 0.94232f,0.95368f,0.96512f,0.97665f,0.98828f,1.00000 + }, + { + 0.00000f,0.00000f,0.00000f,0.00000f,0.00001f,0.00002f,0.00003f,0.00005f,0.00007f,0.00010f, + 0.00014f,0.00019f,0.00024f,0.00031f,0.00038f,0.00047f,0.00057f,0.00069f,0.00081f,0.00096f, + 0.00112f,0.00129f,0.00148f,0.00170f,0.00193f,0.00218f,0.00245f,0.00274f,0.00306f,0.00340f, + 0.00376f,0.00415f,0.00456f,0.00500f,0.00547f,0.00597f,0.00649f,0.00704f,0.00763f,0.00825f, + 0.00889f,0.00957f,0.01029f,0.01104f,0.01182f,0.01264f,0.01350f,0.01439f,0.01532f,0.01630f, + 0.01731f,0.01836f,0.01945f,0.02058f,0.02176f,0.02298f,0.02424f,0.02555f,0.02690f,0.02830f, + 0.02974f,0.03123f,0.03277f,0.03436f,0.03600f,0.03768f,0.03942f,0.04120f,0.04304f,0.04493f, + 0.04687f,0.04886f,0.05091f,0.05301f,0.05517f,0.05738f,0.05964f,0.06196f,0.06434f,0.06677f, + 0.06926f,0.07181f,0.07441f,0.07707f,0.07979f,0.08257f,0.08541f,0.08831f,0.09126f,0.09428f, + 0.09735f,0.10048f,0.10368f,0.10693f,0.11025f,0.11362f,0.11706f,0.12056f,0.12411f,0.12773f, + 0.13141f,0.13515f,0.13895f,0.14281f,0.14673f,0.15072f,0.15476f,0.15886f,0.16303f,0.16725f, + 0.17153f,0.17587f,0.18028f,0.18474f,0.18926f,0.19383f,0.19847f,0.20316f,0.20791f,0.21272f, + 0.21759f,0.22251f,0.22748f,0.23251f,0.23760f,0.24274f,0.24793f,0.25318f,0.25848f,0.26383f, + 0.26923f,0.27468f,0.28018f,0.28573f,0.29133f,0.29697f,0.30266f,0.30840f,0.31418f,0.32001f, + 0.32588f,0.33179f,0.33774f,0.34374f,0.34977f,0.35585f,0.36196f,0.36810f,0.37428f,0.38050f, + 0.38675f,0.39304f,0.39935f,0.40570f,0.41207f,0.41847f,0.42490f,0.43136f,0.43784f,0.44434f, + 0.45087f,0.45741f,0.46398f,0.47057f,0.47717f,0.48379f,0.49042f,0.49707f,0.50373f,0.51041f, + 0.51709f,0.52378f,0.53048f,0.53718f,0.54389f,0.55061f,0.55732f,0.56404f,0.57075f,0.57747f, + 0.58418f,0.59089f,0.59759f,0.60429f,0.61097f,0.61765f,0.62432f,0.63098f,0.63762f,0.64425f, + 0.65086f,0.65746f,0.66404f,0.67060f,0.67714f,0.68365f,0.69015f,0.69662f,0.70307f,0.70948f, + 0.71588f,0.72224f,0.72857f,0.73488f,0.74115f,0.74739f,0.75359f,0.75976f,0.76589f,0.77199f, + 0.77805f,0.78407f,0.79005f,0.79599f,0.80189f,0.80774f,0.81355f,0.81932f,0.82504f,0.83072f, + 0.83635f,0.84194f,0.84747f,0.85296f,0.85840f,0.86378f,0.86912f,0.87441f,0.87964f,0.88482f, + 0.88995f,0.89503f,0.90005f,0.90502f,0.90993f,0.91479f,0.91959f,0.92434f,0.92903f,0.93366f, + 0.93824f,0.94276f,0.94723f,0.95163f,0.95598f,0.96027f,0.96451f,0.96868f,0.97280f,0.97686f, + 0.98086f,0.98481f,0.98869f,0.99252f,0.99629f,1.00000f + }, + { + 0.00000f,0.00000f,0.00000f,0.00001f,0.00002f,0.00003f,0.00005f,0.00008f,0.00013f,0.00018f, + 0.00025f,0.00033f,0.00042f,0.00054f,0.00067f,0.00083f,0.00101f,0.00121f,0.00143f,0.00168f, + 0.00196f,0.00227f,0.00261f,0.00299f,0.00339f,0.00383f,0.00431f,0.00483f,0.00538f,0.00598f, + 0.00661f,0.00729f,0.00802f,0.00879f,0.00961f,0.01048f,0.01140f,0.01237f,0.01340f,0.01447f, + 0.01561f,0.01680f,0.01804f,0.01935f,0.02072f,0.02215f,0.02364f,0.02520f,0.02682f,0.02850f, + 0.03026f,0.03208f,0.03397f,0.03594f,0.03797f,0.04007f,0.04225f,0.04451f,0.04684f,0.04924f, + 0.05172f,0.05428f,0.05691f,0.05963f,0.06242f,0.06530f,0.06825f,0.07129f,0.07441f,0.07761f, + 0.08089f,0.08426f,0.08771f,0.09125f,0.09487f,0.09857f,0.10236f,0.10623f,0.11019f,0.11423f, + 0.11836f,0.12257f,0.12687f,0.13125f,0.13571f,0.14027f,0.14490f,0.14962f,0.15442f,0.15931f, + 0.16427f,0.16932f,0.17445f,0.17966f,0.18496f,0.19033f,0.19578f,0.20130f,0.20691f,0.21259f, + 0.21834f,0.22417f,0.23007f,0.23605f,0.24209f,0.24820f,0.25438f,0.26063f,0.26694f,0.27332f, + 0.27976f,0.28626f,0.29282f,0.29944f,0.30611f,0.31284f,0.31962f,0.32646f,0.33334f,0.34027f, + 0.34724f,0.35426f,0.36132f,0.36842f,0.37556f,0.38273f,0.38994f,0.39718f,0.40445f,0.41174f, + 0.41907f,0.42641f,0.43378f,0.44116f,0.44856f,0.45598f,0.46340f,0.47084f,0.47828f,0.48573f, + 0.49319f,0.50064f,0.50809f,0.51554f,0.52298f,0.53042f,0.53784f,0.54525f,0.55265f,0.56002f, + 0.56738f,0.57472f,0.58203f,0.58932f,0.59658f,0.60381f,0.61101f,0.61817f,0.62529f,0.63238f, + 0.63943f,0.64643f,0.65339f,0.66031f,0.66717f,0.67399f,0.68075f,0.68746f,0.69412f,0.70072f, + 0.70726f,0.71375f,0.72017f,0.72653f,0.73282f,0.73905f,0.74522f,0.75131f,0.75734f,0.76330f, + 0.76918f,0.77500f,0.78074f,0.78640f,0.79199f,0.79751f,0.80295f,0.80831f,0.81359f,0.81880f, + 0.82393f,0.82898f,0.83394f,0.83883f,0.84364f,0.84836f,0.85301f,0.85758f,0.86206f,0.86646f, + 0.87078f,0.87502f,0.87918f,0.88326f,0.88726f,0.89118f,0.89501f,0.89877f,0.90245f,0.90605f, + 0.90957f,0.91301f,0.91638f,0.91966f,0.92288f,0.92601f,0.92908f,0.93206f,0.93498f,0.93782f, + 0.94059f,0.94329f,0.94592f,0.94848f,0.95097f,0.95339f,0.95575f,0.95804f,0.96027f,0.96244f, + 0.96454f,0.96658f,0.96856f,0.97049f,0.97235f,0.97416f,0.97591f,0.97760f,0.97924f,0.98083f, + 0.98237f,0.98386f,0.98530f,0.98669f,0.98803f,0.98933f,0.99058f,0.99179f,0.99295f,0.99408f, + 0.99516f,0.99620f,0.99721f,0.99817f,0.99910f,1.00000f + }, + { + 0.00000f,0.00000f,0.00000f,0.00001f,0.00002f,0.00005f,0.00008f,0.00012f,0.00019f,0.00026f, + 0.00036f,0.00048f,0.00063f,0.00080f,0.00099f,0.00122f,0.00148f,0.00178f,0.00211f,0.00249f, + 0.00290f,0.00335f,0.00386f,0.00440f,0.00500f,0.00565f,0.00636f,0.00711f,0.00793f,0.00881f, + 0.00975f,0.01075f,0.01182f,0.01295f,0.01416f,0.01543f,0.01678f,0.01821f,0.01971f,0.02129f, + 0.02295f,0.02469f,0.02652f,0.02843f,0.03043f,0.03252f,0.03469f,0.03696f,0.03933f,0.04178f, + 0.04433f,0.04698f,0.04973f,0.05258f,0.05552f,0.05857f,0.06172f,0.06498f,0.06834f,0.07180f, + 0.07537f,0.07905f,0.08283f,0.08672f,0.09072f,0.09483f,0.09905f,0.10337f,0.10781f,0.11236f, + 0.11701f,0.12178f,0.12665f,0.13163f,0.13673f,0.14193f,0.14724f,0.15265f,0.15817f,0.16380f, + 0.16954f,0.17538f,0.18132f,0.18737f,0.19351f,0.19976f,0.20610f,0.21255f,0.21908f,0.22572f, + 0.23244f,0.23926f,0.24616f,0.25316f,0.26023f,0.26739f,0.27464f,0.28196f,0.28935f,0.29683f, + 0.30437f,0.31198f,0.31966f,0.32740f,0.33521f,0.34307f,0.35099f,0.35896f,0.36699f,0.37506f, + 0.38317f,0.39133f,0.39952f,0.40775f,0.41601f,0.42429f,0.43261f,0.44094f,0.44929f,0.45766f, + 0.46604f,0.47443f,0.48283f,0.49122f,0.49962f,0.50801f,0.51639f,0.52476f,0.53312f,0.54146f, + 0.54978f,0.55807f,0.56633f,0.57457f,0.58277f,0.59093f,0.59905f,0.60713f,0.61516f,0.62314f, + 0.63107f,0.63895f,0.64676f,0.65452f,0.66221f,0.66984f,0.67739f,0.68488f,0.69229f,0.69963f, + 0.70689f,0.71407f,0.72117f,0.72818f,0.73511f,0.74195f,0.74870f,0.75536f,0.76192f,0.76839f, + 0.77477f,0.78105f,0.78723f,0.79331f,0.79930f,0.80518f,0.81096f,0.81664f,0.82221f,0.82768f, + 0.83305f,0.83832f,0.84347f,0.84853f,0.85348f,0.85832f,0.86306f,0.86770f,0.87223f,0.87666f, + 0.88098f,0.88521f,0.88933f,0.89334f,0.89726f,0.90108f,0.90480f,0.90842f,0.91194f,0.91537f, + 0.91870f,0.92193f,0.92508f,0.92813f,0.93109f,0.93396f,0.93675f,0.93945f,0.94206f,0.94459f, + 0.94704f,0.94941f,0.95169f,0.95391f,0.95604f,0.95810f,0.96009f,0.96201f,0.96386f,0.96564f, + 0.96735f,0.96900f,0.97059f,0.97212f,0.97358f,0.97499f,0.97634f,0.97764f,0.97888f,0.98007f, + 0.98122f,0.98231f,0.98336f,0.98436f,0.98531f,0.98623f,0.98710f,0.98793f,0.98873f,0.98949f, + 0.99021f,0.99090f,0.99155f,0.99218f,0.99277f,0.99333f,0.99387f,0.99437f,0.99486f,0.99531f, + 0.99575f,0.99616f,0.99654f,0.99691f,0.99726f,0.99759f,0.99790f,0.99819f,0.99847f,0.99873f, + 0.99897f,0.99920f,0.99942f,0.99963f,0.99982f,1.00000f + }, + { + 0.00000f,0.00000f,0.00000f,0.00001f,0.00003f,0.00006f,0.00010f,0.00017f,0.00025f,0.00035f, + 0.00048f,0.00064f,0.00083f,0.00106f,0.00132f,0.00163f,0.00197f,0.00237f,0.00281f,0.00330f, + 0.00385f,0.00446f,0.00513f,0.00585f,0.00665f,0.00751f,0.00845f,0.00945f,0.01054f,0.01170f, + 0.01295f,0.01428f,0.01569f,0.01719f,0.01879f,0.02048f,0.02227f,0.02415f,0.02614f,0.02822f, + 0.03042f,0.03272f,0.03513f,0.03765f,0.04028f,0.04303f,0.04589f,0.04887f,0.05198f,0.05520f, + 0.05855f,0.06202f,0.06561f,0.06933f,0.07318f,0.07716f,0.08127f,0.08550f,0.08987f,0.09437f, + 0.09900f,0.10376f,0.10866f,0.11369f,0.11884f,0.12414f,0.12956f,0.13512f,0.14080f,0.14662f, + 0.15257f,0.15865f,0.16485f,0.17118f,0.17764f,0.18423f,0.19093f,0.19776f,0.20471f,0.21177f, + 0.21895f,0.22625f,0.23365f,0.24117f,0.24879f,0.25652f,0.26435f,0.27228f,0.28030f,0.28842f, + 0.29662f,0.30492f,0.31329f,0.32175f,0.33028f,0.33889f,0.34756f,0.35630f,0.36510f,0.37396f, + 0.38287f,0.39183f,0.40084f,0.40989f,0.41897f,0.42809f,0.43723f,0.44640f,0.45559f,0.46479f, + 0.47401f,0.48323f,0.49245f,0.50167f,0.51088f,0.52008f,0.52927f,0.53843f,0.54757f,0.55668f, + 0.56575f,0.57479f,0.58379f,0.59274f,0.60164f,0.61048f,0.61927f,0.62799f,0.63665f,0.64524f, + 0.65376f,0.66220f,0.67056f,0.67883f,0.68702f,0.69511f,0.70312f,0.71103f,0.71884f,0.72655f, + 0.73415f,0.74165f,0.74904f,0.75632f,0.76348f,0.77053f,0.77747f,0.78428f,0.79098f,0.79756f, + 0.80401f,0.81035f,0.81655f,0.82264f,0.82859f,0.83443f,0.84013f,0.84571f,0.85117f,0.85649f, + 0.86169f,0.86677f,0.87172f,0.87654f,0.88124f,0.88581f,0.89026f,0.89459f,0.89880f,0.90289f, + 0.90686f,0.91071f,0.91445f,0.91807f,0.92157f,0.92497f,0.92826f,0.93143f,0.93450f,0.93747f, + 0.94034f,0.94310f,0.94577f,0.94833f,0.95081f,0.95319f,0.95548f,0.95768f,0.95980f,0.96183f, + 0.96378f,0.96565f,0.96744f,0.96916f,0.97081f,0.97238f,0.97388f,0.97532f,0.97669f,0.97801f, + 0.97926f,0.98045f,0.98158f,0.98266f,0.98369f,0.98467f,0.98560f,0.98648f,0.98732f,0.98811f, + 0.98886f,0.98958f,0.99025f,0.99089f,0.99149f,0.99206f,0.99260f,0.99311f,0.99359f,0.99404f, + 0.99446f,0.99486f,0.99523f,0.99559f,0.99592f,0.99623f,0.99652f,0.99679f,0.99705f,0.99729f, + 0.99751f,0.99772f,0.99792f,0.99810f,0.99827f,0.99843f,0.99857f,0.99871f,0.99884f,0.99896f, + 0.99907f,0.99917f,0.99926f,0.99935f,0.99943f,0.99951f,0.99958f,0.99964f,0.99970f,0.99975f, + 0.99980f,0.99985f,0.99989f,0.99993f,0.99997f,1.00000f + } +}; + +#define gld_CalcLightLevel(lightlevel) (lighttable[usegamma][MAX(MIN((lightlevel),255),0)]) + +/* +// experimental new lighting code +static float gld_CalcLightLevel(int lightlevel) { + if (lightlevel < 192) { + lightlevel = lightlevel - ((192 - lightlevel) * 85 / 100); + } + if (lightlevel < 20) + lightlevel = 20; + return lightlevel / 255.0; +} +*/ + +static void gld_StaticLightAlpha(float light, float alpha) +{ + player_t *player; + player = &players[displayplayer]; + + if (player->fixedcolormap) + glColor4f(1.0f, 1.0f, 1.0f, alpha); + else + glColor4f(light, light, light, alpha); +} + +#define gld_StaticLight(light) gld_StaticLightAlpha(light, 1.0f) + +static void gld_InitExtensions(const char *_extensions) +{ + char *extensions; + char *extension; + char *p; + + if (!_extensions) + return; + + extensions = malloc(strlen(_extensions) + 1); + if (!extensions) + return; + memcpy(extensions, _extensions, strlen(_extensions) + 1); + + p = extensions; + extension = p; + + do { + while ((*p != ' ') && (*p != '\0')) + p++; + if (*p != '\0') + *p++ = '\0'; + while (*p == ' ') + p++; + + if (strcasecmp(extension, "GL_EXT_texture_filter_anisotropic") == 0) + gl_texture_filter_anisotropic = true; + else if (strcasecmp(extension, "GL_EXT_paletted_texture") == 0) { + if (gl_use_paletted_texture) { + gl_paletted_texture = true; + // OpenGL ES doesn't support color tables. + // There's a warning about casting from a void pointer to a function pointer. + gld_ColorTableEXT = NULL;//SDL_GL_GetProcAddress("glColorTableEXT"); + if (gld_ColorTableEXT == NULL) + gl_paletted_texture = false; + else + lprintf(LO_INFO,"using GL_EXT_paletted_texture\n"); + } + } + else if (strcasecmp(extension, "GL_EXT_shared_texture_palette") == 0) + if (gl_use_shared_texture_palette) { + gl_shared_texture_palette = true; + // OpenGL ES doesn't support color tables. + // There's a warning about casting from a void pointer to a function pointer. + gld_ColorTableEXT = NULL;//SDL_GL_GetProcAddress("glColorTableEXT"); + if (gld_ColorTableEXT == NULL) + gl_shared_texture_palette = false; + else + lprintf(LO_INFO,"using GL_EXT_shared_texture_palette\n"); + } + + extension = p; + } while (*extension != '\0'); + + free(extensions); +} + +void gld_Init(int width, int height) +{ + GLfloat params[4]={0.0f,0.0f,1.0f,0.0f}; + GLfloat BlackFogColor[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + + // JDC: read PLAYPAL just once, instead of before every line / fill / texture build + // we are going to assume that this never gets changed in a wad file. + { + int lumpNum = W_GetNumForName( "PLAYPAL" ); + staticPlaypal = malloc( W_LumpLength( lumpNum ) ); + W_ReadLump( lumpNum, staticPlaypal ); + } + + lprintf(LO_INFO,"GL_VENDOR: %s\n",glGetString(GL_VENDOR)); + lprintf(LO_INFO,"GL_RENDERER: %s\n",glGetString(GL_RENDERER)); + lprintf(LO_INFO,"GL_VERSION: %s\n",glGetString(GL_VERSION)); + lprintf(LO_INFO,"GL_EXTENSIONS:\n"); + { + char ext_name[256]; + const char *extensions = (char *)glGetString(GL_EXTENSIONS); // JDC: fix warning + const char *rover = extensions; + const char *p = rover; + + while (*rover) + { + p = rover; + while (*p && *p != ' ') + p++; + if (*p) + { + int len = MIN(p-rover, sizeof(ext_name)-1); + memset(ext_name, 0, sizeof(ext_name)); + strncpy(ext_name, rover, len); + lprintf(LO_INFO,"\t%s\n", ext_name); + } + rover = p; + while (*rover && *rover == ' ') + rover++; + } + } + + gld_InitExtensions( (const char *)glGetString(GL_EXTENSIONS)); // JDC: fix pointer warning + //gl_shared_texture_palette = false; + gld_InitPalettedTextures(); + + glViewport(0, 0, SCREENWIDTH, SCREENHEIGHT); + + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClearDepth(1.0f); + + glGetIntegerv(GL_MAX_TEXTURE_SIZE,&gld_max_texturesize); + //gld_max_texturesize=16; + lprintf(LO_INFO,"GL_MAX_TEXTURE_SIZE=%i\n",gld_max_texturesize); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // proff_dis + glShadeModel(GL_FLAT); + glEnable(GL_TEXTURE_2D); + glDepthFunc(GL_LEQUAL); + glEnable(GL_ALPHA_TEST); + glAlphaFunc(GL_GEQUAL,0.5f); + glDisable(GL_CULL_FACE); + glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE); + + glTexGenfv(GL_Q,GL_EYE_PLANE,params); + glTexGenf(GL_S,GL_TEXTURE_GEN_MODE,GL_EYE_LINEAR); + glTexGenf(GL_T,GL_TEXTURE_GEN_MODE,GL_EYE_LINEAR); + glTexGenf(GL_Q,GL_TEXTURE_GEN_MODE,GL_EYE_LINEAR); + glFogi (GL_FOG_MODE, GL_EXP); + glFogfv(GL_FOG_COLOR, BlackFogColor); + glFogf (GL_FOG_DENSITY, (float)fog_density/1000.0f); + glHint (GL_FOG_HINT, GL_NICEST); + glFogf (GL_FOG_START, 0.0f); + glFogf (GL_FOG_END, 1.0f); + if (!strcasecmp(gl_tex_filter_string,"GL_NEAREST_MIPMAP_NEAREST")) + { + use_mipmapping=true; + gl_shared_texture_palette = false; + lprintf(LO_INFO,"Using GL_NEAREST for normal textures.\n"); + lprintf(LO_INFO,"Using GL_NEAREST_MIPMAP_NEAREST for mipmap textures.\n"); + gl_tex_filter=GL_NEAREST; + gl_mipmap_filter=GL_NEAREST_MIPMAP_NEAREST; + } + else + if (!strcasecmp(gl_tex_filter_string,"GL_LINEAR_MIPMAP_NEAREST")) + { + use_mipmapping=true; + gl_shared_texture_palette = false; + lprintf(LO_INFO,"Using GL_LINEAR for normal textures.\n"); + lprintf(LO_INFO,"Using GL_LINEAR_MIPMAP_NEAREST for mipmap textures.\n"); + gl_tex_filter=GL_LINEAR; + gl_mipmap_filter=GL_LINEAR_MIPMAP_NEAREST; + } + else + if (!strcasecmp(gl_tex_filter_string,"GL_NEAREST_MIPMAP_LINEAR")) + { + use_mipmapping=true; + gl_shared_texture_palette = false; + lprintf(LO_INFO,"Using GL_NEAREST for normal textures.\n"); + lprintf(LO_INFO,"Using GL_NEAREST_MIPMAP_LINEAR for mipmap textures.\n"); + gl_tex_filter=GL_NEAREST; + gl_mipmap_filter=GL_NEAREST_MIPMAP_LINEAR; + } + else + if (!strcasecmp(gl_tex_filter_string,"GL_LINEAR_MIPMAP_LINEAR")) + { + use_mipmapping=true; + gl_shared_texture_palette = false; + lprintf(LO_INFO,"Using GL_LINEAR for normal textures.\n"); + lprintf(LO_INFO,"Using GL_LINEAR_MIPMAP_LINEAR for mipmap textures.\n"); + gl_tex_filter=GL_LINEAR; + gl_mipmap_filter=GL_LINEAR_MIPMAP_LINEAR; + } + else + if (!strcasecmp(gl_tex_filter_string,"GL_NEAREST")) + { + use_mipmapping=false; + lprintf(LO_INFO,"Using GL_NEAREST for textures.\n"); + gl_tex_filter=GL_NEAREST; + gl_mipmap_filter=GL_NEAREST; + } + else + { + use_mipmapping=false; + lprintf(LO_INFO,"Using GL_LINEAR for textures.\n"); + gl_tex_filter=GL_LINEAR; + gl_mipmap_filter=GL_LINEAR; + } + +#ifndef USE_GLU_MIPMAP + use_mipmapping = false; +#endif + + if (!strcasecmp(gl_tex_format_string,"GL_RGBA8")) + { + gl_tex_format=GL_RGBA8; + lprintf(LO_INFO,"Using texture format GL_RGBA8.\n"); + } + else + if (!strcasecmp(gl_tex_format_string,"GL_RGB5_A1")) + { + gl_tex_format=GL_RGBA; + lprintf(LO_INFO,"Using texture format GL_RGB5_A1.\n"); + } + else + if (!strcasecmp(gl_tex_format_string,"GL_RGBA4")) + { + gl_tex_format=GL_RGBA; + lprintf(LO_INFO,"Using texture format GL_RGBA4.\n"); + } + else + if (!strcasecmp(gl_tex_format_string,"GL_RGBA2")) + { + gl_tex_format=GL_RGBA2; + lprintf(LO_INFO,"Using texture format GL_RGBA2.\n"); + } + else + { + gl_tex_format=GL_RGBA; + lprintf(LO_INFO,"Using texture format GL_RGBA.\n"); + } + +} + +void gld_InitCommandLine(void) +{ +} + +#define SCALE_X(x) ((flags & VPT_STRETCH)?((float)x)*(float)SCREENWIDTH/320.0f:(float)x) +#define SCALE_Y(y) ((flags & VPT_STRETCH)?((float)y)*(float)SCREENHEIGHT/200.0f:(float)y) + +void gld_DrawNumPatch(int x, int y, int lump, int cm, enum patch_translation_e flags) +{ + GLTexture *gltexture; + float fU1,fU2,fV1,fV2; + float width,height; + float xpos, ypos; + + if (flags & VPT_TRANS) + { + gltexture=gld_RegisterPatch(lump,cm); + gld_BindPatch(gltexture, cm); + } + else + { + gltexture=gld_RegisterPatch(lump,CR_DEFAULT); + gld_BindPatch(gltexture, CR_DEFAULT); + } + if (!gltexture) + return; + fV1=0.0f; + fV2=(float)gltexture->height/(float)gltexture->tex_height; + if (flags & VPT_FLIP) + { + fU1=(float)gltexture->width/(float)gltexture->tex_width; + fU2=0.0f; + } + else + { + fU1=0.0f; + fU2=(float)gltexture->width/(float)gltexture->tex_width; + } + xpos=SCALE_X(x-gltexture->leftoffset); + ypos=SCALE_Y(y-gltexture->topoffset); + width=SCALE_X(gltexture->realtexwidth); + height=SCALE_Y(gltexture->realtexheight); + glBegin(GL_TRIANGLE_STRIP); + glTexCoord2f(fU1, fV1); glVertex2f((xpos),(ypos)); + glTexCoord2f(fU1, fV2); glVertex2f((xpos),(ypos+height)); + glTexCoord2f(fU2, fV1); glVertex2f((xpos+width),(ypos)); + glTexCoord2f(fU2, fV2); glVertex2f((xpos+width),(ypos+height)); + glEnd(); +} + +#undef SCALE_X +#undef SCALE_Y + +void gld_DrawBackground(const char* name) +{ + GLTexture *gltexture; + float fU1,fU2,fV1,fV2; + int width,height; + + gltexture=gld_RegisterFlat(R_FlatNumForName(name), false); + gld_BindFlat(gltexture); + if (!gltexture) + return; + fU1=0; + fV1=0; + fU2=(float)SCREENWIDTH/(float)gltexture->realtexwidth; + fV2=(float)SCREENHEIGHT/(float)gltexture->realtexheight; + width=SCREENWIDTH; + height=SCREENHEIGHT; + glBegin(GL_TRIANGLE_STRIP); + glTexCoord2f(fU1, fV1); glVertex2f((float)(0),(float)(0)); + glTexCoord2f(fU1, fV2); glVertex2f((float)(0),(float)(0+height)); + glTexCoord2f(fU2, fV1); glVertex2f((float)(0+width),(float)(0)); + glTexCoord2f(fU2, fV2); glVertex2f((float)(0+width),(float)(0+height)); + glEnd(); +} + +void gld_DrawLine(int x0, int y0, int x1, int y1, int BaseColor) +{ + // JDC const unsigned char *playpal=W_CacheLumpName("PLAYPAL"); + + glBindTexture(GL_TEXTURE_2D, 0); + last_gltexture = NULL; + last_cm = -1; + glColor3f((float)staticPlaypal[3*BaseColor]/255.0f, // JDC: changed to not lookup PLAYPAL every time + (float)staticPlaypal[3*BaseColor+1]/255.0f, + (float)staticPlaypal[3*BaseColor+2]/255.0f); + glBegin(GL_LINES); + glVertex2i( x0, y0 ); + glVertex2i( x1, y1 ); + glEnd(); +// JDC W_UnlockLumpName("PLAYPAL"); +} + +void gld_DrawWeapon(int weaponlump, vissprite_t *vis, int lightlevel) +{ + GLTexture *gltexture; + float fU1,fU2,fV1,fV2; + int x1,y1,x2,y2; + float scale; + float light; + + gltexture=gld_RegisterPatch(firstspritelump+weaponlump, CR_DEFAULT); + if (!gltexture) + return; + gld_BindPatch(gltexture, CR_DEFAULT); + fU1=0; + fV1=0; + fU2=(float)gltexture->width/(float)gltexture->tex_width; + fV2=(float)gltexture->height/(float)gltexture->tex_height; + x1=viewwindowx+vis->x1; + x2=viewwindowx+vis->x2; + scale=((float)vis->scale/(float)FRACUNIT); + y1=viewwindowy+centery-(int)(((float)vis->texturemid/(float)FRACUNIT)*scale); + y2=y1+(int)((float)gltexture->realtexheight*scale)+1; +#ifdef IPHONE + // don't do the gamma table correction on the lighting + light=lightlevel * (1.0/255); + // some of the sprites come one line off the bottom of the screen + y1++; + y2++; +#else + light=gld_CalcLightLevel(lightlevel); +#endif + + if (viewplayer->mo->flags & MF_SHADOW) + { + glBlendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA); + glAlphaFunc(GL_GEQUAL,0.1f); + //glColor4f(0.2f,0.2f,0.2f,(float)tran_filter_pct/100.0f); + glColor4f(0.2f,0.2f,0.2f,0.33f); + } + else + { + if (viewplayer->mo->flags & MF_TRANSLUCENT) + gld_StaticLightAlpha(light,(float)tran_filter_pct/100.0f); + else + gld_StaticLight(light); + } + glBegin(GL_TRIANGLE_STRIP); + glTexCoord2f(fU1, fV1); glVertex2f((float)(x1),(float)(y1)); + glTexCoord2f(fU1, fV2); glVertex2f((float)(x1),(float)(y2)); + glTexCoord2f(fU2, fV1); glVertex2f((float)(x2),(float)(y1)); + glTexCoord2f(fU2, fV2); glVertex2f((float)(x2),(float)(y2)); + glEnd(); + if(viewplayer->mo->flags & MF_SHADOW) + { + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glAlphaFunc(GL_GEQUAL,0.5f); + } + glColor3f(1.0f,1.0f,1.0f); +} + +void gld_FillBlock(int x, int y, int width, int height, int col) +{ + // JDC const unsigned char *playpal=W_CacheLumpName("PLAYPAL"); + + glBindTexture(GL_TEXTURE_2D, 0); + last_gltexture = NULL; + last_cm = -1; + glColor3f((float)staticPlaypal[3*col]/255.0f, // JDC: changed to not lookup PLAYPAL every time + (float)staticPlaypal[3*col+1]/255.0f, + (float)staticPlaypal[3*col+2]/255.0f); + glBegin(GL_TRIANGLE_STRIP); + glVertex2i( x, y ); + glVertex2i( x, y+height ); + glVertex2i( x+width, y ); + glVertex2i( x+width, y+height ); + glEnd(); + glColor3f(1.0f,1.0f,1.0f); + // JDC W_UnlockLumpName("PLAYPAL"); +} + +void gld_SetPalette(int palette) +{ + static int last_palette = 0; + extra_red=0.0f; + extra_green=0.0f; + extra_blue=0.0f; + extra_alpha=0.0f; + if (palette < 0) + palette = last_palette; + last_palette = palette; + if (gl_shared_texture_palette) { + const unsigned char *playpal; + unsigned char pal[1024]; + int i; + + playpal = W_CacheLumpName("PLAYPAL"); + playpal += (768*palette); + for (i=0; i<256; i++) { + int col; + + if (fixedcolormap) + col = fixedcolormap[i]; + else if (fullcolormap) + col = fullcolormap[i]; + else + col = i; + pal[i*4+0] = playpal[col*3+0]; + pal[i*4+1] = playpal[col*3+1]; + pal[i*4+2] = playpal[col*3+2]; + pal[i*4+3] = 255; + } + pal[transparent_pal_index*4+0]=0; + pal[transparent_pal_index*4+1]=0; + pal[transparent_pal_index*4+2]=0; + pal[transparent_pal_index*4+3]=0; + gld_ColorTableEXT(GL_SHARED_TEXTURE_PALETTE_EXT, GL_RGBA, 256, GL_RGBA, GL_UNSIGNED_BYTE, pal); + W_UnlockLumpName("PLAYPAL"); + } else { + if (palette>0) + { + if (palette<=8) + { + extra_red=(float)palette/2.0f; + extra_green=0.0f; + extra_blue=0.0f; + extra_alpha=(float)palette/10.0f; + } + else + if (palette<=12) + { + palette=palette-8; + extra_red=(float)palette*1.0f; + extra_green=(float)palette*0.8f; + extra_blue=(float)palette*0.1f; + extra_alpha=(float)palette/11.0f; + } + else + if (palette==13) + { + extra_red=0.4f; + extra_green=1.0f; + extra_blue=0.0f; + extra_alpha=0.2f; + } + } + if (extra_red>1.0f) + extra_red=1.0f; + if (extra_green>1.0f) + extra_green=1.0f; + if (extra_blue>1.0f) + extra_blue=1.0f; + if (extra_alpha>1.0f) + extra_alpha=1.0f; + } +} + +unsigned char *gld_ReadScreen(void) +{ + unsigned char *scr; + unsigned char buffer[MAX_SCREENWIDTH*3]; + int i; + + scr = malloc(SCREENWIDTH * SCREENHEIGHT * 3); + if (scr) { + glReadPixels(0,0,SCREENWIDTH,SCREENHEIGHT,GL_RGB,GL_UNSIGNED_BYTE,scr); + for (i=0; i=gld_max_vertexes) + { + gld_max_vertexes+=count+1024; + gld_vertexes=Z_Realloc(gld_vertexes,gld_max_vertexes*sizeof(GLVertex),PU_LEVEL,0); + gld_texcoords=Z_Realloc(gld_texcoords,gld_max_vertexes*sizeof(GLTexcoord),PU_LEVEL,0); + } +} + +GLSeg *gl_segs=NULL; + +#if 0 +#define GLDWF_TOP 1 +#define GLDWF_M1S 2 +#define GLDWF_M2S 3 +#define GLDWF_BOT 4 +#define GLDWF_SKY 5 +#define GLDWF_SKYFLIP 6 + +typedef struct +{ + GLSeg *glseg; + float ytop,ybottom; + float ul,ur,vt,vb; + float light; + float alpha; + float skyymid; + float skyyaw; + GLTexture *gltexture; + byte flag; +} GLWall; + +typedef struct +{ + int sectornum; + float light; // the lightlevel of the flat + float uoffs,voffs; // the texture coordinates + float z; // the z position of the flat (height) + GLTexture *gltexture; + boolean ceiling; +} GLFlat; + +typedef struct +{ + int cm; + float x,y,z; + float vt,vb; + float ul,ur; + float x1,y1; + float x2,y2; + float light; + fixed_t scale; + GLTexture *gltexture; + boolean shadow; + boolean trans; +} GLSprite; + +typedef enum +{ + GLDIT_NONE, + GLDIT_WALL, + GLDIT_FLAT, + GLDIT_SPRITE +} GLDrawItemType; + +typedef struct +{ + GLDrawItemType itemtype; + int itemcount; + int firstitemindex; + byte rendermarker; +} GLDrawItem; + +typedef struct +{ + GLWall *walls; + int num_walls; + int max_walls; + GLFlat *flats; + int num_flats; + int max_flats; + GLSprite *sprites; + int num_sprites; + int max_sprites; + GLDrawItem *drawitems; + int num_drawitems; + int max_drawitems; +} GLDrawInfo; + +#endif + +GLDrawInfo gld_drawinfo; + +// this is the list for all sectors to the loops +/* JDC static */ GLSector *sectorloops; + +byte rendermarker=0; +static byte *sectorrendered; // true if sector rendered (only here for malloc) +/* JDC static */ byte *segrendered; // true if sector rendered (only here for malloc) + +static FILE *levelinfo; + +/***************************** + * + * FLATS + * + *****************************/ + +/* proff - 05/15/2000 + * The idea and algorithm to compute the flats with nodes and subsectors is + * originaly from JHexen. I have redone it. + */ + +#define FIX2DBL(x) ((double)(x)) +#define MAX_CC_SIDES 64 + +#ifndef IPHONE +static boolean gld_PointOnSide(vertex_t *p, divline_t *d) +{ + // We'll return false if the point c is on the left side. + return ((FIX2DBL(d->y)-FIX2DBL(p->y))*FIX2DBL(d->dx)-(FIX2DBL(d->x)-FIX2DBL(p->x))*FIX2DBL(d->dy) >= 0); +} + +// Lines start-end and fdiv must intersect. +static void gld_CalcIntersectionVertex(vertex_t *s, vertex_t *e, divline_t *d, vertex_t *i) +{ + double ax = FIX2DBL(s->x), ay = FIX2DBL(s->y), bx = FIX2DBL(e->x), by = FIX2DBL(e->y); + double cx = FIX2DBL(d->x), cy = FIX2DBL(d->y), dx = cx+FIX2DBL(d->dx), dy = cy+FIX2DBL(d->dy); + double r = ((ay-cy)*(dx-cx)-(ax-cx)*(dy-cy)) / ((bx-ax)*(dy-cy)-(by-ay)*(dx-cx)); + i->x = (fixed_t)((double)s->x + r*((double)e->x-(double)s->x)); + i->y = (fixed_t)((double)s->y + r*((double)e->y-(double)s->y)); +} + +#endif + +#undef FIX2DBL + +#ifndef IPHONE +// Returns a pointer to the list of points. It must be used. +// +static vertex_t *gld_FlatEdgeClipper(int *numpoints, vertex_t *points, int numclippers, divline_t *clippers) +{ + unsigned char sidelist[MAX_CC_SIDES]; + int i, k, num = *numpoints; + + // We'll clip the polygon with each of the divlines. The left side of + // each divline is discarded. + for(i=0; i= MAX_CC_SIDES) + I_Error("gld_FlatEdgeClipper: Too many points in carver"); + + // Make room for the new vertex. + memmove(&points[endIdx+1], &points[endIdx], + (num - endIdx-1)*sizeof(vertex_t)); + memcpy(&points[endIdx], &newvert, sizeof(newvert)); + + memmove(&sidelist[endIdx+1], &sidelist[endIdx], num-endIdx-1); + sidelist[endIdx] = 1; + + // Skip over the new vertex. + k++; + } + } + + // Now we must discard the points that are on the wrong side. + for(k=0; knumlines; + divline_t *clippers; + int i, numedgepoints; + vertex_t *edgepoints; + + clippers=(divline_t*)Z_Malloc(numclippers*sizeof(divline_t),PU_LEVEL,0); + if (!clippers) + return; + for(i=0; ifirstline+i-num]; + clippers[i].x = seg->v1->x; + clippers[i].y = seg->v1->y; + clippers[i].dx = seg->v2->x-seg->v1->x; + clippers[i].dy = seg->v2->y-seg->v1->y; + } + + // Setup the 'worldwide' polygon. + numedgepoints = 4; + edgepoints = (vertex_t*)Z_Malloc(numedgepoints*sizeof(vertex_t),PU_LEVEL,0); + + edgepoints[0].x = INT_MIN; + edgepoints[0].y = INT_MAX; + + edgepoints[1].x = INT_MAX; + edgepoints[1].y = INT_MAX; + + edgepoints[2].x = INT_MAX; + edgepoints[2].y = INT_MIN; + + edgepoints[3].x = INT_MIN; + edgepoints[3].y = INT_MIN; + + // Do some clipping, + edgepoints = gld_FlatEdgeClipper(&numedgepoints, edgepoints, numclippers, clippers); + + if(!numedgepoints) + { + if (levelinfo) fprintf(levelinfo, "All carved away: subsector %i - sector %i\n", ssec-subsectors, ssec->sector->iSectorID); + } + else + { + if(numedgepoints >= 3) + { + gld_AddGlobalVertexes(numedgepoints); + if ((gld_vertexes) && (gld_texcoords)) + { + int currentsector=ssec->sector->iSectorID; + + sectorloops[ currentsector ].loopcount++; + sectorloops[ currentsector ].loops=Z_Realloc(sectorloops[currentsector].loops,sizeof(GLLoopDef)*sectorloops[currentsector].loopcount, PU_LEVEL, 0); + sectorloops[ currentsector ].loops[ sectorloops[currentsector].loopcount-1 ].mode=GL_TRIANGLE_FAN; + sectorloops[ currentsector ].loops[ sectorloops[currentsector].loopcount-1 ].vertexcount=numedgepoints; + sectorloops[ currentsector ].loops[ sectorloops[currentsector].loopcount-1 ].vertexindex=gld_num_vertexes; + + for(i = 0; i < numedgepoints; i++) + { + gld_texcoords[gld_num_vertexes].u = ( (float)edgepoints[i].x/(float)FRACUNIT)/64.0f; + gld_texcoords[gld_num_vertexes].v = (-(float)edgepoints[i].y/(float)FRACUNIT)/64.0f; + gld_vertexes[gld_num_vertexes].x = -(float)edgepoints[i].x/MAP_SCALE; + gld_vertexes[gld_num_vertexes].y = 0.0f; + gld_vertexes[gld_num_vertexes].z = (float)edgepoints[i].y/MAP_SCALE; + gld_num_vertexes++; + } + } + } + } + // We're done, free the edgepoints memory. + Z_Free(edgepoints); + Z_Free(clippers); +} +#endif + +// Unused in iOS version +#ifndef IPHONE +static void gld_CarveFlats(int bspnode, int numdivlines, divline_t *divlines, boolean *sectorclosed) +{ + node_t *nod; + divline_t *childlist, *dl; + int childlistsize = numdivlines+1; + + // If this is a subsector we are dealing with, begin carving with the + // given list. + if(bspnode & NF_SUBSECTOR) + { + // We have arrived at a subsector. The divline list contains all + // the partition lines that carve out the subsector. + // special case for trivial maps (no nodes, single subsector) + int ssidx = (numnodes != 0) ? bspnode & (~NF_SUBSECTOR) : 0; + + if (!sectorclosed[subsectors[ssidx].sector->iSectorID]) + gld_FlatConvexCarver(ssidx, numdivlines, divlines); + return; + } + + // Get a pointer to the node. + nod = nodes + bspnode; + + // Allocate a new list for each child. + childlist = (divline_t*)Z_Malloc(childlistsize*sizeof(divline_t),PU_LEVEL,0); + + // Copy the previous lines. + if(divlines) memcpy(childlist,divlines,numdivlines*sizeof(divline_t)); + + dl = childlist + numdivlines; + dl->x = nod->x; + dl->y = nod->y; + // The right child gets the original line (LEFT side clipped). + dl->dx = nod->dx; + dl->dy = nod->dy; + gld_CarveFlats(nod->children[0],childlistsize,childlist,sectorclosed); + + // The left side. We must reverse the line, otherwise the wrong + // side would get clipped. + dl->dx = -nod->dx; + dl->dy = -nod->dy; + gld_CarveFlats(nod->children[1],childlistsize,childlist,sectorclosed); + + // We are finishing with this node, free the allocated list. + Z_Free(childlist); +} +#endif + +#ifdef USE_GLU_TESS + +static int currentsector; // the sector which is currently tesselated + +// ntessBegin +// +// called when the tesselation of a new loop starts + +static void CALLBACK ntessBegin( GLenum type ) +{ +#ifdef _DEBUG + if (levelinfo) + { + if (type==GL_TRIANGLES) + fprintf(levelinfo, "\t\tBegin: GL_TRIANGLES\n"); + else + if (type==GL_TRIANGLE_FAN) + fprintf(levelinfo, "\t\tBegin: GL_TRIANGLE_FAN\n"); + else + if (type==GL_TRIANGLE_STRIP) + fprintf(levelinfo, "\t\tBegin: GL_TRIANGLE_STRIP\n"); + else + fprintf(levelinfo, "\t\tBegin: unknown\n"); + } +#endif + // increase loopcount for currentsector + sectorloops[ currentsector ].loopcount++; + // reallocate to get space for another loop + // PU_LEVEL is used, so this gets freed before a new level is loaded + sectorloops[ currentsector ].loops=Z_Realloc(sectorloops[currentsector].loops,sizeof(GLLoopDef)*sectorloops[currentsector].loopcount, PU_LEVEL, 0); + // set initial values for current loop + // currentloop is -> sectorloops[currentsector].loopcount-1 + sectorloops[ currentsector ].loops[ sectorloops[currentsector].loopcount-1 ].mode=type; + sectorloops[ currentsector ].loops[ sectorloops[currentsector].loopcount-1 ].vertexcount=0; + sectorloops[ currentsector ].loops[ sectorloops[currentsector].loopcount-1 ].vertexindex=gld_num_vertexes; +} + +// ntessError +// +// called when the tesselation failes (DEBUG only) + +static void CALLBACK ntessError(GLenum error) +{ +#ifdef _DEBUG + const GLubyte *estring; + estring = gluErrorString(error); + fprintf(levelinfo, "\t\tTessellation Error: %s\n", estring); +#endif +} + +// ntessCombine +// +// called when the two or more vertexes are on the same coordinate + +static void CALLBACK ntessCombine( GLdouble coords[3], vertex_t *vert[4], GLfloat w[4], void **dataOut ) +{ +#ifdef _DEBUG + if (levelinfo) + { + fprintf(levelinfo, "\t\tVertexCombine Coords: x %10.5f, y %10.5f z %10.5f\n", coords[0], coords[1], coords[2]); + if (vert[0]) fprintf(levelinfo, "\t\tVertexCombine Vert1 : x %10i, y %10i p %p\n", vert[0]->x>>FRACBITS, vert[0]->y>>FRACBITS, vert[0]); + if (vert[1]) fprintf(levelinfo, "\t\tVertexCombine Vert2 : x %10i, y %10i p %p\n", vert[1]->x>>FRACBITS, vert[1]->y>>FRACBITS, vert[1]); + if (vert[2]) fprintf(levelinfo, "\t\tVertexCombine Vert3 : x %10i, y %10i p %p\n", vert[2]->x>>FRACBITS, vert[2]->y>>FRACBITS, vert[2]); + if (vert[3]) fprintf(levelinfo, "\t\tVertexCombine Vert4 : x %10i, y %10i p %p\n", vert[3]->x>>FRACBITS, vert[3]->y>>FRACBITS, vert[3]); + } +#endif + // just return the first vertex, because all vertexes are on the same coordinate + *dataOut = vert[0]; +} + +// ntessVertex +// +// called when a vertex is found + +static void CALLBACK ntessVertex( vertex_t *vert ) +{ +#ifdef _DEBUG + if (levelinfo) + fprintf(levelinfo, "\t\tVertex : x %10i, y %10i\n", vert->x>>FRACBITS, vert->y>>FRACBITS); +#endif + // increase vertex count + sectorloops[ currentsector ].loops[ sectorloops[currentsector].loopcount-1 ].vertexcount++; + + // increase vertex count + gld_AddGlobalVertexes(1); + // add the new vertex (vert is the second argument of gluTessVertex) + gld_texcoords[gld_num_vertexes].u=( (float)vert->x/(float)FRACUNIT)/64.0f; + gld_texcoords[gld_num_vertexes].v=(-(float)vert->y/(float)FRACUNIT)/64.0f; + gld_vertexes[gld_num_vertexes].x=-(float)vert->x/MAP_SCALE; + gld_vertexes[gld_num_vertexes].y=0.0f; + gld_vertexes[gld_num_vertexes].z= (float)vert->y/MAP_SCALE; + gld_num_vertexes++; +} + +// ntessEnd +// +// called when the tesselation of a the current loop ends (DEBUG only) + +static void CALLBACK ntessEnd( void ) +{ +#ifdef _DEBUG + if (levelinfo) + fprintf(levelinfo, "\t\tEnd loopcount %i vertexcount %i\n", sectorloops[currentsector].loopcount, sectorloops[ currentsector ].loops[ sectorloops[currentsector].loopcount-1 ].vertexcount); +#endif +} + +// gld_PrecalculateSector +// +// this calculates the loops for the sector "num" +// +// how does it work? +// first I have to credit Michael 'Kodak' Ryssen for the usage of the +// glu tesselation functions. the rest of this stuff is entirely done by me (proff). +// if there are any similarities, then they are implications of the algorithm. +// +// I'm starting with the first line of the current sector. I take it's ending vertex and +// add it to the tesselator. the current line is marked as used. then I'm searching for +// the next line which connects to the current line. if there is more than one line, I +// choose the one with the smallest angle to the current. if there is no next line, I +// start a new loop and take the first unused line in the sector. after all lines are +// processed, the polygon is tesselated. + +static void gld_PrecalculateSector(int num) +{ + int i; + boolean *lineadded=NULL; + int linecount; + int currentline; + int oldline; + int currentloop; + int bestline; + int bestlinecount; + vertex_t *startvertex; + vertex_t *currentvertex; + angle_t lineangle; + angle_t angle; + angle_t bestangle; + sector_t *currentbacksector; + GLUtesselator *tess; + double *v=NULL; + int maxvertexnum; + int vertexnum; + + currentsector=num; + lineadded=Z_Malloc(sectors[num].linecount*sizeof(boolean),PU_LEVEL,0); + if (!lineadded) + { + if (levelinfo) fclose(levelinfo); + return; + } + // init tesselator + tess=gluNewTess(); + if (!tess) + { + if (levelinfo) fclose(levelinfo); + Z_Free(lineadded); + return; + } + // set callbacks + gluTessCallback(tess, GLU_TESS_BEGIN, ntessBegin); + gluTessCallback(tess, GLU_TESS_VERTEX, ntessVertex); + gluTessCallback(tess, GLU_TESS_ERROR, ntessError); + gluTessCallback(tess, GLU_TESS_COMBINE, ntessCombine); + gluTessCallback(tess, GLU_TESS_END, ntessEnd); + if (levelinfo) fprintf(levelinfo, "sector %i, %i lines in sector\n", num, sectors[num].linecount); + // remove any line which has both sides in the same sector (i.e. Doom2 Map01 Sector 1) + for (i=0; isidenum[0]!=NO_INDEX) + if (sectors[num].lines[i]->sidenum[1]!=NO_INDEX) + if (sides[sectors[num].lines[i]->sidenum[0]].sector + ==sides[sectors[num].lines[i]->sidenum[1]].sector) + { + lineadded[i]=true; + if (levelinfo) fprintf(levelinfo, "line %4i (iLineID %4i) has both sides in same sector (removed)\n", i, sectors[num].lines[i]->iLineID); + } + } + + // initialize variables + linecount=sectors[num].linecount; + oldline=0; + currentline=0; + startvertex=sectors[num].lines[currentline]->v2; + currentloop=0; + vertexnum=0; + maxvertexnum=0; + // start tesselator + if (levelinfo) fprintf(levelinfo, "gluTessBeginPolygon\n"); + gluTessBeginPolygon(tess, NULL); + if (levelinfo) fprintf(levelinfo, "\tgluTessBeginContour\n"); + gluTessBeginContour(tess); + while (linecount) + { + // if there is no connected line, then start new loop + if ((oldline==currentline) || (startvertex==currentvertex)) + { + currentline=-1; + for (i=0; isidenum[0]!=NO_INDEX) ? (sides[sectors[num].lines[currentline]->sidenum[0]].sector==§ors[num]) : false) + startvertex=sectors[num].lines[currentline]->v1; + else + startvertex=sectors[num].lines[currentline]->v2; + if (levelinfo) fprintf(levelinfo, "\tNew Loop %3i\n", currentloop); + if (oldline!=0) + { + if (levelinfo) fprintf(levelinfo, "\tgluTessEndContour\n"); + gluTessEndContour(tess); +// if (levelinfo) fprintf(levelinfo, "\tgluNextContour\n"); +// gluNextContour(tess, GLU_CW); + if (levelinfo) fprintf(levelinfo, "\tgluTessBeginContour\n"); + gluTessBeginContour(tess); + } + break; + } + } + if (currentline==-1) + break; + // add current line + lineadded[currentline]=true; + // check if currentsector is on the front side of the line ... + if ((sectors[num].lines[currentline]->sidenum[0]!=NO_INDEX) ? (sides[sectors[num].lines[currentline]->sidenum[0]].sector==§ors[num]) : false) + { + // v2 is ending vertex + currentvertex=sectors[num].lines[currentline]->v2; + // calculate the angle of this line for use below + lineangle = R_PointToAngle2(sectors[num].lines[currentline]->v1->x,sectors[num].lines[currentline]->v1->y,sectors[num].lines[currentline]->v2->x,sectors[num].lines[currentline]->v2->y); + lineangle=(lineangle>>ANGLETOFINESHIFT)*360/8192; + if (lineangle>=180) + lineangle=lineangle-360; + if (levelinfo) fprintf(levelinfo, "\t\tAdded Line %4i to Loop, iLineID %5i, Angle: %4i, flipped false\n", currentline, sectors[num].lines[currentline]->iLineID, lineangle); + } + else // ... or on the back side + { + // v1 is ending vertex + currentvertex=sectors[num].lines[currentline]->v1; + // calculate the angle of this line for use below + lineangle = R_PointToAngle2(sectors[num].lines[currentline]->v2->x,sectors[num].lines[currentline]->v2->y,sectors[num].lines[currentline]->v1->x,sectors[num].lines[currentline]->v1->y); + lineangle=(lineangle>>ANGLETOFINESHIFT)*360/8192; + if (lineangle>=180) + lineangle=lineangle-360; + if (levelinfo) fprintf(levelinfo, "\t\tAdded Line %4i to Loop, iLineID %5i, Angle: %4i, flipped true\n", currentline, sectors[num].lines[currentline]->iLineID, lineangle); + } + if (vertexnum>=maxvertexnum) + { + maxvertexnum+=512; + v=Z_Realloc(v,maxvertexnum*3*sizeof(double),PU_LEVEL,0); + } + // calculate coordinates for the glu tesselation functions + v[vertexnum*3+0]=-(double)currentvertex->x/(double)MAP_SCALE; + v[vertexnum*3+1]=0.0; + v[vertexnum*3+2]= (double)currentvertex->y/(double)MAP_SCALE; + // add the vertex to the tesselator, currentvertex is the pointer to the vertexlist of doom + // v[vertexnum] is the GLdouble array of the current vertex + if (levelinfo) fprintf(levelinfo, "\t\tgluTessVertex(%i, %i)\n",currentvertex->x>>FRACBITS,currentvertex->y>>FRACBITS); + gluTessVertex(tess, &v[vertexnum*3], currentvertex); + // increase vertexindex + vertexnum++; + // decrease linecount of current sector + linecount--; + // find the next line + oldline=currentline; // if this isn't changed at the end of the search, a new loop will start + bestline=-1; // set to start values + bestlinecount=0; + // set backsector if there is one + if (sectors[num].lines[currentline]->sidenum[1]!=NO_INDEX) + currentbacksector=sides[sectors[num].lines[currentline]->sidenum[1]].sector; + else + currentbacksector=NULL; + // search through all lines of the current sector + for (i=0; iv1==currentvertex) || (sectors[num].lines[i]->v2==currentvertex)) + { + // calculate the angle of this best line candidate + if ((sectors[num].lines[i]->sidenum[0]!=NO_INDEX) ? (sides[sectors[num].lines[i]->sidenum[0]].sector==§ors[num]) : false) + angle = R_PointToAngle2(sectors[num].lines[i]->v1->x,sectors[num].lines[i]->v1->y,sectors[num].lines[i]->v2->x,sectors[num].lines[i]->v2->y); + else + angle = R_PointToAngle2(sectors[num].lines[i]->v2->x,sectors[num].lines[i]->v2->y,sectors[num].lines[i]->v1->x,sectors[num].lines[i]->v1->y); + angle=(angle>>ANGLETOFINESHIFT)*360/8192; + if (angle>=180) + angle=angle-360; + // check if line is flipped ... + if ((sectors[num].lines[i]->sidenum[0]!=NO_INDEX) ? (sides[sectors[num].lines[i]->sidenum[0]].sector==§ors[num]) : false) + { + // when the line is not flipped and startvertex is not the currentvertex then skip this line + if (sectors[num].lines[i]->v1!=currentvertex) + continue; + } + else + { + // when the line is flipped and endvertex is not the currentvertex then skip this line + if (sectors[num].lines[i]->v2!=currentvertex) + continue; + } + // set new best line candidate + if (bestline==-1) // if this is the first one ... + { + bestline=i; + bestangle=lineangle-angle; + bestlinecount++; + } + else + // check if the angle between the current line and this best line candidate is smaller then + // the angle of the last candidate + if (D_abs(lineangle-angle)1) + if (levelinfo) fprintf(levelinfo, "\t\tBestlinecount: %4i\n", bestlinecount); + } + } + // let the tesselator calculate the loops + if (levelinfo) fprintf(levelinfo, "\tgluTessEndContour\n"); + gluTessEndContour(tess); + if (levelinfo) fprintf(levelinfo, "gluTessEndPolygon\n"); + gluTessEndPolygon(tess); + // clean memory + gluDeleteTess(tess); + Z_Free(v); + Z_Free(lineadded); +} + +#endif /* USE_GLU_TESS */ + +/******************************************** + * Name : gld_GetSubSectorVertices * + * created : 08/13/00 * + * modified : 09/18/00, adapted for PrBoom * + * author : figgi * + * what : prepares subsectorvertices * + * (glnodes only) * + ********************************************/ + +void gld_GetSubSectorVertices(boolean *sectorclosed) +{ + int i, j; + int numedgepoints; + subsector_t* ssector; + + for(i = 0; i < numsubsectors; i++) + { + ssector = &subsectors[i]; + + if (sectorclosed[ssector->sector->iSectorID]) + continue; + + numedgepoints = ssector->numlines; + + gld_AddGlobalVertexes(numedgepoints); + + if ((gld_vertexes) && (gld_texcoords)) + { + int currentsectorid = ssector->sector->iSectorID; + + sectorloops[currentsectorid].loopcount++; + sectorloops[currentsectorid].loops = Z_Realloc(sectorloops[currentsectorid].loops,sizeof(GLLoopDef)*sectorloops[currentsectorid].loopcount, PU_LEVEL, 0); + sectorloops[currentsectorid].loops[sectorloops[currentsectorid].loopcount-1].mode = GL_TRIANGLE_FAN; + sectorloops[currentsectorid].loops[sectorloops[currentsectorid].loopcount-1].vertexcount = numedgepoints; + sectorloops[currentsectorid].loops[sectorloops[currentsector].loopcount-1].vertexindex = gld_num_vertexes; + for(j = 0; j < numedgepoints; j++) + { + gld_texcoords[gld_num_vertexes].u =( (float)(segs[ssector->firstline + j].v1->x)/FRACUNIT)/64.0f; + gld_texcoords[gld_num_vertexes].v =(-(float)(segs[ssector->firstline + j].v1->y)/FRACUNIT)/64.0f; + gld_vertexes[gld_num_vertexes].x = -(float)(segs[ssector->firstline + j].v1->x)/MAP_SCALE; + gld_vertexes[gld_num_vertexes].y = 0.0f; + gld_vertexes[gld_num_vertexes].z = (float)(segs[ssector->firstline + j].v1->y)/MAP_SCALE; + gld_num_vertexes++; + } + } + } +} + +static void gld_PrepareSectorSpecialEffects(int num) +{ + int i; + + // the following is for specialeffects. see r_bsp.c in R_Subsector + sectors[num].no_toptextures=true; + sectors[num].no_bottomtextures=true; + for (i=0; isidenum[0]!=NO_INDEX) && + (sectors[num].lines[i]->sidenum[1]!=NO_INDEX) ) + { + if (sides[sectors[num].lines[i]->sidenum[0]].toptexture!=NO_TEXTURE) + sectors[num].no_toptextures=false; + if (sides[sectors[num].lines[i]->sidenum[0]].bottomtexture!=NO_TEXTURE) + sectors[num].no_bottomtextures=false; + if (sides[sectors[num].lines[i]->sidenum[1]].toptexture!=NO_TEXTURE) + sectors[num].no_toptextures=false; + if (sides[sectors[num].lines[i]->sidenum[1]].bottomtexture!=NO_TEXTURE) + sectors[num].no_bottomtextures=false; + } + else + { + sectors[num].no_toptextures=false; + sectors[num].no_bottomtextures=false; + } + } +#ifdef _DEBUG + if (sectors[num].no_toptextures) + lprintf(LO_INFO,"Sector %i has no toptextures\n",num); + if (sectors[num].no_bottomtextures) + lprintf(LO_INFO,"Sector %i has no bottomtextures\n",num); +#endif +} + +void BuildSideSegs() { + // JDC: since we are drawing with a depth buffer, we can draw complete line + // sides instead of the cut up seg_t used by the software renderer. This saves + // about 20% of the wall primitives, and also makes the drawn geometry "water tight", + // without the occasional pixel cracks that would occur at T-junctions between cut + // walls and uncut sector geometry. + + // We can do more processing here to make the processing during drawing faster + // if we need more speed. + for ( int i = 0 ; i < numsegs ; i++ ) { + seg_t *seg = &segs[i]; + seg_t *sideSeg = &seg->sidedef->sideSeg; + *sideSeg = *seg; + // this might be either the front or back of the line + if ( seg->frontsector == seg->linedef->frontsector ) { + sideSeg->v1 = seg->linedef->v1; + sideSeg->v2 = seg->linedef->v2; + } else { + assert( seg->frontsector == seg->linedef->backsector ); + sideSeg->v1 = seg->linedef->v2; + sideSeg->v2 = seg->linedef->v1; + } + // the total length is needed for textur coordinate generation + float dx = (float)( sideSeg->v2->x - sideSeg->v1->x ) / FRACUNIT; + float dy = (float)( sideSeg->v2->y - sideSeg->v1->y ) / FRACUNIT; + sideSeg->length = sqrt( dx * dx + dy * dy ); + sideSeg->offset = 0; // full-side segs will always have 0 offset + } + + // check that every sidedef had a sideSeg created + for ( int i = 0 ; i < numsides ; i++ ) { + //assert( sides[i].sideSeg.sidedef == &sides[i] ); + } +} + +#define MAX_TRIANGLE_INDEXES 0x10000 +unsigned short triangleIndexes[MAX_TRIANGLE_INDEXES]; +int numTriangleIndexes; +void BuildIndexedTriangles() { + numTriangleIndexes = 0; + numDrawVerts = 0; + // JDC: this chnges the multiple DrawArrays calls into a single DrawElements + // and puts the vertex data into an interleaved array, duplicated for + // the floors and ceilings so they can be combined into a single draw call + // when possible. + + // There are likely duplicated vertexes in sectors with multiple loops, which + // could be a modest optimization to remove. + for ( int i = 0 ; i < numsectors ; i++ ) { + sector_t *sector = §ors[i]; + GLSector *glsector = §orloops[i]; + sector->numIndexes = 0; + sector->numVerts = 0; + int firstIndex = numTriangleIndexes; + sector->verts[0] = &drawVerts[numDrawVerts]; + sector->indexes[0] = &triangleIndexes[numTriangleIndexes]; + + for ( int j = 0 ; j < glsector->loopcount ; j++ ) { + int firstVert = numDrawVerts; + GLLoopDef *loop = &glsector->loops[j]; + drawVert_t *dv = &drawVerts[numDrawVerts]; + for ( int k = 0 ; k < loop->vertexcount ; k++ ) { + dv->xyz[0] = gld_vertexes[loop->vertexindex+k].x; + dv->xyz[1] = sector->floorheight / MAP_SCALE; + dv->xyz[2] = gld_vertexes[loop->vertexindex+k].z; + dv->st[0] = gld_texcoords[loop->vertexindex+k].u; + dv->st[1] = gld_texcoords[loop->vertexindex+k].v; + dv->rgba[0] = dv->rgba[1] = dv->rgba[2] = sector->lightlevel; + dv->rgba[3] = 255; + dv++; + } + + // Find the min texcoord value so we can move them all as close + // to the origin as possible to reduce the required interpolator precision. + // Without this, there is texture jittering visible when the viewpoint + // is near the floor and far away from the origin (dead on the ground in netplay). + float minST[2] = { 99999, 99999 }; + for ( int k = 0 ; k < loop->vertexcount ; k++ ) { + for ( int l = 0 ; l < 2 ; l++ ) { + if ( drawVerts[numDrawVerts+k].st[l] < minST[l] ) { + minST[l] = drawVerts[numDrawVerts+k].st[l]; + } + } + } + for ( int k = 0 ; k < 2 ; k++ ) { + minST[k] = floor( minST[k] ); + } + for ( int k = 0 ; k < loop->vertexcount ; k++ ) { + for ( int l = 0 ; l < 2 ; l++ ) { + drawVerts[numDrawVerts+k].st[l] -= minST[l]; + } + } + + + sector->numVerts += loop->vertexcount; + numDrawVerts += loop->vertexcount; + assert( loop->vertexcount + numTriangleIndexes < MAX_TRIANGLE_INDEXES ); + switch ( loop->mode ) { + case GL_TRIANGLES: + for ( int k = 0 ; k < loop->vertexcount ; k++ ) { + triangleIndexes[numTriangleIndexes++] = firstVert + k; + } + break; + case GL_TRIANGLE_STRIP: + for ( int k = 2 ; k < loop->vertexcount ; k++ ) { + // this doesn't keep the order correct, it flips facing every + // other one, but we don't have face culling on, so we don't care. + triangleIndexes[numTriangleIndexes++] = firstVert + k-2; + triangleIndexes[numTriangleIndexes++] = firstVert + k-1; + triangleIndexes[numTriangleIndexes++] = firstVert + k; + } + break; + case GL_TRIANGLE_FAN: + for ( int k = 2 ; k < loop->vertexcount ; k++ ) { + triangleIndexes[numTriangleIndexes++] = firstVert + 0; + triangleIndexes[numTriangleIndexes++] = firstVert + k-1; + triangleIndexes[numTriangleIndexes++] = firstVert + k; + } + break; + } + } + sector->numIndexes = numTriangleIndexes-firstIndex; + + // duplicate it for the ceiling + sector->verts[1] = &drawVerts[numDrawVerts]; + sector->indexes[1] = &triangleIndexes[numTriangleIndexes]; + memcpy( sector->verts[1], sector->verts[0], sector->numVerts * sizeof( sector->verts[0][0] ) ); + for ( int j = 0 ; j < sector->numVerts ; j++ ) { + sector->verts[1][j].xyz[1] = sector->ceilingheight / MAP_SCALE; + } + for ( int j = 0 ; j < sector->numIndexes ; j++ ) { + sector->indexes[1][j] = sector->indexes[0][j] + sector->numVerts; + } + numTriangleIndexes += sector->numIndexes; + numDrawVerts += sector->numVerts; + + assert( numDrawVerts <= MAX_DRAW_VERTS ); + assert( numTriangleIndexes <= MAX_TRIANGLE_INDEXES ); + } +} + + +// gld_PreprocessLevel +// +// this checks all sectors if they are closed and calls gld_PrecalculateSector to +// calculate the loops for every sector +// the idea to check for closed sectors is from DEU. check next commentary +/* + Note from RQ: + This is a very simple idea, but it works! The first test (above) + checks that all Sectors are closed. But if a closed set of LineDefs + is moved out of a Sector and has all its "external" SideDefs pointing + to that Sector instead of the new one, then we need a second test. + That's why I check if the SideDefs facing each other are bound to + the same Sector. + + Other note from RQ: + Nowadays, what makes the power of a good editor is its automatic tests. + So, if you are writing another Doom editor, you will probably want + to do the same kind of tests in your program. Fine, but if you use + these ideas, don't forget to credit DEU... Just a reminder... :-) +*/ +// so I credited DEU + +void gld_PreprocessSectors(void) +{ + boolean *sectorclosed; + int i; +#ifdef USE_GLU_TESS // figgi + char *vertexcheck; + int v1num; + int v2num; + int j; +#endif + + // JDC: E3M8 has a map error that has a couple lines that should + // be part of sector 1 instead orphaned off in sector 2. I could + // let the non-closed sector carving routine handle this, but it + // would result in some pixel cracks. Instead, I merge the lines + // to where they should have been. + // This is probably not the right solution, because there are + // probably a bunch of other cases in the >100 Id maps. + extern int gameepisode, gamemap; + if ( gameepisode == 3 && gamemap == 8 ) { + void IR_MergeSectors( int fromSector, int intoSector ); + IR_MergeSectors( 2, 1 ); + } + +#ifdef _DEBUG + levelinfo=fopen("levelinfo.txt","a"); + if (levelinfo) + { + if (gamemode==commercial) + fprintf(levelinfo,"MAP%02i\n",gamemap); + else + fprintf(levelinfo,"E%iM%i\n",gameepisode,gamemap); + } +#endif + + sectorclosed=Z_Malloc(numsectors*sizeof(boolean),PU_LEVEL,0); + if (!sectorclosed) + I_Error("gld_PreprocessSectors: Not enough memory for array sectorclosed"); + memset(sectorclosed, 0, sizeof(boolean)*numsectors); + + sectorloops=Z_Malloc(sizeof(GLSector)*numsectors,PU_LEVEL,0); + if (!sectorloops) + I_Error("gld_PreprocessSectors: Not enough memory for array sectorloops"); + memset(sectorloops, 0, sizeof(GLSector)*numsectors); + + sectorrendered=Z_Malloc(numsectors*sizeof(byte),PU_LEVEL,0); + if (!sectorrendered) + I_Error("gld_PreprocessSectors: Not enough memory for array sectorrendered"); + memset(sectorrendered, 0, numsectors*sizeof(byte)); + + segrendered=Z_Malloc(numsegs*sizeof(byte),PU_LEVEL,0); + if (!segrendered) + I_Error("gld_PreprocessSectors: Not enough memory for array segrendered"); + memset(segrendered, 0, numsegs*sizeof(byte)); + + gld_vertexes=NULL; + gld_texcoords=NULL; + gld_max_vertexes=0; + gld_num_vertexes=0; + gld_AddGlobalVertexes(numvertexes*2); + +#ifdef USE_GLU_TESS + vertexcheck=Z_Malloc(numvertexes*sizeof(char),PU_LEVEL,0); + if (!vertexcheck) + { + if (levelinfo) fclose(levelinfo); + I_Error("gld_PreprocessSectors: Not enough memory for array vertexcheck"); + return; + } + + for (i=0; iv1-(int)vertexes)/sizeof(vertex_t); + v2num=((int)sectors[i].lines[j]->v2-(int)vertexes)/sizeof(vertex_t); + if ((v1num>=numvertexes) || (v2num>=numvertexes)) + continue; + if (sectors[i].lines[j]->sidenum[0]!=NO_INDEX) + if (sides[sectors[i].lines[j]->sidenum[0]].sector==§ors[i]) + { + vertexcheck[v1num]|=1; + vertexcheck[v2num]|=2; + } + if (sectors[i].lines[j]->sidenum[1]!=NO_INDEX) + if (sides[sectors[i].lines[j]->sidenum[1]].sector==§ors[i]) + { + vertexcheck[v1num]|=2; + vertexcheck[v2num]|=1; + } + } + if (sectors[i].linecount<3) + { +#ifdef _DEBUG + lprintf(LO_ERROR, "sector %i is not closed! %i lines in sector\n", i, sectors[i].linecount); +#endif + if (levelinfo) fprintf(levelinfo, "sector %i is not closed! %i lines in sector\n", i, sectors[i].linecount); + sectorclosed[i]=false; + } + else + { + sectorclosed[i]=true; + for (j=0; j>ANGLETOFINESHIFT)*360.0f/FINEANGLES; + inv_yaw=-90.0f+(float)(viewangle>>ANGLETOFINESHIFT)*360.0f/FINEANGLES; + +#ifdef _DEBUG + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +#else + glClear(GL_DEPTH_BUFFER_BIT); +#endif + + glEnable(GL_DEPTH_TEST); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + + infinitePerspective(64.0f, 320.0f/200.0f, (float)gl_nearclip/100.0f); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glRotatef(roll, 0.0f, 0.0f, 1.0f); + glRotatef(pitch, 1.0f, 0.0f, 0.0f); + glRotatef(yaw, 0.0f, 1.0f, 0.0f); + glTranslatef(-xCamera, -trY, -yCamera); + + if (use_fog) + glEnable(GL_FOG); + else + glDisable(GL_FOG); + rendermarker++; + gld_drawinfo.num_walls=0; + gld_drawinfo.num_flats=0; + gld_drawinfo.num_sprites=0; + gld_drawinfo.num_drawitems=0; +} + +void gld_EndDrawScene(void) +{ + player_t *player = &players[displayplayer]; + +// JDC: not in GLES, not needed since it is the default condition glDisable(GL_POLYGON_SMOOTH); + + glViewport(0, 0, SCREENWIDTH, SCREENHEIGHT); + glDisable(GL_FOG); + gld_Set2DMode(); + + if (viewangleoffset <= 1024<=-1024<fixedcolormap == 32) { + glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO); + glColor4f(1,1,1,1); + glBindTexture(GL_TEXTURE_2D, 0); + last_gltexture = NULL; + last_cm = -1; + glBegin(GL_TRIANGLE_STRIP); + glVertex2f( 0.0f, 0.0f); + glVertex2f( 0.0f, (float)SCREENHEIGHT); + glVertex2f( (float)SCREENWIDTH, 0.0f); + glVertex2f( (float)SCREENWIDTH, (float)SCREENHEIGHT); + glEnd(); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } +#ifdef IPHONE + // when taking screenshots, we usually don't want the blend + extern float *noBlend; // its actually a cvar, but the value is the first element + if ( *noBlend == 1 ) { + extra_alpha = 0; + } + if ( *noBlend == 2 ) { + extra_alpha = 0.5; // testing performance implications + } +#endif + if (extra_alpha>0.0f) + { + glDisable(GL_ALPHA_TEST); + glColor4f(extra_red, extra_green, extra_blue, extra_alpha); + glBindTexture(GL_TEXTURE_2D, 0); + last_gltexture = NULL; + last_cm = -1; + glBegin(GL_TRIANGLE_STRIP); + glVertex2f( 0.0f, 0.0f); + glVertex2f( 0.0f, (float)SCREENHEIGHT); + glVertex2f( (float)SCREENWIDTH, 0.0f); + glVertex2f( (float)SCREENWIDTH, (float)SCREENHEIGHT); + glEnd(); + glEnable(GL_ALPHA_TEST); + } + + glColor3f(1.0f,1.0f,1.0f); + glDisable(GL_SCISSOR_TEST); + if (gl_shared_texture_palette) + glDisable(GL_SHARED_TEXTURE_PALETTE_EXT); + + // undo the 2x brightness mode now that we have drawn all the 3D stuff + glTexEnvf( GL_TEXTURE_ENV, GL_RGB_SCALE, 1.0 ); // JDC +} + +static void gld_AddDrawItem(GLDrawItemType itemtype, int itemindex) +{ + if (gld_drawinfo.num_drawitems>=gld_drawinfo.max_drawitems) + { + gld_drawinfo.max_drawitems+=64; + gld_drawinfo.drawitems=Z_Realloc(gld_drawinfo.drawitems,gld_drawinfo.max_drawitems*sizeof(GLDrawItem),PU_LEVEL,0); + gld_drawinfo.drawitems[gld_drawinfo.num_drawitems].itemtype=itemtype; + gld_drawinfo.drawitems[gld_drawinfo.num_drawitems].itemcount=1; + gld_drawinfo.drawitems[gld_drawinfo.num_drawitems].firstitemindex=itemindex; + gld_drawinfo.drawitems[gld_drawinfo.num_drawitems].rendermarker=rendermarker; + return; + } + if (gld_drawinfo.drawitems[gld_drawinfo.num_drawitems].rendermarker!=rendermarker) + { + gld_drawinfo.drawitems[gld_drawinfo.num_drawitems].itemtype=GLDIT_NONE; + gld_drawinfo.drawitems[gld_drawinfo.num_drawitems].rendermarker=rendermarker; + } + if (gld_drawinfo.drawitems[gld_drawinfo.num_drawitems].itemtype!=itemtype) + { + if (gld_drawinfo.drawitems[gld_drawinfo.num_drawitems].itemtype!=GLDIT_NONE) + gld_drawinfo.num_drawitems++; + if (gld_drawinfo.num_drawitems>=gld_drawinfo.max_drawitems) + { + gld_drawinfo.max_drawitems+=64; + gld_drawinfo.drawitems=Z_Realloc(gld_drawinfo.drawitems,gld_drawinfo.max_drawitems*sizeof(GLDrawItem),PU_LEVEL,0); + } + gld_drawinfo.drawitems[gld_drawinfo.num_drawitems].itemtype=itemtype; + gld_drawinfo.drawitems[gld_drawinfo.num_drawitems].itemcount=1; + gld_drawinfo.drawitems[gld_drawinfo.num_drawitems].firstitemindex=itemindex; + gld_drawinfo.drawitems[gld_drawinfo.num_drawitems].rendermarker=rendermarker; + return; + } + gld_drawinfo.drawitems[gld_drawinfo.num_drawitems].itemcount++; +} + +/***************** + * * + * Walls * + * * + *****************/ + +static void gld_DrawWall(GLWall *wall) +{ + + gld_BindTexture(wall->gltexture); + + if (wall->flag>=GLDWF_SKY) + { + // Dont Draw Sky Walls. + } + else + { + gld_StaticLightAlpha(wall->light, wall->alpha); + glBegin(GL_TRIANGLE_STRIP); + glTexCoord2f(wall->ul,wall->vt); glVertex3f(wall->glseg->x1,wall->ytop,wall->glseg->z1); + glTexCoord2f(wall->ul,wall->vb); glVertex3f(wall->glseg->x1,wall->ybottom,wall->glseg->z1); + glTexCoord2f(wall->ur,wall->vt); glVertex3f(wall->glseg->x2,wall->ytop,wall->glseg->z2); + glTexCoord2f(wall->ur,wall->vb); glVertex3f(wall->glseg->x2,wall->ybottom,wall->glseg->z2); + glEnd(); + } +} + +#define LINE seg->linedef +#define CALC_Y_VALUES(w, lineheight, floor_height, ceiling_height)\ + (w).ytop=((float)(ceiling_height)/(float)MAP_SCALE)+0.001f;\ + (w).ybottom=((float)(floor_height)/(float)MAP_SCALE)-0.001f;\ + lineheight=((float)fabs(((ceiling_height)/(float)FRACUNIT)-((floor_height)/(float)FRACUNIT))) + +#define OU(w,seg) (((float)((seg)->sidedef->textureoffset+(seg)->offset)/(float)FRACUNIT)/(float)(w).gltexture->buffer_width) +#define OV(w,seg) (((float)((seg)->sidedef->rowoffset)/(float)FRACUNIT)/(float)(w).gltexture->buffer_height) +#define OV_PEG(w,seg,v_offset) (OV((w),(seg))-(((float)(v_offset)/(float)FRACUNIT)/(float)(w).gltexture->buffer_height)) + +#define CALC_TEX_VALUES_TOP(w, seg, peg, linelength, lineheight)\ + (w).flag=GLDWF_TOP;\ + (w).ul=OU((w),(seg))+(0.0f);\ + (w).ur=OU((w),(seg))+((linelength)/(float)(w).gltexture->buffer_width);\ + (peg)?\ + (\ + (w).vb=OV((w),(seg))+((float)(w).gltexture->height/(float)(w).gltexture->tex_height),\ + (w).vt=((w).vb-((float)(lineheight)/(float)(w).gltexture->buffer_height))\ + ):(\ + (w).vt=OV((w),(seg))+(0.0f),\ + (w).vb=OV((w),(seg))+((float)(lineheight)/(float)(w).gltexture->buffer_height)\ + ) + +#define CALC_TEX_VALUES_MIDDLE1S(w, seg, peg, linelength, lineheight)\ + (w).flag=GLDWF_M1S;\ + (w).ul=OU((w),(seg))+(0.0f);\ + (w).ur=OU((w),(seg))+((linelength)/(float)(w).gltexture->buffer_width);\ + (peg)?\ + (\ + (w).vb=OV((w),(seg))+((float)(w).gltexture->height/(float)(w).gltexture->tex_height),\ + (w).vt=((w).vb-((float)(lineheight)/(float)(w).gltexture->buffer_height))\ + ):(\ + (w).vt=OV((w),(seg))+(0.0f),\ + (w).vb=OV((w),(seg))+((float)(lineheight)/(float)(w).gltexture->buffer_height)\ + ) + +#define CALC_TEX_VALUES_MIDDLE2S(w, seg, peg, linelength, lineheight)\ + (w).flag=GLDWF_M2S;\ + (w).ul=OU((w),(seg))+(0.0f);\ + (w).ur=OU((w),(seg))+((linelength)/(float)(w).gltexture->buffer_width);\ + (peg)?\ + (\ + (w).vb=((float)(w).gltexture->height/(float)(w).gltexture->tex_height),\ + (w).vt=((w).vb-((float)(lineheight)/(float)(w).gltexture->buffer_height))\ + ):(\ + (w).vt=(0.0f),\ + (w).vb=((float)(lineheight)/(float)(w).gltexture->buffer_height)\ + ) + +#define CALC_TEX_VALUES_BOTTOM(w, seg, peg, linelength, lineheight, v_offset)\ + (w).flag=GLDWF_BOT;\ + (w).ul=OU((w),(seg))+(0.0f);\ + (w).ur=OU((w),(seg))+((linelength)/(float)(w).gltexture->realtexwidth);\ + (peg)?\ + (\ + (w).vb=OV_PEG((w),(seg),(v_offset))+((float)(w).gltexture->height/(float)(w).gltexture->tex_height),\ + (w).vt=((w).vb-((float)(lineheight)/(float)(w).gltexture->buffer_height))\ + ):(\ + (w).vt=OV((w),(seg))+(0.0f),\ + (w).vb=OV((w),(seg))+((float)(lineheight)/(float)(w).gltexture->buffer_height)\ + ) + +// e6y +// Sky textures with a zero index should be forced +// See third episode of requiem.wad +#define SKYTEXTURE(sky1,sky2)\ + if ((sky1) & PL_SKYFLAT)\ + {\ + const line_t *l = &lines[sky1 & ~PL_SKYFLAT];\ + const side_t *s = *l->sidenum + sides;\ + wall.gltexture=gld_RegisterTexture(texturetranslation[s->toptexture], false, texturetranslation[s->toptexture]==skytexture);\ + wall.skyyaw=-2.0f*((-(float)((viewangle+s->textureoffset)>>ANGLETOFINESHIFT)*360.0f/FINEANGLES)/90.0f);\ + wall.skyymid = 200.0f/319.5f*(((float)s->rowoffset/(float)FRACUNIT - 28.0f)/100.0f);\ + wall.flag = l->special==272 ? GLDWF_SKY : GLDWF_SKYFLIP;\ + }\ + else\ + if ((sky2) & PL_SKYFLAT)\ + {\ + const line_t *l = &lines[sky2 & ~PL_SKYFLAT];\ + const side_t *s = *l->sidenum + sides;\ + wall.gltexture=gld_RegisterTexture(texturetranslation[s->toptexture], false, texturetranslation[s->toptexture]==skytexture);\ + wall.skyyaw=-2.0f*((-(float)((viewangle+s->textureoffset)>>ANGLETOFINESHIFT)*360.0f/FINEANGLES)/90.0f);\ + wall.skyymid = 200.0f/319.5f*(((float)s->rowoffset/(float)FRACUNIT - 28.0f)/100.0f);\ + wall.flag = l->special==272 ? GLDWF_SKY : GLDWF_SKYFLIP;\ + }\ + else\ + {\ + wall.gltexture=gld_RegisterTexture(skytexture, false, true);\ + wall.skyyaw=-2.0f*((yaw+90.0f)/90.0f);\ + wall.skyymid = 200.0f/319.5f*((100.0f)/100.0f);\ + wall.flag = GLDWF_SKY;\ + }; + +#define ADDWALL(wall)\ +{\ + if (gld_drawinfo.num_walls>=gld_drawinfo.max_walls)\ + {\ + gld_drawinfo.max_walls+=128;\ + gld_drawinfo.walls=Z_Realloc(gld_drawinfo.walls,gld_drawinfo.max_walls*sizeof(GLWall),PU_LEVEL,0);\ + }\ + gld_AddDrawItem(GLDIT_WALL, gld_drawinfo.num_walls);\ + gld_drawinfo.walls[gld_drawinfo.num_walls++]=*wall;\ +}; + +void gld_AddWall(seg_t *seg) +{ + GLWall wall; + GLTexture *temptex; + sector_t *theFrontsector; + sector_t *theBacksector; + sector_t ftempsec; // needed for R_FakeFlat + sector_t btempsec; // needed for R_FakeFlat + float lineheight; + int rellight = 0; + + if (!segrendered) + return; + if (segrendered[seg->iSegID]==rendermarker) + return; + segrendered[seg->iSegID]=rendermarker; + if (!seg->frontsector) + return; + theFrontsector=R_FakeFlat(seg->frontsector, &ftempsec, NULL, NULL, false); // for boom effects + if (!theFrontsector) + return; + wall.glseg=&gl_segs[seg->iSegID]; + + rellight = seg->linedef->dx==0? +8 : seg->linedef->dy==0 ? -8 : 0; + wall.light=gld_CalcLightLevel(theFrontsector->lightlevel+rellight+(extralight<<5)); + wall.alpha=1.0f; + wall.gltexture=NULL; + + if (!seg->backsector) /* onesided */ + { + if (theFrontsector->ceilingpic==skyflatnum) + { + wall.ytop=255.0f; + wall.ybottom=(float)theFrontsector->ceilingheight/MAP_SCALE; + SKYTEXTURE(theFrontsector->sky,theFrontsector->sky); + ADDWALL(&wall); + } + if (theFrontsector->floorpic==skyflatnum) + { + wall.ytop=(float)theFrontsector->floorheight/MAP_SCALE; + wall.ybottom=-255.0f; + SKYTEXTURE(theFrontsector->sky,theFrontsector->sky); + ADDWALL(&wall); + } + temptex=gld_RegisterTexture(texturetranslation[seg->sidedef->midtexture], true, false); + if (temptex) + { + wall.gltexture=temptex; + CALC_Y_VALUES(wall, lineheight, theFrontsector->floorheight, theFrontsector->ceilingheight); + CALC_TEX_VALUES_MIDDLE1S( + wall, seg, (LINE->flags & ML_DONTPEGBOTTOM)>0, + segs[seg->iSegID].length, lineheight + ); + ADDWALL(&wall); + } + } + else /* twosided */ + { + int floor_height,ceiling_height; + + theBacksector=R_FakeFlat(seg->backsector, &btempsec, NULL, NULL, true); // for boom effects + if (!theBacksector) + return; + /* toptexture */ + ceiling_height=theFrontsector->ceilingheight; + floor_height=theBacksector->ceilingheight; + if (theFrontsector->ceilingpic==skyflatnum) + { + wall.ytop=255.0f; + if ( + // e6y + // Fix for HOM in the starting area on Memento Mori map29 and on map30. + // old code: (theBacksector->ceilingheight==theBacksector->floorheight) && + (theBacksector->ceilingheight==theBacksector->floorheight||(theBacksector->ceilingheight<=theFrontsector->floorheight)) && + (theBacksector->ceilingpic==skyflatnum) + ) + { + wall.ybottom=(float)theBacksector->floorheight/MAP_SCALE; + SKYTEXTURE(theFrontsector->sky,theBacksector->sky); + ADDWALL(&wall); + } + else + { + if ( (texturetranslation[seg->sidedef->toptexture]!=NO_TEXTURE) ) + { + // e6y + // It corrects some problem with sky, but I do not remember which one + // old code: wall.ybottom=(float)theFrontsector->ceilingheight/MAP_SCALE; + wall.ybottom=(float)MAX(theFrontsector->ceilingheight,theBacksector->ceilingheight)/MAP_SCALE; + + SKYTEXTURE(theFrontsector->sky,theBacksector->sky); + ADDWALL(&wall); + } + else + if ( (theBacksector->ceilingheight <= theFrontsector->floorheight) || + (theBacksector->ceilingpic != skyflatnum) ) + { + wall.ybottom=(float)theBacksector->ceilingheight/MAP_SCALE; + SKYTEXTURE(theFrontsector->sky,theBacksector->sky); + ADDWALL(&wall); + } + } + } + if (floor_heightceilingpic==skyflatnum) && (theBacksector->ceilingpic==skyflatnum))) + { + temptex=gld_RegisterTexture(texturetranslation[seg->sidedef->toptexture], true, false); + if (temptex) + { + wall.gltexture=temptex; + CALC_Y_VALUES(wall, lineheight, floor_height, ceiling_height); + CALC_TEX_VALUES_TOP( + wall, seg, (LINE->flags & (ML_DONTPEGBOTTOM | ML_DONTPEGTOP))==0, + segs[seg->iSegID].length, lineheight + ); + ADDWALL(&wall); + } + } + } + + /* midtexture */ + //e6y + if (comp[comp_maskedanim]) + temptex=gld_RegisterTexture(seg->sidedef->midtexture, true, false); + else + // e6y + // Animated middle textures with a zero index should be forced + // See spacelab.wad (http://www.doomworld.com/idgames/index.php?id=6826) + temptex=gld_RegisterTexture(texturetranslation[seg->sidedef->midtexture], true, true); + + if (temptex && seg->sidedef->midtexture != NO_TEXTURE) + { + wall.gltexture=temptex; + if ( (LINE->flags & ML_DONTPEGBOTTOM) >0) + { + if (seg->backsector->ceilingheight<=seg->frontsector->floorheight) + goto bottomtexture; + floor_height=MAX(seg->frontsector->floorheight,seg->backsector->floorheight)+(seg->sidedef->rowoffset); + ceiling_height=floor_height+(wall.gltexture->realtexheight<backsector->ceilingheight<=seg->frontsector->floorheight) + goto bottomtexture; + ceiling_height=MIN(seg->frontsector->ceilingheight,seg->backsector->ceilingheight)+(seg->sidedef->rowoffset); + floor_height=ceiling_height-(wall.gltexture->realtexheight<flags & ML_DONTPEGBOTTOM)>0, + segs[seg->iSegID].length, lineheight + );*/ + { + int floormax, ceilingmin, linelen; + float mip; + mip = (float)wall.gltexture->realtexheight/(float)wall.gltexture->buffer_height; +// if ( (texturetranslation[seg->sidedef->bottomtexture]!=R_TextureNumForName("-")) ) + if (seg->sidedef->bottomtexture) + floormax=MAX(seg->frontsector->floorheight,seg->backsector->floorheight); + else + floormax=floor_height; + if (seg->sidedef->toptexture) + ceilingmin=MIN(seg->frontsector->ceilingheight,seg->backsector->ceilingheight); + else + ceilingmin=ceiling_height; + linelen=abs(ceiling_height-floor_height); + wall.ytop=((float)MIN(ceilingmin, ceiling_height)/(float)MAP_SCALE); + wall.ybottom=((float)MAX(floormax, floor_height)/(float)MAP_SCALE); + wall.flag=GLDWF_M2S; + wall.ul=OU((wall),(seg))+(0.0f); + wall.ur=OU(wall,(seg))+((segs[seg->iSegID].length)/(float)wall.gltexture->buffer_width); + if (floormax<=floor_height) +#ifdef USE_GLU_IMAGESCALE + wall.vb=1.0f; +#else // USE_GLU_IMAGESCALE + wall.vb=mip*1.0f; +#endif // USE_GLU_IMAGESCALE + else + wall.vb=mip*((float)(ceiling_height - floormax))/linelen; + if (ceilingmin>=ceiling_height) + wall.vt=0.0f; + else + wall.vt=mip*((float)(ceiling_height - ceilingmin))/linelen; + } + + if (seg->linedef->tranlump >= 0 && general_translucency) + wall.alpha=(float)tran_filter_pct/100.0f; + ADDWALL(&wall); + wall.alpha=1.0f; + } +bottomtexture: + /* bottomtexture */ + ceiling_height=theBacksector->floorheight; + floor_height=theFrontsector->floorheight; + if (theFrontsector->floorpic==skyflatnum) + { + wall.ybottom=-255.0f; + if ( + (theBacksector->ceilingheight==theBacksector->floorheight) && + (theBacksector->floorpic==skyflatnum) + ) + { + wall.ytop=(float)theBacksector->floorheight/MAP_SCALE; + SKYTEXTURE(theFrontsector->sky,theBacksector->sky); + ADDWALL(&wall); + } + else + { + if ( (texturetranslation[seg->sidedef->bottomtexture]!=NO_TEXTURE) ) + { + wall.ytop=(float)theFrontsector->floorheight/MAP_SCALE; + SKYTEXTURE(theFrontsector->sky,theBacksector->sky); + ADDWALL(&wall); + } + else + if ( (theBacksector->floorheight >= theFrontsector->ceilingheight) || + (theBacksector->floorpic != skyflatnum) ) + { + wall.ytop=(float)theBacksector->floorheight/MAP_SCALE; + SKYTEXTURE(theFrontsector->sky,theBacksector->sky); + ADDWALL(&wall); + } + } + } + if (floor_heightsidedef->bottomtexture], true, false); + if (temptex) + { + wall.gltexture=temptex; + CALC_Y_VALUES(wall, lineheight, floor_height, ceiling_height); + CALC_TEX_VALUES_BOTTOM( + wall, seg, (LINE->flags & ML_DONTPEGBOTTOM)>0, + segs[seg->iSegID].length, lineheight, + floor_height-theFrontsector->ceilingheight + ); + ADDWALL(&wall); + } + } + } +} + +#undef LINE +#undef CALC_Y_VALUES +#undef OU +#undef OV +#undef OV_PEG +#undef CALC_TEX_VALUES_TOP +#undef CALC_TEX_VALUES_MIDDLE1S +#undef CALC_TEX_VALUES_MIDDLE2S +#undef CALC_TEX_VALUES_BOTTOM +#undef SKYTEXTURE +#undef ADDWALL + +static void gld_PreprocessSegs(void) +{ + int i; + + gl_segs=Z_Malloc(numsegs*sizeof(GLSeg),PU_LEVEL,0); + for (i=0; ix/(float)MAP_SCALE; + gl_segs[i].z1= (float)segs[i].v1->y/(float)MAP_SCALE; + gl_segs[i].x2=-(float)segs[i].v2->x/(float)MAP_SCALE; + gl_segs[i].z2= (float)segs[i].v2->y/(float)MAP_SCALE; + } +} + +/***************** + * * + * Flats * + * * + *****************/ + +static void gld_DrawFlat(GLFlat *flat) +{ + int loopnum; // current loop number + GLLoopDef *currentloop; // the current loop +#ifndef USE_VERTEX_ARRAYS + int vertexnum; +#endif + + gld_BindFlat(flat->gltexture); + gld_StaticLight(flat->light); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glTranslatef(0.0f,flat->z,0.0f); + glMatrixMode(GL_TEXTURE); + glPushMatrix(); + glTranslatef(flat->uoffs/64.0f,flat->voffs/64.0f,0.0f); + if (flat->sectornum>=0) + { + // go through all loops of this sector +#ifndef USE_VERTEX_ARRAYS + for (loopnum=0; loopnumsectornum].loopcount; loopnum++) + { + // set the current loop + currentloop=§orloops[flat->sectornum].loops[loopnum]; + if (!currentloop) + continue; + // set the mode (GL_TRIANGLES, GL_TRIANGLE_STRIP or GL_TRIANGLE_FAN) + glBegin(currentloop->mode); + // go through all vertexes of this loop + for (vertexnum=currentloop->vertexindex; vertexnum<(currentloop->vertexindex+currentloop->vertexcount); vertexnum++) + { + // set texture coordinate of this vertex + glTexCoord2fv(&gld_texcoords[vertexnum].u); // JDC: proper element address + // set vertex coordinate + glVertex3fv(&gld_vertexes[vertexnum].x); // JDC: proper element address + } + // end of loop + glEnd(); + } +#else + for (loopnum=0; loopnumsectornum].loopcount; loopnum++) + { + // set the current loop + currentloop=§orloops[flat->sectornum].loops[loopnum]; + glDrawArrays(currentloop->mode,currentloop->vertexindex,currentloop->vertexcount); + } +#endif + } + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); +} + + +// gld_AddFlat +// +// This draws on flat for the sector "num" +// The ceiling boolean indicates if the flat is a floor(false) or a ceiling(true) + +static void gld_AddFlat(int sectornum, boolean ceiling, visplane_t *plane) +{ + sector_t *sector; // the sector we want to draw + sector_t tempsec; // needed for R_FakeFlat + int floorlightlevel; // killough 3/16/98: set floor lightlevel + int ceilinglightlevel; // killough 4/11/98 + GLFlat flat; + + if (sectornum<0) + return; + flat.sectornum=sectornum; + sector=§ors[sectornum]; // get the sector + sector=R_FakeFlat(sector, &tempsec, &floorlightlevel, &ceilinglightlevel, false); // for boom effects + flat.ceiling=ceiling; + if (!ceiling) // if it is a floor ... + { + if (sector->floorpic == skyflatnum) // don't draw if sky + return; + // get the texture. flattranslation is maintained by doom and + // contains the number of the current animation frame + flat.gltexture=gld_RegisterFlat(flattranslation[sector->floorpic], true); + if (!flat.gltexture) + return; + // get the lightlevel from floorlightlevel + flat.light=gld_CalcLightLevel(floorlightlevel+(extralight<<5)); + // calculate texture offsets + flat.uoffs=(float)sector->floor_xoffs/(float)FRACUNIT; + flat.voffs=(float)sector->floor_yoffs/(float)FRACUNIT; + } + else // if it is a ceiling ... + { + if (sector->ceilingpic == skyflatnum) // don't draw if sky + return; + // get the texture. flattranslation is maintained by doom and + // contains the number of the current animation frame + flat.gltexture=gld_RegisterFlat(flattranslation[sector->ceilingpic], true); + if (!flat.gltexture) + return; + // get the lightlevel from ceilinglightlevel + flat.light=gld_CalcLightLevel(ceilinglightlevel+(extralight<<5)); + // calculate texture offsets + flat.uoffs=(float)sector->ceiling_xoffs/(float)FRACUNIT; + flat.voffs=(float)sector->ceiling_yoffs/(float)FRACUNIT; + } + + // get height from plane + flat.z=(float)plane->height/MAP_SCALE; + + if (gld_drawinfo.num_flats>=gld_drawinfo.max_flats) + { + gld_drawinfo.max_flats+=128; + gld_drawinfo.flats=Z_Realloc(gld_drawinfo.flats,gld_drawinfo.max_flats*sizeof(GLFlat),PU_LEVEL,0); + } + gld_AddDrawItem(GLDIT_FLAT, gld_drawinfo.num_flats); + gld_drawinfo.flats[gld_drawinfo.num_flats++]=flat; +} + +void gld_AddPlane(int subsectornum, visplane_t *floor, visplane_t *ceiling) +{ + subsector_t *subsector; + + // check if all arrays are allocated + if (!sectorrendered) + return; + + subsector = &subsectors[subsectornum]; + if (!subsector) + return; + if (sectorrendered[subsector->sector->iSectorID]!=rendermarker) // if not already rendered + { + // render the floor + if (floor) + gld_AddFlat(subsector->sector->iSectorID, false, floor); + // render the ceiling + if (ceiling) + gld_AddFlat(subsector->sector->iSectorID, true, ceiling); + // set rendered true + sectorrendered[subsector->sector->iSectorID]=rendermarker; + } +} + +/***************** + * * + * Sprites * + * * + *****************/ + +static void gld_DrawSprite(GLSprite *sprite) +{ + + // transparent sprites blend and don't write to the depth buffer + glEnable( GL_BLEND ); + glDepthMask( 0 ); + + glEnable( GL_ALPHA_TEST ); + + gld_BindPatch(sprite->gltexture,sprite->cm); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + // Bring items up out of floor by configurable amount times .01 Mead 8/13/03 + glTranslatef(sprite->x,sprite->y+ (.01f * (float)gl_sprite_offset),sprite->z); + glRotatef(inv_yaw,0.0f,1.0f,0.0f); + if(sprite->shadow) + { + glBlendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA); + //glColor4f(0.2f,0.2f,0.2f,(float)tran_filter_pct/100.0f); + glAlphaFunc(GL_GEQUAL,0.1f); + glColor4f(0.2f,0.2f,0.2f,0.33f); + } + else + { + if(sprite->trans) + gld_StaticLightAlpha(sprite->light,(float)tran_filter_pct/100.0f); + else + gld_StaticLight(sprite->light); + } + glBegin(GL_TRIANGLE_STRIP); + glTexCoord2f(sprite->ul, sprite->vt); glVertex3f(sprite->x1, sprite->y1, 0.0f); + glTexCoord2f(sprite->ur, sprite->vt); glVertex3f(sprite->x2, sprite->y1, 0.0f); + glTexCoord2f(sprite->ul, sprite->vb); glVertex3f(sprite->x1, sprite->y2, 0.0f); + glTexCoord2f(sprite->ur, sprite->vb); glVertex3f(sprite->x2, sprite->y2, 0.0f); + glEnd(); + + glPopMatrix(); + + if(sprite->shadow) + { + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glAlphaFunc(GL_GEQUAL,0.5f); + } + + glDisable( GL_ALPHA_TEST ); + glDepthMask( 1 ); +} + +void gld_AddSprite(vissprite_t *vspr) +{ + mobj_t *pSpr=vspr->thing; + GLSprite sprite; + float voff,hoff; + + sprite.scale=vspr->scale; + if (pSpr->frame & FF_FULLBRIGHT) + sprite.light = 1.0f; + else + sprite.light = gld_CalcLightLevel(pSpr->subsector->sector->lightlevel+(extralight<<5)); + sprite.cm=CR_LIMIT+(int)((pSpr->flags & MF_TRANSLATION) >> (MF_TRANSSHIFT)); + sprite.gltexture=gld_RegisterPatch(vspr->patch+firstspritelump,sprite.cm); + if (!sprite.gltexture) + return; + sprite.shadow = (pSpr->flags & MF_SHADOW) != 0; + sprite.trans = (pSpr->flags & MF_TRANSLUCENT) != 0; + if (movement_smooth) + { + sprite.x = (float)(-pSpr->PrevX + FixedMul (tic_vars.frac, -pSpr->x - (-pSpr->PrevX)))/MAP_SCALE; + sprite.y = (float)(pSpr->PrevZ + FixedMul (tic_vars.frac, pSpr->z - pSpr->PrevZ))/MAP_SCALE; + sprite.z = (float)(pSpr->PrevY + FixedMul (tic_vars.frac, pSpr->y - pSpr->PrevY))/MAP_SCALE; + } + else + { + sprite.x=-(float)pSpr->x/MAP_SCALE; + sprite.y= (float)pSpr->z/MAP_SCALE; + sprite.z= (float)pSpr->y/MAP_SCALE; + } + + sprite.vt=0.0f; + sprite.vb=(float)sprite.gltexture->height/(float)sprite.gltexture->tex_height; + if (vspr->flip) + { + sprite.ul=0.0f; + sprite.ur=(float)sprite.gltexture->width/(float)sprite.gltexture->tex_width; + } + else + { + sprite.ul=(float)sprite.gltexture->width/(float)sprite.gltexture->tex_width; + sprite.ur=0.0f; + } + hoff=(float)sprite.gltexture->leftoffset/(float)(MAP_COEFF); + voff=(float)sprite.gltexture->topoffset/(float)(MAP_COEFF); + sprite.x1=hoff-((float)sprite.gltexture->realtexwidth/(float)(MAP_COEFF)); + sprite.x2=hoff; + sprite.y1=voff; + sprite.y2=voff-((float)sprite.gltexture->realtexheight/(float)(MAP_COEFF)); + + // JDC: don't let sprites poke below the ground level. + // Software rendering Doom didn't use depth buffering, + // so sprites always got drawn on top of the flat they + // were on, but in GL they tend to get a couple pixel + // rows clipped off. + if ( sprite.y2 < 0 ) { + sprite.y1 -= sprite.y2; + sprite.y2 = 0; + } + + if (gld_drawinfo.num_sprites>=gld_drawinfo.max_sprites) + { + gld_drawinfo.max_sprites+=128; + gld_drawinfo.sprites=Z_Realloc(gld_drawinfo.sprites,gld_drawinfo.max_sprites*sizeof(GLSprite),PU_LEVEL,0); + } + gld_AddDrawItem(GLDIT_SPRITE, gld_drawinfo.num_sprites); + gld_drawinfo.sprites[gld_drawinfo.num_sprites++]=sprite; +} + +/***************** + * * + * Draw * + * * + *****************/ +void gld_DrawScene(player_t *player) +{ + int i,j,k,count; + fixed_t max_scale; + + glDisable(GL_CULL_FACE); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glEnableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); + + + //----------------------------------------- + // draw the sky if needed + //----------------------------------------- + if ( true ) { + float s; + float y; + + // Note that these texcoords would have to be corrected + // for different screen aspect ratios or fields of view! + s = ((yaw+90.0f)/90.0f); + y = 1 - 2 * 128.0 / 200; + + // With identity matricies, the vertex coordinates + // can just be in the 0-1 range. + glMatrixMode( GL_MODELVIEW ); + glPushMatrix(); + glLoadIdentity(); + glMatrixMode( GL_PROJECTION ); + glPushMatrix(); + glLoadIdentity(); + + gld_BindTexture( gld_RegisterTexture( skytexture, true, true ) ); + glColor4f( 0.5, 0.5, 0.5, 1.0 ); // native texture color, not double bright + glBegin(GL_TRIANGLE_STRIP); + glTexCoord2f( s, 1 ); glVertex3f(-1,y,0.999); + glTexCoord2f( s, 0 ); glVertex3f(-1,1,0.999); + glTexCoord2f( s+1, 1 ); glVertex3f(1,y,0.999); + glTexCoord2f( s+1, 0 ); glVertex3f(1,1,0.999); + glEnd(); + + // back to the normal drawing matrix + glPopMatrix(); + glMatrixMode( GL_MODELVIEW ); + glPopMatrix(); + } + + + + rendered_visplanes = rendered_segs = rendered_vissprites = 0; + for (i=gld_drawinfo.num_drawitems; i>=0; i--) + { + switch (gld_drawinfo.drawitems[i].itemtype) + { + case GLDIT_FLAT: + // enable backside removing + glEnable(GL_CULL_FACE); + // floors + glCullFace(GL_FRONT); + for (j=(gld_drawinfo.drawitems[i].itemcount-1); j>=0; j--) + if (!gld_drawinfo.flats[j+gld_drawinfo.drawitems[i].firstitemindex].ceiling) + { + rendered_visplanes++; + gld_DrawFlat(&gld_drawinfo.flats[j+gld_drawinfo.drawitems[i].firstitemindex]); + } + // ceilings + glCullFace(GL_BACK); + for (j=(gld_drawinfo.drawitems[i].itemcount-1); j>=0; j--) + if (gld_drawinfo.flats[j+gld_drawinfo.drawitems[i].firstitemindex].ceiling) + { + rendered_visplanes++; + gld_DrawFlat(&gld_drawinfo.flats[j+gld_drawinfo.drawitems[i].firstitemindex]); + } + // disable backside removing + glDisable(GL_CULL_FACE); + break; + + default: break; + } + } + for (i=gld_drawinfo.num_drawitems; i>=0; i--) + { + switch (gld_drawinfo.drawitems[i].itemtype) + { + case GLDIT_WALL: + count=0; + for (k=GLDWF_TOP; k<=GLDWF_SKYFLIP; k++) + { + if (count>=gld_drawinfo.drawitems[i].itemcount) + continue; + if ( (gl_drawskys) && (k>=GLDWF_SKY) ) + { + // Texture gen is not supported in OpenGL ES + #ifndef IPHONE + if (comp[comp_skymap] && gl_shared_texture_palette) + glDisable(GL_SHARED_TEXTURE_PALETTE_EXT); + glEnable(GL_TEXTURE_GEN_S); + glEnable(GL_TEXTURE_GEN_T); + glEnable(GL_TEXTURE_GEN_Q); + #endif + glColor4fv(gl_whitecolor); + } + for (j=(gld_drawinfo.drawitems[i].itemcount-1); j>=0; j--) + if (gld_drawinfo.walls[j+gld_drawinfo.drawitems[i].firstitemindex].flag==k) + { + rendered_segs++; + count++; + gld_DrawWall(&gld_drawinfo.walls[j+gld_drawinfo.drawitems[i].firstitemindex]); + } + if (gl_drawskys) + { + // Texture gen is not supported in OpenGL ES + #ifndef IPHONE + glDisable(GL_TEXTURE_GEN_Q); + glDisable(GL_TEXTURE_GEN_T); + glDisable(GL_TEXTURE_GEN_S); + if (comp[comp_skymap] && gl_shared_texture_palette) + glEnable(GL_SHARED_TEXTURE_PALETTE_EXT); + #endif + } + } + break; + case GLDIT_SPRITE: + if (gl_sortsprites) + { + do + { + max_scale=INT_MAX; + k=-1; + for (j=(gld_drawinfo.drawitems[i].itemcount-1); j>=0; j--) + if (gld_drawinfo.sprites[j+gld_drawinfo.drawitems[i].firstitemindex].scale=0) + { + rendered_vissprites++; + gld_DrawSprite(&gld_drawinfo.sprites[k]); + gld_drawinfo.sprites[k].scale=INT_MAX; + } + } while (max_scale!=INT_MAX); + } + else + { + for (j=(gld_drawinfo.drawitems[i].itemcount-1); j>=0; j--,rendered_vissprites++) + gld_DrawSprite(&gld_drawinfo.sprites[j+gld_drawinfo.drawitems[i].firstitemindex]); + } + break; + default: break; + } + } +// JDC glDisableClientState(GL_TEXTURE_COORD_ARRAY); +// JDC glDisableClientState(GL_VERTEX_ARRAY); +} + +void gld_PreprocessLevel(void) +{ +#ifdef IPHONE + // defeer precache until after the first frame is drawn, so + // we get something in front of the user ASAP + extern int iphoneFrameNum; + extern int levelLoadFrameNum; + levelLoadFrameNum = iphoneFrameNum; + precache = 0; +#endif + if (precache) + gld_Precache(); + gld_PreprocessSectors(); + gld_PreprocessSegs(); + memset(&gld_drawinfo,0,sizeof(GLDrawInfo)); +#ifdef USE_VERTEX_ARRAYS // JDC + glTexCoordPointer(2,GL_FLOAT,0,gld_texcoords); + glVertexPointer(3,GL_FLOAT,0,gld_vertexes); +#endif +} + diff --git a/common/prboom/gl_struct.h b/common/prboom/gl_struct.h new file mode 100755 index 0000000..1bd0779 --- /dev/null +++ b/common/prboom/gl_struct.h @@ -0,0 +1,67 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * + *--------------------------------------------------------------------- + */ + +#ifndef _GL_STRUCT_H +#define _GL_STRUCT_H + +extern int nodesVersion; + + +extern byte *staticPlaypal; // JDC: added to avoid the continuous lookup of PLAYPAL + +void gld_Init(int width, int height); +void gld_InitCommandLine(); + +void gld_DrawNumPatch(int x, int y, int lump, int cm, enum patch_translation_e flags); +void gld_DrawBackground(const char* name); +void gld_DrawLine(int x0, int y0, int x1, int y1, int BaseColor); +void gld_DrawWeapon(int weaponlump, vissprite_t *vis, int lightlevel); +void gld_FillBlock(int x, int y, int width, int height, int col); +void gld_SetPalette(int palette); + +unsigned char *gld_ReadScreen (void); + +void gld_CleanMemory(void); +void gld_PreprocessLevel(void); + +void gld_Set2DMode(); +void gld_InitDrawScene(void); +void gld_StartDrawScene(void); +void gld_AddPlane(int subsectornum, visplane_t *floor, visplane_t *ceiling); +void gld_AddWall(seg_t *seg); +void gld_AddSprite(vissprite_t *vspr); +void gld_DrawScene(player_t *player); +void gld_EndDrawScene(void); +void gld_Finish(); + +#endif // _GL_STRUCT_H diff --git a/common/prboom/gl_texture.c b/common/prboom/gl_texture.c new file mode 100755 index 0000000..af327a9 --- /dev/null +++ b/common/prboom/gl_texture.c @@ -0,0 +1,1112 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * + *--------------------------------------------------------------------- + */ + +#include "z_zone.h" +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#endif +#ifndef CALLBACK +#define CALLBACK +#endif +#include +#include +#include +//#include +#include "SDL_opengl.h" +#include "doomtype.h" +#include "w_wad.h" +#include "m_argv.h" +#include "d_event.h" +#include "v_video.h" +#include "doomstat.h" +#include "r_bsp.h" +#include "r_main.h" +#include "r_draw.h" +#include "r_sky.h" +#include "r_plane.h" +#include "r_data.h" +#include "p_maputl.h" +#include "p_tick.h" +#include "m_bbox.h" +#include "lprintf.h" +#include "gl_intern.h" +#include "gl_struct.h" + +/* TEXTURES */ +/* static */ GLTexture **gld_GLTextures=NULL; +/* PATCHES FLATS SPRITES */ +/* static */ GLTexture **gld_GLPatchTextures=NULL; + +boolean use_mipmapping=false; + +int gld_max_texturesize=0; +const char *gl_tex_format_string; +//int gl_tex_format=GL_RGBA8; +int gl_tex_format=GL_RGBA; +//int gl_tex_format=GL_RGBA4; +//int gl_tex_format=GL_RGBA2; + +GLTexture *last_gltexture=NULL; +int last_cm=-1; + +int transparent_pal_index; +unsigned char gld_palmap[256]; + +void gld_InitPalettedTextures(void) +{ + const unsigned char *playpal; + int pal[256]; + int i,j; + + playpal= staticPlaypal; // JDC W_CacheLumpName("PLAYPAL"); + for (i=0; i<256; i++) { + pal[i] = (playpal[i*3+0] << 16) | (playpal[i*3+1] << 8) | playpal[i*3+2]; + gld_palmap[i] = i; + } + transparent_pal_index = -1; + for (i=0; i<256; i++) { + for (j=i+1; j<256; j++) { + if (pal[i] == pal[j]) { + transparent_pal_index = j; + gld_palmap[j] = i; + break; + } + } + if (transparent_pal_index >= 0) + break; + } +// JDC W_UnlockLumpName("PLAYPAL"); +} + +void gld_UploadAndMip32BitTexture( int width, int height, const byte *rgba ) { // JDC + // OpenGL ES doesn't allow format conversions by glTexImage, so if we want + // a 16 bit image, we need to convert it ourselves. For more efficient + // load times we should go directly there from the paletted textures, but + // this will be a fallback + unsigned short *buffer = malloc( width * height * 2 ); + int i, c; + + c = width * height; + for ( i = 0 ; i < c ; i++ ) { + int r = rgba[i*4+0]; + int g = rgba[i*4+1]; + int b = rgba[i*4+2]; + int a = rgba[i*4+3]; + buffer[i] = ( (r>>3)<<11 ) | ( (g>>3)<<6) | ( (b>>3)<<1 ) | ( (a>>7)<<0 ); +// buffer[i] = ( (r>>3)<<0 ) | ( (g>>3)<<5) | ( (b>>3)<<10 ) | ( (a>>7)<<15 ); + } + + glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, + width, height, + 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, buffer); + free( buffer ); + + // the built-in generate mipmaps is pretty fast +#ifdef GL_OES_framebuffer_object // JDC + glGenerateMipmapOES( GL_TEXTURE_2D ); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST ); +#endif +} + + +int gld_GetTexDimension(int value) +{ + int i; + + i=1; + while (igld_max_texturesize) + i=gld_max_texturesize; + return i; +} + +static GLTexture *gld_AddNewGLTexture(int texture_num) +{ + if (texture_num<0) + return NULL; + if (texture_num>=numtextures) + return NULL; + if (!gld_GLTextures) + { + gld_GLTextures=Z_Malloc(numtextures*sizeof(GLTexture *),PU_STATIC,0); + memset(gld_GLTextures,0,numtextures*sizeof(GLTexture *)); + } + if (!gld_GLTextures[texture_num]) + { + gld_GLTextures[texture_num]=Z_Malloc(sizeof(GLTexture),PU_STATIC,0); + memset(gld_GLTextures[texture_num], 0, sizeof(GLTexture)); + gld_GLTextures[texture_num]->textype=GLDT_UNREGISTERED; + } + return gld_GLTextures[texture_num]; +} + +static GLTexture *gld_AddNewGLPatchTexture(int lump) +{ + if (lump<0) + return NULL; + if (lump>=numlumps) + return NULL; + if (!gld_GLPatchTextures) + { + gld_GLPatchTextures=Z_Malloc(numlumps*sizeof(GLTexture *),PU_STATIC,0); + memset(gld_GLPatchTextures,0,numlumps*sizeof(GLTexture *)); + } + if (!gld_GLPatchTextures[lump]) + { + gld_GLPatchTextures[lump]=Z_Malloc(sizeof(GLTexture),PU_STATIC,0); + memset(gld_GLPatchTextures[lump], 0, sizeof(GLTexture)); + gld_GLPatchTextures[lump]->textype=GLDT_UNREGISTERED; + } + return gld_GLPatchTextures[lump]; +} + +void gld_SetTexturePalette(GLenum target) +{ + const unsigned char *playpal; + unsigned char pal[1024]; + int i; + + playpal= staticPlaypal; // JDC W_CacheLumpName("PLAYPAL"); + for (i=0; i<256; i++) { + pal[i*4+0] = playpal[i*3+0]; + pal[i*4+1] = playpal[i*3+1]; + pal[i*4+2] = playpal[i*3+2]; + pal[i*4+3] = 255; + } + pal[transparent_pal_index*4+0]=0; + pal[transparent_pal_index*4+1]=0; + pal[transparent_pal_index*4+2]=0; + pal[transparent_pal_index*4+3]=0; + gld_ColorTableEXT(target, GL_RGBA, 256, GL_RGBA, GL_UNSIGNED_BYTE, pal); +//JDC W_UnlockLumpName("PLAYPAL"); +} + +static void gld_AddPatchToTexture_UnTranslated(GLTexture *gltexture, unsigned char *buffer, const rpatch_t *patch, int originx, int originy, int paletted) +{ + int x,y,j; + int xs,xe; + int js,je; + const rcolumn_t *column; + const byte *source; + int i, pos; + const unsigned char *playpal; + + if (!gltexture) + return; + if (!patch) + return; + playpal= staticPlaypal; // JDC W_CacheLumpName("PLAYPAL"); + xs=0; + xe=patch->width; + if ((xs+originx)>=gltexture->realtexwidth) + return; + if ((xe+originx)<=0) + return; + if ((xs+originx)<0) + xs=-originx; + if ((xe+originx)>gltexture->realtexwidth) + xe+=(gltexture->realtexwidth-(xe+originx)); + for (x=xs;x=patch->width) + { + lprintf(LO_ERROR,"gld_AddPatchToTexture_UnTranslated x>=patch->width (%i >= %i)\n",x,patch->width); + return; + } +#endif + column = &patch->columns[x]; + for (i=0; inumPosts; i++) { + const rpost_t *post = &column->posts[i]; + y=(post->topdelta+originy); + js=0; + je=post->length; + if ((js+y)>=gltexture->realtexheight) + continue; + if ((je+y)<=0) + continue; + if ((js+y)<0) + js=-y; + if ((je+y)>gltexture->realtexheight) + je+=(gltexture->realtexheight-(je+y)); + source = column->pixels + post->topdelta; + if (paletted) { + pos=(((js+y)*gltexture->buffer_width)+x+originx); + for (j=js;jbuffer_width)) + { +#ifdef RANGECHECK + if (pos>=gltexture->buffer_size) + { + lprintf(LO_ERROR,"gld_AddPatchToTexture_UnTranslated pos>=size (%i >= %i)\n",pos+3,gltexture->buffer_size); + return; + } +#endif + buffer[pos]=gld_palmap[source[j]]; + } + } else { + pos=4*(((js+y)*gltexture->buffer_width)+x+originx); + for (j=js;jbuffer_width)) + { +#ifdef RANGECHECK + if ((pos+3)>=gltexture->buffer_size) + { + lprintf(LO_ERROR,"gld_AddPatchToTexture_UnTranslated pos+3>=size (%i >= %i)\n",pos+3,gltexture->buffer_size); + return; + } +#endif + buffer[pos]=playpal[source[j]*3]; + buffer[pos+1]=playpal[source[j]*3+1]; + buffer[pos+2]=playpal[source[j]*3+2]; + buffer[pos+3]=255; + } + } + } + } +// JDC W_UnlockLumpName("PLAYPAL"); +} + +void gld_AddPatchToTexture(GLTexture *gltexture, unsigned char *buffer, const rpatch_t *patch, int originx, int originy, int cm, int paletted) +{ + int x,y,j; + int xs,xe; + int js,je; + const rcolumn_t *column; + const byte *source; + int i, pos; + const unsigned char *playpal; + const unsigned char *outr; + + if (!gltexture) + return; + if (!patch) + return; + if ((cm==CR_DEFAULT) || (cm==CR_LIMIT)) + { + gld_AddPatchToTexture_UnTranslated(gltexture,buffer,patch,originx,originy, paletted); + return; + } + if (cmwidth; + if ((xs+originx)>=gltexture->realtexwidth) + return; + if ((xe+originx)<=0) + return; + if ((xs+originx)<0) + xs=-originx; + if ((xe+originx)>gltexture->realtexwidth) + xe+=(gltexture->realtexwidth-(xe+originx)); + for (x=xs;x=patch->width) + { + lprintf(LO_ERROR,"gld_AddPatchToTexture x>=patch->width (%i >= %i)\n",x,patch->width); + return; + } +#endif + column = &patch->columns[x]; + for (i=0; inumPosts; i++) { + const rpost_t *post = &column->posts[i]; + y=(post->topdelta+originy); + js=0; + je=post->length; + if ((js+y)>=gltexture->realtexheight) + continue; + if ((je+y)<=0) + continue; + if ((js+y)<0) + js=-y; + if ((je+y)>gltexture->realtexheight) + je+=(gltexture->realtexheight-(je+y)); + source = column->pixels + post->topdelta; + if (paletted) { + pos=(((js+y)*gltexture->buffer_width)+x+originx); + for (j=js;jbuffer_width)) + { +#ifdef RANGECHECK + if (pos>=gltexture->buffer_size) + { + lprintf(LO_ERROR,"gld_AddPatchToTexture_UnTranslated pos>=size (%i >= %i)\n",pos+3,gltexture->buffer_size); + return; + } +#endif + buffer[pos]=gld_palmap[outr[source[j]]]; + } + } else { + pos=4*(((js+y)*gltexture->buffer_width)+x+originx); + for (j=js;jbuffer_width)) + { +#ifdef RANGECHECK + if ((pos+3)>=gltexture->buffer_size) + { + lprintf(LO_ERROR,"gld_AddPatchToTexture pos+3>=size (%i >= %i)\n",pos+3,gltexture->buffer_size); + return; + } +#endif + buffer[pos]=playpal[outr[source[j]]*3]; + buffer[pos+1]=playpal[outr[source[j]]*3+1]; + buffer[pos+2]=playpal[outr[source[j]]*3+2]; + buffer[pos+3]=255; + } + } + } + } +// JDC W_UnlockLumpName("PLAYPAL"); +} + +static void gld_AddFlatToTexture(GLTexture *gltexture, unsigned char *buffer, const unsigned char *flat, int paletted) +{ + int x,y,pos; + const unsigned char *playpal; + + if (!gltexture) + return; + if (!flat) + return; + if (paletted) { + for (y=0;yrealtexheight;y++) + { + pos=(y*gltexture->buffer_width); + for (x=0;xrealtexwidth;x++,pos++) + { +#ifdef RANGECHECK + if (pos>=gltexture->buffer_size) + { + lprintf(LO_ERROR,"gld_AddFlatToTexture pos>=size (%i >= %i)\n",pos,gltexture->buffer_size); + return; + } +#endif + buffer[pos]=gld_palmap[flat[y*64+x]]; + } + } + } else { + playpal= staticPlaypal; // JDC W_CacheLumpName("PLAYPAL"); + for (y=0;yrealtexheight;y++) + { + pos=4*(y*gltexture->buffer_width); + for (x=0;xrealtexwidth;x++,pos+=4) + { +#ifdef RANGECHECK + if ((pos+3)>=gltexture->buffer_size) + { + lprintf(LO_ERROR,"gld_AddFlatToTexture pos+3>=size (%i >= %i)\n",pos+3,gltexture->buffer_size); + return; + } +#endif + buffer[pos]=playpal[flat[y*64+x]*3]; + buffer[pos+1]=playpal[flat[y*64+x]*3+1]; + buffer[pos+2]=playpal[flat[y*64+x]*3+2]; + buffer[pos+3]=255; + } + } + // JDC W_UnlockLumpName("PLAYPAL"); + } +} + +//e6y: "force" flag for loading texture with zero index +GLTexture *gld_RegisterTexture(int texture_num, boolean mipmap, boolean force) +{ + GLTexture *gltexture; + + //e6y: textures with zero index should be loaded sometimes + if (texture_num==NO_TEXTURE && !force) + return NULL; + gltexture=gld_AddNewGLTexture(texture_num); + if (!gltexture) + return NULL; + if (gltexture->textype==GLDT_UNREGISTERED) + { + texture_t *texture=NULL; + + if ((texture_num>=0) || (texture_numtextype=GLDT_BROKEN; + gltexture->index=texture_num; + gltexture->mipmap=mipmap; + gltexture->realtexwidth=texture->width; + gltexture->realtexheight=texture->height; + gltexture->leftoffset=0; + gltexture->topoffset=0; + gltexture->tex_width=gld_GetTexDimension(gltexture->realtexwidth); + gltexture->tex_height=gld_GetTexDimension(gltexture->realtexheight); + gltexture->width=MIN(gltexture->realtexwidth, gltexture->tex_width); + gltexture->height=MIN(gltexture->realtexheight, gltexture->tex_height); + gltexture->buffer_width=gltexture->tex_width; + gltexture->buffer_height=gltexture->tex_height; +#ifdef USE_GLU_IMAGESCALE + gltexture->width=gltexture->tex_width; + gltexture->height=gltexture->tex_height; + gltexture->buffer_width=gltexture->realtexwidth; + gltexture->buffer_height=gltexture->realtexheight; +#endif + if (gltexture->mipmap & use_mipmapping) + { + gltexture->width=gltexture->tex_width; + gltexture->height=gltexture->tex_height; + gltexture->buffer_width=gltexture->realtexwidth; + gltexture->buffer_height=gltexture->realtexheight; + } + gltexture->buffer_size=gltexture->buffer_width*gltexture->buffer_height*4; + if (gltexture->realtexwidth>gltexture->buffer_width) + return gltexture; + if (gltexture->realtexheight>gltexture->buffer_height) + return gltexture; + gltexture->textype=GLDT_TEXTURE; + } + + return gltexture; +} + +void gld_BindTexture(GLTexture *gltexture) +{ + const rpatch_t *patch; + unsigned char *buffer; + + if (gltexture==last_gltexture) + return; + last_gltexture=gltexture; + if (!gltexture) { + glBindTexture(GL_TEXTURE_2D, 0); + last_gltexture = NULL; + last_cm = -1; + return; + } + if (gltexture->textype!=GLDT_TEXTURE) + { + glBindTexture(GL_TEXTURE_2D, 0); + last_gltexture = NULL; + last_cm = -1; + return; + } + if (gltexture->glTexID[CR_DEFAULT]!=0) + { + glBindTexture(GL_TEXTURE_2D, gltexture->glTexID[CR_DEFAULT]); +#ifndef GL_VERSION_ES_CL_1_1 // no GL_TEXTURE_RESIDENT in GLES + glGetTexParameteriv(GL_TEXTURE_2D,GL_TEXTURE_RESIDENT,&i); +#ifdef _DEBUG + if (i!=GL_TRUE) + lprintf(LO_INFO, "glGetTexParam: %i\n", i); +#endif + if (i==GL_TRUE) +#endif // GL_VERSION_ES_CL_1_1 + return; + } + buffer=(unsigned char*)Z_Malloc(gltexture->buffer_size,PU_STATIC,0); + if (!(gltexture->mipmap & use_mipmapping) & gl_paletted_texture) + memset(buffer,transparent_pal_index,gltexture->buffer_size); + else + memset(buffer,0,gltexture->buffer_size); + patch=R_CacheTextureCompositePatchNum(gltexture->index); + gld_AddPatchToTexture(gltexture, buffer, patch, + 0, 0, + CR_DEFAULT, !(gltexture->mipmap & use_mipmapping) & gl_paletted_texture); + R_UnlockTextureCompositePatchNum(gltexture->index); + if (gltexture->glTexID[CR_DEFAULT]==0) + glGenTextures(1,&gltexture->glTexID[CR_DEFAULT]); + glBindTexture(GL_TEXTURE_2D, gltexture->glTexID[CR_DEFAULT]); +#ifdef USE_GLU_MIPMAP + if (gltexture->mipmap & use_mipmapping) + { + gluBuild2DMipmaps(GL_TEXTURE_2D, gl_tex_format, + gltexture->buffer_width, gltexture->buffer_height, + GL_RGBA, GL_UNSIGNED_BYTE, buffer); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_tex_filter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_mipmap_filter); + if (gl_texture_filter_anisotropic) + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 2.0); + } + else +#endif /* USE_GLU_MIPMAP */ + { +#ifdef USE_GLU_IMAGESCALE + if ((gltexture->buffer_width!=gltexture->tex_width) || + (gltexture->buffer_height!=gltexture->tex_height) + ) + { + unsigned char *scaledbuffer; + + scaledbuffer=(unsigned char*)Z_Malloc(gltexture->tex_width*gltexture->tex_height*4,PU_STATIC,0); + if (scaledbuffer) + { + gluScaleImage(GL_RGBA, + gltexture->buffer_width, gltexture->buffer_height, + GL_UNSIGNED_BYTE,buffer, + gltexture->tex_width, gltexture->tex_height, + GL_UNSIGNED_BYTE,scaledbuffer); + Z_Free(buffer); + buffer=scaledbuffer; + glTexImage2D( GL_TEXTURE_2D, 0, gl_tex_format, + gltexture->tex_width, gltexture->tex_height, + 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer); + } + } + else +#endif /* USE_GLU_IMAGESCALE */ + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_tex_filter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_tex_filter); +#ifdef IPHONE // JDC, convert the texture to 16 bit and mipmap + gld_UploadAndMip32BitTexture( gltexture->buffer_width, gltexture->buffer_height, buffer); +#else + { + if (gl_paletted_texture) { + gld_SetTexturePalette(GL_TEXTURE_2D); + glTexImage2D( GL_TEXTURE_2D, 0, GL_COLOR_INDEX8_EXT, + gltexture->buffer_width, gltexture->buffer_height, + 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, buffer); + } else { + glTexImage2D( GL_TEXTURE_2D, 0, gl_tex_format, + gltexture->buffer_width, gltexture->buffer_height, + 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer); + } + } +#endif + } + Z_Free(buffer); +} + +GLTexture *gld_RegisterPatch(int lump, int cm) +{ + const rpatch_t *patch; + GLTexture *gltexture; + + gltexture=gld_AddNewGLPatchTexture(lump); + if (!gltexture) + return NULL; + if (gltexture->textype==GLDT_UNREGISTERED) + { + patch=R_CachePatchNum(lump); + if (!patch) + return NULL; + gltexture->textype=GLDT_BROKEN; + gltexture->index=lump; + gltexture->mipmap=false; + gltexture->realtexwidth=patch->width; + gltexture->realtexheight=patch->height; + gltexture->leftoffset=patch->leftoffset; + gltexture->topoffset=patch->topoffset; + gltexture->tex_width=gld_GetTexDimension(gltexture->realtexwidth); + gltexture->tex_height=gld_GetTexDimension(gltexture->realtexheight); + gltexture->width=MIN(gltexture->realtexwidth, gltexture->tex_width); + gltexture->height=MIN(gltexture->realtexheight, gltexture->tex_height); + gltexture->buffer_width=gltexture->tex_width; + gltexture->buffer_height=gltexture->tex_height; +#ifdef USE_GLU_IMAGESCALE + gltexture->width=MIN(gltexture->realtexwidth, gltexture->tex_width); + gltexture->height=MIN(gltexture->realtexheight, gltexture->tex_height); + gltexture->buffer_width=MAX(gltexture->realtexwidth, gltexture->tex_width); + gltexture->buffer_height=MAX(gltexture->realtexheight, gltexture->tex_height); +#endif + gltexture->buffer_size=gltexture->buffer_width*gltexture->buffer_height*4; + R_UnlockPatchNum(lump); + if (gltexture->realtexwidth>gltexture->buffer_width) + return gltexture; + if (gltexture->realtexheight>gltexture->buffer_height) + return gltexture; + gltexture->textype=GLDT_PATCH; + } + return gltexture; +} + +void gld_BindPatch(GLTexture *gltexture, int cm) +{ + const rpatch_t *patch; + unsigned char *buffer; + + if ((gltexture==last_gltexture) && (cm==last_cm)) + return; + last_gltexture=gltexture; + last_cm=cm; + if (!gltexture) + return; + if (gltexture->textype!=GLDT_PATCH) + { + glBindTexture(GL_TEXTURE_2D, 0); + last_gltexture = NULL; + last_cm = -1; + return; + } + if (gltexture->glTexID[cm]!=0) + { + glBindTexture(GL_TEXTURE_2D, gltexture->glTexID[cm]); +#ifndef GL_VERSION_ES_CL_1_1 // JDC no GL_TEXTURE_RESIDENT in GLES + glGetTexParameteriv(GL_TEXTURE_2D,GL_TEXTURE_RESIDENT,&i); +#ifdef _DEBUG + if (i!=GL_TRUE) + lprintf(LO_INFO, "glGetTexParam: %i\n", i); +#endif + if (i==GL_TRUE) +#endif // GL_VERSION_ES_CL_1_1 + return; + } + patch=R_CachePatchNum(gltexture->index); + buffer=(unsigned char*)Z_Malloc(gltexture->buffer_size,PU_STATIC,0); + if (gl_paletted_texture) + memset(buffer,transparent_pal_index,gltexture->buffer_size); + else + memset(buffer,0,gltexture->buffer_size); + gld_AddPatchToTexture(gltexture, buffer, patch, 0, 0, cm, gl_paletted_texture); + assert( cm >= 0 && cm < sizeof( gltexture->glTexID ) / sizeof( gltexture->glTexID[0] ) ); // JDC + if (gltexture->glTexID[cm]==0) + glGenTextures(1,&gltexture->glTexID[cm]); + glBindTexture(GL_TEXTURE_2D, gltexture->glTexID[cm]); +#ifdef USE_GLU_IMAGESCALE + if ((gltexture->buffer_width>gltexture->tex_width) || + (gltexture->buffer_height>gltexture->tex_height) + ) + { + unsigned char *scaledbuffer; + + scaledbuffer=(unsigned char*)Z_Malloc(gltexture->tex_width*gltexture->tex_height*4,PU_STATIC,0); + if (scaledbuffer) + { + gluScaleImage(GL_RGBA, + gltexture->buffer_width, gltexture->buffer_height, + GL_UNSIGNED_BYTE,buffer, + gltexture->tex_width, gltexture->tex_height, + GL_UNSIGNED_BYTE,scaledbuffer); + Z_Free(buffer); + buffer=scaledbuffer; + glTexImage2D( GL_TEXTURE_2D, 0, gl_tex_format, + gltexture->tex_width, gltexture->tex_height, + 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer); + } + } + else +#endif /* USE_GLU_IMAGESCALE */ + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_tex_filter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_tex_filter); +#ifdef IPHONE // JDC, convert the texture to 16 bit and mipmap + gld_UploadAndMip32BitTexture( gltexture->buffer_width, gltexture->buffer_height, buffer); +#else + { + if (gl_paletted_texture) { + gld_SetTexturePalette(GL_TEXTURE_2D); + glTexImage2D( GL_TEXTURE_2D, 0, GL_COLOR_INDEX8_EXT, + gltexture->buffer_width, gltexture->buffer_height, + 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, buffer); + } else { + glTexImage2D( GL_TEXTURE_2D, 0, gl_tex_format, + gltexture->buffer_width, gltexture->buffer_height, + 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer); + } + } +#endif + printf( "bindPatch on lump: %i '%s' : %i\n", gltexture->index, lumpinfo[ gltexture->index ].name, cm ); // !@# JDC + Z_Free(buffer); + R_UnlockPatchNum(gltexture->index); +} + +GLTexture *gld_RegisterFlat(int lump, boolean mipmap) +{ + GLTexture *gltexture; + + gltexture=gld_AddNewGLPatchTexture(firstflat+lump); + if (!gltexture) + return NULL; + if (gltexture->textype==GLDT_UNREGISTERED) + { + gltexture->textype=GLDT_BROKEN; + gltexture->index=firstflat+lump; + gltexture->mipmap=mipmap; + gltexture->realtexwidth=64; + gltexture->realtexheight=64; + gltexture->leftoffset=0; + gltexture->topoffset=0; + gltexture->tex_width=gld_GetTexDimension(gltexture->realtexwidth); + gltexture->tex_height=gld_GetTexDimension(gltexture->realtexheight); + gltexture->width=MIN(gltexture->realtexwidth, gltexture->tex_width); + gltexture->height=MIN(gltexture->realtexheight, gltexture->tex_height); + gltexture->buffer_width=gltexture->tex_width; + gltexture->buffer_height=gltexture->tex_height; +#ifdef USE_GLU_IMAGESCALE + gltexture->width=gltexture->tex_width; + gltexture->height=gltexture->tex_height; + gltexture->buffer_width=gltexture->realtexwidth; + gltexture->buffer_height=gltexture->realtexheight; +#endif + if (gltexture->mipmap & use_mipmapping) + { + gltexture->width=gltexture->tex_width; + gltexture->height=gltexture->tex_height; + gltexture->buffer_width=gltexture->realtexwidth; + gltexture->buffer_height=gltexture->realtexheight; + } + gltexture->buffer_size=gltexture->buffer_width*gltexture->buffer_height*4; + if (gltexture->realtexwidth>gltexture->buffer_width) + return gltexture; + if (gltexture->realtexheight>gltexture->buffer_height) + return gltexture; + gltexture->textype=GLDT_FLAT; + } + return gltexture; +} + +void gld_BindFlat(GLTexture *gltexture) +{ + const unsigned char *flat; + unsigned char *buffer; + + if (gltexture==last_gltexture) + return; + last_gltexture=gltexture; + if (!gltexture) + return; + if (gltexture->textype!=GLDT_FLAT) + { + glBindTexture(GL_TEXTURE_2D, 0); + last_gltexture = NULL; + last_cm = -1; + return; + } + if (gltexture->glTexID[CR_DEFAULT]!=0) + { + glBindTexture(GL_TEXTURE_2D, gltexture->glTexID[CR_DEFAULT]); +#ifndef GL_VERSION_ES_CL_1_1 // no GL_TEXTURE_RESIDENT in GLES + glGetTexParameteriv(GL_TEXTURE_2D,GL_TEXTURE_RESIDENT,&i); +#ifdef _DEBUG + if (i!=GL_TRUE) + lprintf(LO_INFO, "glGetTexParam: %i\n", i); +#endif + if (i==GL_TRUE) +#endif // GL_VERSION_ES_CL_1_1 + return; + } + flat=W_CacheLumpNum(gltexture->index); + buffer=(unsigned char*)Z_Malloc(gltexture->buffer_size,PU_STATIC,0); + if (!(gltexture->mipmap & use_mipmapping) & gl_paletted_texture) + memset(buffer,transparent_pal_index,gltexture->buffer_size); + else + memset(buffer,0,gltexture->buffer_size); + gld_AddFlatToTexture(gltexture, buffer, flat, !(gltexture->mipmap & use_mipmapping) & gl_paletted_texture); + if (gltexture->glTexID[CR_DEFAULT]==0) + glGenTextures(1,&gltexture->glTexID[CR_DEFAULT]); + glBindTexture(GL_TEXTURE_2D, gltexture->glTexID[CR_DEFAULT]); +#if USE_GLU_MIPMAP + if (gltexture->mipmap & use_mipmapping) + { + gluBuild2DMipmaps(GL_TEXTURE_2D, gl_tex_format, + gltexture->buffer_width, gltexture->buffer_height, + GL_RGBA, GL_UNSIGNED_BYTE, buffer); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_tex_filter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_mipmap_filter); + if (gl_texture_filter_anisotropic) + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 2.0); + } + else +#endif /* USE_GLU_MIPMAP */ + { +#ifdef USE_GLU_IMAGESCALE + if ((gltexture->buffer_width!=gltexture->tex_width) || + (gltexture->buffer_height!=gltexture->tex_height) + ) + { + unsigned char *scaledbuffer; + + scaledbuffer=(unsigned char*)Z_Malloc(gltexture->tex_width*gltexture->tex_height*4,PU_STATIC,0); + if (scaledbuffer) + { + gluScaleImage(GL_RGBA, + gltexture->buffer_width, gltexture->buffer_height, + GL_UNSIGNED_BYTE,buffer, + gltexture->tex_width, gltexture->tex_height, + GL_UNSIGNED_BYTE,scaledbuffer); + Z_Free(buffer); + buffer=scaledbuffer; + glTexImage2D( GL_TEXTURE_2D, 0, gl_tex_format, + gltexture->tex_width, gltexture->tex_height, + 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer); + } + } + else +#endif /* USE_GLU_IMAGESCALE */ + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_tex_filter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_tex_filter); +#ifdef IPHONE // JDC, convert the texture to 16 bit and mipmap + gld_UploadAndMip32BitTexture( gltexture->buffer_width, gltexture->buffer_height, buffer); +#else + { + if (gl_paletted_texture) { + gld_SetTexturePalette(GL_TEXTURE_2D); + glTexImage2D( GL_TEXTURE_2D, 0, GL_COLOR_INDEX8_EXT, + gltexture->buffer_width, gltexture->buffer_height, + 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, buffer); + } else { + glTexImage2D( GL_TEXTURE_2D, 0, gl_tex_format, + gltexture->buffer_width, gltexture->buffer_height, + 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer); + } + } +#endif + } + Z_Free(buffer); + W_UnlockLumpNum(gltexture->index); +} + +static void gld_CleanTextures(void) +{ + int i,j; + + if (!gld_GLTextures) + return; + for (i=0; iglTexID[j]; + + glDeleteTextures(1,&handle); + } + + Z_Free(texture); + + gld_GLTextures[i] = NULL; + } + } + + Z_Free( gld_GLTextures ); + gld_GLTextures = NULL; + numtextures = 0; + +} + +static void gld_CleanPatchTextures(void) +{ + int i,j; + + if (!gld_GLPatchTextures) + return; + for (i=0; iglTexID[j])); + Z_Free(gld_GLPatchTextures[i]); + gld_GLPatchTextures[i] = NULL; + } + } + Z_Free( gld_GLPatchTextures ); + gld_GLPatchTextures = NULL; +} + +void DrawEmptyTriangleToForceTextureLoad() { // JDC + // The iPhone OpenGL driver (and many others), don't + // do all the texture loading work until it is actually + // used to draw something. If you want to avoid all + // hitches during gameplay, call this after binding + // during the precache. + glBegin( GL_TRIANGLES ); + glVertex2f( 0, 0 ); + glVertex2f( 0, 0 ); + glVertex2f( 0, 0 ); + glEnd(); +} + +void gld_Precache(void) +{ + int i, j, k; + + byte *flatHitlist = alloca( numflats ); + byte *wallHitlist = alloca( numtextures ); + byte *spriteHitlist = alloca( numsprites ); + + // JDC: significant rework here to also take over the + // work of gld_CleanMemory() and avoid freeing and reloading + // things that are still needed, making respawning many times + // faster. + + // this updates the spinning wheel icon as we load textures + void iphonePacifierUpdate(); + + // JDC if (demoplayback) + // JDC return; + + //----------------------------------------- + // find everything we will need before loading anything + //----------------------------------------- + + // find flats + memset(flatHitlist, 0, numflats); + for (i = numsectors; --i >= 0; ) { + // JDC: todo: get animated flats + assert( (unsigned)sectors[i].floorpic < numflats ); + assert( (unsigned)sectors[i].ceilingpic < numflats ); + flatHitlist[sectors[i].floorpic] = 1; + flatHitlist[sectors[i].ceilingpic] = 1; + } + + // find walls + memset(wallHitlist, 0, numtextures); + for (i = numsides; --i >= 0;) { + assert( (unsigned)sides[i].bottomtexture < numtextures ); + assert( (unsigned)sides[i].toptexture < numtextures ); + assert( (unsigned)sides[i].midtexture < numtextures ); + wallHitlist[sides[i].bottomtexture] = 1; + wallHitlist[sides[i].toptexture] = 1; + wallHitlist[sides[i].midtexture] = 1; + } + + // Sky texture is always present. + // Note that F_SKY1 is the name used to + // indicate a sky floor/ceiling as a flat, + // while the sky texture is stored like + // a wall texture, with an episode dependend + // name. + wallHitlist[skytexture] = 1; + + // find sprites + memset(spriteHitlist, 0, numsprites); + for ( i = 0 ; i < numsectors ; i++ ) { + for ( mobj_t *thing = sectors[i].thinglist; thing; thing = thing->snext) { + assert( (unsigned)thing->sprite < numsprites ); + spriteHitlist[thing->sprite] = 1; + } + } + + //----------------------------------------- + // free textures not used + //----------------------------------------- + if ( gld_GLPatchTextures ) { + for (i = numflats; --i >= 0; ) { + if (!flatHitlist[i]) { + int patchNum = firstflat + i; + if ( gld_GLPatchTextures[patchNum] ) { + for (j=0; j<(CR_LIMIT+MAXPLAYERS); j++) + glDeleteTextures(1,(GLuint *)&(gld_GLPatchTextures[patchNum]->glTexID[j])); + Z_Free(gld_GLPatchTextures[patchNum]); + gld_GLPatchTextures[patchNum] = NULL; + } + } + } + } + if ( gld_GLTextures ) { + for (i = numtextures; --i >= 0; ) { + if ( !wallHitlist[i] ) { + if (gld_GLTextures[i]) { + for (j=0; j<(CR_LIMIT+MAXPLAYERS); j++) + glDeleteTextures(1,(GLuint *)&(gld_GLTextures[i]->glTexID[j])); + Z_Free(gld_GLTextures[i]); + gld_GLTextures[i] = NULL; + } + } + } + } + + if ( gld_GLPatchTextures ) { + for (i=numsprites; --i >= 0;) { + if ( !spriteHitlist[i] ) { + for (j = 0 ; j < sprites[i].numframes ; j++ ) { + short *sflump = sprites[i].spriteframes[j].lump; + for ( k = 0 ; k < 7 ; k++ ) { + int patchNum = firstspritelump + sflump[k]; + if ( gld_GLPatchTextures[patchNum] ) { + for (j=0; j<(CR_LIMIT+MAXPLAYERS); j++) + glDeleteTextures(1,(GLuint *)&(gld_GLPatchTextures[patchNum]->glTexID[j])); + Z_Free(gld_GLPatchTextures[patchNum]); + gld_GLPatchTextures[patchNum] = NULL; + } + } + } + } + } + } + + //----------------------------------------- + // now load everything that isn't already in memory + //----------------------------------------- + + // flats + for (i = numflats; --i >= 0; ) + if (flatHitlist[i]) { + gld_BindFlat(gld_RegisterFlat(i,true)); + DrawEmptyTriangleToForceTextureLoad(); // JDC + iphonePacifierUpdate(); + } + + // wall textures + for (i = numtextures; --i >= 0; ) + if (wallHitlist[i]) { + gld_BindTexture(gld_RegisterTexture(i,true,false)); + DrawEmptyTriangleToForceTextureLoad(); // JDC + iphonePacifierUpdate(); + } + + // sprites + for (i=numsprites; --i >= 0;) + if (spriteHitlist[i]) + { + j = sprites[i].numframes; + while (--j >= 0) + { + short *sflump = sprites[i].spriteframes[j].lump; + k = 7; + do { + // JDC: changed from CR_DEFAULT to CR_LIMIT to match game behavior + gld_BindPatch(gld_RegisterPatch(firstspritelump + sflump[k],CR_LIMIT),CR_LIMIT); + DrawEmptyTriangleToForceTextureLoad(); + iphonePacifierUpdate(); + } while (--k >= 0); + } + } +} + +void gld_CleanMemory(void) +{ + gld_CleanTextures(); + gld_CleanPatchTextures(); + +} diff --git a/common/prboom/hu_lib.c b/common/prboom/hu_lib.c new file mode 100755 index 0000000..817fb5e --- /dev/null +++ b/common/prboom/hu_lib.c @@ -0,0 +1,762 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: heads-up text and input code + * + *----------------------------------------------------------------------------- + */ + +#include "doomdef.h" +#include "doomstat.h" +#include "v_video.h" +#include "m_swap.h" +#include "hu_lib.h" +#include "hu_stuff.h" +#include "r_main.h" +#include "r_draw.h" + +// boolean : whether the screen is always erased +#define noterased viewwindowx + +extern int key_backspace; // phares +extern int key_enter; // phares + + +//////////////////////////////////////////////////////// +// +// Basic text line widget +// +//////////////////////////////////////////////////////// + +// +// HUlib_clearTextLine() +// +// Blank the internal text line in a hu_textline_t widget +// +// Passed a hu_textline_t, returns nothing +// +void HUlib_clearTextLine(hu_textline_t* t) +{ + t->linelen = // killough 1/23 98: support multiple lines + t->len = 0; + t->l[0] = 0; + t->needsupdate = true; +} + +// +// HUlib_initTextLine() +// +// Initialize a hu_textline_t widget. Set the position, font, start char +// of the font, and color range to be used. +// +// Passed a hu_textline_t, and the values used to initialize +// Returns nothing +// +void HUlib_initTextLine(hu_textline_t* t, int x, int y, + const patchnum_t* f, int sc, int cm ) + //jff 2/16/98 add color range parameter +{ + t->x = x; + t->y = y; + t->f = f; + t->sc = sc; + t->cm = cm; + HUlib_clearTextLine(t); +} + +// +// HUlib_addCharToTextLine() +// +// Adds a character at the end of the text line in a hu_textline_t widget +// +// Passed the hu_textline_t and the char to add +// Returns false if already at length limit, true if the character added +// +boolean HUlib_addCharToTextLine +( hu_textline_t* t, + char ch ) +{ + // killough 1/23/98 -- support multiple lines + if (t->linelen == HU_MAXLINELENGTH) + return false; + else + { + t->linelen++; + if (ch == '\n') + t->linelen=0; + + t->l[t->len++] = ch; + t->l[t->len] = 0; + t->needsupdate = 4; + return true; + } + +} + +// +// HUlib_delCharFromTextLine() +// +// Deletes a character at the end of the text line in a hu_textline_t widget +// +// Passed the hu_textline_t +// Returns false if already empty, true if the character deleted +// +static boolean HUlib_delCharFromTextLine(hu_textline_t* t) +{ + if (!t->len) return false; + else + { + t->l[--t->len] = 0; + t->needsupdate = 4; + return true; + } +} + +// +// HUlib_drawTextLine() +// +// Draws a hu_textline_t widget +// +// Passed the hu_textline_t and flag whether to draw a cursor +// Returns nothing +// +void HUlib_drawTextLine +( hu_textline_t* l, + boolean drawcursor ) +{ + + int i; + int w; + int x; + unsigned char c; + int oc = l->cm; //jff 2/17/98 remember default color + int y = l->y; // killough 1/18/98 -- support multiple lines + + // draw the new stuff + x = l->x; + for (i=0;ilen;i++) + { + c = toupper(l->l[i]); //jff insure were not getting a cheap toupper conv. + + if (c=='\n') // killough 1/18/98 -- support multiple lines + x=0,y+=8; + else if (c=='\t') // killough 1/23/98 -- support tab stops + x=x-x%80+80; + else if (c=='\x1b') //jff 2/17/98 escape code for color change + { //jff 3/26/98 changed to actual escape char + if (++ilen) + if (l->l[i]>='0' && l->l[i]<='9') + l->cm = l->l[i]-'0'; + } + else if (c != ' ' && c >= l->sc && c <= 127) + { + w = l->f[c - l->sc].width; + if (x+w > BASE_WIDTH) + break; + // killough 1/18/98 -- support multiple lines: + // CPhipps - patch drawing updated + V_DrawNumPatch(x, y, FG, l->f[c - l->sc].lumpnum, l->cm, VPT_TRANS | VPT_STRETCH); + x += w; + } + else + { + x += 4; + if (x >= BASE_WIDTH) + break; + } + } + l->cm = oc; //jff 2/17/98 restore original color + + // draw the cursor if requested + if (drawcursor && x + l->f['_' - l->sc].width <= BASE_WIDTH) + { + // killough 1/18/98 -- support multiple lines + // CPhipps - patch drawing updated + V_DrawNumPatch(x, y, FG, l->f['_' - l->sc].lumpnum, CR_DEFAULT, VPT_NONE | VPT_STRETCH); + } +} + +// +// HUlib_eraseTextLine() +// +// Erases a hu_textline_t widget when screen border is behind text +// Sorta called by HU_Erase and just better darn get things straight +// +// Passed the hu_textline_t +// Returns nothing +// +void HUlib_eraseTextLine(hu_textline_t* l) +{ + int lh; + int y; + + // Only erases when NOT in automap and the screen is reduced, + // and the text must either need updating or refreshing + // (because of a recent change back from the automap) + + if (!(automapmode & am_active) && viewwindowx && l->needsupdate) + { + lh = l->f[0].height + 1; + for (y=l->y; yy+lh ; y++) + { + if (y < viewwindowy || y >= viewwindowy + viewheight) + R_VideoErase(0, y, SCREENWIDTH); // erase entire line + else + { + // erase left border + R_VideoErase(0, y, viewwindowx); + // erase right border + R_VideoErase(viewwindowx + viewwidth, y, viewwindowx); + } + } + } + + if (l->needsupdate) l->needsupdate--; +} + +//////////////////////////////////////////////////////// +// +// Player message widget (up to 4 lines of text) +// +//////////////////////////////////////////////////////// + +// +// HUlib_initSText() +// +// Initialize a hu_stext_t widget. Set the position, number of lines, font, +// start char of the font, and color range to be used, and whether enabled. +// +// Passed a hu_stext_t, and the values used to initialize +// Returns nothing +// +void HUlib_initSText +( hu_stext_t* s, + int x, + int y, + int h, + const patchnum_t* font, + int startchar, + int cm, //jff 2/16/98 add color range parameter + boolean* on ) +{ + + int i; + + s->h = h; + s->on = on; + s->laston = true; + s->cl = 0; + for (i=0;il[i], + x, + y - i*(font[0].height+1), + font, + startchar, + cm + ); +} + +// +// HUlib_addLineToSText() +// +// Adds a blank line to a hu_stext_t widget +// +// Passed a hu_stext_t +// Returns nothing +// +static void HUlib_addLineToSText(hu_stext_t* s) +{ + + int i; + + // add a clear line + if (++s->cl == s->h) + s->cl = 0; + HUlib_clearTextLine(&s->l[s->cl]); + + // everything needs updating + for (i=0 ; ih ; i++) + s->l[i].needsupdate = 4; + +} + +// +// HUlib_addMessageToSText() +// +// Adds a message line with prefix to a hu_stext_t widget +// +// Passed a hu_stext_t, the prefix string, and a message string +// Returns nothing +// +void HUlib_addMessageToSText(hu_stext_t* s, const char* prefix, const char* msg) +{ + HUlib_addLineToSText(s); + if (prefix) + while (*prefix) + HUlib_addCharToTextLine(&s->l[s->cl], *(prefix++)); + + while (*msg) + HUlib_addCharToTextLine(&s->l[s->cl], *(msg++)); +} + +// +// HUlib_drawSText() +// +// Displays a hu_stext_t widget +// +// Passed a hu_stext_t +// Returns nothing +// +void HUlib_drawSText(hu_stext_t* s) +{ + int i, idx; + hu_textline_t *l; + + if (!*s->on) + return; // if not on, don't draw + + // draw everything + for (i=0 ; ih ; i++) + { + idx = s->cl - i; + if (idx < 0) + idx += s->h; // handle queue of lines + + l = &s->l[idx]; + + // need a decision made here on whether to skip the draw + HUlib_drawTextLine(l, false); // no cursor, please + } +} + +// +// HUlib_eraseSText() +// +// Erases a hu_stext_t widget, when the screen is not fullsize +// +// Passed a hu_stext_t +// Returns nothing +// +void HUlib_eraseSText(hu_stext_t* s) +{ + int i; + + for (i=0 ; ih ; i++) + { + if (s->laston && !*s->on) + s->l[i].needsupdate = 4; + HUlib_eraseTextLine(&s->l[i]); + } + s->laston = *s->on; +} + +//////////////////////////////////////////////////////// +// +// Scrolling message review widget +// +// jff added 2/26/98 +// +//////////////////////////////////////////////////////// + +// +// HUlib_initMText() +// +// Initialize a hu_mtext_t widget. Set the position, width, number of lines, +// font, start char of the font, color range, background font, and whether +// enabled. +// +// Passed a hu_mtext_t, and the values used to initialize +// Returns nothing +// +void HUlib_initMText(hu_mtext_t *m, int x, int y, int w, int h, + const patchnum_t* font, int startchar, int cm, + const patchnum_t* bgfont, boolean *on) +{ + int i; + + m->nl = 0; + m->nr = 0; + m->cl = -1; //jff 4/28/98 prepare for pre-increment + m->x = x; + m->y = y; + m->w = w; + m->h = h; + m->bg = bgfont; + m->on = on; + for (i=0;il[i], + x, + y + (hud_list_bgon? i+1 : i)*HU_REFRESHSPACING, + font, + startchar, + cm + ); + } +} + +// +// HUlib_addLineToMText() +// +// Adds a blank line to a hu_mtext_t widget +// +// Passed a hu_mtext_t +// Returns nothing +// +static void HUlib_addLineToMText(hu_mtext_t* m) +{ + // add a clear line + if (++m->cl == hud_msg_lines) + m->cl = 0; + HUlib_clearTextLine(&m->l[m->cl]); + + if (m->nlnl++; + + // needs updating + m->l[m->cl].needsupdate = 4; +} + +// +// HUlib_addMessageToMText() +// +// Adds a message line with prefix to a hu_mtext_t widget +// +// Passed a hu_mtext_t, the prefix string, and a message string +// Returns nothing +// +void HUlib_addMessageToMText(hu_mtext_t* m, const char* prefix, const char* msg) +{ + HUlib_addLineToMText(m); + if (prefix) + while (*prefix) + HUlib_addCharToTextLine(&m->l[m->cl], *(prefix++)); + + while (*msg) + HUlib_addCharToTextLine(&m->l[m->cl], *(msg++)); +} + +// +// HUlib_drawMBg() +// +// Draws a background box which the message display review widget can +// display over +// +// Passed position, width, height, and the background patches +// Returns nothing +// +void HUlib_drawMBg +( int x, + int y, + int w, + int h, + const patchnum_t* bgp +) +{ + int xs = bgp[0].width; + int ys = bgp[0].height; + int i,j; + + // CPhipps - patch drawing updated + // top rows + V_DrawNumPatch(x, y, FG, bgp[0].lumpnum, CR_DEFAULT, VPT_STRETCH); // ul + for (j=x+xs;jon) + return; // if not on, don't draw + + // draw everything + if (hud_list_bgon) + HUlib_drawMBg(m->x,m->y,m->w,m->h,m->bg); + y = m->y + HU_REFRESHSPACING; + for (i=0 ; inl ; i++) + { + idx = m->cl - i; + if (idx < 0) + idx += m->nl; // handle queue of lines + + l = &m->l[idx]; + if (hud_list_bgon) + { + l->x = m->x + 4; + l->y = m->y + (i+1)*HU_REFRESHSPACING; + } + else + { + l->x = m->x; + l->y = m->y + i*HU_REFRESHSPACING; + } + + // need a decision made here on whether to skip the draw + HUlib_drawTextLine(l, false); // no cursor, please + } +} + +// +// HUlib_eraseMBg() +// +// Erases background behind hu_mtext_t widget, when the screen is not fullsize +// +// Passed a hu_mtext_t +// Returns nothing +// +static void HUlib_eraseMBg(hu_mtext_t* m) +{ + int lh; + int y; + + // Only erases when NOT in automap and the screen is reduced, + // and the text must either need updating or refreshing + // (because of a recent change back from the automap) + + if (!(automapmode & am_active) && viewwindowx) + { + lh = m->l[0].f[0].height + 1; + for (y=m->y; yy+lh*(hud_msg_lines+2) ; y++) + { + if (y < viewwindowy || y >= viewwindowy + viewheight) + R_VideoErase(0, y, SCREENWIDTH); // erase entire line + else + { + // erase left border + R_VideoErase(0, y, viewwindowx); + // erase right border + R_VideoErase(viewwindowx + viewwidth, y, viewwindowx); + + } + } + } +} + +// +// HUlib_eraseMText() +// +// Erases a hu_mtext_t widget, when the screen is not fullsize +// +// Passed a hu_mtext_t +// Returns nothing +// +void HUlib_eraseMText(hu_mtext_t* m) +{ + int i; + + if (hud_list_bgon) + HUlib_eraseMBg(m); + + for (i=0 ; i< m->nl ; i++) + { + m->l[i].needsupdate = 4; + HUlib_eraseTextLine(&m->l[i]); + } +} + +//////////////////////////////////////////////////////// +// +// Interactive text entry widget +// +//////////////////////////////////////////////////////// + +// +// HUlib_initIText() +// +// Initialize a hu_itext_t widget. Set the position, font, +// start char of the font, color range, and whether enabled. +// +// Passed a hu_itext_t, and the values used to initialize +// Returns nothing +// +void HUlib_initIText +( hu_itext_t* it, + int x, + int y, + const patchnum_t* font, + int startchar, + int cm, //jff 2/16/98 add color range parameter + boolean* on ) +{ + it->lm = 0; // default left margin is start of text + it->on = on; + it->laston = true; + HUlib_initTextLine(&it->l, x, y, font, startchar, cm); +} + +// The following deletion routines adhere to the left margin restriction + +// +// HUlib_delCharFromIText() +// +// Deletes a character at the end of the text line in a hu_itext_t widget +// +// Passed the hu_itext_t +// Returns nothing +// +static void HUlib_delCharFromIText(hu_itext_t* it) +{ + if (it->l.len != it->lm) + HUlib_delCharFromTextLine(&it->l); +} + +// +// HUlib_eraseLineFromIText() +// +// Deletes all characters from a hu_itext_t widget +// +// Passed the hu_itext_t +// Returns nothing +// +#ifndef IPHONE +static void HUlib_eraseLineFromIText(hu_itext_t* it) +{ + while (it->lm != it->l.len) + HUlib_delCharFromTextLine(&it->l); +} +#endif + +// +// HUlib_resetIText() +// +// Deletes all characters from a hu_itext_t widget +// Resets left margin as well +// +// Passed the hu_itext_t +// Returns nothing +// +void HUlib_resetIText(hu_itext_t* it) +{ + it->lm = 0; + HUlib_clearTextLine(&it->l); +} + +// +// HUlib_addPrefixToIText() +// +// Adds a prefix string passed to a hu_itext_t widget +// Sets left margin to length of string added +// +// Passed the hu_itext_t and the prefix string +// Returns nothing +// +void HUlib_addPrefixToIText +( hu_itext_t* it, + char* str ) +{ + while (*str) + HUlib_addCharToTextLine(&it->l, *(str++)); + it->lm = it->l.len; +} + +// +// HUlib_keyInIText() +// +// Wrapper function for handling general keyed input. +// +// Passed the hu_itext_t and the char input +// Returns true if it ate the key +// +boolean HUlib_keyInIText +( hu_itext_t* it, + unsigned char ch ) +{ + + if (ch >= ' ' && ch <= '_') + HUlib_addCharToTextLine(&it->l, (char) ch); + else if (ch == key_backspace) // phares + HUlib_delCharFromIText(it); + else if (ch != key_enter) // phares + return false; // did not eat key + + return true; // ate the key +} + +// +// HUlib_drawIText() +// +// Displays a hu_itext_t widget +// +// Passed the hu_itext_t +// Returns nothing +// +void HUlib_drawIText(hu_itext_t* it) +{ + hu_textline_t *l = &it->l; + + if (!*it->on) + return; + HUlib_drawTextLine(l, true); // draw the line w/ cursor +} + +// +// HUlib_eraseIText() +// +// Erases a hu_itext_t widget when the screen is not fullsize +// +// Passed the hu_itext_t +// Returns nothing +// +void HUlib_eraseIText(hu_itext_t* it) +{ + if (it->laston && !*it->on) + it->l.needsupdate = 4; + HUlib_eraseTextLine(&it->l); + it->laston = *it->on; +} diff --git a/common/prboom/hu_lib.h b/common/prboom/hu_lib.h new file mode 100755 index 0000000..db17572 --- /dev/null +++ b/common/prboom/hu_lib.h @@ -0,0 +1,247 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: none + * + *-----------------------------------------------------------------------------*/ + +#ifndef __HULIB__ +#define __HULIB__ + +// We are referring to patches. +#include "r_defs.h" +#include "v_video.h" //jff 2/16/52 include color range defs + + +/* background and foreground screen numbers + * different from other modules. */ +#define BG 1 +#define FG 0 + +/* font stuff + * #define HU_CHARERASE KEYD_BACKSPACE / not used / phares + */ + +#define HU_MAXLINES 4 +#define HU_MAXLINELENGTH 80 +#define HU_REFRESHSPACING 8 /*jff 2/26/98 space lines in text refresh widget*/ +/*jff 2/26/98 maximum number of messages allowed in refresh list */ +#define HU_MAXMESSAGES 16 + +/* + * Typedefs of widgets + */ + +/* Text Line widget + * (parent of Scrolling Text and Input Text widgets) */ +typedef struct +{ + // left-justified position of scrolling text window + int x; + int y; + + const patchnum_t* f; // font + int sc; // start character + //const char *cr; //jff 2/16/52 output color range + // Proff - Made this an int again. Needed for OpenGL + int cm; //jff 2/16/52 output color range + + // killough 1/23/98: Support multiple lines: + #define MAXLINES 25 + + int linelen; + char l[HU_MAXLINELENGTH*MAXLINES+1]; // line of text + int len; // current line length + + // whether this line needs to be udpated + int needsupdate; + +} hu_textline_t; + + + +// Scrolling Text window widget +// (child of Text Line widget) +typedef struct +{ + hu_textline_t l[HU_MAXLINES]; // text lines to draw + int h; // height in lines + int cl; // current line number + + // pointer to boolean stating whether to update window + boolean* on; + boolean laston; // last value of *->on. + +} hu_stext_t; + +//jff 2/26/98 new widget to display last hud_msg_lines of messages +// Message refresh window widget +typedef struct +{ + hu_textline_t l[HU_MAXMESSAGES]; // text lines to draw + int nl; // height in lines + int nr; // total height in rows + int cl; // current line number + + int x,y,w,h; // window position and size + const patchnum_t *bg; // patches for background + + // pointer to boolean stating whether to update window + boolean* on; + boolean laston; // last value of *->on. + +} hu_mtext_t; + + + +// Input Text Line widget +// (child of Text Line widget) +typedef struct +{ + hu_textline_t l; // text line to input on + + // left margin past which I am not to delete characters + int lm; + + // pointer to boolean stating whether to update window + boolean* on; + boolean laston; // last value of *->on; + +} hu_itext_t; + + +// +// Widget creation, access, and update routines +// + +// +// textline code +// + +// clear a line of text +void HUlib_clearTextLine(hu_textline_t *t); + +void HUlib_initTextLine +( + hu_textline_t *t, + int x, + int y, + const patchnum_t *f, + int sc, + int cm //jff 2/16/98 add color range parameter +); + +// returns success +boolean HUlib_addCharToTextLine(hu_textline_t *t, char ch); + +// draws tline +void HUlib_drawTextLine(hu_textline_t *l, boolean drawcursor); + +// erases text line +void HUlib_eraseTextLine(hu_textline_t *l); + + +// +// Scrolling Text window widget routines +// + +// initialize an stext widget +void HUlib_initSText +( hu_stext_t* s, + int x, + int y, + int h, + const patchnum_t* font, + int startchar, + int cm, //jff 2/16/98 add color range parameter + boolean* on ); + +// add a text message to an stext widget +void HUlib_addMessageToSText(hu_stext_t* s, const char* prefix, const char* msg); + +// draws stext +void HUlib_drawSText(hu_stext_t* s); + +// erases all stext lines +void HUlib_eraseSText(hu_stext_t* s); + +//jff 2/26/98 message refresh widget +// initialize refresh text widget +void HUlib_initMText(hu_mtext_t *m, int x, int y, int w, int h, const patchnum_t* font, + int startchar, int cm, const patchnum_t* bgfont, boolean *on); + +//jff 2/26/98 message refresh widget +// add a text message to refresh text widget +void HUlib_addMessageToMText(hu_mtext_t* m, const char* prefix, const char* msg); + +//jff 2/26/98 new routine to display a background on which +// the list of last hud_msg_lines are displayed +void HUlib_drawMBg +( int x, + int y, + int w, + int h, + const patchnum_t* bgp +); + +//jff 2/26/98 message refresh widget +// draws mtext +void HUlib_drawMText(hu_mtext_t* m); + +//jff 4/28/98 erases behind message list +void HUlib_eraseMText(hu_mtext_t* m); + +// Input Text Line widget routines +void HUlib_initIText +( hu_itext_t* it, + int x, + int y, + const patchnum_t* font, + int startchar, + int cm, //jff 2/16/98 add color range parameter + boolean* on ); + +// resets line and left margin +void HUlib_resetIText(hu_itext_t* it); + +// left of left-margin +void HUlib_addPrefixToIText +( hu_itext_t* it, + char* str ); + +// whether eaten +boolean HUlib_keyInIText +( hu_itext_t* it, + unsigned char ch ); + +void HUlib_drawIText(hu_itext_t* it); + +// erases all itext lines +void HUlib_eraseIText(hu_itext_t* it); + +#endif diff --git a/common/prboom/hu_stuff.c b/common/prboom/hu_stuff.c new file mode 100755 index 0000000..d59e7fa --- /dev/null +++ b/common/prboom/hu_stuff.c @@ -0,0 +1,1601 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: Heads-up displays + * + *----------------------------------------------------------------------------- + */ + +// killough 5/3/98: remove unnecessary headers + +#include "doomstat.h" +#include "hu_stuff.h" +#include "hu_lib.h" +#include "st_stuff.h" /* jff 2/16/98 need loc of status bar */ +#include "w_wad.h" +#include "s_sound.h" +#include "dstrings.h" +#include "sounds.h" +#include "d_deh.h" /* Ty 03/27/98 - externalization of mapnamesx arrays */ +#include "g_game.h" +#include "r_main.h" + +#include "doomiphone.h" + +#include + +// global heads up display controls + +int hud_active; //jff 2/17/98 controls heads-up display mode +int hud_displayed; //jff 2/23/98 turns heads-up display on/off +int hud_nosecrets; //jff 2/18/98 allows secrets line to be disabled in HUD +int hud_distributed; //jff 3/4/98 display HUD in different places on screen +int hud_graph_keys=1; //jff 3/7/98 display HUD keys as graphics + +// +// Locally used constants, shortcuts. +// +// Ty 03/28/98 - +// These four shortcuts modifed to reflect char ** of mapnamesx[] +#define HU_TITLE (*mapnames[(gameepisode-1)*9+gamemap-1]) +#define HU_TITLE2 (*mapnames2[gamemap-1]) +#define HU_TITLEP (*mapnamesp[gamemap-1]) +#define HU_TITLET (*mapnamest[gamemap-1]) +#define HU_TITLEHEIGHT 1 +#define HU_TITLEX 0 +//jff 2/16/98 change 167 to ST_Y-1 +// CPhipps - changed to ST_TY +// proff - changed to 200-ST_HEIGHT for stretching +#define HU_TITLEY ((200-ST_HEIGHT) - 1 - hu_font[0].height) + +//jff 2/16/98 add coord text widget coordinates +// proff - changed to SCREENWIDTH to 320 for stretching +#define HU_COORDX (320 - 13*hu_font2['A'-HU_FONTSTART].width) +//jff 3/3/98 split coord widget into three lines in upper right of screen +#define HU_COORDX_Y (1 + 0*hu_font['A'-HU_FONTSTART].height) +#define HU_COORDY_Y (2 + 1*hu_font['A'-HU_FONTSTART].height) +#define HU_COORDZ_Y (3 + 2*hu_font['A'-HU_FONTSTART].height) + +//jff 2/16/98 add ammo, health, armor widgets, 2/22/98 less gap +#define HU_GAPY 8 +#define HU_HUDHEIGHT (6*HU_GAPY) +#define HU_HUDX 2 +#define HU_HUDY (200-HU_HUDHEIGHT-1) +#define HU_MONSECX (HU_HUDX) +#define HU_MONSECY (HU_HUDY+0*HU_GAPY) +#define HU_KEYSX (HU_HUDX) +//jff 3/7/98 add offset for graphic key widget +#define HU_KEYSGX (HU_HUDX+4*hu_font2['A'-HU_FONTSTART].width) +#define HU_KEYSY (HU_HUDY+1*HU_GAPY) +#define HU_WEAPX (HU_HUDX) +#define HU_WEAPY (HU_HUDY+2*HU_GAPY) +#define HU_AMMOX (HU_HUDX) +#define HU_AMMOY (HU_HUDY+3*HU_GAPY) +#define HU_HEALTHX (HU_HUDX) +#define HU_HEALTHY (HU_HUDY+4*HU_GAPY) +#define HU_ARMORX (HU_HUDX) +#define HU_ARMORY (HU_HUDY+5*HU_GAPY) + +//jff 3/4/98 distributed HUD positions +#define HU_HUDX_LL 2 +#define HU_HUDY_LL (200-2*HU_GAPY-1) +// proff/nicolas 09/20/98: Changed for high-res +#define HU_HUDX_LR (320-120) +#define HU_HUDY_LR (200-2*HU_GAPY-1) +// proff/nicolas 09/20/98: Changed for high-res +#define HU_HUDX_UR (320-96) +#define HU_HUDY_UR 2 +#define HU_MONSECX_D (HU_HUDX_LL) +#define HU_MONSECY_D (HU_HUDY_LL+0*HU_GAPY) +#define HU_KEYSX_D (HU_HUDX_LL) +#define HU_KEYSGX_D (HU_HUDX_LL+4*hu_font2['A'-HU_FONTSTART].width) +#define HU_KEYSY_D (HU_HUDY_LL+1*HU_GAPY) +#define HU_WEAPX_D (HU_HUDX_LR) +#define HU_WEAPY_D (HU_HUDY_LR+0*HU_GAPY) +#define HU_AMMOX_D (HU_HUDX_LR) +#define HU_AMMOY_D (HU_HUDY_LR+1*HU_GAPY) +#define HU_HEALTHX_D (HU_HUDX_UR) +#define HU_HEALTHY_D (HU_HUDY_UR+0*HU_GAPY) +#define HU_ARMORX_D (HU_HUDX_UR) +#define HU_ARMORY_D (HU_HUDY_UR+1*HU_GAPY) + +//#define HU_INPUTTOGGLE 't' // not used // phares +#define HU_INPUTX HU_MSGX +#define HU_INPUTY (HU_MSGY + HU_MSGHEIGHT*(hu_font[0].height) +1) +#define HU_INPUTWIDTH 64 +#define HU_INPUTHEIGHT 1 + +#define key_alt KEYD_RALT +#define key_shift KEYD_RSHIFT + +const char* chat_macros[] = +// Ty 03/27/98 - *not* externalized +// CPhipps - const char* +{ + HUSTR_CHATMACRO0, + HUSTR_CHATMACRO1, + HUSTR_CHATMACRO2, + HUSTR_CHATMACRO3, + HUSTR_CHATMACRO4, + HUSTR_CHATMACRO5, + HUSTR_CHATMACRO6, + HUSTR_CHATMACRO7, + HUSTR_CHATMACRO8, + HUSTR_CHATMACRO9 +}; + +const char* player_names[] = +// Ty 03/27/98 - *not* externalized +// CPhipps - const char* +{ + HUSTR_PLRGREEN, + HUSTR_PLRINDIGO, + HUSTR_PLRBROWN, + HUSTR_PLRRED +}; + +//jff 3/17/98 translate player colmap to text color ranges +int plyrcoltran[MAXPLAYERS]={CR_GREEN,CR_GRAY,CR_BROWN,CR_RED}; + +char chat_char; // remove later. +static player_t* plr; + +// font sets +patchnum_t hu_font[HU_FONTSIZE]; +patchnum_t hu_font2[HU_FONTSIZE]; +patchnum_t hu_fontk[HU_FONTSIZE];//jff 3/7/98 added for graphic key indicators +patchnum_t hu_msgbg[9]; //jff 2/26/98 add patches for message background + +// widgets +static hu_textline_t w_title; +static hu_stext_t w_message; +static hu_itext_t w_chat; +static hu_itext_t w_inputbuffer[MAXPLAYERS]; +static hu_textline_t w_coordx; //jff 2/16/98 new coord widget for automap +static hu_textline_t w_coordy; //jff 3/3/98 split coord widgets automap +static hu_textline_t w_coordz; //jff 3/3/98 split coord widgets automap +static hu_textline_t w_ammo; //jff 2/16/98 new ammo widget for hud +static hu_textline_t w_health; //jff 2/16/98 new health widget for hud +static hu_textline_t w_armor; //jff 2/16/98 new armor widget for hud +static hu_textline_t w_weapon; //jff 2/16/98 new weapon widget for hud +static hu_textline_t w_keys; //jff 2/16/98 new keys widget for hud +static hu_textline_t w_gkeys; //jff 3/7/98 graphic keys widget for hud +static hu_textline_t w_monsec; //jff 2/16/98 new kill/secret widget for hud +static hu_mtext_t w_rtext; //jff 2/26/98 text message refresh widget + +static boolean always_off = false; +static char chat_dest[MAXPLAYERS]; +boolean chat_on; +static boolean message_on; +static boolean message_list; //2/26/98 enable showing list of messages +boolean message_dontfuckwithme; +static boolean message_nottobefuckedwith; +static int message_counter; +extern int showMessages; +extern boolean automapactive; +static boolean headsupactive = false; + +//jff 2/16/98 hud supported automap colors added +int hudcolor_titl; // color range of automap level title +int hudcolor_xyco; // color range of new coords on automap +//jff 2/16/98 hud text colors, controls added +int hudcolor_mesg; // color range of scrolling messages +int hudcolor_chat; // color range of chat lines +int hud_msg_lines; // number of message lines in window +//jff 2/26/98 hud text colors, controls added +int hudcolor_list; // list of messages color +int hud_list_bgon; // enable for solid window background for message list + +//jff 2/16/98 initialization strings for ammo, health, armor widgets +static char hud_coordstrx[32]; +static char hud_coordstry[32]; +static char hud_coordstrz[32]; +static char hud_ammostr[80]; +static char hud_healthstr[80]; +static char hud_armorstr[80]; +static char hud_weapstr[80]; +static char hud_keysstr[80]; +static char hud_gkeysstr[80]; //jff 3/7/98 add support for graphic key display +static char hud_monsecstr[80]; + +// +// Builtin map names. +// The actual names can be found in DStrings.h. +// +// Ty 03/27/98 - externalized map name arrays - now in d_deh.c +// and converted to arrays of pointers to char * +// See modified HUTITLEx macros +extern char **mapnames[]; +extern char **mapnames2[]; +extern char **mapnamesp[]; +extern char **mapnamest[]; + +extern int map_point_coordinates; + +// key tables +// jff 5/10/98 french support removed, +// as it was not being used and couldn't be easily tested +// +const char* shiftxform; + +const char english_shiftxform[] = +{ + 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, + ' ', '!', '"', '#', '$', '%', '&', + '"', // shift-' + '(', ')', '*', '+', + '<', // shift-, + '_', // shift-- + '>', // shift-. + '?', // shift-/ + ')', // shift-0 + '!', // shift-1 + '@', // shift-2 + '#', // shift-3 + '$', // shift-4 + '%', // shift-5 + '^', // shift-6 + '&', // shift-7 + '*', // shift-8 + '(', // shift-9 + ':', + ':', // shift-; + '<', + '+', // shift-= + '>', '?', '@', + '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', + '[', // shift-[ + '!', // shift-backslash - OH MY GOD DOES WATCOM SUCK + ']', // shift-] + '"', '_', + '\'', // shift-` + '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', + '{', '|', '}', '~', 127 +}; + +// +// HU_Init() +// +// Initialize the heads-up display, text that overwrites the primary display +// +// Passed nothing, returns nothing +// +void HU_Init(void) +{ + + int i; + int j; + char buffer[9]; + + shiftxform = english_shiftxform; + + // load the heads-up font + j = HU_FONTSTART; + for (i=0;i122) + { + sprintf(buffer, "STBR%.3d",j); + R_SetPatchNum(&hu_font2[i], buffer); + R_SetPatchNum(&hu_font[i], buffer); + } + else + hu_font[i] = hu_font[0]; //jff 2/16/98 account for gap + } + + // CPhipps - load patches for message background + for (i=0; i<9; i++) { + sprintf(buffer, "BOX%c%c", "UCL"[i/3], "LCR"[i%3]); + R_SetPatchNum(&hu_msgbg[i], buffer); + } + + // CPhipps - load patches for keys and double keys + for (i=0; i<6; i++) { + sprintf(buffer, "STKEYS%d", i); + R_SetPatchNum(&hu_fontk[i], buffer); + } +} + +// +// HU_Stop() +// +// Make the heads-up displays inactive +// +// Passed nothing, returns nothing +// +static void HU_Stop(void) +{ + headsupactive = false; +} + +// +// HU_Start(void) +// +// Create and initialize the heads-up widgets, software machines to +// maintain, update, and display information over the primary display +// +// This routine must be called after any change to the heads up configuration +// in order for the changes to take effect in the actual displays +// +// Passed nothing, returns nothing +// +void HU_Start(void) +{ + + int i; + const char* s; /* cph - const */ + + if (headsupactive) // stop before starting + HU_Stop(); + + plr = &players[displayplayer]; // killough 3/7/98 + message_on = false; + message_dontfuckwithme = false; + message_nottobefuckedwith = false; + chat_on = false; + + // create the message widget + // messages to player in upper-left of screen + HUlib_initSText + ( + &w_message, + HU_MSGX, + HU_MSGY, + HU_MSGHEIGHT, + hu_font, + HU_FONTSTART, + hudcolor_mesg, + &message_on + ); + + //jff 2/16/98 added some HUD widgets + // create the map title widget - map title display in lower left of automap + HUlib_initTextLine + ( + &w_title, + HU_TITLEX, + HU_TITLEY, + hu_font, + HU_FONTSTART, + hudcolor_titl + ); + + // create the hud health widget + // bargraph and number for amount of health, + // lower left or upper right of screen + HUlib_initTextLine + ( + &w_health, + hud_distributed? HU_HEALTHX_D : HU_HEALTHX, //3/4/98 distribute + hud_distributed? HU_HEALTHY_D : HU_HEALTHY, + hu_font2, + HU_FONTSTART, + CR_GREEN + ); + + // create the hud armor widget + // bargraph and number for amount of armor, + // lower left or upper right of screen + HUlib_initTextLine + ( + &w_armor, + hud_distributed? HU_ARMORX_D : HU_ARMORX, //3/4/98 distribute + hud_distributed? HU_ARMORY_D : HU_ARMORY, + hu_font2, + HU_FONTSTART, + CR_GREEN + ); + + // create the hud ammo widget + // bargraph and number for amount of ammo for current weapon, + // lower left or lower right of screen + HUlib_initTextLine + ( + &w_ammo, + hud_distributed? HU_AMMOX_D : HU_AMMOX, //3/4/98 distribute + hud_distributed? HU_AMMOY_D : HU_AMMOY, + hu_font2, + HU_FONTSTART, + CR_GOLD + ); + + // create the hud weapons widget + // list of numbers of weapons possessed + // lower left or lower right of screen + HUlib_initTextLine + ( + &w_weapon, + hud_distributed? HU_WEAPX_D : HU_WEAPX, //3/4/98 distribute + hud_distributed? HU_WEAPY_D : HU_WEAPY, + hu_font2, + HU_FONTSTART, + CR_GRAY + ); + + // create the hud keys widget + // display of key letters possessed + // lower left of screen + HUlib_initTextLine + ( + &w_keys, + hud_distributed? HU_KEYSX_D : HU_KEYSX, //3/4/98 distribute + hud_distributed? HU_KEYSY_D : HU_KEYSY, + hu_font2, + HU_FONTSTART, + CR_GRAY + ); + + // create the hud graphic keys widget + // display of key graphics possessed + // lower left of screen + HUlib_initTextLine + ( + &w_gkeys, + hud_distributed? HU_KEYSGX_D : HU_KEYSGX, //3/4/98 distribute + hud_distributed? HU_KEYSY_D : HU_KEYSY, + hu_fontk, + HU_FONTSTART, + CR_RED + ); + + // create the hud monster/secret widget + // totals and current values for kills, items, secrets + // lower left of screen + HUlib_initTextLine + ( + &w_monsec, + hud_distributed? HU_MONSECX_D : HU_MONSECX, //3/4/98 distribute + hud_distributed? HU_MONSECY_D : HU_MONSECY, + hu_font2, + HU_FONTSTART, + CR_GRAY + ); + + // create the hud text refresh widget + // scrolling display of last hud_msg_lines messages received + if (hud_msg_lines>HU_MAXMESSAGES) + hud_msg_lines=HU_MAXMESSAGES; + //jff 4/21/98 if setup has disabled message list while active, turn it off + message_list = hud_msg_lines > 1; //jff 8/8/98 initialize both ways + //jff 2/26/98 add the text refresh widget initialization + HUlib_initMText + ( + &w_rtext, + 0, + 0, + 320, +// SCREENWIDTH, + (hud_msg_lines+2)*HU_REFRESHSPACING, + hu_font, + HU_FONTSTART, + hudcolor_list, + hu_msgbg, + &message_list + ); + + // initialize the automap's level title widget + if (gamestate == GS_LEVEL) /* cph - stop SEGV here when not in level */ + switch (gamemode) + { + case shareware: + case registered: + case retail: + s = HU_TITLE; + break; + + case commercial: + default: // Ty 08/27/98 - modified to check mission for TNT/Plutonia + s = (gamemission==pack_tnt) ? HU_TITLET : + (gamemission==pack_plut) ? HU_TITLEP : HU_TITLE2; + break; + } else s = ""; + while (*s) + HUlib_addCharToTextLine(&w_title, *(s++)); + + // create the automaps coordinate widget + // jff 3/3/98 split coord widget into three lines: x,y,z + // jff 2/16/98 added + HUlib_initTextLine + ( + &w_coordx, + HU_COORDX, + HU_COORDX_Y, + hu_font, + HU_FONTSTART, + hudcolor_xyco + ); + HUlib_initTextLine + ( + &w_coordy, + HU_COORDX, + HU_COORDY_Y, + hu_font, + HU_FONTSTART, + hudcolor_xyco + ); + HUlib_initTextLine + ( + &w_coordz, + HU_COORDX, + HU_COORDZ_Y, + hu_font, + HU_FONTSTART, + hudcolor_xyco + ); + + // initialize the automaps coordinate widget + //jff 3/3/98 split coordstr widget into 3 parts + if (map_point_coordinates) + { + sprintf(hud_coordstrx,"X: %-5d",0); //jff 2/22/98 added z + s = hud_coordstrx; + while (*s) + HUlib_addCharToTextLine(&w_coordx, *(s++)); + sprintf(hud_coordstry,"Y: %-5d",0); //jff 3/3/98 split x,y,z + s = hud_coordstry; + while (*s) + HUlib_addCharToTextLine(&w_coordy, *(s++)); + sprintf(hud_coordstrz,"Z: %-5d",0); //jff 3/3/98 split x,y,z + s = hud_coordstrz; + while (*s) + HUlib_addCharToTextLine(&w_coordz, *(s++)); + } + + //jff 2/16/98 initialize ammo widget + strcpy(hud_ammostr,"AMM "); + s = hud_ammostr; + while (*s) + HUlib_addCharToTextLine(&w_ammo, *(s++)); + + //jff 2/16/98 initialize health widget + strcpy(hud_healthstr,"HEL "); + s = hud_healthstr; + while (*s) + HUlib_addCharToTextLine(&w_health, *(s++)); + + //jff 2/16/98 initialize armor widget + strcpy(hud_armorstr,"ARM "); + s = hud_armorstr; + while (*s) + HUlib_addCharToTextLine(&w_armor, *(s++)); + + //jff 2/17/98 initialize weapons widget + strcpy(hud_weapstr,"WEA "); + s = hud_weapstr; + while (*s) + HUlib_addCharToTextLine(&w_weapon, *(s++)); + + //jff 2/17/98 initialize keys widget + if (!deathmatch) //jff 3/17/98 show frags in deathmatch mode + strcpy(hud_keysstr,"KEY "); + else + strcpy(hud_keysstr,"FRG "); + s = hud_keysstr; + while (*s) + HUlib_addCharToTextLine(&w_keys, *(s++)); + + //jff 2/17/98 initialize graphic keys widget + strcpy(hud_gkeysstr," "); + s = hud_gkeysstr; + while (*s) + HUlib_addCharToTextLine(&w_gkeys, *(s++)); + + //jff 2/17/98 initialize kills/items/secret widget + strcpy(hud_monsecstr,"STS "); + s = hud_monsecstr; + while (*s) + HUlib_addCharToTextLine(&w_monsec, *(s++)); + + // create the chat widget + HUlib_initIText + ( + &w_chat, + HU_INPUTX, + HU_INPUTY, + hu_font, + HU_FONTSTART, + hudcolor_chat, + &chat_on + ); + + // create the inputbuffer widgets, one per player + for (i=0 ; imo->x)>>FRACBITS); + HUlib_clearTextLine(&w_coordx); + s = hud_coordstrx; + while (*s) + HUlib_addCharToTextLine(&w_coordx, *(s++)); + HUlib_drawTextLine(&w_coordx, false); + + //jff 3/3/98 split coord display into x,y,z lines + // y-coord + sprintf(hud_coordstry,"Y: %-5d", (player->mo->y)>>FRACBITS); + HUlib_clearTextLine(&w_coordy); + s = hud_coordstry; + while (*s) + HUlib_addCharToTextLine(&w_coordy, *(s++)); + HUlib_drawTextLine(&w_coordy, false); + + //jff 3/3/98 split coord display into x,y,z lines + //jff 2/22/98 added z + // z-coord + sprintf(hud_coordstrz,"Z: %-5d", (player->mo->z)>>FRACBITS); + HUlib_clearTextLine(&w_coordz); + s = hud_coordstrz; + while (*s) + HUlib_addCharToTextLine(&w_coordz, *(s++)); + HUlib_drawTextLine(&w_coordz, false); + } + } + + // draw the weapon/health/ammo/armor/kills/keys displays if optioned + //jff 2/17/98 allow new hud stuff to be turned off + // killough 2/21/98: really allow new hud stuff to be turned off COMPLETELY + if + ( + hud_active>0 && // hud optioned on + hud_displayed && // hud on from fullscreen key + viewheight==SCREENHEIGHT && // fullscreen mode is active + !(automapmode & am_active) // automap is not active + ) + { + doit = !(gametic&1); //jff 3/4/98 speed update up for slow systems + if (doit) //jff 8/7/98 update every time, avoid lag in update + { + HU_MoveHud(); // insure HUD display coords are correct + + // do the hud ammo display + // clear the widgets internal line + HUlib_clearTextLine(&w_ammo); + strcpy(hud_ammostr,"AMM "); + if (weaponinfo[player->readyweapon].ammo == am_noammo) + { // special case for weapon with no ammo selected - blank bargraph + N/A + strcat(hud_ammostr,"\x7f\x7f\x7f\x7f\x7f\x7f\x7f N/A"); + w_ammo.cm = CR_GRAY; + } + else + { + int ammo = player->ammo[weaponinfo[player->readyweapon].ammo]; + int fullammo = player->maxammo[weaponinfo[player->readyweapon].ammo]; + int ammopct = (100*ammo)/fullammo; + int ammobars = ammopct/4; + + // build the numeric amount init string + sprintf(ammostr,"%d/%d",ammo,fullammo); + // build the bargraph string + // full bargraph chars + for (i=4;i<4+ammobars/4;) + hud_ammostr[i++] = 123; + // plus one last character with 0,1,2,3 bars + switch(ammobars%4) + { + case 0: + break; + case 1: + hud_ammostr[i++] = 126; + break; + case 2: + hud_ammostr[i++] = 125; + break; + case 3: + hud_ammostr[i++] = 124; + break; + } + // pad string with blank bar characters + while(i<4+7) + hud_ammostr[i++] = 127; + hud_ammostr[i] = '\0'; + strcat(hud_ammostr,ammostr); + + // set the display color from the percentage of total ammo held + if (ammopcthealth; + int healthbars = health>100? 25 : health/4; + + // clear the widgets internal line + HUlib_clearTextLine(&w_health); + + // build the numeric amount init string + sprintf(healthstr,"%3d",health); + // build the bargraph string + // full bargraph chars + for (i=4;i<4+healthbars/4;) + hud_healthstr[i++] = 123; + // plus one last character with 0,1,2,3 bars + switch(healthbars%4) + { + case 0: + break; + case 1: + hud_healthstr[i++] = 126; + break; + case 2: + hud_healthstr[i++] = 125; + break; + case 3: + hud_healthstr[i++] = 124; + break; + } + // pad string with blank bar characters + while(i<4+7) + hud_healthstr[i++] = 127; + hud_healthstr[i] = '\0'; + strcat(hud_healthstr,healthstr); + + // set the display color from the amount of health posessed + if (healtharmorpoints; + int armorbars = armor>100? 25 : armor/4; + + // clear the widgets internal line + HUlib_clearTextLine(&w_armor); + // build the numeric amount init string + sprintf(armorstr,"%3d",armor); + // build the bargraph string + // full bargraph chars + for (i=4;i<4+armorbars/4;) + hud_armorstr[i++] = 123; + // plus one last character with 0,1,2,3 bars + switch(armorbars%4) + { + case 0: + break; + case 1: + hud_armorstr[i++] = 126; + break; + case 2: + hud_armorstr[i++] = 125; + break; + case 3: + hud_armorstr[i++] = 124; + break; + } + // pad string with blank bar characters + while(i<4+7) + hud_armorstr[i++] = 127; + hud_armorstr[i] = '\0'; + strcat(hud_armorstr,armorstr); + + // set the display color from the amount of armor posessed + if (armor=wp_plasma && w!=wp_chainsaw) + ok=0; + break; + case retail: + case registered: + if (w>=wp_supershotgun) + ok=0; + break; + default: + case commercial: + break; + } + if (!ok) continue; + + ammo = player->ammo[weaponinfo[w].ammo]; + fullammo = player->maxammo[weaponinfo[w].ammo]; + ammopct=0; + + // skip weapons not currently posessed + if (!player->weaponowned[w]) + continue; + + ammopct = fullammo? (100*ammo)/fullammo : 100; + + // display each weapon number in a color related to the ammo for it + hud_weapstr[i++] = '\x1b'; //jff 3/26/98 use ESC not '\' for paths + if (weaponinfo[w].ammo==am_noammo) //jff 3/14/98 show berserk on HUD + hud_weapstr[i++] = player->powers[pw_strength]? '0'+CR_GREEN : '0'+CR_GRAY; + else if (ammopct1) + { + int k; + + hud_keysstr[4] = '\0'; //jff 3/7/98 make sure deleted keys go away + //jff add case for graphic key display + if (!deathmatch && hud_graph_keys) + { + i=0; + hud_gkeysstr[i] = '\0'; //jff 3/7/98 init graphic keys widget string + // build text string whose characters call out graphic keys from fontk + for (k=0;k<6;k++) + { + // skip keys not possessed + if (!player->cards[k]) + continue; + + hud_gkeysstr[i++] = '!'+k; // key number plus '!' is char for key + hud_gkeysstr[i++] = ' '; // spacing + hud_gkeysstr[i++] = ' '; + } + hud_gkeysstr[i]='\0'; + } + else // not possible in current code, unless deathmatching, + { + i=4; + hud_keysstr[i] = '\0'; //jff 3/7/98 make sure deleted keys go away + + // if deathmatch, build string showing top four frag counts + if (deathmatch) //jff 3/17/98 show frags, not keys, in deathmatch + { + int top1=-999,top2=-999,top3=-999,top4=-999; + int idx1=-1,idx2=-1,idx3=-1,idx4=-1; + int fragcount,m; + char numbuf[32]; + + // scan thru players + for (k=0;ktop1) + { + top4=top3; top3=top2; top2 = top1; top1=fragcount; + idx4=idx3; idx3=idx2; idx2 = idx1; idx1=k; + } + else if (fragcount>top2) + { + top4=top3; top3=top2; top2=fragcount; + idx4=idx3; idx3=idx2; idx2=k; + } + else if (fragcount>top3) + { + top4=top3; top3=fragcount; + idx4=idx3; idx3=k; + } + else if (fragcount>top4) + { + top4=fragcount; + idx4=k; + } + } + // if the biggest number exists, put it in the init string + if (idx1>-1) + { + sprintf(numbuf,"%5d",top1); + // make frag count in player's color via escape code + hud_keysstr[i++] = '\x1b'; //jff 3/26/98 use ESC not '\' for paths + hud_keysstr[i++] = '0'+plyrcoltran[idx1&3]; + s = numbuf; + while (*s) + hud_keysstr[i++] = *(s++); + } + // if the second biggest number exists, put it in the init string + if (idx2>-1) + { + sprintf(numbuf,"%5d",top2); + // make frag count in player's color via escape code + hud_keysstr[i++] = '\x1b'; //jff 3/26/98 use ESC not '\' for paths + hud_keysstr[i++] = '0'+plyrcoltran[idx2&3]; + s = numbuf; + while (*s) + hud_keysstr[i++] = *(s++); + } + // if the third biggest number exists, put it in the init string + if (idx3>-1) + { + sprintf(numbuf,"%5d",top3); + // make frag count in player's color via escape code + hud_keysstr[i++] = '\x1b'; //jff 3/26/98 use ESC not '\' for paths + hud_keysstr[i++] = '0'+plyrcoltran[idx3&3]; + s = numbuf; + while (*s) + hud_keysstr[i++] = *(s++); + } + // if the fourth biggest number exists, put it in the init string + if (idx4>-1) + { + sprintf(numbuf,"%5d",top4); + // make frag count in player's color via escape code + hud_keysstr[i++] = '\x1b'; //jff 3/26/98 use ESC not '\' for paths + hud_keysstr[i++] = '0'+plyrcoltran[idx4&3]; + s = numbuf; + while (*s) + hud_keysstr[i++] = *(s++); + } + hud_keysstr[i] = '\0'; + } //jff 3/17/98 end of deathmatch clause + else // build alphabetical key display (not used currently) + { + // scan the keys + for (k=0;k<6;k++) + { + // skip any not possessed by the displayed player's stats + if (!player->cards[k]) + continue; + + // use color escapes to make text in key's color + hud_keysstr[i++] = '\x1b'; //jff 3/26/98 use ESC not '\' for paths + switch(k) + { + case 0: + hud_keysstr[i++] = '0'+CR_BLUE; + hud_keysstr[i++] = 'B'; + hud_keysstr[i++] = 'C'; + hud_keysstr[i++] = ' '; + break; + case 1: + hud_keysstr[i++] = '0'+CR_GOLD; + hud_keysstr[i++] = 'Y'; + hud_keysstr[i++] = 'C'; + hud_keysstr[i++] = ' '; + break; + case 2: + hud_keysstr[i++] = '0'+CR_RED; + hud_keysstr[i++] = 'R'; + hud_keysstr[i++] = 'C'; + hud_keysstr[i++] = ' '; + break; + case 3: + hud_keysstr[i++] = '0'+CR_BLUE; + hud_keysstr[i++] = 'B'; + hud_keysstr[i++] = 'S'; + hud_keysstr[i++] = ' '; + break; + case 4: + hud_keysstr[i++] = '0'+CR_GOLD; + hud_keysstr[i++] = 'Y'; + hud_keysstr[i++] = 'S'; + hud_keysstr[i++] = ' '; + break; + case 5: + hud_keysstr[i++] = '0'+CR_RED; + hud_keysstr[i++] = 'R'; + hud_keysstr[i++] = 'S'; + hud_keysstr[i++] = ' '; + break; + } + hud_keysstr[i]='\0'; + } + } + } + } + // display the keys/frags line each frame + if (hud_active>1) + { + HUlib_clearTextLine(&w_keys); // clear the widget strings + HUlib_clearTextLine(&w_gkeys); + + // transfer the built string (frags or key title) to the widget + s = hud_keysstr; //jff 3/7/98 display key titles/key text or frags + while (*s) + HUlib_addCharToTextLine(&w_keys, *(s++)); + HUlib_drawTextLine(&w_keys, false); + + //jff 3/17/98 show graphic keys in non-DM only + if (!deathmatch) //jff 3/7/98 display graphic keys + { + // transfer the graphic key text to the widget + s = hud_gkeysstr; + while (*s) + HUlib_addCharToTextLine(&w_gkeys, *(s++)); + // display the widget + HUlib_drawTextLine(&w_gkeys, false); + } + } + + // display the hud kills/items/secret display if optioned + if (!hud_nosecrets) + { + if (hud_active>1 && doit) + { + // clear the internal widget text buffer + HUlib_clearTextLine(&w_monsec); + //jff 3/26/98 use ESC not '\' for paths + // build the init string with fixed colors + sprintf + ( + hud_monsecstr, + "STS \x1b\x36K \x1b\x33%d \x1b\x36M \x1b\x33%d \x1b\x37I \x1b\x33%d/%d \x1b\x35S \x1b\x33%d/%d", + player->killcount,totallive, + player->itemcount,totalitems, + player->secretcount,totalsecret + ); + // transfer the init string to the widget + s = hud_monsecstr; + while (*s) + HUlib_addCharToTextLine(&w_monsec, *(s++)); + } + // display the kills/items/secrets each frame, if optioned + if (hud_active>1) + HUlib_drawTextLine(&w_monsec, false); + } + } + + //jff 3/4/98 display last to give priority + HU_Erase(); // jff 4/24/98 Erase current lines before drawing current + // needed when screen not fullsize + + //jff 4/21/98 if setup has disabled message list while active, turn it off + if (hud_msg_lines<=1) + message_list = false; + + // if the message review not enabled, show the standard message widget + if (!message_list) + HUlib_drawSText(&w_message); + + // if the message review is enabled show the scrolling message review + if (hud_msg_lines>1 && message_list) + HUlib_drawMText(&w_rtext); + + // display the interactive buffer for chat entry + HUlib_drawIText(&w_chat); +} + +// +// HU_Erase() +// +// Erase hud display lines that can be trashed by small screen display +// +// Passed nothing, returns nothing +// +void HU_Erase(void) +{ + // erase the message display or the message review display + if (!message_list) + HUlib_eraseSText(&w_message); + else + HUlib_eraseMText(&w_rtext); + + // erase the interactive text buffer for chat entry + HUlib_eraseIText(&w_chat); + + // erase the automap title + HUlib_eraseTextLine(&w_title); +} + +// +// HU_Ticker() +// +// Update the hud displays once per frame +// +// Passed nothing, returns nothing +// +static boolean bsdown; // Is backspace down? +static int bscounter; + +void HU_Ticker(void) +{ + int i, rc; + char c; + + // tick down message counter if message is up + if (message_counter && !--message_counter) + { + message_on = false; + message_nottobefuckedwith = false; + } + if (bsdown && bscounter++ > 9) { + HUlib_keyInIText(&w_chat, (unsigned char)key_backspace); + bscounter = 8; + } + + // if messages on, or "Messages Off" is being displayed + // this allows the notification of turning messages off to be seen + if (showMessages || message_dontfuckwithme) + { + // display message if necessary + if ((plr->message && !message_nottobefuckedwith) + || (plr->message && message_dontfuckwithme)) + { +#ifdef IPHONE + // draw with the high quality font, above all UI elements + iphoneSetNotifyText( "%s", plr->message ); +#else + //post the message to the message widget + HUlib_addMessageToSText(&w_message, 0, plr->message); + //jff 2/26/98 add message to refresh text widget too + HUlib_addMessageToMText(&w_rtext, 0, plr->message); +#endif + // clear the message to avoid posting multiple times + plr->message = 0; + // note a message is displayed + message_on = true; + // start the message persistence counter + message_counter = HU_MSGTIMEOUT; + // transfer "Messages Off" exception to the "being displayed" variable + message_nottobefuckedwith = message_dontfuckwithme; + // clear the flag that "Messages Off" is being posted + message_dontfuckwithme = 0; + } + } + + // check for incoming chat characters + if (netgame) + { + for (i=0; i= 'a' && c <= 'z') + c = (char) shiftxform[(unsigned char) c]; + rc = HUlib_keyInIText(&w_inputbuffer[i], c); + if (rc && c == KEYD_ENTER) + { + if (w_inputbuffer[i].l.len + && (chat_dest[i] == consoleplayer+1 + || chat_dest[i] == HU_BROADCAST)) + { + HUlib_addMessageToSText(&w_message, + player_names[i], + w_inputbuffer[i].l.l); + + message_nottobefuckedwith = true; + message_on = true; + message_counter = HU_MSGTIMEOUT; + if ( gamemode == commercial ) + S_StartSound(0, sfx_radio); + else + S_StartSound(0, sfx_tink); + } + HUlib_resetIText(&w_inputbuffer[i]); + } + } + players[i].cmd.chatchar = 0; + } + } + } +} + +#define QUEUESIZE 128 + +static char chatchars[QUEUESIZE]; +static int head = 0; +static int tail = 0; + +// +// HU_queueChatChar() +// +// Add an incoming character to the circular chat queue +// +// Passed the character to queue, returns nothing +// +static void HU_queueChatChar(char c) +{ + if (((head + 1) & (QUEUESIZE-1)) == tail) + { + plr->message = HUSTR_MSGU; + } + else + { + chatchars[head] = c; + head = (head + 1) & (QUEUESIZE-1); + } +} + +// +// HU_dequeueChatChar() +// +// Remove the earliest added character from the circular chat queue +// +// Passed nothing, returns the character dequeued +// +char HU_dequeueChatChar(void) +{ + char c; + + if (head != tail) + { + c = chatchars[tail]; + tail = (tail + 1) & (QUEUESIZE-1); + } + else + { + c = 0; + } + return c; +} + +// +// HU_Responder() +// +// Responds to input events that affect the heads up displays +// +// Passed the event to respond to, returns true if the event was handled +// +boolean HU_Responder(event_t *ev) +{ + + static char lastmessage[HU_MAXLINELENGTH+1]; + const char* macromessage; // CPhipps - const char* + boolean eatkey = false; + static boolean shiftdown = false; + static boolean altdown = false; + unsigned char c; + int i; + int numplayers; + + static int num_nobrainers = 0; + + numplayers = 0; + for (i=0 ; idata1 == key_shift) + { + shiftdown = ev->type == ev_keydown; + return false; + } + else if (ev->data1 == key_alt) + { + altdown = ev->type == ev_keydown; + return false; + } + else if (ev->data1 == key_backspace) + { + bsdown = ev->type == ev_keydown; + bscounter = 0; + } + + if (ev->type != ev_keydown) + return false; + + if (!chat_on) + { + if (ev->data1 == key_enter) // phares + { +#ifndef INSTRUMENTED // never turn on message review if INSTRUMENTED defined + if (hud_msg_lines>1) // it posts multi-line messages that will trash + { + if (message_list) HU_Erase(); //jff 4/28/98 erase behind messages + message_list = !message_list; //jff 2/26/98 toggle list of messages + } +#endif + if (!message_list) // if not message list, refresh message + { + message_on = true; + message_counter = HU_MSGTIMEOUT; + } + eatkey = true; + }//jff 2/26/98 no chat if message review is displayed + // killough 10/02/98: no chat if demo playback + // no chat in -solo-net mode + else if (!demoplayback && !message_list && netgame && numplayers > 1) + { + if (ev->data1 == key_chat) + { + eatkey = chat_on = true; + HUlib_resetIText(&w_chat); + HU_queueChatChar(HU_BROADCAST); + } + else if (numplayers > 2) + { + for (i=0; idata1 == destination_keys[i]) + { + if (playeringame[i] && i!=consoleplayer) + { + eatkey = chat_on = true; + HUlib_resetIText(&w_chat); + HU_queueChatChar((char)(i+1)); + break; + } + else if (i == consoleplayer) + { + num_nobrainers++; + if (num_nobrainers < 3) + plr->message = HUSTR_TALKTOSELF1; + else if (num_nobrainers < 6) + plr->message = HUSTR_TALKTOSELF2; + else if (num_nobrainers < 9) + plr->message = HUSTR_TALKTOSELF3; + else if (num_nobrainers < 32) + plr->message = HUSTR_TALKTOSELF4; + else + plr->message = HUSTR_TALKTOSELF5; + } + } + } + } + } + }//jff 2/26/98 no chat functions if message review is displayed + else if (!message_list) + { + c = ev->data1; + // send a macro + if (altdown) + { + c = c - '0'; + if (c > 9) + return false; + macromessage = chat_macros[c]; + + // kill last message with a '\n' + HU_queueChatChar((char)key_enter); // DEBUG!!! // phares + + // send the macro message + while (*macromessage) + HU_queueChatChar(*macromessage++); + HU_queueChatChar((char)key_enter); // phares + + // leave chat mode and notify that it was sent + chat_on = false; + strcpy(lastmessage, chat_macros[c]); + plr->message = lastmessage; + eatkey = true; + } + else + { + if (shiftdown || (c >= 'a' && c <= 'z')) + c = shiftxform[c]; + eatkey = HUlib_keyInIText(&w_chat, c); + if (eatkey) + HU_queueChatChar(c); + + if (c == key_enter) // phares + { + chat_on = false; + if (w_chat.l.len) + { + strcpy(lastmessage, w_chat.l.l); + plr->message = lastmessage; + } + } + else if (c == key_escape) // phares + chat_on = false; + } + } + return eatkey; +} diff --git a/common/prboom/hu_stuff.h b/common/prboom/hu_stuff.h new file mode 100755 index 0000000..e4cbf24 --- /dev/null +++ b/common/prboom/hu_stuff.h @@ -0,0 +1,90 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: Head up display + * + *-----------------------------------------------------------------------------*/ + +#ifndef __HU_STUFF_H__ +#define __HU_STUFF_H__ + +#include "d_event.h" + +/* + * Globally visible constants. + */ +#define HU_FONTSTART '!' /* the first font characters */ +#define HU_FONTEND (0x7f) /*jff 2/16/98 '_' the last font characters */ + +/* Calculate # of glyphs in font. */ +#define HU_FONTSIZE (HU_FONTEND - HU_FONTSTART + 1) + +#define HU_BROADCAST 5 + +/*#define HU_MSGREFRESH KEYD_ENTER phares */ +#define HU_MSGX 0 +#define HU_MSGY 0 +#define HU_MSGWIDTH 64 /* in characters */ +#define HU_MSGHEIGHT 1 /* in lines */ + +#define HU_MSGTIMEOUT (4*TICRATE) + +/* + * Heads up text + */ +void HU_Init(void); +void HU_Start(void); + +boolean HU_Responder(event_t* ev); + +void HU_Ticker(void); +void HU_Drawer(void); +char HU_dequeueChatChar(void); +void HU_Erase(void); +void HU_MoveHud(void); // jff 3/9/98 avoid glitch in HUD display + +/* killough 5/2/98: moved from m_misc.c: */ + +/* jff 2/16/98 hud supported automap colors added */ +extern int hudcolor_titl; /* color range of automap level title */ +extern int hudcolor_xyco; /* color range of new coords on automap */ +/* jff 2/16/98 hud text colors, controls added */ +extern int hudcolor_mesg; /* color range of scrolling messages */ +extern int hudcolor_chat; /* color range of chat lines */ +/* jff 2/26/98 hud message list color and background enable */ +extern int hudcolor_list; /* color of list of past messages */ +extern int hud_list_bgon; /* solid window background for list of messages */ +extern int hud_msg_lines; /* number of message lines in window up to 16 */ +extern int hud_distributed; /* whether hud is all in lower left or distributed */ +/* jff 2/23/98 hud is currently displayed */ +extern int hud_displayed; /* hud is displayed */ +/* jff 2/18/98 hud/status control */ +extern int hud_active; /* hud mode 0=off, 1=small, 2=full */ +extern int hud_nosecrets; /* status does not list secrets/items/kills */ + +#endif diff --git a/common/prboom/i_joy.h b/common/prboom/i_joy.h new file mode 100755 index 0000000..29f19cb --- /dev/null +++ b/common/prboom/i_joy.h @@ -0,0 +1,47 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Joystick interface. + * + *-----------------------------------------------------------------------------*/ + +extern int joybfire; +extern int joybstrafe; +extern int joybuse; +extern int joybspeed; + +extern int joyleft; +extern int joyright; +extern int joyup; +extern int joydown; + +extern int usejoystick; + +void I_InitJoystick(void); +void I_PollJoystick(void); diff --git a/common/prboom/i_main.h b/common/prboom/i_main.h new file mode 100755 index 0000000..60b4662 --- /dev/null +++ b/common/prboom/i_main.h @@ -0,0 +1,44 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * General system functions. Signal related stuff, exit function + * prototypes, and programmable Doom clock. + * + *----------------------------------------------------------------------------- + */ + +#ifndef __I_MAIN__ +#define __I_MAIN__ + +void I_Init(void); +void I_SafeExit(int rc); + +extern int (*I_GetTime)(void); + +#endif diff --git a/common/prboom/i_network.h b/common/prboom/i_network.h new file mode 100755 index 0000000..532941f --- /dev/null +++ b/common/prboom/i_network.h @@ -0,0 +1,74 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Low level network interface. + *-----------------------------------------------------------------------------*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef USE_SDL_NET + #include "SDL_net.h" + #define UDP_SOCKET UDPsocket + #define UDP_PACKET UDPpacket + #define AF_INET + #define UDP_CHANNEL int + extern UDP_SOCKET udp_socket; +#else + #define UDP_CHANNEL struct sockaddr +#endif + +#ifndef IPPORT_RESERVED + #define IPPORT_RESERVED 1024 +#endif + +void I_InitNetwork(void); +size_t I_GetPacket(packet_header_t* buffer, size_t buflen); +void I_SendPacket(packet_header_t* packet, size_t len); +void I_WaitForPacket(int ms); + +#ifdef USE_SDL_NET +UDP_SOCKET I_Socket(Uint16 port); +int I_ConnectToServer(const char *serv); +UDP_CHANNEL I_RegisterPlayer(IPaddress *ipaddr); +void I_UnRegisterPlayer(UDP_CHANNEL channel); +extern IPaddress sentfrom_addr; +#endif + +#ifdef AF_INET +void I_SendPacketTo(packet_header_t* packet, size_t len, UDP_CHANNEL *to); +void I_SetupSocket(int sock, int port, int family); +void I_PrintAddress(FILE* fp, UDP_CHANNEL *addr); + +extern UDP_CHANNEL sentfrom; +extern int v4socket, v6socket; +#endif + +extern size_t sentbytes, recvdbytes; diff --git a/common/prboom/i_sound.h b/common/prboom/i_sound.h new file mode 100755 index 0000000..e03ccbf --- /dev/null +++ b/common/prboom/i_sound.h @@ -0,0 +1,120 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * System interface, sound. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __I_SOUND__ +#define __I_SOUND__ + +#include "sounds.h" +#include "doomtype.h" + +#define SNDSERV +#undef SNDINTR + +#ifndef SNDSERV +#include "l_soundgen.h" +#endif + +// Init at program start... +void I_InitSound(void); + +// ... shut down and relase at program termination. +void I_ShutdownSound(void); + +// +// SFX I/O +// + +// Initialize channels? +void I_SetChannels(void); + +// Get raw data lump index for sound descriptor. +int I_GetSfxLumpNum (sfxinfo_t *sfxinfo); + +// Starts a sound in a particular sound channel. +int I_StartSound(int id, int channel, int vol, int sep, int pitch, int priority); + +// Stops a sound channel. +void I_StopSound(int handle); + +// Called by S_*() functions +// to see if a channel is still playing. +// Returns 0 if no longer playing, 1 if playing. +boolean I_SoundIsPlaying(int handle); + +// Called by m_menu.c to let the quit sound play and quit right after it stops +boolean I_AnySoundStillPlaying(void); + +// Updates the volume, separation, +// and pitch of a sound channel. +void I_UpdateSoundParams(int handle, int vol, int sep, int pitch); + +// +// MUSIC I/O +// +void I_InitMusic(void); +void I_ShutdownMusic(void); + +void I_UpdateMusic(void); + +// Volume. +void I_SetMusicVolume(int volume); + +// PAUSE game handling. +void I_PauseSong(int handle); +void I_ResumeSong(int handle); + +// Registers a song handle to song data. +int I_RegisterSong(const void *data, size_t len); + +// cournia - tries to load a music file +int I_RegisterMusic( const char* filename, musicinfo_t *music ); + +// Called by anything that wishes to start music. +// plays a song, and when the song is done, +// starts playing it again in an endless loop. +// Horrible thing to do, considering. +void I_PlaySong(int handle, int looping); + +// Stops a song over 3 seconds. +void I_StopSong(int handle); + +// See above (register), then think backwards +void I_UnRegisterSong(int handle); + +// Allegro card support jff 1/18/98 +extern int snd_card; +extern int mus_card; +// CPhipps - put these in config file +extern int snd_samplerate; + +#endif diff --git a/common/prboom/i_system.h b/common/prboom/i_system.h new file mode 100755 index 0000000..c82ae7d --- /dev/null +++ b/common/prboom/i_system.h @@ -0,0 +1,85 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * System specific interface stuff. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __I_SYSTEM__ +#define __I_SYSTEM__ + +#ifdef __cplusplus +extern "C" { +#endif + + +extern int ms_to_next_tick; +boolean I_StartDisplay(void); +void I_EndDisplay(void); +int I_GetTime_RealTime(void); /* killough */ +#ifndef PRBOOM_SERVER +fixed_t I_GetTimeFrac (void); +#endif +void I_GetTime_SaveMS(void); + +unsigned long I_GetRandomTimeSeed(void); /* cphipps */ + +void I_uSleep(unsigned long usecs); + +/* cphipps - I_GetVersionString + * Returns a version string in the given buffer + */ +const char* I_GetVersionString(char* buf, size_t sz); + +/* cphipps - I_SigString + * Returns a string describing a signal number + */ +const char* I_SigString(char* buf, size_t sz, int signum); + +const char *I_DoomExeDir(void); // killough 2/16/98: path to executable's dir + +boolean HasTrailingSlash(const char* dn); +void I_FindFile(const char* wfname, const char* ext, char * returnWadName ); + +/* cph 2001/11/18 - wrapper for read(2) which deals with partial reads */ +void I_Read(int fd, void* buf, size_t sz); + +/* cph 2001/11/18 - Move W_Filelength to i_system.c */ +int I_Filelength(int handle); + +void I_SetAffinityMask(void); + +#define SCREENSHOT_DIR I_DoomExeDir() +#define HEAPDUMP_DIR I_DoomExeDir() + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/common/prboom/i_video.h b/common/prboom/i_video.h new file mode 100755 index 0000000..141e9ef --- /dev/null +++ b/common/prboom/i_video.h @@ -0,0 +1,79 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * System specific interface stuff. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __I_VIDEO__ +#define __I_VIDEO__ + +#include "doomtype.h" +#include "v_video.h" + + +void I_PreInitGraphics(void); /* CPhipps - do stuff immediately on start */ +void I_CalculateRes(unsigned int width, unsigned int height); /* calculate resolution */ +void I_SetRes(void); /* set resolution */ +void I_InitGraphics (void); +void I_UpdateVideoMode(void); +void I_ShutdownGraphics(void); + +/* Takes full 8 bit values. */ +void I_SetPalette(int pal); /* CPhipps - pass down palette number */ + +void I_UpdateNoBlit (void); +void I_FinishUpdate (void); + +int I_ScreenShot (const char *fname); + +/* I_StartTic + * Called by D_DoomLoop, + * called before processing each tic in a frame. + * Quick syncronous operations are performed here. + * Can call D_PostEvent. + */ +void I_StartTic (void); + +/* I_StartFrame + * Called by D_DoomLoop, + * called before processing any tics in a frame + * (just after displaying a frame). + * Time consuming syncronous operations + * are performed here (joystick reading). + * Can call D_PostEvent. + */ + +void I_StartFrame (void); + +extern int use_doublebuffer; /* proff 2001-7-4 - controls wether to use doublebuffering*/ +extern int use_fullscreen; /* proff 21/05/2000 */ +extern int desired_fullscreen; //e6y + +#endif diff --git a/common/prboom/info.c b/common/prboom/info.c new file mode 100755 index 0000000..50349cc --- /dev/null +++ b/common/prboom/info.c @@ -0,0 +1,4899 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Thing frame/state LUT, + * generated by multigen utilitiy. + * This one is the original DOOM version, preserved. + * BOOM changes include commenting and addition of predefined lumps + * for providing things that aren't in the IWAD without sending a + * separate must-use wad file around with the EXE. + * + *----------------------------------------------------------------------------- + */ + +#include "doomdef.h" +#include "sounds.h" +#include "m_fixed.h" +#include "p_mobj.h" +#include "p_enemy.h" +#include "p_pspr.h" +#include "w_wad.h" + +#ifdef __GNUG__ +#pragma implementation "info.h" +#endif +#include "info.h" + + +// ******************************************************************** +// Sprite names +// ******************************************************************** +// This is the list of sprite 4-character prefixes. They are searched +// through, with a NULL entry terminating the list. In DOOM originally +// this NULL entry was missing, and coincidentally the next thing in +// memory was the dummy state_t[] entry that started with zero bytes. +// killough 1/17/98: add an explicit NULL entry. +// NUMSPRITES is an enum from info.h where all these are listed +// as SPR_xxxx + +const char *sprnames[NUMSPRITES+1] = { + "TROO","SHTG","PUNG","PISG","PISF","SHTF","SHT2","CHGG","CHGF","MISG", + "MISF","SAWG","PLSG","PLSF","BFGG","BFGF","BLUD","PUFF","BAL1","BAL2", + "PLSS","PLSE","MISL","BFS1","BFE1","BFE2","TFOG","IFOG","PLAY","POSS", + "SPOS","VILE","FIRE","FATB","FBXP","SKEL","MANF","FATT","CPOS","SARG", + "HEAD","BAL7","BOSS","BOS2","SKUL","SPID","BSPI","APLS","APBX","CYBR", + "PAIN","SSWV","KEEN","BBRN","BOSF","ARM1","ARM2","BAR1","BEXP","FCAN", + "BON1","BON2","BKEY","RKEY","YKEY","BSKU","RSKU","YSKU","STIM","MEDI", + "SOUL","PINV","PSTR","PINS","MEGA","SUIT","PMAP","PVIS","CLIP","AMMO", + "ROCK","BROK","CELL","CELP","SHEL","SBOX","BPAK","BFUG","MGUN","CSAW", + "LAUN","PLAS","SHOT","SGN2","COLU","SMT2","GOR1","POL2","POL5","POL4", + "POL3","POL1","POL6","GOR2","GOR3","GOR4","GOR5","SMIT","COL1","COL2", + "COL3","COL4","CAND","CBRA","COL6","TRE1","TRE2","ELEC","CEYE","FSKU", + "COL5","TBLU","TGRN","TRED","SMBT","SMGT","SMRT","HDB1","HDB2","HDB3", + "HDB4","HDB5","HDB6","POB1","POB2","BRS1","TLMP","TLP2", + "TNT1", // invisible sprite phares 3/9/98 +#ifdef DOGS + "DOGS", /* killough 7/19/98: Marine's best friend :) */ +#endif + NULL +}; + +// ******************************************************************** +// State or "frame" information +// ******************************************************************** +// Each of the states, otherwise known as "frames", is outlined +// here. The data in each element of the array is the way it is +// initialized, with sprite names identified by their enumerator +// value such as SPR_SHTG. These correlate to the above sprite +// array so don't change them around unless you understand what +// you're doing. +// +// The commented name beginning with S_ at the end of each line +// is there to help figure out where the next-frame pointer is +// pointing. These are also additionally identified in info.h +// as enumerated values. From a change-and-recompile point of +// view this is fairly workable, but it adds a lot to the effort +// when trying to change things externally. See also the d_deh.c +// parts where frame rewiring is done for more details and the +// extended way a BEX file can handle this. + +state_t states[NUMSTATES] = { + {SPR_TROO,0,-1,NULL,S_NULL,0,0}, // S_NULL + {SPR_SHTG,4,0,A_Light0,S_NULL,0,0}, // S_LIGHTDONE + {SPR_PUNG,0,1,A_WeaponReady,S_PUNCH,0,0}, // S_PUNCH + {SPR_PUNG,0,1,A_Lower,S_PUNCHDOWN,0,0}, // S_PUNCHDOWN + {SPR_PUNG,0,1,A_Raise,S_PUNCHUP,0,0}, // S_PUNCHUP + {SPR_PUNG,1,4,NULL,S_PUNCH2,0,0}, // S_PUNCH1 + {SPR_PUNG,2,4,A_Punch,S_PUNCH3,0,0}, // S_PUNCH2 + {SPR_PUNG,3,5,NULL,S_PUNCH4,0,0}, // S_PUNCH3 + {SPR_PUNG,2,4,NULL,S_PUNCH5,0,0}, // S_PUNCH4 + {SPR_PUNG,1,5,A_ReFire,S_PUNCH,0,0}, // S_PUNCH5 + {SPR_PISG,0,1,A_WeaponReady,S_PISTOL,0,0},// S_PISTOL + {SPR_PISG,0,1,A_Lower,S_PISTOLDOWN,0,0}, // S_PISTOLDOWN + {SPR_PISG,0,1,A_Raise,S_PISTOLUP,0,0}, // S_PISTOLUP + {SPR_PISG,0,4,NULL,S_PISTOL2,0,0}, // S_PISTOL1 + {SPR_PISG,1,6,A_FirePistol,S_PISTOL3,0,0},// S_PISTOL2 + {SPR_PISG,2,4,NULL,S_PISTOL4,0,0}, // S_PISTOL3 + {SPR_PISG,1,5,A_ReFire,S_PISTOL,0,0}, // S_PISTOL4 + {SPR_PISF,32768,7,A_Light1,S_LIGHTDONE,0,0}, // S_PISTOLFLASH + {SPR_SHTG,0,1,A_WeaponReady,S_SGUN,0,0}, // S_SGUN + {SPR_SHTG,0,1,A_Lower,S_SGUNDOWN,0,0}, // S_SGUNDOWN + {SPR_SHTG,0,1,A_Raise,S_SGUNUP,0,0}, // S_SGUNUP + {SPR_SHTG,0,3,NULL,S_SGUN2,0,0}, // S_SGUN1 + {SPR_SHTG,0,7,A_FireShotgun,S_SGUN3,0,0}, // S_SGUN2 + {SPR_SHTG,1,5,NULL,S_SGUN4,0,0}, // S_SGUN3 + {SPR_SHTG,2,5,NULL,S_SGUN5,0,0}, // S_SGUN4 + {SPR_SHTG,3,4,NULL,S_SGUN6,0,0}, // S_SGUN5 + {SPR_SHTG,2,5,NULL,S_SGUN7,0,0}, // S_SGUN6 + {SPR_SHTG,1,5,NULL,S_SGUN8,0,0}, // S_SGUN7 + {SPR_SHTG,0,3,NULL,S_SGUN9,0,0}, // S_SGUN8 + {SPR_SHTG,0,7,A_ReFire,S_SGUN,0,0}, // S_SGUN9 + {SPR_SHTF,32768,4,A_Light1,S_SGUNFLASH2,0,0}, // S_SGUNFLASH1 + {SPR_SHTF,32769,3,A_Light2,S_LIGHTDONE,0,0}, // S_SGUNFLASH2 + {SPR_SHT2,0,1,A_WeaponReady,S_DSGUN,0,0}, // S_DSGUN + {SPR_SHT2,0,1,A_Lower,S_DSGUNDOWN,0,0}, // S_DSGUNDOWN + {SPR_SHT2,0,1,A_Raise,S_DSGUNUP,0,0}, // S_DSGUNUP + {SPR_SHT2,0,3,NULL,S_DSGUN2,0,0}, // S_DSGUN1 + {SPR_SHT2,0,7,A_FireShotgun2,S_DSGUN3,0,0}, // S_DSGUN2 + {SPR_SHT2,1,7,NULL,S_DSGUN4,0,0}, // S_DSGUN3 + {SPR_SHT2,2,7,A_CheckReload,S_DSGUN5,0,0}, // S_DSGUN4 + {SPR_SHT2,3,7,A_OpenShotgun2,S_DSGUN6,0,0}, // S_DSGUN5 + {SPR_SHT2,4,7,NULL,S_DSGUN7,0,0}, // S_DSGUN6 + {SPR_SHT2,5,7,A_LoadShotgun2,S_DSGUN8,0,0}, // S_DSGUN7 + {SPR_SHT2,6,6,NULL,S_DSGUN9,0,0}, // S_DSGUN8 + {SPR_SHT2,7,6,A_CloseShotgun2,S_DSGUN10,0,0}, // S_DSGUN9 + {SPR_SHT2,0,5,A_ReFire,S_DSGUN,0,0}, // S_DSGUN10 + {SPR_SHT2,1,7,NULL,S_DSNR2,0,0}, // S_DSNR1 + {SPR_SHT2,0,3,NULL,S_DSGUNDOWN,0,0}, // S_DSNR2 + {SPR_SHT2,32776,5,A_Light1,S_DSGUNFLASH2,0,0}, // S_DSGUNFLASH1 + {SPR_SHT2,32777,4,A_Light2,S_LIGHTDONE,0,0}, // S_DSGUNFLASH2 + {SPR_CHGG,0,1,A_WeaponReady,S_CHAIN,0,0}, // S_CHAIN + {SPR_CHGG,0,1,A_Lower,S_CHAINDOWN,0,0}, // S_CHAINDOWN + {SPR_CHGG,0,1,A_Raise,S_CHAINUP,0,0}, // S_CHAINUP + {SPR_CHGG,0,4,A_FireCGun,S_CHAIN2,0,0}, // S_CHAIN1 + {SPR_CHGG,1,4,A_FireCGun,S_CHAIN3,0,0}, // S_CHAIN2 + {SPR_CHGG,1,0,A_ReFire,S_CHAIN,0,0}, // S_CHAIN3 + {SPR_CHGF,32768,5,A_Light1,S_LIGHTDONE,0,0}, // S_CHAINFLASH1 + {SPR_CHGF,32769,5,A_Light2,S_LIGHTDONE,0,0}, // S_CHAINFLASH2 + {SPR_MISG,0,1,A_WeaponReady,S_MISSILE,0,0}, // S_MISSILE + {SPR_MISG,0,1,A_Lower,S_MISSILEDOWN,0,0}, // S_MISSILEDOWN + {SPR_MISG,0,1,A_Raise,S_MISSILEUP,0,0}, // S_MISSILEUP + {SPR_MISG,1,8,A_GunFlash,S_MISSILE2,0,0}, // S_MISSILE1 + {SPR_MISG,1,12,A_FireMissile,S_MISSILE3,0,0}, // S_MISSILE2 + {SPR_MISG,1,0,A_ReFire,S_MISSILE,0,0}, // S_MISSILE3 + {SPR_MISF,32768,3,A_Light1,S_MISSILEFLASH2,0,0}, // S_MISSILEFLASH1 + {SPR_MISF,32769,4,NULL,S_MISSILEFLASH3,0,0}, // S_MISSILEFLASH2 + {SPR_MISF,32770,4,A_Light2,S_MISSILEFLASH4,0,0}, // S_MISSILEFLASH3 + {SPR_MISF,32771,4,A_Light2,S_LIGHTDONE,0,0}, // S_MISSILEFLASH4 + {SPR_SAWG,2,4,A_WeaponReady,S_SAWB,0,0}, // S_SAW + {SPR_SAWG,3,4,A_WeaponReady,S_SAW,0,0}, // S_SAWB + {SPR_SAWG,2,1,A_Lower,S_SAWDOWN,0,0}, // S_SAWDOWN + {SPR_SAWG,2,1,A_Raise,S_SAWUP,0,0}, // S_SAWUP + {SPR_SAWG,0,4,A_Saw,S_SAW2,0,0}, // S_SAW1 + {SPR_SAWG,1,4,A_Saw,S_SAW3,0,0}, // S_SAW2 + {SPR_SAWG,1,0,A_ReFire,S_SAW,0,0}, // S_SAW3 + {SPR_PLSG,0,1,A_WeaponReady,S_PLASMA,0,0}, // S_PLASMA + {SPR_PLSG,0,1,A_Lower,S_PLASMADOWN,0,0}, // S_PLASMADOWN + {SPR_PLSG,0,1,A_Raise,S_PLASMAUP,0,0}, // S_PLASMAUP + {SPR_PLSG,0,3,A_FirePlasma,S_PLASMA2,0,0}, // S_PLASMA1 + {SPR_PLSG,1,20,A_ReFire,S_PLASMA,0,0}, // S_PLASMA2 + {SPR_PLSF,32768,4,A_Light1,S_LIGHTDONE,0,0}, // S_PLASMAFLASH1 + {SPR_PLSF,32769,4,A_Light1,S_LIGHTDONE,0,0}, // S_PLASMAFLASH2 + {SPR_BFGG,0,1,A_WeaponReady,S_BFG,0,0}, // S_BFG + {SPR_BFGG,0,1,A_Lower,S_BFGDOWN,0,0}, // S_BFGDOWN + {SPR_BFGG,0,1,A_Raise,S_BFGUP,0,0}, // S_BFGUP + {SPR_BFGG,0,20,A_BFGsound,S_BFG2,0,0}, // S_BFG1 + {SPR_BFGG,1,10,A_GunFlash,S_BFG3,0,0}, // S_BFG2 + {SPR_BFGG,1,10,A_FireBFG,S_BFG4,0,0}, // S_BFG3 + {SPR_BFGG,1,20,A_ReFire,S_BFG,0,0}, // S_BFG4 + {SPR_BFGF,32768,11,A_Light1,S_BFGFLASH2,0,0}, // S_BFGFLASH1 + {SPR_BFGF,32769,6,A_Light2,S_LIGHTDONE,0,0}, // S_BFGFLASH2 + {SPR_BLUD,2,8,NULL,S_BLOOD2,0,0}, // S_BLOOD1 + {SPR_BLUD,1,8,NULL,S_BLOOD3,0,0}, // S_BLOOD2 + {SPR_BLUD,0,8,NULL,S_NULL,0,0}, // S_BLOOD3 + {SPR_PUFF,32768,4,NULL,S_PUFF2,0,0}, // S_PUFF1 + {SPR_PUFF,1,4,NULL,S_PUFF3,0,0}, // S_PUFF2 + {SPR_PUFF,2,4,NULL,S_PUFF4,0,0}, // S_PUFF3 + {SPR_PUFF,3,4,NULL,S_NULL,0,0}, // S_PUFF4 + {SPR_BAL1,32768,4,NULL,S_TBALL2,0,0}, // S_TBALL1 + {SPR_BAL1,32769,4,NULL,S_TBALL1,0,0}, // S_TBALL2 + {SPR_BAL1,32770,6,NULL,S_TBALLX2,0,0}, // S_TBALLX1 + {SPR_BAL1,32771,6,NULL,S_TBALLX3,0,0}, // S_TBALLX2 + {SPR_BAL1,32772,6,NULL,S_NULL,0,0}, // S_TBALLX3 + {SPR_BAL2,32768,4,NULL,S_RBALL2,0,0}, // S_RBALL1 + {SPR_BAL2,32769,4,NULL,S_RBALL1,0,0}, // S_RBALL2 + {SPR_BAL2,32770,6,NULL,S_RBALLX2,0,0}, // S_RBALLX1 + {SPR_BAL2,32771,6,NULL,S_RBALLX3,0,0}, // S_RBALLX2 + {SPR_BAL2,32772,6,NULL,S_NULL,0,0}, // S_RBALLX3 + {SPR_PLSS,32768,6,NULL,S_PLASBALL2,0,0}, // S_PLASBALL + {SPR_PLSS,32769,6,NULL,S_PLASBALL,0,0}, // S_PLASBALL2 + {SPR_PLSE,32768,4,NULL,S_PLASEXP2,0,0}, // S_PLASEXP + {SPR_PLSE,32769,4,NULL,S_PLASEXP3,0,0}, // S_PLASEXP2 + {SPR_PLSE,32770,4,NULL,S_PLASEXP4,0,0}, // S_PLASEXP3 + {SPR_PLSE,32771,4,NULL,S_PLASEXP5,0,0}, // S_PLASEXP4 + {SPR_PLSE,32772,4,NULL,S_NULL,0,0}, // S_PLASEXP5 + {SPR_MISL,32768,1,NULL,S_ROCKET,0,0}, // S_ROCKET + {SPR_BFS1,32768,4,NULL,S_BFGSHOT2,0,0}, // S_BFGSHOT + {SPR_BFS1,32769,4,NULL,S_BFGSHOT,0,0}, // S_BFGSHOT2 + {SPR_BFE1,32768,8,NULL,S_BFGLAND2,0,0}, // S_BFGLAND + {SPR_BFE1,32769,8,NULL,S_BFGLAND3,0,0}, // S_BFGLAND2 + {SPR_BFE1,32770,8,A_BFGSpray,S_BFGLAND4,0,0}, // S_BFGLAND3 + {SPR_BFE1,32771,8,NULL,S_BFGLAND5,0,0}, // S_BFGLAND4 + {SPR_BFE1,32772,8,NULL,S_BFGLAND6,0,0}, // S_BFGLAND5 + {SPR_BFE1,32773,8,NULL,S_NULL,0,0}, // S_BFGLAND6 + {SPR_BFE2,32768,8,NULL,S_BFGEXP2,0,0}, // S_BFGEXP + {SPR_BFE2,32769,8,NULL,S_BFGEXP3,0,0}, // S_BFGEXP2 + {SPR_BFE2,32770,8,NULL,S_BFGEXP4,0,0}, // S_BFGEXP3 + {SPR_BFE2,32771,8,NULL,S_NULL,0,0}, // S_BFGEXP4 + {SPR_MISL,32769,8,A_Explode,S_EXPLODE2,0,0}, // S_EXPLODE1 + {SPR_MISL,32770,6,NULL,S_EXPLODE3,0,0}, // S_EXPLODE2 + {SPR_MISL,32771,4,NULL,S_NULL,0,0}, // S_EXPLODE3 + {SPR_TFOG,32768,6,NULL,S_TFOG01,0,0}, // S_TFOG + {SPR_TFOG,32769,6,NULL,S_TFOG02,0,0}, // S_TFOG01 + {SPR_TFOG,32768,6,NULL,S_TFOG2,0,0}, // S_TFOG02 + {SPR_TFOG,32769,6,NULL,S_TFOG3,0,0}, // S_TFOG2 + {SPR_TFOG,32770,6,NULL,S_TFOG4,0,0}, // S_TFOG3 + {SPR_TFOG,32771,6,NULL,S_TFOG5,0,0}, // S_TFOG4 + {SPR_TFOG,32772,6,NULL,S_TFOG6,0,0}, // S_TFOG5 + {SPR_TFOG,32773,6,NULL,S_TFOG7,0,0}, // S_TFOG6 + {SPR_TFOG,32774,6,NULL,S_TFOG8,0,0}, // S_TFOG7 + {SPR_TFOG,32775,6,NULL,S_TFOG9,0,0}, // S_TFOG8 + {SPR_TFOG,32776,6,NULL,S_TFOG10,0,0}, // S_TFOG9 + {SPR_TFOG,32777,6,NULL,S_NULL,0,0}, // S_TFOG10 + {SPR_IFOG,32768,6,NULL,S_IFOG01,0,0}, // S_IFOG + {SPR_IFOG,32769,6,NULL,S_IFOG02,0,0}, // S_IFOG01 + {SPR_IFOG,32768,6,NULL,S_IFOG2,0,0}, // S_IFOG02 + {SPR_IFOG,32769,6,NULL,S_IFOG3,0,0}, // S_IFOG2 + {SPR_IFOG,32770,6,NULL,S_IFOG4,0,0}, // S_IFOG3 + {SPR_IFOG,32771,6,NULL,S_IFOG5,0,0}, // S_IFOG4 + {SPR_IFOG,32772,6,NULL,S_NULL,0,0}, // S_IFOG5 + {SPR_PLAY,0,-1,NULL,S_NULL,0,0}, // S_PLAY + {SPR_PLAY,0,4,NULL,S_PLAY_RUN2,0,0}, // S_PLAY_RUN1 + {SPR_PLAY,1,4,NULL,S_PLAY_RUN3,0,0}, // S_PLAY_RUN2 + {SPR_PLAY,2,4,NULL,S_PLAY_RUN4,0,0}, // S_PLAY_RUN3 + {SPR_PLAY,3,4,NULL,S_PLAY_RUN1,0,0}, // S_PLAY_RUN4 + {SPR_PLAY,4,12,NULL,S_PLAY,0,0}, // S_PLAY_ATK1 + {SPR_PLAY,32773,6,NULL,S_PLAY_ATK1,0,0}, // S_PLAY_ATK2 + {SPR_PLAY,6,4,NULL,S_PLAY_PAIN2,0,0}, // S_PLAY_PAIN + {SPR_PLAY,6,4,A_Pain,S_PLAY,0,0}, // S_PLAY_PAIN2 + {SPR_PLAY,7,10,NULL,S_PLAY_DIE2,0,0}, // S_PLAY_DIE1 + {SPR_PLAY,8,10,A_PlayerScream,S_PLAY_DIE3,0,0}, // S_PLAY_DIE2 + {SPR_PLAY,9,10,A_Fall,S_PLAY_DIE4,0,0}, // S_PLAY_DIE3 + {SPR_PLAY,10,10,NULL,S_PLAY_DIE5,0,0}, // S_PLAY_DIE4 + {SPR_PLAY,11,10,NULL,S_PLAY_DIE6,0,0}, // S_PLAY_DIE5 + {SPR_PLAY,12,10,NULL,S_PLAY_DIE7,0,0}, // S_PLAY_DIE6 + {SPR_PLAY,13,-1,NULL,S_NULL,0,0}, // S_PLAY_DIE7 + {SPR_PLAY,14,5,NULL,S_PLAY_XDIE2,0,0}, // S_PLAY_XDIE1 + {SPR_PLAY,15,5,A_XScream,S_PLAY_XDIE3,0,0}, // S_PLAY_XDIE2 + {SPR_PLAY,16,5,A_Fall,S_PLAY_XDIE4,0,0}, // S_PLAY_XDIE3 + {SPR_PLAY,17,5,NULL,S_PLAY_XDIE5,0,0}, // S_PLAY_XDIE4 + {SPR_PLAY,18,5,NULL,S_PLAY_XDIE6,0,0}, // S_PLAY_XDIE5 + {SPR_PLAY,19,5,NULL,S_PLAY_XDIE7,0,0}, // S_PLAY_XDIE6 + {SPR_PLAY,20,5,NULL,S_PLAY_XDIE8,0,0}, // S_PLAY_XDIE7 + {SPR_PLAY,21,5,NULL,S_PLAY_XDIE9,0,0}, // S_PLAY_XDIE8 + {SPR_PLAY,22,-1,NULL,S_NULL,0,0}, // S_PLAY_XDIE9 + {SPR_POSS,0,10,A_Look,S_POSS_STND2,0,0}, // S_POSS_STND + {SPR_POSS,1,10,A_Look,S_POSS_STND,0,0}, // S_POSS_STND2 + {SPR_POSS,0,4,A_Chase,S_POSS_RUN2,0,0}, // S_POSS_RUN1 + {SPR_POSS,0,4,A_Chase,S_POSS_RUN3,0,0}, // S_POSS_RUN2 + {SPR_POSS,1,4,A_Chase,S_POSS_RUN4,0,0}, // S_POSS_RUN3 + {SPR_POSS,1,4,A_Chase,S_POSS_RUN5,0,0}, // S_POSS_RUN4 + {SPR_POSS,2,4,A_Chase,S_POSS_RUN6,0,0}, // S_POSS_RUN5 + {SPR_POSS,2,4,A_Chase,S_POSS_RUN7,0,0}, // S_POSS_RUN6 + {SPR_POSS,3,4,A_Chase,S_POSS_RUN8,0,0}, // S_POSS_RUN7 + {SPR_POSS,3,4,A_Chase,S_POSS_RUN1,0,0}, // S_POSS_RUN8 + {SPR_POSS,4,10,A_FaceTarget,S_POSS_ATK2,0,0}, // S_POSS_ATK1 + {SPR_POSS,5,8,A_PosAttack,S_POSS_ATK3,0,0}, // S_POSS_ATK2 + {SPR_POSS,4,8,NULL,S_POSS_RUN1,0,0}, // S_POSS_ATK3 + {SPR_POSS,6,3,NULL,S_POSS_PAIN2,0,0}, // S_POSS_PAIN + {SPR_POSS,6,3,A_Pain,S_POSS_RUN1,0,0}, // S_POSS_PAIN2 + {SPR_POSS,7,5,NULL,S_POSS_DIE2,0,0}, // S_POSS_DIE1 + {SPR_POSS,8,5,A_Scream,S_POSS_DIE3,0,0}, // S_POSS_DIE2 + {SPR_POSS,9,5,A_Fall,S_POSS_DIE4,0,0}, // S_POSS_DIE3 + {SPR_POSS,10,5,NULL,S_POSS_DIE5,0,0}, // S_POSS_DIE4 + {SPR_POSS,11,-1,NULL,S_NULL,0,0}, // S_POSS_DIE5 + {SPR_POSS,12,5,NULL,S_POSS_XDIE2,0,0}, // S_POSS_XDIE1 + {SPR_POSS,13,5,A_XScream,S_POSS_XDIE3,0,0}, // S_POSS_XDIE2 + {SPR_POSS,14,5,A_Fall,S_POSS_XDIE4,0,0}, // S_POSS_XDIE3 + {SPR_POSS,15,5,NULL,S_POSS_XDIE5,0,0}, // S_POSS_XDIE4 + {SPR_POSS,16,5,NULL,S_POSS_XDIE6,0,0}, // S_POSS_XDIE5 + {SPR_POSS,17,5,NULL,S_POSS_XDIE7,0,0}, // S_POSS_XDIE6 + {SPR_POSS,18,5,NULL,S_POSS_XDIE8,0,0}, // S_POSS_XDIE7 + {SPR_POSS,19,5,NULL,S_POSS_XDIE9,0,0}, // S_POSS_XDIE8 + {SPR_POSS,20,-1,NULL,S_NULL,0,0}, // S_POSS_XDIE9 + {SPR_POSS,10,5,NULL,S_POSS_RAISE2,0,0}, // S_POSS_RAISE1 + {SPR_POSS,9,5,NULL,S_POSS_RAISE3,0,0}, // S_POSS_RAISE2 + {SPR_POSS,8,5,NULL,S_POSS_RAISE4,0,0}, // S_POSS_RAISE3 + {SPR_POSS,7,5,NULL,S_POSS_RUN1,0,0}, // S_POSS_RAISE4 + {SPR_SPOS,0,10,A_Look,S_SPOS_STND2,0,0}, // S_SPOS_STND + {SPR_SPOS,1,10,A_Look,S_SPOS_STND,0,0}, // S_SPOS_STND2 + {SPR_SPOS,0,3,A_Chase,S_SPOS_RUN2,0,0}, // S_SPOS_RUN1 + {SPR_SPOS,0,3,A_Chase,S_SPOS_RUN3,0,0}, // S_SPOS_RUN2 + {SPR_SPOS,1,3,A_Chase,S_SPOS_RUN4,0,0}, // S_SPOS_RUN3 + {SPR_SPOS,1,3,A_Chase,S_SPOS_RUN5,0,0}, // S_SPOS_RUN4 + {SPR_SPOS,2,3,A_Chase,S_SPOS_RUN6,0,0}, // S_SPOS_RUN5 + {SPR_SPOS,2,3,A_Chase,S_SPOS_RUN7,0,0}, // S_SPOS_RUN6 + {SPR_SPOS,3,3,A_Chase,S_SPOS_RUN8,0,0}, // S_SPOS_RUN7 + {SPR_SPOS,3,3,A_Chase,S_SPOS_RUN1,0,0}, // S_SPOS_RUN8 + {SPR_SPOS,4,10,A_FaceTarget,S_SPOS_ATK2,0,0}, // S_SPOS_ATK1 + {SPR_SPOS,32773,10,A_SPosAttack,S_SPOS_ATK3,0,0}, // S_SPOS_ATK2 + {SPR_SPOS,4,10,NULL,S_SPOS_RUN1,0,0}, // S_SPOS_ATK3 + {SPR_SPOS,6,3,NULL,S_SPOS_PAIN2,0,0}, // S_SPOS_PAIN + {SPR_SPOS,6,3,A_Pain,S_SPOS_RUN1,0,0}, // S_SPOS_PAIN2 + {SPR_SPOS,7,5,NULL,S_SPOS_DIE2,0,0}, // S_SPOS_DIE1 + {SPR_SPOS,8,5,A_Scream,S_SPOS_DIE3,0,0}, // S_SPOS_DIE2 + {SPR_SPOS,9,5,A_Fall,S_SPOS_DIE4,0,0}, // S_SPOS_DIE3 + {SPR_SPOS,10,5,NULL,S_SPOS_DIE5,0,0}, // S_SPOS_DIE4 + {SPR_SPOS,11,-1,NULL,S_NULL,0,0}, // S_SPOS_DIE5 + {SPR_SPOS,12,5,NULL,S_SPOS_XDIE2,0,0}, // S_SPOS_XDIE1 + {SPR_SPOS,13,5,A_XScream,S_SPOS_XDIE3,0,0}, // S_SPOS_XDIE2 + {SPR_SPOS,14,5,A_Fall,S_SPOS_XDIE4,0,0}, // S_SPOS_XDIE3 + {SPR_SPOS,15,5,NULL,S_SPOS_XDIE5,0,0}, // S_SPOS_XDIE4 + {SPR_SPOS,16,5,NULL,S_SPOS_XDIE6,0,0}, // S_SPOS_XDIE5 + {SPR_SPOS,17,5,NULL,S_SPOS_XDIE7,0,0}, // S_SPOS_XDIE6 + {SPR_SPOS,18,5,NULL,S_SPOS_XDIE8,0,0}, // S_SPOS_XDIE7 + {SPR_SPOS,19,5,NULL,S_SPOS_XDIE9,0,0}, // S_SPOS_XDIE8 + {SPR_SPOS,20,-1,NULL,S_NULL,0,0}, // S_SPOS_XDIE9 + {SPR_SPOS,11,5,NULL,S_SPOS_RAISE2,0,0}, // S_SPOS_RAISE1 + {SPR_SPOS,10,5,NULL,S_SPOS_RAISE3,0,0}, // S_SPOS_RAISE2 + {SPR_SPOS,9,5,NULL,S_SPOS_RAISE4,0,0}, // S_SPOS_RAISE3 + {SPR_SPOS,8,5,NULL,S_SPOS_RAISE5,0,0}, // S_SPOS_RAISE4 + {SPR_SPOS,7,5,NULL,S_SPOS_RUN1,0,0}, // S_SPOS_RAISE5 + {SPR_VILE,0,10,A_Look,S_VILE_STND2,0,0}, // S_VILE_STND + {SPR_VILE,1,10,A_Look,S_VILE_STND,0,0}, // S_VILE_STND2 + {SPR_VILE,0,2,A_VileChase,S_VILE_RUN2,0,0}, // S_VILE_RUN1 + {SPR_VILE,0,2,A_VileChase,S_VILE_RUN3,0,0}, // S_VILE_RUN2 + {SPR_VILE,1,2,A_VileChase,S_VILE_RUN4,0,0}, // S_VILE_RUN3 + {SPR_VILE,1,2,A_VileChase,S_VILE_RUN5,0,0}, // S_VILE_RUN4 + {SPR_VILE,2,2,A_VileChase,S_VILE_RUN6,0,0}, // S_VILE_RUN5 + {SPR_VILE,2,2,A_VileChase,S_VILE_RUN7,0,0}, // S_VILE_RUN6 + {SPR_VILE,3,2,A_VileChase,S_VILE_RUN8,0,0}, // S_VILE_RUN7 + {SPR_VILE,3,2,A_VileChase,S_VILE_RUN9,0,0}, // S_VILE_RUN8 + {SPR_VILE,4,2,A_VileChase,S_VILE_RUN10,0,0}, // S_VILE_RUN9 + {SPR_VILE,4,2,A_VileChase,S_VILE_RUN11,0,0}, // S_VILE_RUN10 + {SPR_VILE,5,2,A_VileChase,S_VILE_RUN12,0,0}, // S_VILE_RUN11 + {SPR_VILE,5,2,A_VileChase,S_VILE_RUN1,0,0}, // S_VILE_RUN12 + {SPR_VILE,32774,0,A_VileStart,S_VILE_ATK2,0,0}, // S_VILE_ATK1 + {SPR_VILE,32774,10,A_FaceTarget,S_VILE_ATK3,0,0}, // S_VILE_ATK2 + {SPR_VILE,32775,8,A_VileTarget,S_VILE_ATK4,0,0}, // S_VILE_ATK3 + {SPR_VILE,32776,8,A_FaceTarget,S_VILE_ATK5,0,0}, // S_VILE_ATK4 + {SPR_VILE,32777,8,A_FaceTarget,S_VILE_ATK6,0,0}, // S_VILE_ATK5 + {SPR_VILE,32778,8,A_FaceTarget,S_VILE_ATK7,0,0}, // S_VILE_ATK6 + {SPR_VILE,32779,8,A_FaceTarget,S_VILE_ATK8,0,0}, // S_VILE_ATK7 + {SPR_VILE,32780,8,A_FaceTarget,S_VILE_ATK9,0,0}, // S_VILE_ATK8 + {SPR_VILE,32781,8,A_FaceTarget,S_VILE_ATK10,0,0}, // S_VILE_ATK9 + {SPR_VILE,32782,8,A_VileAttack,S_VILE_ATK11,0,0}, // S_VILE_ATK10 + {SPR_VILE,32783,20,NULL,S_VILE_RUN1,0,0}, // S_VILE_ATK11 + {SPR_VILE,32794,10,NULL,S_VILE_HEAL2,0,0}, // S_VILE_HEAL1 + {SPR_VILE,32795,10,NULL,S_VILE_HEAL3,0,0}, // S_VILE_HEAL2 + {SPR_VILE,32796,10,NULL,S_VILE_RUN1,0,0}, // S_VILE_HEAL3 + {SPR_VILE,16,5,NULL,S_VILE_PAIN2,0,0}, // S_VILE_PAIN + {SPR_VILE,16,5,A_Pain,S_VILE_RUN1,0,0}, // S_VILE_PAIN2 + {SPR_VILE,16,7,NULL,S_VILE_DIE2,0,0}, // S_VILE_DIE1 + {SPR_VILE,17,7,A_Scream,S_VILE_DIE3,0,0}, // S_VILE_DIE2 + {SPR_VILE,18,7,A_Fall,S_VILE_DIE4,0,0}, // S_VILE_DIE3 + {SPR_VILE,19,7,NULL,S_VILE_DIE5,0,0}, // S_VILE_DIE4 + {SPR_VILE,20,7,NULL,S_VILE_DIE6,0,0}, // S_VILE_DIE5 + {SPR_VILE,21,7,NULL,S_VILE_DIE7,0,0}, // S_VILE_DIE6 + {SPR_VILE,22,7,NULL,S_VILE_DIE8,0,0}, // S_VILE_DIE7 + {SPR_VILE,23,5,NULL,S_VILE_DIE9,0,0}, // S_VILE_DIE8 + {SPR_VILE,24,5,NULL,S_VILE_DIE10,0,0}, // S_VILE_DIE9 + {SPR_VILE,25,-1,NULL,S_NULL,0,0}, // S_VILE_DIE10 + {SPR_FIRE,32768,2,A_StartFire,S_FIRE2,0,0}, // S_FIRE1 + {SPR_FIRE,32769,2,A_Fire,S_FIRE3,0,0}, // S_FIRE2 + {SPR_FIRE,32768,2,A_Fire,S_FIRE4,0,0}, // S_FIRE3 + {SPR_FIRE,32769,2,A_Fire,S_FIRE5,0,0}, // S_FIRE4 + {SPR_FIRE,32770,2,A_FireCrackle,S_FIRE6,0,0}, // S_FIRE5 + {SPR_FIRE,32769,2,A_Fire,S_FIRE7,0,0}, // S_FIRE6 + {SPR_FIRE,32770,2,A_Fire,S_FIRE8,0,0}, // S_FIRE7 + {SPR_FIRE,32769,2,A_Fire,S_FIRE9,0,0}, // S_FIRE8 + {SPR_FIRE,32770,2,A_Fire,S_FIRE10,0,0}, // S_FIRE9 + {SPR_FIRE,32771,2,A_Fire,S_FIRE11,0,0}, // S_FIRE10 + {SPR_FIRE,32770,2,A_Fire,S_FIRE12,0,0}, // S_FIRE11 + {SPR_FIRE,32771,2,A_Fire,S_FIRE13,0,0}, // S_FIRE12 + {SPR_FIRE,32770,2,A_Fire,S_FIRE14,0,0}, // S_FIRE13 + {SPR_FIRE,32771,2,A_Fire,S_FIRE15,0,0}, // S_FIRE14 + {SPR_FIRE,32772,2,A_Fire,S_FIRE16,0,0}, // S_FIRE15 + {SPR_FIRE,32771,2,A_Fire,S_FIRE17,0,0}, // S_FIRE16 + {SPR_FIRE,32772,2,A_Fire,S_FIRE18,0,0}, // S_FIRE17 + {SPR_FIRE,32771,2,A_Fire,S_FIRE19,0,0}, // S_FIRE18 + {SPR_FIRE,32772,2,A_FireCrackle,S_FIRE20,0,0}, // S_FIRE19 + {SPR_FIRE,32773,2,A_Fire,S_FIRE21,0,0}, // S_FIRE20 + {SPR_FIRE,32772,2,A_Fire,S_FIRE22,0,0}, // S_FIRE21 + {SPR_FIRE,32773,2,A_Fire,S_FIRE23,0,0}, // S_FIRE22 + {SPR_FIRE,32772,2,A_Fire,S_FIRE24,0,0}, // S_FIRE23 + {SPR_FIRE,32773,2,A_Fire,S_FIRE25,0,0}, // S_FIRE24 + {SPR_FIRE,32774,2,A_Fire,S_FIRE26,0,0}, // S_FIRE25 + {SPR_FIRE,32775,2,A_Fire,S_FIRE27,0,0}, // S_FIRE26 + {SPR_FIRE,32774,2,A_Fire,S_FIRE28,0,0}, // S_FIRE27 + {SPR_FIRE,32775,2,A_Fire,S_FIRE29,0,0}, // S_FIRE28 + {SPR_FIRE,32774,2,A_Fire,S_FIRE30,0,0}, // S_FIRE29 + {SPR_FIRE,32775,2,A_Fire,S_NULL,0,0}, // S_FIRE30 + {SPR_PUFF,1,4,NULL,S_SMOKE2,0,0}, // S_SMOKE1 + {SPR_PUFF,2,4,NULL,S_SMOKE3,0,0}, // S_SMOKE2 + {SPR_PUFF,1,4,NULL,S_SMOKE4,0,0}, // S_SMOKE3 + {SPR_PUFF,2,4,NULL,S_SMOKE5,0,0}, // S_SMOKE4 + {SPR_PUFF,3,4,NULL,S_NULL,0,0}, // S_SMOKE5 + {SPR_FATB,32768,2,A_Tracer,S_TRACER2,0,0}, // S_TRACER + {SPR_FATB,32769,2,A_Tracer,S_TRACER,0,0}, // S_TRACER2 + {SPR_FBXP,32768,8,NULL,S_TRACEEXP2,0,0}, // S_TRACEEXP1 + {SPR_FBXP,32769,6,NULL,S_TRACEEXP3,0,0}, // S_TRACEEXP2 + {SPR_FBXP,32770,4,NULL,S_NULL,0,0}, // S_TRACEEXP3 + {SPR_SKEL,0,10,A_Look,S_SKEL_STND2,0,0}, // S_SKEL_STND + {SPR_SKEL,1,10,A_Look,S_SKEL_STND,0,0}, // S_SKEL_STND2 + {SPR_SKEL,0,2,A_Chase,S_SKEL_RUN2,0,0}, // S_SKEL_RUN1 + {SPR_SKEL,0,2,A_Chase,S_SKEL_RUN3,0,0}, // S_SKEL_RUN2 + {SPR_SKEL,1,2,A_Chase,S_SKEL_RUN4,0,0}, // S_SKEL_RUN3 + {SPR_SKEL,1,2,A_Chase,S_SKEL_RUN5,0,0}, // S_SKEL_RUN4 + {SPR_SKEL,2,2,A_Chase,S_SKEL_RUN6,0,0}, // S_SKEL_RUN5 + {SPR_SKEL,2,2,A_Chase,S_SKEL_RUN7,0,0}, // S_SKEL_RUN6 + {SPR_SKEL,3,2,A_Chase,S_SKEL_RUN8,0,0}, // S_SKEL_RUN7 + {SPR_SKEL,3,2,A_Chase,S_SKEL_RUN9,0,0}, // S_SKEL_RUN8 + {SPR_SKEL,4,2,A_Chase,S_SKEL_RUN10,0,0}, // S_SKEL_RUN9 + {SPR_SKEL,4,2,A_Chase,S_SKEL_RUN11,0,0}, // S_SKEL_RUN10 + {SPR_SKEL,5,2,A_Chase,S_SKEL_RUN12,0,0}, // S_SKEL_RUN11 + {SPR_SKEL,5,2,A_Chase,S_SKEL_RUN1,0,0}, // S_SKEL_RUN12 + {SPR_SKEL,6,0,A_FaceTarget,S_SKEL_FIST2,0,0}, // S_SKEL_FIST1 + {SPR_SKEL,6,6,A_SkelWhoosh,S_SKEL_FIST3,0,0}, // S_SKEL_FIST2 + {SPR_SKEL,7,6,A_FaceTarget,S_SKEL_FIST4,0,0}, // S_SKEL_FIST3 + {SPR_SKEL,8,6,A_SkelFist,S_SKEL_RUN1,0,0}, // S_SKEL_FIST4 + {SPR_SKEL,32777,0,A_FaceTarget,S_SKEL_MISS2,0,0}, // S_SKEL_MISS1 + {SPR_SKEL,32777,10,A_FaceTarget,S_SKEL_MISS3,0,0}, // S_SKEL_MISS2 + {SPR_SKEL,10,10,A_SkelMissile,S_SKEL_MISS4,0,0}, // S_SKEL_MISS3 + {SPR_SKEL,10,10,A_FaceTarget,S_SKEL_RUN1,0,0}, // S_SKEL_MISS4 + {SPR_SKEL,11,5,NULL,S_SKEL_PAIN2,0,0}, // S_SKEL_PAIN + {SPR_SKEL,11,5,A_Pain,S_SKEL_RUN1,0,0}, // S_SKEL_PAIN2 + {SPR_SKEL,11,7,NULL,S_SKEL_DIE2,0,0}, // S_SKEL_DIE1 + {SPR_SKEL,12,7,NULL,S_SKEL_DIE3,0,0}, // S_SKEL_DIE2 + {SPR_SKEL,13,7,A_Scream,S_SKEL_DIE4,0,0}, // S_SKEL_DIE3 + {SPR_SKEL,14,7,A_Fall,S_SKEL_DIE5,0,0}, // S_SKEL_DIE4 + {SPR_SKEL,15,7,NULL,S_SKEL_DIE6,0,0}, // S_SKEL_DIE5 + {SPR_SKEL,16,-1,NULL,S_NULL,0,0}, // S_SKEL_DIE6 + {SPR_SKEL,16,5,NULL,S_SKEL_RAISE2,0,0}, // S_SKEL_RAISE1 + {SPR_SKEL,15,5,NULL,S_SKEL_RAISE3,0,0}, // S_SKEL_RAISE2 + {SPR_SKEL,14,5,NULL,S_SKEL_RAISE4,0,0}, // S_SKEL_RAISE3 + {SPR_SKEL,13,5,NULL,S_SKEL_RAISE5,0,0}, // S_SKEL_RAISE4 + {SPR_SKEL,12,5,NULL,S_SKEL_RAISE6,0,0}, // S_SKEL_RAISE5 + {SPR_SKEL,11,5,NULL,S_SKEL_RUN1,0,0}, // S_SKEL_RAISE6 + {SPR_MANF,32768,4,NULL,S_FATSHOT2,0,0}, // S_FATSHOT1 + {SPR_MANF,32769,4,NULL,S_FATSHOT1,0,0}, // S_FATSHOT2 + {SPR_MISL,32769,8,NULL,S_FATSHOTX2,0,0}, // S_FATSHOTX1 + {SPR_MISL,32770,6,NULL,S_FATSHOTX3,0,0}, // S_FATSHOTX2 + {SPR_MISL,32771,4,NULL,S_NULL,0,0}, // S_FATSHOTX3 + {SPR_FATT,0,15,A_Look,S_FATT_STND2,0,0}, // S_FATT_STND + {SPR_FATT,1,15,A_Look,S_FATT_STND,0,0}, // S_FATT_STND2 + {SPR_FATT,0,4,A_Chase,S_FATT_RUN2,0,0}, // S_FATT_RUN1 + {SPR_FATT,0,4,A_Chase,S_FATT_RUN3,0,0}, // S_FATT_RUN2 + {SPR_FATT,1,4,A_Chase,S_FATT_RUN4,0,0}, // S_FATT_RUN3 + {SPR_FATT,1,4,A_Chase,S_FATT_RUN5,0,0}, // S_FATT_RUN4 + {SPR_FATT,2,4,A_Chase,S_FATT_RUN6,0,0}, // S_FATT_RUN5 + {SPR_FATT,2,4,A_Chase,S_FATT_RUN7,0,0}, // S_FATT_RUN6 + {SPR_FATT,3,4,A_Chase,S_FATT_RUN8,0,0}, // S_FATT_RUN7 + {SPR_FATT,3,4,A_Chase,S_FATT_RUN9,0,0}, // S_FATT_RUN8 + {SPR_FATT,4,4,A_Chase,S_FATT_RUN10,0,0}, // S_FATT_RUN9 + {SPR_FATT,4,4,A_Chase,S_FATT_RUN11,0,0}, // S_FATT_RUN10 + {SPR_FATT,5,4,A_Chase,S_FATT_RUN12,0,0}, // S_FATT_RUN11 + {SPR_FATT,5,4,A_Chase,S_FATT_RUN1,0,0}, // S_FATT_RUN12 + {SPR_FATT,6,20,A_FatRaise,S_FATT_ATK2,0,0}, // S_FATT_ATK1 + {SPR_FATT,32775,10,A_FatAttack1,S_FATT_ATK3,0,0}, // S_FATT_ATK2 + {SPR_FATT,8,5,A_FaceTarget,S_FATT_ATK4,0,0}, // S_FATT_ATK3 + {SPR_FATT,6,5,A_FaceTarget,S_FATT_ATK5,0,0}, // S_FATT_ATK4 + {SPR_FATT,32775,10,A_FatAttack2,S_FATT_ATK6,0,0}, // S_FATT_ATK5 + {SPR_FATT,8,5,A_FaceTarget,S_FATT_ATK7,0,0}, // S_FATT_ATK6 + {SPR_FATT,6,5,A_FaceTarget,S_FATT_ATK8,0,0}, // S_FATT_ATK7 + {SPR_FATT,32775,10,A_FatAttack3,S_FATT_ATK9,0,0}, // S_FATT_ATK8 + {SPR_FATT,8,5,A_FaceTarget,S_FATT_ATK10,0,0}, // S_FATT_ATK9 + {SPR_FATT,6,5,A_FaceTarget,S_FATT_RUN1,0,0}, // S_FATT_ATK10 + {SPR_FATT,9,3,NULL,S_FATT_PAIN2,0,0}, // S_FATT_PAIN + {SPR_FATT,9,3,A_Pain,S_FATT_RUN1,0,0}, // S_FATT_PAIN2 + {SPR_FATT,10,6,NULL,S_FATT_DIE2,0,0}, // S_FATT_DIE1 + {SPR_FATT,11,6,A_Scream,S_FATT_DIE3,0,0}, // S_FATT_DIE2 + {SPR_FATT,12,6,A_Fall,S_FATT_DIE4,0,0}, // S_FATT_DIE3 + {SPR_FATT,13,6,NULL,S_FATT_DIE5,0,0}, // S_FATT_DIE4 + {SPR_FATT,14,6,NULL,S_FATT_DIE6,0,0}, // S_FATT_DIE5 + {SPR_FATT,15,6,NULL,S_FATT_DIE7,0,0}, // S_FATT_DIE6 + {SPR_FATT,16,6,NULL,S_FATT_DIE8,0,0}, // S_FATT_DIE7 + {SPR_FATT,17,6,NULL,S_FATT_DIE9,0,0}, // S_FATT_DIE8 + {SPR_FATT,18,6,NULL,S_FATT_DIE10,0,0}, // S_FATT_DIE9 + {SPR_FATT,19,-1,A_BossDeath,S_NULL,0,0}, // S_FATT_DIE10 + {SPR_FATT,17,5,NULL,S_FATT_RAISE2,0,0}, // S_FATT_RAISE1 + {SPR_FATT,16,5,NULL,S_FATT_RAISE3,0,0}, // S_FATT_RAISE2 + {SPR_FATT,15,5,NULL,S_FATT_RAISE4,0,0}, // S_FATT_RAISE3 + {SPR_FATT,14,5,NULL,S_FATT_RAISE5,0,0}, // S_FATT_RAISE4 + {SPR_FATT,13,5,NULL,S_FATT_RAISE6,0,0}, // S_FATT_RAISE5 + {SPR_FATT,12,5,NULL,S_FATT_RAISE7,0,0}, // S_FATT_RAISE6 + {SPR_FATT,11,5,NULL,S_FATT_RAISE8,0,0}, // S_FATT_RAISE7 + {SPR_FATT,10,5,NULL,S_FATT_RUN1,0,0}, // S_FATT_RAISE8 + {SPR_CPOS,0,10,A_Look,S_CPOS_STND2,0,0}, // S_CPOS_STND + {SPR_CPOS,1,10,A_Look,S_CPOS_STND,0,0}, // S_CPOS_STND2 + {SPR_CPOS,0,3,A_Chase,S_CPOS_RUN2,0,0}, // S_CPOS_RUN1 + {SPR_CPOS,0,3,A_Chase,S_CPOS_RUN3,0,0}, // S_CPOS_RUN2 + {SPR_CPOS,1,3,A_Chase,S_CPOS_RUN4,0,0}, // S_CPOS_RUN3 + {SPR_CPOS,1,3,A_Chase,S_CPOS_RUN5,0,0}, // S_CPOS_RUN4 + {SPR_CPOS,2,3,A_Chase,S_CPOS_RUN6,0,0}, // S_CPOS_RUN5 + {SPR_CPOS,2,3,A_Chase,S_CPOS_RUN7,0,0}, // S_CPOS_RUN6 + {SPR_CPOS,3,3,A_Chase,S_CPOS_RUN8,0,0}, // S_CPOS_RUN7 + {SPR_CPOS,3,3,A_Chase,S_CPOS_RUN1,0,0}, // S_CPOS_RUN8 + {SPR_CPOS,4,10,A_FaceTarget,S_CPOS_ATK2,0,0}, // S_CPOS_ATK1 + {SPR_CPOS,32773,4,A_CPosAttack,S_CPOS_ATK3,0,0}, // S_CPOS_ATK2 + {SPR_CPOS,32772,4,A_CPosAttack,S_CPOS_ATK4,0,0}, // S_CPOS_ATK3 + {SPR_CPOS,5,1,A_CPosRefire,S_CPOS_ATK2,0,0}, // S_CPOS_ATK4 + {SPR_CPOS,6,3,NULL,S_CPOS_PAIN2,0,0}, // S_CPOS_PAIN + {SPR_CPOS,6,3,A_Pain,S_CPOS_RUN1,0,0}, // S_CPOS_PAIN2 + {SPR_CPOS,7,5,NULL,S_CPOS_DIE2,0,0}, // S_CPOS_DIE1 + {SPR_CPOS,8,5,A_Scream,S_CPOS_DIE3,0,0}, // S_CPOS_DIE2 + {SPR_CPOS,9,5,A_Fall,S_CPOS_DIE4,0,0}, // S_CPOS_DIE3 + {SPR_CPOS,10,5,NULL,S_CPOS_DIE5,0,0}, // S_CPOS_DIE4 + {SPR_CPOS,11,5,NULL,S_CPOS_DIE6,0,0}, // S_CPOS_DIE5 + {SPR_CPOS,12,5,NULL,S_CPOS_DIE7,0,0}, // S_CPOS_DIE6 + {SPR_CPOS,13,-1,NULL,S_NULL,0,0}, // S_CPOS_DIE7 + {SPR_CPOS,14,5,NULL,S_CPOS_XDIE2,0,0}, // S_CPOS_XDIE1 + {SPR_CPOS,15,5,A_XScream,S_CPOS_XDIE3,0,0}, // S_CPOS_XDIE2 + {SPR_CPOS,16,5,A_Fall,S_CPOS_XDIE4,0,0}, // S_CPOS_XDIE3 + {SPR_CPOS,17,5,NULL,S_CPOS_XDIE5,0,0}, // S_CPOS_XDIE4 + {SPR_CPOS,18,5,NULL,S_CPOS_XDIE6,0,0}, // S_CPOS_XDIE5 + {SPR_CPOS,19,-1,NULL,S_NULL,0,0}, // S_CPOS_XDIE6 + {SPR_CPOS,13,5,NULL,S_CPOS_RAISE2,0,0}, // S_CPOS_RAISE1 + {SPR_CPOS,12,5,NULL,S_CPOS_RAISE3,0,0}, // S_CPOS_RAISE2 + {SPR_CPOS,11,5,NULL,S_CPOS_RAISE4,0,0}, // S_CPOS_RAISE3 + {SPR_CPOS,10,5,NULL,S_CPOS_RAISE5,0,0}, // S_CPOS_RAISE4 + {SPR_CPOS,9,5,NULL,S_CPOS_RAISE6,0,0}, // S_CPOS_RAISE5 + {SPR_CPOS,8,5,NULL,S_CPOS_RAISE7,0,0}, // S_CPOS_RAISE6 + {SPR_CPOS,7,5,NULL,S_CPOS_RUN1,0,0}, // S_CPOS_RAISE7 + {SPR_TROO,0,10,A_Look,S_TROO_STND2,0,0}, // S_TROO_STND + {SPR_TROO,1,10,A_Look,S_TROO_STND,0,0}, // S_TROO_STND2 + {SPR_TROO,0,3,A_Chase,S_TROO_RUN2,0,0}, // S_TROO_RUN1 + {SPR_TROO,0,3,A_Chase,S_TROO_RUN3,0,0}, // S_TROO_RUN2 + {SPR_TROO,1,3,A_Chase,S_TROO_RUN4,0,0}, // S_TROO_RUN3 + {SPR_TROO,1,3,A_Chase,S_TROO_RUN5,0,0}, // S_TROO_RUN4 + {SPR_TROO,2,3,A_Chase,S_TROO_RUN6,0,0}, // S_TROO_RUN5 + {SPR_TROO,2,3,A_Chase,S_TROO_RUN7,0,0}, // S_TROO_RUN6 + {SPR_TROO,3,3,A_Chase,S_TROO_RUN8,0,0}, // S_TROO_RUN7 + {SPR_TROO,3,3,A_Chase,S_TROO_RUN1,0,0}, // S_TROO_RUN8 + {SPR_TROO,4,8,A_FaceTarget,S_TROO_ATK2,0,0}, // S_TROO_ATK1 + {SPR_TROO,5,8,A_FaceTarget,S_TROO_ATK3,0,0}, // S_TROO_ATK2 + {SPR_TROO,6,6,A_TroopAttack,S_TROO_RUN1,0,0}, // S_TROO_ATK3 + {SPR_TROO,7,2,NULL,S_TROO_PAIN2,0,0}, // S_TROO_PAIN + {SPR_TROO,7,2,A_Pain,S_TROO_RUN1,0,0}, // S_TROO_PAIN2 + {SPR_TROO,8,8,NULL,S_TROO_DIE2,0,0}, // S_TROO_DIE1 + {SPR_TROO,9,8,A_Scream,S_TROO_DIE3,0,0}, // S_TROO_DIE2 + {SPR_TROO,10,6,NULL,S_TROO_DIE4,0,0}, // S_TROO_DIE3 + {SPR_TROO,11,6,A_Fall,S_TROO_DIE5,0,0}, // S_TROO_DIE4 + {SPR_TROO,12,-1,NULL,S_NULL,0,0}, // S_TROO_DIE5 + {SPR_TROO,13,5,NULL,S_TROO_XDIE2,0,0}, // S_TROO_XDIE1 + {SPR_TROO,14,5,A_XScream,S_TROO_XDIE3,0,0}, // S_TROO_XDIE2 + {SPR_TROO,15,5,NULL,S_TROO_XDIE4,0,0}, // S_TROO_XDIE3 + {SPR_TROO,16,5,A_Fall,S_TROO_XDIE5,0,0}, // S_TROO_XDIE4 + {SPR_TROO,17,5,NULL,S_TROO_XDIE6,0,0}, // S_TROO_XDIE5 + {SPR_TROO,18,5,NULL,S_TROO_XDIE7,0,0}, // S_TROO_XDIE6 + {SPR_TROO,19,5,NULL,S_TROO_XDIE8,0,0}, // S_TROO_XDIE7 + {SPR_TROO,20,-1,NULL,S_NULL,0,0}, // S_TROO_XDIE8 + {SPR_TROO,12,8,NULL,S_TROO_RAISE2,0,0}, // S_TROO_RAISE1 + {SPR_TROO,11,8,NULL,S_TROO_RAISE3,0,0}, // S_TROO_RAISE2 + {SPR_TROO,10,6,NULL,S_TROO_RAISE4,0,0}, // S_TROO_RAISE3 + {SPR_TROO,9,6,NULL,S_TROO_RAISE5,0,0}, // S_TROO_RAISE4 + {SPR_TROO,8,6,NULL,S_TROO_RUN1,0,0}, // S_TROO_RAISE5 + {SPR_SARG,0,10,A_Look,S_SARG_STND2,0,0}, // S_SARG_STND + {SPR_SARG,1,10,A_Look,S_SARG_STND,0,0}, // S_SARG_STND2 + {SPR_SARG,0,2,A_Chase,S_SARG_RUN2,0,0}, // S_SARG_RUN1 + {SPR_SARG,0,2,A_Chase,S_SARG_RUN3,0,0}, // S_SARG_RUN2 + {SPR_SARG,1,2,A_Chase,S_SARG_RUN4,0,0}, // S_SARG_RUN3 + {SPR_SARG,1,2,A_Chase,S_SARG_RUN5,0,0}, // S_SARG_RUN4 + {SPR_SARG,2,2,A_Chase,S_SARG_RUN6,0,0}, // S_SARG_RUN5 + {SPR_SARG,2,2,A_Chase,S_SARG_RUN7,0,0}, // S_SARG_RUN6 + {SPR_SARG,3,2,A_Chase,S_SARG_RUN8,0,0}, // S_SARG_RUN7 + {SPR_SARG,3,2,A_Chase,S_SARG_RUN1,0,0}, // S_SARG_RUN8 + {SPR_SARG,4,8,A_FaceTarget,S_SARG_ATK2,0,0}, // S_SARG_ATK1 + {SPR_SARG,5,8,A_FaceTarget,S_SARG_ATK3,0,0}, // S_SARG_ATK2 + {SPR_SARG,6,8,A_SargAttack,S_SARG_RUN1,0,0}, // S_SARG_ATK3 + {SPR_SARG,7,2,NULL,S_SARG_PAIN2,0,0}, // S_SARG_PAIN + {SPR_SARG,7,2,A_Pain,S_SARG_RUN1,0,0}, // S_SARG_PAIN2 + {SPR_SARG,8,8,NULL,S_SARG_DIE2,0,0}, // S_SARG_DIE1 + {SPR_SARG,9,8,A_Scream,S_SARG_DIE3,0,0}, // S_SARG_DIE2 + {SPR_SARG,10,4,NULL,S_SARG_DIE4,0,0}, // S_SARG_DIE3 + {SPR_SARG,11,4,A_Fall,S_SARG_DIE5,0,0}, // S_SARG_DIE4 + {SPR_SARG,12,4,NULL,S_SARG_DIE6,0,0}, // S_SARG_DIE5 + {SPR_SARG,13,-1,NULL,S_NULL,0,0}, // S_SARG_DIE6 + {SPR_SARG,13,5,NULL,S_SARG_RAISE2,0,0}, // S_SARG_RAISE1 + {SPR_SARG,12,5,NULL,S_SARG_RAISE3,0,0}, // S_SARG_RAISE2 + {SPR_SARG,11,5,NULL,S_SARG_RAISE4,0,0}, // S_SARG_RAISE3 + {SPR_SARG,10,5,NULL,S_SARG_RAISE5,0,0}, // S_SARG_RAISE4 + {SPR_SARG,9,5,NULL,S_SARG_RAISE6,0,0}, // S_SARG_RAISE5 + {SPR_SARG,8,5,NULL,S_SARG_RUN1,0,0}, // S_SARG_RAISE6 + {SPR_HEAD,0,10,A_Look,S_HEAD_STND,0,0}, // S_HEAD_STND + {SPR_HEAD,0,3,A_Chase,S_HEAD_RUN1,0,0}, // S_HEAD_RUN1 + {SPR_HEAD,1,5,A_FaceTarget,S_HEAD_ATK2,0,0}, // S_HEAD_ATK1 + {SPR_HEAD,2,5,A_FaceTarget,S_HEAD_ATK3,0,0}, // S_HEAD_ATK2 + {SPR_HEAD,32771,5,A_HeadAttack,S_HEAD_RUN1,0,0}, // S_HEAD_ATK3 + {SPR_HEAD,4,3,NULL,S_HEAD_PAIN2,0,0}, // S_HEAD_PAIN + {SPR_HEAD,4,3,A_Pain,S_HEAD_PAIN3,0,0}, // S_HEAD_PAIN2 + {SPR_HEAD,5,6,NULL,S_HEAD_RUN1,0,0}, // S_HEAD_PAIN3 + {SPR_HEAD,6,8,NULL,S_HEAD_DIE2,0,0}, // S_HEAD_DIE1 + {SPR_HEAD,7,8,A_Scream,S_HEAD_DIE3,0,0}, // S_HEAD_DIE2 + {SPR_HEAD,8,8,NULL,S_HEAD_DIE4,0,0}, // S_HEAD_DIE3 + {SPR_HEAD,9,8,NULL,S_HEAD_DIE5,0,0}, // S_HEAD_DIE4 + {SPR_HEAD,10,8,A_Fall,S_HEAD_DIE6,0,0}, // S_HEAD_DIE5 + {SPR_HEAD,11,-1,NULL,S_NULL,0,0}, // S_HEAD_DIE6 + {SPR_HEAD,11,8,NULL,S_HEAD_RAISE2,0,0}, // S_HEAD_RAISE1 + {SPR_HEAD,10,8,NULL,S_HEAD_RAISE3,0,0}, // S_HEAD_RAISE2 + {SPR_HEAD,9,8,NULL,S_HEAD_RAISE4,0,0}, // S_HEAD_RAISE3 + {SPR_HEAD,8,8,NULL,S_HEAD_RAISE5,0,0}, // S_HEAD_RAISE4 + {SPR_HEAD,7,8,NULL,S_HEAD_RAISE6,0,0}, // S_HEAD_RAISE5 + {SPR_HEAD,6,8,NULL,S_HEAD_RUN1,0,0}, // S_HEAD_RAISE6 + {SPR_BAL7,32768,4,NULL,S_BRBALL2,0,0}, // S_BRBALL1 + {SPR_BAL7,32769,4,NULL,S_BRBALL1,0,0}, // S_BRBALL2 + {SPR_BAL7,32770,6,NULL,S_BRBALLX2,0,0}, // S_BRBALLX1 + {SPR_BAL7,32771,6,NULL,S_BRBALLX3,0,0}, // S_BRBALLX2 + {SPR_BAL7,32772,6,NULL,S_NULL,0,0}, // S_BRBALLX3 + {SPR_BOSS,0,10,A_Look,S_BOSS_STND2,0,0}, // S_BOSS_STND + {SPR_BOSS,1,10,A_Look,S_BOSS_STND,0,0}, // S_BOSS_STND2 + {SPR_BOSS,0,3,A_Chase,S_BOSS_RUN2,0,0}, // S_BOSS_RUN1 + {SPR_BOSS,0,3,A_Chase,S_BOSS_RUN3,0,0}, // S_BOSS_RUN2 + {SPR_BOSS,1,3,A_Chase,S_BOSS_RUN4,0,0}, // S_BOSS_RUN3 + {SPR_BOSS,1,3,A_Chase,S_BOSS_RUN5,0,0}, // S_BOSS_RUN4 + {SPR_BOSS,2,3,A_Chase,S_BOSS_RUN6,0,0}, // S_BOSS_RUN5 + {SPR_BOSS,2,3,A_Chase,S_BOSS_RUN7,0,0}, // S_BOSS_RUN6 + {SPR_BOSS,3,3,A_Chase,S_BOSS_RUN8,0,0}, // S_BOSS_RUN7 + {SPR_BOSS,3,3,A_Chase,S_BOSS_RUN1,0,0}, // S_BOSS_RUN8 + {SPR_BOSS,4,8,A_FaceTarget,S_BOSS_ATK2,0,0}, // S_BOSS_ATK1 + {SPR_BOSS,5,8,A_FaceTarget,S_BOSS_ATK3,0,0}, // S_BOSS_ATK2 + {SPR_BOSS,6,8,A_BruisAttack,S_BOSS_RUN1,0,0}, // S_BOSS_ATK3 + {SPR_BOSS,7,2,NULL,S_BOSS_PAIN2,0,0}, // S_BOSS_PAIN + {SPR_BOSS,7,2,A_Pain,S_BOSS_RUN1,0,0}, // S_BOSS_PAIN2 + {SPR_BOSS,8,8,NULL,S_BOSS_DIE2,0,0}, // S_BOSS_DIE1 + {SPR_BOSS,9,8,A_Scream,S_BOSS_DIE3,0,0}, // S_BOSS_DIE2 + {SPR_BOSS,10,8,NULL,S_BOSS_DIE4,0,0}, // S_BOSS_DIE3 + {SPR_BOSS,11,8,A_Fall,S_BOSS_DIE5,0,0}, // S_BOSS_DIE4 + {SPR_BOSS,12,8,NULL,S_BOSS_DIE6,0,0}, // S_BOSS_DIE5 + {SPR_BOSS,13,8,NULL,S_BOSS_DIE7,0,0}, // S_BOSS_DIE6 + {SPR_BOSS,14,-1,A_BossDeath,S_NULL,0,0}, // S_BOSS_DIE7 + {SPR_BOSS,14,8,NULL,S_BOSS_RAISE2,0,0}, // S_BOSS_RAISE1 + {SPR_BOSS,13,8,NULL,S_BOSS_RAISE3,0,0}, // S_BOSS_RAISE2 + {SPR_BOSS,12,8,NULL,S_BOSS_RAISE4,0,0}, // S_BOSS_RAISE3 + {SPR_BOSS,11,8,NULL,S_BOSS_RAISE5,0,0}, // S_BOSS_RAISE4 + {SPR_BOSS,10,8,NULL,S_BOSS_RAISE6,0,0}, // S_BOSS_RAISE5 + {SPR_BOSS,9,8,NULL,S_BOSS_RAISE7,0,0}, // S_BOSS_RAISE6 + {SPR_BOSS,8,8,NULL,S_BOSS_RUN1,0,0}, // S_BOSS_RAISE7 + {SPR_BOS2,0,10,A_Look,S_BOS2_STND2,0,0}, // S_BOS2_STND + {SPR_BOS2,1,10,A_Look,S_BOS2_STND,0,0}, // S_BOS2_STND2 + {SPR_BOS2,0,3,A_Chase,S_BOS2_RUN2,0,0}, // S_BOS2_RUN1 + {SPR_BOS2,0,3,A_Chase,S_BOS2_RUN3,0,0}, // S_BOS2_RUN2 + {SPR_BOS2,1,3,A_Chase,S_BOS2_RUN4,0,0}, // S_BOS2_RUN3 + {SPR_BOS2,1,3,A_Chase,S_BOS2_RUN5,0,0}, // S_BOS2_RUN4 + {SPR_BOS2,2,3,A_Chase,S_BOS2_RUN6,0,0}, // S_BOS2_RUN5 + {SPR_BOS2,2,3,A_Chase,S_BOS2_RUN7,0,0}, // S_BOS2_RUN6 + {SPR_BOS2,3,3,A_Chase,S_BOS2_RUN8,0,0}, // S_BOS2_RUN7 + {SPR_BOS2,3,3,A_Chase,S_BOS2_RUN1,0,0}, // S_BOS2_RUN8 + {SPR_BOS2,4,8,A_FaceTarget,S_BOS2_ATK2,0,0}, // S_BOS2_ATK1 + {SPR_BOS2,5,8,A_FaceTarget,S_BOS2_ATK3,0,0}, // S_BOS2_ATK2 + {SPR_BOS2,6,8,A_BruisAttack,S_BOS2_RUN1,0,0}, // S_BOS2_ATK3 + {SPR_BOS2,7,2,NULL,S_BOS2_PAIN2,0,0}, // S_BOS2_PAIN + {SPR_BOS2,7,2,A_Pain,S_BOS2_RUN1,0,0}, // S_BOS2_PAIN2 + {SPR_BOS2,8,8,NULL,S_BOS2_DIE2,0,0}, // S_BOS2_DIE1 + {SPR_BOS2,9,8,A_Scream,S_BOS2_DIE3,0,0}, // S_BOS2_DIE2 + {SPR_BOS2,10,8,NULL,S_BOS2_DIE4,0,0}, // S_BOS2_DIE3 + {SPR_BOS2,11,8,A_Fall,S_BOS2_DIE5,0,0}, // S_BOS2_DIE4 + {SPR_BOS2,12,8,NULL,S_BOS2_DIE6,0,0}, // S_BOS2_DIE5 + {SPR_BOS2,13,8,NULL,S_BOS2_DIE7,0,0}, // S_BOS2_DIE6 + {SPR_BOS2,14,-1,NULL,S_NULL,0,0}, // S_BOS2_DIE7 + {SPR_BOS2,14,8,NULL,S_BOS2_RAISE2,0,0}, // S_BOS2_RAISE1 + {SPR_BOS2,13,8,NULL,S_BOS2_RAISE3,0,0}, // S_BOS2_RAISE2 + {SPR_BOS2,12,8,NULL,S_BOS2_RAISE4,0,0}, // S_BOS2_RAISE3 + {SPR_BOS2,11,8,NULL,S_BOS2_RAISE5,0,0}, // S_BOS2_RAISE4 + {SPR_BOS2,10,8,NULL,S_BOS2_RAISE6,0,0}, // S_BOS2_RAISE5 + {SPR_BOS2,9,8,NULL,S_BOS2_RAISE7,0,0}, // S_BOS2_RAISE6 + {SPR_BOS2,8,8,NULL,S_BOS2_RUN1,0,0}, // S_BOS2_RAISE7 + {SPR_SKUL,32768,10,A_Look,S_SKULL_STND2,0,0}, // S_SKULL_STND + {SPR_SKUL,32769,10,A_Look,S_SKULL_STND,0,0}, // S_SKULL_STND2 + {SPR_SKUL,32768,6,A_Chase,S_SKULL_RUN2,0,0}, // S_SKULL_RUN1 + {SPR_SKUL,32769,6,A_Chase,S_SKULL_RUN1,0,0}, // S_SKULL_RUN2 + {SPR_SKUL,32770,10,A_FaceTarget,S_SKULL_ATK2,0,0}, // S_SKULL_ATK1 + {SPR_SKUL,32771,4,A_SkullAttack,S_SKULL_ATK3,0,0}, // S_SKULL_ATK2 + {SPR_SKUL,32770,4,NULL,S_SKULL_ATK4,0,0}, // S_SKULL_ATK3 + {SPR_SKUL,32771,4,NULL,S_SKULL_ATK3,0,0}, // S_SKULL_ATK4 + {SPR_SKUL,32772,3,NULL,S_SKULL_PAIN2,0,0}, // S_SKULL_PAIN + {SPR_SKUL,32772,3,A_Pain,S_SKULL_RUN1,0,0}, // S_SKULL_PAIN2 + {SPR_SKUL,32773,6,NULL,S_SKULL_DIE2,0,0}, // S_SKULL_DIE1 + {SPR_SKUL,32774,6,A_Scream,S_SKULL_DIE3,0,0}, // S_SKULL_DIE2 + {SPR_SKUL,32775,6,NULL,S_SKULL_DIE4,0,0}, // S_SKULL_DIE3 + {SPR_SKUL,32776,6,A_Fall,S_SKULL_DIE5,0,0}, // S_SKULL_DIE4 + {SPR_SKUL,9,6,NULL,S_SKULL_DIE6,0,0}, // S_SKULL_DIE5 + {SPR_SKUL,10,6,NULL,S_NULL,0,0}, // S_SKULL_DIE6 + {SPR_SPID,0,10,A_Look,S_SPID_STND2,0,0}, // S_SPID_STND + {SPR_SPID,1,10,A_Look,S_SPID_STND,0,0}, // S_SPID_STND2 + {SPR_SPID,0,3,A_Metal,S_SPID_RUN2,0,0}, // S_SPID_RUN1 + {SPR_SPID,0,3,A_Chase,S_SPID_RUN3,0,0}, // S_SPID_RUN2 + {SPR_SPID,1,3,A_Chase,S_SPID_RUN4,0,0}, // S_SPID_RUN3 + {SPR_SPID,1,3,A_Chase,S_SPID_RUN5,0,0}, // S_SPID_RUN4 + {SPR_SPID,2,3,A_Metal,S_SPID_RUN6,0,0}, // S_SPID_RUN5 + {SPR_SPID,2,3,A_Chase,S_SPID_RUN7,0,0}, // S_SPID_RUN6 + {SPR_SPID,3,3,A_Chase,S_SPID_RUN8,0,0}, // S_SPID_RUN7 + {SPR_SPID,3,3,A_Chase,S_SPID_RUN9,0,0}, // S_SPID_RUN8 + {SPR_SPID,4,3,A_Metal,S_SPID_RUN10,0,0}, // S_SPID_RUN9 + {SPR_SPID,4,3,A_Chase,S_SPID_RUN11,0,0}, // S_SPID_RUN10 + {SPR_SPID,5,3,A_Chase,S_SPID_RUN12,0,0}, // S_SPID_RUN11 + {SPR_SPID,5,3,A_Chase,S_SPID_RUN1,0,0}, // S_SPID_RUN12 + {SPR_SPID,32768,20,A_FaceTarget,S_SPID_ATK2,0,0}, // S_SPID_ATK1 + {SPR_SPID,32774,4,A_SPosAttack,S_SPID_ATK3,0,0}, // S_SPID_ATK2 + {SPR_SPID,32775,4,A_SPosAttack,S_SPID_ATK4,0,0}, // S_SPID_ATK3 + {SPR_SPID,32775,1,A_SpidRefire,S_SPID_ATK2,0,0}, // S_SPID_ATK4 + {SPR_SPID,8,3,NULL,S_SPID_PAIN2,0,0}, // S_SPID_PAIN + {SPR_SPID,8,3,A_Pain,S_SPID_RUN1,0,0}, // S_SPID_PAIN2 + {SPR_SPID,9,20,A_Scream,S_SPID_DIE2,0,0}, // S_SPID_DIE1 + {SPR_SPID,10,10,A_Fall,S_SPID_DIE3,0,0}, // S_SPID_DIE2 + {SPR_SPID,11,10,NULL,S_SPID_DIE4,0,0}, // S_SPID_DIE3 + {SPR_SPID,12,10,NULL,S_SPID_DIE5,0,0}, // S_SPID_DIE4 + {SPR_SPID,13,10,NULL,S_SPID_DIE6,0,0}, // S_SPID_DIE5 + {SPR_SPID,14,10,NULL,S_SPID_DIE7,0,0}, // S_SPID_DIE6 + {SPR_SPID,15,10,NULL,S_SPID_DIE8,0,0}, // S_SPID_DIE7 + {SPR_SPID,16,10,NULL,S_SPID_DIE9,0,0}, // S_SPID_DIE8 + {SPR_SPID,17,10,NULL,S_SPID_DIE10,0,0}, // S_SPID_DIE9 + {SPR_SPID,18,30,NULL,S_SPID_DIE11,0,0}, // S_SPID_DIE10 + {SPR_SPID,18,-1,A_BossDeath,S_NULL,0,0}, // S_SPID_DIE11 + {SPR_BSPI,0,10,A_Look,S_BSPI_STND2,0,0}, // S_BSPI_STND + {SPR_BSPI,1,10,A_Look,S_BSPI_STND,0,0}, // S_BSPI_STND2 + {SPR_BSPI,0,20,NULL,S_BSPI_RUN1,0,0}, // S_BSPI_SIGHT + {SPR_BSPI,0,3,A_BabyMetal,S_BSPI_RUN2,0,0}, // S_BSPI_RUN1 + {SPR_BSPI,0,3,A_Chase,S_BSPI_RUN3,0,0}, // S_BSPI_RUN2 + {SPR_BSPI,1,3,A_Chase,S_BSPI_RUN4,0,0}, // S_BSPI_RUN3 + {SPR_BSPI,1,3,A_Chase,S_BSPI_RUN5,0,0}, // S_BSPI_RUN4 + {SPR_BSPI,2,3,A_Chase,S_BSPI_RUN6,0,0}, // S_BSPI_RUN5 + {SPR_BSPI,2,3,A_Chase,S_BSPI_RUN7,0,0}, // S_BSPI_RUN6 + {SPR_BSPI,3,3,A_BabyMetal,S_BSPI_RUN8,0,0}, // S_BSPI_RUN7 + {SPR_BSPI,3,3,A_Chase,S_BSPI_RUN9,0,0}, // S_BSPI_RUN8 + {SPR_BSPI,4,3,A_Chase,S_BSPI_RUN10,0,0}, // S_BSPI_RUN9 + {SPR_BSPI,4,3,A_Chase,S_BSPI_RUN11,0,0}, // S_BSPI_RUN10 + {SPR_BSPI,5,3,A_Chase,S_BSPI_RUN12,0,0}, // S_BSPI_RUN11 + {SPR_BSPI,5,3,A_Chase,S_BSPI_RUN1,0,0}, // S_BSPI_RUN12 + {SPR_BSPI,32768,20,A_FaceTarget,S_BSPI_ATK2,0,0}, // S_BSPI_ATK1 + {SPR_BSPI,32774,4,A_BspiAttack,S_BSPI_ATK3,0,0}, // S_BSPI_ATK2 + {SPR_BSPI,32775,4,NULL,S_BSPI_ATK4,0,0}, // S_BSPI_ATK3 + {SPR_BSPI,32775,1,A_SpidRefire,S_BSPI_ATK2,0,0}, // S_BSPI_ATK4 + {SPR_BSPI,8,3,NULL,S_BSPI_PAIN2,0,0}, // S_BSPI_PAIN + {SPR_BSPI,8,3,A_Pain,S_BSPI_RUN1,0,0}, // S_BSPI_PAIN2 + {SPR_BSPI,9,20,A_Scream,S_BSPI_DIE2,0,0}, // S_BSPI_DIE1 + {SPR_BSPI,10,7,A_Fall,S_BSPI_DIE3,0,0}, // S_BSPI_DIE2 + {SPR_BSPI,11,7,NULL,S_BSPI_DIE4,0,0}, // S_BSPI_DIE3 + {SPR_BSPI,12,7,NULL,S_BSPI_DIE5,0,0}, // S_BSPI_DIE4 + {SPR_BSPI,13,7,NULL,S_BSPI_DIE6,0,0}, // S_BSPI_DIE5 + {SPR_BSPI,14,7,NULL,S_BSPI_DIE7,0,0}, // S_BSPI_DIE6 + {SPR_BSPI,15,-1,A_BossDeath,S_NULL,0,0}, // S_BSPI_DIE7 + {SPR_BSPI,15,5,NULL,S_BSPI_RAISE2,0,0}, // S_BSPI_RAISE1 + {SPR_BSPI,14,5,NULL,S_BSPI_RAISE3,0,0}, // S_BSPI_RAISE2 + {SPR_BSPI,13,5,NULL,S_BSPI_RAISE4,0,0}, // S_BSPI_RAISE3 + {SPR_BSPI,12,5,NULL,S_BSPI_RAISE5,0,0}, // S_BSPI_RAISE4 + {SPR_BSPI,11,5,NULL,S_BSPI_RAISE6,0,0}, // S_BSPI_RAISE5 + {SPR_BSPI,10,5,NULL,S_BSPI_RAISE7,0,0}, // S_BSPI_RAISE6 + {SPR_BSPI,9,5,NULL,S_BSPI_RUN1,0,0}, // S_BSPI_RAISE7 + {SPR_APLS,32768,5,NULL,S_ARACH_PLAZ2,0,0}, // S_ARACH_PLAZ + {SPR_APLS,32769,5,NULL,S_ARACH_PLAZ,0,0}, // S_ARACH_PLAZ2 + {SPR_APBX,32768,5,NULL,S_ARACH_PLEX2,0,0}, // S_ARACH_PLEX + {SPR_APBX,32769,5,NULL,S_ARACH_PLEX3,0,0}, // S_ARACH_PLEX2 + {SPR_APBX,32770,5,NULL,S_ARACH_PLEX4,0,0}, // S_ARACH_PLEX3 + {SPR_APBX,32771,5,NULL,S_ARACH_PLEX5,0,0}, // S_ARACH_PLEX4 + {SPR_APBX,32772,5,NULL,S_NULL,0,0}, // S_ARACH_PLEX5 + {SPR_CYBR,0,10,A_Look,S_CYBER_STND2,0,0}, // S_CYBER_STND + {SPR_CYBR,1,10,A_Look,S_CYBER_STND,0,0}, // S_CYBER_STND2 + {SPR_CYBR,0,3,A_Hoof,S_CYBER_RUN2,0,0}, // S_CYBER_RUN1 + {SPR_CYBR,0,3,A_Chase,S_CYBER_RUN3,0,0}, // S_CYBER_RUN2 + {SPR_CYBR,1,3,A_Chase,S_CYBER_RUN4,0,0}, // S_CYBER_RUN3 + {SPR_CYBR,1,3,A_Chase,S_CYBER_RUN5,0,0}, // S_CYBER_RUN4 + {SPR_CYBR,2,3,A_Chase,S_CYBER_RUN6,0,0}, // S_CYBER_RUN5 + {SPR_CYBR,2,3,A_Chase,S_CYBER_RUN7,0,0}, // S_CYBER_RUN6 + {SPR_CYBR,3,3,A_Metal,S_CYBER_RUN8,0,0}, // S_CYBER_RUN7 + {SPR_CYBR,3,3,A_Chase,S_CYBER_RUN1,0,0}, // S_CYBER_RUN8 + {SPR_CYBR,4,6,A_FaceTarget,S_CYBER_ATK2,0,0}, // S_CYBER_ATK1 + {SPR_CYBR,5,12,A_CyberAttack,S_CYBER_ATK3,0,0}, // S_CYBER_ATK2 + {SPR_CYBR,4,12,A_FaceTarget,S_CYBER_ATK4,0,0}, // S_CYBER_ATK3 + {SPR_CYBR,5,12,A_CyberAttack,S_CYBER_ATK5,0,0}, // S_CYBER_ATK4 + {SPR_CYBR,4,12,A_FaceTarget,S_CYBER_ATK6,0,0}, // S_CYBER_ATK5 + {SPR_CYBR,5,12,A_CyberAttack,S_CYBER_RUN1,0,0}, // S_CYBER_ATK6 + {SPR_CYBR,6,10,A_Pain,S_CYBER_RUN1,0,0}, // S_CYBER_PAIN + {SPR_CYBR,7,10,NULL,S_CYBER_DIE2,0,0}, // S_CYBER_DIE1 + {SPR_CYBR,8,10,A_Scream,S_CYBER_DIE3,0,0}, // S_CYBER_DIE2 + {SPR_CYBR,9,10,NULL,S_CYBER_DIE4,0,0}, // S_CYBER_DIE3 + {SPR_CYBR,10,10,NULL,S_CYBER_DIE5,0,0}, // S_CYBER_DIE4 + {SPR_CYBR,11,10,NULL,S_CYBER_DIE6,0,0}, // S_CYBER_DIE5 + {SPR_CYBR,12,10,A_Fall,S_CYBER_DIE7,0,0}, // S_CYBER_DIE6 + {SPR_CYBR,13,10,NULL,S_CYBER_DIE8,0,0}, // S_CYBER_DIE7 + {SPR_CYBR,14,10,NULL,S_CYBER_DIE9,0,0}, // S_CYBER_DIE8 + {SPR_CYBR,15,30,NULL,S_CYBER_DIE10,0,0}, // S_CYBER_DIE9 + {SPR_CYBR,15,-1,A_BossDeath,S_NULL,0,0}, // S_CYBER_DIE10 + {SPR_PAIN,0,10,A_Look,S_PAIN_STND,0,0}, // S_PAIN_STND + {SPR_PAIN,0,3,A_Chase,S_PAIN_RUN2,0,0}, // S_PAIN_RUN1 + {SPR_PAIN,0,3,A_Chase,S_PAIN_RUN3,0,0}, // S_PAIN_RUN2 + {SPR_PAIN,1,3,A_Chase,S_PAIN_RUN4,0,0}, // S_PAIN_RUN3 + {SPR_PAIN,1,3,A_Chase,S_PAIN_RUN5,0,0}, // S_PAIN_RUN4 + {SPR_PAIN,2,3,A_Chase,S_PAIN_RUN6,0,0}, // S_PAIN_RUN5 + {SPR_PAIN,2,3,A_Chase,S_PAIN_RUN1,0,0}, // S_PAIN_RUN6 + {SPR_PAIN,3,5,A_FaceTarget,S_PAIN_ATK2,0,0}, // S_PAIN_ATK1 + {SPR_PAIN,4,5,A_FaceTarget,S_PAIN_ATK3,0,0}, // S_PAIN_ATK2 + {SPR_PAIN,32773,5,A_FaceTarget,S_PAIN_ATK4,0,0}, // S_PAIN_ATK3 + {SPR_PAIN,32773,0,A_PainAttack,S_PAIN_RUN1,0,0}, // S_PAIN_ATK4 + {SPR_PAIN,6,6,NULL,S_PAIN_PAIN2,0,0}, // S_PAIN_PAIN + {SPR_PAIN,6,6,A_Pain,S_PAIN_RUN1,0,0}, // S_PAIN_PAIN2 + {SPR_PAIN,32775,8,NULL,S_PAIN_DIE2,0,0}, // S_PAIN_DIE1 + {SPR_PAIN,32776,8,A_Scream,S_PAIN_DIE3,0,0}, // S_PAIN_DIE2 + {SPR_PAIN,32777,8,NULL,S_PAIN_DIE4,0,0}, // S_PAIN_DIE3 + {SPR_PAIN,32778,8,NULL,S_PAIN_DIE5,0,0}, // S_PAIN_DIE4 + {SPR_PAIN,32779,8,A_PainDie,S_PAIN_DIE6,0,0}, // S_PAIN_DIE5 + {SPR_PAIN,32780,8,NULL,S_NULL,0,0}, // S_PAIN_DIE6 + {SPR_PAIN,12,8,NULL,S_PAIN_RAISE2,0,0}, // S_PAIN_RAISE1 + {SPR_PAIN,11,8,NULL,S_PAIN_RAISE3,0,0}, // S_PAIN_RAISE2 + {SPR_PAIN,10,8,NULL,S_PAIN_RAISE4,0,0}, // S_PAIN_RAISE3 + {SPR_PAIN,9,8,NULL,S_PAIN_RAISE5,0,0}, // S_PAIN_RAISE4 + {SPR_PAIN,8,8,NULL,S_PAIN_RAISE6,0,0}, // S_PAIN_RAISE5 + {SPR_PAIN,7,8,NULL,S_PAIN_RUN1,0,0}, // S_PAIN_RAISE6 + {SPR_SSWV,0,10,A_Look,S_SSWV_STND2,0,0}, // S_SSWV_STND + {SPR_SSWV,1,10,A_Look,S_SSWV_STND,0,0}, // S_SSWV_STND2 + {SPR_SSWV,0,3,A_Chase,S_SSWV_RUN2,0,0}, // S_SSWV_RUN1 + {SPR_SSWV,0,3,A_Chase,S_SSWV_RUN3,0,0}, // S_SSWV_RUN2 + {SPR_SSWV,1,3,A_Chase,S_SSWV_RUN4,0,0}, // S_SSWV_RUN3 + {SPR_SSWV,1,3,A_Chase,S_SSWV_RUN5,0,0}, // S_SSWV_RUN4 + {SPR_SSWV,2,3,A_Chase,S_SSWV_RUN6,0,0}, // S_SSWV_RUN5 + {SPR_SSWV,2,3,A_Chase,S_SSWV_RUN7,0,0}, // S_SSWV_RUN6 + {SPR_SSWV,3,3,A_Chase,S_SSWV_RUN8,0,0}, // S_SSWV_RUN7 + {SPR_SSWV,3,3,A_Chase,S_SSWV_RUN1,0,0}, // S_SSWV_RUN8 + {SPR_SSWV,4,10,A_FaceTarget,S_SSWV_ATK2,0,0}, // S_SSWV_ATK1 + {SPR_SSWV,5,10,A_FaceTarget,S_SSWV_ATK3,0,0}, // S_SSWV_ATK2 + {SPR_SSWV,32774,4,A_CPosAttack,S_SSWV_ATK4,0,0}, // S_SSWV_ATK3 + {SPR_SSWV,5,6,A_FaceTarget,S_SSWV_ATK5,0,0}, // S_SSWV_ATK4 + {SPR_SSWV,32774,4,A_CPosAttack,S_SSWV_ATK6,0,0}, // S_SSWV_ATK5 + {SPR_SSWV,5,1,A_CPosRefire,S_SSWV_ATK2,0,0}, // S_SSWV_ATK6 + {SPR_SSWV,7,3,NULL,S_SSWV_PAIN2,0,0}, // S_SSWV_PAIN + {SPR_SSWV,7,3,A_Pain,S_SSWV_RUN1,0,0}, // S_SSWV_PAIN2 + {SPR_SSWV,8,5,NULL,S_SSWV_DIE2,0,0}, // S_SSWV_DIE1 + {SPR_SSWV,9,5,A_Scream,S_SSWV_DIE3,0,0}, // S_SSWV_DIE2 + {SPR_SSWV,10,5,A_Fall,S_SSWV_DIE4,0,0}, // S_SSWV_DIE3 + {SPR_SSWV,11,5,NULL,S_SSWV_DIE5,0,0}, // S_SSWV_DIE4 + {SPR_SSWV,12,-1,NULL,S_NULL,0,0}, // S_SSWV_DIE5 + {SPR_SSWV,13,5,NULL,S_SSWV_XDIE2,0,0}, // S_SSWV_XDIE1 + {SPR_SSWV,14,5,A_XScream,S_SSWV_XDIE3,0,0}, // S_SSWV_XDIE2 + {SPR_SSWV,15,5,A_Fall,S_SSWV_XDIE4,0,0}, // S_SSWV_XDIE3 + {SPR_SSWV,16,5,NULL,S_SSWV_XDIE5,0,0}, // S_SSWV_XDIE4 + {SPR_SSWV,17,5,NULL,S_SSWV_XDIE6,0,0}, // S_SSWV_XDIE5 + {SPR_SSWV,18,5,NULL,S_SSWV_XDIE7,0,0}, // S_SSWV_XDIE6 + {SPR_SSWV,19,5,NULL,S_SSWV_XDIE8,0,0}, // S_SSWV_XDIE7 + {SPR_SSWV,20,5,NULL,S_SSWV_XDIE9,0,0}, // S_SSWV_XDIE8 + {SPR_SSWV,21,-1,NULL,S_NULL,0,0}, // S_SSWV_XDIE9 + {SPR_SSWV,12,5,NULL,S_SSWV_RAISE2,0,0}, // S_SSWV_RAISE1 + {SPR_SSWV,11,5,NULL,S_SSWV_RAISE3,0,0}, // S_SSWV_RAISE2 + {SPR_SSWV,10,5,NULL,S_SSWV_RAISE4,0,0}, // S_SSWV_RAISE3 + {SPR_SSWV,9,5,NULL,S_SSWV_RAISE5,0,0}, // S_SSWV_RAISE4 + {SPR_SSWV,8,5,NULL,S_SSWV_RUN1,0,0}, // S_SSWV_RAISE5 + {SPR_KEEN,0,-1,NULL,S_KEENSTND,0,0}, // S_KEENSTND + {SPR_KEEN,0,6,NULL,S_COMMKEEN2,0,0}, // S_COMMKEEN + {SPR_KEEN,1,6,NULL,S_COMMKEEN3,0,0}, // S_COMMKEEN2 + {SPR_KEEN,2,6,A_Scream,S_COMMKEEN4,0,0}, // S_COMMKEEN3 + {SPR_KEEN,3,6,NULL,S_COMMKEEN5,0,0}, // S_COMMKEEN4 + {SPR_KEEN,4,6,NULL,S_COMMKEEN6,0,0}, // S_COMMKEEN5 + {SPR_KEEN,5,6,NULL,S_COMMKEEN7,0,0}, // S_COMMKEEN6 + {SPR_KEEN,6,6,NULL,S_COMMKEEN8,0,0}, // S_COMMKEEN7 + {SPR_KEEN,7,6,NULL,S_COMMKEEN9,0,0}, // S_COMMKEEN8 + {SPR_KEEN,8,6,NULL,S_COMMKEEN10,0,0}, // S_COMMKEEN9 + {SPR_KEEN,9,6,NULL,S_COMMKEEN11,0,0}, // S_COMMKEEN10 + {SPR_KEEN,10,6,A_KeenDie,S_COMMKEEN12,0,0},// S_COMMKEEN11 + {SPR_KEEN,11,-1,NULL,S_NULL,0,0}, // S_COMMKEEN12 + {SPR_KEEN,12,4,NULL,S_KEENPAIN2,0,0}, // S_KEENPAIN + {SPR_KEEN,12,8,A_Pain,S_KEENSTND,0,0}, // S_KEENPAIN2 + {SPR_BBRN,0,-1,NULL,S_NULL,0,0}, // S_BRAIN + {SPR_BBRN,1,36,A_BrainPain,S_BRAIN,0,0}, // S_BRAIN_PAIN + {SPR_BBRN,0,100,A_BrainScream,S_BRAIN_DIE2,0,0}, // S_BRAIN_DIE1 + {SPR_BBRN,0,10,NULL,S_BRAIN_DIE3,0,0}, // S_BRAIN_DIE2 + {SPR_BBRN,0,10,NULL,S_BRAIN_DIE4,0,0}, // S_BRAIN_DIE3 + {SPR_BBRN,0,-1,A_BrainDie,S_NULL,0,0}, // S_BRAIN_DIE4 + {SPR_SSWV,0,10,A_Look,S_BRAINEYE,0,0}, // S_BRAINEYE + {SPR_SSWV,0,181,A_BrainAwake,S_BRAINEYE1,0,0}, // S_BRAINEYESEE + {SPR_SSWV,0,150,A_BrainSpit,S_BRAINEYE1,0,0}, // S_BRAINEYE1 + {SPR_BOSF,32768,3,A_SpawnSound,S_SPAWN2,0,0}, // S_SPAWN1 + {SPR_BOSF,32769,3,A_SpawnFly,S_SPAWN3,0,0}, // S_SPAWN2 + {SPR_BOSF,32770,3,A_SpawnFly,S_SPAWN4,0,0}, // S_SPAWN3 + {SPR_BOSF,32771,3,A_SpawnFly,S_SPAWN1,0,0}, // S_SPAWN4 + {SPR_FIRE,32768,4,A_Fire,S_SPAWNFIRE2,0,0}, // S_SPAWNFIRE1 + {SPR_FIRE,32769,4,A_Fire,S_SPAWNFIRE3,0,0}, // S_SPAWNFIRE2 + {SPR_FIRE,32770,4,A_Fire,S_SPAWNFIRE4,0,0}, // S_SPAWNFIRE3 + {SPR_FIRE,32771,4,A_Fire,S_SPAWNFIRE5,0,0}, // S_SPAWNFIRE4 + {SPR_FIRE,32772,4,A_Fire,S_SPAWNFIRE6,0,0}, // S_SPAWNFIRE5 + {SPR_FIRE,32773,4,A_Fire,S_SPAWNFIRE7,0,0}, // S_SPAWNFIRE6 + {SPR_FIRE,32774,4,A_Fire,S_SPAWNFIRE8,0,0}, // S_SPAWNFIRE7 + {SPR_FIRE,32775,4,A_Fire,S_NULL,0,0}, // S_SPAWNFIRE8 + {SPR_MISL,32769,10,NULL,S_BRAINEXPLODE2,0,0}, // S_BRAINEXPLODE1 + {SPR_MISL,32770,10,NULL,S_BRAINEXPLODE3,0,0}, // S_BRAINEXPLODE2 + {SPR_MISL,32771,10,A_BrainExplode,S_NULL,0,0}, // S_BRAINEXPLODE3 + {SPR_ARM1,0,6,NULL,S_ARM1A,0,0}, // S_ARM1 + {SPR_ARM1,32769,7,NULL,S_ARM1,0,0}, // S_ARM1A + {SPR_ARM2,0,6,NULL,S_ARM2A,0,0}, // S_ARM2 + {SPR_ARM2,32769,6,NULL,S_ARM2,0,0}, // S_ARM2A + {SPR_BAR1,0,6,NULL,S_BAR2,0,0}, // S_BAR1 + {SPR_BAR1,1,6,NULL,S_BAR1,0,0}, // S_BAR2 + {SPR_BEXP,32768,5,NULL,S_BEXP2,0,0}, // S_BEXP + {SPR_BEXP,32769,5,A_Scream,S_BEXP3,0,0}, // S_BEXP2 + {SPR_BEXP,32770,5,NULL,S_BEXP4,0,0}, // S_BEXP3 + {SPR_BEXP,32771,10,A_Explode,S_BEXP5,0,0}, // S_BEXP4 + {SPR_BEXP,32772,10,NULL,S_NULL,0,0}, // S_BEXP5 + {SPR_FCAN,32768,4,NULL,S_BBAR2,0,0}, // S_BBAR1 + {SPR_FCAN,32769,4,NULL,S_BBAR3,0,0}, // S_BBAR2 + {SPR_FCAN,32770,4,NULL,S_BBAR1,0,0}, // S_BBAR3 + {SPR_BON1,0,6,NULL,S_BON1A,0,0}, // S_BON1 + {SPR_BON1,1,6,NULL,S_BON1B,0,0}, // S_BON1A + {SPR_BON1,2,6,NULL,S_BON1C,0,0}, // S_BON1B + {SPR_BON1,3,6,NULL,S_BON1D,0,0}, // S_BON1C + {SPR_BON1,2,6,NULL,S_BON1E,0,0}, // S_BON1D + {SPR_BON1,1,6,NULL,S_BON1,0,0}, // S_BON1E + {SPR_BON2,0,6,NULL,S_BON2A,0,0}, // S_BON2 + {SPR_BON2,1,6,NULL,S_BON2B,0,0}, // S_BON2A + {SPR_BON2,2,6,NULL,S_BON2C,0,0}, // S_BON2B + {SPR_BON2,3,6,NULL,S_BON2D,0,0}, // S_BON2C + {SPR_BON2,2,6,NULL,S_BON2E,0,0}, // S_BON2D + {SPR_BON2,1,6,NULL,S_BON2,0,0}, // S_BON2E + {SPR_BKEY,0,10,NULL,S_BKEY2,0,0}, // S_BKEY + {SPR_BKEY,32769,10,NULL,S_BKEY,0,0}, // S_BKEY2 + {SPR_RKEY,0,10,NULL,S_RKEY2,0,0}, // S_RKEY + {SPR_RKEY,32769,10,NULL,S_RKEY,0,0}, // S_RKEY2 + {SPR_YKEY,0,10,NULL,S_YKEY2,0,0}, // S_YKEY + {SPR_YKEY,32769,10,NULL,S_YKEY,0,0}, // S_YKEY2 + {SPR_BSKU,0,10,NULL,S_BSKULL2,0,0}, // S_BSKULL + {SPR_BSKU,32769,10,NULL,S_BSKULL,0,0}, // S_BSKULL2 + {SPR_RSKU,0,10,NULL,S_RSKULL2,0,0}, // S_RSKULL + {SPR_RSKU,32769,10,NULL,S_RSKULL,0,0}, // S_RSKULL2 + {SPR_YSKU,0,10,NULL,S_YSKULL2,0,0}, // S_YSKULL + {SPR_YSKU,32769,10,NULL,S_YSKULL,0,0}, // S_YSKULL2 + {SPR_STIM,0,-1,NULL,S_NULL,0,0}, // S_STIM + {SPR_MEDI,0,-1,NULL,S_NULL,0,0}, // S_MEDI + {SPR_SOUL,32768,6,NULL,S_SOUL2,0,0}, // S_SOUL + {SPR_SOUL,32769,6,NULL,S_SOUL3,0,0}, // S_SOUL2 + {SPR_SOUL,32770,6,NULL,S_SOUL4,0,0}, // S_SOUL3 + {SPR_SOUL,32771,6,NULL,S_SOUL5,0,0}, // S_SOUL4 + {SPR_SOUL,32770,6,NULL,S_SOUL6,0,0}, // S_SOUL5 + {SPR_SOUL,32769,6,NULL,S_SOUL,0,0}, // S_SOUL6 + {SPR_PINV,32768,6,NULL,S_PINV2,0,0}, // S_PINV + {SPR_PINV,32769,6,NULL,S_PINV3,0,0}, // S_PINV2 + {SPR_PINV,32770,6,NULL,S_PINV4,0,0}, // S_PINV3 + {SPR_PINV,32771,6,NULL,S_PINV,0,0}, // S_PINV4 + {SPR_PSTR,32768,-1,NULL,S_NULL,0,0}, // S_PSTR + {SPR_PINS,32768,6,NULL,S_PINS2,0,0}, // S_PINS + {SPR_PINS,32769,6,NULL,S_PINS3,0,0}, // S_PINS2 + {SPR_PINS,32770,6,NULL,S_PINS4,0,0}, // S_PINS3 + {SPR_PINS,32771,6,NULL,S_PINS,0,0}, // S_PINS4 + {SPR_MEGA,32768,6,NULL,S_MEGA2,0,0}, // S_MEGA + {SPR_MEGA,32769,6,NULL,S_MEGA3,0,0}, // S_MEGA2 + {SPR_MEGA,32770,6,NULL,S_MEGA4,0,0}, // S_MEGA3 + {SPR_MEGA,32771,6,NULL,S_MEGA,0,0}, // S_MEGA4 + {SPR_SUIT,32768,-1,NULL,S_NULL,0,0}, // S_SUIT + {SPR_PMAP,32768,6,NULL,S_PMAP2,0,0}, // S_PMAP + {SPR_PMAP,32769,6,NULL,S_PMAP3,0,0}, // S_PMAP2 + {SPR_PMAP,32770,6,NULL,S_PMAP4,0,0}, // S_PMAP3 + {SPR_PMAP,32771,6,NULL,S_PMAP5,0,0}, // S_PMAP4 + {SPR_PMAP,32770,6,NULL,S_PMAP6,0,0}, // S_PMAP5 + {SPR_PMAP,32769,6,NULL,S_PMAP,0,0}, // S_PMAP6 + {SPR_PVIS,32768,6,NULL,S_PVIS2,0,0}, // S_PVIS + {SPR_PVIS,1,6,NULL,S_PVIS,0,0}, // S_PVIS2 + {SPR_CLIP,0,-1,NULL,S_NULL,0,0}, // S_CLIP + {SPR_AMMO,0,-1,NULL,S_NULL,0,0}, // S_AMMO + {SPR_ROCK,0,-1,NULL,S_NULL,0,0}, // S_ROCK + {SPR_BROK,0,-1,NULL,S_NULL,0,0}, // S_BROK + {SPR_CELL,0,-1,NULL,S_NULL,0,0}, // S_CELL + {SPR_CELP,0,-1,NULL,S_NULL,0,0}, // S_CELP + {SPR_SHEL,0,-1,NULL,S_NULL,0,0}, // S_SHEL + {SPR_SBOX,0,-1,NULL,S_NULL,0,0}, // S_SBOX + {SPR_BPAK,0,-1,NULL,S_NULL,0,0}, // S_BPAK + {SPR_BFUG,0,-1,NULL,S_NULL,0,0}, // S_BFUG + {SPR_MGUN,0,-1,NULL,S_NULL,0,0}, // S_MGUN + {SPR_CSAW,0,-1,NULL,S_NULL,0,0}, // S_CSAW + {SPR_LAUN,0,-1,NULL,S_NULL,0,0}, // S_LAUN + {SPR_PLAS,0,-1,NULL,S_NULL,0,0}, // S_PLAS + {SPR_SHOT,0,-1,NULL,S_NULL,0,0}, // S_SHOT + {SPR_SGN2,0,-1,NULL,S_NULL,0,0}, // S_SHOT2 + {SPR_COLU,32768,-1,NULL,S_NULL,0,0}, // S_COLU + {SPR_SMT2,0,-1,NULL,S_NULL,0,0}, // S_STALAG + {SPR_GOR1,0,10,NULL,S_BLOODYTWITCH2,0,0}, // S_BLOODYTWITCH + {SPR_GOR1,1,15,NULL,S_BLOODYTWITCH3,0,0}, // S_BLOODYTWITCH2 + {SPR_GOR1,2,8,NULL,S_BLOODYTWITCH4,0,0}, // S_BLOODYTWITCH3 + {SPR_GOR1,1,6,NULL,S_BLOODYTWITCH,0,0}, // S_BLOODYTWITCH4 + {SPR_PLAY,13,-1,NULL,S_NULL,0,0}, // S_DEADTORSO + {SPR_PLAY,18,-1,NULL,S_NULL,0,0}, // S_DEADBOTTOM + {SPR_POL2,0,-1,NULL,S_NULL,0,0}, // S_HEADSONSTICK + {SPR_POL5,0,-1,NULL,S_NULL,0,0}, // S_GIBS + {SPR_POL4,0,-1,NULL,S_NULL,0,0}, // S_HEADONASTICK + {SPR_POL3,32768,6,NULL,S_HEADCANDLES2,0,0}, // S_HEADCANDLES + {SPR_POL3,32769,6,NULL,S_HEADCANDLES,0,0}, // S_HEADCANDLES2 + {SPR_POL1,0,-1,NULL,S_NULL,0,0}, // S_DEADSTICK + {SPR_POL6,0,6,NULL,S_LIVESTICK2,0,0}, // S_LIVESTICK + {SPR_POL6,1,8,NULL,S_LIVESTICK,0,0}, // S_LIVESTICK2 + {SPR_GOR2,0,-1,NULL,S_NULL,0,0}, // S_MEAT2 + {SPR_GOR3,0,-1,NULL,S_NULL,0,0}, // S_MEAT3 + {SPR_GOR4,0,-1,NULL,S_NULL,0,0}, // S_MEAT4 + {SPR_GOR5,0,-1,NULL,S_NULL,0,0}, // S_MEAT5 + {SPR_SMIT,0,-1,NULL,S_NULL,0,0}, // S_STALAGTITE + {SPR_COL1,0,-1,NULL,S_NULL,0,0}, // S_TALLGRNCOL + {SPR_COL2,0,-1,NULL,S_NULL,0,0}, // S_SHRTGRNCOL + {SPR_COL3,0,-1,NULL,S_NULL,0,0}, // S_TALLREDCOL + {SPR_COL4,0,-1,NULL,S_NULL,0,0}, // S_SHRTREDCOL + {SPR_CAND,32768,-1,NULL,S_NULL,0,0}, // S_CANDLESTIK + {SPR_CBRA,32768,-1,NULL,S_NULL,0,0}, // S_CANDELABRA + {SPR_COL6,0,-1,NULL,S_NULL,0,0}, // S_SKULLCOL + {SPR_TRE1,0,-1,NULL,S_NULL,0,0}, // S_TORCHTREE + {SPR_TRE2,0,-1,NULL,S_NULL,0,0}, // S_BIGTREE + {SPR_ELEC,0,-1,NULL,S_NULL,0,0}, // S_TECHPILLAR + {SPR_CEYE,32768,6,NULL,S_EVILEYE2,0,0}, // S_EVILEYE + {SPR_CEYE,32769,6,NULL,S_EVILEYE3,0,0}, // S_EVILEYE2 + {SPR_CEYE,32770,6,NULL,S_EVILEYE4,0,0}, // S_EVILEYE3 + {SPR_CEYE,32769,6,NULL,S_EVILEYE,0,0}, // S_EVILEYE4 + {SPR_FSKU,32768,6,NULL,S_FLOATSKULL2,0,0}, // S_FLOATSKULL + {SPR_FSKU,32769,6,NULL,S_FLOATSKULL3,0,0}, // S_FLOATSKULL2 + {SPR_FSKU,32770,6,NULL,S_FLOATSKULL,0,0}, // S_FLOATSKULL3 + {SPR_COL5,0,14,NULL,S_HEARTCOL2,0,0}, // S_HEARTCOL + {SPR_COL5,1,14,NULL,S_HEARTCOL,0,0}, // S_HEARTCOL2 + {SPR_TBLU,32768,4,NULL,S_BLUETORCH2,0,0}, // S_BLUETORCH + {SPR_TBLU,32769,4,NULL,S_BLUETORCH3,0,0}, // S_BLUETORCH2 + {SPR_TBLU,32770,4,NULL,S_BLUETORCH4,0,0}, // S_BLUETORCH3 + {SPR_TBLU,32771,4,NULL,S_BLUETORCH,0,0}, // S_BLUETORCH4 + {SPR_TGRN,32768,4,NULL,S_GREENTORCH2,0,0}, // S_GREENTORCH + {SPR_TGRN,32769,4,NULL,S_GREENTORCH3,0,0}, // S_GREENTORCH2 + {SPR_TGRN,32770,4,NULL,S_GREENTORCH4,0,0}, // S_GREENTORCH3 + {SPR_TGRN,32771,4,NULL,S_GREENTORCH,0,0}, // S_GREENTORCH4 + {SPR_TRED,32768,4,NULL,S_REDTORCH2,0,0}, // S_REDTORCH + {SPR_TRED,32769,4,NULL,S_REDTORCH3,0,0}, // S_REDTORCH2 + {SPR_TRED,32770,4,NULL,S_REDTORCH4,0,0}, // S_REDTORCH3 + {SPR_TRED,32771,4,NULL,S_REDTORCH,0,0}, // S_REDTORCH4 + {SPR_SMBT,32768,4,NULL,S_BTORCHSHRT2,0,0}, // S_BTORCHSHRT + {SPR_SMBT,32769,4,NULL,S_BTORCHSHRT3,0,0}, // S_BTORCHSHRT2 + {SPR_SMBT,32770,4,NULL,S_BTORCHSHRT4,0,0}, // S_BTORCHSHRT3 + {SPR_SMBT,32771,4,NULL,S_BTORCHSHRT,0,0}, // S_BTORCHSHRT4 + {SPR_SMGT,32768,4,NULL,S_GTORCHSHRT2,0,0}, // S_GTORCHSHRT + {SPR_SMGT,32769,4,NULL,S_GTORCHSHRT3,0,0}, // S_GTORCHSHRT2 + {SPR_SMGT,32770,4,NULL,S_GTORCHSHRT4,0,0}, // S_GTORCHSHRT3 + {SPR_SMGT,32771,4,NULL,S_GTORCHSHRT,0,0}, // S_GTORCHSHRT4 + {SPR_SMRT,32768,4,NULL,S_RTORCHSHRT2,0,0}, // S_RTORCHSHRT + {SPR_SMRT,32769,4,NULL,S_RTORCHSHRT3,0,0}, // S_RTORCHSHRT2 + {SPR_SMRT,32770,4,NULL,S_RTORCHSHRT4,0,0}, // S_RTORCHSHRT3 + {SPR_SMRT,32771,4,NULL,S_RTORCHSHRT,0,0}, // S_RTORCHSHRT4 + {SPR_HDB1,0,-1,NULL,S_NULL,0,0}, // S_HANGNOGUTS + {SPR_HDB2,0,-1,NULL,S_NULL,0,0}, // S_HANGBNOBRAIN + {SPR_HDB3,0,-1,NULL,S_NULL,0,0}, // S_HANGTLOOKDN + {SPR_HDB4,0,-1,NULL,S_NULL,0,0}, // S_HANGTSKULL + {SPR_HDB5,0,-1,NULL,S_NULL,0,0}, // S_HANGTLOOKUP + {SPR_HDB6,0,-1,NULL,S_NULL,0,0}, // S_HANGTNOBRAIN + {SPR_POB1,0,-1,NULL,S_NULL,0,0}, // S_COLONGIBS + {SPR_POB2,0,-1,NULL,S_NULL,0,0}, // S_SMALLPOOL + {SPR_BRS1,0,-1,NULL,S_NULL,0,0}, // S_BRAINSTEM + {SPR_TLMP,32768,4,NULL,S_TECHLAMP2,0,0}, // S_TECHLAMP + {SPR_TLMP,32769,4,NULL,S_TECHLAMP3,0,0}, // S_TECHLAMP2 + {SPR_TLMP,32770,4,NULL,S_TECHLAMP4,0,0}, // S_TECHLAMP3 + {SPR_TLMP,32771,4,NULL,S_TECHLAMP,0,0}, // S_TECHLAMP4 + {SPR_TLP2,32768,4,NULL,S_TECH2LAMP2,0,0}, // S_TECH2LAMP + {SPR_TLP2,32769,4,NULL,S_TECH2LAMP3,0,0}, // S_TECH2LAMP2 + {SPR_TLP2,32770,4,NULL,S_TECH2LAMP4,0,0}, // S_TECH2LAMP3 + {SPR_TLP2,32771,4,NULL,S_TECH2LAMP,0,0}, // S_TECH2LAMP4 + {SPR_TNT1,0,-1,NULL,S_TNT1,0,0}, // S_TNT1 // phares 3/8/98 + + // killough 8/9/98: grenade + {SPR_MISL,32768,1000,A_Die,S_GRENADE,0,0}, // S_GRENADE + + // killough 8/10/98: variable damage explosion + {SPR_MISL,32769,4,A_Scream,S_DETONATE2,0,0}, // S_DETONATE + {SPR_MISL,32770,6,A_Detonate,S_DETONATE3,0,0}, // S_DETONATE2 + {SPR_MISL,32771,10,NULL,S_NULL,0,0}, // S_DETONATE3 + +#ifdef DOGS + // killough 7/19/98: Marine's best friend :) + {SPR_DOGS,0,10,A_Look,S_DOGS_STND2}, // S_DOGS_STND + {SPR_DOGS,1,10,A_Look,S_DOGS_STND}, // S_DOGS_STND2 + {SPR_DOGS,0,2,A_Chase,S_DOGS_RUN2}, // S_DOGS_RUN1 + {SPR_DOGS,0,2,A_Chase,S_DOGS_RUN3}, // S_DOGS_RUN2 + {SPR_DOGS,1,2,A_Chase,S_DOGS_RUN4}, // S_DOGS_RUN3 + {SPR_DOGS,1,2,A_Chase,S_DOGS_RUN5}, // S_DOGS_RUN4 + {SPR_DOGS,2,2,A_Chase,S_DOGS_RUN6}, // S_DOGS_RUN5 + {SPR_DOGS,2,2,A_Chase,S_DOGS_RUN7}, // S_DOGS_RUN6 + {SPR_DOGS,3,2,A_Chase,S_DOGS_RUN8}, // S_DOGS_RUN7 + {SPR_DOGS,3,2,A_Chase,S_DOGS_RUN1}, // S_DOGS_RUN8 + {SPR_DOGS,4,8,A_FaceTarget,S_DOGS_ATK2}, // S_DOGS_ATK1 + {SPR_DOGS,5,8,A_FaceTarget,S_DOGS_ATK3}, // S_DOGS_ATK2 + {SPR_DOGS,6,8,A_SargAttack,S_DOGS_RUN1}, // S_DOGS_ATK3 + {SPR_DOGS,7,2,NULL,S_DOGS_PAIN2}, // S_DOGS_PAIN + {SPR_DOGS,7,2,A_Pain,S_DOGS_RUN1}, // S_DOGS_PAIN2 + {SPR_DOGS,8,8,NULL,S_DOGS_DIE2}, // S_DOGS_DIE1 + {SPR_DOGS,9,8,A_Scream,S_DOGS_DIE3}, // S_DOGS_DIE2 + {SPR_DOGS,10,4,NULL,S_DOGS_DIE4}, // S_DOGS_DIE3 + {SPR_DOGS,11,4,A_Fall,S_DOGS_DIE5}, // S_DOGS_DIE4 + {SPR_DOGS,12,4,NULL,S_DOGS_DIE6}, // S_DOGS_DIE5 + {SPR_DOGS,13,-1,NULL,S_NULL}, // S_DOGS_DIE6 + {SPR_DOGS,13,5,NULL,S_DOGS_RAISE2}, // S_DOGS_RAISE1 + {SPR_DOGS,12,5,NULL,S_DOGS_RAISE3}, // S_DOGS_RAISE2 + {SPR_DOGS,11,5,NULL,S_DOGS_RAISE4}, // S_DOGS_RAISE3 + {SPR_DOGS,10,5,NULL,S_DOGS_RAISE5}, // S_DOGS_RAISE4 + {SPR_DOGS,9,5,NULL,S_DOGS_RAISE6}, // S_DOGS_RAISE5 + {SPR_DOGS,8,5,NULL,S_DOGS_RUN1}, // S_DOGS_RAISE6 +#else + // if dogs are disabled, dummy states are required for dehacked compatibility + {0,0,-1,NULL,S_NULL,0,0}, // S_DOGS_STND + {0,0,-1,NULL,S_NULL,0,0}, // S_DOGS_STND2 + {0,0,-1,NULL,S_NULL,0,0}, // S_DOGS_RUN1 + {0,0,-1,NULL,S_NULL,0,0}, // S_DOGS_RUN2 + {0,0,-1,NULL,S_NULL,0,0}, // S_DOGS_RUN3 + {0,0,-1,NULL,S_NULL,0,0}, // S_DOGS_RUN4 + {0,0,-1,NULL,S_NULL,0,0}, // S_DOGS_RUN5 + {0,0,-1,NULL,S_NULL,0,0}, // S_DOGS_RUN6 + {0,0,-1,NULL,S_NULL,0,0}, // S_DOGS_RUN7 + {0,0,-1,NULL,S_NULL,0,0}, // S_DOGS_RUN8 + {0,0,-1,NULL,S_NULL,0,0}, // S_DOGS_ATK1 + {0,0,-1,NULL,S_NULL,0,0}, // S_DOGS_ATK2 + {0,0,-1,NULL,S_NULL,0,0}, // S_DOGS_ATK3 + {0,0,-1,NULL,S_NULL,0,0}, // S_DOGS_PAIN + {0,0,-1,NULL,S_NULL,0,0}, // S_DOGS_PAIN2 + {0,0,-1,NULL,S_NULL,0,0}, // S_DOGS_DIE1 + {0,0,-1,NULL,S_NULL,0,0}, // S_DOGS_DIE2 + {0,0,-1,NULL,S_NULL,0,0}, // S_DOGS_DIE3 + {0,0,-1,NULL,S_NULL,0,0}, // S_DOGS_DIE4 + {0,0,-1,NULL,S_NULL,0,0}, // S_DOGS_DIE5 + {0,0,-1,NULL,S_NULL,0,0}, // S_DOGS_DIE6 + {0,0,-1,NULL,S_NULL,0,0}, // S_DOGS_RAISE1 + {0,0,-1,NULL,S_NULL,0,0}, // S_DOGS_RAISE2 + {0,0,-1,NULL,S_NULL,0,0}, // S_DOGS_RAISE3 + {0,0,-1,NULL,S_NULL,0,0}, // S_DOGS_RAISE4 + {0,0,-1,NULL,S_NULL,0,0}, // S_DOGS_RAISE5 + {0,0,-1,NULL,S_NULL,0,0}, // S_DOGS_RAISE6 +#endif + + // add dummy beta bfg / lost soul frames for dehacked compatibility + // fixes bug #1576151 (part 2) + {0,0,-1,NULL,S_NULL,0,0}, // S_OLDBFG1 + {0,0,-1,NULL,S_NULL,0,0}, // S_OLDBFG2 + {0,0,-1,NULL,S_NULL,0,0}, // S_OLDBFG3 + {0,0,-1,NULL,S_NULL,0,0}, // S_OLDBFG4 + {0,0,-1,NULL,S_NULL,0,0}, // S_OLDBFG5 + {0,0,-1,NULL,S_NULL,0,0}, // S_OLDBFG6 + {0,0,-1,NULL,S_NULL,0,0}, // S_OLDBFG7 + {0,0,-1,NULL,S_NULL,0,0}, // S_OLDBFG8 + {0,0,-1,NULL,S_NULL,0,0}, // S_OLDBFG9 + {0,0,-1,NULL,S_NULL,0,0}, // S_OLDBFG10 + {0,0,-1,NULL,S_NULL,0,0}, // S_OLDBFG11 + {0,0,-1,NULL,S_NULL,0,0}, // S_OLDBFG12 + {0,0,-1,NULL,S_NULL,0,0}, // S_OLDBFG13 + {0,0,-1,NULL,S_NULL,0,0}, // S_OLDBFG14 + {0,0,-1,NULL,S_NULL,0,0}, // S_OLDBFG15 + {0,0,-1,NULL,S_NULL,0,0}, // S_OLDBFG16 + {0,0,-1,NULL,S_NULL,0,0}, // S_OLDBFG17 + {0,0,-1,NULL,S_NULL,0,0}, // S_OLDBFG18 + {0,0,-1,NULL,S_NULL,0,0}, // S_OLDBFG19 + {0,0,-1,NULL,S_NULL,0,0}, // S_OLDBFG20 + {0,0,-1,NULL,S_NULL,0,0}, // S_OLDBFG21 + {0,0,-1,NULL,S_NULL,0,0}, // S_OLDBFG22 + {0,0,-1,NULL,S_NULL,0,0}, // S_OLDBFG23 + {0,0,-1,NULL,S_NULL,0,0}, // S_OLDBFG24 + {0,0,-1,NULL,S_NULL,0,0}, // S_OLDBFG25 + {0,0,-1,NULL,S_NULL,0,0}, // S_OLDBFG26 + {0,0,-1,NULL,S_NULL,0,0}, // S_OLDBFG27 + {0,0,-1,NULL,S_NULL,0,0}, // S_OLDBFG28 + {0,0,-1,NULL,S_NULL,0,0}, // S_OLDBFG29 + {0,0,-1,NULL,S_NULL,0,0}, // S_OLDBFG30 + {0,0,-1,NULL,S_NULL,0,0}, // S_OLDBFG31 + {0,0,-1,NULL,S_NULL,0,0}, // S_OLDBFG32 + {0,0,-1,NULL,S_NULL,0,0}, // S_OLDBFG33 + {0,0,-1,NULL,S_NULL,0,0}, // S_OLDBFG34 + {0,0,-1,NULL,S_NULL,0,0}, // S_OLDBFG35 + {0,0,-1,NULL,S_NULL,0,0}, // S_OLDBFG36 + {0,0,-1,NULL,S_NULL,0,0}, // S_OLDBFG37 + {0,0,-1,NULL,S_NULL,0,0}, // S_OLDBFG38 + {0,0,-1,NULL,S_NULL,0,0}, // S_OLDBFG39 + {0,0,-1,NULL,S_NULL,0,0}, // S_OLDBFG40 + {0,0,-1,NULL,S_NULL,0,0}, // S_OLDBFG41 + {0,0,-1,NULL,S_NULL,0,0}, // S_OLDBFG42 + {0,0,-1,NULL,S_NULL,0,0}, // S_OLDBFG43 + + {0,0,-1,NULL,S_NULL,0,0}, // S_PLS1BALL + {0,0,-1,NULL,S_NULL,0,0}, // S_PLS1BALL2 + {0,0,-1,NULL,S_NULL,0,0}, // S_PLS1EXP + {0,0,-1,NULL,S_NULL,0,0}, // S_PLS1EXP2 + {0,0,-1,NULL,S_NULL,0,0}, // S_PLS1EXP3 + {0,0,-1,NULL,S_NULL,0,0}, // S_PLS1EXP4 + {0,0,-1,NULL,S_NULL,0,0}, // S_PLS1EXP5 + + {0,0,-1,NULL,S_NULL,0,0}, // S_PLS2BALL + {0,0,-1,NULL,S_NULL,0,0}, // S_PLS2BALL2 + {0,0,-1,NULL,S_NULL,0,0}, // S_PLS2BALLX1 + {0,0,-1,NULL,S_NULL,0,0}, // S_PLS2BALLX2 + {0,0,-1,NULL,S_NULL,0,0}, // S_PLS2BALLX3 + + {0,0,-1,NULL,S_NULL,0,0}, // S_BON3 + {0,0,-1,NULL,S_NULL,0,0}, // S_BON4 + + {0,0,-1,NULL,S_NULL,0,0}, // S_BSKUL_STND + {0,0,-1,NULL,S_NULL,0,0}, // S_BSKUL_RUN1 + {0,0,-1,NULL,S_NULL,0,0}, // S_BSKUL_RUN2 + {0,0,-1,NULL,S_NULL,0,0}, // S_BSKUL_RUN3 + {0,0,-1,NULL,S_NULL,0,0}, // S_BSKUL_RUN4 + {0,0,-1,NULL,S_NULL,0,0}, // S_BSKUL_ATK1 + {0,0,-1,NULL,S_NULL,0,0}, // S_BSKUL_ATK2 + {0,0,-1,NULL,S_NULL,0,0}, // S_BSKUL_ATK3 + {0,0,-1,NULL,S_NULL,0,0}, // S_BSKUL_PAIN1 + {0,0,-1,NULL,S_NULL,0,0}, // S_BSKUL_PAIN2 + {0,0,-1,NULL,S_NULL,0,0}, // S_BSKUL_PAIN3 + {0,0,-1,NULL,S_NULL,0,0}, // S_BSKUL_DIE1 + {0,0,-1,NULL,S_NULL,0,0}, // S_BSKUL_DIE2 + {0,0,-1,NULL,S_NULL,0,0}, // S_BSKUL_DIE3 + {0,0,-1,NULL,S_NULL,0,0}, // S_BSKUL_DIE4 + {0,0,-1,NULL,S_NULL,0,0}, // S_BSKUL_DIE5 + {0,0,-1,NULL,S_NULL,0,0}, // S_BSKUL_DIE6 + {0,0,-1,NULL,S_NULL,0,0}, // S_BSKUL_DIE7 + {0,0,-1,NULL,S_NULL,0,0}, // S_BSKUL_DIE8 + + // killough 10/98: mushroom effect + {SPR_MISL,32769,8,A_Mushroom,S_EXPLODE2,0,0}, // S_MUSHROOM +}; + +// ******************************************************************** +// Object "Thing" definitions +// ******************************************************************** +// Now we get to the actual objects and their characteristics. If +// you've seen Dehacked, much of this is where the Bits are set, +// commented below as "flags", as well as where you wire in which +// frames are the beginning frames for near and far attack, death, +// and such. Sounds are hooked in here too, as well as how much +// mass, speed and so forth a Thing has. Everything you ever wanted +// to know... +// +// Like all this other stuff, the MT_* entries are enumerated in info.h +// +// Note that these are all just indices of the elements involved, and +// not real pointers to them. For example, the player's death sequence +// is S_PLAY_DIE1, which just evaluates to the index in the states[] +// array above, which actually knows what happens then and what the +// sprite looks like, if it makes noise or not, etc. +// +// Additional comments about each of the entries are located in info.h +// next to the mobjinfo_t structure definition. +// +// This goes on for the next 3000+ lines... + +mobjinfo_t mobjinfo[NUMMOBJTYPES] = { + { // MT_PLAYER + -1, // doomednum + S_PLAY, // spawnstate + 100, // spawnhealth + S_PLAY_RUN1, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_PLAY_PAIN, // painstate + 255, // painchance + sfx_plpain, // painsound + S_NULL, // meleestate + S_PLAY_ATK1, // missilestate + S_PLAY_DIE1, // deathstate + S_PLAY_XDIE1, // xdeathstate + sfx_pldeth, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 56*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SHOOTABLE|MF_DROPOFF|MF_PICKUP|MF_NOTDMATCH, // flags + S_NULL // raisestate + }, + + { // MT_POSSESSED + 3004, // doomednum + S_POSS_STND, // spawnstate + 20, // spawnhealth + S_POSS_RUN1, // seestate + sfx_posit1, // seesound + 8, // reactiontime + sfx_pistol, // attacksound + S_POSS_PAIN, // painstate + 200, // painchance + sfx_popain, // painsound + 0, // meleestate + S_POSS_ATK1, // missilestate + S_POSS_DIE1, // deathstate + S_POSS_XDIE1, // xdeathstate + sfx_podth1, // deathsound + 8, // speed + 20*FRACUNIT, // radius + 56*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_posact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags + S_POSS_RAISE1 // raisestate + }, + + { // MT_SHOTGUY + 9, // doomednum + S_SPOS_STND, // spawnstate + 30, // spawnhealth + S_SPOS_RUN1, // seestate + sfx_posit2, // seesound + 8, // reactiontime + 0, // attacksound + S_SPOS_PAIN, // painstate + 170, // painchance + sfx_popain, // painsound + 0, // meleestate + S_SPOS_ATK1, // missilestate + S_SPOS_DIE1, // deathstate + S_SPOS_XDIE1, // xdeathstate + sfx_podth2, // deathsound + 8, // speed + 20*FRACUNIT, // radius + 56*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_posact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags + S_SPOS_RAISE1 // raisestate + }, + + { // MT_VILE + 64, // doomednum + S_VILE_STND, // spawnstate + 700, // spawnhealth + S_VILE_RUN1, // seestate + sfx_vilsit, // seesound + 8, // reactiontime + 0, // attacksound + S_VILE_PAIN, // painstate + 10, // painchance + sfx_vipain, // painsound + 0, // meleestate + S_VILE_ATK1, // missilestate + S_VILE_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_vildth, // deathsound + 15, // speed + 20*FRACUNIT, // radius + 56*FRACUNIT, // height + 500, // mass + 0, // damage + sfx_vilact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags + S_NULL // raisestate + }, + + { // MT_FIRE + -1, // doomednum + S_FIRE1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_TRANSLUCENT, // flags // killough 2/21/98 + S_NULL // raisestate + }, + + { // MT_UNDEAD + 66, // doomednum + S_SKEL_STND, // spawnstate + 300, // spawnhealth + S_SKEL_RUN1, // seestate + sfx_skesit, // seesound + 8, // reactiontime + 0, // attacksound + S_SKEL_PAIN, // painstate + 100, // painchance + sfx_popain, // painsound + S_SKEL_FIST1, // meleestate + S_SKEL_MISS1, // missilestate + S_SKEL_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_skedth, // deathsound + 10, // speed + 20*FRACUNIT, // radius + 56*FRACUNIT, // height + 500, // mass + 0, // damage + sfx_skeact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags + S_SKEL_RAISE1 // raisestate + }, + + { // MT_TRACER + -1, // doomednum + S_TRACER, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_skeatk, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_TRACEEXP1, // deathstate + S_NULL, // xdeathstate + sfx_barexp, // deathsound + 10*FRACUNIT, // speed + 11*FRACUNIT, // radius + 8*FRACUNIT, // height + 100, // mass + 10, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_SMOKE + -1, // doomednum + S_SMOKE1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_TRANSLUCENT, // flags // phares + S_NULL // raisestate + }, + + { // MT_FATSO + 67, // doomednum + S_FATT_STND, // spawnstate + 600, // spawnhealth + S_FATT_RUN1, // seestate + sfx_mansit, // seesound + 8, // reactiontime + 0, // attacksound + S_FATT_PAIN, // painstate + 80, // painchance + sfx_mnpain, // painsound + 0, // meleestate + S_FATT_ATK1, // missilestate + S_FATT_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_mandth, // deathsound + 8, // speed + 48*FRACUNIT, // radius + 64*FRACUNIT, // height + 1000, // mass + 0, // damage + sfx_posact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags + S_FATT_RAISE1 // raisestate + }, + + { // MT_FATSHOT + -1, // doomednum + S_FATSHOT1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_firsht, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_FATSHOTX1, // deathstate + S_NULL, // xdeathstate + sfx_firxpl, // deathsound + 20*FRACUNIT, // speed + 6*FRACUNIT, // radius + 8*FRACUNIT, // height + 100, // mass + 8, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY|MF_TRANSLUCENT, // flags \\ killough 2/21/98 + S_NULL // raisestate + }, + + { // MT_CHAINGUY + 65, // doomednum + S_CPOS_STND, // spawnstate + 70, // spawnhealth + S_CPOS_RUN1, // seestate + sfx_posit2, // seesound + 8, // reactiontime + 0, // attacksound + S_CPOS_PAIN, // painstate + 170, // painchance + sfx_popain, // painsound + 0, // meleestate + S_CPOS_ATK1, // missilestate + S_CPOS_DIE1, // deathstate + S_CPOS_XDIE1, // xdeathstate + sfx_podth2, // deathsound + 8, // speed + 20*FRACUNIT, // radius + 56*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_posact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags + S_CPOS_RAISE1 // raisestate + }, + + { // MT_TROOP + 3001, // doomednum + S_TROO_STND, // spawnstate + 60, // spawnhealth + S_TROO_RUN1, // seestate + sfx_bgsit1, // seesound + 8, // reactiontime + 0, // attacksound + S_TROO_PAIN, // painstate + 200, // painchance + sfx_popain, // painsound + S_TROO_ATK1, // meleestate + S_TROO_ATK1, // missilestate + S_TROO_DIE1, // deathstate + S_TROO_XDIE1, // xdeathstate + sfx_bgdth1, // deathsound + 8, // speed + 20*FRACUNIT, // radius + 56*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_bgact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // killough |MF_TRANSLUCENT, // flags // phares + S_TROO_RAISE1 // raisestate + }, + + { // MT_SERGEANT + 3002, // doomednum + S_SARG_STND, // spawnstate + 150, // spawnhealth + S_SARG_RUN1, // seestate + sfx_sgtsit, // seesound + 8, // reactiontime + sfx_sgtatk, // attacksound + S_SARG_PAIN, // painstate + 180, // painchance + sfx_dmpain, // painsound + S_SARG_ATK1, // meleestate + 0, // missilestate + S_SARG_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_sgtdth, // deathsound + 10, // speed + 30*FRACUNIT, // radius + 56*FRACUNIT, // height + 400, // mass + 0, // damage + sfx_dmact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags + S_SARG_RAISE1 // raisestate + }, + + { // MT_SHADOWS + 58, // doomednum + S_SARG_STND, // spawnstate + 150, // spawnhealth + S_SARG_RUN1, // seestate + sfx_sgtsit, // seesound + 8, // reactiontime + sfx_sgtatk, // attacksound + S_SARG_PAIN, // painstate + 180, // painchance + sfx_dmpain, // painsound + S_SARG_ATK1, // meleestate + 0, // missilestate + S_SARG_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_sgtdth, // deathsound + 10, // speed + 30*FRACUNIT, // radius + 56*FRACUNIT, // height + 400, // mass + 0, // damage + sfx_dmact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_SHADOW|MF_COUNTKILL, // flags + S_SARG_RAISE1 // raisestate + }, + + { // MT_HEAD + 3005, // doomednum + S_HEAD_STND, // spawnstate + 400, // spawnhealth + S_HEAD_RUN1, // seestate + sfx_cacsit, // seesound + 8, // reactiontime + 0, // attacksound + S_HEAD_PAIN, // painstate + 128, // painchance + sfx_dmpain, // painsound + 0, // meleestate + S_HEAD_ATK1, // missilestate + S_HEAD_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_cacdth, // deathsound + 8, // speed + 31*FRACUNIT, // radius + 56*FRACUNIT, // height + 400, // mass + 0, // damage + sfx_dmact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_FLOAT|MF_NOGRAVITY|MF_COUNTKILL, // flags + S_HEAD_RAISE1 // raisestate + }, + + { // MT_BRUISER + 3003, // doomednum + S_BOSS_STND, // spawnstate + 1000, // spawnhealth + S_BOSS_RUN1, // seestate + sfx_brssit, // seesound + 8, // reactiontime + 0, // attacksound + S_BOSS_PAIN, // painstate + 50, // painchance + sfx_dmpain, // painsound + S_BOSS_ATK1, // meleestate + S_BOSS_ATK1, // missilestate + S_BOSS_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_brsdth, // deathsound + 8, // speed + 24*FRACUNIT, // radius + 64*FRACUNIT, // height + 1000, // mass + 0, // damage + sfx_dmact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags + S_BOSS_RAISE1 // raisestate + }, + + { // MT_BRUISERSHOT + -1, // doomednum + S_BRBALL1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_firsht, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_BRBALLX1, // deathstate + S_NULL, // xdeathstate + sfx_firxpl, // deathsound + 15*FRACUNIT, // speed + 6*FRACUNIT, // radius + 8*FRACUNIT, // height + 100, // mass + 8, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY|MF_TRANSLUCENT, // flags killough 2/21/98 + S_NULL // raisestate + }, + + { // MT_KNIGHT + 69, // doomednum + S_BOS2_STND, // spawnstate + 500, // spawnhealth + S_BOS2_RUN1, // seestate + sfx_kntsit, // seesound + 8, // reactiontime + 0, // attacksound + S_BOS2_PAIN, // painstate + 50, // painchance + sfx_dmpain, // painsound + S_BOS2_ATK1, // meleestate + S_BOS2_ATK1, // missilestate + S_BOS2_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_kntdth, // deathsound + 8, // speed + 24*FRACUNIT, // radius + 64*FRACUNIT, // height + 1000, // mass + 0, // damage + sfx_dmact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags + S_BOS2_RAISE1 // raisestate + }, + + { // MT_SKULL + 3006, // doomednum + S_SKULL_STND, // spawnstate + 100, // spawnhealth + S_SKULL_RUN1, // seestate + 0, // seesound + 8, // reactiontime + sfx_sklatk, // attacksound + S_SKULL_PAIN, // painstate + 256, // painchance + sfx_dmpain, // painsound + 0, // meleestate + S_SKULL_ATK1, // missilestate + S_SKULL_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_firxpl, // deathsound + 8, // speed + 16*FRACUNIT, // radius + 56*FRACUNIT, // height + 50, // mass + 3, // damage + sfx_dmact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_FLOAT|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_SPIDER + 7, // doomednum + S_SPID_STND, // spawnstate + 3000, // spawnhealth + S_SPID_RUN1, // seestate + sfx_spisit, // seesound + 8, // reactiontime + sfx_shotgn, // attacksound + S_SPID_PAIN, // painstate + 40, // painchance + sfx_dmpain, // painsound + 0, // meleestate + S_SPID_ATK1, // missilestate + S_SPID_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_spidth, // deathsound + 12, // speed + 128*FRACUNIT, // radius + 100*FRACUNIT, // height + 1000, // mass + 0, // damage + sfx_dmact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags + S_NULL // raisestate + }, + + { // MT_BABY + 68, // doomednum + S_BSPI_STND, // spawnstate + 500, // spawnhealth + S_BSPI_SIGHT, // seestate + sfx_bspsit, // seesound + 8, // reactiontime + 0, // attacksound + S_BSPI_PAIN, // painstate + 128, // painchance + sfx_dmpain, // painsound + 0, // meleestate + S_BSPI_ATK1, // missilestate + S_BSPI_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_bspdth, // deathsound + 12, // speed + 64*FRACUNIT, // radius + 64*FRACUNIT, // height + 600, // mass + 0, // damage + sfx_bspact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags + S_BSPI_RAISE1 // raisestate + }, + + { // MT_CYBORG + 16, // doomednum + S_CYBER_STND, // spawnstate + 4000, // spawnhealth + S_CYBER_RUN1, // seestate + sfx_cybsit, // seesound + 8, // reactiontime + 0, // attacksound + S_CYBER_PAIN, // painstate + 20, // painchance + sfx_dmpain, // painsound + 0, // meleestate + S_CYBER_ATK1, // missilestate + S_CYBER_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_cybdth, // deathsound + 16, // speed + 40*FRACUNIT, // radius + 110*FRACUNIT, // height + 1000, // mass + 0, // damage + sfx_dmact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags + S_NULL // raisestate + }, + + { // MT_PAIN + 71, // doomednum + S_PAIN_STND, // spawnstate + 400, // spawnhealth + S_PAIN_RUN1, // seestate + sfx_pesit, // seesound + 8, // reactiontime + 0, // attacksound + S_PAIN_PAIN, // painstate + 128, // painchance + sfx_pepain, // painsound + 0, // meleestate + S_PAIN_ATK1, // missilestate + S_PAIN_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_pedth, // deathsound + 8, // speed + 31*FRACUNIT, // radius + 56*FRACUNIT, // height + 400, // mass + 0, // damage + sfx_dmact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_FLOAT|MF_NOGRAVITY|MF_COUNTKILL, // flags + S_PAIN_RAISE1 // raisestate + }, + + { // MT_WOLFSS + 84, // doomednum + S_SSWV_STND, // spawnstate + 50, // spawnhealth + S_SSWV_RUN1, // seestate + sfx_sssit, // seesound + 8, // reactiontime + 0, // attacksound + S_SSWV_PAIN, // painstate + 170, // painchance + sfx_popain, // painsound + 0, // meleestate + S_SSWV_ATK1, // missilestate + S_SSWV_DIE1, // deathstate + S_SSWV_XDIE1, // xdeathstate + sfx_ssdth, // deathsound + 8, // speed + 20*FRACUNIT, // radius + 56*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_posact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags + S_SSWV_RAISE1 // raisestate + }, + + { // MT_KEEN + 72, // doomednum + S_KEENSTND, // spawnstate + 100, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_KEENPAIN, // painstate + 256, // painchance + sfx_keenpn, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_COMMKEEN, // deathstate + S_NULL, // xdeathstate + sfx_keendt, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 72*FRACUNIT, // height + 10000000, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY|MF_SHOOTABLE|MF_COUNTKILL, // flags + S_NULL // raisestate + }, + + { // MT_BOSSBRAIN + 88, // doomednum + S_BRAIN, // spawnstate + 250, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_BRAIN_PAIN, // painstate + 255, // painchance + sfx_bospn, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_BRAIN_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_bosdth, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 10000000, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SHOOTABLE, // flags + S_NULL // raisestate + }, + + { // MT_BOSSSPIT + 89, // doomednum + S_BRAINEYE, // spawnstate + 1000, // spawnhealth + S_BRAINEYESEE, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 32*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOSECTOR, // flags + S_NULL // raisestate + }, + + { // MT_BOSSTARGET + 87, // doomednum + S_NULL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 32*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOSECTOR, // flags + S_NULL // raisestate + }, + + { // MT_SPAWNSHOT + -1, // doomednum + S_SPAWN1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_bospit, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_firxpl, // deathsound + 10*FRACUNIT, // speed + 6*FRACUNIT, // radius + 32*FRACUNIT, // height + 100, // mass + 3, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY|MF_NOCLIP, // flags + S_NULL // raisestate + }, + + { // MT_SPAWNFIRE + -1, // doomednum + S_SPAWNFIRE1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_TRANSLUCENT, // flags // phares + S_NULL // raisestate + }, + + { // MT_BARREL + 2035, // doomednum + S_BAR1, // spawnstate + 20, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_BEXP, // deathstate + S_NULL, // xdeathstate + sfx_barexp, // deathsound + 0, // speed + 10*FRACUNIT, // radius + 42*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SHOOTABLE|MF_NOBLOOD, // flags + S_NULL // raisestate + }, + + { // MT_TROOPSHOT + -1, // doomednum + S_TBALL1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_firsht, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_TBALLX1, // deathstate + S_NULL, // xdeathstate + sfx_firxpl, // deathsound + 10*FRACUNIT, // speed + 6*FRACUNIT, // radius + 8*FRACUNIT, // height + 100, // mass + 3, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY|MF_TRANSLUCENT, // flags // phares + S_NULL // raisestate + }, + + { // MT_HEADSHOT + -1, // doomednum + S_RBALL1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_firsht, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_RBALLX1, // deathstate + S_NULL, // xdeathstate + sfx_firxpl, // deathsound + 10*FRACUNIT, // speed + 6*FRACUNIT, // radius + 8*FRACUNIT, // height + 100, // mass + 5, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY|MF_TRANSLUCENT, // flags // phares, // flags + S_NULL // raisestate + }, + + { // MT_ROCKET + -1, // doomednum + S_ROCKET, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_rlaunc, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_EXPLODE1, // deathstate + S_NULL, // xdeathstate + sfx_barexp, // deathsound + 20*FRACUNIT, // speed + 11*FRACUNIT, // radius + 8*FRACUNIT, // height + 100, // mass + 20, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_PLASMA + -1, // doomednum + S_PLASBALL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_plasma, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_PLASEXP, // deathstate + S_NULL, // xdeathstate + sfx_firxpl, // deathsound + 25*FRACUNIT, // speed + 13*FRACUNIT, // radius + 8*FRACUNIT, // height + 100, // mass + 5, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY|MF_TRANSLUCENT, // flags // phares + S_NULL // raisestate + }, + + { // MT_BFG + -1, // doomednum + S_BFGSHOT, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + 0, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_BFGLAND, // deathstate + S_NULL, // xdeathstate + sfx_rxplod, // deathsound + 25*FRACUNIT, // speed + 13*FRACUNIT, // radius + 8*FRACUNIT, // height + 100, // mass + 100, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY|MF_TRANSLUCENT, // flags // phares + S_NULL // raisestate + }, + + { // MT_ARACHPLAZ + -1, // doomednum + S_ARACH_PLAZ, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_plasma, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_ARACH_PLEX, // deathstate + S_NULL, // xdeathstate + sfx_firxpl, // deathsound + 25*FRACUNIT, // speed + 13*FRACUNIT, // radius + 8*FRACUNIT, // height + 100, // mass + 5, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY|MF_TRANSLUCENT, // flags // phares + S_NULL // raisestate + }, + + { // MT_PUFF + -1, // doomednum + S_PUFF1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_TRANSLUCENT, // flags // phares + S_NULL // raisestate + }, + + { // MT_BLOOD + -1, // doomednum + S_BLOOD1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP, // flags + S_NULL // raisestate + }, + + { // MT_TFOG + -1, // doomednum + S_TFOG, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_TRANSLUCENT, // flags // phares + S_NULL // raisestate + }, + + { // MT_IFOG + -1, // doomednum + S_IFOG, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_TRANSLUCENT, // flags // phares + S_NULL // raisestate + }, + + { // MT_TELEPORTMAN + 14, // doomednum + S_NULL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOSECTOR, // flags + S_NULL // raisestate + }, + + { // MT_EXTRABFG + -1, // doomednum + S_BFGEXP, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MISC0 + 2018, // doomednum + S_ARM1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC1 + 2019, // doomednum + S_ARM2, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC2 + 2014, // doomednum + S_BON1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_COUNTITEM, // flags + S_NULL // raisestate + }, + + { // MT_MISC3 + 2015, // doomednum + S_BON2, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_COUNTITEM, // flags + S_NULL // raisestate + }, + + { // MT_MISC4 + 5, // doomednum + S_BKEY, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_NOTDMATCH, // flags + S_NULL // raisestate + }, + + { // MT_MISC5 + 13, // doomednum + S_RKEY, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_NOTDMATCH, // flags + S_NULL // raisestate + }, + + { // MT_MISC6 + 6, // doomednum + S_YKEY, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_NOTDMATCH, // flags + S_NULL // raisestate + }, + + { // MT_MISC7 + 39, // doomednum + S_YSKULL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_NOTDMATCH, // flags + S_NULL // raisestate + }, + + { // MT_MISC8 + 38, // doomednum + S_RSKULL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_NOTDMATCH, // flags + S_NULL // raisestate + }, + + { // MT_MISC9 + 40, // doomednum + S_BSKULL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_NOTDMATCH, // flags + S_NULL // raisestate + }, + + { // MT_MISC10 + 2011, // doomednum + S_STIM, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC11 + 2012, // doomednum + S_MEDI, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC12 + 2013, // doomednum + S_SOUL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_COUNTITEM|MF_TRANSLUCENT, // flags // killough 2/21/98 + S_NULL // raisestate + }, + + { // MT_INV + 2022, // doomednum + S_PINV, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_COUNTITEM|MF_TRANSLUCENT, // flags // killough 2/21/98 + S_NULL // raisestate + }, + + { // MT_MISC13 + 2023, // doomednum + S_PSTR, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_COUNTITEM, // flags + S_NULL // raisestate + }, + + { // MT_INS + 2024, // doomednum + S_PINS, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_COUNTITEM|MF_TRANSLUCENT, // flags // killough 2/21/98 + S_NULL // raisestate + }, + + { // MT_MISC14 + 2025, // doomednum + S_SUIT, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC15 + 2026, // doomednum + S_PMAP, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_COUNTITEM, // flags + S_NULL // raisestate + }, + + { // MT_MISC16 + 2045, // doomednum + S_PVIS, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_COUNTITEM, // flags + S_NULL // raisestate + }, + + { // MT_MEGA + 83, // doomednum + S_MEGA, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_COUNTITEM|MF_TRANSLUCENT, // flags // killough 2/21/98 + S_NULL // raisestate + }, + + { // MT_CLIP + 2007, // doomednum + S_CLIP, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC17 + 2048, // doomednum + S_AMMO, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC18 + 2010, // doomednum + S_ROCK, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC19 + 2046, // doomednum + S_BROK, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC20 + 2047, // doomednum + S_CELL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC21 + 17, // doomednum + S_CELP, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC22 + 2008, // doomednum + S_SHEL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC23 + 2049, // doomednum + S_SBOX, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC24 + 8, // doomednum + S_BPAK, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC25 + 2006, // doomednum + S_BFUG, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_CHAINGUN + 2002, // doomednum + S_MGUN, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC26 + 2005, // doomednum + S_CSAW, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC27 + 2003, // doomednum + S_LAUN, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC28 + 2004, // doomednum + S_PLAS, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_SHOTGUN + 2001, // doomednum + S_SHOT, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_SUPERSHOTGUN + 82, // doomednum + S_SHOT2, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC29 + 85, // doomednum + S_TECHLAMP, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC30 + 86, // doomednum + S_TECH2LAMP, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC31 + 2028, // doomednum + S_COLU, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC32 + 30, // doomednum + S_TALLGRNCOL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC33 + 31, // doomednum + S_SHRTGRNCOL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC34 + 32, // doomednum + S_TALLREDCOL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC35 + 33, // doomednum + S_SHRTREDCOL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC36 + 37, // doomednum + S_SKULLCOL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC37 + 36, // doomednum + S_HEARTCOL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC38 + 41, // doomednum + S_EVILEYE, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC39 + 42, // doomednum + S_FLOATSKULL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC40 + 43, // doomednum + S_TORCHTREE, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC41 + 44, // doomednum + S_BLUETORCH, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC42 + 45, // doomednum + S_GREENTORCH, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC43 + 46, // doomednum + S_REDTORCH, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC44 + 55, // doomednum + S_BTORCHSHRT, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC45 + 56, // doomednum + S_GTORCHSHRT, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC46 + 57, // doomednum + S_RTORCHSHRT, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC47 + 47, // doomednum + S_STALAGTITE, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC48 + 48, // doomednum + S_TECHPILLAR, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC49 + 34, // doomednum + S_CANDLESTIK, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + 0, // flags + S_NULL // raisestate + }, + + { // MT_MISC50 + 35, // doomednum + S_CANDELABRA, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC51 + 49, // doomednum + S_BLOODYTWITCH, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 68*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MISC52 + 50, // doomednum + S_MEAT2, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 84*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MISC53 + 51, // doomednum + S_MEAT3, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 84*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MISC54 + 52, // doomednum + S_MEAT4, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 68*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MISC55 + 53, // doomednum + S_MEAT5, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 52*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MISC56 + 59, // doomednum + S_MEAT2, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 84*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPAWNCEILING|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MISC57 + 60, // doomednum + S_MEAT4, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 68*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPAWNCEILING|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MISC58 + 61, // doomednum + S_MEAT3, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 52*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPAWNCEILING|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MISC59 + 62, // doomednum + S_MEAT5, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 52*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPAWNCEILING|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MISC60 + 63, // doomednum + S_BLOODYTWITCH, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 68*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPAWNCEILING|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MISC61 + 22, // doomednum + S_HEAD_DIE6, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + 0, // flags + S_NULL // raisestate + }, + + { // MT_MISC62 + 15, // doomednum + S_PLAY_DIE7, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + 0, // flags + S_NULL // raisestate + }, + + { // MT_MISC63 + 18, // doomednum + S_POSS_DIE5, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + 0, // flags + S_NULL // raisestate + }, + + { // MT_MISC64 + 21, // doomednum + S_SARG_DIE6, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + 0, // flags + S_NULL // raisestate + }, + + { // MT_MISC65 + 23, // doomednum + S_SKULL_DIE6, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + 0, // flags + S_NULL // raisestate + }, + + { // MT_MISC66 + 20, // doomednum + S_TROO_DIE5, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + 0, // flags + S_NULL // raisestate + }, + + { // MT_MISC67 + 19, // doomednum + S_SPOS_DIE5, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + 0, // flags + S_NULL // raisestate + }, + + { // MT_MISC68 + 10, // doomednum + S_PLAY_XDIE9, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + 0, // flags + S_NULL // raisestate + }, + + { // MT_MISC69 + 12, // doomednum + S_PLAY_XDIE9, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + 0, // flags + S_NULL // raisestate + }, + + { // MT_MISC70 + 28, // doomednum + S_HEADSONSTICK, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC71 + 24, // doomednum + S_GIBS, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + 0, // flags + S_NULL // raisestate + }, + + { // MT_MISC72 + 27, // doomednum + S_HEADONASTICK, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC73 + 29, // doomednum + S_HEADCANDLES, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC74 + 25, // doomednum + S_DEADSTICK, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC75 + 26, // doomednum + S_LIVESTICK, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC76 + 54, // doomednum + S_BIGTREE, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 32*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC77 + 70, // doomednum + S_BBAR1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC78 + 73, // doomednum + S_HANGNOGUTS, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 88*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MISC79 + 74, // doomednum + S_HANGBNOBRAIN, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 88*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MISC80 + 75, // doomednum + S_HANGTLOOKDN, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 64*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MISC81 + 76, // doomednum + S_HANGTSKULL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 64*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MISC82 + 77, // doomednum + S_HANGTLOOKUP, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 64*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MISC83 + 78, // doomednum + S_HANGTNOBRAIN, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 64*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MISC84 + 79, // doomednum + S_COLONGIBS, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP, // flags + S_NULL // raisestate + }, + + { // MT_MISC85 + 80, // doomednum + S_SMALLPOOL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP, // flags + S_NULL // raisestate + }, + + { // MT_MISC86 + 81, // doomednum + S_BRAINSTEM, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP, // flags + S_NULL // raisestate + }, + + // For use with wind and current effects + { // MT_PUSH // phares + 5001, // doomednum // | //jff 5/11/98 deconflict + S_TNT1, // spawnstate // V // with DOSDoom + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 8, // radius + 8, // height + 10, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP, // flags + S_NULL // raisestate + }, + + // For use with wind and current effects + { // MT_PULL + 5002, // doomednum //jff 5/11/98 deconflict + S_TNT1, // spawnstate // with DOSDoom + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 8, // radius + 8, // height + 10, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP, // flags + S_NULL // raisestate + }, +#ifdef DOGS + // Marine's best friend :) // killough 7/19/98 + { // MT_DOGS + 888, // doomednum + S_DOGS_STND, // spawnstate + 500, // spawnhealth + S_DOGS_RUN1, // seestate + sfx_dgsit, // seesound + 8, // reactiontime + sfx_dgatk, // attacksound + S_DOGS_PAIN, // painstate + 180, // painchance + sfx_dgpain, // painsound + S_DOGS_ATK1, // meleestate + 0, // missilestate + S_DOGS_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_dgdth, // deathsound + 10, // speed + 12*FRACUNIT, // radius + 28*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_dgact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags + S_DOGS_RAISE1 // raisestate + }, +#endif +}; diff --git a/common/prboom/info.h b/common/prboom/info.h new file mode 100755 index 0000000..11cfb47 --- /dev/null +++ b/common/prboom/info.h @@ -0,0 +1,1498 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Thing frame/state LUT, + * generated by multigen utilitiy. + * This one is the original DOOM version, preserved. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __INFO__ +#define __INFO__ + +/* Needed for action function pointer handling. */ +#include "d_think.h" + +/******************************************************************** + * Sprite name enumeration - must match info.c * + ********************************************************************/ +typedef enum +{ + SPR_TROO, + SPR_SHTG, + SPR_PUNG, + SPR_PISG, + SPR_PISF, + SPR_SHTF, + SPR_SHT2, + SPR_CHGG, + SPR_CHGF, + SPR_MISG, + SPR_MISF, + SPR_SAWG, + SPR_PLSG, + SPR_PLSF, + SPR_BFGG, + SPR_BFGF, + SPR_BLUD, + SPR_PUFF, + SPR_BAL1, + SPR_BAL2, + SPR_PLSS, + SPR_PLSE, + SPR_MISL, + SPR_BFS1, + SPR_BFE1, + SPR_BFE2, + SPR_TFOG, + SPR_IFOG, + SPR_PLAY, + SPR_POSS, + SPR_SPOS, + SPR_VILE, + SPR_FIRE, + SPR_FATB, + SPR_FBXP, + SPR_SKEL, + SPR_MANF, + SPR_FATT, + SPR_CPOS, + SPR_SARG, + SPR_HEAD, + SPR_BAL7, + SPR_BOSS, + SPR_BOS2, + SPR_SKUL, + SPR_SPID, + SPR_BSPI, + SPR_APLS, + SPR_APBX, + SPR_CYBR, + SPR_PAIN, + SPR_SSWV, + SPR_KEEN, + SPR_BBRN, + SPR_BOSF, + SPR_ARM1, + SPR_ARM2, + SPR_BAR1, + SPR_BEXP, + SPR_FCAN, + SPR_BON1, + SPR_BON2, + SPR_BKEY, + SPR_RKEY, + SPR_YKEY, + SPR_BSKU, + SPR_RSKU, + SPR_YSKU, + SPR_STIM, + SPR_MEDI, + SPR_SOUL, + SPR_PINV, + SPR_PSTR, + SPR_PINS, + SPR_MEGA, + SPR_SUIT, + SPR_PMAP, + SPR_PVIS, + SPR_CLIP, + SPR_AMMO, + SPR_ROCK, + SPR_BROK, + SPR_CELL, + SPR_CELP, + SPR_SHEL, + SPR_SBOX, + SPR_BPAK, + SPR_BFUG, + SPR_MGUN, + SPR_CSAW, + SPR_LAUN, + SPR_PLAS, + SPR_SHOT, + SPR_SGN2, + SPR_COLU, + SPR_SMT2, + SPR_GOR1, + SPR_POL2, + SPR_POL5, + SPR_POL4, + SPR_POL3, + SPR_POL1, + SPR_POL6, + SPR_GOR2, + SPR_GOR3, + SPR_GOR4, + SPR_GOR5, + SPR_SMIT, + SPR_COL1, + SPR_COL2, + SPR_COL3, + SPR_COL4, + SPR_CAND, + SPR_CBRA, + SPR_COL6, + SPR_TRE1, + SPR_TRE2, + SPR_ELEC, + SPR_CEYE, + SPR_FSKU, + SPR_COL5, + SPR_TBLU, + SPR_TGRN, + SPR_TRED, + SPR_SMBT, + SPR_SMGT, + SPR_SMRT, + SPR_HDB1, + SPR_HDB2, + SPR_HDB3, + SPR_HDB4, + SPR_HDB5, + SPR_HDB6, + SPR_POB1, + SPR_POB2, + SPR_BRS1, + SPR_TLMP, + SPR_TLP2, + SPR_TNT1, /* add invisible sprite phares 3/8/98 */ + +#ifdef DOGS + SPR_DOGS, /* killough 7/19/98: Marine's best friend :) */ +#endif + + NUMSPRITES /* counter of how many there are */ + +} spritenum_t; + +/******************************************************************** + * States (frames) enumeration -- must match info.c * + ********************************************************************/ + +typedef enum +{ + S_NULL, + S_LIGHTDONE, + S_PUNCH, + S_PUNCHDOWN, + S_PUNCHUP, + S_PUNCH1, + S_PUNCH2, + S_PUNCH3, + S_PUNCH4, + S_PUNCH5, + S_PISTOL, + S_PISTOLDOWN, + S_PISTOLUP, + S_PISTOL1, + S_PISTOL2, + S_PISTOL3, + S_PISTOL4, + S_PISTOLFLASH, + S_SGUN, + S_SGUNDOWN, + S_SGUNUP, + S_SGUN1, + S_SGUN2, + S_SGUN3, + S_SGUN4, + S_SGUN5, + S_SGUN6, + S_SGUN7, + S_SGUN8, + S_SGUN9, + S_SGUNFLASH1, + S_SGUNFLASH2, + S_DSGUN, + S_DSGUNDOWN, + S_DSGUNUP, + S_DSGUN1, + S_DSGUN2, + S_DSGUN3, + S_DSGUN4, + S_DSGUN5, + S_DSGUN6, + S_DSGUN7, + S_DSGUN8, + S_DSGUN9, + S_DSGUN10, + S_DSNR1, + S_DSNR2, + S_DSGUNFLASH1, + S_DSGUNFLASH2, + S_CHAIN, + S_CHAINDOWN, + S_CHAINUP, + S_CHAIN1, + S_CHAIN2, + S_CHAIN3, + S_CHAINFLASH1, + S_CHAINFLASH2, + S_MISSILE, + S_MISSILEDOWN, + S_MISSILEUP, + S_MISSILE1, + S_MISSILE2, + S_MISSILE3, + S_MISSILEFLASH1, + S_MISSILEFLASH2, + S_MISSILEFLASH3, + S_MISSILEFLASH4, + S_SAW, + S_SAWB, + S_SAWDOWN, + S_SAWUP, + S_SAW1, + S_SAW2, + S_SAW3, + S_PLASMA, + S_PLASMADOWN, + S_PLASMAUP, + S_PLASMA1, + S_PLASMA2, + S_PLASMAFLASH1, + S_PLASMAFLASH2, + S_BFG, + S_BFGDOWN, + S_BFGUP, + S_BFG1, + S_BFG2, + S_BFG3, + S_BFG4, + S_BFGFLASH1, + S_BFGFLASH2, + S_BLOOD1, + S_BLOOD2, + S_BLOOD3, + S_PUFF1, + S_PUFF2, + S_PUFF3, + S_PUFF4, + S_TBALL1, + S_TBALL2, + S_TBALLX1, + S_TBALLX2, + S_TBALLX3, + S_RBALL1, + S_RBALL2, + S_RBALLX1, + S_RBALLX2, + S_RBALLX3, + S_PLASBALL, + S_PLASBALL2, + S_PLASEXP, + S_PLASEXP2, + S_PLASEXP3, + S_PLASEXP4, + S_PLASEXP5, + S_ROCKET, + S_BFGSHOT, + S_BFGSHOT2, + S_BFGLAND, + S_BFGLAND2, + S_BFGLAND3, + S_BFGLAND4, + S_BFGLAND5, + S_BFGLAND6, + S_BFGEXP, + S_BFGEXP2, + S_BFGEXP3, + S_BFGEXP4, + S_EXPLODE1, + S_EXPLODE2, + S_EXPLODE3, + S_TFOG, + S_TFOG01, + S_TFOG02, + S_TFOG2, + S_TFOG3, + S_TFOG4, + S_TFOG5, + S_TFOG6, + S_TFOG7, + S_TFOG8, + S_TFOG9, + S_TFOG10, + S_IFOG, + S_IFOG01, + S_IFOG02, + S_IFOG2, + S_IFOG3, + S_IFOG4, + S_IFOG5, + S_PLAY, + S_PLAY_RUN1, + S_PLAY_RUN2, + S_PLAY_RUN3, + S_PLAY_RUN4, + S_PLAY_ATK1, + S_PLAY_ATK2, + S_PLAY_PAIN, + S_PLAY_PAIN2, + S_PLAY_DIE1, + S_PLAY_DIE2, + S_PLAY_DIE3, + S_PLAY_DIE4, + S_PLAY_DIE5, + S_PLAY_DIE6, + S_PLAY_DIE7, + S_PLAY_XDIE1, + S_PLAY_XDIE2, + S_PLAY_XDIE3, + S_PLAY_XDIE4, + S_PLAY_XDIE5, + S_PLAY_XDIE6, + S_PLAY_XDIE7, + S_PLAY_XDIE8, + S_PLAY_XDIE9, + S_POSS_STND, + S_POSS_STND2, + S_POSS_RUN1, + S_POSS_RUN2, + S_POSS_RUN3, + S_POSS_RUN4, + S_POSS_RUN5, + S_POSS_RUN6, + S_POSS_RUN7, + S_POSS_RUN8, + S_POSS_ATK1, + S_POSS_ATK2, + S_POSS_ATK3, + S_POSS_PAIN, + S_POSS_PAIN2, + S_POSS_DIE1, + S_POSS_DIE2, + S_POSS_DIE3, + S_POSS_DIE4, + S_POSS_DIE5, + S_POSS_XDIE1, + S_POSS_XDIE2, + S_POSS_XDIE3, + S_POSS_XDIE4, + S_POSS_XDIE5, + S_POSS_XDIE6, + S_POSS_XDIE7, + S_POSS_XDIE8, + S_POSS_XDIE9, + S_POSS_RAISE1, + S_POSS_RAISE2, + S_POSS_RAISE3, + S_POSS_RAISE4, + S_SPOS_STND, + S_SPOS_STND2, + S_SPOS_RUN1, + S_SPOS_RUN2, + S_SPOS_RUN3, + S_SPOS_RUN4, + S_SPOS_RUN5, + S_SPOS_RUN6, + S_SPOS_RUN7, + S_SPOS_RUN8, + S_SPOS_ATK1, + S_SPOS_ATK2, + S_SPOS_ATK3, + S_SPOS_PAIN, + S_SPOS_PAIN2, + S_SPOS_DIE1, + S_SPOS_DIE2, + S_SPOS_DIE3, + S_SPOS_DIE4, + S_SPOS_DIE5, + S_SPOS_XDIE1, + S_SPOS_XDIE2, + S_SPOS_XDIE3, + S_SPOS_XDIE4, + S_SPOS_XDIE5, + S_SPOS_XDIE6, + S_SPOS_XDIE7, + S_SPOS_XDIE8, + S_SPOS_XDIE9, + S_SPOS_RAISE1, + S_SPOS_RAISE2, + S_SPOS_RAISE3, + S_SPOS_RAISE4, + S_SPOS_RAISE5, + S_VILE_STND, + S_VILE_STND2, + S_VILE_RUN1, + S_VILE_RUN2, + S_VILE_RUN3, + S_VILE_RUN4, + S_VILE_RUN5, + S_VILE_RUN6, + S_VILE_RUN7, + S_VILE_RUN8, + S_VILE_RUN9, + S_VILE_RUN10, + S_VILE_RUN11, + S_VILE_RUN12, + S_VILE_ATK1, + S_VILE_ATK2, + S_VILE_ATK3, + S_VILE_ATK4, + S_VILE_ATK5, + S_VILE_ATK6, + S_VILE_ATK7, + S_VILE_ATK8, + S_VILE_ATK9, + S_VILE_ATK10, + S_VILE_ATK11, + S_VILE_HEAL1, + S_VILE_HEAL2, + S_VILE_HEAL3, + S_VILE_PAIN, + S_VILE_PAIN2, + S_VILE_DIE1, + S_VILE_DIE2, + S_VILE_DIE3, + S_VILE_DIE4, + S_VILE_DIE5, + S_VILE_DIE6, + S_VILE_DIE7, + S_VILE_DIE8, + S_VILE_DIE9, + S_VILE_DIE10, + S_FIRE1, + S_FIRE2, + S_FIRE3, + S_FIRE4, + S_FIRE5, + S_FIRE6, + S_FIRE7, + S_FIRE8, + S_FIRE9, + S_FIRE10, + S_FIRE11, + S_FIRE12, + S_FIRE13, + S_FIRE14, + S_FIRE15, + S_FIRE16, + S_FIRE17, + S_FIRE18, + S_FIRE19, + S_FIRE20, + S_FIRE21, + S_FIRE22, + S_FIRE23, + S_FIRE24, + S_FIRE25, + S_FIRE26, + S_FIRE27, + S_FIRE28, + S_FIRE29, + S_FIRE30, + S_SMOKE1, + S_SMOKE2, + S_SMOKE3, + S_SMOKE4, + S_SMOKE5, + S_TRACER, + S_TRACER2, + S_TRACEEXP1, + S_TRACEEXP2, + S_TRACEEXP3, + S_SKEL_STND, + S_SKEL_STND2, + S_SKEL_RUN1, + S_SKEL_RUN2, + S_SKEL_RUN3, + S_SKEL_RUN4, + S_SKEL_RUN5, + S_SKEL_RUN6, + S_SKEL_RUN7, + S_SKEL_RUN8, + S_SKEL_RUN9, + S_SKEL_RUN10, + S_SKEL_RUN11, + S_SKEL_RUN12, + S_SKEL_FIST1, + S_SKEL_FIST2, + S_SKEL_FIST3, + S_SKEL_FIST4, + S_SKEL_MISS1, + S_SKEL_MISS2, + S_SKEL_MISS3, + S_SKEL_MISS4, + S_SKEL_PAIN, + S_SKEL_PAIN2, + S_SKEL_DIE1, + S_SKEL_DIE2, + S_SKEL_DIE3, + S_SKEL_DIE4, + S_SKEL_DIE5, + S_SKEL_DIE6, + S_SKEL_RAISE1, + S_SKEL_RAISE2, + S_SKEL_RAISE3, + S_SKEL_RAISE4, + S_SKEL_RAISE5, + S_SKEL_RAISE6, + S_FATSHOT1, + S_FATSHOT2, + S_FATSHOTX1, + S_FATSHOTX2, + S_FATSHOTX3, + S_FATT_STND, + S_FATT_STND2, + S_FATT_RUN1, + S_FATT_RUN2, + S_FATT_RUN3, + S_FATT_RUN4, + S_FATT_RUN5, + S_FATT_RUN6, + S_FATT_RUN7, + S_FATT_RUN8, + S_FATT_RUN9, + S_FATT_RUN10, + S_FATT_RUN11, + S_FATT_RUN12, + S_FATT_ATK1, + S_FATT_ATK2, + S_FATT_ATK3, + S_FATT_ATK4, + S_FATT_ATK5, + S_FATT_ATK6, + S_FATT_ATK7, + S_FATT_ATK8, + S_FATT_ATK9, + S_FATT_ATK10, + S_FATT_PAIN, + S_FATT_PAIN2, + S_FATT_DIE1, + S_FATT_DIE2, + S_FATT_DIE3, + S_FATT_DIE4, + S_FATT_DIE5, + S_FATT_DIE6, + S_FATT_DIE7, + S_FATT_DIE8, + S_FATT_DIE9, + S_FATT_DIE10, + S_FATT_RAISE1, + S_FATT_RAISE2, + S_FATT_RAISE3, + S_FATT_RAISE4, + S_FATT_RAISE5, + S_FATT_RAISE6, + S_FATT_RAISE7, + S_FATT_RAISE8, + S_CPOS_STND, + S_CPOS_STND2, + S_CPOS_RUN1, + S_CPOS_RUN2, + S_CPOS_RUN3, + S_CPOS_RUN4, + S_CPOS_RUN5, + S_CPOS_RUN6, + S_CPOS_RUN7, + S_CPOS_RUN8, + S_CPOS_ATK1, + S_CPOS_ATK2, + S_CPOS_ATK3, + S_CPOS_ATK4, + S_CPOS_PAIN, + S_CPOS_PAIN2, + S_CPOS_DIE1, + S_CPOS_DIE2, + S_CPOS_DIE3, + S_CPOS_DIE4, + S_CPOS_DIE5, + S_CPOS_DIE6, + S_CPOS_DIE7, + S_CPOS_XDIE1, + S_CPOS_XDIE2, + S_CPOS_XDIE3, + S_CPOS_XDIE4, + S_CPOS_XDIE5, + S_CPOS_XDIE6, + S_CPOS_RAISE1, + S_CPOS_RAISE2, + S_CPOS_RAISE3, + S_CPOS_RAISE4, + S_CPOS_RAISE5, + S_CPOS_RAISE6, + S_CPOS_RAISE7, + S_TROO_STND, + S_TROO_STND2, + S_TROO_RUN1, + S_TROO_RUN2, + S_TROO_RUN3, + S_TROO_RUN4, + S_TROO_RUN5, + S_TROO_RUN6, + S_TROO_RUN7, + S_TROO_RUN8, + S_TROO_ATK1, + S_TROO_ATK2, + S_TROO_ATK3, + S_TROO_PAIN, + S_TROO_PAIN2, + S_TROO_DIE1, + S_TROO_DIE2, + S_TROO_DIE3, + S_TROO_DIE4, + S_TROO_DIE5, + S_TROO_XDIE1, + S_TROO_XDIE2, + S_TROO_XDIE3, + S_TROO_XDIE4, + S_TROO_XDIE5, + S_TROO_XDIE6, + S_TROO_XDIE7, + S_TROO_XDIE8, + S_TROO_RAISE1, + S_TROO_RAISE2, + S_TROO_RAISE3, + S_TROO_RAISE4, + S_TROO_RAISE5, + S_SARG_STND, + S_SARG_STND2, + S_SARG_RUN1, + S_SARG_RUN2, + S_SARG_RUN3, + S_SARG_RUN4, + S_SARG_RUN5, + S_SARG_RUN6, + S_SARG_RUN7, + S_SARG_RUN8, + S_SARG_ATK1, + S_SARG_ATK2, + S_SARG_ATK3, + S_SARG_PAIN, + S_SARG_PAIN2, + S_SARG_DIE1, + S_SARG_DIE2, + S_SARG_DIE3, + S_SARG_DIE4, + S_SARG_DIE5, + S_SARG_DIE6, + S_SARG_RAISE1, + S_SARG_RAISE2, + S_SARG_RAISE3, + S_SARG_RAISE4, + S_SARG_RAISE5, + S_SARG_RAISE6, + S_HEAD_STND, + S_HEAD_RUN1, + S_HEAD_ATK1, + S_HEAD_ATK2, + S_HEAD_ATK3, + S_HEAD_PAIN, + S_HEAD_PAIN2, + S_HEAD_PAIN3, + S_HEAD_DIE1, + S_HEAD_DIE2, + S_HEAD_DIE3, + S_HEAD_DIE4, + S_HEAD_DIE5, + S_HEAD_DIE6, + S_HEAD_RAISE1, + S_HEAD_RAISE2, + S_HEAD_RAISE3, + S_HEAD_RAISE4, + S_HEAD_RAISE5, + S_HEAD_RAISE6, + S_BRBALL1, + S_BRBALL2, + S_BRBALLX1, + S_BRBALLX2, + S_BRBALLX3, + S_BOSS_STND, + S_BOSS_STND2, + S_BOSS_RUN1, + S_BOSS_RUN2, + S_BOSS_RUN3, + S_BOSS_RUN4, + S_BOSS_RUN5, + S_BOSS_RUN6, + S_BOSS_RUN7, + S_BOSS_RUN8, + S_BOSS_ATK1, + S_BOSS_ATK2, + S_BOSS_ATK3, + S_BOSS_PAIN, + S_BOSS_PAIN2, + S_BOSS_DIE1, + S_BOSS_DIE2, + S_BOSS_DIE3, + S_BOSS_DIE4, + S_BOSS_DIE5, + S_BOSS_DIE6, + S_BOSS_DIE7, + S_BOSS_RAISE1, + S_BOSS_RAISE2, + S_BOSS_RAISE3, + S_BOSS_RAISE4, + S_BOSS_RAISE5, + S_BOSS_RAISE6, + S_BOSS_RAISE7, + S_BOS2_STND, + S_BOS2_STND2, + S_BOS2_RUN1, + S_BOS2_RUN2, + S_BOS2_RUN3, + S_BOS2_RUN4, + S_BOS2_RUN5, + S_BOS2_RUN6, + S_BOS2_RUN7, + S_BOS2_RUN8, + S_BOS2_ATK1, + S_BOS2_ATK2, + S_BOS2_ATK3, + S_BOS2_PAIN, + S_BOS2_PAIN2, + S_BOS2_DIE1, + S_BOS2_DIE2, + S_BOS2_DIE3, + S_BOS2_DIE4, + S_BOS2_DIE5, + S_BOS2_DIE6, + S_BOS2_DIE7, + S_BOS2_RAISE1, + S_BOS2_RAISE2, + S_BOS2_RAISE3, + S_BOS2_RAISE4, + S_BOS2_RAISE5, + S_BOS2_RAISE6, + S_BOS2_RAISE7, + S_SKULL_STND, + S_SKULL_STND2, + S_SKULL_RUN1, + S_SKULL_RUN2, + S_SKULL_ATK1, + S_SKULL_ATK2, + S_SKULL_ATK3, + S_SKULL_ATK4, + S_SKULL_PAIN, + S_SKULL_PAIN2, + S_SKULL_DIE1, + S_SKULL_DIE2, + S_SKULL_DIE3, + S_SKULL_DIE4, + S_SKULL_DIE5, + S_SKULL_DIE6, + S_SPID_STND, + S_SPID_STND2, + S_SPID_RUN1, + S_SPID_RUN2, + S_SPID_RUN3, + S_SPID_RUN4, + S_SPID_RUN5, + S_SPID_RUN6, + S_SPID_RUN7, + S_SPID_RUN8, + S_SPID_RUN9, + S_SPID_RUN10, + S_SPID_RUN11, + S_SPID_RUN12, + S_SPID_ATK1, + S_SPID_ATK2, + S_SPID_ATK3, + S_SPID_ATK4, + S_SPID_PAIN, + S_SPID_PAIN2, + S_SPID_DIE1, + S_SPID_DIE2, + S_SPID_DIE3, + S_SPID_DIE4, + S_SPID_DIE5, + S_SPID_DIE6, + S_SPID_DIE7, + S_SPID_DIE8, + S_SPID_DIE9, + S_SPID_DIE10, + S_SPID_DIE11, + S_BSPI_STND, + S_BSPI_STND2, + S_BSPI_SIGHT, + S_BSPI_RUN1, + S_BSPI_RUN2, + S_BSPI_RUN3, + S_BSPI_RUN4, + S_BSPI_RUN5, + S_BSPI_RUN6, + S_BSPI_RUN7, + S_BSPI_RUN8, + S_BSPI_RUN9, + S_BSPI_RUN10, + S_BSPI_RUN11, + S_BSPI_RUN12, + S_BSPI_ATK1, + S_BSPI_ATK2, + S_BSPI_ATK3, + S_BSPI_ATK4, + S_BSPI_PAIN, + S_BSPI_PAIN2, + S_BSPI_DIE1, + S_BSPI_DIE2, + S_BSPI_DIE3, + S_BSPI_DIE4, + S_BSPI_DIE5, + S_BSPI_DIE6, + S_BSPI_DIE7, + S_BSPI_RAISE1, + S_BSPI_RAISE2, + S_BSPI_RAISE3, + S_BSPI_RAISE4, + S_BSPI_RAISE5, + S_BSPI_RAISE6, + S_BSPI_RAISE7, + S_ARACH_PLAZ, + S_ARACH_PLAZ2, + S_ARACH_PLEX, + S_ARACH_PLEX2, + S_ARACH_PLEX3, + S_ARACH_PLEX4, + S_ARACH_PLEX5, + S_CYBER_STND, + S_CYBER_STND2, + S_CYBER_RUN1, + S_CYBER_RUN2, + S_CYBER_RUN3, + S_CYBER_RUN4, + S_CYBER_RUN5, + S_CYBER_RUN6, + S_CYBER_RUN7, + S_CYBER_RUN8, + S_CYBER_ATK1, + S_CYBER_ATK2, + S_CYBER_ATK3, + S_CYBER_ATK4, + S_CYBER_ATK5, + S_CYBER_ATK6, + S_CYBER_PAIN, + S_CYBER_DIE1, + S_CYBER_DIE2, + S_CYBER_DIE3, + S_CYBER_DIE4, + S_CYBER_DIE5, + S_CYBER_DIE6, + S_CYBER_DIE7, + S_CYBER_DIE8, + S_CYBER_DIE9, + S_CYBER_DIE10, + S_PAIN_STND, + S_PAIN_RUN1, + S_PAIN_RUN2, + S_PAIN_RUN3, + S_PAIN_RUN4, + S_PAIN_RUN5, + S_PAIN_RUN6, + S_PAIN_ATK1, + S_PAIN_ATK2, + S_PAIN_ATK3, + S_PAIN_ATK4, + S_PAIN_PAIN, + S_PAIN_PAIN2, + S_PAIN_DIE1, + S_PAIN_DIE2, + S_PAIN_DIE3, + S_PAIN_DIE4, + S_PAIN_DIE5, + S_PAIN_DIE6, + S_PAIN_RAISE1, + S_PAIN_RAISE2, + S_PAIN_RAISE3, + S_PAIN_RAISE4, + S_PAIN_RAISE5, + S_PAIN_RAISE6, + S_SSWV_STND, + S_SSWV_STND2, + S_SSWV_RUN1, + S_SSWV_RUN2, + S_SSWV_RUN3, + S_SSWV_RUN4, + S_SSWV_RUN5, + S_SSWV_RUN6, + S_SSWV_RUN7, + S_SSWV_RUN8, + S_SSWV_ATK1, + S_SSWV_ATK2, + S_SSWV_ATK3, + S_SSWV_ATK4, + S_SSWV_ATK5, + S_SSWV_ATK6, + S_SSWV_PAIN, + S_SSWV_PAIN2, + S_SSWV_DIE1, + S_SSWV_DIE2, + S_SSWV_DIE3, + S_SSWV_DIE4, + S_SSWV_DIE5, + S_SSWV_XDIE1, + S_SSWV_XDIE2, + S_SSWV_XDIE3, + S_SSWV_XDIE4, + S_SSWV_XDIE5, + S_SSWV_XDIE6, + S_SSWV_XDIE7, + S_SSWV_XDIE8, + S_SSWV_XDIE9, + S_SSWV_RAISE1, + S_SSWV_RAISE2, + S_SSWV_RAISE3, + S_SSWV_RAISE4, + S_SSWV_RAISE5, + S_KEENSTND, + S_COMMKEEN, + S_COMMKEEN2, + S_COMMKEEN3, + S_COMMKEEN4, + S_COMMKEEN5, + S_COMMKEEN6, + S_COMMKEEN7, + S_COMMKEEN8, + S_COMMKEEN9, + S_COMMKEEN10, + S_COMMKEEN11, + S_COMMKEEN12, + S_KEENPAIN, + S_KEENPAIN2, + S_BRAIN, + S_BRAIN_PAIN, + S_BRAIN_DIE1, + S_BRAIN_DIE2, + S_BRAIN_DIE3, + S_BRAIN_DIE4, + S_BRAINEYE, + S_BRAINEYESEE, + S_BRAINEYE1, + S_SPAWN1, + S_SPAWN2, + S_SPAWN3, + S_SPAWN4, + S_SPAWNFIRE1, + S_SPAWNFIRE2, + S_SPAWNFIRE3, + S_SPAWNFIRE4, + S_SPAWNFIRE5, + S_SPAWNFIRE6, + S_SPAWNFIRE7, + S_SPAWNFIRE8, + S_BRAINEXPLODE1, + S_BRAINEXPLODE2, + S_BRAINEXPLODE3, + S_ARM1, + S_ARM1A, + S_ARM2, + S_ARM2A, + S_BAR1, + S_BAR2, + S_BEXP, + S_BEXP2, + S_BEXP3, + S_BEXP4, + S_BEXP5, + S_BBAR1, + S_BBAR2, + S_BBAR3, + S_BON1, + S_BON1A, + S_BON1B, + S_BON1C, + S_BON1D, + S_BON1E, + S_BON2, + S_BON2A, + S_BON2B, + S_BON2C, + S_BON2D, + S_BON2E, + S_BKEY, + S_BKEY2, + S_RKEY, + S_RKEY2, + S_YKEY, + S_YKEY2, + S_BSKULL, + S_BSKULL2, + S_RSKULL, + S_RSKULL2, + S_YSKULL, + S_YSKULL2, + S_STIM, + S_MEDI, + S_SOUL, + S_SOUL2, + S_SOUL3, + S_SOUL4, + S_SOUL5, + S_SOUL6, + S_PINV, + S_PINV2, + S_PINV3, + S_PINV4, + S_PSTR, + S_PINS, + S_PINS2, + S_PINS3, + S_PINS4, + S_MEGA, + S_MEGA2, + S_MEGA3, + S_MEGA4, + S_SUIT, + S_PMAP, + S_PMAP2, + S_PMAP3, + S_PMAP4, + S_PMAP5, + S_PMAP6, + S_PVIS, + S_PVIS2, + S_CLIP, + S_AMMO, + S_ROCK, + S_BROK, + S_CELL, + S_CELP, + S_SHEL, + S_SBOX, + S_BPAK, + S_BFUG, + S_MGUN, + S_CSAW, + S_LAUN, + S_PLAS, + S_SHOT, + S_SHOT2, + S_COLU, + S_STALAG, + S_BLOODYTWITCH, + S_BLOODYTWITCH2, + S_BLOODYTWITCH3, + S_BLOODYTWITCH4, + S_DEADTORSO, + S_DEADBOTTOM, + S_HEADSONSTICK, + S_GIBS, + S_HEADONASTICK, + S_HEADCANDLES, + S_HEADCANDLES2, + S_DEADSTICK, + S_LIVESTICK, + S_LIVESTICK2, + S_MEAT2, + S_MEAT3, + S_MEAT4, + S_MEAT5, + S_STALAGTITE, + S_TALLGRNCOL, + S_SHRTGRNCOL, + S_TALLREDCOL, + S_SHRTREDCOL, + S_CANDLESTIK, + S_CANDELABRA, + S_SKULLCOL, + S_TORCHTREE, + S_BIGTREE, + S_TECHPILLAR, + S_EVILEYE, + S_EVILEYE2, + S_EVILEYE3, + S_EVILEYE4, + S_FLOATSKULL, + S_FLOATSKULL2, + S_FLOATSKULL3, + S_HEARTCOL, + S_HEARTCOL2, + S_BLUETORCH, + S_BLUETORCH2, + S_BLUETORCH3, + S_BLUETORCH4, + S_GREENTORCH, + S_GREENTORCH2, + S_GREENTORCH3, + S_GREENTORCH4, + S_REDTORCH, + S_REDTORCH2, + S_REDTORCH3, + S_REDTORCH4, + S_BTORCHSHRT, + S_BTORCHSHRT2, + S_BTORCHSHRT3, + S_BTORCHSHRT4, + S_GTORCHSHRT, + S_GTORCHSHRT2, + S_GTORCHSHRT3, + S_GTORCHSHRT4, + S_RTORCHSHRT, + S_RTORCHSHRT2, + S_RTORCHSHRT3, + S_RTORCHSHRT4, + S_HANGNOGUTS, + S_HANGBNOBRAIN, + S_HANGTLOOKDN, + S_HANGTSKULL, + S_HANGTLOOKUP, + S_HANGTNOBRAIN, + S_COLONGIBS, + S_SMALLPOOL, + S_BRAINSTEM, + S_TECHLAMP, + S_TECHLAMP2, + S_TECHLAMP3, + S_TECHLAMP4, + S_TECH2LAMP, + S_TECH2LAMP2, + S_TECH2LAMP3, + S_TECH2LAMP4, + S_TNT1, /* add state for invisible sprite phares 3/8/98 */ + + S_GRENADE, /* killough 8/9/98: grenade launcher */ + S_DETONATE, /* killough 8/9/98: detonation of objects */ + S_DETONATE2, + S_DETONATE3, + + // always count dog states, even if dogs are disabled + S_DOGS_STND, /* killough 7/19/98: Marine's best friend :) */ + S_DOGS_STND2, + S_DOGS_RUN1, + S_DOGS_RUN2, + S_DOGS_RUN3, + S_DOGS_RUN4, + S_DOGS_RUN5, + S_DOGS_RUN6, + S_DOGS_RUN7, + S_DOGS_RUN8, + S_DOGS_ATK1, + S_DOGS_ATK2, + S_DOGS_ATK3, + S_DOGS_PAIN, + S_DOGS_PAIN2, + S_DOGS_DIE1, + S_DOGS_DIE2, + S_DOGS_DIE3, + S_DOGS_DIE4, + S_DOGS_DIE5, + S_DOGS_DIE6, + S_DOGS_RAISE1, + S_DOGS_RAISE2, + S_DOGS_RAISE3, + S_DOGS_RAISE4, + S_DOGS_RAISE5, + S_DOGS_RAISE6, + + // add dummy beta bfg / lost soul frames for dehacked compatibility + // fixes bug #1576151 (part 2) + S_OLDBFG1, // killough 7/11/98: the old BFG's 43 firing frames + S_OLDBFG42 = S_OLDBFG1+41, + S_OLDBFG43, + + S_PLS1BALL, // killough 7/19/98: first plasma fireball in the beta + S_PLS1BALL2, + S_PLS1EXP, + S_PLS1EXP2, + S_PLS1EXP3, + S_PLS1EXP4, + S_PLS1EXP5, + + S_PLS2BALL, // killough 7/19/98: second plasma fireball in the beta + S_PLS2BALL2, + S_PLS2BALLX1, + S_PLS2BALLX2, + S_PLS2BALLX3, + S_BON3, // killough 7/11/98: evil sceptre in beta version + S_BON4, // killough 7/11/98: unholy bible in beta version + + // killough 10/98: beta lost souls were different from their modern cousins + S_BSKUL_STND, + S_BSKUL_RUN1, + S_BSKUL_RUN2, + S_BSKUL_RUN3, + S_BSKUL_RUN4, + S_BSKUL_ATK1, + S_BSKUL_ATK2, + S_BSKUL_ATK3, + S_BSKUL_PAIN1, + S_BSKUL_PAIN2, + S_BSKUL_PAIN3, + S_BSKUL_DIE1, + S_BSKUL_DIE2, + S_BSKUL_DIE3, + S_BSKUL_DIE4, + S_BSKUL_DIE5, + S_BSKUL_DIE6, + S_BSKUL_DIE7, + S_BSKUL_DIE8, + + S_MUSHROOM, /* killough 10/98: mushroom explosion effect */ + + NUMSTATES /* Counter of how many there are */ + +} statenum_t; + +/******************************************************************** + * Definition of the state (frames) structure * + ********************************************************************/ + +typedef struct +{ + spritenum_t sprite; /* sprite number to show */ + long frame; /* which frame/subframe of the sprite is shown */ + long tics; /* number of gametics this frame should last */ + actionf_t action; /* code pointer to function for action if any */ + statenum_t nextstate; /* linked list pointer to next state or zero */ + long misc1, misc2; /* apparently never used in DOOM */ +} state_t; + +/* these are in info.c */ +extern state_t states[NUMSTATES]; +extern const char *sprnames[]; /* 1/17/98 killough - CPhipps - const */ + +/******************************************************************** + * Thing enumeration -- must match info.c * + ******************************************************************** + * Note that many of these are generically named for the ornamentals + */ + +typedef enum { + MT_PLAYER, + MT_POSSESSED, + MT_SHOTGUY, + MT_VILE, + MT_FIRE, + MT_UNDEAD, + MT_TRACER, + MT_SMOKE, + MT_FATSO, + MT_FATSHOT, + MT_CHAINGUY, + MT_TROOP, + MT_SERGEANT, + MT_SHADOWS, + MT_HEAD, + MT_BRUISER, + MT_BRUISERSHOT, + MT_KNIGHT, + MT_SKULL, + MT_SPIDER, + MT_BABY, + MT_CYBORG, + MT_PAIN, + MT_WOLFSS, + MT_KEEN, + MT_BOSSBRAIN, + MT_BOSSSPIT, + MT_BOSSTARGET, + MT_SPAWNSHOT, + MT_SPAWNFIRE, + MT_BARREL, + MT_TROOPSHOT, + MT_HEADSHOT, + MT_ROCKET, + MT_PLASMA, + MT_BFG, + MT_ARACHPLAZ, + MT_PUFF, + MT_BLOOD, + MT_TFOG, + MT_IFOG, + MT_TELEPORTMAN, + MT_EXTRABFG, + MT_MISC0, + MT_MISC1, + MT_MISC2, + MT_MISC3, + MT_MISC4, + MT_MISC5, + MT_MISC6, + MT_MISC7, + MT_MISC8, + MT_MISC9, + MT_MISC10, + MT_MISC11, + MT_MISC12, + MT_INV, + MT_MISC13, + MT_INS, + MT_MISC14, + MT_MISC15, + MT_MISC16, + MT_MEGA, + MT_CLIP, + MT_MISC17, + MT_MISC18, + MT_MISC19, + MT_MISC20, + MT_MISC21, + MT_MISC22, + MT_MISC23, + MT_MISC24, + MT_MISC25, + MT_CHAINGUN, + MT_MISC26, + MT_MISC27, + MT_MISC28, + MT_SHOTGUN, + MT_SUPERSHOTGUN, + MT_MISC29, + MT_MISC30, + MT_MISC31, + MT_MISC32, + MT_MISC33, + MT_MISC34, + MT_MISC35, + MT_MISC36, + MT_MISC37, + MT_MISC38, + MT_MISC39, + MT_MISC40, + MT_MISC41, + MT_MISC42, + MT_MISC43, + MT_MISC44, + MT_MISC45, + MT_MISC46, + MT_MISC47, + MT_MISC48, + MT_MISC49, + MT_MISC50, + MT_MISC51, + MT_MISC52, + MT_MISC53, + MT_MISC54, + MT_MISC55, + MT_MISC56, + MT_MISC57, + MT_MISC58, + MT_MISC59, + MT_MISC60, + MT_MISC61, + MT_MISC62, + MT_MISC63, + MT_MISC64, + MT_MISC65, + MT_MISC66, + MT_MISC67, + MT_MISC68, + MT_MISC69, + MT_MISC70, + MT_MISC71, + MT_MISC72, + MT_MISC73, + MT_MISC74, + MT_MISC75, + MT_MISC76, + MT_MISC77, + MT_MISC78, + MT_MISC79, + MT_MISC80, + MT_MISC81, + MT_MISC82, + MT_MISC83, + MT_MISC84, + MT_MISC85, + MT_MISC86, + MT_PUSH, /* controls push source - phares */ + MT_PULL, /* controls pull source - phares 3/20/98 */ + +#ifdef DOGS + MT_DOGS, /* killough 7/19/98: Marine's best friend */ +#endif + + /* proff 11/22/98: Andy Baker's stealth monsters (next 12) + * cph - moved below the MBF stuff, no need to displace them */ + MT_STEALTHBABY, + MT_STEALTHVILE, + MT_STEALTHBRUISER, + MT_STEALTHHEAD, + MT_STEALTHCHAINGUY, + MT_STEALTHSERGEANT, + MT_STEALTHKNIGHT, + MT_STEALTHIMP, + MT_STEALTHFATSO, + MT_STEALTHUNDEAD, + MT_STEALTHSHOTGUY, + MT_STEALTHZOMBIE, + + NUMMOBJTYPES // Counter of how many there are +} mobjtype_t; + +/******************************************************************** + * Definition of the Thing structure + ********************************************************************/ +/* Note that these are only indices to the state, sound, etc. arrays + * and not actual pointers. Most can be set to zero if the action or + * sound doesn't apply (like lamps generally don't attack or whistle). + */ + +typedef struct +{ + int doomednum; /* Thing number used in id's editor, and now + probably by every other editor too */ + int spawnstate; /* The state (frame) index when this Thing is + first created */ + int spawnhealth; /* The initial hit points for this Thing */ + int seestate; /* The state when it sees you or wakes up */ + int seesound; /* The sound it makes when waking */ + int reactiontime; /* How many tics it waits after it wakes up + before it will start to attack, in normal + skills (halved for nightmare) */ + int attacksound; /* The sound it makes when it attacks */ + int painstate; /* The state to indicate pain */ + int painchance; /* A number that is checked against a random + number 0-255 to see if the Thing is supposed + to go to its painstate or not. Note this + has absolutely nothing to do with the chance + it will get hurt, just the chance of it + reacting visibly. */ + int painsound; /* The sound it emits when it feels pain */ + int meleestate; /* Melee==close attack */ + int missilestate; /* What states to use when it's in the air, if + in fact it is ever used as a missile */ + int deathstate; /* What state begins the death sequence */ + int xdeathstate; /* What state begins the horrible death sequence + like when a rocket takes out a trooper */ + int deathsound; /* The death sound. See also A_Scream() in + p_enemy.c for some tweaking that goes on + for certain monsters */ + int speed; /* How fast it moves. Too fast and it can miss + collision logic. */ + int radius; /* An often incorrect radius */ + int height; /* An often incorrect height, used only to see + if a monster can enter a sector */ + int mass; /* How much an impact will move it. Cacodemons + seem to retreat when shot because they have + very little mass and are moved by impact */ + int damage; /* If this is a missile, how much does it hurt? */ + int activesound; /* What sound it makes wandering around, once + in a while. Chance is 3/256 it will. */ + uint_64_t flags; /* Bit masks for lots of things. See p_mobj.h */ + int raisestate; /* The first state for an Archvile or respawn + resurrection. Zero means it won't come + back to life. */ +} mobjinfo_t; + +/* See p_mobj_h for addition more technical info */ +extern mobjinfo_t mobjinfo[NUMMOBJTYPES]; + +#endif diff --git a/common/prboom/lprintf.c b/common/prboom/lprintf.c new file mode 100755 index 0000000..027191e --- /dev/null +++ b/common/prboom/lprintf.c @@ -0,0 +1,388 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Provides a logical console output routine that allows what is + * output to console normally and when output is redirected to + * be controlled.. + * + *-----------------------------------------------------------------------------*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#endif +#ifdef _MSC_VER +#include +#endif +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include "doomtype.h" +#include "lprintf.h" +#include "i_main.h" +#include "m_argv.h" + +int cons_error_mask = -1-LO_INFO; /* all but LO_INFO when redir'd */ +int cons_output_mask = -1; /* all output enabled */ + +/* cphipps - enlarged message buffer and made non-static + * We still have to be careful here, this function can be called after exit + */ +#define MAX_MESSAGE_SIZE 2048 + +#ifdef _WIN32 +// Variables for the console +HWND con_hWnd=0; +HFONT OemFont; +LONG OemWidth, OemHeight; +int ConWidth,ConHeight; +char szConName[] = "PrBoomConWinClass"; +char Lines[(80+2)*25+1]; +char *Last = NULL; +boolean console_inited=FALSE; +static boolean should_exit = 0; + +static CALLBACK ConWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) +{ + PAINTSTRUCT paint; + HDC dc; + + switch (iMsg) { + case WM_KEYDOWN: + if (wParam == VK_ESCAPE) + should_exit = 1; + break; + case WM_CLOSE: + return 1; + break; + case WM_PAINT: + if (dc = BeginPaint (con_hWnd, &paint)) + { + if (Last) + { + char *row; + int line, last; + + line = paint.rcPaint.top / OemHeight; + last = paint.rcPaint.bottom / OemHeight; + for (row = Lines + (line*(80+2)); line < last; line++) + { + if (row[1]>0) + TextOut (dc, 0, line * OemHeight, &row[2], row[1]); + row += 80 + 2; + } + } + EndPaint (con_hWnd, &paint); + } + return 0; + break; + default: + break; + } + return(DefWindowProc(hwnd,iMsg,wParam,lParam)); +} + +static void I_PrintStr (int xp, const char *cp, int count, BOOL scroll) { + RECT rect; + HDC conDC; + + if ((!con_hWnd) || (!console_inited)) + return; + if (count) + { + conDC=GetDC(con_hWnd); + TextOut (conDC, xp * OemWidth, ConHeight - OemHeight, cp, count); + ReleaseDC(con_hWnd,conDC); + } + if (scroll) { + rect.left = 0; + rect.top = 0; + rect.right = ConWidth; + rect.bottom = ConHeight; + ScrollWindowEx (con_hWnd, 0, -OemHeight, NULL, &rect, NULL, NULL, SW_ERASE|SW_INVALIDATE); + UpdateWindow (con_hWnd); + } +} + +static int I_ConPrintString (const char *outline) +{ + const char *cp, *newcp; + static int xp = 0; + int newxp; + BOOL scroll; + + if (!console_inited) + return 0; + cp = outline; + while (*cp) { + for (newcp = cp, newxp = xp; + *newcp != '\n' && *newcp != '\0' && newxp < 80; + newcp++) { + if (*newcp == '\x08') { + newxp--; + break; + } + else if (*newcp == '\t') { + newxp = ((newxp + 8) / 8) * 8; + break; + } + else + newxp++; + } + + if (*cp) { + const char *poop; + int x; + + for (x = xp, poop = cp; poop < newcp; poop++, x++) { + Last[x+2] = ((*poop) < 32) ? 32 : (*poop); + } + + if (*newcp == '\t') + for (x = xp; x < newxp; x++) + Last[x+2] = ' '; + + if (Last[1] < xp + (newcp - cp)) + Last[1] = xp + (newcp - cp); + + if (*newcp == '\n' || xp == 80) { + if (*newcp != '\n') { + Last[0] = 1; + } + memmove (Lines, Lines + (80 + 2), (80 + 2) * (25 - 1)); + Last[0] = 0; + Last[1] = 0; + newxp = 0; + scroll = TRUE; + } else { + scroll = FALSE; + } + I_PrintStr (xp, cp, newcp - cp, scroll); + + xp = newxp; + + if ((*newcp == '\n') || (*newcp == '\x08') || (*newcp == '\t')) + cp = newcp + 1; + else + cp = newcp; + } + } + + return strlen (outline); +} + +void I_ConTextAttr(unsigned char a) +{ + int r,g,b,col; + HDC conDC; + + if (!console_inited) + return; + conDC=GetDC(con_hWnd); + r=0; g=0; b=0; + if (a & FOREGROUND_INTENSITY) col=255; + else col=128; + if (a & FOREGROUND_RED) r=col; + if (a & FOREGROUND_GREEN) g=col; + if (a & FOREGROUND_BLUE) b=col; + SetTextColor(conDC, PALETTERGB(r,g,b)); + r=0; g=0; b=0; + if (a & BACKGROUND_INTENSITY) col=255; + else col=128; + if (a & BACKGROUND_RED) r=col; + if (a & BACKGROUND_GREEN) g=col; + if (a & BACKGROUND_BLUE) b=col; + SetBkColor(conDC, PALETTERGB(r,g,b)); + ReleaseDC(con_hWnd,conDC); +} + +void I_UpdateConsole(void) +{ + MSG msg; + + UpdateWindow(con_hWnd); + while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) > 0) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + if (should_exit) + exit(0); +} + +static void Init_Console(void) +{ + memset(Lines,0,25*(80+2)+1); + Last = Lines + (25 - 1) * (80 + 2); + console_inited=TRUE; +} + +int Init_ConsoleWin(void) +{ + HDC conDC; + WNDCLASS wndclass; + TEXTMETRIC metrics; + RECT cRect; + int width,height; + int scr_width,scr_height; + HINSTANCE hInstance; + char titlebuffer[2048]; + + if (con_hWnd) + return TRUE; + hInstance = GetModuleHandle(NULL); + Init_Console(); + /* Register the frame class */ + wndclass.style = CS_OWNDC; + wndclass.lpfnWndProc = (WNDPROC)ConWndProc; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = 0; + wndclass.hInstance = hInstance; + wndclass.hIcon = LoadIcon (hInstance, IDI_WINLOGO); + wndclass.hCursor = LoadCursor (NULL,IDC_ARROW); + wndclass.hbrBackground = (HBRUSH)GetStockObject (BLACK_BRUSH); + wndclass.lpszMenuName = szConName; + wndclass.lpszClassName = szConName; + + if (!RegisterClass(&wndclass)) + return FALSE; + + width=100; + height=100; + strcpy(titlebuffer,PACKAGE); + strcat(titlebuffer," "); + strcat(titlebuffer,VERSION); + strcat(titlebuffer," console"); + con_hWnd = CreateWindow(szConName, titlebuffer, + WS_CAPTION | WS_POPUP, + 0, 0, width, height, + NULL, NULL, hInstance, NULL); + conDC=GetDC(con_hWnd); + OemFont = GetStockObject(OEM_FIXED_FONT); + SelectObject(conDC, OemFont); + GetTextMetrics(conDC, &metrics); + OemWidth = metrics.tmAveCharWidth; + OemHeight = metrics.tmHeight; + GetClientRect(con_hWnd, &cRect); + width += (OemWidth * 80) - cRect.right; + height += (OemHeight * 25) - cRect.bottom; + // proff 11/09/98: Added code for centering console + scr_width = GetSystemMetrics(SM_CXFULLSCREEN); + scr_height = GetSystemMetrics(SM_CYFULLSCREEN); + MoveWindow(con_hWnd, (scr_width-width)/2, (scr_height-height)/2, width, height, TRUE); + GetClientRect(con_hWnd, &cRect); + ConWidth = cRect.right; + ConHeight = cRect.bottom; + SetTextColor(conDC, RGB(192,192,192)); + SetBkColor(conDC, RGB(0,0,0)); + SetBkMode(conDC, OPAQUE); + ReleaseDC(con_hWnd,conDC); + ShowWindow(con_hWnd, SW_SHOW); + UpdateWindow(con_hWnd); + return TRUE; +} + +void Done_ConsoleWin(void) +{ + if (con_hWnd) + DestroyWindow(con_hWnd); + UnregisterClass(szConName,GetModuleHandle(NULL)); + con_hWnd=0; +} +#endif + +int lprintf(OutputLevels pri, const char *s, ...) +{ + int r=0; + char msg[MAX_MESSAGE_SIZE]; + int lvl=pri; + + va_list v; + va_start(v,s); +#ifdef HAVE_VSNPRINTF + vsnprintf(msg,sizeof(msg),s,v); /* print message in buffer */ +#else + vsprintf(msg,s,v); +#endif + va_end(v); + + if (lvl&cons_output_mask) /* mask output as specified */ + { + r=fprintf(stdout,"%s",msg); +#ifdef _WIN32 + I_ConPrintString(msg); +#endif + } + if (!isatty(1) && lvl&cons_error_mask) /* if stdout redirected */ + r=fprintf(stderr,"%s",msg); /* select output at console */ + + return r; +} + +/* + * I_Error + * + * cphipps - moved out of i_* headers, to minimise source files that depend on + * the low-level headers. All this does is print the error, then call the + * low-level safe exit function. + * killough 3/20/98: add const + */ + +void I_Error(const char *error, ...) +{ + char errmsg[MAX_MESSAGE_SIZE]; + va_list argptr; + va_start(argptr,error); +#ifdef HAVE_VSNPRINTF + vsnprintf(errmsg,sizeof(errmsg),error,argptr); +#else + vsprintf(errmsg,error,argptr); +#endif + va_end(argptr); + lprintf(LO_ERROR, "%s\n", errmsg); +#ifdef _MSC_VER + if (!M_CheckParm ("-nodraw")) { + //Init_ConsoleWin(); + MessageBox(con_hWnd,errmsg,"PrBoom",MB_OK | MB_TASKMODAL | MB_TOPMOST); + } +#endif + + while( true ) { + printf( " SAFE EXIT \n" ); + + usleep(1000); + } + +} diff --git a/common/prboom/lprintf.h b/common/prboom/lprintf.h new file mode 100755 index 0000000..9871688 --- /dev/null +++ b/common/prboom/lprintf.h @@ -0,0 +1,68 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Declarations etc. for logical console output + * + *-----------------------------------------------------------------------------*/ + +#ifndef __LPRINTF__ +#define __LPRINTF__ + +typedef enum /* Logical output levels */ +{ + LO_INFO=1, /* One of these is used in each physical output */ + LO_CONFIRM=2, /* call. Which are output, or echoed to console */ + LO_WARN=4, /* if output redirected is determined by the */ + LO_ERROR=8, /* global masks: cons_output_mask,cons_error_mask. */ + LO_FATAL=16, + LO_DEBUG=32, + LO_ALWAYS=64, +} OutputLevels; + +#ifndef __GNUC__ +#define __attribute__(x) +#endif + +extern int lprintf(OutputLevels pri, const char *fmt, ...) __attribute__((format(printf,2,3))); +extern int cons_output_mask; +extern int cons_error_mask; + +/* killough 3/20/98: add const + * killough 4/25/98: add gcc attributes + * cphipps 01/11- moved from i_system.h */ +void I_Error(const char *error, ...) __attribute__((format(printf,1,2))); + +#ifdef _WIN32 +void I_ConTextAttr(unsigned char a); +void I_UpdateConsole(void); +int Init_ConsoleWin(void); +void Done_ConsoleWin(void); +#endif + +#endif diff --git a/common/prboom/m_argv.c b/common/prboom/m_argv.c new file mode 100755 index 0000000..9392840 --- /dev/null +++ b/common/prboom/m_argv.c @@ -0,0 +1,58 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Some argument handling. + * + *-----------------------------------------------------------------------------*/ + +#include +// CPhipps - include the correct header +#include "doomtype.h" +#include "m_argv.h" + +int myargc; +const char * const * myargv; // CPhipps - not sure if ANSI C allows you to +// modify contents of argv, but I can't imagine it does. + +// +// M_CheckParm +// Checks for the given parameter +// in the program's command line arguments. +// Returns the argument number (1 to argc-1) +// or 0 if not present +// + +int M_CheckParm(const char *check) +{ + signed int i = myargc; + while (--i>0) + if (!strcasecmp(check, myargv[i])) + return i; + return 0; +} diff --git a/common/prboom/m_argv.h b/common/prboom/m_argv.h new file mode 100755 index 0000000..5340c15 --- /dev/null +++ b/common/prboom/m_argv.h @@ -0,0 +1,47 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Argument handling. + * + *-----------------------------------------------------------------------------*/ + + +#ifndef __M_ARGV__ +#define __M_ARGV__ + +/* + * MISC + */ +extern int myargc; +extern const char * const * myargv; /* CPhipps - const * const * */ + +/* Returns the position of the given parameter in the arg list (0 if not found). */ +int M_CheckParm(const char *check); + +#endif diff --git a/common/prboom/m_bbox.c b/common/prboom/m_bbox.c new file mode 100755 index 0000000..f2097ce --- /dev/null +++ b/common/prboom/m_bbox.c @@ -0,0 +1,58 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Main loop menu stuff. + * Random number LUT. + * Default Config File. + * PCX Screenshots. + * + *-----------------------------------------------------------------------------*/ + +#ifdef __GNUG__ +#pragma implementation "m_bbox.h" +#endif +#include "m_bbox.h" + +void M_ClearBox (fixed_t *box) +{ + box[BOXTOP] = box[BOXRIGHT] = INT_MIN; + box[BOXBOTTOM] = box[BOXLEFT] = INT_MAX; +} + +void M_AddToBox(fixed_t* box,fixed_t x,fixed_t y) + { + if (xbox[BOXRIGHT]) + box[BOXRIGHT] = x; + if (ybox[BOXTOP]) + box[BOXTOP] = y; + } diff --git a/common/prboom/m_bbox.h b/common/prboom/m_bbox.h new file mode 100755 index 0000000..5c2f2df --- /dev/null +++ b/common/prboom/m_bbox.h @@ -0,0 +1,56 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Simple bounding box datatype and functions. + * + *-----------------------------------------------------------------------------*/ + + +#ifndef __M_BBOX__ +#define __M_BBOX__ + +#include +#include "m_fixed.h" + +/* Bounding box coordinate storage. */ +enum +{ + BOXTOP, + BOXBOTTOM, + BOXLEFT, + BOXRIGHT +}; /* bbox coordinates */ + +/* Bounding box functions. */ + +void M_ClearBox(fixed_t* box); + +void M_AddToBox(fixed_t* box,fixed_t x,fixed_t y); + +#endif diff --git a/common/prboom/m_cheat.c b/common/prboom/m_cheat.c new file mode 100755 index 0000000..1265ae2 --- /dev/null +++ b/common/prboom/m_cheat.c @@ -0,0 +1,744 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2002 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Cheat sequence checking. + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" +#include "g_game.h" +#include "r_data.h" +#include "p_inter.h" +#include "p_tick.h" +#include "m_cheat.h" +#include "m_argv.h" +#include "s_sound.h" +#include "sounds.h" +#include "dstrings.h" +#include "r_main.h" +#include "p_map.h" +#include "d_deh.h" // Ty 03/27/98 - externalized strings +/* cph 2006/07/23 - needs direct access to thinkercap */ +#include "p_tick.h" + +#define plyr (players+consoleplayer) /* the console player */ + +//----------------------------------------------------------------------------- +// +// CHEAT SEQUENCE PACKAGE +// +//----------------------------------------------------------------------------- + +static void cheat_mus(); +static void cheat_choppers(); +static void cheat_god(); +static void cheat_fa(); +static void cheat_k(); +static void cheat_kfa(); +static void cheat_noclip(); +static void cheat_pw(); +static void cheat_behold(); +static void cheat_clev(); +static void cheat_mypos(); +static void cheat_rate(); +static void cheat_comp(); +static void cheat_friction(); +static void cheat_pushers(); +static void cheat_tnttran(); +static void cheat_massacre(); +static void cheat_ddt(); +static void cheat_hom(); +static void cheat_fast(); +static void cheat_tntkey(); +static void cheat_tntkeyx(); +static void cheat_tntkeyxx(); +static void cheat_tntweap(); +static void cheat_tntweapx(); +static void cheat_tntammo(); +static void cheat_tntammox(); +static void cheat_smart(); +static void cheat_pitch(); +static void cheat_megaarmour(); +static void cheat_health(); + +//----------------------------------------------------------------------------- +// +// List of cheat codes, functions, and special argument indicators. +// +// The first argument is the cheat code. +// +// The second argument is its DEH name, or NULL if it's not supported by -deh. +// +// The third argument is a combination of the bitmasks: +// {always, not_dm, not_coop, not_net, not_menu, not_demo, not_deh}, +// which excludes the cheat during certain modes of play. +// +// The fourth argument is the handler function. +// +// The fifth argument is passed to the handler function if it's non-negative; +// if negative, then its negative indicates the number of extra characters +// expected after the cheat code, which are passed to the handler function +// via a pointer to a buffer (after folding any letters to lowercase). +// +//----------------------------------------------------------------------------- + +struct cheat_s cheat[] = { + {"idmus", "Change music", always, + cheat_mus, -2, 0, 0 }, + + {"idchoppers", "Chainsaw", not_net | not_demo, + cheat_choppers, 0, 0, 0 }, + + {"iddqd", "God mode", not_net | not_demo, + cheat_god, 0, 0, 0 }, + +#if 0 + {"idk", NULL, not_net | not_demo | not_deh, + cheat_k }, // The most controversial cheat code in Doom history!!! +#endif + + {"idkfa", "Ammo & Keys", not_net | not_demo, + cheat_kfa, 0, 0, 0 }, + + {"idfa", "Ammo", not_net | not_demo, + cheat_fa, 0, 0, 0 }, + + {"idspispopd", "No Clipping 1", not_net | not_demo, + cheat_noclip, 0, 0, 0 }, + + {"idclip", "No Clipping 2", not_net | not_demo, + cheat_noclip, 0, 0, 0 }, + + {"idbeholdh", "Invincibility", not_net | not_demo, + cheat_health, 0, 0, 0 }, + + {"idbeholdm", "Invincibility", not_net | not_demo, + cheat_megaarmour, 0, 0, 0 }, + + {"idbeholdv", "Invincibility", not_net | not_demo, + cheat_pw, pw_invulnerability, 0, 0 }, + + {"idbeholds", "Berserk", not_net | not_demo, + cheat_pw, pw_strength, 0, 0 }, + + {"idbeholdi", "Invisibility", not_net | not_demo, + cheat_pw, pw_invisibility, 0, 0 }, + + {"idbeholdr", "Radiation Suit", not_net | not_demo, + cheat_pw, pw_ironfeet, 0, 0 }, + + {"idbeholda", "Auto-map", not_dm, + cheat_pw, pw_allmap, 0, 0 }, + + {"idbeholdl", "Lite-Amp Goggles", not_dm, + cheat_pw, pw_infrared, 0, 0 }, + + {"idbehold", "BEHOLD menu", not_dm, + cheat_behold, 0, 0, 0 }, + + {"idclev", "Level Warp", not_net | not_demo | not_menu, + cheat_clev, -2, 0, 0}, + + {"idmypos", "Player Position", not_dm, + cheat_mypos, 0, 0, 0 }, + + {"idrate", "Frame rate", 0, + cheat_rate, 0, 0, 0 }, + + {"tntcomp", NULL, not_net | not_demo, + cheat_comp, 0, 0, 0 }, // phares + + {"tntem", NULL, not_net | not_demo, + cheat_massacre, 0, 0, 0 }, // jff 2/01/98 kill all monsters + + {"iddt", "Map cheat", not_dm, + cheat_ddt, 0, 0, 0 }, // killough 2/07/98: moved from am_map.c + + {"tnthom", NULL, always, + cheat_hom, 0, 0, 0 }, // killough 2/07/98: HOM autodetector + + {"tntkey", NULL, not_net | not_demo, + cheat_tntkey, 0, 0, 0 }, // killough 2/16/98: generalized key cheats + + {"tntkeyr", NULL, not_net | not_demo, + cheat_tntkeyx, 0, 0, 0 }, + + {"tntkeyy", NULL, not_net | not_demo, + cheat_tntkeyx, 0, 0, 0 }, + + {"tntkeyb", NULL, not_net | not_demo, + cheat_tntkeyx, 0, 0, 0 }, + + {"tntkeyrc", NULL, not_net | not_demo, + cheat_tntkeyxx, it_redcard, 0, 0 }, + + {"tntkeyyc", NULL, not_net | not_demo, + cheat_tntkeyxx, it_yellowcard, 0, 0 }, + + {"tntkeybc", NULL, not_net | not_demo, + cheat_tntkeyxx, it_bluecard, 0, 0 }, + + {"tntkeyrs", NULL, not_net | not_demo, + cheat_tntkeyxx, it_redskull, 0, 0 }, + + {"tntkeyys", NULL, not_net | not_demo, + cheat_tntkeyxx, it_yellowskull, 0, 0 }, + + {"tntkeybs", NULL, not_net | not_demo, + cheat_tntkeyxx, it_blueskull, 0, 0 }, // killough 2/16/98: end generalized keys + + {"tntka", NULL, not_net | not_demo, + cheat_k, 0, 0, 0 }, // Ty 04/11/98 - Added TNTKA + + {"tntweap", NULL, not_net | not_demo, + cheat_tntweap, 0, 0, 0 }, // killough 2/16/98: generalized weapon cheats + + {"tntweap", NULL, not_net | not_demo, + cheat_tntweapx, -1, 0, 0}, + + {"tntammo", NULL, not_net | not_demo, + cheat_tntammo, 0, 0, 0 }, + + {"tntammo", NULL, not_net | not_demo, + cheat_tntammox, -1, 0, 0}, // killough 2/16/98: end generalized weapons + + {"tnttran", NULL, always, + cheat_tnttran, 0, 0, 0 }, // invoke translucency // phares + + {"tntsmart", NULL, not_net | not_demo, + cheat_smart, 0, 0, 0}, // killough 2/21/98: smart monster toggle + + {"tntpitch", NULL, always, + cheat_pitch, 0, 0, 0}, // killough 2/21/98: pitched sound toggle + + // killough 2/21/98: reduce RSI injury by adding simpler alias sequences: + {"tntran", NULL, always, + cheat_tnttran, 0, 0, 0 }, // killough 2/21/98: same as tnttran + + {"tntamo", NULL, not_net | not_demo, + cheat_tntammo, 0, 0, 0 }, // killough 2/21/98: same as tntammo + + {"tntamo", NULL, not_net | not_demo, + cheat_tntammox, -1, 0, 0}, // killough 2/21/98: same as tntammo + + {"tntfast", NULL, not_net | not_demo, + cheat_fast, 0, 0, 0 }, // killough 3/6/98: -fast toggle + + {"tntice", NULL, not_net | not_demo, + cheat_friction, 0, 0, 0 }, // phares 3/10/98: toggle variable friction effects + + {"tntpush", NULL, not_net | not_demo, + cheat_pushers, 0, 0, 0 }, // phares 3/10/98: toggle pushers + + {NULL, NULL, 0, NULL, 0, 0, 0} // end-of-list marker +}; + +//----------------------------------------------------------------------------- + +static void cheat_mus(buf) +char buf[3]; +{ + int musnum; + + //jff 3/20/98 note: this cheat allowed in netgame/demorecord + + //jff 3/17/98 avoid musnum being negative and crashing + if (!isdigit(buf[0]) || !isdigit(buf[1])) + return; + + plyr->message = s_STSTR_MUS; // Ty 03/27/98 - externalized + + if (gamemode == commercial) + { + musnum = mus_runnin + (buf[0]-'0')*10 + buf[1]-'0' - 1; + + //jff 4/11/98 prevent IDMUS00 in DOOMII and IDMUS36 or greater + if (musnum < mus_runnin || ((buf[0]-'0')*10 + buf[1]-'0') > 35) + plyr->message = s_STSTR_NOMUS; // Ty 03/27/98 - externalized + else + { + S_ChangeMusic(musnum, 1); + idmusnum = musnum; //jff 3/17/98 remember idmus number for restore + } + } + else + { + musnum = mus_e1m1 + (buf[0]-'1')*9 + (buf[1]-'1'); + + //jff 4/11/98 prevent IDMUS0x IDMUSx0 in DOOMI and greater than introa + if (buf[0] < '1' || buf[1] < '1' || ((buf[0]-'1')*9 + buf[1]-'1') > 31) + plyr->message = s_STSTR_NOMUS; // Ty 03/27/98 - externalized + else + { + S_ChangeMusic(musnum, 1); + idmusnum = musnum; //jff 3/17/98 remember idmus number for restore + } + } +} + +// 'choppers' invulnerability & chainsaw +static void cheat_choppers() +{ + plyr->weaponowned[wp_chainsaw] = true; + plyr->powers[pw_invulnerability] = true; + plyr->message = s_STSTR_CHOPPERS; // Ty 03/27/98 - externalized +} + +static void cheat_god() +{ // 'dqd' cheat for toggleable god mode + plyr->cheats ^= CF_GODMODE; + if (plyr->cheats & CF_GODMODE) + { + if (plyr->mo) + plyr->mo->health = god_health; // Ty 03/09/98 - deh + + plyr->health = god_health; + plyr->message = s_STSTR_DQDON; // Ty 03/27/98 - externalized + } + else + plyr->message = s_STSTR_DQDOFF; // Ty 03/27/98 - externalized +} + +// CPhipps - new health and armour cheat codes +static void cheat_health() +{ + if (!(plyr->cheats & CF_GODMODE)) { + if (plyr->mo) + plyr->mo->health = mega_health; + plyr->health = mega_health; + plyr->message = s_STSTR_BEHOLDX; // Ty 03/27/98 - externalized + } +} + +static void cheat_megaarmour() +{ + plyr->armorpoints = idfa_armor; // Ty 03/09/98 - deh + plyr->armortype = idfa_armor_class; // Ty 03/09/98 - deh + plyr->message = s_STSTR_BEHOLDX; // Ty 03/27/98 - externalized +} + +static void cheat_fa() +{ + int i; + + if (!plyr->backpack) + { + for (i=0 ; imaxammo[i] *= 2; + plyr->backpack = true; + } + + plyr->armorpoints = idfa_armor; // Ty 03/09/98 - deh + plyr->armortype = idfa_armor_class; // Ty 03/09/98 - deh + + // You can't own weapons that aren't in the game // phares 02/27/98 + for (i=0;iweaponowned[i] = true; + + for (i=0;iammo[i] = plyr->maxammo[i]; + + plyr->message = s_STSTR_FAADDED; +} + +static void cheat_k() +{ + int i; + for (i=0;icards[i]) // only print message if at least one key added + { // however, caller may overwrite message anyway + plyr->cards[i] = true; + plyr->message = "Keys Added"; + } +} + +static void cheat_kfa() +{ + cheat_k(); + cheat_fa(); + plyr->message = STSTR_KFAADDED; +} + +static void cheat_noclip() +{ + // Simplified, accepting both "noclip" and "idspispopd". + // no clipping mode cheat + + plyr->message = (plyr->cheats ^= CF_NOCLIP) & CF_NOCLIP ? + s_STSTR_NCON : s_STSTR_NCOFF; // Ty 03/27/98 - externalized +} + +// 'behold?' power-up cheats (modified for infinite duration -- killough) +static void cheat_pw(int pw) +{ + if (plyr->powers[pw]) + plyr->powers[pw] = pw!=pw_strength && pw!=pw_allmap; // killough + else + { + P_GivePower(plyr, pw); + if (pw != pw_strength) + plyr->powers[pw] = -1; // infinite duration -- killough + } + plyr->message = s_STSTR_BEHOLDX; // Ty 03/27/98 - externalized +} + +// 'behold' power-up menu +static void cheat_behold() +{ + plyr->message = s_STSTR_BEHOLD; // Ty 03/27/98 - externalized +} + +// 'clev' change-level cheat +static void cheat_clev(char buf[3]) +{ + int epsd, map; + + if (gamemode == commercial) + { + epsd = 1; //jff was 0, but espd is 1-based + map = (buf[0] - '0')*10 + buf[1] - '0'; + } + else + { + epsd = buf[0] - '0'; + map = buf[1] - '0'; + } + + // Catch invalid maps. + if (epsd < 1 || map < 1 || // Ohmygod - this is not going to work. + (gamemode == retail && (epsd > 4 || map > 9 )) || + (gamemode == registered && (epsd > 3 || map > 9 )) || + (gamemode == shareware && (epsd > 1 || map > 9 )) || + (gamemode == commercial && (epsd > 1 || map > 32 )) ) //jff no 33 and 34 + return; //8/14/98 allowed + + // So be it. + + idmusnum = -1; //jff 3/17/98 revert to normal level music on IDCLEV + + plyr->message = s_STSTR_CLEV; // Ty 03/27/98 - externalized + + G_DeferedInitNew(gameskill, epsd, map); +} + +// 'mypos' for player position +// killough 2/7/98: simplified using dprintf and made output more user-friendly +static void cheat_mypos() +{ + doom_printf("Position (%d,%d,%d)\tAngle %-.0f", + players[consoleplayer].mo->x >> FRACBITS, + players[consoleplayer].mo->y >> FRACBITS, + players[consoleplayer].mo->z >> FRACBITS, + players[consoleplayer].mo->angle * (90.0/ANG90)); +} + +// cph - cheat to toggle frame rate/rendering stats display +static void cheat_rate() +{ + rendering_stats ^= 1; +} + +// compatibility cheat + +static void cheat_comp() +{ + // CPhipps - modified for new compatibility system + compatibility_level++; compatibility_level %= MAX_COMPATIBILITY_LEVEL; + // must call G_Compatibility after changing compatibility_level + // (fixes sf bug number 1558738) + G_Compatibility(); + doom_printf("New compatibility level:\n%s", + comp_lev_str[compatibility_level]); +} + +// variable friction cheat +static void cheat_friction() +{ + plyr->message = // Ty 03/27/98 - *not* externalized + (variable_friction = !variable_friction) ? "Variable Friction enabled" : + "Variable Friction disabled"; +} + + +// Pusher cheat +// phares 3/10/98 +static void cheat_pushers() +{ + plyr->message = // Ty 03/27/98 - *not* externalized + (allow_pushers = !allow_pushers) ? "Pushers enabled" : "Pushers disabled"; +} + +// translucency cheat +static void cheat_tnttran() +{ + plyr->message = // Ty 03/27/98 - *not* externalized + (general_translucency = !general_translucency) ? "Translucency enabled" : + "Translucency disabled"; + + // killough 3/1/98, 4/11/98: cache translucency map on a demand basis + if (general_translucency && !main_tranmap) + R_InitTranMap(0); +} + +static void cheat_massacre() // jff 2/01/98 kill all monsters +{ + // jff 02/01/98 'em' cheat - kill all monsters + // partially taken from Chi's .46 port + // + // killough 2/7/98: cleaned up code and changed to use dprintf; + // fixed lost soul bug (LSs left behind when PEs are killed) + + int killcount=0; + thinker_t *currentthinker = NULL; + extern void A_PainDie(mobj_t *); + + // killough 7/20/98: kill friendly monsters only if no others to kill + uint_64_t mask = MF_FRIEND; + P_MapStart(); + do + while ((currentthinker = P_NextThinker(currentthinker,th_all)) != NULL) + if (currentthinker->function == P_MobjThinker && + !(((mobj_t *) currentthinker)->flags & mask) && // killough 7/20/98 + (((mobj_t *) currentthinker)->flags & MF_COUNTKILL || + ((mobj_t *) currentthinker)->type == MT_SKULL)) + { // killough 3/6/98: kill even if PE is dead + if (((mobj_t *) currentthinker)->health > 0) + { + killcount++; + P_DamageMobj((mobj_t *)currentthinker, NULL, NULL, 10000); + } + if (((mobj_t *) currentthinker)->type == MT_PAIN) + { + A_PainDie((mobj_t *) currentthinker); // killough 2/8/98 + P_SetMobjState ((mobj_t *) currentthinker, S_PAIN_DIE6); + } + } + while (!killcount && mask ? mask=0, 1 : 0); // killough 7/20/98 + P_MapEnd(); + // killough 3/22/98: make more intelligent about plural + // Ty 03/27/98 - string(s) *not* externalized + doom_printf("%d Monster%s Killed", killcount, killcount==1 ? "" : "s"); +} + +// killough 2/7/98: move iddt cheat from am_map.c to here +// killough 3/26/98: emulate Doom better +static void cheat_ddt() +{ + extern int ddt_cheating; + if (automapmode & am_active) + ddt_cheating = (ddt_cheating+1) % 3; +} + +// killough 2/7/98: HOM autodetection +static void cheat_hom() +{ + extern int autodetect_hom; // Ty 03/27/98 - *not* externalized + plyr->message = (autodetect_hom = !autodetect_hom) ? "HOM Detection On" : + "HOM Detection Off"; +} + +// killough 3/6/98: -fast parameter toggle +static void cheat_fast() +{ + plyr->message = (fastparm = !fastparm) ? "Fast Monsters On" : + "Fast Monsters Off"; // Ty 03/27/98 - *not* externalized + G_SetFastParms(fastparm); // killough 4/10/98: set -fast parameter correctly +} + +// killough 2/16/98: keycard/skullkey cheat functions +static void cheat_tntkey() +{ + plyr->message = "Red, Yellow, Blue"; // Ty 03/27/98 - *not* externalized +} + +static void cheat_tntkeyx() +{ + plyr->message = "Card, Skull"; // Ty 03/27/98 - *not* externalized +} + +static void cheat_tntkeyxx(int key) +{ + plyr->message = (plyr->cards[key] = !plyr->cards[key]) ? + "Key Added" : "Key Removed"; // Ty 03/27/98 - *not* externalized +} + +// killough 2/16/98: generalized weapon cheats + +static void cheat_tntweap() +{ // Ty 03/27/98 - *not* externalized + plyr->message = gamemode==commercial ? // killough 2/28/98 + "Weapon number 1-9" : "Weapon number 1-8"; +} + +static void cheat_tntweapx(buf) +char buf[3]; +{ + int w = *buf - '1'; + + if ((w==wp_supershotgun && gamemode!=commercial) || // killough 2/28/98 + ((w==wp_bfg || w==wp_plasma) && gamemode==shareware)) + return; + + if (w==wp_fist) // make '1' apply beserker strength toggle + cheat_pw(pw_strength); + else + if (w >= 0 && w < NUMWEAPONS) { + if ((plyr->weaponowned[w] = !plyr->weaponowned[w])) + plyr->message = "Weapon Added"; // Ty 03/27/98 - *not* externalized + else + { + plyr->message = "Weapon Removed"; // Ty 03/27/98 - *not* externalized + if (w==plyr->readyweapon) // maybe switch if weapon removed + plyr->pendingweapon = P_SwitchWeapon(plyr); + } + } +} + +// killough 2/16/98: generalized ammo cheats +static void cheat_tntammo() +{ + plyr->message = "Ammo 1-4, Backpack"; // Ty 03/27/98 - *not* externalized +} + +static void cheat_tntammox(buf) +char buf[1]; +{ + int a = *buf - '1'; + if (*buf == 'b') // Ty 03/27/98 - strings *not* externalized + if ((plyr->backpack = !plyr->backpack)) + for (plyr->message = "Backpack Added", a=0 ; amaxammo[a] <<= 1; + else + for (plyr->message = "Backpack Removed", a=0 ; aammo[a] > (plyr->maxammo[a] >>= 1)) + plyr->ammo[a] = plyr->maxammo[a]; + } + else + if (a>=0 && amessage = (plyr->ammo[a] = !plyr->ammo[a]) ? + plyr->ammo[a] = plyr->maxammo[a], "Ammo Added" : "Ammo Removed"; + } +} + +static void cheat_smart() +{ + plyr->message = (monsters_remember = !monsters_remember) ? + "Smart Monsters Enabled" : "Smart Monsters Disabled"; +} + +static void cheat_pitch() +{ + plyr->message=(pitched_sounds = !pitched_sounds) ? "Pitch Effects Enabled" : + "Pitch Effects Disabled"; +} + +//----------------------------------------------------------------------------- +// 2/7/98: Cheat detection rewritten by Lee Killough, to avoid +// scrambling and to use a more general table-driven approach. +//----------------------------------------------------------------------------- + +#define CHEAT_ARGS_MAX 8 /* Maximum number of args at end of cheats */ + +boolean M_FindCheats(int key) +{ + static uint_64_t sr; + static char argbuf[CHEAT_ARGS_MAX+1], *arg; + static int init, argsleft, cht; + int i, ret, matchedbefore; + + // If we are expecting arguments to a cheat + // (e.g. idclev), put them in the arg buffer + + if (argsleft) + { + *arg++ = tolower(key); // store key in arg buffer + if (!--argsleft) // if last key in arg list, + cheat[cht].func(argbuf); // process the arg buffer + return 1; // affirmative response + } + + key = tolower(key) - 'a'; + if (key < 0 || key >= 32) // ignore most non-alpha cheat letters + { + sr = 0; // clear shift register + return 0; + } + + if (!init) // initialize aux entries of table + { + init = 1; + for (i=0;cheat[i].cheat;i++) + { + uint_64_t c=0, m=0; + const char *p; + + for (p=cheat[i].cheat; *p; p++) + { + unsigned keynum = tolower(*p)-'a'; // convert to 0-31 + if (keynum >= 32) // ignore most non-alpha cheat letters + continue; + c = (c<<5) + keynum; // shift key into code + m = (m<<5) + 31; // shift 1's into mask + } + cheat[i].code = c; // code for this cheat key + cheat[i].mask = m; // mask for this cheat key + } + } + + sr = (sr<<5) + key; // shift this key into shift register + + for (matchedbefore = ret = i = 0; cheat[i].cheat; i++) + if ((sr & cheat[i].mask) == cheat[i].code && // if match found + !(cheat[i].when & not_dm && deathmatch) && // and if cheat allowed + !(cheat[i].when & not_coop && netgame && !deathmatch) && + !(cheat[i].when & not_demo && (demorecording || demoplayback)) && + !(cheat[i].when & not_menu && menuactive) && + !(cheat[i].when & not_deh && M_CheckParm("-deh"))) { + if (cheat[i].arg < 0) // if additional args are required + { + cht = i; // remember this cheat code + arg = argbuf; // point to start of arg buffer + argsleft = -cheat[i].arg; // number of args expected + ret = 1; // responder has eaten key + } + else + if (!matchedbefore) // allow only one cheat at a time + { + matchedbefore = ret = 1; // responder has eaten key + cheat[i].func(cheat[i].arg); // call cheat handler + } + } + return ret; +} diff --git a/common/prboom/m_cheat.h b/common/prboom/m_cheat.h new file mode 100755 index 0000000..f7bafce --- /dev/null +++ b/common/prboom/m_cheat.h @@ -0,0 +1,58 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Cheat code checking. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __M_CHEAT__ +#define __M_CHEAT__ + +/* killough 4/16/98: Cheat table structure */ + +extern struct cheat_s { + const char * cheat; + const char *const deh_cheat; + enum { + always = 0, + not_dm = 1, + not_coop = 2, + not_demo = 4, + not_menu = 8, + not_deh = 16, + not_net = not_dm | not_coop + } const when; + void (*const func)(); + const int arg; + uint_64_t code, mask; +} cheat[]; + +boolean M_FindCheats(int key); + +#endif diff --git a/common/prboom/m_fixed.h b/common/prboom/m_fixed.h new file mode 100755 index 0000000..bb21368 --- /dev/null +++ b/common/prboom/m_fixed.h @@ -0,0 +1,219 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Fixed point arithemtics, implementation. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __M_FIXED__ +#define __M_FIXED__ + +#include "config.h" +#include "doomtype.h" + +/* + * Fixed point, 32bit as 16.16. + */ + +#define FRACBITS 16 +#define FRACUNIT (1<> (8*sizeof _t-1); + return (_t^_s)-_s; + } +# endif + +/* + * Fixed Point Multiplication + */ + +#ifdef I386_ASM +# ifdef _MSC_VER +#pragma warning( disable : 4035 ) +__inline static fixed_t FixedMul(fixed_t a, fixed_t b) +{ +// return (fixed_t)((longlong) a*b >> FRACBITS); + __asm + { + mov eax,a + imul b + shrd eax,edx,16 + } +} +#pragma warning( default : 4035 ) +# else /* _MSC_VER */ +/* killough 5/10/98: In djgpp, use inlined assembly for performance + * CPhipps - made __inline__ to inline, as specified in the gcc docs + * Also made const. Also __asm__ to asm, as in docs. + * Replaced inline asm with Julian's version for Eternity dated 6/7/2001 + */ +inline +static CONSTFUNC fixed_t FixedMul(fixed_t a, fixed_t b) +{ + fixed_t result; + + asm ( + " imull %2 ;" + " shrdl $16,%%edx,%0 ;" + : "=a" (result) /* eax is always the result */ + : "0" (a), /* eax is also first operand */ + "rm" (b) /* second operand can be reg or mem */ + : "%edx", "%cc" /* edx and condition codes clobbered */ + ); + + return result; +} +# endif /* _MSC_VER */ + +#else /* I386_ASM */ + +/* CPhipps - made __inline__ to inline, as specified in the gcc docs + * Also made const */ + +inline static CONSTFUNC fixed_t FixedMul(fixed_t a, fixed_t b) +{ + return (fixed_t)((int_64_t) a*b >> FRACBITS); +} + +#endif /* I386_ASM */ + +/* + * Fixed Point Division + */ + +#ifdef I386_ASM + +# ifdef _MSC_VER +#pragma warning( disable : 4035 ) +__inline static fixed_t FixedDiv(fixed_t a, fixed_t b) +{ + // e6y + // zg is a master of engineer science. + // + // Fixed crash with FixedDiv(-2147483648,x) + // Exception Number : EXCEPTION_INT_OVERFLOW(C0000095) + // + // Some other ports (Eternity, Chocolate) return wrong value instead of MAXINT. + // For example FixedDiv(-2147483648,-30576) should return INT_MAX instead of 307907126 + // 307907126 is truncated correct int64 value: 4602874423 - 2^32 = 307907126 + if ((unsigned)D_abs(a) >> 14 >= (unsigned)D_abs(b)) + return (a^b)<0 ? INT_MIN : INT_MAX; + __asm + { + mov eax,a + mov ebx,b + mov edx,eax + shl eax,16 // proff 11/06/98: Changed from sal to shl, I think + // this is better + sar edx,16 + idiv ebx // This is needed, because when I used 'idiv b' the + // compiler produced wrong code in a different place + } +} +#pragma warning( default : 4035 ) +# else /* _MSC_VER */ +/* killough 5/10/98: In djgpp, use inlined assembly for performance + * killough 9/5/98: optimized to reduce the number of branches + * CPhipps - made __inline__ to inline, as specified in the gcc docs + * Also made const, also __asm__ to asm as in docs. + * Replaced inline asm with Julian's version for Eternity dated 6/7/2001 + */ +inline +static CONSTFUNC fixed_t FixedDiv(fixed_t a, fixed_t b) +{ + //e6y: zg is a master of engineer science + if ((unsigned)D_abs(a) >> 14 < (unsigned)D_abs(b)) + { + fixed_t result; + asm ( + " idivl %3 ;" + : "=a" (result) + : "0" (a<<16), + "d" (a>>16), + "rm" (b) + : "%cc" + ); + return result; + } + return ((a^b)>>31) ^ INT_MAX; +} +# endif /* _MSC_VER */ + +#else /* I386_ASM */ +/* CPhipps - made __inline__ to inline, as specified in the gcc docs + * Also made const */ + +inline static CONSTFUNC fixed_t FixedDiv(fixed_t a, fixed_t b) +{ + return ((unsigned)D_abs(a)>>14) >= (unsigned)D_abs(b) ? ((a^b)>>31) ^ INT_MAX : + (fixed_t)(((int_64_t) a << FRACBITS) / b); +} + +#endif /* I386_ASM */ + +/* CPhipps - + * FixedMod - returns a % b, guaranteeing 0<=a +#include + +#include "doomdef.h" +#include "doomstat.h" +#include "dstrings.h" +#include "d_main.h" +#include "v_video.h" +#include "w_wad.h" +#include "r_main.h" +#include "hu_stuff.h" +#include "g_game.h" +#include "s_sound.h" +#include "sounds.h" +#include "m_menu.h" +#include "d_deh.h" +#include "m_misc.h" +#include "lprintf.h" +#include "am_map.h" +#include "i_main.h" +#include "i_system.h" +#include "i_video.h" +#include "i_sound.h" +#include "r_demo.h" +#include "r_fps.h" + +extern patchnum_t hu_font[HU_FONTSIZE]; +extern boolean message_dontfuckwithme; + +extern boolean chat_on; // in heads-up code + +// +// defaulted values +// + +int mouseSensitivity_horiz; // has default // killough +int mouseSensitivity_vert; // has default + +int showMessages; // Show messages has default, 0 = off, 1 = on + +int hide_setup=1; // killough 5/15/98 + +// Blocky mode, has default, 0 = high, 1 = normal +//int detailLevel; obsolete -- killough +int screenblocks; // has default + +int screenSize; // temp for screenblocks (0-9) + +int quickSaveSlot; // -1 = no quicksave slot picked! + +int messageToPrint; // 1 = message to be printed + +// CPhipps - static const +static const char* messageString; // ...and here is the message string! + +// message x & y +int messx; +int messy; +int messageLastMenuActive; + +boolean messageNeedsInput; // timed message = no input from user + +typedef void (*MessageRoutineFunction)(int response); +MessageRoutineFunction messageRoutine; + +#define SAVESTRINGSIZE 24 + +/* killough 8/15/98: when changes are allowed to sync-critical variables */ +static int allow_changes(void) +{ + return !(demoplayback || demorecording || netgame); +} + +static void M_UpdateCurrent(default_t* def) +{ + /* cph - requires rewrite of m_misc.c */ + if (def->current) { + if (allow_changes()) /* killough 8/15/98 */ + *def->current = *def->location.pi; + else if (*def->current != *def->location.pi) + warn_about_changes(S_LEVWARN); /* killough 8/15/98 */ + } +} + +int warning_about_changes, print_warning_about_changes; + +/* cphipps - M_DrawBackground renamed and moved to v_video.c */ +#define M_DrawBackground V_DrawBackground + +// we are going to be entering a savegame string + +int saveStringEnter; +int saveSlot; // which slot to save in +int saveCharIndex; // which char we're editing +// old save description before edit +char saveOldString[SAVESTRINGSIZE]; + +boolean inhelpscreens; // indicates we are in or just left a help screen + +boolean menuactive; // The menus are up + +#define SKULLXOFF -32 +#define LINEHEIGHT 16 + +char savegamestrings[10][SAVESTRINGSIZE]; + +// +// MENU TYPEDEFS +// + +typedef struct +{ + short status; // 0 = no cursor here, 1 = ok, 2 = arrows ok + char name[10]; + + // choice = menu item #. + // if status = 2, + // choice=0:leftarrow,1:rightarrow + void (*routine)(int choice); + char alphaKey; // hotkey in menu +} menuitem_t; + +typedef struct menu_s +{ + short numitems; // # of menu items + struct menu_s* prevMenu; // previous menu + menuitem_t* menuitems; // menu items + void (*routine)(); // draw routine + short x; + short y; // x,y of menu + short lastOn; // last item user was on in menu +} menu_t; + +short itemOn; // menu item skull is on (for Big Font menus) +short skullAnimCounter; // skull animation counter +short whichSkull; // which skull to draw (he blinks) + +// graphic name of skulls + +const char skullName[2][/*8*/9] = {"M_SKULL1","M_SKULL2"}; + +menu_t* currentMenu; // current menudef + +// phares 3/30/98 +// externs added for setup menus + +extern int mousebfire; +extern int mousebstrafe; +extern int mousebforward; +// proff 08/17/98: Added backward to mousebuttons +extern int mousebbackward; +extern int joybfire; +extern int joybstrafe; +extern int joybuse; +extern int joybspeed; +int mapcolor_me; // cph + +extern int map_point_coordinates; // killough 10/98 + +extern char* chat_macros[]; // chat macros +extern const char* shiftxform; +extern default_t defaults[]; +extern int numdefaults; + +// end of externs added for setup menus + +// +// PROTOTYPES +// +void M_NewGame(int choice); +void M_Episode(int choice); +void M_ChooseSkill(int choice); +void M_LoadGame(int choice); +void M_SaveGame(int choice); +void M_Options(int choice); +void M_EndGame(int choice); +void M_ReadThis(int choice); +void M_ReadThis2(int choice); +void M_QuitDOOM(int choice); + +void M_ChangeMessages(int choice); +void M_ChangeSensitivity(int choice); +void M_SfxVol(int choice); +void M_MusicVol(int choice); +/* void M_ChangeDetail(int choice); unused -- killough */ +void M_SizeDisplay(int choice); +void M_StartGame(int choice); +void M_Sound(int choice); + +void M_Mouse(int choice, int *sens); /* killough */ +void M_MouseVert(int choice); +void M_MouseHoriz(int choice); +void M_DrawMouse(void); + +void M_FinishReadThis(int choice); +void M_FinishHelp(int choice); // killough 10/98 +void M_LoadSelect(int choice); +void M_SaveSelect(int choice); +void M_ReadSaveStrings(void); +void M_QuickSave(void); +void M_QuickLoad(void); + +void M_DrawMainMenu(void); +void M_DrawReadThis1(void); +void M_DrawReadThis2(void); +void M_DrawNewGame(void); +void M_DrawEpisode(void); +void M_DrawOptions(void); +void M_DrawSound(void); +void M_DrawLoad(void); +void M_DrawSave(void); +void M_DrawSetup(void); // phares 3/21/98 +void M_DrawHelp (void); // phares 5/04/98 + +void M_DrawSaveLoadBorder(int x,int y); +void M_SetupNextMenu(menu_t *menudef); +void M_DrawThermo(int x,int y,int thermWidth,int thermDot); +void M_DrawEmptyCell(menu_t *menu,int item); +void M_DrawSelCell(menu_t *menu,int item); +void M_WriteText(int x, int y, const char *string); +int M_StringWidth(const char *string); +int M_StringHeight(const char *string); +void M_StartMessage(const char *string,MessageRoutineFunction routine,boolean input); +void M_StopMessage(void); +void M_ClearMenus (void); + +// phares 3/30/98 +// prototypes added to support Setup Menus and Extended HELP screens + +int M_GetKeyString(int,int); +void M_Setup(int choice); +void M_KeyBindings(int choice); +void M_Weapons(int); +void M_StatusBar(int); +void M_Automap(int); +void M_Enemy(int); +void M_Messages(int); +void M_ChatStrings(int); +void M_InitExtendedHelp(void); +void M_ExtHelpNextScreen(int); +void M_ExtHelp(int); +static int M_GetPixelWidth(const char*); +void M_DrawKeybnd(void); +void M_DrawWeapons(void); +static void M_DrawMenuString(int,int,int); +static void M_DrawStringCentered(int,int,int,const char*); +void M_DrawStatusHUD(void); +void M_DrawExtHelp(void); +void M_DrawAutoMap(void); +void M_DrawEnemy(void); +void M_DrawMessages(void); +void M_DrawChatStrings(void); +void M_Compat(int); // killough 10/98 +void M_ChangeDemoSmoothTurns(void); +void M_General(int); // killough 10/98 +void M_DrawCompat(void); // killough 10/98 +void M_DrawGeneral(void); // killough 10/98 +void M_FullScreen(void); // nathanh 01/01 + +menu_t NewDef; // phares 5/04/98 + +// end of prototypes added to support Setup Menus and Extended HELP screens + +///////////////////////////////////////////////////////////////////////////// +// +// DOOM MENUS +// + +///////////////////////////// +// +// MAIN MENU +// + +// main_e provides numerical values for which Big Font screen you're on + +enum +{ + newgame = 0, + loadgame, + savegame, + options, + readthis, + quitdoom, + main_end +} main_e; + +// +// MainMenu is the definition of what the main menu Screen should look +// like. Each entry shows that the cursor can land on each item (1), the +// built-in graphic lump (i.e. "M_NGAME") that should be displayed, +// the program which takes over when an item is selected, and the hotkey +// associated with the item. +// + +menuitem_t MainMenu[]= +{ + {1,"M_NGAME", M_NewGame, 'n'}, + {1,"M_OPTION",M_Options, 'o'}, + {1,"M_LOADG", M_LoadGame,'l'}, + {1,"M_SAVEG", M_SaveGame,'s'}, + // Another hickup with Special edition. + {1,"M_RDTHIS",M_ReadThis,'r'}, + {1,"M_QUITG", M_QuitDOOM,'q'} +}; + +menu_t MainDef = +{ + main_end, // number of menu items + NULL, // previous menu screen + MainMenu, // table that defines menu items + M_DrawMainMenu, // drawing routine + 97,64, // initial cursor position + 0 // last menu item the user was on +}; + +// +// M_DrawMainMenu +// + +void M_DrawMainMenu(void) +{ + // CPhipps - patch drawing updated + V_DrawNamePatch(94, 2, 0, "M_DOOM", CR_DEFAULT, VPT_STRETCH); +} + +///////////////////////////// +// +// Read This! MENU 1 & 2 +// + +// There are no menu items on the Read This! screens, so read_e just +// provides a placeholder to maintain structure. + +enum +{ + rdthsempty1, + read1_end +} read_e; + +enum +{ + rdthsempty2, + read2_end +} read_e2; + +enum // killough 10/98 +{ + helpempty, + help_end +} help_e; + + +// The definitions of the Read This! screens + +menuitem_t ReadMenu1[] = +{ + {1,"",M_ReadThis2,0} +}; + +menuitem_t ReadMenu2[]= +{ + {1,"",M_FinishReadThis,0} +}; + +menuitem_t HelpMenu[]= // killough 10/98 +{ + {1,"",M_FinishHelp,0} +}; + +menu_t ReadDef1 = +{ + read1_end, + &MainDef, + ReadMenu1, + M_DrawReadThis1, + 330,175, + //280,185, // killough 2/21/98: fix help screens + 0 +}; + +menu_t ReadDef2 = +{ + read2_end, + &ReadDef1, + ReadMenu2, + M_DrawReadThis2, + 330,175, + 0 +}; + +menu_t HelpDef = // killough 10/98 +{ + help_end, + &HelpDef, + HelpMenu, + M_DrawHelp, + 330,175, + 0 +}; + +// +// M_ReadThis +// + +void M_ReadThis(int choice) +{ + M_SetupNextMenu(&ReadDef1); +} + +void M_ReadThis2(int choice) +{ + M_SetupNextMenu(&ReadDef2); +} + +void M_FinishReadThis(int choice) +{ + M_SetupNextMenu(&MainDef); +} + +void M_FinishHelp(int choice) // killough 10/98 +{ + M_SetupNextMenu(&MainDef); +} + +// +// Read This Menus +// Had a "quick hack to fix romero bug" +// +// killough 10/98: updated with new screens + +void M_DrawReadThis1(void) +{ + inhelpscreens = true; + if (gamemode == shareware) + V_DrawNamePatch(0, 0, 0, "HELP2", CR_DEFAULT, VPT_STRETCH); + else + M_DrawCredits(); +} + +// +// Read This Menus - optional second page. +// +// killough 10/98: updated with new screens + +void M_DrawReadThis2(void) +{ + inhelpscreens = true; + if (gamemode == shareware) + M_DrawCredits(); + else + V_DrawNamePatch(0, 0, 0, "CREDIT", CR_DEFAULT, VPT_STRETCH); +} + +///////////////////////////// +// +// EPISODE SELECT +// + +// +// episodes_e provides numbers for the episode menu items. The default is +// 4, to accomodate Ultimate Doom. If the user is running anything else, +// this is accounted for in the code. +// + +enum +{ + ep1, + ep2, + ep3, + ep4, + ep_end +} episodes_e; + +// The definitions of the Episodes menu + +menuitem_t EpisodeMenu[]= +{ + {1,"M_EPI1", M_Episode,'k'}, + {1,"M_EPI2", M_Episode,'t'}, + {1,"M_EPI3", M_Episode,'i'}, + {1,"M_EPI4", M_Episode,'t'} +}; + +menu_t EpiDef = +{ + ep_end, // # of menu items + &MainDef, // previous menu + EpisodeMenu, // menuitem_t -> + M_DrawEpisode, // drawing routine -> + 48,63, // x,y + ep1 // lastOn +}; + +// +// M_Episode +// +int epi; + +void M_DrawEpisode(void) +{ + // CPhipps - patch drawing updated + V_DrawNamePatch(54, 38, 0, "M_EPISOD", CR_DEFAULT, VPT_STRETCH); +} + +void M_Episode(int choice) +{ + if ( (gamemode == shareware) && choice) { + M_StartMessage(s_SWSTRING,NULL,false); // Ty 03/27/98 - externalized + M_SetupNextMenu(&ReadDef1); + return; + } + + // Yet another hack... + if ( (gamemode == registered) && (choice > 2)) + { + lprintf( LO_WARN, + "M_Episode: 4th episode requires UltimateDOOM\n"); + choice = 0; + } + + epi = choice; + M_SetupNextMenu(&NewDef); +} + +///////////////////////////// +// +// NEW GAME +// + +// numerical values for the New Game menu items + +enum +{ + killthings, + toorough, + hurtme, + violence, + nightmare, + newg_end +} newgame_e; + +// The definitions of the New Game menu + +menuitem_t NewGameMenu[]= +{ + {1,"M_JKILL", M_ChooseSkill, 'i'}, + {1,"M_ROUGH", M_ChooseSkill, 'h'}, + {1,"M_HURT", M_ChooseSkill, 'h'}, + {1,"M_ULTRA", M_ChooseSkill, 'u'}, + {1,"M_NMARE", M_ChooseSkill, 'n'} +}; + +menu_t NewDef = +{ + newg_end, // # of menu items + &EpiDef, // previous menu + NewGameMenu, // menuitem_t -> + M_DrawNewGame, // drawing routine -> + 48,63, // x,y + hurtme // lastOn +}; + +// +// M_NewGame +// + +void M_DrawNewGame(void) +{ + // CPhipps - patch drawing updated + V_DrawNamePatch(96, 14, 0, "M_NEWG", CR_DEFAULT, VPT_STRETCH); + V_DrawNamePatch(54, 38, 0, "M_SKILL",CR_DEFAULT, VPT_STRETCH); +} + +/* cph - make `New Game' restart the level in a netgame */ +static void M_RestartLevelResponse(int ch) +{ + if (ch != 'y') + return; + + if (demorecording) + exit(0); + + currentMenu->lastOn = itemOn; + M_ClearMenus (); + G_RestartLevel (); +} + +void M_NewGame(int choice) +{ + if (netgame && !demoplayback) { + if (compatibility_level < lxdoom_1_compatibility) + M_StartMessage(s_NEWGAME,NULL,false); // Ty 03/27/98 - externalized + else // CPhipps - query restarting the level + M_StartMessage(s_RESTARTLEVEL,M_RestartLevelResponse,true); + return; + } + + if (demorecording) { /* killough 5/26/98: exclude during demo recordings */ + M_StartMessage("you can't start a new game\n" + "while recording a demo!\n\n"PRESSKEY, + NULL, false); // killough 5/26/98: not externalized + return; + } + + if ( gamemode == commercial ) + M_SetupNextMenu(&NewDef); + else + M_SetupNextMenu(&EpiDef); +} + +// CPhipps - static +static void M_VerifyNightmare(int ch) +{ + if (ch != 'y') + return; + + G_DeferedInitNew(nightmare,epi+1,1); + M_ClearMenus (); +} + +void M_ChooseSkill(int choice) +{ + if (choice == nightmare) + { // Ty 03/27/98 - externalized + M_StartMessage(s_NIGHTMARE,M_VerifyNightmare,true); + return; + } + + G_DeferedInitNew(choice,epi+1,1); + M_ClearMenus (); +} + +///////////////////////////// +// +// LOAD GAME MENU +// + +// numerical values for the Load Game slots + +enum +{ + load1, + load2, + load3, + load4, + load5, + load6, + load7, //jff 3/15/98 extend number of slots + load8, + load_end +} load_e; + +// The definitions of the Load Game screen + +menuitem_t LoadMenue[]= +{ + {1,"", M_LoadSelect,'1'}, + {1,"", M_LoadSelect,'2'}, + {1,"", M_LoadSelect,'3'}, + {1,"", M_LoadSelect,'4'}, + {1,"", M_LoadSelect,'5'}, + {1,"", M_LoadSelect,'6'}, + {1,"", M_LoadSelect,'7'}, //jff 3/15/98 extend number of slots + {1,"", M_LoadSelect,'8'}, +}; + +menu_t LoadDef = +{ + load_end, + &MainDef, + LoadMenue, + M_DrawLoad, + 80,34, //jff 3/15/98 move menu up + 0 +}; + +#define LOADGRAPHIC_Y 8 + +// +// M_LoadGame & Cie. +// + +void M_DrawLoad(void) +{ + int i; + + //jff 3/15/98 use symbolic load position + // CPhipps - patch drawing updated + V_DrawNamePatch(72 ,LOADGRAPHIC_Y, 0, "M_LOADG", CR_DEFAULT, VPT_STRETCH); + for (i = 0 ; i < load_end ; i++) { + M_DrawSaveLoadBorder(LoadDef.x,LoadDef.y+LINEHEIGHT*i); + M_WriteText(LoadDef.x,LoadDef.y+LINEHEIGHT*i,savegamestrings[i]); + } +} + +// +// Draw border for the savegame description +// + +void M_DrawSaveLoadBorder(int x,int y) +{ + int i; + + V_DrawNamePatch(x-8, y+7, 0, "M_LSLEFT", CR_DEFAULT, VPT_STRETCH); + + for (i = 0 ; i < 24 ; i++) + { + V_DrawNamePatch(x, y+7, 0, "M_LSCNTR", CR_DEFAULT, VPT_STRETCH); + x += 8; + } + + V_DrawNamePatch(x, y+7, 0, "M_LSRGHT", CR_DEFAULT, VPT_STRETCH); +} + +// +// User wants to load this game +// + +void M_LoadSelect(int choice) +{ + // CPhipps - Modified so savegame filename is worked out only internal + // to g_game.c, this only passes the slot. + + G_LoadGame(choice, false); // killough 3/16/98, 5/15/98: add slot, cmd + + M_ClearMenus (); +} + +// +// killough 5/15/98: add forced loadgames +// + +static void M_VerifyForcedLoadGame(int ch) +{ + if (ch=='y') + G_ForcedLoadGame(); + free((char*)messageString); // free the message strdup()'ed below + M_ClearMenus(); +} + +void M_ForcedLoadGame(const char *msg) +{ + M_StartMessage(strdup(msg), M_VerifyForcedLoadGame, true); // free()'d above +} + +// +// Selected from DOOM menu +// + +void M_LoadGame (int choice) +{ + /* killough 5/26/98: exclude during demo recordings + * cph - unless a new demo */ + if (demorecording && (compatibility_level < prboom_2_compatibility)) + { + M_StartMessage("you can't load a game\n" + "while recording an old demo!\n\n"PRESSKEY, + NULL, false); // killough 5/26/98: not externalized + return; + } + + M_SetupNextMenu(&LoadDef); + M_ReadSaveStrings(); +} + +///////////////////////////// +// +// SAVE GAME MENU +// + +// The definitions of the Save Game screen + +menuitem_t SaveMenu[]= +{ + {1,"", M_SaveSelect,'1'}, + {1,"", M_SaveSelect,'2'}, + {1,"", M_SaveSelect,'3'}, + {1,"", M_SaveSelect,'4'}, + {1,"", M_SaveSelect,'5'}, + {1,"", M_SaveSelect,'6'}, + {1,"", M_SaveSelect,'7'}, //jff 3/15/98 extend number of slots + {1,"", M_SaveSelect,'8'}, +}; + +menu_t SaveDef = +{ + load_end, // same number of slots as the Load Game screen + &MainDef, + SaveMenu, + M_DrawSave, + 80,34, //jff 3/15/98 move menu up + 0 +}; + +// +// M_ReadSaveStrings +// read the strings from the savegame files +// +void M_ReadSaveStrings(void) +{ + int i; + + for (i = 0 ; i < load_end ; i++) { + char name[PATH_MAX+1]; // killough 3/22/98 + FILE *fp; // killough 11/98: change to use stdio + + /* killough 3/22/98 + * cph - add not-demoplayback parameter */ + G_SaveGameName(name,sizeof(name),i,false); + fp = fopen(name,"rb"); + if (!fp) { // Ty 03/27/98 - externalized: + strcpy(&savegamestrings[i][0],s_EMPTYSTRING); + LoadMenue[i].status = 0; + continue; + } + fread(&savegamestrings[i], SAVESTRINGSIZE, 1, fp); + fclose(fp); + LoadMenue[i].status = 1; + } +} + +// +// M_SaveGame & Cie. +// +void M_DrawSave(void) +{ + int i; + + //jff 3/15/98 use symbolic load position + // CPhipps - patch drawing updated + V_DrawNamePatch(72, LOADGRAPHIC_Y, 0, "M_SAVEG", CR_DEFAULT, VPT_STRETCH); + for (i = 0 ; i < load_end ; i++) + { + M_DrawSaveLoadBorder(LoadDef.x,LoadDef.y+LINEHEIGHT*i); + M_WriteText(LoadDef.x,LoadDef.y+LINEHEIGHT*i,savegamestrings[i]); + } + + if (saveStringEnter) + { + i = M_StringWidth(savegamestrings[saveSlot]); + M_WriteText(LoadDef.x + i,LoadDef.y+LINEHEIGHT*saveSlot,"_"); + } +} + +// +// M_Responder calls this when user is finished +// +static void M_DoSave(int slot) +{ + G_SaveGame (slot,savegamestrings[slot]); + M_ClearMenus (); + + // PICK QUICKSAVE SLOT YET? + if (quickSaveSlot == -2) + quickSaveSlot = slot; +} + +// +// User wants to save. Start string input for M_Responder +// +void M_SaveSelect(int choice) +{ + // we are going to be intercepting all chars + saveStringEnter = 1; + + saveSlot = choice; + strcpy(saveOldString,savegamestrings[choice]); + if (!strcmp(savegamestrings[choice],s_EMPTYSTRING)) // Ty 03/27/98 - externalized + savegamestrings[choice][0] = 0; + saveCharIndex = strlen(savegamestrings[choice]); +} + +// +// Selected from DOOM menu +// +void M_SaveGame (int choice) +{ + // killough 10/6/98: allow savegames during single-player demo playback + if (!usergame && (!demoplayback || netgame)) + { + M_StartMessage(s_SAVEDEAD,NULL,false); // Ty 03/27/98 - externalized + return; + } + + if (gamestate != GS_LEVEL) + return; + + M_SetupNextMenu(&SaveDef); + M_ReadSaveStrings(); +} + +///////////////////////////// +// +// OPTIONS MENU +// + +// numerical values for the Options menu items + +enum +{ + general, // killough 10/98 + // killough 4/6/98: move setup to be a sub-menu of OPTIONs + setup, // phares 3/21/98 + endgame, + messages, + /* detail, obsolete -- killough */ + scrnsize, + option_empty1, + mousesens, + /* option_empty2, submenu now -- killough */ + soundvol, + opt_end +} options_e; + +// The definitions of the Options menu + +menuitem_t OptionsMenu[]= +{ + // killough 4/6/98: move setup to be a sub-menu of OPTIONs + {1,"M_GENERL", M_General, 'g'}, // killough 10/98 + {1,"M_SETUP", M_Setup, 's'}, // phares 3/21/98 + {1,"M_ENDGAM", M_EndGame,'e'}, + {1,"M_MESSG", M_ChangeMessages,'m'}, + /* {1,"M_DETAIL", M_ChangeDetail,'g'}, unused -- killough */ + {2,"M_SCRNSZ", M_SizeDisplay,'s'}, + {-1,"",0,0}, + {1,"M_MSENS", M_ChangeSensitivity,'m'}, + /* {-1,"",0}, replaced with submenu -- killough */ + {1,"M_SVOL", M_Sound,'s'} +}; + +menu_t OptionsDef = +{ + opt_end, + &MainDef, + OptionsMenu, + M_DrawOptions, + 60,37, + 0 +}; + +// +// M_Options +// +char detailNames[2][9] = {"M_GDHIGH","M_GDLOW"}; +char msgNames[2][9] = {"M_MSGOFF","M_MSGON"}; + + +void M_DrawOptions(void) +{ + // CPhipps - patch drawing updated + // proff/nicolas 09/20/98 -- changed for hi-res + V_DrawNamePatch(108, 15, 0, "M_OPTTTL", CR_DEFAULT, VPT_STRETCH); + + V_DrawNamePatch(OptionsDef.x + 120, OptionsDef.y+LINEHEIGHT*messages, 0, + msgNames[showMessages], CR_DEFAULT, VPT_STRETCH); + + M_DrawThermo(OptionsDef.x,OptionsDef.y+LINEHEIGHT*(scrnsize+1), + 9,screenSize); +} + +void M_Options(int choice) +{ + M_SetupNextMenu(&OptionsDef); +} + +///////////////////////////// +// +// M_QuitDOOM +// +int quitsounds[8] = +{ + sfx_pldeth, + sfx_dmpain, + sfx_popain, + sfx_slop, + sfx_telept, + sfx_posit1, + sfx_posit3, + sfx_sgtatk +}; + +int quitsounds2[8] = +{ + sfx_vilact, + sfx_getpow, + sfx_boscub, + sfx_slop, + sfx_skeswg, + sfx_kntdth, + sfx_bspact, + sfx_sgtatk +}; + +static void M_QuitResponse(int ch) +{ + if (ch != 'y') + return; + if ((!netgame || demoplayback) // killough 12/98 + && !nosfxparm && snd_card) // avoid delay if no sound card + { + int i; + + if (gamemode == commercial) + S_StartSound(NULL,quitsounds2[(gametic>>2)&7]); + else + S_StartSound(NULL,quitsounds[(gametic>>2)&7]); + + // wait till all sounds stopped or 3 seconds are over + i = 30; + while (i>0) { + I_uSleep(100000); // CPhipps - don't thrash cpu in this loop + if (!I_AnySoundStillPlaying()) + break; + i--; + } + } + exit(0); // killough +} + +void M_QuitDOOM(int choice) +{ + static char endstring[160]; + + // We pick index 0 which is language sensitive, + // or one at random, between 1 and maximum number. + // Ty 03/27/98 - externalized DOSY as a string s_DOSY that's in the sprintf + if (language != english) + sprintf(endstring,"%s\n\n%s",s_DOSY, endmsg[0] ); + else // killough 1/18/98: fix endgame message calculation: + sprintf(endstring,"%s\n\n%s", endmsg[gametic%(NUM_QUITMESSAGES-1)+1], s_DOSY); + + M_StartMessage(endstring,M_QuitResponse,true); +} + +///////////////////////////// +// +// SOUND VOLUME MENU +// + +// numerical values for the Sound Volume menu items +// The 'empty' slots are where the sliding scales appear. + +enum +{ + sfx_vol, + sfx_empty1, + music_vol, + sfx_empty2, + sound_end +} sound_e; + +// The definitions of the Sound Volume menu + +menuitem_t SoundMenu[]= +{ + {2,"M_SFXVOL",M_SfxVol,'s'}, + {-1,"",0,0}, + {2,"M_MUSVOL",M_MusicVol,'m'}, + {-1,"",0,0} +}; + +menu_t SoundDef = +{ + sound_end, + &OptionsDef, + SoundMenu, + M_DrawSound, + 80,64, + 0 +}; + +// +// Change Sfx & Music volumes +// + +void M_DrawSound(void) +{ + // CPhipps - patch drawing updated + V_DrawNamePatch(60, 38, 0, "M_SVOL", CR_DEFAULT, VPT_STRETCH); + + M_DrawThermo(SoundDef.x,SoundDef.y+LINEHEIGHT*(sfx_vol+1),16,snd_SfxVolume); + + M_DrawThermo(SoundDef.x,SoundDef.y+LINEHEIGHT*(music_vol+1),16,snd_MusicVolume); +} + +void M_Sound(int choice) +{ + M_SetupNextMenu(&SoundDef); +} + +void M_SfxVol(int choice) +{ + switch(choice) + { + case 0: + if (snd_SfxVolume) + snd_SfxVolume--; + break; + case 1: + if (snd_SfxVolume < 15) + snd_SfxVolume++; + break; + } + + S_SetSfxVolume(snd_SfxVolume /* *8 */); +} + +void M_MusicVol(int choice) +{ + switch(choice) + { + case 0: + if (snd_MusicVolume) + snd_MusicVolume--; + break; + case 1: + if (snd_MusicVolume < 15) + snd_MusicVolume++; + break; + } + + S_SetMusicVolume(snd_MusicVolume /* *8 */); +} + +///////////////////////////// +// +// MOUSE SENSITIVITY MENU -- killough +// + +// numerical values for the Mouse Sensitivity menu items +// The 'empty' slots are where the sliding scales appear. + +enum +{ + mouse_horiz, + mouse_empty1, + mouse_vert, + mouse_empty2, + mouse_end +} mouse_e; + +// The definitions of the Mouse Sensitivity menu + +menuitem_t MouseMenu[]= +{ + {2,"M_HORSEN",M_MouseHoriz,'h'}, + {-1,"",0,0}, + {2,"M_VERSEN",M_MouseVert,'v'}, + {-1,"",0,0} +}; + +menu_t MouseDef = +{ + mouse_end, + &OptionsDef, + MouseMenu, + M_DrawMouse, + 60,64, + 0 +}; + + +// I'm using a scale of 100 since I don't know what's normal -- killough. + +#define MOUSE_SENS_MAX 100 + +// +// Change Mouse Sensitivities -- killough +// + +void M_DrawMouse(void) +{ + int mhmx,mvmx; /* jff 4/3/98 clamp drawn position 99max mead */ + + // CPhipps - patch drawing updated + V_DrawNamePatch(60, 38, 0, "M_MSENS", CR_DEFAULT, VPT_STRETCH); + + //jff 4/3/98 clamp horizontal sensitivity display + mhmx = mouseSensitivity_horiz>99? 99 : mouseSensitivity_horiz; /*mead*/ + M_DrawThermo(MouseDef.x,MouseDef.y+LINEHEIGHT*(mouse_horiz+1),100,mhmx); + //jff 4/3/98 clamp vertical sensitivity display + mvmx = mouseSensitivity_vert>99? 99 : mouseSensitivity_vert; /*mead*/ + M_DrawThermo(MouseDef.x,MouseDef.y+LINEHEIGHT*(mouse_vert+1),100,mvmx); +} + +void M_ChangeSensitivity(int choice) +{ + M_SetupNextMenu(&MouseDef); // killough + + // switch(choice) + // { + // case 0: + // if (mouseSensitivity) + // mouseSensitivity--; + // break; + // case 1: + // if (mouseSensitivity < 9) + // mouseSensitivity++; + // break; + // } +} + +void M_MouseHoriz(int choice) +{ + M_Mouse(choice, &mouseSensitivity_horiz); +} + +void M_MouseVert(int choice) +{ + M_Mouse(choice, &mouseSensitivity_vert); +} + +void M_Mouse(int choice, int *sens) +{ + switch(choice) + { + case 0: + if (*sens) + --*sens; + break; + case 1: + if (*sens < 99) + ++*sens; /*mead*/ + break; + } +} + +///////////////////////////// +// +// M_QuickSave +// + +char tempstring[80]; + +static void M_QuickSaveResponse(int ch) +{ + if (ch == 'y') { + M_DoSave(quickSaveSlot); + S_StartSound(NULL,sfx_swtchx); + } +} + +void M_QuickSave(void) +{ + if (!usergame && (!demoplayback || netgame)) { /* killough 10/98 */ + S_StartSound(NULL,sfx_oof); + return; + } + + if (gamestate != GS_LEVEL) + return; + + if (quickSaveSlot < 0) { + M_StartControlPanel(); + M_ReadSaveStrings(); + M_SetupNextMenu(&SaveDef); + quickSaveSlot = -2; // means to pick a slot now + return; + } + sprintf(tempstring,s_QSPROMPT,savegamestrings[quickSaveSlot]); // Ty 03/27/98 - externalized + M_StartMessage(tempstring,M_QuickSaveResponse,true); +} + +///////////////////////////// +// +// M_QuickLoad +// + +static void M_QuickLoadResponse(int ch) +{ + if (ch == 'y') { + M_LoadSelect(quickSaveSlot); + S_StartSound(NULL,sfx_swtchx); + } +} + +void M_QuickLoad(void) +{ + // cph - removed restriction against quickload in a netgame + + if (demorecording) { // killough 5/26/98: exclude during demo recordings + M_StartMessage("you can't quickload\n" + "while recording a demo!\n\n"PRESSKEY, + NULL, false); // killough 5/26/98: not externalized + return; + } + + if (quickSaveSlot < 0) { + M_StartMessage(s_QSAVESPOT,NULL,false); // Ty 03/27/98 - externalized + return; + } + sprintf(tempstring,s_QLPROMPT,savegamestrings[quickSaveSlot]); // Ty 03/27/98 - externalized + M_StartMessage(tempstring,M_QuickLoadResponse,true); +} + +///////////////////////////// +// +// M_EndGame +// + +static void M_EndGameResponse(int ch) +{ + if (ch != 'y') + return; + + // killough 5/26/98: make endgame quit if recording or playing back demo + if (demorecording || singledemo) + G_CheckDemoStatus(); + + currentMenu->lastOn = itemOn; + M_ClearMenus (); + D_StartTitle (); +} + +void M_EndGame(int choice) +{ + if (netgame) + { + M_StartMessage(s_NETEND,NULL,false); // Ty 03/27/98 - externalized + return; + } + M_StartMessage(s_ENDGAME,M_EndGameResponse,true); // Ty 03/27/98 - externalized +} + +///////////////////////////// +// +// Toggle messages on/off +// + +void M_ChangeMessages(int choice) +{ + // warning: unused parameter `int choice' + choice = 0; + showMessages = 1 - showMessages; + + if (!showMessages) + players[consoleplayer].message = s_MSGOFF; // Ty 03/27/98 - externalized + else + players[consoleplayer].message = s_MSGON ; // Ty 03/27/98 - externalized + + message_dontfuckwithme = true; +} + +///////////////////////////// +// +// CHANGE DISPLAY SIZE +// +// jff 2/23/98 restored to pre-HUD state +// hud_active controlled soley by F5=key_detail (key_hud) +// hud_displayed is toggled by + or = in fullscreen +// hud_displayed is cleared by - + +void M_SizeDisplay(int choice) +{ + switch(choice) { + case 0: + if (screenSize > 0) { + screenblocks--; + screenSize--; + hud_displayed = 0; + } + break; + case 1: + if (screenSize < 8) { + screenblocks++; + screenSize++; + } + else + hud_displayed = !hud_displayed; + break; + } + R_SetViewSize (screenblocks /*, detailLevel obsolete -- killough */); +} + +// +// End of Original Menus +// +///////////////////////////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////////////////////////// +// +// SETUP MENU (phares) +// +// We've added a set of Setup Screens from which you can configure a number +// of variables w/o having to restart the game. There are 7 screens: +// +// Key Bindings +// Weapons +// Status Bar / HUD +// Automap +// Enemies +// Messages +// Chat Strings +// +// killough 10/98: added Compatibility and General menus +// + +///////////////////////////// +// +// booleans for setup screens +// these tell you what state the setup screens are in, and whether any of +// the overlay screens (automap colors, reset button message) should be +// displayed + +boolean setup_active = false; // in one of the setup screens +boolean set_keybnd_active = false; // in key binding setup screens +boolean set_weapon_active = false; // in weapons setup screen +boolean set_status_active = false; // in status bar/hud setup screen +boolean set_auto_active = false; // in automap setup screen +boolean set_enemy_active = false; // in enemies setup screen +boolean set_mess_active = false; // in messages setup screen +boolean set_chat_active = false; // in chat string setup screen +boolean setup_select = false; // changing an item +boolean setup_gather = false; // gathering keys for value +boolean colorbox_active = false; // color palette being shown +boolean default_verify = false; // verify reset defaults decision +boolean set_general_active = false; +boolean set_compat_active = false; + +///////////////////////////// +// +// set_menu_itemon is an index that starts at zero, and tells you which +// item on the current screen the cursor is sitting on. +// +// current_setup_menu is a pointer to the current setup menu table. + +static int set_menu_itemon; // which setup item is selected? // phares 3/98 +setup_menu_t* current_setup_menu; // points to current setup menu table + +///////////////////////////// +// +// The menu_buffer is used to construct strings for display on the screen. + +static char menu_buffer[64]; + +///////////////////////////// +// +// The setup_e enum is used to provide a unique number for each group of Setup +// Screens. + +enum +{ + set_compat, + set_key_bindings, + set_weapons, + set_statbar, + set_automap, + set_enemy, + set_messages, + set_chatstrings, + set_setup_end +} setup_e; + +int setup_screen; // the current setup screen. takes values from setup_e + +///////////////////////////// +// +// SetupMenu is the definition of what the main Setup Screen should look +// like. Each entry shows that the cursor can land on each item (1), the +// built-in graphic lump (i.e. "M_KEYBND") that should be displayed, +// the program which takes over when an item is selected, and the hotkey +// associated with the item. + +menuitem_t SetupMenu[]= +{ + {1,"M_COMPAT",M_Compat, 'p'}, + {1,"M_KEYBND",M_KeyBindings,'k'}, + {1,"M_WEAP" ,M_Weapons, 'w'}, + {1,"M_STAT" ,M_StatusBar, 's'}, + {1,"M_AUTO" ,M_Automap, 'a'}, + {1,"M_ENEM" ,M_Enemy, 'e'}, + {1,"M_MESS" ,M_Messages, 'm'}, + {1,"M_CHAT" ,M_ChatStrings,'c'}, +}; + +///////////////////////////// +// +// M_DoNothing does just that: nothing. Just a placeholder. + +static void M_DoNothing(int choice) +{ +} + +///////////////////////////// +// +// Items needed to satisfy the 'Big Font' menu structures: +// +// the generic_setup_e enum mimics the 'Big Font' menu structures, but +// means nothing to the Setup Menus. + +enum +{ + generic_setupempty1, + generic_setup_end +} generic_setup_e; + +// Generic_Setup is a do-nothing definition that the mainstream Menu code +// can understand, while the Setup Menu code is working. Another placeholder. + +menuitem_t Generic_Setup[] = +{ + {1,"",M_DoNothing,0} +}; + +///////////////////////////// +// +// SetupDef is the menu definition that the mainstream Menu code understands. +// This is used by M_Setup (below) to define what is drawn and what is done +// with the main Setup screen. + +menu_t SetupDef = +{ + set_setup_end, // number of Setup Menu items (Key Bindings, etc.) + &OptionsDef, // menu to return to when BACKSPACE is hit on this menu + SetupMenu, // definition of items to show on the Setup Screen + M_DrawSetup, // program that draws the Setup Screen + 59,37, // x,y position of the skull (modified when the skull is + // drawn). The skull is parked on the upper-left corner + // of the Setup screens, since it isn't needed as a cursor + 0 // last item the user was on for this menu +}; + +///////////////////////////// +// +// Here are the definitions of the individual Setup Menu screens. They +// follow the format of the 'Big Font' menu structures. See the comments +// for SetupDef (above) to help understand what each of these says. + +menu_t KeybndDef = +{ + generic_setup_end, + &SetupDef, + Generic_Setup, + M_DrawKeybnd, + 34,5, // skull drawn here + 0 +}; + +menu_t WeaponDef = +{ + generic_setup_end, + &SetupDef, + Generic_Setup, + M_DrawWeapons, + 34,5, // skull drawn here + 0 +}; + +menu_t StatusHUDDef = +{ + generic_setup_end, + &SetupDef, + Generic_Setup, + M_DrawStatusHUD, + 34,5, // skull drawn here + 0 +}; + +menu_t AutoMapDef = +{ + generic_setup_end, + &SetupDef, + Generic_Setup, + M_DrawAutoMap, + 34,5, // skull drawn here + 0 +}; + +menu_t EnemyDef = // phares 4/08/98 +{ + generic_setup_end, + &SetupDef, + Generic_Setup, + M_DrawEnemy, + 34,5, // skull drawn here + 0 +}; + +menu_t MessageDef = // phares 4/08/98 +{ + generic_setup_end, + &SetupDef, + Generic_Setup, + M_DrawMessages, + 34,5, // skull drawn here + 0 +}; + +menu_t ChatStrDef = // phares 4/10/98 +{ + generic_setup_end, + &SetupDef, + Generic_Setup, + M_DrawChatStrings, + 34,5, // skull drawn here + 0 +}; + +menu_t GeneralDef = // killough 10/98 +{ + generic_setup_end, + &OptionsDef, + Generic_Setup, + M_DrawGeneral, + 34,5, // skull drawn here + 0 +}; + +menu_t CompatDef = // killough 10/98 +{ + generic_setup_end, + &SetupDef, + Generic_Setup, + M_DrawCompat, + 34,5, // skull drawn here + 0 +}; + +///////////////////////////// +// +// Draws the Title for the main Setup screen + +void M_DrawSetup(void) +{ + // CPhipps - patch drawing updated + V_DrawNamePatch(124, 15, 0, "M_SETUP", CR_DEFAULT, VPT_STRETCH); +} + +///////////////////////////// +// +// Uses the SetupDef structure to draw the menu items for the main +// Setup screen + +void M_Setup(int choice) +{ + M_SetupNextMenu(&SetupDef); +} + +///////////////////////////// +// +// Data that's used by the Setup screen code +// +// Establish the message colors to be used + +#define CR_TITLE CR_GOLD +#define CR_SET CR_GREEN +#define CR_ITEM CR_RED +#define CR_HILITE CR_ORANGE +#define CR_SELECT CR_GRAY + +// Data used by the Automap color selection code + +#define CHIP_SIZE 7 // size of color block for colored items + +#define COLORPALXORIG ((320 - 16*(CHIP_SIZE+1))/2) +#define COLORPALYORIG ((200 - 16*(CHIP_SIZE+1))/2) + +#define PAL_BLACK 0 +#define PAL_WHITE 4 + +// Data used by the Chat String editing code + +#define CHAT_STRING_BFR_SIZE 128 + +// chat strings must fit in this screen space +// killough 10/98: reduced, for more general uses +#define MAXCHATWIDTH 272 + +int chat_index; +char* chat_string_buffer; // points to new chat strings while editing + +///////////////////////////// +// +// phares 4/17/98: +// Added 'Reset to Defaults' Button to Setup Menu screens +// This is a small button that sits in the upper-right-hand corner of +// the first screen for each group. It blinks when selected, thus the +// two patches, which it toggles back and forth. + +char ResetButtonName[2][8] = {"M_BUTT1","M_BUTT2"}; + +///////////////////////////// +// +// phares 4/18/98: +// Consolidate Item drawing code +// +// M_DrawItem draws the description of the provided item (the left-hand +// part). A different color is used for the text depending on whether the +// item is selected or not, or whether it's about to change. + +// CPhipps - static, hanging else removed, const parameter +static void M_DrawItem(const setup_menu_t* s) +{ + int x = s->m_x; + int y = s->m_y; + int flags = s->m_flags; + if (flags & S_RESET) + + // This item is the reset button + // Draw the 'off' version if this isn't the current menu item + // Draw the blinking version in tune with the blinking skull otherwise + + // proff/nicolas 09/20/98 -- changed for hi-res + // CPhipps - Patch drawing updated, reformatted + + V_DrawNamePatch(x, y, 0, ResetButtonName[(flags & (S_HILITE|S_SELECT)) ? whichSkull : 0], + CR_DEFAULT, VPT_STRETCH); + + else { // Draw the item string + char *p, *t; + int w = 0; + int color = + flags & S_SELECT ? CR_SELECT : + flags & S_HILITE ? CR_HILITE : + flags & (S_TITLE|S_NEXT|S_PREV) ? CR_TITLE : CR_ITEM; // killough 10/98 + + /* killough 10/98: + * Enhance to support multiline text separated by newlines. + * This supports multiline items on horizontally-crowded menus. + */ + + for (p = t = strdup(s->m_text); (p = strtok(p,"\n")); y += 8, p = NULL) + { /* killough 10/98: support left-justification: */ + strcpy(menu_buffer,p); + if (!(flags & S_LEFTJUST)) + w = M_GetPixelWidth(menu_buffer) + 4; + M_DrawMenuString(x - w, y ,color); + } + free(t); + } +} + +// If a number item is being changed, allow up to N keystrokes to 'gather' +// the value. Gather_count tells you how many you have so far. The legality +// of what is gathered is determined by the low/high settings for the item. + +#define MAXGATHER 5 +int gather_count; +char gather_buffer[MAXGATHER+1]; // killough 10/98: make input character-based + +///////////////////////////// +// +// phares 4/18/98: +// Consolidate Item Setting drawing code +// +// M_DrawSetting draws the setting of the provided item (the right-hand +// part. It determines the text color based on whether the item is +// selected or being changed. Then, depending on the type of item, it +// displays the appropriate setting value: yes/no, a key binding, a number, +// a paint chip, etc. + +static void M_DrawSetting(const setup_menu_t* s) +{ + int x = s->m_x, y = s->m_y, flags = s->m_flags, color; + + // Determine color of the text. This may or may not be used later, + // depending on whether the item is a text string or not. + + color = flags & S_SELECT ? CR_SELECT : flags & S_HILITE ? CR_HILITE : CR_SET; + + // Is the item a YES/NO item? + + if (flags & S_YESNO) { + strcpy(menu_buffer,*s->var.def->location.pi ? "YES" : "NO"); + M_DrawMenuString(x,y,color); + return; + } + + // Is the item a simple number? + + if (flags & S_NUM) { + // killough 10/98: We must draw differently for items being gathered. + if (flags & (S_HILITE|S_SELECT) && setup_gather) { + gather_buffer[gather_count] = 0; + strcpy(menu_buffer, gather_buffer); + } + else + sprintf(menu_buffer,"%d",*s->var.def->location.pi); + M_DrawMenuString(x,y,color); + return; + } + + // Is the item a key binding? + + if (flags & S_KEY) { // Key Binding + int *key = s->var.m_key; + + // Draw the key bound to the action + + if (key) { + M_GetKeyString(*key,0); // string to display + if (key == &key_use) { + // For the 'use' key, you have to build the string + + if (s->m_mouse) + sprintf(menu_buffer+strlen(menu_buffer), "/DBL-CLK MB%d",*s->m_mouse+1); + if (s->m_joy) + sprintf(menu_buffer+strlen(menu_buffer), "/JSB%d",*s->m_joy+1); + } + else if (key == &key_up || key == &key_speed || + key == &key_fire || key == &key_strafe) + { + if (s->m_mouse) + sprintf(menu_buffer+strlen(menu_buffer), "/MB%d", + *s->m_mouse+1); + if (s->m_joy) + sprintf(menu_buffer+strlen(menu_buffer), "/JSB%d", + *s->m_joy+1); + } + M_DrawMenuString(x,y,color); + } + return; + } + + // Is the item a weapon number? + // OR, Is the item a colored text string from the Automap? + // + // killough 10/98: removed special code, since the rest of the engine + // already takes care of it, and this code prevented the user from setting + // their overall weapons preferences while playing Doom 1. + // + // killough 11/98: consolidated weapons code with color range code + + if (flags & (S_WEAP|S_CRITEM)) // weapon number or color range + { + sprintf(menu_buffer,"%d", *s->var.def->location.pi); + M_DrawMenuString(x,y, flags & S_CRITEM ? *s->var.def->location.pi : color); + return; + } + + // Is the item a paint chip? + + if (flags & S_COLOR) // Automap paint chip + { + int ch; + + ch = *s->var.def->location.pi; + // proff 12/6/98: Drawing of colorchips completly changed for hi-res, it now uses a patch + // draw the paint chip + V_FillRect(0, x*SCREENWIDTH/320, (y-1)*SCREENHEIGHT/200, + 8*SCREENWIDTH/320, 8*SCREENHEIGHT/200, + PAL_BLACK); + V_FillRect(0, (x+1)*SCREENWIDTH/320, y*SCREENHEIGHT/200, + 6*SCREENWIDTH/320, 6*SCREENHEIGHT/200, + (byte)ch); + + if (!ch) // don't show this item in automap mode + V_DrawNamePatch(x+1,y,0,"M_PALNO", CR_DEFAULT, VPT_STRETCH); + return; + } + + // Is the item a chat string? + // killough 10/98: or a filename? + + if (flags & S_STRING) { + /* cph - cast to char* as it's really a Z_Strdup'd string (see m_misc.h) */ + char *text = (char*)*s->var.def->location.ppsz; + + // Are we editing this string? If so, display a cursor under + // the correct character. + + if (setup_select && (s->m_flags & (S_HILITE|S_SELECT))) { + int cursor_start, char_width; + char c[2]; + + // If the string is too wide for the screen, trim it back, + // one char at a time until it fits. This should only occur + // while you're editing the string. + + while (M_GetPixelWidth(text) >= MAXCHATWIDTH) { + int len = strlen(text); + text[--len] = 0; + if (chat_index > len) + chat_index--; + } + + // Find the distance from the beginning of the string to + // where the cursor should be drawn, plus the width of + // the char the cursor is under.. + + *c = text[chat_index]; // hold temporarily + c[1] = 0; + char_width = M_GetPixelWidth(c); + if (char_width == 1) + char_width = 7; // default for end of line + text[chat_index] = 0; // NULL to get cursor position + cursor_start = M_GetPixelWidth(text); + text[chat_index] = *c; // replace stored char + + // Now draw the cursor + // proff 12/6/98: Drawing of cursor changed for hi-res + V_FillRect(0, ((x+cursor_start-1)*SCREENWIDTH)/320, (y*SCREENHEIGHT)/200, + (char_width*SCREENWIDTH)/320, 9*SCREENHEIGHT/200, PAL_WHITE); + } + + // Draw the setting for the item + + strcpy(menu_buffer,text); + M_DrawMenuString(x,y,color); + return; + } + + // Is the item a selection of choices? + + if (flags & S_CHOICE) { + if (s->var.def->type == def_int) { + if (s->selectstrings == NULL) { + sprintf(menu_buffer,"%d",*s->var.def->location.pi); + } else { + strcpy(menu_buffer,s->selectstrings[*s->var.def->location.pi]); + } + } + + if (s->var.def->type == def_str) { + sprintf(menu_buffer,"%s", *s->var.def->location.ppsz); + } + + M_DrawMenuString(x,y,color); + return; + } +} + +///////////////////////////// +// +// M_DrawScreenItems takes the data for each menu item and gives it to +// the drawing routines above. + +// CPhipps - static, const parameter, formatting +static void M_DrawScreenItems(const setup_menu_t* src) +{ + if (print_warning_about_changes > 0) { /* killough 8/15/98: print warning */ + if (warning_about_changes & S_BADVAL) { + strcpy(menu_buffer, "Value out of Range"); + M_DrawMenuString(100,176,CR_RED); + } else if (warning_about_changes & S_PRGWARN) { + strcpy(menu_buffer, "Warning: Program must be restarted to see changes"); + M_DrawMenuString(3, 176, CR_RED); + } else if (warning_about_changes & S_BADVID) { + strcpy(menu_buffer, "Video mode not supported"); + M_DrawMenuString(80,176,CR_RED); + } else { + strcpy(menu_buffer, "Warning: Changes are pending until next game"); + M_DrawMenuString(18,184,CR_RED); + } + } + + while (!(src->m_flags & S_END)) { + + // See if we're to draw the item description (left-hand part) + + if (src->m_flags & S_SHOWDESC) + M_DrawItem(src); + + // See if we're to draw the setting (right-hand part) + + if (src->m_flags & S_SHOWSET) + M_DrawSetting(src); + src++; + } +} + +///////////////////////////// +// +// Data used to draw the "are you sure?" dialogue box when resetting +// to defaults. + +#define VERIFYBOXXORG 66 +#define VERIFYBOXYORG 88 +#define PAL_GRAY1 91 +#define PAL_GRAY2 98 +#define PAL_GRAY3 105 + +// And the routine to draw it. + +static void M_DrawDefVerify(void) +{ + // proff 12/6/98: Drawing of verify box changed for hi-res, it now uses a patch + V_DrawNamePatch(VERIFYBOXXORG,VERIFYBOXYORG,0,"M_VBOX",CR_DEFAULT,VPT_STRETCH); + // The blinking messages is keyed off of the blinking of the + // cursor skull. + + if (whichSkull) { // blink the text + strcpy(menu_buffer,"Reset to defaults? (Y or N)"); + M_DrawMenuString(VERIFYBOXXORG+8,VERIFYBOXYORG+8,CR_RED); + } +} + + +///////////////////////////// +// +// phares 4/18/98: +// M_DrawInstructions writes the instruction text just below the screen title +// +// cph 2006/08/06 - go back to the Boom version, and then clean up by using +// M_DrawStringCentered (much better than all those magic 'x' valies!) + +static void M_DrawInstructions(void) +{ + int flags = current_setup_menu[set_menu_itemon].m_flags; + + // There are different instruction messages depending on whether you + // are changing an item or just sitting on it. + + if (setup_select) { + switch (flags & (S_KEY | S_YESNO | S_WEAP | S_NUM | S_COLOR | S_CRITEM | S_CHAT | S_RESET | S_FILE | S_CHOICE)) { + case S_KEY: + // See if a joystick or mouse button setting is allowed for + // this item. + if (current_setup_menu[set_menu_itemon].m_mouse || current_setup_menu[set_menu_itemon].m_joy) + M_DrawStringCentered(160, 20, CR_SELECT, "Press key or button for this action"); + else + M_DrawStringCentered(160, 20, CR_SELECT, "Press key for this action"); + break; + + case S_YESNO: + M_DrawStringCentered(160, 20, CR_SELECT, "Press ENTER key to toggle"); + break; + case S_WEAP: + M_DrawStringCentered(160, 20, CR_SELECT, "Enter weapon number"); + break; + case S_NUM: + M_DrawStringCentered(160, 20, CR_SELECT, "Enter value. Press ENTER when finished."); + break; + case S_COLOR: + M_DrawStringCentered(160, 20, CR_SELECT, "Select color and press enter"); + break; + case S_CRITEM: + M_DrawStringCentered(160, 20, CR_SELECT, "Enter value"); + break; + case S_CHAT: + M_DrawStringCentered(160, 20, CR_SELECT, "Type/edit chat string and Press ENTER"); + break; + case S_FILE: + M_DrawStringCentered(160, 20, CR_SELECT, "Type/edit filename and Press ENTER"); + break; + case S_CHOICE: + M_DrawStringCentered(160, 20, CR_SELECT, "Press left or right to choose"); + break; + case S_RESET: + break; +#ifdef SIMPLECHECKS + default: + lprintf(LO_WARN,"Unrecognised menu item type %d", flags); +#endif + } + } else { + if (flags & S_RESET) + M_DrawStringCentered(160, 20, CR_HILITE, "Press ENTER key to reset to defaults"); + else + M_DrawStringCentered(160, 20, CR_HILITE, "Press Enter to Change"); + } +} + + +///////////////////////////// +// +// The Key Binding Screen tables. + +#define KB_X 160 +#define KB_PREV 57 +#define KB_NEXT 310 +#define KB_Y 31 + +// phares 4/16/98: +// X,Y position of reset button. This is the same for every screen, and is +// only defined once here. + +#define X_BUTTON 301 +#define Y_BUTTON 3 + +// Definitions of the (in this case) four key binding screens. + +setup_menu_t keys_settings1[]; +setup_menu_t keys_settings2[]; +setup_menu_t keys_settings3[]; +setup_menu_t keys_settings4[]; + +// The table which gets you from one screen table to the next. + +setup_menu_t* keys_settings[] = +{ + keys_settings1, + keys_settings2, + keys_settings3, + keys_settings4, + NULL +}; + +int mult_screens_index; // the index of the current screen in a set + +// Here's an example from this first screen, with explanations. +// +// { +// "STRAFE", // The description of the item ('strafe' key) +// S_KEY, // This is a key binding item +// m_scrn, // It belongs to the m_scrn group. Its key cannot be +// // bound to two items in this group. +// KB_X, // The X offset of the start of the right-hand side +// KB_Y+ 8*8, // The Y offset of the start of the right-hand side. +// // Always given in multiples off a baseline. +// &key_strafe, // The variable that holds the key value bound to this +// OR a string that holds the config variable name. +// OR a pointer to another setup_menu +// &mousebstrafe, // The variable that holds the mouse button bound to + // this. If zero, no mouse button can be bound here. +// &joybstrafe, // The variable that holds the joystick button bound to + // this. If zero, no mouse button can be bound here. +// } + +// The first Key Binding screen table. +// Note that the Y values are ascending. If you need to add something to +// this table, (well, this one's not a good example, because it's full) +// you need to make sure the Y values still make sense so everything gets +// displayed. +// +// Note also that the first screen of each set has a line for the reset +// button. If there is more than one screen in a set, the others don't get +// the reset button. +// +// Note also that this screen has a "NEXT ->" line. This acts like an +// item, in that 'activating' it moves you along to the next screen. If +// there's a "<- PREV" item on a screen, it behaves similarly, moving you +// to the previous screen. If you leave these off, you can't move from +// screen to screen. + +setup_menu_t keys_settings1[] = // Key Binding screen strings +{ + {"MOVEMENT" ,S_SKIP|S_TITLE,m_null,KB_X,KB_Y,{NULL},NULL,NULL,NULL,NULL}, + {"FORWARD" ,S_KEY ,m_scrn,KB_X,KB_Y+1*8,{&key_up},&mousebforward,NULL,NULL,NULL}, + {"BACKWARD" ,S_KEY ,m_scrn,KB_X,KB_Y+2*8,{&key_down},NULL,NULL,NULL,NULL}, + {"TURN LEFT" ,S_KEY ,m_scrn,KB_X,KB_Y+3*8,{&key_left},NULL,NULL,NULL,NULL}, + {"TURN RIGHT" ,S_KEY ,m_scrn,KB_X,KB_Y+4*8,{&key_right},NULL,NULL,NULL,NULL}, + {"RUN" ,S_KEY ,m_scrn,KB_X,KB_Y+5*8,{&key_speed},0,&joybspeed,NULL,NULL}, + {"STRAFE LEFT" ,S_KEY ,m_scrn,KB_X,KB_Y+6*8,{&key_strafeleft},NULL,NULL,NULL,NULL}, + {"STRAFE RIGHT",S_KEY ,m_scrn,KB_X,KB_Y+7*8,{&key_straferight},NULL,NULL,NULL,NULL}, + {"STRAFE" ,S_KEY ,m_scrn,KB_X,KB_Y+8*8,{&key_strafe},&mousebstrafe,&joybstrafe,NULL,NULL}, + {"AUTORUN" ,S_KEY ,m_scrn,KB_X,KB_Y+9*8,{&key_autorun},NULL,NULL,NULL,NULL}, + {"180 TURN" ,S_KEY ,m_scrn,KB_X,KB_Y+10*8,{&key_reverse},NULL,NULL,NULL,NULL}, + {"USE" ,S_KEY ,m_scrn,KB_X,KB_Y+11*8,{&key_use},&mousebforward,&joybuse,NULL,NULL}, + + {"MENUS" ,S_SKIP|S_TITLE,m_null,KB_X,KB_Y+12*8,{NULL},NULL,NULL,NULL,NULL}, + {"NEXT ITEM" ,S_KEY ,m_menu,KB_X,KB_Y+13*8,{&key_menu_down},NULL,NULL,NULL,NULL}, + {"PREV ITEM" ,S_KEY ,m_menu,KB_X,KB_Y+14*8,{&key_menu_up},NULL,NULL,NULL,NULL}, + {"LEFT" ,S_KEY ,m_menu,KB_X,KB_Y+15*8,{&key_menu_left},NULL,NULL,NULL,NULL}, + {"RIGHT" ,S_KEY ,m_menu,KB_X,KB_Y+16*8,{&key_menu_right},NULL,NULL,NULL,NULL}, + {"BACKSPACE" ,S_KEY ,m_menu,KB_X,KB_Y+17*8,{&key_menu_backspace},NULL,NULL,NULL,NULL}, + {"SELECT ITEM" ,S_KEY ,m_menu,KB_X,KB_Y+18*8,{&key_menu_enter},NULL,NULL,NULL,NULL}, + {"EXIT" ,S_KEY ,m_menu,KB_X,KB_Y+19*8,{&key_menu_escape},NULL,NULL,NULL,NULL}, + + // Button for resetting to defaults + {0,S_RESET,m_null,X_BUTTON,Y_BUTTON,{NULL},NULL,NULL,NULL,NULL}, + + {"NEXT ->",S_SKIP|S_NEXT,m_null,KB_NEXT,KB_Y+20*8, {keys_settings2},NULL,NULL,NULL,NULL}, + + // Final entry + {0,S_SKIP|S_END,m_null,0,0,{NULL},NULL,NULL,NULL,NULL} + +}; + +setup_menu_t keys_settings2[] = // Key Binding screen strings +{ + {"SCREEN" ,S_SKIP|S_TITLE,m_null,KB_X,KB_Y,{NULL},NULL,NULL,NULL,NULL}, + + // phares 4/13/98: + // key_help and key_escape can no longer be rebound. This keeps the + // player from getting themselves in a bind where they can't remember how + // to get to the menus, and can't remember how to get to the help screen + // to give them a clue as to how to get to the menus. :) + + // Also, the keys assigned to these functions cannot be bound to other + // functions. Introduce an S_KEEP flag to show that you cannot swap this + // key with other keys in the same 'group'. (m_scrn, etc.) + + {"HELP" ,S_SKIP|S_KEEP ,m_scrn,0 ,0 ,{&key_help},NULL,NULL,NULL,NULL}, + {"MENU" ,S_SKIP|S_KEEP ,m_scrn,0 ,0 ,{&key_escape},NULL,NULL,NULL,NULL}, + // killough 10/98: hotkey for entering setup menu: + {"SETUP" ,S_KEY ,m_scrn,KB_X,KB_Y+ 1*8,{&key_setup},NULL,NULL,NULL,NULL}, + {"PAUSE" ,S_KEY ,m_scrn,KB_X,KB_Y+ 2*8,{&key_pause},NULL,NULL,NULL,NULL}, + {"AUTOMAP" ,S_KEY ,m_scrn,KB_X,KB_Y+ 3*8,{&key_map},NULL,NULL,NULL,NULL}, + {"VOLUME" ,S_KEY ,m_scrn,KB_X,KB_Y+ 4*8,{&key_soundvolume},NULL,NULL,NULL,NULL}, + {"HUD" ,S_KEY ,m_scrn,KB_X,KB_Y+ 5*8,{&key_hud},NULL,NULL,NULL,NULL}, + {"MESSAGES" ,S_KEY ,m_scrn,KB_X,KB_Y+ 6*8,{&key_messages},NULL,NULL,NULL,NULL}, + {"GAMMA FIX" ,S_KEY ,m_scrn,KB_X,KB_Y+ 7*8,{&key_gamma},NULL,NULL,NULL,NULL}, + {"SPY" ,S_KEY ,m_scrn,KB_X,KB_Y+ 8*8,{&key_spy},NULL,NULL,NULL,NULL}, + {"LARGER VIEW" ,S_KEY ,m_scrn,KB_X,KB_Y+ 9*8,{&key_zoomin},NULL,NULL,NULL,NULL}, + {"SMALLER VIEW",S_KEY ,m_scrn,KB_X,KB_Y+10*8,{&key_zoomout},NULL,NULL,NULL,NULL}, + {"SCREENSHOT" ,S_KEY ,m_scrn,KB_X,KB_Y+11*8,{&key_screenshot},NULL,NULL,NULL,NULL}, + {"GAME" ,S_SKIP|S_TITLE,m_null,KB_X,KB_Y+12*8,{NULL},NULL,NULL,NULL,NULL}, + {"SAVE" ,S_KEY ,m_scrn,KB_X,KB_Y+13*8,{&key_savegame},NULL,NULL,NULL,NULL}, + {"LOAD" ,S_KEY ,m_scrn,KB_X,KB_Y+14*8,{&key_loadgame},NULL,NULL,NULL,NULL}, + {"QUICKSAVE" ,S_KEY ,m_scrn,KB_X,KB_Y+15*8,{&key_quicksave},NULL,NULL,NULL,NULL}, + {"QUICKLOAD" ,S_KEY ,m_scrn,KB_X,KB_Y+16*8,{&key_quickload},NULL,NULL,NULL,NULL}, + {"END GAME" ,S_KEY ,m_scrn,KB_X,KB_Y+17*8,{&key_endgame},NULL,NULL,NULL,NULL}, + {"QUIT" ,S_KEY ,m_scrn,KB_X,KB_Y+18*8,{&key_quit},NULL,NULL,NULL,NULL}, + {"<- PREV", S_SKIP|S_PREV,m_null,KB_PREV,KB_Y+20*8, {keys_settings1},NULL,NULL,NULL,NULL}, + {"NEXT ->", S_SKIP|S_NEXT,m_null,KB_NEXT,KB_Y+20*8, {keys_settings3},NULL,NULL,NULL,NULL}, + + // Final entry + + {0,S_SKIP|S_END,m_null,0,0,{NULL},NULL,NULL,NULL,NULL} +}; + +setup_menu_t keys_settings3[] = // Key Binding screen strings +{ + {"WEAPONS" ,S_SKIP|S_TITLE,m_null,KB_X,KB_Y,{NULL},NULL,NULL,NULL,NULL}, + {"FIST" ,S_KEY ,m_scrn,KB_X,KB_Y+ 1*8,{&key_weapon1},NULL,NULL,NULL,NULL}, + {"PISTOL" ,S_KEY ,m_scrn,KB_X,KB_Y+ 2*8,{&key_weapon2},NULL,NULL,NULL,NULL}, + {"SHOTGUN" ,S_KEY ,m_scrn,KB_X,KB_Y+ 3*8,{&key_weapon3},NULL,NULL,NULL,NULL}, + {"CHAINGUN",S_KEY ,m_scrn,KB_X,KB_Y+ 4*8,{&key_weapon4},NULL,NULL,NULL,NULL}, + {"ROCKET" ,S_KEY ,m_scrn,KB_X,KB_Y+ 5*8,{&key_weapon5},NULL,NULL,NULL,NULL}, + {"PLASMA" ,S_KEY ,m_scrn,KB_X,KB_Y+ 6*8,{&key_weapon6},NULL,NULL,NULL,NULL}, + {"BFG", S_KEY ,m_scrn,KB_X,KB_Y+ 7*8,{&key_weapon7},NULL,NULL,NULL,NULL}, + {"CHAINSAW",S_KEY ,m_scrn,KB_X,KB_Y+ 8*8,{&key_weapon8},NULL,NULL,NULL,NULL}, + {"SSG" ,S_KEY ,m_scrn,KB_X,KB_Y+ 9*8,{&key_weapon9},NULL,NULL,NULL,NULL}, + {"BEST" ,S_KEY ,m_scrn,KB_X,KB_Y+10*8,{&key_weapontoggle},NULL,NULL,NULL,NULL}, + {"FIRE" ,S_KEY ,m_scrn,KB_X,KB_Y+11*8,{&key_fire},&mousebfire,&joybfire,NULL,NULL}, + + {"<- PREV",S_SKIP|S_PREV,m_null,KB_PREV,KB_Y+20*8, {keys_settings2},NULL,NULL,NULL,NULL}, + {"NEXT ->",S_SKIP|S_NEXT,m_null,KB_NEXT,KB_Y+20*8, {keys_settings4},NULL,NULL,NULL,NULL}, + + // Final entry + + {0,S_SKIP|S_END,m_null,0,0,{NULL},NULL,NULL,NULL,NULL} + +}; + +setup_menu_t keys_settings4[] = // Key Binding screen strings +{ + {"AUTOMAP" ,S_SKIP|S_TITLE,m_null,KB_X,KB_Y,{NULL},NULL,NULL,NULL,NULL}, + {"FOLLOW" ,S_KEY ,m_map ,KB_X,KB_Y+ 1*8,{&key_map_follow},NULL,NULL,NULL,NULL}, + {"ZOOM IN" ,S_KEY ,m_map ,KB_X,KB_Y+ 2*8,{&key_map_zoomin},NULL,NULL,NULL,NULL}, + {"ZOOM OUT" ,S_KEY ,m_map ,KB_X,KB_Y+ 3*8,{&key_map_zoomout},NULL,NULL,NULL,NULL}, + {"SHIFT UP" ,S_KEY ,m_map ,KB_X,KB_Y+ 4*8,{&key_map_up},NULL,NULL,NULL,NULL}, + {"SHIFT DOWN" ,S_KEY ,m_map ,KB_X,KB_Y+ 5*8,{&key_map_down},NULL,NULL,NULL,NULL}, + {"SHIFT LEFT" ,S_KEY ,m_map ,KB_X,KB_Y+ 6*8,{&key_map_left},NULL,NULL,NULL,NULL}, + {"SHIFT RIGHT",S_KEY ,m_map ,KB_X,KB_Y+ 7*8,{&key_map_right},NULL,NULL,NULL,NULL}, + {"MARK PLACE" ,S_KEY ,m_map ,KB_X,KB_Y+ 8*8,{&key_map_mark},NULL,NULL,NULL,NULL}, + {"CLEAR MARKS",S_KEY ,m_map ,KB_X,KB_Y+ 9*8,{&key_map_clear},NULL,NULL,NULL,NULL}, + {"FULL/ZOOM" ,S_KEY ,m_map ,KB_X,KB_Y+10*8,{&key_map_gobig},NULL,NULL,NULL,NULL}, + {"GRID" ,S_KEY ,m_map ,KB_X,KB_Y+11*8,{&key_map_grid},NULL,NULL,NULL,NULL}, + + {"CHATTING" ,S_SKIP|S_TITLE,m_null,KB_X,KB_Y+12*8,{NULL},NULL,NULL,NULL,NULL}, + {"BEGIN CHAT" ,S_KEY ,m_scrn,KB_X,KB_Y+13*8,{&key_chat},NULL,NULL,NULL,NULL}, + {"PLAYER 1" ,S_KEY ,m_scrn,KB_X,KB_Y+14*8,{&destination_keys[0]},NULL,NULL,NULL,NULL}, + {"PLAYER 2" ,S_KEY ,m_scrn,KB_X,KB_Y+15*8,{&destination_keys[1]},NULL,NULL,NULL,NULL}, + {"PLAYER 3" ,S_KEY ,m_scrn,KB_X,KB_Y+16*8,{&destination_keys[2]},NULL,NULL,NULL,NULL}, + {"PLAYER 4" ,S_KEY ,m_scrn,KB_X,KB_Y+17*8,{&destination_keys[3]},NULL,NULL,NULL,NULL}, + {"BACKSPACE" ,S_KEY ,m_scrn,KB_X,KB_Y+18*8,{&key_backspace},NULL,NULL,NULL,NULL}, + {"ENTER" ,S_KEY ,m_scrn,KB_X,KB_Y+19*8,{&key_enter},NULL,NULL,NULL,NULL}, + + {"<- PREV" ,S_SKIP|S_PREV,m_null,KB_PREV,KB_Y+20*8, {keys_settings3},NULL,NULL,NULL,NULL}, + + // Final entry + + {0,S_SKIP|S_END,m_null,0,0,{NULL},NULL,NULL,NULL,NULL} + +}; + +// Setting up for the Key Binding screen. Turn on flags, set pointers, +// locate the first item on the screen where the cursor is allowed to +// land. + +void M_KeyBindings(int choice) +{ + M_SetupNextMenu(&KeybndDef); + + setup_active = true; + setup_screen = ss_keys; + set_keybnd_active = true; + setup_select = false; + default_verify = false; + setup_gather = false; + mult_screens_index = 0; + current_setup_menu = keys_settings[0]; + set_menu_itemon = 0; + while (current_setup_menu[set_menu_itemon++].m_flags & S_SKIP); + current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE; +} + +// The drawing part of the Key Bindings Setup initialization. Draw the +// background, title, instruction line, and items. + +void M_DrawKeybnd(void) + +{ + inhelpscreens = true; // killough 4/6/98: Force status bar redraw + + // Set up the Key Binding screen + + M_DrawBackground("FLOOR4_6", 0); // Draw background + // proff/nicolas 09/20/98 -- changed for hi-res + V_DrawNamePatch(84, 2, 0, "M_KEYBND", CR_DEFAULT, VPT_STRETCH); + M_DrawInstructions(); + M_DrawScreenItems(current_setup_menu); + + // If the Reset Button has been selected, an "Are you sure?" message + // is overlayed across everything else. + + if (default_verify) + M_DrawDefVerify(); +} + +///////////////////////////// +// +// The Weapon Screen tables. + +#define WP_X 203 +#define WP_Y 33 + +// There's only one weapon settings screen (for now). But since we're +// trying to fit a common description for screens, it gets a setup_menu_t, +// which only has one screen definition in it. +// +// Note that this screen has no PREV or NEXT items, since there are no +// neighboring screens. + +enum { // killough 10/98: enum for y-offset info + weap_recoil, + weap_bobbing, + weap_bfg, + weap_stub1, + weap_pref1, + weap_pref2, + weap_pref3, + weap_pref4, + weap_pref5, + weap_pref6, + weap_pref7, + weap_pref8, + weap_pref9, + weap_stub2, + weap_toggle, + weap_toggle2, +}; + +setup_menu_t weap_settings1[]; + +setup_menu_t* weap_settings[] = +{ + weap_settings1, + NULL +}; + +setup_menu_t weap_settings1[] = // Weapons Settings screen +{ + {"ENABLE RECOIL", S_YESNO,m_null,WP_X, WP_Y+ weap_recoil*8, {"weapon_recoil"},NULL,NULL,NULL,NULL}, + {"ENABLE BOBBING",S_YESNO,m_null,WP_X, WP_Y+weap_bobbing*8, {"player_bobbing"},NULL,NULL,NULL,NULL}, + + {"1ST CHOICE WEAPON",S_WEAP,m_null,WP_X,WP_Y+weap_pref1*8, {"weapon_choice_1"},NULL,NULL,NULL,NULL}, + {"2nd CHOICE WEAPON",S_WEAP,m_null,WP_X,WP_Y+weap_pref2*8, {"weapon_choice_2"},NULL,NULL,NULL,NULL}, + {"3rd CHOICE WEAPON",S_WEAP,m_null,WP_X,WP_Y+weap_pref3*8, {"weapon_choice_3"},NULL,NULL,NULL,NULL}, + {"4th CHOICE WEAPON",S_WEAP,m_null,WP_X,WP_Y+weap_pref4*8, {"weapon_choice_4"},NULL,NULL,NULL,NULL}, + {"5th CHOICE WEAPON",S_WEAP,m_null,WP_X,WP_Y+weap_pref5*8, {"weapon_choice_5"},NULL,NULL,NULL,NULL}, + {"6th CHOICE WEAPON",S_WEAP,m_null,WP_X,WP_Y+weap_pref6*8, {"weapon_choice_6"},NULL,NULL,NULL,NULL}, + {"7th CHOICE WEAPON",S_WEAP,m_null,WP_X,WP_Y+weap_pref7*8, {"weapon_choice_7"},NULL,NULL,NULL,NULL}, + {"8th CHOICE WEAPON",S_WEAP,m_null,WP_X,WP_Y+weap_pref8*8, {"weapon_choice_8"},NULL,NULL,NULL,NULL}, + {"9th CHOICE WEAPON",S_WEAP,m_null,WP_X,WP_Y+weap_pref9*8, {"weapon_choice_9"},NULL,NULL,NULL,NULL}, + + {"Enable Fist/Chainsaw\n& SG/SSG toggle", S_YESNO, m_null, WP_X, + WP_Y+ weap_toggle*8, {"doom_weapon_toggles"},NULL,NULL,NULL,NULL}, + + // Button for resetting to defaults + {0,S_RESET,m_null,X_BUTTON,Y_BUTTON,{NULL},NULL,NULL,NULL,NULL}, + + // Final entry + {0,S_SKIP|S_END,m_null,0,0,{NULL},NULL,NULL,NULL,NULL} + +}; + +// Setting up for the Weapons screen. Turn on flags, set pointers, +// locate the first item on the screen where the cursor is allowed to +// land. + +void M_Weapons(int choice) +{ + M_SetupNextMenu(&WeaponDef); + + setup_active = true; + setup_screen = ss_weap; + set_weapon_active = true; + setup_select = false; + default_verify = false; + setup_gather = false; + mult_screens_index = 0; + current_setup_menu = weap_settings[0]; + set_menu_itemon = 0; + while (current_setup_menu[set_menu_itemon++].m_flags & S_SKIP); + current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE; +} + + +// The drawing part of the Weapons Setup initialization. Draw the +// background, title, instruction line, and items. + +void M_DrawWeapons(void) +{ + inhelpscreens = true; // killough 4/6/98: Force status bar redraw + + M_DrawBackground("FLOOR4_6", 0); // Draw background + // proff/nicolas 09/20/98 -- changed for hi-res + V_DrawNamePatch(109, 2, 0, "M_WEAP", CR_DEFAULT, VPT_STRETCH); + M_DrawInstructions(); + M_DrawScreenItems(current_setup_menu); + + // If the Reset Button has been selected, an "Are you sure?" message + // is overlayed across everything else. + + if (default_verify) + M_DrawDefVerify(); +} + +///////////////////////////// +// +// The Status Bar / HUD tables. + +#define ST_X 203 +#define ST_Y 31 + +// Screen table definitions + +setup_menu_t stat_settings1[]; + +setup_menu_t* stat_settings[] = +{ + stat_settings1, + NULL +}; + +setup_menu_t stat_settings1[] = // Status Bar and HUD Settings screen +{ + {"STATUS BAR" ,S_SKIP|S_TITLE,m_null,ST_X,ST_Y+ 1*8,{NULL},NULL,NULL,NULL,NULL }, + + {"USE RED NUMBERS" ,S_YESNO, m_null,ST_X,ST_Y+ 2*8, {"sts_always_red"},NULL,NULL,NULL,NULL}, + {"GRAY %" ,S_YESNO, m_null,ST_X,ST_Y+ 3*8, {"sts_pct_always_gray"},NULL,NULL,NULL,NULL}, + {"SINGLE KEY DISPLAY",S_YESNO, m_null,ST_X,ST_Y+ 4*8, {"sts_traditional_keys"},NULL,NULL,NULL,NULL}, + + {"HEADS-UP DISPLAY" ,S_SKIP|S_TITLE,m_null,ST_X,ST_Y+ 6*8,{NULL},NULL,NULL,NULL,NULL}, + + {"HIDE SECRETS" ,S_YESNO ,m_null,ST_X,ST_Y+ 7*8, {"hud_nosecrets"},NULL,NULL,NULL,NULL}, + {"HEALTH LOW/OK" ,S_NUM ,m_null,ST_X,ST_Y+ 8*8, {"health_red"},NULL,NULL,NULL,NULL}, + {"HEALTH OK/GOOD" ,S_NUM ,m_null,ST_X,ST_Y+ 9*8, {"health_yellow"},NULL,NULL,NULL,NULL}, + {"HEALTH GOOD/EXTRA" ,S_NUM ,m_null,ST_X,ST_Y+10*8, {"health_green"},NULL,NULL,NULL,NULL}, + {"ARMOR LOW/OK" ,S_NUM ,m_null,ST_X,ST_Y+11*8, {"armor_red"},NULL,NULL,NULL,NULL}, + {"ARMOR OK/GOOD" ,S_NUM ,m_null,ST_X,ST_Y+12*8, {"armor_yellow"},NULL,NULL,NULL,NULL}, + {"ARMOR GOOD/EXTRA" ,S_NUM ,m_null,ST_X,ST_Y+13*8, {"armor_green"},NULL,NULL,NULL,NULL}, + {"AMMO LOW/OK" ,S_NUM ,m_null,ST_X,ST_Y+14*8, {"ammo_red"},NULL,NULL,NULL,NULL}, + {"AMMO OK/GOOD" ,S_NUM ,m_null,ST_X,ST_Y+15*8, {"ammo_yellow"},NULL,NULL,NULL,NULL}, + + // Button for resetting to defaults + {0,S_RESET,m_null,X_BUTTON,Y_BUTTON,{NULL},NULL,NULL,NULL,NULL}, + + // Final entry + {0,S_SKIP|S_END,m_null,0,0,{NULL},NULL,NULL,NULL,NULL} +}; + +// Setting up for the Status Bar / HUD screen. Turn on flags, set pointers, +// locate the first item on the screen where the cursor is allowed to +// land. + +void M_StatusBar(int choice) +{ + M_SetupNextMenu(&StatusHUDDef); + + setup_active = true; + setup_screen = ss_stat; + set_status_active = true; + setup_select = false; + default_verify = false; + setup_gather = false; + mult_screens_index = 0; + current_setup_menu = stat_settings[0]; + set_menu_itemon = 0; + while (current_setup_menu[set_menu_itemon++].m_flags & S_SKIP); + current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE; +} + + +// The drawing part of the Status Bar / HUD Setup initialization. Draw the +// background, title, instruction line, and items. + +void M_DrawStatusHUD(void) + +{ + inhelpscreens = true; // killough 4/6/98: Force status bar redraw + + M_DrawBackground("FLOOR4_6", 0); // Draw background + // proff/nicolas 09/20/98 -- changed for hi-res + V_DrawNamePatch(59, 2, 0, "M_STAT", CR_DEFAULT, VPT_STRETCH); + M_DrawInstructions(); + M_DrawScreenItems(current_setup_menu); + + // If the Reset Button has been selected, an "Are you sure?" message + // is overlayed across everything else. + + if (default_verify) + M_DrawDefVerify(); +} + + +///////////////////////////// +// +// The Automap tables. + +#define AU_X 250 +#define AU_Y 31 +#define AU_PREV KB_PREV +#define AU_NEXT KB_NEXT + +setup_menu_t auto_settings1[]; +setup_menu_t auto_settings2[]; + +setup_menu_t* auto_settings[] = +{ + auto_settings1, + auto_settings2, + NULL +}; + +setup_menu_t auto_settings1[] = // 1st AutoMap Settings screen +{ + {"background", S_COLOR, m_null, AU_X, AU_Y, {"mapcolor_back"},NULL,NULL,NULL,NULL}, + {"grid lines", S_COLOR, m_null, AU_X, AU_Y + 1*8, {"mapcolor_grid"},NULL,NULL,NULL,NULL}, + {"normal 1s wall", S_COLOR, m_null,AU_X,AU_Y+ 2*8, {"mapcolor_wall"},NULL,NULL,NULL,NULL}, + {"line at floor height change", S_COLOR, m_null, AU_X, AU_Y+ 3*8, {"mapcolor_fchg"},NULL,NULL,NULL,NULL}, + {"line at ceiling height change" ,S_COLOR,m_null,AU_X,AU_Y+ 4*8, {"mapcolor_cchg"},NULL,NULL,NULL,NULL}, + {"line at sector with floor = ceiling",S_COLOR,m_null,AU_X,AU_Y+ 5*8, {"mapcolor_clsd"},NULL,NULL,NULL,NULL}, + {"red key" ,S_COLOR,m_null,AU_X,AU_Y+ 6*8, {"mapcolor_rkey"},NULL,NULL,NULL,NULL}, + {"blue key" ,S_COLOR,m_null,AU_X,AU_Y+ 7*8, {"mapcolor_bkey"},NULL,NULL,NULL,NULL}, + {"yellow key" ,S_COLOR,m_null,AU_X,AU_Y+ 8*8, {"mapcolor_ykey"},NULL,NULL,NULL,NULL}, + {"red door" ,S_COLOR,m_null,AU_X,AU_Y+ 9*8, {"mapcolor_rdor"},NULL,NULL,NULL,NULL}, + {"blue door" ,S_COLOR,m_null,AU_X,AU_Y+10*8, {"mapcolor_bdor"},NULL,NULL,NULL,NULL}, + {"yellow door" ,S_COLOR,m_null,AU_X,AU_Y+11*8, {"mapcolor_ydor"},NULL,NULL,NULL,NULL}, + + {"AUTOMAP LEVEL TITLE COLOR" ,S_CRITEM,m_null,AU_X,AU_Y+13*8, {"hudcolor_titl"},NULL,NULL,NULL,NULL}, + {"AUTOMAP COORDINATES COLOR" ,S_CRITEM,m_null,AU_X,AU_Y+14*8, {"hudcolor_xyco"},NULL,NULL,NULL,NULL}, + + {"Show Secrets only after entering",S_YESNO,m_null,AU_X,AU_Y+15*8, {"map_secret_after"},NULL,NULL,NULL,NULL}, + + {"Show coordinates of automap pointer",S_YESNO,m_null,AU_X,AU_Y+16*8, {"map_point_coord"},NULL,NULL,NULL,NULL}, // killough 10/98 + + // Button for resetting to defaults + {0,S_RESET,m_null,X_BUTTON,Y_BUTTON,{NULL},NULL,NULL,NULL,NULL}, + + {"NEXT ->",S_SKIP|S_NEXT,m_null,AU_NEXT,AU_Y+20*8, {auto_settings2},NULL,NULL,NULL,NULL}, + + // Final entry + {0,S_SKIP|S_END,m_null,0,0,{NULL},NULL,NULL,NULL,NULL} + +}; + +setup_menu_t auto_settings2[] = // 2nd AutoMap Settings screen +{ + {"teleporter line" ,S_COLOR ,m_null,AU_X,AU_Y, {"mapcolor_tele"},NULL,NULL,NULL,NULL}, + {"secret sector boundary" ,S_COLOR ,m_null,AU_X,AU_Y+ 1*8, {"mapcolor_secr"},NULL,NULL,NULL,NULL}, + //jff 4/23/98 add exit line to automap + {"exit line" ,S_COLOR ,m_null,AU_X,AU_Y+ 2*8, {"mapcolor_exit"},NULL,NULL,NULL,NULL}, + {"computer map unseen line" ,S_COLOR ,m_null,AU_X,AU_Y+ 3*8, {"mapcolor_unsn"},NULL,NULL,NULL,NULL}, + {"line w/no floor/ceiling changes",S_COLOR ,m_null,AU_X,AU_Y+ 4*8, {"mapcolor_flat"},NULL,NULL,NULL,NULL}, + {"general sprite" ,S_COLOR ,m_null,AU_X,AU_Y+ 5*8, {"mapcolor_sprt"},NULL,NULL,NULL,NULL}, + {"countable enemy sprite" ,S_COLOR ,m_null,AU_X,AU_Y+ 6*8, {"mapcolor_enemy"},NULL,NULL,NULL,NULL}, // cph 2006/06/30 + {"countable item sprite" ,S_COLOR ,m_null,AU_X,AU_Y+ 7*8, {"mapcolor_item"},NULL,NULL,NULL,NULL}, // mead 3/4/2003 + {"crosshair" ,S_COLOR ,m_null,AU_X,AU_Y+ 8*8, {"mapcolor_hair"},NULL,NULL,NULL,NULL}, + {"single player arrow" ,S_COLOR ,m_null,AU_X,AU_Y+ 9*8, {"mapcolor_sngl"},NULL,NULL,NULL,NULL}, + {"your colour in multiplayer" ,S_COLOR ,m_null,AU_X,AU_Y+10*8, {"mapcolor_me"},NULL,NULL,NULL,NULL}, + + {"friends" ,S_COLOR ,m_null,AU_X,AU_Y+12*8, {"mapcolor_frnd"},NULL,NULL,NULL,NULL}, // killough 8/8/98 + + {"<- PREV",S_SKIP|S_PREV,m_null,AU_PREV,AU_Y+20*8, {auto_settings1},NULL,NULL,NULL,NULL}, + + // Final entry + + {0,S_SKIP|S_END,m_null,0,0,{NULL},NULL,NULL,NULL,NULL} + +}; + + +// Setting up for the Automap screen. Turn on flags, set pointers, +// locate the first item on the screen where the cursor is allowed to +// land. + +void M_Automap(int choice) +{ + M_SetupNextMenu(&AutoMapDef); + + setup_active = true; + setup_screen = ss_auto; + set_auto_active = true; + setup_select = false; + colorbox_active = false; + default_verify = false; + setup_gather = false; + set_menu_itemon = 0; + mult_screens_index = 0; + current_setup_menu = auto_settings[0]; + while (current_setup_menu[set_menu_itemon++].m_flags & S_SKIP); + current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE; +} + +// Data used by the color palette that is displayed for the player to +// select colors. + +int color_palette_x; // X position of the cursor on the color palette +int color_palette_y; // Y position of the cursor on the color palette +byte palette_background[16*(CHIP_SIZE+1)+8]; + +// M_DrawColPal() draws the color palette when the user needs to select a +// color. + +// phares 4/1/98: now uses a single lump for the palette instead of +// building the image out of individual paint chips. + +static void M_DrawColPal(void) +{ + int cpx, cpy; + + // Draw a background, border, and paint chips + + // proff/nicolas 09/20/98 -- changed for hi-res + // CPhipps - patch drawing updated + V_DrawNamePatch(COLORPALXORIG-5, COLORPALYORIG-5, 0, "M_COLORS", CR_DEFAULT, VPT_STRETCH); + + // Draw the cursor around the paint chip + // (cpx,cpy) is the upper left-hand corner of the paint chip + + cpx = COLORPALXORIG+color_palette_x*(CHIP_SIZE+1)-1; + cpy = COLORPALYORIG+color_palette_y*(CHIP_SIZE+1)-1; + // proff 12/6/98: Drawing of colorchips completly changed for hi-res, it now uses a patch + V_DrawNamePatch(cpx,cpy,0,"M_PALSEL",CR_DEFAULT,VPT_STRETCH); // PROFF_GL_FIX +} + +// The drawing part of the Automap Setup initialization. Draw the +// background, title, instruction line, and items. + +void M_DrawAutoMap(void) + +{ + inhelpscreens = true; // killough 4/6/98: Force status bar redraw + + M_DrawBackground("FLOOR4_6", 0); // Draw background + // CPhipps - patch drawing updated + V_DrawNamePatch(109, 2, 0, "M_AUTO", CR_DEFAULT, VPT_STRETCH); + M_DrawInstructions(); + M_DrawScreenItems(current_setup_menu); + + // If a color is being selected, need to show color paint chips + + if (colorbox_active) + M_DrawColPal(); + + // If the Reset Button has been selected, an "Are you sure?" message + // is overlayed across everything else. + + else if (default_verify) + M_DrawDefVerify(); +} + + +///////////////////////////// +// +// The Enemies table. + +#define E_X 250 +#define E_Y 31 + +setup_menu_t enem_settings1[]; + +setup_menu_t* enem_settings[] = +{ + enem_settings1, + NULL +}; + +enum { + enem_infighting, + + enem_remember = 1, + + enem_backing, + enem_monkeys, + enem_avoid_hazards, + enem_friction, + enem_help_friends, + +#ifdef DOGS + enem_helpers, +#endif + + enem_distfriend, + +#ifdef DOGS + enem_dog_jumping, +#endif + + enem_end +}; + +setup_menu_t enem_settings1[] = // Enemy Settings screen +{ + // killough 7/19/98 + {"Monster Infighting When Provoked",S_YESNO,m_null,E_X,E_Y+ enem_infighting*8, {"monster_infighting"},NULL,NULL,NULL,NULL}, + + {"Remember Previous Enemy",S_YESNO,m_null,E_X,E_Y+ enem_remember*8, {"monsters_remember"},NULL,NULL,NULL,NULL}, + + // killough 9/8/98 + {"Monster Backing Out",S_YESNO,m_null,E_X,E_Y+ enem_backing*8, {"monster_backing"},NULL,NULL,NULL,NULL}, + + {"Climb Steep Stairs", S_YESNO,m_null,E_X,E_Y+enem_monkeys*8, {"monkeys"},NULL,NULL,NULL,NULL}, + + // killough 9/9/98 + {"Intelligently Avoid Hazards",S_YESNO,m_null,E_X,E_Y+ enem_avoid_hazards*8, {"monster_avoid_hazards"},NULL,NULL,NULL,NULL}, + + // killough 10/98 + {"Affected by Friction",S_YESNO,m_null,E_X,E_Y+ enem_friction*8, {"monster_friction"},NULL,NULL,NULL,NULL}, + + {"Rescue Dying Friends",S_YESNO,m_null,E_X,E_Y+ enem_help_friends*8, {"help_friends"},NULL,NULL,NULL,NULL}, + +#ifdef DOGS + // killough 7/19/98 + {"Number Of Single-Player Helper Dogs",S_NUM|S_LEVWARN,m_null,E_X,E_Y+ enem_helpers*8, {"player_helpers"}}, + + // killough 8/8/98 + {"Distance Friends Stay Away",S_NUM,m_null,E_X,E_Y+ enem_distfriend*8, {"friend_distance"}}, + + {"Allow dogs to jump down",S_YESNO,m_null,E_X,E_Y+ enem_dog_jumping*8, {"dog_jumping"}}, +#endif + + // Button for resetting to defaults + {0,S_RESET,m_null,X_BUTTON,Y_BUTTON,{NULL},NULL,NULL,NULL,NULL}, + + // Final entry + {0,S_SKIP|S_END,m_null,0,0,{NULL},NULL,NULL,NULL,NULL} + +}; + +///////////////////////////// + +// Setting up for the Enemies screen. Turn on flags, set pointers, +// locate the first item on the screen where the cursor is allowed to +// land. + +void M_Enemy(int choice) +{ + M_SetupNextMenu(&EnemyDef); + + setup_active = true; + setup_screen = ss_enem; + set_enemy_active = true; + setup_select = false; + default_verify = false; + setup_gather = false; + mult_screens_index = 0; + current_setup_menu = enem_settings[0]; + set_menu_itemon = 0; + while (current_setup_menu[set_menu_itemon++].m_flags & S_SKIP); + current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE; +} + +// The drawing part of the Enemies Setup initialization. Draw the +// background, title, instruction line, and items. + +void M_DrawEnemy(void) + +{ + inhelpscreens = true; + + M_DrawBackground("FLOOR4_6", 0); // Draw background + // proff/nicolas 09/20/98 -- changed for hi-res + V_DrawNamePatch(114, 2, 0, "M_ENEM", CR_DEFAULT, VPT_STRETCH); + M_DrawInstructions(); + M_DrawScreenItems(current_setup_menu); + + // If the Reset Button has been selected, an "Are you sure?" message + // is overlayed across everything else. + + if (default_verify) + M_DrawDefVerify(); +} + + +///////////////////////////// +// +// The General table. +// killough 10/10/98 + +extern int usejoystick, usemouse, default_mus_card, default_snd_card; +extern int detect_voices, realtic_clock_rate, tran_filter_pct; + +setup_menu_t gen_settings1[], gen_settings2[], gen_settings3[]; + +setup_menu_t* gen_settings[] = +{ + gen_settings1, + gen_settings2, + gen_settings3, + NULL +}; + +enum { + general_trans, + general_transpct, + general_fullscreen, + general_videomode, +// general_pcx, +// general_diskicon, + general_uncapped, +}; + +enum { + general_gl_texfilter, + general_gl_texformat, + general_flooroffset, +}; + +enum { +// general_sndcard, +// general_muscard, +// general_detvoices, + general_sndchan, + general_pitch +}; + +#define G_X 250 +#define G_YA 44 +#define G_YA2 (G_YA+9*8) +#define G_YA3 (G_YA2+5*8) +#define GF_X 76 + +static const char *videomodes[] = {"8bit","15bit","16bit", + "32bit","OpenGL", NULL}; + +static const char *gltexfilters[] = {"GL_NEAREST","GL_LINEAR", + "GL_LINEAR_MIPMAP_LINEAR", + NULL}; + +static const char *gltexformats[] = {"GL_RGBA","GL_RGB5_A1", + "GL_RGBA4", NULL}; + +setup_menu_t gen_settings1[] = { // General Settings screen1 + + {"Video" ,S_SKIP|S_TITLE, m_null, G_X, G_YA - 12,{NULL},NULL,NULL,NULL,NULL}, + + {"Enable Translucency", S_YESNO, m_null, G_X, + G_YA + general_trans*8, {"translucency"}, 0, 0, M_Trans,NULL}, + + {"Translucency filter percentage", S_NUM, m_null, G_X, + G_YA + general_transpct*8, {"tran_filter_pct"}, 0, 0, M_Trans,NULL}, + + {"Fullscreen Video mode", S_YESNO|S_PRGWARN, m_null, G_X, + G_YA + general_fullscreen*8, {"use_fullscreen"},NULL,NULL,NULL,NULL}, + + {"Video mode", S_CHOICE|S_PRGWARN, m_null, G_X, + G_YA + general_videomode*8, {"videomode"}, 0, 0, NULL, videomodes}, + + {"Uncapped Framerate", S_YESNO, m_null, G_X, + G_YA + general_uncapped*8, {"uncapped_framerate"},NULL,NULL,NULL,NULL}, + +#ifdef GL_DOOM + {"OpenGL", S_SKIP|S_TITLE, m_null, G_X, G_YA2 - 12,{NULL},NULL,NULL,NULL,NULL}, + + {"Texture filter", S_CHOICE|S_PRGWARN, m_null, G_X, + G_YA2 + general_gl_texfilter*8, {"gl_tex_filter_string"}, 0, 0, NULL, gltexfilters}, + + {"Texture format", S_CHOICE|S_PRGWARN, m_null, G_X, + G_YA2 + general_gl_texformat*8, {"gl_tex_format_string"}, 0, 0, NULL, gltexformats}, + + {"Item out of Floor offset", S_NUM, m_null, G_X, + G_YA2 + general_flooroffset*8, {"gl_sprite_offset"},NULL,NULL,NULL,NULL}, +#endif + +#if 0 + {"PCX instead of BMP for screenshots", S_YESNO, m_null, G_X, + G_YA + general_pcx*8, {"screenshot_pcx"}}, +#endif + +#if 0 // MBF + {"Flash Icon During Disk IO", S_YESNO, m_null, G_X, + G_YA + general_diskicon*8, {"disk_icon"}}, +#endif + + {"Sound & Music", S_SKIP|S_TITLE, m_null, G_X, G_YA3 - 12,{NULL},NULL,NULL,NULL,NULL}, +#if 0 // MBF + {"Sound Card", S_NUM|S_PRGWARN, m_null, G_X, + G_YA2 + general_sndcard*8, {"sound_card"}}, + + {"Music Card", S_NUM|S_PRGWARN, m_null, G_X, + G_YA2 + general_muscard*8, {"music_card"}}, + + {"Autodetect Number of Voices", S_YESNO|S_PRGWARN, m_null, G_X, + G_YA2 + general_detvoices*8, {"detect_voices"}}, +#endif + + {"Number of Sound Channels", S_NUM|S_PRGWARN, m_null, G_X, + G_YA3 + general_sndchan*8, {"snd_channels"},NULL,NULL,NULL,NULL}, + + {"Enable v1.1 Pitch Effects", S_YESNO, m_null, G_X, + G_YA3 + general_pitch*8, {"pitched_sounds"},NULL,NULL,NULL,NULL}, + + // Button for resetting to defaults + {0,S_RESET,m_null,X_BUTTON,Y_BUTTON,{NULL},NULL,NULL,NULL,NULL}, + + {"NEXT ->",S_SKIP|S_NEXT,m_null,KB_NEXT,KB_Y+20*8, {gen_settings2},NULL,NULL,NULL,NULL}, + + // Final entry + {0,S_SKIP|S_END,m_null,0,0,{NULL},NULL,NULL,NULL,NULL} +}; + +enum { + general_mouse, + general_joy, + general_leds +}; + +enum { + general_wad1, + general_wad2, + general_deh1, + general_deh2 +}; + +enum { + general_corpse, + general_realtic, + general_smooth, + general_smoothfactor, + general_defskill, +}; + +#define G_YB 44 +#define G_YB1 (G_YB+44) +#define G_YB2 (G_YB1+52) + +static const char *gen_skillstrings[] = { + // Dummy first option because defaultskill is 1-based + "", "ITYTD", "HNTR", "HMP", "UV", "NM", NULL +}; + +setup_menu_t gen_settings2[] = { // General Settings screen2 + + {"Input Devices" ,S_SKIP|S_TITLE, m_null, G_X, G_YB - 12,{NULL},NULL,NULL,NULL,NULL}, + + {"Enable Mouse", S_YESNO, m_null, G_X, + G_YB + general_mouse*8, {"use_mouse"},NULL,NULL,NULL,NULL}, + + {"Enable Joystick", S_YESNO, m_null, G_X, + G_YB + general_joy*8, {"use_joystick"},NULL,NULL,NULL,NULL}, + + {"Files Preloaded at Game Startup",S_SKIP|S_TITLE, m_null, G_X, + G_YB1 - 12,{NULL},NULL,NULL,NULL,NULL}, + + {"WAD # 1", S_FILE, m_null, GF_X, G_YB1 + general_wad1*8, {"wadfile_1"},NULL,NULL,NULL,NULL}, + + {"WAD #2", S_FILE, m_null, GF_X, G_YB1 + general_wad2*8, {"wadfile_2"},NULL,NULL,NULL,NULL}, + + {"DEH/BEX # 1", S_FILE, m_null, GF_X, G_YB1 + general_deh1*8, {"dehfile_1"},NULL,NULL,NULL,NULL}, + + {"DEH/BEX #2", S_FILE, m_null, GF_X, G_YB1 + general_deh2*8, {"dehfile_2"},NULL,NULL,NULL,NULL}, + + {"Miscellaneous" ,S_SKIP|S_TITLE, m_null, G_X, G_YB2 - 12,{NULL},NULL,NULL,NULL,NULL}, + + {"Maximum number of player corpses", S_NUM|S_PRGWARN, m_null, G_X, + G_YB2 + general_corpse*8, {"max_player_corpse"},NULL,NULL,NULL,NULL}, + + {"Game speed, percentage of normal", S_NUM|S_PRGWARN, m_null, G_X, + G_YB2 + general_realtic*8, {"realtic_clock_rate"},NULL,NULL,NULL,NULL}, + + {"Smooth Demo Playback", S_YESNO, m_null, G_X, + G_YB2 + general_smooth*8, {"demo_smoothturns"}, 0, 0, M_ChangeDemoSmoothTurns,NULL}, + + {"Smooth Demo Playback Factor", S_NUM, m_null, G_X, + G_YB2 + general_smoothfactor*8, {"demo_smoothturnsfactor"}, 0, 0, M_ChangeDemoSmoothTurns,NULL}, + + {"Default skill level", S_CHOICE, m_null, G_X, + G_YB2 + general_defskill*8, {"default_skill"}, 0, 0, NULL, gen_skillstrings}, + + {"<- PREV",S_SKIP|S_PREV, m_null, KB_PREV, KB_Y+20*8, {gen_settings1},NULL,NULL,NULL,NULL}, + + {"NEXT ->",S_SKIP|S_NEXT,m_null,KB_NEXT,KB_Y+20*8, {gen_settings3},NULL,NULL,NULL,NULL}, + + // Final entry + + {0,S_SKIP|S_END,m_null,0,0,{NULL},NULL,NULL,NULL,NULL} +}; + +enum { + general_filterwall, + general_filterfloor, + general_filtersprite, + general_filterpatch, + general_filterz, + general_filter_threshold, + general_spriteedges, + general_patchedges, + general_hom, +}; + +#define G_YC 44 + +static const char *renderfilters[] = {"none", "point", "linear", "rounded"}; +static const char *edgetypes[] = {"jagged", "sloped"}; + +setup_menu_t gen_settings3[] = { // General Settings screen2 + + {"Renderer settings" ,S_SKIP|S_TITLE, m_null, G_X, G_YB - 12,{NULL},NULL,NULL,NULL,NULL}, + + {"Filter for walls", S_CHOICE, m_null, G_X, + G_YC + general_filterwall*8, {"filter_wall"}, 0, 0, NULL, renderfilters}, + + {"Filter for floors/ceilings", S_CHOICE, m_null, G_X, + G_YC + general_filterfloor*8, {"filter_floor"}, 0, 0, NULL, renderfilters}, + + {"Filter for sprites", S_CHOICE, m_null, G_X, + G_YC + general_filtersprite*8, {"filter_sprite"}, 0, 0, NULL, renderfilters}, + + {"Filter for patches", S_CHOICE, m_null, G_X, + G_YC + general_filterpatch*8, {"filter_patch"}, 0, 0, NULL, renderfilters}, + + {"Filter for lighting", S_CHOICE, m_null, G_X, + G_YC + general_filterz*8, {"filter_z"}, 0, 0, NULL, renderfilters}, + + {"Drawing of sprite edges", S_CHOICE, m_null, G_X, + G_YC + general_spriteedges*8, {"sprite_edges"}, 0, 0, NULL, edgetypes}, + + {"Drawing of patch edges", S_CHOICE, m_null, G_X, + G_YC + general_patchedges*8, {"patch_edges"}, 0, 0, NULL, edgetypes}, + + {"Flashing HOM indicator", S_YESNO, m_null, G_X, + G_YC + general_hom*8, {"flashing_hom"},NULL,NULL,NULL,NULL}, + + {"<- PREV",S_SKIP|S_PREV, m_null, KB_PREV, KB_Y+20*8, {gen_settings2},NULL,NULL,NULL,NULL}, + + // Final entry + + {0,S_SKIP|S_END,m_null,0,0,{NULL},NULL,NULL,NULL,NULL} +}; + +void M_Trans(void) // To reset translucency after setting it in menu +{ + general_translucency = default_translucency; //e6y: Fix for "translucency won't change until you restart the engine" + + if (general_translucency) + R_InitTranMap(0); +} + +void M_FullScreen(void) // To (un)set fullscreen video after menu changes +{ + I_UpdateVideoMode(); + V_SetPalette(0); +} + +void M_ChangeDemoSmoothTurns(void) +{ + if (demo_smoothturns) + gen_settings2[12].m_flags &= ~(S_SKIP|S_SELECT); + else + gen_settings2[12].m_flags |= (S_SKIP|S_SELECT); + + R_SmoothPlaying_Reset(NULL); +} + +// Setting up for the General screen. Turn on flags, set pointers, +// locate the first item on the screen where the cursor is allowed to +// land. + +void M_General(int choice) +{ + M_SetupNextMenu(&GeneralDef); + + setup_active = true; + setup_screen = ss_gen; + set_general_active = true; + setup_select = false; + default_verify = false; + setup_gather = false; + mult_screens_index = 0; + current_setup_menu = gen_settings[0]; + set_menu_itemon = 0; + while (current_setup_menu[set_menu_itemon++].m_flags & S_SKIP); + current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE; +} + +// The drawing part of the General Setup initialization. Draw the +// background, title, instruction line, and items. + +void M_DrawGeneral(void) +{ + inhelpscreens = true; + + M_DrawBackground("FLOOR4_6", 0); // Draw background + // proff/nicolas 09/20/98 -- changed for hi-res + V_DrawNamePatch(114, 2, 0, "M_GENERL", CR_DEFAULT, VPT_STRETCH); + M_DrawInstructions(); + M_DrawScreenItems(current_setup_menu); + + // If the Reset Button has been selected, an "Are you sure?" message + // is overlayed across everything else. + + if (default_verify) + M_DrawDefVerify(); +} + +///////////////////////////// +// +// The Compatibility table. +// killough 10/10/98 + +#define C_X 284 +#define C_Y 32 +#define COMP_SPC 12 +#define C_NEXTPREV 131 + +setup_menu_t comp_settings1[], comp_settings2[], comp_settings3[]; + +setup_menu_t* comp_settings[] = +{ + comp_settings1, + comp_settings2, + comp_settings3, + NULL +}; + +enum +{ + compat_telefrag, + compat_dropoff, + compat_falloff, + compat_staylift, + compat_doorstuck, + compat_pursuit, + compat_vile, + compat_pain, + compat_skull, + compat_blazing, + compat_doorlight = 0, + compat_god, + compat_infcheat, + compat_zombie, + compat_skymap, + compat_stairs, + compat_floors, + compat_moveblock, + compat_model, + compat_zerotags, + compat_666 = 0, + compat_soul, + compat_maskedanim, + compat_sound +}; + +setup_menu_t comp_settings1[] = // Compatibility Settings screen #1 +{ + {"Any monster can telefrag on MAP30", S_YESNO, m_null, C_X, + C_Y + compat_telefrag * COMP_SPC, {"comp_telefrag"},NULL,NULL,NULL,NULL}, + + {"Some objects never hang over tall ledges", S_YESNO, m_null, C_X, + C_Y + compat_dropoff * COMP_SPC, {"comp_dropoff"},NULL,NULL,NULL,NULL}, + + {"Objects don't fall under their own weight", S_YESNO, m_null, C_X, + C_Y + compat_falloff * COMP_SPC, {"comp_falloff"},NULL,NULL,NULL,NULL}, + + {"Monsters randomly walk off of moving lifts", S_YESNO, m_null, C_X, + C_Y + compat_staylift * COMP_SPC, {"comp_staylift"},NULL,NULL,NULL,NULL}, + + {"Monsters get stuck on doortracks", S_YESNO, m_null, C_X, + C_Y + compat_doorstuck * COMP_SPC, {"comp_doorstuck"},NULL,NULL,NULL,NULL}, + + {"Monsters don't give up pursuit of targets", S_YESNO, m_null, C_X, + C_Y + compat_pursuit * COMP_SPC, {"comp_pursuit"},NULL,NULL,NULL,NULL}, + + {"Arch-Vile resurrects invincible ghosts", S_YESNO, m_null, C_X, + C_Y + compat_vile * COMP_SPC, {"comp_vile"},NULL,NULL,NULL,NULL}, + + {"Pain Elementals limited to 21 lost souls", S_YESNO, m_null, C_X, + C_Y + compat_pain * COMP_SPC, {"comp_pain"},NULL,NULL,NULL,NULL}, + + {"Lost souls get stuck behind walls", S_YESNO, m_null, C_X, + C_Y + compat_skull * COMP_SPC, {"comp_skull"},NULL,NULL,NULL,NULL}, + + {"Blazing doors make double closing sounds", S_YESNO, m_null, C_X, + C_Y + compat_blazing * COMP_SPC, {"comp_blazing"},NULL,NULL,NULL,NULL}, + + // Button for resetting to defaults + {0,S_RESET,m_null,X_BUTTON,Y_BUTTON,{NULL},NULL,NULL,NULL,NULL}, + + {"NEXT ->",S_SKIP|S_NEXT, m_null, KB_NEXT, C_Y+C_NEXTPREV, {comp_settings2},NULL,NULL,NULL,NULL}, + + // Final entry + {0,S_SKIP|S_END,m_null,0,0,{NULL},NULL,NULL,NULL,NULL} +}; + +setup_menu_t comp_settings2[] = // Compatibility Settings screen #2 +{ + {"Tagged doors don't trigger special lighting", S_YESNO, m_null, C_X, + C_Y + compat_doorlight * COMP_SPC, {"comp_doorlight"},NULL,NULL,NULL,NULL}, + + {"God mode isn't absolute", S_YESNO, m_null, C_X, + C_Y + compat_god * COMP_SPC, {"comp_god"},NULL,NULL,NULL,NULL}, + + {"Powerup cheats are not infinite duration", S_YESNO, m_null, C_X, + C_Y + compat_infcheat * COMP_SPC, {"comp_infcheat"},NULL,NULL,NULL,NULL}, + + {"Dead players can exit levels", S_YESNO, m_null, C_X, + C_Y + compat_zombie * COMP_SPC, {"comp_zombie"},NULL,NULL,NULL,NULL}, + + {"Sky is unaffected by invulnerability", S_YESNO, m_null, C_X, + C_Y + compat_skymap * COMP_SPC, {"comp_skymap"},NULL,NULL,NULL,NULL}, + + {"Use exactly Doom's stairbuilding method", S_YESNO, m_null, C_X, + C_Y + compat_stairs * COMP_SPC, {"comp_stairs"},NULL,NULL,NULL,NULL}, + + {"Use exactly Doom's floor motion behavior", S_YESNO, m_null, C_X, + C_Y + compat_floors * COMP_SPC, {"comp_floors"},NULL,NULL,NULL,NULL}, + + {"Use exactly Doom's movement clipping code", S_YESNO, m_null, C_X, + C_Y + compat_moveblock * COMP_SPC, {"comp_moveblock"},NULL,NULL,NULL,NULL}, + + {"Use exactly Doom's linedef trigger model", S_YESNO, m_null, C_X, + C_Y + compat_model * COMP_SPC, {"comp_model"},NULL,NULL,NULL,NULL}, + + {"Linedef effects work with sector tag = 0", S_YESNO, m_null, C_X, + C_Y + compat_zerotags * COMP_SPC, {"comp_zerotags"},NULL,NULL,NULL,NULL}, + + {"<- PREV", S_SKIP|S_PREV, m_null, KB_PREV, C_Y+C_NEXTPREV,{comp_settings1},NULL,NULL,NULL,NULL}, + + {"NEXT ->",S_SKIP|S_NEXT, m_null, KB_NEXT, C_Y+C_NEXTPREV, {comp_settings3},NULL,NULL,NULL,NULL}, + + // Final entry + + {0,S_SKIP|S_END,m_null,0,0,{NULL},NULL,NULL,NULL,NULL} +}; + +setup_menu_t comp_settings3[] = // Compatibility Settings screen #2 +{ + {"All boss types can trigger tag 666 at ExM8", S_YESNO, m_null, C_X, + C_Y + compat_666 * COMP_SPC, {"comp_666"},NULL,NULL,NULL,NULL}, + + {"Lost souls don't bounce off flat surfaces", S_YESNO, m_null, C_X, + C_Y + compat_soul * COMP_SPC, {"comp_soul"},NULL,NULL,NULL,NULL}, + + {"2S middle textures do not animate", S_YESNO, m_null, C_X, + C_Y + compat_maskedanim * COMP_SPC, {"comp_maskedanim"},NULL,NULL,NULL,NULL}, + + {"Use exactly Doom's sound code behavior", S_YESNO, m_null, C_X, + C_Y + compat_sound * COMP_SPC, {"comp_sound"},NULL,NULL,NULL,NULL}, + + {"<- PREV", S_SKIP|S_PREV, m_null, KB_PREV, C_Y+C_NEXTPREV,{comp_settings2},NULL,NULL,NULL,NULL}, + + // Final entry + + {0,S_SKIP|S_END,m_null,0,0,{NULL},NULL,NULL,NULL,NULL} +}; + +// Setting up for the Compatibility screen. Turn on flags, set pointers, +// locate the first item on the screen where the cursor is allowed to +// land. + +void M_Compat(int choice) +{ + M_SetupNextMenu(&CompatDef); + + setup_active = true; + setup_screen = ss_comp; + set_general_active = true; + setup_select = false; + default_verify = false; + setup_gather = false; + mult_screens_index = 0; + current_setup_menu = comp_settings[0]; + set_menu_itemon = 0; + while (current_setup_menu[set_menu_itemon++].m_flags & S_SKIP); + current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE; +} + +// The drawing part of the Compatibility Setup initialization. Draw the +// background, title, instruction line, and items. + +void M_DrawCompat(void) +{ + inhelpscreens = true; + + M_DrawBackground("FLOOR4_6", 0); // Draw background + V_DrawNamePatch(52,2,0,"M_COMPAT", CR_DEFAULT, VPT_STRETCH); + M_DrawInstructions(); + M_DrawScreenItems(current_setup_menu); + + // If the Reset Button has been selected, an "Are you sure?" message + // is overlayed across everything else. + + if (default_verify) + M_DrawDefVerify(); +} + +///////////////////////////// +// +// The Messages table. + +#define M_X 230 +#define M_Y 39 + +// killough 11/98: enumerated + +enum { + mess_color_play, + mess_timer, + mess_color_chat, + mess_chat_timer, + mess_color_review, + mess_timed, + mess_hud_timer, + mess_lines, + mess_scrollup, + mess_background, +}; + +setup_menu_t mess_settings1[]; + +setup_menu_t* mess_settings[] = +{ + mess_settings1, + NULL +}; + +setup_menu_t mess_settings1[] = // Messages screen +{ + {"Message Color During Play", S_CRITEM, m_null, M_X, + M_Y + mess_color_play*8, {"hudcolor_mesg"},NULL,NULL,NULL,NULL}, + +#if 0 + {"Message Duration During Play (ms)", S_NUM, m_null, M_X, + M_Y + mess_timer*8, {"message_timer"}}, +#endif + + {"Chat Message Color", S_CRITEM, m_null, M_X, + M_Y + mess_color_chat*8, {"hudcolor_chat"},NULL,NULL,NULL,NULL}, + +#if 0 + {"Chat Message Duration (ms)", S_NUM, m_null, M_X, + M_Y + mess_chat_timer*8, {"chat_msg_timer"}}, +#endif + + {"Message Review Color", S_CRITEM, m_null, M_X, + M_Y + mess_color_review*8, {"hudcolor_list"},NULL,NULL,NULL,NULL}, + +#if 0 + {"Message Listing Review is Temporary", S_YESNO, m_null, M_X, + M_Y + mess_timed*8, {"hud_msg_timed"}}, + + {"Message Review Duration (ms)", S_NUM, m_null, M_X, + M_Y + mess_hud_timer*8, {"hud_msg_timer"}}, +#endif + + {"Number of Review Message Lines", S_NUM, m_null, M_X, + M_Y + mess_lines*8, {"hud_msg_lines"},NULL,NULL,NULL,NULL}, + +#if 0 + {"Message Listing Scrolls Upwards", S_YESNO, m_null, M_X, + M_Y + mess_scrollup*8, {"hud_msg_scrollup"}}, +#endif + + {"Message Background", S_YESNO, m_null, M_X, + M_Y + mess_background*8, {"hud_list_bgon"},NULL,NULL,NULL,NULL}, + + // Button for resetting to defaults + {0,S_RESET,m_null,X_BUTTON,Y_BUTTON,{NULL},NULL,NULL,NULL,NULL}, + + // Final entry + + {0,S_SKIP|S_END,m_null,0,0,{NULL},NULL,NULL,NULL,NULL} +}; + + +// Setting up for the Messages screen. Turn on flags, set pointers, +// locate the first item on the screen where the cursor is allowed to +// land. + +void M_Messages(int choice) +{ + M_SetupNextMenu(&MessageDef); + + setup_active = true; + setup_screen = ss_mess; + set_mess_active = true; + setup_select = false; + default_verify = false; + setup_gather = false; + mult_screens_index = 0; + current_setup_menu = mess_settings[0]; + set_menu_itemon = 0; + while (current_setup_menu[set_menu_itemon++].m_flags & S_SKIP); + current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE; +} + + +// The drawing part of the Messages Setup initialization. Draw the +// background, title, instruction line, and items. + +void M_DrawMessages(void) + +{ + inhelpscreens = true; + M_DrawBackground("FLOOR4_6", 0); // Draw background + // CPhipps - patch drawing updated + V_DrawNamePatch(103, 2, 0, "M_MESS", CR_DEFAULT, VPT_STRETCH); + M_DrawInstructions(); + M_DrawScreenItems(current_setup_menu); + if (default_verify) + M_DrawDefVerify(); +} + + +///////////////////////////// +// +// The Chat Strings table. + +#define CS_X 20 +#define CS_Y (31+8) + +setup_menu_t chat_settings1[]; + +setup_menu_t* chat_settings[] = +{ + chat_settings1, + NULL +}; + +setup_menu_t chat_settings1[] = // Chat Strings screen +{ + {"1",S_CHAT,m_null,CS_X,CS_Y+ 1*8, {"chatmacro1"},NULL,NULL,NULL,NULL}, + {"2",S_CHAT,m_null,CS_X,CS_Y+ 2*8, {"chatmacro2"},NULL,NULL,NULL,NULL}, + {"3",S_CHAT,m_null,CS_X,CS_Y+ 3*8, {"chatmacro3"},NULL,NULL,NULL,NULL}, + {"4",S_CHAT,m_null,CS_X,CS_Y+ 4*8, {"chatmacro4"},NULL,NULL,NULL,NULL}, + {"5",S_CHAT,m_null,CS_X,CS_Y+ 5*8, {"chatmacro5"},NULL,NULL,NULL,NULL}, + {"6",S_CHAT,m_null,CS_X,CS_Y+ 6*8, {"chatmacro6"},NULL,NULL,NULL,NULL}, + {"7",S_CHAT,m_null,CS_X,CS_Y+ 7*8, {"chatmacro7"},NULL,NULL,NULL,NULL}, + {"8",S_CHAT,m_null,CS_X,CS_Y+ 8*8, {"chatmacro8"},NULL,NULL,NULL,NULL}, + {"9",S_CHAT,m_null,CS_X,CS_Y+ 9*8, {"chatmacro9"},NULL,NULL,NULL,NULL}, + {"0",S_CHAT,m_null,CS_X,CS_Y+10*8, {"chatmacro0"},NULL,NULL,NULL,NULL}, + + // Button for resetting to defaults + {0,S_RESET,m_null,X_BUTTON,Y_BUTTON,{NULL},NULL,NULL,NULL,NULL}, + + // Final entry + {0,S_SKIP|S_END,m_null,0,0,{NULL},NULL,NULL,NULL,NULL} + +}; + +// Setting up for the Chat Strings screen. Turn on flags, set pointers, +// locate the first item on the screen where the cursor is allowed to +// land. + +void M_ChatStrings(int choice) +{ + M_SetupNextMenu(&ChatStrDef); + setup_active = true; + setup_screen = ss_chat; + set_chat_active = true; + setup_select = false; + default_verify = false; + setup_gather = false; + mult_screens_index = 0; + current_setup_menu = chat_settings[0]; + set_menu_itemon = 0; + while (current_setup_menu[set_menu_itemon++].m_flags & S_SKIP); + current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE; +} + +// The drawing part of the Chat Strings Setup initialization. Draw the +// background, title, instruction line, and items. + +void M_DrawChatStrings(void) + +{ + inhelpscreens = true; + M_DrawBackground("FLOOR4_6", 0); // Draw background + // CPhipps - patch drawing updated + V_DrawNamePatch(83, 2, 0, "M_CHAT", CR_DEFAULT, VPT_STRETCH); + M_DrawInstructions(); + M_DrawScreenItems(current_setup_menu); + + // If the Reset Button has been selected, an "Are you sure?" message + // is overlayed across everything else. + + if (default_verify) + M_DrawDefVerify(); +} + +///////////////////////////// +// +// General routines used by the Setup screens. +// + +static boolean shiftdown = false; // phares 4/10/98: SHIFT key down or not + +// phares 4/17/98: +// M_SelectDone() gets called when you have finished entering your +// Setup Menu item change. + +static void M_SelectDone(setup_menu_t* ptr) +{ + ptr->m_flags &= ~S_SELECT; + ptr->m_flags |= S_HILITE; + S_StartSound(NULL,sfx_itemup); + setup_select = false; + colorbox_active = false; + if (print_warning_about_changes) // killough 8/15/98 + print_warning_about_changes--; +} + +// phares 4/21/98: +// Array of setup screens used by M_ResetDefaults() + +static setup_menu_t **setup_screens[] = +{ + keys_settings, + weap_settings, + stat_settings, + auto_settings, + enem_settings, + mess_settings, + chat_settings, + gen_settings, // killough 10/98 + comp_settings, +}; + +// phares 4/19/98: +// M_ResetDefaults() resets all values for a setup screen to default values +// +// killough 10/98: rewritten to fix bugs and warn about pending changes + +static void M_ResetDefaults(void) +{ + int i; //e6y + + default_t *dp; + int warn = 0; + + // Look through the defaults table and reset every variable that + // belongs to the group we're interested in. + // + // killough: However, only reset variables whose field in the + // current setup screen is the same as in the defaults table. + // i.e. only reset variables really in the current setup screen. + + // e6y + // Fixed crash while trying to read data past array end + // All previous versions of prboom worked only by a lucky accident + // old code: for (dp = defaults; dp->name; dp++) + for (i = 0; i < numdefaults ; i++) + { + dp = &defaults[i]; + + if (dp->setupscreen == setup_screen) + { + setup_menu_t **l, *p; + for (l = setup_screens[setup_screen-1]; *l; l++) + for (p = *l; !(p->m_flags & S_END); p++) + if (p->m_flags & S_HASDEFPTR ? p->var.def == dp : + p->var.m_key == dp->location.pi || + p->m_mouse == dp->location.pi || + p->m_joy == dp->location.pi) + { + if (IS_STRING(*dp)) + free((char*)*dp->location.ppsz), + *dp->location.ppsz = strdup(dp->defaultvalue.psz); + else + *dp->location.pi = dp->defaultvalue.i; + +#if 0 + if (p->m_flags & (S_LEVWARN | S_PRGWARN)) + warn |= p->m_flags & (S_LEVWARN | S_PRGWARN); + else + if (dp->current) + if (allow_changes()) + *dp->current = *dp->location.pi; + else + warn |= S_LEVWARN; +#endif + if (p->action) + p->action(); + + goto end; + } + end:; + } + } + + if (warn) + warn_about_changes(warn); +} + +// +// M_InitDefaults() +// +// killough 11/98: +// +// This function converts all setup menu entries consisting of cfg +// variable names, into pointers to the corresponding default[] +// array entry. var.name becomes converted to var.def. +// + +static void M_InitDefaults(void) +{ + setup_menu_t *const *p, *t; + default_t *dp; + int i; + for (i = 0; i < ss_max-1; i++) + for (p = setup_screens[i]; *p; p++) + for (t = *p; !(t->m_flags & S_END); t++) + if (t->m_flags & S_HASDEFPTR) { + if (!(dp = M_LookupDefault(t->var.name))) + I_Error("M_InitDefaults: Couldn't find config variable %s", t->var.name); + else + (t->var.def = dp)->setup_menu = t; + } +} + +// +// End of Setup Screens. +// +///////////////////////////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////////////////////////// +// +// Start of Extended HELP screens // phares 3/30/98 +// +// The wad designer can define a set of extended HELP screens for their own +// information display. These screens should be 320x200 graphic lumps +// defined in a separate wad. They should be named "HELP01" through "HELP99". +// "HELP01" is shown after the regular BOOM Dynamic HELP screen, and ENTER +// and BACKSPACE keys move the player through the HELP set. +// +// Rather than define a set of menu definitions for each of the possible +// HELP screens, one definition is used, and is altered on the fly +// depending on what HELPnn lumps the game finds. + +// phares 3/30/98: +// Extended Help Screen variables + +int extended_help_count; // number of user-defined help screens found +int extended_help_index; // index of current extended help screen + +menuitem_t ExtHelpMenu[] = +{ + {1,"",M_ExtHelpNextScreen,0} +}; + +menu_t ExtHelpDef = +{ + 1, // # of menu items + &ReadDef1, // previous menu + ExtHelpMenu, // menuitem_t -> + M_DrawExtHelp, // drawing routine -> + 330,181, // x,y + 0 // lastOn +}; + +// M_ExtHelpNextScreen establishes the number of the next HELP screen in +// the series. + +void M_ExtHelpNextScreen(int choice) +{ + choice = 0; + if (++extended_help_index > extended_help_count) + { + + // when finished with extended help screens, return to Main Menu + + extended_help_index = 1; + M_SetupNextMenu(&MainDef); + } +} + +// phares 3/30/98: +// Routine to look for HELPnn screens and create a menu +// definition structure that defines extended help screens. + +void M_InitExtendedHelp(void) + +{ + int index,i; + char namebfr[] = { "HELPnn"} ; + + extended_help_count = 0; + for (index = 1 ; index < 100 ; index++) { + namebfr[4] = index/10 + 0x30; + namebfr[5] = index%10 + 0x30; + i = W_CheckNumForName(namebfr); + if (i == -1) { + if (extended_help_count) { + if (gamemode == commercial) { + ExtHelpDef.prevMenu = &ReadDef1; /* previous menu */ + ReadMenu1[0].routine = M_ExtHelp; + } else { + ExtHelpDef.prevMenu = &ReadDef2; /* previous menu */ + ReadMenu2[0].routine = M_ExtHelp; + } + } + return; + } + extended_help_count++; + } + +} + +// Initialization for the extended HELP screens. + +void M_ExtHelp(int choice) +{ + choice = 0; + extended_help_index = 1; // Start with first extended help screen + M_SetupNextMenu(&ExtHelpDef); +} + +// Initialize the drawing part of the extended HELP screens. + +void M_DrawExtHelp(void) +{ + char namebfr[10] = { "HELPnn" }; // CPhipps - make it local & writable + + inhelpscreens = true; // killough 5/1/98 + namebfr[4] = extended_help_index/10 + 0x30; + namebfr[5] = extended_help_index%10 + 0x30; + // CPhipps - patch drawing updated + V_DrawNamePatch(0, 0, 0, namebfr, CR_DEFAULT, VPT_STRETCH); +} + +// +// End of Extended HELP screens // phares 3/30/98 +// +//////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////// +// +// Dynamic HELP screen // phares 3/2/98 +// +// Rather than providing the static HELP screens from DOOM and its versions, +// BOOM provides the player with a dynamic HELP screen that displays the +// current settings of major key bindings. +// +// The Dynamic HELP screen is defined in a manner similar to that used for +// the Setup Screens above. +// +// M_GetKeyString finds the correct string to represent the key binding +// for the current item being drawn. + +int M_GetKeyString(int c,int offset) +{ + const char* s; + + if (c >= 33 && c <= 126) { + + // The '=', ',', and '.' keys originally meant the shifted + // versions of those keys, but w/o having to shift them in + // the game. Any actions that are mapped to these keys will + // still mean their shifted versions. Could be changed later + // if someone can come up with a better way to deal with them. + + if (c == '=') // probably means the '+' key? + c = '+'; + else if (c == ',') // probably means the '<' key? + c = '<'; + else if (c == '.') // probably means the '>' key? + c = '>'; + menu_buffer[offset++] = c; // Just insert the ascii key + menu_buffer[offset] = 0; + + } else { + + // Retrieve 4-letter (max) string representing the key + + // cph - Keypad keys, general code reorganisation to + // make this smaller and neater. + if ((0x100 <= c) && (c < 0x200)) { + if (c == KEYD_KEYPADENTER) + s = "PADE"; + else { + strcpy(&menu_buffer[offset], "PAD"); + offset+=4; + menu_buffer[offset-1] = c & 0xff; + menu_buffer[offset] = 0; + } + } else if ((KEYD_F1 <= c) && (c < KEYD_F10)) { + menu_buffer[offset++] = 'F'; + menu_buffer[offset++] = '1' + c - KEYD_F1; + menu_buffer[offset] = 0; + } else { + switch(c) { + case KEYD_TAB: s = "TAB"; break; + case KEYD_ENTER: s = "ENTR"; break; + case KEYD_ESCAPE: s = "ESC"; break; + case KEYD_SPACEBAR: s = "SPAC"; break; + case KEYD_BACKSPACE: s = "BACK"; break; + case KEYD_RCTRL: s = "CTRL"; break; + case KEYD_LEFTARROW: s = "LARR"; break; + case KEYD_UPARROW: s = "UARR"; break; + case KEYD_RIGHTARROW: s = "RARR"; break; + case KEYD_DOWNARROW: s = "DARR"; break; + case KEYD_RSHIFT: s = "SHFT"; break; + case KEYD_RALT: s = "ALT"; break; + case KEYD_CAPSLOCK: s = "CAPS"; break; + case KEYD_SCROLLLOCK: s = "SCRL"; break; + case KEYD_HOME: s = "HOME"; break; + case KEYD_PAGEUP: s = "PGUP"; break; + case KEYD_END: s = "END"; break; + case KEYD_PAGEDOWN: s = "PGDN"; break; + case KEYD_INSERT: s = "INST"; break; + case KEYD_DEL: s = "DEL"; break; + case KEYD_F10: s = "F10"; break; + case KEYD_F11: s = "F11"; break; + case KEYD_F12: s = "F12"; break; + case KEYD_PAUSE: s = "PAUS"; break; + default: s = "JUNK"; break; + } + + if (s) { // cph - Slight code change + strcpy(&menu_buffer[offset],s); // string to display + offset += strlen(s); + } + } + } + return offset; +} + +// +// The Dynamic HELP screen table. + +#define KT_X1 283 +#define KT_X2 172 +#define KT_X3 87 + +#define KT_Y1 2 +#define KT_Y2 118 +#define KT_Y3 102 + +setup_menu_t helpstrings[] = // HELP screen strings +{ + {"SCREEN" ,S_SKIP|S_TITLE,m_null,KT_X1,KT_Y1,{NULL},NULL,NULL,NULL,NULL}, + {"HELP" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+ 1*8,{&key_help},NULL,NULL,NULL,NULL}, + {"MENU" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+ 2*8,{&key_escape},NULL,NULL,NULL,NULL}, + {"SETUP" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+ 3*8,{&key_setup},NULL,NULL,NULL,NULL}, + {"PAUSE" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+ 4*8,{&key_pause},NULL,NULL,NULL,NULL}, + {"AUTOMAP" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+ 5*8,{&key_map},NULL,NULL,NULL,NULL}, + {"SOUND VOLUME",S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+ 6*8,{&key_soundvolume},NULL,NULL,NULL,NULL}, + {"HUD" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+ 7*8,{&key_hud},NULL,NULL,NULL,NULL}, + {"MESSAGES" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+ 8*8,{&key_messages},NULL,NULL,NULL,NULL}, + {"GAMMA FIX" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+ 9*8,{&key_gamma},NULL,NULL,NULL,NULL}, + {"SPY" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+10*8,{&key_spy},NULL,NULL,NULL,NULL}, + {"LARGER VIEW" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+11*8,{&key_zoomin},NULL,NULL,NULL,NULL}, + {"SMALLER VIEW",S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+12*8,{&key_zoomout},NULL,NULL,NULL,NULL}, + {"SCREENSHOT" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+13*8,{&key_screenshot},NULL,NULL,NULL,NULL}, + + {"AUTOMAP" ,S_SKIP|S_TITLE,m_null,KT_X1,KT_Y2,{NULL},NULL,NULL,NULL,NULL}, + {"FOLLOW MODE" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y2+ 1*8,{&key_map_follow},NULL,NULL,NULL,NULL}, + {"ZOOM IN" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y2+ 2*8,{&key_map_zoomin},NULL,NULL,NULL,NULL}, + {"ZOOM OUT" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y2+ 3*8,{&key_map_zoomout},NULL,NULL,NULL,NULL}, + {"MARK PLACE" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y2+ 4*8,{&key_map_mark},NULL,NULL,NULL,NULL}, + {"CLEAR MARKS" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y2+ 5*8,{&key_map_clear},NULL,NULL,NULL,NULL}, + {"FULL/ZOOM" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y2+ 6*8,{&key_map_gobig},NULL,NULL,NULL,NULL}, + {"GRID" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y2+ 7*8,{&key_map_grid},NULL,NULL,NULL,NULL}, + + {"WEAPONS" ,S_SKIP|S_TITLE,m_null,KT_X3,KT_Y1,{NULL},NULL,NULL,NULL,NULL}, + {"FIST" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+ 1*8,{&key_weapon1},NULL,NULL,NULL,NULL}, + {"PISTOL" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+ 2*8,{&key_weapon2},NULL,NULL,NULL,NULL}, + {"SHOTGUN" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+ 3*8,{&key_weapon3},NULL,NULL,NULL,NULL}, + {"CHAINGUN" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+ 4*8,{&key_weapon4},NULL,NULL,NULL,NULL}, + {"ROCKET" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+ 5*8,{&key_weapon5},NULL,NULL,NULL,NULL}, + {"PLASMA" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+ 6*8,{&key_weapon6},NULL,NULL,NULL,NULL}, + {"BFG 9000" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+ 7*8,{&key_weapon7},NULL,NULL,NULL,NULL}, + {"CHAINSAW" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+ 8*8,{&key_weapon8},NULL,NULL,NULL,NULL}, + {"SSG" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+ 9*8,{&key_weapon9},NULL,NULL,NULL,NULL}, + {"BEST" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+10*8,{&key_weapontoggle},NULL,NULL,NULL,NULL}, + {"FIRE" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+11*8,{&key_fire},&mousebfire,&joybfire,NULL,NULL}, + + {"MOVEMENT" ,S_SKIP|S_TITLE,m_null,KT_X3,KT_Y3,{NULL},NULL,NULL,NULL,NULL}, + {"FORWARD" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+ 1*8,{&key_up},&mousebforward,NULL,NULL,NULL}, + {"BACKWARD" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+ 2*8,{&key_down},NULL,NULL,NULL,NULL}, + {"TURN LEFT" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+ 3*8,{&key_left},NULL,NULL,NULL,NULL}, + {"TURN RIGHT" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+ 4*8,{&key_right},NULL,NULL,NULL,NULL}, + {"RUN" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+ 5*8,{&key_speed},0,&joybspeed,NULL,NULL}, + {"STRAFE LEFT" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+ 6*8,{&key_strafeleft},NULL,NULL,NULL,NULL}, + {"STRAFE RIGHT",S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+ 7*8,{&key_straferight},NULL,NULL,NULL,NULL}, + {"STRAFE" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+ 8*8,{&key_strafe},&mousebstrafe,&joybstrafe,NULL,NULL}, + {"AUTORUN" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+ 9*8,{&key_autorun},NULL,NULL,NULL,NULL}, + {"180 TURN" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+10*8,{&key_reverse},NULL,NULL,NULL,NULL}, + {"USE" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+11*8,{&key_use},&mousebforward,&joybuse,NULL,NULL}, + + {"GAME" ,S_SKIP|S_TITLE,m_null,KT_X2,KT_Y1,{NULL},NULL,NULL,NULL,NULL}, + {"SAVE" ,S_SKIP|S_KEY,m_null,KT_X2,KT_Y1+ 1*8,{&key_savegame},NULL,NULL,NULL,NULL}, + {"LOAD" ,S_SKIP|S_KEY,m_null,KT_X2,KT_Y1+ 2*8,{&key_loadgame},NULL,NULL,NULL,NULL}, + {"QUICKSAVE" ,S_SKIP|S_KEY,m_null,KT_X2,KT_Y1+ 3*8,{&key_quicksave},NULL,NULL,NULL,NULL}, + {"END GAME" ,S_SKIP|S_KEY,m_null,KT_X2,KT_Y1+ 4*8,{&key_endgame},NULL,NULL,NULL,NULL}, + {"QUICKLOAD" ,S_SKIP|S_KEY,m_null,KT_X2,KT_Y1+ 5*8,{&key_quickload},NULL,NULL,NULL,NULL}, + {"QUIT" ,S_SKIP|S_KEY,m_null,KT_X2,KT_Y1+ 6*8,{&key_quit},NULL,NULL,NULL,NULL}, + + // Final entry + + {0,S_SKIP|S_END,m_null,0,0,{NULL},NULL,NULL,NULL,NULL} +}; + +#define SPACEWIDTH 4 + +/* cph 2006/08/06 + * M_DrawString() is the old M_DrawMenuString, except that it is not tied to + * menu_buffer - no reason to force all the callers to write into one array! */ + +static void M_DrawString(int cx, int cy, int color, const char* ch) +{ + int w; + int c; + + while (*ch) { + c = *ch++; // get next char + c = toupper(c) - HU_FONTSTART; + if (c < 0 || c> HU_FONTSIZE) + { + cx += SPACEWIDTH; // space + continue; + } + w = hu_font[c].width; + if (cx + w > 320) + break; + + // V_DrawpatchTranslated() will draw the string in the + // desired color, colrngs[color] + + // CPhipps - patch drawing updated + V_DrawNumPatch(cx, cy, 0, hu_font[c].lumpnum, color, VPT_STRETCH | VPT_TRANS); + // The screen is cramped, so trim one unit from each + // character so they butt up against each other. + cx += w - 1; + } +} + +// M_DrawMenuString() draws the string in menu_buffer[] + +static void M_DrawMenuString(int cx, int cy, int color) +{ + M_DrawString(cx, cy, color, menu_buffer); +} + +// M_GetPixelWidth() returns the number of pixels in the width of +// the string, NOT the number of chars in the string. + +static int M_GetPixelWidth(const char* ch) +{ + int len = 0; + int c; + + while (*ch) { + c = *ch++; // pick up next char + c = toupper(c) - HU_FONTSTART; + if (c < 0 || c > HU_FONTSIZE) + { + len += SPACEWIDTH; // space + continue; + } + len += hu_font[c].width; + len--; // adjust so everything fits + } + len++; // replace what you took away on the last char only + return len; +} + +static void M_DrawStringCentered(int cx, int cy, int color, const char* ch) +{ + M_DrawString(cx - M_GetPixelWidth(ch)/2, cy, color, ch); +} + +// +// M_DrawHelp +// +// This displays the help screen + +void M_DrawHelp (void) +{ + inhelpscreens = true; // killough 10/98 + M_DrawBackground("FLOOR4_6", 0); + + M_DrawScreenItems(helpstrings); +} + +// +// End of Dynamic HELP screen // phares 3/2/98 +// +//////////////////////////////////////////////////////////////////////////// + +enum { + prog, + prog_stub, + prog_stub1, + prog_stub2, + adcr +}; + +enum { + cr_prog=0, + cr_adcr=2, +}; + +#define CR_S 9 +#define CR_X 20 +#define CR_X2 50 +#define CR_Y 32 +#define CR_SH 9 + +setup_menu_t cred_settings[]={ + + {"Programmers",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X, CR_Y + CR_S*prog + CR_SH*cr_prog,{NULL},NULL,NULL,NULL,NULL}, + {"Florian 'Proff' Schulze",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(prog+1) + CR_SH*cr_prog,{NULL},NULL,NULL,NULL,NULL}, + {"Colin Phipps",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(prog+2) + CR_SH*cr_prog,{NULL},NULL,NULL,NULL,NULL}, + {"Neil Stevens",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(prog+3) + CR_SH*cr_prog,{NULL},NULL,NULL,NULL,NULL}, + {"Andrey Budko",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(prog+4) + CR_SH*cr_prog,{NULL},NULL,NULL,NULL,NULL}, + + {"Additional Credit To",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X, CR_Y + CR_S*adcr + CR_SH*cr_adcr,{NULL},NULL,NULL,NULL,NULL}, + {"id Software for DOOM",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(adcr+1)+CR_SH*cr_adcr,{NULL},NULL,NULL,NULL,NULL}, + {"TeamTNT for BOOM",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(adcr+2)+CR_SH*cr_adcr,{NULL},NULL,NULL,NULL,NULL}, + {"Lee Killough for MBF",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(adcr+3)+CR_SH*cr_adcr,{NULL},NULL,NULL,NULL,NULL}, + {"The DOSDoom-Team for DOSDOOM",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(adcr+4)+CR_SH*cr_adcr,{NULL},NULL,NULL,NULL,NULL}, + {"Randy Heit for ZDOOM",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(adcr+5)+CR_SH*cr_adcr,{NULL},NULL,NULL,NULL,NULL}, + {"Michael 'Kodak' Ryssen for DOOMGL",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(adcr+6)+CR_SH*cr_adcr,{NULL},NULL,NULL,NULL,NULL}, + {"Jess Haas for lSDLDoom",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(adcr+7) + CR_SH*cr_adcr,{NULL},NULL,NULL,NULL,NULL}, + {"all others who helped (see AUTHORS file)",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(adcr+8)+CR_SH*cr_adcr,{NULL},NULL,NULL,NULL,NULL}, + + {0,S_SKIP|S_END,m_null,0,0,{NULL},NULL,NULL,NULL,NULL} +}; + +void M_DrawCredits(void) // killough 10/98: credit screen +{ + inhelpscreens = true; + M_DrawBackground(gamemode==shareware ? "CEIL5_1" : "MFLR8_4", 0); + V_DrawNamePatch(115,9,0, "PRBOOM",CR_GOLD, VPT_TRANS | VPT_STRETCH); + M_DrawScreenItems(cred_settings); +} + +static int M_IndexInChoices(const char *str, const char **choices) { + int i = 0; + + while (*choices != NULL) { + if (!strcmp(str, *choices)) + return i; + i++; + choices++; + } + return 0; +} + +///////////////////////////////////////////////////////////////////////////// +// +// M_Responder +// +// Examines incoming keystrokes and button pushes and determines some +// action based on the state of the system. +// + +boolean M_Responder (event_t* ev) { + int ch; + int i; + static int joywait = 0; + static int mousewait = 0; + + ch = -1; // will be changed to a legit char if we're going to use it here + + // Process joystick input + + if (ev->type == ev_joystick && joywait < I_GetTime()) { + if (ev->data3 == -1) + { + ch = key_menu_up; // phares 3/7/98 + joywait = I_GetTime() + 5; + } + else if (ev->data3 == 1) + { + ch = key_menu_down; // phares 3/7/98 + joywait = I_GetTime() + 5; + } + + if (ev->data2 == -1) + { + ch = key_menu_left; // phares 3/7/98 + joywait = I_GetTime() + 2; + } + else if (ev->data2 == 1) + { + ch = key_menu_right; // phares 3/7/98 + joywait = I_GetTime() + 2; + } + + if (ev->data1&1) + { + ch = key_menu_enter; // phares 3/7/98 + joywait = I_GetTime() + 5; + } + + if (ev->data1&2) + { + ch = key_menu_backspace; // phares 3/7/98 + joywait = I_GetTime() + 5; + } + + // phares 4/4/98: + // Handle joystick buttons 3 and 4, and allow them to pass down + // to where key binding can eat them. + + if (setup_active && set_keybnd_active) { + if (ev->data1&4) { + ch = 0; // meaningless, just to get you past the check for -1 + joywait = I_GetTime() + 5; + } + if (ev->data1&8) { + ch = 0; // meaningless, just to get you past the check for -1 + joywait = I_GetTime() + 5; + } + } + + } else { + // Process mouse input + + if (ev->type == ev_mouse && mousewait < I_GetTime()) { + + // Only process mouse button input + + if (ev->data1&1) + { + ch = key_menu_enter; // phares 3/7/98 + mousewait = I_GetTime() + 15; + } + + if (ev->data1&2) + { + ch = key_menu_backspace; // phares 3/7/98 + mousewait = I_GetTime() + 15; + } + + // phares 4/4/98: + // Handle mouse button 3, and allow it to pass down + // to where key binding can eat it. + + if (setup_active && set_keybnd_active) + if (ev->data1&4) + { + ch = 0; // meaningless, just to get you past the check for -1 + mousewait = I_GetTime() + 15; + } + } + else + + // Process keyboard input + + if (ev->type == ev_keydown) + { + ch = ev->data1; // phares 4/11/98: + if (ch == KEYD_RSHIFT) // For chat string processing, need + shiftdown = true; // to know when shift key is up or + } // down so you can get at the !,#, + else if (ev->type == ev_keyup) // etc. keys. Keydowns are allowed + if (ev->data1 == KEYD_RSHIFT) // past this point, but keyups aren't + shiftdown = false; // so we need to note the difference + } // here using the 'shiftdown' boolean. + + if (ch == -1) + return false; // we can't use the event here + + // Save Game string input + + if (saveStringEnter) { + if (ch == key_menu_backspace) // phares 3/7/98 + { + if (saveCharIndex > 0) + { + saveCharIndex--; + savegamestrings[saveSlot][saveCharIndex] = 0; + } + } + + else if (ch == key_menu_escape) // phares 3/7/98 + { + saveStringEnter = 0; + strcpy(&savegamestrings[saveSlot][0],saveOldString); + } + + else if (ch == key_menu_enter) // phares 3/7/98 + { + saveStringEnter = 0; + if (savegamestrings[saveSlot][0]) + M_DoSave(saveSlot); + } + + else + { + ch = toupper(ch); + if (ch >= 32 && ch <= 127 && + saveCharIndex < SAVESTRINGSIZE-1 && + M_StringWidth(savegamestrings[saveSlot]) < (SAVESTRINGSIZE-2)*8) + { + savegamestrings[saveSlot][saveCharIndex++] = ch; + savegamestrings[saveSlot][saveCharIndex] = 0; + } + } + return true; + } + + // Take care of any messages that need input + + if (messageToPrint) { + if (messageNeedsInput == true && + !(ch == ' ' || ch == 'n' || ch == 'y' || ch == key_escape)) // phares + return false; + + menuactive = messageLastMenuActive; + messageToPrint = 0; + if (messageRoutine) + messageRoutine(ch); + + menuactive = false; + S_StartSound(NULL,sfx_swtchx); + return true; + } + + /* killough 2/22/98: add support for screenshot key: + * cph 2001/02/04: no need for this to be a gameaction, just do it + */ + if (ch == key_screenshot) + { + M_ScreenShot (); + // Don't eat the keypress in this case. See sf bug #1843280. + } + + // If there is no active menu displayed... + + if (!menuactive) { // phares + if (ch == key_autorun) // Autorun // V + { + autorun = !autorun; + return true; + } + + if (ch == key_help) // Help key + { + M_StartControlPanel (); + + currentMenu = &HelpDef; // killough 10/98: new help screen + + itemOn = 0; + S_StartSound(NULL,sfx_swtchn); + return true; + } + + if (ch == key_savegame) // Save Game + { + M_StartControlPanel(); + S_StartSound(NULL,sfx_swtchn); + M_SaveGame(0); + return true; + } + + if (ch == key_loadgame) // Load Game + { + M_StartControlPanel(); + S_StartSound(NULL,sfx_swtchn); + M_LoadGame(0); + return true; + } + + if (ch == key_soundvolume) // Sound Volume + { + M_StartControlPanel (); + currentMenu = &SoundDef; + itemOn = sfx_vol; + S_StartSound(NULL,sfx_swtchn); + return true; + } + + if (ch == key_quicksave) // Quicksave + { + S_StartSound(NULL,sfx_swtchn); + M_QuickSave(); + return true; + } + + if (ch == key_endgame) // End game + { + S_StartSound(NULL,sfx_swtchn); + M_EndGame(0); + return true; + } + + if (ch == key_messages) // Toggle messages + { + M_ChangeMessages(0); + S_StartSound(NULL,sfx_swtchn); + return true; + } + + if (ch == key_quickload) // Quickload + { + S_StartSound(NULL,sfx_swtchn); + M_QuickLoad(); + return true; + } + + if (ch == key_quit) // Quit DOOM + { + S_StartSound(NULL,sfx_swtchn); + M_QuitDOOM(0); + return true; + } + + if (ch == key_gamma) // gamma toggle + { + usegamma++; + if (usegamma > 4) + usegamma = 0; + players[consoleplayer].message = + usegamma == 0 ? s_GAMMALVL0 : + usegamma == 1 ? s_GAMMALVL1 : + usegamma == 2 ? s_GAMMALVL2 : + usegamma == 3 ? s_GAMMALVL3 : + s_GAMMALVL4; + V_SetPalette(0); + return true; + } + + + if (ch == key_zoomout) // zoom out + { + if ((automapmode & am_active) || chat_on) + return false; + M_SizeDisplay(0); + S_StartSound(NULL,sfx_stnmov); + return true; + } + + if (ch == key_zoomin) // zoom in + { // jff 2/23/98 + if ((automapmode & am_active) || chat_on) // allow + return false; // key_hud==key_zoomin + M_SizeDisplay(1); // ^ + S_StartSound(NULL,sfx_stnmov); // | + return true; // phares + } + + if (ch == key_hud) // heads-up mode + { + if ((automapmode & am_active) || chat_on) // jff 2/22/98 + return false; // HUD mode control + if (screenSize<8) // function on default F5 + while (screenSize<8 || !hud_displayed) // make hud visible + M_SizeDisplay(1); // when configuring it + else + { + hud_displayed = 1; //jff 3/3/98 turn hud on + hud_active = (hud_active+1)%3; // cycle hud_active + if (!hud_active) //jff 3/4/98 add distributed + { + hud_distributed = !hud_distributed; // to cycle + HU_MoveHud(); //jff 3/9/98 move it now to avoid glitch + } + } + return true; + } + + /* killough 10/98: allow key shortcut into Setup menu */ + if (ch == key_setup) { + M_StartControlPanel(); + S_StartSound(NULL,sfx_swtchn); + M_SetupNextMenu(&SetupDef); + return true; + } + } + // Pop-up Main menu? + + if (!menuactive) + { + if (ch == key_escape) // phares + { + M_StartControlPanel (); + S_StartSound(NULL,sfx_swtchn); + return true; + } + return false; + } + + // phares 3/26/98 - 4/11/98: + // Setup screen key processing + + if (setup_active) { + setup_menu_t* ptr1= current_setup_menu + set_menu_itemon; + setup_menu_t* ptr2 = NULL; + + // phares 4/19/98: + // Catch the response to the 'reset to default?' verification + // screen + + if (default_verify) + { + if (toupper(ch) == 'Y') { + M_ResetDefaults(); + default_verify = false; + M_SelectDone(ptr1); + } + else if (toupper(ch) == 'N') { + default_verify = false; + M_SelectDone(ptr1); + } + return true; + } + + // Common processing for some items + + if (setup_select) { // changing an entry + if (ch == key_menu_escape) // Exit key = no change + { + M_SelectDone(ptr1); // phares 4/17/98 + setup_gather = false; // finished gathering keys, if any + return true; + } + + if (ptr1->m_flags & S_YESNO) // yes or no setting? + { + if (ch == key_menu_enter) { + *ptr1->var.def->location.pi = !*ptr1->var.def->location.pi; // killough 8/15/98 + + // phares 4/14/98: + // If not in demoplayback, demorecording, or netgame, + // and there's a second variable in var2, set that + // as well + + // killough 8/15/98: add warning messages + + if (ptr1->m_flags & (S_LEVWARN | S_PRGWARN)) + warn_about_changes(ptr1->m_flags & // killough 10/98 + (S_LEVWARN | S_PRGWARN)); + else + M_UpdateCurrent(ptr1->var.def); + + if (ptr1->action) // killough 10/98 + ptr1->action(); + } + M_SelectDone(ptr1); // phares 4/17/98 + return true; + } + + if (ptr1->m_flags & S_CRITEM) + { + if (ch != key_menu_enter) + { + ch -= 0x30; // out of ascii + if (ch < 0 || ch > 9) + return true; // ignore + *ptr1->var.def->location.pi = ch; + } + if (ptr1->action) // killough 10/98 + ptr1->action(); + M_SelectDone(ptr1); // phares 4/17/98 + return true; + } + + if (ptr1->m_flags & S_NUM) // number? + { + if (setup_gather) { // gathering keys for a value? + /* killough 10/98: Allow negatives, and use a more + * friendly input method (e.g. don't clear value early, + * allow backspace, and return to original value if bad + * value is entered). + */ + if (ch == key_menu_enter) { + if (gather_count) { // Any input? + int value; + + gather_buffer[gather_count] = 0; + value = atoi(gather_buffer); // Integer value + + if ((ptr1->var.def->minvalue != UL && + value < ptr1->var.def->minvalue) || + (ptr1->var.def->maxvalue != UL && + value > ptr1->var.def->maxvalue)) + warn_about_changes(S_BADVAL); + else { + *ptr1->var.def->location.pi = value; + + /* killough 8/9/98: fix numeric vars + * killough 8/15/98: add warning message + */ + if (ptr1->m_flags & (S_LEVWARN | S_PRGWARN)) + warn_about_changes(ptr1->m_flags & + (S_LEVWARN | S_PRGWARN)); + else + M_UpdateCurrent(ptr1->var.def); + + if (ptr1->action) // killough 10/98 + ptr1->action(); + } + } + M_SelectDone(ptr1); // phares 4/17/98 + setup_gather = false; // finished gathering keys + return true; + } + + if (ch == key_menu_backspace && gather_count) { + gather_count--; + return true; + } + + if (gather_count >= MAXGATHER) + return true; + + if (!isdigit(ch) && ch != '-') + return true; // ignore + + /* killough 10/98: character-based numerical input */ + gather_buffer[gather_count++] = ch; + } + return true; + } + + if (ptr1->m_flags & S_CHOICE) // selection of choices? + { + if (ch == key_menu_left) { + if (ptr1->var.def->type == def_int) { + int value = *ptr1->var.def->location.pi; + + value = value - 1; + if ((ptr1->var.def->minvalue != UL && + value < ptr1->var.def->minvalue)) + value = ptr1->var.def->minvalue; + if ((ptr1->var.def->maxvalue != UL && + value > ptr1->var.def->maxvalue)) + value = ptr1->var.def->maxvalue; + if (*ptr1->var.def->location.pi != value) + S_StartSound(NULL,sfx_pstop); + *ptr1->var.def->location.pi = value; + } + if (ptr1->var.def->type == def_str) { + int old_value, value; + + old_value = M_IndexInChoices(*ptr1->var.def->location.ppsz, + ptr1->selectstrings); + value = old_value - 1; + if (value < 0) + value = 0; + if (old_value != value) + S_StartSound(NULL,sfx_pstop); + *ptr1->var.def->location.ppsz = ptr1->selectstrings[value]; + } + } + if (ch == key_menu_right) { + if (ptr1->var.def->type == def_int) { + int value = *ptr1->var.def->location.pi; + + value = value + 1; + if ((ptr1->var.def->minvalue != UL && + value < ptr1->var.def->minvalue)) + value = ptr1->var.def->minvalue; + if ((ptr1->var.def->maxvalue != UL && + value > ptr1->var.def->maxvalue)) + value = ptr1->var.def->maxvalue; + if (*ptr1->var.def->location.pi != value) + S_StartSound(NULL,sfx_pstop); + *ptr1->var.def->location.pi = value; + } + if (ptr1->var.def->type == def_str) { + int old_value, value; + + old_value = M_IndexInChoices(*ptr1->var.def->location.ppsz, + ptr1->selectstrings); + value = old_value + 1; + if (ptr1->selectstrings[value] == NULL) + value = old_value; + if (old_value != value) + S_StartSound(NULL,sfx_pstop); + *ptr1->var.def->location.ppsz = ptr1->selectstrings[value]; + } + } + if (ch == key_menu_enter) { + // phares 4/14/98: + // If not in demoplayback, demorecording, or netgame, + // and there's a second variable in var2, set that + // as well + + // killough 8/15/98: add warning messages + + if (ptr1->m_flags & (S_LEVWARN | S_PRGWARN)) + warn_about_changes(ptr1->m_flags & // killough 10/98 + (S_LEVWARN | S_PRGWARN)); + else + M_UpdateCurrent(ptr1->var.def); + + if (ptr1->action) // killough 10/98 + ptr1->action(); + M_SelectDone(ptr1); // phares 4/17/98 + } + return true; + } + + } + + // Key Bindings + + if (set_keybnd_active) // on a key binding setup screen + if (setup_select) // incoming key or button gets bound + { + if (ev->type == ev_joystick) + { + int oldbutton,group; + boolean search = true; + + if (!ptr1->m_joy) + return true; // not a legal action here (yet) + + // see if the button is already bound elsewhere. if so, you + // have to swap bindings so the action where it's currently + // bound doesn't go dead. Since there is more than one + // keybinding screen, you have to search all of them for + // any duplicates. You're only interested in the items + // that belong to the same group as the one you're changing. + + oldbutton = *ptr1->m_joy; + group = ptr1->m_group; + if (ev->data1 & 1) + ch = 0; + else if (ev->data1 & 2) + ch = 1; + else if (ev->data1 & 4) + ch = 2; + else if (ev->data1 & 8) + ch = 3; + else + return true; + for (i = 0 ; keys_settings[i] && search ; i++) + for (ptr2 = keys_settings[i] ; !(ptr2->m_flags & S_END) ; ptr2++) + if (ptr2->m_group == group && ptr1 != ptr2) + if (ptr2->m_flags & S_KEY && ptr2->m_joy) + if (*ptr2->m_joy == ch) + { + *ptr2->m_joy = oldbutton; + search = false; + break; + } + *ptr1->m_joy = ch; + } + else if (ev->type == ev_mouse) + { + int oldbutton,group; + boolean search = true; + + if (!ptr1->m_mouse) + return true; // not a legal action here (yet) + + // see if the button is already bound elsewhere. if so, you + // have to swap bindings so the action where it's currently + // bound doesn't go dead. Since there is more than one + // keybinding screen, you have to search all of them for + // any duplicates. You're only interested in the items + // that belong to the same group as the one you're changing. + + oldbutton = *ptr1->m_mouse; + group = ptr1->m_group; + if (ev->data1 & 1) + ch = 0; + else if (ev->data1 & 2) + ch = 1; + else if (ev->data1 & 4) + ch = 2; + else + return true; + for (i = 0 ; keys_settings[i] && search ; i++) + for (ptr2 = keys_settings[i] ; !(ptr2->m_flags & S_END) ; ptr2++) + if (ptr2->m_group == group && ptr1 != ptr2) + if (ptr2->m_flags & S_KEY && ptr2->m_mouse) + if (*ptr2->m_mouse == ch) + { + *ptr2->m_mouse = oldbutton; + search = false; + break; + } + *ptr1->m_mouse = ch; + } + else // keyboard key + { + int oldkey,group; + boolean search = true; + + // see if 'ch' is already bound elsewhere. if so, you have + // to swap bindings so the action where it's currently + // bound doesn't go dead. Since there is more than one + // keybinding screen, you have to search all of them for + // any duplicates. You're only interested in the items + // that belong to the same group as the one you're changing. + + // if you find that you're trying to swap with an action + // that has S_KEEP set, you can't bind ch; it's already + // bound to that S_KEEP action, and that action has to + // keep that key. + + oldkey = *ptr1->var.m_key; + group = ptr1->m_group; + for (i = 0 ; keys_settings[i] && search ; i++) + for (ptr2 = keys_settings[i] ; !(ptr2->m_flags & S_END) ; ptr2++) + if (ptr2->m_flags & (S_KEY|S_KEEP) && + ptr2->m_group == group && + ptr1 != ptr2) + if (*ptr2->var.m_key == ch) + { + if (ptr2->m_flags & S_KEEP) + return true; // can't have it! + *ptr2->var.m_key = oldkey; + search = false; + break; + } + *ptr1->var.m_key = ch; + } + + M_SelectDone(ptr1); // phares 4/17/98 + return true; + } + + // Weapons + + if (set_weapon_active) // on the weapons setup screen + if (setup_select) // changing an entry + { + if (ch != key_menu_enter) + { + ch -= '0'; // out of ascii + if (ch < 1 || ch > 9) + return true; // ignore + + // Plasma and BFG don't exist in shareware + // killough 10/98: allow it anyway, since this + // isn't the game itself, just setting preferences + + // see if 'ch' is already assigned elsewhere. if so, + // you have to swap assignments. + + // killough 11/98: simplified + + for (i = 0; (ptr2 = weap_settings[i]); i++) + for (; !(ptr2->m_flags & S_END); ptr2++) + if (ptr2->m_flags & S_WEAP && + *ptr2->var.def->location.pi == ch && ptr1 != ptr2) + { + *ptr2->var.def->location.pi = *ptr1->var.def->location.pi; + goto end; + } + end: + *ptr1->var.def->location.pi = ch; + } + + M_SelectDone(ptr1); // phares 4/17/98 + return true; + } + + // Automap + + if (set_auto_active) // on the automap setup screen + if (setup_select) // incoming key + { + if (ch == key_menu_down) + { + if (++color_palette_y == 16) + color_palette_y = 0; + S_StartSound(NULL,sfx_itemup); + return true; + } + + if (ch == key_menu_up) + { + if (--color_palette_y < 0) + color_palette_y = 15; + S_StartSound(NULL,sfx_itemup); + return true; + } + + if (ch == key_menu_left) + { + if (--color_palette_x < 0) + color_palette_x = 15; + S_StartSound(NULL,sfx_itemup); + return true; + } + + if (ch == key_menu_right) + { + if (++color_palette_x == 16) + color_palette_x = 0; + S_StartSound(NULL,sfx_itemup); + return true; + } + + if (ch == key_menu_enter) + { + *ptr1->var.def->location.pi = color_palette_x + 16*color_palette_y; + M_SelectDone(ptr1); // phares 4/17/98 + colorbox_active = false; + return true; + } + } + + // killough 10/98: consolidate handling into one place: + if (setup_select && + set_enemy_active | set_general_active | set_chat_active | + set_mess_active | set_status_active | set_compat_active) + { + if (ptr1->m_flags & S_STRING) // creating/editing a string? + { + if (ch == key_menu_backspace) // backspace and DEL + { + if (chat_string_buffer[chat_index] == 0) + { + if (chat_index > 0) + chat_string_buffer[--chat_index] = 0; + } + // shift the remainder of the text one char left + else + strcpy(&chat_string_buffer[chat_index], + &chat_string_buffer[chat_index+1]); + } + else if (ch == key_menu_left) // move cursor left + { + if (chat_index > 0) + chat_index--; + } + else if (ch == key_menu_right) // move cursor right + { + if (chat_string_buffer[chat_index] != 0) + chat_index++; + } + else if ((ch == key_menu_enter) || + (ch == key_menu_escape)) + { + *ptr1->var.def->location.ppsz = chat_string_buffer; + M_SelectDone(ptr1); // phares 4/17/98 + } + + // Adding a char to the text. Has to be a printable + // char, and you can't overrun the buffer. If the + // chat string gets larger than what the screen can hold, + // it is dealt with when the string is drawn (above). + + else if ((ch >= 32) && (ch <= 126)) + if ((chat_index+1) < CHAT_STRING_BFR_SIZE) + { + if (shiftdown) + ch = shiftxform[ch]; + if (chat_string_buffer[chat_index] == 0) + { + chat_string_buffer[chat_index++] = ch; + chat_string_buffer[chat_index] = 0; + } + else + chat_string_buffer[chat_index++] = ch; + } + return true; + } + + M_SelectDone(ptr1); // phares 4/17/98 + return true; + } + + // Not changing any items on the Setup screens. See if we're + // navigating the Setup menus or selecting an item to change. + + if (ch == key_menu_down) + { + ptr1->m_flags &= ~S_HILITE; // phares 4/17/98 + do + if (ptr1->m_flags & S_END) + { + set_menu_itemon = 0; + ptr1 = current_setup_menu; + } + else + { + set_menu_itemon++; + ptr1++; + } + while (ptr1->m_flags & S_SKIP); + M_SelectDone(ptr1); // phares 4/17/98 + return true; + } + + if (ch == key_menu_up) + { + ptr1->m_flags &= ~S_HILITE; // phares 4/17/98 + do + { + if (set_menu_itemon == 0) + do + set_menu_itemon++; + while(!((current_setup_menu + set_menu_itemon)->m_flags & S_END)); + set_menu_itemon--; + } + while((current_setup_menu + set_menu_itemon)->m_flags & S_SKIP); + M_SelectDone(current_setup_menu + set_menu_itemon); // phares 4/17/98 + return true; + } + + if (ch == key_menu_enter) + { + int flags = ptr1->m_flags; + + // You've selected an item to change. Highlight it, post a new + // message about what to do, and get ready to process the + // change. + // + // killough 10/98: use friendlier char-based input buffer + + if (flags & S_NUM) + { + setup_gather = true; + print_warning_about_changes = false; + gather_count = 0; + } + else if (flags & S_COLOR) + { + int color = *ptr1->var.def->location.pi; + + if (color < 0 || color > 255) // range check the value + color = 0; // 'no show' if invalid + + color_palette_x = *ptr1->var.def->location.pi & 15; + color_palette_y = *ptr1->var.def->location.pi >> 4; + colorbox_active = true; + } + else if (flags & S_STRING) + { + // copy chat string into working buffer; trim if needed. + // free the old chat string memory and replace it with + // the (possibly larger) new memory for editing purposes + // + // killough 10/98: fix bugs, simplify + + chat_string_buffer = malloc(CHAT_STRING_BFR_SIZE); + strncpy(chat_string_buffer, + *ptr1->var.def->location.ppsz, CHAT_STRING_BFR_SIZE); + + // guarantee null delimiter + chat_string_buffer[CHAT_STRING_BFR_SIZE-1] = 0; + + // set chat table pointer to working buffer + // and free old string's memory. + + free((char*)*ptr1->var.def->location.ppsz); + *ptr1->var.def->location.ppsz = chat_string_buffer; + chat_index = 0; // current cursor position in chat_string_buffer + } + else if (flags & S_RESET) + default_verify = true; + + ptr1->m_flags |= S_SELECT; + setup_select = true; + S_StartSound(NULL,sfx_itemup); + return true; + } + + if ((ch == key_menu_escape) || (ch == key_menu_backspace)) + { + if (ch == key_menu_escape) // Clear all menus + M_ClearMenus(); + else // key_menu_backspace = return to Setup Menu + if (currentMenu->prevMenu) + { + currentMenu = currentMenu->prevMenu; + itemOn = currentMenu->lastOn; + S_StartSound(NULL,sfx_swtchn); + } + ptr1->m_flags &= ~(S_HILITE|S_SELECT);// phares 4/19/98 + setup_active = false; + set_keybnd_active = false; + set_weapon_active = false; + set_status_active = false; + set_auto_active = false; + set_enemy_active = false; + set_mess_active = false; + set_chat_active = false; + colorbox_active = false; + default_verify = false; // phares 4/19/98 + set_general_active = false; // killough 10/98 + set_compat_active = false; // killough 10/98 + HU_Start(); // catch any message changes // phares 4/19/98 + S_StartSound(NULL,sfx_swtchx); + return true; + } + + // Some setup screens may have multiple screens. + // When there are multiple screens, m_prev and m_next items need to + // be placed on the appropriate screen tables so the user can + // move among the screens using the left and right arrow keys. + // The m_var1 field contains a pointer to the appropriate screen + // to move to. + + if (ch == key_menu_left) + { + ptr2 = ptr1; + do + { + ptr2++; + if (ptr2->m_flags & S_PREV) + { + ptr1->m_flags &= ~S_HILITE; + mult_screens_index--; + current_setup_menu = ptr2->var.menu; + set_menu_itemon = 0; + print_warning_about_changes = false; // killough 10/98 + while (current_setup_menu[set_menu_itemon++].m_flags&S_SKIP); + current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE; + S_StartSound(NULL,sfx_pstop); // killough 10/98 + return true; + } + } + while (!(ptr2->m_flags & S_END)); + } + + if (ch == key_menu_right) + { + ptr2 = ptr1; + do + { + ptr2++; + if (ptr2->m_flags & S_NEXT) + { + ptr1->m_flags &= ~S_HILITE; + mult_screens_index++; + current_setup_menu = ptr2->var.menu; + set_menu_itemon = 0; + print_warning_about_changes = false; // killough 10/98 + while (current_setup_menu[set_menu_itemon++].m_flags&S_SKIP); + current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE; + S_StartSound(NULL,sfx_pstop); // killough 10/98 + return true; + } + } + while (!(ptr2->m_flags & S_END)); + } + + } // End of Setup Screen processing + + // From here on, these navigation keys are used on the BIG FONT menus + // like the Main Menu. + + if (ch == key_menu_down) // phares 3/7/98 + { + do + { + if (itemOn+1 > currentMenu->numitems-1) + itemOn = 0; + else + itemOn++; + S_StartSound(NULL,sfx_pstop); + } + while(currentMenu->menuitems[itemOn].status==-1); + return true; + } + + if (ch == key_menu_up) // phares 3/7/98 + { + do + { + if (!itemOn) + itemOn = currentMenu->numitems-1; + else + itemOn--; + S_StartSound(NULL,sfx_pstop); + } + while(currentMenu->menuitems[itemOn].status==-1); + return true; + } + + if (ch == key_menu_left) // phares 3/7/98 + { + if (currentMenu->menuitems[itemOn].routine && + currentMenu->menuitems[itemOn].status == 2) + { + S_StartSound(NULL,sfx_stnmov); + currentMenu->menuitems[itemOn].routine(0); + } + return true; + } + + if (ch == key_menu_right) // phares 3/7/98 + { + if (currentMenu->menuitems[itemOn].routine && + currentMenu->menuitems[itemOn].status == 2) + { + S_StartSound(NULL,sfx_stnmov); + currentMenu->menuitems[itemOn].routine(1); + } + return true; + } + + if (ch == key_menu_enter) // phares 3/7/98 + { + if (currentMenu->menuitems[itemOn].routine && + currentMenu->menuitems[itemOn].status) + { + currentMenu->lastOn = itemOn; + if (currentMenu->menuitems[itemOn].status == 2) + { + currentMenu->menuitems[itemOn].routine(1); // right arrow + S_StartSound(NULL,sfx_stnmov); + } + else + { + currentMenu->menuitems[itemOn].routine(itemOn); + S_StartSound(NULL,sfx_pistol); + } + } + //jff 3/24/98 remember last skill selected + // killough 10/98 moved to skill-specific functions + return true; + } + + if (ch == key_menu_escape) // phares 3/7/98 + { + currentMenu->lastOn = itemOn; + M_ClearMenus (); + S_StartSound(NULL,sfx_swtchx); + return true; + } + + if (ch == key_menu_backspace) // phares 3/7/98 + { + currentMenu->lastOn = itemOn; + + // phares 3/30/98: + // add checks to see if you're in the extended help screens + // if so, stay with the same menu definition, but bump the + // index back one. if the index bumps back far enough ( == 0) + // then you can return to the Read_Thisn menu definitions + + if (currentMenu->prevMenu) + { + if (currentMenu == &ExtHelpDef) + { + if (--extended_help_index == 0) + { + currentMenu = currentMenu->prevMenu; + extended_help_index = 1; // reset + } + } + else + currentMenu = currentMenu->prevMenu; + itemOn = currentMenu->lastOn; + S_StartSound(NULL,sfx_swtchn); + } + return true; + } + + else + { + for (i = itemOn+1;i < currentMenu->numitems;i++) + if (currentMenu->menuitems[i].alphaKey == ch) + { + itemOn = i; + S_StartSound(NULL,sfx_pstop); + return true; + } + for (i = 0;i <= itemOn;i++) + if (currentMenu->menuitems[i].alphaKey == ch) + { + itemOn = i; + S_StartSound(NULL,sfx_pstop); + return true; + } + } + return false; +} + +// +// End of M_Responder +// +///////////////////////////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////////////////////////// +// +// General Routines +// +// This displays the Main menu and gets the menu screens rolling. +// Plus a variety of routines that control the Big Font menu display. +// Plus some initialization for game-dependant situations. + +void M_StartControlPanel (void) +{ + // intro might call this repeatedly + + if (menuactive) + return; + + //jff 3/24/98 make default skill menu choice follow -skill or defaultskill + //from command line or config file + // + // killough 10/98: + // Fix to make "always floating" with menu selections, and to always follow + // defaultskill, instead of -skill. + + NewDef.lastOn = defaultskill - 1; + + default_verify = 0; // killough 10/98 + menuactive = 1; + currentMenu = &MainDef; // JDC + itemOn = currentMenu->lastOn; // JDC + print_warning_about_changes = false; // killough 11/98 +} + +// +// M_Drawer +// Called after the view has been rendered, +// but before it has been blitted. +// +// killough 9/29/98: Significantly reformatted source +// + +void M_Drawer (void) +{ + inhelpscreens = false; + + // Horiz. & Vertically center string and print it. + // killough 9/29/98: simplified code, removed 40-character width limit + if (messageToPrint) + { + /* cph - strdup string to writable memory */ + char *ms = strdup(messageString); + char *p = ms; + + int y = 100 - M_StringHeight(messageString)/2; + while (*p) + { + char *string = p, c; + while ((c = *p) && *p != '\n') + p++; + *p = 0; + M_WriteText(160 - M_StringWidth(string)/2, y, string); + y += hu_font[0].height; + if ((*p = c)) + p++; + } + free(ms); + } + else + if (menuactive) + { + int x,y,max,i; + + if (currentMenu->routine) + currentMenu->routine(); // call Draw routine + + // DRAW MENU + + x = currentMenu->x; + y = currentMenu->y; + max = currentMenu->numitems; + + for (i=0;imenuitems[i].name[0]) + V_DrawNamePatch(x,y,0,currentMenu->menuitems[i].name, + CR_DEFAULT, VPT_STRETCH); + y += LINEHEIGHT; + } + + // DRAW SKULL + + // CPhipps - patch drawing updated + V_DrawNamePatch(x + SKULLXOFF, currentMenu->y - 5 + itemOn*LINEHEIGHT,0, + skullName[whichSkull], CR_DEFAULT, VPT_STRETCH); + } +} + +// +// M_ClearMenus +// +// Called when leaving the menu screens for the real world + +void M_ClearMenus (void) +{ + menuactive = 0; + print_warning_about_changes = 0; // killough 8/15/98 + default_verify = 0; // killough 10/98 + + // if (!netgame && usergame && paused) + // sendpause = true; +} + +// +// M_SetupNextMenu +// +void M_SetupNextMenu(menu_t *menudef) +{ + currentMenu = menudef; + itemOn = currentMenu->lastOn; +} + +///////////////////////////// +// +// M_Ticker +// +void M_Ticker (void) +{ + if (--skullAnimCounter <= 0) + { + whichSkull ^= 1; + skullAnimCounter = 8; + } +} + +///////////////////////////// +// +// Message Routines +// + +void M_StartMessage (const char* string,MessageRoutineFunction routine,boolean input) +{ + messageLastMenuActive = menuactive; + messageToPrint = 1; + messageString = string; + messageRoutine = routine; + messageNeedsInput = input; + menuactive = true; + return; +} + +void M_StopMessage(void) +{ + menuactive = messageLastMenuActive; + messageToPrint = 0; +} + +///////////////////////////// +// +// Thermometer Routines +// + +// +// M_DrawThermo draws the thermometer graphic for Mouse Sensitivity, +// Sound Volume, etc. +// +// proff/nicolas 09/20/98 -- changed for hi-res +// CPhipps - patch drawing updated +// +void M_DrawThermo(int x,int y,int thermWidth,int thermDot ) + { + int xx; + int i; + /* + * Modification By Barry Mead to allow the Thermometer to have vastly + * larger ranges. (the thermWidth parameter can now have a value as + * large as 200. Modified 1-9-2000 Originally I used it to make + * the sensitivity range for the mouse better. It could however also + * be used to improve the dynamic range of music and sound affect + * volume controls for example. + */ + int horizScaler; //Used to allow more thermo range for mouse sensitivity. + thermWidth = (thermWidth > 200) ? 200 : thermWidth; //Clamp to 200 max + horizScaler = (thermWidth > 23) ? (200 / thermWidth) : 8; //Dynamic range + xx = x; + V_DrawNamePatch(xx, y, 0, "M_THERML", CR_DEFAULT, VPT_STRETCH); + xx += 8; + for (i=0;ix - 10, menu->y+item*LINEHEIGHT - 1, 0, + "M_CELL1", CR_DEFAULT, VPT_STRETCH); +} + +// +// Draw a full cell in the thermometer +// + +void M_DrawSelCell (menu_t* menu,int item) +{ + // CPhipps - patch drawing updated + V_DrawNamePatch(menu->x - 10, menu->y+item*LINEHEIGHT - 1, 0, + "M_CELL2", CR_DEFAULT, VPT_STRETCH); +} + +///////////////////////////// +// +// String-drawing Routines +// + +// +// Find string width from hu_font chars +// + +int M_StringWidth(const char* string) +{ + int i, c, w = 0; + for (i = 0;(size_t)i < strlen(string);i++) + w += (c = toupper(string[i]) - HU_FONTSTART) < 0 || c >= HU_FONTSIZE ? + 4 : hu_font[c].width; + return w; +} + +// +// Find string height from hu_font chars +// + +int M_StringHeight(const char* string) +{ + int i, h, height = h = hu_font[0].height; + for (i = 0;string[i];i++) // killough 1/31/98 + if (string[i] == '\n') + h += height; + return h; +} + +// +// Write a string using the hu_font +// +void M_WriteText (int x,int y,const char* string) +{ + int w; + const char* ch; + int c; + int cx; + int cy; + + ch = string; + cx = x; + cy = y; + + while(1) { + c = *ch++; + if (!c) + break; + if (c == '\n') { + cx = x; + cy += 12; + continue; + } + + c = toupper(c) - HU_FONTSTART; + if (c < 0 || c>= HU_FONTSIZE) { + cx += 4; + continue; + } + + w = hu_font[c].width; + if (cx+w > SCREENWIDTH) + break; + // proff/nicolas 09/20/98 -- changed for hi-res + // CPhipps - patch drawing updated + V_DrawNumPatch(cx, cy, 0, hu_font[c].lumpnum, CR_DEFAULT, VPT_STRETCH); + cx+=w; + } +} + +///////////////////////////// +// +// Initialization Routines to take care of one-time setup +// + +// phares 4/08/98: +// M_InitHelpScreen() clears the weapons from the HELP +// screen that don't exist in this version of the game. + +void M_InitHelpScreen(void) +{ + setup_menu_t* src; + + src = helpstrings; + while (!(src->m_flags & S_END)) { + + if ((strncmp(src->m_text,"PLASMA",6) == 0) && (gamemode == shareware)) + src->m_flags = S_SKIP; // Don't show setting or item + if ((strncmp(src->m_text,"BFG",3) == 0) && (gamemode == shareware)) + src->m_flags = S_SKIP; // Don't show setting or item + if ((strncmp(src->m_text,"SSG",3) == 0) && (gamemode != commercial)) + src->m_flags = S_SKIP; // Don't show setting or item + src++; + } +} + +// +// M_Init +// +void M_Init(void) +{ + M_InitDefaults(); // killough 11/98 + currentMenu = &MainDef; + menuactive = 0; + itemOn = currentMenu->lastOn; + whichSkull = 0; + skullAnimCounter = 10; + screenSize = screenblocks - 3; + messageToPrint = 0; + messageString = NULL; + messageLastMenuActive = menuactive; + quickSaveSlot = -1; + + // Here we could catch other version dependencies, + // like HELP1/2, and four episodes. + + switch(gamemode) + { + case commercial: + // This is used because DOOM 2 had only one HELP + // page. I use CREDIT as second page now, but + // kept this hack for educational purposes. + MainMenu[readthis] = MainMenu[quitdoom]; + MainDef.numitems--; + MainDef.y += 8; + NewDef.prevMenu = &MainDef; + ReadDef1.routine = M_DrawReadThis1; + ReadDef1.x = 330; + ReadDef1.y = 165; + ReadMenu1[0].routine = M_FinishReadThis; + break; + case registered: + // Episode 2 and 3 are handled, + // branching to an ad screen. + + // killough 2/21/98: Fix registered Doom help screen + // killough 10/98: moved to second screen, moved up to the top + ReadDef2.y = 15; + + case shareware: + // We need to remove the fourth episode. + EpiDef.numitems--; + break; + case retail: + // We are fine. + default: + break; + } + + M_InitHelpScreen(); // init the help screen // phares 4/08/98 + M_InitExtendedHelp(); // init extended help screens // phares 3/30/98 + + M_ChangeDemoSmoothTurns(); +} + +// +// End of General Routines +// +///////////////////////////////////////////////////////////////////////////// diff --git a/common/prboom/m_menu.h b/common/prboom/m_menu.h new file mode 100755 index 0000000..7a391fd --- /dev/null +++ b/common/prboom/m_menu.h @@ -0,0 +1,182 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Menu widget stuff, episode selection and such. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __M_MENU__ +#define __M_MENU__ + +#include "d_event.h" + +// +// MENUS +// +// Called by main loop, +// saves config file and calls I_Quit when user exits. +// Even when the menu is not displayed, +// this can resize the view and change game parameters. +// Does all the real work of the menu interaction. + +boolean M_Responder (event_t *ev); + +// Called by main loop, +// only used for menu (skull cursor) animation. + +void M_Ticker (void); + +// Called by main loop, +// draws the menus directly into the screen buffer. + +void M_Drawer (void); + +// Called by D_DoomMain, +// loads the config file. + +void M_Init (void); + +// Called by intro code to force menu up upon a keypress, +// does nothing if menu is already up. + +void M_StartControlPanel (void); + +void M_ForcedLoadGame(const char *msg); // killough 5/15/98: forced loadgames + +void M_Trans(void); // killough 11/98: reset translucency + +void M_ResetMenu(void); // killough 11/98: reset main menu ordering + +void M_DrawCredits(void); // killough 11/98 + +/* killough 8/15/98: warn about changes not being committed until next game */ +#define warn_about_changes(x) (warning_about_changes=(x), \ + print_warning_about_changes = 2) + +extern int warning_about_changes, print_warning_about_changes; + +/**************************** + * + * The following #defines are for the m_flags field of each item on every + * Setup Screen. They can be OR'ed together where appropriate + */ + +#define S_HILITE 0x1 // Cursor is sitting on this item +#define S_SELECT 0x2 // We're changing this item +#define S_TITLE 0x4 // Title item +#define S_YESNO 0x8 // Yes or No item +#define S_CRITEM 0x10 // Message color +#define S_COLOR 0x20 // Automap color +#define S_CHAT 0x40 // Chat String +#define S_RESET 0x80 // Reset to Defaults Button +#define S_PREV 0x100 // Previous menu exists +#define S_NEXT 0x200 // Next menu exists +#define S_KEY 0x400 // Key Binding +#define S_WEAP 0x800 // Weapon # +#define S_NUM 0x1000 // Numerical item +#define S_SKIP 0x2000 // Cursor can't land here +#define S_KEEP 0x4000 // Don't swap key out +#define S_END 0x8000 // Last item in list (dummy) +#define S_LEVWARN 0x10000// killough 8/30/98: Always warn about pending change +#define S_PRGWARN 0x20000// killough 10/98: Warn about change until next run +#define S_BADVAL 0x40000// killough 10/98: Warn about bad value +#define S_FILE 0x80000// killough 10/98: Filenames +#define S_LEFTJUST 0x100000 // killough 10/98: items which are left-justified +#define S_CREDIT 0x200000 // killough 10/98: credit +#define S_BADVID 0x400000 // killough 12/98: video mode change error +#define S_CHOICE 0x800000 // this item has several values + +/* S_SHOWDESC = the set of items whose description should be displayed + * S_SHOWSET = the set of items whose setting should be displayed + * S_STRING = the set of items whose settings are strings -- killough 10/98: + * S_HASDEFPTR = the set of items whose var field points to default array + */ + +#define S_SHOWDESC (S_TITLE|S_YESNO|S_CRITEM|S_COLOR|S_CHAT|S_RESET|S_PREV|S_NEXT|S_KEY|S_WEAP|S_NUM|S_FILE|S_CREDIT|S_CHOICE) + +#define S_SHOWSET (S_YESNO|S_CRITEM|S_COLOR|S_CHAT|S_KEY|S_WEAP|S_NUM|S_FILE|S_CHOICE) + +#define S_STRING (S_CHAT|S_FILE) + +#define S_HASDEFPTR (S_STRING|S_YESNO|S_NUM|S_WEAP|S_COLOR|S_CRITEM|S_CHOICE) + +/**************************** + * + * The setup_group enum is used to show which 'groups' keys fall into so + * that you can bind a key differently in each 'group'. + */ + +typedef enum { + m_null, // Has no meaning; not applicable + m_scrn, // A key can not be assigned to more than one action + m_map, // in the same group. A key can be assigned to one + m_menu, // action in one group, and another action in another. +} setup_group; + +/**************************** + * + * phares 4/17/98: + * State definition for each item. + * This is the definition of the structure for each setup item. Not all + * fields are used by all items. + * + * A setup screen is defined by an array of these items specific to + * that screen. + * + * killough 11/98: + * + * Restructured to allow simpler table entries, + * and to Xref with defaults[] array in m_misc.c. + * Moved from m_menu.c to m_menu.h so that m_misc.c can use it. + */ + +typedef struct setup_menu_s +{ + const char *m_text; /* text to display */ + int m_flags; /* phares 4/17/98: flag bits S_* (defined above) */ + setup_group m_group; /* Group */ + short m_x; /* screen x position (left is 0) */ + short m_y; /* screen y position (top is 0) */ + + union /* killough 11/98: The first field is a union of several types */ + { + const void *var; /* generic variable */ + int *m_key; /* key value, or 0 if not shown */ + const char *name; /* name */ + struct default_s *def; /* default[] table entry */ + struct setup_menu_s *menu; /* next or prev menu */ + } var; + + int *m_mouse; /* mouse button value, or 0 if not shown */ + int *m_joy; /* joystick button value, or 0 if not shown */ + void (*action)(void); /* killough 10/98: function to call after changing */ + const char **selectstrings; /* list of strings for choice value */ +} setup_menu_t; + +#endif diff --git a/common/prboom/m_misc.c b/common/prboom/m_misc.c new file mode 100755 index 0000000..b36272e --- /dev/null +++ b/common/prboom/m_misc.c @@ -0,0 +1,1088 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Main loop menu stuff. + * Default Config File. + * PCX Screenshots. + * + *-----------------------------------------------------------------------------*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef _MSC_VER +#include +#endif +#include +#include + +#include "doomstat.h" +#include "m_argv.h" +#include "g_game.h" +#include "m_menu.h" +#include "am_map.h" +#include "w_wad.h" +#include "i_system.h" +#include "i_sound.h" +#include "i_video.h" +#include "v_video.h" +#include "hu_stuff.h" +#include "st_stuff.h" +#include "dstrings.h" +#include "m_misc.h" +#include "s_sound.h" +#include "sounds.h" +#include "i_joy.h" +#include "lprintf.h" +#include "d_main.h" +#include "r_draw.h" +#include "r_demo.h" +#include "r_fps.h" + +/* cph - disk icon not implemented */ +static inline void I_BeginRead(void) {} +static inline void I_EndRead(void) {} + +/* + * M_WriteFile + * + * killough 9/98: rewritten to use stdio and to flash disk icon + */ + +boolean M_WriteFile(char const *name, void *source, int length) +{ + FILE *fp; + + errno = 0; + + if (!(fp = fopen(name, "wb"))) // Try opening file + return 0; // Could not open file for writing + + I_BeginRead(); // Disk icon on + length = fwrite(source, 1, length, fp) == (size_t)length; // Write data + fclose(fp); + I_EndRead(); // Disk icon off + + if (!length) // Remove partially written file + remove(name); + + return length; +} + +/* + * M_ReadFile + * + * killough 9/98: rewritten to use stdio and to flash disk icon + */ + +int M_ReadFile(char const *name, byte **buffer) +{ + FILE *fp; + + if ((fp = fopen(name, "rb"))) + { + size_t length; + + I_BeginRead(); + fseek(fp, 0, SEEK_END); + length = ftell(fp); + fseek(fp, 0, SEEK_SET); + *buffer = Z_Malloc(length, PU_STATIC, 0); + if (fread(*buffer, 1, length, fp) == length) + { + fclose(fp); + I_EndRead(); + return length; + } + fclose(fp); + } + + /* cph 2002/08/10 - this used to return 0 on error, but that's ambiguous, + * because we could have a legit 0-length file. So make it -1. */ + return -1; +} + +// +// DEFAULTS +// + +int usemouse; +boolean precache = true; /* if true, load all graphics at start */ + +extern int mousebfire; +extern int mousebstrafe; +extern int mousebforward; + +extern int displaywidth; +extern int displayheight; +extern int viewwidth; +extern int viewheight; +#ifdef GL_DOOM +extern int gl_nearclip; +extern int gl_colorbuffer_bits; +extern int gl_depthbuffer_bits; +extern const char *gl_tex_filter_string; +extern const char *gl_tex_format_string; +extern int gl_drawskys; +extern int gl_sortsprites; +extern int gl_use_paletted_texture; +extern int gl_use_shared_texture_palette; +extern int gl_sprite_offset; +#endif + +extern int realtic_clock_rate; // killough 4/13/98: adjustable timer +extern int tran_filter_pct; // killough 2/21/98 + +extern int screenblocks; +extern int showMessages; + +#ifndef DJGPP +int mus_pause_opt; // 0 = kill music, 1 = pause, 2 = continue +bool mus_on = true; +#endif + +extern const char* chat_macros[]; + +extern int endoom_mode; + +extern const char* S_music_files[]; // cournia + +/* cph - Some MBF stuff parked here for now + * killough 10/98 + */ +int map_point_coordinates; + +default_t defaults[] = +{ + {"Misc settings",{NULL,NULL},{0,NULL},UL,UL,def_none,ss_none,NULL,NULL}, + {"default_compatibility_level",{(int*)&default_compatibility_level,NULL}, + {-1,NULL},-1,MAX_COMPATIBILITY_LEVEL-1, + def_int,ss_none,NULL,NULL}, // compatibility level" - CPhipps + {"realtic_clock_rate",{&realtic_clock_rate,NULL},{100,NULL},0,UL, + def_int,ss_none,NULL,NULL}, // percentage of normal speed (35 fps) realtic clock runs at + {"max_player_corpse", {&bodyquesize,NULL}, {32,NULL},-1,UL, // killough 2/8/98 + def_int,ss_none,NULL,NULL}, // number of dead bodies in view supported (-1 = no limit) + {"flashing_hom",{&flashing_hom,NULL},{0,NULL},0,1, + def_bool,ss_none,NULL,NULL}, // killough 10/98 - enable flashing HOM indicator + {"demo_insurance",{&default_demo_insurance,NULL},{2,NULL},0,2, // killough 3/31/98 + def_int,ss_none,NULL,NULL}, // 1=take special steps ensuring demo sync, 2=only during recordings + {"endoom_mode", {&endoom_mode,NULL},{5,NULL},0,7, // CPhipps - endoom flags + def_hex, ss_none,NULL,NULL}, // 0, +1 for colours, +2 for non-ascii chars, +4 for skip-last-line + {"level_precache",{(int*)&precache,NULL},{0,NULL},0,1, + def_bool,ss_none,NULL,NULL}, // precache level data? + {"demo_smoothturns", {&demo_smoothturns,NULL}, {0,NULL},0,1, + def_bool,ss_stat,NULL,NULL}, + {"demo_smoothturnsfactor", {&demo_smoothturnsfactor,NULL}, {6,NULL},1,SMOOTH_PLAYING_MAXFACTOR, + def_int,ss_stat,NULL,NULL}, + + {"Files",{NULL,NULL},{0,NULL},UL,UL,def_none,ss_none,NULL,NULL}, + /* cph - MBF-like wad/deh/bex autoload code */ + {"wadfile_1",{NULL,&wad_files[0]},{0,""},UL,UL,def_str,ss_none,NULL,NULL}, + {"wadfile_2",{NULL,&wad_files[1]},{0,""},UL,UL,def_str,ss_none,NULL,NULL}, + {"dehfile_1",{NULL,&deh_files[0]},{0,""},UL,UL,def_str,ss_none,NULL,NULL}, + {"dehfile_2",{NULL,&deh_files[1]},{0,""},UL,UL,def_str,ss_none,NULL,NULL}, + + {"Game settings",{NULL,NULL},{0,NULL},UL,UL,def_none,ss_none,NULL,NULL}, + {"default_skill",{&defaultskill,NULL},{3,NULL},1,5, // jff 3/24/98 allow default skill setting + def_int,ss_none,NULL,NULL}, // selects default skill 1=TYTD 2=NTR 3=HMP 4=UV 5=NM + {"weapon_recoil",{&default_weapon_recoil,NULL},{0,NULL},0,1, + def_bool,ss_weap, &weapon_recoil,NULL}, + /* killough 10/98 - toggle between SG/SSG and Fist/Chainsaw */ + {"doom_weapon_toggles",{&doom_weapon_toggles,NULL}, {1,NULL}, 0, 1, + def_bool, ss_weap,NULL,NULL}, + {"player_bobbing",{&default_player_bobbing,NULL},{1,NULL},0,1, // phares 2/25/98 + def_bool,ss_weap, &player_bobbing,NULL}, + {"monsters_remember",{&default_monsters_remember,NULL},{1,NULL},0,1, // killough 3/1/98 + def_bool,ss_enem, &monsters_remember,NULL}, + /* MBF AI enhancement options */ + {"monster_infighting",{&default_monster_infighting,NULL}, {1,NULL}, 0, 1, + def_bool, ss_enem, &monster_infighting,NULL}, + {"monster_backing",{&default_monster_backing,NULL}, {0,NULL}, 0, 1, + def_bool, ss_enem, &monster_backing,NULL}, + {"monster_avoid_hazards",{&default_monster_avoid_hazards,NULL}, {1,NULL}, 0, 1, + def_bool, ss_enem, &monster_avoid_hazards,NULL}, + {"monkeys",{&default_monkeys,NULL}, {0,NULL}, 0, 1, + def_bool, ss_enem, &monkeys,NULL}, + {"monster_friction",{&default_monster_friction,NULL}, {1,NULL}, 0, 1, + def_bool, ss_enem, &monster_friction,NULL}, + {"help_friends",{&default_help_friends,NULL}, {1,NULL}, 0, 1, + def_bool, ss_enem, &help_friends,NULL}, + {"allow_pushers",{&default_allow_pushers,NULL},{1,NULL},0,1, + def_bool,ss_weap, &allow_pushers,NULL}, + {"variable_friction",{&default_variable_friction,NULL},{1,NULL},0,1, + def_bool,ss_weap, &variable_friction,NULL}, +#ifdef DOGS + {"player_helpers",{&default_dogs}, {0}, 0, 3, + def_bool, ss_enem }, + {"friend_distance",{&default_distfriend}, {128}, 0, 999, + def_int, ss_enem, &distfriend}, + {"dog_jumping",{&default_dog_jumping}, {1}, 0, 1, + def_bool, ss_enem, &dog_jumping}, +#endif + /* End of MBF AI extras */ + + {"sts_always_red",{&sts_always_red,NULL},{1,NULL},0,1, // no color changes on status bar + def_bool,ss_stat,NULL,NULL}, + {"sts_pct_always_gray",{&sts_pct_always_gray,NULL},{0,NULL},0,1, // 2/23/98 chg default + def_bool,ss_stat,NULL,NULL}, // makes percent signs on status bar always gray + {"sts_traditional_keys",{&sts_traditional_keys,NULL},{0,NULL},0,1, // killough 2/28/98 + def_bool,ss_stat,NULL,NULL}, // disables doubled card and skull key display on status bar + {"show_messages",{&showMessages,NULL},{1,NULL},0,1, + def_bool,ss_none,NULL,NULL}, // enables message display + {"autorun",{&autorun,NULL},{0,NULL},0,1, // killough 3/6/98: preserve autorun across games + def_bool,ss_none,NULL,NULL}, + + {"Compatibility settings",{NULL,NULL},{0,NULL},UL,UL,def_none,ss_none,NULL,NULL}, + {"comp_zombie",{&default_comp[comp_zombie],NULL},{0,NULL},0,1,def_bool,ss_comp,&comp[comp_zombie],NULL}, + {"comp_infcheat",{&default_comp[comp_infcheat],NULL},{0,NULL},0,1,def_bool,ss_comp,&comp[comp_infcheat],NULL}, + {"comp_stairs",{&default_comp[comp_stairs],NULL},{0,NULL},0,1,def_bool,ss_comp,&comp[comp_stairs],NULL}, + {"comp_telefrag",{&default_comp[comp_telefrag],NULL},{0,NULL},0,1,def_bool,ss_comp,&comp[comp_telefrag],NULL}, + {"comp_dropoff",{&default_comp[comp_dropoff],NULL},{0,NULL},0,1,def_bool,ss_comp,&comp[comp_dropoff],NULL}, + {"comp_falloff",{&default_comp[comp_falloff],NULL},{0,NULL},0,1,def_bool,ss_comp,&comp[comp_falloff],NULL}, + {"comp_staylift",{&default_comp[comp_staylift],NULL},{0,NULL},0,1,def_bool,ss_comp,&comp[comp_staylift],NULL}, + {"comp_doorstuck",{&default_comp[comp_doorstuck],NULL},{0,NULL},0,1,def_bool,ss_comp,&comp[comp_doorstuck],NULL}, + {"comp_pursuit",{&default_comp[comp_pursuit],NULL},{0,NULL},0,1,def_bool,ss_comp,&comp[comp_pursuit],NULL}, + {"comp_vile",{&default_comp[comp_vile],NULL},{0,NULL},0,1,def_bool,ss_comp,&comp[comp_vile],NULL}, + {"comp_pain",{&default_comp[comp_pain],NULL},{0,NULL},0,1,def_bool,ss_comp,&comp[comp_pain],NULL}, + {"comp_skull",{&default_comp[comp_skull],NULL},{0,NULL},0,1,def_bool,ss_comp,&comp[comp_skull],NULL}, + {"comp_blazing",{&default_comp[comp_blazing],NULL},{0,NULL},0,1,def_bool,ss_comp,&comp[comp_blazing],NULL}, + {"comp_doorlight",{&default_comp[comp_doorlight],NULL},{0,NULL},0,1,def_bool,ss_comp,&comp[comp_doorlight],NULL}, + {"comp_god",{&default_comp[comp_god],NULL},{0,NULL},0,1,def_bool,ss_comp,&comp[comp_god],NULL}, + {"comp_skymap",{&default_comp[comp_skymap],NULL},{0,NULL},0,1,def_bool,ss_comp,&comp[comp_skymap],NULL}, + {"comp_floors",{&default_comp[comp_floors],NULL},{0,NULL},0,1,def_bool,ss_comp,&comp[comp_floors],NULL}, + {"comp_model",{&default_comp[comp_model],NULL},{0,NULL},0,1,def_bool,ss_comp,&comp[comp_model],NULL}, + {"comp_zerotags",{&default_comp[comp_zerotags],NULL},{0,NULL},0,1,def_bool,ss_comp,&comp[comp_zerotags],NULL}, + {"comp_moveblock",{&default_comp[comp_moveblock],NULL},{0,NULL},0,1,def_bool,ss_comp,&comp[comp_moveblock],NULL}, + {"comp_sound",{&default_comp[comp_sound],NULL},{0,NULL},0,1,def_bool,ss_comp,&comp[comp_sound],NULL}, + {"comp_666",{&default_comp[comp_666],NULL},{0,NULL},0,1,def_bool,ss_comp,&comp[comp_666],NULL}, + {"comp_soul",{&default_comp[comp_soul],NULL},{0,NULL},0,1,def_bool,ss_comp,&comp[comp_soul],NULL}, + {"comp_maskedanim",{&default_comp[comp_maskedanim],NULL},{0,NULL},0,1,def_bool,ss_comp,&comp[comp_maskedanim],NULL}, + + {"Sound settings",{NULL,NULL},{0,NULL},UL,UL,def_none,ss_none,NULL,NULL}, + {"sound_card",{&snd_card,NULL},{-1,NULL},-1,7, // jff 1/18/98 allow Allegro drivers + def_int,ss_none,NULL,NULL}, // select sounds driver (DOS), -1 is autodetect, 0 is none; in Linux, non-zero enables sound + {"music_card",{&mus_card,NULL},{-1,NULL},-1,9, // to be set, -1 = autodetect + def_int,ss_none,NULL,NULL}, // select music driver (DOS), -1 is autodetect, 0 is none"; in Linux, non-zero enables music + {"pitched_sounds",{&pitched_sounds,NULL},{0,NULL},0,1, // killough 2/21/98 + def_bool,ss_none,NULL,NULL}, // enables variable pitch in sound effects (from id's original code) + {"samplerate",{&snd_samplerate,NULL},{22050,NULL},11025,48000, def_int,ss_none,NULL,NULL}, + {"sfx_volume",{&snd_SfxVolume,NULL},{8,NULL},0,15, def_int,ss_none,NULL,NULL}, + {"music_volume",{&snd_MusicVolume,NULL},{8,NULL},0,15, def_int,ss_none,NULL,NULL}, + {"mus_pause_opt",{&mus_pause_opt,NULL},{2,NULL},0,2, // CPhipps - music pausing + def_int, ss_none,NULL,NULL}, // 0 = kill music when paused, 1 = pause music, 2 = let music continue + {"snd_channels",{&default_numChannels,NULL},{8,NULL},1,32, + def_int,ss_none,NULL,NULL}, // number of audio events simultaneously // killough + + {"Video settings",{NULL,NULL},{0,NULL},UL,UL,def_none,ss_none,NULL,NULL}, +#ifdef GL_DOOM + #ifdef _MSC_VER + {"videomode",{NULL, &default_videomode},{0,"gl"},UL,UL,def_str,ss_none}, + #else + {"videomode",{NULL, &default_videomode},{0,"8"},UL,UL,def_str,ss_none,NULL,NULL}, + #endif +#else + {"videomode",{NULL, &default_videomode},{0,"8"},UL,UL,def_str,ss_none}, +#endif + /* 640x480 default resolution */ + {"screen_width",{&desired_screenwidth,NULL},{640,NULL}, 320, MAX_SCREENWIDTH, + def_int,ss_none,NULL,NULL}, + {"screen_height",{&desired_screenheight,NULL},{480,NULL},200,MAX_SCREENHEIGHT, + def_int,ss_none,NULL,NULL}, + {"use_fullscreen",{&use_fullscreen,NULL},{1,NULL},0,1, /* proff 21/05/2000 */ + def_bool,ss_none,NULL,NULL}, +#ifndef DISABLE_DOUBLEBUFFER + {"use_doublebuffer",{&use_doublebuffer},{1},0,1, // proff 2001-7-4 + def_bool,ss_none}, // enable doublebuffer to avoid display tearing (fullscreen) +#endif +#ifdef IPHONE // JDC, don't waste time builing the tables at startup +{"translucency",{&default_translucency,NULL},{0,NULL},0,1, // phares +def_bool,ss_none,NULL,NULL}, // enables translucency +#else +{"translucency",{&default_translucency},{1},0,1, // phares +def_bool,ss_none}, // enables translucency +#endif + {"tran_filter_pct",{&tran_filter_pct,NULL},{66,NULL},0,100, // killough 2/21/98 + def_int,ss_none,NULL,NULL}, // set percentage of foreground/background translucency mix + {"screenblocks",{&screenblocks,NULL},{10,NULL},3,11, // killough 2/21/98: default to 10 + def_int,ss_none,NULL,NULL}, + {"usegamma",{&usegamma,NULL},{3,NULL},0,4, //jff 3/6/98 fix erroneous upper limit in range + def_int,ss_none,NULL,NULL}, // gamma correction level // killough 1/18/98 + {"uncapped_framerate", {&movement_smooth,NULL}, {0,NULL},0,1, + def_bool,ss_stat,NULL,NULL}, + {"filter_wall",{(int*)&drawvars.filterwall,NULL},{RDRAW_FILTER_POINT,NULL}, + RDRAW_FILTER_POINT, RDRAW_FILTER_ROUNDED, def_int,ss_none,NULL,NULL}, + {"filter_floor",{(int*)&drawvars.filterfloor,NULL},{RDRAW_FILTER_POINT,NULL}, + RDRAW_FILTER_POINT, RDRAW_FILTER_ROUNDED, def_int,ss_none,NULL,NULL}, + {"filter_sprite",{(int*)&drawvars.filtersprite,NULL},{RDRAW_FILTER_POINT,NULL}, + RDRAW_FILTER_POINT, RDRAW_FILTER_ROUNDED, def_int,ss_none,NULL,NULL}, + {"filter_z",{(int*)&drawvars.filterz,NULL},{RDRAW_FILTER_POINT,NULL}, + RDRAW_FILTER_POINT, RDRAW_FILTER_LINEAR, def_int,ss_none,NULL,NULL}, + {"filter_patch",{(int*)&drawvars.filterpatch,NULL},{RDRAW_FILTER_POINT,NULL}, + RDRAW_FILTER_POINT, RDRAW_FILTER_ROUNDED, def_int,ss_none,NULL,NULL}, + {"filter_threshold",{(int*)&drawvars.mag_threshold,NULL},{49152,NULL}, + 0, UL, def_int,ss_none,NULL,NULL}, + {"sprite_edges",{(int*)&drawvars.sprite_edges,NULL},{RDRAW_MASKEDCOLUMNEDGE_SQUARE,NULL}, + RDRAW_MASKEDCOLUMNEDGE_SQUARE, RDRAW_MASKEDCOLUMNEDGE_SLOPED, def_int,ss_none,NULL,NULL}, + {"patch_edges",{(int*)&drawvars.patch_edges,NULL},{RDRAW_MASKEDCOLUMNEDGE_SQUARE,NULL}, + RDRAW_MASKEDCOLUMNEDGE_SQUARE, RDRAW_MASKEDCOLUMNEDGE_SLOPED, def_int,ss_none,NULL,NULL}, + +#ifdef GL_DOOM + {"OpenGL settings",{NULL,NULL},{0,NULL},UL,UL,def_none,ss_none,NULL,NULL}, + {"gl_nearclip",{&gl_nearclip,NULL},{5,NULL},0,UL, + def_int,ss_none,NULL,NULL}, /* near clipping plane pos */ + {"gl_colorbuffer_bits",{&gl_colorbuffer_bits,NULL},{16,NULL},16,32, + def_int,ss_none,NULL,NULL}, + {"gl_depthbuffer_bits",{&gl_depthbuffer_bits,NULL},{16,NULL},16,32, + def_int,ss_none,NULL,NULL}, + {"gl_tex_filter_string", {NULL,&gl_tex_filter_string}, {0,"GL_LINEAR"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"gl_tex_format_string", {NULL,&gl_tex_format_string}, {0,"GL_RGB5_A1"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"gl_drawskys",{&gl_drawskys,NULL},{1,NULL},0,1, + def_bool,ss_none,NULL,NULL}, + {"gl_sortsprites",{&gl_sortsprites,NULL},{1,NULL},0,1, + def_bool,ss_none,NULL,NULL}, + {"gl_use_paletted_texture",{&gl_use_paletted_texture,NULL},{0,NULL},0,1, + def_bool,ss_none,NULL,NULL}, + {"gl_use_shared_texture_palette",{&gl_use_shared_texture_palette,NULL},{0,NULL},0,1, + def_bool,ss_none,NULL,NULL}, +#ifdef GL_DOOM + {"gl_sprite_offset",{&gl_sprite_offset,NULL},{0,NULL}, 0, 5, + def_int,ss_none,NULL,NULL}, // amount to bring items out of floor (GL) Mead 8/13/03 +#endif +#endif + + {"Mouse settings",{NULL,NULL},{0,NULL},UL,UL,def_none,ss_none,NULL,NULL}, + {"use_mouse",{&usemouse,NULL},{1,NULL},0,1, + def_bool,ss_none,NULL,NULL}, // enables use of mouse with DOOM + //jff 4/3/98 allow unlimited sensitivity + {"mouse_sensitivity_horiz",{&mouseSensitivity_horiz,NULL},{10,NULL},0,UL, + def_int,ss_none,NULL,NULL}, /* adjust horizontal (x) mouse sensitivity killough/mead */ + //jff 4/3/98 allow unlimited sensitivity + {"mouse_sensitivity_vert",{&mouseSensitivity_vert,NULL},{10,NULL},0,UL, + def_int,ss_none,NULL,NULL}, /* adjust vertical (y) mouse sensitivity killough/mead */ + //jff 3/8/98 allow -1 in mouse bindings to disable mouse function + {"mouseb_fire",{&mousebfire,NULL},{0,NULL},-1,MAX_MOUSEB, + def_int,ss_keys,NULL,NULL}, // mouse button number to use for fire + {"mouseb_strafe",{&mousebstrafe,NULL},{1,NULL},-1,MAX_MOUSEB, + def_int,ss_keys,NULL,NULL}, // mouse button number to use for strafing + {"mouseb_forward",{&mousebforward,NULL},{2,NULL},-1,MAX_MOUSEB, + def_int,ss_keys,NULL,NULL}, // mouse button number to use for forward motion + //jff 3/8/98 end of lower range change for -1 allowed in mouse binding + +// For key bindings, the values stored in the key_* variables // phares +// are the internal Doom Codes. The values stored in the default.cfg +// file are the keyboard codes. +// CPhipps - now they're the doom codes, so default.cfg can be portable + + {"Key bindings",{NULL,NULL},{0,NULL},UL,UL,def_none,ss_none,NULL,NULL}, + {"key_right", {&key_right,NULL}, {KEYD_RIGHTARROW,NULL}, + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to turn right + {"key_left", {&key_left,NULL}, {KEYD_LEFTARROW,NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to turn left + {"key_up", {&key_up,NULL}, {KEYD_UPARROW,NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to move forward + {"key_down", {&key_down,NULL}, {KEYD_DOWNARROW,NULL}, + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to move backward + {"key_menu_right", {&key_menu_right,NULL}, {KEYD_RIGHTARROW,NULL},// phares 3/7/98 + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to move right in a menu // | + {"key_menu_left", {&key_menu_left,NULL}, {KEYD_LEFTARROW,NULL} ,// V + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to move left in a menu + {"key_menu_up", {&key_menu_up,NULL}, {KEYD_UPARROW,NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to move up in a menu + {"key_menu_down", {&key_menu_down,NULL}, {KEYD_DOWNARROW,NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to move down in a menu + {"key_menu_backspace",{&key_menu_backspace,NULL}, {KEYD_BACKSPACE,NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // delete key in a menu + {"key_menu_escape", {&key_menu_escape,NULL}, {KEYD_ESCAPE,NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to leave a menu , // phares 3/7/98 + {"key_menu_enter", {&key_menu_enter,NULL}, {KEYD_ENTER,NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to select from menu + {"key_strafeleft", {&key_strafeleft,NULL}, {',',NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to strafe left + {"key_straferight", {&key_straferight,NULL}, {'.',NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to strafe right + + {"key_fire", {&key_fire,NULL}, {KEYD_RCTRL,NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // duh + {"key_use", {&key_use,NULL}, {' ',NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to open a door, use a switch + {"key_strafe", {&key_strafe,NULL}, {KEYD_RALT,NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to use with arrows to strafe + {"key_speed", {&key_speed,NULL}, {KEYD_RSHIFT,NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to run + + {"key_savegame", {&key_savegame,NULL}, {KEYD_F2,NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to save current game + {"key_loadgame", {&key_loadgame,NULL}, {KEYD_F3,NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to restore from saved games + {"key_soundvolume", {&key_soundvolume,NULL}, {KEYD_F4,NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to bring up sound controls + {"key_hud", {&key_hud,NULL}, {KEYD_F5,NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to adjust HUD + {"key_quicksave", {&key_quicksave,NULL}, {KEYD_F6,NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to to quicksave + {"key_endgame", {&key_endgame,NULL}, {KEYD_F7,NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to end the game + {"key_messages", {&key_messages,NULL}, {KEYD_F8,NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to toggle message enable + {"key_quickload", {&key_quickload,NULL}, {KEYD_F9,NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to load from quicksave + {"key_quit", {&key_quit,NULL}, {KEYD_F10,NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to quit game + {"key_gamma", {&key_gamma,NULL}, {KEYD_F11,NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to adjust gamma correction + {"key_spy", {&key_spy,NULL}, {KEYD_F12,NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to view from another coop player's view + {"key_pause", {&key_pause,NULL}, {KEYD_PAUSE,NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to pause the game + {"key_autorun", {&key_autorun,NULL}, {KEYD_CAPSLOCK,NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to toggle always run mode + {"key_chat", {&key_chat,NULL}, {'t',NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to enter a chat message + {"key_backspace", {&key_backspace,NULL}, {KEYD_BACKSPACE,NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // backspace key + {"key_enter", {&key_enter,NULL}, {KEYD_ENTER,NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to select from menu or see last message + {"key_map", {&key_map,NULL}, {KEYD_TAB,NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to toggle automap display + {"key_map_right", {&key_map_right,NULL}, {KEYD_RIGHTARROW,NULL},// phares 3/7/98 + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to shift automap right // | + {"key_map_left", {&key_map_left,NULL}, {KEYD_LEFTARROW,NULL} ,// V + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to shift automap left + {"key_map_up", {&key_map_up,NULL}, {KEYD_UPARROW,NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to shift automap up + {"key_map_down", {&key_map_down,NULL}, {KEYD_DOWNARROW,NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to shift automap down + {"key_map_zoomin", {&key_map_zoomin,NULL}, {'=',NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to enlarge automap + {"key_map_zoomout", {&key_map_zoomout,NULL}, {'-',NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to reduce automap + {"key_map_gobig", {&key_map_gobig,NULL}, {'0',NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to get max zoom for automap + {"key_map_follow", {&key_map_follow,NULL}, {'f',NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to toggle follow mode + {"key_map_mark", {&key_map_mark,NULL}, {'m',NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to drop a marker on automap + {"key_map_clear", {&key_map_clear,NULL}, {'c',NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to clear all markers on automap + {"key_map_grid", {&key_map_grid,NULL}, {'g',NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to toggle grid display over automap + {"key_map_rotate", {&key_map_rotate,NULL}, {'r',NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to toggle rotating the automap to match the player's orientation + {"key_map_overlay", {&key_map_overlay,NULL}, {'o',NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to toggle overlaying the automap on the rendered display + {"key_reverse", {&key_reverse,NULL}, {'/',NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to spin 180 instantly + {"key_zoomin", {&key_zoomin,NULL}, {'=',NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to enlarge display + {"key_zoomout", {&key_zoomout,NULL}, {'-',NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to reduce display + {"key_chatplayer1", {&destination_keys[0],NULL}, {'g',NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to chat with player 1 + // killough 11/98: fix 'i'/'b' reversal + {"key_chatplayer2", {&destination_keys[1],NULL}, {'i',NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to chat with player 2 + {"key_chatplayer3", {&destination_keys[2],NULL}, {'b',NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to chat with player 3 + {"key_chatplayer4", {&destination_keys[3],NULL}, {'r',NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to chat with player 4 + {"key_weapontoggle",{&key_weapontoggle,NULL}, {'0',NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to toggle between two most preferred weapons with ammo + {"key_weapon1", {&key_weapon1,NULL}, {'1',NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to switch to weapon 1 (fist/chainsaw) + {"key_weapon2", {&key_weapon2,NULL}, {'2',NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to switch to weapon 2 (pistol) + {"key_weapon3", {&key_weapon3,NULL}, {'3',NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to switch to weapon 3 (supershotgun/shotgun) + {"key_weapon4", {&key_weapon4,NULL}, {'4',NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to switch to weapon 4 (chaingun) + {"key_weapon5", {&key_weapon5,NULL}, {'5',NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to switch to weapon 5 (rocket launcher) + {"key_weapon6", {&key_weapon6,NULL}, {'6',NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to switch to weapon 6 (plasma rifle) + {"key_weapon7", {&key_weapon7,NULL}, {'7',NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to switch to weapon 7 (bfg9000) // ^ + {"key_weapon8", {&key_weapon8,NULL}, {'8',NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to switch to weapon 8 (chainsaw) // | + {"key_weapon9", {&key_weapon9,NULL}, {'9',NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to switch to weapon 9 (supershotgun) // phares + + // killough 2/22/98: screenshot key + {"key_screenshot", {&key_screenshot,NULL}, {'*',NULL} , + 0,MAX_KEY,def_key,ss_keys,NULL,NULL}, // key to take a screenshot + + {"Joystick settings",{NULL,NULL},{0,NULL},UL,UL,def_none,ss_none,NULL,NULL}, + {"use_joystick",{&usejoystick,NULL},{0,NULL},0,2, + def_int,ss_none,NULL,NULL}, // number of joystick to use (0 for none) + {"joy_left",{&joyleft,NULL},{0,NULL}, UL,UL,def_int,ss_none,NULL,NULL}, + {"joy_right",{&joyright,NULL},{0,NULL},UL,UL,def_int,ss_none,NULL,NULL}, + {"joy_up", {&joyup,NULL}, {0,NULL}, UL,UL,def_int,ss_none,NULL,NULL}, + {"joy_down",{&joydown,NULL},{0,NULL}, UL,UL,def_int,ss_none,NULL,NULL}, + {"joyb_fire",{&joybfire,NULL},{0,NULL},0,UL, + def_int,ss_keys,NULL,NULL}, // joystick button number to use for fire + {"joyb_strafe",{&joybstrafe,NULL},{1,NULL},0,UL, + def_int,ss_keys,NULL,NULL}, // joystick button number to use for strafing + {"joyb_speed",{&joybspeed,NULL},{2,NULL},0,UL, + def_int,ss_keys,NULL,NULL}, // joystick button number to use for running + {"joyb_use",{&joybuse,NULL},{3,NULL},0,UL, + def_int,ss_keys,NULL,NULL}, // joystick button number to use for use/open + + {"Chat macros",{NULL,NULL},{0,NULL},UL,UL,def_none,ss_none,NULL,NULL}, + {"chatmacro0", {0,&chat_macros[0]}, {0,HUSTR_CHATMACRO0},UL,UL, + def_str,ss_chat,NULL,NULL}, // chat string associated with 0 key + {"chatmacro1", {0,&chat_macros[1]}, {0,HUSTR_CHATMACRO1},UL,UL, + def_str,ss_chat,NULL,NULL}, // chat string associated with 1 key + {"chatmacro2", {0,&chat_macros[2]}, {0,HUSTR_CHATMACRO2},UL,UL, + def_str,ss_chat,NULL,NULL}, // chat string associated with 2 key + {"chatmacro3", {0,&chat_macros[3]}, {0,HUSTR_CHATMACRO3},UL,UL, + def_str,ss_chat,NULL,NULL}, // chat string associated with 3 key + {"chatmacro4", {0,&chat_macros[4]}, {0,HUSTR_CHATMACRO4},UL,UL, + def_str,ss_chat,NULL,NULL}, // chat string associated with 4 key + {"chatmacro5", {0,&chat_macros[5]}, {0,HUSTR_CHATMACRO5},UL,UL, + def_str,ss_chat,NULL,NULL}, // chat string associated with 5 key + {"chatmacro6", {0,&chat_macros[6]}, {0,HUSTR_CHATMACRO6},UL,UL, + def_str,ss_chat,NULL,NULL}, // chat string associated with 6 key + {"chatmacro7", {0,&chat_macros[7]}, {0,HUSTR_CHATMACRO7},UL,UL, + def_str,ss_chat,NULL,NULL}, // chat string associated with 7 key + {"chatmacro8", {0,&chat_macros[8]}, {0,HUSTR_CHATMACRO8},UL,UL, + def_str,ss_chat,NULL,NULL}, // chat string associated with 8 key + {"chatmacro9", {0,&chat_macros[9]}, {0,HUSTR_CHATMACRO9},UL,UL, + def_str,ss_chat,NULL,NULL}, // chat string associated with 9 key + + {"Automap settings",{NULL,NULL},{0,NULL},UL,UL,def_none,ss_none,NULL,NULL}, + //jff 1/7/98 defaults for automap colors + //jff 4/3/98 remove -1 in lower range, 0 now disables new map features + {"mapcolor_back", {&mapcolor_back,NULL}, {247,NULL},0,255, // black //jff 4/6/98 new black + def_colour,ss_auto,NULL,NULL}, // color used as background for automap + {"mapcolor_grid", {&mapcolor_grid,NULL}, {104,NULL},0,255, // dk gray + def_colour,ss_auto,NULL,NULL}, // color used for automap grid lines + {"mapcolor_wall", {&mapcolor_wall,NULL}, {23,NULL},0,255, // red-brown + def_colour,ss_auto,NULL,NULL}, // color used for one side walls on automap + {"mapcolor_fchg", {&mapcolor_fchg,NULL}, {55,NULL},0,255, // lt brown + def_colour,ss_auto,NULL,NULL}, // color used for lines floor height changes across + {"mapcolor_cchg", {&mapcolor_cchg,NULL}, {215,NULL},0,255, // orange + def_colour,ss_auto,NULL,NULL}, // color used for lines ceiling height changes across + {"mapcolor_clsd", {&mapcolor_clsd,NULL}, {208,NULL},0,255, // white + def_colour,ss_auto,NULL,NULL}, // color used for lines denoting closed doors, objects + {"mapcolor_rkey", {&mapcolor_rkey,NULL}, {175,NULL},0,255, // red + def_colour,ss_auto,NULL,NULL}, // color used for red key sprites + {"mapcolor_bkey", {&mapcolor_bkey,NULL}, {204,NULL},0,255, // blue + def_colour,ss_auto,NULL,NULL}, // color used for blue key sprites + {"mapcolor_ykey", {&mapcolor_ykey,NULL}, {231,NULL},0,255, // yellow + def_colour,ss_auto,NULL,NULL}, // color used for yellow key sprites + {"mapcolor_rdor", {&mapcolor_rdor,NULL}, {175,NULL},0,255, // red + def_colour,ss_auto,NULL,NULL}, // color used for closed red doors + {"mapcolor_bdor", {&mapcolor_bdor,NULL}, {204,NULL},0,255, // blue + def_colour,ss_auto,NULL,NULL}, // color used for closed blue doors + {"mapcolor_ydor", {&mapcolor_ydor,NULL}, {231,NULL},0,255, // yellow + def_colour,ss_auto,NULL,NULL}, // color used for closed yellow doors + {"mapcolor_tele", {&mapcolor_tele,NULL}, {119,NULL},0,255, // dk green + def_colour,ss_auto,NULL,NULL}, // color used for teleporter lines + {"mapcolor_secr", {&mapcolor_secr,NULL}, {252,NULL},0,255, // purple + def_colour,ss_auto,NULL,NULL}, // color used for lines around secret sectors + {"mapcolor_exit", {&mapcolor_exit,NULL}, {0,NULL},0,255, // none + def_colour,ss_auto,NULL,NULL}, // color used for exit lines + {"mapcolor_unsn", {&mapcolor_unsn,NULL}, {104,NULL},0,255, // dk gray + def_colour,ss_auto,NULL,NULL}, // color used for lines not seen without computer map + {"mapcolor_flat", {&mapcolor_flat,NULL}, {88,NULL},0,255, // lt gray + def_colour,ss_auto,NULL,NULL}, // color used for lines with no height changes + {"mapcolor_sprt", {&mapcolor_sprt,NULL}, {112,NULL},0,255, // green + def_colour,ss_auto,NULL,NULL}, // color used as things + {"mapcolor_item", {&mapcolor_item,NULL}, {231,NULL},0,255, // yellow + def_colour,ss_auto,NULL,NULL}, // color used for counted items + {"mapcolor_hair", {&mapcolor_hair,NULL}, {208,NULL},0,255, // white + def_colour,ss_auto,NULL,NULL}, // color used for dot crosshair denoting center of map + {"mapcolor_sngl", {&mapcolor_sngl,NULL}, {208,NULL},0,255, // white + def_colour,ss_auto,NULL,NULL}, // color used for the single player arrow + {"mapcolor_me", {&mapcolor_me,NULL}, {112,NULL},0,255, // green + def_colour,ss_auto,NULL,NULL}, // your (player) colour + {"mapcolor_enemy", {&mapcolor_enemy,NULL}, {177,NULL},0,255, + def_colour,ss_auto,NULL,NULL}, + {"mapcolor_frnd", {&mapcolor_frnd,NULL}, {112,NULL},0,255, + def_colour,ss_auto,NULL,NULL}, + //jff 3/9/98 add option to not show secrets til after found + {"map_secret_after", {&map_secret_after,NULL}, {0,NULL},0,1, // show secret after gotten + def_bool,ss_auto,NULL,NULL}, // prevents showing secret sectors till after entered + {"map_point_coord", {&map_point_coordinates,NULL}, {0,NULL},0,1, + def_bool,ss_auto,NULL,NULL}, + //jff 1/7/98 end additions for automap + {"automapmode", {(int*)&automapmode,NULL}, {0,NULL}, 0, 31, // CPhipps - remember automap mode + def_hex,ss_none,NULL,NULL}, // automap mode + + {"Heads-up display settings",{NULL,NULL},{0,NULL},UL,UL,def_none,ss_none,NULL,NULL}, + //jff 2/16/98 defaults for color ranges in hud and status + {"hudcolor_titl", {&hudcolor_titl,NULL}, {5,NULL},0,9, // gold range + def_int,ss_auto,NULL,NULL}, // color range used for automap level title + {"hudcolor_xyco", {&hudcolor_xyco,NULL}, {3,NULL},0,9, // green range + def_int,ss_auto,NULL,NULL}, // color range used for automap coordinates + {"hudcolor_mesg", {&hudcolor_mesg,NULL}, {6,NULL},0,9, // red range + def_int,ss_mess,NULL,NULL}, // color range used for messages during play + {"hudcolor_chat", {&hudcolor_chat,NULL}, {5,NULL},0,9, // gold range + def_int,ss_mess,NULL,NULL}, // color range used for chat messages and entry + {"hudcolor_list", {&hudcolor_list,NULL}, {5,NULL},0,9, // gold range //jff 2/26/98 + def_int,ss_mess,NULL,NULL}, // color range used for message review + {"hud_msg_lines", {&hud_msg_lines,NULL}, {1,NULL},1,16, // 1 line scrolling window + def_int,ss_mess,NULL,NULL}, // number of messages in review display (1=disable) + {"hud_list_bgon", {&hud_list_bgon,NULL}, {0,NULL},0,1, // solid window bg ena //jff 2/26/98 + def_bool,ss_mess,NULL,NULL}, // enables background window behind message review + {"hud_distributed",{&hud_distributed,NULL},{0,NULL},0,1, // hud broken up into 3 displays //jff 3/4/98 + def_bool,ss_none,NULL,NULL}, // splits HUD into three 2 line displays + + {"health_red", {&health_red,NULL} , {25,NULL},0,200, // below is red + def_int,ss_stat,NULL,NULL}, // amount of health for red to yellow transition + {"health_yellow", {&health_yellow,NULL}, {50,NULL},0,200, // below is yellow + def_int,ss_stat,NULL,NULL}, // amount of health for yellow to green transition + {"health_green", {&health_green,NULL} , {100,NULL},0,200,// below is green, above blue + def_int,ss_stat,NULL,NULL}, // amount of health for green to blue transition + {"armor_red", {&armor_red,NULL} , {25,NULL},0,200, // below is red + def_int,ss_stat,NULL,NULL}, // amount of armor for red to yellow transition + {"armor_yellow", {&armor_yellow,NULL} , {50,NULL},0,200, // below is yellow + def_int,ss_stat,NULL,NULL}, // amount of armor for yellow to green transition + {"armor_green", {&armor_green,NULL} , {100,NULL},0,200,// below is green, above blue + def_int,ss_stat,NULL,NULL}, // amount of armor for green to blue transition + {"ammo_red", {&ammo_red,NULL} , {25,NULL},0,100, // below 25% is red + def_int,ss_stat,NULL,NULL}, // percent of ammo for red to yellow transition + {"ammo_yellow", {&ammo_yellow,NULL} , {50,NULL},0,100, // below 50% is yellow, above green + def_int,ss_stat,NULL,NULL}, // percent of ammo for yellow to green transition + + //jff 2/16/98 HUD and status feature controls + {"hud_active", {&hud_active,NULL}, {2,NULL},0,2, // 0=off, 1=small, 2=full + def_int,ss_none,NULL,NULL}, // 0 for HUD off, 1 for HUD small, 2 for full HUD + //jff 2/23/98 + {"hud_displayed", {&hud_displayed,NULL}, {0,NULL},0,1, // whether hud is displayed + def_bool,ss_none,NULL,NULL}, // enables display of HUD + {"hud_nosecrets", {&hud_nosecrets,NULL}, {0,NULL},0,1, // no secrets/items/kills HUD line + def_bool,ss_stat,NULL,NULL}, // disables display of kills/items/secrets on HUD + + {"Weapon preferences",{NULL,NULL},{0,NULL},UL,UL,def_none,ss_none,NULL,NULL}, + // killough 2/8/98: weapon preferences set by user: + {"weapon_choice_1", {&weapon_preferences[0][0],NULL}, {6,NULL}, 0,9, + def_int,ss_weap,NULL,NULL}, // first choice for weapon (best) + {"weapon_choice_2", {&weapon_preferences[0][1],NULL}, {9,NULL}, 0,9, + def_int,ss_weap,NULL,NULL}, // second choice for weapon + {"weapon_choice_3", {&weapon_preferences[0][2],NULL}, {4,NULL}, 0,9, + def_int,ss_weap,NULL,NULL}, // third choice for weapon + {"weapon_choice_4", {&weapon_preferences[0][3],NULL}, {3,NULL}, 0,9, + def_int,ss_weap,NULL,NULL}, // fourth choice for weapon + {"weapon_choice_5", {&weapon_preferences[0][4],NULL}, {2,NULL}, 0,9, + def_int,ss_weap,NULL,NULL}, // fifth choice for weapon + {"weapon_choice_6", {&weapon_preferences[0][5],NULL}, {8,NULL}, 0,9, + def_int,ss_weap,NULL,NULL}, // sixth choice for weapon + {"weapon_choice_7", {&weapon_preferences[0][6],NULL}, {5,NULL}, 0,9, + def_int,ss_weap,NULL,NULL}, // seventh choice for weapon + {"weapon_choice_8", {&weapon_preferences[0][7],NULL}, {7,NULL}, 0,9, + def_int,ss_weap,NULL,NULL}, // eighth choice for weapon + {"weapon_choice_9", {&weapon_preferences[0][8],NULL}, {1,NULL}, 0,9, + def_int,ss_weap,NULL,NULL}, // ninth choice for weapon (worst) + + // cournia - support for arbitrary music file (defaults are mp3) + {"Music", {NULL,NULL},{0,NULL},UL,UL,def_none,ss_none,NULL,NULL}, + {"mus_e1m1", {0,&S_music_files[mus_e1m1]}, {0,"e1m1.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_e1m2", {0,&S_music_files[mus_e1m2]}, {0,"e1m2.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_e1m3", {0,&S_music_files[mus_e1m3]}, {0,"e1m3.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_e1m4", {0,&S_music_files[mus_e1m4]}, {0,"e1m4.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_e1m5", {0,&S_music_files[mus_e1m5]}, {0,"e1m5.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_e1m6", {0,&S_music_files[mus_e1m6]}, {0,"e1m6.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_e1m7", {0,&S_music_files[mus_e1m7]}, {0,"e1m7.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_e1m8", {0,&S_music_files[mus_e1m8]}, {0,"e1m8.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_e1m9", {0,&S_music_files[mus_e1m9]}, {0,"e1m9.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_e2m1", {0,&S_music_files[mus_e2m1]}, {0,"e2m1.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_e2m2", {0,&S_music_files[mus_e2m2]}, {0,"e2m2.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_e2m3", {0,&S_music_files[mus_e2m3]}, {0,"e2m3.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_e2m4", {0,&S_music_files[mus_e2m4]}, {0,"e2m4.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_e2m5", {0,&S_music_files[mus_e2m5]}, {0,"e1m7.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_e2m6", {0,&S_music_files[mus_e2m6]}, {0,"e2m6.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_e2m7", {0,&S_music_files[mus_e2m7]}, {0,"e2m7.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_e2m8", {0,&S_music_files[mus_e2m8]}, {0,"e2m8.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_e2m9", {0,&S_music_files[mus_e2m9]}, {0,"e3m1.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_e3m1", {0,&S_music_files[mus_e3m1]}, {0,"e3m1.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_e3m2", {0,&S_music_files[mus_e3m2]}, {0,"e3m2.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_e3m3", {0,&S_music_files[mus_e3m3]}, {0,"e3m3.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_e3m4", {0,&S_music_files[mus_e3m4]}, {0,"e1m8.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_e3m5", {0,&S_music_files[mus_e3m5]}, {0,"e1m7.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_e3m6", {0,&S_music_files[mus_e3m6]}, {0,"e1m6.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_e3m7", {0,&S_music_files[mus_e3m7]}, {0,"e2m7.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_e3m8", {0,&S_music_files[mus_e3m8]}, {0,"e3m8.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_e3m9", {0,&S_music_files[mus_e3m9]}, {0,"e1m9.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_inter", {0,&S_music_files[mus_inter]}, {0,"e2m3.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_intro", {0,&S_music_files[mus_intro]}, {0,"intro.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_bunny", {0,&S_music_files[mus_bunny]}, {0,"bunny.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_victor", {0,&S_music_files[mus_victor]}, {0,"victor.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_introa", {0,&S_music_files[mus_introa]}, {0,"intro.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_runnin", {0,&S_music_files[mus_runnin]}, {0,"runnin.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_stalks", {0,&S_music_files[mus_stalks]}, {0,"stalks.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_countd", {0,&S_music_files[mus_countd]}, {0,"countd.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_betwee", {0,&S_music_files[mus_betwee]}, {0,"betwee.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_doom", {0,&S_music_files[mus_doom]}, {0,"doom.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_the_da", {0,&S_music_files[mus_the_da]}, {0,"the_da.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_shawn", {0,&S_music_files[mus_shawn]}, {0,"shawn.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_ddtblu", {0,&S_music_files[mus_ddtblu]}, {0,"ddtblu.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_in_cit", {0,&S_music_files[mus_in_cit]}, {0,"in_cit.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_dead", {0,&S_music_files[mus_dead]}, {0,"dead.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_stlks2", {0,&S_music_files[mus_stlks2]}, {0,"stalks.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_theda2", {0,&S_music_files[mus_theda2]}, {0,"the_da.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_doom2", {0,&S_music_files[mus_doom2]}, {0,"doom.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_ddtbl2", {0,&S_music_files[mus_ddtbl2]}, {0,"ddtblu.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_runni2", {0,&S_music_files[mus_runni2]}, {0,"runnin.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_dead2", {0,&S_music_files[mus_dead2]}, {0,"dead.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_stlks3", {0,&S_music_files[mus_stlks3]}, {0,"stalks.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_romero", {0,&S_music_files[mus_romero]}, {0,"romero.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_shawn2", {0,&S_music_files[mus_shawn2]}, {0,"shawn.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_messag", {0,&S_music_files[mus_messag]}, {0,"messag.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_count2", {0,&S_music_files[mus_count2]}, {0,"countd.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_ddtbl3", {0,&S_music_files[mus_ddtbl3]}, {0,"ddtblu.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_ampie", {0,&S_music_files[mus_ampie]}, {0,"ampie.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_theda3", {0,&S_music_files[mus_theda3]}, {0,"the_da.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_adrian", {0,&S_music_files[mus_adrian]}, {0,"adrian.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_messg2", {0,&S_music_files[mus_messg2]}, {0,"messag.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_romer2", {0,&S_music_files[mus_romer2]}, {0,"romero.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_tense", {0,&S_music_files[mus_tense]}, {0,"tense.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_shawn3", {0,&S_music_files[mus_shawn3]}, {0,"shawn.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_openin", {0,&S_music_files[mus_openin]}, {0,"openin.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_evil", {0,&S_music_files[mus_evil]}, {0,"evil.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_ultima", {0,&S_music_files[mus_ultima]}, {0,"ultima.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_read_m", {0,&S_music_files[mus_read_m]}, {0,"read_m.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_dm2ttl", {0,&S_music_files[mus_dm2ttl]}, {0,"dm2ttl.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, + {"mus_dm2int", {0,&S_music_files[mus_dm2int]}, {0,"dm2int.mp3"},UL,UL, + def_str,ss_none,NULL,NULL}, +}; + +int numdefaults; +static const char* defaultfile; // CPhipps - static, const + +// +// M_SaveDefaults +// + +void M_SaveDefaults (void) + { + int i; + FILE* f; + + f = fopen (defaultfile, "w"); + if (!f) + return; // can't write the file, but don't complain + + // 3/3/98 explain format of file + + fprintf(f,"# Doom config file\n"); + fprintf(f,"# Format:\n"); + fprintf(f,"# variable value\n"); + + for (i = 0 ; i < numdefaults ; i++) { + if (defaults[i].type == def_none) { + // CPhipps - pure headers + fprintf(f, "\n# %s\n", defaults[i].name); + } else + // CPhipps - modified for new default_t form + if (!IS_STRING(defaults[i])) //jff 4/10/98 kill super-hack on pointer value + { + // CPhipps - remove keycode hack + // killough 3/6/98: use spaces instead of tabs for uniform justification + if (defaults[i].type == def_hex) + fprintf (f,"%-25s 0x%x\n",defaults[i].name,*(defaults[i].location.pi)); + else + fprintf (f,"%-25s %5i\n",defaults[i].name,*(defaults[i].location.pi)); + } + else + { + fprintf (f,"%-25s \"%s\"\n",defaults[i].name,*(defaults[i].location.ppsz)); + } + } + + fclose (f); + } + +/* + * M_LookupDefault + * + * cph - mimic MBF function for now. Yes it's crap. + */ + +struct default_s *M_LookupDefault(const char *name) +{ + int i; + for (i = 0 ; i < numdefaults - 1 ; i++) + if ((defaults[i].type != def_none) && !strcmp(name, defaults[i].name)) + return &defaults[i]; + I_Error("M_LookupDefault: %s not found",name); + return NULL; +} + +// +// M_LoadDefaults +// + +#define NUMCHATSTRINGS 10 // phares 4/13/98 + +void M_LoadDefaults (void) +{ + int i; + int len; + FILE* f; + char def[80]; + char strparm[100]; + char* newstring = NULL; // killough + int parm; + boolean isstring; + + // set everything to base values + + numdefaults = sizeof(defaults)/sizeof(defaults[0]); + for (i = 0 ; i < numdefaults ; i++) { + if (defaults[i].location.ppsz) + *defaults[i].location.ppsz = strdup(defaults[i].defaultvalue.psz); + if (defaults[i].location.pi) + *defaults[i].location.pi = defaults[i].defaultvalue.i; + } + + // check for a custom default file + + i = M_CheckParm ("-config"); + if (i && i < myargc-1) + defaultfile = myargv[i+1]; + else { + const char* exedir = I_DoomExeDir(); + defaultfile = malloc(PATH_MAX+1); + /* get config file from same directory as executable */ +#if ((defined GL_DOOM) && (defined _MSC_VER)) + #define PRBOOM_GL_OR_PR "gl" +#else + #define PRBOOM_GL_OR_PR "pr" +#endif + +#ifdef HAVE_SNPRINTF + snprintf((char *)defaultfile, PATH_MAX, + "%s%s%sboom.cfg", exedir, HasTrailingSlash(exedir) ? "" : "/", PRBOOM_GL_OR_PR ); +#else + sprintf ((char *)defaultfile, + "%s%s%sboom.cfg", exedir, HasTrailingSlash(exedir) ? "" : "/", PRBOOM_GL_OR_PR ); +#endif + } + + lprintf (LO_CONFIRM, " default file: %s\n",defaultfile); + + // read the file in, overriding any set defaults + + f = fopen (defaultfile, "r"); + if (f) + { + while (!feof(f)) + { + isstring = false; + if (fscanf (f, "%79s %[^\n]\n", def, strparm) == 2) + { + + //jff 3/3/98 skip lines not starting with an alphanum + + if (!isalnum(def[0])) + continue; + + if (strparm[0] == '"') { + // get a string default + + isstring = true; + len = strlen(strparm); + newstring = (char *) malloc(len); + strparm[len-1] = 0; // clears trailing double-quote mark + strcpy(newstring, strparm+1); // clears leading double-quote mark + } else if ((strparm[0] == '0') && (strparm[1] == 'x')) { + // CPhipps - allow ints to be specified in hex + sscanf(strparm+2, "%x", &parm); + } else { + sscanf(strparm, "%i", &parm); + // Keycode hack removed + } + + for (i = 0 ; i < numdefaults ; i++) + if ((defaults[i].type != def_none) && !strcmp(def, defaults[i].name)) + { + // CPhipps - safety check + if (isstring != IS_STRING(defaults[i])) { + lprintf(LO_WARN, "M_LoadDefaults: Type mismatch reading %s\n", defaults[i].name); + continue; + } + if (!isstring) + { + + //jff 3/4/98 range check numeric parameters + + if ((defaults[i].minvalue==UL || defaults[i].minvalue<=parm) && + (defaults[i].maxvalue==UL || defaults[i].maxvalue>=parm)) + *(defaults[i].location.pi) = parm; + } + else + { + free((char*)*(defaults[i].location.ppsz)); /* phares 4/13/98 */ + *(defaults[i].location.ppsz) = newstring; + } + break; + } + } + } + + fclose (f); + } + //jff 3/4/98 redundant range checks for hud deleted here +} + + +// +// SCREEN SHOTS +// + +// +// M_ScreenShot +// +// Modified by Lee Killough so that any number of shots can be taken, +// the code is faster, and no annoying "screenshot" message appears. + +// CPhipps - modified to use its own buffer for the image +// - checks for the case where no file can be created (doesn't occur on POSIX systems, would on DOS) +// - track errors better +// - split into 2 functions + +// +// M_DoScreenShot +// Takes a screenshot into the names file + +void M_DoScreenShot (const char* fname) +{ + if (I_ScreenShot(fname) != 0) + doom_printf("M_ScreenShot: Error writing screenshot\n"); +} + +#ifndef SCREENSHOT_DIR +#define SCREENSHOT_DIR "." +#endif + +#ifdef HAVE_LIBPNG +#define SCREENSHOT_EXT ".png" +#else +#define SCREENSHOT_EXT ".bmp" +#endif + +void M_ScreenShot(void) +{ + static int shot; + char lbmname[PATH_MAX + 1]; + int startshot; + + if (!access(SCREENSHOT_DIR,2)) + { + startshot = shot; // CPhipps - prevent infinite loop + + do { + sprintf(lbmname,"%s/doom%02d" SCREENSHOT_EXT, SCREENSHOT_DIR, shot++); + } while (!access(lbmname,0) && (shot != startshot) && (shot < 10000)); + + if (access(lbmname,0)) + { + S_StartSound(NULL,gamemode==commercial ? sfx_radio : sfx_tink); + M_DoScreenShot(lbmname); // cph + return; + } + } + + doom_printf ("M_ScreenShot: Couldn't create screenshot"); + return; +} diff --git a/common/prboom/m_misc.h b/common/prboom/m_misc.h new file mode 100755 index 0000000..2e4d545 --- /dev/null +++ b/common/prboom/m_misc.h @@ -0,0 +1,111 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * External non-system-specific stuff, like storing config settings, + * simple file handling, and saving screnshots. + * + *-----------------------------------------------------------------------------*/ + + +#ifndef __M_MISC__ +#define __M_MISC__ + + +#include "doomtype.h" +// +// MISC +// + +boolean M_WriteFile (char const* name,void* source,int length); + +int M_ReadFile (char const* name,byte** buffer); + +void M_ScreenShot (void); +void M_DoScreenShot (const char*); // cph + +void M_LoadDefaults (void); + +void M_SaveDefaults (void); + +struct default_s *M_LookupDefault(const char *name); /* killough 11/98 */ + +// phares 4/21/98: +// Moved from m_misc.c so m_menu.c could see it. + +// CPhipps - struct to hold a value in a config file +// Cannot be a union, as it must be initialised +typedef struct default_s +{ + const char* name; + /* cph - + * The location struct holds the pointer to the variable holding the + * setting. For int's we do nothing special. + * For strings, the string is actually stored on our heap with Z_Strdup() + * BUT we don't want the rest of the program to be able to modify them, + * so we declare it const. It's not really const though, and m_misc.c and + * m_menu.c cast it back when they need to change it. Possibly this is + * more trouble than it's worth. + */ + struct { + int* pi; + const char** ppsz; + } location; + struct { + int i; + const char* psz; + } defaultvalue; // CPhipps - default value + // Limits (for an int) + int minvalue; // jff 3/3/98 minimum allowed value + int maxvalue; // jff 3/3/98 maximum allowed value + enum { + def_none, // Dummy entry + def_str, // A string + def_int, // Integer + def_hex, // Integer (write in hex) + def_bool = def_int, // Boolean + def_key = def_hex, // Key code (byte) + def_mouseb = def_int,// Mouse button + def_colour = def_hex // Colour (256 colour palette entry) + } type; // CPhipps - type of entry + int setupscreen; // phares 4/19/98: setup screen where this appears + int *current; /* cph - MBF-like pointer to current value */ + // cph - removed the help strings from the config file + // const char* help; // jff 3/3/98 description of parameter + // CPhipps - remove unused "lousy hack" code + struct setup_menu_s *setup_menu; /* Xref to setup menu item, if any */ +} default_t; + +#define IS_STRING(dv) ((dv).type == def_str) +// CPhipps - What is the max. key code that X will send us? +#define MAX_KEY 65536 +#define MAX_MOUSEB 2 + +#define UL (-123456789) /* magic number for no min or max for parameter */ + +#endif diff --git a/common/prboom/m_random.c b/common/prboom/m_random.c new file mode 100755 index 0000000..bd0c7bc --- /dev/null +++ b/common/prboom/m_random.c @@ -0,0 +1,147 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Random number LUT. + * + * 1/19/98 killough: Rewrote random number generator for better randomness, + * while at the same time maintaining demo sync and backward compatibility. + * + * 2/16/98 killough: Made each RNG local to each control-equivalent block, + * to reduce the chances of demo sync problems. + * + *-----------------------------------------------------------------------------*/ + + +#include "doomstat.h" +#include "m_random.h" +#include "lprintf.h" + +// +// M_Random +// Returns a 0-255 number +// +static const unsigned char rndtable[256] = { // 1/19/98 killough -- made const + 0, 8, 109, 220, 222, 241, 149, 107, 75, 248, 254, 140, 16, 66 , + 74, 21, 211, 47, 80, 242, 154, 27, 205, 128, 161, 89, 77, 36 , + 95, 110, 85, 48, 212, 140, 211, 249, 22, 79, 200, 50, 28, 188 , + 52, 140, 202, 120, 68, 145, 62, 70, 184, 190, 91, 197, 152, 224 , + 149, 104, 25, 178, 252, 182, 202, 182, 141, 197, 4, 81, 181, 242 , + 145, 42, 39, 227, 156, 198, 225, 193, 219, 93, 122, 175, 249, 0 , + 175, 143, 70, 239, 46, 246, 163, 53, 163, 109, 168, 135, 2, 235 , + 25, 92, 20, 145, 138, 77, 69, 166, 78, 176, 173, 212, 166, 113 , + 94, 161, 41, 50, 239, 49, 111, 164, 70, 60, 2, 37, 171, 75 , + 136, 156, 11, 56, 42, 146, 138, 229, 73, 146, 77, 61, 98, 196 , + 135, 106, 63, 197, 195, 86, 96, 203, 113, 101, 170, 247, 181, 113 , + 80, 250, 108, 7, 255, 237, 129, 226, 79, 107, 112, 166, 103, 241 , + 24, 223, 239, 120, 198, 58, 60, 82, 128, 3, 184, 66, 143, 224 , + 145, 224, 81, 206, 163, 45, 63, 90, 168, 114, 59, 33, 159, 95 , + 28, 139, 123, 98, 125, 196, 15, 70, 194, 253, 54, 14, 109, 226 , + 71, 17, 161, 93, 186, 87, 244, 138, 20, 52, 123, 251, 26, 36 , + 17, 46, 52, 231, 232, 76, 31, 221, 84, 37, 216, 165, 212, 106 , + 197, 242, 98, 43, 39, 175, 254, 145, 190, 84, 118, 222, 187, 136 , + 120, 163, 236, 249 +}; + +rng_t rng; // the random number state + +unsigned long rngseed = 1993; // killough 3/26/98: The seed + +int (P_Random)(pr_class_t pr_class +#ifdef INSTRUMENTED + , const char *file, int line +#endif +) +{ + // killough 2/16/98: We always update both sets of random number + // generators, to ensure repeatability if the demo_compatibility + // flag is changed while the program is running. Changing the + // demo_compatibility flag does not change the sequences generated, + // only which one is selected from. + // + // All of this RNG stuff is tricky as far as demo sync goes -- + // it's like playing with explosives :) Lee + +#ifdef INSTRUMENTED + //lprintf(LO_DEBUG, "%.10d: %.10d - %s:%.5d\n", gametic, pr_class, file, line); +#endif + + int compat = pr_class == pr_misc ? + (rng.prndindex = (rng.prndindex + 1) & 255) : + (rng. rndindex = (rng. rndindex + 1) & 255) ; + + unsigned long boom; + + // killough 3/31/98: + // If demo sync insurance is not requested, use + // much more unstable method by putting everything + // except pr_misc into pr_all_in_one + + if (pr_class != pr_misc && !demo_insurance) // killough 3/31/98 + pr_class = pr_all_in_one; + + boom = rng.seed[pr_class]; + + // killough 3/26/98: add pr_class*2 to addend + + rng.seed[pr_class] = boom * 1664525ul + 221297ul + pr_class*2; + + if (demo_compatibility) + return rndtable[compat]; + + boom >>= 20; + + /* killough 3/30/98: use gametic-levelstarttic to shuffle RNG + * killough 3/31/98: but only if demo insurance requested, + * since it's unnecessary for random shuffling otherwise + * killough 9/29/98: but use basetic now instead of levelstarttic + * cph - DEMOSYNC - this change makes MBF demos work, + * but does it break Boom ones? + */ + + if (demo_insurance) + boom += (gametic-basetic)*7; + + return boom & 255; +} + +// Initialize all the seeds +// +// This initialization method is critical to maintaining demo sync. +// Each seed is initialized according to its class, so if new classes +// are added they must be added to end of pr_class_t list. killough +// + +void M_ClearRandom (void) +{ + int i; + unsigned long seed = rngseed*2+1; // add 3/26/98: add rngseed + for (i=0; i +#ifdef __arch__swab16 +#define doom_swap_s (signed short)__arch__swab16 +#endif +#ifdef __arch__swab32 +#define doom_swap_l (signed long)__arch__swab32 +#endif +#endif /* HAVE_ASM_BYTEORDER_H */ + +#ifdef HAVE_LIBKERN_OSBYTEORDER_H +#include + +#define doom_swap_s (short)OSSwapInt16 +#define doom_swap_l (long)OSSwapInt32 +#endif + +#ifndef doom_swap_l +#define doom_swap_l(x) \ + ((long int)((((unsigned long int)(x) & 0x000000ffU) << 24) | \ + (((unsigned long int)(x) & 0x0000ff00U) << 8) | \ + (((unsigned long int)(x) & 0x00ff0000U) >> 8) | \ + (((unsigned long int)(x) & 0xff000000U) >> 24))) +#endif + +#ifndef doom_swap_s +#define doom_swap_s(x) \ + ((short int)((((unsigned short int)(x) & 0x00ff) << 8) | \ + (((unsigned short int)(x) & 0xff00) >> 8))) +#endif + +/* Macros are named doom_XtoYT, where + * X is thing to convert from, Y is thing to convert to, chosen from + * n for network, h for host (i.e our machine's), w for WAD (Doom data files) + * and T is the type, l or s for long or short + * + * CPhipps - all WADs and network packets will be little endian for now + * Use separate macros so network could be converted to big-endian later. + */ + +#ifdef WORDS_BIGENDIAN + +#define doom_wtohl(x) doom_swap_l(x) +#define doom_htowl(x) doom_swap_l(x) +#define doom_wtohs(x) doom_swap_s(x) +#define doom_htows(x) doom_swap_s(x) + +#define doom_ntohl(x) doom_swap_l(x) +#define doom_htonl(x) doom_swap_l(x) +#define doom_ntohs(x) doom_swap_s(x) +#define doom_htons(x) doom_swap_s(x) + +#else + +#define doom_wtohl(x) (long int)(x) +#define doom_htowl(x) (long int)(x) +#define doom_wtohs(x) (short int)(x) +#define doom_htows(x) (short int)(x) + +#define doom_ntohl(x) (long int)(x) +#define doom_htonl(x) (long int)(x) +#define doom_ntohs(x) (short int)(x) +#define doom_htons(x) (short int)(x) + +#endif + +/* CPhipps - Boom's old LONG and SHORT endianness macros are for WAD stuff */ + +#define LONG(x) doom_wtohl(x) +#define SHORT(x) doom_htows(x) + +#endif diff --git a/common/prboom/md5.c b/common/prboom/md5.c new file mode 100755 index 0000000..6d51e05 --- /dev/null +++ b/common/prboom/md5.c @@ -0,0 +1,240 @@ +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + * + * Changed so as no longer to depend on Colin Plumb's `usual.h' header + * definitions; now uses stuff from dpkg's config.h. + * - Ian Jackson . + * Still in the public domain. + */ +#include "config.h" + +#include /* for memcpy() */ +#include /* for stupid systems */ + +#include "md5.h" + +#ifdef WORDS_BIGENDIAN +void +byteSwap(UWORD32 *buf, unsigned words) +{ + md5byte *p = (md5byte *)buf; + + do { + *buf++ = (UWORD32)((unsigned)p[3] << 8 | p[2]) << 16 | + ((unsigned)p[1] << 8 | p[0]); + p += 4; + } while (--words); +} +#else +#define byteSwap(buf,words) +#endif + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void +MD5Init(struct MD5Context *ctx) +{ + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bytes[0] = 0; + ctx->bytes[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void +MD5Update(struct MD5Context *ctx, md5byte const *buf, unsigned len) +{ + UWORD32 t; + + /* Update byte count */ + + t = ctx->bytes[0]; + if ((ctx->bytes[0] = t + len) < t) + ctx->bytes[1]++; /* Carry from low to high */ + + t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */ + if (t > len) { + memcpy((md5byte *)ctx->in + 64 - t, buf, len); + return; + } + /* First chunk is an odd size */ + memcpy((md5byte *)ctx->in + 64 - t, buf, t); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + buf += t; + len -= t; + + /* Process data in 64-byte chunks */ + while (len >= 64) { + memcpy(ctx->in, buf, 64); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +void +MD5Final(md5byte digest[16], struct MD5Context *ctx) +{ + int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */ + md5byte *p = (md5byte *)ctx->in + count; + + /* Set the first char of padding to 0x80. There is always room. */ + *p++ = 0x80; + + /* Bytes of padding needed to make 56 bytes (-8..55) */ + count = 56 - 1 - count; + + if (count < 0) { /* Padding forces an extra block */ + memset(p, 0, count + 8); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + p = (md5byte *)ctx->in; + count = 56; + } + memset(p, 0, count); + byteSwap(ctx->in, 14); + + /* Append length in bits and transform */ + ctx->in[14] = ctx->bytes[0] << 3; + ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29; + MD5Transform(ctx->buf, ctx->in); + + byteSwap(ctx->buf, 4); + memcpy(digest, ctx->buf, 16); + memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */ +} + +#ifndef ASM_MD5 + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f,w,x,y,z,in,s) \ + (w += f(x,y,z) + in, w = (w<>(32-s)) + x) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +void +MD5Transform(UWORD32 buf[4], UWORD32 const in[16]) +{ + register UWORD32 a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +#endif diff --git a/common/prboom/md5.h b/common/prboom/md5.h new file mode 100755 index 0000000..3ebeb36 --- /dev/null +++ b/common/prboom/md5.h @@ -0,0 +1,47 @@ +/* + * This is the header file for the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + * + * Changed so as no longer to depend on Colin Plumb's `usual.h' + * header definitions; now uses stuff from dpkg's config.h + * - Ian Jackson . + * Still in the public domain. + */ + +#ifndef MD5_H +#define MD5_H + +#ifdef _MSC_VER +#define WIN32_LEAN_AND_MEAN +#include +#define UWORD32 DWORD +#else +#include +#define UWORD32 uint32_t +#endif +#define md5byte unsigned char + +struct MD5Context { + UWORD32 buf[4]; + UWORD32 bytes[2]; + UWORD32 in[16]; +}; + +void MD5Init(struct MD5Context *context); +void MD5Update(struct MD5Context *context, md5byte const *buf, unsigned len); +void MD5Final(unsigned char digest[16], struct MD5Context *context); +void MD5Transform(UWORD32 buf[4], UWORD32 const in[16]); + +#endif /* !MD5_H */ diff --git a/common/prboom/mmus2mid.c b/common/prboom/mmus2mid.c new file mode 100755 index 0000000..39dba3c --- /dev/null +++ b/common/prboom/mmus2mid.c @@ -0,0 +1,847 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * This file supports conversion of MUS format music in memory + * to MIDI format 1 music in memory. + * + * The primary routine, mmus2mid, converts a block of memory in MUS format + * to an Allegro MIDI structure. This supports playing MUS lumps in a wad + * file with BOOM. + * + * Another routine, Midi2MIDI, converts a block of memory in MIDI format 1 to + * an Allegro MIDI structure. This supports playing MIDI lumps in a wad + * file with BOOM. + * + * For testing purposes, and to make a utility if desired, if the symbol + * STANDALONE is defined by uncommenting the definition below, a main + * routine is compiled that will convert a possibly wildcarded set of MUS + * files to a similarly named set of MIDI files. + * + * Much of the code here is thanks to S. Bacquet's source for QMUS2MID.C + * + *----------------------------------------------------------------------------- + */ + + +#include +#include +#include +#include +#include +#include +#include +#ifdef MSDOS /* proff: I don't use allegro in windows */ +#include +#endif /* !MSDOS */ +#include "mmus2mid.h" +#include "lprintf.h" // jff 08/03/98 - declaration of lprintf + +//#define STANDALONE /* uncomment this to make MMUS2MID.EXE */ +#ifndef STANDALONE +#include "m_swap.h" +#include "z_zone.h" +#endif + +// some macros to decode mus event bit fields + +#define last(e) ((UBYTE)((e) & 0x80)) +#define event_type(e) ((UBYTE)(((e) & 0x7F) >> 4)) +#define channel(e) ((UBYTE)((e) & 0x0F)) + +// event types + +typedef enum +{ + RELEASE_NOTE, + PLAY_NOTE, + BEND_NOTE, + SYS_EVENT, + CNTL_CHANGE, + UNKNOWN_EVENT1, + SCORE_END, + UNKNOWN_EVENT2, +} mus_event_t; + +// MUS format header structure + +typedef struct +{ + char ID[4]; // identifier "MUS"0x1A + UWORD ScoreLength; // length of music portion + UWORD ScoreStart; // offset of music portion + UWORD channels; // count of primary channels + UWORD SecChannels; // count of secondary channels + UWORD InstrCnt; // number of instruments +} PACKEDATTR MUSheader; + +// to keep track of information in a MIDI track + +typedef struct Track +{ + char velocity; + long deltaT; + UBYTE lastEvt; + long alloced; +} TrackInfo; + +// array of info about tracks + +static TrackInfo track[MIDI_TRACKS]; + +// initial track size allocation +#define TRACKBUFFERSIZE 1024 + +// lookup table MUS -> MID controls +static UBYTE MUS2MIDcontrol[15] = +{ + 0, // Program change - not a MIDI control change + 0x00, // Bank select + 0x01, // Modulation pot + 0x07, // Volume + 0x0A, // Pan pot + 0x0B, // Expression pot + 0x5B, // Reverb depth + 0x5D, // Chorus depth + 0x40, // Sustain pedal + 0x43, // Soft pedal + 0x78, // All sounds off + 0x7B, // All notes off + 0x7E, // Mono + 0x7F, // Poly + 0x79 // Reset all controllers +}; + +// some strings of bytes used in the midi format + +static UBYTE midikey[] = +{0x00,0xff,0x59,0x02,0x00,0x00}; // C major +static UBYTE miditempo[] = +{0x00,0xff,0x51,0x03,0x09,0xa3,0x1a}; // uS/qnote +static UBYTE midihdr[] = +{'M','T','h','d',0,0,0,6,0,1,0,0,0,0}; // header (length 6, format 1) +static UBYTE trackhdr[] = +{'M','T','r','k'}; // track header + +// static routine prototypes + +static int TWriteByte(MIDI *mididata, int MIDItrack, UBYTE byte); +static int TWriteVarLen(MIDI *mididata, int MIDItrack, register ULONG value); +static ULONG ReadTime(const UBYTE **musptrp); +static int FirstChannelAvailable(int MUS2MIDchannel[]); +static UBYTE MidiEvent(MIDI *mididata,UBYTE midicode,UBYTE MIDIchannel, + UBYTE MIDItrack,int nocomp); + +// +// TWriteByte() +// +// write one byte to the selected MIDItrack, update current position +// if track allocation exceeded, double it +// if track not allocated, initially allocate TRACKBUFFERSIZE bytes +// +// Passed pointer to Allegro MIDI structure, number of the MIDI track being +// written, and the byte to write. +// +// Returns 0 on success, MEMALLOC if a memory allocation error occurs +// +static int TWriteByte(MIDI *mididata, int MIDItrack, UBYTE byte) +{ + ULONG pos ; + + pos = mididata->track[MIDItrack].len; + if (pos >= (ULONG)track[MIDItrack].alloced) + { + track[MIDItrack].alloced = // double allocation + track[MIDItrack].alloced? // or set initial TRACKBUFFERSIZE + 2*track[MIDItrack].alloced : + TRACKBUFFERSIZE; + + if (!(mididata->track[MIDItrack].data = // attempt to reallocate + realloc(mididata->track[MIDItrack].data, + track[MIDItrack].alloced))) + return MEMALLOC; + } + mididata->track[MIDItrack].data[pos] = byte; + mididata->track[MIDItrack].len++; + return 0; +} + +// +// TWriteVarLen() +// +// write the ULONG value to tracknum-th track, in midi format, which is +// big endian, 7 bits per byte, with all bytes but the last flagged by +// bit 8 being set, allowing the length to vary. +// +// Passed the Allegro MIDI structure, the track number to write, +// and the ULONG value to encode in midi format there +// +// Returns 0 if sucessful, MEMALLOC if a memory allocation error occurs +// +static int TWriteVarLen(MIDI *mididata, int tracknum, register ULONG value) +{ + register ULONG buffer; + + buffer = value & 0x7f; + while ((value >>= 7)) // terminates because value unsigned + { + buffer <<= 8; // note first value shifted in has bit 8 clear + buffer |= 0x80; // all succeeding values do not + buffer += (value & 0x7f); + } + while (1) // write bytes out in opposite order + { + if (TWriteByte(mididata, tracknum, (UBYTE)(buffer&0xff))) // insure buffer masked + return MEMALLOC; + + if (buffer & 0x80) + buffer >>= 8; + else // terminate on the byte with bit 8 clear + break; + } + return 0; +} + +// +// ReadTime() +// +// Read a time value from the MUS buffer, advancing the position in it +// +// A time value is a variable length sequence of 8 bit bytes, with all +// but the last having bit 8 set. +// +// Passed a pointer to the pointer to the MUS buffer +// Returns the integer unsigned long time value there and advances the pointer +// +static ULONG ReadTime(const UBYTE **musptrp) +{ + register ULONG timeval = 0; + int byte; + + do // shift each byte read up in the result until a byte with bit 8 clear + { + byte = *(*musptrp)++; + timeval = (timeval << 7) + (byte & 0x7F); + } + while(byte & 0x80); + + return timeval; +} + +// +// FirstChannelAvailable() +// +// Return the next unassigned MIDI channel number +// +// The assignment for MUS channel 15 is not counted in the caculation, that +// being percussion and always assigned to MIDI channel 9 (base 0). +// +// Passed the array of MIDI channels assigned to MUS channels +// Returns the maximum channel number unassigned unless that is 9 in which +// case 10 is returned. +// +// killough 10/7/98: changed char parameter, return values to int + +static int FirstChannelAvailable(int MUS2MIDchannel[]) +{ + int i ; + int max = -1 ; + + // find the largest MIDI channel assigned so far + for (i = 0; i < 15; i++) + if (MUS2MIDchannel[i] > max) + max = MUS2MIDchannel[i]; + + return (max == 8 ? 10 : max+1); // skip MIDI channel 9 (percussion) +} + +// +// MidiEvent() +// +// Constructs a MIDI event code, and writes it to the current MIDI track +// unless its the same as the last event code and compressio is enabled +// in which case nothing is written. +// +// Passed the Allegro MIDI structure, the midi event code, the current +// MIDI channel number, the current MIDI track number, and whether compression +// (running status) is enabled. +// +// Returns the new event code if successful, 0 if a memory allocation error +// +static UBYTE MidiEvent(MIDI *mididata,UBYTE midicode,UBYTE MIDIchannel, + UBYTE MIDItrack,int nocomp) +{ + UBYTE newevent; + + newevent = midicode | MIDIchannel; + if ((newevent != track[MIDItrack].lastEvt) || nocomp) + { + if (TWriteByte(mididata,MIDItrack, newevent)) + return 0; // indicates MEMALLOC error + track[MIDItrack].lastEvt = newevent; + } + return newevent; +} + +// +// mmus2mid() +// +// Convert a memory buffer contain MUS data to an Allegro MIDI structure +// with specified time division and compression. +// +// Passed a pointer to the buffer containing MUS data, a pointer to the +// Allegro MIDI structure, the divisions, and a flag whether to compress. +// +// Returns 0 if successful, otherwise an error code (see mmus2mid.h). +// +int mmus2mid(const UBYTE *mus, MIDI *mididata, UWORD division, int nocomp) +{ + UWORD TrackCnt = 0; + UBYTE evt, MUSchannel, MIDIchannel, MIDItrack=0, NewEvent; + int i, event, data; + const UBYTE *musptr; + size_t muslen; + static MUSheader MUSh; + UBYTE MIDIchan2track[MIDI_TRACKS]; // killough 10/7/98: fix too small array + int MUS2MIDchannel[MIDI_TRACKS]; // killough 10/7/98: fix too small array + + // copy the MUS header from the MUS buffer to the MUSh header structure + + memcpy(&MUSh,mus,sizeof(MUSheader)); + MUSh.ScoreLength = doom_wtohs(MUSh.ScoreLength); + MUSh.ScoreStart = doom_wtohs(MUSh.ScoreStart); + MUSh.channels = doom_wtohs(MUSh.channels); + MUSh.SecChannels = doom_wtohs(MUSh.SecChannels); + MUSh.InstrCnt = doom_wtohs(MUSh.InstrCnt); + + // check some things and set length of MUS buffer from internal data + + if (!(muslen = MUSh.ScoreLength + MUSh.ScoreStart)) + return MUSDATAMT; // MUS file empty + + if (MUSh.channels > 15) // MUSchannels + drum channel > 16 + return TOOMCHAN ; + + musptr = mus+MUSh.ScoreStart; // init musptr to start of score + + for (i = 0; i < MIDI_TRACKS; i++) // init the track structure's tracks + { + MUS2MIDchannel[i] = -1; // flag for channel not used yet + track[i].velocity = 64; + track[i].deltaT = 0; + track[i].lastEvt = 0; + //free(mididata->track[i].data);//jff 3/5/98 remove old allocations + mididata->track[i].data=NULL; + track[i].alloced = 0; + mididata->track[i].len = 0; + } + + if (!division) + division = 70; + + // allocate the first track which is a special tempo/key track + // note multiple tracks means midi format 1 + + // set the divisions (ticks per quarter note) + mididata->divisions = division; + + // allocate for midi tempo/key track, allow for end of track + if (!(mididata->track[0].data = + realloc(mididata->track[0].data,sizeof(midikey)+sizeof(miditempo)+4))) + return MEMALLOC; + + // key C major + memcpy(mididata->track[0].data,midikey,sizeof(midikey)); + // tempo uS/qnote + memcpy(mididata->track[0].data+sizeof(midikey),miditempo,sizeof(miditempo)); + mididata->track[0].len = sizeof(midikey)+sizeof(miditempo); + + TrackCnt++; // music tracks start at 1 + + // process the MUS events in the MUS buffer + + do + { + // get a mus event, decode its type and channel fields + + event = *musptr++; + if ((evt = event_type(event)) == SCORE_END) //jff 1/23/98 use symbol + break; // if end of score event, leave + MUSchannel = channel(event); + + // if this channel not initialized, do so + + if (MUS2MIDchannel[MUSchannel] == -1) + { + // set MIDIchannel and MIDItrack + + MIDIchannel = MUS2MIDchannel[MUSchannel] = + (MUSchannel == 15 ? 9 : FirstChannelAvailable(MUS2MIDchannel)); + MIDItrack = MIDIchan2track[MIDIchannel] = (UBYTE)TrackCnt++; + } + else // channel already allocated as a track, use those values + { + MIDIchannel = MUS2MIDchannel[MUSchannel]; + MIDItrack = MIDIchan2track[MIDIchannel]; + } + + if (TWriteVarLen(mididata, MIDItrack, track[MIDItrack].deltaT)) + return MEMALLOC; + track[MIDItrack].deltaT = 0; + + switch(evt) + { + case RELEASE_NOTE: + // killough 10/7/98: Fix noise problems by not allowing compression + if (!(NewEvent=MidiEvent(mididata,0x90,MIDIchannel,MIDItrack,1))) + return MEMALLOC; + + data = *musptr++; + if (TWriteByte(mididata, MIDItrack, (UBYTE)(data & 0x7F))) + return MEMALLOC; + if (TWriteByte(mididata, MIDItrack, 0)) + return MEMALLOC; + break; + + case PLAY_NOTE: + if (!(NewEvent=MidiEvent(mididata,0x90,MIDIchannel,MIDItrack,nocomp))) + return MEMALLOC; + + data = *musptr++; + if (TWriteByte(mididata, MIDItrack, (UBYTE)(data & 0x7F))) + return MEMALLOC; + if( data & 0x80 ) + track[MIDItrack].velocity = (*musptr++) & 0x7f; + if (TWriteByte(mididata, MIDItrack, track[MIDItrack].velocity)) + return MEMALLOC; + break; + + case BEND_NOTE: + if (!(NewEvent=MidiEvent(mididata,0xE0,MIDIchannel,MIDItrack,nocomp))) + return MEMALLOC; + + data = *musptr++; + if (TWriteByte(mididata, MIDItrack, (UBYTE)((data & 1) << 6))) + return MEMALLOC; + if (TWriteByte(mididata, MIDItrack, (UBYTE)(data >> 1))) + return MEMALLOC; + break; + + case SYS_EVENT: + if (!(NewEvent=MidiEvent(mididata,0xB0,MIDIchannel,MIDItrack,nocomp))) + return MEMALLOC; + + data = *musptr++; + if (data<10 || data>14) + return BADSYSEVT; + + if (TWriteByte(mididata, MIDItrack, MUS2MIDcontrol[data])) + return MEMALLOC; + if (data == 12) + { + if (TWriteByte(mididata, MIDItrack, (UBYTE)(MUSh.channels+1))) + return MEMALLOC; + } + else + if (TWriteByte(mididata, MIDItrack, 0)) + return MEMALLOC; + break; + + case CNTL_CHANGE: + data = *musptr++; + if (data>9) + return BADCTLCHG; + + if (data) + { + if (!(NewEvent=MidiEvent(mididata,0xB0,MIDIchannel,MIDItrack,nocomp))) + return MEMALLOC; + + if (TWriteByte(mididata, MIDItrack, MUS2MIDcontrol[data])) + return MEMALLOC; + } + else + { + if (!(NewEvent=MidiEvent(mididata,0xC0,MIDIchannel,MIDItrack,nocomp))) + return MEMALLOC; + } + data = *musptr++; + if (TWriteByte(mididata, MIDItrack, (UBYTE)(data & 0x7F))) + return MEMALLOC; + break; + + case UNKNOWN_EVENT1: // mus events 5 and 7 + case UNKNOWN_EVENT2: // meaning not known + return BADMUSCTL; + + case SCORE_END: + break; + + default: + return BADMUSCTL; // exit with error + } + if (last(event)) + { + ULONG DeltaTime = ReadTime(&musptr); // killough 10/7/98: make local + for (i = 0;i < MIDI_TRACKS; i++) //jff 3/13/98 update all tracks + track[i].deltaT += DeltaTime; //whether allocated yet or not + } + + } + while ((evt != SCORE_END) && ((size_t)(musptr-mus) < muslen)); + + if (evt!=SCORE_END) + return MUSDATACOR; + + // Now add an end of track to each mididata track, correct allocation + + for (i = 0; i < MIDI_TRACKS; i++) + if (mididata->track[i].len) + { // killough 10/7/98: simplify code + if (TWriteByte(mididata, i, 0x00) || // midi end of track code + TWriteByte(mididata, i, 0xFF) || + TWriteByte(mididata, i, 0x2F) || + TWriteByte(mididata, i, 0x00)) + return MEMALLOC; + + // jff 1/23/98 fix failure to set data NULL, len 0 for unused tracks + // shorten allocation to proper length (important for Allegro) + if (!(mididata->track[i].data = + realloc(mididata->track[i].data,mididata->track[i].len))) + return MEMALLOC; + } + else + { + free(mididata->track[i].data); + mididata->track[i].data = NULL; + } + + return 0; +} + +void free_mididata(MIDI *mid) +{ + int i; + + for (i = 0; i < MIDI_TRACKS; i++) + if (mid->track[i].data) + free(mid->track[i].data); +} + +// +// ReadLength() +// +// Reads the length of a chunk in a midi buffer, advancing the pointer +// 4 bytes, bigendian +// +// Passed a pointer to the pointer to a MIDI buffer +// Returns the chunk length at the pointer position +// +static size_t ReadLength(UBYTE **mid) +{ + UBYTE *midptr = *mid; + + size_t length = (*midptr++)<<24; + length += (*midptr++)<<16; + length += (*midptr++)<<8; + length += *midptr++; + *mid = midptr; + return length; +} + +// +// MidiToMIDI() +// +// Convert an in-memory copy of a MIDI format 0 or 1 file to +// an Allegro MIDI structure, that is valid or has been zeroed +// +// Passed a pointer to a memory buffer with MIDI format music in it and a +// pointer to an Allegro MIDI structure. +// +// Returns 0 if successful, BADMIDHDR if the buffer is not MIDI format +// +int MidiToMIDI(UBYTE *mid,MIDI *mididata) +{ + int i; + int ntracks; + + // read the midi header + + if (memcmp(mid,midihdr,4)) + return BADMIDHDR; + + mididata->divisions = (mid[12]<<8)+mid[13]; + ntracks = (mid[10]<<8)+mid[11]; + + if (ntracks>=MIDI_TRACKS) + return BADMIDHDR; + + mid += 4; + { // killough 10/7/98: fix mid from being modified twice before sequence pt. + size_t t = ReadLength(&mid); // seek past header + mid += t; + } + + // now read each track + + for (i=0;itrack[i].len = ReadLength(&mid); // get length, move mid past it + + // read a track + mididata->track[i].data = realloc(mididata->track[i].data,mididata->track[i].len); + memcpy(mididata->track[i].data,mid,mididata->track[i].len); + mid += mididata->track[i].len; + } + for (;itrack[i].len) + { + free(mididata->track[i].data); + mididata->track[i].data = NULL; + mididata->track[i].len = 0; + } + return 0; +} + +//#ifdef STANDALONE /* this code unused by BOOM provided for future portability */ +// /* it also provides a MUS to MID file converter*/ +// proff: I moved this down, because I need MIDItoMidi + +static void TWriteLength(UBYTE **midiptr,ULONG length); + + + +// +// TWriteLength() +// +// Write the length of a MIDI chunk to a midi buffer. The length is four +// bytes and is written byte-reversed for bigendian. The pointer to the +// midi buffer is advanced. +// +// Passed a pointer to the pointer to a midi buffer, and the length to write +// Returns nothing +// +static void TWriteLength(UBYTE **midiptr,ULONG length) +{ +// proff: Added typecast to avoid warning + *(*midiptr)++ = (unsigned char)((length>>24)&0xff); + *(*midiptr)++ = (unsigned char)((length>>16)&0xff); + *(*midiptr)++ = (unsigned char)((length>>8)&0xff); + *(*midiptr)++ = (unsigned char)((length)&0xff); +} + +// +// MIDIToMidi() +// +// This routine converts an Allegro MIDI structure to a midi 1 format file +// in memory. It is used to support memory MUS -> MIDI conversion +// +// Passed a pointer to an Allegro MIDI structure, a pointer to a pointer to +// a buffer containing midi data, and a pointer to a length return. +// Returns 0 if successful, MEMALLOC if a memory allocation error occurs +// +int MIDIToMidi(MIDI *mididata,UBYTE **mid,int *midlen) +{ + size_t total; + int i,ntrks; + UBYTE *midiptr; + + // calculate how long the mid buffer must be, and allocate + + total = sizeof(midihdr); + for (i=0,ntrks=0;itrack[i].len) + { + total += 8 + mididata->track[i].len; // Track hdr + track length + ntrks++; + } + if ((*mid = malloc(total))==NULL) + return MEMALLOC; + + + // fill in number of tracks and bigendian divisions (ticks/qnote) + + midihdr[10] = 0; + midihdr[11] = (UBYTE)ntrks; // set number of tracks in header + midihdr[12] = (mididata->divisions>>8) & 0x7f; + midihdr[13] = (mididata->divisions) & 0xff; + + // write the midi header + + midiptr = *mid; + memcpy(midiptr,midihdr,sizeof(midihdr)); + midiptr += sizeof(midihdr); + + // write the tracks + + for (i=0;itrack[i].len) + { + memcpy(midiptr,trackhdr,sizeof(trackhdr)); // header + midiptr += sizeof(trackhdr); + TWriteLength(&midiptr,mididata->track[i].len); // track length + // data + memcpy(midiptr,mididata->track[i].data,mididata->track[i].len); + midiptr += mididata->track[i].len; + } + } + + // return length information + + *midlen = midiptr - *mid; + + return 0; +} + +#ifdef STANDALONE /* this code unused by BOOM provided for future portability */ + /* it also provides a MUS to MID file converter*/ +// proff: I moved this down, because I need MIDItoMidi + +// +// main() +// +// Main routine that will convert a globbed set of MUS files to the +// correspondingly named MID files using mmus2mid(). Only compiled +// if the STANDALONE symbol is defined. +// +// Passed the command line arguments, returns 0 if successful +// +int main(int argc,char **argv) +{ + FILE *musst,*midst; + char musfile[FILENAME_MAX],midfile[FILENAME_MAX]; + MUSheader MUSh; + UBYTE *mus,*mid; + static MIDI mididata; + int err,midlen; + char *p,*q; + int i; + + if (argc<2) + { + //jff 8/3/98 use logical output routine + lprintf(LO_INFO,"Usage: MMUS2MID musfile[.MUS]\n"); + lprintf(LO_INFO,"writes musfile.MID as output\n"); + lprintf(LO_INFO,"musfile may contain wildcards\n"); + exit(1); + } + + for (i=1;idirection) + { + case 0: + // If ceiling in stasis, do nothing + break; + + case 1: + // Ceiling is moving up + res = T_MovePlane + ( + ceiling->sector, + ceiling->speed, + ceiling->topheight, + false, + 1, + ceiling->direction + ); + + // if not a silent crusher, make moving sound + if (!(leveltime&7)) + { + switch(ceiling->type) + { + case silentCrushAndRaise: + case genSilentCrusher: + break; + default: + S_StartSound((mobj_t *)&ceiling->sector->soundorg,sfx_stnmov); + break; + } + } + + // handle reaching destination height + if (res == pastdest) + { + switch(ceiling->type) + { + // plain movers are just removed + case raiseToHighest: + case genCeiling: + P_RemoveActiveCeiling(ceiling); + break; + + // movers with texture change, change the texture then get removed + case genCeilingChgT: + case genCeilingChg0: + ceiling->sector->special = ceiling->newspecial; + //jff 3/14/98 transfer old special field as well + ceiling->sector->oldspecial = ceiling->oldspecial; + case genCeilingChg: + ceiling->sector->ceilingpic = ceiling->texture; + P_RemoveActiveCeiling(ceiling); + break; + + // crushers reverse direction at the top + case silentCrushAndRaise: + S_StartSound((mobj_t *)&ceiling->sector->soundorg,sfx_pstop); + case genSilentCrusher: + case genCrusher: + case fastCrushAndRaise: + case crushAndRaise: + ceiling->direction = -1; + break; + + default: + break; + } + } + break; + + case -1: + // Ceiling moving down + res = T_MovePlane + ( + ceiling->sector, + ceiling->speed, + ceiling->bottomheight, + ceiling->crush, + 1, + ceiling->direction + ); + + // if not silent crusher type make moving sound + if (!(leveltime&7)) + { + switch(ceiling->type) + { + case silentCrushAndRaise: + case genSilentCrusher: + break; + default: + S_StartSound((mobj_t *)&ceiling->sector->soundorg,sfx_stnmov); + } + } + + // handle reaching destination height + if (res == pastdest) + { + switch(ceiling->type) + { + // 02/09/98 jff change slow crushers' speed back to normal + // start back up + case genSilentCrusher: + case genCrusher: + if (ceiling->oldspeedspeed = ceiling->oldspeed; + ceiling->direction = 1; //jff 2/22/98 make it go back up! + break; + + // make platform stop at bottom of all crusher strokes + // except generalized ones, reset speed, start back up + case silentCrushAndRaise: + S_StartSound((mobj_t *)&ceiling->sector->soundorg,sfx_pstop); + case crushAndRaise: + ceiling->speed = CEILSPEED; + case fastCrushAndRaise: + ceiling->direction = 1; + break; + + // in the case of ceiling mover/changer, change the texture + // then remove the active ceiling + case genCeilingChgT: + case genCeilingChg0: + ceiling->sector->special = ceiling->newspecial; + //jff add to fix bug in special transfers from changes + ceiling->sector->oldspecial = ceiling->oldspecial; + case genCeilingChg: + ceiling->sector->ceilingpic = ceiling->texture; + P_RemoveActiveCeiling(ceiling); + break; + + // all other case, just remove the active ceiling + case lowerAndCrush: + case lowerToFloor: + case lowerToLowest: + case lowerToMaxFloor: + case genCeiling: + P_RemoveActiveCeiling(ceiling); + break; + + default: + break; + } + } + else // ( res != pastdest ) + { + // handle the crusher encountering an obstacle + if (res == crushed) + { + switch(ceiling->type) + { + //jff 02/08/98 slow down slow crushers on obstacle + case genCrusher: + case genSilentCrusher: + if (ceiling->oldspeed < CEILSPEED*3) + ceiling->speed = CEILSPEED / 8; + break; + case silentCrushAndRaise: + case crushAndRaise: + case lowerAndCrush: + ceiling->speed = CEILSPEED / 8; + break; + + default: + break; + } + } + } + break; + } +} + + +// +// EV_DoCeiling +// +// Move a ceiling up/down or start a crusher +// +// Passed the linedef activating the function and the type of function desired +// returns true if a thinker started +// +int EV_DoCeiling +( line_t* line, + ceiling_e type ) +{ + int secnum; + int rtn; + sector_t* sec; + ceiling_t* ceiling; + + secnum = -1; + rtn = 0; + + // Reactivate in-stasis ceilings...for certain types. + // This restarts a crusher after it has been stopped + switch(type) + { + case fastCrushAndRaise: + case silentCrushAndRaise: + case crushAndRaise: + //jff 4/5/98 return if activated + rtn = P_ActivateInStasisCeiling(line); + default: + break; + } + + // affects all sectors with the same tag as the linedef + while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) + { + sec = §ors[secnum]; + + // if ceiling already moving, don't start a second function on it + if (P_SectorActive(ceiling_special,sec)) //jff 2/22/98 + continue; + + // create a new ceiling thinker + rtn = 1; + ceiling = Z_Malloc (sizeof(*ceiling), PU_LEVSPEC, 0); + memset(ceiling, 0, sizeof(*ceiling)); + P_AddThinker (&ceiling->thinker); + sec->ceilingdata = ceiling; //jff 2/22/98 + ceiling->thinker.function = T_MoveCeiling; + ceiling->sector = sec; + ceiling->crush = false; + + // setup ceiling structure according to type of function + switch(type) + { + case fastCrushAndRaise: + ceiling->crush = true; + ceiling->topheight = sec->ceilingheight; + ceiling->bottomheight = sec->floorheight + (8*FRACUNIT); + ceiling->direction = -1; + ceiling->speed = CEILSPEED * 2; + break; + + case silentCrushAndRaise: + case crushAndRaise: + ceiling->crush = true; + ceiling->topheight = sec->ceilingheight; + case lowerAndCrush: + case lowerToFloor: + ceiling->bottomheight = sec->floorheight; + if (type != lowerToFloor) + ceiling->bottomheight += 8*FRACUNIT; + ceiling->direction = -1; + ceiling->speed = CEILSPEED; + break; + + case raiseToHighest: + ceiling->topheight = P_FindHighestCeilingSurrounding(sec); + ceiling->direction = 1; + ceiling->speed = CEILSPEED; + break; + + case lowerToLowest: + ceiling->bottomheight = P_FindLowestCeilingSurrounding(sec); + ceiling->direction = -1; + ceiling->speed = CEILSPEED; + break; + + case lowerToMaxFloor: + ceiling->bottomheight = P_FindHighestFloorSurrounding(sec); + ceiling->direction = -1; + ceiling->speed = CEILSPEED; + break; + + default: + break; + } + + // add the ceiling to the active list + ceiling->tag = sec->tag; + ceiling->type = type; + P_AddActiveCeiling(ceiling); + } + return rtn; +} + +////////////////////////////////////////////////////////////////////// +// +// Active ceiling list primitives +// +///////////////////////////////////////////////////////////////////// + +// jff 2/22/98 - modified Lee's plat code to work for ceilings +// +// The following were all rewritten by Lee Killough +// to use the new structure which places no limits +// on active ceilings. It also avoids spending as much +// time searching for active ceilings. Previously a +// fixed-size array was used, with NULL indicating +// empty entries, while now a doubly-linked list +// is used. + +// +// P_ActivateInStasisCeiling() +// +// Reactivates all stopped crushers with the right tag +// +// Passed the line reactivating the crusher +// Returns true if a ceiling reactivated +// +//jff 4/5/98 return if activated +int P_ActivateInStasisCeiling(line_t *line) +{ + ceilinglist_t *cl; + int rtn=0; + + for (cl=activeceilings; cl; cl=cl->next) + { + ceiling_t *ceiling = cl->ceiling; + if (ceiling->tag == line->tag && ceiling->direction == 0) + { + ceiling->direction = ceiling->olddirection; + ceiling->thinker.function = T_MoveCeiling; + //jff 4/5/98 return if activated + rtn=1; + } + } + return rtn; +} + +// +// EV_CeilingCrushStop() +// +// Stops all active ceilings with the right tag +// +// Passed the linedef stopping the ceilings +// Returns true if a ceiling put in stasis +// +int EV_CeilingCrushStop(line_t* line) +{ + int rtn=0; + + ceilinglist_t *cl; + for (cl=activeceilings; cl; cl=cl->next) + { + ceiling_t *ceiling = cl->ceiling; + if (ceiling->direction != 0 && ceiling->tag == line->tag) + { + ceiling->olddirection = ceiling->direction; + ceiling->direction = 0; + ceiling->thinker.function = NULL; + rtn=1; + } + } + return rtn; +} + +// +// P_AddActiveCeiling() +// +// Adds a ceiling to the head of the list of active ceilings +// +// Passed the ceiling motion structure +// Returns nothing +// +void P_AddActiveCeiling(ceiling_t* ceiling) +{ + ceilinglist_t *list = malloc(sizeof *list); + list->ceiling = ceiling; + ceiling->list = list; + if ((list->next = activeceilings)) + list->next->prev = &list->next; + list->prev = &activeceilings; + activeceilings = list; +} + +// +// P_RemoveActiveCeiling() +// +// Removes a ceiling from the list of active ceilings +// +// Passed the ceiling motion structure +// Returns nothing +// +void P_RemoveActiveCeiling(ceiling_t* ceiling) +{ + ceilinglist_t *list = ceiling->list; + ceiling->sector->ceilingdata = NULL; //jff 2/22/98 + P_RemoveThinker(&ceiling->thinker); + if ((*list->prev = list->next)) + list->next->prev = list->prev; + free(list); +} + +// +// P_RemoveAllActiveCeilings() +// +// Removes all ceilings from the active ceiling list +// +// Passed nothing, returns nothing +// +void P_RemoveAllActiveCeilings(void) +{ + while (activeceilings) + { + ceilinglist_t *next = activeceilings->next; + free(activeceilings); + activeceilings = next; + } +} diff --git a/common/prboom/p_checksum.c b/common/prboom/p_checksum.c new file mode 100755 index 0000000..5fb6101 --- /dev/null +++ b/common/prboom/p_checksum.c @@ -0,0 +1,100 @@ +#include +#include +#include +#include /* exit(), atexit() */ + +#include "p_checksum.h" +#include "md5.h" +#include "doomstat.h" /* players{,ingame} */ +#include "lprintf.h" + +/* forward decls */ +static void p_checksum_cleanup(void); +void checksum_gamestate(int tic); + +/* vars */ +static void p_checksum_nop(int tic){} /* do nothing */ +void (*P_Checksum)(int) = p_checksum_nop; + +/* + * P_RecordChecksum + * sets up the file and function pointers to write out checksum data + */ +static FILE *outfile = NULL; +static struct MD5Context md5global; + +void P_RecordChecksum(const char *file) { + size_t fnsize; + + fnsize = strlen(file); + + /* special case: write to stdout */ + if(0 == strncmp("-",file,MIN(1,fnsize))) + outfile = stdout; + else { + outfile = fopen(file,"wb"); + if(NULL == outfile) { + I_Error("cannot open %s for writing checksum:\n%s\n", + file, strerror(errno)); + } + atexit(p_checksum_cleanup); + } + + MD5Init(&md5global); + + P_Checksum = checksum_gamestate; +} + +void P_ChecksumFinal(void) { + int i; + unsigned char digest[16]; + + if (!outfile) + return; + + MD5Final(digest, &md5global); + fprintf(outfile, "final: "); + for (i=0; i<16; i++) + fprintf(outfile,"%x", digest[i]); + fprintf(outfile, "\n"); + MD5Init(&md5global); +} + +static void p_checksum_cleanup(void) { + if (outfile && (outfile != stdout)) + fclose(outfile); +} + +/* + * runs on each tic when recording checksums + */ +void checksum_gamestate(int tic) { + int i; + struct MD5Context md5ctx; + unsigned char digest[16]; + char buffer[2048]; + + fprintf(outfile,"%6d, ", tic); + + /* based on "ArchivePlayers" */ + MD5Init(&md5ctx); + for (i=0 ; idirection) + { + case 0: + // Door is waiting + if (!--door->topcountdown) // downcount and check + { + switch(door->type) + { + case blazeRaise: + case genBlazeRaise: + door->direction = -1; // time to go back down + S_StartSound((mobj_t *)&door->sector->soundorg,sfx_bdcls); + break; + + case normal: + case genRaise: + door->direction = -1; // time to go back down + S_StartSound((mobj_t *)&door->sector->soundorg,sfx_dorcls); + break; + + case close30ThenOpen: + case genCdO: + door->direction = 1; // time to go back up + S_StartSound((mobj_t *)&door->sector->soundorg,sfx_doropn); + break; + + case genBlazeCdO: + door->direction = 1; // time to go back up + S_StartSound((mobj_t *)&door->sector->soundorg,sfx_bdopn); + break; + + default: + break; + } + } + break; + + case 2: + // Special case for sector type door that opens in 5 mins + if (!--door->topcountdown) // 5 minutes up? + { + switch(door->type) + { + case raiseIn5Mins: + door->direction = 1; // time to raise then + door->type = normal; // door acts just like normal 1 DR door now + S_StartSound((mobj_t *)&door->sector->soundorg,sfx_doropn); + break; + + default: + break; + } + } + break; + + case -1: + // Door is moving down + res = T_MovePlane + ( + door->sector, + door->speed, + door->sector->floorheight, + false, + 1, + door->direction + ); + + /* killough 10/98: implement gradual lighting effects */ + // e6y: "Tagged doors don't trigger special lighting" handled wrong + // http://sourceforge.net/tracker/index.php?func=detail&aid=1411400&group_id=148658&atid=772943 + // Old code: if (door->lighttag && door->topheight - door->sector->floorheight) + if (door->lighttag && door->topheight - door->sector->floorheight && compatibility_level >= mbf_compatibility) + EV_LightTurnOnPartway(door->line, + FixedDiv(door->sector->ceilingheight - + door->sector->floorheight, + door->topheight - + door->sector->floorheight)); + + // handle door reaching bottom + if (res == pastdest) + { + switch(door->type) + { + // regular open and close doors are all done, remove them + case blazeRaise: + case blazeClose: + case genBlazeRaise: + case genBlazeClose: + door->sector->ceilingdata = NULL; //jff 2/22/98 + P_RemoveThinker (&door->thinker); // unlink and free + // killough 4/15/98: remove double-closing sound of blazing doors + if (comp[comp_blazing]) + S_StartSound((mobj_t *)&door->sector->soundorg,sfx_bdcls); + break; + + case normal: + case close: + case genRaise: + case genClose: + door->sector->ceilingdata = NULL; //jff 2/22/98 + P_RemoveThinker (&door->thinker); // unlink and free + break; + + // close then open doors start waiting + case close30ThenOpen: + door->direction = 0; + door->topcountdown = TICRATE*30; + break; + + case genCdO: + case genBlazeCdO: + door->direction = 0; + door->topcountdown = door->topwait; // jff 5/8/98 insert delay + break; + + default: + break; + } + // e6y: "Tagged doors don't trigger special lighting" handled wrong + // http://sourceforge.net/tracker/index.php?func=detail&aid=1411400&group_id=148658&atid=772943 + if (door->lighttag && door->topheight - door->sector->floorheight && compatibility_level < mbf_compatibility) + EV_LightTurnOnPartway(door->line,0); + } + /* jff 1/31/98 turn lighting off in tagged sectors of manual doors + * killough 10/98: replaced with gradual lighting code + */ + else if (res == crushed) // handle door meeting obstruction on way down + { + switch(door->type) + { + case genClose: + case genBlazeClose: + case blazeClose: + case close: // Close types do not bounce, merely wait + break; + + case blazeRaise: + case genBlazeRaise: + door->direction = 1; + if (!comp[comp_blazing]) { + S_StartSound((mobj_t *)&door->sector->soundorg,sfx_bdopn); + break; + } + + default: // other types bounce off the obstruction + door->direction = 1; + S_StartSound((mobj_t *)&door->sector->soundorg,sfx_doropn); + break; + } + } + break; + + case 1: + // Door is moving up + res = T_MovePlane + ( + door->sector, + door->speed, + door->topheight, + false, + 1, + door->direction + ); + + /* killough 10/98: implement gradual lighting effects */ + // e6y: "Tagged doors don't trigger special lighting" handled wrong + // http://sourceforge.net/tracker/index.php?func=detail&aid=1411400&group_id=148658&atid=772943 + // Old code: if (door->lighttag && door->topheight - door->sector->floorheight) + if (door->lighttag && door->topheight - door->sector->floorheight && compatibility_level >= mbf_compatibility) + EV_LightTurnOnPartway(door->line, + FixedDiv(door->sector->ceilingheight - + door->sector->floorheight, + door->topheight - + door->sector->floorheight)); + + // handle door reaching the top + if (res == pastdest) + { + switch(door->type) + { + case blazeRaise: // regular open/close doors start waiting + case normal: + case genRaise: + case genBlazeRaise: + door->direction = 0; // wait at top with delay + door->topcountdown = door->topwait; + break; + + case close30ThenOpen: // close and close/open doors are done + case blazeOpen: + case open: + case genBlazeOpen: + case genOpen: + case genCdO: + case genBlazeCdO: + door->sector->ceilingdata = NULL; //jff 2/22/98 + P_RemoveThinker (&door->thinker); // unlink and free + break; + + default: + break; + } + + /* jff 1/31/98 turn lighting on in tagged sectors of manual doors + * killough 10/98: replaced with gradual lighting code */ + // e6y: "Tagged doors don't trigger special lighting" handled wrong + // http://sourceforge.net/tracker/index.php?func=detail&aid=1411400&group_id=148658&atid=772943 + if (door->lighttag && door->topheight - door->sector->floorheight && compatibility_level < mbf_compatibility) + EV_LightTurnOnPartway(door->line,FRACUNIT); + } + break; + } +} + +/////////////////////////////////////////////////////////////// +// +// Door linedef handlers +// +/////////////////////////////////////////////////////////////// + +// +// EV_DoLockedDoor +// +// Handle opening a tagged locked door +// +// Passed the line activating the door, the type of door, +// and the thing that activated the line +// Returns true if a thinker created +// +int EV_DoLockedDoor +( line_t* line, + vldoor_e type, + mobj_t* thing ) +{ + player_t* p; + + // only players can open locked doors + p = thing->player; + if (!p) + return 0; + + // check type of linedef, and if key is possessed to open it + switch(line->special) + { + case 99: // Blue Lock + case 133: + if (!p->cards[it_bluecard] && !p->cards[it_blueskull]) + { + p->message = s_PD_BLUEO; // Ty 03/27/98 - externalized + S_StartSound(p->mo,sfx_oof); // killough 3/20/98 + return 0; + } + break; + + case 134: // Red Lock + case 135: + if (!p->cards[it_redcard] && !p->cards[it_redskull]) + { + p->message = s_PD_REDO; // Ty 03/27/98 - externalized + S_StartSound(p->mo,sfx_oof); // killough 3/20/98 + return 0; + } + break; + + case 136: // Yellow Lock + case 137: + if (!p->cards[it_yellowcard] && !p->cards[it_yellowskull]) + { + p->message = s_PD_YELLOWO; // Ty 03/27/98 - externalized + S_StartSound(p->mo,sfx_oof); // killough 3/20/98 + return 0; + } + break; + } + + // got the key, so open the door + return EV_DoDoor(line,type); +} + + +// +// EV_DoDoor +// +// Handle opening a tagged door +// +// Passed the line activating the door and the type of door +// Returns true if a thinker created +// +int EV_DoDoor +( line_t* line, + vldoor_e type ) +{ + int secnum,rtn; + sector_t* sec; + vldoor_t* door; + + secnum = -1; + rtn = 0; + + // open all doors with the same tag as the activating line + while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) + { + sec = §ors[secnum]; + // if the ceiling already moving, don't start the door action + if (P_SectorActive(ceiling_special,sec)) //jff 2/22/98 + continue; + + // new door thinker + rtn = 1; + door = Z_Malloc (sizeof(*door), PU_LEVSPEC, 0); + memset(door, 0, sizeof(*door)); + P_AddThinker (&door->thinker); + sec->ceilingdata = door; //jff 2/22/98 + + door->thinker.function = T_VerticalDoor; + door->sector = sec; + door->type = type; + door->topwait = VDOORWAIT; + door->speed = VDOORSPEED; + door->line = line; // jff 1/31/98 remember line that triggered us + door->lighttag = 0; /* killough 10/98: no light effects with tagged doors */ + + // setup door parameters according to type of door + switch(type) + { + case blazeClose: + door->topheight = P_FindLowestCeilingSurrounding(sec); + door->topheight -= 4*FRACUNIT; + door->direction = -1; + door->speed = VDOORSPEED * 4; + S_StartSound((mobj_t *)&door->sector->soundorg,sfx_bdcls); + break; + + case close: + door->topheight = P_FindLowestCeilingSurrounding(sec); + door->topheight -= 4*FRACUNIT; + door->direction = -1; + S_StartSound((mobj_t *)&door->sector->soundorg,sfx_dorcls); + break; + + case close30ThenOpen: + door->topheight = sec->ceilingheight; + door->direction = -1; + S_StartSound((mobj_t *)&door->sector->soundorg,sfx_dorcls); + break; + + case blazeRaise: + case blazeOpen: + door->direction = 1; + door->topheight = P_FindLowestCeilingSurrounding(sec); + door->topheight -= 4*FRACUNIT; + door->speed = VDOORSPEED * 4; + if (door->topheight != sec->ceilingheight) + S_StartSound((mobj_t *)&door->sector->soundorg,sfx_bdopn); + break; + + case normal: + case open: + door->direction = 1; + door->topheight = P_FindLowestCeilingSurrounding(sec); + door->topheight -= 4*FRACUNIT; + if (door->topheight != sec->ceilingheight) + S_StartSound((mobj_t *)&door->sector->soundorg,sfx_doropn); + break; + + default: + break; + } + } + return rtn; +} + + +// +// EV_VerticalDoor +// +// Handle opening a door manually, no tag value +// +// Passed the line activating the door and the thing activating it +// Returns true if a thinker created +// +// jff 2/12/98 added int return value, fixed all returns +// +int EV_VerticalDoor +( line_t* line, + mobj_t* thing ) +{ + player_t* player; + int secnum; + sector_t* sec; + vldoor_t* door; + + // Check for locks + player = thing->player; + + switch(line->special) + { + case 26: // Blue Lock + case 32: + if ( !player ) + return 0; + if (!player->cards[it_bluecard] && !player->cards[it_blueskull]) + { + player->message = s_PD_BLUEK; // Ty 03/27/98 - externalized + S_StartSound(player->mo,sfx_oof); // killough 3/20/98 + return 0; + } + break; + + case 27: // Yellow Lock + case 34: + if ( !player ) + return 0; + if (!player->cards[it_yellowcard] && !player->cards[it_yellowskull]) + { + player->message = s_PD_YELLOWK; // Ty 03/27/98 - externalized + S_StartSound(player->mo,sfx_oof); // killough 3/20/98 + return 0; + } + break; + + case 28: // Red Lock + case 33: + if ( !player ) + return 0; + if (!player->cards[it_redcard] && !player->cards[it_redskull]) + { + player->message = s_PD_REDK; // Ty 03/27/98 - externalized + S_StartSound(player->mo,sfx_oof); // killough 3/20/98 + return 0; + } + break; + + default: + break; + } + + // if the wrong side of door is pushed, give oof sound + if (line->sidenum[1]==NO_INDEX) // killough + { + S_StartSound(player->mo,sfx_oof); // killough 3/20/98 + return 0; + } + + // get the sector on the second side of activating linedef + sec = sides[line->sidenum[1]].sector; + secnum = sec-sectors; + + /* if door already has a thinker, use it + * cph 2001/04/05 - + * Ok, this is a disaster area. We're assuming that sec->ceilingdata + * is a vldoor_t! What if this door is controlled by both DR lines + * and by switches? I don't know how to fix that. + * Secondly, original Doom didn't distinguish floor/lighting/ceiling + * actions, so we need to do the same in demo compatibility mode. + */ + door = sec->ceilingdata; + if (demo_compatibility) { + if (!door) door = sec->floordata; + if (!door) door = sec->lightingdata; + } + /* If this is a repeatable line, and the door is already moving, then we can just reverse the current action. Note that in prboom 2.3.0 I erroneously removed the if-this-is-repeatable check, hence the prboom_4_compatibility clause below (foolishly assumed that already moving implies repeatable - but it could be moving due to another switch, e.g. lv19-509) */ + if (door && + ((compatibility_level == prboom_4_compatibility) || + (line->special == 1) || (line->special == 117) || (line->special == 26) || (line->special == 27) || (line->special == 28) + ) + ) { + /* For old demos we have to emulate the old buggy behavior and + * mess up non-T_VerticalDoor actions. + */ + if (compatibility_level < prboom_4_compatibility || + door->thinker.function == T_VerticalDoor) { + /* cph - we are writing outval to door->direction iff it is non-zero */ + signed int outval = 0; + + /* An already moving repeatable door which is being re-pressed, or a + * monster is trying to open a closing door - so change direction + * DEMOSYNC: we only read door->direction now if it really is a door. + */ + if (door->thinker.function == T_VerticalDoor && door->direction == -1) { + outval = 1; /* go back up */ + } else if (player) { + outval = -1; /* go back down */ + } + + /* Write this to the thinker. In demo compatibility mode, we might be + * overwriting a field of a non-vldoor_t thinker - we need to add any + * other thinker types here if any demos depend on specific fields + * being corrupted by this. + */ + if (outval) { + if (door->thinker.function == T_VerticalDoor) { + door->direction = outval; + } else if (door->thinker.function == T_PlatRaise) { + plat_t* p = (plat_t*)door; + p->wait = outval; + } else { + lprintf(LO_DEBUG, "EV_VerticalDoor: unknown thinker.function in thinker corruption emulation"); + } + + return 1; + } + } + /* Either we're in prboom >=v2.3 and it's not a door, or it's a door but + * we're a monster and don't want to shut it; exit with no action. + */ + return 0; + } + + // emit proper sound + switch(line->special) + { + case 117: // blazing door raise + case 118: // blazing door open + S_StartSound((mobj_t *)&sec->soundorg,sfx_bdopn); + break; + + default: // normal or locked door sound + S_StartSound((mobj_t *)&sec->soundorg,sfx_doropn); + break; + } + + // new door thinker + door = Z_Malloc (sizeof(*door), PU_LEVSPEC, 0); + memset(door, 0, sizeof(*door)); + P_AddThinker (&door->thinker); + sec->ceilingdata = door; //jff 2/22/98 + door->thinker.function = T_VerticalDoor; + door->sector = sec; + door->direction = 1; + door->speed = VDOORSPEED; + door->topwait = VDOORWAIT; + door->line = line; // jff 1/31/98 remember line that triggered us + + /* killough 10/98: use gradual lighting changes if nonzero tag given */ + door->lighttag = comp[comp_doorlight] ? 0 : line->tag; + + // set the type of door from the activating linedef type + switch(line->special) + { + case 1: + case 26: + case 27: + case 28: + door->type = normal; + break; + + case 31: + case 32: + case 33: + case 34: + door->type = open; + line->special = 0; + break; + + case 117: // blazing door raise + door->type = blazeRaise; + door->speed = VDOORSPEED*4; + break; + case 118: // blazing door open + door->type = blazeOpen; + line->special = 0; + door->speed = VDOORSPEED*4; + break; + + default: + door->lighttag = 0; // killough 10/98 + break; + } + + // find the top and bottom of the movement range + door->topheight = P_FindLowestCeilingSurrounding(sec); + door->topheight -= 4*FRACUNIT; + return 1; +} + + +/////////////////////////////////////////////////////////////// +// +// Sector type door spawners +// +/////////////////////////////////////////////////////////////// + +// +// P_SpawnDoorCloseIn30() +// +// Spawn a door that closes after 30 seconds (called at level init) +// +// Passed the sector of the door, whose type specified the door action +// Returns nothing +// +void P_SpawnDoorCloseIn30 (sector_t* sec) +{ + vldoor_t* door; + + door = Z_Malloc ( sizeof(*door), PU_LEVSPEC, 0); + + memset(door, 0, sizeof(*door)); + P_AddThinker (&door->thinker); + + sec->ceilingdata = door; //jff 2/22/98 + sec->special = 0; + + door->thinker.function = T_VerticalDoor; + door->sector = sec; + door->direction = 0; + door->type = normal; + door->speed = VDOORSPEED; + door->topcountdown = 30 * 35; + door->line = NULL; // jff 1/31/98 remember line that triggered us + door->lighttag = 0; /* killough 10/98: no lighting changes */ +} + +// +// P_SpawnDoorRaiseIn5Mins() +// +// Spawn a door that opens after 5 minutes (called at level init) +// +// Passed the sector of the door, whose type specified the door action +// Returns nothing +// +void P_SpawnDoorRaiseIn5Mins +( sector_t* sec, + int secnum ) +{ + vldoor_t* door; + + door = Z_Malloc ( sizeof(*door), PU_LEVSPEC, 0); + + memset(door, 0, sizeof(*door)); + P_AddThinker (&door->thinker); + + sec->ceilingdata = door; //jff 2/22/98 + sec->special = 0; + + door->thinker.function = T_VerticalDoor; + door->sector = sec; + door->direction = 2; + door->type = raiseIn5Mins; + door->speed = VDOORSPEED; + door->topheight = P_FindLowestCeilingSurrounding(sec); + door->topheight -= 4*FRACUNIT; + door->topwait = VDOORWAIT; + door->topcountdown = 5 * 60 * 35; + door->line = NULL; // jff 1/31/98 remember line that triggered us + door->lighttag = 0; /* killough 10/98: no lighting changes */ +} diff --git a/common/prboom/p_enemy.c b/common/prboom/p_enemy.c new file mode 100755 index 0000000..b1f164b --- /dev/null +++ b/common/prboom/p_enemy.c @@ -0,0 +1,2584 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000,2002 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Enemy thinking, AI. + * Action Pointer Functions + * that are associated with states/frames. + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" +#include "m_random.h" +#include "r_main.h" +#include "p_maputl.h" +#include "p_map.h" +#include "p_setup.h" +#include "p_spec.h" +#include "s_sound.h" +#include "sounds.h" +#include "p_inter.h" +#include "g_game.h" +#include "p_enemy.h" +#include "p_tick.h" +#include "m_bbox.h" +#include "lprintf.h" + +static mobj_t *current_actor; + +typedef enum { + DI_EAST, + DI_NORTHEAST, + DI_NORTH, + DI_NORTHWEST, + DI_WEST, + DI_SOUTHWEST, + DI_SOUTH, + DI_SOUTHEAST, + DI_NODIR, + NUMDIRS +} dirtype_t; + +static void P_NewChaseDir(mobj_t *actor); +void P_ZBumpCheck(mobj_t *); // phares + +// +// ENEMY THINKING +// Enemies are allways spawned +// with targetplayer = -1, threshold = 0 +// Most monsters are spawned unaware of all players, +// but some can be made preaware +// + +// +// Called by P_NoiseAlert. +// Recursively traverse adjacent sectors, +// sound blocking lines cut off traversal. +// +// killough 5/5/98: reformatted, cleaned up + +static void P_RecursiveSound(sector_t *sec, int soundblocks, + mobj_t *soundtarget) +{ + int i; + + // wake up all monsters in this sector + if (sec->validcount == validcount && sec->soundtraversed <= soundblocks+1) + return; // already flooded + + sec->validcount = validcount; + sec->soundtraversed = soundblocks+1; + P_SetTarget(&sec->soundtarget, soundtarget); + + for (i=0; ilinecount; i++) + { + sector_t *other; + line_t *check = sec->lines[i]; + + if (!(check->flags & ML_TWOSIDED)) + continue; + + P_LineOpening(check); + + if (openrange <= 0) + continue; // closed door + + other=sides[check->sidenum[sides[check->sidenum[0]].sector==sec]].sector; + + if (!(check->flags & ML_SOUNDBLOCK)) + P_RecursiveSound(other, soundblocks, soundtarget); + else + if (!soundblocks) + P_RecursiveSound(other, 1, soundtarget); + } +} + +// +// P_NoiseAlert +// If a monster yells at a player, +// it will alert other monsters to the player. +// +void P_NoiseAlert(mobj_t *target, mobj_t *emitter) +{ + validcount++; + P_RecursiveSound(emitter->subsector->sector, 0, target); +} + +// +// P_CheckMeleeRange +// + +static boolean P_CheckMeleeRange(mobj_t *actor) +{ + mobj_t *pl = actor->target; + + return // killough 7/18/98: friendly monsters don't attack other friends + pl && !(actor->flags & pl->flags & MF_FRIEND) && + (P_AproxDistance(pl->x-actor->x, pl->y-actor->y) < + MELEERANGE - 20*FRACUNIT + pl->info->radius) && + P_CheckSight(actor, actor->target); +} + +// +// P_HitFriend() +// +// killough 12/98 +// This function tries to prevent shooting at friends + +static boolean P_HitFriend(mobj_t *actor) +{ + return actor->flags & MF_FRIEND && actor->target && + (P_AimLineAttack(actor, + R_PointToAngle2(actor->x, actor->y, + actor->target->x, actor->target->y), + P_AproxDistance(actor->x-actor->target->x, + actor->y-actor->target->y), 0), + linetarget) && linetarget != actor->target && + !((linetarget->flags ^ actor->flags) & MF_FRIEND); +} + +// +// P_CheckMissileRange +// +static boolean P_CheckMissileRange(mobj_t *actor) +{ + fixed_t dist; + + if (!P_CheckSight(actor, actor->target)) + return false; + + if (actor->flags & MF_JUSTHIT) + { // the target just hit the enemy, so fight back! + actor->flags &= ~MF_JUSTHIT; + + /* killough 7/18/98: no friendly fire at corpses + * killough 11/98: prevent too much infighting among friends + * cph - yikes, talk about fitting everything on one line... */ + + return + !(actor->flags & MF_FRIEND) || + (actor->target->health > 0 && + (!(actor->target->flags & MF_FRIEND) || + (actor->target->player ? + monster_infighting || P_Random(pr_defect) >128 : + !(actor->target->flags & MF_JUSTHIT) && P_Random(pr_defect) >128))); + } + + /* killough 7/18/98: friendly monsters don't attack other friendly + * monsters or players (except when attacked, and then only once) + */ + if (actor->flags & actor->target->flags & MF_FRIEND) + return false; + + if (actor->reactiontime) + return false; // do not attack yet + + // OPTIMIZE: get this from a global checksight + dist = P_AproxDistance ( actor->x-actor->target->x, + actor->y-actor->target->y) - 64*FRACUNIT; + + if (!actor->info->meleestate) + dist -= 128*FRACUNIT; // no melee attack, so fire more + + dist >>= FRACBITS; + + if (actor->type == MT_VILE) + if (dist > 14*64) + return false; // too far away + + + if (actor->type == MT_UNDEAD) + { + if (dist < 196) + return false; // close for fist attack + dist >>= 1; + } + + if (actor->type == MT_CYBORG || + actor->type == MT_SPIDER || + actor->type == MT_SKULL) + dist >>= 1; + + if (dist > 200) + dist = 200; + + if (actor->type == MT_CYBORG && dist > 160) + dist = 160; + + if (P_Random(pr_missrange) < dist) + return false; + + if (P_HitFriend(actor)) + return false; + + return true; +} + +/* + * P_IsOnLift + * + * killough 9/9/98: + * + * Returns true if the object is on a lift. Used for AI, + * since it may indicate the need for crowded conditions, + * or that a monster should stay on the lift for a while + * while it goes up or down. + */ + +static boolean P_IsOnLift(const mobj_t *actor) +{ + const sector_t *sec = actor->subsector->sector; + line_t line; + int l; + + // Short-circuit: it's on a lift which is active. + if (sec->floordata && ((thinker_t *) sec->floordata)->function==T_PlatRaise) + return true; + + // Check to see if it's in a sector which can be activated as a lift. + if ((line.tag = sec->tag)) + for (l = -1; (l = P_FindLineFromLineTag(&line, l)) >= 0;) + switch (lines[l].special) + { + case 10: case 14: case 15: case 20: case 21: case 22: + case 47: case 53: case 62: case 66: case 67: case 68: + case 87: case 88: case 95: case 120: case 121: case 122: + case 123: case 143: case 162: case 163: case 181: case 182: + case 144: case 148: case 149: case 211: case 227: case 228: + case 231: case 232: case 235: case 236: + return true; + } + + return false; +} + +/* + * P_IsUnderDamage + * + * killough 9/9/98: + * + * Returns nonzero if the object is under damage based on + * their current position. Returns 1 if the damage is moderate, + * -1 if it is serious. Used for AI. + */ + +static int P_IsUnderDamage(mobj_t *actor) +{ + const struct msecnode_s *seclist; + const ceiling_t *cl; // Crushing ceiling + int dir = 0; + for (seclist=actor->touching_sectorlist; seclist; seclist=seclist->m_tnext) + if ((cl = seclist->m_sector->ceilingdata) && + cl->thinker.function == T_MoveCeiling) + dir |= cl->direction; + return dir; +} + +// +// P_Move +// Move in the current direction, +// returns false if the move is blocked. +// + +static fixed_t xspeed[8] = {FRACUNIT,47000,0,-47000,-FRACUNIT,-47000,0,47000}; +static fixed_t yspeed[8] = {0,47000,FRACUNIT,47000,0,-47000,-FRACUNIT,-47000}; + +// 1/11/98 killough: Limit removed on special lines crossed +extern line_t **spechit; // New code -- killough +extern int numspechit; + +static boolean P_Move(mobj_t *actor, boolean dropoff) /* killough 9/12/98 */ +{ + fixed_t tryx, tryy, deltax, deltay, origx, origy; + boolean try_ok; + int movefactor = ORIG_FRICTION_FACTOR; // killough 10/98 + int friction = ORIG_FRICTION; + int speed; + + if (actor->movedir == DI_NODIR) + return false; + +#ifdef RANGECHECK + if ((unsigned)actor->movedir >= 8) + I_Error ("P_Move: Weird actor->movedir!"); +#endif + + // killough 10/98: make monsters get affected by ice and sludge too: + + if (monster_friction) + movefactor = P_GetMoveFactor(actor, &friction); + + speed = actor->info->speed; + + if (friction < ORIG_FRICTION && // sludge + !(speed = ((ORIG_FRICTION_FACTOR - (ORIG_FRICTION_FACTOR-movefactor)/2) + * speed) / ORIG_FRICTION_FACTOR)) + speed = 1; // always give the monster a little bit of speed + + tryx = (origx = actor->x) + (deltax = speed * xspeed[actor->movedir]); + tryy = (origy = actor->y) + (deltay = speed * yspeed[actor->movedir]); + + try_ok = P_TryMove(actor, tryx, tryy, dropoff); + + // killough 10/98: + // Let normal momentum carry them, instead of steptoeing them across ice. + + if (try_ok && friction > ORIG_FRICTION) + { + actor->x = origx; + actor->y = origy; + movefactor *= FRACUNIT / ORIG_FRICTION_FACTOR / 4; + actor->momx += FixedMul(deltax, movefactor); + actor->momy += FixedMul(deltay, movefactor); + } + + if (!try_ok) + { // open any specials + int good; + + if (actor->flags & MF_FLOAT && floatok) + { + if (actor->z < tmfloorz) // must adjust height + actor->z += FLOATSPEED; + else + actor->z -= FLOATSPEED; + + actor->flags |= MF_INFLOAT; + + return true; + } + + if (!numspechit) + return false; + + actor->movedir = DI_NODIR; + + /* if the special is not a door that can be opened, return false + * + * killough 8/9/98: this is what caused monsters to get stuck in + * doortracks, because it thought that the monster freed itself + * by opening a door, even if it was moving towards the doortrack, + * and not the door itself. + * + * killough 9/9/98: If a line blocking the monster is activated, + * return true 90% of the time. If a line blocking the monster is + * not activated, but some other line is, return false 90% of the + * time. A bit of randomness is needed to ensure it's free from + * lockups, but for most cases, it returns the correct result. + * + * Do NOT simply return false 1/4th of the time (causes monsters to + * back out when they shouldn't, and creates secondary stickiness). + */ + + for (good = false; numspechit--; ) + if (P_UseSpecialLine(actor, spechit[numspechit], 0)) + good |= spechit[numspechit] == blockline ? 1 : 2; + + /* cph - compatibility maze here + * Boom v2.01 and orig. Doom return "good" + * Boom v2.02 and LxDoom return good && (P_Random(pr_trywalk)&3) + * MBF plays even more games + */ + if (!good || comp[comp_doorstuck]) return good; + if (!mbf_features) + return (P_Random(pr_trywalk)&3); /* jff 8/13/98 */ + else /* finally, MBF code */ + return ((P_Random(pr_opendoor) >= 230) ^ (good & 1)); + } + else + actor->flags &= ~MF_INFLOAT; + + /* killough 11/98: fall more slowly, under gravity, if felldown==true */ + if (!(actor->flags & MF_FLOAT) && + (!felldown || !mbf_features)) + actor->z = actor->floorz; + + return true; +} + +/* + * P_SmartMove + * + * killough 9/12/98: Same as P_Move, except smarter + */ + +static boolean P_SmartMove(mobj_t *actor) +{ + mobj_t *target = actor->target; + int on_lift, dropoff = false, under_damage; + + /* killough 9/12/98: Stay on a lift if target is on one */ + on_lift = !comp[comp_staylift] + && target && target->health > 0 + && target->subsector->sector->tag==actor->subsector->sector->tag && + P_IsOnLift(actor); + + under_damage = monster_avoid_hazards && P_IsUnderDamage(actor); + + // killough 10/98: allow dogs to drop off of taller ledges sometimes. + // dropoff==1 means always allow it, dropoff==2 means only up to 128 high, + // and only if the target is immediately on the other side of the line. + +#ifdef DOGS + // haleyjd: allow all friends of HelperType to also jump down + + if ((actor->type == MT_DOGS || (actor->type == (HelperThing-1) && actor->flags&MF_FRIEND)) + && target && dog_jumping && + !((target->flags ^ actor->flags) & MF_FRIEND) && + P_AproxDistance(actor->x - target->x, + actor->y - target->y) < FRACUNIT*144 && + P_Random(pr_dropoff) < 235) + dropoff = 2; +#endif + + if (!P_Move(actor, dropoff)) + return false; + + // killough 9/9/98: avoid crushing ceilings or other damaging areas + if ( + (on_lift && P_Random(pr_stayonlift) < 230 && // Stay on lift + !P_IsOnLift(actor)) + || + (monster_avoid_hazards && !under_damage && // Get away from damage + (under_damage = P_IsUnderDamage(actor)) && + (under_damage < 0 || P_Random(pr_avoidcrush) < 200)) + ) + actor->movedir = DI_NODIR; // avoid the area (most of the time anyway) + + return true; +} + +// +// TryWalk +// Attempts to move actor on +// in its current (ob->moveangle) direction. +// If blocked by either a wall or an actor +// returns FALSE +// If move is either clear or blocked only by a door, +// returns TRUE and sets... +// If a door is in the way, +// an OpenDoor call is made to start it opening. +// + +static boolean P_TryWalk(mobj_t *actor) +{ + if (!P_SmartMove(actor)) + return false; + actor->movecount = P_Random(pr_trywalk)&15; + return true; +} + +// +// P_DoNewChaseDir +// +// killough 9/8/98: +// +// Most of P_NewChaseDir(), except for what +// determines the new direction to take +// + +static void P_DoNewChaseDir(mobj_t *actor, fixed_t deltax, fixed_t deltay) +{ + dirtype_t xdir, ydir, tdir; + dirtype_t olddir = actor->movedir; + dirtype_t turnaround = olddir; + + if (turnaround != DI_NODIR) // find reverse direction + turnaround ^= 4; + + xdir = + deltax > 10*FRACUNIT ? DI_EAST : + deltax < -10*FRACUNIT ? DI_WEST : DI_NODIR; + + ydir = + deltay < -10*FRACUNIT ? DI_SOUTH : + deltay > 10*FRACUNIT ? DI_NORTH : DI_NODIR; + + // try direct route + if (xdir != DI_NODIR && ydir != DI_NODIR && turnaround != + (actor->movedir = deltay < 0 ? deltax > 0 ? DI_SOUTHEAST : DI_SOUTHWEST : + deltax > 0 ? DI_NORTHEAST : DI_NORTHWEST) && P_TryWalk(actor)) + return; + + // try other directions + if (P_Random(pr_newchase) > 200 || D_abs(deltay)>D_abs(deltax)) + tdir = xdir, xdir = ydir, ydir = tdir; + + if ((xdir == turnaround ? xdir = DI_NODIR : xdir) != DI_NODIR && + (actor->movedir = xdir, P_TryWalk(actor))) + return; // either moved forward or attacked + + if ((ydir == turnaround ? ydir = DI_NODIR : ydir) != DI_NODIR && + (actor->movedir = ydir, P_TryWalk(actor))) + return; + + // there is no direct path to the player, so pick another direction. + if (olddir != DI_NODIR && (actor->movedir = olddir, P_TryWalk(actor))) + return; + + // randomly determine direction of search + if (P_Random(pr_newchasedir) & 1) + { + for (tdir = DI_EAST; tdir <= DI_SOUTHEAST; tdir++) + if (tdir != turnaround && (actor->movedir = tdir, P_TryWalk(actor))) + return; + } + else + for (tdir = DI_SOUTHEAST; tdir != DI_EAST-1; tdir--) + if (tdir != turnaround && (actor->movedir = tdir, P_TryWalk(actor))) + return; + + if ((actor->movedir = turnaround) != DI_NODIR && !P_TryWalk(actor)) + actor->movedir = DI_NODIR; +} + +// +// killough 11/98: +// +// Monsters try to move away from tall dropoffs. +// +// In Doom, they were never allowed to hang over dropoffs, +// and would remain stuck if involuntarily forced over one. +// This logic, combined with p_map.c (P_TryMove), allows +// monsters to free themselves without making them tend to +// hang over dropoffs. + +static fixed_t dropoff_deltax, dropoff_deltay, floorz; + +static boolean PIT_AvoidDropoff(line_t *line) +{ + if (line->backsector && // Ignore one-sided linedefs + tmbbox[BOXRIGHT] > line->bbox[BOXLEFT] && + tmbbox[BOXLEFT] < line->bbox[BOXRIGHT] && + tmbbox[BOXTOP] > line->bbox[BOXBOTTOM] && // Linedef must be contacted + tmbbox[BOXBOTTOM] < line->bbox[BOXTOP] && + P_BoxOnLineSide(tmbbox, line) == -1) + { + fixed_t front = line->frontsector->floorheight; + fixed_t back = line->backsector->floorheight; + angle_t angle; + + // The monster must contact one of the two floors, + // and the other must be a tall dropoff (more than 24). + + if (back == floorz && front < floorz - FRACUNIT*24) + angle = R_PointToAngle2(0,0,line->dx,line->dy); // front side dropoff + else + if (front == floorz && back < floorz - FRACUNIT*24) + angle = R_PointToAngle2(line->dx,line->dy,0,0); // back side dropoff + else + return true; + + // Move away from dropoff at a standard speed. + // Multiple contacted linedefs are cumulative (e.g. hanging over corner) + dropoff_deltax -= finesine[angle >> ANGLETOFINESHIFT]*32; + dropoff_deltay += finecosine[angle >> ANGLETOFINESHIFT]*32; + } + return true; +} + +// +// Driver for above +// + +static fixed_t P_AvoidDropoff(mobj_t *actor) +{ + int yh=((tmbbox[BOXTOP] = actor->y+actor->radius)-bmaporgy)>>MAPBLOCKSHIFT; + int yl=((tmbbox[BOXBOTTOM]= actor->y-actor->radius)-bmaporgy)>>MAPBLOCKSHIFT; + int xh=((tmbbox[BOXRIGHT] = actor->x+actor->radius)-bmaporgx)>>MAPBLOCKSHIFT; + int xl=((tmbbox[BOXLEFT] = actor->x-actor->radius)-bmaporgx)>>MAPBLOCKSHIFT; + int bx, by; + + floorz = actor->z; // remember floor height + + dropoff_deltax = dropoff_deltay = 0; + + // check lines + + validcount++; + for (bx=xl ; bx<=xh ; bx++) + for (by=yl ; by<=yh ; by++) + P_BlockLinesIterator(bx, by, PIT_AvoidDropoff); // all contacted lines + + return dropoff_deltax | dropoff_deltay; // Non-zero if movement prescribed +} + +// +// P_NewChaseDir +// +// killough 9/8/98: Split into two functions +// + +static void P_NewChaseDir(mobj_t *actor) +{ + mobj_t *target = actor->target; + fixed_t deltax = target->x - actor->x; + fixed_t deltay = target->y - actor->y; + + // killough 8/8/98: sometimes move away from target, keeping distance + // + // 1) Stay a certain distance away from a friend, to avoid being in their way + // 2) Take advantage over an enemy without missiles, by keeping distance + + actor->strafecount = 0; + + if (mbf_features) { + if (actor->floorz - actor->dropoffz > FRACUNIT*24 && + actor->z <= actor->floorz && + !(actor->flags & (MF_DROPOFF|MF_FLOAT)) && + !comp[comp_dropoff] && + P_AvoidDropoff(actor)) /* Move away from dropoff */ + { + P_DoNewChaseDir(actor, dropoff_deltax, dropoff_deltay); + + // If moving away from dropoff, set movecount to 1 so that + // small steps are taken to get monster away from dropoff. + + actor->movecount = 1; + return; + } + else + { + fixed_t dist = P_AproxDistance(deltax, deltay); + + // Move away from friends when too close, except + // in certain situations (e.g. a crowded lift) + + if (actor->flags & target->flags & MF_FRIEND && + distfriend << FRACBITS > dist && + !P_IsOnLift(target) && !P_IsUnderDamage(actor)) + { + deltax = -deltax, deltay = -deltay; + } else + if (target->health > 0 && (actor->flags ^ target->flags) & MF_FRIEND) + { // Live enemy target + if (monster_backing && + actor->info->missilestate && actor->type != MT_SKULL && + ((!target->info->missilestate && dist < MELEERANGE*2) || + (target->player && dist < MELEERANGE*3 && + (target->player->readyweapon == wp_fist || + target->player->readyweapon == wp_chainsaw)))) + { // Back away from melee attacker + actor->strafecount = P_Random(pr_enemystrafe) & 15; + deltax = -deltax, deltay = -deltay; + } + } + } + } + + P_DoNewChaseDir(actor, deltax, deltay); + + // If strafing, set movecount to strafecount so that old Doom + // logic still works the same, except in the strafing part + + if (actor->strafecount) + actor->movecount = actor->strafecount; +} + +// +// P_IsVisible +// +// killough 9/9/98: whether a target is visible to a monster +// + +static boolean P_IsVisible(mobj_t *actor, mobj_t *mo, boolean allaround) +{ + if (!allaround) + { + angle_t an = R_PointToAngle2(actor->x, actor->y, + mo->x, mo->y) - actor->angle; + if (an > ANG90 && an < ANG270 && + P_AproxDistance(mo->x-actor->x, mo->y-actor->y) > MELEERANGE) + return false; + } + return P_CheckSight(actor, mo); +} + +// +// PIT_FindTarget +// +// killough 9/5/98 +// +// Finds monster targets for other monsters +// + +static int current_allaround; + +static boolean PIT_FindTarget(mobj_t *mo) +{ + mobj_t *actor = current_actor; + + if (!((mo->flags ^ actor->flags) & MF_FRIEND && // Invalid target + mo->health > 0 && (mo->flags & MF_COUNTKILL || mo->type == MT_SKULL))) + return true; + + // If the monster is already engaged in a one-on-one attack + // with a healthy friend, don't attack around 60% the time + { + const mobj_t *targ = mo->target; + if (targ && targ->target == mo && + P_Random(pr_skiptarget) > 100 && + (targ->flags ^ mo->flags) & MF_FRIEND && + targ->health*2 >= targ->info->spawnhealth) + return true; + } + + if (!P_IsVisible(actor, mo, current_allaround)) + return true; + + P_SetTarget(&actor->lastenemy, actor->target); // Remember previous target + P_SetTarget(&actor->target, mo); // Found target + + // Move the selected monster to the end of its associated + // list, so that it gets searched last next time. + + { + thinker_t *cap = &thinkerclasscap[mo->flags & MF_FRIEND ? + th_friends : th_enemies]; + (mo->thinker.cprev->cnext = mo->thinker.cnext)->cprev = mo->thinker.cprev; + (mo->thinker.cprev = cap->cprev)->cnext = &mo->thinker; + (mo->thinker.cnext = cap)->cprev = &mo->thinker; + } + + return false; +} + +// +// P_LookForPlayers +// If allaround is false, only look 180 degrees in front. +// Returns true if a player is targeted. +// + +static boolean P_LookForPlayers(mobj_t *actor, boolean allaround) +{ + player_t *player; + int stop, stopc, c; + + if (actor->flags & MF_FRIEND) + { // killough 9/9/98: friendly monsters go about players differently + int anyone; + +#if 0 + if (!allaround) // If you want friendly monsters not to awaken unprovoked + return false; +#endif + + // Go back to a player, no matter whether it's visible or not + for (anyone=0; anyone<=1; anyone++) + for (c=0; ctarget, players[c].mo); + + // killough 12/98: + // get out of refiring loop, to avoid hitting player accidentally + + if (actor->info->missilestate) + { + P_SetMobjState(actor, actor->info->seestate); + actor->flags &= ~MF_JUSTHIT; + } + + return true; + } + + return false; + } + + // Change mask of 3 to (MAXPLAYERS-1) -- killough 2/15/98: + stop = (actor->lastlook-1)&(MAXPLAYERS-1); + + c = 0; + + stopc = !mbf_features && + !demo_compatibility && monsters_remember ? + MAXPLAYERS : 2; // killough 9/9/98 + + for (;; actor->lastlook = (actor->lastlook+1)&(MAXPLAYERS-1)) + { + if (!playeringame[actor->lastlook]) + continue; + + // killough 2/15/98, 9/9/98: + if (c++ == stopc || actor->lastlook == stop) // done looking + { + // e6y + // Fixed Boom incompatibilities. The following code was missed. + // There are no more desyncs on Donce's demos on horror.wad + + // Use last known enemy if no players sighted -- killough 2/15/98: + if (!mbf_features && !demo_compatibility && monsters_remember) + { + if (actor->lastenemy && actor->lastenemy->health > 0) + { + actor->target = actor->lastenemy; + actor->lastenemy = NULL; + return true; + } + } + + return false; + } + + player = &players[actor->lastlook]; + + if (player->health <= 0) + continue; // dead + + if (!P_IsVisible(actor, player->mo, allaround)) + continue; + + P_SetTarget(&actor->target, player->mo); + + /* killough 9/9/98: give monsters a threshold towards getting players + * (we don't want it to be too easy for a player with dogs :) + */ + if (!comp[comp_pursuit]) + actor->threshold = 60; + + return true; + } +} + +// +// Friendly monsters, by Lee Killough 7/18/98 +// +// Friendly monsters go after other monsters first, but +// also return to owner if they cannot find any targets. +// A marine's best friend :) killough 7/18/98, 9/98 +// + +static boolean P_LookForMonsters(mobj_t *actor, boolean allaround) +{ + thinker_t *cap, *th; + + if (demo_compatibility) + return false; + + if (actor->lastenemy && actor->lastenemy->health > 0 && monsters_remember && + !(actor->lastenemy->flags & actor->flags & MF_FRIEND)) // not friends + { + P_SetTarget(&actor->target, actor->lastenemy); + P_SetTarget(&actor->lastenemy, NULL); + return true; + } + + /* Old demos do not support monster-seeking bots */ + if (!mbf_features) + return false; + + // Search the threaded list corresponding to this object's potential targets + cap = &thinkerclasscap[actor->flags & MF_FRIEND ? th_enemies : th_friends]; + + // Search for new enemy + + if (cap->cnext != cap) // Empty list? bail out early + { + int x = (actor->x - bmaporgx)>>MAPBLOCKSHIFT; + int y = (actor->y - bmaporgy)>>MAPBLOCKSHIFT; + int d; + + current_actor = actor; + current_allaround = allaround; + + // Search first in the immediate vicinity. + + if (!P_BlockThingsIterator(x, y, PIT_FindTarget)) + return true; + + for (d=1; d<5; d++) + { + int i = 1 - d; + do + if (!P_BlockThingsIterator(x+i, y-d, PIT_FindTarget) || + !P_BlockThingsIterator(x+i, y+d, PIT_FindTarget)) + return true; + while (++i < d); + do + if (!P_BlockThingsIterator(x-d, y+i, PIT_FindTarget) || + !P_BlockThingsIterator(x+d, y+i, PIT_FindTarget)) + return true; + while (--i + d >= 0); + } + + { // Random number of monsters, to prevent patterns from forming + int n = (P_Random(pr_friends) & 31) + 15; + + for (th = cap->cnext; th != cap; th = th->cnext) + if (--n < 0) + { + // Only a subset of the monsters were searched. Move all of + // the ones which were searched so far, to the end of the list. + + (cap->cnext->cprev = cap->cprev)->cnext = cap->cnext; + (cap->cprev = th->cprev)->cnext = cap; + (th->cprev = cap)->cnext = th; + break; + } + else + if (!PIT_FindTarget((mobj_t *) th)) // If target sighted + return true; + } + } + + return false; // No monster found +} + +// +// P_LookForTargets +// +// killough 9/5/98: look for targets to go after, depending on kind of monster +// + +static boolean P_LookForTargets(mobj_t *actor, int allaround) +{ + return actor->flags & MF_FRIEND ? + P_LookForMonsters(actor, allaround) || P_LookForPlayers (actor, allaround): + P_LookForPlayers (actor, allaround) || P_LookForMonsters(actor, allaround); +} + +// +// P_HelpFriend +// +// killough 9/8/98: Help friends in danger of dying +// + +static boolean P_HelpFriend(mobj_t *actor) +{ + thinker_t *cap, *th; + + // If less than 33% health, self-preservation rules + if (actor->health*3 < actor->info->spawnhealth) + return false; + + current_actor = actor; + current_allaround = true; + + // Possibly help a friend under 50% health + cap = &thinkerclasscap[actor->flags & MF_FRIEND ? th_friends : th_enemies]; + + for (th = cap->cnext; th != cap; th = th->cnext) + if (((mobj_t *) th)->health*2 >= ((mobj_t *) th)->info->spawnhealth) + { + if (P_Random(pr_helpfriend) < 180) + break; + } + else + if (((mobj_t *) th)->flags & MF_JUSTHIT && + ((mobj_t *) th)->target && + ((mobj_t *) th)->target != actor->target && + !PIT_FindTarget(((mobj_t *) th)->target)) + { + // Ignore any attacking monsters, while searching for friend + actor->threshold = BASETHRESHOLD; + return true; + } + + return false; +} + +// +// A_KeenDie +// DOOM II special, map 32. +// Uses special tag 666. +// +void A_KeenDie(mobj_t* mo) +{ + thinker_t *th; + line_t junk; + + A_Fall(mo); + + // scan the remaining thinkers to see if all Keens are dead + + for (th = thinkercap.next ; th != &thinkercap ; th=th->next) + if (th->function == P_MobjThinker) + { + mobj_t *mo2 = (mobj_t *) th; + if (mo2 != mo && mo2->type == mo->type && mo2->health > 0) + return; // other Keen not dead + } + + junk.tag = 666; + EV_DoDoor(&junk,open); +} + + +// +// ACTION ROUTINES +// + +// +// A_Look +// Stay in state until a player is sighted. +// + +void A_Look(mobj_t *actor) +{ + mobj_t *targ = actor->subsector->sector->soundtarget; + actor->threshold = 0; // any shot will wake up + + /* killough 7/18/98: + * Friendly monsters go after other monsters first, but + * also return to player, without attacking them, if they + * cannot find any targets. A marine's best friend :) + */ + actor->pursuecount = 0; + + if (!(actor->flags & MF_FRIEND && P_LookForTargets(actor, false)) && + !((targ = actor->subsector->sector->soundtarget) && + targ->flags & MF_SHOOTABLE && + (P_SetTarget(&actor->target, targ), + !(actor->flags & MF_AMBUSH) || P_CheckSight(actor, targ))) && + (actor->flags & MF_FRIEND || !P_LookForTargets(actor, false))) + return; + + // go into chase state + + if (actor->info->seesound) + { + int sound; + switch (actor->info->seesound) + { + case sfx_posit1: + case sfx_posit2: + case sfx_posit3: + sound = sfx_posit1+P_Random(pr_see)%3; + break; + + case sfx_bgsit1: + case sfx_bgsit2: + sound = sfx_bgsit1+P_Random(pr_see)%2; + break; + + default: + sound = actor->info->seesound; + break; + } + if (actor->type==MT_SPIDER || actor->type == MT_CYBORG) + S_StartSound(NULL, sound); // full volume + else + S_StartSound(actor, sound); + } + P_SetMobjState(actor, actor->info->seestate); +} + + +// +// A_Chase +// Actor has a melee attack, +// so it tries to close as fast as possible +// + +void A_Chase(mobj_t *actor) +{ + if (actor->reactiontime) + actor->reactiontime--; + + if (actor->threshold) { /* modify target threshold */ + if (!actor->target || actor->target->health <= 0) + actor->threshold = 0; + else + actor->threshold--; + } + + /* turn towards movement direction if not there yet + * killough 9/7/98: keep facing towards target if strafing or backing out + */ + + if (actor->strafecount) + A_FaceTarget(actor); + else if (actor->movedir < 8) + { + int delta = (actor->angle &= (7<<29)) - (actor->movedir << 29); + if (delta > 0) + actor->angle -= ANG90/2; + else + if (delta < 0) + actor->angle += ANG90/2; + } + + if (!actor->target || !(actor->target->flags&MF_SHOOTABLE)) + { + if (!P_LookForTargets(actor,true)) // look for a new target + P_SetMobjState(actor, actor->info->spawnstate); // no new target + return; + } + + // do not attack twice in a row + if (actor->flags & MF_JUSTATTACKED) + { + actor->flags &= ~MF_JUSTATTACKED; + if (gameskill != sk_nightmare && !fastparm) + P_NewChaseDir(actor); + return; + } + + // check for melee attack + if (actor->info->meleestate && P_CheckMeleeRange(actor)) + { + if (actor->info->attacksound) + S_StartSound(actor, actor->info->attacksound); + P_SetMobjState(actor, actor->info->meleestate); + /* killough 8/98: remember an attack + * cph - DEMOSYNC? */ + if (!actor->info->missilestate) + actor->flags |= MF_JUSTHIT; + return; + } + + // check for missile attack + if (actor->info->missilestate) + if (!(gameskill < sk_nightmare && !fastparm && actor->movecount)) + if (P_CheckMissileRange(actor)) + { + P_SetMobjState(actor, actor->info->missilestate); + actor->flags |= MF_JUSTATTACKED; + return; + } + + if (!actor->threshold) { + if (!mbf_features) + { /* killough 9/9/98: for backward demo compatibility */ + if (netgame && !P_CheckSight(actor, actor->target) && + P_LookForPlayers(actor, true)) + return; + } + /* killough 7/18/98, 9/9/98: new monster AI */ + else if (help_friends && P_HelpFriend(actor)) + return; /* killough 9/8/98: Help friends in need */ + /* Look for new targets if current one is bad or is out of view */ + else if (actor->pursuecount) + actor->pursuecount--; + else { + /* Our pursuit time has expired. We're going to think about + * changing targets */ + actor->pursuecount = BASETHRESHOLD; + + /* Unless (we have a live target + * and it's not friendly + * and we can see it) + * try to find a new one; return if sucessful */ + + if (!(actor->target && actor->target->health > 0 && + ((comp[comp_pursuit] && !netgame) || + (((actor->target->flags ^ actor->flags) & MF_FRIEND || + (!(actor->flags & MF_FRIEND) && monster_infighting)) && + P_CheckSight(actor, actor->target)))) + && P_LookForTargets(actor, true)) + return; + + /* (Current target was good, or no new target was found.) + * + * If monster is a missile-less friend, give up pursuit and + * return to player, if no attacks have occurred recently. + */ + + if (!actor->info->missilestate && actor->flags & MF_FRIEND) { + if (actor->flags & MF_JUSTHIT) /* if recent action, */ + actor->flags &= ~MF_JUSTHIT; /* keep fighting */ + else if (P_LookForPlayers(actor, true)) /* else return to player */ + return; + } + } + } + + if (actor->strafecount) + actor->strafecount--; + + // chase towards player + if (--actor->movecount<0 || !P_SmartMove(actor)) + P_NewChaseDir(actor); + + // make active sound + if (actor->info->activesound && P_Random(pr_see)<3) + S_StartSound(actor, actor->info->activesound); +} + +// +// A_FaceTarget +// +void A_FaceTarget(mobj_t *actor) +{ + if (!actor->target) + return; + actor->flags &= ~MF_AMBUSH; + actor->angle = R_PointToAngle2(actor->x, actor->y, + actor->target->x, actor->target->y); + if (actor->target->flags & MF_SHADOW) + { // killough 5/5/98: remove dependence on order of evaluation: + int t = P_Random(pr_facetarget); + actor->angle += (t-P_Random(pr_facetarget))<<21; + } +} + +// +// A_PosAttack +// + +void A_PosAttack(mobj_t *actor) +{ + int angle, damage, slope, t; + + if (!actor->target) + return; + A_FaceTarget(actor); + angle = actor->angle; + slope = P_AimLineAttack(actor, angle, MISSILERANGE, 0); /* killough 8/2/98 */ + S_StartSound(actor, sfx_pistol); + + // killough 5/5/98: remove dependence on order of evaluation: + t = P_Random(pr_posattack); + angle += (t - P_Random(pr_posattack))<<20; + damage = (P_Random(pr_posattack)%5 + 1)*3; + P_LineAttack(actor, angle, MISSILERANGE, slope, damage); +} + +void A_SPosAttack(mobj_t* actor) +{ + int i, bangle, slope; + + if (!actor->target) + return; + S_StartSound(actor, sfx_shotgn); + A_FaceTarget(actor); + bangle = actor->angle; + slope = P_AimLineAttack(actor, bangle, MISSILERANGE, 0); /* killough 8/2/98 */ + for (i=0; i<3; i++) + { // killough 5/5/98: remove dependence on order of evaluation: + int t = P_Random(pr_sposattack); + int angle = bangle + ((t - P_Random(pr_sposattack))<<20); + int damage = ((P_Random(pr_sposattack)%5)+1)*3; + P_LineAttack(actor, angle, MISSILERANGE, slope, damage); + } +} + +void A_CPosAttack(mobj_t *actor) +{ + int angle, bangle, damage, slope, t; + + if (!actor->target) + return; + S_StartSound(actor, sfx_shotgn); + A_FaceTarget(actor); + bangle = actor->angle; + slope = P_AimLineAttack(actor, bangle, MISSILERANGE, 0); /* killough 8/2/98 */ + + // killough 5/5/98: remove dependence on order of evaluation: + t = P_Random(pr_cposattack); + angle = bangle + ((t - P_Random(pr_cposattack))<<20); + damage = ((P_Random(pr_cposattack)%5)+1)*3; + P_LineAttack(actor, angle, MISSILERANGE, slope, damage); +} + +void A_CPosRefire(mobj_t *actor) +{ + // keep firing unless target got out of sight + A_FaceTarget(actor); + + /* killough 12/98: Stop firing if a friend has gotten in the way */ + if (P_HitFriend(actor)) + goto stop; + + /* killough 11/98: prevent refiring on friends continuously */ + if (P_Random(pr_cposrefire) < 40) { + if (actor->target && actor->flags & actor->target->flags & MF_FRIEND) + goto stop; + else + return; + } + + if (!actor->target || actor->target->health <= 0 + || !P_CheckSight(actor, actor->target)) +stop: P_SetMobjState(actor, actor->info->seestate); +} + +void A_SpidRefire(mobj_t* actor) +{ + // keep firing unless target got out of sight + A_FaceTarget(actor); + + /* killough 12/98: Stop firing if a friend has gotten in the way */ + if (P_HitFriend(actor)) + goto stop; + + if (P_Random(pr_spidrefire) < 10) + return; + + // killough 11/98: prevent refiring on friends continuously + if (!actor->target || actor->target->health <= 0 + || actor->flags & actor->target->flags & MF_FRIEND + || !P_CheckSight(actor, actor->target)) + stop: P_SetMobjState(actor, actor->info->seestate); +} + +void A_BspiAttack(mobj_t *actor) +{ + if (!actor->target) + return; + A_FaceTarget(actor); + P_SpawnMissile(actor, actor->target, MT_ARACHPLAZ); // launch a missile +} + +// +// A_TroopAttack +// + +void A_TroopAttack(mobj_t *actor) +{ + if (!actor->target) + return; + A_FaceTarget(actor); + if (P_CheckMeleeRange(actor)) + { + int damage; + S_StartSound(actor, sfx_claw); + damage = (P_Random(pr_troopattack)%8+1)*3; + P_DamageMobj(actor->target, actor, actor, damage); + return; + } + P_SpawnMissile(actor, actor->target, MT_TROOPSHOT); // launch a missile +} + +void A_SargAttack(mobj_t *actor) +{ + if (!actor->target) + return; + A_FaceTarget(actor); + if (P_CheckMeleeRange(actor)) + { + int damage = ((P_Random(pr_sargattack)%10)+1)*4; + P_DamageMobj(actor->target, actor, actor, damage); + } +} + +void A_HeadAttack(mobj_t *actor) +{ + if (!actor->target) + return; + A_FaceTarget (actor); + if (P_CheckMeleeRange(actor)) + { + int damage = (P_Random(pr_headattack)%6+1)*10; + P_DamageMobj(actor->target, actor, actor, damage); + return; + } + P_SpawnMissile(actor, actor->target, MT_HEADSHOT); // launch a missile +} + +void A_CyberAttack(mobj_t *actor) +{ + if (!actor->target) + return; + A_FaceTarget(actor); + P_SpawnMissile(actor, actor->target, MT_ROCKET); +} + +void A_BruisAttack(mobj_t *actor) +{ + if (!actor->target) + return; + if (P_CheckMeleeRange(actor)) + { + int damage; + S_StartSound(actor, sfx_claw); + damage = (P_Random(pr_bruisattack)%8+1)*10; + P_DamageMobj(actor->target, actor, actor, damage); + return; + } + P_SpawnMissile(actor, actor->target, MT_BRUISERSHOT); // launch a missile +} + +// +// A_SkelMissile +// + +void A_SkelMissile(mobj_t *actor) +{ + mobj_t *mo; + + if (!actor->target) + return; + + A_FaceTarget (actor); + actor->z += 16*FRACUNIT; // so missile spawns higher + mo = P_SpawnMissile (actor, actor->target, MT_TRACER); + actor->z -= 16*FRACUNIT; // back to normal + + mo->x += mo->momx; + mo->y += mo->momy; + P_SetTarget(&mo->tracer, actor->target); +} + +int TRACEANGLE = 0xc000000; + +void A_Tracer(mobj_t *actor) +{ + angle_t exact; + fixed_t dist; + fixed_t slope; + mobj_t *dest; + mobj_t *th; + + /* killough 1/18/98: this is why some missiles do not have smoke + * and some do. Also, internal demos start at random gametics, thus + * the bug in which revenants cause internal demos to go out of sync. + * + * killough 3/6/98: fix revenant internal demo bug by subtracting + * levelstarttic from gametic. + * + * killough 9/29/98: use new "basetic" so that demos stay in sync + * during pauses and menu activations, while retaining old demo sync. + * + * leveltime would have been better to use to start with in Doom, but + * since old demos were recorded using gametic, we must stick with it, + * and improvise around it (using leveltime causes desync across levels). + */ + + if ((gametic-basetic) & 3) + return; + + // spawn a puff of smoke behind the rocket + P_SpawnPuff(actor->x, actor->y, actor->z); + + th = P_SpawnMobj (actor->x-actor->momx, + actor->y-actor->momy, + actor->z, MT_SMOKE); + + th->momz = FRACUNIT; + th->tics -= P_Random(pr_tracer) & 3; + if (th->tics < 1) + th->tics = 1; + + // adjust direction + dest = actor->tracer; + + if (!dest || dest->health <= 0) + return; + + // change angle + exact = R_PointToAngle2(actor->x, actor->y, dest->x, dest->y); + + if (exact != actor->angle) { + if (exact - actor->angle > 0x80000000) + { + actor->angle -= TRACEANGLE; + if (exact - actor->angle < 0x80000000) + actor->angle = exact; + } + else + { + actor->angle += TRACEANGLE; + if (exact - actor->angle > 0x80000000) + actor->angle = exact; + } + } + + exact = actor->angle>>ANGLETOFINESHIFT; + actor->momx = FixedMul(actor->info->speed, finecosine[exact]); + actor->momy = FixedMul(actor->info->speed, finesine[exact]); + + // change slope + dist = P_AproxDistance(dest->x - actor->x, dest->y - actor->y); + + dist = dist / actor->info->speed; + + if (dist < 1) + dist = 1; + + slope = (dest->z+40*FRACUNIT - actor->z) / dist; + + if (slope < actor->momz) + actor->momz -= FRACUNIT/8; + else + actor->momz += FRACUNIT/8; +} + +void A_SkelWhoosh(mobj_t *actor) +{ + if (!actor->target) + return; + A_FaceTarget(actor); + S_StartSound(actor,sfx_skeswg); +} + +void A_SkelFist(mobj_t *actor) +{ + if (!actor->target) + return; + A_FaceTarget(actor); + if (P_CheckMeleeRange(actor)) + { + int damage = ((P_Random(pr_skelfist)%10)+1)*6; + S_StartSound(actor, sfx_skepch); + P_DamageMobj(actor->target, actor, actor, damage); + } +} + +// +// PIT_VileCheck +// Detect a corpse that could be raised. +// + +mobj_t* corpsehit; +mobj_t* vileobj; +fixed_t viletryx; +fixed_t viletryy; + +static boolean PIT_VileCheck(mobj_t *thing) +{ + int maxdist; + boolean check; + + if (!(thing->flags & MF_CORPSE) ) + return true; // not a monster + + if (thing->tics != -1) + return true; // not lying still yet + + if (thing->info->raisestate == S_NULL) + return true; // monster doesn't have a raise state + + maxdist = thing->info->radius + mobjinfo[MT_VILE].radius; + + if (D_abs(thing->x-viletryx) > maxdist || D_abs(thing->y-viletryy) > maxdist) + return true; // not actually touching + +// Check to see if the radius and height are zero. If they are // phares +// then this is a crushed monster that has been turned into a // | +// gib. One of the options may be to ignore this guy. // V + +// Option 1: the original, buggy method, -> ghost (compatibility) +// Option 2: ressurect the monster, but not as a ghost +// Option 3: ignore the gib + +// if (Option3) // ^ +// if ((thing->height == 0) && (thing->radius == 0)) // | +// return true; // phares + + corpsehit = thing; + corpsehit->momx = corpsehit->momy = 0; + if (comp[comp_vile]) // phares + { // | + corpsehit->height <<= 2; // V + check = P_CheckPosition(corpsehit,corpsehit->x,corpsehit->y); + corpsehit->height >>= 2; + } + else + { + int height,radius; + + height = corpsehit->height; // save temporarily + radius = corpsehit->radius; // save temporarily + corpsehit->height = corpsehit->info->height; + corpsehit->radius = corpsehit->info->radius; + corpsehit->flags |= MF_SOLID; + check = P_CheckPosition(corpsehit,corpsehit->x,corpsehit->y); + corpsehit->height = height; // restore + corpsehit->radius = radius; // restore // ^ + corpsehit->flags &= ~MF_SOLID; + } // | + // phares + if (!check) + return true; // doesn't fit here + return false; // got one, so stop checking +} + +// +// A_VileChase +// Check for ressurecting a body +// + +void A_VileChase(mobj_t* actor) +{ + int xl, xh; + int yl, yh; + int bx, by; + + if (actor->movedir != DI_NODIR) + { + // check for corpses to raise + viletryx = + actor->x + actor->info->speed*xspeed[actor->movedir]; + viletryy = + actor->y + actor->info->speed*yspeed[actor->movedir]; + + xl = (viletryx - bmaporgx - MAXRADIUS*2)>>MAPBLOCKSHIFT; + xh = (viletryx - bmaporgx + MAXRADIUS*2)>>MAPBLOCKSHIFT; + yl = (viletryy - bmaporgy - MAXRADIUS*2)>>MAPBLOCKSHIFT; + yh = (viletryy - bmaporgy + MAXRADIUS*2)>>MAPBLOCKSHIFT; + + vileobj = actor; + for (bx=xl ; bx<=xh ; bx++) + { + for (by=yl ; by<=yh ; by++) + { + // Call PIT_VileCheck to check + // whether object is a corpse + // that canbe raised. + if (!P_BlockThingsIterator(bx,by,PIT_VileCheck)) + { + mobjinfo_t *info; + + // got one! + mobj_t* temp = actor->target; + actor->target = corpsehit; + A_FaceTarget(actor); + actor->target = temp; + + P_SetMobjState(actor, S_VILE_HEAL1); + S_StartSound(corpsehit, sfx_slop); + info = corpsehit->info; + + P_SetMobjState(corpsehit,info->raisestate); + + if (comp[comp_vile]) // phares + corpsehit->height <<= 2; // | + else // V + { + corpsehit->height = info->height; // fix Ghost bug + corpsehit->radius = info->radius; // fix Ghost bug + } // phares + + /* killough 7/18/98: + * friendliness is transferred from AV to raised corpse + */ + corpsehit->flags = + (info->flags & ~MF_FRIEND) | (actor->flags & MF_FRIEND); + + if (!((corpsehit->flags ^ MF_COUNTKILL) & (MF_FRIEND | MF_COUNTKILL))) + totallive++; + + corpsehit->health = info->spawnhealth; + P_SetTarget(&corpsehit->target, NULL); // killough 11/98 + + if (mbf_features) + { /* kilough 9/9/98 */ + P_SetTarget(&corpsehit->lastenemy, NULL); + corpsehit->flags &= ~MF_JUSTHIT; + } + + /* killough 8/29/98: add to appropriate thread */ + P_UpdateThinker(&corpsehit->thinker); + + return; + } + } + } + } + A_Chase(actor); // Return to normal attack. +} + +// +// A_VileStart +// + +void A_VileStart(mobj_t *actor) +{ + S_StartSound(actor, sfx_vilatk); +} + +// +// A_Fire +// Keep fire in front of player unless out of sight +// + +void A_StartFire(mobj_t *actor) +{ + S_StartSound(actor,sfx_flamst); + A_Fire(actor); +} + +void A_FireCrackle(mobj_t* actor) +{ + S_StartSound(actor,sfx_flame); + A_Fire(actor); +} + +void A_Fire(mobj_t *actor) +{ + unsigned an; + mobj_t *dest = actor->tracer; + + if (!dest) + return; + + // don't move it if the vile lost sight + if (!P_CheckSight(actor->target, dest) ) + return; + + an = dest->angle >> ANGLETOFINESHIFT; + + P_UnsetThingPosition(actor); + actor->x = dest->x + FixedMul(24*FRACUNIT, finecosine[an]); + actor->y = dest->y + FixedMul(24*FRACUNIT, finesine[an]); + actor->z = dest->z; + P_SetThingPosition(actor); +} + +// +// A_VileTarget +// Spawn the hellfire +// + +void A_VileTarget(mobj_t *actor) +{ + mobj_t *fog; + + if (!actor->target) + return; + + A_FaceTarget(actor); + + // killough 12/98: fix Vile fog coordinates // CPhipps - compatibility optioned + fog = P_SpawnMobj(actor->target->x, + (compatibility_level < lxdoom_1_compatibility) ? actor->target->x : actor->target->y, + actor->target->z,MT_FIRE); + + P_SetTarget(&actor->tracer, fog); + P_SetTarget(&fog->target, actor); + P_SetTarget(&fog->tracer, actor->target); + A_Fire(fog); +} + +// +// A_VileAttack +// + +void A_VileAttack(mobj_t *actor) +{ + mobj_t *fire; + int an; + + if (!actor->target) + return; + + A_FaceTarget(actor); + + if (!P_CheckSight(actor, actor->target)) + return; + + S_StartSound(actor, sfx_barexp); + P_DamageMobj(actor->target, actor, actor, 20); + actor->target->momz = 1000*FRACUNIT/actor->target->info->mass; + + an = actor->angle >> ANGLETOFINESHIFT; + + fire = actor->tracer; + + if (!fire) + return; + + // move the fire between the vile and the player + fire->x = actor->target->x - FixedMul (24*FRACUNIT, finecosine[an]); + fire->y = actor->target->y - FixedMul (24*FRACUNIT, finesine[an]); + P_RadiusAttack(fire, actor, 70); +} + +// +// Mancubus attack, +// firing three missiles (bruisers) +// in three different directions? +// Doesn't look like it. +// + +#define FATSPREAD (ANG90/8) + +void A_FatRaise(mobj_t *actor) +{ + A_FaceTarget(actor); + S_StartSound(actor, sfx_manatk); +} + +void A_FatAttack1(mobj_t *actor) +{ + mobj_t *mo; + int an; + + if (!actor->target) + return; + + A_FaceTarget(actor); + + // Change direction to ... + actor->angle += FATSPREAD; + + P_SpawnMissile(actor, actor->target, MT_FATSHOT); + + mo = P_SpawnMissile (actor, actor->target, MT_FATSHOT); + mo->angle += FATSPREAD; + an = mo->angle >> ANGLETOFINESHIFT; + mo->momx = FixedMul(mo->info->speed, finecosine[an]); + mo->momy = FixedMul(mo->info->speed, finesine[an]); +} + +void A_FatAttack2(mobj_t *actor) +{ + mobj_t *mo; + int an; + + if (!actor->target) + return; + + A_FaceTarget(actor); + // Now here choose opposite deviation. + actor->angle -= FATSPREAD; + P_SpawnMissile(actor, actor->target, MT_FATSHOT); + + mo = P_SpawnMissile(actor, actor->target, MT_FATSHOT); + mo->angle -= FATSPREAD*2; + an = mo->angle >> ANGLETOFINESHIFT; + mo->momx = FixedMul(mo->info->speed, finecosine[an]); + mo->momy = FixedMul(mo->info->speed, finesine[an]); +} + +void A_FatAttack3(mobj_t *actor) +{ + mobj_t *mo; + int an; + + if (!actor->target) + return; + + A_FaceTarget(actor); + + mo = P_SpawnMissile(actor, actor->target, MT_FATSHOT); + mo->angle -= FATSPREAD/2; + an = mo->angle >> ANGLETOFINESHIFT; + mo->momx = FixedMul(mo->info->speed, finecosine[an]); + mo->momy = FixedMul(mo->info->speed, finesine[an]); + + mo = P_SpawnMissile(actor, actor->target, MT_FATSHOT); + mo->angle += FATSPREAD/2; + an = mo->angle >> ANGLETOFINESHIFT; + mo->momx = FixedMul(mo->info->speed, finecosine[an]); + mo->momy = FixedMul(mo->info->speed, finesine[an]); +} + + +// +// SkullAttack +// Fly at the player like a missile. +// +#define SKULLSPEED (20*FRACUNIT) + +void A_SkullAttack(mobj_t *actor) +{ + mobj_t *dest; + angle_t an; + int dist; + + if (!actor->target) + return; + + dest = actor->target; + actor->flags |= MF_SKULLFLY; + + S_StartSound(actor, actor->info->attacksound); + A_FaceTarget(actor); + an = actor->angle >> ANGLETOFINESHIFT; + actor->momx = FixedMul(SKULLSPEED, finecosine[an]); + actor->momy = FixedMul(SKULLSPEED, finesine[an]); + dist = P_AproxDistance(dest->x - actor->x, dest->y - actor->y); + dist = dist / SKULLSPEED; + + if (dist < 1) + dist = 1; + actor->momz = (dest->z+(dest->height>>1) - actor->z) / dist; +} + +// +// A_PainShootSkull +// Spawn a lost soul and launch it at the target +// + +static void A_PainShootSkull(mobj_t *actor, angle_t angle) +{ + fixed_t x,y,z; + mobj_t *newmobj; + angle_t an; + int prestep; + +// The original code checked for 20 skulls on the level, // phares +// and wouldn't spit another one if there were. If not in // phares +// compatibility mode, we remove the limit. // phares + // phares + if (comp[comp_pain]) /* killough 10/98: compatibility-optioned */ + { + // count total number of skulls currently on the level + int count = 0; + thinker_t *currentthinker = NULL; + while ((currentthinker = P_NextThinker(currentthinker,th_all)) != NULL) + if ((currentthinker->function == P_MobjThinker) + && ((mobj_t *)currentthinker)->type == MT_SKULL) + count++; + if (count > 20) // phares + return; // phares + } + + // okay, there's room for another one + + an = angle >> ANGLETOFINESHIFT; + + prestep = 4*FRACUNIT + 3*(actor->info->radius + mobjinfo[MT_SKULL].radius)/2; + + x = actor->x + FixedMul(prestep, finecosine[an]); + y = actor->y + FixedMul(prestep, finesine[an]); + z = actor->z + 8*FRACUNIT; + + if (comp[comp_skull]) /* killough 10/98: compatibility-optioned */ + newmobj = P_SpawnMobj(x, y, z, MT_SKULL); // phares + else // V + { + // Check whether the Lost Soul is being fired through a 1-sided + // wall or an impassible line, or a "monsters can't cross" line. + // If it is, then we don't allow the spawn. This is a bug fix, but + // it should be considered an enhancement, since it may disturb + // existing demos, so don't do it in compatibility mode. + + if (Check_Sides(actor,x,y)) + return; + + newmobj = P_SpawnMobj(x, y, z, MT_SKULL); + + // Check to see if the new Lost Soul's z value is above the + // ceiling of its new sector, or below the floor. If so, kill it. + + if ((newmobj->z > + (newmobj->subsector->sector->ceilingheight - newmobj->height)) || + (newmobj->z < newmobj->subsector->sector->floorheight)) + { + // kill it immediately + P_DamageMobj(newmobj,actor,actor,10000); + return; // ^ + } // | + } // phares + + /* killough 7/20/98: PEs shoot lost souls with the same friendliness */ + newmobj->flags = (newmobj->flags & ~MF_FRIEND) | (actor->flags & MF_FRIEND); + + /* killough 8/29/98: add to appropriate thread */ + P_UpdateThinker(&newmobj->thinker); + + // Check for movements. + // killough 3/15/98: don't jump over dropoffs: + + if (!P_TryMove(newmobj, newmobj->x, newmobj->y, false)) + { + // kill it immediately + P_DamageMobj(newmobj, actor, actor, 10000); + return; + } + + P_SetTarget(&newmobj->target, actor->target); + A_SkullAttack(newmobj); +} + +// +// A_PainAttack +// Spawn a lost soul and launch it at the target +// + +void A_PainAttack(mobj_t *actor) +{ + if (!actor->target) + return; + A_FaceTarget(actor); + A_PainShootSkull(actor, actor->angle); +} + +void A_PainDie(mobj_t *actor) +{ + A_Fall(actor); + A_PainShootSkull(actor, actor->angle+ANG90); + A_PainShootSkull(actor, actor->angle+ANG180); + A_PainShootSkull(actor, actor->angle+ANG270); +} + +void A_Scream(mobj_t *actor) +{ + int sound; + + switch (actor->info->deathsound) + { + case 0: + return; + + case sfx_podth1: + case sfx_podth2: + case sfx_podth3: + sound = sfx_podth1 + P_Random(pr_scream)%3; + break; + + case sfx_bgdth1: + case sfx_bgdth2: + sound = sfx_bgdth1 + P_Random(pr_scream)%2; + break; + + default: + sound = actor->info->deathsound; + break; + } + + // Check for bosses. + if (actor->type==MT_SPIDER || actor->type == MT_CYBORG) + S_StartSound(NULL, sound); // full volume + else + S_StartSound(actor, sound); +} + +void A_XScream(mobj_t *actor) +{ + S_StartSound(actor, sfx_slop); +} + +void A_Pain(mobj_t *actor) +{ + if (actor->info->painsound) + S_StartSound(actor, actor->info->painsound); +} + +void A_Fall(mobj_t *actor) +{ + // actor is on ground, it can be walked over + actor->flags &= ~MF_SOLID; +} + +// +// A_Explode +// +void A_Explode(mobj_t *thingy) +{ + P_RadiusAttack( thingy, thingy->target, 128 ); +} + +// +// A_BossDeath +// Possibly trigger special effects +// if on first boss level +// + +void A_BossDeath(mobj_t *mo) +{ + thinker_t *th; + line_t junk; + int i; + + if (gamemode == commercial) + { + if (gamemap != 7) + return; + + if ((mo->type != MT_FATSO) + && (mo->type != MT_BABY)) + return; + } + else + { + // e6y + // Additional check of gameepisode is necessary, because + // there is no right or wrong solution for E4M6 in original EXEs, + // there's nothing to emulate. + if (comp[comp_666] && gameepisode < 4) + { + // e6y + // Only following checks are present in doom2.exe ver. 1.666 and 1.9 + // instead of separate checks for each episode in doomult.exe, plutonia.exe and tnt.exe + // There is no more desync on doom.wad\episode3.lmp + // http://www.doomworld.com/idgames/index.php?id=6909 + if (gamemap != 8) + return; + if (mo->type == MT_BRUISER && gameepisode != 1) + return; + } + else + { + switch(gameepisode) + { + case 1: + if (gamemap != 8) + return; + + if (mo->type != MT_BRUISER) + return; + break; + + case 2: + if (gamemap != 8) + return; + + if (mo->type != MT_CYBORG) + return; + break; + + case 3: + if (gamemap != 8) + return; + + if (mo->type != MT_SPIDER) + return; + + break; + + case 4: + switch(gamemap) + { + case 6: + if (mo->type != MT_CYBORG) + return; + break; + + case 8: + if (mo->type != MT_SPIDER) + return; + break; + + default: + return; + break; + } + break; + + default: + if (gamemap != 8) + return; + break; + } + } + + } + + // make sure there is a player alive for victory + for (i=0; i 0) + break; + + if (i==MAXPLAYERS) + return; // no one left alive, so do not end game + + // scan the remaining thinkers to see + // if all bosses are dead + for (th = thinkercap.next ; th != &thinkercap ; th=th->next) + if (th->function == P_MobjThinker) + { + mobj_t *mo2 = (mobj_t *) th; + if (mo2 != mo && mo2->type == mo->type && mo2->health > 0) + return; // other boss not dead + } + + // victory! + if ( gamemode == commercial) + { + if (gamemap == 7) + { + if (mo->type == MT_FATSO) + { + junk.tag = 666; + EV_DoFloor(&junk,lowerFloorToLowest); + return; + } + + if (mo->type == MT_BABY) + { + junk.tag = 667; + EV_DoFloor(&junk,raiseToTexture); + return; + } + } + } + else + { + switch(gameepisode) + { + case 1: + junk.tag = 666; + EV_DoFloor(&junk, lowerFloorToLowest); + return; + break; + + case 4: + switch(gamemap) + { + case 6: + junk.tag = 666; + EV_DoDoor(&junk, blazeOpen); + return; + break; + + case 8: + junk.tag = 666; + EV_DoFloor(&junk, lowerFloorToLowest); + return; + break; + } + } + } + G_ExitLevel(); +} + + +void A_Hoof (mobj_t* mo) +{ + S_StartSound(mo, sfx_hoof); + A_Chase(mo); +} + +void A_Metal(mobj_t *mo) +{ + S_StartSound(mo, sfx_metal); + A_Chase(mo); +} + +void A_BabyMetal(mobj_t *mo) +{ + S_StartSound(mo, sfx_bspwlk); + A_Chase(mo); +} + +void A_OpenShotgun2(player_t *player, pspdef_t *psp) +{ + S_StartSound(player->mo, sfx_dbopn); +} + +void A_LoadShotgun2(player_t *player, pspdef_t *psp) +{ + S_StartSound(player->mo, sfx_dbload); +} + +void A_CloseShotgun2(player_t *player, pspdef_t *psp) +{ + S_StartSound(player->mo, sfx_dbcls); + A_ReFire(player,psp); +} + +// killough 2/7/98: Remove limit on icon landings: +mobj_t **braintargets; +int numbraintargets_alloc; +int numbraintargets; + +struct brain_s brain; // killough 3/26/98: global state of boss brain + +// killough 3/26/98: initialize icon landings at level startup, +// rather than at boss wakeup, to prevent savegame-related crashes + +void P_SpawnBrainTargets(void) // killough 3/26/98: renamed old function +{ + thinker_t *thinker; + + // find all the target spots + numbraintargets = 0; + brain.targeton = 0; + brain.easy = 0; // killough 3/26/98: always init easy to 0 + + for (thinker = thinkercap.next ; + thinker != &thinkercap ; + thinker = thinker->next) + if (thinker->function == P_MobjThinker) + { + mobj_t *m = (mobj_t *) thinker; + + if (m->type == MT_BOSSTARGET ) + { // killough 2/7/98: remove limit on icon landings: + if (numbraintargets >= numbraintargets_alloc) + braintargets = realloc(braintargets, + (numbraintargets_alloc = numbraintargets_alloc ? + numbraintargets_alloc*2 : 32) *sizeof *braintargets); + braintargets[numbraintargets++] = m; + } + } +} + +void A_BrainAwake(mobj_t *mo) +{ + S_StartSound(NULL,sfx_bossit); // killough 3/26/98: only generates sound now +} + +void A_BrainPain(mobj_t *mo) +{ + S_StartSound(NULL,sfx_bospn); +} + +void A_BrainScream(mobj_t *mo) +{ + int x; + for (x=mo->x - 196*FRACUNIT ; x< mo->x + 320*FRACUNIT ; x+= FRACUNIT*8) + { + int y = mo->y - 320*FRACUNIT; + int z = 128 + P_Random(pr_brainscream)*2*FRACUNIT; + mobj_t *th = P_SpawnMobj (x,y,z, MT_ROCKET); + th->momz = P_Random(pr_brainscream)*512; + P_SetMobjState(th, S_BRAINEXPLODE1); + th->tics -= P_Random(pr_brainscream)&7; + if (th->tics < 1) + th->tics = 1; + } + S_StartSound(NULL,sfx_bosdth); +} + +void A_BrainExplode(mobj_t *mo) +{ // killough 5/5/98: remove dependence on order of evaluation: + int t = P_Random(pr_brainexp); + int x = mo->x + (t - P_Random(pr_brainexp))*2048; + int y = mo->y; + int z = 128 + P_Random(pr_brainexp)*2*FRACUNIT; + mobj_t *th = P_SpawnMobj(x,y,z, MT_ROCKET); + th->momz = P_Random(pr_brainexp)*512; + P_SetMobjState(th, S_BRAINEXPLODE1); + th->tics -= P_Random(pr_brainexp)&7; + if (th->tics < 1) + th->tics = 1; +} + +void A_BrainDie(mobj_t *mo) +{ + G_ExitLevel(); +} + +void A_BrainSpit(mobj_t *mo) +{ + mobj_t *targ, *newmobj; + + if (!numbraintargets) // killough 4/1/98: ignore if no targets + return; + + brain.easy ^= 1; // killough 3/26/98: use brain struct + if (gameskill <= sk_easy && !brain.easy) + return; + + // shoot a cube at current target + targ = braintargets[brain.targeton++]; // killough 3/26/98: + brain.targeton %= numbraintargets; // Use brain struct for targets + + // spawn brain missile + newmobj = P_SpawnMissile(mo, targ, MT_SPAWNSHOT); + P_SetTarget(&newmobj->target, targ); + newmobj->reactiontime = (short)(((targ->y-mo->y)/newmobj->momy)/newmobj->state->tics); + + // killough 7/18/98: brain friendliness is transferred + newmobj->flags = (newmobj->flags & ~MF_FRIEND) | (mo->flags & MF_FRIEND); + + // killough 8/29/98: add to appropriate thread + P_UpdateThinker(&newmobj->thinker); + + S_StartSound(NULL, sfx_bospit); +} + +// travelling cube sound +void A_SpawnSound(mobj_t *mo) +{ + S_StartSound(mo,sfx_boscub); + A_SpawnFly(mo); +} + +void A_SpawnFly(mobj_t *mo) +{ + mobj_t *newmobj; + mobj_t *fog; + mobj_t *targ; + int r; + mobjtype_t type; + + if (--mo->reactiontime) + return; // still flying + + targ = mo->target; + + // First spawn teleport fog. + fog = P_SpawnMobj(targ->x, targ->y, targ->z, MT_SPAWNFIRE); + S_StartSound(fog, sfx_telept); + + // Randomly select monster to spawn. + r = P_Random(pr_spawnfly); + + // Probability distribution (kind of :), decreasing likelihood. + if ( r<50 ) + type = MT_TROOP; + else if (r<90) + type = MT_SERGEANT; + else if (r<120) + type = MT_SHADOWS; + else if (r<130) + type = MT_PAIN; + else if (r<160) + type = MT_HEAD; + else if (r<162) + type = MT_VILE; + else if (r<172) + type = MT_UNDEAD; + else if (r<192) + type = MT_BABY; + else if (r<222) + type = MT_FATSO; + else if (r<246) + type = MT_KNIGHT; + else + type = MT_BRUISER; + + newmobj = P_SpawnMobj(targ->x, targ->y, targ->z, type); + + /* killough 7/18/98: brain friendliness is transferred */ + newmobj->flags = (newmobj->flags & ~MF_FRIEND) | (mo->flags & MF_FRIEND); + + /* killough 8/29/98: add to appropriate thread */ + P_UpdateThinker(&newmobj->thinker); + + if (P_LookForTargets(newmobj,true)) /* killough 9/4/98 */ + P_SetMobjState(newmobj, newmobj->info->seestate); + + // telefrag anything in this spot + P_TeleportMove(newmobj, newmobj->x, newmobj->y, true); /* killough 8/9/98 */ + + // remove self (i.e., cube). + P_RemoveMobj(mo); +} + +void A_PlayerScream(mobj_t *mo) +{ + int sound = sfx_pldeth; // Default death sound. + if (gamemode != shareware && mo->health < -50) + sound = sfx_pdiehi; // IF THE PLAYER DIES LESS THAN -50% WITHOUT GIBBING + S_StartSound(mo, sound); +} + +/* cph - MBF-added codepointer functions */ + +// killough 11/98: kill an object +void A_Die(mobj_t *actor) +{ + P_DamageMobj(actor, NULL, NULL, actor->health); +} + +// +// A_Detonate +// killough 8/9/98: same as A_Explode, except that the damage is variable +// + +void A_Detonate(mobj_t *mo) +{ + P_RadiusAttack(mo, mo->target, mo->info->damage); +} + +// +// killough 9/98: a mushroom explosion effect, sorta :) +// Original idea: Linguica +// + +void A_Mushroom(mobj_t *actor) +{ + int i, j, n = actor->info->damage; + + A_Explode(actor); // First make normal explosion + + // Now launch mushroom cloud + for (i = -n; i <= n; i += 8) + for (j = -n; j <= n; j += 8) + { + mobj_t target = *actor, *mo; + target.x += i << FRACBITS; // Aim in many directions from source + target.y += j << FRACBITS; + target.z += P_AproxDistance(i,j) << (FRACBITS+2); // Aim up fairly high + mo = P_SpawnMissile(actor, &target, MT_FATSHOT); // Launch fireball + mo->momx >>= 1; + mo->momy >>= 1; // Slow it down a bit + mo->momz >>= 1; + mo->flags &= ~MF_NOGRAVITY; // Make debris fall under gravity + } +} + +// +// killough 11/98 +// +// The following were inspired by Len Pitre +// +// A small set of highly-sought-after code pointers +// + +void A_Spawn(mobj_t *mo) +{ + if (mo->state->misc1) + { + /* mobj_t *newmobj = */ + P_SpawnMobj(mo->x, mo->y, (mo->state->misc2 << FRACBITS) + mo->z, + mo->state->misc1 - 1); + /* CPhipps - no friendlyness (yet) + newmobj->flags = (newmobj->flags & ~MF_FRIEND) | (mo->flags & MF_FRIEND); + */ + } +} + +void A_Turn(mobj_t *mo) +{ + mo->angle += (unsigned int)(((uint_64_t) mo->state->misc1 << 32) / 360); +} + +void A_Face(mobj_t *mo) +{ + mo->angle = (unsigned int)(((uint_64_t) mo->state->misc1 << 32) / 360); +} + +void A_Scratch(mobj_t *mo) +{ + mo->target && (A_FaceTarget(mo), P_CheckMeleeRange(mo)) ? + mo->state->misc2 ? S_StartSound(mo, mo->state->misc2) : (void) 0, + P_DamageMobj(mo->target, mo, mo, mo->state->misc1) : (void) 0; +} + +void A_PlaySound(mobj_t *mo) +{ + S_StartSound(mo->state->misc2 ? NULL : mo, mo->state->misc1); +} + +void A_RandomJump(mobj_t *mo) +{ + if (P_Random(pr_randomjump) < mo->state->misc2) + P_SetMobjState(mo, mo->state->misc1); +} + +// +// This allows linedef effects to be activated inside deh frames. +// + +void A_LineEffect(mobj_t *mo) +{ + static line_t junk; + player_t player; + player_t *oldplayer; + junk = *lines; + oldplayer = mo->player; + mo->player = &player; + player.health = 100; + junk.special = (short)mo->state->misc1; + if (!junk.special) + return; + junk.tag = (short)mo->state->misc2; + if (!P_UseSpecialLine(mo, &junk, 0)) + P_CrossSpecialLine(&junk, 0, mo); + mo->state->misc1 = junk.special; + mo->player = oldplayer; +} diff --git a/common/prboom/p_enemy.h b/common/prboom/p_enemy.h new file mode 100755 index 0000000..3c85861 --- /dev/null +++ b/common/prboom/p_enemy.h @@ -0,0 +1,118 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Enemy thinking, AI. + * Action Pointer Functions + * that are associated with states/frames. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __P_ENEMY__ +#define __P_ENEMY__ + +#include "p_mobj.h" + +void P_NoiseAlert (mobj_t *target, mobj_t *emmiter); +void P_SpawnBrainTargets(void); /* killough 3/26/98: spawn icon landings */ + +extern struct brain_s { /* killough 3/26/98: global state of boss brain */ + int easy, targeton; +} brain; + +// ******************************************************************** +// Function addresses or Code Pointers +// ******************************************************************** +// These function addresses are the Code Pointers that have been +// modified for years by Dehacked enthusiasts. The new BEX format +// allows more extensive changes (see d_deh.c) + +// Doesn't work with g++, needs actionf_p1 +void A_Explode(); +void A_Pain(); +void A_PlayerScream(); +void A_Fall(); +void A_XScream(); +void A_Look(); +void A_Chase(); +void A_FaceTarget(); +void A_PosAttack(); +void A_Scream(); +void A_SPosAttack(); +void A_VileChase(); +void A_VileStart(); +void A_VileTarget(); +void A_VileAttack(); +void A_StartFire(); +void A_Fire(); +void A_FireCrackle(); +void A_Tracer(); +void A_SkelWhoosh(); +void A_SkelFist(); +void A_SkelMissile(); +void A_FatRaise(); +void A_FatAttack1(); +void A_FatAttack2(); +void A_FatAttack3(); +void A_BossDeath(); +void A_CPosAttack(); +void A_CPosRefire(); +void A_TroopAttack(); +void A_SargAttack(); +void A_HeadAttack(); +void A_BruisAttack(); +void A_SkullAttack(); +void A_Metal(); +void A_SpidRefire(); +void A_BabyMetal(); +void A_BspiAttack(); +void A_Hoof(); +void A_CyberAttack(); +void A_PainAttack(); +void A_PainDie(); +void A_KeenDie(); +void A_BrainPain(); +void A_BrainScream(); +void A_BrainDie(); +void A_BrainAwake(); +void A_BrainSpit(); +void A_SpawnSound(); +void A_SpawnFly(); +void A_BrainExplode(); +void A_Die(); +void A_Detonate(); /* killough 8/9/98: detonate a bomb or other device */ +void A_Mushroom(); /* killough 10/98: mushroom effect */ +void A_Spawn(); // killough 11/98 +void A_Turn(); // killough 11/98 +void A_Face(); // killough 11/98 +void A_Scratch(); // killough 11/98 +void A_PlaySound(); // killough 11/98 +void A_RandomJump(); // killough 11/98 +void A_LineEffect(); // killough 11/98 + +#endif // __P_ENEMY__ diff --git a/common/prboom/p_floor.c b/common/prboom/p_floor.c new file mode 100755 index 0000000..ba55fdf --- /dev/null +++ b/common/prboom/p_floor.c @@ -0,0 +1,1042 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * General plane mover and floor mover action routines + * Floor motion, pure changer types, raising stairs. donuts, elevators + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" +#include "r_main.h" +#include "p_map.h" +#include "p_spec.h" +#include "p_tick.h" +#include "s_sound.h" +#include "sounds.h" + +/////////////////////////////////////////////////////////////////////// +// +// Plane (floor or ceiling), Floor motion and Elevator action routines +// +/////////////////////////////////////////////////////////////////////// + +// +// T_MovePlane() +// +// Move a plane (floor or ceiling) and check for crushing. Called +// every tick by all actions that move floors or ceilings. +// +// Passed the sector to move a plane in, the speed to move it at, +// the dest height it is to achieve, whether it crushes obstacles, +// whether it moves a floor or ceiling, and the direction up or down +// to move. +// +// Returns a result_e: +// ok - plane moved normally, has not achieved destination yet +// pastdest - plane moved normally and is now at destination height +// crushed - plane encountered an obstacle, is holding until removed +// +result_e T_MovePlane +( sector_t* sector, + fixed_t speed, + fixed_t dest, + boolean crush, + int floorOrCeiling, + int direction ) +{ + boolean flag; + fixed_t lastpos; + fixed_t destheight; //jff 02/04/98 used to keep floors/ceilings + // from moving thru each other + + switch(floorOrCeiling) + { + case 0: + // Moving a floor + switch(direction) + { + case -1: + // Moving a floor down + if (sector->floorheight - speed < dest) + { + lastpos = sector->floorheight; + sector->floorheight = dest; + flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk + if (flag == true) + { + sector->floorheight =lastpos; + P_CheckSector(sector,crush); //jff 3/19/98 use faster chk + } + return pastdest; + } + else + { + lastpos = sector->floorheight; + sector->floorheight -= speed; + flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk + /* cph - make more compatible with original Doom, by + * reintroducing this code. This means floors can't lower + * if objects are stuck in the ceiling */ + if ((flag == true) && comp[comp_floors]) { + sector->floorheight = lastpos; + P_ChangeSector(sector,crush); + return crushed; + } + } + break; + + case 1: + // Moving a floor up + // jff 02/04/98 keep floor from moving thru ceilings + // jff 2/22/98 weaken check to demo_compatibility + destheight = (comp[comp_floors] || destceilingheight)? + dest : sector->ceilingheight; + if (sector->floorheight + speed > destheight) + { + lastpos = sector->floorheight; + sector->floorheight = destheight; + flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk + if (flag == true) + { + sector->floorheight = lastpos; + P_CheckSector(sector,crush); //jff 3/19/98 use faster chk + } + return pastdest; + } + else + { + // crushing is possible + lastpos = sector->floorheight; + sector->floorheight += speed; + flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk + if (flag == true) + { + /* jff 1/25/98 fix floor crusher */ + if (comp[comp_floors]) { + if (crush == true) + return crushed; + } + sector->floorheight = lastpos; + P_CheckSector(sector,crush); //jff 3/19/98 use faster chk + return crushed; + } + } + break; + } + break; + + case 1: + // moving a ceiling + switch(direction) + { + case -1: + // moving a ceiling down + // jff 02/04/98 keep ceiling from moving thru floors + // jff 2/22/98 weaken check to demo_compatibility + destheight = (comp[comp_floors] || dest>sector->floorheight)? + dest : sector->floorheight; + if (sector->ceilingheight - speed < destheight) + { + lastpos = sector->ceilingheight; + sector->ceilingheight = destheight; + flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk + + if (flag == true) + { + sector->ceilingheight = lastpos; + P_CheckSector(sector,crush); //jff 3/19/98 use faster chk + } + return pastdest; + } + else + { + // crushing is possible + lastpos = sector->ceilingheight; + sector->ceilingheight -= speed; + flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk + + if (flag == true) + { + if (crush == true) + return crushed; + sector->ceilingheight = lastpos; + P_CheckSector(sector,crush); //jff 3/19/98 use faster chk + return crushed; + } + } + break; + + case 1: + // moving a ceiling up + if (sector->ceilingheight + speed > dest) + { + lastpos = sector->ceilingheight; + sector->ceilingheight = dest; + flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk + if (flag == true) + { + sector->ceilingheight = lastpos; + P_CheckSector(sector,crush); //jff 3/19/98 use faster chk + } + return pastdest; + } + else + { + lastpos = sector->ceilingheight; + sector->ceilingheight += speed; + flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk + } + break; + } + break; + } + return ok; +} + +// +// T_MoveFloor() +// +// Move a floor to it's destination (up or down). +// Called once per tick for each moving floor. +// +// Passed a floormove_t structure that contains all pertinent info about the +// move. See P_SPEC.H for fields. +// No return. +// +// jff 02/08/98 all cases with labels beginning with gen added to support +// generalized line type behaviors. + +void T_MoveFloor(floormove_t* floor) +{ + result_e res; + + res = T_MovePlane // move the floor + ( + floor->sector, + floor->speed, + floor->floordestheight, + floor->crush, + 0, + floor->direction + ); + + if (!(leveltime&7)) // make the floormove sound + S_StartSound((mobj_t *)&floor->sector->soundorg, sfx_stnmov); + + if (res == pastdest) // if destination height is reached + { + if (floor->direction == 1) // going up + { + switch(floor->type) // handle texture/type changes + { + case donutRaise: + floor->sector->special = floor->newspecial; + floor->sector->floorpic = floor->texture; + break; + case genFloorChgT: + case genFloorChg0: + floor->sector->special = floor->newspecial; + //jff add to fix bug in special transfers from changes + floor->sector->oldspecial = floor->oldspecial; + //fall thru + case genFloorChg: + floor->sector->floorpic = floor->texture; + break; + default: + break; + } + } + else if (floor->direction == -1) // going down + { + switch(floor->type) // handle texture/type changes + { + case lowerAndChange: + floor->sector->special = floor->newspecial; + //jff add to fix bug in special transfers from changes + floor->sector->oldspecial = floor->oldspecial; + floor->sector->floorpic = floor->texture; + break; + case genFloorChgT: + case genFloorChg0: + floor->sector->special = floor->newspecial; + //jff add to fix bug in special transfers from changes + floor->sector->oldspecial = floor->oldspecial; + //fall thru + case genFloorChg: + floor->sector->floorpic = floor->texture; + break; + default: + break; + } + } + + floor->sector->floordata = NULL; //jff 2/22/98 + P_RemoveThinker(&floor->thinker);//remove this floor from list of movers + + //jff 2/26/98 implement stair retrigger lockout while still building + // note this only applies to the retriggerable generalized stairs + + if (floor->sector->stairlock==-2) // if this sector is stairlocked + { + sector_t *sec = floor->sector; + sec->stairlock=-1; // thinker done, promote lock to -1 + + while (sec->prevsec!=-1 && sectors[sec->prevsec].stairlock!=-2) + sec = §ors[sec->prevsec]; // search for a non-done thinker + if (sec->prevsec==-1) // if all thinkers previous are done + { + sec = floor->sector; // search forward + while (sec->nextsec!=-1 && sectors[sec->nextsec].stairlock!=-2) + sec = §ors[sec->nextsec]; + if (sec->nextsec==-1) // if all thinkers ahead are done too + { + while (sec->prevsec!=-1) // clear all locks + { + sec->stairlock = 0; + sec = §ors[sec->prevsec]; + } + sec->stairlock = 0; + } + } + } + + // make floor stop sound + S_StartSound((mobj_t *)&floor->sector->soundorg, sfx_pstop); + } +} + +// +// T_MoveElevator() +// +// Move an elevator to it's destination (up or down) +// Called once per tick for each moving floor. +// +// Passed an elevator_t structure that contains all pertinent info about the +// move. See P_SPEC.H for fields. +// No return. +// +// jff 02/22/98 added to support parallel floor/ceiling motion +// +void T_MoveElevator(elevator_t* elevator) +{ + result_e res; + + if (elevator->direction<0) // moving down + { + res = T_MovePlane //jff 4/7/98 reverse order of ceiling/floor + ( + elevator->sector, + elevator->speed, + elevator->ceilingdestheight, + 0, + 1, // move floor + elevator->direction + ); + if (res==ok || res==pastdest) // jff 4/7/98 don't move ceil if blocked + T_MovePlane + ( + elevator->sector, + elevator->speed, + elevator->floordestheight, + 0, + 0, // move ceiling + elevator->direction + ); + } + else // up + { + res = T_MovePlane //jff 4/7/98 reverse order of ceiling/floor + ( + elevator->sector, + elevator->speed, + elevator->floordestheight, + 0, + 0, // move ceiling + elevator->direction + ); + if (res==ok || res==pastdest) // jff 4/7/98 don't move floor if blocked + T_MovePlane + ( + elevator->sector, + elevator->speed, + elevator->ceilingdestheight, + 0, + 1, // move floor + elevator->direction + ); + } + + // make floor move sound + if (!(leveltime&7)) + S_StartSound((mobj_t *)&elevator->sector->soundorg, sfx_stnmov); + + if (res == pastdest) // if destination height acheived + { + elevator->sector->floordata = NULL; //jff 2/22/98 + elevator->sector->ceilingdata = NULL; //jff 2/22/98 + P_RemoveThinker(&elevator->thinker); // remove elevator from actives + + // make floor stop sound + S_StartSound((mobj_t *)&elevator->sector->soundorg, sfx_pstop); + } +} + +/////////////////////////////////////////////////////////////////////// +// +// Floor motion linedef handlers +// +/////////////////////////////////////////////////////////////////////// + +// +// EV_DoFloor() +// +// Handle regular and extended floor types +// +// Passed the line that activated the floor and the type of floor motion +// Returns true if a thinker was created. +// +int EV_DoFloor +( line_t* line, + floor_e floortype ) +{ + int secnum; + int rtn; + int i; + sector_t* sec; + floormove_t* floor; + + secnum = -1; + rtn = 0; + // move all floors with the same tag as the linedef + while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) + { + sec = §ors[secnum]; + + // Don't start a second thinker on the same floor + if (P_SectorActive(floor_special,sec)) //jff 2/23/98 + continue; + + // new floor thinker + rtn = 1; + floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0); + memset(floor, 0, sizeof(*floor)); + P_AddThinker (&floor->thinker); + sec->floordata = floor; //jff 2/22/98 + floor->thinker.function = T_MoveFloor; + floor->type = floortype; + floor->crush = false; + + // setup the thinker according to the linedef type + switch(floortype) + { + case lowerFloor: + floor->direction = -1; + floor->sector = sec; + floor->speed = FLOORSPEED; + floor->floordestheight = P_FindHighestFloorSurrounding(sec); + break; + + //jff 02/03/30 support lowering floor by 24 absolute + case lowerFloor24: + floor->direction = -1; + floor->sector = sec; + floor->speed = FLOORSPEED; + floor->floordestheight = floor->sector->floorheight + 24 * FRACUNIT; + break; + + //jff 02/03/30 support lowering floor by 32 absolute (fast) + case lowerFloor32Turbo: + floor->direction = -1; + floor->sector = sec; + floor->speed = FLOORSPEED*4; + floor->floordestheight = floor->sector->floorheight + 32 * FRACUNIT; + break; + + case lowerFloorToLowest: + floor->direction = -1; + floor->sector = sec; + floor->speed = FLOORSPEED; + floor->floordestheight = P_FindLowestFloorSurrounding(sec); + break; + + //jff 02/03/30 support lowering floor to next lowest floor + case lowerFloorToNearest: + floor->direction = -1; + floor->sector = sec; + floor->speed = FLOORSPEED; + floor->floordestheight = + P_FindNextLowestFloor(sec,floor->sector->floorheight); + break; + + case turboLower: + floor->direction = -1; + floor->sector = sec; + floor->speed = FLOORSPEED * 4; + floor->floordestheight = P_FindHighestFloorSurrounding(sec); + if (floor->floordestheight != sec->floorheight) + floor->floordestheight += 8*FRACUNIT; + break; + + case raiseFloorCrush: + floor->crush = true; + case raiseFloor: + floor->direction = 1; + floor->sector = sec; + floor->speed = FLOORSPEED; + floor->floordestheight = P_FindLowestCeilingSurrounding(sec); + if (floor->floordestheight > sec->ceilingheight) + floor->floordestheight = sec->ceilingheight; + floor->floordestheight -= (8*FRACUNIT)*(floortype == raiseFloorCrush); + break; + + case raiseFloorTurbo: + floor->direction = 1; + floor->sector = sec; + floor->speed = FLOORSPEED*4; + floor->floordestheight = P_FindNextHighestFloor(sec,sec->floorheight); + break; + + case raiseFloorToNearest: + floor->direction = 1; + floor->sector = sec; + floor->speed = FLOORSPEED; + floor->floordestheight = P_FindNextHighestFloor(sec,sec->floorheight); + break; + + case raiseFloor24: + floor->direction = 1; + floor->sector = sec; + floor->speed = FLOORSPEED; + floor->floordestheight = floor->sector->floorheight + 24 * FRACUNIT; + break; + + // jff 2/03/30 support straight raise by 32 (fast) + case raiseFloor32Turbo: + floor->direction = 1; + floor->sector = sec; + floor->speed = FLOORSPEED*4; + floor->floordestheight = floor->sector->floorheight + 32 * FRACUNIT; + break; + + case raiseFloor512: + floor->direction = 1; + floor->sector = sec; + floor->speed = FLOORSPEED; + floor->floordestheight = floor->sector->floorheight + 512 * FRACUNIT; + break; + + case raiseFloor24AndChange: + floor->direction = 1; + floor->sector = sec; + floor->speed = FLOORSPEED; + floor->floordestheight = floor->sector->floorheight + 24 * FRACUNIT; + sec->floorpic = line->frontsector->floorpic; + sec->special = line->frontsector->special; + //jff 3/14/98 transfer both old and new special + sec->oldspecial = line->frontsector->oldspecial; + break; + + case raiseToTexture: + { + int minsize = INT_MAX; + side_t* side; + + /* jff 3/13/98 no ovf */ + if (!comp[comp_model]) minsize = 32000<direction = 1; + floor->sector = sec; + floor->speed = FLOORSPEED; + for (i = 0; i < sec->linecount; i++) + { + if (twoSided (secnum, i) ) + { + side = getSide(secnum,i,0); + // jff 8/14/98 don't scan texture 0, its not real + if (side->bottomtexture > 0 || + (comp[comp_model] && !side->bottomtexture)) + if (textureheight[side->bottomtexture] < minsize) + minsize = textureheight[side->bottomtexture]; + side = getSide(secnum,i,1); + // jff 8/14/98 don't scan texture 0, its not real + if (side->bottomtexture > 0 || + (comp[comp_model] && !side->bottomtexture)) + if (textureheight[side->bottomtexture] < minsize) + minsize = textureheight[side->bottomtexture]; + } + } + if (comp[comp_model]) + floor->floordestheight = floor->sector->floorheight + minsize; + else + { + floor->floordestheight = + (floor->sector->floorheight>>FRACBITS) + (minsize>>FRACBITS); + if (floor->floordestheight>32000) + floor->floordestheight = 32000; //jff 3/13/98 do not + floor->floordestheight<<=FRACBITS; // allow height overflow + } + } + break; + + case lowerAndChange: + floor->direction = -1; + floor->sector = sec; + floor->speed = FLOORSPEED; + floor->floordestheight = P_FindLowestFloorSurrounding(sec); + floor->texture = sec->floorpic; + + // jff 1/24/98 make sure floor->newspecial gets initialized + // in case no surrounding sector is at floordestheight + // --> should not affect compatibility <-- + floor->newspecial = sec->special; + //jff 3/14/98 transfer both old and new special + floor->oldspecial = sec->oldspecial; + + //jff 5/23/98 use model subroutine to unify fixes and handling + sec = P_FindModelFloorSector(floor->floordestheight,sec-sectors); + if (sec) + { + floor->texture = sec->floorpic; + floor->newspecial = sec->special; + //jff 3/14/98 transfer both old and new special + floor->oldspecial = sec->oldspecial; + } + break; + default: + break; + } + } + return rtn; +} + +// +// EV_DoChange() +// +// Handle pure change types. These change floor texture and sector type +// by trigger or numeric model without moving the floor. +// +// The linedef causing the change and the type of change is passed +// Returns true if any sector changes +// +// jff 3/15/98 added to better support generalized sector types +// +int EV_DoChange +( line_t* line, + change_e changetype ) +{ + int secnum; + int rtn; + sector_t* sec; + sector_t* secm; + + secnum = -1; + rtn = 0; + // change all sectors with the same tag as the linedef + while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) + { + sec = §ors[secnum]; + + rtn = 1; + + // handle trigger or numeric change type + switch(changetype) + { + case trigChangeOnly: + sec->floorpic = line->frontsector->floorpic; + sec->special = line->frontsector->special; + sec->oldspecial = line->frontsector->oldspecial; + break; + case numChangeOnly: + secm = P_FindModelFloorSector(sec->floorheight,secnum); + if (secm) // if no model, no change + { + sec->floorpic = secm->floorpic; + sec->special = secm->special; + sec->oldspecial = secm->oldspecial; + } + break; + default: + break; + } + } + return rtn; +} + +/* + * EV_BuildStairs() + * + * Handles staircase building. A sequence of sectors chosen by algorithm + * rise at a speed indicated to a height that increases by the stepsize + * each step. + * + * Passed the linedef triggering the stairs and the type of stair rise + * Returns true if any thinkers are created + * + * cph 2001/09/21 - compatibility nightmares again + * There are three different ways this function has, during its history, stepped + * through all the stairs to be triggered by the single switch + * - original Doom used a linear P_FindSectorFromLineTag, but failed to preserve + * the index of the previous sector found, so instead it would restart its + * linear search from the last sector of the previous staircase + * - MBF/PrBoom with comp_stairs fail to emulate this, because their + * P_FindSectorFromLineTag is a chained hash table implementation. Instead they + * start following the hash chain from the last sector of the previous + * staircase, which will (probably) have the wrong tag, so they miss any further + * stairs + * - Boom fixed the bug, and MBF/PrBoom without comp_stairs work right + */ +static inline int P_FindSectorFromLineTagWithLowerBound +(line_t* l, int start, int min) +{ + /* Emulate original Doom's linear lower-bounded P_FindSectorFromLineTag + * as needed */ + do { + start = P_FindSectorFromLineTag(l,start); + } while (start >= 0 && start <= min); + return start; +} + +int EV_BuildStairs +( line_t* line, + stair_e type ) +{ + /* cph 2001/09/22 - cleaned up this function to save my sanity. A separate + * outer loop index makes the logic much cleared, and local variables moved + * into the inner blocks helps too */ + int ssec = -1; + int minssec = -1; + int rtn = 0; + + // start a stair at each sector tagged the same as the linedef + while ((ssec = P_FindSectorFromLineTagWithLowerBound(line,ssec,minssec)) >= 0) + { + int secnum = ssec; + sector_t* sec = §ors[secnum]; + + // don't start a stair if the first step's floor is already moving + if (!P_SectorActive(floor_special,sec)) { //jff 2/22/98 + floormove_t* floor; + int texture, height; + fixed_t stairsize; + fixed_t speed; + int ok; + + // create new floor thinker for first step + rtn = 1; + floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0); + memset(floor, 0, sizeof(*floor)); + P_AddThinker (&floor->thinker); + sec->floordata = floor; + floor->thinker.function = T_MoveFloor; + floor->direction = 1; + floor->sector = sec; + floor->type = buildStair; //jff 3/31/98 do not leave uninited + + // set up the speed and stepsize according to the stairs type + switch(type) + { + default: // killough -- prevent compiler warning + case build8: + speed = FLOORSPEED/4; + stairsize = 8*FRACUNIT; + if (!demo_compatibility) + floor->crush = false; //jff 2/27/98 fix uninitialized crush field + break; + case turbo16: + speed = FLOORSPEED*4; + stairsize = 16*FRACUNIT; + if (!demo_compatibility) + floor->crush = true; //jff 2/27/98 fix uninitialized crush field + break; + } + floor->speed = speed; + height = sec->floorheight + stairsize; + floor->floordestheight = height; + + texture = sec->floorpic; + + // Find next sector to raise + // 1. Find 2-sided line with same sector side[0] (lowest numbered) + // 2. Other side is the next sector to raise + // 3. Unless already moving, or different texture, then stop building + do + { + int i; + ok = 0; + + for (i = 0;i < sec->linecount;i++) + { + sector_t* tsec = (sec->lines[i])->frontsector; + int newsecnum; + if ( !((sec->lines[i])->flags & ML_TWOSIDED) ) + continue; + + newsecnum = tsec-sectors; + + if (secnum != newsecnum) + continue; + + tsec = (sec->lines[i])->backsector; + if (!tsec) continue; //jff 5/7/98 if no backside, continue + newsecnum = tsec - sectors; + + // if sector's floor is different texture, look for another + if (tsec->floorpic != texture) + continue; + + /* jff 6/19/98 prevent double stepsize + * killough 10/98: intentionally left this way [MBF comment] + * cph 2001/02/06: stair bug fix should be controlled by comp_stairs, + * except if we're emulating MBF which perversly reverted the fix + */ + if (comp[comp_stairs] || (compatibility_level == mbf_compatibility)) + height += stairsize; // jff 6/28/98 change demo compatibility + + // if sector's floor already moving, look for another + if (P_SectorActive(floor_special,tsec)) //jff 2/22/98 + continue; + + /* cph - see comment above - do this iff we didn't do so above */ + if (!comp[comp_stairs] && (compatibility_level != mbf_compatibility)) + height += stairsize; + + sec = tsec; + secnum = newsecnum; + + // create and initialize a thinker for the next step + floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0); + memset(floor, 0, sizeof(*floor)); + P_AddThinker (&floor->thinker); + + sec->floordata = floor; //jff 2/22/98 + floor->thinker.function = T_MoveFloor; + floor->direction = 1; + floor->sector = sec; + floor->speed = speed; + floor->floordestheight = height; + floor->type = buildStair; //jff 3/31/98 do not leave uninited + //jff 2/27/98 fix uninitialized crush field + if (!demo_compatibility) + floor->crush = type==build8? false : true; + ok = 1; + break; + } + } while(ok); // continue until no next step is found + + } + /* killough 10/98: compatibility option */ + if (comp[comp_stairs]) { + /* cph 2001/09/22 - emulate buggy MBF comp_stairs for demos, with logic + * reversed since we now have a separate outer loop index. + * DEMOSYNC - what about boom_compatibility_compatibility? + */ + if ((compatibility_level >= mbf_compatibility) && (compatibility_level < + prboom_3_compatibility)) ssec = secnum; /* Trash outer loop index */ + else { + /* cph 2001/09/22 - now the correct comp_stairs - Doom used a linear + * search from the last secnum, so we set that as a minimum value and do + * a fresh tag search + */ + ssec = -1; minssec = secnum; + } + } + } + return rtn; +} + +// +// EV_DoDonut() +// +// Handle donut function: lower pillar, raise surrounding pool, both to height, +// texture and type of the sector surrounding the pool. +// +// Passed the linedef that triggered the donut +// Returns whether a thinker was created +// +int EV_DoDonut(line_t* line) +{ + sector_t* s1; + sector_t* s2; + sector_t* s3; + int secnum; + int rtn; + int i; + floormove_t* floor; + + secnum = -1; + rtn = 0; + // do function on all sectors with same tag as linedef + while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) + { + s1 = §ors[secnum]; // s1 is pillar's sector + + // do not start the donut if the pillar is already moving + if (P_SectorActive(floor_special,s1)) //jff 2/22/98 + continue; + + s2 = getNextSector(s1->lines[0],s1); // s2 is pool's sector + if (!s2) continue; // note lowest numbered line around + // pillar must be two-sided + + /* do not start the donut if the pool is already moving + * cph - DEMOSYNC - was !compatibility */ + if (!comp[comp_floors] && P_SectorActive(floor_special,s2)) + continue; //jff 5/7/98 + + // find a two sided line around the pool whose other side isn't the pillar + for (i = 0;i < s2->linecount;i++) + { + //jff 3/29/98 use true two-sidedness, not the flag + // killough 4/5/98: changed demo_compatibility to compatibility + if (comp[comp_model]) + { + if ((!s2->lines[i]->flags & ML_TWOSIDED) || + (s2->lines[i]->backsector == s1)) + continue; + } + else if (!s2->lines[i]->backsector || s2->lines[i]->backsector == s1) + continue; + + rtn = 1; //jff 1/26/98 no donut action - no switch change on return + + s3 = s2->lines[i]->backsector; // s3 is model sector for changes + + // Spawn rising slime + floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0); + memset(floor, 0, sizeof(*floor)); + P_AddThinker (&floor->thinker); + s2->floordata = floor; //jff 2/22/98 + floor->thinker.function = T_MoveFloor; + floor->type = donutRaise; + floor->crush = false; + floor->direction = 1; + floor->sector = s2; + floor->speed = FLOORSPEED / 2; + floor->texture = s3->floorpic; + floor->newspecial = 0; + floor->floordestheight = s3->floorheight; + + // Spawn lowering donut-hole pillar + floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0); + memset(floor, 0, sizeof(*floor)); + P_AddThinker (&floor->thinker); + s1->floordata = floor; //jff 2/22/98 + floor->thinker.function = T_MoveFloor; + floor->type = lowerFloor; + floor->crush = false; + floor->direction = -1; + floor->sector = s1; + floor->speed = FLOORSPEED / 2; + floor->floordestheight = s3->floorheight; + break; + } + } + return rtn; +} + +// +// EV_DoElevator +// +// Handle elevator linedef types +// +// Passed the linedef that triggered the elevator and the elevator action +// +// jff 2/22/98 new type to move floor and ceiling in parallel +// +int EV_DoElevator +( line_t* line, + elevator_e elevtype ) +{ + int secnum; + int rtn; + sector_t* sec; + elevator_t* elevator; + + secnum = -1; + rtn = 0; + // act on all sectors with the same tag as the triggering linedef + while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) + { + sec = §ors[secnum]; + + // If either floor or ceiling is already activated, skip it + if (sec->floordata || sec->ceilingdata) //jff 2/22/98 + continue; + + // create and initialize new elevator thinker + rtn = 1; + elevator = Z_Malloc (sizeof(*elevator), PU_LEVSPEC, 0); + memset(elevator, 0, sizeof(*elevator)); + P_AddThinker (&elevator->thinker); + sec->floordata = elevator; //jff 2/22/98 + sec->ceilingdata = elevator; //jff 2/22/98 + elevator->thinker.function = T_MoveElevator; + elevator->type = elevtype; + + // set up the fields according to the type of elevator action + switch(elevtype) + { + // elevator down to next floor + case elevateDown: + elevator->direction = -1; + elevator->sector = sec; + elevator->speed = ELEVATORSPEED; + elevator->floordestheight = + P_FindNextLowestFloor(sec,sec->floorheight); + elevator->ceilingdestheight = + elevator->floordestheight + sec->ceilingheight - sec->floorheight; + break; + + // elevator up to next floor + case elevateUp: + elevator->direction = 1; + elevator->sector = sec; + elevator->speed = ELEVATORSPEED; + elevator->floordestheight = + P_FindNextHighestFloor(sec,sec->floorheight); + elevator->ceilingdestheight = + elevator->floordestheight + sec->ceilingheight - sec->floorheight; + break; + + // elevator to floor height of activating switch's front sector + case elevateCurrent: + elevator->sector = sec; + elevator->speed = ELEVATORSPEED; + elevator->floordestheight = line->frontsector->floorheight; + elevator->ceilingdestheight = + elevator->floordestheight + sec->ceilingheight - sec->floorheight; + elevator->direction = + elevator->floordestheight>sec->floorheight? 1 : -1; + break; + + default: + break; + } + } + return rtn; +} diff --git a/common/prboom/p_genlin.c b/common/prboom/p_genlin.c new file mode 100755 index 0000000..f0de56d --- /dev/null +++ b/common/prboom/p_genlin.c @@ -0,0 +1,1164 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Generalized linedef type handlers + * Floors, Ceilings, Doors, Locked Doors, Lifts, Stairs, Crushers + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" //jff 6/19/98 for demo_compatibility +#include "r_main.h" +#include "p_spec.h" +#include "p_tick.h" +#include "m_random.h" +#include "s_sound.h" +#include "sounds.h" + +////////////////////////////////////////////////////////// +// +// Generalized Linedef Type handlers +// +////////////////////////////////////////////////////////// + +// +// EV_DoGenFloor() +// +// Handle generalized floor types +// +// Passed the line activating the generalized floor function +// Returns true if a thinker is created +// +// jff 02/04/98 Added this routine (and file) to handle generalized +// floor movers using bit fields in the line special type. +// +int EV_DoGenFloor +( line_t* line ) +{ + int secnum; + int rtn; + boolean manual; + sector_t* sec; + floormove_t* floor; + unsigned value = (unsigned)line->special - GenFloorBase; + + // parse the bit fields in the line's special type + + int Crsh = (value & FloorCrush) >> FloorCrushShift; + int ChgT = (value & FloorChange) >> FloorChangeShift; + int Targ = (value & FloorTarget) >> FloorTargetShift; + int Dirn = (value & FloorDirection) >> FloorDirectionShift; + int ChgM = (value & FloorModel) >> FloorModelShift; + int Sped = (value & FloorSpeed) >> FloorSpeedShift; + int Trig = (value & TriggerType) >> TriggerTypeShift; + + rtn = 0; + + // check if a manual trigger, if so do just the sector on the backside + manual = false; + if (Trig==PushOnce || Trig==PushMany) + { + if (!(sec = line->backsector)) + return rtn; + secnum = sec-sectors; + manual = true; + goto manual_floor; + } + + secnum = -1; + // if not manual do all sectors tagged the same as the line + while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) + { + sec = §ors[secnum]; + +manual_floor: + // Do not start another function if floor already moving + if (P_SectorActive(floor_special,sec)) + { + if (!manual) + continue; + else + return rtn; + } + + // new floor thinker + rtn = 1; + floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0); + memset(floor, 0, sizeof(*floor)); + P_AddThinker (&floor->thinker); + sec->floordata = floor; + floor->thinker.function = T_MoveFloor; + floor->crush = Crsh; + floor->direction = Dirn? 1 : -1; + floor->sector = sec; + floor->texture = sec->floorpic; + floor->newspecial = sec->special; + //jff 3/14/98 transfer old special field too + floor->oldspecial = sec->oldspecial; + floor->type = genFloor; + + // set the speed of motion + switch (Sped) + { + case SpeedSlow: + floor->speed = FLOORSPEED; + break; + case SpeedNormal: + floor->speed = FLOORSPEED*2; + break; + case SpeedFast: + floor->speed = FLOORSPEED*4; + break; + case SpeedTurbo: + floor->speed = FLOORSPEED*8; + break; + default: + break; + } + + // set the destination height + switch(Targ) + { + case FtoHnF: + floor->floordestheight = P_FindHighestFloorSurrounding(sec); + break; + case FtoLnF: + floor->floordestheight = P_FindLowestFloorSurrounding(sec); + break; + case FtoNnF: + floor->floordestheight = Dirn? + P_FindNextHighestFloor(sec,sec->floorheight) : + P_FindNextLowestFloor(sec,sec->floorheight); + break; + case FtoLnC: + floor->floordestheight = P_FindLowestCeilingSurrounding(sec); + break; + case FtoC: + floor->floordestheight = sec->ceilingheight; + break; + case FbyST: + floor->floordestheight = (floor->sector->floorheight>>FRACBITS) + + floor->direction * (P_FindShortestTextureAround(secnum)>>FRACBITS); + if (floor->floordestheight>32000) //jff 3/13/98 prevent overflow + floor->floordestheight=32000; // wraparound in floor height + if (floor->floordestheight<-32000) + floor->floordestheight=-32000; + floor->floordestheight<<=FRACBITS; + break; + case Fby24: + floor->floordestheight = floor->sector->floorheight + + floor->direction * 24*FRACUNIT; + break; + case Fby32: + floor->floordestheight = floor->sector->floorheight + + floor->direction * 32*FRACUNIT; + break; + default: + break; + } + + // set texture/type change properties + if (ChgT) // if a texture change is indicated + { + if (ChgM) // if a numeric model change + { + sector_t *sector; + + //jff 5/23/98 find model with ceiling at target height if target + //is a ceiling type + sector = (Targ==FtoLnC || Targ==FtoC)? + P_FindModelCeilingSector(floor->floordestheight,secnum) : + P_FindModelFloorSector(floor->floordestheight,secnum); + if (sector) + { + floor->texture = sector->floorpic; + switch(ChgT) + { + case FChgZero: // zero type + floor->newspecial = 0; + //jff 3/14/98 change old field too + floor->oldspecial = 0; + floor->type = genFloorChg0; + break; + case FChgTyp: // copy type + floor->newspecial = sector->special; + //jff 3/14/98 change old field too + floor->oldspecial = sector->oldspecial; + floor->type = genFloorChgT; + break; + case FChgTxt: // leave type be + floor->type = genFloorChg; + break; + default: + break; + } + } + } + else // else if a trigger model change + { + floor->texture = line->frontsector->floorpic; + switch (ChgT) + { + case FChgZero: // zero type + floor->newspecial = 0; + //jff 3/14/98 change old field too + floor->oldspecial = 0; + floor->type = genFloorChg0; + break; + case FChgTyp: // copy type + floor->newspecial = line->frontsector->special; + //jff 3/14/98 change old field too + floor->oldspecial = line->frontsector->oldspecial; + floor->type = genFloorChgT; + break; + case FChgTxt: // leave type be + floor->type = genFloorChg; + default: + break; + } + } + } + if (manual) return rtn; + } + return rtn; +} + + +// +// EV_DoGenCeiling() +// +// Handle generalized ceiling types +// +// Passed the linedef activating the ceiling function +// Returns true if a thinker created +// +// jff 02/04/98 Added this routine (and file) to handle generalized +// floor movers using bit fields in the line special type. +// +int EV_DoGenCeiling +( line_t* line ) +{ + int secnum; + int rtn; + boolean manual; + fixed_t targheight; + sector_t* sec; + ceiling_t* ceiling; + unsigned value = (unsigned)line->special - GenCeilingBase; + + // parse the bit fields in the line's special type + + int Crsh = (value & CeilingCrush) >> CeilingCrushShift; + int ChgT = (value & CeilingChange) >> CeilingChangeShift; + int Targ = (value & CeilingTarget) >> CeilingTargetShift; + int Dirn = (value & CeilingDirection) >> CeilingDirectionShift; + int ChgM = (value & CeilingModel) >> CeilingModelShift; + int Sped = (value & CeilingSpeed) >> CeilingSpeedShift; + int Trig = (value & TriggerType) >> TriggerTypeShift; + + rtn = 0; + + // check if a manual trigger, if so do just the sector on the backside + manual = false; + if (Trig==PushOnce || Trig==PushMany) + { + if (!(sec = line->backsector)) + return rtn; + secnum = sec-sectors; + manual = true; + goto manual_ceiling; + } + + secnum = -1; + // if not manual do all sectors tagged the same as the line + while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) + { + sec = §ors[secnum]; + +manual_ceiling: + // Do not start another function if ceiling already moving + if (P_SectorActive(ceiling_special,sec)) //jff 2/22/98 + { + if (!manual) + continue; + else + return rtn; + } + + // new ceiling thinker + rtn = 1; + ceiling = Z_Malloc (sizeof(*ceiling), PU_LEVSPEC, 0); + memset(ceiling, 0, sizeof(*ceiling)); + P_AddThinker (&ceiling->thinker); + sec->ceilingdata = ceiling; //jff 2/22/98 + ceiling->thinker.function = T_MoveCeiling; + ceiling->crush = Crsh; + ceiling->direction = Dirn? 1 : -1; + ceiling->sector = sec; + ceiling->texture = sec->ceilingpic; + ceiling->newspecial = sec->special; + //jff 3/14/98 change old field too + ceiling->oldspecial = sec->oldspecial; + ceiling->tag = sec->tag; + ceiling->type = genCeiling; + + // set speed of motion + switch (Sped) + { + case SpeedSlow: + ceiling->speed = CEILSPEED; + break; + case SpeedNormal: + ceiling->speed = CEILSPEED*2; + break; + case SpeedFast: + ceiling->speed = CEILSPEED*4; + break; + case SpeedTurbo: + ceiling->speed = CEILSPEED*8; + break; + default: + break; + } + + // set destination target height + targheight = sec->ceilingheight; + switch(Targ) + { + case CtoHnC: + targheight = P_FindHighestCeilingSurrounding(sec); + break; + case CtoLnC: + targheight = P_FindLowestCeilingSurrounding(sec); + break; + case CtoNnC: + targheight = Dirn? + P_FindNextHighestCeiling(sec,sec->ceilingheight) : + P_FindNextLowestCeiling(sec,sec->ceilingheight); + break; + case CtoHnF: + targheight = P_FindHighestFloorSurrounding(sec); + break; + case CtoF: + targheight = sec->floorheight; + break; + case CbyST: + targheight = (ceiling->sector->ceilingheight>>FRACBITS) + + ceiling->direction * (P_FindShortestUpperAround(secnum)>>FRACBITS); + if (targheight>32000) //jff 3/13/98 prevent overflow + targheight=32000; // wraparound in ceiling height + if (targheight<-32000) + targheight=-32000; + targheight<<=FRACBITS; + break; + case Cby24: + targheight = ceiling->sector->ceilingheight + + ceiling->direction * 24*FRACUNIT; + break; + case Cby32: + targheight = ceiling->sector->ceilingheight + + ceiling->direction * 32*FRACUNIT; + break; + default: + break; + } + if (Dirn) ceiling->topheight = targheight; + else ceiling->bottomheight = targheight; + + // set texture/type change properties + if (ChgT) // if a texture change is indicated + { + if (ChgM) // if a numeric model change + { + sector_t *sector; + + //jff 5/23/98 find model with floor at target height if target + //is a floor type + sector = (Targ==CtoHnF || Targ==CtoF)? + P_FindModelFloorSector(targheight,secnum) : + P_FindModelCeilingSector(targheight,secnum); + if (sector) + { + ceiling->texture = sector->ceilingpic; + switch (ChgT) + { + case CChgZero: // type is zeroed + ceiling->newspecial = 0; + //jff 3/14/98 change old field too + ceiling->oldspecial = 0; + ceiling->type = genCeilingChg0; + break; + case CChgTyp: // type is copied + ceiling->newspecial = sector->special; + //jff 3/14/98 change old field too + ceiling->oldspecial = sector->oldspecial; + ceiling->type = genCeilingChgT; + break; + case CChgTxt: // type is left alone + ceiling->type = genCeilingChg; + break; + default: + break; + } + } + } + else // else if a trigger model change + { + ceiling->texture = line->frontsector->ceilingpic; + switch (ChgT) + { + case CChgZero: // type is zeroed + ceiling->newspecial = 0; + //jff 3/14/98 change old field too + ceiling->oldspecial = 0; + ceiling->type = genCeilingChg0; + break; + case CChgTyp: // type is copied + ceiling->newspecial = line->frontsector->special; + //jff 3/14/98 change old field too + ceiling->oldspecial = line->frontsector->oldspecial; + ceiling->type = genCeilingChgT; + break; + case CChgTxt: // type is left alone + ceiling->type = genCeilingChg; + break; + default: + break; + } + } + } + P_AddActiveCeiling(ceiling); // add this ceiling to the active list + if (manual) return rtn; + } + return rtn; +} + +// +// EV_DoGenLift() +// +// Handle generalized lift types +// +// Passed the linedef activating the lift +// Returns true if a thinker is created +// +int EV_DoGenLift +( line_t* line ) +{ + plat_t* plat; + int secnum; + int rtn; + boolean manual; + sector_t* sec; + unsigned value = (unsigned)line->special - GenLiftBase; + + // parse the bit fields in the line's special type + + int Targ = (value & LiftTarget) >> LiftTargetShift; + int Dely = (value & LiftDelay) >> LiftDelayShift; + int Sped = (value & LiftSpeed) >> LiftSpeedShift; + int Trig = (value & TriggerType) >> TriggerTypeShift; + + secnum = -1; + rtn = 0; + + // Activate all plats that are in_stasis + + if (Targ==LnF2HnF) + P_ActivateInStasis(line->tag); + + // check if a manual trigger, if so do just the sector on the backside + manual = false; + if (Trig==PushOnce || Trig==PushMany) + { + if (!(sec = line->backsector)) + return rtn; + secnum = sec-sectors; + manual = true; + goto manual_lift; + } + + // if not manual do all sectors tagged the same as the line + while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) + { + sec = §ors[secnum]; + +manual_lift: + // Do not start another function if floor already moving + if (P_SectorActive(floor_special,sec)) + { + if (!manual) + continue; + else + return rtn; + } + + // Setup the plat thinker + rtn = 1; + plat = Z_Malloc( sizeof(*plat), PU_LEVSPEC, 0); + memset(plat, 0, sizeof(*plat)); + P_AddThinker(&plat->thinker); + + plat->sector = sec; + plat->sector->floordata = plat; + plat->thinker.function = T_PlatRaise; + plat->crush = false; + plat->tag = line->tag; + + plat->type = genLift; + plat->high = sec->floorheight; + plat->status = down; + + // setup the target destination height + switch(Targ) + { + case F2LnF: + plat->low = P_FindLowestFloorSurrounding(sec); + if (plat->low > sec->floorheight) + plat->low = sec->floorheight; + break; + case F2NnF: + plat->low = P_FindNextLowestFloor(sec,sec->floorheight); + break; + case F2LnC: + plat->low = P_FindLowestCeilingSurrounding(sec); + if (plat->low > sec->floorheight) + plat->low = sec->floorheight; + break; + case LnF2HnF: + plat->type = genPerpetual; + plat->low = P_FindLowestFloorSurrounding(sec); + if (plat->low > sec->floorheight) + plat->low = sec->floorheight; + plat->high = P_FindHighestFloorSurrounding(sec); + if (plat->high < sec->floorheight) + plat->high = sec->floorheight; + plat->status = P_Random(pr_genlift)&1; + break; + default: + break; + } + + // setup the speed of motion + switch(Sped) + { + case SpeedSlow: + plat->speed = PLATSPEED * 2; + break; + case SpeedNormal: + plat->speed = PLATSPEED * 4; + break; + case SpeedFast: + plat->speed = PLATSPEED * 8; + break; + case SpeedTurbo: + plat->speed = PLATSPEED * 16; + break; + default: + break; + } + + // setup the delay time before the floor returns + switch(Dely) + { + case 0: + plat->wait = 1*35; + break; + case 1: + plat->wait = PLATWAIT*35; + break; + case 2: + plat->wait = 5*35; + break; + case 3: + plat->wait = 10*35; + break; + } + + S_StartSound((mobj_t *)&sec->soundorg,sfx_pstart); + P_AddActivePlat(plat); // add this plat to the list of active plats + + if (manual) + return rtn; + } + return rtn; +} + +// +// EV_DoGenStairs() +// +// Handle generalized stair building +// +// Passed the linedef activating the stairs +// Returns true if a thinker is created +// +int EV_DoGenStairs +( line_t* line ) +{ + int secnum; + int osecnum; //jff 3/4/98 preserve loop index + int height; + int i; + int newsecnum; + int texture; + int ok; + int rtn; + boolean manual; + + sector_t* sec; + sector_t* tsec; + + floormove_t* floor; + + fixed_t stairsize; + fixed_t speed; + + unsigned value = (unsigned)line->special - GenStairsBase; + + // parse the bit fields in the line's special type + + int Igno = (value & StairIgnore) >> StairIgnoreShift; + int Dirn = (value & StairDirection) >> StairDirectionShift; + int Step = (value & StairStep) >> StairStepShift; + int Sped = (value & StairSpeed) >> StairSpeedShift; + int Trig = (value & TriggerType) >> TriggerTypeShift; + + rtn = 0; + + // check if a manual trigger, if so do just the sector on the backside + manual = false; + if (Trig==PushOnce || Trig==PushMany) + { + if (!(sec = line->backsector)) + return rtn; + secnum = sec-sectors; + manual = true; + goto manual_stair; + } + + secnum = -1; + // if not manual do all sectors tagged the same as the line + while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) + { + sec = §ors[secnum]; + +manual_stair: + //Do not start another function if floor already moving + //jff 2/26/98 add special lockout condition to wait for entire + //staircase to build before retriggering + if (P_SectorActive(floor_special,sec) || sec->stairlock) + { + if (!manual) + continue; + else + return rtn; + } + + // new floor thinker + rtn = 1; + floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0); + memset(floor, 0, sizeof(*floor)); + P_AddThinker (&floor->thinker); + sec->floordata = floor; + floor->thinker.function = T_MoveFloor; + floor->direction = Dirn? 1 : -1; + floor->sector = sec; + + // setup speed of stair building + switch(Sped) + { + default: + case SpeedSlow: + floor->speed = FLOORSPEED/4; + break; + case SpeedNormal: + floor->speed = FLOORSPEED/2; + break; + case SpeedFast: + floor->speed = FLOORSPEED*2; + break; + case SpeedTurbo: + floor->speed = FLOORSPEED*4; + break; + } + + // setup stepsize for stairs + switch(Step) + { + default: + case 0: + stairsize = 4*FRACUNIT; + break; + case 1: + stairsize = 8*FRACUNIT; + break; + case 2: + stairsize = 16*FRACUNIT; + break; + case 3: + stairsize = 24*FRACUNIT; + break; + } + + speed = floor->speed; + height = sec->floorheight + floor->direction * stairsize; + floor->floordestheight = height; + texture = sec->floorpic; + floor->crush = false; + floor->type = genBuildStair; // jff 3/31/98 do not leave uninited + + sec->stairlock = -2; // jff 2/26/98 set up lock on current sector + sec->nextsec = -1; + sec->prevsec = -1; + + osecnum = secnum; //jff 3/4/98 preserve loop index + // Find next sector to raise + // 1. Find 2-sided line with same sector side[0] + // 2. Other side is the next sector to raise + do + { + ok = 0; + for (i = 0;i < sec->linecount;i++) + { + if ( !((sec->lines[i])->backsector) ) + continue; + + tsec = (sec->lines[i])->frontsector; + newsecnum = tsec-sectors; + + if (secnum != newsecnum) + continue; + + tsec = (sec->lines[i])->backsector; + newsecnum = tsec - sectors; + + if (!Igno && tsec->floorpic != texture) + continue; + + /* jff 6/19/98 prevent double stepsize */ + if (compatibility_level < boom_202_compatibility) + height += floor->direction * stairsize; + + //jff 2/26/98 special lockout condition for retriggering + if (P_SectorActive(floor_special,tsec) || tsec->stairlock) + continue; + + /* jff 6/19/98 increase height AFTER continue */ + if (compatibility_level >= boom_202_compatibility) + height += floor->direction * stairsize; + + // jff 2/26/98 + // link the stair chain in both directions + // lock the stair sector until building complete + sec->nextsec = newsecnum; // link step to next + tsec->prevsec = secnum; // link next back + tsec->nextsec = -1; // set next forward link as end + tsec->stairlock = -2; // lock the step + + sec = tsec; + secnum = newsecnum; + floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0); + + memset(floor, 0, sizeof(*floor)); + P_AddThinker (&floor->thinker); + + sec->floordata = floor; + floor->thinker.function = T_MoveFloor; + floor->direction = Dirn? 1 : -1; + floor->sector = sec; + floor->speed = speed; + floor->floordestheight = height; + floor->crush = false; + floor->type = genBuildStair; // jff 3/31/98 do not leave uninited + + ok = 1; + break; + } + } while(ok); + if (manual) + return rtn; + secnum = osecnum; //jff 3/4/98 restore old loop index + } + // retriggerable generalized stairs build up or down alternately + if (rtn) + line->special ^= StairDirection; // alternate dir on succ activations + return rtn; +} + +// +// EV_DoGenCrusher() +// +// Handle generalized crusher types +// +// Passed the linedef activating the crusher +// Returns true if a thinker created +// +int EV_DoGenCrusher +( line_t* line ) +{ + int secnum; + int rtn; + boolean manual; + sector_t* sec; + ceiling_t* ceiling; + unsigned value = (unsigned)line->special - GenCrusherBase; + + // parse the bit fields in the line's special type + + int Slnt = (value & CrusherSilent) >> CrusherSilentShift; + int Sped = (value & CrusherSpeed) >> CrusherSpeedShift; + int Trig = (value & TriggerType) >> TriggerTypeShift; + + //jff 2/22/98 Reactivate in-stasis ceilings...for certain types. + //jff 4/5/98 return if activated + rtn = P_ActivateInStasisCeiling(line); + + // check if a manual trigger, if so do just the sector on the backside + manual = false; + if (Trig==PushOnce || Trig==PushMany) + { + if (!(sec = line->backsector)) + return rtn; + secnum = sec-sectors; + manual = true; + goto manual_crusher; + } + + secnum = -1; + // if not manual do all sectors tagged the same as the line + while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) + { + sec = §ors[secnum]; + +manual_crusher: + // Do not start another function if ceiling already moving + if (P_SectorActive(ceiling_special,sec)) //jff 2/22/98 + { + if (!manual) + continue; + else + return rtn; + } + + // new ceiling thinker + rtn = 1; + ceiling = Z_Malloc (sizeof(*ceiling), PU_LEVSPEC, 0); + memset(ceiling, 0, sizeof(*ceiling)); + P_AddThinker (&ceiling->thinker); + sec->ceilingdata = ceiling; //jff 2/22/98 + ceiling->thinker.function = T_MoveCeiling; + ceiling->crush = true; + ceiling->direction = -1; + ceiling->sector = sec; + ceiling->texture = sec->ceilingpic; + ceiling->newspecial = sec->special; + ceiling->tag = sec->tag; + ceiling->type = Slnt? genSilentCrusher : genCrusher; + ceiling->topheight = sec->ceilingheight; + ceiling->bottomheight = sec->floorheight + (8*FRACUNIT); + + // setup ceiling motion speed + switch (Sped) + { + case SpeedSlow: + ceiling->speed = CEILSPEED; + break; + case SpeedNormal: + ceiling->speed = CEILSPEED*2; + break; + case SpeedFast: + ceiling->speed = CEILSPEED*4; + break; + case SpeedTurbo: + ceiling->speed = CEILSPEED*8; + break; + default: + break; + } + ceiling->oldspeed=ceiling->speed; + + P_AddActiveCeiling(ceiling); // add to list of active ceilings + if (manual) return rtn; + } + return rtn; +} + +// +// EV_DoGenLockedDoor() +// +// Handle generalized locked door types +// +// Passed the linedef activating the generalized locked door +// Returns true if a thinker created +// +int EV_DoGenLockedDoor +( line_t* line ) +{ + int secnum,rtn; + sector_t* sec; + vldoor_t* door; + boolean manual; + unsigned value = (unsigned)line->special - GenLockedBase; + + // parse the bit fields in the line's special type + + int Kind = (value & LockedKind) >> LockedKindShift; + int Sped = (value & LockedSpeed) >> LockedSpeedShift; + int Trig = (value & TriggerType) >> TriggerTypeShift; + + rtn = 0; + + // check if a manual trigger, if so do just the sector on the backside + manual = false; + if (Trig==PushOnce || Trig==PushMany) + { + if (!(sec = line->backsector)) + return rtn; + secnum = sec-sectors; + manual = true; + goto manual_locked; + } + + secnum = -1; + rtn = 0; + + // if not manual do all sectors tagged the same as the line + while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) + { + sec = §ors[secnum]; +manual_locked: + // Do not start another function if ceiling already moving + if (P_SectorActive(ceiling_special,sec)) //jff 2/22/98 + { + if (!manual) + continue; + else + return rtn; + } + + // new door thinker + rtn = 1; + door = Z_Malloc (sizeof(*door), PU_LEVSPEC, 0); + memset(door, 0, sizeof(*door)); + P_AddThinker (&door->thinker); + sec->ceilingdata = door; //jff 2/22/98 + + door->thinker.function = T_VerticalDoor; + door->sector = sec; + door->topwait = VDOORWAIT; + door->line = line; + door->topheight = P_FindLowestCeilingSurrounding(sec); + door->topheight -= 4*FRACUNIT; + door->direction = 1; + + /* killough 10/98: implement gradual lighting */ + door->lighttag = !comp[comp_doorlight] && + (line->special&6) == 6 && + line->special > GenLockedBase ? line->tag : 0; + + // setup speed of door motion + switch(Sped) + { + default: + case SpeedSlow: + door->type = Kind? genOpen : genRaise; + door->speed = VDOORSPEED; + break; + case SpeedNormal: + door->type = Kind? genOpen : genRaise; + door->speed = VDOORSPEED*2; + break; + case SpeedFast: + door->type = Kind? genBlazeOpen : genBlazeRaise; + door->speed = VDOORSPEED*4; + break; + case SpeedTurbo: + door->type = Kind? genBlazeOpen : genBlazeRaise; + door->speed = VDOORSPEED*8; + + break; + } + + // killough 4/15/98: fix generalized door opening sounds + // (previously they always had the blazing door close sound) + + S_StartSound((mobj_t *)&door->sector->soundorg, // killough 4/15/98 + door->speed >= VDOORSPEED*4 ? sfx_bdopn : sfx_doropn); + + if (manual) + return rtn; + } + return rtn; +} + +// +// EV_DoGenDoor() +// +// Handle generalized door types +// +// Passed the linedef activating the generalized door +// Returns true if a thinker created +// +int EV_DoGenDoor +( line_t* line ) +{ + int secnum,rtn; + sector_t* sec; + boolean manual; + vldoor_t* door; + unsigned value = (unsigned)line->special - GenDoorBase; + + // parse the bit fields in the line's special type + + int Dely = (value & DoorDelay) >> DoorDelayShift; + int Kind = (value & DoorKind) >> DoorKindShift; + int Sped = (value & DoorSpeed) >> DoorSpeedShift; + int Trig = (value & TriggerType) >> TriggerTypeShift; + + rtn = 0; + + // check if a manual trigger, if so do just the sector on the backside + manual = false; + if (Trig==PushOnce || Trig==PushMany) + { + if (!(sec = line->backsector)) + return rtn; + secnum = sec-sectors; + manual = true; + goto manual_door; + } + + + secnum = -1; + rtn = 0; + + // if not manual do all sectors tagged the same as the line + while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) + { + sec = §ors[secnum]; +manual_door: + // Do not start another function if ceiling already moving + if (P_SectorActive(ceiling_special,sec)) //jff 2/22/98 + { + if (!manual) + continue; + else + return rtn; + } + + // new door thinker + rtn = 1; + door = Z_Malloc (sizeof(*door), PU_LEVSPEC, 0); + memset(door, 0, sizeof(*door)); + P_AddThinker (&door->thinker); + sec->ceilingdata = door; //jff 2/22/98 + + door->thinker.function = T_VerticalDoor; + door->sector = sec; + // setup delay for door remaining open/closed + switch(Dely) + { + default: + case 0: + door->topwait = 35; + break; + case 1: + door->topwait = VDOORWAIT; + break; + case 2: + door->topwait = 2*VDOORWAIT; + break; + case 3: + door->topwait = 7*VDOORWAIT; + break; + } + + // setup speed of door motion + switch(Sped) + { + default: + case SpeedSlow: + door->speed = VDOORSPEED; + break; + case SpeedNormal: + door->speed = VDOORSPEED*2; + break; + case SpeedFast: + door->speed = VDOORSPEED*4; + break; + case SpeedTurbo: + door->speed = VDOORSPEED*8; + break; + } + door->line = line; // jff 1/31/98 remember line that triggered us + + /* killough 10/98: implement gradual lighting */ + door->lighttag = !comp[comp_doorlight] && + (line->special&6) == 6 && + line->special > GenLockedBase ? line->tag : 0; + + // set kind of door, whether it opens then close, opens, closes etc. + // assign target heights accordingly + switch(Kind) + { + case OdCDoor: + door->direction = 1; + door->topheight = P_FindLowestCeilingSurrounding(sec); + door->topheight -= 4*FRACUNIT; + if (door->topheight != sec->ceilingheight) + S_StartSound((mobj_t *)&door->sector->soundorg,Sped>=SpeedFast || comp[comp_sound] ? sfx_bdopn : sfx_doropn); + door->type = Sped>=SpeedFast? genBlazeRaise : genRaise; + break; + case ODoor: + door->direction = 1; + door->topheight = P_FindLowestCeilingSurrounding(sec); + door->topheight -= 4*FRACUNIT; + if (door->topheight != sec->ceilingheight) + S_StartSound((mobj_t *)&door->sector->soundorg,Sped>=SpeedFast || comp[comp_sound] ? sfx_bdopn : sfx_doropn); + door->type = Sped>=SpeedFast? genBlazeOpen : genOpen; + break; + case CdODoor: + door->topheight = sec->ceilingheight; + door->direction = -1; + S_StartSound((mobj_t *)&door->sector->soundorg,Sped>=SpeedFast && !comp[comp_sound] ? sfx_bdcls : sfx_dorcls); + door->type = Sped>=SpeedFast? genBlazeCdO : genCdO; + break; + case CDoor: + door->topheight = P_FindLowestCeilingSurrounding(sec); + door->topheight -= 4*FRACUNIT; + door->direction = -1; + S_StartSound((mobj_t *)&door->sector->soundorg,Sped>=SpeedFast && !comp[comp_sound] ? sfx_bdcls : sfx_dorcls); + door->type = Sped>=SpeedFast? genBlazeClose : genClose; + break; + default: + break; + } + if (manual) + return rtn; + } + return rtn; +} diff --git a/common/prboom/p_inter.c b/common/prboom/p_inter.c new file mode 100755 index 0000000..93a9aa7 --- /dev/null +++ b/common/prboom/p_inter.c @@ -0,0 +1,919 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Handling interactions (i.e., collisions). + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" +#include "dstrings.h" +#include "m_random.h" +#include "am_map.h" +#include "r_main.h" +#include "s_sound.h" +#include "sounds.h" +#include "d_deh.h" // Ty 03/22/98 - externalized strings +#include "p_tick.h" +#include "lprintf.h" + +#include "p_inter.h" +#include "p_enemy.h" + +#ifdef __GNUG__ +#pragma implementation "p_inter.h" +#endif +#include "p_inter.h" + +#include "doomiphone.h" + +#define BONUSADD 6 + +// Ty 03/07/98 - add deh externals +// Maximums and such were hardcoded values. Need to externalize those for +// dehacked support (and future flexibility). Most var names came from the key +// strings used in dehacked. + +int initial_health = 100; +int initial_bullets = 50; +int maxhealth = 100; // was MAXHEALTH as a #define, used only in this module +int max_armor = 200; +int green_armor_class = 1; // these are involved with armortype below +int blue_armor_class = 2; +int max_soul = 200; +int soul_health = 100; +int mega_health = 200; +int god_health = 100; // these are used in cheats (see st_stuff.c) +int idfa_armor = 200; +int idfa_armor_class = 2; +// not actually used due to pairing of cheat_k and cheat_fa +int idkfa_armor = 200; +int idkfa_armor_class = 2; + +int bfgcells = 40; // used in p_pspr.c +int monsters_infight = 0; // e6y: Dehacked support - monsters infight +// Ty 03/07/98 - end deh externals + +// a weapon is found with two clip loads, +// a big item has five clip loads +int maxammo[NUMAMMO] = {200, 50, 300, 50}; +int clipammo[NUMAMMO] = { 10, 4, 20, 1}; + +// +// GET STUFF +// + +// +// P_GiveAmmo +// Num is the number of clip loads, +// not the individual count (0= 1/2 clip). +// Returns false if the ammo can't be picked up at all +// + +static boolean P_GiveAmmo(player_t *player, ammotype_t ammo, int num) +{ + int oldammo; + + if (ammo == am_noammo) + return false; + +#ifdef RANGECHECK + if (ammo > NUMAMMO) + I_Error ("P_GiveAmmo: bad type %i", ammo); +#endif + + if ( player->ammo[ammo] == player->maxammo[ammo] ) + return false; + + if (num) + num *= clipammo[ammo]; + else + num = clipammo[ammo]/2; + + // give double ammo in trainer mode, you'll need in nightmare + if (gameskill == sk_baby || gameskill == sk_nightmare) + num <<= 1; + + oldammo = player->ammo[ammo]; + player->ammo[ammo] += num; + + if (player->ammo[ammo] > player->maxammo[ammo]) + player->ammo[ammo] = player->maxammo[ammo]; + + // If non zero ammo, don't change up weapons, player was lower on purpose. + if (oldammo) + return true; + + // We were down to zero, so select a new weapon. + // Preferences are not user selectable. + + switch (ammo) + { + case am_clip: + if (player->readyweapon == wp_fist) { + if (player->weaponowned[wp_chaingun]) + player->pendingweapon = wp_chaingun; + else + player->pendingweapon = wp_pistol; + } + break; + + case am_shell: + if (player->readyweapon == wp_fist || player->readyweapon == wp_pistol) + if (player->weaponowned[wp_shotgun]) + player->pendingweapon = wp_shotgun; + break; + + case am_cell: + if (player->readyweapon == wp_fist || player->readyweapon == wp_pistol) + if (player->weaponowned[wp_plasma]) + player->pendingweapon = wp_plasma; + break; + + case am_misl: + if (player->readyweapon == wp_fist) + if (player->weaponowned[wp_missile]) + player->pendingweapon = wp_missile; + default: + break; + } + return true; +} + +// +// P_GiveWeapon +// The weapon name may have a MF_DROPPED flag ored in. +// + +static boolean P_GiveWeapon(player_t *player, weapontype_t weapon, boolean dropped) +{ + boolean gaveammo; + boolean gaveweapon; + + if (netgame && deathmatch!=2 && !dropped) + { + // leave placed weapons forever on net games + if (player->weaponowned[weapon]) + return false; + + player->bonuscount += BONUSADD; + player->weaponowned[weapon] = true; + + P_GiveAmmo(player, weaponinfo[weapon].ammo, deathmatch ? 5 : 2); + + player->pendingweapon = weapon; + /* cph 20028/10 - for old-school DM addicts, allow old behavior + * where only consoleplayer's pickup sounds are heard */ + // displayplayer, not consoleplayer, for viewing multiplayer demos + if (!comp[comp_sound] || player == &players[displayplayer]) + S_StartSound (player->mo, sfx_wpnup|PICKUP_SOUND); // killough 4/25/98 + return false; + } + + if (weaponinfo[weapon].ammo != am_noammo) + { + // give one clip with a dropped weapon, + // two clips with a found weapon + gaveammo = P_GiveAmmo (player, weaponinfo[weapon].ammo, dropped ? 1 : 2); + } + else + gaveammo = false; + + if (player->weaponowned[weapon]) + gaveweapon = false; + else + { + gaveweapon = true; + player->weaponowned[weapon] = true; + player->pendingweapon = weapon; + } + return gaveweapon || gaveammo; +} + +// +// P_GiveBody +// Returns false if the body isn't needed at all +// + +static boolean P_GiveBody(player_t *player, int num) +{ + if (player->health >= maxhealth) + return false; // Ty 03/09/98 externalized MAXHEALTH to maxhealth + player->health += num; + if (player->health > maxhealth) + player->health = maxhealth; + player->mo->health = player->health; + return true; +} + +// +// P_GiveArmor +// Returns false if the armor is worse +// than the current armor. +// + +static boolean P_GiveArmor(player_t *player, int armortype) +{ + int hits = armortype*100; + if (player->armorpoints >= hits) + return false; // don't pick up + player->armortype = armortype; + player->armorpoints = hits; + return true; +} + +// +// P_GiveCard +// + +static void P_GiveCard(player_t *player, card_t card) +{ + if (player->cards[card]) + return; + player->bonuscount = BONUSADD; + player->cards[card] = 1; +} + +// +// P_GivePower +// +// Rewritten by Lee Killough +// + +boolean P_GivePower(player_t *player, int power) +{ + static const int tics[NUMPOWERS] = { + INVULNTICS, 1 /* strength */, INVISTICS, + IRONTICS, 1 /* allmap */, INFRATICS, + }; + + switch (power) + { + case pw_invisibility: + player->mo->flags |= MF_SHADOW; + break; + case pw_allmap: + if (player->powers[pw_allmap]) + return false; + break; + case pw_strength: + P_GiveBody(player,100); + break; + } + + // Unless player has infinite duration cheat, set duration (killough) + + if (player->powers[power] >= 0) + player->powers[power] = tics[power]; + return true; +} + +// +// P_TouchSpecialThing +// + +void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher) +{ + player_t *player; + int i; + int sound; + fixed_t delta = special->z - toucher->z; + + if (delta > toucher->height || delta < -8*FRACUNIT) + return; // out of reach + + sound = sfx_itemup; + player = toucher->player; + + // Dead thing touching. + // Can happen with a sliding player corpse. + if (toucher->health <= 0) + return; + + // Identify by sprite. + switch (special->sprite) + { + // armor + case SPR_ARM1: + if (!P_GiveArmor (player, green_armor_class)) + return; + player->message = s_GOTARMOR; // Ty 03/22/98 - externalized + break; + + case SPR_ARM2: + if (!P_GiveArmor (player, blue_armor_class)) + return; + player->message = s_GOTMEGA; // Ty 03/22/98 - externalized + break; + + // bonus items + case SPR_BON1: + player->health++; // can go over 100% + if (player->health > (maxhealth * 2)) + player->health = (maxhealth * 2); + player->mo->health = player->health; + player->message = s_GOTHTHBONUS; // Ty 03/22/98 - externalized + break; + + case SPR_BON2: + player->armorpoints++; // can go over 100% + if (player->armorpoints > max_armor) + player->armorpoints = max_armor; + if (!player->armortype) + player->armortype = green_armor_class; + player->message = s_GOTARMBONUS; // Ty 03/22/98 - externalized + break; + + case SPR_SOUL: + player->health += soul_health; + if (player->health > max_soul) + player->health = max_soul; + player->mo->health = player->health; + player->message = s_GOTSUPER; // Ty 03/22/98 - externalized + sound = sfx_getpow; + break; + + case SPR_MEGA: + if (gamemode != commercial) + return; + player->health = mega_health; + player->mo->health = player->health; + P_GiveArmor (player,blue_armor_class); + player->message = s_GOTMSPHERE; // Ty 03/22/98 - externalized + sound = sfx_getpow; + break; + + // cards + // leave cards for everyone + case SPR_BKEY: + if (!player->cards[it_bluecard]) + player->message = s_GOTBLUECARD; // Ty 03/22/98 - externalized + P_GiveCard (player, it_bluecard); + if (!netgame) + break; + return; + + case SPR_YKEY: + if (!player->cards[it_yellowcard]) + player->message = s_GOTYELWCARD; // Ty 03/22/98 - externalized + P_GiveCard (player, it_yellowcard); + if (!netgame) + break; + return; + + case SPR_RKEY: + if (!player->cards[it_redcard]) + player->message = s_GOTREDCARD; // Ty 03/22/98 - externalized + P_GiveCard (player, it_redcard); + if (!netgame) + break; + return; + + case SPR_BSKU: + if (!player->cards[it_blueskull]) + player->message = s_GOTBLUESKUL; // Ty 03/22/98 - externalized + P_GiveCard (player, it_blueskull); + if (!netgame) + break; + return; + + case SPR_YSKU: + if (!player->cards[it_yellowskull]) + player->message = s_GOTYELWSKUL; // Ty 03/22/98 - externalized + P_GiveCard (player, it_yellowskull); + if (!netgame) + break; + return; + + case SPR_RSKU: + if (!player->cards[it_redskull]) + player->message = s_GOTREDSKULL; // Ty 03/22/98 - externalized + P_GiveCard (player, it_redskull); + if (!netgame) + break; + return; + + // medikits, heals + case SPR_STIM: + if (!P_GiveBody (player, 10)) + return; + player->message = s_GOTSTIM; // Ty 03/22/98 - externalized + break; + + case SPR_MEDI: + if (!P_GiveBody (player, 25)) + return; + + if (player->health < 50) // cph - 25 + the 25 just added, thanks to Quasar for reporting this bug + player->message = s_GOTMEDINEED; // Ty 03/22/98 - externalized + else + player->message = s_GOTMEDIKIT; // Ty 03/22/98 - externalized + break; + + + // power ups + case SPR_PINV: + if (!P_GivePower (player, pw_invulnerability)) + return; + player->message = s_GOTINVUL; // Ty 03/22/98 - externalized + sound = sfx_getpow; + break; + + case SPR_PSTR: + if (!P_GivePower (player, pw_strength)) + return; + player->message = s_GOTBERSERK; // Ty 03/22/98 - externalized + if (player->readyweapon != wp_fist) + player->pendingweapon = wp_fist; + sound = sfx_getpow; + break; + + case SPR_PINS: + if (!P_GivePower (player, pw_invisibility)) + return; + player->message = s_GOTINVIS; // Ty 03/22/98 - externalized + sound = sfx_getpow; + break; + + case SPR_SUIT: + if (!P_GivePower (player, pw_ironfeet)) + return; + player->message = s_GOTSUIT; // Ty 03/22/98 - externalized + sound = sfx_getpow; + break; + + case SPR_PMAP: + if (!P_GivePower (player, pw_allmap)) + return; + player->message = s_GOTMAP; // Ty 03/22/98 - externalized + sound = sfx_getpow; + break; + + case SPR_PVIS: + if (!P_GivePower (player, pw_infrared)) + return; + player->message = s_GOTVISOR; // Ty 03/22/98 - externalized + sound = sfx_getpow; + break; + + // ammo + case SPR_CLIP: + if (special->flags & MF_DROPPED) + { + if (!P_GiveAmmo (player,am_clip,0)) + return; + } + else + { + if (!P_GiveAmmo (player,am_clip,1)) + return; + } + player->message = s_GOTCLIP; // Ty 03/22/98 - externalized + break; + + case SPR_AMMO: + if (!P_GiveAmmo (player, am_clip,5)) + return; + player->message = s_GOTCLIPBOX; // Ty 03/22/98 - externalized + break; + + case SPR_ROCK: + if (!P_GiveAmmo (player, am_misl,1)) + return; + player->message = s_GOTROCKET; // Ty 03/22/98 - externalized + break; + + case SPR_BROK: + if (!P_GiveAmmo (player, am_misl,5)) + return; + player->message = s_GOTROCKBOX; // Ty 03/22/98 - externalized + break; + + case SPR_CELL: + if (!P_GiveAmmo (player, am_cell,1)) + return; + player->message = s_GOTCELL; // Ty 03/22/98 - externalized + break; + + case SPR_CELP: + if (!P_GiveAmmo (player, am_cell,5)) + return; + player->message = s_GOTCELLBOX; // Ty 03/22/98 - externalized + break; + + case SPR_SHEL: + if (!P_GiveAmmo (player, am_shell,1)) + return; + player->message = s_GOTSHELLS; // Ty 03/22/98 - externalized + break; + + case SPR_SBOX: + if (!P_GiveAmmo (player, am_shell,5)) + return; + player->message = s_GOTSHELLBOX; // Ty 03/22/98 - externalized + break; + + case SPR_BPAK: + if (!player->backpack) + { + for (i=0 ; imaxammo[i] *= 2; + player->backpack = true; + } + for (i=0 ; imessage = s_GOTBACKPACK; // Ty 03/22/98 - externalized + break; + + // weapons + case SPR_BFUG: + if (!P_GiveWeapon (player, wp_bfg, false) ) + return; + player->message = s_GOTBFG9000; // Ty 03/22/98 - externalized + sound = sfx_wpnup; + break; + + case SPR_MGUN: + if (!P_GiveWeapon (player, wp_chaingun, (special->flags&MF_DROPPED)!=0) ) + return; + player->message = s_GOTCHAINGUN; // Ty 03/22/98 - externalized + sound = sfx_wpnup; + break; + + case SPR_CSAW: + if (!P_GiveWeapon (player, wp_chainsaw, false) ) + return; + player->message = s_GOTCHAINSAW; // Ty 03/22/98 - externalized + sound = sfx_wpnup; + break; + + case SPR_LAUN: + if (!P_GiveWeapon (player, wp_missile, false) ) + return; + player->message = s_GOTLAUNCHER; // Ty 03/22/98 - externalized + sound = sfx_wpnup; + break; + + case SPR_PLAS: + if (!P_GiveWeapon (player, wp_plasma, false) ) + return; + player->message = s_GOTPLASMA; // Ty 03/22/98 - externalized + sound = sfx_wpnup; + break; + + case SPR_SHOT: + if (!P_GiveWeapon (player, wp_shotgun, (special->flags&MF_DROPPED)!=0 ) ) + return; + player->message = s_GOTSHOTGUN; // Ty 03/22/98 - externalized + sound = sfx_wpnup; + break; + + case SPR_SGN2: + if (!P_GiveWeapon(player, wp_supershotgun, (special->flags&MF_DROPPED)!=0)) + return; + player->message = s_GOTSHOTGUN2; // Ty 03/22/98 - externalized + sound = sfx_wpnup; + break; + + default: + I_Error ("P_SpecialThing: Unknown gettable thing"); + } + + if (special->flags & MF_COUNTITEM) + player->itemcount++; + P_RemoveMobj (special); + player->bonuscount += BONUSADD; + + /* cph 20028/10 - for old-school DM addicts, allow old behavior + * where only consoleplayer's pickup sounds are heard */ + // displayplayer, not consoleplayer, for viewing multiplayer demos + if (!comp[comp_sound] || player == &players[displayplayer]) + S_StartSound (player->mo, sound | PICKUP_SOUND); // killough 4/25/98 +} + +// +// KillMobj +// +// killough 11/98: make static +static void P_KillMobj(mobj_t *source, mobj_t *target) +{ + mobjtype_t item; + mobj_t *mo; + + target->flags &= ~(MF_SHOOTABLE|MF_FLOAT|MF_SKULLFLY); + + if (target->type != MT_SKULL) + target->flags &= ~MF_NOGRAVITY; + + target->flags |= MF_CORPSE|MF_DROPOFF; + target->height >>= 2; + + if (!((target->flags ^ MF_COUNTKILL) & (MF_FRIEND | MF_COUNTKILL))) + totallive--; + + if (source && source->player) + { + // count for intermission + if (target->flags & MF_COUNTKILL) + source->player->killcount++; + if (target->player) + source->player->frags[target->player-players]++; + } + else + if (target->flags & MF_COUNTKILL) { /* Add to kills tally */ + if ((compatibility_level < lxdoom_1_compatibility) || !netgame) { + if (!netgame) + // count all monster deaths, + // even those caused by other monsters + players[0].killcount++; + } else + if (!deathmatch) { + // try and find a player to give the kill to, otherwise give the + // kill to a random player. this fixes the missing monsters bug + // in coop - rain + // CPhipps - not a bug as such, but certainly an inconsistency. + if (target->lastenemy && target->lastenemy->health > 0 + && target->lastenemy->player) // Fighting a player + target->lastenemy->player->killcount++; + else { + // cph - randomely choose a player in the game to be credited + // and do it uniformly between the active players + unsigned int activeplayers = 0, player, i; + + for (player = 0; playerplayer) + { + // count environment kills against you + if (!source) + target->player->frags[target->player-players]++; + + target->flags &= ~MF_SOLID; + target->player->playerstate = PST_DEAD; + P_DropWeapon (target->player); + + if (target->player == &players[consoleplayer] && (automapmode & am_active)) + AM_Stop(); // don't die in auto map; switch view prior to dying + } + + if (target->health < -target->info->spawnhealth && target->info->xdeathstate) + P_SetMobjState (target, target->info->xdeathstate); + else + P_SetMobjState (target, target->info->deathstate); + + target->tics -= P_Random(pr_killtics)&3; + + if (target->tics < 1) + target->tics = 1; + + // Drop stuff. + // This determines the kind of object spawned + // during the death frame of a thing. + + switch (target->type) + { + case MT_WOLFSS: + case MT_POSSESSED: + item = MT_CLIP; + break; + + case MT_SHOTGUY: + item = MT_SHOTGUN; + break; + + case MT_CHAINGUY: + item = MT_CHAINGUN; + break; + + default: + return; + } + + mo = P_SpawnMobj (target->x,target->y,ONFLOORZ, item); + mo->flags |= MF_DROPPED; // special versions of items +} + +// +// P_DamageMobj +// Damages both enemies and players +// "inflictor" is the thing that caused the damage +// creature or missile, can be NULL (slime, etc) +// "source" is the thing to target after taking damage +// creature or NULL +// Source and inflictor are the same for melee attacks. +// Source can be NULL for slime, barrel explosions +// and other environmental stuff. +// + +void P_DamageMobj(mobj_t *target,mobj_t *inflictor, mobj_t *source, int damage) +{ + player_t *player; + boolean justhit = false; /* killough 11/98 */ + + /* killough 8/31/98: allow bouncers to take damage */ + if (!(target->flags & (MF_SHOOTABLE | MF_BOUNCES))) + return; // shouldn't happen... + + if (target->health <= 0) + return; + + if (target->flags & MF_SKULLFLY) + target->momx = target->momy = target->momz = 0; + + player = target->player; + if (player && gameskill == sk_baby) + damage >>= 1; // take half damage in trainer mode + + // Some close combat weapons should not + // inflict thrust and push the victim out of reach, + // thus kick away unless using the chainsaw. + + if (inflictor && !(target->flags & MF_NOCLIP) && + (!source || !source->player || + source->player->readyweapon != wp_chainsaw)) + { + unsigned ang = R_PointToAngle2 (inflictor->x, inflictor->y, + target->x, target->y); + + fixed_t thrust = damage*(FRACUNIT>>3)*100/target->info->mass; + + // make fall forwards sometimes + if ( damage < 40 && damage > target->health + && target->z - inflictor->z > 64*FRACUNIT + && P_Random(pr_damagemobj) & 1) + { + ang += ANG180; + thrust *= 4; + } + + ang >>= ANGLETOFINESHIFT; + target->momx += FixedMul (thrust, finecosine[ang]); + target->momy += FixedMul (thrust, finesine[ang]); + + /* killough 11/98: thrust objects hanging off ledges */ + if (target->intflags & MIF_FALLING && target->gear >= MAXGEAR) + target->gear = 0; + } + + // player specific + if (player) + { + // end of game hell hack + if (target->subsector->sector->special == 11 && damage >= target->health) + damage = target->health - 1; + + // Below certain threshold, + // ignore damage in GOD mode, or with INVUL power. + // killough 3/26/98: make god mode 100% god mode in non-compat mode + + if ((damage < 1000 || (!comp[comp_god] && (player->cheats&CF_GODMODE))) && + (player->cheats&CF_GODMODE || player->powers[pw_invulnerability])) + return; + + if (player->armortype) + { + int saved = player->armortype == 1 ? damage/3 : damage/2; + if (player->armorpoints <= saved) + { + // armor is used up + saved = player->armorpoints; + player->armortype = 0; + } + player->armorpoints -= saved; + damage -= saved; + } + + player->health -= damage; // mirror mobj health here for Dave + if (player->health < 0) + player->health = 0; + + player->attacker = source; + player->damagecount += damage; // add damage after armor / invuln +#ifdef IPHONE + if ( player == &players[consoleplayer] && !demoplayback ) { // vibe during demos is annoying + SysIPhoneVibrate(); + } +#endif + if (player->damagecount > 100) + player->damagecount = 100; // teleport stomp does 10k points... + } + + // do the damage + target->health -= damage; + if (target->health <= 0) + { + P_KillMobj (source, target); + return; + } + + // killough 9/7/98: keep track of targets so that friends can help friends + if (mbf_features) + { + /* If target is a player, set player's target to source, + * so that a friend can tell who's hurting a player + */ + if (player) + P_SetTarget(&target->target, source); + + /* killough 9/8/98: + * If target's health is less than 50%, move it to the front of its list. + * This will slightly increase the chances that enemies will choose to + * "finish it off", but its main purpose is to alert friends of danger. + */ + if (target->health*2 < target->info->spawnhealth) + { + thinker_t *cap = &thinkerclasscap[target->flags & MF_FRIEND ? + th_friends : th_enemies]; + (target->thinker.cprev->cnext = target->thinker.cnext)->cprev = + target->thinker.cprev; + (target->thinker.cnext = cap->cnext)->cprev = &target->thinker; + (target->thinker.cprev = cap)->cnext = &target->thinker; + } + } + + if (P_Random (pr_painchance) < target->info->painchance && + !(target->flags & MF_SKULLFLY)) { //killough 11/98: see below + if (mbf_features) + justhit = true; + else + target->flags |= MF_JUSTHIT; // fight back! + + P_SetMobjState(target, target->info->painstate); + } + + target->reactiontime = 0; // we're awake now... + + /* killough 9/9/98: cleaned up, made more consistent: */ + + if (source && source != target && source->type != MT_VILE && + (!target->threshold || target->type == MT_VILE) && + ((source->flags ^ target->flags) & MF_FRIEND || + monster_infighting || + !mbf_features)) + { + /* if not intent on another player, chase after this one + * + * killough 2/15/98: remember last enemy, to prevent + * sleeping early; 2/21/98: Place priority on players + * killough 9/9/98: cleaned up, made more consistent: + */ + + if (!target->lastenemy || target->lastenemy->health <= 0 || + (!mbf_features ? + !target->lastenemy->player : + !((target->flags ^ target->lastenemy->flags) & MF_FRIEND) && + target->target != source)) // remember last enemy - killough + P_SetTarget(&target->lastenemy, target->target); + + P_SetTarget(&target->target, source); // killough 11/98 + target->threshold = BASETHRESHOLD; + if (target->state == &states[target->info->spawnstate] + && target->info->seestate != S_NULL) + P_SetMobjState (target, target->info->seestate); + } + + /* killough 11/98: Don't attack a friend, unless hit by that friend. + * cph 2006/04/01 - implicitly this is only if mbf_features */ + if (justhit && (target->target == source || !target->target || + !(target->flags & target->target->flags & MF_FRIEND))) + target->flags |= MF_JUSTHIT; // fight back! +} diff --git a/common/prboom/p_inter.h b/common/prboom/p_inter.h new file mode 100755 index 0000000..abce3f3 --- /dev/null +++ b/common/prboom/p_inter.h @@ -0,0 +1,72 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Thing events, and dehacked specified numbers controlling them. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __P_INTER__ +#define __P_INTER__ + +#include "d_player.h" +#include "p_mobj.h" + + +/* Ty 03/09/98 Moved to an int in p_inter.c for deh and externalization */ +#define MAXHEALTH maxhealth + +/* follow a player exlusively for 3 seconds */ +#define BASETHRESHOLD (100) + +boolean P_GivePower(player_t *, int); +void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher); +void P_DamageMobj(mobj_t *target,mobj_t *inflictor,mobj_t *source,int damage); + +/* killough 5/2/98: moved from d_deh.c, g_game.c, m_misc.c, others: */ + +extern int god_health; /* Ty 03/09/98 - deh support, see also p_inter.c */ +extern int idfa_armor; +extern int idfa_armor_class; +extern int idkfa_armor; +extern int idkfa_armor_class; /* Ty - end */ +/* Ty 03/13/98 - externalized initial settings for respawned player */ +extern int initial_health; +extern int initial_bullets; +extern int maxhealth; +extern int max_armor; +extern int green_armor_class; +extern int blue_armor_class; +extern int max_soul; +extern int soul_health; +extern int mega_health; +extern int bfgcells; +extern int monsters_infight; // e6y: Dehacked support - monsters infight +extern int maxammo[], clipammo[]; + +#endif diff --git a/common/prboom/p_lights.c b/common/prboom/p_lights.c new file mode 100755 index 0000000..84936e0 --- /dev/null +++ b/common/prboom/p_lights.c @@ -0,0 +1,443 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Action routines for lighting thinkers + * Spawn sector based lighting effects. + * Handle lighting linedef types + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" //jff 5/18/98 +#include "doomdef.h" +#include "m_random.h" +#include "r_main.h" +#include "p_spec.h" +#include "p_tick.h" + +////////////////////////////////////////////////////////// +// +// Lighting action routines, called once per tick +// +////////////////////////////////////////////////////////// + +// +// T_FireFlicker() +// +// Firelight flicker action routine, called once per tick +// +// Passed a fireflicker_t structure containing light levels and timing +// Returns nothing +// +void T_FireFlicker (fireflicker_t* flick) +{ + int amount; + + if (--flick->count) + return; + + amount = (P_Random(pr_lights)&3)*16; + + if (flick->sector->lightlevel - amount < flick->minlight) + flick->sector->lightlevel = flick->minlight; + else + flick->sector->lightlevel = flick->maxlight - amount; + + flick->count = 4; +} + +// +// T_LightFlash() +// +// Broken light flashing action routine, called once per tick +// +// Passed a lightflash_t structure containing light levels and timing +// Returns nothing +// +void T_LightFlash (lightflash_t* flash) +{ + if (--flash->count) + return; + + if (flash->sector->lightlevel == flash->maxlight) + { + flash-> sector->lightlevel = flash->minlight; + flash->count = (P_Random(pr_lights)&flash->mintime)+1; + } + else + { + flash-> sector->lightlevel = flash->maxlight; + flash->count = (P_Random(pr_lights)&flash->maxtime)+1; + } + +} + +// +// T_StrobeFlash() +// +// Strobe light flashing action routine, called once per tick +// +// Passed a strobe_t structure containing light levels and timing +// Returns nothing +// +void T_StrobeFlash (strobe_t* flash) +{ + if (--flash->count) + return; + + if (flash->sector->lightlevel == flash->minlight) + { + flash-> sector->lightlevel = flash->maxlight; + flash->count = flash->brighttime; + } + else + { + flash-> sector->lightlevel = flash->minlight; + flash->count =flash->darktime; + } +} + +// +// T_Glow() +// +// Glowing light action routine, called once per tick +// +// Passed a glow_t structure containing light levels and timing +// Returns nothing +// + +void T_Glow(glow_t* g) +{ + switch(g->direction) + { + case -1: + // light dims + g->sector->lightlevel -= GLOWSPEED; + if (g->sector->lightlevel <= g->minlight) + { + g->sector->lightlevel += GLOWSPEED; + g->direction = 1; + } + break; + + case 1: + // light brightens + g->sector->lightlevel += GLOWSPEED; + if (g->sector->lightlevel >= g->maxlight) + { + g->sector->lightlevel -= GLOWSPEED; + g->direction = -1; + } + break; + } +} + +////////////////////////////////////////////////////////// +// +// Sector lighting type spawners +// +// After the map has been loaded, each sector is scanned +// for specials that spawn thinkers +// +////////////////////////////////////////////////////////// + +// +// P_SpawnFireFlicker() +// +// Spawns a fire flicker lighting thinker +// +// Passed the sector that spawned the thinker +// Returns nothing +// +void P_SpawnFireFlicker (sector_t* sector) +{ + fireflicker_t* flick; + + // Note that we are resetting sector attributes. + // Nothing special about it during gameplay. + sector->special &= ~31; //jff 3/14/98 clear non-generalized sector type + + flick = Z_Malloc ( sizeof(*flick), PU_LEVSPEC, 0); + + memset(flick, 0, sizeof(*flick)); + P_AddThinker (&flick->thinker); + + flick->thinker.function = T_FireFlicker; + flick->sector = sector; + flick->maxlight = sector->lightlevel; + flick->minlight = P_FindMinSurroundingLight(sector,sector->lightlevel)+16; + flick->count = 4; +} + +// +// P_SpawnLightFlash() +// +// Spawns a broken light flash lighting thinker +// +// Passed the sector that spawned the thinker +// Returns nothing +// +void P_SpawnLightFlash (sector_t* sector) +{ + lightflash_t* flash; + + // nothing special about it during gameplay + sector->special &= ~31; //jff 3/14/98 clear non-generalized sector type + + flash = Z_Malloc ( sizeof(*flash), PU_LEVSPEC, 0); + + memset(flash, 0, sizeof(*flash)); + P_AddThinker (&flash->thinker); + + flash->thinker.function = T_LightFlash; + flash->sector = sector; + flash->maxlight = sector->lightlevel; + + flash->minlight = P_FindMinSurroundingLight(sector,sector->lightlevel); + flash->maxtime = 64; + flash->mintime = 7; + flash->count = (P_Random(pr_lights)&flash->maxtime)+1; +} + +// +// P_SpawnStrobeFlash +// +// Spawns a blinking light thinker +// +// Passed the sector that spawned the thinker, speed of blinking +// and whether blinking is to by syncrhonous with other sectors +// +// Returns nothing +// +void P_SpawnStrobeFlash +( sector_t* sector, + int fastOrSlow, + int inSync ) +{ + strobe_t* flash; + + flash = Z_Malloc ( sizeof(*flash), PU_LEVSPEC, 0); + + memset(flash, 0, sizeof(*flash)); + P_AddThinker (&flash->thinker); + + flash->sector = sector; + flash->darktime = fastOrSlow; + flash->brighttime = STROBEBRIGHT; + flash->thinker.function = T_StrobeFlash; + flash->maxlight = sector->lightlevel; + flash->minlight = P_FindMinSurroundingLight(sector, sector->lightlevel); + + if (flash->minlight == flash->maxlight) + flash->minlight = 0; + + // nothing special about it during gameplay + sector->special &= ~31; //jff 3/14/98 clear non-generalized sector type + + if (!inSync) + flash->count = (P_Random(pr_lights)&7)+1; + else + flash->count = 1; +} + +// +// P_SpawnGlowingLight() +// +// Spawns a glowing light (smooth oscillation from min to max) thinker +// +// Passed the sector that spawned the thinker +// Returns nothing +// +void P_SpawnGlowingLight(sector_t* sector) +{ + glow_t* g; + + g = Z_Malloc( sizeof(*g), PU_LEVSPEC, 0); + + memset(g, 0, sizeof(*g)); + P_AddThinker(&g->thinker); + + g->sector = sector; + g->minlight = P_FindMinSurroundingLight(sector,sector->lightlevel); + g->maxlight = sector->lightlevel; + g->thinker.function = T_Glow; + g->direction = -1; + + sector->special &= ~31; //jff 3/14/98 clear non-generalized sector type +} + +////////////////////////////////////////////////////////// +// +// Linedef lighting function handlers +// +////////////////////////////////////////////////////////// + +// +// EV_StartLightStrobing() +// +// Start strobing lights (usually from a trigger) +// +// Passed the line that activated the strobing +// Returns true +// +// jff 2/12/98 added int return value, fixed return +// +int EV_StartLightStrobing(line_t* line) +{ + int secnum; + sector_t* sec; + + secnum = -1; + // start lights strobing in all sectors tagged same as line + while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) + { + sec = §ors[secnum]; + // if already doing a lighting function, don't start a second + if (P_SectorActive(lighting_special,sec)) //jff 2/22/98 + continue; + + P_SpawnStrobeFlash (sec,SLOWDARK, 0); + } + return 1; +} + +// +// EV_TurnTagLightsOff() +// +// Turn line's tagged sector's lights to min adjacent neighbor level +// +// Passed the line that activated the lights being turned off +// Returns true +// +// jff 2/12/98 added int return value, fixed return +// +int EV_TurnTagLightsOff(line_t* line) +{ + int j; + + // search sectors for those with same tag as activating line + + // killough 10/98: replaced inefficient search with fast search + for (j = -1; (j = P_FindSectorFromLineTag(line,j)) >= 0;) + { + sector_t *sector = sectors + j, *tsec; + int i, min = sector->lightlevel; + // find min neighbor light level + for (i = 0;i < sector->linecount; i++) + if ((tsec = getNextSector(sector->lines[i], sector)) && + tsec->lightlevel < min) + min = tsec->lightlevel; + sector->lightlevel = min; + } + return 1; +} + +// +// EV_LightTurnOn() +// +// Turn sectors tagged to line lights on to specified or max neighbor level +// +// Passed the activating line, and a level to set the light to +// If level passed is 0, the maximum neighbor lighting is used +// Returns true +// +// jff 2/12/98 added int return value, fixed return +// +int EV_LightTurnOn(line_t *line, int bright) +{ + int i; + + // search all sectors for ones with same tag as activating line + + // killough 10/98: replace inefficient search with fast search + for (i = -1; (i = P_FindSectorFromLineTag(line,i)) >= 0;) + { + sector_t *temp, *sector = sectors+i; + int j, tbright = bright; //jff 5/17/98 search for maximum PER sector + + // bright = 0 means to search for highest light level surrounding sector + + if (!bright) + for (j = 0;j < sector->linecount; j++) + if ((temp = getNextSector(sector->lines[j],sector)) && + temp->lightlevel > tbright) + tbright = temp->lightlevel; + + sector->lightlevel = tbright; + + //jff 5/17/98 unless compatibility optioned + //then maximum near ANY tagged sector + if (comp[comp_model]) + bright = tbright; + } + return 1; +} + +/* killough 10/98: + * + * EV_LightTurnOnPartway() + * + * Turn sectors tagged to line lights on to specified or max neighbor level + * + * Passed the activating line, and a light level fraction between 0 and 1. + * Sets the light to min on 0, max on 1, and interpolates in-between. + * Used for doors with gradual lighting effects. + * + * Returns true + */ + +int EV_LightTurnOnPartway(line_t *line, fixed_t level) +{ + int i; + + if (level < 0) // clip at extremes + level = 0; + if (level > FRACUNIT) + level = FRACUNIT; + + // search all sectors for ones with same tag as activating line + for (i = -1; (i = P_FindSectorFromLineTag(line,i)) >= 0;) + { + sector_t *temp, *sector = sectors+i; + int j, bright = 0, min = sector->lightlevel; + + for (j = 0; j < sector->linecount; j++) + if ((temp = getNextSector(sector->lines[j],sector))) + { + if (temp->lightlevel > bright) + bright = temp->lightlevel; + if (temp->lightlevel < min) + min = temp->lightlevel; + } + + sector->lightlevel = // Set level in-between extremes + (level * bright + (FRACUNIT-level) * min) >> FRACBITS; + } + return 1; +} + diff --git a/common/prboom/p_map.c b/common/prboom/p_map.c new file mode 100755 index 0000000..249b80b --- /dev/null +++ b/common/prboom/p_map.c @@ -0,0 +1,2335 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2004 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Movement, collision handling. + * Shooting and aiming. + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" +#include "r_main.h" +#include "p_mobj.h" +#include "p_maputl.h" +#include "p_map.h" +#include "p_setup.h" +#include "p_spec.h" +#include "s_sound.h" +#include "sounds.h" +#include "p_inter.h" +#include "m_random.h" +#include "m_bbox.h" +#include "lprintf.h" + +static mobj_t *tmthing; +static fixed_t tmx; +static fixed_t tmy; +static int pe_x; // Pain Elemental position for Lost Soul checks // phares +static int pe_y; // Pain Elemental position for Lost Soul checks // phares +static int ls_x; // Lost Soul position for Lost Soul checks // phares +static int ls_y; // Lost Soul position for Lost Soul checks // phares + +// If "floatok" true, move would be ok +// if within "tmfloorz - tmceilingz". + +boolean floatok; + +/* killough 11/98: if "felldown" true, object was pushed down ledge */ +boolean felldown; + +// The tm* items are used to hold information globally, usually for +// line or object intersection checking + +fixed_t tmbbox[4]; // bounding box for line intersection checks +fixed_t tmfloorz; // floor you'd hit if free to fall +fixed_t tmceilingz; // ceiling of sector you're in +fixed_t tmdropoffz; // dropoff on other side of line you're crossing + +// keep track of the line that lowers the ceiling, +// so missiles don't explode against sky hack walls + +line_t *ceilingline; +line_t *blockline; /* killough 8/11/98: blocking linedef */ +line_t *floorline; /* killough 8/1/98: Highest touched floor */ +static int tmunstuck; /* killough 8/1/98: whether to allow unsticking */ + +// keep track of special lines as they are hit, +// but don't process them until the move is proven valid + +// 1/11/98 killough: removed limit on special lines crossed +line_t **spechit; // new code -- killough +static int spechit_max; // killough + +int numspechit; + +// Temporary holder for thing_sectorlist threads +msecnode_t* sector_list = NULL; // phares 3/16/98 + +// +// TELEPORT MOVE +// + +// +// PIT_StompThing +// + +static boolean telefrag; /* killough 8/9/98: whether to telefrag at exit */ + +boolean PIT_StompThing (mobj_t* thing) + { + fixed_t blockdist; + + // phares 9/10/98: moved this self-check to start of routine + + // don't clip against self + + if (thing == tmthing) + return true; + + if (!(thing->flags & MF_SHOOTABLE)) // Can't shoot it? Can't stomp it! + return true; + + blockdist = thing->radius + tmthing->radius; + + if (D_abs(thing->x - tmx) >= blockdist || D_abs(thing->y - tmy) >= blockdist) + return true; // didn't hit it + + // monsters don't stomp things except on boss level + if (!telefrag) // killough 8/9/98: make consistent across all levels + return false; + + P_DamageMobj (thing, tmthing, tmthing, 10000); // Stomp! + + return true; + } + + +/* + * killough 8/28/98: + * + * P_GetFriction() + * + * Returns the friction associated with a particular mobj. + */ + +int P_GetFriction(const mobj_t *mo, int *frictionfactor) +{ + int friction = ORIG_FRICTION; + int movefactor = ORIG_FRICTION_FACTOR; + const msecnode_t *m; + const sector_t *sec; + + /* Assign the friction value to objects on the floor, non-floating, + * and clipped. Normally the object's friction value is kept at + * ORIG_FRICTION and this thinker changes it for icy or muddy floors. + * + * When the object is straddling sectors with the same + * floorheight that have different frictions, use the lowest + * friction value (muddy has precedence over icy). + */ + + if (!(mo->flags & (MF_NOCLIP|MF_NOGRAVITY)) + && (mbf_features || (mo->player && !compatibility)) && + variable_friction) + for (m = mo->touching_sectorlist; m; m = m->m_tnext) + if ((sec = m->m_sector)->special & FRICTION_MASK && + (sec->friction < friction || friction == ORIG_FRICTION) && + (mo->z <= sec->floorheight || + (sec->heightsec != -1 && + mo->z <= sectors[sec->heightsec].floorheight && + mbf_features))) + friction = sec->friction, movefactor = sec->movefactor; + + if (frictionfactor) + *frictionfactor = movefactor; + + return friction; +} + +/* phares 3/19/98 + * P_GetMoveFactor() returns the value by which the x,y + * movements are multiplied to add to player movement. + * + * killough 8/28/98: rewritten + */ + +int P_GetMoveFactor(const mobj_t *mo, int *frictionp) +{ + int movefactor, friction; + + //e6y + if (!mbf_features) + { + int momentum; + + movefactor = ORIG_FRICTION_FACTOR; + + if (!compatibility && variable_friction && + !(mo->flags & (MF_NOGRAVITY | MF_NOCLIP))) + { + friction = mo->friction; + if (friction == ORIG_FRICTION) // normal floor + ; + else if (friction > ORIG_FRICTION) // ice + { + movefactor = mo->movefactor; + ((mobj_t*)mo)->movefactor = ORIG_FRICTION_FACTOR; // reset + } + else // sludge + { + + // phares 3/11/98: you start off slowly, then increase as + // you get better footing + + momentum = (P_AproxDistance(mo->momx,mo->momy)); + movefactor = mo->movefactor; + if (momentum > MORE_FRICTION_MOMENTUM<<2) + movefactor <<= 3; + + else if (momentum > MORE_FRICTION_MOMENTUM<<1) + movefactor <<= 2; + + else if (momentum > MORE_FRICTION_MOMENTUM) + movefactor <<= 1; + + ((mobj_t*)mo)->movefactor = ORIG_FRICTION_FACTOR; // reset + } + } // ^ + + return(movefactor); // | + } + + // If the floor is icy or muddy, it's harder to get moving. This is where + // the different friction factors are applied to 'trying to move'. In + // p_mobj.c, the friction factors are applied as you coast and slow down. + + if ((friction = P_GetFriction(mo, &movefactor)) < ORIG_FRICTION) + { + // phares 3/11/98: you start off slowly, then increase as + // you get better footing + + int momentum = P_AproxDistance(mo->momx,mo->momy); + + if (momentum > MORE_FRICTION_MOMENTUM<<2) + movefactor <<= 3; + else if (momentum > MORE_FRICTION_MOMENTUM<<1) + movefactor <<= 2; + else if (momentum > MORE_FRICTION_MOMENTUM) + movefactor <<= 1; + } + + if (frictionp) + *frictionp = friction; + + return movefactor; +} + +// +// P_TeleportMove +// + +boolean P_TeleportMove (mobj_t* thing,fixed_t x,fixed_t y, boolean boss) + { + int xl; + int xh; + int yl; + int yh; + int bx; + int by; + + subsector_t* newsubsec; + + /* killough 8/9/98: make telefragging more consistent, preserve compatibility */ + telefrag = thing->player || + (!comp[comp_telefrag] ? boss : (gamemap==30)); + + // kill anything occupying the position + + tmthing = thing; + + tmx = x; + tmy = y; + + tmbbox[BOXTOP] = y + tmthing->radius; + tmbbox[BOXBOTTOM] = y - tmthing->radius; + tmbbox[BOXRIGHT] = x + tmthing->radius; + tmbbox[BOXLEFT] = x - tmthing->radius; + + newsubsec = R_PointInSubsector (x,y); + ceilingline = NULL; + + // The base floor/ceiling is from the subsector + // that contains the point. + // Any contacted lines the step closer together + // will adjust them. + + tmfloorz = tmdropoffz = newsubsec->sector->floorheight; + tmceilingz = newsubsec->sector->ceilingheight; + + validcount++; + numspechit = 0; + + // stomp on any things contacted + + xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT; + xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT; + yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT; + yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT; + + for (bx=xl ; bx<=xh ; bx++) + for (by=yl ; by<=yh ; by++) + if (!P_BlockThingsIterator(bx,by,PIT_StompThing)) + return false; + + // the move is ok, + // so unlink from the old position & link into the new position + + P_UnsetThingPosition (thing); + + thing->floorz = tmfloorz; + thing->ceilingz = tmceilingz; + thing->dropoffz = tmdropoffz; // killough 11/98 + + thing->x = x; + thing->y = y; + + P_SetThingPosition (thing); + + thing->PrevX = x; + thing->PrevY = y; + thing->PrevZ = thing->floorz; + + return true; + } + + +// +// MOVEMENT ITERATOR FUNCTIONS +// + +// e6y: Spechits overrun emulation code +static void SpechitOverrun(line_t *ld); + +// // phares +// PIT_CrossLine // | +// Checks to see if a PE->LS trajectory line crosses a blocking // V +// line. Returns false if it does. +// +// tmbbox holds the bounding box of the trajectory. If that box +// does not touch the bounding box of the line in question, +// then the trajectory is not blocked. If the PE is on one side +// of the line and the LS is on the other side, then the +// trajectory is blocked. +// +// Currently this assumes an infinite line, which is not quite +// correct. A more correct solution would be to check for an +// intersection of the trajectory and the line, but that takes +// longer and probably really isn't worth the effort. +// + +static // killough 3/26/98: make static +boolean PIT_CrossLine (line_t* ld) + { + if (!(ld->flags & ML_TWOSIDED) || + (ld->flags & (ML_BLOCKING|ML_BLOCKMONSTERS))) + if (!(tmbbox[BOXLEFT] > ld->bbox[BOXRIGHT] || + tmbbox[BOXRIGHT] < ld->bbox[BOXLEFT] || + tmbbox[BOXTOP] < ld->bbox[BOXBOTTOM] || + tmbbox[BOXBOTTOM] > ld->bbox[BOXTOP])) + if (P_PointOnLineSide(pe_x,pe_y,ld) != P_PointOnLineSide(ls_x,ls_y,ld)) + return(false); // line blocks trajectory // ^ + return(true); // line doesn't block trajectory // | + } // phares + + +/* killough 8/1/98: used to test intersection between thing and line + * assuming NO movement occurs -- used to avoid sticky situations. + */ + +static int untouched(line_t *ld) +{ + fixed_t x, y, thetmbbox[4]; + return + (thetmbbox[BOXRIGHT] = (x=tmthing->x)+tmthing->radius) <= ld->bbox[BOXLEFT] || + (thetmbbox[BOXLEFT] = x-tmthing->radius) >= ld->bbox[BOXRIGHT] || + (thetmbbox[BOXTOP] = (y=tmthing->y)+tmthing->radius) <= ld->bbox[BOXBOTTOM] || + (thetmbbox[BOXBOTTOM] = y-tmthing->radius) >= ld->bbox[BOXTOP] || + P_BoxOnLineSide(tmbbox, ld) != -1; +} + +// +// PIT_CheckLine +// Adjusts tmfloorz and tmceilingz as lines are contacted +// + +static // killough 3/26/98: make static +boolean PIT_CheckLine (line_t* ld) +{ + if (tmbbox[BOXRIGHT] <= ld->bbox[BOXLEFT] + || tmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT] + || tmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM] + || tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP] ) + return true; // didn't hit it + + if (P_BoxOnLineSide(tmbbox, ld) != -1) + return true; // didn't hit it + + // A line has been hit + + // The moving thing's destination position will cross the given line. + // If this should not be allowed, return false. + // If the line is special, keep track of it + // to process later if the move is proven ok. + // NOTE: specials are NOT sorted by order, + // so two special lines that are only 8 pixels apart + // could be crossed in either order. + + // killough 7/24/98: allow player to move out of 1s wall, to prevent sticking + if (!ld->backsector) // one sided line + { + blockline = ld; + return tmunstuck && !untouched(ld) && + FixedMul(tmx-tmthing->x,ld->dy) > FixedMul(tmy-tmthing->y,ld->dx); + } + + // killough 8/10/98: allow bouncing objects to pass through as missiles + if (!(tmthing->flags & (MF_MISSILE | MF_BOUNCES))) + { + if (ld->flags & ML_BLOCKING) // explicitly blocking everything + return tmunstuck && !untouched(ld); // killough 8/1/98: allow escape + + // killough 8/9/98: monster-blockers don't affect friends + if (!(tmthing->flags & MF_FRIEND || tmthing->player) + && ld->flags & ML_BLOCKMONSTERS) + return false; // block monsters only + } + + // set openrange, opentop, openbottom + // these define a 'window' from one sector to another across this line + + P_LineOpening (ld); + + // adjust floor & ceiling heights + + if (opentop < tmceilingz) + { + tmceilingz = opentop; + ceilingline = ld; + blockline = ld; + } + + if (openbottom > tmfloorz) + { + tmfloorz = openbottom; + floorline = ld; // killough 8/1/98: remember floor linedef + blockline = ld; + } + + if (lowfloor < tmdropoffz) + tmdropoffz = lowfloor; + + // if contacted a special line, add it to the list + + if (ld->special) + { + // 1/11/98 killough: remove limit on lines hit, by array doubling + if (numspechit >= spechit_max) { + spechit_max = spechit_max ? spechit_max*2 : 8; + spechit = realloc(spechit,sizeof *spechit*spechit_max); // killough + } + spechit[numspechit++] = ld; + // e6y: Spechits overrun emulation code + if (numspechit >= 8 && demo_compatibility) + SpechitOverrun(ld); + } + + return true; +} + +// +// PIT_CheckThing +// + +static boolean PIT_CheckThing(mobj_t *thing) // killough 3/26/98: make static +{ + fixed_t blockdist; + int damage; + + // killough 11/98: add touchy things + if (!(thing->flags & (MF_SOLID|MF_SPECIAL|MF_SHOOTABLE|MF_TOUCHY))) + return true; + + blockdist = thing->radius + tmthing->radius; + + if (D_abs(thing->x - tmx) >= blockdist || D_abs(thing->y - tmy) >= blockdist) + return true; // didn't hit it + + // killough 11/98: + // + // This test has less information content (it's almost always false), so it + // should not be moved up to first, as it adds more overhead than it removes. + + // don't clip against self + + if (thing == tmthing) + return true; + + /* killough 11/98: + * + * TOUCHY flag, for mines or other objects which die on contact with solids. + * If a solid object of a different type comes in contact with a touchy + * thing, and the touchy thing is not the sole one moving relative to fixed + * surroundings such as walls, then the touchy thing dies immediately. + */ + + if (thing->flags & MF_TOUCHY && // touchy object + tmthing->flags & MF_SOLID && // solid object touches it + thing->health > 0 && // touchy object is alive + (thing->intflags & MIF_ARMED || // Thing is an armed mine + sentient(thing)) && // ... or a sentient thing + (thing->type != tmthing->type || // only different species + thing->type == MT_PLAYER) && // ... or different players + thing->z + thing->height >= tmthing->z && // touches vertically + tmthing->z + tmthing->height >= thing->z && + (thing->type ^ MT_PAIN) | // PEs and lost souls + (tmthing->type ^ MT_SKULL) && // are considered same + (thing->type ^ MT_SKULL) | // (but Barons & Knights + (tmthing->type ^ MT_PAIN)) // are intentionally not) + { + P_DamageMobj(thing, NULL, NULL, thing->health); // kill object + return true; + } + + // check for skulls slamming into things + + if (tmthing->flags & MF_SKULLFLY) + { + // A flying skull is smacking something. + // Determine damage amount, and the skull comes to a dead stop. + + int skulldamage = ((P_Random(pr_skullfly)%8)+1)*tmthing->info->damage; + + P_DamageMobj (thing, tmthing, tmthing, skulldamage); + + tmthing->flags &= ~MF_SKULLFLY; + tmthing->momx = tmthing->momy = tmthing->momz = 0; + + P_SetMobjState (tmthing, tmthing->info->spawnstate); + + return false; // stop moving + } + + // missiles can hit other things + // killough 8/10/98: bouncing non-solid things can hit other things too + + if (tmthing->flags & MF_MISSILE || (tmthing->flags & MF_BOUNCES && + !(tmthing->flags & MF_SOLID))) + { + // see if it went over / under + + if (tmthing->z > thing->z + thing->height) + return true; // overhead + + if (tmthing->z+tmthing->height < thing->z) + return true; // underneath + + if (tmthing->target && (tmthing->target->type == thing->type || + (tmthing->target->type == MT_KNIGHT && thing->type == MT_BRUISER)|| + (tmthing->target->type == MT_BRUISER && thing->type == MT_KNIGHT))) + { + if (thing == tmthing->target) + return true; // Don't hit same species as originator. + else + // e6y: Dehacked support - monsters infight + if (thing->type != MT_PLAYER && !monsters_infight) // Explode, but do no damage. + return false; // Let players missile other players. + } + + // killough 8/10/98: if moving thing is not a missile, no damage + // is inflicted, and momentum is reduced if object hit is solid. + + if (!(tmthing->flags & MF_MISSILE)) { + if (!(thing->flags & MF_SOLID)) { + return true; + } else { + tmthing->momx = -tmthing->momx; + tmthing->momy = -tmthing->momy; + if (!(tmthing->flags & MF_NOGRAVITY)) + { + tmthing->momx >>= 2; + tmthing->momy >>= 2; + } + return false; + } + } + + if (!(thing->flags & MF_SHOOTABLE)) + return !(thing->flags & MF_SOLID); // didn't do any damage + + // damage / explode + + damage = ((P_Random(pr_damage)%8)+1)*tmthing->info->damage; + P_DamageMobj (thing, tmthing, tmthing->target, damage); + + // don't traverse any more + return false; + } + + // check for special pickup + + if (thing->flags & MF_SPECIAL) + { + uint_64_t solid = thing->flags & MF_SOLID; + if (tmthing->flags & MF_PICKUP) + P_TouchSpecialThing(thing, tmthing); // can remove thing + return !solid; + } + + // killough 3/16/98: Allow non-solid moving objects to move through solid + // ones, by allowing the moving thing (tmthing) to move if it's non-solid, + // despite another solid thing being in the way. + // killough 4/11/98: Treat no-clipping things as not blocking + // ...but not in demo_compatibility mode + + return !(thing->flags & MF_SOLID) + || (!demo_compatibility + && (thing->flags & MF_NOCLIP || !(tmthing->flags & MF_SOLID))); + + // return !(thing->flags & MF_SOLID); // old code -- killough +} + +// This routine checks for Lost Souls trying to be spawned // phares +// across 1-sided lines, impassible lines, or "monsters can't // | +// cross" lines. Draw an imaginary line between the PE // V +// and the new Lost Soul spawn spot. If that line crosses +// a 'blocking' line, then disallow the spawn. Only search +// lines in the blocks of the blockmap where the bounding box +// of the trajectory line resides. Then check bounding box +// of the trajectory vs. the bounding box of each blocking +// line to see if the trajectory and the blocking line cross. +// Then check the PE and LS to see if they're on different +// sides of the blocking line. If so, return true, otherwise +// false. + +boolean Check_Sides(mobj_t* actor, int x, int y) + { + int bx,by,xl,xh,yl,yh; + + pe_x = actor->x; + pe_y = actor->y; + ls_x = x; + ls_y = y; + + // Here is the bounding box of the trajectory + + tmbbox[BOXLEFT] = pe_x < x ? pe_x : x; + tmbbox[BOXRIGHT] = pe_x > x ? pe_x : x; + tmbbox[BOXTOP] = pe_y > y ? pe_y : y; + tmbbox[BOXBOTTOM] = pe_y < y ? pe_y : y; + + // Determine which blocks to look in for blocking lines + + xl = (tmbbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT; + xh = (tmbbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT; + yl = (tmbbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT; + yh = (tmbbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT; + + // xl->xh, yl->yh determine the mapblock set to search + + validcount++; // prevents checking same line twice + for (bx = xl ; bx <= xh ; bx++) + for (by = yl ; by <= yh ; by++) + if (!P_BlockLinesIterator(bx,by,PIT_CrossLine)) + return true; // ^ + return(false); // | + } // phares + +// +// MOVEMENT CLIPPING +// + +// +// P_CheckPosition +// This is purely informative, nothing is modified +// (except things picked up). +// +// in: +// a mobj_t (can be valid or invalid) +// a position to be checked +// (doesn't need to be related to the mobj_t->x,y) +// +// during: +// special things are touched if MF_PICKUP +// early out on solid lines? +// +// out: +// newsubsec +// floorz +// ceilingz +// tmdropoffz +// the lowest point contacted +// (monsters won't move to a dropoff) +// speciallines[] +// numspeciallines +// + +boolean P_CheckPosition (mobj_t* thing,fixed_t x,fixed_t y) + { + int xl; + int xh; + int yl; + int yh; + int bx; + int by; + subsector_t* newsubsec; + + tmthing = thing; + + tmx = x; + tmy = y; + + tmbbox[BOXTOP] = y + tmthing->radius; + tmbbox[BOXBOTTOM] = y - tmthing->radius; + tmbbox[BOXRIGHT] = x + tmthing->radius; + tmbbox[BOXLEFT] = x - tmthing->radius; + + newsubsec = R_PointInSubsector (x,y); + floorline = blockline = ceilingline = NULL; // killough 8/1/98 + + // Whether object can get out of a sticky situation: + tmunstuck = thing->player && /* only players */ + thing->player->mo == thing && /* not voodoo dolls */ + mbf_features; /* not under old demos */ + + // The base floor / ceiling is from the subsector + // that contains the point. + // Any contacted lines the step closer together + // will adjust them. + + tmfloorz = tmdropoffz = newsubsec->sector->floorheight; + tmceilingz = newsubsec->sector->ceilingheight; + validcount++; + numspechit = 0; + + if ( tmthing->flags & MF_NOCLIP ) + return true; + + // Check things first, possibly picking things up. + // The bounding box is extended by MAXRADIUS + // because mobj_ts are grouped into mapblocks + // based on their origin point, and can overlap + // into adjacent blocks by up to MAXRADIUS units. + + xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT; + xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT; + yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT; + yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT; + + + for (bx=xl ; bx<=xh ; bx++) + for (by=yl ; by<=yh ; by++) + if (!P_BlockThingsIterator(bx,by,PIT_CheckThing)) + return false; + + // check lines + + xl = (tmbbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT; + xh = (tmbbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT; + yl = (tmbbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT; + yh = (tmbbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT; + + for (bx=xl ; bx<=xh ; bx++) + for (by=yl ; by<=yh ; by++) + if (!P_BlockLinesIterator (bx,by,PIT_CheckLine)) + return false; // doesn't fit + + return true; + } + + +// +// P_TryMove +// Attempt to move to a new position, +// crossing special lines unless MF_TELEPORT is set. +// +boolean P_TryMove(mobj_t* thing,fixed_t x,fixed_t y, + boolean dropoff) // killough 3/15/98: allow dropoff as option + { + fixed_t oldx; + fixed_t oldy; + + felldown = floatok = false; // killough 11/98 + + if (!P_CheckPosition (thing, x, y)) + return false; // solid wall or thing + + if ( !(thing->flags & MF_NOCLIP) ) + { + // killough 7/26/98: reformatted slightly + // killough 8/1/98: Possibly allow escape if otherwise stuck + + if (tmceilingz - tmfloorz < thing->height || // doesn't fit + // mobj must lower to fit + (floatok = true, !(thing->flags & MF_TELEPORT) && + tmceilingz - thing->z < thing->height) || + // too big a step up + (!(thing->flags & MF_TELEPORT) && + tmfloorz - thing->z > 24*FRACUNIT)) + return tmunstuck + && !(ceilingline && untouched(ceilingline)) + && !( floorline && untouched( floorline)); + + /* killough 3/15/98: Allow certain objects to drop off + * killough 7/24/98, 8/1/98: + * Prevent monsters from getting stuck hanging off ledges + * killough 10/98: Allow dropoffs in controlled circumstances + * killough 11/98: Improve symmetry of clipping on stairs + */ + + if (!(thing->flags & (MF_DROPOFF|MF_FLOAT))) { + if (comp[comp_dropoff]) + { + if ((compatibility || !dropoff + // fix demosync bug in mbf compatibility mode + || (mbf_features && compatibility_level <= prboom_2_compatibility)) + && (tmfloorz - tmdropoffz > 24*FRACUNIT)) + return false; // don't stand over a dropoff + } + else + if (!dropoff || (dropoff==2 && // large jump down (e.g. dogs) + (tmfloorz-tmdropoffz > 128*FRACUNIT || + !thing->target || thing->target->z >tmdropoffz))) + { + if (!monkeys || !mbf_features ? + tmfloorz - tmdropoffz > 24*FRACUNIT : + thing->floorz - tmfloorz > 24*FRACUNIT || + thing->dropoffz - tmdropoffz > 24*FRACUNIT) + return false; + } + else { /* dropoff allowed -- check for whether it fell more than 24 */ + felldown = !(thing->flags & MF_NOGRAVITY) && + thing->z - tmfloorz > 24*FRACUNIT; + } + } + + if (thing->flags & MF_BOUNCES && // killough 8/13/98 + !(thing->flags & (MF_MISSILE|MF_NOGRAVITY)) && + !sentient(thing) && tmfloorz - thing->z > 16*FRACUNIT) + return false; // too big a step up for bouncers under gravity + + // killough 11/98: prevent falling objects from going up too many steps + if (thing->intflags & MIF_FALLING && tmfloorz - thing->z > + FixedMul(thing->momx,thing->momx)+FixedMul(thing->momy,thing->momy)) + return false; + } + + // the move is ok, + // so unlink from the old position and link into the new position + + P_UnsetThingPosition (thing); + + oldx = thing->x; + oldy = thing->y; + thing->floorz = tmfloorz; + thing->ceilingz = tmceilingz; + thing->dropoffz = tmdropoffz; // killough 11/98: keep track of dropoffs + thing->x = x; + thing->y = y; + + P_SetThingPosition (thing); + + // if any special lines were hit, do the effect + + if (! (thing->flags&(MF_TELEPORT|MF_NOCLIP)) ) + while (numspechit--) + if (spechit[numspechit]->special) // see if the line was crossed + { + int oldside; + if ((oldside = P_PointOnLineSide(oldx, oldy, spechit[numspechit])) != + P_PointOnLineSide(thing->x, thing->y, spechit[numspechit])) + P_CrossSpecialLine(spechit[numspechit], oldside, thing); + } + + return true; + } + +/* + * killough 9/12/98: + * + * Apply "torque" to objects hanging off of ledges, so that they + * fall off. It's not really torque, since Doom has no concept of + * rotation, but it's a convincing effect which avoids anomalies + * such as lifeless objects hanging more than halfway off of ledges, + * and allows objects to roll off of the edges of moving lifts, or + * to slide up and then back down stairs, or to fall into a ditch. + * If more than one linedef is contacted, the effects are cumulative, + * so balancing is possible. + */ + +static boolean PIT_ApplyTorque(line_t *ld) +{ + if (ld->backsector && // If thing touches two-sided pivot linedef + tmbbox[BOXRIGHT] > ld->bbox[BOXLEFT] && + tmbbox[BOXLEFT] < ld->bbox[BOXRIGHT] && + tmbbox[BOXTOP] > ld->bbox[BOXBOTTOM] && + tmbbox[BOXBOTTOM] < ld->bbox[BOXTOP] && + P_BoxOnLineSide(tmbbox, ld) == -1) + { + mobj_t *mo = tmthing; + + fixed_t dist = // lever arm + + (ld->dx >> FRACBITS) * (mo->y >> FRACBITS) + - (ld->dy >> FRACBITS) * (mo->x >> FRACBITS) + - (ld->dx >> FRACBITS) * (ld->v1->y >> FRACBITS) + + (ld->dy >> FRACBITS) * (ld->v1->x >> FRACBITS); + + if (dist < 0 ? // dropoff direction + ld->frontsector->floorheight < mo->z && + ld->backsector->floorheight >= mo->z : + ld->backsector->floorheight < mo->z && + ld->frontsector->floorheight >= mo->z) + { + /* At this point, we know that the object straddles a two-sided + * linedef, and that the object's center of mass is above-ground. + */ + + fixed_t x = D_abs(ld->dx), y = D_abs(ld->dy); + + if (y > x) + { + fixed_t t = x; + x = y; + y = t; + } + + y = finesine[(tantoangle[FixedDiv(y,x)>>DBITS] + + ANG90) >> ANGLETOFINESHIFT]; + + /* Momentum is proportional to distance between the + * object's center of mass and the pivot linedef. + * + * It is scaled by 2^(OVERDRIVE - gear). When gear is + * increased, the momentum gradually decreases to 0 for + * the same amount of pseudotorque, so that oscillations + * are prevented, yet it has a chance to reach equilibrium. + */ + dist = FixedDiv(FixedMul(dist, (mo->gear < OVERDRIVE) ? + y << -(mo->gear - OVERDRIVE) : + y >> +(mo->gear - OVERDRIVE)), x); + + /* Apply momentum away from the pivot linedef. */ + + x = FixedMul(ld->dy, dist); + y = FixedMul(ld->dx, dist); + + /* Avoid moving too fast all of a sudden (step into "overdrive") */ + + dist = FixedMul(x,x) + FixedMul(y,y); + + while (dist > FRACUNIT*4 && mo->gear < MAXGEAR) + ++mo->gear, x >>= 1, y >>= 1, dist >>= 1; + + mo->momx -= x; + mo->momy += y; + } + } + return true; +} + +/* + * killough 9/12/98 + * + * Applies "torque" to objects, based on all contacted linedefs + */ + +void P_ApplyTorque(mobj_t *mo) +{ + int xl = ((tmbbox[BOXLEFT] = + mo->x - mo->radius) - bmaporgx) >> MAPBLOCKSHIFT; + int xh = ((tmbbox[BOXRIGHT] = + mo->x + mo->radius) - bmaporgx) >> MAPBLOCKSHIFT; + int yl = ((tmbbox[BOXBOTTOM] = + mo->y - mo->radius) - bmaporgy) >> MAPBLOCKSHIFT; + int yh = ((tmbbox[BOXTOP] = + mo->y + mo->radius) - bmaporgy) >> MAPBLOCKSHIFT; + int bx,by,flags = mo->intflags; //Remember the current state, for gear-change + + tmthing = mo; + validcount++; /* prevents checking same line twice */ + + for (bx = xl ; bx <= xh ; bx++) + for (by = yl ; by <= yh ; by++) + P_BlockLinesIterator(bx, by, PIT_ApplyTorque); + + /* If any momentum, mark object as 'falling' using engine-internal flags */ + if (mo->momx | mo->momy) + mo->intflags |= MIF_FALLING; + else // Clear the engine-internal flag indicating falling object. + mo->intflags &= ~MIF_FALLING; + + /* If the object has been moving, step up the gear. + * This helps reach equilibrium and avoid oscillations. + * + * Doom has no concept of potential energy, much less + * of rotation, so we have to creatively simulate these + * systems somehow :) + */ + + if (!((mo->intflags | flags) & MIF_FALLING)) // If not falling for a while, + mo->gear = 0; // Reset it to full strength + else + if (mo->gear < MAXGEAR) // Else if not at max gear, + mo->gear++; // move up a gear +} + +// +// P_ThingHeightClip +// Takes a valid thing and adjusts the thing->floorz, +// thing->ceilingz, and possibly thing->z. +// This is called for all nearby monsters +// whenever a sector changes height. +// If the thing doesn't fit, +// the z will be set to the lowest value +// and false will be returned. +// + +boolean P_ThingHeightClip (mobj_t* thing) +{ + boolean onfloor; + + onfloor = (thing->z == thing->floorz); + + P_CheckPosition (thing, thing->x, thing->y); + + /* what about stranding a monster partially off an edge? + * killough 11/98: Answer: see below (upset balance if hanging off ledge) + */ + + thing->floorz = tmfloorz; + thing->ceilingz = tmceilingz; + thing->dropoffz = tmdropoffz; /* killough 11/98: remember dropoffs */ + + if (onfloor) + { + + // walking monsters rise and fall with the floor + + thing->z = thing->floorz; + + /* killough 11/98: Possibly upset balance of objects hanging off ledges */ + if (thing->intflags & MIF_FALLING && thing->gear >= MAXGEAR) + thing->gear = 0; + } + else + { + + // don't adjust a floating monster unless forced to + + if (thing->z+thing->height > thing->ceilingz) + thing->z = thing->ceilingz - thing->height; + } + + return thing->ceilingz - thing->floorz >= thing->height; +} + + +// +// SLIDE MOVE +// Allows the player to slide along any angled walls. +// + +/* killough 8/2/98: make variables static */ +static fixed_t bestslidefrac; +static line_t* bestslideline; +static mobj_t* slidemo; +static fixed_t tmxmove; +static fixed_t tmymove; + + +// +// P_HitSlideLine +// Adjusts the xmove / ymove +// so that the next move will slide along the wall. +// If the floor is icy, then you can bounce off a wall. // phares +// + +void P_HitSlideLine (line_t* ld) + { + int side; + angle_t lineangle; + angle_t moveangle; + angle_t deltaangle; + fixed_t movelen; + fixed_t newlen; + boolean icyfloor; // is floor icy? // phares + // | + // Under icy conditions, if the angle of approach to the wall // V + // is more than 45 degrees, then you'll bounce and lose half + // your momentum. If less than 45 degrees, you'll slide along + // the wall. 45 is arbitrary and is believable. + + // Check for the special cases of horz or vert walls. + + /* killough 10/98: only bounce if hit hard (prevents wobbling) + * cph - DEMOSYNC - should only affect players in Boom demos? */ + + //e6y + if (mbf_features) + { + icyfloor = + P_AproxDistance(tmxmove, tmymove) > 4*FRACUNIT && + variable_friction && // killough 8/28/98: calc friction on demand + slidemo->z <= slidemo->floorz && + P_GetFriction(slidemo, NULL) > ORIG_FRICTION; + } + else + { + extern boolean onground; + icyfloor = !compatibility && + variable_friction && + slidemo->player && + onground && + slidemo->friction > ORIG_FRICTION; + } + + if (ld->slopetype == ST_HORIZONTAL) + { + if (icyfloor && (D_abs(tmymove) > D_abs(tmxmove))) + { + tmxmove /= 2; // absorb half the momentum + tmymove = -tmymove/2; + S_StartSound(slidemo,sfx_oof); // oooff! + } + else + tmymove = 0; // no more movement in the Y direction + return; + } + + if (ld->slopetype == ST_VERTICAL) + { + if (icyfloor && (D_abs(tmxmove) > D_abs(tmymove))) + { + tmxmove = -tmxmove/2; // absorb half the momentum + tmymove /= 2; + S_StartSound(slidemo,sfx_oof); // oooff! // ^ + } // | + else // phares + tmxmove = 0; // no more movement in the X direction + return; + } + + // The wall is angled. Bounce if the angle of approach is // phares + // less than 45 degrees. // phares + + side = P_PointOnLineSide (slidemo->x, slidemo->y, ld); + + lineangle = R_PointToAngle2 (0,0, ld->dx, ld->dy); + if (side == 1) + lineangle += ANG180; + moveangle = R_PointToAngle2 (0,0, tmxmove, tmymove); + + // killough 3/2/98: + // The moveangle+=10 breaks v1.9 demo compatibility in + // some demos, so it needs demo_compatibility switch. + + if (!demo_compatibility) + moveangle += 10; // prevents sudden path reversal due to // phares + // rounding error // | + deltaangle = moveangle-lineangle; // V + movelen = P_AproxDistance (tmxmove, tmymove); + if (icyfloor && (deltaangle > ANG45) && (deltaangle < ANG90+ANG45)) + { + moveangle = lineangle - deltaangle; + movelen /= 2; // absorb + S_StartSound(slidemo,sfx_oof); // oooff! + moveangle >>= ANGLETOFINESHIFT; + tmxmove = FixedMul (movelen, finecosine[moveangle]); + tmymove = FixedMul (movelen, finesine[moveangle]); + } // ^ + else // | + { // phares + if (deltaangle > ANG180) + deltaangle += ANG180; + + // I_Error ("SlideLine: ang>ANG180"); + + lineangle >>= ANGLETOFINESHIFT; + deltaangle >>= ANGLETOFINESHIFT; + newlen = FixedMul (movelen, finecosine[deltaangle]); + tmxmove = FixedMul (newlen, finecosine[lineangle]); + tmymove = FixedMul (newlen, finesine[lineangle]); + } // phares + } + + +// +// PTR_SlideTraverse +// + +boolean PTR_SlideTraverse (intercept_t* in) + { + line_t* li; + + if (!in->isaline) + I_Error ("PTR_SlideTraverse: not a line?"); + + li = in->d.line; + + if ( ! (li->flags & ML_TWOSIDED) ) + { + if (P_PointOnLineSide (slidemo->x, slidemo->y, li)) + return true; // don't hit the back side + goto isblocking; + } + + // set openrange, opentop, openbottom. + // These define a 'window' from one sector to another across a line + + P_LineOpening (li); + + if (openrange < slidemo->height) + goto isblocking; // doesn't fit + + if (opentop - slidemo->z < slidemo->height) + goto isblocking; // mobj is too high + + if (openbottom - slidemo->z > 24*FRACUNIT ) + goto isblocking; // too big a step up + + // this line doesn't block movement + + return true; + + // the line does block movement, + // see if it is closer than best so far + +isblocking: + + if (in->frac < bestslidefrac) + { + bestslidefrac = in->frac; + bestslideline = li; + } + + return false; // stop + } + + +// +// P_SlideMove +// The momx / momy move is bad, so try to slide +// along a wall. +// Find the first line hit, move flush to it, +// and slide along it +// +// This is a kludgy mess. +// +// killough 11/98: reformatted + +void P_SlideMove(mobj_t *mo) +{ + int hitcount = 3; + + slidemo = mo; // the object that's sliding + + do + { + fixed_t leadx, leady, trailx, traily; + + if (!--hitcount) + goto stairstep; // don't loop forever + + // trace along the three leading corners + + if (mo->momx > 0) + leadx = mo->x + mo->radius, trailx = mo->x - mo->radius; + else + leadx = mo->x - mo->radius, trailx = mo->x + mo->radius; + + if (mo->momy > 0) + leady = mo->y + mo->radius, traily = mo->y - mo->radius; + else + leady = mo->y - mo->radius, traily = mo->y + mo->radius; + + bestslidefrac = FRACUNIT+1; + + P_PathTraverse(leadx, leady, leadx+mo->momx, leady+mo->momy, + PT_ADDLINES, PTR_SlideTraverse); + P_PathTraverse(trailx, leady, trailx+mo->momx, leady+mo->momy, + PT_ADDLINES, PTR_SlideTraverse); + P_PathTraverse(leadx, traily, leadx+mo->momx, traily+mo->momy, + PT_ADDLINES, PTR_SlideTraverse); + + // move up to the wall + + if (bestslidefrac == FRACUNIT+1) + { + // the move must have hit the middle, so stairstep + + stairstep: + + /* killough 3/15/98: Allow objects to drop off ledges + * + * phares 5/4/98: kill momentum if you can't move at all + * This eliminates player bobbing if pressed against a wall + * while on ice. + * + * killough 10/98: keep buggy code around for old Boom demos + * + * cph 2000/09//23: buggy code was only in Boom v2.01 + */ + + if (!P_TryMove(mo, mo->x, mo->y + mo->momy, true)) + if (!P_TryMove(mo, mo->x + mo->momx, mo->y, true)) + if (compatibility_level == boom_201_compatibility) + mo->momx = mo->momy = 0; + + break; + } + + // fudge a bit to make sure it doesn't hit + + if ((bestslidefrac -= 0x800) > 0) + { + fixed_t newx = FixedMul(mo->momx, bestslidefrac); + fixed_t newy = FixedMul(mo->momy, bestslidefrac); + + // killough 3/15/98: Allow objects to drop off ledges + + if (!P_TryMove(mo, mo->x+newx, mo->y+newy, true)) + goto stairstep; + } + + // Now continue along the wall. + // First calculate remainder. + + bestslidefrac = FRACUNIT-(bestslidefrac+0x800); + + if (bestslidefrac > FRACUNIT) + bestslidefrac = FRACUNIT; + + if (bestslidefrac <= 0) + break; + + tmxmove = FixedMul(mo->momx, bestslidefrac); + tmymove = FixedMul(mo->momy, bestslidefrac); + + P_HitSlideLine(bestslideline); // clip the moves + + mo->momx = tmxmove; + mo->momy = tmymove; + + /* killough 10/98: affect the bobbing the same way (but not voodoo dolls) + * cph - DEMOSYNC? */ + if (mo->player && mo->player->mo == mo) + { + if (D_abs(mo->player->momx) > D_abs(tmxmove)) + mo->player->momx = tmxmove; + if (D_abs(mo->player->momy) > D_abs(tmymove)) + mo->player->momy = tmymove; + } + } // killough 3/15/98: Allow objects to drop off ledges: + while (!P_TryMove(mo, mo->x+tmxmove, mo->y+tmymove, true)); +} + +// +// P_LineAttack +// +mobj_t* linetarget; // who got hit (or NULL) +static mobj_t* shootthing; + +/* killough 8/2/98: for more intelligent autoaiming */ +static uint_64_t aim_flags_mask; + +// Height if not aiming up or down +fixed_t shootz; + +int la_damage; +fixed_t attackrange; + +static fixed_t aimslope; + +// slopes to top and bottom of target +// killough 4/20/98: make static instead of using ones in p_sight.c + +static fixed_t topslope; +static fixed_t bottomslope; + + +// +// PTR_AimTraverse +// Sets linetaget and aimslope when a target is aimed at. +// +boolean PTR_AimTraverse (intercept_t* in) + { + line_t* li; + mobj_t* th; + fixed_t slope; + fixed_t thingtopslope; + fixed_t thingbottomslope; + fixed_t dist; + + if (in->isaline) + { + li = in->d.line; + + if ( !(li->flags & ML_TWOSIDED) ) + return false; // stop + + // Crosses a two sided line. + // A two sided line will restrict + // the possible target ranges. + + P_LineOpening (li); + + if (openbottom >= opentop) + return false; // stop + + dist = FixedMul (attackrange, in->frac); + + if (li->frontsector->floorheight != li->backsector->floorheight) + { + slope = FixedDiv (openbottom - shootz , dist); + if (slope > bottomslope) + bottomslope = slope; + } + + if (li->frontsector->ceilingheight != li->backsector->ceilingheight) + { + slope = FixedDiv (opentop - shootz , dist); + if (slope < topslope) + topslope = slope; + } + + if (topslope <= bottomslope) + return false; // stop + + return true; // shot continues + } + + // shoot a thing + + th = in->d.thing; + if (th == shootthing) + return true; // can't shoot self + + if (!(th->flags&MF_SHOOTABLE)) + return true; // corpse or something + + /* killough 7/19/98, 8/2/98: + * friends don't aim at friends (except players), at least not first + */ + if (th->flags & shootthing->flags & aim_flags_mask && !th->player) + return true; + + // check angles to see if the thing can be aimed at + + dist = FixedMul (attackrange, in->frac); + thingtopslope = FixedDiv (th->z+th->height - shootz , dist); + + if (thingtopslope < bottomslope) + return true; // shot over the thing + + thingbottomslope = FixedDiv (th->z - shootz, dist); + + if (thingbottomslope > topslope) + return true; // shot under the thing + + // this thing can be hit! + + if (thingtopslope > topslope) + thingtopslope = topslope; + + if (thingbottomslope < bottomslope) + thingbottomslope = bottomslope; + + aimslope = (thingtopslope+thingbottomslope)/2; + linetarget = th; + + return false; // don't go any farther + } + + +// +// PTR_ShootTraverse +// +boolean PTR_ShootTraverse (intercept_t* in) + { + fixed_t x; + fixed_t y; + fixed_t z; + fixed_t frac; + + mobj_t* th; + + fixed_t slope; + fixed_t dist; + fixed_t thingtopslope; + fixed_t thingbottomslope; + + if (in->isaline) + { + line_t *li = in->d.line; + + if (li->special) + P_ShootSpecialLine (shootthing, li); + + if (li->flags & ML_TWOSIDED) + { // crosses a two sided (really 2s) line + P_LineOpening (li); + dist = FixedMul(attackrange, in->frac); + + // killough 11/98: simplify + + if ((li->frontsector->floorheight==li->backsector->floorheight || + (slope = FixedDiv(openbottom - shootz , dist)) <= aimslope) && + (li->frontsector->ceilingheight==li->backsector->ceilingheight || + (slope = FixedDiv (opentop - shootz , dist)) >= aimslope)) + return true; // shot continues + } + + // hit line + // position a bit closer + + frac = in->frac - FixedDiv (4*FRACUNIT,attackrange); + x = trace.x + FixedMul (trace.dx, frac); + y = trace.y + FixedMul (trace.dy, frac); + z = shootz + FixedMul (aimslope, FixedMul(frac, attackrange)); + + if (li->frontsector->ceilingpic == skyflatnum) + { + // don't shoot the sky! + + if (z > li->frontsector->ceilingheight) + return false; + + // it's a sky hack wall + + if (li->backsector && li->backsector->ceilingpic == skyflatnum) + + // fix bullet-eaters -- killough: + // WARNING: Almost all demos will lose sync without this + // demo_compatibility flag check!!! killough 1/18/98 + if (demo_compatibility || li->backsector->ceilingheight < z) + return false; + } + + // Spawn bullet puffs. + + P_SpawnPuff (x,y,z); + + // don't go any farther + + return false; + } + + // shoot a thing + + th = in->d.thing; + if (th == shootthing) + return true; // can't shoot self + + if (!(th->flags&MF_SHOOTABLE)) + return true; // corpse or something + + // check angles to see if the thing can be aimed at + + dist = FixedMul (attackrange, in->frac); + thingtopslope = FixedDiv (th->z+th->height - shootz , dist); + + if (thingtopslope < aimslope) + return true; // shot over the thing + + thingbottomslope = FixedDiv (th->z - shootz, dist); + + if (thingbottomslope > aimslope) + return true; // shot under the thing + + // hit thing + // position a bit closer + + frac = in->frac - FixedDiv (10*FRACUNIT,attackrange); + + x = trace.x + FixedMul (trace.dx, frac); + y = trace.y + FixedMul (trace.dy, frac); + z = shootz + FixedMul (aimslope, FixedMul(frac, attackrange)); + + // Spawn bullet puffs or blod spots, + // depending on target type. + if (in->d.thing->flags & MF_NOBLOOD) + P_SpawnPuff (x,y,z); + else + P_SpawnBlood (x,y,z, la_damage); + + if (la_damage) + P_DamageMobj (th, shootthing, shootthing, la_damage); + + // don't go any farther + return false; + } + + +// +// P_AimLineAttack +// +fixed_t P_AimLineAttack(mobj_t* t1,angle_t angle,fixed_t distance, uint_64_t mask) + { + fixed_t x2; + fixed_t y2; + + angle >>= ANGLETOFINESHIFT; + shootthing = t1; + + x2 = t1->x + (distance>>FRACBITS)*finecosine[angle]; + y2 = t1->y + (distance>>FRACBITS)*finesine[angle]; + shootz = t1->z + (t1->height>>1) + 8*FRACUNIT; + + // can't shoot outside view angles + + topslope = 100*FRACUNIT/160; + bottomslope = -100*FRACUNIT/160; + + attackrange = distance; + linetarget = NULL; + + /* killough 8/2/98: prevent friends from aiming at friends */ + aim_flags_mask = mask; + + P_PathTraverse(t1->x,t1->y,x2,y2,PT_ADDLINES|PT_ADDTHINGS,PTR_AimTraverse); + + if (linetarget) + return aimslope; + + return 0; + } + + +// +// P_LineAttack +// If damage == 0, it is just a test trace +// that will leave linetarget set. +// + +void P_LineAttack +(mobj_t* t1, + angle_t angle, + fixed_t distance, + fixed_t slope, + int damage) + { + fixed_t x2; + fixed_t y2; + + angle >>= ANGLETOFINESHIFT; + shootthing = t1; + la_damage = damage; + x2 = t1->x + (distance>>FRACBITS)*finecosine[angle]; + y2 = t1->y + (distance>>FRACBITS)*finesine[angle]; + shootz = t1->z + (t1->height>>1) + 8*FRACUNIT; + attackrange = distance; + aimslope = slope; + + P_PathTraverse(t1->x,t1->y,x2,y2,PT_ADDLINES|PT_ADDTHINGS,PTR_ShootTraverse); + } + + +// +// USE LINES +// + +mobj_t* usething; + +boolean PTR_UseTraverse (intercept_t* in) + { + int side; + + if (!in->d.line->special) + { + P_LineOpening (in->d.line); + if (openrange <= 0) + { + S_StartSound (usething, sfx_noway); + + // can't use through a wall + return false; + } + + // not a special line, but keep checking + + return true; + } + + side = 0; + if (P_PointOnLineSide (usething->x, usething->y, in->d.line) == 1) + side = 1; + + // return false; // don't use back side + + P_UseSpecialLine (usething, in->d.line, side); + + //WAS can't use for than one special line in a row + //jff 3/21/98 NOW multiple use allowed with enabling line flag + + return (!demo_compatibility && (in->d.line->flags&ML_PASSUSE))? + true : false; +} + +// Returns false if a "oof" sound should be made because of a blocking +// linedef. Makes 2s middles which are impassable, as well as 2s uppers +// and lowers which block the player, cause the sound effect when the +// player tries to activate them. Specials are excluded, although it is +// assumed that all special linedefs within reach have been considered +// and rejected already (see P_UseLines). +// +// by Lee Killough +// + +boolean PTR_NoWayTraverse(intercept_t* in) + { + line_t *ld = in->d.line; + // This linedef + return ld->special || !( // Ignore specials + ld->flags & ML_BLOCKING || ( // Always blocking + P_LineOpening(ld), // Find openings + openrange <= 0 || // No opening + openbottom > usething->z+24*FRACUNIT || // Too high it blocks + opentop < usething->z+usething->height // Too low it blocks + ) + ); + } + +// +// P_UseLines +// Looks for special lines in front of the player to activate. +// +void P_UseLines (player_t* player) + { + int angle; + fixed_t x1; + fixed_t y1; + fixed_t x2; + fixed_t y2; + + usething = player->mo; + + angle = player->mo->angle >> ANGLETOFINESHIFT; + + x1 = player->mo->x; + y1 = player->mo->y; + x2 = x1 + (USERANGE>>FRACBITS)*finecosine[angle]; + y2 = y1 + (USERANGE>>FRACBITS)*finesine[angle]; + + // old code: + // + // P_PathTraverse ( x1, y1, x2, y2, PT_ADDLINES, PTR_UseTraverse ); + // + // This added test makes the "oof" sound work on 2s lines -- killough: + + if (P_PathTraverse ( x1, y1, x2, y2, PT_ADDLINES, PTR_UseTraverse )) + if (!comp[comp_sound] && !P_PathTraverse ( x1, y1, x2, y2, PT_ADDLINES, PTR_NoWayTraverse )) + S_StartSound (usething, sfx_noway); + } + + +// +// RADIUS ATTACK +// + +static mobj_t *bombsource, *bombspot; +static int bombdamage; + + +// +// PIT_RadiusAttack +// "bombsource" is the creature +// that caused the explosion at "bombspot". +// + +boolean PIT_RadiusAttack (mobj_t* thing) + { + fixed_t dx; + fixed_t dy; + fixed_t dist; + + /* killough 8/20/98: allow bouncers to take damage + * (missile bouncers are already excluded with MF_NOBLOCKMAP) + */ + + if (!(thing->flags & (MF_SHOOTABLE | MF_BOUNCES))) + return true; + + // Boss spider and cyborg + // take no damage from concussion. + + // killough 8/10/98: allow grenades to hurt anyone, unless + // fired by Cyberdemons, in which case it won't hurt Cybers. + + if (bombspot->flags & MF_BOUNCES ? + thing->type == MT_CYBORG && bombsource->type == MT_CYBORG : + thing->type == MT_CYBORG || thing->type == MT_SPIDER) + return true; + + dx = D_abs(thing->x - bombspot->x); + dy = D_abs(thing->y - bombspot->y); + + dist = dx>dy ? dx : dy; + dist = (dist - thing->radius) >> FRACBITS; + + if (dist < 0) + dist = 0; + + if (dist >= bombdamage) + return true; // out of range + + if ( P_CheckSight (thing, bombspot) ) + { + // must be in direct path + P_DamageMobj (thing, bombspot, bombsource, bombdamage - dist); + } + + return true; + } + + +// +// P_RadiusAttack +// Source is the creature that caused the explosion at spot. +// +void P_RadiusAttack(mobj_t* spot,mobj_t* source,int damage) + { + int x; + int y; + + int xl; + int xh; + int yl; + int yh; + + fixed_t dist; + + dist = (damage+MAXRADIUS)<y + dist - bmaporgy)>>MAPBLOCKSHIFT; + yl = (spot->y - dist - bmaporgy)>>MAPBLOCKSHIFT; + xh = (spot->x + dist - bmaporgx)>>MAPBLOCKSHIFT; + xl = (spot->x - dist - bmaporgx)>>MAPBLOCKSHIFT; + bombspot = spot; + bombsource = source; + bombdamage = damage; + + for (y=yl ; y<=yh ; y++) + for (x=xl ; x<=xh ; x++) + P_BlockThingsIterator (x, y, PIT_RadiusAttack ); + } + + + +// +// SECTOR HEIGHT CHANGING +// After modifying a sectors floor or ceiling height, +// call this routine to adjust the positions +// of all things that touch the sector. +// +// If anything doesn't fit anymore, true will be returned. +// If crunch is true, they will take damage +// as they are being crushed. +// If Crunch is false, you should set the sector height back +// the way it was and call P_ChangeSector again +// to undo the changes. +// + +static boolean crushchange, nofit; + +// +// PIT_ChangeSector +// + +boolean PIT_ChangeSector (mobj_t* thing) + { + mobj_t* mo; + + if (P_ThingHeightClip (thing)) + return true; // keep checking + + // crunch bodies to giblets + + if (thing->health <= 0) + { + P_SetMobjState (thing, S_GIBS); + + thing->flags &= ~MF_SOLID; + thing->height = 0; + thing->radius = 0; + return true; // keep checking + } + + // crunch dropped items + + if (thing->flags & MF_DROPPED) + { + P_RemoveMobj (thing); + + // keep checking + return true; + } + + /* killough 11/98: kill touchy things immediately */ + if (thing->flags & MF_TOUCHY && + (thing->intflags & MIF_ARMED || sentient(thing))) + { + P_DamageMobj(thing, NULL, NULL, thing->health); // kill object + return true; // keep checking + } + + if (! (thing->flags & MF_SHOOTABLE) ) + { + // assume it is bloody gibs or something + return true; + } + + nofit = true; + + if (crushchange && !(leveltime&3)) { + int t; + P_DamageMobj(thing,NULL,NULL,10); + + // spray blood in a random direction + mo = P_SpawnMobj (thing->x, + thing->y, + thing->z + thing->height/2, MT_BLOOD); + + /* killough 8/10/98: remove dependence on order of evaluation */ + t = P_Random(pr_crush); + mo->momx = (t - P_Random (pr_crush))<<12; + t = P_Random(pr_crush); + mo->momy = (t - P_Random (pr_crush))<<12; + } + + // keep checking (crush other things) + return true; + } + + +// +// P_ChangeSector +// +boolean P_ChangeSector(sector_t* sector,boolean crunch) + { + int x; + int y; + + nofit = false; + crushchange = crunch; + + // ARRGGHHH!!!! + // This is horrendously slow!!! + // killough 3/14/98 + + // re-check heights for all things near the moving sector + + for (x=sector->blockbox[BOXLEFT] ; x<= sector->blockbox[BOXRIGHT] ; x++) + for (y=sector->blockbox[BOXBOTTOM];y<= sector->blockbox[BOXTOP] ; y++) + P_BlockThingsIterator (x, y, PIT_ChangeSector); + + return nofit; + } + +// +// P_CheckSector +// jff 3/19/98 added to just check monsters on the periphery +// of a moving sector instead of all in bounding box of the +// sector. Both more accurate and faster. +// + +boolean P_CheckSector(sector_t* sector,boolean crunch) + { + msecnode_t *n; + + if (comp[comp_floors]) /* use the old routine for old demos though */ + return P_ChangeSector(sector,crunch); + + nofit = false; + crushchange = crunch; + + // killough 4/4/98: scan list front-to-back until empty or exhausted, + // restarting from beginning after each thing is processed. Avoids + // crashes, and is sure to examine all things in the sector, and only + // the things which are in the sector, until a steady-state is reached. + // Things can arbitrarily be inserted and removed and it won't mess up. + // + // killough 4/7/98: simplified to avoid using complicated counter + + // Mark all things invalid + + for (n=sector->touching_thinglist; n; n=n->m_snext) + n->visited = false; + + do + for (n=sector->touching_thinglist; n; n=n->m_snext) // go through list + if (!n->visited) // unprocessed thing found + { + n->visited = true; // mark thing as processed + if (!(n->m_thing->flags & MF_NOBLOCKMAP)) //jff 4/7/98 don't do these + PIT_ChangeSector(n->m_thing); // process it + break; // exit and start over + } + while (n); // repeat from scratch until all things left are marked valid + + return nofit; + } + + +// CPhipps - +// Use block memory allocator here + +#include "z_bmalloc.h" + +IMPLEMENT_BLOCK_MEMORY_ALLOC_ZONE(secnodezone, sizeof(msecnode_t), PU_LEVEL, 32, "SecNodes"); + +inline static msecnode_t* P_GetSecnode(void) +{ + return (msecnode_t*)Z_BMalloc(&secnodezone); +} + +// P_PutSecnode() returns a node to the freelist. + +inline static void P_PutSecnode(msecnode_t* node) +{ + Z_BFree(&secnodezone, node); +} + +// phares 3/16/98 +// +// P_AddSecnode() searches the current list to see if this sector is +// already there. If not, it adds a sector node at the head of the list of +// sectors this object appears in. This is called when creating a list of +// nodes that will get linked in later. Returns a pointer to the new node. + +msecnode_t* P_AddSecnode(sector_t* s, mobj_t* thing, msecnode_t* nextnode) + { + msecnode_t* node; + + node = nextnode; + while (node) + { + if (node->m_sector == s) // Already have a node for this sector? + { + node->m_thing = thing; // Yes. Setting m_thing says 'keep it'. + return(nextnode); + } + node = node->m_tnext; + } + + // Couldn't find an existing node for this sector. Add one at the head + // of the list. + + node = P_GetSecnode(); + + // killough 4/4/98, 4/7/98: mark new nodes unvisited. + node->visited = 0; + + node->m_sector = s; // sector + node->m_thing = thing; // mobj + node->m_tprev = NULL; // prev node on Thing thread + node->m_tnext = nextnode; // next node on Thing thread + if (nextnode) + nextnode->m_tprev = node; // set back link on Thing + + // Add new node at head of sector thread starting at s->touching_thinglist + + node->m_sprev = NULL; // prev node on sector thread + node->m_snext = s->touching_thinglist; // next node on sector thread + if (s->touching_thinglist) + node->m_snext->m_sprev = node; + s->touching_thinglist = node; + return(node); + } + + +// P_DelSecnode() deletes a sector node from the list of +// sectors this object appears in. Returns a pointer to the next node +// on the linked list, or NULL. + +msecnode_t* P_DelSecnode(msecnode_t* node) + { + msecnode_t* tp; // prev node on thing thread + msecnode_t* tn; // next node on thing thread + msecnode_t* sp; // prev node on sector thread + msecnode_t* sn; // next node on sector thread + + if (node) + { + + // Unlink from the Thing thread. The Thing thread begins at + // sector_list and not from mobj_t->touching_sectorlist. + + tp = node->m_tprev; + tn = node->m_tnext; + if (tp) + tp->m_tnext = tn; + if (tn) + tn->m_tprev = tp; + + // Unlink from the sector thread. This thread begins at + // sector_t->touching_thinglist. + + sp = node->m_sprev; + sn = node->m_snext; + if (sp) + sp->m_snext = sn; + else + node->m_sector->touching_thinglist = sn; + if (sn) + sn->m_sprev = sp; + + // Return this node to the freelist + + P_PutSecnode(node); + return(tn); + } + return(NULL); + } // phares 3/13/98 + +// Delete an entire sector list + +void P_DelSeclist(msecnode_t* node) + + { + while (node) + node = P_DelSecnode(node); + } + + +// phares 3/14/98 +// +// PIT_GetSectors +// Locates all the sectors the object is in by looking at the lines that +// cross through it. You have already decided that the object is allowed +// at this location, so don't bother with checking impassable or +// blocking lines. + +boolean PIT_GetSectors(line_t* ld) + { + if (tmbbox[BOXRIGHT] <= ld->bbox[BOXLEFT] || + tmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT] || + tmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM] || + tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP]) + return true; + + if (P_BoxOnLineSide(tmbbox, ld) != -1) + return true; + + // This line crosses through the object. + + // Collect the sector(s) from the line and add to the + // sector_list you're examining. If the Thing ends up being + // allowed to move to this position, then the sector_list + // will be attached to the Thing's mobj_t at touching_sectorlist. + + sector_list = P_AddSecnode(ld->frontsector,tmthing,sector_list); + + /* Don't assume all lines are 2-sided, since some Things + * like MT_TFOG are allowed regardless of whether their radius takes + * them beyond an impassable linedef. + * + * killough 3/27/98, 4/4/98: + * Use sidedefs instead of 2s flag to determine two-sidedness. + * killough 8/1/98: avoid duplicate if same sector on both sides + * cph - DEMOSYNC? */ + + if (ld->backsector && ld->backsector != ld->frontsector) + sector_list = P_AddSecnode(ld->backsector, tmthing, sector_list); + + return true; + } + + +// phares 3/14/98 +// +// P_CreateSecNodeList alters/creates the sector_list that shows what sectors +// the object resides in. + +void P_CreateSecNodeList(mobj_t* thing,fixed_t x,fixed_t y) +{ + int xl; + int xh; + int yl; + int yh; + int bx; + int by; + msecnode_t* node; + mobj_t* saved_tmthing = tmthing; /* cph - see comment at func end */ + fixed_t saved_tmx = tmx, saved_tmy = tmy; /* ditto */ + + // First, clear out the existing m_thing fields. As each node is + // added or verified as needed, m_thing will be set properly. When + // finished, delete all nodes where m_thing is still NULL. These + // represent the sectors the Thing has vacated. + + node = sector_list; + while (node) + { + node->m_thing = NULL; + node = node->m_tnext; + } + + tmthing = thing; + + tmx = x; + tmy = y; + + tmbbox[BOXTOP] = y + tmthing->radius; + tmbbox[BOXBOTTOM] = y - tmthing->radius; + tmbbox[BOXRIGHT] = x + tmthing->radius; + tmbbox[BOXLEFT] = x - tmthing->radius; + + validcount++; // used to make sure we only process a line once + + xl = (tmbbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT; + xh = (tmbbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT; + yl = (tmbbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT; + yh = (tmbbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT; + + for (bx=xl ; bx<=xh ; bx++) + for (by=yl ; by<=yh ; by++) + P_BlockLinesIterator(bx,by,PIT_GetSectors); + + // Add the sector of the (x,y) point to sector_list. + + sector_list = P_AddSecnode(thing->subsector->sector,thing,sector_list); + + // Now delete any nodes that won't be used. These are the ones where + // m_thing is still NULL. + + node = sector_list; + while (node) + { + if (node->m_thing == NULL) + { + if (node == sector_list) + sector_list = node->m_tnext; + node = P_DelSecnode(node); + } + else + node = node->m_tnext; + } + + /* cph - + * This is the strife we get into for using global variables. tmthing + * is being used by several different functions calling + * P_BlockThingIterator, including functions that can be called *from* + * P_BlockThingIterator. Using a global tmthing is not reentrant. + * OTOH for Boom/MBF demos we have to preserve the buggy behavior. + * Fun. We restore its previous value unless we're in a Boom/MBF demo. + */ + if ((compatibility_level < boom_compatibility_compatibility) || + (compatibility_level >= prboom_3_compatibility)) + tmthing = saved_tmthing; + /* And, duh, the same for tmx/y - cph 2002/09/22 + * And for tmbbox - cph 2003/08/10 */ + if ((compatibility_level < boom_compatibility_compatibility) /* || + (compatibility_level >= prboom_4_compatibility) */) { + tmx = saved_tmx, tmy = saved_tmy; + if (tmthing) { + tmbbox[BOXTOP] = tmy + tmthing->radius; + tmbbox[BOXBOTTOM] = tmy - tmthing->radius; + tmbbox[BOXRIGHT] = tmx + tmthing->radius; + tmbbox[BOXLEFT] = tmx - tmthing->radius; + } + } +} + +/* cphipps 2004/08/30 - + * Must clear tmthing at tic end, as it might contain a pointer to a removed thinker, or the level might have ended/been ended and we clear the objects it was pointing too. Hopefully we don't need to carry this between tics for sync. */ +void P_MapStart(void) { + if (tmthing) I_Error("P_MapStart: tmthing set!"); +} +void P_MapEnd(void) { + tmthing = NULL; +} + +// e6y +// Code to emulate the behavior of Vanilla Doom when encountering an overrun +// of the spechit array. +// No more desyncs on compet-n\hr.wad\hr18*.lmp, all strain.wad\map07 demos etc. +// http://www.doomworld.com/vb/showthread.php?s=&threadid=35214 +static void SpechitOverrun(line_t *ld) +{ + //int addr = 0x01C09C98 + (ld - lines) * 0x3E; + int addr = 0x00C09C98 + (ld - lines) * 0x3E; + + if (compatibility_level == dosdoom_compatibility || compatibility_level == tasdoom_compatibility) + { + // e6y + // There are no more desyncs in the following dosdoom demos: + // flsofdth.wad\fod3uv.lmp - http://www.doomworld.com/sda/flsofdth.htm + // hr.wad\hf181430.lmp - http://www.doomworld.com/tas/hf181430.zip + // hr.wad\hr181329.lmp - http://www.doomworld.com/tas/hr181329.zip + // icarus.wad\ic09uv.lmp - http://competn.doom2.net/pub/sda/i-o/icuvlmps.zip + + switch(numspechit) + { + case 8: break; /* strange cph's code */ + case 9: + tmfloorz = addr; + break; + case 10: + tmceilingz = addr; + break; + + default: + lprintf(LO_ERROR, "SpechitOverrun: Warning: unable to emulate" + " an overrun where numspechit=%i\n", + numspechit); + break; + } + } + else + { + switch(numspechit) + { + case 8: break; /* numspechit, not significant it seems - cph */ + case 9: + case 10: + case 11: + case 12: + tmbbox[numspechit-9] = addr; + break; + case 13: + nofit = addr; + break; + case 14: + crushchange = addr; + break; + default: + lprintf(LO_ERROR, "SpechitOverrun: Warning: unable to emulate" + " an overrun where numspechit=%i\n", + numspechit); + break; + } + } +} diff --git a/common/prboom/p_map.h b/common/prboom/p_map.h new file mode 100755 index 0000000..8da2f62 --- /dev/null +++ b/common/prboom/p_map.h @@ -0,0 +1,92 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Map functions + * + *-----------------------------------------------------------------------------*/ + +#ifndef __P_MAP__ +#define __P_MAP__ + +#include "r_defs.h" +#include "d_player.h" + +#define USERANGE (64*FRACUNIT) +#define MELEERANGE (64*FRACUNIT) +#define MISSILERANGE (32*64*FRACUNIT) + +// MAXRADIUS is for precalculated sector block boxes the spider demon +// is larger, but we do not have any moving sectors nearby +#define MAXRADIUS (32*FRACUNIT) + +// killough 3/15/98: add fourth argument to P_TryMove +boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean dropoff); + +// killough 8/9/98: extra argument for telefragging +boolean P_TeleportMove(mobj_t *thing, fixed_t x, fixed_t y,boolean boss); +void P_SlideMove(mobj_t *mo); +boolean P_CheckSight(mobj_t *t1, mobj_t *t2); +void P_UseLines(player_t *player); + +// killough 8/2/98: add 'mask' argument to prevent friends autoaiming at others +fixed_t P_AimLineAttack(mobj_t *t1,angle_t angle,fixed_t distance, uint_64_t mask); + +void P_LineAttack(mobj_t *t1, angle_t angle, fixed_t distance, + fixed_t slope, int damage ); +void P_RadiusAttack(mobj_t *spot, mobj_t *source, int damage); +boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y); + +//jff 3/19/98 P_CheckSector(): new routine to replace P_ChangeSector() +boolean P_ChangeSector(sector_t* sector,boolean crunch); +boolean P_CheckSector(sector_t *sector, boolean crunch); +void P_DelSeclist(msecnode_t*); // phares 3/16/98 +void P_CreateSecNodeList(mobj_t*,fixed_t,fixed_t); // phares 3/14/98 +boolean Check_Sides(mobj_t *, int, int); // phares + +int P_GetMoveFactor(const mobj_t *mo, int *friction); // killough 8/28/98 +int P_GetFriction(const mobj_t *mo, int *factor); // killough 8/28/98 +void P_ApplyTorque(mobj_t *mo); // killough 9/12/98 + +/* cphipps 2004/08/30 */ +void P_MapStart(void); +void P_MapEnd(void); + +// If "floatok" true, move would be ok if within "tmfloorz - tmceilingz". +extern boolean floatok; +extern boolean felldown; // killough 11/98: indicates object pushed off ledge +extern fixed_t tmfloorz; +extern fixed_t tmceilingz; +extern line_t *ceilingline; +extern line_t *floorline; // killough 8/23/98 +extern mobj_t *linetarget; // who got hit (or NULL) +extern msecnode_t *sector_list; // phares 3/16/98 +extern fixed_t tmbbox[4]; // phares 3/20/98 +extern line_t *blockline; // killough 8/11/98 + +#endif // __P_MAP__ diff --git a/common/prboom/p_maputl.c b/common/prboom/p_maputl.c new file mode 100755 index 0000000..62ce91c --- /dev/null +++ b/common/prboom/p_maputl.c @@ -0,0 +1,683 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Movement/collision utility functions, + * as used by function in p_map.c. + * BLOCKMAP Iterator functions, + * and some PIT_* functions to use for iteration. + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" +#include "m_bbox.h" +#include "r_main.h" +#include "p_maputl.h" +#include "p_map.h" +#include "p_setup.h" + +// +// P_AproxDistance +// Gives an estimation of distance (not exact) +// + +fixed_t CONSTFUNC P_AproxDistance(fixed_t dx, fixed_t dy) +{ + dx = D_abs(dx); + dy = D_abs(dy); + if (dx < dy) + return dx+dy-(dx>>1); + return dx+dy-(dy>>1); +} + +// +// P_PointOnLineSide +// Returns 0 or 1 +// +// killough 5/3/98: reformatted, cleaned up + +int PUREFUNC P_PointOnLineSide(fixed_t x, fixed_t y, const line_t *line) +{ + return + !line->dx ? x <= line->v1->x ? line->dy > 0 : line->dy < 0 : + !line->dy ? y <= line->v1->y ? line->dx < 0 : line->dx > 0 : + FixedMul(y-line->v1->y, line->dx>>FRACBITS) >= + FixedMul(line->dy>>FRACBITS, x-line->v1->x); +} + +// +// P_BoxOnLineSide +// Considers the line to be infinite +// Returns side 0 or 1, -1 if box crosses the line. +// +// killough 5/3/98: reformatted, cleaned up + +int PUREFUNC P_BoxOnLineSide(const fixed_t *tmbox, const line_t *ld) +{ + switch (ld->slopetype) + { + int p; + default: // shut up compiler warnings -- killough + case ST_HORIZONTAL: + return + (tmbox[BOXBOTTOM] > ld->v1->y) == (p = tmbox[BOXTOP] > ld->v1->y) ? + p ^ (ld->dx < 0) : -1; + case ST_VERTICAL: + return + (tmbox[BOXLEFT] < ld->v1->x) == (p = tmbox[BOXRIGHT] < ld->v1->x) ? + p ^ (ld->dy < 0) : -1; + case ST_POSITIVE: + return + P_PointOnLineSide(tmbox[BOXRIGHT], tmbox[BOXBOTTOM], ld) == + (p = P_PointOnLineSide(tmbox[BOXLEFT], tmbox[BOXTOP], ld)) ? p : -1; + case ST_NEGATIVE: + return + (P_PointOnLineSide(tmbox[BOXLEFT], tmbox[BOXBOTTOM], ld)) == + (p = P_PointOnLineSide(tmbox[BOXRIGHT], tmbox[BOXTOP], ld)) ? p : -1; + } +} + +// +// P_PointOnDivlineSide +// Returns 0 or 1. +// +// killough 5/3/98: reformatted, cleaned up + +static int PUREFUNC P_PointOnDivlineSide(fixed_t x, fixed_t y, const divline_t *line) +{ + return + !line->dx ? x <= line->x ? line->dy > 0 : line->dy < 0 : + !line->dy ? y <= line->y ? line->dx < 0 : line->dx > 0 : + (line->dy^line->dx^(x -= line->x)^(y -= line->y)) < 0 ? (line->dy^x) < 0 : + FixedMul(y>>8, line->dx>>8) >= FixedMul(line->dy>>8, x>>8); +} + +// +// P_MakeDivline +// + +static void P_MakeDivline(const line_t *li, divline_t *dl) +{ + dl->x = li->v1->x; + dl->y = li->v1->y; + dl->dx = li->dx; + dl->dy = li->dy; +} + +// +// P_InterceptVector +// Returns the fractional intercept point +// along the first divline. +// This is only called by the addthings +// and addlines traversers. +// + +/* cph - this is killough's 4/19/98 version of P_InterceptVector and + * P_InterceptVector2 (which were interchangeable). We still use this + * in compatibility mode. */ +fixed_t PUREFUNC P_InterceptVector2(const divline_t *v2, const divline_t *v1) +{ + fixed_t den; + return (den = FixedMul(v1->dy>>8, v2->dx) - FixedMul(v1->dx>>8, v2->dy)) ? + FixedDiv(FixedMul((v1->x - v2->x)>>8, v1->dy) + + FixedMul((v2->y - v1->y)>>8, v1->dx), den) : 0; +} + +fixed_t PUREFUNC P_InterceptVector(const divline_t *v2, const divline_t *v1) +{ + if (compatibility_level < prboom_4_compatibility) + return P_InterceptVector2(v2, v1); + else { + /* cph - This was introduced at prboom_4_compatibility - no precision/overflow problems */ + int_64_t den = (int_64_t)v1->dy * v2->dx - (int_64_t)v1->dx * v2->dy; + den >>= 16; + if (!den) + return 0; + return (fixed_t)(((int_64_t)(v1->x - v2->x) * v1->dy - (int_64_t)(v1->y - v2->y) * v1->dx) / den); + } +} + +// +// P_LineOpening +// Sets opentop and openbottom to the window +// through a two sided line. +// OPTIMIZE: keep this precalculated +// + +fixed_t opentop; +fixed_t openbottom; +fixed_t openrange; +fixed_t lowfloor; + +// moved front and back outside P-LineOpening and changed // phares 3/7/98 +// them to these so we can pick up the new friction value +// in PIT_CheckLine() +sector_t *openfrontsector; // made global // phares +sector_t *openbacksector; // made global + +void P_LineOpening(const line_t *linedef) +{ + if (linedef->sidenum[1] == NO_INDEX) // single sided line + { + openrange = 0; + return; + } + + openfrontsector = linedef->frontsector; + openbacksector = linedef->backsector; + + if (openfrontsector->ceilingheight < openbacksector->ceilingheight) + opentop = openfrontsector->ceilingheight; + else + opentop = openbacksector->ceilingheight; + + if (openfrontsector->floorheight > openbacksector->floorheight) + { + openbottom = openfrontsector->floorheight; + lowfloor = openbacksector->floorheight; + } + else + { + openbottom = openbacksector->floorheight; + lowfloor = openfrontsector->floorheight; + } + openrange = opentop - openbottom; +} + +// +// THING POSITION SETTING +// + +// +// P_UnsetThingPosition +// Unlinks a thing from block map and sectors. +// On each position change, BLOCKMAP and other +// lookups maintaining lists ot things inside +// these structures need to be updated. +// + +void P_UnsetThingPosition (mobj_t *thing) +{ + if (!(thing->flags & MF_NOSECTOR)) + { + /* invisible things don't need to be in sector list + * unlink from subsector + * + * killough 8/11/98: simpler scheme using pointers-to-pointers for prev + * pointers, allows head node pointers to be treated like everything else + */ + + mobj_t **sprev = thing->sprev; + mobj_t *snext = thing->snext; + if ((*sprev = snext)) // unlink from sector list + snext->sprev = sprev; + + // phares 3/14/98 + // + // Save the sector list pointed to by touching_sectorlist. + // In P_SetThingPosition, we'll keep any nodes that represent + // sectors the Thing still touches. We'll add new ones then, and + // delete any nodes for sectors the Thing has vacated. Then we'll + // put it back into touching_sectorlist. It's done this way to + // avoid a lot of deleting/creating for nodes, when most of the + // time you just get back what you deleted anyway. + // + // If this Thing is being removed entirely, then the calling + // routine will clear out the nodes in sector_list. + + sector_list = thing->touching_sectorlist; + thing->touching_sectorlist = NULL; //to be restored by P_SetThingPosition + } + + if (!(thing->flags & MF_NOBLOCKMAP)) + { + /* inert things don't need to be in blockmap + * + * killough 8/11/98: simpler scheme using pointers-to-pointers for prev + * pointers, allows head node pointers to be treated like everything else + * + * Also more robust, since it doesn't depend on current position for + * unlinking. Old method required computing head node based on position + * at time of unlinking, assuming it was the same position as during + * linking. + */ + + mobj_t *bnext, **bprev = thing->bprev; + if (bprev && (*bprev = bnext = thing->bnext)) // unlink from block map + bnext->bprev = bprev; + } +} + +// +// P_SetThingPosition +// Links a thing into both a block and a subsector +// based on it's x y. +// Sets thing->subsector properly +// +// killough 5/3/98: reformatted, cleaned up + +void P_SetThingPosition(mobj_t *thing) +{ // link into subsector + subsector_t *ss = thing->subsector = R_PointInSubsector(thing->x, thing->y); + if (!(thing->flags & MF_NOSECTOR)) + { + // invisible things don't go into the sector links + + // killough 8/11/98: simpler scheme using pointer-to-pointer prev + // pointers, allows head nodes to be treated like everything else + + mobj_t **link = &ss->sector->thinglist; + mobj_t *snext = *link; + if ((thing->snext = snext)) + snext->sprev = &thing->snext; + thing->sprev = link; + *link = thing; + + // phares 3/16/98 + // + // If sector_list isn't NULL, it has a collection of sector + // nodes that were just removed from this Thing. + + // Collect the sectors the object will live in by looking at + // the existing sector_list and adding new nodes and deleting + // obsolete ones. + + // When a node is deleted, its sector links (the links starting + // at sector_t->touching_thinglist) are broken. When a node is + // added, new sector links are created. + + P_CreateSecNodeList(thing,thing->x,thing->y); + thing->touching_sectorlist = sector_list; // Attach to Thing's mobj_t + sector_list = NULL; // clear for next time + } + + // link into blockmap + if (!(thing->flags & MF_NOBLOCKMAP)) + { + // inert things don't need to be in blockmap + int blockx = (thing->x - bmaporgx)>>MAPBLOCKSHIFT; + int blocky = (thing->y - bmaporgy)>>MAPBLOCKSHIFT; + if (blockx>=0 && blockx < bmapwidth && blocky>=0 && blocky < bmapheight) + { + // killough 8/11/98: simpler scheme using pointer-to-pointer prev + // pointers, allows head nodes to be treated like everything else + + mobj_t **link = &blocklinks[blocky*bmapwidth+blockx]; + mobj_t *bnext = *link; + if ((thing->bnext = bnext)) + bnext->bprev = &thing->bnext; + thing->bprev = link; + *link = thing; + } + else // thing is off the map + thing->bnext = NULL, thing->bprev = NULL; + } +} + +// +// BLOCK MAP ITERATORS +// For each line/thing in the given mapblock, +// call the passed PIT_* function. +// If the function returns false, +// exit with false without checking anything else. +// + +// +// P_BlockLinesIterator +// The validcount flags are used to avoid checking lines +// that are marked in multiple mapblocks, +// so increment validcount before the first call +// to P_BlockLinesIterator, then make one or more calls +// to it. +// +// killough 5/3/98: reformatted, cleaned up + +boolean P_BlockLinesIterator(int x, int y, boolean func(line_t*)) +{ + int offset; + const long *list; // killough 3/1/98: for removal of blockmap limit + + if (x<0 || y<0 || x>=bmapwidth || y>=bmapheight) + return true; + offset = y*bmapwidth+x; + offset = *(blockmap+offset); + list = blockmaplump+offset; // original was reading // phares + // delmiting 0 as linedef 0 // phares + + // killough 1/31/98: for compatibility we need to use the old method. + // Most demos go out of sync, and maybe other problems happen, if we + // don't consider linedef 0. For safety this should be qualified. + + if (!demo_compatibility) // killough 2/22/98: demo_compatibility check + list++; // skip 0 starting delimiter // phares + for ( ; *list != -1 ; list++) // phares + { + line_t *ld = &lines[*list]; + if (ld->validcount == validcount) + continue; // line has already been checked + ld->validcount = validcount; + if (!func(ld)) + return false; + } + return true; // everything was checked +} + +// +// P_BlockThingsIterator +// +// killough 5/3/98: reformatted, cleaned up + +boolean P_BlockThingsIterator(int x, int y, boolean func(mobj_t*)) +{ + mobj_t *mobj; + if (!(x<0 || y<0 || x>=bmapwidth || y>=bmapheight)) + for (mobj = blocklinks[y*bmapwidth+x]; mobj; mobj = mobj->bnext) + if (!func(mobj)) + return false; + return true; +} + +// +// INTERCEPT ROUTINES +// + +// 1/11/98 killough: Intercept limit removed +static intercept_t *intercepts, *intercept_p; + +// Check for limit and double size if necessary -- killough +static void check_intercept(void) +{ + static size_t num_intercepts; + size_t offset = intercept_p - intercepts; + if (offset >= num_intercepts) + { + num_intercepts = num_intercepts ? num_intercepts*2 : 128; + intercepts = realloc(intercepts, sizeof(*intercepts)*num_intercepts); + intercept_p = intercepts + offset; + } +} + +divline_t trace; + +// PIT_AddLineIntercepts. +// Looks for lines in the given block +// that intercept the given trace +// to add to the intercepts list. +// +// A line is crossed if its endpoints +// are on opposite sides of the trace. +// +// killough 5/3/98: reformatted, cleaned up + +boolean PIT_AddLineIntercepts(line_t *ld) +{ + int s1; + int s2; + fixed_t frac; + divline_t dl; + + // avoid precision problems with two routines + if (trace.dx > FRACUNIT*16 || trace.dy > FRACUNIT*16 || + trace.dx < -FRACUNIT*16 || trace.dy < -FRACUNIT*16) + { + s1 = P_PointOnDivlineSide (ld->v1->x, ld->v1->y, &trace); + s2 = P_PointOnDivlineSide (ld->v2->x, ld->v2->y, &trace); + } + else + { + s1 = P_PointOnLineSide (trace.x, trace.y, ld); + s2 = P_PointOnLineSide (trace.x+trace.dx, trace.y+trace.dy, ld); + } + + if (s1 == s2) + return true; // line isn't crossed + + // hit the line + P_MakeDivline(ld, &dl); + frac = P_InterceptVector(&trace, &dl); + + if (frac < 0) + return true; // behind source + + check_intercept(); // killough + + intercept_p->frac = frac; + intercept_p->isaline = true; + intercept_p->d.line = ld; + intercept_p++; + + return true; // continue +} + +// +// PIT_AddThingIntercepts +// +// killough 5/3/98: reformatted, cleaned up + +boolean PIT_AddThingIntercepts(mobj_t *thing) +{ + fixed_t x1, y1; + fixed_t x2, y2; + int s1, s2; + divline_t dl; + fixed_t frac; + + // check a corner to corner crossection for hit + if ((trace.dx ^ trace.dy) > 0) + { + x1 = thing->x - thing->radius; + y1 = thing->y + thing->radius; + x2 = thing->x + thing->radius; + y2 = thing->y - thing->radius; + } + else + { + x1 = thing->x - thing->radius; + y1 = thing->y - thing->radius; + x2 = thing->x + thing->radius; + y2 = thing->y + thing->radius; + } + + s1 = P_PointOnDivlineSide (x1, y1, &trace); + s2 = P_PointOnDivlineSide (x2, y2, &trace); + + if (s1 == s2) + return true; // line isn't crossed + + dl.x = x1; + dl.y = y1; + dl.dx = x2-x1; + dl.dy = y2-y1; + + frac = P_InterceptVector (&trace, &dl); + + if (frac < 0) + return true; // behind source + + check_intercept(); // killough + + intercept_p->frac = frac; + intercept_p->isaline = false; + intercept_p->d.thing = thing; + intercept_p++; + + return true; // keep going +} + +// +// P_TraverseIntercepts +// Returns true if the traverser function returns true +// for all lines. +// +// killough 5/3/98: reformatted, cleaned up + +boolean P_TraverseIntercepts(traverser_t func, fixed_t maxfrac) +{ + intercept_t *in = NULL; + int count = intercept_p - intercepts; + while (count--) + { + fixed_t dist = INT_MAX; + intercept_t *scan; + for (scan = intercepts; scan < intercept_p; scan++) + if (scan->frac < dist) + dist = (in=scan)->frac; + if (dist > maxfrac) + return true; // checked everything in range + if (!func(in)) + return false; // don't bother going farther + in->frac = INT_MAX; + } + return true; // everything was traversed +} + +// +// P_PathTraverse +// Traces a line from x1,y1 to x2,y2, +// calling the traverser function for each. +// Returns true if the traverser function returns true +// for all lines. +// +// killough 5/3/98: reformatted, cleaned up + +boolean P_PathTraverse(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, + int flags, boolean trav(intercept_t *)) +{ + fixed_t xt1, yt1; + fixed_t xt2, yt2; + fixed_t xstep, ystep; + fixed_t partial; + fixed_t xintercept, yintercept; + int mapx, mapy; + int mapxstep, mapystep; + int count; + + validcount++; + intercept_p = intercepts; + + if (!((x1-bmaporgx)&(MAPBLOCKSIZE-1))) + x1 += FRACUNIT; // don't side exactly on a line + + if (!((y1-bmaporgy)&(MAPBLOCKSIZE-1))) + y1 += FRACUNIT; // don't side exactly on a line + + trace.x = x1; + trace.y = y1; + trace.dx = x2 - x1; + trace.dy = y2 - y1; + + x1 -= bmaporgx; + y1 -= bmaporgy; + xt1 = x1>>MAPBLOCKSHIFT; + yt1 = y1>>MAPBLOCKSHIFT; + + x2 -= bmaporgx; + y2 -= bmaporgy; + xt2 = x2>>MAPBLOCKSHIFT; + yt2 = y2>>MAPBLOCKSHIFT; + + if (xt2 > xt1) + { + mapxstep = 1; + partial = FRACUNIT - ((x1>>MAPBTOFRAC)&(FRACUNIT-1)); + ystep = FixedDiv (y2-y1,D_abs(x2-x1)); + } + else + if (xt2 < xt1) + { + mapxstep = -1; + partial = (x1>>MAPBTOFRAC)&(FRACUNIT-1); + ystep = FixedDiv (y2-y1,D_abs(x2-x1)); + } + else + { + mapxstep = 0; + partial = FRACUNIT; + ystep = 256*FRACUNIT; + } + + yintercept = (y1>>MAPBTOFRAC) + FixedMul(partial, ystep); + + if (yt2 > yt1) + { + mapystep = 1; + partial = FRACUNIT - ((y1>>MAPBTOFRAC)&(FRACUNIT-1)); + xstep = FixedDiv (x2-x1,D_abs(y2-y1)); + } + else + if (yt2 < yt1) + { + mapystep = -1; + partial = (y1>>MAPBTOFRAC)&(FRACUNIT-1); + xstep = FixedDiv (x2-x1,D_abs(y2-y1)); + } + else + { + mapystep = 0; + partial = FRACUNIT; + xstep = 256*FRACUNIT; + } + + xintercept = (x1>>MAPBTOFRAC) + FixedMul (partial, xstep); + + // Step through map blocks. + // Count is present to prevent a round off error + // from skipping the break. + + mapx = xt1; + mapy = yt1; + + for (count = 0; count < 64; count++) + { + if (flags & PT_ADDLINES) + if (!P_BlockLinesIterator(mapx, mapy,PIT_AddLineIntercepts)) + return false; // early out + + if (flags & PT_ADDTHINGS) + if (!P_BlockThingsIterator(mapx, mapy,PIT_AddThingIntercepts)) + return false; // early out + + if (mapx == xt2 && mapy == yt2) + break; + + if ((yintercept >> FRACBITS) == mapy) + { + yintercept += ystep; + mapx += mapxstep; + } + else + if ((xintercept >> FRACBITS) == mapx) + { + xintercept += xstep; + mapy += mapystep; + } + } + + // go through the sorted list + return P_TraverseIntercepts(trav, FRACUNIT); +} diff --git a/common/prboom/p_maputl.h b/common/prboom/p_maputl.h new file mode 100755 index 0000000..8a70ba0 --- /dev/null +++ b/common/prboom/p_maputl.h @@ -0,0 +1,89 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Map utility functions + * + *-----------------------------------------------------------------------------*/ + +#ifndef __P_MAPUTL__ +#define __P_MAPUTL__ + +#include "r_defs.h" + +/* mapblocks are used to check movement against lines and things */ +#define MAPBLOCKUNITS 128 +#define MAPBLOCKSIZE (MAPBLOCKUNITS*FRACUNIT) +#define MAPBLOCKSHIFT (FRACBITS+7) +#define MAPBMASK (MAPBLOCKSIZE-1) +#define MAPBTOFRAC (MAPBLOCKSHIFT-FRACBITS) + +#define PT_ADDLINES 1 +#define PT_ADDTHINGS 2 +#define PT_EARLYOUT 4 + +typedef struct { + fixed_t x; + fixed_t y; + fixed_t dx; + fixed_t dy; +} divline_t; + +typedef struct { + fixed_t frac; /* along trace line */ + boolean isaline; + union { + mobj_t* thing; + line_t* line; + } d; +} intercept_t; + +typedef boolean (*traverser_t)(intercept_t *in); + +fixed_t CONSTFUNC P_AproxDistance (fixed_t dx, fixed_t dy); +int PUREFUNC P_PointOnLineSide (fixed_t x, fixed_t y, const line_t *line); +int PUREFUNC P_BoxOnLineSide (const fixed_t *tmbox, const line_t *ld); +fixed_t PUREFUNC P_InterceptVector (const divline_t *v2, const divline_t *v1); +/* cph - old compatibility version below */ +fixed_t PUREFUNC P_InterceptVector2(const divline_t *v2, const divline_t *v1); + +void P_LineOpening (const line_t *linedef); +void P_UnsetThingPosition(mobj_t *thing); +void P_SetThingPosition(mobj_t *thing); +boolean P_BlockLinesIterator (int x, int y, boolean func(line_t *)); +boolean P_BlockThingsIterator(int x, int y, boolean func(mobj_t *)); +boolean P_PathTraverse(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, + int flags, boolean trav(intercept_t *)); + +extern fixed_t opentop; +extern fixed_t openbottom; +extern fixed_t openrange; +extern fixed_t lowfloor; +extern divline_t trace; + +#endif /* __P_MAPUTL__ */ diff --git a/common/prboom/p_mobj.c b/common/prboom/p_mobj.c new file mode 100755 index 0000000..83d63e8 --- /dev/null +++ b/common/prboom/p_mobj.c @@ -0,0 +1,1527 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2004 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Moving object handling. Spawn functions. + * + *-----------------------------------------------------------------------------*/ + +#include "doomdef.h" +#include "doomstat.h" +#include "m_random.h" +#include "r_main.h" +#include "p_maputl.h" +#include "p_map.h" +#include "p_tick.h" +#include "sounds.h" +#include "st_stuff.h" +#include "hu_stuff.h" +#include "s_sound.h" +#include "info.h" +#include "g_game.h" +#include "p_inter.h" +#include "lprintf.h" +#include "r_demo.h" + +// +// P_SetMobjState +// Returns true if the mobj is still present. +// + +boolean P_SetMobjState(mobj_t* mobj,statenum_t state) + { + state_t* st; + + // killough 4/9/98: remember states seen, to detect cycles: + + static statenum_t seenstate_tab[NUMSTATES]; // fast transition table + statenum_t *seenstate = seenstate_tab; // pointer to table + static int recursion; // detects recursion + statenum_t i = state; // initial state + boolean ret = true; // return value + statenum_t tempstate[NUMSTATES]; // for use with recursion + + if (recursion++) // if recursion detected, + memset(seenstate=tempstate,0,sizeof tempstate); // clear state table + + do + { + if (state == S_NULL) + { + mobj->state = (state_t *) S_NULL; + P_RemoveMobj (mobj); + ret = false; + break; // killough 4/9/98 + } + + st = &states[state]; + mobj->state = st; + mobj->tics = st->tics; + mobj->sprite = st->sprite; + mobj->frame = st->frame; + + // Modified handling. + // Call action functions when the state is set + + if (st->action) + st->action(mobj); + + seenstate[state] = 1 + st->nextstate; // killough 4/9/98 + + state = st->nextstate; + } while (!mobj->tics && !seenstate[state]); // killough 4/9/98 + + if (ret && !mobj->tics) // killough 4/9/98: detect state cycles + doom_printf("Warning: State Cycle Detected"); + + if (!--recursion) + for (;(state=seenstate[i]);i=state-1) + seenstate[i] = 0; // killough 4/9/98: erase memory of states + + return ret; + } + + +// +// P_ExplodeMissile +// + +void P_ExplodeMissile (mobj_t* mo) + { + mo->momx = mo->momy = mo->momz = 0; + + P_SetMobjState (mo, mobjinfo[mo->type].deathstate); + + mo->tics -= P_Random(pr_explode)&3; + + if (mo->tics < 1) + mo->tics = 1; + + mo->flags &= ~MF_MISSILE; + + if (mo->info->deathsound) + S_StartSound (mo, mo->info->deathsound); + } + + +// +// P_XYMovement +// +// Attempts to move something if it has momentum. +// + +static void P_XYMovement (mobj_t* mo) + { + player_t *player; + fixed_t xmove, ymove; + + //e6y + fixed_t oldx,oldy; // phares 9/10/98: reducing bobbing/momentum on ice + +#if 0 + fixed_t ptryx; + fixed_t ptryy; + fixed_t xmove; + fixed_t ymove; + fixed_t oldx,oldy; // phares 9/10/98: reducing bobbing/momentum on ice + // when up against walls +#endif + if (!(mo->momx | mo->momy)) // Any momentum? + { + if (mo->flags & MF_SKULLFLY) + { + + // the skull slammed into something + + mo->flags &= ~MF_SKULLFLY; + mo->momz = 0; + + P_SetMobjState (mo, mo->info->spawnstate); + } + return; + } + + player = mo->player; + + if (mo->momx > MAXMOVE) + mo->momx = MAXMOVE; + else if (mo->momx < -MAXMOVE) + mo->momx = -MAXMOVE; + + if (mo->momy > MAXMOVE) + mo->momy = MAXMOVE; + else if (mo->momy < -MAXMOVE) + mo->momy = -MAXMOVE; + + xmove = mo->momx; + ymove = mo->momy; + + oldx = mo->x; // phares 9/10/98: new code to reduce bobbing/momentum + oldy = mo->y; // when on ice & up against wall. These will be compared + // to your x,y values later to see if you were able to move + + do + { + fixed_t ptryx, ptryy; + // killough 8/9/98: fix bug in original Doom source: + // Large negative displacements were never considered. + // This explains the tendency for Mancubus fireballs + // to pass through walls. + // CPhipps - compatibility optioned + + if (xmove > MAXMOVE/2 || ymove > MAXMOVE/2 || + (!comp[comp_moveblock] + && (xmove < -MAXMOVE/2 || ymove < -MAXMOVE/2))) + { + ptryx = mo->x + xmove/2; + ptryy = mo->y + ymove/2; + xmove >>= 1; + ymove >>= 1; + } + else + { + ptryx = mo->x + xmove; + ptryy = mo->y + ymove; + xmove = ymove = 0; + } + + // killough 3/15/98: Allow objects to drop off + + if (!P_TryMove (mo, ptryx, ptryy, true)) + { + // blocked move + + // killough 8/11/98: bouncing off walls + // killough 10/98: + // Add ability for objects other than players to bounce on ice + + if (!(mo->flags & MF_MISSILE) && + mbf_features && + (mo->flags & MF_BOUNCES || + (!player && blockline && + variable_friction && mo->z <= mo->floorz && + P_GetFriction(mo, NULL) > ORIG_FRICTION))) + { + if (blockline) + { + fixed_t r = ((blockline->dx >> FRACBITS) * mo->momx + + (blockline->dy >> FRACBITS) * mo->momy) / + ((blockline->dx >> FRACBITS)*(blockline->dx >> FRACBITS)+ + (blockline->dy >> FRACBITS)*(blockline->dy >> FRACBITS)); + fixed_t x = FixedMul(r, blockline->dx); + fixed_t y = FixedMul(r, blockline->dy); + + // reflect momentum away from wall + + mo->momx = x*2 - mo->momx; + mo->momy = y*2 - mo->momy; + + // if under gravity, slow down in + // direction perpendicular to wall. + + if (!(mo->flags & MF_NOGRAVITY)) + { + mo->momx = (mo->momx + x)/2; + mo->momy = (mo->momy + y)/2; + } + } + else + mo->momx = mo->momy = 0; + } + else + if (player) // try to slide along it + P_SlideMove (mo); + else + if (mo->flags & MF_MISSILE) + { + // explode a missile + + if (ceilingline && + ceilingline->backsector && + ceilingline->backsector->ceilingpic == skyflatnum) + if (demo_compatibility || // killough + mo->z > ceilingline->backsector->ceilingheight) + { + // Hack to prevent missiles exploding + // against the sky. + // Does not handle sky floors. + + P_RemoveMobj (mo); + return; + } + P_ExplodeMissile (mo); + } + else // whatever else it is, it is now standing still in (x,y) + mo->momx = mo->momy = 0; + } + } while (xmove || ymove); + + // slow down + +#if 0 /* killough 10/98: this is unused code (except maybe in .deh files?) */ + if (player && player->cheats & CF_NOMOMENTUM) + { + // debug option for no sliding at all + mo->momx = mo->momy = 0; + player->momx = player->momy = 0; /* killough 10/98 */ + return; + } +#endif + + /* no friction for missiles or skulls ever, no friction when airborne */ + if (mo->flags & (MF_MISSILE | MF_SKULLFLY) || mo->z > mo->floorz) + return; + + /* killough 8/11/98: add bouncers + * killough 9/15/98: add objects falling off ledges + * killough 11/98: only include bouncers hanging off ledges + */ + if (((mo->flags & MF_BOUNCES && mo->z > mo->dropoffz) || + mo->flags & MF_CORPSE || mo->intflags & MIF_FALLING) && + (mo->momx > FRACUNIT/4 || mo->momx < -FRACUNIT/4 || + mo->momy > FRACUNIT/4 || mo->momy < -FRACUNIT/4) && + mo->floorz != mo->subsector->sector->floorheight) + return; // do not stop sliding if halfway off a step with some momentum + + // killough 11/98: + // Stop voodoo dolls that have come to rest, despite any + // moving corresponding player, except in old demos: + + if (mo->momx > -STOPSPEED && mo->momx < STOPSPEED && + mo->momy > -STOPSPEED && mo->momy < STOPSPEED && + (!player || !(player->cmd.forwardmove | player->cmd.sidemove) || + (player->mo != mo && compatibility_level >= lxdoom_1_compatibility))) + { + // if in a walking frame, stop moving + + // killough 10/98: + // Don't affect main player when voodoo dolls stop, except in old demos: + +// if ( player&&(unsigned)((player->mo->state - states)- S_PLAY_RUN1) < 4) +// P_SetMobjState (player->mo, S_PLAY); + if (player && (unsigned)(player->mo->state - states - S_PLAY_RUN1) < 4 + && (player->mo == mo || compatibility_level >= lxdoom_1_compatibility)) + P_SetMobjState(player->mo, S_PLAY); + + mo->momx = mo->momy = 0; + + /* killough 10/98: kill any bobbing momentum too (except in voodoo dolls) + * cph - DEMOSYNC - needs compatibility check? + */ + if (player && player->mo == mo) + player->momx = player->momy = 0; + } + else + { + /* phares 3/17/98 + * + * Friction will have been adjusted by friction thinkers for + * icy or muddy floors. Otherwise it was never touched and + * remained set at ORIG_FRICTION + * + * killough 8/28/98: removed inefficient thinker algorithm, + * instead using touching_sectorlist in P_GetFriction() to + * determine friction (and thus only when it is needed). + * + * killough 10/98: changed to work with new bobbing method. + * Reducing player momentum is no longer needed to reduce + * bobbing, so ice works much better now. + * + * cph - DEMOSYNC - need old code for Boom demos? + */ + + //e6y + if (compatibility_level <= boom_201_compatibility) + { + // phares 3/17/98 + // Friction will have been adjusted by friction thinkers for icy + // or muddy floors. Otherwise it was never touched and + // remained set at ORIG_FRICTION + mo->momx = FixedMul(mo->momx,mo->friction); + mo->momy = FixedMul(mo->momy,mo->friction); + mo->friction = ORIG_FRICTION; // reset to normal for next tic + } + else if (compatibility_level <= lxdoom_1_compatibility) + { + // phares 9/10/98: reduce bobbing/momentum when on ice & up against wall + + if ((oldx == mo->x) && (oldy == mo->y)) // Did you go anywhere? + { // No. Use original friction. This allows you to not bob so much + // if you're on ice, but keeps enough momentum around to break free + // when you're mildly stuck in a wall. + mo->momx = FixedMul(mo->momx,ORIG_FRICTION); + mo->momy = FixedMul(mo->momy,ORIG_FRICTION); + } + else + { // Yes. Use stored friction. + mo->momx = FixedMul(mo->momx,mo->friction); + mo->momy = FixedMul(mo->momy,mo->friction); + } + mo->friction = ORIG_FRICTION; // reset to normal for next tic + } + else + { + + fixed_t friction = P_GetFriction(mo, NULL); + + mo->momx = FixedMul(mo->momx, friction); + mo->momy = FixedMul(mo->momy, friction); + + /* killough 10/98: Always decrease player bobbing by ORIG_FRICTION. + * This prevents problems with bobbing on ice, where it was not being + * reduced fast enough, leading to all sorts of kludges being developed. + */ + + if (player && player->mo == mo) /* Not voodoo dolls */ + { + player->momx = FixedMul(player->momx, ORIG_FRICTION); + player->momy = FixedMul(player->momy, ORIG_FRICTION); + } + + } + + } + } + + +// +// P_ZMovement +// +// Attempt vertical movement. + +static void P_ZMovement (mobj_t* mo) +{ + /* killough 7/11/98: + * BFG fireballs bounced on floors and ceilings in Pre-Beta Doom + * killough 8/9/98: added support for non-missile objects bouncing + * (e.g. grenade, mine, pipebomb) + */ + + if (mo->flags & MF_BOUNCES && mo->momz) { + mo->z += mo->momz; + if (mo->z <= mo->floorz) { /* bounce off floors */ + mo->z = mo->floorz; + if (mo->momz < 0) { + mo->momz = -mo->momz; + if (!(mo->flags & MF_NOGRAVITY)) { /* bounce back with decay */ + mo->momz = mo->flags & MF_FLOAT ? // floaters fall slowly + mo->flags & MF_DROPOFF ? // DROPOFF indicates rate + FixedMul(mo->momz, (fixed_t)(FRACUNIT*.85)) : + FixedMul(mo->momz, (fixed_t)(FRACUNIT*.70)) : + FixedMul(mo->momz, (fixed_t)(FRACUNIT*.45)) ; + + /* Bring it to rest below a certain speed */ + if (D_abs(mo->momz) <= mo->info->mass*(GRAVITY*4/256)) + mo->momz = 0; + } + + /* killough 11/98: touchy objects explode on impact */ + if (mo->flags & MF_TOUCHY && mo->intflags & MIF_ARMED + && mo->health > 0) + P_DamageMobj(mo, NULL, NULL, mo->health); + else if (mo->flags & MF_FLOAT && sentient(mo)) + goto floater; + return; + } + } else if (mo->z >= mo->ceilingz - mo->height) { + /* bounce off ceilings */ + mo->z = mo->ceilingz - mo->height; + if (mo->momz > 0) { + if (mo->subsector->sector->ceilingpic != skyflatnum) + mo->momz = -mo->momz; /* always bounce off non-sky ceiling */ + else if (mo->flags & MF_MISSILE) + P_RemoveMobj(mo); /* missiles don't bounce off skies */ + else if (mo->flags & MF_NOGRAVITY) + mo->momz = -mo->momz; // bounce unless under gravity + + if (mo->flags & MF_FLOAT && sentient(mo)) + goto floater; + + return; + } + } else { + if (!(mo->flags & MF_NOGRAVITY)) /* free-fall under gravity */ + mo->momz -= mo->info->mass*(GRAVITY/256); + + if (mo->flags & MF_FLOAT && sentient(mo)) goto floater; + return; + } + + /* came to a stop */ + mo->momz = 0; + + if (mo->flags & MF_MISSILE) { + if (ceilingline && + ceilingline->backsector && + ceilingline->backsector->ceilingpic == skyflatnum && + mo->z > ceilingline->backsector->ceilingheight) + P_RemoveMobj(mo); /* don't explode on skies */ + else + P_ExplodeMissile(mo); + } + + if (mo->flags & MF_FLOAT && sentient(mo)) goto floater; + return; + } + + /* killough 8/9/98: end bouncing object code */ + + // check for smooth step up + + if (mo->player && + mo->player->mo == mo && // killough 5/12/98: exclude voodoo dolls + mo->z < mo->floorz) + { + mo->player->viewheight -= mo->floorz-mo->z; + mo->player->deltaviewheight = (VIEWHEIGHT - mo->player->viewheight)>>3; + } + + // adjust altitude + + mo->z += mo->momz; + +floater: + if ((mo->flags & MF_FLOAT) && mo->target) + + // float down towards target if too close + + if (!((mo->flags ^ MF_FLOAT) & (MF_FLOAT | MF_SKULLFLY | MF_INFLOAT)) && + mo->target) /* killough 11/98: simplify */ + { + fixed_t delta; + if (P_AproxDistance(mo->x - mo->target->x, mo->y - mo->target->y) < + D_abs(delta = mo->target->z + (mo->height>>1) - mo->z)*3) + mo->z += delta < 0 ? -FLOATSPEED : FLOATSPEED; + } + + // clip movement + + if (mo->z <= mo->floorz) + { + // hit the floor + + /* Note (id): + * somebody left this after the setting momz to 0, + * kinda useless there. + * cph - This was the a bug in the linuxdoom-1.10 source which + * caused it not to sync Doom 2 v1.9 demos. Someone + * added the above comment and moved up the following code. So + * demos would desync in close lost soul fights. + * cph - revised 2001/04/15 - + * This was a bug in the Doom/Doom 2 source; the following code + * is meant to make charging lost souls bounce off of floors, but it + * was incorrectly placed after momz was set to 0. + * However, this bug was fixed in Doom95, Final/Ultimate Doom, and + * the v1.10 source release (which is one reason why it failed to sync + * some Doom2 v1.9 demos) + * I've added a comp_soul compatibility option to make this behavior + * selectable for PrBoom v2.3+. For older demos, we do this here only + * if we're in a compatibility level above Doom 2 v1.9 (in which case we + * mimic the bug and do it further down instead) + */ + + if (mo->flags & MF_SKULLFLY && + (!comp[comp_soul] || + (compatibility_level > doom2_19_compatibility && + compatibility_level < prboom_4_compatibility) + )) + mo->momz = -mo->momz; // the skull slammed into something + + if (mo->momz < 0) + { + /* killough 11/98: touchy objects explode on impact */ + if (mo->flags & MF_TOUCHY && mo->intflags & MIF_ARMED && mo->health > 0) + P_DamageMobj(mo, NULL, NULL, mo->health); + else + if (mo->player && /* killough 5/12/98: exclude voodoo dolls */ + mo->player->mo == mo && mo->momz < -GRAVITY*8) + { + // Squat down. + // Decrease viewheight for a moment + // after hitting the ground (hard), + // and utter appropriate sound. + + mo->player->deltaviewheight = mo->momz>>3; + /* cph - prevent "oof" when dead */ + if (comp[comp_sound] || mo->health > 0) + S_StartSound (mo, sfx_oof); + } + mo->momz = 0; + } + mo->z = mo->floorz; + + /* cph 2001/04/15 - + * This is the buggy lost-soul bouncing code referenced above. + * We've already set momz = 0 normally by this point, so it's useless. + * However we might still have upward momentum, in which case this will + * incorrectly reverse it, so we might still need this for demo sync + */ + if (mo->flags & MF_SKULLFLY && + compatibility_level <= doom2_19_compatibility) + mo->momz = -mo->momz; // the skull slammed into something + + if ( (mo->flags & MF_MISSILE) && !(mo->flags & MF_NOCLIP) ) + { + P_ExplodeMissile (mo); + return; + } + } + else // still above the floor // phares + if (!(mo->flags & MF_NOGRAVITY)) + { + if (!mo->momz) + mo->momz = -GRAVITY; + mo->momz -= GRAVITY; + } + + if (mo->z + mo->height > mo->ceilingz) + { + /* cph 2001/04/15 - + * Lost souls were meant to bounce off of ceilings; + * new comp_soul compatibility option added + */ + if (!comp[comp_soul] && mo->flags & MF_SKULLFLY) + mo->momz = -mo->momz; // the skull slammed into something + + // hit the ceiling + + if (mo->momz > 0) + mo->momz = 0; + + mo->z = mo->ceilingz - mo->height; + + /* cph 2001/04/15 - + * We might have hit a ceiling but had downward momentum (e.g. ceiling is + * lowering on us), so for old demos we must still do the buggy + * momentum reversal here + */ + if (comp[comp_soul] && mo->flags & MF_SKULLFLY) + mo->momz = -mo->momz; // the skull slammed into something + + if ( (mo->flags & MF_MISSILE) && !(mo->flags & MF_NOCLIP) ) + { + P_ExplodeMissile (mo); + return; + } + } + } + +// +// P_NightmareRespawn +// + +static void P_NightmareRespawn(mobj_t* mobj) + { + fixed_t x; + fixed_t y; + fixed_t z; + subsector_t* ss; + mobj_t* mo; + mapthing_t* mthing; + + x = mobj->spawnpoint.x << FRACBITS; + y = mobj->spawnpoint.y << FRACBITS; + + /* haleyjd: stupid nightmare respawning bug fix + * + * 08/09/00: compatibility added, time to ramble :) + * This fixes the notorious nightmare respawning bug that causes monsters + * that didn't spawn at level startup to respawn at the point (0,0) + * regardless of that point's nature. SMMU and Eternity need this for + * script-spawned things like Halif Swordsmythe, as well. + * + * cph - copied from eternity, except comp_respawnfix becomes comp_respawn + * and the logic is reversed (i.e. like the rest of comp_ it *disables* + * the fix) + */ + if(!comp[comp_respawn] && !x && !y) + { + // spawnpoint was zeroed out, so use point of death instead + x = mobj->x; + y = mobj->y; + } + + // something is occupying its position? + + if (!P_CheckPosition (mobj, x, y) ) + return; // no respwan + + // spawn a teleport fog at old spot + // because of removal of the body? + + mo = P_SpawnMobj (mobj->x, + mobj->y, + mobj->subsector->sector->floorheight, + MT_TFOG); + + // initiate teleport sound + + S_StartSound (mo, sfx_telept); + + // spawn a teleport fog at the new spot + + ss = R_PointInSubsector (x,y); + + mo = P_SpawnMobj (x, y, ss->sector->floorheight , MT_TFOG); + + S_StartSound (mo, sfx_telept); + + // spawn the new monster + + mthing = &mobj->spawnpoint; + if (mobj->info->flags & MF_SPAWNCEILING) + z = ONCEILINGZ; + else + z = ONFLOORZ; + + // inherit attributes from deceased one + + mo = P_SpawnMobj (x,y,z, mobj->type); + mo->spawnpoint = mobj->spawnpoint; + mo->angle = ANG45 * (mthing->angle/45); + + if (mthing->options & MTF_AMBUSH) + mo->flags |= MF_AMBUSH; + + /* killough 11/98: transfer friendliness from deceased */ + mo->flags = (mo->flags & ~MF_FRIEND) | (mobj->flags & MF_FRIEND); + + mo->reactiontime = 18; + + // remove the old monster, + + P_RemoveMobj (mobj); + } + + +// +// P_MobjThinker +// + +void P_MobjThinker (mobj_t* mobj) + { + // killough 11/98: + // removed old code which looked at target references + // (we use pointer reference counting now) + + mobj->PrevX = mobj->x; + mobj->PrevY = mobj->y; + mobj->PrevZ = mobj->z; + + // momentum movement + if (mobj->momx | mobj->momy || mobj->flags & MF_SKULLFLY) + { + P_XYMovement(mobj); + if (mobj->thinker.function != P_MobjThinker) // cph - Must've been removed + return; // killough - mobj was removed + } + + if (mobj->z != mobj->floorz || mobj->momz) + { + P_ZMovement(mobj); + if (mobj->thinker.function != P_MobjThinker) // cph - Must've been removed + return; // killough - mobj was removed + } + else + if (!(mobj->momx | mobj->momy) && !sentient(mobj)) + { // non-sentient objects at rest + mobj->intflags |= MIF_ARMED; // arm a mine which has come to rest + + // killough 9/12/98: objects fall off ledges if they are hanging off + // slightly push off of ledge if hanging more than halfway off + + if (mobj->z > mobj->dropoffz && // Only objects contacting dropoff + !(mobj->flags & MF_NOGRAVITY) && // Only objects which fall + !comp[comp_falloff]) // Not in old demos + P_ApplyTorque(mobj); // Apply torque + else + mobj->intflags &= ~MIF_FALLING, mobj->gear = 0; // Reset torque + } + + // cycle through states, + // calling action functions at transitions + + if (mobj->tics != -1) + { + mobj->tics--; + + // you can cycle through multiple states in a tic + + if (!mobj->tics) + if (!P_SetMobjState (mobj, mobj->state->nextstate) ) + return; // freed itself + } + else + { + + // check for nightmare respawn + + if (! (mobj->flags & MF_COUNTKILL) ) + return; + + if (!respawnmonsters) + return; + + mobj->movecount++; + + if (mobj->movecount < 12*35) + return; + + if (leveltime & 31) + return; + + if (P_Random (pr_respawn) > 4) + return; + + P_NightmareRespawn (mobj); + } + + } + + +// +// P_SpawnMobj +// +mobj_t* P_SpawnMobj(fixed_t x,fixed_t y,fixed_t z,mobjtype_t type) + { + mobj_t* mobj; + state_t* st; + mobjinfo_t* info; + + mobj = Z_Malloc (sizeof(*mobj), PU_LEVEL, NULL); + memset (mobj, 0, sizeof (*mobj)); + info = &mobjinfo[type]; + mobj->type = type; + mobj->info = info; + mobj->x = x; + mobj->y = y; + mobj->radius = info->radius; + mobj->height = info->height; // phares + mobj->flags = info->flags; + + /* killough 8/23/98: no friends, bouncers, or touchy things in old demos */ + if (!mbf_features) + mobj->flags &= ~(MF_BOUNCES | MF_FRIEND | MF_TOUCHY); + else + if (type == MT_PLAYER) // Except in old demos, players + mobj->flags |= MF_FRIEND; // are always friends. + + mobj->health = info->spawnhealth; + + if (gameskill != sk_nightmare) + mobj->reactiontime = info->reactiontime; + + mobj->lastlook = P_Random (pr_lastlook) % MAXPLAYERS; + + // do not set the state with P_SetMobjState, + // because action routines can not be called yet + + st = &states[info->spawnstate]; + + mobj->state = st; + mobj->tics = st->tics; + mobj->sprite = st->sprite; + mobj->frame = st->frame; + mobj->touching_sectorlist = NULL; // NULL head of sector list // phares 3/13/98 + + // set subsector and/or block links + + P_SetThingPosition (mobj); + + mobj->dropoffz = /* killough 11/98: for tracking dropoffs */ + mobj->floorz = mobj->subsector->sector->floorheight; + mobj->ceilingz = mobj->subsector->sector->ceilingheight; + + mobj->z = z == ONFLOORZ ? mobj->floorz : z == ONCEILINGZ ? + mobj->ceilingz - mobj->height : z; + + mobj->PrevX = mobj->x; + mobj->PrevY = mobj->y; + mobj->PrevZ = mobj->z; + + mobj->thinker.function = P_MobjThinker; + + //e6y + mobj->friction = ORIG_FRICTION; // phares 3/17/98 + + mobj->target = mobj->tracer = mobj->lastenemy = NULL; + P_AddThinker (&mobj->thinker); + if (!((mobj->flags ^ MF_COUNTKILL) & (MF_FRIEND | MF_COUNTKILL))) + totallive++; + return mobj; + } + + +static mapthing_t itemrespawnque[ITEMQUESIZE]; +static int itemrespawntime[ITEMQUESIZE]; +int iquehead; +int iquetail; + + +// +// P_RemoveMobj +// + +void P_RemoveMobj (mobj_t* mobj) +{ + if ((mobj->flags & MF_SPECIAL) + && !(mobj->flags & MF_DROPPED) + && (mobj->type != MT_INV) + && (mobj->type != MT_INS)) + { + itemrespawnque[iquehead] = mobj->spawnpoint; + itemrespawntime[iquehead] = leveltime; + iquehead = (iquehead+1)&(ITEMQUESIZE-1); + + // lose one off the end? + + if (iquehead == iquetail) + iquetail = (iquetail+1)&(ITEMQUESIZE-1); + } + + // unlink from sector and block lists + + P_UnsetThingPosition (mobj); + + // Delete all nodes on the current sector_list phares 3/16/98 + + if (sector_list) + { + P_DelSeclist(sector_list); + sector_list = NULL; + } + + // stop any playing sound + + S_StopSound (mobj); + + // killough 11/98: + // + // Remove any references to other mobjs. + // + // Older demos might depend on the fields being left alone, however, + // if multiple thinkers reference each other indirectly before the + // end of the current tic. + // CPhipps - only leave dead references in old demos; I hope lxdoom_1 level + // demos are rare and don't rely on this. I hope. + + if ((compatibility_level >= lxdoom_1_compatibility) || + (!demorecording && !demoplayback)) { + P_SetTarget(&mobj->target, NULL); + P_SetTarget(&mobj->tracer, NULL); + P_SetTarget(&mobj->lastenemy, NULL); + } + // free block + + P_RemoveThinker (&mobj->thinker); +} + + +/* + * P_FindDoomedNum + * + * Finds a mobj type with a matching doomednum + * + * killough 8/24/98: rewrote to use hashing + */ + +static PUREFUNC int P_FindDoomedNum(unsigned type) +{ + static struct { int first, next; } *hash; + register int i; + + if (!hash) + { + hash = Z_Malloc(sizeof *hash * NUMMOBJTYPES, PU_CACHE, (void **) &hash); + for (i=0; ix << FRACBITS; + y = mthing->y << FRACBITS; + + // spawn a teleport fog at the new spot + + ss = R_PointInSubsector (x,y); + mo = P_SpawnMobj (x, y, ss->sector->floorheight , MT_IFOG); + S_StartSound (mo, sfx_itmbk); + + // find which type to spawn + + /* killough 8/23/98: use table for faster lookup */ + i = P_FindDoomedNum(mthing->type); + + // spawn it + + if (mobjinfo[i].flags & MF_SPAWNCEILING) + z = ONCEILINGZ; + else + z = ONFLOORZ; + + mo = P_SpawnMobj (x,y,z, i); + mo->spawnpoint = *mthing; + mo->angle = ANG45 * (mthing->angle/45); + + // pull it from the queue + + iquetail = (iquetail+1)&(ITEMQUESIZE-1); + } + +// +// P_SpawnPlayer +// Called when a player is spawned on the level. +// Most of the player structure stays unchanged +// between levels. +// + +extern byte playernumtotrans[MAXPLAYERS]; + +void P_SpawnPlayer (int n, const mapthing_t* mthing) + { + player_t* p; + fixed_t x; + fixed_t y; + fixed_t z; + mobj_t* mobj; + int i; + + // not playing? + + if (!playeringame[n]) + return; + + p = &players[n]; + + if (p->playerstate == PST_REBORN) + G_PlayerReborn (mthing->type-1); + + /* cph 2001/08/14 - use the options field of memorised player starts to + * indicate whether the start really exists in the level. + */ + if (!mthing->options) + I_Error("P_SpawnPlayer: attempt to spawn player at unavailable start point"); + + x = mthing->x << FRACBITS; + y = mthing->y << FRACBITS; + z = ONFLOORZ; + mobj = P_SpawnMobj (x,y,z, MT_PLAYER); + + // set color translations for player sprites + + mobj->flags |= playernumtotrans[n]<angle = ANG45 * (mthing->angle/45); + mobj->player = p; + mobj->health = p->health; + + p->mo = mobj; + p->playerstate = PST_LIVE; + p->refire = 0; + p->message = NULL; + p->damagecount = 0; + p->bonuscount = 0; + p->extralight = 0; + p->fixedcolormap = 0; + p->viewheight = VIEWHEIGHT; + + p->momx = p->momy = 0; // killough 10/98: initialize bobbing to 0. + + // setup gun psprite + + P_SetupPsprites (p); + + // give all cards in death match mode + + if (deathmatch) + for (i = 0 ; i < NUMCARDS ; i++) + p->cards[i] = true; + + if (mthing->type-1 == consoleplayer) + { + ST_Start(); // wake up the status bar + HU_Start(); // wake up the heads up text + } + R_SmoothPlaying_Reset(p); // e6y + } + +/* + * P_IsDoomnumAllowed() + * Based on code taken from P_LoadThings() in src/p_setup.c Return TRUE + * if the thing in question is expected to be available in the gamemode used. + */ + +boolean P_IsDoomnumAllowed(int doomnum) +{ + // Do not spawn cool, new monsters if !commercial + if (gamemode != commercial) + switch(doomnum) + { + case 64: // Archvile + case 65: // Former Human Commando + case 66: // Revenant + case 67: // Mancubus + case 68: // Arachnotron + case 69: // Hell Knight + case 71: // Pain Elemental + case 84: // Wolf SS + case 88: // Boss Brain + case 89: // Boss Shooter + return false; + } + + return true; +} + +// +// P_SpawnMapThing +// The fields of the mapthing should +// already be in host byte order. +// + +void P_SpawnMapThing (const mapthing_t* mthing) + { + int i; + //int bit; + mobj_t* mobj; + fixed_t x; + fixed_t y; + fixed_t z; + int options = mthing->options; /* cph 2001/07/07 - make writable copy */ + + // killough 2/26/98: Ignore type-0 things as NOPs + // phares 5/14/98: Ignore Player 5-8 starts (for now) + + switch(mthing->type) + { + case 0: + case DEN_PLAYER5: + case DEN_PLAYER6: + case DEN_PLAYER7: + case DEN_PLAYER8: + return; + } + + // killough 11/98: clear flags unused by Doom + // + // We clear the flags unused in Doom if we see flag mask 256 set, since + // it is reserved to be 0 under the new scheme. A 1 in this reserved bit + // indicates it's a Doom wad made by a Doom editor which puts 1's in + // bits that weren't used in Doom (such as HellMaker wads). So we should + // then simply ignore all upper bits. + + if (demo_compatibility || + (compatibility_level >= lxdoom_1_compatibility && + options & MTF_RESERVED)) { + if (!demo_compatibility) // cph - Add warning about bad thing flags + lprintf(LO_WARN, "P_SpawnMapThing: correcting bad flags (%u) (thing type %d)\n", + options, mthing->type); + options &= MTF_EASY|MTF_NORMAL|MTF_HARD|MTF_AMBUSH|MTF_NOTSINGLE; + } + + // count deathmatch start positions + + // doom2.exe has at most 10 deathmatch starts + if (mthing->type == 11) + { + if (!(!compatibility || deathmatch_p-deathmatchstarts < 10)) { + return; + } else { + // 1/11/98 killough -- new code removes limit on deathmatch starts: + + size_t offset = deathmatch_p - deathmatchstarts; + + if (offset >= num_deathmatchstarts) + { + num_deathmatchstarts = num_deathmatchstarts ? + num_deathmatchstarts*2 : 16; + deathmatchstarts = realloc(deathmatchstarts, + num_deathmatchstarts * + sizeof(*deathmatchstarts)); + deathmatch_p = deathmatchstarts + offset; + } + memcpy(deathmatch_p++, mthing, sizeof(*mthing)); + (deathmatch_p-1)->options = 1; + return; + } + } + + // check for players specially + + if (mthing->type <= 4 && mthing->type > 0) // killough 2/26/98 -- fix crashes + { +#ifdef DOGS + // killough 7/19/98: Marine's best friend :) + if (!netgame && mthing->type > 1 && mthing->type <= dogs+1 && + !players[mthing->type-1].secretcount) + { // use secretcount to avoid multiple dogs in case of multiple starts + players[mthing->type-1].secretcount = 1; + + // killough 10/98: force it to be a friend + options |= MTF_FRIEND; + if(HelperThing != -1) // haleyjd 9/22/99: deh substitution + { + int type = HelperThing - 1; + if(type >= 0 && type < NUMMOBJTYPES) + { + i = type; + } + else + { + doom_printf("Invalid value %i for helper, ignored.", HelperThing); + i = MT_DOGS; + } + } + else { + i = MT_DOGS; + } + goto spawnit; + } +#endif + + // save spots for respawning in coop games + playerstarts[mthing->type-1] = *mthing; + /* cph 2006/07/24 - use the otherwise-unused options field to flag that + * this start is present (so we know which elements of the array are filled + * in, in effect). Also note that the call below to P_SpawnPlayer must use + * the playerstarts version with this field set */ + playerstarts[mthing->type-1].options = 1; + + if (!deathmatch) + P_SpawnPlayer (mthing->type-1, &playerstarts[mthing->type-1]); + return; + } + + // check for apropriate skill level + + /* jff "not single" thing flag */ + if (!netgame && options & MTF_NOTSINGLE) + return; + + //jff 3/30/98 implement "not deathmatch" thing flag + + if (netgame && deathmatch && options & MTF_NOTDM) + return; + + //jff 3/30/98 implement "not cooperative" thing flag + + if (netgame && !deathmatch && options & MTF_NOTCOOP) + return; + + // killough 11/98: simplify + if (gameskill == sk_baby || gameskill == sk_easy ? + !(options & MTF_EASY) : + gameskill == sk_hard || gameskill == sk_nightmare ? + !(options & MTF_HARD) : !(options & MTF_NORMAL)) + return; + + // find which type to spawn + + // killough 8/23/98: use table for faster lookup + i = P_FindDoomedNum(mthing->type); + + // phares 5/16/98: + // Do not abort because of an unknown thing. Ignore it, but post a + // warning message for the player. + + if (i == NUMMOBJTYPES) + { + doom_printf("Unknown Thing type %i at (%i, %i)",mthing->type,mthing->x,mthing->y); + return; + } + + // don't spawn keycards and players in deathmatch + + if (deathmatch && mobjinfo[i].flags & MF_NOTDMATCH) + return; + + // don't spawn any monsters if -nomonsters + + if (nomonsters && (i == MT_SKULL || (mobjinfo[i].flags & MF_COUNTKILL))) + return; + + // spawn it +#ifdef DOGS +spawnit: +#endif + + x = mthing->x << FRACBITS; + y = mthing->y << FRACBITS; + + if (mobjinfo[i].flags & MF_SPAWNCEILING) + z = ONCEILINGZ; + else + z = ONFLOORZ; + + mobj = P_SpawnMobj (x,y,z, i); + mobj->spawnpoint = *mthing; + + if (mobj->tics > 0) + mobj->tics = 1 + (P_Random (pr_spawnthing) % mobj->tics); + + if (!(mobj->flags & MF_FRIEND) && + options & MTF_FRIEND && + mbf_features) + { + mobj->flags |= MF_FRIEND; // killough 10/98: + P_UpdateThinker(&mobj->thinker); // transfer friendliness flag + } + + /* killough 7/20/98: exclude friends */ + if (!((mobj->flags ^ MF_COUNTKILL) & (MF_FRIEND | MF_COUNTKILL))) + totalkills++; + + if (mobj->flags & MF_COUNTITEM) + totalitems++; + + mobj->angle = ANG45 * (mthing->angle/45); + if (options & MTF_AMBUSH) + mobj->flags |= MF_AMBUSH; + } + + +// +// GAME SPAWN FUNCTIONS +// + +// +// P_SpawnPuff +// + +extern fixed_t attackrange; + +void P_SpawnPuff(fixed_t x,fixed_t y,fixed_t z) + { + mobj_t* th; + // killough 5/5/98: remove dependence on order of evaluation: + int t = P_Random(pr_spawnpuff); + z += (t - P_Random(pr_spawnpuff))<<10; + + th = P_SpawnMobj (x,y,z, MT_PUFF); + th->momz = FRACUNIT; + th->tics -= P_Random(pr_spawnpuff)&3; + + if (th->tics < 1) + th->tics = 1; + + // don't make punches spark on the wall + + if (attackrange == MELEERANGE) + P_SetMobjState (th, S_PUFF3); + } + + +// +// P_SpawnBlood +// +void P_SpawnBlood(fixed_t x,fixed_t y,fixed_t z,int damage) + { + mobj_t* th; + // killough 5/5/98: remove dependence on order of evaluation: + int t = P_Random(pr_spawnblood); + z += (t - P_Random(pr_spawnblood))<<10; + th = P_SpawnMobj(x,y,z, MT_BLOOD); + th->momz = FRACUNIT*2; + th->tics -= P_Random(pr_spawnblood)&3; + + if (th->tics < 1) + th->tics = 1; + + if (damage <= 12 && damage >= 9) + P_SetMobjState (th,S_BLOOD2); + else if (damage < 9) + P_SetMobjState (th,S_BLOOD3); + } + + +// +// P_CheckMissileSpawn +// Moves the missile forward a bit +// and possibly explodes it right there. +// + +void P_CheckMissileSpawn (mobj_t* th) + { + th->tics -= P_Random(pr_missile)&3; + if (th->tics < 1) + th->tics = 1; + + // move a little forward so an angle can + // be computed if it immediately explodes + + th->x += (th->momx>>1); + th->y += (th->momy>>1); + th->z += (th->momz>>1); + + // killough 8/12/98: for non-missile objects (e.g. grenades) + if (!(th->flags & MF_MISSILE) && mbf_features) + return; + + // killough 3/15/98: no dropoff (really = don't care for missiles) + + if (!P_TryMove (th, th->x, th->y, false)) + P_ExplodeMissile (th); + } + + +// +// P_SpawnMissile +// + +mobj_t* P_SpawnMissile(mobj_t* source,mobj_t* dest,mobjtype_t type) + { + mobj_t* th; + angle_t an; + int dist; + + th = P_SpawnMobj (source->x,source->y,source->z + 4*8*FRACUNIT,type); + + if (th->info->seesound) + S_StartSound (th, th->info->seesound); + + P_SetTarget(&th->target, source); // where it came from + an = R_PointToAngle2 (source->x, source->y, dest->x, dest->y); + + // fuzzy player + + if (dest->flags & MF_SHADOW) + { // killough 5/5/98: remove dependence on order of evaluation: + int t = P_Random(pr_shadow); + an += (t - P_Random(pr_shadow))<<20; + } + + th->angle = an; + an >>= ANGLETOFINESHIFT; + th->momx = FixedMul (th->info->speed, finecosine[an]); + th->momy = FixedMul (th->info->speed, finesine[an]); + + dist = P_AproxDistance (dest->x - source->x, dest->y - source->y); + dist = dist / th->info->speed; + + if (dist < 1) + dist = 1; + + th->momz = (dest->z - source->z) / dist; + P_CheckMissileSpawn (th); + + return th; + } + + +// +// P_SpawnPlayerMissile +// Tries to aim at a nearby monster +// + +void P_SpawnPlayerMissile(mobj_t* source,mobjtype_t type) +{ + mobj_t *th; + fixed_t x, y, z, slope = 0; + + // see which target is to be aimed at + + angle_t an = source->angle; + + // killough 7/19/98: autoaiming was not in original beta + { + // killough 8/2/98: prefer autoaiming at enemies + uint_64_t mask = mbf_features ? MF_FRIEND : 0; + + do + { + slope = P_AimLineAttack(source, an, 16*64*FRACUNIT, mask); + if (!linetarget) + slope = P_AimLineAttack(source, an += 1<<26, 16*64*FRACUNIT, mask); + if (!linetarget) + slope = P_AimLineAttack(source, an -= 2<<26, 16*64*FRACUNIT, mask); + if (!linetarget) + an = source->angle, slope = 0; + } + while (mask && (mask=0, !linetarget)); // killough 8/2/98 + } + + x = source->x; + y = source->y; + z = source->z + 4*8*FRACUNIT; + + th = P_SpawnMobj (x,y,z, type); + + if (th->info->seesound) + S_StartSound (th, th->info->seesound); + + P_SetTarget(&th->target, source); + th->angle = an; + th->momx = FixedMul(th->info->speed,finecosine[an>>ANGLETOFINESHIFT]); + th->momy = FixedMul(th->info->speed,finesine[an>>ANGLETOFINESHIFT]); + th->momz = FixedMul(th->info->speed,slope); + + P_CheckMissileSpawn(th); + } diff --git a/common/prboom/p_mobj.h b/common/prboom/p_mobj.h new file mode 100755 index 0000000..ccd66f3 --- /dev/null +++ b/common/prboom/p_mobj.h @@ -0,0 +1,403 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Map Objects, MObj, definition and handling. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __P_MOBJ__ +#define __P_MOBJ__ + +// Basics. +#include "tables.h" +#include "m_fixed.h" + +// We need the thinker_t stuff. +#include "d_think.h" + +// We need the WAD data structure for Map things, +// from the THINGS lump. +#include "doomdata.h" + +// States are tied to finite states are +// tied to animation frames. +// Needs precompiled tables/data structures. +#include "info.h" + +// +// NOTES: mobj_t +// +// mobj_ts are used to tell the refresh where to draw an image, +// tell the world simulation when objects are contacted, +// and tell the sound driver how to position a sound. +// +// The refresh uses the next and prev links to follow +// lists of things in sectors as they are being drawn. +// The sprite, frame, and angle elements determine which patch_t +// is used to draw the sprite if it is visible. +// The sprite and frame values are allmost allways set +// from state_t structures. +// The statescr.exe utility generates the states.h and states.c +// files that contain the sprite/frame numbers from the +// statescr.txt source file. +// The xyz origin point represents a point at the bottom middle +// of the sprite (between the feet of a biped). +// This is the default origin position for patch_ts grabbed +// with lumpy.exe. +// A walking creature will have its z equal to the floor +// it is standing on. +// +// The sound code uses the x,y, and subsector fields +// to do stereo positioning of any sound effited by the mobj_t. +// +// The play simulation uses the blocklinks, x,y,z, radius, height +// to determine when mobj_ts are touching each other, +// touching lines in the map, or hit by trace lines (gunshots, +// lines of sight, etc). +// The mobj_t->flags element has various bit flags +// used by the simulation. +// +// Every mobj_t is linked into a single sector +// based on its origin coordinates. +// The subsector_t is found with R_PointInSubsector(x,y), +// and the sector_t can be found with subsector->sector. +// The sector links are only used by the rendering code, +// the play simulation does not care about them at all. +// +// Any mobj_t that needs to be acted upon by something else +// in the play world (block movement, be shot, etc) will also +// need to be linked into the blockmap. +// If the thing has the MF_NOBLOCK flag set, it will not use +// the block links. It can still interact with other things, +// but only as the instigator (missiles will run into other +// things, but nothing can run into a missile). +// Each block in the grid is 128*128 units, and knows about +// every line_t that it contains a piece of, and every +// interactable mobj_t that has its origin contained. +// +// A valid mobj_t is a mobj_t that has the proper subsector_t +// filled in for its xy coordinates and is linked into the +// sector from which the subsector was made, or has the +// MF_NOSECTOR flag set (the subsector_t needs to be valid +// even if MF_NOSECTOR is set), and is linked into a blockmap +// block or has the MF_NOBLOCKMAP flag set. +// Links should only be modified by the P_[Un]SetThingPosition() +// functions. +// Do not change the MF_NO? flags while a thing is valid. +// +// Any questions? +// + +// +// Misc. mobj flags +// + +// Call P_SpecialThing when touched. +#define MF_SPECIAL (uint_64_t)(0x0000000000000001) +// Blocks. +#define MF_SOLID (uint_64_t)(0x0000000000000002) +// Can be hit. +#define MF_SHOOTABLE (uint_64_t)(0x0000000000000004) +// Don't use the sector links (invisible but touchable). +#define MF_NOSECTOR (uint_64_t)(0x0000000000000008) +// Don't use the blocklinks (inert but displayable) +#define MF_NOBLOCKMAP (uint_64_t)(0x0000000000000010) + +// Not to be activated by sound, deaf monster. +#define MF_AMBUSH (uint_64_t)(0x0000000000000020) +// Will try to attack right back. +#define MF_JUSTHIT (uint_64_t)(0x0000000000000040) +// Will take at least one step before attacking. +#define MF_JUSTATTACKED (uint_64_t)(0x0000000000000080) +// On level spawning (initial position), +// hang from ceiling instead of stand on floor. +#define MF_SPAWNCEILING (uint_64_t)(0x0000000000000100) +// Don't apply gravity (every tic), +// that is, object will float, keeping current height +// or changing it actively. +#define MF_NOGRAVITY (uint_64_t)(0x0000000000000200) + +// Movement flags. +// This allows jumps from high places. +#define MF_DROPOFF (uint_64_t)(0x0000000000000400) +// For players, will pick up items. +#define MF_PICKUP (uint_64_t)(0x0000000000000800) +// Player cheat. ??? +#define MF_NOCLIP (uint_64_t)(0x0000000000001000) +// Player: keep info about sliding along walls. +#define MF_SLIDE (uint_64_t)(0x0000000000002000) +// Allow moves to any height, no gravity. +// For active floaters, e.g. cacodemons, pain elementals. +#define MF_FLOAT (uint_64_t)(0x0000000000004000) +// Don't cross lines +// ??? or look at heights on teleport. +#define MF_TELEPORT (uint_64_t)(0x0000000000008000) +// Don't hit same species, explode on block. +// Player missiles as well as fireballs of various kinds. +#define MF_MISSILE (uint_64_t)(0x0000000000010000) +// Dropped by a demon, not level spawned. +// E.g. ammo clips dropped by dying former humans. +#define MF_DROPPED (uint_64_t)(0x0000000000020000) +// Use fuzzy draw (shadow demons or spectres), +// temporary player invisibility powerup. +#define MF_SHADOW (uint_64_t)(0x0000000000040000) +// Flag: don't bleed when shot (use puff), +// barrels and shootable furniture shall not bleed. +#define MF_NOBLOOD (uint_64_t)(0x0000000000080000) +// Don't stop moving halfway off a step, +// that is, have dead bodies slide down all the way. +#define MF_CORPSE (uint_64_t)(0x0000000000100000) +// Floating to a height for a move, ??? +// don't auto float to target's height. +#define MF_INFLOAT (uint_64_t)(0x0000000000200000) + +// On kill, count this enemy object +// towards intermission kill total. +// Happy gathering. +#define MF_COUNTKILL (uint_64_t)(0x0000000000400000) + +// On picking up, count this item object +// towards intermission item total. +#define MF_COUNTITEM (uint_64_t)(0x0000000000800000) + +// Special handling: skull in flight. +// Neither a cacodemon nor a missile. +#define MF_SKULLFLY (uint_64_t)(0x0000000001000000) + +// Don't spawn this object +// in death match mode (e.g. key cards). +#define MF_NOTDMATCH (uint_64_t)(0x0000000002000000) + +// Player sprites in multiplayer modes are modified +// using an internal color lookup table for re-indexing. +// If 0x4 0x8 or 0xc, +// use a translation table for player colormaps +#define MF_TRANSLATION (uint_64_t)(0x000000000c000000) +#define MF_TRANSLATION1 (uint_64_t)(0x0000000004000000) +#define MF_TRANSLATION2 (uint_64_t)(0x0000000008000000) +// Hmm ???. +#define MF_TRANSSHIFT 26 + +#define MF_UNUSED2 (uint_64_t)(0x0000000010000000) +#define MF_UNUSED3 (uint_64_t)(0x0000000020000000) + + // Translucent sprite? // phares +#define MF_TRANSLUCENT (uint_64_t)(0x0000000040000000) + +// this is free LONGLONG(0x0000000100000000) + +// these are greater than an int. That's why the flags below are now uint_64_t + +#define MF_TOUCHY LONGLONG(0x0000000100000000) +#define MF_BOUNCES LONGLONG(0x0000000200000000) +#define MF_FRIEND LONGLONG(0x0000000400000000) + +// killough 9/15/98: Same, but internal flags, not intended for .deh +// (some degree of opaqueness is good, to avoid compatibility woes) + +enum { + MIF_FALLING = 1, // Object is falling + MIF_ARMED = 2, // Object is armed (for MF_TOUCHY objects) +}; + +// Map Object definition. +// +// +// killough 2/20/98: +// +// WARNING: Special steps must be taken in p_saveg.c if C pointers are added to +// this mobj_s struct, or else savegames will crash when loaded. See p_saveg.c. +// Do not add "struct mobj_s *fooptr" without adding code to p_saveg.c to +// convert the pointers to ordinals and back for savegames. This was the whole +// reason behind monsters going to sleep when loading savegames (the "target" +// pointer was simply nullified after loading, to prevent Doom from crashing), +// and the whole reason behind loadgames crashing on savegames of AV attacks. +// + +// killough 9/8/98: changed some fields to shorts, +// for better memory usage (if only for cache). +/* cph 2006/08/28 - move Prev[XYZ] fields to the end of the struct. Add any + * other new fields to the end, and make sure you don't break savegames! */ + +typedef struct mobj_s +{ + // List: thinker links. + thinker_t thinker; + + // Info for drawing: position. + fixed_t x; + fixed_t y; + fixed_t z; + + // More list: links in sector (if needed) + struct mobj_s* snext; + struct mobj_s** sprev; // killough 8/10/98: change to ptr-to-ptr + + //More drawing info: to determine current sprite. + angle_t angle; // orientation + spritenum_t sprite; // used to find patch_t and flip value + int frame; // might be ORed with FF_FULLBRIGHT + + // Interaction info, by BLOCKMAP. + // Links in blocks (if needed). + struct mobj_s* bnext; + struct mobj_s** bprev; // killough 8/11/98: change to ptr-to-ptr + + struct subsector_s* subsector; + + // The closest interval over all contacted Sectors. + fixed_t floorz; + fixed_t ceilingz; + + // killough 11/98: the lowest floor over all contacted Sectors. + fixed_t dropoffz; + + // For movement checking. + fixed_t radius; + fixed_t height; + + // Momentums, used to update position. + fixed_t momx; + fixed_t momy; + fixed_t momz; + + // If == validcount, already checked. + int validcount; + + mobjtype_t type; + mobjinfo_t* info; // &mobjinfo[mobj->type] + + int tics; // state tic counter + state_t* state; + uint_64_t flags; + int intflags; // killough 9/15/98: internal flags + int health; + + // Movement direction, movement generation (zig-zagging). + short movedir; // 0-7 + short movecount; // when 0, select a new dir + short strafecount; // killough 9/8/98: monster strafing + + // Thing being chased/attacked (or NULL), + // also the originator for missiles. + struct mobj_s* target; + + // Reaction time: if non 0, don't attack yet. + // Used by player to freeze a bit after teleporting. + short reactiontime; + + // If >0, the current target will be chased no + // matter what (even if shot by another object) + short threshold; + + // killough 9/9/98: How long a monster pursues a target. + short pursuecount; + + short gear; // killough 11/98: used in torque simulation + + // Additional info record for player avatars only. + // Only valid if type == MT_PLAYER + struct player_s* player; + + // Player number last looked for. + short lastlook; + + // For nightmare respawn. + mapthing_t spawnpoint; + + // Thing being chased/attacked for tracers. + struct mobj_s* tracer; + + // new field: last known enemy -- killough 2/15/98 + struct mobj_s* lastenemy; + + // killough 8/2/98: friction properties part of sectors, + // not objects -- removed friction properties from here + // e6y: restored friction properties here + // Friction values for the sector the object is in + int friction; // phares 3/17/98 + int movefactor; + + // a linked list of sectors where this object appears + struct msecnode_s* touching_sectorlist; // phares 3/14/98 + + fixed_t PrevX; + fixed_t PrevY; + fixed_t PrevZ; + + fixed_t pad; // cph - needed so I can get the size unambiguously on amd64 + + // SEE WARNING ABOVE ABOUT POINTER FIELDS!!! +} mobj_t; + +// External declarations (fomerly in p_local.h) -- killough 5/2/98 + +#define VIEWHEIGHT (41*FRACUNIT) + +#define GRAVITY FRACUNIT +#define MAXMOVE (30*FRACUNIT) + +#define ONFLOORZ INT_MIN +#define ONCEILINGZ INT_MAX + +// Time interval for item respawning. +#define ITEMQUESIZE 128 + +#define FLOATSPEED (FRACUNIT*4) +#define STOPSPEED (FRACUNIT/16) + +// killough 11/98: +// For torque simulation: + +#define OVERDRIVE 6 +#define MAXGEAR (OVERDRIVE+16) + +// killough 11/98: +// Whether an object is "sentient" or not. Used for environmental influences. +#define sentient(mobj) ((mobj)->health > 0 && (mobj)->info->seestate) + +extern int iquehead; +extern int iquetail; + +void P_RespawnSpecials(void); +mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type); +void P_RemoveMobj(mobj_t *th); +boolean P_SetMobjState(mobj_t *mobj, statenum_t state); +void P_MobjThinker(mobj_t *mobj); +void P_SpawnPuff(fixed_t x, fixed_t y, fixed_t z); +void P_SpawnBlood(fixed_t x, fixed_t y, fixed_t z, int damage); +mobj_t *P_SpawnMissile(mobj_t *source, mobj_t *dest, mobjtype_t type); +void P_SpawnPlayerMissile(mobj_t *source, mobjtype_t type); +boolean P_IsDoomnumAllowed(int doomnum); +void P_SpawnMapThing (const mapthing_t* mthing); +void P_SpawnPlayer(int n, const mapthing_t *mthing); +void P_CheckMissileSpawn(mobj_t*); // killough 8/2/98 +void P_ExplodeMissile(mobj_t*); // killough +#endif + diff --git a/common/prboom/p_plats.c b/common/prboom/p_plats.c new file mode 100755 index 0000000..9bea240 --- /dev/null +++ b/common/prboom/p_plats.c @@ -0,0 +1,437 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Plats (i.e. elevator platforms) code, raising/lowering. + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" +#include "m_random.h" +#include "r_main.h" +#include "p_spec.h" +#include "p_tick.h" +#include "s_sound.h" +#include "sounds.h" + +platlist_t *activeplats; // killough 2/14/98: made global again + +// +// T_PlatRaise() +// +// Action routine to move a plat up and down +// +// Passed a plat structure containing all pertinent information about the move +// No return +// +// jff 02/08/98 all cases with labels beginning with gen added to support +// generalized line type behaviors. + +void T_PlatRaise(plat_t* plat) +{ + result_e res; + + // handle plat moving, up, down, waiting, or in stasis, + switch(plat->status) + { + case up: // plat moving up + res = T_MovePlane(plat->sector,plat->speed,plat->high,plat->crush,0,1); + + // if a pure raise type, make the plat moving sound + if (plat->type == raiseAndChange + || plat->type == raiseToNearestAndChange) + { + if (!(leveltime&7)) + S_StartSound((mobj_t *)&plat->sector->soundorg, sfx_stnmov); + } + + // if encountered an obstacle, and not a crush type, reverse direction + if (res == crushed && (!plat->crush)) + { + plat->count = plat->wait; + plat->status = down; + S_StartSound((mobj_t *)&plat->sector->soundorg, sfx_pstart); + } + else // else handle reaching end of up stroke + { + if (res == pastdest) // end of stroke + { + // if not an instant toggle type, wait, make plat stop sound + if (plat->type!=toggleUpDn) + { + plat->count = plat->wait; + plat->status = waiting; + S_StartSound((mobj_t *)&plat->sector->soundorg, sfx_pstop); + } + else // else go into stasis awaiting next toggle activation + { + plat->oldstatus = plat->status;//jff 3/14/98 after action wait + plat->status = in_stasis; //for reactivation of toggle + } + + // lift types and pure raise types are done at end of up stroke + // only the perpetual type waits then goes back up + switch(plat->type) + { + case blazeDWUS: + case downWaitUpStay: + case raiseAndChange: + case raiseToNearestAndChange: + case genLift: + P_RemoveActivePlat(plat); // killough + default: + break; + } + } + } + break; + + case down: // plat moving down + res = T_MovePlane(plat->sector,plat->speed,plat->low,false,0,-1); + + // handle reaching end of down stroke + if (res == pastdest) + { + // if not an instant toggle, start waiting, make plat stop sound + if (plat->type!=toggleUpDn) //jff 3/14/98 toggle up down + { // is silent, instant, no waiting + plat->count = plat->wait; + plat->status = waiting; + S_StartSound((mobj_t *)&plat->sector->soundorg,sfx_pstop); + } + else // instant toggles go into stasis awaiting next activation + { + plat->oldstatus = plat->status;//jff 3/14/98 after action wait + plat->status = in_stasis; //for reactivation of toggle + } + + //jff 1/26/98 remove the plat if it bounced so it can be tried again + //only affects plats that raise and bounce + //killough 1/31/98: relax compatibility to demo_compatibility + + // remove the plat if its a pure raise type + if (!comp[comp_floors]) + { + switch(plat->type) + { + case raiseAndChange: + case raiseToNearestAndChange: + P_RemoveActivePlat(plat); + default: + break; + } + } + } + break; + + case waiting: // plat is waiting + if (!--plat->count) // downcount and check for delay elapsed + { + if (plat->sector->floorheight == plat->low) + plat->status = up; // if at bottom, start up + else + plat->status = down; // if at top, start down + + // make plat start sound + S_StartSound((mobj_t *)&plat->sector->soundorg,sfx_pstart); + } + break; //jff 1/27/98 don't pickup code added later to in_stasis + + case in_stasis: // do nothing if in stasis + break; + } +} + + +// +// EV_DoPlat +// +// Handle Plat linedef types +// +// Passed the linedef that activated the plat, the type of plat action, +// and for some plat types, an amount to raise +// Returns true if a thinker is started, or restarted from stasis +// +int EV_DoPlat +( line_t* line, + plattype_e type, + int amount ) +{ + plat_t* plat; + int secnum; + int rtn; + sector_t* sec; + + secnum = -1; + rtn = 0; + + + // Activate all plats that are in_stasis + switch(type) + { + case perpetualRaise: + P_ActivateInStasis(line->tag); + break; + + case toggleUpDn: + P_ActivateInStasis(line->tag); + rtn=1; + break; + + default: + break; + } + + // act on all sectors tagged the same as the activating linedef + while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) + { + sec = §ors[secnum]; + + // don't start a second floor function if already moving + if (P_SectorActive(floor_special,sec)) //jff 2/23/98 multiple thinkers + continue; + + // Create a thinker + rtn = 1; + plat = Z_Malloc( sizeof(*plat), PU_LEVSPEC, 0); + memset(plat, 0, sizeof(*plat)); + P_AddThinker(&plat->thinker); + + plat->type = type; + plat->sector = sec; + plat->sector->floordata = plat; //jff 2/23/98 multiple thinkers + plat->thinker.function = T_PlatRaise; + plat->crush = false; + plat->tag = line->tag; + + //jff 1/26/98 Avoid raise plat bouncing a head off a ceiling and then + //going down forever -- default low to plat height when triggered + plat->low = sec->floorheight; + + // set up plat according to type + switch(type) + { + case raiseToNearestAndChange: + plat->speed = PLATSPEED/2; + sec->floorpic = sides[line->sidenum[0]].sector->floorpic; + plat->high = P_FindNextHighestFloor(sec,sec->floorheight); + plat->wait = 0; + plat->status = up; + sec->special = 0; + //jff 3/14/98 clear old field as well + sec->oldspecial = 0; + + S_StartSound((mobj_t *)&sec->soundorg,sfx_stnmov); + break; + + case raiseAndChange: + plat->speed = PLATSPEED/2; + sec->floorpic = sides[line->sidenum[0]].sector->floorpic; + plat->high = sec->floorheight + amount*FRACUNIT; + plat->wait = 0; + plat->status = up; + + S_StartSound((mobj_t *)&sec->soundorg,sfx_stnmov); + break; + + case downWaitUpStay: + plat->speed = PLATSPEED * 4; + plat->low = P_FindLowestFloorSurrounding(sec); + + if (plat->low > sec->floorheight) + plat->low = sec->floorheight; + + plat->high = sec->floorheight; + plat->wait = 35*PLATWAIT; + plat->status = down; + S_StartSound((mobj_t *)&sec->soundorg,sfx_pstart); + break; + + case blazeDWUS: + plat->speed = PLATSPEED * 8; + plat->low = P_FindLowestFloorSurrounding(sec); + + if (plat->low > sec->floorheight) + plat->low = sec->floorheight; + + plat->high = sec->floorheight; + plat->wait = 35*PLATWAIT; + plat->status = down; + S_StartSound((mobj_t *)&sec->soundorg,sfx_pstart); + break; + + case perpetualRaise: + plat->speed = PLATSPEED; + plat->low = P_FindLowestFloorSurrounding(sec); + + if (plat->low > sec->floorheight) + plat->low = sec->floorheight; + + plat->high = P_FindHighestFloorSurrounding(sec); + + if (plat->high < sec->floorheight) + plat->high = sec->floorheight; + + plat->wait = 35*PLATWAIT; + plat->status = P_Random(pr_plats)&1; + + S_StartSound((mobj_t *)&sec->soundorg,sfx_pstart); + break; + + case toggleUpDn: //jff 3/14/98 add new type to support instant toggle + plat->speed = PLATSPEED; //not used + plat->wait = 35*PLATWAIT; //not used + plat->crush = true; //jff 3/14/98 crush anything in the way + + // set up toggling between ceiling, floor inclusive + plat->low = sec->ceilingheight; + plat->high = sec->floorheight; + plat->status = down; + break; + + default: + break; + } + P_AddActivePlat(plat); // add plat to list of active plats + } + return rtn; +} + +// The following were all rewritten by Lee Killough +// to use the new structure which places no limits +// on active plats. It also avoids spending as much +// time searching for active plats. Previously a +// fixed-size array was used, with NULL indicating +// empty entries, while now a doubly-linked list +// is used. + +// +// P_ActivateInStasis() +// +// Activate a plat that has been put in stasis +// (stopped perpetual floor, instant floor/ceil toggle) +// +// Passed the tag of the plat that should be reactivated +// Returns nothing +// +void P_ActivateInStasis(int tag) +{ + platlist_t *pl; + for (pl=activeplats; pl; pl=pl->next) // search the active plats + { + plat_t *plat = pl->plat; // for one in stasis with right tag + if (plat->tag == tag && plat->status == in_stasis) + { + if (plat->type==toggleUpDn) //jff 3/14/98 reactivate toggle type + plat->status = plat->oldstatus==up? down : up; + else + plat->status = plat->oldstatus; + plat->thinker.function = T_PlatRaise; + } + } +} + +// +// EV_StopPlat() +// +// Handler for "stop perpetual floor" linedef type +// +// Passed the linedef that stopped the plat +// Returns true if a plat was put in stasis +// +// jff 2/12/98 added int return value, fixed return +// +int EV_StopPlat(line_t* line) +{ + platlist_t *pl; + for (pl=activeplats; pl; pl=pl->next) // search the active plats + { + plat_t *plat = pl->plat; // for one with the tag not in stasis + if (plat->status != in_stasis && plat->tag == line->tag) + { + plat->oldstatus = plat->status; // put it in stasis + plat->status = in_stasis; + plat->thinker.function = NULL; + } + } + return 1; +} + +// +// P_AddActivePlat() +// +// Add a plat to the head of the active plat list +// +// Passed a pointer to the plat to add +// Returns nothing +// +void P_AddActivePlat(plat_t* plat) +{ + platlist_t *list = malloc(sizeof *list); + list->plat = plat; + plat->list = list; + if ((list->next = activeplats)) + list->next->prev = &list->next; + list->prev = &activeplats; + activeplats = list; +} + +// +// P_RemoveActivePlat() +// +// Remove a plat from the active plat list +// +// Passed a pointer to the plat to remove +// Returns nothing +// +void P_RemoveActivePlat(plat_t* plat) +{ + platlist_t *list = plat->list; + plat->sector->floordata = NULL; //jff 2/23/98 multiple thinkers + P_RemoveThinker(&plat->thinker); + if ((*list->prev = list->next)) + list->next->prev = list->prev; + free(list); +} + +// +// P_RemoveAllActivePlats() +// +// Remove all plats from the active plat list +// +// Passed nothing, returns nothing +// +void P_RemoveAllActivePlats(void) +{ + while (activeplats) + { + platlist_t *next = activeplats->next; + free(activeplats); + activeplats = next; + } +} diff --git a/common/prboom/p_pspr.c b/common/prboom/p_pspr.c new file mode 100755 index 0000000..1088860 --- /dev/null +++ b/common/prboom/p_pspr.c @@ -0,0 +1,865 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Weapon sprite animation, weapon objects. + * Action functions for weapons. + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" +#include "r_main.h" +#include "p_map.h" +#include "p_inter.h" +#include "p_pspr.h" +#include "p_enemy.h" +#include "m_random.h" +#include "s_sound.h" +#include "sounds.h" +#include "d_event.h" +#include "r_demo.h" + +#define LOWERSPEED (FRACUNIT*6) +#define RAISESPEED (FRACUNIT*6) +#define WEAPONBOTTOM (FRACUNIT*128) +#define WEAPONTOP (FRACUNIT*32) + +#define BFGCELLS bfgcells /* Ty 03/09/98 externalized in p_inter.c */ + +extern void P_Thrust(player_t *, angle_t, fixed_t); + +// The following array holds the recoil values // phares + +static const int recoil_values[] = { // phares + 10, // wp_fist + 10, // wp_pistol + 30, // wp_shotgun + 10, // wp_chaingun + 100,// wp_missile + 20, // wp_plasma + 100,// wp_bfg + 0, // wp_chainsaw + 80 // wp_supershotgun +}; + +// +// P_SetPsprite +// + +static void P_SetPsprite(player_t *player, int position, statenum_t stnum) +{ + pspdef_t *psp = &player->psprites[position]; + + do + { + state_t *state; + + if (!stnum) + { + // object removed itself + psp->state = NULL; + break; + } + + state = &states[stnum]; + psp->state = state; + psp->tics = state->tics; // could be 0 + + if (state->misc1) + { + // coordinate set + psp->sx = state->misc1 << FRACBITS; + psp->sy = state->misc2 << FRACBITS; + } + + // Call action routine. + // Modified handling. + if (state->action) + { + state->action(player, psp); + if (!psp->state) + break; + } + stnum = psp->state->nextstate; + } + while (!psp->tics); // an initial state of 0 could cycle through +} + +// +// P_BringUpWeapon +// Starts bringing the pending weapon up +// from the bottom of the screen. +// Uses player +// + +static void P_BringUpWeapon(player_t *player) +{ + statenum_t newstate; + + if (player->pendingweapon == wp_nochange) + player->pendingweapon = player->readyweapon; + + if (player->pendingweapon == wp_chainsaw) + S_StartSound (player->mo, sfx_sawup); + + newstate = weaponinfo[player->pendingweapon].upstate; + + player->pendingweapon = wp_nochange; + // killough 12/98: prevent pistol from starting visibly at bottom of screen: + player->psprites[ps_weapon].sy = + mbf_features ? WEAPONBOTTOM+FRACUNIT*2 : WEAPONBOTTOM; + + P_SetPsprite(player, ps_weapon, newstate); +} + +// The first set is where the weapon preferences from // killough, +// default.cfg are stored. These values represent the keys used // phares +// in DOOM2 to bring up the weapon, i.e. 6 = plasma gun. These // | +// are NOT the wp_* constants. // V + +int weapon_preferences[2][NUMWEAPONS+1] = { + {6, 9, 4, 3, 2, 8, 5, 7, 1, 0}, // !compatibility preferences + {6, 9, 4, 3, 2, 8, 5, 7, 1, 0}, // compatibility preferences +}; + +// P_SwitchWeapon checks current ammo levels and gives you the +// most preferred weapon with ammo. It will not pick the currently +// raised weapon. When called from P_CheckAmmo this won't matter, +// because the raised weapon has no ammo anyway. When called from +// G_BuildTiccmd you want to toggle to a different weapon regardless. + +int P_SwitchWeapon(player_t *player) +{ + int *prefer = weapon_preferences[demo_compatibility!=0]; // killough 3/22/98 + int currentweapon = player->readyweapon; + int newweapon = currentweapon; + int i = NUMWEAPONS+1; // killough 5/2/98 + + // killough 2/8/98: follow preferences and fix BFG/SSG bugs + + do + switch (*prefer++) + { + case 1: + if (!player->powers[pw_strength]) // allow chainsaw override + break; + case 0: + newweapon = wp_fist; + break; + case 2: + if (player->ammo[am_clip]) + newweapon = wp_pistol; + break; + case 3: + if (player->weaponowned[wp_shotgun] && player->ammo[am_shell]) + newweapon = wp_shotgun; + break; + case 4: + if (player->weaponowned[wp_chaingun] && player->ammo[am_clip]) + newweapon = wp_chaingun; + break; + case 5: + if (player->weaponowned[wp_missile] && player->ammo[am_misl]) + newweapon = wp_missile; + break; + case 6: + if (player->weaponowned[wp_plasma] && player->ammo[am_cell] && + gamemode != shareware) + newweapon = wp_plasma; + break; + case 7: + if (player->weaponowned[wp_bfg] && gamemode != shareware && + player->ammo[am_cell] >= (demo_compatibility ? 41 : 40)) + newweapon = wp_bfg; + break; + case 8: + if (player->weaponowned[wp_chainsaw]) + newweapon = wp_chainsaw; + break; + case 9: + if (player->weaponowned[wp_supershotgun] && gamemode == commercial && + player->ammo[am_shell] >= (demo_compatibility ? 3 : 2)) + newweapon = wp_supershotgun; + break; + } + while (newweapon==currentweapon && --i); // killough 5/2/98 + return newweapon; +} + +// killough 5/2/98: whether consoleplayer prefers weapon w1 over weapon w2. +int P_WeaponPreferred(int w1, int w2) +{ + return + (weapon_preferences[0][0] != ++w2 && (weapon_preferences[0][0] == ++w1 || + (weapon_preferences[0][1] != w2 && (weapon_preferences[0][1] == w1 || + (weapon_preferences[0][2] != w2 && (weapon_preferences[0][2] == w1 || + (weapon_preferences[0][3] != w2 && (weapon_preferences[0][3] == w1 || + (weapon_preferences[0][4] != w2 && (weapon_preferences[0][4] == w1 || + (weapon_preferences[0][5] != w2 && (weapon_preferences[0][5] == w1 || + (weapon_preferences[0][6] != w2 && (weapon_preferences[0][6] == w1 || + (weapon_preferences[0][7] != w2 && (weapon_preferences[0][7] == w1 + )))))))))))))))); +} + +// +// P_CheckAmmo +// Returns true if there is enough ammo to shoot. +// If not, selects the next weapon to use. +// (only in demo_compatibility mode -- killough 3/22/98) +// + +boolean P_CheckAmmo(player_t *player) +{ + ammotype_t ammo = weaponinfo[player->readyweapon].ammo; + int count = 1; // Regular + + if (player->readyweapon == wp_bfg) // Minimal amount for one shot varies. + count = BFGCELLS; + else + if (player->readyweapon == wp_supershotgun) // Double barrel. + count = 2; + + // Some do not need ammunition anyway. + // Return if current ammunition sufficient. + + if (ammo == am_noammo || player->ammo[ammo] >= count) + return true; + + // Out of ammo, pick a weapon to change to. + // + // killough 3/22/98: for old demos we do the switch here and now; + // for Boom games we cannot do this, and have different player + // preferences across demos or networks, so we have to use the + // G_BuildTiccmd() interface instead of making the switch here. + + if (demo_compatibility) + { + player->pendingweapon = P_SwitchWeapon(player); // phares + // Now set appropriate weapon overlay. + P_SetPsprite(player,ps_weapon,weaponinfo[player->readyweapon].downstate); + } + + return false; +} + +// +// P_FireWeapon. +// + +static void P_FireWeapon(player_t *player) +{ + statenum_t newstate; + + if (!P_CheckAmmo(player)) + return; + + P_SetMobjState(player->mo, S_PLAY_ATK1); + newstate = weaponinfo[player->readyweapon].atkstate; + P_SetPsprite(player, ps_weapon, newstate); + P_NoiseAlert(player->mo, player->mo); +} + +// +// P_DropWeapon +// Player died, so put the weapon away. +// + +void P_DropWeapon(player_t *player) +{ + P_SetPsprite(player, ps_weapon, weaponinfo[player->readyweapon].downstate); +} + +// +// A_WeaponReady +// The player can fire the weapon +// or change to another weapon at this time. +// Follows after getting weapon up, +// or after previous attack/fire sequence. +// + +void A_WeaponReady(player_t *player, pspdef_t *psp) +{ + // get out of attack state + if (player->mo->state == &states[S_PLAY_ATK1] + || player->mo->state == &states[S_PLAY_ATK2] ) + P_SetMobjState(player->mo, S_PLAY); + + if (player->readyweapon == wp_chainsaw && psp->state == &states[S_SAW]) + S_StartSound(player->mo, sfx_sawidl); + + // check for change + // if player is dead, put the weapon away + + if (player->pendingweapon != wp_nochange || !player->health) + { + // change weapon (pending weapon should already be validated) + statenum_t newstate = weaponinfo[player->readyweapon].downstate; + P_SetPsprite(player, ps_weapon, newstate); + return; + } + + // check for fire + // the missile launcher and bfg do not auto fire + + if (player->cmd.buttons & BT_ATTACK) + { + if (!player->attackdown || (player->readyweapon != wp_missile && + player->readyweapon != wp_bfg)) + { + player->attackdown = true; + P_FireWeapon(player); + return; + } + } + else + player->attackdown = false; + + // bob the weapon based on movement speed + { + int angle = (128*leveltime) & FINEMASK; + psp->sx = FRACUNIT + FixedMul(player->bob, finecosine[angle]); + angle &= FINEANGLES/2-1; + psp->sy = WEAPONTOP + FixedMul(player->bob, finesine[angle]); + } +} + +// +// A_ReFire +// The player can re-fire the weapon +// without lowering it entirely. +// + +void A_ReFire(player_t *player, pspdef_t *psp) +{ + // check for fire + // (if a weaponchange is pending, let it go through instead) + + if ( (player->cmd.buttons & BT_ATTACK) + && player->pendingweapon == wp_nochange && player->health) + { + player->refire++; + P_FireWeapon(player); + } + else + { + player->refire = 0; + P_CheckAmmo(player); + } +} + +void A_CheckReload(player_t *player, pspdef_t *psp) +{ + if (!P_CheckAmmo(player) && compatibility_level >= prboom_4_compatibility) { + /* cph 2002/08/08 - In old Doom, P_CheckAmmo would start the weapon lowering + * immediately. This was lost in Boom when the weapon switching logic was + * rewritten. But we must tell Doom that we don't need to complete the + * reload frames for the weapon here. G_BuildTiccmd will set ->pendingweapon + * for us later on. */ + P_SetPsprite(player,ps_weapon,weaponinfo[player->readyweapon].downstate); + } +} + +// +// A_Lower +// Lowers current weapon, +// and changes weapon at bottom. +// + +void A_Lower(player_t *player, pspdef_t *psp) +{ + psp->sy += LOWERSPEED; + + // Is already down. + if (psp->sy < WEAPONBOTTOM) + return; + + // Player is dead. + if (player->playerstate == PST_DEAD) + { + psp->sy = WEAPONBOTTOM; + return; // don't bring weapon back up + } + + // The old weapon has been lowered off the screen, + // so change the weapon and start raising it + + if (!player->health) + { // Player is dead, so keep the weapon off screen. + P_SetPsprite(player, ps_weapon, S_NULL); + return; + } + + player->readyweapon = player->pendingweapon; + + P_BringUpWeapon(player); +} + +// +// A_Raise +// + +void A_Raise(player_t *player, pspdef_t *psp) +{ + statenum_t newstate; + + psp->sy -= RAISESPEED; + + if (psp->sy > WEAPONTOP) + return; + + psp->sy = WEAPONTOP; + + // The weapon has been raised all the way, + // so change to the ready state. + + newstate = weaponinfo[player->readyweapon].readystate; + + P_SetPsprite(player, ps_weapon, newstate); +} + + +// Weapons now recoil, amount depending on the weapon. // phares +// // | +// The P_SetPsprite call in each of the weapon firing routines // V +// was moved here so the recoil could be synched with the +// muzzle flash, rather than the pressing of the trigger. +// The BFG delay caused this to be necessary. + +static void A_FireSomething(player_t* player,int adder) +{ + P_SetPsprite(player, ps_flash, + weaponinfo[player->readyweapon].flashstate+adder); + + // killough 3/27/98: prevent recoil in no-clipping mode + if (!(player->mo->flags & MF_NOCLIP)) + if (!compatibility && weapon_recoil) + P_Thrust(player, + ANG180+player->mo->angle, // ^ + 2048*recoil_values[player->readyweapon]); // | +} // phares + +// +// A_GunFlash +// + +void A_GunFlash(player_t *player, pspdef_t *psp) +{ + P_SetMobjState(player->mo, S_PLAY_ATK2); + + A_FireSomething(player,0); // phares +} + +// +// WEAPON ATTACKS +// + +// +// A_Punch +// + +void A_Punch(player_t *player, pspdef_t *psp) +{ + angle_t angle; + int t, slope, damage = (P_Random(pr_punch)%10+1)<<1; + + if (player->powers[pw_strength]) + damage *= 10; + + angle = player->mo->angle; + + // killough 5/5/98: remove dependence on order of evaluation: + t = P_Random(pr_punchangle); + angle += (t - P_Random(pr_punchangle))<<18; + + /* killough 8/2/98: make autoaiming prefer enemies */ + if (!mbf_features || + (slope = P_AimLineAttack(player->mo, angle, MELEERANGE, MF_FRIEND), + !linetarget)) + slope = P_AimLineAttack(player->mo, angle, MELEERANGE, 0); + + P_LineAttack(player->mo, angle, MELEERANGE, slope, damage); + + if (!linetarget) + return; + + S_StartSound(player->mo, sfx_punch); + + // turn to face target + + player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, + linetarget->x, linetarget->y); + R_SmoothPlaying_Reset(player); // e6y +} + +// +// A_Saw +// + +void A_Saw(player_t *player, pspdef_t *psp) +{ + int slope, damage = 2*(P_Random(pr_saw)%10+1); + angle_t angle = player->mo->angle; + // killough 5/5/98: remove dependence on order of evaluation: + int t = P_Random(pr_saw); + angle += (t - P_Random(pr_saw))<<18; + + /* Use meleerange + 1 so that the puff doesn't skip the flash + * killough 8/2/98: make autoaiming prefer enemies */ + if (!mbf_features || + (slope = P_AimLineAttack(player->mo, angle, MELEERANGE+1, MF_FRIEND), + !linetarget)) + slope = P_AimLineAttack(player->mo, angle, MELEERANGE+1, 0); + + P_LineAttack(player->mo, angle, MELEERANGE+1, slope, damage); + + if (!linetarget) + { + S_StartSound(player->mo, sfx_sawful); + return; + } + + S_StartSound(player->mo, sfx_sawhit); + + // turn to face target + angle = R_PointToAngle2(player->mo->x, player->mo->y, + linetarget->x, linetarget->y); + + if (angle - player->mo->angle > ANG180) { + if (angle - player->mo->angle < -ANG90/20) + player->mo->angle = angle + ANG90/21; + else + player->mo->angle -= ANG90/20; + } else { + if (angle - player->mo->angle > ANG90/20) + player->mo->angle = angle - ANG90/21; + else + player->mo->angle += ANG90/20; + } + + player->mo->flags |= MF_JUSTATTACKED; + R_SmoothPlaying_Reset(player); // e6y +} + +// +// A_FireMissile +// + +void A_FireMissile(player_t *player, pspdef_t *psp) +{ + player->ammo[weaponinfo[player->readyweapon].ammo]--; + P_SpawnPlayerMissile(player->mo, MT_ROCKET); +} + +// +// A_FireBFG +// + +void A_FireBFG(player_t *player, pspdef_t *psp) +{ + player->ammo[weaponinfo[player->readyweapon].ammo] -= BFGCELLS; + P_SpawnPlayerMissile(player->mo, MT_BFG); +} + +// +// A_FirePlasma +// + +void A_FirePlasma(player_t *player, pspdef_t *psp) +{ + player->ammo[weaponinfo[player->readyweapon].ammo]--; + + A_FireSomething(player,P_Random(pr_plasma)&1); // phares + P_SpawnPlayerMissile(player->mo, MT_PLASMA); +} + +// +// P_BulletSlope +// Sets a slope so a near miss is at aproximately +// the height of the intended target +// + +static fixed_t bulletslope; + +#ifdef IPHONE // add some auto-aim to compensate for the touch screen controls + +static angle_t autoAimAngle; + +static void P_BulletSlope(mobj_t *mo) +{ + int aim; + angle_t an = mo->angle; // see which target is to be aimed at + + autoAimAngle = an; + for ( aim = 0 ; aim < 5 ; aim++ ) { + if ( aim & 1 ) { + an += aim<<26; + } else { + an -= aim<<26; + } + bulletslope = P_AimLineAttack(mo, an, 16*64*FRACUNIT, 0); + if ( linetarget ) { + // this will be a hit + if ( aim > 0 ) { + printf( "auto-aim hit on %i\n", aim ); // !@# + } + autoAimAngle = an; + break; + } + } +} + +#else + +static void P_BulletSlope(mobj_t *mo) +{ + angle_t an = mo->angle; // see which target is to be aimed at + + /* killough 8/2/98: make autoaiming prefer enemies */ + uint_64_t mask = mbf_features ? MF_FRIEND : 0; + + do + { + bulletslope = P_AimLineAttack(mo, an, 16*64*FRACUNIT, mask); + if (!linetarget) + bulletslope = P_AimLineAttack(mo, an += 1<<26, 16*64*FRACUNIT, mask); + if (!linetarget) + bulletslope = P_AimLineAttack(mo, an -= 2<<26, 16*64*FRACUNIT, mask); + } + while (mask && (mask=0, !linetarget)); /* killough 8/2/98 */ +} + +#endif + +// +// P_GunShot +// + +static void P_GunShot(mobj_t *mo, boolean accurate) +{ + int damage = 5*(P_Random(pr_gunshot)%3+1); + angle_t angle = mo->angle; +#ifdef IPHONE + if ( !demoplayback ) { + angle = autoAimAngle; + } +#endif + if (!accurate) + { // killough 5/5/98: remove dependence on order of evaluation: + int t = P_Random(pr_misfire); + angle += (t - P_Random(pr_misfire))<<18; + } + + P_LineAttack(mo, angle, MISSILERANGE, bulletslope, damage); +} + +// +// A_FirePistol +// + +void A_FirePistol(player_t *player, pspdef_t *psp) +{ + S_StartSound(player->mo, sfx_pistol); + + P_SetMobjState(player->mo, S_PLAY_ATK2); + player->ammo[weaponinfo[player->readyweapon].ammo]--; + + A_FireSomething(player,0); // phares + P_BulletSlope(player->mo); + P_GunShot(player->mo, !player->refire); +} + +// +// A_FireShotgun +// + +void A_FireShotgun(player_t *player, pspdef_t *psp) +{ + int i; + + S_StartSound(player->mo, sfx_shotgn); + P_SetMobjState(player->mo, S_PLAY_ATK2); + + player->ammo[weaponinfo[player->readyweapon].ammo]--; + + A_FireSomething(player,0); // phares + + P_BulletSlope(player->mo); + + for (i=0; i<7; i++) + P_GunShot(player->mo, false); +} + +// +// A_FireShotgun2 +// + +void A_FireShotgun2(player_t *player, pspdef_t *psp) +{ + int i; + + S_StartSound(player->mo, sfx_dshtgn); + P_SetMobjState(player->mo, S_PLAY_ATK2); + player->ammo[weaponinfo[player->readyweapon].ammo] -= 2; + + A_FireSomething(player,0); // phares + + P_BulletSlope(player->mo); + + for (i=0; i<20; i++) + { + int damage = 5*(P_Random(pr_shotgun)%3+1); + angle_t angle = player->mo->angle; + // killough 5/5/98: remove dependence on order of evaluation: + int t = P_Random(pr_shotgun); + angle += (t - P_Random(pr_shotgun))<<19; + t = P_Random(pr_shotgun); + P_LineAttack(player->mo, angle, MISSILERANGE, bulletslope + + ((t - P_Random(pr_shotgun))<<5), damage); + } +} + +// +// A_FireCGun +// + +void A_FireCGun(player_t *player, pspdef_t *psp) +{ + if (player->ammo[weaponinfo[player->readyweapon].ammo] || comp[comp_sound]) + S_StartSound(player->mo, sfx_pistol); + + if (!player->ammo[weaponinfo[player->readyweapon].ammo]) + return; + + P_SetMobjState(player->mo, S_PLAY_ATK2); + player->ammo[weaponinfo[player->readyweapon].ammo]--; + + A_FireSomething(player,psp->state - &states[S_CHAIN1]); // phares + + P_BulletSlope(player->mo); + + P_GunShot(player->mo, !player->refire); +} + +void A_Light0(player_t *player, pspdef_t *psp) +{ + player->extralight = 0; +} + +void A_Light1 (player_t *player, pspdef_t *psp) +{ + player->extralight = 1; +} + +void A_Light2 (player_t *player, pspdef_t *psp) +{ + player->extralight = 2; +} + +// +// A_BFGSpray +// Spawn a BFG explosion on every monster in view +// + +void A_BFGSpray(mobj_t *mo) +{ + int i; + + for (i=0 ; i<40 ; i++) // offset angles from its attack angle + { + int j, damage; + angle_t an = mo->angle - ANG90/2 + ANG90/40*i; + + // mo->target is the originator (player) of the missile + + // killough 8/2/98: make autoaiming prefer enemies + if (!mbf_features || + (P_AimLineAttack(mo->target, an, 16*64*FRACUNIT, MF_FRIEND), + !linetarget)) + P_AimLineAttack(mo->target, an, 16*64*FRACUNIT, 0); + + if (!linetarget) + continue; + + P_SpawnMobj(linetarget->x, linetarget->y, + linetarget->z + (linetarget->height>>2), MT_EXTRABFG); + + for (damage=j=0; j<15; j++) + damage += (P_Random(pr_bfg)&7) + 1; + + P_DamageMobj(linetarget, mo->target, mo->target, damage); + } +} + +// +// A_BFGsound +// + +void A_BFGsound(player_t *player, pspdef_t *psp) +{ + S_StartSound(player->mo, sfx_bfg); +} + +// +// P_SetupPsprites +// Called at start of level for each player. +// + +void P_SetupPsprites(player_t *player) +{ + int i; + + // remove all psprites + for (i=0; ipsprites[i].state = NULL; + + // spawn the gun + player->pendingweapon = player->readyweapon; + P_BringUpWeapon(player); +} + +// +// P_MovePsprites +// Called every tic by player thinking routine. +// + +void P_MovePsprites(player_t *player) +{ + pspdef_t *psp = player->psprites; + int i; + + // a null state means not active + // drop tic count and possibly change state + // a -1 tic count never changes + + for (i=0; istate && psp->tics != -1 && !--psp->tics) + P_SetPsprite(player, i, psp->state->nextstate); + + player->psprites[ps_flash].sx = player->psprites[ps_weapon].sx; + player->psprites[ps_flash].sy = player->psprites[ps_weapon].sy; +} diff --git a/common/prboom/p_pspr.h b/common/prboom/p_pspr.h new file mode 100755 index 0000000..bb76fb4 --- /dev/null +++ b/common/prboom/p_pspr.h @@ -0,0 +1,116 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Sprite animation. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __P_PSPR__ +#define __P_PSPR__ + +/* Basic data types. + * Needs fixed point, and BAM angles. */ + +#include "m_fixed.h" +#include "tables.h" + +/* Needs to include the precompiled sprite animation tables. + * + * Header generated by multigen utility. + * This includes all the data for thing animation, + * i.e. the Thing Atrributes table and the Frame Sequence table. + */ + +#include "info.h" + + +/* + * Frame flags: + * handles maximum brightness (torches, muzzle flare, light sources) + */ + +#define FF_FULLBRIGHT 0x8000 /* flag in thing->frame */ +#define FF_FRAMEMASK 0x7fff + +/* + * Overlay psprites are scaled shapes + * drawn directly on the view screen, + * coordinates are given for a 320*200 view screen. + */ + +typedef enum +{ + ps_weapon, + ps_flash, + NUMPSPRITES +} psprnum_t; + +typedef struct +{ + state_t *state; /* a NULL state means not active */ + int tics; + fixed_t sx; + fixed_t sy; +} pspdef_t; + +extern int weapon_preferences[2][NUMWEAPONS+1]; /* killough 5/2/98 */ +int P_WeaponPreferred(int w1, int w2); + +struct player_s; +int P_SwitchWeapon(struct player_s *player); +boolean P_CheckAmmo(struct player_s *player); +void P_SetupPsprites(struct player_s *curplayer); +void P_MovePsprites(struct player_s *curplayer); +void P_DropWeapon(struct player_s *player); + +void A_Light0(); +void A_WeaponReady(); +void A_Lower(); +void A_Raise(); +void A_Punch(); +void A_ReFire(); +void A_FirePistol(); +void A_Light1(); +void A_FireShotgun(); +void A_Light2(); +void A_FireShotgun2(); +void A_CheckReload(); +void A_OpenShotgun2(); +void A_LoadShotgun2(); +void A_CloseShotgun2(); +void A_FireCGun(); +void A_GunFlash(); +void A_FireMissile(); +void A_Saw(); +void A_FirePlasma(); +void A_BFGsound(); +void A_FireBFG(); +void A_BFGSpray(); + +#endif diff --git a/common/prboom/p_saveg.c b/common/prboom/p_saveg.c new file mode 100755 index 0000000..7e3d63b --- /dev/null +++ b/common/prboom/p_saveg.c @@ -0,0 +1,1029 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Archiving: SaveGame I/O. + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" +#include "r_main.h" +#include "p_maputl.h" +#include "p_spec.h" +#include "p_tick.h" +#include "p_saveg.h" +#include "m_random.h" +#include "am_map.h" +#include "p_enemy.h" +#include "lprintf.h" + +byte *save_p; + +// Pads save_p to a 4-byte boundary +// so that the load/save works on SGI&Gecko. +#define PADSAVEP() do { save_p += (4 - ((int) save_p & 3)) & 3; } while (0) +// +// P_ArchivePlayers +// +void P_ArchivePlayers (void) +{ + int i; + + CheckSaveGame(sizeof(player_t) * MAXPLAYERS); // killough + for (i=0 ; ipsprites[j].state) + dest->psprites[j].state = + (state_t *)(dest->psprites[j].state-states); + } +} + +// +// P_UnArchivePlayers +// +void P_UnArchivePlayers (void) +{ + int i; + + for (i=0 ; ifloorheight + sizeof sec->ceilingheight) + * numsectors + sizeof(short)*3*numlines + 4; + + for (i=0; itextureoffset + sizeof si->rowoffset; + if (lines[i].sidenum[1] != NO_INDEX) + size += + sizeof(short)*3 + sizeof si->textureoffset + sizeof si->rowoffset; + } + + CheckSaveGame(size); // killough + + PADSAVEP(); // killough 3/22/98 + + put = (short *)save_p; + + // do sectors + for (i=0, sec = sectors ; ifloorheight, sizeof sec->floorheight); + put = (void *)((char *) put + sizeof sec->floorheight); + memcpy(put, &sec->ceilingheight, sizeof sec->ceilingheight); + put = (void *)((char *) put + sizeof sec->ceilingheight); + + *put++ = sec->floorpic; + *put++ = sec->ceilingpic; + *put++ = sec->lightlevel; + *put++ = sec->special; // needed? yes -- transfer types + *put++ = sec->tag; // needed? need them -- killough + } + + // do lines + for (i=0, li = lines ; iflags; + *put++ = li->special; + *put++ = li->tag; + + for (j=0; j<2; j++) + if (li->sidenum[j] != NO_INDEX) + { + si = &sides[li->sidenum[j]]; + + // killough 10/98: save full sidedef offsets, + // preserving fractional scroll offsets + + memcpy(put, &si->textureoffset, sizeof si->textureoffset); + put = (void *)((char *) put + sizeof si->textureoffset); + memcpy(put, &si->rowoffset, sizeof si->rowoffset); + put = (void *)((char *) put + sizeof si->rowoffset); + + *put++ = si->toptexture; + *put++ = si->bottomtexture; + *put++ = si->midtexture; + } + } + save_p = (byte *) put; +} + + + +// +// P_UnArchiveWorld +// +void P_UnArchiveWorld (void) +{ + int i; + sector_t *sec; + line_t *li; + const short *get; + + PADSAVEP(); // killough 3/22/98 + + get = (short *) save_p; + + // do sectors + for (i=0, sec = sectors ; ifloorheight, get, sizeof sec->floorheight); + get = (void *)((char *) get + sizeof sec->floorheight); + memcpy(&sec->ceilingheight, get, sizeof sec->ceilingheight); + get = (void *)((char *) get + sizeof sec->ceilingheight); + + sec->floorpic = *get++; + sec->ceilingpic = *get++; + sec->lightlevel = *get++; + sec->special = *get++; + sec->tag = *get++; + sec->ceilingdata = 0; //jff 2/22/98 now three thinker fields, not two + sec->floordata = 0; + sec->lightingdata = 0; + sec->soundtarget = 0; + } + + // do lines + for (i=0, li = lines ; iflags = *get++; + li->special = *get++; + li->tag = *get++; + for (j=0 ; j<2 ; j++) + if (li->sidenum[j] != NO_INDEX) + { + side_t *si = &sides[li->sidenum[j]]; + + // killough 10/98: load full sidedef offsets, including fractions + + memcpy(&si->textureoffset, get, sizeof si->textureoffset); + get = (void *)((char *) get + sizeof si->textureoffset); + memcpy(&si->rowoffset, get, sizeof si->rowoffset); + get = (void *)((char *) get + sizeof si->rowoffset); + + si->toptexture = *get++; + si->bottomtexture = *get++; + si->midtexture = *get++; + } + } + save_p = (byte *) get; +} + +// +// Thinkers +// + +typedef enum { + tc_end, + tc_mobj +} thinkerclass_t; + +// phares 9/13/98: Moved this code outside of P_ArchiveThinkers so the +// thinker indices could be used by the code that saves sector info. + +static int number_of_thinkers; + +void P_ThinkerToIndex(void) + { + thinker_t *th; + + // killough 2/14/98: + // count the number of thinkers, and mark each one with its index, using + // the prev field as a placeholder, since it can be restored later. + + number_of_thinkers = 0; + for (th = thinkercap.next ; th != &thinkercap ; th=th->next) + if (th->function == P_MobjThinker) + th->prev = (thinker_t *) ++number_of_thinkers; + } + +// phares 9/13/98: Moved this code outside of P_ArchiveThinkers so the +// thinker indices could be used by the code that saves sector info. + +void P_IndexToThinker(void) + { + // killough 2/14/98: restore prev pointers + thinker_t *th; + thinker_t *prev = &thinkercap; + + for (th = thinkercap.next ; th != &thinkercap ; prev=th, th=th->next) + th->prev = prev; + } + +// +// P_ArchiveThinkers +// +// 2/14/98 killough: substantially modified to fix savegame bugs + +void P_ArchiveThinkers (void) +{ + thinker_t *th; + + CheckSaveGame(sizeof brain); // killough 3/26/98: Save boss brain state + memcpy(save_p, &brain, sizeof brain); + save_p += sizeof brain; + + /* check that enough room is available in savegame buffer + * - killough 2/14/98 + * cph - use number_of_thinkers saved by P_ThinkerToIndex above + * size per object is sizeof(mobj_t) - 2*sizeof(void*) - 4*sizeof(fixed_t) plus + * padded type (4) plus 5*sizeof(void*), i.e. sizeof(mobj_t) + 4 + + * 3*sizeof(void*) + * cph - +1 for the tc_end + */ + CheckSaveGame(number_of_thinkers*(sizeof(mobj_t)-3*sizeof(fixed_t)+4+3*sizeof(void*)) +1); + + // save off the current thinkers + for (th = thinkercap.next ; th != &thinkercap ; th=th->next) + if (th->function == P_MobjThinker) + { + mobj_t *mobj; + + *save_p++ = tc_mobj; + PADSAVEP(); + mobj = (mobj_t *)save_p; + /* cph 2006/07/30 - + * The end of mobj_t changed from + * boolean invisible; + * mobj_t* lastenemy; + * mobj_t* above_monster; + * mobj_t* below_monster; + * void* touching_sectorlist; + * to + * mobj_t* lastenemy; + * void* touching_sectorlist; + * fixed_t PrevX, PrevY, PrevZ, padding; + * at prboom 2.4.4. There is code here to preserve the savegame format. + * + * touching_sectorlist is reconstructed anyway, so we now leave off the + * last 2 words of mobj_t, write 5 words of 0 and then write lastenemy + * into the second of these. + */ + memcpy (mobj, th, sizeof(*mobj) - 2*sizeof(void*)); + save_p += sizeof(*mobj) - 2*sizeof(void*) - 4*sizeof(fixed_t); + memset (save_p, 0, 5*sizeof(void*)); + mobj->state = (state_t *)(mobj->state - states); + + // killough 2/14/98: convert pointers into indices. + // Fixes many savegame problems, by properly saving + // target and tracer fields. Note: we store NULL if + // the thinker pointed to by these fields is not a + // mobj thinker. + + if (mobj->target) + mobj->target = mobj->target->thinker.function == + P_MobjThinker ? + (mobj_t *) mobj->target->thinker.prev : NULL; + + if (mobj->tracer) + mobj->tracer = mobj->tracer->thinker.function == + P_MobjThinker ? + (mobj_t *) mobj->tracer->thinker.prev : NULL; + + // killough 2/14/98: new field: save last known enemy. Prevents + // monsters from going to sleep after killing monsters and not + // seeing player anymore. + + if (((mobj_t*)th)->lastenemy && ((mobj_t*)th)->lastenemy->thinker.function == P_MobjThinker) { + memcpy (save_p + sizeof(void*), &(((mobj_t*)th)->lastenemy->thinker.prev), sizeof(void*)); + } + + // killough 2/14/98: end changes + + save_p += 5*sizeof(void*); + + if (mobj->player) + mobj->player = (player_t *)((mobj->player-players) + 1); + } + + // add a terminating marker + *save_p++ = tc_end; + + // killough 9/14/98: save soundtargets + { + int i; + CheckSaveGame(numsectors * sizeof(mobj_t *)); // killough 9/14/98 + for (i = 0; i < numsectors; i++) + { + mobj_t *target = sectors[i].soundtarget; + // Fix crash on reload when a soundtarget points to a removed corpse + // (prboom bug #1590350) + if (target && target->thinker.function == P_MobjThinker) + target = (mobj_t *) target->thinker.prev; + else + target = NULL; + memcpy(save_p, &target, sizeof target); + save_p += sizeof target; + } + } +} + +/* + * killough 11/98 + * + * Same as P_SetTarget() in p_tick.c, except that the target is nullified + * first, so that no old target's reference count is decreased (when loading + * savegames, old targets are indices, not really pointers to targets). + */ + +static void P_SetNewTarget(mobj_t **mop, mobj_t *targ) +{ + *mop = NULL; + P_SetTarget(mop, targ); +} + +// +// P_UnArchiveThinkers +// +// 2/14/98 killough: substantially modified to fix savegame bugs +// + +// savegame file stores ints in the corresponding * field; this function +// safely casts them back to int. +static int P_GetMobj(mobj_t* mi, size_t s) +{ + size_t i = (size_t)mi; + if (i >= s) I_Error("Corrupt savegame"); + return i; +} + +void P_UnArchiveThinkers (void) +{ + thinker_t *th; + mobj_t **mobj_p; // killough 2/14/98: Translation table + size_t size; // killough 2/14/98: size of or index into table + + totallive = 0; + // killough 3/26/98: Load boss brain state + memcpy(&brain, save_p, sizeof brain); + save_p += sizeof brain; + + // remove all the current thinkers + for (th = thinkercap.next; th != &thinkercap; ) + { + thinker_t *next = th->next; + if (th->function == P_MobjThinker) + P_RemoveMobj ((mobj_t *) th); + else + Z_Free (th); + th = next; + } + P_InitThinkers (); + + // killough 2/14/98: count number of thinkers by skipping through them + { + byte *sp = save_p; // save pointer and skip header + for (size = 1; *save_p++ == tc_mobj; size++) // killough 2/14/98 + { // skip all entries, adding up count + PADSAVEP(); + /* cph 2006/07/30 - see comment below for change in layout of mobj_t */ + save_p += sizeof(mobj_t)+3*sizeof(void*)-4*sizeof(fixed_t); + } + + if (*--save_p != tc_end) + I_Error ("P_UnArchiveThinkers: Unknown tclass %i in savegame", *save_p); + + // first table entry special: 0 maps to NULL + *(mobj_p = malloc(size * sizeof *mobj_p)) = 0; // table of pointers + save_p = sp; // restore save pointer + } + + // read in saved thinkers + for (size = 1; *save_p++ == tc_mobj; size++) // killough 2/14/98 + { + mobj_t *mobj = Z_Malloc(sizeof(mobj_t), PU_LEVEL, NULL); + + // killough 2/14/98 -- insert pointers to thinkers into table, in order: + mobj_p[size] = mobj; + + PADSAVEP(); + /* cph 2006/07/30 - + * The end of mobj_t changed from + * boolean invisible; + * mobj_t* lastenemy; + * mobj_t* above_monster; + * mobj_t* below_monster; + * void* touching_sectorlist; + * to + * mobj_t* lastenemy; + * void* touching_sectorlist; + * fixed_t PrevX, PrevY, PrevZ; + * at prboom 2.4.4. There is code here to preserve the savegame format. + * + * touching_sectorlist is reconstructed anyway, so we now read in all + * but the last 5 words from the savegame (filling all but the last 2 + * fields of our current mobj_t. We then pull lastenemy from the 2nd of + * the 5 leftover words, and skip the others. + */ + memcpy (mobj, save_p, sizeof(mobj_t)-2*sizeof(void*)-4*sizeof(fixed_t)); + save_p += sizeof(mobj_t)-sizeof(void*)-4*sizeof(fixed_t); + memcpy (&(mobj->lastenemy), save_p, sizeof(void*)); + save_p += 4*sizeof(void*); + mobj->state = states + (int) mobj->state; + + if (mobj->player) + (mobj->player = &players[(int) mobj->player - 1]) -> mo = mobj; + + P_SetThingPosition (mobj); + mobj->info = &mobjinfo[mobj->type]; + + // killough 2/28/98: + // Fix for falling down into a wall after savegame loaded: + // mobj->floorz = mobj->subsector->sector->floorheight; + // mobj->ceilingz = mobj->subsector->sector->ceilingheight; + + mobj->thinker.function = P_MobjThinker; + P_AddThinker (&mobj->thinker); + + if (!((mobj->flags ^ MF_COUNTKILL) & (MF_FRIEND | MF_COUNTKILL | MF_CORPSE))) + totallive++; + } + + // killough 2/14/98: adjust target and tracer fields, plus + // lastenemy field, to correctly point to mobj thinkers. + // NULL entries automatically handled by first table entry. + // + // killough 11/98: use P_SetNewTarget() to set fields + + for (th = thinkercap.next ; th != &thinkercap ; th=th->next) + { + P_SetNewTarget(&((mobj_t *) th)->target, + mobj_p[P_GetMobj(((mobj_t *)th)->target,size)]); + + P_SetNewTarget(&((mobj_t *) th)->tracer, + mobj_p[P_GetMobj(((mobj_t *)th)->tracer,size)]); + + P_SetNewTarget(&((mobj_t *) th)->lastenemy, + mobj_p[P_GetMobj(((mobj_t *)th)->lastenemy,size)]); + } + + { // killough 9/14/98: restore soundtargets + int i; + for (i = 0; i < numsectors; i++) + { + mobj_t *target; + memcpy(&target, save_p, sizeof target); + save_p += sizeof target; + // Must verify soundtarget. See P_ArchiveThinkers. + P_SetNewTarget(§ors[i].soundtarget, mobj_p[P_GetMobj(target,size)]); + } + } + + free(mobj_p); // free translation table + + // killough 3/26/98: Spawn icon landings: + if (gamemode == commercial) + P_SpawnBrainTargets(); +} + +// +// P_ArchiveSpecials +// +enum { + tc_ceiling, + tc_door, + tc_floor, + tc_plat, + tc_flash, + tc_strobe, + tc_glow, + tc_elevator, //jff 2/22/98 new elevator type thinker + tc_scroll, // killough 3/7/98: new scroll effect thinker + tc_pusher, // phares 3/22/98: new push/pull effect thinker + tc_flicker, // killough 10/4/98 + tc_endspecials +} specials_e; + +// +// Things to handle: +// +// T_MoveCeiling, (ceiling_t: sector_t * swizzle), - active list +// T_VerticalDoor, (vldoor_t: sector_t * swizzle), +// T_MoveFloor, (floormove_t: sector_t * swizzle), +// T_LightFlash, (lightflash_t: sector_t * swizzle), +// T_StrobeFlash, (strobe_t: sector_t *), +// T_Glow, (glow_t: sector_t *), +// T_PlatRaise, (plat_t: sector_t *), - active list +// T_MoveElevator, (plat_t: sector_t *), - active list // jff 2/22/98 +// T_Scroll // killough 3/7/98 +// T_Pusher // phares 3/22/98 +// T_FireFlicker // killough 10/4/98 +// + +void P_ArchiveSpecials (void) +{ + thinker_t *th; + size_t size = 0; // killough + + // save off the current thinkers (memory size calculation -- killough) + + for (th = thinkercap.next ; th != &thinkercap ; th=th->next) + if (!th->function) + { + platlist_t *pl; + ceilinglist_t *cl; //jff 2/22/98 need this for ceilings too now + for (pl=activeplats; pl; pl=pl->next) + if (pl->plat == (plat_t *) th) // killough 2/14/98 + { + size += 4+sizeof(plat_t); + goto end; + } + for (cl=activeceilings; cl; cl=cl->next) // search for activeceiling + if (cl->ceiling == (ceiling_t *) th) //jff 2/22/98 + { + size += 4+sizeof(ceiling_t); + goto end; + } + end:; + } + else + size += + th->function==T_MoveCeiling ? 4+sizeof(ceiling_t) : + th->function==T_VerticalDoor ? 4+sizeof(vldoor_t) : + th->function==T_MoveFloor ? 4+sizeof(floormove_t): + th->function==T_PlatRaise ? 4+sizeof(plat_t) : + th->function==T_LightFlash ? 4+sizeof(lightflash_t): + th->function==T_StrobeFlash ? 4+sizeof(strobe_t) : + th->function==T_Glow ? 4+sizeof(glow_t) : + th->function==T_MoveElevator ? 4+sizeof(elevator_t): + th->function==T_Scroll ? 4+sizeof(scroll_t) : + th->function==T_Pusher ? 4+sizeof(pusher_t) : + th->function==T_FireFlicker? 4+sizeof(fireflicker_t) : + 0; + + CheckSaveGame(size + 1); // killough; cph: +1 for the tc_endspecials + + // save off the current thinkers + for (th=thinkercap.next; th!=&thinkercap; th=th->next) + { + if (!th->function) + { + platlist_t *pl; + ceilinglist_t *cl; //jff 2/22/98 add iter variable for ceilings + + // killough 2/8/98: fix plat original height bug. + // Since acv==NULL, this could be a plat in stasis. + // so check the active plats list, and save this + // plat (jff: or ceiling) even if it is in stasis. + + for (pl=activeplats; pl; pl=pl->next) + if (pl->plat == (plat_t *) th) // killough 2/14/98 + goto plat; + + for (cl=activeceilings; cl; cl=cl->next) + if (cl->ceiling == (ceiling_t *) th) //jff 2/22/98 + goto ceiling; + + continue; + } + + if (th->function == T_MoveCeiling) + { + ceiling_t *ceiling; + ceiling: // killough 2/14/98 + *save_p++ = tc_ceiling; + PADSAVEP(); + ceiling = (ceiling_t *)save_p; + memcpy (ceiling, th, sizeof(*ceiling)); + save_p += sizeof(*ceiling); + ceiling->sector = (sector_t *)(ceiling->sector - sectors); + continue; + } + + if (th->function == T_VerticalDoor) + { + vldoor_t *door; + *save_p++ = tc_door; + PADSAVEP(); + door = (vldoor_t *) save_p; + memcpy (door, th, sizeof *door); + save_p += sizeof(*door); + door->sector = (sector_t *)(door->sector - sectors); + //jff 1/31/98 archive line remembered by door as well + door->line = (line_t *) (door->line ? door->line-lines : -1); + continue; + } + + if (th->function == T_MoveFloor) + { + floormove_t *floor; + *save_p++ = tc_floor; + PADSAVEP(); + floor = (floormove_t *)save_p; + memcpy (floor, th, sizeof(*floor)); + save_p += sizeof(*floor); + floor->sector = (sector_t *)(floor->sector - sectors); + continue; + } + + if (th->function == T_PlatRaise) + { + plat_t *plat; + plat: // killough 2/14/98: added fix for original plat height above + *save_p++ = tc_plat; + PADSAVEP(); + plat = (plat_t *)save_p; + memcpy (plat, th, sizeof(*plat)); + save_p += sizeof(*plat); + plat->sector = (sector_t *)(plat->sector - sectors); + continue; + } + + if (th->function == T_LightFlash) + { + lightflash_t *flash; + *save_p++ = tc_flash; + PADSAVEP(); + flash = (lightflash_t *)save_p; + memcpy (flash, th, sizeof(*flash)); + save_p += sizeof(*flash); + flash->sector = (sector_t *)(flash->sector - sectors); + continue; + } + + if (th->function == T_StrobeFlash) + { + strobe_t *strobe; + *save_p++ = tc_strobe; + PADSAVEP(); + strobe = (strobe_t *)save_p; + memcpy (strobe, th, sizeof(*strobe)); + save_p += sizeof(*strobe); + strobe->sector = (sector_t *)(strobe->sector - sectors); + continue; + } + + if (th->function == T_Glow) + { + glow_t *glow; + *save_p++ = tc_glow; + PADSAVEP(); + glow = (glow_t *)save_p; + memcpy (glow, th, sizeof(*glow)); + save_p += sizeof(*glow); + glow->sector = (sector_t *)(glow->sector - sectors); + continue; + } + + // killough 10/4/98: save flickers + if (th->function == T_FireFlicker) + { + fireflicker_t *flicker; + *save_p++ = tc_flicker; + PADSAVEP(); + flicker = (fireflicker_t *)save_p; + memcpy (flicker, th, sizeof(*flicker)); + save_p += sizeof(*flicker); + flicker->sector = (sector_t *)(flicker->sector - sectors); + continue; + } + + //jff 2/22/98 new case for elevators + if (th->function == T_MoveElevator) + { + elevator_t *elevator; //jff 2/22/98 + *save_p++ = tc_elevator; + PADSAVEP(); + elevator = (elevator_t *)save_p; + memcpy (elevator, th, sizeof(*elevator)); + save_p += sizeof(*elevator); + elevator->sector = (sector_t *)(elevator->sector - sectors); + continue; + } + + // killough 3/7/98: Scroll effect thinkers + if (th->function == T_Scroll) + { + *save_p++ = tc_scroll; + memcpy (save_p, th, sizeof(scroll_t)); + save_p += sizeof(scroll_t); + continue; + } + + // phares 3/22/98: Push/Pull effect thinkers + + if (th->function == T_Pusher) + { + *save_p++ = tc_pusher; + memcpy (save_p, th, sizeof(pusher_t)); + save_p += sizeof(pusher_t); + continue; + } + } + + // add a terminating marker + *save_p++ = tc_endspecials; +} + + +// +// P_UnArchiveSpecials +// +void P_UnArchiveSpecials (void) +{ + byte tclass; + + // read in saved thinkers + while ((tclass = *save_p++) != tc_endspecials) // killough 2/14/98 + switch (tclass) + { + case tc_ceiling: + PADSAVEP(); + { + ceiling_t *ceiling = Z_Malloc (sizeof(*ceiling), PU_LEVEL, NULL); + memcpy (ceiling, save_p, sizeof(*ceiling)); + save_p += sizeof(*ceiling); + ceiling->sector = §ors[(int)ceiling->sector]; + ceiling->sector->ceilingdata = ceiling; //jff 2/22/98 + + if (ceiling->thinker.function) + ceiling->thinker.function = T_MoveCeiling; + + P_AddThinker (&ceiling->thinker); + P_AddActiveCeiling(ceiling); + break; + } + + case tc_door: + PADSAVEP(); + { + vldoor_t *door = Z_Malloc (sizeof(*door), PU_LEVEL, NULL); + memcpy (door, save_p, sizeof(*door)); + save_p += sizeof(*door); + door->sector = §ors[(int)door->sector]; + + //jff 1/31/98 unarchive line remembered by door as well + door->line = (int)door->line!=-1? &lines[(int)door->line] : NULL; + + door->sector->ceilingdata = door; //jff 2/22/98 + door->thinker.function = T_VerticalDoor; + P_AddThinker (&door->thinker); + break; + } + + case tc_floor: + PADSAVEP(); + { + floormove_t *floor = Z_Malloc (sizeof(*floor), PU_LEVEL, NULL); + memcpy (floor, save_p, sizeof(*floor)); + save_p += sizeof(*floor); + floor->sector = §ors[(int)floor->sector]; + floor->sector->floordata = floor; //jff 2/22/98 + floor->thinker.function = T_MoveFloor; + P_AddThinker (&floor->thinker); + break; + } + + case tc_plat: + PADSAVEP(); + { + plat_t *plat = Z_Malloc (sizeof(*plat), PU_LEVEL, NULL); + memcpy (plat, save_p, sizeof(*plat)); + save_p += sizeof(*plat); + plat->sector = §ors[(int)plat->sector]; + plat->sector->floordata = plat; //jff 2/22/98 + + if (plat->thinker.function) + plat->thinker.function = T_PlatRaise; + + P_AddThinker (&plat->thinker); + P_AddActivePlat(plat); + break; + } + + case tc_flash: + PADSAVEP(); + { + lightflash_t *flash = Z_Malloc (sizeof(*flash), PU_LEVEL, NULL); + memcpy (flash, save_p, sizeof(*flash)); + save_p += sizeof(*flash); + flash->sector = §ors[(int)flash->sector]; + flash->thinker.function = T_LightFlash; + P_AddThinker (&flash->thinker); + break; + } + + case tc_strobe: + PADSAVEP(); + { + strobe_t *strobe = Z_Malloc (sizeof(*strobe), PU_LEVEL, NULL); + memcpy (strobe, save_p, sizeof(*strobe)); + save_p += sizeof(*strobe); + strobe->sector = §ors[(int)strobe->sector]; + strobe->thinker.function = T_StrobeFlash; + P_AddThinker (&strobe->thinker); + break; + } + + case tc_glow: + PADSAVEP(); + { + glow_t *glow = Z_Malloc (sizeof(*glow), PU_LEVEL, NULL); + memcpy (glow, save_p, sizeof(*glow)); + save_p += sizeof(*glow); + glow->sector = §ors[(int)glow->sector]; + glow->thinker.function = T_Glow; + P_AddThinker (&glow->thinker); + break; + } + + case tc_flicker: // killough 10/4/98 + PADSAVEP(); + { + fireflicker_t *flicker = Z_Malloc (sizeof(*flicker), PU_LEVEL, NULL); + memcpy (flicker, save_p, sizeof(*flicker)); + save_p += sizeof(*flicker); + flicker->sector = §ors[(int)flicker->sector]; + flicker->thinker.function = T_FireFlicker; + P_AddThinker (&flicker->thinker); + break; + } + + //jff 2/22/98 new case for elevators + case tc_elevator: + PADSAVEP(); + { + elevator_t *elevator = Z_Malloc (sizeof(*elevator), PU_LEVEL, NULL); + memcpy (elevator, save_p, sizeof(*elevator)); + save_p += sizeof(*elevator); + elevator->sector = §ors[(int)elevator->sector]; + elevator->sector->floordata = elevator; //jff 2/22/98 + elevator->sector->ceilingdata = elevator; //jff 2/22/98 + elevator->thinker.function = T_MoveElevator; + P_AddThinker (&elevator->thinker); + break; + } + + case tc_scroll: // killough 3/7/98: scroll effect thinkers + { + scroll_t *scroll = Z_Malloc (sizeof(scroll_t), PU_LEVEL, NULL); + memcpy (scroll, save_p, sizeof(scroll_t)); + save_p += sizeof(scroll_t); + scroll->thinker.function = T_Scroll; + P_AddThinker(&scroll->thinker); + break; + } + + case tc_pusher: // phares 3/22/98: new Push/Pull effect thinkers + { + pusher_t *pusher = Z_Malloc (sizeof(pusher_t), PU_LEVEL, NULL); + memcpy (pusher, save_p, sizeof(pusher_t)); + save_p += sizeof(pusher_t); + pusher->thinker.function = T_Pusher; + pusher->source = P_GetPushThing(pusher->affectee); + P_AddThinker(&pusher->thinker); + break; + } + + default: + I_Error("P_UnarchiveSpecials: Unknown tclass %i in savegame", tclass); + } +} + +// killough 2/16/98: save/restore random number generator state information + +void P_ArchiveRNG(void) +{ + CheckSaveGame(sizeof rng); + memcpy(save_p, &rng, sizeof rng); + save_p += sizeof rng; +} + +void P_UnArchiveRNG(void) +{ + memcpy(&rng, save_p, sizeof rng); + save_p += sizeof rng; +} + +// killough 2/22/98: Save/restore automap state +// killough 2/22/98: Save/restore automap state +void P_ArchiveMap(void) +{ + int zero = 0, one = 1; + CheckSaveGame(2 * sizeof zero + sizeof markpointnum + + markpointnum * sizeof *markpoints + + sizeof automapmode + sizeof one); + + memcpy(save_p, &automapmode, sizeof automapmode); + save_p += sizeof automapmode; + memcpy(save_p, &one, sizeof one); // CPhipps - used to be viewactive, now + save_p += sizeof one; // that's worked out locally by D_Display + memcpy(save_p, &zero, sizeof zero); // CPhipps - used to be followplayer + save_p += sizeof zero; // that is now part of automapmode + memcpy(save_p, &zero, sizeof zero); // CPhipps - used to be automap_grid, ditto + save_p += sizeof zero; + memcpy(save_p, &markpointnum, sizeof markpointnum); + save_p += sizeof markpointnum; + + if (markpointnum) + { + memcpy(save_p, markpoints, sizeof *markpoints * markpointnum); + save_p += markpointnum * sizeof *markpoints; + } +} + +void P_UnArchiveMap(void) +{ + int unused; + memcpy(&automapmode, save_p, sizeof automapmode); + save_p += sizeof automapmode; + memcpy(&unused, save_p, sizeof unused); + save_p += sizeof unused; + memcpy(&unused, save_p, sizeof unused); + save_p += sizeof unused; + memcpy(&unused, save_p, sizeof unused); + save_p += sizeof unused; + + if (automapmode & am_active) + AM_Start(); + + memcpy(&markpointnum, save_p, sizeof markpointnum); + save_p += sizeof markpointnum; + + if (markpointnum) + { + while (markpointnum >= markpointnum_max) + markpoints = realloc(markpoints, sizeof *markpoints * + (markpointnum_max = markpointnum_max ? markpointnum_max*2 : 16)); + memcpy(markpoints, save_p, markpointnum * sizeof *markpoints); + save_p += markpointnum * sizeof *markpoints; + } +} + diff --git a/common/prboom/p_saveg.h b/common/prboom/p_saveg.h new file mode 100755 index 0000000..dd986cf --- /dev/null +++ b/common/prboom/p_saveg.h @@ -0,0 +1,66 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Savegame I/O, archiving, persistence. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __P_SAVEG__ +#define __P_SAVEG__ + +#ifdef __GNUG__ +#pragma interface +#endif + +/* Persistent storage/archiving. + * These are the load / save game routines. */ +void P_ArchivePlayers(void); +void P_UnArchivePlayers(void); +void P_ArchiveWorld(void); +void P_UnArchiveWorld(void); +void P_ArchiveThinkers(void); +void P_UnArchiveThinkers(void); +void P_ArchiveSpecials(void); +void P_UnArchiveSpecials(void); +void P_ThinkerToIndex(void); /* phares 9/13/98: save soundtarget in savegame */ +void P_IndexToThinker(void); /* phares 9/13/98: save soundtarget in savegame */ + +/* 1/18/98 killough: add RNG info to savegame */ +void P_ArchiveRNG(void); +void P_UnArchiveRNG(void); + +/* 2/21/98 killough: add automap info to savegame */ +void P_ArchiveMap(void); +void P_UnArchiveMap(void); + +extern byte *save_p; +void CheckSaveGame(size_t,const char*, int); /* killough */ +#define CheckSaveGame(a) (CheckSaveGame)(a, __FILE__, __LINE__) + +#endif diff --git a/common/prboom/p_setup.c b/common/prboom/p_setup.c new file mode 100755 index 0000000..89eaeaa --- /dev/null +++ b/common/prboom/p_setup.c @@ -0,0 +1,1688 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Do all the WAD I/O, get map description, + * set up initial state and misc. LUTs. + * + *-----------------------------------------------------------------------------*/ + +#include + +#include "doomstat.h" +#include "m_bbox.h" +#include "m_argv.h" +#include "g_game.h" +#include "w_wad.h" +#include "r_main.h" +#include "r_things.h" +#include "p_maputl.h" +#include "p_map.h" +#include "p_setup.h" +#include "p_spec.h" +#include "p_tick.h" +#include "p_enemy.h" +#include "s_sound.h" +#include "lprintf.h" //jff 10/6/98 for debug outputs +#include "v_video.h" +#include "r_demo.h" +#include "r_fps.h" + +// +// MAP related Lookup tables. +// Store VERTEXES, LINEDEFS, SIDEDEFS, etc. +// + +int numvertexes; +vertex_t *vertexes; + +int numsegs; +seg_t *segs; + +int numsectors; +sector_t *sectors; + +int numsubsectors; +subsector_t *subsectors; + +int numnodes; +node_t *nodes; + +int numlines; +line_t *lines; + +int numsides; +side_t *sides; + + +//////////////////////////////////////////////////////////////////////////////////////////// +// figgi 08/21/00 -- constants and globals for glBsp support +#define gNd2 0x32644E67 // figgi -- suppport for new GL_VERT format v2.0 +#define gNd3 0x33644E67 +#define gNd4 0x34644E67 +#define gNd5 0x35644E67 +#define ZNOD 0x444F4E5A +#define ZGLN 0x4E4C475A +#define GL_VERT_OFFSET 4 + +int firstglvertex = 0; +int nodesVersion = 0; +boolean forceOldBsp = false; + +// figgi 08/21/00 -- glSegs +typedef struct +{ + unsigned short v1; // start vertex (16 bit) + unsigned short v2; // end vertex (16 bit) + unsigned short linedef; // linedef, or -1 for minisegs + short side; // side on linedef: 0 for right, 1 for left + unsigned short partner; // corresponding partner seg, or -1 on one-sided walls +} glseg_t; + +// fixed 32 bit gl_vert format v2.0+ (glBsp 1.91) +typedef struct +{ + fixed_t x,y; +} mapglvertex_t; + +enum +{ + ML_GL_LABEL=0, // A separator name, GL_ExMx or GL_MAPxx + ML_GL_VERTS, // Extra Vertices + ML_GL_SEGS, // Segs, from linedefs & minisegs + ML_GL_SSECT, // SubSectors, list of segs + ML_GL_NODES // GL BSP nodes +}; +//////////////////////////////////////////////////////////////////////////////////////////// + + +// BLOCKMAP +// Created from axis aligned bounding box +// of the map, a rectangular array of +// blocks of size ... +// Used to speed up collision detection +// by spatial subdivision in 2D. +// +// Blockmap size. + +int bmapwidth, bmapheight; // size in mapblocks + +// killough 3/1/98: remove blockmap limit internally: +long *blockmap; // was short -- killough + +// offsets in blockmap are from here +long *blockmaplump; // was short -- killough + +fixed_t bmaporgx, bmaporgy; // origin of block map + +mobj_t **blocklinks; // for thing chains + +// +// REJECT +// For fast sight rejection. +// Speeds up enemy AI by skipping detailed +// LineOf Sight calculation. +// Without the special effect, this could +// be used as a PVS lookup as well. +// + +static int rejectlump = -1;// cph - store reject lump num if cached +const byte *rejectmatrix; // cph - const* + +// Maintain single and multi player starting spots. + +// 1/11/98 killough: Remove limit on deathmatch starts +mapthing_t *deathmatchstarts; // killough +size_t num_deathmatchstarts; // killough + +mapthing_t *deathmatch_p; +mapthing_t playerstarts[MAXPLAYERS]; + +// +// P_CheckForZDoomNodes +// + +static boolean P_CheckForZDoomNodes(int lumpnum, int gl_lumpnum) +{ + const void *data; + + data = W_CacheLumpNum(lumpnum + ML_NODES); + if (*(const int *)data == ZNOD) + I_Error("P_CheckForZDoomNodes: ZDoom nodes not supported yet"); + + data = W_CacheLumpNum(lumpnum + ML_SSECTORS); + if (*(const int *)data == ZGLN) + I_Error("P_CheckForZDoomNodes: ZDoom GL nodes not supported yet"); + + return false; +} + +// +// P_GetNodesVersion +// + +static void P_GetNodesVersion(int lumpnum, int gl_lumpnum) +{ + const void *data; + + data = W_CacheLumpNum(gl_lumpnum+ML_GL_VERTS); + if ( (gl_lumpnum > lumpnum) && (forceOldBsp == false) && (compatibility_level >= prboom_2_compatibility) ) { + if (*(const int *)data == gNd2) { + data = W_CacheLumpNum(gl_lumpnum+ML_GL_SEGS); + if (*(const int *)data == gNd3) { + nodesVersion = gNd3; + lprintf(LO_DEBUG, "P_GetNodesVersion: found version 3 nodes\n"); + I_Error("P_GetNodesVersion: version 3 nodes not supported\n"); + } else { + nodesVersion = gNd2; + lprintf(LO_DEBUG, "P_GetNodesVersion: found version 2 nodes\n"); + } + } + if (*(const int *)data == gNd4) { + nodesVersion = gNd4; + lprintf(LO_DEBUG, "P_GetNodesVersion: found version 4 nodes\n"); + I_Error("P_GetNodesVersion: version 4 nodes not supported\n"); + } + if (*(const int *)data == gNd5) { + nodesVersion = gNd5; + lprintf(LO_DEBUG, "P_GetNodesVersion: found version 5 nodes\n"); + I_Error("P_GetNodesVersion: version 5 nodes not supported\n"); + } + } else { + nodesVersion = 0; + lprintf(LO_DEBUG,"P_GetNodesVersion: using normal BSP nodes\n"); + if (P_CheckForZDoomNodes(lumpnum, gl_lumpnum)) + I_Error("P_GetNodesVersion: ZDoom nodes not supported yet"); + } +} + +// +// P_LoadVertexes +// +// killough 5/3/98: reformatted, cleaned up +// +static void P_LoadVertexes (int lump) +{ + const mapvertex_t *data; // cph - const + int i; + + // Determine number of lumps: + // total lump length / vertex record length. + numvertexes = W_LumpLength(lump) / sizeof(mapvertex_t); + + // Allocate zone memory for buffer. + vertexes = Z_Malloc(numvertexes*sizeof(vertex_t),PU_LEVEL,0); + + // Load data into cache. + // cph 2006/07/29 - cast to mapvertex_t here, making the loop below much neater + data = (const mapvertex_t *)W_CacheLumpNum(lump); + + // Copy and convert vertex coordinates, + // internal representation as fixed. + for (i=0; i= 0) // check for glVertices + { + gldata = W_CacheLumpNum(gllump); + + if (nodesVersion == gNd2) // 32 bit GL_VERT format (16.16 fixed) + { + const mapglvertex_t* mgl; + + numvertexes += (W_LumpLength(gllump) - GL_VERT_OFFSET)/sizeof(mapglvertex_t); + vertexes = Z_Malloc (numvertexes*sizeof(vertex_t),PU_LEVEL,0); + mgl = (const mapglvertex_t *) (gldata + GL_VERT_OFFSET); + + for (i = firstglvertex; i < numvertexes; i++) + { + vertexes[i].x = mgl->x; + vertexes[i].y = mgl->y; + mgl++; + } + } + else + { + numvertexes += W_LumpLength(gllump)/sizeof(mapvertex_t); + vertexes = Z_Malloc (numvertexes*sizeof(vertex_t),PU_LEVEL,0); + ml = (const mapvertex_t *)gldata; + + for (i = firstglvertex; i < numvertexes; i++) + { + vertexes[i].x = SHORT(ml->x)<y)<x)<y)<x - v2->x) / (float)FRACUNIT; + b = (float)(v1->y - v2->y) / (float)FRACUNIT; + r = (int)(sqrt(a*a+b*b) * (float)FRACUNIT); + return r; +} + + + +// +// P_LoadSegs +// +// killough 5/3/98: reformatted, cleaned up + +static void P_LoadSegs (int lump) +{ + int i; + const mapseg_t *data; // cph - const + + numsegs = W_LumpLength(lump) / sizeof(mapseg_t); + segs = Z_Calloc(numsegs,sizeof(seg_t),PU_LEVEL,0); + data = (const mapseg_t *)W_CacheLumpNum(lump); // cph - wad lump handling updated + + if ((!data) || (!numsegs)) + I_Error("P_LoadSegs: no segs in level"); + + for (i=0; iiSegID = i; // proff 11/05/2000: needed for OpenGL + + v1 = (unsigned short)SHORT(ml->v1); + v2 = (unsigned short)SHORT(ml->v2); + li->v1 = &vertexes[v1]; + li->v2 = &vertexes[v2]; + + li->miniseg = false; // figgi -- there are no minisegs in classic BSP nodes + li->length = GetDistance(li->v2->x - li->v1->x, li->v2->y - li->v1->y); + li->angle = (SHORT(ml->angle))<<16; + li->offset =(SHORT(ml->offset))<<16; + linedef = (unsigned short)SHORT(ml->linedef); + ldef = &lines[linedef]; + li->linedef = ldef; + side = SHORT(ml->side); + li->sidedef = &sides[ldef->sidenum[side]]; + + /* cph 2006/09/30 - our frontsector can be the second side of the + * linedef, so must check for NO_INDEX in case we are incorrectly + * referencing the back of a 1S line */ + if (ldef->sidenum[side] != NO_INDEX) + li->frontsector = sides[ldef->sidenum[side]].sector; + else { + li->frontsector = 0; + lprintf(LO_WARN, "P_LoadSegs: front of seg %i has no sidedef\n", i); + } + + if (ldef->flags & ML_TWOSIDED && ldef->sidenum[side^1]!=NO_INDEX) + li->backsector = sides[ldef->sidenum[side^1]].sector; + else + li->backsector = 0; + } + + W_UnlockLumpNum(lump); // cph - release the data +} + + + +/******************************************* + * Name : P_LoadGLSegs * + * created : 08/13/00 * + * modified : 09/18/00, adapted for PrBoom * + * author : figgi * + * what : support for gl nodes * + *******************************************/ +static void P_LoadGLSegs(int lump) +{ + int i; + const glseg_t *ml; + line_t *ldef; + + numsegs = W_LumpLength(lump) / sizeof(glseg_t); + segs = Z_Malloc(numsegs * sizeof(seg_t), PU_LEVEL, 0); + memset(segs, 0, numsegs * sizeof(seg_t)); + ml = (const glseg_t*)W_CacheLumpNum(lump); + + if ((!ml) || (!numsegs)) + I_Error("P_LoadGLSegs: no glsegs in level"); + + for(i = 0; i < numsegs; i++) + { // check for gl-vertices + segs[i].v1 = &vertexes[checkGLVertex(SHORT(ml->v1))]; + segs[i].v2 = &vertexes[checkGLVertex(SHORT(ml->v2))]; + segs[i].iSegID = i; + + if(ml->linedef != (unsigned short)-1) // skip minisegs + { + ldef = &lines[ml->linedef]; + segs[i].linedef = ldef; + segs[i].miniseg = false; + segs[i].angle = R_PointToAngle2(segs[i].v1->x,segs[i].v1->y,segs[i].v2->x,segs[i].v2->y); + + segs[i].sidedef = &sides[ldef->sidenum[ml->side]]; + segs[i].length = GetDistance(segs[i].v2->x - segs[i].v1->x, segs[i].v2->y - segs[i].v1->y); + segs[i].frontsector = sides[ldef->sidenum[ml->side]].sector; + if (ldef->flags & ML_TWOSIDED) + segs[i].backsector = sides[ldef->sidenum[ml->side^1]].sector; + else + segs[i].backsector = 0; + + if (ml->side) + segs[i].offset = GetOffset(segs[i].v1, ldef->v2); + else + segs[i].offset = GetOffset(segs[i].v1, ldef->v1); + } + else + { + segs[i].miniseg = true; + segs[i].angle = 0; + segs[i].offset = 0; + segs[i].length = 0; + segs[i].linedef = NULL; + segs[i].sidedef = NULL; + segs[i].frontsector = NULL; + segs[i].backsector = NULL; + } + ml++; + } + W_UnlockLumpNum(lump); +} + +// +// P_LoadSubsectors +// +// killough 5/3/98: reformatted, cleaned up + +static void P_LoadSubsectors (int lump) +{ + /* cph 2006/07/29 - make data a const mapsubsector_t *, so the loop below is simpler & gives no constness warnings */ + const mapsubsector_t *data; + int i; + + numsubsectors = W_LumpLength (lump) / sizeof(mapsubsector_t); + subsectors = Z_Calloc(numsubsectors,sizeof(subsector_t),PU_LEVEL,0); + data = (const mapsubsector_t *)W_CacheLumpNum(lump); + + if ((!data) || (!numsubsectors)) + I_Error("P_LoadSubsectors: no subsectors in level"); + + for (i=0; iiSectorID=i; // proff 04/05/2000: needed for OpenGL + ss->floorheight = SHORT(ms->floorheight)<ceilingheight = SHORT(ms->ceilingheight)<floorpic = R_FlatNumForName(ms->floorpic); + ss->ceilingpic = R_FlatNumForName(ms->ceilingpic); + ss->lightlevel = SHORT(ms->lightlevel); + ss->special = SHORT(ms->special); + ss->oldspecial = SHORT(ms->special); + ss->tag = SHORT(ms->tag); + ss->thinglist = NULL; + ss->touching_thinglist = NULL; // phares 3/14/98 + + ss->nextsec = -1; //jff 2/26/98 add fields to support locking out + ss->prevsec = -1; // stair retriggering until build completes + + // killough 3/7/98: + ss->floor_xoffs = 0; + ss->floor_yoffs = 0; // floor and ceiling flats offsets + ss->ceiling_xoffs = 0; + ss->ceiling_yoffs = 0; + ss->heightsec = -1; // sector used to get floor and ceiling height + ss->floorlightsec = -1; // sector used to get floor lighting + // killough 3/7/98: end changes + + // killough 4/11/98 sector used to get ceiling lighting: + ss->ceilinglightsec = -1; + + // killough 4/4/98: colormaps: + ss->bottommap = ss->midmap = ss->topmap = 0; + + // killough 10/98: sky textures coming from sidedefs: + ss->sky = 0; + } + + W_UnlockLumpNum(lump); // cph - release the data +} + + +// +// P_LoadNodes +// +// killough 5/3/98: reformatted, cleaned up + +static void P_LoadNodes (int lump) +{ + const byte *data; // cph - const* + int i; + + numnodes = W_LumpLength (lump) / sizeof(mapnode_t); + nodes = Z_Malloc (numnodes*sizeof(node_t),PU_LEVEL,0); + data = W_CacheLumpNum (lump); // cph - wad lump handling updated + + if ((!data) || (!numnodes)) + { + // allow trivial maps + if (numsubsectors == 1) + lprintf(LO_INFO, + "P_LoadNodes: trivial map (no nodes, one subsector)\n"); + else + I_Error("P_LoadNodes: no nodes in level"); + } + + for (i=0; ix = SHORT(mn->x)<y = SHORT(mn->y)<dx = SHORT(mn->dx)<dy = SHORT(mn->dy)<children[j] = SHORT(mn->children[j]); + for (k=0 ; k<4 ; k++) + no->bbox[j][k] = SHORT(mn->bbox[j][k])<flags = (unsigned short)SHORT(mld->flags); + ld->special = SHORT(mld->special); + ld->tag = SHORT(mld->tag); + v1 = ld->v1 = &vertexes[(unsigned short)SHORT(mld->v1)]; + v2 = ld->v2 = &vertexes[(unsigned short)SHORT(mld->v2)]; + ld->dx = v2->x - v1->x; + ld->dy = v2->y - v1->y; + + ld->tranlump = -1; // killough 4/11/98: no translucency by default + + ld->slopetype = !ld->dx ? ST_VERTICAL : !ld->dy ? ST_HORIZONTAL : + FixedDiv(ld->dy, ld->dx) > 0 ? ST_POSITIVE : ST_NEGATIVE; + + if (v1->x < v2->x) + { + ld->bbox[BOXLEFT] = v1->x; + ld->bbox[BOXRIGHT] = v2->x; + } + else + { + ld->bbox[BOXLEFT] = v2->x; + ld->bbox[BOXRIGHT] = v1->x; + } + if (v1->y < v2->y) + { + ld->bbox[BOXBOTTOM] = v1->y; + ld->bbox[BOXTOP] = v2->y; + } + else + { + ld->bbox[BOXBOTTOM] = v2->y; + ld->bbox[BOXTOP] = v1->y; + } + + /* calculate sound origin of line to be its midpoint */ + //e6y: fix sound origin for large levels + // no need for comp_sound test, these are only used when comp_sound = 0 + ld->soundorg.x = ld->bbox[BOXLEFT] / 2 + ld->bbox[BOXRIGHT] / 2; + ld->soundorg.y = ld->bbox[BOXTOP] / 2 + ld->bbox[BOXBOTTOM] / 2; + + ld->iLineID=i; // proff 04/05/2000: needed for OpenGL + ld->sidenum[0] = SHORT(mld->sidenum[0]); + ld->sidenum[1] = SHORT(mld->sidenum[1]); + + { + /* cph 2006/09/30 - fix sidedef errors right away. + * cph 2002/07/20 - these errors are fatal if not fixed, so apply them + * in compatibility mode - a desync is better than a crash! */ + int j; + + for (j=0; j < 2; j++) + { + if (ld->sidenum[j] != NO_INDEX && ld->sidenum[j] >= numsides) { + ld->sidenum[j] = NO_INDEX; + lprintf(LO_WARN, "P_LoadLineDefs: linedef %d has out-of-range sidedef number\n",numlines-i-1); + } + } + + // killough 11/98: fix common wad errors (missing sidedefs): + + if (ld->sidenum[0] == NO_INDEX) { + ld->sidenum[0] = 0; // Substitute dummy sidedef for missing right side + // cph - print a warning about the bug + lprintf(LO_WARN, "P_LoadLineDefs: linedef %d missing first sidedef\n",numlines-i-1); + } + + if ((ld->sidenum[1] == NO_INDEX) && (ld->flags & ML_TWOSIDED)) { + ld->flags &= ~ML_TWOSIDED; // Clear 2s flag for missing left side + // cph - print a warning about the bug + lprintf(LO_WARN, "P_LoadLineDefs: linedef %d has two-sided flag set, but no second sidedef\n",numlines-i-1); + } + } + + // killough 4/4/98: support special sidedef interpretation below + if (ld->sidenum[0] != NO_INDEX && ld->special) + sides[*ld->sidenum].special = ld->special; + } + + W_UnlockLumpNum(lump); // cph - release the lump +} + +// killough 4/4/98: delay using sidedefs until they are loaded +// killough 5/3/98: reformatted, cleaned up + +static void P_LoadLineDefs2(int lump) +{ + int i = numlines; + register line_t *ld = lines; + for (;i--;ld++) + { + ld->frontsector = sides[ld->sidenum[0]].sector; //e6y: Can't be NO_INDEX here + ld->backsector = ld->sidenum[1]!=NO_INDEX ? sides[ld->sidenum[1]].sector : 0; + switch (ld->special) + { // killough 4/11/98: handle special types + int thelump, j; + + case 260: // killough 4/11/98: translucent 2s textures + thelump = sides[*ld->sidenum].special; // translucency from sidedef + if (!ld->tag) // if tag==0, + ld->tranlump = thelump; // affect this linedef only + else + for (j=0;jtag) // affect all matching linedefs + lines[j].tranlump = thelump; + break; + } + } +} + +// +// P_LoadSideDefs +// +// killough 4/4/98: split into two functions + +static void P_LoadSideDefs (int lump) +{ + numsides = W_LumpLength(lump) / sizeof(mapsidedef_t); + sides = Z_Calloc(numsides,sizeof(side_t),PU_LEVEL,0); +} + +// killough 4/4/98: delay using texture names until +// after linedefs are loaded, to allow overloading. +// killough 5/3/98: reformatted, cleaned up + +static void P_LoadSideDefs2(int lump) +{ + const byte *data = W_CacheLumpNum(lump); // cph - const*, wad lump handling updated + int i; + + for (i=0; itextureoffset = SHORT(msd->textureoffset)<rowoffset = SHORT(msd->rowoffset)<sector); + if (sector_num >= numsectors) { + lprintf(LO_WARN,"P_LoadSideDefs2: sidedef %i has out-of-range sector num %u\n", i, sector_num); + sector_num = 0; + } + sd->sector = sec = §ors[sector_num]; + } + + // killough 4/4/98: allow sidedef texture names to be overloaded + // killough 4/11/98: refined to allow colormaps to work as wall + // textures if invalid as colormaps but valid as textures. + switch (sd->special) + { + case 242: // variable colormap via 242 linedef + sd->bottomtexture = + (sec->bottommap = R_ColormapNumForName(msd->bottomtexture)) < 0 ? + sec->bottommap = 0, R_TextureNumForName(msd->bottomtexture): 0 ; + sd->midtexture = + (sec->midmap = R_ColormapNumForName(msd->midtexture)) < 0 ? + sec->midmap = 0, R_TextureNumForName(msd->midtexture) : 0 ; + sd->toptexture = + (sec->topmap = R_ColormapNumForName(msd->toptexture)) < 0 ? + sec->topmap = 0, R_TextureNumForName(msd->toptexture) : 0 ; + break; + + case 260: // killough 4/11/98: apply translucency to 2s normal texture + sd->midtexture = strncasecmp("TRANMAP", msd->midtexture, 8) ? + (sd->special = W_CheckNumForName(msd->midtexture)) < 0 || + W_LumpLength(sd->special) != 65536 ? + sd->special=0, R_TextureNumForName(msd->midtexture) : + (sd->special++, 0) : (sd->special=0); + sd->toptexture = R_TextureNumForName(msd->toptexture); + sd->bottomtexture = R_TextureNumForName(msd->bottomtexture); + break; + + default: // normal cases + sd->midtexture = R_SafeTextureNumForName(msd->midtexture, i); + sd->toptexture = R_SafeTextureNumForName(msd->toptexture, i); + sd->bottomtexture = R_SafeTextureNumForName(msd->bottomtexture, i); + break; + } + } + + W_UnlockLumpNum(lump); // cph - release the lump +} + +// +// jff 10/6/98 +// New code added to speed up calculation of internal blockmap +// Algorithm is order of nlines*(ncols+nrows) not nlines*ncols*nrows +// + +#define blkshift 7 /* places to shift rel position for cell num */ +#define blkmask ((1<0 + // jff 10/12/98 0 ok with + 1 in rows,cols + +typedef struct linelist_t // type used to list lines in each block +{ + long num; + struct linelist_t *next; +} linelist_t; + +// +// Subroutine to add a line number to a block list +// It simply returns if the line is already in the block +// + +static void AddBlockLine +( + linelist_t **lists, + int *count, + int *done, + int blockno, + long lineno +) +{ + linelist_t *l; + + if (done[blockno]) + return; + + l = malloc(sizeof(linelist_t)); + l->num = lineno; + l->next = lists[blockno]; + lists[blockno] = l; + count[blockno]++; + done[blockno] = 1; +} + +// +// Actually construct the blockmap lump from the level data +// +// This finds the intersection of each linedef with the column and +// row lines at the left and bottom of each blockmap cell. It then +// adds the line to all block lists touching the intersection. +// + +static void P_CreateBlockMap(void) +{ + int xorg,yorg; // blockmap origin (lower left) + int nrows,ncols; // blockmap dimensions + linelist_t **blocklists=NULL; // array of pointers to lists of lines + int *blockcount=NULL; // array of counters of line lists + int *blockdone=NULL; // array keeping track of blocks/line + int NBlocks; // number of cells = nrows*ncols + long linetotal=0; // total length of all blocklists + int i,j; + int map_minx=INT_MAX; // init for map limits search + int map_miny=INT_MAX; + int map_maxx=INT_MIN; + int map_maxy=INT_MIN; + + // scan for map limits, which the blockmap must enclose + + for (i=0;i map_maxx) + map_maxx = t; + if ((t=vertexes[i].y) < map_miny) + map_miny = t; + else if (t > map_maxy) + map_maxy = t; + } + map_minx >>= FRACBITS; // work in map coords, not fixed_t + map_maxx >>= FRACBITS; + map_miny >>= FRACBITS; + map_maxy >>= FRACBITS; + + // set up blockmap area to enclose level plus margin + + xorg = map_minx-blkmargin; + yorg = map_miny-blkmargin; + ncols = (map_maxx+blkmargin-xorg+1+blkmask)>>blkshift; //jff 10/12/98 + nrows = (map_maxy+blkmargin-yorg+1+blkmask)>>blkshift; //+1 needed for + NBlocks = ncols*nrows; //map exactly 1 cell + + // create the array of pointers on NBlocks to blocklists + // also create an array of linelist counts on NBlocks + // finally make an array in which we can mark blocks done per line + + // CPhipps - calloc's + blocklists = calloc(NBlocks,sizeof(linelist_t *)); + blockcount = calloc(NBlocks,sizeof(int)); + blockdone = malloc(NBlocks*sizeof(int)); + + // initialize each blocklist, and enter the trailing -1 in all blocklists + // note the linked list of lines grows backwards + + for (i=0;inum = -1; + blocklists[i]->next = NULL; + blockcount[i]++; + } + + // For each linedef in the wad, determine all blockmap blocks it touches, + // and add the linedef number to the blocklists for those blocks + + for (i=0;ix>>FRACBITS; // lines[i] map coords + int y1 = lines[i].v1->y>>FRACBITS; + int x2 = lines[i].v2->x>>FRACBITS; + int y2 = lines[i].v2->y>>FRACBITS; + int dx = x2-x1; + int dy = y2-y1; + int vert = !dx; // lines[i] slopetype + int horiz = !dy; + int spos = (dx^dy) > 0; + int sneg = (dx^dy) < 0; + int bx,by; // block cell coords + int minx = x1>x2? x2 : x1; // extremal lines[i] coords + int maxx = x1>x2? x1 : x2; + int miny = y1>y2? y2 : y1; + int maxy = y1>y2? y1 : y2; + + // no blocks done for this linedef yet + + memset(blockdone,0,NBlocks*sizeof(int)); + + // The line always belongs to the blocks containing its endpoints + + bx = (x1-xorg)>>blkshift; + by = (y1-yorg)>>blkshift; + AddBlockLine(blocklists,blockcount,blockdone,by*ncols+bx,i); + bx = (x2-xorg)>>blkshift; + by = (y2-yorg)>>blkshift; + AddBlockLine(blocklists,blockcount,blockdone,by*ncols+bx,i); + + + // For each column, see where the line along its left edge, which + // it contains, intersects the Linedef i. Add i to each corresponding + // blocklist. + + if (!vert) // don't interesect vertical lines with columns + { + for (j=0;j>blkshift; // block row number + int yp = (y-yorg)&blkmask; // y position within block + + if (yb<0 || yb>nrows-1) // outside blockmap, continue + continue; + + if (xmaxx) // line doesn't touch column + continue; + + // The cell that contains the intersection point is always added + + AddBlockLine(blocklists,blockcount,blockdone,ncols*yb+j,i); + + // if the intersection is at a corner it depends on the slope + // (and whether the line extends past the intersection) which + // blocks are hit + + if (yp==0) // intersection at a corner + { + if (sneg) // \ - blocks x,y-, x-,y + { + if (yb>0 && miny0 && minx0 && j>0 && minx0 && minx0 && minx>blkshift; // block column number + int xp = (x-xorg)&blkmask; // x position within block + + if (xb<0 || xb>ncols-1) // outside blockmap, continue + continue; + + if (ymaxy) // line doesn't touch row + continue; + + // The cell that contains the intersection point is always added + + AddBlockLine(blocklists,blockcount,blockdone,ncols*j+xb,i); + + // if the intersection is at a corner it depends on the slope + // (and whether the line extends past the intersection) which + // blocks are hit + + if (xp==0) // intersection at a corner + { + if (sneg) // \ - blocks x,y-, x-,y + { + if (j>0 && miny0 && minx0 && miny0 && j>0 && miny0 && minynext; + blockmaplump[offs++] = bl->num; + free(bl); + bl = tmp; + } + } + + // free all temporary storage + + free (blocklists); + free (blockcount); + free (blockdone); +} + +// jff 10/6/98 +// End new code added to speed up calculation of internal blockmap + +// +// P_LoadBlockMap +// +// killough 3/1/98: substantially modified to work +// towards removing blockmap limit (a wad limitation) +// +// killough 3/30/98: Rewritten to remove blockmap limit, +// though current algorithm is brute-force and unoptimal. +// + +static void P_LoadBlockMap (int lump) +{ + long count; + + if (M_CheckParm("-blockmap") || W_LumpLength(lump)<8 || (count = W_LumpLength(lump)/2) >= 0x10000) //e6y + P_CreateBlockMap(); + else + { + long i; + // cph - const*, wad lump handling updated + const short *wadblockmaplump = W_CacheLumpNum(lump); + blockmaplump = Z_Malloc(sizeof(*blockmaplump) * count, PU_LEVEL, 0); + + // killough 3/1/98: Expand wad blockmap into larger internal one, + // by treating all offsets except -1 as unsigned and zero-extending + // them. This potentially doubles the size of blockmaps allowed, + // because Doom originally considered the offsets as always signed. + + blockmaplump[0] = SHORT(wadblockmaplump[0]); + blockmaplump[1] = SHORT(wadblockmaplump[1]); + blockmaplump[2] = (long)(SHORT(wadblockmaplump[2])) & 0xffff; + blockmaplump[3] = (long)(SHORT(wadblockmaplump[3])) & 0xffff; + + for (i=4 ; i= required) + return; // nothing to do + + // allocate a new block and copy the reject table into it; zero the rest + // PU_LEVEL => will be freed on level exit + newreject = Z_Malloc(required, PU_LEVEL, NULL); + rejectmatrix = (const byte *)memmove(newreject, rejectmatrix, length); + memset(newreject + length, 0, required - length); + // unlock the original lump, it is no longer needed + W_UnlockLumpNum(rejectlump); + rejectlump = -1; + + if (demo_compatibility) + { + // merged in RejectOverrunAddInt(), and the 4 calls to it, here + unsigned int rejectpad[4] = { + 0, // size, will be filled in using totallines + 0, // part of the header of a doom.exe z_zone block + 50, // DOOM_CONST_PU_LEVEL + 0x1d4a11 // DOOM_CONST_ZONEID + }; + unsigned int i, pad = 0, *src = rejectpad; + byte *dest = newreject + length; + + rejectpad[0] = ((totallines*4+3)&~3)+24; // doom.exe zone header size + + // copy at most 16 bytes from rejectpad + // emulating a 32-bit, little-endian architecture (can't memmove) + for (i = 0; i < required - length && i < 16; i++) { // 16 hard-coded + if (!(i&3)) // get the next 4 bytes to copy when i=0,4,8,12 + pad = *src++; + *dest++ = pad & 0xff; // store lowest-significant byte + pad >>= 8; // rotate the next byte down + } + } + lprintf(LO_WARN, "P_LoadReject: REJECT too short (%u<%u) - padded\n", + length, required); +} + +// +// P_GroupLines +// Builds sector line lists and subsector sector numbers. +// Finds block bounding boxes for sectors. +// +// killough 5/3/98: reformatted, cleaned up +// cph 18/8/99: rewritten to avoid O(numlines * numsectors) section +// It makes things more complicated, but saves seconds on big levels +// figgi 09/18/00 -- adapted for gl-nodes + +// cph - convenient sub-function +static void P_AddLineToSector(line_t* li, sector_t* sector) +{ + fixed_t *bbox = (void*)sector->blockbox; + + sector->lines[sector->linecount++] = li; + M_AddToBox (bbox, li->v1->x, li->v1->y); + M_AddToBox (bbox, li->v2->x, li->v2->y); +} + +// modified to return totallines (needed by P_LoadReject) +static int P_GroupLines (void) +{ + register line_t *li; + register sector_t *sector; + int i,j, total = numlines; + + // figgi + for (i=0 ; isidedef) + { + subsectors[i].sector = seg->sidedef->sector; + break; + } + seg++; + } + if(subsectors[i].sector == NULL) + I_Error("P_GroupLines: Subsector a part of no sector!\n"); + } + + // count number of lines in each sector + for (i=0,li=lines; ifrontsector->linecount++; + if (li->backsector && li->backsector != li->frontsector) + { + li->backsector->linecount++; + total++; + } + } + + { // allocate line tables for each sector + line_t **linebuffer = Z_Malloc(total*sizeof(line_t *), PU_LEVEL, 0); + + // e6y: REJECT overrun emulation code + // moved to P_LoadReject + + for (i=0, sector = sectors; ilines = linebuffer; + linebuffer += sector->linecount; + sector->linecount = 0; + M_ClearBox(sector->blockbox); + } + } + + // Enter those lines + for (i=0,li=lines; ifrontsector); + if (li->backsector && li->backsector != li->frontsector) + P_AddLineToSector(li, li->backsector); + } + + for (i=0, sector = sectors; iblockbox; // cph - For convenience, so + // I can sue the old code unchanged + int block; + + // set the degenmobj_t to the middle of the bounding box + if (comp[comp_sound]) + { + sector->soundorg.x = (bbox[BOXRIGHT]+bbox[BOXLEFT])/2; + sector->soundorg.y = (bbox[BOXTOP]+bbox[BOXBOTTOM])/2; + } + else + { + //e6y: fix sound origin for large levels + sector->soundorg.x = bbox[BOXRIGHT]/2+bbox[BOXLEFT]/2; + sector->soundorg.y = bbox[BOXTOP]/2+bbox[BOXBOTTOM]/2; + } + + // adjust bounding box to map blocks + block = (bbox[BOXTOP]-bmaporgy+MAXRADIUS)>>MAPBLOCKSHIFT; + block = block >= bmapheight ? bmapheight-1 : block; + sector->blockbox[BOXTOP]=block; + + block = (bbox[BOXBOTTOM]-bmaporgy-MAXRADIUS)>>MAPBLOCKSHIFT; + block = block < 0 ? 0 : block; + sector->blockbox[BOXBOTTOM]=block; + + block = (bbox[BOXRIGHT]-bmaporgx+MAXRADIUS)>>MAPBLOCKSHIFT; + block = block >= bmapwidth ? bmapwidth-1 : block; + sector->blockbox[BOXRIGHT]=block; + + block = (bbox[BOXLEFT]-bmaporgx-MAXRADIUS)>>MAPBLOCKSHIFT; + block = block < 0 ? 0 : block; + sector->blockbox[BOXLEFT]=block; + } + + return total; // this value is needed by the reject overrun emulation code +} + +// +// killough 10/98 +// +// Remove slime trails. +// +// Slime trails are inherent to Doom's coordinate system -- i.e. there is +// nothing that a node builder can do to prevent slime trails ALL of the time, +// because it's a product of the integer coodinate system, and just because +// two lines pass through exact integer coordinates, doesn't necessarily mean +// that they will intersect at integer coordinates. Thus we must allow for +// fractional coordinates if we are to be able to split segs with node lines, +// as a node builder must do when creating a BSP tree. +// +// A wad file does not allow fractional coordinates, so node builders are out +// of luck except that they can try to limit the number of splits (they might +// also be able to detect the degree of roundoff error and try to avoid splits +// with a high degree of roundoff error). But we can use fractional coordinates +// here, inside the engine. It's like the difference between square inches and +// square miles, in terms of granularity. +// +// For each vertex of every seg, check to see whether it's also a vertex of +// the linedef associated with the seg (i.e, it's an endpoint). If it's not +// an endpoint, and it wasn't already moved, move the vertex towards the +// linedef by projecting it using the law of cosines. Formula: +// +// 2 2 2 2 +// dx x0 + dy x1 + dx dy (y0 - y1) dy y0 + dx y1 + dx dy (x0 - x1) +// {---------------------------------, ---------------------------------} +// 2 2 2 2 +// dx + dy dx + dy +// +// (x0,y0) is the vertex being moved, and (x1,y1)-(x1+dx,y1+dy) is the +// reference linedef. +// +// Segs corresponding to orthogonal linedefs (exactly vertical or horizontal +// linedefs), which comprise at least half of all linedefs in most wads, don't +// need to be considered, because they almost never contribute to slime trails +// (because then any roundoff error is parallel to the linedef, which doesn't +// cause slime). Skipping simple orthogonal lines lets the code finish quicker. +// +// Please note: This section of code is not interchangable with TeamTNT's +// code which attempts to fix the same problem. +// +// Firelines (TM) is a Rezistered Trademark of MBF Productions +// + +static void P_RemoveSlimeTrails(void) // killough 10/98 +{ + byte *hit = calloc(1, numvertexes); // Hitlist for vertices + int i; + for (i=0; idx && l->dy) // We can ignore orthogonal lines + { + vertex_t *v = segs[i].v1; + do + if (!hit[v - vertexes]) // If we haven't processed vertex + { + hit[v - vertexes] = 1; // Mark this vertex as processed + if (v != l->v1 && v != l->v2) // Exclude endpoints of linedefs + { // Project the vertex back onto the parent linedef + int_64_t dx2 = (l->dx >> FRACBITS) * (l->dx >> FRACBITS); + int_64_t dy2 = (l->dy >> FRACBITS) * (l->dy >> FRACBITS); + int_64_t dxy = (l->dx >> FRACBITS) * (l->dy >> FRACBITS); + int_64_t s = dx2 + dy2; + int x0 = v->x, y0 = v->y, x1 = l->v1->x, y1 = l->v1->y; + v->x = (int)((dx2 * x0 + dy2 * x1 + dxy * (y0 - y1)) / s); + v->y = (int)((dy2 * y0 + dx2 * y1 + dxy * (x0 - x1)) / s); + } + } // Obsfucated C contest entry: :) + while ((v != segs[i].v2) && (v = segs[i].v2)); + } + } + free(hit); +} + +// +// P_SetupLevel +// +// killough 5/3/98: reformatted, cleaned up + +void P_SetupLevel(int episode, int map, int playermask, skill_t skill) +{ + int i; + char lumpname[9]; + int lumpnum; + + char gl_lumpname[9]; + int gl_lumpnum; + + R_StopAllInterpolations(); + + totallive = totalkills = totalitems = totalsecret = wminfo.maxfrags = 0; + wminfo.partime = 180; + + for (i=0; i 0) + P_LoadVertexes2 (lumpnum+ML_VERTEXES,gl_lumpnum+ML_GL_VERTS); + else + P_LoadVertexes (lumpnum+ML_VERTEXES); + P_LoadSectors (lumpnum+ML_SECTORS); + P_LoadSideDefs (lumpnum+ML_SIDEDEFS); + P_LoadLineDefs (lumpnum+ML_LINEDEFS); + P_LoadSideDefs2 (lumpnum+ML_SIDEDEFS); + P_LoadLineDefs2 (lumpnum+ML_LINEDEFS); + P_LoadBlockMap (lumpnum+ML_BLOCKMAP); + + if (nodesVersion > 0) + { + P_LoadSubsectors(gl_lumpnum + ML_GL_SSECT); + P_LoadNodes(gl_lumpnum + ML_GL_NODES); + P_LoadGLSegs(gl_lumpnum + ML_GL_SEGS); + } + else + { + P_LoadSubsectors(lumpnum + ML_SSECTORS); + P_LoadNodes(lumpnum + ML_NODES); + P_LoadSegs(lumpnum + ML_SEGS); + } + +#else + + P_LoadVertexes (lumpnum+ML_VERTEXES); + P_LoadSectors (lumpnum+ML_SECTORS); + P_LoadSideDefs (lumpnum+ML_SIDEDEFS); // killough 4/4/98 + P_LoadLineDefs (lumpnum+ML_LINEDEFS); // | + P_LoadSideDefs2 (lumpnum+ML_SIDEDEFS); // | + P_LoadLineDefs2 (lumpnum+ML_LINEDEFS); // killough 4/4/98 + P_LoadBlockMap (lumpnum+ML_BLOCKMAP); // killough 3/1/98 + P_LoadSubsectors(lumpnum+ML_SSECTORS); + P_LoadNodes (lumpnum+ML_NODES); + P_LoadSegs (lumpnum+ML_SEGS); + +#endif + + // reject loading and underflow padding separated out into new function + // P_GroupLines modified to return a number the underflow padding needs + P_LoadReject(lumpnum, P_GroupLines()); + + // e6y + // Correction of desync on dv04-423.lmp/dv.wad + // http://www.doomworld.com/vb/showthread.php?s=&postid=627257#post627257 + if (compatibility_level>=lxdoom_1_compatibility || M_CheckParm("-force_remove_slime_trails") > 0) + P_RemoveSlimeTrails(); // killough 10/98: remove slime trails from wad + + // Note: you don't need to clear player queue slots -- + // a much simpler fix is in g_game.c -- killough 10/98 + + bodyqueslot = 0; + + /* cph - reset all multiplayer starts */ + memset(playerstarts,0,sizeof(playerstarts)); + deathmatch_p = deathmatchstarts; + for (i = 0; i < MAXPLAYERS; i++) + players[i].mo = NULL; + + P_MapStart(); + + P_LoadThings(lumpnum+ML_THINGS); + + // if deathmatch, randomly spawn the active players + if (deathmatch) + { + for (i=0; idx ? x == node->x ? 2 : x <= node->x ? node->dy > 0 : node->dy < 0 : + !node->dy ? ( compatibility_level < prboom_4_compatibility ? x : y) == node->y ? 2 : y <= node->y ? node->dx < 0 : node->dx > 0 : + (right = ((y - node->y) >> FRACBITS) * (node->dx >> FRACBITS)) < + (left = ((x - node->x) >> FRACBITS) * (node->dy >> FRACBITS)) ? 0 : + right == left ? 2 : 1; +} + +// +// P_CrossSubsector +// Returns true +// if strace crosses the given subsector successfully. +// +// killough 4/19/98: made static and cleaned up + +static boolean P_CrossSubsector(int num) +{ + seg_t *seg = segs + subsectors[num].firstline; + int count; + fixed_t opentopheight = 0, openbottomheight = 0; + const sector_t *front = NULL, *back = NULL; + +#ifdef RANGECHECK + if (num >= numsubsectors) + I_Error("P_CrossSubsector: ss %i with numss = %i", num, numsubsectors); +#endif + + for (count = subsectors[num].numlines; --count >= 0; seg++) { // check lines + line_t *line = seg->linedef; + divline_t divl; + + if(!line) // figgi -- skip minisegs + continue; + + // allready checked other side? + if (line->validcount == validcount) + continue; + + line->validcount = validcount; + + /* OPTIMIZE: killough 4/20/98: Added quick bounding-box rejection test + * cph - this is causing demo desyncs on original Doom demos. + * Who knows why. Exclude test for those. + */ + if (!demo_compatibility) + if (line->bbox[BOXLEFT ] > los.bbox[BOXRIGHT ] || + line->bbox[BOXRIGHT ] < los.bbox[BOXLEFT ] || + line->bbox[BOXBOTTOM] > los.bbox[BOXTOP ] || + line->bbox[BOXTOP] < los.bbox[BOXBOTTOM]) + continue; + + // cph - do what we can before forced to check intersection + if (line->flags & ML_TWOSIDED) { + + // no wall to block sight with? + if ((front = seg->frontsector)->floorheight == + (back = seg->backsector)->floorheight && + front->ceilingheight == back->ceilingheight) + continue; + + // possible occluder + // because of ceiling height differences + opentopheight = front->ceilingheight < back->ceilingheight ? + front->ceilingheight : back->ceilingheight ; + + // because of floor height differences + openbottomheight = front->floorheight > back->floorheight ? + front->floorheight : back->floorheight ; + + // cph - reject if does not intrude in the z-space of the possible LOS + if ((opentopheight >= los.maxz) && (openbottomheight <= los.minz)) + continue; + } + + { // Forget this line if it doesn't cross the line of sight + const vertex_t *v1,*v2; + + v1 = line->v1; + v2 = line->v2; + + if (P_DivlineSide(v1->x, v1->y, &los.strace) == + P_DivlineSide(v2->x, v2->y, &los.strace)) + continue; + + divl.dx = v2->x - (divl.x = v1->x); + divl.dy = v2->y - (divl.y = v1->y); + + // line isn't crossed? + if (P_DivlineSide(los.strace.x, los.strace.y, &divl) == + P_DivlineSide(los.t2x, los.t2y, &divl)) + continue; + } + + // cph - if bottom >= top or top < minz or bottom > maxz then it must be + // solid wrt this LOS + if (!(line->flags & ML_TWOSIDED) || (openbottomheight >= opentopheight) || + (opentopheight < los.minz) || (openbottomheight > los.maxz)) + return false; + + { // crosses a two sided line + /* cph 2006/07/15 - oops, we missed this in 2.4.0 & .1; + * use P_InterceptVector2 for those compat levels only. */ + fixed_t frac = (compatibility_level == prboom_5_compatibility || compatibility_level == prboom_6_compatibility) ? + P_InterceptVector2(&los.strace, &divl) : + P_InterceptVector(&los.strace, &divl); + + if (front->floorheight != back->floorheight) { + fixed_t slope = FixedDiv(openbottomheight - los.sightzstart , frac); + if (slope > los.bottomslope) + los.bottomslope = slope; + } + + if (front->ceilingheight != back->ceilingheight) + { + fixed_t slope = FixedDiv(opentopheight - los.sightzstart , frac); + if (slope < los.topslope) + los.topslope = slope; + } + + if (los.topslope <= los.bottomslope) + return false; // stop + } + } + // passed the subsector ok + return true; +} + +// +// P_CrossBSPNode +// Returns true +// if strace crosses the given node successfully. +// +// killough 4/20/98: rewritten to remove tail recursion, clean up, and optimize +// cph - Made to use R_PointOnSide instead of P_DivlineSide, since the latter +// could return 2 which was ambigous, and the former is +// better optimised; also removes two casts :-) + +static boolean P_CrossBSPNode_LxDoom(int bspnum) +{ + while (!(bspnum & NF_SUBSECTOR)) + { + register const node_t *bsp = nodes + bspnum; + int side,side2; + side = R_PointOnSide(los.strace.x, los.strace.y, bsp); + side2 = R_PointOnSide(los.t2x, los.t2y, bsp); + if (side == side2) + bspnum = bsp->children[side]; // doesn't touch the other side + else // the partition plane is crossed here + if (!P_CrossBSPNode_LxDoom(bsp->children[side])) + return 0; // cross the starting side + else + bspnum = bsp->children[side^1]; // cross the ending side + } + return P_CrossSubsector(bspnum == -1 ? 0 : bspnum & ~NF_SUBSECTOR); +} + +static boolean P_CrossBSPNode_PrBoom(int bspnum) +{ + while (!(bspnum & NF_SUBSECTOR)) + { + register const node_t *bsp = nodes + bspnum; + int side,side2; + side = P_DivlineSide(los.strace.x,los.strace.y,(const divline_t *)bsp)&1; + side2= P_DivlineSide(los.t2x, los.t2y, (const divline_t *) bsp); + if (side == side2) + bspnum = bsp->children[side]; // doesn't touch the other side + else // the partition plane is crossed here + if (!P_CrossBSPNode_PrBoom(bsp->children[side])) + return 0; // cross the starting side + else + bspnum = bsp->children[side^1]; // cross the ending side + } + return P_CrossSubsector(bspnum == -1 ? 0 : bspnum & ~NF_SUBSECTOR); +} + +/* proff - Moved the compatibility check outside the functions + * this gives a slight speedup + */ +static boolean P_CrossBSPNode(int bspnum) +{ + /* cph - LxDoom used some R_* funcs here */ + if (compatibility_level == lxdoom_1_compatibility) + return P_CrossBSPNode_LxDoom(bspnum); + else + return P_CrossBSPNode_PrBoom(bspnum); +} + +// +// P_CheckSight +// Returns true +// if a straight line between t1 and t2 is unobstructed. +// Uses REJECT. +// +// killough 4/20/98: cleaned up, made to use new LOS struct + +boolean P_CheckSight(mobj_t *t1, mobj_t *t2) +{ + const sector_t *s1 = t1->subsector->sector; + const sector_t *s2 = t2->subsector->sector; + int pnum = (s1-sectors)*numsectors + (s2-sectors); + + // First check for trivial rejection. + // Determine subsector entries in REJECT table. + // + // Check in REJECT table. + + if (rejectmatrix[pnum>>3] & (1 << (pnum&7))) // can't possibly be connected + return false; + + // killough 4/19/98: make fake floors and ceilings block monster view + + if ((s1->heightsec != -1 && + ((t1->z + t1->height <= sectors[s1->heightsec].floorheight && + t2->z >= sectors[s1->heightsec].floorheight) || + (t1->z >= sectors[s1->heightsec].ceilingheight && + t2->z + t1->height <= sectors[s1->heightsec].ceilingheight))) + || + (s2->heightsec != -1 && + ((t2->z + t2->height <= sectors[s2->heightsec].floorheight && + t1->z >= sectors[s2->heightsec].floorheight) || + (t2->z >= sectors[s2->heightsec].ceilingheight && + t1->z + t2->height <= sectors[s2->heightsec].ceilingheight)))) + return false; + + /* killough 11/98: shortcut for melee situations + * same subsector? obviously visible + * cph - compatibility optioned for demo sync, cf HR06-UV.LMP */ + if ((t1->subsector == t2->subsector) && + (compatibility_level >= mbf_compatibility)) + return true; + + // An unobstructed LOS is possible. + // Now look from eyes of t1 to any part of t2. + + validcount++; + + los.topslope = (los.bottomslope = t2->z - (los.sightzstart = + t1->z + t1->height - + (t1->height>>2))) + t2->height; + los.strace.dx = (los.t2x = t2->x) - (los.strace.x = t1->x); + los.strace.dy = (los.t2y = t2->y) - (los.strace.y = t1->y); + + if (t1->x > t2->x) + los.bbox[BOXRIGHT] = t1->x, los.bbox[BOXLEFT] = t2->x; + else + los.bbox[BOXRIGHT] = t2->x, los.bbox[BOXLEFT] = t1->x; + + if (t1->y > t2->y) + los.bbox[BOXTOP] = t1->y, los.bbox[BOXBOTTOM] = t2->y; + else + los.bbox[BOXTOP] = t2->y, los.bbox[BOXBOTTOM] = t1->y; + + /* cph - calculate min and max z of the potential line of sight + * For old demos, we disable this optimisation by setting them to + * the extremes */ + switch (compatibility_level) { + case lxdoom_1_compatibility: + if (los.sightzstart < t2->z) { + los.maxz = t2->z + t2->height; los.minz = los.sightzstart; + } else if (los.sightzstart > t2->z + t2->height) { + los.maxz = los.sightzstart; los.minz = t2->z; + } else { + los.maxz = t2->z + t2->height; los.minz = t2->z; + } + break; + default: + los.maxz = INT_MAX; los.minz = INT_MIN; + } + + // the head node is the last node output + return P_CrossBSPNode(numnodes-1); +} diff --git a/common/prboom/p_spec.c b/common/prboom/p_spec.c new file mode 100755 index 0000000..74d0f9d --- /dev/null +++ b/common/prboom/p_spec.c @@ -0,0 +1,3354 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * -Loads and initializes texture and flat animation sequences + * -Implements utility functions for all linedef/sector special handlers + * -Dispatches walkover and gun line triggers + * -Initializes and implements special sector types + * -Implements donut linedef triggers + * -Initializes and implements BOOM linedef triggers for + * Scrollers/Conveyors + * Friction + * Wind/Current + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" +#include "p_spec.h" +#include "p_tick.h" +#include "p_setup.h" +#include "m_random.h" +#include "d_englsh.h" +#include "m_argv.h" +#include "w_wad.h" +#include "r_main.h" +#include "p_maputl.h" +#include "p_map.h" +#include "g_game.h" +#include "p_inter.h" +#include "s_sound.h" +#include "sounds.h" +#include "m_bbox.h" // phares 3/20/98 +#include "d_deh.h" +#include "r_plane.h" +#include "lprintf.h" + +// +// Animating textures and planes +// There is another anim_t used in wi_stuff, unrelated. +// +typedef struct +{ + boolean istexture; + int picnum; + int basepic; + int numpics; + int speed; + +} anim_t; + +// +// source animation definition +// +// +#ifdef _MSC_VER // proff: This is the same as __attribute__ ((packed)) in GNUC +#pragma pack(push) +#pragma pack(1) +#endif //_MSC_VER + +#if defined(__MWERKS__) +#pragma options align=packed +#endif + +typedef struct +{ + signed char istexture; //jff 3/23/98 make char for comparison // cph - make signed + char endname[9]; // if false, it is a flat + char startname[9]; + int speed; +} PACKEDATTR animdef_t; //jff 3/23/98 pack to read from memory + +#if defined(__MWERKS__) +#pragma options align=reset +#endif + +#ifdef _MSC_VER +#pragma pack(pop) +#endif //_MSC_VER + +#define MAXANIMS 32 // no longer a strict limit -- killough + +static anim_t* lastanim; +static anim_t* anims; // new structure w/o limits -- killough +static size_t maxanims; + +// killough 3/7/98: Initialize generalized scrolling +static void P_SpawnScrollers(void); + +static void P_SpawnFriction(void); // phares 3/16/98 +static void P_SpawnPushers(void); // phares 3/20/98 + +// +// P_InitPicAnims +// +// Load the table of animation definitions, checking for existence of +// the start and end of each frame. If the start doesn't exist the sequence +// is skipped, if the last doesn't exist, BOOM exits. +// +// Wall/Flat animation sequences, defined by name of first and last frame, +// The full animation sequence is given using all lumps between the start +// and end entry, in the order found in the WAD file. +// +// This routine modified to read its data from a predefined lump or +// PWAD lump called ANIMATED rather than a static table in this module to +// allow wad designers to insert or modify animation sequences. +// +// Lump format is an array of byte packed animdef_t structures, terminated +// by a structure with istexture == -1. The lump can be generated from a +// text source file using SWANTBLS.EXE, distributed with the BOOM utils. +// The standard list of switches and animations is contained in the example +// source text file DEFSWANI.DAT also in the BOOM util distribution. +// +// +void P_InitPicAnims (void) +{ + int i; + const animdef_t *animdefs; //jff 3/23/98 pointer to animation lump + int lump = W_GetNumForName("ANIMATED"); // cph - new wad lump handling + // Init animation + + //jff 3/23/98 read from predefined or wad lump instead of table + animdefs = (const animdef_t *)W_CacheLumpNum(lump); + + lastanim = anims; + for (i=0 ; animdefs[i].istexture != -1 ; i++) + { + // 1/11/98 killough -- removed limit by array-doubling + if (lastanim >= anims + maxanims) + { + size_t newmax = maxanims ? maxanims*2 : MAXANIMS; + anims = realloc(anims, newmax*sizeof(*anims)); // killough + lastanim = anims + maxanims; + maxanims = newmax; + } + + if (animdefs[i].istexture) + { + // different episode ? + if (R_CheckTextureNumForName(animdefs[i].startname) == -1) + continue; + + lastanim->picnum = R_TextureNumForName (animdefs[i].endname); + lastanim->basepic = R_TextureNumForName (animdefs[i].startname); + } + else + { + if ((W_CheckNumForName)(animdefs[i].startname, ns_flats) == -1) // killough 4/17/98 + continue; + + lastanim->picnum = R_FlatNumForName (animdefs[i].endname); + lastanim->basepic = R_FlatNumForName (animdefs[i].startname); + } + + lastanim->istexture = animdefs[i].istexture; + lastanim->numpics = lastanim->picnum - lastanim->basepic + 1; + + if (lastanim->numpics < 2) + I_Error ("P_InitPicAnims: bad cycle from %s to %s", + animdefs[i].startname, + animdefs[i].endname); + + lastanim->speed = LONG(animdefs[i].speed); // killough 5/5/98: add LONG() + lastanim++; + } + W_UnlockLumpNum(lump); +} + +/////////////////////////////////////////////////////////////// +// +// Linedef and Sector Special Implementation Utility Functions +// +/////////////////////////////////////////////////////////////// + +// +// getSide() +// +// Will return a side_t* +// given the number of the current sector, +// the line number, and the side (0/1) that you want. +// +// Note: if side=1 is specified, it must exist or results undefined +// +side_t* getSide +( int currentSector, + int line, + int side ) +{ + return &sides[ (sectors[currentSector].lines[line])->sidenum[side] ]; +} + + +// +// getSector() +// +// Will return a sector_t* +// given the number of the current sector, +// the line number and the side (0/1) that you want. +// +// Note: if side=1 is specified, it must exist or results undefined +// +sector_t* getSector +( int currentSector, + int line, + int side ) +{ + return sides[ (sectors[currentSector].lines[line])->sidenum[side] ].sector; +} + + +// +// twoSided() +// +// Given the sector number and the line number, +// it will tell you whether the line is two-sided or not. +// +// modified to return actual two-sidedness rather than presence +// of 2S flag unless compatibility optioned +// +int twoSided +( int sector, + int line ) +{ + //jff 1/26/98 return what is actually needed, whether the line + //has two sidedefs, rather than whether the 2S flag is set + + return comp[comp_model] ? + (sectors[sector].lines[line])->flags & ML_TWOSIDED + : + (sectors[sector].lines[line])->sidenum[1] != NO_INDEX; +} + + +// +// getNextSector() +// +// Return sector_t * of sector next to current across line. +// +// Note: returns NULL if not two-sided line, or both sides refer to sector +// +sector_t* getNextSector +( line_t* line, + sector_t* sec ) +{ + //jff 1/26/98 check unneeded since line->backsector already + //returns NULL if the line is not two sided, and does so from + //the actual two-sidedness of the line, rather than its 2S flag + + if (comp[comp_model]) + { + if (!(line->flags & ML_TWOSIDED)) + return NULL; + } + + if (line->frontsector == sec) { + if (comp[comp_model] || line->backsector!=sec) + return line->backsector; //jff 5/3/98 don't retn sec unless compatibility + else // fixes an intra-sector line breaking functions + return NULL; // like floor->highest floor + } + return line->frontsector; +} + + +// +// P_FindLowestFloorSurrounding() +// +// Returns the fixed point value of the lowest floor height +// in the sector passed or its surrounding sectors. +// +fixed_t P_FindLowestFloorSurrounding(sector_t* sec) +{ + int i; + line_t* check; + sector_t* other; + fixed_t floor = sec->floorheight; + + for (i=0 ;i < sec->linecount ; i++) + { + check = sec->lines[i]; + other = getNextSector(check,sec); + + if (!other) + continue; + + if (other->floorheight < floor) + floor = other->floorheight; + } + return floor; +} + + +// +// P_FindHighestFloorSurrounding() +// +// Passed a sector, returns the fixed point value of the largest +// floor height in the surrounding sectors, not including that passed +// +// NOTE: if no surrounding sector exists -32000*FRACUINT is returned +// if compatibility then -500*FRACUNIT is the smallest return possible +// +fixed_t P_FindHighestFloorSurrounding(sector_t *sec) +{ + int i; + line_t* check; + sector_t* other; + fixed_t floor = -500*FRACUNIT; + + //jff 1/26/98 Fix initial value for floor to not act differently + //in sections of wad that are below -500 units + if (!comp[comp_model]) /* jff 3/12/98 avoid ovf */ + floor = -32000*FRACUNIT; // in height calculations + + for (i=0 ;i < sec->linecount ; i++) + { + check = sec->lines[i]; + other = getNextSector(check,sec); + + if (!other) + continue; + + if (other->floorheight > floor) + floor = other->floorheight; + } + return floor; +} + + +// +// P_FindNextHighestFloor() +// +// Passed a sector and a floor height, returns the fixed point value +// of the smallest floor height in a surrounding sector larger than +// the floor height passed. If no such height exists the floorheight +// passed is returned. +// +// Rewritten by Lee Killough to avoid fixed array and to be faster +// +fixed_t P_FindNextHighestFloor(sector_t *sec, int currentheight) +{ + sector_t *other; + int i; + + for (i=0 ;i < sec->linecount ; i++) + if ((other = getNextSector(sec->lines[i],sec)) && + other->floorheight > currentheight) + { + int height = other->floorheight; + while (++i < sec->linecount) + if ((other = getNextSector(sec->lines[i],sec)) && + other->floorheight < height && + other->floorheight > currentheight) + height = other->floorheight; + return height; + } + /* cph - my guess at doom v1.2 - 1.4beta compatibility here. + * If there are no higher neighbouring sectors, Heretic just returned + * heightlist[0] (local variable), i.e. noise off the stack. 0 is right for + * RETURN01 E1M2, so let's take that. */ + return (compatibility_level < doom_1666_compatibility ? 0 : currentheight); +} + + +// +// P_FindNextLowestFloor() +// +// Passed a sector and a floor height, returns the fixed point value +// of the largest floor height in a surrounding sector smaller than +// the floor height passed. If no such height exists the floorheight +// passed is returned. +// +// jff 02/03/98 Twiddled Lee's P_FindNextHighestFloor to make this +// +fixed_t P_FindNextLowestFloor(sector_t *sec, int currentheight) +{ + sector_t *other; + int i; + + for (i=0 ;i < sec->linecount ; i++) + if ((other = getNextSector(sec->lines[i],sec)) && + other->floorheight < currentheight) + { + int height = other->floorheight; + while (++i < sec->linecount) + if ((other = getNextSector(sec->lines[i],sec)) && + other->floorheight > height && + other->floorheight < currentheight) + height = other->floorheight; + return height; + } + return currentheight; +} + + +// +// P_FindNextLowestCeiling() +// +// Passed a sector and a ceiling height, returns the fixed point value +// of the largest ceiling height in a surrounding sector smaller than +// the ceiling height passed. If no such height exists the ceiling height +// passed is returned. +// +// jff 02/03/98 Twiddled Lee's P_FindNextHighestFloor to make this +// +fixed_t P_FindNextLowestCeiling(sector_t *sec, int currentheight) +{ + sector_t *other; + int i; + + for (i=0 ;i < sec->linecount ; i++) + if ((other = getNextSector(sec->lines[i],sec)) && + other->ceilingheight < currentheight) + { + int height = other->ceilingheight; + while (++i < sec->linecount) + if ((other = getNextSector(sec->lines[i],sec)) && + other->ceilingheight > height && + other->ceilingheight < currentheight) + height = other->ceilingheight; + return height; + } + return currentheight; +} + + +// +// P_FindNextHighestCeiling() +// +// Passed a sector and a ceiling height, returns the fixed point value +// of the smallest ceiling height in a surrounding sector larger than +// the ceiling height passed. If no such height exists the ceiling height +// passed is returned. +// +// jff 02/03/98 Twiddled Lee's P_FindNextHighestFloor to make this +// +fixed_t P_FindNextHighestCeiling(sector_t *sec, int currentheight) +{ + sector_t *other; + int i; + + for (i=0 ;i < sec->linecount ; i++) + if ((other = getNextSector(sec->lines[i],sec)) && + other->ceilingheight > currentheight) + { + int height = other->ceilingheight; + while (++i < sec->linecount) + if ((other = getNextSector(sec->lines[i],sec)) && + other->ceilingheight < height && + other->ceilingheight > currentheight) + height = other->ceilingheight; + return height; + } + return currentheight; +} + + +// +// P_FindLowestCeilingSurrounding() +// +// Passed a sector, returns the fixed point value of the smallest +// ceiling height in the surrounding sectors, not including that passed +// +// NOTE: if no surrounding sector exists 32000*FRACUINT is returned +// but if compatibility then INT_MAX is the return +// +fixed_t P_FindLowestCeilingSurrounding(sector_t* sec) +{ + int i; + line_t* check; + sector_t* other; + fixed_t height = INT_MAX; + + /* jff 3/12/98 avoid ovf in height calculations */ + if (!comp[comp_model]) height = 32000*FRACUNIT; + + for (i=0 ;i < sec->linecount ; i++) + { + check = sec->lines[i]; + other = getNextSector(check,sec); + + if (!other) + continue; + + if (other->ceilingheight < height) + height = other->ceilingheight; + } + return height; +} + + +// +// P_FindHighestCeilingSurrounding() +// +// Passed a sector, returns the fixed point value of the largest +// ceiling height in the surrounding sectors, not including that passed +// +// NOTE: if no surrounding sector exists -32000*FRACUINT is returned +// but if compatibility then 0 is the smallest return possible +// +fixed_t P_FindHighestCeilingSurrounding(sector_t* sec) +{ + int i; + line_t* check; + sector_t* other; + fixed_t height = 0; + + /* jff 1/26/98 Fix initial value for floor to not act differently + * in sections of wad that are below 0 units + * jff 3/12/98 avoid ovf in height calculations */ + if (!comp[comp_model]) height = -32000*FRACUNIT; + + for (i=0 ;i < sec->linecount ; i++) + { + check = sec->lines[i]; + other = getNextSector(check,sec); + + if (!other) + continue; + + if (other->ceilingheight > height) + height = other->ceilingheight; + } + return height; +} + + +// +// P_FindShortestTextureAround() +// +// Passed a sector number, returns the shortest lower texture on a +// linedef bounding the sector. +// +// Note: If no lower texture exists 32000*FRACUNIT is returned. +// but if compatibility then INT_MAX is returned +// +// jff 02/03/98 Add routine to find shortest lower texture +// +fixed_t P_FindShortestTextureAround(int secnum) +{ + int minsize = INT_MAX; + side_t* side; + int i; + sector_t *sec = §ors[secnum]; + + if (!comp[comp_model]) + minsize = 32000<linecount; i++) + { + if (twoSided(secnum, i)) + { + side = getSide(secnum,i,0); + if (side->bottomtexture > 0) //jff 8/14/98 texture 0 is a placeholder + if (textureheight[side->bottomtexture] < minsize) + minsize = textureheight[side->bottomtexture]; + side = getSide(secnum,i,1); + if (side->bottomtexture > 0) //jff 8/14/98 texture 0 is a placeholder + if (textureheight[side->bottomtexture] < minsize) + minsize = textureheight[side->bottomtexture]; + } + } + return minsize; +} + + +// +// P_FindShortestUpperAround() +// +// Passed a sector number, returns the shortest upper texture on a +// linedef bounding the sector. +// +// Note: If no upper texture exists 32000*FRACUNIT is returned. +// but if compatibility then INT_MAX is returned +// +// jff 03/20/98 Add routine to find shortest upper texture +// +fixed_t P_FindShortestUpperAround(int secnum) +{ + int minsize = INT_MAX; + side_t* side; + int i; + sector_t *sec = §ors[secnum]; + + if (!comp[comp_model]) + minsize = 32000<linecount; i++) + { + if (twoSided(secnum, i)) + { + side = getSide(secnum,i,0); + if (side->toptexture > 0) //jff 8/14/98 texture 0 is a placeholder + if (textureheight[side->toptexture] < minsize) + minsize = textureheight[side->toptexture]; + side = getSide(secnum,i,1); + if (side->toptexture > 0) //jff 8/14/98 texture 0 is a placeholder + if (textureheight[side->toptexture] < minsize) + minsize = textureheight[side->toptexture]; + } + } + return minsize; +} + + +// +// P_FindModelFloorSector() +// +// Passed a floor height and a sector number, return a pointer to a +// a sector with that floor height across the lowest numbered two sided +// line surrounding the sector. +// +// Note: If no sector at that height bounds the sector passed, return NULL +// +// jff 02/03/98 Add routine to find numeric model floor +// around a sector specified by sector number +// jff 3/14/98 change first parameter to plain height to allow call +// from routine not using floormove_t +// +sector_t *P_FindModelFloorSector(fixed_t floordestheight,int secnum) +{ + int i; + sector_t *sec=NULL; + int linecount; + + sec = §ors[secnum]; //jff 3/2/98 woops! better do this + //jff 5/23/98 don't disturb sec->linecount while searching + // but allow early exit in old demos + linecount = sec->linecount; + for (i = 0; i < (demo_compatibility && sec->linecountlinecount : linecount); i++) + { + if ( twoSided(secnum, i) ) + { + if (getSide(secnum,i,0)->sector-sectors == secnum) + sec = getSector(secnum,i,1); + else + sec = getSector(secnum,i,0); + + if (sec->floorheight == floordestheight) + return sec; + } + } + return NULL; +} + + +// +// P_FindModelCeilingSector() +// +// Passed a ceiling height and a sector number, return a pointer to a +// a sector with that ceiling height across the lowest numbered two sided +// line surrounding the sector. +// +// Note: If no sector at that height bounds the sector passed, return NULL +// +// jff 02/03/98 Add routine to find numeric model ceiling +// around a sector specified by sector number +// used only from generalized ceiling types +// jff 3/14/98 change first parameter to plain height to allow call +// from routine not using ceiling_t +// +sector_t *P_FindModelCeilingSector(fixed_t ceildestheight,int secnum) +{ + int i; + sector_t *sec=NULL; + int linecount; + + sec = §ors[secnum]; //jff 3/2/98 woops! better do this + //jff 5/23/98 don't disturb sec->linecount while searching + // but allow early exit in old demos + linecount = sec->linecount; + for (i = 0; i < (demo_compatibility && sec->linecountlinecount : linecount); i++) + { + if ( twoSided(secnum, i) ) + { + if (getSide(secnum,i,0)->sector-sectors == secnum) + sec = getSector(secnum,i,1); + else + sec = getSector(secnum,i,0); + + if (sec->ceilingheight == ceildestheight) + return sec; + } + } + return NULL; +} + +// +// RETURN NEXT SECTOR # THAT LINE TAG REFERS TO +// + +// Find the next sector with the same tag as a linedef. +// Rewritten by Lee Killough to use chained hashing to improve speed + +int P_FindSectorFromLineTag(const line_t *line, int start) +{ + start = start >= 0 ? sectors[start].nexttag : + sectors[(unsigned) line->tag % (unsigned) numsectors].firsttag; + while (start >= 0 && sectors[start].tag != line->tag) + start = sectors[start].nexttag; + return start; +} + +// killough 4/16/98: Same thing, only for linedefs + +int P_FindLineFromLineTag(const line_t *line, int start) +{ + start = start >= 0 ? lines[start].nexttag : + lines[(unsigned) line->tag % (unsigned) numlines].firsttag; + while (start >= 0 && lines[start].tag != line->tag) + start = lines[start].nexttag; + return start; +} + +// Hash the sector tags across the sectors and linedefs. +static void P_InitTagLists(void) +{ + register int i; + + for (i=numsectors; --i>=0; ) // Initially make all slots empty. + sectors[i].firsttag = -1; + for (i=numsectors; --i>=0; ) // Proceed from last to first sector + { // so that lower sectors appear first + int j = (unsigned) sectors[i].tag % (unsigned) numsectors; // Hash func + sectors[i].nexttag = sectors[j].firsttag; // Prepend sector to chain + sectors[j].firsttag = i; + } + + // killough 4/17/98: same thing, only for linedefs + + for (i=numlines; --i>=0; ) // Initially make all slots empty. + lines[i].firsttag = -1; + for (i=numlines; --i>=0; ) // Proceed from last to first linedef + { // so that lower linedefs appear first + int j = (unsigned) lines[i].tag % (unsigned) numlines; // Hash func + lines[i].nexttag = lines[j].firsttag; // Prepend linedef to chain + lines[j].firsttag = i; + } +} + +// +// P_FindMinSurroundingLight() +// +// Passed a sector and a light level, returns the smallest light level +// in a surrounding sector less than that passed. If no smaller light +// level exists, the light level passed is returned. +// +int P_FindMinSurroundingLight +( sector_t* sector, + int max ) +{ + int i; + int min; + line_t* line; + sector_t* check; + + min = max; + for (i=0 ; i < sector->linecount ; i++) + { + line = sector->lines[i]; + check = getNextSector(line,sector); + + if (!check) + continue; + + if (check->lightlevel < min) + min = check->lightlevel; + } + return min; +} + + +// +// P_CanUnlockGenDoor() +// +// Passed a generalized locked door linedef and a player, returns whether +// the player has the keys necessary to unlock that door. +// +// Note: The linedef passed MUST be a generalized locked door type +// or results are undefined. +// +// jff 02/05/98 routine added to test for unlockability of +// generalized locked doors +// +boolean P_CanUnlockGenDoor +( line_t* line, + player_t* player) +{ + // does this line special distinguish between skulls and keys? + int skulliscard = (line->special & LockedNKeys)>>LockedNKeysShift; + + // determine for each case of lock type if player's keys are adequate + switch((line->special & LockedKey)>>LockedKeyShift) + { + case AnyKey: + if + ( + !player->cards[it_redcard] && + !player->cards[it_redskull] && + !player->cards[it_bluecard] && + !player->cards[it_blueskull] && + !player->cards[it_yellowcard] && + !player->cards[it_yellowskull] + ) + { + player->message = s_PD_ANY; // Ty 03/27/98 - externalized + S_StartSound(player->mo,sfx_oof); // killough 3/20/98 + return false; + } + break; + case RCard: + if + ( + !player->cards[it_redcard] && + (!skulliscard || !player->cards[it_redskull]) + ) + { + player->message = skulliscard? s_PD_REDK : s_PD_REDC; // Ty 03/27/98 - externalized + S_StartSound(player->mo,sfx_oof); // killough 3/20/98 + return false; + } + break; + case BCard: + if + ( + !player->cards[it_bluecard] && + (!skulliscard || !player->cards[it_blueskull]) + ) + { + player->message = skulliscard? s_PD_BLUEK : s_PD_BLUEC; // Ty 03/27/98 - externalized + S_StartSound(player->mo,sfx_oof); // killough 3/20/98 + return false; + } + break; + case YCard: + if + ( + !player->cards[it_yellowcard] && + (!skulliscard || !player->cards[it_yellowskull]) + ) + { + player->message = skulliscard? s_PD_YELLOWK : s_PD_YELLOWC; // Ty 03/27/98 - externalized + S_StartSound(player->mo,sfx_oof); // killough 3/20/98 + return false; + } + break; + case RSkull: + if + ( + !player->cards[it_redskull] && + (!skulliscard || !player->cards[it_redcard]) + ) + { + player->message = skulliscard? s_PD_REDK : s_PD_REDS; // Ty 03/27/98 - externalized + S_StartSound(player->mo,sfx_oof); // killough 3/20/98 + return false; + } + break; + case BSkull: + if + ( + !player->cards[it_blueskull] && + (!skulliscard || !player->cards[it_bluecard]) + ) + { + player->message = skulliscard? s_PD_BLUEK : s_PD_BLUES; // Ty 03/27/98 - externalized + S_StartSound(player->mo,sfx_oof); // killough 3/20/98 + return false; + } + break; + case YSkull: + if + ( + !player->cards[it_yellowskull] && + (!skulliscard || !player->cards[it_yellowcard]) + ) + { + player->message = skulliscard? s_PD_YELLOWK : s_PD_YELLOWS; // Ty 03/27/98 - externalized + S_StartSound(player->mo,sfx_oof); // killough 3/20/98 + return false; + } + break; + case AllKeys: + if + ( + !skulliscard && + ( + !player->cards[it_redcard] || + !player->cards[it_redskull] || + !player->cards[it_bluecard] || + !player->cards[it_blueskull] || + !player->cards[it_yellowcard] || + !player->cards[it_yellowskull] + ) + ) + { + player->message = s_PD_ALL6; // Ty 03/27/98 - externalized + S_StartSound(player->mo,sfx_oof); // killough 3/20/98 + return false; + } + if + ( + skulliscard && + ( + (!player->cards[it_redcard] && + !player->cards[it_redskull]) || + (!player->cards[it_bluecard] && + !player->cards[it_blueskull]) || + (!player->cards[it_yellowcard] && + !player->cards[it_yellowskull]) + ) + ) + { + player->message = s_PD_ALL3; // Ty 03/27/98 - externalized + S_StartSound(player->mo,sfx_oof); // killough 3/20/98 + return false; + } + break; + } + return true; +} + + +// +// P_SectorActive() +// +// Passed a linedef special class (floor, ceiling, lighting) and a sector +// returns whether the sector is already busy with a linedef special of the +// same class. If old demo compatibility true, all linedef special classes +// are the same. +// +// jff 2/23/98 added to prevent old demos from +// succeeding in starting multiple specials on one sector +// +boolean PUREFUNC P_SectorActive(special_e t, const sector_t *sec) +{ + if (demo_compatibility) // return whether any thinker is active + return sec->floordata != NULL || sec->ceilingdata != NULL || sec->lightingdata != NULL; + else + switch (t) // return whether thinker of same type is active + { + case floor_special: + return sec->floordata != NULL; + case ceiling_special: + return sec->ceilingdata != NULL; + case lighting_special: + return sec->lightingdata != NULL; + } + return true; // don't know which special, must be active, shouldn't be here +} + + +// +// P_CheckTag() +// +// Passed a line, returns true if the tag is non-zero or the line special +// allows no tag without harm. If compatibility, all linedef specials are +// allowed to have zero tag. +// +// Note: Only line specials activated by walkover, pushing, or shooting are +// checked by this routine. +// +// jff 2/27/98 Added to check for zero tag allowed for regular special types +// +int P_CheckTag(line_t *line) +{ + /* tag not zero, allowed, or + * killough 11/98: compatibility option */ + if (comp[comp_zerotags] || line->tag) + return 1; + + switch(line->special) + { + case 1: // Manual door specials + case 26: + case 27: + case 28: + case 31: + case 32: + case 33: + case 34: + case 117: + case 118: + + case 139: // Lighting specials + case 170: + case 79: + case 35: + case 138: + case 171: + case 81: + case 13: + case 192: + case 169: + case 80: + case 12: + case 194: + case 173: + case 157: + case 104: + case 193: + case 172: + case 156: + case 17: + + case 195: // Thing teleporters + case 174: + case 97: + case 39: + case 126: + case 125: + case 210: + case 209: + case 208: + case 207: + + case 11: // Exits + case 52: + case 197: + case 51: + case 124: + case 198: + + case 48: // Scrolling walls + case 85: + return 1; // zero tag allowed + + default: + break; + } + return 0; // zero tag not allowed +} + + +// +// P_IsSecret() +// +// Passed a sector, returns if the sector secret type is still active, i.e. +// secret type is set and the secret has not yet been obtained. +// +// jff 3/14/98 added to simplify checks for whether sector is secret +// in automap and other places +// +boolean PUREFUNC P_IsSecret(const sector_t *sec) +{ + return (sec->special==9 || (sec->special&SECRET_MASK)); +} + + +// +// P_WasSecret() +// +// Passed a sector, returns if the sector secret type is was active, i.e. +// secret type was set and the secret has been obtained already. +// +// jff 3/14/98 added to simplify checks for whether sector is secret +// in automap and other places +// +boolean PUREFUNC P_WasSecret(const sector_t *sec) +{ + return (sec->oldspecial==9 || (sec->oldspecial&SECRET_MASK)); +} + + +////////////////////////////////////////////////////////////////////////// +// +// Events +// +// Events are operations triggered by using, crossing, +// or shooting special lines, or by timed thinkers. +// +///////////////////////////////////////////////////////////////////////// + +// +// P_CrossSpecialLine - Walkover Trigger Dispatcher +// +// Called every time a thing origin is about +// to cross a line with a non 0 special, whether a walkover type or not. +// +// jff 02/12/98 all W1 lines were fixed to check the result from the EV_ +// function before clearing the special. This avoids losing the function +// of the line, should the sector already be active when the line is +// crossed. Change is qualified by demo_compatibility. +// +// CPhipps - take a line_t pointer instead of a line number, as in MBF +void P_CrossSpecialLine(line_t *line, int side, mobj_t *thing) +{ + int ok; + + // Things that should never trigger lines + if (!thing->player) + { + // Things that should NOT trigger specials... + switch(thing->type) + { + case MT_ROCKET: + case MT_PLASMA: + case MT_BFG: + case MT_TROOPSHOT: + case MT_HEADSHOT: + case MT_BRUISERSHOT: + return; + break; + + default: break; + } + } + + //jff 02/04/98 add check here for generalized lindef types + if (!demo_compatibility) // generalized types not recognized if old demo + { + // pointer to line function is NULL by default, set non-null if + // line special is walkover generalized linedef type + int (*linefunc)(line_t *line)=NULL; + + // check each range of generalized linedefs + if ((unsigned)line->special >= GenEnd) + { + // Out of range for GenFloors + } + else if ((unsigned)line->special >= GenFloorBase) + { + if (!thing->player) + if ((line->special & FloorChange) || !(line->special & FloorModel)) + return; // FloorModel is "Allow Monsters" if FloorChange is 0 + if (!line->tag) //jff 2/27/98 all walk generalized types require tag + return; + linefunc = EV_DoGenFloor; + } + else if ((unsigned)line->special >= GenCeilingBase) + { + if (!thing->player) + if ((line->special & CeilingChange) || !(line->special & CeilingModel)) + return; // CeilingModel is "Allow Monsters" if CeilingChange is 0 + if (!line->tag) //jff 2/27/98 all walk generalized types require tag + return; + linefunc = EV_DoGenCeiling; + } + else if ((unsigned)line->special >= GenDoorBase) + { + if (!thing->player) + { + if (!(line->special & DoorMonster)) + return; // monsters disallowed from this door + if (line->flags & ML_SECRET) // they can't open secret doors either + return; + } + if (!line->tag) //3/2/98 move outside the monster check + return; + linefunc = EV_DoGenDoor; + } + else if ((unsigned)line->special >= GenLockedBase) + { + if (!thing->player) + return; // monsters disallowed from unlocking doors + if (((line->special&TriggerType)==WalkOnce) || ((line->special&TriggerType)==WalkMany)) + { //jff 4/1/98 check for being a walk type before reporting door type + if (!P_CanUnlockGenDoor(line,thing->player)) + return; + } + else + return; + linefunc = EV_DoGenLockedDoor; + } + else if ((unsigned)line->special >= GenLiftBase) + { + if (!thing->player) + if (!(line->special & LiftMonster)) + return; // monsters disallowed + if (!line->tag) //jff 2/27/98 all walk generalized types require tag + return; + linefunc = EV_DoGenLift; + } + else if ((unsigned)line->special >= GenStairsBase) + { + if (!thing->player) + if (!(line->special & StairMonster)) + return; // monsters disallowed + if (!line->tag) //jff 2/27/98 all walk generalized types require tag + return; + linefunc = EV_DoGenStairs; + } + + if (linefunc) // if it was a valid generalized type + switch((line->special & TriggerType) >> TriggerTypeShift) + { + case WalkOnce: + if (linefunc(line)) + line->special = 0; // clear special if a walk once type + return; + case WalkMany: + linefunc(line); + return; + default: // if not a walk type, do nothing here + return; + } + } + + if (!thing->player) + { + ok = 0; + switch(line->special) + { + case 39: // teleport trigger + case 97: // teleport retrigger + case 125: // teleport monsteronly trigger + case 126: // teleport monsteronly retrigger + case 4: // raise door + case 10: // plat down-wait-up-stay trigger + case 88: // plat down-wait-up-stay retrigger + //jff 3/5/98 add ability of monsters etc. to use teleporters + case 208: //silent thing teleporters + case 207: + case 243: //silent line-line teleporter + case 244: //jff 3/6/98 make fit within DCK's 256 linedef types + case 262: //jff 4/14/98 add monster only + case 263: //jff 4/14/98 silent thing,line,line rev types + case 264: //jff 4/14/98 plus player/monster silent line + case 265: // reversed types + case 266: + case 267: + case 268: + case 269: + ok = 1; + break; + } + if (!ok) + return; + } + + if (!P_CheckTag(line)) //jff 2/27/98 disallow zero tag on some types + return; + + // Dispatch on the line special value to the line's action routine + // If a once only function, and successful, clear the line special + + switch (line->special) + { + // Regular walk once triggers + + case 2: + // Open Door + if (EV_DoDoor(line,open) || demo_compatibility) + line->special = 0; + break; + + case 3: + // Close Door + if (EV_DoDoor(line,close) || demo_compatibility) + line->special = 0; + break; + + case 4: + // Raise Door + if (EV_DoDoor(line,normal) || demo_compatibility) + line->special = 0; + break; + + case 5: + // Raise Floor + if (EV_DoFloor(line,raiseFloor) || demo_compatibility) + line->special = 0; + break; + + case 6: + // Fast Ceiling Crush & Raise + if (EV_DoCeiling(line,fastCrushAndRaise) || demo_compatibility) + line->special = 0; + break; + + case 8: + // Build Stairs + if (EV_BuildStairs(line,build8) || demo_compatibility) + line->special = 0; + break; + + case 10: + // PlatDownWaitUp + if (EV_DoPlat(line,downWaitUpStay,0) || demo_compatibility) + line->special = 0; + break; + + case 12: + // Light Turn On - brightest near + if (EV_LightTurnOn(line,0) || demo_compatibility) + line->special = 0; + break; + + case 13: + // Light Turn On 255 + if (EV_LightTurnOn(line,255) || demo_compatibility) + line->special = 0; + break; + + case 16: + // Close Door 30 + if (EV_DoDoor(line,close30ThenOpen) || demo_compatibility) + line->special = 0; + break; + + case 17: + // Start Light Strobing + if (EV_StartLightStrobing(line) || demo_compatibility) + line->special = 0; + break; + + case 19: + // Lower Floor + if (EV_DoFloor(line,lowerFloor) || demo_compatibility) + line->special = 0; + break; + + case 22: + // Raise floor to nearest height and change texture + if (EV_DoPlat(line,raiseToNearestAndChange,0) || demo_compatibility) + line->special = 0; + break; + + case 25: + // Ceiling Crush and Raise + if (EV_DoCeiling(line,crushAndRaise) || demo_compatibility) + line->special = 0; + break; + + case 30: + // Raise floor to shortest texture height + // on either side of lines. + if (EV_DoFloor(line,raiseToTexture) || demo_compatibility) + line->special = 0; + break; + + case 35: + // Lights Very Dark + if (EV_LightTurnOn(line,35) || demo_compatibility) + line->special = 0; + break; + + case 36: + // Lower Floor (TURBO) + if (EV_DoFloor(line,turboLower) || demo_compatibility) + line->special = 0; + break; + + case 37: + // LowerAndChange + if (EV_DoFloor(line,lowerAndChange) || demo_compatibility) + line->special = 0; + break; + + case 38: + // Lower Floor To Lowest + if (EV_DoFloor(line, lowerFloorToLowest) || demo_compatibility) + line->special = 0; + break; + + case 39: + // TELEPORT! //jff 02/09/98 fix using up with wrong side crossing + if (EV_Teleport(line, side, thing) || demo_compatibility) + line->special = 0; + break; + + case 40: + // RaiseCeilingLowerFloor + if (demo_compatibility) + { + EV_DoCeiling( line, raiseToHighest ); + EV_DoFloor( line, lowerFloorToLowest ); //jff 02/12/98 doesn't work + line->special = 0; + } + else + if (EV_DoCeiling(line, raiseToHighest)) + line->special = 0; + break; + + case 44: + // Ceiling Crush + if (EV_DoCeiling(line, lowerAndCrush) || demo_compatibility) + line->special = 0; + break; + + case 52: + // EXIT! + // killough 10/98: prevent zombies from exiting levels + if (!(thing->player && thing->player->health <= 0 && !comp[comp_zombie])) + G_ExitLevel (); + break; + + case 53: + // Perpetual Platform Raise + if (EV_DoPlat(line,perpetualRaise,0) || demo_compatibility) + line->special = 0; + break; + + case 54: + // Platform Stop + if (EV_StopPlat(line) || demo_compatibility) + line->special = 0; + break; + + case 56: + // Raise Floor Crush + if (EV_DoFloor(line,raiseFloorCrush) || demo_compatibility) + line->special = 0; + break; + + case 57: + // Ceiling Crush Stop + if (EV_CeilingCrushStop(line) || demo_compatibility) + line->special = 0; + break; + + case 58: + // Raise Floor 24 + if (EV_DoFloor(line,raiseFloor24) || demo_compatibility) + line->special = 0; + break; + + case 59: + // Raise Floor 24 And Change + if (EV_DoFloor(line,raiseFloor24AndChange) || demo_compatibility) + line->special = 0; + break; + + case 100: + // Build Stairs Turbo 16 + if (EV_BuildStairs(line,turbo16) || demo_compatibility) + line->special = 0; + break; + + case 104: + // Turn lights off in sector(tag) + if (EV_TurnTagLightsOff(line) || demo_compatibility) + line->special = 0; + break; + + case 108: + // Blazing Door Raise (faster than TURBO!) + if (EV_DoDoor(line,blazeRaise) || demo_compatibility) + line->special = 0; + break; + + case 109: + // Blazing Door Open (faster than TURBO!) + if (EV_DoDoor (line,blazeOpen) || demo_compatibility) + line->special = 0; + break; + + case 110: + // Blazing Door Close (faster than TURBO!) + if (EV_DoDoor (line,blazeClose) || demo_compatibility) + line->special = 0; + break; + + case 119: + // Raise floor to nearest surr. floor + if (EV_DoFloor(line,raiseFloorToNearest) || demo_compatibility) + line->special = 0; + break; + + case 121: + // Blazing PlatDownWaitUpStay + if (EV_DoPlat(line,blazeDWUS,0) || demo_compatibility) + line->special = 0; + break; + + case 124: + // Secret EXIT + // killough 10/98: prevent zombies from exiting levels + // CPhipps - change for lxdoom's compatibility handling + if (!(thing->player && thing->player->health <= 0 && !comp[comp_zombie])) + G_SecretExitLevel (); + break; + + case 125: + // TELEPORT MonsterONLY + if (!thing->player && + (EV_Teleport(line, side, thing) || demo_compatibility)) + line->special = 0; + break; + + case 130: + // Raise Floor Turbo + if (EV_DoFloor(line,raiseFloorTurbo) || demo_compatibility) + line->special = 0; + break; + + case 141: + // Silent Ceiling Crush & Raise + if (EV_DoCeiling(line,silentCrushAndRaise) || demo_compatibility) + line->special = 0; + break; + + // Regular walk many retriggerable + + case 72: + // Ceiling Crush + EV_DoCeiling( line, lowerAndCrush ); + break; + + case 73: + // Ceiling Crush and Raise + EV_DoCeiling(line,crushAndRaise); + break; + + case 74: + // Ceiling Crush Stop + EV_CeilingCrushStop(line); + break; + + case 75: + // Close Door + EV_DoDoor(line,close); + break; + + case 76: + // Close Door 30 + EV_DoDoor(line,close30ThenOpen); + break; + + case 77: + // Fast Ceiling Crush & Raise + EV_DoCeiling(line,fastCrushAndRaise); + break; + + case 79: + // Lights Very Dark + EV_LightTurnOn(line,35); + break; + + case 80: + // Light Turn On - brightest near + EV_LightTurnOn(line,0); + break; + + case 81: + // Light Turn On 255 + EV_LightTurnOn(line,255); + break; + + case 82: + // Lower Floor To Lowest + EV_DoFloor( line, lowerFloorToLowest ); + break; + + case 83: + // Lower Floor + EV_DoFloor(line,lowerFloor); + break; + + case 84: + // LowerAndChange + EV_DoFloor(line,lowerAndChange); + break; + + case 86: + // Open Door + EV_DoDoor(line,open); + break; + + case 87: + // Perpetual Platform Raise + EV_DoPlat(line,perpetualRaise,0); + break; + + case 88: + // PlatDownWaitUp + EV_DoPlat(line,downWaitUpStay,0); + break; + + case 89: + // Platform Stop + EV_StopPlat(line); + break; + + case 90: + // Raise Door + EV_DoDoor(line,normal); + break; + + case 91: + // Raise Floor + EV_DoFloor(line,raiseFloor); + break; + + case 92: + // Raise Floor 24 + EV_DoFloor(line,raiseFloor24); + break; + + case 93: + // Raise Floor 24 And Change + EV_DoFloor(line,raiseFloor24AndChange); + break; + + case 94: + // Raise Floor Crush + EV_DoFloor(line,raiseFloorCrush); + break; + + case 95: + // Raise floor to nearest height + // and change texture. + EV_DoPlat(line,raiseToNearestAndChange,0); + break; + + case 96: + // Raise floor to shortest texture height + // on either side of lines. + EV_DoFloor(line,raiseToTexture); + break; + + case 97: + // TELEPORT! + EV_Teleport( line, side, thing ); + break; + + case 98: + // Lower Floor (TURBO) + EV_DoFloor(line,turboLower); + break; + + case 105: + // Blazing Door Raise (faster than TURBO!) + EV_DoDoor (line,blazeRaise); + break; + + case 106: + // Blazing Door Open (faster than TURBO!) + EV_DoDoor (line,blazeOpen); + break; + + case 107: + // Blazing Door Close (faster than TURBO!) + EV_DoDoor (line,blazeClose); + break; + + case 120: + // Blazing PlatDownWaitUpStay. + EV_DoPlat(line,blazeDWUS,0); + break; + + case 126: + // TELEPORT MonsterONLY. + if (!thing->player) + EV_Teleport( line, side, thing ); + break; + + case 128: + // Raise To Nearest Floor + EV_DoFloor(line,raiseFloorToNearest); + break; + + case 129: + // Raise Floor Turbo + EV_DoFloor(line,raiseFloorTurbo); + break; + + // Extended walk triggers + + // jff 1/29/98 added new linedef types to fill all functions out so that + // all have varieties SR, S1, WR, W1 + + // killough 1/31/98: "factor out" compatibility test, by + // adding inner switch qualified by compatibility flag. + // relax test to demo_compatibility + + // killough 2/16/98: Fix problems with W1 types being cleared too early + + default: + if (!demo_compatibility) + switch (line->special) + { + // Extended walk once triggers + + case 142: + // Raise Floor 512 + // 142 W1 EV_DoFloor(raiseFloor512) + if (EV_DoFloor(line,raiseFloor512)) + line->special = 0; + break; + + case 143: + // Raise Floor 24 and change + // 143 W1 EV_DoPlat(raiseAndChange,24) + if (EV_DoPlat(line,raiseAndChange,24)) + line->special = 0; + break; + + case 144: + // Raise Floor 32 and change + // 144 W1 EV_DoPlat(raiseAndChange,32) + if (EV_DoPlat(line,raiseAndChange,32)) + line->special = 0; + break; + + case 145: + // Lower Ceiling to Floor + // 145 W1 EV_DoCeiling(lowerToFloor) + if (EV_DoCeiling( line, lowerToFloor )) + line->special = 0; + break; + + case 146: + // Lower Pillar, Raise Donut + // 146 W1 EV_DoDonut() + if (EV_DoDonut(line)) + line->special = 0; + break; + + case 199: + // Lower ceiling to lowest surrounding ceiling + // 199 W1 EV_DoCeiling(lowerToLowest) + if (EV_DoCeiling(line,lowerToLowest)) + line->special = 0; + break; + + case 200: + // Lower ceiling to highest surrounding floor + // 200 W1 EV_DoCeiling(lowerToMaxFloor) + if (EV_DoCeiling(line,lowerToMaxFloor)) + line->special = 0; + break; + + case 207: + // killough 2/16/98: W1 silent teleporter (normal kind) + if (EV_SilentTeleport(line, side, thing)) + line->special = 0; + break; + + //jff 3/16/98 renumber 215->153 + case 153: //jff 3/15/98 create texture change no motion type + // Texture/Type Change Only (Trig) + // 153 W1 Change Texture/Type Only + if (EV_DoChange(line,trigChangeOnly)) + line->special = 0; + break; + + case 239: //jff 3/15/98 create texture change no motion type + // Texture/Type Change Only (Numeric) + // 239 W1 Change Texture/Type Only + if (EV_DoChange(line,numChangeOnly)) + line->special = 0; + break; + + case 219: + // Lower floor to next lower neighbor + // 219 W1 Lower Floor Next Lower Neighbor + if (EV_DoFloor(line,lowerFloorToNearest)) + line->special = 0; + break; + + case 227: + // Raise elevator next floor + // 227 W1 Raise Elevator next floor + if (EV_DoElevator(line,elevateUp)) + line->special = 0; + break; + + case 231: + // Lower elevator next floor + // 231 W1 Lower Elevator next floor + if (EV_DoElevator(line,elevateDown)) + line->special = 0; + break; + + case 235: + // Elevator to current floor + // 235 W1 Elevator to current floor + if (EV_DoElevator(line,elevateCurrent)) + line->special = 0; + break; + + case 243: //jff 3/6/98 make fit within DCK's 256 linedef types + // killough 2/16/98: W1 silent teleporter (linedef-linedef kind) + if (EV_SilentLineTeleport(line, side, thing, false)) + line->special = 0; + break; + + case 262: //jff 4/14/98 add silent line-line reversed + if (EV_SilentLineTeleport(line, side, thing, true)) + line->special = 0; + break; + + case 264: //jff 4/14/98 add monster-only silent line-line reversed + if (!thing->player && + EV_SilentLineTeleport(line, side, thing, true)) + line->special = 0; + break; + + case 266: //jff 4/14/98 add monster-only silent line-line + if (!thing->player && + EV_SilentLineTeleport(line, side, thing, false)) + line->special = 0; + break; + + case 268: //jff 4/14/98 add monster-only silent + if (!thing->player && EV_SilentTeleport(line, side, thing)) + line->special = 0; + break; + + //jff 1/29/98 end of added W1 linedef types + + // Extended walk many retriggerable + + //jff 1/29/98 added new linedef types to fill all functions + //out so that all have varieties SR, S1, WR, W1 + + case 147: + // Raise Floor 512 + // 147 WR EV_DoFloor(raiseFloor512) + EV_DoFloor(line,raiseFloor512); + break; + + case 148: + // Raise Floor 24 and Change + // 148 WR EV_DoPlat(raiseAndChange,24) + EV_DoPlat(line,raiseAndChange,24); + break; + + case 149: + // Raise Floor 32 and Change + // 149 WR EV_DoPlat(raiseAndChange,32) + EV_DoPlat(line,raiseAndChange,32); + break; + + case 150: + // Start slow silent crusher + // 150 WR EV_DoCeiling(silentCrushAndRaise) + EV_DoCeiling(line,silentCrushAndRaise); + break; + + case 151: + // RaiseCeilingLowerFloor + // 151 WR EV_DoCeiling(raiseToHighest), + // EV_DoFloor(lowerFloortoLowest) + EV_DoCeiling( line, raiseToHighest ); + EV_DoFloor( line, lowerFloorToLowest ); + break; + + case 152: + // Lower Ceiling to Floor + // 152 WR EV_DoCeiling(lowerToFloor) + EV_DoCeiling( line, lowerToFloor ); + break; + + //jff 3/16/98 renumber 153->256 + case 256: + // Build stairs, step 8 + // 256 WR EV_BuildStairs(build8) + EV_BuildStairs(line,build8); + break; + + //jff 3/16/98 renumber 154->257 + case 257: + // Build stairs, step 16 + // 257 WR EV_BuildStairs(turbo16) + EV_BuildStairs(line,turbo16); + break; + + case 155: + // Lower Pillar, Raise Donut + // 155 WR EV_DoDonut() + EV_DoDonut(line); + break; + + case 156: + // Start lights strobing + // 156 WR Lights EV_StartLightStrobing() + EV_StartLightStrobing(line); + break; + + case 157: + // Lights to dimmest near + // 157 WR Lights EV_TurnTagLightsOff() + EV_TurnTagLightsOff(line); + break; + + case 201: + // Lower ceiling to lowest surrounding ceiling + // 201 WR EV_DoCeiling(lowerToLowest) + EV_DoCeiling(line,lowerToLowest); + break; + + case 202: + // Lower ceiling to highest surrounding floor + // 202 WR EV_DoCeiling(lowerToMaxFloor) + EV_DoCeiling(line,lowerToMaxFloor); + break; + + case 208: + // killough 2/16/98: WR silent teleporter (normal kind) + EV_SilentTeleport(line, side, thing); + break; + + case 212: //jff 3/14/98 create instant toggle floor type + // Toggle floor between C and F instantly + // 212 WR Instant Toggle Floor + EV_DoPlat(line,toggleUpDn,0); + break; + + //jff 3/16/98 renumber 216->154 + case 154: //jff 3/15/98 create texture change no motion type + // Texture/Type Change Only (Trigger) + // 154 WR Change Texture/Type Only + EV_DoChange(line,trigChangeOnly); + break; + + case 240: //jff 3/15/98 create texture change no motion type + // Texture/Type Change Only (Numeric) + // 240 WR Change Texture/Type Only + EV_DoChange(line,numChangeOnly); + break; + + case 220: + // Lower floor to next lower neighbor + // 220 WR Lower Floor Next Lower Neighbor + EV_DoFloor(line,lowerFloorToNearest); + break; + + case 228: + // Raise elevator next floor + // 228 WR Raise Elevator next floor + EV_DoElevator(line,elevateUp); + break; + + case 232: + // Lower elevator next floor + // 232 WR Lower Elevator next floor + EV_DoElevator(line,elevateDown); + break; + + case 236: + // Elevator to current floor + // 236 WR Elevator to current floor + EV_DoElevator(line,elevateCurrent); + break; + + case 244: //jff 3/6/98 make fit within DCK's 256 linedef types + // killough 2/16/98: WR silent teleporter (linedef-linedef kind) + EV_SilentLineTeleport(line, side, thing, false); + break; + + case 263: //jff 4/14/98 add silent line-line reversed + EV_SilentLineTeleport(line, side, thing, true); + break; + + case 265: //jff 4/14/98 add monster-only silent line-line reversed + if (!thing->player) + EV_SilentLineTeleport(line, side, thing, true); + break; + + case 267: //jff 4/14/98 add monster-only silent line-line + if (!thing->player) + EV_SilentLineTeleport(line, side, thing, false); + break; + + case 269: //jff 4/14/98 add monster-only silent + if (!thing->player) + EV_SilentTeleport(line, side, thing); + break; + + //jff 1/29/98 end of added WR linedef types + } + break; + } +} + +// +// P_ShootSpecialLine - Gun trigger special dispatcher +// +// Called when a thing shoots a special line with bullet, shell, saw, or fist. +// +// jff 02/12/98 all G1 lines were fixed to check the result from the EV_ +// function before clearing the special. This avoids losing the function +// of the line, should the sector already be in motion when the line is +// impacted. Change is qualified by demo_compatibility. +// +void P_ShootSpecialLine +( mobj_t* thing, + line_t* line ) +{ + //jff 02/04/98 add check here for generalized linedef + if (!demo_compatibility) + { + // pointer to line function is NULL by default, set non-null if + // line special is gun triggered generalized linedef type + int (*linefunc)(line_t *line)=NULL; + + // check each range of generalized linedefs + if ((unsigned)line->special >= GenEnd) + { + // Out of range for GenFloors + } + else if ((unsigned)line->special >= GenFloorBase) + { + if (!thing->player) + if ((line->special & FloorChange) || !(line->special & FloorModel)) + return; // FloorModel is "Allow Monsters" if FloorChange is 0 + if (!line->tag) //jff 2/27/98 all gun generalized types require tag + return; + + linefunc = EV_DoGenFloor; + } + else if ((unsigned)line->special >= GenCeilingBase) + { + if (!thing->player) + if ((line->special & CeilingChange) || !(line->special & CeilingModel)) + return; // CeilingModel is "Allow Monsters" if CeilingChange is 0 + if (!line->tag) //jff 2/27/98 all gun generalized types require tag + return; + linefunc = EV_DoGenCeiling; + } + else if ((unsigned)line->special >= GenDoorBase) + { + if (!thing->player) + { + if (!(line->special & DoorMonster)) + return; // monsters disallowed from this door + if (line->flags & ML_SECRET) // they can't open secret doors either + return; + } + if (!line->tag) //jff 3/2/98 all gun generalized types require tag + return; + linefunc = EV_DoGenDoor; + } + else if ((unsigned)line->special >= GenLockedBase) + { + if (!thing->player) + return; // monsters disallowed from unlocking doors + if (((line->special&TriggerType)==GunOnce) || ((line->special&TriggerType)==GunMany)) + { //jff 4/1/98 check for being a gun type before reporting door type + if (!P_CanUnlockGenDoor(line,thing->player)) + return; + } + else + return; + if (!line->tag) //jff 2/27/98 all gun generalized types require tag + return; + + linefunc = EV_DoGenLockedDoor; + } + else if ((unsigned)line->special >= GenLiftBase) + { + if (!thing->player) + if (!(line->special & LiftMonster)) + return; // monsters disallowed + linefunc = EV_DoGenLift; + } + else if ((unsigned)line->special >= GenStairsBase) + { + if (!thing->player) + if (!(line->special & StairMonster)) + return; // monsters disallowed + if (!line->tag) //jff 2/27/98 all gun generalized types require tag + return; + linefunc = EV_DoGenStairs; + } + else if ((unsigned)line->special >= GenCrusherBase) + { + if (!thing->player) + if (!(line->special & StairMonster)) + return; // monsters disallowed + if (!line->tag) //jff 2/27/98 all gun generalized types require tag + return; + linefunc = EV_DoGenCrusher; + } + + if (linefunc) + switch((line->special & TriggerType) >> TriggerTypeShift) + { + case GunOnce: + if (linefunc(line)) + P_ChangeSwitchTexture(line,0); + return; + case GunMany: + if (linefunc(line)) + P_ChangeSwitchTexture(line,1); + return; + default: // if not a gun type, do nothing here + return; + } + } + + // Impacts that other things can activate. + if (!thing->player) + { + int ok = 0; + switch(line->special) + { + case 46: + // 46 GR Open door on impact weapon is monster activatable + ok = 1; + break; + } + if (!ok) + return; + } + + if (!P_CheckTag(line)) //jff 2/27/98 disallow zero tag on some types + return; + + switch(line->special) + { + case 24: + // 24 G1 raise floor to highest adjacent + if (EV_DoFloor(line,raiseFloor) || demo_compatibility) + P_ChangeSwitchTexture(line,0); + break; + + case 46: + // 46 GR open door, stay open + EV_DoDoor(line,open); + P_ChangeSwitchTexture(line,1); + break; + + case 47: + // 47 G1 raise floor to nearest and change texture and type + if (EV_DoPlat(line,raiseToNearestAndChange,0) || demo_compatibility) + P_ChangeSwitchTexture(line,0); + break; + + //jff 1/30/98 added new gun linedefs here + // killough 1/31/98: added demo_compatibility check, added inner switch + + default: + if (!demo_compatibility) + switch (line->special) + { + case 197: + // Exit to next level + // killough 10/98: prevent zombies from exiting levels + if(thing->player && thing->player->health<=0 && !comp[comp_zombie]) + break; + P_ChangeSwitchTexture(line,0); + G_ExitLevel(); + break; + + case 198: + // Exit to secret level + // killough 10/98: prevent zombies from exiting levels + if(thing->player && thing->player->health<=0 && !comp[comp_zombie]) + break; + P_ChangeSwitchTexture(line,0); + G_SecretExitLevel(); + break; + //jff end addition of new gun linedefs + } + break; + } +} + + +// +// P_PlayerInSpecialSector() +// +// Called every tick frame +// that the player origin is in a special sector +// +// Changed to ignore sector types the engine does not recognize +// +void P_PlayerInSpecialSector (player_t* player) +{ + sector_t* sector; + + sector = player->mo->subsector->sector; + + // Falling, not all the way down yet? + // Sector specials don't apply in mid-air + if (player->mo->z != sector->floorheight) + return; + + // Has hit ground. + //jff add if to handle old vs generalized types + if (sector->special<32) // regular sector specials + { + switch (sector->special) + { + case 5: + // 5/10 unit damage per 31 ticks + if (!player->powers[pw_ironfeet]) + if (!(leveltime&0x1f)) + P_DamageMobj (player->mo, NULL, NULL, 10); + break; + + case 7: + // 2/5 unit damage per 31 ticks + if (!player->powers[pw_ironfeet]) + if (!(leveltime&0x1f)) + P_DamageMobj (player->mo, NULL, NULL, 5); + break; + + case 16: + // 10/20 unit damage per 31 ticks + case 4: + // 10/20 unit damage plus blinking light (light already spawned) + if (!player->powers[pw_ironfeet] + || (P_Random(pr_slimehurt)<5) ) // even with suit, take damage + { + if (!(leveltime&0x1f)) + P_DamageMobj (player->mo, NULL, NULL, 20); + } + break; + + case 9: + // Tally player in secret sector, clear secret special + player->secretcount++; + sector->special = 0; + break; + + case 11: + // Exit on health < 11, take 10/20 damage per 31 ticks + if (comp[comp_god]) /* killough 2/21/98: add compatibility switch */ + player->cheats &= ~CF_GODMODE; // on godmode cheat clearing + // does not affect invulnerability + if (!(leveltime&0x1f)) + P_DamageMobj (player->mo, NULL, NULL, 20); + + if (player->health <= 10) + G_ExitLevel(); + break; + + default: + //jff 1/24/98 Don't exit as DOOM2 did, just ignore + break; + }; + } + else //jff 3/14/98 handle extended sector types for secrets and damage + { + switch ((sector->special&DAMAGE_MASK)>>DAMAGE_SHIFT) + { + case 0: // no damage + break; + case 1: // 2/5 damage per 31 ticks + if (!player->powers[pw_ironfeet]) + if (!(leveltime&0x1f)) + P_DamageMobj (player->mo, NULL, NULL, 5); + break; + case 2: // 5/10 damage per 31 ticks + if (!player->powers[pw_ironfeet]) + if (!(leveltime&0x1f)) + P_DamageMobj (player->mo, NULL, NULL, 10); + break; + case 3: // 10/20 damage per 31 ticks + if (!player->powers[pw_ironfeet] + || (P_Random(pr_slimehurt)<5)) // take damage even with suit + { + if (!(leveltime&0x1f)) + P_DamageMobj (player->mo, NULL, NULL, 20); + } + break; + } + if (sector->special&SECRET_MASK) + { + player->secretcount++; + sector->special &= ~SECRET_MASK; + if (sector->special<32) // if all extended bits clear, + sector->special=0; // sector is not special anymore + } + + // phares 3/19/98: + // + // If FRICTION_MASK or PUSH_MASK is set, we don't care at this + // point, since the code to deal with those situations is + // handled by Thinkers. + + } +} + +// +// P_UpdateSpecials() +// +// Check level timer, frag counter, +// animate flats, scroll walls, +// change button textures +// +// Reads and modifies globals: +// levelTimer, levelTimeCount, +// levelFragLimit, levelFragLimitCount +// + +/* JDC static */boolean levelTimer; +/* JDC static */int levelTimeCount; +boolean levelFragLimit; // Ty 03/18/98 Added -frags support +int levelFragLimitCount; // Ty 03/18/98 Added -frags support + +void P_UpdateSpecials (void) +{ + anim_t* anim; + int pic; + int i; + + // Downcount level timer, exit level if elapsed + if (levelTimer == true) + { + levelTimeCount--; + if (!levelTimeCount) + G_ExitLevel(); + } + + // Check frag counters, if frag limit reached, exit level // Ty 03/18/98 + // Seems like the total frags should be kept in a simple + // array somewhere, but until they are... + if (levelFragLimit == true) // we used -frags so compare count + { + int k,m,fragcount,exitflag=false; + for (k=0;k= levelFragLimitCount) exitflag = true; + if (exitflag == true) break; // skip out of the loop--we're done + } + if (exitflag == true) + G_ExitLevel(); + } + + // Animate flats and textures globally + for (anim = anims ; anim < lastanim ; anim++) + { + for (i=anim->basepic ; ibasepic+anim->numpics ; i++) + { + pic = anim->basepic + ( (leveltime/anim->speed + i)%anim->numpics ); + if (anim->istexture) + texturetranslation[i] = pic; + else + flattranslation[i] = pic; + } + } + + // Check buttons (retriggerable switches) and change texture on timeout + for (i = 0; i < MAXBUTTONS; i++) + if (buttonlist[i].btimer) + { + buttonlist[i].btimer--; + if (!buttonlist[i].btimer) + { + switch(buttonlist[i].where) + { + case top: + sides[buttonlist[i].line->sidenum[0]].toptexture = + buttonlist[i].btexture; + break; + + case middle: + sides[buttonlist[i].line->sidenum[0]].midtexture = + buttonlist[i].btexture; + break; + + case bottom: + sides[buttonlist[i].line->sidenum[0]].bottomtexture = + buttonlist[i].btexture; + break; + } + { + /* don't take the address of the switch's sound origin, + * unless in a compatibility mode. */ + mobj_t *so = (mobj_t *)buttonlist[i].soundorg; + if (comp[comp_sound] || compatibility_level < prboom_6_compatibility) + /* since the buttonlist array is usually zeroed out, + * button popouts generally appear to come from (0,0) */ + so = (mobj_t *)&buttonlist[i].soundorg; + S_StartSound(so, sfx_swtchn); + } + memset(&buttonlist[i],0,sizeof(button_t)); + } + } +} + +////////////////////////////////////////////////////////////////////// +// +// Sector and Line special thinker spawning at level startup +// +////////////////////////////////////////////////////////////////////// + +// +// P_SpawnSpecials +// After the map has been loaded, +// scan for specials that spawn thinkers +// + +// Parses command line parameters. +void P_SpawnSpecials (void) +{ + sector_t* sector; + int i; + int episode; + + episode = 1; + if (W_CheckNumForName("texture2") >= 0) + episode = 2; + +#ifndef IPHONE // JDC: we set these directly + // See if -timer needs to be used. + levelTimer = false; + + i = M_CheckParm("-avg"); // Austin Virtual Gaming 20 min timer on DM play + if (i && deathmatch) + { + levelTimer = true; + levelTimeCount = 20 * 60 * TICRATE; + } + + i = M_CheckParm("-timer"); // user defined timer on game play + if (i && deathmatch) + { + int time; + time = atoi(myargv[i+1]) * 60 * TICRATE; + levelTimer = true; + levelTimeCount = time; + } + + // See if -frags has been used + levelFragLimit = false; + i = M_CheckParm("-frags"); // Ty 03/18/98 Added -frags support + if (i && deathmatch) + { + int frags; + frags = atoi(myargv[i+1]); + if (frags <= 0) frags = 10; // default 10 if no count provided + levelFragLimit = true; + levelFragLimitCount = frags; + } +#endif + + // Init special sectors. + sector = sectors; + for (i=0 ; ispecial) + continue; + + if (sector->special&SECRET_MASK) //jff 3/15/98 count extended + totalsecret++; // secret sectors too + + switch (sector->special&31) + { + case 1: + // random off + P_SpawnLightFlash (sector); + break; + + case 2: + // strobe fast + P_SpawnStrobeFlash(sector,FASTDARK,0); + break; + + case 3: + // strobe slow + P_SpawnStrobeFlash(sector,SLOWDARK,0); + break; + + case 4: + // strobe fast/death slime + P_SpawnStrobeFlash(sector,FASTDARK,0); + sector->special |= 3<special<32) //jff 3/14/98 bits don't count unless not + totalsecret++; // a generalized sector type + break; + + case 10: + // door close in 30 seconds + P_SpawnDoorCloseIn30 (sector); + break; + + case 12: + // sync strobe slow + P_SpawnStrobeFlash (sector, SLOWDARK, 1); + break; + + case 13: + // sync strobe fast + P_SpawnStrobeFlash (sector, FASTDARK, 1); + break; + + case 14: + // door raise in 5 minutes + P_SpawnDoorRaiseIn5Mins (sector, i); + break; + + case 17: + // fire flickering + P_SpawnFireFlicker(sector); + break; + } + } + + P_RemoveAllActiveCeilings(); // jff 2/22/98 use killough's scheme + + P_RemoveAllActivePlats(); // killough + + for (i = 0;i < MAXBUTTONS;i++) + memset(&buttonlist[i],0,sizeof(button_t)); + + // P_InitTagLists() must be called before P_FindSectorFromLineTag() + // or P_FindLineFromLineTag() can be called. + + P_InitTagLists(); // killough 1/30/98: Create xref tables for tags + + P_SpawnScrollers(); // killough 3/7/98: Add generalized scrollers + + P_SpawnFriction(); // phares 3/12/98: New friction model using linedefs + + P_SpawnPushers(); // phares 3/20/98: New pusher model using linedefs + + for (i=0; i= 0;) + sectors[s].heightsec = sec; + break; + + // killough 3/16/98: Add support for setting + // floor lighting independently (e.g. lava) + case 213: + sec = sides[*lines[i].sidenum].sector-sectors; + for (s = -1; (s = P_FindSectorFromLineTag(lines+i,s)) >= 0;) + sectors[s].floorlightsec = sec; + break; + + // killough 4/11/98: Add support for setting + // ceiling lighting independently + case 261: + sec = sides[*lines[i].sidenum].sector-sectors; + for (s = -1; (s = P_FindSectorFromLineTag(lines+i,s)) >= 0;) + sectors[s].ceilinglightsec = sec; + break; + + // killough 10/98: + // + // Support for sky textures being transferred from sidedefs. + // Allows scrolling and other effects (but if scrolling is + // used, then the same sector tag needs to be used for the + // sky sector, the sky-transfer linedef, and the scroll-effect + // linedef). Still requires user to use F_SKY1 for the floor + // or ceiling texture, to distinguish floor and ceiling sky. + + case 271: // Regular sky + case 272: // Same, only flipped + for (s = -1; (s = P_FindSectorFromLineTag(lines+i,s)) >= 0;) + sectors[s].sky = i | PL_SKYFLAT; + break; + } +} + +// killough 2/28/98: +// +// This function, with the help of r_plane.c and r_bsp.c, supports generalized +// scrolling floors and walls, with optional mobj-carrying properties, e.g. +// conveyor belts, rivers, etc. A linedef with a special type affects all +// tagged sectors the same way, by creating scrolling and/or object-carrying +// properties. Multiple linedefs may be used on the same sector and are +// cumulative, although the special case of scrolling a floor and carrying +// things on it, requires only one linedef. The linedef's direction determines +// the scrolling direction, and the linedef's length determines the scrolling +// speed. This was designed so that an edge around the sector could be used to +// control the direction of the sector's scrolling, which is usually what is +// desired. +// +// Process the active scrollers. +// +// This is the main scrolling code +// killough 3/7/98 + +void T_Scroll(scroll_t *s) +{ + fixed_t dx = s->dx, dy = s->dy; + + if (s->control != -1) + { // compute scroll amounts based on a sector's height changes + fixed_t height = sectors[s->control].floorheight + + sectors[s->control].ceilingheight; + fixed_t delta = height - s->last_height; + s->last_height = height; + dx = FixedMul(dx, delta); + dy = FixedMul(dy, delta); + } + + // killough 3/14/98: Add acceleration + if (s->accel) + { + s->vdx = dx += s->vdx; + s->vdy = dy += s->vdy; + } + + if (!(dx | dy)) // no-op if both (x,y) offsets 0 + return; + + switch (s->type) + { + side_t *side; + sector_t *sec; + fixed_t height, waterheight; // killough 4/4/98: add waterheight + msecnode_t *node; + mobj_t *thing; + + case sc_side: // killough 3/7/98: Scroll wall texture + side = sides + s->affectee; + side->textureoffset += dx; + side->rowoffset += dy; + break; + + case sc_floor: // killough 3/7/98: Scroll floor texture + sec = sectors + s->affectee; + sec->floor_xoffs += dx; + sec->floor_yoffs += dy; + break; + + case sc_ceiling: // killough 3/7/98: Scroll ceiling texture + sec = sectors + s->affectee; + sec->ceiling_xoffs += dx; + sec->ceiling_yoffs += dy; + break; + + case sc_carry: + + // killough 3/7/98: Carry things on floor + // killough 3/20/98: use new sector list which reflects true members + // killough 3/27/98: fix carrier bug + // killough 4/4/98: Underwater, carry things even w/o gravity + + sec = sectors + s->affectee; + height = sec->floorheight; + waterheight = sec->heightsec != -1 && + sectors[sec->heightsec].floorheight > height ? + sectors[sec->heightsec].floorheight : INT_MIN; + + for (node = sec->touching_thinglist; node; node = node->m_snext) + if (!((thing = node->m_thing)->flags & MF_NOCLIP) && + (!(thing->flags & MF_NOGRAVITY || thing->z > height) || + thing->z < waterheight)) + { + // Move objects only if on floor or underwater, + // non-floating, and clipped. + thing->momx += dx; + thing->momy += dy; + } + break; + + case sc_carry_ceiling: // to be added later + break; + } +} + +// +// Add_Scroller() +// +// Add a generalized scroller to the thinker list. +// +// type: the enumerated type of scrolling: floor, ceiling, floor carrier, +// wall, floor carrier & scroller +// +// (dx,dy): the direction and speed of the scrolling or its acceleration +// +// control: the sector whose heights control this scroller's effect +// remotely, or -1 if no control sector +// +// affectee: the index of the affected object (sector or sidedef) +// +// accel: non-zero if this is an accelerative effect +// + +static void Add_Scroller(int type, fixed_t dx, fixed_t dy, + int control, int affectee, int accel) +{ + scroll_t *s = Z_Malloc(sizeof *s, PU_LEVSPEC, 0); + s->thinker.function = T_Scroll; + s->type = type; + s->dx = dx; + s->dy = dy; + s->accel = accel; + s->vdx = s->vdy = 0; + if ((s->control = control) != -1) + s->last_height = + sectors[control].floorheight + sectors[control].ceilingheight; + s->affectee = affectee; + P_AddThinker(&s->thinker); +} + +// Adds wall scroller. Scroll amount is rotated with respect to wall's +// linedef first, so that scrolling towards the wall in a perpendicular +// direction is translated into vertical motion, while scrolling along +// the wall in a parallel direction is translated into horizontal motion. +// +// killough 5/25/98: cleaned up arithmetic to avoid drift due to roundoff +// +// killough 10/98: +// fix scrolling aliasing problems, caused by long linedefs causing overflowing + +static void Add_WallScroller(fixed_t dx, fixed_t dy, const line_t *l, + int control, int accel) +{ + fixed_t x = D_abs(l->dx), y = D_abs(l->dy), d; + if (y > x) + d = x, x = y, y = d; + d = FixedDiv(x, finesine[(tantoangle[FixedDiv(y,x) >> DBITS] + ANG90) + >> ANGLETOFINESHIFT]); + + // CPhipps - Import scroller calc overflow fix, compatibility optioned + if (compatibility_level >= lxdoom_1_compatibility) { + x = (fixed_t)(((int_64_t)dy * -(int_64_t)l->dy - (int_64_t)dx * (int_64_t)l->dx) / (int_64_t)d); // killough 10/98: + y = (fixed_t)(((int_64_t)dy * (int_64_t)l->dx - (int_64_t)dx * (int_64_t)l->dy) / (int_64_t)d); // Use long long arithmetic + } else { + x = -FixedDiv(FixedMul(dy, l->dy) + FixedMul(dx, l->dx), d); + y = -FixedDiv(FixedMul(dx, l->dy) - FixedMul(dy, l->dx), d); + } + Add_Scroller(sc_side, x, y, control, *l->sidenum, accel); +} + +// Amount (dx,dy) vector linedef is shifted right to get scroll amount +#define SCROLL_SHIFT 5 + +// Factor to scale scrolling effect into mobj-carrying properties = 3/32. +// (This is so scrolling floors and objects on them can move at same speed.) +#define CARRYFACTOR ((fixed_t)(FRACUNIT*.09375)) + +// Initialize the scrollers +static void P_SpawnScrollers(void) +{ + int i; + line_t *l = lines; + + for (i=0;idx >> SCROLL_SHIFT; // direction and speed of scrolling + fixed_t dy = l->dy >> SCROLL_SHIFT; + int control = -1, accel = 0; // no control sector or acceleration + int special = l->special; + + // killough 3/7/98: Types 245-249 are same as 250-254 except that the + // first side's sector's heights cause scrolling when they change, and + // this linedef controls the direction and speed of the scrolling. The + // most complicated linedef since donuts, but powerful :) + // + // killough 3/15/98: Add acceleration. Types 214-218 are the same but + // are accelerative. + + if (special >= 245 && special <= 249) // displacement scrollers + { + special += 250-245; + control = sides[*l->sidenum].sector - sectors; + } + else + if (special >= 214 && special <= 218) // accelerative scrollers + { + accel = 1; + special += 250-214; + control = sides[*l->sidenum].sector - sectors; + } + + switch (special) + { + register int s; + + case 250: // scroll effect ceiling + for (s=-1; (s = P_FindSectorFromLineTag(l,s)) >= 0;) + Add_Scroller(sc_ceiling, -dx, dy, control, s, accel); + break; + + case 251: // scroll effect floor + case 253: // scroll and carry objects on floor + for (s=-1; (s = P_FindSectorFromLineTag(l,s)) >= 0;) + Add_Scroller(sc_floor, -dx, dy, control, s, accel); + if (special != 253) + break; + + case 252: // carry objects on floor + dx = FixedMul(dx,CARRYFACTOR); + dy = FixedMul(dy,CARRYFACTOR); + for (s=-1; (s = P_FindSectorFromLineTag(l,s)) >= 0;) + Add_Scroller(sc_carry, dx, dy, control, s, accel); + break; + + // killough 3/1/98: scroll wall according to linedef + // (same direction and speed as scrolling floors) + case 254: + for (s=-1; (s = P_FindLineFromLineTag(l,s)) >= 0;) + if (s != i) + Add_WallScroller(dx, dy, lines+s, control, accel); + break; + + case 255: // killough 3/2/98: scroll according to sidedef offsets + s = lines[i].sidenum[0]; + Add_Scroller(sc_side, -sides[s].textureoffset, + sides[s].rowoffset, -1, s, accel); + break; + + case 48: // scroll first side + Add_Scroller(sc_side, FRACUNIT, 0, -1, lines[i].sidenum[0], accel); + break; + + case 85: // jff 1/30/98 2-way scroll + Add_Scroller(sc_side, -FRACUNIT, 0, -1, lines[i].sidenum[0], accel); + break; + } + } +} + +// e6y +// restored boom's friction code + +///////////////////////////// +// +// Add a friction thinker to the thinker list +// +// Add_Friction adds a new friction thinker to the list of active thinkers. +// + +static void Add_Friction(int friction, int movefactor, int affectee) + { + friction_t *f = Z_Malloc(sizeof *f, PU_LEVSPEC, 0); + + f->thinker.function/*.acp1*/ = /*(actionf_p1) */T_Friction; + f->friction = friction; + f->movefactor = movefactor; + f->affectee = affectee; + P_AddThinker(&f->thinker); + } + +///////////////////////////// +// +// This is where abnormal friction is applied to objects in the sectors. +// A friction thinker has been spawned for each sector where less or +// more friction should be applied. The amount applied is proportional to +// the length of the controlling linedef. + +void T_Friction(friction_t *f) + { + sector_t *sec; + mobj_t *thing; + msecnode_t* node; + + if (compatibility || !variable_friction) + return; + + sec = sectors + f->affectee; + + // Be sure the special sector type is still turned on. If so, proceed. + // Else, bail out; the sector type has been changed on us. + + if (!(sec->special & FRICTION_MASK)) + return; + + // Assign the friction value to players on the floor, non-floating, + // and clipped. Normally the object's friction value is kept at + // ORIG_FRICTION and this thinker changes it for icy or muddy floors. + + // In Phase II, you can apply friction to Things other than players. + + // When the object is straddling sectors with the same + // floorheight that have different frictions, use the lowest + // friction value (muddy has precedence over icy). + + node = sec->touching_thinglist; // things touching this sector + while (node) + { + thing = node->m_thing; + if (thing->player && + !(thing->flags & (MF_NOGRAVITY | MF_NOCLIP)) && + thing->z <= sec->floorheight) + { + if ((thing->friction == ORIG_FRICTION) || // normal friction? + (f->friction < thing->friction)) + { + thing->friction = f->friction; + thing->movefactor = f->movefactor; + } + } + node = node->m_snext; + } + } + + +// killough 3/7/98 -- end generalized scroll effects + +//////////////////////////////////////////////////////////////////////////// +// +// FRICTION EFFECTS +// +// phares 3/12/98: Start of friction effects +// +// As the player moves, friction is applied by decreasing the x and y +// momentum values on each tic. By varying the percentage of decrease, +// we can simulate muddy or icy conditions. In mud, the player slows +// down faster. In ice, the player slows down more slowly. +// +// The amount of friction change is controlled by the length of a linedef +// with type 223. A length < 100 gives you mud. A length > 100 gives you ice. +// +// Also, each sector where these effects are to take place is given a +// new special type _______. Changing the type value at runtime allows +// these effects to be turned on or off. +// +// Sector boundaries present problems. The player should experience these +// friction changes only when his feet are touching the sector floor. At +// sector boundaries where floor height changes, the player can find +// himself still 'in' one sector, but with his feet at the floor level +// of the next sector (steps up or down). To handle this, Thinkers are used +// in icy/muddy sectors. These thinkers examine each object that is touching +// their sectors, looking for players whose feet are at the same level as +// their floors. Players satisfying this condition are given new friction +// values that are applied by the player movement code later. +// +// killough 8/28/98: +// +// Completely redid code, which did not need thinkers, and which put a heavy +// drag on CPU. Friction is now a property of sectors, NOT objects inside +// them. All objects, not just players, are affected by it, if they touch +// the sector's floor. Code simpler and faster, only calling on friction +// calculations when an object needs friction considered, instead of doing +// friction calculations on every sector during every tic. +// +// Although this -might- ruin Boom demo sync involving friction, it's the only +// way, short of code explosion, to fix the original design bug. Fixing the +// design bug in Boom's original friction code, while maintaining demo sync +// under every conceivable circumstance, would double or triple code size, and +// would require maintenance of buggy legacy code which is only useful for old +// demos. Doom demos, which are more important IMO, are not affected by this +// change. +// +///////////////////////////// +// +// Initialize the sectors where friction is increased or decreased + +static void P_SpawnFriction(void) +{ + int i; + line_t *l = lines; + + // killough 8/28/98: initialize all sectors to normal friction first + for (i = 0; i < numsectors; i++) + { + sectors[i].friction = ORIG_FRICTION; + sectors[i].movefactor = ORIG_FRICTION_FACTOR; + } + + for (i = 0 ; i < numlines ; i++,l++) + if (l->special == 223) + { + int length = P_AproxDistance(l->dx,l->dy)>>FRACBITS; + int friction = (0x1EB8*length)/0x80 + 0xD000; + int movefactor, s; + + // The following check might seem odd. At the time of movement, + // the move distance is multiplied by 'friction/0x10000', so a + // higher friction value actually means 'less friction'. + + if (friction > ORIG_FRICTION) // ice + movefactor = ((0x10092 - friction)*(0x70))/0x158; + else + movefactor = ((friction - 0xDB34)*(0xA))/0x80; + + if (mbf_features) + { // killough 8/28/98: prevent odd situations + if (friction > FRACUNIT) + friction = FRACUNIT; + if (friction < 0) + friction = 0; + if (movefactor < 32) + movefactor = 32; + } + + for (s = -1; (s = P_FindSectorFromLineTag(l,s)) >= 0 ; ) + { + // killough 8/28/98: + // + // Instead of spawning thinkers, which are slow and expensive, + // modify the sector's own friction values. Friction should be + // a property of sectors, not objects which reside inside them. + // Original code scanned every object in every friction sector + // on every tic, adjusting its friction, putting unnecessary + // drag on CPU. New code adjusts friction of sector only once + // at level startup, and then uses this friction value. + + //e6y: boom's friction code for boom compatibility + if (!demo_compatibility && !mbf_features) + Add_Friction(friction,movefactor,s); + + sectors[s].friction = friction; + sectors[s].movefactor = movefactor; + } + } +} + +// +// phares 3/12/98: End of friction effects +// +//////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////// +// +// PUSH/PULL EFFECT +// +// phares 3/20/98: Start of push/pull effects +// +// This is where push/pull effects are applied to objects in the sectors. +// +// There are four kinds of push effects +// +// 1) Pushing Away +// +// Pushes you away from a point source defined by the location of an +// MT_PUSH Thing. The force decreases linearly with distance from the +// source. This force crosses sector boundaries and is felt w/in a circle +// whose center is at the MT_PUSH. The force is felt only if the point +// MT_PUSH can see the target object. +// +// 2) Pulling toward +// +// Same as Pushing Away except you're pulled toward an MT_PULL point +// source. This force crosses sector boundaries and is felt w/in a circle +// whose center is at the MT_PULL. The force is felt only if the point +// MT_PULL can see the target object. +// +// 3) Wind +// +// Pushes you in a constant direction. Full force above ground, half +// force on the ground, nothing if you're below it (water). +// +// 4) Current +// +// Pushes you in a constant direction. No force above ground, full +// force if on the ground or below it (water). +// +// The magnitude of the force is controlled by the length of a controlling +// linedef. The force vector for types 3 & 4 is determined by the angle +// of the linedef, and is constant. +// +// For each sector where these effects occur, the sector special type has +// to have the PUSH_MASK bit set. If this bit is turned off by a switch +// at run-time, the effect will not occur. The controlling sector for +// types 1 & 2 is the sector containing the MT_PUSH/MT_PULL Thing. + + +#define PUSH_FACTOR 7 + +///////////////////////////// +// +// Add a push thinker to the thinker list + +static void Add_Pusher(int type, int x_mag, int y_mag, mobj_t* source, int affectee) + { + pusher_t *p = Z_Malloc(sizeof *p, PU_LEVSPEC, 0); + + p->thinker.function = T_Pusher; + p->source = source; + p->type = type; + p->x_mag = x_mag>>FRACBITS; + p->y_mag = y_mag>>FRACBITS; + p->magnitude = P_AproxDistance(p->x_mag,p->y_mag); + if (source) // point source exist? + { + p->radius = (p->magnitude)<<(FRACBITS+1); // where force goes to zero + p->x = p->source->x; + p->y = p->source->y; + } + p->affectee = affectee; + P_AddThinker(&p->thinker); + } + +///////////////////////////// +// +// PIT_PushThing determines the angle and magnitude of the effect. +// The object's x and y momentum values are changed. +// +// tmpusher belongs to the point source (MT_PUSH/MT_PULL). +// +// killough 10/98: allow to affect things besides players + +pusher_t* tmpusher; // pusher structure for blockmap searches + +static boolean PIT_PushThing(mobj_t* thing) +{ + /* killough 10/98: made more general */ + if (!mbf_features ? + thing->player && !(thing->flags & (MF_NOCLIP | MF_NOGRAVITY)) : + (sentient(thing) || thing->flags & MF_SHOOTABLE) && + !(thing->flags & MF_NOCLIP)) + { + angle_t pushangle; + fixed_t speed; + fixed_t sx = tmpusher->x; + fixed_t sy = tmpusher->y; + + speed = (tmpusher->magnitude - + ((P_AproxDistance(thing->x - sx,thing->y - sy) + >>FRACBITS)>>1))<<(FRACBITS-PUSH_FACTOR-1); + + // killough 10/98: make magnitude decrease with square + // of distance, making it more in line with real nature, + // so long as it's still in range with original formula. + // + // Removes angular distortion, and makes effort required + // to stay close to source, grow increasingly hard as you + // get closer, as expected. Still, it doesn't consider z :( + + if (speed > 0 && mbf_features) + { + int x = (thing->x-sx) >> FRACBITS; + int y = (thing->y-sy) >> FRACBITS; + speed = (int)(((uint_64_t) tmpusher->magnitude << 23) / (x*x+y*y+1)); + } + + // If speed <= 0, you're outside the effective radius. You also have + // to be able to see the push/pull source point. + + if (speed > 0 && P_CheckSight(thing,tmpusher->source)) + { + pushangle = R_PointToAngle2(thing->x,thing->y,sx,sy); + if (tmpusher->source->type == MT_PUSH) + pushangle += ANG180; // away + pushangle >>= ANGLETOFINESHIFT; + thing->momx += FixedMul(speed,finecosine[pushangle]); + thing->momy += FixedMul(speed,finesine[pushangle]); + } + } + return true; +} + +///////////////////////////// +// +// T_Pusher looks for all objects that are inside the radius of +// the effect. +// + +void T_Pusher(pusher_t *p) + { + sector_t *sec; + mobj_t *thing; + msecnode_t* node; + int xspeed,yspeed; + int xl,xh,yl,yh,bx,by; + int radius; + int ht = 0; + + if (!allow_pushers) + return; + + sec = sectors + p->affectee; + + // Be sure the special sector type is still turned on. If so, proceed. + // Else, bail out; the sector type has been changed on us. + + if (!(sec->special & PUSH_MASK)) + return; + + // For constant pushers (wind/current) there are 3 situations: + // + // 1) Affected Thing is above the floor. + // + // Apply the full force if wind, no force if current. + // + // 2) Affected Thing is on the ground. + // + // Apply half force if wind, full force if current. + // + // 3) Affected Thing is below the ground (underwater effect). + // + // Apply no force if wind, full force if current. + + if (p->type == p_push) + { + + // Seek out all pushable things within the force radius of this + // point pusher. Crosses sectors, so use blockmap. + + tmpusher = p; // MT_PUSH/MT_PULL point source + radius = p->radius; // where force goes to zero + tmbbox[BOXTOP] = p->y + radius; + tmbbox[BOXBOTTOM] = p->y - radius; + tmbbox[BOXRIGHT] = p->x + radius; + tmbbox[BOXLEFT] = p->x - radius; + + xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT; + xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT; + yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT; + yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT; + for (bx=xl ; bx<=xh ; bx++) + for (by=yl ; by<=yh ; by++) + P_BlockThingsIterator(bx,by,PIT_PushThing); + return; + } + + // constant pushers p_wind and p_current + + if (sec->heightsec != -1) // special water sector? + ht = sectors[sec->heightsec].floorheight; + node = sec->touching_thinglist; // things touching this sector + for ( ; node ; node = node->m_snext) + { + thing = node->m_thing; + if (!thing->player || (thing->flags & (MF_NOGRAVITY | MF_NOCLIP))) + continue; + if (p->type == p_wind) + { + if (sec->heightsec == -1) // NOT special water sector + if (thing->z > thing->floorz) // above ground + { + xspeed = p->x_mag; // full force + yspeed = p->y_mag; + } + else // on ground + { + xspeed = (p->x_mag)>>1; // half force + yspeed = (p->y_mag)>>1; + } + else // special water sector + { + if (thing->z > ht) // above ground + { + xspeed = p->x_mag; // full force + yspeed = p->y_mag; + } + else if (thing->player->viewz < ht) // underwater + xspeed = yspeed = 0; // no force + else // wading in water + { + xspeed = (p->x_mag)>>1; // half force + yspeed = (p->y_mag)>>1; + } + } + } + else // p_current + { + if (sec->heightsec == -1) // NOT special water sector + if (thing->z > sec->floorheight) // above ground + xspeed = yspeed = 0; // no force + else // on ground + { + xspeed = p->x_mag; // full force + yspeed = p->y_mag; + } + else // special water sector + if (thing->z > ht) // above ground + xspeed = yspeed = 0; // no force + else // underwater + { + xspeed = p->x_mag; // full force + yspeed = p->y_mag; + } + } + thing->momx += xspeed<<(FRACBITS-PUSH_FACTOR); + thing->momy += yspeed<<(FRACBITS-PUSH_FACTOR); + } + } + +///////////////////////////// +// +// P_GetPushThing() returns a pointer to an MT_PUSH or MT_PULL thing, +// NULL otherwise. + +mobj_t* P_GetPushThing(int s) + { + mobj_t* thing; + sector_t* sec; + + sec = sectors + s; + thing = sec->thinglist; + while (thing) + { + switch(thing->type) + { + case MT_PUSH: + case MT_PULL: + return thing; + default: + break; + } + thing = thing->snext; + } + return NULL; + } + +///////////////////////////// +// +// Initialize the sectors where pushers are present +// + +static void P_SpawnPushers(void) + { + int i; + line_t *l = lines; + register int s; + mobj_t* thing; + + for (i = 0 ; i < numlines ; i++,l++) + switch(l->special) + { + case 224: // wind + for (s = -1; (s = P_FindSectorFromLineTag(l,s)) >= 0 ; ) + Add_Pusher(p_wind,l->dx,l->dy,NULL,s); + break; + case 225: // current + for (s = -1; (s = P_FindSectorFromLineTag(l,s)) >= 0 ; ) + Add_Pusher(p_current,l->dx,l->dy,NULL,s); + break; + case 226: // push/pull + for (s = -1; (s = P_FindSectorFromLineTag(l,s)) >= 0 ; ) + { + thing = P_GetPushThing(s); + if (thing) // No MT_P* means no effect + Add_Pusher(p_push,l->dx,l->dy,thing,s); + } + break; + } + } + +// +// phares 3/20/98: End of Pusher effects +// +//////////////////////////////////////////////////////////////////////////// diff --git a/common/prboom/p_spec.h b/common/prboom/p_spec.h new file mode 100755 index 0000000..1d5aa2b --- /dev/null +++ b/common/prboom/p_spec.h @@ -0,0 +1,1141 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: definitions, declarations and prototypes for specials + * + *-----------------------------------------------------------------------------*/ + +#ifndef __P_SPEC__ +#define __P_SPEC__ + +#include "r_defs.h" +#include "d_player.h" + +// Define values for map objects +#define MO_TELEPORTMAN 14 + +// p_floor + +#define ELEVATORSPEED (FRACUNIT*4) +#define FLOORSPEED FRACUNIT + +// p_ceilng + +#define CEILSPEED FRACUNIT +#define CEILWAIT 150 + +// p_doors + +#define VDOORSPEED (FRACUNIT*2) +#define VDOORWAIT 150 + +// p_plats + +#define PLATWAIT 3 +#define PLATSPEED FRACUNIT + +// p_switch + +// 4 players, 4 buttons each at once, max. +// killough 2/14/98: redefine in terms of MAXPLAYERS +#define MAXBUTTONS (MAXPLAYERS*4) + +// 1 second, in ticks. +#define BUTTONTIME TICRATE + +// p_lights + +#define GLOWSPEED 8 +#define STROBEBRIGHT 5 +#define FASTDARK 15 +#define SLOWDARK 35 + +//jff 3/14/98 add bits and shifts for generalized sector types + +#define DAMAGE_MASK 0x60 +#define DAMAGE_SHIFT 5 +#define SECRET_MASK 0x80 +#define SECRET_SHIFT 7 +#define FRICTION_MASK 0x100 +#define FRICTION_SHIFT 8 +#define PUSH_MASK 0x200 +#define PUSH_SHIFT 9 + +//jff 02/04/98 Define masks, shifts, for fields in +// generalized linedef types + +#define GenEnd 0x8000 +#define GenFloorBase 0x6000 +#define GenCeilingBase 0x4000 +#define GenDoorBase 0x3c00 +#define GenLockedBase 0x3800 +#define GenLiftBase 0x3400 +#define GenStairsBase 0x3000 +#define GenCrusherBase 0x2F80 + +#define TriggerType 0x0007 +#define TriggerTypeShift 0 + +// define masks and shifts for the floor type fields + +#define FloorCrush 0x1000 +#define FloorChange 0x0c00 +#define FloorTarget 0x0380 +#define FloorDirection 0x0040 +#define FloorModel 0x0020 +#define FloorSpeed 0x0018 + +#define FloorCrushShift 12 +#define FloorChangeShift 10 +#define FloorTargetShift 7 +#define FloorDirectionShift 6 +#define FloorModelShift 5 +#define FloorSpeedShift 3 + +// define masks and shifts for the ceiling type fields + +#define CeilingCrush 0x1000 +#define CeilingChange 0x0c00 +#define CeilingTarget 0x0380 +#define CeilingDirection 0x0040 +#define CeilingModel 0x0020 +#define CeilingSpeed 0x0018 + +#define CeilingCrushShift 12 +#define CeilingChangeShift 10 +#define CeilingTargetShift 7 +#define CeilingDirectionShift 6 +#define CeilingModelShift 5 +#define CeilingSpeedShift 3 + +// define masks and shifts for the lift type fields + +#define LiftTarget 0x0300 +#define LiftDelay 0x00c0 +#define LiftMonster 0x0020 +#define LiftSpeed 0x0018 + +#define LiftTargetShift 8 +#define LiftDelayShift 6 +#define LiftMonsterShift 5 +#define LiftSpeedShift 3 + +// define masks and shifts for the stairs type fields + +#define StairIgnore 0x0200 +#define StairDirection 0x0100 +#define StairStep 0x00c0 +#define StairMonster 0x0020 +#define StairSpeed 0x0018 + +#define StairIgnoreShift 9 +#define StairDirectionShift 8 +#define StairStepShift 6 +#define StairMonsterShift 5 +#define StairSpeedShift 3 + +// define masks and shifts for the crusher type fields + +#define CrusherSilent 0x0040 +#define CrusherMonster 0x0020 +#define CrusherSpeed 0x0018 + +#define CrusherSilentShift 6 +#define CrusherMonsterShift 5 +#define CrusherSpeedShift 3 + +// define masks and shifts for the door type fields + +#define DoorDelay 0x0300 +#define DoorMonster 0x0080 +#define DoorKind 0x0060 +#define DoorSpeed 0x0018 + +#define DoorDelayShift 8 +#define DoorMonsterShift 7 +#define DoorKindShift 5 +#define DoorSpeedShift 3 + +// define masks and shifts for the locked door type fields + +#define LockedNKeys 0x0200 +#define LockedKey 0x01c0 +#define LockedKind 0x0020 +#define LockedSpeed 0x0018 + +#define LockedNKeysShift 9 +#define LockedKeyShift 6 +#define LockedKindShift 5 +#define LockedSpeedShift 3 + +// define names for the TriggerType field of the general linedefs + +typedef enum +{ + WalkOnce, + WalkMany, + SwitchOnce, + SwitchMany, + GunOnce, + GunMany, + PushOnce, + PushMany, +} triggertype_e; + +// define names for the Speed field of the general linedefs + +typedef enum +{ + SpeedSlow, + SpeedNormal, + SpeedFast, + SpeedTurbo, +} motionspeed_e; + +// define names for the Target field of the general floor + +typedef enum +{ + FtoHnF, + FtoLnF, + FtoNnF, + FtoLnC, + FtoC, + FbyST, + Fby24, + Fby32, +} floortarget_e; + +// define names for the Changer Type field of the general floor + +typedef enum +{ + FNoChg, + FChgZero, + FChgTxt, + FChgTyp, +} floorchange_e; + +// define names for the Change Model field of the general floor + +typedef enum +{ + FTriggerModel, + FNumericModel, +} floormodel_t; + +// define names for the Target field of the general ceiling + +typedef enum +{ + CtoHnC, + CtoLnC, + CtoNnC, + CtoHnF, + CtoF, + CbyST, + Cby24, + Cby32, +} ceilingtarget_e; + +// define names for the Changer Type field of the general ceiling + +typedef enum +{ + CNoChg, + CChgZero, + CChgTxt, + CChgTyp, +} ceilingchange_e; + +// define names for the Change Model field of the general ceiling + +typedef enum +{ + CTriggerModel, + CNumericModel, +} ceilingmodel_t; + +// define names for the Target field of the general lift + +typedef enum +{ + F2LnF, + F2NnF, + F2LnC, + LnF2HnF, +} lifttarget_e; + +// define names for the door Kind field of the general ceiling + +typedef enum +{ + OdCDoor, + ODoor, + CdODoor, + CDoor, +} doorkind_e; + +// define names for the locked door Kind field of the general ceiling + +typedef enum +{ + AnyKey, + RCard, + BCard, + YCard, + RSkull, + BSkull, + YSkull, + AllKeys, +} keykind_e; + +////////////////////////////////////////////////////////////////// +// +// enums for classes of linedef triggers +// +////////////////////////////////////////////////////////////////// + +//jff 2/23/98 identify the special classes that can share sectors + +typedef enum +{ + floor_special, + ceiling_special, + lighting_special, +} special_e; + +//jff 3/15/98 pure texture/type change for better generalized support +typedef enum +{ + trigChangeOnly, + numChangeOnly, +} change_e; + +// p_plats + +typedef enum +{ + up, + down, + waiting, + in_stasis +} plat_e; + +typedef enum +{ + perpetualRaise, + downWaitUpStay, + raiseAndChange, + raiseToNearestAndChange, + blazeDWUS, + genLift, //jff added to support generalized Plat types + genPerpetual, + toggleUpDn, //jff 3/14/98 added to support instant toggle type + +} plattype_e; + +// p_doors + +typedef enum +{ + normal, + close30ThenOpen, + close, + open, + raiseIn5Mins, + blazeRaise, + blazeOpen, + blazeClose, + + //jff 02/05/98 add generalize door types + genRaise, + genBlazeRaise, + genOpen, + genBlazeOpen, + genClose, + genBlazeClose, + genCdO, + genBlazeCdO, +} vldoor_e; + +// p_ceilng + +typedef enum +{ + lowerToFloor, + raiseToHighest, + lowerToLowest, + lowerToMaxFloor, + lowerAndCrush, + crushAndRaise, + fastCrushAndRaise, + silentCrushAndRaise, + + //jff 02/04/98 add types for generalized ceiling mover + genCeiling, + genCeilingChg, + genCeilingChg0, + genCeilingChgT, + + //jff 02/05/98 add types for generalized ceiling mover + genCrusher, + genSilentCrusher, + +} ceiling_e; + +// p_floor + +typedef enum +{ + // lower floor to highest surrounding floor + lowerFloor, + + // lower floor to lowest surrounding floor + lowerFloorToLowest, + + // lower floor to highest surrounding floor VERY FAST + turboLower, + + // raise floor to lowest surrounding CEILING + raiseFloor, + + // raise floor to next highest surrounding floor + raiseFloorToNearest, + + //jff 02/03/98 lower floor to next lowest neighbor + lowerFloorToNearest, + + //jff 02/03/98 lower floor 24 absolute + lowerFloor24, + + //jff 02/03/98 lower floor 32 absolute + lowerFloor32Turbo, + + // raise floor to shortest height texture around it + raiseToTexture, + + // lower floor to lowest surrounding floor + // and change floorpic + lowerAndChange, + + raiseFloor24, + + //jff 02/03/98 raise floor 32 absolute + raiseFloor32Turbo, + + raiseFloor24AndChange, + raiseFloorCrush, + + // raise to next highest floor, turbo-speed + raiseFloorTurbo, + donutRaise, + raiseFloor512, + + //jff 02/04/98 add types for generalized floor mover + genFloor, + genFloorChg, + genFloorChg0, + genFloorChgT, + + //new types for stair builders + buildStair, + genBuildStair, +} floor_e; + +typedef enum +{ + build8, // slowly build by 8 + turbo16 // quickly build by 16 + +} stair_e; + +typedef enum +{ + elevateUp, + elevateDown, + elevateCurrent, +} elevator_e; + +////////////////////////////////////////////////////////////////// +// +// general enums +// +////////////////////////////////////////////////////////////////// + +// texture type enum +typedef enum +{ + top, + middle, + bottom + +} bwhere_e; + +// crush check returns +typedef enum +{ + ok, + crushed, + pastdest +} result_e; + +////////////////////////////////////////////////////////////////// +// +// linedef and sector special data types +// +////////////////////////////////////////////////////////////////// + +// p_switch + +// switch animation structure type + +#if defined(__MWERKS__) +#pragma options align=packed +#endif + +typedef struct +{ + char name1[9]; + char name2[9]; + short episode; +} PACKEDATTR switchlist_t; //jff 3/23/98 pack to read from memory + +#if defined(__MWERKS__) +#pragma options align=reset +#endif + +typedef struct +{ + line_t* line; + bwhere_e where; + int btexture; + int btimer; + mobj_t* soundorg; + +} button_t; + +// p_lights + +typedef struct +{ + thinker_t thinker; + sector_t* sector; + int count; + int maxlight; + int minlight; + +} fireflicker_t; + +typedef struct +{ + thinker_t thinker; + sector_t* sector; + int count; + int maxlight; + int minlight; + int maxtime; + int mintime; + +} lightflash_t; + +typedef struct +{ + thinker_t thinker; + sector_t* sector; + int count; + int minlight; + int maxlight; + int darktime; + int brighttime; + +} strobe_t; + +typedef struct +{ + thinker_t thinker; + sector_t* sector; + int minlight; + int maxlight; + int direction; + +} glow_t; + +// p_plats + +typedef struct +{ + thinker_t thinker; + sector_t* sector; + fixed_t speed; + fixed_t low; + fixed_t high; + int wait; + int count; + plat_e status; + plat_e oldstatus; + boolean crush; + int tag; + plattype_e type; + + struct platlist *list; // killough +} plat_t; + +// New limit-free plat structure -- killough + +typedef struct platlist { + plat_t *plat; + struct platlist *next,**prev; +} platlist_t; + +// p_ceilng + +typedef struct +{ + thinker_t thinker; + vldoor_e type; + sector_t* sector; + fixed_t topheight; + fixed_t speed; + + // 1 = up, 0 = waiting at top, -1 = down + int direction; + + // tics to wait at the top + int topwait; + // (keep in case a door going down is reset) + // when it reaches 0, start going down + int topcountdown; + + //jff 1/31/98 keep track of line door is triggered by + line_t *line; + + /* killough 10/98: sector tag for gradual lighting effects */ + int lighttag; +} vldoor_t; + +// p_doors + +typedef struct +{ + thinker_t thinker; + ceiling_e type; + sector_t* sector; + fixed_t bottomheight; + fixed_t topheight; + fixed_t speed; + fixed_t oldspeed; + boolean crush; + + //jff 02/04/98 add these to support ceiling changers + int newspecial; + int oldspecial; //jff 3/14/98 add to fix bug in change transfers + short texture; + + // 1 = up, 0 = waiting, -1 = down + int direction; + + // ID + int tag; + int olddirection; + struct ceilinglist *list; // jff 2/22/98 copied from killough's plats +} ceiling_t; + +typedef struct ceilinglist { + ceiling_t *ceiling; + struct ceilinglist *next,**prev; +} ceilinglist_t; + +// p_floor + +typedef struct +{ + thinker_t thinker; + floor_e type; + boolean crush; + sector_t* sector; + int direction; + int newspecial; + int oldspecial; //jff 3/14/98 add to fix bug in change transfers + short texture; + fixed_t floordestheight; + fixed_t speed; + +} floormove_t; + +typedef struct +{ + thinker_t thinker; + elevator_e type; + sector_t* sector; + int direction; + fixed_t floordestheight; + fixed_t ceilingdestheight; + fixed_t speed; +} elevator_t; + +// p_spec + +// killough 3/7/98: Add generalized scroll effects + +typedef struct { + thinker_t thinker; // Thinker structure for scrolling + fixed_t dx, dy; // (dx,dy) scroll speeds + int affectee; // Number of affected sidedef, sector, tag, or whatever + int control; // Control sector (-1 if none) used to control scrolling + fixed_t last_height; // Last known height of control sector + fixed_t vdx, vdy; // Accumulated velocity if accelerative + int accel; // Whether it's accelerative + enum + { + sc_side, + sc_floor, + sc_ceiling, + sc_carry, + sc_carry_ceiling, // killough 4/11/98: carry objects hanging on ceilings + } type; // Type of scroll effect +} scroll_t; + +// phares 3/12/98: added new model of friction for ice/sludge effects + +typedef struct { + thinker_t thinker; // Thinker structure for friction + int friction; // friction value (E800 = normal) + int movefactor; // inertia factor when adding to momentum + int affectee; // Number of affected sector +} friction_t; + +// phares 3/20/98: added new model of Pushers for push/pull effects + +typedef struct { + thinker_t thinker; // Thinker structure for Pusher + enum + { + p_push, + p_pull, + p_wind, + p_current, + } type; + mobj_t* source; // Point source if point pusher + int x_mag; // X Strength + int y_mag; // Y Strength + int magnitude; // Vector strength for point pusher + int radius; // Effective radius for point pusher + int x; // X of point source if point pusher + int y; // Y of point source if point pusher + int affectee; // Number of affected sector +} pusher_t; + +////////////////////////////////////////////////////////////////// +// +// external data declarations +// +////////////////////////////////////////////////////////////////// + +// list of retriggerable buttons active +extern button_t buttonlist[MAXBUTTONS]; + +extern platlist_t *activeplats; // killough 2/14/98 + +extern ceilinglist_t *activeceilings; // jff 2/22/98 + +//////////////////////////////////////////////////////////////// +// +// Linedef and sector special utility function prototypes +// +//////////////////////////////////////////////////////////////// + +int twoSided +( int sector, + int line ); + +sector_t* getSector +( int currentSector, + int line, + int side ); + +side_t* getSide +( int currentSector, + int line, + int side ); + +fixed_t P_FindLowestFloorSurrounding +( sector_t* sec ); + +fixed_t P_FindHighestFloorSurrounding +( sector_t* sec ); + +fixed_t P_FindNextHighestFloor +( sector_t* sec, + int currentheight ); + +fixed_t P_FindNextLowestFloor +( sector_t* sec, + int currentheight ); + +fixed_t P_FindLowestCeilingSurrounding +( sector_t* sec ); // jff 2/04/98 + +fixed_t P_FindHighestCeilingSurrounding +( sector_t* sec ); // jff 2/04/98 + +fixed_t P_FindNextLowestCeiling +( sector_t *sec, + int currentheight ); // jff 2/04/98 + +fixed_t P_FindNextHighestCeiling +( sector_t *sec, + int currentheight ); // jff 2/04/98 + +fixed_t P_FindShortestTextureAround +( int secnum ); // jff 2/04/98 + +fixed_t P_FindShortestUpperAround +( int secnum ); // jff 2/04/98 + +sector_t* P_FindModelFloorSector +( fixed_t floordestheight, + int secnum ); //jff 02/04/98 + +sector_t* P_FindModelCeilingSector +( fixed_t ceildestheight, + int secnum ); //jff 02/04/98 + +int P_FindSectorFromLineTag +( const line_t *line, + int start ); // killough 4/17/98 + +int P_FindLineFromLineTag +( const line_t *line, + int start ); // killough 4/17/98 + +int P_FindMinSurroundingLight +( sector_t* sector, + int max ); + +sector_t* getNextSector +( line_t* line, + sector_t* sec ); + +int P_CheckTag +(line_t *line); // jff 2/27/98 + +boolean P_CanUnlockGenDoor +( line_t* line, + player_t* player); + +boolean PUREFUNC P_SectorActive +( special_e t, + const sector_t* s ); + +boolean PUREFUNC P_IsSecret +( const sector_t *sec ); + +boolean PUREFUNC P_WasSecret +( const sector_t *sec ); + +void P_ChangeSwitchTexture +( line_t* line, + int useAgain ); + +//////////////////////////////////////////////////////////////// +// +// Linedef and sector special action function prototypes +// +//////////////////////////////////////////////////////////////// + +// p_lights + +void T_LightFlash +( lightflash_t* flash ); + +void T_StrobeFlash +( strobe_t* flash ); + +// jff 8/8/98 add missing thinker for flicker +void T_FireFlicker +( fireflicker_t* flick ); + +void T_Glow +( glow_t* g ); + +// p_plats + +void T_PlatRaise +( plat_t* plat ); + +// p_doors + +void T_VerticalDoor +( vldoor_t* door ); + +// p_ceilng + +void T_MoveCeiling +( ceiling_t* ceiling ); + +// p_floor + +result_e T_MovePlane +( sector_t* sector, + fixed_t speed, + fixed_t dest, + boolean crush, + int floorOrCeiling, + int direction ); + +void T_MoveFloor +( floormove_t* floor ); + +void T_MoveElevator +( elevator_t* elevator ); + +// p_spec + +void T_Scroll +( scroll_t * ); // killough 3/7/98: scroll effect thinker + +void T_Friction +( friction_t * ); // phares 3/12/98: friction thinker + +void T_Pusher +( pusher_t * ); // phares 3/20/98: Push thinker + +//////////////////////////////////////////////////////////////// +// +// Linedef and sector special handler prototypes +// +//////////////////////////////////////////////////////////////// + +// p_telept + +int EV_Teleport +( line_t* line, + int side, + mobj_t* thing ); + +// killough 2/14/98: Add silent teleporter +int EV_SilentTeleport +( line_t* line, + int side, + mobj_t* thing ); + +// killough 1/31/98: Add silent line teleporter +int EV_SilentLineTeleport +( line_t* line, + int side, + mobj_t* thing, + boolean reverse); + +// p_floor + +int +EV_DoElevator +( line_t* line, + elevator_e type ); + +int EV_BuildStairs +( line_t* line, + stair_e type ); + +int EV_DoFloor +( line_t* line, + floor_e floortype ); + +// p_ceilng + +int EV_DoCeiling +( line_t* line, + ceiling_e type ); + +int EV_CeilingCrushStop +( line_t* line ); + +// p_doors + +int EV_VerticalDoor +( line_t* line, + mobj_t* thing ); + +int EV_DoDoor +( line_t* line, + vldoor_e type ); + +int EV_DoLockedDoor +( line_t* line, + vldoor_e type, + mobj_t* thing ); + +// p_lights + +int EV_StartLightStrobing +( line_t* line ); + +int EV_TurnTagLightsOff +( line_t* line ); + +int EV_LightTurnOn +( line_t* line, + int bright ); + +int EV_LightTurnOnPartway(line_t* line, fixed_t level); // killough 10/10/98 + +// p_floor + +int EV_DoChange +( line_t* line, + change_e changetype ); + +int EV_DoDonut +( line_t* line ); + +// p_plats + +int EV_DoPlat +( line_t* line, + plattype_e type, + int amount ); + +int EV_StopPlat +( line_t* line ); + +// p_genlin + +int EV_DoGenFloor +( line_t* line ); + +int EV_DoGenCeiling +( line_t* line ); + +int EV_DoGenLift +( line_t* line ); + +int EV_DoGenStairs +( line_t* line ); + +int EV_DoGenCrusher +( line_t* line ); + +int EV_DoGenDoor +( line_t* line ); + +int EV_DoGenLockedDoor +( line_t* line ); + +//////////////////////////////////////////////////////////////// +// +// Linedef and sector special thinker spawning +// +//////////////////////////////////////////////////////////////// + +// at game start +void P_InitPicAnims +( void ); + +void P_InitSwitchList +( void ); + +// at map load +void P_SpawnSpecials +( void ); + +// every tic +void P_UpdateSpecials +( void ); + +// when needed +boolean P_UseSpecialLine +( mobj_t* thing, + line_t* line, + int side ); + +void P_ShootSpecialLine +( mobj_t* thing, + line_t* line ); + +void P_CrossSpecialLine(line_t *line, int side, mobj_t *thing); + +void P_PlayerInSpecialSector +( player_t* player ); + +// p_lights + +void P_SpawnFireFlicker +( sector_t* sector ); + +void P_SpawnLightFlash +( sector_t* sector ); + +void P_SpawnStrobeFlash +( sector_t* sector, + int fastOrSlow, + int inSync ); + +void P_SpawnGlowingLight +( sector_t* sector ); + +// p_plats + +void P_AddActivePlat +( plat_t* plat ); + +void P_RemoveActivePlat +( plat_t* plat ); + +void P_RemoveAllActivePlats +( void ); // killough + +void P_ActivateInStasis +( int tag ); + +// p_doors + +void P_SpawnDoorCloseIn30 +( sector_t* sec ); + +void P_SpawnDoorRaiseIn5Mins +( sector_t* sec, + int secnum ); + +// p_ceilng + +void P_RemoveActiveCeiling +( ceiling_t* ceiling ); //jff 2/22/98 + +void P_RemoveAllActiveCeilings +( void ); //jff 2/22/98 + +void P_AddActiveCeiling +( ceiling_t* c ); + +int P_ActivateInStasisCeiling +( line_t* line ); + +mobj_t* P_GetPushThing(int); // phares 3/23/98 + +#endif diff --git a/common/prboom/p_switch.c b/common/prboom/p_switch.c new file mode 100755 index 0000000..68a543e --- /dev/null +++ b/common/prboom/p_switch.c @@ -0,0 +1,1159 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Switches, buttons. Two-state animation. Exits. + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" +#include "w_wad.h" +#include "r_main.h" +#include "p_spec.h" +#include "g_game.h" +#include "s_sound.h" +#include "sounds.h" +#include "lprintf.h" + +// killough 2/8/98: Remove switch limit + +static int *switchlist; // killough +static int max_numswitches; // killough +static int numswitches; // killough + +button_t buttonlist[MAXBUTTONS]; + +// +// P_InitSwitchList() +// +// Only called at game initialization in order to list the set of switches +// and buttons known to the engine. This enables their texture to change +// when activated, and in the case of buttons, change back after a timeout. +// +// This routine modified to read its data from a predefined lump or +// PWAD lump called SWITCHES rather than a static table in this module to +// allow wad designers to insert or modify switches. +// +// Lump format is an array of byte packed switchlist_t structures, terminated +// by a structure with episode == -0. The lump can be generated from a +// text source file using SWANTBLS.EXE, distributed with the BOOM utils. +// The standard list of switches and animations is contained in the example +// source text file DEFSWANI.DAT also in the BOOM util distribution. +// +// Rewritten by Lee Killough to remove limit 2/8/98 +// +void P_InitSwitchList(void) +{ + int i, index = 0; + int episode = (gamemode == registered || gamemode==retail) ? + 2 : gamemode == commercial ? 3 : 1; + const switchlist_t *alphSwitchList; //jff 3/23/98 pointer to switch table + int lump = W_GetNumForName("SWITCHES"); // cph - new wad lump handling + + //jff 3/23/98 read the switch table from a predefined lump + alphSwitchList = (const switchlist_t *)W_CacheLumpNum(lump); + + for (i=0;;i++) + { + if (index+1 >= max_numswitches) + switchlist = realloc(switchlist, sizeof *switchlist * + (max_numswitches = max_numswitches ? max_numswitches*2 : 8)); + if (SHORT(alphSwitchList[i].episode) <= episode) //jff 5/11/98 endianess + { + int texture1, texture2; + + if (!SHORT(alphSwitchList[i].episode)) + break; + + // Ignore switches referencing unknown texture names, instead of exiting. + // Warn if either one is missing, but only add if both are valid. + texture1 = R_CheckTextureNumForName(alphSwitchList[i].name1); + if (texture1 == -1) + lprintf(LO_WARN, "P_InitSwitchList: unknown texture %s\n", + alphSwitchList[i].name1); + texture2 = R_CheckTextureNumForName(alphSwitchList[i].name2); + if (texture2 == -1) + lprintf(LO_WARN, "P_InitSwitchList: unknown texture %s\n", + alphSwitchList[i].name2); + if (texture1 != -1 && texture2 != -1) { + switchlist[index++] = texture1; + switchlist[index++] = texture2; + } + } + } + + numswitches = index/2; + switchlist[index] = -1; + W_UnlockLumpNum(lump); +} + +// +// P_StartButton() +// +// Start a button (retriggerable switch) counting down till it turns off. +// +// Passed the linedef the button is on, which texture on the sidedef contains +// the button, the texture number of the button, and the time the button is +// to remain active in gametics. +// No return. +// +static void P_StartButton +( line_t* line, + bwhere_e w, + int texture, + int time ) +{ + int i; + + // See if button is already pressed + for (i = 0;i < MAXBUTTONS;i++) + if (buttonlist[i].btimer && buttonlist[i].line == line) + return; + + for (i = 0;i < MAXBUTTONS;i++) + if (!buttonlist[i].btimer) // use first unused element of list + { + buttonlist[i].line = line; + buttonlist[i].where = w; + buttonlist[i].btexture = texture; + buttonlist[i].btimer = time; + /* use sound origin of line itself - no need to compatibility-wrap + * as the popout code gets it wrong whatever its value */ + buttonlist[i].soundorg = (mobj_t *)&line->soundorg; + return; + } + + I_Error("P_StartButton: no button slots left!"); +} + +// +// P_ChangeSwitchTexture() +// +// Function that changes switch wall texture on activation. +// +// Passed the line which the switch is on, and whether its retriggerable. +// If not retriggerable, this function clears the line special to insure that +// +// No return +// +void P_ChangeSwitchTexture +( line_t* line, + int useAgain ) +{ + /* Rearranged a bit to avoid too much code duplication */ + mobj_t *soundorg; + int i, sound; + short *texture, *ttop, *tmid, *tbot; + bwhere_e position; + + ttop = &sides[line->sidenum[0]].toptexture; + tmid = &sides[line->sidenum[0]].midtexture; + tbot = &sides[line->sidenum[0]].bottomtexture; + + sound = sfx_swtchn; + /* use the sound origin of the linedef (its midpoint) + * unless in a compatibility mode */ + soundorg = (mobj_t *)&line->soundorg; + if (comp[comp_sound] || compatibility_level < prboom_6_compatibility) { + /* usually NULL, unless there is another button already pressed in, + * in which case it's the sound origin of that button press... */ + soundorg = buttonlist->soundorg; + } else { + // EXIT SWITCH? + /* don't do this unless you're in a compatibility mode */ + // proff - this works as advertised, but I don't like the sound + // if (line->special == 11 || line->special == 51) // exit or secret exit + // sound = sfx_swtchx; + } + + /* don't zero line->special until after exit switch test */ + if (!useAgain) + line->special = 0; + + /* search for a texture to change */ + texture = NULL; position = 0; + for (i = 0;i < numswitches*2;i++) { /* this could be more efficient... */ + if (switchlist[i] == *ttop) { + texture = ttop; position = top; break; + } else if (switchlist[i] == *tmid) { + texture = tmid; position = middle; break; + } else if (switchlist[i] == *tbot) { + texture = tbot; position = bottom; break; + } + } + if (texture == NULL) + return; /* no switch texture was found to change */ + *texture = switchlist[i^1]; + + S_StartSound(soundorg, sound); + + if (useAgain) + P_StartButton(line, position, switchlist[i], BUTTONTIME); +} + + +// +// P_UseSpecialLine +// +// +// Called when a thing uses (pushes) a special line. +// Only the front sides of lines are usable. +// Dispatches to the appropriate linedef function handler. +// +// Passed the thing using the line, the line being used, and the side used +// Returns true if a thinker was created +// +boolean +P_UseSpecialLine +( mobj_t* thing, + line_t* line, + int side ) +{ + + // e6y + // b.m. side test was broken in boom201 + if ((demoplayback ? (demover != 201) : (compatibility_level != boom_201_compatibility))) + if (side) //jff 6/1/98 fix inadvertent deletion of side test + return false; + + //jff 02/04/98 add check here for generalized floor/ceil mover + if (!demo_compatibility) + { + // pointer to line function is NULL by default, set non-null if + // line special is push or switch generalized linedef type + int (*linefunc)(line_t *line)=NULL; + + // check each range of generalized linedefs + if ((unsigned)line->special >= GenEnd) + { + // Out of range for GenFloors + } + else if ((unsigned)line->special >= GenFloorBase) + { + if (!thing->player) + if ((line->special & FloorChange) || !(line->special & FloorModel)) + return false; // FloorModel is "Allow Monsters" if FloorChange is 0 + if (!line->tag && ((line->special&6)!=6)) //jff 2/27/98 all non-manual + return false; // generalized types require tag + linefunc = EV_DoGenFloor; + } + else if ((unsigned)line->special >= GenCeilingBase) + { + if (!thing->player) + if ((line->special & CeilingChange) || !(line->special & CeilingModel)) + return false; // CeilingModel is "Allow Monsters" if CeilingChange is 0 + if (!line->tag && ((line->special&6)!=6)) //jff 2/27/98 all non-manual + return false; // generalized types require tag + linefunc = EV_DoGenCeiling; + } + else if ((unsigned)line->special >= GenDoorBase) + { + if (!thing->player) + { + if (!(line->special & DoorMonster)) + return false; // monsters disallowed from this door + if (line->flags & ML_SECRET) // they can't open secret doors either + return false; + } + if (!line->tag && ((line->special&6)!=6)) //jff 3/2/98 all non-manual + return false; // generalized types require tag + linefunc = EV_DoGenDoor; + } + else if ((unsigned)line->special >= GenLockedBase) + { + if (!thing->player) + return false; // monsters disallowed from unlocking doors + if (!P_CanUnlockGenDoor(line,thing->player)) + return false; + if (!line->tag && ((line->special&6)!=6)) //jff 2/27/98 all non-manual + return false; // generalized types require tag + + linefunc = EV_DoGenLockedDoor; + } + else if ((unsigned)line->special >= GenLiftBase) + { + if (!thing->player) + if (!(line->special & LiftMonster)) + return false; // monsters disallowed + if (!line->tag && ((line->special&6)!=6)) //jff 2/27/98 all non-manual + return false; // generalized types require tag + linefunc = EV_DoGenLift; + } + else if ((unsigned)line->special >= GenStairsBase) + { + if (!thing->player) + if (!(line->special & StairMonster)) + return false; // monsters disallowed + if (!line->tag && ((line->special&6)!=6)) //jff 2/27/98 all non-manual + return false; // generalized types require tag + linefunc = EV_DoGenStairs; + } + else if ((unsigned)line->special >= GenCrusherBase) + { + if (!thing->player) + if (!(line->special & CrusherMonster)) + return false; // monsters disallowed + if (!line->tag && ((line->special&6)!=6)) //jff 2/27/98 all non-manual + return false; // generalized types require tag + linefunc = EV_DoGenCrusher; + } + + if (linefunc) + switch((line->special & TriggerType) >> TriggerTypeShift) + { + case PushOnce: + if (!side) + if (linefunc(line)) + line->special = 0; + return true; + case PushMany: + if (!side) + linefunc(line); + return true; + case SwitchOnce: + if (linefunc(line)) + P_ChangeSwitchTexture(line,0); + return true; + case SwitchMany: + if (linefunc(line)) + P_ChangeSwitchTexture(line,1); + return true; + default: // if not a switch/push type, do nothing here + return false; + } + } + + // Switches that other things can activate. + if (!thing->player) + { + // never open secret doors + if (line->flags & ML_SECRET) + return false; + + switch(line->special) + { + case 1: // MANUAL DOOR RAISE + case 32: // MANUAL BLUE + case 33: // MANUAL RED + case 34: // MANUAL YELLOW + //jff 3/5/98 add ability to use teleporters for monsters + case 195: // switch teleporters + case 174: + case 210: // silent switch teleporters + case 209: + break; + + default: + return false; + break; + } + } + + if (!P_CheckTag(line)) //jff 2/27/98 disallow zero tag on some types + return false; + + // Dispatch to handler according to linedef type + switch (line->special) + { + // Manual doors, push type with no tag + case 1: // Vertical Door + case 26: // Blue Door/Locked + case 27: // Yellow Door /Locked + case 28: // Red Door /Locked + + case 31: // Manual door open + case 32: // Blue locked door open + case 33: // Red locked door open + case 34: // Yellow locked door open + + case 117: // Blazing door raise + case 118: // Blazing door open + EV_VerticalDoor (line, thing); + break; + + // Switches (non-retriggerable) + case 7: + // Build Stairs + if (EV_BuildStairs(line,build8)) + P_ChangeSwitchTexture(line,0); + break; + + case 9: + // Change Donut + if (EV_DoDonut(line)) + P_ChangeSwitchTexture(line,0); + break; + + case 11: + /* Exit level + * killough 10/98: prevent zombies from exiting levels + */ + if (thing->player && thing->player->health <= 0 && !comp[comp_zombie]) + { + S_StartSound(thing, sfx_noway); + return false; + } +#ifdef IPHONE + // disable level switch with timelimit or fraglimit + extern boolean levelTimer; + extern boolean levelFragLimit; + if ( deathmatch && ( levelTimer || levelFragLimit ) ) { + S_StartSound(thing, sfx_noway); + return false; + } +#endif + + P_ChangeSwitchTexture(line,0); + G_ExitLevel (); + break; + + case 14: + // Raise Floor 32 and change texture + if (EV_DoPlat(line,raiseAndChange,32)) + P_ChangeSwitchTexture(line,0); + break; + + case 15: + // Raise Floor 24 and change texture + if (EV_DoPlat(line,raiseAndChange,24)) + P_ChangeSwitchTexture(line,0); + break; + + case 18: + // Raise Floor to next highest floor + if (EV_DoFloor(line, raiseFloorToNearest)) + P_ChangeSwitchTexture(line,0); + break; + + case 20: + // Raise Plat next highest floor and change texture + if (EV_DoPlat(line,raiseToNearestAndChange,0)) + P_ChangeSwitchTexture(line,0); + break; + + case 21: + // PlatDownWaitUpStay + if (EV_DoPlat(line,downWaitUpStay,0)) + P_ChangeSwitchTexture(line,0); + break; + + case 23: + // Lower Floor to Lowest + if (EV_DoFloor(line,lowerFloorToLowest)) + P_ChangeSwitchTexture(line,0); + break; + + case 29: + // Raise Door + if (EV_DoDoor(line,normal)) + P_ChangeSwitchTexture(line,0); + break; + + case 41: + // Lower Ceiling to Floor + if (EV_DoCeiling(line,lowerToFloor)) + P_ChangeSwitchTexture(line,0); + break; + + case 71: + // Turbo Lower Floor + if (EV_DoFloor(line,turboLower)) + P_ChangeSwitchTexture(line,0); + break; + + case 49: + // Ceiling Crush And Raise + if (EV_DoCeiling(line,crushAndRaise)) + P_ChangeSwitchTexture(line,0); + break; + + case 50: + // Close Door + if (EV_DoDoor(line,close)) + P_ChangeSwitchTexture(line,0); + break; + + case 51: + /* Secret EXIT + * killough 10/98: prevent zombies from exiting levels + */ + if (thing->player && thing->player->health <= 0 && !comp[comp_zombie]) + { + S_StartSound(thing, sfx_noway); + return false; + } + + P_ChangeSwitchTexture(line,0); + G_SecretExitLevel (); + break; + + case 55: + // Raise Floor Crush + if (EV_DoFloor(line,raiseFloorCrush)) + P_ChangeSwitchTexture(line,0); + break; + + case 101: + // Raise Floor + if (EV_DoFloor(line,raiseFloor)) + P_ChangeSwitchTexture(line,0); + break; + + case 102: + // Lower Floor to Surrounding floor height + if (EV_DoFloor(line,lowerFloor)) + P_ChangeSwitchTexture(line,0); + break; + + case 103: + // Open Door + if (EV_DoDoor(line,open)) + P_ChangeSwitchTexture(line,0); + break; + + case 111: + // Blazing Door Raise (faster than TURBO!) + if (EV_DoDoor (line,blazeRaise)) + P_ChangeSwitchTexture(line,0); + break; + + case 112: + // Blazing Door Open (faster than TURBO!) + if (EV_DoDoor (line,blazeOpen)) + P_ChangeSwitchTexture(line,0); + break; + + case 113: + // Blazing Door Close (faster than TURBO!) + if (EV_DoDoor (line,blazeClose)) + P_ChangeSwitchTexture(line,0); + break; + + case 122: + // Blazing PlatDownWaitUpStay + if (EV_DoPlat(line,blazeDWUS,0)) + P_ChangeSwitchTexture(line,0); + break; + + case 127: + // Build Stairs Turbo 16 + if (EV_BuildStairs(line,turbo16)) + P_ChangeSwitchTexture(line,0); + break; + + case 131: + // Raise Floor Turbo + if (EV_DoFloor(line,raiseFloorTurbo)) + P_ChangeSwitchTexture(line,0); + break; + + case 133: + // BlzOpenDoor BLUE + case 135: + // BlzOpenDoor RED + case 137: + // BlzOpenDoor YELLOW + if (EV_DoLockedDoor (line,blazeOpen,thing)) + P_ChangeSwitchTexture(line,0); + break; + + case 140: + // Raise Floor 512 + if (EV_DoFloor(line,raiseFloor512)) + P_ChangeSwitchTexture(line,0); + break; + + // killough 1/31/98: factored out compatibility check; + // added inner switch, relaxed check to demo_compatibility + + default: + if (!demo_compatibility) + switch (line->special) + { + //jff 1/29/98 added linedef types to fill all functions out so that + // all possess SR, S1, WR, W1 types + + case 158: + // Raise Floor to shortest lower texture + // 158 S1 EV_DoFloor(raiseToTexture), CSW(0) + if (EV_DoFloor(line,raiseToTexture)) + P_ChangeSwitchTexture(line,0); + break; + + case 159: + // Raise Floor to shortest lower texture + // 159 S1 EV_DoFloor(lowerAndChange) + if (EV_DoFloor(line,lowerAndChange)) + P_ChangeSwitchTexture(line,0); + break; + + case 160: + // Raise Floor 24 and change + // 160 S1 EV_DoFloor(raiseFloor24AndChange) + if (EV_DoFloor(line,raiseFloor24AndChange)) + P_ChangeSwitchTexture(line,0); + break; + + case 161: + // Raise Floor 24 + // 161 S1 EV_DoFloor(raiseFloor24) + if (EV_DoFloor(line,raiseFloor24)) + P_ChangeSwitchTexture(line,0); + break; + + case 162: + // Moving floor min n to max n + // 162 S1 EV_DoPlat(perpetualRaise,0) + if (EV_DoPlat(line,perpetualRaise,0)) + P_ChangeSwitchTexture(line,0); + break; + + case 163: + // Stop Moving floor + // 163 S1 EV_DoPlat(perpetualRaise,0) + EV_StopPlat(line); + P_ChangeSwitchTexture(line,0); + break; + + case 164: + // Start fast crusher + // 164 S1 EV_DoCeiling(fastCrushAndRaise) + if (EV_DoCeiling(line,fastCrushAndRaise)) + P_ChangeSwitchTexture(line,0); + break; + + case 165: + // Start slow silent crusher + // 165 S1 EV_DoCeiling(silentCrushAndRaise) + if (EV_DoCeiling(line,silentCrushAndRaise)) + P_ChangeSwitchTexture(line,0); + break; + + case 166: + // Raise ceiling, Lower floor + // 166 S1 EV_DoCeiling(raiseToHighest), EV_DoFloor(lowerFloortoLowest) + if (EV_DoCeiling(line, raiseToHighest) || + EV_DoFloor(line, lowerFloorToLowest)) + P_ChangeSwitchTexture(line,0); + break; + + case 167: + // Lower floor and Crush + // 167 S1 EV_DoCeiling(lowerAndCrush) + if (EV_DoCeiling(line, lowerAndCrush)) + P_ChangeSwitchTexture(line,0); + break; + + case 168: + // Stop crusher + // 168 S1 EV_CeilingCrushStop() + if (EV_CeilingCrushStop(line)) + P_ChangeSwitchTexture(line,0); + break; + + case 169: + // Lights to brightest neighbor sector + // 169 S1 EV_LightTurnOn(0) + EV_LightTurnOn(line,0); + P_ChangeSwitchTexture(line,0); + break; + + case 170: + // Lights to near dark + // 170 S1 EV_LightTurnOn(35) + EV_LightTurnOn(line,35); + P_ChangeSwitchTexture(line,0); + break; + + case 171: + // Lights on full + // 171 S1 EV_LightTurnOn(255) + EV_LightTurnOn(line,255); + P_ChangeSwitchTexture(line,0); + break; + + case 172: + // Start Lights Strobing + // 172 S1 EV_StartLightStrobing() + EV_StartLightStrobing(line); + P_ChangeSwitchTexture(line,0); + break; + + case 173: + // Lights to Dimmest Near + // 173 S1 EV_TurnTagLightsOff() + EV_TurnTagLightsOff(line); + P_ChangeSwitchTexture(line,0); + break; + + case 174: + // Teleport + // 174 S1 EV_Teleport(side,thing) + if (EV_Teleport(line,side,thing)) + P_ChangeSwitchTexture(line,0); + break; + + case 175: + // Close Door, Open in 30 secs + // 175 S1 EV_DoDoor(close30ThenOpen) + if (EV_DoDoor(line,close30ThenOpen)) + P_ChangeSwitchTexture(line,0); + break; + + case 189: //jff 3/15/98 create texture change no motion type + // Texture Change Only (Trigger) + // 189 S1 Change Texture/Type Only + if (EV_DoChange(line,trigChangeOnly)) + P_ChangeSwitchTexture(line,0); + break; + + case 203: + // Lower ceiling to lowest surrounding ceiling + // 203 S1 EV_DoCeiling(lowerToLowest) + if (EV_DoCeiling(line,lowerToLowest)) + P_ChangeSwitchTexture(line,0); + break; + + case 204: + // Lower ceiling to highest surrounding floor + // 204 S1 EV_DoCeiling(lowerToMaxFloor) + if (EV_DoCeiling(line,lowerToMaxFloor)) + P_ChangeSwitchTexture(line,0); + break; + + case 209: + // killough 1/31/98: silent teleporter + //jff 209 S1 SilentTeleport + if (EV_SilentTeleport(line, side, thing)) + P_ChangeSwitchTexture(line,0); + break; + + case 241: //jff 3/15/98 create texture change no motion type + // Texture Change Only (Numeric) + // 241 S1 Change Texture/Type Only + if (EV_DoChange(line,numChangeOnly)) + P_ChangeSwitchTexture(line,0); + break; + + case 221: + // Lower floor to next lowest floor + // 221 S1 Lower Floor To Nearest Floor + if (EV_DoFloor(line,lowerFloorToNearest)) + P_ChangeSwitchTexture(line,0); + break; + + case 229: + // Raise elevator next floor + // 229 S1 Raise Elevator next floor + if (EV_DoElevator(line,elevateUp)) + P_ChangeSwitchTexture(line,0); + break; + + case 233: + // Lower elevator next floor + // 233 S1 Lower Elevator next floor + if (EV_DoElevator(line,elevateDown)) + P_ChangeSwitchTexture(line,0); + break; + + case 237: + // Elevator to current floor + // 237 S1 Elevator to current floor + if (EV_DoElevator(line,elevateCurrent)) + P_ChangeSwitchTexture(line,0); + break; + + + // jff 1/29/98 end of added S1 linedef types + + //jff 1/29/98 added linedef types to fill all functions out so that + // all possess SR, S1, WR, W1 types + + case 78: //jff 3/15/98 create texture change no motion type + // Texture Change Only (Numeric) + // 78 SR Change Texture/Type Only + if (EV_DoChange(line,numChangeOnly)) + P_ChangeSwitchTexture(line,1); + break; + + case 176: + // Raise Floor to shortest lower texture + // 176 SR EV_DoFloor(raiseToTexture), CSW(1) + if (EV_DoFloor(line,raiseToTexture)) + P_ChangeSwitchTexture(line,1); + break; + + case 177: + // Raise Floor to shortest lower texture + // 177 SR EV_DoFloor(lowerAndChange) + if (EV_DoFloor(line,lowerAndChange)) + P_ChangeSwitchTexture(line,1); + break; + + case 178: + // Raise Floor 512 + // 178 SR EV_DoFloor(raiseFloor512) + if (EV_DoFloor(line,raiseFloor512)) + P_ChangeSwitchTexture(line,1); + break; + + case 179: + // Raise Floor 24 and change + // 179 SR EV_DoFloor(raiseFloor24AndChange) + if (EV_DoFloor(line,raiseFloor24AndChange)) + P_ChangeSwitchTexture(line,1); + break; + + case 180: + // Raise Floor 24 + // 180 SR EV_DoFloor(raiseFloor24) + if (EV_DoFloor(line,raiseFloor24)) + P_ChangeSwitchTexture(line,1); + break; + + case 181: + // Moving floor min n to max n + // 181 SR EV_DoPlat(perpetualRaise,0) + + EV_DoPlat(line,perpetualRaise,0); + P_ChangeSwitchTexture(line,1); + break; + + case 182: + // Stop Moving floor + // 182 SR EV_DoPlat(perpetualRaise,0) + EV_StopPlat(line); + P_ChangeSwitchTexture(line,1); + break; + + case 183: + // Start fast crusher + // 183 SR EV_DoCeiling(fastCrushAndRaise) + if (EV_DoCeiling(line,fastCrushAndRaise)) + P_ChangeSwitchTexture(line,1); + break; + + case 184: + // Start slow crusher + // 184 SR EV_DoCeiling(crushAndRaise) + if (EV_DoCeiling(line,crushAndRaise)) + P_ChangeSwitchTexture(line,1); + break; + + case 185: + // Start slow silent crusher + // 185 SR EV_DoCeiling(silentCrushAndRaise) + if (EV_DoCeiling(line,silentCrushAndRaise)) + P_ChangeSwitchTexture(line,1); + break; + + case 186: + // Raise ceiling, Lower floor + // 186 SR EV_DoCeiling(raiseToHighest), EV_DoFloor(lowerFloortoLowest) + if (EV_DoCeiling(line, raiseToHighest) || + EV_DoFloor(line, lowerFloorToLowest)) + P_ChangeSwitchTexture(line,1); + break; + + case 187: + // Lower floor and Crush + // 187 SR EV_DoCeiling(lowerAndCrush) + if (EV_DoCeiling(line, lowerAndCrush)) + P_ChangeSwitchTexture(line,1); + break; + + case 188: + // Stop crusher + // 188 SR EV_CeilingCrushStop() + if (EV_CeilingCrushStop(line)) + P_ChangeSwitchTexture(line,1); + break; + + case 190: //jff 3/15/98 create texture change no motion type + // Texture Change Only (Trigger) + // 190 SR Change Texture/Type Only + if (EV_DoChange(line,trigChangeOnly)) + P_ChangeSwitchTexture(line,1); + break; + + case 191: + // Lower Pillar, Raise Donut + // 191 SR EV_DoDonut() + if (EV_DoDonut(line)) + P_ChangeSwitchTexture(line,1); + break; + + case 192: + // Lights to brightest neighbor sector + // 192 SR EV_LightTurnOn(0) + EV_LightTurnOn(line,0); + P_ChangeSwitchTexture(line,1); + break; + + case 193: + // Start Lights Strobing + // 193 SR EV_StartLightStrobing() + EV_StartLightStrobing(line); + P_ChangeSwitchTexture(line,1); + break; + + case 194: + // Lights to Dimmest Near + // 194 SR EV_TurnTagLightsOff() + EV_TurnTagLightsOff(line); + P_ChangeSwitchTexture(line,1); + break; + + case 195: + // Teleport + // 195 SR EV_Teleport(side,thing) + if (EV_Teleport(line,side,thing)) + P_ChangeSwitchTexture(line,1); + break; + + case 196: + // Close Door, Open in 30 secs + // 196 SR EV_DoDoor(close30ThenOpen) + if (EV_DoDoor(line,close30ThenOpen)) + P_ChangeSwitchTexture(line,1); + break; + + case 205: + // Lower ceiling to lowest surrounding ceiling + // 205 SR EV_DoCeiling(lowerToLowest) + if (EV_DoCeiling(line,lowerToLowest)) + P_ChangeSwitchTexture(line,1); + break; + + case 206: + // Lower ceiling to highest surrounding floor + // 206 SR EV_DoCeiling(lowerToMaxFloor) + if (EV_DoCeiling(line,lowerToMaxFloor)) + P_ChangeSwitchTexture(line,1); + break; + + case 210: + // killough 1/31/98: silent teleporter + //jff 210 SR SilentTeleport + if (EV_SilentTeleport(line, side, thing)) + P_ChangeSwitchTexture(line,1); + break; + + case 211: //jff 3/14/98 create instant toggle floor type + // Toggle Floor Between C and F Instantly + // 211 SR Toggle Floor Instant + if (EV_DoPlat(line,toggleUpDn,0)) + P_ChangeSwitchTexture(line,1); + break; + + case 222: + // Lower floor to next lowest floor + // 222 SR Lower Floor To Nearest Floor + if (EV_DoFloor(line,lowerFloorToNearest)) + P_ChangeSwitchTexture(line,1); + break; + + case 230: + // Raise elevator next floor + // 230 SR Raise Elevator next floor + if (EV_DoElevator(line,elevateUp)) + P_ChangeSwitchTexture(line,1); + break; + + case 234: + // Lower elevator next floor + // 234 SR Lower Elevator next floor + if (EV_DoElevator(line,elevateDown)) + P_ChangeSwitchTexture(line,1); + break; + + case 238: + // Elevator to current floor + // 238 SR Elevator to current floor + if (EV_DoElevator(line,elevateCurrent)) + P_ChangeSwitchTexture(line,1); + break; + + case 258: + // Build stairs, step 8 + // 258 SR EV_BuildStairs(build8) + if (EV_BuildStairs(line,build8)) + P_ChangeSwitchTexture(line,1); + break; + + case 259: + // Build stairs, step 16 + // 259 SR EV_BuildStairs(turbo16) + if (EV_BuildStairs(line,turbo16)) + P_ChangeSwitchTexture(line,1); + break; + + // 1/29/98 jff end of added SR linedef types + + } + break; + + // Buttons (retriggerable switches) + case 42: + // Close Door + if (EV_DoDoor(line,close)) + P_ChangeSwitchTexture(line,1); + break; + + case 43: + // Lower Ceiling to Floor + if (EV_DoCeiling(line,lowerToFloor)) + P_ChangeSwitchTexture(line,1); + break; + + case 45: + // Lower Floor to Surrounding floor height + if (EV_DoFloor(line,lowerFloor)) + P_ChangeSwitchTexture(line,1); + break; + + case 60: + // Lower Floor to Lowest + if (EV_DoFloor(line,lowerFloorToLowest)) + P_ChangeSwitchTexture(line,1); + break; + + case 61: + // Open Door + if (EV_DoDoor(line,open)) + P_ChangeSwitchTexture(line,1); + break; + + case 62: + // PlatDownWaitUpStay + if (EV_DoPlat(line,downWaitUpStay,1)) + P_ChangeSwitchTexture(line,1); + break; + + case 63: + // Raise Door + if (EV_DoDoor(line,normal)) + P_ChangeSwitchTexture(line,1); + break; + + case 64: + // Raise Floor to ceiling + if (EV_DoFloor(line,raiseFloor)) + P_ChangeSwitchTexture(line,1); + break; + + case 66: + // Raise Floor 24 and change texture + if (EV_DoPlat(line,raiseAndChange,24)) + P_ChangeSwitchTexture(line,1); + break; + + case 67: + // Raise Floor 32 and change texture + if (EV_DoPlat(line,raiseAndChange,32)) + P_ChangeSwitchTexture(line,1); + break; + + case 65: + // Raise Floor Crush + if (EV_DoFloor(line,raiseFloorCrush)) + P_ChangeSwitchTexture(line,1); + break; + + case 68: + // Raise Plat to next highest floor and change texture + if (EV_DoPlat(line,raiseToNearestAndChange,0)) + P_ChangeSwitchTexture(line,1); + break; + + case 69: + // Raise Floor to next highest floor + if (EV_DoFloor(line, raiseFloorToNearest)) + P_ChangeSwitchTexture(line,1); + break; + + case 70: + // Turbo Lower Floor + if (EV_DoFloor(line,turboLower)) + P_ChangeSwitchTexture(line,1); + break; + + case 114: + // Blazing Door Raise (faster than TURBO!) + if (EV_DoDoor (line,blazeRaise)) + P_ChangeSwitchTexture(line,1); + break; + + case 115: + // Blazing Door Open (faster than TURBO!) + if (EV_DoDoor (line,blazeOpen)) + P_ChangeSwitchTexture(line,1); + break; + + case 116: + // Blazing Door Close (faster than TURBO!) + if (EV_DoDoor (line,blazeClose)) + P_ChangeSwitchTexture(line,1); + break; + + case 123: + // Blazing PlatDownWaitUpStay + if (EV_DoPlat(line,blazeDWUS,0)) + P_ChangeSwitchTexture(line,1); + break; + + case 132: + // Raise Floor Turbo + if (EV_DoFloor(line,raiseFloorTurbo)) + P_ChangeSwitchTexture(line,1); + break; + + case 99: + // BlzOpenDoor BLUE + case 134: + // BlzOpenDoor RED + case 136: + // BlzOpenDoor YELLOW + if (EV_DoLockedDoor (line,blazeOpen,thing)) + P_ChangeSwitchTexture(line,1); + break; + + case 138: + // Light Turn On + EV_LightTurnOn(line,255); + P_ChangeSwitchTexture(line,1); + break; + + case 139: + // Light Turn Off + EV_LightTurnOn(line,35); + P_ChangeSwitchTexture(line,1); + break; + } + return true; +} diff --git a/common/prboom/p_telept.c b/common/prboom/p_telept.c new file mode 100755 index 0000000..89e1cc3 --- /dev/null +++ b/common/prboom/p_telept.c @@ -0,0 +1,345 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2002 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Teleportation. + * + *-----------------------------------------------------------------------------*/ + +#include "doomdef.h" +#include "doomstat.h" +#include "p_spec.h" +#include "p_maputl.h" +#include "p_map.h" +#include "r_main.h" +#include "p_tick.h" +#include "s_sound.h" +#include "sounds.h" +#include "p_user.h" +#include "r_demo.h" + +static mobj_t* P_TeleportDestination(line_t* line) +{ + int i; + for (i = -1; (i = P_FindSectorFromLineTag(line, i)) >= 0;) { + register thinker_t* th = NULL; + while ((th = P_NextThinker(th,th_misc)) != NULL) + if (th->function == P_MobjThinker) { + register mobj_t* m = (mobj_t*)th; + if (m->type == MT_TELEPORTMAN && + m->subsector->sector-sectors == i) + return m; + } + } + return NULL; +} +// +// TELEPORTATION +// +// killough 5/3/98: reformatted, cleaned up + +int EV_Teleport(line_t *line, int side, mobj_t *thing) +{ + mobj_t *m; + + // don't teleport missiles + // Don't teleport if hit back of line, + // so you can get out of teleporter. + if (side || thing->flags & MF_MISSILE) + return 0; + + // killough 1/31/98: improve performance by using + // P_FindSectorFromLineTag instead of simple linear search. + + if ((m = P_TeleportDestination(line)) != NULL) + { + fixed_t oldx = thing->x, oldy = thing->y, oldz = thing->z; + player_t *player = thing->player; + + // killough 5/12/98: exclude voodoo dolls: + if (player && player->mo != thing) + player = NULL; + + if (!P_TeleportMove(thing, m->x, m->y, false)) /* killough 8/9/98 */ + return 0; + + if (compatibility_level != finaldoom_compatibility) + thing->z = thing->floorz; + + if (player) + player->viewz = thing->z + player->viewheight; + + // spawn teleport fog and emit sound at source + S_StartSound(P_SpawnMobj(oldx, oldy, oldz, MT_TFOG), sfx_telept); + + // spawn teleport fog and emit sound at destination + S_StartSound(P_SpawnMobj(m->x + + 20*finecosine[m->angle>>ANGLETOFINESHIFT], + m->y + + 20*finesine[m->angle>>ANGLETOFINESHIFT], + thing->z, MT_TFOG), + sfx_telept); + + /* don't move for a bit + * cph - DEMOSYNC - BOOM had (player) here? */ + if (thing->player) + thing->reactiontime = 18; + + thing->angle = m->angle; + + thing->momx = thing->momy = thing->momz = 0; + + /* killough 10/98: kill all bobbing momentum too */ + if (player) + player->momx = player->momy = 0; + + // e6y + if (player && player->mo == thing) + R_ResetAfterTeleport(player); + + return 1; + } + return 0; +} + +// +// Silent TELEPORTATION, by Lee Killough +// Primarily for rooms-over-rooms etc. +// + +int EV_SilentTeleport(line_t *line, int side, mobj_t *thing) +{ + mobj_t *m; + + // don't teleport missiles + // Don't teleport if hit back of line, + // so you can get out of teleporter. + + if (side || thing->flags & MF_MISSILE) + return 0; + + if ((m = P_TeleportDestination(line)) != NULL) + { + // Height of thing above ground, in case of mid-air teleports: + fixed_t z = thing->z - thing->floorz; + + // Get the angle between the exit thing and source linedef. + // Rotate 90 degrees, so that walking perpendicularly across + // teleporter linedef causes thing to exit in the direction + // indicated by the exit thing. + angle_t angle = + R_PointToAngle2(0, 0, line->dx, line->dy) - m->angle + ANG90; + + // Sine, cosine of angle adjustment + fixed_t s = finesine[angle>>ANGLETOFINESHIFT]; + fixed_t c = finecosine[angle>>ANGLETOFINESHIFT]; + + // Momentum of thing crossing teleporter linedef + fixed_t momx = thing->momx; + fixed_t momy = thing->momy; + + // Whether this is a player, and if so, a pointer to its player_t + player_t *player = thing->player; + + // Attempt to teleport, aborting if blocked + if (!P_TeleportMove(thing, m->x, m->y, false)) /* killough 8/9/98 */ + return 0; + + // Rotate thing according to difference in angles + thing->angle += angle; + + // Adjust z position to be same height above ground as before + thing->z = z + thing->floorz; + + // Rotate thing's momentum to come out of exit just like it entered + thing->momx = FixedMul(momx, c) - FixedMul(momy, s); + thing->momy = FixedMul(momy, c) + FixedMul(momx, s); + + // Adjust player's view, in case there has been a height change + // Voodoo dolls are excluded by making sure player->mo == thing. + if (player && player->mo == thing) + { + // Save the current deltaviewheight, used in stepping + fixed_t deltaviewheight = player->deltaviewheight; + + // Clear deltaviewheight, since we don't want any changes + player->deltaviewheight = 0; + + // Set player's view according to the newly set parameters + P_CalcHeight(player); + + // Reset the delta to have the same dynamics as before + player->deltaviewheight = deltaviewheight; + } + + // e6y + if (player && player->mo == thing) + R_ResetAfterTeleport(player); + + return 1; + } + return 0; +} + +// +// Silent linedef-based TELEPORTATION, by Lee Killough +// Primarily for rooms-over-rooms etc. +// This is the complete player-preserving kind of teleporter. +// It has advantages over the teleporter with thing exits. +// + +// maximum fixed_t units to move object to avoid hiccups +#define FUDGEFACTOR 10 + +int EV_SilentLineTeleport(line_t *line, int side, mobj_t *thing, + boolean reverse) +{ + int i; + line_t *l; + + if (side || thing->flags & MF_MISSILE) + return 0; + + for (i = -1; (i = P_FindLineFromLineTag(line, i)) >= 0;) + if ((l=lines+i) != line && l->backsector) + { + // Get the thing's position along the source linedef + fixed_t pos = D_abs(line->dx) > D_abs(line->dy) ? + FixedDiv(thing->x - line->v1->x, line->dx) : + FixedDiv(thing->y - line->v1->y, line->dy) ; + + // Get the angle between the two linedefs, for rotating + // orientation and momentum. Rotate 180 degrees, and flip + // the position across the exit linedef, if reversed. + angle_t angle = (reverse ? pos = FRACUNIT-pos, 0 : ANG180) + + R_PointToAngle2(0, 0, l->dx, l->dy) - + R_PointToAngle2(0, 0, line->dx, line->dy); + + // Interpolate position across the exit linedef + fixed_t x = l->v2->x - FixedMul(pos, l->dx); + fixed_t y = l->v2->y - FixedMul(pos, l->dy); + + // Sine, cosine of angle adjustment + fixed_t s = finesine[angle>>ANGLETOFINESHIFT]; + fixed_t c = finecosine[angle>>ANGLETOFINESHIFT]; + + // Maximum distance thing can be moved away from interpolated + // exit, to ensure that it is on the correct side of exit linedef + int fudge = FUDGEFACTOR; + + // Whether this is a player, and if so, a pointer to its player_t. + // Voodoo dolls are excluded by making sure thing->player->mo==thing. + player_t *player = thing->player && thing->player->mo == thing ? + thing->player : NULL; + + // Whether walking towards first side of exit linedef steps down + int stepdown = + l->frontsector->floorheight < l->backsector->floorheight; + + // Height of thing above ground + fixed_t z = thing->z - thing->floorz; + + // Side to exit the linedef on positionally. + // + // Notes: + // + // This flag concerns exit position, not momentum. Due to + // roundoff error, the thing can land on either the left or + // the right side of the exit linedef, and steps must be + // taken to make sure it does not end up on the wrong side. + // + // Exit momentum is always towards side 1 in a reversed + // teleporter, and always towards side 0 otherwise. + // + // Exiting positionally on side 1 is always safe, as far + // as avoiding oscillations and stuck-in-wall problems, + // but may not be optimum for non-reversed teleporters. + // + // Exiting on side 0 can cause oscillations if momentum + // is towards side 1, as it is with reversed teleporters. + // + // Exiting on side 1 slightly improves player viewing + // when going down a step on a non-reversed teleporter. + + int theside = reverse || (player && stepdown); + + // Make sure we are on correct side of exit linedef. + while (P_PointOnLineSide(x, y, l) != theside && --fudge>=0) + if (D_abs(l->dx) > D_abs(l->dy)) + y -= l->dx < 0 != theside ? -1 : 1; + else + x += l->dy < 0 != theside ? -1 : 1; + + // Attempt to teleport, aborting if blocked + if (!P_TeleportMove(thing, x, y, false)) /* killough 8/9/98 */ + return 0; + + // e6y + if (player && player->mo == thing) + R_ResetAfterTeleport(player); + + // Adjust z position to be same height above ground as before. + // Ground level at the exit is measured as the higher of the + // two floor heights at the exit linedef. + thing->z = z + sides[l->sidenum[stepdown]].sector->floorheight; + + // Rotate thing's orientation according to difference in linedef angles + thing->angle += angle; + + // Momentum of thing crossing teleporter linedef + x = thing->momx; + y = thing->momy; + + // Rotate thing's momentum to come out of exit just like it entered + thing->momx = FixedMul(x, c) - FixedMul(y, s); + thing->momy = FixedMul(y, c) + FixedMul(x, s); + + // Adjust a player's view, in case there has been a height change + if (player) + { + // Save the current deltaviewheight, used in stepping + fixed_t deltaviewheight = player->deltaviewheight; + + // Clear deltaviewheight, since we don't want any changes now + player->deltaviewheight = 0; + + // Set player's view according to the newly set parameters + P_CalcHeight(player); + + // Reset the delta to have the same dynamics as before + player->deltaviewheight = deltaviewheight; + } + + // e6y + if (player && player->mo == thing) + R_ResetAfterTeleport(player); + + return 1; + } + return 0; +} diff --git a/common/prboom/p_tick.c b/common/prboom/p_tick.c new file mode 100755 index 0000000..6046046 --- /dev/null +++ b/common/prboom/p_tick.c @@ -0,0 +1,291 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000,2002 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Thinker, Ticker. + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" +#include "p_user.h" +#include "p_spec.h" +#include "p_tick.h" +#include "p_map.h" +#include "r_fps.h" + +int leveltime; + +static boolean newthinkerpresent; + +// +// THINKERS +// All thinkers should be allocated by Z_Malloc +// so they can be operated on uniformly. +// The actual structures will vary in size, +// but the first element must be thinker_t. +// + +// killough 8/29/98: we maintain several separate threads, each containing +// a special class of thinkers, to allow more efficient searches. +thinker_t thinkerclasscap[th_all+1]; + +// +// P_InitThinkers +// + +void P_InitThinkers(void) +{ + int i; + + for (i=0; ifunction == P_RemoveThinkerDelayed ? th_delete : + thinker->function == P_MobjThinker && + ((mobj_t *) thinker)->health > 0 && + (((mobj_t *) thinker)->flags & MF_COUNTKILL || + ((mobj_t *) thinker)->type == MT_SKULL) ? + ((mobj_t *) thinker)->flags & MF_FRIEND ? + th_friends : th_enemies : th_misc; + + { + /* Remove from current thread, if in one */ + if ((th = thinker->cnext)!= NULL) + (th->cprev = thinker->cprev)->cnext = th; + } + + // Add to appropriate thread + th = &thinkerclasscap[class]; + th->cprev->cnext = thinker; + thinker->cnext = th; + thinker->cprev = th->cprev; + th->cprev = thinker; +} + +// +// P_AddThinker +// Adds a new thinker at the end of the list. +// + +void P_AddThinker(thinker_t* thinker) +{ + thinkercap.prev->next = thinker; + thinker->next = &thinkercap; + thinker->prev = thinkercap.prev; + thinkercap.prev = thinker; + + thinker->references = 0; // killough 11/98: init reference counter to 0 + + // killough 8/29/98: set sentinel pointers, and then add to appropriate list + thinker->cnext = thinker->cprev = NULL; + P_UpdateThinker(thinker); + newthinkerpresent = true; +} + +// +// killough 11/98: +// +// Make currentthinker external, so that P_RemoveThinkerDelayed +// can adjust currentthinker when thinkers self-remove. + +static thinker_t *currentthinker; + +// +// P_RemoveThinkerDelayed() +// +// Called automatically as part of the thinker loop in P_RunThinkers(), +// on nodes which are pending deletion. +// +// If this thinker has no more pointers referencing it indirectly, +// remove it, and set currentthinker to one node preceeding it, so +// that the next step in P_RunThinkers() will get its successor. +// + +void P_RemoveThinkerDelayed(thinker_t *thinker) +{ + if (!thinker->references) + { + { /* Remove from main thinker list */ + thinker_t *next = thinker->next; + /* Note that currentthinker is guaranteed to point to us, + * and since we're freeing our memory, we had better change that. So + * point it to thinker->prev, so the iterator will correctly move on to + * thinker->prev->next = thinker->next */ + (next->prev = currentthinker = thinker->prev)->next = next; + } + { + /* Remove from current thinker class list */ + thinker_t *th = thinker->cnext; + (th->cprev = thinker->cprev)->cnext = th; + } + Z_Free(thinker); + } +} + +// +// P_RemoveThinker +// +// Deallocation is lazy -- it will not actually be freed +// until its thinking turn comes up. +// +// killough 4/25/98: +// +// Instead of marking the function with -1 value cast to a function pointer, +// set the function to P_RemoveThinkerDelayed(), so that later, it will be +// removed automatically as part of the thinker process. +// + +void P_RemoveThinker(thinker_t *thinker) +{ + R_StopInterpolationIfNeeded(thinker); + thinker->function = P_RemoveThinkerDelayed; + + P_UpdateThinker(thinker); +} + +/* cph 2002/01/13 - iterator for thinker list + * WARNING: Do not modify thinkers between calls to this functin + */ +thinker_t* P_NextThinker(thinker_t* th, th_class cl) +{ + thinker_t* top = &thinkerclasscap[cl]; + if (!th) th = top; + th = cl == th_all ? th->next : th->cnext; + return th == top ? NULL : th; +} + +/* + * P_SetTarget + * + * This function is used to keep track of pointer references to mobj thinkers. + * In Doom, objects such as lost souls could sometimes be removed despite + * their still being referenced. In Boom, 'target' mobj fields were tested + * during each gametic, and any objects pointed to by them would be prevented + * from being removed. But this was incomplete, and was slow (every mobj was + * checked during every gametic). Now, we keep a count of the number of + * references, and delay removal until the count is 0. + */ + +void P_SetTarget(mobj_t **mop, mobj_t *targ) +{ + if (*mop) // If there was a target already, decrease its refcount + (*mop)->thinker.references--; + if ((*mop = targ)) // Set new target and if non-NULL, increase its counter + targ->thinker.references++; +} + +// +// P_RunThinkers +// +// killough 4/25/98: +// +// Fix deallocator to stop using "next" pointer after node has been freed +// (a Doom bug). +// +// Process each thinker. For thinkers which are marked deleted, we must +// load the "next" pointer prior to freeing the node. In Doom, the "next" +// pointer was loaded AFTER the thinker was freed, which could have caused +// crashes. +// +// But if we are not deleting the thinker, we should reload the "next" +// pointer after calling the function, in case additional thinkers are +// added at the end of the list. +// +// killough 11/98: +// +// Rewritten to delete nodes implicitly, by making currentthinker +// external and using P_RemoveThinkerDelayed() implicitly. +// + +static void P_RunThinkers (void) +{ + for (currentthinker = thinkercap.next; + currentthinker != &thinkercap; + currentthinker = currentthinker->next) + { + if (newthinkerpresent) + R_ActivateThinkerInterpolations(currentthinker); + if (currentthinker->function) + currentthinker->function(currentthinker); + } + newthinkerpresent = false; +} + +// +// P_Ticker +// + +void P_Ticker (void) +{ + int i; + + /* pause if in menu and at least one tic has been run + * + * killough 9/29/98: note that this ties in with basetic, + * since G_Ticker does the pausing during recording or + * playback, and compenates by incrementing basetic. + * + * All of this complicated mess is used to preserve demo sync. + */ + + if (paused || (menuactive && !demoplayback && !netgame && + players[consoleplayer].viewz != 1)) + return; + + R_UpdateInterpolations (); + + P_MapStart(); + // not if this is an intermission screen + if(gamestate==GS_LEVEL) + for (i=0; i>= ANGLETOFINESHIFT; + player->mo->momx += FixedMul(move,finecosine[angle]); + player->mo->momy += FixedMul(move,finesine[angle]); + } + + +/* + * P_Bob + * Same as P_Thrust, but only affects bobbing. + * + * killough 10/98: We apply thrust separately between the real physical player + * and the part which affects bobbing. This way, bobbing only comes from player + * motion, nothing external, avoiding many problems, e.g. bobbing should not + * occur on conveyors, unless the player walks on one, and bobbing should be + * reduced at a regular rate, even on ice (where the player coasts). + */ + +static void P_Bob(player_t *player, angle_t angle, fixed_t move) +{ + //e6y + if (!mbf_features) + return; + + player->momx += FixedMul(move,finecosine[angle >>= ANGLETOFINESHIFT]); + player->momy += FixedMul(move,finesine[angle]); +} + +// +// P_CalcHeight +// Calculate the walking / running height adjustment +// + +void P_CalcHeight (player_t* player) + { + int angle; + fixed_t bob; + + // Regular movement bobbing + // (needs to be calculated for gun swing + // even if not on ground) + // OPTIMIZE: tablify angle + // Note: a LUT allows for effects + // like a ramp with low health. + + + /* killough 10/98: Make bobbing depend only on player-applied motion. + * + * Note: don't reduce bobbing here if on ice: if you reduce bobbing here, + * it causes bobbing jerkiness when the player moves from ice to non-ice, + * and vice-versa. + */ + player->bob = !mbf_features ? + (FixedMul (player->mo->momx, player->mo->momx) + + FixedMul (player->mo->momy,player->mo->momy))>>2 : + player_bobbing ? (FixedMul(player->momx,player->momx) + + FixedMul(player->momy,player->momy))>>2 : 0; + + //e6y + if (compatibility_level >= boom_202_compatibility && + compatibility_level <= lxdoom_1_compatibility && + player->mo->friction > ORIG_FRICTION) // ice? + { + if (player->bob > (MAXBOB>>2)) + player->bob = MAXBOB>>2; + } + else + + if (player->bob > MAXBOB) + player->bob = MAXBOB; + + if (!onground || player->cheats & CF_NOMOMENTUM) + { + player->viewz = player->mo->z + VIEWHEIGHT; + + if (player->viewz > player->mo->ceilingz-4*FRACUNIT) + player->viewz = player->mo->ceilingz-4*FRACUNIT; + +// The following line was in the Id source and appears // phares 2/25/98 +// to be a bug. player->viewz is checked in a similar +// manner at a different exit below. + +// player->viewz = player->mo->z + player->viewheight; + return; + } + + angle = (FINEANGLES/20*leveltime)&FINEMASK; + bob = FixedMul(player->bob/2,finesine[angle]); + + // move viewheight + + if (player->playerstate == PST_LIVE) + { + player->viewheight += player->deltaviewheight; + + if (player->viewheight > VIEWHEIGHT) + { + player->viewheight = VIEWHEIGHT; + player->deltaviewheight = 0; + } + + if (player->viewheight < VIEWHEIGHT/2) + { + player->viewheight = VIEWHEIGHT/2; + if (player->deltaviewheight <= 0) + player->deltaviewheight = 1; + } + + if (player->deltaviewheight) + { + player->deltaviewheight += FRACUNIT/4; + if (!player->deltaviewheight) + player->deltaviewheight = 1; + } + } + + player->viewz = player->mo->z + player->viewheight + bob; + + if (player->viewz > player->mo->ceilingz-4*FRACUNIT) + player->viewz = player->mo->ceilingz-4*FRACUNIT; + } + + +// +// P_MovePlayer +// +// Adds momentum if the player is not in the air +// +// killough 10/98: simplified + +void P_MovePlayer (player_t* player) +{ + ticcmd_t *cmd = &player->cmd; + mobj_t *mo = player->mo; + + mo->angle += cmd->angleturn << 16; + onground = mo->z <= mo->floorz; + + // e6y + if (demo_smoothturns && player == &players[displayplayer]) + R_SmoothPlaying_Add(cmd->angleturn << 16); + + // killough 10/98: + // + // We must apply thrust to the player and bobbing separately, to avoid + // anomalies. The thrust applied to bobbing is always the same strength on + // ice, because the player still "works just as hard" to move, while the + // thrust applied to the movement varies with 'movefactor'. + + //e6y + if ((!demo_compatibility && !mbf_features) || (cmd->forwardmove | cmd->sidemove)) // killough 10/98 + { + if (onground || mo->flags & MF_BOUNCES) // killough 8/9/98 + { + int friction, movefactor = P_GetMoveFactor(mo, &friction); + + // killough 11/98: + // On sludge, make bobbing depend on efficiency. + // On ice, make it depend on effort. + + int bobfactor = + friction < ORIG_FRICTION ? movefactor : ORIG_FRICTION_FACTOR; + + if (cmd->forwardmove) + { + P_Bob(player,mo->angle,cmd->forwardmove*bobfactor); + P_Thrust(player,mo->angle,cmd->forwardmove*movefactor); + } + + if (cmd->sidemove) + { + P_Bob(player,mo->angle-ANG90,cmd->sidemove*bobfactor); + P_Thrust(player,mo->angle-ANG90,cmd->sidemove*movefactor); + } + } + if (mo->state == states+S_PLAY) + P_SetMobjState(mo,S_PLAY_RUN1); + } +} + +#define ANG5 (ANG90/18) + +// +// P_DeathThink +// Fall on your face when dying. +// Decrease POV height to floor height. +// + +void P_DeathThink (player_t* player) + { + angle_t angle; + angle_t delta; + + P_MovePsprites (player); + + // fall to the ground + + if (player->viewheight > 6*FRACUNIT) + player->viewheight -= FRACUNIT; + + if (player->viewheight < 6*FRACUNIT) + player->viewheight = 6*FRACUNIT; + + player->deltaviewheight = 0; + onground = (player->mo->z <= player->mo->floorz); + P_CalcHeight (player); + + if (player->attacker && player->attacker != player->mo) + { + angle = R_PointToAngle2 (player->mo->x, + player->mo->y, + player->attacker->x, + player->attacker->y); + + delta = angle - player->mo->angle; + + if (delta < ANG5 || delta > (unsigned)-ANG5) + { + // Looking at killer, + // so fade damage flash down. + + player->mo->angle = angle; + + if (player->damagecount) + player->damagecount--; + } + else if (delta < ANG180) + player->mo->angle += ANG5; + else + player->mo->angle -= ANG5; + } + else if (player->damagecount) + player->damagecount--; + + if (player->cmd.buttons & BT_USE) + player->playerstate = PST_REBORN; + R_SmoothPlaying_Reset(player); // e6y + } + + +// +// P_PlayerThink +// + +void P_PlayerThink (player_t* player) + { + ticcmd_t* cmd; + weapontype_t newweapon; + + if (movement_smooth && players && &players[displayplayer] == player) + { + original_view_vars.viewx = player->mo->x; + original_view_vars.viewy = player->mo->y; + original_view_vars.viewz = player->viewz; + original_view_vars.viewangle = R_SmoothPlaying_Get(player->mo->angle) + viewangleoffset; + } + + // killough 2/8/98, 3/21/98: + if (player->cheats & CF_NOCLIP) + player->mo->flags |= MF_NOCLIP; + else + player->mo->flags &= ~MF_NOCLIP; + + // chain saw run forward + + cmd = &player->cmd; + if (player->mo->flags & MF_JUSTATTACKED) + { + cmd->angleturn = 0; + cmd->forwardmove = 0xc800/512; + cmd->sidemove = 0; + player->mo->flags &= ~MF_JUSTATTACKED; + } + + if (player->playerstate == PST_DEAD) + { + P_DeathThink (player); + return; + } + + // Move around. + // Reactiontime is used to prevent movement + // for a bit after a teleport. + + if (player->mo->reactiontime) + player->mo->reactiontime--; + else + P_MovePlayer (player); + + P_CalcHeight (player); // Determines view height and bobbing + + // Determine if there's anything about the sector you're in that's + // going to affect you, like painful floors. + + if (player->mo->subsector->sector->special) + P_PlayerInSpecialSector (player); + + // Check for weapon change. + + if (cmd->buttons & BT_CHANGE) + { + // The actual changing of the weapon is done + // when the weapon psprite can do it + // (read: not in the middle of an attack). + + newweapon = (cmd->buttons & BT_WEAPONMASK)>>BT_WEAPONSHIFT; + + // killough 3/22/98: For demo compatibility we must perform the fist + // and SSG weapons switches here, rather than in G_BuildTiccmd(). For + // other games which rely on user preferences, we must use the latter. + + if (demo_compatibility) + { // compatibility mode -- required for old demos -- killough + if (newweapon == wp_fist && player->weaponowned[wp_chainsaw] && + (player->readyweapon != wp_chainsaw || + !player->powers[pw_strength])) + newweapon = wp_chainsaw; + if (gamemode == commercial && + newweapon == wp_shotgun && + player->weaponowned[wp_supershotgun] && + player->readyweapon != wp_supershotgun) + newweapon = wp_supershotgun; + } + + // killough 2/8/98, 3/22/98 -- end of weapon selection changes + + if (player->weaponowned[newweapon] && newweapon != player->readyweapon) + + // Do not go to plasma or BFG in shareware, + // even if cheated. + + if ((newweapon != wp_plasma && newweapon != wp_bfg) + || (gamemode != shareware) ) + player->pendingweapon = newweapon; + } + + // check for use + + if (cmd->buttons & BT_USE) + { + if (!player->usedown) + { + P_UseLines (player); + player->usedown = true; + } + } + else + player->usedown = false; + + // cycle psprites + + P_MovePsprites (player); + + // Counters, time dependent power ups. + + // Strength counts up to diminish fade. + + if (player->powers[pw_strength]) + player->powers[pw_strength]++; + + // killough 1/98: Make idbeholdx toggle: + + if (player->powers[pw_invulnerability] > 0) // killough + player->powers[pw_invulnerability]--; + + if (player->powers[pw_invisibility] > 0) // killough + if (! --player->powers[pw_invisibility] ) + player->mo->flags &= ~MF_SHADOW; + + if (player->powers[pw_infrared] > 0) // killough + player->powers[pw_infrared]--; + + if (player->powers[pw_ironfeet] > 0) // killough + player->powers[pw_ironfeet]--; + + if (player->damagecount) + player->damagecount--; + + if (player->bonuscount) + player->bonuscount--; + + // Handling colormaps. + // killough 3/20/98: reformat to terse C syntax + + player->fixedcolormap = player->powers[pw_invulnerability] > 4*32 || + player->powers[pw_invulnerability] & 8 ? INVERSECOLORMAP : + player->powers[pw_infrared] > 4*32 || player->powers[pw_infrared] & 8; + } diff --git a/common/prboom/p_user.h b/common/prboom/p_user.h new file mode 100755 index 0000000..b0540e8 --- /dev/null +++ b/common/prboom/p_user.h @@ -0,0 +1,47 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Player related stuff. + * Bobbing POV/weapon, movement. + * Pending weapon. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __P_USER__ +#define __P_USER__ + +#include "d_player.h" + +void P_PlayerThink(player_t *player); +void P_CalcHeight(player_t *player); +void P_DeathThink(player_t *player); +void P_MovePlayer(player_t *player); +void P_Thrust(player_t *player, angle_t angle, fixed_t move); + +#endif /* __P_USER__ */ diff --git a/common/prboom/protocol.h b/common/prboom/protocol.h new file mode 100755 index 0000000..c2af10d --- /dev/null +++ b/common/prboom/protocol.h @@ -0,0 +1,96 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Doom Network protocol packet definitions. + *-----------------------------------------------------------------------------*/ + +#include "doomtype.h" +#include "d_ticcmd.h" +#include "m_swap.h" + +enum packet_type_e { + PKT_INIT, // initial packet to server + PKT_SETUP, // game information packet + PKT_GO, // game has started + PKT_TICC, // tics from client + PKT_TICS, // tics from server + PKT_RETRANS, // Request for retransmission + PKT_EXTRA, // Extra info packet + PKT_QUIT, // Player quit game + PKT_DOWN, // Server downed + PKT_WAD, // Wad file request + PKT_BACKOFF, // Request for client back-off +}; + +typedef struct { + byte checksum; // Simple checksum of the entire packet + byte type; /* Type of packet */ + byte reserved[2]; /* Was random in prboom <=2.2.4, now 0 */ + unsigned tic; // Timestamp +} PACKEDATTR packet_header_t; + +static inline void packet_set(packet_header_t* p, enum packet_type_e t, unsigned long tic) +{ p->tic = doom_htonl(tic); p->type = t; p->reserved[0] = 0; p->reserved[1] = 0; } + +#ifndef GAME_OPTIONS_SIZE +// From g_game.h +#define GAME_OPTIONS_SIZE 64 +#endif + +struct setup_packet_s { + byte players, yourplayer, skill, episode, level, deathmatch, complevel, ticdup, extratic; + byte game_options[GAME_OPTIONS_SIZE]; + byte numwads; + byte wadnames[1]; // Actually longer +}; + +/* cph - convert network byte stream to usable ticcmd_t and visa-versa + * - the functions are functionally identical apart from parameters + * - the void* param can be unaligned. By using void* as the parameter + * it means gcc won't assume alignment so won't make false assumptions + * when optimising. So I'm told. + */ +inline static void RawToTic(ticcmd_t* dst, const void* src) +{ + memcpy(dst,src,sizeof *dst); + dst->angleturn = doom_ntohs(dst->angleturn); + dst->consistancy = doom_ntohs(dst->consistancy); +} + +inline static void TicToRaw(void* dst, const ticcmd_t* src) +{ + /* We have to make a copy of the source struct, then do byte swaps, + * and fnially copy to the destination (can't do the swaps in the + * destination, because it might not be aligned). + */ + ticcmd_t tmp = *src; + tmp.angleturn = doom_ntohs(tmp.angleturn); + tmp.consistancy = doom_ntohs(tmp.consistancy); + memcpy(dst,&tmp,sizeof tmp); +} diff --git a/common/prboom/r_bsp.c b/common/prboom/r_bsp.c new file mode 100755 index 0000000..1bbcf39 --- /dev/null +++ b/common/prboom/r_bsp.c @@ -0,0 +1,664 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * BSP traversal, handling of LineSegs for rendering. + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" +#include "m_bbox.h" +#include "r_main.h" +#include "r_segs.h" +#include "r_plane.h" +#include "r_things.h" +#include "r_bsp.h" // cph - sanity checking +#include "v_video.h" +#include "lprintf.h" + +seg_t *curline; +side_t *sidedef; +line_t *linedef; +sector_t *frontsector; +sector_t *backsector; +drawseg_t *ds_p; + +// killough 4/7/98: indicates doors closed wrt automap bugfix: +// cph - replaced by linedef rendering flags - int doorclosed; + +// killough: New code which removes 2s linedef limit +drawseg_t *drawsegs; +unsigned maxdrawsegs; +// drawseg_t drawsegs[MAXDRAWSEGS]; // old code -- killough + +// +// R_ClearDrawSegs +// + +void R_ClearDrawSegs(void) +{ + ds_p = drawsegs; +} + +// CPhipps - +// Instead of clipsegs, let's try using an array with one entry for each column, +// indicating whether it's blocked by a solid wall yet or not. + +byte solidcol[MAX_SCREENWIDTH]; + +// CPhipps - +// R_ClipWallSegment +// +// Replaces the old R_Clip*WallSegment functions. It draws bits of walls in those +// columns which aren't solid, and updates the solidcol[] array appropriately + +static void R_ClipWallSegment(int first, int last, boolean solid) +{ + byte *p; + while (first < last) { + if (solidcol[first]) { + if (!(p = memchr(solidcol+first, 0, last-first))) return; // All solid + first = p - solidcol; + } else { + int to; + if (!(p = memchr(solidcol+first, 1, last-first))) to = last; + else to = p - solidcol; + R_StoreWallRange(first, to-1); + if (solid) { + memset(solidcol+first,1,to-first); + } + first = to; + } + } +} + +// +// R_ClearClipSegs +// + +void R_ClearClipSegs (void) +{ + memset(solidcol, 0, SCREENWIDTH); +} + +// killough 1/18/98 -- This function is used to fix the automap bug which +// showed lines behind closed doors simply because the door had a dropoff. +// +// cph - converted to R_RecalcLineFlags. This recalculates all the flags for +// a line, including closure and texture tiling. + +static void R_RecalcLineFlags(void) +{ + linedef->r_validcount = gametic; + + /* First decide if the line is closed, normal, or invisible */ + if (!(linedef->flags & ML_TWOSIDED) + || backsector->ceilingheight <= frontsector->floorheight + || backsector->floorheight >= frontsector->ceilingheight + || ( + // if door is closed because back is shut: + backsector->ceilingheight <= backsector->floorheight + + // preserve a kind of transparent door/lift special effect: + && (backsector->ceilingheight >= frontsector->ceilingheight || + curline->sidedef->toptexture) + + && (backsector->floorheight <= frontsector->floorheight || + curline->sidedef->bottomtexture) + + // properly render skies (consider door "open" if both ceilings are sky): + && (backsector->ceilingpic !=skyflatnum || + frontsector->ceilingpic!=skyflatnum) + ) + ) + linedef->r_flags = RF_CLOSED; + else { + // Reject empty lines used for triggers + // and special events. + // Identical floor and ceiling on both sides, + // identical light levels on both sides, + // and no middle texture. + // CPhipps - recode for speed, not certain if this is portable though + if (backsector->ceilingheight != frontsector->ceilingheight + || backsector->floorheight != frontsector->floorheight + || curline->sidedef->midtexture + || memcmp(&backsector->floor_xoffs, &frontsector->floor_xoffs, + sizeof(frontsector->floor_xoffs) + sizeof(frontsector->floor_yoffs) + + sizeof(frontsector->ceiling_xoffs) + sizeof(frontsector->ceiling_yoffs) + + sizeof(frontsector->ceilingpic) + sizeof(frontsector->floorpic) + + sizeof(frontsector->lightlevel) + sizeof(frontsector->floorlightsec) + + sizeof(frontsector->ceilinglightsec))) { + linedef->r_flags = 0; return; + } else + linedef->r_flags = RF_IGNORE; + } + + /* cph - I'm too lazy to try and work with offsets in this */ + if (curline->sidedef->rowoffset) return; + + /* Now decide on texture tiling */ + if (linedef->flags & ML_TWOSIDED) { + int c; + + /* Does top texture need tiling */ + if ((c = frontsector->ceilingheight - backsector->ceilingheight) > 0 && + (textureheight[texturetranslation[curline->sidedef->toptexture]] > c)) + linedef->r_flags |= RF_TOP_TILE; + + /* Does bottom texture need tiling */ + if ((c = frontsector->floorheight - backsector->floorheight) > 0 && + (textureheight[texturetranslation[curline->sidedef->bottomtexture]] > c)) + linedef->r_flags |= RF_BOT_TILE; + } else { + int c; + /* Does middle texture need tiling */ + if ((c = frontsector->ceilingheight - frontsector->floorheight) > 0 && + (textureheight[texturetranslation[curline->sidedef->midtexture]] > c)) + linedef->r_flags |= RF_MID_TILE; + } +} + +// +// killough 3/7/98: Hack floor/ceiling heights for deep water etc. +// +// If player's view height is underneath fake floor, lower the +// drawn ceiling to be just under the floor height, and replace +// the drawn floor and ceiling textures, and light level, with +// the control sector's. +// +// Similar for ceiling, only reflected. +// +// killough 4/11/98, 4/13/98: fix bugs, add 'back' parameter +// + +sector_t *R_FakeFlat(sector_t *sec, sector_t *tempsec, + int *floorlightlevel, int *ceilinglightlevel, + boolean back) +{ + if (floorlightlevel) + *floorlightlevel = sec->floorlightsec == -1 ? + sec->lightlevel : sectors[sec->floorlightsec].lightlevel; + + if (ceilinglightlevel) + *ceilinglightlevel = sec->ceilinglightsec == -1 ? // killough 4/11/98 + sec->lightlevel : sectors[sec->ceilinglightsec].lightlevel; + + if (sec->heightsec != -1) + { + const sector_t *s = §ors[sec->heightsec]; + int heightsec = viewplayer->mo->subsector->sector->heightsec; + int underwater = heightsec!=-1 && viewz<=sectors[heightsec].floorheight; + + // Replace sector being drawn, with a copy to be hacked + *tempsec = *sec; + + // Replace floor and ceiling height with other sector's heights. + tempsec->floorheight = s->floorheight; + tempsec->ceilingheight = s->ceilingheight; + + // killough 11/98: prevent sudden light changes from non-water sectors: + if (underwater && (tempsec-> floorheight = sec->floorheight, + tempsec->ceilingheight = s->floorheight-1, !back)) + { // head-below-floor hack + tempsec->floorpic = s->floorpic; + tempsec->floor_xoffs = s->floor_xoffs; + tempsec->floor_yoffs = s->floor_yoffs; + + if (underwater) { + if (s->ceilingpic == skyflatnum) { + tempsec->floorheight = tempsec->ceilingheight+1; + tempsec->ceilingpic = tempsec->floorpic; + tempsec->ceiling_xoffs = tempsec->floor_xoffs; + tempsec->ceiling_yoffs = tempsec->floor_yoffs; + } else { + tempsec->ceilingpic = s->ceilingpic; + tempsec->ceiling_xoffs = s->ceiling_xoffs; + tempsec->ceiling_yoffs = s->ceiling_yoffs; + } + } + + tempsec->lightlevel = s->lightlevel; + + if (floorlightlevel) + *floorlightlevel = s->floorlightsec == -1 ? s->lightlevel : + sectors[s->floorlightsec].lightlevel; // killough 3/16/98 + + if (ceilinglightlevel) + *ceilinglightlevel = s->ceilinglightsec == -1 ? s->lightlevel : + sectors[s->ceilinglightsec].lightlevel; // killough 4/11/98 + } + else + if (heightsec != -1 && viewz >= sectors[heightsec].ceilingheight && + sec->ceilingheight > s->ceilingheight) + { // Above-ceiling hack + tempsec->ceilingheight = s->ceilingheight; + tempsec->floorheight = s->ceilingheight + 1; + + tempsec->floorpic = tempsec->ceilingpic = s->ceilingpic; + tempsec->floor_xoffs = tempsec->ceiling_xoffs = s->ceiling_xoffs; + tempsec->floor_yoffs = tempsec->ceiling_yoffs = s->ceiling_yoffs; + + if (s->floorpic != skyflatnum) + { + tempsec->ceilingheight = sec->ceilingheight; + tempsec->floorpic = s->floorpic; + tempsec->floor_xoffs = s->floor_xoffs; + tempsec->floor_yoffs = s->floor_yoffs; + } + + tempsec->lightlevel = s->lightlevel; + + if (floorlightlevel) + *floorlightlevel = s->floorlightsec == -1 ? s->lightlevel : + sectors[s->floorlightsec].lightlevel; // killough 3/16/98 + + if (ceilinglightlevel) + *ceilinglightlevel = s->ceilinglightsec == -1 ? s->lightlevel : + sectors[s->ceilinglightsec].lightlevel; // killough 4/11/98 + } + sec = tempsec; // Use other sector + } + return sec; +} + +// +// R_AddLine +// Clips the given segment +// and adds any visible pieces to the line list. +// + +static void R_AddLine (seg_t *line) +{ + int x1; + int x2; + angle_t angle1; + angle_t angle2; + angle_t span; + angle_t tspan; + static sector_t tempsec; // killough 3/8/98: ceiling/water hack + + curline = line; + + angle1 = R_PointToAngle (line->v1->x, line->v1->y); + angle2 = R_PointToAngle (line->v2->x, line->v2->y); + + // Clip to view edges. + span = angle1 - angle2; + + // Back side, i.e. backface culling + if (span >= ANG180) + return; + + // Global angle needed by segcalc. + rw_angle1 = angle1; + angle1 -= viewangle; + angle2 -= viewangle; + + tspan = angle1 + clipangle; + if (tspan > 2*clipangle) + { + tspan -= 2*clipangle; + + // Totally off the left edge? + if (tspan >= span) + return; + + angle1 = clipangle; + } + + tspan = clipangle - angle2; + if (tspan > 2*clipangle) + { + tspan -= 2*clipangle; + + // Totally off the left edge? + if (tspan >= span) + return; + angle2 = 0-clipangle; + } + + // The seg is in the view range, + // but not necessarily visible. + + angle1 = (angle1+ANG90)>>ANGLETOFINESHIFT; + angle2 = (angle2+ANG90)>>ANGLETOFINESHIFT; + + // killough 1/31/98: Here is where "slime trails" can SOMETIMES occur: + x1 = viewangletox[angle1]; + x2 = viewangletox[angle2]; + +#ifdef GL_DOOM + // proff 11/99: we have to add these segs to avoid gaps in OpenGL + if (x1 >= x2) // killough 1/31/98 -- change == to >= for robustness + { + if (V_GetMode() == VID_MODEGL) + { + if (ds_p == drawsegs+maxdrawsegs) // killough 1/98 -- fix 2s line HOM + { + unsigned pos = ds_p - drawsegs; // jff 8/9/98 fix from ZDOOM1.14a + unsigned newmax = maxdrawsegs ? maxdrawsegs*2 : 128; // killough + drawsegs = realloc(drawsegs,newmax*sizeof(*drawsegs)); + //ds_p = drawsegs+maxdrawsegs; + ds_p = drawsegs + pos; // jff 8/9/98 fix from ZDOOM1.14a + maxdrawsegs = newmax; + } + ds_p->curline = curline; + ds_p++; + gld_AddWall(curline); + return; + } + else + return; + } +#else + // Does not cross a pixel? + if (x1 >= x2) // killough 1/31/98 -- change == to >= for robustness + return; +#endif + + backsector = line->backsector; + + // Single sided line? + if (backsector) + // killough 3/8/98, 4/4/98: hack for invisible ceilings / deep water + backsector = R_FakeFlat(backsector, &tempsec, NULL, NULL, true); + + /* cph - roll up linedef properties in flags */ + if ((linedef = curline->linedef)->r_validcount != gametic) + R_RecalcLineFlags(); + + if (linedef->r_flags & RF_IGNORE) + { + return; + } + else + R_ClipWallSegment (x1, x2, linedef->r_flags & RF_CLOSED); +} + +// +// R_CheckBBox +// Checks BSP node/subtree bounding box. +// Returns true +// if some part of the bbox might be visible. +// + +static const int checkcoord[12][4] = // killough -- static const +{ + {3,0,2,1}, + {3,0,2,0}, + {3,1,2,0}, + {0}, + {2,0,2,1}, + {0,0,0,0}, + {3,1,3,0}, + {0}, + {2,0,3,1}, + {2,1,3,1}, + {2,1,3,0} +}; + +// killough 1/28/98: static // CPhipps - const parameter, reformatted +static boolean R_CheckBBox(const fixed_t *bspcoord) +{ + angle_t angle1, angle2; + + { + int boxpos; + const int* check; + + // Find the corners of the box + // that define the edges from current viewpoint. + boxpos = (viewx <= bspcoord[BOXLEFT] ? 0 : viewx < bspcoord[BOXRIGHT ] ? 1 : 2) + + (viewy >= bspcoord[BOXTOP ] ? 0 : viewy > bspcoord[BOXBOTTOM] ? 4 : 8); + + if (boxpos == 5) + return true; + + check = checkcoord[boxpos]; + angle1 = R_PointToAngle (bspcoord[check[0]], bspcoord[check[1]]) - viewangle; + angle2 = R_PointToAngle (bspcoord[check[2]], bspcoord[check[3]]) - viewangle; + } + + // cph - replaced old code, which was unclear and badly commented + // Much more efficient code now + if ((signed)angle1 < (signed)angle2) { /* it's "behind" us */ + /* Either angle1 or angle2 is behind us, so it doesn't matter if we + * change it to the corect sign + */ + if ((angle1 >= ANG180) && (angle1 < ANG270)) + angle1 = INT_MAX; /* which is ANG180-1 */ + else + angle2 = INT_MIN; + } + + if ((signed)angle2 >= (signed)clipangle) return false; // Both off left edge + if ((signed)angle1 <= -(signed)clipangle) return false; // Both off right edge + if ((signed)angle1 >= (signed)clipangle) angle1 = clipangle; // Clip at left edge + if ((signed)angle2 <= -(signed)clipangle) angle2 = 0-clipangle; // Clip at right edge + + // Find the first clippost + // that touches the source post + // (adjacent pixels are touching). + angle1 = (angle1+ANG90)>>ANGLETOFINESHIFT; + angle2 = (angle2+ANG90)>>ANGLETOFINESHIFT; + { + int sx1 = viewangletox[angle1]; + int sx2 = viewangletox[angle2]; + // const cliprange_t *start; + + // Does not cross a pixel. + if (sx1 == sx2) + return false; + + if (!memchr(solidcol+sx1, 0, sx2-sx1)) return false; + // All columns it covers are already solidly covered + } + + return true; +} + +// +// R_Subsector +// Determine floor/ceiling planes. +// Add sprites of things in sector. +// Draw one or more line segments. +// +// killough 1/31/98 -- made static, polished +// JDC: removed static so it won't be inlined in R_RenderBSPNode, which bloats the recursive stack +/* static */ void R_Subsector(int num) +{ + int count; + seg_t *line; + subsector_t *sub; + sector_t tempsec; // killough 3/7/98: deep water hack + int floorlightlevel; // killough 3/16/98: set floor lightlevel + int ceilinglightlevel; // killough 4/11/98 +#ifdef GL_DOOM + visplane_t dummyfloorplane; + visplane_t dummyceilingplane; +#endif + +#ifdef RANGECHECK + if (num>=numsubsectors) + I_Error ("R_Subsector: ss %i with numss = %i", num, numsubsectors); +#endif + + sub = &subsectors[num]; + frontsector = sub->sector; + count = sub->numlines; + line = &segs[sub->firstline]; + + // killough 3/8/98, 4/4/98: Deep water / fake ceiling effect + frontsector = R_FakeFlat(frontsector, &tempsec, &floorlightlevel, + &ceilinglightlevel, false); // killough 4/11/98 + + // killough 3/7/98: Add (x,y) offsets to flats, add deep water check + // killough 3/16/98: add floorlightlevel + // killough 10/98: add support for skies transferred from sidedefs + + floorplane = frontsector->floorheight < viewz || // killough 3/7/98 + (frontsector->heightsec != -1 && + sectors[frontsector->heightsec].ceilingpic == skyflatnum) ? + R_FindPlane(frontsector->floorheight, + frontsector->floorpic == skyflatnum && // kilough 10/98 + frontsector->sky & PL_SKYFLAT ? frontsector->sky : + frontsector->floorpic, + floorlightlevel, // killough 3/16/98 + frontsector->floor_xoffs, // killough 3/7/98 + frontsector->floor_yoffs + ) : NULL; + + ceilingplane = frontsector->ceilingheight > viewz || + frontsector->ceilingpic == skyflatnum || + (frontsector->heightsec != -1 && + sectors[frontsector->heightsec].floorpic == skyflatnum) ? + R_FindPlane(frontsector->ceilingheight, // killough 3/8/98 + frontsector->ceilingpic == skyflatnum && // kilough 10/98 + frontsector->sky & PL_SKYFLAT ? frontsector->sky : + frontsector->ceilingpic, + ceilinglightlevel, // killough 4/11/98 + frontsector->ceiling_xoffs, // killough 3/7/98 + frontsector->ceiling_yoffs + ) : NULL; +#ifdef GL_DOOM + // check if the sector is faked + if ((frontsector==sub->sector) && (V_GetMode() == VID_MODEGL)) + { + // if the sector has bottomtextures, then the floorheight will be set to the + // highest surounding floorheight + if ((frontsector->no_bottomtextures) || (!floorplane)) + { + int i=frontsector->linecount; + + dummyfloorplane.height=INT_MIN; + while (i--) + { + line_t *tmpline=frontsector->lines[i]; + if (tmpline->backsector) + if (tmpline->backsector != frontsector) + if (tmpline->backsector->floorheight>dummyfloorplane.height) + { + dummyfloorplane.height=tmpline->backsector->floorheight; + dummyfloorplane.lightlevel=tmpline->backsector->lightlevel; + } + if (tmpline->frontsector) + if (tmpline->frontsector != frontsector) + if (tmpline->frontsector->floorheight>dummyfloorplane.height) + { + dummyfloorplane.height=tmpline->frontsector->floorheight; + dummyfloorplane.lightlevel=tmpline->frontsector->lightlevel; + } + } + if (dummyfloorplane.height!=INT_MIN) + floorplane=&dummyfloorplane; + } + // the same for ceilings. they will be set to the lowest ceilingheight + if ((frontsector->no_toptextures) || (!ceilingplane)) + { + int i=frontsector->linecount; + + dummyceilingplane.height=INT_MAX; + while (i--) + { + line_t *tmpline=frontsector->lines[i]; + if (tmpline->backsector) + if (tmpline->backsector != frontsector) + if (tmpline->backsector->ceilingheightbacksector->ceilingheight; + dummyceilingplane.lightlevel=tmpline->backsector->lightlevel; + } + if (tmpline->frontsector) + if (tmpline->frontsector != frontsector) + if (tmpline->frontsector->ceilingheightfrontsector->ceilingheight; + dummyceilingplane.lightlevel=tmpline->frontsector->lightlevel; + } + } + if (dummyceilingplane.height!=INT_MAX) + ceilingplane=&dummyceilingplane; + } + } +#endif + + // killough 9/18/98: Fix underwater slowdown, by passing real sector + // instead of fake one. Improve sprite lighting by basing sprite + // lightlevels on floor & ceiling lightlevels in the surrounding area. + // + // 10/98 killough: + // + // NOTE: TeamTNT fixed this bug incorrectly, messing up sprite lighting!!! + // That is part of the 242 effect!!! If you simply pass sub->sector to + // the old code you will not get correct lighting for underwater sprites!!! + // Either you must pass the fake sector and handle validcount here, on the + // real sector, or you must account for the lighting in some other way, + // like passing it as an argument. + + R_AddSprites(sub, (floorlightlevel+ceilinglightlevel)/2); + while (count--) + { + if (line->miniseg == false) + R_AddLine (line); + line++; + curline = NULL; /* cph 2001/11/18 - must clear curline now we're done with it, so R_ColourMap doesn't try using it for other things */ + } +#ifdef GL_DOOM + if (V_GetMode() == VID_MODEGL) + gld_AddPlane(num, floorplane, ceilingplane); +#endif +} + +// +// RenderBSPNode +// Renders all subsectors below a given node, +// traversing subtree recursively. +// Just call with BSP root. +// +// killough 5/2/98: reformatted, removed tail recursion + +void R_RenderBSPNode(int bspnum) +{ + while (!(bspnum & NF_SUBSECTOR)) // Found a subsector? + { + const node_t *bsp = &nodes[bspnum]; + + // Decide which side the view point is on. + int side = R_PointOnSide(viewx, viewy, bsp); + // Recursively divide front space. + R_RenderBSPNode(bsp->children[side]); + + // Possibly divide back space. + + if (!R_CheckBBox(bsp->bbox[side^1])) + return; + + bspnum = bsp->children[side^1]; + } + R_Subsector(bspnum == -1 ? 0 : bspnum & ~NF_SUBSECTOR); +} diff --git a/common/prboom/r_bsp.h b/common/prboom/r_bsp.h new file mode 100755 index 0000000..4ba9190 --- /dev/null +++ b/common/prboom/r_bsp.h @@ -0,0 +1,64 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Refresh module, BSP traversal and handling. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __R_BSP__ +#define __R_BSP__ + +#ifdef __GNUG__ +#pragma interface +#endif + +extern seg_t *curline; +extern side_t *sidedef; +extern line_t *linedef; +extern sector_t *frontsector; +extern sector_t *backsector; + +/* old code -- killough: + * extern drawseg_t drawsegs[MAXDRAWSEGS]; + * new code -- killough: */ +extern drawseg_t *drawsegs; +extern unsigned maxdrawsegs; + +extern byte solidcol[MAX_SCREENWIDTH]; + +extern drawseg_t *ds_p; + +void R_ClearClipSegs(void); +void R_ClearDrawSegs(void); +void R_RenderBSPNode(int bspnum); + +/* killough 4/13/98: fake floors/ceilings for deep water / fake ceilings: */ +sector_t *R_FakeFlat(sector_t *, sector_t *, int *, int *, boolean); + +#endif diff --git a/common/prboom/r_data.c b/common/prboom/r_data.c new file mode 100755 index 0000000..eb90138 --- /dev/null +++ b/common/prboom/r_data.c @@ -0,0 +1,781 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2002 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Preparation of data for rendering, + * generation of lookups, caching, retrieval by name. + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" +#include "w_wad.h" +#include "r_draw.h" +#include "r_main.h" +#include "r_sky.h" +#include "i_system.h" +#include "r_bsp.h" +#include "r_things.h" +#include "p_tick.h" +#include "lprintf.h" // jff 08/03/98 - declaration of lprintf +#include "p_tick.h" + +// +// Graphics. +// DOOM graphics for walls and sprites +// is stored in vertical runs of opaque pixels (posts). +// A column is composed of zero or more posts, +// a patch or sprite is composed of zero or more columns. +// + +// +// Texture definition. +// Each texture is composed of one or more patches, +// with patches being lumps stored in the WAD. +// The lumps are referenced by number, and patched +// into the rectangular texture space using origin +// and possibly other attributes. +// + +typedef struct +{ + short originx; + short originy; + short patch; + short stepdir; // unused in Doom but might be used in Phase 2 Boom + short colormap; // unused in Doom but might be used in Phase 2 Boom +} PACKEDATTR mappatch_t; + + +typedef struct +{ + char name[8]; + char pad2[4]; // unused + short width; + short height; + char pad[4]; // unused in Doom but might be used in Boom Phase 2 + short patchcount; + mappatch_t patches[1]; +} PACKEDATTR maptexture_t; + +// A maptexturedef_t describes a rectangular texture, which is composed +// of one or more mappatch_t structures that arrange graphic patches. + +// killough 4/17/98: make firstcolormaplump,lastcolormaplump external +int firstcolormaplump, lastcolormaplump; // killough 4/17/98 + +int firstflat, lastflat, numflats; +int firstspritelump, lastspritelump, numspritelumps; +int numtextures; +texture_t **textures; // proff - 04/05/2000 removed static for OpenGL +fixed_t *textureheight; //needed for texture pegging (and TFE fix - killough) +int *flattranslation; // for global animation +int *texturetranslation; + +// +// R_GetTextureColumn +// + +const byte *R_GetTextureColumn(const rpatch_t *texpatch, int col) { + while (col < 0) + col += texpatch->width; + col &= texpatch->widthmask; + + return texpatch->columns[col].pixels; +} + +// +// R_InitTextures +// Initializes the texture list +// with the textures from the world map. +// + +static void R_InitTextures (void) +{ + const maptexture_t *mtexture; + texture_t *texture; + const mappatch_t *mpatch; + texpatch_t *patch; + int i, j; + int maptex_lump[2] = {-1, -1}; + const int *maptex; + const int *maptex1, *maptex2; + char name[9]; + int names_lump; // cph - new wad lump handling + const char *names; // cph - + const char *name_p;// const*'s + int *patchlookup; + int totalwidth; + int nummappatches; + int offset; + int maxoff, maxoff2; + int numtextures1, numtextures2; + const int *directory; + int errors = 0; + + // Load the patch names from pnames.lmp. + name[8] = 0; + names = W_CacheLumpNum(names_lump = W_GetNumForName("PNAMES")); + nummappatches = LONG(*((const int *)names)); + name_p = names+4; + patchlookup = malloc(nummappatches*sizeof(*patchlookup)); // killough + + for (i=0 ; i maxoff) + I_Error("R_InitTextures: Bad texture directory"); + + mtexture = (const maptexture_t *) ( (const byte *)maptex + offset); + + texture = textures[i] = + Z_Malloc(sizeof(texture_t) + + sizeof(texpatch_t)*(SHORT(mtexture->patchcount)-1), + PU_STATIC, 0); + + texture->width = SHORT(mtexture->width); + texture->height = SHORT(mtexture->height); + texture->patchcount = SHORT(mtexture->patchcount); + + /* Mattias Engdegård emailed me of the following explenation of + * why memcpy doesnt work on some systems: + * "I suppose it is the mad unaligned allocation + * going on (and which gcc in some way manages to cope with + * through the __attribute__ ((packed))), and which it forgets + * when optimizing memcpy (to a single word move) since it appears + * to be aligned. Technically a gcc bug, but I can't blame it when + * it's stressed with that amount of + * non-standard nonsense." + * So in short the unaligned struct confuses gcc's optimizer so + * i took the memcpy out alltogether to avoid future problems-Jess + */ + /* The above was #ifndef SPARC, but i got a mail from + * Putera Joseph F NPRI containing: + * I had to use the memcpy function on a sparc machine. The + * other one would give me a core dump. + * cph - I find it hard to believe that sparc memcpy is broken, + * but I don't believe the pointers to memcpy have to be aligned + * either. Use fast memcpy on other machines anyway. + */ +/* + proff - I took this out, because Oli Kraus (olikraus@yahoo.com) told + me the memcpy produced a buserror. Since this function isn't time- + critical I'm using the for loop now. +*/ +/* +#ifndef GCC + memcpy(texture->name, mtexture->name, sizeof(texture->name)); +#else +*/ + { + for(j=0;jname);j++) + texture->name[j]=mtexture->name[j]; + } +/* #endif */ + + mpatch = mtexture->patches; + patch = texture->patches; + + for (j=0 ; jpatchcount ; j++, mpatch++, patch++) + { + patch->originx = SHORT(mpatch->originx); + patch->originy = SHORT(mpatch->originy); + patch->patch = patchlookup[SHORT(mpatch->patch)]; + if (patch->patch == -1) + { + //jff 8/3/98 use logical output routine + lprintf(LO_ERROR,"\nR_InitTextures: Missing patch %d in texture %.8s", + SHORT(mpatch->patch), texture->name); // killough 4/17/98 + ++errors; + } + } + + for (j=1; j*2 <= texture->width; j<<=1) + ; + texture->widthmask = j-1; + textureheight[i] = texture->height<width; + } + + free(patchlookup); // killough + + for (i=0; i<2; i++) // cph - release the TEXTUREx lumps + if (maptex_lump[i] != -1) + W_UnlockLumpNum(maptex_lump[i]); + + if (errors) + I_Error("R_InitTextures: %d errors", errors); + + // Precalculate whatever possible. + if (devparm) // cph - If in development mode, generate now so all errors are found at once + for (i=0 ; iindex = -1; + while (--i >= 0) + { + int texturej = W_LumpNameHash(textures[i]->name) % (unsigned) numtextures; + textures[i]->next = textures[texturej]->index; // Prepend to chain + textures[texturej]->index = i; + } +} + +// +// R_InitFlats +// +static void R_InitFlats(void) +{ + int i; + + firstflat = W_GetNumForName("F_START") + 1; + lastflat = W_GetNumForName("F_END") - 1; + numflats = lastflat - firstflat + 1; + + // Create translation table for global animation. + // killough 4/9/98: make column offsets 32-bit; + // clean up malloc-ing to use sizeof + + flattranslation = + Z_Malloc((numflats+1)*sizeof(*flattranslation), PU_STATIC, 0); + + for (i=0 ; i x ? l : x > u ? u : x); } + +const lighttable_t* R_ColourMap(int lightlevel, fixed_t spriteyscale) +{ + if (fixedcolormap) return fixedcolormap; + else { + if (curline) + if (curline->v1->y == curline->v2->y) + lightlevel -= 1 << LIGHTSEGSHIFT; + else + if (curline->v1->x == curline->v2->x) + lightlevel += 1 << LIGHTSEGSHIFT; + + lightlevel += extralight << LIGHTSEGSHIFT; + + /* cph 2001/11/17 - + * Work out what colour map to use, remembering to clamp it to the number of + * colour maps we actually have. This formula is basically the one from the + * original source, just brought into one place. The main difference is it + * throws away less precision in the lightlevel half, so it supports 32 + * light levels in WADs compared to Doom's 16. + * + * Note we can make it more accurate if we want - we should keep all the + * precision until the final step, so slight scale differences can count + * against slight light level variations. + */ + return fullcolormap + between(0,NUMCOLORMAPS-1, + ((256-lightlevel)*2*NUMCOLORMAPS/256) - 4 + - (FixedMul(spriteyscale,pspriteiscale)/2 >> LIGHTSCALESHIFT) + )*256; + } +} + +// +// R_InitTranMap +// +// Initialize translucency filter map +// +// By Lee Killough 2/21/98 +// + +int tran_filter_pct = 66; // filter percent + +#define TSC 12 /* number of fixed point digits in filter percent */ + +void R_InitTranMap(int progress) +{ + int lump = W_CheckNumForName("TRANMAP"); + + // If a tranlucency filter map lump is present, use it + + if (lump != -1) // Set a pointer to the translucency filter maps. + main_tranmap = W_CacheLumpNum(lump); // killough 4/11/98 + else if (W_CheckNumForName("PLAYPAL")!=-1) // can be called before WAD loaded + { // Compose a default transparent filter map based on PLAYPAL. + const byte *playpal = W_CacheLumpName("PLAYPAL"); + byte *my_tranmap; + + char fname[PATH_MAX+1]; + struct { + unsigned char pct; + unsigned char playpal[256]; + } cache; + FILE *cachefp = fopen(strcat(strcpy(fname, I_DoomExeDir()), "/tranmap.dat"),"rb"); + + main_tranmap = my_tranmap = Z_Malloc(256*256, PU_STATIC, 0); // killough 4/11/98 + + // Use cached translucency filter if it's available + + if (!cachefp || + fread(&cache, 1, sizeof cache, cachefp) != sizeof cache || + cache.pct != tran_filter_pct || + memcmp(cache.playpal, playpal, sizeof cache.playpal) || + fread(my_tranmap, 256, 256, cachefp) != 256 ) // killough 4/11/98 + { + long pal[3][256], tot[256], pal_w1[3][256]; + long w1 = ((unsigned long) tran_filter_pct<=0); + } + + // Next, compute all entries using minimum arithmetic. + + { + int i,j; + byte *tp = my_tranmap; + for (i=0;i<256;i++) + { + long r1 = pal[0][i] * w2; + long g1 = pal[1][i] * w2; + long b1 = pal[2][i] * w2; + if (!(i & 31) && progress) + //jff 8/3/98 use logical output routine + lprintf(LO_INFO,"."); + for (j=0;j<256;j++,tp++) + { + register int color = 255; + register long err; + long r = pal_w1[0][j] + r1; + long g = pal_w1[1][j] + g1; + long b = pal_w1[2][j] + b1; + long best = LONG_MAX; + do + if ((err = tot[color] - pal[0][color]*r + - pal[1][color]*g - pal[2][color]*b) < best) + best = err, *tp = color; + while (--color >= 0); + } + } + } + if ((cachefp = fopen(fname,"wb")) != NULL) // write out the cached translucency map + { + cache.pct = tran_filter_pct; + memcpy(cache.playpal, playpal, 256); + fseek(cachefp, 0, SEEK_SET); + fwrite(&cache, 1, sizeof cache, cachefp); + fwrite(main_tranmap, 256, 256, cachefp); + // CPhipps - leave close for a few lines... + } + } + + if (cachefp) // killough 11/98: fix filehandle leak + fclose(cachefp); + + W_UnlockLumpName("PLAYPAL"); + } +} + +// +// R_InitData +// Locates all the lumps +// that will be used by all views +// Must be called after W_Init. +// + +void R_InitData(void) +{ + lprintf(LO_INFO, "Textures "); + R_InitTextures(); + lprintf(LO_INFO, "Flats "); + R_InitFlats(); + lprintf(LO_INFO, "Sprites "); + R_InitSpriteLumps(); + if (default_translucency) // killough 3/1/98 + R_InitTranMap(1); // killough 2/21/98, 3/6/98 + R_InitColormaps(); // killough 3/20/98 +} + +// +// R_FlatNumForName +// Retrieval, get a flat number for a flat name. +// +// killough 4/17/98: changed to use ns_flats namespace +// + +int R_FlatNumForName(const char *name) // killough -- const added +{ + int i = (W_CheckNumForName)(name, ns_flats); + if (i == -1) + I_Error("R_FlatNumForName: %.8s not found", name); + return i - firstflat; +} + +// +// R_CheckTextureNumForName +// Check whether texture is available. +// Filter out NoTexture indicator. +// +// Rewritten by Lee Killough to use hash table for fast lookup. Considerably +// reduces the time needed to start new levels. See w_wad.c for comments on +// the hashing algorithm, which is also used for lump searches. +// +// killough 1/21/98, 1/31/98 +// + +int PUREFUNC R_CheckTextureNumForName(const char *name) +{ + int i = NO_TEXTURE; + if (*name != '-') // "NoTexture" marker. + { + i = textures[W_LumpNameHash(name) % (unsigned) numtextures]->index; + while (i >= 0 && strncasecmp(textures[i]->name,name,8)) + i = textures[i]->next; + } + return i; +} + +// Maps textures with things we can't show in Germany to appropriate textures. +static const char * germanyRemap[][2] = { + { "ZZWOLF2", "ZZWOLF1" }, + { "ZZWOLF3", "ZZWOLF1" }, + { "ZZWOLF4", "ZZWOLF1" }, + { "ZZWOLF6", "ZZWOLF5" }, + { "ZZWOLF7", "ZZWOLF5" }, + { "ZZWOLF12", "ZZWOLF11" }, + { "ZZWOLF13", "ZZWOLF11" }, + { NULL, NULL } +}; + +// +// R_RemapTextureForGermany +// Given a texture name, returns a suitable replacement texture without any images of swastikas +// or Hitler. +// +const char * R_RemapTextureForGermany( const char * name ) { + return name; + + const char ** currentTestPair = germanyRemap[0]; + + while ( currentTestPair[0] != NULL ) { + if ( strncmp( currentTestPair[0], name, 8 ) == 0 ) { + return currentTestPair[1]; + } + + currentTestPair += 2; + } + + return name; +} + +// +// R_TextureNumForName +// Calls R_CheckTextureNumForName, +// aborts with error message. +// + +int PUREFUNC R_TextureNumForName(const char *name) // const added -- killough +{ + const char * remappedName = R_RemapTextureForGermany( name ); + + int i = R_CheckTextureNumForName(remappedName); + if (i == -1) + I_Error("R_TextureNumForName: %.8s not found", remappedName); + return i; +} + +// +// R_SafeTextureNumForName +// Calls R_CheckTextureNumForName, and changes any error to NO_TEXTURE +int PUREFUNC R_SafeTextureNumForName(const char *name, int snum) +{ + const char * remappedName = R_RemapTextureForGermany( name ); + + int i = R_CheckTextureNumForName(remappedName); + if (i == -1) { + i = NO_TEXTURE; // e6y - return "no texture" + lprintf(LO_DEBUG,"bad texture '%s' in sidedef %d\n",remappedName,snum); + } + return i; +} + +// +// R_PrecacheLevel +// Preloads all relevant graphics for the level. +// +// Totally rewritten by Lee Killough to use less memory, +// to avoid using alloca(), and to improve performance. +// cph - new wad lump handling, calls cache functions but acquires no locks + +static inline void precache_lump(int l) +{ + W_CacheLumpNum(l); W_UnlockLumpNum(l); +} + +void R_PrecacheLevel(void) +{ + register int i; + register byte *hitlist; + + if (demoplayback) + return; + + { + size_t size = numflats > numsprites ? numflats : numsprites; + hitlist = malloc((size_t)numtextures > size ? numtextures : size); + } + + // Precache flats. + + memset(hitlist, 0, numflats); + + for (i = numsectors; --i >= 0; ) + hitlist[sectors[i].floorpic] = hitlist[sectors[i].ceilingpic] = 1; + + for (i = numflats; --i >= 0; ) + if (hitlist[i]) + precache_lump(firstflat + i); + + // Precache textures. + + memset(hitlist, 0, numtextures); + + for (i = numsides; --i >= 0;) + hitlist[sides[i].bottomtexture] = + hitlist[sides[i].toptexture] = + hitlist[sides[i].midtexture] = 1; + + // Sky texture is always present. + // Note that F_SKY1 is the name used to + // indicate a sky floor/ceiling as a flat, + // while the sky texture is stored like + // a wall texture, with an episode dependend + // name. + + hitlist[skytexture] = 1; + + for (i = numtextures; --i >= 0; ) + if (hitlist[i]) + { + texture_t *texture = textures[i]; + int j = texture->patchcount; + while (--j >= 0) + precache_lump(texture->patches[j].patch); + } + + // Precache sprites. + memset(hitlist, 0, numsprites); + + { + thinker_t *th = NULL; + while ((th = P_NextThinker(th,th_all)) != NULL) + if (th->function == P_MobjThinker) + hitlist[((mobj_t *)th)->sprite] = 1; + } + + for (i=numsprites; --i >= 0;) + if (hitlist[i]) + { + int j = sprites[i].numframes; + while (--j >= 0) + { + short *sflump = sprites[i].spriteframes[j].lump; + int k = 7; + do + precache_lump(firstspritelump + sflump[k]); + while (--k >= 0); + } + } + free(hitlist); +} + +// Proff - Added for OpenGL +void R_SetPatchNum(patchnum_t *patchnum, const char *name) +{ + const rpatch_t *patch = R_CachePatchName(name); + patchnum->width = patch->width; + patchnum->height = patch->height; + patchnum->leftoffset = patch->leftoffset; + patchnum->topoffset = patch->topoffset; + patchnum->lumpnum = W_GetNumForName(name); + R_UnlockPatchName(name); +} diff --git a/common/prboom/r_data.h b/common/prboom/r_data.h new file mode 100755 index 0000000..16aac96 --- /dev/null +++ b/common/prboom/r_data.h @@ -0,0 +1,106 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Refresh module, data I/O, caching, retrieval of graphics + * by name. + * + *-----------------------------------------------------------------------------*/ + + +#ifndef __R_DATA__ +#define __R_DATA__ + +#include "r_defs.h" +#include "r_state.h" +#include "r_patch.h" + + +// A single patch from a texture definition, basically +// a rectangular area within the texture rectangle. +typedef struct +{ + int originx, originy; // Block origin, which has already accounted + int patch; // for the internal origin of the patch. +} texpatch_t; + +// +// Texture definition. +// A DOOM wall texture is a list of patches +// which are to be combined in a predefined order. +// + +typedef struct +{ + char name[8]; // Keep name for switch changing, etc. + int next, index; // killough 1/31/98: used in hashing algorithm + // CPhipps - moved arrays with per-texture entries to elements here + unsigned widthmask; + // CPhipps - end of additions + short width, height; + short patchcount; // All the patches[patchcount] are drawn + texpatch_t patches[1]; // back-to-front into the cached texture. +} texture_t; + +extern int numtextures; +extern texture_t **textures; + + +const byte *R_GetTextureColumn(const rpatch_t *texpatch, int col); + + +// I/O, setting up the stuff. +void R_InitData (void); +void R_PrecacheLevel (void); + + +// Retrieval. +// Floor/ceiling opaque texture tiles, +// lookup by name. For animation? +int R_FlatNumForName (const char* name); // killough -- const added + + +// R_*TextureNumForName returns the texture number for the texture name, or NO_TEXTURE if +// there is no texture (i.e. "-") specified. +/* cph 2006/07/23 - defined value for no-texture marker (texture "-" in the WAD file) */ +#define NO_TEXTURE 0 +int PUREFUNC R_TextureNumForName (const char *name); // killough -- const added; cph - now PUREFUNC +int PUREFUNC R_SafeTextureNumForName (const char *name, int snum); +int PUREFUNC R_CheckTextureNumForName (const char *name); + +void R_InitTranMap(int); // killough 3/6/98: translucency initialization +int R_ColormapNumForName(const char *name); // killough 4/4/98 +/* cph 2001/11/17 - new func to do lighting calcs and get suitable colour map */ +const lighttable_t* R_ColourMap(int lightlevel, fixed_t spryscale); + +extern const byte *main_tranmap, *tranmap; + +/* Proff - Added for OpenGL - cph - const char* param */ +void R_SetPatchNum(patchnum_t *patchnum, const char *name); + +#endif diff --git a/common/prboom/r_defs.h b/common/prboom/r_defs.h new file mode 100755 index 0000000..173d629 --- /dev/null +++ b/common/prboom/r_defs.h @@ -0,0 +1,438 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Refresh/rendering module, shared data struct definitions. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __R_DEFS__ +#define __R_DEFS__ + +// Screenwidth. +#include "doomdef.h" + +// Some more or less basic data types +// we depend on. +#include "m_fixed.h" + +// We rely on the thinker data struct +// to handle sound origins in sectors. +#include "d_think.h" + +// SECTORS do store MObjs anyway. +#include "p_mobj.h" + + +// Silhouette, needed for clipping Segs (mainly) +// and sprites representing things. +#define SIL_NONE 0 +#define SIL_BOTTOM 1 +#define SIL_TOP 2 +#define SIL_BOTH 3 + +#define MAXDRAWSEGS 256 + +// +// INTERNAL MAP TYPES +// used by play and refresh +// + +// +// Your plain vanilla vertex. +// Note: transformed values not buffered locally, +// like some DOOM-alikes ("wt", "WebView") do. +// +typedef struct +{ + fixed_t x, y; +} vertex_t; + +// Each sector has a degenmobj_t in its center for sound origin purposes. +typedef struct +{ + thinker_t thinker; // not used for anything + fixed_t x, y, z; +} degenmobj_t; + +// +// The SECTORS record, at runtime. +// Stores things/mobjs. +// + +typedef struct +{ + int iSectorID; // proff 04/05/2000: needed for OpenGL and used in debugmode by the HUD to draw sectornum + boolean no_toptextures; + boolean no_bottomtextures; + fixed_t floorheight; + fixed_t ceilingheight; + int nexttag,firsttag; // killough 1/30/98: improves searches for tags. + int soundtraversed; // 0 = untraversed, 1,2 = sndlines-1 + mobj_t *soundtarget; // thing that made a sound (or null) + int blockbox[4]; // mapblock bounding box for height changes + degenmobj_t soundorg; // origin for any sounds played by the sector + int validcount; // if == validcount, already checked + mobj_t *thinglist; // list of mobjs in sector + + /* killough 8/28/98: friction is a sector property, not an mobj property. + * these fields used to be in mobj_t, but presented performance problems + * when processed as mobj properties. Fix is to make them sector properties. + */ + int friction,movefactor; + + // thinker_t for reversable actions + void *floordata; // jff 2/22/98 make thinkers on + void *ceilingdata; // floors, ceilings, lighting, + void *lightingdata; // independent of one another + + // jff 2/26/98 lockout machinery for stairbuilding + int stairlock; // -2 on first locked -1 after thinker done 0 normally + int prevsec; // -1 or number of sector for previous step + int nextsec; // -1 or number of next step sector + + // killough 3/7/98: support flat heights drawn at another sector's heights + int heightsec; // other sector, or -1 if no other sector + + int bottommap, midmap, topmap; // killough 4/4/98: dynamic colormaps + + // list of mobjs that are at least partially in the sector + // thinglist is a subset of touching_thinglist + struct msecnode_s *touching_thinglist; // phares 3/14/98 + + int linecount; + struct line_s **lines; + + // killough 10/98: support skies coming from sidedefs. Allows scrolling + // skies and other effects. No "level info" kind of lump is needed, + // because you can use an arbitrary number of skies per level with this + // method. This field only applies when skyflatnum is used for floorpic + // or ceilingpic, because the rest of Doom needs to know which is sky + // and which isn't, etc. + + int sky; + + // killough 3/7/98: floor and ceiling texture offsets + fixed_t floor_xoffs, floor_yoffs; + fixed_t ceiling_xoffs, ceiling_yoffs; + + // killough 4/11/98: support for lightlevels coming from another sector + int floorlightsec, ceilinglightsec; + + short floorpic; + short ceilingpic; + short lightlevel; + short special; + short oldspecial; //jff 2/16/98 remembers if sector WAS secret (automap) + short tag; +#ifdef IPHONE // JDC: high performance renderer + // floors and ceiling have identical index count, but reference different verts + int numIndexes; + int numVerts; + unsigned short *indexes[2]; // floor = 0, ceiling = 1 + struct drawVert_s *verts[2]; +#endif +} sector_t; + +// +// The LineSeg. (JDC: moved above sidedef_t) +// +typedef struct side_s side_t; // JDC: forward definiteion +typedef struct line_s line_t; // JDC: forward definiteion +typedef struct +{ + vertex_t *v1, *v2; + fixed_t offset; + angle_t angle; + side_t* sidedef; + line_t* linedef; + + int iSegID; // proff 11/05/2000: needed for OpenGL + // figgi -- needed for glnodes + float length; + boolean miniseg; + + + // Sector references. + // Could be retrieved from linedef, too + // (but that would be slower -- killough) + // backsector is NULL for one sided lines + + sector_t *frontsector, *backsector; +} seg_t; + + +// +// The SideDef. +// + +struct side_s // JDC: moved typedef for forward reference +{ + fixed_t textureoffset; // add this to the calculated texture column + fixed_t rowoffset; // add this to the calculated texture top + short toptexture; // Texture indices. We do not maintain names here. + short bottomtexture; + short midtexture; + sector_t* sector; // Sector the SideDef is facing. + + // killough 4/4/98, 4/11/98: highest referencing special linedef's type, + // or lump number of special effect. Allows texture names to be overloaded + // for other functions. + + int special; +#ifdef IPHONE + seg_t sideSeg; // This segment stretches the entire length of the line, + // even if the line was broken into multiple seg_t by + // the bsp. +#endif +}; + +// +// Move clipping aid for LineDefs. +// +typedef enum +{ + ST_HORIZONTAL, + ST_VERTICAL, + ST_POSITIVE, + ST_NEGATIVE +} slopetype_t; + +struct line_s // JDC: moved typedef for forward reference +{ + int iLineID; // proff 04/05/2000: needed for OpenGL + vertex_t *v1, *v2; // Vertices, from v1 to v2. + fixed_t dx, dy; // Precalculated v2 - v1 for side checking. + unsigned short flags; // Animation related. + short special; + short tag; + unsigned short sidenum[2]; // Visual appearance: SideDefs. + fixed_t bbox[4]; // A bounding box, for the linedef's extent + slopetype_t slopetype; // To aid move clipping. + sector_t *frontsector; // Front and back sector. + sector_t *backsector; + int validcount; // if == validcount, already checked + void *specialdata; // thinker_t for reversable actions + int tranlump; // killough 4/11/98: translucency filter, -1 == none + int firsttag,nexttag; // killough 4/17/98: improves searches for tags. + int r_validcount; // cph: if == gametic, r_flags already done + enum { // cph: + RF_TOP_TILE = 1, // Upper texture needs tiling + RF_MID_TILE = 2, // Mid texture needs tiling + RF_BOT_TILE = 4, // Lower texture needs tiling + RF_IGNORE = 8, // Renderer can skip this line + RF_CLOSED =16, // Line blocks view + } r_flags; + degenmobj_t soundorg; // sound origin for switches/buttons +}; + + +// phares 3/14/98 +// +// Sector list node showing all sectors an object appears in. +// +// There are two threads that flow through these nodes. The first thread +// starts at touching_thinglist in a sector_t and flows through the m_snext +// links to find all mobjs that are entirely or partially in the sector. +// The second thread starts at touching_sectorlist in an mobj_t and flows +// through the m_tnext links to find all sectors a thing touches. This is +// useful when applying friction or push effects to sectors. These effects +// can be done as thinkers that act upon all objects touching their sectors. +// As an mobj moves through the world, these nodes are created and +// destroyed, with the links changed appropriately. +// +// For the links, NULL means top or end of list. + +typedef struct msecnode_s +{ + sector_t *m_sector; // a sector containing this object + struct mobj_s *m_thing; // this object + struct msecnode_s *m_tprev; // prev msecnode_t for this thing + struct msecnode_s *m_tnext; // next msecnode_t for this thing + struct msecnode_s *m_sprev; // prev msecnode_t for this sector + struct msecnode_s *m_snext; // next msecnode_t for this sector + boolean visited; // killough 4/4/98, 4/7/98: used in search algorithms +} msecnode_t; + +// +// A SubSector. +// References a Sector. +// Basically, this is a list of LineSegs, +// indicating the visible walls that define +// (all or some) sides of a convex BSP leaf. +// + +typedef struct subsector_s +{ + sector_t *sector; + unsigned short numlines, firstline; +} subsector_t; + + +// +// BSP node. +// +typedef struct +{ + fixed_t x, y, dx, dy; // Partition line. + fixed_t bbox[2][4]; // Bounding box for each child. + unsigned short children[2]; // If NF_SUBSECTOR its a subsector. +} node_t; + +// +// OTHER TYPES +// + +// This could be wider for >8 bit display. +// Indeed, true color support is posibble +// precalculating 24bpp lightmap/colormap LUT. +// from darkening PLAYPAL to all black. +// Could use even more than 32 levels. + +typedef byte lighttable_t; + +// +// Masked 2s linedefs +// + +typedef struct drawseg_s +{ + seg_t *curline; + int x1, x2; + fixed_t scale1, scale2, scalestep; + int silhouette; // 0=none, 1=bottom, 2=top, 3=both + fixed_t bsilheight; // do not clip sprites above this + fixed_t tsilheight; // do not clip sprites below this + + // Added for filtering (fractional texture u coord) support - POPE + fixed_t rw_offset, rw_distance, rw_centerangle; + + // Pointers to lists for sprite clipping, + // all three adjusted so [x1] is first value. + + int *sprtopclip, *sprbottomclip, *maskedtexturecol; // dropoff overflow +} drawseg_t; + +// proff: Added for OpenGL +typedef struct +{ + int width,height; + int leftoffset,topoffset; + int lumpnum; +} patchnum_t; + +// +// A vissprite_t is a thing that will be drawn during a refresh. +// i.e. a sprite object that is partly visible. +// + +typedef struct vissprite_s +{ + mobj_t *thing; + boolean flip; + int x1, x2; + fixed_t gx, gy; // for line side calculation + fixed_t gz, gzt; // global bottom / top for silhouette clipping + fixed_t startfrac; // horizontal position of x1 + fixed_t scale; + fixed_t xiscale; // negative if flipped + fixed_t texturemid; + int patch; + uint_64_t mobjflags; + + // for color translation and shadow draw, maxbright frames as well + const lighttable_t *colormap; + + // killough 3/27/98: height sector for underwater/fake ceiling support + int heightsec; + + boolean isplayersprite; +} vissprite_t; + +// +// Sprites are patches with a special naming convention +// so they can be recognized by R_InitSprites. +// The base name is NNNNFx or NNNNFxFx, with +// x indicating the rotation, x = 0, 1-7. +// The sprite and frame specified by a thing_t +// is range checked at run time. +// A sprite is a patch_t that is assumed to represent +// a three dimensional object and may have multiple +// rotations pre drawn. +// Horizontal flipping is used to save space, +// thus NNNNF2F5 defines a mirrored patch. +// Some sprites will only have one picture used +// for all views: NNNNF0 +// + +typedef struct +{ + // If false use 0 for any position. + // Note: as eight entries are available, + // we might as well insert the same name eight times. + boolean rotate; + + // Lump to use for view angles 0-7. + short lump[8]; + + // Flip bit (1 = flip) to use for view angles 0-7. + byte flip[8]; + +} spriteframe_t; + +// +// A sprite definition: +// a number of animation frames. +// + +typedef struct +{ + int numframes; + spriteframe_t *spriteframes; +} spritedef_t; + +// +// Now what is a visplane, anyway? +// +// Go to http://classicgaming.com/doom/editing/ to find out -- killough +// + +typedef struct visplane +{ + struct visplane *next; // Next visplane in hash chain -- killough + int picnum, lightlevel, minx, maxx; + fixed_t height; + fixed_t xoffs, yoffs; // killough 2/28/98: Support scrolling flats + unsigned int pad1; // leave pads for [minx-1]/[maxx+1] + unsigned int top[MAX_SCREENWIDTH]; + unsigned int pad2, pad3; // killough 2/8/98, 4/25/98 + unsigned int bottom[MAX_SCREENWIDTH]; + unsigned int pad4; // dropoff overflow +} visplane_t; + +#endif diff --git a/common/prboom/r_demo.c b/common/prboom/r_demo.c new file mode 100755 index 0000000..0f9e6f1 --- /dev/null +++ b/common/prboom/r_demo.c @@ -0,0 +1,88 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze, Andrey Budko + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Demo stuff + * + *--------------------------------------------------------------------- + */ + +#include "doomstat.h" +#include "r_demo.h" +#include "r_fps.h" + +int demo_smoothturns = false; +int demo_smoothturnsfactor = 6; + +static int smooth_playing_turns[SMOOTH_PLAYING_MAXFACTOR]; +static int_64_t smooth_playing_sum; +static int smooth_playing_index; +static angle_t smooth_playing_angle; + +void R_SmoothPlaying_Reset(player_t *player) +{ + if (demo_smoothturns && demoplayback && players) + { + if (!player) + player = &players[displayplayer]; + + if (player==&players[displayplayer]) + { + smooth_playing_angle = players[displayplayer].mo->angle; + memset(smooth_playing_turns, 0, sizeof(smooth_playing_turns[0]) * SMOOTH_PLAYING_MAXFACTOR); + smooth_playing_sum = 0; + smooth_playing_index = 0; + } + } +} + +void R_SmoothPlaying_Add(int delta) +{ + if (demo_smoothturns && demoplayback) + { + smooth_playing_sum -= smooth_playing_turns[smooth_playing_index]; + smooth_playing_turns[smooth_playing_index] = delta; + smooth_playing_index = (smooth_playing_index + 1)%(demo_smoothturnsfactor); + smooth_playing_sum += delta; + smooth_playing_angle += (int)(smooth_playing_sum/(demo_smoothturnsfactor)); + } +} + +angle_t R_SmoothPlaying_Get(angle_t defangle) +{ + if (demo_smoothturns && demoplayback) + return smooth_playing_angle; + else + return defangle; +} + +void R_ResetAfterTeleport(player_t *player) +{ + R_ResetViewInterpolation(); + R_SmoothPlaying_Reset(player); +} diff --git a/common/prboom/r_demo.h b/common/prboom/r_demo.h new file mode 100755 index 0000000..e5be4cb --- /dev/null +++ b/common/prboom/r_demo.h @@ -0,0 +1,45 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze, Andrey Budko + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Demo stuff + * + *--------------------------------------------------------------------- + */ + +#include "doomstat.h" + +#define SMOOTH_PLAYING_MAXFACTOR 16 + +extern int demo_smoothturns; +extern int demo_smoothturnsfactor; + +void R_SmoothPlaying_Reset(player_t *player); +void R_SmoothPlaying_Add(int delta); +angle_t R_SmoothPlaying_Get(angle_t defangle); +void R_ResetAfterTeleport(player_t *player); diff --git a/common/prboom/r_draw.c b/common/prboom/r_draw.c new file mode 100755 index 0000000..106ad60 --- /dev/null +++ b/common/prboom/r_draw.c @@ -0,0 +1,1130 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * The actual span/column drawing functions. + * Here find the main potential for optimization, + * e.g. inline assembly, different algorithms. + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" +#include "w_wad.h" +#include "r_main.h" +#include "r_draw.h" +#include "r_filter.h" +#include "v_video.h" +#include "st_stuff.h" +#include "g_game.h" +#include "am_map.h" +#include "lprintf.h" + +// +// All drawing to the view buffer is accomplished in this file. +// The other refresh files only know about ccordinates, +// not the architecture of the frame buffer. +// Conveniently, the frame buffer is a linear one, +// and we need only the base address, +// and the total size == width*height*depth/8., +// + +byte *viewimage; +int displaywidth; +int displayheight; +int viewwidth; +int scaledviewwidth; +int viewheight; +int viewwindowx; +int viewwindowy; + +// Color tables for different players, +// translate a limited part to another +// (color ramps used for suit colors). +// + +// CPhipps - made const*'s +const byte *tranmap; // translucency filter maps 256x256 // phares +const byte *main_tranmap; // killough 4/11/98 + +// +// R_DrawColumn +// Source is the top of the column to scale. +// + +// SoM: OPTIMIZE for ANYRES +typedef enum +{ + COL_NONE, + COL_OPAQUE, + COL_TRANS, + COL_FLEXTRANS, + COL_FUZZ, + COL_FLEXADD +} columntype_e; + +static int temp_x = 0; +static int tempyl[4], tempyh[4]; +static byte byte_tempbuf[MAX_SCREENHEIGHT * 4]; +static unsigned short short_tempbuf[MAX_SCREENHEIGHT * 4]; +static unsigned int int_tempbuf[MAX_SCREENHEIGHT * 4]; +static int startx = 0; +static int temptype = COL_NONE; +static int commontop, commonbot; +static const byte *temptranmap = NULL; +// SoM 7-28-04: Fix the fuzz problem. +static const byte *tempfuzzmap; + +// +// Spectre/Invisibility. +// + +#define FUZZTABLE 50 +// proff 08/17/98: Changed for high-res +//#define FUZZOFF (SCREENWIDTH) +#define FUZZOFF 1 + +static const int fuzzoffset_org[FUZZTABLE] = { + FUZZOFF,-FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF, + FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF, + FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,-FUZZOFF,-FUZZOFF,-FUZZOFF, + FUZZOFF,-FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF, + FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,-FUZZOFF,FUZZOFF, + FUZZOFF,-FUZZOFF,-FUZZOFF,-FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF, + FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF +}; + +static int fuzzoffset[FUZZTABLE]; + +static int fuzzpos = 0; + +// render pipelines +#define RDC_STANDARD 1 +#define RDC_TRANSLUCENT 2 +#define RDC_TRANSLATED 4 +#define RDC_FUZZ 8 +// no color mapping +#define RDC_NOCOLMAP 16 +// filter modes +#define RDC_DITHERZ 32 +#define RDC_BILINEAR 64 +#define RDC_ROUNDED 128 + +draw_vars_t drawvars = { + NULL, // byte_topleft + NULL, // short_topleft + NULL, // int_topleft + 0, // byte_pitch + 0, // short_pitch + 0, // int_pitch + RDRAW_FILTER_POINT, // filterwall + RDRAW_FILTER_POINT, // filterfloor + RDRAW_FILTER_POINT, // filtersprite + RDRAW_FILTER_POINT, // filterz + RDRAW_FILTER_POINT, // filterpatch + + RDRAW_MASKEDCOLUMNEDGE_SQUARE, // sprite_edges + RDRAW_MASKEDCOLUMNEDGE_SQUARE, // patch_edges + + // 49152 = FRACUNIT * 0.75 + // 81920 = FRACUNIT * 1.25 + 49152 // mag_threshold +}; + +// +// Error functions that will abort if R_FlushColumns tries to flush +// columns without a column type. +// + +static void R_FlushWholeError(void) +{ + I_Error("R_FlushWholeColumns called without being initialized.\n"); +} + +static void R_FlushHTError(void) +{ + I_Error("R_FlushHTColumns called without being initialized.\n"); +} + +static void R_QuadFlushError(void) +{ + I_Error("R_FlushQuadColumn called without being initialized.\n"); +} + +static void (*R_FlushWholeColumns)(void) = R_FlushWholeError; +static void (*R_FlushHTColumns)(void) = R_FlushHTError; +static void (*R_FlushQuadColumn)(void) = R_QuadFlushError; + +static void R_FlushColumns(void) +{ + if(temp_x != 4 || commontop >= commonbot) + R_FlushWholeColumns(); + else + { + R_FlushHTColumns(); + R_FlushQuadColumn(); + } + temp_x = 0; +} + +// +// R_ResetColumnBuffer +// +// haleyjd 09/13/04: new function to call from main rendering loop +// which gets rid of the unnecessary reset of various variables during +// column drawing. +// +void R_ResetColumnBuffer(void) +{ + // haleyjd 10/06/05: this must not be done if temp_x == 0! + if(temp_x) + R_FlushColumns(); + temptype = COL_NONE; + R_FlushWholeColumns = R_FlushWholeError; + R_FlushHTColumns = R_FlushHTError; + R_FlushQuadColumn = R_QuadFlushError; +} + +#define R_DRAWCOLUMN_PIPELINE RDC_STANDARD +#define R_DRAWCOLUMN_PIPELINE_BITS 8 +#define R_FLUSHWHOLE_FUNCNAME R_FlushWhole8 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHT8 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuad8 +#include "r_drawflush.inl" + +#define R_DRAWCOLUMN_PIPELINE RDC_TRANSLUCENT +#define R_DRAWCOLUMN_PIPELINE_BITS 8 +#define R_FLUSHWHOLE_FUNCNAME R_FlushWholeTL8 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHTTL8 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuadTL8 +#include "r_drawflush.inl" + +#define R_DRAWCOLUMN_PIPELINE RDC_FUZZ +#define R_DRAWCOLUMN_PIPELINE_BITS 8 +#define R_FLUSHWHOLE_FUNCNAME R_FlushWholeFuzz8 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHTFuzz8 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuadFuzz8 +#include "r_drawflush.inl" + +#define R_DRAWCOLUMN_PIPELINE RDC_STANDARD +#define R_DRAWCOLUMN_PIPELINE_BITS 15 +#define R_FLUSHWHOLE_FUNCNAME R_FlushWhole15 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHT15 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuad15 +#include "r_drawflush.inl" + +#define R_DRAWCOLUMN_PIPELINE RDC_TRANSLUCENT +#define R_DRAWCOLUMN_PIPELINE_BITS 15 +#define R_FLUSHWHOLE_FUNCNAME R_FlushWholeTL15 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHTTL15 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuadTL15 +#include "r_drawflush.inl" + +#define R_DRAWCOLUMN_PIPELINE RDC_FUZZ +#define R_DRAWCOLUMN_PIPELINE_BITS 15 +#define R_FLUSHWHOLE_FUNCNAME R_FlushWholeFuzz15 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHTFuzz15 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuadFuzz15 +#include "r_drawflush.inl" + +#define R_DRAWCOLUMN_PIPELINE RDC_STANDARD +#define R_DRAWCOLUMN_PIPELINE_BITS 16 +#define R_FLUSHWHOLE_FUNCNAME R_FlushWhole16 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHT16 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuad16 +#include "r_drawflush.inl" + +#define R_DRAWCOLUMN_PIPELINE RDC_TRANSLUCENT +#define R_DRAWCOLUMN_PIPELINE_BITS 16 +#define R_FLUSHWHOLE_FUNCNAME R_FlushWholeTL16 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHTTL16 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuadTL16 +#include "r_drawflush.inl" + +#define R_DRAWCOLUMN_PIPELINE RDC_FUZZ +#define R_DRAWCOLUMN_PIPELINE_BITS 16 +#define R_FLUSHWHOLE_FUNCNAME R_FlushWholeFuzz16 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHTFuzz16 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuadFuzz16 +#include "r_drawflush.inl" + +#define R_DRAWCOLUMN_PIPELINE RDC_STANDARD +#define R_DRAWCOLUMN_PIPELINE_BITS 32 +#define R_FLUSHWHOLE_FUNCNAME R_FlushWhole32 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHT32 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuad32 +#include "r_drawflush.inl" + +#define R_DRAWCOLUMN_PIPELINE RDC_TRANSLUCENT +#define R_DRAWCOLUMN_PIPELINE_BITS 32 +#define R_FLUSHWHOLE_FUNCNAME R_FlushWholeTL32 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHTTL32 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuadTL32 +#include "r_drawflush.inl" + +#define R_DRAWCOLUMN_PIPELINE RDC_FUZZ +#define R_DRAWCOLUMN_PIPELINE_BITS 32 +#define R_FLUSHWHOLE_FUNCNAME R_FlushWholeFuzz32 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHTFuzz32 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuadFuzz32 +#include "r_drawflush.inl" + +// +// R_DrawColumn +// + +// +// A column is a vertical slice/span from a wall texture that, +// given the DOOM style restrictions on the view orientation, +// will always have constant z depth. +// Thus a special case loop for very fast rendering can +// be used. It has also been used with Wolfenstein 3D. +// + +byte *translationtables; + +#define R_DRAWCOLUMN_PIPELINE_TYPE RDC_PIPELINE_STANDARD +#define R_DRAWCOLUMN_PIPELINE_BASE RDC_STANDARD + +#define R_DRAWCOLUMN_PIPELINE_BITS 8 +#define R_DRAWCOLUMN_FUNCNAME_COMPOSITE(postfix) R_DrawColumn8 ## postfix +#define R_FLUSHWHOLE_FUNCNAME R_FlushWhole8 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHT8 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuad8 +#include "r_drawcolpipeline.inl" + +#define R_DRAWCOLUMN_PIPELINE_BITS 15 +#define R_DRAWCOLUMN_FUNCNAME_COMPOSITE(postfix) R_DrawColumn15 ## postfix +#define R_FLUSHWHOLE_FUNCNAME R_FlushWhole15 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHT15 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuad15 +#include "r_drawcolpipeline.inl" + +#define R_DRAWCOLUMN_PIPELINE_BITS 16 +#define R_DRAWCOLUMN_FUNCNAME_COMPOSITE(postfix) R_DrawColumn16 ## postfix +#define R_FLUSHWHOLE_FUNCNAME R_FlushWhole16 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHT16 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuad16 +#include "r_drawcolpipeline.inl" + +#define R_DRAWCOLUMN_PIPELINE_BITS 32 +#define R_DRAWCOLUMN_FUNCNAME_COMPOSITE(postfix) R_DrawColumn32 ## postfix +#define R_FLUSHWHOLE_FUNCNAME R_FlushWhole32 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHT32 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuad32 +#include "r_drawcolpipeline.inl" + +#undef R_DRAWCOLUMN_PIPELINE_BASE +#undef R_DRAWCOLUMN_PIPELINE_TYPE + +// Here is the version of R_DrawColumn that deals with translucent // phares +// textures and sprites. It's identical to R_DrawColumn except // | +// for the spot where the color index is stuffed into *dest. At // V +// that point, the existing color index and the new color index +// are mapped through the TRANMAP lump filters to get a new color +// index whose RGB values are the average of the existing and new +// colors. +// +// Since we're concerned about performance, the 'translucent or +// opaque' decision is made outside this routine, not down where the +// actual code differences are. + +#define R_DRAWCOLUMN_PIPELINE_TYPE RDC_PIPELINE_TRANSLUCENT +#define R_DRAWCOLUMN_PIPELINE_BASE RDC_TRANSLUCENT + +#define R_DRAWCOLUMN_PIPELINE_BITS 8 +#define R_DRAWCOLUMN_FUNCNAME_COMPOSITE(postfix) R_DrawTLColumn8 ## postfix +#define R_FLUSHWHOLE_FUNCNAME R_FlushWholeTL8 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHTTL8 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuadTL8 +#include "r_drawcolpipeline.inl" + +#define R_DRAWCOLUMN_PIPELINE_BITS 15 +#define R_DRAWCOLUMN_FUNCNAME_COMPOSITE(postfix) R_DrawTLColumn15 ## postfix +#define R_FLUSHWHOLE_FUNCNAME R_FlushWholeTL15 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHTTL15 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuadTL15 +#include "r_drawcolpipeline.inl" + +#define R_DRAWCOLUMN_PIPELINE_BITS 16 +#define R_DRAWCOLUMN_FUNCNAME_COMPOSITE(postfix) R_DrawTLColumn16 ## postfix +#define R_FLUSHWHOLE_FUNCNAME R_FlushWholeTL16 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHTTL16 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuadTL16 +#include "r_drawcolpipeline.inl" + +#define R_DRAWCOLUMN_PIPELINE_BITS 32 +#define R_DRAWCOLUMN_FUNCNAME_COMPOSITE(postfix) R_DrawTLColumn32 ## postfix +#define R_FLUSHWHOLE_FUNCNAME R_FlushWholeTL32 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHTTL32 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuadTL32 +#include "r_drawcolpipeline.inl" + +#undef R_DRAWCOLUMN_PIPELINE_BASE +#undef R_DRAWCOLUMN_PIPELINE_TYPE + +// +// R_DrawTranslatedColumn +// Used to draw player sprites +// with the green colorramp mapped to others. +// Could be used with different translation +// tables, e.g. the lighter colored version +// of the BaronOfHell, the HellKnight, uses +// identical sprites, kinda brightened up. +// + +#define R_DRAWCOLUMN_PIPELINE_TYPE RDC_PIPELINE_TRANSLATED +#define R_DRAWCOLUMN_PIPELINE_BASE RDC_TRANSLATED + +#define R_DRAWCOLUMN_PIPELINE_BITS 8 +#define R_DRAWCOLUMN_FUNCNAME_COMPOSITE(postfix) R_DrawTranslatedColumn8 ## postfix +#define R_FLUSHWHOLE_FUNCNAME R_FlushWhole8 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHT8 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuad8 +#include "r_drawcolpipeline.inl" + +#define R_DRAWCOLUMN_PIPELINE_BITS 15 +#define R_DRAWCOLUMN_FUNCNAME_COMPOSITE(postfix) R_DrawTranslatedColumn15 ## postfix +#define R_FLUSHWHOLE_FUNCNAME R_FlushWhole15 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHT15 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuad15 +#include "r_drawcolpipeline.inl" + +#define R_DRAWCOLUMN_PIPELINE_BITS 16 +#define R_DRAWCOLUMN_FUNCNAME_COMPOSITE(postfix) R_DrawTranslatedColumn16 ## postfix +#define R_FLUSHWHOLE_FUNCNAME R_FlushWhole16 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHT16 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuad16 +#include "r_drawcolpipeline.inl" + +#define R_DRAWCOLUMN_PIPELINE_BITS 32 +#define R_DRAWCOLUMN_FUNCNAME_COMPOSITE(postfix) R_DrawTranslatedColumn32 ## postfix +#define R_FLUSHWHOLE_FUNCNAME R_FlushWhole32 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHT32 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuad32 +#include "r_drawcolpipeline.inl" + +#undef R_DRAWCOLUMN_PIPELINE_BASE +#undef R_DRAWCOLUMN_PIPELINE_TYPE + +// +// Framebuffer postprocessing. +// Creates a fuzzy image by copying pixels +// from adjacent ones to left and right. +// Used with an all black colormap, this +// could create the SHADOW effect, +// i.e. spectres and invisible players. +// + +#define R_DRAWCOLUMN_PIPELINE_TYPE RDC_PIPELINE_FUZZ +#define R_DRAWCOLUMN_PIPELINE_BASE RDC_FUZZ + +#define R_DRAWCOLUMN_PIPELINE_BITS 8 +#define R_DRAWCOLUMN_FUNCNAME_COMPOSITE(postfix) R_DrawFuzzColumn8 ## postfix +#define R_FLUSHWHOLE_FUNCNAME R_FlushWholeFuzz8 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHTFuzz8 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuadFuzz8 +#include "r_drawcolpipeline.inl" + +#define R_DRAWCOLUMN_PIPELINE_BITS 15 +#define R_DRAWCOLUMN_FUNCNAME_COMPOSITE(postfix) R_DrawFuzzColumn15 ## postfix +#define R_FLUSHWHOLE_FUNCNAME R_FlushWholeFuzz15 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHTFuzz15 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuadFuzz15 +#include "r_drawcolpipeline.inl" + +#define R_DRAWCOLUMN_PIPELINE_BITS 16 +#define R_DRAWCOLUMN_FUNCNAME_COMPOSITE(postfix) R_DrawFuzzColumn16 ## postfix +#define R_FLUSHWHOLE_FUNCNAME R_FlushWholeFuzz16 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHTFuzz16 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuadFuzz16 +#include "r_drawcolpipeline.inl" + +#define R_DRAWCOLUMN_PIPELINE_BITS 32 +#define R_DRAWCOLUMN_FUNCNAME_COMPOSITE(postfix) R_DrawFuzzColumn32 ## postfix +#define R_FLUSHWHOLE_FUNCNAME R_FlushWholeFuzz32 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHTFuzz32 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuadFuzz32 +#include "r_drawcolpipeline.inl" + +#undef R_DRAWCOLUMN_PIPELINE_BASE +#undef R_DRAWCOLUMN_PIPELINE_TYPE + +static R_DrawColumn_f drawcolumnfuncs[VID_MODEMAX][RDRAW_FILTER_MAXFILTERS][RDRAW_FILTER_MAXFILTERS][RDC_PIPELINE_MAXPIPELINES] = { + { + { + {NULL, NULL, NULL, NULL,}, + {R_DrawColumn8_PointUV, + R_DrawTLColumn8_PointUV, + R_DrawTranslatedColumn8_PointUV, + R_DrawFuzzColumn8_PointUV,}, + {R_DrawColumn8_LinearUV, + R_DrawTLColumn8_LinearUV, + R_DrawTranslatedColumn8_LinearUV, + R_DrawFuzzColumn8_LinearUV,}, + {R_DrawColumn8_RoundedUV, + R_DrawTLColumn8_RoundedUV, + R_DrawTranslatedColumn8_RoundedUV, + R_DrawFuzzColumn8_RoundedUV,}, + }, + { + {NULL, NULL, NULL, NULL,}, + {R_DrawColumn8_PointUV_PointZ, + R_DrawTLColumn8_PointUV_PointZ, + R_DrawTranslatedColumn8_PointUV_PointZ, + R_DrawFuzzColumn8_PointUV_PointZ,}, + {R_DrawColumn8_LinearUV_PointZ, + R_DrawTLColumn8_LinearUV_PointZ, + R_DrawTranslatedColumn8_LinearUV_PointZ, + R_DrawFuzzColumn8_LinearUV_PointZ,}, + {R_DrawColumn8_RoundedUV_PointZ, + R_DrawTLColumn8_RoundedUV_PointZ, + R_DrawTranslatedColumn8_RoundedUV_PointZ, + R_DrawFuzzColumn8_RoundedUV_PointZ,}, + }, + { + {NULL, NULL, NULL, NULL,}, + {R_DrawColumn8_PointUV_LinearZ, + R_DrawTLColumn8_PointUV_LinearZ, + R_DrawTranslatedColumn8_PointUV_LinearZ, + R_DrawFuzzColumn8_PointUV_LinearZ,}, + {R_DrawColumn8_LinearUV_LinearZ, + R_DrawTLColumn8_LinearUV_LinearZ, + R_DrawTranslatedColumn8_LinearUV_LinearZ, + R_DrawFuzzColumn8_LinearUV_LinearZ,}, + {R_DrawColumn8_RoundedUV_LinearZ, + R_DrawTLColumn8_RoundedUV_LinearZ, + R_DrawTranslatedColumn8_RoundedUV_LinearZ, + R_DrawFuzzColumn8_RoundedUV_LinearZ,}, + }, + }, + { + { + {NULL, NULL, NULL, NULL,}, + {R_DrawColumn15_PointUV, + R_DrawTLColumn15_PointUV, + R_DrawTranslatedColumn15_PointUV, + R_DrawFuzzColumn15_PointUV,}, + {R_DrawColumn15_LinearUV, + R_DrawTLColumn15_LinearUV, + R_DrawTranslatedColumn15_LinearUV, + R_DrawFuzzColumn15_LinearUV,}, + {R_DrawColumn15_RoundedUV, + R_DrawTLColumn15_RoundedUV, + R_DrawTranslatedColumn15_RoundedUV, + R_DrawFuzzColumn15_RoundedUV,}, + }, + { + {NULL, NULL, NULL, NULL,}, + {R_DrawColumn15_PointUV_PointZ, + R_DrawTLColumn15_PointUV_PointZ, + R_DrawTranslatedColumn15_PointUV_PointZ, + R_DrawFuzzColumn15_PointUV_PointZ,}, + {R_DrawColumn15_LinearUV_PointZ, + R_DrawTLColumn15_LinearUV_PointZ, + R_DrawTranslatedColumn15_LinearUV_PointZ, + R_DrawFuzzColumn15_LinearUV_PointZ,}, + {R_DrawColumn15_RoundedUV_PointZ, + R_DrawTLColumn15_RoundedUV_PointZ, + R_DrawTranslatedColumn15_RoundedUV_PointZ, + R_DrawFuzzColumn15_RoundedUV_PointZ,}, + }, + { + {NULL, NULL, NULL, NULL,}, + {R_DrawColumn15_PointUV_LinearZ, + R_DrawTLColumn15_PointUV_LinearZ, + R_DrawTranslatedColumn15_PointUV_LinearZ, + R_DrawFuzzColumn15_PointUV_LinearZ,}, + {R_DrawColumn15_LinearUV_LinearZ, + R_DrawTLColumn15_LinearUV_LinearZ, + R_DrawTranslatedColumn15_LinearUV_LinearZ, + R_DrawFuzzColumn15_LinearUV_LinearZ,}, + {R_DrawColumn15_RoundedUV_LinearZ, + R_DrawTLColumn15_RoundedUV_LinearZ, + R_DrawTranslatedColumn15_RoundedUV_LinearZ, + R_DrawFuzzColumn15_RoundedUV_LinearZ,}, + }, + }, + { + { + {NULL, NULL, NULL, NULL,}, + {R_DrawColumn16_PointUV, + R_DrawTLColumn16_PointUV, + R_DrawTranslatedColumn16_PointUV, + R_DrawFuzzColumn16_PointUV,}, + {R_DrawColumn16_LinearUV, + R_DrawTLColumn16_LinearUV, + R_DrawTranslatedColumn16_LinearUV, + R_DrawFuzzColumn16_LinearUV,}, + {R_DrawColumn16_RoundedUV, + R_DrawTLColumn16_RoundedUV, + R_DrawTranslatedColumn16_RoundedUV, + R_DrawFuzzColumn16_RoundedUV,}, + }, + { + {NULL, NULL, NULL, NULL,}, + {R_DrawColumn16_PointUV_PointZ, + R_DrawTLColumn16_PointUV_PointZ, + R_DrawTranslatedColumn16_PointUV_PointZ, + R_DrawFuzzColumn16_PointUV_PointZ,}, + {R_DrawColumn16_LinearUV_PointZ, + R_DrawTLColumn16_LinearUV_PointZ, + R_DrawTranslatedColumn16_LinearUV_PointZ, + R_DrawFuzzColumn16_LinearUV_PointZ,}, + {R_DrawColumn16_RoundedUV_PointZ, + R_DrawTLColumn16_RoundedUV_PointZ, + R_DrawTranslatedColumn16_RoundedUV_PointZ, + R_DrawFuzzColumn16_RoundedUV_PointZ,}, + }, + { + {NULL, NULL, NULL, NULL,}, + {R_DrawColumn16_PointUV_LinearZ, + R_DrawTLColumn16_PointUV_LinearZ, + R_DrawTranslatedColumn16_PointUV_LinearZ, + R_DrawFuzzColumn16_PointUV_LinearZ,}, + {R_DrawColumn16_LinearUV_LinearZ, + R_DrawTLColumn16_LinearUV_LinearZ, + R_DrawTranslatedColumn16_LinearUV_LinearZ, + R_DrawFuzzColumn16_LinearUV_LinearZ,}, + {R_DrawColumn16_RoundedUV_LinearZ, + R_DrawTLColumn16_RoundedUV_LinearZ, + R_DrawTranslatedColumn16_RoundedUV_LinearZ, + R_DrawFuzzColumn16_RoundedUV_LinearZ,}, + }, + }, + { + { + {NULL, NULL, NULL, NULL,}, + {R_DrawColumn32_PointUV, + R_DrawTLColumn32_PointUV, + R_DrawTranslatedColumn32_PointUV, + R_DrawFuzzColumn32_PointUV,}, + {R_DrawColumn32_LinearUV, + R_DrawTLColumn32_LinearUV, + R_DrawTranslatedColumn32_LinearUV, + R_DrawFuzzColumn32_LinearUV,}, + {R_DrawColumn32_RoundedUV, + R_DrawTLColumn32_RoundedUV, + R_DrawTranslatedColumn32_RoundedUV, + R_DrawFuzzColumn32_RoundedUV,}, + }, + { + {NULL, NULL, NULL, NULL,}, + {R_DrawColumn32_PointUV_PointZ, + R_DrawTLColumn32_PointUV_PointZ, + R_DrawTranslatedColumn32_PointUV_PointZ, + R_DrawFuzzColumn32_PointUV_PointZ,}, + {R_DrawColumn32_LinearUV_PointZ, + R_DrawTLColumn32_LinearUV_PointZ, + R_DrawTranslatedColumn32_LinearUV_PointZ, + R_DrawFuzzColumn32_LinearUV_PointZ,}, + {R_DrawColumn32_RoundedUV_PointZ, + R_DrawTLColumn32_RoundedUV_PointZ, + R_DrawTranslatedColumn32_RoundedUV_PointZ, + R_DrawFuzzColumn32_RoundedUV_PointZ,}, + }, + { + {NULL, NULL, NULL, NULL,}, + {R_DrawColumn32_PointUV_LinearZ, + R_DrawTLColumn32_PointUV_LinearZ, + R_DrawTranslatedColumn32_PointUV_LinearZ, + R_DrawFuzzColumn32_PointUV_LinearZ,}, + {R_DrawColumn32_LinearUV_LinearZ, + R_DrawTLColumn32_LinearUV_LinearZ, + R_DrawTranslatedColumn32_LinearUV_LinearZ, + R_DrawFuzzColumn32_LinearUV_LinearZ,}, + {R_DrawColumn32_RoundedUV_LinearZ, + R_DrawTLColumn32_RoundedUV_LinearZ, + R_DrawTranslatedColumn32_RoundedUV_LinearZ, + R_DrawFuzzColumn32_RoundedUV_LinearZ,}, + }, + }, +}; + +R_DrawColumn_f R_GetDrawColumnFunc(enum column_pipeline_e type, + enum draw_filter_type_e filter, + enum draw_filter_type_e filterz) { + R_DrawColumn_f result = drawcolumnfuncs[V_GetMode()][filterz][filter][type]; + if (result == NULL) + I_Error("R_GetDrawColumnFunc: undefined function (%d, %d, %d)", + type, filter, filterz); + return result; +} + +void R_SetDefaultDrawColumnVars(draw_column_vars_t *dcvars) { + dcvars->x = dcvars->yl = dcvars->yh = dcvars->z = 0; + dcvars->iscale = dcvars->texturemid = dcvars->texheight = dcvars->texu = 0; + dcvars->source = dcvars->prevsource = dcvars->nextsource = NULL; + dcvars->colormap = dcvars->nextcolormap = colormaps[0]; + dcvars->translation = NULL; + dcvars->edgeslope = dcvars->drawingmasked = 0; + dcvars->edgetype = drawvars.sprite_edges; +} + +// +// R_InitTranslationTables +// Creates the translation tables to map +// the green color ramp to gray, brown, red. +// Assumes a given structure of the PLAYPAL. +// Could be read from a lump instead. +// + +byte playernumtotrans[MAXPLAYERS]; +extern lighttable_t *(*c_zlight)[LIGHTLEVELS][MAXLIGHTZ]; + +void R_InitTranslationTables (void) +{ + int i, j; +#define MAXTRANS 3 + byte transtocolour[MAXTRANS]; + + // killough 5/2/98: + // Remove dependency of colormaps aligned on 256-byte boundary + + if (translationtables == NULL) // CPhipps - allow multiple calls + translationtables = Z_Malloc(256*MAXTRANS, PU_STATIC, 0); + + for (i=0; i= 0x70 && i<= 0x7f) + { + // CPhipps - configurable player colours + translationtables[i] = colormaps[0][((i&0xf)<<9) + transtocolour[0]]; + translationtables[i+256] = colormaps[0][((i&0xf)<<9) + transtocolour[1]]; + translationtables[i+512] = colormaps[0][((i&0xf)<<9) + transtocolour[2]]; + } + else // Keep all other colors as is. + translationtables[i]=translationtables[i+256]=translationtables[i+512]=i; +} + +// +// R_DrawSpan +// With DOOM style restrictions on view orientation, +// the floors and ceilings consist of horizontal slices +// or spans with constant z depth. +// However, rotation around the world z axis is possible, +// thus this mapping, while simpler and faster than +// perspective correct texture mapping, has to traverse +// the texture at an angle in all but a few cases. +// In consequence, flats are not stored by column (like walls), +// and the inner loop has to step in texture space u and v. +// + +#define R_DRAWSPAN_FUNCNAME R_DrawSpan8_PointUV_PointZ +#define R_DRAWSPAN_PIPELINE_BITS 8 +#define R_DRAWSPAN_PIPELINE (RDC_STANDARD) +#include "r_drawspan.inl" + +#define R_DRAWSPAN_FUNCNAME R_DrawSpan8_PointUV_LinearZ +#define R_DRAWSPAN_PIPELINE_BITS 8 +#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_DITHERZ) +#include "r_drawspan.inl" + +#define R_DRAWSPAN_FUNCNAME R_DrawSpan8_LinearUV_PointZ +#define R_DRAWSPAN_PIPELINE_BITS 8 +#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_BILINEAR) +#include "r_drawspan.inl" + +#define R_DRAWSPAN_FUNCNAME R_DrawSpan8_LinearUV_LinearZ +#define R_DRAWSPAN_PIPELINE_BITS 8 +#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_BILINEAR | RDC_DITHERZ) +#include "r_drawspan.inl" + +#define R_DRAWSPAN_FUNCNAME R_DrawSpan8_RoundedUV_PointZ +#define R_DRAWSPAN_PIPELINE_BITS 8 +#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_ROUNDED) +#include "r_drawspan.inl" + +#define R_DRAWSPAN_FUNCNAME R_DrawSpan8_RoundedUV_LinearZ +#define R_DRAWSPAN_PIPELINE_BITS 8 +#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_ROUNDED | RDC_DITHERZ) +#include "r_drawspan.inl" + +#define R_DRAWSPAN_FUNCNAME R_DrawSpan15_PointUV_PointZ +#define R_DRAWSPAN_PIPELINE_BITS 15 +#define R_DRAWSPAN_PIPELINE (RDC_STANDARD) +#include "r_drawspan.inl" + +#define R_DRAWSPAN_FUNCNAME R_DrawSpan15_PointUV_LinearZ +#define R_DRAWSPAN_PIPELINE_BITS 15 +#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_DITHERZ) +#include "r_drawspan.inl" + +#define R_DRAWSPAN_FUNCNAME R_DrawSpan15_LinearUV_PointZ +#define R_DRAWSPAN_PIPELINE_BITS 15 +#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_BILINEAR) +#include "r_drawspan.inl" + +#define R_DRAWSPAN_FUNCNAME R_DrawSpan15_LinearUV_LinearZ +#define R_DRAWSPAN_PIPELINE_BITS 15 +#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_BILINEAR | RDC_DITHERZ) +#include "r_drawspan.inl" + +#define R_DRAWSPAN_FUNCNAME R_DrawSpan15_RoundedUV_PointZ +#define R_DRAWSPAN_PIPELINE_BITS 15 +#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_ROUNDED) +#include "r_drawspan.inl" + +#define R_DRAWSPAN_FUNCNAME R_DrawSpan15_RoundedUV_LinearZ +#define R_DRAWSPAN_PIPELINE_BITS 15 +#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_ROUNDED | RDC_DITHERZ) +#include "r_drawspan.inl" + +#define R_DRAWSPAN_FUNCNAME R_DrawSpan16_PointUV_PointZ +#define R_DRAWSPAN_PIPELINE_BITS 16 +#define R_DRAWSPAN_PIPELINE (RDC_STANDARD) +#include "r_drawspan.inl" + +#define R_DRAWSPAN_FUNCNAME R_DrawSpan16_PointUV_LinearZ +#define R_DRAWSPAN_PIPELINE_BITS 16 +#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_DITHERZ) +#include "r_drawspan.inl" + +#define R_DRAWSPAN_FUNCNAME R_DrawSpan16_LinearUV_PointZ +#define R_DRAWSPAN_PIPELINE_BITS 16 +#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_BILINEAR) +#include "r_drawspan.inl" + +#define R_DRAWSPAN_FUNCNAME R_DrawSpan16_LinearUV_LinearZ +#define R_DRAWSPAN_PIPELINE_BITS 16 +#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_BILINEAR | RDC_DITHERZ) +#include "r_drawspan.inl" + +#define R_DRAWSPAN_FUNCNAME R_DrawSpan16_RoundedUV_PointZ +#define R_DRAWSPAN_PIPELINE_BITS 16 +#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_ROUNDED) +#include "r_drawspan.inl" + +#define R_DRAWSPAN_FUNCNAME R_DrawSpan16_RoundedUV_LinearZ +#define R_DRAWSPAN_PIPELINE_BITS 16 +#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_ROUNDED | RDC_DITHERZ) +#include "r_drawspan.inl" + +#define R_DRAWSPAN_FUNCNAME R_DrawSpan32_PointUV_PointZ +#define R_DRAWSPAN_PIPELINE_BITS 32 +#define R_DRAWSPAN_PIPELINE (RDC_STANDARD) +#include "r_drawspan.inl" + +#define R_DRAWSPAN_FUNCNAME R_DrawSpan32_PointUV_LinearZ +#define R_DRAWSPAN_PIPELINE_BITS 32 +#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_DITHERZ) +#include "r_drawspan.inl" + +#define R_DRAWSPAN_FUNCNAME R_DrawSpan32_LinearUV_PointZ +#define R_DRAWSPAN_PIPELINE_BITS 32 +#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_BILINEAR) +#include "r_drawspan.inl" + +#define R_DRAWSPAN_FUNCNAME R_DrawSpan32_LinearUV_LinearZ +#define R_DRAWSPAN_PIPELINE_BITS 32 +#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_BILINEAR | RDC_DITHERZ) +#include "r_drawspan.inl" + +#define R_DRAWSPAN_FUNCNAME R_DrawSpan32_RoundedUV_PointZ +#define R_DRAWSPAN_PIPELINE_BITS 32 +#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_ROUNDED) +#include "r_drawspan.inl" + +#define R_DRAWSPAN_FUNCNAME R_DrawSpan32_RoundedUV_LinearZ +#define R_DRAWSPAN_PIPELINE_BITS 32 +#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_ROUNDED | RDC_DITHERZ) +#include "r_drawspan.inl" + +static R_DrawSpan_f drawspanfuncs[VID_MODEMAX][RDRAW_FILTER_MAXFILTERS][RDRAW_FILTER_MAXFILTERS] = { + { + { + NULL, + NULL, + NULL, + NULL, + }, + { + NULL, + R_DrawSpan8_PointUV_PointZ, + R_DrawSpan8_LinearUV_PointZ, + R_DrawSpan8_RoundedUV_PointZ, + }, + { + NULL, + R_DrawSpan8_PointUV_LinearZ, + R_DrawSpan8_LinearUV_LinearZ, + R_DrawSpan8_RoundedUV_LinearZ, + }, + { + NULL, + NULL, + NULL, + NULL, + }, + }, + { + { + NULL, + NULL, + NULL, + NULL, + }, + { + NULL, + R_DrawSpan15_PointUV_PointZ, + R_DrawSpan15_LinearUV_PointZ, + R_DrawSpan15_RoundedUV_PointZ, + }, + { + NULL, + R_DrawSpan15_PointUV_LinearZ, + R_DrawSpan15_LinearUV_LinearZ, + R_DrawSpan15_RoundedUV_LinearZ, + }, + { + NULL, + NULL, + NULL, + NULL, + }, + }, + { + { + NULL, + NULL, + NULL, + NULL, + }, + { + NULL, + R_DrawSpan16_PointUV_PointZ, + R_DrawSpan16_LinearUV_PointZ, + R_DrawSpan16_RoundedUV_PointZ, + }, + { + NULL, + R_DrawSpan16_PointUV_LinearZ, + R_DrawSpan16_LinearUV_LinearZ, + R_DrawSpan16_RoundedUV_LinearZ, + }, + { + NULL, + NULL, + NULL, + NULL, + }, + }, + { + { + NULL, + NULL, + NULL, + NULL, + }, + { + NULL, + R_DrawSpan32_PointUV_PointZ, + R_DrawSpan32_LinearUV_PointZ, + R_DrawSpan32_RoundedUV_PointZ, + }, + { + NULL, + R_DrawSpan32_PointUV_LinearZ, + R_DrawSpan32_LinearUV_LinearZ, + R_DrawSpan32_RoundedUV_LinearZ, + }, + { + NULL, + NULL, + NULL, + NULL, + }, + }, +}; + +R_DrawSpan_f R_GetDrawSpanFunc(enum draw_filter_type_e filter, + enum draw_filter_type_e filterz) { + R_DrawSpan_f result = drawspanfuncs[V_GetMode()][filterz][filter]; + if (result == NULL) + I_Error("R_GetDrawSpanFunc: undefined function (%d, %d)", + filter, filterz); + return result; +} + +void R_DrawSpan(draw_span_vars_t *dsvars) { + R_GetDrawSpanFunc(drawvars.filterfloor, drawvars.filterz)(dsvars); +} + +// +// R_InitBuffer +// Creats lookup tables that avoid +// multiplies and other hazzles +// for getting the framebuffer address +// of a pixel to draw. +// + +void R_InitBuffer(int width, int height) +{ + int i=0; + // Handle resize, + // e.g. smaller view windows + // with border and/or status bar. + + viewwindowx = (SCREENWIDTH-width) >> 1; + + // Same with base row offset. + + viewwindowy = width==SCREENWIDTH ? 0 : (SCREENHEIGHT-(ST_SCALED_HEIGHT-1)-height)>>1; + + drawvars.byte_topleft = screens[0].data + viewwindowy*screens[0].byte_pitch + viewwindowx; + drawvars.short_topleft = (unsigned short *)(screens[0].data) + viewwindowy*screens[0].short_pitch + viewwindowx; + drawvars.int_topleft = (unsigned int *)(screens[0].data) + viewwindowy*screens[0].int_pitch + viewwindowx; + drawvars.byte_pitch = screens[0].byte_pitch; + drawvars.short_pitch = screens[0].short_pitch; + drawvars.int_pitch = screens[0].int_pitch; + + if (V_GetMode() == VID_MODE8) { + for (i=0; i 0) { + for (i = (SCREENHEIGHT - ST_SCALED_HEIGHT); i < SCREENHEIGHT; i++) + { + R_VideoErase (0, i, side); + R_VideoErase (ST_SCALED_WIDTH+side, i, side); + } + } + } + + if ( viewheight >= ( SCREENHEIGHT - ST_SCALED_HEIGHT )) + return; // if high-res, don´t go any further! + + top = ((SCREENHEIGHT-ST_SCALED_HEIGHT)-viewheight)/2; + side = (SCREENWIDTH-scaledviewwidth)/2; + + // copy top + for (i = 0; i < top; i++) + R_VideoErase (0, i, SCREENWIDTH); + + // copy sides + for (i = top; i < (top+viewheight); i++) { + R_VideoErase (0, i, side); + R_VideoErase (viewwidth+side, i, side); + } + + // copy bottom + for (i = top+viewheight; i < (SCREENHEIGHT - ST_SCALED_HEIGHT); i++) + R_VideoErase (0, i, SCREENWIDTH); +} diff --git a/common/prboom/r_draw.h b/common/prboom/r_draw.h new file mode 100755 index 0000000..47dfd68 --- /dev/null +++ b/common/prboom/r_draw.h @@ -0,0 +1,160 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * System specific interface stuff. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __R_DRAW__ +#define __R_DRAW__ + +#include "r_defs.h" + + +enum column_pipeline_e { + RDC_PIPELINE_STANDARD, + RDC_PIPELINE_TRANSLUCENT, + RDC_PIPELINE_TRANSLATED, + RDC_PIPELINE_FUZZ, + RDC_PIPELINE_MAXPIPELINES, +}; + +// Used to specify what kind of filering you want +enum draw_filter_type_e { + RDRAW_FILTER_NONE, + RDRAW_FILTER_POINT, + RDRAW_FILTER_LINEAR, + RDRAW_FILTER_ROUNDED, + RDRAW_FILTER_MAXFILTERS +}; + +// Used to specify what kind of column edge rendering to use on masked +// columns. SQUARE = standard, SLOPED = slope the column edge up or down +// based on neighboring columns +enum sloped_edge_type_e { + RDRAW_MASKEDCOLUMNEDGE_SQUARE, + RDRAW_MASKEDCOLUMNEDGE_SLOPED +}; + +// Packaged into a struct - POPE +typedef struct { + int x; + int yl; + int yh; + fixed_t z; // the current column z coord + fixed_t iscale; + fixed_t texturemid; + int texheight; // killough + fixed_t texu; // the current column u coord + const byte *source; // first pixel in a column + const byte *prevsource; // first pixel in previous column + const byte *nextsource; // first pixel in next column + const lighttable_t *colormap; + const lighttable_t *nextcolormap; + const byte *translation; + int edgeslope; // OR'ed RDRAW_EDGESLOPE_* + // 1 if R_DrawColumn* is currently drawing a masked column, otherwise 0 + int drawingmasked; + enum sloped_edge_type_e edgetype; +} draw_column_vars_t; + +void R_SetDefaultDrawColumnVars(draw_column_vars_t *dcvars); + +void R_VideoErase(int x, int y, int count); + +typedef struct { + int y; + int x1; + int x2; + fixed_t z; // the current span z coord + fixed_t xfrac; + fixed_t yfrac; + fixed_t xstep; + fixed_t ystep; + const byte *source; // start of a 64*64 tile image + const lighttable_t *colormap; + const lighttable_t *nextcolormap; +} draw_span_vars_t; + +typedef struct { + byte *byte_topleft; + unsigned short *short_topleft; + unsigned int *int_topleft; + int byte_pitch; + int short_pitch; + int int_pitch; + + enum draw_filter_type_e filterwall; + enum draw_filter_type_e filterfloor; + enum draw_filter_type_e filtersprite; + enum draw_filter_type_e filterz; + enum draw_filter_type_e filterpatch; + + enum sloped_edge_type_e sprite_edges; + enum sloped_edge_type_e patch_edges; + + // Used to specify an early-out magnification threshold for filtering. + // If a texture is being minified (dcvars.iscale > rdraw_magThresh), then it + // drops back to point filtering. + fixed_t mag_threshold; +} draw_vars_t; + +extern draw_vars_t drawvars; + +extern byte playernumtotrans[MAXPLAYERS]; // CPhipps - what translation table for what player +extern byte *translationtables; + +typedef void (*R_DrawColumn_f)(draw_column_vars_t *dcvars); +R_DrawColumn_f R_GetDrawColumnFunc(enum column_pipeline_e type, + enum draw_filter_type_e filter, + enum draw_filter_type_e filterz); + +// Span blitting for rows, floor/ceiling. No Spectre effect needed. +typedef void (*R_DrawSpan_f)(draw_span_vars_t *dsvars); +R_DrawSpan_f R_GetDrawSpanFunc(enum draw_filter_type_e filter, + enum draw_filter_type_e filterz); +void R_DrawSpan(draw_span_vars_t *dsvars); + +void R_InitBuffer(int width, int height); + +// Initialize color translation tables, for player rendering etc. +void R_InitTranslationTables(void); + +// Rendering function. +void R_FillBackScreen(void); + +// If the view size is not full screen, draws a border around it. +void R_DrawViewBorder(void); + +// haleyjd 09/13/04: new function to call from main rendering loop +// which gets rid of the unnecessary reset of various variables during +// column drawing. +void R_ResetColumnBuffer(void); + +#endif diff --git a/common/prboom/r_drawcolpipeline.inl b/common/prboom/r_drawcolpipeline.inl new file mode 100755 index 0000000..8e122cd --- /dev/null +++ b/common/prboom/r_drawcolpipeline.inl @@ -0,0 +1,51 @@ + +// no color mapping +#define R_DRAWCOLUMN_FUNCNAME R_DRAWCOLUMN_FUNCNAME_COMPOSITE(_PointUV) +#define R_DRAWCOLUMN_PIPELINE (R_DRAWCOLUMN_PIPELINE_BASE | RDC_NOCOLMAP) +#include "r_drawcolumn.inl" + +// simple depth color mapping +#define R_DRAWCOLUMN_FUNCNAME R_DRAWCOLUMN_FUNCNAME_COMPOSITE(_PointUV_PointZ) +#define R_DRAWCOLUMN_PIPELINE R_DRAWCOLUMN_PIPELINE_BASE +#include "r_drawcolumn.inl" + +// z-dither +#define R_DRAWCOLUMN_FUNCNAME R_DRAWCOLUMN_FUNCNAME_COMPOSITE(_PointUV_LinearZ) +#define R_DRAWCOLUMN_PIPELINE (R_DRAWCOLUMN_PIPELINE_BASE | RDC_DITHERZ) +#include "r_drawcolumn.inl" + +// bilinear with no color mapping +#define R_DRAWCOLUMN_FUNCNAME R_DRAWCOLUMN_FUNCNAME_COMPOSITE(_LinearUV) +#define R_DRAWCOLUMN_PIPELINE (R_DRAWCOLUMN_PIPELINE_BASE | RDC_BILINEAR | RDC_NOCOLMAP) +#include "r_drawcolumn.inl" + +// bilinear with simple depth color mapping +#define R_DRAWCOLUMN_FUNCNAME R_DRAWCOLUMN_FUNCNAME_COMPOSITE(_LinearUV_PointZ) +#define R_DRAWCOLUMN_PIPELINE (R_DRAWCOLUMN_PIPELINE_BASE | RDC_BILINEAR) +#include "r_drawcolumn.inl" + +// bilinear + z-dither +#define R_DRAWCOLUMN_FUNCNAME R_DRAWCOLUMN_FUNCNAME_COMPOSITE(_LinearUV_LinearZ) +#define R_DRAWCOLUMN_PIPELINE (R_DRAWCOLUMN_PIPELINE_BASE | RDC_BILINEAR | RDC_DITHERZ) +#include "r_drawcolumn.inl" + +// rounded with no color mapping +#define R_DRAWCOLUMN_FUNCNAME R_DRAWCOLUMN_FUNCNAME_COMPOSITE(_RoundedUV) +#define R_DRAWCOLUMN_PIPELINE (R_DRAWCOLUMN_PIPELINE_BASE | RDC_ROUNDED | RDC_NOCOLMAP) +#include "r_drawcolumn.inl" + +// rounded with simple depth color mapping +#define R_DRAWCOLUMN_FUNCNAME R_DRAWCOLUMN_FUNCNAME_COMPOSITE(_RoundedUV_PointZ) +#define R_DRAWCOLUMN_PIPELINE (R_DRAWCOLUMN_PIPELINE_BASE | RDC_ROUNDED) +#include "r_drawcolumn.inl" + +// rounded + z-dither +#define R_DRAWCOLUMN_FUNCNAME R_DRAWCOLUMN_FUNCNAME_COMPOSITE(_RoundedUV_LinearZ) +#define R_DRAWCOLUMN_PIPELINE (R_DRAWCOLUMN_PIPELINE_BASE | RDC_ROUNDED | RDC_DITHERZ) +#include "r_drawcolumn.inl" + +#undef R_FLUSHWHOLE_FUNCNAME +#undef R_FLUSHHEADTAIL_FUNCNAME +#undef R_FLUSHQUAD_FUNCNAME +#undef R_DRAWCOLUMN_FUNCNAME_COMPOSITE +#undef R_DRAWCOLUMN_PIPELINE_BITS diff --git a/common/prboom/r_drawcolumn.inl b/common/prboom/r_drawcolumn.inl new file mode 100755 index 0000000..84ef852 --- /dev/null +++ b/common/prboom/r_drawcolumn.inl @@ -0,0 +1,386 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + *-----------------------------------------------------------------------------*/ + + +#if (R_DRAWCOLUMN_PIPELINE_BITS == 8) +#define SCREENTYPE byte +#define TEMPBUF byte_tempbuf +#elif (R_DRAWCOLUMN_PIPELINE_BITS == 15) +#define SCREENTYPE unsigned short +#define TEMPBUF short_tempbuf +#elif (R_DRAWCOLUMN_PIPELINE_BITS == 16) +#define SCREENTYPE unsigned short +#define TEMPBUF short_tempbuf +#elif (R_DRAWCOLUMN_PIPELINE_BITS == 32) +#define SCREENTYPE unsigned int +#define TEMPBUF int_tempbuf +#endif + +#define GETDESTCOLOR8(col) (col) +#define GETDESTCOLOR15(col) (col) +#define GETDESTCOLOR16(col) (col) +#define GETDESTCOLOR32(col) (col) + +#if (R_DRAWCOLUMN_PIPELINE & RDC_TRANSLATED) +#define GETCOL8_MAPPED(col) (translation[(col)]) +#else +#define GETCOL8_MAPPED(col) (col) +#endif + +#if (R_DRAWCOLUMN_PIPELINE & RDC_NOCOLMAP) + #define GETCOL8_DEPTH(col) GETCOL8_MAPPED(col) +#else + #if (R_DRAWCOLUMN_PIPELINE & RDC_DITHERZ) + #define GETCOL8_DEPTH(col) (dither_colormaps[filter_getDitheredPixelLevel(x, y, fracz)][GETCOL8_MAPPED(col)]) + #else + #define GETCOL8_DEPTH(col) colormap[GETCOL8_MAPPED(col)] + #endif +#endif + +#if (R_DRAWCOLUMN_PIPELINE & RDC_BILINEAR) + #define GETCOL8(frac, nextfrac) GETCOL8_DEPTH(filter_getDitheredForColumn(x,y,frac,nextfrac)) + #define GETCOL15(frac, nextfrac) filter_getFilteredForColumn15(GETCOL8_DEPTH,frac,nextfrac) + #define GETCOL16(frac, nextfrac) filter_getFilteredForColumn16(GETCOL8_DEPTH,frac,nextfrac) + #define GETCOL32(frac, nextfrac) filter_getFilteredForColumn32(GETCOL8_DEPTH,frac,nextfrac) +#elif (R_DRAWCOLUMN_PIPELINE & RDC_ROUNDED) + #define GETCOL8(frac, nextfrac) GETCOL8_DEPTH(filter_getRoundedForColumn(frac,nextfrac)) + #define GETCOL15(frac, nextfrac) VID_PAL15(GETCOL8_DEPTH(filter_getRoundedForColumn(frac,nextfrac)), VID_COLORWEIGHTMASK) + #define GETCOL16(frac, nextfrac) VID_PAL16(GETCOL8_DEPTH(filter_getRoundedForColumn(frac,nextfrac)), VID_COLORWEIGHTMASK) + #define GETCOL32(frac, nextfrac) VID_PAL32(GETCOL8_DEPTH(filter_getRoundedForColumn(frac,nextfrac)), VID_COLORWEIGHTMASK) +#else + #define GETCOL8(frac, nextfrac) GETCOL8_DEPTH(source[(frac)>>FRACBITS]) + #define GETCOL15(frac, nextfrac) VID_PAL15(GETCOL8_DEPTH(source[(frac)>>FRACBITS]), VID_COLORWEIGHTMASK) + #define GETCOL16(frac, nextfrac) VID_PAL16(GETCOL8_DEPTH(source[(frac)>>FRACBITS]), VID_COLORWEIGHTMASK) + #define GETCOL32(frac, nextfrac) VID_PAL32(GETCOL8_DEPTH(source[(frac)>>FRACBITS]), VID_COLORWEIGHTMASK) +#endif + +#if (R_DRAWCOLUMN_PIPELINE & (RDC_BILINEAR|RDC_ROUNDED|RDC_DITHERZ)) + #define INCY(y) (y++) +#else + #define INCY(y) +#endif + +#if (R_DRAWCOLUMN_PIPELINE & RDC_TRANSLUCENT) +#define COLTYPE (COL_TRANS) +#elif (R_DRAWCOLUMN_PIPELINE & RDC_FUZZ) +#define COLTYPE (COL_FUZZ) +#else +#define COLTYPE (COL_OPAQUE) +#endif + +#if (R_DRAWCOLUMN_PIPELINE_BITS == 8) + #define GETCOL(frac, nextfrac) GETCOL8(frac, nextfrac) + #define GETDESTCOLOR(col) GETDESTCOLOR8(col) +#elif (R_DRAWCOLUMN_PIPELINE_BITS == 15) + #define GETCOL(frac, nextfrac) GETCOL15(frac, nextfrac) + #define GETDESTCOLOR(col) GETDESTCOLOR15(col) +#elif (R_DRAWCOLUMN_PIPELINE_BITS == 16) + #define GETCOL(frac, nextfrac) GETCOL16(frac, nextfrac) + #define GETDESTCOLOR(col) GETDESTCOLOR16(col) +#elif (R_DRAWCOLUMN_PIPELINE_BITS == 32) + #define GETCOL(frac, nextfrac) GETCOL32(frac, nextfrac) + #define GETDESTCOLOR(col) GETDESTCOLOR32(col) +#endif + +static void R_DRAWCOLUMN_FUNCNAME(draw_column_vars_t *dcvars) +{ + int count; + SCREENTYPE *dest; // killough + fixed_t frac; + const fixed_t fracstep = dcvars->iscale; +#if ((R_DRAWCOLUMN_PIPELINE & RDC_BILINEAR) && (R_DRAWCOLUMN_PIPELINE_BITS != 8)) + const fixed_t slope_texu = (dcvars->source == dcvars->nextsource) ? 0 : dcvars->texu & 0xffff; +#else + const fixed_t slope_texu = dcvars->texu; +#endif + + // drop back to point filtering if we're minifying +#if (R_DRAWCOLUMN_PIPELINE & (RDC_BILINEAR|RDC_ROUNDED)) + if (dcvars->iscale > drawvars.mag_threshold) { + R_GetDrawColumnFunc(R_DRAWCOLUMN_PIPELINE_TYPE, + RDRAW_FILTER_POINT, + drawvars.filterz)(dcvars); + return; + } +#endif + +#if (R_DRAWCOLUMN_PIPELINE & RDC_FUZZ) + // Adjust borders. Low... + if (!dcvars->yl) + dcvars->yl = 1; + + // .. and high. + if (dcvars->yh == viewheight-1) + dcvars->yh = viewheight - 2; +#endif + + // leban 1/17/99: + // removed the + 1 here, adjusted the if test, and added an increment + // later. this helps a compiler pipeline a bit better. the x86 + // assembler also does this. + + count = dcvars->yh - dcvars->yl; + + // leban 1/17/99: + // this case isn't executed too often. depending on how many instructions + // there are between here and the second if test below, this case could + // be moved down and might save instructions overall. since there are + // probably different wads that favor one way or the other, i'll leave + // this alone for now. + if (count < 0) // Zero length, column does not exceed a pixel. + return; + +#ifdef RANGECHECK + if (dcvars->x >= SCREENWIDTH + || dcvars->yl < 0 + || dcvars->yh >= SCREENHEIGHT) + I_Error("R_DrawColumn: %i to %i at %i", dcvars->yl, dcvars->yh, dcvars->x); +#endif + + // Determine scaling, which is the only mapping to be done. + #if (R_DRAWCOLUMN_PIPELINE & RDC_BILINEAR) + frac = dcvars->texturemid - (FRACUNIT>>1) + (dcvars->yl-centery)*fracstep; + #else + frac = dcvars->texturemid + (dcvars->yl-centery)*fracstep; + #endif + + if (dcvars->drawingmasked && dcvars->edgetype == RDRAW_MASKEDCOLUMNEDGE_SLOPED) { + // slope the top and bottom column edge based on the fractional u coordinate + // and dcvars->edgeslope, which were set in R_DrawMaskedColumn + // in r_things.c + if (dcvars->yl != 0) { + if (dcvars->edgeslope & RDRAW_EDGESLOPE_TOP_UP) { + // [/#] + int shift = ((0xffff-(slope_texu & 0xffff))/dcvars->iscale); + dcvars->yl += shift; + count -= shift; + frac += 0xffff-(slope_texu & 0xffff); + } + else if (dcvars->edgeslope & RDRAW_EDGESLOPE_TOP_DOWN) { + // [#\] + int shift = ((slope_texu & 0xffff)/dcvars->iscale); + dcvars->yl += shift; + count -= shift; + frac += slope_texu & 0xffff; + } + } + if (dcvars->yh != viewheight-1) { + if (dcvars->edgeslope & RDRAW_EDGESLOPE_BOT_UP) { + // [#/] + int shift = ((0xffff-(slope_texu & 0xffff))/dcvars->iscale); + dcvars->yh -= shift; + count -= shift; + } + else if (dcvars->edgeslope & RDRAW_EDGESLOPE_BOT_DOWN) { + // [\#] + int shift = ((slope_texu & 0xffff)/dcvars->iscale); + dcvars->yh -= shift; + count -= shift; + } + } + if (count <= 0) return; + } + + // Framebuffer destination address. + // SoM: MAGIC + { + // haleyjd: reordered predicates + if(temp_x == 4 || + (temp_x && (temptype != COLTYPE || temp_x + startx != dcvars->x))) + R_FlushColumns(); + + if(!temp_x) + { + startx = dcvars->x; + tempyl[0] = commontop = dcvars->yl; + tempyh[0] = commonbot = dcvars->yh; + temptype = COLTYPE; +#if (R_DRAWCOLUMN_PIPELINE & RDC_TRANSLUCENT) + temptranmap = tranmap; +#elif (R_DRAWCOLUMN_PIPELINE & RDC_FUZZ) + tempfuzzmap = fullcolormap; // SoM 7-28-04: Fix the fuzz problem. +#endif + R_FlushWholeColumns = R_FLUSHWHOLE_FUNCNAME; + R_FlushHTColumns = R_FLUSHHEADTAIL_FUNCNAME; + R_FlushQuadColumn = R_FLUSHQUAD_FUNCNAME; + dest = &TEMPBUF[dcvars->yl << 2]; + } else { + tempyl[temp_x] = dcvars->yl; + tempyh[temp_x] = dcvars->yh; + + if(dcvars->yl > commontop) + commontop = dcvars->yl; + if(dcvars->yh < commonbot) + commonbot = dcvars->yh; + + dest = &TEMPBUF[(dcvars->yl << 2) + temp_x]; + } + temp_x += 1; + } + +// do nothing else when drawin fuzz columns +#if (!(R_DRAWCOLUMN_PIPELINE & RDC_FUZZ)) + { + const byte *source = dcvars->source; + const lighttable_t *colormap = dcvars->colormap; + const byte *translation = dcvars->translation; + +#if (R_DRAWCOLUMN_PIPELINE & (RDC_BILINEAR|RDC_ROUNDED|RDC_DITHERZ)) + int y = dcvars->yl; + const int x = dcvars->x; + (void)x; +#endif +#if (R_DRAWCOLUMN_PIPELINE & RDC_DITHERZ) + const int fracz = (dcvars->z >> 6) & 255; + const byte *dither_colormaps[2] = { dcvars->colormap, dcvars->nextcolormap }; +#endif +#if (R_DRAWCOLUMN_PIPELINE & RDC_BILINEAR) + #if (R_DRAWCOLUMN_PIPELINE_BITS == 8) + const int yl = dcvars->yl; + const byte *dither_sources[2] = { dcvars->source, dcvars->nextsource }; + const unsigned int filter_fracu = (dcvars->source == dcvars->nextsource) ? 0 : (dcvars->texu>>8) & 0xff; + #else + const byte *nextsource = dcvars->nextsource; + const unsigned int filter_fracu = (dcvars->source == dcvars->nextsource) ? 0 : dcvars->texu & 0xffff; + #endif +#endif +#if (R_DRAWCOLUMN_PIPELINE & RDC_ROUNDED) + const byte *prevsource = dcvars->prevsource; + const byte *nextsource = dcvars->nextsource; + const unsigned int filter_fracu = (dcvars->source == dcvars->nextsource) ? 0 : (dcvars->texu>>8) & 0xff; +#endif + + /* Prevent unused variable warnings. */ + (void)source; + (void)colormap; + (void)translation; + + count++; + + // Inner loop that does the actual texture mapping, + // e.g. a DDA-lile scaling. + // This is as fast as it gets. (Yeah, right!!! -- killough) + // + // killough 2/1/98: more performance tuning + + if (dcvars->texheight == 128) { + #define FIXEDT_128MASK ((127<texheight == 0) { + /* cph - another special case */ + while (count--) { + *dest = GETDESTCOLOR(GETCOL(frac, (frac+FRACUNIT))); + INCY(y); + dest += 4; + frac += fracstep; + } + } else { + unsigned heightmask = dcvars->texheight-1; // CPhipps - specify type + if (! (dcvars->texheight & heightmask) ) { // power of 2 -- killough + fixed_t fixedt_heightmask = (heightmask<=0) { // texture height is a power of 2 -- killough + *dest = GETDESTCOLOR(GETCOL(frac & fixedt_heightmask, (frac+FRACUNIT) & fixedt_heightmask)); + INCY(y); + dest += 4; + frac += fracstep; + *dest = GETDESTCOLOR(GETCOL(frac & fixedt_heightmask, (frac+FRACUNIT) & fixedt_heightmask)); + INCY(y); + dest += 4; + frac += fracstep; + } + if (count & 1) + *dest = GETDESTCOLOR(GETCOL(frac & fixedt_heightmask, (frac+FRACUNIT) & fixedt_heightmask)); + INCY(y); + } else { + fixed_t nextfrac = 0; + (void)nextfrac; + + heightmask++; + heightmask <<= FRACBITS; + + if (frac < 0) + while ((frac += heightmask) < 0); + else + while (frac >= (int)heightmask) + frac -= heightmask; + +#if (R_DRAWCOLUMN_PIPELINE & (RDC_BILINEAR|RDC_ROUNDED)) + nextfrac = frac + FRACUNIT; + while (nextfrac >= (int)heightmask) + nextfrac -= heightmask; +#endif + +#define INCFRAC(f) if ((f += fracstep) >= (int)heightmask) f -= heightmask; + + while (count--) { + // Re-map color indices from wall texture column + // using a lighting/special effects LUT. + + // heightmask is the Tutti-Frutti fix -- killough + + *dest = GETDESTCOLOR(GETCOL(frac, nextfrac)); + INCY(y); + dest += 4; + INCFRAC(frac); +#if (R_DRAWCOLUMN_PIPELINE & (RDC_BILINEAR|RDC_ROUNDED)) + INCFRAC(nextfrac); +#endif + } + } + } + } +#endif // (!(R_DRAWCOLUMN_PIPELINE & RDC_FUZZ)) +} + +#undef GETDESTCOLOR32 +#undef GETDESTCOLOR16 +#undef GETDESTCOLOR15 +#undef GETDESTCOLOR8 +#undef GETDESTCOLOR +#undef GETCOL8_MAPPED +#undef GETCOL8_DEPTH +#undef GETCOL32 +#undef GETCOL16 +#undef GETCOL15 +#undef GETCOL8 +#undef GETCOL +#undef INCY +#undef INCFRAC +#undef COLTYPE +#undef TEMPBUF +#undef SCREENTYPE + +#undef R_DRAWCOLUMN_FUNCNAME +#undef R_DRAWCOLUMN_PIPELINE diff --git a/common/prboom/r_drawflush.inl b/common/prboom/r_drawflush.inl new file mode 100755 index 0000000..ab8ce61 --- /dev/null +++ b/common/prboom/r_drawflush.inl @@ -0,0 +1,300 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + *-----------------------------------------------------------------------------*/ + +#if (R_DRAWCOLUMN_PIPELINE_BITS == 8) +#define SCREENTYPE byte +#define TOPLEFT byte_topleft +#define PITCH byte_pitch +#define TEMPBUF byte_tempbuf +#elif (R_DRAWCOLUMN_PIPELINE_BITS == 15) +#define SCREENTYPE unsigned short +#define TOPLEFT short_topleft +#define PITCH short_pitch +#define TEMPBUF short_tempbuf +#elif (R_DRAWCOLUMN_PIPELINE_BITS == 16) +#define SCREENTYPE unsigned short +#define TOPLEFT short_topleft +#define PITCH short_pitch +#define TEMPBUF short_tempbuf +#elif (R_DRAWCOLUMN_PIPELINE_BITS == 32) +#define SCREENTYPE unsigned int +#define TOPLEFT int_topleft +#define PITCH int_pitch +#define TEMPBUF int_tempbuf +#endif + +#if (R_DRAWCOLUMN_PIPELINE & RDC_TRANSLUCENT) +#define GETDESTCOLOR8(col1, col2) (temptranmap[((col1)<<8)+(col2)]) +#define GETDESTCOLOR15(col1, col2) (GETBLENDED15_3268((col1), (col2))) +#define GETDESTCOLOR16(col1, col2) (GETBLENDED16_3268((col1), (col2))) +#define GETDESTCOLOR32(col1, col2) (GETBLENDED32_3268((col1), (col2))) +#elif (R_DRAWCOLUMN_PIPELINE & RDC_FUZZ) +#define GETDESTCOLOR8(col) (tempfuzzmap[6*256+(col)]) +#define GETDESTCOLOR15(col) GETBLENDED15_9406(col, 0) +#define GETDESTCOLOR16(col) GETBLENDED16_9406(col, 0) +#define GETDESTCOLOR32(col) GETBLENDED32_9406(col, 0) +#else +#define GETDESTCOLOR8(col) (col) +#define GETDESTCOLOR15(col) (col) +#define GETDESTCOLOR16(col) (col) +#define GETDESTCOLOR32(col) (col) +#endif + +#if (R_DRAWCOLUMN_PIPELINE & RDC_TRANSLUCENT) + #if (R_DRAWCOLUMN_PIPELINE_BITS == 8) + #define GETDESTCOLOR(col1, col2) GETDESTCOLOR8(col1, col2) + #elif (R_DRAWCOLUMN_PIPELINE_BITS == 15) + #define GETDESTCOLOR(col1, col2) GETDESTCOLOR15(col1, col2) + #elif (R_DRAWCOLUMN_PIPELINE_BITS == 16) + #define GETDESTCOLOR(col1, col2) GETDESTCOLOR16(col1, col2) + #elif (R_DRAWCOLUMN_PIPELINE_BITS == 32) + #define GETDESTCOLOR(col1, col2) GETDESTCOLOR32(col1, col2) + #endif +#else + #if (R_DRAWCOLUMN_PIPELINE_BITS == 8) + #define GETDESTCOLOR(col) GETDESTCOLOR8(col) + #elif (R_DRAWCOLUMN_PIPELINE_BITS == 15) + #define GETDESTCOLOR(col) GETDESTCOLOR15(col) + #elif (R_DRAWCOLUMN_PIPELINE_BITS == 16) + #define GETDESTCOLOR(col) GETDESTCOLOR16(col) + #elif (R_DRAWCOLUMN_PIPELINE_BITS == 32) + #define GETDESTCOLOR(col) GETDESTCOLOR32(col) + #endif +#endif + +// +// R_FlushWholeOpaque +// +// Flushes the entire columns in the buffer, one at a time. +// This is used when a quad flush isn't possible. +// Opaque version -- no remapping whatsoever. +// +static void R_FLUSHWHOLE_FUNCNAME(void) +{ + SCREENTYPE *source; + SCREENTYPE *dest; + int count, yl; + + while(--temp_x >= 0) + { + yl = tempyl[temp_x]; + source = &TEMPBUF[temp_x + (yl << 2)]; + dest = drawvars.TOPLEFT + yl*drawvars.PITCH + startx + temp_x; + count = tempyh[temp_x] - yl + 1; + + while(--count >= 0) + { +#if (R_DRAWCOLUMN_PIPELINE & RDC_TRANSLUCENT) + *dest = GETDESTCOLOR(*dest, *source); +#elif (R_DRAWCOLUMN_PIPELINE & RDC_FUZZ) + // SoM 7-28-04: Fix the fuzz problem. + *dest = GETDESTCOLOR(dest[fuzzoffset[fuzzpos]]); + + // Clamp table lookup index. + if(++fuzzpos == FUZZTABLE) + fuzzpos = 0; +#else + *dest = *source; +#endif + + source += 4; + dest += drawvars.PITCH; + } + } +} + +// +// R_FlushHTOpaque +// +// Flushes the head and tail of columns in the buffer in +// preparation for a quad flush. +// Opaque version -- no remapping whatsoever. +// +static void R_FLUSHHEADTAIL_FUNCNAME(void) +{ + SCREENTYPE *source; + SCREENTYPE *dest; + int count, colnum = 0; + int yl, yh; + + while(colnum < 4) + { + yl = tempyl[colnum]; + yh = tempyh[colnum]; + + // flush column head + if(yl < commontop) + { + source = &TEMPBUF[colnum + (yl << 2)]; + dest = drawvars.TOPLEFT + yl*drawvars.PITCH + startx + colnum; + count = commontop - yl; + + while(--count >= 0) + { +#if (R_DRAWCOLUMN_PIPELINE & RDC_TRANSLUCENT) + // haleyjd 09/11/04: use temptranmap here + *dest = GETDESTCOLOR(*dest, *source); +#elif (R_DRAWCOLUMN_PIPELINE & RDC_FUZZ) + // SoM 7-28-04: Fix the fuzz problem. + *dest = GETDESTCOLOR(dest[fuzzoffset[fuzzpos]]); + + // Clamp table lookup index. + if(++fuzzpos == FUZZTABLE) + fuzzpos = 0; +#else + *dest = *source; +#endif + + source += 4; + dest += drawvars.PITCH; + } + } + + // flush column tail + if(yh > commonbot) + { + source = &TEMPBUF[colnum + ((commonbot + 1) << 2)]; + dest = drawvars.TOPLEFT + (commonbot + 1)*drawvars.PITCH + startx + colnum; + count = yh - commonbot; + + while(--count >= 0) + { +#if (R_DRAWCOLUMN_PIPELINE & RDC_TRANSLUCENT) + // haleyjd 09/11/04: use temptranmap here + *dest = GETDESTCOLOR(*dest, *source); +#elif (R_DRAWCOLUMN_PIPELINE & RDC_FUZZ) + // SoM 7-28-04: Fix the fuzz problem. + *dest = GETDESTCOLOR(dest[fuzzoffset[fuzzpos]]); + + // Clamp table lookup index. + if(++fuzzpos == FUZZTABLE) + fuzzpos = 0; +#else + *dest = *source; +#endif + + source += 4; + dest += drawvars.PITCH; + } + } + ++colnum; + } +} + +static void R_FLUSHQUAD_FUNCNAME(void) +{ + SCREENTYPE *source = &TEMPBUF[commontop << 2]; + SCREENTYPE *dest = drawvars.TOPLEFT + commontop*drawvars.PITCH + startx; + int count; +#if (R_DRAWCOLUMN_PIPELINE & RDC_FUZZ) + int fuzz1, fuzz2, fuzz3, fuzz4; + + fuzz1 = fuzzpos; + fuzz2 = (fuzz1 + tempyl[1]) % FUZZTABLE; + fuzz3 = (fuzz2 + tempyl[2]) % FUZZTABLE; + fuzz4 = (fuzz3 + tempyl[3]) % FUZZTABLE; +#endif + + count = commonbot - commontop + 1; + +#if (R_DRAWCOLUMN_PIPELINE & RDC_TRANSLUCENT) + while(--count >= 0) + { + dest[0] = GETDESTCOLOR(dest[0], source[0]); + dest[1] = GETDESTCOLOR(dest[1], source[1]); + dest[2] = GETDESTCOLOR(dest[2], source[2]); + dest[3] = GETDESTCOLOR(dest[3], source[3]); + source += 4 * sizeof(byte); + dest += drawvars.PITCH * sizeof(byte); + } +#elif (R_DRAWCOLUMN_PIPELINE & RDC_FUZZ) + while(--count >= 0) + { + dest[0] = GETDESTCOLOR(dest[0 + fuzzoffset[fuzz1]]); + dest[1] = GETDESTCOLOR(dest[1 + fuzzoffset[fuzz2]]); + dest[2] = GETDESTCOLOR(dest[2 + fuzzoffset[fuzz3]]); + dest[3] = GETDESTCOLOR(dest[3 + fuzzoffset[fuzz4]]); + fuzz1 = (fuzz1 + 1) % FUZZTABLE; + fuzz2 = (fuzz2 + 1) % FUZZTABLE; + fuzz3 = (fuzz3 + 1) % FUZZTABLE; + fuzz4 = (fuzz4 + 1) % FUZZTABLE; + source += 4 * sizeof(byte); + dest += drawvars.PITCH * sizeof(byte); + } +#else + #if (R_DRAWCOLUMN_PIPELINE_BITS == 8) + if ((sizeof(int) == 4) && (((int)source % 4) == 0) && (((int)dest % 4) == 0)) { + while(--count >= 0) + { + *(int *)dest = *(int *)source; + source += 4 * sizeof(byte); + dest += drawvars.PITCH * sizeof(byte); + } + } else { + while(--count >= 0) + { + dest[0] = source[0]; + dest[1] = source[1]; + dest[2] = source[2]; + dest[3] = source[3]; + source += 4 * sizeof(byte); + dest += drawvars.PITCH * sizeof(byte); + } + } + #else + while(--count >= 0) + { + dest[0] = source[0]; + dest[1] = source[1]; + dest[2] = source[2]; + dest[3] = source[3]; + source += 4; + dest += drawvars.PITCH; + } + #endif +#endif +} + +#undef GETDESTCOLOR32 +#undef GETDESTCOLOR16 +#undef GETDESTCOLOR15 +#undef GETDESTCOLOR8 +#undef GETDESTCOLOR + +#undef TEMPBUF +#undef PITCH +#undef TOPLEFT +#undef SCREENTYPE + +#undef R_DRAWCOLUMN_PIPELINE_BITS +#undef R_DRAWCOLUMN_PIPELINE +#undef R_FLUSHWHOLE_FUNCNAME +#undef R_FLUSHHEADTAIL_FUNCNAME +#undef R_FLUSHQUAD_FUNCNAME diff --git a/common/prboom/r_drawspan.inl b/common/prboom/r_drawspan.inl new file mode 100755 index 0000000..2953a8f --- /dev/null +++ b/common/prboom/r_drawspan.inl @@ -0,0 +1,164 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + *-----------------------------------------------------------------------------*/ + +// +// R_DrawSpan +// + +#if (R_DRAWSPAN_PIPELINE_BITS == 8) +#define SCREENTYPE byte +#define TOPLEFT byte_topleft +#define PITCH byte_pitch +#elif (R_DRAWSPAN_PIPELINE_BITS == 15) +#define SCREENTYPE unsigned short +#define TOPLEFT short_topleft +#define PITCH short_pitch +#elif (R_DRAWSPAN_PIPELINE_BITS == 16) +#define SCREENTYPE unsigned short +#define TOPLEFT short_topleft +#define PITCH short_pitch +#elif (R_DRAWSPAN_PIPELINE_BITS == 32) +#define SCREENTYPE unsigned int +#define TOPLEFT int_topleft +#define PITCH int_pitch +#endif + +#if (R_DRAWSPAN_PIPELINE & RDC_DITHERZ) + #define GETDEPTHMAP(col) dither_colormaps[filter_getDitheredPixelLevel(x1, y, fracz)][(col)] +#else + #define GETDEPTHMAP(col) colormap[(col)] +#endif + +#if (R_DRAWSPAN_PIPELINE_BITS == 8) + #define GETCOL_POINT(col) GETDEPTHMAP(col) + #define GETCOL_LINEAR(col) GETDEPTHMAP(col) +#elif (R_DRAWSPAN_PIPELINE_BITS == 15) + #define GETCOL_POINT(col) VID_PAL15(GETDEPTHMAP(col), VID_COLORWEIGHTMASK) + #define GETCOL_LINEAR(col) filter_getFilteredForSpan15(GETDEPTHMAP, xfrac, yfrac) +#elif (R_DRAWSPAN_PIPELINE_BITS == 16) + #define GETCOL_POINT(col) VID_PAL16(GETDEPTHMAP(col), VID_COLORWEIGHTMASK) + #define GETCOL_LINEAR(col) filter_getFilteredForSpan16(GETDEPTHMAP, xfrac, yfrac) +#elif (R_DRAWSPAN_PIPELINE_BITS == 32) + #define GETCOL_POINT(col) VID_PAL32(GETDEPTHMAP(col), VID_COLORWEIGHTMASK) + #define GETCOL_LINEAR(col) filter_getFilteredForSpan32(GETDEPTHMAP, xfrac, yfrac) +#endif + +#if (R_DRAWSPAN_PIPELINE & RDC_BILINEAR) + #define GETCOL(col) GETCOL_LINEAR(col) +#else + #define GETCOL(col) GETCOL_POINT(col) +#endif + +static void R_DRAWSPAN_FUNCNAME(draw_span_vars_t *dsvars) +{ +#if (R_DRAWSPAN_PIPELINE & (RDC_ROUNDED|RDC_BILINEAR)) + // drop back to point filtering if we're minifying + // 49152 = FRACUNIT * 0.75 + if ((D_abs(dsvars->xstep) > drawvars.mag_threshold) + || (D_abs(dsvars->ystep) > drawvars.mag_threshold)) + { + R_GetDrawSpanFunc(RDRAW_FILTER_POINT, + drawvars.filterz)(dsvars); + return; + } +#endif + { + unsigned count = dsvars->x2 - dsvars->x1 + 1; + fixed_t xfrac = dsvars->xfrac; + fixed_t yfrac = dsvars->yfrac; + const fixed_t xstep = dsvars->xstep; + const fixed_t ystep = dsvars->ystep; + const byte *source = dsvars->source; + const byte *colormap = dsvars->colormap; + (void)colormap; + SCREENTYPE *dest = drawvars.TOPLEFT + dsvars->y*drawvars.PITCH + dsvars->x1; +#if (R_DRAWSPAN_PIPELINE & (RDC_DITHERZ|RDC_BILINEAR)) + const int y = dsvars->y; + int x1 = dsvars->x1; + + (void)y; + (void)x1; +#endif +#if (R_DRAWSPAN_PIPELINE & RDC_DITHERZ) + const int fracz = (dsvars->z >> 12) & 255; + const byte *dither_colormaps[2] = { dsvars->colormap, dsvars->nextcolormap }; +#endif + + while (count) { +#if ((R_DRAWSPAN_PIPELINE_BITS != 8) && (R_DRAWSPAN_PIPELINE & RDC_BILINEAR)) + // truecolor bilinear filtered + *dest++ = GETCOL(0); + xfrac += xstep; + yfrac += ystep; + count--; + #if (R_DRAWSPAN_PIPELINE & RDC_DITHERZ) + x1--; + #endif +#elif (R_DRAWSPAN_PIPELINE & RDC_ROUNDED) + *dest++ = GETCOL(filter_getRoundedForSpan(xfrac, yfrac)); + xfrac += xstep; + yfrac += ystep; + count--; + #if (R_DRAWSPAN_PIPELINE & RDC_DITHERZ) + x1--; + #endif +#else + #if (R_DRAWSPAN_PIPELINE & RDC_BILINEAR) + // 8 bit bilinear + const fixed_t xtemp = ((xfrac >> 16) + (filter_getDitheredPixelLevel(x1, y, ((xfrac>>8)&0xff)))) & 63; + const fixed_t ytemp = ((yfrac >> 10) + 64*(filter_getDitheredPixelLevel(x1, y, ((yfrac>>8)&0xff)))) & 4032; + #else + const fixed_t xtemp = (xfrac >> 16) & 63; + const fixed_t ytemp = (yfrac >> 10) & 4032; + #endif + const fixed_t spot = xtemp | ytemp; + xfrac += xstep; + yfrac += ystep; + *dest++ = GETCOL(source[spot]); + count--; + #if (R_DRAWSPAN_PIPELINE & (RDC_DITHERZ|RDC_BILINEAR)) + x1--; + #endif +#endif + } + } +} + +#undef GETDEPTHMAP +#undef GETCOL_LINEAR +#undef GETCOL_POINT +#undef GETCOL +#undef PITCH +#undef TOPLEFT +#undef SCREENTYPE + +#undef R_DRAWSPAN_PIPELINE_BITS +#undef R_DRAWSPAN_PIPELINE +#undef R_DRAWSPAN_FUNCNAME diff --git a/common/prboom/r_filter.c b/common/prboom/r_filter.c new file mode 100755 index 0000000..ee49bf7 --- /dev/null +++ b/common/prboom/r_filter.c @@ -0,0 +1,119 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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 "doomtype.h" +#include "r_filter.h" + +#define DMR 16 +byte filter_ditherMatrix[DITHER_DIM][DITHER_DIM] = { + {0*DMR, 14*DMR, 3*DMR, 13*DMR}, {11*DMR, 5*DMR, 8*DMR, 6*DMR}, + {12*DMR, 2*DMR, 15*DMR, 1*DMR}, {7*DMR, 9*DMR, 4*DMR, 10*DMR} +}; + +byte filter_roundedUVMap[FILTER_UVDIM*FILTER_UVDIM]; +byte filter_roundedRowMap[4*16]; + +void R_FilterInit(void) { + int i,j,s,t; + + // scale2x takes the following source: + // A B C + // D E F + // G H I + // + // and doubles the size of E to produce: + // E0 E1 + // E2 E3 + // + // E0 = D == B && B != F && D != H ? D : E; + // E1 = B == F && B != D && F != H ? F : E; + // E2 = D == H && D != B && H != F ? D : E; + // E3 = H == F && D != H && B != F ? F : E; + // + // to make this comparison regimen faster, we encode source color + // equivalency into a single byte with the getCode() macro + // + // #define getCode(b,f,h,d) ( (b == f)<<0 | (f == h)<<1 | (h == d)<<2 | (d == b)<<3 ) + + // encode the scale2x conditionals into a lookup code + for (i=0; i<16; i++) { + // E0 = D == B && B != F && D != H ? D : E; // 10-0 => 1000 or 1010 => 8 or A + filter_roundedRowMap[0*16+i] = (i == 0x8 || i == 0xA) ? 0 : 1; + // E1 = B == F && B != D && F != H ? F : E; // 0-01 => 0101 or 0001 => 5 or 1 + filter_roundedRowMap[1*16+i] = (i == 0x5 || i == 0x1) ? 2 : 1; + // E2 = D == H && D != B && H != F ? D : E; // 010- => 0101 or 0100 => 5 or 4 + filter_roundedRowMap[2*16+i] = (i == 0x4 || i == 0x5) ? 0 : 1; + // E3 = H == F && D != H && B != F ? F : E; // -010 => 1010 or 0010 => A or 2 + filter_roundedRowMap[3*16+i] = (i == 0xA || i == 0x2) ? 2 : 1; + } + + // fill the uvMap. this will return: + // 0/\1 + // /4 \ + // \ / + // 2\/3 + // .. based on the uv coordinates + for (i=0; i=0 && t>=0) filter_roundedUVMap[i*FILTER_UVDIM+j] = (s+t > FILTER_UVDIM/2) ? 0 : 4; + else if (s>=0 && t<=0) filter_roundedUVMap[i*FILTER_UVDIM+j] = (s-t > FILTER_UVDIM/2) ? 2 : 4; + else if (s<=0 && t>=0) filter_roundedUVMap[i*FILTER_UVDIM+j] = (-s+t > FILTER_UVDIM/2) ? 1 : 4; + else if (s<=0 && t<=0) filter_roundedUVMap[i*FILTER_UVDIM+j] = (-s-t > FILTER_UVDIM/2) ? 3 : 4; + else filter_roundedUVMap[i*FILTER_UVDIM+j] = 4; + } + } +} + +byte *filter_getScale2xQuadColors(byte e, byte b, byte f, byte h, byte d) { + // A B C + // D E F + // G H I + // perform the Scale2x algorithm (quickly) to get the new quad to represent E + static byte quad[5]; + static byte rowColors[3]; + int code; + + rowColors[0] = d; + rowColors[1] = e; + rowColors[2] = f; + + #define getCode(b,f,h,d) ( (b == f)<<0 | (f == h)<<1 | (h == d)<<2 | (d == b)<<3 ) + + code = getCode(b,f,h,d); + quad[0] = rowColors[filter_roundedRowMap[0*16+code]]; + quad[1] = rowColors[filter_roundedRowMap[1*16+code]]; + quad[2] = rowColors[filter_roundedRowMap[2*16+code]]; + quad[3] = rowColors[filter_roundedRowMap[3*16+code]]; + quad[4] = e; + + return quad; +} diff --git a/common/prboom/r_filter.h b/common/prboom/r_filter.h new file mode 100755 index 0000000..8151eac --- /dev/null +++ b/common/prboom/r_filter.h @@ -0,0 +1,174 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + *-----------------------------------------------------------------------------*/ + +#ifndef R_FILTER_H +#define R_FILTER_H + +#define DITHER_DIM 4 + +extern byte filter_ditherMatrix[DITHER_DIM][DITHER_DIM]; +#define FILTER_UVBITS 6 +#define FILTER_UVDIM (1<> 8), which was empirically +// derived. the "-dcvars.yl" is apparently required to offset some minor +// shaking in coordinate y-axis and prevents dithering seams +#define FILTER_GETV(x,y,texV,nextRowTexV) \ + (filter_getDitheredPixelLevel(x, y, (((texV) - yl) >> 8)&0xff) ? ((nextRowTexV)>>FRACBITS) : ((texV)>>FRACBITS)) + +// Choose current column or next column to the right based on dither of the +// fractional texture U coord +#define filter_getDitheredForColumn(x, y, texV, nextRowTexV) \ + dither_sources[(filter_getDitheredPixelLevel(x, y, filter_fracu))][FILTER_GETV(x,y,texV,nextRowTexV)] + +#define filter_getRoundedForColumn(texV, nextRowTexV) \ + filter_getScale2xQuadColors( \ + source[ ((texV)>>FRACBITS) ], \ + source[ (MAX(0, ((texV)>>FRACBITS)-1)) ], \ + nextsource[ ((texV)>>FRACBITS) ], \ + source[ ((nextRowTexV)>>FRACBITS) ], \ + prevsource[ ((texV)>>FRACBITS) ] \ + ) \ + [ filter_roundedUVMap[ \ + ((filter_fracu>>(8-FILTER_UVBITS))<>8) & 0xff)>>(8-FILTER_UVBITS)) \ + ] ] + +#define filter_getRoundedForSpan(texU, texV) \ + filter_getScale2xQuadColors( \ + source[ (((texU)>>16)&0x3f) | (((texV)>>10)&0xfc0) ], \ + source[ (((texU)>>16)&0x3f) | ((((texV)-FRACUNIT)>>10)&0xfc0) ], \ + source[ ((((texU)+FRACUNIT)>>16)&0x3f) | (((texV)>>10)&0xfc0) ], \ + source[ (((texU)>>16)&0x3f) | ((((texV)+FRACUNIT)>>10)&0xfc0) ], \ + source[ ((((texU)-FRACUNIT)>>16)&0x3f) | (((texV)>>10)&0xfc0) ] \ + ) \ + [ filter_roundedUVMap[ \ + (((((texU)>>8) & 0xff)>>(8-FILTER_UVBITS))<>8) & 0xff)>>(8-FILTER_UVBITS)) \ + ] ] + +byte *filter_getScale2xQuadColors(byte e, byte b, byte f, byte h, byte d); + +// This is the horrendous macro version of the function commented out of +// r_filter.c. It does a bilinear blend on the four source texels for a +// given u and v +#define filter_getFilteredForColumn32(depthmap, texV, nextRowTexV) ( \ + VID_PAL32( depthmap(nextsource[(nextRowTexV)>>FRACBITS]), (filter_fracu*((texV)&0xffff))>>(32-VID_COLORWEIGHTBITS) ) + \ + VID_PAL32( depthmap(source[(nextRowTexV)>>FRACBITS]), ((0xffff-filter_fracu)*((texV)&0xffff))>>(32-VID_COLORWEIGHTBITS) ) + \ + VID_PAL32( depthmap(source[(texV)>>FRACBITS]), ((0xffff-filter_fracu)*(0xffff-((texV)&0xffff)))>>(32-VID_COLORWEIGHTBITS) ) + \ + VID_PAL32( depthmap(nextsource[(texV)>>FRACBITS]), (filter_fracu*(0xffff-((texV)&0xffff)))>>(32-VID_COLORWEIGHTBITS) )) + +// The 16 bit method of the filtering doesn't really maintain enough +// accuracy for discerning viewers, but the alternative requires converting +// from 32 bit, which is slow and requires both the intPalette and the +// shortPalette to be in memory at the same time. +#define filter_getFilteredForColumn16(depthmap, texV, nextRowTexV) ( \ + VID_PAL16( depthmap(nextsource[(nextRowTexV)>>FRACBITS]), (filter_fracu*((texV)&0xffff))>>(32-VID_COLORWEIGHTBITS) ) + \ + VID_PAL16( depthmap(source[(nextRowTexV)>>FRACBITS]), ((0xffff-filter_fracu)*((texV)&0xffff))>>(32-VID_COLORWEIGHTBITS) ) + \ + VID_PAL16( depthmap(source[(texV)>>FRACBITS]), ((0xffff-filter_fracu)*(0xffff-((texV)&0xffff)))>>(32-VID_COLORWEIGHTBITS) ) + \ + VID_PAL16( depthmap(nextsource[(texV)>>FRACBITS]), (filter_fracu*(0xffff-((texV)&0xffff)))>>(32-VID_COLORWEIGHTBITS) )) + +#define filter_getFilteredForColumn15(depthmap, texV, nextRowTexV) ( \ + VID_PAL15( depthmap(nextsource[(nextRowTexV)>>FRACBITS]), (filter_fracu*((texV)&0xffff))>>(32-VID_COLORWEIGHTBITS) ) + \ + VID_PAL15( depthmap(source[(nextRowTexV)>>FRACBITS]), ((0xffff-filter_fracu)*((texV)&0xffff))>>(32-VID_COLORWEIGHTBITS) ) + \ + VID_PAL15( depthmap(source[(texV)>>FRACBITS]), ((0xffff-filter_fracu)*(0xffff-((texV)&0xffff)))>>(32-VID_COLORWEIGHTBITS) ) + \ + VID_PAL15( depthmap(nextsource[(texV)>>FRACBITS]), (filter_fracu*(0xffff-((texV)&0xffff)))>>(32-VID_COLORWEIGHTBITS) )) + +// Same as for column but wrapping at 64 +#define filter_getFilteredForSpan32(depthmap, texU, texV) ( \ + VID_PAL32( depthmap(source[ ((((texU)+FRACUNIT)>>16)&0x3f) | ((((texV)+FRACUNIT)>>10)&0xfc0)]), (unsigned int)(((texU)&0xffff)*((texV)&0xffff))>>(32-VID_COLORWEIGHTBITS)) + \ + VID_PAL32( depthmap(source[ (((texU)>>16)&0x3f) | ((((texV)+FRACUNIT)>>10)&0xfc0)]), (unsigned int)((0xffff-((texU)&0xffff))*((texV)&0xffff))>>(32-VID_COLORWEIGHTBITS)) + \ + VID_PAL32( depthmap(source[ (((texU)>>16)&0x3f) | (((texV)>>10)&0xfc0)]), (unsigned int)((0xffff-((texU)&0xffff))*(0xffff-((texV)&0xffff)))>>(32-VID_COLORWEIGHTBITS)) + \ + VID_PAL32( depthmap(source[ ((((texU)+FRACUNIT)>>16)&0x3f) | (((texV)>>10)&0xfc0)]), (unsigned int)(((texU)&0xffff)*(0xffff-((texV)&0xffff)))>>(32-VID_COLORWEIGHTBITS))) + +// Use 16 bit addition here since it's a little faster and the defects from +// such low-accuracy blending are less visible on spans +#define filter_getFilteredForSpan16(depthmap, texU, texV) ( \ + VID_PAL16( depthmap(source[ ((((texU)+FRACUNIT)>>16)&0x3f) | ((((texV)+FRACUNIT)>>10)&0xfc0)]), (unsigned int)(((texU)&0xffff)*((texV)&0xffff))>>(32-VID_COLORWEIGHTBITS)) + \ + VID_PAL16( depthmap(source[ (((texU)>>16)&0x3f) | ((((texV)+FRACUNIT)>>10)&0xfc0)]), (unsigned int)((0xffff-((texU)&0xffff))*((texV)&0xffff))>>(32-VID_COLORWEIGHTBITS)) + \ + VID_PAL16( depthmap(source[ (((texU)>>16)&0x3f) | (((texV)>>10)&0xfc0)]), (unsigned int)((0xffff-((texU)&0xffff))*(0xffff-((texV)&0xffff)))>>(32-VID_COLORWEIGHTBITS)) + \ + VID_PAL16( depthmap(source[ ((((texU)+FRACUNIT)>>16)&0x3f) | (((texV)>>10)&0xfc0)]), (unsigned int)(((texU)&0xffff)*(0xffff-((texV)&0xffff)))>>(32-VID_COLORWEIGHTBITS))) + +#define filter_getFilteredForSpan15(depthmap, texU, texV) ( \ + VID_PAL15( depthmap(source[ ((((texU)+FRACUNIT)>>16)&0x3f) | ((((texV)+FRACUNIT)>>10)&0xfc0)]), (unsigned int)(((texU)&0xffff)*((texV)&0xffff))>>(32-VID_COLORWEIGHTBITS)) + \ + VID_PAL15( depthmap(source[ (((texU)>>16)&0x3f) | ((((texV)+FRACUNIT)>>10)&0xfc0)]), (unsigned int)((0xffff-((texU)&0xffff))*((texV)&0xffff))>>(32-VID_COLORWEIGHTBITS)) + \ + VID_PAL15( depthmap(source[ (((texU)>>16)&0x3f) | (((texV)>>10)&0xfc0)]), (unsigned int)((0xffff-((texU)&0xffff))*(0xffff-((texV)&0xffff)))>>(32-VID_COLORWEIGHTBITS)) + \ + VID_PAL15( depthmap(source[ ((((texU)+FRACUNIT)>>16)&0x3f) | (((texV)>>10)&0xfc0)]), (unsigned int)(((texU)&0xffff)*(0xffff-((texV)&0xffff)))>>(32-VID_COLORWEIGHTBITS))) + +// do red and blue at once for slight speedup + +#define GETBLENDED15_5050(col1, col2) \ + ((((col1&0x7c1f)+(col2&0x7c1f))>>1)&0x7c1f) | \ + ((((col1&0x03e0)+(col2&0x03e0))>>1)&0x03e0) + +#define GETBLENDED16_5050(col1, col2) \ + ((((col1&0xf81f)+(col2&0xf81f))>>1)&0xf81f) | \ + ((((col1&0x07e0)+(col2&0x07e0))>>1)&0x07e0) + +#define GETBLENDED32_5050(col1, col2) \ + ((((col1&0xff00ff)+(col2&0xff00ff))>>1)&0xff00ff) | \ + ((((col1&0x00ff00)+(col2&0x00ff00))>>1)&0x00ff00) + +#define GETBLENDED15_3268(col1, col2) \ + ((((col1&0x7c1f)*5+(col2&0x7c1f)*11)>>4)&0x7c1f) | \ + ((((col1&0x03e0)*5+(col2&0x03e0)*11)>>4)&0x03e0) + +#define GETBLENDED16_3268(col1, col2) \ + ((((col1&0xf81f)*5+(col2&0xf81f)*11)>>4)&0xf81f) | \ + ((((col1&0x07e0)*5+(col2&0x07e0)*11)>>4)&0x07e0) + +#define GETBLENDED32_3268(col1, col2) \ + ((((col1&0xff00ff)*5+(col2&0xff00ff)*11)>>4)&0xff00ff) | \ + ((((col1&0x00ff00)*5+(col2&0x00ff00)*11)>>4)&0x00ff00) + +#define GETBLENDED15_9406(col1, col2) \ + ((((col1&0x7c1f)*15+(col2&0x7c1f))>>4)&0x7c1f) | \ + ((((col1&0x03e0)*15+(col2&0x03e0))>>4)&0x03e0) + +#define GETBLENDED16_9406(col1, col2) \ + ((((col1&0xf81f)*15+(col2&0xf81f))>>4)&0xf81f) | \ + ((((col1&0x07e0)*15+(col2&0x07e0))>>4)&0x07e0) + +#define GETBLENDED32_9406(col1, col2) \ + ((((col1&0xff00ff)*15+(col2&0xff00ff))>>4)&0xff00ff) | \ + ((((col1&0x00ff00)*15+(col2&0x00ff00))>>4)&0x00ff00) + +#endif diff --git a/common/prboom/r_fps.c b/common/prboom/r_fps.c new file mode 100755 index 0000000..09b7bc0 --- /dev/null +++ b/common/prboom/r_fps.c @@ -0,0 +1,450 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze, Andrey Budko + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Uncapped framerate stuff + * + *--------------------------------------------------------------------- + */ + +#include "doomstat.h" +#include "r_defs.h" +#include "r_state.h" +#include "p_spec.h" +#include "r_demo.h" +#include "r_fps.h" + +int movement_smooth = false; + +typedef enum +{ + INTERP_SectorFloor, + INTERP_SectorCeiling, + INTERP_Vertex, + INTERP_WallPanning, + INTERP_FloorPanning, + INTERP_CeilingPanning +} interpolation_type_e; + +typedef struct +{ + interpolation_type_e type; + void *address; +} interpolation_t; + +static int numinterpolations = 0; + +tic_vars_t tic_vars; + +view_vars_t original_view_vars; + +extern int realtic_clock_rate; +void D_Display(void); + +void R_InitInterpolation(void) +{ + tic_vars.msec = realtic_clock_rate * TICRATE / 100000.0f; +} + +typedef fixed_t fixed2_t[2]; +static fixed2_t *oldipos; +static fixed2_t *bakipos; +static interpolation_t *curipos; + +static boolean NoInterpolateView; +static boolean didInterp; +boolean WasRenderedInTryRunTics; + +void R_InterpolateView (player_t *player, fixed_t frac) +{ + if (movement_smooth) + { + if (NoInterpolateView) + { + NoInterpolateView = false; + original_view_vars.viewx = player->mo->x; + original_view_vars.viewy = player->mo->y; + original_view_vars.viewz = player->viewz; + + original_view_vars.viewangle = player->mo->angle + viewangleoffset; + } + + viewx = original_view_vars.viewx + FixedMul (frac, player->mo->x - original_view_vars.viewx); + viewy = original_view_vars.viewy + FixedMul (frac, player->mo->y - original_view_vars.viewy); + viewz = original_view_vars.viewz + FixedMul (frac, player->viewz - original_view_vars.viewz); + + viewangle = original_view_vars.viewangle + FixedMul (frac, R_SmoothPlaying_Get(player->mo->angle) + viewangleoffset - original_view_vars.viewangle); + } + else + { + viewx = player->mo->x; + viewy = player->mo->y; + viewz = player->viewz; + viewangle = R_SmoothPlaying_Get(player->mo->angle); + } +} + +void R_ResetViewInterpolation () +{ + NoInterpolateView = true; +} + +static void R_CopyInterpToOld (int i) +{ + switch (curipos[i].type) + { + case INTERP_SectorFloor: + oldipos[i][0] = ((sector_t*)curipos[i].address)->floorheight; + break; + case INTERP_SectorCeiling: + oldipos[i][0] = ((sector_t*)curipos[i].address)->ceilingheight; + break; + case INTERP_Vertex: + oldipos[i][0] = ((vertex_t*)curipos[i].address)->x; + oldipos[i][1] = ((vertex_t*)curipos[i].address)->y; + break; + case INTERP_WallPanning: + oldipos[i][0] = ((side_t*)curipos[i].address)->rowoffset; + oldipos[i][1] = ((side_t*)curipos[i].address)->textureoffset; + break; + case INTERP_FloorPanning: + oldipos[i][0] = ((sector_t*)curipos[i].address)->floor_xoffs; + oldipos[i][1] = ((sector_t*)curipos[i].address)->floor_yoffs; + break; + case INTERP_CeilingPanning: + oldipos[i][0] = ((sector_t*)curipos[i].address)->ceiling_xoffs; + oldipos[i][1] = ((sector_t*)curipos[i].address)->ceiling_yoffs; + break; + } +} + +static void R_CopyBakToInterp (int i) +{ + switch (curipos[i].type) + { + case INTERP_SectorFloor: + ((sector_t*)curipos[i].address)->floorheight = bakipos[i][0]; + break; + case INTERP_SectorCeiling: + ((sector_t*)curipos[i].address)->ceilingheight = bakipos[i][0]; + break; + case INTERP_Vertex: + ((vertex_t*)curipos[i].address)->x = bakipos[i][0]; + ((vertex_t*)curipos[i].address)->y = bakipos[i][1]; + break; + case INTERP_WallPanning: + ((side_t*)curipos[i].address)->rowoffset = bakipos[i][0]; + ((side_t*)curipos[i].address)->textureoffset = bakipos[i][1]; + break; + case INTERP_FloorPanning: + ((sector_t*)curipos[i].address)->floor_xoffs = bakipos[i][0]; + ((sector_t*)curipos[i].address)->floor_yoffs = bakipos[i][1]; + break; + case INTERP_CeilingPanning: + ((sector_t*)curipos[i].address)->ceiling_xoffs = bakipos[i][0]; + ((sector_t*)curipos[i].address)->ceiling_yoffs = bakipos[i][1]; + break; + } +} + +static void R_DoAnInterpolation (int i, fixed_t smoothratio) +{ + fixed_t pos; + fixed_t *adr1 = NULL; + fixed_t *adr2 = NULL; + + switch (curipos[i].type) + { + case INTERP_SectorFloor: + adr1 = &((sector_t*)curipos[i].address)->floorheight; + break; + case INTERP_SectorCeiling: + adr1 = &((sector_t*)curipos[i].address)->ceilingheight; + break; + case INTERP_Vertex: + adr1 = &((vertex_t*)curipos[i].address)->x; +//// adr2 = &((vertex_t*)curipos[i].Address)->y; + break; + case INTERP_WallPanning: + adr1 = &((side_t*)curipos[i].address)->rowoffset; + adr2 = &((side_t*)curipos[i].address)->textureoffset; + break; + case INTERP_FloorPanning: + adr1 = &((sector_t*)curipos[i].address)->floor_xoffs; + adr2 = &((sector_t*)curipos[i].address)->floor_yoffs; + break; + case INTERP_CeilingPanning: + adr1 = &((sector_t*)curipos[i].address)->ceiling_xoffs; + adr2 = &((sector_t*)curipos[i].address)->ceiling_yoffs; + break; + + default: + return; + } + + if (adr1) + { + pos = bakipos[i][0] = *adr1; + *adr1 = oldipos[i][0] + FixedMul (pos - oldipos[i][0], smoothratio); + } + + if (adr2) + { + pos = bakipos[i][1] = *adr2; + *adr2 = oldipos[i][1] + FixedMul (pos - oldipos[i][1], smoothratio); + } +} + +void R_UpdateInterpolations() +{ + int i; + if (!movement_smooth) + return; + for (i = numinterpolations-1; i >= 0; --i) + R_CopyInterpToOld (i); +} + +int interpolations_max = 0; + +static void R_SetInterpolation(interpolation_type_e type, void *posptr) +{ + int i; + if (!movement_smooth) + return; + + if (numinterpolations >= interpolations_max) { + interpolations_max = interpolations_max ? interpolations_max * 2 : 256; + + oldipos = (fixed2_t*)realloc(oldipos, sizeof(*oldipos) * interpolations_max); + bakipos = (fixed2_t*)realloc(bakipos, sizeof(*bakipos) * interpolations_max); + curipos = (interpolation_t*)realloc(curipos, sizeof(*curipos) * interpolations_max); + } + + for(i = numinterpolations-1; i >= 0; i--) + if (curipos[i].address == posptr && curipos[i].type == type) + return; + + curipos[numinterpolations].address = posptr; + curipos[numinterpolations].type = type; + R_CopyInterpToOld (numinterpolations); + numinterpolations++; +} + +static void R_StopInterpolation(interpolation_type_e type, void *posptr) +{ + int i; + + if (!movement_smooth) + return; + + for(i=numinterpolations-1; i>= 0; --i) + { + if (curipos[i].address == posptr && curipos[i].type == type) + { + numinterpolations--; + oldipos[i][0] = oldipos[numinterpolations][0]; + oldipos[i][1] = oldipos[numinterpolations][1]; + bakipos[i][0] = bakipos[numinterpolations][0]; + bakipos[i][1] = bakipos[numinterpolations][1]; + curipos[i] = curipos[numinterpolations]; + break; + } + } +} + +void R_StopAllInterpolations(void) +{ + int i; + + if (!movement_smooth) + return; + + for(i=numinterpolations-1; i>= 0; --i) + { + numinterpolations--; + oldipos[i][0] = oldipos[numinterpolations][0]; + oldipos[i][1] = oldipos[numinterpolations][1]; + bakipos[i][0] = bakipos[numinterpolations][0]; + bakipos[i][1] = bakipos[numinterpolations][1]; + curipos[i] = curipos[numinterpolations]; + } +} + +void R_DoInterpolations(fixed_t smoothratio) +{ + int i; + if (!movement_smooth) + return; + + if (smoothratio == FRACUNIT) + { + didInterp = false; + return; + } + + didInterp = true; + + for (i = numinterpolations-1; i >= 0; --i) + { + R_DoAnInterpolation (i, smoothratio); + } +} + +void R_RestoreInterpolations() +{ + int i; + + if (!movement_smooth) + return; + + if (didInterp) + { + didInterp = false; + for (i = numinterpolations-1; i >= 0; --i) + { + R_CopyBakToInterp (i); + } + } +} + +void R_ActivateSectorInterpolations() +{ + int i; + sector_t *sec; + + if (!movement_smooth) + return; + + for (i=0, sec = sectors ; ifloordata) + R_SetInterpolation (INTERP_SectorFloor, sec); + if (sec->ceilingdata) + R_SetInterpolation (INTERP_SectorCeiling, sec); + } +} + +static void R_InterpolationGetData(thinker_t *th, + interpolation_type_e *type1, interpolation_type_e *type2, + void **posptr1, void **posptr2) +{ + *posptr1 = NULL; + *posptr2 = NULL; + + if (th->function == T_MoveFloor) + { + *type1 = INTERP_SectorFloor; + *posptr1 = ((floormove_t *)th)->sector; + } + else + if (th->function == T_PlatRaise) + { + *type1 = INTERP_SectorFloor; + *posptr1 = ((plat_t *)th)->sector; + } + else + if (th->function == T_MoveCeiling) + { + *type1 = INTERP_SectorCeiling; + *posptr1 = ((ceiling_t *)th)->sector; + } + else + if (th->function == T_VerticalDoor) + { + *type1 = INTERP_SectorCeiling; + *posptr1 = ((vldoor_t *)th)->sector; + } + else + if (th->function == T_MoveElevator) + { + *type1 = INTERP_SectorFloor; + *posptr1 = ((elevator_t *)th)->sector; + *type2 = INTERP_SectorCeiling; + *posptr2 = ((elevator_t *)th)->sector; + } + else + if (th->function == T_Scroll) + { + switch (((scroll_t *)th)->type) + { + case sc_side: + *type1 = INTERP_WallPanning; + *posptr1 = sides + ((scroll_t *)th)->affectee; + break; + case sc_floor: + *type1 = INTERP_FloorPanning; + *posptr1 = sectors + ((scroll_t *)th)->affectee; + break; + case sc_ceiling: + *type1 = INTERP_CeilingPanning; + *posptr1 = sectors + ((scroll_t *)th)->affectee; + break; + default: ; + } + } +} + +void R_ActivateThinkerInterpolations(thinker_t *th) +{ + void *posptr1; + void *posptr2; + interpolation_type_e type1, type2; + + if (!movement_smooth) + return; + + R_InterpolationGetData(th, &type1, &type2, &posptr1, &posptr2); + + if(posptr1) + { + R_SetInterpolation (type1, posptr1); + + if(posptr2) + R_SetInterpolation (type2, posptr2); + } +} + +void R_StopInterpolationIfNeeded(thinker_t *th) +{ + void *posptr1; + void *posptr2; + interpolation_type_e type1, type2; + + if (!movement_smooth) + return; + + R_InterpolationGetData(th, &type1, &type2, &posptr1, &posptr2); + + if(posptr1) + { + R_StopInterpolation (type1, posptr1); + if(posptr2) + R_StopInterpolation (type2, posptr2); + } +} + diff --git a/common/prboom/r_fps.h b/common/prboom/r_fps.h new file mode 100755 index 0000000..bfbeab0 --- /dev/null +++ b/common/prboom/r_fps.h @@ -0,0 +1,76 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze, Andrey Budko + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Uncapped framerate stuff + * + *--------------------------------------------------------------------- + */ + +#ifndef __R_FPS__ +#define __R_FPS__ + +#include "doomstat.h" + +extern int movement_smooth; + +typedef struct { + fixed_t viewx; + fixed_t viewy; + fixed_t viewz; + angle_t viewangle; + angle_t viewpitch; +} view_vars_t; + +extern view_vars_t original_view_vars; + +typedef struct { + unsigned int start; + unsigned int next; + unsigned int step; + fixed_t frac; + float msec; +} tic_vars_t; + +extern tic_vars_t tic_vars; + +void R_InitInterpolation(void); +void R_InterpolateView (player_t *player, fixed_t frac); + +extern boolean WasRenderedInTryRunTics; + +void R_ResetViewInterpolation (); +void R_UpdateInterpolations(); +void R_StopAllInterpolations(void); +void R_DoInterpolations(fixed_t smoothratio); +void R_RestoreInterpolations(); +void R_ActivateSectorInterpolations(); +void R_ActivateThinkerInterpolations(thinker_t *th); +void R_StopInterpolationIfNeeded(thinker_t *th); + +#endif diff --git a/common/prboom/r_main.c b/common/prboom/r_main.c new file mode 100755 index 0000000..ac1079b --- /dev/null +++ b/common/prboom/r_main.c @@ -0,0 +1,614 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Rendering main loop and setup functions, + * utility functions (BSP, geometry, trigonometry). + * See tables.c, too. + * + *-----------------------------------------------------------------------------*/ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef USE_SDL +#include "SDL.h" +#endif +#include "doomstat.h" +#include "d_net.h" +#include "w_wad.h" +#include "r_main.h" +#include "r_things.h" +#include "r_plane.h" +#include "r_bsp.h" +#include "r_draw.h" +#include "m_bbox.h" +#include "r_sky.h" +#include "v_video.h" +#include "lprintf.h" +#include "st_stuff.h" +#include "i_main.h" +#include "i_system.h" +#include "g_game.h" +#include "r_demo.h" +#include "r_fps.h" + +// Fineangles in the SCREENWIDTH wide window. +#define FIELDOFVIEW 2048 + +// killough: viewangleoffset is a legacy from the pre-v1.2 days, when Doom +// had Left/Mid/Right viewing. +/-ANG90 offsets were placed here on each +// node, by d_net.c, to set up a L/M/R session. + +int viewangleoffset; +int validcount = 1; // increment every time a check is made +const lighttable_t *fixedcolormap; +int centerx, centery; +fixed_t centerxfrac, centeryfrac; +fixed_t viewheightfrac; //e6y: for correct clipping of things +fixed_t projection; +// proff 11/06/98: Added for high-res +fixed_t projectiony; +fixed_t viewx, viewy, viewz; +angle_t viewangle; +fixed_t viewcos, viewsin; +player_t *viewplayer; +extern lighttable_t **walllights; + +static mobj_t *oviewer; + +// +// precalculated math tables +// + +angle_t clipangle; + +// The viewangletox[viewangle + FINEANGLES/4] lookup +// maps the visible view angles to screen X coordinates, +// flattening the arc to a flat projection plane. +// There will be many angles mapped to the same X. + +int viewangletox[FINEANGLES/2]; + +// The xtoviewangleangle[] table maps a screen pixel +// to the lowest viewangle that maps back to x ranges +// from clipangle to -clipangle. + +angle_t xtoviewangle[MAX_SCREENWIDTH+1]; // killough 2/8/98 + +// killough 3/20/98: Support dynamic colormaps, e.g. deep water +// killough 4/4/98: support dynamic number of them as well + +int numcolormaps; +const lighttable_t *(*c_zlight)[LIGHTLEVELS][MAXLIGHTZ]; +const lighttable_t *(*zlight)[MAXLIGHTZ]; +const lighttable_t *fullcolormap; +const lighttable_t **colormaps; + +// killough 3/20/98, 4/4/98: end dynamic colormaps + +int extralight; // bumped light from gun blasts + +// +// R_PointOnSide +// Traverse BSP (sub) tree, +// check point against partition plane. +// Returns side 0 (front) or 1 (back). +// +// killough 5/2/98: reformatted +// + +PUREFUNC int R_PointOnSide(fixed_t x, fixed_t y, const node_t *node) +{ + if (!node->dx) + return x <= node->x ? node->dy > 0 : node->dy < 0; + + if (!node->dy) + return y <= node->y ? node->dx < 0 : node->dx > 0; + + x -= node->x; + y -= node->y; + + // Try to quickly decide by looking at sign bits. + if ((node->dy ^ node->dx ^ x ^ y) < 0) + return (node->dy ^ x) < 0; // (left is negative) + return FixedMul(y, node->dx>>FRACBITS) >= FixedMul(node->dy>>FRACBITS, x); +} + +// killough 5/2/98: reformatted + +PUREFUNC int R_PointOnSegSide(fixed_t x, fixed_t y, const seg_t *line) +{ + fixed_t lx = line->v1->x; + fixed_t ly = line->v1->y; + fixed_t ldx = line->v2->x - lx; + fixed_t ldy = line->v2->y - ly; + + if (!ldx) + return x <= lx ? ldy > 0 : ldy < 0; + + if (!ldy) + return y <= ly ? ldx < 0 : ldx > 0; + + x -= lx; + y -= ly; + + // Try to quickly decide by looking at sign bits. + if ((ldy ^ ldx ^ x ^ y) < 0) + return (ldy ^ x) < 0; // (left is negative) + return FixedMul(y, ldx>>FRACBITS) >= FixedMul(ldy>>FRACBITS, x); +} + +// +// R_PointToAngle +// To get a global angle from cartesian coordinates, +// the coordinates are flipped until they are in +// the first octant of the coordinate system, then +// the y (<=x) is scaled and divided by x to get a +// tangent (slope) value which is looked up in the +// tantoangle[] table. The +1 size of tantoangle[] +// is to handle the case when x==y without additional +// checking. +// +// killough 5/2/98: reformatted, cleaned up + +#include + +angle_t R_PointToAngle(fixed_t x, fixed_t y) +{ +#if 0 + // JDC: the oldresult case only hit 10%, making it a net loss. + // JDC: added parenthesis to force constant evaluation + return (int)(atan2(y-viewy, x-viewx) * (ANG180/M_PI) ); +#else + static fixed_t oldx, oldy; + static angle_t oldresult; + + x -= viewx; y -= viewy; + + if ( /* !render_precise && */ + // e6y: here is where "slime trails" can SOMETIMES occur +#ifdef GL_DOOM + (V_GetMode() != VID_MODEGL) && +#endif + (x < INT_MAX/4 && x > -INT_MAX/4 && y < INT_MAX/4 && y > -INT_MAX/4) + ) + { + // old R_PointToAngle + return (x || y) ? + x >= 0 ? + y >= 0 ? + (x > y) ? tantoangle[SlopeDiv(y,x)] : // octant 0 + ANG90-1-tantoangle[SlopeDiv(x,y)] : // octant 1 + x > (y = -y) ? 0-tantoangle[SlopeDiv(y,x)] : // octant 8 + ANG270+tantoangle[SlopeDiv(x,y)] : // octant 7 + y >= 0 ? (x = -x) > y ? ANG180-1-tantoangle[SlopeDiv(y,x)] : // octant 3 + ANG90 + tantoangle[SlopeDiv(x,y)] : // octant 2 + (x = -x) > (y = -y) ? ANG180+tantoangle[ SlopeDiv(y,x)] : // octant 4 + ANG270-1-tantoangle[SlopeDiv(x,y)] : // octant 5 + 0; + } + + // R_PointToAngleEx merged into R_PointToAngle + // e6y: The precision of the code above is abysmal so use the CRT atan2 function instead! + if (oldx != x || oldy != y) + { + oldx = x; + oldy = y; + oldresult = (int)(atan2(y, x) * ANG180/M_PI ); + } + return oldresult; +#endif +} + +angle_t R_PointToAngle2(fixed_t viewxpos, fixed_t viewypos, fixed_t x, fixed_t y) +{ + return (y -= viewypos, (x -= viewxpos) || y) ? + x >= 0 ? + y >= 0 ? + (x > y) ? tantoangle[SlopeDiv(y,x)] : // octant 0 + ANG90-1-tantoangle[SlopeDiv(x,y)] : // octant 1 + x > (y = -y) ? 0-tantoangle[SlopeDiv(y,x)] : // octant 8 + ANG270+tantoangle[SlopeDiv(x,y)] : // octant 7 + y >= 0 ? (x = -x) > y ? ANG180-1-tantoangle[SlopeDiv(y,x)] : // octant 3 + ANG90 + tantoangle[SlopeDiv(x,y)] : // octant 2 + (x = -x) > (y = -y) ? ANG180+tantoangle[ SlopeDiv(y,x)] : // octant 4 + ANG270-1-tantoangle[SlopeDiv(x,y)] : // octant 5 + 0; +} + +// +// R_InitTextureMapping +// +// killough 5/2/98: reformatted + +static void R_InitTextureMapping (void) +{ + register int i,x; + fixed_t focallength; + + // Use tangent table to generate viewangletox: + // viewangletox will give the next greatest x + // after the view angle. + // + // Calc focallength + // so FIELDOFVIEW angles covers SCREENWIDTH. + + focallength = FixedDiv(centerxfrac, finetangent[FINEANGLES/4+FIELDOFVIEW/2]); + + for (i=0 ; i FRACUNIT*2) + t = -1; + else + if (finetangent[i] < -FRACUNIT*2) + t = viewwidth+1; + else + { + t = FixedMul(finetangent[i], focallength); + t = (centerxfrac - t + FRACUNIT-1) >> FRACBITS; + if (t < -1) + t = -1; + else + if (t > viewwidth+1) + t = viewwidth+1; + } + viewangletox[i] = t; + } + + // Scan viewangletox[] to generate xtoviewangle[]: + // xtoviewangle will give the smallest view angle + // that maps to x. + + for (x=0; x<=viewwidth; x++) + { + for (i=0; viewangletox[i] > x; i++) + ; + xtoviewangle[x] = (i<>= LIGHTSCALESHIFT)/DISTMAP; + + if (level < 0) + level = 0; + else + if (level >= NUMCOLORMAPS) + level = NUMCOLORMAPS-1; + + // killough 3/20/98: Initialize multiple colormaps + level *= 256; + for (t=0; t>ANGLETOFINESHIFT]); + distscale[i] = FixedDiv(FRACUNIT,cosadj); + } + +} + +// +// R_Init +// + +extern int screenblocks; + +void R_Init (void) +{ + // CPhipps - R_DrawColumn isn't constant anymore, so must + // initialise in code + // current column draw function + lprintf(LO_INFO, "\nR_LoadTrigTables: "); + R_LoadTrigTables(); + lprintf(LO_INFO, "\nR_InitData: "); + R_InitData(); + R_SetViewSize(screenblocks); + lprintf(LO_INFO, "\nR_Init: R_InitPlanes "); + R_InitPlanes(); + lprintf(LO_INFO, "R_InitLightTables "); + R_InitLightTables(); + lprintf(LO_INFO, "R_InitSkyMap "); + R_InitSkyMap(); + lprintf(LO_INFO, "R_InitTranslationsTables "); + R_InitTranslationTables(); + lprintf(LO_INFO, "R_InitPatches "); + R_InitPatches(); +} + +// +// R_PointInSubsector +// +// killough 5/2/98: reformatted, cleaned up + +subsector_t *R_PointInSubsector(fixed_t x, fixed_t y) +{ + int nodenum = numnodes-1; + + // special case for trivial maps (single subsector, no nodes) + if (numnodes == 0) + return subsectors; + + while (!(nodenum & NF_SUBSECTOR)) + nodenum = nodes[nodenum].children[R_PointOnSide(x, y, nodes+nodenum)]; + return &subsectors[nodenum & ~NF_SUBSECTOR]; +} + +// +// R_SetupFrame +// + +static void R_SetupFrame (player_t *player) +{ + int cm; + boolean NoInterpolate = paused || (menuactive && !demoplayback); + + viewplayer = player; + + if (player->mo != oviewer || NoInterpolate) + { + R_ResetViewInterpolation (); + oviewer = player->mo; + } + tic_vars.frac = I_GetTimeFrac (); + if (NoInterpolate) + tic_vars.frac = FRACUNIT; + R_InterpolateView (player, tic_vars.frac); + + extralight = player->extralight; + + viewsin = finesine[viewangle>>ANGLETOFINESHIFT]; + viewcos = finecosine[viewangle>>ANGLETOFINESHIFT]; + + R_DoInterpolations(tic_vars.frac); + + // killough 3/20/98, 4/4/98: select colormap based on player status + + if (player->mo->subsector->sector->heightsec != -1) + { + const sector_t *s = player->mo->subsector->sector->heightsec + sectors; + cm = viewz < s->floorheight ? s->bottommap : viewz > s->ceilingheight ? + s->topmap : s->midmap; + if (cm < 0 || cm > numcolormaps) + cm = 0; + } + else + cm = 0; + + fullcolormap = colormaps[cm]; + zlight = c_zlight[cm]; + + if (player->fixedcolormap) + { + fixedcolormap = fullcolormap // killough 3/20/98: use fullcolormap + + player->fixedcolormap*256*sizeof(lighttable_t); + } + else + fixedcolormap = 0; + + validcount++; +} + +int autodetect_hom = 0; // killough 2/7/98: HOM autodetection flag + +// +// R_ShowStats +// +int rendered_visplanes, rendered_segs, rendered_vissprites; +boolean rendering_stats; + +static void R_ShowStats(void) +{ +//e6y +#if USE_SDL + static unsigned int FPS_SavedTick = 0, FPS_FrameCount = 0; + unsigned int tick = SDL_GetTicks(); + FPS_FrameCount++; + if(tick >= FPS_SavedTick + 1000) + { + doom_printf((V_GetMode() == VID_MODEGL) + ?"Frame rate %d fps\nWalls %d, Flats %d, Sprites %d" + :"Frame rate %d fps\nSegs %d, Visplanes %d, Sprites %d", + 1000 * FPS_FrameCount / (tick - FPS_SavedTick), rendered_segs, + rendered_visplanes, rendered_vissprites); + FPS_SavedTick = tick; + FPS_FrameCount = 0; + } +#else + +#define KEEPTIMES 10 + static int keeptime[KEEPTIMES], showtime; + int now = I_GetTime(); + + if (now - showtime > 35) { + doom_printf((V_GetMode() == VID_MODEGL) + ?"Frame rate %d fps\nWalls %d, Flats %d, Sprites %d" + :"Frame rate %d fps\nSegs %d, Visplanes %d, Sprites %d", + (35*KEEPTIMES)/(now - keeptime[0]), rendered_segs, + rendered_visplanes, rendered_vissprites); + showtime = now; + } + memmove(keeptime, keeptime+1, sizeof(keeptime[0]) * (KEEPTIMES-1)); + keeptime[KEEPTIMES-1] = now; + +#endif //e6y +} + +// +// R_RenderView +// +void R_RenderPlayerView (player_t* player) +{ + R_SetupFrame (player); + + // Clear buffers. + R_ClearClipSegs (); + R_ClearDrawSegs (); + R_ClearPlanes (); + R_ClearSprites (); + + rendered_segs = rendered_visplanes = 0; + + // proff 11/99: clear buffers + gld_InitDrawScene(); + // proff 11/99: switch to perspective mode + gld_StartDrawScene(); + + // The head node is the last node output. + R_RenderBSPNode (numnodes-1); + R_ResetColumnBuffer(); + + // proff 11/99: draw the scene + gld_DrawScene(player); + + // proff 11/99: finishing off + gld_EndDrawScene(); + + + if (rendering_stats) R_ShowStats(); + + R_RestoreInterpolations(); +} diff --git a/common/prboom/r_main.h b/common/prboom/r_main.h new file mode 100755 index 0000000..988237b --- /dev/null +++ b/common/prboom/r_main.h @@ -0,0 +1,120 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Renderer main interface. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __R_MAIN__ +#define __R_MAIN__ + +#include "d_player.h" +#include "r_data.h" + + +// +// POV related. +// +extern int displaywidth; +extern int displayheight; +extern fixed_t viewcos; +extern fixed_t viewsin; +extern int viewwidth; +extern int viewheight; +extern int viewwindowx; +extern int viewwindowy; +extern int centerx; +extern int centery; +extern fixed_t centerxfrac; +extern fixed_t centeryfrac; +extern fixed_t viewheightfrac; //e6y: for correct clipping of things +extern fixed_t projection; +// proff 11/06/98: Added for high-res +extern fixed_t projectiony; +extern int validcount; + +// +// Rendering stats +// + +extern int rendered_visplanes, rendered_segs, rendered_vissprites; +extern boolean rendering_stats; + +// +// Lighting LUT. +// Used for z-depth cuing per column/row, +// and other lighting effects (sector ambient, flash). +// + +// Lighting constants. + +#define LIGHTLEVELS 16 +#define LIGHTSEGSHIFT 4 +#define MAXLIGHTSCALE 48 +#define LIGHTSCALESHIFT 12 +#define MAXLIGHTZ 128 +#define LIGHTZSHIFT 20 + +// killough 3/20/98: Allow colormaps to be dynamic (e.g. underwater) +extern const lighttable_t *(*zlight)[MAXLIGHTZ]; +extern const lighttable_t *fullcolormap; +extern int numcolormaps; // killough 4/4/98: dynamic number of maps +extern const lighttable_t **colormaps; +// killough 3/20/98, 4/4/98: end dynamic colormaps + +extern int extralight; +extern const lighttable_t *fixedcolormap; + +// Number of diminishing brightness levels. +// There a 0-31, i.e. 32 LUT in the COLORMAP lump. + +#define NUMCOLORMAPS 32 + +// +// Utility functions. +// + +PUREFUNC int R_PointOnSide(fixed_t x, fixed_t y, const node_t *node); +PUREFUNC int R_PointOnSegSide(fixed_t x, fixed_t y, const seg_t *line); +angle_t R_PointToAngle(fixed_t x, fixed_t y); +angle_t R_PointToAngle2(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2); +subsector_t *R_PointInSubsector(fixed_t x, fixed_t y); + +// +// REFRESH - the actual rendering functions. +// + +extern int testNewRenderer; // JDC +void IR_RenderPlayerView (player_t* player); // JDC: new version +void R_RenderPlayerView(player_t *player); // Called by G_Drawer. +void R_Init(void); // Called by startup code. +void R_SetViewSize(int blocks); // Called by M_Responder. +void R_ExecuteSetViewSize(void); // cph - called by D_Display to complete a view resize + +#endif diff --git a/common/prboom/r_patch.c b/common/prboom/r_patch.c new file mode 100755 index 0000000..165f948 --- /dev/null +++ b/common/prboom/r_patch.c @@ -0,0 +1,788 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2002 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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 "z_zone.h" +#include "doomstat.h" +#include "w_wad.h" +#include "r_main.h" +#include "r_sky.h" +#include "r_bsp.h" +#include "r_things.h" +#include "p_tick.h" +#include "i_system.h" +#include "r_draw.h" +#include "lprintf.h" +#include "r_patch.h" +#include + +// posts are runs of non masked source pixels +typedef struct +{ + byte topdelta; // -1 is the last post in a column + byte length; // length data bytes follows +} post_t; + +// column_t is a list of 0 or more post_t, (byte)-1 terminated +typedef post_t column_t; + +// +// Patches. +// A patch holds one or more columns. +// Patches are used for sprites and all masked pictures, +// and we compose textures from the TEXTURE1/2 lists +// of patches. +// + +typedef struct +{ + short width, height; // bounding box size + short leftoffset; // pixels to the left of origin + short topoffset; // pixels below the origin + int columnofs[8]; // only [width] used +} patch_t; + +//--------------------------------------------------------------------------- +// Re-engineered patch support +//--------------------------------------------------------------------------- +static rpatch_t *patches = 0; + +static rpatch_t *texture_composites = 0; + +//--------------------------------------------------------------------------- +void R_InitPatches(void) { + if (!patches) + { + patches = (rpatch_t*)malloc(numlumps * sizeof(rpatch_t)); + // clear out new patches to signal they're uninitialized + memset(patches, 0, sizeof(rpatch_t)*numlumps); + } else { + memset(patches, 0, sizeof(rpatch_t)*numlumps); + } + if (!texture_composites) + { + texture_composites = (rpatch_t*)malloc(numtextures * sizeof(rpatch_t)); + // clear out new patches to signal they're uninitialized + memset(texture_composites, 0, sizeof(rpatch_t)*numtextures); + } +} + +//--------------------------------------------------------------------------- +void R_FlushAllPatches(void) { + int i; + + if (patches) + { + for (i=0; i < numlumps; i++) + if (patches[i].locks > 0) + I_Error("R_FlushAllPatches: patch number %i still locked",i); + free(patches); + patches = NULL; + } + if (texture_composites) + { + for (i=0; iwidth; + R_UnlockPatchNum(lump); + return width; +} + +//--------------------------------------------------------------------------- +int R_NumPatchHeight(int lump) +{ + const rpatch_t *patch = R_CachePatchNum(lump); + int height = patch->height; + R_UnlockPatchNum(lump); + return height; +} + +//--------------------------------------------------------------------------- +static int getPatchIsNotTileable(const patch_t *patch) { + int x=0, numPosts, lastColumnDelta = 0; + const column_t *column; + int cornerCount = 0; + int hasAHole = 0; + + for (x=0; xwidth); x++) { + column = (const column_t *)((const byte *)patch + LONG(patch->columnofs[x])); + if (!x) lastColumnDelta = column->topdelta; + else if (lastColumnDelta != column->topdelta) hasAHole = 1; + + numPosts = 0; + while (column->topdelta != 0xff) { + // check to see if a corner pixel filled + if (x == 0 && column->topdelta == 0) cornerCount++; + else if (x == 0 && column->topdelta + column->length >= SHORT(patch->height)) cornerCount++; + else if (x == SHORT(patch->width)-1 && column->topdelta == 0) cornerCount++; + else if (x == SHORT(patch->width)-1 && column->topdelta + column->length >= SHORT(patch->height)) cornerCount++; + + if (numPosts++) hasAHole = 1; + column = (const column_t *)((const byte *)column + column->length + 4); + } + } + + if (cornerCount == 4) return 0; + return hasAHole; +} + +//--------------------------------------------------------------------------- +static int getIsSolidAtSpot(const column_t *column, int spot) { + if (!column) return 0; + while (column->topdelta != 0xff) { + if (spot < column->topdelta) return 0; + if ((spot >= column->topdelta) && (spot <= column->topdelta + column->length)) return 1; + column = (const column_t*)((const byte*)column + 3 + column->length + 1); + } + return 0; +} + +//--------------------------------------------------------------------------- +// Used to determine whether a column edge (top or bottom) should slope +// up or down for smoothed masked edges - POPE +//--------------------------------------------------------------------------- +static int getColumnEdgeSlope(const column_t *prevcolumn, const column_t *nextcolumn, int spot) { + int holeToLeft = !getIsSolidAtSpot(prevcolumn, spot); + int holeToRight = !getIsSolidAtSpot(nextcolumn, spot); + + if (holeToLeft && !holeToRight) return 1; + if (!holeToLeft && holeToRight) return -1; + return 0; +} + +//--------------------------------------------------------------------------- +static void createPatch(int id) { + rpatch_t *patch; + const int patchNum = id; + const patch_t *oldPatch = (const patch_t*)W_CacheLumpNum(patchNum); + const column_t *oldColumn, *oldPrevColumn, *oldNextColumn; + int x, y; + int pixelDataSize; + int columnsDataSize; + int postsDataSize; + int dataSize; + int *numPostsInColumn; + int numPostsTotal; + const unsigned char *oldColumnPixelData; + int numPostsUsedSoFar; + int edgeSlope; + +#ifdef RANGECHECK + if (id >= numlumps) + I_Error("createPatch: %i >= numlumps", id); +#endif + + patch = &patches[id]; + // proff - 2003-02-16 What about endianess? + patch->width = SHORT(oldPatch->width); + patch->widthmask = 0; + patch->height = SHORT(oldPatch->height); + patch->leftoffset = SHORT(oldPatch->leftoffset); + patch->topoffset = SHORT(oldPatch->topoffset); + patch->isNotTileable = getPatchIsNotTileable(oldPatch); + + // work out how much memory we need to allocate for this patch's data + pixelDataSize = (patch->width * patch->height + 4) & ~3; + columnsDataSize = sizeof(rcolumn_t) * patch->width; + + // count the number of posts in each column + numPostsInColumn = (int*)malloc(sizeof(int) * patch->width); + numPostsTotal = 0; + + for (x=0; xwidth; x++) { + oldColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[x])); + numPostsInColumn[x] = 0; + while (oldColumn->topdelta != 0xff) { + numPostsInColumn[x]++; + numPostsTotal++; + oldColumn = (const column_t *)((const byte *)oldColumn + oldColumn->length + 4); + } + } + + postsDataSize = numPostsTotal * sizeof(rpost_t); + + // allocate our data chunk + dataSize = pixelDataSize + columnsDataSize + postsDataSize; + patch->data = (unsigned char*)Z_Malloc(dataSize, PU_CACHE, (void **)&patch->data); + memset(patch->data, 0, dataSize); + + // set out pixel, column, and post pointers into our data array + patch->pixels = patch->data; + patch->columns = (rcolumn_t*)((unsigned char*)patch->pixels + pixelDataSize); + patch->posts = (rpost_t*)((unsigned char*)patch->columns + columnsDataSize); + + // sanity check that we've got all the memory allocated we need + assert((((byte*)patch->posts + numPostsTotal*sizeof(rpost_t)) - (byte*)patch->data) == dataSize); + + memset(patch->pixels, 0xff, (patch->width*patch->height)); + + // fill in the pixels, posts, and columns + numPostsUsedSoFar = 0; + for (x=0; xwidth; x++) { + + oldColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[x])); + + if (patch->isNotTileable) { + // non-tiling + if (x == 0) oldPrevColumn = 0; + else oldPrevColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[x-1])); + if (x == patch->width-1) oldNextColumn = 0; + else oldNextColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[x+1])); + } + else { + // tiling + int prevColumnIndex = x-1; + int nextColumnIndex = x+1; + while (prevColumnIndex < 0) prevColumnIndex += patch->width; + while (nextColumnIndex >= patch->width) nextColumnIndex -= patch->width; + oldPrevColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[prevColumnIndex])); + oldNextColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[nextColumnIndex])); + } + + // setup the column's data + patch->columns[x].pixels = patch->pixels + (x*patch->height) + 0; + patch->columns[x].numPosts = numPostsInColumn[x]; + patch->columns[x].posts = patch->posts + numPostsUsedSoFar; + + while (oldColumn->topdelta != 0xff) { + // set up the post's data + patch->posts[numPostsUsedSoFar].topdelta = oldColumn->topdelta; + patch->posts[numPostsUsedSoFar].length = oldColumn->length; + patch->posts[numPostsUsedSoFar].slope = 0; + + edgeSlope = getColumnEdgeSlope(oldPrevColumn, oldNextColumn, oldColumn->topdelta); + if (edgeSlope == 1) patch->posts[numPostsUsedSoFar].slope |= RDRAW_EDGESLOPE_TOP_UP; + else if (edgeSlope == -1) patch->posts[numPostsUsedSoFar].slope |= RDRAW_EDGESLOPE_TOP_DOWN; + + edgeSlope = getColumnEdgeSlope(oldPrevColumn, oldNextColumn, oldColumn->topdelta+oldColumn->length); + if (edgeSlope == 1) patch->posts[numPostsUsedSoFar].slope |= RDRAW_EDGESLOPE_BOT_UP; + else if (edgeSlope == -1) patch->posts[numPostsUsedSoFar].slope |= RDRAW_EDGESLOPE_BOT_DOWN; + + // fill in the post's pixels + oldColumnPixelData = (const byte *)oldColumn + 3; + for (y=0; ylength; y++) { + patch->pixels[x * patch->height + oldColumn->topdelta + y] = oldColumnPixelData[y]; + } + + oldColumn = (const column_t *)((const byte *)oldColumn + oldColumn->length + 4); + numPostsUsedSoFar++; + } + } + + if (1 || patch->isNotTileable) { + const rcolumn_t *column, *prevColumn; + + // copy the patch image down and to the right where there are + // holes to eliminate the black halo from bilinear filtering + for (x=0; xwidth; x++) { + //oldColumn = (const column_t *)((const byte *)oldPatch + oldPatch->columnofs[x]); + + column = R_GetPatchColumnClamped(patch, x); + prevColumn = R_GetPatchColumnClamped(patch, x-1); + + if (column->pixels[0] == 0xff) { + // force the first pixel (which is a hole), to use + // the color from the next solid spot in the column + for (y=0; yheight; y++) { + if (column->pixels[y] != 0xff) { + column->pixels[0] = column->pixels[y]; + break; + } + } + } + + // copy from above or to the left + for (y=1; yheight; y++) { + //if (getIsSolidAtSpot(oldColumn, y)) continue; + if (column->pixels[y] != 0xff) continue; + + // this pixel is a hole + + if (x && prevColumn->pixels[y-1] != 0xff) { + // copy the color from the left + column->pixels[y] = prevColumn->pixels[y]; + } + else { + // copy the color from above + column->pixels[y] = column->pixels[y-1]; + } + } + } + + // verify that the patch truly is non-rectangular since + // this determines tiling later on + } + + W_UnlockLumpNum(patchNum); + free(numPostsInColumn); +} + +typedef struct { + unsigned short patches; + unsigned short posts; + unsigned short posts_used; +} count_t; + +static void switchPosts(rpost_t *post1, rpost_t *post2) { + rpost_t dummy; + + dummy.topdelta = post1->topdelta; + dummy.length = post1->length; + dummy.slope = post1->slope; + post1->topdelta = post2->topdelta; + post1->length = post2->length; + post1->slope = post2->slope; + post2->topdelta = dummy.topdelta; + post2->length = dummy.length; + post2->slope = dummy.slope; +} + +static void removePostFromColumn(rcolumn_t *column, int post) { + int i; +#ifdef RANGECHECK + if (post >= column->numPosts) + I_Error("removePostFromColumn: invalid post index"); +#endif + if (post < column->numPosts) + for (i=post; i<(column->numPosts-1); i++) { + rpost_t *post1 = &column->posts[i]; + rpost_t *post2 = &column->posts[i+1]; + post1->topdelta = post2->topdelta; + post1->length = post2->length; + post1->slope = post2->slope; + } + column->numPosts--; +} + +//--------------------------------------------------------------------------- +static void createTextureCompositePatch(int id) { + rpatch_t *composite_patch; + texture_t *texture; + texpatch_t *texpatch; + int patchNum; + const patch_t *oldPatch; + const column_t *oldColumn, *oldPrevColumn, *oldNextColumn; + int i, x, y; + int oy, count; + int pixelDataSize; + int columnsDataSize; + int postsDataSize; + int dataSize; + int numPostsTotal; + const unsigned char *oldColumnPixelData; + int numPostsUsedSoFar; + int edgeSlope; + count_t *countsInColumn; + +#ifdef RANGECHECK + if (id >= numtextures) + I_Error("createTextureCompositePatch: %i >= numtextures", id); +#endif + + composite_patch = &texture_composites[id]; + + texture = textures[id]; + + composite_patch->width = texture->width; + composite_patch->height = texture->height; + composite_patch->widthmask = texture->widthmask; + composite_patch->leftoffset = 0; + composite_patch->topoffset = 0; + composite_patch->isNotTileable = 0; + + // work out how much memory we need to allocate for this patch's data + pixelDataSize = (composite_patch->width * composite_patch->height + 4) & ~3; + columnsDataSize = sizeof(rcolumn_t) * composite_patch->width; + + // count the number of posts in each column + countsInColumn = (count_t *)calloc(sizeof(count_t), composite_patch->width); + numPostsTotal = 0; + + for (i=0; ipatchcount; i++) { + texpatch = &texture->patches[i]; + patchNum = texpatch->patch; + oldPatch = (const patch_t*)W_CacheLumpNum(patchNum); + + for (x=0; xwidth); x++) { + int tx = texpatch->originx + x; + + if (tx < 0) + continue; + if (tx >= composite_patch->width) + break; + + countsInColumn[tx].patches++; + + oldColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[x])); + while (oldColumn->topdelta != 0xff) { + countsInColumn[tx].posts++; + numPostsTotal++; + oldColumn = (const column_t *)((const byte *)oldColumn + oldColumn->length + 4); + } + } + + W_UnlockLumpNum(patchNum); + } + + postsDataSize = numPostsTotal * sizeof(rpost_t); + + // allocate our data chunk + dataSize = pixelDataSize + columnsDataSize + postsDataSize; + composite_patch->data = (unsigned char*)Z_Malloc(dataSize, PU_STATIC, (void **)&composite_patch->data); + memset(composite_patch->data, 0, dataSize); + + // set out pixel, column, and post pointers into our data array + composite_patch->pixels = composite_patch->data; + composite_patch->columns = (rcolumn_t*)((unsigned char*)composite_patch->pixels + pixelDataSize); + composite_patch->posts = (rpost_t*)((unsigned char*)composite_patch->columns + columnsDataSize); + + // sanity check that we've got all the memory allocated we need + assert((((byte*)composite_patch->posts + numPostsTotal*sizeof(rpost_t)) - (byte*)composite_patch->data) == dataSize); + + memset(composite_patch->pixels, 0xff, (composite_patch->width*composite_patch->height)); + + numPostsUsedSoFar = 0; + + for (x=0; xwidth; x++) { + // setup the column's data + composite_patch->columns[x].pixels = composite_patch->pixels + (x*composite_patch->height); + composite_patch->columns[x].numPosts = countsInColumn[x].posts; + composite_patch->columns[x].posts = composite_patch->posts + numPostsUsedSoFar; + numPostsUsedSoFar += countsInColumn[x].posts; + } + + // fill in the pixels, posts, and columns + for (i=0; ipatchcount; i++) { + texpatch = &texture->patches[i]; + patchNum = texpatch->patch; + oldPatch = (const patch_t*)W_CacheLumpNum(patchNum); + + for (x=0; xwidth); x++) { + int tx = texpatch->originx + x; + + if (tx < 0) + continue; + if (tx >= composite_patch->width) + break; + + oldColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[x])); + + { + // tiling + int prevColumnIndex = x-1; + int nextColumnIndex = x+1; + while (prevColumnIndex < 0) prevColumnIndex += SHORT(oldPatch->width); + while (nextColumnIndex >= SHORT(oldPatch->width)) nextColumnIndex -= SHORT(oldPatch->width); + oldPrevColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[prevColumnIndex])); + oldNextColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[nextColumnIndex])); + } + + while (oldColumn->topdelta != 0xff) { + rpost_t *post = &composite_patch->columns[tx].posts[countsInColumn[tx].posts_used]; + oldColumnPixelData = (const byte *)oldColumn + 3; + oy = texpatch->originy; + count = oldColumn->length; + // the original renderer had several bugs which we reproduce here + if (countsInColumn[tx].patches > 1) { + // when there are multiple patches, then we need to handle the + // column differently + if (i == 0) { + // draw first patch at original position, it will be partly + // overdrawn below + for (y=0; ytopdelta + y; + if (ty < 0) + continue; + if (ty >= composite_patch->height) + break; + composite_patch->pixels[tx * composite_patch->height + ty] = oldColumnPixelData[y]; + } + } + // do the buggy clipping + if ((oy + oldColumn->topdelta) < 0) { + count += oy; + oy = 0; + } + } else { + // with a single patch only negative y origins are wrong + oy = 0; + } + // set up the post's data + post->topdelta = oldColumn->topdelta + oy; + post->length = count; + if ((post->topdelta + post->length) > composite_patch->height) { + if (post->topdelta > composite_patch->height) + post->length = 0; + else + post->length = composite_patch->height - post->topdelta; + } + if (post->topdelta < 0) { + if ((post->topdelta + post->length) <= 0) + post->length = 0; + else + post->length -= post->topdelta; + post->topdelta = 0; + } + post->slope = 0; + + edgeSlope = getColumnEdgeSlope(oldPrevColumn, oldNextColumn, oldColumn->topdelta); + if (edgeSlope == 1) post->slope |= RDRAW_EDGESLOPE_TOP_UP; + else if (edgeSlope == -1) post->slope |= RDRAW_EDGESLOPE_TOP_DOWN; + + edgeSlope = getColumnEdgeSlope(oldPrevColumn, oldNextColumn, oldColumn->topdelta+count); + if (edgeSlope == 1) post->slope |= RDRAW_EDGESLOPE_BOT_UP; + else if (edgeSlope == -1) post->slope |= RDRAW_EDGESLOPE_BOT_DOWN; + + // fill in the post's pixels + for (y=0; ytopdelta + y; + if (ty < 0) + continue; + if (ty >= composite_patch->height) + break; + composite_patch->pixels[tx * composite_patch->height + ty] = oldColumnPixelData[y]; + } + + oldColumn = (const column_t *)((const byte *)oldColumn + oldColumn->length + 4); + countsInColumn[tx].posts_used++; + assert(countsInColumn[tx].posts_used <= countsInColumn[tx].posts); + } + } + + W_UnlockLumpNum(patchNum); + } + + for (x=0; xwidth; x++) { + rcolumn_t *column; + + if (countsInColumn[x].patches <= 1) + continue; + + // cleanup posts on multipatch columns + column = &composite_patch->columns[x]; + + i = 0; + while (i<(column->numPosts-1)) { + rpost_t *post1 = &column->posts[i]; + rpost_t *post2 = &column->posts[i+1]; + int length; + + if ((post2->topdelta - post1->topdelta) < 0) + switchPosts(post1, post2); + + if ((post1->topdelta + post1->length) >= post2->topdelta) { + length = (post1->length + post2->length) - ((post1->topdelta + post1->length) - post2->topdelta); + if (post1->length < length) { + post1->slope = post2->slope; + post1->length = length; + } + removePostFromColumn(column, i+1); + i = 0; + continue; + } + i++; + } + } + + if (1 || composite_patch->isNotTileable) { + const rcolumn_t *column, *prevColumn; + + // copy the patch image down and to the right where there are + // holes to eliminate the black halo from bilinear filtering + for (x=0; xwidth; x++) { + //oldColumn = (const column_t *)((const byte *)oldPatch + oldPatch->columnofs[x]); + + column = R_GetPatchColumnClamped(composite_patch, x); + prevColumn = R_GetPatchColumnClamped(composite_patch, x-1); + + if (column->pixels[0] == 0xff) { + // force the first pixel (which is a hole), to use + // the color from the next solid spot in the column + for (y=0; yheight; y++) { + if (column->pixels[y] != 0xff) { + column->pixels[0] = column->pixels[y]; + break; + } + } + } + + // copy from above or to the left + for (y=1; yheight; y++) { + //if (getIsSolidAtSpot(oldColumn, y)) continue; + if (column->pixels[y] != 0xff) continue; + + // this pixel is a hole + + if (x && prevColumn->pixels[y-1] != 0xff) { + // copy the color from the left + column->pixels[y] = prevColumn->pixels[y]; + } + else { + // copy the color from above + column->pixels[y] = column->pixels[y-1]; + } + } + } + + // verify that the patch truly is non-rectangular since + // this determines tiling later on + } + + free(countsInColumn); +} + +//--------------------------------------------------------------------------- +const rpatch_t *R_CachePatchNum(int id) { + const int locks = 1; + + if (!patches) + I_Error("R_CachePatchNum: Patches not initialized"); + +#ifdef RANGECHECK + if (id >= numlumps) + I_Error("createPatch: %i >= numlumps", id); +#endif + + if (!patches[id].data) + createPatch(id); + + /* cph - if wasn't locked but now is, tell z_zone to hold it */ + if (!patches[id].locks && locks) { + Z_ChangeTag(patches[id].data,PU_STATIC); +#ifdef TIMEDIAG + patches[id].locktic = gametic; +#endif + } + patches[id].locks += locks; + +#ifdef SIMPLECHECKS + if (!((patches[id].locks+1) & 0xf)) + lprintf(LO_DEBUG, "R_CachePatchNum: High lock on %8s (%d)\n", + lumpinfo[id].name, patches[id].locks); +#endif + + return &patches[id]; +} + +void R_UnlockPatchNum(int id) +{ + const int unlocks = 1; +#ifdef SIMPLECHECKS + if ((signed short)patches[id].locks < unlocks) + lprintf(LO_DEBUG, "R_UnlockPatchNum: Excess unlocks on %8s (%d-%d)\n", + lumpinfo[id].name, patches[id].locks, unlocks); +#endif + patches[id].locks -= unlocks; + /* cph - Note: must only tell z_zone to make purgeable if currently locked, + * else it might already have been purged + */ + if (unlocks && !patches[id].locks) + Z_ChangeTag(patches[id].data, PU_CACHE); +} + +//--------------------------------------------------------------------------- +const rpatch_t *R_CacheTextureCompositePatchNum(int id) { + const int locks = 1; + + if (!texture_composites) + I_Error("R_CacheTextureCompositePatchNum: Composite patches not initialized"); + +#ifdef RANGECHECK + if (id >= numtextures) + I_Error("createTextureCompositePatch: %i >= numtextures", id); +#endif + + if (!texture_composites[id].data) + createTextureCompositePatch(id); + + /* cph - if wasn't locked but now is, tell z_zone to hold it */ + if (!texture_composites[id].locks && locks) { + Z_ChangeTag(texture_composites[id].data,PU_STATIC); +#ifdef TIMEDIAG + texture_composites[id].locktic = gametic; +#endif + } + texture_composites[id].locks += locks; + +#ifdef SIMPLECHECKS + if (!((texture_composites[id].locks+1) & 0xf)) + lprintf(LO_DEBUG, "R_CacheTextureCompositePatchNum: High lock on %8s (%d)\n", + textures[id]->name, texture_composites[id].locks); +#endif + + return &texture_composites[id]; + +} + +void R_UnlockTextureCompositePatchNum(int id) +{ + const int unlocks = 1; +#ifdef SIMPLECHECKS + if ((signed short)texture_composites[id].locks < unlocks) + lprintf(LO_DEBUG, "R_UnlockTextureCompositePatchNum: Excess unlocks on %8s (%d-%d)\n", + textures[id]->name, texture_composites[id].locks, unlocks); +#endif + texture_composites[id].locks -= unlocks; + /* cph - Note: must only tell z_zone to make purgeable if currently locked, + * else it might already have been purged + */ + if (unlocks && !texture_composites[id].locks) + Z_ChangeTag(texture_composites[id].data, PU_CACHE); +} + +//--------------------------------------------------------------------------- +const rcolumn_t *R_GetPatchColumnWrapped(const rpatch_t *patch, int columnIndex) { + while (columnIndex < 0) columnIndex += patch->width; + columnIndex %= patch->width; + return &patch->columns[columnIndex]; +} + +//--------------------------------------------------------------------------- +const rcolumn_t *R_GetPatchColumnClamped(const rpatch_t *patch, int columnIndex) { + if (columnIndex < 0) columnIndex = 0; + if (columnIndex >= patch->width) columnIndex = patch->width-1; + return &patch->columns[columnIndex]; +} + +//--------------------------------------------------------------------------- +const rcolumn_t *R_GetPatchColumn(const rpatch_t *patch, int columnIndex) { + if (patch->isNotTileable) return R_GetPatchColumnClamped(patch, columnIndex); + else return R_GetPatchColumnWrapped(patch, columnIndex); +} + diff --git a/common/prboom/r_patch.h b/common/prboom/r_patch.h new file mode 100755 index 0000000..b0d1387 --- /dev/null +++ b/common/prboom/r_patch.h @@ -0,0 +1,111 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + *-----------------------------------------------------------------------------*/ + + +#ifndef R_PATCH_H +#define R_PATCH_H + +// Used to specify the sloping of the top and bottom of a column post +typedef enum { + RDRAW_EDGESLOPE_TOP_UP = (1<<0), + RDRAW_EDGESLOPE_TOP_DOWN = (1<<1), + RDRAW_EDGESLOPE_BOT_UP = (1<<2), + RDRAW_EDGESLOPE_BOT_DOWN = (1<<3), + RDRAW_EDGESLOPE_TOP_MASK = 0x3, + RDRAW_EDGESLOPE_BOT_MASK = 0xc, +} edgeslope_t; + +typedef struct { + int topdelta; + int length; + edgeslope_t slope; +} rpost_t; + +typedef struct { + int numPosts; + rpost_t *posts; + unsigned char *pixels; +} rcolumn_t; + +typedef struct { + int width; + int height; + unsigned widthmask; + + unsigned char isNotTileable; + + int leftoffset; + int topoffset; + + // this is the single malloc'ed/free'd array + // for this patch + unsigned char *data; + + // these are pointers into the data array + unsigned char *pixels; + rcolumn_t *columns; + rpost_t *posts; + +#ifdef TIMEDIAG + int locktic; +#endif + unsigned int locks; +} rpatch_t; + + +const rpatch_t *R_CachePatchNum(int id); +void R_UnlockPatchNum(int id); +#define R_CachePatchName(name) R_CachePatchNum(W_GetNumForName(name)) +#define R_UnlockPatchName(name) R_UnlockPatchNum(W_GetNumForName(name)) + +const rpatch_t *R_CacheTextureCompositePatchNum(int id); +void R_UnlockTextureCompositePatchNum(int id); + + +// Size query funcs +int R_NumPatchWidth(int lump) ; +int R_NumPatchHeight(int lump); +#define R_NamePatchWidth(name) R_NumPatchWidth(W_GetNumForName(name)) +#define R_NamePatchHeight(name) R_NumPatchHeight(W_GetNumForName(name)) + + +const rcolumn_t *R_GetPatchColumnWrapped(const rpatch_t *patch, int columnIndex); +const rcolumn_t *R_GetPatchColumnClamped(const rpatch_t *patch, int columnIndex); + + +// returns R_GetPatchColumnWrapped for square, non-holed textures +// and R_GetPatchColumnClamped otherwise +const rcolumn_t *R_GetPatchColumn(const rpatch_t *patch, int columnIndex); + + +void R_InitPatches(); +void R_FlushAllPatches(); + +#endif diff --git a/common/prboom/r_plane.c b/common/prboom/r_plane.c new file mode 100755 index 0000000..72b8870 --- /dev/null +++ b/common/prboom/r_plane.c @@ -0,0 +1,468 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Here is a core component: drawing the floors and ceilings, + * while maintaining a per column clipping list only. + * Moreover, the sky areas have to be determined. + * + * MAXVISPLANES is no longer a limit on the number of visplanes, + * but a limit on the number of hash slots; larger numbers mean + * better performance usually but after a point they are wasted, + * and memory and time overheads creep in. + * + * For more information on visplanes, see: + * + * http://classicgaming.com/doom/editing/ + * + * Lee Killough + * + *-----------------------------------------------------------------------------*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "z_zone.h" /* memory allocation wrappers -- killough */ + +#include "doomstat.h" +#include "w_wad.h" +#include "r_main.h" +#include "r_draw.h" +#include "r_things.h" +#include "r_sky.h" +#include "r_plane.h" +#include "v_video.h" +#include "lprintf.h" + +#define MAXVISPLANES 128 /* must be a power of 2 */ + +static visplane_t *visplanes[MAXVISPLANES]; // killough +static visplane_t *freetail; // killough +static visplane_t **freehead = &freetail; // killough +visplane_t *floorplane, *ceilingplane; + +// killough -- hash function for visplanes +// Empirically verified to be fairly uniform: + +#define visplane_hash(picnum,lightlevel,height) \ + ((unsigned)((picnum)*3+(lightlevel)+(height)*7) & (MAXVISPLANES-1)) + +size_t maxopenings; +int *openings,*lastopening; // dropoff overflow + +// Clip values are the solid pixel bounding the range. +// floorclip starts out SCREENHEIGHT +// ceilingclip starts out -1 + +int floorclip[MAX_SCREENWIDTH], ceilingclip[MAX_SCREENWIDTH]; // dropoff overflow + +// spanstart holds the start of a plane span; initialized to 0 at start + +static int spanstart[MAX_SCREENHEIGHT]; // killough 2/8/98 + +// +// texture mapping +// + +static const lighttable_t **planezlight; +static fixed_t planeheight; + +// killough 2/8/98: make variables static + +static fixed_t basexscale, baseyscale; +static fixed_t cachedheight[MAX_SCREENHEIGHT]; +static fixed_t cacheddistance[MAX_SCREENHEIGHT]; +static fixed_t cachedxstep[MAX_SCREENHEIGHT]; +static fixed_t cachedystep[MAX_SCREENHEIGHT]; +static fixed_t xoffs,yoffs; // killough 2/28/98: flat offsets + +fixed_t yslope[MAX_SCREENHEIGHT], distscale[MAX_SCREENWIDTH]; + +// +// R_InitPlanes +// Only at game startup. +// +void R_InitPlanes (void) +{ +} + +// +// R_MapPlane +// +// Uses global vars: +// planeheight +// dsvars.source +// basexscale +// baseyscale +// viewx +// viewy +// xoffs +// yoffs +// +// BASIC PRIMITIVE +// + +static void R_MapPlane(int y, int x1, int x2, draw_span_vars_t *dsvars) +{ + angle_t angle; + fixed_t distance, length; + unsigned index; + +#ifdef RANGECHECK + if (x2 < x1 || x1<0 || x2>=viewwidth || (unsigned)y>(unsigned)viewheight) + I_Error ("R_MapPlane: %i, %i at %i",x1,x2,y); +#endif + + if (planeheight != cachedheight[y]) + { + cachedheight[y] = planeheight; + distance = cacheddistance[y] = FixedMul (planeheight, yslope[y]); + dsvars->xstep = cachedxstep[y] = FixedMul (distance,basexscale); + dsvars->ystep = cachedystep[y] = FixedMul (distance,baseyscale); + } + else + { + distance = cacheddistance[y]; + dsvars->xstep = cachedxstep[y]; + dsvars->ystep = cachedystep[y]; + } + + length = FixedMul (distance,distscale[x1]); + angle = (viewangle + xtoviewangle[x1])>>ANGLETOFINESHIFT; + + // killough 2/28/98: Add offsets + dsvars->xfrac = viewx + FixedMul(finecosine[angle], length) + xoffs; + dsvars->yfrac = -viewy - FixedMul(finesine[angle], length) + yoffs; + + if (drawvars.filterfloor == RDRAW_FILTER_LINEAR) { + dsvars->xfrac -= (FRACUNIT>>1); + dsvars->yfrac -= (FRACUNIT>>1); + } + + if (!(dsvars->colormap = fixedcolormap)) + { + dsvars->z = distance; + index = distance >> LIGHTZSHIFT; + if (index >= MAXLIGHTZ ) + index = MAXLIGHTZ-1; + dsvars->colormap = planezlight[index]; + dsvars->nextcolormap = planezlight[index+1 >= MAXLIGHTZ ? MAXLIGHTZ-1 : index+1]; + } + else + { + dsvars->z = 0; + } + + dsvars->y = y; + dsvars->x1 = x1; + dsvars->x2 = x2; + + if (V_GetMode() != VID_MODEGL) + R_DrawSpan(dsvars); +} + +// +// R_ClearPlanes +// At begining of frame. +// + +void R_ClearPlanes(void) +{ + int i; + + // opening / clipping determination + for (i=0 ; inext; + + lastopening = openings; + + // texture calculation + memset (cachedheight, 0, sizeof(cachedheight)); + + // scale will be unit scale at SCREENWIDTH/2 distance + basexscale = FixedDiv (viewsin,projection); + baseyscale = FixedDiv (viewcos,projection); +} + +// New function, by Lee Killough + +static visplane_t *new_visplane(unsigned hash) +{ + visplane_t *check = freetail; + if (!check) + check = calloc(1, sizeof *check); + else + if (!(freetail = freetail->next)) + freehead = &freetail; + check->next = visplanes[hash]; + visplanes[hash] = check; + return check; +} + +/* + * R_DupPlane + * + * cph 2003/04/18 - create duplicate of existing visplane and set initial range + */ +visplane_t *R_DupPlane(const visplane_t *pl, int start, int stop) +{ + unsigned hash = visplane_hash(pl->picnum, pl->lightlevel, pl->height); + visplane_t *new_pl = new_visplane(hash); + + new_pl->height = pl->height; + new_pl->picnum = pl->picnum; + new_pl->lightlevel = pl->lightlevel; + new_pl->xoffs = pl->xoffs; // killough 2/28/98 + new_pl->yoffs = pl->yoffs; + new_pl->minx = start; + new_pl->maxx = stop; + memset(new_pl->top, 0xff, sizeof new_pl->top); + return new_pl; +} +// +// R_FindPlane +// +// killough 2/28/98: Add offsets + +visplane_t *R_FindPlane(fixed_t height, int picnum, int lightlevel, + fixed_t xoffset, fixed_t yoffset) +{ + visplane_t *check; + unsigned hash; // killough + + if (picnum == skyflatnum || picnum & PL_SKYFLAT) + height = lightlevel = 0; // killough 7/19/98: most skies map together + + // New visplane algorithm uses hash table -- killough + hash = visplane_hash(picnum,lightlevel,height); + + for (check=visplanes[hash]; check; check=check->next) // killough + if (height == check->height && + picnum == check->picnum && + lightlevel == check->lightlevel && + xoffset == check->xoffs && // killough 2/28/98: Add offset checks + yoffset == check->yoffs) + return check; + + check = new_visplane(hash); // killough + + check->height = height; + check->picnum = picnum; + check->lightlevel = lightlevel; + check->minx = viewwidth; // Was SCREENWIDTH -- killough 11/98 + check->maxx = -1; + check->xoffs = xoffset; // killough 2/28/98: Save offsets + check->yoffs = yoffset; + + memset (check->top, 0xff, sizeof check->top); + + return check; +} + +// +// R_CheckPlane +// +visplane_t *R_CheckPlane(visplane_t *pl, int start, int stop) +{ + int intrl, intrh, unionl, unionh, x; + + if (start < pl->minx) + intrl = pl->minx, unionl = start; + else + unionl = pl->minx, intrl = start; + + if (stop > pl->maxx) + intrh = pl->maxx, unionh = stop; + else + unionh = pl->maxx, intrh = stop; + + for (x=intrl ; x <= intrh && pl->top[x] == 0xffffffffu; x++) // dropoff overflow + ; + + if (x > intrh) { /* Can use existing plane; extend range */ + pl->minx = unionl; pl->maxx = unionh; + return pl; + } else /* Cannot use existing plane; create a new one */ + return R_DupPlane(pl,start,stop); +} + +// +// R_MakeSpans +// + +static void R_MakeSpans(int x, unsigned int t1, unsigned int b1, + unsigned int t2, unsigned int b2, + draw_span_vars_t *dsvars) +{ + for (; t1 < t2 && t1 <= b1; t1++) + R_MapPlane(t1, spanstart[t1], x-1, dsvars); + for (; b1 > b2 && b1 >= t1; b1--) + R_MapPlane(b1, spanstart[b1] ,x-1, dsvars); + while (t2 < t1 && t2 <= b2) + spanstart[t2++] = x; + while (b2 > b1 && b2 >= t2) + spanstart[b2--] = x; +} + +// New function, by Lee Killough + +static void R_DoDrawPlane(visplane_t *pl) +{ + register int x; + draw_column_vars_t dcvars; + R_DrawColumn_f colfunc = R_GetDrawColumnFunc(RDC_PIPELINE_STANDARD, drawvars.filterwall, drawvars.filterz); + + R_SetDefaultDrawColumnVars(&dcvars); + + if (pl->minx <= pl->maxx) { + if (pl->picnum == skyflatnum || pl->picnum & PL_SKYFLAT) { // sky flat + int texture; + const rpatch_t *tex_patch; + angle_t an, flip; + + // killough 10/98: allow skies to come from sidedefs. + // Allows scrolling and/or animated skies, as well as + // arbitrary multiple skies per level without having + // to use info lumps. + + an = viewangle; + + if (pl->picnum & PL_SKYFLAT) + { + // Sky Linedef + const line_t *l = &lines[pl->picnum & ~PL_SKYFLAT]; + + // Sky transferred from first sidedef + const side_t *s = *l->sidenum + sides; + + // Texture comes from upper texture of reference sidedef + texture = texturetranslation[s->toptexture]; + + // Horizontal offset is turned into an angle offset, + // to allow sky rotation as well as careful positioning. + // However, the offset is scaled very small, so that it + // allows a long-period of sky rotation. + + an += s->textureoffset; + + // Vertical offset allows careful sky positioning. + + dcvars.texturemid = s->rowoffset - 28*FRACUNIT; + + // We sometimes flip the picture horizontally. + // + // Doom always flipped the picture, so we make it optional, + // to make it easier to use the new feature, while to still + // allow old sky textures to be used. + + flip = l->special==272 ? 0u : ~0u; + } + else + { // Normal Doom sky, only one allowed per level + dcvars.texturemid = skytexturemid; // Default y-offset + texture = skytexture; // Default texture + flip = 0; // Doom flips it + } + + /* Sky is always drawn full bright, i.e. colormaps[0] is used. + * Because of this hack, sky is not affected by INVUL inverse mapping. + * Until Boom fixed this. Compat option added in MBF. */ + + if (comp[comp_skymap] || !(dcvars.colormap = fixedcolormap)) + dcvars.colormap = fullcolormap; // killough 3/20/98 + + dcvars.nextcolormap = dcvars.colormap; // for filtering -- POPE + + //dcvars.texturemid = skytexturemid; + dcvars.texheight = textureheight[skytexture]>>FRACBITS; // killough + // proff 09/21/98: Changed for high-res + dcvars.iscale = FRACUNIT*200/viewheight; + + tex_patch = R_CacheTextureCompositePatchNum(texture); + + // killough 10/98: Use sky scrolling offset, and possibly flip picture + for (x = pl->minx; (dcvars.x = x) <= pl->maxx; x++) + if ((dcvars.yl = pl->top[x]) != -1 && dcvars.yl <= (dcvars.yh = pl->bottom[x])) // dropoff overflow + { + dcvars.source = R_GetTextureColumn(tex_patch, ((an + xtoviewangle[x])^flip) >> ANGLETOSKYSHIFT); + dcvars.prevsource = R_GetTextureColumn(tex_patch, ((an + xtoviewangle[x-1])^flip) >> ANGLETOSKYSHIFT); + dcvars.nextsource = R_GetTextureColumn(tex_patch, ((an + xtoviewangle[x+1])^flip) >> ANGLETOSKYSHIFT); + colfunc(&dcvars); + } + + R_UnlockTextureCompositePatchNum(texture); + + } else { // regular flat + + int stop, light; + draw_span_vars_t dsvars; + + dsvars.source = W_CacheLumpNum(firstflat + flattranslation[pl->picnum]); + + xoffs = pl->xoffs; // killough 2/28/98: Add offsets + yoffs = pl->yoffs; + planeheight = D_abs(pl->height-viewz); + light = (pl->lightlevel >> LIGHTSEGSHIFT) + extralight; + + if (light >= LIGHTLEVELS) + light = LIGHTLEVELS-1; + + if (light < 0) + light = 0; + + stop = pl->maxx + 1; + planezlight = zlight[light]; + pl->top[pl->minx-1] = pl->top[stop] = 0xffffffffu; // dropoff overflow + + for (x = pl->minx ; x <= stop ; x++) + R_MakeSpans(x,pl->top[x-1],pl->bottom[x-1], + pl->top[x],pl->bottom[x], &dsvars); + + W_UnlockLumpNum(firstflat + flattranslation[pl->picnum]); + } + } +} + +// +// RDrawPlanes +// At the end of each frame. +// + +void R_DrawPlanes (void) +{ + visplane_t *pl; + int i; + for (i=0;inext, rendered_visplanes++) + R_DoDrawPlane(pl); +} diff --git a/common/prboom/r_plane.h b/common/prboom/r_plane.h new file mode 100755 index 0000000..7a2a515 --- /dev/null +++ b/common/prboom/r_plane.h @@ -0,0 +1,67 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Refresh, visplane stuff (floor, ceilings). + * + *-----------------------------------------------------------------------------*/ + +#ifndef __R_PLANE__ +#define __R_PLANE__ + +#include "r_data.h" + +#ifdef __GNUG__ +#pragma interface +#endif + +/* killough 10/98: special mask indicates sky flat comes from sidedef */ +#define PL_SKYFLAT (0x80000000) + +/* Visplane related. */ +extern int *lastopening; // dropoff overflow + +extern int floorclip[], ceilingclip[]; // dropoff overflow +extern fixed_t yslope[], distscale[]; + +void R_InitPlanes(void); +void R_ClearPlanes(void); +void R_DrawPlanes (void); + +visplane_t *R_FindPlane( + fixed_t height, + int picnum, + int lightlevel, + fixed_t xoffs, /* killough 2/28/98: add x-y offsets */ + fixed_t yoffs + ); + +visplane_t *R_CheckPlane(visplane_t *pl, int start, int stop); +visplane_t *R_DupPlane(const visplane_t *pl, int start, int stop); + +#endif diff --git a/common/prboom/r_segs.c b/common/prboom/r_segs.c new file mode 100755 index 0000000..cb30b75 --- /dev/null +++ b/common/prboom/r_segs.c @@ -0,0 +1,854 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2004 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * All the clipping: columns, horizontal spans, sky columns. + * + *-----------------------------------------------------------------------------*/ +// +// 4/25/98, 5/2/98 killough: reformatted, beautified + +#include "doomstat.h" +#include "r_main.h" +#include "r_bsp.h" +#include "r_segs.h" +#include "r_plane.h" +#include "r_things.h" +#include "r_draw.h" +#include "w_wad.h" +#include "v_video.h" +#include "lprintf.h" + +// OPTIMIZE: closed two sided lines as single sided + +// killough 1/6/98: replaced globals with statics where appropriate + +// True if any of the segs textures might be visible. +static boolean segtextured; +static boolean markfloor; // False if the back side is the same plane. +static boolean markceiling; +static boolean maskedtexture; +static int toptexture; +static int bottomtexture; +static int midtexture; + +static fixed_t toptexheight, midtexheight, bottomtexheight; // cph + +angle_t rw_normalangle; // angle to line origin +int rw_angle1; +fixed_t rw_distance; + +// +// regular wall +// +static int rw_x; +static int rw_stopx; +static angle_t rw_centerangle; +static fixed_t rw_offset; +static fixed_t rw_scale; +static fixed_t rw_scalestep; +static fixed_t rw_midtexturemid; +static fixed_t rw_toptexturemid; +static fixed_t rw_bottomtexturemid; +static int rw_lightlevel; +static int worldtop; +static int worldbottom; +static int worldhigh; +static int worldlow; +static fixed_t pixhigh; +static fixed_t pixlow; +static fixed_t pixhighstep; +static fixed_t pixlowstep; +static fixed_t topfrac; +static fixed_t topstep; +static fixed_t bottomfrac; +static fixed_t bottomstep; +static int *maskedtexturecol; // dropoff overflow + +// +// R_ScaleFromGlobalAngle +// Returns the texture mapping scale +// for the current line (horizontal span) +// at the given angle. +// rw_distance must be calculated first. +// +// killough 5/2/98: reformatted, cleaned up +// CPhipps - moved here from r_main.c + +static fixed_t R_ScaleFromGlobalAngle(angle_t visangle) +{ + int anglea = ANG90 + (visangle-viewangle); + int angleb = ANG90 + (visangle-rw_normalangle); + int den = FixedMul(rw_distance, finesine[anglea>>ANGLETOFINESHIFT]); +// proff 11/06/98: Changed for high-res + fixed_t num = FixedMul(projectiony, finesine[angleb>>ANGLETOFINESHIFT]); + return den > num>>16 ? (num = FixedDiv(num, den)) > 64*FRACUNIT ? + 64*FRACUNIT : num < 256 ? 256 : num : 64*FRACUNIT; +} + +// +// R_RenderMaskedSegRange +// + +void R_RenderMaskedSegRange(drawseg_t *ds, int x1, int x2) +{ + int texnum; + sector_t tempsec; // killough 4/13/98 + const rpatch_t *patch; + R_DrawColumn_f colfunc; + draw_column_vars_t dcvars; + angle_t angle; + + R_SetDefaultDrawColumnVars(&dcvars); + + // Calculate light table. + // Use different light tables + // for horizontal / vertical / diagonal. Diagonal? + + curline = ds->curline; // OPTIMIZE: get rid of LIGHTSEGSHIFT globally + + // killough 4/11/98: draw translucent 2s normal textures + + colfunc = R_GetDrawColumnFunc(RDC_PIPELINE_STANDARD, drawvars.filterwall, drawvars.filterz); + if (curline->linedef->tranlump >= 0 && general_translucency) + { + colfunc = R_GetDrawColumnFunc(RDC_PIPELINE_TRANSLUCENT, drawvars.filterwall, drawvars.filterz); + tranmap = main_tranmap; + if (curline->linedef->tranlump > 0) + tranmap = W_CacheLumpNum(curline->linedef->tranlump-1); + } + // killough 4/11/98: end translucent 2s normal code + + frontsector = curline->frontsector; + backsector = curline->backsector; + + // cph 2001/11/25 - middle textures did not animate in v1.2 + texnum = curline->sidedef->midtexture; + if (!comp[comp_maskedanim]) + texnum = texturetranslation[texnum]; + + // killough 4/13/98: get correct lightlevel for 2s normal textures + rw_lightlevel = R_FakeFlat(frontsector, &tempsec, NULL, NULL, false) ->lightlevel; + + maskedtexturecol = ds->maskedtexturecol; + + rw_scalestep = ds->scalestep; + spryscale = ds->scale1 + (x1 - ds->x1)*rw_scalestep; + mfloorclip = ds->sprbottomclip; + mceilingclip = ds->sprtopclip; + + // find positioning + if (curline->linedef->flags & ML_DONTPEGBOTTOM) + { + dcvars.texturemid = frontsector->floorheight > backsector->floorheight + ? frontsector->floorheight : backsector->floorheight; + dcvars.texturemid = dcvars.texturemid + textureheight[texnum] - viewz; + } + else + { + dcvars.texturemid =frontsector->ceilingheightceilingheight + ? frontsector->ceilingheight : backsector->ceilingheight; + dcvars.texturemid = dcvars.texturemid - viewz; + } + + dcvars.texturemid += curline->sidedef->rowoffset; + + if (fixedcolormap) { + dcvars.colormap = fixedcolormap; + dcvars.nextcolormap = dcvars.colormap; // for filtering -- POPE + } + + patch = R_CacheTextureCompositePatchNum(texnum); + + // draw the columns + for (dcvars.x = x1 ; dcvars.x <= x2 ; dcvars.x++, spryscale += rw_scalestep) + if (maskedtexturecol[dcvars.x] != INT_MAX) // dropoff overflow + { + // calculate texture offset - POPE + angle = (ds->rw_centerangle + xtoviewangle[dcvars.x]) >> ANGLETOFINESHIFT; + dcvars.texu = ds->rw_offset - FixedMul(finetangent[angle], ds->rw_distance); + if (drawvars.filterwall == RDRAW_FILTER_LINEAR) + dcvars.texu -= (FRACUNIT>>1); + + if (!fixedcolormap) + dcvars.z = spryscale; // for filtering -- POPE + dcvars.colormap = R_ColourMap(rw_lightlevel,spryscale); + dcvars.nextcolormap = R_ColourMap(rw_lightlevel+1,spryscale); // for filtering -- POPE + + // killough 3/2/98: + // + // This calculation used to overflow and cause crashes in Doom: + // + // sprtopscreen = centeryfrac - FixedMul(dcvars.texturemid, spryscale); + // + // This code fixes it, by using double-precision intermediate + // arithmetic and by skipping the drawing of 2s normals whose + // mapping to screen coordinates is totally out of range: + + { + int_64_t t = ((int_64_t) centeryfrac << FRACBITS) - + (int_64_t) dcvars.texturemid * spryscale; + if (t + (int_64_t) textureheight[texnum] * spryscale < 0 || + t > (int_64_t) MAX_SCREENHEIGHT << FRACBITS*2) + continue; // skip if the texture is out of screen's range + sprtopscreen = (long)(t >> FRACBITS); + } + + dcvars.iscale = 0xffffffffu / (unsigned) spryscale; + + // killough 1/25/98: here's where Medusa came in, because + // it implicitly assumed that the column was all one patch. + // Originally, Doom did not construct complete columns for + // multipatched textures, so there were no header or trailer + // bytes in the column referred to below, which explains + // the Medusa effect. The fix is to construct true columns + // when forming multipatched textures (see r_data.c). + + // draw the texture + R_DrawMaskedColumn( + patch, + colfunc, + &dcvars, + R_GetPatchColumnWrapped(patch, maskedtexturecol[dcvars.x]), + R_GetPatchColumnWrapped(patch, maskedtexturecol[dcvars.x]-1), + R_GetPatchColumnWrapped(patch, maskedtexturecol[dcvars.x]+1) + ); + + maskedtexturecol[dcvars.x] = INT_MAX; // dropoff overflow + } + + // Except for main_tranmap, mark others purgable at this point + if (curline->linedef->tranlump > 0 && general_translucency) + W_UnlockLumpNum(curline->linedef->tranlump-1); // cph - unlock it + + R_UnlockTextureCompositePatchNum(texnum); + + curline = NULL; /* cph 2001/11/18 - must clear curline now we're done with it, so R_ColourMap doesn't try using it for other things */ +} + +// +// R_RenderSegLoop +// Draws zero, one, or two textures (and possibly a masked texture) for walls. +// Can draw or mark the starting pixel of floor and ceiling textures. +// CALLED: CORE LOOPING ROUTINE. +// + +#define HEIGHTBITS 12 +#define HEIGHTUNIT (1<>HEIGHTBITS; + int yl = (topfrac+HEIGHTUNIT-1)>>HEIGHTBITS; + + // no space above wall? + int bottom,top = ceilingclip[rw_x]+1; + + if (yl < top) + yl = top; + + if (markceiling) + { + bottom = yl-1; + + if (bottom >= floorclip[rw_x]) + bottom = floorclip[rw_x]-1; + + if (top <= bottom) + { + ceilingplane->top[rw_x] = top; + ceilingplane->bottom[rw_x] = bottom; + } + // SoM: this should be set here + ceilingclip[rw_x] = bottom; + } + +// yh = bottomfrac>>HEIGHTBITS; + + bottom = floorclip[rw_x]-1; + if (yh > bottom) + yh = bottom; + + if (markfloor) + { + + top = yh < ceilingclip[rw_x] ? ceilingclip[rw_x] : yh; + + if (++top <= bottom) + { + floorplane->top[rw_x] = top; + floorplane->bottom[rw_x] = bottom; + } + // SoM: This should be set here to prevent overdraw + floorclip[rw_x] = top; + } + + // texturecolumn and lighting are independent of wall tiers + if (segtextured) + { + // calculate texture offset + angle_t angle =(rw_centerangle+xtoviewangle[rw_x])>>ANGLETOFINESHIFT; + + texturecolumn = rw_offset-FixedMul(finetangent[angle],rw_distance); + if (drawvars.filterwall == RDRAW_FILTER_LINEAR) + texturecolumn -= (FRACUNIT>>1); + dcvars.texu = texturecolumn; // for filtering -- POPE + texturecolumn >>= FRACBITS; + + dcvars.colormap = R_ColourMap(rw_lightlevel,rw_scale); + dcvars.nextcolormap = R_ColourMap(rw_lightlevel+1,rw_scale); // for filtering -- POPE + dcvars.z = rw_scale; // for filtering -- POPE + + dcvars.x = rw_x; + dcvars.iscale = 0xffffffffu / (unsigned)rw_scale; + } + + // draw the wall tiers + if (midtexture) + { + + dcvars.yl = yl; // single sided line + dcvars.yh = yh; + dcvars.texturemid = rw_midtexturemid; + tex_patch = R_CacheTextureCompositePatchNum(midtexture); + dcvars.source = R_GetTextureColumn(tex_patch, texturecolumn); + dcvars.prevsource = R_GetTextureColumn(tex_patch, texturecolumn-1); + dcvars.nextsource = R_GetTextureColumn(tex_patch, texturecolumn+1); + dcvars.texheight = midtexheight; + colfunc (&dcvars); + R_UnlockTextureCompositePatchNum(midtexture); + tex_patch = NULL; + ceilingclip[rw_x] = viewheight; + floorclip[rw_x] = -1; + } + else + { + + // two sided line + if (toptexture) + { + // top wall + int mid = pixhigh>>HEIGHTBITS; + pixhigh += pixhighstep; + + if (mid >= floorclip[rw_x]) + mid = floorclip[rw_x]-1; + + if (mid >= yl) + { + dcvars.yl = yl; + dcvars.yh = mid; + dcvars.texturemid = rw_toptexturemid; + tex_patch = R_CacheTextureCompositePatchNum(toptexture); + dcvars.source = R_GetTextureColumn(tex_patch,texturecolumn); + dcvars.prevsource = R_GetTextureColumn(tex_patch,texturecolumn-1); + dcvars.nextsource = R_GetTextureColumn(tex_patch,texturecolumn+1); + dcvars.texheight = toptexheight; + colfunc (&dcvars); + R_UnlockTextureCompositePatchNum(toptexture); + tex_patch = NULL; + ceilingclip[rw_x] = mid; + } + else + ceilingclip[rw_x] = yl-1; + } + else // no top wall + { + + if (markceiling) + ceilingclip[rw_x] = yl-1; + } + + if (bottomtexture) // bottom wall + { + int mid = (pixlow+HEIGHTUNIT-1)>>HEIGHTBITS; + pixlow += pixlowstep; + + // no space above wall? + if (mid <= ceilingclip[rw_x]) + mid = ceilingclip[rw_x]+1; + + if (mid <= yh) + { + dcvars.yl = mid; + dcvars.yh = yh; + dcvars.texturemid = rw_bottomtexturemid; + tex_patch = R_CacheTextureCompositePatchNum(bottomtexture); + dcvars.source = R_GetTextureColumn(tex_patch, texturecolumn); + dcvars.prevsource = R_GetTextureColumn(tex_patch, texturecolumn-1); + dcvars.nextsource = R_GetTextureColumn(tex_patch, texturecolumn+1); + dcvars.texheight = bottomtexheight; + colfunc (&dcvars); + R_UnlockTextureCompositePatchNum(bottomtexture); + tex_patch = NULL; + floorclip[rw_x] = mid; + } + else + floorclip[rw_x] = yh+1; + } + else // no bottom wall + { + if (markfloor) + floorclip[rw_x] = yh+1; + } + + // cph - if we completely blocked further sight through this column, + // add this info to the solid columns array for r_bsp.c + if ((markceiling || markfloor) && + (floorclip[rw_x] <= ceilingclip[rw_x] + 1)) { + solidcol[rw_x] = 1; didsolidcol = 1; + } + + // save texturecol for backdrawing of masked mid texture + if (maskedtexture) + maskedtexturecol[rw_x] = texturecolumn; + } + + rw_scale += rw_scalestep; + topfrac += topstep; + bottomfrac += bottomstep; + } +} + +// killough 5/2/98: move from r_main.c, made static, simplified + +static fixed_t R_PointToDist(fixed_t x, fixed_t y) +{ + fixed_t dx = D_abs(x - viewx); + fixed_t dy = D_abs(y - viewy); + + if (dy > dx) + { + fixed_t t = dx; + dx = dy; + dy = t; + } + + return FixedDiv(dx, finesine[(tantoangle[FixedDiv(dy,dx) >> DBITS] + + ANG90) >> ANGLETOFINESHIFT]); +} + +// +// R_StoreWallRange +// A wall segment will be drawn +// between start and stop pixels (inclusive). +// +void R_StoreWallRange(const int start, const int stop) +{ + fixed_t hyp; + angle_t offsetangle; + + if (ds_p == drawsegs+maxdrawsegs) // killough 1/98 -- fix 2s line HOM + { + unsigned pos = ds_p - drawsegs; // jff 8/9/98 fix from ZDOOM1.14a + unsigned newmax = maxdrawsegs ? maxdrawsegs*2 : 128; // killough + drawsegs = realloc(drawsegs,newmax*sizeof(*drawsegs)); + ds_p = drawsegs + pos; // jff 8/9/98 fix from ZDOOM1.14a + maxdrawsegs = newmax; + } + + if(curline->miniseg == false) // figgi -- skip minisegs + curline->linedef->flags |= ML_MAPPED; + +#ifdef GL_DOOM + if (V_GetMode() == VID_MODEGL) + { + // proff 11/99: the rest of the calculations is not needed for OpenGL + ds_p++->curline = curline; + gld_AddWall(curline); + + return; + } +#endif + + +#ifdef RANGECHECK + if (start >=viewwidth || start > stop) + I_Error ("Bad R_RenderWallRange: %i to %i", start , stop); +#endif + + sidedef = curline->sidedef; + linedef = curline->linedef; + + // mark the segment as visible for auto map + linedef->flags |= ML_MAPPED; + + // calculate rw_distance for scale calculation + rw_normalangle = curline->angle + ANG90; + + offsetangle = rw_normalangle-rw_angle1; + + if (D_abs(offsetangle) > ANG90) + offsetangle = ANG90; + + hyp = (viewx==curline->v1->x && viewy==curline->v1->y)? + 0 : R_PointToDist (curline->v1->x, curline->v1->y); + rw_distance = FixedMul(hyp, finecosine[offsetangle>>ANGLETOFINESHIFT]); + + ds_p->x1 = rw_x = start; + ds_p->x2 = stop; + ds_p->curline = curline; + rw_stopx = stop+1; + + { // killough 1/6/98, 2/1/98: remove limit on openings + extern int *openings; // dropoff overflow + extern size_t maxopenings; + size_t pos = lastopening - openings; + size_t need = (rw_stopx - start)*4 + pos; + if (need > maxopenings) + { + drawseg_t *ds; //jff 8/9/98 needed for fix from ZDoom + int *oldopenings = openings; // dropoff overflow + int *oldlast = lastopening; // dropoff overflow + + do + maxopenings = maxopenings ? maxopenings*2 : 16384; + while (need > maxopenings); + openings = realloc(openings, maxopenings * sizeof(*openings)); + lastopening = openings + pos; + + // jff 8/9/98 borrowed fix for openings from ZDOOM1.14 + // [RH] We also need to adjust the openings pointers that + // were already stored in drawsegs. + for (ds = drawsegs; ds < ds_p; ds++) + { +#define ADJUST(p) if (ds->p + ds->x1 >= oldopenings && ds->p + ds->x1 <= oldlast)\ + ds->p = ds->p - oldopenings + openings; + ADJUST (maskedtexturecol); + ADJUST (sprtopclip); + ADJUST (sprbottomclip); + } +#undef ADJUST + } + } // killough: end of code to remove limits on openings + + // calculate scale at both ends and step + + ds_p->scale1 = rw_scale = + R_ScaleFromGlobalAngle (viewangle + xtoviewangle[start]); + + if (stop > start) + { + ds_p->scale2 = R_ScaleFromGlobalAngle (viewangle + xtoviewangle[stop]); + ds_p->scalestep = rw_scalestep = (ds_p->scale2-rw_scale) / (stop-start); + } + else + ds_p->scale2 = ds_p->scale1; + + // calculate texture boundaries + // and decide if floor / ceiling marks are needed + + worldtop = frontsector->ceilingheight - viewz; + worldbottom = frontsector->floorheight - viewz; + + midtexture = toptexture = bottomtexture = maskedtexture = 0; + ds_p->maskedtexturecol = NULL; + + if (!backsector) + { + // single sided line + midtexture = texturetranslation[sidedef->midtexture]; + midtexheight = (linedef->r_flags & RF_MID_TILE) ? 0 : textureheight[midtexture] >> FRACBITS; + + // a single sided line is terminal, so it must mark ends + markfloor = markceiling = true; + + if (linedef->flags & ML_DONTPEGBOTTOM) + { // bottom of texture at bottom + fixed_t vtop = frontsector->floorheight + + textureheight[sidedef->midtexture]; + rw_midtexturemid = vtop - viewz; + } + else // top of texture at top + rw_midtexturemid = worldtop; + + rw_midtexturemid += FixedMod(sidedef->rowoffset, textureheight[midtexture]); + + ds_p->silhouette = SIL_BOTH; + ds_p->sprtopclip = screenheightarray; + ds_p->sprbottomclip = negonearray; + ds_p->bsilheight = INT_MAX; + ds_p->tsilheight = INT_MIN; + } + else // two sided line + { + ds_p->sprtopclip = ds_p->sprbottomclip = NULL; + ds_p->silhouette = 0; + + if (linedef->r_flags & RF_CLOSED) { /* cph - closed 2S line e.g. door */ + // cph - killough's (outdated) comment follows - this deals with both + // "automap fixes", his and mine + // killough 1/17/98: this test is required if the fix + // for the automap bug (r_bsp.c) is used, or else some + // sprites will be displayed behind closed doors. That + // fix prevents lines behind closed doors with dropoffs + // from being displayed on the automap. + + ds_p->silhouette = SIL_BOTH; + ds_p->sprbottomclip = negonearray; + ds_p->bsilheight = INT_MAX; + ds_p->sprtopclip = screenheightarray; + ds_p->tsilheight = INT_MIN; + + } else { /* not solid - old code */ + + if (frontsector->floorheight > backsector->floorheight) + { + ds_p->silhouette = SIL_BOTTOM; + ds_p->bsilheight = frontsector->floorheight; + } + else + if (backsector->floorheight > viewz) + { + ds_p->silhouette = SIL_BOTTOM; + ds_p->bsilheight = INT_MAX; + } + + if (frontsector->ceilingheight < backsector->ceilingheight) + { + ds_p->silhouette |= SIL_TOP; + ds_p->tsilheight = frontsector->ceilingheight; + } + else + if (backsector->ceilingheight < viewz) + { + ds_p->silhouette |= SIL_TOP; + ds_p->tsilheight = INT_MIN; + } + } + + worldhigh = backsector->ceilingheight - viewz; + worldlow = backsector->floorheight - viewz; + + // hack to allow height changes in outdoor areas + if (frontsector->ceilingpic == skyflatnum + && backsector->ceilingpic == skyflatnum) + worldtop = worldhigh; + + markfloor = worldlow != worldbottom + || backsector->floorpic != frontsector->floorpic + || backsector->lightlevel != frontsector->lightlevel + + // killough 3/7/98: Add checks for (x,y) offsets + || backsector->floor_xoffs != frontsector->floor_xoffs + || backsector->floor_yoffs != frontsector->floor_yoffs + + // killough 4/15/98: prevent 2s normals + // from bleeding through deep water + || frontsector->heightsec != -1 + + // killough 4/17/98: draw floors if different light levels + || backsector->floorlightsec != frontsector->floorlightsec + ; + + markceiling = worldhigh != worldtop + || backsector->ceilingpic != frontsector->ceilingpic + || backsector->lightlevel != frontsector->lightlevel + + // killough 3/7/98: Add checks for (x,y) offsets + || backsector->ceiling_xoffs != frontsector->ceiling_xoffs + || backsector->ceiling_yoffs != frontsector->ceiling_yoffs + + // killough 4/15/98: prevent 2s normals + // from bleeding through fake ceilings + || (frontsector->heightsec != -1 && + frontsector->ceilingpic!=skyflatnum) + + // killough 4/17/98: draw ceilings if different light levels + || backsector->ceilinglightsec != frontsector->ceilinglightsec + ; + + if (backsector->ceilingheight <= frontsector->floorheight + || backsector->floorheight >= frontsector->ceilingheight) + markceiling = markfloor = true; // closed door + + if (worldhigh < worldtop) // top texture + { + toptexture = texturetranslation[sidedef->toptexture]; + toptexheight = (linedef->r_flags & RF_TOP_TILE) ? 0 : textureheight[toptexture] >> FRACBITS; + rw_toptexturemid = linedef->flags & ML_DONTPEGTOP ? worldtop : + backsector->ceilingheight+textureheight[sidedef->toptexture]-viewz; + rw_toptexturemid += FixedMod(sidedef->rowoffset, textureheight[toptexture]); + } + + if (worldlow > worldbottom) // bottom texture + { + bottomtexture = texturetranslation[sidedef->bottomtexture]; + bottomtexheight = (linedef->r_flags & RF_BOT_TILE) ? 0 : textureheight[bottomtexture] >> FRACBITS; + rw_bottomtexturemid = linedef->flags & ML_DONTPEGBOTTOM ? worldtop : + worldlow; + rw_bottomtexturemid += FixedMod(sidedef->rowoffset, textureheight[bottomtexture]); + } + + // allocate space for masked texture tables + if (sidedef->midtexture) // masked midtexture + { + maskedtexture = true; + ds_p->maskedtexturecol = maskedtexturecol = lastopening - rw_x; + lastopening += rw_stopx - rw_x; + } + } + + // calculate rw_offset (only needed for textured lines) + segtextured = midtexture | toptexture | bottomtexture | maskedtexture; + + if (segtextured) + { + rw_offset = FixedMul (hyp, -finesine[offsetangle >>ANGLETOFINESHIFT]); + + rw_offset += sidedef->textureoffset + curline->offset; + + rw_centerangle = ANG90 + viewangle - rw_normalangle; + + rw_lightlevel = frontsector->lightlevel; + } + + // Remember the vars used to determine fractional U texture + // coords for later - POPE + ds_p->rw_offset = rw_offset; + ds_p->rw_distance = rw_distance; + ds_p->rw_centerangle = rw_centerangle; + + // if a floor / ceiling plane is on the wrong side of the view + // plane, it is definitely invisible and doesn't need to be marked. + + // killough 3/7/98: add deep water check + if (frontsector->heightsec == -1) + { + if (frontsector->floorheight >= viewz) // above view plane + markfloor = false; + if (frontsector->ceilingheight <= viewz && + frontsector->ceilingpic != skyflatnum) // below view plane + markceiling = false; + } + + // calculate incremental stepping values for texture edges + worldtop >>= 4; + worldbottom >>= 4; + + topstep = -FixedMul (rw_scalestep, worldtop); + topfrac = (centeryfrac>>4) - FixedMul (worldtop, rw_scale); + + bottomstep = -FixedMul (rw_scalestep,worldbottom); + bottomfrac = (centeryfrac>>4) - FixedMul (worldbottom, rw_scale); + + if (backsector) + { + worldhigh >>= 4; + worldlow >>= 4; + + if (worldhigh < worldtop) + { + pixhigh = (centeryfrac>>4) - FixedMul (worldhigh, rw_scale); + pixhighstep = -FixedMul (rw_scalestep,worldhigh); + } + if (worldlow > worldbottom) + { + pixlow = (centeryfrac>>4) - FixedMul (worldlow, rw_scale); + pixlowstep = -FixedMul (rw_scalestep,worldlow); + } + } + + // render it + if (markceiling) { + if (ceilingplane) // killough 4/11/98: add NULL ptr checks + ceilingplane = R_CheckPlane (ceilingplane, rw_x, rw_stopx-1); + else + markceiling = 0; + } + + if (markfloor) { + if (floorplane) // killough 4/11/98: add NULL ptr checks + /* cph 2003/04/18 - ceilingplane and floorplane might be the same + * visplane (e.g. if both skies); R_CheckPlane doesn't know about + * modifications to the plane that might happen in parallel with the check + * being made, so we have to override it and split them anyway if that is + * a possibility, otherwise the floor marking would overwrite the ceiling + * marking, resulting in HOM. */ + if (markceiling && ceilingplane == floorplane) + floorplane = R_DupPlane (floorplane, rw_x, rw_stopx-1); + else + floorplane = R_CheckPlane (floorplane, rw_x, rw_stopx-1); + else + markfloor = 0; + } + + didsolidcol = 0; + R_RenderSegLoop(); + + /* cph - if a column was made solid by this wall, we _must_ save full clipping info */ + if (backsector && didsolidcol) { + if (!(ds_p->silhouette & SIL_BOTTOM)) { + ds_p->silhouette |= SIL_BOTTOM; + ds_p->bsilheight = backsector->floorheight; + } + if (!(ds_p->silhouette & SIL_TOP)) { + ds_p->silhouette |= SIL_TOP; + ds_p->tsilheight = backsector->ceilingheight; + } + } + + // save sprite clipping info + if ((ds_p->silhouette & SIL_TOP || maskedtexture) && !ds_p->sprtopclip) + { + memcpy (lastopening, ceilingclip+start, sizeof(int)*(rw_stopx-start)); // dropoff overflow + ds_p->sprtopclip = lastopening - start; + lastopening += rw_stopx - start; + } + if ((ds_p->silhouette & SIL_BOTTOM || maskedtexture) && !ds_p->sprbottomclip) + { + memcpy (lastopening, floorclip+start, sizeof(int)*(rw_stopx-start)); // dropoff overflow + ds_p->sprbottomclip = lastopening - start; + lastopening += rw_stopx - start; + } + if (maskedtexture && !(ds_p->silhouette & SIL_TOP)) + { + ds_p->silhouette |= SIL_TOP; + ds_p->tsilheight = INT_MIN; + } + if (maskedtexture && !(ds_p->silhouette & SIL_BOTTOM)) + { + ds_p->silhouette |= SIL_BOTTOM; + ds_p->bsilheight = INT_MAX; + } + ds_p++; +} diff --git a/common/prboom/r_segs.h b/common/prboom/r_segs.h new file mode 100755 index 0000000..c5b29a6 --- /dev/null +++ b/common/prboom/r_segs.h @@ -0,0 +1,44 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Refresh module, drawing LineSegs from BSP. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __R_SEGS__ +#define __R_SEGS__ + +#ifdef __GNUG__ +#pragma interface +#endif + +void R_RenderMaskedSegRange(drawseg_t *ds, int x1, int x2); +void R_StoreWallRange(const int start, const int stop); + +#endif diff --git a/common/prboom/r_sky.c b/common/prboom/r_sky.c new file mode 100755 index 0000000..bc33c63 --- /dev/null +++ b/common/prboom/r_sky.c @@ -0,0 +1,56 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Sky rendering. The DOOM sky is a texture map like any + * wall, wrapping around. A 1024 columns equal 360 degrees. + * The default sky map is 256 columns and repeats 4 times + * on a 320 screen? + * + *-----------------------------------------------------------------------------*/ + +#ifdef __GNUG__ +#pragma implementation "r_sky.h" +#endif +#include "r_sky.h" + +// +// sky mapping +// +int skyflatnum; +int skytexture; +int skytexturemid; + +// +// R_InitSkyMap +// Called whenever the view size changes. +// +void R_InitSkyMap (void) +{ + skytexturemid = 100*FRACUNIT; +} diff --git a/common/prboom/r_sky.h b/common/prboom/r_sky.h new file mode 100755 index 0000000..1a69ae4 --- /dev/null +++ b/common/prboom/r_sky.h @@ -0,0 +1,55 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Sky rendering. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __R_SKY__ +#define __R_SKY__ + +#include "m_fixed.h" + +#ifdef __GNUG__ +#pragma interface +#endif + +/* SKY, store the number for name. */ +#define SKYFLATNAME "F_SKY1" + +/* The sky map is 256*128*4 maps. */ +#define ANGLETOSKYSHIFT 22 + +extern int skytexture; +extern int skytexturemid; + +/* Called whenever the view size changes. */ +void R_InitSkyMap(void); + +#endif diff --git a/common/prboom/r_state.h b/common/prboom/r_state.h new file mode 100755 index 0000000..1a444cb --- /dev/null +++ b/common/prboom/r_state.h @@ -0,0 +1,113 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Refresh/render internal state variables (global). + * + *-----------------------------------------------------------------------------*/ + + +#ifndef __R_STATE__ +#define __R_STATE__ + +// Need data structure definitions. +#include "d_player.h" +#include "r_data.h" + + + +// +// Refresh internal data structures, +// for rendering. +// + +// needed for texture pegging +extern fixed_t *textureheight; + +extern int scaledviewwidth; + +extern int firstflat, numflats; + +// for global animation +extern int *flattranslation; +extern int *texturetranslation; + +// Sprite.... +extern int firstspritelump; +extern int lastspritelump; +extern int numspritelumps; + +// +// Lookup tables for map data. +// +extern int numsprites; +extern spritedef_t *sprites; + +extern int numvertexes; +extern vertex_t *vertexes; + +extern int numsegs; +extern seg_t *segs; + +extern int numsectors; +extern sector_t *sectors; + +extern int numsubsectors; +extern subsector_t *subsectors; + +extern int numnodes; +extern node_t *nodes; + +extern int numlines; +extern line_t *lines; + +extern int numsides; +extern side_t *sides; + + +// +// POV data. +// +extern fixed_t viewx; +extern fixed_t viewy; +extern fixed_t viewz; +extern angle_t viewangle; +extern player_t *viewplayer; +extern angle_t clipangle; +extern int viewangletox[FINEANGLES/2]; +extern angle_t xtoviewangle[MAX_SCREENWIDTH+1]; // killough 2/8/98 +extern fixed_t rw_distance; +extern angle_t rw_normalangle; + +// angle to line origin +extern int rw_angle1; + +extern visplane_t *floorplane; +extern visplane_t *ceilingplane; + +#endif diff --git a/common/prboom/r_things.c b/common/prboom/r_things.c new file mode 100755 index 0000000..b923f1a --- /dev/null +++ b/common/prboom/r_things.c @@ -0,0 +1,1079 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Refresh of things, i.e. objects represented by sprites. + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" +#include "w_wad.h" +#include "r_main.h" +#include "r_bsp.h" +#include "r_segs.h" +#include "r_draw.h" +#include "r_things.h" +#include "r_fps.h" +#include "v_video.h" +#include "lprintf.h" + +#define MINZ (FRACUNIT*4) +#define BASEYCENTER 100 + +typedef struct { + int x1; + int x2; + int column; + int topclip; + int bottomclip; +} maskdraw_t; + +// +// Sprite rotation 0 is facing the viewer, +// rotation 1 is one angle turn CLOCKWISE around the axis. +// This is not the same as the angle, +// which increases counter clockwise (protractor). +// There was a lot of stuff grabbed wrong, so I changed it... +// + +fixed_t pspritescale; +fixed_t pspriteiscale; +// proff 11/06/98: Added for high-res +fixed_t pspriteyscale; + +// constant arrays +// used for psprite clipping and initializing clipping + +int negonearray[MAX_SCREENWIDTH]; // killough 2/8/98: // dropoff overflow +int screenheightarray[MAX_SCREENWIDTH]; // change to MAX_* // dropoff overflow + +// +// INITIALIZATION FUNCTIONS +// + +// variables used to look up and range check thing_t sprites patches + +spritedef_t *sprites; +int numsprites; + +#define MAX_SPRITE_FRAMES 29 /* Macroized -- killough 1/25/98 */ + +static spriteframe_t sprtemp[MAX_SPRITE_FRAMES]; +static int maxframe; + +// +// R_InstallSpriteLump +// Local function for R_InitSprites. +// + +static void R_InstallSpriteLump(int lump, unsigned frame, + unsigned rotation, boolean flipped) +{ + if (frame >= MAX_SPRITE_FRAMES || rotation > 8) + I_Error("R_InstallSpriteLump: Bad frame characters in lump %i", lump); + + if ((int) frame > maxframe) + maxframe = frame; + + if (rotation == 0) + { // the lump should be used for all rotations + int r; + for (r=0 ; r<8 ; r++) + if (sprtemp[frame].lump[r]==-1) + { + sprtemp[frame].lump[r] = lump - firstspritelump; + sprtemp[frame].flip[r] = (byte) flipped; + sprtemp[frame].rotate = false; //jff 4/24/98 if any subbed, rotless + } + return; + } + + // the lump is only used for one rotation + + if (sprtemp[frame].lump[--rotation] == -1) + { + sprtemp[frame].lump[rotation] = lump - firstspritelump; + sprtemp[frame].flip[rotation] = (byte) flipped; + sprtemp[frame].rotate = true; //jff 4/24/98 only change if rot used + } +} + +// +// R_InitSpriteDefs +// Pass a null terminated list of sprite names +// (4 chars exactly) to be used. +// +// Builds the sprite rotation matrixes to account +// for horizontally flipped sprites. +// +// Will report an error if the lumps are inconsistent. +// Only called at startup. +// +// Sprite lump names are 4 characters for the actor, +// a letter for the frame, and a number for the rotation. +// +// A sprite that is flippable will have an additional +// letter/number appended. +// +// The rotation character can be 0 to signify no rotations. +// +// 1/25/98, 1/31/98 killough : Rewritten for performance +// +// Empirically verified to have excellent hash +// properties across standard Doom sprites: + +#define R_SpriteNameHash(s) ((unsigned)((s)[0]-((s)[1]*3-(s)[3]*2-(s)[2])*2)) + +static void R_InitSpriteDefs(const char * const * namelist) +{ + size_t numentries = lastspritelump-firstspritelump+1; + struct { int index, next; } *hash; + int i; + + if (!numentries || !*namelist) + return; + + // count the number of sprite names + for (i=0; namelist[i]; i++) + ; + + numsprites = i; + + sprites = Z_Malloc(numsprites *sizeof(*sprites), PU_STATIC, NULL); + + memset( sprites, 0, numsprites *sizeof(*sprites) ); // JDC: Z_Malloc isn't zero filled + + // Create hash table based on just the first four letters of each sprite + // killough 1/31/98 + + hash = malloc(sizeof(*hash)*numentries); // allocate hash table + + for (i=0; (size_t)i= 0) + { + memset(sprtemp, -1, sizeof(sprtemp)); + maxframe = -1; + do + { + register lumpinfo_t *lump = lumpinfo + j + firstspritelump; + + // Fast portable comparison -- killough + // (using int pointer cast is nonportable): + + if (!((lump->name[0] ^ spritename[0]) | + (lump->name[1] ^ spritename[1]) | + (lump->name[2] ^ spritename[2]) | + (lump->name[3] ^ spritename[3]))) + { + R_InstallSpriteLump(j+firstspritelump, + lump->name[4] - 'A', + lump->name[5] - '0', + false); + if (lump->name[6]) + R_InstallSpriteLump(j+firstspritelump, + lump->name[6] - 'A', + lump->name[7] - '0', + true); + } + } + while ((j = hash[j].next) >= 0); + + // check the frames that were found for completeness + if ((sprites[i].numframes = ++maxframe)) // killough 1/31/98 + { + int frame; + for (frame = 0; frame < maxframe; frame++) + switch ((int) sprtemp[frame].rotate) + { + case -1: + // no rotations were found for that frame at all + I_Error ("R_InitSprites: No patches found " + "for %.8s frame %c", namelist[i], frame+'A'); + break; + + case 0: + // only the first rotation is needed + break; + + case 1: + // must have all 8 frames + { + int rotation; + for (rotation=0 ; rotation<8 ; rotation++) + if (sprtemp[frame].lump[rotation] == -1) + I_Error ("R_InitSprites: Sprite %.8s frame %c " + "is missing rotations", + namelist[i], frame+'A'); + break; + } + } + // allocate space for the frames present and copy sprtemp to it + sprites[i].spriteframes = + Z_Malloc (maxframe * sizeof(spriteframe_t), PU_STATIC, NULL); + memcpy (sprites[i].spriteframes, sprtemp, + maxframe*sizeof(spriteframe_t)); + } + } + } + free(hash); // free hash table +} + +// +// GAME FUNCTIONS +// + +static vissprite_t *vissprites, **vissprite_ptrs; // killough +static size_t num_vissprite, num_vissprite_alloc, num_vissprite_ptrs; + +// +// R_InitSprites +// Called at program start. +// + +void R_InitSprites(const char * const *namelist) +{ + int i; + for (i=0; i= num_vissprite_alloc) // killough + { + size_t num_vissprite_alloc_prev = num_vissprite_alloc; + + num_vissprite_alloc = num_vissprite_alloc ? num_vissprite_alloc*2 : 128; + vissprites = realloc(vissprites,num_vissprite_alloc*sizeof(*vissprites)); + + //e6y: set all fields to zero + memset(vissprites + num_vissprite_alloc_prev, 0, + (num_vissprite_alloc - num_vissprite_alloc_prev)*sizeof(*vissprites)); + } + return vissprites + num_vissprite++; +} + +// +// R_DrawMaskedColumn +// Used for sprites and masked mid textures. +// Masked means: partly transparent, i.e. stored +// in posts/runs of opaque pixels. +// + +int *mfloorclip; // dropoff overflow +int *mceilingclip; // dropoff overflow +fixed_t spryscale; +fixed_t sprtopscreen; + +void R_DrawMaskedColumn( + const rpatch_t *patch, + R_DrawColumn_f colfunc, + draw_column_vars_t *dcvars, + const rcolumn_t *column, + const rcolumn_t *prevcolumn, + const rcolumn_t *nextcolumn +) +{ + int i; + int topscreen; + int bottomscreen; + fixed_t basetexturemid = dcvars->texturemid; + + dcvars->texheight = patch->height; // killough 11/98 + for (i=0; inumPosts; i++) { + const rpost_t *post = &column->posts[i]; + + // calculate unclipped screen coordinates for post + topscreen = sprtopscreen + spryscale*post->topdelta; + bottomscreen = topscreen + spryscale*post->length; + + dcvars->yl = (topscreen+FRACUNIT-1)>>FRACBITS; + dcvars->yh = (bottomscreen-1)>>FRACBITS; + + if (dcvars->yh >= mfloorclip[dcvars->x]) + dcvars->yh = mfloorclip[dcvars->x]-1; + + if (dcvars->yl <= mceilingclip[dcvars->x]) + dcvars->yl = mceilingclip[dcvars->x]+1; + + // killough 3/2/98, 3/27/98: Failsafe against overflow/crash: + if (dcvars->yl <= dcvars->yh && dcvars->yh < viewheight) + { + dcvars->source = column->pixels + post->topdelta; + dcvars->prevsource = prevcolumn->pixels + post->topdelta; + dcvars->nextsource = nextcolumn->pixels + post->topdelta; + + dcvars->texturemid = basetexturemid - (post->topdelta<edgeslope = post->slope; + // Drawn by either R_DrawColumn + // or (SHADOW) R_DrawFuzzColumn. + dcvars->drawingmasked = 1; // POPE + colfunc (dcvars); + dcvars->drawingmasked = 0; // POPE + } + } + dcvars->texturemid = basetexturemid; +} + +// +// R_DrawVisSprite +// mfloorclip and mceilingclip should also be set. +// +// CPhipps - new wad lump handling, *'s to const*'s +static void R_DrawVisSprite(vissprite_t *vis, int x1, int x2) +{ + int texturecolumn; + fixed_t frac; + const rpatch_t *patch = R_CachePatchNum(vis->patch+firstspritelump); + R_DrawColumn_f colfunc; + draw_column_vars_t dcvars; + enum draw_filter_type_e filter; + enum draw_filter_type_e filterz; + + R_SetDefaultDrawColumnVars(&dcvars); + if (vis->isplayersprite) { + dcvars.edgetype = drawvars.patch_edges; + filter = drawvars.filterpatch; + filterz = RDRAW_FILTER_POINT; + } else { + dcvars.edgetype = drawvars.sprite_edges; + filter = drawvars.filtersprite; + filterz = drawvars.filterz; + } + + dcvars.colormap = vis->colormap; + dcvars.nextcolormap = dcvars.colormap; // for filtering -- POPE + + // killough 4/11/98: rearrange and handle translucent sprites + // mixed with translucent/non-translucenct 2s normals + + if (!dcvars.colormap) // NULL colormap = shadow draw + colfunc = R_GetDrawColumnFunc(RDC_PIPELINE_FUZZ, filter, filterz); // killough 3/14/98 + else + if (vis->mobjflags & MF_TRANSLATION) + { + colfunc = R_GetDrawColumnFunc(RDC_PIPELINE_TRANSLATED, filter, filterz); + dcvars.translation = translationtables - 256 + + ((vis->mobjflags & MF_TRANSLATION) >> (MF_TRANSSHIFT-8) ); + } + else + if (vis->mobjflags & MF_TRANSLUCENT && general_translucency) // phares + { + colfunc = R_GetDrawColumnFunc(RDC_PIPELINE_TRANSLUCENT, filter, filterz); + tranmap = main_tranmap; // killough 4/11/98 + } + else + colfunc = R_GetDrawColumnFunc(RDC_PIPELINE_STANDARD, filter, filterz); // killough 3/14/98, 4/11/98 + +// proff 11/06/98: Changed for high-res + dcvars.iscale = FixedDiv (FRACUNIT, vis->scale); + dcvars.texturemid = vis->texturemid; + frac = vis->startfrac; + if (filter == RDRAW_FILTER_LINEAR) + frac -= (FRACUNIT>>1); + spryscale = vis->scale; + sprtopscreen = centeryfrac - FixedMul(dcvars.texturemid,spryscale); + + for (dcvars.x=vis->x1 ; dcvars.x<=vis->x2 ; dcvars.x++, frac += vis->xiscale) + { + texturecolumn = frac>>FRACBITS; + dcvars.texu = frac; + + R_DrawMaskedColumn( + patch, + colfunc, + &dcvars, + R_GetPatchColumnClamped(patch, texturecolumn), + R_GetPatchColumnClamped(patch, texturecolumn-1), + R_GetPatchColumnClamped(patch, texturecolumn+1) + ); + } + R_UnlockPatchNum(vis->patch+firstspritelump); // cph - release lump +} + +// +// R_ProjectSprite +// Generates a vissprite for a thing if it might be visible. +// + +static void R_ProjectSprite (mobj_t* thing, int lightlevel) +{ + fixed_t gzt; // killough 3/27/98 + fixed_t tx; + fixed_t xscale; + int x1; + int x2; + spritedef_t *sprdef; + spriteframe_t *sprframe; + int lump; + boolean flip; + vissprite_t *vis; + fixed_t iscale; + int heightsec; // killough 3/27/98 + + // transform the origin point + fixed_t tr_x, tr_y; + fixed_t fx, fy, fz; + fixed_t gxt, gyt; + fixed_t tz; + int width; + + if (movement_smooth) + { + fx = thing->PrevX + FixedMul (tic_vars.frac, thing->x - thing->PrevX); + fy = thing->PrevY + FixedMul (tic_vars.frac, thing->y - thing->PrevY); + fz = thing->PrevZ + FixedMul (tic_vars.frac, thing->z - thing->PrevZ); + } + else + { + fx = thing->x; + fy = thing->y; + fz = thing->z; + } + tr_x = fx - viewx; + tr_y = fy - viewy; + + gxt = FixedMul(tr_x,viewcos); + gyt = -FixedMul(tr_y,viewsin); + + tz = gxt-gyt; + + // thing is behind view plane? + if (tz < MINZ) + return; + + xscale = FixedDiv(projection, tz); + + gxt = -FixedMul(tr_x,viewsin); + gyt = FixedMul(tr_y,viewcos); + tx = -(gyt+gxt); + + // too far off the side? + if (D_abs(tx)>(tz<<2)) + return; + + // decide which patch to use for sprite relative to player +#ifdef RANGECHECK + if ((unsigned) thing->sprite >= (unsigned)numsprites) + I_Error ("R_ProjectSprite: Invalid sprite number %i", thing->sprite); +#endif + + sprdef = &sprites[thing->sprite]; + +#ifdef RANGECHECK + if ((thing->frame&FF_FRAMEMASK) >= sprdef->numframes) + I_Error ("R_ProjectSprite: Invalid sprite frame %i : %i", thing->sprite, + thing->frame); +#endif + + if (!sprdef->spriteframes) + I_Error ("R_ProjectSprite: Missing spriteframes %i : %i", thing->sprite, + thing->frame); + + sprframe = &sprdef->spriteframes[thing->frame & FF_FRAMEMASK]; + + if (sprframe->rotate) + { + // choose a different rotation based on player view + angle_t ang = R_PointToAngle(fx, fy); + unsigned rot = (ang-thing->angle+(unsigned)(ANG45/2)*9)>>29; + lump = sprframe->lump[rot]; + flip = (boolean) sprframe->flip[rot]; + } + else + { + // use single rotation for all views + lump = sprframe->lump[0]; + flip = (boolean) sprframe->flip[0]; + } + + { + const rpatch_t* patch = R_CachePatchNum(lump+firstspritelump); + + /* calculate edges of the shape + * cph 2003/08/1 - fraggle points out that this offset must be flipped + * if the sprite is flipped; e.g. FreeDoom imp is messed up by this. */ + if (flip) { + tx -= (patch->width - patch->leftoffset) << FRACBITS; + } else { + tx -= patch->leftoffset << FRACBITS; + } + x1 = (centerxfrac + FixedMul(tx,xscale)) >> FRACBITS; + + tx += patch->width<> FRACBITS) - 1; + + gzt = fz + (patch->topoffset << FRACBITS); + width = patch->width; + R_UnlockPatchNum(lump+firstspritelump); + } + + // off the side? + if (x1 > viewwidth || x2 < 0) + return; + + // killough 4/9/98: clip things which are out of view due to height + // e6y: fix of hanging decoration disappearing in Batman Doom MAP02 + // centeryfrac -> viewheightfrac + if (fz > viewz + FixedDiv(viewheightfrac, xscale) || + gzt < viewz - FixedDiv(viewheightfrac-viewheight, xscale)) + return; + + // killough 3/27/98: exclude things totally separated + // from the viewer, by either water or fake ceilings + // killough 4/11/98: improve sprite clipping for underwater/fake ceilings + + heightsec = thing->subsector->sector->heightsec; + + if (heightsec != -1) // only clip things which are in special sectors + { + int phs = viewplayer->mo->subsector->sector->heightsec; + if (phs != -1 && viewz < sectors[phs].floorheight ? + fz >= sectors[heightsec].floorheight : + gzt < sectors[heightsec].floorheight) + return; + if (phs != -1 && viewz > sectors[phs].ceilingheight ? + gzt < sectors[heightsec].ceilingheight && + viewz >= sectors[heightsec].ceilingheight : + fz >= sectors[heightsec].ceilingheight) + return; + } + + // store information in a vissprite + vis = R_NewVisSprite (); + +#ifdef GL_DOOM + if (V_GetMode() == VID_MODEGL) + { + // proff 11/99: add sprite for OpenGL + vis->thing = thing; + vis->flip = flip; + vis->scale = FixedDiv(projectiony, tz); + vis->patch = lump; + gld_AddSprite(vis); + + return; + } +#endif + // killough 3/27/98: save sector for special clipping later + vis->heightsec = heightsec; + + vis->mobjflags = thing->flags; +// proff 11/06/98: Changed for high-res + vis->scale = FixedDiv(projectiony, tz); + vis->gx = fx; + vis->gy = fy; + vis->gz = fz; + vis->gzt = gzt; // killough 3/27/98 + vis->texturemid = vis->gzt - viewz; + vis->x1 = x1 < 0 ? 0 : x1; + vis->x2 = x2 >= viewwidth ? viewwidth-1 : x2; + iscale = FixedDiv (FRACUNIT, xscale); + + if (flip) + { + vis->startfrac = (width<xiscale = -iscale; + } + else + { + vis->startfrac = 0; + vis->xiscale = iscale; + } + + if (vis->x1 > x1) + vis->startfrac += vis->xiscale*(vis->x1-x1); + vis->patch = lump; + + // get light level + if (thing->flags & MF_SHADOW) + vis->colormap = NULL; // shadow draw + else if (fixedcolormap) + vis->colormap = fixedcolormap; // fixed map + else if (thing->frame & FF_FULLBRIGHT) + vis->colormap = fullcolormap; // full bright // killough 3/20/98 + else + { // diminished light + vis->colormap = R_ColourMap(lightlevel,xscale); + } +} + +// +// R_AddSprites +// During BSP traversal, this adds sprites by sector. +// +// killough 9/18/98: add lightlevel as parameter, fixing underwater lighting +void R_AddSprites(subsector_t* subsec, int lightlevel) +{ + sector_t* sec=subsec->sector; + mobj_t *thing; + + // BSP is traversed by subsector. + // A sector might have been split into several + // subsectors during BSP building. + // Thus we check whether its already added. + + if (sec->validcount == validcount) + return; + + // Well, now it will be done. + sec->validcount = validcount; + + // Handle all things in sector. + + for (thing = sec->thinglist; thing; thing = thing->snext) + R_ProjectSprite(thing, lightlevel); +} + +// +// R_DrawPSprite +// + +static void R_DrawPSprite (pspdef_t *psp, int lightlevel) +{ + int x1, x2; + spritedef_t *sprdef; + spriteframe_t *sprframe; + int lump; + boolean flip; + vissprite_t *vis; + vissprite_t avis; + int width; + fixed_t topoffset; + + avis.isplayersprite = true; + + // decide which patch to use + +#ifdef RANGECHECK + if ( (unsigned)psp->state->sprite >= (unsigned)numsprites) + I_Error ("R_ProjectSprite: Invalid sprite number %i", psp->state->sprite); +#endif + + sprdef = &sprites[psp->state->sprite]; + +#ifdef RANGECHECK + if ( (psp->state->frame & FF_FRAMEMASK) >= sprdef->numframes) + I_Error ("R_ProjectSprite: Invalid sprite frame %i : %li", + psp->state->sprite, psp->state->frame); +#endif + + sprframe = &sprdef->spriteframes[psp->state->frame & FF_FRAMEMASK]; + + lump = sprframe->lump[0]; + flip = (boolean) sprframe->flip[0]; + + { + const rpatch_t* patch = R_CachePatchNum(lump+firstspritelump); + // calculate edges of the shape + fixed_t tx; + tx = psp->sx-160*FRACUNIT; + + tx -= patch->leftoffset<>FRACBITS; + + tx += patch->width<>FRACBITS) - 1; + + width = patch->width; + topoffset = patch->topoffset< viewwidth) + return; + + // store information in a vissprite + vis = &avis; + vis->mobjflags = 0; + // killough 12/98: fix psprite positioning problem + vis->texturemid = (BASEYCENTER<sy-topoffset); + vis->x1 = x1 < 0 ? 0 : x1; + vis->x2 = x2 >= viewwidth ? viewwidth-1 : x2; +// proff 11/06/98: Added for high-res + vis->scale = pspriteyscale; + + if (flip) + { + vis->xiscale = -pspriteiscale; + vis->startfrac = (width<xiscale = pspriteiscale; + vis->startfrac = 0; + } + + if (vis->x1 > x1) + vis->startfrac += vis->xiscale*(vis->x1-x1); + + vis->patch = lump; + + if (viewplayer->powers[pw_invisibility] > 4*32 + || viewplayer->powers[pw_invisibility] & 8) + vis->colormap = NULL; // shadow draw + else if (fixedcolormap) + vis->colormap = fixedcolormap; // fixed color + else if (psp->state->frame & FF_FULLBRIGHT) + vis->colormap = fullcolormap; // full bright // killough 3/20/98 + else + // add a fudge factor to better match the original game + vis->colormap = R_ColourMap(lightlevel, + FixedMul(pspritescale, 0x2b000)); // local light + + // proff 11/99: don't use software stuff in OpenGL + if (V_GetMode() != VID_MODEGL) + { + R_DrawVisSprite(vis, vis->x1, vis->x2); + } +#ifdef GL_DOOM + else + { + int finallightlevel; + sector_t tmpsec; + int floorlightlevel, ceilinglightlevel; + + if ((vis->colormap==fixedcolormap) || (vis->colormap==fullcolormap)) + finallightlevel=255; + else + { +// finallightlevel = (viewplayer->mo->subsector->sector->lightlevel) + (extralight << LIGHTSEGSHIFT); + R_FakeFlat( viewplayer->mo->subsector->sector, &tmpsec, + &floorlightlevel, &ceilinglightlevel, false); + finallightlevel = ((floorlightlevel+ceilinglightlevel) >> 1) + (extralight << LIGHTSEGSHIFT); + + if (finallightlevel < 0) + finallightlevel = 0; + else if (finallightlevel >= 255) + finallightlevel = 255; + } + gld_DrawWeapon(lump,vis,finallightlevel); + } +#endif +} + +// +// R_DrawPlayerSprites +// + +void R_DrawPlayerSprites(void) +{ + int i, lightlevel = viewplayer->mo->subsector->sector->lightlevel; + pspdef_t *psp; + + // clip to screen bounds + mfloorclip = screenheightarray; + mceilingclip = negonearray; + + // add all active psprites + for (i=0, psp=viewplayer->psprites; istate) + R_DrawPSprite (psp, lightlevel); +} + +// +// R_SortVisSprites +// +// Rewritten by Lee Killough to avoid using unnecessary +// linked lists, and to use faster sorting algorithm. +// + +#ifdef DJGPP + +// killough 9/22/98: inlined memcpy of pointer arrays +// CPhipps - added memory as modified +#define bcopyp(d, s, n) asm(" cld; rep; movsl;" :: "D"(d), "S"(s), "c"(n) : "%cc", "%esi", "%edi", "%ecx", "memory") + +#else + +#define bcopyp(d, s, n) memcpy(d, s, (n) * sizeof(void *)) + +#endif + +// killough 9/2/98: merge sort + +static void msort(vissprite_t **s, vissprite_t **t, int n) +{ + if (n >= 16) + { + int n1 = n/2, n2 = n - n1; + vissprite_t **s1 = s, **s2 = s + n1, **d = t; + + msort(s1, t, n1); + msort(s2, t, n2); + + while ((*s1)->scale > (*s2)->scale ? + (*d++ = *s1++, --n1) : (*d++ = *s2++, --n2)); + + if (n2) + bcopyp(d, s2, n2); + else + bcopyp(d, s1, n1); + + bcopyp(s, t, n); + } + else + { + int i; + for (i = 1; i < n; i++) + { + vissprite_t *temp = s[i]; + if (s[i-1]->scale < temp->scale) + { + int j = i; + while ((s[j] = s[j-1])->scale < temp->scale && --j); + s[j] = temp; + } + } + } +} + +void R_SortVisSprites (void) +{ + if (num_vissprite) + { + int i = num_vissprite; + + // If we need to allocate more pointers for the vissprites, + // allocate as many as were allocated for sprites -- killough + // killough 9/22/98: allocate twice as many + + if (num_vissprite_ptrs < num_vissprite*2) + { + free(vissprite_ptrs); // better than realloc -- no preserving needed + vissprite_ptrs = malloc((num_vissprite_ptrs = num_vissprite_alloc*2) + * sizeof *vissprite_ptrs); + } + + while (--i>=0) + vissprite_ptrs[i] = vissprites+i; + + // killough 9/22/98: replace qsort with merge sort, since the keys + // are roughly in order to begin with, due to BSP rendering. + + msort(vissprite_ptrs, vissprite_ptrs + num_vissprite, num_vissprite); + } +} + +// +// R_DrawSprite +// + +static void R_DrawSprite (vissprite_t* spr) +{ + drawseg_t *ds; + int clipbot[MAX_SCREENWIDTH]; // killough 2/8/98: // dropoff overflow + int cliptop[MAX_SCREENWIDTH]; // change to MAX_* // dropoff overflow + int x; + int r1; + int r2; + fixed_t scale; + fixed_t lowscale; + + for (x = spr->x1 ; x<=spr->x2 ; x++) + clipbot[x] = cliptop[x] = -2; + + // Scan drawsegs from end to start for obscuring segs. + // The first drawseg that has a greater scale is the clip seg. + + // Modified by Lee Killough: + // (pointer check was originally nonportable + // and buggy, by going past LEFT end of array): + + // for (ds=ds_p-1 ; ds >= drawsegs ; ds--) old buggy code + + for (ds=ds_p ; ds-- > drawsegs ; ) // new -- killough + { // determine if the drawseg obscures the sprite + if (ds->x1 > spr->x2 || ds->x2 < spr->x1 || + (!ds->silhouette && !ds->maskedtexturecol)) + continue; // does not cover sprite + + r1 = ds->x1 < spr->x1 ? spr->x1 : ds->x1; + r2 = ds->x2 > spr->x2 ? spr->x2 : ds->x2; + + if (ds->scale1 > ds->scale2) + { + lowscale = ds->scale2; + scale = ds->scale1; + } + else + { + lowscale = ds->scale1; + scale = ds->scale2; + } + + if (scale < spr->scale || (lowscale < spr->scale && + !R_PointOnSegSide (spr->gx, spr->gy, ds->curline))) + { + if (ds->maskedtexturecol) // masked mid texture? + R_RenderMaskedSegRange(ds, r1, r2); + continue; // seg is behind sprite + } + + // clip this piece of the sprite + // killough 3/27/98: optimized and made much shorter + + if (ds->silhouette&SIL_BOTTOM && spr->gz < ds->bsilheight) //bottom sil + for (x=r1 ; x<=r2 ; x++) + if (clipbot[x] == -2) + clipbot[x] = ds->sprbottomclip[x]; + + if (ds->silhouette&SIL_TOP && spr->gzt > ds->tsilheight) // top sil + for (x=r1 ; x<=r2 ; x++) + if (cliptop[x] == -2) + cliptop[x] = ds->sprtopclip[x]; + } + + // killough 3/27/98: + // Clip the sprite against deep water and/or fake ceilings. + // killough 4/9/98: optimize by adding mh + // killough 4/11/98: improve sprite clipping for underwater/fake ceilings + // killough 11/98: fix disappearing sprites + + if (spr->heightsec != -1) // only things in specially marked sectors + { + fixed_t h,mh; + int phs = viewplayer->mo->subsector->sector->heightsec; + if ((mh = sectors[spr->heightsec].floorheight) > spr->gz && + (h = centeryfrac - FixedMul(mh-=viewz, spr->scale)) >= 0 && + (h >>= FRACBITS) < viewheight) { + if (mh <= 0 || (phs != -1 && viewz > sectors[phs].floorheight)) + { // clip bottom + for (x=spr->x1 ; x<=spr->x2 ; x++) + if (clipbot[x] == -2 || h < clipbot[x]) + clipbot[x] = h; + } + else // clip top + if (phs != -1 && viewz <= sectors[phs].floorheight) // killough 11/98 + for (x=spr->x1 ; x<=spr->x2 ; x++) + if (cliptop[x] == -2 || h > cliptop[x]) + cliptop[x] = h; + } + + if ((mh = sectors[spr->heightsec].ceilingheight) < spr->gzt && + (h = centeryfrac - FixedMul(mh-viewz, spr->scale)) >= 0 && + (h >>= FRACBITS) < viewheight) { + if (phs != -1 && viewz >= sectors[phs].ceilingheight) + { // clip bottom + for (x=spr->x1 ; x<=spr->x2 ; x++) + if (clipbot[x] == -2 || h < clipbot[x]) + clipbot[x] = h; + } + else // clip top + for (x=spr->x1 ; x<=spr->x2 ; x++) + if (cliptop[x] == -2 || h > cliptop[x]) + cliptop[x] = h; + } + } + // killough 3/27/98: end special clipping for deep water / fake ceilings + + // all clipping has been performed, so draw the sprite + // check for unclipped columns + + for (x = spr->x1 ; x<=spr->x2 ; x++) { + if (clipbot[x] == -2) + clipbot[x] = viewheight; + + if (cliptop[x] == -2) + cliptop[x] = -1; + } + + mfloorclip = clipbot; + mceilingclip = cliptop; + R_DrawVisSprite (spr, spr->x1, spr->x2); +} + +// +// R_DrawMasked +// + +void R_DrawMasked(void) +{ + int i; + drawseg_t *ds; + + R_SortVisSprites(); + + // draw all vissprites back to front + + rendered_vissprites = num_vissprite; + for (i = num_vissprite ;--i>=0; ) + R_DrawSprite(vissprite_ptrs[i]); // killough + + // render any remaining masked mid textures + + // Modified by Lee Killough: + // (pointer check was originally nonportable + // and buggy, by going past LEFT end of array): + + // for (ds=ds_p-1 ; ds >= drawsegs ; ds--) old buggy code + + for (ds=ds_p ; ds-- > drawsegs ; ) // new -- killough + if (ds->maskedtexturecol) + R_RenderMaskedSegRange(ds, ds->x1, ds->x2); + + // draw the psprites on top of everything + // but does not draw on side views + if (!viewangleoffset) + R_DrawPlayerSprites (); +} diff --git a/common/prboom/r_things.h b/common/prboom/r_things.h new file mode 100755 index 0000000..a6c504e --- /dev/null +++ b/common/prboom/r_things.h @@ -0,0 +1,72 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Rendering of moving objects, sprites. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __R_THINGS__ +#define __R_THINGS__ + +#ifdef __GNUG__ +#pragma interface +#endif + +#include "r_draw.h" + +/* Constant arrays used for psprite clipping and initializing clipping. */ + +extern int negonearray[MAX_SCREENWIDTH]; /* killough 2/8/98: */ // dropoff overflow +extern int screenheightarray[MAX_SCREENWIDTH]; /* change to MAX_* */ // dropoff overflow + +/* Vars for R_DrawMaskedColumn */ + +extern int *mfloorclip; // dropoff overflow +extern int *mceilingclip; // dropoff overflow +extern fixed_t spryscale; +extern fixed_t sprtopscreen; +extern fixed_t pspritescale; +extern fixed_t pspriteiscale; +/* proff 11/06/98: Added for high-res */ +extern fixed_t pspriteyscale; + +void R_DrawMaskedColumn(const rpatch_t *patch, + R_DrawColumn_f colfunc, + draw_column_vars_t *dcvars, + const rcolumn_t *column, + const rcolumn_t *prevcolumn, + const rcolumn_t *nextcolumn); +void R_SortVisSprites(void); +void R_AddSprites(subsector_t* subsec, int lightlevel); +void R_DrawPlayerSprites(void); +void R_InitSprites(const char * const * namelist); +void R_ClearSprites(void); +void R_DrawMasked(void); + +#endif diff --git a/common/prboom/s_sound.c b/common/prboom/s_sound.c new file mode 100755 index 0000000..715d2ba --- /dev/null +++ b/common/prboom/s_sound.c @@ -0,0 +1,751 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: Platform-independent sound code + * + *-----------------------------------------------------------------------------*/ + +// killough 3/7/98: modified to allow arbitrary listeners in spy mode +// killough 5/2/98: reindented, removed useless code, beautified + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "doomstat.h" +#include "s_sound.h" +#include "i_sound.h" +#include "i_system.h" +#include "d_main.h" +#include "r_main.h" +#include "m_random.h" +#include "w_wad.h" +#include "lprintf.h" + +// when to clip out sounds +// Does not fit the large outdoor areas. +#define S_CLIPPING_DIST (1200<>FRACBITS) + +// Adjustable by menu. +#define NORM_PITCH 128 +#define NORM_PRIORITY 64 +#define NORM_SEP 128 +#define S_STEREO_SWING (96<= prboom_2_compatibility && sfx_id == sfx_noway); // killough 4/25/98 + sfx_id &= ~PICKUP_SOUND; + + // check for bogus sound # + if (sfx_id < 1 || sfx_id > NUMSFX) + I_Error("S_StartSoundAtVolume: Bad sfx #: %d", sfx_id); + + sfx = &S_sfx[sfx_id]; + + // Initialize sound parameters + if (sfx->link) + { + pitch = sfx->pitch; + priority = sfx->priority; + volume += sfx->volume; + + if (volume < 1) + return; + + if (volume > snd_SfxVolume) + volume = snd_SfxVolume; + } + else + { + pitch = NORM_PITCH; + priority = NORM_PRIORITY; + } + + // Check to see if it is audible, modify the params + // killough 3/7/98, 4/25/98: code rearranged slightly + + if (!origin || origin == players[displayplayer].mo) { + sep = NORM_SEP; + volume *= 8; + } else + if (!S_AdjustSoundParams(players[displayplayer].mo, origin, &volume, + &sep, &pitch)) { + return; + } + else + if ( origin->x == players[displayplayer].mo->x && + origin->y == players[displayplayer].mo->y) + sep = NORM_SEP; + + // hacks to vary the sfx pitches + if (sfx_id >= sfx_sawup && sfx_id <= sfx_sawhit) + pitch += 8 - (M_Random()&15); + else + if (sfx_id != sfx_itemup && sfx_id != sfx_tink) + pitch += 16 - (M_Random()&31); + + if (pitch<0) + pitch = 0; + + if (pitch>255) + pitch = 255; + +#if 0 + // kill old sound + for (cnum=0 ; cnumlumpnum < 0 && (sfx->lumpnum = I_GetSfxLumpNum(sfx)) < 0) + return; + + // increase the usefulness + if (sfx->usefulness++ < 0) + sfx->usefulness = 1; + + // Assigns the handle to one of the channels in the mix/output buffer. + { // e6y: [Fix] Crash with zero-length sounds. + int h = I_StartSound(sfx_id, cnum, volume, sep, pitch, priority); + if (h != -1) channels[cnum].handle = h; + } +} + +void S_StartSound(void *origin, int sfx_id) +{ + S_StartSoundAtVolume(origin, sfx_id, snd_SfxVolume); +} + +void S_StopSound(void *origin) +{ + int cnum; + + //jff 1/22/98 return if sound is not enabled + if (!snd_card || nosfxparm) + return; + + for (cnum=0 ; cnumhandle); + mus_paused = true; + } +} + +void S_ResumeSound(void) +{ + //jff 1/22/98 return if music is not enabled + if (!mus_card || nomusicparm) + return; + + if (mus_playing && mus_paused) + { + I_ResumeSong(mus_playing->handle); + mus_paused = false; + } +} + + +// +// Updates music & sounds +// +void S_UpdateSounds(void* listener_p) +{ + mobj_t *listener = (mobj_t*) listener_p; + int cnum; + + //jff 1/22/98 return if sound is not enabled + if (!snd_card || nosfxparm) + return; + +#ifdef UPDATE_MUSIC + I_UpdateMusic(); +#endif + + for (cnum=0 ; cnumsfxinfo)) + { + if (I_SoundIsPlaying(c->handle)) + { + // initialize parameters + int volume = snd_SfxVolume; + int pitch = NORM_PITCH; + int sep = NORM_SEP; + + if (sfx->link) + { + pitch = sfx->pitch; + volume += sfx->volume; + if (volume < 1) + { + S_StopChannel(cnum); + continue; + } + else + if (volume > snd_SfxVolume) + volume = snd_SfxVolume; + } + + // check non-local sounds for distance clipping + // or modify their params + if (c->origin && listener_p != c->origin) { // killough 3/20/98 + if (!S_AdjustSoundParams(listener, c->origin, + &volume, &sep, &pitch)) + S_StopChannel(cnum); + else + I_UpdateSoundParams(c->handle, volume, sep, pitch); + } + } + else // if channel is allocated but sound has stopped, free it + S_StopChannel(cnum); + } + } +} + + + +void S_SetMusicVolume(int volume) +{ + //jff 1/22/98 return if music is not enabled + if (!mus_card || nomusicparm) + return; + if (volume < 0 || volume > 15) + I_Error("S_SetMusicVolume: Attempt to set music volume at %d", volume); + I_SetMusicVolume(volume); + snd_MusicVolume = volume; +} + + + +void S_SetSfxVolume(int volume) +{ + //jff 1/22/98 return if sound is not enabled + if (!snd_card || nosfxparm) + return; + if (volume < 0 || volume > 127) + I_Error("S_SetSfxVolume: Attempt to set sfx volume at %d", volume); + snd_SfxVolume = volume; +} + + + +// Starts some music with the music id found in sounds.h. +// +void S_StartMusic(int m_id) +{ + //jff 1/22/98 return if music is not enabled + if (!mus_card || nomusicparm) + return; + S_ChangeMusic(m_id, false); +} + + + +void S_ChangeMusic(int musicnum, int looping) +{ + musicinfo_t *music; + int music_file_failed; // cournia - if true load the default MIDI music + char music_filename[ 1024 ]; // cournia + + (void)music_file_failed; + (void)music_filename; + + //jff 1/22/98 return if music is not enabled + if (!mus_card || nomusicparm) + return; + + if (musicnum <= mus_None || musicnum >= NUMMUSIC) + I_Error("S_ChangeMusic: Bad music number %d", musicnum); + + music = &S_music[musicnum]; +#ifndef IPHONE // music was paused in the menu, we want it to always restart even if starting the same level again + if (mus_playing == music) + return; +#endif + +/* +#ifdef IPHONE + extern void iphonePlayMusic( const char *name ); + iphonePlayMusic( music->name ); + +#else +*/ + // shutdown old music + S_StopMusic(); + + // get lumpnum if neccessary + if (!music->lumpnum) + { + char namebuf[9]; + sprintf(namebuf, "d_%s", music->name); + music->lumpnum = W_GetNumForName(namebuf); + } + + music_file_failed = 1; + + // proff_fs - only load when from IWAD + if (lumpinfo[music->lumpnum].source == source_iwad) + { + // cournia - check to see if we can play a higher quality music file + // rather than the default MIDI + I_FindFile(S_music_files[musicnum], "", music_filename); + if ( music_filename[0] != '\0' ) + { + music_file_failed = I_RegisterMusic(music_filename, music); + free(music_filename); + } + } + + if (music_file_failed) + { + //cournia - could not load music file, play default MIDI music + + // load & register it + music->data = W_CacheLumpNum(music->lumpnum); + music->handle = I_RegisterSong(music->data, W_LumpLength(music->lumpnum)); + } + + // play it + I_PlaySong(music->handle, looping); +//#endif + + mus_playing = music; +} + + +void S_StopMusic(void) +{ + //jff 1/22/98 return if music is not enabled + if (!mus_card || nomusicparm) + return; + + if (mus_playing) + { + if (mus_paused) + I_ResumeSong(mus_playing->handle); + + I_StopSong(mus_playing->handle); + I_UnRegisterSong(mus_playing->handle); + if (mus_playing->lumpnum >= 0) + W_UnlockLumpNum(mus_playing->lumpnum); // cph - release the music data + + mus_playing->data = 0; + mus_playing = 0; + } +} + + + +void S_StopChannel(int cnum) +{ + int i; + channel_t *c = &channels[cnum]; + + //jff 1/22/98 return if sound is not enabled + if (!snd_card || nosfxparm) + return; + + if (c->sfxinfo) + { + // stop the sound playing + if (I_SoundIsPlaying(c->handle)) + I_StopSound(c->handle); + + // check to see + // if other channels are playing the sound + for (i=0 ; isfxinfo == channels[i].sfxinfo) + break; + + // degrade usefulness of sound data + c->sfxinfo->usefulness--; + c->sfxinfo = 0; + } +} + +// +// Changes volume, stereo-separation, and pitch variables +// from the norm of a sound effect to be played. +// If the sound is not audible, returns a 0. +// Otherwise, modifies parameters and returns 1. +// + +int S_AdjustSoundParams(mobj_t *listener, mobj_t *source, + int *vol, int *sep, int *pitch) +{ + fixed_t adx, ady,approx_dist; + angle_t angle; + + //jff 1/22/98 return if sound is not enabled + if (!snd_card || nosfxparm) + return 0; + + // e6y + // Fix crash when the program wants to S_AdjustSoundParams() for player + // which is not displayplayer and displayplayer was not spawned at the moment. + // It happens in multiplayer demos only. + // + // Stack trace is: + // P_SetupLevel() \ P_LoadThings() \ P_SpawnMapThing() \ P_SpawnPlayer(players[0]) \ + // P_SetupPsprites() \ P_BringUpWeapon() \ S_StartSound(players[0]->mo, sfx_sawup) \ + // S_StartSoundAtVolume() \ S_AdjustSoundParams(players[displayplayer]->mo, ...); + // players[displayplayer]->mo is NULL + // + // There is no more crash on e1cmnet3.lmp between e1m2 and e1m3 + // http://competn.doom2.net/pub/compet-n/doom/coop/movies/e1cmnet3.zip + if (!listener) + return 0; + + // calculate the distance to sound origin + // and clip it if necessary + adx = D_abs(listener->x - source->x); + ady = D_abs(listener->y - source->y); + + // From _GG1_ p.428. Appox. eucledian distance fast. + approx_dist = adx + ady - ((adx < ady ? adx : ady)>>1); + + if (!approx_dist) // killough 11/98: handle zero-distance as special case + { + *sep = NORM_SEP; + *vol = snd_SfxVolume * 8; // JDC: plasma fire sounds were 1/8 volume without this + return *vol > 0; + } + + if (approx_dist > S_CLIPPING_DIST) + return 0; + + // angle of source to listener + angle = R_PointToAngle2(listener->x, listener->y, source->x, source->y); + + if (angle <= listener->angle) + angle += 0xffffffff; + angle -= listener->angle; + angle >>= ANGLETOFINESHIFT; + + // stereo separation + *sep = 128 - (FixedMul(S_STEREO_SWING,finesine[angle])>>FRACBITS); + + // volume calculation + if (approx_dist < S_CLOSE_DIST) + *vol = snd_SfxVolume*8; + else + // distance effect + *vol = (snd_SfxVolume * ((S_CLIPPING_DIST-approx_dist)>>FRACBITS) * 8) + / S_ATTENUATOR; + + return (*vol > 0); +} + +// +// S_getChannel : +// If none available, return -1. Otherwise channel #. +// +// killough 4/25/98: made static, added is_pickup argument +#ifndef IPHONE +static int S_getChannel(void *origin, sfxinfo_t *sfxinfo, int is_pickup) +{ + // channel number to use + int cnum; + channel_t *c; + + //jff 1/22/98 return if sound is not enabled + if (!snd_card || nosfxparm) + return -1; + + // Find an open channel + for (cnum=0; cnumpriority >= sfxinfo->priority) + break; + if (cnum == numChannels) + return -1; // No lower priority. Sorry, Charlie. + else + S_StopChannel(cnum); // Otherwise, kick out lower priority. + } + + c = &channels[cnum]; // channel is decided to be cnum. + c->sfxinfo = sfxinfo; + c->origin = origin; + c->is_pickup = is_pickup; // killough 4/25/98 + return cnum; +} +#endif diff --git a/common/prboom/s_sound.h b/common/prboom/s_sound.h new file mode 100755 index 0000000..ac72d70 --- /dev/null +++ b/common/prboom/s_sound.h @@ -0,0 +1,97 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * The not so system specific sound interface. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __S_SOUND__ +#define __S_SOUND__ + + +// +// Initializes sound stuff, including volume +// Sets channels, SFX and music volume, +// allocates channel buffer, sets S_sfx lookup. +// +void S_Init(int sfxVolume, int musicVolume); + +// Kills all sounds +void S_Stop(void); + +// +// Per level startup code. +// Kills playing sounds at start of level, +// determines music if any, changes music. +// +void S_Start(void); + +// +// Start sound for thing at +// using from sounds.h +// +void S_StartSound(void *origin, int sound_id); + +// Will start a sound at a given volume. +void S_StartSoundAtVolume(void *origin, int sound_id, int volume); + +// killough 4/25/98: mask used to indicate sound origin is player item pickup +#define PICKUP_SOUND (0x8000) + +// Stop sound for thing at +void S_StopSound(void* origin); + +// Start music using from sounds.h +void S_StartMusic(int music_id); + +// Start music using from sounds.h, and set whether looping +void S_ChangeMusic(int music_id, int looping); + +// Stops the music fer sure. +void S_StopMusic(void); + +// Stop and resume music, during game PAUSE. +void S_PauseSound(void); +void S_ResumeSound(void); + +// +// Updates music & sounds +// +void S_UpdateSounds(void* listener); +void S_SetMusicVolume(int volume); +void S_SetSfxVolume(int volume); + +// machine-independent sound params +extern int default_numChannels; +extern int numChannels; + +//jff 3/17/98 holds last IDMUS number, or -1 +extern int idmusnum; + +#endif diff --git a/common/prboom/sounds.c b/common/prboom/sounds.c new file mode 100755 index 0000000..2875e52 --- /dev/null +++ b/common/prboom/sounds.c @@ -0,0 +1,247 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Created by a sound utility. + * Kept as a sample, DOOM2 sounds. + * + *-----------------------------------------------------------------------------*/ + +// killough 5/3/98: reformatted + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "doomtype.h" +#include "sounds.h" + +// +// Information about all the music +// + +musicinfo_t S_music[] = { + { NULL, 0, NULL, 0 }, + { "e1m1", 0, NULL, 0 }, + { "e1m2", 0, NULL, 0 }, + { "e1m3", 0, NULL, 0 }, + { "e1m4", 0, NULL, 0 }, + { "e1m5", 0, NULL, 0 }, + { "e1m6", 0, NULL, 0 }, + { "e1m7", 0, NULL, 0 }, + { "e1m8", 0, NULL, 0 }, + { "e1m9", 0, NULL, 0 }, + { "e2m1", 0, NULL, 0 }, + { "e2m2", 0, NULL, 0 }, + { "e2m3", 0, NULL, 0 }, + { "e2m4", 0, NULL, 0 }, + { "e2m5", 0, NULL, 0 }, + { "e2m6", 0, NULL, 0 }, + { "e2m7", 0, NULL, 0 }, + { "e2m8", 0, NULL, 0 }, + { "e2m9", 0, NULL, 0 }, + { "e3m1", 0, NULL, 0 }, + { "e3m2", 0, NULL, 0 }, + { "e3m3", 0, NULL, 0 }, + { "e3m4", 0, NULL, 0 }, + { "e3m5", 0, NULL, 0 }, + { "e3m6", 0, NULL, 0 }, + { "e3m7", 0, NULL, 0 }, + { "e3m8", 0, NULL, 0 }, + { "e3m9", 0, NULL, 0 }, + { "inter", 0, NULL, 0 }, + { "intro", 0, NULL, 0 }, + { "bunny", 0, NULL, 0 }, + { "victor", 0, NULL, 0 }, + { "introa", 0, NULL, 0 }, + { "runnin", 0, NULL, 0 }, + { "stalks", 0, NULL, 0 }, + { "countd", 0, NULL, 0 }, + { "betwee", 0, NULL, 0 }, + { "doom", 0, NULL, 0 }, + { "the_da", 0, NULL, 0 }, + { "shawn", 0, NULL, 0 }, + { "ddtblu", 0, NULL, 0 }, + { "in_cit", 0, NULL, 0 }, + { "dead", 0, NULL, 0 }, + { "stlks2", 0, NULL, 0 }, + { "theda2", 0, NULL, 0 }, + { "doom2", 0, NULL, 0 }, + { "ddtbl2", 0, NULL, 0 }, + { "runni2", 0, NULL, 0 }, + { "dead2", 0, NULL, 0 }, + { "stlks3", 0, NULL, 0 }, + { "romero", 0, NULL, 0 }, + { "shawn2", 0, NULL, 0 }, + { "messag", 0, NULL, 0 }, + { "count2", 0, NULL, 0 }, + { "ddtbl3", 0, NULL, 0 }, + { "ampie", 0, NULL, 0 }, + { "theda3", 0, NULL, 0 }, + { "adrian", 0, NULL, 0 }, + { "messg2", 0, NULL, 0 }, + { "romer2", 0, NULL, 0 }, + { "tense", 0, NULL, 0 }, + { "shawn3", 0, NULL, 0 }, + { "openin", 0, NULL, 0 }, + { "evil", 0, NULL, 0 }, + { "ultima", 0, NULL, 0 }, + { "read_m", 0, NULL, 0 }, + { "dm2ttl", 0, NULL, 0 }, + { "dm2int", 0, NULL, 0 }, +}; + + +// +// Information about all the sfx +// + +sfxinfo_t S_sfx[] = { + // S_sfx[0] needs to be a dummy for odd reasons. + { "none", false, 0, 0, -1, -1, 0, 0, 0 }, + + { "pistol", false, 64, 0, -1, -1, 0, 0, 0 }, + { "shotgn", false, 64, 0, -1, -1, 0, 0, 0 }, + { "sgcock", false, 64, 0, -1, -1, 0, 0, 0 }, + { "dshtgn", false, 64, 0, -1, -1, 0, 0, 0 }, + { "dbopn", false, 64, 0, -1, -1, 0, 0, 0 }, + { "dbcls", false, 64, 0, -1, -1, 0, 0, 0 }, + { "dbload", false, 64, 0, -1, -1, 0, 0, 0 }, + { "plasma", false, 64, 0, -1, -1, 0, 0, 0 }, + { "bfg", false, 64, 0, -1, -1, 0, 0, 0 }, + { "sawup", false, 64, 0, -1, -1, 0, 0, 0 }, + { "sawidl", false, 118, 0, -1, -1, 0, 0, 0 }, + { "sawful", false, 64, 0, -1, -1, 0, 0, 0 }, + { "sawhit", false, 64, 0, -1, -1, 0, 0, 0 }, + { "rlaunc", false, 64, 0, -1, -1, 0, 0, 0 }, + { "rxplod", false, 70, 0, -1, -1, 0, 0, 0 }, + { "firsht", false, 70, 0, -1, -1, 0, 0, 0 }, + { "firxpl", false, 70, 0, -1, -1, 0, 0, 0 }, + { "pstart", false, 100, 0, -1, -1, 0, 0, 0 }, + { "pstop", false, 100, 0, -1, -1, 0, 0, 0 }, + { "doropn", false, 100, 0, -1, -1, 0, 0, 0 }, + { "dorcls", false, 100, 0, -1, -1, 0, 0, 0 }, + { "stnmov", false, 119, 0, -1, -1, 0, 0, 0 }, + { "swtchn", false, 78, 0, -1, -1, 0, 0, 0 }, + { "swtchx", false, 78, 0, -1, -1, 0, 0, 0 }, + { "plpain", false, 96, 0, -1, -1, 0, 0, 0 }, + { "dmpain", false, 96, 0, -1, -1, 0, 0, 0 }, + { "popain", false, 96, 0, -1, -1, 0, 0, 0 }, + { "vipain", false, 96, 0, -1, -1, 0, 0, 0 }, + { "mnpain", false, 96, 0, -1, -1, 0, 0, 0 }, + { "pepain", false, 96, 0, -1, -1, 0, 0, 0 }, + { "slop", false, 78, 0, -1, -1, 0, 0, 0 }, + { "itemup", true, 78, 0, -1, -1, 0, 0, 0 }, + { "wpnup", true, 78, 0, -1, -1, 0, 0, 0 }, + { "oof", false, 96, 0, -1, -1, 0, 0, 0 }, + { "telept", false, 32, 0, -1, -1, 0, 0, 0 }, + { "posit1", true, 98, 0, -1, -1, 0, 0, 0 }, + { "posit2", true, 98, 0, -1, -1, 0, 0, 0 }, + { "posit3", true, 98, 0, -1, -1, 0, 0, 0 }, + { "bgsit1", true, 98, 0, -1, -1, 0, 0, 0 }, + { "bgsit2", true, 98, 0, -1, -1, 0, 0, 0 }, + { "sgtsit", true, 98, 0, -1, -1, 0, 0, 0 }, + { "cacsit", true, 98, 0, -1, -1, 0, 0, 0 }, + { "brssit", true, 94, 0, -1, -1, 0, 0, 0 }, + { "cybsit", true, 92, 0, -1, -1, 0, 0, 0 }, + { "spisit", true, 90, 0, -1, -1, 0, 0, 0 }, + { "bspsit", true, 90, 0, -1, -1, 0, 0, 0 }, + { "kntsit", true, 90, 0, -1, -1, 0, 0, 0 }, + { "vilsit", true, 90, 0, -1, -1, 0, 0, 0 }, + { "mansit", true, 90, 0, -1, -1, 0, 0, 0 }, + { "pesit", true, 90, 0, -1, -1, 0, 0, 0 }, + { "sklatk", false, 70, 0, -1, -1, 0, 0, 0 }, + { "sgtatk", false, 70, 0, -1, -1, 0, 0, 0 }, + { "skepch", false, 70, 0, -1, -1, 0, 0, 0 }, + { "vilatk", false, 70, 0, -1, -1, 0, 0, 0 }, + { "claw", false, 70, 0, -1, -1, 0, 0, 0 }, + { "skeswg", false, 70, 0, -1, -1, 0, 0, 0 }, + { "pldeth", false, 32, 0, -1, -1, 0, 0, 0 }, + { "pdiehi", false, 32, 0, -1, -1, 0, 0, 0 }, + { "podth1", false, 70, 0, -1, -1, 0, 0, 0 }, + { "podth2", false, 70, 0, -1, -1, 0, 0, 0 }, + { "podth3", false, 70, 0, -1, -1, 0, 0, 0 }, + { "bgdth1", false, 70, 0, -1, -1, 0, 0, 0 }, + { "bgdth2", false, 70, 0, -1, -1, 0, 0, 0 }, + { "sgtdth", false, 70, 0, -1, -1, 0, 0, 0 }, + { "cacdth", false, 70, 0, -1, -1, 0, 0, 0 }, + { "skldth", false, 70, 0, -1, -1, 0, 0, 0 }, + { "brsdth", false, 32, 0, -1, -1, 0, 0, 0 }, + { "cybdth", false, 32, 0, -1, -1, 0, 0, 0 }, + { "spidth", false, 32, 0, -1, -1, 0, 0, 0 }, + { "bspdth", false, 32, 0, -1, -1, 0, 0, 0 }, + { "vildth", false, 32, 0, -1, -1, 0, 0, 0 }, + { "kntdth", false, 32, 0, -1, -1, 0, 0, 0 }, + { "pedth", false, 32, 0, -1, -1, 0, 0, 0 }, + { "skedth", false, 32, 0, -1, -1, 0, 0, 0 }, + { "posact", true, 120, 0, -1, -1, 0, 0, 0 }, + { "bgact", true, 120, 0, -1, -1, 0, 0, 0 }, + { "dmact", true, 120, 0, -1, -1, 0, 0, 0 }, + { "bspact", true, 100, 0, -1, -1, 0, 0, 0 }, + { "bspwlk", true, 100, 0, -1, -1, 0, 0, 0 }, + { "vilact", true, 100, 0, -1, -1, 0, 0, 0 }, + { "noway", false, 78, 0, -1, -1, 0, 0, 0 }, + { "barexp", false, 60, 0, -1, -1, 0, 0, 0 }, + { "punch", false, 64, 0, -1, -1, 0, 0, 0 }, + { "hoof", false, 70, 0, -1, -1, 0, 0, 0 }, + { "metal", false, 70, 0, -1, -1, 0, 0, 0 }, + { "chgun", false, 64, &S_sfx[sfx_pistol], 150, 0, 0, 0, 0 }, + { "tink", false, 60, 0, -1, -1, 0, 0, 0 }, + { "bdopn", false, 100, 0, -1, -1, 0, 0, 0 }, + { "bdcls", false, 100, 0, -1, -1, 0, 0, 0 }, + { "itmbk", false, 100, 0, -1, -1, 0, 0, 0 }, + { "flame", false, 32, 0, -1, -1, 0, 0, 0 }, + { "flamst", false, 32, 0, -1, -1, 0, 0, 0 }, + { "getpow", false, 60, 0, -1, -1, 0, 0, 0 }, + { "bospit", false, 70, 0, -1, -1, 0, 0, 0 }, + { "boscub", false, 70, 0, -1, -1, 0, 0, 0 }, + { "bossit", false, 70, 0, -1, -1, 0, 0, 0 }, + { "bospn", false, 70, 0, -1, -1, 0, 0, 0 }, + { "bosdth", false, 70, 0, -1, -1, 0, 0, 0 }, + { "manatk", false, 70, 0, -1, -1, 0, 0, 0 }, + { "mandth", false, 70, 0, -1, -1, 0, 0, 0 }, + { "sssit", false, 70, 0, -1, -1, 0, 0, 0 }, + { "ssdth", false, 70, 0, -1, -1, 0, 0, 0 }, + { "keenpn", false, 70, 0, -1, -1, 0, 0, 0 }, + { "keendt", false, 70, 0, -1, -1, 0, 0, 0 }, + { "skeact", false, 70, 0, -1, -1, 0, 0, 0 }, + { "skesit", false, 70, 0, -1, -1, 0, 0, 0 }, + { "skeatk", false, 70, 0, -1, -1, 0, 0, 0 }, + { "radio", false, 60, 0, -1, -1, 0, 0, 0 }, + +#ifdef DOGS + // killough 11/98: dog sounds + { "dgsit", false, 98, 0, -1, -1, 0 }, + { "dgatk", false, 70, 0, -1, -1, 0 }, + { "dgact", false, 120, 0, -1, -1, 0 }, + { "dgdth", false, 70, 0, -1, -1, 0 }, + { "dgpain", false, 96, 0, -1, -1, 0 }, +#endif +}; diff --git a/common/prboom/sounds.h b/common/prboom/sounds.h new file mode 100755 index 0000000..0f82333 --- /dev/null +++ b/common/prboom/sounds.h @@ -0,0 +1,305 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Created by the sound utility written by Dave Taylor. + * Kept as a sample, DOOM2 sounds. Frozen. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __SOUNDS__ +#define __SOUNDS__ + +// +// SoundFX struct. +// + +struct sfxinfo_struct; + +typedef struct sfxinfo_struct sfxinfo_t; + +struct sfxinfo_struct { + + // up to 6-character name + const char *name; // CPhipps - const + + // Sfx singularity (only one at a time) + int singularity; + + // Sfx priority + int priority; + + // referenced sound if a link + sfxinfo_t *link; + + // pitch if a link + int pitch; + + // volume if a link + int volume; + + // sound data + void *data; + + // this is checked every second to see if sound + // can be thrown out (if 0, then decrement, if -1, + // then throw out, if > 0, then it is in use) + int usefulness; + + // lump number of sfx + int lumpnum; +}; + +// +// MusicInfo struct. +// + +typedef struct { + // up to 6-character name + const char *name; // CPhipps - const + + // lump number of music + int lumpnum; + + /* music data - cphipps 4/11 made const void* */ + const void *data; + + // music handle once registered + int handle; +} musicinfo_t; + +// the complete set of sound effects +extern sfxinfo_t S_sfx[]; + +// the complete set of music +extern musicinfo_t S_music[]; + +// +// Identifiers for all music in game. +// + +typedef enum { + mus_None, + mus_e1m1, + mus_e1m2, + mus_e1m3, + mus_e1m4, + mus_e1m5, + mus_e1m6, + mus_e1m7, + mus_e1m8, + mus_e1m9, + mus_e2m1, + mus_e2m2, + mus_e2m3, + mus_e2m4, + mus_e2m5, + mus_e2m6, + mus_e2m7, + mus_e2m8, + mus_e2m9, + mus_e3m1, + mus_e3m2, + mus_e3m3, + mus_e3m4, + mus_e3m5, + mus_e3m6, + mus_e3m7, + mus_e3m8, + mus_e3m9, + mus_inter, + mus_intro, + mus_bunny, + mus_victor, + mus_introa, + mus_runnin, + mus_stalks, + mus_countd, + mus_betwee, + mus_doom, + mus_the_da, + mus_shawn, + mus_ddtblu, + mus_in_cit, + mus_dead, + mus_stlks2, + mus_theda2, + mus_doom2, + mus_ddtbl2, + mus_runni2, + mus_dead2, + mus_stlks3, + mus_romero, + mus_shawn2, + mus_messag, + mus_count2, + mus_ddtbl3, + mus_ampie, + mus_theda3, + mus_adrian, + mus_messg2, + mus_romer2, + mus_tense, + mus_shawn3, + mus_openin, + mus_evil, + mus_ultima, + mus_read_m, + mus_dm2ttl, + mus_dm2int, + NUMMUSIC +} musicenum_t; + +// +// Identifiers for all sfx in game. +// + +typedef enum { + sfx_None, + sfx_pistol, + sfx_shotgn, + sfx_sgcock, + sfx_dshtgn, + sfx_dbopn, + sfx_dbcls, + sfx_dbload, + sfx_plasma, + sfx_bfg, + sfx_sawup, + sfx_sawidl, + sfx_sawful, + sfx_sawhit, + sfx_rlaunc, + sfx_rxplod, + sfx_firsht, + sfx_firxpl, + sfx_pstart, + sfx_pstop, + sfx_doropn, + sfx_dorcls, + sfx_stnmov, + sfx_swtchn, + sfx_swtchx, + sfx_plpain, + sfx_dmpain, + sfx_popain, + sfx_vipain, + sfx_mnpain, + sfx_pepain, + sfx_slop, + sfx_itemup, + sfx_wpnup, + sfx_oof, + sfx_telept, + sfx_posit1, + sfx_posit2, + sfx_posit3, + sfx_bgsit1, + sfx_bgsit2, + sfx_sgtsit, + sfx_cacsit, + sfx_brssit, + sfx_cybsit, + sfx_spisit, + sfx_bspsit, + sfx_kntsit, + sfx_vilsit, + sfx_mansit, + sfx_pesit, + sfx_sklatk, + sfx_sgtatk, + sfx_skepch, + sfx_vilatk, + sfx_claw, + sfx_skeswg, + sfx_pldeth, + sfx_pdiehi, + sfx_podth1, + sfx_podth2, + sfx_podth3, + sfx_bgdth1, + sfx_bgdth2, + sfx_sgtdth, + sfx_cacdth, + sfx_skldth, + sfx_brsdth, + sfx_cybdth, + sfx_spidth, + sfx_bspdth, + sfx_vildth, + sfx_kntdth, + sfx_pedth, + sfx_skedth, + sfx_posact, + sfx_bgact, + sfx_dmact, + sfx_bspact, + sfx_bspwlk, + sfx_vilact, + sfx_noway, + sfx_barexp, + sfx_punch, + sfx_hoof, + sfx_metal, + sfx_chgun, + sfx_tink, + sfx_bdopn, + sfx_bdcls, + sfx_itmbk, + sfx_flame, + sfx_flamst, + sfx_getpow, + sfx_bospit, + sfx_boscub, + sfx_bossit, + sfx_bospn, + sfx_bosdth, + sfx_manatk, + sfx_mandth, + sfx_sssit, + sfx_ssdth, + sfx_keenpn, + sfx_keendt, + sfx_skeact, + sfx_skesit, + sfx_skeatk, + sfx_radio, + +#ifdef DOGS + /* killough 11/98: dog sounds */ + sfx_dgsit, + sfx_dgatk, + sfx_dgact, + sfx_dgdth, + sfx_dgpain, +#endif + + NUMSFX +} sfxenum_t; + +#endif diff --git a/common/prboom/st_lib.c b/common/prboom/st_lib.c new file mode 100755 index 0000000..87504d4 --- /dev/null +++ b/common/prboom/st_lib.c @@ -0,0 +1,374 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * The status bar widget code. + * + *-----------------------------------------------------------------------------*/ + +#include "doomdef.h" +#include "doomstat.h" +#include "v_video.h" +#include "w_wad.h" +#include "st_stuff.h" +#include "st_lib.h" +#include "r_main.h" +#include "lprintf.h" + +int sts_always_red; //jff 2/18/98 control to disable status color changes +int sts_pct_always_gray; // killough 2/21/98: always gray %'s? bug or feature? + +// +// STlib_init() +// +void STlib_init(void) +{ + // cph - no longer hold STMINUS pointer +} + +// +// STlib_initNum() +// +// Initializes an st_number_t widget +// +// Passed the widget, its position, the patches for the digits, a pointer +// to the value displayed, a pointer to the on/off control, and the width +// Returns nothing +// +void STlib_initNum +( st_number_t* n, + int x, + int y, + const patchnum_t* pl, + int* num, + boolean* on, + int width ) +{ + n->x = x; + n->y = y; + n->oldnum = 0; + n->width = width; + n->num = num; + n->on = on; + n->p = pl; +} + +/* + * STlib_drawNum() + * + * A fairly efficient way to draw a number based on differences from the + * old number. + * + * Passed a st_number_t widget, a color range for output, and a flag + * indicating whether refresh is needed. + * Returns nothing + * + * jff 2/16/98 add color translation to digit output + * cphipps 10/99 - const pointer to colour trans table, made function static + */ +static void STlib_drawNum +( st_number_t* n, + int cm, + boolean refresh ) +{ + + int numdigits = n->width; + int num = *n->num; + + int w = n->p[0].width; + int h = n->p[0].height; + int x = n->x; + + int neg; + + // leban 1/20/99: + // strange that somebody went through all the work to draw only the + // differences, and then went and constantly redrew all the numbers. + // return without drawing if the number didn't change and the bar + // isn't refreshing. + if(n->oldnum == num && !refresh) + return; + + // CPhipps - compact some code, use num instead of *n->num + if ((neg = (n->oldnum = num) < 0)) + { + if (numdigits == 2 && num < -9) + num = -9; + else if (numdigits == 3 && num < -99) + num = -99; + + num = -num; + } + + // clear the area + x = n->x - numdigits*w; + +#ifdef RANGECHECK + if (n->y - ST_Y < 0) + I_Error("STlib_drawNum: n->y - ST_Y < 0"); +#endif + + V_CopyRect(x, n->y - ST_Y, BG, w*numdigits, h, x, n->y, FG, VPT_STRETCH); + + // if non-number, do not draw it + if (num == 1994) + return; + + x = n->x; + + //jff 2/16/98 add color translation to digit output + // in the special case of 0, you draw 0 + if (!num) + // CPhipps - patch drawing updated, reformatted + V_DrawNumPatch(x - w, n->y, FG, n->p[0].lumpnum, cm, + (((cm!=CR_DEFAULT) && !sts_always_red) ? VPT_TRANS : VPT_NONE) | VPT_STRETCH); + + // draw the new number + //jff 2/16/98 add color translation to digit output + while (num && numdigits--) { + // CPhipps - patch drawing updated, reformatted + x -= w; + V_DrawNumPatch(x, n->y, FG, n->p[num % 10].lumpnum, cm, + (((cm!=CR_DEFAULT) && !sts_always_red) ? VPT_TRANS : VPT_NONE) | VPT_STRETCH); + num /= 10; + } + + // draw a minus sign if necessary + //jff 2/16/98 add color translation to digit output + // cph - patch drawing updated, load by name instead of acquiring pointer earlier + if (neg) + V_DrawNamePatch(x - w, n->y, FG, "STTMINUS", cm, + (((cm!=CR_DEFAULT) && !sts_always_red) ? VPT_TRANS : VPT_NONE) | VPT_STRETCH); +} + +/* + * STlib_updateNum() + * + * Draws a number conditionally based on the widget's enable + * + * Passed a number widget, the output color range, and a refresh flag + * Returns nothing + * + * jff 2/16/98 add color translation to digit output + * cphipps 10/99 - make that pointer const + */ +void STlib_updateNum +( st_number_t* n, + int cm, + boolean refresh ) +{ + if (*n->on) STlib_drawNum(n, cm, refresh); +} + +// +// STlib_initPercent() +// +// Initialize a st_percent_t number with percent sign widget +// +// Passed a st_percent_t widget, the position, the digit patches, a pointer +// to the number to display, a pointer to the enable flag, and patch +// for the percent sign. +// Returns nothing. +// +void STlib_initPercent +( st_percent_t* p, + int x, + int y, + const patchnum_t* pl, + int* num, + boolean* on, + const patchnum_t* percent ) +{ + STlib_initNum(&p->n, x, y, pl, num, on, 3); + p->p = percent; +} + +/* + * STlib_updatePercent() + * + * Draws a number/percent conditionally based on the widget's enable + * + * Passed a precent widget, the output color range, and a refresh flag + * Returns nothing + * + * jff 2/16/98 add color translation to digit output + * cphipps - const for pointer to the colour translation table + */ + +void STlib_updatePercent +( st_percent_t* per, + int cm, + int refresh ) +{ + if (*per->n.on && (refresh || (per->n.oldnum != *per->n.num))) { + // killough 2/21/98: fix percents not updated; + /* CPhipps - make %'s only be updated if number changed */ + // CPhipps - patch drawing updated + V_DrawNumPatch(per->n.x, per->n.y, FG, per->p->lumpnum, + sts_pct_always_gray ? CR_GRAY : cm, + (sts_always_red ? VPT_NONE : VPT_TRANS) | VPT_STRETCH); + } + + STlib_updateNum(&per->n, cm, refresh); +} + +// +// STlib_initMultIcon() +// +// Initialize a st_multicon_t widget, used for a multigraphic display +// like the status bar's keys. +// +// Passed a st_multicon_t widget, the position, the graphic patches, a pointer +// to the numbers representing what to display, and pointer to the enable flag +// Returns nothing. +// +void STlib_initMultIcon +( st_multicon_t* i, + int x, + int y, + const patchnum_t* il, + int* inum, + boolean* on ) +{ + i->x = x; + i->y = y; + i->oldinum = -1; + i->inum = inum; + i->on = on; + i->p = il; +} + +// +// STlib_updateMultIcon() +// +// Draw a st_multicon_t widget, used for a multigraphic display +// like the status bar's keys. Displays each when the control +// numbers change or refresh is true +// +// Passed a st_multicon_t widget, and a refresh flag +// Returns nothing. +// +void STlib_updateMultIcon +( st_multicon_t* mi, + boolean refresh ) +{ + int w; + int h; + int x; + int y; + + if (*mi->on && (mi->oldinum != *mi->inum || refresh)) + { + if (mi->oldinum != -1) + { + x = mi->x - mi->p[mi->oldinum].leftoffset; + y = mi->y - mi->p[mi->oldinum].topoffset; + w = mi->p[mi->oldinum].width; + h = mi->p[mi->oldinum].height; + +#ifdef RANGECHECK + if (y - ST_Y < 0) + I_Error("STlib_updateMultIcon: y - ST_Y < 0"); +#endif + + V_CopyRect(x, y-ST_Y, BG, w, h, x, y, FG, VPT_STRETCH); + } + if (*mi->inum != -1) // killough 2/16/98: redraw only if != -1 + V_DrawNumPatch(mi->x, mi->y, FG, mi->p[*mi->inum].lumpnum, CR_DEFAULT, VPT_STRETCH); + mi->oldinum = *mi->inum; + } +} + +// +// STlib_initBinIcon() +// +// Initialize a st_binicon_t widget, used for a multinumber display +// like the status bar's weapons, that are present or not. +// +// Passed a st_binicon_t widget, the position, the digit patches, a pointer +// to the flags representing what is displayed, and pointer to the enable flag +// Returns nothing. +// +void STlib_initBinIcon +( st_binicon_t* b, + int x, + int y, + const patchnum_t* i, + boolean* val, + boolean* on ) +{ + b->x = x; + b->y = y; + b->oldval = 0; + b->val = val; + b->on = on; + b->p = i; +} + +// +// STlib_updateBinIcon() +// +// DInitialize a st_binicon_t widget, used for a multinumber display +// like the status bar's weapons, that are present or not. +// +// Draw a st_binicon_t widget, used for a multinumber display +// like the status bar's weapons that are present or not. Displays each +// when the control flag changes or refresh is true +// +// Passed a st_binicon_t widget, and a refresh flag +// Returns nothing. +// +void STlib_updateBinIcon +( st_binicon_t* bi, + boolean refresh ) +{ + int x; + int y; + int w; + int h; + + if (*bi->on && (bi->oldval != *bi->val || refresh)) + { + x = bi->x - bi->p->leftoffset; + y = bi->y - bi->p->topoffset; + w = bi->p->width; + h = bi->p->height; + +#ifdef RANGECHECK + if (y - ST_Y < 0) + I_Error("STlib_updateBinIcon: y - ST_Y < 0"); +#endif + + if (*bi->val) + V_DrawNumPatch(bi->x, bi->y, FG, bi->p->lumpnum, CR_DEFAULT, VPT_STRETCH); + else + V_CopyRect(x, y-ST_Y, BG, w, h, x, y, FG, VPT_STRETCH); + + bi->oldval = *bi->val; + } +} diff --git a/common/prboom/st_lib.h b/common/prboom/st_lib.h new file mode 100755 index 0000000..769a75e --- /dev/null +++ b/common/prboom/st_lib.h @@ -0,0 +1,209 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * The status bar widget definitions and prototypes + * + *-----------------------------------------------------------------------------*/ + +#ifndef __STLIB__ +#define __STLIB__ + +// We are referring to patches. +#include "r_defs.h" +#include "v_video.h" // color ranges + +// +// Background and foreground screen numbers +// +#define BG 4 +#define FG 0 + +// +// Typedefs of widgets +// + +// Number widget + +typedef struct +{ + // upper right-hand corner + // of the number (right-justified) + int x; + int y; + + // max # of digits in number + int width; + + // last number value + int oldnum; + + // pointer to current value + int* num; + + // pointer to boolean stating + // whether to update number + boolean* on; + + // list of patches for 0-9 + const patchnum_t* p; + + // user data + int data; +} st_number_t; + +// Percent widget ("child" of number widget, +// or, more precisely, contains a number widget.) +typedef struct +{ + // number information + st_number_t n; + + // percent sign graphic + const patchnum_t* p; +} st_percent_t; + +// Multiple Icon widget +typedef struct +{ + // center-justified location of icons + int x; + int y; + + // last icon number + int oldinum; + + // pointer to current icon + int* inum; + + // pointer to boolean stating + // whether to update icon + boolean* on; + + // list of icons + const patchnum_t* p; + + // user data + int data; + +} st_multicon_t; + +// Binary Icon widget + +typedef struct +{ + // center-justified location of icon + int x; + int y; + + // last icon value + boolean oldval; + + // pointer to current icon status + boolean* val; + + // pointer to boolean + // stating whether to update icon + boolean* on; + + const patchnum_t* p; // icon + int data; // user data +} st_binicon_t; + +// +// Widget creation, access, and update routines +// + +// Initializes widget library. +// More precisely, initialize STMINUS, +// everything else is done somewhere else. +// +void STlib_init(void); + +// Number widget routines +void STlib_initNum +( st_number_t* n, + int x, + int y, + const patchnum_t* pl, + int* num, + boolean* on, + int width ); + +void STlib_updateNum +( st_number_t* n, + int cm, + boolean refresh ); + + +// Percent widget routines +void STlib_initPercent +( st_percent_t* p, + int x, + int y, + const patchnum_t* pl, + int* num, + boolean* on, + const patchnum_t* percent ); + + +void STlib_updatePercent +( st_percent_t* per, + int cm, + int refresh ); + + +// Multiple Icon widget routines +void STlib_initMultIcon +( st_multicon_t* mi, + int x, + int y, + const patchnum_t* il, + int* inum, + boolean* on ); + + +void STlib_updateMultIcon +( st_multicon_t* mi, + boolean refresh ); + +// Binary Icon widget routines + +void STlib_initBinIcon +( st_binicon_t* b, + int x, + int y, + const patchnum_t* i, + boolean* val, + boolean* on ); + +void STlib_updateBinIcon +( st_binicon_t* bi, + boolean refresh ); + +#endif diff --git a/common/prboom/st_stuff.c b/common/prboom/st_stuff.c new file mode 100755 index 0000000..d220d22 --- /dev/null +++ b/common/prboom/st_stuff.c @@ -0,0 +1,1161 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Status bar code. + * Does the face/direction indicator animatin. + * Does palette indicators as well (red pain/berserk, bright pickup) + * + *-----------------------------------------------------------------------------*/ + +#include "doomdef.h" +#include "doomstat.h" +#include "m_random.h" +#include "i_video.h" +#include "w_wad.h" +#include "st_stuff.h" +#include "st_lib.h" +#include "r_main.h" +#include "am_map.h" +#include "m_cheat.h" +#include "s_sound.h" +#include "sounds.h" +#include "dstrings.h" +#include "r_draw.h" + +// +// STATUS BAR DATA +// + +// Palette indices. +// For damage/bonus red-/gold-shifts +#define STARTREDPALS 1 +#define STARTBONUSPALS 9 +#define NUMREDPALS 8 +#define NUMBONUSPALS 4 +// Radiation suit, green shift. +#define RADIATIONPAL 13 + +// Location of status bar +#define ST_X 0 +#define ST_X2 104 + +// proff 08/18/98: Changed for high-res +#define ST_FX (ST_X+143) +#define ST_FY (ST_Y+1) +//#define ST_FX 143 +//#define ST_FY 169 + +// Should be set to patch width +// for tall numbers later on +#define ST_TALLNUMWIDTH (tallnum[0]->width) + +// Number of status faces. +#define ST_NUMPAINFACES 5 +#define ST_NUMSTRAIGHTFACES 3 +#define ST_NUMTURNFACES 2 +#define ST_NUMSPECIALFACES 3 + +#define ST_FACESTRIDE \ + (ST_NUMSTRAIGHTFACES+ST_NUMTURNFACES+ST_NUMSPECIALFACES) + +#define ST_NUMEXTRAFACES 2 + +#define ST_NUMFACES \ + (ST_FACESTRIDE*ST_NUMPAINFACES+ST_NUMEXTRAFACES) + +#define ST_TURNOFFSET (ST_NUMSTRAIGHTFACES) +#define ST_OUCHOFFSET (ST_TURNOFFSET + ST_NUMTURNFACES) +#define ST_EVILGRINOFFSET (ST_OUCHOFFSET + 1) +#define ST_RAMPAGEOFFSET (ST_EVILGRINOFFSET + 1) +#define ST_GODFACE (ST_NUMPAINFACES*ST_FACESTRIDE) +#define ST_DEADFACE (ST_GODFACE+1) + +// proff 08/18/98: Changed for high-res +#define ST_FACESX (ST_X+143) +#define ST_FACESY (ST_Y) +//#define ST_FACESX 143 +//#define ST_FACESY 168 + +#define ST_EVILGRINCOUNT (2*TICRATE) +#define ST_STRAIGHTFACECOUNT (TICRATE/2) +#define ST_TURNCOUNT (1*TICRATE) +#define ST_OUCHCOUNT (1*TICRATE) +#define ST_RAMPAGEDELAY (2*TICRATE) + +#define ST_MUCHPAIN 20 + +// Location and size of statistics, +// justified according to widget type. +// Problem is, within which space? STbar? Screen? +// Note: this could be read in by a lump. +// Problem is, is the stuff rendered +// into a buffer, +// or into the frame buffer? +// I dunno, why don't you go and find out!!! killough + +// AMMO number pos. +#define ST_AMMOWIDTH 3 +// proff 08/18/98: Changed for high-res +#define ST_AMMOX (ST_X+44) +#define ST_AMMOY (ST_Y+3) +//#define ST_AMMOX 44 +//#define ST_AMMOY 171 + +// HEALTH number pos. +#define ST_HEALTHWIDTH 3 +// proff 08/18/98: Changed for high-res +#define ST_HEALTHX (ST_X+90) +#define ST_HEALTHY (ST_Y+3) +//#define ST_HEALTHX 90 +//#define ST_HEALTHY 171 + +// Weapon pos. +// proff 08/18/98: Changed for high-res +#define ST_ARMSX (ST_X+111) +#define ST_ARMSY (ST_Y+4) +#define ST_ARMSBGX (ST_X+104) +#define ST_ARMSBGY (ST_Y) +//#define ST_ARMSX 111 +//#define ST_ARMSY 172 +//#define ST_ARMSBGX 104 +//#define ST_ARMSBGY 168 +#define ST_ARMSXSPACE 12 +#define ST_ARMSYSPACE 10 + +// Frags pos. +// proff 08/18/98: Changed for high-res +#define ST_FRAGSX (ST_X+138) +#define ST_FRAGSY (ST_Y+3) +//#define ST_FRAGSX 138 +//#define ST_FRAGSY 171 +#define ST_FRAGSWIDTH 2 + +// ARMOR number pos. +#define ST_ARMORWIDTH 3 +// proff 08/18/98: Changed for high-res +#define ST_ARMORX (ST_X+221) +#define ST_ARMORY (ST_Y+3) +//#define ST_ARMORX 221 +//#define ST_ARMORY 171 + +// Key icon positions. +#define ST_KEY0WIDTH 8 +#define ST_KEY0HEIGHT 5 +// proff 08/18/98: Changed for high-res +#define ST_KEY0X (ST_X+239) +#define ST_KEY0Y (ST_Y+3) +//#define ST_KEY0X 239 +//#define ST_KEY0Y 171 +#define ST_KEY1WIDTH ST_KEY0WIDTH +// proff 08/18/98: Changed for high-res +#define ST_KEY1X (ST_X+239) +#define ST_KEY1Y (ST_Y+13) +//#define ST_KEY1X 239 +//#define ST_KEY1Y 181 +#define ST_KEY2WIDTH ST_KEY0WIDTH +// proff 08/18/98: Changed for high-res +#define ST_KEY2X (ST_X+239) +#define ST_KEY2Y (ST_Y+23) +//#define ST_KEY2X 239 +//#define ST_KEY2Y 191 + +// Ammunition counter. +#define ST_AMMO0WIDTH 3 +#define ST_AMMO0HEIGHT 6 +// proff 08/18/98: Changed for high-res +#define ST_AMMO0X (ST_X+288) +#define ST_AMMO0Y (ST_Y+5) +//#define ST_AMMO0X 288 +//#define ST_AMMO0Y 173 +#define ST_AMMO1WIDTH ST_AMMO0WIDTH +// proff 08/18/98: Changed for high-res +#define ST_AMMO1X (ST_X+288) +#define ST_AMMO1Y (ST_Y+11) +//#define ST_AMMO1X 288 +//#define ST_AMMO1Y 179 +#define ST_AMMO2WIDTH ST_AMMO0WIDTH +// proff 08/18/98: Changed for high-res +#define ST_AMMO2X (ST_X+288) +#define ST_AMMO2Y (ST_Y+23) +//#define ST_AMMO2X 288 +//#define ST_AMMO2Y 191 +#define ST_AMMO3WIDTH ST_AMMO0WIDTH +// proff 08/18/98: Changed for high-res +#define ST_AMMO3X (ST_X+288) +#define ST_AMMO3Y (ST_Y+17) +//#define ST_AMMO3X 288 +//#define ST_AMMO3Y 185 + +// Indicate maximum ammunition. +// Only needed because backpack exists. +#define ST_MAXAMMO0WIDTH 3 +#define ST_MAXAMMO0HEIGHT 5 +// proff 08/18/98: Changed for high-res +#define ST_MAXAMMO0X (ST_X+314) +#define ST_MAXAMMO0Y (ST_Y+5) +//#define ST_MAXAMMO0X 314 +//#define ST_MAXAMMO0Y 173 +#define ST_MAXAMMO1WIDTH ST_MAXAMMO0WIDTH +// proff 08/18/98: Changed for high-res +#define ST_MAXAMMO1X (ST_X+314) +#define ST_MAXAMMO1Y (ST_Y+11) +//#define ST_MAXAMMO1X 314 +//#define ST_MAXAMMO1Y 179 +#define ST_MAXAMMO2WIDTH ST_MAXAMMO0WIDTH +// proff 08/18/98: Changed for high-res +#define ST_MAXAMMO2X (ST_X+314) +#define ST_MAXAMMO2Y (ST_Y+23) +//#define ST_MAXAMMO2X 314 +//#define ST_MAXAMMO2Y 191 +#define ST_MAXAMMO3WIDTH ST_MAXAMMO0WIDTH +// proff 08/18/98: Changed for high-res +#define ST_MAXAMMO3X (ST_X+314) +#define ST_MAXAMMO3Y (ST_Y+17) +//#define ST_MAXAMMO3X 314 +//#define ST_MAXAMMO3Y 185 + +// killough 2/8/98: weapon info position macros UNUSED, removed here + +// main player in game +static player_t *plyr; + +// ST_Start() has just been called +static boolean st_firsttime; + +// used to execute ST_Init() only once +static int veryfirsttime = 1; + +// CPhipps - no longer do direct PLAYPAL handling here + +// used for timing +static unsigned int st_clock; + +// used for making messages go away +static int st_msgcounter=0; + +// used when in chat +static st_chatstateenum_t st_chatstate; + +// whether in automap or first-person +static st_stateenum_t st_gamestate; + +// whether left-side main status bar is active +static boolean st_statusbaron; + +// whether status bar chat is active +static boolean st_chat; + +// value of st_chat before message popped up +static boolean st_oldchat; + +// whether chat window has the cursor on +static boolean st_cursoron; + +// !deathmatch +static boolean st_notdeathmatch; + +// !deathmatch && st_statusbaron +static boolean st_armson; + +// !deathmatch +static boolean st_fragson; + +// 0-9, tall numbers +static patchnum_t tallnum[10]; + +// tall % sign +static patchnum_t tallpercent; + +// 0-9, short, yellow (,different!) numbers +static patchnum_t shortnum[10]; + +// 3 key-cards, 3 skulls, 3 card/skull combos +// jff 2/24/98 extend number of patches by three skull/card combos +static patchnum_t keys[NUMCARDS+3]; + +// face status patches +static patchnum_t faces[ST_NUMFACES]; + +// face background +static patchnum_t faceback; // CPhipps - single background, translated for different players + +//e6y: status bar background +/* JDC static */ patchnum_t stbarbg; + +// main bar right +static patchnum_t armsbg; + +// weapon ownership patches +static patchnum_t arms[6][2]; + +// ready-weapon widget +static st_number_t w_ready; + +//jff 2/16/98 status color change levels +int ammo_red; // ammo percent less than which status is red +int ammo_yellow; // ammo percent less is yellow more green +int health_red; // health amount less than which status is red +int health_yellow; // health amount less than which status is yellow +int health_green; // health amount above is blue, below is green +int armor_red; // armor amount less than which status is red +int armor_yellow; // armor amount less than which status is yellow +int armor_green; // armor amount above is blue, below is green + + // in deathmatch only, summary of frags stats +static st_number_t w_frags; + +// health widget +static st_percent_t w_health; + +// arms background +static st_binicon_t w_armsbg; + +// weapon ownership widgets +static st_multicon_t w_arms[6]; + +// face status widget +static st_multicon_t w_faces; + +// keycard widgets +static st_multicon_t w_keyboxes[3]; + +// armor widget +static st_percent_t w_armor; + +// ammo widgets +static st_number_t w_ammo[4]; + +// max ammo widgets +static st_number_t w_maxammo[4]; + + // number of frags so far in deathmatch +static int st_fragscount; + +// used to use appopriately pained face +static int st_oldhealth = -1; + +// used for evil grin +static boolean oldweaponsowned[NUMWEAPONS]; + + // count until face changes +static int st_facecount = 0; + +// current face index, used by w_faces +static int st_faceindex = 0; + +// holds key-type for each key box on bar +static int keyboxes[3]; + +// a random number per tick +static int st_randomnumber; + +extern char *mapnames[]; + +// +// STATUS BAR CODE +// + +static void ST_Stop(void); + +static void ST_refreshBackground(void) +{ + int y=0; + + if (st_statusbaron) + { + // proff 05/17/2000: draw to the frontbuffer in OpenGL + if (V_GetMode() == VID_MODEGL) + y=ST_Y; + V_DrawNumPatch(ST_X, y, BG, stbarbg.lumpnum, CR_DEFAULT, VPT_STRETCH); + if (st_armson) + V_DrawNumPatch(ST_ARMSBGX, y, BG, armsbg.lumpnum, CR_DEFAULT, VPT_STRETCH); + + // killough 3/7/98: make face background change with displayplayer + if (netgame) + { + V_DrawNumPatch(ST_FX, y, BG, faceback.lumpnum, + displayplayer ? CR_LIMIT+displayplayer : CR_DEFAULT, + displayplayer ? (VPT_TRANS | VPT_STRETCH) : VPT_STRETCH); + } + V_CopyRect(ST_X, y, BG, ST_SCALED_WIDTH, ST_SCALED_HEIGHT, ST_X, ST_SCALED_Y, FG, VPT_NONE); + } +} + + +// Respond to keyboard input events, +// intercept cheats. +boolean ST_Responder(event_t *ev) +{ + // Filter automap on/off. + if (ev->type == ev_keyup && (ev->data1 & 0xffff0000) == AM_MSGHEADER) + { + switch(ev->data1) + { + case AM_MSGENTERED: + st_gamestate = AutomapState; + st_firsttime = true; + break; + + case AM_MSGEXITED: + st_gamestate = FirstPersonState; + break; + } + } + else // if a user keypress... + if (ev->type == ev_keydown) // Try cheat responder in m_cheat.c + return M_FindCheats(ev->data1); // killough 4/17/98, 5/2/98 + return false; +} + +static int ST_calcPainOffset(void) +{ + static int lastcalc; + static int oldhealth = -1; + int health = plyr->health > 100 ? 100 : plyr->health; + + if (health != oldhealth) + { + lastcalc = ST_FACESTRIDE * (((100 - health) * ST_NUMPAINFACES) / 101); + oldhealth = health; + } + return lastcalc; +} + +// +// This is a not-very-pretty routine which handles +// the face states and their timing. +// the precedence of expressions is: +// dead > evil grin > turned head > straight ahead +// + +static void ST_updateFaceWidget(void) +{ + int i; + angle_t badguyangle; + angle_t diffang; + static int lastattackdown = -1; + static int priority = 0; + boolean doevilgrin; + + if (priority < 10) + { + // dead + if (!plyr->health) + { + priority = 9; + st_faceindex = ST_DEADFACE; + st_facecount = 1; + } + } + + if (priority < 9) + { + if (plyr->bonuscount) + { + // picking up bonus + doevilgrin = false; + + for (i=0;iweaponowned[i]) + { + doevilgrin = true; + oldweaponsowned[i] = plyr->weaponowned[i]; + } + } + if (doevilgrin) + { + // evil grin if just picked up weapon + priority = 8; + st_facecount = ST_EVILGRINCOUNT; + st_faceindex = ST_calcPainOffset() + ST_EVILGRINOFFSET; + } + } + + } + + if (priority < 8) + { + if (plyr->damagecount && plyr->attacker && plyr->attacker != plyr->mo) + { + // being attacked + priority = 7; + + // haleyjd 10/12/03: classic DOOM problem of missing OUCH face + // was due to inversion of this test: + // if(plyr->health - st_oldhealth > ST_MUCHPAIN) + if(st_oldhealth - plyr->health > ST_MUCHPAIN) + { + st_facecount = ST_TURNCOUNT; + st_faceindex = ST_calcPainOffset() + ST_OUCHOFFSET; + } + else + { + badguyangle = R_PointToAngle2(plyr->mo->x, + plyr->mo->y, + plyr->attacker->x, + plyr->attacker->y); + + if (badguyangle > plyr->mo->angle) + { + // whether right or left + diffang = badguyangle - plyr->mo->angle; + i = diffang > ANG180; + } + else + { + // whether left or right + diffang = plyr->mo->angle - badguyangle; + i = diffang <= ANG180; + } // confusing, aint it? + + + st_facecount = ST_TURNCOUNT; + st_faceindex = ST_calcPainOffset(); + + if (diffang < ANG45) + { + // head-on + st_faceindex += ST_RAMPAGEOFFSET; + } + else if (i) + { + // turn face right + st_faceindex += ST_TURNOFFSET; + } + else + { + // turn face left + st_faceindex += ST_TURNOFFSET+1; + } + } + } + } + + if (priority < 7) + { + // getting hurt because of your own damn stupidity + if (plyr->damagecount) + { + // haleyjd 10/12/03: classic DOOM problem of missing OUCH face + // was due to inversion of this test: + // if(plyr->health - st_oldhealth > ST_MUCHPAIN) + if(st_oldhealth - plyr->health > ST_MUCHPAIN) + { + priority = 7; + st_facecount = ST_TURNCOUNT; + st_faceindex = ST_calcPainOffset() + ST_OUCHOFFSET; + } + else + { + priority = 6; + st_facecount = ST_TURNCOUNT; + st_faceindex = ST_calcPainOffset() + ST_RAMPAGEOFFSET; + } + + } + + } + + if (priority < 6) + { + // rapid firing + if (plyr->attackdown) + { + if (lastattackdown==-1) + lastattackdown = ST_RAMPAGEDELAY; + else if (!--lastattackdown) + { + priority = 5; + st_faceindex = ST_calcPainOffset() + ST_RAMPAGEOFFSET; + st_facecount = 1; + lastattackdown = 1; + } + } + else + lastattackdown = -1; + + } + + if (priority < 5) + { + // invulnerability + if ((plyr->cheats & CF_GODMODE) + || plyr->powers[pw_invulnerability]) + { + priority = 4; + + st_faceindex = ST_GODFACE; + st_facecount = 1; + + } + + } + + // look left or look right if the facecount has timed out + if (!st_facecount) + { + st_faceindex = ST_calcPainOffset() + (st_randomnumber % 3); + st_facecount = ST_STRAIGHTFACECOUNT; + priority = 0; + } + + st_facecount--; + +} + +int sts_traditional_keys; // killough 2/28/98: traditional status bar keys + +static void ST_updateWidgets(void) +{ + static int largeammo = 1994; // means "n/a" + int i; + + // must redirect the pointer if the ready weapon has changed. + // if (w_ready.data != plyr->readyweapon) + // { + if (weaponinfo[plyr->readyweapon].ammo == am_noammo) + w_ready.num = &largeammo; + else + w_ready.num = &plyr->ammo[weaponinfo[plyr->readyweapon].ammo]; + //{ + // static int tic=0; + // static int dir=-1; + // if (!(tic&15)) + // plyr->ammo[weaponinfo[plyr->readyweapon].ammo]+=dir; + // if (plyr->ammo[weaponinfo[plyr->readyweapon].ammo] == -100) + // dir = 1; + // tic++; + // } + w_ready.data = plyr->readyweapon; + + // if (*w_ready.on) + // STlib_updateNum(&w_ready, true); + // refresh weapon change + // } + + // update keycard multiple widgets + for (i=0;i<3;i++) + { + keyboxes[i] = plyr->cards[i] ? i : -1; + + //jff 2/24/98 select double key + //killough 2/28/98: preserve traditional keys by config option + + if (plyr->cards[i+3]) + keyboxes[i] = keyboxes[i]==-1 || sts_traditional_keys ? i+3 : i+6; + } + + // refresh everything if this is him coming back to life + ST_updateFaceWidget(); + + // used by the w_armsbg widget + st_notdeathmatch = !deathmatch; + + // used by w_arms[] widgets + st_armson = st_statusbaron && !deathmatch; + + // used by w_frags widget + st_fragson = deathmatch && st_statusbaron; + st_fragscount = 0; + + for (i=0 ; ifrags[i]; + else + st_fragscount -= plyr->frags[i]; + } + + // get rid of chat window if up because of message + if (!--st_msgcounter) + st_chat = st_oldchat; + +} + +void ST_Ticker(void) +{ + st_clock++; + st_randomnumber = M_Random(); + ST_updateWidgets(); + st_oldhealth = plyr->health; +} + +int st_palette = 0; + +static void ST_doPaletteStuff(void) +{ + int palette; + int cnt = plyr->damagecount; + + if (plyr->powers[pw_strength]) + { + // slowly fade the berzerk out + int bzc = 12 - (plyr->powers[pw_strength]>>6); + if (bzc > cnt) + cnt = bzc; + } + + if (cnt) + { + palette = (cnt+7)>>3; + if (palette >= NUMREDPALS) + palette = NUMREDPALS-1; + + /* cph 2006/08/06 - if in the menu, reduce the red tint - navigating to + * load a game can be tricky if the screen is all red */ + if (menuactive) palette >>=1; + + palette += STARTREDPALS; + } + else + if (plyr->bonuscount) + { + palette = (plyr->bonuscount+7)>>3; + if (palette >= NUMBONUSPALS) + palette = NUMBONUSPALS-1; + palette += STARTBONUSPALS; + } + else + if (plyr->powers[pw_ironfeet] > 4*32 || plyr->powers[pw_ironfeet] & 8) + palette = RADIATIONPAL; + else + palette = 0; + + if (palette != st_palette) { + V_SetPalette(st_palette = palette); // CPhipps - use new palette function + + // have to redraw the entire status bar when the palette changes + // in truecolor modes - POPE + if (V_GetMode() == VID_MODE15 || V_GetMode() == VID_MODE16 || V_GetMode() == VID_MODE32) + st_firsttime = true; + } +} + +static void ST_drawWidgets(boolean refresh) +{ + int i; + + // used by w_arms[] widgets + st_armson = st_statusbaron && !deathmatch; + + // used by w_frags widget + st_fragson = deathmatch && st_statusbaron; + + //jff 2/16/98 make color of ammo depend on amount + if (*w_ready.num*100 < ammo_red*plyr->maxammo[weaponinfo[w_ready.data].ammo]) + STlib_updateNum(&w_ready, CR_RED, refresh); + else + if (*w_ready.num*100 < + ammo_yellow*plyr->maxammo[weaponinfo[w_ready.data].ammo]) + STlib_updateNum(&w_ready, CR_GOLD, refresh); + else + STlib_updateNum(&w_ready, CR_GREEN, refresh); + + for (i=0;i<4;i++) + { + STlib_updateNum(&w_ammo[i], CR_DEFAULT, refresh); //jff 2/16/98 no xlation + STlib_updateNum(&w_maxammo[i], CR_DEFAULT, refresh); + } + + //jff 2/16/98 make color of health depend on amount + if (*w_health.n.numweaponowned[i]; + + for (i=0;i<3;i++) + keyboxes[i] = -1; + + STlib_init(); +} + +static void ST_createWidgets(void) +{ + int i; + + // ready weapon ammo + STlib_initNum(&w_ready, + ST_AMMOX, + ST_AMMOY, + tallnum, + &plyr->ammo[weaponinfo[plyr->readyweapon].ammo], + &st_statusbaron, + ST_AMMOWIDTH ); + + // the last weapon type + w_ready.data = plyr->readyweapon; + + // health percentage + STlib_initPercent(&w_health, + ST_HEALTHX, + ST_HEALTHY, + tallnum, + &plyr->health, + &st_statusbaron, + &tallpercent); + + // arms background + STlib_initBinIcon(&w_armsbg, + ST_ARMSBGX, + ST_ARMSBGY, + &armsbg, + &st_notdeathmatch, + &st_statusbaron); + + // weapons owned + for(i=0;i<6;i++) + { + STlib_initMultIcon(&w_arms[i], + ST_ARMSX+(i%3)*ST_ARMSXSPACE, + ST_ARMSY+(i/3)*ST_ARMSYSPACE, + arms[i], (int *) &plyr->weaponowned[i+1], + &st_armson); + } + + // frags sum + STlib_initNum(&w_frags, + ST_FRAGSX, + ST_FRAGSY, + tallnum, + &st_fragscount, + &st_fragson, + ST_FRAGSWIDTH); + + // faces + STlib_initMultIcon(&w_faces, + ST_FACESX, + ST_FACESY, + faces, + &st_faceindex, + &st_statusbaron); + + // armor percentage - should be colored later + STlib_initPercent(&w_armor, + ST_ARMORX, + ST_ARMORY, + tallnum, + &plyr->armorpoints, + &st_statusbaron, &tallpercent); + + // keyboxes 0-2 + STlib_initMultIcon(&w_keyboxes[0], + ST_KEY0X, + ST_KEY0Y, + keys, + &keyboxes[0], + &st_statusbaron); + + STlib_initMultIcon(&w_keyboxes[1], + ST_KEY1X, + ST_KEY1Y, + keys, + &keyboxes[1], + &st_statusbaron); + + STlib_initMultIcon(&w_keyboxes[2], + ST_KEY2X, + ST_KEY2Y, + keys, + &keyboxes[2], + &st_statusbaron); + + // ammo count (all four kinds) + STlib_initNum(&w_ammo[0], + ST_AMMO0X, + ST_AMMO0Y, + shortnum, + &plyr->ammo[0], + &st_statusbaron, + ST_AMMO0WIDTH); + + STlib_initNum(&w_ammo[1], + ST_AMMO1X, + ST_AMMO1Y, + shortnum, + &plyr->ammo[1], + &st_statusbaron, + ST_AMMO1WIDTH); + + STlib_initNum(&w_ammo[2], + ST_AMMO2X, + ST_AMMO2Y, + shortnum, + &plyr->ammo[2], + &st_statusbaron, + ST_AMMO2WIDTH); + + STlib_initNum(&w_ammo[3], + ST_AMMO3X, + ST_AMMO3Y, + shortnum, + &plyr->ammo[3], + &st_statusbaron, + ST_AMMO3WIDTH); + + // max ammo count (all four kinds) + STlib_initNum(&w_maxammo[0], + ST_MAXAMMO0X, + ST_MAXAMMO0Y, + shortnum, + &plyr->maxammo[0], + &st_statusbaron, + ST_MAXAMMO0WIDTH); + + STlib_initNum(&w_maxammo[1], + ST_MAXAMMO1X, + ST_MAXAMMO1Y, + shortnum, + &plyr->maxammo[1], + &st_statusbaron, + ST_MAXAMMO1WIDTH); + + STlib_initNum(&w_maxammo[2], + ST_MAXAMMO2X, + ST_MAXAMMO2Y, + shortnum, + &plyr->maxammo[2], + &st_statusbaron, + ST_MAXAMMO2WIDTH); + + STlib_initNum(&w_maxammo[3], + ST_MAXAMMO3X, + ST_MAXAMMO3Y, + shortnum, + &plyr->maxammo[3], + &st_statusbaron, + ST_MAXAMMO3WIDTH); +} + +static boolean st_stopped = true; + +void ST_Start(void) +{ + if (!st_stopped) + ST_Stop(); + ST_initData(); + ST_createWidgets(); + st_stopped = false; +} + +static void ST_Stop(void) +{ + if (st_stopped) + return; + V_SetPalette(0); + st_stopped = true; +} + +void ST_Init(void) +{ + veryfirsttime = 0; + ST_loadData(); +} diff --git a/common/prboom/st_stuff.h b/common/prboom/st_stuff.h new file mode 100755 index 0000000..83ba51e --- /dev/null +++ b/common/prboom/st_stuff.h @@ -0,0 +1,102 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Status bar code. + * Does the face/direction indicator animatin. + * Does palette indicators as well (red pain/berserk, bright pickup) + * + *-----------------------------------------------------------------------------*/ + +#ifndef __STSTUFF_H__ +#define __STSTUFF_H__ + +#include "doomtype.h" +#include "d_event.h" + +// Size of statusbar. +// Now sensitive for scaling. + +// proff 08/18/98: Changed for high-res +#define ST_HEIGHT 32 +#define ST_WIDTH 320 +#define ST_Y (200 - ST_HEIGHT) +#define ST_SCALED_HEIGHT (ST_HEIGHT*SCREENHEIGHT/200) +#define ST_SCALED_WIDTH SCREENWIDTH +#define ST_SCALED_Y (SCREENHEIGHT - ST_SCALED_HEIGHT) + +// +// STATUS BAR +// + +// Called by main loop. +boolean ST_Responder(event_t* ev); + +// Called by main loop. +void ST_Ticker(void); + +// Called by main loop. +void ST_Drawer(boolean st_statusbaron, boolean refresh); + +// Called when the console player is spawned on each level. +void ST_Start(void); + +// Called by startup code. +void ST_Init(void); + +// States for status bar code. +typedef enum +{ + AutomapState, + FirstPersonState +} st_stateenum_t; + +// States for the chat code. +typedef enum +{ + StartChatState, + WaitDestState, + GetChatState +} st_chatstateenum_t; + +// killough 5/2/98: moved from m_misc.c: + +extern int health_red; // health amount less than which status is red +extern int health_yellow; // health amount less than which status is yellow +extern int health_green; // health amount above is blue, below is green +extern int armor_red; // armor amount less than which status is red +extern int armor_yellow; // armor amount less than which status is yellow +extern int armor_green; // armor amount above is blue, below is green +extern int ammo_red; // ammo percent less than which status is red +extern int ammo_yellow; // ammo percent less is yellow more green +extern int sts_always_red;// status numbers do not change colors +extern int sts_pct_always_gray;// status percents do not change colors +extern int sts_traditional_keys; // display keys the traditional way + +extern int st_palette; // cph 2006/04/06 - make palette visible +#endif diff --git a/common/prboom/tables.c b/common/prboom/tables.c new file mode 100755 index 0000000..2cf59e1 --- /dev/null +++ b/common/prboom/tables.c @@ -0,0 +1,128 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Lookup tables. + * Do not try to look them up :-). + * In the order of appearance: + * + * int finetangent[4096] - Tangens LUT. + * Should work with BAM fairly well (12 of 16bit, + * effectively, by shifting). + * + * int finesine[10240] - Sine lookup. + * Guess what, serves as cosine, too. + * Remarkable thing is, how to use BAMs with this? + * + * int tantoangle[2049] - ArcTan LUT, + * maps tan(angle) to angle fast. Gotta search. + * + *----------------------------------------------------------------------------- + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "w_wad.h" +#include "tables.h" + +// killough 5/3/98: reformatted + +int SlopeDiv(unsigned num, unsigned den) +{ + unsigned ans; + + if (den < 512) + return SLOPERANGE; + ans = (num<<3)/(den>>8); + return ans <= SLOPERANGE ? ans : SLOPERANGE; +} + +fixed_t finetangent[4096]; + +//const fixed_t *const finecosine = &finesine[FINEANGLES/4]; + +fixed_t finesine[10240]; + +angle_t tantoangle[2049]; + +#include "m_swap.h" +#include "lprintf.h" + +// R_LoadTrigTables +// Load trig tables from a wad file lump +// CPhipps 24/12/98 - fix endianness (!) +// +void R_LoadTrigTables(void) +{ + int lump; + { + lump = (W_CheckNumForName)("SINETABL",ns_prboom); + if (lump == -1) I_Error("Failed to locate trig tables"); + if (W_LumpLength(lump) != sizeof(finesine)) + I_Error("R_LoadTrigTables: Invalid SINETABL"); + W_ReadLump(lump,(unsigned char*)finesine); + } + { + lump = (W_CheckNumForName)("TANGTABL",ns_prboom); + if (lump == -1) I_Error("Failed to locate trig tables"); + if (W_LumpLength(lump) != sizeof(finetangent)) + I_Error("R_LoadTrigTables: Invalid TANGTABL"); + W_ReadLump(lump,(unsigned char*)finetangent); + } + { + lump = (W_CheckNumForName)("TANTOANG",ns_prboom); + if (lump == -1) I_Error("Failed to locate trig tables"); + if (W_LumpLength(lump) != sizeof(tantoangle)) + I_Error("R_LoadTrigTables: Invalid TANTOANG"); + W_ReadLump(lump,(unsigned char*)tantoangle); + } + // Endianness correction - might still be non-portable, but is fast where possible + { + size_t n; + lprintf(LO_INFO, "Endianness..."); + + // This test doesn't assume the endianness of the tables, but deduces them from + // en entry. I hope this is portable. + if ((10 < finesine[1]) && (finesine[1] < 100)) { + lprintf(LO_INFO, "ok."); + return; // Endianness is correct + } + + // Must correct endianness of every long loaded (!) +#define CORRECT_TABLE_ENDIAN(tbl) \ + for (n = 0; nname; p++) + *p->map = W_CacheLumpName(p->name); +} + +// +// V_CopyRect +// +// Copies a source rectangle in a screen buffer to a destination +// rectangle in another screen buffer. Source origin in srcx,srcy, +// destination origin in destx,desty, common size in width and height. +// Source buffer specfified by srcscrn, destination buffer by destscrn. +// +// Marks the destination rectangle on the screen dirty. +// +// No return. +// +static void FUNC_V_CopyRect(int srcx, int srcy, int srcscrn, int width, + int height, int destx, int desty, int destscrn, + enum patch_translation_e flags) +{ + byte *src; + byte *dest; + + if (flags & VPT_STRETCH) + { + srcx=srcx*SCREENWIDTH/320; + srcy=srcy*SCREENHEIGHT/200; + width=width*SCREENWIDTH/320; + height=height*SCREENHEIGHT/200; + destx=destx*SCREENWIDTH/320; + desty=desty*SCREENHEIGHT/200; + } + +#ifdef RANGECHECK + if (srcx<0 + ||srcx+width >SCREENWIDTH + || srcy<0 + || srcy+height>SCREENHEIGHT + ||destx<0||destx+width >SCREENWIDTH + || desty<0 + || desty+height>SCREENHEIGHT) + I_Error ("V_CopyRect: Bad arguments"); +#endif + + src = screens[srcscrn].data+screens[srcscrn].byte_pitch*srcy+srcx*V_GetPixelDepth(); + dest = screens[destscrn].data+screens[destscrn].byte_pitch*desty+destx*V_GetPixelDepth(); + + for ( ; height>0 ; height--) + { + memcpy (dest, src, width*V_GetPixelDepth()); + src += screens[srcscrn].byte_pitch; + dest += screens[destscrn].byte_pitch; + } +} + +/* + * V_DrawBackground tiles a 64x64 patch over the entire screen, providing the + * background for the Help and Setup screens, and plot text betwen levels. + * cphipps - used to have M_DrawBackground, but that was used the framebuffer + * directly, so this is my code from the equivalent function in f_finale.c + */ +static void FUNC_V_DrawBackground(const char* flatname, int scrn) +{ + /* erase the entire screen to a tiled background */ + const byte *src; + int x,y; + int width,height; + int lump; + + // killough 4/17/98: + src = W_CacheLumpNum(lump = firstflat + R_FlatNumForName(flatname)); + + /* V_DrawBlock(0, 0, scrn, 64, 64, src, 0); */ + width = height = 64; + if (V_GetMode() == VID_MODE8) { + byte *dest = screens[scrn].data; + + while (height--) { + memcpy (dest, src, width); + src += width; + dest += screens[scrn].byte_pitch; + } + } else if (V_GetMode() == VID_MODE15) { + unsigned short *dest = (unsigned short *)screens[scrn].data; + + while (height--) { + int i; + for (i=0; itopoffset; + x -= patch->leftoffset; + + // CPhipps - auto-no-stretch if not high-res + if (flags & VPT_STRETCH) + if ((SCREENWIDTH==320) && (SCREENHEIGHT==200)) + flags &= ~VPT_STRETCH; + + // CPhipps - null translation pointer => no translation + if (!trans) + flags &= ~VPT_TRANS; + + if (V_GetMode() == VID_MODE8 && !(flags & VPT_STRETCH)) { + int col; + byte *desttop = screens[scrn].data+y*screens[scrn].byte_pitch+x*V_GetPixelDepth(); + unsigned int w = patch->width; + + if (y<0 || y+patch->height > ((flags & VPT_STRETCH) ? 200 : SCREENHEIGHT)) { + // killough 1/19/98: improved error message: + lprintf(LO_WARN, "V_DrawMemPatch8: Patch (%d,%d)-(%d,%d) exceeds LFB in vertical direction (horizontal is clipped)\n" + "Bad V_DrawMemPatch8 (flags=%u)", x, y, x+patch->width, y+patch->height, flags); + return; + } + + w--; // CPhipps - note: w = width-1 now, speeds up flipping + + for (col=0 ; (unsigned int)col<=w ; desttop++, col++, x++) { + int i; + const int colindex = (flags & VPT_FLIP) ? (w - col) : (col); + const rcolumn_t *column = R_GetPatchColumn(patch, colindex); + + if (x < 0) + continue; + if (x >= SCREENWIDTH) + break; + + // step through the posts in a column + for (i=0; inumPosts; i++) { + const rpost_t *post = &column->posts[i]; + // killough 2/21/98: Unrolled and performance-tuned + + const byte *source = column->pixels + post->topdelta; + byte *dest = desttop + post->topdelta*screens[scrn].byte_pitch; + int count = post->length; + + if (!(flags & VPT_TRANS)) { + if ((count-=4)>=0) + do { + register byte s0,s1; + s0 = source[0]; + s1 = source[1]; + dest[0] = s0; + dest[screens[scrn].byte_pitch] = s1; + dest += screens[scrn].byte_pitch*2; + s0 = source[2]; + s1 = source[3]; + source += 4; + dest[0] = s0; + dest[screens[scrn].byte_pitch] = s1; + dest += screens[scrn].byte_pitch*2; + } while ((count-=4)>=0); + if (count+=4) + do { + *dest = *source++; + dest += screens[scrn].byte_pitch; + } while (--count); + } else { + // CPhipps - merged translation code here + if ((count-=4)>=0) + do { + register byte s0,s1; + s0 = source[0]; + s1 = source[1]; + s0 = trans[s0]; + s1 = trans[s1]; + dest[0] = s0; + dest[screens[scrn].byte_pitch] = s1; + dest += screens[scrn].byte_pitch*2; + s0 = source[2]; + s1 = source[3]; + s0 = trans[s0]; + s1 = trans[s1]; + source += 4; + dest[0] = s0; + dest[screens[scrn].byte_pitch] = s1; + dest += screens[scrn].byte_pitch*2; + } while ((count-=4)>=0); + if (count+=4) + do { + *dest = trans[*source++]; + dest += screens[scrn].byte_pitch; + } while (--count); + } + } + } + } + else { + // CPhipps - move stretched patch drawing code here + // - reformat initialisers, move variables into inner blocks + + int col; + int w = (patch->width << 16) - 1; // CPhipps - -1 for faster flipping + int left, right, top, bottom; + int DX = (SCREENWIDTH<<16) / 320; + int DXI = (320<<16) / SCREENWIDTH; + int DY = (SCREENHEIGHT<<16) / 200; + int DYI = (200<<16) / SCREENHEIGHT; + R_DrawColumn_f colfunc; + draw_column_vars_t dcvars; + draw_vars_t olddrawvars = drawvars; + + R_SetDefaultDrawColumnVars(&dcvars); + + drawvars.byte_topleft = screens[scrn].data; + drawvars.short_topleft = (unsigned short *)screens[scrn].data; + drawvars.int_topleft = (unsigned int *)screens[scrn].data; + drawvars.byte_pitch = screens[scrn].byte_pitch; + drawvars.short_pitch = screens[scrn].short_pitch; + drawvars.int_pitch = screens[scrn].int_pitch; + + if (!(flags & VPT_STRETCH)) { + DX = 1 << 16; + DXI = 1 << 16; + DY = 1 << 16; + DYI = 1 << 16; + } + + if (flags & VPT_TRANS) { + colfunc = R_GetDrawColumnFunc(RDC_PIPELINE_TRANSLATED, drawvars.filterpatch, RDRAW_FILTER_NONE); + dcvars.translation = trans; + } else { + colfunc = R_GetDrawColumnFunc(RDC_PIPELINE_STANDARD, drawvars.filterpatch, RDRAW_FILTER_NONE); + } + + left = ( x * DX ) >> FRACBITS; + top = ( y * DY ) >> FRACBITS; + right = ( (x + patch->width) * DX ) >> FRACBITS; + bottom = ( (y + patch->height) * DY ) >> FRACBITS; + + dcvars.texheight = patch->height; + dcvars.iscale = DYI; + dcvars.drawingmasked = MAX(patch->width, patch->height) > 8; + dcvars.edgetype = drawvars.patch_edges; + + if (drawvars.filterpatch == RDRAW_FILTER_LINEAR) { + // bias the texture u coordinate + if (patch->isNotTileable) + col = -(FRACUNIT>>1); + else + col = (patch->width<>1); + } + else { + col = 0; + } + + for (dcvars.x=left; dcvars.x>16): (col>>16); + const rcolumn_t *column = R_GetPatchColumn(patch, colindex); + const rcolumn_t *prevcolumn = R_GetPatchColumn(patch, colindex-1); + const rcolumn_t *nextcolumn = R_GetPatchColumn(patch, colindex+1); + + // ignore this column if it's to the left of our clampRect + if (dcvars.x < 0) + continue; + if (dcvars.x >= SCREENWIDTH) + break; + + dcvars.texu = ((flags & VPT_FLIP) ? ((patch->width<width<numPosts; i++) { + const rpost_t *post = &column->posts[i]; + int yoffset = 0; + + dcvars.yl = (((y + post->topdelta) * DY)>>FRACBITS); + dcvars.yh = (((y + post->topdelta + post->length) * DY - (FRACUNIT>>1))>>FRACBITS); + dcvars.edgeslope = post->slope; + + if ((dcvars.yh < 0) || (dcvars.yh < top)) + continue; + if ((dcvars.yl >= SCREENHEIGHT) || (dcvars.yl >= bottom)) + continue; + + if (dcvars.yh >= bottom) { + dcvars.yh = bottom-1; + dcvars.edgeslope &= ~RDRAW_EDGESLOPE_BOT_MASK; + } + if (dcvars.yh >= SCREENHEIGHT) { + dcvars.yh = SCREENHEIGHT-1; + dcvars.edgeslope &= ~RDRAW_EDGESLOPE_BOT_MASK; + } + + if (dcvars.yl < 0) { + yoffset = 0-dcvars.yl; + dcvars.yl = 0; + dcvars.edgeslope &= ~RDRAW_EDGESLOPE_TOP_MASK; + } + if (dcvars.yl < top) { + yoffset = top-dcvars.yl; + dcvars.yl = top; + dcvars.edgeslope &= ~RDRAW_EDGESLOPE_TOP_MASK; + } + + dcvars.source = column->pixels + post->topdelta + yoffset; + dcvars.prevsource = prevcolumn ? prevcolumn->pixels + post->topdelta + yoffset: dcvars.source; + dcvars.nextsource = nextcolumn ? nextcolumn->pixels + post->topdelta + yoffset: dcvars.source; + + dcvars.texturemid = -((dcvars.yl-centery)*dcvars.iscale); + + colfunc(&dcvars); + } + } + + R_ResetColumnBuffer(); + drawvars = olddrawvars; + } +} + +// CPhipps - some simple, useful wrappers for that function, for drawing patches from wads + +// CPhipps - GNU C only suppresses generating a copy of a function if it is +// static inline; other compilers have different behaviour. +// This inline is _only_ for the function below + +static void FUNC_V_DrawNumPatch(int x, int y, int scrn, int lump, + int cm, enum patch_translation_e flags) +{ + V_DrawMemPatch(x, y, scrn, R_CachePatchNum(lump), cm, flags); + R_UnlockPatchNum(lump); +} + +unsigned short *V_Palette15 = NULL; +unsigned short *V_Palette16 = NULL; +unsigned int *V_Palette32 = NULL; +static unsigned short *Palettes15 = NULL; +static unsigned short *Palettes16 = NULL; +static unsigned int *Palettes32 = NULL; +static int currentPaletteIndex = 0; + +// +// V_UpdateTrueColorPalette +// +void V_UpdateTrueColorPalette(video_mode_t mode) { + int i, w, p; + byte r,g,b; + int nr,ng,nb; + float t; + int paletteNum = (V_GetMode() == VID_MODEGL ? 0 : currentPaletteIndex); + static int usegammaOnLastPaletteGeneration = -1; + + int pplump = W_GetNumForName("PLAYPAL"); + int gtlump = (W_CheckNumForName)("GAMMATBL",ns_prboom); + const byte *pal = W_CacheLumpNum(pplump); + // opengl doesn't use the gamma + const byte *const gtable = + (const byte *)W_CacheLumpNum(gtlump) + + (V_GetMode() == VID_MODEGL ? 0 : 256*(usegamma)) + ; + + int numPals = W_LumpLength(pplump) / (3*256); + const float dontRoundAbove = 220; + float roundUpR, roundUpG, roundUpB; + + if (usegammaOnLastPaletteGeneration != usegamma) { + if (Palettes15) free(Palettes15); + if (Palettes16) free(Palettes16); + if (Palettes32) free(Palettes32); + Palettes15 = NULL; + Palettes16 = NULL; + Palettes32 = NULL; + usegammaOnLastPaletteGeneration = usegamma; + } + + if (mode == VID_MODE32) { + if (!Palettes32) { + // set int palette + Palettes32 = (unsigned int*)malloc(numPals*256*sizeof(unsigned int)*VID_NUMCOLORWEIGHTS); + for (p=0; p dontRoundAbove) ? 0 : 0.5f; + roundUpG = (g > dontRoundAbove) ? 0 : 0.5f; + roundUpB = (b > dontRoundAbove) ? 0 : 0.5f; + + for (w=0; w dontRoundAbove) ? 0 : 0.5f; + roundUpG = (g > dontRoundAbove) ? 0 : 0.5f; + roundUpB = (b > dontRoundAbove) ? 0 : 0.5f; + + for (w=0; w>3)*t+roundUpR); + ng = (int)((g>>2)*t+roundUpG); + nb = (int)((b>>3)*t+roundUpB); + Palettes16[((p*256+i)*VID_NUMCOLORWEIGHTS)+w] = ( + (nr<<11) | (ng<<5) | nb + ); + } + } + } + } + V_Palette16 = Palettes16 + paletteNum*256*VID_NUMCOLORWEIGHTS; + } + else if (mode == VID_MODE15) { + if (!Palettes15) { + // set short palette + Palettes15 = (unsigned short*)malloc(numPals*256*sizeof(unsigned short)*VID_NUMCOLORWEIGHTS); + for (p=0; p dontRoundAbove) ? 0 : 0.5f; + roundUpG = (g > dontRoundAbove) ? 0 : 0.5f; + roundUpB = (b > dontRoundAbove) ? 0 : 0.5f; + + for (w=0; w>3)*t+roundUpR); + ng = (int)((g>>3)*t+roundUpG); + nb = (int)((b>>3)*t+roundUpB); + Palettes15[((p*256+i)*VID_NUMCOLORWEIGHTS)+w] = ( + (nr<<10) | (ng<<5) | nb + ); + } + } + } + } + V_Palette15 = Palettes15 + paletteNum*256*VID_NUMCOLORWEIGHTS; + } + + W_UnlockLumpNum(pplump); + W_UnlockLumpNum(gtlump); +} + + +//--------------------------------------------------------------------------- +// V_DestroyTrueColorPalette +//--------------------------------------------------------------------------- +static void V_DestroyTrueColorPalette(video_mode_t mode) { + if (mode == VID_MODE15) { + if (Palettes15) free(Palettes15); + Palettes15 = NULL; + V_Palette15 = NULL; + } + if (mode == VID_MODE16) { + if (Palettes16) free(Palettes16); + Palettes16 = NULL; + V_Palette16 = NULL; + } + if (mode == VID_MODE32) { + if (Palettes32) free(Palettes32); + Palettes32 = NULL; + V_Palette32 = NULL; + } +} + +void V_DestroyUnusedTrueColorPalettes(void) { + if (V_GetMode() != VID_MODE15) V_DestroyTrueColorPalette(VID_MODE15); + if (V_GetMode() != VID_MODE16) V_DestroyTrueColorPalette(VID_MODE16); + if (V_GetMode() != VID_MODE32) V_DestroyTrueColorPalette(VID_MODE32); +} + +// +// V_SetPalette +// +// CPhipps - New function to set the palette to palette number pal. +// Handles loading of PLAYPAL and calls I_SetPalette + +void V_SetPalette(int pal) +{ + currentPaletteIndex = pal; + + if (V_GetMode() == VID_MODEGL) { +#ifdef GL_DOOM + gld_SetPalette(pal); +#endif + } else { + I_SetPalette(pal); + if (V_GetMode() == VID_MODE15 || V_GetMode() == VID_MODE16 || V_GetMode() == VID_MODE32) { + // V_SetPalette can be called as part of the gamma setting before + // we've loaded any wads, which prevents us from reading the palette - POPE + if (W_CheckNumForName("PLAYPAL") >= 0) { + V_UpdateTrueColorPalette(V_GetMode()); + } + } + } +} + +// +// V_FillRect +// +// CPhipps - New function to fill a rectangle with a given colour +static void V_FillRect8(int scrn, int x, int y, int width, int height, byte colour) +{ + byte* dest = screens[scrn].data + x + y*screens[scrn].byte_pitch; + while (height--) { + memset(dest, colour, width); + dest += screens[scrn].byte_pitch; + } +} + +static void V_FillRect15(int scrn, int x, int y, int width, int height, byte colour) +{ + unsigned short* dest = (unsigned short *)screens[scrn].data + x + y*screens[scrn].short_pitch; + int w; + short c = VID_PAL15(colour, VID_COLORWEIGHTMASK); + while (height--) { + for (w=0; wa.x, fl->a.y, fl->b.x, fl->b.y, color); +} +#endif + +static void NULL_FillRect(int scrn, int x, int y, int width, int height, byte colour) {} +static void NULL_CopyRect(int srcx, int srcy, int srcscrn, int width, int height, int destx, int desty, int destscrn, enum patch_translation_e flags) {} +static void NULL_DrawBackground(const char *flatname, int n) {} +static void NULL_DrawNumPatch(int x, int y, int scrn, int lump, int cm, enum patch_translation_e flags) {} +static void NULL_PlotPixel(int scrn, int x, int y, byte color) {} +static void NULL_DrawLine(fline_t* fl, int color) {} + +const char *default_videomode; +static video_mode_t current_videomode = VID_MODE8; + +V_CopyRect_f V_CopyRect = NULL_CopyRect; +V_FillRect_f V_FillRect = NULL_FillRect; +V_DrawNumPatch_f V_DrawNumPatch = NULL_DrawNumPatch; +V_DrawBackground_f V_DrawBackground = NULL_DrawBackground; +V_PlotPixel_f V_PlotPixel = NULL_PlotPixel; +V_DrawLine_f V_DrawLine = NULL_DrawLine; + +// +// V_InitMode +// +void V_InitMode(video_mode_t mode) { +#ifndef GL_DOOM + if (mode == VID_MODEGL) + mode = VID_MODE8; +#endif + switch (mode) { + case VID_MODE8: + lprintf(LO_INFO, "V_InitMode: using 8 bit video mode\n"); + V_CopyRect = FUNC_V_CopyRect; + V_FillRect = V_FillRect8; + V_DrawNumPatch = FUNC_V_DrawNumPatch; + V_DrawBackground = FUNC_V_DrawBackground; + V_PlotPixel = V_PlotPixel8; + V_DrawLine = WRAP_V_DrawLine; + current_videomode = VID_MODE8; + break; + case VID_MODE15: + lprintf(LO_INFO, "V_InitMode: using 15 bit video mode\n"); + V_CopyRect = FUNC_V_CopyRect; + V_FillRect = V_FillRect15; + V_DrawNumPatch = FUNC_V_DrawNumPatch; + V_DrawBackground = FUNC_V_DrawBackground; + V_PlotPixel = V_PlotPixel15; + V_DrawLine = WRAP_V_DrawLine; + current_videomode = VID_MODE15; + break; + case VID_MODE16: + lprintf(LO_INFO, "V_InitMode: using 16 bit video mode\n"); + V_CopyRect = FUNC_V_CopyRect; + V_FillRect = V_FillRect16; + V_DrawNumPatch = FUNC_V_DrawNumPatch; + V_DrawBackground = FUNC_V_DrawBackground; + V_PlotPixel = V_PlotPixel16; + V_DrawLine = WRAP_V_DrawLine; + current_videomode = VID_MODE16; + break; + case VID_MODE32: + lprintf(LO_INFO, "V_InitMode: using 32 bit video mode\n"); + V_CopyRect = FUNC_V_CopyRect; + V_FillRect = V_FillRect32; + V_DrawNumPatch = FUNC_V_DrawNumPatch; + V_DrawBackground = FUNC_V_DrawBackground; + V_PlotPixel = V_PlotPixel32; + V_DrawLine = WRAP_V_DrawLine; + current_videomode = VID_MODE32; + break; +#ifdef GL_DOOM + case VID_MODEGL: + lprintf(LO_INFO, "V_InitMode: using OpenGL video mode\n"); + V_CopyRect = WRAP_gld_CopyRect; + V_FillRect = WRAP_gld_FillRect; + V_DrawNumPatch = WRAP_gld_DrawNumPatch; + V_DrawBackground = WRAP_gld_DrawBackground; + V_PlotPixel = V_PlotPixelGL; + V_DrawLine = WRAP_gld_DrawLine; + current_videomode = VID_MODEGL; + break; +#endif + default: break; + } + R_FilterInit(); +} + +// +// V_GetMode +// +video_mode_t V_GetMode(void) { + return current_videomode; +} + +// +// V_GetModePixelDepth +// +int V_GetModePixelDepth(video_mode_t mode) { + switch (mode) { + case VID_MODE8: return 1; + case VID_MODE15: return 2; + case VID_MODE16: return 2; + case VID_MODE32: return 4; + default: return 0; + } +} + +// +// V_GetNumPixelBits +// +int V_GetNumPixelBits(void) { + switch (current_videomode) { + case VID_MODE8: return 8; + case VID_MODE15: return 15; + case VID_MODE16: return 16; + case VID_MODE32: return 32; + default: return 0; + } +} + +// +// V_GetPixelDepth +// +int V_GetPixelDepth(void) { + return V_GetModePixelDepth(current_videomode); +} + +// +// V_AllocScreen +// +void V_AllocScreen(screeninfo_t *scrn) { + if (!scrn->not_on_heap) + if ((scrn->byte_pitch * scrn->height) > 0) + scrn->data = malloc(scrn->byte_pitch*scrn->height); +} + +// +// V_AllocScreens +// +void V_AllocScreens(void) { + int i; + + for (i=0; inot_on_heap) { + free(scrn->data); + scrn->data = NULL; + } +} + +// +// V_FreeScreens +// +void V_FreeScreens(void) { + int i; + + for (i=0; ia.x < 0 || fl->a.x >= SCREENWIDTH + || fl->a.y < 0 || fl->a.y >= SCREENHEIGHT + || fl->b.x < 0 || fl->b.x >= SCREENWIDTH + || fl->b.y < 0 || fl->b.y >= SCREENHEIGHT + ) + { + //jff 8/3/98 use logical output routine + lprintf(LO_DEBUG, "fuck %d \r", fuck++); + return; + } +#endif + +#define PUTDOT(xx,yy,cc) V_PlotPixel(0,xx,yy,(byte)cc) + + dx = fl->b.x - fl->a.x; + ax = 2 * (dx<0 ? -dx : dx); + sx = dx<0 ? -1 : 1; + + dy = fl->b.y - fl->a.y; + ay = 2 * (dy<0 ? -dy : dy); + sy = dy<0 ? -1 : 1; + + x = fl->a.x; + y = fl->a.y; + + if (ax > ay) + { + d = ay - ax/2; + while (1) + { + PUTDOT(x,y,color); + if (x == fl->b.x) return; + if (d>=0) + { + y += sy; + d -= ax; + } + x += sx; + d += ay; + } + } + else + { + d = ax - ay/2; + while (1) + { + PUTDOT(x, y, color); + if (y == fl->b.y) return; + if (d >= 0) + { + x += sx; + d -= ay; + } + y += sy; + d += ax; + } + } +} diff --git a/common/prboom/v_video.h b/common/prboom/v_video.h new file mode 100755 index 0000000..76cfaa2 --- /dev/null +++ b/common/prboom/v_video.h @@ -0,0 +1,207 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Gamma correction LUT. + * Color range translation support + * Functions to draw patches (by post) directly to screen. + * Functions to blit a block to the screen. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __V_VIDEO__ +#define __V_VIDEO__ + +#include "doomtype.h" +#include "doomdef.h" +// Needed because we are refering to patches. +#include "r_data.h" + +// +// VIDEO +// + +#define CENTERY (SCREENHEIGHT/2) + +// Screen 0 is the screen updated by I_Update screen. +// Screen 1 is an extra buffer. + +// array of pointers to color translation tables +extern const byte *colrngs[]; + +// symbolic indices into color translation table pointer array +typedef enum +{ + CR_BRICK, //0 + CR_TAN, //1 + CR_GRAY, //2 + CR_GREEN, //3 + CR_BROWN, //4 + CR_GOLD, //5 + CR_RED, //6 + CR_BLUE, //7 + CR_ORANGE, //8 + CR_YELLOW, //9 + CR_BLUE2, //10 // proff + CR_LIMIT //11 //jff 2/27/98 added for range check +} crange_idx_e; +//jff 1/16/98 end palette color range additions + +#define CR_DEFAULT CR_RED /* default value for out of range colors */ + +typedef struct { + byte *data; // pointer to the screen content + boolean not_on_heap; // if set, no malloc or free is preformed and + // data never set to NULL. Used i.e. with SDL doublebuffer. + int width; // the width of the surface + int height; // the height of the surface, used when mallocing + int byte_pitch; // tha actual width of one line, used when mallocing + int short_pitch; // tha actual width of one line, used when mallocing + int int_pitch; // tha actual width of one line, used when mallocing +} screeninfo_t; + +#define NUM_SCREENS 6 +extern screeninfo_t screens[NUM_SCREENS]; +extern int usegamma; + +// Varying bit-depth support -POPE +// +// For bilinear filtering, each palette color is pre-weighted and put in a +// table for fast blending operations. These macros decide how many weights +// to create for each color. The lower the number, the lower the blend +// accuracy, which can produce very bad artifacts in texture filtering. +#define VID_NUMCOLORWEIGHTS 64 +#define VID_COLORWEIGHTMASK (VID_NUMCOLORWEIGHTS-1) +#define VID_COLORWEIGHTBITS 6 + +// Palettes for converting from 8 bit color to 16 and 32 bit. Also +// contains the weighted versions of each palette color for filtering +// operations +extern unsigned short *V_Palette15; +extern unsigned short *V_Palette16; +extern unsigned int *V_Palette32; + +#define VID_PAL15(color, weight) V_Palette15[ (color)*VID_NUMCOLORWEIGHTS + (weight) ] +#define VID_PAL16(color, weight) V_Palette16[ (color)*VID_NUMCOLORWEIGHTS + (weight) ] +#define VID_PAL32(color, weight) V_Palette32[ (color)*VID_NUMCOLORWEIGHTS + (weight) ] + +// The available bit-depth modes +typedef enum { + VID_MODE8, + VID_MODE15, + VID_MODE16, + VID_MODE32, + VID_MODEGL, + VID_MODEMAX +} video_mode_t; + +extern const char *default_videomode; + +void V_InitMode(video_mode_t mode); + +// video mode query interface +video_mode_t V_GetMode(void); +int V_GetModePixelDepth(video_mode_t mode); +int V_GetNumPixelBits(void); +int V_GetPixelDepth(void); + +//jff 4/24/98 loads color translation lumps +void V_InitColorTranslation(void); + +// Allocates buffer screens, call before R_Init. +void V_Init (void); + +// V_CopyRect +typedef void (*V_CopyRect_f)(int srcx, int srcy, int srcscrn, + int width, int height, + int destx, int desty, int destscrn, + enum patch_translation_e flags); +extern V_CopyRect_f V_CopyRect; + +// V_FillRect +typedef void (*V_FillRect_f)(int scrn, int x, int y, + int width, int height, byte colour); +extern V_FillRect_f V_FillRect; + +// CPhipps - patch drawing +// Consolidated into the 3 really useful functions: + +// V_DrawNumPatch - Draws the patch from lump num +typedef void (*V_DrawNumPatch_f)(int x, int y, int scrn, + int lump, int cm, + enum patch_translation_e flags); +extern V_DrawNumPatch_f V_DrawNumPatch; + +// V_DrawNamePatch - Draws the patch from lump "name" +#define V_DrawNamePatch(x,y,s,n,t,f) V_DrawNumPatch(x,y,s,W_GetNumForName(n),t,f) + +/* cph - + * Functions to return width & height of a patch. + * Doesn't really belong here, but is often used in conjunction with + * this code. + */ +#define V_NamePatchWidth(name) R_NumPatchWidth(W_GetNumForName(name)) +#define V_NamePatchHeight(name) R_NumPatchHeight(W_GetNumForName(name)) + +/* cphipps 10/99: function to tile a flat over the screen */ +typedef void (*V_DrawBackground_f)(const char* flatname, int scrn); +extern V_DrawBackground_f V_DrawBackground; + +void V_DestroyUnusedTrueColorPalettes(void); +// CPhipps - function to set the palette to palette number pal. +void V_SetPalette(int pal); + +// CPhipps - function to plot a pixel + +// V_PlotPixel +typedef void (*V_PlotPixel_f)(int,int,int,byte); +extern V_PlotPixel_f V_PlotPixel; + +typedef struct +{ + int x, y; +} fpoint_t; + +typedef struct +{ + fpoint_t a, b; +} fline_t; + +// V_DrawLine +typedef void (*V_DrawLine_f)(fline_t* fl, int color); +extern V_DrawLine_f V_DrawLine; + +void V_AllocScreen(screeninfo_t *scrn); +void V_AllocScreens(); +void V_FreeScreen(screeninfo_t *scrn); +void V_FreeScreens(); + +#ifdef GL_DOOM +#include "gl_struct.h" +#endif +#endif diff --git a/common/prboom/version.c b/common/prboom/version.c new file mode 100755 index 0000000..142017e --- /dev/null +++ b/common/prboom/version.c @@ -0,0 +1,38 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Date stamp + * + *----------------------------------------------------------------------------- + */ + + +#include "version.h" + +const char version_date[] = __DATE__; diff --git a/common/prboom/version.h b/common/prboom/version.h new file mode 100755 index 0000000..f7ad161 --- /dev/null +++ b/common/prboom/version.h @@ -0,0 +1,40 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Doom version indicators. + * + *-----------------------------------------------------------------------------*/ + + +#ifndef __DOOMVERSION__ +#define __DOOMVERSION__ + +extern const char version_date[]; + +#endif diff --git a/common/prboom/w_memcache.c b/common/prboom/w_memcache.c new file mode 100755 index 0000000..ee1316d --- /dev/null +++ b/common/prboom/w_memcache.c @@ -0,0 +1,165 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2001 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Handles in-memory caching of WAD lumps + * + *----------------------------------------------------------------------------- + */ + +// use config.h if autoconf made one -- josh +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "doomstat.h" +#include "doomtype.h" + +#ifdef __GNUG__ +#pragma implementation "w_wad.h" +#endif +#include "w_wad.h" +#include "z_zone.h" +#include "lprintf.h" + +static struct { + void *cache; +#ifdef TIMEDIAG + int locktic; +#endif + unsigned int locks; +} *cachelump; + +#ifdef HEAPDUMP +void W_PrintLump(FILE* fp, void* p) { + int i; + for (i=0; i= (unsigned)numlumps) + I_Error ("W_CacheLumpNum: %i >= numlumps",lump); +#endif + + if (!cachelump[lump].cache) // read the lump in + W_ReadLump(lump, Z_Malloc(W_LumpLength(lump), PU_CACHE, &cachelump[lump].cache)); + + /* cph - if wasn't locked but now is, tell z_zone to hold it */ + if (!cachelump[lump].locks && locks) { + Z_ChangeTag(cachelump[lump].cache,PU_STATIC); +#ifdef TIMEDIAG + cachelump[lump].locktic = gametic; +#endif + } + cachelump[lump].locks += locks; + +#ifdef SIMPLECHECKS + if (!((cachelump[lump].locks+1) & 0xf)) + lprintf(LO_DEBUG, "W_CacheLumpNum: High lock on %8s (%d)\n", + lumpinfo[lump].name, cachelump[lump].locks); +#endif + + return cachelump[lump].cache; +} + +const void *W_LockLumpNum(int lump) +{ + return W_CacheLumpNum(lump); +} + +/* + * W_UnlockLumpNum + * + * CPhipps - this changes (should reduce) the number of locks on a lump + */ + +void W_UnlockLumpNum(int lump) +{ + const int unlocks = 1; +#ifdef SIMPLECHECKS + if ((signed short)cachelump[lump].locks < unlocks) + lprintf(LO_DEBUG, "W_UnlockLumpNum: Excess unlocks on %8s (%d-%d)\n", + lumpinfo[lump].name, cachelump[lump].locks, unlocks); +#endif + cachelump[lump].locks -= unlocks; + /* cph - Note: must only tell z_zone to make purgeable if currently locked, + * else it might already have been purged + */ + if (unlocks && !cachelump[lump].locks) + Z_ChangeTag(cachelump[lump].cache, PU_CACHE); +} + diff --git a/common/prboom/w_mmap.c b/common/prboom/w_mmap.c new file mode 100755 index 0000000..ace3607 --- /dev/null +++ b/common/prboom/w_mmap.c @@ -0,0 +1,334 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 2001 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Transparent access to data in WADs using mmap + * + *----------------------------------------------------------------------------- + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#else +#include +#endif + +#include "doomstat.h" +#include "doomtype.h" + +#ifdef __GNUG__ +#pragma implementation "w_wad.h" +#endif +#include "w_wad.h" +#include "z_zone.h" +#include "lprintf.h" +#include "i_system.h" + +static struct { + void *cache; +#ifdef TIMEDIAG + int locktic; +#endif + int locks; +} *cachelump; + +#ifdef HEAPDUMP +void W_PrintLump(FILE* fp, void* p) { + int i; + for (i=0; i 0) + lprintf(LO_DEBUG, "%8.8s %6u %2d %6d\n", lumpinfo[i].name, + W_LumpLength(i), cachelump[i].locks, gametic - cachelump[i].locktic); + } +} +#endif + +#ifdef _WIN32 +typedef struct { + HANDLE hnd; + OFSTRUCT fileinfo; + HANDLE hnd_map; + void *data; +} mmap_info_t; + +mmap_info_t *mapped_wad; + +void W_DoneCache(void) +{ + size_t i; + + if (cachelump) { + free(cachelump); + cachelump = NULL; + } + + if (!mapped_wad) + return; + for (i=0; i=numwadfiles)) + I_Error("W_InitCache: wad_index out of range"); +#endif + if (!mapped_wad[wad_index].data) + { + mapped_wad[wad_index].hnd = + (HANDLE)OpenFile( + wadfiles[wad_index].name, + &mapped_wad[wad_index].fileinfo, + OF_READ + ); + if (mapped_wad[wad_index].hnd==(HANDLE)HFILE_ERROR) + I_Error("W_InitCache: OpenFile for memory mapping failed (LastError %i)",GetLastError()); + mapped_wad[wad_index].hnd_map = + CreateFileMapping( + mapped_wad[wad_index].hnd, + NULL, + PAGE_READONLY, + 0, + 0, + NULL + ); + if (mapped_wad[wad_index].hnd_map==NULL) + I_Error("W_InitCache: CreateFileMapping for memory mapping failed (LastError %i)",GetLastError()); + mapped_wad[wad_index].data = + MapViewOfFile( + mapped_wad[wad_index].hnd_map, + FILE_MAP_READ, + 0, + 0, + 0 + ); + if (mapped_wad[wad_index].hnd_map==NULL) + I_Error("W_InitCache: MapViewOfFile for memory mapping failed (LastError %i)",GetLastError()); + } + } + } +} + +const void* W_CacheLumpNum(int lump) +{ + int wad_index = (int)(lumpinfo[lump].wadfile-wadfiles); +#ifdef RANGECHECK + if ((wad_index<0)||((size_t)wad_index>=numwadfiles)) + I_Error("W_CacheLumpNum: wad_index out of range"); + if ((unsigned)lump >= (unsigned)numlumps) + I_Error ("W_CacheLumpNum: %i >= numlumps",lump); +#endif + if (!lumpinfo[lump].wadfile) + return NULL; + return (void*)((unsigned char *)mapped_wad[wad_index].data+lumpinfo[lump].position); +} + +#else + +void ** mapped_wad; + +void W_InitCache(void) +{ + int maxfd = 0; + // set up caching + cachelump = calloc(numlumps, sizeof *cachelump); + if (!cachelump) + I_Error ("W_Init: Couldn't allocate lumpcache"); + +#ifdef TIMEDIAG + atexit(W_ReportLocks); +#endif + + { + int i; + for (i=0; ihandle > maxfd) maxfd = lumpinfo[i].wadfile->handle; + } + mapped_wad = calloc(maxfd+1,sizeof *mapped_wad); + { + int i; + for (i=0; ihandle; + if (!mapped_wad[fd]) + if ((mapped_wad[fd] = mmap(NULL,I_Filelength(fd),PROT_READ,MAP_SHARED,fd,0)) == MAP_FAILED) + I_Error("W_InitCache: failed to mmap"); + } + } + } +} + +void W_DoneCache(void) +{ + { + int i; + for (i=0; ihandle; + if (mapped_wad[fd]) { + if (munmap(mapped_wad[fd],I_Filelength(fd))) + I_Error("W_DoneCache: failed to munmap"); + mapped_wad[fd] = NULL; + } + } + } + free(mapped_wad); +} + +const void* W_CacheLumpNum(int lump) +{ +#ifdef RANGECHECK + if ((unsigned)lump >= (unsigned)numlumps) + I_Error ("W_CacheLumpNum: %i >= numlumps",lump); +#endif +// printf( "W_CacheLumpNum( %i ) = %s\n", lump, lumpinfo[lump].name ); // JDC tracking hitches + if (!lumpinfo[lump].wadfile) + return NULL; + return ((unsigned char*)mapped_wad[lumpinfo[lump].wadfile->handle]+lumpinfo[lump].position); +} +#endif + +/* + * W_LockLumpNum + * + * This copies the lump into a malloced memory region and returns its address + * instead of returning a pointer into the memory mapped area + * + */ +const void* W_LockLumpNum(int lump) +{ + size_t len = W_LumpLength(lump); + const void *data = W_CacheLumpNum(lump); + + if (!cachelump[lump].cache) { + // read the lump in + Z_Malloc(len, PU_CACHE, &cachelump[lump].cache); + memcpy(cachelump[lump].cache, data, len); + } + + /* cph - if wasn't locked but now is, tell z_zone to hold it */ + if (cachelump[lump].locks <= 0) { + Z_ChangeTag(cachelump[lump].cache,PU_STATIC); +#ifdef TIMEDIAG + cachelump[lump].locktic = gametic; +#endif + // reset lock counter + cachelump[lump].locks = 1; + } else { + // increment lock counter + cachelump[lump].locks += 1; + } + +#ifdef SIMPLECHECKS + if (!((cachelump[lump].locks+1) & 0xf)) + lprintf(LO_DEBUG, "W_CacheLumpNum: High lock on %8s (%d)\n", + lumpinfo[lump].name, cachelump[lump].locks); +#endif + + return cachelump[lump].cache; +} + +void W_UnlockLumpNum(int lump) { + if (cachelump[lump].locks == -1) + return; // this lump is memory mapped + +#ifdef SIMPLECHECKS + if (cachelump[lump].locks == 0) + lprintf(LO_DEBUG, "W_UnlockLumpNum: Excess unlocks on %8s\n", + lumpinfo[lump].name); +#endif + cachelump[lump].locks -= 1; + /* cph - Note: must only tell z_zone to make purgeable if currently locked, + * else it might already have been purged + */ + if (cachelump[lump].locks == 0) + Z_ChangeTag(cachelump[lump].cache, PU_CACHE); +} + diff --git a/common/prboom/w_wad.c b/common/prboom/w_wad.c new file mode 100755 index 0000000..d650b4f --- /dev/null +++ b/common/prboom/w_wad.c @@ -0,0 +1,478 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2001 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Handles WAD file header, directory, lump I/O. + * + *----------------------------------------------------------------------------- + */ +// use config.h if autoconf made one -- josh +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef _MSC_VER +#include +#include +#endif +#include + +#include "doomstat.h" +#include "d_net.h" +#include "doomtype.h" +#include "i_system.h" + +#ifdef __GNUG__ +#pragma implementation "w_wad.h" +#endif +#include "w_wad.h" +#include "lprintf.h" + +// +// GLOBALS +// + +// Location of each lump on disk. +lumpinfo_t *lumpinfo; +int numlumps; // killough + +void ExtractFileBase (const char *path, char *dest) +{ + const char *src = path + strlen(path) - 1; + int length; + + // back up until a \ or the start + while (src != path && src[-1] != ':' // killough 3/22/98: allow c:filename + && *(src-1) != '\\' + && *(src-1) != '/') + { + src--; + } + + // copy up to eight characters + memset(dest,0,8); + length = 0; + + while ((*src) && (*src != '.') && (++length<9)) + { + *dest++ = toupper(*src); + src++; + } + /* cph - length check removed, just truncate at 8 chars. + * If there are 8 or more chars, we'll copy 8, and no zero termination + */ +} + +// +// 1/18/98 killough: adds a default extension to a path +// Note: Backslashes are treated specially, for MS-DOS. +// + +char *AddDefaultExtension(char *path, const char *ext) +{ + char *p = path; + while (*p++); + while (p-->path && *p!='/' && *p!='\\') + if (*p=='.') + return path; + if (*ext!='.') + strcat(path,"."); + return strcat(path,ext); +} + +// +// LUMP BASED ROUTINES. +// + +// +// W_AddFile +// All files are optional, but at least one file must be +// found (PWAD, if all required lumps are present). +// Files with a .wad extension are wadlink files +// with multiple lumps. +// Other files are single lumps with the base filename +// for the lump name. +// +// Reload hack removed by Lee Killough +// CPhipps - source is an enum +// +// proff - changed using pointer to wadfile_info_t +static void W_AddFile(wadfile_info_t *wadfile) +// killough 1/31/98: static, const +{ + wadinfo_t header; + lumpinfo_t* lump_p; + unsigned i; + int length; + int startlump; + filelump_t *fileinfo, *fileinfo2free=NULL; //killough + filelump_t singleinfo; + + // open the file and add to directory + + wadfile->handle = open(wadfile->name,O_RDONLY | O_BINARY); + +#ifdef HAVE_NET + if (wadfile->handle == -1 && D_NetGetWad(wadfile->name)) // CPhipps + wadfile->handle = open(wadfile->name,O_RDONLY | O_BINARY); +#endif + + if (wadfile->handle == -1) + { + if ( strlen(wadfile->name)<=4 || // add error check -- killough + (strcasecmp(wadfile->name+strlen(wadfile->name)-4 , ".lmp" ) && + strcasecmp(wadfile->name+strlen(wadfile->name)-4 , ".gwa" ) ) + ) + I_Error("W_AddFile: couldn't open %s",wadfile->name); + return; + } + + //jff 8/3/98 use logical output routine + lprintf (LO_INFO," adding %s\n",wadfile->name); + startlump = numlumps; + + if ( strlen(wadfile->name)<=4 || + ( + strcasecmp(wadfile->name+strlen(wadfile->name)-4,".wad") && + strcasecmp(wadfile->name+strlen(wadfile->name)-4,".gwa") + ) + ) + { + // single lump file + fileinfo = &singleinfo; + singleinfo.filepos = 0; + singleinfo.size = LONG(I_Filelength(wadfile->handle)); + ExtractFileBase(wadfile->name, singleinfo.name); + numlumps++; + } + else + { + // WAD file + I_Read(wadfile->handle, &header, sizeof(header)); + if (strncmp(header.identification,"IWAD",4) && + strncmp(header.identification,"PWAD",4)) + I_Error("W_AddFile: Wad file %s doesn't have IWAD or PWAD id", wadfile->name); + header.numlumps = LONG(header.numlumps); + header.infotableofs = LONG(header.infotableofs); + length = header.numlumps*sizeof(filelump_t); + fileinfo2free = fileinfo = malloc(length); // killough + lseek(wadfile->handle, header.infotableofs, SEEK_SET); + I_Read(wadfile->handle, fileinfo, length); + numlumps += header.numlumps; + } + + // Fill in lumpinfo + lumpinfo = realloc(lumpinfo, numlumps*sizeof(lumpinfo_t)); + + lump_p = &lumpinfo[startlump]; + + for (i=startlump ; (int)iwadfile = wadfile; // killough 4/25/98 + lump_p->position = LONG(fileinfo->filepos); + lump_p->size = LONG(fileinfo->size); + lump_p->li_namespace = ns_global; // killough 4/17/98 + strncpy (lump_p->name, fileinfo->name, 8); + lump_p->source = wadfile->src; // Ty 08/29/98 + } + + free(fileinfo2free); // killough +} + +// jff 1/23/98 Create routines to reorder the master directory +// putting all flats into one marked block, and all sprites into another. +// This will allow loading of sprites and flats from a PWAD with no +// other changes to code, particularly fast hashes of the lumps. +// +// killough 1/24/98 modified routines to be a little faster and smaller + +static int IsMarker(const char *marker, const char *name) +{ + return !strncasecmp(name, marker, 8) || + (*name == *marker && !strncasecmp(name+1, marker, 7)); +} + +// killough 4/17/98: add namespace tags + +static void W_CoalesceMarkedResource(const char *start_marker, + const char *end_marker, int li_namespace) +{ + lumpinfo_t *marked = malloc(sizeof(*marked) * numlumps); + size_t i, num_marked = 0, num_unmarked = 0; + int is_marked = 0, mark_end = 0; + lumpinfo_t *lump = lumpinfo; + + for (i=numlumps; i--; lump++) + if (IsMarker(start_marker, lump->name)) // start marker found + { // If this is the first start marker, add start marker to marked lumps + if (!num_marked) + { + strncpy(marked->name, start_marker, 8); + marked->size = 0; // killough 3/20/98: force size to be 0 + marked->li_namespace = ns_global; // killough 4/17/98 + marked->wadfile = NULL; + num_marked = 1; + } + is_marked = 1; // start marking lumps + } + else + if (IsMarker(end_marker, lump->name)) // end marker found + { + mark_end = 1; // add end marker below + is_marked = 0; // stop marking lumps + } + else + if (is_marked) // if we are marking lumps, + { // move lump to marked list + marked[num_marked] = *lump; + marked[num_marked++].li_namespace = li_namespace; // killough 4/17/98 + } + else + lumpinfo[num_unmarked++] = *lump; // else move down THIS list + + // Append marked list to end of unmarked list + memcpy(lumpinfo + num_unmarked, marked, num_marked * sizeof(*marked)); + + free(marked); // free marked list + + numlumps = num_unmarked + num_marked; // new total number of lumps + + if (mark_end) // add end marker + { + lumpinfo[numlumps].size = 0; // killough 3/20/98: force size to be 0 + lumpinfo[numlumps].wadfile = NULL; + lumpinfo[numlumps].li_namespace = ns_global; // killough 4/17/98 + strncpy(lumpinfo[numlumps++].name, end_marker, 8); + } +} + +// Hash function used for lump names. +// Must be mod'ed with table size. +// Can be used for any 8-character names. +// by Lee Killough + +unsigned W_LumpNameHash(const char *s) +{ + unsigned hash; + (void) ((hash = toupper(s[0]), s[1]) && + (hash = hash*3+toupper(s[1]), s[2]) && + (hash = hash*2+toupper(s[2]), s[3]) && + (hash = hash*2+toupper(s[3]), s[4]) && + (hash = hash*2+toupper(s[4]), s[5]) && + (hash = hash*2+toupper(s[5]), s[6]) && + (hash = hash*2+toupper(s[6]), + hash = hash*2+toupper(s[7])) + ); + return hash; +} + +// +// W_CheckNumForName +// Returns -1 if name not found. +// +// Rewritten by Lee Killough to use hash table for performance. Significantly +// cuts down on time -- increases Doom performance over 300%. This is the +// single most important optimization of the original Doom sources, because +// lump name lookup is used so often, and the original Doom used a sequential +// search. For large wads with > 1000 lumps this meant an average of over +// 500 were probed during every search. Now the average is under 2 probes per +// search. There is no significant benefit to packing the names into longwords +// with this new hashing algorithm, because the work to do the packing is +// just as much work as simply doing the string comparisons with the new +// algorithm, which minimizes the expected number of comparisons to under 2. +// +// killough 4/17/98: add namespace parameter to prevent collisions +// between different resources such as flats, sprites, colormaps +// + +int (W_CheckNumForName)(register const char *name, register int li_namespace) +{ + // Hash function maps the name to one of possibly numlump chains. + // It has been tuned so that the average chain length never exceeds 2. + + // proff 2001/09/07 - check numlumps==0, this happens when called before WAD loaded + register int i = (numlumps==0)?(-1):(lumpinfo[W_LumpNameHash(name) % (unsigned) numlumps].index); + + // We search along the chain until end, looking for case-insensitive + // matches which also match a namespace tag. Separate hash tables are + // not used for each namespace, because the performance benefit is not + // worth the overhead, considering namespace collisions are rare in + // Doom wads. + + while (i >= 0 && (strncasecmp(lumpinfo[i].name, name, 8) || + lumpinfo[i].li_namespace != li_namespace)) + i = lumpinfo[i].next; + + // Return the matching lump, or -1 if none found. + + return i; +} + +// +// killough 1/31/98: Initialize lump hash table +// + +void W_HashLumps(void) +{ + int i; + + for (i=0; i= numlumps) + I_Error ("W_LumpLength: %i >= numlumps",lump); + return lumpinfo[lump].size; +} + +// +// W_ReadLump +// Loads the lump into the given buffer, +// which must be >= W_LumpLength(). +// + +void W_ReadLump(int lump, void *dest) +{ + lumpinfo_t *l = lumpinfo + lump; + +#ifdef RANGECHECK + if (lump >= numlumps) + I_Error ("W_ReadLump: %i >= numlumps",lump); +#endif + + { + if (l->wadfile) + { + lseek(l->wadfile->handle, l->position, SEEK_SET); + I_Read(l->wadfile->handle, dest, l->size); + } + } +} + diff --git a/common/prboom/w_wad.h b/common/prboom/w_wad.h new file mode 100755 index 0000000..7199b90 --- /dev/null +++ b/common/prboom/w_wad.h @@ -0,0 +1,143 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * WAD I/O functions. + * + *-----------------------------------------------------------------------------*/ + + +#ifndef __W_WAD__ +#define __W_WAD__ + + +// +// TYPES +// + +typedef struct +{ + char identification[4]; // Should be "IWAD" or "PWAD". + int numlumps; + int infotableofs; +} wadinfo_t; + +typedef struct +{ + int filepos; + int size; + char name[8]; +} filelump_t; + +// +// WADFILE I/O related stuff. +// + +// CPhipps - defined enum in wider scope +// Ty 08/29/98 - add source field to identify where this lump came from +typedef enum { + // CPhipps - define elements in order of 'how new/unusual' + source_iwad=0, // iwad file load + source_pre, // predefined lump + source_auto_load, // lump auto-loaded by config file + source_pwad, // pwad file load + source_lmp, // lmp file load + source_net // CPhipps +} wad_source_t; + +// CPhipps - changed wad init +// We _must_ have the wadfiles[] the same as those actually loaded, so there +// is no point having these separate entities. This belongs here. +typedef struct { + const char* name; + wad_source_t src; + int handle; +} wadfile_info_t; + +extern wadfile_info_t *wadfiles; + +extern size_t numwadfiles; // CPhipps - size of the wadfiles array + +void W_Init(void); // CPhipps - uses the above array +void W_ReleaseAllWads(void); // Proff - Added for iwad switching +void W_InitCache(void); +void W_DoneCache(void); + +typedef struct +{ + // WARNING: order of some fields important (see info.c). + + char name[9]; + int size; + + // killough 1/31/98: hash table fields, used for ultra-fast hash table lookup + int index, next; + + // killough 4/17/98: namespace tags, to prevent conflicts between resources + enum { + ns_global=0, + ns_sprites, + ns_flats, + ns_colormaps, + ns_prboom + } li_namespace; // haleyjd 05/21/02: renamed from "namespace" + + wadfile_info_t *wadfile; + int position; + wad_source_t source; +} lumpinfo_t; + +extern lumpinfo_t *lumpinfo; +extern int numlumps; + +// killough 4/17/98: if W_CheckNumForName() called with only +// one argument, pass ns_global as the default namespace + +#define W_CheckNumForName(name) (W_CheckNumForName)(name, ns_global) +int (W_CheckNumForName)(const char* name, int); // killough 4/17/98 +int W_GetNumForName (const char* name); +int W_LumpLength (int lump); +void W_ReadLump (int lump, void *dest); +// CPhipps - modified for 'new' lump locking +const void* W_CacheLumpNum (int lump); +const void* W_LockLumpNum(int lump); +void W_UnlockLumpNum(int lump); + +// CPhipps - convenience macros +//#define W_CacheLumpNum(num) (W_CacheLumpNum)((num),1) +#define W_CacheLumpName(name) W_CacheLumpNum (W_GetNumForName(name)) + +//#define W_UnlockLumpNum(num) (W_UnlockLumpNum)((num),1) +#define W_UnlockLumpName(name) W_UnlockLumpNum (W_GetNumForName(name)) + +char *AddDefaultExtension(char *, const char *); // killough 1/18/98 +void ExtractFileBase(const char *, char *); // killough +unsigned W_LumpNameHash(const char *s); // killough 1/31/98 +void W_HashLumps(void); // cph 2001/07/07 - made public + +#endif diff --git a/common/prboom/wi_stuff.c b/common/prboom/wi_stuff.c new file mode 100755 index 0000000..d025965 --- /dev/null +++ b/common/prboom/wi_stuff.c @@ -0,0 +1,2013 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Intermission screens. + * + *----------------------------------------------------------------------------- + */ + +#include "doomstat.h" +#include "m_random.h" +#include "w_wad.h" +#include "g_game.h" +#include "r_main.h" +#include "v_video.h" +#include "wi_stuff.h" +#include "s_sound.h" +#include "sounds.h" +#include "lprintf.h" // jff 08/03/98 - declaration of lprintf +#include "r_draw.h" + +// Ty 03/17/98: flag that new par times have been loaded in d_deh +extern boolean deh_pars; + +// +// Data needed to add patches to full screen intermission pics. +// Patches are statistics messages, and animations. +// Loads of by-pixel layout and placement, offsets etc. +// + +// +// Different vetween registered DOOM (1994) and +// Ultimate DOOM - Final edition (retail, 1995?). +// This is supposedly ignored for commercial +// release (aka DOOM II), which had 34 maps +// in one episode. So there. +#define NUMEPISODES 4 +#define NUMMAPS 9 + + +// Not used +// in tics +//U #define PAUSELEN (TICRATE*2) +//U #define SCORESTEP 100 +//U #define ANIMPERIOD 32 +// pixel distance from "(YOU)" to "PLAYER N" +//U #define STARDIST 10 +//U #define WK 1 + + +// GLOBAL LOCATIONS +#define WI_TITLEY 2 +#define WI_SPACINGY 33 + +// SINGLE-PLAYER STUFF +#define SP_STATSX 50 +#define SP_STATSY 50 + +#define SP_TIMEX 8 +// proff/nicolas 09/20/98 -- changed for hi-res +#define SP_TIMEY 160 +//#define SP_TIMEY (SCREENHEIGHT-32) + + +// NET GAME STUFF +#define NG_STATSY 50 +#define NG_STATSX (32 + V_NamePatchWidth(star)/2 + 32*!dofrags) + +#define NG_SPACINGX 64 + + +// Used to display the frags matrix at endgame +// DEATHMATCH STUFF +#define DM_MATRIXX 42 +#define DM_MATRIXY 68 + +#define DM_SPACINGX 40 + +#define DM_TOTALSX 269 + +#define DM_KILLERSX 10 +#define DM_KILLERSY 100 +#define DM_VICTIMSX 5 +#define DM_VICTIMSY 50 + + +// These animation variables, structures, etc. are used for the +// DOOM/Ultimate DOOM intermission screen animations. This is +// totally different from any sprite or texture/flat animations +typedef enum +{ + ANIM_ALWAYS, // determined by patch entry + ANIM_RANDOM, // occasional + ANIM_LEVEL // continuous +} animenum_t; + +typedef struct +{ + int x; // x/y coordinate pair structure + int y; +} point_t; + + +// +// Animation. +// There is another anim_t used in p_spec. +// +typedef struct +{ + animenum_t type; + + // period in tics between animations + int period; + + // number of animation frames + int nanims; + + // location of animation + point_t loc; + + // ALWAYS: n/a, + // RANDOM: period deviation (<256), + // LEVEL: level + int data1; + + // ALWAYS: n/a, + // RANDOM: random base period, + // LEVEL: n/a + int data2; + + /* actual graphics for frames of animations + * cphipps - const + */ + patchnum_t p[3]; + + // following must be initialized to zero before use! + + // next value of bcnt (used in conjunction with period) + int nexttic; + + // last drawn animation frame + int lastdrawn; + + // next frame number to animate + int ctr; + + // used by RANDOM and LEVEL when animating + int state; +} anim_t; + + +static point_t lnodes[NUMEPISODES][NUMMAPS] = +{ + // Episode 0 World Map + { + { 185, 164 }, // location of level 0 (CJ) + { 148, 143 }, // location of level 1 (CJ) + { 69, 122 }, // location of level 2 (CJ) + { 209, 102 }, // location of level 3 (CJ) + { 116, 89 }, // location of level 4 (CJ) + { 166, 55 }, // location of level 5 (CJ) + { 71, 56 }, // location of level 6 (CJ) + { 135, 29 }, // location of level 7 (CJ) + { 71, 24 } // location of level 8 (CJ) + }, + + // Episode 1 World Map should go here + { + { 254, 25 }, // location of level 0 (CJ) + { 97, 50 }, // location of level 1 (CJ) + { 188, 64 }, // location of level 2 (CJ) + { 128, 78 }, // location of level 3 (CJ) + { 214, 92 }, // location of level 4 (CJ) + { 133, 130 }, // location of level 5 (CJ) + { 208, 136 }, // location of level 6 (CJ) + { 148, 140 }, // location of level 7 (CJ) + { 235, 158 } // location of level 8 (CJ) + }, + + // Episode 2 World Map should go here + { + { 156, 168 }, // location of level 0 (CJ) + { 48, 154 }, // location of level 1 (CJ) + { 174, 95 }, // location of level 2 (CJ) + { 265, 75 }, // location of level 3 (CJ) + { 130, 48 }, // location of level 4 (CJ) + { 279, 23 }, // location of level 5 (CJ) + { 198, 48 }, // location of level 6 (CJ) + { 140, 25 }, // location of level 7 (CJ) + { 281, 136 } // location of level 8 (CJ) + } +}; + + +// +// Animation locations for episode 0 (1). +// Using patches saves a lot of space, +// as they replace 320x200 full screen frames. +// +static anim_t epsd0animinfo[] = +{ + { ANIM_ALWAYS, TICRATE/3, 3, { 224, 104 }, 0, 0, { {0, 0, 0, 0, 0} }, 0, 0, 0, 0 }, + { ANIM_ALWAYS, TICRATE/3, 3, { 184, 160 }, 0, 0, { {0, 0, 0, 0, 0} }, 0, 0, 0, 0 }, + { ANIM_ALWAYS, TICRATE/3, 3, { 112, 136 }, 0, 0, { {0, 0, 0, 0, 0} }, 0, 0, 0, 0 }, + { ANIM_ALWAYS, TICRATE/3, 3, { 72, 112 }, 0, 0, { {0, 0, 0, 0, 0} }, 0, 0, 0, 0 }, + { ANIM_ALWAYS, TICRATE/3, 3, { 88, 96 }, 0, 0, { {0, 0, 0, 0, 0} }, 0, 0, 0, 0 }, + { ANIM_ALWAYS, TICRATE/3, 3, { 64, 48 }, 0, 0, { {0, 0, 0, 0, 0} }, 0, 0, 0, 0 }, + { ANIM_ALWAYS, TICRATE/3, 3, { 192, 40 }, 0, 0, { {0, 0, 0, 0, 0} }, 0, 0, 0, 0 }, + { ANIM_ALWAYS, TICRATE/3, 3, { 136, 16 }, 0, 0, { {0, 0, 0, 0, 0} }, 0, 0, 0, 0 }, + { ANIM_ALWAYS, TICRATE/3, 3, { 80, 16 }, 0, 0, { {0, 0, 0, 0, 0} }, 0, 0, 0, 0 }, + { ANIM_ALWAYS, TICRATE/3, 3, { 64, 24 }, 0, 0, { {0, 0, 0, 0, 0} }, 0, 0, 0, 0 } +}; + +static anim_t epsd1animinfo[] = +{ + { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 1, 0, { {0, 0, 0, 0, 0} }, 0, 0, 0, 0 }, + { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 2, 0, { {0, 0, 0, 0, 0} }, 0, 0, 0, 0 }, + { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 3, 0, { {0, 0, 0, 0, 0} }, 0, 0, 0, 0 }, + { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 4, 0, { {0, 0, 0, 0, 0} }, 0, 0, 0, 0 }, + { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 5, 0, { {0, 0, 0, 0, 0} }, 0, 0, 0, 0 }, + { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 6, 0, { {0, 0, 0, 0, 0} }, 0, 0, 0, 0 }, + { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 7, 0, { {0, 0, 0, 0, 0} }, 0, 0, 0, 0 }, + { ANIM_LEVEL, TICRATE/3, 3, { 192, 144 }, 8, 0, { {0, 0, 0, 0, 0} }, 0, 0, 0, 0 }, + { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 8, 0, { {0, 0, 0, 0, 0} }, 0, 0, 0, 0 } +}; + +static anim_t epsd2animinfo[] = +{ + { ANIM_ALWAYS, TICRATE/3, 3, { 104, 168 }, 0, 0, { {0, 0, 0, 0, 0} }, 0, 0, 0, 0 }, + { ANIM_ALWAYS, TICRATE/3, 3, { 40, 136 }, 0, 0, { {0, 0, 0, 0, 0} }, 0, 0, 0, 0 }, + { ANIM_ALWAYS, TICRATE/3, 3, { 160, 96 }, 0, 0, { {0, 0, 0, 0, 0} }, 0, 0, 0, 0 }, + { ANIM_ALWAYS, TICRATE/3, 3, { 104, 80 }, 0, 0, { {0, 0, 0, 0, 0} }, 0, 0, 0, 0 }, + { ANIM_ALWAYS, TICRATE/3, 3, { 120, 32 }, 0, 0, { {0, 0, 0, 0, 0} }, 0, 0, 0, 0 }, + { ANIM_ALWAYS, TICRATE/4, 3, { 40, 0 }, 0, 0, { {0, 0, 0, 0, 0} }, 0, 0, 0, 0 } +}; + +static int NUMANIMS[NUMEPISODES] = +{ + sizeof(epsd0animinfo)/sizeof(anim_t), + sizeof(epsd1animinfo)/sizeof(anim_t), + sizeof(epsd2animinfo)/sizeof(anim_t) +}; + +static anim_t *anims[NUMEPISODES] = +{ + epsd0animinfo, + epsd1animinfo, + epsd2animinfo +}; + + +// +// GENERAL DATA +// + +// +// Locally used stuff. +// +#define FB 0 + + +// States for single-player +#define SP_KILLS 0 +#define SP_ITEMS 2 +#define SP_SECRET 4 +#define SP_FRAGS 6 +#define SP_TIME 8 +#define SP_PAR ST_TIME + +#define SP_PAUSE 1 + +// in seconds +#define SHOWNEXTLOCDELAY 4 +//#define SHOWLASTLOCDELAY SHOWNEXTLOCDELAY + + +// used to accelerate or skip a stage +int acceleratestage; // killough 3/28/98: made global + +// wbs->pnum +static int me; + + // specifies current state +static stateenum_t state; + +// contains information passed into intermission +static wbstartstruct_t* wbs; + +static wbplayerstruct_t* plrs; // wbs->plyr[] + +// used for general timing +static int cnt; + +// used for timing of background animation +static int bcnt; + +// signals to refresh everything for one frame +static int firstrefresh; + +static int cnt_time; +static int cnt_total_time; +static int cnt_par; +static int cnt_pause; + +// +// GRAPHICS +// + +// You Are Here graphic +static const char* yah[2] = { "WIURH0", "WIURH1" }; + +// splat +static const char* splat = "WISPLAT"; + +// %, : graphics +static const char percent[] = {"WIPCNT"}; +static const char colon[] = {"WICOLON"}; + +// 0-9 graphic +static patchnum_t num[10]; + +// minus sign +static const char wiminus[] = {"WIMINUS"}; + +// "Finished!" graphics +static const char finished[] = {"WIF"}; + +// "Entering" graphic +static const char entering[] = {"WIENTER"}; + +// "secret" +static const char sp_secret[] = {"WISCRT2"}; + +// "Kills", "Scrt", "Items", "Frags" +static const char kills[] = {"WIOSTK"}; +static const char secret[] = {"WIOSTS"}; +static const char items[] = {"WIOSTI"}; +static const char frags[] = {"WIFRGS"}; + +// Time sucks. +static const char time1[] = {"WITIME"}; +static const char par[] = {"WIPAR"}; +static const char sucks[] = {"WISUCKS"}; + +// "killers", "victims" +static const char killers[] = {"WIKILRS"}; +static const char victims[] = {"WIVCTMS"}; + +// "Total", your face, your dead face +static const char total[] = {"WIMSTT"}; +static const char star[] = {"STFST01"}; +static const char bstar[] = {"STFDEAD0"}; + +// "red P[1..MAXPLAYERS]" +static const char facebackp[] = {"STPB0"}; + +// +// CODE +// + +static void WI_endDeathmatchStats(void); +static void WI_endNetgameStats(void); +#define WI_endStats WI_endNetgameStats + +/* ==================================================================== + * WI_levelNameLump + * Purpore: Returns the name of the graphic lump containing the name of + * the given level. + * Args: Episode and level, and buffer (must by 9 chars) to write to + * Returns: void + */ +void WI_levelNameLump(int epis, int map, char* buf) +{ + if (gamemode == commercial) { + sprintf(buf, "CWILV%2.2d", map); + } else { + sprintf(buf, "WILV%d%d", epis, map); + } +} + +// ==================================================================== +// WI_slamBackground +// Purpose: Put the full-screen background up prior to patches +// Args: none +// Returns: void +// +static void WI_slamBackground(void) +{ + char name[9]; // limited to 8 characters + + if (gamemode == commercial || (gamemode == retail && wbs->epsd == 3)) + strcpy(name, "INTERPIC"); + else + sprintf(name, "WIMAP%d", wbs->epsd); + + // background + V_DrawNamePatch(0, 0, FB, name, CR_DEFAULT, VPT_STRETCH); +} + + +// ==================================================================== +// WI_Responder +// Purpose: Draw animations on intermission background screen +// Args: ev -- event pointer, not actually used here. +// Returns: False -- dummy routine +// +// The ticker is used to detect keys +// because of timing issues in netgames. +boolean WI_Responder(event_t* ev) +{ + return false; +} + + +// ==================================================================== +// WI_drawLF +// Purpose: Draw the "Finished" level name before showing stats +// Args: none +// Returns: void +// +void WI_drawLF(void) +{ + int y = WI_TITLEY; + char lname[9]; + + // draw + /* cph - get the graphic lump name and use it */ + WI_levelNameLump(wbs->epsd, wbs->last, lname); + // CPhipps - patch drawing updated + V_DrawNamePatch((320 - V_NamePatchWidth(lname))/2, y, + FB, lname, CR_DEFAULT, VPT_STRETCH); + + // draw "Finished!" + y += (5*V_NamePatchHeight(lname))/4; + + // CPhipps - patch drawing updated + V_DrawNamePatch((320 - V_NamePatchWidth(finished))/2, y, + FB, finished, CR_DEFAULT, VPT_STRETCH); +} + + +// ==================================================================== +// WI_drawEL +// Purpose: Draw introductory "Entering" and level name +// Args: none +// Returns: void +// +void WI_drawEL(void) +{ + int y = WI_TITLEY; + char lname[9]; + + /* cph - get the graphic lump name */ + WI_levelNameLump(wbs->epsd, wbs->next, lname); + + // draw "Entering" + // CPhipps - patch drawing updated + V_DrawNamePatch((320 - V_NamePatchWidth(entering))/2, + y, FB, entering, CR_DEFAULT, VPT_STRETCH); + + // draw level + y += (5*V_NamePatchHeight(lname))/4; + + // CPhipps - patch drawing updated + V_DrawNamePatch((320 - V_NamePatchWidth(lname))/2, y, FB, + lname, CR_DEFAULT, VPT_STRETCH); +} + + +/* ==================================================================== + * WI_drawOnLnode + * Purpose: Draw patches at a location based on episode/map + * Args: n -- index to map# within episode + * c[] -- array of names of patches to be drawn + * Returns: void + */ +void +WI_drawOnLnode // draw stuff at a location by episode/map# +( int n, + const char* const c[] ) +{ + int i; + boolean fits = false; + + i = 0; + do + { + int left; + int top; + int right; + int bottom; + const rpatch_t* patch = R_CachePatchName(c[i]); + + left = lnodes[wbs->epsd][n].x - patch->leftoffset; + top = lnodes[wbs->epsd][n].y - patch->topoffset; + right = left + patch->width; + bottom = top + patch->height; + R_UnlockPatchName(c[i]); + + if (left >= 0 + && right < 320 + && top >= 0 + && bottom < 200) + { + fits = true; + } + else + { + i++; + } + } while (!fits && i!=2); + + if (fits && i<2) + { + // CPhipps - patch drawing updated + V_DrawNamePatch(lnodes[wbs->epsd][n].x, lnodes[wbs->epsd][n].y, + FB, c[i], CR_DEFAULT, VPT_STRETCH); + } + else + { + // DEBUG + //jff 8/3/98 use logical output routine + lprintf(LO_DEBUG,"Could not place patch on level %d", n+1); + } +} + + +// ==================================================================== +// WI_initAnimatedBack +// Purpose: Initialize pointers and styles for background animation +// Args: none +// Returns: void +// +void WI_initAnimatedBack(void) +{ + int i; + anim_t* a; + + if (gamemode == commercial) // no animation for DOOM2 + return; + + if (wbs->epsd > 2) + return; + + for (i=0;iepsd];i++) + { + a = &anims[wbs->epsd][i]; + + // init variables + a->ctr = -1; + + // specify the next time to draw it + if (a->type == ANIM_ALWAYS) + a->nexttic = bcnt + 1 + (M_Random()%a->period); + else + if (a->type == ANIM_RANDOM) + a->nexttic = bcnt + 1 + a->data2+(M_Random()%a->data1); + else + if (a->type == ANIM_LEVEL) + a->nexttic = bcnt + 1; + } +} + + +// ==================================================================== +// WI_updateAnimatedBack +// Purpose: Figure out what animation we do on this iteration +// Args: none +// Returns: void +// +void WI_updateAnimatedBack(void) +{ + int i; + anim_t* a; + + if (gamemode == commercial) + return; + + if (wbs->epsd > 2) + return; + + for (i=0;iepsd];i++) + { + a = &anims[wbs->epsd][i]; + + if (bcnt == a->nexttic) + { + switch (a->type) + { + case ANIM_ALWAYS: + if (++a->ctr >= a->nanims) a->ctr = 0; + a->nexttic = bcnt + a->period; + break; + + case ANIM_RANDOM: + a->ctr++; + if (a->ctr == a->nanims) + { + a->ctr = -1; + a->nexttic = bcnt+a->data2+(M_Random()%a->data1); + } + else + a->nexttic = bcnt + a->period; + break; + + case ANIM_LEVEL: + // gawd-awful hack for level anims + if (!(state == StatCount && i == 7) + && wbs->next == a->data1) + { + a->ctr++; + if (a->ctr == a->nanims) a->ctr--; + a->nexttic = bcnt + a->period; + } + break; + } + } + } +} + + +// ==================================================================== +// WI_drawAnimatedBack +// Purpose: Actually do the animation (whew!) +// Args: none +// Returns: void +// +void WI_drawAnimatedBack(void) +{ + int i; + anim_t* a; + + if (gamemode==commercial) //jff 4/25/98 Someone forgot commercial an enum + return; + + if (wbs->epsd > 2) + return; + + for (i=0 ; iepsd] ; i++) + { + a = &anims[wbs->epsd][i]; + + if (a->ctr >= 0) + // CPhipps - patch drawing updated + V_DrawNumPatch(a->loc.x, a->loc.y, FB, a->p[a->ctr].lumpnum, CR_DEFAULT, VPT_STRETCH); + } +} + + +// ==================================================================== +// WI_drawNum +// Purpose: Draws a number. If digits > 0, then use that many digits +// minimum, otherwise only use as many as necessary +// Args: x, y -- location +// n -- the number to be drawn +// digits -- number of digits minimum or zero +// Returns: new x position after drawing (note we are going to the left) +// CPhipps - static +static int WI_drawNum (int x, int y, int n, int digits) +{ + int fontwidth = num[0].width; + int neg; + int temp; + + if (digits < 0) + { + if (!n) + { + // make variable-length zeros 1 digit long + digits = 1; + } + else + { + // figure out # of digits in # + digits = 0; + temp = n; + + while (temp) + { + temp /= 10; + digits++; + } + } + } + + neg = n < 0; + if (neg) + n = -n; + + // if non-number, do not draw it + if (n == 1994) + return 0; + + // draw the new number + while (digits--) + { + x -= fontwidth; + // CPhipps - patch drawing updated + V_DrawNumPatch(x, y, FB, num[ n % 10 ].lumpnum, CR_DEFAULT, VPT_STRETCH); + n /= 10; + } + + // draw a minus sign if necessary + if (neg) + // CPhipps - patch drawing updated + V_DrawNamePatch(x-=8, y, FB, wiminus, CR_DEFAULT, VPT_STRETCH); + + return x; +} + + +// ==================================================================== +// WI_drawPercent +// Purpose: Draws a percentage, really just a call to WI_drawNum +// after putting a percent sign out there +// Args: x, y -- location +// p -- the percentage value to be drawn, no negatives +// Returns: void +// CPhipps - static +static void WI_drawPercent(int x, int y, int p) +{ + if (p < 0) + return; + + // CPhipps - patch drawing updated + V_DrawNamePatch(x, y, FB, percent, CR_DEFAULT, VPT_STRETCH); + WI_drawNum(x, y, p, -1); +} + + +// ==================================================================== +// WI_drawTime +// Purpose: Draws the level completion time or par time, or "Sucks" +// if 1 hour or more +// Args: x, y -- location +// t -- the time value to be drawn +// Returns: void +// +// CPhipps - static +// - largely rewritten to display hours and use slightly better algorithm + +static void WI_drawTime(int x, int y, int t) +{ + int n; + + if (t<0) + return; + + if (t < 100*60*60) + for(;;) { + n = t % 60; + t /= 60; + x = WI_drawNum(x, y, n, (t || n>9) ? 2 : 1) - V_NamePatchWidth(colon); + + // draw + if (t) + // CPhipps - patch drawing updated + V_DrawNamePatch(x, y, FB, colon, CR_DEFAULT, VPT_STRETCH); + else break; + } + else // "sucks" (maybe should be "addicted", even I've never had a 100 hour game ;) + V_DrawNamePatch(x - V_NamePatchWidth(sucks), + y, FB, sucks, CR_DEFAULT, VPT_STRETCH); +} + + +// ==================================================================== +// WI_End +// Purpose: Unloads data structures (inverse of WI_Start) +// Args: none +// Returns: void +// +void WI_End(void) +{ + if (deathmatch) + WI_endDeathmatchStats(); + else if (netgame) + WI_endNetgameStats(); + else + WI_endStats(); +} + + +// ==================================================================== +// WI_initNoState +// Purpose: Clear state, ready for end of level activity +// Args: none +// Returns: void +// +void WI_initNoState(void) +{ + state = NoState; + acceleratestage = 0; + cnt = 10; +} + + +// ==================================================================== +// WI_drawTimeStats +// Purpose: Put the times on the screen +// Args: time, total time, par time, in seconds +// Returns: void +// +// cph - pulled from WI_drawStats below + +static void WI_drawTimeStats(int cnt_time_sec, int cnt_total_time_sec, int cnt_par_time_sec) +{ + V_DrawNamePatch(SP_TIMEX, SP_TIMEY, FB, time1, CR_DEFAULT, VPT_STRETCH); + WI_drawTime(320/2 - SP_TIMEX, SP_TIMEY, cnt_time_sec); + + V_DrawNamePatch(SP_TIMEX, (SP_TIMEY+200)/2, FB, total, CR_DEFAULT, VPT_STRETCH); + WI_drawTime(320/2 - SP_TIMEX, (SP_TIMEY+200)/2, cnt_total_time_sec); + + // Ty 04/11/98: redid logic: should skip only if with pwad but + // without deh patch + // killough 2/22/98: skip drawing par times on pwads + // Ty 03/17/98: unless pars changed with deh patch + + if (!(modifiedgame && !deh_pars)) + { + if (wbs->epsd < 3) + { + V_DrawNamePatch(320/2 + SP_TIMEX, SP_TIMEY, FB, par, CR_DEFAULT, VPT_STRETCH); + WI_drawTime(320 - SP_TIMEX, SP_TIMEY, cnt_par_time_sec); + } + } +} + +// ==================================================================== +// WI_updateNoState +// Purpose: Cycle until end of level activity is done +// Args: none +// Returns: void +// +void WI_updateNoState(void) +{ + + WI_updateAnimatedBack(); + + if (!--cnt) + G_WorldDone(); +} + +static boolean snl_pointeron = false; + + +// ==================================================================== +// WI_initShowNextLoc +// Purpose: Prepare to show the next level's location +// Args: none +// Returns: void +// +void WI_initShowNextLoc(void) +{ + if ((gamemode != commercial) && (gamemap == 8)) { + G_WorldDone(); + return; + } + + state = ShowNextLoc; + acceleratestage = 0; + + // e6y: That was pretty easy - only a HEX editor and luck + // There is no more desync on ddt-tas.zip\e4tux231.lmp + // --------- tasdoom.idb --------- + // .text:00031194 loc_31194: ; CODE XREF: WI_updateStats+3A9j + // .text:00031194 mov ds:state, 1 + // .text:0003119E mov ds:acceleratestage, 0 + // .text:000311A8 mov ds:cnt, 3Ch + // nowhere no hide + if (compatibility_level == tasdoom_compatibility) + cnt = 60; + else + cnt = SHOWNEXTLOCDELAY * TICRATE; + + WI_initAnimatedBack(); +} + + +// ==================================================================== +// WI_updateShowNextLoc +// Purpose: Prepare to show the next level's location +// Args: none +// Returns: void +// +void WI_updateShowNextLoc(void) +{ + WI_updateAnimatedBack(); + + if (!--cnt || acceleratestage) + WI_initNoState(); + else + snl_pointeron = (cnt & 31) < 20; +} + + +// ==================================================================== +// WI_drawShowNextLoc +// Purpose: Show the next level's location on animated backgrounds +// Args: none +// Returns: void +// +void WI_drawShowNextLoc(void) +{ + int i; + int last; + + WI_slamBackground(); + + // draw animated background + WI_drawAnimatedBack(); + + if ( gamemode != commercial) + { + if (wbs->epsd > 2) + { + WI_drawEL(); // "Entering..." if not E1 or E2 + return; + } + + last = (wbs->last == 8) ? wbs->next - 1 : wbs->last; + + // draw a splat on taken cities. + for (i=0 ; i<=last ; i++) + WI_drawOnLnode(i, &splat); + + // splat the secret level? + if (wbs->didsecret) + WI_drawOnLnode(8, &splat); + + // draw flashing ptr + if (snl_pointeron) + WI_drawOnLnode(wbs->next, yah); + } + + // draws which level you are entering.. + if ( (gamemode != commercial) + || wbs->next != 30) // check for MAP30 end game + WI_drawEL(); +} + +// ==================================================================== +// WI_drawNoState +// Purpose: Draw the pointer and next location +// Args: none +// Returns: void +// +void WI_drawNoState(void) +{ + snl_pointeron = true; + WI_drawShowNextLoc(); +} + +// ==================================================================== +// WI_fragSum +// Purpose: Calculate frags for this player based on the current totals +// of all the other players. Subtract self-frags. +// Args: playernum -- the player to be calculated +// Returns: the total frags for this player +// +int WI_fragSum(int playernum) +{ + int i; + int numfrags = 0; + + for (i=0 ; i 999) // Ty 03/17/98 3-digit frag count + dm_frags[i][j] = 999; + + if (dm_frags[i][j] < -999) + dm_frags[i][j] = -999; + + stillticking = true; + } + } + dm_totals[i] = WI_fragSum(i); + + if (dm_totals[i] > 999) + dm_totals[i] = 999; + + if (dm_totals[i] < -999) + dm_totals[i] = -999; // Ty 03/17/98 end 3-digit frag count + } + } + + if (!stillticking) + { + S_StartSound(0, sfx_barexp); + dm_state++; + } + } + else if (dm_state == 4) + { + if (acceleratestage) + { + S_StartSound(0, sfx_slop); + + if ( gamemode == commercial) + WI_initNoState(); + else + WI_initShowNextLoc(); + } + } + else if (dm_state & 1) + { + if (!--cnt_pause) + { + dm_state++; + cnt_pause = TICRATE; + } + } +} + + +// ==================================================================== +// WI_drawDeathmatchStats +// Purpose: Draw the stats on the screen in a matrix +// Args: none +// Returns: void +// +// proff/nicolas 09/20/98 -- changed for hi-res +// CPhipps - patch drawing updated +void WI_drawDeathmatchStats(void) +{ + int i; + int j; + int x; + int y; + int w; + + int lh; // line height + int halfface = V_NamePatchWidth(facebackp)/2; + + lh = WI_SPACINGY; + + WI_slamBackground(); + + // draw animated background + WI_drawAnimatedBack(); + WI_drawLF(); + + // draw stat titles (top line) + V_DrawNamePatch(DM_TOTALSX-V_NamePatchWidth(total)/2, + DM_MATRIXY-WI_SPACINGY+10, FB, total, CR_DEFAULT, VPT_STRETCH); + + V_DrawNamePatch(DM_KILLERSX, DM_KILLERSY, FB, killers, CR_DEFAULT, VPT_STRETCH); + V_DrawNamePatch(DM_VICTIMSX, DM_VICTIMSY, FB, victims, CR_DEFAULT, VPT_STRETCH); + + // draw P? + x = DM_MATRIXX + DM_SPACINGX; + y = DM_MATRIXY; + + for (i=0 ; i 'int' for cnt_kills, cnt_items and cnt_secret +// +// Original sources use 'int' type for cnt_kills instead of 'short' +// I don't know who have made change of type, but this change +// leads to desynch if 'kills' percentage is more than 32767. +// Actually PrBoom will be in an infinite cycle at calculation of +// percentage if the player will not press for acceleration, because +// the condition (cnt_kills[0] >= (plrs[me].skills * 100) / wbs->maxkills) +// will be always false in this case. +// +// If you will kill 800 monsters on MAP30 on Ultra-Violence skill and +// will not press , vanilla will count up to 80000%, but PrBoom +// will be in infinite cycle of counting: +// (0, 1, 2, ..., 32766, 32767, -32768, -32767, ..., -1, 0, 1, ...) +// Negative numbers will not be displayed. + +static int *cnt_kills; +static int *cnt_items; +static int *cnt_secret; +static int *cnt_frags; +static int dofrags; +static int ng_state; + +// ==================================================================== +// CPhipps - WI_endNetgameStats +// Purpose: Clean up coop game stats +// Args: none +// Returns: void +// +static void WI_endNetgameStats(void) +{ + free(cnt_frags); cnt_frags = NULL; + free(cnt_secret); cnt_secret = NULL; + free(cnt_items); cnt_items = NULL; + free(cnt_kills); cnt_kills = NULL; +} + +// ==================================================================== +// WI_initNetgameStats +// Purpose: Prepare for coop game stats +// Args: none +// Returns: void +// +void WI_initNetgameStats(void) +{ + int i; + + state = StatCount; + acceleratestage = 0; + ng_state = 1; + + cnt_pause = TICRATE; + + // CPhipps - allocate these dynamically, blank with calloc + cnt_kills = calloc(MAXPLAYERS, sizeof(*cnt_kills)); + cnt_items = calloc(MAXPLAYERS, sizeof(*cnt_items)); + cnt_secret= calloc(MAXPLAYERS, sizeof(*cnt_secret)); + cnt_frags = calloc(MAXPLAYERS, sizeof(*cnt_frags)); + + for (i=0 ; imaxkills; + cnt_items[i] = (plrs[i].sitems * 100) / wbs->maxitems; + + // killough 2/22/98: Make secrets = 100% if maxsecret = 0: + cnt_secret[i] = wbs->maxsecret ? + (plrs[i].ssecret * 100) / wbs->maxsecret : 100; + if (dofrags) + cnt_frags[i] = WI_fragSum(i); // we had frags + } + S_StartSound(0, sfx_barexp); // bang + ng_state = 10; + } + + if (ng_state == 2) + { + if (!(bcnt&3)) + S_StartSound(0, sfx_pistol); // pop + + stillticking = false; + + for (i=0 ; i= (plrs[i].skills * 100) / wbs->maxkills) + cnt_kills[i] = (plrs[i].skills * 100) / wbs->maxkills; + else + stillticking = true; // still got stuff to tally + } + + if (!stillticking) + { + S_StartSound(0, sfx_barexp); + ng_state++; + } + } + else if (ng_state == 4) + { + if (!(bcnt&3)) + S_StartSound(0, sfx_pistol); + + stillticking = false; + + for (i=0 ; i= (plrs[i].sitems * 100) / wbs->maxitems) + cnt_items[i] = (plrs[i].sitems * 100) / wbs->maxitems; + else + stillticking = true; + } + + if (!stillticking) + { + S_StartSound(0, sfx_barexp); + ng_state++; + } + } + else if (ng_state == 6) + { + if (!(bcnt&3)) + S_StartSound(0, sfx_pistol); + + stillticking = false; + + for (i=0 ; i= (wbs->maxsecret ? (plrs[i].ssecret * 100) / wbs->maxsecret : compatibility_level < lxdoom_1_compatibility ? 0 : 100)) + cnt_secret[i] = wbs->maxsecret ? (plrs[i].ssecret * 100) / wbs->maxsecret : 100; + else + stillticking = true; + } + + if (!stillticking) + { + S_StartSound(0, sfx_barexp); + ng_state += 1 + 2*!dofrags; + } + } + else if (ng_state == 8) + { + if (!(bcnt&3)) + S_StartSound(0, sfx_pistol); + + stillticking = false; + + for (i=0 ; i= (fsum = WI_fragSum(i))) + cnt_frags[i] = fsum; + else + stillticking = true; + } + + if (!stillticking) + { + S_StartSound(0, sfx_pldeth); + ng_state++; + } + } + else if (ng_state == 10) + { + if (acceleratestage) + { + S_StartSound(0, sfx_sgcock); + if ( gamemode == commercial ) + WI_initNoState(); + else + WI_initShowNextLoc(); + } + } + else if (ng_state & 1) + { + if (!--cnt_pause) + { + ng_state++; + cnt_pause = TICRATE; + } + } +} + + +// ==================================================================== +// WI_drawNetgameStats +// Purpose: Put the coop stats on the screen +// Args: none +// Returns: void +// +// proff/nicolas 09/20/98 -- changed for hi-res +// CPhipps - patch drawing updated +void WI_drawNetgameStats(void) +{ + int i; + int x; + int y; + int pwidth = V_NamePatchWidth(percent); + int fwidth = V_NamePatchWidth(facebackp); + + WI_slamBackground(); + + // draw animated background + WI_drawAnimatedBack(); + + WI_drawLF(); + + // draw stat titles (top line) + V_DrawNamePatch(NG_STATSX+NG_SPACINGX-V_NamePatchWidth(kills), + NG_STATSY, FB, kills, CR_DEFAULT, VPT_STRETCH); + + V_DrawNamePatch(NG_STATSX+2*NG_SPACINGX-V_NamePatchWidth(items), + NG_STATSY, FB, items, CR_DEFAULT, VPT_STRETCH); + + V_DrawNamePatch(NG_STATSX+3*NG_SPACINGX-V_NamePatchWidth(secret), + NG_STATSY, FB, secret, CR_DEFAULT, VPT_STRETCH); + + if (dofrags) + V_DrawNamePatch(NG_STATSX+4*NG_SPACINGX-V_NamePatchWidth(frags), + NG_STATSY, FB, frags, CR_DEFAULT, VPT_STRETCH); + + // draw stats + y = NG_STATSY + V_NamePatchHeight(kills); + + for (i=0 ; itotaltimes / TICRATE, wbs->partime / TICRATE); +} + +static int sp_state; + +// ==================================================================== +// WI_initStats +// Purpose: Get ready for single player stats +// Args: none +// Returns: void +// Comment: Seems like we could do all these stats in a more generic +// set of routines that weren't duplicated for dm, coop, sp +// +void WI_initStats(void) +{ + state = StatCount; + acceleratestage = 0; + sp_state = 1; + + // CPhipps - allocate (awful code, I know, but saves changing it all) and initialise + *(cnt_kills = malloc(sizeof(*cnt_kills))) = + *(cnt_items = malloc(sizeof(*cnt_items))) = + *(cnt_secret= malloc(sizeof(*cnt_secret))) = -1; + cnt_time = cnt_par = cnt_total_time = -1; + cnt_pause = TICRATE; + + WI_initAnimatedBack(); +} + +// ==================================================================== +// WI_updateStats +// Purpose: Calculate solo stats +// Args: none +// Returns: void +// +void WI_updateStats(void) +{ + WI_updateAnimatedBack(); + + if (acceleratestage && sp_state != 10) + { + acceleratestage = 0; + cnt_kills[0] = (plrs[me].skills * 100) / wbs->maxkills; + cnt_items[0] = (plrs[me].sitems * 100) / wbs->maxitems; + + // killough 2/22/98: Make secrets = 100% if maxsecret = 0: + cnt_secret[0] = (wbs->maxsecret ? + (plrs[me].ssecret * 100) / wbs->maxsecret : 100); + + cnt_total_time = wbs->totaltimes / TICRATE; + cnt_time = plrs[me].stime / TICRATE; + cnt_par = wbs->partime / TICRATE; + S_StartSound(0, sfx_barexp); + sp_state = 10; + } + + if (sp_state == 2) + { + cnt_kills[0] += 2; + + if (!(bcnt&3)) + S_StartSound(0, sfx_pistol); + + if (cnt_kills[0] >= (plrs[me].skills * 100) / wbs->maxkills) + { + cnt_kills[0] = (plrs[me].skills * 100) / wbs->maxkills; + S_StartSound(0, sfx_barexp); + sp_state++; + } + } + else if (sp_state == 4) + { + cnt_items[0] += 2; + + if (!(bcnt&3)) + S_StartSound(0, sfx_pistol); + + if (cnt_items[0] >= (plrs[me].sitems * 100) / wbs->maxitems) + { + cnt_items[0] = (plrs[me].sitems * 100) / wbs->maxitems; + S_StartSound(0, sfx_barexp); + sp_state++; + } + } + else if (sp_state == 6) + { + cnt_secret[0] += 2; + + if (!(bcnt&3)) + S_StartSound(0, sfx_pistol); + + // killough 2/22/98: Make secrets = 100% if maxsecret = 0: + if ((!wbs->maxsecret && compatibility_level < lxdoom_1_compatibility) || + cnt_secret[0] >= (wbs->maxsecret ? + (plrs[me].ssecret * 100) / wbs->maxsecret : 100)) + { + cnt_secret[0] = (wbs->maxsecret ? + (plrs[me].ssecret * 100) / wbs->maxsecret : 100); + S_StartSound(0, sfx_barexp); + sp_state++; + } + } + else if (sp_state == 8) + { + int time_done, total_done, par_done; // finished counting? + int time_just, total_just, par_just; // _just_ finished counting? + + // Test if counter is below target, then increment, and test again + // If the first is false and the second true, we've just gone over +#define UPDATE_COUNT(count, inc, target, done, just) \ + (just) = ((count) >= (target)); \ + (count) += (inc); \ + (done) = ((count) >= (target)); \ + (just) = (!(just) && (done)); \ + if ((done)) (count) = (target); + + UPDATE_COUNT(cnt_time, 3, (plrs[me].stime / TICRATE), + time_done, time_just); + UPDATE_COUNT(cnt_total_time, 3, (wbs->totaltimes / TICRATE), + total_done, total_just); + UPDATE_COUNT(cnt_par, 3, (wbs->partime / TICRATE), + par_done, par_just); +#undef UPDATE_COUNT + + // If all three timers are finished, play explosion and bump state + // Ignore total time or par time if not counted or displayed + if (time_done + && (total_done || compatibility_level < lxdoom_1_compatibility) + && (par_done || (modifiedgame && !deh_pars))) + { + // Only play explosion once when counter has just finished + if (time_just + || (total_just && compatibility_level >= lxdoom_1_compatibility) + || (par_just && (!modifiedgame || deh_pars))) + S_StartSound(0, sfx_barexp); + + // Fast-forward total time in old complevels + if (compatibility_level < lxdoom_1_compatibility) + cnt_total_time = (wbs->totaltimes / TICRATE); + + // Only bump state if par timer has actually finished (demosync) + if (par_done) + { + sp_state++; + // Make sure all the counters have reached their targets + cnt_time = (plrs[me].stime / TICRATE); + cnt_total_time = (wbs->totaltimes / TICRATE); + cnt_par = (wbs->partime / TICRATE); + } + } + // Otherwise, if any of the timers are still going, play gunshots + else + { + if (!(bcnt&3)) + S_StartSound(0, sfx_pistol); + } + } + else if (sp_state == 10) + { + if (acceleratestage) + { + S_StartSound(0, sfx_sgcock); + + if (gamemode == commercial) + WI_initNoState(); + else + WI_initShowNextLoc(); + } + } + else if (sp_state & 1) + { + if (!--cnt_pause) + { + sp_state++; + cnt_pause = TICRATE; + } + } +} + +// ==================================================================== +// WI_drawStats +// Purpose: Put the solo stats on the screen +// Args: none +// Returns: void +// +// proff/nicolas 09/20/98 -- changed for hi-res +// CPhipps - patch drawing updated +void WI_drawStats(void) +{ + // line height + int lh; + + lh = (3*num[0].height)/2; + + WI_slamBackground(); + + // draw animated background + WI_drawAnimatedBack(); + + WI_drawLF(); + + V_DrawNamePatch(SP_STATSX, SP_STATSY, FB, kills, CR_DEFAULT, VPT_STRETCH); + if (cnt_kills) + WI_drawPercent(320 - SP_STATSX, SP_STATSY, cnt_kills[0]); + + V_DrawNamePatch(SP_STATSX, SP_STATSY+lh, FB, items, CR_DEFAULT, VPT_STRETCH); + if (cnt_items) + WI_drawPercent(320 - SP_STATSX, SP_STATSY+lh, cnt_items[0]); + + V_DrawNamePatch(SP_STATSX, SP_STATSY+2*lh, FB, sp_secret, CR_DEFAULT, VPT_STRETCH); + if (cnt_secret) + WI_drawPercent(320 - SP_STATSX, SP_STATSY+2*lh, cnt_secret[0]); + + WI_drawTimeStats(cnt_time, cnt_total_time, cnt_par); +} + +// ==================================================================== +// WI_checkForAccelerate +// Purpose: See if the player has hit either the attack or use key +// or mouse button. If so we set acceleratestage to 1 and +// all those display routines above jump right to the end. +// Args: none +// Returns: void +// +void WI_checkForAccelerate(void) +{ + int i; + player_t *player; + + // check for button presses to skip delays + for (i=0, player = players ; icmd.buttons & BT_ATTACK) + { + if (!player->attackdown) + acceleratestage = 1; + player->attackdown = true; + } + else + player->attackdown = false; + + if (player->cmd.buttons & BT_USE) + { + if (!player->usedown) + acceleratestage = 1; + player->usedown = true; + } + else + player->usedown = false; + } + } +} + +// ==================================================================== +// WI_Ticker +// Purpose: Do various updates every gametic, for stats, animation, +// checking that intermission music is running, etc. +// Args: none +// Returns: void +// +void WI_Ticker(void) +{ + // counter for general background animation + bcnt++; + + if (bcnt == 1) + { + // intermission music + if ( gamemode == commercial ) + S_ChangeMusic(mus_dm2int, true); + else + S_ChangeMusic(mus_inter, true); + } + + WI_checkForAccelerate(); + + switch (state) + { + case StatCount: + if (deathmatch) WI_updateDeathmatchStats(); + else if (netgame) WI_updateNetgameStats(); + else WI_updateStats(); + break; + + case ShowNextLoc: + WI_updateShowNextLoc(); + break; + + case NoState: + WI_updateNoState(); + break; + } +} + +/* ==================================================================== + * WI_loadData + * Purpose: Initialize intermission data such as background graphics, + * patches, map names, etc. + * Args: none + * Returns: void + * + * CPhipps - modified for new wad lump handling. + * - no longer preload most graphics, other funcs can use + * them by name + */ + +void WI_loadData(void) +{ + int i; + int j; + char name[9]; // limited to 8 characters + anim_t* a; + + if (gamemode != commercial) + { + if (wbs->epsd < 3) + { + for (j=0;jepsd];j++) + { + a = &anims[wbs->epsd][j]; + for (i=0;inanims;i++) + { + // MONDO HACK! + if (wbs->epsd != 1 || j != 8) + { + // animations + sprintf(name, "WIA%d%.2d%.2d", wbs->epsd, j, i); + R_SetPatchNum(&a->p[i], name); + } + else + { + // HACK ALERT! + a->p[i] = anims[1][4].p[i]; + } + } + } + } + } + + for (i=0;i<10;i++) + { + // numbers 0-9 + sprintf(name, "WINUM%d", i); + R_SetPatchNum(&num[i], name); + } +} + + +// ==================================================================== +// WI_Drawer +// Purpose: Call the appropriate stats drawing routine depending on +// what kind of game is being played (DM, coop, solo) +// Args: none +// Returns: void +// +void WI_Drawer (void) +{ + switch (state) + { + case StatCount: + if (deathmatch) + WI_drawDeathmatchStats(); + else if (netgame) + WI_drawNetgameStats(); + else + WI_drawStats(); + break; + + case ShowNextLoc: + WI_drawShowNextLoc(); + break; + + case NoState: + WI_drawNoState(); + break; + } +} + + +// ==================================================================== +// WI_initVariables +// Purpose: Initialize the intermission information structure +// Note: wbstartstruct_t is defined in d_player.h +// Args: wbstartstruct -- pointer to the structure with the data +// Returns: void +// +void WI_initVariables(wbstartstruct_t* wbstartstruct) +{ + + wbs = wbstartstruct; + +#ifdef RANGECHECKING + if (gamemode != commercial) + { + if ( gamemode == retail ) + RNGCHECK(wbs->epsd, 0, 3); + else + RNGCHECK(wbs->epsd, 0, 2); + } + else + { + RNGCHECK(wbs->last, 0, 8); + RNGCHECK(wbs->next, 0, 8); + } + RNGCHECK(wbs->pnum, 0, MAXPLAYERS); + RNGCHECK(wbs->pnum, 0, MAXPLAYERS); +#endif + + acceleratestage = 0; + cnt = bcnt = 0; + firstrefresh = 1; + me = wbs->pnum; + plrs = wbs->plyr; + + if (!wbs->maxkills) + wbs->maxkills = 1; // probably only useful in MAP30 + + if (!wbs->maxitems) + wbs->maxitems = 1; + + if ( gamemode != retail ) + if (wbs->epsd > 2) + wbs->epsd -= 3; +} + +// ==================================================================== +// WI_Start +// Purpose: Call the various init routines +// Note: wbstartstruct_t is defined in d_player.h +// Args: wbstartstruct -- pointer to the structure with the +// intermission data +// Returns: void +// +void WI_Start(wbstartstruct_t* wbstartstruct) +{ + WI_initVariables(wbstartstruct); + WI_loadData(); + + if (deathmatch) + WI_initDeathmatchStats(); + else if (netgame) + WI_initNetgameStats(); + else + WI_initStats(); +} diff --git a/common/prboom/wi_stuff.h b/common/prboom/wi_stuff.h new file mode 100755 index 0000000..c3363c8 --- /dev/null +++ b/common/prboom/wi_stuff.h @@ -0,0 +1,64 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Intermission screens. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __WI_STUFF__ +#define __WI_STUFF__ + +//#include "v_video.h" + +#include "doomdef.h" + +// States for the intermission + +typedef enum +{ + NoState = -1, + StatCount, + ShowNextLoc + +} stateenum_t; + +// Called by main loop, animate the intermission. +void WI_Ticker (void); + +// Called by main loop, +// draws the intermission directly into the screen buffer. +void WI_Drawer (void); + +// Setup for an intermission screen. +void WI_Start(wbstartstruct_t* wbstartstruct); + +// Release intermission screen memory +void WI_End(void); + +#endif diff --git a/common/prboom/z_bmalloc.c b/common/prboom/z_bmalloc.c new file mode 100755 index 0000000..da3971f --- /dev/null +++ b/common/prboom/z_bmalloc.c @@ -0,0 +1,123 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * This is designed to be a fast allocator for small, regularly used block sizes + *----------------------------------------------------------------------------- + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "doomtype.h" +#include "z_zone.h" +#include "z_bmalloc.h" +#include "lprintf.h" + +typedef struct bmalpool_s { + struct bmalpool_s *nextpool; + size_t blocks; + byte used[]; +} bmalpool_t; + +inline static void* getelem(bmalpool_t *p, size_t size, size_t n) +{ + return (((byte*)p) + sizeof(bmalpool_t) + sizeof(byte)*(p->blocks) + size*n); +} + +inline static PUREFUNC int iselem(const bmalpool_t *pool, size_t size, const void* p) +{ + // CPhipps - need portable # of bytes between pointers + int dif = (const char*)p - (const char*)pool; + + dif -= sizeof(bmalpool_t); + dif -= pool->blocks; + if (dif<0) return -1; + dif /= size; + return (((size_t)dif >= pool->blocks) ? -1 : dif); +} + +enum { unused_block = 0, used_block = 1}; + +void* Z_BMalloc(struct block_memory_alloc_s *pzone) +{ + register bmalpool_t **pool = (bmalpool_t **)&(pzone->firstpool); + while (*pool != NULL) { + byte *p = memchr((*pool)->used, unused_block, (*pool)->blocks); // Scan for unused marker + if (p) { + int n = p - (*pool)->used; +#ifdef SIMPLECHECKS + if ((n<0) || ((size_t)n>=(*pool)->blocks)) + I_Error("Z_BMalloc: memchr returned pointer outside of array"); +#endif + (*pool)->used[n] = used_block; + return getelem(*pool, pzone->size, n); + } else + pool = &((*pool)->nextpool); + } + { + // Nothing available, must allocate a new pool + bmalpool_t *newpool; + + // CPhipps: Allocate new memory, initialised to 0 + + *pool = newpool = Z_Calloc(sizeof(*newpool) + (sizeof(byte) + pzone->size)*(pzone->perpool), + 1, pzone->tag, NULL); + newpool->nextpool = NULL; // NULL = (void*)0 so this is redundant + + // Return element 0 from this pool to satisfy the request + newpool->used[0] = used_block; + newpool->blocks = pzone->perpool; + return getelem(newpool, pzone->size, 0); + } +} + +void Z_BFree(struct block_memory_alloc_s *pzone, void* p) +{ + register bmalpool_t **pool = (bmalpool_t**)&(pzone->firstpool); + + while (*pool != NULL) { + int n = iselem(*pool, pzone->size, p); + if (n >= 0) { +#ifdef SIMPLECHECKS + if ((*pool)->used[n] == unused_block) + I_Error("Z_BFree: Refree in zone %s", pzone->desc); +#endif + (*pool)->used[n] = unused_block; + if (memchr(((*pool)->used), used_block, (*pool)->blocks) == NULL) { + // Block is all unused, can be freed + bmalpool_t *oldpool = *pool; + *pool = (*pool)->nextpool; + Z_Free(oldpool); + } + return; + } else pool = &((*pool)->nextpool); + } + I_Error("Z_BFree: Free not in zone %s", pzone->desc); +} diff --git a/common/prboom/z_bmalloc.h b/common/prboom/z_bmalloc.h new file mode 100755 index 0000000..ed30c9f --- /dev/null +++ b/common/prboom/z_bmalloc.h @@ -0,0 +1,52 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Block memory allocator + * This is designed to be a fast allocator for small, regularly used block sizes + *-----------------------------------------------------------------------------*/ + +struct block_memory_alloc_s { + void *firstpool; + size_t size; + size_t perpool; + int tag; + const char *desc; +}; + +#define DECLARE_BLOCK_MEMORY_ALLOC_ZONE(name) extern struct block_memory_alloc_s name +#define IMPLEMENT_BLOCK_MEMORY_ALLOC_ZONE(name, size, tag, num, desc) \ +struct block_memory_alloc_s name = { NULL, size, num, tag, desc} +#define NULL_BLOCK_MEMORY_ALLOC_ZONE(name) name.firstpool = NULL + +void* Z_BMalloc(struct block_memory_alloc_s *pzone); + +inline static void* Z_BCalloc(struct block_memory_alloc_s *pzone) +{ void *p = Z_BMalloc(pzone); memset(p,0,pzone->size); return p; } + +void Z_BFree(struct block_memory_alloc_s *pzone, void* p); diff --git a/common/prboom/z_zone.c b/common/prboom/z_zone.c new file mode 100755 index 0000000..9b972fe --- /dev/null +++ b/common/prboom/z_zone.c @@ -0,0 +1,705 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Zone Memory Allocation. Neat. + * + * Neat enough to be rewritten by Lee Killough... + * + * Must not have been real neat :) + * + * Made faster and more general, and added wrappers for all of Doom's + * memory allocation functions, including malloc() and similar functions. + * Added line and file numbers, in case of error. Added performance + * statistics and tunables. + *----------------------------------------------------------------------------- + */ + + +// use config.h if autoconf made one -- josh +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include "z_zone.h" +#include "doomstat.h" +#include "m_argv.h" +#include "v_video.h" +#include "g_game.h" +#include "lprintf.h" + +#ifdef DJGPP +#include +#endif + +// Tunables + +// Alignment of zone memory (benefit may be negated by HEADER_SIZE, CHUNK_SIZE) +#define CACHE_ALIGN 32 + +// Minimum chunk size at which blocks are allocated +#define CHUNK_SIZE 32 + +// Minimum size a block must be to become part of a split +#define MIN_BLOCK_SPLIT (1024) + +// How much RAM to leave aside for other libraries +#define LEAVE_ASIDE (128*1024) + +// Amount to subtract when retrying failed attempts to allocate initial pool +#define RETRY_AMOUNT (256*1024) + +// signature for block header +#define ZONEID 0x931d4a11 + +// Number of mallocs & frees kept in history buffer (must be a power of 2) +#define ZONE_HISTORY 4 + +// End Tunables + +typedef struct memblock { + +#ifdef ZONEIDCHECK + unsigned id; +#endif + + struct memblock *next,*prev; + size_t size; + void **user; + unsigned char tag; + +#ifdef INSTRUMENTED + const char *file; + int line; +#endif + +} memblock_t; + +/* size of block header + * cph - base on sizeof(memblock_t), which can be larger than CHUNK_SIZE on + * 64bit architectures */ +static const size_t HEADER_SIZE = (sizeof(memblock_t)+CHUNK_SIZE-1) & ~(CHUNK_SIZE-1); + +static memblock_t *blockbytag[PU_MAX]; + +// 0 means unlimited, any other value is a hard limit +//static int memory_size = 8192*1024; +static int memory_size = 0; +static int free_memory = 0; + +#ifdef INSTRUMENTED + +// statistics for evaluating performance +static int active_memory = 0; +static int purgable_memory = 0; + +static void Z_DrawStats(void) // Print allocation statistics +{ + if (gamestate != GS_LEVEL) + return; + + if (memory_size > 0) { + unsigned long total_memory = free_memory + memory_size + active_memory + purgable_memory; + double s = 100.0 / total_memory; + + doom_printf("%-5i\t%6.01f%%\tstatic\n" + "%-5i\t%6.01f%%\tpurgable\n" + "%-5i\t%6.01f%%\tfree\n" + "%-5li\t\ttotal\n", + active_memory, + active_memory*s, + purgable_memory, + purgable_memory*s, + (free_memory + memory_size), + (free_memory + memory_size)*s, + total_memory + ); + } else { + unsigned long total_memory = active_memory + purgable_memory; + double s = 100.0 / total_memory; + + doom_printf("%-5i\t%6.01f%%\tstatic\n" + "%-5i\t%6.01f%%\tpurgable\n" + "%-5li\t\ttotal\n", + active_memory, + active_memory*s, + purgable_memory, + purgable_memory*s, + total_memory + ); + } +} + +#ifdef HEAPDUMP + +#ifndef HEAPDUMP_DIR +#define HEAPDUMP_DIR "." +#endif + +void W_PrintLump(FILE* fp, void* p); + +void Z_DumpMemory(void) +{ + static int dump; + char buf[PATH_MAX + 1]; + FILE* fp; + size_t total_cache = 0, total_free = 0, total_malloc = 0; + int tag; + + sprintf(buf, "%s/memdump.%d", HEAPDUMP_DIR, dump++); + fp = fopen(buf, "w"); + for (tag = PU_FREE; tag < PU_MAX; tag++) + { + memblock_t* end_block, *block; + block = blockbytag[tag]; + if (!block) + continue; + end_block = block->prev; + while (1) + { + switch (block->tag) { + case PU_FREE: + fprintf(fp, "free %d\n", block->size); + total_free += block->size; + break; + case PU_CACHE: + fprintf(fp, "cache %s:%d:%d\n", block->file, block->line, block->size); + total_cache += block->size; + break; + case PU_LEVEL: + fprintf(fp, "level %s:%d:%d\n", block->file, block->line, block->size); + total_malloc += block->size; + break; + default: + fprintf(fp, "malloc %s:%d:%d", block->file, block->line, block->size); + total_malloc += block->size; + if (block->file) + if (strstr(block->file,"w_memcache.c")) + W_PrintLump(fp, (char*)block + HEADER_SIZE); + fputc('\n', fp); + break; + } + if (block == end_block) + break; + block=block->next; + } + } + fprintf(fp, "malloc %d, cache %d, free %d, total %d\n", + total_malloc, total_cache, total_free, + total_malloc + total_cache + total_free); + fclose(fp); +} +#endif +#endif + +#ifdef INSTRUMENTED + +// killough 4/26/98: Add history information + +enum {malloc_history, free_history, NUM_HISTORY_TYPES}; + +static const char *file_history[NUM_HISTORY_TYPES][ZONE_HISTORY]; +static int line_history[NUM_HISTORY_TYPES][ZONE_HISTORY]; +static int history_index[NUM_HISTORY_TYPES]; +static const char *const desc[NUM_HISTORY_TYPES] = {"malloc()'s", "free()'s"}; + +void Z_DumpHistory(char *buf) +{ + int i,j; + char s[1024]; + strcat(buf,"\n"); + for (i=0;i= sizeof(memblock_t) && size > HEADER_SIZE)) + I_Error("Z_Init: Sanity check failed"); +#endif + + size = (size+CHUNK_SIZE-1) & ~(CHUNK_SIZE-1); // round to chunk size + size += HEADER_SIZE + CACHE_ALIGN; + + // Allocate the memory + + zonebase=(malloc)(size); + if (!zonebase) + I_Error("Z_Init: Failed on allocation of %lu bytes", (unsigned long)size); + + lprintf(LO_INFO,"Z_Init : Allocated %lukb zone memory\n", + (long unsigned)size / 1000); + + // Align on cache boundary + + zone = (memblock_t *) ((char *) zonebase + CACHE_ALIGN - + ((unsigned) zonebase & (CACHE_ALIGN-1))); + + rover = zone; // Rover points to base of zone mem + zone->next = zone->prev = zone; // Single node + zone->size = size; // All memory in one block + zone->tag = PU_FREE; // A free block + zone->vm = 0; + +#ifdef ZONEIDCHECK + zone->id = 0; +#endif + +#ifdef INSTRUMENTED + free_memory = size; + /* cph - remove unnecessary initialisations to 0 */ +#endif +#ifdef HEAPDUMP + atexit(Z_DumpMemory); +#endif +#endif +} + +/* Z_Malloc + * You can pass a NULL user if the tag is < PU_PURGELEVEL. + * + * cph - the algorithm here was a very simple first-fit round-robin + * one - just keep looping around, freeing everything we can until + * we get a large enough space + * + * This has been changed now; we still do the round-robin first-fit, + * but we only free the blocks we actually end up using; we don't + * free all the stuff we just pass on the way. + */ + +void *(Z_Malloc)(size_t size, int tag, void **user +#ifdef INSTRUMENTED + , const char *file, int line +#endif + ) +{ + memblock_t *block = NULL; + +#ifdef INSTRUMENTED +#ifdef CHECKHEAP + Z_CheckHeap(); +#endif + + file_history[malloc_history][history_index[malloc_history]] = file; + line_history[malloc_history][history_index[malloc_history]++] = line; + history_index[malloc_history] &= ZONE_HISTORY-1; +#endif + +#ifdef ZONEIDCHECK + if (tag >= PU_PURGELEVEL && !user) + I_Error ("Z_Malloc: An owner is required for purgable blocks" +#ifdef INSTRUMENTED + "Source: %s:%d", file, line +#endif + ); +#endif + + if (!size) + return user ? *user = NULL : NULL; // malloc(0) returns NULL + + size = (size+CHUNK_SIZE-1) & ~(CHUNK_SIZE-1); // round to chunk size + + if (memory_size > 0 && ((free_memory + memory_size) < (int)(size + HEADER_SIZE))) + { + memblock_t *end_block; + block = blockbytag[PU_CACHE]; + if (block) + { + end_block = block->prev; + while (1) + { + memblock_t *next = block->next; +#ifdef INSTRUMENTED + (Z_Free)((char *) block + HEADER_SIZE, file, line); +#else + (Z_Free)((char *) block + HEADER_SIZE); +#endif + if (((free_memory + memory_size) >= (int)(size + HEADER_SIZE)) || (block == end_block)) + break; + block = next; // Advance to next block + } + } + block = NULL; + } + +#ifdef HAVE_LIBDMALLOC + while (!(block = dmalloc_malloc(file,line,size + HEADER_SIZE,DMALLOC_FUNC_MALLOC,0,0))) { +#else + while (!(block = (malloc)(size + HEADER_SIZE))) { +#endif + if (!blockbytag[PU_CACHE]) + I_Error ("Z_Malloc: Failure trying to allocate %lu bytes" +#ifdef INSTRUMENTED + "\nSource: %s:%d" +#endif + ,(unsigned long) size +#ifdef INSTRUMENTED + , file, line +#endif + ); + Z_FreeTags(PU_CACHE,PU_CACHE); + } + + if (!blockbytag[tag]) + { + blockbytag[tag] = block; + block->next = block->prev = block; + } + else + { + blockbytag[tag]->prev->next = block; + block->prev = blockbytag[tag]->prev; + block->next = blockbytag[tag]; + blockbytag[tag]->prev = block; + } + + block->size = size; + +#ifdef INSTRUMENTED + if (tag >= PU_PURGELEVEL) + purgable_memory += block->size; + else + active_memory += block->size; +#endif + free_memory -= block->size; + +#ifdef INSTRUMENTED + block->file = file; + block->line = line; +#endif + +#ifdef ZONEIDCHECK + block->id = ZONEID; // signature required in block header +#endif + block->tag = tag; // tag + block->user = user; // user + block = (memblock_t *)((char *) block + HEADER_SIZE); + if (user) // if there is a user + *user = block; // set user to point to new block + +#ifdef INSTRUMENTED + Z_DrawStats(); // print memory allocation stats + // scramble memory -- weed out any bugs + memset(block, gametic & 0xff, size); +#endif + + return block; +} + +void (Z_Free)(void *p +#ifdef INSTRUMENTED + , const char *file, int line +#endif + ) +{ + memblock_t *block = (memblock_t *)((char *) p - HEADER_SIZE); + +#ifdef INSTRUMENTED +#ifdef CHECKHEAP + Z_CheckHeap(); +#endif + file_history[free_history][history_index[free_history]] = file; + line_history[free_history][history_index[free_history]++] = line; + history_index[free_history] &= ZONE_HISTORY-1; +#endif + + if (!p) + return; + + +#ifdef ZONEIDCHECK + if (block->id != ZONEID) + I_Error("Z_Free: freed a pointer without ZONEID" +#ifdef INSTRUMENTED + "\nSource: %s:%d" + "\nSource of malloc: %s:%d" + , file, line, block->file, block->line +#endif + ); + block->id = 0; // Nullify id so another free fails +#endif + + if (block->user) // Nullify user if one exists + *block->user = NULL; + + if (block == block->next) + blockbytag[block->tag] = NULL; + else + if (blockbytag[block->tag] == block) + blockbytag[block->tag] = block->next; + block->prev->next = block->next; + block->next->prev = block->prev; + + free_memory += block->size; +#ifdef INSTRUMENTED + if (block->tag >= PU_PURGELEVEL) + purgable_memory -= block->size; + else + active_memory -= block->size; + + /* scramble memory -- weed out any bugs */ + memset(block, gametic & 0xff, block->size + HEADER_SIZE); +#endif + +#ifdef HAVE_LIBDMALLOC + dmalloc_free(file,line,block,DMALLOC_FUNC_MALLOC); +#else + (free)(block); +#endif +#ifdef INSTRUMENTED + Z_DrawStats(); // print memory allocation stats +#endif +} + +void (Z_FreeTags)(int lowtag, int hightag +#ifdef INSTRUMENTED + , const char *file, int line +#endif + ) +{ +#ifdef HEAPDUMP + Z_DumpMemory(); +#endif + + if (lowtag <= PU_FREE) + lowtag = PU_FREE+1; + + if (hightag > PU_CACHE) + hightag = PU_CACHE; + + for (;lowtag <= hightag; lowtag++) + { + memblock_t *block, *end_block; + block = blockbytag[lowtag]; + if (!block) + continue; + end_block = block->prev; + while (1) + { + memblock_t *next = block->next; +#ifdef INSTRUMENTED + (Z_Free)((char *) block + HEADER_SIZE, file, line); +#else + (Z_Free)((char *) block + HEADER_SIZE); +#endif + if (block == end_block) + break; + block = next; // Advance to next block + } + } +} + +void (Z_ChangeTag)(void *ptr, int tag +#ifdef INSTRUMENTED + , const char *file, int line +#endif + ) +{ + memblock_t *block = (memblock_t *)((char *) ptr - HEADER_SIZE); + + // proff - added sanity check, this can happen when an empty lump is locked + if (!ptr) + return; + + // proff - do nothing if tag doesn't differ + if (tag == block->tag) + return; + +#ifdef INSTRUMENTED +#ifdef CHECKHEAP + Z_CheckHeap(); +#endif +#endif + +#ifdef ZONEIDCHECK + if (block->id != ZONEID) + I_Error ("Z_ChangeTag: freed a pointer without ZONEID" +#ifdef INSTRUMENTED + "\nSource: %s:%d" + "\nSource of malloc: %s:%d" + , file, line, block->file, block->line +#endif + ); + + if (tag >= PU_PURGELEVEL && !block->user) + I_Error ("Z_ChangeTag: an owner is required for purgable blocks\n" +#ifdef INSTRUMENTED + "Source: %s:%d" + "\nSource of malloc: %s:%d" + , file, line, block->file, block->line +#endif + ); + +#endif // ZONEIDCHECK + + if (block == block->next) + blockbytag[block->tag] = NULL; + else + if (blockbytag[block->tag] == block) + blockbytag[block->tag] = block->next; + block->prev->next = block->next; + block->next->prev = block->prev; + + if (!blockbytag[tag]) + { + blockbytag[tag] = block; + block->next = block->prev = block; + } + else + { + blockbytag[tag]->prev->next = block; + block->prev = blockbytag[tag]->prev; + block->next = blockbytag[tag]; + blockbytag[tag]->prev = block; + } + +#ifdef INSTRUMENTED + if (block->tag < PU_PURGELEVEL && tag >= PU_PURGELEVEL) + { + active_memory -= block->size; + purgable_memory += block->size; + } + else + if (block->tag >= PU_PURGELEVEL && tag < PU_PURGELEVEL) + { + active_memory += block->size; + purgable_memory -= block->size; + } +#endif + + block->tag = tag; +} + +void *(Z_Realloc)(void *ptr, size_t n, int tag, void **user +#ifdef INSTRUMENTED + , const char *file, int line +#endif + ) +{ + void *p = (Z_Malloc)(n, tag, user DA(file, line)); + if (ptr) + { + memblock_t *block = (memblock_t *)((char *) ptr - HEADER_SIZE); + memcpy(p, ptr, n <= block->size ? n : block->size); + (Z_Free)(ptr DA(file, line)); + if (user) // in case Z_Free nullified same user + *user=p; + } + return p; +} + +void *(Z_Calloc)(size_t n1, size_t n2, int tag, void **user +#ifdef INSTRUMENTED + , const char *file, int line +#endif + ) +{ + return + (n1*=n2) ? memset((Z_Malloc)(n1, tag, user DA(file, line)), 0, n1) : NULL; +} + +char *(Z_Strdup)(const char *s, int tag, void **user +#ifdef INSTRUMENTED + , const char *file, int line +#endif + ) +{ + return strcpy((Z_Malloc)(strlen(s)+1, tag, user DA(file, line)), s); +} + +void (Z_CheckHeap)( +#ifdef INSTRUMENTED + const char *file, int line +#else + void +#endif + ) +{ +#if 0 + memblock_t *block; // Start at base of zone mem + if (block) + do { // Consistency check (last node treated special) + if ((block->next != zone && + (memblock_t *)((char *) block+HEADER_SIZE+block->size) != block->next) + || block->next->prev != block || block->prev->next != block) + I_Error("Z_CheckHeap: Block size does not touch the next block\n" +#ifdef INSTRUMENTED + "Source: %s:%d" + "\nSource of offending block: %s:%d" + , file, line, block->file, block->line +#endif + ); +//#ifdef INSTRUMENTED +// shouldn't be needed anymore, was just for testing +#if 0 + if (((int)block->file < 0x00001000) && (block->file != NULL) && (block->tag != 0)) { + block->file = NULL; + } +#endif + } while ((block=block->next) != zone); +#endif +} diff --git a/common/prboom/z_zone.h b/common/prboom/z_zone.h new file mode 100755 index 0000000..f70ce08 --- /dev/null +++ b/common/prboom/z_zone.h @@ -0,0 +1,129 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * 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. + * + * DESCRIPTION: + * Zone Memory Allocation, perhaps NeXT ObjectiveC inspired. + * Remark: this was the only stuff that, according + * to John Carmack, might have been useful for + * Quake. + * + * Rewritten by Lee Killough, though, since it was not efficient enough. + * + *---------------------------------------------------------------------*/ + +#ifndef __Z_ZONE__ +#define __Z_ZONE__ + +#ifndef __GNUC__ +#define __attribute__(x) +#endif + +// Include system definitions so that prototypes become +// active before macro replacements below are in effect. + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#include +#include +#include + +// ZONE MEMORY +// PU - purge tags. + +enum {PU_FREE, PU_STATIC, PU_SOUND, PU_MUSIC, PU_LEVEL, PU_LEVSPEC, PU_CACHE, + /* Must always be last -- killough */ PU_MAX}; + +#define PU_PURGELEVEL PU_CACHE /* First purgable tag's level */ + +#ifdef INSTRUMENTED +#define DA(x,y) ,x,y +#define DAC(x,y) x,y +#else +#define DA(x,y) +#define DAC(x,y) +#endif + +void *(Z_Malloc)(size_t size, int tag, void **ptr DA(const char *, int)); +void (Z_Free)(void *ptr DA(const char *, int)); +void (Z_FreeTags)(int lowtag, int hightag DA(const char *, int)); +void (Z_ChangeTag)(void *ptr, int tag DA(const char *, int)); +void (Z_Init)(void); +void Z_Close(void); +void *(Z_Calloc)(size_t n, size_t n2, int tag, void **user DA(const char *, int)); +void *(Z_Realloc)(void *p, size_t n, int tag, void **user DA(const char *, int)); +char *(Z_Strdup)(const char *s, int tag, void **user DA(const char *, int)); +void (Z_CheckHeap)(DAC(const char *,int)); // killough 3/22/98: add file/line info +void Z_DumpHistory(char *); + +#ifdef INSTRUMENTED +/* cph - save space if not debugging, don't require file + * and line to memory calls */ +#define Z_Free(a) (Z_Free) (a, __FILE__,__LINE__) +#define Z_FreeTags(a,b) (Z_FreeTags) (a,b, __FILE__,__LINE__) +#define Z_ChangeTag(a,b) (Z_ChangeTag)(a,b, __FILE__,__LINE__) +#define Z_Malloc(a,b,c) (Z_Malloc) (a,b,c, __FILE__,__LINE__) +#define Z_Strdup(a,b,c) (Z_Strdup) (a,b,c, __FILE__,__LINE__) +#define Z_Calloc(a,b,c,d) (Z_Calloc) (a,b,c,d,__FILE__,__LINE__) +#define Z_Realloc(a,b,c,d) (Z_Realloc) (a,b,c,d,__FILE__,__LINE__) +#define Z_CheckHeap() (Z_CheckHeap)(__FILE__,__LINE__) +#endif + +/* cphipps 2001/11/18 - + * If we're using memory mapped file access to WADs, we won't need to maintain + * our own heap. So we *could* let "normal" malloc users use the libc malloc + * directly, for efficiency. Except we do need a wrapper to handle out of memory + * errors... damn, ok, we'll leave it for now. + */ +#ifndef HAVE_LIBDMALLOC +// Remove all definitions before including system definitions + +#undef malloc +#undef free +#undef realloc +#undef calloc +#undef strdup + +#define malloc(n) Z_Malloc(n,PU_STATIC,0) +#define free(p) Z_Free(p) +#define realloc(p,n) Z_Realloc(p,n,PU_STATIC,0) +#define calloc(n1,n2) Z_Calloc(n1,n2,PU_STATIC,0) +#define strdup(s) Z_Strdup(s,PU_STATIC,0) + +#else + +#ifdef HAVE_LIBDMALLOC +#include +#endif + +#endif + +void Z_ZoneHistory(char *); + +#endif diff --git a/gpl.txt b/gpl.txt new file mode 100755 index 0000000..b3f64f0 --- /dev/null +++ b/gpl.txt @@ -0,0 +1,345 @@ + 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. \ No newline at end of file diff --git a/readme_iDoom.txt b/readme_iDoom.txt new file mode 100755 index 0000000..e9a22d9 --- /dev/null +++ b/readme_iDoom.txt @@ -0,0 +1,22 @@ + +The original Wolfenstein 3D code was written in late 1991 / early 1992 using 16 bit Turbo C and the TASM assembler and targeted at 286 based MSDOS systems with VGA graphics and ideally a bit of extended or expanded memory. + +I released the original source for Wolfenstein 3D many years ago, originally under a not-for-commercial purposes license, then later under the GPL. The old code is still available in various places ( http://www.btinternet.com/~belowe/ ) but it isn't very useful on modern platforms. There are several open source projects that have modernized the code so that it works on 32 bit systems and can take advantage of OpenGL acceleration. I started the iphone version with the Wolf3D Redux codebase ( http://wolf3dredux.sourceforge.net/ ), which apparently incorporated a lot of code from NewWolf ( http://newwolf.sourceforge.net/ ). + +At first, I considered trying to build the iphone version as a patch, but when I decided to turn the little research project into a commercial release (and do it in a hurry), I started making more wholesale changes. The Redux codebase had basically gutted the Quake 2 codebase and grafted Wolfenstein into it, which had some nice points, but it meant that the system code was many times as large as the actual Wolfenstein game code. It wasn't really hurting anything, and I considered leaving it all in, but it was such a mess that I finally flattened everything out and cut out about half of the environment code. No attempt was made to make this project portable, although it wouldn't be very hard to clean that up. + +In the past, Id source releases did not include any data files, and you had to extract data files from a commercially obtained version of the game if you wanted to experiment with the original game data. Because it isn't possible for users to tear open an app bundle from the App Store to get at the data, I am including it with the source code to make it easy. You are on-your-honor to buy a copy at the App Store before using the data. :-) The source code is under the GPL, but the data is still strictly copyright Id Software with no license given to distribute outside this code release package or to use for any commercial purpose. You are certainly free to replace all the data and make commercial applications, as long as the code is made available under the GPL. + +/newCode/wolf The 32 bit Wolfenstein code +/newCode/env The Quake 2 derived code +/newCode/iphone The newly written iphone code and xcode project files +/newCode/Tremor Unodified ogg Tremor code for the background music +/base Game data + +I can't say there is a lot of really good code here -- the wolf code is mutated, the quake 2 code is vestigial, and the new code was written in a hurry, but it does all hang together as a pretty fun game to play, and a good testbed for various things. + +If anyone does build another quality commercial application based on this code, let us know, and we can probably do some kind of cross linking. + +John Carmack +2009/03/20 +